Home | History | Annotate | Line # | Download | only in dev
j6x0tp.c revision 1.5
      1 /*	$NetBSD: j6x0tp.c,v 1.5 2004/05/28 17:52:07 tsarna Exp $ */
      2 
      3 /*
      4  * Copyright (c) 2003 Valeriy E. Ushakov
      5  * 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  * 3. The name of the author may not be used to endorse or promote products
     16  *    derived from this software without specific prior written permission
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     28  */
     29 
     30 #include <sys/cdefs.h>
     31 __KERNEL_RCSID(0, "$NetBSD: j6x0tp.c,v 1.5 2004/05/28 17:52:07 tsarna Exp $");
     32 
     33 #include <sys/param.h>
     34 #include <sys/kernel.h>
     35 #include <sys/device.h>
     36 #include <sys/malloc.h>
     37 #include <sys/systm.h>
     38 #include <sys/callout.h>
     39 #ifdef GPROF
     40 #include <sys/gmon.h>
     41 #endif
     42 
     43 #include "opt_j6x0tp.h"
     44 
     45 #include <dev/wscons/wsconsio.h>
     46 #include <dev/wscons/wsmousevar.h>
     47 #include <dev/wscons/wskbdvar.h>
     48 #include <dev/wscons/wsksymvar.h>
     49 #include <dev/wscons/wsksymdef.h>
     50 #include <dev/hpc/hpctpanelvar.h>
     51 
     52 #include <machine/platid.h>
     53 #include <machine/platid_mask.h>
     54 
     55 #include <machine/intr.h>
     56 
     57 #include <sh3/exception.h>
     58 #include <sh3/intcreg.h>
     59 #include <sh3/pfcreg.h>
     60 #include <sh3/adcreg.h>
     61 
     62 #include <sh3/dev/adcvar.h>
     63 
     64 
     65 #define J6X0TP_DEBUG
     66 #if 0 /* XXX: disabled in favor of local version that uses printf_nolog */
     67 #define DPRINTF_ENABLE
     68 #define DPRINTF_DEBUG	j6x0tp_debug
     69 #define DPRINTF_LEVEL	0
     70 #include <machine/debug.h>
     71 #else
     72 #ifdef J6X0TP_DEBUG
     73 volatile int j6x0tp_debug = 0;
     74 #define DPRINTF_PRINTF		printf_nolog
     75 #define DPRINTF(arg)		if (j6x0tp_debug) DPRINTF_PRINTF arg
     76 #define DPRINTFN(n, arg)	if (j6x0tp_debug > (n)) DPRINTF_PRINTF arg
     77 #else
     78 #define DPRINTF(arg)		((void)0)
     79 #define DPRINTFN(n, arg)	((void)0)
     80 #endif
     81 #endif
     82 
     83 
     84 /*
     85  * PFC bits pertinent to Jornada 6x0 touchpanel
     86  */
     87 #define PHDR_TP_PEN_DOWN	0x08
     88 
     89 #define SCPDR_TP_SCAN_ENABLE	0x20
     90 #define SCPDR_TP_SCAN_Y		0x02
     91 #define SCPDR_TP_SCAN_X		0x01
     92 
     93 /*
     94  * A/D converter channels to get x/y from
     95  */
     96 #define ADC_CHANNEL_TP_Y	1
     97 #define ADC_CHANNEL_TP_X	2
     98 
     99 /*
    100  * Default (read: my device :) raw X/Y values for framebuffer edges.
    101  * XXX: defopt these?
    102  */
    103 #define J6X0TP_FB_LEFT		 38
    104 #define J6X0TP_FB_RIGHT		950
    105 #define J6X0TP_FB_TOP		 80
    106 #define J6X0TP_FB_BOTTOM	900
    107 
    108 /*
    109  * Bottom of the n'th hard icon (n = 1..4)
    110  */
    111 #define J6X0TP_HARD_ICON_MAX_Y(n) \
    112 	(J6X0TP_FB_TOP + ((J6X0TP_FB_BOTTOM - J6X0TP_FB_TOP) / 4) * (n))
    113 
    114 
    115 struct j6x0tp_softc {
    116 	struct device sc_dev;
    117 
    118 #define J6X0TP_WSMOUSE_ENABLED	0x01
    119 #define J6X0TP_WSKBD_ENABLED	0x02
    120 	int sc_enabled;
    121 
    122 	int sc_hard_icon;
    123 
    124 	struct callout sc_touch_ch;
    125 
    126 	struct device *sc_wsmousedev;
    127 	struct device *sc_wskbddev;
    128 
    129 	struct tpcalib_softc sc_tpcalib; /* calibration info for wsmouse */
    130 };
    131 
    132 
    133 /* config machinery */
    134 static int	j6x0tp_match(struct device *, struct cfdata *, void *);
    135 static void	j6x0tp_attach(struct device *, struct device *, void *);
    136 static int	j6x0tp_wsmouse_submatch(struct device *, struct cfdata *,
    137 					void *);
    138 static int	j6x0tp_wskbd_submatch(struct device *, struct cfdata *,
    139 				      void *);
    140 
    141 /* wsmouse accessops */
    142 static int	j6x0tp_wsmouse_enable(void *);
    143 static int	j6x0tp_wsmouse_ioctl(void *, u_long, caddr_t, int,
    144 				     struct proc *);
    145 static void	j6x0tp_wsmouse_disable(void *);
    146 
    147 /* wskbd accessops */
    148 static int	j6x0tp_wskbd_enable(void *, int);
    149 static void	j6x0tp_wskbd_set_leds(void *, int);
    150 static int	j6x0tp_wskbd_ioctl(void *, u_long, caddr_t, int,
    151 				   struct proc *);
    152 
    153 /* internal driver routines */
    154 static void	j6x0tp_enable(struct j6x0tp_softc *);
    155 static void	j6x0tp_disable(struct j6x0tp_softc *);
    156 static int	j6x0tp_set_enable(struct j6x0tp_softc *, int, int);
    157 static int	j6x0tp_intr(void *);
    158 static void	j6x0tp_start_polling(void *);
    159 static void	j6x0tp_stop_polling(struct j6x0tp_softc *);
    160 static void	j6x0tp_callout_wsmouse(void *);
    161 static void	j6x0tp_callout_wskbd(void *);
    162 static void	j6x0tp_wsmouse_input(struct j6x0tp_softc *, int, int);
    163 static void	j6x0tp_get_raw_xy(int *, int *);
    164 static int	j6x0tp_get_hard_icon(int, int);
    165 
    166 
    167 const struct wsmouse_accessops j6x0tp_accessops = {
    168 	j6x0tp_wsmouse_enable,
    169 	j6x0tp_wsmouse_ioctl,
    170 	j6x0tp_wsmouse_disable
    171 };
    172 
    173 static const struct wsmouse_calibcoords j6x0tp_default_calib = {
    174 	0, 0, 639, 239,
    175 	4,
    176 	{{ J6X0TP_FB_LEFT,  J6X0TP_FB_TOP,      0,   0 },
    177 	 { J6X0TP_FB_RIGHT, J6X0TP_FB_TOP,    639,   0 },
    178 	 { J6X0TP_FB_LEFT,  J6X0TP_FB_BOTTOM,   0, 239 },
    179 	 { J6X0TP_FB_RIGHT, J6X0TP_FB_BOTTOM, 639, 239 }}
    180 };
    181 
    182 const struct wskbd_accessops j6x0tp_wskbd_accessops = {
    183 	j6x0tp_wskbd_enable,
    184 	j6x0tp_wskbd_set_leds,
    185 	j6x0tp_wskbd_ioctl
    186 };
    187 
    188 
    189 #ifndef J6X0TP_SETTINGS_ICON_KEYSYM
    190 #define J6X0TP_SETTINGS_ICON_KEYSYM	KS_Home
    191 #endif
    192 #ifndef J6X0TP_PGUP_ICON_KEYSYM
    193 #define J6X0TP_PGUP_ICON_KEYSYM		KS_Prior
    194 #endif
    195 #ifndef J6X0TP_PGDN_ICON_KEYSYM
    196 #define J6X0TP_PGDN_ICON_KEYSYM		KS_Next
    197 #endif
    198 #ifndef J6X0TP_SWITCH_ICON_KEYSYM
    199 #define J6X0TP_SWITCH_ICON_KEYSYM	KS_End
    200 #endif
    201 
    202 static const keysym_t j6x0tp_wskbd_keydesc[] = {
    203 	KS_KEYCODE(1), J6X0TP_SETTINGS_ICON_KEYSYM,
    204 	KS_KEYCODE(2), J6X0TP_PGUP_ICON_KEYSYM,
    205 	KS_KEYCODE(3), J6X0TP_PGDN_ICON_KEYSYM,
    206 	KS_KEYCODE(4), J6X0TP_SWITCH_ICON_KEYSYM
    207 };
    208 
    209 const struct wscons_keydesc j6x0tp_wskbd_keydesctab[] = {
    210 	{ KB_US, 0,
    211 	  sizeof(j6x0tp_wskbd_keydesc)/sizeof(keysym_t),
    212 	  j6x0tp_wskbd_keydesc
    213 	},
    214 	{0, 0, 0, 0}
    215 };
    216 
    217 const struct wskbd_mapdata j6x0tp_wskbd_keymapdata = {
    218         j6x0tp_wskbd_keydesctab, KB_US
    219 };
    220 
    221 
    222 CFATTACH_DECL(j6x0tp, sizeof(struct j6x0tp_softc),
    223     j6x0tp_match, j6x0tp_attach, NULL, NULL);
    224 
    225 
    226 static int
    227 j6x0tp_match(struct device *parent, struct cfdata *cf, void *aux)
    228 {
    229 
    230 	/*
    231 	 * XXX: does platid_mask_MACH_HP_LX matches _JORNADA_6XX too?
    232 	 * Is 620 wired similarly?
    233 	 */
    234 	if (!platid_match(&platid, &platid_mask_MACH_HP_JORNADA_6XX))
    235 		return (0);
    236 
    237 	if (strcmp(cf->cf_name, "j6x0tp") != 0)
    238 		return (0);
    239 
    240 	return (1);
    241 }
    242 
    243 
    244 /*
    245  * Attach the touch panel driver and its ws* children.
    246  *
    247  * Note that we have to use submatch to distinguish between children
    248  * because ws{kbd,mouse}_match match unconditionally.
    249  */
    250 static void
    251 j6x0tp_attach(struct device *parent, struct device *self, void *aux)
    252 {
    253 	struct j6x0tp_softc *sc = (struct j6x0tp_softc *)self;
    254 	struct wsmousedev_attach_args wsma;
    255 	struct wskbddev_attach_args wska;
    256 
    257 	printf("\n");
    258 
    259 	sc->sc_enabled = 0;
    260 	sc->sc_hard_icon = 0;
    261 
    262 	/* touch-panel as a pointing device */
    263 	wsma.accessops = &j6x0tp_accessops;
    264 	wsma.accesscookie = sc;
    265 
    266 	sc->sc_wsmousedev = config_found_sm(self, &wsma, wsmousedevprint,
    267 					    j6x0tp_wsmouse_submatch);
    268 	if (sc->sc_wsmousedev == NULL)
    269 		return;
    270 
    271 	/* on-screen "hard icons" as a keyboard device */
    272 	wska.console = 0;
    273 	wska.keymap = &j6x0tp_wskbd_keymapdata;
    274 	wska.accessops = &j6x0tp_wskbd_accessops;
    275 	wska.accesscookie = sc;
    276 
    277 	sc->sc_wskbddev = config_found_sm(self, &wska, wskbddevprint,
    278 					  j6x0tp_wskbd_submatch);
    279 
    280 	/* init calibration, set default parameters */
    281 	tpcalib_init(&sc->sc_tpcalib);
    282 	tpcalib_ioctl(&sc->sc_tpcalib, WSMOUSEIO_SCALIBCOORDS,
    283 		      (caddr_t)&j6x0tp_default_calib, 0, 0);
    284 
    285 	/* used when in polling mode */
    286 	callout_init(&sc->sc_touch_ch);
    287 
    288 	/* establish interrupt handler, but disable until opened */
    289 	intc_intr_establish(SH7709_INTEVT2_IRQ3, IST_EDGE, IPL_TTY,
    290 			    j6x0tp_intr, sc);
    291 	intc_intr_disable(SH7709_INTEVT2_IRQ3);
    292 }
    293 
    294 
    295 static int
    296 j6x0tp_wsmouse_submatch(struct device *parent, struct cfdata *cf, void *aux)
    297 {
    298 
    299 	return (!strcmp(cf->cf_name, "wsmouse"));
    300 }
    301 
    302 
    303 static int
    304 j6x0tp_wskbd_submatch(struct device *parent, struct cfdata *cf, void *aux)
    305 {
    306 
    307 	return (!strcmp(cf->cf_name, "wskbd"));
    308 }
    309 
    310 
    311 /*
    312  * Enable touch panel:  we start in interrupt mode.
    313  * Must be called as spltty().
    314  */
    315 static void
    316 j6x0tp_enable(struct j6x0tp_softc *sc)
    317 {
    318 
    319 	DPRINTFN(2, ("%s: enable\n", sc->sc_dev.dv_xname));
    320 	intc_intr_enable(SH7709_INTEVT2_IRQ3);
    321 }
    322 
    323 
    324 /*
    325  * Disable touch panel: disable interrupt, cancel pending callout.
    326  * Must be called as spltty().
    327  */
    328 static void
    329 j6x0tp_disable(struct j6x0tp_softc *sc)
    330 {
    331 
    332 	DPRINTFN(2, ("%s: disable\n", sc->sc_dev.dv_xname));
    333 	intc_intr_disable(SH7709_INTEVT2_IRQ3);
    334 	callout_stop(&sc->sc_touch_ch);
    335 }
    336 
    337 
    338 static int
    339 j6x0tp_set_enable(struct j6x0tp_softc *sc, int on, int child)
    340 {
    341 	int s = spltty();
    342 
    343 	if (on) {
    344 		if (!sc->sc_enabled)
    345 			j6x0tp_enable(sc);
    346 		sc->sc_enabled |= child;
    347 	} else {
    348 		sc->sc_enabled &= ~child;
    349 		if (!sc->sc_enabled)
    350 			j6x0tp_disable(sc);
    351 	}
    352 
    353 	splx(s);
    354 	return (0);
    355 }
    356 
    357 
    358 static int
    359 j6x0tp_wsmouse_enable(void *self)
    360 {
    361 	struct j6x0tp_softc *sc = (struct j6x0tp_softc *)self;
    362 
    363 	DPRINTFN(1, ("%s: wsmouse enable\n", sc->sc_dev.dv_xname));
    364 	return (j6x0tp_set_enable(sc, 1, J6X0TP_WSMOUSE_ENABLED));
    365 }
    366 
    367 
    368 static void
    369 j6x0tp_wsmouse_disable(void *self)
    370 {
    371 	struct j6x0tp_softc *sc = (struct j6x0tp_softc *)self;
    372 
    373 	DPRINTFN(1, ("%s: wsmouse disable\n", sc->sc_dev.dv_xname));
    374 	j6x0tp_set_enable(sc, 0, J6X0TP_WSMOUSE_ENABLED);
    375 }
    376 
    377 
    378 static int
    379 j6x0tp_wskbd_enable(void *self, int on)
    380 {
    381 	struct j6x0tp_softc *sc = (struct j6x0tp_softc *)self;
    382 
    383 	DPRINTFN(1, ("%s: wskbd %sable\n", sc->sc_dev.dv_xname,
    384 		     on ? "en" : "dis"));
    385 	return (j6x0tp_set_enable(sc, on, J6X0TP_WSKBD_ENABLED));
    386 }
    387 
    388 
    389 static int
    390 j6x0tp_intr(void *self)
    391 {
    392 	struct j6x0tp_softc *sc = (struct j6x0tp_softc *)self;
    393 
    394 	uint8_t irr0;
    395 	uint8_t phdr, touched;
    396 	unsigned int steady, tremor_timeout;
    397 
    398 	irr0 = _reg_read_1(SH7709_IRR0);
    399 	if ((irr0 & IRR0_IRQ3) == 0) {
    400 #ifdef DIAGNOSTIC
    401 		printf("%s: irr0 %02x?\n", sc->sc_dev.dv_xname, irr0);
    402 #endif
    403 		return (0);
    404 	}
    405 
    406 	if (!sc->sc_enabled) {
    407 		DPRINTFN(1, ("%s: intr: !sc_enabled\n", sc->sc_dev.dv_xname));
    408 		intc_intr_disable(SH7709_INTEVT2_IRQ3);
    409 		goto served;
    410 	}
    411 
    412 
    413 	/*
    414 	 * Number of times the "touched" bit should be read
    415 	 * consecutively.
    416 	 */
    417 #	define TREMOR_THRESHOLD 0x300
    418 
    419 	steady = 0;
    420 	tremor_timeout = TREMOR_THRESHOLD * 16;	/* XXX: arbitrary */
    421 	touched = PHDR_TP_PEN_DOWN;	/* we start with "touched" state */
    422 
    423 	do {
    424 		phdr = _reg_read_1(SH7709_PHDR);
    425 
    426 		if ((phdr & PHDR_TP_PEN_DOWN) == touched)
    427 			++steady;
    428 		else {
    429 			steady = 0;
    430 			touched = phdr & PHDR_TP_PEN_DOWN;
    431 		}
    432 
    433 		if (--tremor_timeout == 0) {
    434 			DPRINTF(("%s: tremor timeout!\n",
    435 				 sc->sc_dev.dv_xname));
    436 			goto served;
    437 		}
    438 	} while (steady < TREMOR_THRESHOLD);
    439 
    440 	if (touched) {
    441 		intc_intr_disable(SH7709_INTEVT2_IRQ3);
    442 
    443 		/*
    444 		 * ADC readings are not stable yet, so schedule
    445 		 * callout instead of accessing ADC from the interrupt
    446 		 * handler only to immediately delay().
    447 		 */
    448 		callout_reset(&sc->sc_touch_ch, hz/32,
    449 			      j6x0tp_start_polling, sc);
    450 	} else
    451 		DPRINTFN(1, ("%s: tremor\n", sc->sc_dev.dv_xname));
    452   served:
    453 	/* clear the interrupt (XXX: protect access?) */
    454 	_reg_write_1(SH7709_IRR0, irr0 & ~IRR0_IRQ3);
    455 
    456 	return (1);
    457 }
    458 
    459 
    460 /*
    461  * Called from the interrupt handler at spltty() upon first touch.
    462  * Decide if we are going to report this touch as a mouse click/drag
    463  * or as a key press.
    464  */
    465 static void
    466 j6x0tp_start_polling(void *self)
    467 {
    468 	struct j6x0tp_softc *sc = (struct j6x0tp_softc *)self;
    469 	uint8_t phdr;
    470 	int do_mouse, do_kbd;
    471 	int rawx, rawy;
    472 	int icon;
    473 
    474 	phdr = _reg_read_1(SH7709_PHDR);
    475 	if ((phdr & PHDR_TP_PEN_DOWN) == 0) {
    476 		DPRINTFN(2, ("%s: start: pen is not down\n",
    477 			     sc->sc_dev.dv_xname));
    478 		j6x0tp_stop_polling(sc);
    479 	}
    480 
    481 	j6x0tp_get_raw_xy(&rawx, &rawy);
    482 	DPRINTFN(2, ("%s: start: %4d %4d -> ",
    483 		     sc->sc_dev.dv_xname, rawx, rawy));
    484 
    485 	do_mouse = sc->sc_enabled & J6X0TP_WSMOUSE_ENABLED;
    486 #ifdef J6X0TP_WSMOUSE_EXCLUSIVE
    487 	if (do_mouse)
    488 		do_kbd = 0;
    489 	else
    490 #endif
    491 		do_kbd = sc->sc_enabled & J6X0TP_WSKBD_ENABLED;
    492 
    493 	icon = 0;
    494 	if (do_kbd)
    495 		icon = j6x0tp_get_hard_icon(rawx, rawy);
    496 
    497 	if (icon != 0) {
    498 		DPRINTFN(2, ("icon %d\n", icon));
    499 		sc->sc_hard_icon = icon;
    500 		wskbd_input(sc->sc_wskbddev, WSCONS_EVENT_KEY_DOWN, icon);
    501 		callout_reset(&sc->sc_touch_ch, hz/32,
    502 			      j6x0tp_callout_wskbd, sc);
    503 	} else if (do_mouse) {
    504 		DPRINTFN(2, ("mouse\n"));
    505 		j6x0tp_wsmouse_input(sc, rawx, rawy);
    506 		callout_reset(&sc->sc_touch_ch, hz/32,
    507 			      j6x0tp_callout_wsmouse, sc);
    508 	} else {
    509 		DPRINTFN(2, ("ignore\n"));
    510 		j6x0tp_stop_polling(sc);
    511 	}
    512 }
    513 
    514 
    515 /*
    516  * Re-enable touch panel interrupt.
    517  * Called as spltty() when polling code detects pen-up.
    518  */
    519 static void
    520 j6x0tp_stop_polling(struct j6x0tp_softc *sc)
    521 {
    522 	uint8_t irr0;
    523 
    524 	DPRINTFN(2, ("%s: stop\n", sc->sc_dev.dv_xname));
    525 
    526 	/* clear pending interrupt signal before re-enabling the interrupt */
    527 	irr0 = _reg_read_1(SH7709_IRR0);
    528 	if ((irr0 & IRR0_IRQ3) != 0)
    529 		_reg_write_1(SH7709_IRR0, irr0 & ~IRR0_IRQ3);
    530 
    531 	intc_intr_enable(SH7709_INTEVT2_IRQ3);
    532 }
    533 
    534 
    535 /*
    536  * We are reporting this touch as a keyboard event.
    537  * Poll touch screen waiting for pen-up.
    538  */
    539 static void
    540 j6x0tp_callout_wskbd(void *self)
    541 {
    542 	struct j6x0tp_softc *sc = (struct j6x0tp_softc *)self;
    543 	uint8_t phdr;
    544 	int s;
    545 
    546 	s = spltty();
    547 
    548 	if (!sc->sc_enabled) {
    549 		DPRINTFN(1, ("%s: wskbd callout: !sc_enabled\n",
    550 			     sc->sc_dev.dv_xname));
    551 		splx(s);
    552 		return;
    553 	}
    554 
    555 	phdr = _reg_read_1(SH7709_PHDR);
    556 	if ((phdr & PHDR_TP_PEN_DOWN) != 0) {
    557 		/*
    558 		 * Pen is still down, continue polling.  Wskbd's
    559 		 * auto-repeat takes care of repeating the key.
    560 		 */
    561 		callout_schedule(&sc->sc_touch_ch, hz/32);
    562 	} else {
    563 		wskbd_input(sc->sc_wskbddev,
    564 			    WSCONS_EVENT_KEY_UP, sc->sc_hard_icon);
    565 		j6x0tp_stop_polling(sc);
    566 	}
    567 	splx(s);
    568 }
    569 
    570 
    571 /*
    572  * We are reporting this touch as a mouse click/drag.
    573  */
    574 static void
    575 j6x0tp_callout_wsmouse(void *self)
    576 {
    577 	struct j6x0tp_softc *sc = (struct j6x0tp_softc *)self;
    578 	uint8_t phdr;
    579 	int rawx, rawy;
    580 	int s;
    581 
    582 	s = spltty();
    583 
    584 	if (!sc->sc_enabled) {
    585 		DPRINTFN(1, ("%s: wsmouse callout: !sc_enabled\n",
    586 			     sc->sc_dev.dv_xname));
    587 		splx(s);
    588 		return;
    589 	}
    590 
    591 	phdr = _reg_read_1(SH7709_PHDR);
    592 	if ((phdr & PHDR_TP_PEN_DOWN) != 0) {
    593 		j6x0tp_get_raw_xy(&rawx, &rawy);
    594 		j6x0tp_wsmouse_input(sc, rawx, rawy); /* mouse dragged */
    595 		callout_schedule(&sc->sc_touch_ch, hz/32);
    596 	} else {
    597 		wsmouse_input(sc->sc_wsmousedev, 0, 0, 0, 0, /* button up */
    598 			      WSMOUSE_INPUT_DELTA);
    599 		j6x0tp_stop_polling(sc);
    600 	}
    601 	splx(s);
    602 }
    603 
    604 
    605 /*
    606  * Report mouse click/drag.
    607  */
    608 static void
    609 j6x0tp_wsmouse_input(struct j6x0tp_softc *sc, int rawx, int rawy)
    610 {
    611 	int x, y;
    612 
    613 	tpcalib_trans(&sc->sc_tpcalib, rawx, rawy, &x, &y);
    614 
    615 	DPRINTFN(3, ("%s: %4d %4d -> %3d %3d\n",
    616 		     sc->sc_dev.dv_xname, rawx, rawy, x, y));
    617 
    618 	wsmouse_input(sc->sc_wsmousedev,
    619 		      1,	/* button */
    620 		      x, y,
    621 		      0,	/* flags */
    622 		      WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y);
    623 }
    624 
    625 
    626 /*
    627  * Read raw X/Y coordinates from the ADC.
    628  * XXX: protect accesses to SCPDR?
    629  */
    630 static void
    631 j6x0tp_get_raw_xy(int *rawxp, int *rawyp)
    632 {
    633 	uint8_t scpdr;
    634 
    635 	/* Y axis */
    636 	scpdr = _reg_read_1(SH7709_SCPDR);
    637 	scpdr |=  SCPDR_TP_SCAN_ENABLE;
    638 	scpdr &= ~SCPDR_TP_SCAN_Y; /* pull low to scan */
    639 	_reg_write_1(SH7709_SCPDR, scpdr);
    640 	delay(10);
    641 
    642 	*rawyp = adc_sample_channel(ADC_CHANNEL_TP_Y);
    643 
    644 	/* X axis */
    645 	scpdr = _reg_read_1(SH7709_SCPDR);
    646 	scpdr |=  SCPDR_TP_SCAN_Y;
    647 	scpdr &= ~SCPDR_TP_SCAN_X; /* pull low to scan */
    648 	_reg_write_1(SH7709_SCPDR, scpdr);
    649 	delay(10);
    650 
    651 	*rawxp = adc_sample_channel(ADC_CHANNEL_TP_X);
    652 
    653 	/* restore SCPDR */
    654 	scpdr = _reg_read_1(SH7709_SCPDR);
    655 	scpdr |=  SCPDR_TP_SCAN_X;
    656 	scpdr &= ~SCPDR_TP_SCAN_ENABLE;
    657 	_reg_write_1(SH7709_SCPDR, scpdr);
    658 }
    659 
    660 
    661 /*
    662  * Check if the (rawx, rawy) is inside one of the 4 hard icons.
    663  * Return the icon number 1..4, or 0 if not inside an icon.
    664  */
    665 static int
    666 j6x0tp_get_hard_icon(int rawx, int rawy)
    667 {
    668 	if (rawx <= J6X0TP_FB_RIGHT)
    669 		return (0);
    670 
    671 	if (rawy < J6X0TP_HARD_ICON_MAX_Y(1))
    672 		return (1);
    673 	else if (rawy < J6X0TP_HARD_ICON_MAX_Y(2))
    674 		return (2);
    675 	else if (rawy < J6X0TP_HARD_ICON_MAX_Y(3))
    676 		return (3);
    677 	else
    678 		return (4);
    679 }
    680 
    681 
    682 static int
    683 j6x0tp_wsmouse_ioctl(void *self, u_long cmd, caddr_t data, int flag,
    684 		     struct proc *p)
    685 {
    686 	struct j6x0tp_softc *sc = (struct j6x0tp_softc *)self;
    687 
    688 	return hpc_tpanel_ioctl(&sc->sc_tpcalib, cmd, data, flag, p);
    689 }
    690 
    691 
    692 static int
    693 j6x0tp_wskbd_ioctl(void *self, u_long cmd, caddr_t data, int flag,
    694 		     struct proc *p)
    695 {
    696 	/* struct j6x0tp_softc *sc = (struct j6x0tp_softc *)self; */
    697 
    698 	switch (cmd) {
    699 	case WSKBDIO_GTYPE:
    700 		*(int *)data = WSKBD_TYPE_HPC_BTN; /* may be use new type? */
    701 		return (0);
    702 
    703 	case WSKBDIO_GETLEDS:
    704 		*(int *)data = 0;
    705 		return (0);
    706 
    707 	default:
    708 		return (EPASSTHROUGH);
    709 	}
    710 }
    711 
    712 
    713 static void
    714 j6x0tp_wskbd_set_leds(void *self, int leds)
    715 {
    716 
    717 	/* nothing to do*/
    718 	return;
    719 }
    720