~kris/9p

9hist

84fb6f81169424782034293ab7b7ba3abe3391ba — David du Colombier 24 years ago d40538d
Plan 9 from Bell Labs 2001-11-21
M alphapc/mmu.c => alphapc/mmu.c +1 -1
@@ 251,7 251,7 @@ mmudump(void)
	if(up) {
		top = up->mmutop;
		if(top != nil)
			iprint("top %lux top[N-1] %lux\n", top->va, ((uvlong *)top->va)[PTE2PG-1]);
			iprint("top %lux top[N-1] %llux\n", top->va, ((uvlong *)top->va)[PTE2PG-1]);
		lvl2 = up->mmulvl2;
		if(lvl2 != nil)
			iprint("lvl2 %lux\n", lvl2->va);

M alphapc/mouse.c => alphapc/mouse.c +124 -39
@@ 22,6 22,34 @@ enum
	MousePS2=	2,
};
static int mousetype;
static int intellimouse;
static int packetsize;
static int resolution;
static int accelerated;

enum
{
	CMaccelerated,
	CMintellimouse,
	CMlinear,
	CMps2,
	CMps2intellimouse,
	CMres,
	CMreset,
	CMserial,
};

static Cmdtab mousectlmsg[] =
{
	CMaccelerated,		"accelerated",		0,
	CMintellimouse,		"intellimouse",		1,
	CMlinear,		"linear",		1,
	CMps2,			"ps2",			1,
	CMps2intellimouse,	"ps2intellimouse",	1,
	CMres,			"res",			0,
	CMreset,		"reset",		1,
	CMserial,		"serial",		0,
};

/*
 *  setup a serial mouse


@@ 58,24 86,55 @@ serialmouse(int port, char *type, int setspeed)
 *	byte 1 -	DX
 *	byte 2 -	DY
 *
 *  shift & left button is the same as middle button
 *  shift & right button is the same as middle button
 *
 * Intellimouse and AccuPoint with extra buttons deliver
 *	byte 3 -	00 or 01 or FF according to extra button state.
 * extra buttons are mapped in this code to buttons 4 and 5.
 * AccuPoint generates repeated events for these buttons;
*  it and Intellimouse generate 'down' events only, so
 * user-level code is required to generate button 'up' events
 * if they are needed by the application.
 * Also on laptops with AccuPoint AND external mouse, the
 * controller may deliver 3 or 4 bytes according to the type
 * of the external mouse; code must adapt.
 *
 * On the NEC Versa series (and perhaps others?) we seem to
 * lose a byte from the packet every once in a while, which
 * means we lose where we are in the instruction stream.
 * To resynchronize, if we get a byte more than two seconds
 * after the previous byte, we assume it's the first in a packet.
 */
static void
ps2mouseputc(int c, int shift)
{
	static short msg[3];
	static short msg[4];
	static int nb;
	static uchar b[] = {0, 1, 4, 5, 2, 3, 6, 7, 0, 1, 2, 5, 2, 3, 6, 7 };
	static uchar b[] = {0, 1, 4, 5, 2, 3, 6, 7, 0, 1, 2, 3, 2, 3, 6, 7 };
	static ulong lasttick;
	ulong m;
	int buttons, dx, dy;

	/*
	 * Resynchronize in stream with timing; see comment above.
	 */
	m = MACHP(0)->ticks;
	if(TK2SEC(m - lasttick) > 2)
		nb = 0;
	lasttick = m;

	/* 
	 *  check byte 0 for consistency
	 */
	if(nb==0 && (c&0xc8)!=0x08)
		return;
		if(intellimouse && (c==0x00 || c==0x01 || c==0xFF)){
			/* last byte of 4-byte packet */
			packetsize = 4;
			return;
		}

	msg[nb] = c;
	if(++nb == 3){
	if(++nb == packetsize){
		nb = 0;
		if(msg[0] & 0x10)
			msg[1] |= 0xFF00;


@@ 83,9 142,25 @@ ps2mouseputc(int c, int shift)
			msg[2] |= 0xFF00;

		buttons = b[(msg[0]&7) | (shift ? 8 : 0)];
		if(intellimouse && packetsize==4){
			if((msg[3]&0xc8) == 0x08){
				/* first byte of 3-byte packet */
				packetsize = 3;
				msg[0] = msg[3];
				nb = 1;
				/* fall through to emit previous packet */
			}else{
				/* the AccuPoint on the Toshiba 34[48]0CT encodes extra buttons as 4 and 5 */
				/* they repeat and don't release, however, so user-level timing code is required */
				if(msg[3] == 0xFF) 
					buttons |= 1<<3;
				if(msg[3] == 0x01) 
					buttons |= 1<<4;
			}
		}
		dx = msg[1];
		dy = -msg[2];
		mousetrack(buttons, dx, dy, TK2MS(MACHP(0)->ticks));
		mousetrack(dx, dy, buttons, TK2MS(MACHP(0)->ticks));
	}
	return;
}


@@ 105,12 180,9 @@ ps2mouse(void)
	i8042auxcmd(0xF4);

	mousetype = MousePS2;
	packetsize = 3;
}

