smsc95.c 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180
  1. /*++
  2. Copyright (c) 2013 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. smsc95.c
  5. Abstract:
  6. This module implements support for the driver portion of the SMSC95xx
  7. family of USB 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. // ------------------------------------------------------ Data Type Definitions
  25. //
  26. //
  27. // ----------------------------------------------- Internal Function Prototypes
  28. //
  29. KSTATUS
  30. Sm95AddDevice (
  31. PVOID Driver,
  32. PSTR DeviceId,
  33. PSTR ClassId,
  34. PSTR CompatibleIds,
  35. PVOID DeviceToken
  36. );
  37. VOID
  38. Sm95DispatchStateChange (
  39. PIRP Irp,
  40. PVOID DeviceContext,
  41. PVOID IrpContext
  42. );
  43. VOID
  44. Sm95DispatchOpen (
  45. PIRP Irp,
  46. PVOID DeviceContext,
  47. PVOID IrpContext
  48. );
  49. VOID
  50. Sm95DispatchClose (
  51. PIRP Irp,
  52. PVOID DeviceContext,
  53. PVOID IrpContext
  54. );
  55. VOID
  56. Sm95DispatchIo (
  57. PIRP Irp,
  58. PVOID DeviceContext,
  59. PVOID IrpContext
  60. );
  61. VOID
  62. Sm95DispatchSystemControl (
  63. PIRP Irp,
  64. PVOID DeviceContext,
  65. PVOID IrpContext
  66. );
  67. VOID
  68. Sm95DestroyLink (
  69. PVOID DeviceContext
  70. );
  71. KSTATUS
  72. Sm95pInitializeDeviceStructures (
  73. PVOID OsDevice,
  74. PSM95_DEVICE *NewDevice
  75. );
  76. VOID
  77. Sm95pDestroyDeviceStructures (
  78. PSM95_DEVICE Device
  79. );
  80. VOID
  81. Sm95pDeviceAddReference (
  82. PSM95_DEVICE Device
  83. );
  84. VOID
  85. Sm95pDeviceReleaseReference (
  86. PSM95_DEVICE Device
  87. );
  88. KSTATUS
  89. Sm95pSetUpUsbDevice (
  90. PSM95_DEVICE Device
  91. );
  92. KSTATUS
  93. Sm95pStartDevice (
  94. PIRP Irp,
  95. PSM95_DEVICE Device
  96. );
  97. KSTATUS
  98. Sm95pStopDevice (
  99. PIRP Irp,
  100. PSM95_DEVICE Device
  101. );
  102. //
  103. // -------------------------------------------------------------------- Globals
  104. //
  105. PDRIVER Sm95Driver = NULL;
  106. //
  107. // ------------------------------------------------------------------ Functions
  108. //
  109. KSTATUS
  110. DriverEntry (
  111. PDRIVER Driver
  112. )
  113. /*++
  114. Routine Description:
  115. This routine is the entry point for the SMSC95xx driver. It registers its
  116. other dispatch functions, and performs driver-wide initialization.
  117. Arguments:
  118. Driver - Supplies a pointer to the driver object.
  119. Return Value:
  120. STATUS_SUCCESS on success.
  121. Failure code on error.
  122. --*/
  123. {
  124. DRIVER_FUNCTION_TABLE FunctionTable;
  125. KSTATUS Status;
  126. Sm95Driver = Driver;
  127. RtlZeroMemory(&FunctionTable, sizeof(DRIVER_FUNCTION_TABLE));
  128. FunctionTable.Version = DRIVER_FUNCTION_TABLE_VERSION;
  129. FunctionTable.AddDevice = Sm95AddDevice;
  130. FunctionTable.DispatchStateChange = Sm95DispatchStateChange;
  131. FunctionTable.DispatchOpen = Sm95DispatchOpen;
  132. FunctionTable.DispatchClose = Sm95DispatchClose;
  133. FunctionTable.DispatchIo = Sm95DispatchIo;
  134. FunctionTable.DispatchSystemControl = Sm95DispatchSystemControl;
  135. Status = IoRegisterDriverFunctions(Driver, &FunctionTable);
  136. return Status;
  137. }
  138. KSTATUS
  139. Sm95AddDevice (
  140. PVOID Driver,
  141. PSTR DeviceId,
  142. PSTR ClassId,
  143. PSTR CompatibleIds,
  144. PVOID DeviceToken
  145. )
  146. /*++
  147. Routine Description:
  148. This routine is called when a device is detected for which the SMSC95xx
  149. driver acts as the function driver. The driver will attach itself to the
  150. stack.
  151. Arguments:
  152. Driver - Supplies a pointer to the driver being called.
  153. DeviceId - Supplies a pointer to a string with the device ID.
  154. ClassId - Supplies a pointer to a string containing the device's class ID.
  155. CompatibleIds - Supplies a pointer to a string containing device IDs
  156. that would be compatible with this device.
  157. DeviceToken - Supplies an opaque token that the driver can use to identify
  158. the device in the system. This token should be used when attaching to
  159. the stack.
  160. Return Value:
  161. STATUS_SUCCESS on success.
  162. Failure code if the driver was unsuccessful in attaching itself.
  163. --*/
  164. {
  165. PSM95_DEVICE Device;
  166. KSTATUS Status;
  167. Status = Sm95pInitializeDeviceStructures(DeviceToken, &Device);
  168. if (!KSUCCESS(Status)) {
  169. goto AddDeviceEnd;
  170. }
  171. Status = IoAttachDriverToDevice(Driver, DeviceToken, Device);
  172. if (!KSUCCESS(Status)) {
  173. goto AddDeviceEnd;
  174. }
  175. AddDeviceEnd:
  176. if (!KSUCCESS(Status)) {
  177. if (Device != NULL) {
  178. Sm95pDeviceReleaseReference(Device);
  179. }
  180. }
  181. return Status;
  182. }
  183. VOID
  184. Sm95DispatchStateChange (
  185. PIRP Irp,
  186. PVOID DeviceContext,
  187. PVOID IrpContext
  188. )
  189. /*++
  190. Routine Description:
  191. This routine handles State Change IRPs.
  192. Arguments:
  193. Irp - Supplies a pointer to the I/O request packet.
  194. DeviceContext - Supplies the context pointer supplied by the driver when it
  195. attached itself to the driver stack. Presumably this pointer contains
  196. driver-specific device context.
  197. IrpContext - Supplies the context pointer supplied by the driver when
  198. the IRP was created.
  199. Return Value:
  200. None.
  201. --*/
  202. {
  203. KSTATUS Status;
  204. ASSERT(Irp->MajorCode == IrpMajorStateChange);
  205. if (Irp->Direction == IrpUp) {
  206. switch (Irp->MinorCode) {
  207. case IrpMinorQueryResources:
  208. case IrpMinorQueryChildren:
  209. IoCompleteIrp(Sm95Driver, Irp, STATUS_SUCCESS);
  210. break;
  211. case IrpMinorStartDevice:
  212. Status = Sm95pStartDevice(Irp, DeviceContext);
  213. if (!KSUCCESS(Status)) {
  214. IoCompleteIrp(Sm95Driver, Irp, Status);
  215. }
  216. break;
  217. case IrpMinorRemoveDevice:
  218. Status = Sm95pStopDevice(Irp, DeviceContext);
  219. if (!KSUCCESS(Status)) {
  220. IoCompleteIrp(Sm95Driver, Irp, Status);
  221. break;
  222. }
  223. break;
  224. default:
  225. break;
  226. }
  227. }
  228. return;
  229. }
  230. VOID
  231. Sm95DispatchOpen (
  232. PIRP Irp,
  233. PVOID DeviceContext,
  234. PVOID IrpContext
  235. )
  236. /*++
  237. Routine Description:
  238. This routine handles Open IRPs.
  239. Arguments:
  240. Irp - Supplies a pointer to the I/O request packet.
  241. DeviceContext - Supplies the context pointer supplied by the driver when it
  242. attached itself to the driver stack. Presumably this pointer contains
  243. driver-specific device context.
  244. IrpContext - Supplies the context pointer supplied by the driver when
  245. the IRP was created.
  246. Return Value:
  247. None.
  248. --*/
  249. {
  250. return;
  251. }
  252. VOID
  253. Sm95DispatchClose (
  254. PIRP Irp,
  255. PVOID DeviceContext,
  256. PVOID IrpContext
  257. )
  258. /*++
  259. Routine Description:
  260. This routine handles Close IRPs.
  261. Arguments:
  262. Irp - Supplies a pointer to the I/O request packet.
  263. DeviceContext - Supplies the context pointer supplied by the driver when it
  264. attached itself to the driver stack. Presumably this pointer contains
  265. driver-specific device context.
  266. IrpContext - Supplies the context pointer supplied by the driver when
  267. the IRP was created.
  268. Return Value:
  269. None.
  270. --*/
  271. {
  272. return;
  273. }
  274. VOID
  275. Sm95DispatchIo (
  276. PIRP Irp,
  277. PVOID DeviceContext,
  278. PVOID IrpContext
  279. )
  280. /*++
  281. Routine Description:
  282. This routine handles I/O IRPs.
  283. Arguments:
  284. Irp - Supplies a pointer to the I/O request packet.
  285. DeviceContext - Supplies the context pointer supplied by the driver when it
  286. attached itself to the driver stack. Presumably this pointer contains
  287. driver-specific device context.
  288. IrpContext - Supplies the context pointer supplied by the driver when
  289. the IRP was created.
  290. Return Value:
  291. None.
  292. --*/
  293. {
  294. return;
  295. }
  296. VOID
  297. Sm95DispatchSystemControl (
  298. PIRP Irp,
  299. PVOID DeviceContext,
  300. PVOID IrpContext
  301. )
  302. /*++
  303. Routine Description:
  304. This routine handles System Control IRPs.
  305. Arguments:
  306. Irp - Supplies a pointer to the I/O request packet.
  307. DeviceContext - Supplies the context pointer supplied by the driver when it
  308. attached itself to the driver stack. Presumably this pointer contains
  309. driver-specific device context.
  310. IrpContext - Supplies the context pointer supplied by the driver when
  311. the IRP was created.
  312. Return Value:
  313. None.
  314. --*/
  315. {
  316. PSM95_DEVICE Device;
  317. PSYSTEM_CONTROL_DEVICE_INFORMATION DeviceInformationRequest;
  318. KSTATUS Status;
  319. ASSERT(Irp->MajorCode == IrpMajorSystemControl);
  320. Device = DeviceContext;
  321. if (Irp->Direction == IrpDown) {
  322. switch (Irp->MinorCode) {
  323. case IrpMinorSystemControlDeviceInformation:
  324. DeviceInformationRequest = Irp->U.SystemControl.SystemContext;
  325. Status = NetGetSetLinkDeviceInformation(
  326. Device->NetworkLink,
  327. &(DeviceInformationRequest->Uuid),
  328. DeviceInformationRequest->Data,
  329. &(DeviceInformationRequest->DataSize),
  330. DeviceInformationRequest->Set);
  331. IoCompleteIrp(Sm95Driver, Irp, Status);
  332. break;
  333. default:
  334. break;
  335. }
  336. }
  337. return;
  338. }
  339. KSTATUS
  340. Sm95pAddNetworkDevice (
  341. PSM95_DEVICE Device
  342. )
  343. /*++
  344. Routine Description:
  345. This routine adds the device to core networking's available links.
  346. Arguments:
  347. Device - Supplies a pointer to the device to add.
  348. Return Value:
  349. Status code.
  350. --*/
  351. {
  352. NET_LINK_PROPERTIES Properties;
  353. KSTATUS Status;
  354. if (Device->NetworkLink != NULL) {
  355. Status = STATUS_SUCCESS;
  356. goto AddNetworkDeviceEnd;
  357. }
  358. //
  359. // Add a link to the core networking library.
  360. //
  361. RtlZeroMemory(&Properties, sizeof(NET_LINK_PROPERTIES));
  362. Properties.Version = NET_LINK_PROPERTIES_VERSION;
  363. Properties.TransmitAlignment = MmGetIoBufferAlignment();
  364. Properties.Device = Device->OsDevice;
  365. Properties.DeviceContext = Device;
  366. Properties.PacketSizeInformation.MaxPacketSize = SM95_MAX_PACKET_SIZE;
  367. Properties.PacketSizeInformation.HeaderSize = SM95_TRANSMIT_HEADER_SIZE;
  368. Properties.DataLinkType = NetDomainEthernet;
  369. Properties.MaxPhysicalAddress = MAX_ULONG;
  370. Properties.PhysicalAddress.Domain = NetDomainEthernet;
  371. RtlCopyMemory(&(Properties.PhysicalAddress.Address),
  372. &(Device->MacAddress),
  373. sizeof(Device->MacAddress));
  374. Properties.Interface.Send = Sm95Send;
  375. Properties.Interface.GetSetInformation = Sm95GetSetInformation;
  376. Properties.Interface.DestroyLink = Sm95DestroyLink;
  377. Status = NetAddLink(&Properties, &(Device->NetworkLink));
  378. if (!KSUCCESS(Status)) {
  379. goto AddNetworkDeviceEnd;
  380. }
  381. //
  382. // The networking core now references the device structure. Add a
  383. // reference for it.
  384. //
  385. Sm95pDeviceAddReference(Device);
  386. AddNetworkDeviceEnd:
  387. if (!KSUCCESS(Status)) {
  388. if (Device->NetworkLink != NULL) {
  389. NetRemoveLink(Device->NetworkLink);
  390. Device->NetworkLink = NULL;
  391. }
  392. }
  393. return Status;
  394. }
  395. VOID
  396. Sm95DestroyLink (
  397. PVOID DeviceContext
  398. )
  399. /*++
  400. Routine Description:
  401. This routine notifies the device layer that the networking core is in the
  402. process of destroying the link and will no longer call into the device for
  403. this link. This allows the device layer to release any context that was
  404. supporting the device link interface.
  405. Arguments:
  406. DeviceContext - Supplies a pointer to the device context associated with
  407. the link being destroyed.
  408. Return Value:
  409. None.
  410. --*/
  411. {
  412. Sm95pDeviceReleaseReference(DeviceContext);
  413. return;
  414. }
  415. //
  416. // --------------------------------------------------------- Internal Functions
  417. //
  418. KSTATUS
  419. Sm95pInitializeDeviceStructures (
  420. PVOID OsDevice,
  421. PSM95_DEVICE *NewDevice
  422. )
  423. /*++
  424. Routine Description:
  425. This routine initializes an SMSC95xx device.
  426. Arguments:
  427. OsDevice - Supplies a pointer to the system token that represents this
  428. device.
  429. NewDevice - Supplies a pointer where the new structure will be returned.
  430. Return Value:
  431. Status code.
  432. --*/
  433. {
  434. ULONG BufferAlignment;
  435. PSM95_DEVICE Device;
  436. ULONG Index;
  437. ULONG IoBufferFlags;
  438. UINTN IoBufferSize;
  439. ULONG MaxControlSize;
  440. ULONG MaxHighSpeedBurstSize;
  441. ULONG MaxInterruptSize;
  442. PHYSICAL_ADDRESS PhysicalAddress;
  443. KSTATUS Status;
  444. PUSB_TRANSFER UsbTransfer;
  445. PVOID VirtualAddress;
  446. Device = MmAllocatePagedPool(sizeof(SM95_DEVICE), SM95_ALLOCATION_TAG);
  447. if (Device == NULL) {
  448. Status = STATUS_INSUFFICIENT_RESOURCES;
  449. goto InitializeDeviceStructuresEnd;
  450. }
  451. RtlZeroMemory(Device, sizeof(SM95_DEVICE));
  452. Device->OsDevice = OsDevice;
  453. Device->UsbCoreHandle = INVALID_HANDLE;
  454. Device->ReferenceCount = 1;
  455. INITIALIZE_LIST_HEAD(&(Device->BulkOutFreeTransferList));
  456. Device->BulkOutListLock = KeCreateQueuedLock();
  457. if (Device->BulkOutListLock == NULL) {
  458. Status = STATUS_INSUFFICIENT_RESOURCES;
  459. goto InitializeDeviceStructuresEnd;
  460. }
  461. //
  462. // Attempt to attach to the USB core.
  463. //
  464. Status = UsbDriverAttach(OsDevice, Sm95Driver, &(Device->UsbCoreHandle));
  465. if (!KSUCCESS(Status)) {
  466. goto InitializeDeviceStructuresEnd;
  467. }
  468. Status = Sm95pSetUpUsbDevice(Device);
  469. if (!KSUCCESS(Status)) {
  470. goto InitializeDeviceStructuresEnd;
  471. }
  472. //
  473. // Create an I/O buffer for the control and receive transfers.
  474. //
  475. BufferAlignment = MmGetIoBufferAlignment();
  476. MaxHighSpeedBurstSize = ALIGN_RANGE_UP(SM95_HIGH_SPEED_BURST_SIZE,
  477. BufferAlignment);
  478. MaxControlSize = ALIGN_RANGE_UP(SM95_MAX_CONTROL_TRANSFER_SIZE,
  479. BufferAlignment);
  480. MaxInterruptSize = ALIGN_RANGE_UP(SM95_MAX_INTERRUPT_TRANSFER_SIZE,
  481. BufferAlignment);
  482. IoBufferSize = (MaxHighSpeedBurstSize * SM95_BULK_IN_TRANSFER_COUNT) +
  483. MaxControlSize + MaxInterruptSize;
  484. IoBufferFlags = IO_BUFFER_FLAG_PHYSICALLY_CONTIGUOUS;
  485. Device->IoBuffer = MmAllocateNonPagedIoBuffer(0,
  486. MAX_ULONG,
  487. BufferAlignment,
  488. IoBufferSize,
  489. IoBufferFlags);
  490. if (Device->IoBuffer == NULL) {
  491. Status = STATUS_INSUFFICIENT_RESOURCES;
  492. goto InitializeDeviceStructuresEnd;
  493. }
  494. ASSERT(Device->IoBuffer->FragmentCount == 1);
  495. ASSERT(Device->IoBuffer->Fragment[0].VirtualAddress != NULL);
  496. PhysicalAddress = Device->IoBuffer->Fragment[0].PhysicalAddress;
  497. VirtualAddress = Device->IoBuffer->Fragment[0].VirtualAddress;
  498. //
  499. // Set up the bulk in transfers that are used to receive packets.
  500. //
  501. for (Index = 0; Index < SM95_BULK_IN_TRANSFER_COUNT; Index += 1) {
  502. UsbTransfer = UsbAllocateTransfer(Device->UsbCoreHandle,
  503. Device->BulkInEndpoint,
  504. SM95_HIGH_SPEED_BURST_SIZE,
  505. 0);
  506. if (UsbTransfer == NULL) {
  507. Status = STATUS_INSUFFICIENT_RESOURCES;
  508. goto InitializeDeviceStructuresEnd;
  509. }
  510. UsbTransfer->Buffer = VirtualAddress;
  511. UsbTransfer->BufferPhysicalAddress = PhysicalAddress;
  512. UsbTransfer->Direction = UsbTransferDirectionIn;
  513. UsbTransfer->Length = SM95_HIGH_SPEED_BURST_SIZE;
  514. UsbTransfer->BufferActualLength = MaxHighSpeedBurstSize;
  515. UsbTransfer->UserData = Device;
  516. UsbTransfer->CallbackRoutine = Sm95BulkInTransferCompletion;
  517. Device->BulkInTransfer[Index] = UsbTransfer;
  518. PhysicalAddress += MaxHighSpeedBurstSize;
  519. VirtualAddress += MaxHighSpeedBurstSize;
  520. }
  521. //
  522. // Set up the control transfer that's used for register reads and writes.
  523. //
  524. Device->ControlTransfer = UsbAllocateTransfer(
  525. Device->UsbCoreHandle,
  526. 0,
  527. SM95_MAX_CONTROL_TRANSFER_SIZE,
  528. 0);
  529. if (Device->ControlTransfer == NULL) {
  530. Status = STATUS_INSUFFICIENT_RESOURCES;
  531. goto InitializeDeviceStructuresEnd;
  532. }
  533. Device->ControlTransfer->Buffer = VirtualAddress;
  534. Device->ControlTransfer->BufferPhysicalAddress = PhysicalAddress;
  535. Device->ControlTransfer->BufferActualLength = MaxControlSize;
  536. VirtualAddress += MaxControlSize;
  537. PhysicalAddress += MaxControlSize;
  538. //
  539. // Set up the interrupt transfer that's used for link change notifications.
  540. //
  541. Device->InterruptTransfer = UsbAllocateTransfer(
  542. Device->UsbCoreHandle,
  543. Device->InterruptEndpoint,
  544. SM95_MAX_INTERRUPT_TRANSFER_SIZE,
  545. 0);
  546. if (Device->InterruptTransfer == NULL) {
  547. Status = STATUS_INSUFFICIENT_RESOURCES;
  548. goto InitializeDeviceStructuresEnd;
  549. }
  550. Device->InterruptTransfer->Buffer = VirtualAddress;
  551. Device->InterruptTransfer->BufferPhysicalAddress = PhysicalAddress;
  552. Device->InterruptTransfer->BufferActualLength = MaxInterruptSize;
  553. Device->InterruptTransfer->Direction = UsbTransferDirectionIn;
  554. Device->InterruptTransfer->Length = sizeof(ULONG);
  555. Device->InterruptTransfer->UserData = Device;
  556. Device->InterruptTransfer->CallbackRoutine =
  557. Sm95InterruptTransferCompletion;
  558. Status = STATUS_SUCCESS;
  559. InitializeDeviceStructuresEnd:
  560. if (!KSUCCESS(Status)) {
  561. if (Device != NULL) {
  562. Sm95pDeviceReleaseReference(Device);
  563. Device = NULL;
  564. }
  565. }
  566. *NewDevice = Device;
  567. return Status;
  568. }
  569. VOID
  570. Sm95pDestroyDeviceStructures (
  571. PSM95_DEVICE Device
  572. )
  573. /*++
  574. Routine Description:
  575. This routine destroys an SMSC95xx device structure.
  576. Arguments:
  577. Device - Supplies a pointer to the device.
  578. Return Value:
  579. None.
  580. --*/
  581. {
  582. ULONG Index;
  583. //
  584. // Destroy all the allocated transfers. For good measure, make sure they
  585. // are cancelled.
  586. //
  587. for (Index = 0; Index < SM95_BULK_IN_TRANSFER_COUNT; Index += 1) {
  588. if (Device->BulkInTransfer[Index] != NULL) {
  589. UsbCancelTransfer(Device->BulkInTransfer[Index], TRUE);
  590. UsbDestroyTransfer(Device->BulkInTransfer[Index]);
  591. }
  592. }
  593. if (Device->ControlTransfer != NULL) {
  594. UsbCancelTransfer(Device->ControlTransfer, TRUE);
  595. UsbDestroyTransfer(Device->ControlTransfer);
  596. }
  597. if (Device->InterruptTransfer != NULL) {
  598. UsbCancelTransfer(Device->InterruptTransfer, TRUE);
  599. UsbDestroyTransfer(Device->InterruptTransfer);
  600. }
  601. if (Device->IoBuffer != NULL) {
  602. MmFreeIoBuffer(Device->IoBuffer);
  603. }
  604. //
  605. // There should be no active bulk out transfers, so destroy all the free
  606. // transfers.
  607. //
  608. Sm95pDestroyBulkOutTransfers(Device);
  609. if (Device->BulkOutListLock != NULL) {
  610. KeDestroyQueuedLock(Device->BulkOutListLock);
  611. }
  612. MmFreePagedPool(Device);
  613. return;
  614. }
  615. VOID
  616. Sm95pDeviceAddReference (
  617. PSM95_DEVICE Device
  618. )
  619. /*++
  620. Routine Description:
  621. This routine increments the reference count of the given SM95 device.
  622. Arguments:
  623. Device - Supplies a pointer to the SM95 device.
  624. Return Value:
  625. None.
  626. --*/
  627. {
  628. ULONG OldReferenceCount;
  629. OldReferenceCount = RtlAtomicAdd32(&(Device->ReferenceCount), 1);
  630. ASSERT((OldReferenceCount != 0) & (OldReferenceCount < 0x20000000));
  631. return;
  632. }
  633. VOID
  634. Sm95pDeviceReleaseReference (
  635. PSM95_DEVICE Device
  636. )
  637. /*++
  638. Routine Description:
  639. This routine decrements the reference count of the given SM95 device.
  640. Arguments:
  641. Device - Supplies a pointer to the SM95 device.
  642. Return Value:
  643. None.
  644. --*/
  645. {
  646. ULONG OldReferenceCount;
  647. OldReferenceCount = RtlAtomicAdd32(&(Device->ReferenceCount), -1);
  648. ASSERT(OldReferenceCount != 0);
  649. if (OldReferenceCount == 1) {
  650. Sm95pDestroyDeviceStructures(Device);
  651. }
  652. return;
  653. }
  654. KSTATUS
  655. Sm95pSetUpUsbDevice (
  656. PSM95_DEVICE Device
  657. )
  658. /*++
  659. Routine Description:
  660. This routine claims the proper interface for the device and finds the
  661. bulk in, bulk out, and interrupt endpoints.
  662. Arguments:
  663. Device - Supplies a pointer to the device.
  664. Return Value:
  665. Status code.
  666. --*/
  667. {
  668. PUSB_CONFIGURATION_DESCRIPTION Configuration;
  669. PLIST_ENTRY CurrentEntry;
  670. USB_TRANSFER_DIRECTION Direction;
  671. PUSB_ENDPOINT_DESCRIPTION Endpoint;
  672. UCHAR EndpointType;
  673. PUSB_INTERFACE_DESCRIPTION Interface;
  674. KSTATUS Status;
  675. if (Device->InterfaceClaimed != FALSE) {
  676. ASSERT((Device->BulkInEndpoint != 0) &&
  677. (Device->BulkOutEndpoint != 0) &&
  678. (Device->InterruptEndpoint != 0));
  679. Status = STATUS_SUCCESS;
  680. goto SetUpUsbDeviceEnd;
  681. }
  682. //
  683. // If the configuration isn't yet set, set the first one.
  684. //
  685. Configuration = UsbGetActiveConfiguration(Device->UsbCoreHandle);
  686. if (Configuration == NULL) {
  687. Status = UsbSetConfiguration(Device->UsbCoreHandle, 0, TRUE);
  688. if (!KSUCCESS(Status)) {
  689. goto SetUpUsbDeviceEnd;
  690. }
  691. Configuration = UsbGetActiveConfiguration(Device->UsbCoreHandle);
  692. ASSERT(Configuration != NULL);
  693. }
  694. //
  695. // Get and verify the interface.
  696. //
  697. Interface = UsbGetDesignatedInterface(Device->OsDevice,
  698. Device->UsbCoreHandle);
  699. if (Interface == NULL) {
  700. Status = STATUS_NO_INTERFACE;
  701. goto SetUpUsbDeviceEnd;
  702. }
  703. if (Interface->Descriptor.Class != UsbInterfaceClassVendor) {
  704. Status = STATUS_NO_INTERFACE;
  705. goto SetUpUsbDeviceEnd;
  706. }
  707. //
  708. // Locate the IN and OUT bulk endpoints, and the interrupt endpoint.
  709. //
  710. CurrentEntry = Interface->EndpointListHead.Next;
  711. while (CurrentEntry != &(Interface->EndpointListHead)) {
  712. if ((Device->BulkInEndpoint != 0) &&
  713. (Device->BulkOutEndpoint != 0) &&
  714. (Device->InterruptEndpoint != 0)) {
  715. break;
  716. }
  717. Endpoint = LIST_VALUE(CurrentEntry,
  718. USB_ENDPOINT_DESCRIPTION,
  719. ListEntry);
  720. CurrentEntry = CurrentEntry->Next;
  721. //
  722. // Deconstruct the components of the endpoint descriptor.
  723. //
  724. EndpointType = Endpoint->Descriptor.Attributes &
  725. USB_ENDPOINT_ATTRIBUTES_TYPE_MASK;
  726. if ((Endpoint->Descriptor.EndpointAddress &
  727. USB_ENDPOINT_ADDRESS_DIRECTION_IN) != 0) {
  728. Direction = UsbTransferDirectionIn;
  729. } else {
  730. Direction = UsbTransferDirectionOut;
  731. }
  732. //
  733. // Look to match the endpoint up to one of the required ones.
  734. //
  735. if (EndpointType == USB_ENDPOINT_ATTRIBUTES_TYPE_BULK) {
  736. if ((Device->BulkInEndpoint == 0) &&
  737. (Direction == UsbTransferDirectionIn)) {
  738. Device->BulkInEndpoint = Endpoint->Descriptor.EndpointAddress;
  739. } else if ((Device->BulkOutEndpoint == 0) &&
  740. (Direction == UsbTransferDirectionOut)) {
  741. Device->BulkOutEndpoint = Endpoint->Descriptor.EndpointAddress;
  742. }
  743. } else if (EndpointType == USB_ENDPOINT_ATTRIBUTES_TYPE_INTERRUPT) {
  744. if ((Device->InterruptEndpoint == 0) &&
  745. (Direction == UsbTransferDirectionIn)) {
  746. Device->InterruptEndpoint =
  747. Endpoint->Descriptor.EndpointAddress;
  748. }
  749. }
  750. }
  751. if ((Device->BulkInEndpoint == 0) ||
  752. (Device->BulkOutEndpoint == 0) ||
  753. (Device->InterruptEndpoint == 0)) {
  754. Status = STATUS_INVALID_CONFIGURATION;
  755. goto SetUpUsbDeviceEnd;
  756. }
  757. //
  758. // Everything's all ready, claim the interface.
  759. //
  760. Status = UsbClaimInterface(Device->UsbCoreHandle,
  761. Interface->Descriptor.InterfaceNumber);
  762. if (!KSUCCESS(Status)) {
  763. goto SetUpUsbDeviceEnd;
  764. }
  765. Device->InterfaceNumber = Interface->Descriptor.InterfaceNumber;
  766. Device->InterfaceClaimed = TRUE;
  767. Status = STATUS_SUCCESS;
  768. SetUpUsbDeviceEnd:
  769. return Status;
  770. }
  771. KSTATUS
  772. Sm95pStartDevice (
  773. PIRP Irp,
  774. PSM95_DEVICE Device
  775. )
  776. /*++
  777. Routine Description:
  778. This routine starts the SMSC95xx LAN device.
  779. Arguments:
  780. Irp - Supplies a pointer to the start IRP.
  781. Device - Supplies a pointer to the device information.
  782. Return Value:
  783. Status code.
  784. --*/
  785. {
  786. KSTATUS Status;
  787. //
  788. // Start up the controller.
  789. //
  790. Status = Sm95pInitialize(Device);
  791. if (!KSUCCESS(Status)) {
  792. goto StartDeviceEnd;
  793. }
  794. StartDeviceEnd:
  795. return Status;
  796. }
  797. KSTATUS
  798. Sm95pStopDevice (
  799. PIRP Irp,
  800. PSM95_DEVICE Device
  801. )
  802. /*++
  803. Routine Description:
  804. This routine stops the SMSC95xx LAN device.
  805. Arguments:
  806. Irp - Supplies a pointer to the removal IRP.
  807. Device - Supplies a pointer to the device information.
  808. Return Value:
  809. Status code.
  810. --*/
  811. {
  812. //
  813. // Detach the device from USB. This will cancel all transfer attached to
  814. // the device, including the in-flight bulk out transfers that this driver
  815. // does not track.
  816. //
  817. if (Device->UsbCoreHandle != INVALID_HANDLE) {
  818. UsbDetachDevice(Device->UsbCoreHandle);
  819. }
  820. if (Device->InterfaceClaimed != FALSE) {
  821. UsbReleaseInterface(Device->UsbCoreHandle, Device->InterfaceNumber);
  822. }
  823. if (Device->UsbCoreHandle != INVALID_HANDLE) {
  824. UsbDeviceClose(Device->UsbCoreHandle);
  825. }
  826. //
  827. // The device is gone, notify the networking core that the link has bene
  828. // removed.
  829. //
  830. if (Device->NetworkLink != NULL) {
  831. NetRemoveLink(Device->NetworkLink);
  832. Device->NetworkLink = NULL;
  833. }
  834. Sm95pDeviceReleaseReference(Device);
  835. return STATUS_SUCCESS;
  836. }