0c1cf9c17cfd5b3135a922dfe45d713d861eae0b
[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 = NULL;
862
863 if (BufferLength)
864 {
865 //
866 // allocate mdl
867 //
868 Mdl = IoAllocateMdl(Buffer, BufferLength, FALSE, FALSE, 0);
869 if (!Mdl)
870 return STATUS_INSUFFICIENT_RESOURCES;
871
872 //
873 // HACK HACK HACK: assume the buffer is build from non paged pool
874 //
875 MmBuildMdlForNonPagedPool(Mdl);
876 }
877
878 //
879 // commit setup packet
880 //
881 Status = CommitSetupPacket(SetupPacket, 0, BufferLength, Mdl);
882
883 if (Mdl != NULL)
884 {
885 //
886 // free mdl
887 //
888 IoFreeMdl(Mdl);
889 }
890
891 //
892 // done
893 //
894 return Status;
895 }
896
897 //----------------------------------------------------------------------------------------
898 NTSTATUS
899 CUSBDevice::SelectConfiguration(
900 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
901 IN PUSBD_INTERFACE_INFORMATION InterfaceInfo,
902 OUT USBD_CONFIGURATION_HANDLE *ConfigurationHandle)
903 {
904 ULONG InterfaceIndex, PipeIndex;
905 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
906 NTSTATUS Status;
907 PUSB_CONFIGURATION_DESCRIPTOR CurrentConfigurationDescriptor;
908 PUSB_INTERFACE_DESCRIPTOR CurrentInterfaceDescriptor;
909 PUSB_ENDPOINT_DESCRIPTOR CurrentEndpointDescriptor;
910 PVOID StartPosition;
911
912 //
913 // FIXME: support multiple configurations
914 //
915 ASSERT(m_DeviceDescriptor.bNumConfigurations == 1);
916 ASSERT(m_ConfigurationDescriptors[0]);
917 CurrentConfigurationDescriptor = m_ConfigurationDescriptors[0];
918
919 //
920 // sanity check
921 //
922 PC_ASSERT(ConfigurationDescriptor->iConfiguration == CurrentConfigurationDescriptor->iConfiguration);
923 PC_ASSERT(ConfigurationDescriptor->bNumInterfaces <= CurrentConfigurationDescriptor->bNumInterfaces);
924 DPRINT1("CUSBDevice::SelectConfiguration NumInterfaces %lu\n", ConfigurationDescriptor->bNumInterfaces);
925
926
927 //
928 // copy interface info and pipe info
929 //
930 for(InterfaceIndex = 0; InterfaceIndex < ConfigurationDescriptor->bNumInterfaces; InterfaceIndex++)
931 {
932 //
933 // find interface descriptor
934 //
935 CurrentInterfaceDescriptor = USBD_ParseConfigurationDescriptor(CurrentConfigurationDescriptor, InterfaceInfo->InterfaceNumber, InterfaceInfo->AlternateSetting);
936
937 //
938 // sanity check
939 //
940 ASSERT(CurrentInterfaceDescriptor);
941 ASSERT(CurrentInterfaceDescriptor->bLength != 0);
942 ASSERT(InterfaceInfo->NumberOfPipes == CurrentInterfaceDescriptor->bNumEndpoints);
943 ASSERT(InterfaceInfo->Length != 0);
944 #ifdef _MSC_VER
945 PC_ASSERT(InterfaceInfo->Length == FIELD_OFFSET(USBD_INTERFACE_INFORMATION, Pipes[InterfaceInfo->NumberOfPipes]));
946 #endif
947
948 DPRINT1("CUSBDevice::SelectConfiguration InterfaceNumber %lu AlternativeSetting %lu bNumEndpoints %lu\n", InterfaceInfo->InterfaceNumber, InterfaceInfo->AlternateSetting, CurrentInterfaceDescriptor->bNumEndpoints);
949
950 //
951 // copy interface info
952 //
953 InterfaceInfo->InterfaceHandle = (USBD_INTERFACE_HANDLE)CurrentInterfaceDescriptor;
954 InterfaceInfo->Class = CurrentInterfaceDescriptor->bInterfaceClass;
955 InterfaceInfo->SubClass = CurrentInterfaceDescriptor->bInterfaceSubClass;
956 InterfaceInfo->Protocol = CurrentInterfaceDescriptor->bInterfaceProtocol;
957 InterfaceInfo->Reserved = 0;
958
959 //
960 // copy endpoint info
961 //
962 StartPosition = CurrentInterfaceDescriptor;
963 for(PipeIndex = 0; PipeIndex < InterfaceInfo->NumberOfPipes; PipeIndex++)
964 {
965 //
966 // find corresponding endpoint descriptor
967 //
968 CurrentEndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)USBD_ParseDescriptors(CurrentConfigurationDescriptor, CurrentConfigurationDescriptor->wTotalLength, StartPosition, USB_ENDPOINT_DESCRIPTOR_TYPE);
969
970 //
971 // sanity checks
972 //
973 ASSERT(CurrentEndpointDescriptor);
974 ASSERT(CurrentEndpointDescriptor->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE);
975
976 //
977 // copy pipe info
978 //
979 InterfaceInfo->Pipes[PipeIndex].MaximumPacketSize = CurrentEndpointDescriptor->wMaxPacketSize;
980 InterfaceInfo->Pipes[PipeIndex].EndpointAddress = CurrentEndpointDescriptor->bEndpointAddress;
981 InterfaceInfo->Pipes[PipeIndex].Interval = CurrentEndpointDescriptor->bInterval;
982 InterfaceInfo->Pipes[PipeIndex].PipeType = (USBD_PIPE_TYPE)CurrentEndpointDescriptor->bmAttributes;
983 InterfaceInfo->Pipes[PipeIndex].PipeHandle = (PVOID)CurrentEndpointDescriptor;
984
985 //
986 // move start position beyond the current endpoint descriptor
987 //
988 StartPosition = (PVOID)(CurrentEndpointDescriptor + 1);
989 }
990
991 //
992 // move offset
993 //
994 InterfaceInfo = (PUSBD_INTERFACE_INFORMATION)((ULONG_PTR)PtrToUlong(InterfaceInfo) + InterfaceInfo->Length);
995 }
996
997 //
998 // now build setup packet
999 //
1000 RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1001 CtrlSetup.bRequest = USB_REQUEST_SET_CONFIGURATION;
1002 CtrlSetup.wValue.W = ConfigurationDescriptor->bConfigurationValue;
1003
1004 //
1005 // select configuration
1006 //
1007 Status = CommitSetupPacket(&CtrlSetup, 0, 0, 0);
1008
1009 //
1010 // informal debug print
1011 //
1012 DPRINT1("CUsbDevice::SelectConfiguration New Configuration %x Old Configuration %x Result %x\n", ConfigurationDescriptor->iConfiguration, m_ConfigurationIndex, Status);
1013
1014 if (NT_SUCCESS(Status))
1015 {
1016 //
1017 // store configuration device index
1018 //
1019 m_ConfigurationIndex = ConfigurationDescriptor->iConfiguration;
1020
1021 //
1022 // store configuration handle
1023 //
1024 *ConfigurationHandle = m_ConfigurationDescriptors[0];
1025 }
1026
1027 //
1028 // done
1029 //
1030 return Status;
1031 }
1032
1033 //----------------------------------------------------------------------------------------
1034 NTSTATUS
1035 CUSBDevice::SelectInterface(
1036 IN USBD_CONFIGURATION_HANDLE ConfigurationHandle,
1037 IN OUT PUSBD_INTERFACE_INFORMATION InterfaceInfo)
1038 {
1039 PUSB_CONFIGURATION_DESCRIPTOR Configuration;
1040 ULONG PipeIndex;
1041 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
1042 NTSTATUS Status;
1043 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
1044 PUSB_ENDPOINT_DESCRIPTOR CurrentEndpointDescriptor;
1045 PVOID StartPosition;
1046
1047 //
1048 // FIXME support multiple configurations
1049 //
1050 PC_ASSERT(m_ConfigurationDescriptors[0] == (PUSB_CONFIGURATION_DESCRIPTOR)ConfigurationHandle);
1051
1052 //
1053 // get configuration struct
1054 //
1055 Configuration = (PUSB_CONFIGURATION_DESCRIPTOR)ConfigurationHandle;
1056
1057 //
1058 // sanity checks
1059 //
1060 PC_ASSERT(Configuration->bNumInterfaces > InterfaceInfo->InterfaceNumber);
1061 #ifdef _MSC_VER
1062 //PC_ASSERT(InterfaceInfo->Length == FIELD_OFFSET(USBD_INTERFACE_INFORMATION, Pipes[InterfaceInfo->NumberOfPipes]));
1063 #endif
1064
1065 //
1066 // FIXME: check bandwidth
1067 //
1068
1069 //
1070 // find interface number
1071 //
1072 InterfaceDescriptor = USBD_ParseConfigurationDescriptor(Configuration, InterfaceInfo->InterfaceNumber, InterfaceInfo->AlternateSetting);
1073 ASSERT(InterfaceDescriptor);
1074
1075 //
1076 // initialize setup packet
1077 //
1078 RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1079 CtrlSetup.bRequest = USB_REQUEST_SET_INTERFACE;
1080 CtrlSetup.wValue.W = InterfaceDescriptor->bAlternateSetting;
1081 CtrlSetup.wIndex.W = InterfaceDescriptor->bInterfaceNumber;
1082 CtrlSetup.bmRequestType.B = 0x01;
1083
1084 //
1085 // issue request
1086 //
1087 Status = CommitSetupPacket(&CtrlSetup, 0, 0, 0);
1088
1089 //
1090 // informal debug print
1091 //
1092 DPRINT1("CUSBDevice::SelectInterface AlternateSetting %x InterfaceNumber %x Status %x\n", InterfaceInfo->AlternateSetting, InterfaceInfo->InterfaceNumber, Status);
1093 DPRINT1("CUSBDevice::SelectInterface bInterfaceNumber %u bAlternateSetting %u NumberOfPipes %u Length %lu\n",
1094 InterfaceDescriptor->bInterfaceNumber, InterfaceDescriptor->bAlternateSetting, InterfaceInfo->NumberOfPipes, InterfaceInfo->Length);
1095 InterfaceInfo->InterfaceHandle = InterfaceDescriptor;
1096 InterfaceInfo->NumberOfPipes = InterfaceDescriptor->bNumEndpoints;
1097
1098 //
1099 // are there end points
1100 //
1101 if (InterfaceDescriptor->bNumEndpoints)
1102 {
1103 //
1104 // sanity check
1105 //
1106 ASSERT(InterfaceInfo->Length == sizeof(USBD_INTERFACE_INFORMATION) + (InterfaceDescriptor->bNumEndpoints > 1 ? sizeof(USBD_PIPE_INFORMATION) * (InterfaceDescriptor->bNumEndpoints - 1) : 0));
1107
1108 //
1109 // store number of pipes
1110 //
1111 InterfaceInfo->NumberOfPipes = InterfaceDescriptor->bNumEndpoints;
1112
1113 StartPosition = InterfaceDescriptor;
1114 for(PipeIndex = 0; PipeIndex < InterfaceInfo->NumberOfPipes; PipeIndex++)
1115 {
1116 //
1117 // find corresponding endpoint descriptor
1118 //
1119 CurrentEndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)USBD_ParseDescriptors(Configuration, Configuration->wTotalLength, StartPosition, USB_ENDPOINT_DESCRIPTOR_TYPE);
1120
1121 //
1122 // sanity checks
1123 //
1124 ASSERT(CurrentEndpointDescriptor);
1125 ASSERT(CurrentEndpointDescriptor->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE);
1126
1127 //
1128 // copy pipe info
1129 //
1130 InterfaceInfo->Pipes[PipeIndex].MaximumPacketSize = CurrentEndpointDescriptor->wMaxPacketSize;
1131 InterfaceInfo->Pipes[PipeIndex].EndpointAddress = CurrentEndpointDescriptor->bEndpointAddress;
1132 InterfaceInfo->Pipes[PipeIndex].Interval = CurrentEndpointDescriptor->bInterval;
1133 InterfaceInfo->Pipes[PipeIndex].PipeType = (USBD_PIPE_TYPE)CurrentEndpointDescriptor->bmAttributes;
1134 InterfaceInfo->Pipes[PipeIndex].PipeHandle = (PVOID)CurrentEndpointDescriptor;
1135
1136 //
1137 // move start position beyond the current endpoint descriptor
1138 //
1139 StartPosition = (PVOID)(CurrentEndpointDescriptor + 1);
1140 }
1141 }
1142 //
1143 // done
1144 //
1145 return Status;
1146 }
1147
1148 //----------------------------------------------------------------------------------------
1149 NTSTATUS
1150 CreateUSBDevice(
1151 PUSBDEVICE *OutDevice)
1152 {
1153 CUSBDevice * This;
1154
1155 //
1156 // allocate controller
1157 //
1158 This = new(NonPagedPool, TAG_USBOHCI) CUSBDevice(0);
1159 if (!This)
1160 {
1161 //
1162 // failed to allocate
1163 //
1164 return STATUS_INSUFFICIENT_RESOURCES;
1165 }
1166
1167 //
1168 // add reference count
1169 //
1170 This->AddRef();
1171
1172 //
1173 // return result
1174 //
1175 *OutDevice = (PUSBDEVICE)This;
1176
1177 //
1178 // done
1179 //
1180 return STATUS_SUCCESS;
1181 }
1182