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