~kris/9p

9hist

12bb3867cea8b5ebc9fa18e6804338ac82b1cc0d — David du Colombier 27 years ago bb6464d
Plan 9 from Bell Labs 1999-05-26
2 files changed, 41 insertions(+), 640 deletions(-)

M pc/devlml.c
M port/alloc.c
M pc/devlml.c => pc/devlml.c +38 -637
@@ 12,51 12,27 @@ static void *		pciPhysBaseAddr;
static ulong		pciBaseAddr;
static Pcidev *		pcidev;

#define DBGREGS 0x01
#define DBGREAD 0x02
#define DBGWRIT 0x04
#define DBG819	0x08
#define DBGINTR	0x10
#define DBGINTS	0x20
#define DBGREAD 0x01
#define DBGWRIT 0x02
#define DBGINTR	0x04
#define DBGINTS	0x08

int debug = 0;

// Lml 22 driver

#ifdef MEMMAP
struct {
	ulong pci;
	ulong statcom;
	ulong codedata;
} lmlmap;
#endif

enum{
	Qdir,
#ifdef MEMMAP
	Q060,
	Q819,
	Q856,
	Qreg,
	Qmap,
	Qbuf,
#endif
	Qjvideo,
	Qjframe,
	Qjcount,
};

static Dirtab lmldir[]={
//	 name,		 qid,		size,		mode
#ifdef MEMMAP
	"lml060",	{Q060},		0x400,		0644,
	"lml819",	{Q819},		0,		0644,
	"lml856",	{Q856},		0,		0644,
	"lmlreg",	{Qreg},		0x400,		0644,
	"lmlmap",	{Qmap},		sizeof lmlmap,	0444,
	"lmlbuf",	{Qbuf},		0,		0644,
#endif
	"jvideo",	{Qjvideo},	0,		0666,
	"jframe",	{Qjframe},	0,		0666,
	"jcount",	{Qjcount},	0,		0444,
};

CodeData *	codeData;


@@ 82,402 58,34 @@ static FrameHeader frameHeader = {
};


#ifndef MEMMAP
#define writel(v, a) *(ulong *)(a) = (v)
#define readl(a) *(ulong*)(a)
#else
ulong
writel(ulong v, ulong a) {
	if (debug&DBGREGS)
		pprint("%.8lux (%.8lux) <-- %.8lux\n",
			a, (ulong)a-pciBaseAddr, v);
	return *(ulong *)a = v;
}

ulong
readl(ulong a) {
	ulong v;

	v = *(ulong*)a;
	if (debug&DBGREGS)
		pprint("%.8lux (%.8lux) --> %.8lux\n",
			a, (ulong)a-pciBaseAddr, v);
	return v;
}
ushort
writew(ushort v, ulong a) {
	if (debug&DBGREGS)
		pprint("%.8lux (%.8lux) <--     %.4ux\n",
			a, (ulong)a-pciBaseAddr, v);
	return *(ushort *)a = v;
}

uchar
writeb(uchar v, ulong a) {
	if (debug&DBGREGS)
		pprint("%.8lux (%.8lux) <--       %.2ux\n",
			a, (ulong)a-pciBaseAddr, v);
	return *(uchar *)a = v;
}

ushort
readw(ulong a) {
	ushort v;

	v = *(ushort*)a;
	if (debug&DBGREGS)
		pprint("%.8lux (%.8lux) -->     %.4ux\n",
			a, (ulong)a-pciBaseAddr, v);
	return v;
}

uchar
readb(ulong a) {
	uchar v;

	v = *(uchar*)a;
	if (debug&DBGREGS)
		pprint("%.8lux (%.8lux) -->       %.2ux\n",
			a, (ulong)a-pciBaseAddr, v);
	return v;
}

static void
i2c_pause(void) {

	microdelay(I2C_DELAY);
}

static void
i2c_waitscl(void) {
	int i;

	for (i = 0; i < I2C_TIMEOUT; i++)
		if (readl(pciBaseAddr + I2C_BUS) & I2C_SCL)
			return;
	error(Eio);
}

