xref: /inferno-os/os/ipaq1110/devipaq.c (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
1*74a4d8c2SCharles.Forsyth /*
2*74a4d8c2SCharles.Forsyth  *  iPAQ H3650 touch screen and other devices
3*74a4d8c2SCharles.Forsyth  *
4*74a4d8c2SCharles.Forsyth  * Inferno driver derived from sketchy documentation and
5*74a4d8c2SCharles.Forsyth  * information gleaned from linux/char/h3650_ts.c
6*74a4d8c2SCharles.Forsyth  * by Charles Flynn.
7*74a4d8c2SCharles.Forsyth  *
8*74a4d8c2SCharles.Forsyth  * Copyright © 2000,2001 Vita Nuova Holdings Limited.  All rights reserved.
9*74a4d8c2SCharles.Forsyth  */
10*74a4d8c2SCharles.Forsyth #include	"u.h"
11*74a4d8c2SCharles.Forsyth #include	"../port/lib.h"
12*74a4d8c2SCharles.Forsyth #include	"mem.h"
13*74a4d8c2SCharles.Forsyth #include	"dat.h"
14*74a4d8c2SCharles.Forsyth #include	"fns.h"
15*74a4d8c2SCharles.Forsyth #include	"io.h"
16*74a4d8c2SCharles.Forsyth #include	"../port/error.h"
17*74a4d8c2SCharles.Forsyth 
18*74a4d8c2SCharles.Forsyth #include "keyboard.h"
19*74a4d8c2SCharles.Forsyth #include <kernel.h>
20*74a4d8c2SCharles.Forsyth 
21*74a4d8c2SCharles.Forsyth #include <draw.h>
22*74a4d8c2SCharles.Forsyth #include <memdraw.h>
23*74a4d8c2SCharles.Forsyth #include "screen.h"
24*74a4d8c2SCharles.Forsyth 
25*74a4d8c2SCharles.Forsyth #define	DEBUG	0
26*74a4d8c2SCharles.Forsyth 
27*74a4d8c2SCharles.Forsyth /*
28*74a4d8c2SCharles.Forsyth  * packet format
29*74a4d8c2SCharles.Forsyth  *
30*74a4d8c2SCharles.Forsyth  * SOF (0x02)
31*74a4d8c2SCharles.Forsyth  * (id<<4) | len	byte length
32*74a4d8c2SCharles.Forsyth  * data[len] bytes
33*74a4d8c2SCharles.Forsyth  * chk	checksum mod 256 excluding SOF
34*74a4d8c2SCharles.Forsyth  */
35*74a4d8c2SCharles.Forsyth 
36*74a4d8c2SCharles.Forsyth enum {
37*74a4d8c2SCharles.Forsyth 	Csof = 0x02,
38*74a4d8c2SCharles.Forsyth 	Ceof = 0x03,
39*74a4d8c2SCharles.Forsyth 	Hdrlen = 3,
40*74a4d8c2SCharles.Forsyth 
41*74a4d8c2SCharles.Forsyth 	/* opcodes */
42*74a4d8c2SCharles.Forsyth 
43*74a4d8c2SCharles.Forsyth 	Oversion = 0,
44*74a4d8c2SCharles.Forsyth 	Okeys = 2,
45*74a4d8c2SCharles.Forsyth 	Otouch = 3,
46*74a4d8c2SCharles.Forsyth 	Ordeeprom = 4,
47*74a4d8c2SCharles.Forsyth 	Owreeprom = 5,
48*74a4d8c2SCharles.Forsyth 	Othermal = 6,
49*74a4d8c2SCharles.Forsyth 	Oled = 8,
50*74a4d8c2SCharles.Forsyth 	Obattery = 9,
51*74a4d8c2SCharles.Forsyth 	Ospiread = 11,
52*74a4d8c2SCharles.Forsyth 	Ospiwrite = 12,
53*74a4d8c2SCharles.Forsyth 	Obacklight = 13,
54*74a4d8c2SCharles.Forsyth 	Oextstatus = 0xA1,
55*74a4d8c2SCharles.Forsyth  };
56*74a4d8c2SCharles.Forsyth 
57*74a4d8c2SCharles.Forsyth enum {
58*74a4d8c2SCharles.Forsyth 	Powerbit = 0,	/* GPIO bit for power on/off key */
59*74a4d8c2SCharles.Forsyth };
60*74a4d8c2SCharles.Forsyth 
61*74a4d8c2SCharles.Forsyth enum{
62*74a4d8c2SCharles.Forsyth 	Qdir,
63*74a4d8c2SCharles.Forsyth 	Qctl,
64*74a4d8c2SCharles.Forsyth 	Qtouchctl,
65*74a4d8c2SCharles.Forsyth 	Qbattery,
66*74a4d8c2SCharles.Forsyth 	Qversion,
67*74a4d8c2SCharles.Forsyth };
68*74a4d8c2SCharles.Forsyth 
69*74a4d8c2SCharles.Forsyth static
70*74a4d8c2SCharles.Forsyth Dirtab ipaqtab[]={
71*74a4d8c2SCharles.Forsyth 	".",	{Qdir, 0, QTDIR},	0,	0555,
72*74a4d8c2SCharles.Forsyth 	"ipaqctl",		{Qctl},		0,	0600,
73*74a4d8c2SCharles.Forsyth 	"battery",		{Qbattery},	0,	0444,
74*74a4d8c2SCharles.Forsyth 	"version",		{Qversion},	0,	0444,
75*74a4d8c2SCharles.Forsyth 	"touchctl",	{Qtouchctl},	0,	0644,
76*74a4d8c2SCharles.Forsyth };
77*74a4d8c2SCharles.Forsyth 
78*74a4d8c2SCharles.Forsyth static struct {
79*74a4d8c2SCharles.Forsyth 	QLock;
80*74a4d8c2SCharles.Forsyth 	Chan*	c;
81*74a4d8c2SCharles.Forsyth 
82*74a4d8c2SCharles.Forsyth 	Lock	rl;	/* protect cmd, reply */
83*74a4d8c2SCharles.Forsyth 	int	cmd;
84*74a4d8c2SCharles.Forsyth 	Block*	reply;
85*74a4d8c2SCharles.Forsyth 	Rendez	r;
86*74a4d8c2SCharles.Forsyth } atmel;
87*74a4d8c2SCharles.Forsyth 
88*74a4d8c2SCharles.Forsyth /* to and from fixed point */
89*74a4d8c2SCharles.Forsyth #define	FX(a,b)	(((a)<<16)/(b))
90*74a4d8c2SCharles.Forsyth #define	XF(v)		((v)>>16)
91*74a4d8c2SCharles.Forsyth 
92*74a4d8c2SCharles.Forsyth static struct {
93*74a4d8c2SCharles.Forsyth 	Lock;
94*74a4d8c2SCharles.Forsyth 	int	rate;
95*74a4d8c2SCharles.Forsyth 	int	m[2][3];	/* transformation matrix */
96*74a4d8c2SCharles.Forsyth 	Point	avg;
97*74a4d8c2SCharles.Forsyth 	Point	diff;
98*74a4d8c2SCharles.Forsyth 	Point	pts[4];
99*74a4d8c2SCharles.Forsyth 	int	n;	/* number of points in pts */
100*74a4d8c2SCharles.Forsyth 	int	p;	/* current index in pts */
101*74a4d8c2SCharles.Forsyth 	int	down;
102*74a4d8c2SCharles.Forsyth 	int	nout;
103*74a4d8c2SCharles.Forsyth } touch = {
104*74a4d8c2SCharles.Forsyth 	{0},
105*74a4d8c2SCharles.Forsyth 	.m {{-FX(1,3), 0, FX(346,1)},{0, -FX(1,4), FX(256, 1)}},
106*74a4d8c2SCharles.Forsyth };
107*74a4d8c2SCharles.Forsyth 
108*74a4d8c2SCharles.Forsyth /*
109*74a4d8c2SCharles.Forsyth  * map rocker positions to same codes as plan 9
110*74a4d8c2SCharles.Forsyth  */
111*74a4d8c2SCharles.Forsyth static	Rune	rockermap[2][4] ={
112*74a4d8c2SCharles.Forsyth 	{Right, Down, Up, Left},	/* landscape */
113*74a4d8c2SCharles.Forsyth 	{Up, Right, Left, Down},	/* portrait */
114*74a4d8c2SCharles.Forsyth };
115*74a4d8c2SCharles.Forsyth 
116*74a4d8c2SCharles.Forsyth static	Rendez	powerevent;
117*74a4d8c2SCharles.Forsyth 
118*74a4d8c2SCharles.Forsyth static	void	cmdack(int, void*, int);
119*74a4d8c2SCharles.Forsyth static	int	cmdio(int, void*, int, void*, int);
120*74a4d8c2SCharles.Forsyth static	void	ipaqreadproc(void*);
121*74a4d8c2SCharles.Forsyth static	void	powerwaitproc(void*);
122*74a4d8c2SCharles.Forsyth static	Block*	rdevent(Block**);
123*74a4d8c2SCharles.Forsyth static	long	touchctl(char*, long);
124*74a4d8c2SCharles.Forsyth static	void	touched(Block*, int);
125*74a4d8c2SCharles.Forsyth static	int	wrcmd(int, void*, int, void*, int);
126*74a4d8c2SCharles.Forsyth static	char*	acstatus(int);
127*74a4d8c2SCharles.Forsyth static	char*	batstatus(int);
128*74a4d8c2SCharles.Forsyth static	void	powerintr(Ureg*, void*);
129*74a4d8c2SCharles.Forsyth 
130*74a4d8c2SCharles.Forsyth static void
ipaqreset(void)131*74a4d8c2SCharles.Forsyth ipaqreset(void)
132*74a4d8c2SCharles.Forsyth {
133*74a4d8c2SCharles.Forsyth 	intrenable(Powerbit, powerintr, nil, BusGPIOfalling, "power off");
134*74a4d8c2SCharles.Forsyth }
135*74a4d8c2SCharles.Forsyth 
136*74a4d8c2SCharles.Forsyth static void
ipaqinit(void)137*74a4d8c2SCharles.Forsyth ipaqinit(void)
138*74a4d8c2SCharles.Forsyth {
139*74a4d8c2SCharles.Forsyth 	kproc("powerwait", powerwaitproc, nil, 0);
140*74a4d8c2SCharles.Forsyth }
141*74a4d8c2SCharles.Forsyth 
142*74a4d8c2SCharles.Forsyth static Chan*
ipaqattach(char * spec)143*74a4d8c2SCharles.Forsyth ipaqattach(char* spec)
144*74a4d8c2SCharles.Forsyth {
145*74a4d8c2SCharles.Forsyth 	int fd;
146*74a4d8c2SCharles.Forsyth 
147*74a4d8c2SCharles.Forsyth 	qlock(&atmel);
148*74a4d8c2SCharles.Forsyth 	if(waserror()){
149*74a4d8c2SCharles.Forsyth 		qunlock(&atmel);
150*74a4d8c2SCharles.Forsyth 		nexterror();
151*74a4d8c2SCharles.Forsyth 	}
152*74a4d8c2SCharles.Forsyth 	if(atmel.c == nil){
153*74a4d8c2SCharles.Forsyth 		fd = kopen("#t/eia1ctl", ORDWR);
154*74a4d8c2SCharles.Forsyth 		if(fd < 0)
155*74a4d8c2SCharles.Forsyth 			error(up->env->errstr);
156*74a4d8c2SCharles.Forsyth 		kwrite(fd, "b115200", 7);	/* it's already pn, l8 */
157*74a4d8c2SCharles.Forsyth 		kclose(fd);
158*74a4d8c2SCharles.Forsyth 		fd = kopen("#t/eia1", ORDWR);
159*74a4d8c2SCharles.Forsyth 		if(fd < 0)
160*74a4d8c2SCharles.Forsyth 			error(up->env->errstr);
161*74a4d8c2SCharles.Forsyth 		atmel.c = fdtochan(up->env->fgrp, fd, ORDWR, 0, 1);
162*74a4d8c2SCharles.Forsyth 		kclose(fd);
163*74a4d8c2SCharles.Forsyth 		atmel.cmd = -1;
164*74a4d8c2SCharles.Forsyth 		kproc("ipaqread", ipaqreadproc, nil, 0);
165*74a4d8c2SCharles.Forsyth 	}
166*74a4d8c2SCharles.Forsyth 	poperror();
167*74a4d8c2SCharles.Forsyth 	qunlock(&atmel);
168*74a4d8c2SCharles.Forsyth 	return devattach('T', spec);
169*74a4d8c2SCharles.Forsyth }
170*74a4d8c2SCharles.Forsyth 
171*74a4d8c2SCharles.Forsyth static Walkqid*
ipaqwalk(Chan * c,Chan * nc,char ** name,int nname)172*74a4d8c2SCharles.Forsyth ipaqwalk(Chan *c, Chan *nc, char **name, int nname)
173*74a4d8c2SCharles.Forsyth {
174*74a4d8c2SCharles.Forsyth 	return devwalk(c, nc, name, nname, ipaqtab, nelem(ipaqtab), devgen);
175*74a4d8c2SCharles.Forsyth }
176*74a4d8c2SCharles.Forsyth 
177*74a4d8c2SCharles.Forsyth static int
ipaqstat(Chan * c,uchar * db,int n)178*74a4d8c2SCharles.Forsyth ipaqstat(Chan* c, uchar *db, int n)
179*74a4d8c2SCharles.Forsyth {
180*74a4d8c2SCharles.Forsyth 	return devstat(c, db, n, ipaqtab, nelem(ipaqtab), devgen);
181*74a4d8c2SCharles.Forsyth }
182*74a4d8c2SCharles.Forsyth 
183*74a4d8c2SCharles.Forsyth static Chan*
ipaqopen(Chan * c,int omode)184*74a4d8c2SCharles.Forsyth ipaqopen(Chan* c, int omode)
185*74a4d8c2SCharles.Forsyth {
186*74a4d8c2SCharles.Forsyth 	return devopen(c, omode, ipaqtab, nelem(ipaqtab), devgen);
187*74a4d8c2SCharles.Forsyth }
188*74a4d8c2SCharles.Forsyth 
189*74a4d8c2SCharles.Forsyth static void
ipaqclose(Chan *)190*74a4d8c2SCharles.Forsyth ipaqclose(Chan*)
191*74a4d8c2SCharles.Forsyth {
192*74a4d8c2SCharles.Forsyth }
193*74a4d8c2SCharles.Forsyth 
194*74a4d8c2SCharles.Forsyth static long
ipaqread(Chan * c,void * a,long n,vlong offset)195*74a4d8c2SCharles.Forsyth ipaqread(Chan* c, void* a, long n, vlong offset)
196*74a4d8c2SCharles.Forsyth {
197*74a4d8c2SCharles.Forsyth 	char *tmp, buf[64];
198*74a4d8c2SCharles.Forsyth 	uchar reply[12];
199*74a4d8c2SCharles.Forsyth 	int v, p, l;
200*74a4d8c2SCharles.Forsyth 
201*74a4d8c2SCharles.Forsyth 	switch((ulong)c->qid.path){
202*74a4d8c2SCharles.Forsyth 	case Qdir:
203*74a4d8c2SCharles.Forsyth 		return devdirread(c, a, n, ipaqtab, nelem(ipaqtab), devgen);
204*74a4d8c2SCharles.Forsyth 	case Qtouchctl:
205*74a4d8c2SCharles.Forsyth 		tmp = malloc(READSTR);
206*74a4d8c2SCharles.Forsyth 		if(waserror()){
207*74a4d8c2SCharles.Forsyth 			free(tmp);
208*74a4d8c2SCharles.Forsyth 			nexterror();
209*74a4d8c2SCharles.Forsyth 		}
210*74a4d8c2SCharles.Forsyth 		snprint(tmp, READSTR, "s%d\nr%d\nR%d\nX %d %d %d\nY %d %d %d\n",
211*74a4d8c2SCharles.Forsyth 			1000, 0, 1,
212*74a4d8c2SCharles.Forsyth 			touch.m[0][0], touch.m[0][1], touch.m[0][2],
213*74a4d8c2SCharles.Forsyth 			touch.m[1][0], touch.m[1][1], touch.m[1][2]);
214*74a4d8c2SCharles.Forsyth 		n = readstr(offset, a, n, tmp);
215*74a4d8c2SCharles.Forsyth 		poperror();
216*74a4d8c2SCharles.Forsyth 		free(tmp);
217*74a4d8c2SCharles.Forsyth 		break;
218*74a4d8c2SCharles.Forsyth 	case Qbattery:
219*74a4d8c2SCharles.Forsyth 		cmdio(Obattery, reply, 0, reply, sizeof(reply));
220*74a4d8c2SCharles.Forsyth 		tmp = malloc(READSTR);
221*74a4d8c2SCharles.Forsyth 		if(waserror()){
222*74a4d8c2SCharles.Forsyth 			free(tmp);
223*74a4d8c2SCharles.Forsyth 			nexterror();
224*74a4d8c2SCharles.Forsyth 		}
225*74a4d8c2SCharles.Forsyth 		v = (reply[4]<<8)|reply[3];
226*74a4d8c2SCharles.Forsyth 		p = 425*v/1000 - 298;
227*74a4d8c2SCharles.Forsyth 		snprint(tmp, READSTR, "voltage: %d %dmV %d%% %d\nac: %s\nstatus: %d %s\nchem: %d\n",
228*74a4d8c2SCharles.Forsyth 			v, 1000*v/228, p, 300*p/100, acstatus(reply[1]), reply[5], batstatus(reply[5]), reply[2]);
229*74a4d8c2SCharles.Forsyth 		n = readstr(offset, a, n, tmp);
230*74a4d8c2SCharles.Forsyth 		poperror();
231*74a4d8c2SCharles.Forsyth 		free(tmp);
232*74a4d8c2SCharles.Forsyth 		break;
233*74a4d8c2SCharles.Forsyth 	case Qversion:
234*74a4d8c2SCharles.Forsyth 		l = cmdio(Oversion, reply, 0, reply, sizeof(reply));
235*74a4d8c2SCharles.Forsyth 		if(l > 4){
236*74a4d8c2SCharles.Forsyth 			l--;
237*74a4d8c2SCharles.Forsyth 			memmove(buf, reply+1, 4);
238*74a4d8c2SCharles.Forsyth 			if(l > 8){
239*74a4d8c2SCharles.Forsyth 				buf[4] = ' ';
240*74a4d8c2SCharles.Forsyth 				memmove(buf+5, reply+5, 4);	/* pack version */
241*74a4d8c2SCharles.Forsyth 				sprint(buf+9, " %.2x\n", reply[9]);	/* ``boot type'' */
242*74a4d8c2SCharles.Forsyth 			}else{
243*74a4d8c2SCharles.Forsyth 				buf[4] = '\n';
244*74a4d8c2SCharles.Forsyth 				buf[5] = 0;
245*74a4d8c2SCharles.Forsyth 			}
246*74a4d8c2SCharles.Forsyth 			return readstr(offset, a, n, buf);
247*74a4d8c2SCharles.Forsyth 		}
248*74a4d8c2SCharles.Forsyth 		n=0;
249*74a4d8c2SCharles.Forsyth 		break;
250*74a4d8c2SCharles.Forsyth 	default:
251*74a4d8c2SCharles.Forsyth 		n=0;
252*74a4d8c2SCharles.Forsyth 		break;
253*74a4d8c2SCharles.Forsyth 	}
254*74a4d8c2SCharles.Forsyth 	return n;
255*74a4d8c2SCharles.Forsyth }
256*74a4d8c2SCharles.Forsyth 
257*74a4d8c2SCharles.Forsyth static long
ipaqwrite(Chan * c,void * a,long n,vlong)258*74a4d8c2SCharles.Forsyth ipaqwrite(Chan* c, void* a, long n, vlong)
259*74a4d8c2SCharles.Forsyth {
260*74a4d8c2SCharles.Forsyth 	char cmd[64], op[32], *fields[6];
261*74a4d8c2SCharles.Forsyth 	int nf;
262*74a4d8c2SCharles.Forsyth 
263*74a4d8c2SCharles.Forsyth 	switch((ulong)c->qid.path){
264*74a4d8c2SCharles.Forsyth 	case Qctl:
265*74a4d8c2SCharles.Forsyth 		if(n >= sizeof(cmd)-1)
266*74a4d8c2SCharles.Forsyth 			n = sizeof(cmd)-1;
267*74a4d8c2SCharles.Forsyth 		memmove(cmd, a, n);
268*74a4d8c2SCharles.Forsyth 		cmd[n] = 0;
269*74a4d8c2SCharles.Forsyth 		nf = getfields(cmd, fields, nelem(fields), 1, " \t\n");
270*74a4d8c2SCharles.Forsyth 		if(nf <= 0)
271*74a4d8c2SCharles.Forsyth 			error(Ebadarg);
272*74a4d8c2SCharles.Forsyth 		if(nf >= 4 && strcmp(fields[0], "light") == 0){
273*74a4d8c2SCharles.Forsyth 			op[0] = atoi(fields[1]);	/* mode */
274*74a4d8c2SCharles.Forsyth 			op[1] = atoi(fields[2]);	/* power */
275*74a4d8c2SCharles.Forsyth 			op[2] = atoi(fields[3]);	/* brightness */
276*74a4d8c2SCharles.Forsyth 			cmdack(Obacklight, op, 3);
277*74a4d8c2SCharles.Forsyth 		}else if(nf >= 5 && strcmp(fields[0], "led") == 0){
278*74a4d8c2SCharles.Forsyth 			op[0] = atoi(fields[1]);
279*74a4d8c2SCharles.Forsyth 			op[1] = atoi(fields[2]);
280*74a4d8c2SCharles.Forsyth 			op[2] = atoi(fields[3]);
281*74a4d8c2SCharles.Forsyth 			op[3] = atoi(fields[4]);
282*74a4d8c2SCharles.Forsyth 			cmdack(Oled, op, 4);
283*74a4d8c2SCharles.Forsyth 		}else if(strcmp(fields[0], "suspend") == 0){
284*74a4d8c2SCharles.Forsyth 			/* let the kproc do it */
285*74a4d8c2SCharles.Forsyth 			wakeup(&powerevent);
286*74a4d8c2SCharles.Forsyth 		}else
287*74a4d8c2SCharles.Forsyth 			error(Ebadarg);
288*74a4d8c2SCharles.Forsyth 		break;
289*74a4d8c2SCharles.Forsyth 	case Qtouchctl:
290*74a4d8c2SCharles.Forsyth 		return touchctl(a, n);
291*74a4d8c2SCharles.Forsyth 	default:
292*74a4d8c2SCharles.Forsyth 		error(Ebadusefd);
293*74a4d8c2SCharles.Forsyth 	}
294*74a4d8c2SCharles.Forsyth 	return n;
295*74a4d8c2SCharles.Forsyth }
296*74a4d8c2SCharles.Forsyth 
297*74a4d8c2SCharles.Forsyth static void
powerintr(Ureg *,void *)298*74a4d8c2SCharles.Forsyth powerintr(Ureg*, void*)
299*74a4d8c2SCharles.Forsyth {
300*74a4d8c2SCharles.Forsyth 	wakeup(&powerevent);
301*74a4d8c2SCharles.Forsyth }
302*74a4d8c2SCharles.Forsyth 
303*74a4d8c2SCharles.Forsyth static void
cmdack(int id,void * a,int n)304*74a4d8c2SCharles.Forsyth cmdack(int id, void *a, int n)
305*74a4d8c2SCharles.Forsyth {
306*74a4d8c2SCharles.Forsyth 	uchar reply[16];
307*74a4d8c2SCharles.Forsyth 
308*74a4d8c2SCharles.Forsyth 	cmdio(id, a, n, reply, sizeof(reply));
309*74a4d8c2SCharles.Forsyth }
310*74a4d8c2SCharles.Forsyth 
311*74a4d8c2SCharles.Forsyth static int
cmdio(int id,void * a,int n,void * reply,int lim)312*74a4d8c2SCharles.Forsyth cmdio(int id, void *a, int n, void *reply, int lim)
313*74a4d8c2SCharles.Forsyth {
314*74a4d8c2SCharles.Forsyth 	qlock(&atmel);
315*74a4d8c2SCharles.Forsyth 	if(waserror()){
316*74a4d8c2SCharles.Forsyth 		qunlock(&atmel);
317*74a4d8c2SCharles.Forsyth 		nexterror();
318*74a4d8c2SCharles.Forsyth 	}
319*74a4d8c2SCharles.Forsyth 	n = wrcmd(id, a, n, reply, lim);
320*74a4d8c2SCharles.Forsyth 	poperror();
321*74a4d8c2SCharles.Forsyth 	qunlock(&atmel);
322*74a4d8c2SCharles.Forsyth 	return n;
323*74a4d8c2SCharles.Forsyth }
324*74a4d8c2SCharles.Forsyth 
325*74a4d8c2SCharles.Forsyth static int
havereply(void *)326*74a4d8c2SCharles.Forsyth havereply(void*)
327*74a4d8c2SCharles.Forsyth {
328*74a4d8c2SCharles.Forsyth 	return atmel.reply != nil;
329*74a4d8c2SCharles.Forsyth }
330*74a4d8c2SCharles.Forsyth 
331*74a4d8c2SCharles.Forsyth static int
wrcmd(int id,void * a,int n,void * b,int lim)332*74a4d8c2SCharles.Forsyth wrcmd(int id, void *a, int n, void *b, int lim)
333*74a4d8c2SCharles.Forsyth {
334*74a4d8c2SCharles.Forsyth 	uchar buf[32];
335*74a4d8c2SCharles.Forsyth 	int i, sum;
336*74a4d8c2SCharles.Forsyth 	Block *e;
337*74a4d8c2SCharles.Forsyth 
338*74a4d8c2SCharles.Forsyth 	if(n >= 16)
339*74a4d8c2SCharles.Forsyth 		error(Eio);
340*74a4d8c2SCharles.Forsyth 	lock(&atmel.rl);
341*74a4d8c2SCharles.Forsyth 	atmel.cmd = id;
342*74a4d8c2SCharles.Forsyth 	unlock(&atmel.rl);
343*74a4d8c2SCharles.Forsyth 	buf[0] = Csof;
344*74a4d8c2SCharles.Forsyth 	buf[1] = (id<<4) | (n&0xF);
345*74a4d8c2SCharles.Forsyth 	if(n)
346*74a4d8c2SCharles.Forsyth 		memmove(buf+2, a, n);
347*74a4d8c2SCharles.Forsyth 	sum = 0;
348*74a4d8c2SCharles.Forsyth 	for(i=1; i<n+2; i++)
349*74a4d8c2SCharles.Forsyth 		sum += buf[i];
350*74a4d8c2SCharles.Forsyth 	buf[i++] = sum;
351*74a4d8c2SCharles.Forsyth 	if(0){
352*74a4d8c2SCharles.Forsyth 		iprint("msg=");
353*74a4d8c2SCharles.Forsyth 		for(sum=0; sum<i; sum++)
354*74a4d8c2SCharles.Forsyth 			iprint(" %2.2ux", buf[sum]);
355*74a4d8c2SCharles.Forsyth 		iprint("\n");
356*74a4d8c2SCharles.Forsyth 	}
357*74a4d8c2SCharles.Forsyth 	if(kchanio(atmel.c, buf, i, OWRITE) != i)
358*74a4d8c2SCharles.Forsyth 		error(Eio);
359*74a4d8c2SCharles.Forsyth 	tsleep(&atmel.r, havereply, nil, 500);
360*74a4d8c2SCharles.Forsyth 	lock(&atmel.rl);
361*74a4d8c2SCharles.Forsyth 	e = atmel.reply;
362*74a4d8c2SCharles.Forsyth 	atmel.reply = nil;
363*74a4d8c2SCharles.Forsyth 	atmel.cmd = -1;
364*74a4d8c2SCharles.Forsyth 	unlock(&atmel.rl);
365*74a4d8c2SCharles.Forsyth 	if(e == nil){
366*74a4d8c2SCharles.Forsyth 		print("ipaq: no reply\n");
367*74a4d8c2SCharles.Forsyth 		error(Eio);
368*74a4d8c2SCharles.Forsyth 	}
369*74a4d8c2SCharles.Forsyth 	if(waserror()){
370*74a4d8c2SCharles.Forsyth 		freeb(e);
371*74a4d8c2SCharles.Forsyth 		nexterror();
372*74a4d8c2SCharles.Forsyth 	}
373*74a4d8c2SCharles.Forsyth 	if(e->rp[0] != id){
374*74a4d8c2SCharles.Forsyth 		print("ipaq: rdreply: mismatched reply %d :: %d\n", id, e->rp[0]);
375*74a4d8c2SCharles.Forsyth 		error(Eio);
376*74a4d8c2SCharles.Forsyth 	}
377*74a4d8c2SCharles.Forsyth 	n = BLEN(e);
378*74a4d8c2SCharles.Forsyth 	if(n < lim)
379*74a4d8c2SCharles.Forsyth 		lim = n;
380*74a4d8c2SCharles.Forsyth 	memmove(b, e->rp, lim);
381*74a4d8c2SCharles.Forsyth 	poperror();
382*74a4d8c2SCharles.Forsyth 	freeb(e);
383*74a4d8c2SCharles.Forsyth 	return lim;
384*74a4d8c2SCharles.Forsyth }
385*74a4d8c2SCharles.Forsyth 
386*74a4d8c2SCharles.Forsyth static void
ipaqreadproc(void *)387*74a4d8c2SCharles.Forsyth ipaqreadproc(void*)
388*74a4d8c2SCharles.Forsyth {
389*74a4d8c2SCharles.Forsyth 	Block *e, *b, *partial;
390*74a4d8c2SCharles.Forsyth 	int c, mousemod;
391*74a4d8c2SCharles.Forsyth 
392*74a4d8c2SCharles.Forsyth 	while(waserror())
393*74a4d8c2SCharles.Forsyth 		print("ipaqread: %r\n");
394*74a4d8c2SCharles.Forsyth 	partial = nil;
395*74a4d8c2SCharles.Forsyth 	mousemod = 0;
396*74a4d8c2SCharles.Forsyth 	for(;;){
397*74a4d8c2SCharles.Forsyth 		e = rdevent(&partial);
398*74a4d8c2SCharles.Forsyth 		if(e == nil){
399*74a4d8c2SCharles.Forsyth 			print("ipaqread: rdevent: %r\n");
400*74a4d8c2SCharles.Forsyth 			continue;
401*74a4d8c2SCharles.Forsyth 		}
402*74a4d8c2SCharles.Forsyth 		switch(e->rp[0]){
403*74a4d8c2SCharles.Forsyth 		case Otouch:
404*74a4d8c2SCharles.Forsyth 			touched(e, mousemod);
405*74a4d8c2SCharles.Forsyth 			freeb(e);
406*74a4d8c2SCharles.Forsyth 			break;
407*74a4d8c2SCharles.Forsyth 		case Okeys:
408*74a4d8c2SCharles.Forsyth 			//print("key %2.2ux\n", e->rp[1]);
409*74a4d8c2SCharles.Forsyth 			c = e->rp[1] & 0xF;
410*74a4d8c2SCharles.Forsyth 			if(c >= 6 && c < 10){	/* rocker */
411*74a4d8c2SCharles.Forsyth 				if((e->rp[1] & 0x80) == 0){
412*74a4d8c2SCharles.Forsyth 					kbdrepeat(0);
413*74a4d8c2SCharles.Forsyth 					kbdputc(kbdq, rockermap[conf.portrait&1][c-6]);
414*74a4d8c2SCharles.Forsyth 				}else
415*74a4d8c2SCharles.Forsyth 					kbdrepeat(0);
416*74a4d8c2SCharles.Forsyth 			}else{
417*74a4d8c2SCharles.Forsyth 				/* TO DO: change tkmouse and mousetrack to allow extra buttons */
418*74a4d8c2SCharles.Forsyth 				if(--c == 0)
419*74a4d8c2SCharles.Forsyth 					c = 5;
420*74a4d8c2SCharles.Forsyth 				if(e->rp[1] & 0x80)
421*74a4d8c2SCharles.Forsyth 					mousemod &= ~(1<<c);
422*74a4d8c2SCharles.Forsyth 				else
423*74a4d8c2SCharles.Forsyth 					mousemod |= 1<<c;
424*74a4d8c2SCharles.Forsyth 			}
425*74a4d8c2SCharles.Forsyth 			freeb(e);
426*74a4d8c2SCharles.Forsyth 			break;
427*74a4d8c2SCharles.Forsyth 		default:
428*74a4d8c2SCharles.Forsyth 			lock(&atmel.rl);
429*74a4d8c2SCharles.Forsyth 			if(atmel.cmd == e->rp[0]){
430*74a4d8c2SCharles.Forsyth 				b = atmel.reply;
431*74a4d8c2SCharles.Forsyth 				atmel.reply = e;
432*74a4d8c2SCharles.Forsyth 				unlock(&atmel.rl);
433*74a4d8c2SCharles.Forsyth 				wakeup(&atmel.r);
434*74a4d8c2SCharles.Forsyth 				if(b != nil)
435*74a4d8c2SCharles.Forsyth 					freeb(b);
436*74a4d8c2SCharles.Forsyth 			}else{
437*74a4d8c2SCharles.Forsyth 				unlock(&atmel.rl);
438*74a4d8c2SCharles.Forsyth 				print("ipaqread: discard op %d\n", e->rp[0]);
439*74a4d8c2SCharles.Forsyth 				freeb(e);
440*74a4d8c2SCharles.Forsyth 			}
441*74a4d8c2SCharles.Forsyth 		}
442*74a4d8c2SCharles.Forsyth 	}
443*74a4d8c2SCharles.Forsyth }
444*74a4d8c2SCharles.Forsyth 
445*74a4d8c2SCharles.Forsyth static Block *
rdevent(Block ** bp)446*74a4d8c2SCharles.Forsyth rdevent(Block **bp)
447*74a4d8c2SCharles.Forsyth {
448*74a4d8c2SCharles.Forsyth 	Block *b, *e;
449*74a4d8c2SCharles.Forsyth 	int s, c, len, csum;
450*74a4d8c2SCharles.Forsyth 	enum {Ssof=16, Sid, Ssum};
451*74a4d8c2SCharles.Forsyth 
452*74a4d8c2SCharles.Forsyth 	s = Ssof;
453*74a4d8c2SCharles.Forsyth 	csum = 0;
454*74a4d8c2SCharles.Forsyth 	len = 0;
455*74a4d8c2SCharles.Forsyth 	e = nil;
456*74a4d8c2SCharles.Forsyth 	if(waserror()){
457*74a4d8c2SCharles.Forsyth 		if(e != nil)
458*74a4d8c2SCharles.Forsyth 			freeb(e);
459*74a4d8c2SCharles.Forsyth 		nexterror();
460*74a4d8c2SCharles.Forsyth 	}
461*74a4d8c2SCharles.Forsyth 	for(;;){
462*74a4d8c2SCharles.Forsyth 		b = *bp;
463*74a4d8c2SCharles.Forsyth 		*bp = nil;
464*74a4d8c2SCharles.Forsyth 		if(b == nil){
465*74a4d8c2SCharles.Forsyth 			b = devtab[atmel.c->type]->bread(atmel.c, 128, 0);
466*74a4d8c2SCharles.Forsyth 			if(b == nil)
467*74a4d8c2SCharles.Forsyth 				error(Eio);
468*74a4d8c2SCharles.Forsyth 			if(DEBUG)
469*74a4d8c2SCharles.Forsyth 				iprint("r: %ld\n", BLEN(b));
470*74a4d8c2SCharles.Forsyth 		}
471*74a4d8c2SCharles.Forsyth 		while(b->rp < b->wp){
472*74a4d8c2SCharles.Forsyth 			c = *b->rp++;
473*74a4d8c2SCharles.Forsyth 			switch(s){
474*74a4d8c2SCharles.Forsyth 			case Ssof:
475*74a4d8c2SCharles.Forsyth 				if(c == Csof)
476*74a4d8c2SCharles.Forsyth 					s = Sid;
477*74a4d8c2SCharles.Forsyth 				else if(1)
478*74a4d8c2SCharles.Forsyth 					iprint("!sof: %2.2ux %d\n", c, s);
479*74a4d8c2SCharles.Forsyth 				break;
480*74a4d8c2SCharles.Forsyth 			case Sid:
481*74a4d8c2SCharles.Forsyth 				csum = c;
482*74a4d8c2SCharles.Forsyth 				len = c & 0xF;
483*74a4d8c2SCharles.Forsyth 				e = allocb(len+1);
484*74a4d8c2SCharles.Forsyth 				if(e == nil)
485*74a4d8c2SCharles.Forsyth 					error(Eio);
486*74a4d8c2SCharles.Forsyth 				*e->wp++ = c>>4;	/* id */
487*74a4d8c2SCharles.Forsyth 				if(len)
488*74a4d8c2SCharles.Forsyth 					s = 0;
489*74a4d8c2SCharles.Forsyth 				else
490*74a4d8c2SCharles.Forsyth 					s = Ssum;
491*74a4d8c2SCharles.Forsyth 				break;
492*74a4d8c2SCharles.Forsyth 			case Ssum:
493*74a4d8c2SCharles.Forsyth 				csum &= 0xFF;
494*74a4d8c2SCharles.Forsyth 				if(c != csum){
495*74a4d8c2SCharles.Forsyth 					iprint("cksum: %2.2ux != %2.2ux\n", c, csum);
496*74a4d8c2SCharles.Forsyth 					s = Ssof;	/* try to resynchronise */
497*74a4d8c2SCharles.Forsyth 					if(e != nil){
498*74a4d8c2SCharles.Forsyth 						freeb(e);
499*74a4d8c2SCharles.Forsyth 						e = nil;
500*74a4d8c2SCharles.Forsyth 					}
501*74a4d8c2SCharles.Forsyth 					break;
502*74a4d8c2SCharles.Forsyth 				}
503*74a4d8c2SCharles.Forsyth 				if(b->rp < b->wp)
504*74a4d8c2SCharles.Forsyth 					*bp = b;
505*74a4d8c2SCharles.Forsyth 				else
506*74a4d8c2SCharles.Forsyth 					freeb(b);
507*74a4d8c2SCharles.Forsyth 				if(DEBUG){
508*74a4d8c2SCharles.Forsyth 					int i;
509*74a4d8c2SCharles.Forsyth 					iprint("event: [%ld]", BLEN(e));
510*74a4d8c2SCharles.Forsyth 					for(i=0; i<BLEN(e);i++)
511*74a4d8c2SCharles.Forsyth 						iprint(" %2.2ux", e->rp[i]);
512*74a4d8c2SCharles.Forsyth 					iprint("\n");
513*74a4d8c2SCharles.Forsyth 				}
514*74a4d8c2SCharles.Forsyth 				poperror();
515*74a4d8c2SCharles.Forsyth 				return e;
516*74a4d8c2SCharles.Forsyth 			default:
517*74a4d8c2SCharles.Forsyth 				csum += c;
518*74a4d8c2SCharles.Forsyth 				*e->wp++ = c;
519*74a4d8c2SCharles.Forsyth 				if(++s >= len)
520*74a4d8c2SCharles.Forsyth 					s = Ssum;
521*74a4d8c2SCharles.Forsyth 				break;
522*74a4d8c2SCharles.Forsyth 			}
523*74a4d8c2SCharles.Forsyth 		}
524*74a4d8c2SCharles.Forsyth 		freeb(b);
525*74a4d8c2SCharles.Forsyth 	}
526*74a4d8c2SCharles.Forsyth 	return 0;	/* not reached */
527*74a4d8c2SCharles.Forsyth }
528*74a4d8c2SCharles.Forsyth 
529*74a4d8c2SCharles.Forsyth static char *
acstatus(int x)530*74a4d8c2SCharles.Forsyth acstatus(int x)
531*74a4d8c2SCharles.Forsyth {
532*74a4d8c2SCharles.Forsyth 	switch(x){
533*74a4d8c2SCharles.Forsyth 	case 0:	return "offline";
534*74a4d8c2SCharles.Forsyth 	case 1:	return "online";
535*74a4d8c2SCharles.Forsyth 	case 2:	return "backup";
536*74a4d8c2SCharles.Forsyth 	}
537*74a4d8c2SCharles.Forsyth 	return "unknown";
538*74a4d8c2SCharles.Forsyth }
539*74a4d8c2SCharles.Forsyth 
540*74a4d8c2SCharles.Forsyth static char *
batstatus(int x)541*74a4d8c2SCharles.Forsyth batstatus(int x)
542*74a4d8c2SCharles.Forsyth {
543*74a4d8c2SCharles.Forsyth 	if(x & 0x40)
544*74a4d8c2SCharles.Forsyth 		return "charging";	/* not in linux but seems to be on mine */
545*74a4d8c2SCharles.Forsyth 	switch(x){
546*74a4d8c2SCharles.Forsyth 	case 0:		return "ok";
547*74a4d8c2SCharles.Forsyth 	case 1:		return "high";
548*74a4d8c2SCharles.Forsyth 	case 2:		return "low";
549*74a4d8c2SCharles.Forsyth 	case 4:		return "critical";
550*74a4d8c2SCharles.Forsyth 	case 8:		return "charging";
551*74a4d8c2SCharles.Forsyth 	case 0x80:	return "none";
552*74a4d8c2SCharles.Forsyth 	}
553*74a4d8c2SCharles.Forsyth 	return "unknown";
554*74a4d8c2SCharles.Forsyth }
555*74a4d8c2SCharles.Forsyth 
556*74a4d8c2SCharles.Forsyth static int
ptmap(int * m,int x,int y)557*74a4d8c2SCharles.Forsyth ptmap(int *m, int x, int y)
558*74a4d8c2SCharles.Forsyth {
559*74a4d8c2SCharles.Forsyth 	return XF(m[0]*x + m[1]*y + m[2]);
560*74a4d8c2SCharles.Forsyth }
561*74a4d8c2SCharles.Forsyth 
562*74a4d8c2SCharles.Forsyth static void
touched(Block * b,int buttons)563*74a4d8c2SCharles.Forsyth touched(Block *b, int buttons)
564*74a4d8c2SCharles.Forsyth {
565*74a4d8c2SCharles.Forsyth 	int rx, ry, x, y, dx, dy, n;
566*74a4d8c2SCharles.Forsyth 	Point op, *lp, cur;
567*74a4d8c2SCharles.Forsyth 
568*74a4d8c2SCharles.Forsyth 	if(BLEN(b) == 5){
569*74a4d8c2SCharles.Forsyth 		/* id Xhi Xlo Yhi Ylo */
570*74a4d8c2SCharles.Forsyth 		if(touch.down < 0){
571*74a4d8c2SCharles.Forsyth 			touch.down = 0;
572*74a4d8c2SCharles.Forsyth 			return;
573*74a4d8c2SCharles.Forsyth 		}
574*74a4d8c2SCharles.Forsyth 		rx = (b->rp[1]<<8)|b->rp[2];
575*74a4d8c2SCharles.Forsyth 		ry = (b->rp[3]<<8)|b->rp[4];
576*74a4d8c2SCharles.Forsyth 		if(conf.portrait){
577*74a4d8c2SCharles.Forsyth 			dx = rx; rx = ry; ry = dx;
578*74a4d8c2SCharles.Forsyth 		}
579*74a4d8c2SCharles.Forsyth 		if(touch.down == 0){
580*74a4d8c2SCharles.Forsyth 			touch.nout = 0;
581*74a4d8c2SCharles.Forsyth 			touch.p = 1;
582*74a4d8c2SCharles.Forsyth 			touch.n = 1;
583*74a4d8c2SCharles.Forsyth 			touch.avg = Pt(rx, ry);
584*74a4d8c2SCharles.Forsyth 			touch.pts[0] = touch.avg;
585*74a4d8c2SCharles.Forsyth 			touch.down = 1;
586*74a4d8c2SCharles.Forsyth 			return;
587*74a4d8c2SCharles.Forsyth 		}
588*74a4d8c2SCharles.Forsyth 		n = touch.p-1;
589*74a4d8c2SCharles.Forsyth 		if(n < 0)
590*74a4d8c2SCharles.Forsyth 			n = nelem(touch.pts)-1;
591*74a4d8c2SCharles.Forsyth 		lp = &touch.pts[n];	/* last point */
592*74a4d8c2SCharles.Forsyth 		if(touch.n > 0 && (rx-lp->x)*(ry-lp->y) > 50*50){	/* far out */
593*74a4d8c2SCharles.Forsyth 			if(++touch.nout > 3){
594*74a4d8c2SCharles.Forsyth 				touch.down = 0;
595*74a4d8c2SCharles.Forsyth 				touch.n = 0;
596*74a4d8c2SCharles.Forsyth 			}
597*74a4d8c2SCharles.Forsyth 			return;
598*74a4d8c2SCharles.Forsyth 		}
599*74a4d8c2SCharles.Forsyth 		op = touch.pts[touch.p];
600*74a4d8c2SCharles.Forsyth 		touch.pts[touch.p] = Pt(rx, ry);
601*74a4d8c2SCharles.Forsyth 		touch.p = (touch.p+1) % nelem(touch.pts);
602*74a4d8c2SCharles.Forsyth 		touch.avg.x += rx;
603*74a4d8c2SCharles.Forsyth 		touch.avg.y += ry;
604*74a4d8c2SCharles.Forsyth 		if(touch.n < nelem(touch.pts)){
605*74a4d8c2SCharles.Forsyth 			touch.n++;
606*74a4d8c2SCharles.Forsyth 			return;
607*74a4d8c2SCharles.Forsyth 		}
608*74a4d8c2SCharles.Forsyth 		touch.avg.x -= op.x;
609*74a4d8c2SCharles.Forsyth 		touch.avg.y -= op.y;
610*74a4d8c2SCharles.Forsyth 		cur = mousexy();
611*74a4d8c2SCharles.Forsyth 		rx = touch.avg.x/touch.n;
612*74a4d8c2SCharles.Forsyth 		ry = touch.avg.y/touch.n;
613*74a4d8c2SCharles.Forsyth 		x = ptmap(touch.m[0], rx, ry);
614*74a4d8c2SCharles.Forsyth 		dx = x-cur.x;
615*74a4d8c2SCharles.Forsyth 		y = ptmap(touch.m[1], rx, ry);
616*74a4d8c2SCharles.Forsyth 		dy = y-cur.y;
617*74a4d8c2SCharles.Forsyth 		if(dx*dx + dy*dy <= 2){
618*74a4d8c2SCharles.Forsyth 			dx = 0;
619*74a4d8c2SCharles.Forsyth 			dy = 0;
620*74a4d8c2SCharles.Forsyth 		}
621*74a4d8c2SCharles.Forsyth 		if(buttons == 0)
622*74a4d8c2SCharles.Forsyth 			buttons = 1<<0;	/* by default, stylus down implies button 1 */
623*74a4d8c2SCharles.Forsyth 		mousetrack(buttons&0x1f, dx, dy, 1);	/* TO DO: allow more than 3 buttons */
624*74a4d8c2SCharles.Forsyth 		/* TO DO: swcursupdate(oldx, oldy, x, y); */
625*74a4d8c2SCharles.Forsyth 		touch.down = 1;
626*74a4d8c2SCharles.Forsyth 	}else{
627*74a4d8c2SCharles.Forsyth 		if(touch.down){
628*74a4d8c2SCharles.Forsyth 			mousetrack(0, 0, 0, 1);	/* stylus up */
629*74a4d8c2SCharles.Forsyth 			touch.down = 0;
630*74a4d8c2SCharles.Forsyth 		}else
631*74a4d8c2SCharles.Forsyth 			touch.down = -1;
632*74a4d8c2SCharles.Forsyth 		touch.n = 0;
633*74a4d8c2SCharles.Forsyth 		touch.p = 0;
634*74a4d8c2SCharles.Forsyth 		touch.avg.x = 0;
635*74a4d8c2SCharles.Forsyth 		touch.avg.y = 0;
636*74a4d8c2SCharles.Forsyth 	}
637*74a4d8c2SCharles.Forsyth }
638*74a4d8c2SCharles.Forsyth 
639*74a4d8c2SCharles.Forsyth /*
640*74a4d8c2SCharles.Forsyth  * touchctl commands:
641*74a4d8c2SCharles.Forsyth  *	X a b c	- set X transformation
642*74a4d8c2SCharles.Forsyth  *	Y d e f	- set Y transformation
643*74a4d8c2SCharles.Forsyth  *	s<delay>		- set sample delay in millisec per sample
644*74a4d8c2SCharles.Forsyth  *	r<delay>		- set read delay in microsec
645*74a4d8c2SCharles.Forsyth  *	R<l2nr>			- set log2 of number of readings to average
646*74a4d8c2SCharles.Forsyth  */
647*74a4d8c2SCharles.Forsyth static long
touchctl(char * a,long n)648*74a4d8c2SCharles.Forsyth touchctl(char* a, long n)
649*74a4d8c2SCharles.Forsyth {
650*74a4d8c2SCharles.Forsyth 	char buf[64];
651*74a4d8c2SCharles.Forsyth 	char *cp;
652*74a4d8c2SCharles.Forsyth 	int n0 = n;
653*74a4d8c2SCharles.Forsyth 	int bn;
654*74a4d8c2SCharles.Forsyth 	char *field[8];
655*74a4d8c2SCharles.Forsyth 	int nf, cmd, pn, m[2][3];
656*74a4d8c2SCharles.Forsyth 
657*74a4d8c2SCharles.Forsyth 	while(n) {
658*74a4d8c2SCharles.Forsyth 		bn = (cp = memchr(a, '\n', n))!=nil ? cp-a+1 : n;
659*74a4d8c2SCharles.Forsyth 		n -= bn;
660*74a4d8c2SCharles.Forsyth 		cp = a;
661*74a4d8c2SCharles.Forsyth 		a += bn;
662*74a4d8c2SCharles.Forsyth 		bn = bn > sizeof(buf)-1 ? sizeof(buf)-1 : bn;
663*74a4d8c2SCharles.Forsyth 		memmove(buf, cp, bn);
664*74a4d8c2SCharles.Forsyth 		buf[bn] = '\0';
665*74a4d8c2SCharles.Forsyth 		nf = getfields(buf, field, nelem(field), 1, " \t\n");
666*74a4d8c2SCharles.Forsyth 		if(nf <= 0)
667*74a4d8c2SCharles.Forsyth 			continue;
668*74a4d8c2SCharles.Forsyth 		if(strcmp(field[0], "calibrate") == 0){
669*74a4d8c2SCharles.Forsyth 			if(nf == 1){
670*74a4d8c2SCharles.Forsyth 				lock(&touch);
671*74a4d8c2SCharles.Forsyth 				memset(touch.m, 0, sizeof(touch.m));
672*74a4d8c2SCharles.Forsyth 				touch.m[0][0] = FX(1,1);
673*74a4d8c2SCharles.Forsyth 				touch.m[1][1] = FX(1,1);
674*74a4d8c2SCharles.Forsyth 				unlock(&touch);
675*74a4d8c2SCharles.Forsyth 			}else if(nf >= 5){
676*74a4d8c2SCharles.Forsyth 				memset(m, 0, sizeof(m));
677*74a4d8c2SCharles.Forsyth 				m[0][0] = strtol(field[1], 0, 0);
678*74a4d8c2SCharles.Forsyth 				m[1][1] = strtol(field[2], 0, 0);
679*74a4d8c2SCharles.Forsyth 				m[0][2] = strtol(field[3], 0, 0);
680*74a4d8c2SCharles.Forsyth 				m[1][2] = strtol(field[4], 0, 0);
681*74a4d8c2SCharles.Forsyth 				if(nf > 5)
682*74a4d8c2SCharles.Forsyth 					m[0][1] = strtol(field[5], 0, 0);
683*74a4d8c2SCharles.Forsyth 				if(nf > 6)
684*74a4d8c2SCharles.Forsyth 					m[1][0] = strtol(field[6], 0, 0);
685*74a4d8c2SCharles.Forsyth 				lock(&touch);
686*74a4d8c2SCharles.Forsyth 				memmove(touch.m, m, sizeof(touch.m[0]));
687*74a4d8c2SCharles.Forsyth 				unlock(&touch);
688*74a4d8c2SCharles.Forsyth 			}else
689*74a4d8c2SCharles.Forsyth 				error(Ebadarg);
690*74a4d8c2SCharles.Forsyth 			continue;
691*74a4d8c2SCharles.Forsyth 		}
692*74a4d8c2SCharles.Forsyth 		cmd = *field[0]++;
693*74a4d8c2SCharles.Forsyth 		pn = *field[0] == 0;
694*74a4d8c2SCharles.Forsyth 		switch(cmd) {
695*74a4d8c2SCharles.Forsyth 		case 's':
696*74a4d8c2SCharles.Forsyth 			pn = strtol(field[pn], 0, 0);
697*74a4d8c2SCharles.Forsyth 			if(pn <= 0)
698*74a4d8c2SCharles.Forsyth 				error(Ebadarg);
699*74a4d8c2SCharles.Forsyth 			touch.rate = pn;
700*74a4d8c2SCharles.Forsyth 			break;
701*74a4d8c2SCharles.Forsyth 		case 'r':
702*74a4d8c2SCharles.Forsyth 			/* touch read delay */
703*74a4d8c2SCharles.Forsyth 			break;
704*74a4d8c2SCharles.Forsyth 		case 'X':
705*74a4d8c2SCharles.Forsyth 		case 'Y':
706*74a4d8c2SCharles.Forsyth 			if(nf < pn+2)
707*74a4d8c2SCharles.Forsyth 				error(Ebadarg);
708*74a4d8c2SCharles.Forsyth 			m[0][0] = strtol(field[pn], 0, 0);
709*74a4d8c2SCharles.Forsyth 			m[0][1] = strtol(field[pn+1], 0, 0);
710*74a4d8c2SCharles.Forsyth 			m[0][2] = strtol(field[pn+2], 0, 0);
711*74a4d8c2SCharles.Forsyth 			lock(&touch);
712*74a4d8c2SCharles.Forsyth 			memmove(touch.m[cmd=='Y'], m[0], sizeof(touch.m[0]));
713*74a4d8c2SCharles.Forsyth 			unlock(&touch);
714*74a4d8c2SCharles.Forsyth 			break;
715*74a4d8c2SCharles.Forsyth 		default:
716*74a4d8c2SCharles.Forsyth 			error(Ebadarg);
717*74a4d8c2SCharles.Forsyth 		}
718*74a4d8c2SCharles.Forsyth 	}
719*74a4d8c2SCharles.Forsyth 	return n0-n;
720*74a4d8c2SCharles.Forsyth }
721*74a4d8c2SCharles.Forsyth 
722*74a4d8c2SCharles.Forsyth /*
723*74a4d8c2SCharles.Forsyth  * this might belong elsewhere
724*74a4d8c2SCharles.Forsyth  */
725*74a4d8c2SCharles.Forsyth static int
powerwait(void *)726*74a4d8c2SCharles.Forsyth powerwait(void*)
727*74a4d8c2SCharles.Forsyth {
728*74a4d8c2SCharles.Forsyth 	return (GPIOREG->gplr & GPIO_PWR_ON_i) == 0;
729*74a4d8c2SCharles.Forsyth }
730*74a4d8c2SCharles.Forsyth 
731*74a4d8c2SCharles.Forsyth static void
powerwaitproc(void *)732*74a4d8c2SCharles.Forsyth powerwaitproc(void*)
733*74a4d8c2SCharles.Forsyth {
734*74a4d8c2SCharles.Forsyth 	for(;;){
735*74a4d8c2SCharles.Forsyth 		sleep(&powerevent, powerwait, nil);
736*74a4d8c2SCharles.Forsyth 		do{
737*74a4d8c2SCharles.Forsyth 			tsleep(&up->sleep, return0, nil, 50);
738*74a4d8c2SCharles.Forsyth 		}while((GPIOREG->gplr & GPIO_PWR_ON_i) == 0);
739*74a4d8c2SCharles.Forsyth 		powersuspend();
740*74a4d8c2SCharles.Forsyth 	}
741*74a4d8c2SCharles.Forsyth }
742*74a4d8c2SCharles.Forsyth 
743*74a4d8c2SCharles.Forsyth Dev ipaqdevtab = {
744*74a4d8c2SCharles.Forsyth 	'T',
745*74a4d8c2SCharles.Forsyth 	"ipaq",
746*74a4d8c2SCharles.Forsyth 
747*74a4d8c2SCharles.Forsyth 	ipaqreset,
748*74a4d8c2SCharles.Forsyth 	ipaqinit,
749*74a4d8c2SCharles.Forsyth 	devshutdown,
750*74a4d8c2SCharles.Forsyth 	ipaqattach,
751*74a4d8c2SCharles.Forsyth 	ipaqwalk,
752*74a4d8c2SCharles.Forsyth 	ipaqstat,
753*74a4d8c2SCharles.Forsyth 	ipaqopen,
754*74a4d8c2SCharles.Forsyth 	devcreate,
755*74a4d8c2SCharles.Forsyth 	ipaqclose,
756*74a4d8c2SCharles.Forsyth 	ipaqread,
757*74a4d8c2SCharles.Forsyth 	devbread,
758*74a4d8c2SCharles.Forsyth 	ipaqwrite,
759*74a4d8c2SCharles.Forsyth 	devbwrite,
760*74a4d8c2SCharles.Forsyth 	devremove,
761*74a4d8c2SCharles.Forsyth 	devwstat,
762*74a4d8c2SCharles.Forsyth };
763