Sync with trunk r63637.
[reactos.git] / drivers / usb / usbd / usbd.c
1 /*
2 * PROJECT: ReactOS Universal Serial Bus Driver/Helper Library
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbd/usbd.c
5 * PURPOSE: Helper Library for USB
6 * PROGRAMMERS:
7 * Filip Navara <xnavara@volny.cz>
8 * Michael Martin <michael.martin@reactos.org>
9 *
10 */
11
12 /*
13 * Universal Serial Bus Driver/Helper Library
14 *
15 * Written by Filip Navara <xnavara@volny.cz>
16 *
17 * Notes:
18 * This driver was obsoleted in Windows XP and most functions
19 * became pure stubs. But some of them were retained for backward
20 * compatibility with existing drivers.
21 *
22 * Preserved functions:
23 *
24 * USBD_Debug_GetHeap (implemented)
25 * USBD_Debug_RetHeap (implemented)
26 * USBD_CalculateUsbBandwidth (implemented, tested)
27 * USBD_CreateConfigurationRequestEx (implemented)
28 * USBD_CreateConfigurationRequest
29 * USBD_GetInterfaceLength (implemented)
30 * USBD_ParseConfigurationDescriptorEx (implemented)
31 * USBD_ParseDescriptors (implemented)
32 * USBD_GetPdoRegistryParameters (implemented)
33 */
34
35 #define _USBD_
36 #define NDEBUG
37 #include <ntddk.h>
38 #include <usbdi.h>
39 #include <usbdlib.h>
40 #include <debug.h>
41 #ifndef PLUGPLAY_REGKEY_DRIVER
42 #define PLUGPLAY_REGKEY_DRIVER 2
43 #endif
44
45 NTSTATUS NTAPI
46 DriverEntry(PDRIVER_OBJECT DriverObject,
47 PUNICODE_STRING RegistryPath)
48 {
49 return STATUS_SUCCESS;
50 }
51
52 /*
53 * @implemented
54 */
55 ULONG NTAPI
56 DllInitialize(ULONG Unknown)
57 {
58 return 0;
59 }
60
61 /*
62 * @implemented
63 */
64 ULONG NTAPI
65 DllUnload(VOID)
66 {
67 return 0;
68 }
69
70 /*
71 * @implemented
72 */
73 PVOID NTAPI
74 USBD_Debug_GetHeap(ULONG Unknown1, POOL_TYPE PoolType, ULONG NumberOfBytes,
75 ULONG Tag)
76 {
77 return ExAllocatePoolWithTag(PoolType, NumberOfBytes, Tag);
78 }
79
80 /*
81 * @implemented
82 */
83 VOID NTAPI
84 USBD_Debug_RetHeap(PVOID Heap, ULONG Unknown2, ULONG Unknown3)
85 {
86 ExFreePool(Heap);
87 }
88
89 /*
90 * @implemented
91 */
92 VOID NTAPI
93 USBD_Debug_LogEntry(PCHAR Name, ULONG_PTR Info1, ULONG_PTR Info2,
94 ULONG_PTR Info3)
95 {
96 }
97
98 /*
99 * @implemented
100 */
101 PVOID NTAPI
102 USBD_AllocateDeviceName(ULONG Unknown)
103 {
104 UNIMPLEMENTED
105 return NULL;
106 }
107
108 /*
109 * @implemented
110 */
111 ULONG NTAPI
112 USBD_CalculateUsbBandwidth(
113 ULONG MaxPacketSize,
114 UCHAR EndpointType,
115 BOOLEAN LowSpeed
116 )
117 {
118 ULONG OverheadTable[] = {
119 0x00, /* UsbdPipeTypeControl */
120 0x09, /* UsbdPipeTypeIsochronous */
121 0x00, /* UsbdPipeTypeBulk */
122 0x0d /* UsbdPipeTypeInterrupt */
123 };
124 ULONG Result;
125
126 if (OverheadTable[EndpointType] != 0)
127 {
128 Result = ((MaxPacketSize + OverheadTable[EndpointType]) * 8 * 7) / 6;
129 if (LowSpeed)
130 return Result << 3;
131 return Result;
132 }
133 return 0;
134 }
135
136 /*
137 * @implemented
138 */
139 ULONG NTAPI
140 USBD_Dispatch(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3, ULONG Unknown4)
141 {
142 UNIMPLEMENTED
143 return 1;
144 }
145
146 /*
147 * @implemented
148 */
149 VOID NTAPI
150 USBD_FreeDeviceMutex(PVOID Unknown)
151 {
152 UNIMPLEMENTED
153 }
154
155 /*
156 * @implemented
157 */
158 VOID NTAPI
159 USBD_FreeDeviceName(PVOID Unknown)
160 {
161 UNIMPLEMENTED
162 }
163
164 /*
165 * @implemented
166 */
167 VOID NTAPI
168 USBD_WaitDeviceMutex(PVOID Unknown)
169 {
170 UNIMPLEMENTED
171 }
172
173 /*
174 * @implemented
175 */
176 ULONG NTAPI
177 USBD_GetSuspendPowerState(ULONG Unknown1)
178 {
179 UNIMPLEMENTED
180 return 0;
181 }
182
183 /*
184 * @implemented
185 */
186 NTSTATUS NTAPI
187 USBD_InitializeDevice(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3,
188 ULONG Unknown4, ULONG Unknown5, ULONG Unknown6)
189 {
190 UNIMPLEMENTED
191 return STATUS_NOT_SUPPORTED;
192 }
193
194 /*
195 * @implemented
196 */
197 NTSTATUS NTAPI
198 USBD_RegisterHostController(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3,
199 ULONG Unknown4, ULONG Unknown5, ULONG Unknown6, ULONG Unknown7,
200 ULONG Unknown8, ULONG Unknown9, ULONG Unknown10)
201 {
202 UNIMPLEMENTED
203 return STATUS_NOT_SUPPORTED;
204 }
205
206 /*
207 * @implemented
208 */
209 NTSTATUS NTAPI
210 USBD_GetDeviceInformation(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3)
211 {
212 UNIMPLEMENTED
213 return STATUS_NOT_SUPPORTED;
214 }
215
216 /*
217 * @implemented
218 */
219 NTSTATUS NTAPI
220 USBD_CreateDevice(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3,
221 ULONG Unknown4, ULONG Unknown5)
222 {
223 UNIMPLEMENTED
224 return STATUS_NOT_SUPPORTED;
225 }
226
227 /*
228 * @implemented
229 */
230 NTSTATUS NTAPI
231 USBD_RemoveDevice(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3)
232 {
233 UNIMPLEMENTED
234 return STATUS_NOT_SUPPORTED;
235 }
236
237 /*
238 * @implemented
239 */
240 VOID NTAPI
241 USBD_CompleteRequest(ULONG Unknown1, ULONG Unknown2)
242 {
243 UNIMPLEMENTED
244 }
245
246 /*
247 * @implemented
248 */
249 VOID NTAPI
250 USBD_RegisterHcFilter(
251 PDEVICE_OBJECT DeviceObject,
252 PDEVICE_OBJECT FilterDeviceObject
253 )
254 {
255 UNIMPLEMENTED
256 }
257
258 /*
259 * @implemented
260 */
261 VOID NTAPI
262 USBD_SetSuspendPowerState(ULONG Unknown1, ULONG Unknown2)
263 {
264 UNIMPLEMENTED
265 }
266
267 /*
268 * @implemented
269 */
270 NTSTATUS NTAPI
271 USBD_MakePdoName(ULONG Unknown1, ULONG Unknown2)
272 {
273 UNIMPLEMENTED
274 return STATUS_NOT_SUPPORTED;
275 }
276
277 /*
278 * @implemented
279 */
280 NTSTATUS NTAPI
281 USBD_QueryBusTime(
282 PDEVICE_OBJECT RootHubPdo,
283 PULONG CurrentFrame
284 )
285 {
286 UNIMPLEMENTED
287 return STATUS_NOT_SUPPORTED;
288 }
289
290 /*
291 * @implemented
292 */
293 VOID NTAPI
294 USBD_GetUSBDIVersion(
295 PUSBD_VERSION_INFORMATION Version
296 )
297 {
298 if (Version != NULL)
299 {
300 Version->USBDI_Version = USBDI_VERSION;
301 Version->Supported_USB_Version = 0x200;
302 }
303 }
304
305 /*
306 * @implemented
307 */
308 NTSTATUS NTAPI
309 USBD_RestoreDevice(ULONG Unknown1, ULONG Unknown2, ULONG Unknown3)
310 {
311 UNIMPLEMENTED
312 return STATUS_NOT_SUPPORTED;
313 }
314
315 /*
316 * @implemented
317 */
318 VOID NTAPI
319 USBD_RegisterHcDeviceCapabilities(ULONG Unknown1, ULONG Unknown2,
320 ULONG Unknown3)
321 {
322 UNIMPLEMENTED
323 }
324
325 /*
326 * @implemented
327 */
328 PURB NTAPI
329 USBD_CreateConfigurationRequestEx(
330 PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
331 PUSBD_INTERFACE_LIST_ENTRY InterfaceList
332 )
333 {
334 PURB Urb;
335 ULONG UrbSize = 0;
336 ULONG InterfaceCount = 0, PipeCount = 0;
337 ULONG InterfaceNumber, EndPointNumber;
338 PUSBD_INTERFACE_INFORMATION InterfaceInfo;
339
340 while(InterfaceList[InterfaceCount].InterfaceDescriptor)
341 {
342 // pipe count
343 PipeCount += InterfaceList[InterfaceCount].InterfaceDescriptor->bNumEndpoints;
344
345 // interface count
346 InterfaceCount++;
347 }
348
349 // size of urb
350 UrbSize = GET_SELECT_CONFIGURATION_REQUEST_SIZE(InterfaceCount, PipeCount);
351
352 // allocate urb
353 Urb = ExAllocatePool(NonPagedPool, UrbSize);
354 if (!Urb)
355 {
356 // no memory
357 return NULL;
358 }
359
360 // zero urb
361 RtlZeroMemory(Urb, UrbSize);
362
363 // init urb header
364 Urb->UrbSelectConfiguration.Hdr.Function = URB_FUNCTION_SELECT_CONFIGURATION;
365 Urb->UrbSelectConfiguration.Hdr.Length = UrbSize;
366 Urb->UrbSelectConfiguration.ConfigurationDescriptor = ConfigurationDescriptor;
367
368 // init interface information
369 InterfaceInfo = &Urb->UrbSelectConfiguration.Interface;
370 for (InterfaceNumber = 0; InterfaceNumber < InterfaceCount; InterfaceNumber++)
371 {
372 // init interface info
373 InterfaceList[InterfaceNumber].Interface = InterfaceInfo;
374 InterfaceInfo->InterfaceNumber = InterfaceList[InterfaceNumber].InterfaceDescriptor->bInterfaceNumber;
375 InterfaceInfo->AlternateSetting = InterfaceList[InterfaceNumber].InterfaceDescriptor->bAlternateSetting;
376 InterfaceInfo->NumberOfPipes = InterfaceList[InterfaceNumber].InterfaceDescriptor->bNumEndpoints;
377
378 // store length
379 InterfaceInfo->Length = GET_USBD_INTERFACE_SIZE(InterfaceList[InterfaceNumber].InterfaceDescriptor->bNumEndpoints);
380
381 // sanity check
382 //C_ASSERT(FIELD_OFFSET(USBD_INTERFACE_INFORMATION, Pipes) == 16);
383
384 for (EndPointNumber = 0; EndPointNumber < InterfaceInfo->NumberOfPipes; EndPointNumber++)
385 {
386 // init max transfer size
387 InterfaceInfo->Pipes[EndPointNumber].MaximumTransferSize = PAGE_SIZE;
388 }
389
390 // next interface info
391 InterfaceInfo = (PUSBD_INTERFACE_INFORMATION) ((ULONG_PTR)InterfaceInfo + InterfaceInfo->Length);
392 }
393
394 return Urb;
395 }
396
397 /*
398 * @implemented
399 */
400 PURB NTAPI
401 USBD_CreateConfigurationRequest(
402 PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
403 PUSHORT Size
404 )
405 {
406 /* WindowsXP returns NULL */
407 return NULL;
408 }
409
410 /*
411 * @implemented
412 */
413 ULONG NTAPI
414 USBD_GetInterfaceLength(
415 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor,
416 PUCHAR BufferEnd
417 )
418 {
419 ULONG_PTR Current;
420 PUSB_INTERFACE_DESCRIPTOR CurrentDescriptor = InterfaceDescriptor;
421 ULONG Length = 0;
422 BOOLEAN InterfaceFound = FALSE;
423
424 for (Current = (ULONG_PTR)CurrentDescriptor;
425 Current < (ULONG_PTR)BufferEnd;
426 Current += CurrentDescriptor->bLength)
427 {
428 CurrentDescriptor = (PUSB_INTERFACE_DESCRIPTOR)Current;
429
430 if ((CurrentDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE) && (InterfaceFound))
431 break;
432 else if (CurrentDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
433 InterfaceFound = TRUE;
434
435 Length += CurrentDescriptor->bLength;
436 }
437
438 return Length;
439 }
440
441 /*
442 * @implemented
443 */
444 PUSB_COMMON_DESCRIPTOR NTAPI
445 USBD_ParseDescriptors(
446 PVOID DescriptorBuffer,
447 ULONG TotalLength,
448 PVOID StartPosition,
449 LONG DescriptorType
450 )
451 {
452 PUSB_COMMON_DESCRIPTOR CommonDescriptor;
453
454 /* use start position */
455 CommonDescriptor = (PUSB_COMMON_DESCRIPTOR)StartPosition;
456
457
458 /* find next available descriptor */
459 while(CommonDescriptor)
460 {
461 if ((ULONG_PTR)CommonDescriptor >= ((ULONG_PTR)DescriptorBuffer + TotalLength))
462 {
463 /* end reached */
464 DPRINT("End reached %p\n", CommonDescriptor);
465 return NULL;
466 }
467
468 DPRINT("CommonDescriptor Type %x Length %x\n", CommonDescriptor->bDescriptorType, CommonDescriptor->bLength);
469
470 /* is the requested one */
471 if (CommonDescriptor->bDescriptorType == DescriptorType)
472 {
473 /* it is */
474 return CommonDescriptor;
475 }
476
477 if (CommonDescriptor->bLength == 0)
478 {
479 /* invalid usb descriptor */
480 return NULL;
481 }
482
483 /* move to next descriptor */
484 CommonDescriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)CommonDescriptor + CommonDescriptor->bLength);
485 }
486
487 /* no descriptor found */
488 return NULL;
489 }
490
491
492 /*
493 * @implemented
494 */
495 PUSB_INTERFACE_DESCRIPTOR NTAPI
496 USBD_ParseConfigurationDescriptorEx(
497 PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
498 PVOID StartPosition,
499 LONG InterfaceNumber,
500 LONG AlternateSetting,
501 LONG InterfaceClass,
502 LONG InterfaceSubClass,
503 LONG InterfaceProtocol
504 )
505 {
506 BOOLEAN Found;
507 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
508
509 /* set to start position */
510 InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)StartPosition;
511
512 DPRINT("USBD_ParseConfigurationDescriptorEx\n");
513 DPRINT("ConfigurationDescriptor %p Length %lu\n", ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength);
514 DPRINT("CurrentOffset %p Offset %lu\n", StartPosition, ((ULONG_PTR)StartPosition - (ULONG_PTR)ConfigurationDescriptor));
515
516 while(InterfaceDescriptor)
517 {
518 /* get interface descriptor */
519 InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR) USBD_ParseDescriptors(ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength, InterfaceDescriptor, USB_INTERFACE_DESCRIPTOR_TYPE);
520 if (!InterfaceDescriptor)
521 {
522 /* no more descriptors available */
523 break;
524 }
525
526 DPRINT("InterfaceDescriptor %p InterfaceNumber %x AlternateSetting %x Length %lu\n", InterfaceDescriptor, InterfaceDescriptor->bInterfaceNumber, InterfaceDescriptor->bAlternateSetting, InterfaceDescriptor->bLength);
527
528 /* set found */
529 Found = TRUE;
530
531 /* is there an interface number provided */
532 if(InterfaceNumber != -1)
533 {
534 if(InterfaceNumber != InterfaceDescriptor->bInterfaceNumber)
535 {
536 /* interface number does not match */
537 Found = FALSE;
538 }
539 }
540
541 /* is there an alternate setting provided */
542 if(AlternateSetting != -1)
543 {
544 if(AlternateSetting != InterfaceDescriptor->bAlternateSetting)
545 {
546 /* alternate setting does not match */
547 Found = FALSE;
548 }
549 }
550
551 /* match on interface class */
552 if(InterfaceClass != -1)
553 {
554 if(InterfaceClass != InterfaceDescriptor->bInterfaceClass)
555 {
556 /* no match with interface class criteria */
557 Found = FALSE;
558 }
559 }
560
561 /* match on interface sub class */
562 if(InterfaceSubClass != -1)
563 {
564 if(InterfaceSubClass != InterfaceDescriptor->bInterfaceSubClass)
565 {
566 /* no interface sub class match */
567 Found = FALSE;
568 }
569 }
570
571 /* interface protocol criteria */
572 if(InterfaceProtocol != -1)
573 {
574 if(InterfaceProtocol != InterfaceDescriptor->bInterfaceProtocol)
575 {
576 /* no interface protocol match */
577 Found = FALSE;
578 }
579 }
580
581 if (Found)
582 {
583 /* the choosen one */
584 return InterfaceDescriptor;
585 }
586
587 /* sanity check */
588 ASSERT(InterfaceDescriptor->bLength);
589
590 /* move to next descriptor */
591 InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
592 }
593
594 DPRINT("No Descriptor With InterfaceNumber %ld AlternateSetting %ld InterfaceClass %ld InterfaceSubClass %ld InterfaceProtocol %ld found\n", InterfaceNumber,
595 AlternateSetting, InterfaceClass, InterfaceSubClass, InterfaceProtocol);
596
597 return NULL;
598 }
599
600 /*
601 * @implemented
602 */
603 PUSB_INTERFACE_DESCRIPTOR NTAPI
604 USBD_ParseConfigurationDescriptor(
605 PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
606 UCHAR InterfaceNumber,
607 UCHAR AlternateSetting
608 )
609 {
610 return USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor,
611 (PVOID)ConfigurationDescriptor, InterfaceNumber, AlternateSetting,
612 -1, -1, -1);
613 }
614
615
616 /*
617 * @implemented
618 */
619 ULONG NTAPI
620 USBD_GetPdoRegistryParameter(
621 PDEVICE_OBJECT PhysicalDeviceObject,
622 PVOID Parameter,
623 ULONG ParameterLength,
624 PWCHAR KeyName,
625 ULONG KeyNameLength
626 )
627 {
628 NTSTATUS Status;
629 HANDLE DevInstRegKey;
630
631 /* Open the device key */
632 Status = IoOpenDeviceRegistryKey(PhysicalDeviceObject,
633 PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_ALL, &DevInstRegKey);
634 if (NT_SUCCESS(Status))
635 {
636 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo;
637 UNICODE_STRING ValueName;
638 ULONG Length;
639
640 /* Initialize the unicode string based on caller data */
641 ValueName.Buffer = KeyName;
642 ValueName.Length = ValueName.MaximumLength = KeyNameLength;
643
644 Length = ParameterLength + sizeof(KEY_VALUE_PARTIAL_INFORMATION);
645 PartialInfo = ExAllocatePool(PagedPool, Length);
646 if (PartialInfo)
647 {
648 Status = ZwQueryValueKey(DevInstRegKey, &ValueName,
649 KeyValuePartialInformation, PartialInfo, Length, &Length);
650 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
651 {
652 /* The caller doesn't want all the data */
653 ExFreePool(PartialInfo);
654 PartialInfo = ExAllocatePool(PagedPool, Length);
655 if (PartialInfo)
656 {
657 Status = ZwQueryValueKey(DevInstRegKey, &ValueName,
658 KeyValuePartialInformation, PartialInfo, Length, &Length);
659 }
660 else
661 {
662 Status = STATUS_NO_MEMORY;
663 }
664 }
665
666 if (NT_SUCCESS(Status))
667 {
668 /* Compute the length to copy back */
669 if (ParameterLength < PartialInfo->DataLength)
670 Length = ParameterLength;
671 else
672 Length = PartialInfo->DataLength;
673
674 RtlCopyMemory(Parameter,
675 PartialInfo->Data,
676 Length);
677 }
678
679 if (PartialInfo)
680 {
681 ExFreePool(PartialInfo);
682 }
683 } else
684 Status = STATUS_NO_MEMORY;
685 ZwClose(DevInstRegKey);
686 }
687 return Status;
688 }