[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 NTSTATUS
13 HidClassPDO_HandleQueryDeviceId(
14 IN PDEVICE_OBJECT DeviceObject,
15 IN PIRP Irp)
16 {
17 NTSTATUS Status;
18 LPWSTR Buffer;
19 LPWSTR NewBuffer, Ptr;
20 ULONG Length;
21
22 //
23 // copy current stack location
24 //
25 IoCopyCurrentIrpStackLocationToNext(Irp);
26
27 //
28 // call mini-driver
29 //
30 Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
31 if (!NT_SUCCESS(Status))
32 {
33 //
34 // failed
35 //
36 return Status;
37 }
38
39 //
40 // get buffer
41 //
42 Buffer = (LPWSTR)Irp->IoStatus.Information;
43 Length = wcslen(Buffer);
44
45 //
46 // allocate new buffer
47 //
48 NewBuffer = (LPWSTR)ExAllocatePool(NonPagedPool, (Length + 1) * sizeof(WCHAR));
49 if (!NewBuffer)
50 {
51 //
52 // failed to allocate buffer
53 //
54 return STATUS_INSUFFICIENT_RESOURCES;
55 }
56
57 //
58 // replace bus
59 //
60 wcscpy(NewBuffer, L"HID\\");
61
62 //
63 // get offset to first '\\'
64 //
65 Ptr = wcschr(Buffer, L'\\');
66 if (Ptr)
67 {
68 //
69 // append result
70 //
71 wcscat(NewBuffer, Ptr + 1);
72 }
73
74 //
75 // free old buffer
76 //
77 ExFreePool(Buffer);
78
79 //
80 // store result
81 //
82 Irp->IoStatus.Information = (ULONG_PTR)NewBuffer;
83 return STATUS_SUCCESS;
84 }
85
86 NTSTATUS
87 HidClassPDO_HandleQueryHardwareId(
88 IN PDEVICE_OBJECT DeviceObject,
89 IN PIRP Irp)
90 {
91 NTSTATUS Status;
92 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension;
93 WCHAR Buffer[100];
94 ULONG Offset = 0;
95 LPWSTR Ptr;
96
97 //
98 // get device extension
99 //
100 PDODeviceExtension = (PHIDCLASS_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
101 ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
102
103 //
104 // copy current stack location
105 //
106 IoCopyCurrentIrpStackLocationToNext(Irp);
107
108 //
109 // call mini-driver
110 //
111 Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
112 if (!NT_SUCCESS(Status))
113 {
114 //
115 // failed
116 //
117 return Status;
118 }
119
120 //
121 // store hardware ids
122 //
123 Offset = swprintf(&Buffer[Offset], L"HID\\Vid_%04x&Pid_%04x&Rev_%04x", PDODeviceExtension->Attributes.VendorID, PDODeviceExtension->Attributes.ProductID, PDODeviceExtension->Attributes.VersionNumber) + 1;
124 Offset += swprintf(&Buffer[Offset], L"HID\\Vid_%04x&Pid_%04x", PDODeviceExtension->Attributes.VendorID, PDODeviceExtension->Attributes.ProductID) + 1;
125
126 if (PDODeviceExtension->DeviceDescription.CollectionDesc[PDODeviceExtension->CollectionIndex].UsagePage == HID_USAGE_PAGE_GENERIC)
127 {
128 switch(PDODeviceExtension->DeviceDescription.CollectionDesc[PDODeviceExtension->CollectionIndex].Usage)
129 {
130 case HID_USAGE_GENERIC_POINTER:
131 case HID_USAGE_GENERIC_MOUSE:
132 //
133 // Pointer / Mouse
134 //
135 Offset += swprintf(&Buffer[Offset], L"HID_DEVICE_SYSTEM_MOUSE") + 1;
136 break;
137 case HID_USAGE_GENERIC_GAMEPAD:
138 case HID_USAGE_GENERIC_JOYSTICK:
139 //
140 // Joystick / Gamepad
141 //
142 Offset += swprintf(&Buffer[Offset], L"HID_DEVICE_SYSTEM_GAME") + 1;
143 break;
144 case HID_USAGE_GENERIC_KEYBOARD:
145 case HID_USAGE_GENERIC_KEYPAD:
146 //
147 // Keyboard / Keypad
148 //
149 Offset += swprintf(&Buffer[Offset], L"HID_DEVICE_SYSTEM_KEYBOARD") + 1;
150 break;
151 case HID_USAGE_GENERIC_SYSTEM_CTL:
152 //
153 // System Control
154 //
155 Offset += swprintf(&Buffer[Offset], L"HID_DEVICE_SYSTEM_CONTROL") + 1;
156 break;
157 }
158 }
159 else if (PDODeviceExtension->DeviceDescription.CollectionDesc[PDODeviceExtension->CollectionIndex].UsagePage == HID_USAGE_PAGE_CONSUMER && PDODeviceExtension->DeviceDescription.CollectionDesc[PDODeviceExtension->CollectionIndex].Usage == HID_USAGE_CONSUMERCTRL)
160 {
161 //
162 // Consumer Audio Control
163 //
164 Offset += swprintf(&Buffer[Offset], L"HID_DEVICE_SYSTEM_CONSUMER") + 1;
165 }
166
167 //
168 // FIXME: add 'HID_DEVICE_UP:0001_U:0002'
169 //
170
171 //
172 // add HID
173 //
174 Offset +=swprintf(&Buffer[Offset], L"HID_DEVICE") + 1;
175
176 //
177 // free old buffer
178 //
179 ExFreePool((PVOID)Irp->IoStatus.Information);
180
181 //
182 // allocate buffer
183 //
184 Ptr = (LPWSTR)ExAllocatePool(NonPagedPool, (Offset +1)* sizeof(WCHAR));
185 if (!Ptr)
186 {
187 //
188 // no memory
189 //
190 Irp->IoStatus.Information = 0;
191 return STATUS_INSUFFICIENT_RESOURCES;
192 }
193
194 //
195 // copy buffer
196 //
197 RtlCopyMemory(Ptr, Buffer, Offset * sizeof(WCHAR));
198 Ptr[Offset] = UNICODE_NULL;
199
200 //
201 // store result
202 //
203 Irp->IoStatus.Information = (ULONG_PTR)Ptr;
204 return STATUS_SUCCESS;
205 }
206
207 NTSTATUS
208 HidClassPDO_HandleQueryInstanceId(
209 IN PDEVICE_OBJECT DeviceObject,
210 IN PIRP Irp)
211 {
212 NTSTATUS Status;
213
214 //
215 // copy current stack location
216 //
217 IoCopyCurrentIrpStackLocationToNext(Irp);
218
219 //
220 // call mini-driver
221 //
222 Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
223 if (!NT_SUCCESS(Status))
224 {
225 //
226 // failed
227 //
228 return Status;
229 }
230 DPRINT1("HidClassPDO_HandleQueryInstanceId Buffer %S\n", Irp->IoStatus.Information);
231 //
232 //TODO implement instance id
233 // example:
234 // HID\VID_045E&PID_0047\8&1A0700BC&0&0000
235 return STATUS_NOT_IMPLEMENTED;
236 }
237
238 NTSTATUS
239 HidClassPDO_HandleQueryCompatibleId(
240 IN PDEVICE_OBJECT DeviceObject,
241 IN PIRP Irp)
242 {
243 NTSTATUS Status;
244
245 //
246 // copy current stack location
247 //
248 IoCopyCurrentIrpStackLocationToNext(Irp);
249
250 //
251 // call mini-driver
252 //
253 Status = HidClassFDO_DispatchRequestSynchronous(DeviceObject, Irp);
254 if (!NT_SUCCESS(Status))
255 {
256 //
257 // failed
258 //
259 return Status;
260 }
261
262 //
263 // FIXME: implement me
264 //
265 return STATUS_NOT_IMPLEMENTED;
266 }
267
268
269 NTSTATUS
270 HidClassPDO_PnP(
271 IN PDEVICE_OBJECT DeviceObject,
272 IN PIRP Irp)
273 {
274 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension;
275 PIO_STACK_LOCATION IoStack;
276 NTSTATUS Status;
277 PPNP_BUS_INFORMATION BusInformation;
278 PDEVICE_RELATIONS DeviceRelation;
279
280 //
281 // get device extension
282 //
283 PDODeviceExtension = (PHIDCLASS_PDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
284 ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
285
286 //
287 // get current irp stack location
288 //
289 IoStack = IoGetCurrentIrpStackLocation(Irp);
290
291 //
292 // handle request
293 //
294 switch(IoStack->MinorFunction)
295 {
296 case IRP_MN_QUERY_ID:
297 {
298 if (IoStack->Parameters.QueryId.IdType == BusQueryDeviceID)
299 {
300 //
301 // handle query device id
302 //
303 Status = HidClassPDO_HandleQueryDeviceId(DeviceObject, Irp);
304 break;
305 }
306 else if (IoStack->Parameters.QueryId.IdType == BusQueryHardwareIDs)
307 {
308 //
309 // handle instance id
310 //
311 Status = HidClassPDO_HandleQueryHardwareId(DeviceObject, Irp);
312 break;
313 }
314 else if (IoStack->Parameters.QueryId.IdType == BusQueryInstanceID)
315 {
316 //
317 // handle instance id
318 //
319 Status = HidClassPDO_HandleQueryInstanceId(DeviceObject, Irp);
320 break;
321 }
322 else if (IoStack->Parameters.QueryId.IdType == BusQueryCompatibleIDs)
323 {
324 //
325 // handle instance id
326 //
327 Status = HidClassPDO_HandleQueryCompatibleId(DeviceObject, Irp);
328 break;
329 }
330
331 DPRINT1("[HIDCLASS]: IRP_MN_QUERY_ID IdType %x unimplemented\n", IoStack->Parameters.QueryId.IdType);
332 Status = STATUS_NOT_SUPPORTED;
333 Irp->IoStatus.Information = 0;
334 break;
335 }
336 case IRP_MN_QUERY_CAPABILITIES:
337 {
338 if (IoStack->Parameters.DeviceCapabilities.Capabilities == NULL)
339 {
340 //
341 // invalid request
342 //
343 Status = STATUS_DEVICE_CONFIGURATION_ERROR;
344 }
345
346 //
347 // copy capabilities
348 //
349 RtlCopyMemory(IoStack->Parameters.DeviceCapabilities.Capabilities, &PDODeviceExtension->Capabilities, sizeof(DEVICE_CAPABILITIES));
350 Status = STATUS_SUCCESS;
351 break;
352 }
353 case IRP_MN_QUERY_BUS_INFORMATION:
354 {
355 //
356 //
357 //
358 BusInformation = (PPNP_BUS_INFORMATION)ExAllocatePool(NonPagedPool, sizeof(PNP_BUS_INFORMATION));
359
360 //
361 // fill in result
362 //
363 RtlCopyMemory(&BusInformation->BusTypeGuid, &GUID_BUS_TYPE_HID, sizeof(GUID));
364 BusInformation->LegacyBusType = PNPBus;
365 BusInformation->BusNumber = 0; //FIXME
366
367 //
368 // store result
369 //
370 Irp->IoStatus.Information = (ULONG_PTR)BusInformation;
371 Status = STATUS_SUCCESS;
372 break;
373 }
374 case IRP_MN_QUERY_PNP_DEVICE_STATE:
375 {
376 //
377 // FIXME set flags when driver fails / disabled
378 //
379 Status = STATUS_SUCCESS;
380 break;
381 }
382 case IRP_MN_QUERY_DEVICE_RELATIONS:
383 {
384 //
385 // only target relations are supported
386 //
387 if (IoStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
388 {
389 //
390 // not supported
391 //
392 Status = Irp->IoStatus.Status;
393 break;
394 }
395
396 //
397 // allocate device relations
398 //
399 DeviceRelation = (PDEVICE_RELATIONS)ExAllocatePool(NonPagedPool, sizeof(DEVICE_RELATIONS));
400 if (!DeviceRelation)
401 {
402 //
403 // no memory
404 //
405 Status = STATUS_INSUFFICIENT_RESOURCES;
406 break;
407 }
408
409 //
410 // init device relation
411 //
412 DeviceRelation->Count = 1;
413 DeviceRelation->Objects[0] = DeviceObject;
414 ObReferenceObject(DeviceRelation->Objects[0]);
415
416 //
417 // store result
418 //
419 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelation;
420 Status = STATUS_SUCCESS;
421 break;
422 }
423 case IRP_MN_START_DEVICE:
424 {
425 DPRINT1("[HIDCLASS] PDO PnP not implemented %x\n", IoStack->MinorFunction);
426 ASSERT(FALSE);
427
428 //
429 // do nothing
430 //
431 Status = Irp->IoStatus.Status;
432 break;
433 }
434 case IRP_MN_REMOVE_DEVICE:
435 {
436 DPRINT1("[HIDCLASS] PDO IRP_MN_REMOVE_DEVICE not implemented\n");
437 ASSERT(FALSE);
438
439 //
440 // do nothing
441 //
442 Status = Irp->IoStatus.Status;
443 break;
444 }
445 case IRP_MN_QUERY_INTERFACE:
446 {
447 DPRINT1("[HIDCLASS] PDO IRP_MN_QUERY_INTERFACE not implemented\n");
448 ASSERT(FALSE);
449
450 //
451 // do nothing
452 //
453 Status = Irp->IoStatus.Status;
454 break;
455 }
456 default:
457 {
458 //
459 // do nothing
460 //
461 Status = Irp->IoStatus.Status;
462 break;
463 }
464 }
465
466 //
467 // complete request
468 //
469 if (Status != STATUS_PENDING)
470 {
471 //
472 // store result
473 //
474 Irp->IoStatus.Status = Status;
475
476 //
477 // complete request
478 //
479 IoCompleteRequest(Irp, IO_NO_INCREMENT);
480 }
481
482 //
483 // done processing
484 //
485 return Status;
486 }
487
488 NTSTATUS
489 HidClassPDO_CreatePDO(
490 IN PDEVICE_OBJECT DeviceObject)
491 {
492 PHIDCLASS_FDO_EXTENSION FDODeviceExtension;
493 NTSTATUS Status;
494 PDEVICE_OBJECT PDODeviceObject;
495 PHIDCLASS_PDO_DEVICE_EXTENSION PDODeviceExtension;
496
497 //
498 // get device extension
499 //
500 FDODeviceExtension = (PHIDCLASS_FDO_EXTENSION)DeviceObject->DeviceExtension;
501 ASSERT(FDODeviceExtension->Common.IsFDO);
502
503 //
504 // lets create the device object
505 //
506 Status = IoCreateDevice(FDODeviceExtension->Common.DriverExtension->DriverObject, sizeof(HIDCLASS_PDO_DEVICE_EXTENSION), NULL, FILE_DEVICE_UNKNOWN, FILE_AUTOGENERATED_DEVICE_NAME, FALSE, &PDODeviceObject);
507 if (!NT_SUCCESS(Status))
508 {
509 //
510 // failed to create device
511 //
512 DPRINT1("[HIDCLASS] Failed to create device %x\n", Status);
513 return Status;
514 }
515
516 //
517 // patch stack size
518 //
519 PDODeviceObject->StackSize = DeviceObject->StackSize + 1;
520
521 //
522 // get device extension
523 //
524 PDODeviceExtension = (PHIDCLASS_PDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension;
525
526 //
527 // init device extension
528 //
529 PDODeviceExtension->Common.HidDeviceExtension.MiniDeviceExtension = FDODeviceExtension->Common.HidDeviceExtension.MiniDeviceExtension;
530 PDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject = FDODeviceExtension->Common.HidDeviceExtension.NextDeviceObject;
531 PDODeviceExtension->Common.HidDeviceExtension.PhysicalDeviceObject = NULL;
532 PDODeviceExtension->Common.IsFDO = FALSE;
533 PDODeviceExtension->Common.DriverExtension = FDODeviceExtension->Common.DriverExtension;
534 RtlCopyMemory(&PDODeviceExtension->Attributes, &FDODeviceExtension->Attributes, sizeof(HID_DEVICE_ATTRIBUTES));
535 RtlCopyMemory(&PDODeviceExtension->DeviceDescription, &FDODeviceExtension->DeviceDescription, sizeof(HIDP_DEVICE_DESC));
536 RtlCopyMemory(&PDODeviceExtension->Capabilities, &FDODeviceExtension->Capabilities, sizeof(DEVICE_CAPABILITIES));
537
538 //
539 // FIXME: support composite devices
540 //
541 PDODeviceExtension->CollectionIndex = 0;
542 ASSERT(PDODeviceExtension->DeviceDescription.CollectionDescLength == 1);
543
544 //
545 // store in device relations struct
546 //
547 FDODeviceExtension->DeviceRelations.Count = 1;
548 FDODeviceExtension->DeviceRelations.Objects[0] = PDODeviceObject;
549
550 //
551 // set device flags
552 //
553 PDODeviceObject->Flags |= DO_MAP_IO_BUFFER;
554
555 //
556 // device is initialized
557 //
558 PDODeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
559
560 ObReferenceObject(PDODeviceObject);
561
562 //
563 // done
564 //
565 return STATUS_SUCCESS;
566 }