static void
i2c_start(void) {

	writel(I2C_SCL|I2C_SDA, pciBaseAddr + I2C_BUS);
	i2c_waitscl();
	i2c_pause();

	writel(I2C_SCL, pciBaseAddr + I2C_BUS);
	i2c_pause();

	writel(0, pciBaseAddr + I2C_BUS);
	i2c_pause();
}

static void
i2c_stop(void) {
	// the clock should already be low, make sure data is
	writel(0, pciBaseAddr + I2C_BUS);
	i2c_pause();

	// set clock high and wait for device to catch up
	writel(I2C_SCL, pciBaseAddr + I2C_BUS);
	i2c_waitscl();
	i2c_pause();

	// set the data high to indicate the stop bit
	writel(I2C_SCL|I2C_SDA, pciBaseAddr + I2C_BUS);
	i2c_pause();
}

static void i2c_wrbit(int bit) {
	if (bit){
		writel(I2C_SDA, pciBaseAddr + I2C_BUS); // set data
		i2c_pause();
		writel(I2C_SDA|I2C_SCL, pciBaseAddr + I2C_BUS);
		i2c_waitscl();
		i2c_pause();
		writel(I2C_SDA, pciBaseAddr + I2C_BUS);
		i2c_pause();
	} else {
		writel(0, pciBaseAddr + I2C_BUS); // clr data
		i2c_pause();
		writel(I2C_SCL, pciBaseAddr + I2C_BUS);
		i2c_waitscl();
		i2c_pause();
		writel(0, pciBaseAddr + I2C_BUS);
		i2c_pause();
	}
}

