2 * PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbehci/usb_device.cpp
5 * PURPOSE: USB EHCI device driver.
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
14 typedef struct _USB_ENDPOINT
16 USB_ENDPOINT_DESCRIPTOR EndPointDescriptor
;
17 } USB_ENDPOINT
, *PUSB_ENDPOINT
;
19 typedef struct _USB_INTERFACE
21 USB_INTERFACE_DESCRIPTOR InterfaceDescriptor
;
22 USB_ENDPOINT
*EndPoints
;
23 } USB_INTERFACE
, *PUSB_INTERFACE
;
25 typedef struct _USB_CONFIGURATION
27 USB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
;
28 USB_INTERFACE
*Interfaces
;
29 } USB_CONFIGURATION
, *PUSB_CONFIGURATION
;
32 class CUSBDevice
: public IUSBDevice
35 STDMETHODIMP
QueryInterface( REFIID InterfaceId
, PVOID
* Interface
);
37 STDMETHODIMP_(ULONG
) AddRef()
39 InterlockedIncrement(&m_Ref
);
42 STDMETHODIMP_(ULONG
) Release()
44 InterlockedDecrement(&m_Ref
);
54 // IUSBDevice interface functions
55 virtual NTSTATUS
Initialize(IN PHUBCONTROLLER HubController
, IN PUSBHARDWAREDEVICE Device
, IN PVOID Parent
, IN ULONG Port
, IN ULONG PortStatus
);
56 virtual BOOLEAN
IsHub();
57 virtual NTSTATUS
GetParent(PVOID
* Parent
);
58 virtual UCHAR
GetDeviceAddress();
59 virtual ULONG
GetPort();
60 virtual USB_DEVICE_SPEED
GetSpeed();
61 virtual USB_DEVICE_TYPE
GetType();
62 virtual ULONG
GetState();
63 virtual void SetDeviceHandleData(PVOID Data
);
64 virtual NTSTATUS
SetDeviceAddress(UCHAR DeviceAddress
);
65 virtual void GetDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor
);
66 virtual UCHAR
GetConfigurationValue();
67 virtual NTSTATUS
SubmitIrp(PIRP Irp
);
68 virtual VOID
GetConfigurationDescriptors(IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptorBuffer
, IN ULONG BufferLength
, OUT PULONG OutBufferLength
);
69 virtual ULONG
GetConfigurationDescriptorsLength();
70 virtual NTSTATUS
SubmitSetupPacket(IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket
, OUT ULONG BufferLength
, OUT PVOID Buffer
);
71 virtual NTSTATUS
SelectConfiguration(IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
, IN PUSBD_INTERFACE_INFORMATION Interface
, OUT USBD_CONFIGURATION_HANDLE
*ConfigurationHandle
);
72 virtual NTSTATUS
SelectInterface(IN USBD_CONFIGURATION_HANDLE ConfigurationHandle
, IN OUT PUSBD_INTERFACE_INFORMATION Interface
);
75 virtual NTSTATUS
CommitIrp(PIRP Irp
);
76 virtual NTSTATUS
CommitSetupPacket(PUSB_DEFAULT_PIPE_SETUP_PACKET Packet
, IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor
, IN ULONG BufferLength
, IN OUT PMDL Mdl
);
77 virtual NTSTATUS
CreateConfigurationDescriptor(ULONG ConfigurationIndex
);
78 virtual NTSTATUS
CreateDeviceDescriptor();
79 virtual VOID
DumpDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor
);
80 virtual VOID
DumpConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
);
82 // constructor / destructor
83 CUSBDevice(IUnknown
*OuterUnknown
){}
84 virtual ~CUSBDevice(){}
88 PHUBCONTROLLER m_HubController
;
89 PUSBHARDWAREDEVICE m_Device
;
92 UCHAR m_DeviceAddress
;
94 UCHAR m_ConfigurationIndex
;
96 USB_DEVICE_DESCRIPTOR m_DeviceDescriptor
;
99 PDMAMEMORYMANAGER m_DmaManager
;
101 PUSB_CONFIGURATION m_ConfigurationDescriptors
;
104 //----------------------------------------------------------------------------------------
107 CUSBDevice::QueryInterface(
111 return STATUS_UNSUCCESSFUL
;
114 //----------------------------------------------------------------------------------------
116 CUSBDevice::Initialize(
117 IN PHUBCONTROLLER HubController
,
118 IN PUSBHARDWAREDEVICE Device
,
126 // initialize members
128 m_HubController
= HubController
;
132 m_PortStatus
= PortStatus
;
135 // initialize device lock
137 KeInitializeSpinLock(&m_Lock
);
140 // no device address has been set yet
145 // get usb request queue
147 Status
= m_Device
->GetUSBQueue(&m_Queue
);
148 if (!NT_SUCCESS(Status
))
151 // failed to get usb queue
153 DPRINT1("CUSBDevice::Initialize GetUsbQueue failed with %x\n", Status
);
160 Status
= m_Device
->GetDMA(&m_DmaManager
);
161 if (!NT_SUCCESS(Status
))
164 // failed to get dma manager
166 DPRINT1("CUSBDevice::Initialize GetDMA failed with %x\n", Status
);
173 PC_ASSERT(m_DmaManager
);
176 // get device descriptor
178 Status
= CreateDeviceDescriptor();
179 if (!NT_SUCCESS(Status
))
182 // failed to get device descriptor
184 DPRINT1("CUSBDevice::Initialize Failed to get device descriptor with %x\n", Status
);
194 //----------------------------------------------------------------------------------------
199 // USB Standard Device Class see http://www.usb.org/developers/defined_class/#BaseClass09h
202 return (m_DeviceDescriptor
.bDeviceClass
== 0x09 && m_DeviceDescriptor
.bDeviceSubClass
== 0x00);
205 //----------------------------------------------------------------------------------------
207 CUSBDevice::GetParent(
218 return STATUS_SUCCESS
;
221 //----------------------------------------------------------------------------------------
223 CUSBDevice::GetDeviceAddress()
226 // get device address
228 return m_DeviceAddress
;
231 //----------------------------------------------------------------------------------------
233 CUSBDevice::GetPort()
236 // get port to which this device is connected to
241 //----------------------------------------------------------------------------------------
243 CUSBDevice::GetSpeed()
245 if (m_PortStatus
& USB_PORT_STATUS_LOW_SPEED
)
252 else if (m_PortStatus
& USB_PORT_STATUS_HIGH_SPEED
)
261 // default to full speed
266 //----------------------------------------------------------------------------------------
268 CUSBDevice::GetType()
271 // device is encoded into bcdUSB
273 if (m_DeviceDescriptor
.bcdUSB
== 0x110)
280 else if (m_DeviceDescriptor
.bcdUSB
== 0x200)
288 DPRINT1("CUSBDevice::GetType Unknown bcdUSB Type %x\n", m_DeviceDescriptor
.bcdUSB
);
294 //----------------------------------------------------------------------------------------
296 CUSBDevice::GetState()
302 //----------------------------------------------------------------------------------------
304 CUSBDevice::SetDeviceHandleData(
308 // set device data, for debugging issues
313 //----------------------------------------------------------------------------------------
315 CUSBDevice::SetDeviceAddress(
318 PUSB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup
;
323 DPRINT1("CUSBDevice::SetDeviceAddress Address %d\n", DeviceAddress
);
325 CtrlSetup
= (PUSB_DEFAULT_PIPE_SETUP_PACKET
)ExAllocatePoolWithTag(NonPagedPool
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
), TAG_USBEHCI
);
327 return STATUS_INSUFFICIENT_RESOURCES
;
332 RtlZeroMemory(CtrlSetup
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
335 // initialize request
337 CtrlSetup
->bRequest
= USB_REQUEST_SET_ADDRESS
;
338 CtrlSetup
->wValue
.W
= (USHORT
)DeviceAddress
;
341 // set device address
343 Status
= CommitSetupPacket(CtrlSetup
, 0, 0, 0);
348 ExFreePoolWithTag(CtrlSetup
, TAG_USBEHCI
);
353 if (!NT_SUCCESS(Status
))
356 // failed to set device address
358 DPRINT1("CUSBDevice::SetDeviceAddress> failed to set device address with %x Address %x\n", Status
, DeviceAddress
);
363 // lets have a short nap
365 KeStallExecutionProcessor(300);
368 // back up old address
370 OldAddress
= m_DeviceAddress
;
373 // store new device address
375 m_DeviceAddress
= DeviceAddress
;
378 // check that setting device address succeeded by retrieving the device descriptor
380 Status
= CreateDeviceDescriptor();
381 if (!NT_SUCCESS(Status
))
384 // failed to retrieve device descriptor
386 DPRINT1("CUSBbDevice::SetDeviceAddress> failed to retrieve device descriptor with device address set Error %x\n", Status
);
387 m_DeviceAddress
= OldAddress
;
390 // return error status
398 PC_ASSERT(m_DeviceDescriptor
.bNumConfigurations
);
401 // allocate configuration descriptor
403 m_ConfigurationDescriptors
= (PUSB_CONFIGURATION
) ExAllocatePoolWithTag(NonPagedPool
, sizeof(USB_CONFIGURATION
) * m_DeviceDescriptor
.bNumConfigurations
, TAG_USBEHCI
);
406 // zero configuration descriptor
408 RtlZeroMemory(m_ConfigurationDescriptors
, sizeof(USB_CONFIGURATION
) * m_DeviceDescriptor
.bNumConfigurations
);
411 // retrieve the configuration descriptors
413 for(Index
= 0; Index
< m_DeviceDescriptor
.bNumConfigurations
; Index
++)
416 // retrieve configuration descriptors from device
418 Status
= CreateConfigurationDescriptor(Index
);
419 if (!NT_SUCCESS(Status
))
421 DPRINT1("CUSBDevice::SetDeviceAddress> failed to retrieve configuration %lu\n", Index
);
433 //----------------------------------------------------------------------------------------
435 CUSBDevice::GetDeviceDescriptor(
436 PUSB_DEVICE_DESCRIPTOR DeviceDescriptor
)
438 RtlMoveMemory(DeviceDescriptor
, &m_DeviceDescriptor
, sizeof(USB_DEVICE_DESCRIPTOR
));
441 //----------------------------------------------------------------------------------------
443 CUSBDevice::GetConfigurationValue()
446 // return configuration index
448 return m_ConfigurationIndex
;
451 //----------------------------------------------------------------------------------------
453 CUSBDevice::CommitIrp(
459 if (!m_Queue
|| !m_DmaManager
)
464 DPRINT1("CUSBDevice::CommitUrb> no queue / dma !!!\n");
465 return STATUS_UNSUCCESSFUL
;
471 Status
= m_Queue
->CreateUSBRequest(&Request
);
472 if (!NT_SUCCESS(Status
))
475 // failed to build request
477 DPRINT1("CUSBDevice::CommitSetupPacket> CreateUSBRequest failed with %x\n", Status
);
482 // initialize request
484 Status
= Request
->InitializeWithIrp(m_DmaManager
, Irp
);
487 // mark irp as pending
489 IoMarkIrpPending(Irp
);
492 // now add the request
494 Status
= m_Queue
->AddUSBRequest(Request
);
495 if (!NT_SUCCESS(Status
))
498 // failed to add request
500 DPRINT1("CUSBDevice::CommitSetupPacket> failed add request to queue with %x\n", Status
);
508 return STATUS_PENDING
;
511 //----------------------------------------------------------------------------------------
513 CUSBDevice::SubmitIrp(
520 // acquire device lock
522 DPRINT(__FUNCTION__
" acquire\n");
523 KeAcquireSpinLock(&m_Lock
, &OldLevel
);
524 DPRINT(__FUNCTION__
" acquired\n");
529 Status
= CommitIrp(Irp
);
534 DPRINT(__FUNCTION__
"release\n");
535 KeReleaseSpinLock(&m_Lock
, OldLevel
);
539 //----------------------------------------------------------------------------------------
541 CUSBDevice::CommitSetupPacket(
542 IN PUSB_DEFAULT_PIPE_SETUP_PACKET Packet
,
543 IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor
,
544 IN ULONG BufferLength
,
555 DPRINT1("CUSBDevice::CommitSetupPacket> no queue!!!\n");
556 return STATUS_UNSUCCESSFUL
;
562 Status
= m_Queue
->CreateUSBRequest(&Request
);
563 if (!NT_SUCCESS(Status
))
566 // failed to build request
568 DPRINT1("CUSBDevice::CommitSetupPacket> CreateUSBRequest failed with %x\n", Status
);
573 // initialize request
575 Status
= Request
->InitializeWithSetupPacket(m_DmaManager
, Packet
, m_DeviceAddress
, EndpointDescriptor
, BufferLength
, Mdl
);
576 if (!NT_SUCCESS(Status
))
579 // failed to initialize request
581 DPRINT1("CUSBDevice::CommitSetupPacket> failed to initialize usb request with %x\n", Status
);
587 // now add the request
589 Status
= m_Queue
->AddUSBRequest(Request
);
590 if (!NT_SUCCESS(Status
))
593 // failed to add request
595 DPRINT1("CUSBDevice::CommitSetupPacket> failed add request to queue with %x\n", Status
);
601 // get the result code when the operation has been finished
603 Request
->GetResultStatus(&Status
, NULL
);
616 //----------------------------------------------------------------------------------------
618 CUSBDevice::CreateDeviceDescriptor()
620 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup
;
627 RtlZeroMemory(&m_DeviceDescriptor
, sizeof(USB_DEVICE_DESCRIPTOR
));
628 RtlZeroMemory(&CtrlSetup
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
633 CtrlSetup
.bRequest
= USB_REQUEST_GET_DESCRIPTOR
;
634 CtrlSetup
.wValue
.HiByte
= USB_DEVICE_DESCRIPTOR_TYPE
;
635 CtrlSetup
.wLength
= sizeof(USB_DEVICE_DESCRIPTOR
);
636 CtrlSetup
.bmRequestType
.B
= 0x80;
639 // allocate mdl describing the device descriptor
641 Mdl
= IoAllocateMdl(&m_DeviceDescriptor
, sizeof(USB_DEVICE_DESCRIPTOR
), FALSE
, FALSE
, 0);
645 // failed to allocate mdl
647 return STATUS_INSUFFICIENT_RESOURCES
;
651 // build mdl for non paged pool
653 MmBuildMdlForNonPagedPool(Mdl
);
656 // commit setup packet
658 Status
= CommitSetupPacket(&CtrlSetup
, 0, sizeof(USB_DEVICE_DESCRIPTOR
), Mdl
);
665 if (NT_SUCCESS(Status
))
668 // informal dbg print
670 DumpDeviceDescriptor(&m_DeviceDescriptor
);
680 //----------------------------------------------------------------------------------------
682 CUSBDevice::CreateConfigurationDescriptor(
686 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup
;
689 ULONG InterfaceIndex
, EndPointIndex
;
690 PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
;
691 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor
;
692 PUSB_ENDPOINT_DESCRIPTOR EndPointDescriptor
;
698 PC_ASSERT(m_ConfigurationDescriptors
);
701 // first allocate a buffer which should be enough to store all different interfaces and endpoints
703 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, PAGE_SIZE
, TAG_USBEHCI
);
707 // failed to allocate buffer
709 return STATUS_INSUFFICIENT_RESOURCES
;
713 // build setup packet
715 CtrlSetup
.bmRequestType
._BM
.Recipient
= BMREQUEST_TO_DEVICE
;
716 CtrlSetup
.bmRequestType
._BM
.Type
= BMREQUEST_STANDARD
;
717 CtrlSetup
.bmRequestType
._BM
.Reserved
= 0;
718 CtrlSetup
.bmRequestType
._BM
.Dir
= BMREQUEST_DEVICE_TO_HOST
;
719 CtrlSetup
.bRequest
= USB_REQUEST_GET_DESCRIPTOR
;
720 CtrlSetup
.wValue
.LowByte
= 0;
721 CtrlSetup
.wValue
.HiByte
= USB_CONFIGURATION_DESCRIPTOR_TYPE
;
722 CtrlSetup
.wIndex
.W
= 0;
723 CtrlSetup
.wLength
= PAGE_SIZE
;
726 // FIXME: where put configuration index?
730 // now build MDL describing the buffer
732 Mdl
= IoAllocateMdl(Buffer
, PAGE_SIZE
, FALSE
, FALSE
, 0);
736 // failed to allocate mdl
738 ExFreePoolWithTag(Buffer
, TAG_USBEHCI
);
739 return STATUS_INSUFFICIENT_RESOURCES
;
743 // build mdl for non paged pool
745 MmBuildMdlForNonPagedPool(Mdl
);
750 Status
= CommitSetupPacket(&CtrlSetup
, 0, PAGE_SIZE
, Mdl
);
751 if (!NT_SUCCESS(Status
))
754 // failed to issue request, cleanup
767 // get configuration descriptor
769 ConfigurationDescriptor
= (PUSB_CONFIGURATION_DESCRIPTOR
)Buffer
;
772 // informal debug print
774 DumpConfigurationDescriptor(ConfigurationDescriptor
);
779 PC_ASSERT(ConfigurationDescriptor
->bLength
== sizeof(USB_CONFIGURATION_DESCRIPTOR
));
780 PC_ASSERT(ConfigurationDescriptor
->wTotalLength
<= PAGE_SIZE
);
781 PC_ASSERT(ConfigurationDescriptor
->bNumInterfaces
);
784 // request is complete, initialize configuration descriptor
786 RtlCopyMemory(&m_ConfigurationDescriptors
[Index
].ConfigurationDescriptor
, ConfigurationDescriptor
, ConfigurationDescriptor
->bLength
);
789 // now allocate interface descriptors
791 m_ConfigurationDescriptors
[Index
].Interfaces
= (PUSB_INTERFACE
)ExAllocatePoolWithTag(NonPagedPool
, sizeof(USB_INTERFACE
) * ConfigurationDescriptor
->bNumInterfaces
, TAG_USBEHCI
);
792 if (!m_ConfigurationDescriptors
[Index
].Interfaces
)
795 // failed to allocate interface descriptors
798 return STATUS_INSUFFICIENT_RESOURCES
;
802 // zero interface descriptor
804 RtlZeroMemory(m_ConfigurationDescriptors
[Index
].Interfaces
, sizeof(USB_INTERFACE
) * ConfigurationDescriptor
->bNumInterfaces
);
807 // get first interface descriptor
809 InterfaceDescriptor
= (PUSB_INTERFACE_DESCRIPTOR
)(ConfigurationDescriptor
+ 1);
812 // setup interface descriptors
814 for(InterfaceIndex
= 0; InterfaceIndex
< ConfigurationDescriptor
->bNumInterfaces
; InterfaceIndex
++)
819 PC_ASSERT(InterfaceDescriptor
->bLength
== sizeof(USB_INTERFACE_DESCRIPTOR
));
820 PC_ASSERT(InterfaceDescriptor
->bNumEndpoints
);
823 // copy current interface descriptor
825 RtlCopyMemory(&m_ConfigurationDescriptors
[Index
].Interfaces
[InterfaceIndex
].InterfaceDescriptor
, InterfaceDescriptor
, InterfaceDescriptor
->bLength
);
828 // allocate end point descriptors
830 m_ConfigurationDescriptors
[Index
].Interfaces
[InterfaceIndex
].EndPoints
= (PUSB_ENDPOINT
)ExAllocatePoolWithTag(NonPagedPool
, sizeof(USB_ENDPOINT
) * InterfaceDescriptor
->bNumEndpoints
, TAG_USBEHCI
);
831 if (!m_ConfigurationDescriptors
[Index
].Interfaces
[InterfaceIndex
].EndPoints
)
834 // failed to allocate endpoint
836 Status
= STATUS_INSUFFICIENT_RESOURCES
;
843 RtlZeroMemory(m_ConfigurationDescriptors
[Index
].Interfaces
[InterfaceIndex
].EndPoints
, sizeof(USB_ENDPOINT
) * InterfaceDescriptor
->bNumEndpoints
);
846 // initialize end point descriptors
848 EndPointDescriptor
= (PUSB_ENDPOINT_DESCRIPTOR
)(InterfaceDescriptor
+ 1);
850 for(EndPointIndex
= 0; EndPointIndex
< InterfaceDescriptor
->bNumEndpoints
; EndPointIndex
++)
855 PC_ASSERT(EndPointDescriptor
->bLength
== sizeof(USB_ENDPOINT_DESCRIPTOR
));
858 // copy endpoint descriptor
860 RtlCopyMemory(&m_ConfigurationDescriptors
[Index
].Interfaces
[InterfaceIndex
].EndPoints
[EndPointIndex
].EndPointDescriptor
, EndPointDescriptor
, EndPointDescriptor
->bLength
);
863 // move to next offset
865 EndPointDescriptor
= (PUSB_ENDPOINT_DESCRIPTOR
)((ULONG_PTR
)EndPointDescriptor
+ EndPointDescriptor
->bLength
);
869 // update interface descriptor offset
871 InterfaceDescriptor
= (PUSB_INTERFACE_DESCRIPTOR
)EndPointDescriptor
;
877 ExFreePoolWithTag(Buffer
, TAG_USBEHCI
);
884 //----------------------------------------------------------------------------------------
886 CUSBDevice::GetConfigurationDescriptors(
887 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptorBuffer
,
888 IN ULONG BufferLength
,
889 OUT PULONG OutBufferLength
)
892 ULONG InterfaceIndex
, EndpointIndex
;
897 PC_ASSERT(BufferLength
>= sizeof(USB_CONFIGURATION_DESCRIPTOR
));
898 PC_ASSERT(ConfigDescriptorBuffer
);
899 PC_ASSERT(OutBufferLength
);
902 // reset copied length
904 *OutBufferLength
= 0;
907 // FIXME: support multiple configurations
909 PC_ASSERT(m_DeviceDescriptor
.bNumConfigurations
== 1);
912 // copy first configuration descriptor
914 RtlCopyMemory(ConfigDescriptorBuffer
, &m_ConfigurationDescriptors
[0].ConfigurationDescriptor
, sizeof(USB_CONFIGURATION_DESCRIPTOR
));
919 BufferLength
-= sizeof(USB_CONFIGURATION_DESCRIPTOR
);
920 *OutBufferLength
+= sizeof(USB_CONFIGURATION_DESCRIPTOR
);
925 Buffer
= (PVOID
)(ConfigDescriptorBuffer
+ 1);
927 for(InterfaceIndex
= 0; InterfaceIndex
< m_ConfigurationDescriptors
[0].ConfigurationDescriptor
.bNumInterfaces
; InterfaceIndex
++)
929 if (BufferLength
< sizeof(USB_INTERFACE_DESCRIPTOR
))
932 // no more room in buffer
938 // copy interface descriptor
940 RtlCopyMemory(Buffer
, &m_ConfigurationDescriptors
[0].Interfaces
[InterfaceIndex
].InterfaceDescriptor
, sizeof(USB_INTERFACE_DESCRIPTOR
));
945 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ sizeof(USB_INTERFACE_DESCRIPTOR
));
946 BufferLength
-= sizeof(USB_INTERFACE_DESCRIPTOR
);
947 *OutBufferLength
+= sizeof(USB_INTERFACE_DESCRIPTOR
);
950 // does the interface have endpoints
952 if (m_ConfigurationDescriptors
[0].Interfaces
[InterfaceIndex
].InterfaceDescriptor
.bNumEndpoints
)
955 // is enough space available
957 if (BufferLength
< sizeof(USB_ENDPOINT_DESCRIPTOR
) * m_ConfigurationDescriptors
[0].Interfaces
[InterfaceIndex
].InterfaceDescriptor
.bNumEndpoints
)
968 for(EndpointIndex
= 0; EndpointIndex
< m_ConfigurationDescriptors
[0].Interfaces
[InterfaceIndex
].InterfaceDescriptor
.bNumEndpoints
; EndpointIndex
++)
973 RtlCopyMemory(Buffer
, &m_ConfigurationDescriptors
[0].Interfaces
[InterfaceIndex
].EndPoints
[EndpointIndex
].EndPointDescriptor
, sizeof(USB_ENDPOINT_DESCRIPTOR
));
976 // increment buffer offset
978 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ sizeof(USB_ENDPOINT_DESCRIPTOR
));
979 BufferLength
-= sizeof(USB_ENDPOINT_DESCRIPTOR
);
980 *OutBufferLength
+= sizeof(USB_ENDPOINT_DESCRIPTOR
);
986 //----------------------------------------------------------------------------------------
988 CUSBDevice::GetConfigurationDescriptorsLength()
991 // FIXME: support multiple configurations
993 PC_ASSERT(m_DeviceDescriptor
.bNumConfigurations
== 1);
995 return m_ConfigurationDescriptors
[0].ConfigurationDescriptor
.wTotalLength
;
997 //----------------------------------------------------------------------------------------
999 CUSBDevice::DumpDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor
)
1001 DPRINT1("Dumping Device Descriptor %x\n", DeviceDescriptor
);
1002 DPRINT1("bLength %x\n", DeviceDescriptor
->bLength
);
1003 DPRINT1("bDescriptorType %x\n", DeviceDescriptor
->bDescriptorType
);
1004 DPRINT1("bcdUSB %x\n", DeviceDescriptor
->bcdUSB
);
1005 DPRINT1("bDeviceClass %x\n", DeviceDescriptor
->bDeviceClass
);
1006 DPRINT1("bDeviceSubClass %x\n", DeviceDescriptor
->bDeviceSubClass
);
1007 DPRINT1("bDeviceProtocol %x\n", DeviceDescriptor
->bDeviceProtocol
);
1008 DPRINT1("bMaxPacketSize0 %x\n", DeviceDescriptor
->bMaxPacketSize0
);
1009 DPRINT1("idVendor %x\n", DeviceDescriptor
->idVendor
);
1010 DPRINT1("idProduct %x\n", DeviceDescriptor
->idProduct
);
1011 DPRINT1("bcdDevice %x\n", DeviceDescriptor
->bcdDevice
);
1012 DPRINT1("iManufacturer %x\n", DeviceDescriptor
->iManufacturer
);
1013 DPRINT1("iProduct %x\n", DeviceDescriptor
->iProduct
);
1014 DPRINT1("iSerialNumber %x\n", DeviceDescriptor
->iSerialNumber
);
1015 DPRINT1("bNumConfigurations %x\n", DeviceDescriptor
->bNumConfigurations
);
1018 //----------------------------------------------------------------------------------------
1020 CUSBDevice::DumpConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
)
1022 DPRINT1("Dumping ConfigurationDescriptor %x\n", ConfigurationDescriptor
);
1023 DPRINT1("bLength %x\n", ConfigurationDescriptor
->bLength
);
1024 DPRINT1("bDescriptorType %x\n", ConfigurationDescriptor
->bDescriptorType
);
1025 DPRINT1("wTotalLength %x\n", ConfigurationDescriptor
->wTotalLength
);
1026 DPRINT1("bNumInterfaces %x\n", ConfigurationDescriptor
->bNumInterfaces
);
1027 DPRINT1("bConfigurationValue %x\n", ConfigurationDescriptor
->bConfigurationValue
);
1028 DPRINT1("iConfiguration %x\n", ConfigurationDescriptor
->iConfiguration
);
1029 DPRINT1("bmAttributes %x\n", ConfigurationDescriptor
->bmAttributes
);
1030 DPRINT1("MaxPower %x\n", ConfigurationDescriptor
->MaxPower
);
1032 //----------------------------------------------------------------------------------------
1034 CUSBDevice::SubmitSetupPacket(
1035 IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket
,
1036 IN OUT ULONG BufferLength
,
1045 Mdl
= IoAllocateMdl(Buffer
, BufferLength
, FALSE
, FALSE
, 0);
1048 // HACK HACK HACK: assume the buffer is build from non paged pool
1050 MmBuildMdlForNonPagedPool(Mdl
);
1053 // commit setup packet
1055 Status
= CommitSetupPacket(SetupPacket
, 0, BufferLength
, Mdl
);
1068 //----------------------------------------------------------------------------------------
1070 CUSBDevice::SelectConfiguration(
1071 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
,
1072 IN PUSBD_INTERFACE_INFORMATION InterfaceInfo
,
1073 OUT USBD_CONFIGURATION_HANDLE
*ConfigurationHandle
)
1075 ULONG ConfigurationIndex
= 0;
1076 ULONG InterfaceIndex
, PipeIndex
;
1077 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup
;
1081 // FIXME: support multiple configurations
1083 PC_ASSERT(m_DeviceDescriptor
.bNumConfigurations
== 1);
1084 PC_ASSERT(ConfigurationDescriptor
->iConfiguration
== m_ConfigurationDescriptors
[ConfigurationIndex
].ConfigurationDescriptor
.iConfiguration
);
1089 PC_ASSERT(ConfigurationDescriptor
->bNumInterfaces
<= m_ConfigurationDescriptors
[ConfigurationIndex
].ConfigurationDescriptor
.bNumInterfaces
);
1092 // copy interface info and pipe info
1094 for(InterfaceIndex
= 0; InterfaceIndex
< ConfigurationDescriptor
->bNumInterfaces
; InterfaceIndex
++)
1097 // sanity check: is the info pre-layed out
1099 PC_ASSERT(InterfaceInfo
->NumberOfPipes
== m_ConfigurationDescriptors
[ConfigurationIndex
].Interfaces
[InterfaceIndex
].InterfaceDescriptor
.bNumEndpoints
);
1100 PC_ASSERT(InterfaceInfo
->Length
!= 0);
1102 PC_ASSERT(InterfaceInfo
->Length
== FIELD_OFFSET(USBD_INTERFACE_INFORMATION
, Pipes
[InterfaceInfo
->NumberOfPipes
]));
1106 // copy interface info
1108 InterfaceInfo
->InterfaceHandle
= (USBD_INTERFACE_HANDLE
)&m_ConfigurationDescriptors
[ConfigurationIndex
].Interfaces
[InterfaceIndex
];
1109 InterfaceInfo
->Class
= m_ConfigurationDescriptors
[ConfigurationIndex
].Interfaces
[InterfaceIndex
].InterfaceDescriptor
.bInterfaceClass
;
1110 InterfaceInfo
->SubClass
= m_ConfigurationDescriptors
[ConfigurationIndex
].Interfaces
[InterfaceIndex
].InterfaceDescriptor
.bInterfaceSubClass
;
1111 InterfaceInfo
->Protocol
= m_ConfigurationDescriptors
[ConfigurationIndex
].Interfaces
[InterfaceIndex
].InterfaceDescriptor
.bInterfaceProtocol
;
1112 InterfaceInfo
->Reserved
= 0;
1115 // copy endpoint info
1117 for(PipeIndex
= 0; PipeIndex
< InterfaceInfo
->NumberOfPipes
; PipeIndex
++)
1122 InterfaceInfo
->Pipes
[PipeIndex
].MaximumPacketSize
= m_ConfigurationDescriptors
[ConfigurationIndex
].Interfaces
[InterfaceIndex
].EndPoints
[PipeIndex
].EndPointDescriptor
.wMaxPacketSize
;
1123 InterfaceInfo
->Pipes
[PipeIndex
].EndpointAddress
= m_ConfigurationDescriptors
[ConfigurationIndex
].Interfaces
[InterfaceIndex
].EndPoints
[PipeIndex
].EndPointDescriptor
.bEndpointAddress
;
1124 InterfaceInfo
->Pipes
[PipeIndex
].Interval
= m_ConfigurationDescriptors
[ConfigurationIndex
].Interfaces
[InterfaceIndex
].EndPoints
[PipeIndex
].EndPointDescriptor
.bInterval
;
1125 InterfaceInfo
->Pipes
[PipeIndex
].PipeType
= (USBD_PIPE_TYPE
)m_ConfigurationDescriptors
[ConfigurationIndex
].Interfaces
[InterfaceIndex
].EndPoints
[PipeIndex
].EndPointDescriptor
.bmAttributes
;
1126 InterfaceInfo
->Pipes
[PipeIndex
].PipeHandle
= (PVOID
)&m_ConfigurationDescriptors
[ConfigurationIndex
].Interfaces
[InterfaceIndex
].EndPoints
[PipeIndex
].EndPointDescriptor
;
1132 InterfaceInfo
= (PUSBD_INTERFACE_INFORMATION
)((ULONG_PTR
)PtrToUlong(InterfaceInfo
) + InterfaceInfo
->Length
);
1136 // now build setup packet
1138 RtlZeroMemory(&CtrlSetup
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
1139 CtrlSetup
.bRequest
= USB_REQUEST_SET_CONFIGURATION
;
1140 CtrlSetup
.wValue
.W
= ConfigurationDescriptor
->bConfigurationValue
;
1143 // select configuration
1145 Status
= CommitSetupPacket(&CtrlSetup
, 0, 0, 0);
1148 // informal debug print
1150 DPRINT1("CUsbDevice::SelectConfiguration New Configuration %x Old Configuration %x Result %x\n", ConfigurationDescriptor
->iConfiguration
, m_ConfigurationIndex
, Status
);
1152 if (NT_SUCCESS(Status
))
1155 // store configuration device index
1157 m_ConfigurationIndex
= ConfigurationDescriptor
->iConfiguration
;
1160 // store configuration handle
1162 *ConfigurationHandle
= &m_ConfigurationDescriptors
[ConfigurationIndex
];
1171 //----------------------------------------------------------------------------------------
1173 CUSBDevice::SelectInterface(
1174 IN USBD_CONFIGURATION_HANDLE ConfigurationHandle
,
1175 IN OUT PUSBD_INTERFACE_INFORMATION InterfaceInfo
)
1177 ULONG ConfigurationIndex
= 0;
1178 PUSB_CONFIGURATION Configuration
;
1180 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup
;
1184 // FIXME support multiple configurations
1186 PC_ASSERT(&m_ConfigurationDescriptors
[ConfigurationIndex
] == (PUSB_CONFIGURATION
)ConfigurationHandle
);
1189 // get configuration struct
1191 Configuration
= (PUSB_CONFIGURATION
)ConfigurationHandle
;
1196 PC_ASSERT(Configuration
->ConfigurationDescriptor
.bNumInterfaces
> InterfaceInfo
->InterfaceNumber
);
1197 PC_ASSERT(Configuration
->Interfaces
[InterfaceInfo
->InterfaceNumber
].InterfaceDescriptor
.bNumEndpoints
== InterfaceInfo
->NumberOfPipes
);
1199 PC_ASSERT(InterfaceInfo
->Length
== FIELD_OFFSET(USBD_INTERFACE_INFORMATION
, Pipes
[InterfaceInfo
->NumberOfPipes
]));
1203 // copy pipe handles
1205 for(PipeIndex
= 0; PipeIndex
< InterfaceInfo
->NumberOfPipes
; PipeIndex
++)
1210 DPRINT1("PipeIndex %lu\n", PipeIndex
);
1211 DPRINT1("EndpointAddress %x\n", InterfaceInfo
->Pipes
[PipeIndex
].EndpointAddress
);
1212 DPRINT1("Interval %d\n", InterfaceInfo
->Pipes
[PipeIndex
].Interval
);
1213 DPRINT1("MaximumPacketSize %d\n", InterfaceInfo
->Pipes
[PipeIndex
].MaximumPacketSize
);
1214 DPRINT1("MaximumTransferSize %d\n", InterfaceInfo
->Pipes
[PipeIndex
].MaximumTransferSize
);
1215 DPRINT1("PipeFlags %d\n", InterfaceInfo
->Pipes
[PipeIndex
].PipeFlags
);
1216 DPRINT1("PipeType %dd\n", InterfaceInfo
->Pipes
[PipeIndex
].PipeType
);
1217 DPRINT1("UsbEndPoint %x\n", Configuration
->Interfaces
[InterfaceInfo
->InterfaceNumber
].EndPoints
[PipeIndex
].EndPointDescriptor
.bEndpointAddress
);
1218 PC_ASSERT(Configuration
->Interfaces
[InterfaceInfo
->InterfaceNumber
].EndPoints
[PipeIndex
].EndPointDescriptor
.bEndpointAddress
== InterfaceInfo
->Pipes
[PipeIndex
].EndpointAddress
);
1220 InterfaceInfo
->Pipes
[PipeIndex
].PipeHandle
= &Configuration
->Interfaces
[InterfaceInfo
->InterfaceNumber
].EndPoints
[PipeIndex
].EndPointDescriptor
;
1222 if (Configuration
->Interfaces
[InterfaceInfo
->InterfaceNumber
].EndPoints
[PipeIndex
].EndPointDescriptor
.bmAttributes
& (USB_ENDPOINT_TYPE_ISOCHRONOUS
| USB_ENDPOINT_TYPE_INTERRUPT
))
1225 // FIXME: check if enough bandwidth is available
1231 // initialize setup packet
1233 RtlZeroMemory(&CtrlSetup
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
1234 CtrlSetup
.bRequest
= USB_REQUEST_SET_INTERFACE
;
1235 CtrlSetup
.wValue
.W
= Configuration
->Interfaces
[InterfaceInfo
->InterfaceNumber
].InterfaceDescriptor
.bAlternateSetting
;
1236 CtrlSetup
.wIndex
.W
= Configuration
->Interfaces
[InterfaceInfo
->InterfaceNumber
].InterfaceDescriptor
.bInterfaceNumber
;
1237 CtrlSetup
.bmRequestType
.B
= 0x01;
1242 Status
= CommitSetupPacket(&CtrlSetup
, 0, 0, 0);
1245 // informal debug print
1247 DPRINT1("CUSBDevice::SelectInterface AlternateSetting %x InterfaceNumber %x Status %x\n", InterfaceInfo
->AlternateSetting
, InterfaceInfo
->InterfaceNumber
, Status
);
1255 //----------------------------------------------------------------------------------------
1258 PUSBDEVICE
*OutDevice
)
1263 // allocate controller
1265 This
= new(NonPagedPool
, TAG_USBEHCI
) CUSBDevice(0);
1269 // failed to allocate
1271 return STATUS_INSUFFICIENT_RESOURCES
;
1275 // add reference count
1282 *OutDevice
= (PUSBDEVICE
)This
;
1287 return STATUS_SUCCESS
;