diff options
author | Kenji Aoyama <aoyama@cvs.openbsd.org> | 2014-12-08 13:24:05 +0000 |
---|---|---|
committer | Kenji Aoyama <aoyama@cvs.openbsd.org> | 2014-12-08 13:24:05 +0000 |
commit | d71bffbfa96bf4e6799fcd075134d69f7c4a2f8c (patch) | |
tree | 77479be4dc99b14fd27742daf20cdccc1a3dc112 /sys/arch/luna88k | |
parent | dedad2d1a0ffc3db836cf6f1211a51cce0c7cf67 (diff) |
Add an intermediate layer driver, cbus(4), to manage its own
interrupts of PC-9801 extension board slot bus (so-called 'C-bus') on
LUNA-88K2.
Existing pcex(4) is now attached at cbus(4), i.e.
cbus0 at mainbus0
pcex0 at cbus0
With this driver, some other PC-9801 boards might be supported on luna88k
in the (near?) future:-)
ok miod@
Diffstat (limited to 'sys/arch/luna88k')
-rw-r--r-- | sys/arch/luna88k/conf/GENERIC | 5 | ||||
-rw-r--r-- | sys/arch/luna88k/conf/files.luna88k | 8 | ||||
-rw-r--r-- | sys/arch/luna88k/dev/cbus.c | 297 | ||||
-rw-r--r-- | sys/arch/luna88k/dev/cbusvar.h | 46 | ||||
-rw-r--r-- | sys/arch/luna88k/dev/pcex.c | 125 | ||||
-rw-r--r-- | sys/arch/luna88k/luna88k/mainbus.c | 9 |
6 files changed, 379 insertions, 111 deletions
diff --git a/sys/arch/luna88k/conf/GENERIC b/sys/arch/luna88k/conf/GENERIC index 9f9382661e4..45ff38d2b5e 100644 --- a/sys/arch/luna88k/conf/GENERIC +++ b/sys/arch/luna88k/conf/GENERIC @@ -1,4 +1,4 @@ -# $OpenBSD: GENERIC,v 1.17 2014/04/16 12:01:33 aoyama Exp $ +# $OpenBSD: GENERIC,v 1.18 2014/12/08 13:24:04 aoyama Exp $ # # For further information on compiling OpenBSD kernels, see the config(8) # man page. @@ -43,7 +43,8 @@ spc0 at mainbus0 spc1 at mainbus0 # PC-9801 extension board slot -pcex0 at mainbus0 +cbus0 at mainbus0 +pcex0 at cbus0 # Workstation Console attachments wsdisplay* at fb? diff --git a/sys/arch/luna88k/conf/files.luna88k b/sys/arch/luna88k/conf/files.luna88k index 249ad97a148..69b87de8953 100644 --- a/sys/arch/luna88k/conf/files.luna88k +++ b/sys/arch/luna88k/conf/files.luna88k @@ -1,4 +1,4 @@ -# $OpenBSD: files.luna88k,v 1.21 2014/11/08 21:18:42 aoyama Exp $ +# $OpenBSD: files.luna88k,v 1.22 2014/12/08 13:24:04 aoyama Exp $ # maxpartitions 16 @@ -65,8 +65,12 @@ file arch/luna88k/dev/mb89352.c spc #file arch/luna88k/dev/nec86hw.c pcm needs-flag #file arch/luna88k/dev/nec86_luna88k.c pcm needs-flag +device cbus {} +attach cbus at mainbus +file arch/luna88k/dev/cbus.c + device pcex -attach pcex at mainbus +attach pcex at cbus file arch/luna88k/dev/pcex.c pcex needs-flag # list of standard files diff --git a/sys/arch/luna88k/dev/cbus.c b/sys/arch/luna88k/dev/cbus.c new file mode 100644 index 00000000000..1f92b8f0ca5 --- /dev/null +++ b/sys/arch/luna88k/dev/cbus.c @@ -0,0 +1,297 @@ +/* $OpenBSD: cbus.c,v 1.1 2014/12/08 13:24:04 aoyama Exp $ */ + +/* + * Copyright (c) 2014 Kenji Aoyama. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * PC-9801 extension board slot bus ('C-bus') driver for LUNA-88K2. + */ + +#include <sys/param.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/systm.h> + +#include <machine/asm_macro.h> /* ff1() */ +#include <machine/autoconf.h> +#include <machine/board.h> /* PC_BASE */ + +#include <luna88k/dev/cbusvar.h> +#include <luna88k/luna88k/isr.h> /* isrlink_autovec() */ + +#if 0 +#define CBUS_DEBUG +#endif + +/* + * C-bus interrupt status register + */ +#define CBUS_INTR_STAT_REG (PC_BASE + 0x1100000) +volatile u_int8_t *cbus_isreg = (u_int8_t *)CBUS_INTR_STAT_REG; + +/* autoconf stuff */ +int cbus_match(struct device *, void *, void *); +void cbus_attach(struct device *, struct device *, void *); +int cbus_print(void *, const char *); + +struct cbus_softc { + struct device sc_dev; + struct cbus_isr_t cbus_isr[NCBUSISR]; + u_int8_t registered; +}; + +const struct cfattach cbus_ca = { + sizeof(struct cbus_softc), cbus_match, cbus_attach +}; + +struct cfdriver cbus_cd = { + NULL, "cbus", DV_DULL +}; + +/* prototypes */ +int cbus_isrlink(int (*)(void *), void *, int, const char *); +int cbus_isrunlink(int (*)(void *), int); +void cbus_isrdispatch(int); +int cbus_intr(void *); + +int +cbus_match(struct device *parent, void *cf, void *aux) +{ + struct mainbus_attach_args *ma = aux; + + if (strcmp(ma->ma_name, cbus_cd.cd_name)) + return 0; +#if 0 + if (badaddr((vaddr_t)ma->ma_addr, 4)) + return 0; +#endif + return 1; +} + +void +cbus_attach(struct device *parent, struct device *self, void *args) +{ + struct cbus_softc *sc = (struct cbus_softc *)self; + struct mainbus_attach_args *ma = args; + struct cbus_attach_args caa; + int i; + + for (i = 0; i < NCBUSISR; i++) { + sc->cbus_isr[i].isr_func = NULL; + /* clearing interrupt flags (INT0-INT6) */ + *cbus_isreg = (u_int8_t)i; + } + + /* register C-bus interrupt service routine on mainbus */ + isrlink_autovec(cbus_intr, (void *)self, ma->ma_ilvl, + ISRPRI_TTY, self->dv_xname); + + printf("\n"); + + caa.intlevel = -1; /* not specified */ + config_found(self, &caa, cbus_print); + return; +} + +int +cbus_print(void *aux, const char *pnp) +{ + struct cbus_attach_args *caa = aux; +#if 0 /* not yet */ + if (pnp) + printf("%s at %s", caa->name, pnp); /* not configured */ +#endif + if (caa->intlevel != -1) + printf(" INT %d", caa->intlevel); + + return UNCONF; +} + +/* + * Register a C-bus interrupt service routine. + */ +int +cbus_isrlink(int (*func)(void *), void *arg, int ipl, const char *name) +{ + struct cbus_softc *sc = NULL; + + if (cbus_cd.cd_ndevs != 0) + sc = cbus_cd.cd_devs[0]; + if (sc == NULL) + panic("cbus_isrlink: can't find cbus_softc"); + +#ifdef DIAGNOSTIC + if (ipl < 0 || ipl >= NCBUSISR) { + printf("cbus_isrlink: bad ipl %d\n", ipl); + return -1; + } +#endif + + if (sc->cbus_isr[ipl].isr_func != NULL) { + printf("cbus_isrlink: isr already assigned on INT%d\n", ipl); + return -1; + } + + /* set the entry */ + sc->cbus_isr[ipl].isr_func = func; + sc->cbus_isr[ipl].isr_arg = arg; + evcount_attach(&(sc->cbus_isr[ipl].isr_count), name, &ipl); + sc->registered |= (1 << (6 - ipl)); +#ifdef CBUS_DEBUG + printf("cbus_isrlink: sc->registered = 0x%02x\n", sc->registered); +#endif + + return 0; +} + +/* + * Unregister a C-bus interrupt service routine. + */ +int +cbus_isrunlink(int (*func)(void *), int ipl) +{ + struct cbus_softc *sc = NULL; + + if (cbus_cd.cd_ndevs != 0) + sc = cbus_cd.cd_devs[0]; + if (sc == NULL) + panic("cbus_isrunlink: can't find cbus_softc"); + +#ifdef DIAGNOSTIC + if (ipl < 0 || ipl >= NCBUSISR) { + printf("cbus_isrunlink: bad ipl %d\n", ipl); + return -1; + } +#endif + + if (sc->cbus_isr[ipl].isr_func == NULL) { + printf("cbus_isrunlink: isr not assigned on INT%d\n", ipl); + return -1; + } + + /* reset the entry */ + sc->cbus_isr[ipl].isr_func = NULL; + sc->cbus_isr[ipl].isr_arg = NULL; + evcount_detach(&(sc->cbus_isr[ipl].isr_count)); + sc->registered &= ~(1 << (6 - ipl)); +#ifdef CBUS_DEBUG + printf("cbus_isrunlink: sc->registered = 0x%02x\n", sc->registered); +#endif + + return 0; +} + +/* + * Dispatch C-bus interrupt service routines. + */ +void +cbus_isrdispatch(int ipl) +{ + int rc; + static int straycount, unexpected; + struct cbus_softc *sc = NULL; + + if (cbus_cd.cd_ndevs != 0) + sc = cbus_cd.cd_devs[0]; + if (sc == NULL) + panic("cbus_isrdispatch: can't find cbus_softc"); + +#ifdef DIAGNOSTIC + if (ipl < 0 || ipl >= NCBUSISR) + panic("cbus_isrdispatch: bad ipl 0x%d", ipl); +#endif + + if (sc->cbus_isr[ipl].isr_func == NULL) { + printf("cbus_isrdispatch: ipl %d unexpected\n", ipl); + if (++unexpected > 10) + panic("too many unexpected interrupts"); + return; + } + + rc = sc->cbus_isr[ipl].isr_func(sc->cbus_isr[ipl].isr_arg); + if (rc != 0) + sc->cbus_isr[ipl].isr_count.ec_count++; + + if (rc) + straycount = 0; + else if (++straycount > 50) + panic("cbus_isrdispatch: too many stray interrupts"); + else + printf("cbus_isrdispatch: stray level %d interrupt\n", ipl); +} + +/* + * Note about interrupt on PC-9801 extension board slot + * + * PC-9801 extension board slot bus (so-called 'C-bus' in Japan) use 8 own + * interrupt levels, INT0-INT6, and NMI. On LUNA-88K2, they all trigger + * level 4 interrupt on mainbus, so we need to check the dedicated interrupt + * status register to know which C-bus interrupt is occurred. + * + * The interrupt status register for C-bus is located at + * (u_int8_t *)CBUS_INTR_STAT. Each bit of the register becomes 0 when + * corresponding C-bus interrupt has occurred, otherwise 1. + * + * bit 7 = NMI(?) + * bit 6 = INT0 + * bit 5 = INT1 + * : + * bit 0 = INT6 + * + * To clear the C-bus interrupt flag, write the corresponding 'bit' number + * (as u_int_8) to the register. For example, if you want to clear INT1, + * you should write '5' like: + * *(u_int8_t *)CBUS_INTR_STAT = 5; + */ + +/* + * Interrupt handler on mainbus. + */ +int +cbus_intr(void *arg) +{ + struct cbus_softc *sc = (struct cbus_softc *)arg; + u_int8_t intr_status; + int n; + + /* + * LUNA-88K2's interrupt level 4 is shared with other devices, + * such as le(4), for example. So we check: + * - the value of our C-bus interrupt status register, and + * - if the INT level is what we are looking for. + */ + intr_status = *cbus_isreg & sc->registered; + if (intr_status == sc->registered) return 0; /* Not for me */ + +#ifdef CBUS_DEBUG + printf("cbus_intr: called, *cbus_isreg=0x%02x, registered = 0x%02x\n", + *cbus_isreg, sc->registered); +#endif + /* Make the bit pattern that we should proces */ + intr_status = intr_status ^ sc->registered; +#ifdef CBUS_DEBUG + printf("cbus_intr: processing 0x%02x\n", intr_status); +#endif + + /* Process, and clear each interrupt flag */ + while ((n = ff1(intr_status)) != 32) { + cbus_isrdispatch(6 - n); + *cbus_isreg = (u_int8_t)n; + intr_status &= ~(1 << n); + } + + return 1; +} diff --git a/sys/arch/luna88k/dev/cbusvar.h b/sys/arch/luna88k/dev/cbusvar.h new file mode 100644 index 00000000000..c73e8629223 --- /dev/null +++ b/sys/arch/luna88k/dev/cbusvar.h @@ -0,0 +1,46 @@ +/* $OpenBSD: cbusvar.h,v 1.1 2014/12/08 13:24:04 aoyama Exp $ */ + +/* + * Copyright (c) 2014 Kenji Aoyama. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * PC-9801 extension board slot bus ('C-bus') driver for LUNA-88K2. + */ + +#include <sys/evcount.h> +#include <sys/queue.h> + +/* + * Currently 7 level C-bus interrupts (INT0 - INT6) are supported. + */ +#define NCBUSISR 7 + +/* + * C-bus interrupt handler + */ +struct cbus_isr_t { + int (*isr_func)(void *); + void *isr_arg; + struct evcount isr_count; +}; + +int cbus_isrlink(int (*)(void *), void *, int, const char *); +int cbus_isrunlink(int (*)(void *), int); +void cbus_isrdispatch(int); + +struct cbus_attach_args { + int intlevel; +}; diff --git a/sys/arch/luna88k/dev/pcex.c b/sys/arch/luna88k/dev/pcex.c index a2c825ab81c..82e8d19abac 100644 --- a/sys/arch/luna88k/dev/pcex.c +++ b/sys/arch/luna88k/dev/pcex.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pcex.c,v 1.3 2014/05/17 10:06:43 aoyama Exp $ */ +/* $OpenBSD: pcex.c,v 1.4 2014/12/08 13:24:04 aoyama Exp $ */ /* * Copyright (c) 2014 Kenji Aoyama. @@ -25,16 +25,12 @@ #include <sys/device.h> #include <sys/ioctl.h> -#include <machine/asm_macro.h> /* ff1() */ #include <machine/autoconf.h> #include <machine/board.h> /* PC_BASE */ #include <machine/conf.h> -#include <machine/intr.h> #include <machine/pcex.h> -#include <uvm/uvm_extern.h> - -#include <luna88k/luna88k/isr.h> +#include <luna88k/dev/cbusvar.h> extern int hz; @@ -44,23 +40,6 @@ extern int hz; #define PCEXMEM_BASE PC_BASE #define PCEXIO_BASE (PC_BASE + 0x1000000) -#define CBUS_ISR (PC_BASE + 0x1100000) - -/* - * C-bus Interrupt Status Register - */ -volatile u_int8_t *cisr = (u_int8_t *)CBUS_ISR; - -const u_int8_t cisr_int_bits[] = { - 0x40, /* INT 0 */ - 0x20, /* INT 1 */ - 0x10, /* INT 2 */ - 0x08, /* INT 3 */ - 0x04, /* INT 4 */ - 0x02, /* INT 5 */ - 0x01 /* INT 6 */ -/* 0x80 NMI(?), not supported in this driver now */ -}; /* autoconf stuff */ int pcex_match(struct device *, void *, void *); @@ -68,7 +47,7 @@ void pcex_attach(struct device *, struct device *, void *); struct pcex_softc { struct device sc_dev; - u_int8_t int_bits; + int intr_use[NCBUSISR]; }; const struct cfattach pcex_ca = { @@ -88,34 +67,20 @@ int pcex_wait_int(struct pcex_softc *, u_int); int pcex_match(struct device *parent, void *cf, void *aux) { - struct mainbus_attach_args *ma = aux; - - if (strcmp(ma->ma_name, pcex_cd.cd_name)) - return 0; -#if 0 - if (badaddr((vaddr_t)ma->ma_addr, 4)) - return 0; -#endif - return 1; + return 1; /* XXX: always matched */ } void pcex_attach(struct device *parent, struct device *self, void *args) { struct pcex_softc *sc = (struct pcex_softc *)self; - struct mainbus_attach_args *ma = args; - u_int8_t i; + int i; - sc->int_bits = 0x00; - - /* make sure of clearing interrupt flags for INT0-INT6 */ - for (i = 0; i < 7; i++) - *cisr = i; - - isrlink_autovec(pcex_intr, (void *)self, ma->ma_ilvl, - ISRPRI_TTY, self->dv_xname); + for (i = 0; i < NCBUSISR; i++) + sc->intr_use[i] = 0; printf("\n"); + return; } int @@ -190,8 +155,12 @@ pcex_set_int(struct pcex_softc *sc, u_int level) { if (level > 6) return EINVAL; + if (sc->intr_use[level] != 0) + return EINVAL; /* Duplicate */ - sc->int_bits |= cisr_int_bits[level]; + sc->intr_use[level] = 1; + cbus_isrlink(pcex_intr, &(sc->intr_use[level]), level, + sc->sc_dev.dv_xname); return 0; } @@ -201,8 +170,11 @@ pcex_reset_int(struct pcex_softc *sc, u_int level) { if (level > 6) return EINVAL; + if (sc->intr_use[level] == 0) + return EINVAL; /* Not registered */ - sc->int_bits &= ~cisr_int_bits[level]; + sc->intr_use[level] = 0; + cbus_isrunlink(pcex_intr, level); return 0; } @@ -214,74 +186,27 @@ pcex_wait_int(struct pcex_softc *sc, u_int level) if (level > 6) return EINVAL; + if (sc->intr_use[level] == 0) + return EINVAL; /* Not registered */ + + ret = tsleep(&(sc->intr_use[level]), PWAIT | PCATCH, "pcex", + hz /* XXX: 1 sec. */); - ret = tsleep((void *)sc, PWAIT | PCATCH, "pcex", hz /* XXX: 1 sec. */); #ifdef PCEX_DEBUG if (ret == EWOULDBLOCK) - printf("%s: timeout in tsleep\n", __func__); + printf("pcex_wait_int: timeout in tsleep\n"); #endif return ret; } -/* - * Note about interrupt on PC-9801 extension board slot - * - * PC-9801 extension board slot bus (so-called 'C-bus' in Japan) use 8 own - * interrupt levels, INT0-INT6, and NMI. On LUNA-88K2, they all trigger - * level 4 interrupt, so we need to check the dedicated interrupt status - * register to know which C-bus interrupt is occurred. - * - * The interrupt status register for C-bus is located at (u_int8_t *)CBUS_ISR. - * Each bit of the register becomes 0 when corresponding C-bus interrupt has - * occurred, otherwise 1. - * - * bit 7 = NMI(?) - * bit 6 = INT0 - * bit 5 = INT1 - * : - * bit 0 = INT6 - * - * To clear the C-bus interrupt flag, write the corresponding 'bit' number - * (as u_int_8) to the register. For example, if you want to clear INT1, - * you should write '5' like: - * *(u_int8_t *)CBUS_ISR = 5; - */ - -/* - * Interrupt handler - */ int pcex_intr(void *arg) { - struct pcex_softc *sc = (struct pcex_softc *)arg; - u_int8_t int_status; - int n; - - /* - * LUNA-88K2's interrupt level 4 is shared with other devices, - * such as le(4), for example. So we check: - * - the value of our C-bus interrupt status register, and - * - if the INT level is what we are looking for. - */ - int_status = *cisr & sc->int_bits; - if (int_status == sc->int_bits) return 0; /* Not for me */ - #ifdef PCEX_DEBUG - printf("%s: called, *cisr=0x%02x, int_bits = 0x%02x\n", - __func__, *cisr, sc->int_bits); + printf("pcex_intr: called, arg=%p\n", arg); #endif - /* Just wakeup(9) for now */ - wakeup((void *)sc); - - /* Make the bit pattern that we should clear interrupt flag */ - int_status = int_status ^ sc->int_bits; - - /* Clear each interrupt flag */ - while ((n = ff1(int_status)) != 32) { - *cisr = (u_int8_t)n; - int_status &= ~(1 << n); - } + wakeup(arg); return 1; } diff --git a/sys/arch/luna88k/luna88k/mainbus.c b/sys/arch/luna88k/luna88k/mainbus.c index da163a051e1..30a17e7b90a 100644 --- a/sys/arch/luna88k/luna88k/mainbus.c +++ b/sys/arch/luna88k/luna88k/mainbus.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mainbus.c,v 1.11 2014/05/08 13:31:00 aoyama Exp $ */ +/* $OpenBSD: mainbus.c,v 1.12 2014/12/08 13:24:04 aoyama Exp $ */ /* $NetBSD: mainbus.c,v 1.2 2000/01/07 05:13:08 nisimura Exp $ */ /*- @@ -54,12 +54,7 @@ static const struct mainbus_attach_args devs[] = { { "fb", 0xc1100000, -1, LUNA_88K|LUNA_88K2 }, /* BrookTree RAMDAC */ { "spc", 0xe1000000, 3, LUNA_88K|LUNA_88K2 }, /* MB89352 */ { "spc", 0xe1000040, 3, LUNA_88K2 }, /* ditto, LUNA-88K2 only */ -#if NPCM > 0 - { "pcm", 0x91000000, 4, LUNA_88K2 }, /* NEC-9801-86 Sound board (under testing) */ -#endif -#if NPCEX > 0 - { "pcex", 0x91000000, 4, LUNA_88K2 }, /* PC-9801 extension slot */ -#endif + { "cbus", 0x91000000, 4, LUNA_88K2 }, /* PC-9801 extension slot */ }; void mainbus_attach(struct device *, struct device *, void *); |