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