[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->bmRequestType.B = 0xB;
319 CtrlSetup->bRequest = USB_REQUEST_SET_ADDRESS;
320 CtrlSetup->wValue.W = (USHORT)DeviceAddress;
321
322 //
323 // set device address
324 //
325 Status = CommitSetupPacket(CtrlSetup, 0, 0, 0);
326
327 //
328 // free setup packet
329 //
330 ExFreePoolWithTag(CtrlSetup, TAG_USBOHCI);
331
332 //
333 // check for success
334 //
335 if (!NT_SUCCESS(Status))
336 {
337 //
338 // failed to set device address
339 //
340 DPRINT1("CUSBDevice::SetDeviceAddress> failed to set device address with %x Address %x\n", Status, DeviceAddress);
341 return Status;
342 }
343
344 //
345 // lets have a short nap
346 //
347 KeStallExecutionProcessor(300);
348
349 //
350 // back up old address
351 //
352 OldAddress = m_DeviceAddress;
353
354 //
355 // store new device address
356 //
357 m_DeviceAddress = DeviceAddress;
358
359 //
360 // check that setting device address succeeded by retrieving the device descriptor
361 //
362 Status = CreateDeviceDescriptor();
363 if (!NT_SUCCESS(Status))
364 {
365 //
366 // failed to retrieve device descriptor
367 //
368 DPRINT1("CUSBbDevice::SetDeviceAddress> failed to retrieve device descriptor with device address set Error %x\n", Status);
369 m_DeviceAddress = OldAddress;
370
371 //
372 // return error status
373 //
374 return Status;
375 }
376
377 //
378 // sanity checks
379 //
380 PC_ASSERT(m_DeviceDescriptor.bNumConfigurations);
381
382 //
383 // allocate configuration descriptor
384 //
385 m_ConfigurationDescriptors = (PUSB_CONFIGURATION_DESCRIPTOR*) ExAllocatePoolWithTag(NonPagedPool, sizeof(PUSB_CONFIGURATION_DESCRIPTOR) * m_DeviceDescriptor.bNumConfigurations, TAG_USBOHCI);
386
387 //
388 // zero configuration descriptor
389 //
390 RtlZeroMemory(m_ConfigurationDescriptors, sizeof(PUSB_CONFIGURATION_DESCRIPTOR) * m_DeviceDescriptor.bNumConfigurations);
391
392 //
393 // retrieve the configuration descriptors
394 //
395 for(Index = 0; Index < m_DeviceDescriptor.bNumConfigurations; Index++)
396 {
397 //
398 // retrieve configuration descriptors from device
399 //
400 Status = CreateConfigurationDescriptor(Index);
401 if (!NT_SUCCESS(Status))
402 {
403 DPRINT1("CUSBDevice::SetDeviceAddress> failed to retrieve configuration %lu\n", Index);
404 break;
405 }
406 }
407
408 //
409 // done
410 //
411 return Status;
412
413 }
414
415 //----------------------------------------------------------------------------------------
416 void
417 CUSBDevice::GetDeviceDescriptor(
418 PUSB_DEVICE_DESCRIPTOR DeviceDescriptor)
419 {
420 RtlMoveMemory(DeviceDescriptor, &m_DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
421 }
422
423 //----------------------------------------------------------------------------------------
424 UCHAR
425 CUSBDevice::GetConfigurationValue()
426 {
427 //
428 // return configuration index
429 //
430 return m_ConfigurationIndex;
431 }
432
433 //----------------------------------------------------------------------------------------
434 NTSTATUS
435 CUSBDevice::CommitIrp(
436 PIRP Irp)
437 {
438 NTSTATUS Status;
439 PUSBREQUEST Request;
440
441 if (!m_Queue || !m_DmaManager)
442 {
443 //
444 // no queue, wtf?
445 //
446 DPRINT1("CUSBDevice::CommitUrb> no queue / dma !!!\n");
447 return STATUS_UNSUCCESSFUL;
448 }
449
450 //
451 // build usb request
452 //
453 Status = m_Queue->CreateUSBRequest(&Request);
454 if (!NT_SUCCESS(Status))
455 {
456 //
457 // failed to build request
458 //
459 DPRINT1("CUSBDevice::CommitSetupPacket> CreateUSBRequest failed with %x\n", Status);
460 return Status;
461 }
462
463 //
464 // initialize request
465 //
466 Status = Request->InitializeWithIrp(m_DmaManager, Irp);
467
468 //
469 // mark irp as pending
470 //
471 IoMarkIrpPending(Irp);
472
473 //
474 // now add the request
475 //
476 Status = m_Queue->AddUSBRequest(Request);
477 if (!NT_SUCCESS(Status))
478 {
479 //
480 // failed to add request
481 //
482 DPRINT1("CUSBDevice::CommitSetupPacket> failed add request to queue with %x\n", Status);
483 Request->Release();
484 return Status;
485 }
486
487 //
488 // done
489 //
490 return STATUS_PENDING;
491 }
492
493 //----------------------------------------------------------------------------------------
494 NTSTATUS
495 CUSBDevice::SubmitIrp(
496 PIRP Irp)
497 {
498 KIRQL OldLevel;
499 NTSTATUS Status;
500
501 //
502 // acquire device lock
503 //
504 KeAcquireSpinLock(&m_Lock, &OldLevel);
505
506 //
507 // commit urb
508 //
509 Status = CommitIrp(Irp);
510
511 //
512 // release lock
513 //
514 KeReleaseSpinLock(&m_Lock, OldLevel);
515
516 return Status;
517 }
518 //----------------------------------------------------------------------------------------
519 NTSTATUS
520 CUSBDevice::CommitSetupPacket(
521 IN PUSB_DEFAULT_PIPE_SETUP_PACKET Packet,
522 IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor,
523 IN ULONG BufferLength,
524 IN OUT PMDL Mdl)
525 {
526 NTSTATUS Status;
527 PUSBREQUEST Request;
528
529 if (!m_Queue)
530 {
531 //
532 // no queue, wtf?
533 //
534 DPRINT1("CUSBDevice::CommitSetupPacket> no queue!!!\n");
535 return STATUS_UNSUCCESSFUL;
536 }
537
538 //
539 // build usb request
540 //
541 Status = m_Queue->CreateUSBRequest(&Request);
542 if (!NT_SUCCESS(Status))
543 {
544 //
545 // failed to build request
546 //
547 DPRINT1("CUSBDevice::CommitSetupPacket> CreateUSBRequest failed with %x\n", Status);
548 return Status;
549 }
550
551 //
552 // initialize request
553 //
554 Status = Request->InitializeWithSetupPacket(m_DmaManager, Packet, m_DeviceAddress, EndpointDescriptor, BufferLength, Mdl);
555 if (!NT_SUCCESS(Status))
556 {
557 //
558 // failed to initialize request
559 //
560 DPRINT1("CUSBDevice::CommitSetupPacket> failed to initialize usb request with %x\n", Status);
561 Request->Release();
562 return Status;
563 }
564
565 //
566 // now add the request
567 //
568 Status = m_Queue->AddUSBRequest(Request);
569 if (!NT_SUCCESS(Status))
570 {
571 //
572 // failed to add request
573 //
574 DPRINT1("CUSBDevice::CommitSetupPacket> failed add request to queue with %x\n", Status);
575 Request->Release();
576 return Status;
577 }
578
579 //
580 // get the result code when the operation has been finished
581 //
582 Request->GetResultStatus(&Status, NULL);
583
584 //
585 // release request
586 //
587 Request->Release();
588
589 //
590 // done
591 //
592 return Status;
593 }
594
595 //----------------------------------------------------------------------------------------
596 NTSTATUS
597 CUSBDevice::CreateDeviceDescriptor()
598 {
599 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
600 PMDL Mdl;
601 NTSTATUS Status;
602
603 //
604 // zero descriptor
605 //
606 RtlZeroMemory(&m_DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
607 RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
608
609 //
610 // setup request
611 //
612 CtrlSetup.bRequest = USB_REQUEST_GET_DESCRIPTOR;
613 CtrlSetup.wValue.HiByte = USB_DEVICE_DESCRIPTOR_TYPE;
614 CtrlSetup.wLength = sizeof(USB_DEVICE_DESCRIPTOR);
615 CtrlSetup.bmRequestType.B = 0x80;
616
617 //
618 // allocate mdl describing the device descriptor
619 //
620 Mdl = IoAllocateMdl(&m_DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR), FALSE, FALSE, 0);
621 if (!Mdl)
622 {
623 //
624 // failed to allocate mdl
625 //
626 return STATUS_INSUFFICIENT_RESOURCES;
627 }
628
629 //
630 // build mdl for non paged pool
631 //
632 MmBuildMdlForNonPagedPool(Mdl);
633
634 //
635 // commit setup packet
636 //
637 Status = CommitSetupPacket(&CtrlSetup, 0, sizeof(USB_DEVICE_DESCRIPTOR), Mdl);
638
639 //
640 // now free the mdl
641 //
642 IoFreeMdl(Mdl);
643
644 if (NT_SUCCESS(Status))
645 {
646 //
647 // informal dbg print
648 //
649 DumpDeviceDescriptor(&m_DeviceDescriptor);
650 }
651
652 //
653 // done
654 //
655 return Status;
656
657 }
658
659 //----------------------------------------------------------------------------------------
660 NTSTATUS
661 CUSBDevice::CreateConfigurationDescriptor(
662 ULONG Index)
663 {
664 PVOID Buffer;
665 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
666 NTSTATUS Status;
667 PMDL Mdl;
668 PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
669
670
671 //
672 // sanity checks
673 //
674 PC_ASSERT(m_ConfigurationDescriptors);
675
676 //
677 // first allocate a buffer which should be enough to store all different interfaces and endpoints
678 //
679 Buffer = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, TAG_USBOHCI);
680 if (!Buffer)
681 {
682 //
683 // failed to allocate buffer
684 //
685 return STATUS_INSUFFICIENT_RESOURCES;
686 }
687
688 //
689 // zero buffer
690 //
691 RtlZeroMemory(Buffer, PAGE_SIZE);
692
693 //
694 // build setup packet
695 //
696 CtrlSetup.bmRequestType._BM.Recipient = BMREQUEST_TO_DEVICE;
697 CtrlSetup.bmRequestType._BM.Type = BMREQUEST_STANDARD;
698 CtrlSetup.bmRequestType._BM.Reserved = 0;
699 CtrlSetup.bmRequestType._BM.Dir = BMREQUEST_DEVICE_TO_HOST;
700 CtrlSetup.bRequest = USB_REQUEST_GET_DESCRIPTOR;
701 CtrlSetup.wValue.LowByte = 0;
702 CtrlSetup.wValue.HiByte = USB_CONFIGURATION_DESCRIPTOR_TYPE;
703 CtrlSetup.wIndex.W = 0;
704 CtrlSetup.wLength = PAGE_SIZE;
705
706 //
707 // FIXME: where put configuration index?
708 //
709
710 //
711 // now build MDL describing the buffer
712 //
713 Mdl = IoAllocateMdl(Buffer, PAGE_SIZE, FALSE, FALSE, 0);
714 if (!Mdl)
715 {
716 //
717 // failed to allocate mdl
718 //
719 ExFreePoolWithTag(Buffer, TAG_USBOHCI);
720 return STATUS_INSUFFICIENT_RESOURCES;
721 }
722
723 //
724 // build mdl for non paged pool
725 //
726 MmBuildMdlForNonPagedPool(Mdl);
727
728 //
729 // commit packet
730 //
731 Status = CommitSetupPacket(&CtrlSetup, 0, PAGE_SIZE, Mdl);
732 if (!NT_SUCCESS(Status))
733 {
734 //
735 // failed to issue request, cleanup
736 //
737 IoFreeMdl(Mdl);
738 ExFreePool(Buffer);
739 return Status;
740 }
741
742 //
743 // now free the mdl
744 //
745 IoFreeMdl(Mdl);
746
747 //
748 // get configuration descriptor
749 //
750 ConfigurationDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)Buffer;
751
752 //
753 // informal debug print
754 //
755 DumpConfigurationDescriptor(ConfigurationDescriptor);
756
757 //
758 // sanity check
759 //
760 PC_ASSERT(ConfigurationDescriptor->bLength == sizeof(USB_CONFIGURATION_DESCRIPTOR));
761 PC_ASSERT(ConfigurationDescriptor->wTotalLength <= PAGE_SIZE);
762 PC_ASSERT(ConfigurationDescriptor->bNumInterfaces);
763
764 //
765 // store configuration descriptor
766 //
767 m_ConfigurationDescriptors[Index] = ConfigurationDescriptor;
768
769 //
770 // done
771 //
772 return Status;
773 }
774 //----------------------------------------------------------------------------------------
775 VOID
776 CUSBDevice::GetConfigurationDescriptors(
777 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptorBuffer,
778 IN ULONG BufferLength,
779 OUT PULONG OutBufferLength)
780 {
781 //
782 // sanity check
783 //
784 PC_ASSERT(BufferLength >= sizeof(USB_CONFIGURATION_DESCRIPTOR));
785 PC_ASSERT(ConfigDescriptorBuffer);
786 PC_ASSERT(OutBufferLength);
787
788 //
789 // reset copied length
790 //
791 *OutBufferLength = 0;
792
793 //
794 // FIXME: support multiple configurations
795 //
796 PC_ASSERT(m_DeviceDescriptor.bNumConfigurations == 1);
797
798 //
799 // copy configuration descriptor
800 //
801 RtlCopyMemory(ConfigDescriptorBuffer, m_ConfigurationDescriptors[0], min(m_ConfigurationDescriptors[0]->wTotalLength, BufferLength));
802 *OutBufferLength = m_ConfigurationDescriptors[0]->wTotalLength;
803 }
804
805 //----------------------------------------------------------------------------------------
806 ULONG
807 CUSBDevice::GetConfigurationDescriptorsLength()
808 {
809 //
810 // FIXME: support multiple configurations
811 //
812 PC_ASSERT(m_DeviceDescriptor.bNumConfigurations == 1);
813
814 ASSERT(m_ConfigurationDescriptors[0]);
815 ASSERT(m_ConfigurationDescriptors[0]->wTotalLength);
816
817 return m_ConfigurationDescriptors[0]->wTotalLength;
818 }
819 //----------------------------------------------------------------------------------------
820 VOID
821 CUSBDevice::DumpDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor)
822 {
823 DPRINT1("Dumping Device Descriptor %x\n", DeviceDescriptor);
824 DPRINT1("bLength %x\n", DeviceDescriptor->bLength);
825 DPRINT1("bDescriptorType %x\n", DeviceDescriptor->bDescriptorType);
826 DPRINT1("bcdUSB %x\n", DeviceDescriptor->bcdUSB);
827 DPRINT1("bDeviceClass %x\n", DeviceDescriptor->bDeviceClass);
828 DPRINT1("bDeviceSubClass %x\n", DeviceDescriptor->bDeviceSubClass);
829 DPRINT1("bDeviceProtocol %x\n", DeviceDescriptor->bDeviceProtocol);
830 DPRINT1("bMaxPacketSize0 %x\n", DeviceDescriptor->bMaxPacketSize0);
831 DPRINT1("idVendor %x\n", DeviceDescriptor->idVendor);
832 DPRINT1("idProduct %x\n", DeviceDescriptor->idProduct);
833 DPRINT1("bcdDevice %x\n", DeviceDescriptor->bcdDevice);
834 DPRINT1("iManufacturer %x\n", DeviceDescriptor->iManufacturer);
835 DPRINT1("iProduct %x\n", DeviceDescriptor->iProduct);
836 DPRINT1("iSerialNumber %x\n", DeviceDescriptor->iSerialNumber);
837 DPRINT1("bNumConfigurations %x\n", DeviceDescriptor->bNumConfigurations);
838 }
839
840 //----------------------------------------------------------------------------------------
841 VOID
842 CUSBDevice::DumpConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
843 {
844 DPRINT1("Dumping ConfigurationDescriptor %x\n", ConfigurationDescriptor);
845 DPRINT1("bLength %x\n", ConfigurationDescriptor->bLength);
846 DPRINT1("bDescriptorType %x\n", ConfigurationDescriptor->bDescriptorType);
847 DPRINT1("wTotalLength %x\n", ConfigurationDescriptor->wTotalLength);
848 DPRINT1("bNumInterfaces %x\n", ConfigurationDescriptor->bNumInterfaces);
849 DPRINT1("bConfigurationValue %x\n", ConfigurationDescriptor->bConfigurationValue);
850 DPRINT1("iConfiguration %x\n", ConfigurationDescriptor->iConfiguration);
851 DPRINT1("bmAttributes %x\n", ConfigurationDescriptor->bmAttributes);
852 DPRINT1("MaxPower %x\n", ConfigurationDescriptor->MaxPower);
853 }
854 //----------------------------------------------------------------------------------------
855 NTSTATUS
856 CUSBDevice::SubmitSetupPacket(
857 IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
858 IN OUT ULONG BufferLength,
859 OUT PVOID Buffer)
860 {
861 NTSTATUS Status;
862 PMDL Mdl;
863
864 //
865 // allocate mdl
866 //
867 Mdl = IoAllocateMdl(Buffer, BufferLength, FALSE, FALSE, 0);
868
869 //
870 // HACK HACK HACK: assume the buffer is build from non paged pool
871 //
872 MmBuildMdlForNonPagedPool(Mdl);
873
874 //
875 // commit setup packet
876 //
877 Status = CommitSetupPacket(SetupPacket, 0, BufferLength, Mdl);
878
879 //
880 // free mdl
881 //
882 IoFreeMdl(Mdl);
883
884 //
885 // done
886 //
887 return Status;
888 }
889
890 //----------------------------------------------------------------------------------------
891 NTSTATUS
892 CUSBDevice::SelectConfiguration(
893 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
894 IN PUSBD_INTERFACE_INFORMATION InterfaceInfo,
895 OUT USBD_CONFIGURATION_HANDLE *ConfigurationHandle)
896 {
897 ULONG InterfaceIndex, PipeIndex;
898 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
899 NTSTATUS Status;
900 PUSB_CONFIGURATION_DESCRIPTOR CurrentConfigurationDescriptor;
901 PUSB_INTERFACE_DESCRIPTOR CurrentInterfaceDescriptor;
902 PUSB_ENDPOINT_DESCRIPTOR CurrentEndpointDescriptor;
903 PVOID StartPosition;
904
905 //
906 // FIXME: support multiple configurations
907 //
908 ASSERT(m_DeviceDescriptor.bNumConfigurations == 1);
909 ASSERT(m_ConfigurationDescriptors[0]);
910 CurrentConfigurationDescriptor = m_ConfigurationDescriptors[0];
911
912 //
913 // sanity check
914 //
915 PC_ASSERT(ConfigurationDescriptor->iConfiguration == CurrentConfigurationDescriptor->iConfiguration);
916 PC_ASSERT(ConfigurationDescriptor->bNumInterfaces <= CurrentConfigurationDescriptor->bNumInterfaces);
917 DPRINT1("CUSBDevice::SelectConfiguration NumInterfaces %lu\n", ConfigurationDescriptor->bNumInterfaces);
918
919
920 //
921 // copy interface info and pipe info
922 //
923 for(InterfaceIndex = 0; InterfaceIndex < ConfigurationDescriptor->bNumInterfaces; InterfaceIndex++)
924 {
925 //
926 // find interface descriptor
927 //
928 CurrentInterfaceDescriptor = USBD_ParseConfigurationDescriptor(CurrentConfigurationDescriptor, InterfaceInfo->InterfaceNumber, InterfaceInfo->AlternateSetting);
929
930 //
931 // sanity check
932 //
933 ASSERT(CurrentInterfaceDescriptor);
934 ASSERT(CurrentInterfaceDescriptor->bLength != 0);
935 ASSERT(InterfaceInfo->NumberOfPipes == CurrentInterfaceDescriptor->bNumEndpoints);
936 ASSERT(InterfaceInfo->Length != 0);
937 #ifdef _MSC_VER
938 PC_ASSERT(InterfaceInfo->Length == FIELD_OFFSET(USBD_INTERFACE_INFORMATION, Pipes[InterfaceInfo->NumberOfPipes]));
939 #endif
940
941 DPRINT1("CUSBDevice::SelectConfiguration InterfaceNumber %lu AlternativeSetting %lu bNumEndpoints %lu\n", InterfaceInfo->InterfaceNumber, InterfaceInfo->AlternateSetting, CurrentInterfaceDescriptor->bNumEndpoints);
942
943 //
944 // copy interface info
945 //
946 InterfaceInfo->InterfaceHandle = (USBD_INTERFACE_HANDLE)CurrentInterfaceDescriptor;
947 InterfaceInfo->Class = CurrentInterfaceDescriptor->bInterfaceClass;
948 InterfaceInfo->SubClass = CurrentInterfaceDescriptor->bInterfaceSubClass;
949 InterfaceInfo->Protocol = CurrentInterfaceDescriptor->bInterfaceProtocol;
950 InterfaceInfo->Reserved = 0;
951
952 //
953 // copy endpoint info
954 //
955 StartPosition = CurrentInterfaceDescriptor;
956 for(PipeIndex = 0; PipeIndex < InterfaceInfo->NumberOfPipes; PipeIndex++)
957 {
958 //
959 // find corresponding endpoint descriptor
960 //
961 CurrentEndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)USBD_ParseDescriptors(CurrentConfigurationDescriptor, CurrentConfigurationDescriptor->wTotalLength, StartPosition, USB_ENDPOINT_DESCRIPTOR_TYPE);
962
963 //
964 // sanity checks
965 //
966 ASSERT(CurrentEndpointDescriptor);
967 ASSERT(CurrentEndpointDescriptor->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE);
968
969 //
970 // copy pipe info
971 //
972 InterfaceInfo->Pipes[PipeIndex].MaximumPacketSize = CurrentEndpointDescriptor->wMaxPacketSize;
973 InterfaceInfo->Pipes[PipeIndex].EndpointAddress = CurrentEndpointDescriptor->bEndpointAddress;
974 InterfaceInfo->Pipes[PipeIndex].Interval = CurrentEndpointDescriptor->bInterval;
975 InterfaceInfo->Pipes[PipeIndex].PipeType = (USBD_PIPE_TYPE)CurrentEndpointDescriptor->bmAttributes;
976 InterfaceInfo->Pipes[PipeIndex].PipeHandle = (PVOID)CurrentEndpointDescriptor;
977
978 //
979 // move start position beyond the current endpoint descriptor
980 //
981 StartPosition = (PVOID)(CurrentEndpointDescriptor + 1);
982 }
983
984 //
985 // move offset
986 //
987 InterfaceInfo = (PUSBD_INTERFACE_INFORMATION)((ULONG_PTR)PtrToUlong(InterfaceInfo) + InterfaceInfo->Length);
988 }
989
990 //
991 // now build setup packet
992 //
993 RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
994 CtrlSetup.bRequest = USB_REQUEST_SET_CONFIGURATION;
995 CtrlSetup.wValue.W = ConfigurationDescriptor->bConfigurationValue;
996
997 //
998 // select configuration
999 //
1000 Status = CommitSetupPacket(&CtrlSetup, 0, 0, 0);
1001
1002 //
1003 // informal debug print
1004 //
1005 DPRINT1("CUsbDevice::SelectConfiguration New Configuration %x Old Configuration %x Result %x\n", ConfigurationDescriptor->iConfiguration, m_ConfigurationIndex, Status);
1006
1007 if (NT_SUCCESS(Status))
1008 {
1009 //
1010 // store configuration device index
1011 //
1012 m_ConfigurationIndex = ConfigurationDescriptor->iConfiguration;
1013
1014 //
1015 // store configuration handle
1016 //
1017 *ConfigurationHandle = m_ConfigurationDescriptors[0];
1018 }
1019
1020 //
1021 // done
1022 //
1023 return Status;
1024 }
1025
1026 //----------------------------------------------------------------------------------------
1027 NTSTATUS
1028 CUSBDevice::SelectInterface(
1029 IN USBD_CONFIGURATION_HANDLE ConfigurationHandle,
1030 IN OUT PUSBD_INTERFACE_INFORMATION InterfaceInfo)
1031 {
1032 PUSB_CONFIGURATION_DESCRIPTOR Configuration;
1033 ULONG PipeIndex;
1034 USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
1035 NTSTATUS Status;
1036 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
1037 PUSB_ENDPOINT_DESCRIPTOR CurrentEndpointDescriptor;
1038 PVOID StartPosition;
1039
1040 //
1041 // FIXME support multiple configurations
1042 //
1043 PC_ASSERT(m_ConfigurationDescriptors[0] == (PUSB_CONFIGURATION_DESCRIPTOR)ConfigurationHandle);
1044
1045 //
1046 // get configuration struct
1047 //
1048 Configuration = (PUSB_CONFIGURATION_DESCRIPTOR)ConfigurationHandle;
1049
1050 //
1051 // sanity checks
1052 //
1053 PC_ASSERT(Configuration->bNumInterfaces > InterfaceInfo->InterfaceNumber);
1054 #ifdef _MSC_VER
1055 //PC_ASSERT(InterfaceInfo->Length == FIELD_OFFSET(USBD_INTERFACE_INFORMATION, Pipes[InterfaceInfo->NumberOfPipes]));
1056 #endif
1057
1058 //
1059 // FIXME: check bandwidth
1060 //
1061
1062 //
1063 // find interface number
1064 //
1065 InterfaceDescriptor = USBD_ParseConfigurationDescriptor(Configuration, InterfaceInfo->InterfaceNumber, InterfaceInfo->AlternateSetting);
1066 ASSERT(InterfaceDescriptor);
1067
1068 //
1069 // initialize setup packet
1070 //
1071 RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
1072 CtrlSetup.bRequest = USB_REQUEST_SET_INTERFACE;
1073 CtrlSetup.wValue.W = InterfaceDescriptor->bAlternateSetting;
1074 CtrlSetup.wIndex.W = InterfaceDescriptor->bInterfaceNumber;
1075 CtrlSetup.bmRequestType.B = 0x01;
1076
1077 //
1078 // issue request
1079 //
1080 Status = CommitSetupPacket(&CtrlSetup, 0, 0, 0);
1081
1082 //
1083 // informal debug print
1084 //
1085 DPRINT1("CUSBDevice::SelectInterface AlternateSetting %x InterfaceNumber %x Status %x\n", InterfaceInfo->AlternateSetting, InterfaceInfo->InterfaceNumber, Status);
1086 DPRINT1("CUSBDevice::SelectInterface bInterfaceNumber %u bAlternateSetting %u NumberOfPipes %u Length %lu\n",
1087 InterfaceDescriptor->bInterfaceNumber, InterfaceDescriptor->bAlternateSetting, InterfaceInfo->NumberOfPipes, InterfaceInfo->Length);
1088 InterfaceInfo->InterfaceHandle = InterfaceDescriptor;
1089 InterfaceInfo->NumberOfPipes = InterfaceDescriptor->bNumEndpoints;
1090
1091 //
1092 // are there end points
1093 //
1094 if (InterfaceDescriptor->bNumEndpoints)
1095 {
1096 //
1097 // sanity check
1098 //
1099 ASSERT(InterfaceInfo->Length == sizeof(USBD_INTERFACE_INFORMATION) + (InterfaceDescriptor->bNumEndpoints > 1 ? sizeof(USBD_PIPE_INFORMATION) * (InterfaceDescriptor->bNumEndpoints - 1) : 0));
1100
1101 //
1102 // store number of pipes
1103 //
1104 InterfaceInfo->NumberOfPipes = InterfaceDescriptor->bNumEndpoints;
1105
1106 StartPosition = InterfaceDescriptor;
1107 for(PipeIndex = 0; PipeIndex < InterfaceInfo->NumberOfPipes; PipeIndex++)
1108 {
1109 //
1110 // find corresponding endpoint descriptor
1111 //
1112 CurrentEndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)USBD_ParseDescriptors(Configuration, Configuration->wTotalLength, StartPosition, USB_ENDPOINT_DESCRIPTOR_TYPE);
1113
1114 //
1115 // sanity checks
1116 //
1117 ASSERT(CurrentEndpointDescriptor);
1118 ASSERT(CurrentEndpointDescriptor->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE);
1119
1120 //
1121 // copy pipe info
1122 //
1123 InterfaceInfo->Pipes[PipeIndex].MaximumPacketSize = CurrentEndpointDescriptor->wMaxPacketSize;
1124 InterfaceInfo->Pipes[PipeIndex].EndpointAddress = CurrentEndpointDescriptor->bEndpointAddress;
1125 InterfaceInfo->Pipes[PipeIndex].Interval = CurrentEndpointDescriptor->bInterval;
1126 InterfaceInfo->Pipes[PipeIndex].PipeType = (USBD_PIPE_TYPE)CurrentEndpointDescriptor->bmAttributes;
1127 InterfaceInfo->Pipes[PipeIndex].PipeHandle = (PVOID)CurrentEndpointDescriptor;
1128
1129 //
1130 // move start position beyond the current endpoint descriptor
1131 //
1132 StartPosition = (PVOID)(CurrentEndpointDescriptor + 1);
1133 }
1134 }
1135 //
1136 // done
1137 //
1138 return Status;
1139 }
1140
1141 //----------------------------------------------------------------------------------------
1142 NTSTATUS
1143 CreateUSBDevice(
1144 PUSBDEVICE *OutDevice)
1145 {
1146 CUSBDevice * This;
1147
1148 //
1149 // allocate controller
1150 //
1151 This = new(NonPagedPool, TAG_USBOHCI) CUSBDevice(0);
1152 if (!This)
1153 {
1154 //
1155 // failed to allocate
1156 //
1157 return STATUS_INSUFFICIENT_RESOURCES;
1158 }
1159
1160 //
1161 // add reference count
1162 //
1163 This->AddRef();
1164
1165 //
1166 // return result
1167 //
1168 *OutDevice = (PUSBDEVICE)This;
1169
1170 //
1171 // done
1172 //
1173 return STATUS_SUCCESS;
1174 }
1175