fe89da13ad0e01ca823e0b86e376051b72138370
[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->InterfaceList = FDODeviceExtension->InterfaceList;
283 PDODeviceExtension->InterfaceListCount = FDODeviceExtension->InterfaceListCount;
284 PDODeviceExtension->ConfigurationHandle = FDODeviceExtension->ConfigurationHandle;
285 PDODeviceExtension->ConfigurationDescriptor = FDODeviceExtension->ConfigurationDescriptor;
286 RtlCopyMemory(&PDODeviceExtension->Capabilities, &FDODeviceExtension->Capabilities, sizeof(DEVICE_CAPABILITIES));
287 RtlCopyMemory(&PDODeviceExtension->DeviceDescriptor, &FDODeviceExtension->DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
288
289 //
290 // patch the stack size
291 //
292 PDODeviceObject->StackSize = DeviceObject->StackSize + 1;
293
294 //
295 // set device flags
296 //
297 PDODeviceObject->Flags |= DO_DIRECT_IO | DO_MAP_IO_BUFFER;
298
299 //
300 // device is initialized
301 //
302 PDODeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
303 }
304
305 //
306 // done
307 //
308 return STATUS_SUCCESS;
309 }
310
311 NTSTATUS
312 FDO_StartDevice(
313 PDEVICE_OBJECT DeviceObject,
314 PIRP Irp)
315 {
316 NTSTATUS Status;
317 PFDO_DEVICE_EXTENSION FDODeviceExtension;
318
319 //
320 // get device extension
321 //
322 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
323 ASSERT(FDODeviceExtension->Common.IsFDO);
324
325 //
326 // first start lower device
327 //
328 Status = USBCCGP_SyncForwardIrp(FDODeviceExtension->NextDeviceObject, Irp);
329
330 if (!NT_SUCCESS(Status))
331 {
332 //
333 // failed to start lower device
334 //
335 DPRINT1("FDO_StartDevice lower device failed to start with %x\n", Status);
336 return Status;
337 }
338
339 // get descriptors
340 Status = USBCCGP_GetDescriptors(DeviceObject);
341 if (!NT_SUCCESS(Status))
342 {
343 // failed to start lower device
344 DPRINT1("FDO_StartDevice failed to get descriptors with %x\n", Status);
345 return Status;
346 }
347
348 // get capabilities
349 Status = FDO_QueryCapabilities(DeviceObject, &FDODeviceExtension->Capabilities);
350 if (!NT_SUCCESS(Status))
351 {
352 // failed to start lower device
353 DPRINT1("FDO_StartDevice failed to get capabilities with %x\n", Status);
354 return Status;
355 }
356
357 // now select the configuration
358 Status = USBCCGP_SelectConfiguration(DeviceObject, FDODeviceExtension);
359 if (!NT_SUCCESS(Status))
360 {
361 // failed to select interface
362 DPRINT1("FDO_StartDevice failed to get capabilities with %x\n", Status);
363 return Status;
364 }
365
366 // query bus interface
367 USBCCGP_QueryInterface(FDODeviceExtension->NextDeviceObject, &FDODeviceExtension->BusInterface);
368
369 // now enumerate the functions
370 Status = USBCCGP_EnumerateFunctions(DeviceObject);
371 if (!NT_SUCCESS(Status))
372 {
373 // failed to enumerate functions
374 DPRINT1("Failed to enumerate functions with %x\n", Status);
375 return Status;
376 }
377
378 //
379 // sanity checks
380 //
381 ASSERT(FDODeviceExtension->FunctionDescriptorCount);
382 ASSERT(FDODeviceExtension->FunctionDescriptor);
383 DumpFunctionDescriptor(FDODeviceExtension->FunctionDescriptor, FDODeviceExtension->FunctionDescriptorCount);
384
385 //
386 // now create the pdo
387 //
388 Status = FDO_CreateChildPdo(DeviceObject);
389 if (!NT_SUCCESS(Status))
390 {
391 //
392 // failed
393 //
394 DPRINT1("FDO_CreateChildPdo failed with %x\n", Status);
395 return Status;
396 }
397
398 //
399 // inform pnp manager of new device objects
400 //
401 IoInvalidateDeviceRelations(FDODeviceExtension->PhysicalDeviceObject, BusRelations);
402
403 //
404 // done
405 //
406 DPRINT1("[USBCCGP] FDO initialized successfully\n");
407 return Status;
408 }
409
410 NTSTATUS
411 FDO_HandlePnp(
412 PDEVICE_OBJECT DeviceObject,
413 PIRP Irp)
414 {
415 PIO_STACK_LOCATION IoStack;
416 NTSTATUS Status;
417 PFDO_DEVICE_EXTENSION FDODeviceExtension;
418
419 // get device extension
420 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
421 ASSERT(FDODeviceExtension->Common.IsFDO);
422
423
424 // get stack location
425 IoStack = IoGetCurrentIrpStackLocation(Irp);
426 DPRINT1("[USBCCGP] PnP Minor %x\n", IoStack->MinorFunction);
427 switch(IoStack->MinorFunction)
428 {
429 case IRP_MN_START_DEVICE:
430 {
431 //
432 // start the device
433 //
434 Status = FDO_StartDevice(DeviceObject, Irp);
435 break;
436 }
437 case IRP_MN_QUERY_DEVICE_RELATIONS:
438 {
439 //
440 // handle device relations
441 //
442 Status = FDO_DeviceRelations(DeviceObject, Irp);
443 break;
444 }
445 case IRP_MN_QUERY_CAPABILITIES:
446 {
447 //
448 // copy capabilities
449 //
450 RtlCopyMemory(IoStack->Parameters.DeviceCapabilities.Capabilities, &FDODeviceExtension->Capabilities, sizeof(DEVICE_CAPABILITIES));
451 Status = USBCCGP_SyncForwardIrp(FDODeviceExtension->NextDeviceObject, Irp);
452 if (NT_SUCCESS(Status))
453 {
454 //
455 // surprise removal ok
456 //
457 IoStack->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = TRUE;
458 }
459 break;
460 }
461 default:
462 {
463 //
464 // forward irp to next device object
465 //
466 IoSkipCurrentIrpStackLocation(Irp);
467 return IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp);
468 }
469
470 }
471
472 //
473 // complete request
474 //
475 Irp->IoStatus.Status = Status;
476 IoCompleteRequest(Irp, IO_NO_INCREMENT);
477 return Status;
478
479
480 }
481
482 NTSTATUS
483 FDO_Dispatch(
484 PDEVICE_OBJECT DeviceObject,
485 PIRP Irp)
486 {
487 PIO_STACK_LOCATION IoStack;
488 NTSTATUS Status;
489
490 /* get stack location */
491 IoStack = IoGetCurrentIrpStackLocation(Irp);
492
493 switch(IoStack->MajorFunction)
494 {
495 case IRP_MJ_PNP:
496 return FDO_HandlePnp(DeviceObject, Irp);
497 default:
498 DPRINT1("FDO_Dispatch Function %x not implemented\n", IoStack->MajorFunction);
499 ASSERT(FALSE);
500 Status = Irp->IoStatus.Status;
501 IoCompleteRequest(Irp, IO_NO_INCREMENT);
502 return Status;
503 }
504
505 }
506
507