Browse Source

Plan 9 from Bell Labs 2011-02-11

David du Colombier 8 years ago
parent
commit
65ab4cf535

+ 8 - 0
sys/lib/plumb/basic

@@ -94,6 +94,14 @@ type is text
 data matches '([a-zA-Z¡-￿0-9_\-./]+)\(([1-8])\)'
 plumb start rc -c 'man -b '$2' '$1'
 
+# RFC references are looked up in /lib/rfc and passed to editor
+type is text
+data	matches 'RFC ?([0-9]+)'
+arg isfile /lib/rfc/rfc$1
+data set	$file
+plumb to edit
+plumb client window $editor
+
 # start rule for images without known suffixes
 dst is image
 plumb to image

+ 5 - 3
sys/src/9/kw/coproc.c

@@ -16,7 +16,9 @@
 enum {
 	/* alternates:	0xe12fff1e	BX (R14); last e is R14 */
 	/*		0xe28ef000	B 0(R14); second e is R14 (ken) */
-	Retinst	= 0xe1a0f00e,		/* MOV R14, R15 */
+	Retinst	= 0xe1a0f00e,		/* MOVW R14, R15 */
+
+	Fpproc	= 10,			/* for vfp 3+; also 11 for doubles */
 };
 
 void
@@ -111,7 +113,7 @@ fprd(int fpreg)
 	 * VMRS.  return value will be in R0, which is convenient.
 	 * Rt will be R0.
 	 */
-	instr[0] = 0xeef00a10 | fpreg << 16 | 0 << 12;
+	instr[0] = 0xeef00010 | fpreg << 16 | 0 << 12 | Fpproc << 8;
 	instr[1] = Retinst;
 	coherence();
 
@@ -136,7 +138,7 @@ fpwr(int fpreg, ulong val)
 	s = splhi();
 	fpreg &= 017;
 	/* VMSR.  Rt will be R0. */
-	instr[0] = 0xeee00a10 | fpreg << 16 | 0 << 12;
+	instr[0] = 0xeee00010 | fpreg << 16 | 0 << 12 | Fpproc << 8;
 	instr[1] = Retinst;
 	coherence();
 

+ 1 - 1
sys/src/9/kw/devusb.c

@@ -45,7 +45,7 @@
 #include	"fns.h"
 #include	"io.h"
 #include	"../port/error.h"
-#include	"usb.h"
+#include	"../port/usb.h"
 
 typedef struct Hcitype Hcitype;
 

+ 2 - 2
sys/src/9/kw/mkfile

@@ -129,8 +129,8 @@ fpi.$O fpiarm.$O fpimem.$O: fpi.h
 l.$O lexception.$O lproc.$O mmu.$O: arm.s arm.h mem.h
 main.$O:	errstr.h init.h reboot.h
 mouse.$O:	screen.h
-devusb.$O:	usb.h
-usbehci.$O usbohci.$O usbuhci.$O: usb.h usbehci.h uncached.h
+devusb.$O:	../port/usb.h
+usbehci.$O usbohci.$O usbuhci.$O: ../port/usb.h usbehci.h uncached.h
 
 init.h:D:	../port/initcode.c init9.s
 	$CC ../port/initcode.c

+ 2 - 2
sys/src/9/kw/plug

@@ -42,7 +42,7 @@ link
 	flashkw		ecc
 	loopbackmedium
 	netdevmedium
-	usbehci
+	usbehci		usbehcikw
 
 ip
 	tcp
@@ -74,7 +74,7 @@ bootdir
 	boot$CONF.out boot
 	/arm/bin/ip/ipconfig
 	/arm/bin/auth/factotum
-	/arm/bin/paqfs
+#	/arm/bin/paqfs
 	/arm/bin/usb/usbd
 # nvram not needed any longer, it's in flash
 	nvram

File diff suppressed because it is too large
+ 0 - 3610
sys/src/9/kw/usbehci.c


+ 79 - 12
sys/src/9/kw/usbehci.h

@@ -1,6 +1,30 @@
+/* override default macros from ../port/usb.h */
+#undef	dprint
+#undef	ddprint
+#undef	deprint
+#undef	ddeprint
+#define dprint		if(ehcidebug)print
+#define ddprint		if(ehcidebug>1)print
+#define deprint		if(ehcidebug || ep->debug)print
+#define ddeprint	if(ehcidebug>1 || ep->debug>1)print
+
+typedef struct Ctlr Ctlr;
 typedef struct Ecapio Ecapio;
 typedef struct Eopio Eopio;
 typedef struct Edbgio Edbgio;
+typedef struct Isoio Isoio;
+typedef struct Poll Poll;
+typedef struct Qh Qh;
+typedef struct Qtree Qtree;
+
+#pragma incomplete Ctlr;
+#pragma incomplete Ecapio;
+#pragma incomplete Eopio;
+#pragma incomplete Edbgio;
+#pragma incomplete Isoio;
+#pragma incomplete Poll;
+#pragma incomplete Qh;
+#pragma incomplete Qtree;
 
 /*
  * EHCI interface registers and bits
@@ -63,7 +87,7 @@ enum
 	Iall		= 0x3F,		/* all interrupts */
 
 	/* Config reg. */
-	Callmine		= 1,		/* route all ports to us */
+	Callmine	= 1,		/* route all ports to us */
 
 	/* Portsc reg. */
 	Pspresent	= 0x00000001,	/* device present */
@@ -105,7 +129,7 @@ enum
 	/* Debug port addr reg. */
 	Adevshift	= 8,		/* device address */
 	Adevmask	= 0x7F,
-	Aepshift		= 0,		/* endpoint number */
+	Aepshift	= 0,		/* endpoint number */
 	Aepmask		= 0xF,
 };
 
@@ -120,6 +144,55 @@ struct Ecapio
 	ulong	portroute;	/* 0c not on the CS5536 */
 };
 
+/*
+ * Debug port registers (hw)
+ */
+struct Edbgio
+{
+	ulong	csw;		/* control and status */
+	ulong	pid;		/* USB pid */
+	uchar	data[8];	/* data buffer */
+	ulong	addr;		/* device and endpoint addresses */
+};
+
+struct Poll
+{
+	Lock;
+	Rendez;
+	int	must;
+	int	does;
+};
+
+struct Ctlr
+{
+	Rendez;			/* for waiting to async advance doorbell */
+	Lock;			/* for ilock. qh lists and basic ctlr I/O */
+	QLock	portlck;	/* for port resets/enable... (and doorbell) */
+	int	active;		/* in use or not */
+	Ecapio*	capio;		/* Capability i/o regs */
+	Eopio*	opio;		/* Operational i/o regs */
+
+	int	nframes;	/* 1024, 512, or 256 frames in the list */
+	ulong*	frames;		/* periodic frame list (hw) */
+	Qh*	qhs;		/* async Qh circular list for bulk/ctl */
+	Qtree*	tree;		/* tree of Qhs for the periodic list */
+	int	ntree;		/* number of dummy qhs in tree */
+	Qh*	intrqhs;		/* list of (not dummy) qhs in tree  */
+	Isoio*	iso;		/* list of active Iso I/O */
+	ulong	load;
+	ulong	isoload;
+	int	nintr;		/* number of interrupts attended */
+	int	ntdintr;	/* number of intrs. with something to do */
+	int	nqhintr;	/* number of async td intrs. */
+	int	nisointr;	/* number of periodic td intrs. */
+	int	nreqs;
+	Poll	poll;
+};
+
+/*
+ * Kirkwood-specific stuff
+ */
+
 /*
  * Operational registers (hw)
  */
