xref: /reactos/drivers/usb/usbd/usbd.c (revision c2c66aff)
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
DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath)46 DriverEntry(PDRIVER_OBJECT DriverObject,
47             PUNICODE_STRING RegistryPath)
48 {
49     return STATUS_SUCCESS;
50 }
51 
52 /*
53  * @implemented
54  */
55 ULONG NTAPI
DllInitialize(ULONG Unknown)56 DllInitialize(ULONG Unknown)
57 {
58     return 0;
59 }
60 
61 /*
62  * @implemented
63  */
64 ULONG NTAPI
DllUnload(VOID)65 DllUnload(VOID)
66 {
67     return 0;
68 }
69 
70 /*
71  * @implemented
72  */
73 PVOID NTAPI
USBD_Debug_GetHeap(ULONG Unknown1,POOL_TYPE PoolType,ULONG NumberOfBytes,ULONG Tag)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
USBD_Debug_RetHeap(PVOID Heap,ULONG Unknown2,ULONG Unknown3)84 USBD_Debug_RetHeap(PVOID Heap, ULONG Unknown2, ULONG Unknown3)
85 {
86     ExFreePool(Heap);
87 }
88 
89 /*
90  * @implemented
91  */
92 VOID NTAPI
USBD_Debug_LogEntry(PCHAR Name,ULONG_PTR Info1,ULONG_PTR Info2,ULONG_PTR Info3)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
USBD_AllocateDeviceName(ULONG Unknown)102 USBD_AllocateDeviceName(ULONG Unknown)
103 {
104     UNIMPLEMENTED;
105     return NULL;
106 }
107 
108 /*
109  * @implemented
110  */
111 ULONG NTAPI
USBD_CalculateUsbBandwidth(ULONG MaxPacketSize,UCHAR EndpointType,BOOLEAN LowSpeed)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
USBD_Dispatch(ULONG Unknown1,ULONG Unknown2,ULONG Unknown3,ULONG Unknown4)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
USBD_FreeDeviceMutex(PVOID Unknown)150 USBD_FreeDeviceMutex(PVOID Unknown)
151 {
152     UNIMPLEMENTED;
153 }
154 
155 /*
156  * @implemented
157  */
158 VOID NTAPI
USBD_FreeDeviceName(PVOID Unknown)159 USBD_FreeDeviceName(PVOID Unknown)
160 {
161     UNIMPLEMENTED;
162 }
163 
164 /*
165  * @implemented
166  */
167 VOID NTAPI
USBD_WaitDeviceMutex(PVOID Unknown)168 USBD_WaitDeviceMutex(PVOID Unknown)
169 {
170     UNIMPLEMENTED;
171 }
172 
173 /*
174  * @implemented
175  */
176 ULONG NTAPI
USBD_GetSuspendPowerState(ULONG Unknown1)177 USBD_GetSuspendPowerState(ULONG Unknown1)
178 {
179     UNIMPLEMENTED;
180     return 0;
181 }
182 
183 /*
184  * @implemented
185  */
186 NTSTATUS NTAPI
USBD_InitializeDevice(ULONG Unknown1,ULONG Unknown2,ULONG Unknown3,ULONG Unknown4,ULONG Unknown5,ULONG Unknown6)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
USBD_RegisterHostController(ULONG Unknown1,ULONG Unknown2,ULONG Unknown3,ULONG Unknown4,ULONG Unknown5,ULONG Unknown6,ULONG Unknown7,ULONG Unknown8,ULONG Unknown9,ULONG Unknown10)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
USBD_GetDeviceInformation(ULONG Unknown1,ULONG Unknown2,ULONG Unknown3)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
USBD_CreateDevice(ULONG Unknown1,ULONG Unknown2,ULONG Unknown3,ULONG Unknown4,ULONG Unknown5)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
USBD_RemoveDevice(ULONG Unknown1,ULONG Unknown2,ULONG Unknown3)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
USBD_CompleteRequest(ULONG Unknown1,ULONG Unknown2)241 USBD_CompleteRequest(ULONG Unknown1, ULONG Unknown2)
242 {
243     UNIMPLEMENTED;
244 }
245 
246 /*
247  * @implemented
248  */
249 VOID NTAPI
USBD_RegisterHcFilter(PDEVICE_OBJECT DeviceObject,PDEVICE_OBJECT FilterDeviceObject)250 USBD_RegisterHcFilter(
251     PDEVICE_OBJECT DeviceObject,
252     PDEVICE_OBJECT FilterDeviceObject
253     )
254 {
255     UNIMPLEMENTED;
256 }
257 
258 /*
259  * @implemented
260  */
261 VOID NTAPI
USBD_SetSuspendPowerState(ULONG Unknown1,ULONG Unknown2)262 USBD_SetSuspendPowerState(ULONG Unknown1, ULONG Unknown2)
263 {
264     UNIMPLEMENTED;
265 }
266 
267 /*
268  * @implemented
269  */
270 NTSTATUS NTAPI
USBD_MakePdoName(ULONG Unknown1,ULONG Unknown2)271 USBD_MakePdoName(ULONG Unknown1, ULONG Unknown2)
272 {
273     UNIMPLEMENTED;
274     return STATUS_NOT_SUPPORTED;
275 }
276 
277 /*
278  * @implemented
279  */
280 NTSTATUS NTAPI
USBD_QueryBusTime(PDEVICE_OBJECT RootHubPdo,PULONG CurrentFrame)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
USBD_GetUSBDIVersion(PUSBD_VERSION_INFORMATION Version)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
USBD_RestoreDevice(ULONG Unknown1,ULONG Unknown2,ULONG Unknown3)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
USBD_RegisterHcDeviceCapabilities(ULONG Unknown1,ULONG Unknown2,ULONG Unknown3)319 USBD_RegisterHcDeviceCapabilities(ULONG Unknown1, ULONG Unknown2,
320     ULONG Unknown3)
321 {
322     UNIMPLEMENTED;
323 }
324 
325 /*
326  * @implemented
327  */
328 PURB NTAPI
USBD_CreateConfigurationRequestEx(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,PUSBD_INTERFACE_LIST_ENTRY InterfaceList)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
USBD_CreateConfigurationRequest(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,PUSHORT Size)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
USBD_GetInterfaceLength(PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor,PUCHAR BufferEnd)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
USBD_ParseDescriptors(PVOID DescriptorBuffer,ULONG TotalLength,PVOID StartPosition,LONG DescriptorType)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
USBD_ParseConfigurationDescriptorEx(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,PVOID StartPosition,LONG InterfaceNumber,LONG AlternateSetting,LONG InterfaceClass,LONG InterfaceSubClass,LONG InterfaceProtocol)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 chosen 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
USBD_ParseConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,UCHAR InterfaceNumber,UCHAR AlternateSetting)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
USBD_GetPdoRegistryParameter(PDEVICE_OBJECT PhysicalDeviceObject,PVOID Parameter,ULONG ParameterLength,PWCHAR KeyName,ULONG KeyNameLength)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 }
689