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