reactos/drivers/usb/usbehci_new/usb_device.cpp
Johannes Anderwald 3ac2c07f55 [USBEHCI_NEW]
- Null terminate buffer from IOCTL_USB_GET_ROOT_HUB_NAME, fixes usbview problems
- Implement URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER, IUSBHardware needs more work
- Silence debug traces
- Start implementing IUSBRequest interfaces
- Complete unhandled major irp with status success

svn path=/branches/usb-bringup/; revision=51396
2011-04-19 01:21:10 +00:00

549 lines
12 KiB
C++

/*
* PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/usb/usbehci/usb_device.cpp
* PURPOSE: USB EHCI device driver.
* PROGRAMMERS:
* Michael Martin (michael.martin@reactos.org)
* Johannes Anderwald (johannes.anderwald@reactos.org)
*/
#define INITGUID
#include "usbehci.h"
class CUSBDevice : public IUSBDevice
{
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;
}
// IUSBDevice interface functions
virtual NTSTATUS Initialize(IN PHUBCONTROLLER HubController, IN PUSBHARDWAREDEVICE Device, IN PVOID Parent, IN ULONG Port, IN ULONG PortStatus);
virtual BOOLEAN IsHub();
virtual NTSTATUS GetParent(PVOID * Parent);
virtual ULONG GetDeviceAddress();
virtual ULONG GetPort();
virtual USB_DEVICE_SPEED GetSpeed();
virtual USB_DEVICE_TYPE GetType();
virtual ULONG GetState();
virtual void SetDeviceHandleData(PVOID Data);
virtual NTSTATUS SetDeviceAddress(ULONG DeviceAddress);
virtual void GetDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor);
virtual UCHAR GetConfigurationValue();
virtual NTSTATUS SubmitUrb(PURB Urb);
// local function
virtual NTSTATUS CommitUrb(PURB Urb);
virtual NTSTATUS CommitSetupPacket(PUSB_DEFAULT_PIPE_SETUP_PACKET Packet, IN ULONG BufferLength, IN OUT PVOID Buffer, IN OPTIONAL PIRP Irp, IN OPTIONAL PKEVENT pEvent);
// constructor / destructor
CUSBDevice(IUnknown *OuterUnknown){}
virtual ~CUSBDevice(){}
protected:
LONG m_Ref;
PHUBCONTROLLER m_HubController;
PUSBHARDWAREDEVICE m_Device;
PVOID m_Parent;
ULONG m_Port;
ULONG m_DeviceAddress;
PVOID m_Data;
KSPIN_LOCK m_Lock;
USB_DEVICE_DESCRIPTOR m_DeviceDescriptor;
ULONG m_PortStatus;
PUSBQUEUE m_Queue;
PDMAMEMORYMANAGER m_DmaManager;
};
//----------------------------------------------------------------------------------------
NTSTATUS
STDMETHODCALLTYPE
CUSBDevice::QueryInterface(
IN REFIID refiid,
OUT PVOID* Output)
{
return STATUS_UNSUCCESSFUL;
}
//----------------------------------------------------------------------------------------
NTSTATUS
CUSBDevice::Initialize(
IN PHUBCONTROLLER HubController,
IN PUSBHARDWAREDEVICE Device,
IN PVOID Parent,
IN ULONG Port,
IN ULONG PortStatus)
{
NTSTATUS Status;
USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
//
// initialize members
//
m_HubController = HubController;
m_Device = Device;
m_Parent = Parent;
m_Port = Port;
m_PortStatus = PortStatus;
//
// initialize device lock
//
KeInitializeSpinLock(&m_Lock);
//
// no device address has been set yet
//
m_DeviceAddress = 0;
//
// get usb request queue
//
Status = m_Device->GetUSBQueue(&m_Queue);
if (!NT_SUCCESS(Status))
{
//
// failed to get usb queue
//
DPRINT1("CUSBDevice::Initialize GetUsbQueue failed with %x\n", Status);
return Status;
}
//
// FIXME: get dma manager
//
//Status = m_Device->GetDMA(&m_DmaManager);
if (!NT_SUCCESS(Status))
{
//
// failed to get usb queue
//
DPRINT1("CUSBDevice::Initialize GetUsbQueue failed with %x\n", Status);
return Status;
}
//
// zero descriptor
//
RtlZeroMemory(&m_DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
//
// setup request
//
CtrlSetup.bRequest = USB_REQUEST_GET_DESCRIPTOR;
CtrlSetup.wValue.HiByte = USB_DEVICE_DESCRIPTOR_TYPE;
CtrlSetup.wLength = sizeof(USB_DEVICE_DESCRIPTOR);
CtrlSetup.bmRequestType.B = 0x80;
//
// commit setup packet
//
Status = CommitSetupPacket(&CtrlSetup, sizeof(USB_DEVICE_DESCRIPTOR), &m_DeviceDescriptor, 0, 0);
//
// check for success
//
if (!NT_SUCCESS(Status))
{
DPRINT1("CUSBDevice::Initialize CommitSetupPacket failed with %x\n", Status);
}
//
// done
//
return Status;
}
//----------------------------------------------------------------------------------------
BOOLEAN
CUSBDevice::IsHub()
{
//
// USB Standard Device Class see http://www.usb.org/developers/defined_class/#BaseClass09h
// for details
//
return (m_DeviceDescriptor.bDeviceClass == 0x09 && m_DeviceDescriptor.bDeviceSubClass == 0x00);
}
//----------------------------------------------------------------------------------------
NTSTATUS
CUSBDevice::GetParent(
PVOID * Parent)
{
//
// returns parent
//
*Parent = m_Parent;
//
// done
//
return STATUS_SUCCESS;
}
//----------------------------------------------------------------------------------------
ULONG
CUSBDevice::GetDeviceAddress()
{
//
// get device address
//
return m_DeviceAddress;
}
//----------------------------------------------------------------------------------------
ULONG
CUSBDevice::GetPort()
{
//
// get port to which this device is connected to
//
return m_Port;
}
//----------------------------------------------------------------------------------------
USB_DEVICE_SPEED
CUSBDevice::GetSpeed()
{
if (m_PortStatus & USB_PORT_STATUS_LOW_SPEED)
{
//
// low speed device
//
return UsbLowSpeed;
}
else if (m_PortStatus & USB_PORT_STATUS_HIGH_SPEED)
{
//
// high speed device
//
return UsbHighSpeed;
}
//
// default to full speed
//
return UsbFullSpeed;
}
//----------------------------------------------------------------------------------------
USB_DEVICE_TYPE
CUSBDevice::GetType()
{
//
// device is encoded into bcdUSB
//
if (m_DeviceDescriptor.bcdUSB == 0x110)
{
//
// USB 1.1 device
//
return Usb11Device;
}
else if (m_DeviceDescriptor.bcdUSB == 0x200)
{
//
// USB 2.0 device
//
return Usb20Device;
}
DPRINT1("CUSBDevice::GetType Unknown bcdUSB Type %x\n", m_DeviceDescriptor.bcdUSB);
PC_ASSERT(FALSE);
return Usb11Device;
}
//----------------------------------------------------------------------------------------
ULONG
CUSBDevice::GetState()
{
UNIMPLEMENTED
return FALSE;
}
//----------------------------------------------------------------------------------------
void
CUSBDevice::SetDeviceHandleData(
PVOID Data)
{
//
// set device data, for debugging issues
//
m_Data = Data;
}
//----------------------------------------------------------------------------------------
NTSTATUS
CUSBDevice::SetDeviceAddress(
ULONG DeviceAddress)
{
USB_DEFAULT_PIPE_SETUP_PACKET CtrlSetup;
NTSTATUS Status;
//
// zero request
//
RtlZeroMemory(&CtrlSetup, sizeof(USB_DEFAULT_PIPE_SETUP_PACKET));
//
// initialize request
//
CtrlSetup.bRequest = USB_REQUEST_SET_ADDRESS;
CtrlSetup.wValue.W = (USHORT)DeviceAddress;
//
// set device address
//
Status = CommitSetupPacket(&CtrlSetup, 0, 0, 0, 0);
//
// check for success
//
if (!NT_SUCCESS(Status))
{
//
// failed to set device address
//
DPRINT1("CUSBDevice::SetDeviceAddress> failed to set device address with %x Address %x\n", Status, DeviceAddress);
return Status;
}
//
// store device address
//
m_DeviceAddress = DeviceAddress;
//
// done
//
return STATUS_SUCCESS;
}
//----------------------------------------------------------------------------------------
void
CUSBDevice::GetDeviceDescriptor(
PUSB_DEVICE_DESCRIPTOR DeviceDescriptor)
{
RtlMoveMemory(DeviceDescriptor, &m_DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
}
//----------------------------------------------------------------------------------------
UCHAR
CUSBDevice::GetConfigurationValue()
{
UNIMPLEMENTED
return 0x1;
}
//----------------------------------------------------------------------------------------
NTSTATUS
CUSBDevice::CommitUrb(
PURB Urb)
{
UNIMPLEMENTED
return STATUS_NOT_IMPLEMENTED;
}
//----------------------------------------------------------------------------------------
NTSTATUS
CUSBDevice::SubmitUrb(
PURB Urb)
{
KIRQL OldLevel;
NTSTATUS Status;
//
// acquire device lock
//
KeAcquireSpinLock(&m_Lock, &OldLevel);
//
// commit urb
//
Status = CommitUrb(Urb);
//
// release lock
//
KeReleaseSpinLock(&m_Lock, OldLevel);
return Status;
}
//----------------------------------------------------------------------------------------
NTSTATUS
CUSBDevice::CommitSetupPacket(
PUSB_DEFAULT_PIPE_SETUP_PACKET Packet,
IN ULONG BufferLength,
IN OUT PVOID Buffer,
IN PIRP Irp,
IN PKEVENT pEvent)
{
NTSTATUS Status;
PUSBREQUEST Request;
KEVENT Event;
BOOLEAN Wait = FALSE;
PMDL Mdl = 0;
if (!m_Queue)
{
//
// no queue, wtf?
//
DPRINT1("CUSBDevice::CommitSetupPacket> no queue!!!\n");
return STATUS_UNSUCCESSFUL;
}
//
// build usb request
//
Status = m_Queue->CreateUSBRequest(&Request);
if (!NT_SUCCESS(Status))
{
//
// failed to build request
//
DPRINT1("CUSBDevice::CommitSetupPacket> CreateUSBRequest failed with %x\n", Status);
return Status;
}
/* FIXME build MDL */
//
// initialize request
//
Status = Request->InitializeWithSetupPacket(m_DmaManager, Packet, BufferLength, Mdl);
if (!NT_SUCCESS(Status))
{
//
// failed to initialize request
//
DPRINT1("CUSBDevice::CommitSetupPacket> failed to initialize usb request with %x\n", Status);
Request->Release();
return Status;
}
//
// is a irp or event provided ?
//
if (Irp == NULL && pEvent == NULL)
{
//
// no completion details provided, requestor wants synchronized
//
KeInitializeEvent(&Event, NotificationEvent, FALSE);
pEvent = &Event;
Wait = TRUE;
}
//
// set completion details
//
Status = Request->SetCompletionEvent(pEvent);
if (!NT_SUCCESS(Status))
{
//
// failed to set completion details
//
DPRINT1("CUSBDevice::CommitSetupPacket> failed to set completion details with %x\n", Status);
Request->Release();
return Status;
}
//
// now add the request
//
Status = m_Queue->AddUSBRequest(Request);
if (!NT_SUCCESS(Status))
{
//
// failed to add request
//
DPRINT1("CUSBDevice::CommitSetupPacket> failed add request to queue with %x\n", Status);
Request->Release();
return Status;
}
if (Wait)
{
//
// wait for the operation to complete
//
KeWaitForSingleObject(pEvent, Executive, KernelMode, FALSE, NULL);
}
//TODO:
// Get result code from operation
//
//
// returns the result code when the operation has been finished
//
//Status = Request->GetResultCode();
//
// release request
//
Request->Release();
//
// done
//
return Status;
}
//----------------------------------------------------------------------------------------
NTSTATUS
CreateUSBDevice(
PUSBDEVICE *OutDevice)
{
CUSBDevice * This;
//
// allocate controller
//
This = new(NonPagedPool, TAG_USBEHCI) CUSBDevice(0);
if (!This)
{
//
// failed to allocate
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// add reference count
//
This->AddRef();
//
// return result
//
*OutDevice = (PUSBDEVICE)This;
//
// done
//
return STATUS_SUCCESS;
}