Subject: merged touch-panel driver
To: None <uwe@ptc.spbu.ru>
From: KIYOHARA Takashi <kiyohara@kk.iij4u.or.jp>
List: port-hpcsh
Date: 07/04/2005 02:40:10
----Next_Part(Mon_Jul__4_02:40:10_2005_142)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Hi, uwe.
I merged drivers of the touch-panel of j6x0 and psh3.
BTW,
PERSONA is using DADR0 by play, and using AD4 by record.
I have not written the driver of audio yet. ;-< Do you write driver?
--
kiyohara
----Next_Part(Mon_Jul__4_02:40:10_2005_142)--
Content-Type: Text/Plain; charset=us-ascii
Content-Transfer-Encoding: 7bit
Content-Disposition: inline; filename="pfctp.c"
/* $NetBSD$ */
/*
* Copyright (c) 2005 KIYOHARA Takashi
* All rights reserved.
*/
/*
* Copyright (c) 2003 Valeriy E. Ushakov
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD$");
#include <sys/param.h>
#include <sys/kernel.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/systm.h>
#include <sys/callout.h>
#ifdef GPROF
#include <sys/gmon.h>
#endif
#include "opt_pfctp.h"
#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsmousevar.h>
#include <dev/wscons/wskbdvar.h>
#include <dev/wscons/wsksymvar.h>
#include <dev/wscons/wsksymdef.h>
#include <dev/hpc/hpctpanelvar.h>
#include <machine/platid.h>
#include <machine/platid_mask.h>
#include <machine/intr.h>
#include <sh3/exception.h>
#include <sh3/intcreg.h>
#include <sh3/pfcreg.h>
#include <sh3/adcreg.h>
#include <sh3/dev/adcvar.h>
#define PFCTP_DEBUG
#if 0 /* XXX: disabled in favor of local version that uses printf_nolog */
#define DPRINTF_ENABLE
#define DPRINTF_DEBUG pfctp_debug
#define DPRINTF_LEVEL 0
#include <machine/debug.h>
#else
#ifdef PFCTP_DEBUG
volatile int pfctp_debug = 0;
#define DPRINTF_PRINTF printf_nolog
#define DPRINTF(arg) if (pfctp_debug) DPRINTF_PRINTF arg
#define DPRINTFN(n, arg) if (pfctp_debug > (n)) DPRINTF_PRINTF arg
#else
#define DPRINTF(arg) ((void)0)
#define DPRINTFN(n, arg) ((void)0)
#endif
#endif
/*
* PFC bits pertinent to Jornada 6x0 and PERSONA SH3 machines touchpanel
*/
#define PFCTP_J6X0_PEN_DOWN 0x08
#define PFCTP_J6X0_SCAN_ENABLE 0x20
#define PFCTP_J6X0_SCAN_Y 0x02
#define PFCTP_J6X0_SCAN_X 0x01
#define PFCTP_PSH3_PEN_UP 0x40
#define PFCTP_PSH3_SCAN_ENABLE 0x20
#define PFCTP_PSH3_SCAN_DISABLE 0x01
#define PFCTP_PSH3_SCAN_X 0x06
#define PFCTP_PSH3_SCAN_Y 0x09
/*
* A/D converter channels to get x/y from
*/
#define PFCTP_J6X0_ADC_CHANNEL_TP_Y 1
#define PFCTP_J6X0_ADC_CHANNEL_TP_X 2
#define PFCTP_PSH3_ADC_CHANNEL_TP_Y 0
#define PFCTP_PSH3_ADC_CHANNEL_TP_X 1
/*
* Default (read: my device :) raw X/Y values for framebuffer edges.
* XXX: defopt these?
*/
#define PFCTP_J6X0_FB_LEFT 38
#define PFCTP_J6X0_FB_RIGHT 950
#define PFCTP_J6X0_FB_TOP 80
#define PFCTP_J6X0_FB_BOTTOM 900
#define PFCTP_PSH3_FB_RIGHT 56
#define PFCTP_PSH3_FB_LEFT 969
#define PFCTP_PSH3_FB_TOP 848
#define PFCTP_PSH3_FB_BOTTOM 121
/*
* Bottom of the n'th hard icon (n = 1..4)
*/
#define PFCTP_J6X0_HARD_ICON_MAX_Y(n) \
(PFCTP_J6X0_FB_TOP + \
((PFCTP_J6X0_FB_BOTTOM - PFCTP_J6X0_FB_TOP) / 4) * (n))
struct pfctp_softc {
struct device sc_dev;
#define PFCTP_WSMOUSE_ENABLED 0x01
#define PFCTP_WSKBD_ENABLED 0x02
int sc_enabled;
int sc_hard_icon;
struct callout sc_touch_ch;
struct device *sc_wsmousedev;
struct device *sc_wskbddev;
struct tpcalib_softc sc_tpcalib; /* calibration info for wsmouse */
int sc_irq;
int sc_intevt;
struct wsmouse_calibcoords *sc_default_calib;
struct wskbd_mapdata *sc_wskbd_keymap;
int (*sc_get_stat)(void);
int (*sc_get_touched)(struct pfctp_softc *, int *);
void (*sc_get_raw_xy)(int *, int *);
int (*sc_get_hard_icon)(int, int);
};
/* config machinery */
static int pfctp_match(struct device *, struct cfdata *, void *);
static void pfctp_attach(struct device *, struct device *, void *);
static int pfctp_wsmouse_submatch(struct device *, struct cfdata *,
void *);
static int pfctp_wskbd_submatch(struct device *, struct cfdata *, void *);
/* wsmouse accessops */
static int pfctp_wsmouse_enable(void *);
static int pfctp_wsmouse_ioctl(void *, u_long, caddr_t, int,
struct proc *);
static void pfctp_wsmouse_disable(void *);
/* wskbd accessops */
static int pfctp_wskbd_enable(void *, int);
static void pfctp_wskbd_set_leds(void *, int);
static int pfctp_wskbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
/* internal driver routines */
static void pfctp_enable(struct pfctp_softc *);
static void pfctp_disable(struct pfctp_softc *);
static int pfctp_set_enable(struct pfctp_softc *, int, int);
static int pfctp_intr(void *);
static void pfctp_start_polling(void *);
static void pfctp_stop_polling(struct pfctp_softc *);
static void pfctp_callout_wsmouse(void *);
static void pfctp_callout_wskbd(void *);
static void pfctp_wsmouse_input(struct pfctp_softc *, int, int);
/* platid independent routines */
static int pfctp_j6x0_get_stat(void);
static int pfctp_j6x0_get_touched(struct pfctp_softc *, int *);
static void pfctp_j6x0_get_raw_xy(int *, int *);
static int pfctp_j6x0_get_hard_icon(int, int);
static int pfctp_psh3_get_stat(void);
static int pfctp_psh3_get_touched(struct pfctp_softc *, int *);
static void pfctp_psh3_get_raw_xy(int *, int *);
static const struct wsmouse_accessops pfctp_accessops = {
pfctp_wsmouse_enable,
pfctp_wsmouse_ioctl,
pfctp_wsmouse_disable
};
static const struct wskbd_accessops pfctp_wskbd_accessops = {
pfctp_wskbd_enable,
pfctp_wskbd_set_leds,
pfctp_wskbd_ioctl
};
static const struct wsmouse_calibcoords pfctp_j6x0_default_calib = {
0, 0, 639, 239,
4,
{{ PFCTP_J6X0_FB_LEFT, PFCTP_J6X0_FB_TOP, 0, 0 },
{ PFCTP_J6X0_FB_RIGHT, PFCTP_J6X0_FB_TOP, 639, 0 },
{ PFCTP_J6X0_FB_LEFT, PFCTP_J6X0_FB_BOTTOM, 0, 239 },
{ PFCTP_J6X0_FB_RIGHT, PFCTP_J6X0_FB_BOTTOM, 639, 239 }}
};
static const struct wsmouse_calibcoords pfctp_psh3_default_calib = {
0, 0, 639, 239,
4,
{{ PFCTP_PSH3_FB_LEFT, PFCTP_PSH3_FB_TOP, 0, 0 },
{ PFCTP_PSH3_FB_RIGHT, PFCTP_PSH3_FB_TOP, 639, 0 },
{ PFCTP_PSH3_FB_LEFT, PFCTP_PSH3_FB_BOTTOM, 0, 239 },
{ PFCTP_PSH3_FB_RIGHT, PFCTP_PSH3_FB_BOTTOM, 639, 239 }}
};
#ifndef PFCTP_J6X0_SETTINGS_ICON_KEYSYM
#define PFCTP_J6X0_SETTINGS_ICON_KEYSYM KS_Home
#endif
#ifndef PFCTP_J6X0_PGUP_ICON_KEYSYM
#define PFCTP_J6X0_PGUP_ICON_KEYSYM KS_Prior
#endif
#ifndef PFCTP_J6X0_PGDN_ICON_KEYSYM
#define PFCTP_J6X0_PGDN_ICON_KEYSYM KS_Next
#endif
#ifndef PFCTP_J6X0_SWITCH_ICON_KEYSYM
#define PFCTP_J6X0_SWITCH_ICON_KEYSYM KS_End
#endif
static const keysym_t pfctp_j6x0_wskbd_keydesc[] = {
KS_KEYCODE(1), PFCTP_J6X0_SETTINGS_ICON_KEYSYM,
KS_KEYCODE(2), PFCTP_J6X0_PGUP_ICON_KEYSYM,
KS_KEYCODE(3), PFCTP_J6X0_PGDN_ICON_KEYSYM,
KS_KEYCODE(4), PFCTP_J6X0_SWITCH_ICON_KEYSYM
};
static const struct wscons_keydesc pfctp_j6x0_wskbd_keydesctab[] = {
{ KB_US, 0,
sizeof(pfctp_j6x0_wskbd_keydesc)/sizeof(keysym_t),
pfctp_j6x0_wskbd_keydesc
},
{0, 0, 0, 0}
};
static const struct wskbd_mapdata pfctp_j6x0_wskbd_keymapdata = {
pfctp_j6x0_wskbd_keydesctab, KB_US
};
/* pfctp any values table. this values is platfrom specific. */
static const struct {
platid_mask_t *platform;
int irq;
int intevt;
struct wsmouse_calibcoords *default_calib;
struct wskbd_mapdata *wskbd_keymap;
int (*get_stat)(void);
int (*get_touched)(struct pfctp_softc *, int *);
void (*get_raw_xy)(int *, int *);
int (*get_hard_icon)(int, int);
} pfctp_values_table[] = {
{ &platid_mask_MACH_HP_JORNADA_6XX,
IRR0_IRQ3, SH7709_INTEVT2_IRQ3,
__UNCONST(&pfctp_j6x0_default_calib),
__UNCONST(&pfctp_j6x0_wskbd_keymapdata),
pfctp_j6x0_get_stat, pfctp_j6x0_get_touched,
pfctp_j6x0_get_raw_xy, pfctp_j6x0_get_hard_icon },
{ &platid_mask_MACH_HITACHI_PERSONA,
IRR0_IRQ2, SH7709_INTEVT2_IRQ2,
__UNCONST(&pfctp_psh3_default_calib),
NULL,
pfctp_psh3_get_stat, pfctp_psh3_get_touched,
pfctp_psh3_get_raw_xy, NULL }
};
CFATTACH_DECL(pfctp, sizeof(struct pfctp_softc),
pfctp_match, pfctp_attach, NULL, NULL);
static int
pfctp_match(struct device *parent, struct cfdata *cf, void *aux)
{
int i, n = sizeof(pfctp_values_table) / sizeof(pfctp_values_table[0]);
/*
* XXX: does platid_mask_MACH_HP_LX matches _JORNADA_6XX too?
* Is 620 wired similarly?
*/
for (i = 0; i < n; i++)
if (platid_match(&platid, pfctp_values_table[i].platform))
break;
if (i == n)
return (0);
if (strcmp(cf->cf_name, "pfctp") != 0)
return (0);
return (1);
}
/*
* Attach the touch panel driver and its ws* children.
*
* Note that we have to use submatch to distinguish between children
* because ws{kbd,mouse}_match match unconditionally.
*/
static void
pfctp_attach(struct device *parent, struct device *self, void *aux)
{
struct pfctp_softc *sc = (struct pfctp_softc *)self;
struct wsmousedev_attach_args wsma;
struct wskbddev_attach_args wska;
int i, n = sizeof(pfctp_values_table) / sizeof(pfctp_values_table[0]);
for (i = 0; i < n; i++)
if (platid_match(&platid, pfctp_values_table[i].platform))
break;
printf("\n");
sc->sc_enabled = 0;
sc->sc_hard_icon = 0;
sc->sc_irq = pfctp_values_table[i].irq;
sc->sc_intevt = pfctp_values_table[i].intevt;
sc->sc_default_calib = pfctp_values_table[i].default_calib;
sc->sc_wskbd_keymap = pfctp_values_table[i].wskbd_keymap;
sc->sc_get_stat = pfctp_values_table[i].get_stat;
sc->sc_get_touched = pfctp_values_table[i].get_touched;
sc->sc_get_raw_xy = pfctp_values_table[i].get_raw_xy;
sc->sc_get_hard_icon = pfctp_values_table[i].get_hard_icon;
/* touch-panel as a pointing device */
wsma.accessops = &pfctp_accessops;
wsma.accesscookie = sc;
sc->sc_wsmousedev = config_found_sm(
self, &wsma, wsmousedevprint, pfctp_wsmouse_submatch);
if (sc->sc_wsmousedev == NULL)
return;
if (sc->sc_wskbd_keymap != NULL) {
/* on-screen "hard icons" as a keyboard device */
wska.console = 0;
wska.keymap = sc->sc_wskbd_keymap;
wska.accessops = &pfctp_wskbd_accessops;
wska.accesscookie = sc;
sc->sc_wskbddev = config_found_sm(
self, &wska, wskbddevprint, pfctp_wskbd_submatch);
}
/* init calibration, set default parameters */
tpcalib_init(&sc->sc_tpcalib);
tpcalib_ioctl(&sc->sc_tpcalib, WSMOUSEIO_SCALIBCOORDS,
(caddr_t)__UNCONST(sc->sc_default_calib), 0, 0);
/* used when in polling mode */
callout_init(&sc->sc_touch_ch);
/* establish interrupt handler, but disable until opened */
intc_intr_establish(
sc->sc_intevt, IST_EDGE, IPL_TTY, pfctp_intr, sc);
intc_intr_disable(sc->sc_intevt);
}
static int
pfctp_wsmouse_submatch(struct device *parent, struct cfdata *cf, void *aux)
{
return (!strcmp(cf->cf_name, "wsmouse"));
}
static int
pfctp_wskbd_submatch(struct device *parent, struct cfdata *cf, void *aux)
{
return (!strcmp(cf->cf_name, "wskbd"));
}
/*
* Enable touch panel: we start in interrupt mode.
* Must be called at spltty().
*/
static void
pfctp_enable(struct pfctp_softc *sc)
{
DPRINTFN(2, ("%s: enable\n", sc->sc_dev.dv_xname));
intc_intr_enable(sc->sc_intevt);
}
/*
* Disable touch panel: disable interrupt, cancel pending callout.
* Must be called at spltty().
*/
static void
pfctp_disable(struct pfctp_softc *sc)
{
DPRINTFN(2, ("%s: disable\n", sc->sc_dev.dv_xname));
intc_intr_disable(sc->sc_intevt);
callout_stop(&sc->sc_touch_ch);
}
static int
pfctp_set_enable(struct pfctp_softc *sc, int on, int child)
{
int s = spltty();
if (on) {
if (!sc->sc_enabled)
pfctp_enable(sc);
sc->sc_enabled |= child;
} else {
sc->sc_enabled &= ~child;
if (!sc->sc_enabled)
pfctp_disable(sc);
}
splx(s);
return (0);
}
static int
pfctp_wsmouse_enable(void *self)
{
struct pfctp_softc *sc = (struct pfctp_softc *)self;
DPRINTFN(1, ("%s: wsmouse enable\n", sc->sc_dev.dv_xname));
return (pfctp_set_enable(sc, 1, PFCTP_WSMOUSE_ENABLED));
}
static void
pfctp_wsmouse_disable(void *self)
{
struct pfctp_softc *sc = (struct pfctp_softc *)self;
DPRINTFN(1, ("%s: wsmouse disable\n", sc->sc_dev.dv_xname));
pfctp_set_enable(sc, 0, PFCTP_WSMOUSE_ENABLED);
}
static int
pfctp_wskbd_enable(void *self, int on)
{
struct pfctp_softc *sc = (struct pfctp_softc *)self;
DPRINTFN(1, ("%s: wskbd %sable\n",
sc->sc_dev.dv_xname, on ? "en" : "dis"));
return (pfctp_set_enable(sc, on, PFCTP_WSKBD_ENABLED));
}
static int
pfctp_intr(void *self)
{
struct pfctp_softc *sc = (struct pfctp_softc *)self;
int touched, sflag = 0;
uint8_t irr0;
irr0 = _reg_read_1(SH7709_IRR0);
if ((irr0 & sc->sc_irq) == 0) {
#ifdef DIAGNOSTIC
printf("%s: irr0 %02x?\n", sc->sc_dev.dv_xname, irr0);
#endif
return (0);
}
if (!sc->sc_enabled) {
DPRINTFN(1, ("%s: intr: !sc_enabled\n", sc->sc_dev.dv_xname));
intc_intr_disable(sc->sc_intevt);
goto served;
}
touched = sc->sc_get_touched(sc, &sflag);
if (sflag)
goto served;
if (touched) {
intc_intr_disable(sc->sc_intevt);
/*
* ADC readings are not stable yet, so schedule
* callout instead of accessing ADC from the interrupt
* handler only to immediately delay().
*/
callout_reset(&sc->sc_touch_ch, hz/32, pfctp_start_polling, sc);
} else
DPRINTFN(1, ("%s: tremor\n", sc->sc_dev.dv_xname));
served:
/* clear the interrupt (XXX: protect access?) */
_reg_write_1(SH7709_IRR0, irr0 & ~sc->sc_irq);
return (1);
}
/*
* Called from the interrupt handler at spltty() upon first touch.
* Decide if we are going to report this touch as a mouse click/drag
* or as a key press.
*/
static void
pfctp_start_polling(void *self)
{
struct pfctp_softc *sc = (struct pfctp_softc *)self;
int do_mouse, do_kbd;
int rawx, rawy;
int icon = 0;
if (!sc->sc_get_stat()) {
DPRINTFN(2, ("%s: start: pen is not down\n",
sc->sc_dev.dv_xname));
pfctp_stop_polling(sc);
}
sc->sc_get_raw_xy(&rawx, &rawy);
DPRINTFN(2, ("%s: start: %4d %4d -> ",
sc->sc_dev.dv_xname, rawx, rawy));
do_mouse = sc->sc_enabled & PFCTP_WSMOUSE_ENABLED;
if (sc->sc_wskbd_keymap == NULL) {
#ifdef PFCTP_WSMOUSE_EXCLUSIVE
if (do_mouse)
do_kbd = 0;
else
#endif
do_kbd = sc->sc_enabled & PFCTP_WSKBD_ENABLED;
if (do_kbd)
icon = sc->sc_get_hard_icon(rawx, rawy);
}
if (icon != 0) {
DPRINTFN(2, ("icon %d\n", icon));
sc->sc_hard_icon = icon;
wskbd_input(sc->sc_wskbddev, WSCONS_EVENT_KEY_DOWN, icon);
callout_reset(&sc->sc_touch_ch, hz/32, pfctp_callout_wskbd, sc);
} else if (do_mouse) {
DPRINTFN(2, ("mouse\n"));
pfctp_wsmouse_input(sc, rawx, rawy);
callout_reset(&sc->sc_touch_ch,
hz/32, pfctp_callout_wsmouse, sc);
} else {
DPRINTFN(2, ("ignore\n"));
pfctp_stop_polling(sc);
}
}
/*
* Re-enable touch panel interrupt.
* Called at spltty() when polling code detects pen-up.
*/
static void
pfctp_stop_polling(struct pfctp_softc *sc)
{
uint8_t irr0;
DPRINTFN(2, ("%s: stop\n", sc->sc_dev.dv_xname));
/* clear pending interrupt signal before re-enabling the interrupt */
irr0 = _reg_read_1(SH7709_IRR0);
if ((irr0 & sc->sc_irq) != 0)
_reg_write_1(SH7709_IRR0, irr0 & ~sc->sc_irq);
intc_intr_enable(sc->sc_intevt);
}
/*
* We are reporting this touch as a keyboard event.
* Poll touch screen waiting for pen-up.
*/
static void
pfctp_callout_wskbd(void *self)
{
struct pfctp_softc *sc = (struct pfctp_softc *)self;
int s;
s = spltty();
if (!sc->sc_enabled) {
DPRINTFN(1, ("%s: wskbd callout: !sc_enabled\n",
sc->sc_dev.dv_xname));
splx(s);
return;
}
if (sc->sc_get_stat()) {
/*
* Pen is still down, continue polling. Wskbd's
* auto-repeat takes care of repeating the key.
*/
callout_schedule(&sc->sc_touch_ch, hz/32);
} else {
wskbd_input(sc->sc_wskbddev,
WSCONS_EVENT_KEY_UP, sc->sc_hard_icon);
pfctp_stop_polling(sc);
}
splx(s);
}
/*
* We are reporting this touch as a mouse click/drag.
*/
static void
pfctp_callout_wsmouse(void *self)
{
struct pfctp_softc *sc = (struct pfctp_softc *)self;
int rawx, rawy;
int s;
s = spltty();
if (!sc->sc_enabled) {
DPRINTFN(1, ("%s: wsmouse callout: !sc_enabled\n",
sc->sc_dev.dv_xname));
splx(s);
return;
}
if (sc->sc_get_stat()) {
sc->sc_get_raw_xy(&rawx, &rawy);
pfctp_wsmouse_input(sc, rawx, rawy); /* mouse dragged */
callout_schedule(&sc->sc_touch_ch, hz/32);
} else {
wsmouse_input(/* button up */
sc->sc_wsmousedev, 0, 0, 0, 0, WSMOUSE_INPUT_DELTA);
pfctp_stop_polling(sc);
}
splx(s);
}
/*
* Report mouse click/drag.
*/
static void
pfctp_wsmouse_input(struct pfctp_softc *sc, int rawx, int rawy)
{
int x, y;
tpcalib_trans(&sc->sc_tpcalib, rawx, rawy, &x, &y);
DPRINTFN(3, ("%s: %4d %4d -> %3d %3d\n",
sc->sc_dev.dv_xname, rawx, rawy, x, y));
wsmouse_input(sc->sc_wsmousedev,
1, /* button */
x, y,
0, /* flags */
WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y);
}
static int
pfctp_wsmouse_ioctl(void *self, u_long cmd, caddr_t data, int flag,
struct proc *p)
{
struct pfctp_softc *sc = (struct pfctp_softc *)self;
return hpc_tpanel_ioctl(&sc->sc_tpcalib, cmd, data, flag, p);
}
static int
pfctp_wskbd_ioctl(void *self, u_long cmd, caddr_t data, int flag,
struct proc *p)
{
/* struct pfcp_softc *sc = (struct pfctp_softc *)self; */
switch (cmd) {
case WSKBDIO_GTYPE:
*(int *)data = WSKBD_TYPE_HPC_BTN; /* may be use new type? */
return (0);
case WSKBDIO_GETLEDS:
*(int *)data = 0;
return (0);
default:
return (EPASSTHROUGH);
}
}
static void
pfctp_wskbd_set_leds(void *self, int leds)
{
/* nothing to do*/
return;
}
/*
* platid independent routines.
*/
/*
* Jornada 6x0 routines.
*/
static int
pfctp_j6x0_get_stat()
{
uint8_t phdr;
phdr = _reg_read_1(SH7709_PHDR);
return(phdr & PFCTP_J6X0_PEN_DOWN);
}
static int
pfctp_j6x0_get_touched(struct pfctp_softc *sc, int *served)
{
uint8_t phdr, touched;
unsigned int steady, tremor_timeout;
/*
* Number of times the "touched" bit should be read
* consecutively.
*/
#define J6X0_TREMOR_THRESHOLD 0x300
steady = 0;
tremor_timeout = J6X0_TREMOR_THRESHOLD * 16; /* XXX: arbitrary */
touched = PFCTP_J6X0_PEN_DOWN;/* we start with "touched" state */
do {
phdr = _reg_read_1(SH7709_PHDR);
if ((phdr & PFCTP_J6X0_PEN_DOWN) == touched)
++steady;
else {
steady = 0;
touched = phdr & PFCTP_J6X0_PEN_DOWN;
}
if (--tremor_timeout == 0) {
DPRINTF(("%s: tremor timeout!\n", sc->sc_dev.dv_xname));
*served = 1;
return (0);
}
} while (steady < J6X0_TREMOR_THRESHOLD);
return (touched);
}
/*
* Read raw X/Y coordinates from the ADC.
* XXX: protect accesses to SCPDR?
*/
static void
pfctp_j6x0_get_raw_xy(int *rawxp, int *rawyp)
{
uint8_t scpdr;
/* Y axis */
scpdr = _reg_read_1(SH7709_SCPDR);
scpdr |= PFCTP_J6X0_SCAN_ENABLE;
scpdr &= ~PFCTP_J6X0_SCAN_Y; /* pull low to scan */
_reg_write_1(SH7709_SCPDR, scpdr);
delay(10);
*rawyp = adc_sample_channel(PFCTP_J6X0_ADC_CHANNEL_TP_Y);
/* X axis */
scpdr = _reg_read_1(SH7709_SCPDR);
scpdr |= PFCTP_J6X0_SCAN_Y;
scpdr &= ~PFCTP_J6X0_SCAN_X; /* pull low to scan */
_reg_write_1(SH7709_SCPDR, scpdr);
delay(10);
*rawxp = adc_sample_channel(PFCTP_J6X0_ADC_CHANNEL_TP_X);
/* restore SCPDR */
scpdr = _reg_read_1(SH7709_SCPDR);
scpdr |= PFCTP_J6X0_SCAN_X;
scpdr &= ~PFCTP_J6X0_SCAN_ENABLE;
_reg_write_1(SH7709_SCPDR, scpdr);
}
/*
* Check if the (rawx, rawy) is inside one of the 4 hard icons.
* Return the icon number 1..4, or 0 if not inside an icon.
*/
static int
pfctp_j6x0_get_hard_icon(int rawx, int rawy)
{
if (rawx <= PFCTP_J6X0_FB_RIGHT)
return (0);
if (rawy < PFCTP_J6X0_HARD_ICON_MAX_Y(1))
return (1);
else if (rawy < PFCTP_J6X0_HARD_ICON_MAX_Y(2))
return (2);
else if (rawy < PFCTP_J6X0_HARD_ICON_MAX_Y(3))
return (3);
else
return (4);
}
/*
* PERSONA SH3 machine routines.
*/
static int
pfctp_psh3_get_stat()
{
uint8_t phdr;
phdr = _reg_read_1(SH7709_PHDR);
return ((phdr & PFCTP_PSH3_PEN_UP) != PFCTP_PSH3_PEN_UP);
}
static int
pfctp_psh3_get_touched(struct pfctp_softc *sc, int *served)
{
uint8_t phdr, touched;
unsigned int steady, tremor_timeout;
/*
* Number of times the "touched" bit should be read
* consecutively.
*/
#define PSH3_TREMOR_THRESHOLD 0x300
steady = 0;
tremor_timeout = PSH3_TREMOR_THRESHOLD * 16; /* XXX: arbitrary */
touched = TRUE; /* we start with "touched" state */
do {
uint8_t state;
phdr = _reg_read_1(SH7709_PHDR);
state = ((phdr & PFCTP_PSH3_PEN_UP) != PFCTP_PSH3_PEN_UP);
if (state == touched)
++ steady;
else {
steady = 0;
touched = state;
}
if (-- tremor_timeout == 0) {
DPRINTF(("%s: tremor timeout!\n", sc->sc_dev.dv_xname));
*served = 1;
return (0);
}
} while (steady < PSH3_TREMOR_THRESHOLD);
return (touched);
}
/*
* Read raw X/Y coordinates from the ADC.
*/
static void
pfctp_psh3_get_raw_xy(int *rawxp, int *rawyp)
{
uint8_t scpdr;
/* X axis */
scpdr = _reg_read_1(SH7709_SCPDR);
scpdr &= ~PFCTP_PSH3_SCAN_DISABLE;
scpdr |= (PFCTP_PSH3_SCAN_ENABLE | PFCTP_PSH3_SCAN_X);
_reg_write_1(SH7709_SCPDR, scpdr);
delay(40);
*rawxp = adc_sample_channel(PFCTP_PSH3_ADC_CHANNEL_TP_X);
/* Y axis */
scpdr = _reg_read_1(SH7709_SCPDR);
scpdr &= ~PFCTP_PSH3_SCAN_X;
scpdr |= (PFCTP_PSH3_SCAN_ENABLE | PFCTP_PSH3_SCAN_Y);
_reg_write_1(SH7709_SCPDR, scpdr);
delay(40);
*rawyp = adc_sample_channel(PFCTP_PSH3_ADC_CHANNEL_TP_Y);
/* restore SCPDR */
scpdr = _reg_read_1(SH7709_SCPDR);
scpdr &= ~(PFCTP_PSH3_SCAN_ENABLE | PFCTP_PSH3_SCAN_Y);
scpdr |= PFCTP_PSH3_SCAN_DISABLE;
_reg_write_1(SH7709_SCPDR, scpdr);
}
----Next_Part(Mon_Jul__4_02:40:10_2005_142)----