e100hw.c 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. e100hw.c
  5. Abstract:
  6. This module implements the portion of the e100 driver that actually
  7. interacts with the hardware.
  8. Author:
  9. Evan Green 4-Apr-2013
  10. Environment:
  11. Kernel
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. #include <minoca/kernel/driver.h>
  17. #include <minoca/net/netdrv.h>
  18. #include "e100.h"
  19. //
  20. // ---------------------------------------------------------------- Definitions
  21. //
  22. //
  23. // Define the maximum amount of packets that E100 will keep queued before it
  24. // starts to drop packets.
  25. //
  26. #define E100_MAX_TRANSMIT_PACKET_LIST_COUNT (E100_COMMAND_RING_COUNT * 2)
  27. //
  28. // ------------------------------------------------------ Data Type Definitions
  29. //
  30. //
  31. // ----------------------------------------------- Internal Function Prototypes
  32. //
  33. KSTATUS
  34. E100pReadDeviceMacAddress (
  35. PE100_DEVICE Device
  36. );
  37. KSTATUS
  38. E100pPerformEepromIo (
  39. PE100_DEVICE Device,
  40. USHORT RegisterOffset,
  41. PUSHORT Value,
  42. BOOL Write
  43. );
  44. KSTATUS
  45. E100pDetermineEepromAddressWidth (
  46. PE100_DEVICE Device
  47. );
  48. VOID
  49. E100pReapCompletedCommands (
  50. PE100_DEVICE Device
  51. );
  52. VOID
  53. E100pReapReceivedFrames (
  54. PE100_DEVICE Device
  55. );
  56. VOID
  57. E100pSendPendingPackets (
  58. PE100_DEVICE Device
  59. );
  60. //
  61. // -------------------------------------------------------------------- Globals
  62. //
  63. BOOL E100DisablePacketDropping = FALSE;
  64. //
  65. // ------------------------------------------------------------------ Functions
  66. //
  67. KSTATUS
  68. E100Send (
  69. PVOID DeviceContext,
  70. PNET_PACKET_LIST PacketList
  71. )
  72. /*++
  73. Routine Description:
  74. This routine sends data through the network.
  75. Arguments:
  76. DeviceContext - Supplies a pointer to the device context associated with
  77. the link down which this data is to be sent.
  78. PacketList - Supplies a pointer to a list of network packets to send. Data
  79. in these packets may be modified by this routine, but must not be used
  80. once this routine returns.
  81. Return Value:
  82. STATUS_SUCCESS if all packets were sent.
  83. STATUS_RESOURCE_IN_USE if some or all of the packets were dropped due to
  84. the hardware being backed up with too many packets to send.
  85. Other failure codes indicate that none of the packets were sent.
  86. --*/
  87. {
  88. PE100_DEVICE Device;
  89. UINTN PacketListCount;
  90. KSTATUS Status;
  91. ASSERT(KeGetRunLevel() == RunLevelLow);
  92. Device = (PE100_DEVICE)DeviceContext;
  93. KeAcquireQueuedLock(Device->CommandListLock);
  94. if (Device->LinkActive == FALSE) {
  95. Status = STATUS_NO_NETWORK_CONNECTION;
  96. goto SendEnd;
  97. }
  98. //
  99. // If there is any room in the packet list (or dropping packets is
  100. // disabled), add all of the packets to the list waiting to be sent.
  101. //
  102. PacketListCount = Device->TransmitPacketList.Count;
  103. if ((PacketListCount < E100_MAX_TRANSMIT_PACKET_LIST_COUNT) ||
  104. (E100DisablePacketDropping != FALSE)) {
  105. NET_APPEND_PACKET_LIST(PacketList, &(Device->TransmitPacketList));
  106. E100pSendPendingPackets(Device);
  107. Status = STATUS_SUCCESS;
  108. //
  109. // Otherwise report that the resource is use as it is too busy to handle
  110. // more packets.
  111. //
  112. } else {
  113. Status = STATUS_RESOURCE_IN_USE;
  114. }
  115. SendEnd:
  116. KeReleaseQueuedLock(Device->CommandListLock);
  117. return Status;
  118. }
  119. KSTATUS
  120. E100GetSetInformation (
  121. PVOID DeviceContext,
  122. NET_LINK_INFORMATION_TYPE InformationType,
  123. PVOID Data,
  124. PUINTN DataSize,
  125. BOOL Set
  126. )
  127. /*++
  128. Routine Description:
  129. This routine gets or sets the network device layer's link information.
  130. Arguments:
  131. DeviceContext - Supplies a pointer to the device context associated with
  132. the link for which information is being set or queried.
  133. InformationType - Supplies the type of information being queried or set.
  134. Data - Supplies a pointer to the data buffer where the data is either
  135. returned for a get operation or given for a set operation.
  136. DataSize - Supplies a pointer that on input contains the size of the data
  137. buffer. On output, contains the required size of the data buffer.
  138. Set - Supplies a boolean indicating if this is a get operation (FALSE) or a
  139. set operation (TRUE).
  140. Return Value:
  141. Status code.
  142. --*/
  143. {
  144. PULONG Flags;
  145. KSTATUS Status;
  146. switch (InformationType) {
  147. case NetLinkInformationChecksumOffload:
  148. if (*DataSize != sizeof(ULONG)) {
  149. return STATUS_INVALID_PARAMETER;
  150. }
  151. if (Set != FALSE) {
  152. return STATUS_NOT_SUPPORTED;
  153. }
  154. Flags = (PULONG)Data;
  155. *Flags = 0;
  156. break;
  157. default:
  158. Status = STATUS_NOT_SUPPORTED;
  159. break;
  160. }
  161. return Status;
  162. }
  163. KSTATUS
  164. E100pInitializeDeviceStructures (
  165. PE100_DEVICE Device
  166. )
  167. /*++
  168. Routine Description:
  169. This routine performs housekeeping preparation for resetting and enabling
  170. an E100 device.
  171. Arguments:
  172. Device - Supplies a pointer to the device.
  173. Return Value:
  174. Status code.
  175. --*/
  176. {
  177. ULONG AllocationSize;
  178. PE100_COMMAND Command;
  179. ULONG CommandIndex;
  180. ULONG CommandSize;
  181. PE100_RECEIVE_FRAME Frame;
  182. ULONG FrameBasePhysical;
  183. ULONG FrameIndex;
  184. ULONG IoBufferFlags;
  185. ULONG NextFrameAddress;
  186. ULONG ReceiveSize;
  187. KSTATUS Status;
  188. //
  189. // Initialize the command and receive list locks.
  190. //
  191. Device->CommandListLock = KeCreateQueuedLock();
  192. if (Device->CommandListLock == NULL) {
  193. Status = STATUS_INSUFFICIENT_RESOURCES;
  194. goto InitializeDeviceStructuresEnd;
  195. }
  196. Device->ReceiveListLock = KeCreateQueuedLock();
  197. if (Device->ReceiveListLock == NULL) {
  198. Status = STATUS_INSUFFICIENT_RESOURCES;
  199. goto InitializeDeviceStructuresEnd;
  200. }
  201. //
  202. // Allocate the receive buffers. This is allocated as non-write though and
  203. // cacheable, which means software must be careful when the frame is
  204. // first received (and do an invalidate), and when setting up the
  205. // link pointers, but after the receive is complete it's normal memory.
  206. //
  207. ReceiveSize = sizeof(E100_RECEIVE_FRAME) * E100_RECEIVE_FRAME_COUNT;
  208. ASSERT(Device->ReceiveFrameIoBuffer == NULL);
  209. IoBufferFlags = IO_BUFFER_FLAG_PHYSICALLY_CONTIGUOUS;
  210. Device->ReceiveFrameIoBuffer = MmAllocateNonPagedIoBuffer(0,
  211. MAX_ULONG,
  212. 16,
  213. ReceiveSize,
  214. IoBufferFlags);
  215. if (Device->ReceiveFrameIoBuffer == NULL) {
  216. Status = STATUS_INSUFFICIENT_RESOURCES;
  217. goto InitializeDeviceStructuresEnd;
  218. }
  219. ASSERT(Device->ReceiveFrameIoBuffer->FragmentCount == 1);
  220. ASSERT(Device->ReceiveFrameIoBuffer->Fragment[0].VirtualAddress != NULL);
  221. Device->ReceiveFrame =
  222. Device->ReceiveFrameIoBuffer->Fragment[0].VirtualAddress;
  223. Device->ReceiveListBegin = 0;
  224. //
  225. // Allocate the command blocks (which don't include the data to transmit).
  226. // This memory is allocated non-cached since every write and read
  227. // essentially interacts with the hardware, and the data to transmit isn't
  228. // included.
  229. //
  230. CommandSize = sizeof(E100_COMMAND) * E100_COMMAND_RING_COUNT;
  231. ASSERT(Device->CommandIoBuffer == NULL);
  232. IoBufferFlags = IO_BUFFER_FLAG_PHYSICALLY_CONTIGUOUS;
  233. Device->CommandIoBuffer = MmAllocateNonPagedIoBuffer(0,
  234. MAX_ULONG,
  235. 16,
  236. CommandSize,
  237. IoBufferFlags);
  238. if (Device->CommandIoBuffer == NULL) {
  239. Status = STATUS_INSUFFICIENT_RESOURCES;
  240. goto InitializeDeviceStructuresEnd;
  241. }
  242. ASSERT(Device->CommandIoBuffer->FragmentCount == 1);
  243. ASSERT(Device->CommandIoBuffer->Fragment[0].VirtualAddress != NULL);
  244. Device->Command = Device->CommandIoBuffer->Fragment[0].VirtualAddress;
  245. Device->CommandLastReaped = E100_COMMAND_RING_COUNT - 1;
  246. Device->CommandNextToUse = 1;
  247. RtlZeroMemory(Device->Command, CommandSize);
  248. NET_INITIALIZE_PACKET_LIST(&(Device->TransmitPacketList));
  249. //
  250. // Allocate an array of pointers to net packet buffers that runs parallel
  251. // to the command array.
  252. //
  253. AllocationSize = sizeof(PNET_PACKET_BUFFER) * E100_COMMAND_RING_COUNT;
  254. Device->CommandPacket = MmAllocatePagedPool(AllocationSize,
  255. E100_ALLOCATION_TAG);
  256. if (Device->CommandPacket == NULL) {
  257. Status = STATUS_INSUFFICIENT_RESOURCES;
  258. goto InitializeDeviceStructuresEnd;
  259. }
  260. RtlZeroMemory(Device->CommandPacket, AllocationSize);
  261. ASSERT(Device->LinkCheckTimer == NULL);
  262. Device->LinkCheckTimer = KeCreateTimer(E100_ALLOCATION_TAG);
  263. if (Device->LinkCheckTimer == NULL) {
  264. Status = STATUS_INSUFFICIENT_RESOURCES;
  265. goto InitializeDeviceStructuresEnd;
  266. }
  267. //
  268. // Initialize the receive frame list.
  269. //
  270. FrameBasePhysical =
  271. (ULONG)(Device->ReceiveFrameIoBuffer->Fragment[0].PhysicalAddress);
  272. NextFrameAddress = FrameBasePhysical + sizeof(E100_RECEIVE_FRAME);
  273. for (FrameIndex = 0;
  274. FrameIndex < E100_RECEIVE_FRAME_COUNT;
  275. FrameIndex += 1) {
  276. Frame = &(Device->ReceiveFrame[FrameIndex]);
  277. Frame->Status = 0;
  278. if (FrameIndex == E100_RECEIVE_FRAME_COUNT - 1) {
  279. Frame->Status |= E100_RECEIVE_COMMAND_SUSPEND;
  280. Frame->NextFrame = FrameBasePhysical;
  281. } else {
  282. Frame->NextFrame = NextFrameAddress;
  283. }
  284. NextFrameAddress += sizeof(E100_RECEIVE_FRAME);
  285. Frame->Sizes = RECEIVE_FRAME_DATA_SIZE <<
  286. E100_RECEIVE_SIZE_BUFFER_SIZE_SHIFT;
  287. }
  288. //
  289. // Initialize the ring of commands.
  290. //
  291. FrameBasePhysical =
  292. (ULONG)(Device->CommandIoBuffer->Fragment[0].PhysicalAddress);
  293. NextFrameAddress = FrameBasePhysical + sizeof(E100_COMMAND);
  294. for (CommandIndex = 0;
  295. CommandIndex < E100_COMMAND_RING_COUNT;
  296. CommandIndex += 1) {
  297. Command = &(Device->Command[CommandIndex]);
  298. Command->Command = 0;
  299. //
  300. // Loop the last command back around to the first: a real ring!
  301. //
  302. if (CommandIndex == E100_COMMAND_RING_COUNT - 1) {
  303. Command->NextCommand = FrameBasePhysical;
  304. //
  305. // Point this link at the next command.
  306. //
  307. } else {
  308. Command->NextCommand = NextFrameAddress;
  309. NextFrameAddress += sizeof(E100_COMMAND);
  310. }
  311. }
  312. //
  313. // Set the first command to be a no-op that suspends the command unit.
  314. //
  315. Command = &(Device->Command[0]);
  316. Command->Command = E100_COMMAND_SUSPEND | E100_COMMAND_NOP;
  317. Status = STATUS_SUCCESS;
  318. InitializeDeviceStructuresEnd:
  319. if (!KSUCCESS(Status)) {
  320. if (Device->CommandListLock != NULL) {
  321. KeDestroyQueuedLock(Device->CommandListLock);
  322. Device->CommandListLock = NULL;
  323. }
  324. if (Device->ReceiveListLock != NULL) {
  325. KeDestroyQueuedLock(Device->ReceiveListLock);
  326. Device->ReceiveListLock = NULL;
  327. }
  328. if (Device->ReceiveFrameIoBuffer != NULL) {
  329. MmFreeIoBuffer(Device->ReceiveFrameIoBuffer);
  330. Device->ReceiveFrameIoBuffer = NULL;
  331. Device->ReceiveFrame = NULL;
  332. }
  333. if (Device->CommandIoBuffer != NULL) {
  334. MmFreeIoBuffer(Device->CommandIoBuffer);
  335. Device->CommandIoBuffer = NULL;
  336. Device->Command = NULL;
  337. }
  338. if (Device->CommandPacket != NULL) {
  339. MmFreePagedPool(Device->CommandPacket);
  340. Device->CommandPacket = NULL;
  341. }
  342. if (Device->LinkCheckTimer != NULL) {
  343. KeDestroyTimer(Device->LinkCheckTimer);
  344. Device->LinkCheckTimer = NULL;
  345. }
  346. }
  347. return Status;
  348. }
  349. KSTATUS
  350. E100pResetDevice (
  351. PE100_DEVICE Device
  352. )
  353. /*++
  354. Routine Description:
  355. This routine resets the E100 device.
  356. Arguments:
  357. Device - Supplies a pointer to the device.
  358. Return Value:
  359. Status code.
  360. --*/
  361. {
  362. PE100_COMMAND Command;
  363. ULONG CommandIndex;
  364. UCHAR GeneralStatus;
  365. ULONGLONG LinkSpeed;
  366. PE100_COMMAND PreviousCommand;
  367. ULONG PreviousCommandIndex;
  368. KSTATUS Status;
  369. ULONGLONG Timeout;
  370. ULONG Value;
  371. //
  372. // Perform a complete device reset.
  373. //
  374. E100_WRITE_REGISTER32(Device, E100RegisterPort, E100_PORT_RESET);
  375. HlBusySpin(E100_PORT_RESET_DELAY_MICROSECONDS);
  376. //
  377. // Read the MAC address out of the EEPROM.
  378. //
  379. Status = E100pReadDeviceMacAddress(Device);
  380. if (!KSUCCESS(Status)) {
  381. goto ResetDeviceEnd;
  382. }
  383. //
  384. // Destroy any old packets lying around.
  385. //
  386. for (CommandIndex = 0;
  387. CommandIndex < E100_COMMAND_RING_COUNT;
  388. CommandIndex += 1) {
  389. if (Device->CommandPacket[CommandIndex] != NULL) {
  390. NetFreeBuffer(Device->CommandPacket[CommandIndex]);
  391. Device->CommandPacket[CommandIndex] = NULL;
  392. }
  393. }
  394. //
  395. // Set up the first command to set the individual address.
  396. //
  397. Command = &(Device->Command[Device->CommandNextToUse]);
  398. PreviousCommandIndex = E100_DECREMENT_RING_INDEX(Device->CommandNextToUse,
  399. E100_COMMAND_RING_COUNT);
  400. PreviousCommand = &(Device->Command[PreviousCommandIndex]);
  401. Device->CommandNextToUse = E100_INCREMENT_RING_INDEX(
  402. Device->CommandNextToUse,
  403. E100_COMMAND_RING_COUNT);
  404. RtlCopyMemory(&(Command->U.SetAddress),
  405. &(Device->EepromMacAddress[0]),
  406. ETHERNET_ADDRESS_SIZE);
  407. Command->Command = E100_COMMAND_SUSPEND |
  408. (E100CommandSetIndividualAddress <<
  409. E100_COMMAND_BLOCK_COMMAND_SHIFT);
  410. PreviousCommand->Command &= ~E100_COMMAND_SUSPEND;
  411. //
  412. // Set the command unit base and start the command unit.
  413. //
  414. E100_WRITE_REGISTER32(Device, E100RegisterPointer, 0);
  415. E100_WRITE_COMMAND_REGISTER(Device, E100_COMMAND_UNIT_LOAD_BASE);
  416. do {
  417. Value = E100_READ_COMMAND_REGISTER(Device);
  418. } while ((Value & E100_COMMAND_UNIT_COMMAND_MASK) != 0);
  419. Value = Device->CommandIoBuffer->Fragment[0].PhysicalAddress;
  420. E100_WRITE_REGISTER32(Device, E100RegisterPointer, Value);
  421. E100_WRITE_COMMAND_REGISTER(Device, E100_COMMAND_UNIT_START);
  422. do {
  423. Value = E100_READ_COMMAND_REGISTER(Device);
  424. } while ((Value & E100_COMMAND_UNIT_COMMAND_MASK) != 0);
  425. //
  426. // Set the receive unit base and start the receive unit.
  427. //
  428. E100_WRITE_REGISTER32(Device, E100RegisterPointer, 0);
  429. E100_WRITE_COMMAND_REGISTER(Device, E100_COMMAND_RECEIVE_LOAD_BASE);
  430. do {
  431. Value = E100_READ_COMMAND_REGISTER(Device);
  432. } while ((Value & E100_COMMAND_RECEIVE_COMMAND_MASK) != 0);
  433. Value = Device->ReceiveFrameIoBuffer->Fragment[0].PhysicalAddress;
  434. E100_WRITE_REGISTER32(Device, E100RegisterPointer, Value);
  435. E100_WRITE_COMMAND_REGISTER(Device, E100_COMMAND_RECEIVE_START);
  436. do {
  437. Value = E100_READ_COMMAND_REGISTER(Device);
  438. } while ((Value & E100_COMMAND_RECEIVE_COMMAND_MASK) != 0);
  439. //
  440. // Check to see how everything is doing. The status register may take a
  441. // little while to transition from idle to ready.
  442. //
  443. Timeout = KeGetRecentTimeCounter() +
  444. KeConvertMicrosecondsToTimeTicks(E100_READY_TIMEOUT);
  445. Status = STATUS_NOT_READY;
  446. do {
  447. Value = E100_READ_STATUS_REGISTER(Device);
  448. if ((Value & E100_STATUS_RECEIVE_UNIT_STATUS_MASK) ==
  449. E100_STATUS_RECEIVE_UNIT_READY) {
  450. Status = STATUS_SUCCESS;
  451. break;
  452. } else if ((Value & E100_STATUS_RECEIVE_UNIT_STATUS_MASK) !=
  453. E100_STATUS_RECEIVE_UNIT_IDLE) {
  454. break;
  455. }
  456. } while (KeGetRecentTimeCounter() <= Timeout);
  457. if (!KSUCCESS(Status)) {
  458. goto ResetDeviceEnd;
  459. }
  460. //
  461. // Notify the networking core of this new link now that the device is ready
  462. // to send and receive data, pending media being present.
  463. //
  464. if (Device->NetworkLink == NULL) {
  465. Status = E100pAddNetworkDevice(Device);
  466. if (!KSUCCESS(Status)) {
  467. goto ResetDeviceEnd;
  468. }
  469. }
  470. //
  471. // Figure out if the link is up, and report on it if so.
  472. // TODO: The link state should be checked periodically, rather than just
  473. // once at the beginning.
  474. //
  475. GeneralStatus = E100_READ_REGISTER8(Device, E100RegisterGeneralStatus);
  476. if ((GeneralStatus & E100_CONTROL_STATUS_LINK_UP) != 0) {
  477. LinkSpeed = NET_SPEED_10_MBPS;
  478. if ((GeneralStatus & E100_CONTROL_STATUS_100_MBPS) != 0) {
  479. LinkSpeed = NET_SPEED_100_MBPS;
  480. }
  481. Device->LinkActive = TRUE;
  482. NetSetLinkState(Device->NetworkLink, TRUE, LinkSpeed);
  483. } else {
  484. Device->LinkActive = FALSE;
  485. NetSetLinkState(Device->NetworkLink, FALSE, 0);
  486. }
  487. Status = STATUS_SUCCESS;
  488. ResetDeviceEnd:
  489. return Status;
  490. }
  491. INTERRUPT_STATUS
  492. E100pInterruptService (
  493. PVOID Context
  494. )
  495. /*++
  496. Routine Description:
  497. This routine implements the e100 interrupt service routine.
  498. Arguments:
  499. Context - Supplies the context pointer given to the system when the
  500. interrupt was connected. In this case, this points to the e100 device
  501. structure.
  502. Return Value:
  503. Interrupt status.
  504. --*/
  505. {
  506. PE100_DEVICE Device;
  507. INTERRUPT_STATUS InterruptStatus;
  508. USHORT PendingBits;
  509. Device = (PE100_DEVICE)Context;
  510. InterruptStatus = InterruptStatusNotClaimed;
  511. //
  512. // Read the status register, and if anything's set add it to the pending
  513. // bits.
  514. //
  515. PendingBits = E100_READ_STATUS_REGISTER(Device) &
  516. E100_STATUS_INTERRUPT_MASK;
  517. if (PendingBits != 0) {
  518. InterruptStatus = InterruptStatusClaimed;
  519. RtlAtomicOr32(&(Device->PendingStatusBits), PendingBits);
  520. //
  521. // Write to clear the bits that got grabbed. Since the semantics of this
  522. // register are "write 1 to clear", any bits that get set between the
  523. // read and this write will just stick and generate another level
  524. // triggered interrupt.
  525. //
  526. E100_WRITE_REGISTER8(Device,
  527. E100RegisterAcknowledge,
  528. PendingBits >> BITS_PER_BYTE);
  529. }
  530. return InterruptStatus;
  531. }
  532. INTERRUPT_STATUS
  533. E100pInterruptServiceWorker (
  534. PVOID Parameter
  535. )
  536. /*++
  537. Routine Description:
  538. This routine processes interrupts for the e100 controller at low level.
  539. Arguments:
  540. Parameter - Supplies an optional parameter passed in by the creator of the
  541. work item.
  542. Return Value:
  543. Interrupt status.
  544. --*/
  545. {
  546. PE100_DEVICE Device;
  547. ULONG PendingBits;
  548. ULONG ProcessFramesMask;
  549. Device = (PE100_DEVICE)(Parameter);
  550. ASSERT(KeGetRunLevel() == RunLevelLow);
  551. //
  552. // Clear out the pending bits.
  553. //
  554. PendingBits = RtlAtomicExchange32(&(Device->PendingStatusBits), 0);
  555. if (PendingBits == 0) {
  556. return InterruptStatusNotClaimed;
  557. }
  558. //
  559. // Handle the receive unit leaving the ready state and new frames
  560. // coming in.
  561. //
  562. ProcessFramesMask = E100_STATUS_RECEIVE_NOT_READY |
  563. E100_STATUS_FRAME_RECEIVED;
  564. if ((PendingBits & ProcessFramesMask) != 0) {
  565. E100pReapReceivedFrames(Device);
  566. }
  567. //
  568. // If the command unit finished what it was up to, reap that memory.
  569. //
  570. if ((PendingBits &
  571. (E100_STATUS_COMMAND_NOT_ACTIVE |
  572. E100_STATUS_COMMAND_COMPLETE)) != 0) {
  573. E100pReapCompletedCommands(Device);
  574. }
  575. return InterruptStatusClaimed;
  576. }
  577. //
  578. // --------------------------------------------------------- Internal Functions
  579. //
  580. KSTATUS
  581. E100pReadDeviceMacAddress (
  582. PE100_DEVICE Device
  583. )
  584. /*++
  585. Routine Description:
  586. This routine reads the device's MAC address out of the EEPROM.
  587. Arguments:
  588. Device - Supplies a pointer to the device. The resulting MAC address will
  589. be stored in here.
  590. Return Value:
  591. Status code.
  592. --*/
  593. {
  594. ULONG ByteIndex;
  595. USHORT Register;
  596. KSTATUS Status;
  597. USHORT Value;
  598. Register = E100_EEPROM_INDIVIDUAL_ADDRESS_OFFSET;
  599. Value = 0;
  600. for (ByteIndex = 0;
  601. ByteIndex < sizeof(Device->EepromMacAddress);
  602. ByteIndex += sizeof(USHORT)) {
  603. Status = E100pPerformEepromIo(Device, Register, &Value, FALSE);
  604. if (!KSUCCESS(Status)) {
  605. return Status;
  606. }
  607. //
  608. // The bytes come out of the EEPROM a little backwards. If the MAC
  609. // address started with 00:AA:..., the first read out of the EEPROM
  610. // would have 00 in byte 0, and AA in byte 1. Maybe that's not
  611. // backwards at all.
  612. //
  613. Device->EepromMacAddress[ByteIndex] = (BYTE)Value;
  614. Device->EepromMacAddress[ByteIndex + 1] =
  615. (BYTE)(Value >> BITS_PER_BYTE);
  616. Register += 1;
  617. }
  618. return Status;
  619. }
  620. KSTATUS
  621. E100pPerformEepromIo (
  622. PE100_DEVICE Device,
  623. USHORT RegisterOffset,
  624. PUSHORT Value,
  625. BOOL Write
  626. )
  627. /*++
  628. Routine Description:
  629. This routine performs an I/O operation with the e100's attached EEPROM.
  630. Arguments:
  631. Device - Supplies a pointer to the device.
  632. RegisterOffset - Supplies the EEPROM register to read.
  633. Value - Supplies a pointer to a value that for write operations contains the
  634. value to write. For read operations, supplies a pointer where the
  635. read value will be returned.
  636. Write - Supplies a boolean indicating whether to write to the EEPROM (TRUE)
  637. or read from the EEPROM (FALSE).
  638. Return Value:
  639. STATUS_SUCCESS on success.
  640. STATUS_NOT_READY if the number of address bits could not be determined.
  641. --*/
  642. {
  643. ULONG BitCount;
  644. ULONG BitIndex;
  645. ULONG Mask;
  646. ULONG OpcodeShift;
  647. ULONG OutValue;
  648. USHORT ReadRegister;
  649. USHORT ReadValue;
  650. ULONG Register;
  651. KSTATUS Status;
  652. //
  653. // Determine the address width of the EEPROM if needed.
  654. //
  655. if (Device->EepromAddressBits == 0) {
  656. Status = E100pDetermineEepromAddressWidth(Device);
  657. if (!KSUCCESS(Status)) {
  658. return Status;
  659. }
  660. }
  661. ASSERT(Device->EepromAddressBits != 0);
  662. //
  663. // Build the bitfield to send, which looks like: Opcode, Address, Value.
  664. // The opcode is 3 bits, address is variable (probably 6 or 8), and the
  665. // value is 16 bits.
  666. //
  667. OpcodeShift = (sizeof(USHORT) * BITS_PER_BYTE) + Device->EepromAddressBits;
  668. if (Write != FALSE) {
  669. OutValue = E100_EEPROM_OPCODE_WRITE << OpcodeShift;
  670. OutValue |= *Value;
  671. } else {
  672. OutValue = E100_EEPROM_OPCODE_READ << OpcodeShift;
  673. }
  674. OutValue |= RegisterOffset << (sizeof(USHORT) * BITS_PER_BYTE);
  675. //
  676. // Activate the EEPROM.
  677. //
  678. Register = E100_EEPROM_CHIP_SELECT;
  679. E100_WRITE_REGISTER16(Device, E100RegisterEepromControl, Register);
  680. //
  681. // Write out the value, one bit at a time.
  682. //
  683. ReadValue = 0;
  684. BitCount = OpcodeShift + E100_EEPROM_OPCODE_LENGTH;
  685. for (BitIndex = 0; BitIndex < BitCount; BitIndex += 1) {
  686. Mask = 1 << (BitCount - BitIndex - 1);
  687. if ((OutValue & Mask) != 0) {
  688. Register |= E100_EEPROM_DATA_IN;
  689. } else {
  690. Register &= ~E100_EEPROM_DATA_IN;
  691. }
  692. //
  693. // Write the data in bit out to the EEPROM.
  694. //
  695. E100_WRITE_REGISTER16(Device, E100RegisterEepromControl, Register);
  696. //
  697. // Set the clock high and wait the appropriate amount of time.
  698. //
  699. E100_WRITE_REGISTER16(Device,
  700. E100RegisterEepromControl,
  701. Register | E100_EEPROM_CLOCK);
  702. HlBusySpin(E100_EEPROM_DELAY_MICROSECONDS);
  703. //
  704. // Set the clock low and wait again.
  705. //
  706. E100_WRITE_REGISTER16(Device, E100RegisterEepromControl, Register);
  707. HlBusySpin(E100_EEPROM_DELAY_MICROSECONDS);
  708. //
  709. // Read the bit in and save it. Since this field is a short, the higher
  710. // bits (like the address and opcode) that don't make sense to read
  711. // will just drop off the big end.
  712. //
  713. ReadRegister = E100_READ_REGISTER16(Device, E100RegisterEepromControl);
  714. if ((ReadRegister & E100_EEPROM_DATA_OUT) != 0) {
  715. ReadValue |= (USHORT)Mask;
  716. }
  717. }
  718. //
  719. // Disable the EEPROM.
  720. //
  721. E100_WRITE_REGISTER16(Device, E100RegisterEepromControl, 0);
  722. if (Write == FALSE) {
  723. *Value = ReadValue;
  724. }
  725. return STATUS_SUCCESS;
  726. }
  727. KSTATUS
  728. E100pDetermineEepromAddressWidth (
  729. PE100_DEVICE Device
  730. )
  731. /*++
  732. Routine Description:
  733. This routine determines how many address bits there are on the EEPROM
  734. attached to the e100 device. This is needed to be able to successfully
  735. read from and write to the EEPROM. Common results are 6 and 8 (for 64 and
  736. 256 word EEPROMs).
  737. Arguments:
  738. Device - Supplies a pointer to the device. The address width will be
  739. stored in here.
  740. Return Value:
  741. STATUS_SUCCESS on success.
  742. STATUS_NOT_READY if the number of address bits could not be determined.
  743. --*/
  744. {
  745. ULONG BitIndex;
  746. ULONG Mask;
  747. USHORT ReadRegister;
  748. USHORT Register;
  749. KSTATUS Status;
  750. ULONG WriteValue;
  751. Status = STATUS_SUCCESS;
  752. WriteValue = E100_EEPROM_OPCODE_READ << (32 - E100_EEPROM_OPCODE_LENGTH);
  753. //
  754. // Activate the EEPROM.
  755. //
  756. Register = E100_EEPROM_CHIP_SELECT;
  757. E100_WRITE_REGISTER16(Device, E100RegisterEepromControl, Register);
  758. //
  759. // Write out the opcode and address bits, and watch for the EEPROM to start
  760. // sending the dummy zero.
  761. //
  762. for (BitIndex = 0;
  763. BitIndex < sizeof(ULONG) * BITS_PER_BYTE;
  764. BitIndex += 1) {
  765. Mask = 1 << (31 - BitIndex);
  766. if ((WriteValue & Mask) != 0) {
  767. Register |= E100_EEPROM_DATA_IN;
  768. } else {
  769. Register &= ~E100_EEPROM_DATA_IN;
  770. }
  771. //
  772. // Write the data in bit out to the EEPROM.
  773. //
  774. E100_WRITE_REGISTER16(Device, E100RegisterEepromControl, Register);
  775. //
  776. // Set the clock high and wait the appropriate amount of time.
  777. //
  778. E100_WRITE_REGISTER16(Device,
  779. E100RegisterEepromControl,
  780. Register | E100_EEPROM_CLOCK);
  781. HlBusySpin(E100_EEPROM_DELAY_MICROSECONDS);
  782. //
  783. // Set the clock low and wait again.
  784. //
  785. E100_WRITE_REGISTER16(Device, E100RegisterEepromControl, Register);
  786. HlBusySpin(E100_EEPROM_DELAY_MICROSECONDS);
  787. //
  788. // If the opcode has already gone by, then start watching for the
  789. // dummy 0 bit coming out of the EEPROM.
  790. //
  791. ReadRegister = E100_READ_REGISTER16(Device, E100RegisterEepromControl);
  792. if ((BitIndex >= E100_EEPROM_OPCODE_LENGTH) &&
  793. ((ReadRegister & E100_EEPROM_DATA_OUT) == 0)) {
  794. break;
  795. }
  796. }
  797. if (BitIndex == sizeof(ULONG) * BITS_PER_BYTE) {
  798. Status = STATUS_NOT_READY;
  799. } else if (BitIndex == E100_EEPROM_OPCODE_LENGTH) {
  800. Status = STATUS_UNSUCCESSFUL;
  801. } else {
  802. Device->EepromAddressBits = BitIndex - E100_EEPROM_OPCODE_LENGTH + 1;
  803. }
  804. //
  805. // Don't leave the EEPROM hanging, read the 16 bit word that was requested.
  806. //
  807. Register = E100_EEPROM_CHIP_SELECT;
  808. for (BitIndex = 0;
  809. BitIndex < sizeof(USHORT) * BITS_PER_BYTE;
  810. BitIndex += 1) {
  811. //
  812. // Set the clock high and wait the appropriate amount of time.
  813. //
  814. E100_WRITE_REGISTER16(Device,
  815. E100RegisterEepromControl,
  816. Register | E100_EEPROM_CLOCK);
  817. HlBusySpin(E100_EEPROM_DELAY_MICROSECONDS);
  818. //
  819. // Set the clock low and wait again.
  820. //
  821. E100_WRITE_REGISTER16(Device, E100RegisterEepromControl, Register);
  822. HlBusySpin(E100_EEPROM_DELAY_MICROSECONDS);
  823. //
  824. // Read the data out, but ignore it.
  825. //
  826. ReadRegister = E100_READ_REGISTER16(Device, E100RegisterEepromControl);
  827. }
  828. //
  829. // Disable the EEPROM.
  830. //
  831. E100_WRITE_REGISTER16(Device, E100RegisterEepromControl, 0);
  832. return Status;
  833. }
  834. VOID
  835. E100pReapCompletedCommands (
  836. PE100_DEVICE Device
  837. )
  838. /*++
  839. Routine Description:
  840. This routine cleans out any commands added to the command list that have
  841. been dealt with by the controller. This routine must be called at low
  842. level and assumes the command list lock is already held.
  843. Arguments:
  844. Device - Supplies a pointer to the device.
  845. Return Value:
  846. None.
  847. --*/
  848. {
  849. PE100_COMMAND Command;
  850. ULONG CommandIndex;
  851. BOOL CommandReaped;
  852. KeAcquireQueuedLock(Device->CommandListLock);
  853. CommandReaped = FALSE;
  854. while (TRUE) {
  855. //
  856. // Check to see if the next command can be reaped.
  857. //
  858. CommandIndex = E100_INCREMENT_RING_INDEX(Device->CommandLastReaped,
  859. E100_COMMAND_RING_COUNT);
  860. Command = &(Device->Command[CommandIndex]);
  861. //
  862. // If the command word is zeroed, that's the mark that there are no
  863. // more commands on the list.
  864. //
  865. if (Command->Command == 0) {
  866. break;
  867. }
  868. //
  869. // If the command, whatever it may be, is not complete, then this is
  870. // an active entry, so stop reaping.
  871. //
  872. if ((Command->Command & E100_COMMAND_MASK_COMMAND_COMPLETE) == 0) {
  873. break;
  874. }
  875. //
  876. // If it's a transmit command and it's complete, go free the transmit
  877. // buffer.
  878. //
  879. if ((Command->Command & E100_COMMAND_BLOCK_COMMAND_MASK) ==
  880. (E100CommandTransmit << E100_COMMAND_BLOCK_COMMAND_SHIFT)) {
  881. NetFreeBuffer(Device->CommandPacket[CommandIndex]);
  882. Device->CommandPacket[CommandIndex] = NULL;
  883. }
  884. //
  885. // Zero out the command, this one's finished.
  886. //
  887. Command->Command = 0;
  888. //
  889. // Update the last reaped index to reflex that the command at the
  890. // current index has been reaped.
  891. //
  892. Device->CommandLastReaped = CommandIndex;
  893. CommandReaped = TRUE;
  894. }
  895. //
  896. // If space was freed up, send more segments.
  897. //
  898. if (CommandReaped != FALSE) {
  899. E100pSendPendingPackets(Device);
  900. }
  901. KeReleaseQueuedLock(Device->CommandListLock);
  902. return;
  903. }
  904. VOID
  905. E100pReapReceivedFrames (
  906. PE100_DEVICE Device
  907. )
  908. /*++
  909. Routine Description:
  910. This routine processes any received frames from the network.
  911. Arguments:
  912. Device - Supplies a pointer to the device.
  913. Return Value:
  914. None.
  915. --*/
  916. {
  917. PE100_RECEIVE_FRAME Frame;
  918. PE100_RECEIVE_FRAME LastFrame;
  919. ULONG ListBegin;
  920. ULONG ListEnd;
  921. NET_PACKET_BUFFER Packet;
  922. ULONG ReceivePhysicalAddress;
  923. USHORT ReceiveStatus;
  924. ASSERT(KeGetRunLevel() == RunLevelLow);
  925. //
  926. // Loop grabbing completed frames.
  927. //
  928. Packet.Flags = 0;
  929. KeAcquireQueuedLock(Device->ReceiveListLock);
  930. ReceivePhysicalAddress =
  931. (ULONG)(Device->ReceiveFrameIoBuffer->Fragment[0].PhysicalAddress);
  932. while (TRUE) {
  933. ListBegin = Device->ReceiveListBegin;
  934. Frame = &(Device->ReceiveFrame[ListBegin]);
  935. //
  936. // If the frame is not complete, then this is the end of packets that
  937. // need to be reaped.
  938. //
  939. if ((Frame->Status & E100_RECEIVE_COMPLETE) == 0) {
  940. break;
  941. }
  942. //
  943. // If the frame came through alright, send it up to the core networking
  944. // library to process.
  945. //
  946. if ((Frame->Status & E100_RECEIVE_OK) != 0) {
  947. Packet.Buffer = (PVOID)(&(Frame->ReceiveFrame));
  948. Packet.BufferPhysicalAddress = ReceivePhysicalAddress +
  949. (ListBegin * sizeof(E100_RECEIVE_FRAME));
  950. Packet.BufferSize = Frame->Sizes &
  951. E100_RECEIVE_SIZE_ACTUAL_COUNT_MASK;
  952. Packet.DataSize = Packet.BufferSize;
  953. Packet.DataOffset = 0;
  954. Packet.FooterOffset = Packet.DataSize;
  955. NetProcessReceivedPacket(Device->NetworkLink, &Packet);
  956. }
  957. //
  958. // Set this frame up to be reused, it will be the new end of the list.
  959. //
  960. Frame->Status = E100_RECEIVE_COMMAND_SUSPEND;
  961. Frame->Sizes = RECEIVE_FRAME_DATA_SIZE <<
  962. E100_RECEIVE_SIZE_BUFFER_SIZE_SHIFT;
  963. //
  964. // Clear the end of list bit in the previous final frame. The atomic
  965. // AND also acts as a full memory barrier.
  966. //
  967. ListEnd = E100_DECREMENT_RING_INDEX(ListBegin,
  968. E100_RECEIVE_FRAME_COUNT);
  969. LastFrame = &(Device->ReceiveFrame[ListEnd]);
  970. RtlAtomicAnd32(&(LastFrame->Status), ~E100_RECEIVE_COMMAND_SUSPEND);
  971. //
  972. // Move the beginning pointer up.
  973. //
  974. Device->ReceiveListBegin = E100_INCREMENT_RING_INDEX(
  975. ListBegin,
  976. E100_RECEIVE_FRAME_COUNT);
  977. }
  978. //
  979. // Resume the receive unit if it's not active.
  980. //
  981. ReceiveStatus = E100_READ_STATUS_REGISTER(Device) &
  982. E100_STATUS_RECEIVE_UNIT_STATUS_MASK;
  983. if (ReceiveStatus != E100_STATUS_RECEIVE_UNIT_READY) {
  984. ASSERT(ReceiveStatus == E100_STATUS_RECEIVE_UNIT_SUSPENDED);
  985. E100_WRITE_COMMAND_REGISTER(Device, E100_COMMAND_RECEIVE_RESUME);
  986. }
  987. KeReleaseQueuedLock(Device->ReceiveListLock);
  988. return;
  989. }
  990. VOID
  991. E100pSendPendingPackets (
  992. PE100_DEVICE Device
  993. )
  994. /*++
  995. Routine Description:
  996. This routine sends as many packets as can fit in the hardware descriptor
  997. buffer. This routine assumes the command list lock is already held.
  998. Arguments:
  999. Device - Supplies a pointer to the device.
  1000. Return Value:
  1001. None.
  1002. --*/
  1003. {
  1004. ULONG BufferDescriptorAddress;
  1005. PE100_COMMAND Command;
  1006. ULONG CommandIndex;
  1007. PNET_PACKET_BUFFER Packet;
  1008. ULONG PreviousCommandIndex;
  1009. ULONG Status;
  1010. BOOL WakeDevice;
  1011. //
  1012. // Chew up as many open command slots as possible, but always leave the
  1013. // last reaped command open. The hardware is more than likely suspended on
  1014. // that command. This routine will take that command out of suspend and
  1015. // poke the hardware to resume. If this routine did not leave the last spot
  1016. // open, the hardware would wake up and see the command is still in the
  1017. // suspended state and go back to sleep.
  1018. //
  1019. WakeDevice = FALSE;
  1020. while ((NET_PACKET_LIST_EMPTY(&(Device->TransmitPacketList)) == FALSE) &&
  1021. (Device->CommandNextToUse != Device->CommandLastReaped)) {
  1022. Packet = LIST_VALUE(Device->TransmitPacketList.Head.Next,
  1023. NET_PACKET_BUFFER,
  1024. ListEntry);
  1025. CommandIndex = Device->CommandNextToUse;
  1026. Command = &(Device->Command[CommandIndex]);
  1027. //
  1028. // The command better be reaped and not in use.
  1029. //
  1030. ASSERT(Command->Command == 0);
  1031. NET_REMOVE_PACKET_FROM_LIST(Packet, &(Device->TransmitPacketList));
  1032. //
  1033. // Success, a free command entry. Let's fill it out!
  1034. //
  1035. Command->Command = (E100CommandTransmit <<
  1036. E100_COMMAND_BLOCK_COMMAND_SHIFT) |
  1037. E100_COMMAND_SUSPEND |
  1038. E100_COMMAND_TRANSMIT_FLEXIBLE_MODE;
  1039. //
  1040. // Calculate the physical address of the transmit buffer descriptor
  1041. // "array" (in quotes because there's only one element in it).
  1042. //
  1043. BufferDescriptorAddress =
  1044. Device->CommandIoBuffer->Fragment[0].PhysicalAddress +
  1045. (CommandIndex * sizeof(E100_COMMAND)) +
  1046. FIELD_OFFSET(E100_COMMAND, U.Transmit.BufferAddress);
  1047. Command->U.Transmit.DescriptorAddress = BufferDescriptorAddress;
  1048. Command->U.Transmit.DescriptorProperties =
  1049. (1 << E100_TRANSMIT_BUFFER_DESCRIPTOR_COUNT_SHIFT) |
  1050. E100_TRANSMIT_THRESHOLD;
  1051. //
  1052. // Fill out the transfer buffer descriptor array with the one
  1053. // data entry it points to.
  1054. //
  1055. Command->U.Transmit.BufferAddress = Packet->BufferPhysicalAddress +
  1056. Packet->DataOffset;
  1057. Command->U.Transmit.BufferProperties =
  1058. (Packet->FooterOffset - Packet->DataOffset) |
  1059. E100_TRANSMIT_BUFFER_END_OF_LIST;
  1060. //
  1061. // Also save the virtual address of this packet. This is not used
  1062. // by hardware, but helps the reaping function know how to free the
  1063. // buffer once it's fully processed by the hardware.
  1064. //
  1065. Command->U.Transmit.BufferVirtual = Packet->Buffer +
  1066. Packet->DataOffset;
  1067. Device->CommandPacket[CommandIndex] = Packet;
  1068. //
  1069. // Now that this command is set up, clear the suspend bit on the
  1070. // previous command so the hardware access this new packet. This
  1071. // atomic access also acts as a memory barrier, ensuring this packet
  1072. // is all set up in memory.
  1073. //
  1074. PreviousCommandIndex = E100_DECREMENT_RING_INDEX(
  1075. CommandIndex,
  1076. E100_COMMAND_RING_COUNT);
  1077. RtlAtomicAnd32(&(Device->Command[PreviousCommandIndex].Command),
  1078. ~E100_COMMAND_SUSPEND);
  1079. //
  1080. // Move the pointer past this entry.
  1081. //
  1082. Device->CommandNextToUse = E100_INCREMENT_RING_INDEX(
  1083. CommandIndex,
  1084. E100_COMMAND_RING_COUNT);
  1085. WakeDevice = TRUE;
  1086. }
  1087. //
  1088. // If the device is suspended at this point (after adding all these great
  1089. // commands), wake it up.
  1090. //
  1091. if (WakeDevice != FALSE) {
  1092. Status = E100_READ_STATUS_REGISTER(Device);
  1093. Status &= E100_STATUS_COMMAND_UNIT_STATUS_MASK;
  1094. if (Status == E100_STATUS_COMMAND_UNIT_SUSPENDED) {
  1095. E100_WRITE_COMMAND_REGISTER(Device, E100_COMMAND_UNIT_RESUME);
  1096. }
  1097. }
  1098. return;
  1099. }