123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631 |
- /*++
- Copyright (c) 2013 Minoca Corp. All Rights Reserved
- Module Name:
- enum.c
- Abstract:
- This module implements device enumeration for the USB core.
- Author:
- Evan Green 16-Jan-2013
- Environment:
- Kernel
- --*/
- //
- // ------------------------------------------------------------------- Includes
- //
- #include <minoca/kernel/driver.h>
- #include "usbcore.h"
- //
- // ---------------------------------------------------------------- Definitions
- //
- //
- // Define the format of device identifiers that USB presents devices with.
- //
- #define USB_DEVICE_ID_LENGTH 20
- #define USB_DEVICE_ID_FORMAT "VID_%04X&PID_%04X"
- #define USB_DEVICE_ID_WITH_INTERFACE_FORMAT "VID_%04X&PID_%04X_%02X"
- //
- // Define the number of times an enumeration request will be made before
- // declaring that it really doesn't work.
- //
- #define USB_ENUMERATION_TRANSFER_TRY_COUNT 5
- //
- // ------------------------------------------------------ Data Type Definitions
- //
- //
- // ----------------------------------------------- Internal Function Prototypes
- //
- KSTATUS
- UsbpEnumerateRootHub (
- PUSB_HOST_CONTROLLER Controller
- );
- PUSB_DEVICE
- UsbpCreateDevice (
- USB_DEVICE_SPEED DeviceSpeed,
- PUSB_DEVICE ParentDevice,
- UCHAR PortNumber,
- PUSB_HOST_CONTROLLER ParentController
- );
- VOID
- UsbpDestroyDevice (
- PUSB_DEVICE Device
- );
- KSTATUS
- UsbpGetDeviceDescriptor (
- PUSB_DEVICE Device,
- PUSB_DEVICE_DESCRIPTOR DeviceDescriptor,
- BOOL FirstEightBytesOnly
- );
- KSTATUS
- UsbpAssignDeviceAddress (
- PUSB_DEVICE Device
- );
- VOID
- UsbpUnassignDeviceAddress (
- PUSB_DEVICE Device
- );
- KSTATUS
- UsbpReadDeviceStrings (
- PUSB_DEVICE Device,
- PUSB_DEVICE_DESCRIPTOR DeviceDescriptor
- );
- PSTR
- UsbpCreateAnsiStringFromStringDescriptor (
- PUSB_STRING_DESCRIPTOR StringDescriptor
- );
- VOID
- UsbpGetDeviceClass (
- PUSB_DEVICE Device,
- PUCHAR Class,
- PUCHAR Subclass,
- PUCHAR Protocol
- );
- KSTATUS
- UsbpCreateOsDevice (
- PUSB_DEVICE Device,
- UCHAR Class,
- UCHAR Subclass,
- UCHAR Protocol,
- UCHAR Interface,
- BOOL InterfaceDevice,
- PDEVICE *CreatedDevice
- );
- UCHAR
- UsbpGetReservedDeviceAddress (
- PUSB_DEVICE Device
- );
- //
- // -------------------------------------------------------------------- Globals
- //
- //
- // ------------------------------------------------------------------ Functions
- //
- USB_API
- KSTATUS
- UsbHostQueryChildren (
- PIRP Irp,
- HANDLE UsbDeviceHandle
- )
- /*++
- Routine Description:
- This routine responds to the Query Children IRP for a USB Host controller.
- Arguments:
- Irp - Supplies a pointer to the Query Children IRP.
- UsbDeviceHandle - Supplies a pointer to the USB Host controller handle.
- Return Value:
- Status code.
- --*/
- {
- PUSB_HOST_CONTROLLER Controller;
- KSTATUS Status;
- Controller = (PUSB_HOST_CONTROLLER)UsbDeviceHandle;
- ASSERT(Controller != NULL);
- //
- // If the root hub's device has never before been created, create it now.
- //
- if (Controller->RootDevice == NULL) {
- Status = UsbpEnumerateRootHub(Controller);
- if (!KSUCCESS(Status)) {
- goto HostQueryChildrenEnd;
- }
- }
- ASSERT((Controller->RootDevice != NULL) &&
- (Controller->RootDevice->Device != NULL));
- //
- // Merge whatever is in the IRP with the enumeration of this root hub.
- //
- Status = IoMergeChildArrays(Irp,
- &(Controller->RootDevice->Device),
- 1,
- USB_CORE_ALLOCATION_TAG);
- if (!KSUCCESS(Status)) {
- goto HostQueryChildrenEnd;
- }
- HostQueryChildrenEnd:
- return Status;
- }
- USB_API
- KSTATUS
- UsbDriverAttach (
- PDEVICE Device,
- PDRIVER Driver,
- PHANDLE UsbCoreHandle
- )
- /*++
- Routine Description:
- This routine attaches a USB driver to a USB device, and returns a USB
- core handle to the device, used for all USB communications. This routine
- must be called at low level.
- Arguments:
- Device - Supplies a pointer to the OS device object representation of the
- USB device.
- Driver - Supplies a pointer to the driver that will take ownership of the
- device.
- UsbCoreHandle - Supplies a pointer where the USB Core device handle will
- be returned.
- Return Value:
- Status code.
- --*/
- {
- PUSB_DEVICE CurrentDevice;
- PLIST_ENTRY CurrentEntry;
- PUSB_DEVICE FoundDevice;
- PUSB_INTERFACE Interface;
- KSTATUS Status;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- FoundDevice = NULL;
- *UsbCoreHandle = INVALID_HANDLE;
- if (Driver == NULL) {
- return STATUS_ARGUMENT_EXPECTED;
- }
- //
- // Loop through all USB controllers.
- //
- Status = STATUS_NOT_FOUND;
- KeAcquireQueuedLock(UsbDeviceListLock);
- CurrentEntry = UsbDeviceList.Next;
- while (CurrentEntry != &UsbDeviceList) {
- CurrentDevice = LIST_VALUE(CurrentEntry, USB_DEVICE, GlobalListEntry);
- ASSERT(CurrentEntry != NULL);
- CurrentEntry = CurrentEntry->Next;
- //
- // Check to see if the driver is attaching to the current device.
- //
- if (CurrentDevice->Device == Device) {
- FoundDevice = CurrentDevice;
- if (FoundDevice->Driver == NULL) {
- FoundDevice->Driver = Driver;
- Status = STATUS_SUCCESS;
- }
- break;
- }
- //
- // Check all the interfaces of the current configuration to see if the
- // driver is actually just attaching to an interface.
- //
- Interface = (PUSB_INTERFACE)UsbGetDesignatedInterface(Device,
- CurrentDevice);
- if (Interface != NULL) {
- FoundDevice = CurrentDevice;
- ASSERT(Interface->Driver == NULL);
- Interface->Driver = Driver;
- Status = STATUS_SUCCESS;
- break;
- }
- }
- KeReleaseQueuedLock(UsbDeviceListLock);
- //
- // Only a device's removel IRP marks the device as disconnected. Since the
- // removal IRP is the last action a device can take, it is safe to assume
- // that the attempt to open the device here will succeed.
- //
- if (FoundDevice != NULL) {
- ASSERT(FoundDevice->Connected != FALSE);
- *UsbCoreHandle = UsbDeviceOpen(FoundDevice);
- ASSERT(*UsbCoreHandle != INVALID_HANDLE);
- }
- return Status;
- }
- USB_API
- KSTATUS
- UsbEnumerateDeviceForInterface (
- HANDLE UsbCoreHandle,
- PUSB_INTERFACE_DESCRIPTION InterfaceDescription,
- PDEVICE *ChildDevice
- )
- /*++
- Routine Description:
- This routine enumerates a child OS device on the requested device and
- interface combination. With this interface multiple drivers can
- independently operate interfaces of a shared USB device.
- Arguments:
- UsbCoreHandle - Supplies the core handle to the device containing the
- interface to share.
- InterfaceDescription - Supplies a pointer to the interface to enumerate a
- device for.
- ChildDevice - Supplies a pointer to an OS device that will come up to
- claim the given interface. This device should be returned in Query
- Children calls sent to the parent device so the device can properly
- enumerate.
- Return Value:
- Status code.
- --*/
- {
- UCHAR Class;
- PUSB_DEVICE Device;
- PUSB_INTERFACE Interface;
- UCHAR InterfaceNumber;
- UCHAR Protocol;
- KSTATUS Status;
- UCHAR Subclass;
- Device = (PUSB_DEVICE)UsbCoreHandle;
- Interface = (PUSB_INTERFACE)InterfaceDescription;
- if (Interface->Device != NULL) {
- *ChildDevice = Interface->Device;
- Status = STATUS_SUCCESS;
- goto EnumerateDeviceForInterfaceEnd;
- }
- Class = InterfaceDescription->Descriptor.Class;
- Subclass = InterfaceDescription->Descriptor.Subclass;
- Protocol = InterfaceDescription->Descriptor.Protocol;
- InterfaceNumber = InterfaceDescription->Descriptor.InterfaceNumber;
- ASSERT(Device->DebugDevice == FALSE);
- Status = UsbpCreateOsDevice(Device,
- Class,
- Subclass,
- Protocol,
- InterfaceNumber,
- TRUE,
- ChildDevice);
- if (!KSUCCESS(Status)) {
- goto EnumerateDeviceForInterfaceEnd;
- }
- Interface->Device = *ChildDevice;
- Status = STATUS_SUCCESS;
- EnumerateDeviceForInterfaceEnd:
- if (!KSUCCESS(Status)) {
- *ChildDevice = NULL;
- }
- return Status;
- }
- USB_API
- PUSB_INTERFACE_DESCRIPTION
- UsbGetDesignatedInterface (
- PDEVICE Device,
- HANDLE UsbCoreHandle
- )
- /*++
- Routine Description:
- This routine returns the interface for which the given pseudo-device was
- enumerated. This routine is used by general class drivers (like Hub or
- Mass Storage) that can interact with an interface without necessarily
- taking responsibility for the entire device.
- Arguments:
- Device - Supplies a pointer to the OS device object representation of the
- USB device.
- UsbCoreHandle - Supplies the core handle to the device.
- Return Value:
- Returns a pointer to the interface this pseudo-device is supposed to take
- ownership of. If the device only has one interface, then that interface is
- returned.
- NULL if the OS device was not enumerated for any one particular interface.
- --*/
- {
- PUSB_CONFIGURATION Configuration;
- PUSB_INTERFACE FoundInterface;
- PUSB_INTERFACE Interface;
- PLIST_ENTRY InterfaceEntry;
- PLIST_ENTRY InterfaceListHead;
- PUSB_DEVICE UsbDevice;
- UsbDevice = (PUSB_DEVICE)UsbCoreHandle;
- if (UsbCoreHandle == INVALID_HANDLE) {
- return NULL;
- }
- FoundInterface = NULL;
- Configuration = UsbDevice->ActiveConfiguration;
- if (Configuration == NULL) {
- return NULL;
- }
- //
- // If there's only one interface, return that one.
- //
- InterfaceListHead = &(Configuration->Description.InterfaceListHead);
- ASSERT(LIST_EMPTY(InterfaceListHead) == FALSE);
- InterfaceEntry = InterfaceListHead->Next;
- //
- // If this is the main device attached to the USB device, just give it the
- // first interface.
- //
- if (UsbDevice->Device == Device) {
- FoundInterface = LIST_VALUE(InterfaceEntry,
- USB_INTERFACE,
- Description.ListEntry);
- return (PUSB_INTERFACE_DESCRIPTION)&(FoundInterface->Description);
- }
- //
- // Loop through all the interfaces looking for the one associated with this
- // device.
- //
- while (InterfaceEntry != InterfaceListHead) {
- Interface = LIST_VALUE(InterfaceEntry,
- USB_INTERFACE,
- Description.ListEntry);
- if (Interface->Device == Device) {
- FoundInterface = Interface;
- break;
- }
- InterfaceEntry = InterfaceEntry->Next;
- }
- return (PUSB_INTERFACE_DESCRIPTION)&(FoundInterface->Description);
- }
- USB_API
- KSTATUS
- UsbGetDeviceSpeed (
- PUSB_DEVICE Device,
- PUSB_DEVICE_SPEED Speed
- )
- /*++
- Routine Description:
- This routine returns the connected speed of the given USB device.
- Arguments:
- Device - Supplies a pointer to the device.
- Speed - Supplies a pointer where the device speed will be returned.
- Return Value:
- Status code.
- --*/
- {
- *Speed = Device->Speed;
- return STATUS_SUCCESS;
- }
- USB_API
- VOID
- UsbDetachDevice (
- HANDLE UsbCoreHandle
- )
- /*++
- Routine Description:
- This routine detaches a USB device from the USB core by marking it as
- disconnected, and cancelling all active transfers belonging to the device.
- It does not close the device.
- Arguments:
- UsbCoreHandle - Supplies the core handle to the device that is to be
- removed.
- Return Value:
- None.
- --*/
- {
- PUSB_DEVICE Device;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- ASSERT(UsbCoreHandle != INVALID_HANDLE);
- Device = (PUSB_DEVICE)UsbCoreHandle;
- //
- // Acquire the device's lock that protects the status and transfer list in
- // order to synchronize with transfer submission and deletion.
- //
- KeAcquireQueuedLock(Device->Lock);
- //
- // Mark the device as disconnected. Mark this before cancelling the
- // transfer so that no new transfers cannot be submitted.
- //
- Device->Connected = FALSE;
- KeReleaseQueuedLock(Device->Lock);
- //
- // Cancel all of the device's transfers.
- //
- UsbpCancelAllTransfers(UsbCoreHandle);
- return;
- }
- USB_API
- KSTATUS
- UsbReadDeviceString (
- PUSB_DEVICE Device,
- UCHAR StringNumber,
- USHORT Language,
- PUSB_STRING_DESCRIPTOR Buffer
- )
- /*++
- Routine Description:
- This routine reads a string descriptor from a USB device.
- Arguments:
- Device - Supplies a pointer to the device to read from.
- StringNumber - Supplies the string descriptor index of the string to read.
- Language - Supplies the language code.
- Buffer - Supplies a pointer where the string descriptor and data will be
- returned. This buffer must be the size of the maximum string descriptor,
- which is 256 bytes.
- Return Value:
- Status code.
- --*/
- {
- ULONG LengthTransferred;
- USB_SETUP_PACKET SetupPacket;
- KSTATUS Status;
- ULONG Try;
- //
- // Initialize the setup packet. Send the request once with just a single
- // letter's worth of space to get the real size. Some devices don't like
- // it when the length is greater than the actual string they want to send.
- //
- RtlZeroMemory(&SetupPacket, sizeof(USB_SETUP_PACKET));
- SetupPacket.RequestType = USB_SETUP_REQUEST_TO_HOST |
- USB_SETUP_REQUEST_STANDARD |
- USB_SETUP_REQUEST_DEVICE_RECIPIENT;
- SetupPacket.Request = USB_DEVICE_REQUEST_GET_DESCRIPTOR;
- SetupPacket.Index = Language;
- SetupPacket.Length = sizeof(USB_STRING_DESCRIPTOR) + 2;
- SetupPacket.Value = (UsbDescriptorTypeString << 8) | StringNumber;
- for (Try = 0; Try < USB_ENUMERATION_TRANSFER_TRY_COUNT; Try += 1) {
- Status = UsbSendControlTransfer(Device,
- UsbTransferDirectionIn,
- &SetupPacket,
- Buffer,
- SetupPacket.Length,
- &LengthTransferred);
- if (!KSUCCESS(Status)) {
- if ((UsbDebugFlags &
- (USB_DEBUG_ENUMERATION | USB_DEBUG_ERRORS)) != 0) {
- RtlDebugPrint("USB: Failed to read (small) string %d "
- "(language 0x%x) from device 0x%x: status %x,"
- "try %d.\n",
- StringNumber,
- Language,
- Device,
- Status,
- Try + 1);
- }
- }
- if (KSUCCESS(Status)) {
- break;
- }
- }
- if (!KSUCCESS(Status)) {
- if ((UsbDebugFlags & (USB_DEBUG_ENUMERATION | USB_DEBUG_ERRORS)) != 0) {
- RtlDebugPrint("USB: ReadDeviceString Giving up.\n");
- }
- goto ReadDeviceStringEnd;
- }
- //
- // If the string descriptor header was not fully read, exit.
- //
- if (LengthTransferred < sizeof(USB_STRING_DESCRIPTOR)) {
- Status = STATUS_DATA_LENGTH_MISMATCH;
- goto ReadDeviceStringEnd;
- }
- //
- // Now read it for real with the correct size.
- //
- SetupPacket.Length = Buffer->Length;
- for (Try = 0; Try < USB_ENUMERATION_TRANSFER_TRY_COUNT; Try += 1) {
- Status = UsbSendControlTransfer(Device,
- UsbTransferDirectionIn,
- &SetupPacket,
- Buffer,
- SetupPacket.Length,
- &LengthTransferred);
- if (!KSUCCESS(Status)) {
- if ((UsbDebugFlags &
- (USB_DEBUG_ENUMERATION | USB_DEBUG_ERRORS)) != 0) {
- RtlDebugPrint("USB: Failed to read string %d (language 0x%x) "
- "from device 0x%x: status %x, try %d\n",
- StringNumber,
- Language,
- Device,
- Status,
- Try);
- }
- }
- if (KSUCCESS(Status)) {
- break;
- }
- }
- if (!KSUCCESS(Status)) {
- if ((UsbDebugFlags & (USB_DEBUG_ENUMERATION | USB_DEBUG_ERRORS)) != 0) {
- RtlDebugPrint("USB: ReadDeviceString Giving up.\n");
- }
- goto ReadDeviceStringEnd;
- }
- ReadDeviceStringEnd:
- return Status;
- }
- VOID
- UsbpDeviceAddReference (
- PUSB_DEVICE Device
- )
- /*++
- Routine Description:
- This routine increments the reference count on the given device.
- Arguments:
- Device - Supplies a pointer to the device whose reference count should be
- incremented.
- Return Value:
- None.
- --*/
- {
- ULONG OldReferenceCount;
- OldReferenceCount = RtlAtomicAdd32(&(Device->ReferenceCount), 1);
- ASSERT((OldReferenceCount != 0) && (OldReferenceCount < 0x1000));
- return;
- }
- VOID
- UsbpDeviceReleaseReference (
- PUSB_DEVICE Device
- )
- /*++
- Routine Description:
- This routine decrements the reference count on the given device, and
- destroys it if it hits zero.
- Arguments:
- Device - Supplies a pointer to the device whose reference count should be
- decremented.
- Return Value:
- None.
- --*/
- {
- ULONG OldReferenceCount;
- OldReferenceCount = RtlAtomicAdd32(&(Device->ReferenceCount), -1);
- ASSERT((OldReferenceCount != 0) && (OldReferenceCount < 0x1000));
- if (OldReferenceCount == 1) {
- UsbpDestroyDevice(Device);
- }
- return;
- }
- KSTATUS
- UsbpEnumerateDevice (
- PUSB_HUB ParentHub,
- PUSB_DEVICE ParentHubDevice,
- UCHAR PortNumber,
- USB_DEVICE_SPEED DeviceSpeed,
- PHANDLE DeviceHandle
- )
- /*++
- Routine Description:
- This routine creates a new USB device in the system. This routine must be
- called at low level, and must be called with the parent hub's child lock
- held.
- Arguments:
- ParentHub - Supplies a pointer to the parent hub object.
- ParentHubDevice - Supplies the handle of the parent USB hub device
- enumerating the new device.
- PortNumber - Supplies the parent hub's one-based port number where this
- device exists.
- DeviceSpeed - Supplies the speed of the device being enumerated.
- DeviceHandle - Supplies a pointer where a handle representing the device
- will be returned upon success.
- Return Value:
- Status code.
- --*/
- {
- UCHAR Class;
- UCHAR Configuration;
- PUSB_DEVICE Device;
- USB_DEVICE_DESCRIPTOR DeviceDescriptor;
- UCHAR Protocol;
- KSTATUS Status;
- UCHAR Subclass;
- ULONG Try;
- Device = NULL;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- ASSERT(KeIsQueuedLockHeld(ParentHubDevice->ChildLock) != FALSE);
- //
- // Acquire the parent device's controller lock to synchronize access to
- // address zero.
- //
- KeAcquireQueuedLock(ParentHubDevice->Controller->Lock);
- //
- // Create the child device.
- //
- if ((UsbDebugFlags & USB_DEBUG_ENUMERATION) != 0) {
- RtlDebugPrint("USB: Creating device on hub 0x%x port %d.\n",
- ParentHubDevice,
- PortNumber);
- }
- Device = UsbpCreateDevice(DeviceSpeed,
- ParentHubDevice,
- PortNumber,
- ParentHubDevice->Controller);
- if (Device == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto EnumerateDeviceEnd;
- }
- //
- // Attempt to establish communication with the device by asking for the
- // first 8 bytes of the device descriptor, which contain the maximum
- // packet size.
- //
- for (Try = 0; Try < USB_ENUMERATION_TRANSFER_TRY_COUNT; Try += 1) {
- RtlZeroMemory(&DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
- Status = UsbpGetDeviceDescriptor(Device, &DeviceDescriptor, TRUE);
- if (((UsbDebugFlags & USB_DEBUG_ENUMERATION) != 0) ||
- ((!KSUCCESS(Status)) &&
- ((UsbDebugFlags & USB_DEBUG_ERRORS) != 0))) {
- RtlDebugPrint("USB: GetDeviceDescriptor try %d on device %x, "
- "Status %x.\n",
- Try + 1,
- Device,
- Status);
- }
- if (KSUCCESS(Status)) {
- break;
- }
- HlBusySpin(50 * MICROSECONDS_PER_MILLISECOND);
- }
- if (!KSUCCESS(Status)) {
- goto EnumerateDeviceEnd;
- }
- //
- // Reset the device again.
- //
- Status = UsbpResetHubPort(ParentHub, PortNumber - 1);
- if (!KSUCCESS(Status)) {
- if ((UsbDebugFlags & (USB_DEBUG_ENUMERATION | USB_DEBUG_ERRORS)) != 0) {
- RtlDebugPrint("USB: Hub %x Port %x failed to reset.\n",
- ParentHubDevice,
- PortNumber);
- }
- goto EnumerateDeviceEnd;
- }
- //
- // Reset the endpoint to get the newly found max packet size all the way
- // down into the host controller.
- //
- UsbpResetEndpoint(Device, Device->EndpointZero);
- //
- // Request the entire device descriptor.
- //
- for (Try = 0; Try < USB_ENUMERATION_TRANSFER_TRY_COUNT; Try += 1) {
- Status = UsbpGetDeviceDescriptor(Device, &DeviceDescriptor, FALSE);
- if (((UsbDebugFlags & USB_DEBUG_ENUMERATION) != 0) ||
- ((!KSUCCESS(Status)) &&
- ((UsbDebugFlags & USB_DEBUG_ERRORS) != 0))) {
- RtlDebugPrint("USB: GetDeviceDescriptor2 Try %d on device %x, "
- "Status %x.\n",
- Try + 1,
- Device,
- Status);
- }
- if (KSUCCESS(Status)) {
- break;
- }
- }
- if (!KSUCCESS(Status)) {
- goto EnumerateDeviceEnd;
- }
- //
- // Assign the device an address.
- //
- Status = UsbpAssignDeviceAddress(Device);
- if (((UsbDebugFlags & USB_DEBUG_ENUMERATION) != 0) ||
- ((!KSUCCESS(Status)) &&
- ((UsbDebugFlags & USB_DEBUG_ERRORS) != 0))) {
- RtlDebugPrint("USB: AssignDeviceAddress on device %x, Status %x.\n",
- Device,
- Status);
- }
- if (!KSUCCESS(Status)) {
- goto EnumerateDeviceEnd;
- }
- //
- // Remember if the device is a hub.
- //
- if (DeviceDescriptor.Class == UsbDeviceClassHub) {
- Device->Type = UsbDeviceTypeHub;
- }
- Device->ConfigurationCount = DeviceDescriptor.ConfigurationCount;
- //
- // Attempt to read the interesting device strings.
- //
- Status = UsbpReadDeviceStrings(Device, &DeviceDescriptor);
- if (((UsbDebugFlags & USB_DEBUG_ENUMERATION) != 0) ||
- ((!KSUCCESS(Status)) &&
- ((UsbDebugFlags & USB_DEBUG_ERRORS) != 0))) {
- RtlDebugPrint("USB: ReadDeviceStrings on device %x, Status %x.\n",
- Device,
- Status);
- }
- if (!KSUCCESS(Status)) {
- goto EnumerateDeviceEnd;
- }
- //
- // Read the configuration descriptors.
- //
- for (Try = 0; Try < USB_ENUMERATION_TRANSFER_TRY_COUNT; Try += 1) {
- Status = UsbpReadConfigurationDescriptors(Device, &DeviceDescriptor);
- if (((UsbDebugFlags & USB_DEBUG_ENUMERATION) != 0) ||
- ((!KSUCCESS(Status)) &&
- ((UsbDebugFlags & USB_DEBUG_ERRORS) != 0))) {
- RtlDebugPrint("USB: ReadConfigurationDescriptors on device %x, "
- "Status %x.\n",
- Device,
- Status);
- }
- if (KSUCCESS(Status)) {
- break;
- }
- }
- if (!KSUCCESS(Status)) {
- goto EnumerateDeviceEnd;
- }
- //
- // If this is the debug device, avoid exposing it to the operating system,
- // as the debugger is using it.
- //
- if (Device->DebugDevice != FALSE) {
- Configuration = Device->Controller->HandoffData->U.Usb.Configuration;
- Status = UsbSetConfiguration(Device, Configuration, FALSE);
- if (((UsbDebugFlags & USB_DEBUG_DEBUGGER_HANDOFF) != 0) ||
- ((!KSUCCESS(Status)) &&
- ((UsbDebugFlags & USB_DEBUG_ERRORS) != 0))) {
- RtlDebugPrint("USB: Set configuration %d for debug device %x: "
- "%x.\n",
- Configuration,
- Device,
- Status);
- }
- if (!KSUCCESS(Status)) {
- goto EnumerateDeviceEnd;
- }
- //
- // The debug device is back online, reconnect!
- //
- KdConnect();
- } else {
- //
- // Now that the device is properly enumerated, expose it to the
- // operating system.
- //
- UsbpGetDeviceClass(Device, &Class, &Subclass, &Protocol);
- Status = UsbpCreateOsDevice(Device,
- Class,
- Subclass,
- Protocol,
- 0,
- FALSE,
- &(Device->Device));
- if (((UsbDebugFlags & USB_DEBUG_ENUMERATION) != 0) ||
- ((!KSUCCESS(Status)) &&
- ((UsbDebugFlags & USB_DEBUG_ERRORS) != 0))) {
- RtlDebugPrint("USB: CreateOsDevice on device %x, Status %x.\n",
- Device,
- Status);
- }
- if (!KSUCCESS(Status)) {
- goto EnumerateDeviceEnd;
- }
- }
- //
- // Add the device to the list of children.
- //
- INSERT_BEFORE(&(Device->ListEntry), &(ParentHubDevice->ChildList));
- Status = STATUS_SUCCESS;
- if ((UsbDebugFlags & USB_DEBUG_ENUMERATION) != 0) {
- RtlDebugPrint("USB: Enumeration complete for device %x.\n", Device);
- }
- EnumerateDeviceEnd:
- KeReleaseQueuedLock(ParentHubDevice->Controller->Lock);
- if (!KSUCCESS(Status)) {
- if (Device != NULL) {
- //
- // Remove the device.
- //
- ASSERT(Device->ReferenceCount == 1);
- UsbpRemoveDevice(Device);
- Device = NULL;
- }
- }
- if (Device == NULL) {
- *DeviceHandle = INVALID_HANDLE;
- } else {
- *DeviceHandle = (HANDLE)Device;
- }
- return Status;
- }
- VOID
- UsbpRemoveDevice (
- PUSB_DEVICE Device
- )
- /*++
- Routine Description:
- This routine removes a device from its parent hub. The parent USB device's
- child lock should be held.
- Arguments:
- Device - Supplies a pointer to the device that is to be removed.
- Return Value:
- None.
- --*/
- {
- ASSERT(KeGetRunLevel() == RunLevelLow);
- ASSERT(Device->Parent->Type != UsbDeviceTypeNonHub);
- ASSERT(KeIsQueuedLockHeld(Device->Parent->ChildLock) != FALSE);
- //
- // Remove the device from the parent's list.
- //
- if (Device->ListEntry.Next != NULL) {
- LIST_REMOVE(&(Device->ListEntry));
- Device->ListEntry.Next = NULL;
- }
- //
- // Remove the device from the global list.
- //
- if (Device->GlobalListEntry.Next != NULL) {
- KeAcquireQueuedLock(UsbDeviceListLock);
- LIST_REMOVE(&(Device->GlobalListEntry));
- KeReleaseQueuedLock(UsbDeviceListLock);
- Device->GlobalListEntry.Next = NULL;
- }
- //
- // Release the reference on the device that the hub took during
- // enumeration.
- //
- UsbpDeviceReleaseReference(Device);
- return;
- }
- KSTATUS
- UsbpReserveDeviceAddress (
- PUSB_HOST_CONTROLLER Controller,
- PUSB_DEVICE Device,
- UCHAR Address
- )
- /*++
- Routine Description:
- This routine assigns the given device to a specific address.
- Arguments:
- Controller - Supplies a pointer to the controller the device lives on.
- Device - Supplies a pointer to the USB device reserving the address. This
- can be NULL.
- Address - Supplies the address to reserve.
- Return Value:
- STATUS_SUCCESS on success.
- STATUS_INSUFFICIENT_RESOURCES if an allocation failed.
- STATUS_RESOURCE_IN_USE if the address is already assigned.
- --*/
- {
- ULONG AllocationSize;
- PUSB_DEVICE *Segment;
- ULONG SegmentIndex;
- ULONG SegmentOffset;
- SegmentIndex = Address / USB_HOST_ADDRESSES_PER_SEGMENT;
- if (SegmentIndex >= USB_HOST_ADDRESS_SEGMENT_COUNT) {
- return STATUS_INVALID_PARAMETER;
- }
- Segment = Controller->ChildrenByAddress[SegmentIndex];
- //
- // If the segment is not yet allocated, allocate it now.
- //
- if (Segment == NULL) {
- AllocationSize = sizeof(PUSB_DEVICE) * USB_HOST_ADDRESSES_PER_SEGMENT;
- Segment = MmAllocateNonPagedPool(AllocationSize,
- USB_CORE_ALLOCATION_TAG);
- if (Segment == NULL) {
- return STATUS_INSUFFICIENT_RESOURCES;
- }
- RtlZeroMemory(Segment, AllocationSize);
- Controller->ChildrenByAddress[SegmentIndex] = Segment;
- }
- //
- // Fail if there's already something valid in that slot.
- //
- SegmentOffset = Address % USB_HOST_ADDRESSES_PER_SEGMENT;
- if ((Segment[SegmentOffset] != NULL) &&
- (Segment[SegmentOffset] != (PUSB_DEVICE)-1)) {
- return STATUS_RESOURCE_IN_USE;
- }
- //
- // Reserve it.
- //
- if (Device == NULL) {
- Segment[SegmentOffset] = (PUSB_DEVICE)-1;
- } else {
- Segment[SegmentOffset] = Device;
- }
- return STATUS_SUCCESS;
- }
- //
- // --------------------------------------------------------- Internal Functions
- //
- KSTATUS
- UsbpEnumerateRootHub (
- PUSB_HOST_CONTROLLER Controller
- )
- /*++
- Routine Description:
- This routine enumerates a root hub off of a host controller.
- Arguments:
- Controller - Supplies a pointer to the host controller.
- Return Value:
- Status code.
- --*/
- {
- PUSB_DEVICE RootDevice;
- KSTATUS Status;
- ASSERT(Controller->RootDevice == NULL);
- //
- // Create a USB device structure.
- //
- RootDevice = UsbpCreateDevice(Controller->Device.Speed,
- NULL,
- 0,
- Controller);
- if (RootDevice == NULL) {
- Status = STATUS_INVALID_PARAMETER;
- goto EnumerateRootHubEnd;
- }
- RootDevice->Type = UsbDeviceTypeRootHub;
- Controller->RootDevice = RootDevice;
- //
- // Create the OS device to go with the USB device.
- //
- Status = IoCreateDevice(Controller->Device.DriverObject,
- NULL,
- Controller->Device.DeviceObject,
- USB_ROOT_HUB_DEVICE_ID,
- NULL,
- NULL,
- &(RootDevice->Device));
- if (!KSUCCESS(Status)) {
- goto EnumerateRootHubEnd;
- }
- Status = STATUS_SUCCESS;
- EnumerateRootHubEnd:
- if (!KSUCCESS(Status)) {
- if (RootDevice != NULL) {
- ASSERT(RootDevice->ReferenceCount == 1);
- UsbpRemoveDevice(RootDevice);
- }
- }
- return Status;
- }
- PUSB_DEVICE
- UsbpCreateDevice (
- USB_DEVICE_SPEED DeviceSpeed,
- PUSB_DEVICE ParentDevice,
- UCHAR PortNumber,
- PUSB_HOST_CONTROLLER ParentController
- )
- /*++
- Routine Description:
- This routine allocates and initializes a new USB device structure. This
- routine must be called at low level.
- Arguments:
- DeviceSpeed - Supplies the speed of the device being enumerated.
- ParentDevice - Supplies an optional pointer to the hub device enumerating
- this device.
- PortNumber - Supplies the parent hub's one-based port number where this
- device exists.
- ParentController - Supplies a pointer to the host controller that this
- device descends from.
- Return Value:
- Status code.
- --*/
- {
- PUSB_DEVICE Device;
- ULONG MaxPacketSize;
- KSTATUS Status;
- Device = NULL;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- ASSERT(DeviceSpeed != UsbDeviceSpeedInvalid);
- ASSERT((ParentDevice == NULL) || (PortNumber != 0));
- //
- // It is illegal to enumerate a child object with a different parent host
- // controller.
- //
- ASSERT((ParentDevice == NULL) ||
- (ParentDevice->Controller == ParentController));
- //
- // Create a device structure.
- //
- Device = MmAllocateNonPagedPool(sizeof(USB_DEVICE),
- USB_CORE_ALLOCATION_TAG);
- if (Device == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto CreateDeviceEnd;
- }
- RtlZeroMemory(Device, sizeof(USB_DEVICE));
- INITIALIZE_LIST_HEAD(&(Device->ChildList));
- INITIALIZE_LIST_HEAD(&(Device->ConfigurationList));
- INITIALIZE_LIST_HEAD(&(Device->TransferList));
- Device->ReferenceCount = 1;
- Device->Speed = DeviceSpeed;
- Device->Controller = ParentController;
- Device->Parent = ParentDevice;
- Device->PortNumber = PortNumber;
- Device->Depth = 0;
- if (ParentDevice != NULL) {
- Device->Depth = ParentDevice->Depth + 1;
- }
- Device->ChildLock = KeCreateQueuedLock();
- if (Device->ChildLock == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto CreateDeviceEnd;
- }
- Device->ConfigurationLock = KeCreateQueuedLock();
- if (Device->ConfigurationLock == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto CreateDeviceEnd;
- }
- Device->Lock = KeCreateQueuedLock();
- if (Device->Lock == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto CreateDeviceEnd;
- }
- ASSERT(Device->ListEntry.Next == NULL);
- ASSERT(Device->GlobalListEntry.Next == NULL);
- //
- // Create the default control endpoint.
- //
- MaxPacketSize = 8;
- Status = UsbpCreateEndpoint(Device,
- 0,
- UsbTransferBidirectional,
- UsbTransferTypeControl,
- MaxPacketSize,
- 0,
- &(Device->EndpointZero));
- if (!KSUCCESS(Status)) {
- goto CreateDeviceEnd;
- }
- //
- // Mark the device as connected before adding it to the global list. The
- // device needs to be marked connected for transfers to be submitted.
- //
- Device->Connected = TRUE;
- //
- // Insert the device onto the global list.
- //
- KeAcquireQueuedLock(UsbDeviceListLock);
- INSERT_AFTER(&(Device->GlobalListEntry), &UsbDeviceList);
- KeReleaseQueuedLock(UsbDeviceListLock);
- Status = STATUS_SUCCESS;
- CreateDeviceEnd:
- if (!KSUCCESS(Status)) {
- if (Device != NULL) {
- if (Device->EndpointZero != NULL) {
- ASSERT(Device->EndpointZero->ReferenceCount == 1);
- UsbpEndpointReleaseReference(Device, Device->EndpointZero);
- }
- if (Device->ChildLock != NULL) {
- KeDestroyQueuedLock(Device->ChildLock);
- }
- if (Device->ConfigurationLock != NULL) {
- KeDestroyQueuedLock(Device->ConfigurationLock);
- }
- if (Device->Lock != NULL) {
- KeDestroyQueuedLock(Device->Lock);
- }
- MmFreeNonPagedPool(Device);
- Device = NULL;
- }
- }
- return Device;
- }
- VOID
- UsbpDestroyDevice (
- PUSB_DEVICE Device
- )
- /*++
- Routine Description:
- This routine releases the memory associated with a USB device. It is
- assumed that the device is already pulled off of all lists to which it
- belonged. This routine must be called at low level.
- Arguments:
- Device - Supplies a pointer to the device to release.
- Return Value:
- None.
- --*/
- {
- PUSB_CONFIGURATION Configuration;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- //
- // Assert that all references have been released, the device has no more
- // children and that it has no more transfers.
- //
- ASSERT(Device->ReferenceCount == 0);
- ASSERT(LIST_EMPTY(&(Device->ChildList)) != FALSE);
- ASSERT(LIST_EMPTY(&(Device->TransferList)) != FALSE);
- //
- // Unassign the device's bus address.
- //
- if (Device->Type != UsbDeviceTypeRootHub) {
- UsbpUnassignDeviceAddress(Device);
- }
- //
- // Release the reference taken on the endpoint.
- //
- UsbpEndpointReleaseReference(Device, Device->EndpointZero);
- //
- // Release all cached configurations.
- //
- while (LIST_EMPTY(&(Device->ConfigurationList)) == FALSE) {
- Configuration = LIST_VALUE(Device->ConfigurationList.Next,
- USB_CONFIGURATION,
- ListEntry);
- LIST_REMOVE(&(Configuration->ListEntry));
- MmFreePagedPool(Configuration);
- }
- //
- // Destroy all other structures.
- //
- KeDestroyQueuedLock(Device->Lock);
- KeDestroyQueuedLock(Device->ConfigurationLock);
- KeDestroyQueuedLock(Device->ChildLock);
- if (Device->Manufacturer != NULL) {
- MmFreePagedPool(Device->Manufacturer);
- }
- if (Device->ProductName != NULL) {
- MmFreePagedPool(Device->ProductName);
- }
- if (Device->SerialNumber != NULL) {
- MmFreePagedPool(Device->SerialNumber);
- }
- MmFreeNonPagedPool(Device);
- return;
- }
- KSTATUS
- UsbpGetDeviceDescriptor (
- PUSB_DEVICE Device,
- PUSB_DEVICE_DESCRIPTOR DeviceDescriptor,
- BOOL FirstEightBytesOnly
- )
- /*++
- Routine Description:
- This routine attempts to get the device descriptor out of a new USB device.
- Arguments:
- Device - Supplies a pointer to the device to query.
- DeviceDescriptor - Supplies a pointer where the device descriptor will be
- returned.
- FirstEightBytesOnly - Supplies a boolean indicating if only the first 8
- bytes of the device descriptor should be retrieved.
- Return Value:
- Status code.
- --*/
- {
- ULONG LengthTransferred;
- USB_SETUP_PACKET Setup;
- KSTATUS Status;
- //
- // Create the setup packet to get the device descriptor.
- //
- RtlZeroMemory(&Setup, sizeof(USB_SETUP_PACKET));
- Setup.RequestType = USB_SETUP_REQUEST_TO_HOST |
- USB_SETUP_REQUEST_STANDARD |
- USB_SETUP_REQUEST_DEVICE_RECIPIENT;
- Setup.Request = USB_DEVICE_REQUEST_GET_DESCRIPTOR;
- Setup.Value = UsbDescriptorTypeDevice << 8;
- Setup.Index = 0;
- if (FirstEightBytesOnly != FALSE) {
- Setup.Length = 8;
- } else {
- Setup.Length = sizeof(USB_DEVICE_DESCRIPTOR);
- }
- Status = UsbSendControlTransfer(Device,
- UsbTransferDirectionIn,
- &Setup,
- DeviceDescriptor,
- Setup.Length,
- &LengthTransferred);
- if (!KSUCCESS(Status)) {
- goto GetDeviceDescriptorEnd;
- }
- if (LengthTransferred != Setup.Length) {
- Status = STATUS_DATA_LENGTH_MISMATCH;
- goto GetDeviceDescriptorEnd;
- }
- //
- // Save the values just grabbed into the device if they were retrieved.
- // If only the first 8 bytes were grabbed, that's enough to determine the
- // max packet size so that the rest of the device descriptor can be
- // requested next.
- //
- Device->EndpointZero->MaxPacketSize = DeviceDescriptor->MaxPacketSize;
- if (FirstEightBytesOnly == FALSE) {
- Device->VendorId = DeviceDescriptor->VendorId;
- Device->ProductId = DeviceDescriptor->ProductId;
- Device->ClassCode = DeviceDescriptor->Class;
- Device->SubclassCode = DeviceDescriptor->Subclass;
- Device->ProtocolCode = DeviceDescriptor->Protocol;
- }
- Status = STATUS_SUCCESS;
- GetDeviceDescriptorEnd:
- return Status;
- }
- KSTATUS
- UsbpAssignDeviceAddress (
- PUSB_DEVICE Device
- )
- /*++
- Routine Description:
- This routine assigns a new address to the USB device. This routine must be
- called at low level, and assumes the controller lock is held.
- Arguments:
- Device - Supplies a pointer to the device to assign an address to.
- Return Value:
- Status code. On success, the new device address will be returned inside the
- device, and this routine will send a SET_ADDRESS command to the device.
- --*/
- {
- UCHAR AddressIndex;
- BOOL AddressLockHeld;
- PUSB_HOST_CONTROLLER Controller;
- UCHAR FoundAddress;
- ULONG LengthTransferred;
- UCHAR ReservedAddress;
- PUSB_DEVICE *Segment;
- ULONG SegmentIndex;
- USB_SETUP_PACKET SetupPacket;
- KSTATUS Status;
- AddressLockHeld = FALSE;
- FoundAddress = 0;
- ASSERT(KeGetRunLevel() == RunLevelLow);
- ASSERT(Device->BusAddress == 0);
- ASSERT(KeIsQueuedLockHeld(Device->Controller->Lock) != FALSE);
- //
- // Acquire the controller's address lock in order to find an address.
- //
- Controller = Device->Controller;
- KeAcquireQueuedLock(Controller->AddressLock);
- AddressLockHeld = TRUE;
- ReservedAddress = UsbpGetReservedDeviceAddress(Device);
- if (ReservedAddress != 0) {
- //
- // Make the association between the address (which is just reserved)
- // to the actual device pointer.
- //
- Status = UsbpReserveDeviceAddress(Controller, Device, ReservedAddress);
- ASSERT(KSUCCESS(Status));
- FoundAddress = ReservedAddress;
- //
- // This device is not special, go allocate an address.
- //
- } else {
- if (Controller->ControllerFull != FALSE) {
- Status = STATUS_RESOURCE_IN_USE;
- goto AssignDeviceAddressEnd;
- }
- //
- // Loop through every segment of addresses. Segmentation of the 128
- // addresses is done to cut down on wasted memory allocations.
- //
- for (SegmentIndex = 0;
- SegmentIndex < USB_HOST_ADDRESS_SEGMENT_COUNT;
- SegmentIndex += 1) {
- Segment = Controller->ChildrenByAddress[SegmentIndex];
- for (AddressIndex = 0;
- AddressIndex < USB_HOST_ADDRESSES_PER_SEGMENT;
- AddressIndex += 1) {
- //
- // Skip address zero.
- //
- if ((SegmentIndex == 0) && (AddressIndex == 0)) {
- continue;
- }
- //
- // If there is no segment or the index is free, try to reserve
- // it.
- //
- if ((Segment == NULL) || (Segment[AddressIndex] == NULL)) {
- FoundAddress =
- (SegmentIndex * USB_HOST_ADDRESSES_PER_SEGMENT) +
- AddressIndex;
- Status = UsbpReserveDeviceAddress(Controller,
- Device,
- FoundAddress);
- if (KSUCCESS(Status)) {
- break;
- }
- FoundAddress = 0;
- }
- }
- if (FoundAddress != 0) {
- break;
- }
- }
- }
- //
- // If an address could not be allocated, the bus is full of devices!
- //
- if (FoundAddress == 0) {
- Controller->ControllerFull = TRUE;
- Status = STATUS_RESOURCE_IN_USE;
- goto AssignDeviceAddressEnd;
- }
- //
- // Now that an address has been acquired, release the address lock.
- //
- KeReleaseQueuedLock(Controller->AddressLock);
- AddressLockHeld = FALSE;
- //
- // Send a SET_ADDRESS command to the device to get it off of address zero.
- //
- RtlZeroMemory(&SetupPacket, sizeof(USB_SETUP_PACKET));
- SetupPacket.RequestType = USB_SETUP_REQUEST_TO_DEVICE |
- USB_SETUP_REQUEST_STANDARD |
- USB_SETUP_REQUEST_DEVICE_RECIPIENT;
- SetupPacket.Request = USB_DEVICE_REQUEST_SET_ADDRESS;
- SetupPacket.Value = FoundAddress;
- SetupPacket.Index = 0;
- SetupPacket.Length = 0;
- Status = UsbSendControlTransfer(Device,
- UsbTransferDirectionOut,
- &SetupPacket,
- NULL,
- 0,
- &LengthTransferred);
- if (!KSUCCESS(Status)) {
- goto AssignDeviceAddressEnd;
- }
- //
- // Wait 2ms for the set address request to settle (see section 9.2.6.3 of
- // the USB 2.0 specification).
- //
- HlBusySpin(2 * 1000);
- Device->BusAddress = FoundAddress;
- Status = STATUS_SUCCESS;
- AssignDeviceAddressEnd:
- //
- // Release the address lock first before unassigning the address. That
- // routine also acquires the lock.
- //
- if (AddressLockHeld != FALSE) {
- KeReleaseQueuedLock(Controller->AddressLock);
- }
- if (!KSUCCESS(Status)) {
- //
- // Unassign the bus address if it was assigned.
- //
- if (FoundAddress != 0) {
- UsbpUnassignDeviceAddress(Device);
- }
- }
- return Status;
- }
- VOID
- UsbpUnassignDeviceAddress (
- PUSB_DEVICE Device
- )
- /*++
- Routine Description:
- This routine unassigns a USB device's address.
- Arguments:
- Device - Supplies a pointer to the USB device whose address is to be
- unassigned.
- Return Value:
- None.
- --*/
- {
- ULONG AddressIndex;
- PUSB_HOST_CONTROLLER Controller;
- PUSB_DEVICE *Segment;
- BOOL SegmentEmpty;
- ULONG SegmentIndex;
- //
- // There's nothing to do if the device never received an address.
- //
- if (Device->BusAddress == 0) {
- return;
- }
- //
- // Acquire the controller's address lock before releasing the address.
- //
- Controller = Device->Controller;
- KeAcquireQueuedLock(Controller->AddressLock);
- //
- // Release the address and mark that the controller is not full.
- //
- SegmentIndex = Device->BusAddress / USB_HOST_ADDRESSES_PER_SEGMENT;
- Segment = Controller->ChildrenByAddress[SegmentIndex];
- Segment[Device->BusAddress % USB_HOST_ADDRESSES_PER_SEGMENT] = NULL;
- Device->BusAddress = 0;
- Controller->ControllerFull = FALSE;
- //
- // Loop through the segment addresses to determine if it is empty.
- //
- SegmentEmpty = TRUE;
- for (AddressIndex = 0;
- AddressIndex < USB_HOST_ADDRESSES_PER_SEGMENT;
- AddressIndex += 1) {
- //
- // Skip address zero.
- //
- if ((SegmentIndex == 0) && (AddressIndex == 0)) {
- continue;
- }
- //
- // If the space is not free, declare that the segment is not empty.
- //
- if (Segment[AddressIndex] != NULL) {
- SegmentEmpty = FALSE;
- break;
- }
- }
- //
- // If the segment is empty, null it out.
- //
- if (SegmentEmpty != FALSE) {
- Controller->ChildrenByAddress[SegmentIndex] = NULL;
- }
- //
- // Release the address lock.
- //
- KeReleaseQueuedLock(Controller->AddressLock);
- //
- // With the lock released, free the segment if it was empty.
- //
- if (SegmentEmpty != FALSE) {
- MmFreeNonPagedPool(Segment);
- }
- return;
- }
- KSTATUS
- UsbpReadDeviceStrings (
- PUSB_DEVICE Device,
- PUSB_DEVICE_DESCRIPTOR DeviceDescriptor
- )
- /*++
- Routine Description:
- This routine attempts to read the manufacturer, product, and serial number
- strings from the device, if they exist.
- Arguments:
- Device - Supplies a pointer to the device to assign an address to.
- DeviceDescriptor - Supplies a pointer to the device descriptor (which
- contains the string descriptor indices).
- Return Value:
- Status code. On success, the strings will be allocated and filled into the
- device.
- --*/
- {
- ULONG LanguageCount;
- PUSHORT LanguageId;
- ULONG LanguageIndex;
- KSTATUS Status;
- PUSB_STRING_DESCRIPTOR StringDescriptor;
- BOOL UsEnglishSupported;
- StringDescriptor = NULL;
- //
- // If none of the strings being sought exist, just exit.
- //
- if ((DeviceDescriptor->ManufacturerStringIndex == 0) &&
- (DeviceDescriptor->ProductStringIndex == 0) &&
- (DeviceDescriptor->SerialNumberStringIndex == 0)) {
- Status = STATUS_SUCCESS;
- goto ReadDeviceStringsEnd;
- }
- //
- // Create a temporary string descriptor of the maximum possible size.
- //
- StringDescriptor = MmAllocateNonPagedPool(USB_STRING_DESCRIPTOR_MAX_SIZE,
- USB_CORE_ALLOCATION_TAG);
- if (StringDescriptor == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ReadDeviceStringsEnd;
- }
- //
- // Attempt to read string 0, which returns the list of supported languages.
- //
- Status = UsbReadDeviceString(Device, 0, 0, StringDescriptor);
- if (!KSUCCESS(Status)) {
- if ((UsbDebugFlags & (USB_DEBUG_ENUMERATION | USB_DEBUG_ERRORS)) != 0) {
- RtlDebugPrint("USB: Device 0x%x failed to read language ID string "
- "0.\n",
- Device);
- }
- goto ReadDeviceStringsEnd;
- }
- LanguageCount = StringDescriptor->Length / 2;
- LanguageId = (PUSHORT)(StringDescriptor + 1);
- UsEnglishSupported = FALSE;
- for (LanguageIndex = 0; LanguageIndex < LanguageCount; LanguageIndex += 1) {
- if (LanguageId[LanguageIndex] == USB_LANGUAGE_ENGLISH_US) {
- UsEnglishSupported = TRUE;
- }
- }
- if (UsEnglishSupported == FALSE) {
- if ((UsbDebugFlags & USB_DEBUG_ENUMERATION) != 0) {
- RtlDebugPrint("USB: Device %x supports %d languages but US "
- "English (0x0409) is not one of them. Skipping "
- "device strings.\n",
- Device);
- Status = STATUS_SUCCESS;
- goto ReadDeviceStringsEnd;
- }
- }
- //
- // Attempt to get the manufacturer string descriptor.
- //
- if (DeviceDescriptor->ManufacturerStringIndex != 0) {
- Status = UsbReadDeviceString(Device,
- DeviceDescriptor->ManufacturerStringIndex,
- USB_LANGUAGE_ENGLISH_US,
- StringDescriptor);
- if (!KSUCCESS(Status)) {
- goto ReadDeviceStringsEnd;
- }
- if (Device->Manufacturer != NULL) {
- MmFreePagedPool(Device->Manufacturer);
- }
- Device->Manufacturer =
- UsbpCreateAnsiStringFromStringDescriptor(StringDescriptor);
- if (Device->Manufacturer == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ReadDeviceStringsEnd;
- }
- }
- //
- // Attempt to get the product name string descriptor.
- //
- if (DeviceDescriptor->ProductStringIndex != 0) {
- Status = UsbReadDeviceString(Device,
- DeviceDescriptor->ProductStringIndex,
- USB_LANGUAGE_ENGLISH_US,
- StringDescriptor);
- if (!KSUCCESS(Status)) {
- goto ReadDeviceStringsEnd;
- }
- if (Device->ProductName != NULL) {
- MmFreePagedPool(Device->ProductName);
- }
- Device->ProductName =
- UsbpCreateAnsiStringFromStringDescriptor(StringDescriptor);
- if (Device->ProductName == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ReadDeviceStringsEnd;
- }
- }
- //
- // Attempt to get the serial number string descriptor.
- //
- if (DeviceDescriptor->SerialNumberStringIndex != 0) {
- Status = UsbReadDeviceString(Device,
- DeviceDescriptor->SerialNumberStringIndex,
- USB_LANGUAGE_ENGLISH_US,
- StringDescriptor);
- if (!KSUCCESS(Status)) {
- goto ReadDeviceStringsEnd;
- }
- if (Device->SerialNumber != NULL) {
- MmFreePagedPool(Device->SerialNumber);
- }
- Device->SerialNumber =
- UsbpCreateAnsiStringFromStringDescriptor(StringDescriptor);
- if (Device->SerialNumber == NULL) {
- Status = STATUS_INSUFFICIENT_RESOURCES;
- goto ReadDeviceStringsEnd;
- }
- }
- Status = STATUS_SUCCESS;
- ReadDeviceStringsEnd:
- if (KSUCCESS(Status)) {
- if ((UsbDebugFlags & USB_DEBUG_ENUMERATION) != 0) {
- RtlDebugPrint("USB: New Device VID: %04x, PID %04x, Class %d, "
- "Address %d\nUSB: Manufacturer: \"%s\" Product Name: "
- "\"%s\" Serial Number: \"%s\".\n",
- DeviceDescriptor->VendorId,
- DeviceDescriptor->ProductId,
- DeviceDescriptor->Class,
- Device->BusAddress,
- Device->Manufacturer,
- Device->ProductName,
- Device->SerialNumber);
- }
- }
- if (StringDescriptor != NULL) {
- MmFreeNonPagedPool(StringDescriptor);
- }
- return Status;
- }
- PSTR
- UsbpCreateAnsiStringFromStringDescriptor (
- PUSB_STRING_DESCRIPTOR StringDescriptor
- )
- /*++
- Routine Description:
- This routine converts a unicode string descriptor into an ANSI string.
- Arguments:
- StringDescriptor - Supplies a pointer to the string descriptor to convert.
- Return Value:
- Returns a pointer to the string on success. The caller is responsible for
- freeing this new string from paged pool.
- NULL on failure.
- --*/
- {
- ULONG Index;
- ULONG Length;
- PSTR NewString;
- PSTR UnicodeString;
- if ((StringDescriptor->Length < 2) ||
- ((StringDescriptor->Length & 0x1) != 0)) {
- return NULL;
- }
- Length = (StringDescriptor->Length / 2) - 1;
- NewString = MmAllocatePagedPool(Length + 1, USB_CORE_ALLOCATION_TAG);
- if (NewString == NULL) {
- return NULL;
- }
- Index = 0;
- UnicodeString = (PSTR)(StringDescriptor + 1);
- while (Index < Length) {
- NewString[Index] = *UnicodeString;
- Index += 1;
- UnicodeString += 2;
- }
- NewString[Index] = '\0';
- return NewString;
- }
- VOID
- UsbpGetDeviceClass (
- PUSB_DEVICE Device,
- PUCHAR Class,
- PUCHAR Subclass,
- PUCHAR Protocol
- )
- /*++
- Routine Description:
- This routine returns the given device's effective class, subclass, and
- protocol identifiers. It will return information from the device descriptor
- if it is filled in, or the first interface if there is only one
- configuration and one interface.
- Arguments:
- Device - Supplies a pointer to the device to enumerate.
- Class - Supplies a pointer where the class code will be returned.
- Subclass - Supplies a pointer where the sub-class code will be returned.
- Protocol - Supplies a pointer where the protocol code will be returned.
- Return Value:
- Status code.
- --*/
- {
- UCHAR ClassCode;
- PUSB_CONFIGURATION Configuration;
- PUSB_INTERFACE_DESCRIPTION Interface;
- PLIST_ENTRY InterfaceListHead;
- UCHAR ProtocolCode;
- UCHAR SubclassCode;
- //
- // If the class code in the device descriptor is set, use it. If it defers
- // to the interfaces, look to see if there is only one interface. If so,
- // use that one.
- //
- ClassCode = Device->ClassCode;
- SubclassCode = Device->SubclassCode;
- ProtocolCode = Device->ProtocolCode;
- if (ClassCode == UsbDeviceClassUseInterface) {
- ASSERT(LIST_EMPTY(&(Device->ConfigurationList)) == FALSE);
- Configuration = LIST_VALUE(Device->ConfigurationList.Next,
- USB_CONFIGURATION,
- ListEntry);
- InterfaceListHead = &(Configuration->Description.InterfaceListHead);
- ASSERT(LIST_EMPTY(InterfaceListHead) == FALSE);
- //
- // If there's only one interface on the list, use it.
- //
- if (InterfaceListHead->Next == InterfaceListHead->Previous) {
- Interface = LIST_VALUE(InterfaceListHead->Next,
- USB_INTERFACE_DESCRIPTION,
- ListEntry);
- ClassCode = Interface->Descriptor.Class;
- SubclassCode = Interface->Descriptor.Subclass;
- ProtocolCode = Interface->Descriptor.Protocol;
- //
- // Also save these back directly into the device.
- //
- Device->ClassCode = ClassCode;
- Device->SubclassCode = SubclassCode;
- Device->ProtocolCode = ProtocolCode;
- }
- }
- *Class = ClassCode;
- *Subclass = SubclassCode;
- *Protocol = ProtocolCode;
- return;
- }
- KSTATUS
- UsbpCreateOsDevice (
- PUSB_DEVICE Device,
- UCHAR Class,
- UCHAR Subclass,
- UCHAR Protocol,
- UCHAR Interface,
- BOOL InterfaceDevice,
- PDEVICE *CreatedDevice
- )
- /*++
- Routine Description:
- This routine creates an operating system device object for the given USB
- object.
- Arguments:
- Device - Supplies a pointer to the USB device corresponding to the soon-to-
- be-created OS device.
- Class - Supplies the USB device class code of the new device.
- Subclass - Supplies the USB subclass code of the new device.
- Protocol - Supplies the USB protocol code of the new device.
- Interface - Supplies an optional interface number for the device. If the
- interface device boolean flag is false, this parameter is ignored.
- InterfaceDevice - Supplies a boolean indicating if this device is just
- enumerating an interface off a pre-existing device, or if it's
- enumerating the device itself. For interface devies, the interface
- number is tacked onto the device ID.
- CreatedDevice - Supplies a pointer where the pointer to the fresh OS
- device will be returned.
- Return Value:
- Status code.
- --*/
- {
- PSTR DeviceClass;
- CHAR DeviceId[USB_DEVICE_ID_LENGTH + 1];
- PDRIVER Driver;
- PDEVICE Parent;
- KSTATUS Status;
- *CreatedDevice = NULL;
- //
- // Create the device ID string.
- //
- if (InterfaceDevice != FALSE) {
- RtlPrintToString(DeviceId,
- USB_DEVICE_ID_LENGTH + 1,
- CharacterEncodingDefault,
- USB_DEVICE_ID_WITH_INTERFACE_FORMAT,
- Device->VendorId,
- Device->ProductId,
- Interface);
- } else {
- RtlPrintToString(DeviceId,
- USB_DEVICE_ID_LENGTH + 1,
- CharacterEncodingDefault,
- USB_DEVICE_ID_FORMAT,
- Device->VendorId,
- Device->ProductId);
- }
- //
- // Set the class ID if applicable.
- //
- switch (Class) {
- case UsbDeviceClassUseInterface:
- DeviceClass = USB_COMPOUND_DEVICE_CLASS_ID;
- break;
- case UsbDeviceClassHid:
- DeviceClass = USB_HID_CLASS_ID;
- if ((Subclass == USB_HID_BOOT_INTERFACE_SUBCLASS) &&
- (Protocol == USB_HID_BOOT_KEYBOARD_PROTOCOL)) {
- DeviceClass = USB_BOOT_KEYBOARD_CLASS_ID;
- } else if ((Subclass == USB_HID_BOOT_INTERFACE_SUBCLASS) &&
- (Protocol == USB_HID_BOOT_MOUSE_PROTOCOL)) {
- DeviceClass = USB_BOOT_MOUSE_CLASS_ID;
- }
- break;
- case UsbInterfaceClassMassStorage:
- DeviceClass = USB_MASS_STORAGE_CLASS_ID;
- break;
- case UsbDeviceClassHub:
- DeviceClass = USB_HUB_CLASS_ID;
- break;
- default:
- DeviceClass = NULL;
- break;
- }
- //
- // For interface devices, the device itself is the parent.
- //
- if (InterfaceDevice != FALSE) {
- Driver = Device->Driver;
- Parent = Device->Device;
- } else {
- ASSERT(Device->Parent != NULL);
- Driver = Device->Parent->Driver;
- Parent = Device->Parent->Device;
- }
- ASSERT((Driver != NULL) && (Parent != NULL));
- //
- // Create the OS device object, making the device visible to the system.
- //
- Status = IoCreateDevice(Driver,
- NULL,
- Parent,
- DeviceId,
- DeviceClass,
- NULL,
- CreatedDevice);
- if (!KSUCCESS(Status)) {
- goto CreateOsDeviceEnd;
- }
- Status = STATUS_SUCCESS;
- CreateOsDeviceEnd:
- return Status;
- }
- UCHAR
- UsbpGetReservedDeviceAddress (
- PUSB_DEVICE Device
- )
- /*++
- Routine Description:
- This routine returns the device's reserved address if it is a special
- device. The debug device and debug device hub both have reserved addresses
- since they're being used up in debugger land.
- Arguments:
- Device - Supplies a pointer to the device whose address is being assigned.
- Return Value:
- Returns the device's reserved address on success.
- 0 if the device does not have a reserved address.
- --*/
- {
- PUSB_DEVICE CheckDevice;
- ULONG CheckIndex;
- PUSB_HOST_CONTROLLER Controller;
- PDEBUG_USB_HANDOFF_DATA HandoffData;
- ULONG PathIndex;
- Controller = Device->Controller;
- if (Controller->HandoffData == NULL) {
- return 0;
- }
- HandoffData = &(Controller->HandoffData->U.Usb);
- //
- // If this is not the debug device itself or the hub of the debug device,
- // then the device is not special.
- //
- ASSERT(Device->Depth != 0);
- PathIndex = Device->Depth - 1;
- if ((PathIndex != HandoffData->DevicePathSize - 1) &&
- (PathIndex != HandoffData->DevicePathSize - 2)) {
- return 0;
- }
- if ((UsbDebugFlags & USB_DEBUG_DEBUGGER_HANDOFF) != 0) {
- RtlDebugPrint("USB: Checking device %04X:%04X against debugger "
- "device path.\n",
- Device->VendorId,
- Device->ProductId);
- }
- CheckIndex = PathIndex;
- CheckDevice = Device;
- while (TRUE) {
- //
- // If the device's hub address is not equal to the debug device path,
- // exit.
- //
- if (CheckDevice->PortNumber != HandoffData->DevicePath[CheckIndex]) {
- return 0;
- }
- if (CheckIndex == 0) {
- break;
- }
- CheckIndex -= 1;
- CheckDevice = CheckDevice->Parent;
- }
- //
- // The path lines up, this is either the debug device itself or the hub.
- //
- if (PathIndex == HandoffData->DevicePathSize - 1) {
- if ((UsbDebugFlags & USB_DEBUG_DEBUGGER_HANDOFF) != 0) {
- RtlDebugPrint("USB: Found debugger device %x! Assigning "
- "address %x\n",
- Device,
- HandoffData->DeviceAddress);
- }
- if ((Device->VendorId != HandoffData->VendorId) ||
- (Device->ProductId != HandoffData->ProductId)) {
- RtlDebugPrint("USB: Found VID:PID %04X:%04X at debug device path, "
- "expected %04X:%04x.\n",
- Device->VendorId,
- Device->ProductId,
- HandoffData->VendorId,
- HandoffData->ProductId);
- return 0;
- }
- Device->DebugDevice = TRUE;
- return HandoffData->DeviceAddress;
- }
- //
- // If there's a hub address, return that.
- //
- if ((UsbDebugFlags & USB_DEBUG_DEBUGGER_HANDOFF) != 0) {
- RtlDebugPrint("USB: Found debugger hub %x. Assigning "
- "address %x\n",
- Device,
- HandoffData->HubAddress);
- }
- return HandoffData->HubAddress;
- }
|