glenda.party
term% ls -F
term% pwd
$home/manuals/9front/2/nusb
term% cat index.txt
NUSB(2)                       System Calls Manual                      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     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 */
       };
       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 */
       };
       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 */
       };
       struct Altc {
               int     attrib;
               int     interval;
               void*   aux;            /* for the driver program */
       };
       struct Iface {
               int     id;             /* interface number */
               ulong   csp;            /* USB class/subclass/proto */
               Altc*   altc[Naltc];
               Ep*     ep[Nep];
               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. */
               Altc*   altc;           /* last alt.c. 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, 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);
       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 de‐
       vices.  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  end‐
       point.   The rest of the work is up to the driver and is where this li‐
       brary may help.

       An endpoint as provided by usb(3) is represented by a Dev  data  struc‐
       ture.   The  setup endpoint for a device represents the USB device, be‐
       cause it is the means to configure and operate the device.  This struc‐
       ture  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 end‐
       point 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 descriptors, respec‐
       tively.  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 information.

       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
       Opendev creates a Dev for the endpoint with directory fn.  Usually, the
       endpoint  is  a setup endpoint representing a device. The endpoint con‐
       trol file is open, but the data file is not.  The  USB  description  is
       void.   In most cases drivers call startdevs 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 calling it, the device is
       ready for I/O and the USB description in Dev.usb is valid.

       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 control 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 performed  by  reading/writing  the
       descriptor kept in the dfd field of Dev.

       For  control  endpoints, it is not necessary to call read and write di‐
       rectly.  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  symbols  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, representing a CSP.
       Subclass does the same for the device subclass and Proto for the proto‐
       col.  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 rep‐
       resenting 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 de‐
       scriptor number sid.

SOURCE
       /sys/src/cmd/nusb/lib

SEE ALSO
       usb(3), nusb(4).

BUGS
       Not heavily exercised yet.



                                                                       NUSB(2)