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
);
68 virtual NTSTATUS
BuildInterfaceDescriptor(IN ULONG ConfigurationIndex
, IN PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor
, OUT PUSBD_INTERFACE_INFORMATION InterfaceInfo
, OUT PUSB_INTERFACE
*OutUsbInterface
);
71 // constructor / destructor
72 CUSBDevice(IUnknown
*OuterUnknown
){}
73 virtual ~CUSBDevice(){}
77 PHUBCONTROLLER m_HubController
;
78 PUSBHARDWAREDEVICE m_Device
;
81 UCHAR m_DeviceAddress
;
83 UCHAR m_ConfigurationIndex
;
85 USB_DEVICE_DESCRIPTOR m_DeviceDescriptor
;
88 PDMAMEMORYMANAGER m_DmaManager
;
90 PUSB_CONFIGURATION m_ConfigurationDescriptors
;
93 //----------------------------------------------------------------------------------------
96 CUSBDevice::QueryInterface(
100 return STATUS_UNSUCCESSFUL
;
103 //----------------------------------------------------------------------------------------
105 CUSBDevice::Initialize(
106 IN PHUBCONTROLLER HubController
,
107 IN PUSBHARDWAREDEVICE Device
,
115 // initialize members
117 m_HubController
= HubController
;
121 m_PortStatus
= PortStatus
;
124 // initialize device lock
126 KeInitializeSpinLock(&m_Lock
);
129 // no device address has been set yet
134 // get usb request queue
136 Status
= m_Device
->GetUSBQueue(&m_Queue
);
137 if (!NT_SUCCESS(Status
))
140 // failed to get usb queue
142 DPRINT1("CUSBDevice::Initialize GetUsbQueue failed with %x\n", Status
);
149 Status
= m_Device
->GetDMA(&m_DmaManager
);
150 if (!NT_SUCCESS(Status
))
153 // failed to get dma manager
155 DPRINT1("CUSBDevice::Initialize GetDMA failed with %x\n", Status
);
162 PC_ASSERT(m_DmaManager
);
165 // get device descriptor
167 Status
= CreateDeviceDescriptor();
168 if (!NT_SUCCESS(Status
))
171 // failed to get device descriptor
173 DPRINT1("CUSBDevice::Initialize Failed to get device descriptor with %x\n", Status
);
183 //----------------------------------------------------------------------------------------
188 // USB Standard Device Class see http://www.usb.org/developers/defined_class/#BaseClass09h
191 return (m_DeviceDescriptor
.bDeviceClass
== 0x09 && m_DeviceDescriptor
.bDeviceSubClass
== 0x00);
194 //----------------------------------------------------------------------------------------
196 CUSBDevice::GetParent(
207 return STATUS_SUCCESS
;
210 //----------------------------------------------------------------------------------------
212 CUSBDevice::GetDeviceAddress()
215 // get device address
217 return m_DeviceAddress
;
220 //----------------------------------------------------------------------------------------
222 CUSBDevice::GetPort()
225 // get port to which this device is connected to
230 //----------------------------------------------------------------------------------------
232 CUSBDevice::GetSpeed()
234 if (m_PortStatus
& USB_PORT_STATUS_LOW_SPEED
)
241 else if (m_PortStatus
& USB_PORT_STATUS_HIGH_SPEED
)
250 // default to full speed
255 //----------------------------------------------------------------------------------------
257 CUSBDevice::GetType()
260 // device is encoded into bcdUSB
262 if (m_DeviceDescriptor
.bcdUSB
== 0x110)
269 else if (m_DeviceDescriptor
.bcdUSB
== 0x200)
277 DPRINT1("CUSBDevice::GetType Unknown bcdUSB Type %x\n", m_DeviceDescriptor
.bcdUSB
);
283 //----------------------------------------------------------------------------------------
285 CUSBDevice::GetState()
291 //----------------------------------------------------------------------------------------
293 CUSBDevice::SetDeviceHandleData(
297 // set device data, for debugging issues
302 //----------------------------------------------------------------------------------------
304 CUSBDevice::SetDeviceAddress(
307 PUSB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup
;
312 DPRINT1("CUSBDevice::SetDeviceAddress Address %d\n", DeviceAddress
);
314 CtrlSetup
= (PUSB_DEFAULT_PIPE_SETUP_PACKET
)ExAllocatePoolWithTag(NonPagedPool
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
), TAG_USBLIB
);
316 return STATUS_INSUFFICIENT_RESOURCES
;
319 RtlZeroMemory(CtrlSetup
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
321 // initialize request
322 CtrlSetup
->bRequest
= USB_REQUEST_SET_ADDRESS
;
323 CtrlSetup
->wValue
.W
= DeviceAddress
;
325 // set device address
326 Status
= CommitSetupPacket(CtrlSetup
, 0, 0, 0);
329 ExFreePoolWithTag(CtrlSetup
, TAG_USBLIB
);
332 if (!NT_SUCCESS(Status
))
334 // failed to set device address
335 DPRINT1("CUSBDevice::SetDeviceAddress> failed to set device address with %x Address %x\n", Status
, DeviceAddress
);
339 // lets have a short nap
340 KeStallExecutionProcessor(300);
342 // back up old address
343 OldAddress
= m_DeviceAddress
;
345 // store new device address
346 m_DeviceAddress
= DeviceAddress
;
348 // fetch device descriptor
349 Status
= CreateDeviceDescriptor();
350 if (!NT_SUCCESS(Status
))
352 DPRINT1("CUSBbDevice::SetDeviceAddress> failed to retrieve device descriptor with device address set Error %x\n", Status
);
353 // return error status
357 // check for invalid device descriptor
358 if (m_DeviceDescriptor
.bLength
!= sizeof(USB_DEVICE_DESCRIPTOR
) ||
359 m_DeviceDescriptor
.bDescriptorType
!= USB_DEVICE_DESCRIPTOR_TYPE
||
360 m_DeviceDescriptor
.bNumConfigurations
== 0)
362 // failed to retrieve device descriptor
363 DPRINT1("CUSBbDevice::SetDeviceAddress> device returned bogus device descriptor\n");
364 DumpDeviceDescriptor(&m_DeviceDescriptor
);
366 // return error status
367 return STATUS_UNSUCCESSFUL
;
370 // dump device descriptor
371 DumpDeviceDescriptor(&m_DeviceDescriptor
);
374 PC_ASSERT(m_DeviceDescriptor
.bNumConfigurations
);
376 // allocate configuration descriptor
377 m_ConfigurationDescriptors
= (PUSB_CONFIGURATION
) ExAllocatePoolWithTag(NonPagedPool
, sizeof(USB_CONFIGURATION
) * m_DeviceDescriptor
.bNumConfigurations
, TAG_USBLIB
);
379 // zero configuration descriptor
380 RtlZeroMemory(m_ConfigurationDescriptors
, sizeof(USB_CONFIGURATION
) * m_DeviceDescriptor
.bNumConfigurations
);
382 // retrieve the configuration descriptors
383 for(Index
= 0; Index
< m_DeviceDescriptor
.bNumConfigurations
; Index
++)
385 // retrieve configuration descriptors from device
386 Status
= CreateConfigurationDescriptor(Index
);
387 if (!NT_SUCCESS(Status
))
389 DPRINT1("CUSBDevice::SetDeviceAddress> failed to retrieve configuration %lu\n", Index
);
402 //----------------------------------------------------------------------------------------
404 CUSBDevice::GetDeviceDescriptor(
405 PUSB_DEVICE_DESCRIPTOR DeviceDescriptor
)
407 RtlMoveMemory(DeviceDescriptor
, &m_DeviceDescriptor
, sizeof(USB_DEVICE_DESCRIPTOR
));
410 //----------------------------------------------------------------------------------------
412 CUSBDevice::GetConfigurationValue()
415 // return configuration index
417 return m_ConfigurationIndex
;
420 //----------------------------------------------------------------------------------------
422 CUSBDevice::CommitIrp(
428 if (!m_Queue
|| !m_DmaManager
)
433 DPRINT1("CUSBDevice::CommitUrb> no queue / dma !!!\n");
434 return STATUS_UNSUCCESSFUL
;
440 Status
= m_Queue
->CreateUSBRequest(&Request
);
441 if (!NT_SUCCESS(Status
))
444 // failed to build request
446 DPRINT1("CUSBDevice::CommitSetupPacket> CreateUSBRequest failed with %x\n", Status
);
451 // initialize request
453 Status
= Request
->InitializeWithIrp(m_DmaManager
, PUSBDEVICE(this), Irp
);
456 // mark irp as pending
458 IoMarkIrpPending(Irp
);
461 // now add the request
463 Status
= m_Queue
->AddUSBRequest(Request
);
464 if (!NT_SUCCESS(Status
))
467 // failed to add request
469 DPRINT1("CUSBDevice::CommitSetupPacket> failed add request to queue with %x\n", Status
);
477 return STATUS_PENDING
;
480 //----------------------------------------------------------------------------------------
482 CUSBDevice::SubmitIrp(
489 // acquire device lock
491 KeAcquireSpinLock(&m_Lock
, &OldLevel
);
496 Status
= CommitIrp(Irp
);
501 KeReleaseSpinLock(&m_Lock
, OldLevel
);
505 //----------------------------------------------------------------------------------------
507 CUSBDevice::CommitSetupPacket(
508 IN PUSB_DEFAULT_PIPE_SETUP_PACKET Packet
,
509 IN OPTIONAL PUSB_ENDPOINT EndpointDescriptor
,
510 IN ULONG BufferLength
,
521 DPRINT1("CUSBDevice::CommitSetupPacket> no queue!!!\n");
522 return STATUS_UNSUCCESSFUL
;
528 Status
= m_Queue
->CreateUSBRequest(&Request
);
529 if (!NT_SUCCESS(Status
))
532 // failed to build request
534 DPRINT1("CUSBDevice::CommitSetupPacket> CreateUSBRequest failed with %x\n", Status
);
539 // initialize request
541 Status
= Request
->InitializeWithSetupPacket(m_DmaManager
, Packet
, PUSBDEVICE(this), EndpointDescriptor
, BufferLength
, Mdl
);
542 if (!NT_SUCCESS(Status
))
545 // failed to initialize request
547 DPRINT1("CUSBDevice::CommitSetupPacket> failed to initialize usb request with %x\n", Status
);
553 // now add the request
555 Status
= m_Queue
->AddUSBRequest(Request
);
556 if (!NT_SUCCESS(Status
))
559 // failed to add request
561 DPRINT1("CUSBDevice::CommitSetupPacket> failed add request to queue with %x\n", Status
);
567 // get the result code when the operation has been finished
569 Request
->GetResultStatus(&Status
, NULL
);
582 //----------------------------------------------------------------------------------------
584 CUSBDevice::CreateDeviceDescriptor()
586 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup
;
594 RtlZeroMemory(&m_DeviceDescriptor
, sizeof(USB_DEVICE_DESCRIPTOR
));
595 RtlZeroMemory(&CtrlSetup
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
600 CtrlSetup
.bRequest
= USB_REQUEST_GET_DESCRIPTOR
;
601 CtrlSetup
.wValue
.HiByte
= USB_DEVICE_DESCRIPTOR_TYPE
;
602 CtrlSetup
.wLength
= sizeof(USB_DEVICE_DESCRIPTOR
);
603 CtrlSetup
.bmRequestType
.B
= 0x80;
608 Buffer
= ExAllocatePool(NonPagedPool
, PAGE_SIZE
);
612 // failed to allocate
614 return STATUS_INSUFFICIENT_RESOURCES
;
620 RtlZeroMemory(Buffer
, PAGE_SIZE
);
623 // allocate mdl describing the device descriptor
625 Mdl
= IoAllocateMdl(Buffer
, sizeof(USB_DEVICE_DESCRIPTOR
), FALSE
, FALSE
, 0);
629 // failed to allocate mdl
631 return STATUS_INSUFFICIENT_RESOURCES
;
635 // build mdl for non paged pool
637 MmBuildMdlForNonPagedPool(Mdl
);
640 // commit setup packet
642 Status
= CommitSetupPacket(&CtrlSetup
, 0, sizeof(USB_DEVICE_DESCRIPTOR
), Mdl
);
649 if (NT_SUCCESS(Status
))
652 // copy device descriptor
654 RtlCopyMemory(&m_DeviceDescriptor
, Buffer
, sizeof(USB_DEVICE_DESCRIPTOR
));
669 //----------------------------------------------------------------------------------------
671 CUSBDevice::GetConfigurationDescriptor(
672 IN UCHAR ConfigurationIndex
,
673 IN USHORT BufferSize
,
676 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup
;
682 // now build MDL describing the buffer
684 Mdl
= IoAllocateMdl(Buffer
, BufferSize
, FALSE
, FALSE
, 0);
688 // failed to allocate mdl
690 return STATUS_INSUFFICIENT_RESOURCES
;
694 // build mdl for non paged pool
696 MmBuildMdlForNonPagedPool(Mdl
);
700 // build setup packet
702 CtrlSetup
.bmRequestType
._BM
.Recipient
= BMREQUEST_TO_DEVICE
;
703 CtrlSetup
.bmRequestType
._BM
.Type
= BMREQUEST_STANDARD
;
704 CtrlSetup
.bmRequestType
._BM
.Reserved
= 0;
705 CtrlSetup
.bmRequestType
._BM
.Dir
= BMREQUEST_DEVICE_TO_HOST
;
706 CtrlSetup
.bRequest
= USB_REQUEST_GET_DESCRIPTOR
;
707 CtrlSetup
.wValue
.LowByte
= ConfigurationIndex
;
708 CtrlSetup
.wValue
.HiByte
= USB_CONFIGURATION_DESCRIPTOR_TYPE
;
709 CtrlSetup
.wIndex
.W
= 0;
710 CtrlSetup
.wLength
= BufferSize
;
715 Status
= CommitSetupPacket(&CtrlSetup
, 0, BufferSize
, Mdl
);
728 //----------------------------------------------------------------------------------------
730 CUSBDevice::CreateConfigurationDescriptor(
734 PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
;
739 PC_ASSERT(m_ConfigurationDescriptors
);
742 // first allocate a buffer which should be enough to store all different interfaces and endpoints
744 ConfigurationDescriptor
= (PUSB_CONFIGURATION_DESCRIPTOR
)ExAllocatePoolWithTag(NonPagedPool
, PAGE_SIZE
, TAG_USBLIB
);
745 if (!ConfigurationDescriptor
)
748 // failed to allocate buffer
750 return STATUS_INSUFFICIENT_RESOURCES
;
754 // get partial configuration descriptor
756 Status
= GetConfigurationDescriptor(Index
, sizeof(USB_CONFIGURATION_DESCRIPTOR
), ConfigurationDescriptor
);
757 if (!NT_SUCCESS(Status
))
760 // failed to get partial configuration descriptor
762 DPRINT1("[USBLIB] Failed to get partial configuration descriptor Status %x Index %x\n", Status
, Index
);
763 ExFreePoolWithTag(ConfigurationDescriptor
, TAG_USBLIB
);
768 // now get full descriptor
770 Status
= GetConfigurationDescriptor(Index
, ConfigurationDescriptor
->wTotalLength
, ConfigurationDescriptor
);
771 if (!NT_SUCCESS(Status
))
774 // failed to get full configuration descriptor
776 DPRINT1("[USBLIB] Failed to get full configuration descriptor Status %x Index %x\n", Status
, Index
);
777 ExFreePoolWithTag(ConfigurationDescriptor
, TAG_USBLIB
);
782 // informal debug print
784 DumpConfigurationDescriptor(ConfigurationDescriptor
);
789 PC_ASSERT(ConfigurationDescriptor
->bLength
== sizeof(USB_CONFIGURATION_DESCRIPTOR
));
790 PC_ASSERT(ConfigurationDescriptor
->wTotalLength
<= PAGE_SIZE
);
791 PC_ASSERT(ConfigurationDescriptor
->bNumInterfaces
);
794 // request is complete, initialize configuration descriptor
796 m_ConfigurationDescriptors
[Index
].ConfigurationDescriptor
= ConfigurationDescriptor
;
797 InitializeListHead(&m_ConfigurationDescriptors
[Index
].InterfaceList
);
804 //----------------------------------------------------------------------------------------
806 CUSBDevice::GetConfigurationDescriptors(
807 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptorBuffer
,
808 IN ULONG BufferLength
,
809 OUT PULONG OutBufferLength
)
812 ASSERT(BufferLength
>= sizeof(USB_CONFIGURATION_DESCRIPTOR
));
813 ASSERT(ConfigDescriptorBuffer
);
814 ASSERT(OutBufferLength
);
816 // reset copied length
817 *OutBufferLength
= 0;
819 // FIXME: support multiple configurations
820 PC_ASSERT(m_DeviceDescriptor
.bNumConfigurations
== 1);
822 // copy configuration descriptor
823 RtlCopyMemory(ConfigDescriptorBuffer
, m_ConfigurationDescriptors
[0].ConfigurationDescriptor
, min(m_ConfigurationDescriptors
[0].ConfigurationDescriptor
->wTotalLength
, BufferLength
));
824 *OutBufferLength
= m_ConfigurationDescriptors
[0].ConfigurationDescriptor
->wTotalLength
;
827 //----------------------------------------------------------------------------------------
829 CUSBDevice::GetConfigurationDescriptorsLength()
832 // FIXME: support multiple configurations
834 PC_ASSERT(m_DeviceDescriptor
.bNumConfigurations
== 1);
836 return m_ConfigurationDescriptors
[0].ConfigurationDescriptor
->wTotalLength
;
838 //----------------------------------------------------------------------------------------
840 CUSBDevice::DumpDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor
)
842 DPRINT1("Dumping Device Descriptor %x\n", DeviceDescriptor
);
843 DPRINT1("bLength %x\n", DeviceDescriptor
->bLength
);
844 DPRINT1("bDescriptorType %x\n", DeviceDescriptor
->bDescriptorType
);
845 DPRINT1("bcdUSB %x\n", DeviceDescriptor
->bcdUSB
);
846 DPRINT1("bDeviceClass %x\n", DeviceDescriptor
->bDeviceClass
);
847 DPRINT1("bDeviceSubClass %x\n", DeviceDescriptor
->bDeviceSubClass
);
848 DPRINT1("bDeviceProtocol %x\n", DeviceDescriptor
->bDeviceProtocol
);
849 DPRINT1("bMaxPacketSize0 %x\n", DeviceDescriptor
->bMaxPacketSize0
);
850 DPRINT1("idVendor %x\n", DeviceDescriptor
->idVendor
);
851 DPRINT1("idProduct %x\n", DeviceDescriptor
->idProduct
);
852 DPRINT1("bcdDevice %x\n", DeviceDescriptor
->bcdDevice
);
853 DPRINT1("iManufacturer %x\n", DeviceDescriptor
->iManufacturer
);
854 DPRINT1("iProduct %x\n", DeviceDescriptor
->iProduct
);
855 DPRINT1("iSerialNumber %x\n", DeviceDescriptor
->iSerialNumber
);
856 DPRINT1("bNumConfigurations %x\n", DeviceDescriptor
->bNumConfigurations
);
859 //----------------------------------------------------------------------------------------
861 CUSBDevice::DumpConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
)
863 DPRINT1("Dumping ConfigurationDescriptor %x\n", ConfigurationDescriptor
);
864 DPRINT1("bLength %x\n", ConfigurationDescriptor
->bLength
);
865 DPRINT1("bDescriptorType %x\n", ConfigurationDescriptor
->bDescriptorType
);
866 DPRINT1("wTotalLength %x\n", ConfigurationDescriptor
->wTotalLength
);
867 DPRINT1("bNumInterfaces %x\n", ConfigurationDescriptor
->bNumInterfaces
);
868 DPRINT1("bConfigurationValue %x\n", ConfigurationDescriptor
->bConfigurationValue
);
869 DPRINT1("iConfiguration %x\n", ConfigurationDescriptor
->iConfiguration
);
870 DPRINT1("bmAttributes %x\n", ConfigurationDescriptor
->bmAttributes
);
871 DPRINT1("MaxPower %x\n", ConfigurationDescriptor
->MaxPower
);
873 //----------------------------------------------------------------------------------------
875 CUSBDevice::SubmitSetupPacket(
876 IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket
,
877 IN OUT ULONG BufferLength
,
888 Mdl
= IoAllocateMdl(Buffer
, BufferLength
, FALSE
, FALSE
, 0);
894 return STATUS_INSUFFICIENT_RESOURCES
;
898 // HACK HACK HACK: assume the buffer is build from non paged pool
900 MmBuildMdlForNonPagedPool(Mdl
);
904 // commit setup packet
906 Status
= CommitSetupPacket(SetupPacket
, 0, BufferLength
, Mdl
);
921 //----------------------------------------------------------------------------------------
923 CUSBDevice::BuildInterfaceDescriptor(
924 IN ULONG ConfigurationIndex
,
925 IN PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor
,
926 OUT PUSBD_INTERFACE_INFORMATION InterfaceInfo
,
927 OUT PUSB_INTERFACE
*OutUsbInterface
)
929 PUSB_INTERFACE UsbInterface
;
930 PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor
;
933 // allocate interface handle
934 UsbInterface
= (PUSB_INTERFACE
)ExAllocatePool(NonPagedPool
, sizeof(USB_INTERFACE
) + (InterfaceDescriptor
->bNumEndpoints
- 1) * sizeof(USB_ENDPOINT
));
937 // failed to allocate memory
938 return STATUS_INSUFFICIENT_RESOURCES
;
942 RtlZeroMemory(UsbInterface
, sizeof(USB_INTERFACE
) + (InterfaceDescriptor
->bNumEndpoints
- 1) * sizeof(USB_ENDPOINT
));
945 InterfaceInfo
->InterfaceHandle
= (USBD_INTERFACE_HANDLE
)UsbInterface
;
946 InterfaceInfo
->Class
= InterfaceDescriptor
->bInterfaceClass
;
947 InterfaceInfo
->SubClass
= InterfaceDescriptor
->bInterfaceSubClass
;
948 InterfaceInfo
->Protocol
= InterfaceDescriptor
->bInterfaceProtocol
;
949 InterfaceInfo
->Reserved
= 0;
952 // init interface handle
953 UsbInterface
->InterfaceDescriptor
= InterfaceDescriptor
;
954 InsertTailList(&m_ConfigurationDescriptors
[ConfigurationIndex
].InterfaceList
, &UsbInterface
->ListEntry
);
956 // grab first endpoint descriptor
957 EndpointDescriptor
= (PUSB_ENDPOINT_DESCRIPTOR
) (InterfaceDescriptor
+ 1);
959 // now copy all endpoint information
960 for(PipeIndex
= 0; PipeIndex
< InterfaceDescriptor
->bNumEndpoints
; PipeIndex
++)
962 while(EndpointDescriptor
->bDescriptorType
!= USB_ENDPOINT_DESCRIPTOR_TYPE
)
964 // skip intermediate descriptors
965 if (EndpointDescriptor
->bLength
== 0 || EndpointDescriptor
->bDescriptorType
== USB_INTERFACE_DESCRIPTOR_TYPE
)
967 // bogus configuration descriptor
968 DPRINT1("[USBEHCI] Bogus descriptor found in InterfaceNumber %x Alternate %x EndpointIndex %x bLength %x bDescriptorType %x\n", InterfaceDescriptor
->bInterfaceNumber
, InterfaceDescriptor
->bAlternateSetting
, PipeIndex
,
969 EndpointDescriptor
->bLength
, EndpointDescriptor
->bDescriptorType
);
972 return STATUS_UNSUCCESSFUL
;
975 // move to next descriptor
976 EndpointDescriptor
= (PUSB_ENDPOINT_DESCRIPTOR
)((ULONG_PTR
)EndpointDescriptor
+ EndpointDescriptor
->bLength
);
979 // store in interface info
980 RtlCopyMemory(&UsbInterface
->EndPoints
[PipeIndex
].EndPointDescriptor
, EndpointDescriptor
, sizeof(USB_ENDPOINT_DESCRIPTOR
));
982 DPRINT("Configuration Descriptor %p Length %lu\n", m_ConfigurationDescriptors
[ConfigurationIndex
].ConfigurationDescriptor
, m_ConfigurationDescriptors
[ConfigurationIndex
].ConfigurationDescriptor
->wTotalLength
);
983 DPRINT("EndpointDescriptor %p DescriptorType %x bLength %x\n", EndpointDescriptor
, EndpointDescriptor
->bDescriptorType
, EndpointDescriptor
->bLength
);
984 DPRINT("EndpointDescriptorHandle %p bAddress %x bmAttributes %x\n",&UsbInterface
->EndPoints
[PipeIndex
], UsbInterface
->EndPoints
[PipeIndex
].EndPointDescriptor
.bEndpointAddress
,
985 UsbInterface
->EndPoints
[PipeIndex
].EndPointDescriptor
.bmAttributes
);
988 InterfaceInfo
->Pipes
[PipeIndex
].MaximumPacketSize
= UsbInterface
->EndPoints
[PipeIndex
].EndPointDescriptor
.wMaxPacketSize
;
989 InterfaceInfo
->Pipes
[PipeIndex
].EndpointAddress
= UsbInterface
->EndPoints
[PipeIndex
].EndPointDescriptor
.bEndpointAddress
;
990 InterfaceInfo
->Pipes
[PipeIndex
].Interval
= UsbInterface
->EndPoints
[PipeIndex
].EndPointDescriptor
.bInterval
;
991 InterfaceInfo
->Pipes
[PipeIndex
].PipeType
= (USBD_PIPE_TYPE
)UsbInterface
->EndPoints
[PipeIndex
].EndPointDescriptor
.bmAttributes
;
992 InterfaceInfo
->Pipes
[PipeIndex
].PipeHandle
= (PVOID
)&UsbInterface
->EndPoints
[PipeIndex
];
994 // move to next descriptor
995 EndpointDescriptor
= (PUSB_ENDPOINT_DESCRIPTOR
)((ULONG_PTR
)EndpointDescriptor
+ EndpointDescriptor
->bLength
);
1001 *OutUsbInterface
= UsbInterface
;
1003 return STATUS_SUCCESS
;
1008 //----------------------------------------------------------------------------------------
1010 CUSBDevice::SelectConfiguration(
1011 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
,
1012 IN PUSBD_INTERFACE_INFORMATION InterfaceInfo
,
1013 OUT USBD_CONFIGURATION_HANDLE
*ConfigurationHandle
)
1015 ULONG InterfaceIndex
;
1016 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup
;
1018 UCHAR bConfigurationValue
= 0;
1019 ULONG ConfigurationIndex
= 0, Index
;
1020 UCHAR Found
= FALSE
;
1021 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor
;
1022 PUSB_INTERFACE UsbInterface
;
1025 if (ConfigurationDescriptor
)
1027 // find configuration index
1028 for(Index
= 0; Index
< m_DeviceDescriptor
.bNumConfigurations
; Index
++)
1030 if (m_ConfigurationDescriptors
[Index
].ConfigurationDescriptor
->bConfigurationValue
== ConfigurationDescriptor
->bConfigurationValue
)
1032 // found configuration index
1033 ConfigurationIndex
= Index
;
1040 DPRINT1("[USBUHCI] invalid configuration value %lu\n", ConfigurationDescriptor
->bConfigurationValue
);
1041 return STATUS_INVALID_PARAMETER
;
1045 ASSERT(ConfigurationDescriptor
->bNumInterfaces
<= m_ConfigurationDescriptors
[ConfigurationIndex
].ConfigurationDescriptor
->bNumInterfaces
);
1047 // get configuration value
1048 bConfigurationValue
= ConfigurationDescriptor
->bConfigurationValue
;
1051 // now build setup packet
1052 RtlZeroMemory(&CtrlSetup
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
1053 CtrlSetup
.bRequest
= USB_REQUEST_SET_CONFIGURATION
;
1054 CtrlSetup
.wValue
.W
= bConfigurationValue
;
1056 // select configuration
1057 Status
= CommitSetupPacket(&CtrlSetup
, 0, 0, 0);
1059 if (!ConfigurationDescriptor
)
1061 // unconfigure request
1062 DPRINT1("CUsbDevice::SelectConfiguration Unconfigure Request Status %x\n", Status
);
1063 m_ConfigurationIndex
= 0;
1067 // informal debug print
1068 DPRINT1("CUsbDevice::SelectConfiguration New Configuration %x Old Configuration %x Result %x\n", ConfigurationIndex
, m_ConfigurationIndex
, Status
);
1069 if (!NT_SUCCESS(Status
))
1077 // destroy old interface info
1078 while(!IsListEmpty(&m_ConfigurationDescriptors
[m_ConfigurationIndex
].InterfaceList
))
1081 Entry
= RemoveHeadList(&m_ConfigurationDescriptors
[m_ConfigurationIndex
].InterfaceList
);
1083 // get interface info
1084 UsbInterface
= (PUSB_INTERFACE
)CONTAINING_RECORD(Entry
, USB_INTERFACE
, ListEntry
);
1086 // free interface info
1087 ExFreePool(UsbInterface
);
1091 ASSERT(IsListEmpty(&m_ConfigurationDescriptors
[ConfigurationIndex
].InterfaceList
));
1093 // store new configuration device index
1094 m_ConfigurationIndex
= ConfigurationIndex
;
1096 // store configuration handle
1097 *ConfigurationHandle
= &m_ConfigurationDescriptors
[ConfigurationIndex
];
1099 // copy interface info and pipe info
1100 for(InterfaceIndex
= 0; InterfaceIndex
< ConfigurationDescriptor
->bNumInterfaces
; InterfaceIndex
++)
1102 // interface info checks
1103 ASSERT(InterfaceInfo
->Length
!= 0);
1106 PC_ASSERT(InterfaceInfo
->Length
== FIELD_OFFSET(USBD_INTERFACE_INFORMATION
, Pipes
[InterfaceInfo
->NumberOfPipes
]));
1109 // find interface descriptor
1110 InterfaceDescriptor
= USBD_ParseConfigurationDescriptor(m_ConfigurationDescriptors
[ConfigurationIndex
].ConfigurationDescriptor
, InterfaceInfo
->InterfaceNumber
, InterfaceInfo
->AlternateSetting
);
1113 ASSERT(InterfaceDescriptor
!= NULL
);
1115 // check if the number of pipes have been properly set
1116 ASSERT(InterfaceInfo
->NumberOfPipes
== InterfaceDescriptor
->bNumEndpoints
);
1118 // copy interface info
1119 Status
= BuildInterfaceDescriptor(ConfigurationIndex
, InterfaceDescriptor
, InterfaceInfo
, NULL
);
1120 if (!NT_SUCCESS(Status
))
1127 InterfaceInfo
= (PUSBD_INTERFACE_INFORMATION
)((ULONG_PTR
)PtrToUlong(InterfaceInfo
) + InterfaceInfo
->Length
);
1136 //----------------------------------------------------------------------------------------
1138 CUSBDevice::SelectInterface(
1139 IN USBD_CONFIGURATION_HANDLE ConfigurationHandle
,
1140 IN OUT PUSBD_INTERFACE_INFORMATION InterfaceInfo
)
1143 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup
;
1145 ULONG Index
, ConfigurationIndex
= 0, Found
= FALSE
;
1146 PUSB_INTERFACE UsbInterface
;
1148 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor
;
1150 // check if handle is valid
1151 for(Index
= 0; Index
< m_DeviceDescriptor
.bNumConfigurations
; Index
++)
1153 if (&m_ConfigurationDescriptors
[Index
] == ConfigurationHandle
)
1155 // found configuration index
1156 ConfigurationIndex
= Index
;
1163 // invalid handle passed
1164 DPRINT1("[USBEHCI] Invalid configuration handle passed %p\n", ConfigurationHandle
);
1165 return STATUS_INVALID_PARAMETER
;
1168 // initialize setup packet
1169 RtlZeroMemory(&CtrlSetup
, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET
));
1170 CtrlSetup
.bRequest
= USB_REQUEST_SET_INTERFACE
;
1171 CtrlSetup
.wValue
.W
= InterfaceInfo
->AlternateSetting
;
1172 CtrlSetup
.wIndex
.W
= InterfaceInfo
->InterfaceNumber
;
1173 CtrlSetup
.bmRequestType
.B
= 0x01;
1176 Status
= CommitSetupPacket(&CtrlSetup
, 0, 0, 0);
1178 // informal debug print
1179 DPRINT1("CUSBDevice::SelectInterface AlternateSetting %x InterfaceNumber %x Status %x\n", InterfaceInfo
->AlternateSetting
, InterfaceInfo
->InterfaceNumber
, Status
);
1181 if (!NT_SUCCESS(Status
))
1183 // failed to select interface
1188 Status
= STATUS_SUCCESS
;
1193 Entry
= m_ConfigurationDescriptors
[ConfigurationIndex
].InterfaceList
.Flink
;
1194 while(Entry
!= &m_ConfigurationDescriptors
[ConfigurationIndex
].InterfaceList
)
1196 // grab interface descriptor
1197 UsbInterface
= (PUSB_INTERFACE
)CONTAINING_RECORD(Entry
, USB_INTERFACE
, ListEntry
);
1198 if (UsbInterface
->InterfaceDescriptor
->bAlternateSetting
== InterfaceInfo
->AlternateSetting
&&
1199 UsbInterface
->InterfaceDescriptor
->bInterfaceNumber
== InterfaceInfo
->InterfaceNumber
)
1207 Entry
= Entry
->Flink
;
1212 // find interface descriptor
1213 InterfaceDescriptor
= USBD_ParseConfigurationDescriptor(m_ConfigurationDescriptors
[ConfigurationIndex
].ConfigurationDescriptor
, InterfaceInfo
->InterfaceNumber
, InterfaceInfo
->AlternateSetting
);
1214 if (!InterfaceDescriptor
)
1216 DPRINT1("[LIBUSB] No such interface Alternate %x InterfaceNumber %x\n", InterfaceInfo
->AlternateSetting
, InterfaceInfo
->InterfaceNumber
);
1217 return STATUS_UNSUCCESSFUL
;
1220 // build interface descriptor
1221 Status
= BuildInterfaceDescriptor(ConfigurationIndex
, InterfaceDescriptor
, InterfaceInfo
, &UsbInterface
);
1222 if (!NT_SUCCESS(Status
))
1225 DPRINT1("[LIBUSB] Failed to build interface descriptor Status %x\n", Status
);
1230 // assert on pipe length mismatch
1231 DPRINT1("NumberOfPipes %lu Endpoints %lu Length %lu\n", InterfaceInfo
->NumberOfPipes
, UsbInterface
->InterfaceDescriptor
->bNumEndpoints
, InterfaceInfo
->Length
);
1234 ASSERT(GET_USBD_INTERFACE_SIZE(UsbInterface
->InterfaceDescriptor
->bNumEndpoints
) == InterfaceInfo
->Length
);
1236 // store number of pipes
1237 InterfaceInfo
->NumberOfPipes
= UsbInterface
->InterfaceDescriptor
->bNumEndpoints
;
1239 // copy pipe handles
1240 for(PipeIndex
= 0; PipeIndex
< UsbInterface
->InterfaceDescriptor
->bNumEndpoints
; PipeIndex
++)
1243 DPRINT1("PipeIndex %lu\n", PipeIndex
);
1244 DPRINT1("EndpointAddress %x\n", InterfaceInfo
->Pipes
[PipeIndex
].EndpointAddress
);
1245 DPRINT1("Interval %d\n", InterfaceInfo
->Pipes
[PipeIndex
].Interval
);
1246 DPRINT1("MaximumPacketSize %d\n", InterfaceInfo
->Pipes
[PipeIndex
].MaximumPacketSize
);
1247 DPRINT1("MaximumTransferSize %d\n", InterfaceInfo
->Pipes
[PipeIndex
].MaximumTransferSize
);
1248 DPRINT1("PipeFlags %d\n", InterfaceInfo
->Pipes
[PipeIndex
].PipeFlags
);
1249 DPRINT1("PipeType %dd\n", InterfaceInfo
->Pipes
[PipeIndex
].PipeType
);
1250 DPRINT1("UsbEndPoint %x\n", InterfaceInfo
->Pipes
[PipeIndex
].EndpointAddress
);
1253 ASSERT(InterfaceInfo
->Pipes
[PipeIndex
].EndpointAddress
== UsbInterface
->EndPoints
[PipeIndex
].EndPointDescriptor
.bEndpointAddress
);
1254 ASSERT(InterfaceInfo
->Pipes
[PipeIndex
].Interval
== UsbInterface
->EndPoints
[PipeIndex
].EndPointDescriptor
.bInterval
);
1256 // store pipe handle
1257 InterfaceInfo
->Pipes
[PipeIndex
].PipeHandle
= &UsbInterface
->EndPoints
[PipeIndex
];
1259 // data toggle is reset on select interface requests
1260 UsbInterface
->EndPoints
[PipeIndex
].DataToggle
= FALSE
;
1271 CUSBDevice::AbortPipe(
1272 IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor
)
1275 // let it handle usb queue
1278 ASSERT(m_DeviceAddress
);
1283 return m_Queue
->AbortDevicePipe(m_DeviceAddress
, EndpointDescriptor
);
1287 CUSBDevice::GetMaxPacketSize()
1289 return m_DeviceDescriptor
.bMaxPacketSize0
;
1293 //----------------------------------------------------------------------------------------
1297 PUSBDEVICE
*OutDevice
)
1302 // allocate controller
1304 This
= new(NonPagedPool
, TAG_USBLIB
) CUSBDevice(0);
1308 // failed to allocate
1310 return STATUS_INSUFFICIENT_RESOURCES
;
1314 // add reference count
1321 *OutDevice
= (PUSBDEVICE
)This
;
1326 return STATUS_SUCCESS
;