[BACK]Return to jmcu.c CVS log [TXT][DIR] Up to [local] / sys / arch / jornada / dev

File: [local] / sys / arch / jornada / dev / jmcu.c (download)

Revision 1.4, Tue Sep 30 19:35:06 2008 UTC (15 years, 7 months ago) by nbrk
Branch: MAIN
CVS Tags: HEAD
Changes since 1.3: +2 -2 lines

do not query jornada's onboard MCU about battery status in jmcu_attach();
although, my driver works nice with real hardware, querying battery status
seems to lock up gxemul emulation.

/*	$Id: jmcu.c,v 1.4 2008/09/30 19:35:06 nbrk Exp $	*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/proc.h>
#include <sys/conf.h>
#include <sys/endian.h>

#include <machine/intr.h>
#include <machine/bus.h>

#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wskbdvar.h>
#include <dev/wscons/wsksymdef.h>
#include <dev/wscons/wsksymvar.h>

#include <dev/spivar.h>

#include <jornada/dev/jmcu_cmd.h>

#include <arm/sa11x0/sa11x0_var.h>
#include <arm/sa11x0/sa11x0_reg.h>
#include <arm/sa11x0/sa11x0_gpiovar.h>

#include <jornada/dev/jmcu_kbdmap.h>
#include "wskbd.h"

#define JMCU_KBD_GPIOINTR	0
#define JMCU_TS_GPIOINTR	15

#define JMCU_KBD_NEVENTS	8

struct jmcu_softc {
	struct device	sc_dev;

	/* parent SPI stuff */
	struct spi_bus	*sc_bus;
	void	*sc_spisc;

	/* keyboard stuff */
	struct device	*sc_wskbddev;
	int	sc_polling;	/* if in 'poll' mode now */
	u_int	sc_kbdqtypes[JMCU_KBD_NEVENTS];
	uint8_t	sc_kbdqkeys[JMCU_KBD_NEVENTS];
	uint8_t	sc_kbdnevents;

	/* battery charge */
	uint16_t	sc_batmain;
	uint16_t	sc_batback;
};

struct jmcu_softc *jmcu_sc;

struct wskbd_mapdata jmcukbd_keymapdata = {
        jmcukbd_keydesctab,   
        KB_US,
};

/*
 * Prototypes.
 */
int	jmcu_match(struct device *parent, void *cf, void *aux);
void	jmcu_attach(struct device *parent, struct device *self, void *aux);
int	jmcu_kbdintr(void *arg);
int	jmcu_touchintr(void *arg);
void	jmcukbd_cngetc(void *v, u_int *type, int *data);
void	jmcukbd_cnpollc(void *v, int on);
void	jmcukbd_poll(void *v);
void	jmcukbd_enqueue(struct jmcu_softc *sc, u_int type, uint8_t key);
void	jmcukbd_dequeue(struct jmcu_softc *sc, u_int *type, int *data);
void	jmcubatt_getstatus(struct jmcu_softc *sc);
void	jmcukbd_readcodes(struct jmcu_softc *sc, char *buf);
/* accessops */
int jmcukbd_enable(void *, int);
void jmcukbd_set_leds(void *, int);
int jmcukbd_ioctl(void *, u_long, caddr_t, int, struct proc *);


/*
 * Autoconf glue.
 */
struct cfattach	jmcu_ca = {
	sizeof(struct jmcu_softc), jmcu_match, jmcu_attach, NULL, NULL
};

struct cfdriver	jmcu_cd = {
	NULL,
	"jmcu",
	DV_DULL
};

/*
 * Console ops.
 */
struct wskbd_consops jmcukbd_consops = {
	jmcukbd_cngetc,
	jmcukbd_cnpollc,
	NULL /* bell */
};

struct wskbd_accessops jmcukbd_accessops = {
	jmcukbd_enable,
	jmcukbd_set_leds,
	jmcukbd_ioctl,
};


int
jmcu_match(struct device *parent, void *cf, void *aux)
{
	return (1);
}

void
jmcu_attach(struct device *parent, struct device *self, void *aux)
{
	struct jmcu_softc *sc = (struct jmcu_softc *)self;
	struct spibus_attach_args *sba = aux;
#if NWSKBD > 0
	struct wskbddev_attach_args	wda;
#endif
	/* leap to parent */
	sc->sc_bus = sba->sba_bus;
	sc->sc_spisc = sba->sba_spisc;

	jmcu_sc = sc;

/*	jmcubatt_getstatus(sc); */

	printf(": Jornada MCU (battery charge: main=%d backup=%d)\n", sc->sc_batmain, sc->sc_batback);

#if 0
	sa11x0_gpio_intr_establish(JMCU_KBD_GPIOINTR, IST_EDGE_FALLING, IPL_TTY, jmcu_kbdintr, sc, "jmcukbd_intr");
#endif /* 0 */

#if NWSKBD > 0
	/* empty event queue */
	sc->sc_kbdnevents = 0;

	wskbd_cnattach(&jmcukbd_consops, sc, &jmcukbd_keymapdata);

	wda.console = 1;
	wda.keymap = &jmcukbd_keymapdata;
	wda.accessops = &jmcukbd_accessops;
	wda.accesscookie = sc;

	sc->sc_wskbddev = config_found(self, &wda, wskbddevprint);
#endif
	return;
}

#if 0
int
jmcu_kbdintr(void *arg)
{
	jmcukbd_poll(arg);

	return(0);
}
#endif

