Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676/* * PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface * LICENSE: GPL - See COPYING in the top level directory * FILE: drivers/usb/usbccgp/fdo.c * PURPOSE: USB device driver. * PROGRAMMERS: * Michael Martin (michael.martin@reactos.org) * Johannes Anderwald (johannes.anderwald@reactos.org) * Cameron Gutman */
#include "usbccgp.h"
#define NDEBUG#include <debug.h>
NTSTATUSNTAPIFDO_QueryCapabilitiesCompletionRoutine( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context){ /* Set event */ KeSetEvent((PRKEVENT)Context, 0, FALSE);
/* Completion is done in the HidClassFDO_QueryCapabilities routine */ return STATUS_MORE_PROCESSING_REQUIRED;}
NTSTATUSFDO_QueryCapabilities( IN PDEVICE_OBJECT DeviceObject, IN OUT PDEVICE_CAPABILITIES Capabilities){ PIRP Irp; KEVENT Event; NTSTATUS Status; PIO_STACK_LOCATION IoStack; PFDO_DEVICE_EXTENSION FDODeviceExtension;
/* Get device extension */ FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; ASSERT(FDODeviceExtension->Common.IsFDO);
/* Init event */ KeInitializeEvent(&Event, NotificationEvent, FALSE);
/* Now allocate the irp */ Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE); if (!Irp) { /* No memory */ return STATUS_INSUFFICIENT_RESOURCES; }
/* Get next stack location */ IoStack = IoGetNextIrpStackLocation(Irp);
/* Init stack location */ IoStack->MajorFunction = IRP_MJ_PNP; IoStack->MinorFunction = IRP_MN_QUERY_CAPABILITIES; IoStack->Parameters.DeviceCapabilities.Capabilities = Capabilities;
/* Set completion routine */ IoSetCompletionRoutine(Irp, FDO_QueryCapabilitiesCompletionRoutine, (PVOID)&Event, TRUE, TRUE, TRUE);
/* Init capabilities */ RtlZeroMemory(Capabilities, sizeof(DEVICE_CAPABILITIES)); Capabilities->Size = sizeof(DEVICE_CAPABILITIES); Capabilities->Version = 1; // FIXME hardcoded constant Capabilities->Address = MAXULONG; Capabilities->UINumber = MAXULONG;
/* Pnp irps have default completion code */ Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
/* Call lower device */ Status = IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp); if (Status == STATUS_PENDING) { /* Wait for completion */ KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL); }
/* Get status */ Status = Irp->IoStatus.Status;
/* Complete request */ IoFreeIrp(Irp);
/* Done */ return Status;}
NTSTATUSFDO_DeviceRelations( PDEVICE_OBJECT DeviceObject, PIRP Irp){ ULONG DeviceCount = 0; ULONG Index; PDEVICE_RELATIONS DeviceRelations; PIO_STACK_LOCATION IoStack; PFDO_DEVICE_EXTENSION FDODeviceExtension;
/* Get device extension */ FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
/* Get current irp stack location */ IoStack = IoGetCurrentIrpStackLocation(Irp);
/* Check if relation type is BusRelations */ if (IoStack->Parameters.QueryDeviceRelations.Type != BusRelations) { /* FDO always only handles bus relations */ return STATUS_SUCCESS; }
/* Go through array and count device objects */ for(Index = 0; Index < FDODeviceExtension->FunctionDescriptorCount; Index++) { if (FDODeviceExtension->ChildPDO[Index]) { /* Child pdo */ DeviceCount++; } }
/* Allocate device relations */ DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(PagedPool, sizeof(DEVICE_RELATIONS) + (DeviceCount > 1 ? (DeviceCount-1) * sizeof(PDEVICE_OBJECT) : 0)); if (!DeviceRelations) { /* No memory */ return STATUS_INSUFFICIENT_RESOURCES; }
/* Add device objects */ for(Index = 0; Index < FDODeviceExtension->FunctionDescriptorCount; Index++) { if (FDODeviceExtension->ChildPDO[Index]) { /* Store child pdo */ DeviceRelations->Objects[DeviceRelations->Count] = FDODeviceExtension->ChildPDO[Index];
/* Add reference */ ObReferenceObject(FDODeviceExtension->ChildPDO[Index]);
/* Increment count */ DeviceRelations->Count++; } }
/* Store result */ Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations; Irp->IoStatus.Status = STATUS_SUCCESS;
/* Request completed successfully */ return STATUS_SUCCESS;}
NTSTATUSFDO_CreateChildPdo( IN PDEVICE_OBJECT DeviceObject){ NTSTATUS Status; PDEVICE_OBJECT PDODeviceObject; PPDO_DEVICE_EXTENSION PDODeviceExtension; PFDO_DEVICE_EXTENSION FDODeviceExtension; ULONG Index;
/* Get device extension */ FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; ASSERT(FDODeviceExtension->Common.IsFDO);
/* Lets create array for the child PDO */ FDODeviceExtension->ChildPDO = AllocateItem(NonPagedPool, sizeof(PDEVICE_OBJECT) * FDODeviceExtension->FunctionDescriptorCount); if (!FDODeviceExtension->ChildPDO) { /* No memory */ return STATUS_INSUFFICIENT_RESOURCES; }
/* Create pdo for each function */ for (Index = 0; Index < FDODeviceExtension->FunctionDescriptorCount; Index++) { if (FDODeviceExtension->FunctionDescriptor[Index].NumberOfInterfaces == 0) { // Ignore invalid devices DPRINT1("[USBCCGP] Found descriptor with 0 interfaces\n"); continue; }
/* Create the PDO */ Status = IoCreateDevice(FDODeviceExtension->DriverObject, sizeof(PDO_DEVICE_EXTENSION), NULL, FILE_DEVICE_USB, FILE_AUTOGENERATED_DEVICE_NAME, FALSE, &PDODeviceObject); if (!NT_SUCCESS(Status)) { /* Failed to create device object */ DPRINT1("IoCreateDevice failed with %x\n", Status); return Status; }
/* Store in array */ FDODeviceExtension->ChildPDO[Index] = PDODeviceObject;
/* Get device extension */ PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension; RtlZeroMemory(PDODeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
/* Init device extension */ PDODeviceExtension->Common.IsFDO = FALSE; PDODeviceExtension->FunctionDescriptor = &FDODeviceExtension->FunctionDescriptor[Index]; PDODeviceExtension->NextDeviceObject = DeviceObject; PDODeviceExtension->FunctionIndex = Index; PDODeviceExtension->FDODeviceExtension = FDODeviceExtension; PDODeviceExtension->InterfaceList = FDODeviceExtension->InterfaceList; PDODeviceExtension->InterfaceListCount = FDODeviceExtension->InterfaceListCount; PDODeviceExtension->ConfigurationHandle = FDODeviceExtension->ConfigurationHandle; PDODeviceExtension->ConfigurationDescriptor = FDODeviceExtension->ConfigurationDescriptor; RtlCopyMemory(&PDODeviceExtension->Capabilities, &FDODeviceExtension->Capabilities, sizeof(DEVICE_CAPABILITIES)); RtlCopyMemory(&PDODeviceExtension->DeviceDescriptor, FDODeviceExtension->DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
/* Patch the stack size */ PDODeviceObject->StackSize = DeviceObject->StackSize + 1;
/* Set device flags */ PDODeviceObject->Flags |= DO_DIRECT_IO | DO_MAP_IO_BUFFER;
/* Device is initialized */ PDODeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; }
/* Done */ return STATUS_SUCCESS;}
NTSTATUSFDO_StartDevice( PDEVICE_OBJECT DeviceObject, PIRP Irp){ NTSTATUS Status; PFDO_DEVICE_EXTENSION FDODeviceExtension;
/* Get device extension */ FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; ASSERT(FDODeviceExtension->Common.IsFDO);
/* First start lower device */ if (IoForwardIrpSynchronously(FDODeviceExtension->NextDeviceObject, Irp)) { Status = Irp->IoStatus.Status; } else { Status = STATUS_UNSUCCESSFUL; }
if (!NT_SUCCESS(Status)) { /* Failed to start lower device */ DPRINT1("FDO_StartDevice lower device failed to start with %x\n", Status); return Status; }
/* Get descriptors */ Status = USBCCGP_GetDescriptors(DeviceObject); if (!NT_SUCCESS(Status)) { /* Failed to start lower device */ DPRINT1("FDO_StartDevice failed to get descriptors with %x\n", Status); return Status; }
/* Get capabilities */ Status = FDO_QueryCapabilities(DeviceObject, &FDODeviceExtension->Capabilities); if (!NT_SUCCESS(Status)) { /* Failed to start lower device */ DPRINT1("FDO_StartDevice failed to get capabilities with %x\n", Status); return Status; }
/* Now select the configuration */ Status = USBCCGP_SelectConfiguration(DeviceObject, FDODeviceExtension); if (!NT_SUCCESS(Status)) { /* Failed to select interface */ DPRINT1("FDO_StartDevice failed to get capabilities with %x\n", Status); return Status; }
/* Query bus interface */ USBCCGP_QueryInterface(FDODeviceExtension->NextDeviceObject, &FDODeviceExtension->BusInterface);
/* Now enumerate the functions */ Status = USBCCGP_EnumerateFunctions(DeviceObject); if (!NT_SUCCESS(Status)) { /* Failed to enumerate functions */ DPRINT1("Failed to enumerate functions with %x\n", Status); return Status; }
/* Sanity checks */ ASSERT(FDODeviceExtension->FunctionDescriptorCount); ASSERT(FDODeviceExtension->FunctionDescriptor); DumpFunctionDescriptor(FDODeviceExtension->FunctionDescriptor, FDODeviceExtension->FunctionDescriptorCount);
/* Now create the pdo */ Status = FDO_CreateChildPdo(DeviceObject); if (!NT_SUCCESS(Status)) { /* Failed */ DPRINT1("FDO_CreateChildPdo failed with %x\n", Status); return Status; }
/* Inform pnp manager of new device objects */ IoInvalidateDeviceRelations(FDODeviceExtension->PhysicalDeviceObject, BusRelations);
/* Done */ DPRINT("[USBCCGP] FDO initialized successfully\n"); return Status;}
NTSTATUSFDO_CloseConfiguration( IN PDEVICE_OBJECT DeviceObject){ NTSTATUS Status; PURB Urb; PFDO_DEVICE_EXTENSION FDODeviceExtension;
/* Get device extension */ FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; ASSERT(FDODeviceExtension->Common.IsFDO);
/* Nothing to do if we're not configured */ if (FDODeviceExtension->ConfigurationDescriptor == NULL || FDODeviceExtension->InterfaceList == NULL) { return STATUS_SUCCESS; }
/* Now allocate the urb */ Urb = USBD_CreateConfigurationRequestEx(FDODeviceExtension->ConfigurationDescriptor, FDODeviceExtension->InterfaceList); if (!Urb) { /* No memory */ return STATUS_INSUFFICIENT_RESOURCES; }
/* Clear configuration descriptor to make it an unconfigure request */ Urb->UrbSelectConfiguration.ConfigurationDescriptor = NULL;
/* Submit urb */ Status = USBCCGP_SyncUrbRequest(FDODeviceExtension->NextDeviceObject, Urb); if (!NT_SUCCESS(Status)) { /* Failed to set configuration */ DPRINT1("USBCCGP_SyncUrbRequest failed to unconfigure device\n", Status); }
ExFreePool(Urb); return Status;}
NTSTATUSFDO_HandlePnp( PDEVICE_OBJECT DeviceObject, PIRP Irp){ PIO_STACK_LOCATION IoStack; NTSTATUS Status; PFDO_DEVICE_EXTENSION FDODeviceExtension;
/* Get device extension */ FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; ASSERT(FDODeviceExtension->Common.IsFDO);
/* Get stack location */ IoStack = IoGetCurrentIrpStackLocation(Irp); DPRINT("[USBCCGP] PnP Minor %x\n", IoStack->MinorFunction); switch(IoStack->MinorFunction) { case IRP_MN_REMOVE_DEVICE: { // Unconfigure device */ DPRINT1("[USBCCGP] FDO IRP_MN_REMOVE\n"); FDO_CloseConfiguration(DeviceObject);
/* Send the IRP down the stack */ Irp->IoStatus.Status = STATUS_SUCCESS; IoSkipCurrentIrpStackLocation(Irp); Status = IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp);
/* Detach from the device stack */ IoDetachDevice(FDODeviceExtension->NextDeviceObject);
/* Delete the device object */ IoDeleteDevice(DeviceObject);
/* The lower driver completes the IRP for removal */ return Status; } case IRP_MN_START_DEVICE: { /* Start the device */ Status = FDO_StartDevice(DeviceObject, Irp); break; } case IRP_MN_QUERY_DEVICE_RELATIONS: { /* Handle device relations */ Status = FDO_DeviceRelations(DeviceObject, Irp); if (!NT_SUCCESS(Status)) { break; }
/* Forward irp to next device object */ IoSkipCurrentIrpStackLocation(Irp); return IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp); } case IRP_MN_QUERY_CAPABILITIES: { /* Copy capabilities */ RtlCopyMemory(IoStack->Parameters.DeviceCapabilities.Capabilities, &FDODeviceExtension->Capabilities, sizeof(DEVICE_CAPABILITIES)); Status = STATUS_UNSUCCESSFUL;
if (IoForwardIrpSynchronously(FDODeviceExtension->NextDeviceObject, Irp)) { Status = Irp->IoStatus.Status; if (NT_SUCCESS(Status)) { IoStack->Parameters.DeviceCapabilities.Capabilities->SurpriseRemovalOK = TRUE; } } break; } case IRP_MN_QUERY_REMOVE_DEVICE: case IRP_MN_QUERY_STOP_DEVICE: { /* Sure */ Irp->IoStatus.Status = STATUS_SUCCESS;
/* Forward irp to next device object */ IoSkipCurrentIrpStackLocation(Irp); return IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp); } default: { /* Forward irp to next device object */ IoSkipCurrentIrpStackLocation(Irp); return IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp); }
}
/* Complete request */ Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status;}
NTSTATUSFDO_HandleResetCyclePort( PDEVICE_OBJECT DeviceObject, PIRP Irp){ PIO_STACK_LOCATION IoStack; NTSTATUS Status; PFDO_DEVICE_EXTENSION FDODeviceExtension; PLIST_ENTRY ListHead, Entry; LIST_ENTRY TempList; PUCHAR ResetActive; PIRP ListIrp; KIRQL OldLevel;
/* Get device extension */ FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; ASSERT(FDODeviceExtension->Common.IsFDO);
/* Get stack location */ IoStack = IoGetCurrentIrpStackLocation(Irp); DPRINT("FDO_HandleResetCyclePort IOCTL %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_RESET_PORT) { /* Use reset port list */ ListHead = &FDODeviceExtension->ResetPortListHead; ResetActive = &FDODeviceExtension->ResetPortActive; } else { /* Use cycle port list */ ListHead = &FDODeviceExtension->CyclePortListHead; ResetActive = &FDODeviceExtension->CyclePortActive; }
/* Acquire lock */ KeAcquireSpinLock(&FDODeviceExtension->Lock, &OldLevel);
if (*ResetActive) { /* Insert into pending list */ InsertTailList(ListHead, &Irp->Tail.Overlay.ListEntry);
/* Mark irp pending */ IoMarkIrpPending(Irp); Status = STATUS_PENDING;
/* Release lock */ KeReleaseSpinLock(&FDODeviceExtension->Lock, OldLevel); } else { /* Mark reset active */ *ResetActive = TRUE;
/* Release lock */ KeReleaseSpinLock(&FDODeviceExtension->Lock, OldLevel);
/* Forward request synchronized */ NT_VERIFY(IoForwardIrpSynchronously(FDODeviceExtension->NextDeviceObject, Irp));
/* Reacquire lock */ KeAcquireSpinLock(&FDODeviceExtension->Lock, &OldLevel);
/* Mark reset as completed */ *ResetActive = FALSE;
/* Move all requests into temporary list */ InitializeListHead(&TempList); while(!IsListEmpty(ListHead)) { Entry = RemoveHeadList(ListHead); InsertTailList(&TempList, Entry); }
/* Release lock */ KeReleaseSpinLock(&FDODeviceExtension->Lock, OldLevel);
/* Complete pending irps */ while(!IsListEmpty(&TempList)) { Entry = RemoveHeadList(&TempList); ListIrp = (PIRP)CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry);
/* Complete request with status success */ ListIrp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(ListIrp, IO_NO_INCREMENT); }
/* Status success */ Status = STATUS_SUCCESS; }
return Status;}
NTSTATUSFDO_HandleInternalDeviceControl( PDEVICE_OBJECT DeviceObject, PIRP Irp){ PIO_STACK_LOCATION IoStack; NTSTATUS Status; PFDO_DEVICE_EXTENSION FDODeviceExtension;
/* Get device extension */ FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; ASSERT(FDODeviceExtension->Common.IsFDO);
/* Get stack location */ IoStack = IoGetCurrentIrpStackLocation(Irp);
if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_RESET_PORT || IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_CYCLE_PORT) { /* Handle reset / cycle ports */ Status = FDO_HandleResetCyclePort(DeviceObject, Irp); DPRINT("FDO_HandleResetCyclePort Status %x\n", Status); if (Status != STATUS_PENDING) { /* Complete request */ Irp->IoStatus.Status = Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); } return Status; }
/* Forward and forget request */ IoSkipCurrentIrpStackLocation(Irp); return IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp);}
NTSTATUSFDO_HandleSystemControl( PDEVICE_OBJECT DeviceObject, PIRP Irp){ PFDO_DEVICE_EXTENSION FDODeviceExtension;
/* Get device extension */ FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension; ASSERT(FDODeviceExtension->Common.IsFDO);
/* Forward and forget request */ IoSkipCurrentIrpStackLocation(Irp); return IoCallDriver(FDODeviceExtension->NextDeviceObject, Irp);}
NTSTATUSFDO_Dispatch( PDEVICE_OBJECT DeviceObject, PIRP Irp){ PIO_STACK_LOCATION IoStack; NTSTATUS Status; PFDO_DEVICE_EXTENSION FDODeviceExtension;
/* Get device extension */ FDODeviceExtension = DeviceObject->DeviceExtension; ASSERT(FDODeviceExtension->Common.IsFDO);
/* Get stack location */ IoStack = IoGetCurrentIrpStackLocation(Irp);
switch(IoStack->MajorFunction) { case IRP_MJ_PNP: return FDO_HandlePnp(DeviceObject, Irp); case IRP_MJ_INTERNAL_DEVICE_CONTROL: return FDO_HandleInternalDeviceControl(DeviceObject, Irp); case IRP_MJ_POWER: PoStartNextPowerIrp(Irp); IoSkipCurrentIrpStackLocation(Irp); return PoCallDriver(FDODeviceExtension->NextDeviceObject, Irp); case IRP_MJ_SYSTEM_CONTROL: return FDO_HandleSystemControl(DeviceObject, Irp); default: DPRINT1("FDO_Dispatch Function %x not implemented\n", IoStack->MajorFunction); ASSERT(FALSE); Status = Irp->IoStatus.Status; IoCompleteRequest(Irp, IO_NO_INCREMENT); return Status; }
}