typedef struct Device Device;
typedef struct Dconf Dconf;
typedef struct Ddesc Ddesc;
typedef struct Dinf Dinf;
typedef struct Dalt Dalt;
typedef struct Endpt Endpt;

struct Device
{
	Ref;
	int		ctlrno;
	int		id;
	int		state;
	int		ctl;
	int		setup;
	int		status;
	int		ls;			/* low speed */

	int		vers;			/* USB version supported, in BCD */
	ulong	csp;			/* USB class/subclass/proto */
	int		max0;		/* max packet size for endpoint 0 */
	int		vid;			/* vendor id */
	int		did;			/* product (device) id */
	int		release;		/* device release number, in BCD */
	int		manufacturer;	/* string index */
	int		product;		/* string index */
	int		serial;		/* string index */
	int		nconf;
	Dconf*	config;
	char		*strings[256];
};

struct Ddesc
{
	int		ndesc;		/* number of descriptors */
	int		bytes;		/* total size of descriptors */
	uchar	*data;		/* descriptor data */
};

struct Dconf
{
	Device	*d;			/* owning device */
	int		x;			/* index into Device.config array */
	int		nif;			/* number of interfaces */
	int		cval;			/* value for set configuration request */
	int		config;		/* string index */
	int		attrib;
	int		milliamps;	/* maximum power in this configuration */
	Ddesc	desc;		/* additional descriptors for this configuration */
	Dinf*	iface;
};

struct Dinf
{
	Device	*d;			/* owning device */
	Dconf	*conf;		/* owning configuration */
	int		x;			/* index into Dconf.iface array */
	ulong	csp;			/* USB class/subclass/proto */
	int		interface;		/* string index */
	Dalt		*alt;			/* linked list of alternatives */
	Dinf		*next;		/* caller-maintained list of interfaces */
};

struct Dalt
{
	Dinf		*intf;			/* owning interface */
	int		alt;			/* alternate number, used to select this alternate */
	int		npt;			/* number of endpoints */
	Endpt*	ep;			/* endpoints for this interface alternate */
	Ddesc	desc;		/* additional descriptors for this alternate */
	Dalt*		next;			/* next in linked list of alternatives */
};

struct Endpt
{
	uchar	addr;		/* endpoint address, 0-15 */
	uchar	dir;			/* direction, Ein/Eout */
	uchar	type;			/* Econtrol, Eiso, Ebulk, Eintr */
	uchar	isotype;		/* Eunknown, Easync, Eadapt, Esync */
	int		maxpkt;		/* maximum packet size for endpoint */
	int		pollms;		/* polling interval for interrupts */
	Ddesc	desc;		/* additional descriptors for this endpoint */
};

enum
{
	/* Device.state */
	Detached = 0,
	Attached,
	Enabled,
	Assigned,
	Configured,

	/* Dconf.attrib */
	Cbuspowered = 1<<7,
	Cselfpowered = 1<<6,
	Cremotewakeup = 1<<5,

	/* Endpt.dir */
	Ein = 0,
	Eout,

	/* Endpt.type */
	Econtrol = 0,
	Eiso,
	Ebulk,
	Eintr,

	/* Endpt.isotype */
	Eunknown = 0,
	Easync,
	Eadapt,
	Esync,
};

#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))

enum
{
	/* known classes */
	CL_AUDIO = 1,
	CL_COMMS = 2,
	CL_HID = 3,
	CL_PHYSICAL = 5,
	CL_IMAGE = 6,
	CL_PRINTER = 7,
	CL_STORAGE = 8,
	CL_HUB = 9,
	CL_DATA = 10,
	CL_CHIP = 11,
	CL_SECURITY = 13,
};

/*
 * interface
 */
void		usbfmtinit(void);
Device*	opendev(int, int);
void		closedev(Device*);
int		describedevice(Device*);
void		dumpdevice(int, Device*);
void		loadstr(Device*, int, int);
void		loadstrings(Device*, int);

int		setupreq(Device*, int, int, int, int, uchar*, int);

void	*	emalloc(ulong);
void	*	emallocz(ulong, int);

#pragma	varargck	type  "D"	Device*
