NUSB(2) NUSB(2)
NAME
usbcmd, classname, closedev, configdev, devctl, getdev,
loaddevstr, opendev, opendevdata, openep, unstall - USB
device driver library
SYNOPSIS
#include <u.h>
#include <libc.h>
#include "../lib/usb.h"
9 struct Dev {
Ref;
char* dir; /* path for the endpoint dir */
int id; /* usb id for device or ep. number */
int dfd; /* descriptor for the data file */
int cfd; /* descriptor for the control file */
int maxpkt; /* cached from usb description */
Usbdev* usb; /* USB description */
void* aux; /* for the device driver */
void (*free)(void*); /* idem. to release aux */
char* hname; /* hash name, unique for device */
};
9 struct Usbdev {
ulong csp; /* USB class/subclass/proto */
int vid; /* vendor id */
int did; /* product (device) id */
int dno; /* device release number */
char* vendor;
char* product;
char* serial;
int ls; /* low speed */
int class; /* from descriptor */
int nconf; /* from descriptor */
Conf* conf[Nconf]; /* configurations */
Ep* ep[Nep]; /* all endpoints in device */
Desc* ddesc[Nddesc]; /* (raw) device specific descriptors */
};
9 struct Ep {
uchar addr; /* endpt address */
uchar dir; /* direction, Ein/Eout */
uchar type; /* Econtrol, Eiso, Ebulk, Eintr */
uchar isotype; /* Eunknown, Easync, Eadapt, Esync */
int id;
int maxpkt; /* max. packet size */
Conf* conf; /* the endpoint belongs to */
Iface* iface; /* the endpoint belongs to */
};
9 struct Altc {
int attrib;
Page 1 Plan 9 (printed 10/25/25)
NUSB(2) NUSB(2)
int interval;
void* aux; /* for the driver program */
};
9 struct Iface {
int id; /* interface number */
ulong csp; /* USB class/subclass/proto */
Altc* altc[Naltc];
Ep* ep[Nep];
void* aux; /* for the driver program */
};
9 struct Conf {
int cval; /* value for set configuration */
int attrib;
int milliamps; /* maximum power in this config. */
Iface* iface[Niface]; /* up to 16 interfaces */
};
9 struct Desc {
Conf* conf; /* where this descriptor was read */
Iface* iface; /* last iface before desc in conf. */
Ep* ep; /* last endpt before desc in conf. */
Altc* altc; /* last alt.c. before desc in conf. */
DDesc data; /* unparsed standard USB descriptor */
};
9 struct DDesc {
uchar bLength;
uchar bDescriptorType;
uchar bbytes[1];
/* extra bytes allocated here to keep the rest of it */
};
9 #define Class(csp) ((csp)&0xff)
#define Subclass(csp) (((csp)>>8)&0xff)
#define Proto(csp) (((csp)>>16)&0xff)
#define CSP(c, s, p) ((c) | ((s)<<8) | ((p)<<16))
#define GET2(p) ...
#define PUT2(p,v) ...
#define GET4(p) ...
#define PUT4(p,v) ...
#define dprint if(usbdebug)fprint
#define ddprint if(usbdebug > 1)fprint
9 int Ufmt(Fmt *f);
char* classname(int c);
void closedev(Dev *d);
int configdev(Dev *d);
int devctl(Dev *dev, char *fmt, ...);
void* emallocz(ulong size, int zero);
char* estrdup(char *s);
char* hexstr(void *a, int n);
char* loaddevstr(Dev *d, int sid);
Dev* opendev(char *fn);
Page 2 Plan 9 (printed 10/25/25)
NUSB(2) NUSB(2)
int opendevdata(Dev *d, int mode);
Dev* openep(Dev *d, int id);
int unstall(Dev *dev, Dev *ep, int dir);
int usbcmd(Dev *d, int type, int req,
int value, int index, uchar *data, int count);
Dev* getdev(char *devid);
9 extern int usbdebug; /* more messages for bigger values */
DESCRIPTION
This library provides convenience structures and functions
to write USB device drivers. It is not intended for user
programs using USB devices. See usb(3) for a description of
the interfaces provided for that purpose.
Usb drivers rely on usb(3) to perform I/O through USB as
well as on usbd to perform the initial configuration for the
device's setup endpoint. The rest of the work is up to the
driver and is where this library may help.
An endpoint as provided by usb(3) is represented by a Dev
data structure. The setup endpoint for a device represents
the USB device, because it is the means to configure and
operate the device. This structure is reference counted.
Functions creating Devs adjust the number of references to
one, initially. The driver is free to call incref (in
lock(2)) to add references and closedev to drop references
(and release resources when the last one vanishes). As an
aid to the driver, the field aux may keep driver-specific
data and the function free will be called (if not null) to
release the aux structure when the reference count goes down
to zero.
Dev.dir holds the path for the endpoint's directory.
The field id keeps the device number for setup endpoints and
the endpoint number for all other endpoints. For example,
it would be 3 for /dev/usb/ep3.0 and 1 for /dev/usb/ep3.1.
It is easy to remember this because the former is created to
operate on the device, while the later has been created as a
particular endpoint to perform I/O.
Fields dfd and cfd keep the data and control file descrip-
tors, respectively. When a Dev is created the control file
is open, initially. Opening the data file requires calling
opendevdata with the appropriate mode.
When the device configuration information has been loaded
(see below), maxpkt holds the maximum packet size (in bytes)
for the endpoint and usb keeps the rest of the USB informa-
tion.
9
Page 3 Plan 9 (printed 10/25/25)
NUSB(2) NUSB(2)
Most of the information in usb comes from parsing various
device and configuration descriptors provided by the device,
by calling one of the functions described later. Only
descriptors unknown to the library are kept unparsed at
usb.ddesc as an aid for the driver (which should know how to
parse them and what to do with the information).
Configuration
Getdev is the primary entry point for device setup. It takes
a numeric device address or device path which usually gets
passed to drivers as a program argument and sets up the
device, retuning a configured Dev representing the setup
endpoint of the device.
Opendev creates a Dev for the endpoint with directory fn.
Usually, the endpoint is a setup endpoint representing a
device. The endpoint control file is open, but the data file
is not. The USB description is void. In most cases drivers
call getdev and openep and do not call this function
directly.
Configdev opens the data file for the device supplied and
loads and parses its configuration information. After call-
ing it, the device is ready for I/O and the USB description
in Dev.usb is valid. In most cases drivers call getdev and
do not call this function directly.
Control requests for an endpoint may be written by calling
devctl in the style of print(2). It is better not to call
print directly because the control request should be issued
as a single write system call. See usb(3) for a list of
available control requests (not to be confused with USB con-
trol transfers performed on a control endpoint).
Input/Output
Opendevdata opens the data file for the device according to
the given mode. The mode must match that of the endpoint,
doing otherwise is considered an error. Actual I/O is per-
formed by reading/writing the descriptor kept in the dfd
field of Dev.
For control endpoints, it is not necessary to call read and
write directly. Instead, usbcmd issues a USB control
request to the device d (not to be confused with a usb(3)
control request sent to its control file). Usbcmd retries
the control request several times upon failure because some
devices require it. The format of requests is fixed per the
USB standard: type is the type of request and req identifies
the request. Arguments value and index are parameters to the
request and the last two arguments, data and count, are sim-
ilar to read and write arguments. However, data may be nil
if no transfer (other than the control request) has to take
Page 4 Plan 9 (printed 10/25/25)
NUSB(2) NUSB(2)
place. The library header file includes numerous symbols
defined to help writing the type and arguments for a
request.
The return value from usbcmd is the number of bytes trans-
ferred, zero to indicate a stall and -1 to indicate an
error.
A common request is to unstall an endpoint that has been
stalled due to some reason by the device (eg., when read or
write indicate a count of zero bytes read or written on the
endpoint). The function unstall does this. It is given the
device that stalled the endpoint, dev, the stalled endpoint,
ep, and the direction of the stall (one of Ein or Eout).
The function takes care of notifying the device of the
unstall as well as notifying the kernel.
Tools
Class returns the class part of the number given, represent-
ing a CSP. Subclass does the same for the device subclass
and Proto for the protocol. The counterpart is CSP, which
builds a CSP from the device class, subclass, and protocol.
For some classes, classname knows the name (for those with
constants in the library header file).
The macros GET2 and PUT2 get and put a (little-endian) two-
byte value and are useful to parse descriptors and replies
for control requests.
Functions emallocz and estrdup are similar to mallocz and
strdup but abort program operation upon failure.
The function Ufmt is a format routine suitable for
fmtinstall(2) to print a Dev data structure. The auxiliary
hexstr returns a string representing a dump (in hexadecimal)
of n bytes starting at a. The string is allocated using
malloc(2) and memory must be released by the caller.
Loaddevstr returns the string obtained by reading the device
string descriptor number sid.
SOURCE
/sys/src/cmd/nusb/lib
SEE ALSO
usb(3), nusb(4).
BUGS
Not heavily exercised yet.
Page 5 Plan 9 (printed 10/25/25)