version 1.2, 2008/03/05 20:31:27 |
version 1.3, 2008/05/11 10:26:11 |
|
|
#include <arm/sa11x0/sa11x0_gpiovar.h> |
#include <arm/sa11x0/sa11x0_gpiovar.h> |
|
|
#include <jornada/dev/jmcu_kbdmap.h> |
#include <jornada/dev/jmcu_kbdmap.h> |
|
#include "wskbd.h" |
|
|
#define JMCU_KBD_GPIOINTR 0 |
#define JMCU_KBD_GPIOINTR 0 |
#define JMCU_TS_GPIOINTR 15 |
#define JMCU_TS_GPIOINTR 15 |
|
|
struct jmcu_softc { |
struct jmcu_softc { |
struct device sc_dev; |
struct device sc_dev; |
|
|
|
/* parent SPI stuff */ |
struct spi_bus *sc_bus; |
struct spi_bus *sc_bus; |
void *sc_spisc; |
void *sc_spisc; |
|
|
uint8_t sc_kbdeventsbuf[JMCU_KBD_NEVENTS]; |
/* keyboard stuff */ |
uint8_t sc_kbdeventsnum; |
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 jmcu_softc *jmcu_sc; |
|
|
struct wskbd_mapdata jmcukbd_keymapdata = { |
struct wskbd_mapdata jmcukbd_keymapdata = { |
jmcukbd_keydesctab, |
jmcukbd_keydesctab, |
KB_US, |
KB_US, |
|
|
int jmcu_kbdintr(void *arg); |
int jmcu_kbdintr(void *arg); |
int jmcu_touchintr(void *arg); |
int jmcu_touchintr(void *arg); |
void jmcukbd_cngetc(void *v, u_int *type, int *data); |
void jmcukbd_cngetc(void *v, u_int *type, int *data); |
void jmcukbd_enqueue(struct jmcu_softc *sc, uint8_t keycode); |
void jmcukbd_cnpollc(void *v, int on); |
void jmcukbd_dequeue(struct jmcu_softc *sc, uint8_t *keycodep); |
void jmcukbd_poll(void *v); |
void jmcukbd_getcodes(struct jmcu_softc *sc, int block); |
void jmcukbd_enqueue(struct jmcu_softc *sc, u_int type, uint8_t key); |
void jmcubatt_status(struct jmcu_softc *sc); |
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. |
* Autoconf glue. |
*/ |
*/ |
|
|
*/ |
*/ |
struct wskbd_consops jmcukbd_consops = { |
struct wskbd_consops jmcukbd_consops = { |
jmcukbd_cngetc, |
jmcukbd_cngetc, |
NULL, /* pollc */ |
jmcukbd_cnpollc, |
NULL /* bell */ |
NULL /* bell */ |
}; |
}; |
|
|
|
struct wskbd_accessops jmcukbd_accessops = { |
|
jmcukbd_enable, |
|
jmcukbd_set_leds, |
|
jmcukbd_ioctl, |
|
}; |
|
|
|
|
int |
int |
jmcu_match(struct device *parent, void *cf, void *aux) |
jmcu_match(struct device *parent, void *cf, void *aux) |
{ |
{ |
|
|
{ |
{ |
struct jmcu_softc *sc = (struct jmcu_softc *)self; |
struct jmcu_softc *sc = (struct jmcu_softc *)self; |
struct spibus_attach_args *sba = aux; |
struct spibus_attach_args *sba = aux; |
|
#if NWSKBD > 0 |
struct wskbddev_attach_args wda; |
struct wskbddev_attach_args wda; |
|
#endif |
|
/* leap to parent */ |
sc->sc_bus = sba->sba_bus; |
sc->sc_bus = sba->sba_bus; |
sc->sc_spisc = sba->sba_spisc; |
sc->sc_spisc = sba->sba_spisc; |
|
|
printf(": Jornada MCU\n"); |
|
|
|
jmcu_sc = sc; |
jmcu_sc = sc; |
|
|
/* XXX */ |
jmcubatt_getstatus(sc); |
jmcubatt_status(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); |
wskbd_cnattach(&jmcukbd_consops, sc, &jmcukbd_keymapdata); |
|
|
wda.console = 1; |
wda.console = 1; |
wda.keymap = &jmcukbd_keymapdata; |
wda.keymap = &jmcukbd_keymapdata; |
wda.accessops = NULL; //jmcukbd_accessops; |
wda.accessops = &jmcukbd_accessops; |
wda.accesscookie = sc; |
wda.accesscookie = sc; |
|
|
config_found(self, &wda, wskbddevprint); |
sc->sc_wskbddev = config_found(self, &wda, wskbddevprint); |
|
#endif |
return; |
return; |
} |
} |
|
|
|
#if 0 |
int |
int |
jmcu_kbdintr(void *arg) |
jmcu_kbdintr(void *arg) |
{ |
{ |
struct jmcu_softc *sc = arg; |
jmcukbd_poll(arg); |
printf("%s: jmcu_kbdintr\n", sc->sc_dev.dv_xname); |
|
|
|
return(0); |
return(0); |
} |
} |
|
#endif |
|
|
|
#if 0 |
int |
int |
jmcu_touchintr(void *arg) |
jmcu_touchintr(void *arg) |
{ |
{ |
|
|
|
|
return(0); |
return(0); |
} |
} |
|
#endif |
|
|
void |
void |
jmcukbd_cngetc(void *v, u_int *type, int *data) |
jmcukbd_cngetc(void *v, u_int *type, int *data) |
{ |
{ |
struct jmcu_softc *sc = v; |
struct jmcu_softc *sc = v; |
uint8_t ourdata; |
|
|
|
printf("jmcukbd_cngetc:\n"); |
/* XXX we should block until new keycode has been obtained */ |
|
|
if (sc->sc_kbdeventsnum == 0) |
sc->sc_polling = 1; |
jmcukbd_getcodes(sc, 1); /* note that we've passed blocking flag */ |
while (sc->sc_kbdnevents == 0) { |
|
/* enqueue events */ |
|
jmcukbd_poll(v); |
|
} |
|
sc->sc_polling = 0; |
|
|
jmcukbd_dequeue(sc, &ourdata); |
jmcukbd_dequeue(sc, type, data); |
|
} |
|
|
*data = ourdata & 0x7f; |
void |
*type = ourdata & 0x80 ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN; |
jmcukbd_cnpollc(void *v, int on) |
|
{ |
|
|
} |
} |
|
|
void |
void |
jmcukbd_getcodes(struct jmcu_softc *sc, int block) |
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; |
int nkeys; |
uint8_t keycode; |
|
|
|
/* wake up the MCU */ |
/* wake up the MCU */ |
sa11x0_gpio_clear_bit(25); |
sa11x0_gpio_clear_bit(25); |
|
|
spi_acquire(sc->sc_spisc); |
spi_acquire(sc->sc_spisc); |
|
|
do { |
/* ask mcu about how many keypress events are there; should get TXDUMMY here */ |
/* 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) { |
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); |
printf("%s: WARNING, no txdummy received\n", sc->sc_dev.dv_xname); |
|
|
nkeys = spi_shift_1(sc->sc_spisc, JMCU_CMD_TXDUMMY); |
goto out; |
} while(nkeys == 0 && block); |
} |
|
|
|
nkeys = spi_shift_1(sc->sc_spisc, JMCU_CMD_TXDUMMY); |
|
|
while (nkeys) { |
while (nkeys) { |
keycode = spi_shift_1(sc->sc_spisc, JMCU_CMD_TXDUMMY); |
*buf = spi_shift_1(sc->sc_spisc, JMCU_CMD_TXDUMMY); |
jmcukbd_enqueue(sc, keycode); |
|
|
|
nkeys--; |
nkeys--; |
|
buf++; |
} |
} |
|
|
|
out: |
|
/* terminate buffer */ |
|
*buf = 0; |
|
|
spi_release(sc->sc_spisc); |
spi_release(sc->sc_spisc); |
|
|
/* park off the MCU */ |
/* park off the MCU */ |
sa11x0_gpio_set_bit(25); |
sa11x0_gpio_set_bit(25); |
} |
} |
|
|
|
|
void |
void |
jmcukbd_enqueue(struct jmcu_softc *sc, uint8_t keycode) |
jmcukbd_enqueue(struct jmcu_softc *sc, u_int type, uint8_t key) |
{ |
{ |
if (sc->sc_kbdeventsnum >= JMCU_KBD_NEVENTS) { |
|
printf("%s: WARNING, event queue is full; keycode 0x%x will be discarded\n", sc->sc_dev.dv_xname, keycode); |
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; |
return; |
} |
} |
|
|
sc->sc_kbdeventsbuf[sc->sc_kbdeventsnum] = keycode; |
sc->sc_kbdqtypes[sc->sc_kbdnevents] = type; |
sc->sc_kbdeventsnum++; |
sc->sc_kbdqkeys[sc->sc_kbdnevents] = key; |
|
sc->sc_kbdnevents++; |
} |
} |
|
|
void |
void |
jmcukbd_dequeue(struct jmcu_softc *sc, uint8_t *keycodep) |
jmcukbd_dequeue(struct jmcu_softc *sc, u_int *type, int *data) |
{ |
{ |
|
#if 0 |
if (sc->sc_kbdeventsnum < 1) { |
if (sc->sc_kbdeventsnum < 1) { |
printf("%s: WARNING, event queue is empty\n", sc->sc_dev.dv_xname); |
printf("%s: WARNING, event queue is empty\n", sc->sc_dev.dv_xname); |
return; |
return; |
} |
} |
|
#endif |
sc->sc_kbdeventsnum--; |
sc->sc_kbdnevents--; |
*keycodep = sc->sc_kbdeventsbuf[sc->sc_kbdeventsnum]; |
*type = sc->sc_kbdqtypes[sc->sc_kbdnevents]; |
|
*data = sc->sc_kbdqkeys[sc->sc_kbdnevents]; |
} |
} |
|
|
|
|
void |
void |
jmcubatt_status(struct jmcu_softc *sc) |
jmcubatt_getstatus(struct jmcu_softc *sc) |
{ |
{ |
uint16_t mainbatt; |
|
uint16_t backbatt; |
|
uint8_t fraction; |
uint8_t fraction; |
|
|
/* wake up the MCU */ |
/* wake up the MCU */ |
|
|
|
|
spi_acquire(sc->sc_spisc); |
spi_acquire(sc->sc_spisc); |
spi_shift_1(sc->sc_spisc, JMCU_CMD_GETBATTERYDATA); |
spi_shift_1(sc->sc_spisc, JMCU_CMD_GETBATTERYDATA); |
mainbatt = spi_shift_1(sc->sc_spisc, JMCU_CMD_TXDUMMY); |
sc->sc_batmain = spi_shift_1(sc->sc_spisc, JMCU_CMD_TXDUMMY); |
backbatt = 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); |
fraction = spi_shift_1(sc->sc_spisc, JMCU_CMD_TXDUMMY); |
spi_release(sc->sc_spisc); |
spi_release(sc->sc_spisc); |
|
|
|
|
sa11x0_gpio_set_bit(25); |
sa11x0_gpio_set_bit(25); |
|
|
/* fraction[0:1] is mainbatt[8:9]; fraction[2:3] is backbatt[8:9] */ |
/* fraction[0:1] is mainbatt[8:9]; fraction[2:3] is backbatt[8:9] */ |
mainbatt |= (uint16_t)((fraction & 0x03) << 8); |
sc->sc_batmain |= (uint16_t)((fraction & 0x03) << 8); |
backbatt |= (uint16_t)((fraction & 0xc0) << 6); |
sc->sc_batback |= (uint16_t)((fraction & 0x0c) << 6); |
|
} |
|
|
printf("%s: battery status: main %d, backup %d\n", sc->sc_dev.dv_xname, mainbatt, backbatt); |
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; |
|
} |
|
|
|
|