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