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