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