df273ee3f8aba00a36410fcd0e53e62a4998b1de
[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 #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 /* sanity check */
478 ASSERT(CommonDescriptor->bLength);
479
480 /* move to next descriptor */
481 CommonDescriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)CommonDescriptor + CommonDescriptor->bLength);
482 }
483
484 /* no descriptor found */
485 return NULL;
486 }
487
488
489 /*
490 * @implemented
491 */
492 PUSB_INTERFACE_DESCRIPTOR NTAPI
493 USBD_ParseConfigurationDescriptorEx(
494 PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
495 PVOID StartPosition,
496 LONG InterfaceNumber,
497 LONG AlternateSetting,
498 LONG InterfaceClass,
499 LONG InterfaceSubClass,
500 LONG InterfaceProtocol
501 )
502 {
503 BOOLEAN Found;
504 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
505
506 /* set to start position */
507 InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)StartPosition;
508
509 DPRINT("USBD_ParseConfigurationDescriptorEx\n");
510 DPRINT("ConfigurationDescriptor %p Length %lu\n", ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength);
511 DPRINT("CurrentOffset %p Offset %lu\n", StartPosition, ((ULONG_PTR)StartPosition - (ULONG_PTR)ConfigurationDescriptor));
512
513 while(InterfaceDescriptor)
514 {
515 /* get interface descriptor */
516 InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR) USBD_ParseDescriptors(ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength, InterfaceDescriptor, USB_INTERFACE_DESCRIPTOR_TYPE);
517 if (!InterfaceDescriptor)
518 {
519 /* no more descriptors available */
520 break;
521 }
522
523 DPRINT("InterfaceDescriptor %p InterfaceNumber %x AlternateSetting %x Length %lu\n", InterfaceDescriptor, InterfaceDescriptor->bInterfaceNumber, InterfaceDescriptor->bAlternateSetting, InterfaceDescriptor->bLength);
524
525 /* set found */
526 Found = TRUE;
527
528 /* is there an interface number provided */
529 if(InterfaceNumber != -1)
530 {
531 if(InterfaceNumber != InterfaceDescriptor->bInterfaceNumber)
532 {
533 /* interface number does not match */
534 Found = FALSE;
535 }
536 }
537
538 /* is there an alternate setting provided */
539 if(AlternateSetting != -1)
540 {
541 if(AlternateSetting != InterfaceDescriptor->bAlternateSetting)
542 {
543 /* alternate setting does not match */
544 Found = FALSE;
545 }
546 }
547
548 /* match on interface class */
549 if(InterfaceClass != -1)
550 {
551 if(InterfaceClass != InterfaceDescriptor->bInterfaceClass)
552 {
553 /* no match with interface class criteria */
554 Found = FALSE;
555 }
556 }
557
558 /* match on interface sub class */
559 if(InterfaceSubClass != -1)
560 {
561 if(InterfaceSubClass != InterfaceDescriptor->bInterfaceSubClass)
562 {
563 /* no interface sub class match */
564 Found = FALSE;
565 }
566 }
567
568 /* interface protocol criteria */
569 if(InterfaceProtocol != -1)
570 {
571 if(InterfaceProtocol != InterfaceDescriptor->bInterfaceProtocol)
572 {
573 /* no interface protocol match */
574 Found = FALSE;
575 }
576 }
577
578 if (Found)
579 {
580 /* the choosen one */
581 return InterfaceDescriptor;
582 }
583
584 /* sanity check */
585 ASSERT(InterfaceDescriptor->bLength);
586
587 /* move to next descriptor */
588 InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
589 }
590
591 DPRINT("No Descriptor With InterfaceNumber %ld AlternateSetting %ld InterfaceClass %ld InterfaceSubClass %ld InterfaceProtocol %ld found\n", InterfaceNumber,
592 AlternateSetting, InterfaceClass, InterfaceSubClass, InterfaceProtocol);
593
594 return NULL;
595 }
596
597 /*
598 * @implemented
599 */
600 PUSB_INTERFACE_DESCRIPTOR NTAPI
601 USBD_ParseConfigurationDescriptor(
602 PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
603 UCHAR InterfaceNumber,
604 UCHAR AlternateSetting
605 )
606 {
607 return USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor,
608 (PVOID)ConfigurationDescriptor, InterfaceNumber, AlternateSetting,
609 -1, -1, -1);
610 }
611
612
613 /*
614 * @implemented
615 */
616 ULONG NTAPI
617 USBD_GetPdoRegistryParameter(
618 PDEVICE_OBJECT PhysicalDeviceObject,
619 PVOID Parameter,
620 ULONG ParameterLength,
621 PWCHAR KeyName,
622 ULONG KeyNameLength
623 )
624 {
625 NTSTATUS Status;
626 HANDLE DevInstRegKey;
627
628 /* Open the device key */
629 Status = IoOpenDeviceRegistryKey(PhysicalDeviceObject,
630 PLUGPLAY_REGKEY_DEVICE, STANDARD_RIGHTS_ALL, &DevInstRegKey);
631 if (NT_SUCCESS(Status))
632 {
633 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo;
634 UNICODE_STRING ValueName;
635 ULONG Length;
636
637 /* Initialize the unicode string based on caller data */
638 ValueName.Buffer = KeyName;
639 ValueName.Length = ValueName.MaximumLength = KeyNameLength;
640
641 Length = ParameterLength + sizeof(KEY_VALUE_PARTIAL_INFORMATION);
642 PartialInfo = ExAllocatePool(PagedPool, Length);
643 if (PartialInfo)
644 {
645 Status = ZwQueryValueKey(DevInstRegKey, &ValueName,
646 KeyValuePartialInformation, PartialInfo, Length, &Length);
647 if (Status == STATUS_BUFFER_OVERFLOW || Status == STATUS_BUFFER_TOO_SMALL)
648 {
649 /* The caller doesn't want all the data */
650 ExFreePool(PartialInfo);
651 PartialInfo = ExAllocatePool(PagedPool, Length);
652 if (PartialInfo)
653 {
654 Status = ZwQueryValueKey(DevInstRegKey, &ValueName,
655 KeyValuePartialInformation, PartialInfo, Length, &Length);
656 }
657 else
658 {
659 Status = STATUS_NO_MEMORY;
660 }
661 }
662
663 if (NT_SUCCESS(Status))
664 {
665 /* Compute the length to copy back */
666 if (ParameterLength < PartialInfo->DataLength)
667 Length = ParameterLength;
668 else
669 Length = PartialInfo->DataLength;
670
671 RtlCopyMemory(Parameter,
672 PartialInfo->Data,
673 Length);
674 }
675
676 if (PartialInfo)
677 {
678 ExFreePool(PartialInfo);
679 }
680 } else
681 Status = STATUS_NO_MEMORY;
682 ZwClose(DevInstRegKey);
683 }
684 return Status;
685 }