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