[USBCCGP]
[reactos.git] / reactos / drivers / usb / usbccgp / pdo.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/pdo.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 #define NDEBUG
15 #include <debug.h>
16
17 NTSTATUS
18 USBCCGP_PdoHandleQueryDeviceText(
19 IN PDEVICE_OBJECT DeviceObject,
20 IN OUT PIRP Irp)
21 {
22 LPWSTR Buffer;
23 PPDO_DEVICE_EXTENSION PDODeviceExtension;
24 LPWSTR GenericString = L"Composite USB Device";
25 //
26 // get device extension
27 //
28 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
29
30 //
31 // is there a device description
32 //
33 if (PDODeviceExtension->FunctionDescriptor->FunctionDescription.Length)
34 {
35 //
36 // allocate buffer
37 //
38 Buffer = AllocateItem(NonPagedPool, PDODeviceExtension->FunctionDescriptor->FunctionDescription.Length + sizeof(WCHAR));
39 if (!Buffer)
40 {
41 //
42 // no memory
43 //
44 return STATUS_INSUFFICIENT_RESOURCES;
45 }
46
47 //
48 // copy buffer
49 //
50 Irp->IoStatus.Information = (ULONG_PTR)Buffer;
51 RtlCopyMemory(Buffer, PDODeviceExtension->FunctionDescriptor->FunctionDescription.Buffer, PDODeviceExtension->FunctionDescriptor->FunctionDescription.Length);
52 return STATUS_SUCCESS;
53 }
54
55 //
56 // FIXME use GenericCompositeUSBDeviceString
57 //
58 UNIMPLEMENTED
59 Buffer = AllocateItem(PagedPool, (wcslen(GenericString) + 1) * sizeof(WCHAR));
60 if (!Buffer)
61 {
62 //
63 // no memory
64 //
65 return STATUS_INSUFFICIENT_RESOURCES;
66 }
67 RtlCopyMemory(Buffer, GenericString, (wcslen(GenericString) + 1) * sizeof(WCHAR));
68 Irp->IoStatus.Information = (ULONG_PTR)Buffer;
69
70 return STATUS_SUCCESS;
71 }
72
73 NTSTATUS
74 USBCCGP_PdoHandleDeviceRelations(
75 IN PDEVICE_OBJECT DeviceObject,
76 IN OUT PIRP Irp)
77 {
78 PDEVICE_RELATIONS DeviceRelations;
79 PIO_STACK_LOCATION IoStack;
80
81 DPRINT("USBCCGP_PdoHandleDeviceRelations\n");
82
83 //
84 // get current irp stack location
85 //
86 IoStack = IoGetCurrentIrpStackLocation(Irp);
87
88 //
89 // check if relation type is BusRelations
90 //
91 if (IoStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
92 {
93 //
94 // PDO handles only target device relation
95 //
96 return Irp->IoStatus.Status;
97 }
98
99 //
100 // allocate device relations
101 //
102 DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(PagedPool, sizeof(DEVICE_RELATIONS));
103 if (!DeviceRelations)
104 {
105 //
106 // no memory
107 //
108 return STATUS_INSUFFICIENT_RESOURCES;
109 }
110
111 //
112 // initialize device relations
113 //
114 DeviceRelations->Count = 1;
115 DeviceRelations->Objects[0] = DeviceObject;
116 ObReferenceObject(DeviceObject);
117
118 //
119 // store result
120 //
121 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
122
123 //
124 // completed successfully
125 //
126 return STATUS_SUCCESS;
127 }
128
129 NTSTATUS
130 USBCCGP_PdoAppendInterfaceNumber(
131 IN LPWSTR DeviceId,
132 IN ULONG InterfaceNumber,
133 OUT LPWSTR *OutString)
134 {
135 ULONG Length = 0, StringLength;
136 LPWSTR String;
137
138 //
139 // count length of string
140 //
141 String = DeviceId;
142 while (*String)
143 {
144 StringLength = wcslen(String) + 1;
145 Length += StringLength;
146 Length += 6; //&MI_XX
147 String += StringLength;
148 }
149
150 //
151 // now allocate the buffer
152 //
153 String = AllocateItem(NonPagedPool, (Length + 2) * sizeof(WCHAR));
154 if (!String)
155 {
156 //
157 // no memory
158 //
159 return STATUS_INSUFFICIENT_RESOURCES;
160 }
161
162 //
163 // store result
164 //
165 *OutString = String;
166
167 while (*DeviceId)
168 {
169 StringLength = swprintf(String, L"%s&MI_%02x", DeviceId, InterfaceNumber) + 1;
170 Length = wcslen(DeviceId) + 1;
171 DPRINT("String %p\n", String);
172
173 //
174 // next string
175 //
176 String += StringLength;
177 DeviceId += Length;
178 }
179
180 //
181 // success
182 //
183 return STATUS_SUCCESS;
184 }
185
186
187 NTSTATUS
188 USBCCGP_PdoHandleQueryId(
189 PDEVICE_OBJECT DeviceObject,
190 PIRP Irp)
191 {
192 PIO_STACK_LOCATION IoStack;
193 PUNICODE_STRING DeviceString = NULL;
194 PPDO_DEVICE_EXTENSION PDODeviceExtension;
195 NTSTATUS Status;
196 LPWSTR Buffer;
197
198 //
199 // get current irp stack location
200 //
201 IoStack = IoGetCurrentIrpStackLocation(Irp);
202
203 //
204 // get device extension
205 //
206 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
207
208
209 if (IoStack->Parameters.QueryId.IdType == BusQueryDeviceID)
210 {
211 //
212 // handle query device id
213 //
214 Status = USBCCGP_SyncForwardIrp(PDODeviceExtension->NextDeviceObject, Irp);
215 if (NT_SUCCESS(Status))
216 {
217 //
218 // allocate buffer
219 //
220 Buffer = AllocateItem(NonPagedPool, (wcslen((LPWSTR)Irp->IoStatus.Information) + 7) * sizeof(WCHAR));
221 if (Buffer)
222 {
223 //
224 // append interface number
225 //
226 ASSERT(Irp->IoStatus.Information);
227 swprintf(Buffer, L"%s&MI_%02x", (LPWSTR)Irp->IoStatus.Information, PDODeviceExtension->FunctionDescriptor->FunctionNumber);
228 DPRINT("BusQueryDeviceID %S\n", Buffer);
229
230 ExFreePool((PVOID)Irp->IoStatus.Information);
231 Irp->IoStatus.Information = (ULONG_PTR)Buffer;
232 }
233 else
234 {
235 //
236 // no memory
237 //
238 Status = STATUS_INSUFFICIENT_RESOURCES;
239 }
240 }
241 return Status;
242 }
243 else if (IoStack->Parameters.QueryId.IdType == BusQueryHardwareIDs)
244 {
245 //
246 // handle instance id
247 //
248 DeviceString = &PDODeviceExtension->FunctionDescriptor->HardwareId;
249 }
250 else if (IoStack->Parameters.QueryId.IdType == BusQueryInstanceID)
251 {
252 //
253 // handle instance id
254 //
255 Buffer = AllocateItem(NonPagedPool, 5 * sizeof(WCHAR));
256 if (!Buffer)
257 {
258 //
259 // no memory
260 //
261 return STATUS_INSUFFICIENT_RESOURCES;
262 }
263
264 //
265 // use function number
266 //
267 swprintf(Buffer, L"%04x", PDODeviceExtension->FunctionDescriptor->FunctionNumber);
268 Irp->IoStatus.Information = (ULONG_PTR)Buffer;
269 return STATUS_SUCCESS;
270 }
271 else if (IoStack->Parameters.QueryId.IdType == BusQueryCompatibleIDs)
272 {
273 //
274 // handle instance id
275 //
276 DeviceString = &PDODeviceExtension->FunctionDescriptor->CompatibleId;
277 }
278 else
279 {
280 //
281 // unsupported query
282 //
283 return Irp->IoStatus.Status;
284 }
285
286 //
287 // sanity check
288 //
289 ASSERT(DeviceString != NULL);
290
291 //
292 // allocate buffer
293 //
294 Buffer = AllocateItem(NonPagedPool, DeviceString->Length + sizeof(WCHAR));
295 if (!Buffer)
296 {
297 //
298 // no memory
299 //
300 return STATUS_INSUFFICIENT_RESOURCES;
301 }
302
303 //
304 // copy buffer
305 //
306 RtlCopyMemory(Buffer, DeviceString->Buffer, DeviceString->Length);
307 Buffer[DeviceString->Length / sizeof(WCHAR)] = UNICODE_NULL;
308 Irp->IoStatus.Information = (ULONG_PTR)Buffer;
309
310 return STATUS_SUCCESS;
311 }
312
313 NTSTATUS
314 PDO_HandlePnp(
315 PDEVICE_OBJECT DeviceObject,
316 PIRP Irp)
317 {
318 PIO_STACK_LOCATION IoStack;
319 PPDO_DEVICE_EXTENSION PDODeviceExtension;
320 NTSTATUS Status;
321 ULONG Index, bFound;
322
323 //
324 // get current stack location
325 //
326 IoStack = IoGetCurrentIrpStackLocation(Irp);
327
328 //
329 // get device extension
330 //
331 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
332
333 //
334 // sanity check
335 //
336 ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
337
338 switch(IoStack->MinorFunction)
339 {
340 case IRP_MN_QUERY_DEVICE_RELATIONS:
341 {
342 //
343 // handle device relations
344 //
345 Status = USBCCGP_PdoHandleDeviceRelations(DeviceObject, Irp);
346 break;
347 }
348 case IRP_MN_QUERY_DEVICE_TEXT:
349 {
350 //
351 // handle query device text
352 //
353 Status = USBCCGP_PdoHandleQueryDeviceText(DeviceObject, Irp);
354 break;
355 }
356 case IRP_MN_QUERY_ID:
357 {
358 //
359 // handle request
360 //
361 Status = USBCCGP_PdoHandleQueryId(DeviceObject, Irp);
362 break;
363 }
364 case IRP_MN_REMOVE_DEVICE:
365 {
366 //
367 // remove us from the fdo's pdo list
368 //
369 bFound = FALSE;
370 for(Index = 0; Index < PDODeviceExtension->FDODeviceExtension->FunctionDescriptorCount; Index++)
371 {
372 if (PDODeviceExtension->FDODeviceExtension->ChildPDO[Index] == DeviceObject)
373 {
374 //
375 // remove us
376 //
377 PDODeviceExtension->FDODeviceExtension->ChildPDO[Index] = NULL;
378 bFound = TRUE;
379 break;
380 }
381 }
382
383 //
384 // Complete the IRP
385 //
386 Irp->IoStatus.Status = STATUS_SUCCESS;
387 IoCompleteRequest(Irp, IO_NO_INCREMENT);
388
389 if (bFound)
390 {
391 //
392 // Delete the device object
393 //
394 IoDeleteDevice(DeviceObject);
395 }
396 return STATUS_SUCCESS;
397 }
398 case IRP_MN_QUERY_CAPABILITIES:
399 {
400 //
401 // copy device capabilities
402 //
403 RtlCopyMemory(IoStack->Parameters.DeviceCapabilities.Capabilities, &PDODeviceExtension->Capabilities, sizeof(DEVICE_CAPABILITIES));
404
405 /* Complete the IRP */
406 Irp->IoStatus.Status = STATUS_SUCCESS;
407 IoCompleteRequest(Irp, IO_NO_INCREMENT);
408 return STATUS_SUCCESS;
409 }
410 case IRP_MN_QUERY_REMOVE_DEVICE:
411 case IRP_MN_QUERY_STOP_DEVICE:
412 {
413 //
414 // sure
415 //
416 Status = STATUS_SUCCESS;
417 break;
418 }
419 case IRP_MN_START_DEVICE:
420 {
421 //
422 // no-op for PDO
423 //
424 DPRINT("[USBCCGP] PDO IRP_MN_START\n");
425 Status = STATUS_SUCCESS;
426 break;
427 }
428 case IRP_MN_QUERY_INTERFACE:
429 {
430 //
431 // forward to lower device object
432 //
433 IoSkipCurrentIrpStackLocation(Irp);
434 return IoCallDriver(PDODeviceExtension->NextDeviceObject, Irp);
435 }
436 default:
437 {
438 //
439 // do nothing
440 //
441 Status = Irp->IoStatus.Status;
442 break;
443 }
444 }
445
446 //
447 // complete request
448 //
449 if (Status != STATUS_PENDING)
450 {
451 //
452 // store result
453 //
454 Irp->IoStatus.Status = Status;
455
456 //
457 // complete request
458 //
459 IoCompleteRequest(Irp, IO_NO_INCREMENT);
460 }
461
462 //
463 // done processing
464 //
465 return Status;
466
467 }
468
469 NTSTATUS
470 USBCCGP_BuildConfigurationDescriptor(
471 PDEVICE_OBJECT DeviceObject,
472 PIRP Irp)
473 {
474 PIO_STACK_LOCATION IoStack;
475 PPDO_DEVICE_EXTENSION PDODeviceExtension;
476 PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
477 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
478 ULONG TotalSize, Index;
479 ULONG Size;
480 PURB Urb;
481 PVOID Buffer;
482 PUCHAR BufferPtr;
483 UCHAR InterfaceNumber;
484
485 //
486 // get current stack location
487 //
488 IoStack = IoGetCurrentIrpStackLocation(Irp);
489
490 DPRINT("USBCCGP_BuildConfigurationDescriptor\n");
491
492 //
493 // get device extension
494 //
495 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
496
497 //
498 // get configuration descriptor
499 //
500 ConfigurationDescriptor = PDODeviceExtension->ConfigurationDescriptor;
501
502 //
503 // calculate size of configuration descriptor
504 //
505 TotalSize = sizeof(USB_CONFIGURATION_DESCRIPTOR);
506
507 for (Index = 0; Index < PDODeviceExtension->FunctionDescriptor->NumberOfInterfaces; Index++)
508 {
509 //
510 // get current interface descriptor
511 //
512 InterfaceDescriptor = PDODeviceExtension->FunctionDescriptor->InterfaceDescriptorList[Index];
513 InterfaceNumber = InterfaceDescriptor->bInterfaceNumber;
514
515 //
516 // add to size and move to next descriptor
517 //
518 TotalSize += InterfaceDescriptor->bLength;
519 InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
520
521 do
522 {
523 if ((ULONG_PTR)InterfaceDescriptor >= ((ULONG_PTR)ConfigurationDescriptor + ConfigurationDescriptor->wTotalLength))
524 {
525 //
526 // reached end of configuration descriptor
527 //
528 break;
529 }
530
531 //
532 // association descriptors are removed
533 //
534 if (InterfaceDescriptor->bDescriptorType != USB_INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE)
535 {
536 if (InterfaceDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
537 {
538 if (InterfaceNumber != InterfaceDescriptor->bInterfaceNumber)
539 {
540 //
541 // reached next descriptor
542 //
543 break;
544 }
545
546 //
547 // include alternate descriptor
548 //
549 }
550
551 //
552 // append size
553 //
554 TotalSize += InterfaceDescriptor->bLength;
555 }
556
557 //
558 // move to next descriptor
559 //
560 InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
561 } while(TRUE);
562 }
563
564 //
565 // now allocate temporary buffer for the configuration descriptor
566 //
567 Buffer = AllocateItem(NonPagedPool, TotalSize);
568 if (!Buffer)
569 {
570 //
571 // failed to allocate buffer
572 //
573 DPRINT1("[USBCCGP] Failed to allocate %lu Bytes\n", TotalSize);
574 return STATUS_INSUFFICIENT_RESOURCES;
575 }
576
577 //
578 // first copy the configuration descriptor
579 //
580 RtlCopyMemory(Buffer, ConfigurationDescriptor, sizeof(USB_CONFIGURATION_DESCRIPTOR));
581 BufferPtr = (PUCHAR)((ULONG_PTR)Buffer + ConfigurationDescriptor->bLength);
582
583 for (Index = 0; Index < PDODeviceExtension->FunctionDescriptor->NumberOfInterfaces; Index++)
584 {
585 //
586 // get current interface descriptor
587 //
588 InterfaceDescriptor = PDODeviceExtension->FunctionDescriptor->InterfaceDescriptorList[Index];
589 InterfaceNumber = InterfaceDescriptor->bInterfaceNumber;
590
591 //
592 // copy descriptor and move to next descriptor
593 //
594 RtlCopyMemory(BufferPtr, InterfaceDescriptor, InterfaceDescriptor->bLength);
595 BufferPtr += InterfaceDescriptor->bLength;
596 InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
597
598 do
599 {
600 if ((ULONG_PTR)InterfaceDescriptor >= ((ULONG_PTR)ConfigurationDescriptor + ConfigurationDescriptor->wTotalLength))
601 {
602 //
603 // reached end of configuration descriptor
604 //
605 break;
606 }
607
608 //
609 // association descriptors are removed
610 //
611 if (InterfaceDescriptor->bDescriptorType != USB_INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE)
612 {
613 if (InterfaceDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
614 {
615 if (InterfaceNumber != InterfaceDescriptor->bInterfaceNumber)
616 {
617 //
618 // reached next descriptor
619 //
620 break;
621 }
622
623 //
624 // include alternate descriptor
625 //
626 DPRINT("InterfaceDescriptor %p Alternate %x InterfaceNumber %x\n", InterfaceDescriptor, InterfaceDescriptor->bAlternateSetting, InterfaceDescriptor->bInterfaceNumber);
627 }
628
629 //
630 // copy descriptor
631 //
632 RtlCopyMemory(BufferPtr, InterfaceDescriptor, InterfaceDescriptor->bLength);
633 BufferPtr += InterfaceDescriptor->bLength;
634 }
635
636 //
637 // move to next descriptor
638 //
639 InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
640 } while(TRUE);
641 }
642
643 //
644 // modify configuration descriptor
645 //
646 ConfigurationDescriptor = Buffer;
647 ConfigurationDescriptor->wTotalLength = (USHORT)TotalSize;
648 ConfigurationDescriptor->bNumInterfaces = PDODeviceExtension->FunctionDescriptor->NumberOfInterfaces;
649
650 //
651 // get urb
652 //
653 Urb = (PURB)IoStack->Parameters.Others.Argument1;
654 ASSERT(Urb);
655
656 //
657 // copy descriptor
658 //
659 Size = min(TotalSize, Urb->UrbControlDescriptorRequest.TransferBufferLength);
660 RtlCopyMemory(Urb->UrbControlDescriptorRequest.TransferBuffer, Buffer, Size);
661
662 //
663 // store final size
664 //
665 Urb->UrbControlDescriptorRequest.TransferBufferLength = Size;
666
667 //
668 // free buffer
669 //
670 FreeItem(Buffer);
671
672 //
673 // done
674 //
675 return STATUS_SUCCESS;
676 }
677
678 NTSTATUS
679 USBCCGP_PDOSelectConfiguration(
680 PDEVICE_OBJECT DeviceObject,
681 PIRP Irp)
682 {
683 PIO_STACK_LOCATION IoStack;
684 PPDO_DEVICE_EXTENSION PDODeviceExtension;
685 PURB Urb, NewUrb;
686 PUSBD_INTERFACE_INFORMATION InterfaceInformation;
687 ULONG InterfaceIndex, Length;
688 PUSBD_INTERFACE_LIST_ENTRY Entry;
689 ULONG NeedSelect, FoundInterface;
690 NTSTATUS Status;
691
692 //
693 // get current stack location
694 //
695 IoStack = IoGetCurrentIrpStackLocation(Irp);
696
697 //
698 // get device extension
699 //
700 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
701
702 //
703 // get urb
704 //
705 Urb = (PURB)IoStack->Parameters.Others.Argument1;
706 ASSERT(Urb);
707
708 //
709 // is there already an configuration handle
710 //
711 if (Urb->UrbSelectConfiguration.ConfigurationHandle)
712 {
713 //
714 // nothing to do
715 //
716 return STATUS_SUCCESS;
717 }
718
719 // sanity checks
720 //C_ASSERT(sizeof(struct _URB_HEADER) == 16);
721 //C_ASSERT(FIELD_OFFSET(struct _URB_SELECT_CONFIGURATION, Interface.Length) == 24);
722 //C_ASSERT(sizeof(USBD_INTERFACE_INFORMATION) == 36);
723 //C_ASSERT(sizeof(struct _URB_SELECT_CONFIGURATION) == 0x3C);
724
725 // available buffer length
726 Length = Urb->UrbSelectConfiguration.Hdr.Length - FIELD_OFFSET(struct _URB_SELECT_CONFIGURATION, Interface.Length);
727
728 //
729 // check all interfaces
730 //
731 InterfaceInformation = &Urb->UrbSelectConfiguration.Interface;
732
733 Entry = NULL;
734 do
735 {
736 DPRINT1("[USBCCGP] SelectConfiguration Function %x InterfaceNumber %x Alternative %x Length %lu InterfaceInformation->Length %lu\n", PDODeviceExtension->FunctionDescriptor->FunctionNumber, InterfaceInformation->InterfaceNumber, InterfaceInformation->AlternateSetting, Length, InterfaceInformation->Length);
737 ASSERT(InterfaceInformation->Length);
738 //
739 // search for the interface in the local interface list
740 //
741 FoundInterface = FALSE;
742 for (InterfaceIndex = 0; InterfaceIndex < PDODeviceExtension->FunctionDescriptor->NumberOfInterfaces; InterfaceIndex++)
743 {
744 if (PDODeviceExtension->FunctionDescriptor->InterfaceDescriptorList[InterfaceIndex]->bInterfaceNumber == InterfaceInformation->InterfaceNumber)
745 {
746 // found interface entry
747 FoundInterface = TRUE;
748 break;
749 }
750 }
751
752 if (!FoundInterface)
753 {
754 //
755 // invalid parameter
756 //
757 DPRINT1("InterfaceInformation InterfaceNumber %x Alternative %x NumberOfPipes %x not found\n", InterfaceInformation->InterfaceNumber, InterfaceInformation->AlternateSetting, InterfaceInformation->NumberOfPipes);
758 ASSERT(FALSE);
759 return STATUS_INVALID_PARAMETER;
760 }
761
762 //
763 // now query the total interface list
764 //
765 Entry = NULL;
766 for (InterfaceIndex = 0; InterfaceIndex < PDODeviceExtension->InterfaceListCount; InterfaceIndex++)
767 {
768 if (PDODeviceExtension->InterfaceList[InterfaceIndex].Interface->InterfaceNumber == InterfaceInformation->InterfaceNumber)
769 {
770 //
771 // found entry
772 //
773 Entry = &PDODeviceExtension->InterfaceList[InterfaceIndex];
774 }
775 }
776
777 //
778 // sanity check
779 //
780 ASSERT(Entry);
781 if (!Entry)
782 {
783 //
784 // corruption detected
785 //
786 KeBugCheck(0);
787 }
788
789 NeedSelect = FALSE;
790 if (Entry->InterfaceDescriptor->bAlternateSetting == InterfaceInformation->AlternateSetting)
791 {
792 for(InterfaceIndex = 0; InterfaceIndex < InterfaceInformation->NumberOfPipes; InterfaceIndex++)
793 {
794 if (InterfaceInformation->Pipes[InterfaceIndex].MaximumTransferSize != Entry->Interface->Pipes[InterfaceIndex].MaximumTransferSize)
795 {
796 //
797 // changed interface
798 //
799 NeedSelect = TRUE;
800 }
801 }
802 }
803 else
804 {
805 //
806 // need select as the interface number differ
807 //
808 NeedSelect = TRUE;
809 }
810
811 if (!NeedSelect)
812 {
813 //
814 // interface is already selected
815 //
816 ASSERT(Length >= Entry->Interface->Length);
817 RtlCopyMemory(InterfaceInformation, Entry->Interface, Entry->Interface->Length);
818
819 //
820 // adjust remaining buffer size
821 //
822 ASSERT(Entry->Interface->Length);
823 Length -= Entry->Interface->Length;
824
825 //
826 // move to next output interface information
827 //
828 InterfaceInformation = (PUSBD_INTERFACE_INFORMATION)((ULONG_PTR)InterfaceInformation + Entry->Interface->Length);
829 }
830 else
831 {
832 //
833 // select interface
834 //
835 DPRINT1("Selecting InterfaceIndex %lu AlternateSetting %lu NumberOfPipes %lu\n", InterfaceInformation->InterfaceNumber, InterfaceInformation->AlternateSetting, InterfaceInformation->NumberOfPipes);
836 ASSERT(InterfaceInformation->Length == Entry->Interface->Length);
837
838 //
839 // build urb
840 //
841 NewUrb = AllocateItem(NonPagedPool, GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceInformation->NumberOfPipes));
842 if (!NewUrb)
843 {
844 //
845 // no memory
846 //
847 return STATUS_INSUFFICIENT_RESOURCES;
848 }
849
850 //
851 // now prepare interface urb
852 //
853 UsbBuildSelectInterfaceRequest(NewUrb, (USHORT)GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceInformation->NumberOfPipes), PDODeviceExtension->ConfigurationHandle, InterfaceInformation->InterfaceNumber, InterfaceInformation->AlternateSetting);
854
855 //
856 // now select the interface
857 //
858 Status = USBCCGP_SyncUrbRequest(PDODeviceExtension->NextDeviceObject, NewUrb);
859 DPRINT1("SelectInterface Status %x\n", Status);
860
861 if (!NT_SUCCESS(Status))
862 {
863 //
864 // failed
865 //
866 break;
867 }
868
869 //
870 // update configuration info
871 //
872 ASSERT(Entry->Interface->Length >= NewUrb->UrbSelectInterface.Interface.Length);
873 ASSERT(Length >= NewUrb->UrbSelectInterface.Interface.Length);
874 RtlCopyMemory(Entry->Interface, &NewUrb->UrbSelectInterface.Interface, NewUrb->UrbSelectInterface.Interface.Length);
875
876 //
877 // update provided interface information
878 //
879 ASSERT(Length >= Entry->Interface->Length);
880 RtlCopyMemory(InterfaceInformation, Entry->Interface, Entry->Interface->Length);
881
882 //
883 // decrement remaining buffer size
884 //
885 ASSERT(Entry->Interface->Length);
886 Length -= Entry->Interface->Length;
887
888 //
889 // adjust output buffer offset
890 //
891 InterfaceInformation = (PUSBD_INTERFACE_INFORMATION)((ULONG_PTR)InterfaceInformation + Entry->Interface->Length);
892
893 //
894 // free urb
895 //
896 FreeItem(NewUrb);
897 }
898
899 } while(Length);
900
901 //
902 // store configuration handle
903 //
904 Urb->UrbSelectConfiguration.ConfigurationHandle = PDODeviceExtension->ConfigurationHandle;
905
906 DPRINT1("[USBCCGP] SelectConfiguration Function %x Completed\n", PDODeviceExtension->FunctionDescriptor->FunctionNumber);
907
908 //
909 // done
910 //
911 return STATUS_SUCCESS;
912 }
913
914 NTSTATUS
915 PDO_HandleInternalDeviceControl(
916 PDEVICE_OBJECT DeviceObject,
917 PIRP Irp)
918 {
919 PIO_STACK_LOCATION IoStack;
920 PPDO_DEVICE_EXTENSION PDODeviceExtension;
921 NTSTATUS Status;
922 PURB Urb;
923
924 //
925 // get current stack location
926 //
927 IoStack = IoGetCurrentIrpStackLocation(Irp);
928
929 //
930 // get device extension
931 //
932 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
933
934 if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_SUBMIT_URB)
935 {
936 //
937 // get urb
938 //
939 Urb = (PURB)IoStack->Parameters.Others.Argument1;
940 ASSERT(Urb);
941 DPRINT("IOCTL_INTERNAL_USB_SUBMIT_URB Function %x\n", Urb->UrbHeader.Function);
942
943 if (Urb->UrbHeader.Function == URB_FUNCTION_SELECT_CONFIGURATION)
944 {
945 //
946 // select configuration
947 //
948 Status = USBCCGP_PDOSelectConfiguration(DeviceObject, Irp);
949 Irp->IoStatus.Status = Status;
950 IoCompleteRequest(Irp, IO_NO_INCREMENT);
951 return Status;
952 }
953 else if (Urb->UrbHeader.Function == URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE)
954 {
955 if (Urb->UrbControlDescriptorRequest.DescriptorType == USB_DEVICE_DESCRIPTOR_TYPE)
956 {
957 //
958 // is the buffer big enough
959 //
960 if (Urb->UrbControlDescriptorRequest.TransferBufferLength < sizeof(USB_DEVICE_DESCRIPTOR))
961 {
962 //
963 // invalid buffer size
964 //
965 DPRINT1("[USBCCGP] invalid device descriptor size %lu\n", Urb->UrbControlDescriptorRequest.TransferBufferLength);
966 Urb->UrbControlDescriptorRequest.TransferBufferLength = sizeof(USB_DEVICE_DESCRIPTOR);
967 Irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE;
968 IoCompleteRequest(Irp, IO_NO_INCREMENT);
969 return STATUS_INVALID_BUFFER_SIZE;
970 }
971
972 //
973 // copy device descriptor
974 //
975 ASSERT(Urb->UrbControlDescriptorRequest.TransferBuffer);
976 RtlCopyMemory(Urb->UrbControlDescriptorRequest.TransferBuffer, &PDODeviceExtension->DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
977 Irp->IoStatus.Status = STATUS_SUCCESS;
978 IoCompleteRequest(Irp, IO_NO_INCREMENT);
979 return STATUS_SUCCESS;
980 }
981 else if (Urb->UrbControlDescriptorRequest.DescriptorType == USB_CONFIGURATION_DESCRIPTOR_TYPE)
982 {
983 //
984 // build configuration descriptor
985 //
986 Status = USBCCGP_BuildConfigurationDescriptor(DeviceObject, Irp);
987 Irp->IoStatus.Status = Status;
988 IoCompleteRequest(Irp, IO_NO_INCREMENT);
989 return Status;
990 }
991 else if (Urb->UrbControlDescriptorRequest.DescriptorType == USB_STRING_DESCRIPTOR_TYPE)
992 {
993 PUSB_STRING_DESCRIPTOR StringDescriptor;
994
995 //
996 // get the requested string descriptor
997 //
998 ASSERT(Urb->UrbControlDescriptorRequest.TransferBuffer);
999 Status = USBCCGP_GetDescriptor(PDODeviceExtension->FDODeviceExtension->NextDeviceObject,
1000 USB_STRING_DESCRIPTOR_TYPE,
1001 Urb->UrbControlDescriptorRequest.TransferBufferLength,
1002 Urb->UrbControlDescriptorRequest.Index,
1003 Urb->UrbControlDescriptorRequest.LanguageId,
1004 (PVOID*)&StringDescriptor);
1005 if (NT_SUCCESS(Status))
1006 {
1007 if (StringDescriptor->bLength == 2)
1008 {
1009 FreeItem(StringDescriptor);
1010 Status = STATUS_DEVICE_DATA_ERROR;
1011 }
1012 else
1013 {
1014 RtlCopyMemory(Urb->UrbControlDescriptorRequest.TransferBuffer,
1015 StringDescriptor->bString,
1016 StringDescriptor->bLength + sizeof(WCHAR));
1017 FreeItem(StringDescriptor);
1018 Status = STATUS_SUCCESS;
1019 }
1020 }
1021 Irp->IoStatus.Status = Status;
1022 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1023 return Status;
1024 }
1025 }
1026 else
1027 {
1028 IoSkipCurrentIrpStackLocation(Irp);
1029 Status = IoCallDriver(PDODeviceExtension->NextDeviceObject, Irp);
1030 return Status;
1031 }
1032 }
1033 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_GET_PORT_STATUS)
1034 {
1035 IoSkipCurrentIrpStackLocation(Irp);
1036 Status = IoCallDriver(PDODeviceExtension->NextDeviceObject, Irp);
1037 return Status;
1038 }
1039 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_RESET_PORT)
1040 {
1041 IoSkipCurrentIrpStackLocation(Irp);
1042 Status = IoCallDriver(PDODeviceExtension->NextDeviceObject, Irp);
1043 return Status;
1044 }
1045 else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_CYCLE_PORT)
1046 {
1047 IoSkipCurrentIrpStackLocation(Irp);
1048 Status = IoCallDriver(PDODeviceExtension->NextDeviceObject, Irp);
1049 return Status;
1050 }
1051
1052 DPRINT1("IOCTL %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
1053 DPRINT1("InputBufferLength %lu\n", IoStack->Parameters.DeviceIoControl.InputBufferLength);
1054 DPRINT1("OutputBufferLength %lu\n", IoStack->Parameters.DeviceIoControl.OutputBufferLength);
1055 DPRINT1("Type3InputBuffer %p\n", IoStack->Parameters.DeviceIoControl.Type3InputBuffer);
1056
1057 ASSERT(FALSE);
1058
1059 Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
1060 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1061 return STATUS_NOT_IMPLEMENTED;
1062 }
1063
1064
1065 NTSTATUS
1066 PDO_Dispatch(
1067 PDEVICE_OBJECT DeviceObject,
1068 PIRP Irp)
1069 {
1070 PIO_STACK_LOCATION IoStack;
1071 NTSTATUS Status;
1072
1073 /* get stack location */
1074 IoStack = IoGetCurrentIrpStackLocation(Irp);
1075
1076 switch(IoStack->MajorFunction)
1077 {
1078 case IRP_MJ_PNP:
1079 return PDO_HandlePnp(DeviceObject, Irp);
1080 case IRP_MJ_INTERNAL_DEVICE_CONTROL:
1081 return PDO_HandleInternalDeviceControl(DeviceObject, Irp);
1082 case IRP_MJ_POWER:
1083 PoStartNextPowerIrp(Irp);
1084 Irp->IoStatus.Status = STATUS_SUCCESS;
1085 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1086 return STATUS_SUCCESS;
1087 default:
1088 DPRINT1("PDO_Dispatch Function %x not implemented\n", IoStack->MajorFunction);
1089 Status = Irp->IoStatus.Status;
1090 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1091 return Status;
1092 }
1093 }