2013-05-18 03:53:28 +04:00
|
|
|
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
|
2013-05-30 18:00:40 +04:00
|
|
|
the kernel code and looks as follows: 3 = usbhid.obj, 7 = usbprint.obj,
|
|
|
|
8 = usbstor.obj, 9 is handled by the kernel itself, other = usbother.obj.
|
2013-05-18 03:53:28 +04:00
|
|
|
|
|
|
|
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
|
|
|
|
);
|
|
|
|
|
2013-05-30 18:00:40 +04:00
|
|
|
The parameter 'pipe0' is a handle of the control pipe for endpoint zero
|
2013-05-18 03:53:28 +04:00
|
|
|
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
|
2013-07-02 01:35:01 +04:00
|
|
|
data allocated with Kmalloc, or index in some internal table.
|
2013-05-18 03:53:28 +04:00
|
|
|
|
|
|
|
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.
|
2013-05-30 18:00:40 +04:00
|
|
|
The output handle becomes invalid when a) it is explicitly closed with
|
|
|
|
the following function or b) the function DeviceDisconnected provided
|
|
|
|
by the driver returns.
|
|
|
|
|
|
|
|
void __stdcall USBClosePipe(
|
|
|
|
void* pipe
|
|
|
|
);
|
|
|
|
|
|
|
|
Releases all resources associated with the given pipe. The only parameter
|
|
|
|
must be a handle returned by USBOpenPipe.
|
|
|
|
When a device is disconnected, all associated pipes are closed by the kernel;
|
|
|
|
there is no need to ever call this function if all pipes are used continuously
|
|
|
|
while a device is connected.
|
2013-05-18 03:53:28 +04:00
|
|
|
|
|
|
|
void* __stdcall USBNormalTransferAsync(
|
|
|
|
void* pipe,
|
|
|
|
void* buffer,
|
|
|
|
int size,
|
|
|
|
void* callback,
|
|
|
|
void* calldata,
|
|
|
|
int flags
|
|
|
|
);
|
|
|
|
void* __stdcall USBControlTransferAsync(
|
|
|
|
void* pipe,
|
2013-05-30 18:00:40 +04:00
|
|
|
void* setup,
|
2013-05-18 03:53:28 +04:00
|
|
|
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
|
2013-05-30 18:00:40 +04:00
|
|
|
is concluded from 'setup' packet, bit 7 of byte 0 is set for IN transfers
|
2013-05-18 03:53:28 +04:00
|
|
|
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.
|
2013-05-30 18:00:40 +04:00
|
|
|
The parameter 'setup' of USBControlTransferAsync points to 8-byte
|
2013-05-18 03:53:28 +04:00
|
|
|
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.
|
2013-07-02 01:35:01 +04:00
|
|
|
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
|
|
|
|
USB_STATUS_BUFUNDERRUN = 13 ; underflow of internal controller buffer
|
|
|
|
USB_STATUS_CLOSED = 16 ; pipe closed, either explicitly with USBClosePipe
|
|
|
|
; or due to device disconnect
|
2014-01-29 16:14:28 +04:00
|
|
|
USB_STATUS_CANCELLED = 17 ; transfer cancelled with USBAbortPipe
|
2013-05-18 03:53:28 +04:00
|
|
|
|
|
|
|
If several transfers are queued for the same pipe, their callback functions
|
|
|
|
are called in the same order as they were queued.
|
2013-05-30 18:00:40 +04:00
|
|
|
When a pipe is closed, either explicitly with USBClosePipe, or
|
|
|
|
implicitly due to device disconnect, all callback functions are called
|
|
|
|
with USB_STATUS_CLOSED. The call to DeviceDisconnected() occurs after
|
2013-05-18 03:53:28 +04:00
|
|
|
all callbacks.
|
2013-07-02 01:35:01 +04:00
|
|
|
|
2014-01-29 16:14:28 +04:00
|
|
|
void __stdcall USBAbortPipe(void* pipe);
|
|
|
|
Initiates cancellation of all active transfers for the given pipe. Asynchronous.
|
|
|
|
When a transfer will be cancelled, the associated callback function
|
|
|
|
will be called with USB_STATUS_CANCELLED.
|
|
|
|
|
2013-07-02 01:35:01 +04:00
|
|
|
void* __stdcall USBGetParam(void* pipe0, int param);
|
|
|
|
Returns miscellaneous parameters of the device.
|
|
|
|
pipe0 is the pointer to the config pipe.
|
|
|
|
param = 0: return pointer to device descriptor
|
|
|
|
param = 1: return pointer to config descriptor, same as passed to AddDevice
|
|
|
|
param = 2: return speed at which the device is operating, one of
|
|
|
|
USB_SPEED_FS = 0 ; full-speed
|
|
|
|
USB_SPEED_LS = 1 ; low-speed
|
|
|
|
USB_SPEED_HS = 2 ; high-speed
|