1*7433666eSthorpej /* $NetBSD: j6x0tp.c,v 1.26 2023/12/20 14:50:02 thorpej Exp $ */
2e4bd58b0Suwe
3e4bd58b0Suwe /*
4e4bd58b0Suwe * Copyright (c) 2003 Valeriy E. Ushakov
5e4bd58b0Suwe * All rights reserved.
6e4bd58b0Suwe *
7e4bd58b0Suwe * Redistribution and use in source and binary forms, with or without
8e4bd58b0Suwe * modification, are permitted provided that the following conditions
9e4bd58b0Suwe * are met:
10e4bd58b0Suwe * 1. Redistributions of source code must retain the above copyright
11e4bd58b0Suwe * notice, this list of conditions and the following disclaimer.
12e4bd58b0Suwe * 2. Redistributions in binary form must reproduce the above copyright
13e4bd58b0Suwe * notice, this list of conditions and the following disclaimer in the
14e4bd58b0Suwe * documentation and/or other materials provided with the distribution.
15e4bd58b0Suwe * 3. The name of the author may not be used to endorse or promote products
16e4bd58b0Suwe * derived from this software without specific prior written permission
17e4bd58b0Suwe *
18e4bd58b0Suwe * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19e4bd58b0Suwe * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20e4bd58b0Suwe * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21e4bd58b0Suwe * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22e4bd58b0Suwe * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23e4bd58b0Suwe * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24e4bd58b0Suwe * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25e4bd58b0Suwe * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26e4bd58b0Suwe * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27e4bd58b0Suwe * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28e4bd58b0Suwe */
29e4bd58b0Suwe
30e4bd58b0Suwe #include <sys/cdefs.h>
31*7433666eSthorpej __KERNEL_RCSID(0, "$NetBSD: j6x0tp.c,v 1.26 2023/12/20 14:50:02 thorpej Exp $");
32e4bd58b0Suwe
33e4bd58b0Suwe #include <sys/param.h>
34e4bd58b0Suwe #include <sys/kernel.h>
35e4bd58b0Suwe #include <sys/device.h>
36e4bd58b0Suwe #include <sys/systm.h>
37e4bd58b0Suwe #include <sys/callout.h>
38e4bd58b0Suwe
390af2a039Suwe #include "opt_j6x0tp.h"
400af2a039Suwe
41e4bd58b0Suwe #include <dev/wscons/wsconsio.h>
42e4bd58b0Suwe #include <dev/wscons/wsmousevar.h>
430af2a039Suwe #include <dev/wscons/wskbdvar.h>
440af2a039Suwe #include <dev/wscons/wsksymvar.h>
450af2a039Suwe #include <dev/wscons/wsksymdef.h>
46f53a32e6Stsarna #include <dev/hpc/hpctpanelvar.h>
47e4bd58b0Suwe
48e4bd58b0Suwe #include <machine/platid.h>
49e4bd58b0Suwe #include <machine/platid_mask.h>
50e4bd58b0Suwe
51e4bd58b0Suwe #include <machine/intr.h>
52e4bd58b0Suwe
53e4bd58b0Suwe #include <sh3/exception.h>
54e4bd58b0Suwe #include <sh3/intcreg.h>
55e4bd58b0Suwe #include <sh3/pfcreg.h>
56e4bd58b0Suwe #include <sh3/adcreg.h>
57e4bd58b0Suwe
5849fd54d3Suwe #include <sh3/dev/adcvar.h>
5949fd54d3Suwe
6049fd54d3Suwe
61e4bd58b0Suwe #if 0 /* XXX: disabled in favor of local version that uses printf_nolog */
62e4bd58b0Suwe #define DPRINTF_ENABLE
63e4bd58b0Suwe #define DPRINTF_DEBUG j6x0tp_debug
64e4bd58b0Suwe #define DPRINTF_LEVEL 0
65e4bd58b0Suwe #include <machine/debug.h>
66e4bd58b0Suwe #else
67e4bd58b0Suwe #ifdef J6X0TP_DEBUG
68e4bd58b0Suwe volatile int j6x0tp_debug = 0;
690af2a039Suwe #define DPRINTF_PRINTF printf_nolog
700af2a039Suwe #define DPRINTF(arg) if (j6x0tp_debug) DPRINTF_PRINTF arg
710af2a039Suwe #define DPRINTFN(n, arg) if (j6x0tp_debug > (n)) DPRINTF_PRINTF arg
72e4bd58b0Suwe #else
73e4bd58b0Suwe #define DPRINTF(arg) ((void)0)
74e4bd58b0Suwe #define DPRINTFN(n, arg) ((void)0)
75e4bd58b0Suwe #endif
76e4bd58b0Suwe #endif
77e4bd58b0Suwe
78e4bd58b0Suwe
790af2a039Suwe /*
800af2a039Suwe * PFC bits pertinent to Jornada 6x0 touchpanel
810af2a039Suwe */
82e4bd58b0Suwe #define PHDR_TP_PEN_DOWN 0x08
83e4bd58b0Suwe
84e4bd58b0Suwe #define SCPDR_TP_SCAN_ENABLE 0x20
85e4bd58b0Suwe #define SCPDR_TP_SCAN_Y 0x02
86e4bd58b0Suwe #define SCPDR_TP_SCAN_X 0x01
87e4bd58b0Suwe
880af2a039Suwe /*
89758b6ed7Suwe * A/D converter channels to get x/y from
900af2a039Suwe */
91e4bd58b0Suwe #define ADC_CHANNEL_TP_Y 1
92e4bd58b0Suwe #define ADC_CHANNEL_TP_X 2
93e4bd58b0Suwe
940af2a039Suwe /*
950af2a039Suwe * Default (read: my device :) raw X/Y values for framebuffer edges.
960af2a039Suwe * XXX: defopt these?
970af2a039Suwe */
980af2a039Suwe #define J6X0TP_FB_LEFT 38
990af2a039Suwe #define J6X0TP_FB_RIGHT 950
1000af2a039Suwe #define J6X0TP_FB_TOP 80
1010af2a039Suwe #define J6X0TP_FB_BOTTOM 900
1020af2a039Suwe
1030af2a039Suwe /*
1040af2a039Suwe * Bottom of the n'th hard icon (n = 1..4)
1050af2a039Suwe */
1060af2a039Suwe #define J6X0TP_HARD_ICON_MAX_Y(n) \
1070af2a039Suwe (J6X0TP_FB_TOP + ((J6X0TP_FB_BOTTOM - J6X0TP_FB_TOP) / 4) * (n))
1080af2a039Suwe
109e4bd58b0Suwe
110e4bd58b0Suwe struct j6x0tp_softc {
111b5ba6eebSuwe device_t sc_dev;
112e4bd58b0Suwe
1130af2a039Suwe #define J6X0TP_WSMOUSE_ENABLED 0x01
1140af2a039Suwe #define J6X0TP_WSKBD_ENABLED 0x02
115e4bd58b0Suwe int sc_enabled;
116e4bd58b0Suwe
1170af2a039Suwe int sc_hard_icon;
1180af2a039Suwe
1190af2a039Suwe struct callout sc_touch_ch;
1200af2a039Suwe
121b5ba6eebSuwe device_t sc_wsmousedev;
122b5ba6eebSuwe device_t sc_wskbddev;
1230af2a039Suwe
1240af2a039Suwe struct tpcalib_softc sc_tpcalib; /* calibration info for wsmouse */
125e4bd58b0Suwe };
126e4bd58b0Suwe
1270af2a039Suwe
1280af2a039Suwe /* config machinery */
129b5ba6eebSuwe static int j6x0tp_match(device_t, cfdata_t, void *);
130b5ba6eebSuwe static void j6x0tp_attach(device_t, device_t, void *);
131e4bd58b0Suwe
1320af2a039Suwe /* wsmouse accessops */
1330af2a039Suwe static int j6x0tp_wsmouse_enable(void *);
134b5ba6eebSuwe static int j6x0tp_wsmouse_ioctl(void *, u_long, void *, int, lwp_t *);
1350af2a039Suwe static void j6x0tp_wsmouse_disable(void *);
136e4bd58b0Suwe
1370af2a039Suwe /* wskbd accessops */
1380af2a039Suwe static int j6x0tp_wskbd_enable(void *, int);
1390af2a039Suwe static void j6x0tp_wskbd_set_leds(void *, int);
140b5ba6eebSuwe static int j6x0tp_wskbd_ioctl(void *, u_long, void *, int, lwp_t *);
141e4bd58b0Suwe
1420af2a039Suwe /* internal driver routines */
1430af2a039Suwe static void j6x0tp_enable(struct j6x0tp_softc *);
1440af2a039Suwe static void j6x0tp_disable(struct j6x0tp_softc *);
1454a747421Suwe static int j6x0tp_enable_child(struct j6x0tp_softc *, int, int);
1460af2a039Suwe static int j6x0tp_intr(void *);
1470af2a039Suwe static void j6x0tp_start_polling(void *);
1480af2a039Suwe static void j6x0tp_stop_polling(struct j6x0tp_softc *);
1490af2a039Suwe static void j6x0tp_callout_wsmouse(void *);
1500af2a039Suwe static void j6x0tp_callout_wskbd(void *);
1510af2a039Suwe static void j6x0tp_wsmouse_input(struct j6x0tp_softc *, int, int);
1520af2a039Suwe static void j6x0tp_get_raw_xy(int *, int *);
1530af2a039Suwe static int j6x0tp_get_hard_icon(int, int);
1540af2a039Suwe
155e4bd58b0Suwe
156828f7077Suwe static const struct wsmouse_accessops j6x0tp_accessops = {
1570af2a039Suwe j6x0tp_wsmouse_enable,
1580af2a039Suwe j6x0tp_wsmouse_ioctl,
1590af2a039Suwe j6x0tp_wsmouse_disable
160e4bd58b0Suwe };
161e4bd58b0Suwe
162e4bd58b0Suwe static const struct wsmouse_calibcoords j6x0tp_default_calib = {
163e4bd58b0Suwe 0, 0, 639, 239,
164e4bd58b0Suwe 4,
1650af2a039Suwe {{ J6X0TP_FB_LEFT, J6X0TP_FB_TOP, 0, 0 },
1660af2a039Suwe { J6X0TP_FB_RIGHT, J6X0TP_FB_TOP, 639, 0 },
1670af2a039Suwe { J6X0TP_FB_LEFT, J6X0TP_FB_BOTTOM, 0, 239 },
1680af2a039Suwe { J6X0TP_FB_RIGHT, J6X0TP_FB_BOTTOM, 639, 239 }}
1690af2a039Suwe };
1700af2a039Suwe
171828f7077Suwe static const struct wskbd_accessops j6x0tp_wskbd_accessops = {
1720af2a039Suwe j6x0tp_wskbd_enable,
1730af2a039Suwe j6x0tp_wskbd_set_leds,
1740af2a039Suwe j6x0tp_wskbd_ioctl
175e4bd58b0Suwe };
176e4bd58b0Suwe
177e4bd58b0Suwe
1780af2a039Suwe #ifndef J6X0TP_SETTINGS_ICON_KEYSYM
1790af2a039Suwe #define J6X0TP_SETTINGS_ICON_KEYSYM KS_Home
1800af2a039Suwe #endif
1810af2a039Suwe #ifndef J6X0TP_PGUP_ICON_KEYSYM
1820af2a039Suwe #define J6X0TP_PGUP_ICON_KEYSYM KS_Prior
1830af2a039Suwe #endif
1840af2a039Suwe #ifndef J6X0TP_PGDN_ICON_KEYSYM
1850af2a039Suwe #define J6X0TP_PGDN_ICON_KEYSYM KS_Next
1860af2a039Suwe #endif
1870af2a039Suwe #ifndef J6X0TP_SWITCH_ICON_KEYSYM
1880af2a039Suwe #define J6X0TP_SWITCH_ICON_KEYSYM KS_End
1890af2a039Suwe #endif
1900af2a039Suwe
1910af2a039Suwe static const keysym_t j6x0tp_wskbd_keydesc[] = {
1920af2a039Suwe KS_KEYCODE(1), J6X0TP_SETTINGS_ICON_KEYSYM,
1930af2a039Suwe KS_KEYCODE(2), J6X0TP_PGUP_ICON_KEYSYM,
1940af2a039Suwe KS_KEYCODE(3), J6X0TP_PGDN_ICON_KEYSYM,
1950af2a039Suwe KS_KEYCODE(4), J6X0TP_SWITCH_ICON_KEYSYM
1960af2a039Suwe };
1970af2a039Suwe
198828f7077Suwe static const struct wscons_keydesc j6x0tp_wskbd_keydesctab[] = {
1990af2a039Suwe { KB_US, 0,
2000af2a039Suwe sizeof(j6x0tp_wskbd_keydesc)/sizeof(keysym_t),
2010af2a039Suwe j6x0tp_wskbd_keydesc
2020af2a039Suwe },
2030af2a039Suwe {0, 0, 0, 0}
2040af2a039Suwe };
2050af2a039Suwe
206828f7077Suwe static const struct wskbd_mapdata j6x0tp_wskbd_keymapdata = {
2070af2a039Suwe j6x0tp_wskbd_keydesctab, KB_US
2080af2a039Suwe };
2090af2a039Suwe
2100af2a039Suwe
211b5ba6eebSuwe CFATTACH_DECL_NEW(j6x0tp, sizeof(struct j6x0tp_softc),
2120af2a039Suwe j6x0tp_match, j6x0tp_attach, NULL, NULL);
213e4bd58b0Suwe
214e4bd58b0Suwe
215e4bd58b0Suwe static int
j6x0tp_match(device_t parent,cfdata_t cf,void * aux)216b5ba6eebSuwe j6x0tp_match(device_t parent, cfdata_t cf, void *aux)
217e4bd58b0Suwe {
218e4bd58b0Suwe
219e4bd58b0Suwe /*
220065e2422Suwe * XXX: platid_mask_MACH_HP_LX also matches 360LX. It's not
221065e2422Suwe * confirmed whether touch panel in 360LX is connected this
222065e2422Suwe * way. We may need to regroup platid masks.
223e4bd58b0Suwe */
224065e2422Suwe if (!platid_match(&platid, &platid_mask_MACH_HP_JORNADA_6XX)
225065e2422Suwe && !platid_match(&platid, &platid_mask_MACH_HP_LX))
226e4bd58b0Suwe return (0);
227e4bd58b0Suwe
2280af2a039Suwe if (strcmp(cf->cf_name, "j6x0tp") != 0)
229e4bd58b0Suwe return (0);
230e4bd58b0Suwe
231e4bd58b0Suwe return (1);
232e4bd58b0Suwe }
233e4bd58b0Suwe
234e4bd58b0Suwe
235e4bd58b0Suwe static void
j6x0tp_attach(device_t parent,device_t self,void * aux)236b5ba6eebSuwe j6x0tp_attach(device_t parent, device_t self, void *aux)
237e4bd58b0Suwe {
238b5ba6eebSuwe struct j6x0tp_softc *sc;
239e4bd58b0Suwe struct wsmousedev_attach_args wsma;
2400af2a039Suwe struct wskbddev_attach_args wska;
241e4bd58b0Suwe
242b5ba6eebSuwe aprint_naive("\n");
243b5ba6eebSuwe aprint_normal("\n");
244b5ba6eebSuwe
245b5ba6eebSuwe sc = device_private(self);
246b5ba6eebSuwe sc->sc_dev = self;
247e4bd58b0Suwe
248e4bd58b0Suwe sc->sc_enabled = 0;
2490af2a039Suwe sc->sc_hard_icon = 0;
250e4bd58b0Suwe
2510af2a039Suwe /* touch-panel as a pointing device */
252e4bd58b0Suwe wsma.accessops = &j6x0tp_accessops;
253e4bd58b0Suwe wsma.accesscookie = sc;
254e4bd58b0Suwe
2552685996bSthorpej sc->sc_wsmousedev = config_found(self, &wsma, wsmousedevprint,
256c7fb772bSthorpej CFARGS(.iattr = "wsmousedev"));
257e4bd58b0Suwe if (sc->sc_wsmousedev == NULL)
258e4bd58b0Suwe return;
259e4bd58b0Suwe
2600af2a039Suwe /* on-screen "hard icons" as a keyboard device */
2610af2a039Suwe wska.console = 0;
2620af2a039Suwe wska.keymap = &j6x0tp_wskbd_keymapdata;
2630af2a039Suwe wska.accessops = &j6x0tp_wskbd_accessops;
2640af2a039Suwe wska.accesscookie = sc;
2650af2a039Suwe
2662685996bSthorpej sc->sc_wskbddev = config_found(self, &wska, wskbddevprint,
267c7fb772bSthorpej CFARGS(.iattr = "wskbddev"));
2680af2a039Suwe
269758b6ed7Suwe /* init calibration, set default parameters */
270e4bd58b0Suwe tpcalib_init(&sc->sc_tpcalib);
271e4bd58b0Suwe tpcalib_ioctl(&sc->sc_tpcalib, WSMOUSEIO_SCALIBCOORDS,
27253524e44Schristos (void *)__UNCONST(&j6x0tp_default_calib), 0, 0);
273e4bd58b0Suwe
2740af2a039Suwe /* used when in polling mode */
2752af9604eSuwe callout_init(&sc->sc_touch_ch, 0);
276e4bd58b0Suwe
2770af2a039Suwe /* establish interrupt handler, but disable until opened */
278e4bd58b0Suwe intc_intr_establish(SH7709_INTEVT2_IRQ3, IST_EDGE, IPL_TTY,
279e4bd58b0Suwe j6x0tp_intr, sc);
2800af2a039Suwe intc_intr_disable(SH7709_INTEVT2_IRQ3);
281620a6f25Suwe
282620a6f25Suwe if (!pmf_device_register(self, NULL, NULL))
283620a6f25Suwe aprint_error_dev(self, "unable to establish power handler\n");
284e4bd58b0Suwe }
285e4bd58b0Suwe
286e4bd58b0Suwe
2870af2a039Suwe /*
2880af2a039Suwe * Enable touch panel: we start in interrupt mode.
2890af2a039Suwe * Must be called as spltty().
2900af2a039Suwe */
2910af2a039Suwe static void
j6x0tp_enable(struct j6x0tp_softc * sc)2920af2a039Suwe j6x0tp_enable(struct j6x0tp_softc *sc)
2930af2a039Suwe {
2940af2a039Suwe
295b5ba6eebSuwe DPRINTFN(2, ("%s: enable\n", device_xname(sc->sc_dev)));
2960af2a039Suwe intc_intr_enable(SH7709_INTEVT2_IRQ3);
2970af2a039Suwe }
2980af2a039Suwe
2990af2a039Suwe
3000af2a039Suwe /*
3010af2a039Suwe * Disable touch panel: disable interrupt, cancel pending callout.
3020af2a039Suwe * Must be called as spltty().
3030af2a039Suwe */
3040af2a039Suwe static void
j6x0tp_disable(struct j6x0tp_softc * sc)3050af2a039Suwe j6x0tp_disable(struct j6x0tp_softc *sc)
3060af2a039Suwe {
3070af2a039Suwe
308b5ba6eebSuwe DPRINTFN(2, ("%s: disable\n", device_xname(sc->sc_dev)));
3090af2a039Suwe intc_intr_disable(SH7709_INTEVT2_IRQ3);
3100af2a039Suwe callout_stop(&sc->sc_touch_ch);
3110af2a039Suwe }
3120af2a039Suwe
3130af2a039Suwe
3140af2a039Suwe static int
j6x0tp_enable_child(struct j6x0tp_softc * sc,int child,int on)3154a747421Suwe j6x0tp_enable_child(struct j6x0tp_softc *sc, int child, int on)
3160af2a039Suwe {
3170af2a039Suwe int s = spltty();
3180af2a039Suwe
3190af2a039Suwe if (on) {
3200af2a039Suwe if (!sc->sc_enabled)
3210af2a039Suwe j6x0tp_enable(sc);
3220af2a039Suwe sc->sc_enabled |= child;
3230af2a039Suwe } else {
3240af2a039Suwe sc->sc_enabled &= ~child;
3250af2a039Suwe if (!sc->sc_enabled)
3260af2a039Suwe j6x0tp_disable(sc);
3270af2a039Suwe }
328e4bd58b0Suwe
329e4bd58b0Suwe splx(s);
330e4bd58b0Suwe return (0);
331e4bd58b0Suwe }
332e4bd58b0Suwe
333e4bd58b0Suwe
3340af2a039Suwe static int
j6x0tp_wsmouse_enable(void * arg)335b5ba6eebSuwe j6x0tp_wsmouse_enable(void *arg)
336e4bd58b0Suwe {
337b5ba6eebSuwe struct j6x0tp_softc *sc = arg;
338e4bd58b0Suwe
339b5ba6eebSuwe DPRINTFN(1, ("%s: wsmouse enable\n", device_xname(sc->sc_dev)));
3404a747421Suwe return (j6x0tp_enable_child(sc, J6X0TP_WSMOUSE_ENABLED, 1));
3410af2a039Suwe }
342e4bd58b0Suwe
343e4bd58b0Suwe
3440af2a039Suwe static void
j6x0tp_wsmouse_disable(void * arg)345b5ba6eebSuwe j6x0tp_wsmouse_disable(void *arg)
3460af2a039Suwe {
347b5ba6eebSuwe struct j6x0tp_softc *sc = arg;
348e4bd58b0Suwe
349b5ba6eebSuwe DPRINTFN(1, ("%s: wsmouse disable\n", device_xname(sc->sc_dev)));
3504a747421Suwe j6x0tp_enable_child(sc, J6X0TP_WSMOUSE_ENABLED, 0);
3510af2a039Suwe }
3520af2a039Suwe
3530af2a039Suwe
3540af2a039Suwe static int
j6x0tp_wskbd_enable(void * arg,int on)355b5ba6eebSuwe j6x0tp_wskbd_enable(void *arg, int on)
3560af2a039Suwe {
357b5ba6eebSuwe struct j6x0tp_softc *sc = arg;
3580af2a039Suwe
359b5ba6eebSuwe DPRINTFN(1, ("%s: wskbd %sable\n", device_xname(sc->sc_dev),
3600af2a039Suwe on ? "en" : "dis"));
3614a747421Suwe return (j6x0tp_enable_child(sc, J6X0TP_WSKBD_ENABLED, on));
362e4bd58b0Suwe }
363e4bd58b0Suwe
364e4bd58b0Suwe
365e4bd58b0Suwe static int
j6x0tp_intr(void * arg)366b5ba6eebSuwe j6x0tp_intr(void *arg)
367e4bd58b0Suwe {
368b5ba6eebSuwe struct j6x0tp_softc *sc = arg;
369e4bd58b0Suwe
370e4bd58b0Suwe uint8_t irr0;
371e4bd58b0Suwe uint8_t phdr, touched;
372e4bd58b0Suwe unsigned int steady, tremor_timeout;
373e4bd58b0Suwe
374e4bd58b0Suwe irr0 = _reg_read_1(SH7709_IRR0);
375e4bd58b0Suwe if ((irr0 & IRR0_IRQ3) == 0) {
376e4bd58b0Suwe #ifdef DIAGNOSTIC
377b5ba6eebSuwe printf("%s: irr0 %02x?\n", device_xname(sc->sc_dev), irr0);
378e4bd58b0Suwe #endif
379e4bd58b0Suwe return (0);
380e4bd58b0Suwe }
381e4bd58b0Suwe
3820af2a039Suwe if (!sc->sc_enabled) {
383aa1315c6Suwe DPRINTFN(1, ("%s: intr: !sc_enabled\n",
384b5ba6eebSuwe device_xname(sc->sc_dev)));
3850af2a039Suwe intc_intr_disable(SH7709_INTEVT2_IRQ3);
3860af2a039Suwe goto served;
3870af2a039Suwe }
3880af2a039Suwe
3890af2a039Suwe
390e4bd58b0Suwe /*
391e4bd58b0Suwe * Number of times the "touched" bit should be read
392e4bd58b0Suwe * consecutively.
393e4bd58b0Suwe */
394e4bd58b0Suwe # define TREMOR_THRESHOLD 0x300
395e4bd58b0Suwe
396e4bd58b0Suwe steady = 0;
397e4bd58b0Suwe tremor_timeout = TREMOR_THRESHOLD * 16; /* XXX: arbitrary */
398e4bd58b0Suwe touched = PHDR_TP_PEN_DOWN; /* we start with "touched" state */
399e4bd58b0Suwe
400e4bd58b0Suwe do {
401e4bd58b0Suwe phdr = _reg_read_1(SH7709_PHDR);
402e4bd58b0Suwe
403e4bd58b0Suwe if ((phdr & PHDR_TP_PEN_DOWN) == touched)
404e4bd58b0Suwe ++steady;
405e4bd58b0Suwe else {
406e4bd58b0Suwe steady = 0;
407e4bd58b0Suwe touched = phdr & PHDR_TP_PEN_DOWN;
408e4bd58b0Suwe }
409e4bd58b0Suwe
410e4bd58b0Suwe if (--tremor_timeout == 0) {
411e4bd58b0Suwe DPRINTF(("%s: tremor timeout!\n",
412b5ba6eebSuwe device_xname(sc->sc_dev)));
413e4bd58b0Suwe goto served;
414e4bd58b0Suwe }
415e4bd58b0Suwe } while (steady < TREMOR_THRESHOLD);
416e4bd58b0Suwe
4170af2a039Suwe if (touched) {
418e4bd58b0Suwe intc_intr_disable(SH7709_INTEVT2_IRQ3);
419e4bd58b0Suwe
4200af2a039Suwe /*
4210af2a039Suwe * ADC readings are not stable yet, so schedule
4220af2a039Suwe * callout instead of accessing ADC from the interrupt
4230af2a039Suwe * handler only to immediately delay().
4240af2a039Suwe */
425e4bd58b0Suwe callout_reset(&sc->sc_touch_ch, hz/32,
4260af2a039Suwe j6x0tp_start_polling, sc);
4270af2a039Suwe } else
428b5ba6eebSuwe DPRINTFN(1, ("%s: tremor\n", device_xname(sc->sc_dev)));
429e4bd58b0Suwe served:
4300af2a039Suwe /* clear the interrupt (XXX: protect access?) */
431e4bd58b0Suwe _reg_write_1(SH7709_IRR0, irr0 & ~IRR0_IRQ3);
432e4bd58b0Suwe
433e4bd58b0Suwe return (1);
434e4bd58b0Suwe }
435e4bd58b0Suwe
436e4bd58b0Suwe
4370af2a039Suwe /*
4380af2a039Suwe * Called from the interrupt handler at spltty() upon first touch.
4390af2a039Suwe * Decide if we are going to report this touch as a mouse click/drag
4400af2a039Suwe * or as a key press.
4410af2a039Suwe */
442e4bd58b0Suwe static void
j6x0tp_start_polling(void * arg)443b5ba6eebSuwe j6x0tp_start_polling(void *arg)
444e4bd58b0Suwe {
445b5ba6eebSuwe struct j6x0tp_softc *sc = arg;
4460af2a039Suwe uint8_t phdr;
4470af2a039Suwe int do_mouse, do_kbd;
4480af2a039Suwe int rawx, rawy;
4490af2a039Suwe int icon;
4500af2a039Suwe
4510af2a039Suwe phdr = _reg_read_1(SH7709_PHDR);
4520af2a039Suwe if ((phdr & PHDR_TP_PEN_DOWN) == 0) {
4530af2a039Suwe DPRINTFN(2, ("%s: start: pen is not down\n",
454b5ba6eebSuwe device_xname(sc->sc_dev)));
4550af2a039Suwe j6x0tp_stop_polling(sc);
4560af2a039Suwe }
4570af2a039Suwe
4580af2a039Suwe j6x0tp_get_raw_xy(&rawx, &rawy);
4590af2a039Suwe DPRINTFN(2, ("%s: start: %4d %4d -> ",
460b5ba6eebSuwe device_xname(sc->sc_dev), rawx, rawy));
4610af2a039Suwe
4620af2a039Suwe do_mouse = sc->sc_enabled & J6X0TP_WSMOUSE_ENABLED;
4630af2a039Suwe #ifdef J6X0TP_WSMOUSE_EXCLUSIVE
4640af2a039Suwe if (do_mouse)
4650af2a039Suwe do_kbd = 0;
4660af2a039Suwe else
4670af2a039Suwe #endif
4680af2a039Suwe do_kbd = sc->sc_enabled & J6X0TP_WSKBD_ENABLED;
4690af2a039Suwe
4700af2a039Suwe icon = 0;
4710af2a039Suwe if (do_kbd)
4720af2a039Suwe icon = j6x0tp_get_hard_icon(rawx, rawy);
4730af2a039Suwe
4740af2a039Suwe if (icon != 0) {
4750af2a039Suwe DPRINTFN(2, ("icon %d\n", icon));
4760af2a039Suwe sc->sc_hard_icon = icon;
4770af2a039Suwe wskbd_input(sc->sc_wskbddev, WSCONS_EVENT_KEY_DOWN, icon);
4780af2a039Suwe callout_reset(&sc->sc_touch_ch, hz/32,
4790af2a039Suwe j6x0tp_callout_wskbd, sc);
4800af2a039Suwe } else if (do_mouse) {
4810af2a039Suwe DPRINTFN(2, ("mouse\n"));
4820af2a039Suwe j6x0tp_wsmouse_input(sc, rawx, rawy);
4830af2a039Suwe callout_reset(&sc->sc_touch_ch, hz/32,
4840af2a039Suwe j6x0tp_callout_wsmouse, sc);
4850af2a039Suwe } else {
4860af2a039Suwe DPRINTFN(2, ("ignore\n"));
4870af2a039Suwe j6x0tp_stop_polling(sc);
4880af2a039Suwe }
4890af2a039Suwe }
4900af2a039Suwe
4910af2a039Suwe
4920af2a039Suwe /*
4930af2a039Suwe * Re-enable touch panel interrupt.
4940af2a039Suwe * Called as spltty() when polling code detects pen-up.
4950af2a039Suwe */
4960af2a039Suwe static void
j6x0tp_stop_polling(struct j6x0tp_softc * sc)4970af2a039Suwe j6x0tp_stop_polling(struct j6x0tp_softc *sc)
4980af2a039Suwe {
499e4bd58b0Suwe uint8_t irr0;
5000af2a039Suwe
501b5ba6eebSuwe DPRINTFN(2, ("%s: stop\n", device_xname(sc->sc_dev)));
5020af2a039Suwe
5030af2a039Suwe /* clear pending interrupt signal before re-enabling the interrupt */
5040af2a039Suwe irr0 = _reg_read_1(SH7709_IRR0);
5050af2a039Suwe if ((irr0 & IRR0_IRQ3) != 0)
5060af2a039Suwe _reg_write_1(SH7709_IRR0, irr0 & ~IRR0_IRQ3);
5070af2a039Suwe
5080af2a039Suwe intc_intr_enable(SH7709_INTEVT2_IRQ3);
5090af2a039Suwe }
5100af2a039Suwe
5110af2a039Suwe
5120af2a039Suwe /*
5130af2a039Suwe * We are reporting this touch as a keyboard event.
5140af2a039Suwe * Poll touch screen waiting for pen-up.
5150af2a039Suwe */
5160af2a039Suwe static void
j6x0tp_callout_wskbd(void * arg)517b5ba6eebSuwe j6x0tp_callout_wskbd(void *arg)
5180af2a039Suwe {
519b5ba6eebSuwe struct j6x0tp_softc *sc = arg;
5200af2a039Suwe uint8_t phdr;
521e4bd58b0Suwe int s;
522e4bd58b0Suwe
523e4bd58b0Suwe s = spltty();
524e4bd58b0Suwe
525e4bd58b0Suwe if (!sc->sc_enabled) {
5260af2a039Suwe DPRINTFN(1, ("%s: wskbd callout: !sc_enabled\n",
527b5ba6eebSuwe device_xname(sc->sc_dev)));
528e4bd58b0Suwe splx(s);
529e4bd58b0Suwe return;
530e4bd58b0Suwe }
531e4bd58b0Suwe
532e4bd58b0Suwe phdr = _reg_read_1(SH7709_PHDR);
5330af2a039Suwe if ((phdr & PHDR_TP_PEN_DOWN) != 0) {
5340af2a039Suwe /*
5350af2a039Suwe * Pen is still down, continue polling. Wskbd's
5360af2a039Suwe * auto-repeat takes care of repeating the key.
5370af2a039Suwe */
5380af2a039Suwe callout_schedule(&sc->sc_touch_ch, hz/32);
5390af2a039Suwe } else {
5400af2a039Suwe wskbd_input(sc->sc_wskbddev,
5410af2a039Suwe WSCONS_EVENT_KEY_UP, sc->sc_hard_icon);
5420af2a039Suwe j6x0tp_stop_polling(sc);
5430af2a039Suwe }
5440af2a039Suwe splx(s);
5450af2a039Suwe }
546e4bd58b0Suwe
547e4bd58b0Suwe
5480af2a039Suwe /*
5490af2a039Suwe * We are reporting this touch as a mouse click/drag.
5500af2a039Suwe */
5510af2a039Suwe static void
j6x0tp_callout_wsmouse(void * arg)552b5ba6eebSuwe j6x0tp_callout_wsmouse(void *arg)
5530af2a039Suwe {
554b5ba6eebSuwe struct j6x0tp_softc *sc = arg;
5550af2a039Suwe uint8_t phdr;
5560af2a039Suwe int rawx, rawy;
5570af2a039Suwe int s;
558e4bd58b0Suwe
5590af2a039Suwe s = spltty();
5600af2a039Suwe
5610af2a039Suwe if (!sc->sc_enabled) {
5620af2a039Suwe DPRINTFN(1, ("%s: wsmouse callout: !sc_enabled\n",
563b5ba6eebSuwe device_xname(sc->sc_dev)));
564e4bd58b0Suwe splx(s);
565e4bd58b0Suwe return;
566e4bd58b0Suwe }
567e4bd58b0Suwe
5680af2a039Suwe phdr = _reg_read_1(SH7709_PHDR);
5690af2a039Suwe if ((phdr & PHDR_TP_PEN_DOWN) != 0) {
5700af2a039Suwe j6x0tp_get_raw_xy(&rawx, &rawy);
5710af2a039Suwe j6x0tp_wsmouse_input(sc, rawx, rawy); /* mouse dragged */
5720af2a039Suwe callout_schedule(&sc->sc_touch_ch, hz/32);
5730af2a039Suwe } else {
57457c0199dSplunky wsmouse_input(sc->sc_wsmousedev, 0, 0, 0, 0, 0, /* button up */
5750af2a039Suwe WSMOUSE_INPUT_DELTA);
5760af2a039Suwe j6x0tp_stop_polling(sc);
5770af2a039Suwe }
5780af2a039Suwe splx(s);
5790af2a039Suwe }
5800af2a039Suwe
5810af2a039Suwe
5820af2a039Suwe /*
5830af2a039Suwe * Report mouse click/drag.
5840af2a039Suwe */
5850af2a039Suwe static void
j6x0tp_wsmouse_input(struct j6x0tp_softc * sc,int rawx,int rawy)5860af2a039Suwe j6x0tp_wsmouse_input(struct j6x0tp_softc *sc, int rawx, int rawy)
5870af2a039Suwe {
5880af2a039Suwe int x, y;
5890af2a039Suwe
5900af2a039Suwe tpcalib_trans(&sc->sc_tpcalib, rawx, rawy, &x, &y);
5910af2a039Suwe
5920af2a039Suwe DPRINTFN(3, ("%s: %4d %4d -> %3d %3d\n",
593b5ba6eebSuwe device_xname(sc->sc_dev), rawx, rawy, x, y));
5940af2a039Suwe
5950af2a039Suwe wsmouse_input(sc->sc_wsmousedev,
5960af2a039Suwe 1, /* button */
59757c0199dSplunky x, y, 0, 0,
5980af2a039Suwe WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y);
5990af2a039Suwe }
6000af2a039Suwe
6010af2a039Suwe
6020af2a039Suwe /*
6030af2a039Suwe * Read raw X/Y coordinates from the ADC.
6040af2a039Suwe * XXX: protect accesses to SCPDR?
6050af2a039Suwe */
6060af2a039Suwe static void
j6x0tp_get_raw_xy(int * rawxp,int * rawyp)6070af2a039Suwe j6x0tp_get_raw_xy(int *rawxp, int *rawyp)
6080af2a039Suwe {
6090af2a039Suwe uint8_t scpdr;
610e4bd58b0Suwe
611e4bd58b0Suwe /* Y axis */
612e4bd58b0Suwe scpdr = _reg_read_1(SH7709_SCPDR);
613e4bd58b0Suwe scpdr |= SCPDR_TP_SCAN_ENABLE;
614e4bd58b0Suwe scpdr &= ~SCPDR_TP_SCAN_Y; /* pull low to scan */
615e4bd58b0Suwe _reg_write_1(SH7709_SCPDR, scpdr);
616e4bd58b0Suwe delay(10);
6170af2a039Suwe
6180af2a039Suwe *rawyp = adc_sample_channel(ADC_CHANNEL_TP_Y);
619e4bd58b0Suwe
620e4bd58b0Suwe /* X axis */
621e4bd58b0Suwe scpdr = _reg_read_1(SH7709_SCPDR);
622e4bd58b0Suwe scpdr |= SCPDR_TP_SCAN_Y;
623e4bd58b0Suwe scpdr &= ~SCPDR_TP_SCAN_X; /* pull low to scan */
624e4bd58b0Suwe _reg_write_1(SH7709_SCPDR, scpdr);
625e4bd58b0Suwe delay(10);
6260af2a039Suwe
6270af2a039Suwe *rawxp = adc_sample_channel(ADC_CHANNEL_TP_X);
628e4bd58b0Suwe
629e4bd58b0Suwe /* restore SCPDR */
630e4bd58b0Suwe scpdr = _reg_read_1(SH7709_SCPDR);
631e4bd58b0Suwe scpdr |= SCPDR_TP_SCAN_X;
632e4bd58b0Suwe scpdr &= ~SCPDR_TP_SCAN_ENABLE;
633e4bd58b0Suwe _reg_write_1(SH7709_SCPDR, scpdr);
6340af2a039Suwe }
635e4bd58b0Suwe
636e4bd58b0Suwe
6370af2a039Suwe /*
6380af2a039Suwe * Check if the (rawx, rawy) is inside one of the 4 hard icons.
6390af2a039Suwe * Return the icon number 1..4, or 0 if not inside an icon.
6400af2a039Suwe */
6410af2a039Suwe static int
j6x0tp_get_hard_icon(int rawx,int rawy)6420af2a039Suwe j6x0tp_get_hard_icon(int rawx, int rawy)
6430af2a039Suwe {
6440af2a039Suwe if (rawx <= J6X0TP_FB_RIGHT)
6450af2a039Suwe return (0);
646e4bd58b0Suwe
6470af2a039Suwe if (rawy < J6X0TP_HARD_ICON_MAX_Y(1))
6480af2a039Suwe return (1);
6490af2a039Suwe else if (rawy < J6X0TP_HARD_ICON_MAX_Y(2))
6500af2a039Suwe return (2);
6510af2a039Suwe else if (rawy < J6X0TP_HARD_ICON_MAX_Y(3))
6520af2a039Suwe return (3);
6530af2a039Suwe else
6540af2a039Suwe return (4);
655e4bd58b0Suwe }
656e4bd58b0Suwe
657e4bd58b0Suwe
658e4bd58b0Suwe static int
j6x0tp_wsmouse_ioctl(void * arg,u_long cmd,void * data,int flag,lwp_t * l)659b5ba6eebSuwe j6x0tp_wsmouse_ioctl(void *arg, u_long cmd, void *data, int flag, lwp_t *l)
660e4bd58b0Suwe {
661b5ba6eebSuwe struct j6x0tp_softc *sc = arg;
662e4bd58b0Suwe
66395e1ffb1Schristos return hpc_tpanel_ioctl(&sc->sc_tpcalib, cmd, data, flag, l);
664e4bd58b0Suwe }
6650af2a039Suwe
6660af2a039Suwe
6670af2a039Suwe static int
j6x0tp_wskbd_ioctl(void * arg,u_long cmd,void * data,int flag,lwp_t * l)668b5ba6eebSuwe j6x0tp_wskbd_ioctl(void *arg, u_long cmd, void *data, int flag, lwp_t *l)
6690af2a039Suwe {
670b5ba6eebSuwe /* struct j6x0tp_softc *sc = arg; */
6710af2a039Suwe
6720af2a039Suwe switch (cmd) {
6730af2a039Suwe case WSKBDIO_GTYPE:
6740af2a039Suwe *(int *)data = WSKBD_TYPE_HPC_BTN; /* may be use new type? */
6750af2a039Suwe return (0);
6760af2a039Suwe
6770af2a039Suwe case WSKBDIO_GETLEDS:
6780af2a039Suwe *(int *)data = 0;
6790af2a039Suwe return (0);
6800af2a039Suwe
6810af2a039Suwe default:
6820af2a039Suwe return (EPASSTHROUGH);
6830af2a039Suwe }
6840af2a039Suwe }
6850af2a039Suwe
6860af2a039Suwe
6870af2a039Suwe static void
j6x0tp_wskbd_set_leds(void * arg,int leds)688b5ba6eebSuwe j6x0tp_wskbd_set_leds(void *arg, int leds)
6890af2a039Suwe {
6900af2a039Suwe
6910af2a039Suwe /* nothing to do*/
6920af2a039Suwe return;
6930af2a039Suwe }
694