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