vrpiu.c revision 1.2
1/*	$NetBSD: vrpiu.c,v 1.2 2000/01/08 02:57:24 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));
74#ifdef DEBUG
75static void	vrpiu_dump_cntreg __P((unsigned int cmd));
76#endif
77
78static int	vrpiu_enable __P((void *));
79static int	vrpiu_ioctl __P((void *, u_long, caddr_t, int, struct proc *));
80static void	vrpiu_disable __P((void *));
81
82/* mra is defined in mra.c */
83int mra_Y_AX1_BX2_C __P((int *y, int ys, int *x1, int x1s, int *x2, int x2s,
84			 int n, int scale, int *a, int *b, int *c));
85
86/*
87 * static or global variables
88 */
89struct cfattach vrpiu_ca = {
90	sizeof(struct vrpiu_softc), vrpiumatch, vrpiuattach
91};
92
93const struct wsmouse_accessops vrpiu_accessops = {
94	vrpiu_enable,
95	vrpiu_ioctl,
96	vrpiu_disable,
97};
98
99/*
100 * function definitions
101 */
102static inline void
103vrpiu_write(sc, port, val)
104	struct vrpiu_softc *sc;
105	int port;
106	unsigned short val;
107{
108	bus_space_write_2(sc->sc_iot, sc->sc_ioh, port, val);
109}
110
111static inline u_short
112vrpiu_read(sc, port)
113	struct vrpiu_softc *sc;
114	int port;
115{
116	return bus_space_read_2(sc->sc_iot, sc->sc_ioh, port);
117}
118
119static int
120vrpiumatch(parent, cf, aux)
121	struct device *parent;
122	struct cfdata *cf;
123	void *aux;
124{
125	return 1;
126}
127
128static void
129vrpiuattach(parent, self, aux)
130	struct device *parent;
131	struct device *self;
132	void *aux;
133{
134	struct vrpiu_softc *sc = (struct vrpiu_softc *)self;
135	struct vrip_attach_args *va = aux;
136	struct wsmousedev_attach_args wsmaa;
137
138	bus_space_tag_t iot = va->va_iot;
139	bus_space_handle_t ioh;
140
141	if (bus_space_map(iot, va->va_addr, 1, 0, &ioh)) {
142		printf(": can't map bus space\n");
143		return;
144	}
145
146	sc->sc_iot = iot;
147	sc->sc_ioh = ioh;
148	sc->sc_vrip = va->va_vc;
149
150	/*
151	 * disable device until vrpiu_enable called
152	 */
153	sc->sc_stat = VRPIU_STAT_DISABLE;
154
155	vrpiu_reset_param(sc);
156#if 1
157	/*
158	 * XXX, calibrate parameters
159	 */
160	{
161		static struct sample {
162			int xraw, yraw, x, y;
163		} D[] = {
164			/* samples got on my MC-R500 */
165			{ 502, 486, 320, 120 },
166			{  55, 109,   0,   0 },
167			{  54, 913,   0, 239 },
168			{ 973, 924, 639, 239 },
169			{ 975, 123, 639,   0 },
170		};
171		int s = sizeof(*D);
172		int n = sizeof(D)/s;
173
174		sc->sc_prmxs = 640;
175		sc->sc_prmys = 240;
176
177		if (mra_Y_AX1_BX2_C(&D->x, s, &D->xraw, s, &D->yraw, s, n,
178				    SCALE, &sc->sc_prmax, &sc->sc_prmbx,
179				    &sc->sc_prmcx) ||
180		    mra_Y_AX1_BX2_C(&D->y, s, &D->xraw, s, &D->yraw, s, n,
181				    SCALE, &sc->sc_prmay,
182				    &sc->sc_prmby, &sc->sc_prmcy)) {
183			printf(": MRA error");
184			vrpiu_reset_param(sc);
185		} else {
186			DPRINTF(("Ax=%d Bx=%d Cx=%d\n",
187				 sc->sc_prmax, sc->sc_prmbx, sc->sc_prmcx));
188			DPRINTF(("Ay=%d By=%d Cy=%d\n",
189				 sc->sc_prmay, sc->sc_prmby, sc->sc_prmcy));
190		}
191	}
192#endif
193
194	/* install interrupt handler and enable interrupt */
195	if (!(sc->sc_handler =
196	      vrip_intr_establish(va->va_vc, va->va_intr, IPL_TTY,
197				  vrpiu_intr, sc))) {
198		printf (": can't map interrupt line.\n");
199		return;
200	}
201
202	/* mask level2 interrupt, stop scan sequencer and mask clock to piu */
203	vrpiu_disable(sc);
204
205	printf("\n");
206
207	wsmaa.accessops = &vrpiu_accessops;
208	wsmaa.accesscookie = sc;
209
210	/*
211	 * attach the wsmouse
212	 */
213	sc->sc_wsmousedev = config_found(self, &wsmaa, wsmousedevprint);
214}
215
216int
217vrpiu_enable(v)
218	void *v;
219{
220	struct vrpiu_softc *sc = v;
221	int s;
222	unsigned int cnt;
223
224	DPRINTF(("%s(%d): vrpiu_enable()\n", __FILE__, __LINE__));
225	if (sc->sc_stat != VRPIU_STAT_DISABLE)
226		return EBUSY;
227
228	/* supply clock to PIU */
229	__vrcmu_supply(CMUMSKPIU, 1);
230
231	/* Scan interval 0x7FF is maximum value */
232	vrpiu_write(sc, PIUSIVL_REG_W, 0x7FF);
233
234	s = spltty();
235
236	/* clear interrupt status */
237	vrpiu_write(sc, PIUINT_REG_W, PIUINT_ALLINTR);
238
239	/* Disable -> Standby */
240	cnt = PIUCNT_PIUPWR |
241		PIUCNT_PIUMODE_COORDINATE |
242		PIUCNT_PADATSTART | PIUCNT_PADATSTOP;
243	vrpiu_write(sc, PIUCNT_REG_W, cnt);
244
245	/* save pen status, touch or release */
246	cnt = vrpiu_read(sc, PIUCNT_REG_W);
247
248	/* Level2 interrupt register setting */
249	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, PIUINT_ALLINTR, 1);
250
251	/*
252	 * Enable scan sequencer operation
253	 * Standby -> WaitPenTouch
254	 */
255	cnt |= PIUCNT_PIUSEQEN;
256	vrpiu_write(sc, PIUCNT_REG_W, cnt);
257
258	/* transit status DISABLE -> TOUCH or RELEASE */
259	sc->sc_stat = (cnt & PIUCNT_PENSTC) ?
260		VRPIU_STAT_TOUCH : VRPIU_STAT_RELEASE;
261
262	splx(s);
263
264	return 0;
265}
266
267void
268vrpiu_disable(v)
269	void *v;
270{
271	struct vrpiu_softc *sc = v;
272
273	DPRINTF(("%s(%d): vrpiu_disable()\n", __FILE__, __LINE__));
274
275	/* Set level2 interrupt register to mask interrupts */
276	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, PIUINT_ALLINTR, 0);
277
278	sc->sc_stat = VRPIU_STAT_DISABLE;
279
280	/* Disable scan sequencer operation and power off */
281	vrpiu_write(sc, PIUCNT_REG_W, 0);
282
283	/* mask clock to PIU */
284	__vrcmu_supply(CMUMSKPIU, 1);
285}
286
287int
288vrpiu_ioctl(v, cmd, data, flag, p)
289	void *v;
290	u_long cmd;
291	caddr_t data;
292	int flag;
293	struct proc *p;
294{
295	struct vrpiu_softc *sc = v;
296
297	DPRINTF(("%s(%d): vrpiu_ioctl(%08lx)\n", __FILE__, __LINE__, cmd));
298
299	switch (cmd) {
300	case WSMOUSEIO_GTYPE:
301		*(u_int *)data = WSMOUSE_TYPE_TPANEL;
302		break;
303
304	case WSMOUSEIO_SRES:
305		printf("%s(%d): WSMOUSRIO_SRES is not supported",
306		       __FILE__, __LINE__);
307		break;
308
309	default:
310		return (-1);
311	}
312	return (0);
313}
314
315/*
316 * PIU interrupt handler.
317 */
318int
319vrpiu_intr(arg)
320	void *arg;
321{
322        struct vrpiu_softc *sc = arg;
323	unsigned int cnt, i;
324	unsigned int intrstat, page;
325	int tpx0, tpx1, tpy0, tpy1;
326	int x, y, xraw, yraw;
327
328	intrstat = vrpiu_read(sc, PIUINT_REG_W);
329
330	if (sc->sc_stat == VRPIU_STAT_DISABLE) {
331		/*
332		 * the device isn't enabled. just clear interrupt.
333		 */
334		vrpiu_write(sc, PIUINT_REG_W, intrstat);
335		return (0);
336	}
337
338	page = (intrstat & PIUINT_OVP) ? 1 : 0;
339	if (intrstat & (PIUINT_PADPAGE0INTR | PIUINT_PADPAGE1INTR)) {
340		tpx0 = vrpiu_read(sc, PIUPB(page, 0));
341		tpx1 = vrpiu_read(sc, PIUPB(page, 1));
342		tpy0 = vrpiu_read(sc, PIUPB(page, 2));
343		tpy1 = vrpiu_read(sc, PIUPB(page, 3));
344	}
345
346	if (intrstat & PIUINT_PADDLOSTINTR) {
347		page = page ? 0 : 1;
348		for (i = 0; i < 4; i++)
349			vrpiu_read(sc, PIUPB(page, i));
350	}
351
352	cnt = vrpiu_read(sc, PIUCNT_REG_W);
353#ifdef DEBUG
354	if (vrpiu_debug)
355		vrpiu_dump_cntreg(cnt);
356#endif
357
358	/* clear interrupt status */
359	vrpiu_write(sc, PIUINT_REG_W, intrstat);
360
361#if 0
362	DPRINTF(("vrpiu_intr: OVP=%d", page));
363	if (intrstat & PIUINT_PADCMDINTR)
364		DPRINTF((" CMD"));
365	if (intrstat & PIUINT_PADADPINTR)
366		DPRINTF((" A/D"));
367	if (intrstat & PIUINT_PADPAGE1INTR)
368		DPRINTF((" PAGE1"));
369	if (intrstat & PIUINT_PADPAGE0INTR)
370		DPRINTF((" PAGE0"));
371	if (intrstat & PIUINT_PADDLOSTINTR)
372		DPRINTF((" DLOST"));
373	if (intrstat & PIUINT_PENCHGINTR)
374		DPRINTF((" PENCHG"));
375	DPRINTF(("\n"));
376#endif
377	if (cnt & PIUCNT_PENSTC) {
378		if (sc->sc_stat == VRPIU_STAT_RELEASE) {
379			/*
380			 * pen touch
381			 */
382			DPRINTF(("PEN TOUCH\n"));
383			sc->sc_stat = VRPIU_STAT_TOUCH;
384			/* button 0 DOWN */
385			wsmouse_input(sc->sc_wsmousedev,
386				      (1 << 0),
387				      0, 0, 0, 0);
388		}
389	} else {
390		if (sc->sc_stat == VRPIU_STAT_TOUCH) {
391			/*
392			 * pen release
393			 */
394			DPRINTF(("RELEASE\n"));
395			sc->sc_stat = VRPIU_STAT_RELEASE;
396			/* button 0 UP */
397			wsmouse_input(sc->sc_wsmousedev,
398				      0,
399				      0, 0, 0, 0);
400		}
401	}
402
403	if (intrstat & (PIUINT_PADPAGE0INTR | PIUINT_PADPAGE1INTR)) {
404		if (!((tpx0 & PIUPB_VALID) && (tpx1 & PIUPB_VALID) &&
405		      (tpy0 & PIUPB_VALID) && (tpy1 & PIUPB_VALID))) {
406			printf("vrpiu: internal error, data is not valid!\n");
407		} else {
408			tpx0 &= PIUPB_PADDATA_MASK;
409			tpx1 &= PIUPB_PADDATA_MASK;
410			tpy0 &= PIUPB_PADDATA_MASK;
411			tpy1 &= PIUPB_PADDATA_MASK;
412#define ISVALID(n, c, m)	((c) - (m) < (n) && (n) < (c) + (m))
413			if (ISVALID(tpx0 + tpx1, 1024, 200) &&
414			    ISVALID(tpx0 + tpx1, 1024, 200)) {
415#if 0
416				DPRINTF(("%04x %04x %04x %04x\n",
417					 tpx0, tpx1, tpy0, tpy1));
418				DPRINTF(("%3d %3d (%4d %4d)->", tpx0, tpy0,
419					 tpx0 + tpx1, tpy0 + tpy1);
420#endif
421				xraw = tpy1 * 1024 / (tpy0 + tpy1);
422				yraw = tpx1 * 1024 / (tpx0 + tpx1);
423				DPRINTF(("%3d %3d", xraw, yraw));
424
425				x = (sc->sc_prmax*xraw + sc->sc_prmbx*yraw) /
426					SCALE + sc->sc_prmcx;
427				y = (sc->sc_prmay*xraw + sc->sc_prmby*yraw) /
428					SCALE + sc->sc_prmcy;
429				if (x < 0) x = 0;
430				if (y < 0) y = 0;
431				if (sc->sc_prmxs <= x)
432					x = sc->sc_prmxs - 1;
433				if (sc->sc_prmys <= y)
434					y = sc->sc_prmys - 1;
435				DPRINTF(("->%4d %4d", x, y));
436				wsmouse_input(sc->sc_wsmousedev,
437					      (cnt & PIUCNT_PENSTC) ? 1 : 0,
438					      x, /* x */
439					      y, /* y */
440					      0, /* z */
441					      WSMOUSE_INPUT_ABSOLUTE_X |
442					      WSMOUSE_INPUT_ABSOLUTE_Y);
443				DPRINTF(("\n"));
444			}
445		}
446	}
447
448	if (intrstat & PIUINT_PADDLOSTINTR) {
449		cnt |= PIUCNT_PIUSEQEN;
450		vrpiu_write(sc, PIUCNT_REG_W, cnt);
451	}
452
453	return 0;
454}
455
456void
457vrpiu_reset_param(sc)
458        struct vrpiu_softc *sc;
459{
460	sc->sc_prmax = SCALE;
461	sc->sc_prmbx = 0;
462	sc->sc_prmcx = 0;
463	sc->sc_prmxs = PIUPB_PADDATA_MAX;
464	sc->sc_prmay = 0;
465	sc->sc_prmby = SCALE;
466	sc->sc_prmcy = 0;
467	sc->sc_prmys = PIUPB_PADDATA_MAX;
468}
469
470#ifdef DEBUG
471void
472vrpiu_dump_cntreg(cnt)
473	unsigned int cnt;
474{
475	printf("%s", (cnt & PIUCNT_PENSTC) ? "Touch" : "Release");
476	printf(" state=");
477	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_CmdScan)
478		printf("CmdScan");
479	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_IntervalNextScan)
480		printf("IntervalNextScan");
481	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_PenDataScan)
482		printf("PenDataScan");
483	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_WaitPenTouch)
484		printf("WaitPenTouch");
485	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_RFU)
486		printf("???");
487	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_ADPortScan)
488		printf("ADPortScan");
489	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_Standby)
490		printf("Standby");
491	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_Disable)
492		printf("Disable");
493	if (cnt & PIUCNT_PADATSTOP)
494		printf(" AutoStop");
495	if (cnt & PIUCNT_PADATSTART)
496		printf(" AutoStart");
497	if (cnt & PIUCNT_PADSCANSTOP)
498		printf(" Stop");
499	if (cnt & PIUCNT_PADSCANSTART)
500		printf(" Start");
501	if (cnt & PIUCNT_PADSCANTYPE)
502		printf(" ScanPressure");
503	if ((cnt & PIUCNT_PIUMODE_MASK) == PIUCNT_PIUMODE_ADCONVERTER)
504		printf(" A/D");
505	if ((cnt & PIUCNT_PIUMODE_MASK) == PIUCNT_PIUMODE_COORDINATE)
506		printf(" Coordinate");
507	if (cnt & PIUCNT_PIUSEQEN)
508		printf(" SeqEn");
509	if ((cnt & PIUCNT_PIUPWR) == 0)
510		printf(" PowerOff");
511	if ((cnt & PIUCNT_PADRST) == 0)
512		printf(" Reset");
513	printf("\n");
514}
515#endif
516