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