#if 0
int
jmcu_touchintr(void *arg)
{
	struct jmcu_softc *sc = arg;
	printf("%s: jmcu_touchintr\n", sc->sc_dev.dv_xname);

	return(0);
}
#endif

void
jmcukbd_cngetc(void *v, u_int *type, int *data)
{
	struct jmcu_softc *sc = v;

	/* XXX we should block until new keycode has been obtained */

	sc->sc_polling = 1;
	while (sc->sc_kbdnevents == 0) {
		/* enqueue events */
		jmcukbd_poll(v);
	}
	sc->sc_polling = 0;

	jmcukbd_dequeue(sc, type, data);
}

void
jmcukbd_cnpollc(void *v, int on)
{

}

void
jmcukbd_poll(void *v)
{
	struct jmcu_softc *sc = v;
	u_int	type;
	int	key, s;
	char buf[JMCU_KBD_NEVENTS + 1], *p;

	s = spltty();

	jmcukbd_readcodes(sc, buf);

	for (p = buf; *p; p++) {
		type = *p & 0x80 ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
		key = *p & 0x7f;

		/* XXX */
		if (sc->sc_polling == 0)
			wskbd_input(sc->sc_wskbddev, type, key);
		else {
			/* enqueue event */
			jmcukbd_enqueue(sc, type, key);
		}
	}

	splx(s);
}

void
jmcukbd_readcodes(struct jmcu_softc *sc, char *buf)
{
	int	nkeys;

	/* wake up the MCU */
	sa11x0_gpio_clear_bit(25);

	spi_acquire(sc->sc_spisc);

	/* ask mcu about how many keypress events are there; should get TXDUMMY here */
	if (spi_shift_1(sc->sc_spisc, JMCU_CMD_GETKEYCODES) != JMCU_CMD_TXDUMMY) {
		printf("%s: WARNING, no txdummy received\n", sc->sc_dev.dv_xname);

		goto out;
	}

	nkeys = spi_shift_1(sc->sc_spisc, JMCU_CMD_TXDUMMY);

	while (nkeys) {
		*buf = spi_shift_1(sc->sc_spisc, JMCU_CMD_TXDUMMY);

		nkeys--;
		buf++;
	}

out:
	/* terminate buffer */
	*buf = 0;

	spi_release(sc->sc_spisc);

	/* park off the MCU */
	sa11x0_gpio_set_bit(25);
}


void
jmcukbd_enqueue(struct jmcu_softc *sc, u_int type, uint8_t key)
{

	if (sc->sc_kbdnevents > JMCU_KBD_NEVENTS) {
		printf("%s: WARNING, event queue is full; keycode 0x%x will be discarded\n", sc->sc_dev.dv_xname, key);
		return;
	}

	sc->sc_kbdqtypes[sc->sc_kbdnevents] = type;
	sc->sc_kbdqkeys[sc->sc_kbdnevents] = key;
	sc->sc_kbdnevents++;
}

void
jmcukbd_dequeue(struct jmcu_softc *sc, u_int *type, int *data)
{
#if 0
	if (sc->sc_kbdeventsnum < 1) {
		printf("%s: WARNING, event queue is empty\n", sc->sc_dev.dv_xname);
		return;
	}
#endif
	sc->sc_kbdnevents--;
	*type = sc->sc_kbdqtypes[sc->sc_kbdnevents];
	*data = sc->sc_kbdqkeys[sc->sc_kbdnevents];
}


void
jmcubatt_getstatus(struct jmcu_softc *sc)
{
	uint8_t	fraction;

	/* wake up the MCU */
	sa11x0_gpio_clear_bit(25);

	spi_acquire(sc->sc_spisc);
	spi_shift_1(sc->sc_spisc, JMCU_CMD_GETBATTERYDATA);
	sc->sc_batmain = spi_shift_1(sc->sc_spisc, JMCU_CMD_TXDUMMY);
	sc->sc_batback = spi_shift_1(sc->sc_spisc, JMCU_CMD_TXDUMMY);
	fraction = spi_shift_1(sc->sc_spisc, JMCU_CMD_TXDUMMY);
	spi_release(sc->sc_spisc);

	/* park off the MCU */
	sa11x0_gpio_set_bit(25);

	/* fraction[0:1] is mainbatt[8:9]; fraction[2:3] is backbatt[8:9] */
	sc->sc_batmain |= (uint16_t)((fraction & 0x03) << 8);
	sc->sc_batback |= (uint16_t)((fraction & 0x0c) << 6);
}

int
jmcukbd_enable(void *v, int on)
{
        return 0;
}
        
void
jmcukbd_set_leds(void *v, int on)
{
}

int
jmcukbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
{
#ifdef WSDISPLAY_COMPAT_RAWKBD
	struct jmcukbd_softc *sc = v;
#endif

	switch (cmd) {

	case WSKBDIO_GTYPE:
		*(int *)data = WSKBD_TYPE_ZAURUS /* XXX WSKBD_TYPE_JORNADA */;
		return 0;
	case WSKBDIO_SETLEDS:
		return 0;
	case WSKBDIO_GETLEDS:
		*(int *)data = 0;
		return 0;
#ifdef WSDISPLAY_COMPAT_RAWKBD
	case WSKBDIO_SETMODE:
		sc->sc_rawkbd = *(int *)data == WSKBD_RAW;
		timeout_del(&sc->sc_rawrepeat_ch);
		return (0);
#endif
 
	}
	/* kbdioctl(...); */

	return -1;
}