@@ -162,14 +235,8 @@ struct Eopio
 	ulong	ctl;
 };
 
-/*
- * Debug port registers (hw)
- */
-struct Edbgio
-{
-	ulong	csw;		/* control and status */
-	ulong	pid;		/* USB pid */
-	uchar	data[8];	/* data buffer */
-	ulong	addr;		/* device and endpoint addresses */
-};
+extern int ehcidebug;
 
+void	ehcilinkage(Hci *hp);
+void	ehcimeminit(Ctlr *ctlr);
+void	ehcirun(Ctlr *ctlr, int on);

+ 350 - 0
sys/src/9/kw/usbehcikw.c

@@ -0,0 +1,350 @@
+/*
+ * Kirkwood-specific code for
+ * USB Enhanced Host Controller Interface (EHCI) driver
+ * High speed USB 2.0.
+ */
+
+#include	"u.h"
+#include	"../port/lib.h"
+#include	"mem.h"
+#include	"dat.h"
+#include	"fns.h"
+#include	"io.h"
+#include	"../port/error.h"
+#include	"../port/usb.h"
+#include	"usbehci.h"
+//#include	"uncached.h"
+
+#define WINTARG(ctl)	(((ctl) >> 4) & 017)
+#define WINATTR(ctl)	(((ctl) >> 8) & 0377)
+#define WIN64KSIZE(ctl)	(((ctl) >> 16) + 1)
+
+#define SIZETO64KSIZE(size) ((size) / (64*1024) - 1)
+
+enum {
+	Debug = 0,
+};
+
+typedef struct Kwusb Kwusb;
+typedef struct Kwusbtt Kwusbtt;
+typedef struct Usbwin Usbwin;
+
+/* kirkwood usb transaction translator registers? (undocumented) */
+struct Kwusbtt {		/* at soc.ehci */
+	ulong	id;
+	ulong	hwgeneral;
+	ulong	hwhost;
+	ulong	hwdevice;
+	ulong	hwtxbuf;
+	ulong	hwrxbuf;
+	ulong	hwtttxbuf;
+	ulong	hwttrxbuf;
+};
+
+/* kirkwood usb bridge & phy registers */
+struct Kwusb {			/* at offset 0x300 from soc.ehci */
+	ulong	bcs;		/* bridge ctl & sts */
+	uchar	_pad0[0x310-0x304];
+
+	ulong	bic;		/* bridge intr. cause */
+	ulong	bim;		/* bridge intr. mask */
+	ulong	_pad1;
+	ulong	bea;		/* bridge error addr. */
+	struct Usbwin {
+		ulong	ctl;	/* see Winenable in io.h */
+		ulong	base;
+		ulong	_pad2[2];
+	} win[4];
+	ulong	phycfg;		/* phy config. */
+	uchar	_pad3[0x400-0x364];
+
+	ulong	pwrctl;		/* power control */
+	uchar	_pad4[0x410-0x404];
+	ulong	phypll;		/* phy pll control */
+	uchar	_pad5[0x420-0x414];
+	ulong	phytxctl;	/* phy transmit control */
+	uchar	_pad6[0x430-0x424];
+	ulong	phyrxctl;	/* phy receive control */
+	uchar	_pad7[0x440-0x434];
+	ulong	phyivref;	/* phy ivref control */
+};
+
+static Ctlr* ctlrs[Nhcis];
+
+static void
+addrmapdump(void)
+{
+	int i;
+	ulong ctl, targ, attr, size64k;
+	Kwusb *map;
+	Usbwin *win;
+
+	if (!Debug)
+		return;
+	map = (Kwusb *)(soc.ehci + 0x300);
+	for (i = 0; i < nelem(map->win); i++) {
+		win = &map->win[i];
+		ctl = win->ctl;
+		if (ctl & Winenable) {
+			targ = WINTARG(ctl);
+			attr = WINATTR(ctl);
+			size64k = WIN64KSIZE(ctl);
+			print("usbehci: address map window %d: "
+				"targ %ld attr %#lux size %,ld addr %#lux\n",
+				i, targ, attr, size64k * 64*1024, win->base);
+		}
+	}
+}
+
+/* assumes ctlr is ilocked */
+static void
+ctlrreset(Ctlr *ctlr)
+{
+	int i;
+	Eopio *opio;
+
+	opio = ctlr->opio;
+	opio->cmd |= Chcreset;
+	coherence();
+	/* wait for it to come out of reset */
+	for(i = 0; i < 100 && opio->cmd & Chcreset; i++)
+		delay(1);
+	if(i >= 100)
+		print("ehci %#p controller reset timed out\n", ctlr->capio);
+	/*
+	 * Marvell errata FE-USB-340 workaround: 1 << 4 magic:
+	 * disable streaming.  Magic 3 (usb host mode) from the linux driver
+	 * makes it work.  Ick.
+	 */
+	opio->usbmode |= 1 << 4 | 3;
+	coherence();
+}
+
+/*
+ * configure window `win' as 256MB dram with attribute `attr' and
+ * base address
+ */
+static void
+setaddrwin(Kwusb *kw, int win, int attr, ulong base)
+{
+	kw->win[win].ctl = Winenable | Targdram << 4 | attr << 8 |
+		SIZETO64KSIZE(256*MB) << 16;
+	kw->win[win].base = base;
+}
+
+static void
+ehcireset(Ctlr *ctlr)
+{
+	int i, amp, txvdd;
+	ulong v;
+	Eopio *opio;
+	Kwusb *kw;
+
+	ilock(ctlr);
+	dprint("ehci %#p reset\n", ctlr->capio);
+	opio = ctlr->opio;
+
+	kw = (Kwusb *)(soc.ehci + 0x300);
+	kw->bic = 0;
+	kw->bim = (1<<4) - 1;		/* enable all defined intrs */
+	ctlrreset(ctlr);
+
+	/*
+	 * clear high 32 bits of address signals if it's 64 bits capable.
+	 * This is probably not needed but it does not hurt and others do it.
+	 */
+	if((ctlr->capio->capparms & C64) != 0){
+		dprint("ehci: 64 bits\n");
+		opio->seg = 0;
+	}
+
+	/* requesting more interrupts per µframe may miss interrupts */
+	opio->cmd |= Citc8;		/* 1 intr. per ms */
+	switch(opio->cmd & Cflsmask){
+	case Cfls1024:
+		ctlr->nframes = 1024;
+		break;
+	case Cfls512:
+		ctlr->nframes = 512;
+		break;
+	case Cfls256:
+		ctlr->nframes = 256;
+		break;
+	default:
+		panic("ehci: unknown fls %ld", opio->cmd & Cflsmask);
+	}
+	dprint("ehci: %d frames\n", ctlr->nframes);
+
+	/*
+	 * set up the USB address map (bridge address decoding)
+	 */
+	for (i = 0; i < nelem(kw->win); i++)
+		kw->win[i].ctl = kw->win[i].base = 0;
+	coherence();
+
+	setaddrwin(kw, 0, Attrcs0, 0);
+	setaddrwin(kw, 1, Attrcs1, 256*MB);
+	coherence();
+
+	if (Debug)
+		if (kw->bcs & (1 << 4))
+			print("usbehci: not swapping bytes\n");
+		else
+			print("usbehci: swapping bytes\n");
+	addrmapdump();				/* verify sanity */
+
+	kw->pwrctl |= 1 << 0 | 1 << 1;		/* Pu | PuPll */
+	coherence();
+
+	/*
+	 * Marvell guideline GL-USB-160.
+	 */
+	kw->phypll |= 1 << 21;		/* VCOCAL_START: PLL calibration */
+	coherence();
+	microdelay(100);
+	kw->phypll &= ~(1 << 21);
+
+	v = kw->phytxctl & ~(017 << 27 | 7);	/* REG_EXT_FS_RCALL & AMP_2_0 */
+	switch (m->socrev) {
+	default:
+		print("usbehci: bad 6281 soc rev %d\n", m->socrev);
+		/* fall through */
+	case Socreva0:
+		amp = 4;
+		txvdd = 1;
+		break;
+	case Socreva1:
+		amp = 3;
+		txvdd = 3;
+		break;
+	}
+	/* REG_EXT_FS_RCALL_EN | REG_RCAL_START | AMP_2_0 */
+	kw->phytxctl = v | 1 << 26 | 1 << 12 | amp;
+	coherence();
+	microdelay(100);
+	kw->phytxctl &= ~(1 << 12);
+
+	v = kw->phyrxctl & ~(3 << 2 | 017 << 4); /* LPF_COEF_1_0 & SQ_THRESH_3_0 */
+	kw->phyrxctl = v | 1 << 2 | 8 << 4;
+
+	v = kw->phyivref & ~(3 << 8);		/* TXVDD12 */
+	kw->phyivref = v | txvdd << 8;
+	coherence();
+
+	ehcirun(ctlr, 0);
+	ctlrreset(ctlr);
+
+	iunlock(ctlr);
+}
+
+static void
+setdebug(Hci*, int d)
+{
+	ehcidebug = d;
+}
+
+static void
+shutdown(Hci *hp)
+{
+	Ctlr *ctlr;
+	Eopio *opio;
+
+	ctlr = hp->aux;
+	ilock(ctlr);
+	ctlrreset(ctlr);
+
+	delay(100);
+	ehcirun(ctlr, 0);
+
+	opio = ctlr->opio;
+	opio->frbase = 0;
+	coherence();
+	iunlock(ctlr);
+}
+
+static void
+findehcis(void)		/* actually just use fixed addresses on sheeva */
+{
+	int i;
+	Ctlr *ctlr;
+	static int already = 0;
+
+	if(already)
+		return;
+	already = 1;
+
+	ctlr = mallocz(sizeof(Ctlr), 1);
+	/* the sheeva's usb 2.0 otg uses a superset of the ehci registers */
+	ctlr->capio = (Ecapio *)(soc.ehci + 0x100);
+	ctlr->opio  = (Eopio *) (soc.ehci + 0x140);
+	dprint("usbehci: port %#p\n", ctlr->capio);
+
+	for(i = 0; i < Nhcis; i++)
+		if(ctlrs[i] == nil){
+			ctlrs[i] = ctlr;
+			break;
+		}
+	if(i == Nhcis)
+		print("ehci: bug: more than %d controllers\n", Nhcis);
+}
+
+static int
+reset(Hci *hp)
+{
+	static Lock resetlck;
+	int i;
+	Ctlr *ctlr;
+	Ecapio *capio;
+
+	ilock(&resetlck);
+	findehcis();
+
+	/*
+	 * Any adapter matches if no hp->port is supplied,
+	 * otherwise the ports must match.
+	 */
+	ctlr = nil;
+	for(i = 0; i < Nhcis && ctlrs[i] != nil; i++){
+		ctlr = ctlrs[i];
+		if(ctlr->active == 0)
+		if(hp->port == 0 || hp->port == (uintptr)ctlr->capio){
+			ctlr->active = 1;
+			break;
+		}
+	}
+	iunlock(&resetlck);
+	if(ctlrs[i] == nil || i == Nhcis)
+		return -1;
+
+	hp->aux = ctlr;
+	hp->port = (uintptr)ctlr->capio;
+	hp->irq = IRQ0usb0;
+	hp->tbdf = 0;
+
+	capio = ctlr->capio;
+	hp->nports = capio->parms & Cnports;
+
+	ddprint("echi: %s, ncc %lud npcc %lud\n",
+		capio->parms & 0x10000 ? "leds" : "no leds",
+		(capio->parms >> 12) & 0xf, (capio->parms >> 8) & 0xf);
+	ddprint("ehci: routing %s, %sport power ctl, %d ports\n",
+		capio->parms & 0x40 ? "explicit" : "automatic",
+		capio->parms & 0x10 ? "" : "no ", hp->nports);
+
+	ehcireset(ctlr);
+	ehcimeminit(ctlr);
+
+	/*
+	 * Linkage to the generic HCI driver.
+	 */
+	ehcilinkage(hp);
+	hp->shutdown = shutdown;
+	hp->debug = setdebug;
+	return 0;
+}
+
+void
+usbehcilink(void)
+{
+	addhcitype("ehci", reset);
+}

