~kris/9p

9hist

d2a20e0abc18e86bac9e72d3c9749604aba60e19 — David du Colombier 25 years ago d52f338
Plan 9 from Bell Labs 2000-10-21
A bitsy/devpenmouse.c => bitsy/devpenmouse.c +447 -0
@@ 0,0 1,447 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"../port/error.h"

#define	Image	IMAGE
#include	<draw.h>
#include	<memdraw.h>
#include	<cursor.h>
#include	"screen.h"

typedef struct Mouseinfo	Mouseinfo;
typedef struct Mousestate	Mousestate;
typedef struct Calibration	Calibration;

struct Calibration
{
	long	scalex;
	long	scaley;
	long	transx;
	long	transy;
} calibration = {
	-0x10000*0x400/320,
	-0x10000*0x400/240,
	320,
	240
};

struct Mousestate
{
	Point	xy;			/* mouse.xy */
	int		buttons;	/* mouse.buttons */
	ulong	counter;	/* increments every update */
	ulong	msec;		/* time of last event */
};

struct Mouseinfo
{
	Mousestate;
	ulong	lastcounter;	/* value when /dev/mouse read */
	Rendez	r;
	Ref;
	QLock;
	int	open;
	int	inopen;
	Mousestate 	queue[16];	/* circular buffer of click events */
	int	ri;	/* read index into queue */
	int	wi;	/* write index into queue */
	uchar	qfull;	/* queue is full */
};

Mouseinfo	mouse;
int		mouseshifted;

int	penmousechanged(void*);
static void	penmousetrack(int b, int x, int y);

enum{
	Qdir,
	Qmouse,
	Qmousein,
	Qmousectl,
};

static Dirtab mousedir[]={
	"mouse",	{Qmouse},		0,			0666,
	"mousein",	{Qmousein},		0,			0220,
	"mousectl",	{Qmousectl},	0,			0220,
};

static uchar buttonmap[8] = {
	0, 1, 2, 3, 4, 5, 6, 7,
};
static int mouseswap;

extern	Memimage*	gscreen;

void
penbutton(int up, int b) {
	if (up)
		mouse.buttons &= ~ (1 << b);
	else
		mouse.buttons |= 1 << b;
	penmousetrack(mouse.buttons, -1, -1);
}

void
pentrackxy(int x, int y) {
	if (x == -1) {
		/* pen up. associate with button 1, 2, 3 up */
		if (mouse.buttons & 0x7)
			mouse.buttons &= ~0x7;
	} else {
		x = (x<<16)/calibration.scalex + calibration.transx;
		y = (y<<16)/calibration.scaley + calibration.transy;
	}
	penmousetrack(mouse.buttons, x, y);
}

static void
penmousereset(void)
{
	if(!conf.monitor)
		return;
}

static void
penmouseinit(void)
{
	if(!conf.monitor)
		return;
}

static Chan*
penmouseattach(char *spec)
{
	if(!conf.monitor)
		error(Egreg);
	return devattach('m', spec);
}

static Chan*
penmouseclone(Chan *c, Chan *nc)
{
	nc = devclone(c, nc);
	if(c->qid.path != CHDIR)
		incref(&mouse);
	return nc;
}

static int
penmousewalk(Chan *c, char *name)
{
	return devwalk(c, name, mousedir, nelem(mousedir), devgen);
}

static void
penmousestat(Chan *c, char *db)
{
	devstat(c, db, mousedir, nelem(mousedir), devgen);
}

static Chan*
penmouseopen(Chan *c, int omode)
{
	switch(c->qid.path){
	case CHDIR:
		if(omode != OREAD)
			error(Eperm);
		break;
	case Qmouse:
		lock(&mouse);
		if(mouse.open){
			unlock(&mouse);
			error(Einuse);
		}
		mouse.open = 1;
		mouse.ref++;
		unlock(&mouse);
		break;
	case Qmousein:
	/*	error("disabled");	*/
		lock(&mouse);
		if(mouse.inopen){
			unlock(&mouse);
			error(Einuse);
		}
		mouse.inopen = 1;
		unlock(&mouse);
		break;
	default:
		incref(&mouse);
	}
	c->mode = openmode(omode);
	c->flag |= COPEN;
	c->offset = 0;
	return c;
}

static void
penmousecreate(Chan*, char*, int, ulong)
{
	if(!conf.monitor)
		error(Egreg);
	error(Eperm);
}

static void
penmouseclose(Chan *c)
{
	if(c->qid.path!=CHDIR && (c->flag&COPEN)){
		lock(&mouse);
		if(c->qid.path == Qmouse)
			mouse.open = 0;
		else if(c->qid.path == Qmousein){
			mouse.inopen = 0;
			unlock(&mouse);
			return;
		}
		--mouse.ref;
		unlock(&mouse);
	}
}


static long
penmouseread(Chan *c, void *va, long n, vlong)
{
	char buf[4*12+1];
	static int map[8] = {0, 4, 2, 6, 1, 5, 3, 7 };
	Mousestate m;
	int b;

	switch(c->qid.path){
	case CHDIR:
		return devdirread(c, va, n, mousedir, nelem(mousedir), devgen);

	case Qmouse:
		while(penmousechanged(0) == 0)
			sleep(&mouse.r, penmousechanged, 0);

		mouse.qfull = 0;

		/*
		 * No lock of the indicies is necessary here, because ri is only
		 * updated by us, and there is only one mouse reader
		 * at a time.  I suppose that more than one process
		 * could try to read the fd at one time, but such behavior
		 * is degenerate and already violates the calling
		 * conventions for sleep above.
		 */
		if(mouse.ri != mouse.wi) {
			m = mouse.queue[mouse.ri];
			if(++mouse.ri == nelem(mouse.queue))
				mouse.ri = 0;
		} else {
			m = mouse.Mousestate;
		}

		b = buttonmap[m.buttons&7];
		/* put buttons 4 and 5 back in */
		b |= m.buttons & (3<<3);
		sprint(buf, "m%11d %11d %11d %11lud",
			m.xy.x, m.xy.y,
			b,
			m.msec);
		mouse.lastcounter = m.counter;
		if(n > 1+4*12)
			n = 1+4*12;
		memmove(va, buf, n);
		return n;
	}
	return 0;
}

static void
setbuttonmap(char* map)
{
	int i, x, one, two, three;

	one = two = three = 0;
	for(i = 0; i < 3; i++){
		if(map[i] == 0)
			error(Ebadarg);
		if(map[i] == '1'){
			if(one)
				error(Ebadarg);
			one = 1<<i;
		}
		else if(map[i] == '2'){
			if(two)
				error(Ebadarg);
			two = 1<<i;
		}
		else if(map[i] == '3'){
			if(three)
				error(Ebadarg);
			three = 1<<i;
		}
		else
			error(Ebadarg);
	}
	if(map[i])
		error(Ebadarg);

	memset(buttonmap, 0, 8);
	for(i = 0; i < 8; i++){
		x = 0;
		if(i & 1)
			x |= one;
		if(i & 2)
			x |= two;
		if(i & 4)
			x |= three;
		buttonmap[x] = i;
	}
}

