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