f851b9b961c78d0bc95083f5345bd2327e8c1747
[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 |= 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   PXE_DB_INITIALIZE   *DbPtr;\r
381 \r
382   if ((CdbPtr->OpFlags != PXE_OPFLAGS_INITIALIZE_DETECT_CABLE) &&\r
383       (CdbPtr->OpFlags != PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE)) {\r
384     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
385     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
386     return ;\r
387   }\r
388 \r
389   //\r
390   // check if it is already initialized\r
391   //\r
392   if (AdapterInfo->State == PXE_STATFLAGS_GET_STATE_INITIALIZED) {\r
393     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
394     CdbPtr->StatCode  = PXE_STATCODE_ALREADY_INITIALIZED;\r
395     return ;\r
396   }\r
397 \r
398   CpbPtr  = (PXE_CPB_INITIALIZE *) (UINTN) CdbPtr->CPBaddr;\r
399   DbPtr   = (PXE_DB_INITIALIZE *) (UINTN) CdbPtr->DBaddr;\r
400 \r
401   if (CpbPtr->MemoryLength < (UINT32) MEMORY_NEEDED) {\r
402     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
403     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CPB;\r
404     return ;\r
405   }\r
406 \r
407   //\r
408   // default behaviour is to detect the cable, if the 3rd param is 1,\r
409   // do not do that\r
410   //\r
411   AdapterInfo->CableDetect = (UINT8) ((CdbPtr->OpFlags == (UINT16) PXE_OPFLAGS_INITIALIZE_DO_NOT_DETECT_CABLE) ? (UINT8) 0 : (UINT8) 1);\r
412   AdapterInfo->LinkSpeedReq = (UINT16) CpbPtr->LinkSpeed;\r
413   AdapterInfo->DuplexReq    = CpbPtr->DuplexMode;\r
414   AdapterInfo->LoopBack     = CpbPtr->LoopBackMode;\r
415   AdapterInfo->MemoryPtr    = CpbPtr->MemoryAddr;\r
416   AdapterInfo->MemoryLength = CpbPtr->MemoryLength;\r
417 \r
418   CdbPtr->StatCode          = (PXE_STATCODE) E100bInit (AdapterInfo);\r
419 \r
420   if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {\r
421     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
422   } else {\r
423     AdapterInfo->State = PXE_STATFLAGS_GET_STATE_INITIALIZED;\r
424   }\r
425 \r
426   return ;\r
427 }\r
428 \r
429 VOID\r
430 UNDI_Reset (\r
431   IN  PXE_CDB           *CdbPtr,\r
432   IN  NIC_DATA_INSTANCE *AdapterInfo\r
433   )\r
434 /*++\r
435 \r
436 Routine Description:\r
437   This routine resets the network adapter and initializes the UNDI using the parameters supplied in\r
438   the CPB.  The transmit and receive queues are emptied and any pending interrupts are cleared.\r
439 \r
440   If the NIC reset fails, the CdbPtr->StatFlags are updated with PXE_STATFLAGS_COMMAND_FAILED\r
441 \r
442 Arguments:\r
443   CdbPtr            - Pointer to the command descriptor block.\r
444   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
445 \r
446 Returns:\r
447   None\r
448 \r
449 --*/\r
450 {\r
451   if (CdbPtr->OpFlags != PXE_OPFLAGS_NOT_USED &&\r
452       CdbPtr->OpFlags != PXE_OPFLAGS_RESET_DISABLE_INTERRUPTS &&\r
453       CdbPtr->OpFlags != PXE_OPFLAGS_RESET_DISABLE_FILTERS ) {\r
454 \r
455     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
456     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
457     return ;\r
458   }\r
459 \r
460   CdbPtr->StatCode = (UINT16) E100bReset (AdapterInfo, CdbPtr->OpFlags);\r
461 \r
462   if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {\r
463     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
464   }\r
465 }\r
466 \r
467 VOID\r
468 UNDI_Shutdown (\r
469   IN  PXE_CDB           *CdbPtr,\r
470   IN  NIC_DATA_INSTANCE *AdapterInfo\r
471   )\r
472 /*++\r
473 \r
474 Routine Description:\r
475   This routine resets the network adapter and leaves it in a safe state for another driver to\r
476   initialize.  Any pending transmits or receives are lost.  Receive filters and external\r
477   interrupt enables are disabled.  Once the UNDI has been shutdown, it can then be stopped\r
478   or initialized again.\r
479 \r
480   If the NIC reset fails, the CdbPtr->StatFlags are updated with PXE_STATFLAGS_COMMAND_FAILED\r
481 \r
482   Otherwise, AdapterInfo->State is updated with PXE_STATFLAGS_GET_STATE_STARTED showing the state of\r
483   the NIC as being started.\r
484 \r
485 Arguments:\r
486   CdbPtr            - Pointer to the command descriptor block.\r
487   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
488 \r
489 Returns:\r
490   None\r
491 \r
492 --*/\r
493 {\r
494   //\r
495   // do the shutdown stuff here\r
496   //\r
497   CdbPtr->StatCode = (UINT16) E100bShutdown (AdapterInfo);\r
498 \r
499   if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {\r
500     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
501   } else {\r
502     AdapterInfo->State = PXE_STATFLAGS_GET_STATE_STARTED;\r
503   }\r
504 \r
505   return ;\r
506 }\r
507 \r
508 VOID\r
509 UNDI_Interrupt (\r
510   IN  PXE_CDB           *CdbPtr,\r
511   IN  NIC_DATA_INSTANCE *AdapterInfo\r
512   )\r
513 /*++\r
514 \r
515 Routine Description:\r
516   This routine can be used to read and/or change the current external interrupt enable\r
517   settings.  Disabling an external interrupt enable prevents and external (hardware)\r
518   interrupt from being signaled by the network device.  Internally the interrupt events\r
519   can still be polled by using the UNDI_GetState command.\r
520 \r
521   The resulting information on the interrupt state will be passed back in the CdbPtr->StatFlags.\r
522 \r
523 Arguments:\r
524   CdbPtr            - Pointer to the command descriptor block.\r
525   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
526 \r
527 Returns:\r
528   None\r
529 \r
530 --*/\r
531 {\r
532   UINT8 IntMask;\r
533 \r
534   IntMask = (UINT8)(UINTN)(CdbPtr->OpFlags & (PXE_OPFLAGS_INTERRUPT_RECEIVE |\r
535                                               PXE_OPFLAGS_INTERRUPT_TRANSMIT |\r
536                                               PXE_OPFLAGS_INTERRUPT_COMMAND |\r
537                                               PXE_OPFLAGS_INTERRUPT_SOFTWARE));\r
538 \r
539   switch (CdbPtr->OpFlags & PXE_OPFLAGS_INTERRUPT_OPMASK) {\r
540   case PXE_OPFLAGS_INTERRUPT_READ:\r
541     break;\r
542 \r
543   case PXE_OPFLAGS_INTERRUPT_ENABLE:\r
544     if (IntMask == 0) {\r
545       CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
546       CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
547       return ;\r
548     }\r
549 \r
550     AdapterInfo->int_mask = IntMask;\r
551     E100bSetInterruptState (AdapterInfo);\r
552     break;\r
553 \r
554   case PXE_OPFLAGS_INTERRUPT_DISABLE:\r
555     if (IntMask != 0) {\r
556       AdapterInfo->int_mask &= ~(IntMask);\r
557       E100bSetInterruptState (AdapterInfo);\r
558       break;\r
559     }\r
560 \r
561   //\r
562   // else fall thru.\r
563   //\r
564   default:\r
565     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
566     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
567     return ;\r
568   }\r
569 \r
570   if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_RECEIVE) != 0) {\r
571     CdbPtr->StatFlags |= PXE_STATFLAGS_INTERRUPT_RECEIVE;\r
572 \r
573   }\r
574 \r
575   if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_TRANSMIT) != 0) {\r
576     CdbPtr->StatFlags |= PXE_STATFLAGS_INTERRUPT_TRANSMIT;\r
577 \r
578   }\r
579 \r
580   if ((AdapterInfo->int_mask & PXE_OPFLAGS_INTERRUPT_COMMAND) != 0) {\r
581     CdbPtr->StatFlags |= PXE_STATFLAGS_INTERRUPT_COMMAND;\r
582 \r
583   }\r
584 \r
585   return ;\r
586 }\r
587 \r
588 VOID\r
589 UNDI_RecFilter (\r
590   IN  PXE_CDB           *CdbPtr,\r
591   IN  NIC_DATA_INSTANCE *AdapterInfo\r
592   )\r
593 /*++\r
594 \r
595 Routine Description:\r
596   This routine is used to read and change receive filters and, if supported, read\r
597   and change multicast MAC address filter list.\r
598 \r
599 Arguments:\r
600   CdbPtr            - Pointer to the command descriptor block.\r
601   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
602 \r
603 Returns:\r
604   None\r
605 \r
606 --*/\r
607 {\r
608   UINT16                  NewFilter;\r
609   UINT16                  OpFlags;\r
610   PXE_DB_RECEIVE_FILTERS  *DbPtr;\r
611   UINT8                   *MacAddr;\r
612   UINTN                   MacCount;\r
613   UINT16                  Index;\r
614   UINT16                  copy_len;\r
615   UINT8                   *ptr1;\r
616   UINT8                   *ptr2;\r
617   OpFlags   = CdbPtr->OpFlags;\r
618   NewFilter = (UINT16) (OpFlags & 0x1F);\r
619 \r
620   switch (OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_OPMASK) {\r
621   case PXE_OPFLAGS_RECEIVE_FILTER_READ:\r
622 \r
623     //\r
624     // not expecting a cpb, not expecting any filter bits\r
625     //\r
626     if ((NewFilter != 0) || (CdbPtr->CPBsize != 0)) {\r
627       goto BadCdb;\r
628 \r
629     }\r
630 \r
631     if ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) == 0) {\r
632       goto JustRead;\r
633 \r
634     }\r
635 \r
636     NewFilter |= AdapterInfo->Rx_Filter;\r
637     //\r
638     // all other flags are ignored except mcast_reset\r
639     //\r
640     break;\r
641 \r
642   case PXE_OPFLAGS_RECEIVE_FILTER_ENABLE:\r
643     //\r
644     // there should be atleast one other filter bit set.\r
645     //\r
646     if (NewFilter == 0) {\r
647       //\r
648       // nothing to enable\r
649       //\r
650       goto BadCdb;\r
651     }\r
652 \r
653     if (CdbPtr->CPBsize != 0) {\r
654       //\r
655       // this must be a multicast address list!\r
656       // don't accept the list unless selective_mcast is set\r
657       // don't accept confusing mcast settings with this\r
658       //\r
659       if (((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) == 0) ||\r
660           ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||\r
661           ((NewFilter & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) ||\r
662           ((CdbPtr->CPBsize % sizeof (PXE_MAC_ADDR)) != 0) ) {\r
663         goto BadCdb;\r
664       }\r
665 \r
666       MacAddr   = (UINT8 *) ((UINTN) (CdbPtr->CPBaddr));\r
667       MacCount  = CdbPtr->CPBsize / sizeof (PXE_MAC_ADDR);\r
668 \r
669       for (; MacCount-- != 0; MacAddr += sizeof (PXE_MAC_ADDR)) {\r
670         if (MacAddr[0] != 0x01 || MacAddr[1] != 0x00 || MacAddr[2] != 0x5E || (MacAddr[3] & 0x80) != 0) {\r
671           CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
672           CdbPtr->StatCode  = PXE_STATCODE_INVALID_CPB;\r
673           return ;\r
674         }\r
675       }\r
676     }\r
677 \r
678     //\r
679     // check selective mcast case enable case\r
680     //\r
681     if ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST) != 0) {\r
682       if (((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) ||\r
683           ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_ALL_MULTICAST) != 0) ) {\r
684         goto BadCdb;\r
685 \r
686       }\r
687       //\r
688       // if no cpb, make sure we have an old list\r
689       //\r
690       if ((CdbPtr->CPBsize == 0) && (AdapterInfo->mcast_list.list_len == 0)) {\r
691         goto BadCdb;\r
692       }\r
693     }\r
694     //\r
695     // if you want to enable anything, you got to have unicast\r
696     // and you have what you already enabled!\r
697     //\r
698     NewFilter |= (PXE_OPFLAGS_RECEIVE_FILTER_UNICAST | AdapterInfo->Rx_Filter);\r
699 \r
700     break;\r
701 \r
702   case PXE_OPFLAGS_RECEIVE_FILTER_DISABLE:\r
703 \r
704     //\r
705     // mcast list not expected, i.e. no cpb here!\r
706     //\r
707     if (CdbPtr->CPBsize != PXE_CPBSIZE_NOT_USED) {\r
708       goto BadCdb;\r
709     }\r
710 \r
711     NewFilter = (UINT16) ((~(CdbPtr->OpFlags & 0x1F)) & AdapterInfo->Rx_Filter);\r
712 \r
713     break;\r
714 \r
715   default:\r
716     goto BadCdb;\r
717   }\r
718 \r
719   if ((OpFlags & PXE_OPFLAGS_RECEIVE_FILTER_RESET_MCAST_LIST) != 0) {\r
720     AdapterInfo->mcast_list.list_len = 0;\r
721     NewFilter &= (~PXE_OPFLAGS_RECEIVE_FILTER_FILTERED_MULTICAST);\r
722   }\r
723 \r
724   E100bSetfilter (AdapterInfo, NewFilter, CdbPtr->CPBaddr, CdbPtr->CPBsize);\r
725 \r
726 JustRead:\r
727   //\r
728   // give the current mcast list\r
729   //\r
730   if ((CdbPtr->DBsize != 0) && (AdapterInfo->mcast_list.list_len != 0)) {\r
731     //\r
732     // copy the mc list to db\r
733     //\r
734 \r
735     DbPtr = (PXE_DB_RECEIVE_FILTERS *) (UINTN) CdbPtr->DBaddr;\r
736     ptr1  = (UINT8 *) (&DbPtr->MCastList[0]);\r
737 \r
738     //\r
739     // DbPtr->mc_count = AdapterInfo->mcast_list.list_len;\r
740     //\r
741     copy_len = (UINT16) (AdapterInfo->mcast_list.list_len * PXE_MAC_LENGTH);\r
742 \r
743     if (copy_len > CdbPtr->DBsize) {\r
744       copy_len = CdbPtr->DBsize;\r
745 \r
746     }\r
747 \r
748     ptr2 = (UINT8 *) (&AdapterInfo->mcast_list.mc_list[0]);\r
749     for (Index = 0; Index < copy_len; Index++) {\r
750       ptr1[Index] = ptr2[Index];\r
751     }\r
752   }\r
753   //\r
754   // give the stat flags here\r
755   //\r
756   if (AdapterInfo->Receive_Started) {\r
757     CdbPtr->StatFlags |= AdapterInfo->Rx_Filter;\r
758 \r
759   }\r
760 \r
761   return ;\r
762 \r
763 BadCdb:\r
764   CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
765   CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
766 }\r
767 \r
768 VOID\r
769 UNDI_StnAddr (\r
770   IN  PXE_CDB           *CdbPtr,\r
771   IN  NIC_DATA_INSTANCE *AdapterInfo\r
772   )\r
773 /*++\r
774 \r
775 Routine Description:\r
776   This routine is used to get the current station and broadcast MAC addresses, and to change the\r
777   current station MAC address.\r
778 \r
779 Arguments:\r
780   CdbPtr            - Pointer to the command descriptor block.\r
781   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
782 \r
783 Returns:\r
784   None\r
785 \r
786 --*/\r
787 {\r
788   PXE_CPB_STATION_ADDRESS *CpbPtr;\r
789   PXE_DB_STATION_ADDRESS  *DbPtr;\r
790   UINT16                  Index;\r
791 \r
792   if (CdbPtr->OpFlags == PXE_OPFLAGS_STATION_ADDRESS_RESET) {\r
793     //\r
794     // configure the permanent address.\r
795     // change the AdapterInfo->CurrentNodeAddress field.\r
796     //\r
797     if (CompareMem (\r
798           &AdapterInfo->CurrentNodeAddress[0],\r
799           &AdapterInfo->PermNodeAddress[0],\r
800           PXE_MAC_LENGTH\r
801           ) != 0) {\r
802       for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {\r
803         AdapterInfo->CurrentNodeAddress[Index] = AdapterInfo->PermNodeAddress[Index];\r
804       }\r
805 \r
806       E100bSetupIAAddr (AdapterInfo);\r
807     }\r
808   }\r
809 \r
810   if (CdbPtr->CPBaddr != (UINT64) 0) {\r
811     CpbPtr = (PXE_CPB_STATION_ADDRESS *) (UINTN) (CdbPtr->CPBaddr);\r
812     //\r
813     // configure the new address\r
814     //\r
815     for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {\r
816       AdapterInfo->CurrentNodeAddress[Index] = CpbPtr->StationAddr[Index];\r
817     }\r
818 \r
819     E100bSetupIAAddr (AdapterInfo);\r
820   }\r
821 \r
822   if (CdbPtr->DBaddr != (UINT64) 0) {\r
823     DbPtr = (PXE_DB_STATION_ADDRESS *) (UINTN) (CdbPtr->DBaddr);\r
824     //\r
825     // fill it with the new values\r
826     //\r
827     for (Index = 0; Index < PXE_MAC_LENGTH; Index++) {\r
828       DbPtr->StationAddr[Index]   = AdapterInfo->CurrentNodeAddress[Index];\r
829       DbPtr->BroadcastAddr[Index] = AdapterInfo->BroadcastNodeAddress[Index];\r
830       DbPtr->PermanentAddr[Index] = AdapterInfo->PermNodeAddress[Index];\r
831     }\r
832   }\r
833 \r
834   return ;\r
835 }\r
836 \r
837 VOID\r
838 UNDI_Statistics (\r
839   IN  PXE_CDB           *CdbPtr,\r
840   IN  NIC_DATA_INSTANCE *AdapterInfo\r
841   )\r
842 /*++\r
843 \r
844 Routine Description:\r
845   This routine is used to read and clear the NIC traffic statistics.  This command is supported only\r
846   if the !PXE structure's Implementation flags say so.\r
847 \r
848   Results will be parsed out in the following manner:\r
849   CdbPtr->DBaddr.Data[0]   R  Total Frames (Including frames with errors and dropped frames)\r
850   CdbPtr->DBaddr.Data[1]   R  Good Frames (All frames copied into receive buffer)\r
851   CdbPtr->DBaddr.Data[2]   R  Undersize Frames (Frames below minimum length for media <64 for ethernet)\r
852   CdbPtr->DBaddr.Data[4]   R  Dropped Frames (Frames that were dropped because receive buffers were full)\r
853   CdbPtr->DBaddr.Data[8]   R  CRC Error Frames (Frames with alignment or CRC errors)\r
854   CdbPtr->DBaddr.Data[A]   T  Total Frames (Including frames with errors and dropped frames)\r
855   CdbPtr->DBaddr.Data[B]   T  Good Frames (All frames copied into transmit buffer)\r
856   CdbPtr->DBaddr.Data[C]   T  Undersize Frames (Frames below minimum length for media <64 for ethernet)\r
857   CdbPtr->DBaddr.Data[E]   T  Dropped Frames (Frames that were dropped because of collisions)\r
858   CdbPtr->DBaddr.Data[14]  T  Total Collision Frames (Total collisions on this subnet)\r
859 \r
860 Arguments:\r
861   CdbPtr            - Pointer to the command descriptor block.\r
862   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
863 \r
864 Returns:\r
865   None\r
866 \r
867 --*/\r
868 {\r
869   if ((CdbPtr->OpFlags &~(PXE_OPFLAGS_STATISTICS_RESET)) != 0) {\r
870     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
871     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
872     return ;\r
873   }\r
874 \r
875   if ((CdbPtr->OpFlags & PXE_OPFLAGS_STATISTICS_RESET) != 0) {\r
876     //\r
877     // Reset the statistics\r
878     //\r
879     CdbPtr->StatCode = (UINT16) E100bStatistics (AdapterInfo, 0, 0);\r
880   } else {\r
881     CdbPtr->StatCode = (UINT16) E100bStatistics (AdapterInfo, CdbPtr->DBaddr, CdbPtr->DBsize);\r
882   }\r
883 \r
884   return ;\r
885 }\r
886 \r
887 VOID\r
888 UNDI_ip2mac (\r
889   IN  PXE_CDB           *CdbPtr,\r
890   IN  NIC_DATA_INSTANCE *AdapterInfo\r
891   )\r
892 /*++\r
893 \r
894 Routine Description:\r
895   This routine is used to translate a multicast IP address to a multicast MAC address.\r
896 \r
897   This results in a MAC address composed of 25 bits of fixed data with the upper 23 bits of the IP\r
898   address being appended to it.  Results passed back in the equivalent of CdbPtr->DBaddr->MAC[0-5].\r
899 \r
900 Arguments:\r
901   CdbPtr            - Pointer to the command descriptor block.\r
902   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
903 \r
904 Returns:\r
905   None\r
906 \r
907 --*/\r
908 {\r
909   PXE_CPB_MCAST_IP_TO_MAC *CpbPtr;\r
910   PXE_DB_MCAST_IP_TO_MAC  *DbPtr;\r
911   UINT8                   *TmpPtr;\r
912 \r
913   CpbPtr  = (PXE_CPB_MCAST_IP_TO_MAC *) (UINTN) CdbPtr->CPBaddr;\r
914   DbPtr   = (PXE_DB_MCAST_IP_TO_MAC *) (UINTN) CdbPtr->DBaddr;\r
915 \r
916   if ((CdbPtr->OpFlags & PXE_OPFLAGS_MCAST_IPV6_TO_MAC) != 0) {\r
917     //\r
918     // for now this is not supported\r
919     //\r
920     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
921     CdbPtr->StatCode  = PXE_STATCODE_UNSUPPORTED;\r
922     return ;\r
923   }\r
924 \r
925   TmpPtr = (UINT8 *) (&CpbPtr->IP.IPv4);\r
926   //\r
927   // check if the ip given is a mcast IP\r
928   //\r
929   if ((TmpPtr[0] & 0xF0) != 0xE0) {\r
930     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
931     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CPB;\r
932   }\r
933   //\r
934   // take the last 23 bits in IP.\r
935   // be very careful. accessing word on a non-word boundary will hang motherboard codenamed Big Sur\r
936   // casting the mac array (in the middle) to a UINT32 pointer and accessing\r
937   // the UINT32 content hung the system...\r
938   //\r
939   DbPtr->MAC[0] = 0x01;\r
940   DbPtr->MAC[1] = 0x00;\r
941   DbPtr->MAC[2] = 0x5e;\r
942   DbPtr->MAC[3] = (UINT8) (TmpPtr[1] & 0x7f);\r
943   DbPtr->MAC[4] = (UINT8) TmpPtr[2];\r
944   DbPtr->MAC[5] = (UINT8) TmpPtr[3];\r
945 \r
946   return ;\r
947 }\r
948 \r
949 VOID\r
950 UNDI_NVData (\r
951   IN  PXE_CDB           *CdbPtr,\r
952   IN  NIC_DATA_INSTANCE *AdapterInfo\r
953   )\r
954 /*++\r
955 \r
956 Routine Description:\r
957   This routine is used to read and write non-volatile storage on the NIC (if supported).  The NVRAM\r
958   could be EEPROM, FLASH, or battery backed RAM.\r
959 \r
960   This is an optional function according to the UNDI specification  (or will be......)\r
961 \r
962 Arguments:\r
963   CdbPtr            - Pointer to the command descriptor block.\r
964   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
965 \r
966 Returns:\r
967   None\r
968 \r
969 --*/\r
970 {\r
971   PXE_DB_NVDATA *DbPtr;\r
972   UINT16        Index;\r
973 \r
974   if ((CdbPtr->OpFlags == PXE_OPFLAGS_NVDATA_READ) != 0) {\r
975 \r
976     if ((CdbPtr->DBsize == PXE_DBSIZE_NOT_USED) != 0) {\r
977       CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
978       CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
979       return ;\r
980     }\r
981 \r
982     DbPtr = (PXE_DB_NVDATA *) (UINTN) CdbPtr->DBaddr;\r
983 \r
984     for (Index = 0; Index < MAX_PCI_CONFIG_LEN; Index++) {\r
985       DbPtr->Data.Dword[Index] = AdapterInfo->NVData[Index];\r
986 \r
987     }\r
988 \r
989   } else {\r
990     //\r
991     // no write for now\r
992     //\r
993     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
994     CdbPtr->StatCode  = PXE_STATCODE_UNSUPPORTED;\r
995   }\r
996 \r
997   return ;\r
998 }\r
999 \r
1000 VOID\r
1001 UNDI_Status (\r
1002   IN  PXE_CDB           *CdbPtr,\r
1003   IN  NIC_DATA_INSTANCE *AdapterInfo\r
1004   )\r
1005 /*++\r
1006 \r
1007 Routine Description:\r
1008   This routine returns the current interrupt status and/or the transmitted buffer addresses.\r
1009   If the current interrupt status is returned, pending interrupts will be acknowledged by this\r
1010   command.  Transmitted buffer addresses that are written to the DB are removed from the transmit\r
1011   buffer queue.\r
1012 \r
1013   Normally, this command would be polled with interrupts disabled.\r
1014 \r
1015   The transmit buffers are returned in CdbPtr->DBaddr->TxBufer[0 - NumEntries].\r
1016   The interrupt status is returned in CdbPtr->StatFlags.\r
1017 \r
1018 Arguments:\r
1019   CdbPtr            - Pointer to the command descriptor block.\r
1020   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
1021 \r
1022 Returns:\r
1023   None\r
1024 \r
1025 --*/\r
1026 {\r
1027   PXE_DB_GET_STATUS *DbPtr;\r
1028   PXE_DB_GET_STATUS TmpGetStatus;\r
1029   UINT16            Index;\r
1030   UINT16            Status;\r
1031   UINT16            NumEntries;\r
1032   RxFD              *RxPtr;\r
1033 \r
1034   //\r
1035   // Fill in temporary GetStatus storage.\r
1036   //\r
1037   RxPtr = &AdapterInfo->rx_ring[AdapterInfo->cur_rx_ind];\r
1038 \r
1039   if ((RxPtr->cb_header.status & RX_COMPLETE) != 0) {\r
1040     TmpGetStatus.RxFrameLen = RxPtr->ActualCount & 0x3fff;\r
1041   } else {\r
1042     TmpGetStatus.RxFrameLen = 0;\r
1043   }\r
1044 \r
1045   TmpGetStatus.reserved = 0;\r
1046 \r
1047   //\r
1048   // Fill in size of next available receive packet and\r
1049   // reserved field in caller's DB storage.\r
1050   //\r
1051   DbPtr = (PXE_DB_GET_STATUS *) (UINTN) CdbPtr->DBaddr;\r
1052 \r
1053   if (CdbPtr->DBsize > 0 && CdbPtr->DBsize < sizeof (UINT32) * 2) {\r
1054     CopyMem (DbPtr, &TmpGetStatus, CdbPtr->DBsize);\r
1055   } else {\r
1056     CopyMem (DbPtr, &TmpGetStatus, sizeof (UINT32) * 2);\r
1057   }\r
1058 \r
1059   //\r
1060   //\r
1061   //\r
1062   if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_TRANSMITTED_BUFFERS) != 0) {\r
1063     //\r
1064     // DBsize of zero is invalid if Tx buffers are requested.\r
1065     //\r
1066     if (CdbPtr->DBsize == 0) {\r
1067       CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1068       CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
1069       return ;\r
1070     }\r
1071 \r
1072     //\r
1073     // remember this b4 we overwrite\r
1074     //\r
1075     NumEntries = (UINT16) (CdbPtr->DBsize - sizeof (UINT64));\r
1076 \r
1077     //\r
1078     // We already filled in 2 UINT32s.\r
1079     //\r
1080     CdbPtr->DBsize = sizeof (UINT32) * 2;\r
1081 \r
1082     //\r
1083     // will claim any hanging free CBs\r
1084     //\r
1085     CheckCBList (AdapterInfo);\r
1086 \r
1087     if (AdapterInfo->xmit_done_head == AdapterInfo->xmit_done_tail) {\r
1088       CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_TXBUF_QUEUE_EMPTY;\r
1089     } else {\r
1090       for (Index = 0; NumEntries >= sizeof (UINT64); Index++, NumEntries -= sizeof (UINT64)) {\r
1091         if (AdapterInfo->xmit_done_head != AdapterInfo->xmit_done_tail) {\r
1092           DbPtr->TxBuffer[Index]      = AdapterInfo->xmit_done[AdapterInfo->xmit_done_head];\r
1093           AdapterInfo->xmit_done_head = next (AdapterInfo->xmit_done_head);\r
1094           CdbPtr->DBsize += sizeof (UINT64);\r
1095         } else {\r
1096           break;\r
1097         }\r
1098       }\r
1099     }\r
1100 \r
1101     if (AdapterInfo->xmit_done_head != AdapterInfo->xmit_done_tail) {\r
1102       CdbPtr->StatFlags |= PXE_STATFLAGS_DB_WRITE_TRUNCATED;\r
1103 \r
1104     }\r
1105     //\r
1106     // check for a receive buffer and give it's size in db\r
1107     //\r
1108   }\r
1109   //\r
1110   //\r
1111   //\r
1112   if ((CdbPtr->OpFlags & PXE_OPFLAGS_GET_INTERRUPT_STATUS) != 0) {\r
1113 \r
1114     Status = InWord (AdapterInfo, AdapterInfo->ioaddr + SCBStatus);\r
1115     AdapterInfo->Int_Status |= Status;\r
1116 \r
1117     //\r
1118     // acknoledge the interrupts\r
1119     //\r
1120     OutWord (AdapterInfo, (UINT16) (Status & 0xfc00), (UINT32) (AdapterInfo->ioaddr + SCBStatus));\r
1121 \r
1122     //\r
1123     // report all the outstanding interrupts\r
1124     //\r
1125     Status = AdapterInfo->Int_Status;\r
1126     if ((Status & SCB_STATUS_FR) != 0) {\r
1127       CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_RECEIVE;\r
1128     }\r
1129 \r
1130     if ((Status & SCB_STATUS_SWI) != 0) {\r
1131       CdbPtr->StatFlags |= PXE_STATFLAGS_GET_STATUS_SOFTWARE;\r
1132     }\r
1133   }\r
1134 \r
1135   return ;\r
1136 }\r
1137 \r
1138 VOID\r
1139 UNDI_FillHeader (\r
1140   IN  PXE_CDB           *CdbPtr,\r
1141   IN  NIC_DATA_INSTANCE *AdapterInfo\r
1142   )\r
1143 /*++\r
1144 \r
1145 Routine Description:\r
1146   This routine is used to fill media header(s) in transmit packet(s).\r
1147   Copies the MAC address into the media header whether it is dealing\r
1148   with fragmented or non-fragmented packets.\r
1149 \r
1150 Arguments:\r
1151   CdbPtr            - Pointer to the command descriptor block.\r
1152   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
1153 \r
1154 Returns:\r
1155   None\r
1156 \r
1157 --*/\r
1158 {\r
1159   PXE_CPB_FILL_HEADER             *Cpb;\r
1160   PXE_CPB_FILL_HEADER_FRAGMENTED  *Cpbf;\r
1161   EtherHeader                     *MacHeader;\r
1162   UINTN                           Index;\r
1163 \r
1164   if (CdbPtr->CPBsize == PXE_CPBSIZE_NOT_USED) {\r
1165     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1166     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
1167     return ;\r
1168   }\r
1169 \r
1170   if ((CdbPtr->OpFlags & PXE_OPFLAGS_FILL_HEADER_FRAGMENTED) != 0) {\r
1171     Cpbf = (PXE_CPB_FILL_HEADER_FRAGMENTED *) (UINTN) CdbPtr->CPBaddr;\r
1172 \r
1173     //\r
1174     // assume 1st fragment is big enough for the mac header\r
1175     //\r
1176     if ((Cpbf->FragCnt == 0) || (Cpbf->FragDesc[0].FragLen < PXE_MAC_HEADER_LEN_ETHER)) {\r
1177       //\r
1178       // no buffers given\r
1179       //\r
1180       CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1181       CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
1182       return ;\r
1183     }\r
1184 \r
1185     MacHeader = (EtherHeader *) (UINTN) Cpbf->FragDesc[0].FragAddr;\r
1186     //\r
1187     // we don't swap the protocol bytes\r
1188     //\r
1189     MacHeader->type = Cpbf->Protocol;\r
1190 \r
1191     for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {\r
1192       MacHeader->dest_addr[Index] = Cpbf->DestAddr[Index];\r
1193       MacHeader->src_addr[Index]  = Cpbf->SrcAddr[Index];\r
1194     }\r
1195   } else {\r
1196     Cpb       = (PXE_CPB_FILL_HEADER *) (UINTN) CdbPtr->CPBaddr;\r
1197 \r
1198     MacHeader = (EtherHeader *) (UINTN) Cpb->MediaHeader;\r
1199     //\r
1200     // we don't swap the protocol bytes\r
1201     //\r
1202     MacHeader->type = Cpb->Protocol;\r
1203 \r
1204     for (Index = 0; Index < PXE_HWADDR_LEN_ETHER; Index++) {\r
1205       MacHeader->dest_addr[Index] = Cpb->DestAddr[Index];\r
1206       MacHeader->src_addr[Index]  = Cpb->SrcAddr[Index];\r
1207     }\r
1208   }\r
1209 \r
1210   return ;\r
1211 }\r
1212 \r
1213 VOID\r
1214 UNDI_Transmit (\r
1215   IN  PXE_CDB           *CdbPtr,\r
1216   IN  NIC_DATA_INSTANCE *AdapterInfo\r
1217   )\r
1218 /*++\r
1219 \r
1220 Routine Description:\r
1221   This routine is used to place a packet into the transmit queue.  The data buffers given to\r
1222   this command are to be considered locked and the application or network driver loses\r
1223   ownership of these buffers and must not free or relocate them until the ownership returns.\r
1224 \r
1225   When the packets are transmitted, a transmit complete interrupt is generated (if interrupts\r
1226   are disabled, the transmit interrupt status is still set and can be checked using the UNDI_Status\r
1227   command.\r
1228 \r
1229   Some implementations and adapters support transmitting multiple packets with one transmit\r
1230   command.  If this feature is supported, the transmit CPBs can be linked in one transmit\r
1231   command.\r
1232 \r
1233   All UNDIs support fragmented frames, now all network devices or protocols do.  If a fragmented\r
1234   frame CPB is given to UNDI and the network device does not support fragmented frames\r
1235   (see !PXE.Implementation flag), the UNDI will have to copy the fragments into a local buffer\r
1236   before transmitting.\r
1237 \r
1238 \r
1239 Arguments:\r
1240   CdbPtr            - Pointer to the command descriptor block.\r
1241   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
1242 \r
1243 Returns:\r
1244   None\r
1245 \r
1246 --*/\r
1247 {\r
1248 \r
1249   if (CdbPtr->CPBsize == PXE_CPBSIZE_NOT_USED) {\r
1250     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1251     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
1252     return ;\r
1253   }\r
1254 \r
1255   CdbPtr->StatCode = (PXE_STATCODE) E100bTransmit (AdapterInfo, CdbPtr->CPBaddr, CdbPtr->OpFlags);\r
1256 \r
1257   if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {\r
1258     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1259   }\r
1260 \r
1261   return ;\r
1262 }\r
1263 \r
1264 VOID\r
1265 UNDI_Receive (\r
1266   IN  PXE_CDB           *CdbPtr,\r
1267   IN  NIC_DATA_INSTANCE *AdapterInfo\r
1268   )\r
1269 /*++\r
1270 \r
1271 Routine Description:\r
1272   When the network adapter has received a frame, this command is used to copy the frame\r
1273   into the driver/application storage location.  Once a frame has been copied, it is\r
1274   removed from the receive queue.\r
1275 \r
1276 Arguments:\r
1277   CdbPtr            - Pointer to the command descriptor block.\r
1278   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
1279 \r
1280 Returns:\r
1281   None\r
1282 \r
1283 --*/\r
1284 {\r
1285   PXE_CPB_RECEIVE *cpbptr;\r
1286 \r
1287   //\r
1288   // check if RU has started...\r
1289   //\r
1290   if (!AdapterInfo->Receive_Started) {\r
1291     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1292     CdbPtr->StatCode  = PXE_STATCODE_NOT_INITIALIZED;\r
1293     return ;\r
1294   }\r
1295 \r
1296   cpbptr            = (PXE_CPB_RECEIVE *) (UINTN) CdbPtr->CPBaddr;\r
1297 \r
1298   CdbPtr->StatCode  = (UINT16) E100bReceive (AdapterInfo, CdbPtr->CPBaddr, CdbPtr->DBaddr);\r
1299   if (CdbPtr->StatCode != PXE_STATCODE_SUCCESS) {\r
1300     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1301 \r
1302   }\r
1303 \r
1304   return ;\r
1305 }\r
1306 \r
1307 VOID\r
1308 UNDI_APIEntry_old (\r
1309   IN  UINT64 cdb\r
1310   )\r
1311 /*++\r
1312 \r
1313 Routine Description:\r
1314   This is the main SW UNDI API entry using the older nii protocol.\r
1315   The parameter passed in is a 64 bit flat model virtual\r
1316   address of the cdb.  We then jump into the common routine for both old and\r
1317   new nii protocol entries.\r
1318 \r
1319 Arguments:\r
1320   CdbPtr            - Pointer to the command descriptor block.\r
1321   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
1322 \r
1323 Returns:\r
1324   None\r
1325 \r
1326 --*/\r
1327 // TODO:    cdb - add argument and description to function comment\r
1328 {\r
1329   PXE_CDB           *CdbPtr;\r
1330   NIC_DATA_INSTANCE *AdapterInfo;\r
1331 \r
1332   if (cdb == (UINT64) 0) {\r
1333     return ;\r
1334 \r
1335   }\r
1336 \r
1337   CdbPtr = (PXE_CDB *) (UINTN) cdb;\r
1338 \r
1339   if (CdbPtr->IFnum >= pxe->IFcnt) {\r
1340     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1341     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
1342     return ;\r
1343   }\r
1344 \r
1345   AdapterInfo               = &(UNDI32DeviceList[CdbPtr->IFnum]->NicInfo);\r
1346   \r
1347   //\r
1348   // entering from older entry point\r
1349   //\r
1350   AdapterInfo->VersionFlag  = 0x30;\r
1351   UNDI_APIEntry_Common (cdb);\r
1352 }\r
1353 \r
1354 VOID\r
1355 UNDI_APIEntry_new (\r
1356   IN  UINT64 cdb\r
1357   )\r
1358 /*++\r
1359 \r
1360 Routine Description:\r
1361   This is the main SW UNDI API entry using the newer nii protocol.\r
1362   The parameter passed in is a 64 bit flat model virtual\r
1363   address of the cdb.  We then jump into the common routine for both old and\r
1364   new nii protocol entries.\r
1365 \r
1366 Arguments:\r
1367   CdbPtr            - Pointer to the command descriptor block.\r
1368   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
1369 \r
1370 Returns:\r
1371   None\r
1372 \r
1373 --*/\r
1374 // TODO:    cdb - add argument and description to function comment\r
1375 {\r
1376   PXE_CDB           *CdbPtr;\r
1377   NIC_DATA_INSTANCE *AdapterInfo;\r
1378 \r
1379   if (cdb == (UINT64) 0) {\r
1380     return ;\r
1381 \r
1382   }\r
1383 \r
1384   CdbPtr = (PXE_CDB *) (UINTN) cdb;\r
1385 \r
1386   if (CdbPtr->IFnum >= pxe_31->IFcnt) {\r
1387     CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1388     CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
1389     return ;\r
1390   }\r
1391 \r
1392   AdapterInfo               = &(UNDI32DeviceList[CdbPtr->IFnum]->NicInfo);\r
1393   //\r
1394   // entering from older entry point\r
1395   //\r
1396   AdapterInfo->VersionFlag  = 0x31;\r
1397   UNDI_APIEntry_Common (cdb);\r
1398 }\r
1399 \r
1400 VOID\r
1401 UNDI_APIEntry_Common (\r
1402   IN  UINT64 cdb\r
1403   )\r
1404 /*++\r
1405 \r
1406 Routine Description:\r
1407   This is the common routine for both old and new entry point procedures.\r
1408   The parameter passed in is a 64 bit flat model virtual\r
1409   address of the cdb.  We then jump into the service routine pointed to by the\r
1410   Api_Table[OpCode].\r
1411 \r
1412 Arguments:\r
1413   CdbPtr            - Pointer to the command descriptor block.\r
1414   AdapterInfo       - Pointer to the NIC data structure information which the UNDI driver is layering on..\r
1415 \r
1416 Returns:\r
1417   None\r
1418 \r
1419 --*/\r
1420 // TODO:    cdb - add argument and description to function comment\r
1421 {\r
1422   PXE_CDB           *CdbPtr;\r
1423   NIC_DATA_INSTANCE *AdapterInfo;\r
1424   UNDI_CALL_TABLE   *tab_ptr;\r
1425 \r
1426   CdbPtr = (PXE_CDB *) (UINTN) cdb;\r
1427 \r
1428   //\r
1429   // check the OPCODE range\r
1430   //\r
1431   if ((CdbPtr->OpCode > PXE_OPCODE_LAST_VALID) ||\r
1432       (CdbPtr->StatCode != PXE_STATCODE_INITIALIZE) ||\r
1433       (CdbPtr->StatFlags != PXE_STATFLAGS_INITIALIZE) ||\r
1434       (CdbPtr->IFnum >= pxe_31->IFcnt) ) {\r
1435     goto badcdb;\r
1436 \r
1437   }\r
1438 \r
1439   if (CdbPtr->CPBsize == PXE_CPBSIZE_NOT_USED) {\r
1440     if (CdbPtr->CPBaddr != PXE_CPBADDR_NOT_USED) {\r
1441       goto badcdb;\r
1442     }\r
1443   } else if (CdbPtr->CPBaddr == PXE_CPBADDR_NOT_USED) {\r
1444     goto badcdb;\r
1445   }\r
1446 \r
1447   if (CdbPtr->DBsize == PXE_DBSIZE_NOT_USED) {\r
1448     if (CdbPtr->DBaddr != PXE_DBADDR_NOT_USED) {\r
1449       goto badcdb;\r
1450     }\r
1451   } else if (CdbPtr->DBaddr == PXE_DBADDR_NOT_USED) {\r
1452     goto badcdb;\r
1453   }\r
1454 \r
1455   //\r
1456   // check if cpbsize and dbsize are as needed\r
1457   // check if opflags are as expected\r
1458   //\r
1459   tab_ptr = &api_table[CdbPtr->OpCode];\r
1460 \r
1461   if (tab_ptr->cpbsize != (UINT16) (DONT_CHECK) && tab_ptr->cpbsize != CdbPtr->CPBsize) {\r
1462     goto badcdb;\r
1463   }\r
1464 \r
1465   if (tab_ptr->dbsize != (UINT16) (DONT_CHECK) && tab_ptr->dbsize != CdbPtr->DBsize) {\r
1466     goto badcdb;\r
1467   }\r
1468 \r
1469   if (tab_ptr->opflags != (UINT16) (DONT_CHECK) && tab_ptr->opflags != CdbPtr->OpFlags) {\r
1470     goto badcdb;\r
1471 \r
1472   }\r
1473 \r
1474   AdapterInfo = &(UNDI32DeviceList[CdbPtr->IFnum]->NicInfo);\r
1475 \r
1476   //\r
1477   // check if UNDI_State is valid for this call\r
1478   //\r
1479   if (tab_ptr->state != (UINT16) (-1)) {\r
1480     //\r
1481     // should atleast be started\r
1482     //\r
1483     if (AdapterInfo->State == PXE_STATFLAGS_GET_STATE_STOPPED) {\r
1484       CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1485       CdbPtr->StatCode  = PXE_STATCODE_NOT_STARTED;\r
1486       return ;\r
1487     }\r
1488     //\r
1489     // check if it should be initialized\r
1490     //\r
1491     if (tab_ptr->state == 2) {\r
1492       if (AdapterInfo->State != PXE_STATFLAGS_GET_STATE_INITIALIZED) {\r
1493         CdbPtr->StatCode  = PXE_STATCODE_NOT_INITIALIZED;\r
1494         CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1495         return ;\r
1496       }\r
1497     }\r
1498   }\r
1499   //\r
1500   // set the return variable for success case here\r
1501   //\r
1502   CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;\r
1503   CdbPtr->StatCode  = PXE_STATCODE_SUCCESS;\r
1504 \r
1505   tab_ptr->api_ptr (CdbPtr, AdapterInfo);\r
1506   return ;\r
1507   //\r
1508   // %% AVL - check for command linking\r
1509   //\r
1510 badcdb:\r
1511   CdbPtr->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;\r
1512   CdbPtr->StatCode  = PXE_STATCODE_INVALID_CDB;\r
1513   return ;\r
1514 }\r
1515 \r
1516 UINT8\r
1517 ChkSum (\r
1518   IN  VOID   *Buffer,\r
1519   IN  UINT16 Len\r
1520   )\r
1521 /*++\r
1522 \r
1523 Routine Description:\r
1524   This does an 8 bit check sum of the passed in buffer for Len bytes.\r
1525   This is primarily used to update the check sum in the SW UNDI header.\r
1526 \r
1527 Arguments:\r
1528   Buffer            - Pointer to the passed in buffer to check sum\r
1529   Len               - Length of buffer to be check summed in bytes.\r
1530 \r
1531 Returns:\r
1532   None\r
1533 \r
1534 --*/\r
1535 {\r
1536   UINT8 Chksum;\r
1537   INT8  *Bp;\r
1538 \r
1539   Chksum = 0;\r
1540   if ((Bp = Buffer) != NULL) {\r
1541     while (Len--) {\r
1542       Chksum = (UINT8) (Chksum +*Bp++);\r
1543 \r
1544     }\r
1545 \r
1546   }\r
1547 \r
1548   return Chksum;\r
1549 }\r
1550 \r
1551 VOID\r
1552 PxeUpdate (\r
1553   IN  NIC_DATA_INSTANCE *NicPtr,\r
1554   IN PXE_SW_UNDI        *PxePtr\r
1555   )\r
1556 /*++\r
1557 \r
1558 Routine Description:\r
1559   When called with a null NicPtr, this routine decrements the number of NICs\r
1560   this UNDI is supporting and removes the NIC_DATA_POINTER from the array.\r
1561   Otherwise, it increments the number of NICs this UNDI is supported and\r
1562   updates the pxe.Fudge to ensure a proper check sum results.\r
1563 \r
1564 Arguments:\r
1565   NicPtr            - Pointer to the NIC data structure.\r
1566 \r
1567 Returns:\r
1568   None\r
1569 \r
1570 --*/\r
1571 // TODO:    PxePtr - add argument and description to function comment\r
1572 {\r
1573   if (NicPtr == NULL) {\r
1574     if (PxePtr->IFcnt > 0) {\r
1575       //\r
1576       // number of NICs this undi supports\r
1577       //\r
1578       PxePtr->IFcnt--;\r
1579     }\r
1580 \r
1581     PxePtr->Fudge = (UINT8) (PxePtr->Fudge - ChkSum ((VOID *) PxePtr, PxePtr->Len));\r
1582     return ;\r
1583   }\r
1584 \r
1585   //\r
1586   // number of NICs this undi supports\r
1587   //\r
1588   PxePtr->IFcnt++;\r
1589   PxePtr->Fudge = (UINT8) (PxePtr->Fudge - ChkSum ((VOID *) PxePtr, PxePtr->Len));\r
1590 \r
1591   return ;\r
1592 }\r
1593 \r
1594 VOID\r
1595 PxeStructInit (\r
1596   IN PXE_SW_UNDI *PxePtr,\r
1597   IN UINTN       VersionFlag\r
1598   )\r
1599 /*++\r
1600 \r
1601 Routine Description:\r
1602   Initialize the !PXE structure\r
1603 \r
1604 Arguments:\r
1605   RemainingDevicePath - Not used, always produce all possible children.\r
1606 \r
1607 Returns:\r
1608   EFI_SUCCESS         - This driver is added to Controller.\r
1609   other               - This driver does not support this device.\r
1610 \r
1611 --*/\r
1612 // TODO:    PxePtr - add argument and description to function comment\r
1613 // TODO:    VersionFlag - add argument and description to function comment\r
1614 {\r
1615   //\r
1616   // Initialize the !PXE structure\r
1617   //\r
1618   PxePtr->Signature = PXE_ROMID_SIGNATURE;\r
1619   PxePtr->Len       = sizeof (PXE_SW_UNDI);\r
1620   //\r
1621   // cksum\r
1622   //\r
1623   PxePtr->Fudge     = 0;\r
1624   //\r
1625   // number of NICs this undi supports\r
1626   //\r
1627   PxePtr->IFcnt = 0;\r
1628   PxePtr->Rev       = PXE_ROMID_REV;\r
1629   PxePtr->MajorVer  = PXE_ROMID_MAJORVER;\r
1630   PxePtr->MinorVer  = PXE_ROMID_MINORVER;\r
1631   PxePtr->reserved1 = 0;\r
1632 \r
1633   PxePtr->Implementation = PXE_ROMID_IMP_SW_VIRT_ADDR |\r
1634     PXE_ROMID_IMP_FRAG_SUPPORTED |\r
1635     PXE_ROMID_IMP_CMD_LINK_SUPPORTED |\r
1636     PXE_ROMID_IMP_NVDATA_READ_ONLY |\r
1637     PXE_ROMID_IMP_STATION_ADDR_SETTABLE |\r
1638     PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED |\r
1639     PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED |\r
1640     PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED |\r
1641     PXE_ROMID_IMP_FILTERED_MULTICAST_RX_SUPPORTED |\r
1642     PXE_ROMID_IMP_SOFTWARE_INT_SUPPORTED |\r
1643     PXE_ROMID_IMP_PACKET_RX_INT_SUPPORTED;\r
1644 \r
1645   if (VersionFlag == 0x30) {\r
1646     PxePtr->EntryPoint = (UINT64) UNDI_APIEntry_old;\r
1647   } else {\r
1648     PxePtr->EntryPoint  = (UINT64) UNDI_APIEntry_new;\r
1649     PxePtr->MinorVer    = PXE_ROMID_MINORVER_31;\r
1650   }\r
1651 \r
1652   PxePtr->reserved2[0]  = 0;\r
1653   PxePtr->reserved2[1]  = 0;\r
1654   PxePtr->reserved2[2]  = 0;\r
1655   PxePtr->BusCnt        = 1;\r
1656   PxePtr->BusType[0]    = PXE_BUSTYPE_PCI;\r
1657 \r
1658   PxePtr->Fudge         = (UINT8) (PxePtr->Fudge - ChkSum ((VOID *) PxePtr, PxePtr->Len));\r
1659 }\r
1660 \r
1661 #pragma data_seg()\r