1 /*
2 * PROJECT: ReactOS DC21x4 Driver
3 * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4 * PURPOSE: EEPROM manipulation and parsing
5 * COPYRIGHT: Copyright 2023 Dmitry Borisov <di.sean@protonmail.com>
6 */
7
8 /* INCLUDES *******************************************************************/
9
10 #include "dc21x4.h"
11
12 #include <debug.h>
13
14 /* GLOBALS ********************************************************************/
15
16 #define SROM_READ(Adapter, Data) \
17 do { \
18 *Data = DC_READ((Adapter), DcCsr9_SerialInterface); \
19 NdisStallExecution(10); \
20 } while (0)
21
22 #define SROM_WRITE(Adapter, Value) \
23 do { \
24 DC_WRITE((Adapter), DcCsr9_SerialInterface, Value); \
25 NdisStallExecution(10); \
26 } while (0)
27
28 extern DC_PG_DATA DC_SROM_REPAIR_ENTRY SRompRepairData[];
29
30 LIST_ENTRY SRompAdapterList;
31
32 _Interlocked_
33 static volatile LONG SRompAdapterLock = 0;
34
35 /* PRIVATE FUNCTIONS **********************************************************/
36
37 static
38 CODE_SEG("PAGE")
39 VOID
SRomAcquireListMutex(VOID)40 SRomAcquireListMutex(VOID)
41 {
42 PAGED_CODE();
43
44 while (_InterlockedCompareExchange(&SRompAdapterLock, 1, 0))
45 {
46 NdisMSleep(10);
47 }
48 }
49
50 static inline
51 CODE_SEG("PAGE")
52 VOID
SRomReleaseListMutex(VOID)53 SRomReleaseListMutex(VOID)
54 {
55 PAGED_CODE();
56
57 _InterlockedDecrement(&SRompAdapterLock);
58 }
59
60 static
61 CODE_SEG("PAGE")
62 BOOLEAN
SRomIsAdapterInList(_In_ PDC21X4_ADAPTER Adapter,_In_ BOOLEAN SearchForMaster,_Out_opt_ PDC_SROM_ENTRY * FoundEntry)63 SRomIsAdapterInList(
64 _In_ PDC21X4_ADAPTER Adapter,
65 _In_ BOOLEAN SearchForMaster,
66 _Out_opt_ PDC_SROM_ENTRY* FoundEntry)
67 {
68 PLIST_ENTRY PrevEntry;
69 PDC_SROM_ENTRY SRomEntry;
70
71 PAGED_CODE();
72
73 /* Loop the adapter list backwards */
74 for (PrevEntry = (&SRompAdapterList)->Blink;
75 PrevEntry != &SRompAdapterList;
76 PrevEntry = PrevEntry->Blink)
77 {
78 SRomEntry = CONTAINING_RECORD(PrevEntry, DC_SROM_ENTRY, ListEntry);
79
80 if ((SRomEntry->ChipType == Adapter->ChipType) &&
81 (SRomEntry->BusNumber == Adapter->BusNumber) &&
82 (!SearchForMaster || (SRomEntry->DeviceNumber == Adapter->DeviceNumber)))
83 {
84 if (FoundEntry)
85 *FoundEntry = SRomEntry;
86
87 return TRUE;
88 }
89 }
90
91 return FALSE;
92 }
93
94 static
95 CODE_SEG("PAGE")
96 BOOLEAN
SRomRegisterMasterAdapter(_In_ PDC21X4_ADAPTER Adapter,_In_ PDC_SROM_ENTRY SRomEntry)97 SRomRegisterMasterAdapter(
98 _In_ PDC21X4_ADAPTER Adapter,
99 _In_ PDC_SROM_ENTRY SRomEntry)
100 {
101 BOOLEAN Success;
102
103 PAGED_CODE();
104
105 SRomAcquireListMutex();
106
107 /* Check if board is already registered */
108 if (SRomIsAdapterInList(Adapter, TRUE, NULL))
109 {
110 Success = FALSE;
111 goto Exit;
112 }
113
114 Adapter->SRomEntry = SRomEntry;
115
116 SRomEntry->ChipType = Adapter->ChipType;
117 SRomEntry->BusNumber = Adapter->BusNumber;
118 SRomEntry->DeviceNumber = Adapter->DeviceNumber;
119 SRomEntry->InterruptLevel = Adapter->InterruptLevel;
120 SRomEntry->InterruptVector = Adapter->InterruptVector;
121
122 /* Register the port */
123 SRomEntry->DeviceBitmap |= 1 << Adapter->DeviceNumber;
124
125 /*
126 * On some multiport boards only the first port contains an EEPROM.
127 * We put their references to the global adapter list.
128 */
129 InsertTailList(&SRompAdapterList, &SRomEntry->ListEntry);
130 Success = TRUE;
131
132 Exit:
133 SRomReleaseListMutex();
134
135 return Success;
136 }
137
138 static
139 CODE_SEG("PAGE")
140 BOOLEAN
SRomFindMasterAdapter(_In_ PDC21X4_ADAPTER Adapter,_Out_ PDC_SROM_ENTRY * FoundEntry)141 SRomFindMasterAdapter(
142 _In_ PDC21X4_ADAPTER Adapter,
143 _Out_ PDC_SROM_ENTRY* FoundEntry)
144 {
145 PDC_SROM_ENTRY SRomEntry;
146 ULONG i;
147 BOOLEAN Found;
148
149 PAGED_CODE();
150
151 SRomAcquireListMutex();
152
153 if (!SRomIsAdapterInList(Adapter, FALSE, &SRomEntry))
154 {
155 Found = FALSE;
156 goto Exit;
157 }
158
159 Adapter->SRomEntry = SRomEntry;
160
161 /* Register the port */
162 SRomEntry->DeviceBitmap |= 1 << Adapter->DeviceNumber;
163
164 /*
165 * Determine the port index that should be used in order to
166 * (possibly) update the base MAC address.
167 */
168 for (i = 0; i < PCI_MAX_DEVICES; ++i)
169 {
170 if (i == Adapter->DeviceNumber)
171 break;
172
173 if (SRomEntry->DeviceBitmap & (1 << i))
174 ++Adapter->ControllerIndex;
175 }
176
177 /*
178 * On a multiport board there can be up to 4 ports
179 * connected through a 21050 or 21152 PCI-to-PCI Bridge.
180 * These boards share a single IRQ line between all of the chips.
181 * Some BIOSes incorrectly assign different IRQs to the different ports.
182 */
183 Adapter->InterruptLevel = SRomEntry->InterruptLevel;
184 Adapter->InterruptVector = SRomEntry->InterruptVector;
185
186 WARN("EEPROM is missing on controller %u, using image from the master at %u:%u\n",
187 Adapter->DeviceNumber,
188 SRomEntry->BusNumber,
189 SRomEntry->DeviceNumber);
190
191 *FoundEntry = SRomEntry;
192 Found = TRUE;
193
194 Exit:
195 SRomReleaseListMutex();
196
197 return Found;
198 }
199
200 static
201 CODE_SEG("PAGE")
202 BOOLEAN
SRomIsEmpty(_In_reads_bytes_ (Length)const VOID * Buffer,_In_ ULONG Length)203 SRomIsEmpty(
204 _In_reads_bytes_(Length) const VOID* Buffer,
205 _In_ ULONG Length)
206 {
207 const UCHAR* Data = Buffer;
208 const UCHAR FirstByte = Data[0];
209 ULONG i;
210
211 PAGED_CODE();
212
213 for (i = 1; i < Length; ++i)
214 {
215 if (FirstByte != Data[i])
216 return FALSE;
217 }
218
219 return TRUE;
220 }
221
222 static
223 CODE_SEG("PAGE")
224 VOID
SRomNWayAdvertise(_In_ PDC21X4_ADAPTER Adapter,_In_ ULONG MediaCode)225 SRomNWayAdvertise(
226 _In_ PDC21X4_ADAPTER Adapter,
227 _In_ ULONG MediaCode)
228 {
229 PAGED_CODE();
230
231 switch (MediaCode)
232 {
233 case MEDIA_10T:
234 Adapter->SymAdvertising |= MII_ADV_10T_HD;
235 break;
236 case MEDIA_10T_FD:
237 Adapter->SymAdvertising |= MII_ADV_10T_FD;
238 break;
239 case MEDIA_100TX_HD:
240 Adapter->SymAdvertising |= MII_ADV_100T_HD;
241 break;
242 case MEDIA_100TX_FD:
243 Adapter->SymAdvertising |= MII_ADV_100T_FD;
244 break;
245 case MEDIA_100T4:
246 Adapter->SymAdvertising |= MII_ADV_100T4;
247 break;
248
249 default:
250 break;
251 }
252 }
253
254 static
255 CODE_SEG("PAGE")
256 NDIS_STATUS
SRomDecodeBlockGpr(_In_ PDC21X4_ADAPTER Adapter,_In_ PUCHAR SRomEnd,_In_ PUCHAR BlockData)257 SRomDecodeBlockGpr(
258 _In_ PDC21X4_ADAPTER Adapter,
259 _In_ PUCHAR SRomEnd,
260 _In_ PUCHAR BlockData)
261 {
262 PDC_MEDIA Media;
263 ULONG MediaCode, OpMode;
264 USHORT Command;
265
266 PAGED_CODE();
267
268 if (BlockData > (SRomEnd - 4))
269 return NDIS_STATUS_BUFFER_OVERFLOW;
270
271 MediaCode = SRomGetMediaCode(*BlockData++);
272 if (MediaCode > SROM_MEDIA_MAX)
273 {
274 WARN("Unknown media code %u\n", MediaCode);
275 return NDIS_STATUS_SUCCESS;
276 }
277 Adapter->MediaBitmap |= 1 << MediaCode;
278
279 Media = &Adapter->Media[MediaCode];
280
281 Media->GpioData = *BlockData++;
282
283 Command = DcRetrieveWord(BlockData);
284
285 OpMode = Media->OpMode;
286 OpMode &= ~SROM_OPMODE_MASK;
287 OpMode |= SRomCommandToOpMode(Command);
288 Media->OpMode = OpMode;
289
290 if (SRomMediaHasActivityIndicator(Command))
291 {
292 Media->LinkMask = SRomMediaGetSenseMask(Command);
293 }
294 if (SRomMediaActivityIsActiveLow(Command))
295 {
296 Media->Polarity = 0xFFFFFFFF;
297 }
298
299 INFO("GPR #%u %s, Command %04lx, Data %02lx\n",
300 MediaCode,
301 MediaNumber2Str(Adapter, MediaCode),
302 Command,
303 Media->GpioData);
304
305 return NDIS_STATUS_SUCCESS;
306 }
307
308 static
309 CODE_SEG("PAGE")
310 NDIS_STATUS
SRomDecodeBlockMii(_In_ PDC21X4_ADAPTER Adapter,_In_ PUCHAR SRomEnd,_In_ PUCHAR BlockData,_In_ BOOLEAN IsOldVersion)311 SRomDecodeBlockMii(
312 _In_ PDC21X4_ADAPTER Adapter,
313 _In_ PUCHAR SRomEnd,
314 _In_ PUCHAR BlockData,
315 _In_ BOOLEAN IsOldVersion)
316 {
317 PDC_MII_MEDIA Media;
318 ULONG i, Bytes, Offset;
319 UCHAR PhyNumber, StreamLength, InterruptInfo;
320 USHORT Capabilities, Fdx, Ttm;
321
322 PAGED_CODE();
323
324 if (BlockData > (SRomEnd - 2))
325 return NDIS_STATUS_BUFFER_OVERFLOW;
326
327 PhyNumber = *BlockData++;
328
329 /*
330 * Even though the SROM specification allows several
331 * PHY devices to be connected to the same chip on a board,
332 * most if not all boards never use more than 1 MII PHY device.
333 */
334 if (Adapter->Features & DC_HAS_MII)
335 {
336 WARN("Unsupported PHY %u\n", PhyNumber);
337 return NDIS_STATUS_SUCCESS;
338 }
339
340 Media = &Adapter->MiiMedia;
341
342 /*
343 * PHY selection sequence
344 */
345
346 StreamLength = *BlockData++;
347 if (StreamLength > SROM_MAX_STREAM_REGS)
348 {
349 WARN("Too much registers %u\n", StreamLength);
350 return NDIS_STATUS_SUCCESS;
351 }
352
353 Bytes = StreamLength;
354 if (!IsOldVersion)
355 {
356 /* In words */
357 Bytes *= 2;
358 }
359 if ((BlockData + Bytes) > (SRomEnd - 1))
360 {
361 return NDIS_STATUS_BUFFER_OVERFLOW;
362 }
363
364 Media->SetupStreamLength = StreamLength;
365
366 /* Check if we already have the GPIO direction data */
367 if (Media->SetupStream[0] != 0)
368 {
369 Offset = 1;
370 ++Media->SetupStreamLength;
371 }
372 else
373 {
374 Offset = 0;
375 }
376
377 for (i = 0; i < StreamLength; ++i)
378 {
379 if (IsOldVersion)
380 {
381 Media->SetupStream[i + Offset] = *BlockData++;
382 }
383 else
384 {
385 Media->SetupStream[i + Offset] = DcRetrieveWord(BlockData);
386 BlockData += sizeof(USHORT);
387 }
388 }
389
390 /*
391 * PHY reset sequence
392 */
393
394 if (BlockData > (SRomEnd - 1))
395 {
396 return NDIS_STATUS_BUFFER_OVERFLOW;
397 }
398
399 StreamLength = *BlockData++;
400 if (StreamLength > SROM_MAX_STREAM_REGS)
401 {
402 WARN("Too much registers %u\n", StreamLength);
403 return NDIS_STATUS_SUCCESS;
404 }
405
406 Bytes = StreamLength;
407 if (!IsOldVersion)
408 {
409 /* In words */
410 Bytes *= 2;
411 }
412 if ((BlockData + Bytes) > (SRomEnd - 1))
413 {
414 return NDIS_STATUS_BUFFER_OVERFLOW;
415 }
416
417 Media->ResetStreamLength = StreamLength;
418
419 for (i = 0; i < StreamLength; ++i)
420 {
421 if (IsOldVersion)
422 {
423 Media->ResetStream[i] = *BlockData++;
424 }
425 else
426 {
427 Media->ResetStream[i] = DcRetrieveWord(BlockData);
428 BlockData += sizeof(USHORT);
429 }
430 }
431
432 /*
433 * MII data
434 */
435
436 Bytes = 4 * sizeof(USHORT);
437 if (!IsOldVersion)
438 {
439 Bytes += 1;
440 }
441 if (BlockData > (SRomEnd - Bytes))
442 {
443 return NDIS_STATUS_BUFFER_OVERFLOW;
444 }
445
446 Capabilities = DcRetrieveWord(BlockData);
447 BlockData += sizeof(USHORT);
448
449 Media->Advertising = DcRetrieveWord(BlockData);
450 BlockData += sizeof(USHORT);
451
452 Fdx = DcRetrieveWord(BlockData);
453 BlockData += sizeof(USHORT);
454
455 Ttm = DcRetrieveWord(BlockData);
456 BlockData += sizeof(USHORT);
457
458 InterruptInfo = IsOldVersion ? 0 : *BlockData;
459
460 Adapter->Features |= DC_HAS_MII;
461
462 INFO("MII #%u, Caps %04lx, Adv %04lx, Fdx %04lx, Ttm %04lx, Int %02x\n",
463 PhyNumber,
464 Capabilities,
465 Media->Advertising,
466 Fdx,
467 Ttm,
468 InterruptInfo);
469
470 return NDIS_STATUS_SUCCESS;
471 }
472
473 static
474 CODE_SEG("PAGE")
475 NDIS_STATUS
SRomDecodeBlockSia(_In_ PDC21X4_ADAPTER Adapter,_In_ PUCHAR SRomEnd,_In_ PUCHAR BlockData)476 SRomDecodeBlockSia(
477 _In_ PDC21X4_ADAPTER Adapter,
478 _In_ PUCHAR SRomEnd,
479 _In_ PUCHAR BlockData)
480 {
481 PDC_MEDIA Media;
482 UCHAR BlockStart;
483 ULONG MediaCode;
484 BOOLEAN HasExtendedData;
485
486 PAGED_CODE();
487
488 if (BlockData > (SRomEnd - 1))
489 return NDIS_STATUS_BUFFER_OVERFLOW;
490
491 BlockStart = *BlockData++;
492
493 HasExtendedData = SRomBlockHasExtendedData(BlockStart);
494 if (BlockData > (SRomEnd - (HasExtendedData ? 10 : 4)))
495 return NDIS_STATUS_BUFFER_OVERFLOW;
496
497 MediaCode = SRomGetMediaCode(BlockStart);
498 if (MediaCode > SROM_MEDIA_MAX && MediaCode != SROM_MEDIA_HMR)
499 {
500 WARN("Unknown media code %u\n", MediaCode);
501 return NDIS_STATUS_SUCCESS;
502 }
503
504 /* TODO: There were a few 21143-based boards with HMR media */
505 if ((MediaCode == SROM_MEDIA_HMR) && (Adapter->ChipType != DC21145))
506 {
507 ERR("FIXME: 21143 HMR is not supported yet\n");
508 return NDIS_STATUS_SUCCESS;
509 }
510
511 /* Map the code to our internal value */
512 if (MediaCode == SROM_MEDIA_HMR)
513 {
514 MediaCode = MEDIA_HMR;
515 }
516
517 Adapter->MediaBitmap |= 1 << MediaCode;
518
519 Media = &Adapter->Media[MediaCode];
520
521 if (HasExtendedData)
522 {
523 Media->Csr13 = DcRetrieveWord(BlockData);
524 BlockData += sizeof(USHORT);
525
526 Media->Csr14 = DcRetrieveWord(BlockData);
527 BlockData += sizeof(USHORT);
528
529 Media->Csr15 = DcRetrieveWord(BlockData);
530 BlockData += sizeof(USHORT);
531 }
532
533 Media->GpioCtrl = DcRetrieveWord(BlockData);
534 BlockData += sizeof(USHORT);
535
536 Media->GpioData = DcRetrieveWord(BlockData);
537 BlockData += sizeof(USHORT);
538
539 SRomNWayAdvertise(Adapter, MediaCode);
540
541 INFO("SIA #%u %s, %sCSR13 %04lx CSR14 %04lx CSR15 %04lx, "
542 "Ctrl %04lx, Data %04lx\n",
543 MediaCode,
544 MediaNumber2Str(Adapter, MediaCode),
545 HasExtendedData ? "EXT " : "",
546 Media->Csr13,
547 Media->Csr14,
548 Media->Csr15,
549 Media->GpioCtrl,
550 Media->GpioData);
551
552 return NDIS_STATUS_SUCCESS;
553 }
554
555 static
556 CODE_SEG("PAGE")
557 NDIS_STATUS
SRomDecodeBlockSym(_In_ PDC21X4_ADAPTER Adapter,_In_ PUCHAR SRomEnd,_In_ PUCHAR BlockData)558 SRomDecodeBlockSym(
559 _In_ PDC21X4_ADAPTER Adapter,
560 _In_ PUCHAR SRomEnd,
561 _In_ PUCHAR BlockData)
562 {
563 PDC_MEDIA Media;
564 ULONG MediaCode, OpMode;
565 USHORT Command;
566
567 PAGED_CODE();
568
569 if (BlockData > (SRomEnd - 7))
570 return NDIS_STATUS_BUFFER_OVERFLOW;
571
572 MediaCode = SRomGetMediaCode(*BlockData++);
573 if (MediaCode > SROM_MEDIA_MAX)
574 {
575 WARN("Unknown media code %u\n", MediaCode);
576 return NDIS_STATUS_SUCCESS;
577 }
578 Adapter->MediaBitmap |= 1 << MediaCode;
579
580 Media = &Adapter->Media[MediaCode];
581
582 Media->GpioCtrl = DcRetrieveWord(BlockData);
583 BlockData += sizeof(USHORT);
584
585 Media->GpioData = DcRetrieveWord(BlockData);
586 BlockData += sizeof(USHORT);
587
588 Command = DcRetrieveWord(BlockData);
589 BlockData += sizeof(USHORT);
590
591 OpMode = Media->OpMode;
592 OpMode &= ~SROM_OPMODE_MASK;
593 OpMode |= SRomCommandToOpMode(Command);
594 Media->OpMode = OpMode;
595
596 SRomNWayAdvertise(Adapter, MediaCode);
597
598 INFO("SYM #%u %s, Command %04lx, Ctrl %04lx, Data %04lx\n",
599 MediaCode,
600 MediaNumber2Str(Adapter, MediaCode),
601 Command,
602 Media->GpioCtrl,
603 Media->GpioData);
604
605 return NDIS_STATUS_SUCCESS;
606 }
607
608 static
609 CODE_SEG("PAGE")
610 NDIS_STATUS
SRomDecodeBlockReset(_In_ PDC21X4_ADAPTER Adapter,_In_ PUCHAR SRomEnd,_In_ PUCHAR BlockData)611 SRomDecodeBlockReset(
612 _In_ PDC21X4_ADAPTER Adapter,
613 _In_ PUCHAR SRomEnd,
614 _In_ PUCHAR BlockData)
615 {
616 UCHAR i, StreamLength;
617
618 PAGED_CODE();
619
620 if (BlockData > (SRomEnd - 1))
621 return NDIS_STATUS_BUFFER_OVERFLOW;
622
623 StreamLength = *BlockData++;
624 if (StreamLength > SROM_MAX_STREAM_REGS)
625 {
626 WARN("Too much registers %u\n", StreamLength);
627 return NDIS_STATUS_SUCCESS;
628 }
629
630 if ((BlockData + StreamLength * 2) > (SRomEnd - 1))
631 return NDIS_STATUS_BUFFER_OVERFLOW;
632
633 Adapter->ResetStreamLength = StreamLength;
634
635 for (i = 0; i < StreamLength; ++i)
636 {
637 Adapter->ResetStream[i] = DcRetrieveWord(BlockData);
638 BlockData += sizeof(USHORT);
639 }
640
641 INFO("RESET, length %u\n", StreamLength);
642
643 return NDIS_STATUS_SUCCESS;
644 }
645
646 static
647 CODE_SEG("PAGE")
648 NDIS_STATUS
SRomDecodeBlockHmr(_In_ PDC21X4_ADAPTER Adapter,_In_ PUCHAR SRomEnd,_In_ PUCHAR BlockData,_In_ UCHAR BlockLength)649 SRomDecodeBlockHmr(
650 _In_ PDC21X4_ADAPTER Adapter,
651 _In_ PUCHAR SRomEnd,
652 _In_ PUCHAR BlockData,
653 _In_ UCHAR BlockLength)
654 {
655 ULONG Offset, ExtraData, i;
656
657 PAGED_CODE();
658
659 if (BlockData > (SRomEnd - (2 + 6)))
660 return NDIS_STATUS_BUFFER_OVERFLOW;
661
662 Adapter->AnalogControl = DcRetrieveWord(BlockData) << 16;
663 BlockData += sizeof(USHORT);
664
665 Adapter->HpnaRegister[HPNA_CONTROL_LOW] = *BlockData++;
666 Adapter->HpnaRegister[HPNA_CONTROL_HIGH] = *BlockData++;
667 Adapter->HpnaRegister[HPNA_NOISE] = *BlockData++;
668 Adapter->HpnaRegister[HPNA_NOISE_FLOOR] = *BlockData++;
669 Adapter->HpnaRegister[HPNA_NOISE_CEILING] = *BlockData++;
670 Adapter->HpnaRegister[HPNA_NOISE_ATTACK] = *BlockData++;
671 Adapter->HpnaInitBitmap |= ((1 << HPNA_CONTROL_LOW) |
672 (1 << HPNA_CONTROL_HIGH) |
673 (1 << HPNA_NOISE) |
674 (1 << HPNA_NOISE_FLOOR) |
675 (1 << HPNA_NOISE_CEILING) |
676 (1 << HPNA_NOISE_ATTACK));
677
678 Offset = 2 /* Length and type fields */ + 2 /* Analog ctrl */ + 6; /* Regs */
679 ExtraData = (BlockLength - Offset);
680
681 if ((BlockData + ExtraData) > (SRomEnd - 1))
682 return NDIS_STATUS_BUFFER_OVERFLOW;
683
684 for (i = 0; i < ExtraData / sizeof(USHORT); ++i)
685 {
686 UCHAR RegAddress = SRomHmrRegAddress(*BlockData++);
687 UCHAR RegValue = *BlockData++;
688
689 Adapter->HpnaRegister[RegAddress] = RegValue;
690 Adapter->HpnaInitBitmap |= 1 << RegAddress;
691 }
692
693 #if DBG
694 INFO_VERB("Analog Ctrl %04lx\n", Adapter->AnalogControl);
695
696 for (i = 0; i < RTL_NUMBER_OF(Adapter->HpnaRegister); ++i)
697 {
698 if (Adapter->HpnaInitBitmap & (1 << i))
699 {
700 INFO_VERB("HR Reg %02x = %02x\n", i, Adapter->HpnaRegister[i]);
701 }
702 }
703
704 if (ExtraData % sizeof(USHORT))
705 {
706 INFO_VERB("HR Data = %02x\n", *BlockData);
707 }
708 #endif
709
710 return NDIS_STATUS_SUCCESS;
711 }
712
713 static
714 CODE_SEG("PAGE")
715 NDIS_STATUS
SRomParseExtendedBlock(_In_ PDC21X4_ADAPTER Adapter,_In_ PUCHAR SRomEnd,_In_ PUCHAR BlockData,_Out_ PULONG BlockSize)716 SRomParseExtendedBlock(
717 _In_ PDC21X4_ADAPTER Adapter,
718 _In_ PUCHAR SRomEnd,
719 _In_ PUCHAR BlockData,
720 _Out_ PULONG BlockSize)
721 {
722 NDIS_STATUS Status;
723 ULONG Length, Type;
724
725 PAGED_CODE();
726
727 if (BlockData > (SRomEnd - 2))
728 return NDIS_STATUS_BUFFER_OVERFLOW;
729
730 Length = SRomGetExtendedBlockLength(*BlockData++);
731 Type = *BlockData++;
732
733 *BlockSize = Length;
734
735 switch (Type)
736 {
737 case SROM_BLOCK_TYPE_GPR:
738 Status = SRomDecodeBlockGpr(Adapter, SRomEnd, BlockData);
739 break;
740 case SROM_BLOCK_TYPE_MII_1:
741 case SROM_BLOCK_TYPE_MII_2:
742 Status = SRomDecodeBlockMii(Adapter,
743 SRomEnd,
744 BlockData,
745 (Type == SROM_BLOCK_TYPE_MII_1));
746 break;
747 case SROM_BLOCK_TYPE_SIA:
748 Status = SRomDecodeBlockSia(Adapter, SRomEnd, BlockData);
749 break;
750 case SROM_BLOCK_TYPE_SYM:
751 Status = SRomDecodeBlockSym(Adapter, SRomEnd, BlockData);
752 break;
753 case SROM_BLOCK_TYPE_RESET:
754 Status = SRomDecodeBlockReset(Adapter, SRomEnd, BlockData);
755 break;
756 case SROM_BLOCK_TYPE_HOMERUN:
757 Status = SRomDecodeBlockHmr(Adapter, SRomEnd, BlockData, Length);
758 break;
759
760 /* Skip over the unused or unknown blocks */
761 default:
762 WARN("Unknown block type %u, length %u\n", Type, Length);
763 case SROM_BLOCK_TYPE_PHY_SHUTDOWN:
764 Status = NDIS_STATUS_SUCCESS;
765 break;
766 }
767
768 return Status;
769 }
770
771 static
772 CODE_SEG("PAGE")
773 NDIS_STATUS
SRomParse21041Block(_In_ PDC21X4_ADAPTER Adapter,_In_ PUCHAR SRomEnd,_In_ PUCHAR BlockData,_Out_ PULONG BlockSize)774 SRomParse21041Block(
775 _In_ PDC21X4_ADAPTER Adapter,
776 _In_ PUCHAR SRomEnd,
777 _In_ PUCHAR BlockData,
778 _Out_ PULONG BlockSize)
779 {
780 PDC_MEDIA Media;
781 UCHAR BlockStart;
782 ULONG MediaCode;
783 BOOLEAN HasExtendedData;
784
785 PAGED_CODE();
786
787 if (BlockData > (SRomEnd - 1))
788 return NDIS_STATUS_BUFFER_OVERFLOW;
789
790 BlockStart = *BlockData++;
791
792 HasExtendedData = SRomBlockHasExtendedData(BlockStart);
793 if (BlockData > (SRomEnd - (HasExtendedData ? 7 : 1)))
794 return NDIS_STATUS_BUFFER_OVERFLOW;
795
796 *BlockSize = HasExtendedData ? 7 : 1;
797
798 MediaCode = SRomGetMediaCode(BlockStart);
799 if (MediaCode > SROM_MEDIA_MAX)
800 {
801 WARN("Unknown media code %u\n", MediaCode);
802 return NDIS_STATUS_SUCCESS;
803 }
804 Adapter->MediaBitmap |= 1 << MediaCode;
805
806 Media = &Adapter->Media[MediaCode];
807
808 if (HasExtendedData)
809 {
810 Media->Csr13 = DcRetrieveWord(BlockData);
811 BlockData += sizeof(USHORT);
812
813 Media->Csr14 = DcRetrieveWord(BlockData);
814 BlockData += sizeof(USHORT);
815
816 Media->Csr15 = DcRetrieveWord(BlockData);
817 BlockData += sizeof(USHORT);
818 }
819
820 INFO("SIA #%u %s, %sCSR13 %04lx CSR14 %04lx CSR15 %04lx\n",
821 MediaCode,
822 MediaNumber2Str(Adapter, MediaCode),
823 HasExtendedData ? "EXT " : "",
824 Media->Csr13,
825 Media->Csr14,
826 Media->Csr15);
827
828 return NDIS_STATUS_SUCCESS;
829 }
830
831 static
832 CODE_SEG("PAGE")
833 BOOLEAN
SRomChecksumValid(_In_ PUCHAR SRom)834 SRomChecksumValid(
835 _In_ PUCHAR SRom)
836 {
837 USHORT Checksum;
838
839 PAGED_CODE();
840
841 Checksum = ~DcEthernetCrc(SRom, SROM_CHECKSUM_V1);
842 if (Checksum == DcRetrieveWord(&SRom[SROM_CHECKSUM_V1]))
843 return TRUE;
844
845 Checksum = ~DcEthernetCrc(SRom, SROM_CHECKSUM_V2);
846 if (Checksum == DcRetrieveWord(&SRom[SROM_CHECKSUM_V2]))
847 return TRUE;
848
849 return FALSE;
850 }
851
852 static
853 CODE_SEG("PAGE")
854 BOOLEAN
AddressRomChecksumValid(_In_reads_bytes_ (EAR_SIZE)PVOID AddressRom)855 AddressRomChecksumValid(
856 _In_reads_bytes_(EAR_SIZE) PVOID AddressRom)
857 {
858 const UCHAR* Octet = AddressRom;
859 ULONG64 TestPatterm;
860 ULONG Checksum, i;
861
862 PAGED_CODE();
863
864 NdisMoveMemory(&TestPatterm, &Octet[24], 8);
865 if (TestPatterm != EAR_TEST_PATTERN)
866 return FALSE;
867
868 for (i = 0; i < 8; ++i)
869 {
870 if (Octet[i] != Octet[15 - i])
871 return FALSE;
872 }
873
874 Checksum = (Octet[0] << 10) + (Octet[2] << 9) + (Octet[4] << 8) +
875 (Octet[1] << 2) + (Octet[3] << 1) + Octet[5];
876 Checksum %= 0xFFFF;
877
878 return ((USHORT)Checksum == ((Octet[6] << 8) | Octet[7]));
879 }
880
881 static
882 CODE_SEG("PAGE")
883 BOOLEAN
SRomReadMacAddress(_In_ PDC21X4_ADAPTER Adapter,_In_ PUCHAR SRom,_Out_opt_ PULONG AddressOffset)884 SRomReadMacAddress(
885 _In_ PDC21X4_ADAPTER Adapter,
886 _In_ PUCHAR SRom,
887 _Out_opt_ PULONG AddressOffset)
888 {
889 ULONG MacOffset;
890
891 PAGED_CODE();
892
893 /* Check if we have a board with an old EAR format */
894 if (NdisEqualMemory(SRom, &SRom[16], 8))
895 {
896 /* Validate the EAR checksum */
897 if (!AddressRomChecksumValid(SRom))
898 {
899 ERR("EAR has an invalid checksum\n");
900 return FALSE;
901 }
902
903 MacOffset = 0;
904 goto ReadMac;
905 }
906
907 /* Check for a new SROM format */
908 if (Adapter->ChipType != DC21040)
909 {
910 /* Validate the SROM checksum */
911 if (SRomChecksumValid(SRom))
912 {
913 MacOffset = SROM_MAC_ADDRESS;
914 goto ReadMac;
915 }
916 }
917
918 /* Sanity check */
919 if (*(PULONG)SRom == 0xFFFFFFFF || *(PULONG)SRom == 0)
920 return FALSE;
921
922 WARN("Legacy/unknown board found\n");
923 MacOffset = 0;
924
925 ReadMac:
926 if (AddressOffset)
927 *AddressOffset = MacOffset;
928
929 NdisMoveMemory(Adapter->PermanentMacAddress,
930 &SRom[MacOffset],
931 ETH_LENGTH_OF_ADDRESS);
932
933 return TRUE;
934 }
935
936 static
937 CODE_SEG("PAGE")
938 NDIS_STATUS
SRomParseHeader(_In_ PDC21X4_ADAPTER Adapter,_In_ PUCHAR SRom,_Out_ PUCHAR * InfoLeaf,_Out_ PUCHAR * SRomEnd)939 SRomParseHeader(
940 _In_ PDC21X4_ADAPTER Adapter,
941 _In_ PUCHAR SRom,
942 _Out_ PUCHAR* InfoLeaf,
943 _Out_ PUCHAR* SRomEnd)
944 {
945 ULONG i, MacOffset, LeafOffset;
946
947 PAGED_CODE();
948
949 if (!SRomReadMacAddress(Adapter, SRom, &MacOffset))
950 {
951 ERR("Unable to read the MAC address\n");
952 return NDIS_STATUS_FAILURE;
953 }
954
955 /* Assign our own fake info leaf */
956 if (MacOffset != SROM_MAC_ADDRESS)
957 {
958 for (i = 0; SRompRepairData[i].InfoLeaf; ++i)
959 {
960 /* Check for a MAC match */
961 if (NdisEqualMemory(SRompRepairData[i].InfoLeaf, &Adapter->PermanentMacAddress, 3))
962 {
963 /* This check is used to distinguish Accton EN1207 from Maxtech */
964 if ((Adapter->PermanentMacAddress[0] == 0xE8) && (SRom[0x1A] == 0x55))
965 ++i;
966
967 break;
968 }
969 }
970 if (!SRompRepairData[i].InfoLeaf)
971 {
972 ERR("Non-standard SROM format, OUI %02x:%02x:%02x\n",
973 Adapter->PermanentMacAddress[0],
974 Adapter->PermanentMacAddress[1],
975 Adapter->PermanentMacAddress[2]);
976
977 return NDIS_STATUS_ADAPTER_NOT_FOUND;
978 }
979
980 *InfoLeaf = &SRompRepairData[i].InfoLeaf[3];
981 *SRomEnd = *InfoLeaf + SRompRepairData[i].Length;
982
983 /* Update the base address on multiport boards */
984 Adapter->PermanentMacAddress[5] += Adapter->ControllerIndex;
985
986 #if DBG
987 WARN("Non-standard SROM format, using '%s' info leaf\n", SRompRepairData[i].Name);
988 #endif
989 return STATUS_SUCCESS;
990 }
991
992 /* Check if the SROM chip is shared between multiple controllers on a multiport board */
993 if (SRom[SROM_CONTROLLER_COUNT] > 1)
994 {
995 INFO("Multiport board, controller number %u (%u/%u)\n",
996 Adapter->DeviceNumber,
997 Adapter->ControllerIndex + 1,
998 SRom[SROM_CONTROLLER_COUNT]);
999
1000 for (i = 0; i < SRom[SROM_CONTROLLER_COUNT]; ++i)
1001 {
1002 if (SROM_DEVICE_NUMBER(i) >= EE_SIZE)
1003 return NDIS_STATUS_BUFFER_OVERFLOW;
1004
1005 if (SRom[SROM_DEVICE_NUMBER(i)] == Adapter->DeviceNumber)
1006 break;
1007 }
1008 if (i == SRom[SROM_CONTROLLER_COUNT])
1009 {
1010 ERR("Controller %u was not found in the SROM\n", Adapter->DeviceNumber);
1011 return NDIS_STATUS_ADAPTER_NOT_FOUND;
1012 }
1013
1014 if (SROM_LEAF_OFFSET(i) >= EE_SIZE)
1015 return NDIS_STATUS_BUFFER_OVERFLOW;
1016
1017 /* Update the base address */
1018 Adapter->PermanentMacAddress[5] += i;
1019 }
1020 else
1021 {
1022 i = 0;
1023 }
1024
1025 /* Controller info block offset */
1026 LeafOffset = DcRetrieveWord(SRom + SROM_LEAF_OFFSET(i));
1027 if (LeafOffset > (EE_SIZE - sizeof(DC_SROM_COMPACT_BLOCK)))
1028 return NDIS_STATUS_BUFFER_OVERFLOW;
1029
1030 /* Controller info leaf */
1031 *InfoLeaf = &SRom[LeafOffset];
1032
1033 *SRomEnd = SRom + EE_SIZE;
1034
1035 return STATUS_SUCCESS;
1036 }
1037
1038 static
1039 CODE_SEG("PAGE")
1040 NDIS_STATUS
SRomParse(_In_ PDC21X4_ADAPTER Adapter,_In_ PUCHAR SRom)1041 SRomParse(
1042 _In_ PDC21X4_ADAPTER Adapter,
1043 _In_ PUCHAR SRom)
1044 {
1045 ULONG Index, BlockCount, BlockSize, DefaultMedia;
1046 NDIS_STATUS Status;
1047 USHORT GpioCtrl;
1048 PUCHAR Data, SRomEnd;
1049
1050 PAGED_CODE();
1051
1052 INFO("SROM Version %u, Controller count %u\n",
1053 SRom[SROM_VERSION],
1054 SRom[SROM_CONTROLLER_COUNT]);
1055
1056 Status = SRomParseHeader(Adapter, SRom, &Data, &SRomEnd);
1057 if (Status != NDIS_STATUS_SUCCESS)
1058 return Status;
1059
1060 DefaultMedia = DcRetrieveWord(Data);
1061 Data += sizeof(USHORT);
1062
1063 INFO("Default Media: %04lx\n", DefaultMedia);
1064
1065 /* Direction of the GPIO pins */
1066 if (Adapter->ChipType == DC21140)
1067 {
1068 GpioCtrl = *Data++;
1069
1070 INFO("GPIO Direction: %04lx\n", GpioCtrl);
1071
1072 GpioCtrl |= DC_GPIO_CONTROL;
1073
1074 for (Index = 0; Index < MEDIA_LIST_MAX; ++Index)
1075 {
1076 Adapter->Media[Index].GpioCtrl = GpioCtrl;
1077 }
1078
1079 /* Control word for block type 1 */
1080 Adapter->MiiMedia.SetupStream[0] = GpioCtrl;
1081 }
1082
1083 BlockCount = *Data++;
1084
1085 INFO("Block Count: %u\n", BlockCount);
1086
1087 if (BlockCount == 0 || BlockCount == 0xFF)
1088 {
1089 WARN("No media information found\n");
1090 return NDIS_STATUS_SUCCESS;
1091 }
1092
1093 /* Analyze and decode blocks */
1094 for (Index = 0; Index < BlockCount; ++Index)
1095 {
1096 if (Adapter->ChipType == DC21041)
1097 {
1098 Status = SRomParse21041Block(Adapter, SRomEnd, Data, &BlockSize);
1099 }
1100 else
1101 {
1102 if (Data > (SRomEnd - 1))
1103 return NDIS_STATUS_BUFFER_OVERFLOW;
1104
1105 if (SRomIsBlockExtended(*Data))
1106 {
1107 Status = SRomParseExtendedBlock(Adapter, SRomEnd, Data, &BlockSize);
1108 }
1109 else
1110 {
1111 Status = SRomDecodeBlockGpr(Adapter, SRomEnd, Data);
1112 BlockSize = 4;
1113 }
1114 }
1115 if (Status != NDIS_STATUS_SUCCESS)
1116 return Status;
1117
1118 Data += BlockSize;
1119 }
1120
1121 if ((Adapter->MediaBitmap == 0) && !(Adapter->Features & DC_HAS_MII))
1122 {
1123 WARN("No media information found\n");
1124 }
1125
1126 return NDIS_STATUS_SUCCESS;
1127 }
1128
1129 static
1130 CODE_SEG("PAGE")
1131 VOID
SRomShiftOut(_In_ PDC21X4_ADAPTER Adapter,_In_ ULONG Sequence,_In_ ULONG BitCount)1132 SRomShiftOut(
1133 _In_ PDC21X4_ADAPTER Adapter,
1134 _In_ ULONG Sequence,
1135 _In_ ULONG BitCount)
1136 {
1137 LONG i;
1138
1139 PAGED_CODE();
1140
1141 for (i = BitCount - 1; i >= 0; --i)
1142 {
1143 ULONG DataIn = ((Sequence >> i) & 1) << DC_SERIAL_EE_DI_SHIFT;
1144
1145 SROM_WRITE(Adapter, DataIn | DC_SERIAL_EE_RD | DC_SERIAL_EE_SR | DC_SERIAL_EE_CS);
1146 SROM_WRITE(Adapter, DataIn | DC_SERIAL_EE_RD | DC_SERIAL_EE_SR | DC_SERIAL_EE_CS |
1147 DC_SERIAL_EE_SK);
1148 SROM_WRITE(Adapter, DataIn | DC_SERIAL_EE_RD | DC_SERIAL_EE_SR | DC_SERIAL_EE_CS);
1149 }
1150 }
1151
1152 static
1153 CODE_SEG("PAGE")
1154 USHORT
SRomShiftIn(_In_ PDC21X4_ADAPTER Adapter)1155 SRomShiftIn(
1156 _In_ PDC21X4_ADAPTER Adapter)
1157 {
1158 ULONG i, Csr;
1159 USHORT SerialData;
1160
1161 PAGED_CODE();
1162
1163 /* Shift the data out of the EEPROM */
1164 SerialData = 0;
1165 for (i = 0; i < RTL_BITS_OF(USHORT); ++i)
1166 {
1167 SROM_WRITE(Adapter, DC_SERIAL_EE_RD | DC_SERIAL_EE_SR | DC_SERIAL_EE_CS | DC_SERIAL_EE_SK);
1168
1169 SROM_READ(Adapter, &Csr);
1170 SerialData = (SerialData << 1) | ((Csr >> DC_SERIAL_EE_DO_SHIFT) & 1);
1171
1172 SROM_WRITE(Adapter, DC_SERIAL_EE_RD | DC_SERIAL_EE_SR | DC_SERIAL_EE_CS);
1173 }
1174
1175 /* End the read cycle */
1176 SROM_WRITE(Adapter, DC_SERIAL_EE_RD | DC_SERIAL_EE_SR);
1177
1178 return SerialData;
1179 }
1180
1181 static
1182 CODE_SEG("PAGE")
1183 ULONG
SRomDetectAddressBusWidth(_In_ PDC21X4_ADAPTER Adapter)1184 SRomDetectAddressBusWidth(
1185 _In_ PDC21X4_ADAPTER Adapter)
1186 {
1187 ULONG Csr, BusWidth;
1188
1189 PAGED_CODE();
1190
1191 /* Assume the SROM is a 1kB ROM, send the read command and zero address (6 bits) */
1192 SRomShiftOut(Adapter, EEPROM_CMD_READ << 6, EEPROM_CMD_LENGTH + 6);
1193
1194 /* Check the preceding dummy zero bit */
1195 Csr = DC_READ(Adapter, DcCsr9_SerialInterface);
1196 if (Csr & DC_SERIAL_EE_DO)
1197 {
1198 /* 4kB EEPROM */
1199 BusWidth = 8;
1200
1201 /* Send the remaining part of the address */
1202 SRomShiftOut(Adapter, 0, 8 - 6);
1203
1204 /* The preceding dummy bit must be zero */
1205 Csr = DC_READ(Adapter, DcCsr9_SerialInterface);
1206 if (Csr & DC_SERIAL_EE_DO)
1207 return 0;
1208 }
1209 else
1210 {
1211 /* 1kB EEPROM */
1212 BusWidth = 6;
1213 }
1214
1215 /* Complete the read cycle */
1216 (VOID)SRomShiftIn(Adapter);
1217
1218 return BusWidth;
1219 }
1220
1221 static
1222 CODE_SEG("PAGE")
1223 BOOLEAN
SRomReadSRom(_In_ PDC21X4_ADAPTER Adapter,_Out_writes_all_ (EE_SIZE)PVOID SRom)1224 SRomReadSRom(
1225 _In_ PDC21X4_ADAPTER Adapter,
1226 _Out_writes_all_(EE_SIZE) PVOID SRom)
1227 {
1228 PUSHORT SRomWord = SRom;
1229 BOOLEAN Success = TRUE;
1230 ULONG BusWidth, Address;
1231
1232 PAGED_CODE();
1233
1234 /* Select the device */
1235 SROM_WRITE(Adapter, DC_SERIAL_EE_RD | DC_SERIAL_EE_SR);
1236 SROM_WRITE(Adapter, DC_SERIAL_EE_RD | DC_SERIAL_EE_SR | DC_SERIAL_EE_CS);
1237
1238 BusWidth = SRomDetectAddressBusWidth(Adapter);
1239 if (BusWidth == 0)
1240 {
1241 Success = FALSE;
1242 goto Done;
1243 }
1244 INFO("SROM Bus width: %u\n", BusWidth);
1245
1246 /* Read the SROM contents once */
1247 for (Address = 0; Address < (EE_SIZE / sizeof(USHORT)); ++Address)
1248 {
1249 /* Send the command and address */
1250 SRomShiftOut(Adapter,
1251 (EEPROM_CMD_READ << BusWidth) | Address,
1252 EEPROM_CMD_LENGTH + BusWidth);
1253
1254 /* Read the data */
1255 SRomWord[Address] = SRomShiftIn(Adapter);
1256 }
1257
1258 Done:
1259 /* End chip select */
1260 DC_WRITE(Adapter, DcCsr9_SerialInterface, 0);
1261
1262 return Success;
1263 }
1264
1265 #if DBG
1266 static
1267 CODE_SEG("PAGE")
1268 VOID
SRomDumpContents(_In_reads_bytes_ (Length)const VOID * Buffer,_In_ ULONG Length)1269 SRomDumpContents(
1270 _In_reads_bytes_(Length) const VOID* Buffer,
1271 _In_ ULONG Length)
1272 {
1273 ULONG Offset, Count, i;
1274 const UCHAR* Data = Buffer;
1275
1276 PAGED_CODE();
1277
1278 DbgPrint("SROM data:\n");
1279
1280 Offset = 0;
1281 while (Offset < Length)
1282 {
1283 DbgPrint("%04x:\t", Offset);
1284
1285 Count = min(Length - Offset, 16);
1286 for (i = 0; i < Count; ++i, ++Offset)
1287 {
1288 DbgPrint("0x%02x, ", Data[Offset], (i == 7) ? '-' : ' ');
1289 }
1290
1291 DbgPrint("\n");
1292 }
1293 }
1294 #endif // DBG
1295
1296 static
1297 CODE_SEG("PAGE")
1298 NDIS_STATUS
SRomRead(_In_ PDC21X4_ADAPTER Adapter)1299 SRomRead(
1300 _In_ PDC21X4_ADAPTER Adapter)
1301 {
1302 PDC_SROM_ENTRY SRomEntry;
1303 NDIS_STATUS Status;
1304 BOOLEAN ReleaseImage;
1305
1306 PAGED_CODE();
1307
1308 Status = NdisAllocateMemoryWithTag((PVOID*)&SRomEntry,
1309 FIELD_OFFSET(DC_SROM_ENTRY, SRomImage[EE_SIZE]),
1310 DC21X4_TAG);
1311 if (Status != NDIS_STATUS_SUCCESS)
1312 return NDIS_STATUS_RESOURCES;
1313 NdisZeroMemory(SRomEntry, FIELD_OFFSET(DC_SROM_ENTRY, SRomImage));
1314
1315 ReleaseImage = FALSE;
1316
1317 if (SRomReadSRom(Adapter, SRomEntry->SRomImage))
1318 {
1319 if (!SRomRegisterMasterAdapter(Adapter, SRomEntry))
1320 ReleaseImage = TRUE;
1321 }
1322 else
1323 {
1324 NdisFreeMemory(SRomEntry, 0, 0);
1325
1326 if (!SRomFindMasterAdapter(Adapter, &SRomEntry))
1327 {
1328 ERR("Failed to retrieve the SROM contents\n");
1329 return NDIS_STATUS_FAILURE;
1330 }
1331 }
1332
1333 Status = SRomParse(Adapter, SRomEntry->SRomImage);
1334 if (Status != NDIS_STATUS_SUCCESS)
1335 {
1336 ERR("Failed to parse SROM\n");
1337 }
1338
1339 #if DBG
1340 if (Status != NDIS_STATUS_SUCCESS)
1341 SRomDumpContents(SRomEntry->SRomImage, EE_SIZE);
1342 #endif
1343
1344 if (ReleaseImage)
1345 NdisFreeMemory(SRomEntry, 0, 0);
1346
1347 return Status;
1348 }
1349
1350 static
1351 CODE_SEG("PAGE")
1352 BOOLEAN
AddressRomReadData(_In_ PDC21X4_ADAPTER Adapter,_Out_writes_all_ (EAR_SIZE)PUCHAR AddressRom)1353 AddressRomReadData(
1354 _In_ PDC21X4_ADAPTER Adapter,
1355 _Out_writes_all_(EAR_SIZE) PUCHAR AddressRom)
1356 {
1357 ULONG Data, i, j;
1358
1359 PAGED_CODE();
1360
1361 /* Reset the ROM pointer */
1362 DC_WRITE(Adapter, DcCsr9_SerialInterface, 0);
1363
1364 for (i = 0; i < EAR_SIZE; ++i)
1365 {
1366 for (j = 10000; j > 0; --j)
1367 {
1368 NdisStallExecution(1);
1369 Data = DC_READ(Adapter, DcCsr9_SerialInterface);
1370
1371 if (!(Data & DC_SERIAL_EAR_DN))
1372 break;
1373 }
1374 AddressRom[i] = Data & DC_SERIAL_EAR_DT;
1375 }
1376
1377 if (SRomIsEmpty(AddressRom, EAR_SIZE))
1378 return FALSE;
1379
1380 return TRUE;
1381 }
1382
1383 static
1384 CODE_SEG("PAGE")
1385 NDIS_STATUS
AddressRomRead(_In_ PDC21X4_ADAPTER Adapter)1386 AddressRomRead(
1387 _In_ PDC21X4_ADAPTER Adapter)
1388 {
1389 PDC_SROM_ENTRY SRomEntry;
1390 NDIS_STATUS Status;
1391 BOOLEAN ReleaseImage;
1392
1393 PAGED_CODE();
1394
1395 Status = NdisAllocateMemoryWithTag((PVOID*)&SRomEntry,
1396 FIELD_OFFSET(DC_SROM_ENTRY, SRomImage[EAR_SIZE]),
1397 DC21X4_TAG);
1398 if (Status != NDIS_STATUS_SUCCESS)
1399 return NDIS_STATUS_RESOURCES;
1400 NdisZeroMemory(SRomEntry, FIELD_OFFSET(DC_SROM_ENTRY, SRomImage));
1401
1402 ReleaseImage = FALSE;
1403
1404 if (AddressRomReadData(Adapter, SRomEntry->SRomImage))
1405 {
1406 if (!SRomRegisterMasterAdapter(Adapter, SRomEntry))
1407 ReleaseImage = TRUE;
1408 }
1409 else
1410 {
1411 NdisFreeMemory(SRomEntry, 0, 0);
1412
1413 if (!SRomFindMasterAdapter(Adapter, &SRomEntry))
1414 {
1415 ERR("Failed to retrieve the EAR contents\n");
1416 return NDIS_STATUS_FAILURE;
1417 }
1418 }
1419
1420 if (!SRomReadMacAddress(Adapter, SRomEntry->SRomImage, NULL))
1421 {
1422 ERR("Unable to read the MAC address\n");
1423 Status = NDIS_STATUS_FAILURE;
1424 }
1425
1426 /* Update the base address on multiport boards */
1427 Adapter->PermanentMacAddress[5] += Adapter->ControllerIndex;
1428
1429 #if DBG
1430 if (Status != NDIS_STATUS_SUCCESS)
1431 SRomDumpContents(SRomEntry->SRomImage, EAR_SIZE);
1432 #endif
1433
1434 if (ReleaseImage)
1435 NdisFreeMemory(SRomEntry, 0, 0);
1436
1437 return Status;
1438 }
1439
1440 /* PUBLIC FUNCTIONS ***********************************************************/
1441
1442 CODE_SEG("PAGE")
1443 VOID
DcFreeEeprom(_In_ PDC21X4_ADAPTER Adapter)1444 DcFreeEeprom(
1445 _In_ PDC21X4_ADAPTER Adapter)
1446 {
1447 PDC_SROM_ENTRY SRomEntry;
1448
1449 PAGED_CODE();
1450
1451 SRomEntry = Adapter->SRomEntry;
1452 if (!SRomEntry)
1453 return;
1454
1455 SRomAcquireListMutex();
1456
1457 /* Unregister the port */
1458 SRomEntry->DeviceBitmap &= ~(1 << Adapter->DeviceNumber);
1459
1460 /*
1461 * Free the SROM as soon as the last registered port has removed.
1462 * We can't free it in an unload handler
1463 * as the bus numbers can be changed by a resource rebalance.
1464 */
1465 if (SRomEntry->DeviceBitmap == 0)
1466 {
1467 INFO("Freeing SROM %p at %u:%u\n",
1468 SRomEntry,
1469 SRomEntry->BusNumber,
1470 SRomEntry->DeviceNumber);
1471
1472 RemoveEntryList(&SRomEntry->ListEntry);
1473
1474 NdisFreeMemory(SRomEntry, 0, 0);
1475 }
1476
1477 SRomReleaseListMutex();
1478 }
1479
1480 CODE_SEG("PAGE")
1481 NDIS_STATUS
DcReadEeprom(_In_ PDC21X4_ADAPTER Adapter)1482 DcReadEeprom(
1483 _In_ PDC21X4_ADAPTER Adapter)
1484 {
1485 NDIS_STATUS Status;
1486
1487 PAGED_CODE();
1488
1489 if (Adapter->ChipType == DC21040)
1490 {
1491 /* Ethernet Address ROM */
1492 Status = AddressRomRead(Adapter);
1493 }
1494 else
1495 {
1496 /* MicroWire Compatible Serial EEPROM */
1497 Status = SRomRead(Adapter);
1498 }
1499
1500 if (Status != NDIS_STATUS_SUCCESS)
1501 return Status;
1502
1503 INFO("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n",
1504 Adapter->PermanentMacAddress[0],
1505 Adapter->PermanentMacAddress[1],
1506 Adapter->PermanentMacAddress[2],
1507 Adapter->PermanentMacAddress[3],
1508 Adapter->PermanentMacAddress[4],
1509 Adapter->PermanentMacAddress[5]);
1510
1511 if (ETH_IS_BROADCAST(Adapter->PermanentMacAddress) ||
1512 ETH_IS_EMPTY(Adapter->PermanentMacAddress) ||
1513 ETH_IS_MULTICAST(Adapter->PermanentMacAddress))
1514 {
1515 ERR("Invalid permanent MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",
1516 Adapter->PermanentMacAddress[0],
1517 Adapter->PermanentMacAddress[1],
1518 Adapter->PermanentMacAddress[2],
1519 Adapter->PermanentMacAddress[3],
1520 Adapter->PermanentMacAddress[4],
1521 Adapter->PermanentMacAddress[5]);
1522
1523 NdisWriteErrorLogEntry(Adapter->AdapterHandle, NDIS_ERROR_CODE_NETWORK_ADDRESS, 0);
1524
1525 return NDIS_STATUS_INVALID_ADDRESS;
1526 }
1527
1528 return NDIS_STATUS_SUCCESS;
1529 }
1530