+ 1 - 0
sys/src/9/omap/archomap.c

@@ -17,6 +17,7 @@
 #include "../port/netif.h"
 #include "etherif.h"
 #include "../port/flashif.h"
+#include "../port/usb.h"
 #include "usbehci.h"
 
 #define FREQSEL(x) ((x) << 4)

+ 1 - 1
sys/src/9/omap/beagle

@@ -43,7 +43,7 @@ link
 	ether9221
 ## avoid tickling errata 3.1.1.183
 ##	usbohci
-#	usbehci
+#	usbehci		usbehciomap
 
 ip
 	tcp

+ 1 - 1
sys/src/9/omap/devusb.c

@@ -45,7 +45,7 @@
 #include	"fns.h"
 #include	"io.h"
 #include	"../port/error.h"
-#include	"usb.h"
+#include	"../port/usb.h"
 
 typedef struct Hcitype Hcitype;
 

+ 2 - 2
sys/src/9/omap/mkfile

@@ -111,8 +111,8 @@ l.$O lexception.$O lproc.$O mmu.$O: arm.s arm.h mem.h
 l.$O rebootcode.$O: cache.v7.s
 main.$O: errstr.h init.h reboot.h
 devdss.$O devmouse.$O mouse.$O screen.$O: screen.h
-devusb.$O: usb.h
-usbehci.$O usbohci.$O usbuhci.$O: usb.h usbehci.h uncached.h
+devusb.$O: ../port/usb.h
+usbehci.$O usbohci.$O usbuhci.$O: ../port/usb.h usbehci.h uncached.h
 
 init.h:D:	../port/initcode.c init9.s
 	$CC ../port/initcode.c

+ 0 - 194
sys/src/9/omap/usb.h

