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"
	  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	  isusb3;	  /* this is a usb3 device */
		  int	  depth;	  /* hub depth for usb3	hubs */
		  int	  maxpkt;	  /* cached from usb description */
		  Usbdev* usb;		  /* USB description */
		  Ep*	  ep;		  /* endpoint from epopen() */
		  void*	  aux;		  /* for the device driver */
		  char*	  hname;	  /* hash name,	unique for device */
	  };
	  struct Usbdev	{
		  int	  ver;		  /* usb version */
		  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	  vsid;
		  int	  psid;
		  int	  ssid;
		  int	  class;	  /* from descriptor */
		  int	  nconf;	  /* from descriptor */
		  Conf*	  conf[Nconf];	  /* configurations */
		  Ep*	  ep[Epmax+1];	  /* all endpoints in device (chained),	indexed	by address */
		  Desc*	  ddesc[Nddesc];  /* (raw) device specific descriptors */
	  };
	  struct Ep {
		  Iface*  iface;	  /* the endpoint belongs to */
		  Conf*	  conf;		  /* the endpoint belongs to */

		  int	  id;		  /* endpoint number: (id & Epmax) == endpoint address */
		  uchar	  dir;		  /* direction,	Ein/Eout/Eboth */
		  uchar	  type;		  /* Econtrol, Eiso, Ebulk, Eintr */

		  int	  attrib;
		  int	  pollival;
		  int	  maxpkt;	  /* max. packet size */
		  int	  ntds;		  /* nb. of Tds	per µframe */

		  /* chain of endpoints	with same address (used	in different interfaces/altsettings) */
		  Ep*	  next;

		  void*	  aux;		  /* for the driver program */
	  };
	  struct Iface {
		  int	  id;		  /* interface number */
		  int	  alt;		  /* altsetting	for this interface */
		  ulong	  csp;		  /* USB class/subclass/proto */
		  Iface*  next;		  /* chain of interfaces of different altsettings */
		  Ep*	  ep[Nep];	  /* consecutive array of endpoints in this interface (not including ep0) */

		  void*	  aux;		  /* for the driver program */
	  };
	  struct Conf {
		  int	  cval;		  /* value for set configuration */
		  int	  attrib;
		  int	  milliamps;	  /* maximum power in this config. */
		  Iface*  iface[Niface];  /* up	to 16 interfaces */
	  };
	  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. */
		  DDesc	  data;		  /* unparsed standard USB descriptor */
	  };
	  struct DDesc {
		  uchar	  bLength;
		  uchar	  bDescriptorType;
		  uchar	  bbytes[1];
		  /* extra bytes allocated here	to keep	the rest of it */
	  };
	  #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
	  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);
	  int	  opendevdata(Dev *d, int mode);
	  Dev*	  openep(Dev *d, Ep *e);
	  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);
	  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.

	  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.	The endpoint
	  number identifies devusb endpoint and	is unique within a
	  device.  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.

	  The field ep holds the endpoint structure that was passed in
	  epopen which gives easy access to the	endpoint configura-
	  tion.

	  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.

	  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 cal-
	  ling 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
	  similar to read and write arguments.	However, data may be
	  nil if no transfer (other than the control request) has to
	  take place.  The library header file includes	numerous sym-
	  bols defined to help writing the type	and arguments for a
	  request.

	  The return value from	usbcmd is the number of	bytes
	  transferred, 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.



/plan9/man/2/