static long
penmousewrite(Chan *c, void *va, long n, vlong)
{
	char *p;
	Point pt;
	char buf[64], *field[3];
	int nf, b;

	p = va;
	switch(c->qid.path){
	case CHDIR:
		error(Eisdir);

	case Qmousectl:
		if(n >= sizeof(buf))
			n = sizeof(buf)-1;
		strncpy(buf, va, n);
		if(buf[n - 1] == '\n')
			buf[n-1] = 0;
		else
			buf[n] = 0;
		nf = getfields(buf, field, 3, 1, " ");
		if(strcmp(field[0], "swap") == 0){
			if(mouseswap)
				setbuttonmap("123");
			else
				setbuttonmap("321");
			mouseswap ^= 1;
		}
		else if(strcmp(field[0], "calibrate") == 0){
			if (nf == 1) {
				calibration.scalex = 1;
				calibration.scaley = 1;
				calibration.transx = 0;
				calibration.transy = 0;
			} else if (nf == 5) {
				calibration.scalex = strtol(field[1], nil, 0);
				calibration.scaley = strtol(field[2], nil, 0);
				calibration.transx = strtol(field[3], nil, 0);
				calibration.transy = strtol(field[4], nil, 0);
			}
		}
		return n;

	case Qmousein:
		if(n > sizeof buf-1)
			n = sizeof buf -1;
		memmove(buf, va, n);
		buf[n] = 0;
		p = 0;
		pt.x = strtol(buf+1, &p, 0);
		if(p == 0)
			error(Eshort);
		pt.y = strtol(p, &p, 0);
		if(p == 0)
			error(Eshort);
		b = strtol(p, &p, 0);
		penmousetrack(b, pt.x, pt.y);
		return n;
		
	case Qmouse:
		if(n > sizeof buf-1)
			n = sizeof buf -1;
		memmove(buf, va, n);
		buf[n] = 0;
		p = 0;
		pt.x = strtoul(buf+1, &p, 0);
		if(p == 0)
			error(Eshort);
		pt.y = strtoul(p, 0, 0);
		qlock(&mouse);
		if(ptinrect(pt, gscreen->r))
			penmousetrack(mouse.buttons, pt.x, pt.y);
		qunlock(&mouse);
		return n;
	}

	error(Egreg);
	return -1;
}

Dev penmousedevtab = {
	'm',
	"penmouse",

	penmousereset,
	penmouseinit,
	penmouseattach,
	penmouseclone,
	penmousewalk,
	penmousestat,
	penmouseopen,
	penmousecreate,
	penmouseclose,
	penmouseread,
	devbread,
	penmousewrite,
	devbwrite,
	devremove,
	devwstat,
};

/*
 *  called at interrupt level to update the structure and
 *  awaken any waiting procs.
 */
static void
penmousetrack(int b, int x, int y)
{
	int lastb;

	if(gscreen==nil)
		return;

	if (x >= 0) {
		mouse.xy = Pt(x, y);
	}
	lastb = mouse.buttons;
	mouse.buttons = b;
	mouse.counter++;
	mouse.msec = TK2MS(MACHP(0)->ticks);

	/*
	 * if the queue fills, we discard the entire queue and don't
	 * queue any more events until a reader polls the mouse.
	 */
	if(!mouse.qfull && lastb != b) {	/* add to ring */
		mouse.queue[mouse.wi] = mouse.Mousestate;
		if(++mouse.wi == nelem(mouse.queue))
			mouse.wi = 0;
		if(mouse.wi == mouse.ri)
			mouse.qfull = 1;
	}
	wakeup(&mouse.r);
}

int
penmousechanged(void*)
{
	return mouse.lastcounter != mouse.counter;
}

Point
penmousexy(void)
{
	return mouse.xy;
}

A bitsy/devµc.c => bitsy/devµc.c +352 -0
@@ 0,0 1,352 @@
#include	"u.h"
#include	"../port/lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"io.h"
#include	"../port/error.h"

enum{
	Qbacklight = 1,
	Qbattery,
	Qbuttons,
	Qled,
	Qversion,

	/* command types */
	BLversion=	0,
	BLbuttons=	2,	/* button events */
	BLtouch=	3,	/* read touch screen events */
	BLled=		8,	/* turn LED on/off */
	BLbattery=	9,	/* read battery status */
	BLbacklight=	0xd,	/* backlight control */

	SOF=	0x2,		/* start of frame */

	/* key definitions */
	Up=		0xFF0E,
	Left=		0xFF11,
	Right=		0xFF12,
	Down=		0x8000,
};

Dirtab µcdir[]={
	"backlight",	{ Qbacklight, 0 },	0,	0664,
	"battery",	{ Qbattery, 0 },	0,	0664,
	"buttons",	{ Qbuttons, 0 },	0,	0664,
	"led",		{ Qled, 0 },		0,	0664,
	"version",	{ Qversion, 0 },	0,	0664,
};

static struct µcontroller
{
	/* message being rcvd */
	int	state;
	uchar	buf[16+4];
	uchar	n;

	/* for messages that require acks */
	QLock;
	Rendez	r;

	/* battery */
	uchar	acstatus;
	uchar	voltage;
	ushort	batstatus;
	uchar	batchem;

	/* version string */
	char	version[16+2];
} ctlr;

/* button map */
Rune bmap[4] = 
{
	Up, Right, Down, Left
};

