diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2006-05-09 18:14:34 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2006-05-09 18:14:34 +0000 |
commit | 8421d0b16c28fb92cbc740972557e19380c75a72 (patch) | |
tree | 9bb1a646704aace8f40f4127436a7dfc4f233203 | |
parent | c1df95c0790333c06a9f179bfb2a40c48af6e600 (diff) |
Oops, correct import this time.
-rw-r--r-- | sys/arch/aviion/conf/files.aviion | 55 | ||||
-rw-r--r-- | sys/arch/aviion/dev/dart.c | 1039 | ||||
-rw-r--r-- | sys/arch/aviion/dev/dart_syscon.c | 103 | ||||
-rw-r--r-- | sys/arch/aviion/dev/if_le_syscon.c | 172 | ||||
-rw-r--r-- | sys/arch/aviion/dev/mainbus.c | 163 | ||||
-rw-r--r-- | sys/arch/aviion/dev/syscon.c | 201 | ||||
-rw-r--r-- | sys/arch/aviion/dev/vme.c | 550 |
7 files changed, 2283 insertions, 0 deletions
diff --git a/sys/arch/aviion/conf/files.aviion b/sys/arch/aviion/conf/files.aviion new file mode 100644 index 00000000000..072f95ddf85 --- /dev/null +++ b/sys/arch/aviion/conf/files.aviion @@ -0,0 +1,55 @@ +# $OpenBSD: files.aviion,v 1.1 2006/05/09 18:14:33 miod Exp $ +# +maxpartitions 16 + +device mainbus {[addr = -1]} +attach mainbus at root + +device syscon {[offset = -1], [ipl = 0]} +attach syscon at mainbus +file arch/aviion/dev/syscon.c syscon needs-flag + +device nvram +attach nvram at syscon +file arch/aviion/dev/nvram.c nvram needs-flag + +device dart: tty +attach dart at syscon with dart_syscon +file arch/aviion/dev/dart.c dart needs-flag +file arch/aviion/dev/dart_syscon.c dart_syscon + +attach le at syscon with le_syscon +file arch/aviion/dev/if_le_syscon.c le_syscon + +include "../../../scsi/files.scsi" + +major {sd = 4} +major {st = 5} +major {cd = 6} +major {rd = 7} +major {vnd = 8} + +device vme {[a16 = -1], [a24 = -1], [a32 = -1], [ipl = -1]} +attach vme at syscon +file arch/aviion/dev/vme.c vme needs-flag + +attach le at vme with le_vme +file arch/aviion/dev/if_le_vme.c le_vme + +# list of standard files +file dev/cninit.c + +file arch/aviion/aviion/autoconf.c +#file arch/aviion/aviion/bus_dma.c +file arch/aviion/aviion/conf.c +file arch/aviion/aviion/db_machdep.c ddb +file arch/aviion/aviion/disksubr.c +file arch/aviion/aviion/eh.S +file arch/aviion/aviion/machdep.c +file arch/aviion/aviion/av400_machdep.c av400 +file arch/aviion/aviion/m8820x.c m88100 +file arch/aviion/aviion/mem.c +file arch/aviion/aviion/pmap_bootstrap.c +file arch/aviion/aviion/pmap_table.c +file arch/aviion/aviion/prom.c +file arch/aviion/dev/mainbus.c diff --git a/sys/arch/aviion/dev/dart.c b/sys/arch/aviion/dev/dart.c new file mode 100644 index 00000000000..ccbca07b568 --- /dev/null +++ b/sys/arch/aviion/dev/dart.c @@ -0,0 +1,1039 @@ +/* $OpenBSD: dart.c,v 1.1 2006/05/09 18:13:32 miod Exp $ */ + +/* + * Mach Operating System + * Copyright (c) 1993-1991 Carnegie Mellon University + * All Rights Reserved. + * + * 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 AND OMRON ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS IS" + * CONDITION. CARNEGIE MELLON AND OMRON DISCLAIM 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/ioctl.h> +#include <sys/proc.h> +#include <sys/tty.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/syslog.h> + +#include <machine/autoconf.h> +#include <machine/conf.h> +#include <machine/cpu.h> + +#include <dev/cons.h> + +#include <machine/av400.h> +#include <aviion/dev/sysconreg.h> +#include <aviion/dev/dartreg.h> +#include <aviion/dev/dartvar.h> + +#ifdef DDB +#include <ddb/db_var.h> +#endif + +struct cfdriver dart_cd = { + NULL, "dart", DV_TTY +}; + +/* console is on the first port */ +#define CONS_PORT A_PORT +#ifdef USE_PROM_CONSOLE +#define dartcn_sv sc->sc_sv_reg_storage +#else +struct dart_sv_reg dartcn_sv; +#endif + +/* prototypes */ +cons_decl(dart); +int dart_speed(int); +struct tty *darttty(dev_t); +void dartstart(struct tty *); +int dartmctl(struct dartsoftc *, int, int, int); +int dartparam(struct tty *, struct termios *); +void dartmodemtrans(struct dartsoftc *, unsigned int, unsigned int); +void dartrint(struct dartsoftc *, int); +void dartxint(struct dartsoftc *, int); + +/* + * DUART registers are mapped as the least-significant byte of 32-bit + * addresses. The following macros hide this. + */ + +#define dart_read(sc, reg) \ + bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, 3 + ((reg) << 2)) +#define dart_write(sc, reg, val) \ + bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, 3 + ((reg) << 2), (val)) + +#define DART_CHIP(dev) (minor(dev) >> 1) +#define DART_PORT(dev) (minor(dev) & 1) + +void +dart_common_attach(struct dartsoftc *sc) +{ + if (sc->sc_console) { + sc->sc_sv_reg = &dartcn_sv; + + if (A_PORT != CONS_PORT) { + sc->sc_sv_reg->sv_mr1[A_PORT] = PARDIS | RXRTS | CL8; + sc->sc_sv_reg->sv_mr2[A_PORT] = /* TXCTS | */ SB1; + sc->sc_sv_reg->sv_csr[A_PORT] = BD9600; + sc->sc_sv_reg->sv_cr[A_PORT] = TXEN | RXEN; + sc->sc_sv_reg->sv_opr |= OPDTRA | OPRTSA; + } else { + sc->sc_sv_reg->sv_mr1[B_PORT] = PARDIS | RXRTS | CL8; + sc->sc_sv_reg->sv_mr2[B_PORT] = /* TXCTS | */ SB1; + sc->sc_sv_reg->sv_csr[B_PORT] = BD9600; + sc->sc_sv_reg->sv_cr[B_PORT] = TXEN | RXEN; + sc->sc_sv_reg->sv_opr |= OPDTRB | OPRTSB; + } + } else { + sc->sc_sv_reg = &sc->sc_sv_reg_storage; + + sc->sc_sv_reg->sv_mr1[A_PORT] = PARDIS | RXRTS | CL8; + sc->sc_sv_reg->sv_mr2[A_PORT] = /* TXCTS | */ SB1; + sc->sc_sv_reg->sv_csr[A_PORT] = BD9600; + sc->sc_sv_reg->sv_cr[A_PORT] = TXEN | RXEN; + + sc->sc_sv_reg->sv_mr1[B_PORT] = PARDIS | RXRTS | CL8; + sc->sc_sv_reg->sv_mr2[B_PORT] = /* TXCTS | */ SB1; + sc->sc_sv_reg->sv_csr[B_PORT] = BD9600; + sc->sc_sv_reg->sv_cr[B_PORT] = TXEN | RXEN; + + sc->sc_sv_reg->sv_opr = OPDTRA | OPRTSA | OPDTRB | OPRTSB; + + /* Start out with Tx and RX interrupts disabled */ + /* Enable input port change interrupt */ + sc->sc_sv_reg->sv_imr = IIPCHG; + } + + /* reset port a */ + if (sc->sc_console == 0 || CONS_PORT != A_PORT) { + dart_write(sc, DART_CRA, RXRESET | TXDIS | RXDIS); + DELAY_CR; + dart_write(sc, DART_CRA, TXRESET | TXDIS | RXDIS); + DELAY_CR; + dart_write(sc, DART_CRA, ERRRESET | TXDIS | RXDIS); + DELAY_CR; + dart_write(sc, DART_CRA, BRKINTRESET | TXDIS | RXDIS); + DELAY_CR; + dart_write(sc, DART_CRA, MRRESET | TXDIS | RXDIS); +#if 0 + DELAY_CR; +#endif + + dart_write(sc, DART_MR1A, sc->sc_sv_reg->sv_mr1[A_PORT]); + dart_write(sc, DART_MR2A, sc->sc_sv_reg->sv_mr2[A_PORT]); + dart_write(sc, DART_CSRA, sc->sc_sv_reg->sv_csr[A_PORT]); + dart_write(sc, DART_CRA, sc->sc_sv_reg->sv_cr[A_PORT]); + } + + /* reset port b */ + if (sc->sc_console == 0 || CONS_PORT != B_PORT) { + dart_write(sc, DART_CRB, RXRESET | TXDIS | RXDIS); + DELAY_CR; + dart_write(sc, DART_CRB, TXRESET | TXDIS | RXDIS); + DELAY_CR; + dart_write(sc, DART_CRB, ERRRESET | TXDIS | RXDIS); + DELAY_CR; + dart_write(sc, DART_CRB, BRKINTRESET | TXDIS | RXDIS); + DELAY_CR; + dart_write(sc, DART_CRB, MRRESET | TXDIS | RXDIS); +#if 0 + DELAY_CR; +#endif + + dart_write(sc, DART_MR1B, sc->sc_sv_reg->sv_mr1[B_PORT]); + dart_write(sc, DART_MR2B, sc->sc_sv_reg->sv_mr2[B_PORT]); + dart_write(sc, DART_CSRB, sc->sc_sv_reg->sv_csr[B_PORT]); + dart_write(sc, DART_CRB, sc->sc_sv_reg->sv_cr[B_PORT]); + } + + /* initialize common register of a DUART */ + dart_write(sc, DART_OPRS, sc->sc_sv_reg->sv_opr); + +#if 0 + dart_write(sc, DART_CTUR, SLCTIM >> 8); + dart_write(sc, DART_CTLR, SLCTIM & 0xff); + dart_write(sc, DART_ACR, BDSET2 | CCLK16 | IPDCDIB | IPDCDIA); +#endif + dart_write(sc, DART_IMR, sc->sc_sv_reg->sv_imr); +#if 0 + dart_write(sc, DART_OPCR, OPSET); +#endif +#if 0 + dart_write(sc, DART_IVR, SYSCON_VECT + SYSCV_SCC); +#endif + + sc->sc_dart[A_PORT].tty = sc->sc_dart[B_PORT].tty = NULL; + sc->sc_dart[A_PORT].dart_swflags = sc->sc_dart[B_PORT].dart_swflags = 0; + if (sc->sc_console) + sc->sc_dart[CONS_PORT].dart_swflags |= TIOCFLAG_SOFTCAR; + + printf("\n"); +} + +/* speed tables */ +const struct dart_s { + int kspeed; + int dspeed; +} dart_speeds[] = { + { B0, 0 }, /* 0 baud, special HUP condition */ + { B50, NOBAUD }, /* 50 baud, not implemented */ + { B75, BD75 }, /* 75 baud */ + { B110, BD110 }, /* 110 baud */ + { B134, BD134 }, /* 134.5 baud */ + { B150, BD150 }, /* 150 baud */ + { B200, NOBAUD }, /* 200 baud, not implemented */ + { B300, BD300 }, /* 300 baud */ + { B600, BD600 }, /* 600 baud */ + { B1200, BD1200 }, /* 1200 baud */ + { B1800, BD1800 }, /* 1800 baud */ + { B2400, BD2400 }, /* 2400 baud */ + { B4800, BD4800 }, /* 4800 baud */ + { B9600, BD9600 }, /* 9600 baud */ + { B19200, BD19200 }, /* 19200 baud */ + { -1, NOBAUD }, /* anything more is uncivilized */ +}; + +int +dart_speed(int speed) +{ + const struct dart_s *ds; + + for (ds = dart_speeds; ds->kspeed != -1; ds++) + if (ds->kspeed == speed) + return ds->dspeed; + + return NOBAUD; +} + +struct tty * +darttty(dev_t dev) +{ + u_int port, chip; + struct dartsoftc *sc; + + chip = DART_CHIP(dev); + port = DART_PORT(dev); + if (dart_cd.cd_ndevs <= chip || port >= NDARTPORTS) + return (NULL); + + sc = (struct dartsoftc *)dart_cd.cd_devs[chip]; + if (sc == NULL) + return (NULL); + + return sc->sc_dart[port].tty; +} + +void +dartstart(struct tty *tp) +{ + struct dartsoftc *sc; + dev_t dev; + int s; + u_int port, chip; + int c, tries; + bus_addr_t ptaddr; + + if ((tp->t_state & TS_ISOPEN) == 0) + return; + + dev = tp->t_dev; + chip = DART_CHIP(dev); + port = DART_PORT(dev); + sc = (struct dartsoftc *)dart_cd.cd_devs[chip]; + ptaddr = port == A_PORT ? DART_A_BASE : DART_B_BASE; + + s = spltty(); + + if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) + goto bail; + + if (tp->t_outq.c_cc <= tp->t_lowat) { + if (tp->t_state & TS_ASLEEP) { + tp->t_state &= ~TS_ASLEEP; + wakeup((caddr_t)&tp->t_outq); + } + selwakeup(&tp->t_wsel); + if (tp->t_outq.c_cc == 0) + goto bail; + } + + tp->t_state |= TS_BUSY; + while (tp->t_outq.c_cc != 0) { + + /* load transmitter until it is full */ + for (tries = 10000; tries != 0; tries --) + if (dart_read(sc, ptaddr + DART_SRA) & TXRDY) + break; + + if (tries == 0) { + timeout_add(&tp->t_rstrt_to, 1); + tp->t_state |= TS_TIMEOUT; + break; + } else { + c = getc(&tp->t_outq); + + dart_write(sc, ptaddr + DART_TBA, c & 0xff); + + sc->sc_sv_reg->sv_imr |= + port == A_PORT ? ITXRDYA : ITXRDYB; + dart_write(sc, DART_IMR, sc->sc_sv_reg->sv_imr); + } + } + tp->t_state &= ~TS_BUSY; + +bail: + splx(s); +} + +int +dartstop(struct tty *tp, int flag) +{ + int s; + + s = spltty(); + if (tp->t_state & TS_BUSY) { + if ((tp->t_state & TS_TTSTOP) == 0) + tp->t_state |= TS_FLUSH; + } + splx(s); + + return 0; +} + +/* + * To be called at spltty - tty already locked. + * Returns status of carrier. + */ +int +dartmctl(struct dartsoftc *sc, int port, int flags, int how) +{ + int newflags, flagsmask; + struct dart_info *dart; + int s; + + dart = &sc->sc_dart[port]; + + s = spltty(); + + flagsmask = port == A_PORT ? (OPDTRA | OPRTSA) : (OPDTRB | OPRTSB); + newflags = (flags & TIOCM_DTR ? (OPDTRA | OPDTRB) : 0) | + (flags & TIOCM_RTS ? (OPRTSA | OPRTSB) : 0); + newflags &= flagsmask; /* restrict to the port we are acting on */ + + switch (how) { + case DMSET: + dart_write(sc, DART_OPRS, newflags); + dart_write(sc, DART_OPRR, ~newflags); + /* only replace the sv_opr bits for the port we are acting on */ + sc->sc_sv_reg->sv_opr &= ~flagsmask; + sc->sc_sv_reg->sv_opr |= newflags; + break; + case DMBIS: + dart_write(sc, DART_OPRS, newflags); + sc->sc_sv_reg->sv_opr |= newflags; + break; + case DMBIC: + dart_write(sc, DART_OPRR, newflags); + sc->sc_sv_reg->sv_opr &= ~newflags; + break; + case DMGET: + flags = 0; + if (port == A_PORT) { + if (sc->sc_sv_reg->sv_opr & OPDTRA) + flags |= TIOCM_DTR; + if (sc->sc_sv_reg->sv_opr & OPRTSA) + flags |= TIOCM_RTS; + } else { + if (sc->sc_sv_reg->sv_opr & OPDTRB) + flags |= TIOCM_DTR; + if (sc->sc_sv_reg->sv_opr & OPRTSB) + flags |= TIOCM_RTS; + } + break; + } + + splx(s); + return (flags); +} + +int +dartioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) +{ + int error; + u_int port, chip; + struct tty *tp; + struct dart_info *dart; + struct dartsoftc *sc; + + chip = DART_CHIP(dev); + port = DART_PORT(dev); + sc = (struct dartsoftc *)dart_cd.cd_devs[chip]; + dart = &sc->sc_dart[port]; + + tp = dart->tty; + if (tp == NULL) + return (ENXIO); + + error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, p); + if (error >= 0) + return(error); + + error = ttioctl(tp, cmd, data, flag, p); + if (error >= 0) + return(error); + + switch (cmd) { + case TIOCSBRK: + case TIOCCBRK: + break; + case TIOCSDTR: + (void)dartmctl(sc, port, TIOCM_DTR | TIOCM_RTS, DMBIS); + break; + case TIOCCDTR: + (void)dartmctl(sc, port, TIOCM_DTR | TIOCM_RTS, DMBIC); + break; + case TIOCMSET: + (void)dartmctl(sc, port, *(int *) data, DMSET); + break; + case TIOCMBIS: + (void)dartmctl(sc, port, *(int *) data, DMBIS); + break; + case TIOCMBIC: + (void)dartmctl(sc, port, *(int *) data, DMBIC); + break; + case TIOCMGET: + *(int *)data = dartmctl(sc, port, 0, DMGET); + break; + case TIOCGFLAGS: + *(int *)data = dart->dart_swflags; + break; + case TIOCSFLAGS: + error = suser(p, 0); + if (error != 0) + return (EPERM); + + dart->dart_swflags = *(int *)data; + dart->dart_swflags &= /* only allow valid flags */ + (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | TIOCFLAG_CRTSCTS); + break; + default: + return (ENOTTY); + } + + return (0); +} + +int +dartparam(struct tty *tp, struct termios *t) +{ + int flags; + u_int port, chip; + int speeds; + unsigned char mr1, mr2; + struct dart_info *dart; + struct dartsoftc *sc; + dev_t dev; + bus_addr_t ptaddr; + + dev = tp->t_dev; + chip = DART_CHIP(dev); + port = DART_PORT(dev); + sc = (struct dartsoftc *)dart_cd.cd_devs[chip]; + dart = &sc->sc_dart[port]; + ptaddr = port == A_PORT ? DART_A_BASE : DART_B_BASE; + + tp->t_ispeed = t->c_ispeed; + tp->t_ospeed = t->c_ospeed; + tp->t_cflag = t->c_cflag; + + flags = tp->t_flags; + + /* Reset to make global changes*/ + /* disable Tx and Rx */ + + if (sc->sc_console == 0 || CONS_PORT != port) { + if (port == A_PORT) + sc->sc_sv_reg->sv_imr &= ~(ITXRDYA | IRXRDYA); + else + sc->sc_sv_reg->sv_imr &= ~(ITXRDYB | IRXRDYB); + dart_write(sc, DART_IMR, sc->sc_sv_reg->sv_imr); + + /* hang up on zero baud rate */ + if (tp->t_ispeed == 0) { + dartmctl(sc, port, HUPCL, DMSET); + return (0); + } else { + /* set baudrate */ + speeds = dart_speed(tp->t_ispeed); + if (speeds == NOBAUD) + speeds = sc->sc_sv_reg->sv_csr[port]; + dart_write(sc, ptaddr + DART_CSRA, speeds); + sc->sc_sv_reg->sv_csr[port] = speeds; + } + + /* get saved mode registers and clear set up parameters */ + mr1 = sc->sc_sv_reg->sv_mr1[port]; + mr1 &= ~(CLMASK | PARTYPEMASK | PARMODEMASK); + + mr2 = sc->sc_sv_reg->sv_mr2[port]; + mr2 &= ~SBMASK; + + /* set up character size */ + switch (t->c_cflag & CSIZE) { + case CL8: + mr1 |= CL8; + break; + case CL7: + mr1 |= CL7; + break; + case CL6: + mr1 |= CL6; + break; + case CL5: + mr1 |= CL5; + break; + } + + /* set up stop bits */ + if (tp->t_ospeed == B110) + mr2 |= SB2; + else + mr2 |= SB1; + + /* set up parity */ + if (t->c_cflag & PARENB) { + mr1 |= PAREN; + if (t->c_cflag & PARODD) + mr1 |= ODDPAR; + else + mr1 |= EVENPAR; + } else + mr1 |= PARDIS; + + if (sc->sc_sv_reg->sv_mr1[port] != mr1 || + sc->sc_sv_reg->sv_mr2[port] != mr2) { + /* write mode registers to duart */ + dart_write(sc, ptaddr + DART_CRA, MRRESET); + dart_write(sc, ptaddr + DART_MR1A, mr1); + dart_write(sc, ptaddr + DART_MR2A, mr2); + + /* save changed mode registers */ + sc->sc_sv_reg->sv_mr1[port] = mr1; + sc->sc_sv_reg->sv_mr2[port] = mr2; + } + } + + /* enable transmitter? */ + if (tp->t_state & TS_BUSY) { + sc->sc_sv_reg->sv_imr |= port == A_PORT ? ITXRDYA : ITXRDYB; + dart_write(sc, DART_IMR, sc->sc_sv_reg->sv_imr); + } + + /* re-enable the receiver */ +#if 0 + DELAY_CR; +#endif + sc->sc_sv_reg->sv_imr |= port == A_PORT ? IRXRDYA : IRXRDYB; + dart_write(sc, DART_IMR, sc->sc_sv_reg->sv_imr); + + return (0); +} + +void +dartmodemtrans(struct dartsoftc *sc, unsigned int ip, unsigned int ipcr) +{ + unsigned int dcdstate; + struct tty *tp; + int port; + struct dart_info *dart; + + /* input is inverted at port!!! */ + if (ipcr & IPCRDCDA) { + port = A_PORT; + dcdstate = !(ip & IPDCDA); + } else if (ipcr & IPCRDCDB) { + port = B_PORT; + dcdstate = !(ip & IPDCDB); + } else { +#ifdef DIAGNOSTIC + printf("dartmodemtrans: unknown transition ip=0x%x ipcr=0x%x\n", + ip, ipcr); +#endif + return; + } + + dart = &sc->sc_dart[port]; + tp = dart->tty; + if (tp != NULL) + ttymodem(tp, dcdstate); +} + +int +dartopen(dev_t dev, int flag, int mode, struct proc *p) +{ + int s; + u_int port, chip; + struct dart_info *dart; + struct dartsoftc *sc; + struct tty *tp; + + chip = DART_CHIP(dev); + port = DART_PORT(dev); + if (dart_cd.cd_ndevs <= chip || port >= NDARTPORTS) + return (ENODEV); + sc = (struct dartsoftc *)dart_cd.cd_devs[chip]; + if (sc == NULL) + return (ENODEV); + dart = &sc->sc_dart[port]; + + s = spltty(); + if (dart->tty != NULL) + tp = dart->tty; + else + tp = dart->tty = ttymalloc(); + + tp->t_oproc = dartstart; + tp->t_param = dartparam; + tp->t_dev = dev; + + if ((tp->t_state & TS_ISOPEN) == 0) { + ttychars(tp); + + if (tp->t_ispeed == 0) { + tp->t_iflag = TTYDEF_IFLAG; + tp->t_oflag = TTYDEF_OFLAG; + tp->t_lflag = TTYDEF_LFLAG; + tp->t_ispeed = tp->t_ospeed = B9600; + if (sc->sc_console && port == CONS_PORT) { + /* console is 8N1 */ + tp->t_cflag = (CREAD | CS8 | HUPCL); + } else { + tp->t_cflag = TTYDEF_CFLAG; + } + } + + if (dart->dart_swflags & TIOCFLAG_CLOCAL) + tp->t_cflag |= CLOCAL; + if (dart->dart_swflags & TIOCFLAG_CRTSCTS) + tp->t_cflag |= CRTSCTS; + if (dart->dart_swflags & TIOCFLAG_MDMBUF) + tp->t_cflag |= MDMBUF; + + dartparam(tp, &tp->t_termios); + ttsetwater(tp); + + (void)dartmctl(sc, port, TIOCM_DTR | TIOCM_RTS, DMSET); + tp->t_state |= TS_CARR_ON; + } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { + splx(s); + return (EBUSY); + } + + /* + * Reset the tty pointer, as there could have been a dialout + * use of the tty with a dialin open waiting. + */ + tp->t_dev = dev; + splx(s); + return ((*linesw[tp->t_line].l_open)(dev, tp)); +} + +int +dartclose(dev_t dev, int flag, int mode, struct proc *p) +{ + struct tty *tp; + struct dart_info *dart; + struct dartsoftc *sc; + u_int port, chip; + + chip = DART_CHIP(dev); + port = DART_PORT(dev); + sc = (struct dartsoftc *)dart_cd.cd_devs[chip]; + dart = &sc->sc_dart[port]; + + tp = dart->tty; + (*linesw[tp->t_line].l_close)(tp, flag); + ttyclose(tp); + + return (0); +} + +int +dartread(dev_t dev, struct uio *uio, int flag) +{ + u_int port, chip; + struct tty *tp; + struct dart_info *dart; + struct dartsoftc *sc; + + chip = DART_CHIP(dev); + port = DART_PORT(dev); + sc = (struct dartsoftc *)dart_cd.cd_devs[chip]; + dart = &sc->sc_dart[port]; + + tp = dart->tty; + if (tp == NULL) + return (ENXIO); + return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); +} + +int +dartwrite(dev_t dev, struct uio *uio, int flag) +{ + u_int port, chip; + struct tty *tp; + struct dart_info *dart; + struct dartsoftc *sc; + + chip = DART_CHIP(dev); + port = DART_PORT(dev); + sc = (struct dartsoftc *)dart_cd.cd_devs[chip]; + dart = &sc->sc_dart[port]; + + tp = dart->tty; + if (tp == NULL) + return (ENXIO); + return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); +} + +void +dartrint(struct dartsoftc *sc, int port) +{ + struct tty *tp; + unsigned char data, sr; + struct dart_info *dart; + bus_addr_t ptaddr; + + dart = &sc->sc_dart[port]; + ptaddr = port == A_PORT ? DART_A_BASE : DART_B_BASE; + tp = dart->tty; + + /* read status reg */ + while ((sr = dart_read(sc, ptaddr + DART_SRA)) & RXRDY) { + /* read data and reset receiver */ + data = dart_read(sc, ptaddr + DART_RBA); + + if ((tp->t_state & (TS_ISOPEN|TS_WOPEN)) == 0 && + (sc->sc_console == 0 || CONS_PORT != port)) { + return; + } + + if (sr & RBRK) { + /* clear break state */ + dart_write(sc, ptaddr + DART_CRA, BRKINTRESET); + DELAY_CR; + dart_write(sc, ptaddr + DART_CRA, ERRRESET); + +#if defined(DDB) + if (db_console != 0 && + sc->sc_console && port == CONS_PORT) + Debugger(); +#endif + } else { + if (sr & (FRERR | PERR | ROVRN)) { /* errors */ + if (sr & ROVRN) + log(LOG_WARNING, "%s port %c: " + "receiver overrun\n", + sc->sc_dev.dv_xname, 'A' + port); + if (sr & FRERR) + log(LOG_WARNING, "%s port %c: " + "framing error\n", + sc->sc_dev.dv_xname, 'A' + port); + if (sr & PERR) + log(LOG_WARNING, "%s port %c: " + "parity error\n", + sc->sc_dev.dv_xname, 'A' + port); + /* clear error state */ + dart_write(sc, ptaddr + DART_CRA, ERRRESET); + } else { + /* no errors */ + (*linesw[tp->t_line].l_rint)(data,tp); + } + } + } +} + +void +dartxint(struct dartsoftc *sc, int port) +{ + struct tty *tp; + struct dart_info *dart; + + dart = &sc->sc_dart[port]; + tp = dart->tty; + + if ((tp->t_state & (TS_ISOPEN|TS_WOPEN))==0) + goto out; + + if (tp->t_state & TS_BUSY) { + tp->t_state &= ~(TS_BUSY | TS_FLUSH); + dartstart(tp); + if (tp->t_state & TS_BUSY) { + /* do not disable transmitter, yet */ + return; + } + } +out: + + /* disable transmitter */ + sc->sc_sv_reg->sv_imr &= port == A_PORT ? ~ITXRDYA : ~ITXRDYB; + dart_write(sc, DART_IMR, sc->sc_sv_reg->sv_imr); +} + +int +dartintr(void *arg) +{ + struct dartsoftc *sc = arg; + unsigned char isr, imr; + int port; + + /* read interrupt status register and mask with imr */ + isr = dart_read(sc, DART_ISR); + imr = sc->sc_sv_reg->sv_imr; + + if ((isr & imr) == 0) { + /* + * We got an interrupt on a disabled condition (such as TX + * ready change on a disabled port). This should not happen, + * but we have to claim the interrupt anyway. + */ +#ifdef DIAGNOSTIC + printf("%s: spurious interrupt, isr %x imr %x\n", + sc->sc_dev.dv_xname, isr, imr); +#endif + return (1); + } + isr &= imr; + + if (isr & IIPCHG) { + unsigned int ip, ipcr; + + ip = dart_read(sc, DART_IP); + ipcr = dart_read(sc, DART_IPCR); + dartmodemtrans(sc, ip, ipcr); + return (1); + } + + if (isr & (IRXRDYA | ITXRDYA)) + port = 0; +#ifdef DIAGNOSTIC + else if ((isr & (IRXRDYB | ITXRDYB)) == 0) { + printf("%s: spurious interrupt, isr %x\n", + sc->sc_dev.dv_xname, isr); + return (1); /* claim it anyway */ + } +#endif + else + port = 1; + + if (isr & (IRXRDYA | IRXRDYB)) + dartrint(sc, port); + if (isr & (ITXRDYA | ITXRDYB)) + dartxint(sc, port); + if (isr & (port == A_PORT ? IBRKA : IBRKB)) + dart_write(sc, port == A_PORT ? DART_CRA : DART_CRB, + BRKINTRESET); + + return (1); +} + +/* + * Console interface routines. +#ifdef USE_PROM_CONSOLE + * Since we select the actual console after all devices are attached, + * we can safely pick the appropriate softc and use its information. +#endif + */ + +#ifdef USE_PROM_CONSOLE +#define dart_cnread(reg) dart_read(sc, (reg)) +#define dart_cnwrite(reg, val) dart_write(sc, (reg), (val)) +#else +#define dart_cnread(reg) \ + *(volatile u_int8_t *)(DART_BASE + 3 + ((reg) << 2)) +#define dart_cnwrite(reg, val) \ + *(volatile u_int8_t *)(DART_BASE + 3 + ((reg) << 2)) = (val) +#endif + +void +dartcnprobe(struct consdev *cp) +{ + int maj; + + if (badaddr(DART_BASE, 4) != 0) + return; + +#ifdef USE_PROM_CONSOLE + /* do not attach as console if dart has been disabled */ + if (dart_cd.cd_ndevs == 0 || dart_cd.cd_devs[0] == NULL) + return; +#endif + + /* locate the major number */ + for (maj = 0; maj < nchrdev; maj++) + if (cdevsw[maj].d_open == dartopen) + break; + if (maj == nchrdev) + return; + + cp->cn_dev = makedev(maj, CONS_PORT); + cp->cn_pri = CN_NORMAL; +} + +void +dartcninit(cp) + struct consdev *cp; +{ +#ifndef USE_PROM_CONSOLE + dartcn_sv.sv_mr1[CONS_PORT] = PARDIS | RXRTS | CL8; + dartcn_sv.sv_mr2[CONS_PORT] = /* TXCTS | */ SB1; + dartcn_sv.sv_csr[CONS_PORT] = BD9600; + dartcn_sv.sv_cr[CONS_PORT] = TXEN | RXEN; + dartcn_sv.sv_opr = CONS_PORT == A_PORT ? (OPDTRA | OPRTSA) : + (OPDTRB | OPRTSB); + dartcn_sv.sv_imr = IIPCHG; + + dart_cnwrite(DART_CRA, RXRESET | TXDIS | RXDIS); + DELAY_CR; + dart_cnwrite(DART_CRA, TXRESET | TXDIS | RXDIS); + DELAY_CR; + dart_cnwrite(DART_CRA, ERRRESET | TXDIS | RXDIS); + DELAY_CR; + dart_cnwrite(DART_CRA, BRKINTRESET | TXDIS | RXDIS); + DELAY_CR; + dart_cnwrite(DART_CRA, MRRESET | TXDIS | RXDIS); + DELAY_CR; + + dart_cnwrite(DART_MR1A, dartcn_sv.sv_mr1[CONS_PORT]); + dart_cnwrite(DART_MR2A, dartcn_sv.sv_mr2[CONS_PORT]); + dart_cnwrite(DART_CSRA, dartcn_sv.sv_csr[CONS_PORT]); + dart_cnwrite(DART_CRA, dartcn_sv.sv_cr[CONS_PORT]); + + dart_cnwrite(DART_OPRS, dartcn_sv.sv_opr); + + dart_cnwrite(DART_IMR, dartcn_sv.sv_imr); +#endif +} + +void +dartcnputc(dev_t dev, int c) +{ +#ifdef USE_PROM_CONSOLE + struct dartsoftc *sc; +#endif + int s; + u_int port; + bus_addr_t ptaddr; + +#ifdef USE_PROM_CONSOLE + sc = (struct dartsoftc *)dart_cd.cd_devs[0]; + port = DART_PORT(dev); +#else + port = CONS_PORT; +#endif + ptaddr = port == A_PORT ? DART_A_BASE : DART_B_BASE; + + s = spltty(); + + /* inhibit interrupts on the chip */ + dart_cnwrite(DART_IMR, dartcn_sv.sv_imr & + (CONS_PORT == A_PORT ? ~ITXRDYA : ~ITXRDYB)); + /* make sure transmitter is enabled */ +#if 0 + DELAY_CR; +#endif + dart_cnwrite(ptaddr + DART_CRA, TXEN); + + while ((dart_cnread(ptaddr + DART_SRA) & TXRDY) == 0) + ; + dart_cnwrite(ptaddr + DART_TBA, c); + + /* wait for transmitter to empty */ + while ((dart_cnread(ptaddr + DART_SRA) & TXEMT) == 0) + ; + + /* restore the previous state */ + dart_cnwrite(DART_IMR, dartcn_sv.sv_imr); +#if 0 + DELAY_CR; +#endif + dart_cnwrite(ptaddr + DART_CRA, dartcn_sv.sv_cr[0]); + + splx(s); +} + +int +dartcngetc(dev_t dev) +{ +#ifdef USE_PROM_CONSOLE + struct dartsoftc *sc; +#endif + unsigned char sr; /* status reg of port a/b */ + u_char c; /* received character */ + int s; + u_int port; + bus_addr_t ptaddr; + +#ifdef USE_PROM_CONSOLE + sc = (struct dartsoftc *)dart_cd.cd_devs[0]; + port = DART_PORT(dev); +#else + port = CONS_PORT; +#endif + ptaddr = port == A_PORT ? DART_A_BASE : DART_B_BASE; + + s = spltty(); + + /* enable receiver */ + dart_cnwrite(ptaddr + DART_CRA, RXEN); + + for (;;) { + /* read status reg */ + sr = dart_cnread(ptaddr + DART_SRA); + + /* receiver interrupt handler*/ + if (sr & RXRDY) { + /* read character from port */ + c = dart_cnread(ptaddr + DART_RBA); + + /* check break condition */ + if (sr & RBRK) { + /* clear break state */ + dart_cnwrite(ptaddr + DART_CRA, BRKINTRESET); + DELAY_CR; + dart_cnwrite(ptaddr + DART_CRA, ERRRESET); + break; + } + + if (sr & (FRERR | PERR | ROVRN)) { + /* clear error state */ + dart_cnwrite(ptaddr + DART_CRA, ERRRESET); + } else { + break; + } + } + } + splx(s); + + return ((int)c); +} diff --git a/sys/arch/aviion/dev/dart_syscon.c b/sys/arch/aviion/dev/dart_syscon.c new file mode 100644 index 00000000000..73d63540e40 --- /dev/null +++ b/sys/arch/aviion/dev/dart_syscon.c @@ -0,0 +1,103 @@ +/* $OpenBSD: dart_syscon.c,v 1.1 2006/05/09 18:13:37 miod Exp $ */ +/* + * Copyright (c) 2006, Miodrag Vallat + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> + +#include <machine/autoconf.h> +#include <machine/cpu.h> + +#include <machine/av400.h> + +#include <aviion/dev/sysconreg.h> +#include <aviion/dev/dartvar.h> + +int dart_syscon_match(struct device *parent, void *self, void *aux); +void dart_syscon_attach(struct device *parent, struct device *self, void *aux); + +struct cfattach dart_syscon_ca = { + sizeof(struct dartsoftc), dart_syscon_match, dart_syscon_attach +}; + +int +dart_syscon_match(struct device *parent, void *cf, void *aux) +{ + struct confargs *ca = aux; + bus_space_handle_t ioh; + int rc; + + /* + * We do not accept empty locators here... + */ + if (ca->ca_paddr == (paddr_t)-1) + return (0); + + if (bus_space_map(ca->ca_iot, ca->ca_paddr, DART_SIZE, 0, &ioh) != 0) + return (0); + rc = badaddr((vaddr_t)bus_space_vaddr(ca->ca_iot, ioh), 4); + bus_space_unmap(ca->ca_iot, ca->ca_paddr, DART_SIZE); + + return (rc == 0); +} + +void +dart_syscon_attach(struct device *parent, struct device *self, void *aux) +{ + struct dartsoftc *sc = (struct dartsoftc *)self; + struct confargs *ca = aux; + bus_space_handle_t ioh; + u_int vec; + + if (ca->ca_ipl < 0) + ca->ca_ipl = IPL_TTY; + + sc->sc_iot = ca->ca_iot; + if (bus_space_map(sc->sc_iot, ca->ca_paddr, DART_SIZE, 0, &ioh) != 0) { + printf(": can't map registers!\n"); + return; + } + sc->sc_ioh = ioh; + + if (ca->ca_paddr == DART_BASE) { + vec = SYSCV_SCC; + sc->sc_console = 1; /* XXX for now */ + printf(": console"); + } else { + vec = SYSCV_SCC2; + sc->sc_console = 0; + } + + /* enable interrupts */ + sc->sc_ih.ih_fn = dartintr; + sc->sc_ih.ih_arg = sc; + sc->sc_ih.ih_wantframe = 0; + sc->sc_ih.ih_ipl = ca->ca_ipl; + + sysconintr_establish(vec, &sc->sc_ih, self->dv_xname); + + dart_common_attach(sc); +} diff --git a/sys/arch/aviion/dev/if_le_syscon.c b/sys/arch/aviion/dev/if_le_syscon.c new file mode 100644 index 00000000000..7142c7af5ea --- /dev/null +++ b/sys/arch/aviion/dev/if_le_syscon.c @@ -0,0 +1,172 @@ +/* $OpenBSD: if_le_syscon.c,v 1.1 2006/05/09 18:13:40 miod Exp $ */ + +/*- + * Copyright (c) 1996 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Adam Glass and Gordon W. Ross. + * + * 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 NetBSD + * Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/mbuf.h> +#include <sys/syslog.h> +#include <sys/socket.h> +#include <sys/device.h> + +#include <net/if.h> + +#ifdef INET +#include <netinet/in.h> +#include <netinet/if_ether.h> +#endif + +#include <net/if_media.h> + +#include <machine/autoconf.h> +#include <machine/cpu.h> + +#include <machine/av400.h> +#include <aviion/dev/sysconreg.h> + +#include <dev/ic/am7990reg.h> +#include <dev/ic/am7990var.h> + +/* + * LANCE registers. Although these are 16 bit registers, on the AV400 + * design, they need to be accessed as 32 bit registers. Bus magic... + * The real stuff is in dev/ic/am7990reg.h + */ +struct av_lereg { + volatile u_int32_t ler1_rdp; /* data port */ + volatile u_int32_t ler1_rap; /* register select port */ +}; + +/* + * Ethernet software status per interface. + * The real stuff is in dev/ic/am7990var.h + */ +struct le_softc { + struct am7990_softc sc_am7990; /* glue to MI code */ + + struct av_lereg *sc_r1; /* LANCE registers */ + struct intrhand sc_ih; +}; + +int le_syscon_match(struct device *, void *, void *); +void le_syscon_attach(struct device *, struct device *, void *); + +struct cfattach le_syscon_ca = { + sizeof(struct le_softc), le_syscon_match, le_syscon_attach +}; + +void le_syscon_wrcsr(struct am7990_softc *, u_int16_t, u_int16_t); +u_int16_t le_syscon_rdcsr(struct am7990_softc *, u_int16_t); + +void +le_syscon_wrcsr(sc, port, val) + struct am7990_softc *sc; + u_int16_t port, val; +{ + struct av_lereg *ler1 = ((struct le_softc *)sc)->sc_r1; + + ler1->ler1_rap = port; + ler1->ler1_rdp = val; +} + +u_int16_t +le_syscon_rdcsr(sc, port) + struct am7990_softc *sc; + u_int16_t port; +{ + struct av_lereg *ler1 = ((struct le_softc *)sc)->sc_r1; + u_int16_t val; + + ler1->ler1_rap = port; + val = ler1->ler1_rdp; + return (val); +} + +int +le_syscon_match(parent, cf, aux) + struct device *parent; + void *cf, *aux; +{ + return (1); +} + +void +le_syscon_attach(parent, self, aux) + struct device *parent, *self; + void *aux; +{ + struct le_softc *lesc = (struct le_softc *)self; + struct am7990_softc *sc = &lesc->sc_am7990; + struct confargs *ca = aux; + extern void *etherbuf; + extern size_t etherlen; + + if (etherbuf == NULL) { + printf(": no available memory, kernel is too large\n"); + return; + } + + lesc->sc_r1 = (struct av_lereg *)ca->ca_paddr; + + sc->sc_mem = (void *)etherbuf; + etherbuf = NULL; + sc->sc_conf3 = LE_C3_BSWP; + sc->sc_addr = (u_long)sc->sc_mem & 0x00ffffff; + sc->sc_memsize = etherlen; + + myetheraddr(sc->sc_arpcom.ac_enaddr); + + sc->sc_copytodesc = am7990_copytobuf_contig; + sc->sc_copyfromdesc = am7990_copyfrombuf_contig; + sc->sc_copytobuf = am7990_copytobuf_contig; + sc->sc_copyfrombuf = am7990_copyfrombuf_contig; + sc->sc_zerobuf = am7990_zerobuf_contig; + + sc->sc_rdcsr = le_syscon_rdcsr; + sc->sc_wrcsr = le_syscon_wrcsr; + sc->sc_hwreset = NULL; + sc->sc_hwinit = NULL; + + am7990_config(sc); + + lesc->sc_ih.ih_fn = am7990_intr; + lesc->sc_ih.ih_arg = sc; + lesc->sc_ih.ih_wantframe = 0; + lesc->sc_ih.ih_ipl = ca->ca_ipl; + + sysconintr_establish(SYSCV_LE, &lesc->sc_ih, self->dv_xname); +} diff --git a/sys/arch/aviion/dev/mainbus.c b/sys/arch/aviion/dev/mainbus.c new file mode 100644 index 00000000000..6795ebb0c66 --- /dev/null +++ b/sys/arch/aviion/dev/mainbus.c @@ -0,0 +1,163 @@ +/* $OpenBSD: mainbus.c,v 1.1 2006/05/09 18:13:53 miod Exp $ */ +/* + * Copyright (c) 1998 Steve Murphree, Jr. + * Copyright (c) 2004, Miodrag Vallat. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/reboot.h> +#include <sys/conf.h> +#include <sys/device.h> +#include <sys/disklabel.h> +#include <sys/extent.h> + +#include <uvm/uvm_extern.h> + +#include <machine/autoconf.h> +#include <machine/bus.h> +#include <machine/cmmu.h> +#include <machine/cpu.h> +#include <machine/prom.h> + +#include <machine/av400.h> + +void mainbus_attach(struct device *, struct device *, void *); +int mainbus_match(struct device *, void *, void *); +int mainbus_print(void *, const char *); +int mainbus_scan(struct device *, void *, void *); + +/* + * bus_space routines for 1:1 obio mappings + */ + +int mainbus_map(bus_addr_t, bus_size_t, int, bus_space_handle_t *); +void mainbus_unmap(bus_space_handle_t, bus_size_t); +int mainbus_subregion(bus_space_handle_t, bus_size_t, bus_size_t, + bus_space_handle_t *); +void *mainbus_vaddr(bus_space_handle_t); + +const struct aviion_bus_space_tag mainbus_bustag = { + mainbus_map, + mainbus_unmap, + mainbus_subregion, + mainbus_vaddr +}; + +/* + * Obio (internal IO) space is mapped 1:1 (see pmap_bootstrap() for details). + */ + +int +mainbus_map(bus_addr_t addr, bus_size_t size, int flags, + bus_space_handle_t *ret) +{ + *ret = (bus_space_handle_t)addr; + return 0; +} + +void +mainbus_unmap(bus_space_handle_t handle, bus_size_t size) +{ + /* nothing to do */ +} + +int +mainbus_subregion(bus_space_handle_t handle, bus_addr_t offset, + bus_size_t size, bus_space_handle_t *ret) +{ + *ret = handle + offset; + return (0); +} + +void * +mainbus_vaddr(bus_space_handle_t handle) +{ + return (void *)handle; +} + +/* + * Configuration glue + */ + +struct cfattach mainbus_ca = { + sizeof(struct device), mainbus_match, mainbus_attach +}; + +struct cfdriver mainbus_cd = { + NULL, "mainbus", DV_DULL +}; + +int +mainbus_match(struct device *parent, void *cf, void *args) +{ + return (mainbus_cd.cd_ndevs == 0); +} + +void +mainbus_attach(struct device *parent, struct device *self, void *args) +{ + extern char cpu_model[]; + extern int32_t cpuid, sysid; + + printf(": %s, cpuid 0x%x", cpu_model, cpuid); + if (sysid != -1) + printf(", sysid %x", sysid); + printf("\n"); + + /* + * Display cpu/mmu details for the main processor. + */ + cpu_configuration_print(1); + + (void)config_search(mainbus_scan, self, args); +} + +int +mainbus_scan(struct device *parent, void *child, void *args) +{ + struct cfdata *cf = child; + struct confargs oca; + + oca.ca_iot = &mainbus_bustag; + oca.ca_paddr = (paddr_t)cf->cf_loc[0]; + oca.ca_offset = (paddr_t)-1; + oca.ca_ipl = (u_int)-1; + + if ((*cf->cf_attach->ca_match)(parent, cf, &oca) == 0) + return (0); + + config_attach(parent, cf, &oca, mainbus_print); + return (1); +} + +int +mainbus_print(void *args, const char *bus) +{ + struct confargs *ca = args; + + if (ca->ca_paddr != (paddr_t)-1) + printf(" addr 0x%08x", ca->ca_paddr); + return (UNCONF); +} diff --git a/sys/arch/aviion/dev/syscon.c b/sys/arch/aviion/dev/syscon.c new file mode 100644 index 00000000000..8921ed28266 --- /dev/null +++ b/sys/arch/aviion/dev/syscon.c @@ -0,0 +1,201 @@ +/* $OpenBSD: syscon.c,v 1.1 2006/05/09 18:14:07 miod Exp $ */ +/* + * Copyright (c) 1999 Steve Murphree, Jr. + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +#include <sys/param.h> +#include <sys/conf.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/device.h> + +#include <machine/autoconf.h> +#include <machine/cpu.h> +#include <machine/frame.h> + +#include <machine/av400.h> +#include <aviion/dev/sysconreg.h> + +struct sysconsoftc { + struct device sc_dev; + + struct intrhand sc_abih; /* `abort' switch */ + struct intrhand sc_acih; /* `ac fail' */ + struct intrhand sc_sfih; /* `sys fail' */ +#if 0 + struct intrhand sc_av400ih; /* `av400 interrupt' */ +#endif +}; + +void sysconattach(struct device *, struct device *, void *); +int sysconmatch(struct device *, void *, void *); + +int syscon_print(void *, const char *); +int syscon_scan(struct device *, void *, void *); +int sysconabort(void *); +int sysconacfail(void *); +int sysconsysfail(void *); +int sysconav400(void *); + +struct cfattach syscon_ca = { + sizeof(struct sysconsoftc), sysconmatch, sysconattach +}; + +struct cfdriver syscon_cd = { + NULL, "syscon", DV_DULL +}; + +int +sysconmatch(struct device *parent, void *cf, void *args) +{ + return (syscon_cd.cd_ndevs == 0); +} + +void +sysconattach(struct device *parent, struct device *self, void *args) +{ + struct sysconsoftc *sc = (struct sysconsoftc *)self; + + printf("\n"); + + /* + * Clear SYSFAIL if lit. + */ + *(volatile u_int32_t *)AV400_UCSR |= UCSR_DRVSFBIT; + + /* + * pseudo driver, abort interrupt handler + */ + sc->sc_abih.ih_fn = sysconabort; + sc->sc_abih.ih_arg = 0; + sc->sc_abih.ih_wantframe = 1; + sc->sc_abih.ih_ipl = IPL_ABORT; + + sc->sc_acih.ih_fn = sysconacfail; + sc->sc_acih.ih_arg = 0; + sc->sc_acih.ih_wantframe = 1; + sc->sc_acih.ih_ipl = IPL_ABORT; + + sc->sc_sfih.ih_fn = sysconsysfail; + sc->sc_sfih.ih_arg = 0; + sc->sc_sfih.ih_wantframe = 1; + sc->sc_sfih.ih_ipl = IPL_ABORT; + +#if 0 + sc->sc_av400ih.ih_fn = sysconav400; + sc->sc_av400ih.ih_arg = 0; + sc->sc_av400ih.ih_wantframe = 1; + sc->sc_av400ih.ih_ipl = IPL_ABORT; +#endif + + sysconintr_establish(SYSCV_ABRT, &sc->sc_abih, "abort"); + sysconintr_establish(SYSCV_ACF, &sc->sc_acih, "acfail"); + sysconintr_establish(SYSCV_SYSF, &sc->sc_sfih, "sysfail"); +#if 0 + intr_establish(AV400_IVEC, &sc->sc_av400ih, self->dv_xname); +#endif + + config_search(syscon_scan, self, args); +} + +int +syscon_scan(struct device *parent, void *child, void *args) +{ + struct cfdata *cf = child; + struct confargs oca, *ca = args; + + bzero(&oca, sizeof oca); + oca.ca_iot = ca->ca_iot; + oca.ca_offset = (paddr_t)cf->cf_loc[0]; + if (oca.ca_offset != (paddr_t)-1) + oca.ca_paddr = ca->ca_paddr + oca.ca_offset; + else + oca.ca_paddr = (paddr_t)-1; + oca.ca_ipl = (u_int)cf->cf_loc[1]; + + if ((*cf->cf_attach->ca_match)(parent, cf, &oca) == 0) + return (0); + + config_attach(parent, cf, &oca, syscon_print); + return (1); +} + +int +syscon_print(void *args, const char *pnp) +{ + struct confargs *ca = args; + + if (ca->ca_offset != (paddr_t)-1) + printf(" offset 0x%x", ca->ca_offset); + if (ca->ca_ipl != (u_int)-1) + printf(" ipl %u", ca->ca_ipl); + return (UNCONF); +} + +int +sysconintr_establish(u_int vec, struct intrhand *ih, const char *name) +{ +#ifdef DIAGNOSTIC + if (vec < 0 || vec >= SYSCON_NVEC) { + printf("sysconintr_establish: illegal vector 0x%x\n", vec); + return (EINVAL); + } +#endif + + return (intr_establish(SYSCON_VECT + vec, ih, name)); +} + +int +sysconabort(void *eframe) +{ + *(volatile u_int32_t *)AV400_CLRINT = ISTATE_ABORT; + nmihand(eframe); + return (1); +} + +int +sysconsysfail(void *eframe) +{ + *(volatile u_int32_t *)AV400_CLRINT = ISTATE_SYSFAIL; + printf("WARNING: SYSFAIL* ASSERTED\n"); + return (1); +} + +int +sysconacfail(void *eframe) +{ + *(volatile u_int32_t *)AV400_CLRINT = ISTATE_ACFAIL; + printf("WARNING: ACFAIL* ASSERTED\n"); + return (1); +} + +#if 0 +int +sysconav400(void *eframe) +{ + /* shouldn't happen! */ + printf("AV400: self-inflicted interrupt\n"); + return (1); +} +#endif diff --git a/sys/arch/aviion/dev/vme.c b/sys/arch/aviion/dev/vme.c new file mode 100644 index 00000000000..514150dc19b --- /dev/null +++ b/sys/arch/aviion/dev/vme.c @@ -0,0 +1,550 @@ +/* $OpenBSD: vme.c,v 1.1 2006/05/09 18:14:15 miod Exp $ */ +/* + * Copyright (c) 2006, Miodrag Vallat. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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. + */ + +/* + * XXX TODO: Finish /dev/vme{a16,a24,a32}{d8,d16,d32} interface. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/extent.h> +#include <sys/malloc.h> +#include <sys/proc.h> +#include <sys/uio.h> + +#include <machine/bus.h> +#include <machine/conf.h> + +#include <uvm/uvm_extern.h> + +#include <aviion/dev/vmevar.h> + +#include <machine/av400.h> +#include <aviion/dev/sysconreg.h> + +struct vmesoftc { + struct device sc_dev; + + struct extent *sc_ext_a16; + struct extent *sc_ext_a24; + struct extent *sc_ext_a32; +}; + +int vmematch(struct device *, void *, void *); +void vmeattach(struct device *, struct device *, void *); + +struct cfattach vme_ca = { + sizeof(struct vmesoftc), vmematch, vmeattach +}; + +struct cfdriver vme_cd = { + NULL, "vme", DV_DULL +}; + +int vme16_map(bus_addr_t, bus_size_t, int, bus_space_handle_t *); +void vme16_unmap(bus_space_handle_t, bus_size_t); +void * vme16_vaddr(bus_space_handle_t); +int vme24_map(bus_addr_t, bus_size_t, int, bus_space_handle_t *); +void vme24_unmap(bus_space_handle_t, bus_size_t); +void * vme24_vaddr(bus_space_handle_t); +int vme32_map(bus_addr_t, bus_size_t, int, bus_space_handle_t *); +void vme32_unmap(bus_space_handle_t, bus_size_t); +void * vme32_vaddr(bus_space_handle_t); +int vme_subregion(bus_space_handle_t, bus_size_t, bus_size_t, + bus_space_handle_t *); + +int vme_map(struct extent *, bus_addr_t, bus_size_t, int, + bus_space_handle_t *); +void vme_unmap(struct extent *, bus_space_handle_t, bus_size_t); +int vmeprint(void *, const char *); +int vmescan(struct device *, void *, void *); + +u_int vmevecbase; + +int +vmematch(struct device *parent, void *vcf, void *aux) +{ + /* XXX no VME on AV100/AV200/AV300, though */ + return (1); +} + +void +vmeattach(struct device *parent, struct device *self, void *aux) +{ + struct vmesoftc *sc = (struct vmesoftc *)self; + u_int32_t ucsr; + + printf("\n"); + + /* + * Initialize extents + */ + sc->sc_ext_a16 = extent_create("vme a16", 0, 1 << (16 - PAGE_SHIFT), + M_DEVBUF, NULL, 0, EX_NOWAIT); + sc->sc_ext_a24 = extent_create("vme a24", 0, 1 << (24 - PAGE_SHIFT), + M_DEVBUF, NULL, 0, EX_NOWAIT); + sc->sc_ext_a32 = extent_create("vme a32", 0, 1 << (32 - PAGE_SHIFT), + M_DEVBUF, NULL, 0, EX_NOWAIT); + + vmevecbase = 0x80; /* Hard coded for AV400 */ + + /* + * Force a reasonable timeout for VME data transfers. + * We can not disable this, this would cause autoconf to hang + * on the first missing device we'll probe. + */ + ucsr = *(volatile u_int32_t*)AV400_UCSR; + ucsr = (ucsr & ~VTOSELBITS) | VTO128US; + *(volatile u_int32_t *)AV400_UCSR = ucsr; + + /* + * Clear EXTAD to allow VME A24 devices to access the first 16MB + * of memory. + */ + *(volatile u_int32_t *)AV400_EXTAD = 0x00000000; + + /* + * Use supervisor data address modifiers for VME accesses. + */ + *(volatile u_int32_t *)AV400_EXTAM = 0x0d; + + /* + * Display AV400 VME ranges. + */ + printf("%s: A32 %08x-%08x\n", self->dv_xname, + AV400_VME32_START1, AV400_VME32_END1); + printf("%s: A32 %08x-%08x\n", self->dv_xname, + AV400_VME32_START2, AV400_VME32_END2); + printf("%s: A24 %08x-%08x\n", self->dv_xname, + AV400_VME24_START, AV400_VME24_END); + printf("%s: A16 %08x-%08x\n", self->dv_xname, + AV400_VME16_START, AV400_VME16_END); + + /* scan for child devices */ + config_search(vmescan, self, aux); +} + +int +vmescan(struct device *parent, void *vcf, void *aux) +{ + struct cfdata *cf = vcf; + struct vme_attach_args vaa; + + bzero(&vaa, sizeof vaa); + vaa.vaa_addr_a16 = (vme_addr_t)cf->cf_loc[0]; + vaa.vaa_addr_a24 = (vme_addr_t)cf->cf_loc[1]; + vaa.vaa_addr_a32 = (vme_addr_t)cf->cf_loc[2]; + vaa.vaa_ipl = (u_int)cf->cf_loc[3]; + + if ((*cf->cf_attach->ca_match)(parent, cf, &vaa) == 0) + return (0); + + config_attach(parent, cf, &vaa, vmeprint); + return (1); +} + +int +vmeprint(void *aux, const char *pnp) +{ + struct vme_attach_args *vaa = aux; + + if (vaa->vaa_addr_a16 != (vme_addr_t)-1) + printf(" a16 0x%04x", vaa->vaa_addr_a16); + if (vaa->vaa_addr_a24 != (vme_addr_t)-1) + printf(" a24 0x%06x", vaa->vaa_addr_a24); + if (vaa->vaa_addr_a32 != (vme_addr_t)-1) + printf(" a32 0x%08x", vaa->vaa_addr_a32); + if (vaa->vaa_ipl != (u_int)-1) + printf(" ipl %u", vaa->vaa_ipl); + + return (UNCONF); +} + +/* + * Interrupt related code + */ + +/* allocate interrupt vectors */ +int +vmeintr_allocate(u_int count, int flags, u_int *array) +{ + u_int vec, v; + + if ((flags & VMEINTR_CONTIGUOUS) == 0) { + for (vec = vmevecbase; vec <= NVMEINTR - count; vec++) { + if (SLIST_EMPTY(&intr_handlers[vec])) { + *array++ = vec; + if (--count == 0) + return (0); + } + } + } else { + for (vec = vmevecbase; vec <= NVMEINTR - count; vec++) { + /* do we have count contiguous unassigned vectors? */ + for (v = count; v != 0; v--) + if (!SLIST_EMPTY(&intr_handlers[vec + v - 1])) + break; + + if (v == 0) { + *array = vec; + return (0); + } + } + } + + return (EPERM); +} + +/* enable and establish interrupt */ +int +vmeintr_establish(u_int vec, struct intrhand *ih, const char *name) +{ + /* + * No need to enable the VME interrupt source in the AV400 interrupt + * controller, as they are enabled by default. + */ + return intr_establish(vec, ih, name); +} + +/* + * bus_space specific functions + */ + +int +vme16_map(bus_addr_t addr, bus_size_t size, int flags, bus_space_handle_t *ret) +{ + struct vmesoftc *sc = (void *)vme_cd.cd_devs[0]; + + if (AV400_ISVMEA32(addr) && AV400_ISVMEA32(addr + size - 1)) + return (vme_map(sc->sc_ext_a16, addr, size, flags, ret)); + else + return (EINVAL); +} + +int +vme24_map(bus_addr_t addr, bus_size_t size, int flags, bus_space_handle_t *ret) +{ + struct vmesoftc *sc = (void *)vme_cd.cd_devs[0]; + + if (AV400_ISVMEA24(addr) && AV400_ISVMEA24(addr + size - 1)) + return (vme_map(sc->sc_ext_a24, addr, size, flags, ret)); + else + return (EINVAL); +} + +int +vme32_map(bus_addr_t addr, bus_size_t size, int flags, bus_space_handle_t *ret) +{ + struct vmesoftc *sc = (void *)vme_cd.cd_devs[0]; + + if (AV400_ISVMEA16(addr) && AV400_ISVMEA16(addr + size - 1)) + return (vme_map(sc->sc_ext_a32, addr, size, flags, ret)); + else + return (EINVAL); +} + +int +vme_map(struct extent *ext, bus_addr_t addr, bus_size_t size, int flags, + bus_space_handle_t *ret) +{ + int rc; + paddr_t pa; + psize_t len; + vaddr_t ova, va; + u_int pg; + extern vaddr_t pmap_map(vaddr_t, paddr_t, paddr_t, vm_prot_t, u_int); + + pa = trunc_page((paddr_t)addr); + len = round_page((paddr_t)addr + size) - pa; + + if (ext != NULL) { + rc = extent_alloc_region(ext, atop(pa), atop(len), + EX_NOWAIT | EX_MALLOCOK); + if (rc != 0) + return (rc); + } + + ova = va = uvm_km_valloc(kernel_map, len); + if (va == NULL) { + rc = ENOMEM; + goto fail; + } + + *ret = (bus_space_handle_t)va; + + for (pg = atop(len); pg !=0; pg--) { + pmap_kenter_pa(va, pa, UVM_PROT_RW); + va += PAGE_SIZE; + pa += PAGE_SIZE; + } + if (flags & BUS_SPACE_MAP_CACHEABLE) + pmap_cache_ctrl(pmap_kernel(), ova, ova + len, CACHE_GLOBAL); + pmap_update(pmap_kernel()); + + return (0); + +fail: + if (ext != NULL) + extent_free(ext, atop(pa), atop(len), EX_NOWAIT | EX_MALLOCOK); + return (rc); +} + +void +vme16_unmap(bus_space_handle_t handle, bus_size_t size) +{ + struct vmesoftc *sc = (void *)vme_cd.cd_devs[0]; + + return (vme_unmap(sc->sc_ext_a16, handle, size)); +} + +void +vme24_unmap(bus_space_handle_t handle, bus_size_t size) +{ + struct vmesoftc *sc = (void *)vme_cd.cd_devs[0]; + + return (vme_unmap(sc->sc_ext_a24, handle, size)); +} + +void +vme32_unmap(bus_space_handle_t handle, bus_size_t size) +{ + struct vmesoftc *sc = (void *)vme_cd.cd_devs[0]; + + return (vme_unmap(sc->sc_ext_a32, handle, size)); +} + +void +vme_unmap(struct extent *ext, bus_space_handle_t handle, bus_size_t size) +{ + vaddr_t va; + vsize_t len; + + va = trunc_page((vaddr_t)handle); + len = round_page((vaddr_t)handle + size) - va; + + pmap_kremove(va, len); + pmap_update(pmap_kernel()); + uvm_km_free(kernel_map, va, len); + + if (ext != NULL) + extent_free(ext, atop(va), atop(len), EX_NOWAIT | EX_MALLOCOK); +} + +int +vme_subregion(bus_space_handle_t handle, bus_addr_t offset, bus_size_t size, + bus_space_handle_t *ret) +{ + /* since vme_map produces linear mappings, this is safe */ + *ret = handle + offset; + return (0); +} + +void * +vme16_vaddr(bus_space_handle_t handle) +{ + return (void *)(AV400_VME16_START + (vaddr_t)handle); +} + +void * +vme24_vaddr(bus_space_handle_t handle) +{ + return (void *)(AV400_VME24_START + (vaddr_t)handle); +} + +void * +vme32_vaddr(bus_space_handle_t handle) +{ + return (void *)(handle); +} + +/* + * Get a bus_space_tag for the requested address and data access modes. + * + * On aviion, we do not honour the dspace yet. + */ +int +vmebus_get_bst(struct device *vsc, u_int aspace, u_int dspace, + bus_space_tag_t *bst) +{ + struct aviion_bus_space_tag *tag; + + switch (dspace) { + case VME_D32: + case VME_D16: + case VME_D8: + break; + default: + return (EINVAL); + } + + switch (aspace) { + case VME_A32: + case VME_A24: + case VME_A16: + break; + default: + return (EINVAL); + } + + tag = (struct aviion_bus_space_tag *)malloc(sizeof *tag, M_DEVBUF, + M_NOWAIT); + if (tag == NULL) + return (ENOMEM); + + switch (aspace) { + default: + case VME_A32: + tag->bs_map = vme32_map; + tag->bs_unmap = vme32_unmap; + tag->bs_subregion = vme_subregion; + tag->bs_vaddr = vme32_vaddr; + break; + case VME_A24: + tag->bs_map = vme24_map; + tag->bs_unmap = vme24_unmap; + tag->bs_subregion = vme_subregion; + tag->bs_vaddr = vme24_vaddr; + break; + case VME_A16: + tag->bs_map = vme16_map; + tag->bs_unmap = vme16_unmap; + tag->bs_subregion = vme_subregion; + tag->bs_vaddr = vme16_vaddr; + break; + } + + *bst = tag; + return (0); +} + +void +vmebus_release_bst(struct device *vsc, bus_space_tag_t b) +{ + free((void *)b, M_DEVBUF); +} + +/* + * /dev/vme* access routines + */ + +/* minor device number encoding */ +#define AWIDTH_FIELD(minor) (minor & 0x0f) +#define AWIDTH(w) ((w) << 3) +#define DWIDTH_FIELD(minor) ((minor & 0xf0) >> 4) +#define DWIDTH(w) ((w) << 3) + +int +vmeopen(dev_t dev, int flags, int type, struct proc *p) +{ + if (vme_cd.cd_ndevs == 0 || vme_cd.cd_devs[0] == NULL) + return (ENODEV); + + switch (AWIDTH_FIELD(minor(dev))) { + case VME_A32: + case VME_A24: + case VME_A16: + break; + default: + return (ENODEV); + } + + switch (DWIDTH_FIELD(minor(dev))) { + case VME_D32: + case VME_D16: + case VME_D8: + break; + default: + return (ENODEV); + } + + return (0); +} + +int +vmeclose(dev_t dev, int flags, int type, struct proc *p) +{ + return (0); +} + +int +vmeread(dev_t dev, struct uio *uio, int flags) +{ + return (EIO); +} + +int +vmewrite(dev_t dev, struct uio *uio, int flags) +{ + return (EIO); +} + +int +vmeioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) +{ + switch (cmd) { + default: + return (ENOTTY); + } +} + +paddr_t +vmemmap(dev_t dev, off_t off, int prot) +{ + int awidth; + paddr_t pa; + + if ((off & PAGE_MASK) != 0) + return (-1); + + awidth = AWIDTH_FIELD(minor(dev)); + + /* check offset range */ + if (off < 0 || off >= (1ULL << AWIDTH(awidth))) + return (-1); + + pa = (paddr_t)off; + + switch (awidth) { + case VME_A32: + if (!AV400_ISVMEA32(pa)) + return (-1); + break; + case VME_A24: + pa += AV400_VME24_START; + if (!AV400_ISVMEA24(pa)) + return (-1); + break; + case VME_A16: + pa += AV400_VME16_START; + if (!AV400_ISVMEA16(pa)) + return (-1); + break; + } + + return (atop(pa)); +} |