[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 PVOID DeviceDescriptor;
602
603 //
604 // allocate descriptor page aligned
605 //
606 DeviceDescriptor = ExAllocatePool(NonPagedPool, PAGE_SIZE);
607 if (!DeviceDescriptor)
608 {
609 //
610 // no memory
611 //
612 return STATUS_INSUFFICIENT_RESOURCES;
613 }
614
615 //
616 // zero descriptor
617 //
618 RtlZeroMemory(DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
619 RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
620
621 //
622 // setup request
623 //
624 CtrlSetup.bRequest = USB_REQUEST_GET_DESCRIPTOR;
625 CtrlSetup.wValue.HiByte = USB_DEVICE_DESCRIPTOR_TYPE;
626 CtrlSetup.wLength = sizeof(USB_DEVICE_DESCRIPTOR);
627 CtrlSetup.bmRequestType.B = 0x80;
628
629 //
630 // allocate mdl describing the device descriptor
631 //
632 Mdl = IoAllocateMdl(DeviceDescriptor, PAGE_SIZE, FALSE, FALSE, 0);
633 if (!Mdl)
634 {
635 //
636 // failed to allocate mdl
637 //
638 return STATUS_INSUFFICIENT_RESOURCES;
639 }
640
641 //
642 // build mdl for non paged pool
643 //
644 MmBuildMdlForNonPagedPool(Mdl);
645
646 //
647 // commit setup packet
648 //
649 Status = CommitSetupPacket(&CtrlSetup, 0, sizeof(USB_DEVICE_DESCRIPTOR), Mdl);
650
651 //
652 // now free the mdl
653 //
654 IoFreeMdl(Mdl);
655
656 if (NT_SUCCESS(Status))
657 {
658 //
659 // copy back device descriptor
660 //
661 RtlCopyMemory(&m_DeviceDescriptor, DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
662
663 //
664 // informal dbg print
665 //
666 DumpDeviceDescriptor(&m_DeviceDescriptor);
667 }
668
669 //
670 // free item
671 //
672 ExFreePool(DeviceDescriptor);
673
674 //
675 // done
676 //
677 return Status;
678
679 }
680
681 //----------------------------------------------------------------------------------------
682 NTSTATUS
683 CUSBDevice::CreateConfigurationDescriptor(
684 ULONG Index)
685 {
686 PVOID Buffer;
687 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
688 NTSTATUS Status;
689 PMDL Mdl;
690 PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
691
692
693 //
694 // sanity checks
695 //
696 PC_ASSERT(m_ConfigurationDescriptors);
697
698 //
699 // first allocate a buffer which should be enough to store all different interfaces and endpoints
700 //
701 Buffer = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, TAG_USBOHCI);
702 if (!Buffer)
703 {
704 //
705 // failed to allocate buffer
706 //
707 return STATUS_INSUFFICIENT_RESOURCES;
708 }
709
710 //
711 // zero buffer
712 //
713 RtlZeroMemory(Buffer, PAGE_SIZE);
714
715 //
716 // build setup packet
717 //
718 CtrlSetup.bmRequestType._BM.Recipient = BMREQUEST_TO_DEVICE;
719 CtrlSetup.bmRequestType._BM.Type = BMREQUEST_STANDARD;
720 CtrlSetup.bmRequestType._BM.Reserved = 0;
721 CtrlSetup.bmRequestType._BM.Dir = BMREQUEST_DEVICE_TO_HOST;
722 CtrlSetup.bRequest = USB_REQUEST_GET_DESCRIPTOR;
723 CtrlSetup.wValue.LowByte = 0;
724 CtrlSetup.wValue.HiByte = USB_CONFIGURATION_DESCRIPTOR_TYPE;
725 CtrlSetup.wIndex.W = 0;
726 CtrlSetup.wLength = PAGE_SIZE;
727
728 //
729 // FIXME: where put configuration index?
730 //
731
732 //
733 // now build MDL describing the buffer
734 //
735 Mdl = IoAllocateMdl(Buffer, PAGE_SIZE, FALSE, FALSE, 0);
736 if (!Mdl)
737 {
738 //
739 // failed to allocate mdl
740 //
741 ExFreePoolWithTag(Buffer, TAG_USBOHCI);
742 return STATUS_INSUFFICIENT_RESOURCES;
743 }
744
745 //
746 // build mdl for non paged pool
747 //
748 MmBuildMdlForNonPagedPool(Mdl);
749
750 //
751 // commit packet
752 //
753 Status = CommitSetupPacket(&CtrlSetup, 0, PAGE_SIZE, Mdl);
754 if (!NT_SUCCESS(Status))
755 {
756 //
757 // failed to issue request, cleanup
758 //
759 IoFreeMdl(Mdl);
760 ExFreePool(Buffer);
761 return Status;
762 }
763
764 //
765 // now free the mdl
766 //
767 IoFreeMdl(Mdl);
768
769 //
770 // get configuration descriptor
771 //
772 ConfigurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)Buffer;
773
774 //
775 // informal debug print
776 //
777 DumpConfigurationDescriptor(ConfigurationDescriptor);
778
779 //
780 // sanity check
781 //
782 PC_ASSERT(ConfigurationDescriptor->bLength == sizeof(USB_CONFIGURATION_DESCRIPTOR));
783 PC_ASSERT(ConfigurationDescriptor->wTotalLength <= PAGE_SIZE);
784 PC_ASSERT(ConfigurationDescriptor->bNumInterfaces);
785
786 //
787 // store configuration descriptor
788 //
789 m_ConfigurationDescriptors[Index] = ConfigurationDescriptor;
790
791 //
792 // done
793 //
794 return Status;
795 }
796 //----------------------------------------------------------------------------------------
797 VOID
798 CUSBDevice::GetConfigurationDescriptors(
799 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptorBuffer,
800 IN ULONG BufferLength,
801 OUT PULONG OutBufferLength)
802 {
803 //
804 // sanity check
805 //
806 PC_ASSERT(BufferLength >= sizeof(USB_CONFIGURATION_DESCRIPTOR));
807 PC_ASSERT(ConfigDescriptorBuffer);
808 PC_ASSERT(OutBufferLength);
809
810 //
811 // reset copied length
812 //
813 *OutBufferLength = 0;
814
815 //
816 // FIXME: support multiple configurations
817 //
818 PC_ASSERT(m_DeviceDescriptor.bNumConfigurations == 1);
819
820 //
821 // copy configuration descriptor
822 //
823 RtlCopyMemory(ConfigDescriptorBuffer, m_ConfigurationDescriptors[0], min(m_ConfigurationDescriptors[0]->wTotalLength, BufferLength));
824 *OutBufferLength = m_ConfigurationDescriptors[0]->wTotalLength;
825 }
826
827 //----------------------------------------------------------------------------------------
828 ULONG
829 CUSBDevice::GetConfigurationDescriptorsLength()
830 {
831 //
832 // FIXME: support multiple configurations
833 //
834 PC_ASSERT(m_DeviceDescriptor.bNumConfigurations == 1);
835
836 ASSERT(m_ConfigurationDescriptors[0]);
837 ASSERT(m_ConfigurationDescriptors[0]->wTotalLength);
838
839 return m_ConfigurationDescriptors[0]->wTotalLength;
840 }
841 //----------------------------------------------------------------------------------------
842 VOID
843 CUSBDevice::DumpDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor)
844 {
845 DPRINT1("Dumping Device Descriptor %x\n", DeviceDescriptor);
846 DPRINT1("bLength %x\n", DeviceDescriptor->bLength);
847 DPRINT1("bDescriptorType %x\n", DeviceDescriptor->bDescriptorType);
848 DPRINT1("bcdUSB %x\n", DeviceDescriptor->bcdUSB);
849 DPRINT1("bDeviceClass %x\n", DeviceDescriptor->bDeviceClass);
850 DPRINT1("bDeviceSubClass %x\n", DeviceDescriptor->bDeviceSubClass);
851 DPRINT1("bDeviceProtocol %x\n", DeviceDescriptor->bDeviceProtocol);
852 DPRINT1("bMaxPacketSize0 %x\n", DeviceDescriptor->bMaxPacketSize0);
853 DPRINT1("idVendor %x\n", DeviceDescriptor->idVendor);
854 DPRINT1("idProduct %x\n", DeviceDescriptor->idProduct);
855 DPRINT1("bcdDevice %x\n", DeviceDescriptor->bcdDevice);
856 DPRINT1("iManufacturer %x\n", DeviceDescriptor->iManufacturer);
857 DPRINT1("iProduct %x\n", DeviceDescriptor->iProduct);
858 DPRINT1("iSerialNumber %x\n", DeviceDescriptor->iSerialNumber);
859 DPRINT1("bNumConfigurations %x\n", DeviceDescriptor->bNumConfigurations);
860 }
861
862 //----------------------------------------------------------------------------------------
863 VOID
864 CUSBDevice::DumpConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
865 {
866 DPRINT1("Dumping ConfigurationDescriptor %x\n", ConfigurationDescriptor);
867 DPRINT1("bLength %x\n", ConfigurationDescriptor->bLength);
868 DPRINT1("bDescriptorType %x\n", ConfigurationDescriptor->bDescriptorType);
869 DPRINT1("wTotalLength %x\n", ConfigurationDescriptor->wTotalLength);
870 DPRINT1("bNumInterfaces %x\n", ConfigurationDescriptor->bNumInterfaces);
871 DPRINT1("bConfigurationValue %x\n", ConfigurationDescriptor->bConfigurationValue);
872 DPRINT1("iConfiguration %x\n", ConfigurationDescriptor->iConfiguration);
873 DPRINT1("bmAttributes %x\n", ConfigurationDescriptor->bmAttributes);
874 DPRINT1("MaxPower %x\n", ConfigurationDescriptor->MaxPower);
875 }
876 //----------------------------------------------------------------------------------------
877 NTSTATUS
878 CUSBDevice::SubmitSetupPacket(
879 IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
880 IN OUT ULONG BufferLength,
881 OUT PVOID Buffer)
882 {
883 NTSTATUS Status;
884 PMDL Mdl = NULL;
885
886 if (BufferLength)
887 {
888 //
889 // allocate mdl
890 //
891 Mdl = IoAllocateMdl(Buffer, BufferLength, FALSE, FALSE, 0);
892 if (!Mdl)
893 return STATUS_INSUFFICIENT_RESOURCES;
894
895 //
896 // HACK HACK HACK: assume the buffer is build from non paged pool
897 //
898 MmBuildMdlForNonPagedPool(Mdl);
899 }
900
901 //
902 // commit setup packet
903 //
904 Status = CommitSetupPacket(SetupPacket, 0, BufferLength, Mdl);
905
906 if (Mdl != NULL)
907 {
908 //
909 // free mdl
910 //
911 IoFreeMdl(Mdl);
912 }
913
914 //
915 // done
916 //
917 return Status;
918 }
919
920 //----------------------------------------------------------------------------------------
921 NTSTATUS
922 CUSBDevice::SelectConfiguration(
923 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
924 IN PUSBD_INTERFACE_INFORMATION InterfaceInfo,
925 OUT USBD_CONFIGURATION_HANDLE *ConfigurationHandle)
926 {
927 ULONG InterfaceIndex, PipeIndex;
928 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
929 NTSTATUS Status;
930 PUSB_CONFIGURATION_DESCRIPTOR CurrentConfigurationDescriptor;
931 PUSB_INTERFACE_DESCRIPTOR CurrentInterfaceDescriptor;
932 PUSB_ENDPOINT_DESCRIPTOR CurrentEndpointDescriptor;
933 PVOID StartPosition;
934
935 //
936 // FIXME: support multiple configurations
937 //
938 ASSERT(m_DeviceDescriptor.bNumConfigurations == 1);
939 ASSERT(m_ConfigurationDescriptors[0]);
940 CurrentConfigurationDescriptor = m_ConfigurationDescriptors[0];
941
942 //
943 // sanity check
944 //
945 PC_ASSERT(ConfigurationDescriptor->iConfiguration == CurrentConfigurationDescriptor->iConfiguration);
946 PC_ASSERT(ConfigurationDescriptor->bNumInterfaces <= CurrentConfigurationDescriptor->bNumInterfaces);
947 DPRINT1("CUSBDevice::SelectConfiguration NumInterfaces %lu\n", ConfigurationDescriptor->bNumInterfaces);
948
949
950 //
951 // copy interface info and pipe info
952 //
953 for(InterfaceIndex = 0; InterfaceIndex < ConfigurationDescriptor->bNumInterfaces; InterfaceIndex++)
954 {
955 //
956 // find interface descriptor
957 //
958 CurrentInterfaceDescriptor = USBD_ParseConfigurationDescriptor(CurrentConfigurationDescriptor, InterfaceInfo->InterfaceNumber, InterfaceInfo->AlternateSetting);
959
960 //
961 // sanity check
962 //
963 ASSERT(CurrentInterfaceDescriptor);
964 ASSERT(CurrentInterfaceDescriptor->bLength != 0);
965 ASSERT(InterfaceInfo->NumberOfPipes == CurrentInterfaceDescriptor->bNumEndpoints);
966 ASSERT(InterfaceInfo->Length != 0);
967 #ifdef _MSC_VER
968 PC_ASSERT(InterfaceInfo->Length == FIELD_OFFSET(USBD_INTERFACE_INFORMATION, Pipes[InterfaceInfo->NumberOfPipes]));
969 #endif
970
971 DPRINT1("CUSBDevice::SelectConfiguration InterfaceNumber %lu AlternativeSetting %lu bNumEndpoints %lu\n", InterfaceInfo->InterfaceNumber, InterfaceInfo->AlternateSetting, CurrentInterfaceDescriptor->bNumEndpoints);
972
973 //
974 // copy interface info
975 //
976 InterfaceInfo->InterfaceHandle = (USBD_INTERFACE_HANDLE)CurrentInterfaceDescriptor;
977 InterfaceInfo->Class = CurrentInterfaceDescriptor->bInterfaceClass;
978 InterfaceInfo->SubClass = CurrentInterfaceDescriptor->bInterfaceSubClass;
979 InterfaceInfo->Protocol = CurrentInterfaceDescriptor->bInterfaceProtocol;
980 InterfaceInfo->Reserved = 0;
981
982 //
983 // copy endpoint info
984 //
985 StartPosition = CurrentInterfaceDescriptor;
986 for(PipeIndex = 0; PipeIndex < InterfaceInfo->NumberOfPipes; PipeIndex++)
987 {
988 //
989 // find corresponding endpoint descriptor
990 //
991 CurrentEndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)USBD_ParseDescriptors(CurrentConfigurationDescriptor, CurrentConfigurationDescriptor->wTotalLength, StartPosition, USB_ENDPOINT_DESCRIPTOR_TYPE);
992
993 //
994 // sanity checks
995 //
996 ASSERT(CurrentEndpointDescriptor);
997 ASSERT(CurrentEndpointDescriptor->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE);
998
999 //
1000 // copy pipe info
1001 //
1002 InterfaceInfo->Pipes[PipeIndex].MaximumPacketSize = CurrentEndpointDescriptor->wMaxPacketSize;
1003 InterfaceInfo->Pipes[PipeIndex].EndpointAddress = CurrentEndpointDescriptor->bEndpointAddress;
1004 InterfaceInfo->Pipes[PipeIndex].Interval = CurrentEndpointDescriptor->bInterval;
1005 InterfaceInfo->Pipes[PipeIndex].PipeType = (USBD_PIPE_TYPE)CurrentEndpointDescriptor->bmAttributes;
1006 InterfaceInfo->Pipes[PipeIndex].PipeHandle = (PVOID)CurrentEndpointDescriptor;
1007
1008 //
1009 // move start position beyond the current endpoint descriptor
1010 //
1011 StartPosition = (PVOID)(CurrentEndpointDescriptor + 1);
1012 }
1013
1014 //
1015 // move offset
1016 //
1017 InterfaceInfo = (PUSBD_INTERFACE_INFORMATION)((ULONG_PTR)PtrToUlong(InterfaceInfo) + InterfaceInfo->Length);
1018 }
1019
1020 //
1021 // now build setup packet
1022 //
1023 RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1024 CtrlSetup.bRequest = USB_REQUEST_SET_CONFIGURATION;
1025 CtrlSetup.wValue.W = ConfigurationDescriptor->bConfigurationValue;
1026
1027 //
1028 // select configuration
1029 //
1030 Status = CommitSetupPacket(&CtrlSetup, 0, 0, 0);
1031
1032 //
1033 // informal debug print
1034 //
1035 DPRINT1("CUsbDevice::SelectConfiguration New Configuration %x Old Configuration %x Result %x\n", ConfigurationDescriptor->iConfiguration, m_ConfigurationIndex, Status);
1036
1037 if (NT_SUCCESS(Status))
1038 {
1039 //
1040 // store configuration device index
1041 //
1042 m_ConfigurationIndex = ConfigurationDescriptor->iConfiguration;
1043
1044 //
1045 // store configuration handle
1046 //
1047 *ConfigurationHandle = m_ConfigurationDescriptors[0];
1048 }
1049
1050 //
1051 // done
1052 //
1053 return Status;
1054 }
1055
1056 //----------------------------------------------------------------------------------------
1057 NTSTATUS
1058 CUSBDevice::SelectInterface(
1059 IN USBD_CONFIGURATION_HANDLE ConfigurationHandle,
1060 IN OUT PUSBD_INTERFACE_INFORMATION InterfaceInfo)
1061 {
1062 PUSB_CONFIGURATION_DESCRIPTOR Configuration;
1063 ULONG PipeIndex;
1064 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
1065 NTSTATUS Status;
1066 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
1067 PUSB_ENDPOINT_DESCRIPTOR CurrentEndpointDescriptor;
1068 PVOID StartPosition;
1069
1070 //
1071 // FIXME support multiple configurations
1072 //
1073 PC_ASSERT(m_ConfigurationDescriptors[0] == (PUSB_CONFIGURATION_DESCRIPTOR)ConfigurationHandle);
1074
1075 //
1076 // get configuration struct
1077 //
1078 Configuration = (PUSB_CONFIGURATION_DESCRIPTOR)ConfigurationHandle;
1079
1080 //
1081 // sanity checks
1082 //
1083 PC_ASSERT(Configuration->bNumInterfaces > InterfaceInfo->InterfaceNumber);
1084 #ifdef _MSC_VER
1085 //PC_ASSERT(InterfaceInfo->Length == FIELD_OFFSET(USBD_INTERFACE_INFORMATION, Pipes[InterfaceInfo->NumberOfPipes]));
1086 #endif
1087
1088 //
1089 // FIXME: check bandwidth
1090 //
1091
1092 //
1093 // find interface number
1094 //
1095 InterfaceDescriptor = USBD_ParseConfigurationDescriptor(Configuration, InterfaceInfo->InterfaceNumber, InterfaceInfo->AlternateSetting);
1096 ASSERT(InterfaceDescriptor);
1097
1098 //
1099 // initialize setup packet
1100 //
1101 RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1102 CtrlSetup.bRequest = USB_REQUEST_SET_INTERFACE;
1103 CtrlSetup.wValue.W = InterfaceDescriptor->bAlternateSetting;
1104 CtrlSetup.wIndex.W = InterfaceDescriptor->bInterfaceNumber;
1105 CtrlSetup.bmRequestType.B = 0x01;
1106
1107 //
1108 // issue request
1109 //
1110 Status = CommitSetupPacket(&CtrlSetup, 0, 0, 0);
1111
1112 //
1113 // informal debug print
1114 //
1115 DPRINT1("CUSBDevice::SelectInterface AlternateSetting %x InterfaceNumber %x Status %x\n", InterfaceInfo->AlternateSetting, InterfaceInfo->InterfaceNumber, Status);
1116 DPRINT1("CUSBDevice::SelectInterface bInterfaceNumber %u bAlternateSetting %u NumberOfPipes %u Length %lu\n",
1117 InterfaceDescriptor->bInterfaceNumber, InterfaceDescriptor->bAlternateSetting, InterfaceInfo->NumberOfPipes, InterfaceInfo->Length);
1118 InterfaceInfo->InterfaceHandle = InterfaceDescriptor;
1119 InterfaceInfo->NumberOfPipes = InterfaceDescriptor->bNumEndpoints;
1120
1121 //
1122 // are there end points
1123 //
1124 if (InterfaceDescriptor->bNumEndpoints)
1125 {
1126 //
1127 // sanity check
1128 //
1129 ASSERT(InterfaceInfo->Length == sizeof(USBD_INTERFACE_INFORMATION) + (InterfaceDescriptor->bNumEndpoints > 1 ? sizeof(USBD_PIPE_INFORMATION) * (InterfaceDescriptor->bNumEndpoints - 1) : 0));
1130
1131 //
1132 // store number of pipes
1133 //
1134 InterfaceInfo->NumberOfPipes = InterfaceDescriptor->bNumEndpoints;
1135
1136 StartPosition = InterfaceDescriptor;
1137 for(PipeIndex = 0; PipeIndex < InterfaceInfo->NumberOfPipes; PipeIndex++)
1138 {
1139 //
1140 // find corresponding endpoint descriptor
1141 //
1142 CurrentEndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)USBD_ParseDescriptors(Configuration, Configuration->wTotalLength, StartPosition, USB_ENDPOINT_DESCRIPTOR_TYPE);
1143
1144 //
1145 // sanity checks
1146 //
1147 ASSERT(CurrentEndpointDescriptor);
1148 ASSERT(CurrentEndpointDescriptor->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE);
1149
1150 //
1151 // copy pipe info
1152 //
1153 InterfaceInfo->Pipes[PipeIndex].MaximumPacketSize = CurrentEndpointDescriptor->wMaxPacketSize;
1154 InterfaceInfo->Pipes[PipeIndex].EndpointAddress = CurrentEndpointDescriptor->bEndpointAddress;
1155 InterfaceInfo->Pipes[PipeIndex].Interval = CurrentEndpointDescriptor->bInterval;
1156 InterfaceInfo->Pipes[PipeIndex].PipeType = (USBD_PIPE_TYPE)CurrentEndpointDescriptor->bmAttributes;
1157 InterfaceInfo->Pipes[PipeIndex].PipeHandle = (PVOID)CurrentEndpointDescriptor;
1158
1159 //
1160 // move start position beyond the current endpoint descriptor
1161 //
1162 StartPosition = (PVOID)(CurrentEndpointDescriptor + 1);
1163 }
1164 }
1165 //
1166 // done
1167 //
1168 return Status;
1169 }
1170
1171 //----------------------------------------------------------------------------------------
1172 NTSTATUS
1173 CreateUSBDevice(
1174 PUSBDEVICE *OutDevice)
1175 {
1176 CUSBDevice * This;
1177
1178 //
1179 // allocate controller
1180 //
1181 This = new(NonPagedPool, TAG_USBOHCI) CUSBDevice(0);
1182 if (!This)
1183 {
1184 //
1185 // failed to allocate
1186 //
1187 return STATUS_INSUFFICIENT_RESOURCES;
1188 }
1189
1190 //
1191 // add reference count
1192 //
1193 This->AddRef();
1194
1195 //
1196 // return result
1197 //
1198 *OutDevice = (PUSBDEVICE)This;
1199
1200 //
1201 // done
1202 //
1203 return STATUS_SUCCESS;
1204 }
1205