@@ -1,194 +0,0 @@
-/*
- * common USB definitions.
- */
-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	= 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) */
-};
-
-/*
- * 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*));
-#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);}
-
-extern char *usbmodename[];
-extern char Estalled[];
-
-extern char *seprintdata(char*,char*,uchar*,int);

+ 87 - 19
sys/src/9/omap/usbehci.h

@@ -1,6 +1,31 @@
+/* override default macros from ../port/usb.h */
+#undef	dprint
+#undef	ddprint
+#undef	deprint
+#undef	ddeprint
+#define dprint		if(ehcidebug)print
+#define ddprint		if(ehcidebug>1)print
+#define deprint		if(ehcidebug || ep->debug)print
+#define ddeprint	if(ehcidebug>1 || ep->debug>1)print
+
+typedef struct Ctlr Ctlr;
 typedef struct Ecapio Ecapio;
 typedef struct Eopio Eopio;
 typedef struct Edbgio Edbgio;
+typedef struct Isoio Isoio;
+typedef struct Poll Poll;
+typedef struct Qh Qh;
+typedef struct Qtree Qtree;
+
+#pragma incomplete Ctlr;
+#pragma incomplete Ecapio;
+#pragma incomplete Eopio;
+#pragma incomplete Edbgio;
+#pragma incomplete Isoio;
+#pragma incomplete Poll;
+#pragma incomplete Qh;
+#pragma incomplete Qtree;
+
 
 /*
  * EHCI interface registers and bits
@@ -64,7 +89,7 @@ enum
 	Iall		= 0x3F,		/* all interrupts */
 
 	/* Config reg. */
-	Callmine		= 1,		/* route all ports to us */
+	Callmine	= 1,		/* route all ports to us */
 
 	/* Portsc reg. */
 	Pspresent	= 0x00000001,	/* device present */
@@ -106,7 +131,7 @@ enum
 	/* Debug port addr reg. */
 	Adevshift	= 8,		/* device address */
 	Adevmask	= 0x7F,
-	Aepshift		= 0,		/* endpoint number */
+	Aepshift	= 0,		/* endpoint number */
 	Aepmask		= 0xF,
 };
 
@@ -121,6 +146,60 @@ struct Ecapio
 	ulong	portroute;	/* 0c not on the CS5536 */
 };
 
+/*
+ * Debug port registers (hw)
+ */
+struct Edbgio
+{
+	ulong	csw;		/* control and status */
+	ulong	pid;		/* USB pid */
+	uchar	data[8];	/* data buffer */
+	ulong	addr;		/* device and endpoint addresses */
+};
+
+struct Poll
+{
+	Lock;
+	Rendez;
+	int	must;
+	int	does;
+};
+
+struct Ctlr
+{
+	Rendez;			/* for waiting to async advance doorbell */
+	Lock;			/* for ilock. qh lists and basic ctlr I/O */
+	QLock	portlck;	/* for port resets/enable... (and doorbell) */
+	int	active;		/* in use or not */
+	Ecapio*	capio;		/* Capability i/o regs */
+	Eopio*	opio;		/* Operational i/o regs */
+
+	int	nframes;	/* 1024, 512, or 256 frames in the list */
+	ulong*	frames;		/* periodic frame list (hw) */
+	Qh*	qhs;		/* async Qh circular list for bulk/ctl */
+	Qtree*	tree;		/* tree of Qhs for the periodic list */
+	int	ntree;		/* number of dummy qhs in tree */
+	Qh*	intrqhs;	/* list of (not dummy) qhs in tree  */
+	Isoio*	iso;		/* list of active Iso I/O */
+	ulong	load;
+	ulong	isoload;
+	int	nintr;		/* number of interrupts attended */
+	int	ntdintr;	/* number of intrs. with something to do */
+	int	nqhintr;	/* number of async td intrs. */
+	int	nisointr;	/* number of periodic td intrs. */
+	int	nreqs;
+	Poll	poll;
+};
+
+/*
+ * OMAP3-specific stuff
+ */
+
+enum {
+	/* hostconfig bits */
+	P1ulpi_bypass = 1<<0,	/* utmi if set; else ulpi */
+};
+
 /*
  * Operational registers (hw)
  */
@@ -134,7 +213,6 @@ struct Eopio
 	ulong	frbase;		/* 14 frame list base addr, 4096-byte boundary */
 	ulong	link;		/* 18 link for async list */
 	uchar	d2c[0x40-0x1c];	/* 1c dummy */
-
 	ulong	config;		/* 40 1: all ports default-routed to this HC */
 	ulong	portsc[3];	/* 44 Port status and control, one per port */
 
@@ -143,17 +221,6 @@ struct Eopio
 	ulong	insn[6];	/* implementation-specific */
 };
 
