[USBUHCI]

- Start implementing UHCI controller

svn path=/trunk/; revision=55780
This commit is contained in:
Johannes Anderwald 2012-02-21 15:49:08 +00:00
parent ddc66b9898
commit 1dce437b2b
15 changed files with 9217 additions and 0 deletions

View file

@ -0,0 +1,34 @@
set_cpp()
remove_definitions(-D_WIN32_WINNT=0x502)
add_definitions(-D_WIN32_WINNT=0x600)
add_library(usbuhci SHARED
usbuhci.cpp
usb_device.cpp
usb_request.cpp
usb_queue.cpp
hcd_controller.cpp
hardware.cpp
misc.cpp
purecall.cpp
hub_controller.cpp
memory_manager.cpp
usbuhci.rc)
target_link_libraries(usbuhci
libcntpr
${PSEH_LIB})
if(MSVC)
set_target_properties(usbuhci PROPERTIES COMPILE_FLAGS "/GR-")
else()
target_link_libraries(usbuhci -lgcc)
set_target_properties(usbuhci PROPERTIES COMPILE_FLAGS "-fno-exceptions -fno-rtti")
endif(MSVC)
set_module_type(usbuhci kernelmodedriver)
add_importlibs(usbuhci ntoskrnl hal usbd)
add_cd_file(TARGET usbuhci DESTINATION reactos/system32/drivers NO_CAB FOR all)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,188 @@
/*
* Copyright 2004-2006, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Michael Lotz <mmlr@mlotz.ch>
* Niels S. Reedijk
*/
#ifndef UHCI_HARDWARE_H
#define UHCI_HARDWARE_H
/************************************************************
* The Registers *
************************************************************/
// R/W -- Read/Write
// R/WC -- Read/Write Clear
// ** -- Only writable with words!
// PCI register
#define PCI_LEGSUP 0xC0
#define PCI_LEGSUP_USBPIRQDEN 0x2000
#define PCI_LEGSUP_CLEAR_SMI 0x8f00
// Registers
#define UHCI_USBCMD 0x00 // USB Command - word - R/W
#define UHCI_USBSTS 0x02 // USB Status - word - R/WC
#define UHCI_USBINTR 0x04 // USB Interrupt Enable - word - R/W
#define UHCI_FRNUM 0x06 // Frame number - word - R/W**
#define UHCI_FRBASEADD 0x08 // Frame List BAse Address - dword - R/W
#define UHCI_SOFMOD 0x0c // Start of Frame Modify - byte - R/W
#define UHCI_PORTSC1 0x10 // Port 1 Status/Control - word - R/WC**
#define UHCI_PORTSC2 0x12 // Port 2 Status/Control - word - R/WC**
// USBCMD
#define UHCI_USBCMD_RS 0x01 // Run/Stop
#define UHCI_USBCMD_HCRESET 0x02 // Host Controller Reset
#define UHCI_USBCMD_GRESET 0x04 // Global Reset
#define UHCI_USBCMD_EGSM 0x08 // Enter Global Suspensd mode
#define UHCI_USBCMD_FGR 0x10 // Force Global resume
#define UHCI_USBCMD_SWDBG 0x20 // Software Debug
#define UHCI_USBCMD_CF 0x40 // Configure Flag
#define UHCI_USBCMD_MAXP 0x80 // Max packet
//USBSTS
#define UHCI_USBSTS_USBINT 0x01 // USB interrupt
#define UHCI_USBSTS_ERRINT 0x02 // USB error interrupt
#define UHCI_USBSTS_RESDET 0x04 // Resume Detect
#define UHCI_USBSTS_HOSTERR 0x08 // Host System Error
#define UHCI_USBSTS_HCPRERR 0x10 // Host Controller Process error
#define UHCI_USBSTS_HCHALT 0x20 // HCHalted
//USBINTR
#define UHCI_USBINTR_CRC 0x01 // Timeout/ CRC interrupt enable
#define UHCI_USBINTR_RESUME 0x02 // Resume interrupt enable
#define UHCI_USBINTR_IOC 0x04 // Interrupt on complete enable
#define UHCI_USBINTR_SHORT 0x08 // Short packet interrupt enable
//PORTSC
#define UHCI_PORTSC_CURSTAT 0x0001 // Current connect status
#define UHCI_PORTSC_STATCHA 0x0002 // Current connect status change
#define UHCI_PORTSC_ENABLED 0x0004 // Port enabled/disabled
#define UHCI_PORTSC_ENABCHA 0x0008 // Change in enabled/disabled
#define UHCI_PORTSC_LINE_0 0x0010 // The status of D+
#define UHCI_PORTSC_LINE_1 0x0020 // The status of D-
#define UHCI_PORTSC_RESUME 0x0040 // Something with the suspend state ???
#define UHCI_PORTSC_LOWSPEED 0x0100 // Low speed device attached?
#define UHCI_PORTSC_RESET 0x0200 // Port is in reset
#define UHCI_PORTSC_SUSPEND 0x1000 // Set port in suspend state
#define UHCI_PORTSC_DATAMASK 0x13f5 // Mask that excludes the change bits
/************************************************************
* Hardware structs *
************************************************************/
// Framelist flags
#define FRAMELIST_TERMINATE 0x1
#define FRAMELIST_NEXT_IS_QH 0x2
// Number of frames
#define NUMBER_OF_FRAMES 1024
#define MAX_AVAILABLE_BANDWIDTH 900 // Microseconds
// Represents a Transfer Descriptor (TD)
typedef struct _UHCI_TRANSFER_DESCRIPTOR
{
ULONG LinkPhysical; // Link to next transfer descriptor / queue head
ULONG Status; // status
ULONG Token; // packet header
ULONG BufferPhysical; // pointer to the buffer
// Software part
PHYSICAL_ADDRESS PhysicalAddress; // Physical address of this descriptor
PVOID NextLogicalDescriptor;
ULONG BufferSize; // Size of the buffer
PVOID BufferLogical; // Logical pointer to the buffer
}UHCI_TRANSFER_DESCRIPTOR, *PUHCI_TRANSFER_DESCRIPTOR;
#define TD_NEXT_IS_QH 0x02
// Control and Status
#define TD_CONTROL_SPD (1 << 29)
#define TD_CONTROL_3_ERRORS (3 << 27)
#define TD_CONTROL_LOWSPEED (1 << 26)
#define TD_CONTROL_ISOCHRONOUS (1 << 25)
#define TD_CONTROL_IOC (1 << 24)
#define TD_STATUS_ACTIVE (1 << 23)
#define TD_STATUS_ERROR_STALLED (1 << 22)
#define TD_STATUS_ERROR_BUFFER (1 << 21)
#define TD_STATUS_ERROR_BABBLE (1 << 20)
#define TD_STATUS_ERROR_NAK (1 << 19)
#define TD_STATUS_ERROR_CRC (1 << 18)
#define TD_STATUS_ERROR_TIMEOUT (1 << 18)
#define TD_STATUS_ERROR_BITSTUFF (1 << 17)
#define TD_STATUS_ACTLEN_MASK 0x07ff
#define TD_STATUS_ACTLEN_NULL 0x07ff
// Token
#define TD_TOKEN_MAXLEN_SHIFT 21
#define TD_TOKEN_NULL_DATA (0x07ff << TD_TOKEN_MAXLEN_SHIFT)
#define TD_TOKEN_DATA_TOGGLE_SHIFT 19
#define TD_TOKEN_DATA1 (1 << TD_TOKEN_DATA_TOGGLE_SHIFT)
#define TD_TOKEN_SETUP 0x2d
#define TD_TOKEN_IN 0x69
#define TD_TOKEN_OUT 0xe1
#define TD_TOKEN_ENDPTADDR_SHIFT 15
#define TD_TOKEN_DEVADDR_SHIFT 8
#define TD_DEPTH_FIRST 0x04
#define TD_TERMINATE 0x01
#define TD_ERROR_MASK 0x440000
#define TD_ERROR_COUNT_SHIFT 27
#define TD_ERROR_COUNT_MASK 0x03
#define TD_LINK_MASK 0xfffffff0
static
inline
ULONG
UHCI_TRANSFER_DESCRIPTOR_MAXIMUM_LENGTH(PUHCI_TRANSFER_DESCRIPTOR Descriptor)
{
ULONG Length = (Descriptor->Token >> TD_TOKEN_MAXLEN_SHIFT) + 1;
if (Length == TD_STATUS_ACTLEN_NULL + 1)
return 0;
return Length;
}
static
inline
ULONG
UHCI_TRANSFER_DESCRIPTOR_LENGTH(PUHCI_TRANSFER_DESCRIPTOR Descriptor)
{
ULONG Length = (Descriptor->Status & TD_STATUS_ACTLEN_MASK) + 1;
if (Length == TD_STATUS_ACTLEN_NULL + 1)
return 0;
return Length;
}
// Represents a Queue Head (QH)
typedef struct
{
// hardware part
ULONG LinkPhysical; // address
ULONG ElementPhysical; // next descriptor
// Software part
ULONG PhysicalAddress;
PVOID NextLogicalDescriptor;
}UHCI_QUEUE_HEAD, *PUHCI_QUEUE_HEAD;
#define QH_TERMINATE 0x01
#define QH_NEXT_IS_QH 0x02
#define QH_LINK_MASK 0xfffffff0
#define UHCI_INTERRUPT_QUEUE 0
#define UHCI_LOW_SPEED_CONTROL_QUEUE 1
#define UHCI_FULL_SPEED_CONTROL_QUEUE 2
#define UHCI_BULK_QUEUE 3
#define UHCI_DEBUG_QUEUE 4
#endif

View file

