d4bfacf30ac287a28366f5373ab66af56ae846ff
[reactos.git] / drivers / usb / usbccgp / fdo.c
1 /*
2 * PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbccgp/fdo.c
5 * PURPOSE: USB device driver.
6 * PROGRAMMERS:
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
9 * Cameron Gutman
10 */
11
12 #include "usbccgp.h"
13
14 NTSTATUS
15 NTAPI
16 FDO_QueryCapabilitiesCompletionRoutine(
17 IN PDEVICE_OBJECT DeviceObject,
18 IN PIRP Irp,
19 IN PVOID Context)
20 {
21 //
22 // set event
23 //
24 KeSetEvent((PRKEVENT)Context, 0, FALSE);
25
26 //
27 // completion is done in the HidClassFDO_QueryCapabilities routine
28 //
29 return STATUS_MORE_PROCESSING_REQUIRED;
30 }
31
32 NTSTATUS
33 FDO_QueryCapabilities(
34 IN PDEVICE_OBJECT DeviceObject,
35 IN OUT PDEVICE_CAPABILITIES Capabilities)
36 {
37 PIRP Irp;
38 KEVENT Event;
39 NTSTATUS Status;
40 PIO_STACK_LOCATION IoStack;
41 PFDO_DEVICE_EXTENSION FDODeviceExtension;
42
43 //
44 // get device extension
45 //
46 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
47 ASSERT(FDODeviceExtension->Common.IsFDO);
48
49 //
50 // init event
51 //
52 KeInitializeEvent(&Event, NotificationEvent, FALSE);
53
54 //
55 // now allocte the irp
56 //
57 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
58 if (!Irp)
59 {
60 //
61 // no memory
62 //
63 return STATUS_INSUFFICIENT_RESOURCES;
64 }
65
66 //
67 // get next stack location
68 //
69 IoStack = IoGetNextIrpStackLocation(Irp);
70
71 //
72 // init stack location
73 //
74 IoStack->MajorFunction = IRP_MJ_PNP;
75 IoStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES;
76 IoStack->Parameters.DeviceCapabilities.Capabilities = Capabilities;
77
78 //
79 // set completion routine
80 //
81 IoSetCompletionRoutine(Irp, FDO_QueryCapabilitiesCompletionRoutine, (PVOID)&Event, TRUE, TRUE, TRUE);
82
83 //
84 // init capabilities
85 //
86 RtlZeroMemory(Capabilities, sizeof(DEVICE_CAPABILITIES));
87 Capabilities->Size = sizeof(DEVICE_CAPABILITIES);
88 Capabilities->Version = 1; // FIXME hardcoded constant
89 Capabilities->Address = MAXULONG;
90 Capabilities->UINumber = MAXULONG;
91
92 //
93 // pnp irps have default completion code
94 //
95 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
96
97 //
98 // call lower device
99 //
100 Status = IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp);
101 if (Status == STATUS_PENDING)
102 {
103 //
104 // wait for completion
105 //
106 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
107 }
108
109 //
110 // get status
111 //
112 Status = Irp->IoStatus.Status;
113
114 //
115 // complete request
116 //
117 IoFreeIrp(Irp);
118
119 //
120 // done
121 //
122 return Status;
123 }
124
125 NTSTATUS
126 FDO_DeviceRelations(
127 PDEVICE_OBJECT DeviceObject,
128 PIRP Irp)
129 {
130 ULONG DeviceCount = 0;
131 ULONG Index;
132 PDEVICE_RELATIONS DeviceRelations;
133 PIO_STACK_LOCATION IoStack;
134 PFDO_DEVICE_EXTENSION FDODeviceExtension;
135
136 //
137 // get device extension
138 //
139 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
140
141 //
142 // get current irp stack location
143 //
144 IoStack = IoGetCurrentIrpStackLocation(Irp);
145
146 //
147 // check if relation type is BusRelations
148 //
149 if (IoStack->Parameters.QueryDeviceRelations.Type != BusRelations)
150 {
151 //
152 // FDO always only handles bus relations
153 //
154 return USBCCGP_SyncForwardIrp(FDODeviceExtension->NextDeviceObject, Irp);
155 }
156
157 //
158 // go through array and count device objects
159 //
160 for(Index = 0; Index < FDODeviceExtension->FunctionDescriptorCount; Index++)
161 {
162 if (FDODeviceExtension->ChildPDO[Index])
163 {
164 //
165 // child pdo
166 //
167 DeviceCount++;
168 }
169 }
170
171 //
172 // allocate device relations
173 //
174 DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(PagedPool, sizeof(DEVICE_RELATIONS) + (DeviceCount > 1 ? (DeviceCount-1) * sizeof(PDEVICE_OBJECT) : 0));
175 if (!DeviceRelations)
176 {
177 //
178 // no memory
179 //
180 return STATUS_INSUFFICIENT_RESOURCES;
181 }
182
183 //
184 // add device objects
185 //
186 for(Index = 0; Index < FDODeviceExtension->FunctionDescriptorCount; Index++)
187 {
188 if (FDODeviceExtension->ChildPDO[Index])
189 {
190 //
191 // store child pdo
192 //
193 DeviceRelations->Objects[DeviceRelations->Count] = FDODeviceExtension->ChildPDO[Index];
194
195 //
196 // add reference
197 //
198 ObReferenceObject(FDODeviceExtension->ChildPDO[Index]);
199
200 //
201 // increment count
202 //
203 DeviceRelations->Count++;
204 }
205 }
206
207 //
208 // store result
209 //
210 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
211
212 //
213 // request completed successfully
214 //
215 return STATUS_SUCCESS;
216 }
217
218 NTSTATUS
219 FDO_CreateChildPdo(
220 IN PDEVICE_OBJECT DeviceObject)
221 {
222 NTSTATUS Status;
223 PDEVICE_OBJECT PDODeviceObject;
224 PPDO_DEVICE_EXTENSION PDODeviceExtension;
225 PFDO_DEVICE_EXTENSION FDODeviceExtension;
226 ULONG Index;
227
228 //
229 // get device extension
230 //
231 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
232 ASSERT(FDODeviceExtension->Common.IsFDO);
233
234 //
235 // lets create array for the child PDO
236 //
237 FDODeviceExtension->ChildPDO = AllocateItem(NonPagedPool, sizeof(PDEVICE_OBJECT) * FDODeviceExtension->FunctionDescriptorCount);
238 if (!FDODeviceExtension->ChildPDO)
239 {
240 //
241 // no memory
242 //
243 return STATUS_INSUFFICIENT_RESOURCES;
244 }
245
246 //
247 // create pdo for each function
248 //
249 for(Index = 0; Index < FDODeviceExtension->FunctionDescriptorCount; Index++)
250 {
251 //
252 // create the PDO
253 //
254 Status = IoCreateDevice(FDODeviceExtension->DriverObject, sizeof(PDO_DEVICE_EXTENSION), NULL, FILE_DEVICE_USB, FILE_AUTOGENERATED_DEVICE_NAME, FALSE, &PDODeviceObject);
255 if (!NT_SUCCESS(Status))
256 {
257 //
258 // failed to create device object
259 //
260 DPRINT1("IoCreateDevice failed with %x\n", Status);
261 return Status;
262 }
263
264 //
265 // store in array
266 //
267 FDODeviceExtension->ChildPDO[Index] = PDODeviceObject;
268
269 //
270 // get device extension
271 //
272 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension;
273 RtlZeroMemory(PDODeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
274
275 //
276 // init device extension
277 //
278 PDODeviceExtension->Common.IsFDO = FALSE;
279 PDODeviceExtension->FunctionDescriptor = &FDODeviceExtension->FunctionDescriptor[Index];
280 PDODeviceExtension->NextDeviceObject = FDODeviceExtension->NextDeviceObject; //DeviceObject; HACK
281 PDODeviceExtension->FunctionIndex = Index;
282 PDODeviceExtension->FDODeviceExtension = FDODeviceExtension;
283 PDODeviceExtension->InterfaceList = FDODeviceExtension->InterfaceList;
284 PDODeviceExtension->InterfaceListCount = FDODeviceExtension->InterfaceListCount;
285 PDODeviceExtension->ConfigurationHandle = FDODeviceExtension->ConfigurationHandle;
286 PDODeviceExtension->ConfigurationDescriptor = FDODeviceExtension->ConfigurationDescriptor;
287 RtlCopyMemory(&PDODeviceExtension->Capabilities, &FDODeviceExtension->Capabilities, sizeof(DEVICE_CAPABILITIES));
288 RtlCopyMemory(&PDODeviceExtension->DeviceDescriptor, &FDODeviceExtension->DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
289
290 //
291 // patch the stack size
292 //
293 PDODeviceObject->StackSize = DeviceObject->StackSize + 1;
294
295 //
296 // set device flags
297 //
298 PDODeviceObject->Flags |= DO_DIRECT_IO | DO_MAP_IO_BUFFER;
299
300 //
301 // device is initialized
302 //
303 PDODeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
304 }
305
306 //
307 // done
308 //
309 return STATUS_SUCCESS;
310 }
311
312 NTSTATUS
313 FDO_StartDevice(
314 PDEVICE_OBJECT DeviceObject,
315 PIRP Irp)
316 {
317 NTSTATUS Status;
318 PFDO_DEVICE_EXTENSION FDODeviceExtension;
319
320 //
321 // get device extension
322 //
323 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
324 ASSERT(FDODeviceExtension->Common.IsFDO);
325
326 //
327 // first start lower device
328 //
329 Status = USBCCGP_SyncForwardIrp(FDODeviceExtension->NextDeviceObject, Irp);
330
331 if (!NT_SUCCESS(Status))
332 {
333 //
334 // failed to start lower device
335 //
336 DPRINT1("FDO_StartDevice lower device failed to start with %x\n", Status);
337 return Status;
338 }
339
340 // get descriptors
341 Status = USBCCGP_GetDescriptors(DeviceObject);
342 if (!NT_SUCCESS(Status))
343 {
344 // failed to start lower device
345 DPRINT1("FDO_StartDevice failed to get descriptors with %x\n", Status);
346 return Status;
347 }
348
349 // get capabilities
350 Status = FDO_QueryCapabilities(DeviceObject, &FDODeviceExtension->Capabilities);
351 if (!NT_SUCCESS(Status))
352 {
353 // failed to start lower device
354 DPRINT1("FDO_StartDevice failed to get capabilities with %x\n", Status);
355 return Status;
356 }
357
358 // now select the configuration
359 Status = USBCCGP_SelectConfiguration(DeviceObject, FDODeviceExtension);
360 if (!NT_SUCCESS(Status))
361 {
362 // failed to select interface
363 DPRINT1("FDO_StartDevice failed to get capabilities with %x\n", Status);
364 return Status;
365 }
366
367 // query bus interface
368 USBCCGP_QueryInterface(FDODeviceExtension->NextDeviceObject, &FDODeviceExtension->BusInterface);
369
370 // now enumerate the functions
371 Status = USBCCGP_EnumerateFunctions(DeviceObject);
372 if (!NT_SUCCESS(Status))
373 {
374 // failed to enumerate functions
375 DPRINT1("Failed to enumerate functions with %x\n", Status);
376 return Status;
377 }
378
379 //
380 // sanity checks
381 //
382 ASSERT(FDODeviceExtension->FunctionDescriptorCount);
383 ASSERT(FDODeviceExtension->FunctionDescriptor);
384 DumpFunctionDescriptor(FDODeviceExtension->FunctionDescriptor, FDODeviceExtension->FunctionDescriptorCount);
385
386 //
387 // now create the pdo
388 //
389 Status = FDO_CreateChildPdo(DeviceObject);
390 if (!NT_SUCCESS(Status))
391 {
392 //
393 // failed
394 //
395 DPRINT1("FDO_CreateChildPdo failed with %x\n", Status);
396 return Status;
397 }
398
399 //
400 // inform pnp manager of new device objects
401 //
402 IoInvalidateDeviceRelations(FDODeviceExtension->PhysicalDeviceObject, BusRelations);
403
404 //
405 // done
406 //
407 DPRINT1("[USBCCGP] FDO initialized successfully\n");
408 return Status;
409 }
410
411 NTSTATUS
412 FDO_HandlePnp(
413 PDEVICE_OBJECT DeviceObject,
414 PIRP Irp)
415 {
416 PIO_STACK_LOCATION IoStack;
417 NTSTATUS Status;
418 PFDO_DEVICE_EXTENSION FDODeviceExtension;
419
420 // get device extension
421 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
422 ASSERT(FDODeviceExtension->Common.IsFDO);
423
424
425 // get stack location
426 IoStack = IoGetCurrentIrpStackLocation(Irp);
427 DPRINT1("[USBCCGP] PnP Minor %x\n", IoStack->MinorFunction);
428 switch(IoStack->MinorFunction)
429 {
430 case IRP_MN_REMOVE_DEVICE:
431 {
432 /* Send the IRP down the stack */
433 Status = USBCCGP_SyncForwardIrp(FDODeviceExtension->NextDeviceObject, Irp);
434 if (NT_SUCCESS(Status))
435 {
436 //
437 // Detach from the device stack
438 //
439 IoDetachDevice(FDODeviceExtension->NextDeviceObject);
440
441 //
442 // Delete the device object
443 //
444 IoDeleteDevice(DeviceObject);
445 }
446
447 //
448 // request completed
449 //
450 break;
451 }
452 case IRP_MN_START_DEVICE:
453 {
454 //
455 // start the device
456 //
457 Status = FDO_StartDevice(DeviceObject, Irp);
458 break;
459 }
460 case IRP_MN_QUERY_DEVICE_RELATIONS:
461 {
462 //
463 // handle device relations
464 //
465 Status = FDO_DeviceRelations(DeviceObject, Irp);
466 break;
467 }
468 case IRP_MN_QUERY_CAPABILITIES:
469 {
470 //
471 // copy capabilities
472 //
473 RtlCopyMemory(IoStack->Parameters.DeviceCapabilities.Capabilities, &FDODeviceExtension->Capabilities, sizeof(DEVICE_CAPABILITIES));
474 Status = USBCCGP_SyncForwardIrp(FDODeviceExtension->NextDeviceObject, Irp);
475 if (NT_SUCCESS(Status))
476 {
477 //
478 // surprise removal ok
479 //
480 IoStack->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = TRUE;
481 }
482 break;
483 }
484 default:
485 {
486 //
487 // forward irp to next device object
488 //
489 IoSkipCurrentIrpStackLocation(Irp);
490 return IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp);
491 }
492
493 }
494
495 //
496 // complete request
497 //
498 Irp->IoStatus.Status = Status;
499 IoCompleteRequest(Irp, IO_NO_INCREMENT);
500 return Status;
501
502
503 }
504
505 NTSTATUS
506 FDO_Dispatch(
507 PDEVICE_OBJECT DeviceObject,
508 PIRP Irp)
509 {
510 PIO_STACK_LOCATION IoStack;
511 NTSTATUS Status;
512
513 /* get stack location */
514 IoStack = IoGetCurrentIrpStackLocation(Irp);
515
516 switch(IoStack->MajorFunction)
517 {
518 case IRP_MJ_PNP:
519 return FDO_HandlePnp(DeviceObject, Irp);
520 default:
521 DPRINT1("FDO_Dispatch Function %x not implemented\n", IoStack->MajorFunction);
522 ASSERT(FALSE);
523 Status = Irp->IoStatus.Status;
524 IoCompleteRequest(Irp, IO_NO_INCREMENT);
525 return Status;
526 }
527
528 }
529
530