1
0

sm91c1hw.c 42 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773
  1. /*++
  2. Copyright (c) 2014 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. sm91c1hw.c
  5. Abstract:
  6. This module implements device support for the SMSC91C111 LAN Ethernet
  7. Controller.
  8. Author:
  9. Chris Stevens 16-Apr-2014
  10. Environment:
  11. Kernel
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. #include <minoca/kernel/driver.h>
  17. #include <minoca/net/netdrv.h>
  18. #include "sm91c1.h"
  19. //
  20. // --------------------------------------------------------------------- Macros
  21. //
  22. #define SM91C1_WRITE_ZERO_TO_MI(_Device) \
  23. Sm91c1pWriteRegister(_Device, Sm91c1RegisterManagementInterface, 0x8); \
  24. Sm91c1pWriteRegister(_Device, Sm91c1RegisterManagementInterface, 0xC); \
  25. Sm91c1pWriteRegister(_Device, Sm91c1RegisterManagementInterface, 0x8);
  26. #define SM91C1_WRITE_ONE_TO_MI(_Device) \
  27. Sm91c1pWriteRegister(_Device, Sm91c1RegisterManagementInterface, 0x9); \
  28. Sm91c1pWriteRegister(_Device, Sm91c1RegisterManagementInterface, 0xD); \
  29. Sm91c1pWriteRegister(_Device, Sm91c1RegisterManagementInterface, 0x9);
  30. #define SM91C1_WRITE_Z_TO_MI(_Device) \
  31. Sm91c1pWriteRegister(_Device, Sm91c1RegisterManagementInterface, 0x0); \
  32. Sm91c1pWriteRegister(_Device, Sm91c1RegisterManagementInterface, 0x4); \
  33. Sm91c1pWriteRegister(_Device, Sm91c1RegisterManagementInterface, 0x0);
  34. //
  35. // ---------------------------------------------------------------- Definitions
  36. //
  37. //
  38. // Define the maximum number of pending transfers allowed.
  39. //
  40. #define SM91C1_MAX_TRANSMIT_PACKET_LIST_COUNT 64
  41. //
  42. // ------------------------------------------------------ Data Type Definitions
  43. //
  44. //
  45. // ----------------------------------------------- Internal Function Prototypes
  46. //
  47. VOID
  48. Sm91c1pSendPacket (
  49. PSM91C1_DEVICE Device,
  50. PNET_PACKET_BUFFER Packet
  51. );
  52. VOID
  53. Sm91c1pReceivePacket (
  54. PSM91C1_DEVICE Device
  55. );
  56. VOID
  57. Sm91c1pInitializePhy (
  58. PSM91C1_DEVICE Device
  59. );
  60. KSTATUS
  61. Sm91c1pReadMacAddress (
  62. PSM91C1_DEVICE Device
  63. );
  64. USHORT
  65. Sm91c1pReadRegister (
  66. PSM91C1_DEVICE Device,
  67. SM91C1_REGISTER Register
  68. );
  69. VOID
  70. Sm91c1pWriteRegister (
  71. PSM91C1_DEVICE Device,
  72. SM91C1_REGISTER Register,
  73. USHORT Value
  74. );
  75. USHORT
  76. Sm91c1pReadMdio (
  77. PSM91C1_DEVICE Device,
  78. SM91C1_MII_REGISTER Register
  79. );
  80. VOID
  81. Sm91c1pWriteMdio (
  82. PSM91C1_DEVICE Device,
  83. SM91C1_MII_REGISTER Register,
  84. USHORT Value
  85. );
  86. VOID
  87. Sm91c1SynchronizeMdio (
  88. PSM91C1_DEVICE Device
  89. );
  90. //
  91. // -------------------------------------------------------------------- Globals
  92. //
  93. BOOL Sm91c1DisablePacketDropping = FALSE;
  94. // ------------------------------------------------------------------ Functions
  95. //
  96. KSTATUS
  97. Sm91c1Send (
  98. PVOID DeviceContext,
  99. PNET_PACKET_LIST PacketList
  100. )
  101. /*++
  102. Routine Description:
  103. This routine sends data through the network.
  104. Arguments:
  105. DeviceContext - Supplies a pointer to the device context associated with
  106. the link down which this data is to be sent.
  107. PacketList - Supplies a pointer to a list of network packets to send. Data
  108. in these packets may be modified by this routine, but must not be used
  109. once this routine returns.
  110. Return Value:
  111. STATUS_SUCCESS if all packets were sent.
  112. STATUS_RESOURCE_IN_USE if some or all of the packets were dropped due to
  113. the hardware being backed up with too many packets to send.
  114. Other failure codes indicate that none of the packets were sent.
  115. --*/
  116. {
  117. BOOL AllocatePacket;
  118. PSM91C1_DEVICE Device;
  119. USHORT InterruptMask;
  120. USHORT MmuCommand;
  121. UINTN PacketListCount;
  122. KSTATUS Status;
  123. ASSERT(KeGetRunLevel() == RunLevelLow);
  124. AllocatePacket = FALSE;
  125. Device = (PSM91C1_DEVICE)DeviceContext;
  126. //
  127. // If there is any room in the packet list (or dropping packets is
  128. // disabled), add all of the packets to the list waiting to be sent.
  129. //
  130. KeAcquireQueuedLock(Device->Lock);
  131. PacketListCount = Device->TransmitPacketList.Count;
  132. if ((PacketListCount < SM91C1_MAX_TRANSMIT_PACKET_LIST_COUNT) ||
  133. (Sm91c1DisablePacketDropping != FALSE)) {
  134. NET_APPEND_PACKET_LIST(PacketList, &(Device->TransmitPacketList));
  135. AllocatePacket = TRUE;
  136. Status = STATUS_SUCCESS;
  137. //
  138. // Otherwise report that the resource is use as it is too busy to handle
  139. // more packets.
  140. //
  141. } else {
  142. Status = STATUS_RESOURCE_IN_USE;
  143. }
  144. //
  145. // If necessary and an allocation isn't already in flight, allocate a
  146. // packet. The actual sending of a packet is handled when the allocate
  147. // interrupt is fired.
  148. //
  149. if ((AllocatePacket != FALSE) && (Device->AllocateInProgress == FALSE)) {
  150. Device->AllocateInProgress = TRUE;
  151. MmuCommand = (SM91C1_MMU_OPERATION_ALLOCATE_FOR_TRANSMIT <<
  152. SM91C1_MMU_COMMAND_OPERATION_SHIFT) &
  153. SM91C1_MMU_COMMAND_OPERATION_MASK;
  154. Sm91c1pWriteRegister(Device, Sm91c1RegisterMmuCommand, MmuCommand);
  155. //
  156. // Re-enable the allocation interrupt. Do this after the allocate
  157. // command is set because the previous allocate interrupt is not
  158. // cleared until a new allocate command is sent.
  159. //
  160. InterruptMask = Sm91c1pReadRegister(Device,
  161. Sm91c1RegisterInterruptMask);
  162. InterruptMask |= SM91C1_INTERRUPT_ALLOCATE;
  163. Sm91c1pWriteRegister(Device,
  164. Sm91c1RegisterInterruptMask,
  165. InterruptMask);
  166. }
  167. KeReleaseQueuedLock(Device->Lock);
  168. return Status;
  169. }
  170. KSTATUS
  171. Sm91c1GetSetInformation (
  172. PVOID DeviceContext,
  173. NET_LINK_INFORMATION_TYPE InformationType,
  174. PVOID Data,
  175. PUINTN DataSize,
  176. BOOL Set
  177. )
  178. /*++
  179. Routine Description:
  180. This routine gets or sets the network device layer's link information.
  181. Arguments:
  182. DeviceContext - Supplies a pointer to the device context associated with
  183. the link for which information is being set or queried.
  184. InformationType - Supplies the type of information being queried or set.
  185. Data - Supplies a pointer to the data buffer where the data is either
  186. returned for a get operation or given for a set operation.
  187. DataSize - Supplies a pointer that on input contains the size of the data
  188. buffer. On output, contains the required size of the data buffer.
  189. Set - Supplies a boolean indicating if this is a get operation (FALSE) or a
  190. set operation (TRUE).
  191. Return Value:
  192. Status code.
  193. --*/
  194. {
  195. PULONG Flags;
  196. KSTATUS Status;
  197. switch (InformationType) {
  198. case NetLinkInformationChecksumOffload:
  199. if (*DataSize != sizeof(ULONG)) {
  200. return STATUS_INVALID_PARAMETER;
  201. }
  202. if (Set != FALSE) {
  203. return STATUS_NOT_SUPPORTED;
  204. }
  205. Flags = (PULONG)Data;
  206. *Flags = 0;
  207. break;
  208. default:
  209. Status = STATUS_NOT_SUPPORTED;
  210. break;
  211. }
  212. return Status;
  213. }
  214. KSTATUS
  215. Sm91c1pInitializeDeviceStructures (
  216. PSM91C1_DEVICE Device
  217. )
  218. /*++
  219. Routine Description:
  220. This routine performs housekeeping preparation for resetting and enabling
  221. an SM91C1 device.
  222. Arguments:
  223. Device - Supplies a pointer to the device.
  224. Return Value:
  225. Status code.
  226. --*/
  227. {
  228. ULONG IoBufferFlags;
  229. KSTATUS Status;
  230. KeInitializeSpinLock(&(Device->InterruptLock));
  231. KeInitializeSpinLock(&(Device->BankLock));
  232. NET_INITIALIZE_PACKET_LIST(&(Device->TransmitPacketList));
  233. Device->SelectedBank = -1;
  234. ASSERT(Device->Lock == NULL);
  235. Device->Lock = KeCreateQueuedLock();
  236. if (Device->Lock == NULL) {
  237. Status = STATUS_INSUFFICIENT_RESOURCES;
  238. goto InitializeDeviceStructuresEnd;
  239. }
  240. IoBufferFlags = IO_BUFFER_FLAG_PHYSICALLY_CONTIGUOUS;
  241. Device->ReceiveIoBuffer = MmAllocateNonPagedIoBuffer(0,
  242. MAX_ULONGLONG,
  243. 0,
  244. SM91C1_MAX_PACKET_SIZE,
  245. IoBufferFlags);
  246. if (Device->ReceiveIoBuffer == NULL) {
  247. Status = STATUS_INSUFFICIENT_RESOURCES;
  248. goto InitializeDeviceStructuresEnd;
  249. }
  250. Status = STATUS_SUCCESS;
  251. InitializeDeviceStructuresEnd:
  252. return Status;
  253. }
  254. VOID
  255. Sm91c1pDestroyDeviceStructures (
  256. PSM91C1_DEVICE Device
  257. )
  258. /*++
  259. Routine Description:
  260. This routine performs destroy any device structures allocated for the
  261. SM91C1 device.
  262. Arguments:
  263. Device - Supplies a pointer to the device.
  264. Return Value:
  265. None.
  266. --*/
  267. {
  268. if (Device->ReceiveIoBuffer == NULL) {
  269. MmFreeIoBuffer(Device->ReceiveIoBuffer);
  270. }
  271. return;
  272. }
  273. KSTATUS
  274. Sm91c1pInitialize (
  275. PSM91C1_DEVICE Device
  276. )
  277. /*++
  278. Routine Description:
  279. This routine initializes and enables the SMSC91C1 device.
  280. Arguments:
  281. Device - Supplies a pointer to the device.
  282. Return Value:
  283. Status code.
  284. --*/
  285. {
  286. BOOL LinkUp;
  287. USHORT MmuCommand;
  288. KSTATUS Status;
  289. USHORT Value;
  290. //
  291. // Reset the device.
  292. //
  293. Sm91c1pWriteRegister(Device,
  294. Sm91c1RegisterReceiveControl,
  295. SM91C1_RECEIVE_CONTROL_SOFT_RESET);
  296. Sm91c1pWriteRegister(Device, Sm91c1RegisterReceiveControl, 0);
  297. //
  298. // Delay here to let the reset settle down.
  299. //
  300. KeDelayExecution(FALSE, FALSE, 50 * MICROSECONDS_PER_MILLISECOND);
  301. //
  302. // Disable all interrupts.
  303. //
  304. Sm91c1pWriteRegister(Device, Sm91c1RegisterInterruptMask, 0);
  305. //
  306. // Enable the power by setting the EPH Power Enable bit in the
  307. // configuration register.
  308. //
  309. Value = Sm91c1pReadRegister(Device, Sm91c1RegisterConfiguration);
  310. Value |= SM91C1_CONFIGURATION_REGISTER_EPH_POWER_ENABLE;
  311. Sm91c1pWriteRegister(Device, Sm91c1RegisterConfiguration, Value);
  312. //
  313. // Clear the power down bit in the PHY MII control register.
  314. //
  315. Value = Sm91c1pReadMdio(Device, Sm91c1MiiRegisterBasicControl);
  316. Value &= ~SM91C1_MII_BASIC_CONTROL_POWER_DOWN;
  317. Sm91c1pWriteMdio(Device, Sm91c1MiiRegisterBasicControl, Value);
  318. //
  319. // Reset the MMU.
  320. //
  321. MmuCommand = (SM91C1_MMU_OPERATION_RESET <<
  322. SM91C1_MMU_COMMAND_OPERATION_SHIFT) &
  323. SM91C1_MMU_COMMAND_OPERATION_MASK;
  324. Sm91c1pWriteRegister(Device, Sm91c1RegisterMmuCommand, MmuCommand);
  325. //
  326. // Initialize the PHY, starting auto-negotiation.
  327. //
  328. Sm91c1pInitializePhy(Device);
  329. //
  330. // Set the transmit packets to auto-release.
  331. //
  332. Value = Sm91c1pReadRegister(Device, Sm91c1RegisterControl);
  333. Value |= SM91C1_CONTROL_AUTO_RELEASE;
  334. Sm91c1pWriteRegister(Device, Sm91c1RegisterControl, Value);
  335. //
  336. // Enable transmitter by setting the TXENA bit in the Transmit Control
  337. // Register.
  338. //
  339. Sm91c1pWriteRegister(Device,
  340. Sm91c1RegisterTransmitControl,
  341. SM91C1_TRANSMIT_CONTROL_ENABLE);
  342. //
  343. // Enable the receiver by setting the RXENA bit in the Receive Control
  344. // Register.
  345. //
  346. Sm91c1pWriteRegister(Device,
  347. Sm91c1RegisterReceiveControl,
  348. SM91C1_RECEIVE_CONTROL_ENABLE);
  349. //
  350. // Get the MAC address out of the EEPROM.
  351. //
  352. Status = Sm91c1pReadMacAddress(Device);
  353. if (!KSUCCESS(Status)) {
  354. goto InitializeEnd;
  355. }
  356. //
  357. // Notify the networking core of this new link now that the device is ready
  358. // to send and receive data, pending media being present.
  359. //
  360. Status = Sm91c1pAddNetworkDevice(Device);
  361. if (!KSUCCESS(Status)) {
  362. goto InitializeEnd;
  363. }
  364. //
  365. // If the network link is up, notify networking core.
  366. //
  367. LinkUp = FALSE;
  368. Value = Sm91c1pReadRegister(Device, Sm91c1RegisterEphStatus);
  369. if ((Value & SM91C1_EPH_STATUS_LINK_OK) != 0) {
  370. LinkUp = TRUE;
  371. } else {
  372. Value = Sm91c1pReadMdio(Device, Sm91c1MiiRegisterBasicStatus);
  373. if (((Value & SM91C1_MII_BASIC_STATUS_LINK_STATUS) != 0) &&
  374. ((Value & SM91C1_MII_BASIC_STATUS_AUTONEGOTIATE_COMPLETE) != 0)) {
  375. LinkUp = TRUE;
  376. }
  377. }
  378. if (LinkUp != FALSE) {
  379. //
  380. // TODO: Get the real device speed when generic MII support is added.
  381. //
  382. NetSetLinkState(Device->NetworkLink, TRUE, NET_SPEED_100_MBPS);
  383. }
  384. //
  385. // Clear all the interrupts and then enable the desired ones.
  386. //
  387. Sm91c1pWriteRegister(Device, Sm91c1RegisterInterrupt, 0xFF);
  388. Sm91c1pWriteRegister(Device,
  389. Sm91c1RegisterInterruptMask,
  390. SM91C1_DEFAULT_INTERRUPTS);
  391. Status = STATUS_SUCCESS;
  392. InitializeEnd:
  393. return Status;
  394. }
  395. INTERRUPT_STATUS
  396. Sm91c1pInterruptService (
  397. PVOID Context
  398. )
  399. /*++
  400. Routine Description:
  401. This routine implements the SM91C1 interrupt service routine.
  402. Arguments:
  403. Context - Supplies the context pointer given to the system when the
  404. interrupt was connected. In this case, this points to the SM91c1 device
  405. structure.
  406. Return Value:
  407. Interrupt status.
  408. --*/
  409. {
  410. PSM91C1_DEVICE Device;
  411. USHORT Interrupts;
  412. USHORT InterruptsMask;
  413. INTERRUPT_STATUS InterruptStatus;
  414. USHORT PacketNumber;
  415. USHORT PhyInterrupts;
  416. Device = (PSM91C1_DEVICE)Context;
  417. InterruptStatus = InterruptStatusNotClaimed;
  418. PhyInterrupts = 0;
  419. //
  420. // Read the interrupt register.
  421. //
  422. Interrupts = Sm91c1pReadRegister(Device, Sm91c1RegisterInterrupt);
  423. InterruptsMask = Sm91c1pReadRegister(Device, Sm91c1RegisterInterruptMask);
  424. Interrupts &= InterruptsMask;
  425. if (Interrupts != 0) {
  426. KeAcquireSpinLock(&(Device->InterruptLock));
  427. //
  428. // If the MD interrupt bit is set, then gather the interrupt state from
  429. // the PHY MII. This read clears the interrupts as well.
  430. //
  431. if ((Interrupts & SM91C1_INTERRUPT_MD) != 0) {
  432. PhyInterrupts = Sm91c1pReadMdio(Device, Sm91c1MiiRegisterInterrupt);
  433. }
  434. //
  435. // The allocate interrupt remains high until the next interrupt
  436. // attempt. Unmask it now.
  437. //
  438. if ((Interrupts & SM91C1_INTERRUPT_ALLOCATE) != 0) {
  439. ASSERT(Device->AllocateInProgress != FALSE);
  440. InterruptsMask &= ~SM91C1_INTERRUPT_ALLOCATE;
  441. Sm91c1pWriteRegister(Device,
  442. Sm91c1RegisterInterruptMask,
  443. InterruptsMask);
  444. }
  445. //
  446. // The receive interrupt remains high until the receive FIFO is empty,
  447. // but only one receive interrupt can really be handled at a time.
  448. // Unmask it until it's handled.
  449. //
  450. if ((Interrupts & SM91C1_INTERRUPT_RECEIVE) != 0) {
  451. InterruptsMask &= ~SM91C1_INTERRUPT_RECEIVE;
  452. Sm91c1pWriteRegister(Device,
  453. Sm91c1RegisterInterruptMask,
  454. InterruptsMask);
  455. }
  456. //
  457. // The device is set to auto-release transmit packets. If a packet
  458. // interrupt is fired, that means there was a transmit failure. Save
  459. // the packet.
  460. //
  461. if ((Interrupts & SM91C1_INTERRUPT_TRANSMIT) != 0) {
  462. PacketNumber = Sm91c1pReadRegister(Device,
  463. Sm91c1RegisterTransmitFifo);
  464. ASSERT((PacketNumber & SM91C1_FIFO_PORTS_TRANSMIT_EMPTY) == 0);
  465. PacketNumber &= SM91C1_FIFO_PORTS_TRANSMIT_PACKET_NUMBER_MASK;
  466. }
  467. InterruptStatus = InterruptStatusClaimed;
  468. RtlAtomicOr32(&(Device->PendingInterrupts), Interrupts);
  469. RtlAtomicOr32(&(Device->PendingPhyInterrupts), PhyInterrupts);
  470. if ((Interrupts & SM91C1_INTERRUPT_TRANSMIT) != 0) {
  471. Device->PendingTransmitPacket = PacketNumber;
  472. }
  473. Device->PendingInterrupts |= Interrupts;
  474. Device->PendingPhyInterrupts |= PhyInterrupts;
  475. //
  476. // Clear the pending interrupt bits that can be acknowledged through
  477. // standard means.
  478. //
  479. Interrupts &= SM91C1_ACKNOWLEDGE_INTERRUPT_MASK;
  480. if (Interrupts != 0) {
  481. Sm91c1pWriteRegister(Device, Sm91c1RegisterInterrupt, Interrupts);
  482. }
  483. KeReleaseSpinLock(&(Device->InterruptLock));
  484. }
  485. return InterruptStatus;
  486. }
  487. INTERRUPT_STATUS
  488. Sm91c1pInterruptServiceWorker (
  489. PVOID Context
  490. )
  491. /*++
  492. Routine Description:
  493. This routine implements the SM91C1 low level interrupt service routine.
  494. Arguments:
  495. Context - Supplies the context pointer given to the system when the
  496. interrupt was connected. In this case, this points to the SM91c1 device
  497. structure.
  498. Return Value:
  499. Interrupt status.
  500. --*/
  501. {
  502. PSM91C1_DEVICE Device;
  503. PLIST_ENTRY FirstEntry;
  504. ULONG Interrupts;
  505. USHORT InterruptsMask;
  506. USHORT MmuCommand;
  507. RUNLEVEL OldRunLevel;
  508. PNET_PACKET_BUFFER Packet;
  509. USHORT PendingPacket;
  510. ULONG PhyInterrupts;
  511. USHORT PointerValue;
  512. USHORT StatusWord;
  513. USHORT Value;
  514. Device = (PSM91C1_DEVICE)Context;
  515. ASSERT(KeGetRunLevel() == RunLevelLow);
  516. //
  517. // Clear out the pending bits.
  518. //
  519. Interrupts = RtlAtomicExchange32(&(Device->PendingInterrupts), 0);
  520. PhyInterrupts = RtlAtomicExchange32(&(Device->PendingPhyInterrupts), 0);
  521. PendingPacket = Device->PendingTransmitPacket;
  522. if ((Interrupts == 0) && (PhyInterrupts == 0)) {
  523. return InterruptStatusNotClaimed;
  524. }
  525. ASSERT((PhyInterrupts == 0) ||
  526. ((Interrupts & SM91C1_INTERRUPT_MD) != 0));
  527. //
  528. // Handle link status changes.
  529. //
  530. if ((Interrupts & SM91C1_INTERRUPT_MD) != 0) {
  531. OldRunLevel = IoRaiseToInterruptRunLevel(Device->InterruptHandle);
  532. KeAcquireSpinLock(&(Device->InterruptLock));
  533. Value = Sm91c1pReadMdio(Device, Sm91c1MiiRegisterBasicStatus);
  534. KeReleaseSpinLock(&(Device->InterruptLock));
  535. KeLowerRunLevel(OldRunLevel);
  536. if ((Value & SM91C1_MII_BASIC_STATUS_LINK_STATUS) != 0) {
  537. if ((Value & SM91C1_MII_BASIC_STATUS_AUTONEGOTIATE_COMPLETE) != 0) {
  538. //
  539. // TODO: Get the real device speed when generic MII support is
  540. // added.
  541. //
  542. NetSetLinkState(Device->NetworkLink, TRUE, NET_SPEED_100_MBPS);
  543. }
  544. } else {
  545. NetSetLinkState(Device->NetworkLink, FALSE, 0);
  546. }
  547. }
  548. //
  549. // If the transmit interrupt was returned, check the transmit status.
  550. //
  551. if ((Interrupts & SM91C1_INTERRUPT_TRANSMIT) != 0 ) {
  552. KeAcquireQueuedLock(Device->Lock);
  553. Sm91c1pWriteRegister(Device, Sm91c1RegisterPacketNumber, PendingPacket);
  554. PointerValue = SM91C1_POINTER_READ |
  555. SM91C1_POINTER_AUTO_INCREMENT |
  556. SM91C1_POINTER_TRANSMIT;
  557. Sm91c1pWriteRegister(Device, Sm91c1RegisterPointer, PointerValue);
  558. StatusWord = Sm91c1pReadRegister(Device, Sm91c1RegisterData);
  559. //
  560. // Release the packet now that its status has been retrieved.
  561. //
  562. MmuCommand = (SM91C1_MMU_OPERATION_RELEASE_PACKET <<
  563. SM91C1_MMU_COMMAND_OPERATION_SHIFT) &
  564. SM91C1_MMU_COMMAND_OPERATION_MASK;
  565. Sm91c1pWriteRegister(Device, Sm91c1RegisterMmuCommand, MmuCommand);
  566. KeReleaseQueuedLock(Device->Lock);
  567. RtlDebugPrint("SM91C1: TX failed with status 0x%04x.\n", StatusWord);
  568. //
  569. // Re-enable transmission. It was disabled when the packet failed.
  570. //
  571. Sm91c1pWriteRegister(Device,
  572. Sm91c1RegisterTransmitControl,
  573. SM91C1_TRANSMIT_CONTROL_ENABLE);
  574. }
  575. //
  576. // If the receive interrupt was returned, process the data.
  577. //
  578. if ((Interrupts & SM91C1_INTERRUPT_RECEIVE) != 0) {
  579. Sm91c1pReceivePacket(Device);
  580. //
  581. // Re-enable the receive interrupt. It was disabled by the ISR.
  582. //
  583. InterruptsMask = Sm91c1pReadRegister(Device,
  584. Sm91c1RegisterInterruptMask);
  585. ASSERT((InterruptsMask & SM91C1_INTERRUPT_RECEIVE) == 0);
  586. InterruptsMask |= SM91C1_INTERRUPT_RECEIVE;
  587. Sm91c1pWriteRegister(Device,
  588. Sm91c1RegisterInterruptMask,
  589. InterruptsMask);
  590. }
  591. //
  592. // If a packet was allocated and there are packets to transmit, try to
  593. // send some data.
  594. //
  595. if ((Interrupts & SM91C1_INTERRUPT_ALLOCATE) != 0) {
  596. Packet = NULL;
  597. KeAcquireQueuedLock(Device->Lock);
  598. //
  599. // Send the first packet on the transmission list using the packet
  600. // that was allocated.
  601. //
  602. if (NET_PACKET_LIST_EMPTY(&(Device->TransmitPacketList)) == FALSE) {
  603. FirstEntry = Device->TransmitPacketList.Head.Next;
  604. Packet = LIST_VALUE(FirstEntry, NET_PACKET_BUFFER, ListEntry);
  605. NET_REMOVE_PACKET_FROM_LIST(Packet, &(Device->TransmitPacketList));
  606. Sm91c1pSendPacket(Device, Packet);
  607. }
  608. //
  609. // If the list is still not empty then allocate another packet.
  610. //
  611. if (NET_PACKET_LIST_EMPTY(&(Device->TransmitPacketList)) == FALSE) {
  612. ASSERT(Device->AllocateInProgress != FALSE);
  613. MmuCommand = (SM91C1_MMU_OPERATION_ALLOCATE_FOR_TRANSMIT <<
  614. SM91C1_MMU_COMMAND_OPERATION_SHIFT) &
  615. SM91C1_MMU_COMMAND_OPERATION_MASK;
  616. Sm91c1pWriteRegister(Device, Sm91c1RegisterMmuCommand, MmuCommand);
  617. //
  618. // Re-enable the allocation interrupt. Do this after the allocate
  619. // command is set because the previous allocate interrupt is not
  620. // cleared until a new allocate command is sent.
  621. //
  622. InterruptsMask = Sm91c1pReadRegister(Device,
  623. Sm91c1RegisterInterruptMask);
  624. ASSERT((InterruptsMask & SM91C1_INTERRUPT_ALLOCATE) == 0);
  625. InterruptsMask |= SM91C1_INTERRUPT_ALLOCATE;
  626. Sm91c1pWriteRegister(Device,
  627. Sm91c1RegisterInterruptMask,
  628. InterruptsMask);
  629. //
  630. // Otherwise note that no allocations are in progress, meaning that the
  631. // next send call should trigger an allocation.
  632. //
  633. } else {
  634. Device->AllocateInProgress = FALSE;
  635. }
  636. KeReleaseQueuedLock(Device->Lock);
  637. //
  638. // If a packet was transmitted, release it now.
  639. //
  640. if (Packet != NULL) {
  641. NetFreeBuffer(Packet);
  642. }
  643. }
  644. return InterruptStatusClaimed;
  645. }
  646. //
  647. // --------------------------------------------------------- Internal Functions
  648. //
  649. VOID
  650. Sm91c1pSendPacket (
  651. PSM91C1_DEVICE Device,
  652. PNET_PACKET_BUFFER Packet
  653. )
  654. /*++
  655. Routine Description:
  656. This routine sends the given packet using the packet sitting in the
  657. allocation result register. This routine assumes that the device spin lock
  658. is held.
  659. Arguments:
  660. Device - Supplies a pointer to the SM91C1 device that owns the packet.
  661. Packet - Supplies a pointer to the network packet to send.
  662. Return Value:
  663. None.
  664. --*/
  665. {
  666. BYTE AllocationResult;
  667. USHORT ByteCount;
  668. PUSHORT Data;
  669. ULONG DataSize;
  670. PBYTE Footer;
  671. PUSHORT Header;
  672. USHORT MmuCommand;
  673. BYTE PacketNumber;
  674. USHORT PointerValue;
  675. ASSERT(KeIsQueuedLockHeld(Device->Lock) != FALSE);
  676. //
  677. // There should be space in the packet for the header.
  678. //
  679. ASSERT(Packet->DataOffset == SM91C1_PACKET_HEADER_SIZE);
  680. //
  681. // Get the current data size.
  682. //
  683. DataSize = Packet->FooterOffset - Packet->DataOffset;
  684. ASSERT(DataSize == (USHORT)DataSize);
  685. Packet->DataOffset -= SM91C1_PACKET_HEADER_SIZE;
  686. Header = Packet->Buffer;
  687. //
  688. // Initialize the SM91c111 packet header. The first two bytes are the
  689. // status word. This gets set to 0. The second word is the byte count,
  690. // which includes the data size, the status word, the byte count word,
  691. // and the control word. The byte count is always even because any odd
  692. // byte in the data is included in the lower byte of the control word.
  693. //
  694. *Header = 0x0;
  695. ByteCount = DataSize +
  696. SM91C1_PACKET_HEADER_SIZE +
  697. SM91C1_PACKET_FOOTER_SIZE;
  698. *(Header + 1) = ALIGN_RANGE_DOWN(ByteCount, sizeof(USHORT));
  699. Footer = Packet->Buffer + Packet->FooterOffset;
  700. //
  701. // If the original byte count was odd, then the footer points at the
  702. // high byte of the control word. Set the ODD bit there. The low byte
  703. // of the control word correctly contains the last byte of data.
  704. //
  705. if ((ByteCount & 0x1) != 0) {
  706. *Footer = SM91C1_CONTROL_BYTE_ODD;
  707. Packet->FooterOffset += 1;
  708. //
  709. // Otherwise, the footer points at the low byte of the control word.
  710. // Zero the entire control word.
  711. //
  712. } else {
  713. *Footer = 0;
  714. *(Footer + 1) = 0;
  715. Packet->FooterOffset += 2;
  716. }
  717. //
  718. // Read the allocated packet from the allocation result register.
  719. //
  720. AllocationResult = Sm91c1pReadRegister(Device,
  721. Sm91c1RegisterAllocationResult);
  722. ASSERT((AllocationResult & SM91C1_ALLOCATION_RESULT_FAILED) == 0);
  723. PacketNumber = AllocationResult &
  724. SM91C1_ALLOCATION_RESULT_PACKET_NUMBER_MASK;
  725. //
  726. // Write the packet number to the packet number register.
  727. //
  728. Sm91c1pWriteRegister(Device, Sm91c1RegisterPacketNumber, PacketNumber);
  729. //
  730. // Initialize the pointer register for transmit, write, and auto-increment.
  731. //
  732. PointerValue = SM91C1_POINTER_WRITE |
  733. SM91C1_POINTER_AUTO_INCREMENT |
  734. SM91C1_POINTER_TRANSMIT;
  735. Sm91c1pWriteRegister(Device, Sm91c1RegisterPointer, PointerValue);
  736. //
  737. // Now write the packet data into the data register.
  738. //
  739. Data = Packet->Buffer;
  740. DataSize = Packet->FooterOffset - Packet->DataOffset;
  741. ASSERT(IS_ALIGNED(DataSize, sizeof(USHORT)) != FALSE);
  742. ASSERT(DataSize <= Packet->BufferSize);
  743. while (DataSize != 0) {
  744. Sm91c1pWriteRegister(Device, Sm91c1RegisterData, *Data);
  745. Data += 1;
  746. DataSize -= sizeof(USHORT);
  747. }
  748. //
  749. // Queue the packet. It will get automatically release once it is sent.
  750. //
  751. MmuCommand = (SM91C1_MMU_OPERATION_QUEUE_PACKET_FOR_TRANSMIT <<
  752. SM91C1_MMU_COMMAND_OPERATION_SHIFT) &
  753. SM91C1_MMU_COMMAND_OPERATION_MASK;
  754. Sm91c1pWriteRegister(Device, Sm91c1RegisterMmuCommand, MmuCommand);
  755. return;
  756. }
  757. VOID
  758. Sm91c1pReceivePacket (
  759. PSM91C1_DEVICE Device
  760. )
  761. /*++
  762. Routine Description:
  763. This routine handles receiving and processing a packet for the SM91c111 LAN
  764. Ethernet Controller.
  765. Arguments:
  766. Device - Supplies a pointer to the SM91C1 device.
  767. Return Value:
  768. None.
  769. --*/
  770. {
  771. USHORT ByteCount;
  772. USHORT BytesRemaining;
  773. BYTE ControlByte;
  774. USHORT ControlWord;
  775. PUSHORT Data;
  776. ULONG Index;
  777. USHORT MmuCommand;
  778. NET_PACKET_BUFFER Packet;
  779. USHORT PacketNumber;
  780. ULONG PacketSize;
  781. USHORT PointerValue;
  782. USHORT StatusWord;
  783. //
  784. // Read the packet number from the received FIFO.
  785. //
  786. PacketNumber = Sm91c1pReadRegister(Device, Sm91c1RegisterReceiveFifo);
  787. if ((PacketNumber & SM91C1_FIFO_PORTS_RECEIVE_EMPTY) != 0) {
  788. RtlDebugPrint("SM91C1: Receive interrupt lacks packet.\n");
  789. return;
  790. }
  791. //
  792. // Acquire the lock to protect access to the pointer and data registers.
  793. //
  794. KeAcquireQueuedLock(Device->Lock);
  795. //
  796. // Set the pointer register to receive, read, and auto-increment.
  797. //
  798. PointerValue = SM91C1_POINTER_READ |
  799. SM91C1_POINTER_AUTO_INCREMENT |
  800. SM91C1_POINTER_RECEIVE;
  801. Sm91c1pWriteRegister(Device, Sm91c1RegisterPointer, PointerValue);
  802. //
  803. // Read the status word.
  804. //
  805. StatusWord = Sm91c1pReadRegister(Device, Sm91c1RegisterData);
  806. //
  807. // Read the byte count and calculate the packet size. The byte count
  808. // contains the header, footer, and CRC size.
  809. //
  810. ByteCount = Sm91c1pReadRegister(Device, Sm91c1RegisterData);
  811. PacketSize = ByteCount -
  812. (SM91C1_PACKET_HEADER_SIZE +
  813. SM91C1_PACKET_FOOTER_SIZE +
  814. SM91C1_PACKET_CRC_SIZE);
  815. //
  816. // Read the data out of the data register and into the receive I/O buffer.
  817. //
  818. Data = Device->ReceiveIoBuffer->Fragment[0].VirtualAddress;
  819. BytesRemaining = PacketSize;
  820. ASSERT((BytesRemaining & 0x1) == 0);
  821. while (BytesRemaining != 0) {
  822. *Data = Sm91c1pReadRegister(Device, Sm91c1RegisterData);
  823. Data += 1;
  824. BytesRemaining -= 2;
  825. }
  826. //
  827. // Read the CRC.
  828. //
  829. for (Index = 0; Index < SM91C1_PACKET_CRC_SIZE; Index += sizeof(USHORT)) {
  830. Sm91c1pReadRegister(Device, Sm91c1RegisterData);
  831. }
  832. //
  833. // Read the control word. If the high byte (the control byte) indicates
  834. // that the packet has an odd length, the the low byte is the last byte of
  835. // data.
  836. //
  837. ControlWord = Sm91c1pReadRegister(Device, Sm91c1RegisterData);
  838. ControlByte = (BYTE)(ControlWord >> 8);
  839. if ((ControlByte & SM91C1_CONTROL_BYTE_ODD) != 0) {
  840. ASSERT((StatusWord & 0x1000) != 0);
  841. *Data = (BYTE)ControlWord;
  842. PacketSize += 1;
  843. }
  844. //
  845. // Relesae the lock as use of the data register is done. The receive buffer
  846. // is protected as there is only ever one receive in flight at a time.
  847. //
  848. KeReleaseQueuedLock(Device->Lock);
  849. //
  850. // Initialize the packet and notify the networking core.
  851. //
  852. Packet.Buffer = Device->ReceiveIoBuffer->Fragment[0].VirtualAddress;
  853. Packet.BufferPhysicalAddress =
  854. Device->ReceiveIoBuffer->Fragment[0].PhysicalAddress;
  855. Packet.IoBuffer = Device->ReceiveIoBuffer;
  856. Packet.Flags = 0;
  857. Packet.BufferSize = PacketSize;
  858. Packet.DataSize = PacketSize;
  859. Packet.DataOffset = 0;
  860. Packet.FooterOffset = PacketSize;
  861. NetProcessReceivedPacket(Device->NetworkLink, &Packet);
  862. //
  863. // Release the packet.
  864. //
  865. MmuCommand = (SM91C1_MMU_OPERATION_RECEiVE_FIFO_REMOVE_AND_RELEASE <<
  866. SM91C1_MMU_COMMAND_OPERATION_SHIFT) &
  867. SM91C1_MMU_COMMAND_OPERATION_MASK;
  868. Sm91c1pWriteRegister(Device, Sm91c1RegisterMmuCommand, MmuCommand);
  869. return;
  870. }
  871. VOID
  872. Sm91c1pInitializePhy (
  873. PSM91C1_DEVICE Device
  874. )
  875. /*++
  876. Routine Description:
  877. This routine initializes the PHY on the SMSC91C111.
  878. Arguments:
  879. Device - Supplies a pointer to the device.
  880. Return Value:
  881. None.
  882. --*/
  883. {
  884. USHORT PhyControl;
  885. ULONG Value;
  886. //
  887. // Enable auto-negotiation and set the LED state. LED A remains in the
  888. // default 10/100 link detected state and LED B gets set to full-duplex.
  889. //
  890. PhyControl = SM91C1_PHY_CONTROL_AUTONEGOTIATION |
  891. SM91C1_PHY_CONTROL_LED_SELECT_0B |
  892. SM91C1_PHY_CONTROL_LED_SELECT_1B;
  893. Sm91c1pWriteRegister(Device, Sm91c1RegisterPhyControl, PhyControl);
  894. //
  895. // Reset the PHY.
  896. //
  897. Sm91c1pWriteMdio(Device,
  898. Sm91c1MiiRegisterBasicControl,
  899. SM91C1_MII_BASIC_CONTROL_RESET);
  900. while (TRUE) {
  901. KeDelayExecution(FALSE, FALSE, 50 * MICROSECONDS_PER_MILLISECOND);
  902. Value = Sm91c1pReadMdio(Device, Sm91c1MiiRegisterBasicControl);
  903. if ((Value & SM91C1_MII_BASIC_CONTROL_RESET) == 0) {
  904. break;
  905. }
  906. }
  907. //
  908. // Start the auto-negotiation process.
  909. //
  910. Value = Sm91c1pReadMdio(Device, Sm91c1MiiRegisterBasicControl);
  911. Value |= SM91C1_MII_BASIC_CONTROL_ENABLE_AUTONEGOTIATION;
  912. Sm91c1pWriteMdio(Device, Sm91c1MiiRegisterBasicControl, Value);
  913. //
  914. // Read the interrupt status register to clear the bits.
  915. //
  916. Sm91c1pReadMdio(Device, Sm91c1MiiRegisterInterrupt);
  917. //
  918. // Write the interrupt mask.
  919. //
  920. Value = SM91C1_MII_INTERRUPT_STATUS_LINK_FAIL |
  921. SM91C1_MII_INTERRUPT_STATUS_INTERRUPT;
  922. Sm91c1pWriteMdio(Device, Sm91c1MiiRegisterInterruptMask, ~Value);
  923. return;
  924. }
  925. KSTATUS
  926. Sm91c1pReadMacAddress (
  927. PSM91C1_DEVICE Device
  928. )
  929. /*++
  930. Routine Description:
  931. This routine reads the MAC address out of the EEPROM on the SMSC91C1. The
  932. MAC address will be stored in the device structure.
  933. Arguments:
  934. Device - Supplies a pointer to the device.
  935. Return Value:
  936. Status code.
  937. --*/
  938. {
  939. SM91C1_REGISTER AddressRegister;
  940. ULONG Index;
  941. USHORT Value;
  942. //
  943. // Trigger a reload of the EEPROM values into the configuration, base, and
  944. // individual address registers. Do not set the EEPROM select bit and set
  945. // the RELOAD bit.
  946. //
  947. Value = Sm91c1pReadRegister(Device, Sm91c1RegisterControl);
  948. Value |= SM91C1_CONTROL_EEPROM_RELOAD;
  949. Sm91c1pWriteRegister(Device, Sm91c1RegisterControl, Value);
  950. //
  951. // Wait until the reload bit is cleared.
  952. //
  953. while (TRUE) {
  954. KeDelayExecution(FALSE, FALSE, 50 * MICROSECONDS_PER_MILLISECOND);
  955. Value = Sm91c1pReadRegister(Device, Sm91c1RegisterControl);
  956. if ((Value & SM91C1_CONTROL_EEPROM_RELOAD) == 0) {
  957. break;
  958. }
  959. }
  960. //
  961. // Now the MAC address should be filled into the individual address
  962. // registers. There is one byte in each but two can be read at a time as
  963. // they are sequential registers.
  964. //
  965. AddressRegister = Sm91c1RegisterIndividualAddress0;
  966. for (Index = 0; Index < sizeof(Device->MacAddress); Index += 1) {
  967. Value = Sm91c1pReadRegister(Device, AddressRegister);
  968. Device->MacAddress[Index] = (BYTE)Value;
  969. AddressRegister += 1;
  970. }
  971. //
  972. // Check to determine if this is a valid MAC address.
  973. //
  974. if (NetIsEthernetAddressValid(Device->MacAddress) == FALSE) {
  975. return STATUS_INVALID_ADDRESS;
  976. }
  977. return STATUS_SUCCESS;
  978. }
  979. USHORT
  980. Sm91c1pReadRegister (
  981. PSM91C1_DEVICE Device,
  982. SM91C1_REGISTER Register
  983. )
  984. /*++
  985. Routine Description:
  986. This routine reads from the specified register for the given SMSC91C1
  987. device.
  988. Arguments:
  989. Device - Supplies a pointer to the SMSC91C1 device whose register is to be
  990. read.
  991. Register - Supplies the register to read.
  992. Return Value:
  993. Returns the value of the register.
  994. --*/
  995. {
  996. BYTE Bank;
  997. BYTE ByteCount;
  998. BYTE Offset;
  999. RUNLEVEL OldRunLevel;
  1000. USHORT Value;
  1001. ASSERT((Sm91c1RegisterBankSelect & SM91C1_REGISTER_BANK_MASK) == 0);
  1002. if (Device->InterruptHandle == INVALID_HANDLE) {
  1003. OldRunLevel = KeRaiseRunLevel(RunLevelHigh);
  1004. } else {
  1005. OldRunLevel = IoRaiseToInterruptRunLevel(Device->InterruptHandle);
  1006. }
  1007. KeAcquireSpinLock(&(Device->BankLock));
  1008. //
  1009. // First select the correct bank. The bank register can always be accessed
  1010. // from the currently selected bank.
  1011. //
  1012. Bank = (Register & SM91C1_REGISTER_BANK_MASK) >> SM91C1_REGISTER_BANK_SHIFT;
  1013. if (Bank != Device->SelectedBank) {
  1014. Offset = (Sm91c1RegisterBankSelect & SM91C1_REGISTER_OFFSET_MASK) >>
  1015. SM91C1_REGISTER_OFFSET_SHIFT;
  1016. ByteCount = (Sm91c1RegisterBankSelect &
  1017. SM91C1_REGISTER_BYTE_COUNT_MASK) >>
  1018. SM91C1_REGISTER_BYTE_COUNT_SHIFT;
  1019. ASSERT(ByteCount == sizeof(USHORT));
  1020. HlWriteRegister16(Device->ControllerBase + Offset, Bank);
  1021. Device->SelectedBank = Bank;
  1022. }
  1023. //
  1024. // Now read the register. Act according to the byte count.
  1025. //
  1026. ByteCount = (Register & SM91C1_REGISTER_BYTE_COUNT_MASK) >>
  1027. SM91C1_REGISTER_BYTE_COUNT_SHIFT;
  1028. Offset = (Register & SM91C1_REGISTER_OFFSET_MASK) >>
  1029. SM91C1_REGISTER_OFFSET_SHIFT;
  1030. if (ByteCount == sizeof(BYTE)) {
  1031. Value = HlReadRegister8(Device->ControllerBase + Offset);
  1032. } else {
  1033. ASSERT(ByteCount == sizeof(USHORT));
  1034. Value = HlReadRegister16(Device->ControllerBase + Offset);
  1035. }
  1036. KeReleaseSpinLock(&(Device->BankLock));
  1037. KeLowerRunLevel(OldRunLevel);
  1038. return Value;
  1039. }
  1040. VOID
  1041. Sm91c1pWriteRegister (
  1042. PSM91C1_DEVICE Device,
  1043. SM91C1_REGISTER Register,
  1044. USHORT Value
  1045. )
  1046. /*++
  1047. Routine Description:
  1048. This routine writes to the specified register for the given SMSC91C1
  1049. device.
  1050. Arguments:
  1051. Device - Supplies a pointer to the SMSC91C1 device whose register is to be
  1052. written.
  1053. Register - Supplies the register to write.
  1054. Value - Supplies the value to write to the given register.
  1055. Return Value:
  1056. Returns the value of the register.
  1057. --*/
  1058. {
  1059. BYTE Bank;
  1060. BYTE ByteCount;
  1061. BYTE Offset;
  1062. RUNLEVEL OldRunLevel;
  1063. if (Device->InterruptHandle == INVALID_HANDLE) {
  1064. OldRunLevel = KeRaiseRunLevel(RunLevelHigh);
  1065. } else {
  1066. OldRunLevel = IoRaiseToInterruptRunLevel(Device->InterruptHandle);
  1067. }
  1068. //
  1069. // First select the correct bank, if necessary. The bank register can
  1070. // always be accessed from the currently selected bank.
  1071. //
  1072. KeAcquireSpinLock(&(Device->BankLock));
  1073. Bank = (Register & SM91C1_REGISTER_BANK_MASK) >> SM91C1_REGISTER_BANK_SHIFT;
  1074. if (Bank != Device->SelectedBank) {
  1075. Offset = (Sm91c1RegisterBankSelect & SM91C1_REGISTER_OFFSET_MASK) >>
  1076. SM91C1_REGISTER_OFFSET_SHIFT;
  1077. ByteCount = (Sm91c1RegisterBankSelect &
  1078. SM91C1_REGISTER_BYTE_COUNT_MASK) >>
  1079. SM91C1_REGISTER_BYTE_COUNT_SHIFT;
  1080. ASSERT(ByteCount == sizeof(USHORT));
  1081. HlWriteRegister16(Device->ControllerBase + Offset, Bank);
  1082. Device->SelectedBank = Bank;
  1083. }
  1084. //
  1085. // Now write the register. Act according to the byte count.
  1086. //
  1087. ByteCount = (Register & SM91C1_REGISTER_BYTE_COUNT_MASK) >>
  1088. SM91C1_REGISTER_BYTE_COUNT_SHIFT;
  1089. Offset = (Register & SM91C1_REGISTER_OFFSET_MASK) >>
  1090. SM91C1_REGISTER_OFFSET_SHIFT;
  1091. if (ByteCount == sizeof(BYTE)) {
  1092. HlWriteRegister8(Device->ControllerBase + Offset, (BYTE)Value);
  1093. } else {
  1094. ASSERT(ByteCount == sizeof(USHORT));
  1095. HlWriteRegister16(Device->ControllerBase + Offset, Value);
  1096. }
  1097. KeReleaseSpinLock(&(Device->BankLock));
  1098. KeLowerRunLevel(OldRunLevel);
  1099. return;
  1100. }
  1101. USHORT
  1102. Sm91c1pReadMdio (
  1103. PSM91C1_DEVICE Device,
  1104. SM91C1_MII_REGISTER Register
  1105. )
  1106. /*++
  1107. Routine Description:
  1108. This routine performs an MDIO register read.
  1109. Arguments:
  1110. Device - Supplies a pointer to the SMSC91C1 device context for the read.
  1111. Register - Supplies the SMSC91C1 MII register to read.
  1112. Return Value:
  1113. Returns the value of the MDO register.
  1114. --*/
  1115. {
  1116. USHORT Data;
  1117. ULONG Index;
  1118. USHORT Value;
  1119. //
  1120. // Synchronize the MI to prepare for the start bits.
  1121. //
  1122. Sm91c1SynchronizeMdio(Device);
  1123. //
  1124. // Issue the start bits: a 0 followed by a 1.
  1125. //
  1126. SM91C1_WRITE_ZERO_TO_MI(Device);
  1127. SM91C1_WRITE_ONE_TO_MI(Device);
  1128. //
  1129. // Issue a read command by writing a 1 followed by a 0.
  1130. //
  1131. SM91C1_WRITE_ONE_TO_MI(Device);
  1132. SM91C1_WRITE_ZERO_TO_MI(Device);
  1133. //
  1134. // Write the PHY device address which is 00000.
  1135. //
  1136. for (Index = 0; Index < 5; Index += 1) {
  1137. SM91C1_WRITE_ZERO_TO_MI(Device);
  1138. }
  1139. //
  1140. // Write the MII register to read. Most significant bit first.
  1141. //
  1142. for (Index = 0; Index < 5; Index += 1) {
  1143. if ((Register & 0x10) != 0) {
  1144. SM91C1_WRITE_ONE_TO_MI(Device);
  1145. } else {
  1146. SM91C1_WRITE_ZERO_TO_MI(Device);
  1147. }
  1148. Register <<= 1;
  1149. }
  1150. //
  1151. // Write Z for the turnaround time.
  1152. //
  1153. SM91C1_WRITE_Z_TO_MI(Device);
  1154. //
  1155. // Read the data bit by bit.
  1156. //
  1157. Data = 0;
  1158. for (Index = 0; Index < 16; Index += 1) {
  1159. Data <<= 1;
  1160. Sm91c1pWriteRegister(Device, Sm91c1RegisterManagementInterface, 0x0);
  1161. Sm91c1pWriteRegister(Device, Sm91c1RegisterManagementInterface, 0x4);
  1162. Value = Sm91c1pReadRegister(Device, Sm91c1RegisterManagementInterface);
  1163. Sm91c1pWriteRegister(Device, Sm91c1RegisterManagementInterface, 0x0);
  1164. if ((Value & SM91C1_MANAGEMENT_INTERFACE_MII_MDI) != 0) {
  1165. Data |= 0x1;
  1166. }
  1167. }
  1168. //
  1169. // Send the turnaround bit again.
  1170. //
  1171. SM91C1_WRITE_Z_TO_MI(Device);
  1172. return Data;
  1173. }
  1174. VOID
  1175. Sm91c1pWriteMdio (
  1176. PSM91C1_DEVICE Device,
  1177. SM91C1_MII_REGISTER Register,
  1178. USHORT Value
  1179. )
  1180. /*++
  1181. Routine Description:
  1182. This routine performs a write to an MDIO register.
  1183. Arguments:
  1184. Device - Supplies a pointer to the SMSC91C1 device context for the write.
  1185. Register - Supplies the SMSC91C1 MII register to write.
  1186. Value - Supplies the value to be written to the MDIO register.
  1187. Return Value:
  1188. None.
  1189. --*/
  1190. {
  1191. ULONG Index;
  1192. //
  1193. // Synchronize the MI to prepare for the start bits.
  1194. //
  1195. Sm91c1SynchronizeMdio(Device);
  1196. //
  1197. // Issue the start bits: a 0 followed by a 1.
  1198. //
  1199. SM91C1_WRITE_ZERO_TO_MI(Device);
  1200. SM91C1_WRITE_ONE_TO_MI(Device);
  1201. //
  1202. // Issue a write command by writing a 0 followed by a 1.
  1203. //
  1204. SM91C1_WRITE_ZERO_TO_MI(Device);
  1205. SM91C1_WRITE_ONE_TO_MI(Device);
  1206. //
  1207. // Write the PHY device address which is 00000.
  1208. //
  1209. for (Index = 0; Index < 5; Index += 1) {
  1210. SM91C1_WRITE_ZERO_TO_MI(Device);
  1211. }
  1212. //
  1213. // Write the MII register to read. Most significant bit first.
  1214. //
  1215. for (Index = 0; Index < 5; Index += 1) {
  1216. if ((Register & 0x10) != 0) {
  1217. SM91C1_WRITE_ONE_TO_MI(Device);
  1218. } else {
  1219. SM91C1_WRITE_ZERO_TO_MI(Device);
  1220. }
  1221. Register <<= 1;
  1222. }
  1223. //
  1224. // Send the turnaround sequence: a 1 and then a 0.
  1225. //
  1226. SM91C1_WRITE_ONE_TO_MI(Device);
  1227. SM91C1_WRITE_ZERO_TO_MI(Device);
  1228. //
  1229. // Write the data bit by bit, starting with the most significant bit.
  1230. //
  1231. for (Index = 0; Index < 16; Index += 1) {
  1232. if ((Value & 0x8000) != 0) {
  1233. SM91C1_WRITE_ONE_TO_MI(Device);
  1234. } else {
  1235. SM91C1_WRITE_ZERO_TO_MI(Device);
  1236. }
  1237. Value <<= 1;
  1238. }
  1239. //
  1240. // Send the turnaround Z.
  1241. //
  1242. SM91C1_WRITE_Z_TO_MI(Device);
  1243. return;
  1244. }
  1245. VOID
  1246. Sm91c1SynchronizeMdio (
  1247. PSM91C1_DEVICE Device
  1248. )
  1249. /*++
  1250. Routine Description:
  1251. This routine synchronizes the MDIO to prepare it for a register read or
  1252. write.
  1253. Arguments:
  1254. Device - Supplies a pointer to the SMSC91C1 device context.
  1255. Return Value:
  1256. None.
  1257. --*/
  1258. {
  1259. ULONG Index;
  1260. //
  1261. // Synchronize the MII by writing at least 32 ones.
  1262. //
  1263. for (Index = 0; Index < SM91C1_MII_SYNCHRONIZE_COUNT; Index += 1) {
  1264. SM91C1_WRITE_ONE_TO_MI(Device);
  1265. }
  1266. return;
  1267. }