0,0 → 1,183 |
When the kernel detects a connected USB device, it configures the device in |
terms of USB protocol - SET_ADDRESS + SET_CONFIGURATION, the first |
configuration is always selected. The kernel also reads device descriptor to |
print some information, reads and parses configuration descriptor. For every |
interface the kernel looks for class code of this interface and loads the |
corresponding COFF driver. Currently the correspondence is hardcoded into |
the kernel code and looks as follows: 3 = usbhid.obj, 8 = usbstor.obj, |
9 is handled by the kernel itself, other = usbother.obj. |
|
The driver must be standard driver in COFF format, exporting procedure |
named "START" and a variable named "version". Loader calls "START" procedure |
as stdcall with one parameter DRV_ENTRY = 1; if initialization is successful, |
the "START" procedure is also called by shutdown code with one parameter |
DRV_EXIT = -1. |
|
The driver must register itself as a USB driver in "START" procedure. |
This is done by call to exported function RegUSBDriver and passing the returned |
value as result of "START" procedure. |
|
void* __stdcall RegUSBDriver( |
const char* name, |
void* handler, |
const USBFUNC* usbfunc |
); |
|
The parameter 'name' should match the name of driver, "usbhid" for usbhid.obj. |
The parameter 'handler' is optional; if it is non-NULL, it should point to |
the standard handler for IOCTL interface as in non-USB drivers. |
The parameter 'usbfunc' is a pointer to the following structure: |
|
struc USBFUNC |
{ |
.strucsize dd ? ; size of the structure, including this field |
.add_device dd ? ; pointer to AddDevice function in the driver |
; required |
.device_disconnect dd ? ; pointer to DeviceDisconnected function in the driver |
; optional, may be NULL |
; other functions may be added in the future |
} |
|
The driver should implement the function |
|
void* __stdcall AddDevice( |
void* pipe0, |
void* configdescr, |
void* interfacedescr |
); |
|
The parameter 'controlpipe' is a handle of the control pipe for endpoint zero |
of the device. It can be used as the argument of USBControlTransferAsync. |
The parameter 'configdescr' points to USB configuration descriptor |
and all associated data, as returned by GET_DESCRIPTOR request. |
The total length of all associated data is contained in the configuration |
descriptor. |
The parameter 'interfacedescr' points to USB interface descriptor corresponding |
to the interface which is initializing. This is a pointer inside data |
associated with the configuration descriptor. |
Note that one device can implement many interfaces, so AddDevice may be |
called several times with the same 'configdescr' and different 'interfacedescr'. |
The returned value NULL means that the initialization has failed. |
Any other value means that configuration was successful; the kernel does not |
try to interpret the value. It can be, for example, pointer to the internal |
data allocated with Kmalloc, or index in some internal table. Remember that |
Kmalloc() is NOT stdcall, it destroys ebx. |
|
The driver can implement the function |
|
void __stdcall DeviceDisconnected( |
void* devicedata |
); |
|
If this function is implemented, the kernel calls it when the device is |
disconnected, passing the returned value of AddDevice as 'devicedata'. |
|
The driver can use the following functions exported by the kernel. |
|
void* __stdcall USBOpenPipe( |
void* pipe0, |
int endpoint, |
int maxpacketsize, |
int type, |
int interval |
); |
|
The parameter 'pipe0' is a handle of the pipe for endpoint zero for |
the device, as passed to AddDevice. It is used to identify the device. |
The parameter 'endpoint' is endpoint number as defined by USB. Lower |
4 bits form the number itself, bit 7 - highest bit of low byte - |
is 0/1 for OUT/IN endpoints, other bits should be zero. |
The parameter 'maxpacketsize' sets the maximum packet size for this pipe. |
The parameter 'type' selects the type of the endpoint as defined by USB: |
0 = control, 1 = isochronous (not supported yet), 2 = bulk, 3 = interrupt. |
The parameter 'interval' is ignored for control and bulk endpoints. |
For interrupt endpoints, it sets the polling interval in milliseconds. |
The function returns a handle to the pipe or NULL on failure. |
|
void* __stdcall USBNormalTransferAsync( |
void* pipe, |
void* buffer, |
int size, |
void* callback, |
void* calldata, |
int flags |
); |
void* __stdcall USBControlTransferAsync( |
void* pipe, |
void* config, |
void* buffer, |
int size, |
void* callback, |
void* calldata, |
int flags |
); |
|
The first function inserts a bulk or interrupt transfer to the transfer queue |
for given pipe. Type and direction of transfer are fixed for bulk and interrupt |
endpoints and are set in USBOpenPipe. The second function inserts a control |
transfer to the transfer queue for given pipe. Direction of a control transfer |
is concluded from 'config' packet, bit 7 of byte 0 is set for IN transfers |
and cleared for OUT transfers. These function return immediately; when data |
are transferred, the callback function will be called. |
|
The parameter 'pipe' is a handle returned by USBOpenPipe. |
The parameter 'config' of USBControlTransferAsync points to 8-byte |
configuration packet as defined by USB. |
The parameter 'buffer' is a pointer to buffer. For IN transfers, it will be |
filled with the data. For OUT transfers, it should contain data to be |
transferred. It can be NULL for an empty transfer or if no additional data are |
required for a control transfer. |
The parameter 'size' is size of data to transfer. It can be 0 for an empty |
transfer or if no additional data are required for a control transfer. |
The parameter 'callback' is a pointer to a function which will be called |
when the transfer will be done. |
The parameter 'calldata' will be passed as is to the callback function. |
For example, it can be NULL, it can be a pointer to device data or it can be |
a pointer to data used to pass additional parameters between caller and |
callback. The transfer-specific data can also be associated with 'buffer', |
preceding (negative offsets from 'buffer') or following (offsets more than |
or equal to 'size') the buffer itself. |
The parameter 'flags' is the bitmask. |
The bit 0 is ignored for OUT transfers, for IN transfers it controls whether |
the device can transfer less data than 'size' bytes. If the bit is 0, a small |
transfer is an error; if the bit is 1, a small transfer is OK. |
All other bits are reserved and should be zero. |
The returned value is NULL if an error occured and non-NULL if the transfer |
was successfully queued. If an error will occur later, the callback function |
will be notified. |
|
void __stdcall CallbackFunction( |
void* pipe, |
int status, |
void* buffer, |
int length, |
void* calldata |
); |
|
The parameters 'pipe', 'buffer', 'calldata' are the same as for the |
corresponding USB*TransferAsync. |
The parameter 'length' is the number of bytes transferred. For |
control transfers, this includes 8 bytes from SETUP stage, so |
0 means that SETUP stage failed and 'size'+8 means full transfer. |
The parameter 'status' is nonzero if an error occured. |
USB_STATUS_OK = 0 ; no error |
USB_STATUS_CRC = 1 ; CRC error |
USB_STATUS_BITSTUFF = 2 ; bit stuffing violation |
USB_STATUS_TOGGLE = 3 ; data toggle mismatch |
USB_STATUS_STALL = 4 ; device returned STALL |
USB_STATUS_NORESPONSE = 5 ; device not responding |
USB_STATUS_PIDCHECK = 6 ; invalid PID check bits |
USB_STATUS_WRONGPID = 7 ; unexpected PID value |
USB_STATUS_OVERRUN = 8 ; too many data from endpoint |
USB_STATUS_UNDERRUN = 9 ; too few data from endpoint |
USB_STATUS_BUFOVERRUN = 12 ; overflow of internal controller buffer |
; possible only for isochronous transfers |
USB_STATUS_BUFUNDERRUN = 13 ; underflow of internal controller buffer |
; possible only for isochronous transfers |
USB_STATUS_DISCONNECTED = 16 ; device disconnected |
|
If several transfers are queued for the same pipe, their callback functions |
are called in the same order as they were queued. |
When the device is disconnected, all callback functions are called |
with USB_STATUS_DISCONNECTED. The call to DeviceDisconnected() occurs after |
all callbacks. |