7ef98b818a6b9053b7bcd735ae4ce0aa81f557a4
[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 KeAcquireSpinLock(&m_Lock, &OldLevel);
523
524 //
525 // commit urb
526 //
527 Status = CommitIrp(Irp);
528
529 //
530 // release lock
531 //
532 KeReleaseSpinLock(&m_Lock, OldLevel);
533
534 return Status;
535 }
536 //----------------------------------------------------------------------------------------
537 NTSTATUS
538 CUSBDevice::CommitSetupPacket(
539 IN PUSB_DEFAULT_PIPE_SETUP_PACKET Packet,
540 IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor,
541 IN ULONG BufferLength,
542 IN OUT PMDL Mdl)
543 {
544 NTSTATUS Status;
545 PUSBREQUEST Request;
546
547 if (!m_Queue)
548 {
549 //
550 // no queue, wtf?
551 //
552 DPRINT1("CUSBDevice::CommitSetupPacket> no queue!!!\n");
553 return STATUS_UNSUCCESSFUL;
554 }
555
556 //
557 // build usb request
558 //
559 Status = m_Queue->CreateUSBRequest(&Request);
560 if (!NT_SUCCESS(Status))
561 {
562 //
563 // failed to build request
564 //
565 DPRINT1("CUSBDevice::CommitSetupPacket> CreateUSBRequest failed with %x\n", Status);
566 return Status;
567 }
568
569 //
570 // initialize request
571 //
572 Status = Request->InitializeWithSetupPacket(m_DmaManager, Packet, m_DeviceAddress, EndpointDescriptor, BufferLength, Mdl);
573 if (!NT_SUCCESS(Status))
574 {
575 //
576 // failed to initialize request
577 //
578 DPRINT1("CUSBDevice::CommitSetupPacket> failed to initialize usb request with %x\n", Status);
579 Request->Release();
580 return Status;
581 }
582
583 //
584 // now add the request
585 //
586 Status = m_Queue->AddUSBRequest(Request);
587 if (!NT_SUCCESS(Status))
588 {
589 //
590 // failed to add request
591 //
592 DPRINT1("CUSBDevice::CommitSetupPacket> failed add request to queue with %x\n", Status);
593 Request->Release();
594 return Status;
595 }
596
597 //
598 // get the result code when the operation has been finished
599 //
600 Request->GetResultStatus(&Status, NULL);
601
602 //
603 // release request
604 //
605 Request->Release();
606
607 //
608 // done
609 //
610 return Status;
611 }
612
613 //----------------------------------------------------------------------------------------
614 NTSTATUS
615 CUSBDevice::CreateDeviceDescriptor()
616 {
617 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
618 PMDL Mdl;
619 NTSTATUS Status;
620
621 //
622 // zero descriptor
623 //
624 RtlZeroMemory(&m_DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
625 RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
626
627 //
628 // setup request
629 //
630 CtrlSetup.bRequest = USB_REQUEST_GET_DESCRIPTOR;
631 CtrlSetup.wValue.HiByte = USB_DEVICE_DESCRIPTOR_TYPE;
632 CtrlSetup.wLength = sizeof(USB_DEVICE_DESCRIPTOR);
633 CtrlSetup.bmRequestType.B = 0x80;
634
635 //
636 // allocate mdl describing the device descriptor
637 //
638 Mdl = IoAllocateMdl(&m_DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR), FALSE, FALSE, 0);
639 if (!Mdl)
640 {
641 //
642 // failed to allocate mdl
643 //
644 return STATUS_INSUFFICIENT_RESOURCES;
645 }
646
647 //
648 // build mdl for non paged pool
649 //
650 MmBuildMdlForNonPagedPool(Mdl);
651
652 //
653 // commit setup packet
654 //
655 Status = CommitSetupPacket(&CtrlSetup, 0, sizeof(USB_DEVICE_DESCRIPTOR), Mdl);
656
657 //
658 // now free the mdl
659 //
660 IoFreeMdl(Mdl);
661
662 if (NT_SUCCESS(Status))
663 {
664 //
665 // informal dbg print
666 //
667 DumpDeviceDescriptor(&m_DeviceDescriptor);
668 }
669
670 //
671 // done
672 //
673 return Status;
674
675 }
676
677 //----------------------------------------------------------------------------------------
678 NTSTATUS
679 CUSBDevice::CreateConfigurationDescriptor(
680 ULONG Index)
681 {
682 PVOID Buffer;
683 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
684 NTSTATUS Status;
685 PMDL Mdl;
686 ULONG InterfaceIndex, EndPointIndex;
687 PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
688 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
689 PUSB_ENDPOINT_DESCRIPTOR EndPointDescriptor;
690
691
692 //
693 // sanity checks
694 //
695 PC_ASSERT(m_ConfigurationDescriptors);
696
697 //
698 // first allocate a buffer which should be enough to store all different interfaces and endpoints
699 //
700 Buffer = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, TAG_USBEHCI);
701 if (!Buffer)
702 {
703 //
704 // failed to allocate buffer
705 //
706 return STATUS_INSUFFICIENT_RESOURCES;
707 }
708
709 //
710 // build setup packet
711 //
712 CtrlSetup.bmRequestType._BM.Recipient = BMREQUEST_TO_DEVICE;
713 CtrlSetup.bmRequestType._BM.Type = BMREQUEST_STANDARD;
714 CtrlSetup.bmRequestType._BM.Reserved = 0;
715 CtrlSetup.bmRequestType._BM.Dir = BMREQUEST_DEVICE_TO_HOST;
716 CtrlSetup.bRequest = USB_REQUEST_GET_DESCRIPTOR;
717 CtrlSetup.wValue.LowByte = 0;
718 CtrlSetup.wValue.HiByte = USB_CONFIGURATION_DESCRIPTOR_TYPE;
719 CtrlSetup.wIndex.W = 0;
720 CtrlSetup.wLength = PAGE_SIZE;
721
722 //
723 // FIXME: where put configuration index?
724 //
725
726 //
727 // now build MDL describing the buffer
728 //
729 Mdl = IoAllocateMdl(Buffer, PAGE_SIZE, FALSE, FALSE, 0);
730 if (!Mdl)
731 {
732 //
733 // failed to allocate mdl
734 //
735 ExFreePoolWithTag(Buffer, TAG_USBEHCI);
736 return STATUS_INSUFFICIENT_RESOURCES;
737 }
738
739 //
740 // build mdl for non paged pool
741 //
742 MmBuildMdlForNonPagedPool(Mdl);
743
744 //
745 // commit packet
746 //
747 Status = CommitSetupPacket(&CtrlSetup, 0, PAGE_SIZE, Mdl);
748 if (!NT_SUCCESS(Status))
749 {
750 //
751 // failed to issue request, cleanup
752 //
753 IoFreeMdl(Mdl);
754 ExFreePool(Buffer);
755 return Status;
756 }
757
758 //
759 // now free the mdl
760 //
761 IoFreeMdl(Mdl);
762
763 //
764 // get configuration descriptor
765 //
766 ConfigurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)Buffer;
767
768 //
769 // informal debug print
770 //
771 DumpConfigurationDescriptor(ConfigurationDescriptor);
772
773 //
774 // sanity check
775 //
776 PC_ASSERT(ConfigurationDescriptor->bLength == sizeof(USB_CONFIGURATION_DESCRIPTOR));
777 PC_ASSERT(ConfigurationDescriptor->wTotalLength <= PAGE_SIZE);
778 PC_ASSERT(ConfigurationDescriptor->bNumInterfaces);
779
780 //
781 // request is complete, initialize configuration descriptor
782 //
783 RtlCopyMemory(&m_ConfigurationDescriptors[Index].ConfigurationDescriptor, ConfigurationDescriptor, ConfigurationDescriptor->bLength);
784
785 //
786 // now allocate interface descriptors
787 //
788 m_ConfigurationDescriptors[Index].Interfaces = (PUSB_INTERFACE)ExAllocatePoolWithTag(NonPagedPool, sizeof(USB_INTERFACE) * ConfigurationDescriptor->bNumInterfaces, TAG_USBEHCI);
789 if (!m_ConfigurationDescriptors[Index].Interfaces)
790 {
791 //
792 // failed to allocate interface descriptors
793 //
794 ExFreePool(Buffer);
795 return STATUS_INSUFFICIENT_RESOURCES;
796 }
797
798 //
799 // zero interface descriptor
800 //
801 RtlZeroMemory(m_ConfigurationDescriptors[Index].Interfaces, sizeof(USB_INTERFACE) * ConfigurationDescriptor->bNumInterfaces);
802
803 //
804 // get first interface descriptor
805 //
806 InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)(ConfigurationDescriptor + 1);
807
808 //
809 // setup interface descriptors
810 //
811 for(InterfaceIndex = 0; InterfaceIndex < ConfigurationDescriptor->bNumInterfaces; InterfaceIndex++)
812 {
813 //
814 // sanity check
815 //
816 PC_ASSERT(InterfaceDescriptor->bLength == sizeof(USB_INTERFACE_DESCRIPTOR));
817 PC_ASSERT(InterfaceDescriptor->bNumEndpoints);
818
819 //
820 // copy current interface descriptor
821 //
822 RtlCopyMemory(&m_ConfigurationDescriptors[Index].Interfaces[InterfaceIndex].InterfaceDescriptor, InterfaceDescriptor, InterfaceDescriptor->bLength);
823
824 //
825 // allocate end point descriptors
826 //
827 m_ConfigurationDescriptors[Index].Interfaces[InterfaceIndex].EndPoints = (PUSB_ENDPOINT)ExAllocatePoolWithTag(NonPagedPool, sizeof(USB_ENDPOINT) * InterfaceDescriptor->bNumEndpoints, TAG_USBEHCI);
828 if (!m_ConfigurationDescriptors[Index].Interfaces[InterfaceIndex].EndPoints)
829 {
830 //
831 // failed to allocate endpoint
832 //
833 Status = STATUS_INSUFFICIENT_RESOURCES;
834 break;
835 }
836
837 //
838 // zero memory
839 //
840 RtlZeroMemory(m_ConfigurationDescriptors[Index].Interfaces[InterfaceIndex].EndPoints, sizeof(USB_ENDPOINT) * InterfaceDescriptor->bNumEndpoints);
841
842 //
843 // initialize end point descriptors
844 //
845 EndPointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)(InterfaceDescriptor + 1);
846
847 for(EndPointIndex = 0; EndPointIndex < InterfaceDescriptor->bNumEndpoints; EndPointIndex++)
848 {
849 //
850 // sanity check
851 //
852 PC_ASSERT(EndPointDescriptor->bLength == sizeof(USB_ENDPOINT_DESCRIPTOR));
853
854 //
855 // copy endpoint descriptor
856 //
857 RtlCopyMemory(&m_ConfigurationDescriptors[Index].Interfaces[InterfaceIndex].EndPoints[EndPointIndex].EndPointDescriptor, EndPointDescriptor, EndPointDescriptor->bLength);
858
859 //
860 // move to next offset
861 //
862 EndPointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)((ULONG_PTR)EndPointDescriptor + EndPointDescriptor->bLength);
863 }
864
865 //
866 // update interface descriptor offset
867 //
868 InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)EndPointDescriptor;
869 }
870
871 //
872 // free buffer
873 //
874 ExFreePoolWithTag(Buffer, TAG_USBEHCI);
875
876 //
877 // done
878 //
879 return Status;
880 }
881 //----------------------------------------------------------------------------------------
882 VOID
883 CUSBDevice::GetConfigurationDescriptors(
884 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptorBuffer,
885 IN ULONG BufferLength,
886 OUT PULONG OutBufferLength)
887 {
888 PVOID Buffer;
889 ULONG InterfaceIndex, EndpointIndex;
890
891 //
892 // sanity check
893 //
894 PC_ASSERT(BufferLength >= sizeof(USB_CONFIGURATION_DESCRIPTOR));
895 PC_ASSERT(ConfigDescriptorBuffer);
896 PC_ASSERT(OutBufferLength);
897
898 //
899 // reset copied length
900 //
901 *OutBufferLength = 0;
902
903 //
904 // FIXME: support multiple configurations
905 //
906 PC_ASSERT(m_DeviceDescriptor.bNumConfigurations == 1);
907
908 //
909 // copy first configuration descriptor
910 //
911 RtlCopyMemory(ConfigDescriptorBuffer, &m_ConfigurationDescriptors[0].ConfigurationDescriptor, sizeof(USB_CONFIGURATION_DESCRIPTOR));
912
913 //
914 // subtract length
915 //
916 BufferLength -= sizeof(USB_CONFIGURATION_DESCRIPTOR);
917 *OutBufferLength += sizeof(USB_CONFIGURATION_DESCRIPTOR);
918
919 //
920 // increment offset
921 //
922 Buffer = (PVOID)(ConfigDescriptorBuffer + 1);
923
924 for(InterfaceIndex = 0; InterfaceIndex < m_ConfigurationDescriptors[0].ConfigurationDescriptor.bNumInterfaces; InterfaceIndex++)
925 {
926 if (BufferLength < sizeof(USB_INTERFACE_DESCRIPTOR))
927 {
928 //
929 // no more room in buffer
930 //
931 return;
932 }
933
934 //
935 // copy interface descriptor
936 //
937 RtlCopyMemory(Buffer, &m_ConfigurationDescriptors[0].Interfaces[InterfaceIndex].InterfaceDescriptor, sizeof(USB_INTERFACE_DESCRIPTOR));
938
939 //
940 // increment offset
941 //
942 Buffer = (PVOID)((ULONG_PTR)Buffer + sizeof(USB_INTERFACE_DESCRIPTOR));
943 BufferLength -= sizeof(USB_INTERFACE_DESCRIPTOR);
944 *OutBufferLength += sizeof(USB_INTERFACE_DESCRIPTOR);
945
946 //
947 // does the interface have endpoints
948 //
949 if (m_ConfigurationDescriptors[0].Interfaces[InterfaceIndex].InterfaceDescriptor.bNumEndpoints)
950 {
951 //
952 // is enough space available
953 //
954 if (BufferLength < sizeof(USB_ENDPOINT_DESCRIPTOR) * m_ConfigurationDescriptors[0].Interfaces[InterfaceIndex].InterfaceDescriptor.bNumEndpoints)
955 {
956 //
957 // no buffer
958 //
959 return;
960 }
961
962 //
963 // copy end points
964 //
965 for(EndpointIndex = 0; EndpointIndex < m_ConfigurationDescriptors[0].Interfaces[InterfaceIndex].InterfaceDescriptor.bNumEndpoints; EndpointIndex++)
966 {
967 //
968 // copy endpoint
969 //
970 RtlCopyMemory(Buffer, &m_ConfigurationDescriptors[0].Interfaces[InterfaceIndex].EndPoints[EndpointIndex].EndPointDescriptor, sizeof(USB_ENDPOINT_DESCRIPTOR));
971
972 //
973 // increment buffer offset
974 //
975 Buffer = (PVOID)((ULONG_PTR)Buffer + sizeof(USB_ENDPOINT_DESCRIPTOR));
976 BufferLength -= sizeof(USB_ENDPOINT_DESCRIPTOR);
977 *OutBufferLength += sizeof(USB_ENDPOINT_DESCRIPTOR);
978 }
979 }
980 }
981 }
982
983 //----------------------------------------------------------------------------------------
984 ULONG
985 CUSBDevice::GetConfigurationDescriptorsLength()
986 {
987 //
988 // FIXME: support multiple configurations
989 //
990 PC_ASSERT(m_DeviceDescriptor.bNumConfigurations == 1);
991
992 return m_ConfigurationDescriptors[0].ConfigurationDescriptor.wTotalLength;
993 }
994 //----------------------------------------------------------------------------------------
995 VOID
996 CUSBDevice::DumpDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor)
997 {
998 DPRINT1("Dumping Device Descriptor %x\n", DeviceDescriptor);
999 DPRINT1("bLength %x\n", DeviceDescriptor->bLength);
1000 DPRINT1("bDescriptorType %x\n", DeviceDescriptor->bDescriptorType);
1001 DPRINT1("bcdUSB %x\n", DeviceDescriptor->bcdUSB);
1002 DPRINT1("bDeviceClass %x\n", DeviceDescriptor->bDeviceClass);
1003 DPRINT1("bDeviceSubClass %x\n", DeviceDescriptor->bDeviceSubClass);
1004 DPRINT1("bDeviceProtocol %x\n", DeviceDescriptor->bDeviceProtocol);
1005 DPRINT1("bMaxPacketSize0 %x\n", DeviceDescriptor->bMaxPacketSize0);
1006 DPRINT1("idVendor %x\n", DeviceDescriptor->idVendor);
1007 DPRINT1("idProduct %x\n", DeviceDescriptor->idProduct);
1008 DPRINT1("bcdDevice %x\n", DeviceDescriptor->bcdDevice);
1009 DPRINT1("iManufacturer %x\n", DeviceDescriptor->iManufacturer);
1010 DPRINT1("iProduct %x\n", DeviceDescriptor->iProduct);
1011 DPRINT1("iSerialNumber %x\n", DeviceDescriptor->iSerialNumber);
1012 DPRINT1("bNumConfigurations %x\n", DeviceDescriptor->bNumConfigurations);
1013 }
1014
1015 //----------------------------------------------------------------------------------------
1016 VOID
1017 CUSBDevice::DumpConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
1018 {
1019 DPRINT1("Dumping ConfigurationDescriptor %x\n", ConfigurationDescriptor);
1020 DPRINT1("bLength %x\n", ConfigurationDescriptor->bLength);
1021 DPRINT1("bDescriptorType %x\n", ConfigurationDescriptor->bDescriptorType);
1022 DPRINT1("wTotalLength %x\n", ConfigurationDescriptor->wTotalLength);
1023 DPRINT1("bNumInterfaces %x\n", ConfigurationDescriptor->bNumInterfaces);
1024 DPRINT1("bConfigurationValue %x\n", ConfigurationDescriptor->bConfigurationValue);
1025 DPRINT1("iConfiguration %x\n", ConfigurationDescriptor->iConfiguration);
1026 DPRINT1("bmAttributes %x\n", ConfigurationDescriptor->bmAttributes);
1027 DPRINT1("MaxPower %x\n", ConfigurationDescriptor->MaxPower);
1028 }
1029 //----------------------------------------------------------------------------------------
1030 NTSTATUS
1031 CUSBDevice::SubmitSetupPacket(
1032 IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
1033 IN OUT ULONG BufferLength,
1034 OUT PVOID Buffer)
1035 {
1036 NTSTATUS Status;
1037 PMDL Mdl;
1038
1039 //
1040 // allocate mdl
1041 //
1042 Mdl = IoAllocateMdl(Buffer, BufferLength, FALSE, FALSE, 0);
1043
1044 //
1045 // HACK HACK HACK: assume the buffer is build from non paged pool
1046 //
1047 MmBuildMdlForNonPagedPool(Mdl);
1048
1049 //
1050 // commit setup packet
1051 //
1052 Status = CommitSetupPacket(SetupPacket, 0, BufferLength, Mdl);
1053
1054 //
1055 // free mdl
1056 //
1057 IoFreeMdl(Mdl);
1058
1059 //
1060 // done
1061 //
1062 return Status;
1063 }
1064
1065 //----------------------------------------------------------------------------------------
1066 NTSTATUS
1067 CUSBDevice::SelectConfiguration(
1068 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
1069 IN PUSBD_INTERFACE_INFORMATION InterfaceInfo,
1070 OUT USBD_CONFIGURATION_HANDLE *ConfigurationHandle)
1071 {
1072 ULONG ConfigurationIndex = 0;
1073 ULONG InterfaceIndex, PipeIndex;
1074 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
1075 NTSTATUS Status;
1076
1077 //
1078 // FIXME: support multiple configurations
1079 //
1080 PC_ASSERT(m_DeviceDescriptor.bNumConfigurations == 1);
1081 PC_ASSERT(ConfigurationDescriptor->iConfiguration == m_ConfigurationDescriptors[ConfigurationIndex].ConfigurationDescriptor.iConfiguration);
1082
1083 //
1084 // sanity check
1085 //
1086 PC_ASSERT(ConfigurationDescriptor->bNumInterfaces <= m_ConfigurationDescriptors[ConfigurationIndex].ConfigurationDescriptor.bNumInterfaces);
1087
1088 //
1089 // copy interface info and pipe info
1090 //
1091 for(InterfaceIndex = 0; InterfaceIndex < ConfigurationDescriptor->bNumInterfaces; InterfaceIndex++)
1092 {
1093 //
1094 // sanity check: is the info pre-layed out
1095 //
1096 PC_ASSERT(InterfaceInfo->NumberOfPipes == m_ConfigurationDescriptors[ConfigurationIndex].Interfaces[InterfaceIndex].InterfaceDescriptor.bNumEndpoints);
1097 PC_ASSERT(InterfaceInfo->Length != 0);
1098 #ifdef _MSC_VER
1099 PC_ASSERT(InterfaceInfo->Length == FIELD_OFFSET(USBD_INTERFACE_INFORMATION, Pipes[InterfaceInfo->NumberOfPipes]));
1100 #endif
1101
1102 //
1103 // copy interface info
1104 //
1105 InterfaceInfo->InterfaceHandle = (USBD_INTERFACE_HANDLE)&m_ConfigurationDescriptors[ConfigurationIndex].Interfaces[InterfaceIndex];
1106 InterfaceInfo->Class = m_ConfigurationDescriptors[ConfigurationIndex].Interfaces[InterfaceIndex].InterfaceDescriptor.bInterfaceClass;
1107 InterfaceInfo->SubClass = m_ConfigurationDescriptors[ConfigurationIndex].Interfaces[InterfaceIndex].InterfaceDescriptor.bInterfaceSubClass;
1108 InterfaceInfo->Protocol = m_ConfigurationDescriptors[ConfigurationIndex].Interfaces[InterfaceIndex].InterfaceDescriptor.bInterfaceProtocol;
1109 InterfaceInfo->Reserved = 0;
1110
1111 //
1112 // copy endpoint info
1113 //
1114 for(PipeIndex = 0; PipeIndex < InterfaceInfo->NumberOfPipes; PipeIndex++)
1115 {
1116 //
1117 // copy pipe info
1118 //
1119 InterfaceInfo->Pipes[PipeIndex].MaximumPacketSize = m_ConfigurationDescriptors[ConfigurationIndex].Interfaces[InterfaceIndex].EndPoints[PipeIndex].EndPointDescriptor.wMaxPacketSize;
1120 InterfaceInfo->Pipes[PipeIndex].EndpointAddress = m_ConfigurationDescriptors[ConfigurationIndex].Interfaces[InterfaceIndex].EndPoints[PipeIndex].EndPointDescriptor.bEndpointAddress;
1121 InterfaceInfo->Pipes[PipeIndex].Interval = m_ConfigurationDescriptors[ConfigurationIndex].Interfaces[InterfaceIndex].EndPoints[PipeIndex].EndPointDescriptor.bInterval;
1122 InterfaceInfo->Pipes[PipeIndex].PipeType = (USBD_PIPE_TYPE)m_ConfigurationDescriptors[ConfigurationIndex].Interfaces[InterfaceIndex].EndPoints[PipeIndex].EndPointDescriptor.bmAttributes;
1123 InterfaceInfo->Pipes[PipeIndex].PipeHandle = (PVOID)&m_ConfigurationDescriptors[ConfigurationIndex].Interfaces[InterfaceIndex].EndPoints[PipeIndex].EndPointDescriptor;
1124 }
1125
1126 //
1127 // move offset
1128 //
1129 InterfaceInfo = (PUSBD_INTERFACE_INFORMATION)((ULONG_PTR)PtrToUlong(InterfaceInfo) + InterfaceInfo->Length);
1130 }
1131
1132 //
1133 // now build setup packet
1134 //
1135 RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1136 CtrlSetup.bRequest = USB_REQUEST_SET_CONFIGURATION;
1137 CtrlSetup.wValue.W = ConfigurationDescriptor->bConfigurationValue;
1138
1139 //
1140 // select configuration
1141 //
1142 Status = CommitSetupPacket(&CtrlSetup, 0, 0, 0);
1143
1144 //
1145 // informal debug print
1146 //
1147 DPRINT1("CUsbDevice::SelectConfiguration New Configuration %x Old Configuration %x Result %x\n", ConfigurationDescriptor->iConfiguration, m_ConfigurationIndex, Status);
1148
1149 if (NT_SUCCESS(Status))
1150 {
1151 //
1152 // store configuration device index
1153 //
1154 m_ConfigurationIndex = ConfigurationDescriptor->iConfiguration;
1155
1156 //
1157 // store configuration handle
1158 //
1159 *ConfigurationHandle = &m_ConfigurationDescriptors[ConfigurationIndex];
1160 }
1161
1162 //
1163 // done
1164 //
1165 return Status;
1166 }
1167
1168 //----------------------------------------------------------------------------------------
1169 NTSTATUS
1170 CUSBDevice::SelectInterface(
1171 IN USBD_CONFIGURATION_HANDLE ConfigurationHandle,
1172 IN OUT PUSBD_INTERFACE_INFORMATION InterfaceInfo)
1173 {
1174 ULONG ConfigurationIndex = 0;
1175 PUSB_CONFIGURATION Configuration;
1176 ULONG PipeIndex;
1177 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
1178 NTSTATUS Status;
1179
1180 //
1181 // FIXME support multiple configurations
1182 //
1183 PC_ASSERT(&m_ConfigurationDescriptors[ConfigurationIndex] == (PUSB_CONFIGURATION)ConfigurationHandle);
1184
1185 //
1186 // get configuration struct
1187 //
1188 Configuration = (PUSB_CONFIGURATION)ConfigurationHandle;
1189
1190 //
1191 // sanity checks
1192 //
1193 PC_ASSERT(Configuration->ConfigurationDescriptor.bNumInterfaces > InterfaceInfo->InterfaceNumber);
1194 PC_ASSERT(Configuration->Interfaces[InterfaceInfo->InterfaceNumber].InterfaceDescriptor.bNumEndpoints == InterfaceInfo->NumberOfPipes);
1195 #ifdef _MSC_VER
1196 PC_ASSERT(InterfaceInfo->Length == FIELD_OFFSET(USBD_INTERFACE_INFORMATION, Pipes[InterfaceInfo->NumberOfPipes]));
1197 #endif
1198
1199 //
1200 // copy pipe handles
1201 //
1202 for(PipeIndex = 0; PipeIndex < InterfaceInfo->NumberOfPipes; PipeIndex++)
1203 {
1204 //
1205 // copy pipe handle
1206 //
1207 DPRINT1("PipeIndex %lu\n", PipeIndex);
1208 DPRINT1("EndpointAddress %x\n", InterfaceInfo->Pipes[PipeIndex].EndpointAddress);
1209 DPRINT1("Interval %d\n", InterfaceInfo->Pipes[PipeIndex].Interval);
1210 DPRINT1("MaximumPacketSize %d\n", InterfaceInfo->Pipes[PipeIndex].MaximumPacketSize);
1211 DPRINT1("MaximumTransferSize %d\n", InterfaceInfo->Pipes[PipeIndex].MaximumTransferSize);
1212 DPRINT1("PipeFlags %d\n", InterfaceInfo->Pipes[PipeIndex].PipeFlags);
1213 DPRINT1("PipeType %dd\n", InterfaceInfo->Pipes[PipeIndex].PipeType);
1214 DPRINT1("UsbEndPoint %x\n", Configuration->Interfaces[InterfaceInfo->InterfaceNumber].EndPoints[PipeIndex].EndPointDescriptor.bEndpointAddress);
1215 PC_ASSERT(Configuration->Interfaces[InterfaceInfo->InterfaceNumber].EndPoints[PipeIndex].EndPointDescriptor.bEndpointAddress == InterfaceInfo->Pipes[PipeIndex].EndpointAddress);
1216
1217 InterfaceInfo->Pipes[PipeIndex].PipeHandle = &Configuration->Interfaces[InterfaceInfo->InterfaceNumber].EndPoints[PipeIndex].EndPointDescriptor;
1218
1219 if (Configuration->Interfaces[InterfaceInfo->InterfaceNumber].EndPoints[PipeIndex].EndPointDescriptor.bmAttributes & (USB_ENDPOINT_TYPE_ISOCHRONOUS | USB_ENDPOINT_TYPE_INTERRUPT))
1220 {
1221 //
1222 // FIXME: check if enough bandwidth is available
1223 //
1224 }
1225 }
1226
1227 //
1228 // initialize setup packet
1229 //
1230 RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1231 CtrlSetup.bRequest = USB_REQUEST_SET_INTERFACE;
1232 CtrlSetup.wValue.W = Configuration->Interfaces[InterfaceInfo->InterfaceNumber].InterfaceDescriptor.bAlternateSetting;
1233 CtrlSetup.wIndex.W = Configuration->Interfaces[InterfaceInfo->InterfaceNumber].InterfaceDescriptor.bInterfaceNumber;
1234 CtrlSetup.bmRequestType.B = 0x01;
1235
1236 //
1237 // issue request
1238 //
1239 Status = CommitSetupPacket(&CtrlSetup, 0, 0, 0);
1240
1241 //
1242 // informal debug print
1243 //
1244 DPRINT1("CUSBDevice::SelectInterface AlternateSetting %x InterfaceNumber %x Status %x\n", InterfaceInfo->AlternateSetting, InterfaceInfo->InterfaceNumber, Status);
1245
1246 //
1247 // done
1248 //
1249 return Status;
1250 }
1251
1252 //----------------------------------------------------------------------------------------
1253 NTSTATUS
1254 CreateUSBDevice(
1255 PUSBDEVICE *OutDevice)
1256 {
1257 CUSBDevice * This;
1258
1259 //
1260 // allocate controller
1261 //
1262 This = new(NonPagedPool, TAG_USBEHCI) CUSBDevice(0);
1263 if (!This)
1264 {
1265 //
1266 // failed to allocate
1267 //
1268 return STATUS_INSUFFICIENT_RESOURCES;
1269 }
1270
1271 //
1272 // add reference count
1273 //
1274 This->AddRef();
1275
1276 //
1277 // return result
1278 //
1279 *OutDevice = (PUSBDEVICE)This;
1280
1281 //
1282 // done
1283 //
1284 return STATUS_SUCCESS;
1285 }
1286