static int
i2c_rdbit(void) {
	int bit;
	// the clk line should be low

	// ensure we are not asserting the data line
	writel(I2C_SDA, pciBaseAddr + I2C_BUS);
	i2c_pause();

	// set the clock high and wait for device to catch up
	writel(I2C_SDA|I2C_SCL, pciBaseAddr + I2C_BUS);
	i2c_waitscl();
	i2c_pause();

	// the data line should be a valid bit
	bit = readl(pciBaseAddr+I2C_BUS);
	if (bit & I2C_SDA){
		bit = 1;
	} else {
		bit = 0;
getbuffer(void){
	static last = NBUF-1;
	int l = last;

	for (;;) {
		last = (last+1) % NBUF;
		if (codeData->statCom[last] & STAT_BIT)
			return last;
		if (last == l)
			sleep(&sleeper, return0, 0);
	}

	// set the clock low to indicate end of cycle
	writel(I2C_SDA, pciBaseAddr + I2C_BUS);
	i2c_pause();

	return bit;
	return 0;
}

static int
i2c_rdbyte(uchar *v) {
	int i, ack;
	uchar res;

	res = 0;
	for (i = 0; i < 8; i++) {
		res  = res << 1;
		res += i2c_rdbit();
	}

	ack = i2c_rdbit();

	*v = res;

	return ack;
}

static int
i2c_wrbyte(uchar v) {
	int i, ack;

	for (i = 0; i < 8; i++) {
		i2c_wrbit(v & 0x80);
		v = v << 1;
	}

	ack = i2c_rdbit();

	return ack;
}

static void
i2c_write_bytes(uchar addr, uchar sub, uchar *bytes, long num) {
	int ack;
	long i;

	i2c_start();

	ack = i2c_wrbyte(addr);
	if (ack == 1) error(Eio);

	ack = i2c_wrbyte(sub);
	if (ack == 1) error(Eio);

	for (i = 0; i < num; i++) {
		ack = i2c_wrbyte(bytes[i]);
		if (ack == 1) error(Eio);
	}

	i2c_stop();
}

static int
i2c_bt856rd8(void) {
	uchar ret;

	i2c_start ();

	if (i2c_wrbyte(BT856Addr + 1) == 1
	 || i2c_rdbyte(&ret) == 0) {
		i2c_stop ();
		return -1;
	}

	i2c_stop ();
	return ret;
}

static int
i2c_rd8(int addr, int sub)
{
	uchar msb;

	i2c_start();

	if (i2c_wrbyte(addr) == 1
	 || i2c_wrbyte(sub) == 1) {
		if (debug&DBGREGS) pprint("i2c_rd8, failure 1\n");
		i2c_stop();
		return -1;
	}

	i2c_start();

	if (i2c_wrbyte(addr+1) == 1
	 || i2c_rdbyte(&msb) == 0){
		if (debug&DBGREGS) pprint("i2c_rd8, failure 2\n");
		i2c_stop();
		return -1;
	}

	i2c_stop();

	return msb;
}

static int
i2c_wr8(uchar addr, uchar sub, uchar msb) {
	
	i2c_start();
static long
vcount(Chan *, void *va, long nbytes, vlong) {
	char *p = (char *)va;

	if (i2c_wrbyte(addr) == 1
	 || i2c_wrbyte(sub) == 1
	 || i2c_wrbyte(msb) == 1)
		return 0;
	
	i2c_stop();
	
	// reads always return one byte: the next available buffer number
	if (nbytes <= 0) return 0;
	*p = getbuffer();
	return 1;
}

/*
 * The following mapping applies for the guests in the LML33
 *
 * Guest        Device
 *   0          zr36060
 *              uses subaddress GADR[0..1]
 *   1          zr36060 START#
 *   2          -
 *   3          zr36060 RESET#
 *   4          -
 *   5          -
 *   6          -
 *   7          -
 */

// post_idle waits for the guest bus to become free
static int
post_idle(void) {
	ulong a;
	int timeout;

	for (timeout = 0; timeout < GUEST_TIMEOUT; timeout++){
		a = readl(pciBaseAddr + POST_OFFICE);
		if ((a & POST_PEND) == 0) 
			return a;
	}
	pprint("post_idle timeout\n");
	return -1;
}

// post_write writes a byte to a guest using postoffice mechanism
int
post_write(unsigned int guest, unsigned int reg, unsigned int v) {
	int w;

	// wait for postoffice not busy
	post_idle();

	// Trim the values, just in case
	guest &= 0x07;
	reg   &= 0x07;
	v     &= 0xFF;

	// write postoffice operation
	w = POST_DIR | (guest<<20) | (reg<<16) | v;
	writel(w, pciBaseAddr + POST_OFFICE);

	// wait for postoffice not busy
	return post_idle() == -1;
}

// post_read reads a byte from a guest using postoffice mechanism
int
post_read(int guest, int reg) {
	int w;

	// wait for postoffice not busy
	post_idle();

	// Trim the values, just in case
	guest &= 0x07;
	reg   &= 0x07;

	// write postoffice operation
	w = (guest<<20) + (reg<<16);
	writel(w, pciBaseAddr + POST_OFFICE);

	// wait for postoffice not busy, get result
	w = post_idle();

	// decide if read went ok
	if (w == -1) return -1;

	return w & 0xFF;
}

static int
zr060_write(int reg, int v) {
  
	if (post_write(GID060, 1, (reg>>8) & 0x03)
	 || post_write(GID060, 2, reg & 0xff)
	 || post_write(GID060, 3, v))
		return -1;
}

static int
zr060_read(int reg) {
  
	if (post_write(GID060, 1, (reg>>8) & 0x03)
	 || post_write(GID060, 2, reg    & 0xff))
		return -1;
	return post_read(GID060, 3);
}
#endif

static int
prepareBuffer(int i) {
	if (i >= 0 && i < NBUF && (codeData->statCom[i] & STAT_BIT)) {
		codeData->statCom[i] = PADDR(&(codeData->fragdesc[i]));
    		return codeData->fragdesc[i].leng;
	} else
		return -1;
}

static int
getProcessedBuffer(void){
	static lastBuffer = NBUF-1;
	int l = lastBuffer;

	while (1) { 
		lastBuffer = (lastBuffer+1) % NBUF;
		if (codeData->statCom[lastBuffer] & STAT_BIT)
			return lastBuffer;
		if (lastBuffer == l)
			break;
	}
	return -1;
}

static int
getBuffer(int i, int* frameNo) {

	if(codeData->statCom[i] & STAT_BIT) {
		*frameNo = codeData->statCom[i] >> 24;
		return (codeData->statCom[i] & 0x00FFFFFF) >> 1;
	} else
		return -1;
}

static long
vread(Chan *, void *va, long nbytes, vlong) {
	static int bufpos;


@@ 495,20 103,20 @@ vread(Chan *, void *va, long nbytes, vlong) {
	while (count > 0) {
		switch (state) {
		case New:
			while ((curbuf = getProcessedBuffer()) == -1)
				sleep(&sleeper, return0, 0);
			fragsize = getBuffer(curbuf, &frameno);
			curbuf = getbuffer();
			frameNo = codeData->statCom[curbuf] >> 24;
			fragsize = (codeData->statCom[curbuf] & 0x00ffffff)>>1;
			if (debug & DBGREAD)
				pprint("devlml: got read buf %d, fr %d, size %d\n",
					curbuf, frameNo, fragsize);
			if (frameno != (frameprev + 1) % 256)
			if (!singleFrame && frameno != (frameprev + 1) % 256)
				pprint("Frame out of sequence: %d %d\n",
					frameprev, frameno);
			frameprev = frameno;
			if (fragsize <= 0 || fragsize > sizeof(Fragment)) {
				pprint("Wrong sized fragment, %d (ignored)\n",
					fragsize);
				prepareBuffer(curbuf);
				codeData->statCom[curbuf] = PADDR(&(codeData->fragdesc[curbuf]));
				break;
			}
			// Fill in APP marker fields here


@@ 550,7 158,7 @@ vread(Chan *, void *va, long nbytes, vlong) {
			p += i;

			// Allow reuse of current buffer
			prepareBuffer(curbuf);
			codeData->statCom[curbuf] = PADDR(&(codeData->fragdesc[curbuf]));
			state = New;
			if (singleFrame) {
				state = Error;


@@ 577,11 185,7 @@ vwrite(Chan *, void *va, long nbytes, vlong) {
	while (count > 0) {
		switch (state) {
		case New:
			while((curbuf = getProcessedBuffer()) == -1) {
				if (debug&DBGWRIT)
					pprint("devlml::sleep\n");
				sleep(&sleeper, return0, 0);
			}
			curbuf = getbuffer();
			if (debug&DBGWRIT)
				pprint("current buffer %d\n", curbuf);
			bufptr = codeData->frag[curbuf].fb;


@@ 638,9 242,9 @@ vwrite(Chan *, void *va, long nbytes, vlong) {
			p += i;
			count -= i;
			// We have written the frame, time to display it
			i = prepareBuffer(curbuf);
			codeData->statCom[curbuf] = PADDR(&(codeData->fragdesc[curbuf]));
			if (debug&DBGWRIT)
				pprint("Sending buffer %d: %d\n", curbuf, i);
				pprint("Sending buffer %d\n", curbuf);
			if (singleFrame) {
				state = Error;
				return nbytes - count;


@@ 658,10 262,8 @@ static void lmlintr(Ureg *, void *);
static void
lmlreset(void)
{
// LMLSEG
	Physseg segbuf;
	Physseg segreg;
//
	ulong regpa;
	ulong cdsize;
	int i;


@@ 682,7 284,7 @@ lmlreset(void)

	// Get access to DMA memory buffer
	memset(codeData, 0xAA, sizeof(CodeData));
	codeData->physaddr = PADDR(&(codeData->statCom[0]));
	codeData->physaddr = PADDR(codeData->statCom);
	for (i = 0; i < NBUF; i++) {
		codeData->statCom[i] = PADDR(&(codeData->fragdesc[i]));
		codeData->fragdesc[i].addr = PADDR(&(codeData->frag[i]));


@@ 704,23 306,9 @@ lmlreset(void)
	pciBaseAddr = (ulong)KADDR(regpa);
	print(", mapped at 0x%.8lux\n", pciBaseAddr);

	// make sure the device will respond to mem accesses
	// (pcicmd_master | pcicmd_memory) -- probably superfluous
//	pcicfgw32(pcidev, PciPCR, 0x04 | 0x02);

	// set bus latency -- probably superfluous
//	pcicfgw8(pcidev, PciLTR, 64);

	// Interrupt handler
	intrenable(pcidev->intl, lmlintr, nil, pcidev->tbdf);

#ifdef MEMMAP
	lmlmap.pci = pciBaseAddr;
	lmlmap.statcom = PADDR(codeData->statCom);
	lmlmap.codedata = (ulong)codeData;
#endif

// LMLSEG
	memset(&segbuf, 0, sizeof(segbuf));
	segbuf.attr = SG_PHYSICAL;
	segbuf.name = smalloc(NAMELEN);


@@ 742,8 330,6 @@ lmlreset(void)
		print("lml: physsegment: lmlmjpg\n");
		return;
	}
//

	return; 
}



@@ 771,17 357,9 @@ lmlopen(Chan *c, int omode) {

	c->aux = 0;
	switch(c->qid.path){
#ifdef MEMMAP
	case Q060:
	case Q819:
	case Q856:
	case Qreg:
	case Qmap:
	case Qbuf:
		break;
#endif
	case Qjframe:
	case Qjvideo:
	case Qjcount:
		if (nopens)
			error(Einuse);
		nopens = 1;


@@ 800,18 378,9 @@ static void
lmlclose(Chan *c) {

	switch(c->qid.path){
#ifdef MEMMAP
	case Q060:
	case Q819:
	case Q856:
	case Qreg:
	case Qmap:
	case Qbuf:
		authclose(c);
		break;
#endif
	case Qjvideo:
	case Qjframe:
	case Qjcount:
		nopens = 0;
		authclose(c);
	}


@@ 819,9 388,6 @@ lmlclose(Chan *c) {

static long
lmlread(Chan *c, void *va, long n, vlong voff) {
#ifdef MEMMAP
	int i, d;
#endif
	uchar *buf = va;
	long off = voff;



@@ 829,188 395,23 @@ lmlread(Chan *c, void *va, long n, vlong voff) {

	case Qdir:
		return devdirread(c, (char *)buf, n, lmldir, nelem(lmldir), devgen);

#ifdef MEMMAP
	case Q060:
		if (off < 0 || off + n > 0x400)
			return 0;
		for (i = 0; i < n; i++) {
			if ((d = zr060_read(off + i)) < 0) break;
			*buf++ = d;
		}
		return i;
	case Q819:
		if (off < 0 || off + n > 0x20)
			return 0;
		for (i = 0; i < n; i++) {
			if ((d = i2c_rd8(BT819Addr, off++)) < 0) break;
			*buf++ = d;
		}
		return i;
	case Q856:
		if (n != 1)
			return 0;
		switch ((int)off) {
		case 0:
			if ((d = i2c_bt856rd8()) < 0)
				return 0;
			*buf = d;
			break;
		case 0xDA:
			*buf = q856[0];
			break;
		case 0xDC:
			*buf = q856[1];
			break;
		case 0xDE:
			*buf = q856[2];
			break;
		default:
			return 0;
		}
		return 1;
	case Qmap:
		if (off < 0)
			return 0;
		for (i = 0; i < n; i++) {
			if (off + i >= sizeof lmlmap)
				break;
			buf[i] = ((uchar *)&lmlmap)[off + i];
		}
		return i;
	case Qreg:
		if (off < 0 || off + n >= 0x400)
			return 0;
		switch(n) {
		case 1:
			*buf = readb(pciBaseAddr + off);
			break;
		case 2:
			if (off & (n-1)) return 0;
			*(short *)buf = readw(pciBaseAddr + off);
			break;
		case 4:
			if (off & (n-1)) return 0;
			*(long *)buf = readl(pciBaseAddr + off);
			break;
		default:
			return 0;
		}
		return n;
	case Qbuf:
		if (off < 0 || off + n >= sizeof *codeData)
			return 0;
		switch(n) {
		case 1:
			*buf = readb((ulong)codeData + off);
			break;
		case 2:
			if (off & (n-1)) return 0;
			*(short *)buf = readw((ulong)codeData + off);
			break;
		case 4:
			if (off & (n-1)) return 0;
			*(long *)buf = readl((ulong)codeData + off);
			break;
		default:
			return 0;
		}
		return n;
#endif
	case Qjvideo:
	case Qjframe:
		return vread(c, buf, n, off);
	case Qjcount:
		return vcount(c, buf, n, off);
	}
}

static long
lmlwrite(Chan *c, void *va, long n, vlong voff) {
#ifdef MEMMAP
	int i;
#endif
	uchar *buf = va;
	long off = voff;

	switch(c->qid.path & ~CHDIR){

	case Qdir:
	case Qjcount:
		error(Eperm);

#ifdef MEMMAP
	case Q060:
		if (off < 0 || off + n > 0x400)
			return 0;
		for (i = 0; i < n; i++) {
			if (zr060_write(off + i, *buf++) < 0) break;
		}
		return i;
	case Q819:
		if (off < 0 || off + n >= 0x20)
			return 0;
		for (i = 0; i < n; i++)
			if (i2c_wr8(BT819Addr, off + i, *buf++) == 0)
				break;
		return i;
	case Q856:
		if (n != 1 || off < 0xda || off + n > 0xe0)
			return 0;
		if (i2c_wr8(BT856Addr, off, *buf) == 0)
				return 0;
		switch ((int)off) {
		case 0xDA:
			q856[0] = *buf;
			break;
		case 0xDC:
			q856[1] = *buf;
			break;
		case 0xDE:
			q856[2] = *buf;
			break;
		}
		return 1;
	case Qreg:
		if (off < 0 || off + n >= 0x400)
			return 0;
		switch (n) {
		case 1:
			writeb(*buf, pciBaseAddr + off);
			break;
		case 2:
			if (off & 0x1)
				return 0;
			writew(*(short *)buf, pciBaseAddr + off);
			break;
		case 4:
			if (off & 0x3)
				return 0;
			writel(*(long *)buf, pciBaseAddr + off);
			break;
		default:
			return 0;
		}
		return n;
	case Qbuf:
		if (off < 0 || off + n >= sizeof *codeData)
			return 0;
		switch (n) {
		case 1:
			writeb(*buf, (ulong)codeData + off);
			break;
		case 2:
			if (off & 0x1)
				return 0;
			writew(*(short *)buf, (ulong)codeData + off);
			break;
		case 4:
			if (off & 0x3)
				return 0;
			writel(*(long *)buf, (ulong)codeData + off);
			break;
		default:
			return 0;
		}
		return n;
#endif
	case Qjvideo:
	case Qjframe:
		return vwrite(c, buf, n, off);

M port/alloc.c => port/alloc.c +3 -3
@@ 368,7 368,7 @@ malloc(ulong size)
	v = poolalloc(mainmem, size);
	if(v != nil)
		memset(v, 0, size);
{
if(v != nil){
Bhdr *h;
D2B(h, v);
B2T(h)->pad = getcallerpc(&size);


@@ 403,11 403,11 @@ mallocz(ulong size, int clr)

	v = poolalloc(mainmem, size);
	if(clr && v != nil)
{
		memset(v, 0, size);
if(v != nil){
Bhdr *h;
D2B(h, v);
B2T(h)->pad = getcallerpc(&size);
		memset(v, 0, size);
}
	return v;
}