[usb/usbehci]

- Implement tracking port status and change status.
- When device has connected on port, set the port status. For now assume high speed device.
- Fix returning root hubs Status Change Endpoint for URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER.
- Implement USB_REQUEST_GET_STATUS for functions URB_FUNCTION_GET_STATUS_FROM_DEVICE and URB_FUNCTION_CLASS_OTHER. Implement USB_REQUEST_CLEAR_FEATURE and USB_REQUEST_SET_FEATURE.
- Implement IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE to return the root hubs device handle, fix IOCTL_INTERNAL_USB_GET_HUB_COUNT to return 1 vice 0 as the root hub must be accounted for.
- Code based on XEN PV Drivers by James Harper.

svn path=/trunk/; revision=46660
This commit is contained in:
Michael Martin 2010-04-02 04:49:01 +00:00
parent b121447744
commit 44cbfd23f2
4 changed files with 169 additions and 51 deletions

View file

@ -100,9 +100,9 @@ EhciDefferedRoutine(PKDPC Dpc, PVOID DeferredContext, PVOID SystemArgument1, PVO
tmp = READ_REGISTER_ULONG((PULONG)((Base + EHCI_PORTSC) + (4 * i)));
DPRINT("port tmp %x\n", tmp);
GetDeviceDescriptor(FdoDeviceExtension, 0, 0, FALSE);
PdoDeviceExtension->ChildDeviceCount++;
PdoDeviceExtension->Ports[i].PortStatus |= USB_PORT_STATUS_HIGH_SPEED | USB_PORT_STATUS_CONNECT | USB_PORT_STATUS_ENABLE;
WorkItemData = ExAllocatePool(NonPagedPool, sizeof(WORKITEM_DATA));
if (!WorkItemData) ASSERT(FALSE);
WorkItemData->IoWorkItem = IoAllocateWorkItem(PdoDeviceExtension->DeviceObject);

View file

@ -88,35 +88,65 @@ CompletePendingURBRequest(PPDO_DEVICE_EXTENSION DeviceExtension)
if (UsbDevice == NULL)
UsbDevice = DeviceExtension->UsbDevices[0];
/* Assume URB success */
Urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
/* Set the DeviceHandle to the Internal Device */
Urb->UrbHeader.UsbdDeviceHandle = UsbDevice;
switch (Urb->UrbHeader.Function)
{
case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
{
/* Are we suppose to only return on this request when a device is connected
or is it the RootHubInitNotification Callback */
DPRINT1("URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:\n");
DPRINT1("--->TransferBufferLength %x\n",Urb->UrbBulkOrInterruptTransfer.TransferBufferLength);
DPRINT1("--->TransferBuffer %x\n",Urb->UrbBulkOrInterruptTransfer.TransferBuffer);
DPRINT1("--->PipeHandle %x\n",Urb->UrbBulkOrInterruptTransfer.PipeHandle);
DPRINT1("---->(PVOID)&UsbDevice->EndPointDescriptor %x\n", (PVOID)&UsbDevice->EndPointDescriptor);
DPRINT1("--->TransferFlags %x\n", Urb->UrbBulkOrInterruptTransfer.TransferFlags);
/* FIXME */
RtlZeroMemory(Urb->UrbBulkOrInterruptTransfer.TransferBuffer, Urb->UrbBulkOrInterruptTransfer.TransferBufferLength);
((PUCHAR)Urb->UrbBulkOrInterruptTransfer.TransferBuffer)[0] = 1;
/* Turn off Irp handling as nothing is handled beyond this */
DeviceExtension->HaltUrbHandling = TRUE;
if (UsbDevice == DeviceExtension->UsbDevices[0])
{
if (Urb->UrbBulkOrInterruptTransfer.TransferFlags & (USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK))
{
LONG i;
for (i = 0; i < 8; i++)
{
if (DeviceExtension->Ports[i].PortChange)
{
DPRINT1("Inform hub driver that port %d has changed\n", i+1);
((PUCHAR)Urb->UrbBulkOrInterruptTransfer.TransferBuffer)[0] = 1 << (i + 1);
}
}
}
else
{
Urb->UrbHeader.Status = USBD_STATUS_INVALID_PARAMETER;
Status = STATUS_UNSUCCESSFUL;
}
}
break;
}
case URB_FUNCTION_GET_STATUS_FROM_DEVICE:
{
DPRINT1("Get Status from Device\n");
DPRINT("Get Status from Device\n");
DPRINT("Index : %d\n", Urb->UrbControlGetStatusRequest.Index);
/* Copied from pvdrivers */
if (Urb->UrbControlGetStatusRequest.Index == 0)
{
*(PUSHORT)Urb->UrbControlGetStatusRequest.TransferBuffer = USB_PORT_STATUS_CONNECT | USB_PORT_STATUS_ENABLE;
}
else
{
DPRINT1("Uknown identifier\n");
Urb->UrbHeader.Status = USBD_STATUS_INVALID_URB_FUNCTION;
Status = STATUS_UNSUCCESSFUL;
}
break;
}
case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
{
Urb->UrbHeader.Function = 0x08;
Urb->UrbHeader.UsbdFlags = 0;
Urb->UrbHeader.UsbdDeviceHandle = UsbDevice;
switch(Urb->UrbControlDescriptorRequest.DescriptorType)
{
case USB_DEVICE_DESCRIPTOR_TYPE:
@ -130,9 +160,6 @@ CompletePendingURBRequest(PPDO_DEVICE_EXTENSION DeviceExtension)
RtlCopyMemory(Urb->UrbControlDescriptorRequest.TransferBuffer,
&UsbDevice->DeviceDescriptor,
Urb->UrbControlDescriptorRequest.TransferBufferLength);
Urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
break;
}
case USB_CONFIGURATION_DESCRIPTOR_TYPE:
@ -150,9 +177,6 @@ CompletePendingURBRequest(PPDO_DEVICE_EXTENSION DeviceExtension)
RtlCopyMemory(Urb->UrbControlDescriptorRequest.TransferBuffer,
&UsbDevice->ConfigurationDescriptor,
Urb->UrbControlDescriptorRequest.TransferBufferLength);
Urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
break;
}
case USB_STRING_DESCRIPTOR_TYPE:
@ -232,10 +256,6 @@ CompletePendingURBRequest(PPDO_DEVICE_EXTENSION DeviceExtension)
}
InterfaceInfo = (PUSBD_INTERFACE_INFORMATION)((PUCHAR)InterfaceInfo + InterfaceInfo->Length);
}
Urb->UrbHeader.UsbdDeviceHandle = UsbDevice;
Urb->UrbHeader.UsbdFlags = 0;
Urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
}
else
{
@ -252,7 +272,6 @@ CompletePendingURBRequest(PPDO_DEVICE_EXTENSION DeviceExtension)
DPRINT1("TransferFlags %x\n", Urb->UrbControlVendorClassRequest.TransferFlags);
DPRINT1("Urb->UrbControlVendorClassRequest.Value %x\n", Urb->UrbControlVendorClassRequest.Value);
switch (Urb->UrbControlVendorClassRequest.Value >> 8)
{
case USB_DEVICE_CLASS_AUDIO:
@ -328,10 +347,16 @@ CompletePendingURBRequest(PPDO_DEVICE_EXTENSION DeviceExtension)
DPRINT1("Unknown UrbControlVendorClassRequest Value\n");
}
}
Urb->UrbHeader.Function = 0x08;
Urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
Urb->UrbHeader.UsbdDeviceHandle = UsbDevice;
Urb->UrbHeader.UsbdFlags = 0;
break;
}
case USB_REQUEST_GET_STATUS:
{
DPRINT1("DEVICE: USB_REQUEST_GET_STATUS for port %d\n", Urb->UrbControlVendorClassRequest.Index);
if (Urb->UrbControlVendorClassRequest.Index == 1)
{
((PULONG)Urb->UrbControlVendorClassRequest.TransferBuffer)[0] = 0;
}
break;
}
default:
@ -348,22 +373,51 @@ CompletePendingURBRequest(PPDO_DEVICE_EXTENSION DeviceExtension)
{
case USB_REQUEST_GET_STATUS:
{
DPRINT1("USB_REQUEST_GET_STATUS\n");
DPRINT1("OTHER: USB_REQUEST_GET_STATUS for port %d\n", Urb->UrbControlVendorClassRequest.Index);
((PUSHORT)Urb->UrbControlVendorClassRequest.TransferBuffer)[0] = DeviceExtension->Ports[Urb->UrbControlVendorClassRequest.Index-1].PortStatus;
((PUSHORT)Urb->UrbControlVendorClassRequest.TransferBuffer)[1] = DeviceExtension->Ports[Urb->UrbControlVendorClassRequest.Index-1].PortChange;
break;
}
case USB_REQUEST_CLEAR_FEATURE:
{
DPRINT1("USB_REQUEST_CLEAR_FEATURE\n");
DPRINT1("USB_REQUEST_CLEAR_FEATURE Port %d, value %x\n", Urb->UrbControlVendorClassRequest.Index,
Urb->UrbControlVendorClassRequest.Value);
switch (Urb->UrbControlVendorClassRequest.Value)
{
case C_PORT_CONNECTION:
DeviceExtension->Ports[Urb->UrbControlVendorClassRequest.Index-1].PortChange &= ~USB_PORT_STATUS_CONNECT;
break;
case C_PORT_RESET:
DeviceExtension->Ports[Urb->UrbControlVendorClassRequest.Index-1].PortChange &= ~USB_PORT_STATUS_RESET;
break;
default:
DPRINT1("Unknown Value for Clear Feature %x \n", Urb->UrbControlVendorClassRequest.Value);
break;
}
break;
}
case USB_REQUEST_SET_FEATURE:
{
DPRINT1("USB_REQUEST_SET_FEATURE value %x\n", Urb->UrbControlVendorClassRequest.Value);
DPRINT1("USB_REQUEST_SET_FEATURE Port %d, value %x\n", Urb->UrbControlVendorClassRequest.Index,
Urb->UrbControlVendorClassRequest.Value);
switch(Urb->UrbControlVendorClassRequest.Value)
{
/* FIXME: Needs research */
case 0x01:
case PORT_RESET:
{
DeviceExtension->Ports[Urb->UrbControlVendorClassRequest.Index-1].PortChange |= USB_PORT_STATUS_RESET;
break;
}
case PORT_ENABLE:
{
DPRINT1("Unhandled Set Feature\n");
break;
}
default:
{
DPRINT1("Unknown Set Feature!\n");
break;
}
}
break;
@ -371,6 +425,7 @@ CompletePendingURBRequest(PPDO_DEVICE_EXTENSION DeviceExtension)
case USB_REQUEST_SET_ADDRESS:
{
DPRINT1("USB_REQUEST_SET_ADDRESS\n");
ASSERT(FALSE);
break;
}
case USB_REQUEST_GET_DESCRIPTOR:
@ -408,6 +463,12 @@ CompletePendingURBRequest(PPDO_DEVICE_EXTENSION DeviceExtension)
DPRINT1("USB_REQUEST_SYNC_FRAME\n");
break;
}
default:
{
DPRINT1("Unknown Function Class Unknown request\n");
ASSERT(FALSE);
break;
}
}
break;
}
@ -415,6 +476,7 @@ CompletePendingURBRequest(PPDO_DEVICE_EXTENSION DeviceExtension)
{
DPRINT1("Unhandled URB %x\n", Urb->UrbHeader.Function);
Urb->UrbHeader.Status = USBD_STATUS_INVALID_URB_FUNCTION;
ASSERT(FALSE);
}
}
@ -424,6 +486,13 @@ CompletePendingURBRequest(PPDO_DEVICE_EXTENSION DeviceExtension)
Irp->IoStatus.Status = Status;
Irp->IoStatus.Information = Information;
if (Urb->UrbHeader.Status == USBD_STATUS_SUCCESS)
{
/* Fake a successful Control Transfer */
Urb->UrbHeader.Function = 0x08;
Urb->UrbHeader.UsbdFlags = 0;
}
IoCompleteRequest(Irp, IO_NO_INCREMENT);
KeAcquireSpinLock(&DeviceExtension->IrpQueueLock, &oldIrql);
}

