File: [local] / sys / arch / jornada / dev / jmcu.c (download)
Revision 1.4, Tue Sep 30 19:35:06 2008 UTC (15 years, 8 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;
}