[USB-BRINGUP]
[reactos.git] / drivers / hid / hidclass / pdo.c
1 /*
2 * PROJECT: ReactOS Universal Serial Bus Human Interface Device Driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/hid/hidclass/fdo.c
5 * PURPOSE: HID Class Driver
6 * PROGRAMMERS:
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
9 */
10 #include "precomp.h"
11
12 PHIDP_COLLECTION_DESC
13 HidClassPDO_GetCollectionDescription(
14 PHIDP_DEVICE_DESC DeviceDescription,
15 ULONG CollectionNumber)
16 {
17 ULONG Index;
18
19 for(Index = 0; Index < DeviceDescription->CollectionDescLength; Index++)
20 {
21 if (DeviceDescription->CollectionDesc[Index].CollectionNumber == CollectionNumber)
22 {
23 //
24 // found collection
25 //
26 return &DeviceDescription->CollectionDesc[Index];
27 }
28 }
29
30 //
31 // failed to find collection
32 //
33 DPRINT1("[HIDCLASS] GetCollectionDescription CollectionNumber %x not found\n", CollectionNumber);
34 ASSERT(FALSE);
35 return NULL;
36 }
37
38 PHIDP_REPORT_IDS
39 HidClassPDO_GetReportDescription(
40 PHIDP_DEVICE_DESC DeviceDescription,
41 ULONG CollectionNumber)
42 {
43 ULONG Index;
44
45 for(Index = 0; Index < DeviceDescription->ReportIDsLength; Index++)
46 {
47 if (DeviceDescription->ReportIDs[Index].CollectionNumber == CollectionNumber)
48 {
49 //
50 // found collection
51 //
52 return &DeviceDescription->ReportIDs[Index];
53 }
54 }
55
56 //
57 // failed to find collection
58 //
59 DPRINT1("[HIDCLASS] GetReportDescription CollectionNumber %x not found\n", CollectionNumber);
60 ASSERT(FALSE);
61 return NULL;
62 }
63
64 NTSTATUS
65 HidClassPDO_HandleQueryDeviceId(
66 IN PDEVICE_OBJECT DeviceObject,
67 IN PIRP Irp)
68 {
69 NTSTATUS Status;
70 LPWSTR Buffer;
71 LPWSTR NewBuffer, Ptr;
72 ULONG Length;
73
74 //
75 // copy current stack location
76 //
77 IoCopyCurrentIrpStackLocationToNext(Irp);
78
79 //
80 // call mini-driver
81 //
82 Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
83 if (!NT_SUCCESS(Status))
84 {
85 //
86 // failed
87 //
88 return Status;
89 }
90
91 //
92 // get buffer
93 //
94 Buffer = (LPWSTR)Irp->IoStatus.Information;
95 Length = wcslen(Buffer);
96
97 //
98 // allocate new buffer
99 //
100 NewBuffer = (LPWSTR)ExAllocatePool(NonPagedPool, (Length + 1) * sizeof(WCHAR));
101 if (!NewBuffer)
102 {
103 //
104 // failed to allocate buffer
105 //
106 return STATUS_INSUFFICIENT_RESOURCES;
107 }
108
109 //
110 // replace bus
111 //
112 wcscpy(NewBuffer, L"HID\\");
113
114 //
115 // get offset to first '\\'
116 //
117 Ptr = wcschr(Buffer, L'\\');
118 if (Ptr)
119 {
120 //
121 // append result
122 //
123 wcscat(NewBuffer, Ptr + 1);
124 }
125
126 //
127 // free old buffer
128 //
129 ExFreePool(Buffer);
130
131 //
132 // store result
133 //
134 Irp->IoStatus.Information = (ULONG_PTR)NewBuffer;
135 return STATUS_SUCCESS;
136 }
137
138 NTSTATUS
139 HidClassPDO_HandleQueryHardwareId(
140 IN PDEVICE_OBJECT DeviceObject,
141 IN PIRP Irp)
142 {
143 NTSTATUS Status;
144 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension;
145 WCHAR Buffer[100];
146 ULONG Offset = 0;
147 LPWSTR Ptr;
148 PHIDP_COLLECTION_DESC CollectionDescription;
149
150 //
151 // get device extension
152 //
153 PDODeviceExtension = (PHIDCLASS_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
154 ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
155
156 //
157 // copy current stack location
158 //
159 IoCopyCurrentIrpStackLocationToNext(Irp);
160
161 //
162 // call mini-driver
163 //
164 Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
165 if (!NT_SUCCESS(Status))
166 {
167 //
168 // failed
169 //
170 return Status;
171 }
172
173 if (PDODeviceExtension->Common.DeviceDescription.CollectionDescLength > 1)
174 {
175 //
176 // multi-tlc device
177 //
178 Offset = swprintf(&Buffer[Offset], L"HID\\Vid_%04x&Pid_%04x&Rev_%04x&Col%02x", PDODeviceExtension->Common.Attributes.VendorID, PDODeviceExtension->Common.Attributes.ProductID, PDODeviceExtension->Common.Attributes.VersionNumber, PDODeviceExtension->CollectionNumber) + 1;
179 Offset += swprintf(&Buffer[Offset], L"HID\\Vid_%04x&Pid_%04x&Col%02x", PDODeviceExtension->Common.Attributes.VendorID, PDODeviceExtension->Common.Attributes.ProductID, PDODeviceExtension->CollectionNumber) + 1;
180 }
181 else
182 {
183 //
184 // single tlc device
185 //
186 Offset = swprintf(&Buffer[Offset], L"HID\\Vid_%04x&Pid_%04x&Rev_%04x", PDODeviceExtension->Common.Attributes.VendorID, PDODeviceExtension->Common.Attributes.ProductID, PDODeviceExtension->Common.Attributes.VersionNumber) + 1;
187 Offset += swprintf(&Buffer[Offset], L"HID\\Vid_%04x&Pid_%04x", PDODeviceExtension->Common.Attributes.VendorID, PDODeviceExtension->Common.Attributes.ProductID) + 1;
188 }
189
190 //
191 // get collection description
192 //
193 CollectionDescription = HidClassPDO_GetCollectionDescription(&PDODeviceExtension->Common.DeviceDescription, PDODeviceExtension->CollectionNumber);
194 ASSERT(CollectionDescription);
195
196 if (CollectionDescription->UsagePage == HID_USAGE_PAGE_GENERIC)
197 {
198 switch(CollectionDescription->Usage)
199 {
200 case HID_USAGE_GENERIC_POINTER:
201 case HID_USAGE_GENERIC_MOUSE:
202 //
203 // Pointer / Mouse
204 //
205 Offset += swprintf(&Buffer[Offset], L"HID_DEVICE_SYSTEM_MOUSE") + 1;
206 break;
207 case HID_USAGE_GENERIC_GAMEPAD:
208 case HID_USAGE_GENERIC_JOYSTICK:
209 //
210 // Joystick / Gamepad
211 //
212 Offset += swprintf(&Buffer[Offset], L"HID_DEVICE_SYSTEM_GAME") + 1;
213 break;
214 case HID_USAGE_GENERIC_KEYBOARD:
215 case HID_USAGE_GENERIC_KEYPAD:
216 //
217 // Keyboard / Keypad
218 //
219 Offset += swprintf(&Buffer[Offset], L"HID_DEVICE_SYSTEM_KEYBOARD") + 1;
220 break;
221 case HID_USAGE_GENERIC_SYSTEM_CTL:
222 //
223 // System Control
224 //
225 Offset += swprintf(&Buffer[Offset], L"HID_DEVICE_SYSTEM_CONTROL") + 1;
226 break;
227 }
228 }
229 else if (CollectionDescription->UsagePage == HID_USAGE_PAGE_CONSUMER && CollectionDescription->Usage == HID_USAGE_CONSUMERCTRL)
230 {
231 //
232 // Consumer Audio Control
233 //
234 Offset += swprintf(&Buffer[Offset], L"HID_DEVICE_SYSTEM_CONSUMER") + 1;
235 }
236
237 //
238 // FIXME: add 'HID_DEVICE_UP:0001_U:0002'
239 //
240
241 //
242 // add HID
243 //
244 Offset +=swprintf(&Buffer[Offset], L"HID_DEVICE") + 1;
245
246 //
247 // free old buffer
248 //
249 ExFreePool((PVOID)Irp->IoStatus.Information);
250
251 //
252 // allocate buffer
253 //
254 Ptr = (LPWSTR)ExAllocatePool(NonPagedPool, (Offset +1)* sizeof(WCHAR));
255 if (!Ptr)
256 {
257 //
258 // no memory
259 //
260 Irp->IoStatus.Information = 0;
261 return STATUS_INSUFFICIENT_RESOURCES;
262 }
263
264 //
265 // copy buffer
266 //
267 RtlCopyMemory(Ptr, Buffer, Offset * sizeof(WCHAR));
268 Ptr[Offset] = UNICODE_NULL;
269
270 //
271 // store result
272 //
273 Irp->IoStatus.Information = (ULONG_PTR)Ptr;
274 return STATUS_SUCCESS;
275 }
276
277 NTSTATUS
278 HidClassPDO_HandleQueryInstanceId(
279 IN PDEVICE_OBJECT DeviceObject,
280 IN PIRP Irp)
281 {
282 NTSTATUS Status;
283
284 //
285 // copy current stack location
286 //
287 IoCopyCurrentIrpStackLocationToNext(Irp);
288
289 //
290 // call mini-driver
291 //
292 Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
293 if (!NT_SUCCESS(Status))
294 {
295 //
296 // failed
297 //
298 return Status;
299 }
300 DPRINT1("HidClassPDO_HandleQueryInstanceId Buffer %S\n", Irp->IoStatus.Information);
301 //
302 //TODO implement instance id
303 // example:
304 // HID\VID_045E&PID_0047\8&1A0700BC&0&0000
305 return STATUS_NOT_IMPLEMENTED;
306 }
307
308 NTSTATUS
309 HidClassPDO_HandleQueryCompatibleId(
310 IN PDEVICE_OBJECT DeviceObject,
311 IN PIRP Irp)
312 {
313 NTSTATUS Status;
314
315 //
316 // copy current stack location
317 //
318 IoCopyCurrentIrpStackLocationToNext(Irp);
319
320 //
321 // call mini-driver
322 //
323 Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
324 if (!NT_SUCCESS(Status))
325 {
326 //
327 // failed
328 //
329 return Status;
330 }
331
332 //
333 // FIXME: implement me
334 //
335 return STATUS_NOT_IMPLEMENTED;
336 }
337
338
339 NTSTATUS
340 HidClassPDO_PnP(
341 IN PDEVICE_OBJECT DeviceObject,
342 IN PIRP Irp)
343 {
344 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension;
345 PIO_STACK_LOCATION IoStack;
346 NTSTATUS Status;
347 PPNP_BUS_INFORMATION BusInformation;
348 PDEVICE_RELATIONS DeviceRelation;
349
350 //
351 // get device extension
352 //
353 PDODeviceExtension = (PHIDCLASS_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
354 ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
355
356 //
357 // get current irp stack location
358 //
359 IoStack = IoGetCurrentIrpStackLocation(Irp);
360
361 //
362 // handle request
363 //
364 switch(IoStack->MinorFunction)
365 {
366 case IRP_MN_QUERY_ID:
367 {
368 if (IoStack->Parameters.QueryId.IdType == BusQueryDeviceID)
369 {
370 //
371 // handle query device id
372 //
373 Status = HidClassPDO_HandleQueryDeviceId(DeviceObject, Irp);
374 break;
375 }
376 else if (IoStack->Parameters.QueryId.IdType == BusQueryHardwareIDs)
377 {
378 //
379 // handle instance id
380 //
381 Status = HidClassPDO_HandleQueryHardwareId(DeviceObject, Irp);
382 break;
383 }
384 else if (IoStack->Parameters.QueryId.IdType == BusQueryInstanceID)
385 {
386 //
387 // handle instance id
388 //
389 Status = HidClassPDO_HandleQueryInstanceId(DeviceObject, Irp);
390 break;
391 }
392 else if (IoStack->Parameters.QueryId.IdType == BusQueryCompatibleIDs)
393 {
394 //
395 // handle instance id
396 //
397 Status = HidClassPDO_HandleQueryCompatibleId(DeviceObject, Irp);
398 break;
399 }
400
401 DPRINT1("[HIDCLASS]: IRP_MN_QUERY_ID IdType %x unimplemented\n", IoStack->Parameters.QueryId.IdType);
402 Status = STATUS_NOT_SUPPORTED;
403 Irp->IoStatus.Information = 0;
404 break;
405 }
406 case IRP_MN_QUERY_CAPABILITIES:
407 {
408 if (IoStack->Parameters.DeviceCapabilities.Capabilities == NULL)
409 {
410 //
411 // invalid request
412 //
413 Status = STATUS_DEVICE_CONFIGURATION_ERROR;
414 }
415
416 //
417 // copy capabilities
418 //
419 RtlCopyMemory(IoStack->Parameters.DeviceCapabilities.Capabilities, &PDODeviceExtension->Capabilities, sizeof(DEVICE_CAPABILITIES));
420 Status = STATUS_SUCCESS;
421 break;
422 }
423 case IRP_MN_QUERY_BUS_INFORMATION:
424 {
425 //
426 //
427 //
428 BusInformation = (PPNP_BUS_INFORMATION)ExAllocatePool(NonPagedPool, sizeof(PNP_BUS_INFORMATION));
429
430 //
431 // fill in result
432 //
433 RtlCopyMemory(&BusInformation->BusTypeGuid, &GUID_BUS_TYPE_HID, sizeof(GUID));
434 BusInformation->LegacyBusType = PNPBus;
435 BusInformation->BusNumber = 0; //FIXME
436
437 //
438 // store result
439 //
440 Irp->IoStatus.Information = (ULONG_PTR)BusInformation;
441 Status = STATUS_SUCCESS;
442 break;
443 }
444 case IRP_MN_QUERY_PNP_DEVICE_STATE:
445 {
446 //
447 // FIXME set flags when driver fails / disabled
448 //
449 Status = STATUS_SUCCESS;
450 break;
451 }
452 case IRP_MN_QUERY_DEVICE_RELATIONS:
453 {
454 //
455 // only target relations are supported
456 //
457 if (IoStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
458 {
459 //
460 // not supported
461 //
462 Status = Irp->IoStatus.Status;
463 break;
464 }
465
466 //
467 // allocate device relations
468 //
469 DeviceRelation = (PDEVICE_RELATIONS)ExAllocatePool(NonPagedPool, sizeof(DEVICE_RELATIONS));
470 if (!DeviceRelation)
471 {
472 //
473 // no memory
474 //
475 Status = STATUS_INSUFFICIENT_RESOURCES;
476 break;
477 }
478
479 //
480 // init device relation
481 //
482 DeviceRelation->Count = 1;
483 DeviceRelation->Objects[0] = DeviceObject;
484 ObReferenceObject(DeviceRelation->Objects[0]);
485
486 //
487 // store result
488 //
489 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelation;
490 Status = STATUS_SUCCESS;
491 break;
492 }
493 case IRP_MN_START_DEVICE:
494 {
495 //
496 // FIXME: support polled devices
497 //
498 ASSERT(PDODeviceExtension->Common.DriverExtension->DevicesArePolled == FALSE);
499
500 //
501 // now register the device interface
502 //
503 Status = IoRegisterDeviceInterface(PDODeviceExtension->Common.HidDeviceExtension.PhysicalDeviceObject, &GUID_DEVINTERFACE_HID, NULL, &PDODeviceExtension->DeviceInterface);
504 DPRINT1("[HIDCLASS] IoRegisterDeviceInterfaceState Status %x\n", Status);
505 if (NT_SUCCESS(Status))
506 {
507 //
508 // enable device interface
509 //
510 Status = IoSetDeviceInterfaceState(&PDODeviceExtension->DeviceInterface, TRUE);
511 DPRINT1("[HIDCLASS] IoSetDeviceInterFaceState %x\n", Status);
512 }
513 ASSERT(Status == STATUS_SUCCESS);
514 //
515 // break
516 //
517 break;
518 }
519 case IRP_MN_REMOVE_DEVICE:
520 {
521 DPRINT1("[HIDCLASS] PDO IRP_MN_REMOVE_DEVICE not implemented\n");
522 ASSERT(FALSE);
523
524 //
525 // do nothing
526 //
527 Status = STATUS_SUCCESS; //Irp->IoStatus.Status;
528 break;
529 }
530 case IRP_MN_QUERY_INTERFACE:
531 {
532 DPRINT1("[HIDCLASS] PDO IRP_MN_QUERY_INTERFACE not implemented\n");
533 ASSERT(FALSE);
534
535 //
536 // do nothing
537 //
538 Status = Irp->IoStatus.Status;
539 break;
540 }
541 default:
542 {
543 //
544 // do nothing
545 //
546 Status = Irp->IoStatus.Status;
547 break;
548 }
549 }
550
551 //
552 // complete request
553 //
554 if (Status != STATUS_PENDING)
555 {
556 //
557 // store result
558 //
559 Irp->IoStatus.Status = Status;
560
561 //
562 // complete request
563 //
564 IoCompleteRequest(Irp, IO_NO_INCREMENT);
565 }
566
567 //
568 // done processing
569 //
570 return Status;
571 }
572
573 NTSTATUS
574 HidClassPDO_CreatePDO(
575 IN PDEVICE_OBJECT DeviceObject,
576 OUT PDEVICE_RELATIONS *OutDeviceRelations)
577 {
578 PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
579 NTSTATUS Status;
580 PDEVICE_OBJECT PDODeviceObject;
581 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension;
582 ULONG Index;
583 PDEVICE_RELATIONS DeviceRelations;
584 ULONG Length;
585
586 //
587 // get device extension
588 //
589 FDODeviceExtension = (PHIDCLASS_FDO_EXTENSION)DeviceObject->DeviceExtension;
590 ASSERT(FDODeviceExtension->Common.IsFDO);
591
592 //
593 // first allocate device relations
594 //
595 Length = sizeof(DEVICE_RELATIONS) + sizeof(PDEVICE_OBJECT) * FDODeviceExtension->Common.DeviceDescription.CollectionDescLength;
596 DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(NonPagedPool, Length);
597 if (!DeviceRelations)
598 {
599 //
600 // no memory
601 //
602 return STATUS_INSUFFICIENT_RESOURCES;
603 }
604
605 //
606 // zero device relations
607 //
608 RtlZeroMemory(DeviceRelations, Length);
609
610 //
611 // lets create a PDO for top level collection
612 //
613 Index = 0;
614 do
615 {
616 //
617 // lets create the device object
618 //
619 Status = IoCreateDevice(FDODeviceExtension->Common.DriverExtension->DriverObject, sizeof(HIDCLASS_PDO_DEVICE_EXTENSION), NULL, FILE_DEVICE_UNKNOWN, FILE_AUTOGENERATED_DEVICE_NAME, FALSE, &PDODeviceObject);
620 if (!NT_SUCCESS(Status))
621 {
622 //
623 // failed to create device
624 //
625 DPRINT1("[HIDCLASS] Failed to create PDO %x\n", Status);
626 break;
627 }
628
629 //
630 // patch stack size
631 //
632 PDODeviceObject->StackSize = DeviceObject->StackSize + 1;
633
634 //
635 // get device extension
636 //
637 PDODeviceExtension = (PHIDCLASS_PDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension;
638
639 //
640 // init device extension
641 //
642 PDODeviceExtension->Common.HidDeviceExtension.MiniDeviceExtension = FDODeviceExtension->Common.HidDeviceExtension.MiniDeviceExtension;
643 PDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject = FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject;
644 PDODeviceExtension->Common.HidDeviceExtension.PhysicalDeviceObject = FDODeviceExtension->Common.HidDeviceExtension.PhysicalDeviceObject;
645 PDODeviceExtension->Common.IsFDO = FALSE;
646 PDODeviceExtension->FDODeviceObject = DeviceObject;
647 PDODeviceExtension->Common.DriverExtension = FDODeviceExtension->Common.DriverExtension;
648 PDODeviceExtension->CollectionNumber = FDODeviceExtension->Common.DeviceDescription.CollectionDesc[Index].CollectionNumber;
649
650 //
651 // copy device data
652 //
653 RtlCopyMemory(&PDODeviceExtension->Common.Attributes, &FDODeviceExtension->Common.Attributes, sizeof(HID_DEVICE_ATTRIBUTES));
654 RtlCopyMemory(&PDODeviceExtension->Common.DeviceDescription, &FDODeviceExtension->Common.DeviceDescription, sizeof(HIDP_DEVICE_DESC));
655 RtlCopyMemory(&PDODeviceExtension->Capabilities, &FDODeviceExtension->Capabilities, sizeof(DEVICE_CAPABILITIES));
656
657 //
658 // set device flags
659 //
660 PDODeviceObject->Flags |= DO_MAP_IO_BUFFER;
661
662 //
663 // device is initialized
664 //
665 PDODeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
666
667 //
668 // store device object in device relations
669 //
670 DeviceRelations->Objects[Index] = PDODeviceObject;
671 DeviceRelations->Count++;
672
673 //
674 // move to next
675 //
676 Index++;
677
678 }while(Index < FDODeviceExtension->Common.DeviceDescription.CollectionDescLength);
679
680
681 //
682 // check if creating succeeded
683 //
684 if (!NT_SUCCESS(Status))
685 {
686 //
687 // failed
688 //
689 for(Index = 0; Index < DeviceRelations->Count; Index++)
690 {
691 //
692 // delete device
693 //
694 IoDeleteDevice(DeviceRelations->Objects[Index]);
695 }
696
697 //
698 // free device relations
699 //
700 ExFreePool(DeviceRelations);
701 return Status;
702 }
703
704 //
705 // store device relations
706 //
707 *OutDeviceRelations = DeviceRelations;
708
709 //
710 // done
711 //
712 return STATUS_SUCCESS;
713 }