smsc95hw.c 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. smsc95hw.c
  5. Abstract:
  6. This module implements device support for the SMSC95xx family of USB
  7. Ethernet Controllers.
  8. Author:
  9. Evan Green 7-Nov-2013
  10. Environment:
  11. Kernel
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. #include <minoca/kernel/driver.h>
  17. #include <minoca/net/netdrv.h>
  18. #include <minoca/usb/usb.h>
  19. #include "smsc95.h"
  20. //
  21. // ---------------------------------------------------------------- Definitions
  22. //
  23. //
  24. // Define the maximum number of bulk out transfers that are allowed to be
  25. // submitted to USB at one time.
  26. //
  27. #define SM95_MAX_BULK_OUT_TRANSFER_COUNT 64
  28. //
  29. // ------------------------------------------------------ Data Type Definitions
  30. //
  31. /*++
  32. Structure Description:
  33. This structure defines an SM95xx bulk out transfer. These transfers are
  34. allocated on demand and recycled when complete.
  35. Members:
  36. ListEntry - Stores a pointer to the next and previous bulk out transfer
  37. on the devices free transfer list.
  38. Device - Stores a pointer to the SM95 device that owns the transfer.
  39. UsbTransfer - Stores a pointer to the USB transfer that belongs to this
  40. SM95 transfer for the duration of its existence.
  41. Packet - Stores a pointer to the network packet buffer whose data is being
  42. sent by the USB transfer.
  43. --*/
  44. typedef struct _SM95_BULK_OUT_TRANSFER {
  45. LIST_ENTRY ListEntry;
  46. PSM95_DEVICE Device;
  47. PUSB_TRANSFER UsbTransfer;
  48. PNET_PACKET_BUFFER Packet;
  49. } SM95_BULK_OUT_TRANSFER, *PSM95_BULK_OUT_TRANSFER;
  50. //
  51. // ----------------------------------------------- Internal Function Prototypes
  52. //
  53. VOID
  54. Sm95pTransmitPacketCompletion (
  55. PUSB_TRANSFER Transfer
  56. );
  57. KSTATUS
  58. Sm95pEnableMac (
  59. PSM95_DEVICE Device
  60. );
  61. KSTATUS
  62. Sm95pSetupChecksumOffloading (
  63. PSM95_DEVICE Device,
  64. BOOL EnableTransmitChecksumOffload,
  65. BOOL EnableReceiveChecksumOffload
  66. );
  67. KSTATUS
  68. Sm95pSetMacAddress (
  69. PSM95_DEVICE Device,
  70. BYTE Address[ETHERNET_ADDRESS_SIZE]
  71. );
  72. KSTATUS
  73. Sm95pReadMacAddress (
  74. PSM95_DEVICE Device
  75. );
  76. KSTATUS
  77. Sm95pInitializePhy (
  78. PSM95_DEVICE Device
  79. );
  80. KSTATUS
  81. Sm95pRestartNway (
  82. PSM95_DEVICE Device
  83. );
  84. KSTATUS
  85. Sm95pReadEeprom (
  86. PSM95_DEVICE Device,
  87. ULONG Offset,
  88. ULONG Length,
  89. PBYTE Data
  90. );
  91. KSTATUS
  92. Sm95pWaitForEeprom (
  93. PSM95_DEVICE Device,
  94. BOOL ObserveEepromTimeout
  95. );
  96. KSTATUS
  97. Sm95pWriteMdio (
  98. PSM95_DEVICE Device,
  99. USHORT PhyId,
  100. USHORT Index,
  101. ULONG Data
  102. );
  103. KSTATUS
  104. Sm95pReadMdio (
  105. PSM95_DEVICE Device,
  106. USHORT PhyId,
  107. USHORT Index,
  108. PULONG Data
  109. );
  110. KSTATUS
  111. Sm95pWaitForPhy (
  112. PSM95_DEVICE Device
  113. );
  114. KSTATUS
  115. Sm95pWriteRegister (
  116. PSM95_DEVICE Device,
  117. USHORT Register,
  118. ULONG Data
  119. );
  120. KSTATUS
  121. Sm95pReadRegister (
  122. PSM95_DEVICE Device,
  123. USHORT Register,
  124. PULONG Data
  125. );
  126. KSTATUS
  127. Sm95pSubmitBulkInTransfers (
  128. PSM95_DEVICE Device
  129. );
  130. VOID
  131. Sm95pCancelBulkInTransfers (
  132. PSM95_DEVICE Device
  133. );
  134. PSM95_BULK_OUT_TRANSFER
  135. Sm95pAllocateBulkOutTransfer (
  136. PSM95_DEVICE Device
  137. );
  138. VOID
  139. Sm95pFreeBulkOutTransfer (
  140. PSM95_BULK_OUT_TRANSFER Transfer
  141. );
  142. //
  143. // -------------------------------------------------------------------- Globals
  144. //
  145. BOOL Sm95DisablePacketDropping = FALSE;
  146. //
  147. // ------------------------------------------------------------------ Functions
  148. //
  149. KSTATUS
  150. Sm95Send (
  151. PVOID DeviceContext,
  152. PNET_PACKET_LIST PacketList
  153. )
  154. /*++
  155. Routine Description:
  156. This routine sends data through the network.
  157. Arguments:
  158. DeviceContext - Supplies a pointer to the device context associated with
  159. the link down which this data is to be sent.
  160. PacketList - Supplies a pointer to a list of network packets to send. Data
  161. in these packets may be modified by this routine, but must not be used
  162. once this routine returns.
  163. Return Value:
  164. STATUS_SUCCESS if all packets were sent.
  165. STATUS_RESOURCE_IN_USE if some or all of the packets were dropped due to
  166. the hardware being backed up with too many packets to send.
  167. Other failure codes indicate that none of the packets were sent.
  168. --*/
  169. {
  170. ULONG DataSize;
  171. PSM95_DEVICE Device;
  172. PULONG Header;
  173. PNET_PACKET_BUFFER Packet;
  174. PSM95_BULK_OUT_TRANSFER Sm95Transfer;
  175. KSTATUS Status;
  176. PUSB_TRANSFER UsbTransfer;
  177. Device = (PSM95_DEVICE)DeviceContext;
  178. //
  179. // If there are more bulk out transfers in transit that allowed, drop all
  180. // of these packets.
  181. //
  182. if ((Device->BulkOutTransferCount >= SM95_MAX_BULK_OUT_TRANSFER_COUNT) &&
  183. (Sm95DisablePacketDropping == FALSE)) {
  184. return STATUS_RESOURCE_IN_USE;
  185. }
  186. //
  187. // Otherwise submit all the packets. This may stretch over the maximum
  188. // number of bulk out transfers, but it's a flexible line.
  189. //
  190. while (NET_PACKET_LIST_EMPTY(PacketList) == FALSE) {
  191. Packet = LIST_VALUE(PacketList->Head.Next,
  192. NET_PACKET_BUFFER,
  193. ListEntry);
  194. NET_REMOVE_PACKET_FROM_LIST(Packet, PacketList);
  195. ASSERT(IS_ALIGNED(Packet->BufferSize, MmGetIoBufferAlignment()) !=
  196. FALSE);
  197. ASSERT(IS_ALIGNED((UINTN)Packet->Buffer,
  198. MmGetIoBufferAlignment()) != FALSE);
  199. ASSERT(IS_ALIGNED((UINTN)Packet->BufferPhysicalAddress,
  200. MmGetIoBufferAlignment()) != FALSE);
  201. //
  202. // There might be legitimate reasons for this assert to be spurious,
  203. // but most likely this assert fired because something in the
  204. // networking stack failed to properly allocate the required header
  205. // space. Go figure out who allocated this packet.
  206. //
  207. ASSERT(Packet->DataOffset == SM95_TRANSMIT_HEADER_SIZE);
  208. DataSize = Packet->FooterOffset - Packet->DataOffset;
  209. Packet->DataOffset -= SM95_TRANSMIT_HEADER_SIZE;
  210. Header = Packet->Buffer;
  211. *Header = DataSize |
  212. SM95_TRANSMIT_FLAG_FIRST_SEGMENT |
  213. SM95_TRANSMIT_FLAG_LAST_SEGMENT;
  214. *(Header + 1) = DataSize;
  215. //
  216. // Allocate a transfer for this packet. All packets need to be dealt
  217. // with, so if the allocation or submission fails then free the buffer.
  218. //
  219. Sm95Transfer = Sm95pAllocateBulkOutTransfer(Device);
  220. if (Sm95Transfer == NULL) {
  221. Status = STATUS_INSUFFICIENT_RESOURCES;
  222. RtlDebugPrint("SM95: Failed to allocate transfer.\n");
  223. NetFreeBuffer(Packet);
  224. break;
  225. }
  226. Sm95Transfer->Packet = Packet;
  227. UsbTransfer = Sm95Transfer->UsbTransfer;
  228. UsbTransfer->Length = Packet->FooterOffset;
  229. UsbTransfer->BufferActualLength = Packet->BufferSize;
  230. UsbTransfer->Buffer = Header;
  231. UsbTransfer->BufferPhysicalAddress = Packet->BufferPhysicalAddress;
  232. RtlAtomicAdd32(&(Device->BulkOutTransferCount), 1);
  233. Status = UsbSubmitTransfer(UsbTransfer);
  234. if (!KSUCCESS(Status)) {
  235. RtlDebugPrint("SM95: Failed to submit transmit packet: %d\n",
  236. Status);
  237. Sm95Transfer->Packet = NULL;
  238. Sm95pFreeBulkOutTransfer(Sm95Transfer);
  239. NetFreeBuffer(Packet);
  240. RtlAtomicAdd32(&(Device->BulkOutTransferCount), -1);
  241. break;
  242. }
  243. }
  244. return Status;
  245. }
  246. KSTATUS
  247. Sm95GetSetInformation (
  248. PVOID DeviceContext,
  249. NET_LINK_INFORMATION_TYPE InformationType,
  250. PVOID Data,
  251. PUINTN DataSize,
  252. BOOL Set
  253. )
  254. /*++
  255. Routine Description:
  256. This routine gets or sets the network device layer's link information.
  257. Arguments:
  258. DeviceContext - Supplies a pointer to the device context associated with
  259. the link for which information is being set or queried.
  260. InformationType - Supplies the type of information being queried or set.
  261. Data - Supplies a pointer to the data buffer where the data is either
  262. returned for a get operation or given for a set operation.
  263. DataSize - Supplies a pointer that on input contains the size of the data
  264. buffer. On output, contains the required size of the data buffer.
  265. Set - Supplies a boolean indicating if this is a get operation (FALSE) or a
  266. set operation (TRUE).
  267. Return Value:
  268. Status code.
  269. --*/
  270. {
  271. PULONG Flags;
  272. KSTATUS Status;
  273. switch (InformationType) {
  274. case NetLinkInformationChecksumOffload:
  275. if (*DataSize != sizeof(ULONG)) {
  276. return STATUS_INVALID_PARAMETER;
  277. }
  278. if (Set != FALSE) {
  279. return STATUS_NOT_SUPPORTED;
  280. }
  281. Flags = (PULONG)Data;
  282. *Flags = 0;
  283. break;
  284. default:
  285. Status = STATUS_NOT_SUPPORTED;
  286. break;
  287. }
  288. return Status;
  289. }
  290. VOID
  291. Sm95InterruptTransferCompletion (
  292. PUSB_TRANSFER Transfer
  293. )
  294. /*++
  295. Routine Description:
  296. This routine is called when the interrupt transfer returns. It processes
  297. the notification from the device.
  298. Arguments:
  299. Transfer - Supplies a pointer to the transfer that completed.
  300. Return Value:
  301. None.
  302. --*/
  303. {
  304. PSM95_DEVICE Device;
  305. BOOL OriginalLinkUp;
  306. ULONG Source;
  307. KSTATUS Status;
  308. ULONG Value;
  309. Device = Transfer->UserData;
  310. ASSERT(Transfer == Device->InterruptTransfer);
  311. //
  312. // If the transfer failed, don't bother with the data. If it was cancelled,
  313. // just exit immediately. The device was likely removed.
  314. //
  315. if (!KSUCCESS(Transfer->Status)) {
  316. if (Transfer->Status == STATUS_OPERATION_CANCELLED) {
  317. return;
  318. }
  319. goto InterruptTransferCompletionEnd;
  320. }
  321. if (Transfer->LengthTransferred != sizeof(ULONG)) {
  322. RtlDebugPrint("SM95: Got weird interrupt transfer of size %d.\n",
  323. Transfer->LengthTransferred);
  324. goto InterruptTransferCompletionEnd;
  325. }
  326. RtlCopyMemory(&Value, Transfer->Buffer, sizeof(ULONG));
  327. if ((Value & SM95_INTERRUPT_STATUS_PHY) != 0) {
  328. //
  329. // Read the interrupt status to clear it from the PHY.
  330. //
  331. Status = Sm95pReadMdio(Device,
  332. Device->PhyId,
  333. Sm95PhyRegisterInterruptSource,
  334. &Source);
  335. if (!KSUCCESS(Status)) {
  336. goto InterruptTransferCompletionEnd;
  337. }
  338. //
  339. // Read the status register to find out what happened to the link. Read
  340. // the register twice as the link status bit is sticky.
  341. //
  342. Status = Sm95pReadMdio(Device,
  343. Device->PhyId,
  344. MiiRegisterBasicStatus,
  345. &Value);
  346. if (!KSUCCESS(Status)) {
  347. goto InterruptTransferCompletionEnd;
  348. }
  349. Status = Sm95pReadMdio(Device,
  350. Device->PhyId,
  351. MiiRegisterBasicStatus,
  352. &Value);
  353. if (!KSUCCESS(Status)) {
  354. goto InterruptTransferCompletionEnd;
  355. }
  356. if ((Value & MII_BASIC_STATUS_LINK_STATUS) != 0) {
  357. if ((Value & MII_BASIC_STATUS_AUTONEGOTIATE_COMPLETE) != 0) {
  358. //
  359. // Get the current link state.
  360. //
  361. NetGetLinkState(Device->NetworkLink, &OriginalLinkUp, NULL);
  362. //
  363. // TODO: Get the real device speed when generic MII support is
  364. // added.
  365. //
  366. NetSetLinkState(Device->NetworkLink, TRUE, NET_SPEED_100_MBPS);
  367. //
  368. // Submit the bulk IN transfer if the original state was down.
  369. //
  370. if (OriginalLinkUp == FALSE) {
  371. Status = Sm95pSubmitBulkInTransfers(Device);
  372. if (!KSUCCESS(Status)) {
  373. goto InterruptTransferCompletionEnd;
  374. }
  375. }
  376. }
  377. } else {
  378. NetSetLinkState(Device->NetworkLink, FALSE, 0);
  379. //
  380. // Try to cancel the bulk IN transfer. If the transfer has also
  381. // completed, it may be waiting to run, in which case it is too
  382. // late to cancel. That's OK as it will check the link state and
  383. // see that it should not re-submit. Make sure that the cancel
  384. // routine does not wait for the transfer to reach the inactive
  385. // state as the transfer could be sitting on the completed transfer
  386. // queue behind this transfer.
  387. //
  388. Sm95pCancelBulkInTransfers(Device);
  389. }
  390. }
  391. //
  392. // Write the interrupt status register to clear the interrupts.
  393. //
  394. Status = Sm95pWriteRegister(Device,
  395. Sm95RegisterInterruptStatus,
  396. SM95_INTERRUPT_MASK);
  397. if (!KSUCCESS(Status)) {
  398. goto InterruptTransferCompletionEnd;
  399. }
  400. InterruptTransferCompletionEnd:
  401. //
  402. // Resubmit the transfer.
  403. //
  404. Status = UsbSubmitTransfer(Transfer);
  405. if (!KSUCCESS(Status)) {
  406. RtlDebugPrint("SM95: Failed to resubmit interrupt transfer: %d.\n",
  407. Status);
  408. }
  409. return;
  410. }
  411. VOID
  412. Sm95BulkInTransferCompletion (
  413. PUSB_TRANSFER Transfer
  414. )
  415. /*++
  416. Routine Description:
  417. This routine is called when the bulk in transfer returns. It processes
  418. the notification from the device.
  419. Arguments:
  420. Transfer - Supplies a pointer to the transfer that completed.
  421. Return Value:
  422. None.
  423. --*/
  424. {
  425. PUCHAR Data;
  426. PSM95_DEVICE Device;
  427. PULONG Header;
  428. ULONG Length;
  429. BOOL LinkUp;
  430. NET_PACKET_BUFFER Packet;
  431. ULONG PacketLength;
  432. PHYSICAL_ADDRESS PhysicalAddress;
  433. KSTATUS Status;
  434. Device = Transfer->UserData;
  435. Status = STATUS_SUCCESS;
  436. //
  437. // If the transfer failed, don't bother with the data.
  438. //
  439. if (!KSUCCESS(Transfer->Status)) {
  440. //
  441. // If the transfer stalled, attempt to clear the HALT feature from the
  442. // endpoint.
  443. //
  444. if (Transfer->Error == UsbErrorTransferStalled) {
  445. Status = UsbClearFeature(Device->UsbCoreHandle,
  446. USB_SETUP_REQUEST_ENDPOINT_RECIPIENT,
  447. USB_FEATURE_ENDPOINT_HALT,
  448. Device->BulkInEndpoint);
  449. }
  450. goto BulkInTransferCompletionEnd;
  451. }
  452. Data = Transfer->Buffer;
  453. PhysicalAddress = Transfer->BufferPhysicalAddress;
  454. Length = Transfer->LengthTransferred;
  455. Packet.IoBuffer = NULL;
  456. Packet.Flags = 0;
  457. while (Length > 0) {
  458. if (Length < sizeof(ULONG)) {
  459. RtlDebugPrint("SM95: Received odd sized data (%d).\n", Length);
  460. break;
  461. }
  462. Header = (PULONG)Data;
  463. ASSERT(((UINTN)Header & 0x3) == 0);
  464. if ((*Header & SM95_RECEIVE_FLAG_ERROR_SUMMARY) != 0) {
  465. RtlDebugPrint("SM95: Receive error summary 0x%x\n", *Header);
  466. break;
  467. }
  468. PacketLength = (*Header & SM95_RECEIVE_FRAME_LENGTH_MASK) >>
  469. SM95_RECEIVE_FRAME_LENGTH_SHIFT;
  470. if (PacketLength > Length - sizeof(ULONG)) {
  471. RtlDebugPrint("SM95: Got packet purported to be size %d, but "
  472. "only %d bytes remaining in the transfer.\n",
  473. PacketLength,
  474. Length - sizeof(ULONG));
  475. break;
  476. }
  477. Packet.Buffer = Data + sizeof(ULONG) + SM95_RECEIVE_DATA_OFFSET;
  478. Packet.BufferPhysicalAddress = PhysicalAddress +
  479. sizeof(ULONG) +
  480. SM95_RECEIVE_DATA_OFFSET;
  481. Packet.BufferSize = PacketLength - sizeof(ULONG);
  482. Packet.DataSize = Packet.BufferSize;
  483. Packet.DataOffset = 0;
  484. Packet.FooterOffset = Packet.DataSize;
  485. NetProcessReceivedPacket(Device->NetworkLink, &Packet);
  486. //
  487. // Advance to the next packet, adding an extra 4 and aligning the total
  488. // offset to 4.
  489. //
  490. PacketLength += sizeof(ULONG) + SM95_RECEIVE_DATA_OFFSET;
  491. PacketLength = ALIGN_RANGE_UP(PacketLength, sizeof(ULONG));
  492. if (PacketLength >= Length) {
  493. break;
  494. }
  495. Length -= PacketLength;
  496. Data += PacketLength;
  497. PhysicalAddress += PacketLength;
  498. }
  499. BulkInTransferCompletionEnd:
  500. //
  501. // If the link is still up and everything went smashingly above, resubmit
  502. // the transfer and around it goes.
  503. //
  504. NetGetLinkState(Device->NetworkLink, &LinkUp, NULL);
  505. if (KSUCCESS(Status) && (LinkUp != FALSE)) {
  506. Status = UsbSubmitTransfer(Transfer);
  507. if (!KSUCCESS(Status)) {
  508. RtlDebugPrint("SM95: Failed to resubmit bulk IN transfer.\n");
  509. }
  510. }
  511. return;
  512. }
  513. KSTATUS
  514. Sm95pInitialize (
  515. PSM95_DEVICE Device
  516. )
  517. /*++
  518. Routine Description:
  519. This routine initializes and enables the SMSC95xx device.
  520. Arguments:
  521. Device - Supplies a pointer to the device.
  522. Return Value:
  523. Status code.
  524. --*/
  525. {
  526. ULONGLONG CurrentTime;
  527. ULONG ReadValue;
  528. USB_DEVICE_SPEED Speed;
  529. KSTATUS Status;
  530. ULONGLONG Timeout;
  531. ULONGLONG TimeoutTicks;
  532. ULONG Value;
  533. TimeoutTicks = HlQueryTimeCounterFrequency() * SM95_DEVICE_TIMEOUT;
  534. //
  535. // The device's PHY is at a fixed address.
  536. //
  537. Device->PhyId = SM95_PHY_ID;
  538. //
  539. // Perform a reset of the device.
  540. //
  541. Value = SM95_HARDWARE_CONFIG_LITE_RESET;
  542. Status = Sm95pWriteRegister(Device, Sm95RegisterHardwareConfig, Value);
  543. if (!KSUCCESS(Status)) {
  544. goto InitializeEnd;
  545. }
  546. CurrentTime = KeGetRecentTimeCounter();
  547. Timeout = CurrentTime + TimeoutTicks;
  548. do {
  549. Status = Sm95pReadRegister(Device,
  550. Sm95RegisterHardwareConfig,
  551. &ReadValue);
  552. if (!KSUCCESS(Status)) {
  553. goto InitializeEnd;
  554. }
  555. if ((ReadValue & SM95_HARDWARE_CONFIG_LITE_RESET) == 0) {
  556. break;
  557. }
  558. CurrentTime = KeGetRecentTimeCounter();
  559. } while (CurrentTime <= Timeout);
  560. if (CurrentTime > Timeout) {
  561. Status = STATUS_TIMEOUT;
  562. goto InitializeEnd;
  563. }
  564. //
  565. // Also reset the PHY.
  566. //
  567. Value = SM95_POWER_CONTROL_PHY_RESET;
  568. Status = Sm95pWriteRegister(Device, Sm95RegisterPowerControl, Value);
  569. CurrentTime = KeGetRecentTimeCounter();
  570. Timeout = CurrentTime + TimeoutTicks;
  571. do {
  572. Status = Sm95pReadRegister(Device,
  573. Sm95RegisterPowerControl,
  574. &ReadValue);
  575. if (!KSUCCESS(Status)) {
  576. goto InitializeEnd;
  577. }
  578. if ((ReadValue & SM95_POWER_CONTROL_PHY_RESET) == 0) {
  579. break;
  580. }
  581. CurrentTime = KeGetRecentTimeCounter();
  582. } while (CurrentTime <= Timeout);
  583. if (CurrentTime > Timeout) {
  584. Status = STATUS_TIMEOUT;
  585. goto InitializeEnd;
  586. }
  587. //
  588. // Read the MAC address from the EEPROM and program it into the device.
  589. // If there was no EEPROM, generate a random MAC address.
  590. //
  591. Status = Sm95pReadMacAddress(Device);
  592. if (Status == STATUS_INVALID_ADDRESS) {
  593. NetCreateEthernetAddress(Device->MacAddress);
  594. } else if (!KSUCCESS(Status)) {
  595. goto InitializeEnd;
  596. }
  597. Status = Sm95pSetMacAddress(Device, Device->MacAddress);
  598. if (!KSUCCESS(Status)) {
  599. goto InitializeEnd;
  600. }
  601. //
  602. // Enable BIR.
  603. //
  604. Status = Sm95pReadRegister(Device, Sm95RegisterHardwareConfig, &ReadValue);
  605. if (!KSUCCESS(Status)) {
  606. goto InitializeEnd;
  607. }
  608. Value = ReadValue | SM95_HARDWARE_CONFIG_BULK_IN_EMPTY_RESPONSE;
  609. Status = Sm95pWriteRegister(Device, Sm95RegisterHardwareConfig, Value);
  610. if (!KSUCCESS(Status)) {
  611. goto InitializeEnd;
  612. }
  613. //
  614. // Set up the burst capability.
  615. //
  616. Status = UsbGetDeviceSpeed(Device->UsbCoreHandle, &Speed);
  617. if (!KSUCCESS(Status)) {
  618. goto InitializeEnd;
  619. }
  620. if (Speed == UsbDeviceSpeedHigh) {
  621. Value = SM95_HIGH_SPEED_BURST_SIZE / SM95_HIGH_SPEED_TRANSFER_SIZE;
  622. } else {
  623. ASSERT(Speed == UsbDeviceSpeedFull);
  624. Value = SM95_FULL_SPEED_BURST_SIZE / SM95_FULL_SPEED_TRANSFER_SIZE;
  625. }
  626. Status = Sm95pWriteRegister(Device, Sm95RegisterBurstCapability, Value);
  627. if (!KSUCCESS(Status)) {
  628. goto InitializeEnd;
  629. }
  630. //
  631. // Set the bulk IN delay.
  632. //
  633. Value = SM95_DEFAULT_BULK_IN_DELAY;
  634. Status = Sm95pWriteRegister(Device, Sm95RegisterBulkInDelay, Value);
  635. if (!KSUCCESS(Status)) {
  636. goto InitializeEnd;
  637. }
  638. //
  639. // Enable MEF and BCE.
  640. //
  641. Status = Sm95pReadRegister(Device, Sm95RegisterHardwareConfig, &Value);
  642. if (!KSUCCESS(Status)) {
  643. goto InitializeEnd;
  644. }
  645. Value |= SM95_HARDWARE_CONFIG_MULTIPLE_ETHERNET_FRAMES |
  646. SM95_HARDWARE_CONFIG_BURST_CAP_ENABLED;
  647. Value &= ~SM95_HARDWARE_CONFIG_RX_DATA_OFFSET_MASK;
  648. Value |= SM95_RECEIVE_DATA_OFFSET <<
  649. SM95_HARDWARE_CONFIG_RX_DATA_OFFSET_SHIFT;
  650. Status = Sm95pWriteRegister(Device, Sm95RegisterHardwareConfig, Value);
  651. if (!KSUCCESS(Status)) {
  652. goto InitializeEnd;
  653. }
  654. //
  655. // Clear all interrupts.
  656. //
  657. Value = SM95_INTERRUPT_MASK;
  658. Status = Sm95pWriteRegister(Device, Sm95RegisterInterruptStatus, Value);
  659. if (!KSUCCESS(Status)) {
  660. goto InitializeEnd;
  661. }
  662. //
  663. // Configure the GPIO pins as LED outputs.
  664. //
  665. Value = SM95_LED_GPIO_CONFIG_SPEED_LED | SM95_LED_GPIO_CONFIG_LINK_LED |
  666. SM95_LED_GPIO_CONFIG_FULL_DUPLEX_LED;
  667. Status = Sm95pWriteRegister(Device, Sm95RegisterLedGpioConfig, Value);
  668. if (!KSUCCESS(Status)) {
  669. goto InitializeEnd;
  670. }
  671. //
  672. // Initialize transmit parameters.
  673. //
  674. Status = Sm95pWriteRegister(Device, Sm95RegisterFlowControl, 0);
  675. if (!KSUCCESS(Status)) {
  676. goto InitializeEnd;
  677. }
  678. Value = SM95_AUTO_FLOW_CONTROL_DEFAULT;
  679. Status = Sm95pWriteRegister(Device, Sm95RegisterAutoFlowControl, Value);
  680. if (!KSUCCESS(Status)) {
  681. goto InitializeEnd;
  682. }
  683. Status = Sm95pReadRegister(Device,
  684. Sm95RegisterMacControl,
  685. &(Device->MacControl));
  686. if (!KSUCCESS(Status)) {
  687. goto InitializeEnd;
  688. }
  689. //
  690. // Initialize receive parameters.
  691. //
  692. Value = SM95_VLAN_8021Q;
  693. Status = Sm95pWriteRegister(Device, Sm95RegisterVlan1, Value);
  694. if (!KSUCCESS(Status)) {
  695. goto InitializeEnd;
  696. }
  697. //
  698. // Disable checksum offload engines.
  699. //
  700. Status = Sm95pSetupChecksumOffloading(Device, FALSE, FALSE);
  701. if (!KSUCCESS(Status)) {
  702. goto InitializeEnd;
  703. }
  704. Status = Sm95pInitializePhy(Device);
  705. if (!KSUCCESS(Status)) {
  706. goto InitializeEnd;
  707. }
  708. //
  709. // Enable PHY interrupts.
  710. //
  711. Status = Sm95pReadRegister(Device,
  712. Sm95RegisterInterruptEndpointControl,
  713. &Value);
  714. if (!KSUCCESS(Status)) {
  715. goto InitializeEnd;
  716. }
  717. Value |= SM95_INTERRUPT_ENDPOINT_CONTROL_PHY_INTERRUPTS;
  718. Status = Sm95pWriteRegister(Device,
  719. Sm95RegisterInterruptEndpointControl,
  720. Value);
  721. if (!KSUCCESS(Status)) {
  722. goto InitializeEnd;
  723. }
  724. Status = Sm95pEnableMac(Device);
  725. if (!KSUCCESS(Status)) {
  726. goto InitializeEnd;
  727. }
  728. //
  729. // Do an initial read of the MII status and report the link as up if it
  730. // started connected. Read the register twice as the link status bit is
  731. // sticky.
  732. //
  733. Status = Sm95pReadMdio(Device,
  734. Device->PhyId,
  735. MiiRegisterBasicStatus,
  736. &Value);
  737. if (!KSUCCESS(Status)) {
  738. goto InitializeEnd;
  739. }
  740. Status = Sm95pReadMdio(Device,
  741. Device->PhyId,
  742. MiiRegisterBasicStatus,
  743. &Value);
  744. if (!KSUCCESS(Status)) {
  745. goto InitializeEnd;
  746. }
  747. //
  748. // Notify the networking core of this new link now that the device is ready
  749. // to send and receive data, pending media being present.
  750. //
  751. Status = Sm95pAddNetworkDevice(Device);
  752. if (!KSUCCESS(Status)) {
  753. goto InitializeEnd;
  754. }
  755. if (((Value & MII_BASIC_STATUS_LINK_STATUS) != 0) &&
  756. ((Value & MII_BASIC_STATUS_AUTONEGOTIATE_COMPLETE) != 0)) {
  757. //
  758. // TODO: Get the real device speed when generic MII support is added.
  759. //
  760. NetSetLinkState(Device->NetworkLink, TRUE, NET_SPEED_100_MBPS);
  761. //
  762. // Submit the bulk IN transfer.
  763. //
  764. Status = Sm95pSubmitBulkInTransfers(Device);
  765. if (!KSUCCESS(Status)) {
  766. goto InitializeEnd;
  767. }
  768. }
  769. //
  770. // Submit the interrupt transfer.
  771. //
  772. Status = UsbSubmitTransfer(Device->InterruptTransfer);
  773. if (!KSUCCESS(Status)) {
  774. goto InitializeEnd;
  775. }
  776. InitializeEnd:
  777. return Status;
  778. }
  779. VOID
  780. Sm95pDestroyBulkOutTransfers (
  781. PSM95_DEVICE Device
  782. )
  783. /*++
  784. Routine Description:
  785. This routine destroys the SMSC95xx device's bulk out tranfers.
  786. Arguments:
  787. Device - Supplies a pointer to the device.
  788. Return Value:
  789. None.
  790. --*/
  791. {
  792. PSM95_BULK_OUT_TRANSFER Sm95Transfer;
  793. while (LIST_EMPTY(&(Device->BulkOutFreeTransferList)) == FALSE) {
  794. Sm95Transfer = LIST_VALUE(Device->BulkOutFreeTransferList.Next,
  795. SM95_BULK_OUT_TRANSFER,
  796. ListEntry);
  797. ASSERT(Sm95Transfer->Packet == NULL);
  798. LIST_REMOVE(&(Sm95Transfer->ListEntry));
  799. UsbDestroyTransfer(Sm95Transfer->UsbTransfer);
  800. MmFreePagedPool(Sm95Transfer);
  801. }
  802. return;
  803. }
  804. //
  805. // --------------------------------------------------------- Internal Functions
  806. //
  807. VOID
  808. Sm95pTransmitPacketCompletion (
  809. PUSB_TRANSFER Transfer
  810. )
  811. /*++
  812. Routine Description:
  813. This routine is called when an asynchronous I/O request completes with
  814. success, failure, or is cancelled.
  815. Arguments:
  816. Transfer - Supplies a pointer to the transfer that completed.
  817. Return Value:
  818. None.
  819. --*/
  820. {
  821. PSM95_BULK_OUT_TRANSFER Sm95Transfer;
  822. Sm95Transfer = Transfer->UserData;
  823. RtlAtomicAdd32(&(Sm95Transfer->Device->BulkOutTransferCount), -1);
  824. NetFreeBuffer(Sm95Transfer->Packet);
  825. Sm95Transfer->Packet = NULL;
  826. Sm95pFreeBulkOutTransfer(Sm95Transfer);
  827. return;
  828. }
  829. KSTATUS
  830. Sm95pEnableMac (
  831. PSM95_DEVICE Device
  832. )
  833. /*++
  834. Routine Description:
  835. This routine enables transmitting and receiving of data from the wild.
  836. Arguments:
  837. Device - Supplies a pointer to the device.
  838. Return Value:
  839. Status code.
  840. --*/
  841. {
  842. KSTATUS Status;
  843. //
  844. // Disable multicast for now.
  845. //
  846. Device->MacControl &= ~(SM95_MAC_CONTROL_PRMS |
  847. SM95_MAC_CONTROL_MULTICAST_PAS |
  848. SM95_MAC_CONTROL_HP_FILTER |
  849. SM95_MAC_CONTROL_RECEIVE_OWN);
  850. //
  851. // Enable transmit and receive at the MAC.
  852. //
  853. Device->MacControl |= SM95_MAC_CONTROL_FULL_DUPLEX|
  854. SM95_MAC_CONTROL_ENABLE_TRANSMIT |
  855. SM95_MAC_CONTROL_ENABLE_RECEIVE;
  856. Status = Sm95pWriteRegister(Device,
  857. Sm95RegisterMacControl,
  858. Device->MacControl);
  859. if (!KSUCCESS(Status)) {
  860. return Status;
  861. }
  862. //
  863. // Enable transmit at the SCSRs.
  864. //
  865. Status = Sm95pWriteRegister(Device,
  866. Sm95RegisterTransmitControl,
  867. SM95_TRANSMIT_CONTROL_ENABLE);
  868. return Status;
  869. }
  870. KSTATUS
  871. Sm95pSetupChecksumOffloading (
  872. PSM95_DEVICE Device,
  873. BOOL EnableTransmitChecksumOffload,
  874. BOOL EnableReceiveChecksumOffload
  875. )
  876. /*++
  877. Routine Description:
  878. This routine enables or disables the checksum offload engines for transmit
  879. and receive packets.
  880. Arguments:
  881. Device - Supplies a pointer to the device.
  882. EnableTransmitChecksumOffload - Supplies a boolean indicating whether or
  883. not checksum offloading should be enabled for outgoing packets.
  884. EnableReceiveChecksumOffload - Supplies a boolean indicating whether or not
  885. checksum offloading should be enabled for incoming packets.
  886. Return Value:
  887. Status code.
  888. --*/
  889. {
  890. KSTATUS Status;
  891. ULONG Value;
  892. Status = Sm95pReadRegister(Device,
  893. Sm95RegisterChecksumOffloadControl,
  894. &Value);
  895. if (!KSUCCESS(Status)) {
  896. return Status;
  897. }
  898. Value &= ~(SM95_CHECKSUM_CONTROL_TRANSMIT_ENABLE |
  899. SM95_CHECKSUM_CONTROL_RECEIVE_ENABLE);
  900. if (EnableTransmitChecksumOffload != FALSE) {
  901. Value |= SM95_CHECKSUM_CONTROL_TRANSMIT_ENABLE;
  902. }
  903. if (EnableReceiveChecksumOffload != FALSE) {
  904. Value |= SM95_CHECKSUM_CONTROL_RECEIVE_ENABLE;
  905. }
  906. Status = Sm95pWriteRegister(Device,
  907. Sm95RegisterChecksumOffloadControl,
  908. Value);
  909. if (!KSUCCESS(Status)) {
  910. return Status;
  911. }
  912. return Status;
  913. }
  914. KSTATUS
  915. Sm95pSetMacAddress (
  916. PSM95_DEVICE Device,
  917. BYTE Address[ETHERNET_ADDRESS_SIZE]
  918. )
  919. /*++
  920. Routine Description:
  921. This routine sets the individual physical address for the given device.
  922. Arguments:
  923. Device - Supplies a pointer to the device.
  924. Address - Supplies the new address to set.
  925. Return Value:
  926. Status code.
  927. --*/
  928. {
  929. ULONG AddressHigh;
  930. ULONG AddressLow;
  931. KSTATUS Status;
  932. RtlCopyMemory(&AddressLow, Address, sizeof(ULONG));
  933. AddressHigh = 0;
  934. RtlCopyMemory(&AddressHigh, &(Address[sizeof(ULONG)]), sizeof(USHORT));
  935. Status = Sm95pWriteRegister(Device, Sm95RegisterMacAddressLow, AddressLow);
  936. if (!KSUCCESS(Status)) {
  937. return Status;
  938. }
  939. Status = Sm95pWriteRegister(Device,
  940. Sm95RegisterMacAddressHigh,
  941. AddressHigh);
  942. if (!KSUCCESS(Status)) {
  943. return Status;
  944. }
  945. return STATUS_SUCCESS;
  946. }
  947. KSTATUS
  948. Sm95pReadMacAddress (
  949. PSM95_DEVICE Device
  950. )
  951. /*++
  952. Routine Description:
  953. This routine reads the MAC address out of the EEPROM on the SMSC95xx. The
  954. MAC address will be stored in the device structure.
  955. Arguments:
  956. Device - Supplies a pointer to the device.
  957. Return Value:
  958. Status code.
  959. --*/
  960. {
  961. KSTATUS Status;
  962. Status = Sm95pReadEeprom(Device,
  963. SM95_EEPROM_MAC_ADDRESS,
  964. sizeof(Device->MacAddress),
  965. Device->MacAddress);
  966. if (!KSUCCESS(Status)) {
  967. return Status;
  968. }
  969. if (NetIsEthernetAddressValid(Device->MacAddress) == FALSE) {
  970. return STATUS_INVALID_ADDRESS;
  971. }
  972. return STATUS_SUCCESS;
  973. }
  974. KSTATUS
  975. Sm95pInitializePhy (
  976. PSM95_DEVICE Device
  977. )
  978. /*++
  979. Routine Description:
  980. This routine initializes the PHY on the SMSC95xx.
  981. Arguments:
  982. Device - Supplies a pointer to the device.
  983. Return Value:
  984. Status code.
  985. --*/
  986. {
  987. KSTATUS Status;
  988. ULONG Value;
  989. Status = Sm95pWriteMdio(Device,
  990. Device->PhyId,
  991. MiiRegisterBasicControl,
  992. MII_BASIC_CONTROL_RESET);
  993. if (!KSUCCESS(Status)) {
  994. return Status;
  995. }
  996. //
  997. // Wait for the reset to complete.
  998. //
  999. do {
  1000. Status = Sm95pReadMdio(Device,
  1001. Device->PhyId,
  1002. MiiRegisterBasicControl,
  1003. &Value);
  1004. if (!KSUCCESS(Status)) {
  1005. return Status;
  1006. }
  1007. } while ((Value & MII_BASIC_CONTROL_RESET) != 0);
  1008. //
  1009. // Advertise all modes and pause capabilities.
  1010. //
  1011. Value = MII_ADVERTISE_ALL | MII_ADVERTISE_CSMA | MII_ADVERTISE_PAUSE |
  1012. MII_ADVERTISE_PAUSE_ASYMMETRIC;
  1013. Status = Sm95pWriteMdio(Device, Device->PhyId, MiiRegisterAdvertise, Value);
  1014. if (!KSUCCESS(Status)) {
  1015. return Status;
  1016. }
  1017. //
  1018. // Read the interrupt status register to clear the bits.
  1019. //
  1020. Status = Sm95pReadMdio(Device,
  1021. Device->PhyId,
  1022. Sm95PhyRegisterInterruptSource,
  1023. &Value);
  1024. if (!KSUCCESS(Status)) {
  1025. return Status;
  1026. }
  1027. //
  1028. // Write the interrupt mask.
  1029. //
  1030. Value = SM95_PHY_INTERRUPT_AUTONEGOTIATION_COMPLETE |
  1031. SM95_PHY_INTERRUPT_LINK_DOWN;
  1032. Status = Sm95pWriteMdio(Device,
  1033. Device->PhyId,
  1034. Sm95PhyRegisterInterruptMask,
  1035. Value);
  1036. if (!KSUCCESS(Status)) {
  1037. return Status;
  1038. }
  1039. //
  1040. // Restart auto-negotiation.
  1041. //
  1042. Status = Sm95pReadMdio(Device,
  1043. Device->PhyId,
  1044. MiiRegisterBasicControl,
  1045. &Value);
  1046. if (!KSUCCESS(Status)) {
  1047. return Status;
  1048. }
  1049. Value |= MII_BASIC_CONTROL_RESTART_AUTONEGOTIATION;
  1050. Status = Sm95pWriteMdio(Device,
  1051. Device->PhyId,
  1052. MiiRegisterBasicControl,
  1053. Value);
  1054. if (!KSUCCESS(Status)) {
  1055. return Status;
  1056. }
  1057. return Status;
  1058. }
  1059. KSTATUS
  1060. Sm95pRestartNway (
  1061. PSM95_DEVICE Device
  1062. )
  1063. /*++
  1064. Routine Description:
  1065. This routine restarts N-Way (autonegotiation) for the device.
  1066. Arguments:
  1067. Device - Supplies a pointer to the device.
  1068. Return Value:
  1069. Status code.
  1070. --*/
  1071. {
  1072. KSTATUS Status;
  1073. ULONG Value;
  1074. //
  1075. // Read the control register, and restart autonegotiation if it's enabled.
  1076. //
  1077. Status = Sm95pReadMdio(Device,
  1078. Device->PhyId,
  1079. MiiRegisterBasicControl,
  1080. &Value);
  1081. if (!KSUCCESS(Status)) {
  1082. return Status;
  1083. }
  1084. if ((Value & MII_BASIC_CONTROL_ENABLE_AUTONEGOTIATION) != 0) {
  1085. Value |= MII_BASIC_CONTROL_RESTART_AUTONEGOTIATION;
  1086. Status = Sm95pWriteMdio(Device,
  1087. Device->PhyId,
  1088. MiiRegisterBasicControl,
  1089. Value);
  1090. } else {
  1091. Status = STATUS_INVALID_CONFIGURATION;
  1092. }
  1093. return Status;
  1094. }
  1095. KSTATUS
  1096. Sm95pReadEeprom (
  1097. PSM95_DEVICE Device,
  1098. ULONG Offset,
  1099. ULONG Length,
  1100. PBYTE Data
  1101. )
  1102. /*++
  1103. Routine Description:
  1104. This routine reads from the EEPROM on the SMSC95xx device.
  1105. Arguments:
  1106. Device - Supplies a pointer to the device.
  1107. Offset - Supplies the offset in bytes from the beginning of the EEPROM to
  1108. read from.
  1109. Length - Supplies the number of bytes to read.
  1110. Data - Supplies a pointer where the EEPROM data will be returned on success.
  1111. Return Value:
  1112. Status code.
  1113. --*/
  1114. {
  1115. ULONG ByteIndex;
  1116. ULONG Command;
  1117. KSTATUS Status;
  1118. ULONG Value;
  1119. Status = Sm95pWaitForEeprom(Device, FALSE);
  1120. if (!KSUCCESS(Status)) {
  1121. return Status;
  1122. }
  1123. //
  1124. // Read bytes from the EEPROM one at a time.
  1125. //
  1126. for (ByteIndex = 0; ByteIndex < Length; ByteIndex += 1) {
  1127. //
  1128. // Set up the command register to read the EEPROM at the specified
  1129. // offset.
  1130. //
  1131. ASSERT(Offset + ByteIndex <= SM95_EEPROM_COMMAND_ADDRESS_MASK);
  1132. Command = SM95_EEPROM_COMMAND_BUSY |
  1133. ((Offset + ByteIndex) & SM95_EEPROM_COMMAND_ADDRESS_MASK);
  1134. Status = Sm95pWriteRegister(Device, Sm95RegisterEepromCommand, Command);
  1135. if (!KSUCCESS(Status)) {
  1136. return Status;
  1137. }
  1138. //
  1139. // Wait for the EEPROM to accept the command.
  1140. //
  1141. Status = Sm95pWaitForEeprom(Device, TRUE);
  1142. if (!KSUCCESS(Status)) {
  1143. return Status;
  1144. }
  1145. //
  1146. // Read the spoils out of the data register.
  1147. //
  1148. Status = Sm95pReadRegister(Device, Sm95RegisterEepromData, &Value);
  1149. if (!KSUCCESS(Status)) {
  1150. return Status;
  1151. }
  1152. Data[ByteIndex] = (BYTE)Value;
  1153. }
  1154. return STATUS_SUCCESS;
  1155. }
  1156. KSTATUS
  1157. Sm95pWaitForEeprom (
  1158. PSM95_DEVICE Device,
  1159. BOOL ObserveEepromTimeout
  1160. )
  1161. /*++
  1162. Routine Description:
  1163. This routine waits for the EEPROM to finish or time out.
  1164. Arguments:
  1165. Device - Supplies a pointer to the device.
  1166. ObserveEepromTimeout - Supplies a boolean indicating if the EEPROM timeout
  1167. bit should be checked as well as the busy bit (TRUE) or if only the
  1168. busy bit should be waited on (FALSE).
  1169. Return Value:
  1170. Status code.
  1171. --*/
  1172. {
  1173. KSTATUS Status;
  1174. ULONGLONG Timeout;
  1175. ULONG Value;
  1176. Timeout = KeGetRecentTimeCounter() +
  1177. (HlQueryTimeCounterFrequency() * SM95_EEPROM_TIMEOUT);
  1178. do {
  1179. Status = Sm95pReadRegister(Device, Sm95RegisterEepromCommand, &Value);
  1180. if (!KSUCCESS(Status)) {
  1181. return Status;
  1182. }
  1183. if ((ObserveEepromTimeout != FALSE) &&
  1184. ((Value & SM95_EEPROM_COMMAND_TIMEOUT) != 0)) {
  1185. break;
  1186. }
  1187. if ((Value & SM95_EEPROM_COMMAND_BUSY) == 0) {
  1188. return STATUS_SUCCESS;
  1189. }
  1190. } while (KeGetRecentTimeCounter() <= Timeout);
  1191. return STATUS_TIMEOUT;
  1192. }
  1193. KSTATUS
  1194. Sm95pWriteMdio (
  1195. PSM95_DEVICE Device,
  1196. USHORT PhyId,
  1197. USHORT Index,
  1198. ULONG Data
  1199. )
  1200. /*++
  1201. Routine Description:
  1202. This routine performs an MDIO register write.
  1203. Arguments:
  1204. Device - Supplies a pointer to the device.
  1205. PhyId - Supplies the device ID to write to.
  1206. Index - Supplies the register to write.
  1207. Data - Supplies the value to write.
  1208. Return Value:
  1209. Status code.
  1210. --*/
  1211. {
  1212. ULONG Address;
  1213. KSTATUS Status;
  1214. Status = Sm95pWaitForPhy(Device);
  1215. if (!KSUCCESS(Status)) {
  1216. return Status;
  1217. }
  1218. //
  1219. // Write the data contents first.
  1220. //
  1221. Status = Sm95pWriteRegister(Device, Sm95RegisterMiiData, Data);
  1222. if (!KSUCCESS(Status)) {
  1223. return Status;
  1224. }
  1225. //
  1226. // Write the address into the address register to execute the write.
  1227. //
  1228. Address = (PhyId << SM95_MII_ADDRESS_PHY_ID_SHIFT) |
  1229. (Index << SM95_MII_ADDRESS_INDEX_SHIFT) |
  1230. SM95_MII_ADDRESS_WRITE;
  1231. Status = Sm95pWriteRegister(Device, Sm95RegisterMiiAddress, Address);
  1232. if (!KSUCCESS(Status)) {
  1233. return Status;
  1234. }
  1235. return Status;
  1236. }
  1237. KSTATUS
  1238. Sm95pReadMdio (
  1239. PSM95_DEVICE Device,
  1240. USHORT PhyId,
  1241. USHORT Index,
  1242. PULONG Data
  1243. )
  1244. /*++
  1245. Routine Description:
  1246. This routine performs an MDIO register read.
  1247. Arguments:
  1248. Device - Supplies a pointer to the device.
  1249. PhyId - Supplies the device ID to read from.
  1250. Index - Supplies the register to read.
  1251. Data - Supplies a pointer where the register contents will be returned on
  1252. success.
  1253. Return Value:
  1254. Status code.
  1255. --*/
  1256. {
  1257. ULONG Address;
  1258. KSTATUS Status;
  1259. ULONG Value;
  1260. Status = Sm95pWaitForPhy(Device);
  1261. if (!KSUCCESS(Status)) {
  1262. return Status;
  1263. }
  1264. //
  1265. // Write the address into the address register.
  1266. //
  1267. Address = (PhyId << SM95_MII_ADDRESS_PHY_ID_SHIFT) |
  1268. (Index << SM95_MII_ADDRESS_INDEX_SHIFT);
  1269. Status = Sm95pWriteRegister(Device, Sm95RegisterMiiAddress, Address);
  1270. if (!KSUCCESS(Status)) {
  1271. return Status;
  1272. }
  1273. Status = Sm95pWaitForPhy(Device);
  1274. if (!KSUCCESS(Status)) {
  1275. return Status;
  1276. }
  1277. //
  1278. // Read the requested data out of the data register.
  1279. //
  1280. Status = Sm95pReadRegister(Device, Sm95RegisterMiiData, &Value);
  1281. if (!KSUCCESS(Status)) {
  1282. return Status;
  1283. }
  1284. *Data = Value & 0x0000FFFF;
  1285. return Status;
  1286. }
  1287. KSTATUS
  1288. Sm95pWaitForPhy (
  1289. PSM95_DEVICE Device
  1290. )
  1291. /*++
  1292. Routine Description:
  1293. This routine waits until the PHY is not busy.
  1294. Arguments:
  1295. Device - Supplies a pointer to the device.
  1296. Return Value:
  1297. Status code.
  1298. --*/
  1299. {
  1300. KSTATUS Status;
  1301. ULONGLONG Timeout;
  1302. ULONG Value;
  1303. Timeout = KeGetRecentTimeCounter() +
  1304. (HlQueryTimeCounterFrequency() * SM95_DEVICE_TIMEOUT);
  1305. do {
  1306. Status = Sm95pReadRegister(Device, Sm95RegisterMiiAddress, &Value);
  1307. if (!KSUCCESS(Status)) {
  1308. return Status;
  1309. }
  1310. if ((Value & SM95_MII_ADDRESS_BUSY) == 0) {
  1311. return STATUS_SUCCESS;
  1312. }
  1313. } while (KeGetRecentTimeCounter() <= Timeout);
  1314. return STATUS_TIMEOUT;
  1315. }
  1316. KSTATUS
  1317. Sm95pWriteRegister (
  1318. PSM95_DEVICE Device,
  1319. USHORT Register,
  1320. ULONG Data
  1321. )
  1322. /*++
  1323. Routine Description:
  1324. This routine performs a register write to the SMSC95xx device.
  1325. Arguments:
  1326. Device - Supplies a pointer to the device.
  1327. Register - Supplies the register number to write to.
  1328. Data - Supplies the value to write.
  1329. Return Value:
  1330. Status code.
  1331. --*/
  1332. {
  1333. PUSB_TRANSFER ControlTransfer;
  1334. PUSB_SETUP_PACKET Setup;
  1335. KSTATUS Status;
  1336. ControlTransfer = Device->ControlTransfer;
  1337. Setup = ControlTransfer->Buffer;
  1338. Setup->RequestType = USB_SETUP_REQUEST_TO_DEVICE |
  1339. USB_SETUP_REQUEST_VENDOR |
  1340. USB_SETUP_REQUEST_DEVICE_RECIPIENT;
  1341. Setup->Request = SM95_VENDOR_REQUEST_WRITE_REGISTER;
  1342. Setup->Value = 0;
  1343. Setup->Index = Register;
  1344. Setup->Length = sizeof(ULONG);
  1345. RtlCopyMemory(Setup + 1, &Data, sizeof(ULONG));
  1346. ControlTransfer->Direction = UsbTransferDirectionOut;
  1347. ControlTransfer->Length = sizeof(USB_SETUP_PACKET) + sizeof(ULONG);
  1348. Status = UsbSubmitSynchronousTransfer(ControlTransfer);
  1349. return Status;
  1350. }
  1351. KSTATUS
  1352. Sm95pReadRegister (
  1353. PSM95_DEVICE Device,
  1354. USHORT Register,
  1355. PULONG Data
  1356. )
  1357. /*++
  1358. Routine Description:
  1359. This routine performs a register read from the SMSC95xx device.
  1360. Arguments:
  1361. Device - Supplies a pointer to the device.
  1362. Register - Supplies the register number to read from.
  1363. Data - Supplies a pointer where the register contents will be returned on
  1364. success.
  1365. Return Value:
  1366. Status code.
  1367. --*/
  1368. {
  1369. PUSB_TRANSFER ControlTransfer;
  1370. PUSB_SETUP_PACKET Setup;
  1371. KSTATUS Status;
  1372. ControlTransfer = Device->ControlTransfer;
  1373. Setup = ControlTransfer->Buffer;
  1374. Setup->RequestType = USB_SETUP_REQUEST_TO_HOST |
  1375. USB_SETUP_REQUEST_VENDOR |
  1376. USB_SETUP_REQUEST_DEVICE_RECIPIENT;
  1377. Setup->Request = SM95_VENDOR_REQUEST_READ_REGISTER;
  1378. Setup->Value = 0;
  1379. Setup->Index = Register;
  1380. Setup->Length = sizeof(ULONG);
  1381. ControlTransfer->Direction = UsbTransferDirectionIn;
  1382. ControlTransfer->Length = sizeof(USB_SETUP_PACKET) + sizeof(ULONG);
  1383. Status = UsbSubmitSynchronousTransfer(ControlTransfer);
  1384. if (!KSUCCESS(Status)) {
  1385. return Status;
  1386. }
  1387. RtlCopyMemory(Data, Setup + 1, sizeof(ULONG));
  1388. return Status;
  1389. }
  1390. KSTATUS
  1391. Sm95pSubmitBulkInTransfers (
  1392. PSM95_DEVICE Device
  1393. )
  1394. /*++
  1395. Routine Description:
  1396. This routine submits all the bulk IN transfers allocated for the device.
  1397. Arguments:
  1398. Device - Supplies a pointer to an SM95 device.
  1399. Return Value:
  1400. Status code.
  1401. --*/
  1402. {
  1403. ULONG Index;
  1404. KSTATUS Status;
  1405. for (Index = 0; Index < SM95_BULK_IN_TRANSFER_COUNT; Index += 1) {
  1406. Status = UsbSubmitTransfer(Device->BulkInTransfer[Index]);
  1407. if (!KSUCCESS(Status)) {
  1408. break;
  1409. }
  1410. }
  1411. return Status;
  1412. }
  1413. VOID
  1414. Sm95pCancelBulkInTransfers (
  1415. PSM95_DEVICE Device
  1416. )
  1417. /*++
  1418. Routine Description:
  1419. This routine attempts to cancel all the bulk IN transfers for the device.
  1420. Arguments:
  1421. Device - Supplies a pointer to an SM95 device.
  1422. Return Value:
  1423. None.
  1424. --*/
  1425. {
  1426. ULONG Index;
  1427. for (Index = 0; Index < SM95_BULK_IN_TRANSFER_COUNT; Index += 1) {
  1428. UsbCancelTransfer(Device->BulkInTransfer[Index], FALSE);
  1429. }
  1430. return;
  1431. }
  1432. PSM95_BULK_OUT_TRANSFER
  1433. Sm95pAllocateBulkOutTransfer (
  1434. PSM95_DEVICE Device
  1435. )
  1436. /*++
  1437. Routine Description:
  1438. This routine allocates an SM95 bulk OUT transfer. If there are no free bulk
  1439. OUT transfers ready to go, it will create a new transfer.
  1440. Arguments:
  1441. Device - Supplies a pointer to the SM95 device in need of a new transfer.
  1442. Return Value:
  1443. Returns a pointer to the allocated SM95 bulk OUT transfer on success or
  1444. NULL on failure.
  1445. --*/
  1446. {
  1447. PSM95_BULK_OUT_TRANSFER Sm95Transfer;
  1448. PUSB_TRANSFER UsbTransfer;
  1449. ASSERT(KeGetRunLevel() == RunLevelLow);
  1450. //
  1451. // Loop attempting to use the most recently released existing transfer, but
  1452. // allocate a new transfer if none are available.
  1453. //
  1454. Sm95Transfer = NULL;
  1455. while (Sm95Transfer == NULL) {
  1456. if (LIST_EMPTY(&(Device->BulkOutFreeTransferList)) != FALSE) {
  1457. Sm95Transfer = MmAllocatePagedPool(sizeof(SM95_BULK_OUT_TRANSFER),
  1458. SM95_ALLOCATION_TAG);
  1459. if (Sm95Transfer == NULL) {
  1460. goto AllocateBulkOutTransferEnd;
  1461. }
  1462. UsbTransfer = UsbAllocateTransfer(Device->UsbCoreHandle,
  1463. Device->BulkOutEndpoint,
  1464. SM95_MAX_PACKET_SIZE,
  1465. 0);
  1466. if (UsbTransfer == NULL) {
  1467. MmFreePagedPool(Sm95Transfer);
  1468. Sm95Transfer = NULL;
  1469. goto AllocateBulkOutTransferEnd;
  1470. }
  1471. UsbTransfer->Direction = UsbTransferDirectionOut;
  1472. UsbTransfer->CallbackRoutine = Sm95pTransmitPacketCompletion;
  1473. UsbTransfer->UserData = Sm95Transfer;
  1474. Sm95Transfer->Device = Device;
  1475. Sm95Transfer->UsbTransfer = UsbTransfer;
  1476. Sm95Transfer->Packet = NULL;
  1477. } else {
  1478. KeAcquireQueuedLock(Device->BulkOutListLock);
  1479. if (LIST_EMPTY(&(Device->BulkOutFreeTransferList)) == FALSE) {
  1480. Sm95Transfer = LIST_VALUE(Device->BulkOutFreeTransferList.Next,
  1481. SM95_BULK_OUT_TRANSFER,
  1482. ListEntry);
  1483. LIST_REMOVE(&(Sm95Transfer->ListEntry));
  1484. }
  1485. KeReleaseQueuedLock(Device->BulkOutListLock);
  1486. }
  1487. }
  1488. AllocateBulkOutTransferEnd:
  1489. return Sm95Transfer;
  1490. }
  1491. VOID
  1492. Sm95pFreeBulkOutTransfer (
  1493. PSM95_BULK_OUT_TRANSFER Transfer
  1494. )
  1495. /*++
  1496. Routine Description:
  1497. This routine releases an SM95 bulk OUT transfer for recycling.
  1498. Arguments:
  1499. Transfer - Supplies a pointer to the SM95 transfer to be recycled.
  1500. Return Value:
  1501. None.
  1502. --*/
  1503. {
  1504. PSM95_DEVICE Device;
  1505. ASSERT(KeGetRunLevel() == RunLevelLow);
  1506. //
  1507. // Insert it onto the head of the list so it stays hot.
  1508. //
  1509. Device = Transfer->Device;
  1510. KeAcquireQueuedLock(Device->BulkOutListLock);
  1511. INSERT_AFTER(&(Transfer->ListEntry), &(Device->BulkOutFreeTransferList));
  1512. KeReleaseQueuedLock(Device->BulkOutListLock);
  1513. return;
  1514. }