-/*
- * Debug port registers (hw)
- */
-struct Edbgio
-{
-	ulong	csw;		/* control and status */
-	ulong	pid;		/* USB pid */
-	uchar	data[8];	/* data buffer */
-	ulong	addr;		/* device and endpoint addresses */
-};
-
 typedef struct Uhh Uhh;
 struct Uhh {
 	ulong	revision;	/* ro */
@@ -166,10 +233,11 @@ struct Uhh {
 	ulong	debug_csr;
 };
 
-enum {
-	/* hostconfig bits */
-	P1ulpi_bypass = 1<<0,	/* utmi if set; else ulpi */
-};
-
 extern Ecapio *ehcidebugcapio;
 extern int ehcidebugport;
+
+extern int ehcidebug;
+
+void	ehcilinkage(Hci *hp);
+void	ehcimeminit(Ctlr *ctlr);
+void	ehcirun(Ctlr *ctlr, int on);

+ 225 - 0
sys/src/9/omap/usbehciomap.c

@@ -0,0 +1,225 @@
+/*
+ * OMAP3-specific code for
+ * USB Enhanced Host Controller Interface (EHCI) driver
+ * High speed USB 2.0.
+ */
+
+#include	"u.h"
+#include	"../port/lib.h"
+#include	"mem.h"
+#include	"dat.h"
+#include	"fns.h"
+#include	"io.h"
+#include	"../port/error.h"
+#include	"../port/usb.h"
+#include	"usbehci.h"
+
+static Ctlr* ctlrs[Nhcis];
+
+static void
+ehcireset(Ctlr *ctlr)
+{
+	Eopio *opio;
+	int i;
+
+	ilock(ctlr);
+	dprint("ehci %#p reset\n", ctlr->capio);
+	opio = ctlr->opio;
+
+	/*
+	 * Turn off legacy mode. Some controllers won't
+	 * interrupt us as expected otherwise.
+	 */
+	ehcirun(ctlr, 0);
+
+	/* clear high 32 bits of address signals if it's 64 bits capable.
+	 * This is probably not needed but it does not hurt and others do it.
+	 */
+	if((ctlr->capio->capparms & C64) != 0){
+		dprint("ehci: 64 bits\n");
+		opio->seg = 0;
+	}
+
+	if(ehcidebugcapio != ctlr->capio){
+		opio->cmd |= Chcreset;	/* controller reset */
+		coherence();
+		for(i = 0; i < 100; i++){
+			if((opio->cmd & Chcreset) == 0)
+				break;
+			delay(1);
+		}
+		if(i == 100)
+			print("ehci %#p controller reset timed out\n", ctlr->capio);
+	}
+
+	/* requesting more interrupts per µframe may miss interrupts */
+	opio->cmd |= Citc8;		/* 1 intr. per ms */
+	coherence();
+	switch(opio->cmd & Cflsmask){
+	case Cfls1024:
+		ctlr->nframes = 1024;
+		break;
+	case Cfls512:
+		ctlr->nframes = 512;
+		break;
+	case Cfls256:
+		ctlr->nframes = 256;
+		break;
+	default:
+		panic("ehci: unknown fls %ld", opio->cmd & Cflsmask);
+	}
+	coherence();
+	dprint("ehci: %d frames\n", ctlr->nframes);
+	iunlock(ctlr);
+}
+
+static void
+setdebug(Hci*, int d)
+{
+	ehcidebug = d;
+}
+
+static void
+shutdown(Hci *hp)
+{
+	int i;
+	Ctlr *ctlr;
+	Eopio *opio;
+
+	ctlr = hp->aux;
+	ilock(ctlr);
+	opio = ctlr->opio;
+	opio->cmd |= Chcreset;		/* controller reset */
+	coherence();
+	for(i = 0; i < 100; i++){
+		if((opio->cmd & Chcreset) == 0)
+			break;
+		delay(1);
+	}
+	if(i >= 100)
+		print("ehci %#p controller reset timed out\n", ctlr->capio);
+	delay(100);
+	ehcirun(ctlr, 0);
+	opio->frbase = 0;
+	coherence();
+	iunlock(ctlr);
+}
+
+/*
+ * omap3-specific ehci code
+ */
+
+enum {
+	/* opio->insn[5] bits */
+	Control		= 1<<31,  /* set to start access, cleared when done */
+	Write		= 2<<22,
+	Read		= 3<<22,
+	Portsh		= 24,
+	Regaddrsh	= 16,		/* 0x2f means use extended reg addr */
+	Eregaddrsh	= 8,
+
+	/* phy reg addresses */
+	Funcctlreg	= 4,
+	Ifcctlreg	= 7,
+
+	Phystppullupoff	= 0x90,		/* on is 0x10 */
+
+	Phyrstport2	= 147,		/* gpio # */
+
+};
+
+static void
+wrulpi(Eopio *opio, int port, int reg, uchar data)
+{
+	opio->insn[5] = Control | port << Portsh | Write | reg << Regaddrsh |
+		data;
+	coherence();
+	/*
+	 * this seems contrary to the skimpy documentation in the manual
+	 * but inverting the test hangs forever.
+	 */
+	while (!(opio->insn[5] & Control))
+		;
+}
+
+static int
+reset(Hci *hp)
+{
+	Ctlr *ctlr;
+	Ecapio *capio;
+	Eopio *opio;
+	Uhh *uhh;
+	static int beenhere;
+
+	if (beenhere)
+		return -1;
+	beenhere = 1;
+
+	if(getconf("*nousbehci") != nil || probeaddr(PHYSEHCI) < 0)
+		return -1;
+
+	ctlr = mallocz(sizeof(Ctlr), 1);
+	/*
+	 * don't bother with vmap; i/o space is all mapped anyway,
+	 * and a size less than 1MB will blow an assertion in mmukmap.
+	 */
+	ctlr->capio = capio = (Ecapio *)PHYSEHCI;
+//	ctlr->capio = capio = vmap(PHYSEHCI, 1024);
+	ctlr->opio = opio = (Eopio*)((uintptr)capio + (capio->cap & 0xff));
+
+	hp->aux = ctlr;
+	hp->port = (uintptr)ctlr->capio;
+	hp->irq = 77;
+	hp->nports = capio->parms & Cnports;
+
+	ddprint("echi: %s, ncc %lud npcc %lud\n",
+		capio->parms & 0x10000 ? "leds" : "no leds",
+		(capio->parms >> 12) & 0xf, (capio->parms >> 8) & 0xf);
+	ddprint("ehci: routing %s, %sport power ctl, %d ports\n",
+		capio->parms & 0x40 ? "explicit" : "automatic",
+		capio->parms & 0x10 ? "" : "no ", hp->nports);
+
+	ehcireset(ctlr);
+	ehcimeminit(ctlr);
+
+	/* omap35-specific set up */
+	/* bit 5 `must be set to 1 for proper behavior', spruf98d §23.2.6.7.17 */
+	opio->insn[4] |= 1<<5;
+	coherence();
+
+	/* insn[5] is for both utmi and ulpi, depending on hostconfig mode */
+	uhh = (Uhh *)PHYSUHH;
+	if (uhh->hostconfig & P1ulpi_bypass) {		/* utmi port 1 active */
+		/* not doing this */
+		iprint("usbehci: bypassing ulpi on port 1!\n");
+		opio->insn[5] &= ~(MASK(4) << 13);
+		opio->insn[5] |= 1 << 13;		/* select port 1 */
+		coherence();
+	} else {					/* ulpi port 1 active */
+		/* TODO may need to reset gpio port2 here */
+
+		/* disable integrated stp pull-up resistor */
+		wrulpi(opio, 1, Ifcctlreg, Phystppullupoff);
+
+		/* force phy to `high-speed' */
+		wrulpi(opio, 1, Funcctlreg, 0x40);
+	}
+
+	/*
+	 * Linkage to the generic HCI driver.
+	 */
+	ehcilinkage(hp);
+	hp->shutdown = shutdown;
+	hp->debug = setdebug;
+
+	intrenable(78, hp->interrupt, hp, UNKNOWN, "usbtll");
+	intrenable(92, hp->interrupt, hp, UNKNOWN, "usb otg");
+	intrenable(93, hp->interrupt, hp, UNKNOWN, "usb otg dma");
+	return 0;
+}
+
+void
+usbehcilink(void)
+{
+	addhcitype("ehci", reset);
+}

+ 12 - 24
sys/src/9/pc/devusb.c

@@ -1,5 +1,5 @@
 /*
- * USB device driver.
+ * USB device driver framework.
  *
  * This is in charge of providing access to actual HCIs
  * and providing I/O to the various endpoints of devices.
@@ -36,7 +36,6 @@
  * a generic controller driver, the problem is that details
  * regarding how to handle toggles, tokens, Tds, etc. will
  * get in the way. Thus, code is probably easier the way it is.
- *
  */
 
 #include	"u.h"
@@ -46,7 +45,7 @@
 #include	"fns.h"
 #include	"io.h"
 #include	"../port/error.h"
-#include	"usb.h"
+#include	"../port/usb.h"
 
 typedef struct Hcitype Hcitype;
 
@@ -126,7 +125,7 @@ static Cmdtab epctls[] =
 	{CMpollival,	"pollival",	2},
 	{CMsamplesz,	"samplesz",	2},
 	{CMhz,		"hz",		2},
-	{CMinfo,		"info",		0},
+	{CMinfo,	"info",		0},
 	{CMdetach,	"detach",	1},
 	{CMaddress,	"address",	1},
 	{CMdebugep,	"debug",	2},
@@ -179,8 +178,7 @@ static int	usbidgen;	/* device address generator */
 char*
 seprintdata(char *s, char *se, uchar *d, int n)
 {
-	int i;
-	int l;
+	int i, l;
 
 	s = seprint(s, se, " %#p[%d]: ", d, n);
 	l = n;
@@ -742,7 +740,7 @@ usbreset(void)
 			hcis[ctlrno++] = hp;
 		}
 	if(hcis[Nhcis-1] != nil)
-		print("usbreset: bug: Nhcis too small\n");
+		print("usbreset: bug: Nhcis (%d) too small\n", Nhcis);
 }
 
 static void
