1/*	$NetBSD: ucbtp.c,v 1.24 2023/09/10 15:18:51 andvar Exp $ */
2
3/*-
4 * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by UCHIYAMA Yasushi.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 *    notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 *    notice, this list of conditions and the following disclaimer in the
17 *    documentation and/or other materials provided with the distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31
32/*
33 * Device driver for PHILIPS UCB1200 Advanced modem/audio analog front-end
34 *	Touch panel part.
35 */
36
37#include <sys/cdefs.h>
38__KERNEL_RCSID(0, "$NetBSD: ucbtp.c,v 1.24 2023/09/10 15:18:51 andvar Exp $");
39
40#include "opt_use_poll.h"
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/device.h>
45
46#include <machine/bus.h>
47#include <machine/intr.h>
48#include <machine/bootinfo.h> /* bootinfo */
49
50#include <dev/wscons/wsconsio.h>
51#include <dev/wscons/wsmousevar.h>
52
53#include <dev/hpc/hpctpanelvar.h>
54
55#include <hpcmips/tx/tx39var.h>
56#include <hpcmips/tx/tx39sibvar.h>
57#include <hpcmips/tx/tx39sibreg.h>
58#include <hpcmips/tx/tx39icureg.h>
59
60#include <hpcmips/dev/ucb1200var.h>
61#include <hpcmips/dev/ucb1200reg.h>
62
63#include <hpcmips/tx/txsnd.h>
64#include <dev/hpc/video_subr.h> /* debug */
65
66#ifdef UCBTPDEBUG
67#define DPRINTF_ENABLE
68#define DPRINTF_DEBUG	ucbtp_debug
69#endif
70#include <machine/debug.h>
71
72enum ucbts_stat {
73	UCBTS_STAT_DISABLE,
74	UCBTS_STAT_RELEASE,
75	UCBTS_STAT_TOUCH,
76	UCBTS_STAT_DRAG,
77};
78
79#define UCBTS_POSX	1
80#define UCBTS_POSY	2
81#define UCBTS_PRESS	3
82
83#define UCBTS_PRESS_THRESHOLD	80
84#define UCBTS_TAP_THRESHOLD	5
85
86enum ucbadc_state {
87/* 0 */	UCBADC_IDLE,
88/* 1 */	UCBADC_ADC_INIT,
89/* 2 */	UCBADC_ADC_FINI,
90/* 3 */	UCBADC_MEASUMENT_INIT,
91/* 4 */	UCBADC_MEASUMENT_FINI,
92/* 5 */	UCBADC_ADC_ENABLE,
93/* 6 */	UCBADC_ADC_START0,
94/* 7 */	UCBADC_ADC_START1,
95/* 8 */	UCBADC_ADC_DATAREAD,
96/* 9 */	UCBADC_ADC_DATAREAD_WAIT,
97/*10 */	UCBADC_ADC_DISABLE,
98/*11 */	UCBADC_ADC_INTRMODE,
99/*12 */	UCBADC_ADC_INPUT,
100/*13 */	UCBADC_INTR_ACK0,
101/*14 */	UCBADC_INTR_ACK1,
102/*15 */	UCBADC_INTR_ACK2,
103/*16 */	UCBADC_REGREAD,
104/*17 */	UCBADC_REGWRITE
105};
106
107struct ucbtp_softc {
108	device_t sc_dev;
109	device_t sc_sib; /* parent (TX39 SIB module) */
110	device_t sc_ucb; /* parent (UCB1200 module) */
111	tx_chipset_tag_t sc_tc;
112
113	enum ucbts_stat sc_stat;
114	int sc_polling;
115	int sc_polling_finish;
116	void *sc_pollh;
117
118	struct tpcalib_softc sc_tpcalib;
119	int sc_calibrated;
120
121	/* measurement value */
122	int sc_x, sc_y, sc_p;
123	int sc_ox, sc_oy;
124	int sc_xy_reverse; /* some platform pin connect interchanged */
125
126	/*
127	 * touch panel state machine
128	 */
129	void *sm_ih; /* TX39 SIB subframe 0 interrupt handler */
130
131	int sm_addr; /* UCB1200 register address */
132	u_int32_t sm_reg;  /* UCB1200 register data & TX39 SIB header */
133	int sm_tmpreg;
134#define UCBADC_RETRY_DEFAULT		200
135	int sm_retry; /* retry counter */
136
137	enum ucbadc_state sm_state;
138	int		sm_measurement; /* X, Y, Pressure */
139#define	UCBADC_MEASUREMENT_X		0
140#define	UCBADC_MEASUREMENT_Y		1
141#define	UCBADC_MEASUREMENT_PRESSURE	2
142	int sm_returnstate;
143
144	int sm_read_state, sm_write_state;
145	int sm_writing;	/* writing state flag */
146	u_int32_t sm_write_val;	/* temporary buffer */
147
148	int sm_rw_retry; /* retry counter for r/w */
149
150	/* wsmouse */
151	device_t sc_wsmousedev;
152};
153
154int	ucbtp_match(device_t, cfdata_t, void *);
155void	ucbtp_attach(device_t, device_t, void *);
156
157int	ucbtp_sibintr(void *);
158int	ucbtp_poll(void *);
159int	ucbtp_adc_async(void *);
160int	ucbtp_input(struct ucbtp_softc *);
161int	ucbtp_busy(void *);
162
163int	ucbtp_enable(void *);
164int	ucbtp_ioctl(void *, u_long, void *, int, struct lwp *);
165void	ucbtp_disable(void *);
166
167CFATTACH_DECL_NEW(ucbtp, sizeof(struct ucbtp_softc),
168    ucbtp_match, ucbtp_attach, NULL, NULL);
169
170const struct wsmouse_accessops ucbtp_accessops = {
171	ucbtp_enable,
172	ucbtp_ioctl,
173	ucbtp_disable,
174};
175
176/*
177 * XXX currently no calibration method. this is temporary hack.
178 */
179#include <machine/platid.h>
180
181struct	wsmouse_calibcoords *calibration_sample_lookup(void);
182int	ucbtp_calibration(struct ucbtp_softc *);
183
184struct calibration_sample_table {
185	platid_t	cst_platform;
186	struct wsmouse_calibcoords cst_sample;
187} calibration_sample_table[] = {
188	{{{PLATID_WILD, PLATID_MACH_COMPAQ_C_8XX}},  /* uch machine */
189	 { 0, 0, 639, 239, 5,
190	   {{ 507, 510, 320, 120 },
191	    { 898, 757,  40,  40 },
192	    { 900, 255,  40, 200 },
193	    { 109, 249, 600, 200 },
194	    { 110, 753, 600,  40 }}}},
195
196	{{{PLATID_WILD, PLATID_MACH_COMPAQ_C_2010}}, /* uch machine */
197	 { 0, 0, 639, 239, 5,
198	   {{ 506, 487, 320, 120 },
199	    { 880, 250,  40,  40 },
200	    { 880, 718,  40, 200 },
201	    { 140, 726, 600, 200 },
202	    { 137, 250, 600,  40 }}}},
203
204	{{{PLATID_WILD, PLATID_MACH_SHARP_MOBILON_HC4100}}, /* uch machine */
205	 { 0, 0, 639, 239, 5,
206	   {{ 497, 501, 320, 120 },
207	    { 752, 893,  40,  40 },
208	    { 242, 891,  40, 200 },
209	    { 241, 115, 600, 200 },
210	    { 747, 101, 600,  40 }}}},
211
212	{{{PLATID_WILD, PLATID_MACH_SHARP_TELIOS_HCVJ}}, /* uch machine */
213	 { 0, 0, 799, 479, 5,
214	   {{ 850, 150,   1,   1 },
215	    { 850, 880,   1, 479 },
216	    { 850, 880,   1, 479 },
217	    {  85, 880, 799, 479 },
218	    {  85, 150, 799,   1 }}}},
219
220	{{{PLATID_UNKNOWN, PLATID_UNKNOWN}},
221	 { 0, 0, 639, 239, 5,
222	   {{0, 0, 0, 0},
223	    {0, 0, 0, 0},
224	    {0, 0, 0, 0},
225	    {0, 0, 0, 0},
226	    {0, 0, 0, 0}}}},
227};
228
229struct wsmouse_calibcoords *
230calibration_sample_lookup(void)
231{
232	struct calibration_sample_table *tab;
233	platid_mask_t mask;
234
235	for (tab = calibration_sample_table;
236	    tab->cst_platform.dw.dw1 != PLATID_UNKNOWN; tab++) {
237
238		mask = PLATID_DEREF(&tab->cst_platform);
239
240		if (platid_match(&platid, &mask)) {
241			return (&tab->cst_sample);
242		}
243	}
244
245	return (0);
246}
247
248int
249ucbtp_calibration(struct ucbtp_softc *sc)
250{
251	struct wsmouse_calibcoords *cs;
252
253	if (sc->sc_tc->tc_videot)
254		video_calibration_pattern(sc->sc_tc->tc_videot); /* debug */
255
256	tpcalib_init(&sc->sc_tpcalib);
257
258	if (!(cs = calibration_sample_lookup())) {
259		DPRINTF("no calibration data");
260		return (1);
261	}
262
263	sc->sc_calibrated =
264	    tpcalib_ioctl(&sc->sc_tpcalib, WSMOUSEIO_SCALIBCOORDS,
265		(void *)cs, 0, 0) == 0 ? 1 : 0;
266
267	if (!sc->sc_calibrated)
268		printf("not ");
269	printf("calibrated");
270
271	return (0);
272}
273
274int
275ucbtp_match(device_t parent, cfdata_t cf, void *aux)
276{
277
278	return (1);
279}
280
281void
282ucbtp_attach(device_t parent, device_t self, void *aux)
283{
284	struct ucb1200_attach_args *ucba = aux;
285	struct ucbtp_softc *sc = device_private(self);
286	struct wsmousedev_attach_args wsmaa;
287	tx_chipset_tag_t tc;
288
289	sc->sc_dev = self;
290	tc = sc->sc_tc = ucba->ucba_tc;
291	sc->sc_sib = ucba->ucba_sib;
292	sc->sc_ucb = ucba->ucba_ucb;
293
294	printf(": ");
295	/* touch panel interrupt */
296	tx_intr_establish(tc, MAKEINTR(1, TX39_INTRSTATUS1_SIBIRQPOSINT),
297	    IST_EDGE, IPL_TTY, ucbtp_sibintr, sc);
298
299	/* attempt to calibrate touch panel */
300	ucbtp_calibration(sc);
301#ifdef TX392X /* hack for Telios HC-VJ1C */
302	sc->sc_xy_reverse = 1;
303#endif
304
305	printf("\n");
306
307	wsmaa.accessops = &ucbtp_accessops;
308	wsmaa.accesscookie = sc;
309
310	ucb1200_state_install(parent, ucbtp_busy, self, UCB1200_TP_MODULE);
311
312	/*
313	 * attach the wsmouse
314	 */
315	sc->sc_wsmousedev = config_found(self, &wsmaa, wsmousedevprint,
316	    CFARGS_NONE);
317}
318
319int
320ucbtp_busy(void *arg)
321{
322	struct ucbtp_softc *sc = arg;
323
324	return (sc->sm_state != UCBADC_IDLE);
325}
326
327int
328ucbtp_poll(void *arg)
329{
330	struct ucbtp_softc *sc = arg;
331
332	if (!ucb1200_state_idle(sc->sc_ucb)) /* subframe0 busy */
333		return (POLL_CONT);
334
335	if (sc->sc_polling_finish) {
336		sc->sc_polling_finish = 0;
337		return (POLL_END);
338	}
339
340	/* execute A-D converter */
341	sc->sm_state = UCBADC_ADC_INIT;
342	ucbtp_adc_async(sc);
343
344	return (POLL_CONT);
345}
346
347int
348ucbtp_sibintr(void *arg)
349{
350	struct ucbtp_softc *sc = arg;
351
352	sc->sc_stat = UCBTS_STAT_TOUCH;
353
354	/* click! */
355	tx_sound_click(sc->sc_tc);
356
357	/* invoke touch panel polling */
358	if (!sc->sc_polling) {
359		sc->sc_pollh = tx39_poll_establish(sc->sc_tc, 1, IST_EDGE,
360		    ucbtp_poll, sc);
361		if (!sc->sc_pollh) {
362			printf("%s: can't poll\n", device_xname(sc->sc_dev));
363		}
364	}
365
366	/* don't acknoledge interrupt until polling finish */
367
368	return (0);
369}
370
371#define REGWRITE(addr, reg, ret) (					\
372	sc->sm_addr = (addr),						\
373	sc->sm_reg = (reg),						\
374	sc->sm_returnstate = (ret),					\
375	sc->sm_state = UCBADC_REGWRITE)
376#define REGREAD(addr, ret) (						\
377	sc->sm_addr = (addr),						\
378	sc->sm_returnstate = (ret),					\
379	sc->sm_state = UCBADC_REGREAD)
380
381int
382ucbtp_adc_async(void *arg)
383{
384	struct ucbtp_softc *sc = arg;
385	tx_chipset_tag_t tc = sc->sc_tc;
386	txreg_t reg;
387	u_int16_t reg16;
388
389	DPRINTFN(9, "state: %d\n", sc->sm_state);
390
391	switch (sc->sm_state) {
392	default:
393		panic("ucbtp_adc: invalid state %d", sc->sm_state);
394		/* NOTREACHED */
395		break;
396
397	case UCBADC_IDLE:
398		/* nothing to do */
399		break;
400
401	case UCBADC_ADC_INIT:
402		sc->sc_polling++;
403		sc->sc_stat = UCBTS_STAT_DRAG;
404		/* enable heart beat of this state machine */
405		sc->sm_ih = tx_intr_establish(
406			tc,
407			MAKEINTR(1, TX39_INTRSTATUS1_SIBSF0INT),
408			IST_EDGE, IPL_TTY, ucbtp_adc_async, sc);
409
410		sc->sm_state = UCBADC_MEASUMENT_INIT;
411		break;
412
413	case UCBADC_ADC_FINI:
414		/* disable heart beat of this state machine */
415		tx_intr_disestablish(tc, sc->sm_ih);
416		sc->sm_state = UCBADC_IDLE;
417		break;
418
419	case UCBADC_MEASUMENT_INIT:
420		switch (sc->sm_measurement) {
421		default:
422			panic("unknown measurement spec.");
423			/* NOTREACHED */
424			break;
425		case UCBADC_MEASUREMENT_X:
426			REGWRITE(UCB1200_TSCTRL_REG,
427			    UCB1200_TSCTRL_XPOSITION,
428			    UCBADC_ADC_ENABLE);
429			break;
430		case UCBADC_MEASUREMENT_Y:
431			REGWRITE(UCB1200_TSCTRL_REG,
432			    UCB1200_TSCTRL_YPOSITION,
433			    UCBADC_ADC_ENABLE);
434			break;
435		case UCBADC_MEASUREMENT_PRESSURE:
436			REGWRITE(UCB1200_TSCTRL_REG,
437			    UCB1200_TSCTRL_PRESSURE,
438			    UCBADC_ADC_ENABLE);
439			break;
440		}
441		break;
442
443	case UCBADC_MEASUMENT_FINI:
444		switch (sc->sm_measurement) {
445		case UCBADC_MEASUREMENT_X:
446			sc->sm_measurement = UCBADC_MEASUREMENT_Y;
447			sc->sm_state = UCBADC_MEASUMENT_INIT;
448			break;
449		case UCBADC_MEASUREMENT_Y:
450			sc->sm_measurement = UCBADC_MEASUREMENT_PRESSURE;
451			sc->sm_state = UCBADC_MEASUMENT_INIT;
452			break;
453		case UCBADC_MEASUREMENT_PRESSURE:
454			sc->sm_measurement = UCBADC_MEASUREMENT_X;
455			/* measurement complete. pass down to wsmouse_input */
456			sc->sm_state = UCBADC_ADC_INPUT;
457			break;
458		}
459		break;
460
461	case UCBADC_ADC_ENABLE:
462		switch (sc->sm_measurement) {
463		case UCBADC_MEASUREMENT_PRESSURE:
464			/* FALLTHROUGH */
465		case UCBADC_MEASUREMENT_X:
466			sc->sm_tmpreg = UCB1200_ADCCTRL_INPUT_SET(
467				UCB1200_ADCCTRL_ENABLE,
468				UCB1200_ADCCTRL_INPUT_TSPX);
469			REGWRITE(UCB1200_ADCCTRL_REG, sc->sm_tmpreg,
470			    UCBADC_ADC_START0);
471			break;
472		case UCBADC_MEASUREMENT_Y:
473			sc->sm_tmpreg = UCB1200_ADCCTRL_INPUT_SET(
474				UCB1200_ADCCTRL_ENABLE,
475				UCB1200_ADCCTRL_INPUT_TSPY);
476			REGWRITE(UCB1200_ADCCTRL_REG, sc->sm_tmpreg,
477			    UCBADC_ADC_START0);
478			break;
479		}
480		break;
481
482	case UCBADC_ADC_START0:
483		REGWRITE(UCB1200_ADCCTRL_REG,
484		    sc->sm_tmpreg | UCB1200_ADCCTRL_START,
485		    UCBADC_ADC_START1);
486		break;
487
488	case UCBADC_ADC_START1:
489		REGWRITE(UCB1200_ADCCTRL_REG,
490		    sc->sm_tmpreg,
491		    UCBADC_ADC_DATAREAD);
492		sc->sm_retry = UCBADC_RETRY_DEFAULT;
493		break;
494
495	case UCBADC_ADC_DATAREAD:
496		REGREAD(UCB1200_ADCDATA_REG, UCBADC_ADC_DATAREAD_WAIT);
497		break;
498
499	case UCBADC_ADC_DATAREAD_WAIT:
500		reg16 = TX39_SIBSF0_REGDATA(sc->sm_reg);
501		if (!(reg16 & UCB1200_ADCDATA_INPROGRESS) &&
502		    --sc->sm_retry > 0) {
503			sc->sm_state = UCBADC_ADC_DATAREAD;
504		} else {
505			if (sc->sm_retry <= 0) {
506				printf("dataread failed\n");
507				sc->sm_state = UCBADC_ADC_FINI;
508				break;
509			}
510
511			switch (sc->sm_measurement) {
512			case UCBADC_MEASUREMENT_X:
513				sc->sc_x = UCB1200_ADCDATA(reg16);
514				DPRINTFN(9, "x=%d\n", sc->sc_x);
515				break;
516			case UCBADC_MEASUREMENT_Y:
517				sc->sc_y = UCB1200_ADCDATA(reg16);
518				DPRINTFN(9, "y=%d\n", sc->sc_y);
519				break;
520			case UCBADC_MEASUREMENT_PRESSURE:
521				sc->sc_p = UCB1200_ADCDATA(reg16);
522				DPRINTFN(9, "p=%d\n", sc->sc_p);
523				break;
524			}
525
526			sc->sm_state = UCBADC_ADC_DISABLE;
527		}
528
529		break;
530
531	case UCBADC_ADC_DISABLE:
532		REGWRITE(UCB1200_ADCCTRL_REG, 0, UCBADC_ADC_INTRMODE);
533
534		break;
535	case UCBADC_ADC_INTRMODE:
536		REGWRITE(UCB1200_TSCTRL_REG, UCB1200_TSCTRL_INTERRUPT,
537		    UCBADC_MEASUMENT_FINI);
538		break;
539
540	case UCBADC_ADC_INPUT:
541		if (ucbtp_input(sc) == 0)
542			sc->sm_state = UCBADC_ADC_FINI;
543		else
544			sc->sm_state = UCBADC_INTR_ACK0;
545		break;
546
547	case UCBADC_INTR_ACK0:
548		REGREAD(UCB1200_INTSTAT_REG, UCBADC_INTR_ACK1);
549		break;
550
551	case UCBADC_INTR_ACK1:
552		REGWRITE(UCB1200_INTSTAT_REG, sc->sm_reg, UCBADC_INTR_ACK2);
553		break;
554
555	case UCBADC_INTR_ACK2:
556		sc->sc_polling_finish = 1;
557		REGWRITE(UCB1200_INTSTAT_REG, 0, UCBADC_ADC_FINI);
558		break;
559
560		/*
561		 * UCB1200 register access state
562		 */
563	case UCBADC_REGREAD:
564		/*
565		 * In	: sc->sm_addr
566		 * Out	: sc->sm_reg  (with SIBtag)
567		 */
568#define TXSIB_REGREAD_INIT	0
569#define TXSIB_REGREAD_READ	1
570		switch (sc->sm_read_state) {
571		case TXSIB_REGREAD_INIT:
572			reg = TX39_SIBSF0_REGADDR_SET(0, sc->sm_addr);
573			tx_conf_write(tc, TX39_SIBSF0CTRL_REG, reg);
574			sc->sm_rw_retry = UCBADC_RETRY_DEFAULT;
575			sc->sm_read_state = TXSIB_REGREAD_READ;
576			break;
577		case TXSIB_REGREAD_READ:
578			reg = tx_conf_read(tc, TX39_SIBSF0STAT_REG);
579			if ((TX39_SIBSF0_REGADDR(reg) != sc->sm_addr) &&
580			    --sc->sm_rw_retry > 0) {
581				break;
582			}
583
584			if (sc->sm_rw_retry <= 0) {
585				printf("sf0read: command failed\n");
586				sc->sm_state = UCBADC_ADC_FINI;
587			} else {
588				sc->sm_reg = reg;
589				sc->sm_read_state = TXSIB_REGREAD_INIT;
590				DPRINTFN(9, "%08x\n", reg);
591				if (sc->sm_writing)
592					sc->sm_state = UCBADC_REGWRITE;
593				else
594					sc->sm_state = sc->sm_returnstate;
595			}
596			break;
597		}
598		break;
599
600	case UCBADC_REGWRITE:
601		/*
602		 * In	: sc->sm_addr, sc->sm_reg (lower 16bit only)
603		 */
604#define TXSIB_REGWRITE_INIT	0
605#define TXSIB_REGWRITE_WRITE	1
606		switch (sc->sm_write_state) {
607		case TXSIB_REGWRITE_INIT:
608			sc->sm_writing = 1;
609			sc->sm_write_state = TXSIB_REGWRITE_WRITE;
610			sc->sm_state = UCBADC_REGREAD;
611
612			sc->sm_write_val = sc->sm_reg;
613			break;
614		case TXSIB_REGWRITE_WRITE:
615			sc->sm_writing = 0;
616			sc->sm_write_state = TXSIB_REGWRITE_INIT;
617			sc->sm_state = sc->sm_returnstate;
618
619			reg = sc->sm_reg;
620			reg |= TX39_SIBSF0_WRITE;
621			TX39_SIBSF0_REGDATA_CLR(reg);
622			reg = TX39_SIBSF0_REGDATA_SET(reg, sc->sm_write_val);
623			tx_conf_write(tc, TX39_SIBSF0CTRL_REG, reg);
624			break;
625		}
626		break;
627	}
628
629	return (0);
630}
631
632int
633ucbtp_input(struct ucbtp_softc *sc)
634{
635	int rx, ry, x, y, p;
636
637	rx = sc->sc_x;
638	ry = sc->sc_y;
639	p = sc->sc_p;
640
641	if (!sc->sc_calibrated) {
642		DPRINTFN(2, "x=%4d y=%4d p=%4d\n", rx, ry, p);
643		DPRINTF("ucbtp_input: no calibration data\n");
644	}
645
646	if (p < UCBTS_PRESS_THRESHOLD || rx == 0x3ff || ry == 0x3ff ||
647	    rx == 0 || ry == 0) {
648		sc->sc_stat = UCBTS_STAT_RELEASE;
649		if (sc->sc_polling < UCBTS_TAP_THRESHOLD) {
650			DPRINTFN(2, "TAP!\n");
651			/* button 0 DOWN */
652			wsmouse_input(sc->sc_wsmousedev, 1, 0, 0, 0, 0, 0);
653			/* button 0 UP */
654			wsmouse_input(sc->sc_wsmousedev, 0, 0, 0, 0, 0, 0);
655		} else {
656			wsmouse_input(sc->sc_wsmousedev, 0,
657			    sc->sc_ox, sc->sc_oy, 0, 0,
658			    WSMOUSE_INPUT_ABSOLUTE_X |
659			    WSMOUSE_INPUT_ABSOLUTE_Y);
660
661			DPRINTFN(2, "RELEASE\n");
662		}
663		sc->sc_polling = 0;
664
665		return (1);
666	}
667
668	if (sc->sc_xy_reverse)
669		tpcalib_trans(&sc->sc_tpcalib, ry, rx, &x, &y);
670	else
671		tpcalib_trans(&sc->sc_tpcalib, rx, ry, &x, &y);
672
673	DPRINTFN(2, "x: %4d->%4d y: %4d->%4d pressure=%4d\n",
674	    rx, x, ry, y, p);
675
676	/* debug draw */
677	if (sc->sc_tc->tc_videot) {
678		if (sc->sc_polling == 1)
679			video_dot(sc->sc_tc->tc_videot, x, y);
680		else
681			video_line(sc->sc_tc->tc_videot, sc->sc_ox,
682			    sc->sc_oy, x, y);
683	}
684
685	sc->sc_ox = x, sc->sc_oy = y;
686
687	wsmouse_input(sc->sc_wsmousedev, 1, x, y, 0, 0,
688	    WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y);
689
690	return (0);
691}
692
693/*
694 * access ops.
695 */
696
697int
698ucbtp_enable(void *v)
699{
700	/* not yet */
701	return (0);
702}
703
704void
705ucbtp_disable(void *v)
706{
707	/* not yet */
708}
709
710int
711ucbtp_ioctl(void *v, u_long cmd, void *data, int flag, struct lwp *l)
712{
713	struct ucbtp_softc *sc = v;
714
715	DPRINTF("%s(%d): ucbtp_ioctl(%08lx)\n", __FILE__, __LINE__, cmd);
716
717	switch (cmd) {
718	case WSMOUSEIO_SRES:
719		printf("%s(%d): WSMOUSRIO_SRES is not supported",
720		    __FILE__, __LINE__);
721		break;
722
723	default:
724		return hpc_tpanel_ioctl(&sc->sc_tpcalib, cmd, data, flag, l);
725	}
726
727	return 0;
728}
729