Home |
Attachment/Detachment Callbacks Structure of a Passive USB Client Structure of an Active USB Client |
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; } Structure of a Passive USB Client
|