1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180 |
- /*++
- Copyright (c) 2013 Minoca Corp. All Rights Reserved
- Module Name:
- smsc95.c
- Abstract:
- This module implements support for the driver portion of the SMSC95xx
- family of USB Ethernet Controllers.
- Author:
- Evan Green 7-Nov-2013
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/driver.h>
- #include <minoca/net/netdrv.h>
- #include <minoca/usb/usb.h>
- #include "smsc95.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- KSTATUS
- Sm95AddDevice (
- PVOID Driver,
- PSTR DeviceId,
- PSTR ClassId,
- PSTR CompatibleIds,
- PVOID DeviceToken
- );
- VOID
- Sm95DispatchStateChange (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- Sm95DispatchOpen (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- Sm95DispatchClose (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- Sm95DispatchIo (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- Sm95DispatchSystemControl (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- );
- VOID
- Sm95DestroyLink (
- PVOID DeviceContext
- );
- KSTATUS
- Sm95pInitializeDeviceStructures (
- PVOID OsDevice,
- PSM95_DEVICE *NewDevice
- );
- VOID
- Sm95pDestroyDeviceStructures (
- PSM95_DEVICE Device
- );
- VOID
- Sm95pDeviceAddReference (
- PSM95_DEVICE Device
- );
- VOID
- Sm95pDeviceReleaseReference (
- PSM95_DEVICE Device
- );
- KSTATUS
- Sm95pSetUpUsbDevice (
- PSM95_DEVICE Device
- );
- KSTATUS
- Sm95pStartDevice (
- PIRP Irp,
- PSM95_DEVICE Device
- );
- KSTATUS
- Sm95pStopDevice (
- PIRP Irp,
- PSM95_DEVICE Device
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- PDRIVER Sm95Driver = NULL;
- //
- // ------------------------------------------------------------------ Functions
- //
- KSTATUS
- DriverEntry (
- PDRIVER Driver
- )
- /*++
- Routine Description:
- This routine is the entry point for the SMSC95xx driver. It registers its
- other dispatch functions, and performs driver-wide initialization.
- Arguments:
- Driver - Supplies a pointer to the driver object.
- Return Value:
- STATUS_SUCCESS on success.
- Failure code on error.
- --*/
- {
- DRIVER_FUNCTION_TABLE FunctionTable;
- KSTATUS Status;
- Sm95Driver = Driver;
- RtlZeroMemory(&FunctionTable, sizeof(DRIVER_FUNCTION_TABLE));
- FunctionTable.Version = DRIVER_FUNCTION_TABLE_VERSION;
- FunctionTable.AddDevice = Sm95AddDevice;
- FunctionTable.DispatchStateChange = Sm95DispatchStateChange;
- FunctionTable.DispatchOpen = Sm95DispatchOpen;
- FunctionTable.DispatchClose = Sm95DispatchClose;
- FunctionTable.DispatchIo = Sm95DispatchIo;
- FunctionTable.DispatchSystemControl = Sm95DispatchSystemControl;
- Status = IoRegisterDriverFunctions(Driver, &FunctionTable);
- return Status;
- }
- KSTATUS
- Sm95AddDevice (
- PVOID Driver,
- PSTR DeviceId,
- PSTR ClassId,
- PSTR CompatibleIds,
- PVOID DeviceToken
- )
- /*++
- Routine Description:
- This routine is called when a device is detected for which the SMSC95xx
- driver acts as the function driver. The driver will attach itself to the
- stack.
- Arguments:
- Driver - Supplies a pointer to the driver being called.
- DeviceId - Supplies a pointer to a string with the device ID.
- ClassId - Supplies a pointer to a string containing the device's class ID.
- CompatibleIds - Supplies a pointer to a string containing device IDs
- that would be compatible with this device.
- DeviceToken - Supplies an opaque token that the driver can use to identify
- the device in the system. This token should be used when attaching to
- the stack.
- Return Value:
- STATUS_SUCCESS on success.
- Failure code if the driver was unsuccessful in attaching itself.
- --*/
- {
- PSM95_DEVICE Device;
- KSTATUS Status;
- Status = Sm95pInitializeDeviceStructures(DeviceToken, &Device);
- if (!KSUCCESS(Status)) {
- goto AddDeviceEnd;
- }
- Status = IoAttachDriverToDevice(Driver, DeviceToken, Device);
- if (!KSUCCESS(Status)) {
- goto AddDeviceEnd;
- }
- AddDeviceEnd:
- if (!KSUCCESS(Status)) {
- if (Device != NULL) {
- Sm95pDeviceReleaseReference(Device);
- }
- }
- return Status;
- }
- VOID
- Sm95DispatchStateChange (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles State Change IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- KSTATUS Status;
- ASSERT(Irp->MajorCode == IrpMajorStateChange);
- if (Irp->Direction == IrpUp) {
- switch (Irp->MinorCode) {
- case IrpMinorQueryResources:
- case IrpMinorQueryChildren:
- IoCompleteIrp(Sm95Driver, Irp, STATUS_SUCCESS);
- break;
- case IrpMinorStartDevice:
- Status = Sm95pStartDevice(Irp, DeviceContext);
- if (!KSUCCESS(Status)) {
- IoCompleteIrp(Sm95Driver, Irp, Status);
- }
- break;
- case IrpMinorRemoveDevice:
- Status = Sm95pStopDevice(Irp, DeviceContext);
- if (!KSUCCESS(Status)) {
- IoCompleteIrp(Sm95Driver, Irp, Status);
- break;
- }
- break;
- default:
- break;
- }
- }
- return;
- }
- VOID
- Sm95DispatchOpen (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles Open IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- return;
- }
- VOID
- Sm95DispatchClose (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles Close IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- return;
- }
- VOID
- Sm95DispatchIo (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles I/O IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- return;
- }
- VOID
- Sm95DispatchSystemControl (
- PIRP Irp,
- PVOID DeviceContext,
- PVOID IrpContext
- )
- /*++
- Routine Description:
- This routine handles System Control IRPs.
- Arguments:
- Irp - Supplies a pointer to the I/O request packet.
- DeviceContext - Supplies the context pointer supplied by the driver when it
- attached itself to the driver stack. Presumably this pointer contains
- driver-specific device context.
- IrpContext - Supplies the context pointer supplied by the driver when
- the IRP was created.
- Return Value:
- None.
- --*/
- {
- PSM95_DEVICE Device;
- PSYSTEM_CONTROL_DEVICE_INFORMATION DeviceInformationRequest;
- KSTATUS Status;
- ASSERT(Irp->MajorCode == IrpMajorSystemControl);
- Device = DeviceContext;
- if (Irp->Direction == IrpDown) {
- switch (Irp->MinorCode) {
- case IrpMinorSystemControlDeviceInformation:
- DeviceInformationRequest = Irp->U.SystemControl.SystemContext;
- Status = NetGetSetLinkDeviceInformation(
- Device->NetworkLink,
- &(DeviceInformationRequest->Uuid),
- DeviceInformationRequest->Data,
- &(DeviceInformationRequest->DataSize),
- DeviceInformationRequest->Set);
- IoCompleteIrp(Sm95Driver, Irp, Status);
- break;
- default:
- break;
- }
- }
- return;
- }
- KSTATUS
- Sm95pAddNetworkDevice (
- PSM95_DEVICE Device
- )
- /*++
- Routine Description:
- This routine adds the device to core networking's available links.
- Arguments:
- Device - Supplies a pointer to the device to add.
- Return Value:
- Status code.
- --*/
- {
- NET_LINK_PROPERTIES Properties;
- KSTATUS Status;
- if (Device->NetworkLink != NULL) {
- Status = STATUS_SUCCESS;
- goto AddNetworkDeviceEnd;
- }
- //
- // Add a link to the core networking library.
- //
- RtlZeroMemory(&Properties, sizeof(NET_LINK_PROPERTIES));
- Properties.Version = NET_LINK_PROPERTIES_VERSION;
- Properties.TransmitAlignment = MmGetIoBufferAlignment();
- Properties.Device = Device->OsDevice;
- Properties.DeviceContext = Device;
- Properties.PacketSizeInformation.MaxPacketSize = SM95_MAX_PACKET_SIZE;
- Properties.PacketSizeInformation.HeaderSize = SM95_TRANSMIT_HEADER_SIZE;
- Properties.DataLinkType = NetDomainEthernet;
- Properties.MaxPhysicalAddress = MAX_ULONG;
- Properties.PhysicalAddress.Domain = NetDomainEthernet;
- RtlCopyMemory(&(Properties.PhysicalAddress.Address),
- &(Device->MacAddress),
- sizeof(Device->MacAddress));
- Properties.Interface.Send = Sm95Send;
- Properties.Interface.GetSetInformation = Sm95GetSetInformation;
- Properties.Interface.DestroyLink = Sm95DestroyLink;
- Status = NetAddLink(&Properties, &(Device->NetworkLink));
- if (!KSUCCESS(Status)) {
- goto AddNetworkDeviceEnd;
- }
- //
- // The networking core now references the device structure. Add a
- // reference for it.
- //
- Sm95pDeviceAddReference(Device);
- AddNetworkDeviceEnd:
- if (!KSUCCESS(Status)) {
- if (Device->NetworkLink != NULL) {
- NetRemoveLink(Device->NetworkLink);
- Device->NetworkLink = NULL;
- }
- }
- return Status;
- }
- VOID
- Sm95DestroyLink (
- PVOID DeviceContext
- )
- /*++
- Routine Description:
- This routine notifies the device layer that the networking core is in the
- process of destroying the link and will no longer call into the device for
- this link. This allows the device layer to release any context that was
- supporting the device link interface.
- Arguments:
- DeviceContext - Supplies a pointer to the device context associated with
- the link being destroyed.
- Return Value:
- None.
- --*/
- {
- Sm95pDeviceReleaseReference(DeviceContext);
- return;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- KSTATUS
- Sm95pInitializeDeviceStructures (
- PVOID OsDevice,
- PSM95_DEVICE *NewDevice
- )
- /*++
- Routine Description:
- This routine initializes an SMSC95xx device.
- Arguments:
- OsDevice - Supplies a pointer to the system token that represents this
- device.
- NewDevice - Supplies a pointer where the new structure will be returned.
- Return Value:
- Status code.
- --*/
- {
- ULONG BufferAlignment;
- PSM95_DEVICE Device;
- ULONG Index;
- ULONG IoBufferFlags;
- UINTN IoBufferSize;
- ULONG MaxControlSize;
- ULONG MaxHighSpeedBurstSize;
- ULONG MaxInterruptSize;
- PHYSICAL_ADDRESS PhysicalAddress;
- KSTATUS Status;
- PUSB_TRANSFER UsbTransfer;
- PVOID VirtualAddress;
- Device = MmAllocatePagedPool(sizeof(SM95_DEVICE), SM95_ALLOCATION_TAG);
- if (Device == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeDeviceStructuresEnd;
- }
- RtlZeroMemory(Device, sizeof(SM95_DEVICE));
- Device->OsDevice = OsDevice;
- Device->UsbCoreHandle = INVALID_HANDLE;
- Device->ReferenceCount = 1;
- INITIALIZE_LIST_HEAD(&(Device->BulkOutFreeTransferList));
- Device->BulkOutListLock = KeCreateQueuedLock();
- if (Device->BulkOutListLock == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeDeviceStructuresEnd;
- }
- //
- // Attempt to attach to the USB core.
- //
- Status = UsbDriverAttach(OsDevice, Sm95Driver, &(Device->UsbCoreHandle));
- if (!KSUCCESS(Status)) {
- goto InitializeDeviceStructuresEnd;
- }
- Status = Sm95pSetUpUsbDevice(Device);
- if (!KSUCCESS(Status)) {
- goto InitializeDeviceStructuresEnd;
- }
- //
- // Create an I/O buffer for the control and receive transfers.
- //
- BufferAlignment = MmGetIoBufferAlignment();
- MaxHighSpeedBurstSize = ALIGN_RANGE_UP(SM95_HIGH_SPEED_BURST_SIZE,
- BufferAlignment);
- MaxControlSize = ALIGN_RANGE_UP(SM95_MAX_CONTROL_TRANSFER_SIZE,
- BufferAlignment);
- MaxInterruptSize = ALIGN_RANGE_UP(SM95_MAX_INTERRUPT_TRANSFER_SIZE,
- BufferAlignment);
- IoBufferSize = (MaxHighSpeedBurstSize * SM95_BULK_IN_TRANSFER_COUNT) +
- MaxControlSize + MaxInterruptSize;
- IoBufferFlags = IO_BUFFER_FLAG_PHYSICALLY_CONTIGUOUS;
- Device->IoBuffer = MmAllocateNonPagedIoBuffer(0,
- MAX_ULONG,
- BufferAlignment,
- IoBufferSize,
- IoBufferFlags);
- if (Device->IoBuffer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeDeviceStructuresEnd;
- }
- ASSERT(Device->IoBuffer->FragmentCount == 1);
- ASSERT(Device->IoBuffer->Fragment[0].VirtualAddress != NULL);
- PhysicalAddress = Device->IoBuffer->Fragment[0].PhysicalAddress;
- VirtualAddress = Device->IoBuffer->Fragment[0].VirtualAddress;
- //
- // Set up the bulk in transfers that are used to receive packets.
- //
- for (Index = 0; Index < SM95_BULK_IN_TRANSFER_COUNT; Index += 1) {
- UsbTransfer = UsbAllocateTransfer(Device->UsbCoreHandle,
- Device->BulkInEndpoint,
- SM95_HIGH_SPEED_BURST_SIZE,
- 0);
- if (UsbTransfer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeDeviceStructuresEnd;
- }
- UsbTransfer->Buffer = VirtualAddress;
- UsbTransfer->BufferPhysicalAddress = PhysicalAddress;
- UsbTransfer->Direction = UsbTransferDirectionIn;
- UsbTransfer->Length = SM95_HIGH_SPEED_BURST_SIZE;
- UsbTransfer->BufferActualLength = MaxHighSpeedBurstSize;
- UsbTransfer->UserData = Device;
- UsbTransfer->CallbackRoutine = Sm95BulkInTransferCompletion;
- Device->BulkInTransfer[Index] = UsbTransfer;
- PhysicalAddress += MaxHighSpeedBurstSize;
- VirtualAddress += MaxHighSpeedBurstSize;
- }
- //
- // Set up the control transfer that's used for register reads and writes.
- //
- Device->ControlTransfer = UsbAllocateTransfer(
- Device->UsbCoreHandle,
- 0,
- SM95_MAX_CONTROL_TRANSFER_SIZE,
- 0);
- if (Device->ControlTransfer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeDeviceStructuresEnd;
- }
- Device->ControlTransfer->Buffer = VirtualAddress;
- Device->ControlTransfer->BufferPhysicalAddress = PhysicalAddress;
- Device->ControlTransfer->BufferActualLength = MaxControlSize;
- VirtualAddress += MaxControlSize;
- PhysicalAddress += MaxControlSize;
- //
- // Set up the interrupt transfer that's used for link change notifications.
- //
- Device->InterruptTransfer = UsbAllocateTransfer(
- Device->UsbCoreHandle,
- Device->InterruptEndpoint,
- SM95_MAX_INTERRUPT_TRANSFER_SIZE,
- 0);
- if (Device->InterruptTransfer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto InitializeDeviceStructuresEnd;
- }
- Device->InterruptTransfer->Buffer = VirtualAddress;
- Device->InterruptTransfer->BufferPhysicalAddress = PhysicalAddress;
- Device->InterruptTransfer->BufferActualLength = MaxInterruptSize;
- Device->InterruptTransfer->Direction = UsbTransferDirectionIn;
- Device->InterruptTransfer->Length = sizeof(ULONG);
- Device->InterruptTransfer->UserData = Device;
- Device->InterruptTransfer->CallbackRoutine =
- Sm95InterruptTransferCompletion;
- Status = STATUS_SUCCESS;
- InitializeDeviceStructuresEnd:
- if (!KSUCCESS(Status)) {
- if (Device != NULL) {
- Sm95pDeviceReleaseReference(Device);
- Device = NULL;
- }
- }
- *NewDevice = Device;
- return Status;
- }
- VOID
- Sm95pDestroyDeviceStructures (
- PSM95_DEVICE Device
- )
- /*++
- Routine Description:
- This routine destroys an SMSC95xx device structure.
- Arguments:
- Device - Supplies a pointer to the device.
- Return Value:
- None.
- --*/
- {
- ULONG Index;
- //
- // Destroy all the allocated transfers. For good measure, make sure they
- // are cancelled.
- //
- for (Index = 0; Index < SM95_BULK_IN_TRANSFER_COUNT; Index += 1) {
- if (Device->BulkInTransfer[Index] != NULL) {
- UsbCancelTransfer(Device->BulkInTransfer[Index], TRUE);
- UsbDestroyTransfer(Device->BulkInTransfer[Index]);
- }
- }
- if (Device->ControlTransfer != NULL) {
- UsbCancelTransfer(Device->ControlTransfer, TRUE);
- UsbDestroyTransfer(Device->ControlTransfer);
- }
- if (Device->InterruptTransfer != NULL) {
- UsbCancelTransfer(Device->InterruptTransfer, TRUE);
- UsbDestroyTransfer(Device->InterruptTransfer);
- }
- if (Device->IoBuffer != NULL) {
- MmFreeIoBuffer(Device->IoBuffer);
- }
- //
- // There should be no active bulk out transfers, so destroy all the free
- // transfers.
- //
- Sm95pDestroyBulkOutTransfers(Device);
- if (Device->BulkOutListLock != NULL) {
- KeDestroyQueuedLock(Device->BulkOutListLock);
- }
- MmFreePagedPool(Device);
- return;
- }
- VOID
- Sm95pDeviceAddReference (
- PSM95_DEVICE Device
- )
- /*++
- Routine Description:
- This routine increments the reference count of the given SM95 device.
- Arguments:
- Device - Supplies a pointer to the SM95 device.
- Return Value:
- None.
- --*/
- {
- ULONG OldReferenceCount;
- OldReferenceCount = RtlAtomicAdd32(&(Device->ReferenceCount), 1);
- ASSERT((OldReferenceCount != 0) & (OldReferenceCount < 0x20000000));
- return;
- }
- VOID
- Sm95pDeviceReleaseReference (
- PSM95_DEVICE Device
- )
- /*++
- Routine Description:
- This routine decrements the reference count of the given SM95 device.
- Arguments:
- Device - Supplies a pointer to the SM95 device.
- Return Value:
- None.
- --*/
- {
- ULONG OldReferenceCount;
- OldReferenceCount = RtlAtomicAdd32(&(Device->ReferenceCount), -1);
- ASSERT(OldReferenceCount != 0);
- if (OldReferenceCount == 1) {
- Sm95pDestroyDeviceStructures(Device);
- }
- return;
- }
- KSTATUS
- Sm95pSetUpUsbDevice (
- PSM95_DEVICE Device
- )
- /*++
- Routine Description:
- This routine claims the proper interface for the device and finds the
- bulk in, bulk out, and interrupt endpoints.
- Arguments:
- Device - Supplies a pointer to the device.
- Return Value:
- Status code.
- --*/
- {
- PUSB_CONFIGURATION_DESCRIPTION Configuration;
- PLIST_ENTRY CurrentEntry;
- USB_TRANSFER_DIRECTION Direction;
- PUSB_ENDPOINT_DESCRIPTION Endpoint;
- UCHAR EndpointType;
- PUSB_INTERFACE_DESCRIPTION Interface;
- KSTATUS Status;
- if (Device->InterfaceClaimed != FALSE) {
- ASSERT((Device->BulkInEndpoint != 0) &&
- (Device->BulkOutEndpoint != 0) &&
- (Device->InterruptEndpoint != 0));
- Status = STATUS_SUCCESS;
- goto SetUpUsbDeviceEnd;
- }
- //
- // If the configuration isn't yet set, set the first one.
- //
- Configuration = UsbGetActiveConfiguration(Device->UsbCoreHandle);
- if (Configuration == NULL) {
- Status = UsbSetConfiguration(Device->UsbCoreHandle, 0, TRUE);
- if (!KSUCCESS(Status)) {
- goto SetUpUsbDeviceEnd;
- }
- Configuration = UsbGetActiveConfiguration(Device->UsbCoreHandle);
- ASSERT(Configuration != NULL);
- }
- //
- // Get and verify the interface.
- //
- Interface = UsbGetDesignatedInterface(Device->OsDevice,
- Device->UsbCoreHandle);
- if (Interface == NULL) {
- Status = STATUS_NO_INTERFACE;
- goto SetUpUsbDeviceEnd;
- }
- if (Interface->Descriptor.Class != UsbInterfaceClassVendor) {
- Status = STATUS_NO_INTERFACE;
- goto SetUpUsbDeviceEnd;
- }
- //
- // Locate the IN and OUT bulk endpoints, and the interrupt endpoint.
- //
- CurrentEntry = Interface->EndpointListHead.Next;
- while (CurrentEntry != &(Interface->EndpointListHead)) {
- if ((Device->BulkInEndpoint != 0) &&
- (Device->BulkOutEndpoint != 0) &&
- (Device->InterruptEndpoint != 0)) {
- break;
- }
- Endpoint = LIST_VALUE(CurrentEntry,
- USB_ENDPOINT_DESCRIPTION,
- ListEntry);
- CurrentEntry = CurrentEntry->Next;
- //
- // Deconstruct the components of the endpoint descriptor.
- //
- EndpointType = Endpoint->Descriptor.Attributes &
- USB_ENDPOINT_ATTRIBUTES_TYPE_MASK;
- if ((Endpoint->Descriptor.EndpointAddress &
- USB_ENDPOINT_ADDRESS_DIRECTION_IN) != 0) {
- Direction = UsbTransferDirectionIn;
- } else {
- Direction = UsbTransferDirectionOut;
- }
- //
- // Look to match the endpoint up to one of the required ones.
- //
- if (EndpointType == USB_ENDPOINT_ATTRIBUTES_TYPE_BULK) {
- if ((Device->BulkInEndpoint == 0) &&
- (Direction == UsbTransferDirectionIn)) {
- Device->BulkInEndpoint = Endpoint->Descriptor.EndpointAddress;
- } else if ((Device->BulkOutEndpoint == 0) &&
- (Direction == UsbTransferDirectionOut)) {
- Device->BulkOutEndpoint = Endpoint->Descriptor.EndpointAddress;
- }
- } else if (EndpointType == USB_ENDPOINT_ATTRIBUTES_TYPE_INTERRUPT) {
- if ((Device->InterruptEndpoint == 0) &&
- (Direction == UsbTransferDirectionIn)) {
- Device->InterruptEndpoint =
- Endpoint->Descriptor.EndpointAddress;
- }
- }
- }
- if ((Device->BulkInEndpoint == 0) ||
- (Device->BulkOutEndpoint == 0) ||
- (Device->InterruptEndpoint == 0)) {
- Status = STATUS_INVALID_CONFIGURATION;
- goto SetUpUsbDeviceEnd;
- }
- //
- // Everything's all ready, claim the interface.
- //
- Status = UsbClaimInterface(Device->UsbCoreHandle,
- Interface->Descriptor.InterfaceNumber);
- if (!KSUCCESS(Status)) {
- goto SetUpUsbDeviceEnd;
- }
- Device->InterfaceNumber = Interface->Descriptor.InterfaceNumber;
- Device->InterfaceClaimed = TRUE;
- Status = STATUS_SUCCESS;
- SetUpUsbDeviceEnd:
- return Status;
- }
- KSTATUS
- Sm95pStartDevice (
- PIRP Irp,
- PSM95_DEVICE Device
- )
- /*++
- Routine Description:
- This routine starts the SMSC95xx LAN device.
- Arguments:
- Irp - Supplies a pointer to the start IRP.
- Device - Supplies a pointer to the device information.
- Return Value:
- Status code.
- --*/
- {
- KSTATUS Status;
- //
- // Start up the controller.
- //
- Status = Sm95pInitialize(Device);
- if (!KSUCCESS(Status)) {
- goto StartDeviceEnd;
- }
- StartDeviceEnd:
- return Status;
- }
- KSTATUS
- Sm95pStopDevice (
- PIRP Irp,
- PSM95_DEVICE Device
- )
- /*++
- Routine Description:
- This routine stops the SMSC95xx LAN device.
- Arguments:
- Irp - Supplies a pointer to the removal IRP.
- Device - Supplies a pointer to the device information.
- Return Value:
- Status code.
- --*/
- {
- //
- // Detach the device from USB. This will cancel all transfer attached to
- // the device, including the in-flight bulk out transfers that this driver
- // does not track.
- //
- if (Device->UsbCoreHandle != INVALID_HANDLE) {
- UsbDetachDevice(Device->UsbCoreHandle);
- }
- if (Device->InterfaceClaimed != FALSE) {
- UsbReleaseInterface(Device->UsbCoreHandle, Device->InterfaceNumber);
- }
- if (Device->UsbCoreHandle != INVALID_HANDLE) {
- UsbDeviceClose(Device->UsbCoreHandle);
- }
- //
- // The device is gone, notify the networking core that the link has bene
- // removed.
- //
- if (Device->NetworkLink != NULL) {
- NetRemoveLink(Device->NetworkLink);
- Device->NetworkLink = NULL;
- }
- Sm95pDeviceReleaseReference(Device);
- return STATUS_SUCCESS;
- }
|