static int intellimouse;
static int resolution;
static int accelerated;

static void
setaccelerated(int x)
{


@@ 155,6 227,7 @@ static void
setintellimouse(void)
{
	intellimouse = 1;
	packetsize = 4;
	switch(mousetype){
	case MousePS2:
		i8042auxcmd(0xF3);	/* set sample */


@@ 170,6 243,7 @@ setintellimouse(void)
static void
resetmouse(void)
{
	packetsize = 3;
	switch(mousetype){
	case MousePS2:
		i8042auxcmd(0xF6);


@@ 182,35 256,35 @@ resetmouse(void)
}

void
mousectl(char* field[], int n)
mousectl(Cmdbuf *cb)
{
	if(strncmp(field[0], "serial", 6) == 0){
		switch(n){
		case 1:
			serialmouse(atoi(field[0]+6), 0, 1);
			break;
		case 2:
			serialmouse(atoi(field[1]), 0, 0);
			break;
		case 3:
		default:
			serialmouse(atoi(field[1]), field[2], 0);
			break;
		}
	} else if(strcmp(field[0], "ps2") == 0){
	Cmdtab *ct;

	ct = lookupcmd(cb, mousectlmsg, nelem(mousectlmsg));
	switch(ct->index){
	case CMaccelerated:
		setaccelerated(cb->nf == 1 ? 1 : atoi(cb->f[1]));
		break;
	case CMintellimouse:
		setintellimouse();
		break;
	case CMlinear:
		setlinear();
		break;
	case CMps2:
		ps2mouse();
	} else if(strcmp(field[0], "ps2intellimouse") == 0){
		break;
	case CMps2intellimouse:
		ps2mouse();
		setintellimouse();
	} else if(strcmp(field[0], "accelerated") == 0){
		setaccelerated(n == 1 ? 1 : atoi(field[1]));
	} else if(strcmp(field[0], "linear") == 0){
		setlinear();
	} else if(strcmp(field[0], "res") == 0){
		if(n >= 2)
			n = atoi(field[1]);
		setres(n);
	} else if(strcmp(field[0], "reset") == 0){
		break;
	case CMres:
		if(cb->nf >= 2)
			setres(atoi(cb->f[1]));
		else
			setres(1);
		break;
	case CMreset:
		resetmouse();
		if(accelerated)
			setaccelerated(accelerated);


@@ 218,9 292,20 @@ mousectl(char* field[], int n)
			setres(resolution);
		if(intellimouse)
			setintellimouse();
	} else if(strcmp(field[0], "intellimouse") == 0){
		setintellimouse();
		break;
	case CMserial:
		switch(cb->nf){
		case 1:
			serialmouse(atoi(cb->f[0]+6), 0, 1);
			break;
		case 2:
			serialmouse(atoi(cb->f[1]), 0, 0);
			break;
		case 3:
		default:
			serialmouse(atoi(cb->f[1]), cb->f[2], 0);
			break;
		}
		break;
	}
	else
		error(Ebadctl);
}

M alphapc/trap.c => alphapc/trap.c +2 -2
@@ 196,11 196,11 @@ mcheck(Ureg *ur, void *x)

	m = x;
	data = x;
	iprint("panic: Machine Check @%lux: %s (%lux) len %d\n",
	iprint("panic: Machine Check @%lux: %s (%lux) len %lud\n",
			m, smcheck(m->code), m->code, m->len);
	iprint("proc offset %lux sys offset %lux\n", m->procoff, m->sysoff);
	for (i = 0, col = 0; i < m->len/8; i++) {
		iprint("%.3lux: %.16llux%s", 8*i, data[i], (col == 2) ? "\n" : "    ");
		iprint("%.3x: %.16llux%s", 8*i, data[i], (col == 2) ? "\n" : "    ");
		if (col++ == 2)
			col = 0;
	}

M bitsy/devpenmouse.c => bitsy/devpenmouse.c +30 -14
@@ 83,6 83,18 @@ static Dirtab mousedir[]={
	"mousectl",	{Qmousectl},		0,	0660,
};

enum
{
	CMcalibrate,
	CMswap,
};

static Cmdtab penmousecmd[] =
{
	CMcalibrate,	"calibrate",	0,
	CMswap,		"swap",		1,
};

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


@@ 325,6 337,8 @@ penmousewrite(Chan *c, void *va, long n, vlong)
{
	char *p;
	Point pt;
	Cmdbuf *cb;
	Cmdtab *ct;
	char buf[64], *field[5];
	int nf, b;



@@ 334,28 348,27 @@ penmousewrite(Chan *c, void *va, long n, vlong)
		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 = tokenize(buf, field, 5);
		if(strcmp(field[0], "swap") == 0){
		cb = parsecmd(va, n);
		if(waserror()){
			free(cb);
			nexterror();
		}
		ct = lookupcmd(cb, penmousecmd, nelem(penmousecmd));
		switch(ct->index){
		case CMswap:
			if(mouseswap)
				setbuttonmap("123");
			else
				setbuttonmap("321");
			mouseswap ^= 1;
		}
		else if(strcmp(field[0], "calibrate") == 0){
			if (nf == 1) {
			break;
		case CMcalibrate:
			if (cb->nf == 1) {
				calibration.scalex = 1<<16;
				calibration.scaley = 1<<16;
				calibration.transx = 0;
				calibration.transy = 0;
			} else if (nf == 5) {
			} else if (cb->nf == 5) {
				if ((!isdigit(*field[1]) && *field[1] != '-')
				 || (!isdigit(*field[2]) && *field[2] != '-')
				 || (!isdigit(*field[3]) && *field[3] != '-')


@@ 366,8 379,11 @@ penmousewrite(Chan *c, void *va, long n, vlong)
				calibration.transx = strtol(field[3], nil, 0);
				calibration.transy = strtol(field[4], nil, 0);
			} else
				print("calibrate %d fields\n", nf);
				cmderror(cb, Ecmdargs);
			break;
		}
		free(cb);
		poperror();
		return n;

	case Qmousein:

M bitsy/devuda1341.c => bitsy/devuda1341.c +23 -20
@@ 235,6 235,7 @@ static	struct
[Vinvert]	{"invert",		Fin|Fout|Fmono,	  0,		  0,	nil },
[Nvol]	{0}
};

static void	setreg(char *name, int val, int n);

/*


@@ 1247,10 1248,10 @@ static long
audiowrite(Chan *c, void *vp, long n, vlong)
{
	long m, n0;
	int i, nf, v, left, right, in, out;
	char buf[255], *field[Ncmd];
	int i, v, left, right, in, out;
	char *p;
	IOstate *a;
	Cmdbuf *cb;

	p = vp;
	n0 = n;


@@ 1265,25 1266,25 @@ audiowrite(Chan *c, void *vp, long n, vlong)
		right = 1;
		in = 1;
		out = 1;
		if(n > sizeof(buf)-1)
			n = sizeof(buf)-1;
		memmove(buf, p, n);
		buf[n] = '\0';
		cb = parsecmd(p, n);
		if(waserror()){
			free(cb);
			nexterror();
		}

		nf = tokenize(buf, field, Ncmd);
		for(i = 0; i < nf; i++){
		for(i = 0; i < cb->nf; i++){
			/*
			 * a number is volume
			 */
			if(field[i][0] >= '0' && field[i][0] <= '9') {
				m = strtoul(field[i], 0, 10);
			if(cb->f[i][0] >= '0' && cb->f[i][0] <= '9') {
				m = strtoul(cb->f[i], 0, 10);
				if (volumes[v].setval)
					volumes[v].setval(in, out, left, right, m);
				goto cont0;
			}

			for(m=0; volumes[m].name; m++) {
				if(strcmp(field[i], volumes[m].name) == 0) {
				if(strcmp(cb->f[i], volumes[m].name) == 0) {
					v = m;
					in = 1;
					out = 1;


@@ 1293,38 1294,38 @@ audiowrite(Chan *c, void *vp, long n, vlong)
				}
			}

			if(strcmp(field[i], "reset") == 0) {
			if(strcmp(cb->f[i], "reset") == 0) {
				resetlevel();
				goto cont0;
			}
			if(strcmp(field[i], "debug") == 0) {
			if(strcmp(cb->f[i], "debug") == 0) {
				debug = debug?0:1;
				goto cont0;
			}
			if(strcmp(field[i], "in") == 0) {
			if(strcmp(cb->f[i], "in") == 0) {
				in = 1;
				out = 0;
				goto cont0;
			}
			if(strcmp(field[i], "out") == 0) {
			if(strcmp(cb->f[i], "out") == 0) {
				in = 0;
				out = 1;
				goto cont0;
			}
			if(strcmp(field[i], "left") == 0) {
			if(strcmp(cb->f[i], "left") == 0) {
				left = 1;
				right = 0;
				goto cont0;
			}
			if(strcmp(field[i], "right") == 0) {
			if(strcmp(cb->f[i], "right") == 0) {
				left = 0;
				right = 1;
				goto cont0;
			}
			if(strcmp(field[i], "reg") == 0) {
				if(nf < 3)
			if(strcmp(cb->f[i], "reg") == 0) {
				if(cb->nf < 3)
					error(Evolume);
				setreg(field[1], atoi(field[2]), nf == 4 ? atoi(field[3]):1);
				setreg(cb->f[1], atoi(cb->f[2]), cb->nf == 4 ? atoi(cb->f[3]):1);
				return n0;
			}
			error(Evolume);


@@ 1332,6 1333,8 @@ audiowrite(Chan *c, void *vp, long n, vlong)
		cont0:;
		}
		mxvolume();
		poperror();
		free(cb);
		break;

	case Qaudio:

M boot/bootauth.c => boot/bootauth.c +2 -1
@@ 21,9 21,10 @@ authentication(int cpuflag)
	av[ac++] = "factotum";
//av[ac++] = "-d";
	if(cpuflag)
		av[ac++] = "-s";
		av[ac++] = "-S";
	else
		av[ac++] = "-u";
	av[ac++] = "-sfactotum";
	if(authaddr != nil){
		av[ac++] = "-a";
		av[ac++] = authaddr;

M mtx/trap.c => mtx/trap.c +25 -15
@@ 152,13 152,14 @@ trap(Ureg *ur)
{
	int ecode;
	static struct {int callsched;} c = {1};
	int user = (ur->srr1 & MSR_PR) != 0;
	char buf[ERRLEN];
	int user;
	char buf[ERRMAX];

	m->intrts = fastticks(nil);
	ecode = (ur->cause >> 8) & 0xff;
//	user = (ur->srr1 & MSR_PR) != 0;

if(ur->status & MSR_RI == 0)
/* if(ur->status & MSR_RI == 0)
print("double fault?: ecode = %d\n", ecode);
	switch(ecode){
	case CEI:


@@ 213,7 214,7 @@ if(0) print("CDMISS: %lux %lux\n", m->epn, m->cmp1);
		delay(100);
		reset();
	}

*/
	splhi();
	if(user)
		notify(ur);


@@ 223,8 224,9 @@ void
faultpower(Ureg *ureg, ulong addr, int read)
{
	int user, insyscall, n;
	char buf[ERRLEN];
	user = (ureg->srr1 & MSR_PR) != 0;
	char buf[ERRMAX];

//	user = (ureg->srr1 & MSR_PR) != 0;
if(0)print("fault: pid=%ld pc = %lux, addr = %lux read = %d user = %d stack=%ulx\n", up->pid, ureg->pc, addr, read, user, &ureg);
	insyscall = up->insyscall;
	up->insyscall = 1;


@@ 261,6 263,7 @@ Lock	veclock;
void
trapinit(void)
{
#ifdef	BLOG
	int i;
	IMM *io;



@@ 289,11 292,13 @@ trapinit(void)
	sethvec2(CIMISS<<8, itlbmiss);
	sethvec2(CDMISS<<8, dtlbmiss);
	sethvec2(CDTLBE<<8, dtlberror);
#endif
}

void
intrenable(int v, void (*r)(Ureg*, void*), void *arg, int, char *name)
{
#ifdef BLOG
	Handler *h;
	IMM *io;



@@ 327,11 332,13 @@ intrenable(int v, void (*r)(Ureg*, void*), void *arg, int, char *name)
		io->simask |= 1<<(31-LEV(v));
	eieio();
	iunlock(&veclock);
#endif
}

void
intr(Ureg *ur)
{
#ifdef BLOG
	int b, v;
	IMM *io;
	Handler *h;


@@ 376,6 383,7 @@ intr(Ureg *ur)
	if(v >= VectorCPIC)
		io->cisr |= 1<<(v-VectorCPIC);
	eieio();
#endif
}

int


@@ 457,7 465,7 @@ dumpregs(Ureg *ur)
	ulong *l;
	if(up) {
		print("registers for %s %ld\n", up->text, up->pid);
		if(ur->srr1 & MSR_PR == 0)
//		if(ur->srr1 & MSR_PR == 0)
		if(ur->usp < (ulong)up->kstack || ur->usp > (ulong)up->kstack+KSTACK)
			print("invalid stack ptr\n");
	}


@@ 503,6 511,7 @@ dumplongs(char*, ulong*, int)
void
reset(void)
{
#ifdef BLOG
	IMM *io;

	io = m->iomem;


@@ 515,6 524,7 @@ print("reset = %ulx\n", getmsr());
	// cause checkstop -> causes reset
	*(uchar*)(0xdeadbeef) = 0;
	*(ulong*)(0) = 0;
#endif
}

/*


@@ 623,8 633,8 @@ syscall(Ureg* ureg)
	long	ret;
	int	i, scallnr;

	if((ureg->srr1 & MSR_PR) == 0)
		panic("syscall: srr1 0x%4.4uX\n", ureg->srr1);
//	if((ureg->srr1 & MSR_PR) == 0)
//		panic("syscall: srr1 0x%4.4uX\n", ureg->srr1);

	m->syscall++;
	up->insyscall = 1;


@@ 709,8 719,8 @@ notify(Ureg* ur)
	n = &up->note[0];
	if(strncmp(n->msg, "sys:", 4) == 0){
		l = strlen(n->msg);
		if(l > ERRLEN-15)	/* " pc=0x12345678\0" */
			l = ERRLEN-15;
		if(l > ERRMAX-15)	/* " pc=0x12345678\0" */
			l = ERRMAX-15;
		sprint(n->msg+l, " pc=0x%.8lux", ur->pc);
	}



@@ 735,7 745,7 @@ notify(Ureg* ur)
	sp -= sizeof(Ureg);

	if(!okaddr((ulong)up->notify, BY2WD, 0) ||
	   !okaddr(sp-ERRLEN-4*BY2WD, sizeof(Ureg)+ERRLEN+4*BY2WD, 1)) {
	   !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)) {
		pprint("suicide: bad address or sp in notify\n");
		qunlock(&up->debug);
		pexit("Suicide", 0);


@@ 744,8 754,8 @@ notify(Ureg* ur)
	memmove((Ureg*)sp, ur, sizeof(Ureg));
	*(Ureg**)(sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */
	up->ureg = (void*)sp;
	sp -= BY2WD+ERRLEN;
	memmove((char*)sp, up->note[0].msg, ERRLEN);
	sp -= BY2WD+ERRMAX;
	memmove((char*)sp, up->note[0].msg, ERRMAX);
	sp -= 3*BY2WD;
	*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;	/* arg 2 is string */
	ur->r1 = (long)up->ureg;		/* arg 1 is ureg* */


@@ 813,7 823,7 @@ noted(Ureg* ureg, ulong arg0)
			pexit("Suicide", 0);
		}
		qunlock(&up->debug);
		sp = oureg-4*BY2WD-ERRLEN;
		sp = oureg-4*BY2WD-ERRMAX;
		splhi();
		ureg->sp = sp;
		((ulong*)sp)[1] = oureg;	/* arg 1 0(FP) is ureg* */

M pc/mouse.c => pc/mouse.c +36 -14
@@ 26,10 26,12 @@ static int intellimouse;
static int packetsize;
static int resolution;
static int accelerated;
static int mousehwaccel;

enum
{
	CMaccelerated,
	CMhwaccel,
	CMintellimouse,
	CMlinear,
	CMps2,


@@ 42,6 44,7 @@ enum
static Cmdtab mousectlmsg[] =
{
	CMaccelerated,		"accelerated",		0,
	CMhwaccel,		"hwaccel",		2,
	CMintellimouse,		"intellimouse",		1,
	CMlinear,		"linear",		1,
	CMps2,			"ps2",			1,


@@ 181,34 184,46 @@ ps2mouse(void)

	mousetype = MousePS2;
	packetsize = 3;
	mousehwaccel = 1;
}

/*
 * The PS/2 Trackpoint multiplexor on the IBM Thinkpad T23 ignores
 * acceleration commands.  It is supposed to pass them on
 * to the attached device, but my Logitech mouse is simply
 * not behaving any differently.  For such devices, we allow
 * the user to use "hwaccel off" to tell us to back off to
 * software acceleration even if we're using the PS/2 port.
 * (Serial mice are always software accelerated.)
 * For more information on the Thinkpad multiplexor, see
 * http://wwwcssrv.almaden.ibm.com/trackpoint/
 */
static void
setaccelerated(int x)
{
	accelerated = x;
	switch(mousetype){
	case MousePS2:
		i8042auxcmd(0xE7);
		break;
	default:
		mouseaccelerate(x);
		break;
	if(mousehwaccel){
		switch(mousetype){
		case MousePS2:
			i8042auxcmd(0xE7);
			return;
		}
	}
	mouseaccelerate(x);
}

static void
setlinear(void)
{
	accelerated = 0;
	switch(mousetype){
	case MousePS2:
		i8042auxcmd(0xE6);
		break;
	default:
		mouseaccelerate(0);
		break;
	if(mousehwaccel){
		switch(mousetype){
		case MousePS2:
			i8042auxcmd(0xE6);
			return;
		}
	}
	mouseaccelerate(0);
}

static void


@@ 307,5 322,12 @@ mousectl(Cmdbuf *cb)
			break;
		}
		break;
	case CMhwaccel:
		if(strcmp(cb->f[1], "on")==0)
			mousehwaccel = 1;
		else if(strcmp(cb->f[1], "off")==0)
			mousehwaccel = 0;
		else
			cmderror(cb, "bad mouse control message");
	}
}

M port/devaudio.c => port/devaudio.c +18 -16
@@ 1067,8 1067,8 @@ static long
audiowrite(Chan *c, void *vp, long n, vlong)
{
	long m, n0;
	int i, nf, v, left, right, in, out;
	char buf[255], *field[Ncmd];
	int i, v, left, right, in, out;
	Cmdbuf *cb;
	Buf *b;
	char *a;



@@ 1085,18 1085,18 @@ audiowrite(Chan *c, void *vp, long n, vlong)
		right = 1;
		in = 1;
		out = 1;
		if(n > sizeof(buf)-1)
			n = sizeof(buf)-1;
		memmove(buf, a, n);
		buf[n] = '\0';
		cb = parsecmd(vp, n);
		if(waserror()){
			free(cb);
			nexterror();
		}

		nf = tokenize(buf, field, Ncmd);
		for(i = 0; i < nf; i++){
		for(i = 0; i < cb->nf; i++){
			/*
			 * a number is volume
			 */
			if(field[i][0] >= '0' && field[i][0] <= '9') {
				m = strtoul(field[i], 0, 10);
			if(cb->f[i][0] >= '0' && cb->f[i][0] <= '9') {
				m = strtoul(cb->f[i], 0, 10);
				if(left && out)
					audio.lovol[v] = m;
				if(left && in)


@@ 1110,7 1110,7 @@ audiowrite(Chan *c, void *vp, long n, vlong)
			}

			for(m=0; volumes[m].name; m++) {
				if(strcmp(field[i], volumes[m].name) == 0) {
				if(strcmp(cb->f[i], volumes[m].name) == 0) {
					v = m;
					in = 1;
					out = 1;


@@ 1120,27 1120,27 @@ audiowrite(Chan *c, void *vp, long n, vlong)
				}
			}

			if(strcmp(field[i], "reset") == 0) {
			if(strcmp(cb->f[i], "reset") == 0) {
				resetlevel();
				mxvolume();
				goto cont0;
			}
			if(strcmp(field[i], "in") == 0) {
			if(strcmp(cb->f[i], "in") == 0) {
				in = 1;
				out = 0;
				goto cont0;
			}
			if(strcmp(field[i], "out") == 0) {
			if(strcmp(cb->f[i], "out") == 0) {
				in = 0;
				out = 1;
				goto cont0;
			}
			if(strcmp(field[i], "left") == 0) {
			if(strcmp(cb->f[i], "left") == 0) {
				left = 1;
				right = 0;
				goto cont0;
			}
			if(strcmp(field[i], "right") == 0) {
			if(strcmp(cb->f[i], "right") == 0) {
				left = 0;
				right = 1;
				goto cont0;


@@ 1149,6 1149,8 @@ audiowrite(Chan *c, void *vp, long n, vlong)
			break;
		cont0:;
		}
		free(cb);
		poperror();
		break;

	case Qaudio: