Subversion Repositories planix.SVN

Rev

Blame | Last modification | View Log | RSS feed

/*
 * common USB definitions.
 */
#define dprint          if(debug)print
#define ddprint         if(debug>1)print
#define deprint         if(debug || ep->debug)print
#define ddeprint        if(debug>1 || ep->debug>1)print

#define GET2(p)         ((((p)[1]&0xFF)<<8)|((p)[0]&0xFF))
#define PUT2(p,v)       {((p)[0] = (v)); ((p)[1] = (v)>>8);}

typedef struct Udev Udev;       /* USB device */
typedef struct Ep Ep;           /* Endpoint */
typedef struct Hci Hci;         /* Host Controller Interface */
typedef struct Hciimpl Hciimpl; /* Link to the controller impl. */

enum
{
        /* fundamental constants */
        Ndeveps = 16,           /* max nb. of endpoints per device */

        /* tunable parameters */
        Nhcis   = 16,           /* max nb. of HCIs */
        Neps    = 128,          /* max nb. of endpoints */
        Maxctllen = 32*1024, /* max allowed sized for ctl. xfers; see Maxdevconf */
        Xfertmout = 2000,       /* default request time out (ms) */

        /* transfer types. keep this order */
        Tnone = 0,              /* no tranfer type configured */
        Tctl,                   /* wr req + rd/wr data + wr/rd sts */
        Tiso,                   /* stream rd or wr (real time) */
        Tbulk,                  /* stream rd or wr */
        Tintr,                  /* msg rd or wr */
        Nttypes,                /* number of transfer types */

        Epmax   = 0xF,          /* max ep. addr */
        Devmax  = 0x7F,         /* max dev. addr */

        /* Speeds */
        Fullspeed = 0,
        Lowspeed,
        Highspeed,
        Nospeed,

        /* request type */
        Rh2d = 0<<7,
        Rd2h = 1<<7,
        Rstd = 0<<5,
        Rclass =  1<<5,
        Rdev = 0,
        Rep = 2,
        Rother = 3,

        /* req offsets */
        Rtype   = 0,
        Rreq    = 1,
        Rvalue  = 2,
        Rindex  = 4,
        Rcount  = 6,
        Rsetuplen = 8,

        /* standard requests */
        Rgetstatus      = 0,
        Rclearfeature   = 1,
        Rsetfeature     = 3,
        Rsetaddr        = 5,
        Rgetdesc        = 6,

        /* device states */
        Dconfig  = 0,           /* configuration in progress */
        Denabled,               /* address assigned */
        Ddetach,                /* device is detached */
        Dreset,                 /* its port is being reset */

        /* (root) Hub reply to port status (reported to usbd) */
        HPpresent       = 0x1,
        HPenable        = 0x2,
        HPsuspend       = 0x4,
        HPovercurrent   = 0x8,
        HPreset         = 0x10,
        HPpower         = 0x100,
        HPslow          = 0x200,
        HPhigh          = 0x400,
        HPstatuschg     = 0x10000,
        HPchange        = 0x20000,
};

/*
 * Services provided by the driver.
 * epopen allocates hardware structures to prepare the endpoint
 * for I/O. This happens when the user opens the data file.
 * epclose releases them. This happens when the data file is closed.
 * epwrite tries to write the given bytes, waiting until all of them
 * have been written (or failed) before returning; but not for Iso.
 * epread does the same for reading.
 * It can be assumed that endpoints are DMEXCL but concurrent
 * read/writes may be issued and the controller must take care.
 * For control endpoints, device-to-host requests must be followed by
 * a read of the expected length if needed.
 * The port requests are called when usbd issues commands for root
 * hubs. Port status must return bits as a hub request would do.
 * Toggle handling and other details are left for the controller driver
 * to avoid mixing too much the controller and the comon device.
 * While an endpoint is closed, its toggles are saved in the Ep struct.
 */
struct Hciimpl
{
        void    *aux;                           /* for controller info */
        void    (*init)(Hci*);                  /* init. controller */
        void    (*dump)(Hci*);                  /* debug */
        void    (*interrupt)(Ureg*, void*);     /* service interrupt */
        void    (*epopen)(Ep*);                 /* prepare ep. for I/O */
        void    (*epclose)(Ep*);                /* terminate I/O on ep. */
        long    (*epread)(Ep*,void*,long);      /* transmit data for ep */
        long    (*epwrite)(Ep*,void*,long);     /* receive data for ep */
        char*   (*seprintep)(char*,char*,Ep*);  /* debug */
        int     (*portenable)(Hci*, int, int);  /* enable/disable port */
        int     (*portreset)(Hci*, int, int);   /* set/clear port reset */
        int     (*portstatus)(Hci*, int);       /* get port status */
        void    (*shutdown)(Hci*);              /* shutdown for reboot */
        void    (*debug)(Hci*, int);            /* set/clear debug flag */
};

struct Hci
{
        ISAConf;                                /* hardware info */
        int     tbdf;                           /* type+busno+devno+funcno */
        int     ctlrno;                         /* controller number */
        int     nports;                         /* number of ports in hub */
        int     highspeed;
        Hciimpl;                                        /* HCI driver  */
};

/*
 * USB endpoint.
 * All endpoints are kept in a global array. The first
 * block of fields is constant after endpoint creation.
 * The rest is configuration information given to all controllers.
 * The first endpoint for a device (known as ep0) represents the
 * device and is used to configure it and create other endpoints.
 * Its QLock also protects per-device data in dev.
 * See Hciimpl for clues regarding how this is used by controllers.
 */
struct Ep
{
        Ref;                    /* one per fid (and per dev ep for ep0s) */

        /* const once inited. */
        int     idx;            /* index in global eps array */
        int     nb;             /* endpoint number in device */
        Hci*    hp;             /* HCI it belongs to */
        Udev*   dev;            /* device for the endpoint */
        Ep*     ep0;            /* control endpoint for its device */

        QLock;                  /* protect fields below */
        char*   name;           /* for ep file names at #u/ */
        int     inuse;          /* endpoint is open */
        int     mode;           /* OREAD, OWRITE, or ORDWR */
        int     clrhalt;        /* true if halt was cleared on ep. */
        int     debug;          /* per endpoint debug flag */
        char*   info;           /* for humans to read */
        long    maxpkt;         /* maximum packet size */
        int     ttype;          /* tranfer type */
        ulong   load;           /* in µs, for a fransfer of maxpkt bytes */
        void*   aux;            /* for controller specific info */
        int     rhrepl;         /* fake root hub replies */
        int     toggle[2];      /* saved toggles (while ep is not in use) */
        long    pollival;               /* poll interval ([µ]frames; intr/iso) */
        long    hz;             /* poll frequency (iso) */
        long    samplesz;       /* sample size (iso) */
        int     ntds;           /* nb. of Tds per µframe */
        int     tmout;          /* 0 or timeout for transfers (ms) */
};

/*
 * Per-device configuration and cached list of endpoints.
 * eps[0]->QLock protects it.
 */
struct Udev
{
        int     nb;             /* USB device number */
        int     state;          /* state for the device */
        int     ishub;          /* hubs can allocate devices */
        int     isroot;         /* is a root hub */
        int     speed;          /* Full/Low/High/No -speed */
        int     hub;            /* dev number for the parent hub */
        int     port;           /* port number in the parent hub */
        Ep*     eps[Ndeveps];   /* end points for this device (cached) */
};

void    addhcitype(char *type, int (*reset)(Hci*));

extern char *usbmodename[];

extern char *seprintdata(char*,char*,uchar*,int);