@@ -1086,11 +1084,7 @@ usbread(Chan *c, void *a, long n, vlong offset)
 static long
 pow2(int n)
 {
-	long v;
-
-	for(v = 1; n > 0; n--)
-		v *= 2;
-	return v;
+	return 1 << n;
 }
 
 static void
@@ -1121,18 +1115,13 @@ setmaxpkt(Ep *ep, char* s)
 static long
 epctl(Ep *ep, Chan *c, void *a, long n)
 {
-	static char *Info = "info ";
+	int i, l, mode, nb, tt;
+	char *b, *s;
+	Cmdbuf *cb;
+	Cmdtab *ct;
 	Ep *nep;
 	Udev *d;
-	int l;
-	char *s;
-	char *b;
-	int tt;
-	int i;
-	int mode;
-	int nb;
-	Cmdtab *ct;
-	Cmdbuf *cb;
+	static char *Info = "info ";
 
 	d = ep->dev;
 
@@ -1409,9 +1398,8 @@ ctlwrite(Chan *c, void *a, long n)
 static long
 usbwrite(Chan *c, void *a, long n, vlong off)
 {
-	int q;
+	int nr, q;
 	Ep *ep;
-	int nr;
 
 	if(c->qid.type == QTDIR)
 		error(Eisdir);

+ 1 - 1
sys/src/9/pc/mkfile

@@ -114,7 +114,7 @@ devaoe.$O sdaoe.$O:		../port/aoe.h
 main.$O:			init.h reboot.h
 wavelan.$O:			wavelan.c ../pc/wavelan.c ../pc/wavelan.h
 etherwavelan.$O:		etherwavelan.c ../pc/wavelan.h
-devusb.$O usbuhci.$O usbohci.$O usbehci.$O: usb.h
+devusb.$O usbuhci.$O usbohci.$O usbehci.$O: ../port/usb.h
 trap.$O:			/sys/include/tos.h
 uartaxp.$O:			uartaxp.i
 etherm10g.$O:			etherm10g2k.i etherm10g4k.i

+ 1 - 1
sys/src/9/pc/pc

@@ -71,7 +71,7 @@ link
 	loopbackmedium
 	usbuhci
 	usbohci
-	usbehci
+	usbehci		usbehcipc
 
 misc
 	archmp		mp apic

+ 1 - 1
sys/src/9/pc/pcauth

@@ -42,7 +42,7 @@ link
 	loopbackmedium
 	usbuhci
 	usbohci
-	usbehci
+	usbehci		usbehcipc
 
 misc
 	realmode

+ 1 - 1
sys/src/9/pc/pccd

@@ -71,7 +71,7 @@ link
 	netdevmedium
 	usbuhci
 	usbohci
-	usbehci
+	usbehci		usbehcipc
 
 misc
 	archmp		mp apic

+ 1 - 1
sys/src/9/pc/pccpu

@@ -58,7 +58,7 @@ link
 	loopbackmedium
 	usbuhci
 	usbohci
-	usbehci
+	usbehci		usbehcipc
 
 misc
 	archmp		mp apic

+ 1 - 1
sys/src/9/pc/pccpuf

@@ -66,7 +66,7 @@ link
 	loopbackmedium
 	usbuhci
 	usbohci
-	usbehci
+	usbehci		usbehcipc
 
 misc
 	archmp		mp apic

+ 1 - 1
sys/src/9/pc/pcdisk

@@ -69,7 +69,7 @@ link
 	loopbackmedium
 	usbuhci
 	usbohci
-	usbehci
+	usbehci		usbehcipc
 
 misc
 	archmp		mp apic

+ 1 - 1
sys/src/9/pc/pcf

@@ -71,7 +71,7 @@ link
 	loopbackmedium
 	usbuhci
 	usbohci
-	usbehci
+	usbehci		usbehcipc
 
 misc
 	archmp		mp apic

+ 1 - 1
sys/src/9/pc/pcfs

@@ -41,7 +41,7 @@ link
 	loopbackmedium
 	usbuhci
 	usbohci
-	usbehci
+	usbehci		usbehcipc
 
 misc
 	realmode

+ 4 - 0
sys/src/9/pc/uncached.h

@@ -0,0 +1,4 @@
+/*
+ * On the PC, processor accesses, memory caches and DMA are all
+ * coherent, so we don't need to use uncached memory.
+ */

+ 0 - 194
sys/src/9/pc/usb.h

@@ -1,194 +0,0 @@
-/*
- * common USB definitions.
- */
-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	= 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) */
-};
-
-/*
- * 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*));
-#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);}
-
-extern char *usbmodename[];
-extern char Estalled[];
-
-extern char *seprintdata(char*,char*,uchar*,int);

File diff suppressed because it is too large
+ 0 - 3398
sys/src/9/pc/usbehci.c


+ 82 - 14
sys/src/9/pc/usbehci.h

@@ -1,6 +1,30 @@
+/* override default macros from ../port/usb.h */
+#undef	dprint
+#undef	ddprint
+#undef	deprint
+#undef	ddeprint
+#define dprint		if(ehcidebug)print
+#define ddprint		if(ehcidebug>1)print
+#define deprint		if(ehcidebug || ep->debug)print
+#define ddeprint	if(ehcidebug>1 || ep->debug>1)print
+
+typedef struct Ctlr Ctlr;
 typedef struct Ecapio Ecapio;
-typedef struct Eopio Eopio;
 typedef struct Edbgio Edbgio;
+typedef struct Eopio Eopio;
+typedef struct Isoio Isoio;
+typedef struct Poll Poll;
+typedef struct Qh Qh;
+typedef struct Qtree Qtree;
+
+#pragma incomplete Ctlr;
+#pragma incomplete Ecapio;
+#pragma incomplete Edbgio;
+#pragma incomplete Eopio;
+#pragma incomplete Isoio;
+#pragma incomplete Poll;
+#pragma incomplete Qh;
+#pragma incomplete Qtree;
 
 /*
  * EHCI interface registers and bits
@@ -64,7 +88,7 @@ enum
 	Iall		= 0x3F,		/* all interrupts */
 
 	/* Config reg. */
-	Callmine		= 1,		/* route all ports to us */
+	Callmine	= 1,		/* route all ports to us */
 
 	/* Portsc reg. */
 	Pspresent	= 0x00000001,	/* device present */
@@ -106,7 +130,7 @@ enum
 	/* Debug port addr reg. */
 	Adevshift	= 8,		/* device address */
 	Adevmask	= 0x7F,
-	Aepshift		= 0,		/* endpoint number */
+	Aepshift	= 0,		/* endpoint number */
 	Aepmask		= 0xF,
 };
 
@@ -121,6 +145,56 @@ struct Ecapio
 	ulong	portroute;	/* 0c not on the CS5536 */
 };
 
