[LIBUSB]
[reactos.git] / reactos / lib / drivers / libusb / usb_device.cpp
1 /*
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.
6 * PROGRAMMERS:
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
9 */
10
11
12 #define INITGUID
13 #include "libusb.h"
14
15 class CUSBDevice : public IUSBDevice
16 {
17 public:
18 STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
19
20 STDMETHODIMP_(ULONG) AddRef()
21 {
22 InterlockedIncrement(&m_Ref);
23 return m_Ref;
24 }
25 STDMETHODIMP_(ULONG) Release()
26 {
27 InterlockedDecrement(&m_Ref);
28
29 if (!m_Ref)
30 {
31 delete this;
32 return 0;
33 }
34 return m_Ref;
35 }
36
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();
58
59
60 // local function
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
69 // constructor / destructor
70 CUSBDevice(IUnknown *OuterUnknown){}
71 virtual ~CUSBDevice(){}
72
73 protected:
74 LONG m_Ref;
75 PHUBCONTROLLER m_HubController;
76 PUSBHARDWAREDEVICE m_Device;
77 PVOID m_Parent;
78 ULONG m_Port;
79 UCHAR m_DeviceAddress;
80 PVOID m_Data;
81 UCHAR m_ConfigurationIndex;
82 KSPIN_LOCK m_Lock;
83 USB_DEVICE_DESCRIPTOR m_DeviceDescriptor;
84 ULONG m_PortStatus;
85 PUSBQUEUE m_Queue;
86 PDMAMEMORYMANAGER m_DmaManager;
87
88 PUSB_CONFIGURATION m_ConfigurationDescriptors;
89 };
90
91 //----------------------------------------------------------------------------------------
92 NTSTATUS
93 STDMETHODCALLTYPE
94 CUSBDevice::QueryInterface(
95 IN REFIID refiid,
96 OUT PVOID* Output)
97 {
98 return STATUS_UNSUCCESSFUL;
99 }
100
101 //----------------------------------------------------------------------------------------
102 NTSTATUS
103 CUSBDevice::Initialize(
104 IN PHUBCONTROLLER HubController,
105 IN PUSBHARDWAREDEVICE Device,
106 IN PVOID Parent,
107 IN ULONG Port,
108 IN ULONG PortStatus)
109 {
110 NTSTATUS Status;
111
112 //
113 // initialize members
114 //
115 m_HubController = HubController;
116 m_Device = Device;
117 m_Parent = Parent;
118 m_Port = Port;
119 m_PortStatus = PortStatus;
120
121 //
122 // initialize device lock
123 //
124 KeInitializeSpinLock(&m_Lock);
125
126 //
127 // no device address has been set yet
128 //
129 m_DeviceAddress = 0;
130
131 //
132 // get usb request queue
133 //
134 Status = m_Device->GetUSBQueue(&m_Queue);
135 if (!NT_SUCCESS(Status))
136 {
137 //
138 // failed to get usb queue
139 //
140 DPRINT1("CUSBDevice::Initialize GetUsbQueue failed with %x\n", Status);
141 return Status;
142 }
143
144 //
145 // get dma manager
146 //
147 Status = m_Device->GetDMA(&m_DmaManager);
148 if (!NT_SUCCESS(Status))
149 {
150 //
151 // failed to get dma manager
152 //
153 DPRINT1("CUSBDevice::Initialize GetDMA failed with %x\n", Status);
154 return Status;
155 }
156
157 //
158 // sanity check
159 //
160 PC_ASSERT(m_DmaManager);
161
162 //
163 // get device descriptor
164 //
165 Status = CreateDeviceDescriptor();
166 if (!NT_SUCCESS(Status))
167 {
168 //
169 // failed to get device descriptor
170 //
171 DPRINT1("CUSBDevice::Initialize Failed to get device descriptor with %x\n", Status);
172 return Status;
173 }
174
175 //
176 // done
177 //
178 return Status;
179 }
180
181 //----------------------------------------------------------------------------------------
182 BOOLEAN
183 CUSBDevice::IsHub()
184 {
185 //
186 // USB Standard Device Class see http://www.usb.org/developers/defined_class/#BaseClass09h
187 // for details
188 //
189 return (m_DeviceDescriptor.bDeviceClass == 0x09 && m_DeviceDescriptor.bDeviceSubClass == 0x00);
190 }
191
192 //----------------------------------------------------------------------------------------
193 NTSTATUS
194 CUSBDevice::GetParent(
195 PVOID * Parent)
196 {
197 //
198 // returns parent
199 //
200 *Parent = m_Parent;
201
202 //
203 // done
204 //
205 return STATUS_SUCCESS;
206 }
207
208 //----------------------------------------------------------------------------------------
209 UCHAR
210 CUSBDevice::GetDeviceAddress()
211 {
212 //
213 // get device address
214 //
215 return m_DeviceAddress;
216 }
217
218 //----------------------------------------------------------------------------------------
219 ULONG
220 CUSBDevice::GetPort()
221 {
222 //
223 // get port to which this device is connected to
224 //
225 return m_Port;
226 }
227
228 //----------------------------------------------------------------------------------------
229 USB_DEVICE_SPEED
230 CUSBDevice::GetSpeed()
231 {
232 if (m_PortStatus & USB_PORT_STATUS_LOW_SPEED)
233 {
234 //
235 // low speed device
236 //
237 return UsbLowSpeed;
238 }
239 else if (m_PortStatus & USB_PORT_STATUS_HIGH_SPEED)
240 {
241 //
242 // high speed device
243 //
244 return UsbHighSpeed;
245 }
246
247 //
248 // default to full speed
249 //
250 return UsbFullSpeed;
251 }
252
253 //----------------------------------------------------------------------------------------
254 USB_DEVICE_TYPE
255 CUSBDevice::GetType()
256 {
257 //
258 // device is encoded into bcdUSB
259 //
260 if (m_DeviceDescriptor.bcdUSB == 0x110)
261 {
262 //
263 // USB 1.1 device
264 //
265 return Usb11Device;
266 }
267 else if (m_DeviceDescriptor.bcdUSB == 0x200)
268 {
269 //
270 // USB 2.0 device
271 //
272 return Usb20Device;
273 }
274
275 DPRINT1("CUSBDevice::GetType Unknown bcdUSB Type %x\n", m_DeviceDescriptor.bcdUSB);
276 //PC_ASSERT(FALSE);
277
278 return Usb11Device;
279 }
280
281 //----------------------------------------------------------------------------------------
282 ULONG
283 CUSBDevice::GetState()
284 {
285 UNIMPLEMENTED
286 return FALSE;
287 }
288
289 //----------------------------------------------------------------------------------------
290 void
291 CUSBDevice::SetDeviceHandleData(
292 PVOID Data)
293 {
294 //
295 // set device data, for debugging issues
296 //
297 m_Data = Data;
298 }
299
300 //----------------------------------------------------------------------------------------
301 NTSTATUS
302 CUSBDevice::SetDeviceAddress(
303 UCHAR DeviceAddress)
304 {
305 PUSB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
306 NTSTATUS Status;
307 UCHAR OldAddress;
308 UCHAR Index;
309
310 DPRINT1("CUSBDevice::SetDeviceAddress Address %d\n", DeviceAddress);
311
312 CtrlSetup = (PUSB_DEFAULT_PIPE_SETUP_PACKET)ExAllocatePoolWithTag(NonPagedPool, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET), TAG_USBLIB);
313 if (!CtrlSetup)
314 return STATUS_INSUFFICIENT_RESOURCES;
315
316 // zero request
317 RtlZeroMemory(CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
318
319 // initialize request
320 CtrlSetup->bRequest = USB_REQUEST_SET_ADDRESS;
321 CtrlSetup->wValue.W = DeviceAddress;
322
323 // set device address
324 Status = CommitSetupPacket(CtrlSetup, 0, 0, 0);
325
326 // free setup packet
327 ExFreePoolWithTag(CtrlSetup, TAG_USBLIB);
328
329 // check for success
330 if (!NT_SUCCESS(Status))
331 {
332 // failed to set device address
333 DPRINT1("CUSBDevice::SetDeviceAddress> failed to set device address with %x Address %x\n", Status, DeviceAddress);
334 return Status;
335 }
336
337 // lets have a short nap
338 KeStallExecutionProcessor(300);
339
340 // back up old address
341 OldAddress = m_DeviceAddress;
342
343 // store new device address
344 m_DeviceAddress = DeviceAddress;
345
346 // fetch device descriptor
347 Status = CreateDeviceDescriptor();
348 if (!NT_SUCCESS(Status))
349 {
350 DPRINT1("CUSBbDevice::SetDeviceAddress> failed to retrieve device descriptor with device address set Error %x\n", Status);
351 // return error status
352 return Status;
353 }
354
355 // check for invalid device descriptor
356 if (m_DeviceDescriptor.bLength != sizeof(USB_DEVICE_DESCRIPTOR) ||
357 m_DeviceDescriptor.bDescriptorType != USB_DEVICE_DESCRIPTOR_TYPE ||
358 m_DeviceDescriptor.bNumConfigurations == 0)
359 {
360 // failed to retrieve device descriptor
361 DPRINT1("CUSBbDevice::SetDeviceAddress> device returned bogus device descriptor\n");
362 DumpDeviceDescriptor(&m_DeviceDescriptor);
363
364 // return error status
365 return STATUS_UNSUCCESSFUL;
366 }
367
368 // dump device descriptor
369 DumpDeviceDescriptor(&m_DeviceDescriptor);
370
371 // sanity checks
372 PC_ASSERT(m_DeviceDescriptor.bNumConfigurations);
373
374 // allocate configuration descriptor
375 m_ConfigurationDescriptors = (PUSB_CONFIGURATION) ExAllocatePoolWithTag(NonPagedPool, sizeof(USB_CONFIGURATION) * m_DeviceDescriptor.bNumConfigurations, TAG_USBLIB);
376
377 // zero configuration descriptor
378 RtlZeroMemory(m_ConfigurationDescriptors, sizeof(USB_CONFIGURATION) * m_DeviceDescriptor.bNumConfigurations);
379
380 // retrieve the configuration descriptors
381 for(Index = 0; Index < m_DeviceDescriptor.bNumConfigurations; Index++)
382 {
383 // retrieve configuration descriptors from device
384 Status = CreateConfigurationDescriptor(Index);
385 if (!NT_SUCCESS(Status))
386 {
387 DPRINT1("CUSBDevice::SetDeviceAddress> failed to retrieve configuration %lu\n", Index);
388 ASSERT(FALSE);
389 break;
390 }
391 }
392
393 //
394 // done
395 //
396 return Status;
397
398 }
399
400 //----------------------------------------------------------------------------------------
401 void
402 CUSBDevice::GetDeviceDescriptor(
403 PUSB_DEVICE_DESCRIPTOR DeviceDescriptor)
404 {
405 RtlMoveMemory(DeviceDescriptor, &m_DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
406 }
407
408 //----------------------------------------------------------------------------------------
409 UCHAR
410 CUSBDevice::GetConfigurationValue()
411 {
412 //
413 // return configuration index
414 //
415 return m_ConfigurationIndex;
416 }
417
418 //----------------------------------------------------------------------------------------
419 NTSTATUS
420 CUSBDevice::CommitIrp(
421 PIRP Irp)
422 {
423 NTSTATUS Status;
424 PUSBREQUEST Request;
425
426 if (!m_Queue || !m_DmaManager)
427 {
428 //
429 // no queue, wtf?
430 //
431 DPRINT1("CUSBDevice::CommitUrb> no queue / dma !!!\n");
432 return STATUS_UNSUCCESSFUL;
433 }
434
435 //
436 // build usb request
437 //
438 Status = m_Queue->CreateUSBRequest(&Request);
439 if (!NT_SUCCESS(Status))
440 {
441 //
442 // failed to build request
443 //
444 DPRINT1("CUSBDevice::CommitSetupPacket> CreateUSBRequest failed with %x\n", Status);
445 return Status;
446 }
447
448 //
449 // initialize request
450 //
451 Status = Request->InitializeWithIrp(m_DmaManager, PUSBDEVICE(this), Irp);
452
453 //
454 // mark irp as pending
455 //
456 IoMarkIrpPending(Irp);
457
458 //
459 // now add the request
460 //
461 Status = m_Queue->AddUSBRequest(Request);
462 if (!NT_SUCCESS(Status))
463 {
464 //
465 // failed to add request
466 //
467 DPRINT1("CUSBDevice::CommitSetupPacket> failed add request to queue with %x\n", Status);
468 Request->Release();
469 return Status;
470 }
471
472 //
473 // done
474 //
475 return STATUS_PENDING;
476 }
477
478 //----------------------------------------------------------------------------------------
479 NTSTATUS
480 CUSBDevice::SubmitIrp(
481 PIRP Irp)
482 {
483 KIRQL OldLevel;
484 NTSTATUS Status;
485
486 //
487 // acquire device lock
488 //
489 KeAcquireSpinLock(&m_Lock, &OldLevel);
490
491 //
492 // commit urb
493 //
494 Status = CommitIrp(Irp);
495
496 //
497 // release lock
498 //
499 KeReleaseSpinLock(&m_Lock, OldLevel);
500
501 return Status;
502 }
503 //----------------------------------------------------------------------------------------
504 NTSTATUS
505 CUSBDevice::CommitSetupPacket(
506 IN PUSB_DEFAULT_PIPE_SETUP_PACKET Packet,
507 IN OPTIONAL PUSB_ENDPOINT EndpointDescriptor,
508 IN ULONG BufferLength,
509 IN OUT PMDL Mdl)
510 {
511 NTSTATUS Status;
512 PUSBREQUEST Request;
513
514 if (!m_Queue)
515 {
516 //
517 // no queue, wtf?
518 //
519 DPRINT1("CUSBDevice::CommitSetupPacket> no queue!!!\n");
520 return STATUS_UNSUCCESSFUL;
521 }
522
523 //
524 // build usb request
525 //
526 Status = m_Queue->CreateUSBRequest(&Request);
527 if (!NT_SUCCESS(Status))
528 {
529 //
530 // failed to build request
531 //
532 DPRINT1("CUSBDevice::CommitSetupPacket> CreateUSBRequest failed with %x\n", Status);
533 return Status;
534 }
535
536 //
537 // initialize request
538 //
539 Status = Request->InitializeWithSetupPacket(m_DmaManager, Packet, PUSBDEVICE(this), EndpointDescriptor, BufferLength, Mdl);
540 if (!NT_SUCCESS(Status))
541 {
542 //
543 // failed to initialize request
544 //
545 DPRINT1("CUSBDevice::CommitSetupPacket> failed to initialize usb request with %x\n", Status);
546 Request->Release();
547 return Status;
548 }
549
550 //
551 // now add the request
552 //
553 Status = m_Queue->AddUSBRequest(Request);
554 if (!NT_SUCCESS(Status))
555 {
556 //
557 // failed to add request
558 //
559 DPRINT1("CUSBDevice::CommitSetupPacket> failed add request to queue with %x\n", Status);
560 Request->Release();
561 return Status;
562 }
563
564 //
565 // get the result code when the operation has been finished
566 //
567 Request->GetResultStatus(&Status, NULL);
568
569 //
570 // release request
571 //
572 Request->Release();
573
574 //
575 // done
576 //
577 return Status;
578 }
579
580 //----------------------------------------------------------------------------------------
581 NTSTATUS
582 CUSBDevice::CreateDeviceDescriptor()
583 {
584 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
585 PMDL Mdl;
586 NTSTATUS Status;
587 PVOID Buffer;
588
589 //
590 // zero descriptor
591 //
592 RtlZeroMemory(&m_DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
593 RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
594
595 //
596 // setup request
597 //
598 CtrlSetup.bRequest = USB_REQUEST_GET_DESCRIPTOR;
599 CtrlSetup.wValue.HiByte = USB_DEVICE_DESCRIPTOR_TYPE;
600 CtrlSetup.wLength = sizeof(USB_DEVICE_DESCRIPTOR);
601 CtrlSetup.bmRequestType.B = 0x80;
602
603 //
604 // allocate buffer
605 //
606 Buffer = ExAllocatePool(NonPagedPool, PAGE_SIZE);
607 if (!Buffer)
608 {
609 //
610 // failed to allocate
611 //
612 return STATUS_INSUFFICIENT_RESOURCES;
613 }
614
615 //
616 // zero buffer
617 //
618 RtlZeroMemory(Buffer, PAGE_SIZE);
619
620 //
621 // allocate mdl describing the device descriptor
622 //
623 Mdl = IoAllocateMdl(Buffer, sizeof(USB_DEVICE_DESCRIPTOR), FALSE, FALSE, 0);
624 if (!Mdl)
625 {
626 //
627 // failed to allocate mdl
628 //
629 return STATUS_INSUFFICIENT_RESOURCES;
630 }
631
632 //
633 // build mdl for non paged pool
634 //
635 MmBuildMdlForNonPagedPool(Mdl);
636
637 //
638 // commit setup packet
639 //
640 Status = CommitSetupPacket(&CtrlSetup, 0, sizeof(USB_DEVICE_DESCRIPTOR), Mdl);
641
642 //
643 // now free the mdl
644 //
645 IoFreeMdl(Mdl);
646
647 if (NT_SUCCESS(Status))
648 {
649 //
650 // copy device descriptor
651 //
652 RtlCopyMemory(&m_DeviceDescriptor, Buffer, sizeof(USB_DEVICE_DESCRIPTOR));
653 }
654
655 //
656 // free buffer
657 //
658 ExFreePool(Buffer);
659
660 //
661 // done
662 //
663 return Status;
664
665 }
666
667 //----------------------------------------------------------------------------------------
668 NTSTATUS
669 CUSBDevice::GetConfigurationDescriptor(
670 IN UCHAR ConfigurationIndex,
671 IN USHORT BufferSize,
672 IN PVOID Buffer)
673 {
674 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
675 NTSTATUS Status;
676 PMDL Mdl;
677
678
679 //
680 // now build MDL describing the buffer
681 //
682 Mdl = IoAllocateMdl(Buffer, BufferSize, FALSE, FALSE, 0);
683 if (!Mdl)
684 {
685 //
686 // failed to allocate mdl
687 //
688 return STATUS_INSUFFICIENT_RESOURCES;
689 }
690
691 //
692 // build mdl for non paged pool
693 //
694 MmBuildMdlForNonPagedPool(Mdl);
695
696
697 //
698 // build setup packet
699 //
700 CtrlSetup.bmRequestType._BM.Recipient = BMREQUEST_TO_DEVICE;
701 CtrlSetup.bmRequestType._BM.Type = BMREQUEST_STANDARD;
702 CtrlSetup.bmRequestType._BM.Reserved = 0;
703 CtrlSetup.bmRequestType._BM.Dir = BMREQUEST_DEVICE_TO_HOST;
704 CtrlSetup.bRequest = USB_REQUEST_GET_DESCRIPTOR;
705 CtrlSetup.wValue.LowByte = ConfigurationIndex;
706 CtrlSetup.wValue.HiByte = USB_CONFIGURATION_DESCRIPTOR_TYPE;
707 CtrlSetup.wIndex.W = 0;
708 CtrlSetup.wLength = BufferSize;
709
710 //
711 // commit packet
712 //
713 Status = CommitSetupPacket(&CtrlSetup, 0, BufferSize, Mdl);
714
715 //
716 // free mdl
717 //
718 IoFreeMdl(Mdl);
719
720 //
721 // done
722 //
723 return Status;
724 }
725
726 //----------------------------------------------------------------------------------------
727 NTSTATUS
728 CUSBDevice::CreateConfigurationDescriptor(
729 UCHAR Index)
730 {
731 NTSTATUS Status;
732 PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
733
734 //
735 // sanity checks
736 //
737 PC_ASSERT(m_ConfigurationDescriptors);
738
739 //
740 // first allocate a buffer which should be enough to store all different interfaces and endpoints
741 //
742 ConfigurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, TAG_USBLIB);
743 if (!ConfigurationDescriptor)
744 {
745 //
746 // failed to allocate buffer
747 //
748 return STATUS_INSUFFICIENT_RESOURCES;
749 }
750
751 //
752 // get partial configuration descriptor
753 //
754 Status = GetConfigurationDescriptor(Index, sizeof(USB_CONFIGURATION_DESCRIPTOR), ConfigurationDescriptor);
755 if (!NT_SUCCESS(Status))
756 {
757 //
758 // failed to get partial configuration descriptor
759 //
760 DPRINT1("[USBLIB] Failed to get partial configuration descriptor Status %x Index %x\n", Status, Index);
761 ExFreePoolWithTag(ConfigurationDescriptor, TAG_USBLIB);
762 return Status;
763 }
764
765 //
766 // now get full descriptor
767 //
768 Status = GetConfigurationDescriptor(Index, ConfigurationDescriptor->wTotalLength, ConfigurationDescriptor);
769 if (!NT_SUCCESS(Status))
770 {
771 //
772 // failed to get full configuration descriptor
773 //
774 DPRINT1("[USBLIB] Failed to get full configuration descriptor Status %x Index %x\n", Status, Index);
775 ExFreePoolWithTag(ConfigurationDescriptor, TAG_USBLIB);
776 return Status;
777 }
778
779 //
780 // informal debug print
781 //
782 DumpConfigurationDescriptor(ConfigurationDescriptor);
783
784 //
785 // sanity check
786 //
787 PC_ASSERT(ConfigurationDescriptor->bLength == sizeof(USB_CONFIGURATION_DESCRIPTOR));
788 PC_ASSERT(ConfigurationDescriptor->wTotalLength <= PAGE_SIZE);
789 PC_ASSERT(ConfigurationDescriptor->bNumInterfaces);
790
791 //
792 // request is complete, initialize configuration descriptor
793 //
794 m_ConfigurationDescriptors[Index].ConfigurationDescriptor = ConfigurationDescriptor;
795 InitializeListHead(&m_ConfigurationDescriptors[Index].InterfaceList);
796
797 //
798 // done
799 //
800 return Status;
801 }
802 //----------------------------------------------------------------------------------------
803 VOID
804 CUSBDevice::GetConfigurationDescriptors(
805 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptorBuffer,
806 IN ULONG BufferLength,
807 OUT PULONG OutBufferLength)
808 {
809 // sanity check
810 ASSERT(BufferLength >= sizeof(USB_CONFIGURATION_DESCRIPTOR));
811 ASSERT(ConfigDescriptorBuffer);
812 ASSERT(OutBufferLength);
813
814 // reset copied length
815 *OutBufferLength = 0;
816
817 // FIXME: support multiple configurations
818 PC_ASSERT(m_DeviceDescriptor.bNumConfigurations == 1);
819
820 // copy configuration descriptor
821 RtlCopyMemory(ConfigDescriptorBuffer, m_ConfigurationDescriptors[0].ConfigurationDescriptor, min(m_ConfigurationDescriptors[0].ConfigurationDescriptor->wTotalLength, BufferLength));
822 *OutBufferLength = m_ConfigurationDescriptors[0].ConfigurationDescriptor->wTotalLength;
823 }
824
825 //----------------------------------------------------------------------------------------
826 ULONG
827 CUSBDevice::GetConfigurationDescriptorsLength()
828 {
829 //
830 // FIXME: support multiple configurations
831 //
832 PC_ASSERT(m_DeviceDescriptor.bNumConfigurations == 1);
833
834 return m_ConfigurationDescriptors[0].ConfigurationDescriptor->wTotalLength;
835 }
836 //----------------------------------------------------------------------------------------
837 VOID
838 CUSBDevice::DumpDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor)
839 {
840 DPRINT1("Dumping Device Descriptor %x\n", DeviceDescriptor);
841 DPRINT1("bLength %x\n", DeviceDescriptor->bLength);
842 DPRINT1("bDescriptorType %x\n", DeviceDescriptor->bDescriptorType);
843 DPRINT1("bcdUSB %x\n", DeviceDescriptor->bcdUSB);
844 DPRINT1("bDeviceClass %x\n", DeviceDescriptor->bDeviceClass);
845 DPRINT1("bDeviceSubClass %x\n", DeviceDescriptor->bDeviceSubClass);
846 DPRINT1("bDeviceProtocol %x\n", DeviceDescriptor->bDeviceProtocol);
847 DPRINT1("bMaxPacketSize0 %x\n", DeviceDescriptor->bMaxPacketSize0);
848 DPRINT1("idVendor %x\n", DeviceDescriptor->idVendor);
849 DPRINT1("idProduct %x\n", DeviceDescriptor->idProduct);
850 DPRINT1("bcdDevice %x\n", DeviceDescriptor->bcdDevice);
851 DPRINT1("iManufacturer %x\n", DeviceDescriptor->iManufacturer);
852 DPRINT1("iProduct %x\n", DeviceDescriptor->iProduct);
853 DPRINT1("iSerialNumber %x\n", DeviceDescriptor->iSerialNumber);
854 DPRINT1("bNumConfigurations %x\n", DeviceDescriptor->bNumConfigurations);
855 }
856
857 //----------------------------------------------------------------------------------------
858 VOID
859 CUSBDevice::DumpConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
860 {
861 DPRINT1("Dumping ConfigurationDescriptor %x\n", ConfigurationDescriptor);
862 DPRINT1("bLength %x\n", ConfigurationDescriptor->bLength);
863 DPRINT1("bDescriptorType %x\n", ConfigurationDescriptor->bDescriptorType);
864 DPRINT1("wTotalLength %x\n", ConfigurationDescriptor->wTotalLength);
865 DPRINT1("bNumInterfaces %x\n", ConfigurationDescriptor->bNumInterfaces);
866 DPRINT1("bConfigurationValue %x\n", ConfigurationDescriptor->bConfigurationValue);
867 DPRINT1("iConfiguration %x\n", ConfigurationDescriptor->iConfiguration);
868 DPRINT1("bmAttributes %x\n", ConfigurationDescriptor->bmAttributes);
869 DPRINT1("MaxPower %x\n", ConfigurationDescriptor->MaxPower);
870 }
871 //----------------------------------------------------------------------------------------
872 NTSTATUS
873 CUSBDevice::SubmitSetupPacket(
874 IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
875 IN OUT ULONG BufferLength,
876 OUT PVOID Buffer)
877 {
878 NTSTATUS Status;
879 PMDL Mdl = NULL;
880
881 if (BufferLength)
882 {
883 //
884 // allocate mdl
885 //
886 Mdl = IoAllocateMdl(Buffer, BufferLength, FALSE, FALSE, 0);
887 if (!Mdl)
888 {
889 //
890 // no memory
891 //
892 return STATUS_INSUFFICIENT_RESOURCES;
893 }
894
895 //
896 // HACK HACK HACK: assume the buffer is build from non paged pool
897 //
898 MmBuildMdlForNonPagedPool(Mdl);
899 }
900
901 //
902 // commit setup packet
903 //
904 Status = CommitSetupPacket(SetupPacket, 0, BufferLength, Mdl);
905
906 if (Mdl != NULL)
907 {
908 //
909 // free mdl
910 //
911 IoFreeMdl(Mdl);
912 }
913
914 //
915 // done
916 //
917 return Status;
918 }
919
920 //----------------------------------------------------------------------------------------
921 NTSTATUS
922 CUSBDevice::SelectConfiguration(
923 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
924 IN PUSBD_INTERFACE_INFORMATION InterfaceInfo,
925 OUT USBD_CONFIGURATION_HANDLE *ConfigurationHandle)
926 {
927 ULONG InterfaceIndex, PipeIndex;
928 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
929 NTSTATUS Status;
930 UCHAR bConfigurationValue = 0;
931 ULONG ConfigurationIndex = 0, Index;
932 UCHAR Found = FALSE;
933 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
934 PUSB_INTERFACE UsbInterface;
935 PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
936 PLIST_ENTRY Entry;
937
938 if (ConfigurationDescriptor)
939 {
940 // find configuration index
941 for(Index = 0; Index < m_DeviceDescriptor.bNumConfigurations; Index++)
942 {
943 if (m_ConfigurationDescriptors[Index].ConfigurationDescriptor->bConfigurationValue == ConfigurationDescriptor->bConfigurationValue)
944 {
945 // found configuration index
946 ConfigurationIndex = Index;
947 Found = TRUE;
948 }
949 }
950
951 if (!Found)
952 {
953 DPRINT1("[USBUHCI] invalid configuration value %lu\n", ConfigurationDescriptor->bConfigurationValue);
954 return STATUS_INVALID_PARAMETER;
955 }
956
957 // sanity check
958 ASSERT(ConfigurationDescriptor->bNumInterfaces <= m_ConfigurationDescriptors[ConfigurationIndex].ConfigurationDescriptor->bNumInterfaces);
959
960 // get configuration value
961 bConfigurationValue = ConfigurationDescriptor->bConfigurationValue;
962 }
963
964 // now build setup packet
965 RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
966 CtrlSetup.bRequest = USB_REQUEST_SET_CONFIGURATION;
967 CtrlSetup.wValue.W = bConfigurationValue;
968
969 // select configuration
970 Status = CommitSetupPacket(&CtrlSetup, 0, 0, 0);
971
972 if (!ConfigurationDescriptor)
973 {
974 // unconfigure request
975 DPRINT1("CUsbDevice::SelectConfiguration Unconfigure Request Status %x\n", Status);
976 m_ConfigurationIndex = 0;
977 return Status;
978 }
979
980 // informal debug print
981 DPRINT1("CUsbDevice::SelectConfiguration New Configuration %x Old Configuration %x Result %x\n", ConfigurationIndex, m_ConfigurationIndex, Status);
982 if (!NT_SUCCESS(Status))
983 {
984 //
985 // failed
986 //
987 return Status;
988 }
989
990 // destroy old interface info
991 while(!IsListEmpty(&m_ConfigurationDescriptors[m_ConfigurationIndex].InterfaceList))
992 {
993 // remove entry
994 Entry = RemoveHeadList(&m_ConfigurationDescriptors[m_ConfigurationIndex].InterfaceList);
995
996 // get interface info
997 UsbInterface = (PUSB_INTERFACE)CONTAINING_RECORD(Entry, USB_INTERFACE, ListEntry);
998
999 // free interface info
1000 ExFreePool(UsbInterface);
1001 }
1002
1003 // sanity check
1004 ASSERT(IsListEmpty(&m_ConfigurationDescriptors[ConfigurationIndex].InterfaceList));
1005
1006 // store new configuration device index
1007 m_ConfigurationIndex = ConfigurationIndex;
1008
1009 // store configuration handle
1010 *ConfigurationHandle = &m_ConfigurationDescriptors[ConfigurationIndex];
1011
1012 // copy interface info and pipe info
1013 for(InterfaceIndex = 0; InterfaceIndex < ConfigurationDescriptor->bNumInterfaces; InterfaceIndex++)
1014 {
1015 // interface info checks
1016 ASSERT(InterfaceInfo->Length != 0);
1017
1018 #ifdef _MSC_VER
1019 PC_ASSERT(InterfaceInfo->Length == FIELD_OFFSET(USBD_INTERFACE_INFORMATION, Pipes[InterfaceInfo->NumberOfPipes]));
1020 #endif
1021
1022 // find interface descriptor
1023 InterfaceDescriptor = USBD_ParseConfigurationDescriptor(m_ConfigurationDescriptors[ConfigurationIndex].ConfigurationDescriptor, InterfaceInfo->InterfaceNumber, InterfaceInfo->AlternateSetting);
1024
1025 // sanity checks
1026 ASSERT(InterfaceDescriptor != NULL);
1027
1028 // check if the number of pipes have been properly set
1029 ASSERT(InterfaceInfo->NumberOfPipes == InterfaceDescriptor->bNumEndpoints);
1030
1031 // copy interface info
1032 InterfaceInfo->Class = InterfaceDescriptor->bInterfaceClass;
1033 InterfaceInfo->SubClass = InterfaceDescriptor->bInterfaceSubClass;
1034 InterfaceInfo->Protocol = InterfaceDescriptor->bInterfaceProtocol;
1035 InterfaceInfo->Reserved = 0;
1036
1037 // allocate interface handle
1038 UsbInterface = (PUSB_INTERFACE)ExAllocatePool(NonPagedPool, sizeof(USB_INTERFACE) + (InterfaceInfo->NumberOfPipes - 1) * sizeof(USB_ENDPOINT));
1039 if (!UsbInterface)
1040 {
1041 // failed to allocate memory
1042 return STATUS_INSUFFICIENT_RESOURCES;
1043 }
1044
1045 // store handle
1046 InterfaceInfo->InterfaceHandle = (USBD_INTERFACE_HANDLE)UsbInterface;
1047
1048 // init interface handle
1049 UsbInterface->InterfaceDescriptor = InterfaceDescriptor;
1050 InsertTailList(&m_ConfigurationDescriptors[ConfigurationIndex].InterfaceList, &UsbInterface->ListEntry);
1051
1052 // grab first endpoint descriptor
1053 EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR) (InterfaceDescriptor + 1);
1054
1055 // now copy all endpoint information
1056 for(PipeIndex = 0; PipeIndex < InterfaceInfo->NumberOfPipes; PipeIndex++)
1057 {
1058 while(EndpointDescriptor->bDescriptorType != USB_ENDPOINT_DESCRIPTOR_TYPE && EndpointDescriptor->bLength != sizeof(USB_ENDPOINT_DESCRIPTOR))
1059 {
1060 // skip intermediate descriptors
1061 if (EndpointDescriptor->bLength == 0 || EndpointDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
1062 {
1063 // bogus configuration descriptor
1064 DPRINT1("[USBEHCI] Bogus descriptor found in InterfaceNumber %x Alternate %x EndpointIndex %x bLength %x bDescriptorType %x\n", InterfaceDescriptor->bInterfaceNumber, InterfaceDescriptor->bAlternateSetting, PipeIndex,
1065 EndpointDescriptor->bLength, EndpointDescriptor->bDescriptorType);
1066
1067 // failed
1068 return STATUS_UNSUCCESSFUL;
1069 }
1070
1071 // move to next descriptor
1072 EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)EndpointDescriptor + EndpointDescriptor->bLength);
1073 }
1074
1075 // store in interface info
1076 RtlCopyMemory(&UsbInterface->EndPoints[PipeIndex].EndPointDescriptor, EndpointDescriptor, sizeof(USB_ENDPOINT_DESCRIPTOR));
1077
1078 // copy pipe info
1079 InterfaceInfo->Pipes[PipeIndex].MaximumPacketSize = UsbInterface->EndPoints[PipeIndex].EndPointDescriptor.wMaxPacketSize;
1080 InterfaceInfo->Pipes[PipeIndex].EndpointAddress = UsbInterface->EndPoints[PipeIndex].EndPointDescriptor.bEndpointAddress;
1081 InterfaceInfo->Pipes[PipeIndex].Interval = UsbInterface->EndPoints[PipeIndex].EndPointDescriptor.bInterval;
1082 InterfaceInfo->Pipes[PipeIndex].PipeType = (USBD_PIPE_TYPE)UsbInterface->EndPoints[PipeIndex].EndPointDescriptor.bmAttributes;
1083 InterfaceInfo->Pipes[PipeIndex].PipeHandle = (PVOID)&UsbInterface->EndPoints[PipeIndex];
1084
1085 // move to next descriptor
1086 EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)EndpointDescriptor + EndpointDescriptor->bLength);
1087 }
1088
1089 // move offset
1090 InterfaceInfo = (PUSBD_INTERFACE_INFORMATION)((ULONG_PTR)PtrToUlong(InterfaceInfo) + InterfaceInfo->Length);
1091 }
1092
1093 //
1094 // done
1095 //
1096 return Status;
1097 }
1098
1099 //----------------------------------------------------------------------------------------
1100 NTSTATUS
1101 CUSBDevice::SelectInterface(
1102 IN USBD_CONFIGURATION_HANDLE ConfigurationHandle,
1103 IN OUT PUSBD_INTERFACE_INFORMATION InterfaceInfo)
1104 {
1105 ULONG PipeIndex;
1106 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
1107 NTSTATUS Status;
1108 ULONG Index, ConfigurationIndex = 0, Found = FALSE;
1109 PUSB_INTERFACE UsbInterface;
1110 PLIST_ENTRY Entry;
1111
1112 // check if handle is valid
1113 for(Index = 0; Index < m_DeviceDescriptor.bNumConfigurations; Index++)
1114 {
1115 if (&m_ConfigurationDescriptors[Index] == ConfigurationHandle)
1116 {
1117 // found configuration index
1118 ConfigurationIndex = Index;
1119 Found = TRUE;
1120 }
1121 }
1122
1123 if (!Found)
1124 {
1125 // invalid handle passed
1126 DPRINT1("[USBEHCI] Invalid configuration handle passed %p\n", ConfigurationHandle);
1127 return STATUS_INVALID_PARAMETER;
1128 }
1129
1130 // initialize setup packet
1131 RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1132 CtrlSetup.bRequest = USB_REQUEST_SET_INTERFACE;
1133 CtrlSetup.wValue.W = InterfaceInfo->AlternateSetting;
1134 CtrlSetup.wIndex.W = InterfaceInfo->InterfaceNumber;
1135 CtrlSetup.bmRequestType.B = 0x01;
1136
1137 // issue request
1138 Status = CommitSetupPacket(&CtrlSetup, 0, 0, 0);
1139
1140 // informal debug print
1141 DPRINT1("CUSBDevice::SelectInterface AlternateSetting %x InterfaceNumber %x Status %x\n", InterfaceInfo->AlternateSetting, InterfaceInfo->InterfaceNumber, Status);
1142 #if 0
1143 if (!NT_SUCCESS(Status))
1144 {
1145 // failed to select interface
1146 return Status;
1147 }
1148 #endif
1149
1150 Status = STATUS_SUCCESS;
1151
1152
1153 // find interface
1154 Found = FALSE;
1155 Entry = m_ConfigurationDescriptors[ConfigurationIndex].InterfaceList.Flink;
1156 while(Entry != &m_ConfigurationDescriptors[ConfigurationIndex].InterfaceList)
1157 {
1158 // grab interface descriptor
1159 UsbInterface = (PUSB_INTERFACE)CONTAINING_RECORD(Entry, USB_INTERFACE, ListEntry);
1160 if (UsbInterface->InterfaceDescriptor->bAlternateSetting == InterfaceInfo->AlternateSetting &&
1161 UsbInterface->InterfaceDescriptor->bInterfaceNumber == InterfaceInfo->InterfaceNumber)
1162 {
1163 // found interface
1164 Found = TRUE;
1165 break;
1166 }
1167 }
1168
1169 if (!Found)
1170 {
1171 // selected interface but interface not found
1172 // something is really wrong
1173 DPRINT1("[USBEHCI] Error: interface not found!!!\n");
1174 return STATUS_UNSUCCESSFUL;
1175 }
1176
1177 // assert on pipe length mismatch
1178 ASSERT(InterfaceInfo->NumberOfPipes == UsbInterface->InterfaceDescriptor->bNumEndpoints);
1179
1180 // copy pipe handles
1181 for(PipeIndex = 0; PipeIndex < min(InterfaceInfo->NumberOfPipes, UsbInterface->InterfaceDescriptor->bNumEndpoints); PipeIndex++)
1182 {
1183 // copy pipe handle
1184 DPRINT1("PipeIndex %lu\n", PipeIndex);
1185 DPRINT1("EndpointAddress %x\n", InterfaceInfo->Pipes[PipeIndex].EndpointAddress);
1186 DPRINT1("Interval %d\n", InterfaceInfo->Pipes[PipeIndex].Interval);
1187 DPRINT1("MaximumPacketSize %d\n", InterfaceInfo->Pipes[PipeIndex].MaximumPacketSize);
1188 DPRINT1("MaximumTransferSize %d\n", InterfaceInfo->Pipes[PipeIndex].MaximumTransferSize);
1189 DPRINT1("PipeFlags %d\n", InterfaceInfo->Pipes[PipeIndex].PipeFlags);
1190 DPRINT1("PipeType %dd\n", InterfaceInfo->Pipes[PipeIndex].PipeType);
1191 DPRINT1("UsbEndPoint %x\n", InterfaceInfo->Pipes[PipeIndex].EndpointAddress);
1192
1193 // sanity checks
1194 ASSERT(InterfaceInfo->Pipes[PipeIndex].EndpointAddress == UsbInterface->EndPoints[PipeIndex].EndPointDescriptor.bEndpointAddress);
1195 ASSERT(InterfaceInfo->Pipes[PipeIndex].Interval == UsbInterface->EndPoints[PipeIndex].EndPointDescriptor.bInterval);
1196
1197 // store pipe handle
1198 InterfaceInfo->Pipes[PipeIndex].PipeHandle = &UsbInterface->EndPoints[PipeIndex];
1199
1200 // data toggle is reset on select interface requests
1201 UsbInterface->EndPoints[PipeIndex].DataToggle = FALSE;
1202 }
1203
1204
1205 //
1206 // done
1207 //
1208 return Status;
1209 }
1210
1211 NTSTATUS
1212 CUSBDevice::AbortPipe(
1213 IN PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor)
1214 {
1215 //
1216 // let it handle usb queue
1217 //
1218 ASSERT(m_Queue);
1219 ASSERT(m_DeviceAddress);
1220
1221 //
1222 // done
1223 //
1224 return m_Queue->AbortDevicePipe(m_DeviceAddress, EndpointDescriptor);
1225 }
1226
1227 UCHAR
1228 CUSBDevice::GetMaxPacketSize()
1229 {
1230 return m_DeviceDescriptor.bMaxPacketSize0;
1231 }
1232
1233
1234 //----------------------------------------------------------------------------------------
1235 NTSTATUS
1236 NTAPI
1237 CreateUSBDevice(
1238 PUSBDEVICE *OutDevice)
1239 {
1240 CUSBDevice * This;
1241
1242 //
1243 // allocate controller
1244 //
1245 This = new(NonPagedPool, TAG_USBLIB) CUSBDevice(0);
1246 if (!This)
1247 {
1248 //
1249 // failed to allocate
1250 //
1251 return STATUS_INSUFFICIENT_RESOURCES;
1252 }
1253
1254 //
1255 // add reference count
1256 //
1257 This->AddRef();
1258
1259 //
1260 // return result
1261 //
1262 *OutDevice = (PUSBDEVICE)This;
1263
1264 //
1265 // done
1266 //
1267 return STATUS_SUCCESS;
1268 }
1269