int
µcputc(Queue*, int ch)
{
	int i, len, b, up;
	uchar cksum;
	uchar *p;

	if(ctlr.n > sizeof(ctlr.buf))
		panic("µcputc");

	ctlr.buf[ctlr.n++] = (uchar)ch;
		
	for(;;){
		/* message hasn't started yet */
		if(ctlr.buf[0] != SOF){
			ctlr.n = 0;
			break;
		}
	
		/* if it's too short, wait */
		len = ctlr.buf[1] & 0xf;
		if(ctlr.n < 3 || ctlr.n < len+3)
			break;
	
		/* check the sum */
		ctlr.buf[0] = ~SOF;
		cksum = 0;
		for(i = 1; i < len+2; i++)
			cksum += ctlr.buf[i];
	
		/* ignore bad checksums */
		if(ctlr.buf[len+2] != cksum){
			p = memchr(ctlr.buf+1, SOF, ctlr.n);
			if(p == nil){
				ctlr.n = 0;
				break;
			} else {
				ctlr.n -= p-ctlr.buf;
				memmove(ctlr.buf, p, ctlr.n);
				continue;
			}
		}
	
		/* parse resulting message */
		p = ctlr.buf+2;
		switch(ctlr.buf[1] >> 4){
		case BLversion:
			strncpy(ctlr.version, (char*)p, len);
			ctlr.version[len] = '0';
			strcat(ctlr.version, "\n");
			wakeup(&ctlr.r);
			break;
		case BLbuttons:
			if(len < 1)
				break;
			b = p[0] & 0x7f;
			up = p[0] & 80;
	
			if(b > 5){
				/* rocker panel acts like arrow keys */
				if(b < 10)
					kbdputc(kbdq, bmap[b-6]);
			} else {
				/* the rest like mouse buttons */
				if(--b == 0)
					b = 5;
				penbutton(up, 1<<b);
			}
			break;
		case BLtouch:
			if(len == 4)
				pentrackxy((p[0]<<8)|p[1], (p[2]<<8)|p[3]);
			else
				pentrackxy(-1, -1);
			break;
		case BLled:
			wakeup(&ctlr.r);
			break;
		case BLbattery:
			if(len >= 5){
				ctlr.acstatus = p[0];
				ctlr.voltage = (p[3]<<8)|p[2];
				ctlr.batstatus = p[4];
				ctlr.batchem = p[1];
			}
			wakeup(&ctlr.r);
			break;
		case BLbacklight:
			wakeup(&ctlr.r);
			break;
		}
	
		/* remove the message */
		ctlr.n -= len+3;
		memmove(ctlr.buf, &ctlr.buf[len+3], ctlr.n);
	}
	return 0;
}

static void
_sendmsg(uchar id, uchar *data, int len)
{
	uchar buf[20];
	uchar cksum;
	uchar c;
	uchar *p = buf;
	int i;

	/* create the message */
	if(sizeof(buf) < len+4)
		return;
	cksum = (id<<4) | len;
	*p++ = SOF;
	*p++ = cksum;
	for(i = 0; i < len; i++){
		c = data[i];
		cksum += c;
		*p++ = c;
	}
	*p++ = cksum;

	/* send the message - there should be a more generic way to do this */
	serialµcputs(buf, p-buf);
}

static void
sendmsgwithack(uchar id, uchar *data, int len)
{
	if(waserror()){
		qunlock(&ctlr);
		nexterror();
	}
	qlock(&ctlr);
	_sendmsg(id, data, len);
	tsleep(&ctlr.r, return0, 0, 100);
	qunlock(&ctlr);
	poperror();
}

static void
sendmsg(uchar id, uchar *data, int len)
{
	if(waserror()){
		qunlock(&ctlr);
		nexterror();
	}
	qlock(&ctlr);
	_sendmsg(id, data, len);
	qunlock(&ctlr);
	poperror();
}

void
µcinit(void)
{
}

static Chan*
µcattach(char* spec)
{
	return devattach('r', spec);
}

static int	 
µcwalk(Chan* c, char* name)
{
	return devwalk(c, name, µcdir, nelem(µcdir), devgen);
}

static void	 
µcstat(Chan* c, char* dp)
{
	devstat(c, dp, µcdir, nelem(µcdir), devgen);
}

static Chan*
µcopen(Chan* c, int omode)
{
	omode = openmode(omode);
	if(strcmp(up->user, eve)!=0)
		error(Eperm);
	return devopen(c, omode, µcdir, nelem(µcdir), devgen);
}

static void	 
µcclose(Chan*)
{
}

char*
acstatus(int x)
{
	if(x)
		return "attached";
	else
		return "detached";
}

char*
batstatus(int x)
{
	switch(x){
	case 1:		return "high";
	case 2:		return "low";
	case 4:		return "critical";
	case 8:		return "charging";
	case 0x80:	return "none";
	}
	return "ok";
}

static long	 
µcread(Chan* c, void* a, long n, vlong off)
{
	char buf[64];

	if(c->qid.path & CHDIR)
		return devdirread(c, a, n, µcdir, nelem(µcdir), devgen);

	switch(c->qid.path){
	case Qbattery:
		sendmsgwithack(BLbattery, nil, 0);		/* send a battery request */
		sprint(buf, "voltage: %d\nac: %s\nstatus: %s\n", ctlr.voltage,
			acstatus(ctlr.acstatus),
			batstatus(ctlr.batstatus));
		return readstr(off, a, n, buf);
	case Qversion:
		sendmsgwithack(BLversion, nil, 0);		/* send a battery request */
		return readstr(off, a, n, ctlr.version);
	}
	error(Ebadarg);
	return 0;
}

#define PUTBCD(n,o) bcdclock[o] = (n % 10) | (((n / 10) % 10)<<4)

static long	 
µcwrite(Chan* c, void* a, long n, vlong off)
{
	Cmdbuf *cmd;
	uchar data[16];
	int i;

	if(off != 0)
		error(Ebadarg);

	cmd = parsecmd(a, n);
	if(cmd->nf > 15)
		error(Ebadarg);
	for(i = 0; i < cmd->nf; i++)
		data[i] = atoi(cmd->f[i]);

	switch(c->qid.path){
	case Qled:
		sendmsgwithack(BLled, data, cmd->nf);
		break;
	case Qbacklight:
		sendmsgwithack(BLbacklight, data, cmd->nf);
		break;
	default:
		error(Ebadarg);
	}
	return n;
}

Dev µcdevtab = {
	'r',
	"µc",

	devreset,
	µcinit,
	µcattach,
	devclone,
	µcwalk,
	µcstat,
	µcopen,
	devcreate,
	µcclose,
	µcread,
	devbread,
	µcwrite,
	devbwrite,
	devremove,
	devwstat,
};

M bitsy/fns.h => bitsy/fns.h +4 -0
@@ 33,8 33,11 @@ void	mmuenable(void);
void	mmudisable(void);
void	mmuinvalidate(void);
void	mmuinvalidateaddr(ulong);
int	µcputc(Queue*, int);
void	noted(Ureg*, ulong);
int	notify(Ureg*);
void	penbutton(int, int);
void	pentrackxy(int x, int y);
#define	procrestore(p)
void	procsave(Proc*);
void	procsetup(Proc*);


@@ 50,6 53,7 @@ void	sa1100_uartsetup(int);
void	screeninit(void);
int	screenprint(char*, ...);			/* debugging */
void	screenputs(char*, int);
void	serialµcputs(uchar *str, int n);
void	setr13(int, ulong*);
uchar*	tarlookup(uchar*, char*, int*);
void	touser(void*);

