2 * PROJECT: ReactOS Universal Serial Bus Bulk Driver Library
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: lib/drivers/libusb/usb_device.cpp
5 * PURPOSE: USB Common Driver Library.
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
15 class CUSBDevice
: public IUSBDevice
18 STDMETHODIMP
QueryInterface( REFIID InterfaceId
, PVOID
* Interface
);
20 STDMETHODIMP_(ULONG
) AddRef()
22 InterlockedIncrement(&m_Ref
);
25 STDMETHODIMP_(ULONG
) Release()
27 InterlockedDecrement(&m_Ref
);
37 // IUSBDevice interface functions
38 virtual NTSTATUS
Initialize(IN PHUBCONTROLLER HubController
, IN PUSBHARDWAREDEVICE Device
, IN PVOID Parent
, IN ULONG Port
, IN ULONG PortStatus
);
39 virtual BOOLEAN
IsHub();
40 virtual NTSTATUS
GetParent(PVOID
* Parent
);
41 virtual UCHAR
GetDeviceAddress();
42 virtual ULONG
GetPort();
43 virtual USB_DEVICE_SPEED
GetSpeed();
44 virtual USB_DEVICE_TYPE
GetType();
45 virtual ULONG
GetState();
46 virtual void SetDeviceHandleData(PVOID Data
);
47 virtual NTSTATUS
SetDeviceAddress(UCHAR DeviceAddress
);
48 virtual void GetDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor
);
49 virtual UCHAR
GetConfigurationValue();
50 virtual NTSTATUS
SubmitIrp(PIRP Irp
);
51 virtual VOID
GetConfigurationDescriptors(IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptorBuffer
, IN ULONG BufferLength
, OUT PULONG OutBufferLength
);
52 virtual ULONG
GetConfigurationDescriptorsLength();
53 virtual NTSTATUS
SubmitSetupPacket(IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket
, OUT ULONG BufferLength
, OUT PVOID Buffer
);
54 virtual NTSTATUS
SelectConfiguration(IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
, IN PUSBD_INTERFACE_INFORMATION Interface
, OUT USBD_CONFIGURATION_HANDLE
*ConfigurationHandle
);
55 virtual NTSTATUS
SelectInterface(IN USBD_CONFIGURATION_HANDLE ConfigurationHandle
, IN OUT PUSBD_INTERFACE_INFORMATION Interface
);
56 virtual NTSTATUS
AbortPipe(IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor
);
57 virtual UCHAR
GetMaxPacketSize();
61 virtual NTSTATUS
CommitIrp(PIRP Irp
);
62 virtual NTSTATUS
CommitSetupPacket(PUSB_DEFAULT_PIPE_SETUP_PACKET Packet
, IN OPTIONAL PUSB_ENDPOINT EndpointDescriptor
, IN ULONG BufferLength
, IN OUT PMDL Mdl
);
63 virtual NTSTATUS
CreateConfigurationDescriptor(UCHAR ConfigurationIndex
);
64 virtual NTSTATUS
CreateDeviceDescriptor();
65 virtual VOID
DumpDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor
);
66 virtual VOID
DumpConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
);
67 virtual NTSTATUS
GetConfigurationDescriptor(UCHAR ConfigurationIndex
, USHORT BufferSize
, PVOID Buffer
);
69 // constructor / destructor
70 CUSBDevice(IUnknown
*OuterUnknown
){}
71 virtual ~CUSBDevice(){}
75 PHUBCONTROLLER m_HubController
;
76 PUSBHARDWAREDEVICE m_Device
;
79 UCHAR m_DeviceAddress
;
81 UCHAR m_ConfigurationIndex
;
83 USB_DEVICE_DESCRIPTOR m_DeviceDescriptor
;
86 PDMAMEMORYMANAGER m_DmaManager
;
88 PUSB_CONFIGURATION m_ConfigurationDescriptors
;
91 //----------------------------------------------------------------------------------------
94 CUSBDevice::QueryInterface(
98 return STATUS_UNSUCCESSFUL
;
101 //----------------------------------------------------------------------------------------
103 CUSBDevice::Initialize(
104 IN PHUBCONTROLLER HubController
,
105 IN PUSBHARDWAREDEVICE Device
,
113 // initialize members
115 m_HubController
= HubController
;
119 m_PortStatus
= PortStatus
;
122 // initialize device lock
124 KeInitializeSpinLock(&m_Lock
);
127 // no device address has been set yet
132 // get usb request queue
134 Status
= m_Device
->GetUSBQueue(&m_Queue
);
135 if (!NT_SUCCESS(Status
))
138 // failed to get usb queue
140 DPRINT1("CUSBDevice::Initialize GetUsbQueue failed with %x\n", Status
);
147 Status
= m_Device
->GetDMA(&m_DmaManager
);
148 if (!NT_SUCCESS(Status
))
151 // failed to get dma manager
153 DPRINT1("CUSBDevice::Initialize GetDMA failed with %x\n", Status
);
160 PC_ASSERT(m_DmaManager
);
163 // get device descriptor
165 Status
= CreateDeviceDescriptor();
166 if (!NT_SUCCESS(Status
))
169 // failed to get device descriptor
171 DPRINT1("CUSBDevice::Initialize Failed to get device descriptor with %x\n", Status
);
181 //----------------------------------------------------------------------------------------
186 // USB Standard Device Class see http://www.usb.org/developers/defined_class/#BaseClass09h
189 return (m_DeviceDescriptor
.bDeviceClass
== 0x09 && m_DeviceDescriptor
.bDeviceSubClass
== 0x00);
192 //----------------------------------------------------------------------------------------
194 CUSBDevice::GetParent(
205 return STATUS_SUCCESS
;
208 //----------------------------------------------------------------------------------------
210 CUSBDevice::GetDeviceAddress()
213 // get device address
215 return m_DeviceAddress
;
218 //----------------------------------------------------------------------------------------
220 CUSBDevice::GetPort()
223 // get port to which this device is connected to
228 //----------------------------------------------------------------------------------------
230 CUSBDevice::GetSpeed()
232 if (m_PortStatus
& USB_PORT_STATUS_LOW_SPEED
)
239 else if (m_PortStatus
& USB_PORT_STATUS_HIGH_SPEED
)
248 // default to full speed
253 //----------------------------------------------------------------------------------------
255 CUSBDevice::GetType()
258 // device is encoded into bcdUSB
260 if (m_DeviceDescriptor
.bcdUSB
== 0x110)
267 else if (m_DeviceDescriptor
.bcdUSB
== 0x200)
275 DPRINT1("CUSBDevice::GetType Unknown bcdUSB Type %x\n", m_DeviceDescriptor
.bcdUSB
);
281 //----------------------------------------------------------------------------------------
283 CUSBDevice::GetState()
289 //----------------------------------------------------------------------------------------
291 CUSBDevice::SetDeviceHandleData(
295 // set device data, for debugging issues
300 //----------------------------------------------------------------------------------------
302 CUSBDevice::SetDeviceAddress(
305 PUSB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup
;
310 DPRINT1("CUSBDevice::SetDeviceAddress Address %d\n", DeviceAddress
);
312 CtrlSetup
= (PUSB_DEFAULT_PIPE_SETUP_PACKET
)ExAllocatePoolWithTag(NonPagedPool
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
), TAG_USBLIB
);
314 return STATUS_INSUFFICIENT_RESOURCES
;
317 RtlZeroMemory(CtrlSetup
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
319 // initialize request
320 CtrlSetup
->bRequest
= USB_REQUEST_SET_ADDRESS
;
321 CtrlSetup
->wValue
.W
= DeviceAddress
;
323 // set device address
324 Status
= CommitSetupPacket(CtrlSetup
, 0, 0, 0);
327 ExFreePoolWithTag(CtrlSetup
, TAG_USBLIB
);
330 if (!NT_SUCCESS(Status
))
332 // failed to set device address
333 DPRINT1("CUSBDevice::SetDeviceAddress> failed to set device address with %x Address %x\n", Status
, DeviceAddress
);
337 // lets have a short nap
338 KeStallExecutionProcessor(300);
340 // back up old address
341 OldAddress
= m_DeviceAddress
;
343 // store new device address
344 m_DeviceAddress
= DeviceAddress
;
346 // fetch device descriptor
347 Status
= CreateDeviceDescriptor();
348 if (!NT_SUCCESS(Status
))
350 DPRINT1("CUSBbDevice::SetDeviceAddress> failed to retrieve device descriptor with device address set Error %x\n", Status
);
351 // return error status
355 // check for invalid device descriptor
356 if (m_DeviceDescriptor
.bLength
!= sizeof(USB_DEVICE_DESCRIPTOR
) ||
357 m_DeviceDescriptor
.bDescriptorType
!= USB_DEVICE_DESCRIPTOR_TYPE
||
358 m_DeviceDescriptor
.bNumConfigurations
== 0)
360 // failed to retrieve device descriptor
361 DPRINT1("CUSBbDevice::SetDeviceAddress> device returned bogus device descriptor\n");
362 DumpDeviceDescriptor(&m_DeviceDescriptor
);
364 // return error status
365 return STATUS_UNSUCCESSFUL
;
368 // dump device descriptor
369 DumpDeviceDescriptor(&m_DeviceDescriptor
);
372 PC_ASSERT(m_DeviceDescriptor
.bNumConfigurations
);
374 // allocate configuration descriptor
375 m_ConfigurationDescriptors
= (PUSB_CONFIGURATION
) ExAllocatePoolWithTag(NonPagedPool
, sizeof(USB_CONFIGURATION
) * m_DeviceDescriptor
.bNumConfigurations
, TAG_USBLIB
);
377 // zero configuration descriptor
378 RtlZeroMemory(m_ConfigurationDescriptors
, sizeof(USB_CONFIGURATION
) * m_DeviceDescriptor
.bNumConfigurations
);
380 // retrieve the configuration descriptors
381 for(Index
= 0; Index
< m_DeviceDescriptor
.bNumConfigurations
; Index
++)
383 // retrieve configuration descriptors from device
384 Status
= CreateConfigurationDescriptor(Index
);
385 if (!NT_SUCCESS(Status
))
387 DPRINT1("CUSBDevice::SetDeviceAddress> failed to retrieve configuration %lu\n", Index
);
400 //----------------------------------------------------------------------------------------
402 CUSBDevice::GetDeviceDescriptor(
403 PUSB_DEVICE_DESCRIPTOR DeviceDescriptor
)
405 RtlMoveMemory(DeviceDescriptor
, &m_DeviceDescriptor
, sizeof(USB_DEVICE_DESCRIPTOR
));
408 //----------------------------------------------------------------------------------------
410 CUSBDevice::GetConfigurationValue()
413 // return configuration index
415 return m_ConfigurationIndex
;
418 //----------------------------------------------------------------------------------------
420 CUSBDevice::CommitIrp(
426 if (!m_Queue
|| !m_DmaManager
)
431 DPRINT1("CUSBDevice::CommitUrb> no queue / dma !!!\n");
432 return STATUS_UNSUCCESSFUL
;
438 Status
= m_Queue
->CreateUSBRequest(&Request
);
439 if (!NT_SUCCESS(Status
))
442 // failed to build request
444 DPRINT1("CUSBDevice::CommitSetupPacket> CreateUSBRequest failed with %x\n", Status
);
449 // initialize request
451 Status
= Request
->InitializeWithIrp(m_DmaManager
, PUSBDEVICE(this), Irp
);
454 // mark irp as pending
456 IoMarkIrpPending(Irp
);
459 // now add the request
461 Status
= m_Queue
->AddUSBRequest(Request
);
462 if (!NT_SUCCESS(Status
))
465 // failed to add request
467 DPRINT1("CUSBDevice::CommitSetupPacket> failed add request to queue with %x\n", Status
);
475 return STATUS_PENDING
;
478 //----------------------------------------------------------------------------------------
480 CUSBDevice::SubmitIrp(
487 // acquire device lock
489 KeAcquireSpinLock(&m_Lock
, &OldLevel
);
494 Status
= CommitIrp(Irp
);
499 KeReleaseSpinLock(&m_Lock
, OldLevel
);
503 //----------------------------------------------------------------------------------------
505 CUSBDevice::CommitSetupPacket(
506 IN PUSB_DEFAULT_PIPE_SETUP_PACKET Packet
,
507 IN OPTIONAL PUSB_ENDPOINT EndpointDescriptor
,
508 IN ULONG BufferLength
,
519 DPRINT1("CUSBDevice::CommitSetupPacket> no queue!!!\n");
520 return STATUS_UNSUCCESSFUL
;
526 Status
= m_Queue
->CreateUSBRequest(&Request
);
527 if (!NT_SUCCESS(Status
))
530 // failed to build request
532 DPRINT1("CUSBDevice::CommitSetupPacket> CreateUSBRequest failed with %x\n", Status
);
537 // initialize request
539 Status
= Request
->InitializeWithSetupPacket(m_DmaManager
, Packet
, PUSBDEVICE(this), EndpointDescriptor
, BufferLength
, Mdl
);
540 if (!NT_SUCCESS(Status
))
543 // failed to initialize request
545 DPRINT1("CUSBDevice::CommitSetupPacket> failed to initialize usb request with %x\n", Status
);
551 // now add the request
553 Status
= m_Queue
->AddUSBRequest(Request
);
554 if (!NT_SUCCESS(Status
))
557 // failed to add request
559 DPRINT1("CUSBDevice::CommitSetupPacket> failed add request to queue with %x\n", Status
);
565 // get the result code when the operation has been finished
567 Request
->GetResultStatus(&Status
, NULL
);
580 //----------------------------------------------------------------------------------------
582 CUSBDevice::CreateDeviceDescriptor()
584 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup
;
592 RtlZeroMemory(&m_DeviceDescriptor
, sizeof(USB_DEVICE_DESCRIPTOR
));
593 RtlZeroMemory(&CtrlSetup
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
598 CtrlSetup
.bRequest
= USB_REQUEST_GET_DESCRIPTOR
;
599 CtrlSetup
.wValue
.HiByte
= USB_DEVICE_DESCRIPTOR_TYPE
;
600 CtrlSetup
.wLength
= sizeof(USB_DEVICE_DESCRIPTOR
);
601 CtrlSetup
.bmRequestType
.B
= 0x80;
606 Buffer
= ExAllocatePool(NonPagedPool
, PAGE_SIZE
);
610 // failed to allocate
612 return STATUS_INSUFFICIENT_RESOURCES
;
618 RtlZeroMemory(Buffer
, PAGE_SIZE
);
621 // allocate mdl describing the device descriptor
623 Mdl
= IoAllocateMdl(Buffer
, sizeof(USB_DEVICE_DESCRIPTOR
), FALSE
, FALSE
, 0);
627 // failed to allocate mdl
629 return STATUS_INSUFFICIENT_RESOURCES
;
633 // build mdl for non paged pool
635 MmBuildMdlForNonPagedPool(Mdl
);
638 // commit setup packet
640 Status
= CommitSetupPacket(&CtrlSetup
, 0, sizeof(USB_DEVICE_DESCRIPTOR
), Mdl
);
647 if (NT_SUCCESS(Status
))
650 // copy device descriptor
652 RtlCopyMemory(&m_DeviceDescriptor
, Buffer
, sizeof(USB_DEVICE_DESCRIPTOR
));
667 //----------------------------------------------------------------------------------------
669 CUSBDevice::GetConfigurationDescriptor(
670 IN UCHAR ConfigurationIndex
,
671 IN USHORT BufferSize
,
674 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup
;
680 // now build MDL describing the buffer
682 Mdl
= IoAllocateMdl(Buffer
, BufferSize
, FALSE
, FALSE
, 0);
686 // failed to allocate mdl
688 return STATUS_INSUFFICIENT_RESOURCES
;
692 // build mdl for non paged pool
694 MmBuildMdlForNonPagedPool(Mdl
);
698 // build setup packet
700 CtrlSetup
.bmRequestType
._BM
.Recipient
= BMREQUEST_TO_DEVICE
;
701 CtrlSetup
.bmRequestType
._BM
.Type
= BMREQUEST_STANDARD
;
702 CtrlSetup
.bmRequestType
._BM
.Reserved
= 0;
703 CtrlSetup
.bmRequestType
._BM
.Dir
= BMREQUEST_DEVICE_TO_HOST
;
704 CtrlSetup
.bRequest
= USB_REQUEST_GET_DESCRIPTOR
;
705 CtrlSetup
.wValue
.LowByte
= ConfigurationIndex
;
706 CtrlSetup
.wValue
.HiByte
= USB_CONFIGURATION_DESCRIPTOR_TYPE
;
707 CtrlSetup
.wIndex
.W
= 0;
708 CtrlSetup
.wLength
= BufferSize
;
713 Status
= CommitSetupPacket(&CtrlSetup
, 0, BufferSize
, Mdl
);
726 //----------------------------------------------------------------------------------------
728 CUSBDevice::CreateConfigurationDescriptor(
732 PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
;
737 PC_ASSERT(m_ConfigurationDescriptors
);
740 // first allocate a buffer which should be enough to store all different interfaces and endpoints
742 ConfigurationDescriptor
= (PUSB_CONFIGURATION_DESCRIPTOR
)ExAllocatePoolWithTag(NonPagedPool
, PAGE_SIZE
, TAG_USBLIB
);
743 if (!ConfigurationDescriptor
)
746 // failed to allocate buffer
748 return STATUS_INSUFFICIENT_RESOURCES
;
752 // get partial configuration descriptor
754 Status
= GetConfigurationDescriptor(Index
, sizeof(USB_CONFIGURATION_DESCRIPTOR
), ConfigurationDescriptor
);
755 if (!NT_SUCCESS(Status
))
758 // failed to get partial configuration descriptor
760 DPRINT1("[USBLIB] Failed to get partial configuration descriptor Status %x Index %x\n", Status
, Index
);
761 ExFreePoolWithTag(ConfigurationDescriptor
, TAG_USBLIB
);
766 // now get full descriptor
768 Status
= GetConfigurationDescriptor(Index
, ConfigurationDescriptor
->wTotalLength
, ConfigurationDescriptor
);
769 if (!NT_SUCCESS(Status
))
772 // failed to get full configuration descriptor
774 DPRINT1("[USBLIB] Failed to get full configuration descriptor Status %x Index %x\n", Status
, Index
);
775 ExFreePoolWithTag(ConfigurationDescriptor
, TAG_USBLIB
);
780 // informal debug print
782 DumpConfigurationDescriptor(ConfigurationDescriptor
);
787 PC_ASSERT(ConfigurationDescriptor
->bLength
== sizeof(USB_CONFIGURATION_DESCRIPTOR
));
788 PC_ASSERT(ConfigurationDescriptor
->wTotalLength
<= PAGE_SIZE
);
789 PC_ASSERT(ConfigurationDescriptor
->bNumInterfaces
);
792 // request is complete, initialize configuration descriptor
794 m_ConfigurationDescriptors
[Index
].ConfigurationDescriptor
= ConfigurationDescriptor
;
795 InitializeListHead(&m_ConfigurationDescriptors
[Index
].InterfaceList
);
802 //----------------------------------------------------------------------------------------
804 CUSBDevice::GetConfigurationDescriptors(
805 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptorBuffer
,
806 IN ULONG BufferLength
,
807 OUT PULONG OutBufferLength
)
810 ASSERT(BufferLength
>= sizeof(USB_CONFIGURATION_DESCRIPTOR
));
811 ASSERT(ConfigDescriptorBuffer
);
812 ASSERT(OutBufferLength
);
814 // reset copied length
815 *OutBufferLength
= 0;
817 // FIXME: support multiple configurations
818 PC_ASSERT(m_DeviceDescriptor
.bNumConfigurations
== 1);
820 // copy configuration descriptor
821 RtlCopyMemory(ConfigDescriptorBuffer
, m_ConfigurationDescriptors
[0].ConfigurationDescriptor
, min(m_ConfigurationDescriptors
[0].ConfigurationDescriptor
->wTotalLength
, BufferLength
));
822 *OutBufferLength
= m_ConfigurationDescriptors
[0].ConfigurationDescriptor
->wTotalLength
;
825 //----------------------------------------------------------------------------------------
827 CUSBDevice::GetConfigurationDescriptorsLength()
830 // FIXME: support multiple configurations
832 PC_ASSERT(m_DeviceDescriptor
.bNumConfigurations
== 1);
834 return m_ConfigurationDescriptors
[0].ConfigurationDescriptor
->wTotalLength
;
836 //----------------------------------------------------------------------------------------
838 CUSBDevice::DumpDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor
)
840 DPRINT1("Dumping Device Descriptor %x\n", DeviceDescriptor
);
841 DPRINT1("bLength %x\n", DeviceDescriptor
->bLength
);
842 DPRINT1("bDescriptorType %x\n", DeviceDescriptor
->bDescriptorType
);
843 DPRINT1("bcdUSB %x\n", DeviceDescriptor
->bcdUSB
);
844 DPRINT1("bDeviceClass %x\n", DeviceDescriptor
->bDeviceClass
);
845 DPRINT1("bDeviceSubClass %x\n", DeviceDescriptor
->bDeviceSubClass
);
846 DPRINT1("bDeviceProtocol %x\n", DeviceDescriptor
->bDeviceProtocol
);
847 DPRINT1("bMaxPacketSize0 %x\n", DeviceDescriptor
->bMaxPacketSize0
);
848 DPRINT1("idVendor %x\n", DeviceDescriptor
->idVendor
);
849 DPRINT1("idProduct %x\n", DeviceDescriptor
->idProduct
);
850 DPRINT1("bcdDevice %x\n", DeviceDescriptor
->bcdDevice
);
851 DPRINT1("iManufacturer %x\n", DeviceDescriptor
->iManufacturer
);
852 DPRINT1("iProduct %x\n", DeviceDescriptor
->iProduct
);
853 DPRINT1("iSerialNumber %x\n", DeviceDescriptor
->iSerialNumber
);
854 DPRINT1("bNumConfigurations %x\n", DeviceDescriptor
->bNumConfigurations
);
857 //----------------------------------------------------------------------------------------
859 CUSBDevice::DumpConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
)
861 DPRINT1("Dumping ConfigurationDescriptor %x\n", ConfigurationDescriptor
);
862 DPRINT1("bLength %x\n", ConfigurationDescriptor
->bLength
);
863 DPRINT1("bDescriptorType %x\n", ConfigurationDescriptor
->bDescriptorType
);
864 DPRINT1("wTotalLength %x\n", ConfigurationDescriptor
->wTotalLength
);
865 DPRINT1("bNumInterfaces %x\n", ConfigurationDescriptor
->bNumInterfaces
);
866 DPRINT1("bConfigurationValue %x\n", ConfigurationDescriptor
->bConfigurationValue
);
867 DPRINT1("iConfiguration %x\n", ConfigurationDescriptor
->iConfiguration
);
868 DPRINT1("bmAttributes %x\n", ConfigurationDescriptor
->bmAttributes
);
869 DPRINT1("MaxPower %x\n", ConfigurationDescriptor
->MaxPower
);
871 //----------------------------------------------------------------------------------------
873 CUSBDevice::SubmitSetupPacket(
874 IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket
,
875 IN OUT ULONG BufferLength
,
886 Mdl
= IoAllocateMdl(Buffer
, BufferLength
, FALSE
, FALSE
, 0);
892 return STATUS_INSUFFICIENT_RESOURCES
;
896 // HACK HACK HACK: assume the buffer is build from non paged pool
898 MmBuildMdlForNonPagedPool(Mdl
);
902 // commit setup packet
904 Status
= CommitSetupPacket(SetupPacket
, 0, BufferLength
, Mdl
);
920 //----------------------------------------------------------------------------------------
922 CUSBDevice::SelectConfiguration(
923 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
,
924 IN PUSBD_INTERFACE_INFORMATION InterfaceInfo
,
925 OUT USBD_CONFIGURATION_HANDLE
*ConfigurationHandle
)
927 ULONG InterfaceIndex
, PipeIndex
;
928 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup
;
930 UCHAR bConfigurationValue
= 0;
931 ULONG ConfigurationIndex
= 0, Index
;
933 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor
;
934 PUSB_INTERFACE UsbInterface
;
935 PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor
;
938 if (ConfigurationDescriptor
)
940 // find configuration index
941 for(Index
= 0; Index
< m_DeviceDescriptor
.bNumConfigurations
; Index
++)
943 if (m_ConfigurationDescriptors
[Index
].ConfigurationDescriptor
->bConfigurationValue
== ConfigurationDescriptor
->bConfigurationValue
)
945 // found configuration index
946 ConfigurationIndex
= Index
;
953 DPRINT1("[USBUHCI] invalid configuration value %lu\n", ConfigurationDescriptor
->bConfigurationValue
);
954 return STATUS_INVALID_PARAMETER
;
958 ASSERT(ConfigurationDescriptor
->bNumInterfaces
<= m_ConfigurationDescriptors
[ConfigurationIndex
].ConfigurationDescriptor
->bNumInterfaces
);
960 // get configuration value
961 bConfigurationValue
= ConfigurationDescriptor
->bConfigurationValue
;
964 // now build setup packet
965 RtlZeroMemory(&CtrlSetup
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
966 CtrlSetup
.bRequest
= USB_REQUEST_SET_CONFIGURATION
;
967 CtrlSetup
.wValue
.W
= bConfigurationValue
;
969 // select configuration
970 Status
= CommitSetupPacket(&CtrlSetup
, 0, 0, 0);
972 if (!ConfigurationDescriptor
)
974 // unconfigure request
975 DPRINT1("CUsbDevice::SelectConfiguration Unconfigure Request Status %x\n", Status
);
976 m_ConfigurationIndex
= 0;
980 // informal debug print
981 DPRINT1("CUsbDevice::SelectConfiguration New Configuration %x Old Configuration %x Result %x\n", ConfigurationIndex
, m_ConfigurationIndex
, Status
);
982 if (!NT_SUCCESS(Status
))
990 // destroy old interface info
991 while(!IsListEmpty(&m_ConfigurationDescriptors
[m_ConfigurationIndex
].InterfaceList
))
994 Entry
= RemoveHeadList(&m_ConfigurationDescriptors
[m_ConfigurationIndex
].InterfaceList
);
996 // get interface info
997 UsbInterface
= (PUSB_INTERFACE
)CONTAINING_RECORD(Entry
, USB_INTERFACE
, ListEntry
);
999 // free interface info
1000 ExFreePool(UsbInterface
);
1004 ASSERT(IsListEmpty(&m_ConfigurationDescriptors
[ConfigurationIndex
].InterfaceList
));
1006 // store new configuration device index
1007 m_ConfigurationIndex
= ConfigurationIndex
;
1009 // store configuration handle
1010 *ConfigurationHandle
= &m_ConfigurationDescriptors
[ConfigurationIndex
];
1012 // copy interface info and pipe info
1013 for(InterfaceIndex
= 0; InterfaceIndex
< ConfigurationDescriptor
->bNumInterfaces
; InterfaceIndex
++)
1015 // interface info checks
1016 ASSERT(InterfaceInfo
->Length
!= 0);
1019 PC_ASSERT(InterfaceInfo
->Length
== FIELD_OFFSET(USBD_INTERFACE_INFORMATION
, Pipes
[InterfaceInfo
->NumberOfPipes
]));
1022 // find interface descriptor
1023 InterfaceDescriptor
= USBD_ParseConfigurationDescriptor(m_ConfigurationDescriptors
[ConfigurationIndex
].ConfigurationDescriptor
, InterfaceInfo
->InterfaceNumber
, InterfaceInfo
->AlternateSetting
);
1026 ASSERT(InterfaceDescriptor
!= NULL
);
1028 // check if the number of pipes have been properly set
1029 ASSERT(InterfaceInfo
->NumberOfPipes
== InterfaceDescriptor
->bNumEndpoints
);
1031 // copy interface info
1032 InterfaceInfo
->Class
= InterfaceDescriptor
->bInterfaceClass
;
1033 InterfaceInfo
->SubClass
= InterfaceDescriptor
->bInterfaceSubClass
;
1034 InterfaceInfo
->Protocol
= InterfaceDescriptor
->bInterfaceProtocol
;
1035 InterfaceInfo
->Reserved
= 0;
1037 // allocate interface handle
1038 UsbInterface
= (PUSB_INTERFACE
)ExAllocatePool(NonPagedPool
, sizeof(USB_INTERFACE
) + (InterfaceInfo
->NumberOfPipes
- 1) * sizeof(USB_ENDPOINT
));
1041 // failed to allocate memory
1042 return STATUS_INSUFFICIENT_RESOURCES
;
1046 InterfaceInfo
->InterfaceHandle
= (USBD_INTERFACE_HANDLE
)UsbInterface
;
1048 // init interface handle
1049 UsbInterface
->InterfaceDescriptor
= InterfaceDescriptor
;
1050 InsertTailList(&m_ConfigurationDescriptors
[ConfigurationIndex
].InterfaceList
, &UsbInterface
->ListEntry
);
1052 // grab first endpoint descriptor
1053 EndpointDescriptor
= (PUSB_ENDPOINT_DESCRIPTOR
) (InterfaceDescriptor
+ 1);
1055 // now copy all endpoint information
1056 for(PipeIndex
= 0; PipeIndex
< InterfaceInfo
->NumberOfPipes
; PipeIndex
++)
1058 while(EndpointDescriptor
->bDescriptorType
!= USB_ENDPOINT_DESCRIPTOR_TYPE
&& EndpointDescriptor
->bLength
!= sizeof(USB_ENDPOINT_DESCRIPTOR
))
1060 // skip intermediate descriptors
1061 if (EndpointDescriptor
->bLength
== 0 || EndpointDescriptor
->bDescriptorType
== USB_INTERFACE_DESCRIPTOR_TYPE
)
1063 // bogus configuration descriptor
1064 DPRINT1("[USBEHCI] Bogus descriptor found in InterfaceNumber %x Alternate %x EndpointIndex %x bLength %x bDescriptorType %x\n", InterfaceDescriptor
->bInterfaceNumber
, InterfaceDescriptor
->bAlternateSetting
, PipeIndex
,
1065 EndpointDescriptor
->bLength
, EndpointDescriptor
->bDescriptorType
);
1068 return STATUS_UNSUCCESSFUL
;
1071 // move to next descriptor
1072 EndpointDescriptor
= (PUSB_ENDPOINT_DESCRIPTOR
)((ULONG_PTR
)EndpointDescriptor
+ EndpointDescriptor
->bLength
);
1075 // store in interface info
1076 RtlCopyMemory(&UsbInterface
->EndPoints
[PipeIndex
].EndPointDescriptor
, EndpointDescriptor
, sizeof(USB_ENDPOINT_DESCRIPTOR
));
1079 InterfaceInfo
->Pipes
[PipeIndex
].MaximumPacketSize
= UsbInterface
->EndPoints
[PipeIndex
].EndPointDescriptor
.wMaxPacketSize
;
1080 InterfaceInfo
->Pipes
[PipeIndex
].EndpointAddress
= UsbInterface
->EndPoints
[PipeIndex
].EndPointDescriptor
.bEndpointAddress
;
1081 InterfaceInfo
->Pipes
[PipeIndex
].Interval
= UsbInterface
->EndPoints
[PipeIndex
].EndPointDescriptor
.bInterval
;
1082 InterfaceInfo
->Pipes
[PipeIndex
].PipeType
= (USBD_PIPE_TYPE
)UsbInterface
->EndPoints
[PipeIndex
].EndPointDescriptor
.bmAttributes
;
1083 InterfaceInfo
->Pipes
[PipeIndex
].PipeHandle
= (PVOID
)&UsbInterface
->EndPoints
[PipeIndex
];
1085 // move to next descriptor
1086 EndpointDescriptor
= (PUSB_ENDPOINT_DESCRIPTOR
)((ULONG_PTR
)EndpointDescriptor
+ EndpointDescriptor
->bLength
);
1090 InterfaceInfo
= (PUSBD_INTERFACE_INFORMATION
)((ULONG_PTR
)PtrToUlong(InterfaceInfo
) + InterfaceInfo
->Length
);
1099 //----------------------------------------------------------------------------------------
1101 CUSBDevice::SelectInterface(
1102 IN USBD_CONFIGURATION_HANDLE ConfigurationHandle
,
1103 IN OUT PUSBD_INTERFACE_INFORMATION InterfaceInfo
)
1106 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup
;
1108 ULONG Index
, ConfigurationIndex
= 0, Found
= FALSE
;
1109 PUSB_INTERFACE UsbInterface
;
1112 // check if handle is valid
1113 for(Index
= 0; Index
< m_DeviceDescriptor
.bNumConfigurations
; Index
++)
1115 if (&m_ConfigurationDescriptors
[Index
] == ConfigurationHandle
)
1117 // found configuration index
1118 ConfigurationIndex
= Index
;
1125 // invalid handle passed
1126 DPRINT1("[USBEHCI] Invalid configuration handle passed %p\n", ConfigurationHandle
);
1127 return STATUS_INVALID_PARAMETER
;
1130 // initialize setup packet
1131 RtlZeroMemory(&CtrlSetup
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
1132 CtrlSetup
.bRequest
= USB_REQUEST_SET_INTERFACE
;
1133 CtrlSetup
.wValue
.W
= InterfaceInfo
->AlternateSetting
;
1134 CtrlSetup
.wIndex
.W
= InterfaceInfo
->InterfaceNumber
;
1135 CtrlSetup
.bmRequestType
.B
= 0x01;
1138 Status
= CommitSetupPacket(&CtrlSetup
, 0, 0, 0);
1140 // informal debug print
1141 DPRINT1("CUSBDevice::SelectInterface AlternateSetting %x InterfaceNumber %x Status %x\n", InterfaceInfo
->AlternateSetting
, InterfaceInfo
->InterfaceNumber
, Status
);
1143 if (!NT_SUCCESS(Status
))
1145 // failed to select interface
1150 Status
= STATUS_SUCCESS
;
1155 Entry
= m_ConfigurationDescriptors
[ConfigurationIndex
].InterfaceList
.Flink
;
1156 while(Entry
!= &m_ConfigurationDescriptors
[ConfigurationIndex
].InterfaceList
)
1158 // grab interface descriptor
1159 UsbInterface
= (PUSB_INTERFACE
)CONTAINING_RECORD(Entry
, USB_INTERFACE
, ListEntry
);
1160 if (UsbInterface
->InterfaceDescriptor
->bAlternateSetting
== InterfaceInfo
->AlternateSetting
&&
1161 UsbInterface
->InterfaceDescriptor
->bInterfaceNumber
== InterfaceInfo
->InterfaceNumber
)
1171 // selected interface but interface not found
1172 // something is really wrong
1173 DPRINT1("[USBEHCI] Error: interface not found!!!\n");
1174 return STATUS_UNSUCCESSFUL
;
1177 // assert on pipe length mismatch
1178 ASSERT(InterfaceInfo
->NumberOfPipes
== UsbInterface
->InterfaceDescriptor
->bNumEndpoints
);
1180 // copy pipe handles
1181 for(PipeIndex
= 0; PipeIndex
< min(InterfaceInfo
->NumberOfPipes
, UsbInterface
->InterfaceDescriptor
->bNumEndpoints
); PipeIndex
++)
1184 DPRINT1("PipeIndex %lu\n", PipeIndex
);
1185 DPRINT1("EndpointAddress %x\n", InterfaceInfo
->Pipes
[PipeIndex
].EndpointAddress
);
1186 DPRINT1("Interval %d\n", InterfaceInfo
->Pipes
[PipeIndex
].Interval
);
1187 DPRINT1("MaximumPacketSize %d\n", InterfaceInfo
->Pipes
[PipeIndex
].MaximumPacketSize
);
1188 DPRINT1("MaximumTransferSize %d\n", InterfaceInfo
->Pipes
[PipeIndex
].MaximumTransferSize
);
1189 DPRINT1("PipeFlags %d\n", InterfaceInfo
->Pipes
[PipeIndex
].PipeFlags
);
1190 DPRINT1("PipeType %dd\n", InterfaceInfo
->Pipes
[PipeIndex
].PipeType
);
1191 DPRINT1("UsbEndPoint %x\n", InterfaceInfo
->Pipes
[PipeIndex
].EndpointAddress
);
1194 ASSERT(InterfaceInfo
->Pipes
[PipeIndex
].EndpointAddress
== UsbInterface
->EndPoints
[PipeIndex
].EndPointDescriptor
.bEndpointAddress
);
1195 ASSERT(InterfaceInfo
->Pipes
[PipeIndex
].Interval
== UsbInterface
->EndPoints
[PipeIndex
].EndPointDescriptor
.bInterval
);
1197 // store pipe handle
1198 InterfaceInfo
->Pipes
[PipeIndex
].PipeHandle
= &UsbInterface
->EndPoints
[PipeIndex
];
1200 // data toggle is reset on select interface requests
1201 UsbInterface
->EndPoints
[PipeIndex
].DataToggle
= FALSE
;
1212 CUSBDevice::AbortPipe(
1213 IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor
)
1216 // let it handle usb queue
1219 ASSERT(m_DeviceAddress
);
1224 return m_Queue
->AbortDevicePipe(m_DeviceAddress
, EndpointDescriptor
);
1228 CUSBDevice::GetMaxPacketSize()
1230 return m_DeviceDescriptor
.bMaxPacketSize0
;
1234 //----------------------------------------------------------------------------------------
1238 PUSBDEVICE
*OutDevice
)
1243 // allocate controller
1245 This
= new(NonPagedPool
, TAG_USBLIB
) CUSBDevice(0);
1249 // failed to allocate
1251 return STATUS_INSUFFICIENT_RESOURCES
;
1255 // add reference count
1262 *OutDevice
= (PUSBDEVICE
)This
;
1267 return STATUS_SUCCESS
;