![]() |
| Home |
|
|
Structure of an Active USB ClientAn active USB client is a driver which requires a thread, usually to receive data at any time. Devices with Interrupt and possibly Isochronous endpoints typically fall into this category. A typical active USB client is a mouse driver. Below is a framework for a very simple USB mouse driver. Please note that the following code is intended as an example only. RTUSB-32 contains a real mouse class driver. Its complete source code is available in file Driver\Rtu32\Usbmouse.c. The example below is the demo program MouseDemo. MouseDemo has an attachment/detachment callback called USBMouseEvent(). In the RTUConnect event, it checks whether this new device has the desired interface. If so, a device data block containing the required pipe is allocated, initialized, and sent to a thread created for the device. This client does not need a semaphore to protect the device data since the device data is attached to the device using RTUSetClientData. When the device is detached, the attachment and detachment callback simply closes the pipe. The thread will then receive an RTU_CANCELED event or a call to RTUStartIO will fail, causing the thread to deallocate the device data and to terminate itself. Active USB Client (MouseDemo):
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <Rtk32.h>
#include <Rtusb.h>
// The device we want has USB class RTU_USB_CLASS_HID declared in Rtusb.h
// subclasses
#define SUBCLASS_BOOTDEVICE 1
// protocols, only used with subclass SUBCLASS_BOOTDEVICE
#define PROT_MOUSE 2
// this is the actual data sent by a USB mouse.
// See the USB HID spec for details
typedef struct {
BYTE Buttons;
signed char DeltaX,
DeltaY,
DeltaZ;
} RawMouseData;
// DriverDataType is a structure with data the driver has to maintain
// per device. In this case, it's a pipe and a receive buffer
typedef struct {
RTUPipeHandle MouseIn;
RawMouseData Data;
} DriverDataType;
/*-----------------------------------*/
static void ProcessMouseEvent(RawMouseData * Data)
// function to display the raw data received from the mouse
// a real mouse client would call WriteConsoleInput() here
{
printf("Buttons: %02X, Deltas: X: %3i, Y: %3i, Z: %3i\n",
Data->Buttons, Data->DeltaX, Data->DeltaY, Data->DeltaZ);
}
/*-----------------------------------*/
static void RTKAPI MouseThread(void * p)
// thread to handle one mouse. Any number of these can run simultaneously
// The device data is passed as a parameter
{
DriverDataType * MouseData = (DriverDataType *)p;
while (1)
{
// listen for data
int Result = RTUStartIO(MouseData->MouseIn,
&MouseData->Data, sizeof(MouseData->Data));
if (Result < RTU_SUCCESS) // did someone close my pipe?
break;
// wait until data comes in
Result = RTUIOWait(MouseData->MouseIn, NULL);
if (Result == RTU_CANCELED) // the pipe was closed,
break; // terminate this thread
if (Result < RTU_SUCCESS) // other error?
printf("Error in MouseThread: %s\n", RTUErrorMessage(Result));
else
ProcessMouseEvent(&MouseData->Data);
}
// cleanup
delete MouseData;
// thread now terminates
}
/*-----------------------------------*/
void RTTAPI USBMouseEvent(RTUDeviceHandle Device, RTUSBEvent Event)
// attach/detach event callback
{
DriverDataType * MouseData;
switch (Event)
{
case RTUConnect:
{
const RTUConfigurationDescriptor * C;
// look for a suitable interface
const RTUInterfaceDescriptor * I =
RTUFindInterface(Device, RTU_USB_CLASS_HID,
SUBCLASS_BOOTDEVICE, PROT_MOUSE, 0, &C);
// and endpoint
const RTUEndpointDescriptor * E =
RTUFindEndpoint(I, RTUInterrupt, RTUInput);
// ignore if this is not a mouse
if (I == NULL || E == NULL)
return;
// grab it. This will fail if someone else grabbed it
if (RTUClaimInterface(Device, C, I, USBMouseEvent) < RTU_SUCCESS)
return;
// allocate data for the device
MouseData = new DriverDataType;
memset(MouseData, 0, sizeof(DriverDataType));
// open the required pipe
MouseData->MouseIn = RTUOpenPipe(Device, E, 1);
// this is optional, but convenient as we can query this data
// in the RTUDisconnect event
RTUSetClientData(Device, USBMouseEvent, MouseData);
// create a thread and pass it the device data
RTKRTLCreateThread(MouseThread, 0, 0, 0, MouseData, "Mouse Thread");
printf("new mouse!\n");
break;
}
case RTUDisconnect:
// did we attach some data to this device?
MouseData = (DriverDataType*) RTUGetClientData(Device, USBMouseEvent);
if (MouseData)
{
// close the pipe. This will cause I/O on this pipe to fail
RTUClosePipe(MouseData->MouseIn);
printf("mouse removed!\n");
}
break;
}
}
/*-----------------------------------*/
int main(void)
{
RTURegisterCallback(USBMouseEvent); // install our USB client
printf("Found %i USB host controllers\n", FindUSBControllers());
printf("Connect a USB mouse to the USB.\n");
printf("hit return to terminate...\n");
getc(stdin);
return 0;
}
|