M bitsy/sa1110uart.c => bitsy/sa1110uart.c +20 -1
@@ 353,6 353,25 @@ serialputs(char *str, int n)
}

/*
 *  for iprint, just write it
 */
void
serialµcputs(uchar *str, int n)
{
	Uartregs *ur;

	ur = uart1regs;
	while(n-- > 0){
		/* wait for output ready */
		while((ur->status[1] & Tnotfull) == 0)
			;
		ur->data = *str++;
	}
	while((ur->status[1] & Tbusy))
		;
}

/*
 *  take an interrupt
 */
static void


@@ 433,6 452,6 @@ sa1100_uartsetup(int console)
	gpclkregs->r0 = Gpclk_sus;	/* set uart mode */
	uart1regs = mapspecial(UART1REGS, 64);
	p = uartsetup(&sa1100_uart, uart1regs, ClockFreq, "serialport1");
	sa1100_uartbaud(p, 115200);
	uartspecial(p, 115200, 0, 0, µcputc);
	intrenable(IRQuart1b, sa1100_uartintr, p, p->name);
}

M bitsy/screen.c => bitsy/screen.c +4 -6
@@ 123,14 123,14 @@ static Memimage xgscreen =
	{ 0, 0, Wid, Ht },	/* r */
	{ 0, 0, Wid, Ht },	/* clipr */
	16,					/* depth */
	1,					/* nchan */
	3,					/* nchan */
	RGB16,				/* chan */
	nil,				/* cmap */
	&xgdata,			/* data */
	0,					/* zero */
	Wid/2,				/* width */
	0,					/* layer */
	Frepl,				/* flags */
	0,					/* flags */
};

Memimage *gscreen;


@@ 174,7 174,6 @@ lcdinit(void)
	lcd->lccr2 = (Ht-1)<<LPP | vsw<<VSW | efw<<EFW | bfw<<BFW;
	lcd->lccr1 = (Wid-16)<<PPL | hsw<<HSW | elw<<ELW | blw<<BLW;
	lcd->lccr0 = 1<<LEN | 0<<CMS | 0<<SDS | 1<<LDM | 1<<BAM | 1<<ERM | 1<<PAS | 0<<BLE | 0<<DPD | 0<<PDD;

}

void


@@ 185,14 184,12 @@ screeninit(void)
	/* map the lcd regs into the kernel's virtual space */
	lcd = (struct sa1110regs*)mapspecial(LCDREGS, sizeof(struct sa1110regs));;

	framebuf = xspanalloc(sizeof *framebuf, 0x10, 0);
	framebuf = xspanalloc(sizeof *framebuf, 0x20, 0);
	/* the following works because main memory is direct mapped */

	framebuf->palette[0] = Pal0;

	iprint("LCD power up\n");
	lcdpower(1);

	lcdinit();

	gscreen = &xgscreen;


@@ 335,6 332,7 @@ screenputc(char *buf)
	Rectangle r;
	static int *xp;
	static int xbuf[256];
return;

	if(xp < xbuf || xp >= &xbuf[sizeof(xbuf)])
		xp = xbuf;

M bitsy/screen.h => bitsy/screen.h +7 -1
@@ 1,3 1,9 @@
typedef struct Cursorinfo Cursorinfo;
typedef struct Cursor Cursor;

struct Cursorinfo {
	Lock;
};

extern void	blankscreen(int);
extern void	flushmemscreen(Rectangle);


M boot/aux.c => boot/aux.c +2 -8
@@ 54,19 54,13 @@ sendmsg(int fd, char *msg)
void
warning(char *s)
{
	char buf[ERRLEN];

	errstr(buf);
	fprint(2, "boot: %s: %s\n", s, buf);
	fprint(2, "boot: %s: %r\n", s);
}

void
fatal(char *s)
{
	char buf[ERRLEN];

	errstr(buf);
	fprint(2, "boot: %s: %s\n", s, buf);
	fprint(2, "boot fatal: %s: %r\n", s);
	exits(0);
}


M boot/bootip.c => boot/bootip.c +2 -2
@@ 27,7 27,7 @@ configip(void)

	arg = malloc((bargc+1) * sizeof(char*));
	if(arg == nil)
		fatal("%r");
		fatal("malloc");
	memmove(arg, bargv, (bargc+1) * sizeof(char*));

	argc = bargc;


@@ 56,7 56,7 @@ configip(void)
	/* let ipconfig configure the ip interface */
	switch(pid = fork()){
	case -1:
		fatal("configuring ip: %r");
		fatal("configuring ip");
	case 0:
		exec("/ipconfig", arg);
		fatal("execing /ipconfig");

M carrera/screen.c => carrera/screen.c +2 -2
@@ 8,7 8,7 @@
#include	"../port/error.h"

#define	Image	IMAGE
#include	<draw.h>
#include	<draw.h>
#include	<memdraw.h>
#include	<cursor.h>
#include	"screen.h"


@@ 63,7 63,7 @@ static Memimage xgscreen =
	0,	/* zero */
	512,	/* width */
	0,	/* layer */
	Frepl,	/* flags */
	0,	/* flags */
};

Memimage *gscreen;

M pc/devi82365.c => pc/devi82365.c +19 -9
@@ 1093,14 1093,14 @@ readc(Cisdat *pp, uchar *x)
}

