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 class CUSBDevice
: public IUSBDevice
17 STDMETHODIMP
QueryInterface( REFIID InterfaceId
, PVOID
* Interface
);
19 STDMETHODIMP_(ULONG
) AddRef()
21 InterlockedIncrement(&m_Ref
);
24 STDMETHODIMP_(ULONG
) Release()
26 InterlockedDecrement(&m_Ref
);
36 // IUSBDevice interface functions
37 virtual NTSTATUS
Initialize(IN PHUBCONTROLLER HubController
, IN PUSBHARDWAREDEVICE Device
, IN PVOID Parent
, IN ULONG Port
, IN ULONG PortStatus
);
38 virtual BOOLEAN
IsHub();
39 virtual NTSTATUS
GetParent(PVOID
* Parent
);
40 virtual UCHAR
GetDeviceAddress();
41 virtual ULONG
GetPort();
42 virtual USB_DEVICE_SPEED
GetSpeed();
43 virtual USB_DEVICE_TYPE
GetType();
44 virtual ULONG
GetState();
45 virtual void SetDeviceHandleData(PVOID Data
);
46 virtual NTSTATUS
SetDeviceAddress(UCHAR DeviceAddress
);
47 virtual void GetDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor
);
48 virtual UCHAR
GetConfigurationValue();
49 virtual NTSTATUS
SubmitIrp(PIRP Irp
);
50 virtual VOID
GetConfigurationDescriptors(IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptorBuffer
, IN ULONG BufferLength
, OUT PULONG OutBufferLength
);
51 virtual ULONG
GetConfigurationDescriptorsLength();
52 virtual NTSTATUS
SubmitSetupPacket(IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket
, OUT ULONG BufferLength
, OUT PVOID Buffer
);
53 virtual NTSTATUS
SelectConfiguration(IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
, IN PUSBD_INTERFACE_INFORMATION Interface
, OUT USBD_CONFIGURATION_HANDLE
*ConfigurationHandle
);
54 virtual NTSTATUS
SelectInterface(IN USBD_CONFIGURATION_HANDLE ConfigurationHandle
, IN OUT PUSBD_INTERFACE_INFORMATION Interface
);
55 virtual NTSTATUS
AbortPipe(IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor
);
59 virtual NTSTATUS
CommitIrp(PIRP Irp
);
60 virtual NTSTATUS
CommitSetupPacket(PUSB_DEFAULT_PIPE_SETUP_PACKET Packet
, IN OPTIONAL PUSB_ENDPOINT EndpointDescriptor
, IN ULONG BufferLength
, IN OUT PMDL Mdl
);
61 virtual NTSTATUS
CreateConfigurationDescriptor(UCHAR ConfigurationIndex
);
62 virtual NTSTATUS
CreateDeviceDescriptor();
63 virtual VOID
DumpDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor
);
64 virtual VOID
DumpConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
);
66 // constructor / destructor
67 CUSBDevice(IUnknown
*OuterUnknown
){}
68 virtual ~CUSBDevice(){}
72 PHUBCONTROLLER m_HubController
;
73 PUSBHARDWAREDEVICE m_Device
;
76 UCHAR m_DeviceAddress
;
78 UCHAR m_ConfigurationIndex
;
80 USB_DEVICE_DESCRIPTOR m_DeviceDescriptor
;
83 PDMAMEMORYMANAGER m_DmaManager
;
85 PUSB_CONFIGURATION m_ConfigurationDescriptors
;
88 //----------------------------------------------------------------------------------------
91 CUSBDevice::QueryInterface(
95 return STATUS_UNSUCCESSFUL
;
98 //----------------------------------------------------------------------------------------
100 CUSBDevice::Initialize(
101 IN PHUBCONTROLLER HubController
,
102 IN PUSBHARDWAREDEVICE Device
,
110 // initialize members
112 m_HubController
= HubController
;
116 m_PortStatus
= PortStatus
;
119 // initialize device lock
121 KeInitializeSpinLock(&m_Lock
);
124 // no device address has been set yet
129 // get usb request queue
131 Status
= m_Device
->GetUSBQueue(&m_Queue
);
132 if (!NT_SUCCESS(Status
))
135 // failed to get usb queue
137 DPRINT1("CUSBDevice::Initialize GetUsbQueue failed with %x\n", Status
);
144 Status
= m_Device
->GetDMA(&m_DmaManager
);
145 if (!NT_SUCCESS(Status
))
148 // failed to get dma manager
150 DPRINT1("CUSBDevice::Initialize GetDMA failed with %x\n", Status
);
157 PC_ASSERT(m_DmaManager
);
160 // get device descriptor
162 Status
= CreateDeviceDescriptor();
163 if (!NT_SUCCESS(Status
))
166 // failed to get device descriptor
168 DPRINT1("CUSBDevice::Initialize Failed to get device descriptor with %x\n", Status
);
178 //----------------------------------------------------------------------------------------
183 // USB Standard Device Class see http://www.usb.org/developers/defined_class/#BaseClass09h
186 return (m_DeviceDescriptor
.bDeviceClass
== 0x09 && m_DeviceDescriptor
.bDeviceSubClass
== 0x00);
189 //----------------------------------------------------------------------------------------
191 CUSBDevice::GetParent(
202 return STATUS_SUCCESS
;
205 //----------------------------------------------------------------------------------------
207 CUSBDevice::GetDeviceAddress()
210 // get device address
212 return m_DeviceAddress
;
215 //----------------------------------------------------------------------------------------
217 CUSBDevice::GetPort()
220 // get port to which this device is connected to
225 //----------------------------------------------------------------------------------------
227 CUSBDevice::GetSpeed()
229 if (m_PortStatus
& USB_PORT_STATUS_LOW_SPEED
)
236 else if (m_PortStatus
& USB_PORT_STATUS_HIGH_SPEED
)
245 // default to full speed
250 //----------------------------------------------------------------------------------------
252 CUSBDevice::GetType()
255 // device is encoded into bcdUSB
257 if (m_DeviceDescriptor
.bcdUSB
== 0x110)
264 else if (m_DeviceDescriptor
.bcdUSB
== 0x200)
272 DPRINT1("CUSBDevice::GetType Unknown bcdUSB Type %x\n", m_DeviceDescriptor
.bcdUSB
);
278 //----------------------------------------------------------------------------------------
280 CUSBDevice::GetState()
286 //----------------------------------------------------------------------------------------
288 CUSBDevice::SetDeviceHandleData(
292 // set device data, for debugging issues
297 //----------------------------------------------------------------------------------------
299 CUSBDevice::SetDeviceAddress(
302 PUSB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup
;
307 DPRINT1("CUSBDevice::SetDeviceAddress Address %d\n", DeviceAddress
);
309 CtrlSetup
= (PUSB_DEFAULT_PIPE_SETUP_PACKET
)ExAllocatePoolWithTag(NonPagedPool
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
), TAG_USBEHCI
);
311 return STATUS_INSUFFICIENT_RESOURCES
;
316 RtlZeroMemory(CtrlSetup
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
319 // initialize request
321 CtrlSetup
->bRequest
= USB_REQUEST_SET_ADDRESS
;
322 CtrlSetup
->wValue
.W
= (USHORT
)DeviceAddress
;
325 // set device address
327 Status
= CommitSetupPacket(CtrlSetup
, 0, 0, 0);
332 ExFreePoolWithTag(CtrlSetup
, TAG_USBEHCI
);
337 if (!NT_SUCCESS(Status
))
340 // failed to set device address
342 DPRINT1("CUSBDevice::SetDeviceAddress> failed to set device address with %x Address %x\n", Status
, DeviceAddress
);
347 // lets have a short nap
349 KeStallExecutionProcessor(300);
352 // back up old address
354 OldAddress
= m_DeviceAddress
;
357 // store new device address
359 m_DeviceAddress
= DeviceAddress
;
362 // check that setting device address succeeded by retrieving the device descriptor
364 Status
= CreateDeviceDescriptor();
365 if (!NT_SUCCESS(Status
))
368 // failed to retrieve device descriptor
370 DPRINT1("CUSBbDevice::SetDeviceAddress> failed to retrieve device descriptor with device address set Error %x\n", Status
);
371 m_DeviceAddress
= OldAddress
;
374 // return error status
382 PC_ASSERT(m_DeviceDescriptor
.bNumConfigurations
);
385 // allocate configuration descriptor
387 m_ConfigurationDescriptors
= (PUSB_CONFIGURATION
) ExAllocatePoolWithTag(NonPagedPool
, sizeof(USB_CONFIGURATION
) * m_DeviceDescriptor
.bNumConfigurations
, TAG_USBEHCI
);
390 // zero configuration descriptor
392 RtlZeroMemory(m_ConfigurationDescriptors
, sizeof(USB_CONFIGURATION
) * m_DeviceDescriptor
.bNumConfigurations
);
395 // retrieve the configuration descriptors
397 for(Index
= 0; Index
< m_DeviceDescriptor
.bNumConfigurations
; Index
++)
400 // retrieve configuration descriptors from device
402 Status
= CreateConfigurationDescriptor(Index
);
403 if (!NT_SUCCESS(Status
))
405 DPRINT1("CUSBDevice::SetDeviceAddress> failed to retrieve configuration %lu\n", Index
);
417 //----------------------------------------------------------------------------------------
419 CUSBDevice::GetDeviceDescriptor(
420 PUSB_DEVICE_DESCRIPTOR DeviceDescriptor
)
422 RtlMoveMemory(DeviceDescriptor
, &m_DeviceDescriptor
, sizeof(USB_DEVICE_DESCRIPTOR
));
425 //----------------------------------------------------------------------------------------
427 CUSBDevice::GetConfigurationValue()
430 // return configuration index
432 return m_ConfigurationIndex
;
435 //----------------------------------------------------------------------------------------
437 CUSBDevice::CommitIrp(
443 if (!m_Queue
|| !m_DmaManager
)
448 DPRINT1("CUSBDevice::CommitUrb> no queue / dma !!!\n");
449 return STATUS_UNSUCCESSFUL
;
455 Status
= m_Queue
->CreateUSBRequest(&Request
);
456 if (!NT_SUCCESS(Status
))
459 // failed to build request
461 DPRINT1("CUSBDevice::CommitSetupPacket> CreateUSBRequest failed with %x\n", Status
);
466 // initialize request
468 Status
= Request
->InitializeWithIrp(m_DmaManager
, Irp
);
471 // mark irp as pending
473 IoMarkIrpPending(Irp
);
476 // now add the request
478 Status
= m_Queue
->AddUSBRequest(Request
);
479 if (!NT_SUCCESS(Status
))
482 // failed to add request
484 DPRINT1("CUSBDevice::CommitSetupPacket> failed add request to queue with %x\n", Status
);
492 return STATUS_PENDING
;
495 //----------------------------------------------------------------------------------------
497 CUSBDevice::SubmitIrp(
504 // acquire device lock
506 KeAcquireSpinLock(&m_Lock
, &OldLevel
);
511 Status
= CommitIrp(Irp
);
516 KeReleaseSpinLock(&m_Lock
, OldLevel
);
520 //----------------------------------------------------------------------------------------
522 CUSBDevice::CommitSetupPacket(
523 IN PUSB_DEFAULT_PIPE_SETUP_PACKET Packet
,
524 IN OPTIONAL PUSB_ENDPOINT EndpointDescriptor
,
525 IN ULONG BufferLength
,
536 DPRINT1("CUSBDevice::CommitSetupPacket> no queue!!!\n");
537 return STATUS_UNSUCCESSFUL
;
543 Status
= m_Queue
->CreateUSBRequest(&Request
);
544 if (!NT_SUCCESS(Status
))
547 // failed to build request
549 DPRINT1("CUSBDevice::CommitSetupPacket> CreateUSBRequest failed with %x\n", Status
);
554 // initialize request
556 Status
= Request
->InitializeWithSetupPacket(m_DmaManager
, Packet
, m_DeviceAddress
, EndpointDescriptor
, BufferLength
, Mdl
);
557 if (!NT_SUCCESS(Status
))
560 // failed to initialize request
562 DPRINT1("CUSBDevice::CommitSetupPacket> failed to initialize usb request with %x\n", Status
);
568 // now add the request
570 Status
= m_Queue
->AddUSBRequest(Request
);
571 if (!NT_SUCCESS(Status
))
574 // failed to add request
576 DPRINT1("CUSBDevice::CommitSetupPacket> failed add request to queue with %x\n", Status
);
582 // get the result code when the operation has been finished
584 Request
->GetResultStatus(&Status
, NULL
);
597 //----------------------------------------------------------------------------------------
599 CUSBDevice::CreateDeviceDescriptor()
601 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup
;
609 RtlZeroMemory(&m_DeviceDescriptor
, sizeof(USB_DEVICE_DESCRIPTOR
));
610 RtlZeroMemory(&CtrlSetup
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
615 CtrlSetup
.bRequest
= USB_REQUEST_GET_DESCRIPTOR
;
616 CtrlSetup
.wValue
.HiByte
= USB_DEVICE_DESCRIPTOR_TYPE
;
617 CtrlSetup
.wLength
= sizeof(USB_DEVICE_DESCRIPTOR
);
618 CtrlSetup
.bmRequestType
.B
= 0x80;
623 Buffer
= ExAllocatePool(NonPagedPool
, PAGE_SIZE
);
627 // failed to allocate
629 return STATUS_INSUFFICIENT_RESOURCES
;
635 RtlZeroMemory(Buffer
, PAGE_SIZE
);
638 // allocate mdl describing the device descriptor
640 Mdl
= IoAllocateMdl(Buffer
, sizeof(USB_DEVICE_DESCRIPTOR
), FALSE
, FALSE
, 0);
644 // failed to allocate mdl
646 return STATUS_INSUFFICIENT_RESOURCES
;
650 // build mdl for non paged pool
652 MmBuildMdlForNonPagedPool(Mdl
);
655 // commit setup packet
657 Status
= CommitSetupPacket(&CtrlSetup
, 0, sizeof(USB_DEVICE_DESCRIPTOR
), Mdl
);
664 if (NT_SUCCESS(Status
))
667 // informal dbg print
669 RtlCopyMemory(&m_DeviceDescriptor
, Buffer
, sizeof(USB_DEVICE_DESCRIPTOR
));
670 DumpDeviceDescriptor(&m_DeviceDescriptor
);
685 //----------------------------------------------------------------------------------------
687 CUSBDevice::CreateConfigurationDescriptor(
691 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup
;
694 ULONG InterfaceIndex
, EndPointIndex
;
695 PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
;
696 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor
;
697 PUSB_ENDPOINT_DESCRIPTOR EndPointDescriptor
;
703 PC_ASSERT(m_ConfigurationDescriptors
);
706 // first allocate a buffer which should be enough to store all different interfaces and endpoints
708 Buffer
= ExAllocatePoolWithTag(NonPagedPool
, PAGE_SIZE
, TAG_USBEHCI
);
712 // failed to allocate buffer
714 return STATUS_INSUFFICIENT_RESOURCES
;
718 // build setup packet
720 CtrlSetup
.bmRequestType
._BM
.Recipient
= BMREQUEST_TO_DEVICE
;
721 CtrlSetup
.bmRequestType
._BM
.Type
= BMREQUEST_STANDARD
;
722 CtrlSetup
.bmRequestType
._BM
.Reserved
= 0;
723 CtrlSetup
.bmRequestType
._BM
.Dir
= BMREQUEST_DEVICE_TO_HOST
;
724 CtrlSetup
.bRequest
= USB_REQUEST_GET_DESCRIPTOR
;
725 CtrlSetup
.wValue
.LowByte
= Index
;
726 CtrlSetup
.wValue
.HiByte
= USB_CONFIGURATION_DESCRIPTOR_TYPE
;
727 CtrlSetup
.wIndex
.W
= 0;
728 CtrlSetup
.wLength
= PAGE_SIZE
;
731 // now build MDL describing the buffer
733 Mdl
= IoAllocateMdl(Buffer
, PAGE_SIZE
, FALSE
, FALSE
, 0);
737 // failed to allocate mdl
739 ExFreePoolWithTag(Buffer
, TAG_USBEHCI
);
740 return STATUS_INSUFFICIENT_RESOURCES
;
744 // build mdl for non paged pool
746 MmBuildMdlForNonPagedPool(Mdl
);
751 Status
= CommitSetupPacket(&CtrlSetup
, 0, PAGE_SIZE
, Mdl
);
752 if (!NT_SUCCESS(Status
))
755 // failed to issue request, cleanup
768 // get configuration descriptor
770 ConfigurationDescriptor
= (PUSB_CONFIGURATION_DESCRIPTOR
)Buffer
;
773 // informal debug print
775 DumpConfigurationDescriptor(ConfigurationDescriptor
);
780 PC_ASSERT(ConfigurationDescriptor
->bLength
== sizeof(USB_CONFIGURATION_DESCRIPTOR
));
781 PC_ASSERT(ConfigurationDescriptor
->wTotalLength
<= PAGE_SIZE
);
782 PC_ASSERT(ConfigurationDescriptor
->bNumInterfaces
);
785 // request is complete, initialize configuration descriptor
787 RtlCopyMemory(&m_ConfigurationDescriptors
[Index
].ConfigurationDescriptor
, ConfigurationDescriptor
, ConfigurationDescriptor
->bLength
);
790 // now allocate interface descriptors
792 m_ConfigurationDescriptors
[Index
].Interfaces
= (PUSB_INTERFACE
)ExAllocatePoolWithTag(NonPagedPool
, sizeof(USB_INTERFACE
) * ConfigurationDescriptor
->bNumInterfaces
, TAG_USBEHCI
);
793 if (!m_ConfigurationDescriptors
[Index
].Interfaces
)
796 // failed to allocate interface descriptors
799 return STATUS_INSUFFICIENT_RESOURCES
;
803 // zero interface descriptor
805 RtlZeroMemory(m_ConfigurationDescriptors
[Index
].Interfaces
, sizeof(USB_INTERFACE
) * ConfigurationDescriptor
->bNumInterfaces
);
808 // get first interface descriptor
810 InterfaceDescriptor
= (PUSB_INTERFACE_DESCRIPTOR
)(ConfigurationDescriptor
+ 1);
813 // setup interface descriptors
815 for(InterfaceIndex
= 0; InterfaceIndex
< ConfigurationDescriptor
->bNumInterfaces
; InterfaceIndex
++)
820 PC_ASSERT(InterfaceDescriptor
->bLength
== sizeof(USB_INTERFACE_DESCRIPTOR
));
821 PC_ASSERT(InterfaceDescriptor
->bNumEndpoints
);
824 // copy current interface descriptor
826 RtlCopyMemory(&m_ConfigurationDescriptors
[Index
].Interfaces
[InterfaceIndex
].InterfaceDescriptor
, InterfaceDescriptor
, InterfaceDescriptor
->bLength
);
829 // allocate end point descriptors
831 m_ConfigurationDescriptors
[Index
].Interfaces
[InterfaceIndex
].EndPoints
= (PUSB_ENDPOINT
)ExAllocatePoolWithTag(NonPagedPool
, sizeof(USB_ENDPOINT
) * InterfaceDescriptor
->bNumEndpoints
, TAG_USBEHCI
);
832 if (!m_ConfigurationDescriptors
[Index
].Interfaces
[InterfaceIndex
].EndPoints
)
835 // failed to allocate endpoint
837 Status
= STATUS_INSUFFICIENT_RESOURCES
;
844 RtlZeroMemory(m_ConfigurationDescriptors
[Index
].Interfaces
[InterfaceIndex
].EndPoints
, sizeof(USB_ENDPOINT
) * InterfaceDescriptor
->bNumEndpoints
);
847 // initialize end point descriptors
849 EndPointDescriptor
= (PUSB_ENDPOINT_DESCRIPTOR
)(InterfaceDescriptor
+ 1);
851 for(EndPointIndex
= 0; EndPointIndex
< InterfaceDescriptor
->bNumEndpoints
; EndPointIndex
++)
856 PC_ASSERT(EndPointDescriptor
->bLength
== sizeof(USB_ENDPOINT_DESCRIPTOR
));
859 // copy endpoint descriptor
861 RtlCopyMemory(&m_ConfigurationDescriptors
[Index
].Interfaces
[InterfaceIndex
].EndPoints
[EndPointIndex
].EndPointDescriptor
, EndPointDescriptor
, EndPointDescriptor
->bLength
);
864 // move to next offset
866 EndPointDescriptor
= (PUSB_ENDPOINT_DESCRIPTOR
)((ULONG_PTR
)EndPointDescriptor
+ EndPointDescriptor
->bLength
);
870 // update interface descriptor offset
872 InterfaceDescriptor
= (PUSB_INTERFACE_DESCRIPTOR
)EndPointDescriptor
;
878 ExFreePoolWithTag(Buffer
, TAG_USBEHCI
);
885 //----------------------------------------------------------------------------------------
887 CUSBDevice::GetConfigurationDescriptors(
888 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptorBuffer
,
889 IN ULONG BufferLength
,
890 OUT PULONG OutBufferLength
)
893 ULONG InterfaceIndex
, EndpointIndex
;
898 PC_ASSERT(BufferLength
>= sizeof(USB_CONFIGURATION_DESCRIPTOR
));
899 PC_ASSERT(ConfigDescriptorBuffer
);
900 PC_ASSERT(OutBufferLength
);
903 // reset copied length
905 *OutBufferLength
= 0;
908 // FIXME: support multiple configurations
910 PC_ASSERT(m_DeviceDescriptor
.bNumConfigurations
== 1);
913 // copy first configuration descriptor
915 RtlCopyMemory(ConfigDescriptorBuffer
, &m_ConfigurationDescriptors
[0].ConfigurationDescriptor
, sizeof(USB_CONFIGURATION_DESCRIPTOR
));
920 BufferLength
-= sizeof(USB_CONFIGURATION_DESCRIPTOR
);
921 *OutBufferLength
+= sizeof(USB_CONFIGURATION_DESCRIPTOR
);
926 Buffer
= (PVOID
)(ConfigDescriptorBuffer
+ 1);
928 for(InterfaceIndex
= 0; InterfaceIndex
< m_ConfigurationDescriptors
[0].ConfigurationDescriptor
.bNumInterfaces
; InterfaceIndex
++)
930 if (BufferLength
< sizeof(USB_INTERFACE_DESCRIPTOR
))
933 // no more room in buffer
939 // copy interface descriptor
941 RtlCopyMemory(Buffer
, &m_ConfigurationDescriptors
[0].Interfaces
[InterfaceIndex
].InterfaceDescriptor
, sizeof(USB_INTERFACE_DESCRIPTOR
));
946 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ sizeof(USB_INTERFACE_DESCRIPTOR
));
947 BufferLength
-= sizeof(USB_INTERFACE_DESCRIPTOR
);
948 *OutBufferLength
+= sizeof(USB_INTERFACE_DESCRIPTOR
);
951 // does the interface have endpoints
953 if (m_ConfigurationDescriptors
[0].Interfaces
[InterfaceIndex
].InterfaceDescriptor
.bNumEndpoints
)
956 // is enough space available
958 if (BufferLength
< sizeof(USB_ENDPOINT_DESCRIPTOR
) * m_ConfigurationDescriptors
[0].Interfaces
[InterfaceIndex
].InterfaceDescriptor
.bNumEndpoints
)
969 for(EndpointIndex
= 0; EndpointIndex
< m_ConfigurationDescriptors
[0].Interfaces
[InterfaceIndex
].InterfaceDescriptor
.bNumEndpoints
; EndpointIndex
++)
974 RtlCopyMemory(Buffer
, &m_ConfigurationDescriptors
[0].Interfaces
[InterfaceIndex
].EndPoints
[EndpointIndex
].EndPointDescriptor
, sizeof(USB_ENDPOINT_DESCRIPTOR
));
977 // increment buffer offset
979 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ sizeof(USB_ENDPOINT_DESCRIPTOR
));
980 BufferLength
-= sizeof(USB_ENDPOINT_DESCRIPTOR
);
981 *OutBufferLength
+= sizeof(USB_ENDPOINT_DESCRIPTOR
);
987 //----------------------------------------------------------------------------------------
989 CUSBDevice::GetConfigurationDescriptorsLength()
992 // FIXME: support multiple configurations
994 PC_ASSERT(m_DeviceDescriptor
.bNumConfigurations
== 1);
996 return m_ConfigurationDescriptors
[0].ConfigurationDescriptor
.wTotalLength
;
998 //----------------------------------------------------------------------------------------
1000 CUSBDevice::DumpDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor
)
1002 DPRINT1("Dumping Device Descriptor %x\n", DeviceDescriptor
);
1003 DPRINT1("bLength %x\n", DeviceDescriptor
->bLength
);
1004 DPRINT1("bDescriptorType %x\n", DeviceDescriptor
->bDescriptorType
);
1005 DPRINT1("bcdUSB %x\n", DeviceDescriptor
->bcdUSB
);
1006 DPRINT1("bDeviceClass %x\n", DeviceDescriptor
->bDeviceClass
);
1007 DPRINT1("bDeviceSubClass %x\n", DeviceDescriptor
->bDeviceSubClass
);
1008 DPRINT1("bDeviceProtocol %x\n", DeviceDescriptor
->bDeviceProtocol
);
1009 DPRINT1("bMaxPacketSize0 %x\n", DeviceDescriptor
->bMaxPacketSize0
);
1010 DPRINT1("idVendor %x\n", DeviceDescriptor
->idVendor
);
1011 DPRINT1("idProduct %x\n", DeviceDescriptor
->idProduct
);
1012 DPRINT1("bcdDevice %x\n", DeviceDescriptor
->bcdDevice
);
1013 DPRINT1("iManufacturer %x\n", DeviceDescriptor
->iManufacturer
);
1014 DPRINT1("iProduct %x\n", DeviceDescriptor
->iProduct
);
1015 DPRINT1("iSerialNumber %x\n", DeviceDescriptor
->iSerialNumber
);
1016 DPRINT1("bNumConfigurations %x\n", DeviceDescriptor
->bNumConfigurations
);
1019 //----------------------------------------------------------------------------------------
1021 CUSBDevice::DumpConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
)
1023 DPRINT1("Dumping ConfigurationDescriptor %x\n", ConfigurationDescriptor
);
1024 DPRINT1("bLength %x\n", ConfigurationDescriptor
->bLength
);
1025 DPRINT1("bDescriptorType %x\n", ConfigurationDescriptor
->bDescriptorType
);
1026 DPRINT1("wTotalLength %x\n", ConfigurationDescriptor
->wTotalLength
);
1027 DPRINT1("bNumInterfaces %x\n", ConfigurationDescriptor
->bNumInterfaces
);
1028 DPRINT1("bConfigurationValue %x\n", ConfigurationDescriptor
->bConfigurationValue
);
1029 DPRINT1("iConfiguration %x\n", ConfigurationDescriptor
->iConfiguration
);
1030 DPRINT1("bmAttributes %x\n", ConfigurationDescriptor
->bmAttributes
);
1031 DPRINT1("MaxPower %x\n", ConfigurationDescriptor
->MaxPower
);
1033 //----------------------------------------------------------------------------------------
1035 CUSBDevice::SubmitSetupPacket(
1036 IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket
,
1037 IN OUT ULONG BufferLength
,
1048 Mdl
= IoAllocateMdl(Buffer
, BufferLength
, FALSE
, FALSE
, 0);
1054 return STATUS_INSUFFICIENT_RESOURCES
;
1058 // HACK HACK HACK: assume the buffer is build from non paged pool
1060 MmBuildMdlForNonPagedPool(Mdl
);
1064 // commit setup packet
1066 Status
= CommitSetupPacket(SetupPacket
, 0, BufferLength
, Mdl
);
1082 //----------------------------------------------------------------------------------------
1084 CUSBDevice::SelectConfiguration(
1085 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
,
1086 IN PUSBD_INTERFACE_INFORMATION InterfaceInfo
,
1087 OUT USBD_CONFIGURATION_HANDLE
*ConfigurationHandle
)
1089 ULONG InterfaceIndex
, PipeIndex
;
1090 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup
;
1096 ASSERT(ConfigurationDescriptor
->iConfiguration
< m_DeviceDescriptor
.bNumConfigurations
);
1097 ASSERT(ConfigurationDescriptor
->iConfiguration
== m_ConfigurationDescriptors
[ConfigurationDescriptor
->iConfiguration
].ConfigurationDescriptor
.iConfiguration
);
1102 ASSERT(ConfigurationDescriptor
->bNumInterfaces
<= m_ConfigurationDescriptors
[ConfigurationDescriptor
->iConfiguration
].ConfigurationDescriptor
.bNumInterfaces
);
1105 // now build setup packet
1107 RtlZeroMemory(&CtrlSetup
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
1108 CtrlSetup
.bRequest
= USB_REQUEST_SET_CONFIGURATION
;
1109 CtrlSetup
.wValue
.W
= ConfigurationDescriptor
->bConfigurationValue
;
1112 // select configuration
1114 Status
= CommitSetupPacket(&CtrlSetup
, 0, 0, 0);
1117 // informal debug print
1119 DPRINT1("CUsbDevice::SelectConfiguration New Configuration %x Old Configuration %x Result %x\n", ConfigurationDescriptor
->iConfiguration
, m_ConfigurationIndex
, Status
);
1120 if (!NT_SUCCESS(Status
))
1129 // store configuration device index
1131 m_ConfigurationIndex
= ConfigurationDescriptor
->iConfiguration
;
1134 // store configuration handle
1136 *ConfigurationHandle
= &m_ConfigurationDescriptors
[ConfigurationDescriptor
->iConfiguration
];
1139 // copy interface info and pipe info
1141 for(InterfaceIndex
= 0; InterfaceIndex
< ConfigurationDescriptor
->bNumInterfaces
; InterfaceIndex
++)
1144 // sanity check: is the info pre-layed out
1146 PC_ASSERT(InterfaceInfo
->NumberOfPipes
== m_ConfigurationDescriptors
[ConfigurationDescriptor
->iConfiguration
].Interfaces
[InterfaceIndex
].InterfaceDescriptor
.bNumEndpoints
);
1147 PC_ASSERT(InterfaceInfo
->Length
!= 0);
1149 PC_ASSERT(InterfaceInfo
->Length
== FIELD_OFFSET(USBD_INTERFACE_INFORMATION
, Pipes
[InterfaceInfo
->NumberOfPipes
]));
1153 // copy interface info
1155 InterfaceInfo
->InterfaceHandle
= (USBD_INTERFACE_HANDLE
)&m_ConfigurationDescriptors
[ConfigurationDescriptor
->iConfiguration
].Interfaces
[InterfaceIndex
];
1156 InterfaceInfo
->Class
= m_ConfigurationDescriptors
[ConfigurationDescriptor
->iConfiguration
].Interfaces
[InterfaceIndex
].InterfaceDescriptor
.bInterfaceClass
;
1157 InterfaceInfo
->SubClass
= m_ConfigurationDescriptors
[ConfigurationDescriptor
->iConfiguration
].Interfaces
[InterfaceIndex
].InterfaceDescriptor
.bInterfaceSubClass
;
1158 InterfaceInfo
->Protocol
= m_ConfigurationDescriptors
[ConfigurationDescriptor
->iConfiguration
].Interfaces
[InterfaceIndex
].InterfaceDescriptor
.bInterfaceProtocol
;
1159 InterfaceInfo
->Reserved
= 0;
1162 // copy endpoint info
1164 for(PipeIndex
= 0; PipeIndex
< InterfaceInfo
->NumberOfPipes
; PipeIndex
++)
1169 InterfaceInfo
->Pipes
[PipeIndex
].MaximumPacketSize
= m_ConfigurationDescriptors
[ConfigurationDescriptor
->iConfiguration
].Interfaces
[InterfaceIndex
].EndPoints
[PipeIndex
].EndPointDescriptor
.wMaxPacketSize
;
1170 InterfaceInfo
->Pipes
[PipeIndex
].EndpointAddress
= m_ConfigurationDescriptors
[ConfigurationDescriptor
->iConfiguration
].Interfaces
[InterfaceIndex
].EndPoints
[PipeIndex
].EndPointDescriptor
.bEndpointAddress
;
1171 InterfaceInfo
->Pipes
[PipeIndex
].Interval
= m_ConfigurationDescriptors
[ConfigurationDescriptor
->iConfiguration
].Interfaces
[InterfaceIndex
].EndPoints
[PipeIndex
].EndPointDescriptor
.bInterval
;
1172 InterfaceInfo
->Pipes
[PipeIndex
].PipeType
= (USBD_PIPE_TYPE
)m_ConfigurationDescriptors
[ConfigurationDescriptor
->iConfiguration
].Interfaces
[InterfaceIndex
].EndPoints
[PipeIndex
].EndPointDescriptor
.bmAttributes
;
1173 InterfaceInfo
->Pipes
[PipeIndex
].PipeHandle
= (PVOID
)&m_ConfigurationDescriptors
[ConfigurationDescriptor
->iConfiguration
].Interfaces
[InterfaceIndex
].EndPoints
[PipeIndex
].EndPointDescriptor
;
1176 // data toggle is reset on configuration requests
1178 m_ConfigurationDescriptors
[ConfigurationDescriptor
->iConfiguration
].Interfaces
[InterfaceIndex
].EndPoints
[PipeIndex
].DataToggle
= FALSE
;
1184 InterfaceInfo
= (PUSBD_INTERFACE_INFORMATION
)((ULONG_PTR
)PtrToUlong(InterfaceInfo
) + InterfaceInfo
->Length
);
1193 //----------------------------------------------------------------------------------------
1195 CUSBDevice::SelectInterface(
1196 IN USBD_CONFIGURATION_HANDLE ConfigurationHandle
,
1197 IN OUT PUSBD_INTERFACE_INFORMATION InterfaceInfo
)
1199 PUSB_CONFIGURATION Configuration
;
1201 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup
;
1205 // get configuration struct
1207 Configuration
= (PUSB_CONFIGURATION
)ConfigurationHandle
;
1212 ASSERT(Configuration
->ConfigurationDescriptor
.bDescriptorType
== USB_CONFIGURATION_DESCRIPTOR_TYPE
);
1213 ASSERT(Configuration
->ConfigurationDescriptor
.bLength
== sizeof(USB_CONFIGURATION_DESCRIPTOR
));
1214 ASSERT(Configuration
->ConfigurationDescriptor
.iConfiguration
< m_DeviceDescriptor
.bNumConfigurations
);
1215 ASSERT(&m_ConfigurationDescriptors
[Configuration
->ConfigurationDescriptor
.iConfiguration
] == Configuration
);
1218 // initialize setup packet
1220 RtlZeroMemory(&CtrlSetup
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
1221 CtrlSetup
.bRequest
= USB_REQUEST_SET_INTERFACE
;
1222 CtrlSetup
.wValue
.W
= Configuration
->Interfaces
[InterfaceInfo
->InterfaceNumber
].InterfaceDescriptor
.bAlternateSetting
;
1223 CtrlSetup
.wIndex
.W
= Configuration
->Interfaces
[InterfaceInfo
->InterfaceNumber
].InterfaceDescriptor
.bInterfaceNumber
;
1224 CtrlSetup
.bmRequestType
.B
= 0x01;
1229 Status
= CommitSetupPacket(&CtrlSetup
, 0, 0, 0);
1232 // informal debug print
1234 DPRINT1("CUSBDevice::SelectInterface AlternateSetting %x InterfaceNumber %x Status %x\n", InterfaceInfo
->AlternateSetting
, InterfaceInfo
->InterfaceNumber
, Status
);
1235 if (!NT_SUCCESS(Status
))
1238 // failed to select interface
1247 PC_ASSERT(Configuration
->ConfigurationDescriptor
.bNumInterfaces
> InterfaceInfo
->InterfaceNumber
);
1248 PC_ASSERT(Configuration
->Interfaces
[InterfaceInfo
->InterfaceNumber
].InterfaceDescriptor
.bNumEndpoints
== InterfaceInfo
->NumberOfPipes
);
1250 PC_ASSERT(InterfaceInfo
->Length
== FIELD_OFFSET(USBD_INTERFACE_INFORMATION
, Pipes
[InterfaceInfo
->NumberOfPipes
]));
1254 // copy pipe handles
1256 for(PipeIndex
= 0; PipeIndex
< InterfaceInfo
->NumberOfPipes
; PipeIndex
++)
1261 DPRINT1("PipeIndex %lu\n", PipeIndex
);
1262 DPRINT1("EndpointAddress %x\n", InterfaceInfo
->Pipes
[PipeIndex
].EndpointAddress
);
1263 DPRINT1("Interval %d\n", InterfaceInfo
->Pipes
[PipeIndex
].Interval
);
1264 DPRINT1("MaximumPacketSize %d\n", InterfaceInfo
->Pipes
[PipeIndex
].MaximumPacketSize
);
1265 DPRINT1("MaximumTransferSize %d\n", InterfaceInfo
->Pipes
[PipeIndex
].MaximumTransferSize
);
1266 DPRINT1("PipeFlags %d\n", InterfaceInfo
->Pipes
[PipeIndex
].PipeFlags
);
1267 DPRINT1("PipeType %dd\n", InterfaceInfo
->Pipes
[PipeIndex
].PipeType
);
1268 DPRINT1("UsbEndPoint %x\n", Configuration
->Interfaces
[InterfaceInfo
->InterfaceNumber
].EndPoints
[PipeIndex
].EndPointDescriptor
.bEndpointAddress
);
1269 PC_ASSERT(Configuration
->Interfaces
[InterfaceInfo
->InterfaceNumber
].EndPoints
[PipeIndex
].EndPointDescriptor
.bEndpointAddress
== InterfaceInfo
->Pipes
[PipeIndex
].EndpointAddress
);
1271 InterfaceInfo
->Pipes
[PipeIndex
].PipeHandle
= &Configuration
->Interfaces
[InterfaceInfo
->InterfaceNumber
].EndPoints
[PipeIndex
].EndPointDescriptor
;
1274 // data toggle is reset on select interface requests
1276 m_ConfigurationDescriptors
[Configuration
->ConfigurationDescriptor
.iConfiguration
].Interfaces
[InterfaceInfo
->InterfaceNumber
].EndPoints
[PipeIndex
].DataToggle
= FALSE
;
1278 if (Configuration
->Interfaces
[InterfaceInfo
->InterfaceNumber
].EndPoints
[PipeIndex
].EndPointDescriptor
.bmAttributes
& (USB_ENDPOINT_TYPE_ISOCHRONOUS
| USB_ENDPOINT_TYPE_INTERRUPT
))
1281 // FIXME: check if enough bandwidth is available
1294 CUSBDevice::AbortPipe(
1295 IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor
)
1298 // let it handle usb queue
1301 ASSERT(m_DeviceAddress
);
1306 return m_Queue
->AbortDevicePipe(m_DeviceAddress
, EndpointDescriptor
);
1310 //----------------------------------------------------------------------------------------
1313 PUSBDEVICE
*OutDevice
)
1318 // allocate controller
1320 This
= new(NonPagedPool
, TAG_USBEHCI
) CUSBDevice(0);
1324 // failed to allocate
1326 return STATUS_INSUFFICIENT_RESOURCES
;
1330 // add reference count
1337 *OutDevice
= (PUSBDEVICE
)This
;
1342 return STATUS_SUCCESS
;