View file

@ -172,18 +172,24 @@ PdoDispatchInternalDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
}
case IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE:
{
DPRINT1("IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE\n");
DPRINT1("IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE %x\n", IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE);
if (Stack->Parameters.Others.Argument1)
{
/* Return the root hubs devicehandle */
*(PVOID *)Stack->Parameters.Others.Argument1 = (PVOID)PdoDeviceExtension->UsbDevices[0];
}
else
Status = STATUS_INVALID_DEVICE_REQUEST;
break;
}
case IOCTL_INTERNAL_USB_GET_HUB_COUNT:
{
DPRINT1("IOCTL_INTERNAL_USB_GET_HUB_COUNT\n");
DPRINT1("IOCTL_INTERNAL_USB_GET_HUB_COUNT %x\n", IOCTL_INTERNAL_USB_GET_HUB_COUNT);
if (Stack->Parameters.Others.Argument1)
{
/* FIXME: Determine the number of hubs between the usb device and root hub */
/* For now return 0 */
*(PVOID *)Stack->Parameters.Others.Argument1 = 0;
/* For now return 1, the root hub */
*(PVOID *)Stack->Parameters.Others.Argument1 = (PVOID)1;
}
break;
}
@ -216,9 +222,8 @@ PdoDispatchInternalDeviceControl(PDEVICE_OBJECT DeviceObject, PIRP Irp)
if (Stack->Parameters.Others.Argument2)
*(PVOID *)Stack->Parameters.Others.Argument2 = IoGetAttachedDevice(FdoDeviceExtension->DeviceObject);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
return STATUS_SUCCESS;
Information = 0;
Status = STATUS_SUCCESS;
break;
}
case IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION:
@ -287,7 +292,6 @@ PdoQueryId(PDEVICE_OBJECT DeviceObject, PIRP Irp, ULONG_PTR* Information)
}
}
/* Lifted from hpoussin */
Status = DuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
&SourceString,
&String);
@ -350,6 +354,7 @@ PdoDispatchPnp(
PPDO_DEVICE_EXTENSION PdoDeviceExtension;
PFDO_DEVICE_EXTENSION FdoDeviceExtension;
UNICODE_STRING InterfaceSymLinkName;
LONG i;
PdoDeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
FdoDeviceExtension = (PFDO_DEVICE_EXTENSION)PdoDeviceExtension->ControllerFdo->DeviceExtension;
@ -357,6 +362,12 @@ PdoDispatchPnp(
/* Create the root hub */
RootHubDevice = InternalCreateUsbDevice(1, 0, NULL, TRUE);
for (i = 0; i < 8; i++)
{
PdoDeviceExtension->Ports[i].PortStatus = USB_PORT_STATUS_ENABLE;
PdoDeviceExtension->Ports[i].PortChange = 0;
}
RtlCopyMemory(&RootHubDevice->DeviceDescriptor,
ROOTHUB2_DEVICE_DESCRIPTOR,
sizeof(ROOTHUB2_DEVICE_DESCRIPTOR));
@ -409,8 +420,16 @@ PdoDispatchPnp(
break;
}
case BusRelations:
DPRINT1("BusRelations!!!!!\n");
case RemovalRelations:
case EjectionRelations:
{
/* Ignore the request */
Information = Irp->IoStatus.Information;
Status = Irp->IoStatus.Status;
break;
}
default:
{
DPRINT1("IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unhandled type 0x%lx\n",
@ -534,7 +553,8 @@ PdoDispatchPnp(
else
{
DPRINT1("Not Supported\n");
Status = STATUS_NOT_SUPPORTED;
Status = Irp->IoStatus.Status;
Information = Irp->IoStatus.Information;
}
break;
}

View file

@ -75,6 +75,25 @@ OR with QUEUE_TRANSFER_DESCRIPTOR Token.SplitTransactionState */
#define PING_STATE_DO_OUT 0x00
#define PING_STATE_DO_PING 0x01
#define C_HUB_LOCAL_POWER 0
#define C_HUB_OVER_CURRENT 1
#define PORT_CONNECTION 0
#define PORT_ENABLE 1
#define PORT_SUSPEND 2
#define PORT_OVER_CURRENT 3
#define PORT_RESET 4
#define PORT_POWER 8
#define PORT_LOW_SPEED 9
#define PORT_HIGH_SPEED 9
#define C_PORT_CONNECTION 16
#define C_PORT_ENABLE 17
#define C_PORT_SUSPEND 18
#define C_PORT_OVER_CURRENT 19
#define C_PORT_RESET 20
#define PORT_TEST 21
#define PORT_INDICATOR 22
#define USB_PORT_STATUS_CHANGE 0x4000
/* QUEUE ELEMENT TRANSFER DESCRIPTOR TOKEN */
typedef struct _QETD_TOKEN_BITS
{
@ -273,16 +292,16 @@ typedef struct _EHCI_HCC_CONTENT
} EHCI_HCC_CONTENT, *PEHCI_HCC_CONTENT;
typedef struct _EHCI_CAPS {
UCHAR Length;
UCHAR Reserved;
USHORT HCIVersion;
UCHAR Length;
UCHAR Reserved;
USHORT HCIVersion;
union
{
EHCI_HCS_CONTENT HCSParams;
ULONG HCSParamsLong;
EHCI_HCS_CONTENT HCSParams;
ULONG HCSParamsLong;
};
ULONG HCCParams;
UCHAR PortRoute [8];
ULONG HCCParams;
UCHAR PortRoute [8];
} EHCI_CAPS, *PEHCI_CAPS;
typedef struct _COMMON_DEVICE_EXTENSION
@ -292,6 +311,14 @@ typedef struct _COMMON_DEVICE_EXTENSION
PDEVICE_OBJECT DeviceObject;
} COMMON_DEVICE_EXTENSION, *PCOMMON_DEVICE_EXTENSION;
typedef struct _EHCIPORTS
{
ULONG PortNumber;
ULONG PortType;
USHORT PortStatus;
USHORT PortChange;
} EHCIPORTS, *PEHCIPORTS;
typedef struct _FDO_DEVICE_EXTENSION
{
COMMON_DEVICE_EXTENSION Common;
@ -333,8 +360,8 @@ typedef struct _FDO_DEVICE_EXTENSION
PULONG PeriodicFramList;
PULONG AsyncListQueueHeadPtr;
PHYSICAL_ADDRESS PeriodicFramListPhysAddr;
PHYSICAL_ADDRESS AsyncListQueueHeadPtrPhysAddr;
PHYSICAL_ADDRESS PeriodicFramListPhysAddr;
PHYSICAL_ADDRESS AsyncListQueueHeadPtrPhysAddr;
BOOLEAN AsyncComplete;
@ -356,6 +383,8 @@ typedef struct _PDO_DEVICE_EXTENSION
BOOLEAN HaltUrbHandling;
PVOID CallbackContext;
PRH_INIT_CALLBACK CallbackRoutine;
ULONG NumberOfPorts;
EHCIPORTS Ports[32];
} PDO_DEVICE_EXTENSION, *PPDO_DEVICE_EXTENSION;
typedef struct _WORKITEM_DATA