+/*
+ * Debug port registers (hw)
+ */
+struct Edbgio
+{
+	ulong	csw;		/* control and status */
+	ulong	pid;		/* USB pid */
+	uchar	data[8];	/* data buffer */
+	ulong	addr;		/* device and endpoint addresses */
+};
+
+struct Poll
+{
+	Lock;
+	Rendez;
+	int	must;
+	int	does;
+};
+
+struct Ctlr
+{
+	Rendez;			/* for waiting to async advance doorbell */
+	Lock;			/* for ilock. qh lists and basic ctlr I/O */
+	QLock	portlck;	/* for port resets/enable... (and doorbell) */
+	int	active;		/* in use or not */
+	Pcidev*	pcidev;
+	Ecapio*	capio;		/* Capability i/o regs */
+	Eopio*	opio;		/* Operational i/o regs */
+
+	int	nframes;	/* 1024, 512, or 256 frames in the list */
+	ulong*	frames;		/* periodic frame list (hw) */
+	Qh*	qhs;		/* async Qh circular list for bulk/ctl */
+	Qtree*	tree;		/* tree of Qhs for the periodic list */
+	int	ntree;		/* number of dummy qhs in tree */
+	Qh*	intrqhs;		/* list of (not dummy) qhs in tree  */
+	Isoio*	iso;		/* list of active Iso I/O */
+	ulong	load;
+	ulong	isoload;
+	int	nintr;		/* number of interrupts attended */
+	int	ntdintr;	/* number of intrs. with something to do */
+	int	nqhintr;	/* number of async td intrs. */
+	int	nisointr;	/* number of periodic td intrs. */
+	int	nreqs;
+	Poll	poll;
+};
+
+/*
+ * PC-specific stuff
+ */
+
 /*
  * Operational registers (hw)
  */
@@ -138,16 +212,10 @@ struct Eopio
 	ulong	portsc[1];	/* 44 Port status and control, one per port */
 };
 
-/*
- * Debug port registers (hw)
- */
-struct Edbgio
-{
-	ulong	csw;		/* control and status */
-	ulong	pid;		/* USB pid */
-	uchar	data[8];	/* data buffer */
-	ulong	addr;		/* device and endpoint addresses */
-};
-
+extern int ehcidebug;
 extern Ecapio *ehcidebugcapio;
 extern int ehcidebugport;
+
+void	ehcilinkage(Hci *hp);
+void	ehcimeminit(Ctlr *ctlr);
+void	ehcirun(Ctlr *ctlr, int on);

+ 272 - 0
sys/src/9/pc/usbehcipc.c

@@ -0,0 +1,272 @@
+/*
+ * PC-specific code for
+ * USB Enhanced Host Controller Interface (EHCI) driver
+ * High speed USB 2.0.
+ */
+
+#include	"u.h"
+#include	"../port/lib.h"
+#include	"mem.h"
+#include	"dat.h"
+#include	"fns.h"
+#include	"io.h"
+#include	"../port/error.h"
+#include	"../port/usb.h"
+#include	"usbehci.h"
+
+static Ctlr* ctlrs[Nhcis];
+
+/* Isn't this cap list search in a helper function? */
+static void
+getehci(Ctlr* ctlr)
+{
+	int i, ptr, cap, sem;
+
+	ptr = (ctlr->capio->capparms >> Ceecpshift) & Ceecpmask;
+	for(; ptr != 0; ptr = pcicfgr8(ctlr->pcidev, ptr+1)){
+		if(ptr < 0x40 || (ptr & ~0xFC))
+			break;
+		cap = pcicfgr8(ctlr->pcidev, ptr);
+		if(cap != Clegacy)
+			continue;
+		sem = pcicfgr8(ctlr->pcidev, ptr+CLbiossem);
+		if(sem == 0)
+			continue;
+		pcicfgw8(ctlr->pcidev, ptr+CLossem, 1);
+		for(i = 0; i < 100; i++){
+			if(pcicfgr8(ctlr->pcidev, ptr+CLbiossem) == 0)
+				break;
+			delay(10);
+		}
+		if(i == 100)
+			dprint("ehci %#p: bios timed out\n", ctlr->capio);
+		pcicfgw32(ctlr->pcidev, ptr+CLcontrol, 0);	/* no SMIs */
+		ctlr->opio->config = 0;
+		coherence();
+		return;
+	}
+}
+
+static void
+ehcireset(Ctlr *ctlr)
+{
+	Eopio *opio;
+	int i;
+
+	ilock(ctlr);
+	dprint("ehci %#p reset\n", ctlr->capio);
+	opio = ctlr->opio;
+
+	/*
+	 * Turn off legacy mode. Some controllers won't
+	 * interrupt us as expected otherwise.
+	 */
+	ehcirun(ctlr, 0);
+	pcicfgw16(ctlr->pcidev, 0xc0, 0x2000);
+
+	/*
+	 * reclaim from bios
+	 */
+	getehci(ctlr);
+
+	/* clear high 32 bits of address signals if it's 64 bits capable.
+	 * This is probably not needed but it does not hurt and others do it.
+	 */
+	if((ctlr->capio->capparms & C64) != 0){
+		dprint("ehci: 64 bits\n");
+		opio->seg = 0;
+		coherence();
+	}
+
+	if(ehcidebugcapio != ctlr->capio){
+		opio->cmd |= Chcreset;	/* controller reset */
+		coherence();
+		for(i = 0; i < 100; i++){
+			if((opio->cmd & Chcreset) == 0)
+				break;
+			delay(1);
+		}
+		if(i == 100)
+			print("ehci %#p controller reset timed out\n", ctlr->capio);
+	}
+
+	/* requesting more interrupts per µframe may miss interrupts */
+	opio->cmd |= Citc8;		/* 1 intr. per ms */
+	coherence();
+	switch(opio->cmd & Cflsmask){
+	case Cfls1024:
+		ctlr->nframes = 1024;
+		break;
+	case Cfls512:
+		ctlr->nframes = 512;
+		break;
+	case Cfls256:
+		ctlr->nframes = 256;
+		break;
+	default:
+		panic("ehci: unknown fls %ld", opio->cmd & Cflsmask);
+	}
+	dprint("ehci: %d frames\n", ctlr->nframes);
+	iunlock(ctlr);
+}
+
+static void
+setdebug(Hci*, int d)
+{
+	ehcidebug = d;
+}
+
+static void
+shutdown(Hci *hp)
+{
+	int i;
+	Ctlr *ctlr;
+	Eopio *opio;
+
+	ctlr = hp->aux;
+	ilock(ctlr);
+	opio = ctlr->opio;
+	opio->cmd |= Chcreset;		/* controller reset */
+	coherence();
+	for(i = 0; i < 100; i++){
+		if((opio->cmd & Chcreset) == 0)
+			break;
+		delay(1);
+	}
+	if(i >= 100)
+		print("ehci %#p controller reset timed out\n", ctlr->capio);
+	delay(100);
+	ehcirun(ctlr, 0);
+	opio->frbase = 0;
+	iunlock(ctlr);
+}
+
+static void
+scanpci(void)
+{
+	static int already = 0;
+	int i;
+	ulong io;
+	Ctlr *ctlr;
+	Pcidev *p;
+	Ecapio *capio;
+
+	if(already)
+		return;
+	already = 1;
+	p = nil;
+	while ((p = pcimatch(p, 0, 0)) != nil) {
+		/*
+		 * Find EHCI controllers (Programming Interface = 0x20).
+		 */
+		if(p->ccrb != Pcibcserial || p->ccru != Pciscusb)
+			continue;
+		switch(p->ccrp){
+		case 0x20:
+			io = p->mem[0].bar & ~0x0f;
+			break;
+		default:
+			continue;
+		}
+		if(io == 0){
+			print("usbehci: %x %x: failed to map registers\n",
+				p->vid, p->did);
+			continue;
+		}
+		if(p->intl == 0xff || p->intl == 0) {
+			print("usbehci: no irq assigned for port %#lux\n", io);
+			continue;
+		}
+		dprint("usbehci: %#x %#x: port %#lux size %#x irq %d\n",
+			p->vid, p->did, io, p->mem[0].size, p->intl);
+
+		ctlr = mallocz(sizeof(Ctlr), 1);
+		ctlr->pcidev = p;
+		capio = ctlr->capio = vmap(io, p->mem[0].size);
+		ctlr->opio = (Eopio*)((uintptr)capio + (capio->cap & 0xff));
+		pcisetbme(p);
+		pcisetpms(p, 0);
+		for(i = 0; i < Nhcis; i++)
+			if(ctlrs[i] == nil){
+				ctlrs[i] = ctlr;
+				break;
+			}
+		if(i == Nhcis)
+			print("ehci: bug: more than %d controllers\n", Nhcis);
+
+		/*
+		 * currently, if we enable a second ehci controller,
+		 * we'll wedge solid after iunlock in init for the second one.
+		 */
+		if (i > 0 && i < Nhcis) {
+			iprint("usbehci: ignoring controllers after the first, "
+				"at %#p\n", io);
+			ctlrs[i] = nil;
+		}
+	}
+}
+
+static int
+reset(Hci *hp)
+{
+	int i;
+	Ctlr *ctlr;
+	Ecapio *capio;
+	Pcidev *p;
+	static Lock resetlck;
+
+	if(getconf("*nousbehci"))
+		return -1;
+	ilock(&resetlck);
+	scanpci();
+
+	/*
+	 * Any adapter matches if no hp->port is supplied,
+	 * otherwise the ports must match.
+	 */
+	ctlr = nil;
+	for(i = 0; i < Nhcis && ctlrs[i] != nil; i++){
+		ctlr = ctlrs[i];
+		if(ctlr->active == 0)
+		if(hp->port == 0 || hp->port == (uintptr)ctlr->capio){
+			ctlr->active = 1;
+			break;
+		}
+	}
+	iunlock(&resetlck);
+	if(i >= Nhcis || ctlrs[i] == nil)
+		return -1;
+
+	p = ctlr->pcidev;
+	hp->aux = ctlr;
+	hp->port = (uintptr)ctlr->capio;
+	hp->irq = p->intl;
+	hp->tbdf = p->tbdf;
+
+	capio = ctlr->capio;
+	hp->nports = capio->parms & Cnports;
+
+	ddprint("echi: %s, ncc %lud npcc %lud\n",
+		capio->parms & 0x10000 ? "leds" : "no leds",
+		(capio->parms >> 12) & 0xf, (capio->parms >> 8) & 0xf);
+	ddprint("ehci: routing %s, %sport power ctl, %d ports\n",
+		capio->parms & 0x40 ? "explicit" : "automatic",
+		capio->parms & 0x10 ? "" : "no ", hp->nports);
+
+	ehcireset(ctlr);
+	ehcimeminit(ctlr);
+
+	/*
+	 * Linkage to the generic HCI driver.
+	 */
+	ehcilinkage(hp);
+	hp->shutdown = shutdown;
+	hp->debug = setdebug;
+	return 0;
+}
+
+void
+usbehcilink(void)
+{
+	addhcitype("ehci", reset);
+}

