Further check-in to smooth Intel IPF compiler building.
[people/mcb30/edk2.git] / edk2 / EdkModulePkg / Bus / Pci / Undi / RuntimeDxe / Decode.c
1 /*++\r
2 \r
3 Copyright (c) 2006, Intel Corporation                                                         \r
4 All rights reserved. This program and the accompanying materials                          \r
5 are licensed and made available under the terms and conditions of the BSD License         \r
6 which accompanies this distribution.  The full text of the license may be found at        \r
7 http://opensource.org/licenses/bsd-license.php                                            \r
8                                                                                           \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
11 \r
12 Module name:\r
13     decode.c\r
14 \r
15 Abstract:\r
16 \r
17 Revision history:\r
18 \r
19 --*/\r
20 \r
21 // TODO: fix comment to add: Module Name: DECODE.C\r
22 #include "undi32.h"\r
23 \r
24 \r
25 #pragma data_seg("rtdata")\r
26 \r
27 //\r
28 // Global variables defined outside this file\r
29 //\r
30 extern PXE_SW_UNDI  *pxe;     // !pxe structure\r
31 extern PXE_SW_UNDI  *pxe_31;  // !pxe structure for 3.1 drivers\r
32 extern UNDI32_DEV   *UNDI32DeviceList[MAX_NIC_INTERFACES];\r
33 \r
34 //\r
35 // Global variables defined in this file\r
36 //\r
37 UNDI_CALL_TABLE api_table[PXE_OPCODE_LAST_VALID+1] = { \\r
38   {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,0, (UINT16)(ANY_STATE),UNDI_GetState },\\r
39   {(UINT16)(DONT_CHECK),PXE_DBSIZE_NOT_USED,0,(UINT16)(ANY_STATE),UNDI_Start },\\r
40   {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,0,MUST_BE_STARTED,UNDI_Stop },\\r
41   {PXE_CPBSIZE_NOT_USED,sizeof(PXE_DB_GET_INIT_INFO),0,MUST_BE_STARTED, UNDI_GetInitInfo },\\r
42   {PXE_CPBSIZE_NOT_USED,sizeof(PXE_DB_GET_CONFIG_INFO),0,MUST_BE_STARTED, UNDI_GetConfigInfo },\\r
43   {sizeof(PXE_CPB_INITIALIZE),(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK),MUST_BE_STARTED,UNDI_Initialize },\\r
44   {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED,UNDI_Reset },\\r
45   {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,0, MUST_BE_INITIALIZED,UNDI_Shutdown },\\r
46   {PXE_CPBSIZE_NOT_USED,PXE_DBSIZE_NOT_USED,(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED,UNDI_Interrupt },\\r
47   {(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_RecFilter },\\r
48   {(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_StnAddr },\\r
49   {PXE_CPBSIZE_NOT_USED, (UINT16)(DONT_CHECK), (UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_Statistics },\\r
50   {sizeof(PXE_CPB_MCAST_IP_TO_MAC),sizeof(PXE_DB_MCAST_IP_TO_MAC), (UINT16)(DONT_CHECK),MUST_BE_INITIALIZED, UNDI_ip2mac },\\r
51   {(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_NVData },\\r
52   {PXE_CPBSIZE_NOT_USED,(UINT16)(DONT_CHECK),(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_Status },\\r
53   {(UINT16)(DONT_CHECK),PXE_DBSIZE_NOT_USED,(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_FillHeader },\\r
54   {(UINT16)(DONT_CHECK),PXE_DBSIZE_NOT_USED,(UINT16)(DONT_CHECK), MUST_BE_INITIALIZED, UNDI_Transmit },\\r
55   {sizeof(PXE_CPB_RECEIVE),sizeof(PXE_DB_RECEIVE),0,MUST_BE_INITIALIZED, UNDI_Receive } \\r
56 };\r
57 \r
58 //\r
59 // end of global variables\r
60 //\r
61 \r
62 VOID\r
63 UNDI_GetState (\r
64   IN  PXE_CDB           *CdbPtr,\r
65   IN  NIC_DATA_INSTANCE *AdapterInfo\r
66   )\r
67 /*++\r
68 \r
69 Routine Description:\r
70   This routine determines the operational state of the UNDI.  It updates the state flags in the\r
71   Command Descriptor Block based on information derived from the AdapterInfo instance data.\r
72 \r
73   To ensure the command has completed successfully, CdbPtr->StatCode will contain the result of\r
74   the command execution.\r
75 \r
76   The CdbPtr->StatFlags will contain a STOPPED, STARTED, or INITIALIZED state once the command\r
77   has successfully completed.\r
78 \r
79   Keep in mind the AdapterInfo->State is the active state of the adapter (based on software\r
80   interrogation), and the CdbPtr->StateFlags is the passed back information that is reflected\r
81   to the caller of the UNDI API.\r
82 \r
83 Arguments:\r
84   CdbPtr            - Pointer to the command descriptor block.\r
85   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
86 \r
87 Returns:\r
88   None\r
89 \r
90 --*/\r
91 {\r
92   CdbPtr->StatFlags = (PXE_STATFLAGS) (CdbPtr->StatFlags | AdapterInfo->State);\r
93   return ;\r
94 }\r
95 \r
96 VOID\r
97 UNDI_Start (\r
98   IN  PXE_CDB           *CdbPtr,\r
99   IN  NIC_DATA_INSTANCE *AdapterInfo\r
100   )\r
101 /*++\r
102 \r
103 Routine Description:\r
104   This routine is used to change the operational state of the UNDI from stopped to started.\r
105   It will do this as long as the adapter's state is PXE_STATFLAGS_GET_STATE_STOPPED, otherwise\r
106   the CdbPtr->StatFlags will reflect a command failure, and the CdbPtr->StatCode will reflect the\r
107   UNDI as having already been started.\r
108 \r
109   This routine is modified to reflect the undi 1.1 specification changes. The\r
110   changes in the spec are mainly in the callback routines, the new spec adds\r
111   3 more callbacks and a unique id.\r
112   Since this UNDI supports both old and new undi specifications,\r
113   The NIC's data structure is filled in with the callback routines (depending\r
114   on the version) pointed to in the caller's CpbPtr.  This seeds the Delay,\r
115   Virt2Phys, Block, and Mem_IO for old and new versions and Map_Mem, UnMap_Mem\r
116   and Sync_Mem routines and a unique id variable for the new version.\r
117   This is the function which an external entity (SNP, O/S, etc) would call\r
118   to provide it's I/O abstraction to the UNDI.\r
119 \r
120   It's final action is to change the AdapterInfo->State to PXE_STATFLAGS_GET_STATE_STARTED.\r
121 \r
122 Arguments:\r
123   CdbPtr            - Pointer to the command descriptor block.\r
124   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
125 \r
126 Returns:\r
127   None\r
128 \r
129 --*/\r
130 {\r
131   PXE_CPB_START_30  *CpbPtr;\r
132   PXE_CPB_START_31  *CpbPtr_31;\r
133 \r
134   //\r
135   // check if it is already started.\r
136   //\r
137   if (AdapterInfo->State != PXE_STATFLAGS_GET_STATE_STOPPED) {\r
138     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
139     CdbPtr->StatCode  = PXE_STATCODE_ALREADY_STARTED;\r
140     return ;\r
141   }\r
142 \r
143   if (CdbPtr->CPBsize != sizeof(PXE_CPB_START_30) &&\r
144       CdbPtr->CPBsize != sizeof(PXE_CPB_START_31)) {\r
145 \r
146     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
147     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
148     return ;\r
149   }\r
150 \r
151   CpbPtr    = (PXE_CPB_START_30 *) (UINTN) (CdbPtr->CPBaddr);\r
152   CpbPtr_31 = (PXE_CPB_START_31 *) (UINTN) (CdbPtr->CPBaddr);\r
153 \r
154   if (AdapterInfo->VersionFlag == 0x30) {\r
155     AdapterInfo->Delay_30     = (bsptr_30) (UINTN) CpbPtr->Delay;\r
156     AdapterInfo->Virt2Phys_30 = (virtphys_30) (UINTN) CpbPtr->Virt2Phys;\r
157     AdapterInfo->Block_30     = (block_30) (UINTN) CpbPtr->Block;\r
158     //\r
159     // patch for old buggy 3.0 code:\r
160     // In EFI1.0 undi used to provide the full (absolute) I/O address to the\r
161     // i/o calls and SNP used to provide a callback that used GlobalIoFncs and\r
162     // everything worked fine! In EFI 1.1, UNDI is not using the full\r
163     // i/o or memory address to access the device, The base values for the i/o\r
164     // and memory address is abstracted by the device specific PciIoFncs and\r
165     // UNDI only uses the offset values. Since UNDI3.0 cannot provide any\r
166     // identification to SNP, SNP cannot use nic specific PciIoFncs callback!\r
167     //\r
168     // To fix this and make undi3.0 work with SNP in EFI1.1 we\r
169     // use a TmpMemIo function that is defined in init.c\r
170     // This breaks the runtime driver feature of undi, but what to do\r
171     // if we have to provide the 3.0 compatibility (including the 3.0 bugs)\r
172     //\r
173     // This TmpMemIo function also takes a UniqueId parameter\r
174     // (as in undi3.1 design) and so initialize the UniqueId as well here\r
175     // Note: AdapterInfo->Mem_Io_30 is just filled for consistency with other\r
176     // parameters but never used, we only use Mem_Io field in the In/Out routines\r
177     // inside e100b.c.\r
178     //\r
179     AdapterInfo->Mem_Io_30  = (mem_io_30) (UINTN) CpbPtr->Mem_IO;\r
180     AdapterInfo->Mem_Io     = (mem_io) (UINTN) TmpMemIo;\r
181     AdapterInfo->Unique_ID  = (UINT64) (UINTN) AdapterInfo;\r
182 \r
183   } else {\r
184     AdapterInfo->Delay      = (bsptr) (UINTN) CpbPtr_31->Delay;\r
185     AdapterInfo->Virt2Phys  = (virtphys) (UINTN) CpbPtr_31->Virt2Phys;\r
186     AdapterInfo->Block      = (block) (UINTN) CpbPtr_31->Block;\r
187     AdapterInfo->Mem_Io     = (mem_io) (UINTN) CpbPtr_31->Mem_IO;\r
188 \r
189     AdapterInfo->Map_Mem    = (map_mem) (UINTN) CpbPtr_31->Map_Mem;\r
190     AdapterInfo->UnMap_Mem  = (unmap_mem) (UINTN) CpbPtr_31->UnMap_Mem;\r
191     AdapterInfo->Sync_Mem   = (sync_mem) (UINTN) CpbPtr_31->Sync_Mem;\r
192     AdapterInfo->Unique_ID  = CpbPtr_31->Unique_ID;\r
193   }\r
194 \r
195   AdapterInfo->State = PXE_STATFLAGS_GET_STATE_STARTED;\r
196 \r
197   return ;\r
198 }\r
199 \r
200 VOID\r
201 UNDI_Stop (\r
202   IN  PXE_CDB           *CdbPtr,\r
203   IN  NIC_DATA_INSTANCE *AdapterInfo\r
204   )\r
205 /*++\r
206 \r
207 Routine Description:\r
208   This routine is used to change the operational state of the UNDI from started to stopped.\r
209   It will not do this if the adapter's state is PXE_STATFLAGS_GET_STATE_INITIALIZED, otherwise\r
210   the CdbPtr->StatFlags will reflect a command failure, and the CdbPtr->StatCode will reflect the\r
211   UNDI as having already not been shut down.\r
212 \r
213   The NIC's data structure will have the Delay, Virt2Phys, and Block, pointers zero'd out..\r
214 \r
215   It's final action is to change the AdapterInfo->State to PXE_STATFLAGS_GET_STATE_STOPPED.\r
216 \r
217 Arguments:\r
218   CdbPtr            - Pointer to the command descriptor block.\r
219   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
220 \r
221 Returns:\r
222   None\r
223 \r
224 --*/\r
225 {\r
226   if (AdapterInfo->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {\r
227     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
228     CdbPtr->StatCode  = PXE_STATCODE_NOT_SHUTDOWN;\r
229     return ;\r
230   }\r
231 \r
232   AdapterInfo->Delay_30     = 0;\r
233   AdapterInfo->Virt2Phys_30 = 0;\r
234   AdapterInfo->Block_30     = 0;\r
235 \r
236   AdapterInfo->Delay        = 0;\r
237   AdapterInfo->Virt2Phys    = 0;\r
238   AdapterInfo->Block        = 0;\r
239 \r
240   AdapterInfo->Map_Mem      = 0;\r
241   AdapterInfo->UnMap_Mem    = 0;\r
242   AdapterInfo->Sync_Mem     = 0;\r
243 \r
244   AdapterInfo->State        = PXE_STATFLAGS_GET_STATE_STOPPED;\r
245 \r
246   return ;\r
247 }\r
248 \r
249 VOID\r
250 UNDI_GetInitInfo (\r
251   IN  PXE_CDB           *CdbPtr,\r
252   IN  NIC_DATA_INSTANCE *AdapterInfo\r
253   )\r
254 /*++\r
255 \r
256 Routine Description:\r
257   This routine is used to retrieve the initialization information that is needed by drivers and\r
258   applications to initialize the UNDI.  This will fill in data in the Data Block structure that is\r
259   pointed to by the caller's CdbPtr->DBaddr.  The fields filled in are as follows:\r
260 \r
261   MemoryRequired, FrameDataLen, LinkSpeeds[0-3], NvCount, NvWidth, MediaHeaderLen, HWaddrLen,\r
262   MCastFilterCnt, TxBufCnt, TxBufSize, RxBufCnt, RxBufSize, IFtype, Duplex, and LoopBack.\r
263 \r
264   In addition, the CdbPtr->StatFlags ORs in that this NIC supports cable detection.  (APRIORI knowledge)\r
265 \r
266 Arguments:\r
267   CdbPtr            - Pointer to the command descriptor block.\r
268   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
269 \r
270 Returns:\r
271   None\r
272 \r
273 --*/\r
274 {\r
275   PXE_DB_GET_INIT_INFO  *DbPtr;\r
276 \r
277   DbPtr = (PXE_DB_GET_INIT_INFO *) (UINTN) (CdbPtr->DBaddr);\r
278 \r
279   DbPtr->MemoryRequired = MEMORY_NEEDED;\r
280   DbPtr->FrameDataLen = PXE_MAX_TXRX_UNIT_ETHER;\r
281   DbPtr->LinkSpeeds[0] = 10;\r
282   DbPtr->LinkSpeeds[1] = 100;\r
283   DbPtr->LinkSpeeds[2] = DbPtr->LinkSpeeds[3] = 0;\r
284   DbPtr->NvCount = MAX_EEPROM_LEN;\r
285   DbPtr->NvWidth = 4;\r
286   DbPtr->MediaHeaderLen = PXE_MAC_HEADER_LEN_ETHER;\r
287   DbPtr->HWaddrLen = PXE_HWADDR_LEN_ETHER;\r
288   DbPtr->MCastFilterCnt = MAX_MCAST_ADDRESS_CNT;\r
289 \r
290   DbPtr->TxBufCnt = TX_BUFFER_COUNT;\r
291   DbPtr->TxBufSize = sizeof (TxCB);\r
292   DbPtr->RxBufCnt = RX_BUFFER_COUNT;\r
293   DbPtr->RxBufSize = sizeof (RxFD);\r
294 \r
295   DbPtr->IFtype = PXE_IFTYPE_ETHERNET;\r
296   DbPtr->SupportedDuplexModes = PXE_DUPLEX_ENABLE_FULL_SUPPORTED |\r
297                   PXE_DUPLEX_FORCE_FULL_SUPPORTED;\r
298   DbPtr->SupportedLoopBackModes = PXE_LOOPBACK_INTERNAL_SUPPORTED |\r
299                     PXE_LOOPBACK_EXTERNAL_SUPPORTED;\r
300 \r
301   CdbPtr->StatFlags |= PXE_STATFLAGS_CABLE_DETECT_SUPPORTED;\r
302   return ;\r
303 }\r
304 \r
305 VOID\r
306 UNDI_GetConfigInfo (\r
307   IN  PXE_CDB           *CdbPtr,\r
308   IN  NIC_DATA_INSTANCE *AdapterInfo\r
309   )\r
310 /*++\r
311 \r
312 Routine Description:\r
313   This routine is used to retrieve the configuration information about the NIC being controlled by\r
314   this driver.  This will fill in data in the Data Block structure that is pointed to by the caller's CdbPtr->DBaddr.\r
315   The fields filled in are as follows:\r
316 \r
317   DbPtr->pci.BusType, DbPtr->pci.Bus, DbPtr->pci.Device, and DbPtr->pci.\r
318 \r
319   In addition, the DbPtr->pci.Config.Dword[0-63] grabs a copy of this NIC's PCI configuration space.\r
320 \r
321 Arguments:\r
322   CdbPtr            - Pointer to the command descriptor block.\r
323   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
324 \r
325 Returns:\r
326   None\r
327 \r
328 --*/\r
329 {\r
330   UINT16                  Index;\r
331   PXE_DB_GET_CONFIG_INFO  *DbPtr;\r
332 \r
333   DbPtr               = (PXE_DB_GET_CONFIG_INFO *) (UINTN) (CdbPtr->DBaddr);\r
334 \r
335   DbPtr->pci.BusType  = PXE_BUSTYPE_PCI;\r
336   DbPtr->pci.Bus      = AdapterInfo->Bus;\r
337   DbPtr->pci.Device   = AdapterInfo->Device;\r
338   DbPtr->pci.Function = AdapterInfo->Function;\r
339 \r
340   for (Index = 0; Index < MAX_PCI_CONFIG_LEN; Index++) {\r
341     DbPtr->pci.Config.Dword[Index] = AdapterInfo->Config[Index];\r
342   }\r
343 \r
344   return ;\r
345 }\r
346 \r
347 VOID\r
348 UNDI_Initialize (\r
349   IN  PXE_CDB       *CdbPtr,\r
350   NIC_DATA_INSTANCE *AdapterInfo\r
351   )\r
352 /*++\r
353 \r
354 Routine Description:\r
355   This routine resets the network adapter and initializes the UNDI using the parameters supplied in\r
356   the CPB.  This command must be issued before the network adapter can be setup to transmit and\r
357   receive packets.\r
358 \r
359   Once the memory requirements of the UNDI are obtained by using the GetInitInfo command, a block\r
360   of non-swappable memory may need to be allocated.  The address of this memory must be passed to\r
361   UNDI during the Initialize in the CPB.  This memory is used primarily for transmit and receive buffers.\r
362 \r
363   The fields CableDetect, LinkSpeed, Duplex, LoopBack, MemoryPtr, and MemoryLength are set with information\r
364   that was passed in the CPB and the NIC is initialized.\r
365 \r
366   If the NIC initialization fails, the CdbPtr->StatFlags are updated with PXE_STATFLAGS_COMMAND_FAILED\r
367   Otherwise, AdapterInfo->State is updated with PXE_STATFLAGS_GET_STATE_INITIALIZED showing the state of\r
368   the UNDI is now initialized.\r
369 \r
370 Arguments:\r
371   CdbPtr            - Pointer to the command descriptor block.\r
372   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
373 \r
374 Returns:\r
375   None\r
376 \r
377 --*/\r
378 {\r
379   PXE_CPB_INITIALIZE  *CpbPtr;\r
380 \r
381   if ((CdbPtr->OpFlags != PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) &&\r
382       (CdbPtr->OpFlags != PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE)) {\r
383     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
384     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
385     return ;\r
386   }\r
387 \r
388   //\r
389   // check if it is already initialized\r
390   //\r
391   if (AdapterInfo->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {\r
392     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
393     CdbPtr->StatCode  = PXE_STATCODE_ALREADY_INITIALIZED;\r
394     return ;\r
395   }\r
396 \r
397   CpbPtr  = (PXE_CPB_INITIALIZE *) (UINTN) CdbPtr->CPBaddr;\r
398 \r
399   if (CpbPtr->MemoryLength < (UINT32) MEMORY_NEEDED) {\r
400     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
401     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CPB;\r
402     return ;\r
403   }\r
404 \r
405   //\r
406   // default behaviour is to detect the cable, if the 3rd param is 1,\r
407   // do not do that\r
408   //\r
409   AdapterInfo->CableDetect = (UINT8) ((CdbPtr->OpFlags == (UINT16) PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE) ? (UINT8) 0 : (UINT8) 1);\r
410   AdapterInfo->LinkSpeedReq = (UINT16) CpbPtr->LinkSpeed;\r
411   AdapterInfo->DuplexReq    = CpbPtr->DuplexMode;\r
412   AdapterInfo->LoopBack     = CpbPtr->LoopBackMode;\r
413   AdapterInfo->MemoryPtr    = CpbPtr->MemoryAddr;\r
414   AdapterInfo->MemoryLength = CpbPtr->MemoryLength;\r
415 \r
416   CdbPtr->StatCode          = (PXE_STATCODE) E100bInit (AdapterInfo);\r
417 \r
418   if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {\r
419     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
420   } else {\r
421     AdapterInfo->State = PXE_STATFLAGS_GET_STATE_INITIALIZED;\r
422   }\r
423 \r
424   return ;\r
425 }\r
426 \r
427 VOID\r
428 UNDI_Reset (\r
429   IN  PXE_CDB           *CdbPtr,\r
430   IN  NIC_DATA_INSTANCE *AdapterInfo\r
431   )\r
432 /*++\r
433 \r
434 Routine Description:\r
435   This routine resets the network adapter and initializes the UNDI using the parameters supplied in\r
436   the CPB.  The transmit and receive queues are emptied and any pending interrupts are cleared.\r
437 \r
438   If the NIC reset fails, the CdbPtr->StatFlags are updated with PXE_STATFLAGS_COMMAND_FAILED\r
439 \r
440 Arguments:\r
441   CdbPtr            - Pointer to the command descriptor block.\r
442   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
443 \r
444 Returns:\r
445   None\r
446 \r
447 --*/\r
448 {\r
449   if (CdbPtr->OpFlags != PXE_OPFLAGS_NOT_USED &&\r
450       CdbPtr->OpFlags != PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS &&\r
451       CdbPtr->OpFlags != PXE_OPFLAGS_RESET_DISABLE_FILTERS ) {\r
452 \r
453     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
454     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
455     return ;\r
456   }\r
457 \r
458   CdbPtr->StatCode = (UINT16) E100bReset (AdapterInfo, CdbPtr->OpFlags);\r
459 \r
460   if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {\r
461     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
462   }\r
463 }\r
464 \r
465 VOID\r
466 UNDI_Shutdown (\r
467   IN  PXE_CDB           *CdbPtr,\r
468   IN  NIC_DATA_INSTANCE *AdapterInfo\r
469   )\r
470 /*++\r
471 \r
472 Routine Description:\r
473   This routine resets the network adapter and leaves it in a safe state for another driver to\r
474   initialize.  Any pending transmits or receives are lost.  Receive filters and external\r
475   interrupt enables are disabled.  Once the UNDI has been shutdown, it can then be stopped\r
476   or initialized again.\r
477 \r
478   If the NIC reset fails, the CdbPtr->StatFlags are updated with PXE_STATFLAGS_COMMAND_FAILED\r
479 \r
480   Otherwise, AdapterInfo->State is updated with PXE_STATFLAGS_GET_STATE_STARTED showing the state of\r
481   the NIC as being started.\r
482 \r
483 Arguments:\r
484   CdbPtr            - Pointer to the command descriptor block.\r
485   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
486 \r
487 Returns:\r
488   None\r
489 \r
490 --*/\r
491 {\r
492   //\r
493   // do the shutdown stuff here\r
494   //\r
495   CdbPtr->StatCode = (UINT16) E100bShutdown (AdapterInfo);\r
496 \r
497   if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {\r
498     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
499   } else {\r
500     AdapterInfo->State = PXE_STATFLAGS_GET_STATE_STARTED;\r
501   }\r
502 \r
503   return ;\r
504 }\r
505 \r
506 VOID\r
507 UNDI_Interrupt (\r
508   IN  PXE_CDB           *CdbPtr,\r
509   IN  NIC_DATA_INSTANCE *AdapterInfo\r
510   )\r
511 /*++\r
512 \r
513 Routine Description:\r
514   This routine can be used to read and/or change the current external interrupt enable\r
515   settings.  Disabling an external interrupt enable prevents and external (hardware)\r
516   interrupt from being signaled by the network device.  Internally the interrupt events\r
517   can still be polled by using the UNDI_GetState command.\r
518 \r
519   The resulting information on the interrupt state will be passed back in the CdbPtr->StatFlags.\r
520 \r
521 Arguments:\r
522   CdbPtr            - Pointer to the command descriptor block.\r
523   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
524 \r
525 Returns:\r
526   None\r
527 \r
528 --*/\r
529 {\r
530   UINT8 IntMask;\r
531 \r
532   IntMask = (UINT8)(UINTN)(CdbPtr->OpFlags & (PXE_OPFLAGS_INTERRUPT_RECEIVE |\r
533                                               PXE_OPFLAGS_INTERRUPT_TRANSMIT |\r
534                                               PXE_OPFLAGS_INTERRUPT_COMMAND |\r
535                                               PXE_OPFLAGS_INTERRUPT_SOFTWARE));\r
536 \r
537   switch (CdbPtr->OpFlags & PXE_OPFLAGS_INTERRUPT_OPMASK) {\r
538   case PXE_OPFLAGS_INTERRUPT_READ:\r
539     break;\r
540 \r
541   case PXE_OPFLAGS_INTERRUPT_ENABLE:\r
542     if (IntMask == 0) {\r
543       CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
544       CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
545       return ;\r
546     }\r
547 \r
548     AdapterInfo->int_mask = IntMask;\r
549     E100bSetInterruptState (AdapterInfo);\r
550     break;\r
551 \r
552   case PXE_OPFLAGS_INTERRUPT_DISABLE:\r
553     if (IntMask != 0) {\r
554       AdapterInfo->int_mask = (UINT16) (AdapterInfo->int_mask & ~(IntMask));\r
555       E100bSetInterruptState (AdapterInfo);\r
556       break;\r
557     }\r
558 \r
559   //\r
560   // else fall thru.\r
561   //\r
562   default:\r
563     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
564     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
565     return ;\r
566   }\r
567 \r
568   if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_RECEIVE) != 0) {\r
569     CdbPtr->StatFlags |= PXE_STATFLAGS_INTERRUPT_RECEIVE;\r
570 \r
571   }\r
572 \r
573   if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_TRANSMIT) != 0) {\r
574     CdbPtr->StatFlags |= PXE_STATFLAGS_INTERRUPT_TRANSMIT;\r
575 \r
576   }\r
577 \r
578   if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_COMMAND) != 0) {\r
579     CdbPtr->StatFlags |= PXE_STATFLAGS_INTERRUPT_COMMAND;\r
580 \r
581   }\r
582 \r
583   return ;\r
584 }\r
585 \r
586 VOID\r
587 UNDI_RecFilter (\r
588   IN  PXE_CDB           *CdbPtr,\r
589   IN  NIC_DATA_INSTANCE *AdapterInfo\r
590   )\r
591 /*++\r
592 \r
593 Routine Description:\r
594   This routine is used to read and change receive filters and, if supported, read\r
595   and change multicast MAC address filter list.\r
596 \r
597 Arguments:\r
598   CdbPtr            - Pointer to the command descriptor block.\r
599   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
600 \r
601 Returns:\r
602   None\r
603 \r
604 --*/\r
605 {\r
606   UINT16                  NewFilter;\r
607   UINT16                  OpFlags;\r
608   PXE_DB_RECEIVE_FILTERS  *DbPtr;\r
609   UINT8                   *MacAddr;\r
610   UINTN                   MacCount;\r
611   UINT16                  Index;\r
612   UINT16                  copy_len;\r
613   UINT8                   *ptr1;\r
614   UINT8                   *ptr2;\r
615   OpFlags   = CdbPtr->OpFlags;\r
616   NewFilter = (UINT16) (OpFlags & 0x1F);\r
617 \r
618   switch (OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_OPMASK) {\r
619   case PXE_OPFLAGS_RECEIVE_FILTER_READ:\r
620 \r
621     //\r
622     // not expecting a cpb, not expecting any filter bits\r
623     //\r
624     if ((NewFilter != 0) || (CdbPtr->CPBsize != 0)) {\r
625       goto BadCdb;\r
626 \r
627     }\r
628 \r
629     if ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) == 0) {\r
630       goto JustRead;\r
631 \r
632     }\r
633 \r
634     NewFilter = (UINT16) (NewFilter | AdapterInfo->Rx_Filter);\r
635     //\r
636     // all other flags are ignored except mcast_reset\r
637     //\r
638     break;\r
639 \r
640   case PXE_OPFLAGS_RECEIVE_FILTER_ENABLE:\r
641     //\r
642     // there should be atleast one other filter bit set.\r
643     //\r
644     if (NewFilter == 0) {\r
645       //\r
646       // nothing to enable\r
647       //\r
648       goto BadCdb;\r
649     }\r
650 \r
651     if (CdbPtr->CPBsize != 0) {\r
652       //\r
653       // this must be a multicast address list!\r
654       // don't accept the list unless selective_mcast is set\r
655       // don't accept confusing mcast settings with this\r
656       //\r
657       if (((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) == 0) ||\r
658           ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||\r
659           ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) ||\r
660           ((CdbPtr->CPBsize % sizeof (PXE_MAC_ADDR)) != 0) ) {\r
661         goto BadCdb;\r
662       }\r
663 \r
664       MacAddr   = (UINT8 *) ((UINTN) (CdbPtr->CPBaddr));\r
665       MacCount  = CdbPtr->CPBsize / sizeof (PXE_MAC_ADDR);\r
666 \r
667       for (; MacCount-- != 0; MacAddr += sizeof (PXE_MAC_ADDR)) {\r
668         if (MacAddr[0] != 0x01 || MacAddr[1] != 0x00 || MacAddr[2] != 0x5E || (MacAddr[3] & 0x80) != 0) {\r
669           CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
670           CdbPtr->StatCode  = PXE_STATCODE_INVALID_CPB;\r
671           return ;\r
672         }\r
673       }\r
674     }\r
675 \r
676     //\r
677     // check selective mcast case enable case\r
678     //\r
679     if ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {\r
680       if (((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||\r
681           ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) ) {\r
682         goto BadCdb;\r
683 \r
684       }\r
685       //\r
686       // if no cpb, make sure we have an old list\r
687       //\r
688       if ((CdbPtr->CPBsize == 0) && (AdapterInfo->mcast_list.list_len == 0)) {\r
689         goto BadCdb;\r
690       }\r
691     }\r
692     //\r
693     // if you want to enable anything, you got to have unicast\r
694     // and you have what you already enabled!\r
695     //\r
696     NewFilter = (UINT16) (NewFilter | (PXE_OPFLAGS_RECEIVE_FILTER_UNICAST | AdapterInfo->Rx_Filter));\r
697 \r
698     break;\r
699 \r
700   case PXE_OPFLAGS_RECEIVE_FILTER_DISABLE:\r
701 \r
702     //\r
703     // mcast list not expected, i.e. no cpb here!\r
704     //\r
705     if (CdbPtr->CPBsize != PXE_CPBSIZE_NOT_USED) {\r
706       goto BadCdb;\r
707     }\r
708 \r
709     NewFilter = (UINT16) ((~(CdbPtr->OpFlags & 0x1F)) & AdapterInfo->Rx_Filter);\r
710 \r
711     break;\r
712 \r
713   default:\r
714     goto BadCdb;\r
715   }\r
716 \r
717   if ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) {\r
718     AdapterInfo->mcast_list.list_len = 0;\r
719     NewFilter &= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST);\r
720   }\r
721 \r
722   E100bSetfilter (AdapterInfo, NewFilter, CdbPtr->CPBaddr, CdbPtr->CPBsize);\r
723 \r
724 JustRead:\r
725   //\r
726   // give the current mcast list\r
727   //\r
728   if ((CdbPtr->DBsize != 0) && (AdapterInfo->mcast_list.list_len != 0)) {\r
729     //\r
730     // copy the mc list to db\r
731     //\r
732 \r
733     DbPtr = (PXE_DB_RECEIVE_FILTERS *) (UINTN) CdbPtr->DBaddr;\r
734     ptr1  = (UINT8 *) (&DbPtr->MCastList[0]);\r
735 \r
736     //\r
737     // DbPtr->mc_count = AdapterInfo->mcast_list.list_len;\r
738     //\r
739     copy_len = (UINT16) (AdapterInfo->mcast_list.list_len * PXE_MAC_LENGTH);\r
740 \r
741     if (copy_len > CdbPtr->DBsize) {\r
742       copy_len = CdbPtr->DBsize;\r
743 \r
744     }\r
745 \r
746     ptr2 = (UINT8 *) (&AdapterInfo->mcast_list.mc_list[0]);\r
747     for (Index = 0; Index < copy_len; Index++) {\r
748       ptr1[Index] = ptr2[Index];\r
749     }\r
750   }\r
751   //\r
752   // give the stat flags here\r
753   //\r
754   if (AdapterInfo->Receive_Started) {\r
755     CdbPtr->StatFlags = (PXE_STATFLAGS) (CdbPtr->StatFlags | AdapterInfo->Rx_Filter);\r
756 \r
757   }\r
758 \r
759   return ;\r
760 \r
761 BadCdb:\r
762   CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
763   CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
764 }\r
765 \r
766 VOID\r
767 UNDI_StnAddr (\r
768   IN  PXE_CDB           *CdbPtr,\r
769   IN  NIC_DATA_INSTANCE *AdapterInfo\r
770   )\r
771 /*++\r
772 \r
773 Routine Description:\r
774   This routine is used to get the current station and broadcast MAC addresses, and to change the\r
775   current station MAC address.\r
776 \r
777 Arguments:\r
778   CdbPtr            - Pointer to the command descriptor block.\r
779   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
780 \r
781 Returns:\r
782   None\r
783 \r
784 --*/\r
785 {\r
786   PXE_CPB_STATION_ADDRESS *CpbPtr;\r
787   PXE_DB_STATION_ADDRESS  *DbPtr;\r
788   UINT16                  Index;\r
789 \r
790   if (CdbPtr->OpFlags == PXE_OPFLAGS_STATION_ADDRESS_RESET) {\r
791     //\r
792     // configure the permanent address.\r
793     // change the AdapterInfo->CurrentNodeAddress field.\r
794     //\r
795     if (CompareMem (\r
796           &AdapterInfo->CurrentNodeAddress[0],\r
797           &AdapterInfo->PermNodeAddress[0],\r
798           PXE_MAC_LENGTH\r
799           ) != 0) {\r
800       for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {\r
801         AdapterInfo->CurrentNodeAddress[Index] = AdapterInfo->PermNodeAddress[Index];\r
802       }\r
803 \r
804       E100bSetupIAAddr (AdapterInfo);\r
805     }\r
806   }\r
807 \r
808   if (CdbPtr->CPBaddr != (UINT64) 0) {\r
809     CpbPtr = (PXE_CPB_STATION_ADDRESS *) (UINTN) (CdbPtr->CPBaddr);\r
810     //\r
811     // configure the new address\r
812     //\r
813     for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {\r
814       AdapterInfo->CurrentNodeAddress[Index] = CpbPtr->StationAddr[Index];\r
815     }\r
816 \r
817     E100bSetupIAAddr (AdapterInfo);\r
818   }\r
819 \r
820   if (CdbPtr->DBaddr != (UINT64) 0) {\r
821     DbPtr = (PXE_DB_STATION_ADDRESS *) (UINTN) (CdbPtr->DBaddr);\r
822     //\r
823     // fill it with the new values\r
824     //\r
825     for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {\r
826       DbPtr->StationAddr[Index]   = AdapterInfo->CurrentNodeAddress[Index];\r
827       DbPtr->BroadcastAddr[Index] = AdapterInfo->BroadcastNodeAddress[Index];\r
828       DbPtr->PermanentAddr[Index] = AdapterInfo->PermNodeAddress[Index];\r
829     }\r
830   }\r
831 \r
832   return ;\r
833 }\r
834 \r
835 VOID\r
836 UNDI_Statistics (\r
837   IN  PXE_CDB           *CdbPtr,\r
838   IN  NIC_DATA_INSTANCE *AdapterInfo\r
839   )\r
840 /*++\r
841 \r
842 Routine Description:\r
843   This routine is used to read and clear the NIC traffic statistics.  This command is supported only\r
844   if the !PXE structure's Implementation flags say so.\r
845 \r
846   Results will be parsed out in the following manner:\r
847   CdbPtr->DBaddr.Data[0]   R  Total Frames (Including frames with errors and dropped frames)\r
848   CdbPtr->DBaddr.Data[1]   R  Good Frames (All frames copied into receive buffer)\r
849   CdbPtr->DBaddr.Data[2]   R  Undersize Frames (Frames below minimum length for media <64 for ethernet)\r
850   CdbPtr->DBaddr.Data[4]   R  Dropped Frames (Frames that were dropped because receive buffers were full)\r
851   CdbPtr->DBaddr.Data[8]   R  CRC Error Frames (Frames with alignment or CRC errors)\r
852   CdbPtr->DBaddr.Data[A]   T  Total Frames (Including frames with errors and dropped frames)\r
853   CdbPtr->DBaddr.Data[B]   T  Good Frames (All frames copied into transmit buffer)\r
854   CdbPtr->DBaddr.Data[C]   T  Undersize Frames (Frames below minimum length for media <64 for ethernet)\r
855   CdbPtr->DBaddr.Data[E]   T  Dropped Frames (Frames that were dropped because of collisions)\r
856   CdbPtr->DBaddr.Data[14]  T  Total Collision Frames (Total collisions on this subnet)\r
857 \r
858 Arguments:\r
859   CdbPtr            - Pointer to the command descriptor block.\r
860   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
861 \r
862 Returns:\r
863   None\r
864 \r
865 --*/\r
866 {\r
867   if ((CdbPtr->OpFlags &~(PXE_OPFLAGS_STATISTICS_RESET)) != 0) {\r
868     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
869     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
870     return ;\r
871   }\r
872 \r
873   if ((CdbPtr->OpFlags & PXE_OPFLAGS_STATISTICS_RESET) != 0) {\r
874     //\r
875     // Reset the statistics\r
876     //\r
877     CdbPtr->StatCode = (UINT16) E100bStatistics (AdapterInfo, 0, 0);\r
878   } else {\r
879     CdbPtr->StatCode = (UINT16) E100bStatistics (AdapterInfo, CdbPtr->DBaddr, CdbPtr->DBsize);\r
880   }\r
881 \r
882   return ;\r
883 }\r
884 \r
885 VOID\r
886 UNDI_ip2mac (\r
887   IN  PXE_CDB           *CdbPtr,\r
888   IN  NIC_DATA_INSTANCE *AdapterInfo\r
889   )\r
890 /*++\r
891 \r
892 Routine Description:\r
893   This routine is used to translate a multicast IP address to a multicast MAC address.\r
894 \r
895   This results in a MAC address composed of 25 bits of fixed data with the upper 23 bits of the IP\r
896   address being appended to it.  Results passed back in the equivalent of CdbPtr->DBaddr->MAC[0-5].\r
897 \r
898 Arguments:\r
899   CdbPtr            - Pointer to the command descriptor block.\r
900   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
901 \r
902 Returns:\r
903   None\r
904 \r
905 --*/\r
906 {\r
907   PXE_CPB_MCAST_IP_TO_MAC *CpbPtr;\r
908   PXE_DB_MCAST_IP_TO_MAC  *DbPtr;\r
909   UINT8                   *TmpPtr;\r
910 \r
911   CpbPtr  = (PXE_CPB_MCAST_IP_TO_MAC *) (UINTN) CdbPtr->CPBaddr;\r
912   DbPtr   = (PXE_DB_MCAST_IP_TO_MAC *) (UINTN) CdbPtr->DBaddr;\r
913 \r
914   if ((CdbPtr->OpFlags & PXE_OPFLAGS_MCAST_IPV6_TO_MAC) != 0) {\r
915     //\r
916     // for now this is not supported\r
917     //\r
918     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
919     CdbPtr->StatCode  = PXE_STATCODE_UNSUPPORTED;\r
920     return ;\r
921   }\r
922 \r
923   TmpPtr = (UINT8 *) (&CpbPtr->IP.IPv4);\r
924   //\r
925   // check if the ip given is a mcast IP\r
926   //\r
927   if ((TmpPtr[0] & 0xF0) != 0xE0) {\r
928     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
929     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CPB;\r
930   }\r
931   //\r
932   // take the last 23 bits in IP.\r
933   // be very careful. accessing word on a non-word boundary will hang motherboard codenamed Big Sur\r
934   // casting the mac array (in the middle) to a UINT32 pointer and accessing\r
935   // the UINT32 content hung the system...\r
936   //\r
937   DbPtr->MAC[0] = 0x01;\r
938   DbPtr->MAC[1] = 0x00;\r
939   DbPtr->MAC[2] = 0x5e;\r
940   DbPtr->MAC[3] = (UINT8) (TmpPtr[1] & 0x7f);\r
941   DbPtr->MAC[4] = (UINT8) TmpPtr[2];\r
942   DbPtr->MAC[5] = (UINT8) TmpPtr[3];\r
943 \r
944   return ;\r
945 }\r
946 \r
947 VOID\r
948 UNDI_NVData (\r
949   IN  PXE_CDB           *CdbPtr,\r
950   IN  NIC_DATA_INSTANCE *AdapterInfo\r
951   )\r
952 /*++\r
953 \r
954 Routine Description:\r
955   This routine is used to read and write non-volatile storage on the NIC (if supported).  The NVRAM\r
956   could be EEPROM, FLASH, or battery backed RAM.\r
957 \r
958   This is an optional function according to the UNDI specification  (or will be......)\r
959 \r
960 Arguments:\r
961   CdbPtr            - Pointer to the command descriptor block.\r
962   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
963 \r
964 Returns:\r
965   None\r
966 \r
967 --*/\r
968 {\r
969   PXE_DB_NVDATA *DbPtr;\r
970   UINT16        Index;\r
971 \r
972   if ((CdbPtr->OpFlags == PXE_OPFLAGS_NVDATA_READ) != 0) {\r
973 \r
974     if ((CdbPtr->DBsize == PXE_DBSIZE_NOT_USED) != 0) {\r
975       CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
976       CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
977       return ;\r
978     }\r
979 \r
980     DbPtr = (PXE_DB_NVDATA *) (UINTN) CdbPtr->DBaddr;\r
981 \r
982     for (Index = 0; Index < MAX_PCI_CONFIG_LEN; Index++) {\r
983       DbPtr->Data.Dword[Index] = AdapterInfo->NVData[Index];\r
984 \r
985     }\r
986 \r
987   } else {\r
988     //\r
989     // no write for now\r
990     //\r
991     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
992     CdbPtr->StatCode  = PXE_STATCODE_UNSUPPORTED;\r
993   }\r
994 \r
995   return ;\r
996 }\r
997 \r
998 VOID\r
999 UNDI_Status (\r
1000   IN  PXE_CDB           *CdbPtr,\r
1001   IN  NIC_DATA_INSTANCE *AdapterInfo\r
1002   )\r
1003 /*++\r
1004 \r
1005 Routine Description:\r
1006   This routine returns the current interrupt status and/or the transmitted buffer addresses.\r
1007   If the current interrupt status is returned, pending interrupts will be acknowledged by this\r
1008   command.  Transmitted buffer addresses that are written to the DB are removed from the transmit\r
1009   buffer queue.\r
1010 \r
1011   Normally, this command would be polled with interrupts disabled.\r
1012 \r
1013   The transmit buffers are returned in CdbPtr->DBaddr->TxBufer[0 - NumEntries].\r
1014   The interrupt status is returned in CdbPtr->StatFlags.\r
1015 \r
1016 Arguments:\r
1017   CdbPtr            - Pointer to the command descriptor block.\r
1018   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
1019 \r
1020 Returns:\r
1021   None\r
1022 \r
1023 --*/\r
1024 {\r
1025   PXE_DB_GET_STATUS *DbPtr;\r
1026   PXE_DB_GET_STATUS TmpGetStatus;\r
1027   UINT16            Index;\r
1028   UINT16            Status;\r
1029   UINT16            NumEntries;\r
1030   RxFD              *RxPtr;\r
1031 \r
1032   //\r
1033   // Fill in temporary GetStatus storage.\r
1034   //\r
1035   RxPtr = &AdapterInfo->rx_ring[AdapterInfo->cur_rx_ind];\r
1036 \r
1037   if ((RxPtr->cb_header.status & RX_COMPLETE) != 0) {\r
1038     TmpGetStatus.RxFrameLen = RxPtr->ActualCount & 0x3fff;\r
1039   } else {\r
1040     TmpGetStatus.RxFrameLen = 0;\r
1041   }\r
1042 \r
1043   TmpGetStatus.reserved = 0;\r
1044 \r
1045   //\r
1046   // Fill in size of next available receive packet and\r
1047   // reserved field in caller's DB storage.\r
1048   //\r
1049   DbPtr = (PXE_DB_GET_STATUS *) (UINTN) CdbPtr->DBaddr;\r
1050 \r
1051   if (CdbPtr->DBsize > 0 && CdbPtr->DBsize < sizeof (UINT32) * 2) {\r
1052     CopyMem (DbPtr, &TmpGetStatus, CdbPtr->DBsize);\r
1053   } else {\r
1054     CopyMem (DbPtr, &TmpGetStatus, sizeof (UINT32) * 2);\r
1055   }\r
1056 \r
1057   //\r
1058   //\r
1059   //\r
1060   if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS) != 0) {\r
1061     //\r
1062     // DBsize of zero is invalid if Tx buffers are requested.\r
1063     //\r
1064     if (CdbPtr->DBsize == 0) {\r
1065       CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1066       CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
1067       return ;\r
1068     }\r
1069 \r
1070     //\r
1071     // remember this b4 we overwrite\r
1072     //\r
1073     NumEntries = (UINT16) (CdbPtr->DBsize - sizeof (UINT64));\r
1074 \r
1075     //\r
1076     // We already filled in 2 UINT32s.\r
1077     //\r
1078     CdbPtr->DBsize = sizeof (UINT32) * 2;\r
1079 \r
1080     //\r
1081     // will claim any hanging free CBs\r
1082     //\r
1083     CheckCBList (AdapterInfo);\r
1084 \r
1085     if (AdapterInfo->xmit_done_head == AdapterInfo->xmit_done_tail) {\r
1086       CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_TXBUF_QUEUE_EMPTY;\r
1087     } else {\r
1088       for (Index = 0; NumEntries >= sizeof (UINT64); Index++, NumEntries -= sizeof (UINT64)) {\r
1089         if (AdapterInfo->xmit_done_head != AdapterInfo->xmit_done_tail) {\r
1090           DbPtr->TxBuffer[Index]      = AdapterInfo->xmit_done[AdapterInfo->xmit_done_head];\r
1091           AdapterInfo->xmit_done_head = next (AdapterInfo->xmit_done_head);\r
1092           CdbPtr->DBsize += sizeof (UINT64);\r
1093         } else {\r
1094           break;\r
1095         }\r
1096       }\r
1097     }\r
1098 \r
1099     if (AdapterInfo->xmit_done_head != AdapterInfo->xmit_done_tail) {\r
1100       CdbPtr->StatFlags |= PXE_STATFLAGS_DB_WRITE_TRUNCATED;\r
1101 \r
1102     }\r
1103     //\r
1104     // check for a receive buffer and give it's size in db\r
1105     //\r
1106   }\r
1107   //\r
1108   //\r
1109   //\r
1110   if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_INTERRUPT_STATUS) != 0) {\r
1111 \r
1112     Status = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBStatus);\r
1113     AdapterInfo->Int_Status = (UINT16) (AdapterInfo->Int_Status | Status);\r
1114 \r
1115     //\r
1116     // acknoledge the interrupts\r
1117     //\r
1118     OutWord (AdapterInfo, (UINT16) (Status & 0xfc00), (UINT32) (AdapterInfo->ioaddr + SCBStatus));\r
1119 \r
1120     //\r
1121     // report all the outstanding interrupts\r
1122     //\r
1123     Status = AdapterInfo->Int_Status;\r
1124     if ((Status & SCB_STATUS_FR) != 0) {\r
1125       CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_RECEIVE;\r
1126     }\r
1127 \r
1128     if ((Status & SCB_STATUS_SWI) != 0) {\r
1129       CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_SOFTWARE;\r
1130     }\r
1131   }\r
1132 \r
1133   return ;\r
1134 }\r
1135 \r
1136 VOID\r
1137 UNDI_FillHeader (\r
1138   IN  PXE_CDB           *CdbPtr,\r
1139   IN  NIC_DATA_INSTANCE *AdapterInfo\r
1140   )\r
1141 /*++\r
1142 \r
1143 Routine Description:\r
1144   This routine is used to fill media header(s) in transmit packet(s).\r
1145   Copies the MAC address into the media header whether it is dealing\r
1146   with fragmented or non-fragmented packets.\r
1147 \r
1148 Arguments:\r
1149   CdbPtr            - Pointer to the command descriptor block.\r
1150   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
1151 \r
1152 Returns:\r
1153   None\r
1154 \r
1155 --*/\r
1156 {\r
1157   PXE_CPB_FILL_HEADER             *Cpb;\r
1158   PXE_CPB_FILL_HEADER_FRAGMENTED  *Cpbf;\r
1159   EtherHeader                     *MacHeader;\r
1160   UINTN                           Index;\r
1161 \r
1162   if (CdbPtr->CPBsize == PXE_CPBSIZE_NOT_USED) {\r
1163     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1164     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
1165     return ;\r
1166   }\r
1167 \r
1168   if ((CdbPtr->OpFlags & PXE_OPFLAGS_FILL_HEADER_FRAGMENTED) != 0) {\r
1169     Cpbf = (PXE_CPB_FILL_HEADER_FRAGMENTED *) (UINTN) CdbPtr->CPBaddr;\r
1170 \r
1171     //\r
1172     // assume 1st fragment is big enough for the mac header\r
1173     //\r
1174     if ((Cpbf->FragCnt == 0) || (Cpbf->FragDesc[0].FragLen < PXE_MAC_HEADER_LEN_ETHER)) {\r
1175       //\r
1176       // no buffers given\r
1177       //\r
1178       CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1179       CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
1180       return ;\r
1181     }\r
1182 \r
1183     MacHeader = (EtherHeader *) (UINTN) Cpbf->FragDesc[0].FragAddr;\r
1184     //\r
1185     // we don't swap the protocol bytes\r
1186     //\r
1187     MacHeader->type = Cpbf->Protocol;\r
1188 \r
1189     for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {\r
1190       MacHeader->dest_addr[Index] = Cpbf->DestAddr[Index];\r
1191       MacHeader->src_addr[Index]  = Cpbf->SrcAddr[Index];\r
1192     }\r
1193   } else {\r
1194     Cpb       = (PXE_CPB_FILL_HEADER *) (UINTN) CdbPtr->CPBaddr;\r
1195 \r
1196     MacHeader = (EtherHeader *) (UINTN) Cpb->MediaHeader;\r
1197     //\r
1198     // we don't swap the protocol bytes\r
1199     //\r
1200     MacHeader->type = Cpb->Protocol;\r
1201 \r
1202     for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {\r
1203       MacHeader->dest_addr[Index] = Cpb->DestAddr[Index];\r
1204       MacHeader->src_addr[Index]  = Cpb->SrcAddr[Index];\r
1205     }\r
1206   }\r
1207 \r
1208   return ;\r
1209 }\r
1210 \r
1211 VOID\r
1212 UNDI_Transmit (\r
1213   IN  PXE_CDB           *CdbPtr,\r
1214   IN  NIC_DATA_INSTANCE *AdapterInfo\r
1215   )\r
1216 /*++\r
1217 \r
1218 Routine Description:\r
1219   This routine is used to place a packet into the transmit queue.  The data buffers given to\r
1220   this command are to be considered locked and the application or network driver loses\r
1221   ownership of these buffers and must not free or relocate them until the ownership returns.\r
1222 \r
1223   When the packets are transmitted, a transmit complete interrupt is generated (if interrupts\r
1224   are disabled, the transmit interrupt status is still set and can be checked using the UNDI_Status\r
1225   command.\r
1226 \r
1227   Some implementations and adapters support transmitting multiple packets with one transmit\r
1228   command.  If this feature is supported, the transmit CPBs can be linked in one transmit\r
1229   command.\r
1230 \r
1231   All UNDIs support fragmented frames, now all network devices or protocols do.  If a fragmented\r
1232   frame CPB is given to UNDI and the network device does not support fragmented frames\r
1233   (see !PXE.Implementation flag), the UNDI will have to copy the fragments into a local buffer\r
1234   before transmitting.\r
1235 \r
1236 \r
1237 Arguments:\r
1238   CdbPtr            - Pointer to the command descriptor block.\r
1239   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
1240 \r
1241 Returns:\r
1242   None\r
1243 \r
1244 --*/\r
1245 {\r
1246 \r
1247   if (CdbPtr->CPBsize == PXE_CPBSIZE_NOT_USED) {\r
1248     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1249     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
1250     return ;\r
1251   }\r
1252 \r
1253   CdbPtr->StatCode = (PXE_STATCODE) E100bTransmit (AdapterInfo, CdbPtr->CPBaddr, CdbPtr->OpFlags);\r
1254 \r
1255   if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {\r
1256     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1257   }\r
1258 \r
1259   return ;\r
1260 }\r
1261 \r
1262 VOID\r
1263 UNDI_Receive (\r
1264   IN  PXE_CDB           *CdbPtr,\r
1265   IN  NIC_DATA_INSTANCE *AdapterInfo\r
1266   )\r
1267 /*++\r
1268 \r
1269 Routine Description:\r
1270   When the network adapter has received a frame, this command is used to copy the frame\r
1271   into the driver/application storage location.  Once a frame has been copied, it is\r
1272   removed from the receive queue.\r
1273 \r
1274 Arguments:\r
1275   CdbPtr            - Pointer to the command descriptor block.\r
1276   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
1277 \r
1278 Returns:\r
1279   None\r
1280 \r
1281 --*/\r
1282 {\r
1283 \r
1284   //\r
1285   // check if RU has started...\r
1286   //\r
1287   if (!AdapterInfo->Receive_Started) {\r
1288     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1289     CdbPtr->StatCode  = PXE_STATCODE_NOT_INITIALIZED;\r
1290     return ;\r
1291   }\r
1292 \r
1293 \r
1294   CdbPtr->StatCode  = (UINT16) E100bReceive (AdapterInfo, CdbPtr->CPBaddr, CdbPtr->DBaddr);\r
1295   if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {\r
1296     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1297 \r
1298   }\r
1299 \r
1300   return ;\r
1301 }\r
1302 \r
1303 VOID\r
1304 UNDI_APIEntry_old (\r
1305   IN  UINT64 cdb\r
1306   )\r
1307 /*++\r
1308 \r
1309 Routine Description:\r
1310   This is the main SW UNDI API entry using the older nii protocol.\r
1311   The parameter passed in is a 64 bit flat model virtual\r
1312   address of the cdb.  We then jump into the common routine for both old and\r
1313   new nii protocol entries.\r
1314 \r
1315 Arguments:\r
1316   CdbPtr            - Pointer to the command descriptor block.\r
1317   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
1318 \r
1319 Returns:\r
1320   None\r
1321 \r
1322 --*/\r
1323 // TODO:    cdb - add argument and description to function comment\r
1324 {\r
1325   PXE_CDB           *CdbPtr;\r
1326   NIC_DATA_INSTANCE *AdapterInfo;\r
1327 \r
1328   if (cdb == (UINT64) 0) {\r
1329     return ;\r
1330 \r
1331   }\r
1332 \r
1333   CdbPtr = (PXE_CDB *) (UINTN) cdb;\r
1334 \r
1335   if (CdbPtr->IFnum >= pxe->IFcnt) {\r
1336     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1337     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
1338     return ;\r
1339   }\r
1340 \r
1341   AdapterInfo               = &(UNDI32DeviceList[CdbPtr->IFnum]->NicInfo);\r
1342   \r
1343   //\r
1344   // entering from older entry point\r
1345   //\r
1346   AdapterInfo->VersionFlag  = 0x30;\r
1347   UNDI_APIEntry_Common (cdb);\r
1348 }\r
1349 \r
1350 VOID\r
1351 UNDI_APIEntry_new (\r
1352   IN  UINT64 cdb\r
1353   )\r
1354 /*++\r
1355 \r
1356 Routine Description:\r
1357   This is the main SW UNDI API entry using the newer nii protocol.\r
1358   The parameter passed in is a 64 bit flat model virtual\r
1359   address of the cdb.  We then jump into the common routine for both old and\r
1360   new nii protocol entries.\r
1361 \r
1362 Arguments:\r
1363   CdbPtr            - Pointer to the command descriptor block.\r
1364   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
1365 \r
1366 Returns:\r
1367   None\r
1368 \r
1369 --*/\r
1370 // TODO:    cdb - add argument and description to function comment\r
1371 {\r
1372   PXE_CDB           *CdbPtr;\r
1373   NIC_DATA_INSTANCE *AdapterInfo;\r
1374 \r
1375   if (cdb == (UINT64) 0) {\r
1376     return ;\r
1377 \r
1378   }\r
1379 \r
1380   CdbPtr = (PXE_CDB *) (UINTN) cdb;\r
1381 \r
1382   if (CdbPtr->IFnum >= pxe_31->IFcnt) {\r
1383     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1384     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
1385     return ;\r
1386   }\r
1387 \r
1388   AdapterInfo               = &(UNDI32DeviceList[CdbPtr->IFnum]->NicInfo);\r
1389   //\r
1390   // entering from older entry point\r
1391   //\r
1392   AdapterInfo->VersionFlag  = 0x31;\r
1393   UNDI_APIEntry_Common (cdb);\r
1394 }\r
1395 \r
1396 VOID\r
1397 UNDI_APIEntry_Common (\r
1398   IN  UINT64 cdb\r
1399   )\r
1400 /*++\r
1401 \r
1402 Routine Description:\r
1403   This is the common routine for both old and new entry point procedures.\r
1404   The parameter passed in is a 64 bit flat model virtual\r
1405   address of the cdb.  We then jump into the service routine pointed to by the\r
1406   Api_Table[OpCode].\r
1407 \r
1408 Arguments:\r
1409   CdbPtr            - Pointer to the command descriptor block.\r
1410   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
1411 \r
1412 Returns:\r
1413   None\r
1414 \r
1415 --*/\r
1416 // TODO:    cdb - add argument and description to function comment\r
1417 {\r
1418   PXE_CDB           *CdbPtr;\r
1419   NIC_DATA_INSTANCE *AdapterInfo;\r
1420   UNDI_CALL_TABLE   *tab_ptr;\r
1421 \r
1422   CdbPtr = (PXE_CDB *) (UINTN) cdb;\r
1423 \r
1424   //\r
1425   // check the OPCODE range\r
1426   //\r
1427   if ((CdbPtr->OpCode > PXE_OPCODE_LAST_VALID) ||\r
1428       (CdbPtr->StatCode != PXE_STATCODE_INITIALIZE) ||\r
1429       (CdbPtr->StatFlags != PXE_STATFLAGS_INITIALIZE) ||\r
1430       (CdbPtr->IFnum >= pxe_31->IFcnt) ) {\r
1431     goto badcdb;\r
1432 \r
1433   }\r
1434 \r
1435   if (CdbPtr->CPBsize == PXE_CPBSIZE_NOT_USED) {\r
1436     if (CdbPtr->CPBaddr != PXE_CPBADDR_NOT_USED) {\r
1437       goto badcdb;\r
1438     }\r
1439   } else if (CdbPtr->CPBaddr == PXE_CPBADDR_NOT_USED) {\r
1440     goto badcdb;\r
1441   }\r
1442 \r
1443   if (CdbPtr->DBsize == PXE_DBSIZE_NOT_USED) {\r
1444     if (CdbPtr->DBaddr != PXE_DBADDR_NOT_USED) {\r
1445       goto badcdb;\r
1446     }\r
1447   } else if (CdbPtr->DBaddr == PXE_DBADDR_NOT_USED) {\r
1448     goto badcdb;\r
1449   }\r
1450 \r
1451   //\r
1452   // check if cpbsize and dbsize are as needed\r
1453   // check if opflags are as expected\r
1454   //\r
1455   tab_ptr = &api_table[CdbPtr->OpCode];\r
1456 \r
1457   if (tab_ptr->cpbsize != (UINT16) (DONT_CHECK) && tab_ptr->cpbsize != CdbPtr->CPBsize) {\r
1458     goto badcdb;\r
1459   }\r
1460 \r
1461   if (tab_ptr->dbsize != (UINT16) (DONT_CHECK) && tab_ptr->dbsize != CdbPtr->DBsize) {\r
1462     goto badcdb;\r
1463   }\r
1464 \r
1465   if (tab_ptr->opflags != (UINT16) (DONT_CHECK) && tab_ptr->opflags != CdbPtr->OpFlags) {\r
1466     goto badcdb;\r
1467 \r
1468   }\r
1469 \r
1470   AdapterInfo = &(UNDI32DeviceList[CdbPtr->IFnum]->NicInfo);\r
1471 \r
1472   //\r
1473   // check if UNDI_State is valid for this call\r
1474   //\r
1475   if (tab_ptr->state != (UINT16) (-1)) {\r
1476     //\r
1477     // should atleast be started\r
1478     //\r
1479     if (AdapterInfo->State == PXE_STATFLAGS_GET_STATE_STOPPED) {\r
1480       CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1481       CdbPtr->StatCode  = PXE_STATCODE_NOT_STARTED;\r
1482       return ;\r
1483     }\r
1484     //\r
1485     // check if it should be initialized\r
1486     //\r
1487     if (tab_ptr->state == 2) {\r
1488       if (AdapterInfo->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {\r
1489         CdbPtr->StatCode  = PXE_STATCODE_NOT_INITIALIZED;\r
1490         CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1491         return ;\r
1492       }\r
1493     }\r
1494   }\r
1495   //\r
1496   // set the return variable for success case here\r
1497   //\r
1498   CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;\r
1499   CdbPtr->StatCode  = PXE_STATCODE_SUCCESS;\r
1500 \r
1501   tab_ptr->api_ptr (CdbPtr, AdapterInfo);\r
1502   return ;\r
1503   //\r
1504   // %% AVL - check for command linking\r
1505   //\r
1506 badcdb:\r
1507   CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1508   CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
1509   return ;\r
1510 }\r
1511 \r
1512 STATIC\r
1513 UINT8\r
1514 ChkSum (\r
1515   IN  VOID   *Buffer,\r
1516   IN  UINT16 Len\r
1517   )\r
1518 /*++\r
1519 \r
1520 Routine Description:\r
1521   This does an 8 bit check sum of the passed in buffer for Len bytes.\r
1522   This is primarily used to update the check sum in the SW UNDI header.\r
1523 \r
1524 Arguments:\r
1525   Buffer            - Pointer to the passed in buffer to check sum\r
1526   Len               - Length of buffer to be check summed in bytes.\r
1527 \r
1528 Returns:\r
1529   None\r
1530 \r
1531 --*/\r
1532 {\r
1533   UINT8 Chksum;\r
1534   INT8  *Bp;\r
1535 \r
1536   Chksum = 0;\r
1537   if ((Bp = Buffer) != NULL) {\r
1538     while (Len--) {\r
1539       Chksum = (UINT8) (Chksum +*Bp++);\r
1540 \r
1541     }\r
1542 \r
1543   }\r
1544 \r
1545   return Chksum;\r
1546 }\r
1547 \r
1548 VOID\r
1549 PxeUpdate (\r
1550   IN  NIC_DATA_INSTANCE *NicPtr,\r
1551   IN PXE_SW_UNDI        *PxePtr\r
1552   )\r
1553 /*++\r
1554 \r
1555 Routine Description:\r
1556   When called with a null NicPtr, this routine decrements the number of NICs\r
1557   this UNDI is supporting and removes the NIC_DATA_POINTER from the array.\r
1558   Otherwise, it increments the number of NICs this UNDI is supported and\r
1559   updates the pxe.Fudge to ensure a proper check sum results.\r
1560 \r
1561 Arguments:\r
1562   NicPtr            - Pointer to the NIC data structure.\r
1563 \r
1564 Returns:\r
1565   None\r
1566 \r
1567 --*/\r
1568 // TODO:    PxePtr - add argument and description to function comment\r
1569 {\r
1570   if (NicPtr == NULL) {\r
1571     if (PxePtr->IFcnt > 0) {\r
1572       //\r
1573       // number of NICs this undi supports\r
1574       //\r
1575       PxePtr->IFcnt--;\r
1576     }\r
1577 \r
1578     PxePtr->Fudge = (UINT8) (PxePtr->Fudge - ChkSum ((VOID *) PxePtr, PxePtr->Len));\r
1579     return ;\r
1580   }\r
1581 \r
1582   //\r
1583   // number of NICs this undi supports\r
1584   //\r
1585   PxePtr->IFcnt++;\r
1586   PxePtr->Fudge = (UINT8) (PxePtr->Fudge - ChkSum ((VOID *) PxePtr, PxePtr->Len));\r
1587 \r
1588   return ;\r
1589 }\r
1590 \r
1591 VOID\r
1592 PxeStructInit (\r
1593   IN PXE_SW_UNDI *PxePtr,\r
1594   IN UINTN       VersionFlag\r
1595   )\r
1596 /*++\r
1597 \r
1598 Routine Description:\r
1599   Initialize the !PXE structure\r
1600 \r
1601 Arguments:\r
1602   RemainingDevicePath - Not used, always produce all possible children.\r
1603 \r
1604 Returns:\r
1605   EFI_SUCCESS         - This driver is added to Controller.\r
1606   other               - This driver does not support this device.\r
1607 \r
1608 --*/\r
1609 // TODO:    PxePtr - add argument and description to function comment\r
1610 // TODO:    VersionFlag - add argument and description to function comment\r
1611 {\r
1612   //\r
1613   // Initialize the !PXE structure\r
1614   //\r
1615   PxePtr->Signature = PXE_ROMID_SIGNATURE;\r
1616   PxePtr->Len       = sizeof (PXE_SW_UNDI);\r
1617   //\r
1618   // cksum\r
1619   //\r
1620   PxePtr->Fudge     = 0;\r
1621   //\r
1622   // number of NICs this undi supports\r
1623   //\r
1624   PxePtr->IFcnt = 0;\r
1625   PxePtr->Rev       = PXE_ROMID_REV;\r
1626   PxePtr->MajorVer  = PXE_ROMID_MAJORVER;\r
1627   PxePtr->MinorVer  = PXE_ROMID_MINORVER;\r
1628   PxePtr->reserved1 = 0;\r
1629 \r
1630   PxePtr->Implementation = PXE_ROMID_IMP_SW_VIRT_ADDR |\r
1631     PXE_ROMID_IMP_FRAG_SUPPORTED |\r
1632     PXE_ROMID_IMP_CMD_LINK_SUPPORTED |\r
1633     PXE_ROMID_IMP_NVDATA_READ_ONLY |\r
1634     PXE_ROMID_IMP_STATION_ADDR_SETTABLE |\r
1635     PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED |\r
1636     PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED |\r
1637     PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED |\r
1638     PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED |\r
1639     PXE_ROMID_IMP_SOFTWARE_INT_SUPPORTED |\r
1640     PXE_ROMID_IMP_PACKET_RX_INT_SUPPORTED;\r
1641 \r
1642   if (VersionFlag == 0x30) {\r
1643     PxePtr->EntryPoint = (UINT64) UNDI_APIEntry_old;\r
1644   } else {\r
1645     PxePtr->EntryPoint  = (UINT64) UNDI_APIEntry_new;\r
1646     PxePtr->MinorVer    = PXE_ROMID_MINORVER_31;\r
1647   }\r
1648 \r
1649   PxePtr->reserved2[0]  = 0;\r
1650   PxePtr->reserved2[1]  = 0;\r
1651   PxePtr->reserved2[2]  = 0;\r
1652   PxePtr->BusCnt        = 1;\r
1653   PxePtr->BusType[0]    = PXE_BUSTYPE_PCI;\r
1654 \r
1655   PxePtr->Fudge         = (UINT8) (PxePtr->Fudge - ChkSum ((VOID *) PxePtr, PxePtr->Len));\r
1656 }\r
1657 \r
1658 #pragma data_seg()\r