@ -0,0 +1,751 @@
/*
* PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/usb/usbohci/hcd_controller.cpp
* PURPOSE: USB OHCI device driver.
* PROGRAMMERS:
* Michael Martin (michael.martin@reactos.org)
* Johannes Anderwald (johannes.anderwald@reactos.org)
*/
#define INITGUID
#include "usbuhci.h"
class CHCDController : public IHCDController,
public IDispatchIrp
{
public:
STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
STDMETHODIMP_(ULONG) AddRef()
{
InterlockedIncrement(&m_Ref);
return m_Ref;
}
STDMETHODIMP_(ULONG) Release()
{
InterlockedDecrement(&m_Ref);
if (!m_Ref)
{
delete this;
return 0;
}
return m_Ref;
}
// IHCDController interface functions
NTSTATUS Initialize(IN PROOTHDCCONTROLLER RootHCDController, IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject);
// IDispatchIrp interface functions
NTSTATUS HandlePnp(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp);
NTSTATUS HandlePower(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp);
NTSTATUS HandleDeviceControl(IN PDEVICE_OBJECT DeviceObject, IN OUT PIRP Irp);
// local functions
NTSTATUS CreateFDO(PDRIVER_OBJECT DriverObject, PDEVICE_OBJECT * OutDeviceObject);
NTSTATUS SetSymbolicLink(BOOLEAN Enable);
// constructor / destructor
CHCDController(IUnknown *OuterUnknown){}
virtual ~CHCDController(){}
protected:
LONG m_Ref;
PROOTHDCCONTROLLER m_RootController;
PDRIVER_OBJECT m_DriverObject;
PDEVICE_OBJECT m_PhysicalDeviceObject;
PDEVICE_OBJECT m_FunctionalDeviceObject;
PDEVICE_OBJECT m_NextDeviceObject;
PUSBHARDWAREDEVICE m_Hardware;
PHUBCONTROLLER m_HubController;
ULONG m_FDODeviceNumber;
};
//=================================================================================================
// COM
//
NTSTATUS
STDMETHODCALLTYPE
CHCDController::QueryInterface(
IN REFIID refiid,
OUT PVOID* Output)
{
return STATUS_UNSUCCESSFUL;
}
//-------------------------------------------------------------------------------------------------
NTSTATUS
CHCDController::Initialize(
IN PROOTHDCCONTROLLER RootHCDController,
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject)
{
NTSTATUS Status;
PCOMMON_DEVICE_EXTENSION DeviceExtension;
//
// create usb hardware
//
Status = CreateUSBHardware(&m_Hardware);
if (!NT_SUCCESS(Status))
{
//
// failed to create hardware object
//
DPRINT1("Failed to create hardware object\n");
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// initialize members
//
m_DriverObject = DriverObject;
m_PhysicalDeviceObject = PhysicalDeviceObject;
m_RootController = RootHCDController;
//
// create FDO
//
Status = CreateFDO(m_DriverObject, &m_FunctionalDeviceObject);
if (!NT_SUCCESS(Status))
{
//
// failed to create PDO
//
return Status;
}
//
// now attach to device stack
//
m_NextDeviceObject = IoAttachDeviceToDeviceStack(m_FunctionalDeviceObject, m_PhysicalDeviceObject);
if (!m_NextDeviceObject)
{
//
// failed to attach to device stack
//
IoDeleteDevice(m_FunctionalDeviceObject);
m_FunctionalDeviceObject = 0;
return STATUS_NO_SUCH_DEVICE;
}
//
// initialize hardware object
//
Status = m_Hardware->Initialize(m_DriverObject, m_FunctionalDeviceObject, m_PhysicalDeviceObject, m_NextDeviceObject);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to initialize hardware object %x\n", Status);
//
// failed to initialize hardware object, detach from device stack
//
IoDetachDevice(m_NextDeviceObject);
//
// now delete the device
//
IoDeleteDevice(m_FunctionalDeviceObject);
//
// nullify pointers :)
//
m_FunctionalDeviceObject = 0;
m_NextDeviceObject = 0;
return Status;
}
//
// set device flags
//
m_FunctionalDeviceObject->Flags |= DO_BUFFERED_IO | DO_POWER_PAGABLE;
//
// get device extension
//
DeviceExtension = (PCOMMON_DEVICE_EXTENSION)m_FunctionalDeviceObject->DeviceExtension;
PC_ASSERT(DeviceExtension);
//
// initialize device extension
//
DeviceExtension->IsFDO = TRUE;
DeviceExtension->IsHub = FALSE;
DeviceExtension->Dispatcher = PDISPATCHIRP(this);
//
// device is initialized
//
m_FunctionalDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
//
// is there a root controller
//
if (m_RootController)
{
//
// add reference
//
m_RootController->AddRef();
//
// register with controller
//
m_RootController->RegisterHCD(this);
}
//
// done
//
return STATUS_SUCCESS;
}
//-------------------------------------------------------------------------------------------------
NTSTATUS
CHCDController::HandleDeviceControl(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PIO_STACK_LOCATION IoStack;
PCOMMON_DEVICE_EXTENSION DeviceExtension;
NTSTATUS Status = STATUS_NOT_IMPLEMENTED;
PUSB_HCD_DRIVERKEY_NAME DriverKey;
ULONG ResultLength;
//
// get current stack location
//
IoStack = IoGetCurrentIrpStackLocation(Irp);
//
// get device extension
//
DeviceExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
//
// sanity check
//
PC_ASSERT(DeviceExtension->IsFDO);
DPRINT1("HandleDeviceControl>Type: IoCtl %x InputBufferLength %lu OutputBufferLength %lu\n",
IoStack->Parameters.DeviceIoControl.IoControlCode,
IoStack->Parameters.DeviceIoControl.InputBufferLength,
IoStack->Parameters.DeviceIoControl.OutputBufferLength);
//
// perform ioctl for FDO
//
if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_GET_HCD_DRIVERKEY_NAME)
{
//
// check if sizee is at least >= USB_HCD_DRIVERKEY_NAME
//
if(IoStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(USB_HCD_DRIVERKEY_NAME))
{
//
// get device property size
//
Status = IoGetDeviceProperty(m_PhysicalDeviceObject, DevicePropertyDriverKeyName, 0, NULL, &ResultLength);
//
// get input buffer
//
DriverKey = (PUSB_HCD_DRIVERKEY_NAME)Irp->AssociatedIrp.SystemBuffer;
//
// check result
//
if (Status == STATUS_BUFFER_TOO_SMALL)
{
//
// does the caller provide enough buffer space
//
if (IoStack->Parameters.DeviceIoControl.OutputBufferLength >= ResultLength)
{
//
// it does
//
Status = IoGetDeviceProperty(m_PhysicalDeviceObject, DevicePropertyDriverKeyName, IoStack->Parameters.DeviceIoControl.OutputBufferLength - sizeof(ULONG), DriverKey->DriverKeyName, &ResultLength);
if (NT_SUCCESS(Status))
{
//
// informal debug print
//
DPRINT1("Result %S\n", DriverKey->DriverKeyName);
}
}
//
// store result
//
DriverKey->ActualLength = ResultLength + FIELD_OFFSET(USB_HCD_DRIVERKEY_NAME, DriverKeyName) + sizeof(WCHAR);
Irp->IoStatus.Information = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
Status = STATUS_SUCCESS;
}
}
else
{
//
// buffer is certainly too small
//
Status = STATUS_BUFFER_OVERFLOW;
Irp->IoStatus.Information = sizeof(USB_HCD_DRIVERKEY_NAME);
}
}
else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_USB_GET_ROOT_HUB_NAME)
{
//
// check if sizee is at least >= USB_HCD_DRIVERKEY_NAME
//
if(IoStack->Parameters.DeviceIoControl.OutputBufferLength >= sizeof(USB_HCD_DRIVERKEY_NAME))
{
//
// sanity check
//
PC_ASSERT(m_HubController);
//
// get input buffer
//
DriverKey = (PUSB_HCD_DRIVERKEY_NAME)Irp->AssociatedIrp.SystemBuffer;
//
// get symbolic link
//
Status = m_HubController->GetHubControllerSymbolicLink(IoStack->Parameters.DeviceIoControl.OutputBufferLength - sizeof(ULONG), DriverKey->DriverKeyName, &ResultLength);
if (NT_SUCCESS(Status))
{
//
// null terminate it
//
PC_ASSERT(IoStack->Parameters.DeviceIoControl.OutputBufferLength - sizeof(ULONG) - sizeof(WCHAR) >= ResultLength);
DriverKey->DriverKeyName[ResultLength / sizeof(WCHAR)] = L'\0';
DPRINT1("Result %S\n", DriverKey->DriverKeyName);
}
//
// store result
//
DriverKey->ActualLength = ResultLength + FIELD_OFFSET(USB_HCD_DRIVERKEY_NAME, DriverKeyName) + sizeof(WCHAR);
Irp->IoStatus.Information = IoStack->Parameters.DeviceIoControl.OutputBufferLength;
Status = STATUS_SUCCESS;
}
else
{
//
// buffer is certainly too small
//
Status = STATUS_BUFFER_OVERFLOW;
Irp->IoStatus.Information = sizeof(USB_HCD_DRIVERKEY_NAME);
}
}
//
// complete the request
//
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
//
// done
//
return Status;
}
NTSTATUS
CHCDController::HandlePnp(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PIO_STACK_LOCATION IoStack;
PCOMMON_DEVICE_EXTENSION DeviceExtension;
PCM_RESOURCE_LIST RawResourceList;
PCM_RESOURCE_LIST TranslatedResourceList;
PDEVICE_RELATIONS DeviceRelations;
NTSTATUS Status;
//
// get device extension
//
DeviceExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
//
// sanity check
//
PC_ASSERT(DeviceExtension->IsFDO);
//
// get current stack location
//
IoStack = IoGetCurrentIrpStackLocation(Irp);
switch(IoStack->MinorFunction)
{
case IRP_MN_START_DEVICE:
{
DPRINT1("CHCDController::HandlePnp IRP_MN_START FDO\n");
//
// first start lower device object
//
Status = SyncForwardIrp(m_NextDeviceObject, Irp);
if (NT_SUCCESS(Status))
{
//
// operation succeeded, lets start the device
//
RawResourceList = IoStack->Parameters.StartDevice.AllocatedResources;
TranslatedResourceList = IoStack->Parameters.StartDevice.AllocatedResourcesTranslated;
if (m_Hardware)
{
//
// start the hardware
//
Status = m_Hardware->PnpStart(RawResourceList, TranslatedResourceList);
}
//
// enable symbolic link
//
Status = SetSymbolicLink(TRUE);
}
DPRINT1("CHCDController::HandlePnp IRP_MN_START FDO: Status %x\n", Status);
break;
}
case IRP_MN_QUERY_DEVICE_RELATIONS:
{
DPRINT1("CHCDController::HandlePnp IRP_MN_QUERY_DEVICE_RELATIONS Type %lx\n", IoStack->Parameters.QueryDeviceRelations.Type);
if (m_HubController == NULL)
{
//
// create hub controller
//
Status = CreateHubController(&m_HubController);
if (!NT_SUCCESS(Status))
{
//
// failed to create hub controller
//
break;
}
//
// initialize hub controller
//
Status = m_HubController->Initialize(m_DriverObject, PHCDCONTROLLER(this), m_Hardware, TRUE, 0 /* FIXME*/);
if (!NT_SUCCESS(Status))
{
//
// failed to initialize hub controller
//
break;
}
//
// add reference to prevent it from getting deleting while hub driver adds / removes references
//
m_HubController->AddRef();
}
if (IoStack->Parameters.QueryDeviceRelations.Type == BusRelations)
{
//
// allocate device relations
//
DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
if (!DeviceRelations)
{
//
// no memory
//
Status = STATUS_INSUFFICIENT_RESOURCES;
break;
}
//
// init device relations
//
DeviceRelations->Count = 1;
Status = m_HubController->GetHubControllerDeviceObject(&DeviceRelations->Objects [0]);
//
// sanity check
//
PC_ASSERT(Status == STATUS_SUCCESS);
ObReferenceObject(DeviceRelations->Objects [0]);
//
// store result
//
Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
Status = STATUS_SUCCESS;
}
else
{
//
// not supported
//
PC_ASSERT(0);
Status = STATUS_NOT_SUPPORTED;
}
break;
}
case IRP_MN_STOP_DEVICE:
{
DPRINT1("CHCDController::HandlePnp IRP_MN_STOP_DEVICE\n");
if (m_Hardware)
{
//
// stop the hardware
//
Status = m_Hardware->PnpStop();
}
else
{
//
// fake success
//
Status = STATUS_SUCCESS;
}
if (NT_SUCCESS(Status))
{
//
// stop lower device
//
Status = SyncForwardIrp(m_NextDeviceObject, Irp);
}
break;
}
case IRP_MN_REMOVE_DEVICE:
{
DPRINT1("CHCDController::HandlePnp IRP_MN_REMOVE_DEVICE FDO\n");
//
// detach device from device stack
//
IoDetachDevice(m_NextDeviceObject);
//
// delete device
//
IoDeleteDevice(m_FunctionalDeviceObject);
Status = STATUS_SUCCESS;
break;
}
default:
{
//
// forward irp to next device object
//
IoSkipCurrentIrpStackLocation(Irp);
return IoCallDriver(m_NextDeviceObject, Irp);
}
}
//
// store result and complete request
//
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
NTSTATUS
CHCDController::HandlePower(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
UNIMPLEMENTED
Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
CHCDController::CreateFDO(
PDRIVER_OBJECT DriverObject,
PDEVICE_OBJECT * OutDeviceObject)
{
WCHAR CharDeviceName[64];
NTSTATUS Status;
ULONG UsbDeviceNumber = 0;
UNICODE_STRING DeviceName;
while (TRUE)
{
//
// construct device name
//
swprintf(CharDeviceName, L"\\Device\\USBFDO-%d", UsbDeviceNumber);
//
// initialize device name
//
RtlInitUnicodeString(&DeviceName, CharDeviceName);
//
// create device
//
Status = IoCreateDevice(DriverObject,
sizeof(COMMON_DEVICE_EXTENSION),
&DeviceName,
FILE_DEVICE_CONTROLLER,
0,
FALSE,
OutDeviceObject);
//
// check for success
//
if (NT_SUCCESS(Status))
break;
//
// is there a device object with that same name
//
if ((Status == STATUS_OBJECT_NAME_EXISTS) || (Status == STATUS_OBJECT_NAME_COLLISION))
{
//
// Try the next name
//
UsbDeviceNumber++;
continue;
}
//
// bail out on other errors
//
if (!NT_SUCCESS(Status))
{
DPRINT1("CreateFDO: Failed to create %wZ, Status %x\n", &DeviceName, Status);
return Status;
}
}
//
// store FDO number
//
m_FDODeviceNumber = UsbDeviceNumber;
DPRINT1("CreateFDO: DeviceName %wZ\n", &DeviceName);
/* done */
return Status;
}
NTSTATUS
CHCDController::SetSymbolicLink(
BOOLEAN Enable)
{
NTSTATUS Status;
WCHAR LinkName[32];
WCHAR FDOName[32];
UNICODE_STRING Link, FDO;
if (Enable)
{
//
// create legacy link
//
swprintf(LinkName, L"\\DosDevices\\HCD%d", m_FDODeviceNumber);
swprintf(FDOName, L"\\Device\\USBFDO-%d", m_FDODeviceNumber);
RtlInitUnicodeString(&Link, LinkName);
RtlInitUnicodeString(&FDO, FDOName);
//
// create symbolic link
//
Status = IoCreateSymbolicLink(&Link, &FDO);
if (!NT_SUCCESS(Status))
{
//
// FIXME: handle me
//
ASSERT(0);
}
}
else
{
//
// create legacy link
//
swprintf(LinkName, L"\\DosDevices\\HCD%d", m_FDODeviceNumber);
RtlInitUnicodeString(&Link, LinkName);
//
// now delete the symbolic link
//
Status = IoDeleteSymbolicLink(&Link);
if (!NT_SUCCESS(Status))
{
//
// FIXME: handle me
//
ASSERT(0);
}
}
//
// done
//
return Status;
}
NTSTATUS
CreateHCDController(
PHCDCONTROLLER *OutHcdController)
{
PHCDCONTROLLER This;
//
// allocate controller
//
This = new(NonPagedPool, TAG_USBOHCI) CHCDController(0);
if (!This)
{
//
// failed to allocate
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// add reference count
//
This->AddRef();
//
// return result
//
*OutHcdController = (PHCDCONTROLLER)This;
//
// done
//
return STATUS_SUCCESS;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,738 @@
#ifndef INTERFACES_HPP
#define INTERFACES_HPP
//---------------------------------------------------------------------------
//
// Object Hierachy
// --------------------------------------------------------------------
// | IRootHCDController |
// | IHCDController Intel USB Universal Host Controller - 3A37 |
// | IHCDController - Intel USB Universal HostController - 3A38 |
// | IHCDController - Intel USB Universal HostController - 3A38 |
// |------------------------------------------------------------------|
//
//
// IHCDController Intel USB Universal Host Controller - 3A37
// IHubController
// IUSBHardwareDevice
// IDMAMemoryManager
// IUSBQueue <- interacts with -> IUSBRequest
//
//
// Each IHCDController creates an IUSBHardwareDevice class upon initialization. The
// IUSBHardwardeDevice class is used to abstract usb controller specifics. The IHubController
// manages all attached devices and handles hub control ioctl requests.
//
// Each IUSBHardwareDevice has one IDMAMemoryManager and one IUSBQueue. The IDMAMemoryManager
// is used to handle dma memory allocations. The IUSBQueue manages requests which are send to the
// usb hardware. See IUSBRequest class for details.
//
//=========================================================================================
//
// class IRootHCDController
//
// Description: This class serves as the root host controller. The host controller mantains
// a list of registered controllers and provides support functions for the host controllers
struct IHCDController;
DECLARE_INTERFACE_(IRootHCDController, IUnknown)
{
DEFINE_ABSTRACT_UNKNOWN()
//-----------------------------------------------------------------------------------------
//
// Initialize
//
// Description: This function initializes the root host controller. It allocates the resources
// required to manage the registered controllers
virtual NTSTATUS Initialize() = 0;
//-----------------------------------------------------------------------------------------
//
// RegisterHCD
//
// Description: this function registers a host controller with the root host controller
virtual NTSTATUS RegisterHCD(struct IHCDController * Controller) = 0;
//-----------------------------------------------------------------------------------------
//
// UnregisterHCD
//
// Description: this function unregistes a host controller
virtual NTSTATUS UnregisterHCD(struct IHCDController * Controller) = 0;
//-----------------------------------------------------------------------------------------
//
// GetControllerCount
//
// Description: returns the number of host controllers registered
virtual ULONG GetControllerCount() = 0;
};
typedef IRootHCDController *PROOTHDCCONTROLLER;
//=========================================================================================
//
// class IHCDController
//
// Description: This class is used to manage a single USB host controller
//
DECLARE_INTERFACE_(IHCDController, IUnknown)
{
DEFINE_ABSTRACT_UNKNOWN()
//-----------------------------------------------------------------------------------------
//
// Initialize
//
// Description: This function initializes the IHCDController implementation.
// It creates an IUSBHardwareDevice object and initializes it. It also registeres itself with
// the IRootHCDController
//
virtual NTSTATUS Initialize(IN PROOTHDCCONTROLLER RootHCDController,
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject) = 0;
};
typedef IHCDController *PHCDCONTROLLER;
struct _UHCI_TRANSFER_DESCRIPTOR;
//=========================================================================================
//
// class IUSBHardwareDevice
//
// Description: This class provides access to the usb hardware controller
//
struct IDMAMemoryManager;
struct IUSBQueue;
DECLARE_INTERFACE_(IUSBHardwareDevice, IUnknown)
{
DEFINE_ABSTRACT_UNKNOWN()
//-----------------------------------------------------------------------------------------
//
// Initialize
//
// Description: Initializes the usb device controller
virtual NTSTATUS Initialize(PDRIVER_OBJECT DriverObject,
PDEVICE_OBJECT FunctionalDeviceObject,
PDEVICE_OBJECT PhysicalDeviceObject,
PDEVICE_OBJECT LowerDeviceObject) = 0;
//-----------------------------------------------------------------------------------------
//
// PnpStart
//
// Description: handles pnp start request from device. It registeres the interrupt,
// sets up the ports and prepares the device. It then starts the controller
virtual NTSTATUS PnpStart(PCM_RESOURCE_LIST RawResources,
PCM_RESOURCE_LIST TranslatedResources) = 0;
//-----------------------------------------------------------------------------------------
//
// PnpStop
//
// Description: handles pnp stop request from device. It unregisteres the interrupt, releases ports and dma object.
virtual NTSTATUS PnpStop(void) = 0;
//-----------------------------------------------------------------------------------------
//
// GetDeviceDetails
//
// Description: returns the device details such as vendor id, device id, number of ports and speed
virtual NTSTATUS GetDeviceDetails(OUT OPTIONAL PUSHORT VendorId,
OUT OPTIONAL PUSHORT DeviceId,
OUT OPTIONAL PULONG NumberOfPorts,
OUT OPTIONAL PULONG Speed) = 0;
//-----------------------------------------------------------------------------------------
//
// GetUSBQueue
//
// Description: returns interface to internal IUSBQueue
// Interface is reference counted, you need to call release method when you are done with it
// Do not call Initialize on IUSBQueue, the object is already initialized
virtual NTSTATUS GetUSBQueue(OUT struct IUSBQueue **OutUsbQueue) = 0;
//-----------------------------------------------------------------------------------------
//
// GetDMA
//
// Description: returns the DMA object which can be used to allocate memory from the common buffer
virtual NTSTATUS GetDMA(OUT struct IDMAMemoryManager **OutDMAMemoryManager) = 0;
//-----------------------------------------------------------------------------------------
//
// ResetController()
//
// Description: this function resets the controller
// Returns STATUS_SUCCESS when the controller was successfully reset
virtual NTSTATUS ResetController() = 0;
//-----------------------------------------------------------------------------------------
//
// StartController
//
// Description: this functions starts controller allowing interrupts for device connects/removal, and execution of
// Periodic and Asynchronous Schedules.
//
virtual NTSTATUS StartController() = 0;
//-----------------------------------------------------------------------------------------
//
// StopController
//
// Description: this functions stops controller disabling interrupts for device connects/removal, and execution of
// Periodic and Asynchronous Schedules.
//
virtual NTSTATUS StopController() = 0;
//-----------------------------------------------------------------------------------------
//
// ResetPort
//
// Description: this functions resets the port on the controller
//
virtual NTSTATUS ResetPort(ULONG PortNumber) = 0;
//-----------------------------------------------------------------------------------------
//
// GetPortStatus
//
// Description: this functions return status and change state of port
//
virtual NTSTATUS GetPortStatus(ULONG PortId, OUT USHORT *PortStatus, OUT USHORT *PortChange) = 0;
//-----------------------------------------------------------------------------------------
//
// ClearPortStatus
//
// Description: Clears Status of Port, for example Connection, Enable and Reset
//
virtual NTSTATUS ClearPortStatus(ULONG PortId, ULONG Status) = 0;
//-----------------------------------------------------------------------------------------
//
// SetPortFeature
//
// Description: this functions Sets Feature on Port, for example Enable, Power and Reset
//
virtual NTSTATUS SetPortFeature(ULONG PortId, ULONG Feature) = 0;
//-----------------------------------------------------------------------------------------
//
// SetStatusChangeEndpointCallBack
//
// Description: Used to callback to the hub controller when SCE detected
//
virtual VOID SetStatusChangeEndpointCallBack(PVOID CallBack,PVOID Context) = 0;
//-----------------------------------------------------------------------------------------
//
// AcquireDeviceLock
//
// Description: acquires the device lock
virtual KIRQL AcquireDeviceLock(void) = 0;
//-----------------------------------------------------------------------------------------
//
// ReleaseLock
//
// Description: releases the device lock
virtual void ReleaseDeviceLock(KIRQL OldLevel) = 0;
};
typedef IUSBHardwareDevice *PUSBHARDWAREDEVICE;
//=========================================================================================
//
// class IDMAMemoryManager
//
// Description: This class provides access to the dma buffer. It provides methods to
// allocate and free from the dma buffer
//
DECLARE_INTERFACE_(IDMAMemoryManager, IUnknown)
{
DEFINE_ABSTRACT_UNKNOWN()
//-----------------------------------------------------------------------------------------
//
// Initialize
//
// Description: initializes the memory manager
virtual NTSTATUS Initialize(IN PUSBHARDWAREDEVICE Device,
IN PKSPIN_LOCK Lock,
IN ULONG DmaBufferSize,
IN PVOID VirtualBase,
IN PHYSICAL_ADDRESS PhysicalAddress,
IN ULONG DefaultBlockSize) = 0;
//-----------------------------------------------------------------------------------------
//
// Allocate
//
// Description: allocates block of memory from allocator
virtual NTSTATUS Allocate(IN ULONG Size,
OUT PVOID *OutVirtualBase,
OUT PPHYSICAL_ADDRESS OutPhysicalAddress) = 0;
//-----------------------------------------------------------------------------------------
//
// Free
//
// Description: releases memory block
virtual NTSTATUS Release(IN PVOID VirtualBase,
IN ULONG Size) = 0;
};
typedef IDMAMemoryManager *PDMAMEMORYMANAGER;
//=========================================================================================
//
// class IUSBRequest
//
// Description: This class is used to issue request to usb controller. The class is
// initialized using InitializeXXX methods. You also need to call SetEndpoint to define the endpoint
// In addition you can call SetCompletionDetails if you need to wait for the end of
// the request or want to complete an irp. You call AddUSBRequest to add the request to the queue.
// Once the request is completed the CompletionCallback is invoked. The CompletionCallback
// will take care of any completion details which have been set. If the request is cancelled, the
// CancelCallback routine is invoked.
//
DECLARE_INTERFACE_(IUSBRequest, IUnknown)
{
DEFINE_ABSTRACT_UNKNOWN()
//-----------------------------------------------------------------------------------------
//
// InitializeWithSetupPacket
//
// Description: initializes the request packet with an setup packet
// If there is a TransferBuffer, the TransferBufferLength contains the length of the buffer
virtual NTSTATUS InitializeWithSetupPacket(IN PDMAMEMORYMANAGER DmaManager,
IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
IN UCHAR DeviceAddress,
IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor,
IN OUT ULONG TransferBufferLength,
IN OUT PMDL TransferBuffer) = 0;
//-----------------------------------------------------------------------------------------
//
// InitializeWithIrp
//
// Description: initializes the request with an IRP
// The irp contains an URB block which contains all necessary information
virtual NTSTATUS InitializeWithIrp(IN PDMAMEMORYMANAGER DmaManager,
IN OUT PIRP Irp) = 0;
//-----------------------------------------------------------------------------------------
//
// IsRequestComplete
//
// Description: returns true when the request has been completed
// Should be called after the CompletionCallback has been invoked
// This function is called by IUSBQueue after queue head has been completed
// If the function returns true, IUSBQueue will then call ShouldReleaseRequestAfterCompletion
// If that function returns also true, it calls Release() to delete the IUSBRequest
virtual BOOLEAN IsRequestComplete() = 0;
//-----------------------------------------------------------------------------------------
//
// GetTransferType
//
// Description: returns the type of the request: control, bulk, iso, interrupt
virtual ULONG GetTransferType() = 0;
//-----------------------------------------------------------------------------------------
//
// GetEndpointDescriptor
//
// Description: returns the general transfer descriptor
virtual NTSTATUS GetEndpointDescriptor(struct _UHCI_TRANSFER_DESCRIPTOR ** OutDescriptor) = 0;
//-----------------------------------------------------------------------------------------
//
// GetResultStatus
//
// Description: returns the status code of the result
// Note: this function will block the caller untill the request has been completed
virtual VOID GetResultStatus(OUT OPTIONAL NTSTATUS * NtStatusCode,
OUT OPTIONAL PULONG UrbStatusCode) = 0;
//-----------------------------------------------------------------------------------------
//
// IsRequestInitialized
//
// Description: returns true when the request has been successfully initialized using InitializeXXX methods
virtual BOOLEAN IsRequestInitialized() = 0;
//-----------------------------------------------------------------------------------------
//
// GetInterruptInterval
//
// Description: returns interval of the iso / interrupt
virtual UCHAR GetInterval() = 0;
};
typedef IUSBRequest *PUSBREQUEST;
//=========================================================================================
//
// class IUSBQueue
//
// Description: This class manages pending requests
//
DECLARE_INTERFACE_(IUSBQueue, IUnknown)
{
DEFINE_ABSTRACT_UNKNOWN()
//-----------------------------------------------------------------------------------------
//
// Initialize
//
// Description: initializes the object
virtual NTSTATUS Initialize(IN PUSBHARDWAREDEVICE Hardware,
IN PDMA_ADAPTER AdapterObject,
IN PDMAMEMORYMANAGER MemManager,
IN OPTIONAL PKSPIN_LOCK Lock) = 0;
//-----------------------------------------------------------------------------------------
//
// GetPendingRequestCount
//
// Description: returns the number of pending requests true from IsRequestComplete
virtual ULONG GetPendingRequestCount() = 0;
//-----------------------------------------------------------------------------------------
//
// AddUSBRequest
//
// Description: adds an usb request to the queue.
// Returns status success when successful
virtual NTSTATUS AddUSBRequest(IUSBRequest * Request) = 0;
//-----------------------------------------------------------------------------------------
//
// CancelRequests()
//
// Description: cancels all requests
virtual NTSTATUS CancelRequests() = 0;
//-----------------------------------------------------------------------------------------
//
// CreateUSBRequest
//
// Description: creates an usb request
virtual NTSTATUS CreateUSBRequest(IUSBRequest **OutRequest) = 0;
};
typedef IUSBQueue *PUSBQUEUE;
//=========================================================================================
//
// class IHubController
//
// Description: This class implements a hub controller
//
DECLARE_INTERFACE_(IHubController, IUnknown)
{
DEFINE_ABSTRACT_UNKNOWN()
//----------------------------------------------------------------------------------------
//
// Initialize
//
// Description: Initializes the hub controller
virtual NTSTATUS Initialize(IN PDRIVER_OBJECT DriverObject,
IN PHCDCONTROLLER Controller,
IN PUSBHARDWAREDEVICE Device,
IN BOOLEAN IsRootHubDevice,
IN ULONG DeviceAddress) = 0;
//----------------------------------------------------------------------------------------
//
// GetHubControllerDeviceObject
//
// Description: Returns the hub controller device object
virtual NTSTATUS GetHubControllerDeviceObject(PDEVICE_OBJECT * HubDeviceObject) = 0;
//----------------------------------------------------------------------------------------
//
// GetHubControllerSymbolicLink
//
// Description: Returns the symbolic link of the root hub
virtual NTSTATUS GetHubControllerSymbolicLink(ULONG BufferLength, PVOID Buffer, PULONG RequiredLength) = 0;
};
typedef IHubController *PHUBCONTROLLER;
//=========================================================================================
//
// class IDispatchIrp
//
// Description: This class is used to handle irp dispatch requests
//
DECLARE_INTERFACE_(IDispatchIrp, IUnknown)
{
DEFINE_ABSTRACT_UNKNOWN()
//-----------------------------------------------------------------------------------------
//
// HandlePnp
//
// Description: This function handles all pnp requests
virtual NTSTATUS HandlePnp(IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp) = 0;
//-----------------------------------------------------------------------------------------
//
// HandlePower
//
// Description: This function handles all power pnp requests
//
virtual NTSTATUS HandlePower(IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp) = 0;
//-----------------------------------------------------------------------------------------
//
// HandleDeviceControl
//
// Description: handles device io control requests
virtual NTSTATUS HandleDeviceControl(IN PDEVICE_OBJECT DeviceObject,
IN OUT PIRP Irp) = 0;
};
typedef IDispatchIrp *PDISPATCHIRP;
//=========================================================================================
//
// class IUSBDevice
//
// Description: This class is used to abstract details of a usb device
//
DECLARE_INTERFACE_(IUSBDevice, IUnknown)
{
DEFINE_ABSTRACT_UNKNOWN()
//----------------------------------------------------------------------------------------
//
// Initialize
//
// Description: Initializes the usb device
virtual NTSTATUS Initialize(IN PHUBCONTROLLER HubController,
IN PUSBHARDWAREDEVICE Device,
IN PVOID Parent,
IN ULONG Port,
IN ULONG PortStatus) = 0;
//-----------------------------------------------------------------------------------------
//
// IsHub
//
// Description: returns true when device is a hub
virtual BOOLEAN IsHub() = 0;
//-----------------------------------------------------------------------------------------
//
// GetParent
//
// Description: gets the parent device of the this device
virtual NTSTATUS GetParent(PVOID * Parent) = 0;
//-----------------------------------------------------------------------------------------
//
// GetDeviceAddress
//
// Description: gets the device address of the this device
virtual UCHAR GetDeviceAddress() = 0;
//-----------------------------------------------------------------------------------------
//
// GetPort
//
// Description: gets the port to which this device is connected
virtual ULONG GetPort() = 0;
//-----------------------------------------------------------------------------------------
//
// GetSpeed
//
// Description: gets the speed of the device
virtual USB_DEVICE_SPEED GetSpeed() = 0;
//-----------------------------------------------------------------------------------------
//
// GetType
//
// Description: gets the type of the device, either 1.1 or 2.0 device
virtual USB_DEVICE_TYPE GetType() = 0;
//-----------------------------------------------------------------------------------------
//
// GetState
//
// Description: gets the device state
virtual ULONG GetState() = 0;
//-----------------------------------------------------------------------------------------
//
// SetDeviceHandleData
//
// Description: sets device handle data
virtual void SetDeviceHandleData(PVOID Data) = 0;
//-----------------------------------------------------------------------------------------
//
// SetDeviceAddress
//
// Description: sets device handle data
virtual NTSTATUS SetDeviceAddress(UCHAR DeviceAddress) = 0;
//-----------------------------------------------------------------------------------------
//
// GetDeviceDescriptor
//
// Description: sets device handle data
virtual void GetDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor) = 0;
//-----------------------------------------------------------------------------------------
//
// GetConfigurationValue
//
// Description: gets current selected configuration index
virtual UCHAR GetConfigurationValue() = 0;
//-----------------------------------------------------------------------------------------
//
// SubmitIrp
//
// Description: submits an irp containing an urb
virtual NTSTATUS SubmitIrp(PIRP Irp) = 0;
//-----------------------------------------------------------------------------------------
//
// GetConfigurationDescriptors
//
// Description: returns one or more configuration descriptors
virtual VOID GetConfigurationDescriptors(IN PUSB_CONFIGURATION_DESCRIPTOR ConfigDescriptorBuffer,
IN ULONG BufferLength,
OUT PULONG OutBufferLength) = 0;
//-----------------------------------------------------------------------------------------
//
// Description: returns length of configuration descriptors
//
virtual ULONG GetConfigurationDescriptorsLength() = 0;
//-----------------------------------------------------------------------------------------
//
// SubmitSetupPacket
//
// Description: submits an setup packet. The usb device will then create an usb request from it and submit it to the queue
virtual NTSTATUS SubmitSetupPacket(IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
IN OUT ULONG BufferLength,
OUT PVOID Buffer) = 0;
//-----------------------------------------------------------------------------------------
//
// SelectConfiguration
//
// Description: selects a configuration
virtual NTSTATUS SelectConfiguration(IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
IN PUSBD_INTERFACE_INFORMATION Interface,
OUT USBD_CONFIGURATION_HANDLE *ConfigurationHandle) = 0;
//-----------------------------------------------------------------------------------------
//
// SelectConfiguration
//
// Description: selects a interface of an configuration
virtual NTSTATUS SelectInterface(IN USBD_CONFIGURATION_HANDLE ConfigurationHandle,
IN OUT PUSBD_INTERFACE_INFORMATION Interface) = 0;
};
typedef IUSBDevice *PUSBDEVICE;
#endif

View file

@ -0,0 +1,358 @@
/*
* PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/usb/usbohci/memory_manager.cpp
* PURPOSE: USB OHCI device driver.
* PROGRAMMERS:
* Michael Martin (michael.martin@reactos.org)
* Johannes Anderwald (johannes.anderwald@reactos.org)
*/
#include "usbuhci.h"
class CDMAMemoryManager : public IDMAMemoryManager
{
public:
STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
STDMETHODIMP_(ULONG) AddRef()
{
InterlockedIncrement(&m_Ref);
return m_Ref;
}
STDMETHODIMP_(ULONG) Release()
{
InterlockedDecrement(&m_Ref);
if (!m_Ref)
{
delete this;
return 0;
}
return m_Ref;
}
// IDMAMemoryManager interface functions
virtual NTSTATUS Initialize(IN PUSBHARDWAREDEVICE Device, IN PKSPIN_LOCK Lock, IN ULONG DmaBufferSize, IN PVOID VirtualBase, IN PHYSICAL_ADDRESS PhysicalAddress, IN ULONG DefaultBlockSize);
virtual NTSTATUS Allocate(IN ULONG Size, OUT PVOID *OutVirtualBase, OUT PPHYSICAL_ADDRESS OutPhysicalAddress);
virtual NTSTATUS Release(IN PVOID VirtualBase, IN ULONG Size);
// constructor / destructor
CDMAMemoryManager(IUnknown *OuterUnknown){}
virtual ~CDMAMemoryManager(){}
protected:
LONG m_Ref;
PUSBHARDWAREDEVICE m_Device;
PKSPIN_LOCK m_Lock;
LONG m_DmaBufferSize;
PVOID m_VirtualBase;
PHYSICAL_ADDRESS m_PhysicalAddress;
ULONG m_BlockSize;
PULONG m_BitmapBuffer;
RTL_BITMAP m_Bitmap;
};
//----------------------------------------------------------------------------------------
NTSTATUS
STDMETHODCALLTYPE
CDMAMemoryManager::QueryInterface(
IN REFIID refiid,
OUT PVOID* Output)
{
return STATUS_UNSUCCESSFUL;
}
NTSTATUS
CDMAMemoryManager::Initialize(
IN PUSBHARDWAREDEVICE Device,
IN PKSPIN_LOCK Lock,
IN ULONG DmaBufferSize,
IN PVOID VirtualBase,
IN PHYSICAL_ADDRESS PhysicalAddress,
IN ULONG DefaultBlockSize)
{
ULONG BitmapLength;
//
// sanity checks
//
PC_ASSERT(DmaBufferSize >= PAGE_SIZE);
PC_ASSERT(DmaBufferSize % PAGE_SIZE == 0);
PC_ASSERT(DefaultBlockSize == 32 || DefaultBlockSize == 64 || DefaultBlockSize == 128);
//
// calculate bitmap length
//
BitmapLength = (DmaBufferSize / DefaultBlockSize) / 8;
//
// allocate bitmap buffer
//
m_BitmapBuffer = (PULONG)ExAllocatePoolWithTag(NonPagedPool, BitmapLength, TAG_USBOHCI);
if (!m_BitmapBuffer)
{
//
// no memory
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// initialize bitmap
//
RtlInitializeBitMap(&m_Bitmap, m_BitmapBuffer, BitmapLength * 8);
//
// clear all bits
//
RtlClearAllBits(&m_Bitmap);
//
// initialize rest of memory allocator
//
m_PhysicalAddress = PhysicalAddress;
m_VirtualBase = VirtualBase;
m_DmaBufferSize = DmaBufferSize;
m_BitmapBuffer = m_BitmapBuffer;
m_Lock = Lock;
m_BlockSize = DefaultBlockSize;
/* done */
return STATUS_SUCCESS;
}
NTSTATUS
CDMAMemoryManager::Allocate(
IN ULONG Size,
OUT PVOID *OutVirtualAddress,
OUT PPHYSICAL_ADDRESS OutPhysicalAddress)
{
ULONG Length, BlockCount, FreeIndex, StartPage, EndPage;
KIRQL OldLevel;
ULONG BlocksPerPage;
//
// sanity checks
//
ASSERT(Size <= PAGE_SIZE);
//ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
//
// align request
//
Length = (Size + m_BlockSize -1) & ~(m_BlockSize -1);
//
// sanity check
//
ASSERT(Length);
//
// convert to block count
//
BlockCount = Length / m_BlockSize;
//
// acquire lock
//
KeAcquireSpinLock(m_Lock, &OldLevel);
//
// helper variable
//
BlocksPerPage = PAGE_SIZE / m_BlockSize;
//
// start search
//
FreeIndex = 0;
do
{
//
// search for an free index
//
FreeIndex = RtlFindClearBits(&m_Bitmap, BlockCount, FreeIndex);
//
// check if there was a block found
//
if (FreeIndex == MAXULONG)
{
//
// no free block found
//
break;
}
//
// check that the allocation does not spawn over page boundaries
//
StartPage = (FreeIndex * m_BlockSize);
StartPage = (StartPage != 0 ? StartPage / PAGE_SIZE : 0);
EndPage = ((FreeIndex + BlockCount) * m_BlockSize) / PAGE_SIZE;
//
// does the request start and end on the same page
//
if (StartPage == EndPage)
{
//
// reserve block
//
RtlSetBits(&m_Bitmap, FreeIndex, BlockCount);
//
// reserve block
//
break;
}
else if ((BlockCount == BlocksPerPage) && (FreeIndex % BlocksPerPage == 0))
{
//
// the request equals PAGE_SIZE and is aligned at page boundary
// reserve block
//
RtlSetBits(&m_Bitmap, FreeIndex, BlockCount);
//
// reserve block
//
break;
}
else
{
//
// request spawned over page boundary
// restart search on next page
//
FreeIndex = (EndPage * PAGE_SIZE) / m_BlockSize;
}
}
while(TRUE);
//
// release lock
//
KeReleaseSpinLock(m_Lock, OldLevel);
//
// did allocation succeed
//
if (FreeIndex == MAXULONG)
{
//
// failed to allocate block, requestor must retry
//
return STATUS_UNSUCCESSFUL;
}
//
// return result
//
*OutVirtualAddress = (PVOID)((ULONG_PTR)m_VirtualBase + FreeIndex * m_BlockSize);
OutPhysicalAddress->QuadPart = m_PhysicalAddress.QuadPart + FreeIndex * m_BlockSize;
//
// clear block
//
RtlZeroMemory(*OutVirtualAddress, Length);
//
// done
//
return STATUS_SUCCESS;
}
NTSTATUS
CDMAMemoryManager::Release(
IN PVOID VirtualAddress,
IN ULONG Size)
{
KIRQL OldLevel;
ULONG BlockOffset = 0, BlockLength;
//
// sanity checks
//
PC_ASSERT(VirtualAddress);
PC_ASSERT((ULONG_PTR)VirtualAddress >= (ULONG_PTR)m_VirtualBase);
PC_ASSERT((ULONG_PTR)m_VirtualBase + m_DmaBufferSize > (ULONG_PTR)m_VirtualBase);
//
// calculate block length
//
BlockLength = ((ULONG_PTR)VirtualAddress - (ULONG_PTR)m_VirtualBase);
//
// check if its the first block
//
if (BlockLength)
{
//
// divide by base block size
//
BlockOffset = BlockLength / m_BlockSize;
}
//
// align length to block size
//
Size = (Size + m_BlockSize - 1) & ~(m_BlockSize - 1);
//
// acquire lock
//
KeAcquireSpinLock(m_Lock, &OldLevel);
//
// release buffer
//
RtlClearBits(&m_Bitmap, BlockOffset, Size);
//
// release lock
//
KeReleaseSpinLock(m_Lock, OldLevel);
//
// done
//
return STATUS_SUCCESS;
}
NTSTATUS
CreateDMAMemoryManager(
PDMAMEMORYMANAGER *OutMemoryManager)
{
CDMAMemoryManager* This;
//
// allocate controller
//
This = new(NonPagedPool, TAG_USBOHCI) CDMAMemoryManager(0);
if (!This)
{
//
// failed to allocate
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// add reference count
//
This->AddRef();
//
// return result
//
*OutMemoryManager = (PDMAMEMORYMANAGER)This;
//
// done
//
return STATUS_SUCCESS;
}

View file

@ -0,0 +1,134 @@
/*
* PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/usb/usbohci/misc.cpp
* PURPOSE: USB OHCI device driver.
* PROGRAMMERS:
* Michael Martin (michael.martin@reactos.org)
* Johannes Anderwald (johannes.anderwald@reactos.org)
*/
#include "usbuhci.h"
//
// driver verifier
//
IO_COMPLETION_ROUTINE SyncForwardIrpCompletionRoutine;
NTSTATUS
NTAPI
SyncForwardIrpCompletionRoutine(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context)
{
if (Irp->PendingReturned)
{
KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
}
return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
NTAPI
SyncForwardIrp(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
KEVENT Event;
NTSTATUS Status;
//
// initialize event
//
KeInitializeEvent(&Event, NotificationEvent, FALSE);
//
// copy irp stack location
//
IoCopyCurrentIrpStackLocationToNext(Irp);
//
// set completion routine
//
IoSetCompletionRoutine(Irp, SyncForwardIrpCompletionRoutine, &Event, TRUE, TRUE, TRUE);
//
// call driver
//
Status = IoCallDriver(DeviceObject, Irp);
//
// check if pending
//
if (Status == STATUS_PENDING)
{
//
// wait for the request to finish
//
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
//
// copy status code
//
Status = Irp->IoStatus.Status;
}
//
// done
//
return Status;
}
NTSTATUS
NTAPI
GetBusInterface(
PDEVICE_OBJECT DeviceObject,
PBUS_INTERFACE_STANDARD busInterface)
{
KEVENT Event;
NTSTATUS Status;
PIRP Irp;
IO_STATUS_BLOCK IoStatus;
PIO_STACK_LOCATION Stack;
if ((!DeviceObject) || (!busInterface))
return STATUS_UNSUCCESSFUL;
KeInitializeEvent(&Event, NotificationEvent, FALSE);
Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
DeviceObject,
NULL,
0,
NULL,
&Event,
&IoStatus);
if (Irp == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
Stack=IoGetNextIrpStackLocation(Irp);
Stack->MajorFunction = IRP_MJ_PNP;
Stack->MinorFunction = IRP_MN_QUERY_INTERFACE;
Stack->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD);
Stack->Parameters.QueryInterface.InterfaceType = (LPGUID)&GUID_BUS_INTERFACE_STANDARD;
Stack->Parameters.QueryInterface.Version = 1;
Stack->Parameters.QueryInterface.Interface = (PINTERFACE)busInterface;
Stack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
Irp->IoStatus.Status=STATUS_NOT_SUPPORTED ;
Status=IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status=IoStatus.Status;
}
return Status;
}

View file

@ -0,0 +1,24 @@
/*
* PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/usb/usbohci/purecall.cpp
* PURPOSE: USB OHCI device driver.
* PROGRAMMERS:
* Michael Martin (michael.martin@reactos.org)
* Johannes Anderwald (johannes.anderwald@reactos.org)
*/
#include "usbuhci.h"
extern "C" {
void
__cxa_pure_virtual()
{
// put error handling here
DbgBreakPoint();
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,169 @@
/*
* PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/usb/usbohci/usb_queue.cpp
* PURPOSE: USB OHCI device driver.
* PROGRAMMERS:
* Michael Martin (michael.martin@reactos.org)
* Johannes Anderwald (johannes.anderwald@reactos.org)
*/
#include "usbuhci.h"
#include "hardware.h"
class CUSBQueue : public IUSBQueue
{
public:
STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
STDMETHODIMP_(ULONG) AddRef()
{
InterlockedIncrement(&m_Ref);
return m_Ref;
}
STDMETHODIMP_(ULONG) Release()
{
InterlockedDecrement(&m_Ref);
if (!m_Ref)
{
delete this;
return 0;
}
return m_Ref;
}
// com
virtual NTSTATUS Initialize(IN PUSBHARDWAREDEVICE Hardware, PDMA_ADAPTER AdapterObject, IN PDMAMEMORYMANAGER MemManager, IN OPTIONAL PKSPIN_LOCK Lock);
virtual ULONG GetPendingRequestCount();
virtual NTSTATUS AddUSBRequest(IUSBRequest * Request);
virtual NTSTATUS CancelRequests();
virtual NTSTATUS CreateUSBRequest(IUSBRequest **OutRequest);
// constructor / destructor
CUSBQueue(IUnknown *OuterUnknown){}
virtual ~CUSBQueue(){}
protected:
LONG m_Ref; // reference count
KSPIN_LOCK m_Lock; // list lock
PUSBHARDWAREDEVICE m_Hardware; // hardware
};
//=================================================================================================
// COM
//
NTSTATUS
STDMETHODCALLTYPE
CUSBQueue::QueryInterface(
IN REFIID refiid,
OUT PVOID* Output)
{
if (IsEqualGUIDAligned(refiid, IID_IUnknown))
{
*Output = PVOID(PUNKNOWN(this));
PUNKNOWN(*Output)->AddRef();
return STATUS_SUCCESS;
}
return STATUS_UNSUCCESSFUL;
}
NTSTATUS
CUSBQueue::Initialize(
IN PUSBHARDWAREDEVICE Hardware,
IN PDMA_ADAPTER AdapterObject,
IN PDMAMEMORYMANAGER MemManager,
IN OPTIONAL PKSPIN_LOCK Lock)
{
//
// initialize spinlock
//
KeInitializeSpinLock(&m_Lock);
//
// store hardware
//
m_Hardware = Hardware;
return STATUS_SUCCESS;
}
ULONG
CUSBQueue::GetPendingRequestCount()
{
//
// Loop through the pending list and iterrate one for each QueueHead that
// has a IRP to complete.
//
return 0;
}
NTSTATUS
CUSBQueue::AddUSBRequest(
IUSBRequest * Request)
{
DPRINT("CUSBQueue::AddUSBRequest\n");
ASSERT(FALSE);
return STATUS_SUCCESS;
}
NTSTATUS
CUSBQueue::CancelRequests()
{
UNIMPLEMENTED
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
CUSBQueue::CreateUSBRequest(
IUSBRequest **OutRequest)
{
PUSBREQUEST UsbRequest;
NTSTATUS Status;
*OutRequest = NULL;
Status = InternalCreateUSBRequest(&UsbRequest);
if (NT_SUCCESS(Status))
{
*OutRequest = UsbRequest;
}
return Status;
}
NTSTATUS
CreateUSBQueue(
PUSBQUEUE *OutUsbQueue)
{
PUSBQUEUE This;
//
// allocate controller
//
This = new(NonPagedPool, TAG_USBOHCI) CUSBQueue(0);
if (!This)
{
//
// failed to allocate
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// add reference count
//
This->AddRef();
//
// return result
//
*OutUsbQueue = (PUSBQUEUE)This;
//
// done
//
return STATUS_SUCCESS;
}

View file

@ -0,0 +1,686 @@
/*
* PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/usb/usbohci/usb_request.cpp
* PURPOSE: USB OHCI device driver.
* PROGRAMMERS:
* Michael Martin (michael.martin@reactos.org)
* Johannes Anderwald (johannes.anderwald@reactos.org)
*/
#define INITGUID
#include "usbuhci.h"
#include "hardware.h"
class CUSBRequest : public IUSBRequest
{
public:
STDMETHODIMP QueryInterface( REFIID InterfaceId, PVOID* Interface);
STDMETHODIMP_(ULONG) AddRef()
{
InterlockedIncrement(&m_Ref);
return m_Ref;
}
STDMETHODIMP_(ULONG) Release()
{
InterlockedDecrement(&m_Ref);
if (!m_Ref)
{
delete this;
return 0;
}
return m_Ref;
}
// IUSBRequest interface functions
virtual NTSTATUS InitializeWithSetupPacket(IN PDMAMEMORYMANAGER DmaManager, IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket, IN UCHAR DeviceAddress, IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor, IN OUT ULONG TransferBufferLength, IN OUT PMDL TransferBuffer);
virtual NTSTATUS InitializeWithIrp(IN PDMAMEMORYMANAGER DmaManager, IN OUT PIRP Irp);
virtual BOOLEAN IsRequestComplete();
virtual ULONG GetTransferType();
virtual NTSTATUS GetEndpointDescriptor(struct _UHCI_TRANSFER_DESCRIPTOR ** OutEndpointDescriptor);
virtual VOID GetResultStatus(OUT OPTIONAL NTSTATUS *NtStatusCode, OUT OPTIONAL PULONG UrbStatusCode);
virtual BOOLEAN IsRequestInitialized();
virtual BOOLEAN IsQueueHeadComplete(struct _QUEUE_HEAD * QueueHead);
virtual UCHAR GetInterval();
// local functions
ULONG InternalGetTransferType();
UCHAR InternalGetPidDirection();
UCHAR GetDeviceAddress();
NTSTATUS BuildSetupPacket();
NTSTATUS BuildSetupPacketFromURB();
UCHAR GetEndpointAddress();
USHORT GetMaxPacketSize();
// constructor / destructor
CUSBRequest(IUnknown *OuterUnknown){}
virtual ~CUSBRequest(){}
protected:
LONG m_Ref;
//
// memory manager for allocating setup packet / queue head / transfer descriptors
//
PDMAMEMORYMANAGER m_DmaManager;
//
// caller provided irp packet containing URB request
//
PIRP m_Irp;
//
// transfer buffer length
//
ULONG m_TransferBufferLength;
//
// current transfer length
//
ULONG m_TransferBufferLengthCompleted;
//
// Total Transfer Length
//
ULONG m_TotalBytesTransferred;
//
// transfer buffer MDL
//
PMDL m_TransferBufferMDL;
//
// caller provided setup packet
//
PUSB_DEFAULT_PIPE_SETUP_PACKET m_SetupPacket;
//
// completion event for callers who initialized request with setup packet
//
PKEVENT m_CompletionEvent;
//
// device address for callers who initialized it with device address
//
UCHAR m_DeviceAddress;
//
// store end point address
//
PUSB_ENDPOINT_DESCRIPTOR m_EndpointDescriptor;
//
// allocated setup packet from the DMA pool
//
PUSB_DEFAULT_PIPE_SETUP_PACKET m_DescriptorPacket;
PHYSICAL_ADDRESS m_DescriptorSetupPacket;
//
// stores the result of the operation
//
NTSTATUS m_NtStatusCode;
ULONG m_UrbStatusCode;
};
//----------------------------------------------------------------------------------------
NTSTATUS
STDMETHODCALLTYPE
CUSBRequest::QueryInterface(
IN REFIID refiid,
OUT PVOID* Output)
{
return STATUS_UNSUCCESSFUL;
}
//----------------------------------------------------------------------------------------
NTSTATUS
CUSBRequest::InitializeWithSetupPacket(
IN PDMAMEMORYMANAGER DmaManager,
IN PUSB_DEFAULT_PIPE_SETUP_PACKET SetupPacket,
IN UCHAR DeviceAddress,
IN OPTIONAL PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor,
IN OUT ULONG TransferBufferLength,
IN OUT PMDL TransferBuffer)
{
//
// sanity checks
//
PC_ASSERT(DmaManager);
PC_ASSERT(SetupPacket);
//
// initialize packet
//
m_DmaManager = DmaManager;
m_SetupPacket = SetupPacket;
m_TransferBufferLength = TransferBufferLength;
m_TransferBufferMDL = TransferBuffer;
m_DeviceAddress = DeviceAddress;
m_EndpointDescriptor = EndpointDescriptor;
m_TotalBytesTransferred = 0;
//
// Set Length Completed to 0
//
m_TransferBufferLengthCompleted = 0;
//
// allocate completion event
//
m_CompletionEvent = (PKEVENT)ExAllocatePoolWithTag(NonPagedPool, sizeof(KEVENT), TAG_USBOHCI);
if (!m_CompletionEvent)
{
//
// failed to allocate completion event
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// initialize completion event
//
KeInitializeEvent(m_CompletionEvent, NotificationEvent, FALSE);
//
// done
//
return STATUS_SUCCESS;
}
//----------------------------------------------------------------------------------------
NTSTATUS
CUSBRequest::InitializeWithIrp(
IN PDMAMEMORYMANAGER DmaManager,
IN OUT PIRP Irp)
{
PIO_STACK_LOCATION IoStack;
PURB Urb;
//
// sanity checks
//
PC_ASSERT(DmaManager);
PC_ASSERT(Irp);
m_DmaManager = DmaManager;
m_TotalBytesTransferred = 0;
//
// get current irp stack location
//
IoStack = IoGetCurrentIrpStackLocation(Irp);
//
// sanity check
//
PC_ASSERT(IoStack->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL);
PC_ASSERT(IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_SUBMIT_URB);
PC_ASSERT(IoStack->Parameters.Others.Argument1 != 0);
//
// get urb
//
Urb = (PURB)IoStack->Parameters.Others.Argument1;
//
// store irp
//
m_Irp = Irp;
//
// check function type
//
switch (Urb->UrbHeader.Function)
{
case URB_FUNCTION_ISOCH_TRANSFER:
{
//
// there must be at least one packet
//
ASSERT(Urb->UrbIsochronousTransfer.NumberOfPackets);
//
// is there data to be transferred
//
if (Urb->UrbIsochronousTransfer.TransferBufferLength)
{
//
// Check if there is a MDL
//
if (!Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL)
{
//
// sanity check
//
PC_ASSERT(Urb->UrbBulkOrInterruptTransfer.TransferBuffer);
//
// Create one using TransferBuffer
//
DPRINT("Creating Mdl from Urb Buffer %p Length %lu\n", Urb->UrbBulkOrInterruptTransfer.TransferBuffer, Urb->UrbBulkOrInterruptTransfer.TransferBufferLength);
m_TransferBufferMDL = IoAllocateMdl(Urb->UrbBulkOrInterruptTransfer.TransferBuffer,
Urb->UrbBulkOrInterruptTransfer.TransferBufferLength,
FALSE,
FALSE,
NULL);
if (!m_TransferBufferMDL)
{
//
// failed to allocate mdl
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// build mdl for non paged pool
// FIXME: Does hub driver already do this when passing MDL?
//
MmBuildMdlForNonPagedPool(m_TransferBufferMDL);
}
else
{
//
// use provided mdl
//
m_TransferBufferMDL = Urb->UrbIsochronousTransfer.TransferBufferMDL;
}
}
//
// save buffer length
//
m_TransferBufferLength = Urb->UrbIsochronousTransfer.TransferBufferLength;
//
// Set Length Completed to 0
//
m_TransferBufferLengthCompleted = 0;
//
// get endpoint descriptor
//
m_EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbIsochronousTransfer.PipeHandle;
//
// completed initialization
//
break;
}
//
// luckily those request have the same structure layout
//
case URB_FUNCTION_CLASS_INTERFACE:
case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
{
//
// bulk interrupt transfer
//
if (Urb->UrbBulkOrInterruptTransfer.TransferBufferLength)
{
//
// Check if there is a MDL
//
if (!Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL)
{
//
// sanity check
//
PC_ASSERT(Urb->UrbBulkOrInterruptTransfer.TransferBuffer);
//
// Create one using TransferBuffer
//
DPRINT("Creating Mdl from Urb Buffer %p Length %lu\n", Urb->UrbBulkOrInterruptTransfer.TransferBuffer, Urb->UrbBulkOrInterruptTransfer.TransferBufferLength);
m_TransferBufferMDL = IoAllocateMdl(Urb->UrbBulkOrInterruptTransfer.TransferBuffer,
Urb->UrbBulkOrInterruptTransfer.TransferBufferLength,
FALSE,
FALSE,
NULL);
if (!m_TransferBufferMDL)
{
//
// failed to allocate mdl
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// build mdl for non paged pool
// FIXME: Does hub driver already do this when passing MDL?
//
MmBuildMdlForNonPagedPool(m_TransferBufferMDL);
//
// Keep that ehci created the MDL and needs to free it.
//
}
else
{
m_TransferBufferMDL = Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL;
}
//
// save buffer length
//
m_TransferBufferLength = Urb->UrbBulkOrInterruptTransfer.TransferBufferLength;
//
// Set Length Completed to 0
//
m_TransferBufferLengthCompleted = 0;
//
// get endpoint descriptor
//
m_EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)Urb->UrbBulkOrInterruptTransfer.PipeHandle;
}
break;
}
default:
DPRINT1("URB Function: not supported %x\n", Urb->UrbHeader.Function);
PC_ASSERT(FALSE);
}
//
// done
//
return STATUS_SUCCESS;
}
//----------------------------------------------------------------------------------------
BOOLEAN
CUSBRequest::IsRequestComplete()
{
//
// FIXME: check if request was split
//
//
// Check if the transfer was completed, only valid for Bulk Transfers
//
if ((m_TransferBufferLengthCompleted < m_TransferBufferLength)
&& (GetTransferType() == USB_ENDPOINT_TYPE_BULK))
{
//
// Transfer not completed
//
return FALSE;
}
return TRUE;
}
//----------------------------------------------------------------------------------------
ULONG
CUSBRequest::GetTransferType()
{
//
// call internal implementation
//
return InternalGetTransferType();
}
USHORT
CUSBRequest::GetMaxPacketSize()
{
if (!m_EndpointDescriptor)
{
//
// control request
//
return 0;
}
ASSERT(m_Irp);
ASSERT(m_EndpointDescriptor);
//
// return max packet size
//
return m_EndpointDescriptor->wMaxPacketSize;
}
UCHAR
CUSBRequest::GetInterval()
{
ASSERT(m_EndpointDescriptor);
ASSERT((m_EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_INTERRUPT);
//
// return interrupt interval
//
return m_EndpointDescriptor->bInterval;
}
UCHAR
CUSBRequest::GetEndpointAddress()
{
if (!m_EndpointDescriptor)
{
//
// control request
//
return 0;
}
ASSERT(m_Irp);
ASSERT(m_EndpointDescriptor);
//
// endpoint number is between 1-15
//
return (m_EndpointDescriptor->bEndpointAddress & 0xF);
}
//----------------------------------------------------------------------------------------
ULONG
CUSBRequest::InternalGetTransferType()
{
ULONG TransferType;
//
// check if an irp is provided
//
if (m_Irp)
{
ASSERT(m_EndpointDescriptor);
//
// end point is defined in the low byte of bmAttributes
//
TransferType = (m_EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK);
}
else
{
//
// initialized with setup packet, must be a control transfer
//
TransferType = USB_ENDPOINT_TYPE_CONTROL;
}
//
// done
//
return TransferType;
}
UCHAR
CUSBRequest::InternalGetPidDirection()
{
ASSERT(m_Irp);
ASSERT(m_EndpointDescriptor);
//
// end point is defined in the low byte of bEndpointAddress
//
return (m_EndpointDescriptor->bEndpointAddress & USB_ENDPOINT_DIRECTION_MASK) >> 7;
}
//----------------------------------------------------------------------------------------
UCHAR
CUSBRequest::GetDeviceAddress()
{
PIO_STACK_LOCATION IoStack;
PURB Urb;
PUSBDEVICE UsbDevice;
//
// check if there is an irp provided
//
if (!m_Irp)
{
//
// used provided address
//
return m_DeviceAddress;
}
//
// get current stack location
//
IoStack = IoGetCurrentIrpStackLocation(m_Irp);
//
// get contained urb
//
Urb = (PURB)IoStack->Parameters.Others.Argument1;
//
// check if there is a pipe handle provided
//
if (Urb->UrbHeader.UsbdDeviceHandle)
{
//
// there is a device handle provided
//
UsbDevice = (PUSBDEVICE)Urb->UrbHeader.UsbdDeviceHandle;
//
// return device address
//
return UsbDevice->GetDeviceAddress();
}
//
// no device handle provided, it is the host root bus
//
return 0;
}
//----------------------------------------------------------------------------------------
NTSTATUS
CUSBRequest::GetEndpointDescriptor(
struct _UHCI_TRANSFER_DESCRIPTOR ** OutDescriptor)
{
ASSERT(FALSE);
//
// done
//
return STATUS_NOT_IMPLEMENTED;
}
//----------------------------------------------------------------------------------------
VOID
CUSBRequest::GetResultStatus(
OUT OPTIONAL NTSTATUS * NtStatusCode,
OUT OPTIONAL PULONG UrbStatusCode)
{
//
// sanity check
//
PC_ASSERT(m_CompletionEvent);
//
// wait for the operation to complete
//
KeWaitForSingleObject(m_CompletionEvent, Executive, KernelMode, FALSE, NULL);
//
// copy status
//
if (NtStatusCode)
{
*NtStatusCode = m_NtStatusCode;
}
//
// copy urb status
//
if (UrbStatusCode)
{
*UrbStatusCode = m_UrbStatusCode;
}
}
//-----------------------------------------------------------------------------------------
BOOLEAN
CUSBRequest::IsRequestInitialized()
{
if (m_Irp || m_SetupPacket)
{
//
// request is initialized
//
return TRUE;
}
//
// request is not initialized
//
return FALSE;
}
//-----------------------------------------------------------------------------------------
BOOLEAN
CUSBRequest::IsQueueHeadComplete(
struct _QUEUE_HEAD * QueueHead)
{
UNIMPLEMENTED
return TRUE;
}
//-----------------------------------------------------------------------------------------
NTSTATUS
InternalCreateUSBRequest(
PUSBREQUEST *OutRequest)
{
PUSBREQUEST This;
//
// allocate requests
//
This = new(NonPagedPool, TAG_USBOHCI) CUSBRequest(0);
if (!This)
{
//
// failed to allocate
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// add reference count
//
This->AddRef();
//
// return result
//
*OutRequest = (PUSBREQUEST)This;
//
// done
//
return STATUS_SUCCESS;
}

View file

@ -0,0 +1,143 @@
/*
* PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/usb/usbohci/usbohci.cpp
* PURPOSE: USB OHCI device driver.
* PROGRAMMERS:
* Michael Martin (michael.martin@reactos.org)
* Johannes Anderwald (johannes.anderwald@reactos.org)
*/
#include "usbuhci.h"
//
// driver verifier
//
DRIVER_ADD_DEVICE UHCI_AddDevice;
NTSTATUS
NTAPI
UHCI_AddDevice(
PDRIVER_OBJECT DriverObject,
PDEVICE_OBJECT PhysicalDeviceObject)
{
NTSTATUS Status;
PHCDCONTROLLER HcdController;
DPRINT1("UHCI_AddDevice\n");
/* first create the controller object */
Status = CreateHCDController(&HcdController);
if (!NT_SUCCESS(Status))
{
/* failed to create hcd */
DPRINT1("AddDevice: Failed to create hcd with %x\n", Status);
return Status;
}
/* initialize the hcd */
Status = HcdController->Initialize(NULL, // FIXME
DriverObject,
PhysicalDeviceObject);
/* check for success */
if (!NT_SUCCESS(Status))
{
/* failed to initialize device */
DPRINT1("AddDevice: failed to initialize\n");
/* release object */
HcdController->Release();
}
return Status;
}
NTSTATUS
NTAPI
UHCI_Dispatch(
PDEVICE_OBJECT DeviceObject,
PIRP Irp)
{
PCOMMON_DEVICE_EXTENSION DeviceExtension;
PIO_STACK_LOCATION IoStack;
NTSTATUS Status;
//
// get common device extension
//
DeviceExtension = (PCOMMON_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
//
// get current stack location
//
IoStack = IoGetCurrentIrpStackLocation(Irp);
//
// sanity checks
//
PC_ASSERT(DeviceExtension->Dispatcher);
switch(IoStack->MajorFunction)
{
case IRP_MJ_PNP:
{
//
// dispatch pnp
//
return DeviceExtension->Dispatcher->HandlePnp(DeviceObject, Irp);
}
case IRP_MJ_POWER:
{
//
// dispatch pnp
//
return DeviceExtension->Dispatcher->HandlePower(DeviceObject, Irp);
}
case IRP_MJ_INTERNAL_DEVICE_CONTROL:
case IRP_MJ_DEVICE_CONTROL:
{
//
// dispatch pnp
//
return DeviceExtension->Dispatcher->HandleDeviceControl(DeviceObject, Irp);
}
default:
{
DPRINT1("UHCI_Dispatch> Major %lu Minor %lu unhandeled\n", IoStack->MajorFunction, IoStack->MinorFunction);
Status = STATUS_SUCCESS;
}
}
//
// complete request
//
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
extern
"C"
NTSTATUS
NTAPI
DriverEntry(
PDRIVER_OBJECT DriverObject,
PUNICODE_STRING RegistryPath)
{
DPRINT1("[UHCI] Driver Entry\n");
/* initialize driver object*/
DriverObject->DriverExtension->AddDevice = UHCI_AddDevice;
DriverObject->MajorFunction[IRP_MJ_CREATE] = UHCI_Dispatch;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = UHCI_Dispatch;
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = UHCI_Dispatch;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = UHCI_Dispatch;
DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = UHCI_Dispatch;
DriverObject->MajorFunction[IRP_MJ_PNP] = UHCI_Dispatch;
return STATUS_SUCCESS;
}

View file

@ -0,0 +1,110 @@
#ifndef USBOHCI_H__
#define USBOHCI_H__
#include <ntddk.h>
#define NDEBUG
#include <debug.h>
#include <hubbusif.h>
#include <usbbusif.h>
#include <usbioctl.h>
extern
"C"
{
#include <usbdlib.h>
}
//
// FIXME:
// #include <usbprotocoldefs.h>
//
#include <usb.h>
#include <stdio.h>
#include <wdmguid.h>
//
// FIXME:
// the following includes are required to get kcom to compile
//
#include <portcls.h>
#include <dmusicks.h>
#include <kcom.h>
#include "interfaces.h"
//
// flags for handling USB_REQUEST_SET_FEATURE / USB_REQUEST_GET_FEATURE
//
#define PORT_ENABLE 1
#define PORT_SUSPEND 2
#define PORT_OVER_CURRENT 3
#define PORT_RESET 4
#define PORT_POWER 8
#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
typedef struct
{
BOOLEAN IsFDO; // is device a FDO or PDO
BOOLEAN IsHub; // is device a hub / child - not yet used
PDISPATCHIRP Dispatcher; // dispatches the code
}COMMON_DEVICE_EXTENSION, *PCOMMON_DEVICE_EXTENSION;
//
// tag for allocations
//
#define TAG_USBOHCI 'ICHO'
//
// assert for c++ - taken from portcls
//
#define PC_ASSERT(exp) \
(VOID)((!(exp)) ? \
RtlAssert((PVOID) #exp, (PVOID)__FILE__, __LINE__, NULL ), FALSE : TRUE)
//
// hcd_controller.cpp
//
NTSTATUS CreateHCDController(PHCDCONTROLLER *HcdController);
//
// hardware.cpp
//
NTSTATUS CreateUSBHardware(PUSBHARDWAREDEVICE *OutHardware);
//
// misc.cpp
//
NTSTATUS NTAPI SyncForwardIrp(PDEVICE_OBJECT DeviceObject, PIRP Irp);
NTSTATUS NTAPI GetBusInterface(PDEVICE_OBJECT DeviceObject, PBUS_INTERFACE_STANDARD busInterface);
//
// root_hub_controller.cpp
//
NTSTATUS CreateHubController(PHUBCONTROLLER * OutHubController);
//
// memory_manager.cpp
//
NTSTATUS CreateDMAMemoryManager(PDMAMEMORYMANAGER *OutMemoryManager);
//
// usb_device.cpp
//
NTSTATUS CreateUSBDevice(PUSBDEVICE *OutDevice);
//
// usb_queue.cpp
//
NTSTATUS CreateUSBQueue(PUSBQUEUE *OutUsbQueue);
//
// usb_request.cpp
//
NTSTATUS InternalCreateUSBRequest(PUSBREQUEST *OutRequest);
#endif

View file

@ -0,0 +1,5 @@
#define REACTOS_VERSION_DLL
#define REACTOS_STR_FILE_DESCRIPTION "USBUHCI Driver API\0"
#define REACTOS_STR_INTERNAL_NAME "usbuhci\0"
#define REACTOS_STR_ORIGINAL_FILENAME "usbuhci.sys\0"
#include <reactos/version.rc>