+ 1 - 1
sys/src/9/pc/usbohci.c

@@ -18,7 +18,7 @@
 #include	"io.h"
 #include	"../port/error.h"
 
-#include	"usb.h"
+#include	"../port/usb.h"
 
 typedef struct Ctlio Ctlio;
 typedef struct Ctlr Ctlr;

+ 1 - 1
sys/src/9/pc/usbuhci.c

@@ -15,7 +15,7 @@
 #include	"fns.h"
 #include	"io.h"
 #include	"../port/error.h"
-#include	"usb.h"
+#include	"../port/usb.h"
 
 typedef struct Ctlio Ctlio;
 typedef struct Ctlr Ctlr;

+ 8 - 6
sys/src/9/kw/usb.h

@@ -1,6 +1,14 @@
 /*
  * 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 */
@@ -181,12 +189,6 @@ struct Udev
 };
 
 void	addhcitype(char *type, int (*reset)(Hci*));
-#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);}
 
 extern char *usbmodename[];
 extern char Estalled[];

File diff suppressed because it is too large
+ 135 - 348
sys/src/9/omap/usbehci.c


+ 15 - 14
sys/src/cmd/usb/serial/serial.c

@@ -112,16 +112,17 @@ serialrecover(Serial *ser, Serialport *p, Dev *ep, char *err)
 	if(strstr(err, "detached") != nil)
 		return -1;
 	if(ser->recover < 3){
-		if(ep != nil){
-			if(p->epintr != nil && ep == p->epintr)
-				unstall(ser->dev, p->epintr, Ein);
-			if(p->epin != nil && ep == p->epin)
-				unstall(ser->dev, p->epin, Ein);
-			if(p->epout != nil && ep == p->epout)
-				unstall(ser->dev, p->epout, Eout);
-			return 0;
-		}
-		if(p != nil){
+		if(p != nil){	
+			if(ep != nil){
+				if(ep == p->epintr)
+					unstall(ser->dev, p->epintr, Ein);
+				if(ep == p->epin)
+					unstall(ser->dev, p->epin, Ein);
+				if(ep == p->epout)
+					unstall(ser->dev, p->epout, Eout);
+				return 0;
+			}
+
 			if(p->epintr != nil)
 				unstall(ser->dev, p->epintr, Ein);
 			if(p->epin != nil)
@@ -267,7 +268,7 @@ serialctl(Serialport *p, char *cmd)
 			else
 				nw = write(p->epout->dfd, &x, 1);
 			if(nw != 1){
-				serialrecover(ser, nil, p->epout, "");
+				serialrecover(ser, p, p->epout, "");
 				return -1;
 			}
 			break;
@@ -535,7 +536,7 @@ dread(Usbfs *fs, Fid *fid, void *data, long count, vlong offset)
 		if(rcount < 0){
 			dsprint(2, "serial: need to recover, data read %ld %r\n",
 				count);
-			serialrecover(ser, nil, p->epin, err);
+			serialrecover(ser, p, p->epin, err);
 		}
 		dsprint(2, "serial: read from bulk %ld\n", rcount);
 		count = rcount;
@@ -587,7 +588,7 @@ altwrite(Serialport *p, uchar *buf, long count)
 		dsprint(2, "serial: need to recover, status in write %d %r\n",
 			nw);
 		snprint(err, sizeof err, "%r");
-		serialrecover(p->s, nil, p->epout, err);
+		serialrecover(p->s, p, p->epout, err);
 	}
 	return nw;
 }
@@ -631,7 +632,7 @@ dwrite(Usbfs *fs, Fid *fid, void *buf, long count, vlong)
 	if(count >= 0)
 		ser->recover = 0;
 	else
-		serialrecover(ser, nil, p->epout, "writing");
+		serialrecover(ser, p, p->epout, "writing");
 	qunlock(ser);
 	return count;
 }