vrpiu.c revision 1.1
1/*	$NetBSD: vrpiu.c,v 1.1 1999/12/28 03:15:18 takemura Exp $	*/
2
3/*
4 * Copyright (c) 1999 Shin Takemura All rights reserved.
5 * Copyright (c) 1999 PocketBSD Project. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 */
29
30#include <sys/param.h>
31#include <sys/systm.h>
32#include <sys/device.h>
33#include <sys/kernel.h>
34
35#include <dev/wscons/wsconsio.h>
36#include <dev/wscons/wsmousevar.h>
37
38#include <machine/bus.h>
39
40#include <hpcmips/vr/vripvar.h>
41#include <hpcmips/vr/cmureg.h>
42#include <hpcmips/vr/vrpiuvar.h>
43#include <hpcmips/vr/vrpiureg.h>
44
45/*
46 * contant and macro definitions
47 */
48#define VRPIUDEBUG
49#ifdef VRPIUDEBUG
50int	vrpiu_debug = 0;
51#define	DPRINTF(arg) if (vrpiu_debug) printf arg;
52#else
53#define	DPRINTF(arg)
54#endif
55
56#define SCALE	(1024*1024)
57
58/*
59 * data types
60 */
61/* struct vrpiu_softc is defined in vrpiuvar.h */
62
63/*
64 * function prototypes
65 */
66static int	vrpiumatch __P((struct device *, struct cfdata *, void *));
67static void	vrpiuattach __P((struct device *, struct device *, void *));
68
69static void	vrpiu_write __P((struct vrpiu_softc *, int, unsigned short));
70static u_short	vrpiu_read __P((struct vrpiu_softc *, int));
71
72static int	vrpiu_intr __P((void *));
73static void	vrpiu_reset_param __P((struct vrpiu_softc *sc));
74static void	vrpiu_timeout __P((void *));
75#ifdef DEBUG
76static void	vrpiu_dump_cntreg __P((unsigned int cmd));
77#endif
78
79static int	vrpiu_enable __P((void *));
80static int	vrpiu_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
81static void	vrpiu_disable __P((void *));
82
83/* mra is defined in mra.c */
84int mra_Y_AX1_BX2_C __P((int *y, int ys, int *x1, int x1s, int *x2, int x2s,
85			 int n, int scale, int *a, int *b, int *c));
86
87/*
88 * static or global variables
89 */
90struct cfattach vrpiu_ca = {
91	sizeof(struct vrpiu_softc), vrpiumatch, vrpiuattach
92};
93
94const struct wsmouse_accessops vrpiu_accessops = {
95	vrpiu_enable,
96	vrpiu_ioctl,
97	vrpiu_disable,
98};
99
100/*
101 * function definitions
102 */
103static inline void
104vrpiu_write(sc, port, val)
105	struct vrpiu_softc *sc;
106	int port;
107	unsigned short val;
108{
109	bus_space_write_2(sc->sc_iot, sc->sc_ioh, port, val);
110}
111
112static inline u_short
113vrpiu_read(sc, port)
114	struct vrpiu_softc *sc;
115	int port;
116{
117	return bus_space_read_2(sc->sc_iot, sc->sc_ioh, port);
118}
119
120static int
121vrpiumatch(parent, cf, aux)
122	struct device *parent;
123	struct cfdata *cf;
124	void *aux;
125{
126	return 1;
127}
128
129static void
130vrpiuattach(parent, self, aux)
131	struct device *parent;
132	struct device *self;
133	void *aux;
134{
135	struct vrpiu_softc *sc = (struct vrpiu_softc *)self;
136	struct vrip_attach_args *va = aux;
137	struct wsmousedev_attach_args wsmaa;
138
139	bus_space_tag_t iot = va->va_iot;
140	bus_space_handle_t ioh;
141
142	if (bus_space_map(iot, va->va_addr, 1, 0, &ioh)) {
143		printf(": can't map bus space\n");
144		return;
145	}
146
147	sc->sc_iot = iot;
148	sc->sc_ioh = ioh;
149	sc->sc_vrip = va->va_vc;
150
151	/*
152	 * disable device until vrpiu_enable called
153	 */
154	sc->sc_stat = VRPIU_STAT_DISABLE;
155
156	vrpiu_reset_param(sc);
157#if 1
158	/*
159	 * XXX, calibrate parameters
160	 */
161	{
162		static struct sample {
163			int xraw, yraw, x, y;
164		} D[] = {
165			/* samples got on my MC-R500 */
166			{ 502, 486, 320, 120 },
167			{  55, 109,   0,   0 },
168			{  54, 913,   0, 239 },
169			{ 973, 924, 639, 239 },
170			{ 975, 123, 639,   0 },
171		};
172		int s = sizeof(*D);
173		int n = sizeof(D)/s;
174
175		sc->sc_prmxs = 640;
176		sc->sc_prmys = 240;
177
178		if (mra_Y_AX1_BX2_C(&D->x, s, &D->xraw, s, &D->yraw, s, n,
179				    SCALE, &sc->sc_prmax, &sc->sc_prmbx,
180				    &sc->sc_prmcx) ||
181		    mra_Y_AX1_BX2_C(&D->y, s, &D->xraw, s, &D->yraw, s, n,
182				    SCALE, &sc->sc_prmay,
183				    &sc->sc_prmby, &sc->sc_prmcy)) {
184			printf(": MRA error");
185			vrpiu_reset_param(sc);
186		} else {
187			DPRINTF(("Ax=%d Bx=%d Cx=%d\n",
188				 sc->sc_prmax, sc->sc_prmbx, sc->sc_prmcx));
189			DPRINTF(("Ay=%d By=%d Cy=%d\n",
190				 sc->sc_prmay, sc->sc_prmby, sc->sc_prmcy));
191		}
192	}
193#endif
194
195	/* install interrupt handler and enable interrupt */
196	if (!(sc->sc_handler =
197	      vrip_intr_establish(va->va_vc, va->va_intr, IPL_TTY,
198				  vrpiu_intr, sc))) {
199		printf (": can't map interrupt line.\n");
200		return;
201	}
202
203	/* mask level2 interrupt, stop scan sequencer and mask clock to piu */
204	vrpiu_disable(sc);
205
206	printf("\n");
207
208	wsmaa.accessops = &vrpiu_accessops;
209	wsmaa.accesscookie = sc;
210
211	/*
212	 * attach the wsmouse
213	 */
214	sc->sc_wsmousedev = config_found(self, &wsmaa, wsmousedevprint);
215}
216
217int
218vrpiu_enable(v)
219	void *v;
220{
221	struct vrpiu_softc *sc = v;
222	int s;
223	unsigned int cnt;
224
225	DPRINTF(("%s(%d): vrpiu_enable()\n", __FILE__, __LINE__));
226	if (sc->sc_stat != VRPIU_STAT_DISABLE)
227		return EBUSY;
228
229	/* supply clock to PIU */
230	__vrcmu_supply(CMUMSKPIU, 1);
231
232	/* Scan interval 0x7FF is maximum value */
233	vrpiu_write(sc, PIUSIVL_REG_W, 0x7FF);
234
235	s = spltty();
236
237	/* clear interrupt status */
238	vrpiu_write(sc, PIUINT_REG_W, PIUINT_ALLINTR);
239
240	/* Disable -> Standby */
241	cnt = PIUCNT_PIUPWR |
242		PIUCNT_PIUMODE_COORDINATE |
243		PIUCNT_PADATSTART | PIUCNT_PADATSTOP;
244	vrpiu_write(sc, PIUCNT_REG_W, cnt);
245
246	/* save pen status, touch or release */
247	cnt = vrpiu_read(sc, PIUCNT_REG_W);
248
249	/* Level2 interrupt register setting */
250	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, PIUINT_ALLINTR, 1);
251
252	/*
253	 * Enable scan sequencer operation
254	 * Standby -> WaitPenTouch
255	 */
256	cnt |= PIUCNT_PIUSEQEN;
257	vrpiu_write(sc, PIUCNT_REG_W, cnt);
258
259	/* transit status DISABLE -> TOUCH or RELEASE */
260	sc->sc_stat = (cnt & PIUCNT_PENSTC) ?
261		VRPIU_STAT_TOUCH : VRPIU_STAT_RELEASE;
262
263	sc->sc_timeout = 1;
264
265	splx(s);
266
267	return 0;
268}
269
270void
271vrpiu_disable(v)
272	void *v;
273{
274	struct vrpiu_softc *sc = v;
275	int s;
276
277	DPRINTF(("%s(%d): vrpiu_disable()\n", __FILE__, __LINE__));
278
279	/* Set level2 interrupt register to mask interrupts */
280	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, PIUINT_ALLINTR, 0);
281
282	sc->sc_stat = VRPIU_STAT_DISABLE;
283
284	/* Disable scan sequencer operation and power off */
285	vrpiu_write(sc, PIUCNT_REG_W, 0);
286
287	/* mask clock to PIU */
288	__vrcmu_supply(CMUMSKPIU, 1);
289
290	s = spltty();
291	if (!sc->sc_timeout) {
292		untimeout(vrpiu_timeout, sc);
293	}
294	splx(s);
295}
296
297int
298vrpiu_ioctl(v, cmd, data, flag, p)
299	void *v;
300	u_long cmd;
301	caddr_t data;
302	int flag;
303	struct proc *p;
304{
305	struct vrpiu_softc *sc = v;
306
307	DPRINTF(("%s(%d): vrpiu_ioctl(%08lx)\n", __FILE__, __LINE__, cmd));
308
309	switch (cmd) {
310	case WSMOUSEIO_GTYPE:
311		*(u_int *)data = WSMOUSE_TYPE_PS2;
312		break;
313
314	case WSMOUSEIO_SRES:
315		printf("%s(%d): WSMOUSRIO_SRES is not supported",
316		       __FILE__, __LINE__);
317		break;
318
319	default:
320		return (-1);
321	}
322	return (0);
323}
324
325/*
326 * PIU interrupt handler.
327 */
328int
329vrpiu_intr(arg)
330	void *arg;
331{
332        struct vrpiu_softc *sc = arg;
333	unsigned int cnt, i;
334	unsigned int intrstat, page;
335	int tpx0, tpx1, tpy0, tpy1;
336	int x, y, xraw, yraw;
337
338	intrstat = vrpiu_read(sc, PIUINT_REG_W);
339
340	if (sc->sc_stat == VRPIU_STAT_DISABLE) {
341		/*
342		 * the device isn't enabled. just clear interrupt.
343		 */
344		vrpiu_write(sc, PIUINT_REG_W, intrstat);
345		return (0);
346	}
347
348	page = (intrstat & PIUINT_OVP) ? 1 : 0;
349	if (intrstat & (PIUINT_PADPAGE0INTR | PIUINT_PADPAGE1INTR)) {
350		tpx0 = vrpiu_read(sc, PIUPB(page, 0));
351		tpx1 = vrpiu_read(sc, PIUPB(page, 1));
352		tpy0 = vrpiu_read(sc, PIUPB(page, 2));
353		tpy1 = vrpiu_read(sc, PIUPB(page, 3));
354	}
355
356	if (intrstat & PIUINT_PADDLOSTINTR) {
357		page = page ? 0 : 1;
358		for (i = 0; i < 4; i++)
359			vrpiu_read(sc, PIUPB(page, i));
360	}
361
362	cnt = vrpiu_read(sc, PIUCNT_REG_W);
363#ifdef DEBUG
364	if (vrpiu_debug)
365		vrpiu_dump_cntreg(cnt);
366#endif
367
368	/* clear interrupt status */
369	vrpiu_write(sc, PIUINT_REG_W, intrstat);
370
371#if 0
372	DPRINTF(("vrpiu_intr: OVP=%d", page));
373	if (intrstat & PIUINT_PADCMDINTR)
374		DPRINTF((" CMD"));
375	if (intrstat & PIUINT_PADADPINTR)
376		DPRINTF((" A/D"));
377	if (intrstat & PIUINT_PADPAGE1INTR)
378		DPRINTF((" PAGE1"));
379	if (intrstat & PIUINT_PADPAGE0INTR)
380		DPRINTF((" PAGE0"));
381	if (intrstat & PIUINT_PADDLOSTINTR)
382		DPRINTF((" DLOST"));
383	if (intrstat & PIUINT_PENCHGINTR)
384		DPRINTF((" PENCHG"));
385	DPRINTF(("\n"));
386#endif
387	if (cnt & PIUCNT_PENSTC) {
388		if (sc->sc_stat == VRPIU_STAT_RELEASE) {
389			/*
390			 * pen touch
391			 */
392			DPRINTF(("PEN TOUCH\n"));
393			sc->sc_stat = VRPIU_STAT_TOUCH;
394			if (sc->sc_timeout) {
395				sc->sc_timeout = 0;
396				sc->sc_releasecount = 0;
397				timeout(vrpiu_timeout, sc, hz/3);
398			}
399		}
400	} else {
401		if (sc->sc_stat == VRPIU_STAT_TOUCH ||
402		    sc->sc_stat == VRPIU_STAT_DRAG) {
403			/*
404			 * pen release
405			 */
406			DPRINTF(("RELEASE\n"));
407			sc->sc_stat = VRPIU_STAT_RELEASE;
408			if (!sc->sc_timeout) {
409				if (++sc->sc_releasecount == 2) {
410					untimeout(vrpiu_timeout, sc);
411					sc->sc_timeout = 1;
412					DPRINTF(("TAP!\n"));
413					/* button 0 DOWN */
414					wsmouse_input(sc->sc_wsmousedev,
415						      (1 << 0),
416						      0, 0, 0);
417					/* button 0 UP */
418					wsmouse_input(sc->sc_wsmousedev,
419						      0, 0, 0, 0);
420				}
421			}
422		}
423	}
424
425	if (intrstat & (PIUINT_PADPAGE0INTR | PIUINT_PADPAGE1INTR)) {
426		if (!((tpx0 & PIUPB_VALID) && (tpx1 & PIUPB_VALID) &&
427		      (tpy0 & PIUPB_VALID) && (tpy1 & PIUPB_VALID))) {
428			printf("vrpiu: internal error, data is not valid!\n");
429		} else {
430			tpx0 &= PIUPB_PADDATA_MASK;
431			tpx1 &= PIUPB_PADDATA_MASK;
432			tpy0 &= PIUPB_PADDATA_MASK;
433			tpy1 &= PIUPB_PADDATA_MASK;
434#define ISVALID(n, c, m)	((c) - (m) < (n) && (n) < (c) + (m))
435			if (ISVALID(tpx0 + tpx1, 1024, 200) &&
436			    ISVALID(tpx0 + tpx1, 1024, 200)) {
437#if 0
438				DPRINTF(("%04x %04x %04x %04x\n",
439					 tpx0, tpx1, tpy0, tpy1));
440				DPRINTF(("%3d %3d (%4d %4d)->", tpx0, tpy0,
441					 tpx0 + tpx1, tpy0 + tpy1);
442#endif
443				xraw = tpy1 * 1024 / (tpy0 + tpy1);
444				yraw = tpx1 * 1024 / (tpx0 + tpx1);
445				DPRINTF(("%3d %3d", xraw, yraw));
446
447				x = (sc->sc_prmax*xraw + sc->sc_prmbx*yraw) /
448					SCALE + sc->sc_prmcx;
449				y = (sc->sc_prmay*xraw + sc->sc_prmby*yraw) /
450					SCALE + sc->sc_prmcy;
451				if (x < 0) x = 0;
452				if (y < 0) y = 0;
453				if (sc->sc_prmxs <= x)
454					x = sc->sc_prmxs - 1;
455				if (sc->sc_prmys <= y)
456					y = sc->sc_prmys - 1;
457				DPRINTF(("->%4d %4d", x, y));
458				if (sc->sc_stat == VRPIU_STAT_TOUCH) {
459					sc->sc_stat = VRPIU_STAT_DRAG;
460					sc->sc_x = x;
461					sc->sc_y = y;
462				} else
463				if (sc->sc_stat == VRPIU_STAT_DRAG) {
464					DPRINTF((" delta %d %d",
465						 x - sc->sc_x, y - sc->sc_y));
466					wsmouse_input(sc->sc_wsmousedev,
467						      0, /* all buttons up */
468						      x - sc->sc_x, /* dx */
469						      y - sc->sc_y, /* dy */
470						      0); /* dz */
471					sc->sc_x = x;
472					sc->sc_y = y;
473				}
474				DPRINTF(("\n"));
475			}
476		}
477	}
478
479	if (intrstat & PIUINT_PADDLOSTINTR) {
480		cnt |= PIUCNT_PIUSEQEN;
481		vrpiu_write(sc, PIUCNT_REG_W, cnt);
482	}
483
484	return 0;
485}
486
487void
488vrpiu_reset_param(sc)
489        struct vrpiu_softc *sc;
490{
491	sc->sc_prmax = SCALE;
492	sc->sc_prmbx = 0;
493	sc->sc_prmcx = 0;
494	sc->sc_prmxs = PIUPB_PADDATA_MAX;
495	sc->sc_prmay = 0;
496	sc->sc_prmby = SCALE;
497	sc->sc_prmcy = 0;
498	sc->sc_prmys = PIUPB_PADDATA_MAX;
499}
500
501void
502vrpiu_timeout(arg)
503	void *arg;
504{
505        struct vrpiu_softc *sc = arg;
506	sc->sc_timeout = 1;
507}
508
509#ifdef DEBUG
510void
511vrpiu_dump_cntreg(cnt)
512	unsigned int cnt;
513{
514	printf("%s", (cnt & PIUCNT_PENSTC) ? "Touch" : "Release");
515	printf(" state=");
516	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_CmdScan)
517		printf("CmdScan");
518	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_IntervalNextScan)
519		printf("IntervalNextScan");
520	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_PenDataScan)
521		printf("PenDataScan");
522	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_WaitPenTouch)
523		printf("WaitPenTouch");
524	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_RFU)
525		printf("???");
526	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_ADPortScan)
527		printf("ADPortScan");
528	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_Standby)
529		printf("Standby");
530	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_Disable)
531		printf("Disable");
532	if (cnt & PIUCNT_PADATSTOP)
533		printf(" AutoStop");
534	if (cnt & PIUCNT_PADATSTART)
535		printf(" AutoStart");
536	if (cnt & PIUCNT_PADSCANSTOP)
537		printf(" Stop");
538	if (cnt & PIUCNT_PADSCANSTART)
539		printf(" Start");
540	if (cnt & PIUCNT_PADSCANTYPE)
541		printf(" ScanPressure");
542	if ((cnt & PIUCNT_PIUMODE_MASK) == PIUCNT_PIUMODE_ADCONVERTER)
543		printf(" A/D");
544	if ((cnt & PIUCNT_PIUMODE_MASK) == PIUCNT_PIUMODE_COORDINATE)
545		printf(" Coordinate");
546	if (cnt & PIUCNT_PIUSEQEN)
547		printf(" SeqEn");
548	if ((cnt & PIUCNT_PIUPWR) == 0)
549		printf(" PowerOff");
550	if ((cnt & PIUCNT_PADRST) == 0)
551		printf(" Reset");
552	printf("\n");
553}
554#endif
555