Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1090 lines
26 KiB

  1. #include <ndis.h>
  2. #include <e100_equ.h>
  3. #include <e100_557.h>
  4. #include <e100_def.h>
  5. #include <mp_def.h>
  6. #include <mp_cmn.h>
  7. #include <mp.h>
  8. #include <mp_nic.h>
  9. #include <mp_dbg.h>
  10. #include <e100_sup.h>
  11. // Things to note:
  12. // PME_ena bit should be active before the 82558 is set into low power mode
  13. // Default for WOL should generate wake up event after a HW Reset
  14. // Fixed Packet Filtering
  15. // Need to verify that the micro code is loaded and Micro Machine is active
  16. // Clock signal is active on PCI clock
  17. // Address Matching
  18. // Need to enable IAMatch_Wake_En bit and the MCMatch_Wake_En bit is set
  19. // ARP Wakeup
  20. // Need to set BRCST DISABL bet to 0 (broadcast enable)
  21. // To handle VLAN set the VLAN_ARP bit
  22. // IP address needs to be configured with 16 least significant bits
  23. // Set the IP Address in the IP_Address configuration word.
  24. // Fixed WakeUp Filters:
  25. // There are 3ight different fixed WakeUp Filters
  26. // ( Unicast, Multicast, Arp. etc).
  27. // Link Status Event
  28. // Set Link_Status_Wakeup Enable bit.
  29. // Flexible filtering:
  30. // Supports: ARP packets, Directed, Magic Packet and Link Event
  31. // Flexible Filtering Overview:
  32. // driver should program micro-code before setting card into low power
  33. // Incoming packets are compared against the loadable microcode. If PME is
  34. // is enabled then, the system is woken up.
  35. // Segments are defined in book - but not implemented here.
  36. // WakeUp Packet -that causes the machine to wake up will be stored
  37. // in the Micro Machine temporary storage area so that the driver can read it.
  38. // Software Work:
  39. // Power Down:
  40. // OS requests the driver to go to a low power state
  41. // Software Pends request
  42. // SW sets CU and RU to idle by issuing a Selective Reset to the device
  43. // 3rd portion .- Wake Up Segments defintion
  44. // The above three segments are loaded as on chain. The last CB must have
  45. // its EL bit set.
  46. // Device can now be powered down.
  47. // Software driver completes OS request
  48. // OS then physically switches the Device to low power state
  49. //
  50. // Power Up:
  51. // OS powers up the Device
  52. // OS tells the SW that it is now in D0
  53. // driver should NOT initialize the Device. It should NOT issue a Self Test
  54. // Driver Initiates a PORT DUMP command
  55. // Device dumps its internal registers including the wakeup frame storage area
  56. // SW reads the PME register
  57. // SW reads the WakeUp Frame Data, analyzes it and acts accordingly
  58. // SW restores its cvonfiguration and and resumes normal operation.
  59. //
  60. //
  61. // Power Management definitions from the Intel Handbook
  62. //
  63. //
  64. // Definitions from Table 4.2, Pg 4.9
  65. // of the 10/100 Mbit Ethernet Family Software Technical
  66. // Reference Manual
  67. //
  68. #define PMC_Offset 0xDE
  69. #define E100_PMC_WAKE_FROM_D0 0x1
  70. #define E100_PMC_WAKE_FROM_D1 0x2
  71. #define E100_PMC_WAKE_FROM_D2 0x4
  72. #define E100_PMC_WAKE_FROM_D3HOT 0x8
  73. #define E100_PMC_WAKE_FROM_D3_AUX 0x10
  74. //
  75. // Load Programmable filter definintions.
  76. // Taken from C-19 from the Software Reference Manual.
  77. // It has examples too. The opcode used for load is 0x80000
  78. //
  79. #define BIT_15_13 0xA000
  80. #define CB_LOAD_PROG_FILTER BIT_3
  81. #define CU_LOAD_PROG_FILTER_EL BIT_7
  82. #define CU_SUCCEED_LOAD_PROG_FILTER BIT_15_13
  83. #define CB_FILTER_EL BIT_7
  84. #define CB_FILTER_PREDEFINED_FIX BIT_6
  85. #define CB_FILTER_ARP_WAKEUP BIT_3
  86. #define CB_FILTER_IA_WAKEUP BIT_1
  87. #define CU_SCB_NULL ((UINT)-1)
  88. #pragma pack( push, enter_include1, 1 )
  89. //
  90. // Define the PM Capabilities register in the device
  91. // portion of the PCI config space
  92. //
  93. typedef struct _MP_PM_CAP_REG {
  94. USHORT UnInteresting:11;
  95. USHORT PME_Support:5;
  96. } MP_PM_CAP_REG;
  97. //
  98. // Define the PM Control/Status Register
  99. //
  100. typedef struct _MP_PMCSR {
  101. USHORT PowerState:2; // Power State;
  102. USHORT Res:2; // reserved
  103. USHORT DynData:1; // Ignored
  104. USHORT Res1:3; // Reserved
  105. USHORT PME_En:1; // Enable device to set the PME Event;
  106. USHORT DataSel:4; // Unused
  107. USHORT DataScale:2; // Data Scale - Unused
  108. USHORT PME_Status:1; // PME Status - Sticky bit;
  109. } MP_PMCSR ;
  110. typedef struct _MP_PM_PCI_SPACE {
  111. UCHAR Stuff[PMC_Offset];
  112. // PM capabilites
  113. MP_PM_CAP_REG PMCaps;
  114. // PM Control Status Register
  115. MP_PMCSR PMCSR;
  116. } MP_PM_PCI_SPACE , *PMP_PM_PCI_SPACE ;
  117. //
  118. // This is the Programmable Filter Command Structure
  119. //
  120. typedef struct _MP_PROG_FILTER_COMM_STRUCT
  121. {
  122. // CB Status Word
  123. USHORT CBStatus;
  124. // CB Command Word
  125. USHORT CBCommand;
  126. //Next CB PTR == ffff ffff
  127. ULONG NextCBPTR;
  128. //Programmable Filters
  129. ULONG FilterData[16];
  130. } MP_PROG_FILTER_COMM_STRUCT,*PMP_PROG_FILTER_COMM_STRUCT;
  131. typedef struct _MP_PMDR
  132. {
  133. // Status of the PME bit
  134. UCHAR PMEStatus:1;
  135. // Is the TCO busy
  136. UCHAR TCORequest:1;
  137. // Force TCO indication
  138. UCHAR TCOForce:1;
  139. // Is the TCO Ready
  140. UCHAR TCOReady:1;
  141. // Reserved
  142. UCHAR Reserved:1;
  143. // Has an InterestingPacket been received
  144. UCHAR InterestingPacket:1;
  145. // Has a Magic Packet been received
  146. UCHAR MagicPacket:1;
  147. // Has the Link Status been changed
  148. UCHAR LinkStatus:1;
  149. } MP_PMDR , *PMP_PMDR;
  150. //-------------------------------------------------------------------------
  151. // Structure used to set up a programmable filter.
  152. // This is overlayed over the Control/Status Register (CSR)
  153. //-------------------------------------------------------------------------
  154. typedef struct _CSR_FILTER_STRUC {
  155. // Status- used to verify if the load prog filter command
  156. // has been accepted .set to 0xa000
  157. USHORT ScbStatus; // SCB Status register
  158. // Set to an opcode of 0x8
  159. //
  160. UCHAR ScbCommandLow; // SCB Command register (low byte)
  161. // 80. Low + High gives the required opcode 0x80080000
  162. UCHAR ScbCommandHigh; // SCB Command register (high byte)
  163. // Set to NULL ff ff ff ff
  164. ULONG NextPointer; // SCB General pointer
  165. // Set to a hardcoded filter, Arp + IA Match, + IP address
  166. union
  167. {
  168. ULONG u32;
  169. struct {
  170. UCHAR IPAddress[2];
  171. UCHAR Reserved;
  172. UCHAR Set;
  173. }PreDefined;
  174. }Programmable; // Wake UP Filter union
  175. } CSR_FILTER_STRUC, *PCSR_FILTER_STRUC;
  176. #pragma pack( pop, enter_include1 )
  177. #define MP_CLEAR_PMDR(pPMDR) (*pPMDR) = ((*pPMDR) | 0xe0); // clear the 3 uppermost bits in the PMDR
  178. //-------------------------------------------------------------------------
  179. // L O C A L P R O T O T Y P E S
  180. //-------------------------------------------------------------------------
  181. __inline
  182. NDIS_STATUS
  183. MPIssueScbPoMgmtCommand(
  184. IN PMP_ADAPTER Adapter,
  185. IN PCSR_FILTER_STRUC pFilter,
  186. IN BOOLEAN WaitForScb
  187. );
  188. VOID
  189. MPCreateProgrammableFilter (
  190. IN PMP_WAKE_PATTERN pMpWakePattern ,
  191. IN PUCHAR pFilter,
  192. IN OUT PULONG pNext
  193. );
  194. //
  195. // Macros used to walk a doubly linked list. Only macros that are not defined in ndis.h
  196. // The List Next macro will work on Single and Doubly linked list as Flink is a common
  197. // field name in both
  198. //
  199. /*
  200. PLIST_ENTRY
  201. ListNext (
  202. IN PLIST_ENTRY
  203. );
  204. PSINGLE_LIST_ENTRY
  205. ListNext (
  206. IN PSINGLE_LIST_ENTRY
  207. );
  208. */
  209. #define ListNext(_pL) (_pL)->Flink
  210. /*
  211. PLIST_ENTRY
  212. ListPrev (
  213. IN LIST_ENTRY *
  214. );
  215. */
  216. #define ListPrev(_pL) (_pL)->Blink
  217. //-------------------------------------------------------------------------
  218. // P O W E R M G M T F U N C T I O N S
  219. //-------------------------------------------------------------------------
  220. PUCHAR
  221. HwReadPowerPMDR(
  222. IN PMP_ADAPTER Adapter
  223. )
  224. /*++
  225. Routine Description:
  226. This routine will Hardware's PM registers
  227. Arguments:
  228. Adapter Pointer to our adapter
  229. Return Value:
  230. NDIS_STATUS_SUCCESS
  231. NDIS_STATUS_HARD_ERRORS
  232. --*/
  233. {
  234. UCHAR PMDR =0;
  235. PUCHAR pPMDR = NULL;
  236. #define CSR_SIZE sizeof (*Adapter->CSRAddress)
  237. ASSERT (CSR_SIZE == 0x18);
  238. pPMDR = 0x18 + (PUCHAR)Adapter->CSRAddress ;
  239. PMDR = *pPMDR;
  240. return pPMDR;
  241. }
  242. NDIS_STATUS
  243. MPWritePciSlotInfo(
  244. PMP_ADAPTER pAdapter,
  245. ULONG Offset,
  246. PVOID pValue,
  247. ULONG SizeofValue
  248. )
  249. {
  250. ULONG ulResult;
  251. NDIS_STATUS Status;
  252. ulResult = NdisWritePciSlotInformation(
  253. pAdapter->AdapterHandle,
  254. 0,
  255. Offset,
  256. pValue,
  257. SizeofValue);
  258. ASSERT (ulResult == SizeofValue);
  259. // What do we do in case of failure;
  260. //
  261. if (ulResult == SizeofValue)
  262. {
  263. Status = NDIS_STATUS_SUCCESS;
  264. }
  265. else
  266. {
  267. Status = NDIS_STATUS_FAILURE;
  268. }
  269. return Status;
  270. }
  271. NDIS_STATUS
  272. MPReadPciSlotInfo(
  273. PMP_ADAPTER pAdapter,
  274. ULONG Offset,
  275. PVOID pValue,
  276. ULONG SizeofValue
  277. )
  278. {
  279. ULONG ulResult;
  280. NDIS_STATUS Status;
  281. ulResult = NdisReadPciSlotInformation(
  282. pAdapter->AdapterHandle,
  283. 0,
  284. Offset,
  285. pValue,
  286. SizeofValue);
  287. ASSERT (ulResult == SizeofValue);
  288. // What do we do in case of failure;
  289. //
  290. if (ulResult == SizeofValue)
  291. {
  292. Status = NDIS_STATUS_SUCCESS;
  293. }
  294. else
  295. {
  296. Status = NDIS_STATUS_FAILURE;
  297. }
  298. return Status;
  299. }
  300. NDIS_STATUS
  301. MpClearPME_En (
  302. IN PMP_ADAPTER pAdapter,
  303. IN MP_PMCSR PMCSR
  304. )
  305. {
  306. NDIS_STATUS Status;
  307. UINT ulResult;
  308. PMCSR.PME_En = 0;
  309. Status = MPWritePciSlotInfo( pAdapter,
  310. FIELD_OFFSET(MP_PM_PCI_SPACE, PMCSR),
  311. (PVOID)&PMCSR,
  312. sizeof(PMCSR));
  313. return Status;
  314. }
  315. VOID MpExtractPMInfoFromPciSpace(
  316. PMP_ADAPTER pAdapter,
  317. PUCHAR pPciConfig
  318. )
  319. /*++
  320. Routine Description:
  321. Looks at the PM information in the
  322. device specific section of the PCI Config space.
  323. Interprets the register values and stores it
  324. in the adapter structure
  325. Definitions from Table 4.2 & 4.3, Pg 4-9 & 4-10
  326. of the 10/100 Mbit Ethernet Family Software Technical
  327. Reference Manual
  328. Arguments:
  329. Adapter Pointer to our adapter
  330. pPciConfig Pointer to Common Pci Space
  331. Return Value:
  332. --*/
  333. {
  334. PMP_PM_PCI_SPACE pPmPciConfig = (PMP_PM_PCI_SPACE )pPciConfig;
  335. PMP_POWER_MGMT pPoMgmt = &pAdapter->PoMgmt;
  336. MP_PMCSR PMCSR;
  337. //
  338. // First interpret the PM Capabities register
  339. //
  340. {
  341. MP_PM_CAP_REG PmCaps;
  342. PmCaps = pPmPciConfig->PMCaps;
  343. if(PmCaps.PME_Support & E100_PMC_WAKE_FROM_D0)
  344. {
  345. pAdapter->PoMgmt.bWakeFromD0 = TRUE;
  346. }
  347. if(PmCaps.PME_Support & E100_PMC_WAKE_FROM_D1)
  348. {
  349. pAdapter->PoMgmt.bWakeFromD1 = TRUE;
  350. }
  351. if(PmCaps.PME_Support & E100_PMC_WAKE_FROM_D2)
  352. {
  353. pAdapter->PoMgmt.bWakeFromD2 = TRUE;
  354. }
  355. if(PmCaps.PME_Support & E100_PMC_WAKE_FROM_D3HOT)
  356. {
  357. pAdapter->PoMgmt.bWakeFromD3Hot = TRUE;
  358. }
  359. if(PmCaps.PME_Support & E100_PMC_WAKE_FROM_D3_AUX)
  360. {
  361. pAdapter->PoMgmt.bWakeFromD3Aux = TRUE;
  362. }
  363. }
  364. //
  365. // Interpret the PM Control/Status Register
  366. //
  367. {
  368. PMCSR = pPmPciConfig->PMCSR;
  369. if (PMCSR.PME_En == 1)
  370. {
  371. //
  372. // PME is enabled. Clear the PME_En bit.
  373. // So that it is not asserted
  374. //
  375. MpClearPME_En (pAdapter,PMCSR);
  376. }
  377. //pPoMgmt->PowerState = PMCSR.PowerState;
  378. }
  379. }
  380. VOID
  381. MPSetPowerLowPrivate(
  382. PMP_ADAPTER pAdapter
  383. )
  384. /*++
  385. Routine Description:
  386. The section follows the steps mentioned in
  387. Section C.2.6.2 of the Reference Manual.
  388. Arguments:
  389. Adapter Pointer to our adapter
  390. Return Value:
  391. --*/
  392. {
  393. CSR_FILTER_STRUC Filter;
  394. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  395. USHORT IntStatus;
  396. MP_PMCSR PMCSR;
  397. NdisZeroMemory (&Filter, sizeof (Filter));
  398. do
  399. {
  400. //
  401. // Before issue the command to low power state, we should disable the
  402. // interrup and ack all the pending interrupts, then set the adapter's power to
  403. // low state.
  404. //
  405. NICDisableInterrupt(pAdapter);
  406. NIC_ACK_INTERRUPT(pAdapter, IntStatus);
  407. pAdapter->CurrentPowerState = pAdapter->NextPowerState;
  408. //
  409. // If the driver should wake up the machine
  410. //
  411. if (pAdapter->WakeUpEnable != 0)
  412. {
  413. //
  414. // Send the WakeUp Patter to the nic
  415. MPIssueScbPoMgmtCommand(pAdapter, &Filter, TRUE);
  416. //
  417. // Section C.2.6.2 - The driver needs to wait for the CU to idle
  418. // The above function already waits for the CU to idle
  419. //
  420. ASSERT ((pAdapter->CSRAddress->ScbStatus & SCB_CUS_MASK) == SCB_CUS_IDLE);
  421. }
  422. else
  423. {
  424. MPReadPciSlotInfo(pAdapter,
  425. FIELD_OFFSET(MP_PM_PCI_SPACE, PMCSR),
  426. (PVOID)&PMCSR,
  427. sizeof(PMCSR));
  428. if (PMCSR.PME_En == 1)
  429. {
  430. //
  431. // PME is enabled. Clear the PME_En bit.
  432. // So that it is not asserted
  433. //
  434. MpClearPME_En (pAdapter,PMCSR);
  435. }
  436. //
  437. // Set the driver to lower power state by OS
  438. //
  439. }
  440. } while (FALSE);
  441. }
  442. NDIS_STATUS
  443. MPSetPowerD0Private (
  444. IN MP_ADAPTER* pAdapter
  445. )
  446. {
  447. PUCHAR pPMDR;
  448. NDIS_STATUS Status;
  449. do
  450. {
  451. // Dump the packet if necessary
  452. //Cause of Wake Up
  453. pPMDR = HwReadPowerPMDR(pAdapter);
  454. NICInitializeAdapter(pAdapter);
  455. // Clear the PMDR
  456. MP_CLEAR_PMDR(pPMDR);
  457. NICIssueSelectiveReset(pAdapter);
  458. } while (FALSE);
  459. return NDIS_STATUS_SUCCESS;
  460. }
  461. VOID
  462. MPSetPowerWorkItem(
  463. IN PNDIS_WORK_ITEM pWorkItem,
  464. IN PVOID pContext
  465. )
  466. {
  467. //
  468. // Call the appropriate function
  469. //
  470. //
  471. // Complete the original request
  472. //
  473. }
  474. VOID
  475. HwSetWakeUpConfigure(
  476. IN PMP_ADAPTER pAdapter,
  477. PUCHAR pPoMgmtConfigType,
  478. UINT WakeUpParameter
  479. )
  480. {
  481. if (MPIsPoMgmtSupported( pAdapter) == TRUE)
  482. {
  483. (*pPoMgmtConfigType)= ((*pPoMgmtConfigType)| CB_WAKE_ON_LINK_BYTE9 |CB_WAKE_ON_ARP_PKT_BYTE9 );
  484. }
  485. }
  486. NDIS_STATUS
  487. MPSetUpFilterCB(
  488. IN PMP_ADAPTER pAdapter
  489. )
  490. {
  491. NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
  492. PCB_HEADER_STRUC NonTxCmdBlockHdr = (PCB_HEADER_STRUC)pAdapter->NonTxCmdBlock;
  493. PFILTER_CB_STRUC pFilterCb = (PFILTER_CB_STRUC)NonTxCmdBlockHdr;
  494. ULONG Curr = 0;
  495. ULONG Next = 0;
  496. PLIST_ENTRY pPatternEntry = ListNext(&pAdapter->PoMgmt.PatternList) ;
  497. DBGPRINT(MP_TRACE, ("--> HwSetupIAAddress\n"));
  498. NdisZeroMemory (pFilterCb, sizeof(*pFilterCb));
  499. // Individual Address Setup
  500. NonTxCmdBlockHdr->CbStatus = 0;
  501. NonTxCmdBlockHdr->CbCommand = CB_EL_BIT | CB_LOAD_PROG_FILTER;
  502. NonTxCmdBlockHdr->CbLinkPointer = DRIVER_NULL;
  503. // go through each filter in the list.
  504. while (pPatternEntry != (&pAdapter->PoMgmt.PatternList))
  505. {
  506. PMP_WAKE_PATTERN pWakeUpPattern = NULL;
  507. PNDIS_PM_PACKET_PATTERN pCurrPattern = NULL;;
  508. // initialize local variables
  509. pWakeUpPattern = CONTAINING_RECORD(pPatternEntry, MP_WAKE_PATTERN, linkListEntry);
  510. // increment the iterator
  511. pPatternEntry = ListNext (pPatternEntry);
  512. // Update the Curr Array Pointer
  513. Curr = Next;
  514. // Create the Programmable filter for this device.
  515. MPCreateProgrammableFilter (pWakeUpPattern , (PUCHAR)&pFilterCb->Pattern[Curr], &Next);
  516. if (Next >=16)
  517. {
  518. break;
  519. }
  520. }
  521. {
  522. // Set the EL bit on the last pattern
  523. PUCHAR pLastPattern = (PUCHAR) &pFilterCb->Pattern[Curr];
  524. // Get to bit 31
  525. pLastPattern[3] |= CB_FILTER_EL ;
  526. }
  527. ASSERT(pAdapter->CSRAddress->ScbCommandLow == 0)
  528. // Wait for the CU to Idle before giving it this command
  529. if(!WaitScb(pAdapter))
  530. {
  531. Status = NDIS_STATUS_HARD_ERRORS;
  532. }
  533. return Status;
  534. }
  535. NDIS_STATUS
  536. MPIssueScbPoMgmtCommand(
  537. IN PMP_ADAPTER pAdapter,
  538. IN PCSR_FILTER_STRUC pNewFilter,
  539. IN BOOLEAN WaitForScb
  540. )
  541. {
  542. NDIS_STATUS Status = NDIS_STATUS_FAILURE;
  543. do
  544. {
  545. // Set up SCB to issue this command
  546. Status = MPSetUpFilterCB(pAdapter);
  547. if (Status != NDIS_STATUS_SUCCESS)
  548. {
  549. break;
  550. }
  551. // Submit the configure command to the chip, and wait for it to complete.
  552. pAdapter->CSRAddress->ScbGeneralPointer = pAdapter->NonTxCmdBlockPhys;
  553. Status = D100SubmitCommandBlockAndWait(pAdapter);
  554. if(Status != NDIS_STATUS_SUCCESS)
  555. {
  556. Status = NDIS_STATUS_NOT_ACCEPTED;
  557. break;
  558. }
  559. } while (FALSE);
  560. return Status;
  561. }
  562. NDIS_STATUS
  563. MPCalculateE100PatternForFilter (
  564. IN PUCHAR pFrame,
  565. IN ULONG FrameLength,
  566. IN PUCHAR pMask,
  567. IN ULONG MaskLength,
  568. OUT PULONG pSignature
  569. )
  570. /*++
  571. Routine Description:
  572. This function outputs the E100 specific Pattern Signature
  573. used to wake up the machine.
  574. Section C.2.4 - CRC word calculation of a Flexible Filer
  575. Arguments:
  576. pFrame - Pattern Set by the protocols
  577. FrameLength - Length of the Pattern
  578. pMask - Mask set by the Protocols
  579. MaskLength - Length of the Mask
  580. pSignature - caller allocated return structure
  581. Return Value:
  582. Returns Success
  583. Failure - if the Pattern is greater than 129 bytes
  584. --*/
  585. {
  586. const ULONG Coefficients = 0x04c11db7;
  587. ULONG Signature = 0;
  588. ULONG n = 0;
  589. ULONG i= 0;
  590. PUCHAR pCurrentMaskByte = pMask - 1; // init to -1
  591. ULONG MaskOffset = 0;
  592. ULONG BitOffsetInMask = 0;
  593. ULONG MaskBit = 0;
  594. BOOLEAN fIgnoreCurrentByte = FALSE;
  595. ULONG ShiftBy = 0;
  596. UCHAR FrameByte = 0;
  597. NDIS_STATUS Status = NDIS_STATUS_FAILURE;
  598. *pSignature = 0;
  599. do
  600. {
  601. if (FrameLength > 128)
  602. {
  603. Status = NDIS_STATUS_FAILURE;
  604. break;
  605. }
  606. // The E100 driver can only accept 3 DWORDS of Mask in a single pattern
  607. if (MaskLength > (3*sizeof(ULONG)))
  608. {
  609. Status = NDIS_STATUS_FAILURE;
  610. break;
  611. }
  612. for (n=i=0;(n<128) && (n < FrameLength); ++n)
  613. {
  614. // The first half deals with the question -
  615. // Is the nth Frame byte to be included in the Filter
  616. //
  617. BitOffsetInMask = (n % 8);
  618. if (BitOffsetInMask == 0)
  619. {
  620. //
  621. // We need to move to a new byte.
  622. // [0] for 0th byte, [1] for 8th byte, [2] for 16th byte, etc.
  623. //
  624. MaskOffset = n/8; // This is the new byte we need to go
  625. //
  626. //
  627. if (MaskOffset == MaskLength)
  628. {
  629. break;
  630. }
  631. pCurrentMaskByte ++;
  632. ASSERT (*pCurrentMaskByte == pMask[n/8]);
  633. }
  634. // Now look at the actual bit in the mask
  635. MaskBit = 1 << BitOffsetInMask ;
  636. // If the current Mask Bit is set in the Mask then
  637. // we need to use it in the CRC calculation, otherwise we ignore it
  638. fIgnoreCurrentByte = ! (MaskBit & pCurrentMaskByte[0]);
  639. if (fIgnoreCurrentByte)
  640. {
  641. continue;
  642. }
  643. // We are suppossed to take in the current byte as part of the CRC calculation
  644. // Initialize the variables
  645. FrameByte = pFrame[n];
  646. ShiftBy = (i % 3 ) * 8;
  647. ASSERT (ShiftBy!= 24); // Bit 24 is never used
  648. if (Signature & 0x80000000)
  649. {
  650. Signature = ((Signature << 1) ^ ( FrameByte << ShiftBy) ^ Coefficients);
  651. }
  652. else
  653. {
  654. Signature = ((Signature << 1 ) ^ (FrameByte << ShiftBy));
  655. }
  656. ++i;
  657. }
  658. // Clear bits 22-31
  659. Signature &= 0x00ffffff;
  660. // Update the result
  661. *pSignature = Signature;
  662. // We have succeeded
  663. Status = NDIS_STATUS_SUCCESS;
  664. } while (FALSE);
  665. return Status;
  666. }
  667. VOID
  668. MPCreateProgrammableFilter (
  669. IN PMP_WAKE_PATTERN pMpWakePattern ,
  670. IN PUCHAR pFilter,
  671. IN OUT PULONG pNext
  672. )
  673. /*++
  674. Routine Description:
  675. This function outputs the E100 specific Pattern Signature
  676. used to wake up the machine.
  677. Section C.2.4 - Load Programmable Filter page C.20
  678. Arguments:
  679. pMpWakePattern - Filter will be created for this pattern,
  680. pFilter - Filter will be stored here,
  681. pNext - Used for validation . This Ulong will also be incremented by the size
  682. of the filter (in ulongs)
  683. Return Value:
  684. --*/
  685. {
  686. PUCHAR pCurrentByte = pFilter;
  687. ULONG NumBytesWritten = 0;
  688. PULONG pCurrentUlong = (PULONG)pFilter;
  689. PNDIS_PM_PACKET_PATTERN pNdisPattern = (PNDIS_PM_PACKET_PATTERN)(&pMpWakePattern->Pattern[0]);
  690. ULONG LengthOfFilter = 0;
  691. // Is there enough room for this pattern
  692. //
  693. {
  694. // Length in DWORDS
  695. LengthOfFilter = pNdisPattern->MaskSize /4;
  696. if (pNdisPattern->MaskSize % 4 != 0)
  697. {
  698. LengthOfFilter++;
  699. }
  700. // Increment LengthOfFilter to account for the 1st DWORD
  701. LengthOfFilter++;
  702. // We are only allowed 16 DWORDS in a filter
  703. if (*pNext + LengthOfFilter >= 16)
  704. {
  705. // Failure - early exit
  706. return;
  707. }
  708. }
  709. // Clear the Predefined bit; already cleared in the previous function.
  710. // first , initialize -
  711. *pCurrentUlong = 0;
  712. // Mask Length goes into Bits 27-29 of the 1st DWORD. MaskSize is measured in DWORDs
  713. {
  714. ULONG dwMaskSize = pNdisPattern->MaskSize /4;
  715. ULONG dwMLen = 0;
  716. // If there is a remainder a remainder then increment
  717. if (pNdisPattern->MaskSize % 4 != 0)
  718. {
  719. dwMaskSize++;
  720. }
  721. //
  722. // If we fail this assertion, it means our
  723. // MaskSize is greater than 16 bytes.
  724. // This filter should have been failed upfront at the time of the request
  725. //
  726. ASSERT (0 < dwMaskSize <5);
  727. //
  728. // In the Spec, 0 - Single DWORD maske, 001 - 2 DWORD mask,
  729. // 011 - 3 DWORD mask, 111 - 4 Dword Mask.
  730. //
  731. if (dwMaskSize == 1) dwMLen = 0;
  732. if (dwMaskSize == 2) dwMLen = 1;
  733. if (dwMaskSize == 3) dwMLen = 3;
  734. if (dwMaskSize == 4) dwMLen = 7;
  735. // Adjust the Mlen, so it is in the correct position
  736. dwMLen = (dwMLen << 3);
  737. if (dwMLen != 0)
  738. {
  739. ASSERT (dwMLen <= 0x38 && dwMLen >= 0x08);
  740. }
  741. // These go into bits 27,28,29 (bits 3,4 and 5 of the 4th byte)
  742. pCurrentByte[3] |= dwMLen ;
  743. }
  744. // Add the signature to bits 0-23 of the 1st DWORD
  745. {
  746. PUCHAR pSignature = (PUCHAR)&pMpWakePattern->Signature;
  747. // Bits 0-23 are also the 1st three bytes of the DWORD
  748. pCurrentByte[0] = pSignature[0];
  749. pCurrentByte[1] = pSignature[1];
  750. pCurrentByte[2] = pSignature[2];
  751. }
  752. // Lets move to the next DWORD. Init variables
  753. pCurrentByte += 4 ;
  754. NumBytesWritten = 4;
  755. pCurrentUlong = (PULONG)pCurrentByte;
  756. // We Copy in the Mask over here
  757. {
  758. // The Mask is at the end of the pattern
  759. PUCHAR pMask = (PUCHAR)pNdisPattern + sizeof(*pNdisPattern);
  760. Dump (pMask,pNdisPattern->MaskSize, 0,1);
  761. NdisMoveMemory (pCurrentByte, pMask, pNdisPattern->MaskSize);
  762. NumBytesWritten += pNdisPattern->MaskSize;
  763. }
  764. // Update the output value
  765. {
  766. ULONG NumUlongs = (NumBytesWritten /4);
  767. if ((NumBytesWritten %4) != 0)
  768. {
  769. NumUlongs ++;
  770. }
  771. ASSERT (NumUlongs == LengthOfFilter);
  772. *pNext = *pNext + NumUlongs;
  773. }
  774. return;
  775. }