glenda.party
term% ls -F
term% cat index.txt
USB(2)                        System Calls Manual                       USB(2)



NAME
       usbcmd,  classname,  closedev, configdev, devctl, finddevs, loaddevstr,
       matchdevcsp, opendev, opendevdata, openep, startdevs,  unstall,  class,
       subclass, proto, CSP - USB device driver library

SYNOPSIS
       #include <u.h>
       #include <libc.h>
       #include <thread.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 */
       };
       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);
       int     finddevs(int (*matchf)(char*,void*), void *farg, char** dirs, int ndirs);
       char*   hexstr(void *a, int n);
       char*   loaddevstr(Dev *d, int sid);
       int     matchdevcsp(char *info, void *a);
       Dev*    opendev(char *fn);
       int     opendevdata(Dev *d, int mode);
       Dev*    openep(Dev *d, int id);
       void    startdevs(char *args, char *argv[], int argc,
                       int (*mf)(char*,void*), void*ma, int (*df)(Dev*,int,char**));
       int     unstall(Dev *dev, Dev *ep, int dir);
       int     usbcmd(Dev *d, int type, int req,
                       int value, int index, uchar *data, int count);
       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.  For drivers that provide a file system and may be embed‐
       ded  into usbd, the library includes a file system implementation tool‐
       kit described in usbfs(2).

       Usb drivers rely on usb(3) to perform I/O through USB  as  well  as  on
       usbd(4)  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.

       In  most cases, a driver locates the devices of interest and configures
       them by calling startdevs and then  sets  up  additional  endpoints  as
       needed  (by calling openep) to finally perform I/O by reading and writ‐
       ing the data files for the endpoints.

       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,
       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 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
       Startdevs is a wrapper that locates devices of  interest,  loads  their
       configuration  information,  and  starts  a  thread(2)'s  proc for each
       device located so that it executes f as its main entry point. The entry
       point  is  called  with  a  pointer to the Dev for the device it has to
       process, argc, and argv.  Devices are located either from the arguments
       (after  options)  in argv, if any, or by calling the helper function mf
       with the argument ma to determine (for each device  available)  if  the
       device  belongs  to  the driver or not. If the function returns -1 then
       the device is not for us.

       In many cases, matchdevcsp may be supplied as mf  along  with  a  (null
       terminated) vector of CSP values supplied as ma.  This function returns
       0 for any device with a CSP matching one in the vector supplied  as  an
       argument and -1 otherwise.  In other cases (eg., when a particular ven‐
       dor and device ids are the ones identifying the device) the driver must
       include  its  own  function  and supply it as an argument to startdevs.
       The first argument of the function corresponds to the information known
       about the device (the second line in its ctl file).  Openep creates the
       endpoint number id for the device d and  returns  a  Dev  structure  to
       operate on it (with just the control file open).

       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.  When using
       startdevs it is not desirable to call this function (because  startdevs
       already calls it).

       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
       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 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
       descriptor number sid.

SOURCE
       /sys/src/cmd/usb/lib

SEE ALSO
       usbfs(2), usb(3), usb(4), usbd(4).

BUGS
       Not heavily exercised yet.



                                                                        USB(2)