rename
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Universal / Network / SnpDxe / Transmit.c
1 /** @file\r
2 Copyright (c) 2004 - 2007, Intel Corporation\r
3 All rights reserved. This program and the accompanying materials\r
4 are licensed and made available under the terms and conditions of the BSD License\r
5 which accompanies this distribution.  The full text of the license may be found at\r
6 http://opensource.org/licenses/bsd-license.php\r
7 \r
8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
10 \r
11 Module name:\r
12 \r
13     transmit.c\r
14 \r
15 Abstract:\r
16 \r
17 Revision history:\r
18   2000-Feb-03 M(f)J   Genesis.\r
19 \r
20 **/\r
21 \r
22 #include "Snp.h"\r
23 \r
24 \r
25 /**\r
26   This routine calls undi to create the meadia header for the given data buffer.\r
27 \r
28   @param  snp                 pointer to SNP driver structure\r
29   @param  MacHeaderPtr        address where the media header will be filled in.\r
30   @param  MacHeaderSize       size of the memory at MacHeaderPtr\r
31   @param  BufferPtr           data buffer pointer\r
32   @param  BufferLength        Size of data in the BufferPtr\r
33   @param  DestinationAddrPtr  address of the destination mac address buffer\r
34   @param  SourceAddrPtr       address of the source mac address buffer\r
35   @param  ProtocolPtr         address of the protocol type\r
36 \r
37   @retval EFI_SUCCESS         if successfully completed the undi call\r
38   @retval Other               error return from undi call.\r
39 \r
40 **/\r
41 STATIC\r
42 EFI_STATUS\r
43 pxe_fillheader (\r
44   SNP_DRIVER      *snp,\r
45   VOID            *MacHeaderPtr,\r
46   UINTN           MacHeaderSize,\r
47   VOID            *BufferPtr,\r
48   UINTN           BufferLength,\r
49   EFI_MAC_ADDRESS *DestinationAddrPtr,\r
50   EFI_MAC_ADDRESS *SourceAddrPtr,\r
51   UINT16          *ProtocolPtr\r
52   )\r
53 {\r
54   PXE_CPB_FILL_HEADER_FRAGMENTED  *cpb;\r
55 \r
56   cpb = snp->cpb;\r
57   if (SourceAddrPtr) {\r
58     CopyMem (\r
59       (VOID *) cpb->SrcAddr,\r
60       (VOID *) SourceAddrPtr,\r
61       snp->mode.HwAddressSize\r
62       );\r
63   } else {\r
64     CopyMem (\r
65       (VOID *) cpb->SrcAddr,\r
66       (VOID *) &(snp->mode.CurrentAddress),\r
67       snp->mode.HwAddressSize\r
68       );\r
69   }\r
70 \r
71   CopyMem (\r
72     (VOID *) cpb->DestAddr,\r
73     (VOID *) DestinationAddrPtr,\r
74     snp->mode.HwAddressSize\r
75     );\r
76 \r
77   //\r
78   // we need to do the byte swapping\r
79   //\r
80   cpb->Protocol             = (UINT16) PXE_SWAP_UINT16 (*ProtocolPtr);\r
81 \r
82   cpb->PacketLen            = (UINT32) (BufferLength);\r
83   cpb->MediaHeaderLen       = (UINT16) MacHeaderSize;\r
84 \r
85   cpb->FragCnt              = 2;\r
86   cpb->reserved             = 0;\r
87 \r
88   cpb->FragDesc[0].FragAddr = (UINT64)(UINTN) MacHeaderPtr;\r
89   cpb->FragDesc[0].FragLen  = (UINT32) MacHeaderSize;\r
90   cpb->FragDesc[1].FragAddr = (UINT64)(UINTN) BufferPtr;\r
91   cpb->FragDesc[1].FragLen  = (UINT32) BufferLength;\r
92 \r
93   cpb->FragDesc[0].reserved = cpb->FragDesc[1].reserved = 0;\r
94 \r
95   snp->cdb.OpCode     = PXE_OPCODE_FILL_HEADER;\r
96   snp->cdb.OpFlags    = PXE_OPFLAGS_FILL_HEADER_FRAGMENTED;\r
97 \r
98   snp->cdb.DBsize     = PXE_DBSIZE_NOT_USED;\r
99   snp->cdb.DBaddr     = PXE_DBADDR_NOT_USED;\r
100 \r
101   snp->cdb.CPBsize    = sizeof (PXE_CPB_FILL_HEADER_FRAGMENTED);\r
102   snp->cdb.CPBaddr    = (UINT64)(UINTN) cpb;\r
103 \r
104   snp->cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
105   snp->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
106   snp->cdb.IFnum      = snp->if_num;\r
107   snp->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
108 \r
109   //\r
110   // Issue UNDI command and check result.\r
111   //\r
112   DEBUG ((EFI_D_NET, "\nsnp->undi.fill_header()  "));\r
113 \r
114   (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);\r
115 \r
116   switch (snp->cdb.StatCode) {\r
117   case PXE_STATCODE_SUCCESS:\r
118     return EFI_SUCCESS;\r
119 \r
120   case PXE_STATCODE_INVALID_PARAMETER:\r
121     DEBUG (\r
122       (EFI_D_ERROR,\r
123       "\nsnp->undi.fill_header()  %xh:%xh\n",\r
124       snp->cdb.StatFlags,\r
125       snp->cdb.StatCode)\r
126       );\r
127 \r
128     return EFI_INVALID_PARAMETER;\r
129 \r
130   default:\r
131     DEBUG (\r
132       (EFI_D_ERROR,\r
133       "\nsnp->undi.fill_header()  %xh:%xh\n",\r
134       snp->cdb.StatFlags,\r
135       snp->cdb.StatCode)\r
136       );\r
137 \r
138     return EFI_DEVICE_ERROR;\r
139   }\r
140 }\r
141 \r
142 \r
143 /**\r
144   This routine calls undi to transmit the given data buffer\r
145 \r
146   @param  snp                 pointer to SNP driver structure\r
147   @param  BufferPtr           data buffer pointer\r
148   @param  BufferLength        Size of data in the BufferPtr\r
149 \r
150   @retval EFI_SUCCESS         if successfully completed the undi call\r
151   @retval Other               error return from undi call.\r
152 \r
153 **/\r
154 STATIC\r
155 EFI_STATUS\r
156 pxe_transmit (\r
157   SNP_DRIVER *snp,\r
158   VOID       *BufferPtr,\r
159   UINTN      BufferLength\r
160   )\r
161 {\r
162   PXE_CPB_TRANSMIT  *cpb;\r
163   EFI_STATUS        Status;\r
164 \r
165   cpb             = snp->cpb;\r
166   cpb->FrameAddr  = (UINT64) (UINTN) BufferPtr;\r
167   cpb->DataLen    = (UINT32) BufferLength;\r
168 \r
169   cpb->MediaheaderLen = 0;\r
170   cpb->reserved       = 0;\r
171 \r
172   snp->cdb.OpFlags    = PXE_OPFLAGS_TRANSMIT_WHOLE;\r
173 \r
174   snp->cdb.CPBsize    = sizeof (PXE_CPB_TRANSMIT);\r
175   snp->cdb.CPBaddr    = (UINT64)(UINTN) cpb;\r
176 \r
177   snp->cdb.OpCode     = PXE_OPCODE_TRANSMIT;\r
178   snp->cdb.DBsize     = PXE_DBSIZE_NOT_USED;\r
179   snp->cdb.DBaddr     = PXE_DBADDR_NOT_USED;\r
180 \r
181   snp->cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
182   snp->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
183   snp->cdb.IFnum      = snp->if_num;\r
184   snp->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
185 \r
186   //\r
187   // Issue UNDI command and check result.\r
188   //\r
189   DEBUG ((EFI_D_NET, "\nsnp->undi.transmit()  "));\r
190   DEBUG ((EFI_D_NET, "\nsnp->cdb.OpCode  == %x", snp->cdb.OpCode));\r
191   DEBUG ((EFI_D_NET, "\nsnp->cdb.CPBaddr == %X", snp->cdb.CPBaddr));\r
192   DEBUG ((EFI_D_NET, "\nsnp->cdb.DBaddr  == %X", snp->cdb.DBaddr));\r
193   DEBUG ((EFI_D_NET, "\ncpb->FrameAddr   == %X\n", cpb->FrameAddr));\r
194 \r
195   (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb);\r
196 \r
197   DEBUG ((EFI_D_NET, "\nexit snp->undi.transmit()  "));\r
198   DEBUG ((EFI_D_NET, "\nsnp->cdb.StatCode == %r", snp->cdb.StatCode));\r
199 \r
200   //\r
201   // we will unmap the buffers in get_status call, not here\r
202   //\r
203   switch (snp->cdb.StatCode) {\r
204   case PXE_STATCODE_SUCCESS:\r
205     return EFI_SUCCESS;\r
206 \r
207   case PXE_STATCODE_QUEUE_FULL:\r
208   case PXE_STATCODE_BUSY:\r
209     Status = EFI_NOT_READY;\r
210     break;\r
211 \r
212   default:\r
213     Status = EFI_DEVICE_ERROR;\r
214   }\r
215 \r
216   DEBUG (\r
217     (EFI_D_ERROR,\r
218     "\nsnp->undi.transmit()  %xh:%xh\n",\r
219     snp->cdb.StatFlags,\r
220     snp->cdb.StatCode)\r
221     );\r
222 \r
223   return Status;\r
224 }\r
225 \r
226 \r
227 /**\r
228   This is the snp interface routine for transmitting a packet. this routine\r
229   basically retrieves the snp structure, checks the snp state and calls\r
230   pxe_fill_header and pxe_transmit calls to complete the transmission.\r
231 \r
232   @param  this                pointer to SNP driver context\r
233   @param  MacHeaderSize       size of the memory at MacHeaderPtr\r
234   @param  BufferLength        Size of data in the BufferPtr\r
235   @param  BufferPtr           data buffer pointer\r
236   @param  SourceAddrPtr       address of the source mac address buffer\r
237   @param  DestinationAddrPtr  address of the destination mac address buffer\r
238   @param  ProtocolPtr         address of the protocol type\r
239 \r
240   @retval EFI_SUCCESS         if successfully completed the undi call\r
241   @retval Other               error return from undi call.\r
242 \r
243 **/\r
244 EFI_STATUS\r
245 EFIAPI\r
246 snp_undi32_transmit (\r
247   IN EFI_SIMPLE_NETWORK_PROTOCOL * this,\r
248   IN UINTN                       MacHeaderSize,\r
249   IN UINTN                       BufferLength,\r
250   IN VOID                        *BufferPtr,\r
251   IN EFI_MAC_ADDRESS             * SourceAddrPtr OPTIONAL,\r
252   IN EFI_MAC_ADDRESS             * DestinationAddrPtr OPTIONAL,\r
253   IN UINT16                      *ProtocolPtr OPTIONAL\r
254   )\r
255 {\r
256   SNP_DRIVER  *snp;\r
257   EFI_STATUS  Status;\r
258   EFI_TPL     OldTpl;\r
259 \r
260   if (this == NULL) {\r
261     return EFI_INVALID_PARAMETER;\r
262   }\r
263 \r
264   snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);\r
265 \r
266   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
267 \r
268   if (snp == NULL) {\r
269     return EFI_DEVICE_ERROR;\r
270   }\r
271 \r
272   switch (snp->mode.State) {\r
273   case EfiSimpleNetworkInitialized:\r
274     break;\r
275 \r
276   case EfiSimpleNetworkStopped:\r
277     Status = EFI_NOT_STARTED;\r
278     goto ON_EXIT;\r
279 \r
280   default:\r
281     Status = EFI_DEVICE_ERROR;\r
282     goto ON_EXIT;\r
283   }\r
284 \r
285   if (BufferPtr == NULL) {\r
286     Status = EFI_INVALID_PARAMETER;\r
287     goto ON_EXIT;\r
288   }\r
289 \r
290   if (BufferLength < snp->mode.MediaHeaderSize) {\r
291     Status = EFI_BUFFER_TOO_SMALL;\r
292     goto ON_EXIT;\r
293   }\r
294 \r
295   //\r
296   // if the MacHeaderSize is non-zero, we need to fill up the header and for that\r
297   // we need the destination address and the protocol\r
298   //\r
299   if (MacHeaderSize != 0) {\r
300     if (MacHeaderSize != snp->mode.MediaHeaderSize || DestinationAddrPtr == 0 || ProtocolPtr == 0) {\r
301       Status = EFI_INVALID_PARAMETER;\r
302       goto ON_EXIT;\r
303     }\r
304 \r
305     Status = pxe_fillheader (\r
306               snp,\r
307               BufferPtr,\r
308               MacHeaderSize,\r
309               (UINT8 *) BufferPtr + MacHeaderSize,\r
310               BufferLength - MacHeaderSize,\r
311               DestinationAddrPtr,\r
312               SourceAddrPtr,\r
313               ProtocolPtr\r
314               );\r
315 \r
316     if (EFI_ERROR (Status)) {\r
317       goto ON_EXIT;\r
318     }\r
319   }\r
320 \r
321   Status = pxe_transmit (snp, BufferPtr, BufferLength);\r
322 \r
323 ON_EXIT:\r
324   gBS->RestoreTPL (OldTpl);\r
325 \r
326   return Status;\r
327 }\r