static int
xcistuple(int slotno, int tuple, void *v, int nv, int attr)
xcistuple(int slotno, int tuple, int subtuple, void *v, int nv, int attr)
{
	PCMmap *m;
	Cisdat cis;
	int i, l;
	uchar *p;
	uchar type, link;
	int this;
	uchar type, link, n, c;
	int this, subtype;

	m = pcmmap(slotno, 0, 0, attr);
	if(m == 0)


@@ 1122,9 1122,19 @@ xcistuple(int slotno, int tuple, void *v, int nv, int attr)
			break;
		if(link == 0xFF)
			break;
		if(type == tuple) {

		n = link;
		if (link > 1 && subtuple != -1) {
			if (readc(&cis, &c) != 1)
				break;
			subtype = c;
			n--;
		} else
			subtype = -1;

		if(type == tuple && subtype == subtuple) {
			p = v;
			for(l=0; l<nv && l<link; l++)
			for(l=0; l<nv && l<n; l++)
				if(readc(&cis, p++) != 1)
					break;
			pcmunmap(slotno, m);


@@ 1137,14 1147,14 @@ xcistuple(int slotno, int tuple, void *v, int nv, int attr)
}

int
pcmcistuple(int slotno, int tuple, void *v, int nv)
pcmcistuple(int slotno, int tuple, int subtuple, void *v, int nv)
{
	int n;

	/* try attribute space, then memory */
	if((n = xcistuple(slotno, tuple, v, nv, 1)) >= 0)
	if((n = xcistuple(slotno, tuple, subtuple, v, nv, 1)) >= 0)
		return n;
	return xcistuple(slotno, tuple, v, nv, 0);
	return xcistuple(slotno, tuple, subtuple, v, nv, 0);
}

static void


@@ 1161,7 1171,7 @@ cisread(Slot *pp)
	pp->nctab = 0;

	for(i = 0; i < nelem(cistab); i++) {
		if((nv = pcmcistuple(pp->slotno, cistab[i].n, v, sizeof(v))) >= 0) {
		if((nv = pcmcistuple(pp->slotno, cistab[i].n, -1, v, sizeof(v))) >= 0) {
			cis.cisbase = v;
			cis.cispos = 0;
			cis.cisskip = 1;

M pc/ether589.c => pc/ether589.c +1 -1
@@ 152,7 152,7 @@ reset(Ether* ether)
	 */
	memset(ea, 0, sizeof ea);
	if(memcmp(ea, ether->ea, 6) == 0 && strcmp(type, "3C562") == 0) {
		if(pcmcistuple(slot, 0x88, ea, 6) == 6) {
		if(pcmcistuple(slot, 0x88, -1, ea, 6) == 6) {
			for(i = 0; i < 6; i += 2){
				t = ea[i];
				ea[i] = ea[i+1];

A pc/ethersmc.c => pc/ethersmc.c +779 -0
@@ 0,0 1,779 @@
/*
 * SMC EtherEZ (SMC91cXX chip) PCMCIA card support.
 */

#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/netif.h"
#include "etherif.h"

enum {
	IoSize		= 0x10,		/* port pool size */
	TxTimeout	= 150,
};

enum {	/* PCMCIA related */
	TupleFunce	= 0x22,
	TfNodeId	= 0x04,
};

enum {	/* bank 0 registers */
	Tcr		= 0x0000,	/* transmit control */
	Eph		= 0x0002,	/* ethernet protocol handler */
	Rcr		= 0x0004,	/* receiver control */
	Counter		= 0x0006,	/* statistics counter */
	MemInfo		= 0x0008,
	MemCfg		= 0x000A,
};

enum {	/* bank 1 registers */
	Config		= 0x0000,
	BaseAddr	= 0x0002,
	Addr0		= 0x0004,	/* ethernet address */
	Addr1		= 0x0006,
	Addr2		= 0x0008,
	General		= 0x000A,
	Control		= 0x000C,
};

enum {	/* bank 2 registers */
	MmuCmd		= 0x0000,
	PktNo		= 0x0002,
	AllocRes	= 0x0003,
	FifoPorts	= 0x0004,
	Pointer		= 0x0006,
	Data1		= 0x0008,
	Interrupt	= 0x000C,
	IntrMask	= 0x000D,
};

enum {	/* bank 3 registers */
	Mcast0		= 0x0000,
	Mcast2		= 0x0002,
	Mcast4		= 0x0004,
	Mcast6		= 0x0006,
	Revision	= 0x000A,
};

enum {
	BankSelect	= 0x000E	/* bank select register */
};

enum {
	BsrMask		= 0xFF00,	/* mask for chip identification */
	BsrId		= 0x3300,
};


enum {	/* Tcr values */
	TcrClear	= 0x0000,
	TcrEnable	= 0x0001,	/* enable transmit */
	TcrLoop		= 0x0002,	/* enable internal analogue loopback */
	TcrForceCol	= 0x0004,	/* force collision on next tx */
	TcrPadEn	= 0x0080,	/* pad short packets to 64 bytes */
	TcrNoCrc	= 0x0100,	/* do not append CRC */
	TcrMonCns	= 0x0400,	/* monitor carrier status */
	TcrFduplx	= 0x0800,
	TcrStpSqet	= 0x1000,
	TcrEphLoop	= 0x2000,
	TcrNormal	= TcrEnable,
};

enum {	/* Eph values */
	EphTxOk		= 0x0001,
	Eph1Col		= 0x0002,	/* single collision */
	EphMCol		= 0x0004,	/* multiple collisions */  
	EphTxMcast	= 0x0008,	/* multicast transmit */
	Eph16Col	= 0x0010,	/* 16 collisions, tx disabled */
	EphSqet		= 0x0020,	/* SQE test failed, tx disabled */
	EphTxBcast	= 0x0040,	/* broadcast tx */
	EphDefr		= 0x0080,	/* deffered tx */
	EphLatCol	= 0x0200,	/* late collision, tx disabled */
	EphLostCarr	= 0x0400,	/* lost carrier, tx disabled */
	EphExcDefr	= 0x0800,	/* excessive defferals */
	EphCntRol	= 0x1000,	/* ECR counter(s) rolled over */
	EphRxOvrn	= 0x2000,	/* receiver overrun, packets dropped */
	EphLinkOk	= 0x4000,
	EphTxUnrn	= 0x8000,	/* tx underrun */
};

enum {	/* Rcr values */
	RcrClear	= 0x0000,
	RcrPromisc	= 0x0002,
	RcrAllMcast	= 0x0004,
	RcrEnable	= 0x0100,
	RcrStripCrc	= 0x0200,
	RcrSoftReset	= 0x8000,
	RcrNormal	= RcrStripCrc | RcrEnable,
};

enum { /* Counter value masks */
	CntColMask	= 0x000F,	/* collisions */
	CntMColMask	= 0x00F0,	/* multiple collisions */
	CntDtxMask	= 0x0F00,	/* deferred transmits */
	CntExDtxMask	= 0xF000,	/* excessively deferred transmits */

	CntColShr	= 1,
	CntMColShr	= 4,
	CntDtxShr	= 8,
};

enum { /* MemInfo value masks */
	MirTotalMask	= 0x00FF,
	MirFreeMask	= 0xFF00,
};

enum {	/* Config values */
	CfgIrqSel0	= 0x0002,
	CfgIrqSel1	= 0x0004,
	CfgDisLink	= 0x0040,	/* disable 10BaseT link test */
	Cfg16Bit	= 0x0080,
	CfgAuiSelect	= 0x0100,
	CfgSetSqlch	= 0x0200,
	CfgFullStep	= 0x0400,
	CfgNoWait	= 0x1000,
	CfgMiiSelect	= 0x8000,
};

enum {	/* Control values */
	CtlStore	= 0x0001,	/* store to EEPROM */
	CtlReload	= 0x0002,	/* reload EEPROM into registers */
	CtlEeSelect	= 0x0004,	/* select registers for reload/store */
	CtlTeEnable	= 0x0020,	/* tx error detection via eph irq */
	CtlCrEnable	= 0x0040,	/* counter rollover via eph irq */
	CtlLeEnable	= 0x0080,	/* link error detection via eph irq*/
	CtlAutoRls	= 0x0800,	/* auto release mode */
	CtlPowerDn	= 0x2000,
};

enum {	/* MmuCmd values */
	McBusy		= 0x0001,
	McAlloc		= 0x0020,	/* | with number of 256 byte packets - 1 */
	McReset		= 0x0040,
	McRelease	= 0x0080,	/* dequeue (but not free) current rx packet */
	McFreePkt	= 0x00A0,	/* dequeue and free current rx packet */
	McEnqueue	= 0x00C0,	/* enqueue the packet for tx */
	McTxReset	= 0x00E0,	/* reset transmit queues */
};

enum { /* AllocRes values */
	ArFailed	= 0x80,
};
	  
enum {	/* FifoPorts values */
	FpTxEmpty	= 0x0080,
	FpRxEmpty	= 0x8000,
	FpTxMask	= 0x007F,
	FpRxMask	= 0x7F00,
};

enum {	/* Pointer values */
	PtrRead		= 0x2000,
	PtrAutoInc	= 0x4000,
	PtrRcv		= 0x8000,
};

enum {	/* Interrupt values */
	IntRcv		= 0x0001,
	IntTxError	= 0x0002,
	IntTxEmpty	= 0x0004,
	IntAllo		= 0x0008,
	IntRxOvrn	= 0x0010,
	IntEph		= 0x0020,
};

enum { /* transmit status bits */
	TsSuccess	= 0x0001,
	Ts16Col		= 0x00A0,
	TsLatCol	= 0x0200,
	TsLostCar	= 0x0400,
};

enum { /* receive status bits */
	RsMcast		= 0x0001,
	RsTooShort	= 0x0400,
	RsTooLong	= 0x0800,
	RsOddFrame	= 0x1000,
	RsBadCrc	= 0x2000,
	RsAlgnErr	= 0x8000,
	RsError		= RsAlgnErr | RsBadCrc | RsTooLong | RsTooShort,
};

enum {
	RxLenMask	= 0x07FF,	/* significant rx len bits */
	HdrSize		= 6,		/* packet header length */
	PageSize	= 256,		/* page length */
};

typedef struct {
	Lock;
	ushort rev;
	int attached;
	Block *txbp;
	ulong txtime;

	ulong rovrn;
	ulong lcar;
	ulong col;
	ulong scol;
	ulong mcol;
	ulong lcol;
	ulong dfr;
} Smc91xx;

#define SELECT_BANK(x) outs(port + BankSelect, x)

static int
readnodeid(int slot, Ether* ether)
{
	uchar data[Eaddrlen + 1];
	int len;

	len = sizeof(data);
	if (pcmcistuple(slot, TupleFunce, TfNodeId, data, len) != len)
		return -1;

	if (data[0] != Eaddrlen)
		return -1;

	memmove(ether->ea, &data[1], Eaddrlen);
	return 0;
}

static void
chipreset(Ether* ether)
{
	int port;
	int i;

	port = ether->port;

	/* reset the chip */
	SELECT_BANK(0);
	outs(port + Rcr, RcrSoftReset);
	delay(1);
	outs(port + Rcr, RcrClear);
	outs(port + Tcr, TcrClear);
	SELECT_BANK(1);
	outs(port + Control, CtlAutoRls | CtlTeEnable |
		CtlCrEnable);

	for(i = 0; i < 6; i++) {
		outb(port + Addr0 +  i, ether->ea[i]);
	}

	SELECT_BANK(2);
	outs(port + MmuCmd, McReset);
}

static void
chipenable(Ether* ether)
{
	int port;

	port = ether->port;
	SELECT_BANK(0);
	outs(port + Tcr, TcrNormal);
	outs(port + Rcr, RcrNormal);
	SELECT_BANK(2);
	outb(port + IntrMask, IntEph | IntRxOvrn | IntRcv);
}

static void
attach(Ether *ether)
{
	Smc91xx* ctlr;

	ctlr = ether->ctlr;
	ilock(ctlr);
	
	if (ctlr->attached) {
		iunlock(ctlr);
		return;
	}

	chipenable(ether);
	ctlr->attached = 1;
	iunlock(ctlr);
}

static void
txstart(Ether* ether)
{
	int port;
	Smc91xx* ctlr;
	Block* bp;
	int len, npages;
	int pno;

	/* assumes ctlr is locked and bank 2 is selected */
	/* leaves bank 2 selected on return */
	port = ether->port;
	ctlr = ether->ctlr;

	if (ctlr->txbp) {
		bp = ctlr->txbp;
		ctlr->txbp = 0;
	} else {
		bp = qget(ether->oq);
		if (bp == 0)
			return;

		len = BLEN(bp);
		npages = (len + HdrSize) / PageSize;
		outs(port + MmuCmd, McAlloc | npages);
	}

	pno = inb(port + AllocRes);
	if (pno & ArFailed) {
		outb(port + IntrMask, inb(port + IntrMask) | IntAlloc);
		ctlr->txbp = bp;
		ctlr->txtime = MACHP(0)->ticks;
		return;
	}

	outb(port + PktNo, pno);
	outs(port + Pointer, PtrAutoInc);

	len = BLEN(bp);
	outs(port + Data1, 0);
	outb(port + Data1, (len + HdrSize) & 0xFF);
	outb(port + Data1, (len + HdrSize) >> 8);
	outss(port + Data1, bp->rp, len / 2);
	if ((len & 1) == 0) {
		outs(port + Data1, 0);
	} else {
		outb(port + Data1, bp->rp[len - 1]);
		outb(port + Data1, 0x20);	/* no info what 0x20 means */
	}

	outb(port + IntrMask, inb(port + IntrMask) |
			IntTxError | IntTxEmpty);

	outs(port + MmuCmd, McEnqueue);
	freeb(bp);
}

static void
receive(Ether* ether)
{
	int port;
	Block* bp;
	int pktno, status, len;

	/* assumes ctlr is locked and bank 2 is selected */
	/* leaves bank 2 selected on return */
	port = ether->port;

	pktno = ins(port + FifoPorts);
	if (pktno & FpRxEmpty) {
		return;
	}

	outs(port + Pointer, PtrRead | PtrRcv | PtrAutoInc);
	status = ins(port + Data1);
	len = ins(port + Data1) & RxLenMask - HdrSize;
	
	if (status & RsOddFrame)
		len++;
	
	if ((status & RsError) || (bp = iallocb(len)) == 0) {

		if (status & RsAlgnErr)
			ether->frames++;
		if (status & (RsTooShort | RsTooLong))
			ether->buffs++;
		if (status & RsBadCrc)
			ether->crcs++;

		outs(port + MmuCmd, McRelease);
		return;
	}

	/* packet length is padded to word */
	inss(port + Data1, bp->rp, len / 2);
	bp->wp = bp->rp + (len & ~1);
	
	if (len & 1) {
		*bp->wp = inb(port + Data1);
		bp->wp++;
	}
	  
	etheriq(ether, bp, 1);
	ether->inpackets++;
	outs(port + MmuCmd, McRelease);
}

static void
txerror(Ether* ether)
{
	int port;
	Smc91xx* ctlr;
	int save_pkt;
	int pktno, status;

	/* assumes ctlr is locked and bank 2 is selected */
	/* leaves bank 2 selected on return */
	port = ether->port;
	ctlr = ether->ctlr;

	save_pkt = inb(port + PktNo);

	pktno = ins(port + FifoPorts) & FpTxMask;
	outb(port + PktNo, pktno);
	outs(port + Pointer, PtrAutoInc | PtrRead);
	status = ins(port + Data1);
	
	if (status & TsLostCar)
		ctlr->lcar++;

	if (status & TsLatCol)
		ctlr->lcol++;

	if (status & Ts16Col)
		ctlr->scol++;

	ether->oerrs++;
	
	SELECT_BANK(0);
	outs(port + Tcr, ins(port + Tcr) | TcrEnable);
	
	SELECT_BANK(2);
	outs(port + MmuCmd, McFreePkt);

	outb(port + PktNo, save_pkt);
}

static void
eph_irq(Ether* ether)
{
	int port;
	Smc91xx* ctlr;
	ushort status;
	int n;

	/* assumes ctlr is locked and bank 2 is selected */
	/* leaves bank 2 selected on return */
	port = ether->port;
	ctlr = ether->ctlr;

	SELECT_BANK(0);
	status = ins(port + Eph);

	if (status & EphCntRol) {
		/* read the counter register even if we don't need it */
		/* otherwise we will keep getting this interrupt */
		n = ins(port + Counter);
		ctlr->col += (n & CntColMask) >> CntColShr;
		ctlr->mcol += (n & CntMColMask) >> CntMColShr;
		ctlr->dfr += (n & CntDtxMask) >> CntDtxShr;
	}

	/* if there was a transmit error, Tcr is disabled */
	outs(port + Tcr, ins(port + Tcr) | TcrEnable);

	/* clear a link error interrupt */
	SELECT_BANK(1);
	outs(port + Control, CtlAutoRls);
	outs(port + Control, CtlAutoRls | CtlTeEnable | CtlCrEnable);

	SELECT_BANK(2);
}

static void
transmit(Ether* ether)
{
	Smc91xx* ctlr;
	int port, n;

	ctlr = ether->ctlr;
	port = ether->port;
	ilock(ctlr);

	if (ctlr->txbp) {
		n = TK2MS(MACHP(0)->ticks - ctlr->txtime);
		if (n > TxTimeout) {
			chipreset(ether);
			chipenable(ether);
			freeb(ctlr->txbp);
			ctlr->txbp = 0;
		}
		iunlock(ctlr);
		return;
	}

	SELECT_BANK(2);
	txstart(ether);
	iunlock(ctlr);
}

static void
interrupt(Ureg*, void *arg)
{
	int port;
	Smc91xx* ctlr;
	Ether* ether;
	int save_bank;
	int save_pointer;
	int mask, status;

	ether = arg;
	port = ether->port;
	ctlr = ether->ctlr;
	
	ilock(ctlr);
	save_bank = ins(port + BankSelect);
	SELECT_BANK(2);
	save_pointer = ins(port + Pointer);
	
	mask = inb(port + IntrMask);
	outb(port + IntrMask, 0);

	while ((status = inb(port + Interrupt) & mask) != 0) {
		if (status & IntRcv) {
			receive(ether);
		}

		if (status & IntTxError) {
			txerror(ether);
		}

		if (status & IntTxEmpty) {
			outb(port + Interrupt, IntTxEmpty);
			outb(port + IntrMask, mask & ~IntTxEmpty);
			txstart(ether);
			mask = inb(port + IntrMask);
		}

		if (status & IntAlloc) {
			outb(port + IntrMask, mask & ~IntAlloc);
			txstart(ether);;
			mask = inb(port + IntrMask);
		}

		if (status & IntRxOvrn) {
			ctlr->rovrn++;
			ether->misses++;
			outb(port + Interrupt,IntRxOvrn);
		}

		if (status & IntEph)
			eph_irq(ether);
	}
	
	outb(port + IntrMask, mask);
	outs(port + Pointer, save_pointer);
	outs(port + BankSelect, save_bank);
	iunlock(ctlr);
}

static void
promiscuous(void* arg, int on)
{
	int port;
	Smc91xx *ctlr;
	Ether* ether;
	ushort x;

	ether = arg;
	port = ether->port;
	ctlr = ether->ctlr;

	ilock(ctlr);
	SELECT_BANK(0);
	x = ins(port + Rcr);
	if (on)
		x |= RcrPromisc;
	else
		x &= ~RcrPromisc;
	
	outs(port + Rcr, x);
	iunlock(ctlr);
}

static void
multicast(void* arg, uchar *addr, int on)
{
	int port;
	Smc91xx*ctlr;
	Ether *ether;
	ushort x;
	
	USED(addr, on);

	ether = arg;
	port = ether->port;
	ctlr = ether->ctlr;
	ilock(ctlr);
	
	SELECT_BANK(0);
	x = ins(port + Rcr);
	
	if (ether->nmaddr)
		x |= RcrAllMcast;
	else
		x &= ~RcrAllMcast;
	
	outs(port + Rcr, x);
	iunlock(ctlr);
}

static long
ifstat(Ether* ether, void* a, long n, ulong offset)
{
	static char *chiprev[] = {
		[3] 	"92",
		[5]	"95",
		[7]	"100",
		[8]	"100-FD",
		[9]	"110",
	};

	Smc91xx* ctlr;
	char* p;
	int r, len;
	char* s;
	
	if (n == 0)
		return 0;

	ctlr = ether->ctlr;
	p = malloc(READSTR);

	s = 0;
	if (ctlr->rev > 0) {
		r = ctlr->rev >> 4;
		if (r < nelem(chiprev))
			s = chiprev[r];

		if (r == 4) {
			if ((ctlr->rev & 0x0F) >= 6)
				s = "96";
			else
				s = "94";
		}
	}

	len = snprint(p, READSTR, "rev: 91c%s\n", (s) ? s : "???");
	len += snprint(p + len, READSTR - len, "rxovrn: %uld\n", ctlr->rovrn);
	len += snprint(p + len, READSTR - len, "lcar: %uld\n", ctlr->lcar);
	len += snprint(p + len, READSTR - len, "col: %uld\n", ctlr->col);
	len += snprint(p + len, READSTR - len, "16col: %uld\n", ctlr->scol);
	len += snprint(p + len, READSTR - len, "mcol: %uld\n", ctlr->mcol);
	len += snprint(p + len, READSTR - len, "lcol: %uld\n", ctlr->lcol);
	len += snprint(p + len, READSTR - len, "dfr: %uld\n", ctlr->dfr);
	USED(len);

	n = readstr(offset, a, n, p);
	free(p);
	
	return n;
}

static int
reset(Ether* ether)
{
	int port;
	int i, x;
	char* type;
	Smc91xx* ctlr;
	int slot;
	uchar ea[Eaddrlen];

	if (ether->irq == 0)
		ether->irq = 9;

	if (ether->port == 0)
		ether->port = 0x100;

	type = "8020";
	for(i = 0; i < ether->nopt; i++) {
		if (cistrncmp(ether->opt[i], "id=", 3))
			continue;
		type = &ether->opt[i][3];
		break;
	}

	if ((slot = pcmspecial(type, ether)) < 0)
		return -1;

	if (ioalloc(ether->port, IoSize, 0, "smc91cXX") < 0) {
		pcmspecialclose(slot);
		return -1;
	}

	ether->ctlr = malloc(sizeof(Smc91xx));
	ctlr = ether->ctlr;
	if (ctlr == 0) {
		iofree(ether->port);
		pcmspecialclose(slot);
	}

	ilock(ctlr);
	ctlr->rev = 0;
	ctlr->txbp = nil;
	ctlr->attached = 0;
	ctlr->rovrn = 0;
	ctlr->lcar = 0;
	ctlr->col = 0;
	ctlr->scol = 0;
	ctlr->mcol = 0;
	ctlr->lcol = 0;
	ctlr->dfr = 0;

	port = ether->port;

	SELECT_BANK(1);
	if ((ins(port + BankSelect) & BsrMask) != BsrId) {
		outs(port + Control, 0);	/* try powering up the chip */
		delay(55);
	}

	outs(port + Config, ins(port + Config) | Cfg16Bit);
	x = ins(port + BaseAddr);

	if (((ins(port + BankSelect) & BsrMask) != BsrId) ||
		((x >> 8) == (x & 0xFF))) {
		iunlock(ctlr);
		iofree(port);
		pcmspecialclose(slot);
		return -1;
	}

	SELECT_BANK(3);
	ctlr->rev = ins(port + Revision) & 0xFF;

	memset(ea, 0, Eaddrlen);
	if (memcmp(ea, ether->ea, Eaddrlen) == 0) {
		if (readnodeid(slot, ether) < 0) {
			print("Smc91cXX: cannot find ethernet address\n");
			iunlock(ctlr);
			iofree(port);
			pcmspecialclose(slot);
			return -1;
		}
	}

	chipreset(ether);

	ether->attach = attach;
	ether->transmit = transmit;
	ether->interrupt = interrupt;
	ether->ifstat = ifstat;
	ether->promiscuous = promiscuous;
	ether->multicast = multicast;
	ether->arg = ether;
	iunlock(ctlr);
	return 0;
}

void
ethersmclink(void)
{
	addethercard("smc91cXX", reset);
}

M pc/fns.h => pc/fns.h +1 -1
@@ 95,7 95,7 @@ Pcidev* pcimatch(Pcidev*, int, int);
Pcidev* pcimatchtbdf(int);
void	pcireset(void);
void	pcisetbme(Pcidev*);
int	pcmcistuple(int, int, void*, int);
int	pcmcistuple(int, int, int, void*, int);
PCMmap*	pcmmap(int, ulong, int, int);
int	pcmspecial(char*, ISAConf*);
void	pcmspecialclose(int);

M port/devcons.c => port/devcons.c +58 -28
@@ 256,6 256,62 @@ pprint(char *fmt, ...)
	return n;
}

static void
echoscreen(char *buf, int n)
{
	char *e, *p;
	char ebuf[128];
	int x;

	p = ebuf;
	e = ebuf + sizeof(ebuf) - 4;
	while(n-- > 0){
		if(p >= e){
			screenputs(ebuf, p - ebuf);
			p = ebuf;
		}
		x = *buf++;
		if(x == 0x15){
			*p++ = '^';
			*p++ = 'U';
			*p++ = '\n';
		} else
			*p++ = x;
	}
	if(p != ebuf)
		screenputs(ebuf, p - ebuf);
}

static void
echoprintq(char *buf, int n)
{
	char *e, *p;
	char ebuf[128];
	int x;

	p = ebuf;
	e = ebuf + sizeof(ebuf) - 4;
	while(n-- > 0){
		if(p >= e){
			qiwrite(printq, ebuf, p - ebuf);
			p = ebuf;
		}
		x = *buf++;
		if(x == '\n'){
			*p++ = '\r';
			*p++ = '\n';
		} else if(x == 0x15){
			*p++ = '^';
			*p++ = 'U';
			*p++ = '\n';
		} else
			*p++ = x;
	}
	if(p != ebuf)
		qiwrite(printq, ebuf, p - ebuf);
}


void
echo(char *buf, int n)
{


@@ 263,7 319,6 @@ echo(char *buf, int n)
	extern ulong etext;
	int x;
	char *e, *p;
	char ebuf[128];

	e = buf+n;
	for(p = buf; p < e; p++){


@@ 330,34 385,9 @@ echo(char *buf, int n)
	if(kbd.raw)
		return;

	/*
	 *  finally, the actual echoing
	 */
	p = ebuf;
	e = ebuf + sizeof(ebuf) - 4;
	while(n-- > 0){
		if(p >= e){
			screenputs(ebuf, p - ebuf);
			if(printq)
				qiwrite(printq, ebuf, p - ebuf);
			p = ebuf;
		}
		x = *buf++;
		if(x == '\n'){
			*p++ = '\r';
			*p++ = '\n';
		} else if(x == 0x15){
			*p++ = '^';
			*p++ = 'U';
			*p++ = '\n';
		} else
			*p++ = x;
	}
	if(p == ebuf)
		return;
	screenputs(ebuf, p - ebuf);
	echoscreen(buf, n);
	if(printq)
		qiwrite(printq, ebuf, p - ebuf);
		echoprintq(buf, n);
}

/*

M port/devdraw.c => port/devdraw.c +1 -1
@@ 1225,7 1225,7 @@ printmesg(char *fmt, uchar *a, int plsprnt)
	char *p, *q;
	int s;

	if(1|| plsprnt==0){
	if(1 || plsprnt==0){
		SET(s,q,p);
		USED(fmt, a, buf, p, q, s);
		return;