1*74a4d8c2SCharles.Forsyth #include "u.h"
2*74a4d8c2SCharles.Forsyth #include "../port/lib.h"
3*74a4d8c2SCharles.Forsyth #include "mem.h"
4*74a4d8c2SCharles.Forsyth #include "dat.h"
5*74a4d8c2SCharles.Forsyth #include "fns.h"
6*74a4d8c2SCharles.Forsyth #include "io.h"
7*74a4d8c2SCharles.Forsyth #include "../port/error.h"
8*74a4d8c2SCharles.Forsyth
9*74a4d8c2SCharles.Forsyth #define DPRINT if(0)print
10*74a4d8c2SCharles.Forsyth #define THREEBUT 0 /* !=0, enable 3-button emulation (see below) */
11*74a4d8c2SCharles.Forsyth
12*74a4d8c2SCharles.Forsyth /*
13*74a4d8c2SCharles.Forsyth * DynaPro touch panel and Maxim MAX192 A/D converter on
14*74a4d8c2SCharles.Forsyth * York Electronics Centre's BRD/98/024 (Version A) interface,
15*74a4d8c2SCharles.Forsyth * accessed via mpc8xx SPI interface (see spi.c).
16*74a4d8c2SCharles.Forsyth *
17*74a4d8c2SCharles.Forsyth * The highest level of the driver is derived from the ARM/UCB touch panel driver,
18*74a4d8c2SCharles.Forsyth * simplified because of the differences between the panels.
19*74a4d8c2SCharles.Forsyth */
20*74a4d8c2SCharles.Forsyth
21*74a4d8c2SCharles.Forsyth /*
22*74a4d8c2SCharles.Forsyth * Values determined by interface board
23*74a4d8c2SCharles.Forsyth */
24*74a4d8c2SCharles.Forsyth enum {
25*74a4d8c2SCharles.Forsyth /* MAX192 control words */
26*74a4d8c2SCharles.Forsyth MeasureX = (1<<7)|(0<<6)|(1<<3)|(1<<2)|3, /* start, channel 0, unipolar, single-ended, external clock */
27*74a4d8c2SCharles.Forsyth MeasureY = (1<<7)|(1<<6)|(1<<3)|(1<<2)|3, /* start, channel 1, unipolar, single-ended, external clock */
28*74a4d8c2SCharles.Forsyth
29*74a4d8c2SCharles.Forsyth /* port B bits */
30*74a4d8c2SCharles.Forsyth ADselect = IBIT(16), /* chip select to MAX192, active low */
31*74a4d8c2SCharles.Forsyth
32*74a4d8c2SCharles.Forsyth /* port C bits */
33*74a4d8c2SCharles.Forsyth Xenable = 1<<2, /* PC13: TOUCH_XEN, active low */
34*74a4d8c2SCharles.Forsyth Yenable = 1<<3, /* PC12: TOUCH_YEN, active low */
35*74a4d8c2SCharles.Forsyth Touched = 1<<10, /* PC5: contact detect, active low */
36*74a4d8c2SCharles.Forsyth
37*74a4d8c2SCharles.Forsyth /* interrupt control via port C */
38*74a4d8c2SCharles.Forsyth TouchIRQ= 2, /* parallel i/o - PC5 */
39*74a4d8c2SCharles.Forsyth TouchEnable= 1<<TouchIRQ, /* mask for cimr */
40*74a4d8c2SCharles.Forsyth
41*74a4d8c2SCharles.Forsyth /* other parameters */
42*74a4d8c2SCharles.Forsyth Nconverge = 10, /* maximum iterations for convergence */
43*74a4d8c2SCharles.Forsyth MaxDelta = 2, /* acceptable change in X/Y between iterations */
44*74a4d8c2SCharles.Forsyth };
45*74a4d8c2SCharles.Forsyth
46*74a4d8c2SCharles.Forsyth /*
47*74a4d8c2SCharles.Forsyth * ADC interface via SPI (see MAX192 data sheet)
48*74a4d8c2SCharles.Forsyth * select the ADC
49*74a4d8c2SCharles.Forsyth * send 8-bit control word and two zero bytes to clock the conversion
50*74a4d8c2SCharles.Forsyth * receive three data bytes
51*74a4d8c2SCharles.Forsyth * deselect the ADC and return the result
52*74a4d8c2SCharles.Forsyth */
53*74a4d8c2SCharles.Forsyth static int
getcoord(int cw)54*74a4d8c2SCharles.Forsyth getcoord(int cw)
55*74a4d8c2SCharles.Forsyth {
56*74a4d8c2SCharles.Forsyth uchar tbuf[3], rbuf[3];
57*74a4d8c2SCharles.Forsyth IMM *io;
58*74a4d8c2SCharles.Forsyth int nr;
59*74a4d8c2SCharles.Forsyth
60*74a4d8c2SCharles.Forsyth tbuf[0] = cw;
61*74a4d8c2SCharles.Forsyth tbuf[1] = 0;
62*74a4d8c2SCharles.Forsyth tbuf[2] = 0;
63*74a4d8c2SCharles.Forsyth io = ioplock();
64*74a4d8c2SCharles.Forsyth io->pbdat &= ~ADselect;
65*74a4d8c2SCharles.Forsyth iopunlock();
66*74a4d8c2SCharles.Forsyth nr = spioutin(tbuf, sizeof(tbuf), rbuf);
67*74a4d8c2SCharles.Forsyth io = ioplock();
68*74a4d8c2SCharles.Forsyth io->pbdat |= ADselect;
69*74a4d8c2SCharles.Forsyth iopunlock();
70*74a4d8c2SCharles.Forsyth if(nr != 3)
71*74a4d8c2SCharles.Forsyth return -1;
72*74a4d8c2SCharles.Forsyth return ((rbuf[1]<<8)|rbuf[2])>>5;
73*74a4d8c2SCharles.Forsyth }
74*74a4d8c2SCharles.Forsyth
75*74a4d8c2SCharles.Forsyth /*
76*74a4d8c2SCharles.Forsyth * keep reading the a/d until the value stabilises
77*74a4d8c2SCharles.Forsyth */
78*74a4d8c2SCharles.Forsyth static int
dejitter(int enable,int cw)79*74a4d8c2SCharles.Forsyth dejitter(int enable, int cw)
80*74a4d8c2SCharles.Forsyth {
81*74a4d8c2SCharles.Forsyth int i, diff, prev, v;
82*74a4d8c2SCharles.Forsyth IMM *io;
83*74a4d8c2SCharles.Forsyth
84*74a4d8c2SCharles.Forsyth io = ioplock();
85*74a4d8c2SCharles.Forsyth io->pcdat &= ~enable; /* active low */
86*74a4d8c2SCharles.Forsyth iopunlock();
87*74a4d8c2SCharles.Forsyth
88*74a4d8c2SCharles.Forsyth i = 0;
89*74a4d8c2SCharles.Forsyth v = getcoord(cw);
90*74a4d8c2SCharles.Forsyth do{
91*74a4d8c2SCharles.Forsyth prev = v;
92*74a4d8c2SCharles.Forsyth v = getcoord(cw);
93*74a4d8c2SCharles.Forsyth diff = v - prev;
94*74a4d8c2SCharles.Forsyth if(diff < 0)
95*74a4d8c2SCharles.Forsyth diff = -diff;
96*74a4d8c2SCharles.Forsyth }while(diff >= MaxDelta && ++i <= Nconverge);
97*74a4d8c2SCharles.Forsyth
98*74a4d8c2SCharles.Forsyth io = ioplock();
99*74a4d8c2SCharles.Forsyth io->pcdat |= enable;
100*74a4d8c2SCharles.Forsyth iopunlock();
101*74a4d8c2SCharles.Forsyth return v;
102*74a4d8c2SCharles.Forsyth }
103*74a4d8c2SCharles.Forsyth
104*74a4d8c2SCharles.Forsyth static void
adcreset(void)105*74a4d8c2SCharles.Forsyth adcreset(void)
106*74a4d8c2SCharles.Forsyth {
107*74a4d8c2SCharles.Forsyth IMM *io;
108*74a4d8c2SCharles.Forsyth
109*74a4d8c2SCharles.Forsyth /* select port pins */
110*74a4d8c2SCharles.Forsyth io = ioplock();
111*74a4d8c2SCharles.Forsyth io->pcdir &= ~(Xenable|Yenable); /* ensure set to input before changing state */
112*74a4d8c2SCharles.Forsyth io->pcpar &= ~(Xenable|Yenable);
113*74a4d8c2SCharles.Forsyth io->pcdat |= Xenable|Yenable;
114*74a4d8c2SCharles.Forsyth io->pcdir |= Xenable; /* change enable bits to output one at a time to avoid both being low at once (could damage panel) */
115*74a4d8c2SCharles.Forsyth io->pcdat |= Xenable; /* ensure it's high after making it an output */
116*74a4d8c2SCharles.Forsyth io->pcdir |= Yenable;
117*74a4d8c2SCharles.Forsyth io->pcdat |= Yenable; /* ensure it's high after making it an output */
118*74a4d8c2SCharles.Forsyth io->pcso &= ~(Xenable|Yenable);
119*74a4d8c2SCharles.Forsyth io->pbdat |= ADselect;
120*74a4d8c2SCharles.Forsyth io->pbpar &= ~ADselect;
121*74a4d8c2SCharles.Forsyth io->pbdir |= ADselect;
122*74a4d8c2SCharles.Forsyth iopunlock();
123*74a4d8c2SCharles.Forsyth }
124*74a4d8c2SCharles.Forsyth
125*74a4d8c2SCharles.Forsyth /*
126*74a4d8c2SCharles.Forsyth * high-level touch panel interface
127*74a4d8c2SCharles.Forsyth */
128*74a4d8c2SCharles.Forsyth
129*74a4d8c2SCharles.Forsyth /* to and from fixed point */
130*74a4d8c2SCharles.Forsyth #define FX(n) ((n)<<16)
131*74a4d8c2SCharles.Forsyth #define XF(v) ((v)>>16)
132*74a4d8c2SCharles.Forsyth
133*74a4d8c2SCharles.Forsyth typedef struct Touch Touch;
134*74a4d8c2SCharles.Forsyth
135*74a4d8c2SCharles.Forsyth struct Touch {
136*74a4d8c2SCharles.Forsyth Lock;
137*74a4d8c2SCharles.Forsyth Rendez r;
138*74a4d8c2SCharles.Forsyth int m[2][3]; /* transformation matrix */
139*74a4d8c2SCharles.Forsyth int rate;
140*74a4d8c2SCharles.Forsyth int down;
141*74a4d8c2SCharles.Forsyth int raw_count;
142*74a4d8c2SCharles.Forsyth int valid_count;
143*74a4d8c2SCharles.Forsyth int wake_time;
144*74a4d8c2SCharles.Forsyth int sleep_time;
145*74a4d8c2SCharles.Forsyth };
146*74a4d8c2SCharles.Forsyth
147*74a4d8c2SCharles.Forsyth static Touch touch = {
148*74a4d8c2SCharles.Forsyth {0},
149*74a4d8c2SCharles.Forsyth .r {0},
150*74a4d8c2SCharles.Forsyth .m {{FX(1), 0, 0},{0, FX(1), 0}}, /* default is 1:1 */
151*74a4d8c2SCharles.Forsyth .rate 20, /* milliseconds */
152*74a4d8c2SCharles.Forsyth };
153*74a4d8c2SCharles.Forsyth
154*74a4d8c2SCharles.Forsyth /*
155*74a4d8c2SCharles.Forsyth * panel-touched state and interrupt
156*74a4d8c2SCharles.Forsyth */
157*74a4d8c2SCharles.Forsyth
158*74a4d8c2SCharles.Forsyth static int
touching(void)159*74a4d8c2SCharles.Forsyth touching(void)
160*74a4d8c2SCharles.Forsyth {
161*74a4d8c2SCharles.Forsyth eieio();
162*74a4d8c2SCharles.Forsyth return (m->iomem->pcdat & Touched) == 0;
163*74a4d8c2SCharles.Forsyth }
164*74a4d8c2SCharles.Forsyth
165*74a4d8c2SCharles.Forsyth static int
ispendown(void *)166*74a4d8c2SCharles.Forsyth ispendown(void*)
167*74a4d8c2SCharles.Forsyth {
168*74a4d8c2SCharles.Forsyth return touch.down || touching();
169*74a4d8c2SCharles.Forsyth }
170*74a4d8c2SCharles.Forsyth
171*74a4d8c2SCharles.Forsyth static void
touchintr(Ureg *,void *)172*74a4d8c2SCharles.Forsyth touchintr(Ureg*, void*)
173*74a4d8c2SCharles.Forsyth {
174*74a4d8c2SCharles.Forsyth if((m->iomem->pcdat & Touched) == 0){
175*74a4d8c2SCharles.Forsyth m->iomem->cimr &= ~TouchEnable; /* mask interrupts when reading pen */
176*74a4d8c2SCharles.Forsyth touch.down = 1;
177*74a4d8c2SCharles.Forsyth wakeup(&touch.r);
178*74a4d8c2SCharles.Forsyth }
179*74a4d8c2SCharles.Forsyth }
180*74a4d8c2SCharles.Forsyth
181*74a4d8c2SCharles.Forsyth static void
touchenable(void)182*74a4d8c2SCharles.Forsyth touchenable(void)
183*74a4d8c2SCharles.Forsyth {
184*74a4d8c2SCharles.Forsyth IMM *io;
185*74a4d8c2SCharles.Forsyth
186*74a4d8c2SCharles.Forsyth io = ioplock();
187*74a4d8c2SCharles.Forsyth io->cimr |= TouchEnable;
188*74a4d8c2SCharles.Forsyth iopunlock();
189*74a4d8c2SCharles.Forsyth }
190*74a4d8c2SCharles.Forsyth
191*74a4d8c2SCharles.Forsyth /*
192*74a4d8c2SCharles.Forsyth * touchctl commands:
193*74a4d8c2SCharles.Forsyth * X a b c - set X transformation
194*74a4d8c2SCharles.Forsyth * Y d e f - set Y transformation
195*74a4d8c2SCharles.Forsyth * s<delay> - set sample delay in millisec per sample
196*74a4d8c2SCharles.Forsyth * r<delay> - set read delay in microsec
197*74a4d8c2SCharles.Forsyth * R<l2nr> - set log2 of number of readings to average
198*74a4d8c2SCharles.Forsyth */
199*74a4d8c2SCharles.Forsyth
200*74a4d8c2SCharles.Forsyth enum{
201*74a4d8c2SCharles.Forsyth Qdir,
202*74a4d8c2SCharles.Forsyth Qtouchctl,
203*74a4d8c2SCharles.Forsyth Qtouchstat,
204*74a4d8c2SCharles.Forsyth Qtouch,
205*74a4d8c2SCharles.Forsyth };
206*74a4d8c2SCharles.Forsyth
207*74a4d8c2SCharles.Forsyth Dirtab touchdir[]={
208*74a4d8c2SCharles.Forsyth ".", {Qdir, 0, QTDIR}, 0, 0555,
209*74a4d8c2SCharles.Forsyth "touchctl", {Qtouchctl, 0}, 0, 0666,
210*74a4d8c2SCharles.Forsyth "touchstat", {Qtouchstat, 0}, 0, 0444,
211*74a4d8c2SCharles.Forsyth "touch", {Qtouch, 0}, 0, 0444,
212*74a4d8c2SCharles.Forsyth };
213*74a4d8c2SCharles.Forsyth
214*74a4d8c2SCharles.Forsyth static int
ptmap(int * m,int x,int y)215*74a4d8c2SCharles.Forsyth ptmap(int *m, int x, int y)
216*74a4d8c2SCharles.Forsyth {
217*74a4d8c2SCharles.Forsyth return XF(m[0]*x + m[1]*y + m[2]);
218*74a4d8c2SCharles.Forsyth }
219*74a4d8c2SCharles.Forsyth
220*74a4d8c2SCharles.Forsyth /*
221*74a4d8c2SCharles.Forsyth * read a point from the touch panel;
222*74a4d8c2SCharles.Forsyth * returns true iff the point is valid, otherwise x, y aren't changed
223*74a4d8c2SCharles.Forsyth */
224*74a4d8c2SCharles.Forsyth static int
touchreadxy(int * fx,int * fy)225*74a4d8c2SCharles.Forsyth touchreadxy(int *fx, int *fy)
226*74a4d8c2SCharles.Forsyth {
227*74a4d8c2SCharles.Forsyth int rx, ry;
228*74a4d8c2SCharles.Forsyth
229*74a4d8c2SCharles.Forsyth if(touching()){
230*74a4d8c2SCharles.Forsyth rx = dejitter(Xenable, MeasureX);
231*74a4d8c2SCharles.Forsyth ry = dejitter(Yenable, MeasureY);
232*74a4d8c2SCharles.Forsyth microdelay(40);
233*74a4d8c2SCharles.Forsyth if(rx >=0 && ry >= 0){
234*74a4d8c2SCharles.Forsyth if(0)
235*74a4d8c2SCharles.Forsyth print("touch %d %d\n", rx, ry);
236*74a4d8c2SCharles.Forsyth *fx = ptmap(touch.m[0], rx, ry);
237*74a4d8c2SCharles.Forsyth *fy = ptmap(touch.m[1], rx, ry);
238*74a4d8c2SCharles.Forsyth touch.raw_count++;
239*74a4d8c2SCharles.Forsyth return 1;
240*74a4d8c2SCharles.Forsyth }
241*74a4d8c2SCharles.Forsyth }
242*74a4d8c2SCharles.Forsyth return 0;
243*74a4d8c2SCharles.Forsyth }
244*74a4d8c2SCharles.Forsyth
245*74a4d8c2SCharles.Forsyth #define timer_start() 0 /* could use TBL if necessary */
246*74a4d8c2SCharles.Forsyth #define tmr2us(n) 0
247*74a4d8c2SCharles.Forsyth
248*74a4d8c2SCharles.Forsyth static void
touchproc(void *)249*74a4d8c2SCharles.Forsyth touchproc(void*)
250*74a4d8c2SCharles.Forsyth {
251*74a4d8c2SCharles.Forsyth int b, i, x, y;
252*74a4d8c2SCharles.Forsyth ulong t1, t2;
253*74a4d8c2SCharles.Forsyth
254*74a4d8c2SCharles.Forsyth t1 = timer_start();
255*74a4d8c2SCharles.Forsyth b = 1;
256*74a4d8c2SCharles.Forsyth for(;;) {
257*74a4d8c2SCharles.Forsyth //setpri(PriHi);
258*74a4d8c2SCharles.Forsyth do{
259*74a4d8c2SCharles.Forsyth touch.down = 0;
260*74a4d8c2SCharles.Forsyth touch.wake_time += (t2 = timer_start())-t1;
261*74a4d8c2SCharles.Forsyth touchenable();
262*74a4d8c2SCharles.Forsyth sleep(&touch.r, ispendown, nil);
263*74a4d8c2SCharles.Forsyth touch.sleep_time += (t1 = timer_start())-t2;
264*74a4d8c2SCharles.Forsyth }while(!touchreadxy(&x, &y));
265*74a4d8c2SCharles.Forsyth
266*74a4d8c2SCharles.Forsyth /* 640x480-specific 3-button emulation hack: */
267*74a4d8c2SCharles.Forsyth if(THREEBUT){
268*74a4d8c2SCharles.Forsyth if(y > 481) {
269*74a4d8c2SCharles.Forsyth b = ((639-x) >> 7);
270*74a4d8c2SCharles.Forsyth continue;
271*74a4d8c2SCharles.Forsyth } else if(y < -2) {
272*74a4d8c2SCharles.Forsyth b = (x >> 7)+3;
273*74a4d8c2SCharles.Forsyth continue;
274*74a4d8c2SCharles.Forsyth }
275*74a4d8c2SCharles.Forsyth }
276*74a4d8c2SCharles.Forsyth
277*74a4d8c2SCharles.Forsyth DPRINT("#%d %d", x, y);
278*74a4d8c2SCharles.Forsyth mousetrack(b, x, y, 0);
279*74a4d8c2SCharles.Forsyth setpri(PriNormal);
280*74a4d8c2SCharles.Forsyth while(touching()) {
281*74a4d8c2SCharles.Forsyth for(i=0; i<3; i++)
282*74a4d8c2SCharles.Forsyth if(touchreadxy(&x, &y)) {
283*74a4d8c2SCharles.Forsyth DPRINT("*%d %d", x, y);
284*74a4d8c2SCharles.Forsyth mousetrack(b, x, y, 0);
285*74a4d8c2SCharles.Forsyth break;
286*74a4d8c2SCharles.Forsyth }
287*74a4d8c2SCharles.Forsyth touch.wake_time += (t2 = timer_start())-t1;
288*74a4d8c2SCharles.Forsyth tsleep(&touch.r, return0, nil, touch.rate);
289*74a4d8c2SCharles.Forsyth touch.sleep_time += (t1 = timer_start())-t2;
290*74a4d8c2SCharles.Forsyth }
291*74a4d8c2SCharles.Forsyth mousetrack(0, x, y, 0);
292*74a4d8c2SCharles.Forsyth b = 1; /* go back to just button one for next press */
293*74a4d8c2SCharles.Forsyth }
294*74a4d8c2SCharles.Forsyth }
295*74a4d8c2SCharles.Forsyth
296*74a4d8c2SCharles.Forsyth static void
touchreset(void)297*74a4d8c2SCharles.Forsyth touchreset(void)
298*74a4d8c2SCharles.Forsyth {
299*74a4d8c2SCharles.Forsyth IMM *io;
300*74a4d8c2SCharles.Forsyth
301*74a4d8c2SCharles.Forsyth spireset();
302*74a4d8c2SCharles.Forsyth adcreset();
303*74a4d8c2SCharles.Forsyth intrenable(VectorCPIC+TouchIRQ, touchintr, &touch, BUSUNKNOWN, "touch");
304*74a4d8c2SCharles.Forsyth
305*74a4d8c2SCharles.Forsyth /* set i/o pin to interrupt when panel touched */
306*74a4d8c2SCharles.Forsyth io = ioplock();
307*74a4d8c2SCharles.Forsyth io->pcdat &= ~Touched;
308*74a4d8c2SCharles.Forsyth io->pcpar &= ~Touched;
309*74a4d8c2SCharles.Forsyth io->pcdir &= ~Touched;
310*74a4d8c2SCharles.Forsyth io->pcso &= ~Touched;
311*74a4d8c2SCharles.Forsyth io->pcint |= Touched; /* high-to-low trigger */
312*74a4d8c2SCharles.Forsyth io->cimr &= ~TouchEnable; /* touchproc will enable when ready */
313*74a4d8c2SCharles.Forsyth iopunlock();
314*74a4d8c2SCharles.Forsyth }
315*74a4d8c2SCharles.Forsyth
316*74a4d8c2SCharles.Forsyth static void
touchinit(void)317*74a4d8c2SCharles.Forsyth touchinit(void)
318*74a4d8c2SCharles.Forsyth {
319*74a4d8c2SCharles.Forsyth static int done;
320*74a4d8c2SCharles.Forsyth
321*74a4d8c2SCharles.Forsyth if(!done){
322*74a4d8c2SCharles.Forsyth done = 1;
323*74a4d8c2SCharles.Forsyth kproc( "touchscreen", touchproc, nil, 0);
324*74a4d8c2SCharles.Forsyth }
325*74a4d8c2SCharles.Forsyth }
326*74a4d8c2SCharles.Forsyth
327*74a4d8c2SCharles.Forsyth static Chan*
touchattach(char * spec)328*74a4d8c2SCharles.Forsyth touchattach(char* spec)
329*74a4d8c2SCharles.Forsyth {
330*74a4d8c2SCharles.Forsyth return devattach('T', spec);
331*74a4d8c2SCharles.Forsyth }
332*74a4d8c2SCharles.Forsyth
333*74a4d8c2SCharles.Forsyth static Walkqid*
touchwalk(Chan * c,Chan * nc,char ** name,int nname)334*74a4d8c2SCharles.Forsyth touchwalk(Chan* c, Chan *nc, char **name, int nname)
335*74a4d8c2SCharles.Forsyth {
336*74a4d8c2SCharles.Forsyth return devwalk(c, nc, name, nname, touchdir, nelem(touchdir), devgen);
337*74a4d8c2SCharles.Forsyth }
338*74a4d8c2SCharles.Forsyth
339*74a4d8c2SCharles.Forsyth static int
touchstat(Chan * c,uchar * dp,int n)340*74a4d8c2SCharles.Forsyth touchstat(Chan* c, uchar* dp, int n)
341*74a4d8c2SCharles.Forsyth {
342*74a4d8c2SCharles.Forsyth return devstat(c, dp, n, touchdir, nelem(touchdir), devgen);
343*74a4d8c2SCharles.Forsyth }
344*74a4d8c2SCharles.Forsyth
345*74a4d8c2SCharles.Forsyth static Chan*
touchopen(Chan * c,int omode)346*74a4d8c2SCharles.Forsyth touchopen(Chan* c, int omode)
347*74a4d8c2SCharles.Forsyth {
348*74a4d8c2SCharles.Forsyth omode = openmode(omode);
349*74a4d8c2SCharles.Forsyth switch((ulong)c->qid.path){
350*74a4d8c2SCharles.Forsyth case Qtouchctl:
351*74a4d8c2SCharles.Forsyth case Qtouchstat:
352*74a4d8c2SCharles.Forsyth if(!iseve())
353*74a4d8c2SCharles.Forsyth error(Eperm);
354*74a4d8c2SCharles.Forsyth break;
355*74a4d8c2SCharles.Forsyth }
356*74a4d8c2SCharles.Forsyth return devopen(c, omode, touchdir, nelem(touchdir), devgen);
357*74a4d8c2SCharles.Forsyth }
358*74a4d8c2SCharles.Forsyth
359*74a4d8c2SCharles.Forsyth static void
touchclose(Chan *)360*74a4d8c2SCharles.Forsyth touchclose(Chan*)
361*74a4d8c2SCharles.Forsyth {
362*74a4d8c2SCharles.Forsyth }
363*74a4d8c2SCharles.Forsyth
364*74a4d8c2SCharles.Forsyth static long
touchread(Chan * c,void * buf,long n,vlong offset)365*74a4d8c2SCharles.Forsyth touchread(Chan* c, void* buf, long n, vlong offset)
366*74a4d8c2SCharles.Forsyth {
367*74a4d8c2SCharles.Forsyth char *tmp;
368*74a4d8c2SCharles.Forsyth int x, y;
369*74a4d8c2SCharles.Forsyth
370*74a4d8c2SCharles.Forsyth if(c->qid.type & QTDIR)
371*74a4d8c2SCharles.Forsyth return devdirread(c, buf, n, touchdir, nelem(touchdir), devgen);
372*74a4d8c2SCharles.Forsyth
373*74a4d8c2SCharles.Forsyth tmp = malloc(READSTR);
374*74a4d8c2SCharles.Forsyth if(waserror()){
375*74a4d8c2SCharles.Forsyth free(tmp);
376*74a4d8c2SCharles.Forsyth nexterror();
377*74a4d8c2SCharles.Forsyth }
378*74a4d8c2SCharles.Forsyth switch((ulong)c->qid.path){
379*74a4d8c2SCharles.Forsyth case Qtouch:
380*74a4d8c2SCharles.Forsyth if(!touchreadxy(&x, &y))
381*74a4d8c2SCharles.Forsyth x = y = -1;
382*74a4d8c2SCharles.Forsyth snprint(tmp, READSTR, "%d %d", x, y);
383*74a4d8c2SCharles.Forsyth break;
384*74a4d8c2SCharles.Forsyth case Qtouchctl:
385*74a4d8c2SCharles.Forsyth snprint(tmp, READSTR, "s%d\nr%d\nR%d\nX %d %d %d\nY %d %d %d\n",
386*74a4d8c2SCharles.Forsyth touch.rate, 0, 1,
387*74a4d8c2SCharles.Forsyth touch.m[0][0], touch.m[0][1], touch.m[0][2],
388*74a4d8c2SCharles.Forsyth touch.m[1][0], touch.m[1][1], touch.m[1][2]);
389*74a4d8c2SCharles.Forsyth break;
390*74a4d8c2SCharles.Forsyth case Qtouchstat:
391*74a4d8c2SCharles.Forsyth snprint(tmp, READSTR, "%d %d\n%d %d\n",
392*74a4d8c2SCharles.Forsyth touch.raw_count, touch.valid_count, tmr2us(touch.sleep_time), tmr2us(touch.wake_time));
393*74a4d8c2SCharles.Forsyth touch.raw_count = 0;
394*74a4d8c2SCharles.Forsyth touch.valid_count = 0;
395*74a4d8c2SCharles.Forsyth touch.sleep_time = 0;
396*74a4d8c2SCharles.Forsyth touch.wake_time = 0;
397*74a4d8c2SCharles.Forsyth break;
398*74a4d8c2SCharles.Forsyth default:
399*74a4d8c2SCharles.Forsyth error(Ebadarg);
400*74a4d8c2SCharles.Forsyth return 0;
401*74a4d8c2SCharles.Forsyth }
402*74a4d8c2SCharles.Forsyth n = readstr(offset, buf, n, tmp);
403*74a4d8c2SCharles.Forsyth poperror();
404*74a4d8c2SCharles.Forsyth free(tmp);
405*74a4d8c2SCharles.Forsyth return n;
406*74a4d8c2SCharles.Forsyth }
407*74a4d8c2SCharles.Forsyth
408*74a4d8c2SCharles.Forsyth static void
dotouchwrite(Chan * c,char * buf)409*74a4d8c2SCharles.Forsyth dotouchwrite(Chan *c, char *buf)
410*74a4d8c2SCharles.Forsyth {
411*74a4d8c2SCharles.Forsyth char *field[8];
412*74a4d8c2SCharles.Forsyth int nf, cmd, pn, m[3], n;
413*74a4d8c2SCharles.Forsyth
414*74a4d8c2SCharles.Forsyth nf = getfields(buf, field, nelem(field), 1, " \t\n");
415*74a4d8c2SCharles.Forsyth if(nf <= 0)
416*74a4d8c2SCharles.Forsyth return;
417*74a4d8c2SCharles.Forsyth switch((ulong)c->qid.path){
418*74a4d8c2SCharles.Forsyth case Qtouchctl:
419*74a4d8c2SCharles.Forsyth cmd = *(field[0])++;
420*74a4d8c2SCharles.Forsyth pn = *field[0] == 0;
421*74a4d8c2SCharles.Forsyth switch(cmd) {
422*74a4d8c2SCharles.Forsyth case 's':
423*74a4d8c2SCharles.Forsyth n = strtol(field[pn], 0, 0);
424*74a4d8c2SCharles.Forsyth if(n <= 0)
425*74a4d8c2SCharles.Forsyth error(Ebadarg);
426*74a4d8c2SCharles.Forsyth touch.rate = n;
427*74a4d8c2SCharles.Forsyth break;
428*74a4d8c2SCharles.Forsyth case 'r':
429*74a4d8c2SCharles.Forsyth /* touch read delay */
430*74a4d8c2SCharles.Forsyth break;
431*74a4d8c2SCharles.Forsyth case 'X':
432*74a4d8c2SCharles.Forsyth case 'Y':
433*74a4d8c2SCharles.Forsyth if(nf < pn+2)
434*74a4d8c2SCharles.Forsyth error(Ebadarg);
435*74a4d8c2SCharles.Forsyth m[0] = strtol(field[pn], 0, 0);
436*74a4d8c2SCharles.Forsyth m[1] = strtol(field[pn+1], 0, 0);
437*74a4d8c2SCharles.Forsyth m[2] = strtol(field[pn+2], 0, 0);
438*74a4d8c2SCharles.Forsyth memmove(touch.m[cmd=='Y'], m, sizeof(touch.m[0]));
439*74a4d8c2SCharles.Forsyth break;
440*74a4d8c2SCharles.Forsyth case 'c':
441*74a4d8c2SCharles.Forsyth case 'C':
442*74a4d8c2SCharles.Forsyth case 'v':
443*74a4d8c2SCharles.Forsyth case 't':
444*74a4d8c2SCharles.Forsyth case 'e':
445*74a4d8c2SCharles.Forsyth /* not used */
446*74a4d8c2SCharles.Forsyth /* break; */
447*74a4d8c2SCharles.Forsyth default:
448*74a4d8c2SCharles.Forsyth error(Ebadarg);
449*74a4d8c2SCharles.Forsyth }
450*74a4d8c2SCharles.Forsyth break;
451*74a4d8c2SCharles.Forsyth default:
452*74a4d8c2SCharles.Forsyth error(Ebadarg);
453*74a4d8c2SCharles.Forsyth return;
454*74a4d8c2SCharles.Forsyth }
455*74a4d8c2SCharles.Forsyth }
456*74a4d8c2SCharles.Forsyth
457*74a4d8c2SCharles.Forsyth static long
touchwrite(Chan * c,void * vp,long n,vlong)458*74a4d8c2SCharles.Forsyth touchwrite(Chan* c, void* vp, long n, vlong)
459*74a4d8c2SCharles.Forsyth {
460*74a4d8c2SCharles.Forsyth char buf[64];
461*74a4d8c2SCharles.Forsyth char *cp, *a;
462*74a4d8c2SCharles.Forsyth int n0 = n;
463*74a4d8c2SCharles.Forsyth int bn;
464*74a4d8c2SCharles.Forsyth
465*74a4d8c2SCharles.Forsyth a = vp;
466*74a4d8c2SCharles.Forsyth while(n) {
467*74a4d8c2SCharles.Forsyth bn = (cp = memchr(a, '\n', n))!=nil ? cp-a+1 : n;
468*74a4d8c2SCharles.Forsyth n -= bn;
469*74a4d8c2SCharles.Forsyth bn = bn > sizeof(buf)-1 ? sizeof(buf)-1 : bn;
470*74a4d8c2SCharles.Forsyth memmove(buf, a, bn);
471*74a4d8c2SCharles.Forsyth buf[bn] = '\0';
472*74a4d8c2SCharles.Forsyth a = cp;
473*74a4d8c2SCharles.Forsyth dotouchwrite(c, buf);
474*74a4d8c2SCharles.Forsyth }
475*74a4d8c2SCharles.Forsyth return n0-n;
476*74a4d8c2SCharles.Forsyth }
477*74a4d8c2SCharles.Forsyth
478*74a4d8c2SCharles.Forsyth Dev touchdevtab = {
479*74a4d8c2SCharles.Forsyth 'T',
480*74a4d8c2SCharles.Forsyth "touch",
481*74a4d8c2SCharles.Forsyth
482*74a4d8c2SCharles.Forsyth touchreset,
483*74a4d8c2SCharles.Forsyth touchinit,
484*74a4d8c2SCharles.Forsyth devshutdown,
485*74a4d8c2SCharles.Forsyth touchattach,
486*74a4d8c2SCharles.Forsyth touchwalk,
487*74a4d8c2SCharles.Forsyth touchstat,
488*74a4d8c2SCharles.Forsyth touchopen,
489*74a4d8c2SCharles.Forsyth devcreate,
490*74a4d8c2SCharles.Forsyth touchclose,
491*74a4d8c2SCharles.Forsyth touchread,
492*74a4d8c2SCharles.Forsyth devbread,
493*74a4d8c2SCharles.Forsyth touchwrite,
494*74a4d8c2SCharles.Forsyth devbwrite,
495*74a4d8c2SCharles.Forsyth devremove,
496*74a4d8c2SCharles.Forsyth devwstat,
497*74a4d8c2SCharles.Forsyth };
498