plan9fox/sys/src/9/port/usb.h
cinap_lenrek 41908149de nusb: resolve endpoint id conflict with different input and output types
ftrvxmtrx repots devices that use the endpoint number for
input and output of different types like:

 nusb/ether:             parsedesc endpoint 5[7]  07 05 81 03 08 00 09	# ep1 in intr
 nusb/ether:             parsedesc endpoint 5[7]  07 05 82 02 00 02 00
 nusb/ether:             parsedesc endpoint 5[7]  07 05 01 02 00 02 00	# ep1 out bulk

the previous change tried to work arround this but had the
concequence that only the lastly defined endpoint was
usable.

this change addresses the issue by allowing up to 32 endpoints
per device (16 output + 16 input endpoints) in devusb. the
hci driver will ignore the 4th bit and will only use the
lower 4 bits as endpoint address when talking to the usb
device.

when we encounter a conflict, we map the input endpoint
to the upper id range 16..31 and the output endpoint
to id 0..15 so two distinct endpoints are created.
2014-04-23 20:03:01 +02:00

198 lines
6.1 KiB
C

/*
* 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 = 32, /* max nb. of endpoints per device (16 in + 16 out) */
/* tunable parameters */
Nhcis = 16, /* max nb. of HCIs */
Neps = 64, /* 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) */
int sampledelay; /* maximum delay introduced by buffering (iso) */
};
/*
* 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 Estalled[];
extern char *seprintdata(char*,char*,uchar*,int);