merged touch-panel driver

KIYOHARA Takashi <[email protected]>
Newsgroups gmane.os.netbsd.ports.hpcsh
Message-ID <[email protected]>
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
pfctp.c (text/plain, 21.7 KB)
/*	$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);
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.