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