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 KeAcquireSpinLock(&m_Lock
, &OldLevel
);
527 Status
= CommitIrp(Irp
);
532 KeReleaseSpinLock(&m_Lock
, OldLevel
);
536 //----------------------------------------------------------------------------------------
538 CUSBDevice::CommitSetupPacket(
539 IN PUSB_DEFAULT_PIPE_SETUP_PACKET Packet
,
540 IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor
,
541 IN ULONG BufferLength
,
552 DPRINT1("CUSBDevice::CommitSetupPacket> no queue!!!\n");
553 return STATUS_UNSUCCESSFUL
;
559 Status
= m_Queue
->CreateUSBRequest(&Request
);
560 if (!NT_SUCCESS(Status
))
563 // failed to build request
565 DPRINT1("CUSBDevice::CommitSetupPacket> CreateUSBRequest failed with %x\n", Status
);
570 // initialize request
572 Status
= Request
->InitializeWithSetupPacket(m_DmaManager
, Packet
, m_DeviceAddress
, EndpointDescriptor
, BufferLength
, Mdl
);
573 if (!NT_SUCCESS(Status
))
576 // failed to initialize request
578 DPRINT1("CUSBDevice::CommitSetupPacket> failed to initialize usb request with %x\n", Status
);
584 // now add the request
586 Status
= m_Queue
->AddUSBRequest(Request
);
587 if (!NT_SUCCESS(Status
))
590 // failed to add request
592 DPRINT1("CUSBDevice::CommitSetupPacket> failed add request to queue with %x\n", Status
);
598 // get the result code when the operation has been finished
600 Request
->GetResultStatus(&Status
, NULL
);
613 //----------------------------------------------------------------------------------------
615 CUSBDevice::CreateDeviceDescriptor()
617 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup
;
624 RtlZeroMemory(&m_DeviceDescriptor
, sizeof(USB_DEVICE_DESCRIPTOR
));
625 RtlZeroMemory(&CtrlSetup
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
630 CtrlSetup
.bRequest
= USB_REQUEST_GET_DESCRIPTOR
;
631 CtrlSetup
.wValue
.HiByte
= USB_DEVICE_DESCRIPTOR_TYPE
;
632 CtrlSetup
.wLength
= sizeof(USB_DEVICE_DESCRIPTOR
);
633 CtrlSetup
.bmRequestType
.B
= 0x80;
636 // allocate mdl describing the device descriptor
638 Mdl
= IoAllocateMdl(&m_DeviceDescriptor
, sizeof(USB_DEVICE_DESCRIPTOR
), FALSE
, FALSE
, 0);
642 // failed to allocate mdl
644 return STATUS_INSUFFICIENT_RESOURCES
;
648 // build mdl for non paged pool
650 MmBuildMdlForNonPagedPool(Mdl
);
653 // commit setup packet
655 Status
= CommitSetupPacket(&CtrlSetup
, 0, sizeof(USB_DEVICE_DESCRIPTOR
), Mdl
);
662 if (NT_SUCCESS(Status
))
665 // informal dbg print
667 DumpDeviceDescriptor(&m_DeviceDescriptor
);
677 //----------------------------------------------------------------------------------------
679 CUSBDevice::CreateConfigurationDescriptor(
683 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup
;
686 ULONG InterfaceIndex
, EndPointIndex
;
687 PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
;
688 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor
;
689 PUSB_ENDPOINT_DESCRIPTOR EndPointDescriptor
;
695 PC_ASSERT(m_ConfigurationDescriptors
);
698 // first allocate a buffer which should be enough to store all different interfaces and endpoints
700 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, PAGE_SIZE
, TAG_USBEHCI
);
704 // failed to allocate buffer
706 return STATUS_INSUFFICIENT_RESOURCES
;
710 // build setup packet
712 CtrlSetup
.bmRequestType
._BM
.Recipient
= BMREQUEST_TO_DEVICE
;
713 CtrlSetup
.bmRequestType
._BM
.Type
= BMREQUEST_STANDARD
;
714 CtrlSetup
.bmRequestType
._BM
.Reserved
= 0;
715 CtrlSetup
.bmRequestType
._BM
.Dir
= BMREQUEST_DEVICE_TO_HOST
;
716 CtrlSetup
.bRequest
= USB_REQUEST_GET_DESCRIPTOR
;
717 CtrlSetup
.wValue
.LowByte
= 0;
718 CtrlSetup
.wValue
.HiByte
= USB_CONFIGURATION_DESCRIPTOR_TYPE
;
719 CtrlSetup
.wIndex
.W
= 0;
720 CtrlSetup
.wLength
= PAGE_SIZE
;
723 // FIXME: where put configuration index?
727 // now build MDL describing the buffer
729 Mdl
= IoAllocateMdl(Buffer
, PAGE_SIZE
, FALSE
, FALSE
, 0);
733 // failed to allocate mdl
735 ExFreePoolWithTag(Buffer
, TAG_USBEHCI
);
736 return STATUS_INSUFFICIENT_RESOURCES
;
740 // build mdl for non paged pool
742 MmBuildMdlForNonPagedPool(Mdl
);
747 Status
= CommitSetupPacket(&CtrlSetup
, 0, PAGE_SIZE
, Mdl
);
748 if (!NT_SUCCESS(Status
))
751 // failed to issue request, cleanup
764 // get configuration descriptor
766 ConfigurationDescriptor
= (PUSB_CONFIGURATION_DESCRIPTOR
)Buffer
;
769 // informal debug print
771 DumpConfigurationDescriptor(ConfigurationDescriptor
);
776 PC_ASSERT(ConfigurationDescriptor
->bLength
== sizeof(USB_CONFIGURATION_DESCRIPTOR
));
777 PC_ASSERT(ConfigurationDescriptor
->wTotalLength
<= PAGE_SIZE
);
778 PC_ASSERT(ConfigurationDescriptor
->bNumInterfaces
);
781 // request is complete, initialize configuration descriptor
783 RtlCopyMemory(&m_ConfigurationDescriptors
[Index
].ConfigurationDescriptor
, ConfigurationDescriptor
, ConfigurationDescriptor
->bLength
);
786 // now allocate interface descriptors
788 m_ConfigurationDescriptors
[Index
].Interfaces
= (PUSB_INTERFACE
)ExAllocatePoolWithTag(NonPagedPool
, sizeof(USB_INTERFACE
) * ConfigurationDescriptor
->bNumInterfaces
, TAG_USBEHCI
);
789 if (!m_ConfigurationDescriptors
[Index
].Interfaces
)
792 // failed to allocate interface descriptors
795 return STATUS_INSUFFICIENT_RESOURCES
;
799 // zero interface descriptor
801 RtlZeroMemory(m_ConfigurationDescriptors
[Index
].Interfaces
, sizeof(USB_INTERFACE
) * ConfigurationDescriptor
->bNumInterfaces
);
804 // get first interface descriptor
806 InterfaceDescriptor
= (PUSB_INTERFACE_DESCRIPTOR
)(ConfigurationDescriptor
+ 1);
809 // setup interface descriptors
811 for(InterfaceIndex
= 0; InterfaceIndex
< ConfigurationDescriptor
->bNumInterfaces
; InterfaceIndex
++)
816 PC_ASSERT(InterfaceDescriptor
->bLength
== sizeof(USB_INTERFACE_DESCRIPTOR
));
817 PC_ASSERT(InterfaceDescriptor
->bNumEndpoints
);
820 // copy current interface descriptor
822 RtlCopyMemory(&m_ConfigurationDescriptors
[Index
].Interfaces
[InterfaceIndex
].InterfaceDescriptor
, InterfaceDescriptor
, InterfaceDescriptor
->bLength
);
825 // allocate end point descriptors
827 m_ConfigurationDescriptors
[Index
].Interfaces
[InterfaceIndex
].EndPoints
= (PUSB_ENDPOINT
)ExAllocatePoolWithTag(NonPagedPool
, sizeof(USB_ENDPOINT
) * InterfaceDescriptor
->bNumEndpoints
, TAG_USBEHCI
);
828 if (!m_ConfigurationDescriptors
[Index
].Interfaces
[InterfaceIndex
].EndPoints
)
831 // failed to allocate endpoint
833 Status
= STATUS_INSUFFICIENT_RESOURCES
;
840 RtlZeroMemory(m_ConfigurationDescriptors
[Index
].Interfaces
[InterfaceIndex
].EndPoints
, sizeof(USB_ENDPOINT
) * InterfaceDescriptor
->bNumEndpoints
);
843 // initialize end point descriptors
845 EndPointDescriptor
= (PUSB_ENDPOINT_DESCRIPTOR
)(InterfaceDescriptor
+ 1);
847 for(EndPointIndex
= 0; EndPointIndex
< InterfaceDescriptor
->bNumEndpoints
; EndPointIndex
++)
852 PC_ASSERT(EndPointDescriptor
->bLength
== sizeof(USB_ENDPOINT_DESCRIPTOR
));
855 // copy endpoint descriptor
857 RtlCopyMemory(&m_ConfigurationDescriptors
[Index
].Interfaces
[InterfaceIndex
].EndPoints
[EndPointIndex
].EndPointDescriptor
, EndPointDescriptor
, EndPointDescriptor
->bLength
);
860 // move to next offset
862 EndPointDescriptor
= (PUSB_ENDPOINT_DESCRIPTOR
)((ULONG_PTR
)EndPointDescriptor
+ EndPointDescriptor
->bLength
);
866 // update interface descriptor offset
868 InterfaceDescriptor
= (PUSB_INTERFACE_DESCRIPTOR
)EndPointDescriptor
;
874 ExFreePoolWithTag(Buffer
, TAG_USBEHCI
);
881 //----------------------------------------------------------------------------------------
883 CUSBDevice::GetConfigurationDescriptors(
884 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptorBuffer
,
885 IN ULONG BufferLength
,
886 OUT PULONG OutBufferLength
)
889 ULONG InterfaceIndex
, EndpointIndex
;
894 PC_ASSERT(BufferLength
>= sizeof(USB_CONFIGURATION_DESCRIPTOR
));
895 PC_ASSERT(ConfigDescriptorBuffer
);
896 PC_ASSERT(OutBufferLength
);
899 // reset copied length
901 *OutBufferLength
= 0;
904 // FIXME: support multiple configurations
906 PC_ASSERT(m_DeviceDescriptor
.bNumConfigurations
== 1);
909 // copy first configuration descriptor
911 RtlCopyMemory(ConfigDescriptorBuffer
, &m_ConfigurationDescriptors
[0].ConfigurationDescriptor
, sizeof(USB_CONFIGURATION_DESCRIPTOR
));
916 BufferLength
-= sizeof(USB_CONFIGURATION_DESCRIPTOR
);
917 *OutBufferLength
+= sizeof(USB_CONFIGURATION_DESCRIPTOR
);
922 Buffer
= (PVOID
)(ConfigDescriptorBuffer
+ 1);
924 for(InterfaceIndex
= 0; InterfaceIndex
< m_ConfigurationDescriptors
[0].ConfigurationDescriptor
.bNumInterfaces
; InterfaceIndex
++)
926 if (BufferLength
< sizeof(USB_INTERFACE_DESCRIPTOR
))
929 // no more room in buffer
935 // copy interface descriptor
937 RtlCopyMemory(Buffer
, &m_ConfigurationDescriptors
[0].Interfaces
[InterfaceIndex
].InterfaceDescriptor
, sizeof(USB_INTERFACE_DESCRIPTOR
));
942 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ sizeof(USB_INTERFACE_DESCRIPTOR
));
943 BufferLength
-= sizeof(USB_INTERFACE_DESCRIPTOR
);
944 *OutBufferLength
+= sizeof(USB_INTERFACE_DESCRIPTOR
);
947 // does the interface have endpoints
949 if (m_ConfigurationDescriptors
[0].Interfaces
[InterfaceIndex
].InterfaceDescriptor
.bNumEndpoints
)
952 // is enough space available
954 if (BufferLength
< sizeof(USB_ENDPOINT_DESCRIPTOR
) * m_ConfigurationDescriptors
[0].Interfaces
[InterfaceIndex
].InterfaceDescriptor
.bNumEndpoints
)
965 for(EndpointIndex
= 0; EndpointIndex
< m_ConfigurationDescriptors
[0].Interfaces
[InterfaceIndex
].InterfaceDescriptor
.bNumEndpoints
; EndpointIndex
++)
970 RtlCopyMemory(Buffer
, &m_ConfigurationDescriptors
[0].Interfaces
[InterfaceIndex
].EndPoints
[EndpointIndex
].EndPointDescriptor
, sizeof(USB_ENDPOINT_DESCRIPTOR
));
973 // increment buffer offset
975 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ sizeof(USB_ENDPOINT_DESCRIPTOR
));
976 BufferLength
-= sizeof(USB_ENDPOINT_DESCRIPTOR
);
977 *OutBufferLength
+= sizeof(USB_ENDPOINT_DESCRIPTOR
);
983 //----------------------------------------------------------------------------------------
985 CUSBDevice::GetConfigurationDescriptorsLength()
988 // FIXME: support multiple configurations
990 PC_ASSERT(m_DeviceDescriptor
.bNumConfigurations
== 1);
992 return m_ConfigurationDescriptors
[0].ConfigurationDescriptor
.wTotalLength
;
994 //----------------------------------------------------------------------------------------
996 CUSBDevice::DumpDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor
)
998 DPRINT1("Dumping Device Descriptor %x\n", DeviceDescriptor
);
999 DPRINT1("bLength %x\n", DeviceDescriptor
->bLength
);
1000 DPRINT1("bDescriptorType %x\n", DeviceDescriptor
->bDescriptorType
);
1001 DPRINT1("bcdUSB %x\n", DeviceDescriptor
->bcdUSB
);
1002 DPRINT1("bDeviceClass %x\n", DeviceDescriptor
->bDeviceClass
);
1003 DPRINT1("bDeviceSubClass %x\n", DeviceDescriptor
->bDeviceSubClass
);
1004 DPRINT1("bDeviceProtocol %x\n", DeviceDescriptor
->bDeviceProtocol
);
1005 DPRINT1("bMaxPacketSize0 %x\n", DeviceDescriptor
->bMaxPacketSize0
);
1006 DPRINT1("idVendor %x\n", DeviceDescriptor
->idVendor
);
1007 DPRINT1("idProduct %x\n", DeviceDescriptor
->idProduct
);
1008 DPRINT1("bcdDevice %x\n", DeviceDescriptor
->bcdDevice
);
1009 DPRINT1("iManufacturer %x\n", DeviceDescriptor
->iManufacturer
);
1010 DPRINT1("iProduct %x\n", DeviceDescriptor
->iProduct
);
1011 DPRINT1("iSerialNumber %x\n", DeviceDescriptor
->iSerialNumber
);
1012 DPRINT1("bNumConfigurations %x\n", DeviceDescriptor
->bNumConfigurations
);
1015 //----------------------------------------------------------------------------------------
1017 CUSBDevice::DumpConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
)
1019 DPRINT1("Dumping ConfigurationDescriptor %x\n", ConfigurationDescriptor
);
1020 DPRINT1("bLength %x\n", ConfigurationDescriptor
->bLength
);
1021 DPRINT1("bDescriptorType %x\n", ConfigurationDescriptor
->bDescriptorType
);
1022 DPRINT1("wTotalLength %x\n", ConfigurationDescriptor
->wTotalLength
);
1023 DPRINT1("bNumInterfaces %x\n", ConfigurationDescriptor
->bNumInterfaces
);
1024 DPRINT1("bConfigurationValue %x\n", ConfigurationDescriptor
->bConfigurationValue
);
1025 DPRINT1("iConfiguration %x\n", ConfigurationDescriptor
->iConfiguration
);
1026 DPRINT1("bmAttributes %x\n", ConfigurationDescriptor
->bmAttributes
);
1027 DPRINT1("MaxPower %x\n", ConfigurationDescriptor
->MaxPower
);
1029 //----------------------------------------------------------------------------------------
1031 CUSBDevice::SubmitSetupPacket(
1032 IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket
,
1033 IN OUT ULONG BufferLength
,
1042 Mdl
= IoAllocateMdl(Buffer
, BufferLength
, FALSE
, FALSE
, 0);
1045 // HACK HACK HACK: assume the buffer is build from non paged pool
1047 MmBuildMdlForNonPagedPool(Mdl
);
1050 // commit setup packet
1052 Status
= CommitSetupPacket(SetupPacket
, 0, BufferLength
, Mdl
);
1065 //----------------------------------------------------------------------------------------
1067 CUSBDevice::SelectConfiguration(
1068 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
,
1069 IN PUSBD_INTERFACE_INFORMATION InterfaceInfo
,
1070 OUT USBD_CONFIGURATION_HANDLE
*ConfigurationHandle
)
1072 ULONG ConfigurationIndex
= 0;
1073 ULONG InterfaceIndex
, PipeIndex
;
1074 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup
;
1078 // FIXME: support multiple configurations
1080 PC_ASSERT(m_DeviceDescriptor
.bNumConfigurations
== 1);
1081 PC_ASSERT(ConfigurationDescriptor
->iConfiguration
== m_ConfigurationDescriptors
[ConfigurationIndex
].ConfigurationDescriptor
.iConfiguration
);
1086 PC_ASSERT(ConfigurationDescriptor
->bNumInterfaces
<= m_ConfigurationDescriptors
[ConfigurationIndex
].ConfigurationDescriptor
.bNumInterfaces
);
1089 // copy interface info and pipe info
1091 for(InterfaceIndex
= 0; InterfaceIndex
< ConfigurationDescriptor
->bNumInterfaces
; InterfaceIndex
++)
1094 // sanity check: is the info pre-layed out
1096 PC_ASSERT(InterfaceInfo
->NumberOfPipes
== m_ConfigurationDescriptors
[ConfigurationIndex
].Interfaces
[InterfaceIndex
].InterfaceDescriptor
.bNumEndpoints
);
1097 PC_ASSERT(InterfaceInfo
->Length
!= 0);
1099 PC_ASSERT(InterfaceInfo
->Length
== FIELD_OFFSET(USBD_INTERFACE_INFORMATION
, Pipes
[InterfaceInfo
->NumberOfPipes
]));
1103 // copy interface info
1105 InterfaceInfo
->InterfaceHandle
= (USBD_INTERFACE_HANDLE
)&m_ConfigurationDescriptors
[ConfigurationIndex
].Interfaces
[InterfaceIndex
];
1106 InterfaceInfo
->Class
= m_ConfigurationDescriptors
[ConfigurationIndex
].Interfaces
[InterfaceIndex
].InterfaceDescriptor
.bInterfaceClass
;
1107 InterfaceInfo
->SubClass
= m_ConfigurationDescriptors
[ConfigurationIndex
].Interfaces
[InterfaceIndex
].InterfaceDescriptor
.bInterfaceSubClass
;
1108 InterfaceInfo
->Protocol
= m_ConfigurationDescriptors
[ConfigurationIndex
].Interfaces
[InterfaceIndex
].InterfaceDescriptor
.bInterfaceProtocol
;
1109 InterfaceInfo
->Reserved
= 0;
1112 // copy endpoint info
1114 for(PipeIndex
= 0; PipeIndex
< InterfaceInfo
->NumberOfPipes
; PipeIndex
++)
1119 InterfaceInfo
->Pipes
[PipeIndex
].MaximumPacketSize
= m_ConfigurationDescriptors
[ConfigurationIndex
].Interfaces
[InterfaceIndex
].EndPoints
[PipeIndex
].EndPointDescriptor
.wMaxPacketSize
;
1120 InterfaceInfo
->Pipes
[PipeIndex
].EndpointAddress
= m_ConfigurationDescriptors
[ConfigurationIndex
].Interfaces
[InterfaceIndex
].EndPoints
[PipeIndex
].EndPointDescriptor
.bEndpointAddress
;
1121 InterfaceInfo
->Pipes
[PipeIndex
].Interval
= m_ConfigurationDescriptors
[ConfigurationIndex
].Interfaces
[InterfaceIndex
].EndPoints
[PipeIndex
].EndPointDescriptor
.bInterval
;
1122 InterfaceInfo
->Pipes
[PipeIndex
].PipeType
= (USBD_PIPE_TYPE
)m_ConfigurationDescriptors
[ConfigurationIndex
].Interfaces
[InterfaceIndex
].EndPoints
[PipeIndex
].EndPointDescriptor
.bmAttributes
;
1123 InterfaceInfo
->Pipes
[PipeIndex
].PipeHandle
= (PVOID
)&m_ConfigurationDescriptors
[ConfigurationIndex
].Interfaces
[InterfaceIndex
].EndPoints
[PipeIndex
].EndPointDescriptor
;
1129 InterfaceInfo
= (PUSBD_INTERFACE_INFORMATION
)((ULONG_PTR
)PtrToUlong(InterfaceInfo
) + InterfaceInfo
->Length
);
1133 // now build setup packet
1135 RtlZeroMemory(&CtrlSetup
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
1136 CtrlSetup
.bRequest
= USB_REQUEST_SET_CONFIGURATION
;
1137 CtrlSetup
.wValue
.W
= ConfigurationDescriptor
->bConfigurationValue
;
1140 // select configuration
1142 Status
= CommitSetupPacket(&CtrlSetup
, 0, 0, 0);
1145 // informal debug print
1147 DPRINT1("CUsbDevice::SelectConfiguration New Configuration %x Old Configuration %x Result %x\n", ConfigurationDescriptor
->iConfiguration
, m_ConfigurationIndex
, Status
);
1149 if (NT_SUCCESS(Status
))
1152 // store configuration device index
1154 m_ConfigurationIndex
= ConfigurationDescriptor
->iConfiguration
;
1157 // store configuration handle
1159 *ConfigurationHandle
= &m_ConfigurationDescriptors
[ConfigurationIndex
];
1168 //----------------------------------------------------------------------------------------
1170 CUSBDevice::SelectInterface(
1171 IN USBD_CONFIGURATION_HANDLE ConfigurationHandle
,
1172 IN OUT PUSBD_INTERFACE_INFORMATION InterfaceInfo
)
1174 ULONG ConfigurationIndex
= 0;
1175 PUSB_CONFIGURATION Configuration
;
1177 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup
;
1181 // FIXME support multiple configurations
1183 PC_ASSERT(&m_ConfigurationDescriptors
[ConfigurationIndex
] == (PUSB_CONFIGURATION
)ConfigurationHandle
);
1186 // get configuration struct
1188 Configuration
= (PUSB_CONFIGURATION
)ConfigurationHandle
;
1193 PC_ASSERT(Configuration
->ConfigurationDescriptor
.bNumInterfaces
> InterfaceInfo
->InterfaceNumber
);
1194 PC_ASSERT(Configuration
->Interfaces
[InterfaceInfo
->InterfaceNumber
].InterfaceDescriptor
.bNumEndpoints
== InterfaceInfo
->NumberOfPipes
);
1196 PC_ASSERT(InterfaceInfo
->Length
== FIELD_OFFSET(USBD_INTERFACE_INFORMATION
, Pipes
[InterfaceInfo
->NumberOfPipes
]));
1200 // copy pipe handles
1202 for(PipeIndex
= 0; PipeIndex
< InterfaceInfo
->NumberOfPipes
; PipeIndex
++)
1207 DPRINT1("PipeIndex %lu\n", PipeIndex
);
1208 DPRINT1("EndpointAddress %x\n", InterfaceInfo
->Pipes
[PipeIndex
].EndpointAddress
);
1209 DPRINT1("Interval %d\n", InterfaceInfo
->Pipes
[PipeIndex
].Interval
);
1210 DPRINT1("MaximumPacketSize %d\n", InterfaceInfo
->Pipes
[PipeIndex
].MaximumPacketSize
);
1211 DPRINT1("MaximumTransferSize %d\n", InterfaceInfo
->Pipes
[PipeIndex
].MaximumTransferSize
);
1212 DPRINT1("PipeFlags %d\n", InterfaceInfo
->Pipes
[PipeIndex
].PipeFlags
);
1213 DPRINT1("PipeType %dd\n", InterfaceInfo
->Pipes
[PipeIndex
].PipeType
);
1214 DPRINT1("UsbEndPoint %x\n", Configuration
->Interfaces
[InterfaceInfo
->InterfaceNumber
].EndPoints
[PipeIndex
].EndPointDescriptor
.bEndpointAddress
);
1215 PC_ASSERT(Configuration
->Interfaces
[InterfaceInfo
->InterfaceNumber
].EndPoints
[PipeIndex
].EndPointDescriptor
.bEndpointAddress
== InterfaceInfo
->Pipes
[PipeIndex
].EndpointAddress
);
1217 InterfaceInfo
->Pipes
[PipeIndex
].PipeHandle
= &Configuration
->Interfaces
[InterfaceInfo
->InterfaceNumber
].EndPoints
[PipeIndex
].EndPointDescriptor
;
1219 if (Configuration
->Interfaces
[InterfaceInfo
->InterfaceNumber
].EndPoints
[PipeIndex
].EndPointDescriptor
.bmAttributes
& (USB_ENDPOINT_TYPE_ISOCHRONOUS
| USB_ENDPOINT_TYPE_INTERRUPT
))
1222 // FIXME: check if enough bandwidth is available
1228 // initialize setup packet
1230 RtlZeroMemory(&CtrlSetup
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
1231 CtrlSetup
.bRequest
= USB_REQUEST_SET_INTERFACE
;
1232 CtrlSetup
.wValue
.W
= Configuration
->Interfaces
[InterfaceInfo
->InterfaceNumber
].InterfaceDescriptor
.bAlternateSetting
;
1233 CtrlSetup
.wIndex
.W
= Configuration
->Interfaces
[InterfaceInfo
->InterfaceNumber
].InterfaceDescriptor
.bInterfaceNumber
;
1234 CtrlSetup
.bmRequestType
.B
= 0x01;
1239 Status
= CommitSetupPacket(&CtrlSetup
, 0, 0, 0);
1242 // informal debug print
1244 DPRINT1("CUSBDevice::SelectInterface AlternateSetting %x InterfaceNumber %x Status %x\n", InterfaceInfo
->AlternateSetting
, InterfaceInfo
->InterfaceNumber
, Status
);
1252 //----------------------------------------------------------------------------------------
1255 PUSBDEVICE
*OutDevice
)
1260 // allocate controller
1262 This
= new(NonPagedPool
, TAG_USBEHCI
) CUSBDevice(0);
1266 // failed to allocate
1268 return STATUS_INSUFFICIENT_RESOURCES
;
1272 // add reference count
1279 *OutDevice
= (PUSBDEVICE
)This
;
1284 return STATUS_SUCCESS
;