summaryrefslogtreecommitdiff
path: root/sys/arch/alpha/isa
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/alpha/isa')
-rw-r--r--sys/arch/alpha/isa/isa_machdep.h53
-rw-r--r--sys/arch/alpha/isa/isafcns_jensen.c28
-rw-r--r--sys/arch/alpha/isa/mcclock_isa.c120
-rw-r--r--sys/arch/alpha/isa/pckbd.c400
-rw-r--r--sys/arch/alpha/isa/pms.c329
-rw-r--r--sys/arch/alpha/isa/spkrreg.h11
-rw-r--r--sys/arch/alpha/isa/timerreg.h100
7 files changed, 877 insertions, 164 deletions
diff --git a/sys/arch/alpha/isa/isa_machdep.h b/sys/arch/alpha/isa/isa_machdep.h
new file mode 100644
index 00000000000..051811ecafe
--- /dev/null
+++ b/sys/arch/alpha/isa/isa_machdep.h
@@ -0,0 +1,53 @@
+/* $NetBSD: isa_machdep.h,v 1.2 1996/04/12 05:39:02 cgd Exp $ */
+
+/*
+ * Copyright (c) 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+/*
+ * Types provided to machine-independent ISA code.
+ */
+typedef struct alpha_isa_chipset *isa_chipset_tag_t;
+
+struct alpha_isa_chipset {
+ void *ic_v;
+
+ void (*ic_attach_hook) __P((struct device *, struct device *,
+ struct isabus_attach_args *));
+ void *(*ic_intr_establish) __P((void *, int, int, int,
+ int (*)(void *), void *));
+ void (*ic_intr_disestablish) __P((void *, void *));
+};
+
+/*
+ * Functions provided to machine-independent ISA code.
+ */
+#define isa_attach_hook(p, s, a) \
+ (*(a)->iba_ic->ic_attach_hook)((p), (s), (a))
+#define isa_intr_establish(c, i, t, l, f, a) \
+ (*(c)->ic_intr_establish)((c)->ic_v, (i), (t), (l), (f), (a))
+#define isa_intr_disestablish(c, h) \
+ (*(c)->ic_intr_disestablish)((c)->ic_v, (h))
diff --git a/sys/arch/alpha/isa/isafcns_jensen.c b/sys/arch/alpha/isa/isafcns_jensen.c
index 3e5624357b8..5ac135aea69 100644
--- a/sys/arch/alpha/isa/isafcns_jensen.c
+++ b/sys/arch/alpha/isa/isafcns_jensen.c
@@ -1,3 +1,31 @@
+/* $NetBSD: isafcns_jensen.c,v 1.2 1996/04/12 01:54:04 cgd Exp $ */
+
+/*
+ * Copyright (c) 1995, 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
#include <sys/types.h>
#include <machine/pio.h>
diff --git a/sys/arch/alpha/isa/mcclock_isa.c b/sys/arch/alpha/isa/mcclock_isa.c
new file mode 100644
index 00000000000..fb9ac1f778b
--- /dev/null
+++ b/sys/arch/alpha/isa/mcclock_isa.c
@@ -0,0 +1,120 @@
+/* $NetBSD: mcclock_isa.c,v 1.2 1996/04/17 22:22:46 cgd Exp $ */
+
+/*
+ * Copyright (c) 1995, 1996 Carnegie-Mellon University.
+ * All rights reserved.
+ *
+ * Author: Chris G. Demetriou
+ *
+ * Permission to use, copy, modify and distribute this software and
+ * its documentation is hereby granted, provided that both the copyright
+ * notice and this permission notice appear in all copies of the
+ * software, derivative works or modified versions, and any portions
+ * thereof, and that both notices appear in supporting documentation.
+ *
+ * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
+ * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
+ * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
+ *
+ * Carnegie Mellon requests users of this software to return to
+ *
+ * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
+ * School of Computer Science
+ * Carnegie Mellon University
+ * Pittsburgh PA 15213-3890
+ *
+ * any improvements or extensions that they make and grant Carnegie the
+ * rights to redistribute these changes.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <machine/bus.h>
+
+#include <alpha/alpha/clockvar.h>
+#include <alpha/alpha/mcclockvar.h>
+#include <dev/ic/mc146818reg.h>
+#include <dev/isa/isavar.h>
+
+struct mcclock_isa_softc {
+ struct mcclock_softc sc_mcclock;
+
+ bus_chipset_tag_t sc_bc;
+ bus_io_handle_t sc_ioh;
+};
+
+int mcclock_isa_match __P((struct device *, void *, void *));
+void mcclock_isa_attach __P((struct device *, struct device *, void *));
+
+struct cfattach mcclock_isa_ca = {
+ sizeof (struct mcclock_isa_softc), mcclock_isa_match,
+ mcclock_isa_attach,
+};
+
+void mcclock_isa_write __P((struct mcclock_softc *, u_int, u_int));
+u_int mcclock_isa_read __P((struct mcclock_softc *, u_int));
+
+const struct mcclock_busfns mcclock_isa_busfns = {
+ mcclock_isa_write, mcclock_isa_read,
+};
+
+int
+mcclock_isa_match(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ struct isa_attach_args *ia = aux;
+
+ if (ia->ia_iobase != 0x70 && ia->ia_iobase != -1)
+ return (0);
+
+ ia->ia_iobase = 0x70; /* XXX */
+ ia->ia_iosize = 2; /* XXX */
+ ia->ia_msize = 0;
+
+ return (1);
+}
+
+void
+mcclock_isa_attach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct isa_attach_args *ia = aux;
+ struct mcclock_isa_softc *sc = (struct mcclock_isa_softc *)self;
+
+ sc->sc_bc = ia->ia_bc;
+ if (bus_io_map(sc->sc_bc, ia->ia_iobase, ia->ia_iosize, &sc->sc_ioh))
+ panic("mcclock_isa_attach: couldn't map clock I/O space");
+
+ mcclock_attach(&sc->sc_mcclock, &mcclock_isa_busfns);
+}
+
+void
+mcclock_isa_write(mcsc, reg, datum)
+ struct mcclock_softc *mcsc;
+ u_int reg, datum;
+{
+ struct mcclock_isa_softc *sc = (struct mcclock_isa_softc *)mcsc;
+ bus_chipset_tag_t bc = sc->sc_bc;
+ bus_io_handle_t ioh = sc->sc_ioh;
+
+ bus_io_write_1(bc, ioh, 0, reg);
+ bus_io_write_1(bc, ioh, 1, datum);
+}
+
+u_int
+mcclock_isa_read(mcsc, reg)
+ struct mcclock_softc *mcsc;
+ u_int reg;
+{
+ struct mcclock_isa_softc *sc = (struct mcclock_isa_softc *)mcsc;
+ bus_chipset_tag_t bc = sc->sc_bc;
+ bus_io_handle_t ioh = sc->sc_ioh;
+
+ bus_io_write_1(bc, ioh, 0, reg);
+ return bus_io_read_1(bc, ioh, 1);
+}
diff --git a/sys/arch/alpha/isa/pckbd.c b/sys/arch/alpha/isa/pckbd.c
index ab269620ef7..0a212449aeb 100644
--- a/sys/arch/alpha/isa/pckbd.c
+++ b/sys/arch/alpha/isa/pckbd.c
@@ -1,4 +1,4 @@
-/* $NetBSD: pckbd.c,v 1.3 1995/12/24 02:29:35 mycroft Exp $ */
+/* $NetBSD: pckbd.c,v 1.7 1996/05/05 01:41:53 thorpej Exp $ */
/*-
* Copyright (c) 1993, 1994, 1995 Charles Hannum. All rights reserved.
@@ -52,16 +52,18 @@
#include <sys/kernel.h>
#include <sys/device.h>
-#include <machine/cpu.h>
+#include <machine/intr.h>
+#include <machine/bus.h>
#include <dev/isa/isareg.h>
#include <dev/isa/isavar.h>
#include <alpha/isa/pckbdreg.h>
+#include <alpha/isa/spkrreg.h>
+#include <alpha/isa/timerreg.h>
+#include <machine/wsconsio.h>
-#include "wsc.h"
-#if NWSC
-#include <alpha/pci/wsconsvar.h>
-#endif
+#include <alpha/wscons/wsconsvar.h>
+#include "wscons.h"
static volatile u_char ack, nak; /* Don't ask. */
static u_char async, kernel, polling; /* Really, you don't want to know. */
@@ -70,28 +72,58 @@ static u_char lock_state = 0x00, /* all off */
typematic_rate = 0xff, /* don't update until set by user */
old_typematic_rate = 0xff;
-__const struct isa_intr_fns *pckbd_intr_fns; /* XXX */
-void *pckbd_intr_arg; /* XXX */
-__const struct isa_pio_fns *pckbd_pio_fns; /* XXX */
-void *pckbd_pio_arg; /* XXX */
+bus_chipset_tag_t pckbd_bc;
+isa_chipset_tag_t pckbd_ic;
+
+bus_io_handle_t pckbd_data_ioh;
+#define pckbd_out_ioh pckbd_data_ioh
+bus_io_handle_t pckbd_status_ioh;
+#define pckbd_cmd_ioh pckbd_status_ioh
+bus_io_handle_t pckbd_timer_ioh;
+bus_io_handle_t pckbd_pitaux_ioh;
+bus_io_handle_t pckbd_delay_ioh;
struct pckbd_softc {
struct device sc_dev;
void *sc_ih;
+
+ int sc_bellactive; /* is the bell active? */
+ int sc_bellpitch; /* last pitch programmed */
};
int pckbdprobe __P((struct device *, void *, void *));
void pckbdattach __P((struct device *, struct device *, void *));
int pckbdintr __P((void *));
-struct cfdriver pckbdcd = {
- NULL, "pckbd", pckbdprobe, pckbdattach, DV_DULL,
- sizeof(struct pckbd_softc)
+struct cfattach pckbd_ca = {
+ sizeof(struct pckbd_softc), pckbdprobe, pckbdattach,
};
-char *sget __P((void));
-int pccngetc __P((void *));
-void pccnpollc __P((void *, int));
+struct cfdriver pckbd_cd = {
+ NULL, "pckbd", DV_DULL,
+};
+
+int pckbd_cngetc __P((struct device *));
+void pckbd_cnpollc __P((struct device *, int));
+void pckbd_bell __P((struct device *, struct wsconsio_bell_data *));
+int pckbd_ioctl __P((struct device *, u_long, caddr_t, int,
+ struct proc *));
+
+char *pckbd_translate __P((struct device *dev, int c));
+
+#if NWSCONS
+struct wscons_idev_spec pckbd_wscons_idev = {
+ pckbd_cngetc,
+ pckbd_cnpollc,
+ pckbd_bell,
+ pckbd_ioctl,
+ pckbd_translate,
+ 0x7f, /* key data mask */
+ 0x80, /* key-up mask */
+};
+#endif
+
+void pckbd_bell_stop __P((void *));
/*
* DANGER WIL ROBINSON -- the values of SCROLL, NUM, CAPS, and ALT are
@@ -109,10 +141,10 @@ void pccnpollc __P((void *, int));
#define NONE 0x0400 /* no function */
#define KBD_DELAY \
- { u_char x = INB(pckbd_pio_fns, pckbd_pio_arg, 0x84); } \
- { u_char x = INB(pckbd_pio_fns, pckbd_pio_arg, 0x84); } \
- { u_char x = INB(pckbd_pio_fns, pckbd_pio_arg, 0x84); } \
- { u_char x = INB(pckbd_pio_fns, pckbd_pio_arg, 0x84); }
+ { u_char x = bus_io_read_1(pckbd_bc, pckbd_delay_ioh, 0); } \
+ { u_char x = bus_io_read_1(pckbd_bc, pckbd_delay_ioh, 0); } \
+ { u_char x = bus_io_read_1(pckbd_bc, pckbd_delay_ioh, 0); } \
+ { u_char x = bus_io_read_1(pckbd_bc, pckbd_delay_ioh, 0); }
static inline int
kbd_wait_output()
@@ -120,7 +152,7 @@ kbd_wait_output()
u_int i;
for (i = 100000; i; i--)
- if ((INB(pckbd_pio_fns, pckbd_pio_arg, KBSTATP) & KBS_IBF)
+ if ((bus_io_read_1(pckbd_bc, pckbd_status_ioh, 0) & KBS_IBF)
== 0) {
KBD_DELAY;
return 1;
@@ -134,7 +166,7 @@ kbd_wait_input()
u_int i;
for (i = 100000; i; i--)
- if ((INB(pckbd_pio_fns, pckbd_pio_arg, KBSTATP) & KBS_DIB)
+ if ((bus_io_read_1(pckbd_bc, pckbd_status_ioh, 0) & KBS_DIB)
!= 0) {
KBD_DELAY;
return 1;
@@ -148,11 +180,11 @@ kbd_flush_input()
u_int i;
for (i = 10; i; i--) {
- if ((INB(pckbd_pio_fns, pckbd_pio_arg, KBSTATP) & KBS_DIB)
+ if ((bus_io_read_1(pckbd_bc, pckbd_status_ioh, 0) & KBS_DIB)
== 0)
return;
KBD_DELAY;
- (void) INB(pckbd_pio_fns, pckbd_pio_arg, KBDATAP);
+ (void) bus_io_read_1(pckbd_bc, pckbd_data_ioh, 0);
}
}
@@ -166,10 +198,10 @@ kbc_get8042cmd()
if (!kbd_wait_output())
return -1;
- OUTB(pckbd_pio_fns, pckbd_pio_arg, KBCMDP, K_RDCMDBYTE);
+ bus_io_write_1(pckbd_bc, pckbd_cmd_ioh, 0, K_RDCMDBYTE);
if (!kbd_wait_input())
return -1;
- return INB(pckbd_pio_fns, pckbd_pio_arg, KBDATAP);
+ return bus_io_read_1(pckbd_bc, pckbd_data_ioh, 0);
}
#endif
@@ -183,10 +215,10 @@ kbc_put8042cmd(val)
if (!kbd_wait_output())
return 0;
- OUTB(pckbd_pio_fns, pckbd_pio_arg, KBCMDP, K_LDCMDBYTE);
+ bus_io_write_1(pckbd_bc, pckbd_cmd_ioh, 0, K_LDCMDBYTE);
if (!kbd_wait_output())
return 0;
- OUTB(pckbd_pio_fns, pckbd_pio_arg, KBOUTP, val);
+ bus_io_write_1(pckbd_bc, pckbd_out_ioh, 0, val);
return 1;
}
@@ -205,16 +237,16 @@ kbd_cmd(val, polling)
if (!kbd_wait_output())
return 0;
ack = nak = 0;
- OUTB(pckbd_pio_fns, pckbd_pio_arg, KBOUTP, val);
+ bus_io_write_1(pckbd_bc, pckbd_out_ioh, 0, val);
if (polling)
for (i = 100000; i; i--) {
- if (INB(pckbd_pio_fns, pckbd_pio_arg,
- KBSTATP) & KBS_DIB) {
+ if (bus_io_read_1(pckbd_bc,
+ pckbd_status_ioh, 0) & KBS_DIB) {
register u_char c;
KBD_DELAY;
- c = INB(pckbd_pio_fns, pckbd_pio_arg,
- KBDATAP);
+ c = bus_io_read_1(pckbd_bc,
+ pckbd_data_ioh, 0);
if (c == KBR_ACK || c == KBR_ECHO) {
ack = 1;
return 1;
@@ -231,8 +263,8 @@ kbd_cmd(val, polling)
}
else
for (i = 100000; i; i--) {
- (void) INB(pckbd_pio_fns, pckbd_pio_arg,
- KBSTATP);
+ (void) bus_io_read_1(pckbd_bc,
+ pckbd_status_ioh, 0);
if (ack)
return 1;
if (nak)
@@ -252,11 +284,19 @@ pckbdprobe(parent, match, aux)
struct device *parent;
void *match, *aux;
{
- struct isadev_attach_args *ida = aux;
+ struct isa_attach_args *ia = aux;
u_int i;
- pckbd_pio_fns = ida->ida_piofns; /* XXX */
- pckbd_pio_arg = ida->ida_pioarg; /* XXX */
+ pckbd_bc = ia->ia_bc;
+ pckbd_ic = ia->ia_ic;
+
+ if (bus_io_map(pckbd_bc, KBDATAP, 1, &pckbd_data_ioh) ||
+ bus_io_map(pckbd_bc, KBSTATP, 1, &pckbd_status_ioh) ||
+ bus_io_map(pckbd_bc, IO_TIMER1, 4, &pckbd_timer_ioh) ||
+ bus_io_map(pckbd_bc, PITAUX_PORT, 1, &pckbd_pitaux_ioh))
+ return 0;
+
+ pckbd_delay_ioh = ia->ia_delayioh;
/* Enable interrupts and keyboard, etc. */
if (!kbc_put8042cmd(CMDBYTE)) {
@@ -273,12 +313,12 @@ pckbdprobe(parent, match, aux)
goto lose;
}
for (i = 600000; i; i--)
- if ((INB(pckbd_pio_fns, pckbd_pio_arg, KBSTATP) & KBS_DIB)
+ if ((bus_io_read_1(pckbd_bc, pckbd_status_ioh, 0) & KBS_DIB)
!= 0) {
KBD_DELAY;
break;
}
- if (i == 0 || INB(pckbd_pio_fns, pckbd_pio_arg, KBDATAP)
+ if (i == 0 || bus_io_read_1(pckbd_bc, pckbd_data_ioh, 0)
!= KBR_RSTDONE) {
printf("pcprobe: reset error %d\n", 2);
goto lose;
@@ -329,8 +369,8 @@ lose:
*/
#endif
- ida->ida_nports[0] = 16;
- ida->ida_iosiz[0] = 0;
+ ia->ia_iobase = 16;
+ ia->ia_iosize = 0;
return 1;
}
@@ -340,20 +380,29 @@ pckbdattach(parent, self, aux)
void *aux;
{
struct pckbd_softc *sc = (void *)self;
- struct isadev_attach_args *ida = aux;
-
- pckbd_intr_fns = ida->ida_intrfns; /* XXX */
- pckbd_intr_arg = ida->ida_intrarg; /* XXX */
- pckbd_pio_fns = ida->ida_piofns; /* XXX */
- pckbd_pio_arg = ida->ida_pioarg; /* XXX */
-
- sc->sc_ih = ISA_INTR_ESTABLISH(pckbd_intr_fns, pckbd_intr_arg,
- ida->ida_irq[0], IST_EDGE, IPL_TTY, pckbdintr, sc);
-#if NWSC
+ struct isa_attach_args *ia = aux;
+
+ pckbd_bc = ia->ia_bc;
+ pckbd_ic = ia->ia_ic;
+
+ if (bus_io_map(pckbd_bc, KBDATAP, 1, &pckbd_data_ioh) ||
+ bus_io_map(pckbd_bc, KBSTATP, 1, &pckbd_status_ioh) ||
+ bus_io_map(pckbd_bc, IO_TIMER1, 4, &pckbd_timer_ioh) ||
+ bus_io_map(pckbd_bc, PITAUX_PORT, 1, &pckbd_pitaux_ioh))
+ panic("pckbdattach couldn't map");
+
+ pckbd_delay_ioh = ia->ia_delayioh;
+
+ sc->sc_ih = isa_intr_establish(pckbd_ic, ia->ia_irq, IST_EDGE,
+ IPL_TTY, pckbdintr, sc);
+
+ sc->sc_bellactive = sc->sc_bellpitch = 0;
+
+#if NWSCONS
printf("\n");
- wscattach_input(self, self, pccngetc, pccnpollc);
+ kbdattach(self, &pckbd_wscons_idev);
#else
- printf(": no wsc driver; no input possible\n");
+ printf(": no wscons driver present; no input possible\n");
#endif
}
@@ -367,19 +416,35 @@ pckbdintr(arg)
void *arg;
{
struct pckbd_softc *sc = arg;
- u_char *cp;
+ u_char data;
+ static u_char last;
- if ((INB(pckbd_pio_fns, pckbd_pio_arg, KBSTATP) & KBS_DIB) == 0)
+ if ((bus_io_read_1(pckbd_bc, pckbd_status_ioh, 0) & KBS_DIB) == 0)
return 0;
if (polling)
return 1;
do {
- cp = sget();
-#if NWSC
- if (cp)
- wscons_kbdinput(cp);
+ KBD_DELAY;
+ data = bus_io_read_1(pckbd_bc, pckbd_data_ioh, 0);
+
+ switch (data) {
+ case KBR_ACK:
+ ack = 1;
+ break;
+ case KBR_RESEND:
+ nak = 1;
+ break;
+ default:
+ /* Always ignore typematic keys */
+ if (data == last)
+ break;
+ last = data;
+#if NWSCONS
+ kbd_input(data);
#endif
- } while (INB(pckbd_pio_fns, pckbd_pio_arg, KBSTATP) & KBS_DIB);
+ break;
+ }
+ } while (bus_io_read_1(pckbd_bc, pckbd_status_ioh, 0) & KBS_DIB);
return 1;
}
@@ -426,6 +491,23 @@ async_update()
}
}
+int
+pckbd_ioctl(dev, cmd, data, flag, p)
+ struct device *dev;
+ u_long cmd;
+ caddr_t data;
+ int flag;
+ struct proc *p;
+{
+
+ switch (cmd) {
+ case WSCONSIO_KBD_GTYPE:
+ *(int *)data = KBD_TYPE_PC;
+ return 0;
+ }
+ return ENOTTY;
+}
+
#if 0
int
pcioctl(dev, cmd, data, flag, p)
@@ -633,96 +715,18 @@ static Scan_def scan_codes[] = {
* Get characters from the keyboard. If none are present, return NULL.
*/
char *
-sget()
+pckbd_translate(dev, c)
+ struct device *dev;
+ int c;
{
- u_char dt;
+ u_char dt = c;
static u_char extended = 0, shift_state = 0;
static u_char capchar[2];
-top:
- KBD_DELAY;
- dt = INB(pckbd_pio_fns, pckbd_pio_arg, KBDATAP);
-
- switch (dt) {
- case KBR_ACK:
- ack = 1;
- goto loop;
- case KBR_RESEND:
- nak = 1;
- goto loop;
- }
-
-#if 0
- if (pc_xmode > 0) {
-#if defined(DDB) && defined(XSERVER_DDB)
- /* F12 enters the debugger while in X mode */
- if (dt == 88)
- Debugger();
-#endif
- capchar[0] = dt;
- capchar[1] = 0;
- /*
- * Check for locking keys.
- *
- * XXX Setting the LEDs this way is a bit bogus. What if the
- * keyboard has been remapped in X?
- */
- switch (scan_codes[dt & 0x7f].type) {
- case NUM:
- if (dt & 0x80) {
- shift_state &= ~NUM;
- break;
- }
- if (shift_state & NUM)
- break;
- shift_state |= NUM;
- lock_state ^= NUM;
- async_update();
- break;
- case CAPS:
- if (dt & 0x80) {
- shift_state &= ~CAPS;
- break;
- }
- if (shift_state & CAPS)
- break;
- shift_state |= CAPS;
- lock_state ^= CAPS;
- async_update();
- break;
- case SCROLL:
- if (dt & 0x80) {
- shift_state &= ~SCROLL;
- break;
- }
- if (shift_state & SCROLL)
- break;
- shift_state |= SCROLL;
- lock_state ^= SCROLL;
- if ((lock_state & SCROLL) == 0)
- wakeup((caddr_t)&lock_state);
- async_update();
- break;
- }
- return capchar;
- }
-#endif /* 0 */
-
- switch (dt) {
- case KBR_EXTENDED:
+ if (dt == KBR_EXTENDED) {
extended = 1;
- goto loop;
- }
-
-#ifdef DDB
- /*
- * Check for cntl-alt-esc.
- */
- if ((dt == 1) && (shift_state & (CTL | ALT)) == (CTL | ALT)) {
- Debugger();
- dt |= 0x80; /* discard esc (ddb discarded ctl-alt) */
+ return NULL;
}
-#endif
/*
* Check for make/break.
@@ -837,31 +841,43 @@ top:
}
extended = 0;
-loop:
- if ((INB(pckbd_pio_fns, pckbd_pio_arg, KBSTATP) & KBS_DIB) == 0)
- return 0;
- goto top;
+ return (NULL);
}
/* ARGSUSED */
int
-pccngetc(cookie)
- void *cookie;
+pckbd_cngetc(dev)
+ struct device *dev;
{
register char *cp;
-
-#if 0
- if (pc_xmode > 0)
- return 0;
-#endif
+ u_char data;
+ static u_char last;
do {
- /* wait for byte */
- while ((INB(pckbd_pio_fns, pckbd_pio_arg, KBSTATP) & KBS_DIB)
- == 0);
- /* see if it's worthwhile */
- cp = sget();
+ /* wait for byte */
+ while ((bus_io_read_1(pckbd_bc, pckbd_status_ioh, 0) & KBS_DIB)
+ == 0)
+ KBD_DELAY;
+ KBD_DELAY;
+
+ data = bus_io_read_1(pckbd_bc, pckbd_data_ioh, 0);
+
+ if (data == KBR_ACK) {
+ ack = 1;
+ continue;
+ }
+ if (data == KBR_RESEND) {
+ nak = 1;
+ continue;
+ }
+
+ /* Ignore typematic keys */
+ if (data == last)
+ continue;
+ last = data;
+
+ cp = pckbd_translate(NULL, data);
} while (!cp);
if (*cp == '\r')
return '\n';
@@ -869,11 +885,11 @@ pccngetc(cookie)
}
void
-pccnpollc(cookie, on)
- void *cookie;
+pckbd_cnpollc(dev, on)
+ struct device *dev;
int on;
{
- struct pckbd_softc *sc = cookie;
+ struct pckbd_softc *sc = (struct pckbd_softc *)dev;
polling = on;
if (!on) {
@@ -892,3 +908,59 @@ pccnpollc(cookie, on)
}
}
}
+
+void
+pckbd_bell(dev, wbd)
+ struct device *dev;
+ struct wsconsio_bell_data *wbd;
+{
+ struct pckbd_softc *sc = (struct pckbd_softc *)dev;
+ int pitch, period;
+ int s;
+
+ pitch = wbd->wbd_pitch;
+ period = (wbd->wbd_period * hz) / 1000;
+ /* XXX volume ignored */
+
+ s = splhigh();
+ if (sc->sc_bellactive)
+ untimeout(pckbd_bell_stop, sc);
+ splx(s);
+ if (pitch == 0 || period == 0) {
+ pckbd_bell_stop(sc);
+ sc->sc_bellpitch = 0;
+ return;
+ }
+ if (!sc->sc_bellactive || sc->sc_bellpitch != pitch) {
+ s = splhigh();
+ bus_io_write_1(pckbd_bc, pckbd_timer_ioh, TIMER_MODE,
+ TIMER_SEL2 | TIMER_16BIT | TIMER_SQWAVE);
+ bus_io_write_1(pckbd_bc, pckbd_timer_ioh, TIMER_CNTR2,
+ TIMER_DIV(pitch) % 256);
+ bus_io_write_1(pckbd_bc, pckbd_timer_ioh, TIMER_CNTR2,
+ TIMER_DIV(pitch) / 256);
+ /* enable speaker */
+ bus_io_write_1(pckbd_bc, pckbd_pitaux_ioh, 0,
+ bus_io_read_1(pckbd_bc, pckbd_pitaux_ioh, 0) |
+ PIT_SPKR);
+ splx(s);
+ }
+ sc->sc_bellpitch = pitch;
+ sc->sc_bellactive = 1;
+ timeout(pckbd_bell_stop, sc, period);
+}
+
+void
+pckbd_bell_stop(arg)
+ void *arg;
+{
+ struct pckbd_softc *sc = arg;
+ int s;
+
+ /* disable bell */
+ s = splhigh();
+ bus_io_write_1(pckbd_bc, pckbd_pitaux_ioh, 0,
+ bus_io_read_1(pckbd_bc, pckbd_pitaux_ioh, 0) & ~PIT_SPKR);
+ sc->sc_bellactive = 0;
+ splx(s);
+}
diff --git a/sys/arch/alpha/isa/pms.c b/sys/arch/alpha/isa/pms.c
new file mode 100644
index 00000000000..5fc6e3ae649
--- /dev/null
+++ b/sys/arch/alpha/isa/pms.c
@@ -0,0 +1,329 @@
+/* $NetBSD: pms.c,v 1.1 1996/04/12 01:53:06 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1994 Charles Hannum.
+ * Copyright (c) 1992, 1993 Erik Forsberg.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY ``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 I 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.
+ */
+
+/*
+ * XXXX
+ * This is a hack. This driver should really be combined with the
+ * keyboard driver, since they go through the same buffer and use the
+ * same I/O ports. Frobbing the mouse and keyboard at the same time
+ * may result in dropped characters and/or corrupted mouse events.
+ */
+
+#include "pms.h"
+#if NPMS > 1
+#error Only one PS/2 style mouse may be configured into your system.
+#endif
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/systm.h>
+#include <sys/buf.h>
+#include <sys/malloc.h>
+#include <sys/ioctl.h>
+#include <sys/tty.h>
+#include <sys/file.h>
+#include <sys/select.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <sys/device.h>
+
+#include <machine/intr.h>
+#include <dev/isa/isavar.h>
+#include <alpha/wscons/wsconsvar.h>
+
+#define PMS_DATA 0x60 /* offset for data port, read-write */
+#define PMS_CNTRL 0x64 /* offset for control port, write-only */
+#define PMS_STATUS 0x64 /* offset for status port, read-only */
+#define PMS_NPORTS 8
+
+/* status bits */
+#define PMS_OBUF_FULL 0x01
+#define PMS_IBUF_FULL 0x02
+
+/* controller commands */
+#define PMS_INT_ENABLE 0x47 /* enable controller interrupts */
+#define PMS_INT_DISABLE 0x65 /* disable controller interrupts */
+#define PMS_AUX_ENABLE 0xa8 /* enable auxiliary port */
+#define PMS_AUX_DISABLE 0xa7 /* disable auxiliary port */
+#define PMS_AUX_TEST 0xa9 /* test auxiliary port */
+
+#define PMS_8042_CMD 0x65
+
+/* mouse commands */
+#define PMS_SET_SCALE11 0xe6 /* set scaling 1:1 */
+#define PMS_SET_SCALE21 0xe7 /* set scaling 2:1 */
+#define PMS_SET_RES 0xe8 /* set resolution */
+#define PMS_GET_SCALE 0xe9 /* get scaling factor */
+#define PMS_SET_STREAM 0xea /* set streaming mode */
+#define PMS_SET_SAMPLE 0xf3 /* set sampling rate */
+#define PMS_DEV_ENABLE 0xf4 /* mouse on */
+#define PMS_DEV_DISABLE 0xf5 /* mouse off */
+#define PMS_RESET 0xff /* reset */
+
+#define PMS_CHUNK 128 /* chunk size for read */
+#define PMS_BSIZE 1020 /* buffer size */
+
+struct pms_softc { /* driver status information */
+ struct device sc_dev;
+
+ void *sc_ih;
+
+ u_char sc_state; /* mouse driver state */
+#define PMS_OPEN 0x01 /* device is open */
+#define PMS_ASLP 0x02 /* waiting for mouse data */
+ u_char sc_status; /* mouse button status */
+ int sc_x, sc_y; /* accumulated motion in the X,Y axis */
+};
+
+bus_chipset_tag_t pms_bc;
+isa_chipset_tag_t pms_ic;
+bus_io_handle_t pms_cntrl_ioh;
+#define pms_status_ioh pms_cntrl_ioh
+bus_io_handle_t pms_data_ioh;
+
+int pmsprobe __P((struct device *, void *, void *));
+void pmsattach __P((struct device *, struct device *, void *));
+int pmsintr __P((void *));
+
+struct cfattach pms_ca = {
+ sizeof(struct pms_softc), pmsprobe, pmsattach,
+};
+
+struct cfdriver pms_cd = {
+ NULL, "pms", DV_TTY,
+};
+
+#define PMSUNIT(dev) (minor(dev))
+
+int pms_enable __P((struct device *));
+int pms_disable __P((struct device *));
+
+struct wscons_mdev_spec pms_mdev_spec = {
+ pms_enable,
+ pms_disable,
+};
+
+static inline void
+pms_flush()
+{
+ u_char c;
+
+ while (c = bus_io_read_1(pms_bc, pms_status_ioh, 0) & 0x03)
+ if ((c & PMS_OBUF_FULL) == PMS_OBUF_FULL) {
+ /* XXX - delay is needed to prevent some keyboards from
+ wedging when the system boots */
+ delay(6);
+ (void) bus_io_read_1(pms_bc, pms_data_ioh, 0);
+ }
+}
+
+static inline void
+pms_dev_cmd(value)
+ u_char value;
+{
+
+ pms_flush();
+ bus_io_write_1(pms_bc, pms_cntrl_ioh, 0, 0xd4);
+ pms_flush();
+ bus_io_write_1(pms_bc, pms_data_ioh, 0, value);
+}
+
+static inline void
+pms_aux_cmd(value)
+ u_char value;
+{
+
+ pms_flush();
+ bus_io_write_1(pms_bc, pms_cntrl_ioh, 0, value);
+}
+
+static inline void
+pms_pit_cmd(value)
+ u_char value;
+{
+
+ pms_flush();
+ bus_io_write_1(pms_bc, pms_cntrl_ioh, 0, 0x60);
+ pms_flush();
+ bus_io_write_1(pms_bc, pms_data_ioh, 0, value);
+}
+
+int
+pmsprobe(parent, match, aux)
+ struct device *parent;
+ void *match, *aux;
+{
+ struct isa_attach_args *ia = aux;
+ u_char x;
+
+ pms_bc = ia->ia_bc;
+
+ if (ia->ia_iobase != 0x60)
+ return 0;
+
+ if (bus_io_map(pms_bc, PMS_DATA, 1, &pms_data_ioh) ||
+ bus_io_map(pms_bc, PMS_CNTRL, 1, &pms_cntrl_ioh))
+ return 0;
+
+ pms_dev_cmd(PMS_RESET);
+ pms_aux_cmd(PMS_AUX_TEST);
+ delay(1000);
+ x = bus_io_read_1(pms_bc, pms_data_ioh, 0);
+ pms_pit_cmd(PMS_INT_DISABLE);
+ if (x & 0x04)
+ return 0;
+
+ ia->ia_iosize = PMS_NPORTS;
+ ia->ia_msize = 0;
+ return 1;
+}
+
+void
+pmsattach(parent, self, aux)
+ struct device *parent, *self;
+ void *aux;
+{
+ struct pms_softc *sc = (void *)self;
+ struct isa_attach_args *ia = aux;
+
+ pms_bc = ia->ia_bc;
+ pms_ic = ia->ia_ic;
+
+ if (bus_io_map(pms_bc, PMS_DATA, 1, &pms_data_ioh) ||
+ bus_io_map(pms_bc, PMS_CNTRL, 1, &pms_cntrl_ioh)) {
+ printf(": can't map I/O ports!\n");
+ return;
+ }
+
+ msattach(self, &pms_mdev_spec);
+
+ printf("\n");
+
+ /* Other initialization was done by pmsprobe. */
+ sc->sc_state = 0;
+
+ sc->sc_ih = isa_intr_establish(pms_ic, ia->ia_irq, IST_EDGE, IPL_TTY,
+ pmsintr, sc);
+}
+
+int
+pms_enable(dev)
+ struct device *dev;
+{
+ struct pms_softc *sc = (struct pms_softc *)dev;
+
+ if (sc->sc_state & PMS_OPEN)
+ return EBUSY;
+
+ sc->sc_state |= PMS_OPEN;
+ sc->sc_status = 0;
+ sc->sc_x = sc->sc_y = 0;
+
+ /* Enable interrupts. */
+ pms_dev_cmd(PMS_DEV_ENABLE);
+ pms_aux_cmd(PMS_AUX_ENABLE);
+#if 0
+ pms_dev_cmd(PMS_SET_RES);
+ pms_dev_cmd(3); /* 8 counts/mm */
+ pms_dev_cmd(PMS_SET_SCALE21);
+ pms_dev_cmd(PMS_SET_SAMPLE);
+ pms_dev_cmd(100); /* 100 samples/sec */
+ pms_dev_cmd(PMS_SET_STREAM);
+#endif
+ pms_pit_cmd(PMS_INT_ENABLE);
+
+ return 0;
+}
+
+int
+pms_disable(dev)
+ struct device *dev;
+{
+ struct pms_softc *sc = (struct pms_softc *)dev;
+
+ /* Disable interrupts. */
+ pms_dev_cmd(PMS_DEV_DISABLE);
+ pms_pit_cmd(PMS_INT_DISABLE);
+ pms_aux_cmd(PMS_AUX_DISABLE);
+
+ sc->sc_state &= ~PMS_OPEN;
+
+ return 0;
+}
+
+/* Masks for the first byte of a packet */
+#define PS2LBUTMASK 0x01
+#define PS2RBUTMASK 0x02
+#define PS2MBUTMASK 0x04
+
+int
+pmsintr(arg)
+ void *arg;
+{
+ struct pms_softc *sc = arg;
+ static int state = 0;
+ static u_char buttons;
+ u_char changed;
+ static char dx, dy;
+ u_char buffer[5];
+
+ if ((sc->sc_state & PMS_OPEN) == 0) {
+ /* Interrupts are not expected. Discard the byte. */
+ pms_flush();
+ return 0;
+ }
+
+ switch (state) {
+
+ case 0:
+ buttons = bus_io_read_1(pms_bc, pms_data_ioh, 0);
+ if ((buttons & 0xc0) == 0)
+ ++state;
+ break;
+
+ case 1:
+ dx = bus_io_read_1(pms_bc, pms_data_ioh, 0);
+ /* Bounding at -127 avoids a bug in XFree86. */
+ dx = (dx == -128) ? -127 : dx;
+ ++state;
+ break;
+
+ case 2:
+ dy = bus_io_read_1(pms_bc, pms_data_ioh, 0);
+ dy = (dy == -128) ? -127 : dy;
+ state = 0;
+
+ buttons = ((buttons & PS2LBUTMASK) << 2) |
+ ((buttons & (PS2RBUTMASK | PS2MBUTMASK)) >> 1);
+ changed = (buttons ^ sc->sc_status);
+ sc->sc_status = buttons;
+
+ if (dx || dy || changed)
+ ms_event(buttons, dx, dy);
+ break;
+ }
+
+ return -1;
+}
diff --git a/sys/arch/alpha/isa/spkrreg.h b/sys/arch/alpha/isa/spkrreg.h
new file mode 100644
index 00000000000..66bdf7f6651
--- /dev/null
+++ b/sys/arch/alpha/isa/spkrreg.h
@@ -0,0 +1,11 @@
+/* $NetBSD: spkrreg.h,v 1.1 1996/04/12 01:54:46 cgd Exp $ */
+
+/*
+ * PIT port addresses and speaker control values
+ */
+
+#define PITAUX_PORT 0x61 /* port of Programmable Peripheral Interface */
+#define PIT_ENABLETMR2 0x01 /* Enable timer/counter 2 */
+#define PIT_SPKRDATA 0x02 /* Direct to speaker */
+
+#define PIT_SPKR (PIT_ENABLETMR2|PIT_SPKRDATA)
diff --git a/sys/arch/alpha/isa/timerreg.h b/sys/arch/alpha/isa/timerreg.h
new file mode 100644
index 00000000000..04f2804f2b7
--- /dev/null
+++ b/sys/arch/alpha/isa/timerreg.h
@@ -0,0 +1,100 @@
+/* $NetBSD: timerreg.h,v 1.1 1996/04/12 01:54:56 cgd Exp $ */
+
+/*-
+ * Copyright (c) 1993 The Regents of the University of California.
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``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 REGENTS OR CONTRIBUTORS 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.
+ */
+
+/*
+ * Register definitions for the Intel 8253 Programmable Interval Timer.
+ *
+ * This chip has three independent 16-bit down counters that can be
+ * read on the fly. There are three mode registers and three countdown
+ * registers. The countdown registers are addressed directly, via the
+ * first three I/O ports. The three mode registers are accessed via
+ * the fourth I/O port, with two bits in the mode byte indicating the
+ * register. (Why are hardware interfaces always so braindead?).
+ *
+ * To write a value into the countdown register, the mode register
+ * is first programmed with a command indicating the which byte of
+ * the two byte register is to be modified. The three possibilities
+ * are load msb (TMR_MR_MSB), load lsb (TMR_MR_LSB), or load lsb then
+ * msb (TMR_MR_BOTH).
+ *
+ * To read the current value ("on the fly") from the countdown register,
+ * you write a "latch" command into the mode register, then read the stable
+ * value from the corresponding I/O port. For example, you write
+ * TMR_MR_LATCH into the corresponding mode register. Presumably,
+ * after doing this, a write operation to the I/O port would result
+ * in undefined behavior (but hopefully not fry the chip).
+ * Reading in this manner has no side effects.
+ *
+ * The outputs of the three timers are connected as follows:
+ *
+ * timer 0 -> irq 0
+ * timer 1 -> dma chan 0 (for dram refresh)
+ * timer 2 -> speaker (via keyboard controller)
+ *
+ * Timer 0 is used to call hardclock.
+ * Timer 2 is used to generate console beeps.
+ */
+
+/*
+ * Frequency of all three count-down timers; (TIMER_FREQ/freq) is the
+ * appropriate count to generate a frequency of freq hz.
+ */
+#ifndef TIMER_FREQ
+#define TIMER_FREQ 1193182
+#endif
+#define TIMER_DIV(x) ((TIMER_FREQ+(x)/2)/(x))
+
+/*
+ * Macros for specifying values to be written into a mode register.
+ */
+#define TIMER_CNTR0 0 /* timer 0 counter port */
+#define TIMER_CNTR1 1 /* timer 1 counter port */
+#define TIMER_CNTR2 2 /* timer 2 counter port */
+#define TIMER_MODE 3 /* timer mode port */
+#define TIMER_SEL0 0x00 /* select counter 0 */
+#define TIMER_SEL1 0x40 /* select counter 1 */
+#define TIMER_SEL2 0x80 /* select counter 2 */
+#define TIMER_INTTC 0x00 /* mode 0, intr on terminal cnt */
+#define TIMER_ONESHOT 0x02 /* mode 1, one shot */
+#define TIMER_RATEGEN 0x04 /* mode 2, rate generator */
+#define TIMER_SQWAVE 0x06 /* mode 3, square wave */
+#define TIMER_SWSTROBE 0x08 /* mode 4, s/w triggered strobe */
+#define TIMER_HWSTROBE 0x0a /* mode 5, h/w triggered strobe */
+#define TIMER_LATCH 0x00 /* latch counter for reading */
+#define TIMER_LSB 0x10 /* r/w counter LSB */
+#define TIMER_MSB 0x20 /* r/w counter MSB */
+#define TIMER_16BIT 0x30 /* r/w counter 16 bits, LSB first */
+#define TIMER_BCD 0x01 /* count in BCD */
+