[USBCCGP]
[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 //
143 // get current irp stack location
144 //
145 IoStack = IoGetCurrentIrpStackLocation(Irp);
146
147 //
148 // check if relation type is BusRelations
149 //
150 if (IoStack->Parameters.QueryDeviceRelations.Type != BusRelations)
151 {
152 //
153 // FDO always only handles bus relations
154 //
155 return USBCCGP_SyncForwardIrp(FDODeviceExtension->NextDeviceObject, Irp);
156 }
157
158 //
159 // go through array and count device objects
160 //
161 for(Index = 0; Index < FDODeviceExtension->FunctionDescriptorCount; Index++)
162 {
163 if (FDODeviceExtension->ChildPDO[Index])
164 {
165 //
166 // child pdo
167 //
168 DeviceCount++;
169 }
170 }
171
172 //
173 // allocate device relations
174 //
175 DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(PagedPool, sizeof(DEVICE_RELATIONS) + (DeviceCount > 1 ? (DeviceCount-1) * sizeof(PDEVICE_OBJECT) : 0));
176 if (!DeviceRelations)
177 {
178 //
179 // no memory
180 //
181 return STATUS_INSUFFICIENT_RESOURCES;
182 }
183
184 //
185 // add device objects
186 //
187 for(Index = 0; Index < FDODeviceExtension->FunctionDescriptorCount; Index++)
188 {
189 if (FDODeviceExtension->ChildPDO[Index])
190 {
191 //
192 // store child pdo
193 //
194 DeviceRelations->Objects[DeviceRelations->Count] = FDODeviceExtension->ChildPDO[Index];
195
196 //
197 // add reference
198 //
199 ObReferenceObject(FDODeviceExtension->ChildPDO[Index]);
200
201 //
202 // increment count
203 //
204 DeviceRelations->Count++;
205 }
206 }
207
208 //
209 // store result
210 //
211 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
212
213 //
214 // request completed successfully
215 //
216 return STATUS_SUCCESS;
217 }
218
219 NTSTATUS
220 FDO_CreateChildPdo(
221 IN PDEVICE_OBJECT DeviceObject)
222 {
223 NTSTATUS Status;
224 PDEVICE_OBJECT PDODeviceObject;
225 PPDO_DEVICE_EXTENSION PDODeviceExtension;
226 PFDO_DEVICE_EXTENSION FDODeviceExtension;
227 ULONG Index;
228
229 //
230 // get device extension
231 //
232 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
233 ASSERT(FDODeviceExtension->Common.IsFDO);
234
235 //
236 // lets create array for the child PDO
237 //
238 FDODeviceExtension->ChildPDO = AllocateItem(NonPagedPool, sizeof(PDEVICE_OBJECT) * FDODeviceExtension->FunctionDescriptorCount);
239 if (!FDODeviceExtension->ChildPDO)
240 {
241 //
242 // no memory
243 //
244 return STATUS_INSUFFICIENT_RESOURCES;
245 }
246
247 //
248 // create pdo for each function
249 //
250 for(Index = 0; Index < FDODeviceExtension->FunctionDescriptorCount; Index++)
251 {
252 //
253 // create the PDO
254 //
255 Status = IoCreateDevice(FDODeviceExtension->DriverObject, sizeof(PDO_DEVICE_EXTENSION), NULL, FILE_DEVICE_USB, FILE_AUTOGENERATED_DEVICE_NAME, FALSE, &PDODeviceObject);
256 if (!NT_SUCCESS(Status))
257 {
258 //
259 // failed to create device object
260 //
261 DPRINT1("IoCreateDevice failed with %x\n", Status);
262 return Status;
263 }
264
265 //
266 // store in array
267 //
268 FDODeviceExtension->ChildPDO[Index] = PDODeviceObject;
269
270 //
271 // get device extension
272 //
273 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension;
274 RtlZeroMemory(PDODeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
275
276 //
277 // init device extension
278 //
279 PDODeviceExtension->Common.IsFDO = FALSE;
280 PDODeviceExtension->FunctionDescriptor = &FDODeviceExtension->FunctionDescriptor[Index];
281 PDODeviceExtension->NextDeviceObject = DeviceObject;
282 PDODeviceExtension->FunctionIndex = Index;
283 RtlCopyMemory(&PDODeviceExtension->Capabilities, &FDODeviceExtension->Capabilities, sizeof(DEVICE_CAPABILITIES));
284
285 //
286 // patch the stack size
287 //
288 PDODeviceObject->StackSize = DeviceObject->StackSize + 1;
289
290 //
291 // set device flags
292 //
293 PDODeviceObject->Flags |= DO_DIRECT_IO | DO_MAP_IO_BUFFER;
294
295 //
296 // device is initialized
297 //
298 PDODeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
299 }
300
301 //
302 // done
303 //
304 return STATUS_SUCCESS;
305 }
306
307 NTSTATUS
308 FDO_StartDevice(
309 PDEVICE_OBJECT DeviceObject,
310 PIRP Irp)
311 {
312 NTSTATUS Status;
313 PFDO_DEVICE_EXTENSION FDODeviceExtension;
314
315 //
316 // get device extension
317 //
318 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
319 ASSERT(FDODeviceExtension->Common.IsFDO);
320
321 //
322 // first start lower device
323 //
324 Status = USBCCGP_SyncForwardIrp(FDODeviceExtension->NextDeviceObject, Irp);
325
326 if (!NT_SUCCESS(Status))
327 {
328 //
329 // failed to start lower device
330 //
331 DPRINT1("FDO_StartDevice lower device failed to start with %x\n", Status);
332 return Status;
333 }
334
335 // get descriptors
336 Status = USBCCGP_GetDescriptors(DeviceObject);
337 if (!NT_SUCCESS(Status))
338 {
339 // failed to start lower device
340 DPRINT1("FDO_StartDevice failed to get descriptors with %x\n", Status);
341 return Status;
342 }
343
344 // get capabilities
345 Status = FDO_QueryCapabilities(DeviceObject, &FDODeviceExtension->Capabilities);
346 if (!NT_SUCCESS(Status))
347 {
348 // failed to start lower device
349 DPRINT1("FDO_StartDevice failed to get capabilities with %x\n", Status);
350 return Status;
351 }
352
353 // now select the configuration
354 Status = USBCCGP_SelectConfiguration(DeviceObject, FDODeviceExtension);
355 if (!NT_SUCCESS(Status))
356 {
357 // failed to select interface
358 DPRINT1("FDO_StartDevice failed to get capabilities with %x\n", Status);
359 return Status;
360 }
361
362 // query bus interface
363 USBCCGP_QueryInterface(FDODeviceExtension->NextDeviceObject, &FDODeviceExtension->BusInterface);
364
365 // now enumerate the functions
366 Status = USBCCGP_EnumerateFunctions(DeviceObject);
367 if (!NT_SUCCESS(Status))
368 {
369 // failed to enumerate functions
370 DPRINT1("Failed to enumerate functions with %x\n", Status);
371 return Status;
372 }
373
374 //
375 // sanity checks
376 //
377 ASSERT(FDODeviceExtension->FunctionDescriptorCount);
378 ASSERT(FDODeviceExtension->FunctionDescriptor);
379
380 //
381 // now create the pdo
382 //
383 Status = FDO_CreateChildPdo(DeviceObject);
384 if (!NT_SUCCESS(Status))
385 {
386 //
387 // failed
388 //
389 DPRINT1("FDO_CreateChildPdo failed with %x\n", Status);
390 return Status;
391 }
392
393 //
394 // inform pnp manager of new device objects
395 //
396 IoInvalidateDeviceRelations(FDODeviceExtension->PhysicalDeviceObject, BusRelations);
397
398 //
399 // done
400 //
401 DPRINT1("[USBCCGP] FDO initialized successfully\n");
402 return Status;
403 }
404
405 NTSTATUS
406 FDO_HandlePnp(
407 PDEVICE_OBJECT DeviceObject,
408 PIRP Irp)
409 {
410 PIO_STACK_LOCATION IoStack;
411 NTSTATUS Status;
412 PFDO_DEVICE_EXTENSION FDODeviceExtension;
413
414 // get device extension
415 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
416 ASSERT(FDODeviceExtension->Common.IsFDO);
417
418
419 // get stack location
420 IoStack = IoGetCurrentIrpStackLocation(Irp);
421
422 switch(IoStack->MinorFunction)
423 {
424 case IRP_MN_START_DEVICE:
425 {
426 //
427 // start the device
428 //
429 Status = FDO_StartDevice(DeviceObject, Irp);
430 break;
431 }
432 case IRP_MN_QUERY_DEVICE_RELATIONS:
433 {
434 //
435 // handle device relations
436 //
437 Status = FDO_DeviceRelations(DeviceObject, Irp);
438 break;
439 }
440 case IRP_MN_QUERY_CAPABILITIES:
441 {
442 //
443 // copy capabilities
444 //
445 RtlCopyMemory(IoStack->Parameters.DeviceCapabilities.Capabilities, &FDODeviceExtension->Capabilities, sizeof(DEVICE_CAPABILITIES));
446 Status = USBCCGP_SyncForwardIrp(FDODeviceExtension->NextDeviceObject, Irp);
447 if (NT_SUCCESS(Status))
448 {
449 //
450 // surprise removal ok
451 //
452 IoStack->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = TRUE;
453 }
454 break;
455 }
456 default:
457 {
458 //
459 // forward irp to next device object
460 //
461 IoSkipCurrentIrpStackLocation(Irp);
462 return IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp);
463 }
464
465 }
466
467 //
468 // complete request
469 //
470 Irp->IoStatus.Status = Status;
471 IoCompleteRequest(Irp, IO_NO_INCREMENT);
472 return Status;
473
474
475 }
476
477 NTSTATUS
478 FDO_Dispatch(
479 PDEVICE_OBJECT DeviceObject,
480 PIRP Irp)
481 {
482 PIO_STACK_LOCATION IoStack;
483 NTSTATUS Status;
484
485 /* get stack location */
486 IoStack = IoGetCurrentIrpStackLocation(Irp);
487
488 switch(IoStack->MajorFunction)
489 {
490 case IRP_MJ_PNP:
491 return FDO_HandlePnp(DeviceObject, Irp);
492 default:
493 DPRINT1("FDO_Dispatch Function %x not implemented\n", IoStack->MajorFunction);
494 ASSERT(FALSE);
495 Status = Irp->IoStatus.Status;
496 IoCompleteRequest(Irp, IO_NO_INCREMENT);
497 return Status;
498 }
499
500 }
501
502