/* * USB implementation for Plan 9 * (c) 1998, 1999 C H Forsyth */ enum { Dbginfo = 0x01, Dbgfs = 0x02, Dbgproc = 0x04, Dbgcontrol = 0x08, }; extern int debug, debugdebug, verbose; typedef uchar byte; #ifndef CHANNOP typedef struct Ref Ref; #define threadprint fprint #endif /* * USB definitions */ typedef struct DConfig DConfig; typedef struct DDevice DDevice; typedef struct DEndpoint DEndpoint; typedef struct DHid DHid; typedef struct DHub DHub; typedef struct DInterface DInterface; typedef struct Dconf Dconf; typedef struct Dalt Dalt; typedef struct Device Device; typedef struct Dinf Dinf; typedef struct Endpt Endpt; typedef struct Namelist Namelist; #define GET2(p) ((((p)[1]&0xFF)<<8)|((p)[0]&0xFF)) #define PUT2(p,v) {((p)[0] = (v)); ((p)[1] = (v)>>8);} enum { /* request type */ RH2D = 0<<7, RD2H = 1<<7, Rstandard = 0<<5, /* types */ Rclass = 1<<5, Rvendor = 2<<5, Rdevice = 0, /* recipients */ Rinterface = 1, Rendpt = 2, Rother = 3, /* standard requests */ GET_STATUS = 0, CLEAR_FEATURE = 1, SET_FEATURE = 3, SET_ADDRESS = 5, GET_DESCRIPTOR = 6, SET_DESCRIPTOR = 7, GET_CONFIGURATION = 8, SET_CONFIGURATION = 9, GET_INTERFACE = 10, SET_INTERFACE = 11, SYNCH_FRAME = 12, GET_CUR = 0x81, GET_MIN = 0x82, GET_MAX = 0x83, GET_RES = 0x84, SET_CUR = 0x01, SET_MIN = 0x02, SET_MAX = 0x03, SET_RES = 0x04, /* hub class feature selectors */ C_HUB_LOCAL_POWER = 0, C_HUB_OVER_CURRENT, PORT_CONNECTION = 0, PORT_ENABLE = 1, PORT_SUSPEND = 2, PORT_OVER_CURRENT = 3, PORT_RESET = 4, PORT_POWER = 8, PORT_LOW_SPEED = 9, C_PORT_CONNECTION = 16, C_PORT_ENABLE, C_PORT_SUSPEND, C_PORT_OVER_CURRENT, C_PORT_RESET, /* descriptor types */ DEVICE = 1, CONFIGURATION = 2, STRING = 3, INTERFACE = 4, ENDPOINT = 5, HID = 0x21, REPORT = 0x22, PHYSICAL = 0x23, HUB = 0x29, /* feature selectors */ DEVICE_REMOTE_WAKEUP = 1, ENDPOINT_STALL = 0, /* report types */ Tmtype = 3<<2, Tmitem = 0xF0, Tmain = 0<<2, Tinput = 0x80, Toutput = 0x90, Tfeature = 0xB0, Tcoll = 0xA0, Tecoll = 0xC0, Tglobal = 1<<2, Tusagepage = 0x00, Tlmin = 0x10, Tlmax = 0x20, Tpmin = 0x30, Tpmax = 0x40, Tunitexp = 0x50, Tunit = 0x60, Trepsize = 0x70, TrepID = 0x80, Trepcount = 0x90, Tpush = 0xA0, Tpop = 0xB0, Tlocal = 2<<2, Tusage = 0x00, Tumin = 0x10, Tumax = 0x20, Tdindex = 0x30, Tdmin = 0x40, Tdmax = 0x50, Tsindex = 0x70, Tsmin = 0x80, Tsmax = 0x90, Tsetdelim = 0xA0, Treserved = 3<<2, Tlong = 0xFE, /* parameters */ Nendpt = 16, /* device state */ Detached = 0, Attached, Enabled, Assigned, Configured, /* classes */ Noclass = 0, Hubclass, Otherclass, /* endpoint direction */ Ein = 0, Eout, Eboth, /* endpoint type */ Econtrol = 0, Eiso = 1, Ebulk = 2, Eintr = 3, /* endpoint isotype */ Eunknown = 0, Easync = 1, Eadapt = 2, Esync = 3, }; enum { CL_AUDIO = 1, CL_COMMS = 2, CL_HID = 3, CL_PRINTER = 7, CL_STORAGE = 8, CL_HUB = 9, CL_DATA = 10, }; struct Endpt { uchar addr; /* endpoint address, 0-15 (|0x80 if direction==Ein) */ uchar dir; /* direction, Ein/Eout */ uchar type; /* Econtrol, Eiso, Ebulk, Eintr */ uchar isotype; /* Eunknown, Easync, Eadapt, Esync */ int id; int class; ulong csp; int maxpkt; Device* dev; Dconf* conf; Dinf* iface; }; struct Dalt { int attrib; int interval; void* devspec; /* device specific settings */ }; struct Dinf { int interface; /* interface number */ ulong csp; /* USB class/subclass/proto */ Dalt* dalt[16]; Endpt* endpt[16]; }; struct Dconf { ulong csp; /* USB class/subclass/proto */ int nif; /* number of interfaces */ int cval; /* value for set configuration */ int attrib; int milliamps; /* maximum power in this configuration */ Dinf* iface[16]; /* up to 16 interfaces */ }; /* Dconf.attrib */ enum { Cbuspowered = 1<<7, Cselfpowered = 1<<6, Cremotewakeup = 1<<5, }; struct Device { Ref; int ctlrno; int ctl; /* fd */ int setup; /* fd */ int status; /* fd */ int state; int id; int class; int npt; int ls; /* low speed */ ulong csp; /* USB class/subclass/proto */ int nconf; int nif; /* # of interfaces (sum of per-conf `nif's) */ int vid; /* vendor id */ int did; /* product (device) id */ Dconf* config[16]; Endpt* ep[Nendpt]; Device* setupfd; /* for usbprobe */ Device* cfd; /* for usbprobe */ }; /* * layout of standard descriptor types */ struct DDevice { byte bLength; byte bDescriptorType; byte bcdUSB[2]; byte bDeviceClass; byte bDeviceSubClass; byte bDeviceProtocol; byte bMaxPacketSize0; byte idVendor[2]; byte idProduct[2]; byte bcdDevice[2]; byte iManufacturer; byte iProduct; byte iSerialNumber; byte bNumConfigurations; }; #define DDEVLEN 18 struct DConfig { byte bLength; byte bDescriptorType; byte wTotalLength[2]; byte bNumInterfaces; byte bConfigurationValue; byte iConfiguration; byte bmAttributes; byte MaxPower; }; #define DCONFLEN 9 struct DInterface { byte bLength; byte bDescriptorType; byte bInterfaceNumber; byte bAlternateSetting; byte bNumEndpoints; byte bInterfaceClass; byte bInterfaceSubClass; byte bInterfaceProtocol; byte iInterface; }; #define DINTERLEN 9 struct DEndpoint { byte bLength; byte bDescriptorType; byte bEndpointAddress; byte bmAttributes; byte wMaxPacketSize[2]; byte bInterval; }; #define DENDPLEN 7 struct DHid { byte bLength; byte bDescriptorType; byte bcdHID[2]; byte bCountryCode; byte bNumDescriptors; byte bClassDescriptorType; byte wItemLength[2]; }; #define DHIDLEN 9 struct DHub { byte bLength; byte bDescriptorType; byte bNbrPorts; byte wHubCharacteristics[2]; byte bPwrOn2PwrGood; byte bHubContrCurrent; byte DeviceRemovable[1]; /* variable length */ /* byte PortPwrCtrlMask; /* variable length, deprecated in USB v1.1 */ }; #define DHUBLEN 9 struct Namelist { short index; char *name; }; typedef struct Drivetab { ulong csp; void (*driver)(Device *d); } Drivetab; #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)) extern void (*dprinter[0x100])(Device *, int, ulong, void *b, int n); /* * format routines */ void pdesc (Device *, int, ulong, byte *, int); void preport (Device *, int, ulong, byte *, int); void pstring (Device *, int, ulong, void *, int); void phub (Device *, int, ulong, void *, int); void pdevice (Device *, int, ulong, void *, int); void phid (Device *, int, ulong, void *, int); void pcs_raw(char *tag, byte *b, int n); /* * interface */ void usbfmtinit(void); Device* opendev(int, int); void closedev(Device*); int describedevice(Device*); int loadconfig(Device *d, int n); Endpt * newendpt(Device *d, int id, ulong csp); int setupcmd(Endpt*, int, int, int, int, byte*, int); int setupreq(Endpt*, int, int, int, int, int); int setupreply(Endpt*, void*, int); void setdevclass(Device *d, int n); void * emalloc(ulong); void * emallocz(ulong, int); char * namefor(Namelist *, int); #pragma varargck type "D" Device*