vrpiu.c revision 1.5
1/*	$NetBSD: vrpiu.c,v 1.5 2000/06/13 05:59:55 matt 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#include <machine/platid.h>
40#include <machine/platid_mask.h>
41
42#include <hpcmips/dev/tpcalibvar.h>
43#include <hpcmips/vr/vripvar.h>
44#include <hpcmips/vr/cmureg.h>
45#include <hpcmips/vr/vrpiuvar.h>
46#include <hpcmips/vr/vrpiureg.h>
47
48/*
49 * contant and macro definitions
50 */
51#define VRPIUDEBUG
52#ifdef VRPIUDEBUG
53int	vrpiu_debug = 0;
54#define	DPRINTF(arg) if (vrpiu_debug) printf arg;
55#else
56#define	DPRINTF(arg)
57#endif
58
59/*
60 * data types
61 */
62/* struct vrpiu_softc is defined in vrpiuvar.h */
63
64/*
65 * function prototypes
66 */
67static int	vrpiumatch __P((struct device *, struct cfdata *, void *));
68static void	vrpiuattach __P((struct device *, struct device *, void *));
69
70static void	vrpiu_write __P((struct vrpiu_softc *, int, unsigned short));
71static u_short	vrpiu_read __P((struct vrpiu_softc *, int));
72
73static int	vrpiu_intr __P((void *));
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	tpcalib_init(&sc->sc_tpcalib);
156#if 1
157	/*
158	 * XXX, calibrate parameters
159	 */
160	{
161		int i;
162		static const struct {
163			platid_mask_t *mask;
164			struct wsmouse_calibcoords coords;
165		} calibrations[] = {
166			{ &platid_mask_MACH_NEC_MCR_700A,
167				{ 0, 0, 799, 599,
168				  4,
169				{ { 115,  80,   0,   0 },
170				  { 115, 966,   0, 599 },
171				  { 912,  80, 799,   0 },
172				  { 912, 966, 799, 599 } } } },
173
174			{ NULL,		/* samples got on my MC-R500 */
175				{ 0, 0, 639, 239,
176				5,
177				{ { 502, 486, 320, 120 },
178				  {  55, 109,   0,   0 },
179				  {  54, 913,   0, 239 },
180				  { 973, 924, 639, 239 },
181				  { 975, 123, 639,   0 } } } },
182		};
183		for (i = 0; ; i++) {
184			if (calibrations[i].mask == NULL
185			    || platid_match(&platid, calibrations[i].mask))
186				break;
187		}
188		tpcalib_ioctl(&sc->sc_tpcalib, WSMOUSEIO_SCALIBCOORDS,
189			      (caddr_t)&calibrations[i].coords, 0, 0);
190	}
191#endif
192
193	/* install interrupt handler and enable interrupt */
194	if (!(sc->sc_handler =
195	      vrip_intr_establish(va->va_vc, va->va_intr, IPL_TTY,
196				  vrpiu_intr, sc))) {
197		printf (": can't map interrupt line.\n");
198		return;
199	}
200
201	/* mask level2 interrupt, stop scan sequencer and mask clock to piu */
202	vrpiu_disable(sc);
203
204	printf("\n");
205
206	wsmaa.accessops = &vrpiu_accessops;
207	wsmaa.accesscookie = sc;
208
209	/*
210	 * attach the wsmouse
211	 */
212	sc->sc_wsmousedev = config_found(self, &wsmaa, wsmousedevprint);
213}
214
215int
216vrpiu_enable(v)
217	void *v;
218{
219	struct vrpiu_softc *sc = v;
220	int s;
221	unsigned int cnt;
222
223	DPRINTF(("%s(%d): vrpiu_enable()\n", __FILE__, __LINE__));
224	if (sc->sc_stat != VRPIU_STAT_DISABLE)
225		return EBUSY;
226
227	/* supply clock to PIU */
228	__vrcmu_supply(CMUMSKPIU, 1);
229
230	/* Scan interval 0x7FF is maximum value */
231	vrpiu_write(sc, PIUSIVL_REG_W, 0x7FF);
232
233	s = spltty();
234
235	/* clear interrupt status */
236	vrpiu_write(sc, PIUINT_REG_W, PIUINT_ALLINTR);
237
238	/* Disable -> Standby */
239	cnt = PIUCNT_PIUPWR |
240		PIUCNT_PIUMODE_COORDINATE |
241		PIUCNT_PADATSTART | PIUCNT_PADATSTOP;
242	vrpiu_write(sc, PIUCNT_REG_W, cnt);
243
244	/* save pen status, touch or release */
245	cnt = vrpiu_read(sc, PIUCNT_REG_W);
246
247	/* Level2 interrupt register setting */
248	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, PIUINT_ALLINTR, 1);
249
250	/*
251	 * Enable scan sequencer operation
252	 * Standby -> WaitPenTouch
253	 */
254	cnt |= PIUCNT_PIUSEQEN;
255	vrpiu_write(sc, PIUCNT_REG_W, cnt);
256
257	/* transit status DISABLE -> TOUCH or RELEASE */
258	sc->sc_stat = (cnt & PIUCNT_PENSTC) ?
259		VRPIU_STAT_TOUCH : VRPIU_STAT_RELEASE;
260
261	splx(s);
262
263	return 0;
264}
265
266void
267vrpiu_disable(v)
268	void *v;
269{
270	struct vrpiu_softc *sc = v;
271
272	DPRINTF(("%s(%d): vrpiu_disable()\n", __FILE__, __LINE__));
273
274	/* Set level2 interrupt register to mask interrupts */
275	vrip_intr_setmask2(sc->sc_vrip, sc->sc_handler, PIUINT_ALLINTR, 0);
276
277	sc->sc_stat = VRPIU_STAT_DISABLE;
278
279	/* Disable scan sequencer operation and power off */
280	vrpiu_write(sc, PIUCNT_REG_W, 0);
281
282	/* mask clock to PIU */
283	__vrcmu_supply(CMUMSKPIU, 1);
284}
285
286int
287vrpiu_ioctl(v, cmd, data, flag, p)
288	void *v;
289	u_long cmd;
290	caddr_t data;
291	int flag;
292	struct proc *p;
293{
294	struct vrpiu_softc *sc = v;
295
296	DPRINTF(("%s(%d): vrpiu_ioctl(%08lx)\n", __FILE__, __LINE__, cmd));
297
298	switch (cmd) {
299	case WSMOUSEIO_GTYPE:
300		*(u_int *)data = WSMOUSE_TYPE_TPANEL;
301		break;
302
303	case WSMOUSEIO_SRES:
304		printf("%s(%d): WSMOUSRIO_SRES is not supported",
305		       __FILE__, __LINE__);
306		break;
307
308	case WSMOUSEIO_SCALIBCOORDS:
309	case WSMOUSEIO_GCALIBCOORDS:
310                return tpcalib_ioctl(&sc->sc_tpcalib, cmd, data, flag, p);
311
312	default:
313		return (-1);
314	}
315	return (0);
316}
317
318/*
319 * PIU interrupt handler.
320 */
321int
322vrpiu_intr(arg)
323	void *arg;
324{
325        struct vrpiu_softc *sc = arg;
326	unsigned int cnt, i;
327	unsigned int intrstat, page;
328	int tpx0, tpx1, tpy0, tpy1;
329	int x, y, xraw, yraw;
330
331	intrstat = vrpiu_read(sc, PIUINT_REG_W);
332
333	if (sc->sc_stat == VRPIU_STAT_DISABLE) {
334		/*
335		 * the device isn't enabled. just clear interrupt.
336		 */
337		vrpiu_write(sc, PIUINT_REG_W, intrstat);
338		return (0);
339	}
340
341	page = (intrstat & PIUINT_OVP) ? 1 : 0;
342	if (intrstat & (PIUINT_PADPAGE0INTR | PIUINT_PADPAGE1INTR)) {
343		tpx0 = vrpiu_read(sc, PIUPB(page, 0));
344		tpx1 = vrpiu_read(sc, PIUPB(page, 1));
345		tpy0 = vrpiu_read(sc, PIUPB(page, 2));
346		tpy1 = vrpiu_read(sc, PIUPB(page, 3));
347	}
348
349	if (intrstat & PIUINT_PADDLOSTINTR) {
350		page = page ? 0 : 1;
351		for (i = 0; i < 4; i++)
352			vrpiu_read(sc, PIUPB(page, i));
353	}
354
355	cnt = vrpiu_read(sc, PIUCNT_REG_W);
356#ifdef DEBUG
357	if (vrpiu_debug)
358		vrpiu_dump_cntreg(cnt);
359#endif
360
361	/* clear interrupt status */
362	vrpiu_write(sc, PIUINT_REG_W, intrstat);
363
364#if 0
365	DPRINTF(("vrpiu_intr: OVP=%d", page));
366	if (intrstat & PIUINT_PADCMDINTR)
367		DPRINTF((" CMD"));
368	if (intrstat & PIUINT_PADADPINTR)
369		DPRINTF((" A/D"));
370	if (intrstat & PIUINT_PADPAGE1INTR)
371		DPRINTF((" PAGE1"));
372	if (intrstat & PIUINT_PADPAGE0INTR)
373		DPRINTF((" PAGE0"));
374	if (intrstat & PIUINT_PADDLOSTINTR)
375		DPRINTF((" DLOST"));
376	if (intrstat & PIUINT_PENCHGINTR)
377		DPRINTF((" PENCHG"));
378	DPRINTF(("\n"));
379#endif
380	if (intrstat & (PIUINT_PADPAGE0INTR | PIUINT_PADPAGE1INTR)) {
381		if (!((tpx0 & PIUPB_VALID) && (tpx1 & PIUPB_VALID) &&
382		      (tpy0 & PIUPB_VALID) && (tpy1 & PIUPB_VALID))) {
383			printf("vrpiu: internal error, data is not valid!\n");
384		} else {
385			tpx0 &= PIUPB_PADDATA_MASK;
386			tpx1 &= PIUPB_PADDATA_MASK;
387			tpy0 &= PIUPB_PADDATA_MASK;
388			tpy1 &= PIUPB_PADDATA_MASK;
389#define ISVALID(n, c, m)	((c) - (m) < (n) && (n) < (c) + (m))
390			if (ISVALID(tpx0 + tpx1, 1024, 200) &&
391			    ISVALID(tpx0 + tpx1, 1024, 200)) {
392#if 0
393				DPRINTF(("%04x %04x %04x %04x\n",
394					 tpx0, tpx1, tpy0, tpy1));
395				DPRINTF(("%3d %3d (%4d %4d)->", tpx0, tpy0,
396					 tpx0 + tpx1, tpy0 + tpy1));
397#endif
398				xraw = tpy1 * 1024 / (tpy0 + tpy1);
399				yraw = tpx1 * 1024 / (tpx0 + tpx1);
400				DPRINTF(("%3d %3d", xraw, yraw));
401
402				tpcalib_trans(&sc->sc_tpcalib,
403					      xraw, yraw, &x, &y);
404
405				DPRINTF(("->%4d %4d", x, y));
406				wsmouse_input(sc->sc_wsmousedev,
407					      (cnt & PIUCNT_PENSTC) ? 1 : 0,
408					      x, /* x */
409					      y, /* y */
410					      0, /* z */
411					      WSMOUSE_INPUT_ABSOLUTE_X |
412					      WSMOUSE_INPUT_ABSOLUTE_Y);
413				DPRINTF(("\n"));
414			}
415		}
416	}
417
418	if (cnt & PIUCNT_PENSTC) {
419		if (sc->sc_stat == VRPIU_STAT_RELEASE) {
420			/*
421			 * pen touch
422			 */
423			DPRINTF(("PEN TOUCH\n"));
424			sc->sc_stat = VRPIU_STAT_TOUCH;
425			/*
426			 * We should not report button down event while
427			 * we don't know where it occur.
428			 */
429		}
430	} else {
431		if (sc->sc_stat == VRPIU_STAT_TOUCH) {
432			/*
433			 * pen release
434			 */
435			DPRINTF(("RELEASE\n"));
436			sc->sc_stat = VRPIU_STAT_RELEASE;
437			/* button 0 UP */
438			wsmouse_input(sc->sc_wsmousedev,
439				      0,
440				      0, 0, 0, 0);
441		}
442	}
443
444	if (intrstat & PIUINT_PADDLOSTINTR) {
445		cnt |= PIUCNT_PIUSEQEN;
446		vrpiu_write(sc, PIUCNT_REG_W, cnt);
447	}
448
449	return 0;
450}
451
452#ifdef DEBUG
453void
454vrpiu_dump_cntreg(cnt)
455	unsigned int cnt;
456{
457	printf("%s", (cnt & PIUCNT_PENSTC) ? "Touch" : "Release");
458	printf(" state=");
459	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_CmdScan)
460		printf("CmdScan");
461	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_IntervalNextScan)
462		printf("IntervalNextScan");
463	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_PenDataScan)
464		printf("PenDataScan");
465	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_WaitPenTouch)
466		printf("WaitPenTouch");
467	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_RFU)
468		printf("???");
469	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_ADPortScan)
470		printf("ADPortScan");
471	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_Standby)
472		printf("Standby");
473	if ((cnt & PIUCNT_PADSTATE_MASK) == PIUCNT_PADSTATE_Disable)
474		printf("Disable");
475	if (cnt & PIUCNT_PADATSTOP)
476		printf(" AutoStop");
477	if (cnt & PIUCNT_PADATSTART)
478		printf(" AutoStart");
479	if (cnt & PIUCNT_PADSCANSTOP)
480		printf(" Stop");
481	if (cnt & PIUCNT_PADSCANSTART)
482		printf(" Start");
483	if (cnt & PIUCNT_PADSCANTYPE)
484		printf(" ScanPressure");
485	if ((cnt & PIUCNT_PIUMODE_MASK) == PIUCNT_PIUMODE_ADCONVERTER)
486		printf(" A/D");
487	if ((cnt & PIUCNT_PIUMODE_MASK) == PIUCNT_PIUMODE_COORDINATE)
488		printf(" Coordinate");
489	if (cnt & PIUCNT_PIUSEQEN)
490		printf(" SeqEn");
491	if ((cnt & PIUCNT_PIUPWR) == 0)
492		printf(" PowerOff");
493	if ((cnt & PIUCNT_PADRST) == 0)
494		printf(" Reset");
495	printf("\n");
496}
497#endif
498