diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2002-08-12 10:44:05 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2002-08-12 10:44:05 +0000 |
commit | 15dafe6228319925897f71b6a78bb04ebfb3abc4 (patch) | |
tree | 2bfbe764cfc6f9b1e3c6ca9d29d0881a4283149e /sys/arch/sparc/dev | |
parent | a83486fe3ff711d8b3727f8abae7995141bb7562 (diff) |
Convert sparc console code from rcons and pseudo-devices to rasops and wscons.
For most framebuffers it is faster.
Other changes include:
o 24 bit support in tcx(4) for the S24 framebuffer
o accelerated cgsix(4) text console
o new cgtwelve(4) driver for the GS framebuffer
o improved serial driver code
o better keyboard support
The following framebuffers have not been tested but should work: cgfour,
cgeight and cgfourteen
These changes will require XF4 changes, to use Xwsfb instead of Xsun*, to be
commited later today.
Most of the work by me during the LSM and the week after, with code borrowed
from jason@, NetBSD (new serial code), and feedback from mickey@. Work on
pnozz(4) done by millert@
Diffstat (limited to 'sys/arch/sparc/dev')
31 files changed, 9366 insertions, 7317 deletions
diff --git a/sys/arch/sparc/dev/bt_subr.c b/sys/arch/sparc/dev/bt_subr.c index 224de260bfa..d877f690900 100644 --- a/sys/arch/sparc/dev/bt_subr.c +++ b/sys/arch/sparc/dev/bt_subr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bt_subr.c,v 1.7 2002/08/02 16:13:07 millert Exp $ */ +/* $OpenBSD: bt_subr.c,v 1.8 2002/08/12 10:44:03 miod Exp $ */ /* $NetBSD: bt_subr.c,v 1.5 1996/03/14 19:44:32 christos Exp $ */ /* @@ -52,69 +52,104 @@ #include <uvm/uvm_extern.h> -#include <machine/fbio.h> +#include <dev/wscons/wsconsio.h> #include <sparc/dev/btreg.h> #include <sparc/dev/btvar.h> /* * Common code for dealing with Brooktree video DACs. - * (Contains some software-only code as well, since the colormap - * ioctls are shared between the cgthree and cgsix drivers.) */ -/* - * Implement an FBIOGETCMAP-like ioctl. - */ int -bt_getcmap(p, cm, cmsize) - register struct fbcmap *p; - union bt_cmap *cm; - int cmsize; +bt_getcmap(bcm, rcm) + union bt_cmap *bcm; + struct wsdisplay_cmap *rcm; { - register u_int i, start, count; - register u_char *cp; + u_int index = rcm->index, count = rcm->count, i; + int error; - start = p->index; - count = p->count; - if (start >= cmsize || count > cmsize - start) + if (index >= 256 || count > 256 - index) return (EINVAL); - if (!uvm_useracc(p->red, count, B_WRITE) || - !uvm_useracc(p->green, count, B_WRITE) || - !uvm_useracc(p->blue, count, B_WRITE)) - return (EFAULT); - for (cp = &cm->cm_map[start][0], i = 0; i < count; cp += 3, i++) { - p->red[i] = cp[0]; - p->green[i] = cp[1]; - p->blue[i] = cp[2]; + for (i = 0; i < count; i++) { + if ((error = copyout(&bcm->cm_map[index + i][0], + &rcm->red[i], 1)) != 0) + return (error); + if ((error = copyout(&bcm->cm_map[index + i][1], + &rcm->green[i], 1)) != 0) + return (error); + if ((error = copyout(&bcm->cm_map[index + i][2], + &rcm->blue[i], 1)) != 0) + return (error); } return (0); } -/* - * Implement the software portion of an FBIOPUTCMAP-like ioctl. - */ int -bt_putcmap(p, cm, cmsize) - register struct fbcmap *p; - union bt_cmap *cm; - int cmsize; +bt_putcmap(bcm, rcm) + union bt_cmap *bcm; + struct wsdisplay_cmap *rcm; { - register u_int i, start, count; - register u_char *cp; + u_int index = rcm->index, count = rcm->count, i; + int error; - start = p->index; - count = p->count; - if (start >= cmsize || count > cmsize - start) + if (index >= 256 || count > 256 - index) return (EINVAL); - if (!uvm_useracc(p->red, count, B_READ) || - !uvm_useracc(p->green, count, B_READ) || - !uvm_useracc(p->blue, count, B_READ)) - return (EFAULT); - for (cp = &cm->cm_map[start][0], i = 0; i < count; cp += 3, i++) { - cp[0] = p->red[i]; - cp[1] = p->green[i]; - cp[2] = p->blue[i]; + for (i = 0; i < count; i++) { + if ((error = copyin(&rcm->red[i], + &bcm->cm_map[index + i][0], 1)) != 0) + return (error); + if ((error = copyin(&rcm->green[i], + &bcm->cm_map[index + i][1], 1)) != 0) + return (error); + if ((error = copyin(&rcm->blue[i], + &bcm->cm_map[index + i][2], 1)) != 0) + return (error); } return (0); } + +void +bt_loadcmap(cm, bt, start, ncolors, cgsix) + union bt_cmap *cm; + volatile struct bt_regs *bt; + u_int start, ncolors; + int cgsix; +{ + u_int *ip, i; + int count; + + ip = &cm->cm_chip[BT_D4M3(start)]; /* start/4 * 3 */ + count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3; + + if (cgsix) { + /* hardware that makes one want to pound boards with hammers */ + bt->bt_addr = BT_D4M4(start) << 24; + while (--count >= 0) { + i = *ip++; + bt->bt_cmap = i; + bt->bt_cmap = i << 8; + bt->bt_cmap = i << 16; + bt->bt_cmap = i << 24; + } + } else { + bt->bt_addr = BT_D4M4(start); + while (--count >= 0) + bt->bt_cmap = *ip++; + } +} + +void +bt_setcolor(cm, bt, index, r, g, b, cgsix) + union bt_cmap *cm; + volatile struct bt_regs *bt; + u_int index; + u_int8_t r, g, b; + int cgsix; +{ + + cm->cm_map[index][0] = r; + cm->cm_map[index][1] = g; + cm->cm_map[index][2] = b; + bt_loadcmap(cm, bt, index, 1, cgsix); +} diff --git a/sys/arch/sparc/dev/btvar.h b/sys/arch/sparc/dev/btvar.h index f33e9907eba..1cbbaf9b2e6 100644 --- a/sys/arch/sparc/dev/btvar.h +++ b/sys/arch/sparc/dev/btvar.h @@ -1,4 +1,4 @@ -/* $OpenBSD: btvar.h,v 1.3 2002/03/14 01:26:42 millert Exp $ */ +/* $OpenBSD: btvar.h,v 1.4 2002/08/12 10:44:03 miod Exp $ */ /* $NetBSD: btvar.h,v 1.2 1994/11/20 20:51:56 deraadt Exp $ */ /* @@ -62,8 +62,12 @@ union bt_cmap { /* * Routines in bt_subr.c. */ -int bt_getcmap(struct fbcmap *, union bt_cmap *, int); -int bt_putcmap(struct fbcmap *, union bt_cmap *, int); +int bt_getcmap(union bt_cmap *, struct wsdisplay_cmap *); +int bt_putcmap(union bt_cmap *, struct wsdisplay_cmap *); +void bt_loadcmap(union bt_cmap *, volatile struct bt_regs *, + u_int, u_int, int); +void bt_setcolor(union bt_cmap *, volatile struct bt_regs *, + u_int, u_int8_t, u_int8_t, u_int8_t, int); /* * Compute (x / 4) * 3 and (x / 4) * 4. These are used in turning diff --git a/sys/arch/sparc/dev/bwtwo.c b/sys/arch/sparc/dev/bwtwo.c index 81cf7720afe..7e98badb2cc 100644 --- a/sys/arch/sparc/dev/bwtwo.c +++ b/sys/arch/sparc/dev/bwtwo.c @@ -1,7 +1,8 @@ -/* $OpenBSD: bwtwo.c,v 1.21 2002/07/09 23:33:15 jason Exp $ */ +/* $OpenBSD: bwtwo.c,v 1.22 2002/08/12 10:44:03 miod Exp $ */ /* $NetBSD: bwtwo.c,v 1.33 1997/05/24 20:16:02 pk Exp $ */ /* + * Copyright (c) 2002 Miodrag Vallat. All rights reserved. * Copyright (c) 1996 Jason R. Thorpe. All rights reserved. * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. @@ -49,8 +50,6 @@ /* * black&white display (bwtwo) driver. * - * Does not handle interrupts, even though they can occur. - * * P4 and overlay plane support by Jason R. Thorpe <thorpej@NetBSD.ORG>. * Overlay plane handling hints and ideas provided by Brad Spencer. */ @@ -66,10 +65,7 @@ #include <uvm/uvm_extern.h> -#include <machine/fbio.h> #include <machine/autoconf.h> -#include <machine/pmap.h> -#include <machine/fbvar.h> #include <machine/eeprom.h> #include <machine/ctlreg.h> #include <machine/conf.h> @@ -82,32 +78,68 @@ #include <sparc/dev/pfourreg.h> #endif +#include <dev/wscons/wsconsio.h> +#include <dev/wscons/wsdisplayvar.h> +#include <dev/wscons/wscons_raster.h> +#include <dev/rasops/rasops.h> +#include <machine/fbvar.h> + +#include <machine/pmap.h> + /* per-display variables */ struct bwtwo_softc { - struct device sc_dev; /* base device */ + struct sunfb sc_sunfb; /* common base part */ struct sbusdev sc_sd; /* sbus device */ - struct fbdevice sc_fb; /* frame buffer device */ volatile struct fbcontrol *sc_reg;/* control registers */ struct rom_reg sc_phys; /* phys address description */ int sc_bustype; /* type of bus we live on */ int sc_pixeloffset; /* offset to framebuffer */ -#if defined(SUN4) - /* - * Additional overlay plane goo. - */ - int sc_ovtype; /* what kind of color fb? */ -#define BWO_NONE 0x00 -#define BWO_CGFOUR 0x01 -#define BWO_CGEIGHT 0x02 -#endif + int sc_nscreens; +}; + +struct wsscreen_descr bwtwo_stdscreen = { + "std", + 0, 0, /* will be filled in */ + 0, + 0, 0, + WSSCREEN_REVERSE +}; + +const struct wsscreen_descr *bwtwo_scrlist[] = { + &bwtwo_stdscreen, +}; + +struct wsscreen_list bwtwo_screenlist = { + sizeof(bwtwo_scrlist) / sizeof(struct wsscreen_descr *), + bwtwo_scrlist +}; + +int bwtwo_ioctl(void *, u_long, caddr_t, int, struct proc *); +int bwtwo_alloc_screen(void *, const struct wsscreen_descr *, void **, + int *, int *, long *); +void bwtwo_free_screen(void *, void *); +int bwtwo_show_screen(void *, void *, int, void (*cb)(void *, int, int), + void *); +paddr_t bwtwo_mmap(void *, off_t, int); +void bwtwo_burner(void *, u_int, u_int); +int bwtwo_intr(void *); + +struct wsdisplay_accessops bwtwo_accessops = { + bwtwo_ioctl, + bwtwo_mmap, + bwtwo_alloc_screen, + bwtwo_free_screen, + bwtwo_show_screen, + NULL, /* load_font */ + NULL, /* scrollback */ + NULL, /* getchar */ + bwtwo_burner, }; + /* autoconfiguration driver */ -static void bwtwoattach(struct device *, struct device *, void *); -static int bwtwomatch(struct device *, void *, void *); -static void bwtwounblank(struct device *); -static void bwtwo_set_video(struct bwtwo_softc *, int); -static int bwtwo_get_video(struct bwtwo_softc *); +void bwtwoattach(struct device *, struct device *, void *); +int bwtwomatch(struct device *, void *, void *); struct cfattach bwtwo_ca = { sizeof(struct bwtwo_softc), bwtwomatch, bwtwoattach @@ -117,16 +149,6 @@ struct cfdriver bwtwo_cd = { NULL, "bwtwo", DV_DULL }; -/* XXX we do not handle frame buffer interrupts (do not know how) */ - -/* frame buffer generic driver */ -static struct fbdriver bwtwofbdriver = { - bwtwounblank, bwtwoopen, bwtwoclose, bwtwoioctl, bwtwommap -}; - -extern int fbnode; -extern struct tty *fbconstty; - /* * Match a bwtwo. */ @@ -139,17 +161,17 @@ bwtwomatch(parent, vcf, aux) struct confargs *ca = aux; struct romaux *ra = &ca->ca_ra; - if (CPU_ISSUN4 && cf->cf_unit != 0) - return (0); - - if (strcmp(cf->cf_driver->cd_name, ra->ra_name)) - return (0); - /* * Mask out invalid flags from the user. */ cf->cf_flags &= FB_USERMASK; + if (strcmp(cf->cf_driver->cd_name, ra->ra_name)) + return (0); + + if (CPU_ISSUN4 && cf->cf_unit != 0) + return (0); + if (ca->ca_bustype == BUS_SBUS) return(1); @@ -162,18 +184,19 @@ bwtwomatch(parent, vcf, aux) #if defined(SUN4) if (CPU_ISSUN4 && (ca->ca_bustype == BUS_OBIO)) { /* - * Check for a pfour framebuffer. + * Check for a pfour framebuffer, but do not match the + * overlay planes for color pfour framebuffers. */ switch (fb_pfour_id(ra->ra_vaddr)) { case PFOUR_ID_BW: - case PFOUR_ID_COLOR8P1: /* bwtwo in ... */ - case PFOUR_ID_COLOR24: /* ...overlay plane */ cf->cf_flags |= FB_PFOUR; /* FALLTHROUGH */ case PFOUR_NOTPFOUR: return (1); + case PFOUR_ID_COLOR8P1: /* bwtwo in ... */ + case PFOUR_ID_COLOR24: /* ...overlay plane */ default: return (0); } @@ -184,38 +207,39 @@ bwtwomatch(parent, vcf, aux) } /* - * Attach a display. We need to notice if it is the console, too. + * Attach a display. */ void bwtwoattach(parent, self, args) struct device *parent, *self; void *args; { - register struct bwtwo_softc *sc = (struct bwtwo_softc *)self; - register struct confargs *ca = args; - register int node = ca->ca_ra.ra_node, ramsize; - struct fbdevice *fb = &sc->sc_fb; + struct bwtwo_softc *sc = (struct bwtwo_softc *)self; + struct confargs *ca = args; + struct wsemuldisplaydev_attach_args waa; + int node = ca->ca_ra.ra_node; int isconsole = 0; int sbus = 1; char *nam = NULL; - fb->fb_driver = &bwtwofbdriver; - fb->fb_device = &sc->sc_dev; - fb->fb_type.fb_type = FBTYPE_SUN2BW; - fb->fb_flags = sc->sc_dev.dv_cfdata->cf_flags; + sc->sc_sunfb.sf_flags = self->dv_cfdata->cf_flags; /* * Map the control register. */ - if (fb->fb_flags & FB_PFOUR) { - fb->fb_pfour = (volatile u_int32_t *) +#if defined(SUN4) + if (CPU_ISSUN4 && ca->ca_bustype == BUS_OBIO && + ISSET(sc->sc_sunfb.sf_flags, FB_PFOUR)) { + sc->sc_sunfb.sf_pfour = (volatile u_int32_t *) mapiodev(ca->ca_ra.ra_reg, 0, sizeof(u_int32_t)); sc->sc_reg = NULL; - } else { + } else +#endif + { sc->sc_reg = (volatile struct fbcontrol *) mapiodev(ca->ca_ra.ra_reg, BWREG_REG, sizeof(struct fbcontrol)); - fb->fb_pfour = NULL; + sc->sc_sunfb.sf_pfour = NULL; } /* Set up default pixel offset. May be changed below. */ @@ -228,30 +252,9 @@ bwtwoattach(parent, self, args) sbus = node = 0; #if defined(SUN4) - if (fb->fb_flags & FB_PFOUR) { + if (ISSET(sc->sc_sunfb.sf_flags, FB_PFOUR)) { nam = "bwtwo/p4"; - /* - * Notice if this is an overlay plane on a color - * framebuffer. Note that PFOUR_COLOR_OFF_OVERLAY - * is the same as PFOUR_BW_OFF, but we use the - * different names anyway. - */ - switch (PFOUR_ID(*fb->fb_pfour)) { - case PFOUR_ID_COLOR8P1: - sc->sc_ovtype = BWO_CGFOUR; - sc->sc_pixeloffset = PFOUR_COLOR_OFF_OVERLAY; - break; - - case PFOUR_ID_COLOR24: - sc->sc_ovtype = BWO_CGEIGHT; - sc->sc_pixeloffset = PFOUR_COLOR_OFF_OVERLAY; - break; - - default: - sc->sc_ovtype = BWO_NONE; - sc->sc_pixeloffset = PFOUR_BW_OFF; - break; - } + sc->sc_pixeloffset = PFOUR_BW_OFF; } else #endif nam = "bwtwo"; @@ -264,180 +267,118 @@ bwtwoattach(parent, self, args) break; case BUS_SBUS: - obp_name: +obp_name: #if defined(SUN4C) || defined(SUN4M) nam = getpropstring(node, "model"); #endif break; } - sc->sc_phys = ca->ca_ra.ra_reg[0]; - sc->sc_bustype = ca->ca_bustype; - - fb->fb_type.fb_depth = 1; - fb_setsize(fb, fb->fb_type.fb_depth, 1152, 900, node, ca->ca_bustype); - - ramsize = fb->fb_type.fb_height * fb->fb_linebytes; - fb->fb_type.fb_cmsize = 0; - fb->fb_type.fb_size = ramsize; - printf(": %s, %d x %d", nam, - fb->fb_type.fb_width, fb->fb_type.fb_height); + printf(": %s", nam); #if defined(SUN4) if (CPU_ISSUN4) { struct eeprom *eep = (struct eeprom *)eeprom_va; - int constype = (fb->fb_flags & FB_PFOUR) ? EE_CONS_P4OPT : - EE_CONS_BW; + int constype = ISSET(sc->sc_sunfb.sf_flags, FB_PFOUR) ? + EE_CONS_P4OPT : EE_CONS_BW; /* * Assume this is the console if there's no eeprom info * to be found. */ if (eep == NULL || eep->eeConsole == constype) - isconsole = (fbconstty != NULL); + isconsole = 1; else - isconsole = 0; + /* + * On sun4 systems without on-board framebuffers (such as + * the 4/3xx models), the PROM will accept the EE_CONS_BW + * setting although the framebuffer is a P4. + * Accept this setting as well. + */ + if (eep->eeConsole == EE_CONS_BW) + isconsole = 1; } #endif if (CPU_ISSUN4COR4M) - isconsole = node == fbnode && fbconstty != NULL; - - /* - * When the ROM has mapped in a bwtwo display, the address - * maps only the video RAM, hence we always map the control - * registers ourselves. We only need the video RAM if we are - * going to print characters via rconsole. - */ - if ((fb->fb_pixels = ca->ca_ra.ra_vaddr) == NULL && isconsole) { - /* this probably cannot happen (on sun4c), but what the heck */ - fb->fb_pixels = - mapiodev(ca->ca_ra.ra_reg, sc->sc_pixeloffset, ramsize); - } - - /* Insure video is enabled */ - bwtwo_set_video(sc, 1); + isconsole = node == fbnode; - if (isconsole) { - printf(" (console)\n"); -#ifdef RASTERCONSOLE -#if defined(SUN4) - /* - * XXX rcons doesn't seem to work properly on the overlay - * XXX plane. This is a temporary kludge until someone - * XXX fixes it. - */ - if ((fb->fb_flags & FB_PFOUR) == 0 || - (sc->sc_ovtype == BWO_NONE)) -#endif - fbrcons_init(fb); -#endif - } else - printf("\n"); + sc->sc_phys = ca->ca_ra.ra_reg[0]; + sc->sc_bustype = ca->ca_bustype; -#if defined(SUN4C) || defined(SUN4M) - if (sbus) - sbus_establish(&sc->sc_sd, &sc->sc_dev); -#endif + /* enable video */ + bwtwo_burner(sc, 1, 0); -#if defined(SUN4) - if ((fb->fb_flags & FB_PFOUR) && (sc->sc_ovtype != BWO_NONE)) { - char *ovnam; + fb_setsize(&sc->sc_sunfb, 1, 1152, 900, node, ca->ca_bustype); + printf(", %d x %d\n", sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height); - switch (sc->sc_ovtype) { - case BWO_CGFOUR: - ovnam = "cgfour"; - break; + sc->sc_sunfb.sf_ro.ri_bits = mapiodev(ca->ca_ra.ra_reg, + sc->sc_pixeloffset, round_page(sc->sc_sunfb.sf_fbsize)); + sc->sc_sunfb.sf_ro.ri_hw = sc; + fbwscons_init(&sc->sc_sunfb, isconsole); - case BWO_CGEIGHT: - ovnam = "cgeight"; - break; + bwtwo_stdscreen.nrows = sc->sc_sunfb.sf_ro.ri_rows; + bwtwo_stdscreen.ncols = sc->sc_sunfb.sf_ro.ri_cols; + bwtwo_stdscreen.textops = &sc->sc_sunfb.sf_ro.ri_ops; - default: - ovnam = "unknown"; - break; - } - printf("%s: %s overlay plane\n", sc->sc_dev.dv_xname, ovnam); + if (isconsole) { + fbwscons_console_init(&sc->sc_sunfb, &bwtwo_stdscreen, -1, + NULL, bwtwo_burner); } -#endif - if (CPU_ISSUN4 || node == fbnode) { -#if defined(SUN4) - /* - * If we're on an overlay plane of a color framebuffer, - * then we don't force the issue in fb_attach() because - * we'd like the color framebuffer to actually be the - * "console framebuffer". We're only around to speed - * up rconsole. - */ - if ((fb->fb_flags & FB_PFOUR) && (sc->sc_ovtype != BWO_NONE )) - fb_attach(fb, 0); - else +#if defined(SUN4C) || defined(SUN4M) + if (sbus) + sbus_establish(&sc->sc_sd, &sc->sc_sunfb.sf_dev); #endif - fb_attach(fb, isconsole); - } -} - -int -bwtwoopen(dev, flags, mode, p) - dev_t dev; - int flags, mode; - struct proc *p; -{ - int unit = minor(dev); - - if (unit >= bwtwo_cd.cd_ndevs || bwtwo_cd.cd_devs[unit] == NULL) - return (ENXIO); - - return (0); -} - -int -bwtwoclose(dev, flags, mode, p) - dev_t dev; - int flags, mode; - struct proc *p; -{ - return (0); + waa.console = isconsole; + waa.scrdata = &bwtwo_screenlist; + waa.accessops = &bwtwo_accessops; + waa.accesscookie = sc; + config_found(self, &waa, wsemuldisplaydevprint); } int -bwtwoioctl(dev, cmd, data, flags, p) - dev_t dev; +bwtwo_ioctl(v, cmd, data, flags, p) + void *v; u_long cmd; caddr_t data; int flags; struct proc *p; { - struct bwtwo_softc *sc = bwtwo_cd.cd_devs[minor(dev)]; + struct bwtwo_softc *sc = v; + struct wsdisplay_fbinfo *wdf; switch (cmd) { - - case FBIOGTYPE: - *(struct fbtype *)data = sc->sc_fb.fb_type; + case WSDISPLAYIO_GTYPE: + *(u_int *)data = WSDISPLAY_TYPE_SUNBW; break; - - case FBIOGVIDEO: - *(int *)data = bwtwo_get_video(sc); + case WSDISPLAYIO_GINFO: + wdf = (struct wsdisplay_fbinfo *)data; + wdf->height = sc->sc_sunfb.sf_height; + wdf->width = sc->sc_sunfb.sf_width; + wdf->depth = sc->sc_sunfb.sf_depth; + wdf->cmsize = 0; /* no colormap */ + break; + case WSDISPLAYIO_LINEBYTES: + *(u_int *)data = sc->sc_sunfb.sf_linebytes; break; - case FBIOSVIDEO: - bwtwo_set_video(sc, (*(int *)data)); + case WSDISPLAYIO_GETCMAP: + case WSDISPLAYIO_PUTCMAP: break; + case WSDISPLAYIO_SVIDEO: + case WSDISPLAYIO_GVIDEO: + case WSDISPLAYIO_GCURPOS: + case WSDISPLAYIO_SCURPOS: + case WSDISPLAYIO_GCURMAX: + case WSDISPLAYIO_GCURSOR: + case WSDISPLAYIO_SCURSOR: default: - return (ENOTTY); + return (-1); /* not supported yet */ } - return (0); -} - -static void -bwtwounblank(dev) - struct device *dev; -{ - struct bwtwo_softc *sc = (struct bwtwo_softc *)dev; - bwtwo_set_video(sc, 1); + return (0); } /* @@ -445,64 +386,39 @@ bwtwounblank(dev) * offset, allowing for the given protection, or return -1 for error. */ paddr_t -bwtwommap(dev, off, prot) - dev_t dev; - off_t off; +bwtwo_mmap(v, offset, prot) + void *v; + off_t offset; int prot; { - register struct bwtwo_softc *sc = bwtwo_cd.cd_devs[minor(dev)]; + struct bwtwo_softc *sc = v; - if (off & PGOFSET) - panic("bwtwommap"); - if (off < 0) + if (offset & PGOFSET) return (-1); - if ((unsigned)off >= sc->sc_fb.fb_type.fb_size) - return (-1); - /* - * I turned on PMAP_NC here to disable the cache as I was - * getting horribly broken behaviour with it on. - */ - return (REG2PHYS(&sc->sc_phys, sc->sc_pixeloffset + off) | PMAP_NC); -} -static int -bwtwo_get_video(sc) - struct bwtwo_softc *sc; -{ - -#if defined(SUN4) - if (CPU_ISSUN4 && (sc->sc_bustype == BUS_OBIO)) { - if (sc->sc_fb.fb_flags & FB_PFOUR) { - /* - * This handles the overlay plane case, too. - */ - return (fb_pfour_get_video(&sc->sc_fb)); - } else - return ((lduba(AC_SYSENABLE, - ASI_CONTROL) & SYSEN_VIDEO) != 0); + if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize) { + return (REG2PHYS(&sc->sc_phys, sc->sc_pixeloffset + offset) | + PMAP_NC); } -#endif - return ((sc->sc_reg->fbc_ctrl & FBC_VENAB) != 0); + return (-1); } -static void -bwtwo_set_video(sc, enable) - struct bwtwo_softc *sc; - int enable; +void +bwtwo_burner(v, on, flags) + void *v; + u_int on, flags; { - extern int sparc_vsyncblank; + struct bwtwo_softc *sc = v; + int s; #if defined(SUN4) if (CPU_ISSUN4 && (sc->sc_bustype == BUS_OBIO)) { - if (sc->sc_fb.fb_flags & FB_PFOUR) { - /* - * This handles the overlay plane case, too. - */ - fb_pfour_set_video(&sc->sc_fb, enable); + if (ISSET(sc->sc_sunfb.sf_flags, FB_PFOUR)) { + fb_pfour_set_video(&sc->sc_sunfb, on); return; } - if (enable) + if (on) stba(AC_SYSENABLE, ASI_CONTROL, lduba(AC_SYSENABLE, ASI_CONTROL) | SYSEN_VIDEO); else @@ -513,11 +429,56 @@ bwtwo_set_video(sc, enable) } #endif - if (enable) + s = splhigh(); + if (on) sc->sc_reg->fbc_ctrl |= FBC_VENAB | FBC_TIMING; else { sc->sc_reg->fbc_ctrl &= ~FBC_VENAB; - if (sparc_vsyncblank) + if (flags & WSDISPLAY_BURN_VBLANK) sc->sc_reg->fbc_ctrl &= ~FBC_TIMING; } + splx(s); +} + +int +bwtwo_alloc_screen(v, type, cookiep, curxp, curyp, attrp) + void *v; + const struct wsscreen_descr *type; + void **cookiep; + int *curxp, *curyp; + long *attrp; +{ + struct bwtwo_softc *sc = v; + + if (sc->sc_nscreens > 0) + return (ENOMEM); + + *cookiep = &sc->sc_sunfb.sf_ro; + *curyp = 0; + *curxp = 0; + sc->sc_sunfb.sf_ro.ri_ops.alloc_attr(&sc->sc_sunfb.sf_ro, + 0, 0, 0, attrp); + sc->sc_nscreens++; + return (0); +} + +void +bwtwo_free_screen(v, cookie) + void *v; + void *cookie; +{ + struct bwtwo_softc *sc = v; + + sc->sc_nscreens--; +} + +int +bwtwo_show_screen(v, cookie, waitok, cb, cbarg) + void *v; + void *cookie; + int waitok; + void (*cb)(void *, int, int); + void *cbarg; +{ + return (0); } diff --git a/sys/arch/sparc/dev/cgeight.c b/sys/arch/sparc/dev/cgeight.c index 1ced12ab486..344925dfaa9 100644 --- a/sys/arch/sparc/dev/cgeight.c +++ b/sys/arch/sparc/dev/cgeight.c @@ -1,7 +1,8 @@ -/* $OpenBSD: cgeight.c,v 1.13 2002/03/14 01:26:42 millert Exp $ */ +/* $OpenBSD: cgeight.c,v 1.14 2002/08/12 10:44:03 miod Exp $ */ /* $NetBSD: cgeight.c,v 1.13 1997/05/24 20:16:04 pk Exp $ */ /* + * Copyright (c) 2002 Miodrag Vallat. All rights reserved. * Copyright (c) 1996 Jason R. Thorpe. All rights reserved. * Copyright (c) 1995 Theo de Raadt * Copyright (c) 1992, 1993 @@ -67,55 +68,80 @@ #include <uvm/uvm_extern.h> -#include <machine/fbio.h> #include <machine/autoconf.h> #include <machine/pmap.h> -#include <machine/fbvar.h> #include <machine/eeprom.h> #include <machine/conf.h> +#include <dev/wscons/wsconsio.h> +#include <dev/wscons/wsdisplayvar.h> +#include <dev/wscons/wscons_raster.h> +#include <dev/rasops/rasops.h> +#include <machine/fbvar.h> + #include <sparc/dev/btreg.h> #include <sparc/dev/btvar.h> #include <sparc/dev/pfourreg.h> /* per-display variables */ struct cgeight_softc { - struct device sc_dev; /* base device */ - struct fbdevice sc_fb; /* frame buffer device */ - struct rom_reg sc_phys; /* display RAM (phys addr) */ + struct sunfb sc_sunfb; /* common base part */ + struct rom_reg sc_phys; /* display RAM (phys addr) */ volatile struct fbcontrol *sc_fbc; /* Brooktree registers */ - int sc_bustype; /* type of bus we live on */ union bt_cmap sc_cmap; /* Brooktree color map */ + int sc_nscreens; }; -/* autoconfiguration driver */ -static void cgeightattach(struct device *, struct device *, void *); -static int cgeightmatch(struct device *, void *, void *); -#if defined(SUN4) -static void cgeightunblank(struct device *); -#endif +struct wsscreen_descr cgeight_stdscreen = { + "std", + 0, 0, /* will be filled in */ + 0, + 0, 0, + WSSCREEN_REVERSE | WSSCREEN_WSCOLORS +}; -struct cfattach cgeight_ca = { - sizeof(struct cgeight_softc), cgeightmatch, cgeightattach +const struct wsscreen_descr *cgeight_scrlist[] = { + &cgeight_stdscreen, }; -struct cfdriver cgeight_cd = { - NULL, "cgeight", DV_DULL +struct wsscreen_list cgeight_screenlist = { + sizeof(cgeight_scrlist) /sizeof(struct wsscreen_descr *), + cgeight_scrlist }; -#if defined(SUN4) -/* frame buffer generic driver */ -static struct fbdriver cgeightfbdriver = { - cgeightunblank, cgeightopen, cgeightclose, cgeightioctl, cgeightmmap +int cgeight_ioctl(void *, u_long, caddr_t, int, struct proc *); +int cgeight_alloc_screen(void *, const struct wsscreen_descr *, void **, + int *, int *, long *); +void cgeight_free_screen(void *, void *); +int cgeight_show_screen(void *, void *, int, void (*cb)(void *, int, int), + void *); +paddr_t cgeight_mmap(void *, off_t, int); +int cgeight_is_console(int); +void cgeight_reset(struct cgeight_softc *); +void cgeight_burner(void *, u_int, u_int); + +struct wsdisplay_accessops cgeight_accessops = { + cgeight_ioctl, + cgeight_mmap, + cgeight_alloc_screen, + cgeight_free_screen, + cgeight_show_screen, + NULL, /* load_font */ + NULL, /* scrollback */ + NULL, /* getchar */ + cgeight_burner, }; -extern int fbnode; -extern struct tty *fbconstty; +void cgeightattach(struct device *, struct device *, void *); +int cgeightmatch(struct device *, void *, void *); -static void cgeightloadcmap(struct cgeight_softc *, int, int); -static int cgeight_get_video(struct cgeight_softc *); -static void cgeight_set_video(struct cgeight_softc *, int); -#endif +struct cfattach cgeight_ca = { + sizeof(struct cgeight_softc), cgeightmatch, cgeightattach +}; + +struct cfdriver cgeight_cd = { + NULL, "cgeight", DV_DULL +}; /* * Match a cgeight. @@ -129,24 +155,15 @@ cgeightmatch(parent, vcf, aux) struct confargs *ca = aux; struct romaux *ra = &ca->ca_ra; - if (strcmp(cf->cf_driver->cd_name, ra->ra_name)) - return (0); - /* * Mask out invalid flags from the user. */ cf->cf_flags &= FB_USERMASK; - /* - * Only exists on a sun4. - */ - if (!CPU_ISSUN4) + if (strcmp(cf->cf_driver->cd_name, ra->ra_name)) return (0); - /* - * Only exists on obio. - */ - if (ca->ca_bustype != BUS_OBIO) + if (!CPU_ISSUN4 || ca->ca_bustype != BUS_OBIO) return (0); /* @@ -155,7 +172,6 @@ cgeightmatch(parent, vcf, aux) if (probeget(ra->ra_vaddr, 4) == -1) return (0); -#if defined(SUN4) /* * Check the pfour register. */ @@ -163,57 +179,31 @@ cgeightmatch(parent, vcf, aux) cf->cf_flags |= FB_PFOUR; return (1); } -#endif return (0); } /* - * Attach a display. We need to notice if it is the console, too. + * Attach a display. */ void cgeightattach(parent, self, args) struct device *parent, *self; void *args; { -#if defined(SUN4) - register struct cgeight_softc *sc = (struct cgeight_softc *)self; - register struct confargs *ca = args; - register int node = 0, ramsize, i; - register volatile struct bt_regs *bt; - struct fbdevice *fb = &sc->sc_fb; - int isconsole; - - fb->fb_driver = &cgeightfbdriver; - fb->fb_device = &sc->sc_dev; - fb->fb_type.fb_type = FBTYPE_MEMCOLOR; - fb->fb_flags = sc->sc_dev.dv_cfdata->cf_flags; + struct cgeight_softc *sc = (struct cgeight_softc *)self; + struct confargs *ca = args; + struct wsemuldisplaydev_attach_args waa; + int node = 0, i; + volatile struct bt_regs *bt; + int isconsole = 0; - /* - * Only pfour cgfours, thank you... - */ - if ((ca->ca_bustype != BUS_OBIO) || - ((fb->fb_flags & FB_PFOUR) == 0)) { - printf("%s: ignoring; not a pfour\n", sc->sc_dev.dv_xname); - return; - } + sc->sc_sunfb.sf_flags = self->dv_cfdata->cf_flags; /* Map the pfour register. */ - fb->fb_pfour = (volatile u_int32_t *) + sc->sc_sunfb.sf_pfour = (volatile u_int32_t *) mapiodev(ca->ca_ra.ra_reg, 0, sizeof(u_int32_t)); - ramsize = PFOUR_COLOR_OFF_END - PFOUR_COLOR_OFF_OVERLAY; - - fb->fb_type.fb_depth = 24; - fb_setsize(fb, fb->fb_type.fb_depth, 1152, 900, node, ca->ca_bustype); - - sc->sc_fb.fb_type.fb_cmsize = 256; - sc->sc_fb.fb_type.fb_size = ramsize; - printf(": cgeight/p4, %d x %d", fb->fb_type.fb_width, - fb->fb_type.fb_height); - - isconsole = 0; - if (cputyp == CPU_SUN4) { struct eeprom *eep = (struct eeprom *)eeprom_va; @@ -222,45 +212,15 @@ cgeightattach(parent, self, args) * to be found. */ if (eep == NULL || eep->eeConsole == EE_CONS_P4OPT) - isconsole = (fbconstty != NULL); + isconsole = 1; } -#if 0 - /* - * We don't do any of the console handling here. Instead, - * we let the bwtwo driver pick up the overlay plane and - * use it instead. Rconsole should have better performance - * with the 1-bit depth. - * -- Jason R. Thorpe <thorpej@NetBSD.ORG> - */ - - /* - * When the ROM has mapped in a cgfour display, the address - * maps only the video RAM, so in any case we have to map the - * registers ourselves. We only need the video RAM if we are - * going to print characters via rconsole. - */ - - if (isconsole) { - /* XXX this is kind of a waste */ - fb->fb_pixels = mapiodev(ca->ca_ra.ra_reg, - PFOUR_COLOR_OFF_OVERLAY, ramsize); - } -#endif - /* Map the Brooktree. */ sc->sc_fbc = (volatile struct fbcontrol *) mapiodev(ca->ca_ra.ra_reg, PFOUR_COLOR_OFF_CMAP, sizeof(struct fbcontrol)); sc->sc_phys = ca->ca_ra.ra_reg[0]; - sc->sc_bustype = ca->ca_bustype; - -#if 0 /* XXX thorpej ??? */ - /* tell the enable plane to look at the mono image */ - memset(ca->ca_ra.ra_vaddr, 0xff, - sc->sc_fb.fb_type.fb_width * sc->sc_fb.fb_type.fb_height / 8); -#endif /* grab initial (current) color map */ bt = &sc->sc_fbc->fbc_dac; @@ -268,245 +228,162 @@ cgeightattach(parent, self, args) for (i = 0; i < 256 * 3 / 4; i++) sc->sc_cmap.cm_chip[i] = bt->bt_cmap; + /* enable video */ + cgeight_burner(sc, 1, 0); BT_INIT(bt, 0); -#if 0 /* see above */ - if (isconsole) { - printf(" (console)\n"); -#if defined(RASTERCONSOLE) && 0 /* XXX been told it doesn't work well. */ - fbrcons_init(fb); -#endif - } else -#endif /* 0 */ - printf("\n"); + fb_setsize(&sc->sc_sunfb, 24, 1152, 900, node, ca->ca_bustype); + sc->sc_sunfb.sf_ro.ri_hw = sc; + sc->sc_sunfb.sf_ro.ri_bits = mapiodev(ca->ca_ra.ra_reg, + PFOUR_COLOR_OFF_OVERLAY, round_page(sc->sc_sunfb.sf_fbsize)); + fbwscons_init(&sc->sc_sunfb, isconsole); - /* - * Even though we're not using rconsole, we'd still like - * to notice if we're the console framebuffer. - */ - fb_attach(&sc->sc_fb, isconsole); -#endif -} + cgeight_stdscreen.nrows = sc->sc_sunfb.sf_ro.ri_rows; + cgeight_stdscreen.ncols = sc->sc_sunfb.sf_ro.ri_cols; + cgeight_stdscreen.textops = &sc->sc_sunfb.sf_ro.ri_ops; -int -cgeightopen(dev, flags, mode, p) - dev_t dev; - int flags, mode; - struct proc *p; -{ - int unit = minor(dev); + printf(": cgeight/p4, %dx%d", sc->sc_sunfb.sf_width, + sc->sc_sunfb.sf_height); - if (unit >= cgeight_cd.cd_ndevs || cgeight_cd.cd_devs[unit] == NULL) - return (ENXIO); - return (0); -} - -int -cgeightclose(dev, flags, mode, p) - dev_t dev; - int flags, mode; - struct proc *p; -{ + if (isconsole) { + fbwscons_console_init(&sc->sc_sunfb, &cgeight_stdscreen, -1, + NULL, cgeight_burner); + } - return (0); + waa.console = isconsole; + waa.scrdata = &cgeight_screenlist; + waa.accessops = &cgeight_accessops; + waa.accesscookie = sc; + config_found(self, &waa, wsemuldisplaydevprint); } int -cgeightioctl(dev, cmd, data, flags, p) - dev_t dev; +cgeight_ioctl(v, cmd, data, flags, p) + void *v; u_long cmd; - register caddr_t data; + caddr_t data; int flags; struct proc *p; { -#if defined(SUN4) - register struct cgeight_softc *sc = cgeight_cd.cd_devs[minor(dev)]; - register struct fbgattr *fba; + struct cgeight_softc *sc = v; + struct wsdisplay_cmap *cm; + struct wsdisplay_fbinfo *wdf; int error; switch (cmd) { - - case FBIOGTYPE: - *(struct fbtype *)data = sc->sc_fb.fb_type; + case WSDISPLAYIO_GTYPE: + *(u_int *)data = WSDISPLAY_TYPE_UNKNOWN; break; - - case FBIOGATTR: - fba = (struct fbgattr *)data; - fba->real_type = sc->sc_fb.fb_type.fb_type; - fba->owner = 0; /* XXX ??? */ - fba->fbtype = sc->sc_fb.fb_type; - fba->sattr.flags = 0; - fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type; - fba->sattr.dev_specific[0] = -1; - fba->emu_types[0] = sc->sc_fb.fb_type.fb_type; - fba->emu_types[1] = -1; + case WSDISPLAYIO_GINFO: + wdf = (struct wsdisplay_fbinfo *)data; + wdf->height = sc->sc_sunfb.sf_height; + wdf->width = sc->sc_sunfb.sf_width; + wdf->depth = sc->sc_sunfb.sf_depth; + wdf->cmsize = 256; break; - - case FBIOGETCMAP: - return (bt_getcmap((struct fbcmap *)data, &sc->sc_cmap, 256)); - - case FBIOPUTCMAP: - /* copy to software map */ -#define p ((struct fbcmap *)data) - error = bt_putcmap(p, &sc->sc_cmap, 256); + case WSDISPLAYIO_GETCMAP: + cm = (struct wsdisplay_cmap *)data; + error = bt_getcmap(&sc->sc_cmap, cm); if (error) return (error); - /* now blast them into the chip */ - /* XXX should use retrace interrupt */ - cgeightloadcmap(sc, p->index, p->count); -#undef p - break; - - case FBIOGVIDEO: - *(int *)data = cgeight_get_video(sc); break; - - case FBIOSVIDEO: - cgeight_set_video(sc, *(int *)data); + case WSDISPLAYIO_PUTCMAP: + cm = (struct wsdisplay_cmap *)data; + error = bt_putcmap(&sc->sc_cmap, cm); + if (error) + return (error); + bt_loadcmap(&sc->sc_cmap, &sc->sc_fbc->fbc_dac, + cm->index, cm->count, 0); break; + case WSDISPLAYIO_SVIDEO: + case WSDISPLAYIO_GVIDEO: + case WSDISPLAYIO_GCURPOS: + case WSDISPLAYIO_SCURPOS: + case WSDISPLAYIO_GCURMAX: + case WSDISPLAYIO_GCURSOR: + case WSDISPLAYIO_SCURSOR: default: - return (ENOTTY); + return (-1); /* not supported yet */ + } -#endif + return (0); } -/* - * Return the address that would map the given device at the given - * offset, allowing for the given protection, or return -1 for error. - * - * The cg8 maps it's overlay plane at 0 for 128K, followed by the - * enable plane for 128K, followed by the colour for as long as it - * goes. Starting at 8MB, it maps the ramdac for NBPG, then the p4 - * register for NBPG, then the bootrom for 0x40000. - */ -paddr_t -cgeightmmap(dev, off, prot) - dev_t dev; - off_t off; - int prot; +int +cgeight_alloc_screen(v, type, cookiep, curxp, curyp, attrp) + void *v; + const struct wsscreen_descr *type; + void **cookiep; + int *curxp, *curyp; + long *attrp; { - register struct cgeight_softc *sc = cgeight_cd.cd_devs[minor(dev)]; - int poff; - -#define START_ENABLE (128*1024) -#define START_COLOR ((128*1024) + (128*1024)) -#define COLOR_SIZE (sc->sc_fb.fb_type.fb_width * \ - sc->sc_fb.fb_type.fb_height * 3) -#define END_COLOR (START_COLOR + COLOR_SIZE) -#define START_SPECIAL 0x800000 -#define PROMSIZE 0x40000 -#define NOOVERLAY (0x04000000) - - if (off & PGOFSET) - panic("cgeightmap"); - - if (off < 0) - return (-1); - if ((u_int)off >= NOOVERLAY) { - off -= NOOVERLAY; + struct cgeight_softc *sc = v; - /* - * X11 maps a huge chunk of the frame buffer; far more than - * there really is. We compensate by double-mapping the - * first page for as many other pages as it wants - */ - while ((u_int)off >= COLOR_SIZE) - off -= COLOR_SIZE; /* XXX thorpej ??? */ + if (sc->sc_nscreens > 0) + return (ENOMEM); - poff = off + PFOUR_COLOR_OFF_COLOR; - } else if ((u_int)off < START_ENABLE) { - /* - * in overlay plane - */ - poff = PFOUR_COLOR_OFF_OVERLAY + off; - } else if ((u_int)off < START_COLOR) { - /* - * in enable plane - */ - poff = (off - START_ENABLE) + PFOUR_COLOR_OFF_ENABLE; - } else if ((u_int)off < sc->sc_fb.fb_type.fb_size) { - /* - * in colour plane - */ - poff = (off - START_COLOR) + PFOUR_COLOR_OFF_COLOR; - } else if ((u_int)off < START_SPECIAL) { - /* - * hole - */ - poff = 0; /* XXX */ - } else if ((u_int)off == START_SPECIAL) { - /* - * colour map (Brooktree) - */ - poff = PFOUR_COLOR_OFF_CMAP; - } else if ((u_int)off == START_SPECIAL + NBPG) { - /* - * p4 register - */ - poff = 0; - } else if ((u_int)off > (START_SPECIAL + (NBPG * 2)) && - (u_int) off < (START_SPECIAL + (NBPG * 2) + PROMSIZE)) { - /* - * rom - */ - poff = 0x8000 + (off - (START_SPECIAL + (NBPG * 2))); - } else - return (-1); - /* - * I turned on PMAP_NC here to disable the cache as I was - * getting horribly broken behaviour with it on. - */ - return (REG2PHYS(&sc->sc_phys, poff) | PMAP_NC); + *cookiep = &sc->sc_sunfb.sf_ro; + *curyp = 0; + *curxp = 0; + sc->sc_sunfb.sf_ro.ri_ops.alloc_attr(&sc->sc_sunfb.sf_ro, + 0, 0, 0, attrp); + sc->sc_nscreens++; + return (0); } -#if defined(SUN4) -/* - * Undo the effect of an FBIOSVIDEO that turns the video off. - */ -static void -cgeightunblank(dev) - struct device *dev; +void +cgeight_free_screen(v, cookie) + void *v; + void *cookie; { + struct cgeight_softc *sc = v; - cgeight_set_video((struct cgeight_softc *)dev, 1); + sc->sc_nscreens--; } -static int -cgeight_get_video(sc) - struct cgeight_softc *sc; +int +cgeight_show_screen(v, cookie, waitok, cb, cbarg) + void *v; + void *cookie; + int waitok; + void (*cb)(void *, int, int); + void *cbarg; { - - return (fb_pfour_get_video(&sc->sc_fb)); + return (0); } -static void -cgeight_set_video(sc, enable) - struct cgeight_softc *sc; - int enable; +/* + * Return the address that would map the given device at the given + * offset, allowing for the given protection, or return -1 for error. + */ +paddr_t +cgeight_mmap(v, offset, prot) + void *v; + off_t offset; + int prot; { + struct cgeight_softc *sc = v; + + if (offset & PGOFSET) + return (-1); + + /* Allow mapping as a dumb framebuffer from offset 0 */ + if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize) { + return (REG2PHYS(&sc->sc_phys, offset + + PFOUR_COLOR_OFF_OVERLAY) | PMAP_NC); + } - fb_pfour_set_video(&sc->sc_fb, enable); + return (-1); /* not a user-map offset */ } -/* - * Load a subset of the current (new) colormap into the Brooktree DAC. - */ -static void -cgeightloadcmap(sc, start, ncolors) - register struct cgeight_softc *sc; - register int start, ncolors; +void +cgeight_burner(v, on, flags) + void *v; + u_int on, flags; { - register volatile struct bt_regs *bt; - register u_int *ip; - register int count; + struct cgeight_softc *sc = v; - ip = &sc->sc_cmap.cm_chip[BT_D4M3(start)]; /* start/4 * 3 */ - count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3; - bt = &sc->sc_fbc->fbc_dac; - bt->bt_addr = BT_D4M4(start); - while (--count >= 0) - bt->bt_cmap = *ip++; + fb_pfour_set_video(&sc->sc_sunfb, on); } -#endif diff --git a/sys/arch/sparc/dev/cgfour.c b/sys/arch/sparc/dev/cgfour.c index af24d4e5b9a..fb7eae702f2 100644 --- a/sys/arch/sparc/dev/cgfour.c +++ b/sys/arch/sparc/dev/cgfour.c @@ -1,7 +1,8 @@ -/* $OpenBSD: cgfour.c,v 1.13 2002/03/14 01:26:42 millert Exp $ */ +/* $OpenBSD: cgfour.c,v 1.14 2002/08/12 10:44:03 miod Exp $ */ /* $NetBSD: cgfour.c,v 1.13 1997/05/24 20:16:06 pk Exp $ */ /* + * Coyrpight (c) 2002 Miodrag Vallat. All rights reserved. * Copyright (c) 1996 Jason R. Thorpe. All rights reserved. * Copyright (c) 1995 Theo de Raadt. All rights reserved. * Copyright (c) 1992, 1993 @@ -69,57 +70,81 @@ #include <sys/tty.h> #include <sys/conf.h> -#include <uvm/uvm_extern.h> +#include <uvm/uvm_extern.h> /* NBPG */ -#include <machine/fbio.h> #include <machine/autoconf.h> #include <machine/pmap.h> -#include <machine/fbvar.h> #include <machine/eeprom.h> #include <machine/conf.h> +#include <dev/wscons/wsconsio.h> +#include <dev/wscons/wsdisplayvar.h> +#include <dev/wscons/wscons_raster.h> +#include <dev/rasops/rasops.h> +#include <machine/fbvar.h> + #include <sparc/dev/btreg.h> #include <sparc/dev/btvar.h> #include <sparc/dev/pfourreg.h> /* per-display variables */ struct cgfour_softc { - struct device sc_dev; /* base device */ - struct fbdevice sc_fb; /* frame buffer device */ + struct sunfb sc_sunfb; /* common base part */ struct rom_reg sc_phys; /* display RAM (phys addr) */ volatile struct fbcontrol *sc_fbc; /* Brooktree registers */ - int sc_bustype; /* type of bus we live on */ union bt_cmap sc_cmap; /* Brooktree color map */ + int sc_nscreens; }; -/* autoconfiguration driver */ -static void cgfourattach(struct device *, struct device *, void *); -static int cgfourmatch(struct device *, void *, void *); -#if defined(SUN4) -static void cgfourunblank(struct device *); -#endif +struct wsscreen_descr cgfour_stdscreen = { + "std", + 0, 0, /* will be filled in */ + 0, + 0, 0, + WSSCREEN_REVERSE | WSSCREEN_WSCOLORS +}; -struct cfattach cgfour_ca = { - sizeof(struct cgfour_softc), cgfourmatch, cgfourattach +const struct wsscreen_descr *cgfour_scrlist[] = { + &cgfour_stdscreen, }; -struct cfdriver cgfour_cd = { - NULL, "cgfour", DV_DULL +struct wsscreen_list cgfour_screenlist = { + sizeof(cgfour_scrlist) / sizeof(struct wsscreen_descr *), + cgfour_scrlist }; -#if defined(SUN4) -/* frame buffer generic driver */ -static struct fbdriver cgfourfbdriver = { - cgfourunblank, cgfouropen, cgfourclose, cgfourioctl, cgfourmmap +int cgfour_ioctl(void *, u_long, caddr_t, int, struct proc *); +int cgfour_alloc_screen(void *, const struct wsscreen_descr *, void **, + int *, int *, long *); +void cgfour_free_screen(void *, void *); +int cgfour_show_screen(void *, void *, int, void (*cb)(void *, int, int), + void *); +paddr_t cgfour_mmap(void *, off_t, int); +void cgfour_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t); +void cgfour_burner(void *, u_int, u_int); + +struct wsdisplay_accessops cgfour_accessops = { + cgfour_ioctl, + cgfour_mmap, + cgfour_alloc_screen, + cgfour_free_screen, + cgfour_show_screen, + NULL, /* load_font */ + NULL, /* scrollback */ + NULL, /* getchar */ + cgfour_burner, }; -extern int fbnode; -extern struct tty *fbconstty; +void cgfourattach(struct device *, struct device *, void *); +int cgfourmatch(struct device *, void *, void *); -static void cgfourloadcmap(struct cgfour_softc *, int, int); -static int cgfour_get_video(struct cgfour_softc *); -static void cgfour_set_video(struct cgfour_softc *, int); -#endif +struct cfattach cgfour_ca = { + sizeof(struct cgfour_softc), cgfourmatch, cgfourattach +}; + +struct cfdriver cgfour_cd = { + NULL, "cgfour", DV_DULL +}; /* * Match a cgfour. @@ -133,33 +158,20 @@ cgfourmatch(parent, vcf, aux) struct confargs *ca = aux; struct romaux *ra = &ca->ca_ra; - if (strcmp(cf->cf_driver->cd_name, ra->ra_name)) - return (0); - /* * Mask out invalid flags from the user. */ cf->cf_flags &= FB_USERMASK; - /* - * Only exists on a sun4. - */ - if (!CPU_ISSUN4) + if (strcmp(cf->cf_driver->cd_name, ra->ra_name)) return (0); - /* - * Only exists on obio. - */ - if (ca->ca_bustype != BUS_OBIO) + if (!CPU_ISSUN4 || ca->ca_bustype != BUS_OBIO) return (0); - /* - * Make sure there's hardware there. - */ if (probeget(ra->ra_vaddr, 4) == -1) return (0); -#if defined(SUN4) /* * Check the pfour register. */ @@ -167,56 +179,28 @@ cgfourmatch(parent, vcf, aux) cf->cf_flags |= FB_PFOUR; return (1); } -#endif return (0); } /* - * Attach a display. We need to notice if it is the console, too. + * Attach a display. */ void cgfourattach(parent, self, args) struct device *parent, *self; void *args; { -#if defined(SUN4) - register struct cgfour_softc *sc = (struct cgfour_softc *)self; - register struct confargs *ca = args; - register int node = 0, ramsize, i; - register volatile struct bt_regs *bt; - struct fbdevice *fb = &sc->sc_fb; - int isconsole; - - fb->fb_driver = &cgfourfbdriver; - fb->fb_device = &sc->sc_dev; - fb->fb_type.fb_type = FBTYPE_SUN4COLOR; - fb->fb_flags = sc->sc_dev.dv_cfdata->cf_flags; + struct cgfour_softc *sc = (struct cgfour_softc *)self; + struct confargs *ca = args; + struct wsemuldisplaydev_attach_args waa; + int node = 0, i; + volatile struct bt_regs *bt; + int isconsole = 0; - /* - * Only pfour cgfours, thank you... - */ - if ((ca->ca_bustype != BUS_OBIO) || - ((fb->fb_flags & FB_PFOUR) == 0)) { - printf("%s: ignoring; not a pfour\n", sc->sc_dev.dv_xname); - return; - } + sc->sc_sunfb.sf_flags = self->dv_cfdata->cf_flags; - /* Map the pfour register. */ - fb->fb_pfour = (volatile u_int32_t *) - mapiodev(ca->ca_ra.ra_reg, 0, sizeof(u_int32_t)); - - ramsize = PFOUR_COLOR_OFF_END - PFOUR_COLOR_OFF_OVERLAY; - - fb->fb_type.fb_depth = 8; - fb_setsize(fb, fb->fb_type.fb_depth, 1152, 900, node, ca->ca_bustype); - - fb->fb_type.fb_cmsize = 256; - fb->fb_type.fb_size = ramsize; - printf(": cgfour/p4, %d x %d", fb->fb_type.fb_width, - fb->fb_type.fb_height); - - isconsole = 0; + printf(": cgfour/p4"); if (CPU_ISSUN4) { struct eeprom *eep = (struct eeprom *)eeprom_va; @@ -226,17 +210,12 @@ cgfourattach(parent, self, args) * to be found. */ if (eep == NULL || eep->eeConsole == EE_CONS_P4OPT) - isconsole = (fbconstty != NULL); + isconsole = 1; } -#if 0 - /* - * We don't do any of the console handling here. Instead, - * we let the bwtwo driver pick up the overlay plane and - * use it instead. Rconsole should have better performance - * with the 1-bit depth. - * -- Jason R. Thorpe <thorpej@NetBSD.ORG> - */ + /* Map the pfour register. */ + sc->sc_sunfb.sf_pfour = (volatile u_int32_t *) + mapiodev(ca->ca_ra.ra_reg, 0, sizeof(u_int32_t)); /* * When the ROM has mapped in a cgfour display, the address @@ -245,20 +224,7 @@ cgfourattach(parent, self, args) * going to print characters via rconsole. */ - if (isconsole) { - /* XXX this is kind of a waste */ - fb->fb_pixels = mapiodev(ca->ca_ra.ra_reg, - PFOUR_COLOR_OFF_OVERLAY, ramsize); - } -#endif - - /* Map the Brooktree. */ - sc->sc_fbc = (volatile struct fbcontrol *) - mapiodev(ca->ca_ra.ra_reg, - PFOUR_COLOR_OFF_CMAP, sizeof(struct fbcontrol)); - sc->sc_phys = ca->ca_ra.ra_reg[0]; - sc->sc_bustype = ca->ca_bustype; /* grab initial (current) color map */ bt = &sc->sc_fbc->fbc_dac; @@ -266,227 +232,185 @@ cgfourattach(parent, self, args) for (i = 0; i < 256 * 3 / 4; i++) ((char *)&sc->sc_cmap)[i] = bt->bt_cmap >> 24; + /* enable video */ + cgfour_burner(sc, 1, 0); BT_INIT(bt, 24); -#if 0 /* See above. */ - if (isconsole) { - printf(" (console)\n"); -#if defined(RASTERCONSOLE) && 0 /* XXX been told it doesn't work well. */ - fbrcons_init(fb); -#endif - } else -#endif /* 0 */ - printf("\n"); + /* + * XXX should initialize the enable plane, instead of expecting the + * PROM to do so for us + */ + fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, ca->ca_bustype); /* - * Even though we're not using rconsole, we'd still like - * to notice if we're the console framebuffer. + * XXX this only maps the color plane, not the overlay or the enable + * planes */ - fb_attach(fb, isconsole); -#endif -} + sc->sc_sunfb.sf_ro.ri_bits = mapiodev(ca->ca_ra.ra_reg, + PFOUR_COLOR_OFF_COLOR, round_page(sc->sc_sunfb.sf_fbsize)); + sc->sc_sunfb.sf_ro.ri_hw = sc; + fbwscons_init(&sc->sc_sunfb, isconsole); -int -cgfouropen(dev, flags, mode, p) - dev_t dev; - int flags, mode; - struct proc *p; -{ - int unit = minor(dev); + cgfour_stdscreen.nrows = sc->sc_sunfb.sf_ro.ri_rows; + cgfour_stdscreen.ncols = sc->sc_sunfb.sf_ro.ri_cols; + cgfour_stdscreen.textops = &sc->sc_sunfb.sf_ro.ri_ops; - if (unit >= cgfour_cd.cd_ndevs || cgfour_cd.cd_devs[unit] == NULL) - return (ENXIO); - return (0); -} + printf(", %dx%d\n", sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height); -int -cgfourclose(dev, flags, mode, p) - dev_t dev; - int flags, mode; - struct proc *p; -{ + if (isconsole) { + fbwscons_console_init(&sc->sc_sunfb, &cgfour_stdscreen, -1, + cgfour_setcolor, cgfour_burner); + } - return (0); + waa.console = isconsole; + waa.scrdata = &cgfour_screenlist; + waa.accessops = &cgfour_accessops; + waa.accesscookie = sc; + config_found(self, &waa, wsemuldisplaydevprint); } int -cgfourioctl(dev, cmd, data, flags, p) - dev_t dev; +cgfour_ioctl(v, cmd, data, flags, p) + void *v; u_long cmd; - register caddr_t data; + caddr_t data; int flags; struct proc *p; { -#if defined(SUN4) - register struct cgfour_softc *sc = cgfour_cd.cd_devs[minor(dev)]; - register struct fbgattr *fba; + struct cgfour_softc *sc = v; + struct wsdisplay_fbinfo *wdf; + struct wsdisplay_cmap *cm; int error; switch (cmd) { - - case FBIOGTYPE: - *(struct fbtype *)data = sc->sc_fb.fb_type; + case WSDISPLAYIO_GTYPE: + *(u_int *)data = WSDISPLAY_TYPE_UNKNOWN; break; - - case FBIOGATTR: - fba = (struct fbgattr *)data; - fba->real_type = sc->sc_fb.fb_type.fb_type; - fba->owner = 0; /* XXX ??? */ - fba->fbtype = sc->sc_fb.fb_type; - fba->sattr.flags = 0; - fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type; - fba->sattr.dev_specific[0] = -1; - fba->emu_types[0] = sc->sc_fb.fb_type.fb_type; - fba->emu_types[1] = -1; + case WSDISPLAYIO_GINFO: + wdf = (struct wsdisplay_fbinfo *)data; + wdf->height = sc->sc_sunfb.sf_height; + wdf->width = sc->sc_sunfb.sf_width; + wdf->depth = sc->sc_sunfb.sf_depth; + wdf->cmsize = 256; + break; + case WSDISPLAYIO_LINEBYTES: + *(u_int *)data = sc->sc_sunfb.sf_linebytes; break; - case FBIOGETCMAP: - return (bt_getcmap((struct fbcmap *)data, &sc->sc_cmap, 256)); - - case FBIOPUTCMAP: - /* copy to software map */ -#define p ((struct fbcmap *)data) - error = bt_putcmap(p, &sc->sc_cmap, 256); + case WSDISPLAYIO_GETCMAP: + cm = (struct wsdisplay_cmap *)data; + error = bt_getcmap(&sc->sc_cmap, cm); if (error) return (error); - /* now blast them into the chip */ - /* XXX should use retrace interrupt */ - cgfourloadcmap(sc, p->index, p->count); -#undef p - break; - - case FBIOGVIDEO: - *(int *)data = cgfour_get_video(sc); break; - case FBIOSVIDEO: - cgfour_set_video(sc, *(int *)data); + case WSDISPLAYIO_PUTCMAP: + cm = (struct wsdisplay_cmap *)data; + error = bt_putcmap(&sc->sc_cmap, cm); + if (error) + return (error); + bt_loadcmap(&sc->sc_cmap, &sc->sc_fbc->fbc_dac, + cm->index, cm->count, 1); break; + case WSDISPLAYIO_SVIDEO: + case WSDISPLAYIO_GVIDEO: + case WSDISPLAYIO_GCURPOS: + case WSDISPLAYIO_SCURPOS: + case WSDISPLAYIO_GCURMAX: + case WSDISPLAYIO_GCURSOR: + case WSDISPLAYIO_SCURSOR: default: - return (ENOTTY); - } -#endif + return (-1); /* not supported yet */ + } + return (0); } -/* - * Return the address that would map the given device at the given - * offset, allowing for the given protection, or return -1 for error. - * - * the cg4 maps it's overlay plane for 128K, followed by the enable - * plane for 128K, followed by the colour plane (for as much colour - * as their is.) - * - * As well, mapping at an offset of 0x04000000 causes the cg4 to map - * only it's colour plane, at 0. - */ -paddr_t -cgfourmmap(dev, off, prot) - dev_t dev; - off_t off; - int prot; +int +cgfour_alloc_screen(v, type, cookiep, curxp, curyp, attrp) + void *v; + const struct wsscreen_descr *type; + void **cookiep; + int *curxp, *curyp; + long *attrp; { - register struct cgfour_softc *sc = cgfour_cd.cd_devs[minor(dev)]; - int poff; + struct cgfour_softc *sc = v; -#define START_ENABLE (128*1024) -#define START_COLOR ((128*1024) + (128*1024)) -#define COLOR_SIZE (sc->sc_fb.fb_type.fb_width * \ - sc->sc_fb.fb_type.fb_height) -#define END_COLOR (START_COLOR + COLOR_SIZE) -#define NOOVERLAY (0x04000000) + if (sc->sc_nscreens > 0) + return (ENOMEM); - if (off & PGOFSET) - panic("cgfourmap"); - - if (off < 0) - return (-1); - if ((u_int)off >= NOOVERLAY) { - off -= NOOVERLAY; + *cookiep = &sc->sc_sunfb.sf_ro; + *curyp = 0; + *curxp = 0; + sc->sc_sunfb.sf_ro.ri_ops.alloc_attr(&sc->sc_sunfb.sf_ro, + WSCOL_BLACK, WSCOL_WHITE, WSATTR_WSCOLORS, attrp); + sc->sc_nscreens++; + return (0); +} - /* - * X11 maps a huge chunk of the frame buffer; far more than - * there really is. We compensate by double-mapping the - * first page for as many other pages as it wants - */ - while ((u_int)off >= COLOR_SIZE) - off -= COLOR_SIZE; /* XXX thorpej ??? */ +void +cgfour_free_screen(v, cookie) + void *v; + void *cookie; +{ + struct cgfour_softc *sc = v; - poff = off + PFOUR_COLOR_OFF_COLOR; - } else if ((u_int)off < START_ENABLE) { - /* - * in overlay plane - */ - poff = PFOUR_COLOR_OFF_OVERLAY + off; - } else if ((u_int)off < START_COLOR) { - /* - * in enable plane - */ - poff = (off - START_ENABLE) + PFOUR_COLOR_OFF_ENABLE; - } else if ((u_int)off < sc->sc_fb.fb_type.fb_size) { - /* - * in colour plane - */ - poff = (off - START_COLOR) + PFOUR_COLOR_OFF_COLOR; - } else - return (-1); + sc->sc_nscreens--; +} - return (REG2PHYS(&sc->sc_phys, poff) | PMAP_NC); +int +cgfour_show_screen(v, cookie, waitok, cb, cbarg) + void *v; + void *cookie; + int waitok; + void (*cb)(void *, int, int); + void *cbarg; +{ + return (0); } -#if defined(SUN4) + /* - * Undo the effect of an FBIOSVIDEO that turns the video off. + * Return the address that would map the given device at the given + * offset, allowing for the given protection, or return -1 for error. */ -static void -cgfourunblank(dev) - struct device *dev; +paddr_t +cgfour_mmap(v, offset, prot) + void *v; + off_t offset; + int prot; { + struct cgfour_softc *sc = v; - cgfour_set_video((struct cgfour_softc *)dev, 1); -} + if (offset & PGOFSET) + return (-1); -static int -cgfour_get_video(sc) - struct cgfour_softc *sc; -{ + if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize) { + return (REG2PHYS(&sc->sc_phys, + PFOUR_COLOR_OFF_COLOR + offset) | PMAP_NC); + } - return (fb_pfour_get_video(&sc->sc_fb)); + return (-1); } -static void -cgfour_set_video(sc, enable) - struct cgfour_softc *sc; - int enable; +void +cgfour_setcolor(v, index, r, g, b) + void *v; + u_int index; + u_int8_t r, g, b; { + struct cgfour_softc *sc = v; - fb_pfour_set_video(&sc->sc_fb, enable); + bt_setcolor(&sc->sc_cmap, &sc->sc_fbc->fbc_dac, index, r, g, b, 1); } -/* - * Load a subset of the current (new) colormap into the Brooktree DAC. - */ -static void -cgfourloadcmap(sc, start, ncolors) - register struct cgfour_softc *sc; - register int start, ncolors; +void +cgfour_burner(v, on, flags) + void *v; + u_int on, flags; { - register volatile struct bt_regs *bt; - register u_int *ip, i; - register int count; + struct cgfour_softc *sc = v; - ip = &sc->sc_cmap.cm_chip[BT_D4M3(start)]; /* start/4 * 3 */ - count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3; - bt = &sc->sc_fbc->fbc_dac; - bt->bt_addr = BT_D4M4(start) << 24; - while (--count >= 0) { - i = *ip++; - /* hardware that makes one want to pound boards with hammers */ - bt->bt_cmap = i; - bt->bt_cmap = i << 8; - bt->bt_cmap = i << 16; - bt->bt_cmap = i << 24; - } + fb_pfour_set_video(&sc->sc_sunfb, on); } -#endif diff --git a/sys/arch/sparc/dev/cgfourteen.c b/sys/arch/sparc/dev/cgfourteen.c index 372df567452..bd5de10f91b 100644 --- a/sys/arch/sparc/dev/cgfourteen.c +++ b/sys/arch/sparc/dev/cgfourteen.c @@ -1,8 +1,32 @@ -/* $OpenBSD: cgfourteen.c,v 1.10 2002/08/02 16:13:07 millert Exp $ */ +/* $OpenBSD: cgfourteen.c,v 1.11 2002/08/12 10:44:03 miod Exp $ */ /* $NetBSD: cgfourteen.c,v 1.7 1997/05/24 20:16:08 pk Exp $ */ /* - * Copyright (c) 1996 + * Copyright (c) 2002 Miodrag Vallat. 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. + * + * + * Copyright (c) 1996 * The President and Fellows of Harvard College. All rights reserved. * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. @@ -60,23 +84,14 @@ * Does not handle interrupts, even though they can occur. * * XXX should defer colormap updates to vertical retrace interrupts + * + * XXX should bring hardware cursor code back */ -/* - * The following is for debugging only; it opens up a security hole - * enabled by allowing any user to map the control registers for the - * cg14 into their space. - */ -#undef CG14_MAP_REGS - /* - * The following enables 24-bit operation: when opened, the framebuffer - * will switch to 24-bit mode (actually 32-bit mode), and provide a - * simple cg8 emulation. - * - * XXX Note that the code enabled by this define is currently untested/broken. + * XXX define this to allow 24-bit operation. Rumored not to work. */ -#undef CG14_CG8 +#undef CG14_FULLCOLOR #include <sys/param.h> #include <sys/systm.h> @@ -90,48 +105,96 @@ #include <uvm/uvm_extern.h> -#include <machine/fbio.h> #include <machine/autoconf.h> #include <machine/pmap.h> -#include <machine/fbvar.h> #include <machine/cpu.h> #include <machine/conf.h> +#include <dev/wscons/wsconsio.h> +#include <dev/wscons/wsdisplayvar.h> +#include <dev/wscons/wscons_raster.h> +#include <dev/rasops/rasops.h> +#include <machine/fbvar.h> + +#define CG3REG_MEM 0x800000 #include <sparc/dev/cgfourteenreg.h> -#include <sparc/dev/cgfourteenvar.h> -/* autoconfiguration driver */ -static void cgfourteenattach(struct device *, struct device *, void *); -static int cgfourteenmatch(struct device *, void *, void *); -static void cgfourteenunblank(struct device *); +/* + * per-display variables/state + */ +struct cgfourteen_softc { + struct sunfb sc_sunfb; /* common base part */ + + struct rom_reg sc_phys; /* phys address of frame buffer */ + union cg14cmap sc_cmap; /* current colormap */ + + struct cg14ctl *sc_ctl; /* various registers */ + struct cg14curs *sc_hwc; + struct cg14dac *sc_dac; + struct cg14xlut *sc_xlut; + struct cg14clut *sc_clut1; + struct cg14clut *sc_clut2; + struct cg14clut *sc_clut3; + u_int *sc_clutincr; + + int sc_nscreens; +}; -struct cfattach cgfourteen_ca = { - sizeof(struct cgfourteen_softc), cgfourteenmatch, cgfourteenattach +struct wsscreen_descr cgfourteen_stdscreen = { + "std", + 0, 0, /* will be filled in */ + 0, + 0, 0, + WSSCREEN_REVERSE | WSSCREEN_WSCOLORS }; -struct cfdriver cgfourteen_cd = { - NULL, "cgfourteen", DV_DULL +const struct wsscreen_descr *cgfourteen_scrlist[] = { + &cgfourteen_stdscreen, +}; + +struct wsscreen_list cgfourteen_screenlist = { + sizeof(cgfourteen_scrlist) / sizeof(struct wsscreen_descr *), + cgfourteen_scrlist }; -/* frame buffer generic driver */ -static struct fbdriver cgfourteenfbdriver = { - cgfourteenunblank, cgfourteenopen, cgfourteenclose, cgfourteenioctl, - cgfourteenmmap +int cgfourteen_ioctl(void *, u_long, caddr_t, int, struct proc *); +int cgfourteen_alloc_screen(void *, const struct wsscreen_descr *, void **, + int *, int *, long *); +void cgfourteen_free_screen(void *, void *); +int cgfourteen_show_screen(void *, void *, int, void (*cb)(void *, int, int), + void *); +paddr_t cgfourteen_mmap(void *, off_t, int); +int cgfourteen_is_console(int); +void cgfourteen_reset(struct cgfourteen_softc *); +void cgfourteen_burner(void *, u_int, u_int); + +int cgfourteen_getcmap(union cg14cmap *, struct wsdisplay_cmap *); +int cgfourteen_putcmap(union cg14cmap *, struct wsdisplay_cmap *); +void cgfourteen_loadcmap(struct cgfourteen_softc *, int, int); +void cgfourteen_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t); + +struct wsdisplay_accessops cgfourteen_accessops = { + cgfourteen_ioctl, + cgfourteen_mmap, + cgfourteen_alloc_screen, + cgfourteen_free_screen, + cgfourteen_show_screen, + NULL, /* load_font */ + NULL, /* scrollback */ + NULL, /* getchar */ + cgfourteen_burner, }; -extern int fbnode; -extern struct tty *fbconstty; +void cgfourteenattach(struct device *, struct device *, void *); +int cgfourteenmatch(struct device *, void *, void *); + +struct cfattach cgfourteen_ca = { + sizeof(struct cgfourteen_softc), cgfourteenmatch, cgfourteenattach +}; -static void cg14_set_video(struct cgfourteen_softc *, int); -static int cg14_get_video(struct cgfourteen_softc *); -static int cg14_get_cmap(struct fbcmap *, union cg14cmap *, int); -static int cg14_put_cmap(struct fbcmap *, union cg14cmap *, int); -static void cg14_load_hwcmap(struct cgfourteen_softc *, int, int); -static void cg14_init(struct cgfourteen_softc *); -static void cg14_reset(struct cgfourteen_softc *); -static void cg14_loadomap(struct cgfourteen_softc *);/* cursor overlay */ -static void cg14_setcursor(struct cgfourteen_softc *);/* set position */ -static void cg14_loadcursor(struct cgfourteen_softc *);/* set shape */ +struct cfdriver cgfourteen_cd = { + NULL, "cgfourteen", DV_DULL +}; /* * Match a cgfourteen. @@ -150,7 +213,6 @@ cgfourteenmatch(parent, vcf, aux) */ cf->cf_flags &= FB_USERMASK; - /* Check driver name */ if (strcmp(cf->cf_driver->cd_name, ra->ra_name)) return (0); @@ -161,65 +223,46 @@ cgfourteenmatch(parent, vcf, aux) * Additionally, these things exist only on the Sun4m. */ if (CPU_ISSUN4M && ca->ca_bustype == BUS_OBIO) - return(1); + return (1); + return (0); } /* - * Attach a display. We need to notice if it is the console, too. + * Attach a display. */ void cgfourteenattach(parent, self, args) struct device *parent, *self; void *args; { - register struct cgfourteen_softc *sc = (struct cgfourteen_softc *)self; - register struct confargs *ca = args; - register int node = 0, ramsize; - register u_int32_t *lut; - int i, isconsole; + struct cgfourteen_softc *sc = (struct cgfourteen_softc *)self; + struct confargs *ca = args; + struct wsemuldisplaydev_attach_args waa; + int node = 0, depth, i; + u_int32_t *lut; + int isconsole = 0; + char *nam; - sc->sc_fb.fb_driver = &cgfourteenfbdriver; - sc->sc_fb.fb_device = &sc->sc_dev; - sc->sc_fb.fb_flags = sc->sc_dev.dv_cfdata->cf_flags; - - /* - * We're emulating a cg3/8, so represent ourselves as one - */ -#ifdef CG14_CG8 - sc->sc_fb.fb_type.fb_type = FBTYPE_MEMCOLOR; -#else - sc->sc_fb.fb_type.fb_type = FBTYPE_SUN3COLOR; -#endif + sc->sc_sunfb.sf_flags = self->dv_cfdata->cf_flags; node = ca->ca_ra.ra_node; -#ifdef CG14_CG8 - sc->sc_fb.fb_type.fb_depth = 32; -#else - sc->sc_fb.fb_type.fb_depth = 8; -#endif - fb_setsize(&sc->sc_fb, sc->sc_fb.fb_type.fb_depth, - 1152, 900, node, ca->ca_bustype); - - ramsize = round_page(sc->sc_fb.fb_type.fb_height * - sc->sc_fb.fb_linebytes); + nam = getpropstring(node, "model"); + printf(": %s", nam); - sc->sc_fb.fb_type.fb_cmsize = CG14_CLUT_SIZE; - sc->sc_fb.fb_type.fb_size = ramsize; + isconsole = node == fbnode; /* - * Now map in the 8 useful pages of registers + * Map in the 8 useful pages of registers */ if (ca->ca_ra.ra_len < 0x10000) { -#ifdef DIAGNOSTIC - printf("warning: can't find all cgfourteen registers...\n"); -#endif - ca->ca_ra.ra_len = 0x10000; + panic("\ncgfourteen: expected %x bytes of registers, got %x", + 0x10000, ca->ca_ra.ra_len); } - sc->sc_ctl = (struct cg14ctl *) mapiodev(ca->ca_ra.ra_reg, 0, + sc->sc_ctl = (struct cg14ctl *) mapiodev(ca->ca_ra.ra_reg, 0, ca->ca_ra.ra_len); - sc->sc_hwc = (struct cg14curs *) ((u_int)sc->sc_ctl + + sc->sc_hwc = (struct cg14curs *) ((u_int)sc->sc_ctl + CG14_OFFSET_CURS); sc->sc_dac = (struct cg14dac *) ((u_int)sc->sc_ctl + CG14_OFFSET_DAC); @@ -233,34 +276,19 @@ cgfourteenattach(parent, self, args) CG14_OFFSET_CLUT3); sc->sc_clutincr = (u_int *) ((u_int)sc->sc_ctl + CG14_OFFSET_CLUTINCR); - + /* * Stash the physical address of the framebuffer for use by mmap */ if (ca->ca_ra.ra_nreg < 2) - panic("cgfourteen with only one register set; can't find" - " framebuffer"); + panic("\ncgfourteen: expected 2 registers, got %d", + ca->ca_ra.ra_nreg); sc->sc_phys = ca->ca_ra.ra_reg[1]; -#if defined(DEBUG) && defined(CG14_MAP_REGS) - /* Store the physical address of the control registers */ - sc->sc_regphys = ca->ca_ra.ra_reg[0]; -#endif - - /* - * Let the user know that we're here - */ -#ifdef CG14_CG8 - printf(": cgeight emulated at %dx%dx24bpp", - sc->sc_fb.fb_type.fb_width, sc->sc_fb.fb_type.fb_height); -#else - printf(": cgthree emulated at %dx%dx8bpp", - sc->sc_fb.fb_type.fb_width, sc->sc_fb.fb_type.fb_height); -#endif /* - * Enable the video, but don't change the pixel depth. + * Reset frame buffer controls */ - cg14_set_video(sc, 1); + cgfourteen_reset(sc); /* * Grab the initial colormap @@ -269,279 +297,145 @@ cgfourteenattach(parent, self, args) for (i = 0; i < CG14_CLUT_SIZE; i++) sc->sc_cmap.cm_chip[i] = lut[i]; - /* See if we're the console */ - isconsole = node == fbnode && fbconstty != NULL; - /* - * We don't use the raster console since the cg14 is fast enough - * already. + * Enable the video. */ -#ifdef notdef - /* - * When the ROM has mapped in a cgfourteen display, the address - * maps only the video RAM, so in any case we have to map the - * registers ourselves. We only need the video RAM if we are - * going to print characters via rconsole. - */ - if ((sc->sc_fb.fb_pixels = ca->ca_ra.ra_vaddr) == NULL && isconsole) { - /* this probably cannot happen, but what the heck */ - sc->sc_fb.fb_pixels = mapiodev(ca->ca_ra.ra_reg, CG3REG_MEM, - ramsize); - } -#endif /* notdef */ + cgfourteen_burner(sc, 1, 0); - - if (isconsole) { - printf(" (console)\n"); -#ifdef notdef -#ifdef RASTERCONSOLE - fbrcons_init(&sc->sc_fb); +#ifdef CG14_FULLCOLOR + depth = 32; +#else + depth = 8; #endif -#endif /* notdef */ - } else - printf("\n"); - - /* Attach to /dev/fb */ - if (node == fbnode) - fb_attach(&sc->sc_fb, isconsole); -} - -/* - * Keep track of the number of opens made. In the 24-bit driver, we need to - * switch to 24-bit mode on the first open, and switch back to 8-bit on - * the last close. This kind of nonsense is needed to give screenblank - * a fighting chance of working. - */ -static int cg14_opens = 0; - -int -cgfourteenopen(dev, flags, mode, p) - dev_t dev; - int flags, mode; - struct proc *p; -{ - register struct cgfourteen_softc *sc = cgfourteen_cd.cd_devs[minor(dev)]; - int unit = minor(dev); - int s, oldopens; - - if (unit >= cgfourteen_cd.cd_ndevs || - cgfourteen_cd.cd_devs[unit] == NULL) - return (ENXIO); - - s = splhigh(); - oldopens = cg14_opens++; - splx(s); - - /* Setup the cg14 as we want it, and save the original PROM state */ - if (oldopens == 0) /* first open only, to make screenblank work */ - cg14_init(sc); + fb_setsize(&sc->sc_sunfb, depth, 1152, 900, node, ca->ca_bustype); + /* XXX is this right? */ + sc->sc_sunfb.sf_ro.ri_bits = mapiodev(ca->ca_ra.ra_reg, + CG3REG_MEM, round_page(sc->sc_sunfb.sf_fbsize)); + sc->sc_sunfb.sf_ro.ri_hw = sc; + fbwscons_init(&sc->sc_sunfb, isconsole); - return (0); -} - -int -cgfourteenclose(dev, flags, mode, p) - dev_t dev; - int flags, mode; - struct proc *p; -{ - register struct cgfourteen_softc *sc = cgfourteen_cd.cd_devs[minor(dev)]; - int s, opens; + cgfourteen_stdscreen.nrows = sc->sc_sunfb.sf_ro.ri_rows; + cgfourteen_stdscreen.ncols = sc->sc_sunfb.sf_ro.ri_cols; + cgfourteen_stdscreen.textops = &sc->sc_sunfb.sf_ro.ri_ops; - s = splhigh(); - opens = --cg14_opens; - if (cg14_opens < 0) - opens = cg14_opens = 0; - splx(s); + printf(", %dx%d, depth %d\n", sc->sc_sunfb.sf_width, + sc->sc_sunfb.sf_height, sc->sc_sunfb.sf_depth); - /* - * Restore video state to make the PROM happy, on last close. - */ - if (opens == 0) - cg14_reset(sc); + if (isconsole) { + fbwscons_console_init(&sc->sc_sunfb, &cgfourteen_stdscreen, -1, + cgfourteen_setcolor, cgfourteen_burner); + } - return (0); + waa.console = isconsole; + waa.scrdata = &cgfourteen_screenlist; + waa.accessops = &cgfourteen_accessops; + waa.accesscookie = sc; + config_found(self, &waa, wsemuldisplaydevprint); } int -cgfourteenioctl(dev, cmd, data, flags, p) - dev_t dev; +cgfourteen_ioctl(dev, cmd, data, flags, p) + void *dev; u_long cmd; - register caddr_t data; + caddr_t data; int flags; struct proc *p; { - register struct cgfourteen_softc *sc = cgfourteen_cd.cd_devs[minor(dev)]; - register struct fbgattr *fba; - union cg14cursor_cmap tcm; - int v, error; - u_int count; + struct cgfourteen_softc *sc = dev; + struct wsdisplay_cmap *cm; + struct wsdisplay_fbinfo *wdf; + int error; switch (cmd) { - - case FBIOGTYPE: - *(struct fbtype *)data = sc->sc_fb.fb_type; + case WSDISPLAYIO_GTYPE: + *(u_int *)data = WSDISPLAY_TYPE_UNKNOWN; break; - - case FBIOGATTR: - fba = (struct fbgattr *)data; - fba->real_type = FBTYPE_MDICOLOR; - fba->owner = 0; /* XXX ??? */ - fba->fbtype = sc->sc_fb.fb_type; - fba->sattr.flags = 0; - fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type; - fba->sattr.dev_specific[0] = -1; - fba->emu_types[0] = sc->sc_fb.fb_type.fb_type; - fba->emu_types[1] = -1; + case WSDISPLAYIO_GINFO: + wdf = (struct wsdisplay_fbinfo *)data; + wdf->height = sc->sc_sunfb.sf_height; + wdf->width = sc->sc_sunfb.sf_width; + wdf->depth = sc->sc_sunfb.sf_depth; + wdf->cmsize = 256; + break; + case WSDISPLAYIO_LINEBYTES: + *(u_int *)data = sc->sc_sunfb.sf_linebytes; break; - case FBIOGETCMAP: - return (cg14_get_cmap((struct fbcmap *)data, &sc->sc_cmap, - CG14_CLUT_SIZE)); - - case FBIOPUTCMAP: - /* copy to software map */ -#define p ((struct fbcmap *)data) -#ifdef CG14_CG8 - p->index &= 0xffffff; -#endif - error = cg14_put_cmap(p, &sc->sc_cmap, CG14_CLUT_SIZE); + case WSDISPLAYIO_GETCMAP: + cm = (struct wsdisplay_cmap *)data; + error = cgfourteen_getcmap(&sc->sc_cmap, cm); if (error) return (error); - /* now blast them into the chip */ - /* XXX should use retrace interrupt */ - cg14_load_hwcmap(sc, p->index, p->count); -#undef p - break; - - case FBIOGVIDEO: - *(int *)data = cg14_get_video(sc); - break; - - case FBIOSVIDEO: - cg14_set_video(sc, *(int *)data); break; -/* these are for both FBIOSCURSOR and FBIOGCURSOR */ -#define p ((struct fbcursor *)data) -#define cc (&sc->sc_cursor) - case FBIOGCURSOR: - /* do not quite want everything here... */ - p->set = FB_CUR_SETALL; /* close enough, anyway */ - p->enable = cc->cc_enable; - p->pos = cc->cc_pos; - p->hot = cc->cc_hot; - p->size = cc->cc_size; - - /* begin ugh ... can we lose some of this crap?? */ - if (p->image != NULL) { - count = cc->cc_size.y * 32 / NBBY; - error = copyout((caddr_t)cc->cc_cplane, - (caddr_t)p->image, count); - if (error) - return (error); - error = copyout((caddr_t)cc->cc_eplane, - (caddr_t)p->mask, count); - if (error) - return (error); - } - if (p->cmap.red != NULL) { - error = cg14_get_cmap(&p->cmap, - (union cg14cmap *)&cc->cc_color, 2); - if (error) - return (error); - } else { - p->cmap.index = 0; - p->cmap.count = 2; - } - /* end ugh */ - break; - - case FBIOSCURSOR: - /* - * For setcmap and setshape, verify parameters, so that - * we do not get halfway through an update and then crap - * out with the software state screwed up. - */ - v = p->set; - if (v & FB_CUR_SETCMAP) { - /* - * This use of a temporary copy of the cursor - * colormap is not terribly efficient, but these - * copies are small (8 bytes)... - */ - tcm = cc->cc_color; - error = cg14_put_cmap(&p->cmap, (union cg14cmap *)&tcm, - 2); - if (error) - return (error); - } - if (v & FB_CUR_SETSHAPE) { - if ((u_int)p->size.x > 32 || (u_int)p->size.y > 32) - return (EINVAL); - count = p->size.y * 32 / NBBY; - if (!uvm_useracc(p->image, count, B_READ) || - !uvm_useracc(p->mask, count, B_READ)) - return (EFAULT); - } - - /* parameters are OK; do it */ - if (v & (FB_CUR_SETCUR | FB_CUR_SETPOS | FB_CUR_SETHOT)) { - if (v & FB_CUR_SETCUR) - cc->cc_enable = p->enable; - if (v & FB_CUR_SETPOS) - cc->cc_pos = p->pos; - if (v & FB_CUR_SETHOT) - cc->cc_hot = p->hot; - cg14_setcursor(sc); - } - if (v & FB_CUR_SETCMAP) { - cc->cc_color = tcm; - cg14_loadomap(sc); /* XXX defer to vertical retrace */ - } - if (v & FB_CUR_SETSHAPE) { - cc->cc_size = p->size; - count = p->size.y * 32 / NBBY; - bzero((caddr_t)cc->cc_eplane, sizeof cc->cc_eplane); - bzero((caddr_t)cc->cc_cplane, sizeof cc->cc_cplane); - bcopy(p->mask, (caddr_t)cc->cc_eplane, count); - bcopy(p->image, (caddr_t)cc->cc_cplane, count); - cg14_loadcursor(sc); - } + case WSDISPLAYIO_PUTCMAP: + cm = (struct wsdisplay_cmap *)data; + error = cgfourteen_putcmap(&sc->sc_cmap, cm); + if (error) + return (error); + /* XXX should use retrace interrupt */ + cgfourteen_loadcmap(sc, cm->index, cm->count); break; -#undef cc -#undef p - case FBIOGCURPOS: - *(struct fbcurpos *)data = sc->sc_cursor.cc_pos; - break; + case WSDISPLAYIO_SVIDEO: + case WSDISPLAYIO_GVIDEO: + case WSDISPLAYIO_GCURPOS: + case WSDISPLAYIO_SCURPOS: + case WSDISPLAYIO_GCURMAX: + case WSDISPLAYIO_GCURSOR: + case WSDISPLAYIO_SCURSOR: + default: + return (-1); /* not supported yet */ + } + return (0); +} - case FBIOSCURPOS: - sc->sc_cursor.cc_pos = *(struct fbcurpos *)data; - cg14_setcursor(sc); - break; +int +cgfourteen_alloc_screen(v, type, cookiep, curxp, curyp, attrp) + void *v; + const struct wsscreen_descr *type; + void **cookiep; + int *curxp, *curyp; + long *attrp; +{ + struct cgfourteen_softc *sc = v; - case FBIOGCURMAX: - /* max cursor size is 32x32 */ - ((struct fbcurpos *)data)->x = 32; - ((struct fbcurpos *)data)->y = 32; - break; + if (sc->sc_nscreens > 0) + return (ENOMEM); - default: - return (ENOTTY); - } + *cookiep = &sc->sc_sunfb.sf_ro; + *curyp = 0; + *curxp = 0; +#ifdef CG14_FULLCOLOR + sc->sc_sunfb.sf_ro.ri_ops.alloc_attr(&sc->sc_sunfb.sf_ro, + 0, 0, 0, attrp); +#else + sc->sc_sunfb.sf_ro.ri_ops.alloc_attr(&sc->sc_sunfb.sf_ro, + WSCOL_BLACK, WSCOL_WHITE, WSATTR_WSCOLORS, attrp); +#endif + sc->sc_nscreens++; return (0); } -/* - * Undo the effect of an FBIOSVIDEO that turns the video off. - */ -static void -cgfourteenunblank(dev) - struct device *dev; +void +cgfourteen_free_screen(v, cookie) + void *v; + void *cookie; { + struct cgfourteen_softc *sc = v; - cg14_set_video((struct cgfourteen_softc *)dev, 1); + sc->sc_nscreens--; +} + +int +cgfourteen_show_screen(v, cookie, waitok, cb, cbarg) + void *v; + void *cookie; + int waitok; + void (*cb)(void *, int, int); + void *cbarg; +{ + return (0); } /* @@ -555,109 +449,44 @@ cgfourteenunblank(dev) * channel information. We hardwire the Xlut to all zeroes to insure * that, regardless of this value, direct 24-bit color access will be * used. - * - * Alternatively, mapping the frame buffer at an offset of 16M seems to + * + * Alternatively, mapping the frame buffer at an offset of 16M seems to * tell the chip to ignore the X channel. XXX where does it get the X value * to use? */ paddr_t -cgfourteenmmap(dev, off, prot) - dev_t dev; - off_t off; +cgfourteen_mmap(v, offset, prot) + void *v; + off_t offset; int prot; { - register struct cgfourteen_softc *sc = cgfourteen_cd.cd_devs[minor(dev)]; + struct cgfourteen_softc *sc = v; -#define CG3START (128*1024 + 128*1024) -#define CG8START (256*1024) -#define NOOVERLAY (0x04000000) - - if (off & PGOFSET) - panic("cgfourteenmmap"); - - if (off < 0) + if (offset & PGOFSET) return (-1); -#if defined(DEBUG) && defined(CG14_MAP_REGS) /* XXX: security hole */ - /* - * Map the control registers into user space. Should only be - * used for debugging! - */ - if ((u_int)off >= 0x10000000 && (u_int)off < 0x10000000 + 16*4096) { - off -= 0x10000000; - return (REG2PHYS(&sc->sc_regphys, off, 0) | PMAP_NC); - } -#endif - - if ((u_int)off >= NOOVERLAY) - off -= NOOVERLAY; -#ifdef CG14_CG8 - else if ((u_int)off >= CG8START) { - off -= CG8START; - } -#else - else if ((u_int)off >= CG3START) - off -= CG3START; -#endif - else - off = 0; - - if ((unsigned)off >= sc->sc_fb.fb_type.fb_size * - sc->sc_fb.fb_type.fb_depth/8) { -#ifdef DEBUG - printf("\nmmap request out of bounds: request 0x%x, " - "bound 0x%x\n", (unsigned) off, - (unsigned)sc->sc_fb.fb_type.fb_size); -#endif - return (-1); + /* Allow mapping as a dumb framebuffer from offset 0 */ + if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize) { + return (REG2PHYS(&sc->sc_phys, offset) | PMAP_NC); } - /* - * Use PMAP_NC to disable the cache, since otherwise refresh is - * very confused. - */ - return (REG2PHYS(&sc->sc_phys, off) | PMAP_NC); + return (-1); } -/* - * Miscellaneous helper functions - */ - /* Initialize the framebuffer, storing away useful state for later reset */ -static void -cg14_init(sc) +void +cgfourteen_reset(sc) struct cgfourteen_softc *sc; { - register u_int32_t *clut; - register u_int8_t *xlut; - register int i; - /* - * We stash away the following to restore on close: - * - * color look-up table 1 (sc->sc_saveclut) - * x look-up table (sc->sc_savexlut) - * control register (sc->sc_savectl) - * cursor control register (sc->sc_savehwc) - */ - sc->sc_savectl = sc->sc_ctl->ctl_mctl; - sc->sc_savehwc = sc->sc_hwc->curs_ctl; - - clut = (u_int32_t *) sc->sc_clut1->clut_lut; - xlut = (u_int8_t *) sc->sc_xlut->xlut_lut; - for (i = 0; i < CG14_CLUT_SIZE; i++) { - sc->sc_saveclut.cm_chip[i] = clut[i]; - sc->sc_savexlut[i] = xlut[i]; - } - -#ifdef CG14_CG8 +#ifdef CG14_FULLCOLOR /* * Enable the video, and put in 24 bit mode. */ sc->sc_ctl->ctl_mctl = CG14_MCTL_ENABLEVID | CG14_MCTL_PIXMODE_32 | - CG14_MCTL_POWERCTL; + CG14_MCTL_POWERCTL; - /* + /* * Zero the xlut to enable direct-color mode */ bzero(sc->sc_xlut, CG14_CLUT_SIZE); @@ -666,54 +495,22 @@ cg14_init(sc) * Enable the video and put it in 8 bit mode */ sc->sc_ctl->ctl_mctl = CG14_MCTL_ENABLEVID | CG14_MCTL_PIXMODE_8 | - CG14_MCTL_POWERCTL; + CG14_MCTL_POWERCTL; #endif } -static void -cg14_reset(sc) /* Restore the state saved on cg14_init */ - struct cgfourteen_softc *sc; +void +cgfourteen_burner(v, on, flags) + void *v; + u_int on, flags; { - register u_int32_t *clut; - register u_int8_t *xlut; - register int i; + struct cgfourteen_softc *sc = v; /* - * We restore the following, saved in cg14_init: - * - * color look-up table 1 (sc->sc_saveclut) - * x look-up table (sc->sc_savexlut) - * control register (sc->sc_savectl) - * cursor control register (sc->sc_savehwc) - * - * Note that we don't touch the video enable bits in the - * control register; otherwise, screenblank wouldn't work. - */ - sc->sc_ctl->ctl_mctl = (sc->sc_ctl->ctl_mctl & (CG14_MCTL_ENABLEVID | - CG14_MCTL_POWERCTL)) | - (sc->sc_savectl & ~(CG14_MCTL_ENABLEVID | - CG14_MCTL_POWERCTL)); - sc->sc_hwc->curs_ctl = sc->sc_savehwc; - - clut = (u_int32_t *) sc->sc_clut1->clut_lut; - xlut = (u_int8_t *) sc->sc_xlut->xlut_lut; - for (i = 0; i < CG14_CLUT_SIZE; i++) { - clut[i] = sc->sc_saveclut.cm_chip[i]; - xlut[i] = sc->sc_savexlut[i]; - } -} - -/* Enable/disable video display; power down monitor if DPMS-capable */ -static void -cg14_set_video(sc, enable) - struct cgfourteen_softc *sc; - int enable; -{ - /* * We can only use DPMS to power down the display if the chip revision * is greater than 0. */ - if (enable) { + if (on) { if ((sc->sc_ctl->ctl_rsr & CG14_RSR_REVMASK) > 0) sc->sc_ctl->ctl_mctl |= (CG14_MCTL_ENABLEVID | CG14_MCTL_POWERCTL); @@ -728,151 +525,89 @@ cg14_set_video(sc, enable) } } -/* Get status of video display */ -static int -cg14_get_video(sc) - struct cgfourteen_softc *sc; -{ - return ((sc->sc_ctl->ctl_mctl & CG14_MCTL_ENABLEVID) != 0); -} - /* Read the software shadow colormap */ -static int -cg14_get_cmap(p, cm, cmsize) - register struct fbcmap *p; +int +cgfourteen_getcmap(cm, rcm) union cg14cmap *cm; - int cmsize; + struct wsdisplay_cmap *rcm; { - register u_int i, start, count; - register u_char *cp; - - start = p->index; - count = p->count; - if (start >= cmsize || count > cmsize - start) -#ifdef DEBUG - { - printf("putcmaperror: start %u cmsize %d count %u\n", - start, cmsize, count); -#endif + u_int index = rcm->index, count = rcm->count, i; + int error; + + if (index >= CG14_CLUT_SIZE || count > CG14_CLUT_SIZE - index) return (EINVAL); -#ifdef DEBUG - } -#endif - if (!uvm_useracc(p->red, count, B_WRITE) || - !uvm_useracc(p->green, count, B_WRITE) || - !uvm_useracc(p->blue, count, B_WRITE)) - return (EFAULT); - for (cp = &cm->cm_map[start][0], i = 0; i < count; cp += 4, i++) { - p->red[i] = cp[3]; - p->green[i] = cp[2]; - p->blue[i] = cp[1]; - } - return (0); + for (i = 0; i < count; i++) { + if ((error = copyout(&cm->cm_map[index + i][3], + &rcm->red[i], 1)) != 0) + return (error); + if ((error = copyout(&cm->cm_map[index + i][2], + &rcm->green[i], 1)) != 0) + return (error); + if ((error = copyout(&cm->cm_map[index + i][1], + &rcm->blue[i], 1)) != 0) + return (error); + } + return (0); } /* Write the software shadow colormap */ -static int -cg14_put_cmap(p, cm, cmsize) - register struct fbcmap *p; +int +cgfourteen_putcmap(cm, rcm) union cg14cmap *cm; - int cmsize; + struct wsdisplay_cmap *rcm; { - register u_int i, start, count; - register u_char *cp; - - start = p->index; - count = p->count; - if (start >= cmsize || count > cmsize - start) -#ifdef DEBUG - { - printf("putcmaperror: start %u cmsize %d count %u\n", - start, cmsize, count); -#endif + u_int index = rcm->index, count = rcm->count, i; + int error; + + if (index >= CG14_CLUT_SIZE || count > CG14_CLUT_SIZE - index) return (EINVAL); -#ifdef DEBUG - } -#endif - if (!uvm_useracc(p->red, count, B_READ) || - !uvm_useracc(p->green, count, B_READ) || - !uvm_useracc(p->blue, count, B_READ)) - return (EFAULT); - for (cp = &cm->cm_map[start][0], i = 0; i < count; cp += 4, i++) { - cp[3] = p->red[i]; - cp[2] = p->green[i]; - cp[1] = p->blue[i]; - cp[0] = 0; /* no alpha channel */ - } - return (0); + for (i = 0; i < count; i++) { + if ((error = copyin(&rcm->red[i], + &cm->cm_map[index + i][3], 1)) != 0) + return (error); + if ((error = copyin(&rcm->green[i], + &cm->cm_map[index + i][2], 1)) != 0) + return (error); + if ((error = copyin(&rcm->blue[i], + &cm->cm_map[index + i][1], 1)) != 0) + return (error); + cm->cm_map[index +i][0] = 0; /* no alpha channel */ + } + return (0); } -static void -cg14_load_hwcmap(sc, start, ncolors) - register struct cgfourteen_softc *sc; - register int start, ncolors; +void +cgfourteen_loadcmap(sc, start, ncolors) + struct cgfourteen_softc *sc; + int start, ncolors; { /* XXX switch to auto-increment, and on retrace intr */ /* Setup pointers to source and dest */ - register u_int32_t *colp = &sc->sc_cmap.cm_chip[start]; - volatile register u_int32_t *lutp = &sc->sc_clut1->clut_lut[start]; + u_int32_t *colp = &sc->sc_cmap.cm_chip[start]; + volatile u_int32_t *lutp = &sc->sc_clut1->clut_lut[start]; /* Copy by words */ while (--ncolors >= 0) *lutp++ = *colp++; } -/* - * Load the cursor (overlay `foreground' and `background') colors. - */ -static void -cg14_setcursor(sc) - register struct cgfourteen_softc *sc; -{ - /* we need to subtract the hot-spot value here */ -#define COORD(f) (sc->sc_cursor.cc_pos.f - sc->sc_cursor.cc_hot.f) - - sc->sc_hwc->curs_ctl = (sc->sc_cursor.cc_enable ? CG14_CURS_ENABLE : 0); - sc->sc_hwc->curs_x = COORD(x); - sc->sc_hwc->curs_y = COORD(y); - -#undef COORD -} - -static void -cg14_loadcursor(sc) - register struct cgfourteen_softc *sc; +void +cgfourteen_setcolor(v, index, r, g, b) + void *v; + u_int index; + u_int8_t r, g, b; { - register volatile struct cg14curs *hwc; - register u_int edgemask, m; - register int i; + struct cgfourteen_softc *sc = v; - /* - * Keep the top size.x bits. Here we *throw out* the top - * size.x bits from an all-one-bits word, introducing zeros in - * the top size.x bits, then invert all the bits to get what - * we really wanted as our mask. But this fails if size.x is - * 32---a sparc uses only the low 5 bits of the shift count--- - * so we have to special case that. - */ - edgemask = ~0; - if (sc->sc_cursor.cc_size.x < 32) - edgemask = ~(edgemask >> sc->sc_cursor.cc_size.x); - hwc = sc->sc_hwc; - for (i = 0; i < 32; i++) { - m = sc->sc_cursor.cc_eplane[i] & edgemask; - hwc->curs_plane0[i] = m; - hwc->curs_plane1[i] = m & sc->sc_cursor.cc_cplane[i]; - } -} + /* XXX - Wait for retrace? */ -static void -cg14_loadomap(sc) - register struct cgfourteen_softc *sc; -{ - /* set background color */ - sc->sc_hwc->curs_color1 = sc->sc_cursor.cc_color.cm_chip[0]; - /* set foreground color */ - sc->sc_hwc->curs_color2 = sc->sc_cursor.cc_color.cm_chip[1]; + sc->sc_cmap.cm_map[index][3] = r; + sc->sc_cmap.cm_map[index][2] = g; + sc->sc_cmap.cm_map[index][1] = b; + sc->sc_cmap.cm_map[index][0] = 0; /* no alpha channel */ + + cgfourteen_loadcmap(sc, index, 1); } diff --git a/sys/arch/sparc/dev/cgfourteenreg.h b/sys/arch/sparc/dev/cgfourteenreg.h index c0fdb1b5c0a..30b541894b2 100644 --- a/sys/arch/sparc/dev/cgfourteenreg.h +++ b/sys/arch/sparc/dev/cgfourteenreg.h @@ -1,8 +1,8 @@ -/* $OpenBSD: cgfourteenreg.h,v 1.1 1997/08/08 08:24:49 downsj Exp $ */ +/* $OpenBSD: cgfourteenreg.h,v 1.2 2002/08/12 10:44:03 miod Exp $ */ /* $NetBSD: cgfourteenreg.h,v 1.1 1996/09/30 22:41:02 abrown Exp $ */ /* - * Copyright (c) 1996 + * Copyright (c) 1996 * The President and Fellows of Harvard College. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -52,7 +52,7 @@ struct cg14ctl { volatile u_int8_t ctl_mctl; /* main control register */ #define CG14_MCTL_ENABLEINTR 0x80 /* interrupts */ #define CG14_MCTL_ENABLEVID 0x40 /* enable video */ -#define CG14_MCTL_PIXMODE_MASK 0x30 +#define CG14_MCTL_PIXMODE_MASK 0x30 #define CG14_MCTL_PIXMODE_8 0x00 /* data is 16 8-bit pixels */ #define CG14_MCTL_PIXMODE_16 0x20 /* data is 8 16-bit pixels */ #define CG14_MCTL_PIXMODE_32 0x30 /* data is 4 32-bit pixels */ @@ -121,3 +121,32 @@ struct cg14clut { volatile u_int32_t clut_lutinc[CG14_CLUT_SIZE]; /* autoincr */ volatile u_int32_t clut_lutincd[CG14_CLUT_SIZE]; }; + +/* + * Layout of cg14 hardware colormap + */ +union cg14cmap { + u_char cm_map[256][4]; /* 256 R/G/B/A entries (B is high)*/ + u_int32_t cm_chip[256]; /* the way the chip gets loaded */ +}; + +/* + * cg14 hardware cursor colormap + */ +union cg14cursor_cmap { /* colormap, like bt_cmap, but tiny */ + u_char cm_map[2][4]; /* 2 R/G/B/A entries */ + u_int32_t cm_chip[2]; /* 2 chip equivalents */ +}; + +/* + * cg14 hardware cursor status + */ +struct cg14_cursor { /* cg14 hardware cursor status */ + short cc_enable; /* cursor is enabled */ + struct wsdisplay_curpos cc_pos; /* position */ + struct wsdisplay_curpos cc_hot; /* hot-spot */ + struct wsdisplay_curpos cc_size; /* size of mask & image fields */ + u_int cc_eplane[32]; /* enable plane */ + u_int cc_cplane[32]; /* color plane */ + union cg14cursor_cmap cc_color; /* cursor colormap */ +}; diff --git a/sys/arch/sparc/dev/cgfourteenvar.h b/sys/arch/sparc/dev/cgfourteenvar.h deleted file mode 100644 index 654945e01bb..00000000000 --- a/sys/arch/sparc/dev/cgfourteenvar.h +++ /dev/null @@ -1,94 +0,0 @@ -/* $OpenBSD: cgfourteenvar.h,v 1.1 1997/08/08 08:24:50 downsj Exp $ */ -/* $NetBSD: cgfourteenvar.h,v 1.1 1996/09/30 22:41:03 abrown Exp $ */ - -/* - * Copyright (c) 1996 - * The President and Fellows of Harvard College. 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 Harvard University 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. - */ - -/* - * Layout of cg14 hardware colormap - */ -union cg14cmap { - u_char cm_map[256][4]; /* 256 R/G/B/A entries (B is high)*/ - u_int32_t cm_chip[256]; /* the way the chip gets loaded */ -}; - -/* - * cg14 hardware cursor colormap - */ -union cg14cursor_cmap { /* colormap, like bt_cmap, but tiny */ - u_char cm_map[2][4]; /* 2 R/G/B/A entries */ - u_int32_t cm_chip[2]; /* 2 chip equivalents */ -}; - -/* - * cg14 hardware cursor status - */ -struct cg14_cursor { /* cg14 hardware cursor status */ - short cc_enable; /* cursor is enabled */ - struct fbcurpos cc_pos; /* position */ - struct fbcurpos cc_hot; /* hot-spot */ - struct fbcurpos cc_size; /* size of mask & image fields */ - u_int cc_eplane[32]; /* enable plane */ - u_int cc_cplane[32]; /* color plane */ - union cg14cursor_cmap cc_color; /* cursor colormap */ -}; - -/* - * per-cg14 variables/state - */ -struct cgfourteen_softc { - struct device sc_dev; /* base device */ - struct fbdevice sc_fb; /* frame buffer device */ - - struct rom_reg sc_phys; /* phys address of frame buffer */ -#if defined(DEBUG) && defined(CG14_MAP_REGS) - struct rom_reg sc_regphys; /* phys addr of fb regs; for debug */ -#endif - union cg14cmap sc_cmap; /* current colormap */ - - struct cg14_cursor sc_cursor; /* Hardware cursor state */ - - union cg14cmap sc_saveclut; /* a place to stash PROM state */ - u_int8_t sc_savexlut[256]; - u_int8_t sc_savectl; - u_int8_t sc_savehwc; - - struct cg14ctl *sc_ctl; /* various registers */ - struct cg14curs *sc_hwc; - struct cg14dac *sc_dac; - struct cg14xlut *sc_xlut; - struct cg14clut *sc_clut1; - struct cg14clut *sc_clut2; - struct cg14clut *sc_clut3; - u_int *sc_clutincr; -}; diff --git a/sys/arch/sparc/dev/cgsix.c b/sys/arch/sparc/dev/cgsix.c index c63655b841d..43bddb7aabf 100644 --- a/sys/arch/sparc/dev/cgsix.c +++ b/sys/arch/sparc/dev/cgsix.c @@ -1,7 +1,42 @@ -/* $OpenBSD: cgsix.c,v 1.18 2002/03/14 01:26:42 millert Exp $ */ +/* $OpenBSD: cgsix.c,v 1.19 2002/08/12 10:44:03 miod Exp $ */ /* $NetBSD: cgsix.c,v 1.33 1997/08/07 19:12:30 pk Exp $ */ /* + * Copyright (c) 2002 Miodrag Vallat. All rights reserved. + * Copyright (c) 2001 Jason L. Wright (jason@thought.net) + * 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 Jason L. Wright + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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. + * + * Effort sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F30602-01-2-0537. + * + * * Copyright (c) 1993 * The Regents of the University of California. All rights reserved. * @@ -47,39 +82,34 @@ /* * color display (cgsix) driver. - * - * Does not handle interrupts, even though they can occur. - * - * XXX should defer colormap updates to vertical retrace interrupts */ #include <sys/param.h> #include <sys/systm.h> #include <sys/buf.h> #include <sys/device.h> -#include <machine/fbio.h> #include <sys/ioctl.h> #include <sys/malloc.h> #include <sys/mman.h> #include <sys/tty.h> #include <sys/conf.h> -#ifdef DEBUG -#include <sys/proc.h> -#include <sys/syslog.h> -#endif - #include <uvm/uvm_extern.h> #include <machine/autoconf.h> #include <machine/pmap.h> -#include <machine/fbvar.h> #include <machine/cpu.h> #if defined(SUN4) #include <machine/eeprom.h> #endif #include <machine/conf.h> +#include <dev/wscons/wsconsio.h> +#include <dev/wscons/wsdisplayvar.h> +#include <dev/wscons/wscons_raster.h> +#include <dev/rasops/rasops.h> +#include <machine/fbvar.h> + #include <sparc/dev/btreg.h> #include <sparc/dev/btvar.h> #include <sparc/dev/cgsixreg.h> @@ -88,76 +118,80 @@ #include <sparc/dev/pfourreg.h> #endif -extern int sparc_vsyncblank; - -union cursor_cmap { /* colormap, like bt_cmap, but tiny */ - u_char cm_map[2][3]; /* 2 R/G/B entries */ - u_int cm_chip[2]; /* 2 chip equivalents */ -}; - -struct cg6_cursor { /* cg6 hardware cursor status */ - short cc_enable; /* cursor is enabled */ - struct fbcurpos cc_pos; /* position */ - struct fbcurpos cc_hot; /* hot-spot */ - struct fbcurpos cc_size; /* size of mask & image fields */ - u_int cc_bits[2][32]; /* space for mask & image bits */ - union cursor_cmap cc_color; /* cursor colormap */ -}; - /* per-display variables */ struct cgsix_softc { - struct device sc_dev; /* base device */ + struct sunfb sc_sunfb; /* common base part */ struct sbusdev sc_sd; /* sbus device */ - struct fbdevice sc_fb; /* frame buffer device */ - struct rom_reg sc_physadr; /* phys addr of h/w */ - int sc_bustype; /* type of bus we live on */ + struct rom_reg sc_phys; /* phys addr of h/w */ volatile struct bt_regs *sc_bt; /* Brooktree registers */ volatile int *sc_fhc; /* FHC register */ - volatile struct cg6_thc *sc_thc; /* THC registers */ - volatile struct cg6_tec_xxx *sc_tec; /* TEC registers */ - short sc_fhcrev; /* hardware rev */ - short sc_blanked; /* true if blanked */ - struct cg6_cursor sc_cursor; /* software cursor info */ + volatile struct cgsix_thc *sc_thc; /* THC registers */ + volatile struct cgsix_fbc *sc_fbc; /* FBC registers */ + volatile struct cgsix_tec_xxx *sc_tec; /* TEC registers */ union bt_cmap sc_cmap; /* Brooktree color map */ + struct intrhand sc_ih; + int sc_nscreens; }; -/* autoconfiguration driver */ -static void cgsixattach(struct device *, struct device *, void *); -static int cgsixmatch(struct device *, void *, void *); -static void cg6_unblank(struct device *); +struct wsscreen_descr cgsix_stdscreen = { + "std", + 0, 0, /* will be filled in */ + 0, + 0, 0, + WSSCREEN_REVERSE | WSSCREEN_WSCOLORS +}; -struct cfattach cgsix_ca = { - sizeof(struct cgsix_softc), cgsixmatch, cgsixattach +const struct wsscreen_descr *cgsix_scrlist[] = { + &cgsix_stdscreen, }; -struct cfdriver cgsix_cd = { - NULL, "cgsix", DV_DULL +struct wsscreen_list cgsix_screenlist = { + sizeof(cgsix_scrlist) / sizeof(struct wsscreen_descr *), cgsix_scrlist }; -/* frame buffer generic driver */ -static struct fbdriver cg6_fbdriver = { - cg6_unblank, cgsixopen, cgsixclose, cgsixioctl, cgsixmmap +int cgsix_ioctl(void *, u_long, caddr_t, int, struct proc *); +int cgsix_alloc_screen(void *, const struct wsscreen_descr *, void **, + int *, int *, long *); +void cgsix_free_screen(void *, void *); +int cgsix_show_screen(void *, void *, int, void (*cb)(void *, int, int), + void *); +paddr_t cgsix_mmap(void *, off_t, int); +void cgsix_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t); +static __inline__ void cgsix_loadcmap_deferred(struct cgsix_softc *, + u_int, u_int); +void cgsix_reset(struct cgsix_softc *, u_int); +void cgsix_burner(void *, u_int, u_int); +int cgsix_intr(void *); + +void cgsix_ras_init(struct cgsix_softc *); +void cgsix_ras_copyrows(void *, int, int, int); +void cgsix_ras_copycols(void *, int, int, int, int); +void cgsix_ras_erasecols(void *, int, int, int, long int); +void cgsix_ras_eraserows(void *, int, int, long int); +void cgsix_ras_do_cursor(struct rasops_info *); + +struct wsdisplay_accessops cgsix_accessops = { + cgsix_ioctl, + cgsix_mmap, + cgsix_alloc_screen, + cgsix_free_screen, + cgsix_show_screen, + NULL, /* load_font */ + NULL, /* scrollback */ + NULL, /* getchar */ + cgsix_burner, }; -/* - * Unlike the bw2 and cg3 drivers, we do not need to provide an rconsole - * interface, as the cg6 is fast enough.. but provide a knob to turn it - * on anyway. - * XXXCDC: rethink this. the Sun PROM is buggy with some escape sequences - * thus causing your display to get messed up. raster console prevents - * this.... - */ -#ifdef RASTERCONSOLE -int cgsix_use_rasterconsole = 1; -#endif +int cgsixmatch(struct device *, void *, void *); +void cgsixattach(struct device *, struct device *, void *); -extern int fbnode; +struct cfattach cgsix_ca = { + sizeof(struct cgsix_softc), cgsixmatch, cgsixattach +}; -static void cg6_reset(struct cgsix_softc *); -static void cg6_loadcmap(struct cgsix_softc *, int, int); -static void cg6_loadomap(struct cgsix_softc *); -static void cg6_setcursor(struct cgsix_softc *);/* set position */ -static void cg6_loadcursor(struct cgsix_softc *);/* set shape */ +struct cfdriver cgsix_cd = { + NULL, "cgsix", DV_DULL +}; /* * Match a cgsix. @@ -171,14 +205,15 @@ cgsixmatch(parent, vcf, aux) struct confargs *ca = aux; struct romaux *ra = &ca->ca_ra; - if (strcmp(cf->cf_driver->cd_name, ra->ra_name)) - return (0); - /* * Mask out invalid flags from the user. */ cf->cf_flags &= FB_USERMASK; + if (strcmp(ra->ra_name, cf->cf_driver->cd_name) && + strcmp(ra->ra_name, "SUNW,cgsix")) + return (0); + if (ca->ca_bustype == BUS_SBUS) return (1); @@ -214,41 +249,36 @@ cgsixattach(parent, self, args) struct device *parent, *self; void *args; { - register struct cgsix_softc *sc = (struct cgsix_softc *)self; - register struct confargs *ca = args; - register int node = 0, ramsize, i; - register volatile struct bt_regs *bt; - struct fbdevice *fb = &sc->sc_fb; + struct cgsix_softc *sc = (struct cgsix_softc *)self; + struct confargs *ca = args; + struct wsemuldisplaydev_attach_args waa; + int node = 0, i; + volatile struct bt_regs *bt; int isconsole = 0, sbus = 1; char *nam = NULL; - extern struct tty *fbconstty; + u_int fhcrev; - fb->fb_driver = &cg6_fbdriver; - fb->fb_device = &sc->sc_dev; - fb->fb_type.fb_type = FBTYPE_SUNFAST_COLOR; - fb->fb_flags = sc->sc_dev.dv_cfdata->cf_flags; + sc->sc_sunfb.sf_flags = self->dv_cfdata->cf_flags; /* - * Dunno what the PROM has mapped, though obviously it must have - * the video RAM mapped. Just map what we care about for ourselves - * (the FHC, THC, and Brooktree registers). + * May just BT, FHC, FBC, THC, and video RAM. */ -#define O(memb) ((u_int)(&((struct cg6_layout *)0)->memb)) - sc->sc_physadr = ca->ca_ra.ra_reg[0]; - sc->sc_bustype = ca->ca_bustype; + sc->sc_phys = ca->ca_ra.ra_reg[0]; sc->sc_bt = bt = (volatile struct bt_regs *) - mapiodev(ca->ca_ra.ra_reg, O(cg6_bt_un.un_btregs),sizeof *sc->sc_bt); + mapiodev(ca->ca_ra.ra_reg, CGSIX_BT_OFFSET, CGSIX_BT_SIZE); sc->sc_fhc = (volatile int *) - mapiodev(ca->ca_ra.ra_reg, O(cg6_fhc_un.un_fhc), sizeof *sc->sc_fhc); - sc->sc_thc = (volatile struct cg6_thc *) - mapiodev(ca->ca_ra.ra_reg, O(cg6_thc_un.un_thc), sizeof *sc->sc_thc); - sc->sc_tec = (volatile struct cg6_tec_xxx *) - mapiodev(ca->ca_ra.ra_reg, O(cg6_tec_un.un_tec), sizeof *sc->sc_tec); + mapiodev(ca->ca_ra.ra_reg, CGSIX_FHC_OFFSET, CGSIX_FHC_SIZE); + sc->sc_thc = (volatile struct cgsix_thc *) + mapiodev(ca->ca_ra.ra_reg, CGSIX_THC_OFFSET, CGSIX_THC_SIZE); + sc->sc_fbc = (volatile struct cgsix_fbc *) + mapiodev(ca->ca_ra.ra_reg, CGSIX_FBC_OFFSET, CGSIX_FBC_SIZE); + sc->sc_tec = (volatile struct cgsix_tec_xxx *) + mapiodev(ca->ca_ra.ra_reg, CGSIX_TEC_OFFSET, CGSIX_TEC_SIZE); switch (ca->ca_bustype) { case BUS_OBIO: sbus = node = 0; - if (fb->fb_flags & FB_PFOUR) + if (ISSET(sc->sc_sunfb.sf_flags, FB_PFOUR)) nam = "cgsix/p4"; else nam = "cgsix"; @@ -278,289 +308,202 @@ cgsixattach(parent, self, args) return; } - /* Don't have to map the pfour register on the cgsix. */ - fb->fb_pfour = NULL; - - fb->fb_type.fb_depth = 8; - fb_setsize(fb, fb->fb_type.fb_depth, 1152, 900, - node, ca->ca_bustype); - - ramsize = fb->fb_type.fb_height * fb->fb_linebytes; - fb->fb_type.fb_cmsize = 256; - fb->fb_type.fb_size = ramsize; - printf(": %s, %d x %d", nam, fb->fb_type.fb_width, - fb->fb_type.fb_height); + printf(": %s", nam); #if defined(SUN4) if (CPU_ISSUN4) { struct eeprom *eep = (struct eeprom *)eeprom_va; - int constype = (fb->fb_flags & FB_PFOUR) ? EE_CONS_P4OPT : - EE_CONS_COLOR; + int constype = ISSET(sc->sc_sunfb.sf_flags, FB_PFOUR) ? + EE_CONS_P4OPT : EE_CONS_COLOR; /* * Assume this is the console if there's no eeprom info * to be found. */ if (eep == NULL || eep->eeConsole == constype) - isconsole = (fbconstty != NULL); - else - isconsole = 0; + isconsole = 1; } #endif -#if defined(SUN4C) || defined(SUN4M) if (CPU_ISSUN4COR4M) - isconsole = node == fbnode && fbconstty != NULL; -#endif + isconsole = node == fbnode; - sc->sc_fhcrev = (*sc->sc_fhc >> FHC_REV_SHIFT) & + fhcrev = (*sc->sc_fhc >> FHC_REV_SHIFT) & (FHC_REV_MASK >> FHC_REV_SHIFT); - printf(", rev %d", sc->sc_fhcrev); + + sc->sc_ih.ih_fun = cgsix_intr; + sc->sc_ih.ih_arg = sc; + intr_establish(ca->ca_ra.ra_intr[0].int_pri, &sc->sc_ih, IPL_FB); /* reset cursor & frame buffer controls */ - cg6_reset(sc); + cgsix_reset(sc, fhcrev); - /* grab initial (current) color map (DOES THIS WORK?) */ + /* grab initial (current) color map */ bt->bt_addr = 0; for (i = 0; i < 256 * 3; i++) ((char *)&sc->sc_cmap)[i] = bt->bt_cmap >> 24; /* enable video */ - sc->sc_thc->thc_misc |= THC_MISC_VIDEN | THC_MISC_SYNCEN; + cgsix_burner(sc, 1, 0); + + fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, ca->ca_bustype); + sc->sc_sunfb.sf_ro.ri_bits = mapiodev(ca->ca_ra.ra_reg, + CGSIX_VID_OFFSET, round_page(sc->sc_sunfb.sf_fbsize)); + sc->sc_sunfb.sf_ro.ri_hw = sc; + fbwscons_init(&sc->sc_sunfb, isconsole); + + /* + * Old rev. cg6 cards do not like the current acceleration code. + * + * Some hints from Sun point out at timing and cache problems, which + * will be investigated later. + */ + if (fhcrev >= 5) { + sc->sc_sunfb.sf_ro.ri_ops.copyrows = cgsix_ras_copyrows; + sc->sc_sunfb.sf_ro.ri_ops.copycols = cgsix_ras_copycols; + sc->sc_sunfb.sf_ro.ri_ops.eraserows = cgsix_ras_eraserows; + sc->sc_sunfb.sf_ro.ri_ops.erasecols = cgsix_ras_erasecols; + sc->sc_sunfb.sf_ro.ri_do_cursor = cgsix_ras_do_cursor; + cgsix_ras_init(sc); + } + + cgsix_stdscreen.nrows = sc->sc_sunfb.sf_ro.ri_rows; + cgsix_stdscreen.ncols = sc->sc_sunfb.sf_ro.ri_cols; + cgsix_stdscreen.textops = &sc->sc_sunfb.sf_ro.ri_ops; + + printf(", %dx%d, rev %d\n", sc->sc_sunfb.sf_width, + sc->sc_sunfb.sf_height, fhcrev); if (isconsole) { - printf(" (console)\n"); -#ifdef RASTERCONSOLE - if (cgsix_use_rasterconsole) { - sc->sc_fb.fb_pixels = (caddr_t) - mapiodev(ca->ca_ra.ra_reg, - O(cg6_ram[0]), ramsize); - fbrcons_init(&sc->sc_fb); - } -#endif - } else - printf("\n"); + fbwscons_console_init(&sc->sc_sunfb, &cgsix_stdscreen, -1, + cgsix_setcolor, cgsix_burner); + } + #if defined(SUN4C) || defined(SUN4M) if (sbus) - sbus_establish(&sc->sc_sd, &sc->sc_dev); + sbus_establish(&sc->sc_sd, &sc->sc_sunfb.sf_dev); #endif - if (CPU_ISSUN4 || (node == fbnode)) - fb_attach(&sc->sc_fb, isconsole); -} - -int -cgsixopen(dev, flags, mode, p) - dev_t dev; - int flags, mode; - struct proc *p; -{ - int unit = minor(dev); - if (unit >= cgsix_cd.cd_ndevs || cgsix_cd.cd_devs[unit] == NULL) - return (ENXIO); - return (0); + waa.console = isconsole; + waa.scrdata = &cgsix_screenlist; + waa.accessops = &cgsix_accessops; + waa.accesscookie = sc; + config_found(self, &waa, wsemuldisplaydevprint); } int -cgsixclose(dev, flags, mode, p) - dev_t dev; - int flags, mode; - struct proc *p; -{ - struct cgsix_softc *sc = cgsix_cd.cd_devs[minor(dev)]; - - cg6_reset(sc); - return (0); -} - -int -cgsixioctl(dev, cmd, data, flags, p) - dev_t dev; +cgsix_ioctl(dev, cmd, data, flags, p) + void *dev; u_long cmd; - register caddr_t data; + caddr_t data; int flags; struct proc *p; { - register struct cgsix_softc *sc = cgsix_cd.cd_devs[minor(dev)]; - u_int count; - int v, error; - union cursor_cmap tcm; + struct cgsix_softc *sc = dev; + struct wsdisplay_cmap *cm; + struct wsdisplay_fbinfo *wdf; + int error; switch (cmd) { - - case FBIOGTYPE: - *(struct fbtype *)data = sc->sc_fb.fb_type; + case WSDISPLAYIO_GTYPE: + *(u_int *)data = WSDISPLAY_TYPE_UNKNOWN; break; - - case FBIOGATTR: -#define fba ((struct fbgattr *)data) - fba->real_type = sc->sc_fb.fb_type.fb_type; - fba->owner = 0; /* XXX ??? */ - fba->fbtype = sc->sc_fb.fb_type; - fba->sattr.flags = 0; - fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type; - fba->sattr.dev_specific[0] = -1; - fba->emu_types[0] = sc->sc_fb.fb_type.fb_type; - fba->emu_types[1] = -1; -#undef fba + case WSDISPLAYIO_GINFO: + wdf = (struct wsdisplay_fbinfo *)data; + wdf->height = sc->sc_sunfb.sf_height; + wdf->width = sc->sc_sunfb.sf_width; + wdf->depth = sc->sc_sunfb.sf_depth; + wdf->cmsize = 256; + break; + case WSDISPLAYIO_LINEBYTES: + *(u_int *)data = sc->sc_sunfb.sf_linebytes; break; - case FBIOGETCMAP: - return (bt_getcmap((struct fbcmap *)data, &sc->sc_cmap, 256)); - - case FBIOPUTCMAP: - /* copy to software map */ -#define p ((struct fbcmap *)data) - error = bt_putcmap(p, &sc->sc_cmap, 256); + case WSDISPLAYIO_GETCMAP: + cm = (struct wsdisplay_cmap *)data; + error = bt_getcmap(&sc->sc_cmap, cm); if (error) return (error); - /* now blast them into the chip */ - /* XXX should use retrace interrupt */ - cg6_loadcmap(sc, p->index, p->count); -#undef p - break; - - case FBIOGVIDEO: - *(int *)data = sc->sc_blanked; break; - case FBIOSVIDEO: - if (*(int *)data) - cg6_unblank(&sc->sc_dev); - else if (!sc->sc_blanked) { - sc->sc_blanked = 1; - sc->sc_thc->thc_misc &= ~(THC_MISC_VIDEN | - (sparc_vsyncblank ? THC_MISC_SYNCEN : 0)); - } + case WSDISPLAYIO_PUTCMAP: + cm = (struct wsdisplay_cmap *)data; + error = bt_putcmap(&sc->sc_cmap, cm); + if (error) + return (error); + cgsix_loadcmap_deferred(sc, cm->index, cm->count); break; -/* these are for both FBIOSCURSOR and FBIOGCURSOR */ -#define p ((struct fbcursor *)data) -#define cc (&sc->sc_cursor) - - case FBIOGCURSOR: - /* do not quite want everything here... */ - p->set = FB_CUR_SETALL; /* close enough, anyway */ - p->enable = cc->cc_enable; - p->pos = cc->cc_pos; - p->hot = cc->cc_hot; - p->size = cc->cc_size; - - /* begin ugh ... can we lose some of this crap?? */ - if (p->image != NULL) { - count = cc->cc_size.y * 32 / NBBY; - error = copyout((caddr_t)cc->cc_bits[1], - (caddr_t)p->image, count); - if (error) - return (error); - error = copyout((caddr_t)cc->cc_bits[0], - (caddr_t)p->mask, count); - if (error) - return (error); - } - if (p->cmap.red != NULL) { - error = bt_getcmap(&p->cmap, - (union bt_cmap *)&cc->cc_color, 2); - if (error) - return (error); - } else { - p->cmap.index = 0; - p->cmap.count = 2; - } - /* end ugh */ - break; + case WSDISPLAYIO_SVIDEO: + case WSDISPLAYIO_GVIDEO: + case WSDISPLAYIO_GCURPOS: + case WSDISPLAYIO_SCURPOS: + case WSDISPLAYIO_GCURMAX: + case WSDISPLAYIO_GCURSOR: + case WSDISPLAYIO_SCURSOR: + default: + return (-1); /* not supported yet */ + } - case FBIOSCURSOR: - /* - * For setcmap and setshape, verify parameters, so that - * we do not get halfway through an update and then crap - * out with the software state screwed up. - */ - v = p->set; - if (v & FB_CUR_SETCMAP) { - /* - * This use of a temporary copy of the cursor - * colormap is not terribly efficient, but these - * copies are small (8 bytes)... - */ - tcm = cc->cc_color; - error = bt_putcmap(&p->cmap, (union bt_cmap *)&tcm, 2); - if (error) - return (error); - } - if (v & FB_CUR_SETSHAPE) { - if ((u_int)p->size.x > 32 || (u_int)p->size.y > 32) - return (EINVAL); - count = p->size.y * 32 / NBBY; - if (!uvm_useracc(p->image, count, B_READ) || - !uvm_useracc(p->mask, count, B_READ)) - return (EFAULT); - } + return (0); +} - /* parameters are OK; do it */ - if (v & (FB_CUR_SETCUR | FB_CUR_SETPOS | FB_CUR_SETHOT)) { - if (v & FB_CUR_SETCUR) - cc->cc_enable = p->enable; - if (v & FB_CUR_SETPOS) - cc->cc_pos = p->pos; - if (v & FB_CUR_SETHOT) - cc->cc_hot = p->hot; - cg6_setcursor(sc); - } - if (v & FB_CUR_SETCMAP) { - cc->cc_color = tcm; - cg6_loadomap(sc); /* XXX defer to vertical retrace */ - } - if (v & FB_CUR_SETSHAPE) { - cc->cc_size = p->size; - count = p->size.y * 32 / NBBY; - bzero((caddr_t)cc->cc_bits, sizeof cc->cc_bits); - bcopy(p->mask, (caddr_t)cc->cc_bits[0], count); - bcopy(p->image, (caddr_t)cc->cc_bits[1], count); - cg6_loadcursor(sc); - } - break; +int +cgsix_alloc_screen(v, type, cookiep, curxp, curyp, attrp) + void *v; + const struct wsscreen_descr *type; + void **cookiep; + int *curxp, *curyp; + long *attrp; +{ + struct cgsix_softc *sc = v; -#undef p -#undef cc + if (sc->sc_nscreens > 0) + return (ENOMEM); - case FBIOGCURPOS: - *(struct fbcurpos *)data = sc->sc_cursor.cc_pos; - break; + *cookiep = &sc->sc_sunfb.sf_ro; + *curyp = 0; + *curxp = 0; + sc->sc_sunfb.sf_ro.ri_ops.alloc_attr(&sc->sc_sunfb.sf_ro, + WSCOL_BLACK, WSCOL_WHITE, WSATTR_WSCOLORS, attrp); + sc->sc_nscreens++; + return (0); +} - case FBIOSCURPOS: - sc->sc_cursor.cc_pos = *(struct fbcurpos *)data; - cg6_setcursor(sc); - break; +void +cgsix_free_screen(v, cookie) + void *v; + void *cookie; +{ + struct cgsix_softc *sc = v; - case FBIOGCURMAX: - /* max cursor size is 32x32 */ - ((struct fbcurpos *)data)->x = 32; - ((struct fbcurpos *)data)->y = 32; - break; + sc->sc_nscreens--; +} - default: -#ifdef DEBUG - log(LOG_NOTICE, "cgsixioctl(0x%lx) (%s[%d])\n", cmd, - p->p_comm, p->p_pid); -#endif - return (ENOTTY); - } +int +cgsix_show_screen(v, cookie, waitok, cb, cbarg) + void *v; + void *cookie; + int waitok; + void (*cb)(void *, int, int); + void *cbarg; +{ return (0); } /* * Clean up hardware state (e.g., after bootup or after X crashes). */ -static void -cg6_reset(sc) - register struct cgsix_softc *sc; +void +cgsix_reset(sc, fhcrev) + struct cgsix_softc *sc; + u_int fhcrev; { - register volatile struct cg6_tec_xxx *tec; - register int fhc; - register volatile struct bt_regs *bt; + volatile struct cgsix_tec_xxx *tec; + int fhc; + volatile struct bt_regs *bt; /* hide the cursor, just in case */ - sc->sc_thc->thc_cursxy = (THC_CURSOFF << 16) | THC_CURSOFF; + sc->sc_thc->thc_cursxy = THC_CURSOFF; /* turn off frobs in transform engine (makes X11 work) */ tec = sc->sc_tec; @@ -569,7 +512,7 @@ cg6_reset(sc) tec->tec_vdc = 0; /* take care of hardware bugs in old revisions */ - if (sc->sc_fhcrev < 5) { + if (fhcrev < 5) { /* * Keep current resolution; set cpu to 68020, set test * window (size 1Kx1K), and for rev 1, disable dest cache. @@ -577,7 +520,7 @@ cg6_reset(sc) fhc = (*sc->sc_fhc & FHC_RES_MASK) | FHC_CPU_68020 | FHC_TEST | (11 << FHC_TESTX_SHIFT) | (11 << FHC_TESTY_SHIFT); - if (sc->sc_fhcrev < 2) + if (fhcrev < 2) fhc |= FHC_DST_DISABLE; *sc->sc_fhc = fhc; } @@ -588,185 +531,337 @@ cg6_reset(sc) bt->bt_ctrl |= 0x03 << 24; } -static void -cg6_setcursor(sc) - register struct cgsix_softc *sc; +/* + * Return the address that would map the given device at the given + * offset, allowing for the given protection, or return -1 for error. + */ +paddr_t +cgsix_mmap(v, offset, prot) + void *v; + off_t offset; + int prot; +{ + struct cgsix_softc *sc = v; + + if (offset & PGOFSET) + return (-1); + + /* Allow mapping as a dumb framebuffer from offset 0 */ + if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize) { + return (REG2PHYS(&sc->sc_phys, offset + CGSIX_VID_OFFSET) | + PMAP_NC); + } + + return (-1); /* not a user-map offset */ +} + +void +cgsix_setcolor(v, index, r, g, b) + void *v; + u_int index; + u_int8_t r, g, b; { + struct cgsix_softc *sc = v; - /* we need to subtract the hot-spot value here */ -#define COORD(f) (sc->sc_cursor.cc_pos.f - sc->sc_cursor.cc_hot.f) - sc->sc_thc->thc_cursxy = sc->sc_cursor.cc_enable ? - ((COORD(x) << 16) | (COORD(y) & 0xffff)) : - (THC_CURSOFF << 16) | THC_CURSOFF; -#undef COORD + bt_setcolor(&sc->sc_cmap, sc->sc_bt, index, r, g, b, 1); } -static void -cg6_loadcursor(sc) - register struct cgsix_softc *sc; +static __inline__ void +cgsix_loadcmap_deferred(struct cgsix_softc *sc, u_int start, u_int ncolors) { - register volatile struct cg6_thc *thc; - register u_int edgemask, m; - register int i; + u_int32_t thcm; - /* - * Keep the top size.x bits. Here we *throw out* the top - * size.x bits from an all-one-bits word, introducing zeros in - * the top size.x bits, then invert all the bits to get what - * we really wanted as our mask. But this fails if size.x is - * 32---a sparc uses only the low 5 bits of the shift count--- - * so we have to special case that. - */ - edgemask = ~0; - if (sc->sc_cursor.cc_size.x < 32) - edgemask = ~(edgemask >> sc->sc_cursor.cc_size.x); - thc = sc->sc_thc; - for (i = 0; i < 32; i++) { - m = sc->sc_cursor.cc_bits[0][i] & edgemask; - thc->thc_cursmask[i] = m; - thc->thc_cursbits[i] = m & sc->sc_cursor.cc_bits[1][i]; + thcm = sc->sc_thc->thc_misc; + thcm &= ~THC_MISC_RESET; + thcm |= THC_MISC_INTEN; + sc->sc_thc->thc_misc = thcm; +} + +void +cgsix_burner(v, on, flags) + void *v; + u_int on, flags; +{ + struct cgsix_softc *sc = v; + int s; + u_int32_t thcm; + + s = splhigh(); + thcm = sc->sc_thc->thc_misc; + if (on) + thcm |= THC_MISC_VIDEN | THC_MISC_SYNCEN; + else { + thcm &= ~THC_MISC_VIDEN; + if (flags & WSDISPLAY_BURN_VBLANK) + thcm &= ~THC_MISC_SYNCEN; } + sc->sc_thc->thc_misc = thcm; + splx(s); } -/* - * Load a subset of the current (new) colormap into the color DAC. - */ -static void -cg6_loadcmap(sc, start, ncolors) - register struct cgsix_softc *sc; - register int start, ncolors; +int +cgsix_intr(v) + void *v; { - register volatile struct bt_regs *bt; - register u_int *ip, i; - register int count; + struct cgsix_softc *sc = v; + u_int32_t thcm; - ip = &sc->sc_cmap.cm_chip[BT_D4M3(start)]; /* start/4 * 3 */ - count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3; - bt = sc->sc_bt; - bt->bt_addr = BT_D4M4(start) << 24; - while (--count >= 0) { - i = *ip++; - /* hardware that makes one want to pound boards with hammers */ - bt->bt_cmap = i; - bt->bt_cmap = i << 8; - bt->bt_cmap = i << 16; - bt->bt_cmap = i << 24; + thcm = sc->sc_thc->thc_misc; + if ((thcm & (THC_MISC_INTEN | THC_MISC_INTR)) != + (THC_MISC_INTEN | THC_MISC_INTR)) { + /* Not expecting an interrupt, it's not for us. */ + return (0); } + + /* Acknowledge the interrupt and disable it. */ + thcm &= ~(THC_MISC_RESET | THC_MISC_INTEN); + thcm |= THC_MISC_INTR; + sc->sc_thc->thc_misc = thcm; + bt_loadcmap(&sc->sc_cmap, sc->sc_bt, 0, 256, 1); + return (1); } /* - * Load the cursor (overlay `foreground' and `background') colors. + * Specifics rasops handlers for accelerated console */ -static void -cg6_loadomap(sc) - register struct cgsix_softc *sc; + +#define CG6_BLIT_WAIT(fbc) \ + while (((fbc)->fbc_blit & (FBC_BLIT_UNKNOWN | FBC_BLIT_GXFULL)) == \ + (FBC_BLIT_UNKNOWN | FBC_BLIT_GXFULL)) +#define CG6_DRAW_WAIT(fbc) \ + while (((fbc)->fbc_draw & (FBC_DRAW_UNKNOWN | FBC_DRAW_GXFULL)) == \ + (FBC_DRAW_UNKNOWN | FBC_DRAW_GXFULL)) +#define CG6_DRAIN(fbc) \ + while ((fbc)->fbc_s & FBC_S_GXINPROGRESS) + +void +cgsix_ras_init(sc) + struct cgsix_softc *sc; { - register volatile struct bt_regs *bt; - register u_int i; + u_int32_t m; - bt = sc->sc_bt; - bt->bt_addr = 0x01 << 24; /* set background color */ - i = sc->sc_cursor.cc_color.cm_chip[0]; - bt->bt_omap = i; /* R */ - bt->bt_omap = i << 8; /* G */ - bt->bt_omap = i << 16; /* B */ - - bt->bt_addr = 0x03 << 24; /* set foreground color */ - bt->bt_omap = i << 24; /* R */ - i = sc->sc_cursor.cc_color.cm_chip[1]; - bt->bt_omap = i; /* G */ - bt->bt_omap = i << 8; /* B */ + CG6_DRAIN(sc->sc_fbc); + m = sc->sc_fbc->fbc_mode; + m &= ~FBC_MODE_MASK; + m |= FBC_MODE_VAL; + sc->sc_fbc->fbc_mode = m; } -static void -cg6_unblank(dev) - struct device *dev; +void +cgsix_ras_copyrows(cookie, src, dst, n) + void *cookie; + int src, dst, n; { - struct cgsix_softc *sc = (struct cgsix_softc *)dev; + struct rasops_info *ri = cookie; + struct cgsix_softc *sc = ri->ri_hw; + volatile struct cgsix_fbc *fbc = sc->sc_fbc; - if (sc->sc_blanked) { - sc->sc_blanked = 0; - sc->sc_thc->thc_misc |= THC_MISC_VIDEN|THC_MISC_SYNCEN; + if (dst == src) + return; + if (src < 0) { + n += src; + src = 0; } + if (src + n > ri->ri_rows) + n = ri->ri_rows - src; + if (dst < 0) { + n += dst; + dst = 0; + } + if (dst + n > ri->ri_rows) + n = ri->ri_rows - dst; + if (n <= 0) + return; + n *= ri->ri_font->fontheight; + src *= ri->ri_font->fontheight; + dst *= ri->ri_font->fontheight; + + fbc->fbc_clip = 0; + fbc->fbc_s = 0; + fbc->fbc_offx = 0; + fbc->fbc_offy = 0; + fbc->fbc_clipminx = 0; + fbc->fbc_clipminy = 0; + fbc->fbc_clipmaxx = ri->ri_width - 1; + fbc->fbc_clipmaxy = ri->ri_height - 1; + fbc->fbc_alu = FBC_ALU_COPY; + fbc->fbc_x0 = ri->ri_xorigin; + fbc->fbc_y0 = ri->ri_yorigin + src; + fbc->fbc_x1 = ri->ri_xorigin + ri->ri_emuwidth - 1; + fbc->fbc_y1 = ri->ri_yorigin + src + n - 1; + fbc->fbc_x2 = ri->ri_xorigin; + fbc->fbc_y2 = ri->ri_yorigin + dst; + fbc->fbc_x3 = ri->ri_xorigin + ri->ri_emuwidth - 1; + fbc->fbc_y3 = ri->ri_yorigin + dst + n - 1; + CG6_BLIT_WAIT(fbc); + CG6_DRAIN(fbc); } -/* XXX the following should be moved to a "user interface" header */ -/* - * Base addresses at which users can mmap() the various pieces of a cg6. - * Note that although the Brooktree color registers do not occupy 8K, - * the X server dies if we do not allow it to map 8K there (it just maps - * from 0x70000000 forwards, as a contiguous chunk). - */ -#define CG6_USER_FBC 0x70000000 -#define CG6_USER_TEC 0x70001000 -#define CG6_USER_BTREGS 0x70002000 -#define CG6_USER_FHC 0x70004000 -#define CG6_USER_THC 0x70005000 -#define CG6_USER_ROM 0x70006000 -#define CG6_USER_RAM 0x70016000 -#define CG6_USER_DHC 0x80000000 - -struct mmo { - u_int mo_uaddr; /* user (virtual) address */ - u_int mo_size; /* size, or 0 for video ram size */ - u_int mo_physoff; /* offset from sc_physadr */ -}; +void +cgsix_ras_copycols(cookie, row, src, dst, n) + void *cookie; + int row, src, dst, n; +{ + struct rasops_info *ri = cookie; + struct cgsix_softc *sc = ri->ri_hw; + volatile struct cgsix_fbc *fbc = sc->sc_fbc; -/* - * Return the address that would map the given device at the given - * offset, allowing for the given protection, or return -1 for error. - * - * XXX needs testing against `demanding' applications (e.g., aviator) - */ -paddr_t -cgsixmmap(dev, off, prot) - dev_t dev; - off_t off; - int prot; + if (dst == src) + return; + if ((row < 0) || (row >= ri->ri_rows)) + return; + if (src < 0) { + n += src; + src = 0; + } + if (src + n > ri->ri_cols) + n = ri->ri_cols - src; + if (dst < 0) { + n += dst; + dst = 0; + } + if (dst + n > ri->ri_cols) + n = ri->ri_cols - dst; + if (n <= 0) + return; + n *= ri->ri_font->fontwidth; + src *= ri->ri_font->fontwidth; + dst *= ri->ri_font->fontwidth; + row *= ri->ri_font->fontheight; + + fbc->fbc_clip = 0; + fbc->fbc_s = 0; + fbc->fbc_offx = 0; + fbc->fbc_offy = 0; + fbc->fbc_clipminx = 0; + fbc->fbc_clipminy = 0; + fbc->fbc_clipmaxx = ri->ri_width - 1; + fbc->fbc_clipmaxy = ri->ri_height - 1; + fbc->fbc_alu = FBC_ALU_COPY; + fbc->fbc_x0 = ri->ri_xorigin + src; + fbc->fbc_y0 = ri->ri_yorigin + row; + fbc->fbc_x1 = ri->ri_xorigin + src + n - 1; + fbc->fbc_y1 = ri->ri_yorigin + row + ri->ri_font->fontheight - 1; + fbc->fbc_x2 = ri->ri_xorigin + dst; + fbc->fbc_y2 = ri->ri_yorigin + row; + fbc->fbc_x3 = ri->ri_xorigin + dst + n - 1; + fbc->fbc_y3 = ri->ri_yorigin + row + ri->ri_font->fontheight - 1; + CG6_BLIT_WAIT(fbc); + CG6_DRAIN(fbc); +} + +void +cgsix_ras_erasecols(cookie, row, col, n, attr) + void *cookie; + int row, col, n; + long int attr; { - register struct cgsix_softc *sc = cgsix_cd.cd_devs[minor(dev)]; - register struct mmo *mo; - register u_int u, sz; -#define O(memb) ((u_int)(&((struct cg6_layout *)0)->memb)) - static struct mmo mmo[] = { - { CG6_USER_RAM, 0, O(cg6_ram) }, - - /* do not actually know how big most of these are! */ - { CG6_USER_FBC, 1, O(cg6_fbc_un) }, - { CG6_USER_TEC, 1, O(cg6_tec_un) }, - { CG6_USER_BTREGS, 8192 /* XXX */, O(cg6_bt_un) }, - { CG6_USER_FHC, 1, O(cg6_fhc_un) }, - { CG6_USER_THC, sizeof(struct cg6_thc), O(cg6_thc_un) }, - { CG6_USER_ROM, 65536, O(cg6_rom_un) }, - { CG6_USER_DHC, 1, O(cg6_dhc_un) }, - }; -#define NMMO (sizeof mmo / sizeof *mmo) - - if (off & PGOFSET) - panic("cgsixmmap"); + struct rasops_info *ri = cookie; + struct cgsix_softc *sc = ri->ri_hw; + volatile struct cgsix_fbc *fbc = sc->sc_fbc; - /* - * Entries with size 0 map video RAM (i.e., the size in fb data). - * - * Since we work in pages, the fact that the map offset table's - * sizes are sometimes bizarre (e.g., 1) is effectively ignored: - * one byte is as good as one page. - */ - for (mo = mmo; mo < &mmo[NMMO]; mo++) { - if ((u_int)off < mo->mo_uaddr) - continue; - u = off - mo->mo_uaddr; - sz = mo->mo_size ? mo->mo_size : sc->sc_fb.fb_type.fb_size; - if (u < sz) - return (REG2PHYS(&sc->sc_physadr, u + mo->mo_physoff) | - PMAP_NC); + if ((row < 0) || (row >= ri->ri_rows)) + return; + if (col < 0) { + n += col; + col = 0; } -#ifdef DEBUG - { - register struct proc *p = curproc; /* XXX */ - log(LOG_NOTICE, "cgsixmmap(0x%x) (%s[%d])\n", - off, p->p_comm, p->p_pid); + if (col + n > ri->ri_cols) + n = ri->ri_cols - col; + if (n <= 0) + return; + n *= ri->ri_font->fontwidth; + col *= ri->ri_font->fontwidth; + row *= ri->ri_font->fontheight; + + fbc->fbc_clip = 0; + fbc->fbc_s = 0; + fbc->fbc_offx = 0; + fbc->fbc_offy = 0; + fbc->fbc_clipminx = 0; + fbc->fbc_clipminy = 0; + fbc->fbc_clipmaxx = ri->ri_width - 1; + fbc->fbc_clipmaxy = ri->ri_height - 1; + fbc->fbc_alu = FBC_ALU_FILL; + fbc->fbc_fg = ri->ri_devcmap[(attr >> 16) & 0xf]; + fbc->fbc_arecty = ri->ri_yorigin + row; + fbc->fbc_arectx = ri->ri_xorigin + col; + fbc->fbc_arecty = ri->ri_yorigin + row + ri->ri_font->fontheight - 1; + fbc->fbc_arectx = ri->ri_xorigin + col + n - 1; + CG6_DRAW_WAIT(fbc); + CG6_DRAIN(fbc); +} + +void +cgsix_ras_eraserows(cookie, row, n, attr) + void *cookie; + int row, n; + long int attr; +{ + struct rasops_info *ri = cookie; + struct cgsix_softc *sc = ri->ri_hw; + volatile struct cgsix_fbc *fbc = sc->sc_fbc; + + if (row < 0) { + n += row; + row = 0; } -#endif - return (-1); /* not a user-map offset */ + if (row + n > ri->ri_rows) + n = ri->ri_rows - row; + if (n <= 0) + return; + + fbc->fbc_clip = 0; + fbc->fbc_s = 0; + fbc->fbc_offx = 0; + fbc->fbc_offy = 0; + fbc->fbc_clipminx = 0; + fbc->fbc_clipminy = 0; + fbc->fbc_clipmaxx = ri->ri_width - 1; + fbc->fbc_clipmaxy = ri->ri_height - 1; + fbc->fbc_alu = FBC_ALU_FILL; + fbc->fbc_fg = ri->ri_devcmap[(attr >> 16) & 0xf]; + if ((n == ri->ri_rows) && (ri->ri_flg & RI_FULLCLEAR)) { + fbc->fbc_arecty = 0; + fbc->fbc_arectx = 0; + fbc->fbc_arecty = ri->ri_height - 1; + fbc->fbc_arectx = ri->ri_width - 1; + } else { + row *= ri->ri_font->fontheight; + fbc->fbc_arecty = ri->ri_yorigin + row; + fbc->fbc_arectx = ri->ri_xorigin; + fbc->fbc_arecty = + ri->ri_yorigin + row + (n * ri->ri_font->fontheight) - 1; + fbc->fbc_arectx = + ri->ri_xorigin + ri->ri_emuwidth - 1; + } + CG6_DRAW_WAIT(fbc); + CG6_DRAIN(fbc); +} + +void +cgsix_ras_do_cursor(ri) + struct rasops_info *ri; +{ + struct cgsix_softc *sc = ri->ri_hw; + int row, col; + volatile struct cgsix_fbc *fbc = sc->sc_fbc; + + row = ri->ri_crow * ri->ri_font->fontheight; + col = ri->ri_ccol * ri->ri_font->fontwidth; + fbc->fbc_clip = 0; + fbc->fbc_s = 0; + fbc->fbc_offx = 0; + fbc->fbc_offy = 0; + fbc->fbc_clipminx = 0; + fbc->fbc_clipminy = 0; + fbc->fbc_clipmaxx = ri->ri_width - 1; + fbc->fbc_clipmaxy = ri->ri_height - 1; + fbc->fbc_alu = FBC_ALU_FLIP; + fbc->fbc_arecty = ri->ri_yorigin + row; + fbc->fbc_arectx = ri->ri_xorigin + col; + fbc->fbc_arecty = ri->ri_yorigin + row + ri->ri_font->fontheight - 1; + fbc->fbc_arectx = ri->ri_xorigin + col + ri->ri_font->fontwidth - 1; + CG6_DRAW_WAIT(fbc); + CG6_DRAIN(fbc); } diff --git a/sys/arch/sparc/dev/cgsixreg.h b/sys/arch/sparc/dev/cgsixreg.h index a8a63d0a082..04deda89b3f 100644 --- a/sys/arch/sparc/dev/cgsixreg.h +++ b/sys/arch/sparc/dev/cgsixreg.h @@ -1,7 +1,37 @@ -/* $OpenBSD: cgsixreg.h,v 1.3 1997/08/08 08:24:52 downsj Exp $ */ +/* $OpenBSD: cgsixreg.h,v 1.4 2002/08/12 10:44:03 miod Exp $ */ /* $NetBSD: cgsixreg.h,v 1.4 1996/02/27 22:09:31 thorpej Exp $ */ /* + * Copyright (c) 2002 Jason L. Wright (jason@thought.net) + * 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 Jason L. Wright + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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. + */ +/* * Copyright (c) 1993 * The Regents of the University of California. All rights reserved. * @@ -46,10 +76,7 @@ */ /* - * CG6 display registers. (Note, I got tired of writing `cgsix' about - * halfway through and changed everything to cg6, but I probably missed - * some. Unfortunately, the way config works, we need to spell out `six' - * in some places anyway.) + * CG6 display registers. * * The cg6 is a complicated beastie. We have been unable to extract any * documentation and most of the following are guesses based on a limited @@ -73,137 +100,190 @@ */ /* offsets */ -#define CGSIX_FHC_OFFSET 0x300000 +#define CGSIX_ROM_OFFSET 0x000000 +#define CGSIX_BT_OFFSET 0x200000 +#define CGSIX_BT_SIZE (sizeof(u_int32_t) * 4) +#define CGSIX_DHC_OFFSET 0x240000 +#define CGSIX_ALT_OFFSET 0x280000 +#define CGSIX_FHC_OFFSET 0x300000 +#define CGSIX_FHC_SIZE (sizeof(u_int32_t) * 1) +#define CGSIX_THC_OFFSET 0x301000 +#define CGSIX_THC_SIZE (sizeof(u_int32_t) * 640) +#define CGSIX_FBC_OFFSET 0x700000 +#define CGSIX_FBC_SIZE 0x1000 +#define CGSIX_TEC_OFFSET 0x701000 +#define CGSIX_TEC_SIZE (sizeof(u_int32_t) * 3) +#define CGSIX_VID_OFFSET 0x800000 +#define CGSIX_VID_SIZE (1024 * 1024) + +#define CG6_FHC 0x0 /* fhc register */ /* bits in FHC register */ -#define FHC_FBID_MASK 0xff000000 /* bits 24..31 are frame buffer ID */ -#define FHC_FBID_SHIFT 24 -#define FHC_REV_MASK 0x00f00000 /* bits 20..23 are revision */ -#define FHC_REV_SHIFT 20 -#define FHC_FROP_DISABLE 0x00080000 /* disable fast/font? rasterops */ -#define FHC_ROW_DISABLE 0x00040000 /* ??? */ -#define FHC_SRC_DISABLE 0x00020000 /* ??? */ -#define FHC_DST_DISABLE 0x00010000 /* disable destination cache */ -#define FHC_RESET 0x00008000 /* ??? */ -#define FHC_XXX0 0x00004000 /* ??? */ -#define FHC_LEBO 0x00002000 /* set little endian byte order? */ -#define FHC_RES_MASK 0x00001800 /* bits 11&12 are resolution */ -#define FHC_RES_1024 0x00000000 /* res = 1024x768 */ -#define FHC_RES_1152 0x00000800 /* res = 1152x900 */ -#define FHC_RES_1280 0x00001000 /* res = 1280x1024 */ -#define FHC_RES_1600 0x00001800 /* res = 1600x1200 */ -#define FHC_CPU_MASK 0x00000600 /* bits 9&10 are cpu type */ -#define FHC_CPU_SPARC 0x00000000 /* cpu = sparc */ -#define FHC_CPU_68020 0x00000200 /* cpu = 68020 */ -#define FHC_CPU_386 0x00000400 /* cpu = 80386 */ -#define FHC_CPU_XXX 0x00000600 /* ??? */ -#define FHC_TEST 0x00000100 /* ??? test window ??? */ -#define FHC_TESTX_MASK 0x000000f0 /* bits 4..7 are test window X */ -#define FHC_TESTX_SHIFT 4 -#define FHC_TESTY_MASK 0x0000000f /* bits 0..3 are test window Y */ -#define FHC_TESTY_SHIFT 0 +#define FHC_FBID_MASK 0xff000000 /* frame buffer id */ +#define FHC_FBID_SHIFT 24 +#define FHC_REV_MASK 0x00f00000 /* revision */ +#define FHC_REV_SHIFT 20 +#define FHC_FROP_DISABLE 0x00080000 /* disable fast rasterop */ +#define FHC_ROW_DISABLE 0x00040000 /* ??? */ +#define FHC_SRC_DISABLE 0x00020000 /* ??? */ +#define FHC_DST_DISABLE 0x00010000 /* disable dst cache */ +#define FHC_RESET 0x00008000 /* ??? */ +#define FHC_LEBO 0x00002000 /* set little endian order */ +#define FHC_RES_MASK 0x00001800 /* resolution: */ +#define FHC_RES_1024 0x00000000 /* 1024x768 */ +#define FHC_RES_1152 0x00000800 /* 1152x900 */ +#define FHC_RES_1280 0x00001000 /* 1280x1024 */ +#define FHC_RES_1600 0x00001800 /* 1600x1200 */ +#define FHC_CPU_MASK 0x00000600 /* cpu type: */ +#define FHC_CPU_SPARC 0x00000000 /* sparc */ +#define FHC_CPU_68020 0x00000200 /* 68020 */ +#define FHC_CPU_386 0x00000400 /* i386 */ +#define FHC_TEST 0x00000100 /* test window */ +#define FHC_TESTX_MASK 0x000000f0 /* test window X */ +#define FHC_TESTX_SHIFT 4 +#define FHC_TESTY_MASK 0x0000000f /* test window Y */ +#define FHC_TESTY_SHIFT 0 + +struct cgsix_fbc { + u_int32_t fbc_xxx0[1]; + u_int32_t fbc_mode; /* mode setting */ + u_int32_t fbc_clip; /* ??? */ + u_int32_t fbc_xxx1[1]; + u_int32_t fbc_s; /* global status */ + u_int32_t fbc_draw; /* drawing pipeline status */ + u_int32_t fbc_blit; /* blitter status */ + u_int32_t fbc_xxx2[25]; + u_int32_t fbc_x0; /* blitter, src llx */ + u_int32_t fbc_y0; /* blitter, src lly */ + u_int32_t fbc_xxx3[2]; + u_int32_t fbc_x1; /* blitter, src urx */ + u_int32_t fbc_y1; /* blitter, src ury */ + u_int32_t fbc_xxx4[2]; + u_int32_t fbc_x2; /* blitter, dst llx */ + u_int32_t fbc_y2; /* blitter, dst lly */ + u_int32_t fbc_xxx5[2]; + u_int32_t fbc_x3; /* blitter, dst urx */ + u_int32_t fbc_y3; /* blitter, dst ury */ + u_int32_t fbc_xxx6[2]; + u_int32_t fbc_offx; /* x offset for drawing */ + u_int32_t fbc_offy; /* y offset for drawing */ + u_int32_t fbc_xxx7[6]; + u_int32_t fbc_clipminx; /* clip rectangle llx */ + u_int32_t fbc_clipminy; /* clip rectangle lly */ + u_int32_t fbc_xxx8[2]; + u_int32_t fbc_clipmaxx; /* clip rectangle urx */ + u_int32_t fbc_clipmaxy; /* clip rectangle ury */ + u_int32_t fbc_xxx9[2]; + u_int32_t fbc_fg; /* fg value for rop */ + u_int32_t fbc_xxx10[1]; + u_int32_t fbc_alu; /* operation */ + u_int32_t fbc_xxx11[509]; + u_int32_t fbc_arectx; /* rectangle drawing, x coord */ + u_int32_t fbc_arecty; /* rectangle drawing, y coord */ +}; + +#define FBC_MODE_MASK ( \ + 0x00300000 /* GX_BLIT_ALL */ \ + | 0x00060000 /* GX_MODE_ALL */ \ + | 0x00018000 /* GX_DRAW_ALL */ \ + | 0x00006000 /* GX_BWRITE0_ALL */ \ + | 0x00001800 /* GX_BWRITE1_ALL */ \ + | 0x00000600 /* GX_BREAD_ALL */ \ + | 0x00000180 /* GX_BDISP_ALL */ \ +) + +#define FBC_MODE_VAL ( \ + 0x00200000 /* GX_BLIT_SRC */ \ + | 0x00020000 /* GX_MODE_COLOR8 */ \ + | 0x00008000 /* GX_DRAW_RENDER */ \ + | 0x00002000 /* GX_BWRITE0_ENABLE */ \ + | 0x00001000 /* GX_BWRITE1_DISABLE */ \ + | 0x00000200 /* GX_BREAD_0 */ \ + | 0x00000080 /* GX_BDISP_0 */ \ +) + +#define FBC_S_GXINPROGRESS 0x10000000 /* drawing in progress */ + +#define FBC_BLIT_UNKNOWN 0x80000000 /* ??? */ +#define FBC_BLIT_GXFULL 0x20000000 /* queue is full */ + +#define FBC_DRAW_UNKNOWN 0x80000000 /* ??? */ +#define FBC_DRAW_GXFULL 0x20000000 + +/* Value for the alu register for screen-to-screen copies */ +#define FBC_ALU_COPY ( \ + 0x80000000 /* GX_PLANE_ONES (ignore planemask register) */ \ + | 0x20000000 /* GX_PIXEL_ONES (ignore pixelmask register) */ \ + | 0x00800000 /* GX_ATTR_SUPP (function unknown) */ \ + | 0x00000000 /* GX_RAST_BOOL (function unknown) */ \ + | 0x00000000 /* GX_PLOT_PLOT (function unknown) */ \ + | 0x08000000 /* GX_PATTERN_ONES (ignore pattern) */ \ + | 0x01000000 /* GX_POLYG_OVERLAP (unsure - handle overlap?) */ \ + | 0x0000cccc /* ALU = src */ \ +) + +/* Value for the alu register for region fills */ +#define FBC_ALU_FILL ( \ + 0x80000000 /* GX_PLANE_ONES (ignore planemask register) */ \ + | 0x20000000 /* GX_PIXEL_ONES (ignore pixelmask register) */ \ + | 0x00800000 /* GX_ATTR_SUPP (function unknown) */ \ + | 0x00000000 /* GX_RAST_BOOL (function unknown) */ \ + | 0x00000000 /* GX_PLOT_PLOT (function unknown) */ \ + | 0x08000000 /* GX_PATTERN_ONES (ignore pattern) */ \ + | 0x01000000 /* GX_POLYG_OVERLAP (unsure - handle overlap?) */ \ + | 0x0000ff00 /* ALU = fg color */ \ +) + +/* Value for the alu register for toggling an area */ +#define FBC_ALU_FLIP ( \ + 0x80000000 /* GX_PLANE_ONES (ignore planemask register) */ \ + | 0x20000000 /* GX_PIXEL_ONES (ignore pixelmask register) */ \ + | 0x00800000 /* GX_ATTR_SUPP (function unknown) */ \ + | 0x00000000 /* GX_RAST_BOOL (function unknown) */ \ + | 0x00000000 /* GX_PLOT_PLOT (function unknown) */ \ + | 0x08000000 /* GX_PATTERN_ONES (ignore pattern) */ \ + | 0x01000000 /* GX_POLYG_OVERLAP (unsure - handle overlap?) */ \ + | 0x00005555 /* ALU = ~dst */ \ +) /* * The layout of the THC. */ -struct cg6_thc { - u_int thc_xxx0[512]; /* ??? */ - u_int thc_hsync1; /* horizontal sync timing */ - u_int thc_hsync2; /* more hsync timing */ - u_int thc_hsync3; /* yet more hsync timing */ - u_int thc_vsync1; /* vertical sync timing */ - u_int thc_vsync2; /* only two of these */ - u_int thc_refresh; /* refresh counter */ - u_int thc_misc; /* miscellaneous control & status */ - u_int thc_xxx1[56]; /* ??? */ - u_int thc_cursxy; /* cursor x,y position (16 bits each) */ - u_int thc_cursmask[32]; /* cursor mask bits */ - u_int thc_cursbits[32]; /* what to show where mask enabled */ +struct cgsix_thc { + u_int32_t thc_xxx0[512]; /* ??? */ + u_int32_t thc_hsync1; /* horizontal sync timing */ + u_int32_t thc_hsync2; /* more hsync timing */ + u_int32_t thc_hsync3; /* yet more hsync timing */ + u_int32_t thc_vsync1; /* vertical sync timing */ + u_int32_t thc_vsync2; /* only two of these */ + u_int32_t thc_refresh; /* refresh counter */ + u_int32_t thc_misc; /* miscellaneous control & status */ + u_int32_t thc_xxx1[56]; /* ??? */ + u_int32_t thc_cursxy; /* cursor x,y position (16 bits each) */ + u_int32_t thc_cursmask[32]; /* cursor mask bits */ + u_int32_t thc_cursbits[32]; /* what to show where mask enabled */ }; -/* bits in thc_misc */ -#define THC_MISC_XXX0 0xfff00000 /* unused */ -#define THC_MISC_REVMASK 0x000f0000 /* cg6 revision? */ -#define THC_MISC_REVSHIFT 16 -#define THC_MISC_XXX1 0x0000e000 /* unused */ -#define THC_MISC_RESET 0x00001000 /* ??? */ -#define THC_MISC_XXX2 0x00000800 /* unused */ +/* cursor x/y position for 'off' */ +#define THC_CURSOFF ((65536-32) | ((65536-32) << 16)) + +#define THC_MISC_REV_M 0x000f0000 /* chip revision */ +#define THC_MISC_REV_S 16 +#define THC_MISC_RESET 0x00001000 /* reset */ #define THC_MISC_VIDEN 0x00000400 /* video enable */ #define THC_MISC_SYNC 0x00000200 /* not sure what ... */ #define THC_MISC_VSYNC 0x00000100 /* ... these really are */ #define THC_MISC_SYNCEN 0x00000080 /* sync enable */ #define THC_MISC_CURSRES 0x00000040 /* cursor resolution */ #define THC_MISC_INTEN 0x00000020 /* v.retrace intr enable */ -#define THC_MISC_INTR 0x00000010 /* intr pending / ack bit */ -#define THC_MISC_XXX 0x0000000f /* ??? */ - -/* cursor x / y position value for `off' */ -#define THC_CURSOFF (65536-32) /* i.e., USHRT_MAX+1-32 */ +#define THC_MISC_INTR 0x00000010 /* intr pending/ack */ +#define THC_MISC_CYCLS 0x0000000f /* cycles before transfer */ /* * Partial description of TEC (needed to get around FHC rev 1 bugs). */ -struct cg6_tec_xxx { - u_int tec_mv; /* matrix stuff */ - u_int tec_clip; /* clipping stuff */ - u_int tec_vdc; /* ??? */ -}; - -/* - * This structure exists only to compute the layout of the CG6 - * hardware. Each of the individual substructures lives on a - * separate `page' (where a `page' is at least 4K), and many are - * very far apart. We avoid large offsets (which make for lousy - * code) by using pointers to the individual interesting pieces, - * and map them in independently (to avoid using up PTEs unnecessarily). - */ -struct cg6_layout { - /* ROM at 0 */ - union { - long un_id; /* ID = ?? */ - char un_rom[65536]; /* 64K rom */ - char un_pad[0x200000]; - } cg6_rom_un; - - /* Brooktree DAC at 0x200000 */ - union { - struct bt_regs un_btregs; - char un_pad[0x040000]; - } cg6_bt_un; - - /* DHC, whatever that is, at 0x240000 */ - union { - char un_pad[0x40000]; - } cg6_dhc_un; - - /* ALT, whatever that is, at 0x280000 */ - union { - char un_pad[0x80000]; - } cg6_alt_un; - - /* FHC register at 0x300000 */ - union { - int un_fhc; - char un_pad[0x1000]; - } cg6_fhc_un; - - /* THC at 0x301000 */ - union { - struct cg6_thc un_thc; - char un_pad[0x400000 - 0x1000]; - } cg6_thc_un; - - /* FBC at 0x700000 */ - union { - char un_pad[0x1000]; - } cg6_fbc_un; - - /* TEC at 0x701000 */ - union { - char un_pad[0x100000 - 0x1000]; - struct cg6_tec_xxx un_tec; - } cg6_tec_un; - - /* Video RAM at 0x800000 */ - char cg6_ram[1024 * 1024]; /* approx.? */ +struct cgsix_tec_xxx { + u_int32_t tec_mv; /* matrix stuff */ + u_int32_t tec_clip; /* clipping stuff */ + u_int32_t tec_vdc; /* ??? */ }; diff --git a/sys/arch/sparc/dev/cgthree.c b/sys/arch/sparc/dev/cgthree.c index 4a079be7265..9f522a855d8 100644 --- a/sys/arch/sparc/dev/cgthree.c +++ b/sys/arch/sparc/dev/cgthree.c @@ -1,7 +1,42 @@ -/* $OpenBSD: cgthree.c,v 1.14 2002/07/09 23:33:15 jason Exp $ */ +/* $OpenBSD: cgthree.c,v 1.15 2002/08/12 10:44:03 miod Exp $ */ /* $NetBSD: cgthree.c,v 1.33 1997/05/24 20:16:11 pk Exp $ */ /* + * Copyright (c) 2002 Miodrag Vallat. All rights reserved. + * Copyright (c) 2001 Jason L. Wright (jason@thought.net) + * 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 Jason L. Wright + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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. + * + * Effort sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F30602-01-2-0537. + * + * * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * @@ -48,9 +83,6 @@ /* * color display (cgthree) driver. * - * Does not handle interrupts, even though they can occur. - * - * XXX should defer colormap updates to vertical retrace interrupts */ #include <sys/param.h> @@ -65,13 +97,17 @@ #include <uvm/uvm_extern.h> -#include <machine/fbio.h> #include <machine/autoconf.h> #include <machine/pmap.h> -#include <machine/fbvar.h> #include <machine/cpu.h> #include <machine/conf.h> +#include <dev/wscons/wsconsio.h> +#include <dev/wscons/wsdisplayvar.h> +#include <dev/wscons/wscons_raster.h> +#include <dev/rasops/rasops.h> +#include <machine/fbvar.h> + #include <sparc/dev/btreg.h> #include <sparc/dev/btvar.h> #include <sparc/dev/cgthreereg.h> @@ -79,53 +115,88 @@ /* per-display variables */ struct cgthree_softc { - struct device sc_dev; /* base device */ + struct sunfb sc_sunfb; /* common base part */ struct sbusdev sc_sd; /* sbus device */ - struct fbdevice sc_fb; /* frame buffer device */ struct rom_reg sc_phys; /* phys address description */ volatile struct fbcontrol *sc_fbc; /* Brooktree registers */ - int sc_bustype; /* type of bus we live on */ - int sc_isrdi; /* is an RDI */ union bt_cmap sc_cmap; /* Brooktree color map */ + struct intrhand sc_ih; + int sc_nscreens; }; -/* autoconfiguration driver */ -static void cgthreeattach(struct device *, struct device *, void *); -static int cgthreematch(struct device *, void *, void *); -static void cgthreeunblank(struct device *); +struct wsscreen_descr cgthree_stdscreen = { + "std", + 0, 0, /* will be filled in */ + 0, + 0, 0, + WSSCREEN_REVERSE | WSSCREEN_WSCOLORS +}; -struct cfattach cgthree_ca = { - sizeof(struct cgthree_softc), cgthreematch, cgthreeattach +const struct wsscreen_descr *cgthree_scrlist[] = { + &cgthree_stdscreen, }; -struct cfdriver cgthree_cd = { - NULL, "cgthree", DV_DULL +struct wsscreen_list cgthree_screenlist = { + sizeof(cgthree_scrlist) / sizeof(struct wsscreen_descr *), + cgthree_scrlist }; -/* frame buffer generic driver */ -static struct fbdriver cgthreefbdriver = { - cgthreeunblank, cgthreeopen, cgthreeclose, cgthreeioctl, cgthreemmap +int cgthree_ioctl(void *, u_long, caddr_t, int, struct proc *); +int cgthree_alloc_screen(void *, const struct wsscreen_descr *, void **, + int *, int *, long *); +void cgthree_free_screen(void *, void *); +int cgthree_show_screen(void *, void *, int, void (*cb)(void *, int, int), + void *); +paddr_t cgthree_mmap(void *, off_t, int); +void cgthree_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t); +static __inline__ void cgthree_loadcmap_deferred(struct cgthree_softc *, + u_int, u_int); +void cgthree_burner(void *, u_int, u_int); +int cgthree_intr(void *); + +struct wsdisplay_accessops cgthree_accessops = { + cgthree_ioctl, + cgthree_mmap, + cgthree_alloc_screen, + cgthree_free_screen, + cgthree_show_screen, + NULL, /* load_font */ + NULL, /* scrollback */ + NULL, /* getchar */ + cgthree_burner, }; -extern int fbnode; -extern struct tty *fbconstty; +int cgthreematch(struct device *, void *, void *); +void cgthreeattach(struct device *, struct device *, void *); + +struct cfattach cgthree_ca = { + sizeof (struct cgthree_softc), cgthreematch, cgthreeattach +}; -static void cgthreeloadcmap(struct cgthree_softc *, int, int); -static void cgthree_set_video(struct cgthree_softc *, int); -static int cgthree_get_video(struct cgthree_softc *); +struct cfdriver cgthree_cd = { + NULL, "cgthree", DV_DULL +}; /* Video control parameters */ struct cg3_videoctrl { - unsigned char sense; /* Monitor sense value */ - unsigned char vctrl[12]; + u_int8_t sense; + u_int8_t vctrl[12]; } cg3_videoctrl[] = { -/* Missing entries: sense 0x10, 0x30, 0x50 */ - { 0x40, /* this happens to be my 19'' 1152x900 gray-scale monitor */ - {0xbb, 0x2b, 0x3, 0xb, 0xb3, 0x3, 0xaf, 0x2b, 0x2, 0xa, 0xff, 0x1} + { /* cpd-1790 */ + 0x31, + { 0xbb, 0x2b, 0x04, 0x14, 0xae, 0x03, + 0xa8, 0x24, 0x01, 0x05, 0xff, 0x01 }, + }, + { /* gdm-20e20 */ + 0x41, + { 0xb7, 0x27, 0x03, 0x0f, 0xae, 0x03, + 0xae, 0x2a, 0x01, 0x09, 0xff, 0x01 }, + }, + { /* defaults, should be last */ + 0xff, + { 0xbb, 0x2b, 0x03, 0x0b, 0xb3, 0x03, + 0xaf, 0x2b, 0x02, 0x0a, 0xff, 0x01 }, }, - { 0x00, /* default? must be last */ - {0xbb, 0x2b, 0x3, 0xb, 0xb3, 0x3, 0xaf, 0x2b, 0x2, 0xa, 0xff, 0x1} - } }; /* @@ -145,45 +216,43 @@ cgthreematch(parent, vcf, aux) */ cf->cf_flags &= FB_USERMASK; - if (strcmp(cf->cf_driver->cd_name, ra->ra_name) && - strcmp("cgRDI",ra->ra_name)) + if (strcmp(cf->cf_driver->cd_name, ra->ra_name) && + strcmp("cgRDI", ra->ra_name)) return (0); + if (ca->ca_bustype == BUS_SBUS) - return(1); + return (1); + ra->ra_len = NBPG; return (probeget(ra->ra_vaddr, 4) != -1); } /* - * Attach a display. We need to notice if it is the console, too. + * Attach a display. */ void cgthreeattach(parent, self, args) struct device *parent, *self; void *args; { - register struct cgthree_softc *sc = (struct cgthree_softc *)self; - register struct confargs *ca = args; - register int node = 0, ramsize, i; - register volatile struct bt_regs *bt; - int isconsole; - int sbus = 1; + struct cgthree_softc *sc = (struct cgthree_softc *)self; + struct confargs *ca = args; + struct wsemuldisplaydev_attach_args waa; + int node = 0, isrdi = 0, i; + volatile struct bt_regs *bt; + int isconsole = 0, sbus = 1; char *nam = NULL; - sc->sc_fb.fb_driver = &cgthreefbdriver; - sc->sc_fb.fb_device = &sc->sc_dev; - sc->sc_fb.fb_flags = sc->sc_dev.dv_cfdata->cf_flags; - /* - * The defaults below match my screen, but are not guaranteed - * to be correct as defaults go... - */ - sc->sc_fb.fb_type.fb_type = FBTYPE_SUN3COLOR; + sc->sc_sunfb.sf_flags = self->dv_cfdata->cf_flags; + switch (ca->ca_bustype) { case BUS_OBIO: if (CPU_ISSUN4M) { /* 4m has framebuffer on obio */ sbus = 0; node = ca->ca_ra.ra_node; nam = getpropstring(node, "model"); + if (*nam == '\0') + nam = "cgthree"; break; } case BUS_VME32: @@ -195,49 +264,36 @@ cgthreeattach(parent, self, args) case BUS_SBUS: node = ca->ca_ra.ra_node; nam = getpropstring(node, "model"); + if (*nam == '\0') + nam = "cgthree"; break; } - sc->sc_fb.fb_type.fb_depth = 8; - fb_setsize(&sc->sc_fb, sc->sc_fb.fb_type.fb_depth, - 1152, 900, node, ca->ca_bustype); - if(!strcmp(ca->ca_ra.ra_name, "cgRDI")) { - sc->sc_isrdi = 1; + if (!strcmp(ca->ca_ra.ra_name, "cgRDI")) { + isrdi = 1; nam = "cgRDI"; } - ramsize = round_page(sc->sc_fb.fb_type.fb_height * - sc->sc_fb.fb_linebytes); - sc->sc_fb.fb_type.fb_cmsize = 256; - sc->sc_fb.fb_type.fb_size = ramsize; - printf(": %s, %d x %d", nam, - sc->sc_fb.fb_type.fb_width, sc->sc_fb.fb_type.fb_height); + printf(": %s", nam); + + isconsole = node == fbnode; - /* - * When the ROM has mapped in a cgthree display, the address - * maps only the video RAM, so in any case we have to map the - * registers ourselves. We only need the video RAM if we are - * going to print characters via rconsole. - */ - isconsole = node == fbnode && fbconstty != NULL; - if ((sc->sc_fb.fb_pixels = ca->ca_ra.ra_vaddr) == NULL && isconsole) { - /* this probably cannot happen, but what the heck */ - sc->sc_fb.fb_pixels = mapiodev(ca->ca_ra.ra_reg, CG3REG_MEM, - ramsize); - } sc->sc_fbc = (volatile struct fbcontrol *) mapiodev(ca->ca_ra.ra_reg, CG3REG_REG, sizeof(struct fbcontrol)); /* Transfer video magic to board, if it's not running */ - if (!sc->sc_isrdi && (sc->sc_fbc->fbc_ctrl & FBC_TIMING) == 0) + if (isrdi == 0 && (sc->sc_fbc->fbc_ctrl & FBC_TIMING) == 0) for (i = 0; i < sizeof(cg3_videoctrl)/sizeof(cg3_videoctrl[0]); i++) { volatile struct fbcontrol *fbc = sc->sc_fbc; - if ((fbc->fbc_status & FBS_MSENSE) == + if (cg3_videoctrl[i].sense == 0xff || + (fbc->fbc_status & FBS_MSENSE) == cg3_videoctrl[i].sense) { int j; - printf(" setting video ctrl"); +#ifdef DEBUG + printf(" (setting video ctrl)"); +#endif for (j = 0; j < 12; j++) fbc->fbc_vcontrol[j] = cg3_videoctrl[i].vctrl[j]; @@ -247,7 +303,10 @@ cgthreeattach(parent, self, args) } sc->sc_phys = ca->ca_ra.ra_reg[0]; - sc->sc_bustype = ca->ca_bustype; + + sc->sc_ih.ih_fun = cgthree_intr; + sc->sc_ih.ih_arg = sc; + intr_establish(ca->ca_ra.ra_intr[0].int_pri, &sc->sc_ih, IPL_FB); /* grab initial (current) color map */ bt = &sc->sc_fbc->fbc_dac; @@ -255,200 +314,213 @@ cgthreeattach(parent, self, args) for (i = 0; i < 256 * 3 / 4; i++) sc->sc_cmap.cm_chip[i] = bt->bt_cmap; - /* make sure we are not blanked */ - cgthree_set_video(sc, 1); + /* enable video */ + cgthree_burner(sc, 1, 0); BT_INIT(bt, 0); - if (isconsole) { - printf(" (console)\n"); -#ifdef RASTERCONSOLE - fbrcons_init(&sc->sc_fb); -#endif - } else - printf("\n"); - if (sbus) - sbus_establish(&sc->sc_sd, &sc->sc_dev); - if (node == fbnode) - fb_attach(&sc->sc_fb, isconsole); -} + fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, ca->ca_bustype); + sc->sc_sunfb.sf_ro.ri_bits = mapiodev(ca->ca_ra.ra_reg, CG3REG_MEM, + round_page(sc->sc_sunfb.sf_fbsize)); + sc->sc_sunfb.sf_ro.ri_hw = sc; + fbwscons_init(&sc->sc_sunfb, isconsole); -int -cgthreeopen(dev, flags, mode, p) - dev_t dev; - int flags, mode; - struct proc *p; -{ - int unit = minor(dev); + cgthree_stdscreen.nrows = sc->sc_sunfb.sf_ro.ri_rows; + cgthree_stdscreen.ncols = sc->sc_sunfb.sf_ro.ri_cols; + cgthree_stdscreen.textops = &sc->sc_sunfb.sf_ro.ri_ops; - if (unit >= cgthree_cd.cd_ndevs || cgthree_cd.cd_devs[unit] == NULL) - return (ENXIO); - return (0); -} + printf(", %dx%d\n", sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height); -int -cgthreeclose(dev, flags, mode, p) - dev_t dev; - int flags, mode; - struct proc *p; -{ + if (isconsole) { + fbwscons_console_init(&sc->sc_sunfb, &cgthree_stdscreen, -1, + cgthree_setcolor, cgthree_burner); + } +#if defined(SUN4C) || defined(SUN4M) + if (sbus) + sbus_establish(&sc->sc_sd, &sc->sc_sunfb.sf_dev); +#endif - return (0); + waa.console = isconsole; + waa.scrdata = &cgthree_screenlist; + waa.accessops = &cgthree_accessops; + waa.accesscookie = sc; + config_found(self, &waa, wsemuldisplaydevprint); } int -cgthreeioctl(dev, cmd, data, flags, p) - dev_t dev; +cgthree_ioctl(v, cmd, data, flags, p) + void *v; u_long cmd; - register caddr_t data; + caddr_t data; int flags; struct proc *p; { - register struct cgthree_softc *sc = cgthree_cd.cd_devs[minor(dev)]; - register struct fbgattr *fba; + struct cgthree_softc *sc = v; + struct wsdisplay_fbinfo *wdf; + struct wsdisplay_cmap *cm; int error; switch (cmd) { - - case FBIOGTYPE: - *(struct fbtype *)data = sc->sc_fb.fb_type; + case WSDISPLAYIO_GTYPE: + *(u_int *)data = WSDISPLAY_TYPE_UNKNOWN; break; - - case FBIOGATTR: - fba = (struct fbgattr *)data; - fba->real_type = sc->sc_fb.fb_type.fb_type; - fba->owner = 0; /* XXX ??? */ - fba->fbtype = sc->sc_fb.fb_type; - fba->sattr.flags = 0; - fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type; - fba->sattr.dev_specific[0] = -1; - fba->emu_types[0] = sc->sc_fb.fb_type.fb_type; - fba->emu_types[1] = -1; + case WSDISPLAYIO_GINFO: + wdf = (struct wsdisplay_fbinfo *)data; + wdf->height = sc->sc_sunfb.sf_height; + wdf->width = sc->sc_sunfb.sf_width; + wdf->depth = sc->sc_sunfb.sf_depth; + wdf->cmsize = 256; + break; + case WSDISPLAYIO_LINEBYTES: + *(u_int *)data = sc->sc_sunfb.sf_linebytes; break; - case FBIOGETCMAP: - return (bt_getcmap((struct fbcmap *)data, &sc->sc_cmap, 256)); - - case FBIOPUTCMAP: - /* copy to software map */ -#define p ((struct fbcmap *)data) - error = bt_putcmap(p, &sc->sc_cmap, 256); + case WSDISPLAYIO_GETCMAP: + cm = (struct wsdisplay_cmap *)data; + error = bt_getcmap(&sc->sc_cmap, cm); if (error) return (error); - /* now blast them into the chip */ - /* XXX should use retrace interrupt */ - cgthreeloadcmap(sc, p->index, p->count); -#undef p - break; - - case FBIOGVIDEO: - *(int *)data = cgthree_get_video(sc); break; - case FBIOSVIDEO: - cgthree_set_video(sc, *(int *)data); + case WSDISPLAYIO_PUTCMAP: + cm = (struct wsdisplay_cmap *)data; + error = bt_putcmap(&sc->sc_cmap, cm); + if (error) + return (error); + cgthree_loadcmap_deferred(sc, cm->index, cm->count); break; + case WSDISPLAYIO_SVIDEO: + case WSDISPLAYIO_GVIDEO: + case WSDISPLAYIO_GCURPOS: + case WSDISPLAYIO_SCURPOS: + case WSDISPLAYIO_GCURMAX: + case WSDISPLAYIO_GCURSOR: + case WSDISPLAYIO_SCURSOR: default: - return (ENOTTY); - } + return (-1); /* not supported yet */ + } + return (0); } -/* - * Undo the effect of an FBIOSVIDEO that turns the video off. - */ -static void -cgthreeunblank(dev) - struct device *dev; +int +cgthree_alloc_screen(v, type, cookiep, curxp, curyp, attrp) + void *v; + const struct wsscreen_descr *type; + void **cookiep; + int *curxp, *curyp; + long *attrp; { + struct cgthree_softc *sc = v; - cgthree_set_video((struct cgthree_softc *)dev, 1); -} - -static void -cgthree_set_video(sc, enable) - struct cgthree_softc *sc; - int enable; -{ - extern int sparc_vsyncblank; + if (sc->sc_nscreens > 0) + return (ENOMEM); - if (enable) - sc->sc_fbc->fbc_ctrl |= FBC_VENAB | FBC_TIMING; - else { - sc->sc_fbc->fbc_ctrl &= ~FBC_VENAB; - if (sparc_vsyncblank) - sc->sc_fbc->fbc_ctrl &= ~FBC_TIMING; - } + *cookiep = &sc->sc_sunfb.sf_ro; + *curyp = 0; + *curxp = 0; + sc->sc_sunfb.sf_ro.ri_ops.alloc_attr(&sc->sc_sunfb.sf_ro, + WSCOL_BLACK, WSCOL_WHITE, WSATTR_WSCOLORS, attrp); + sc->sc_nscreens++; + return (0); } -static int -cgthree_get_video(sc) - struct cgthree_softc *sc; +void +cgthree_free_screen(v, cookie) + void *v; + void *cookie; { + struct cgthree_softc *sc = v; - return ((sc->sc_fbc->fbc_ctrl & FBC_VENAB) != 0); + sc->sc_nscreens--; } -/* - * Load a subset of the current (new) colormap into the Brooktree DAC. - */ -static void -cgthreeloadcmap(sc, start, ncolors) - register struct cgthree_softc *sc; - register int start, ncolors; +int +cgthree_show_screen(v, cookie, waitok, cb, cbarg) + void *v; + void *cookie; + int waitok; + void (*cb)(void *, int, int); + void *cbarg; { - register volatile struct bt_regs *bt; - register u_int *ip; - register int count; - - ip = &sc->sc_cmap.cm_chip[BT_D4M3(start)]; /* start/4 * 3 */ - count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3; - bt = &sc->sc_fbc->fbc_dac; - bt->bt_addr = BT_D4M4(start); - while (--count >= 0) - bt->bt_cmap = *ip++; + return (0); } /* * Return the address that would map the given device at the given * offset, allowing for the given protection, or return -1 for error. - * - * The cg3 is mapped starting at 256KB, for pseudo-compatibility with - * the cg4 (which had an overlay plane in the first 128K and an enable - * plane in the next 128K). X11 uses only 256k+ region but tries to - * map the whole thing, so we repeatedly map the first 256K to the - * first page of the color screen. If someone tries to use the overlay - * and enable regions, they will get a surprise.... - * - * As well, mapping at an offset of 0x04000000 causes the cg3 to be - * mapped in flat mode without the cg4 emulation. */ paddr_t -cgthreemmap(dev, off, prot) - dev_t dev; - off_t off; +cgthree_mmap(v, offset, prot) + void *v; + off_t offset; int prot; { - register struct cgthree_softc *sc = cgthree_cd.cd_devs[minor(dev)]; -#define START (128*1024 + 128*1024) -#define NOOVERLAY (0x04000000) + struct cgthree_softc *sc = v; - if (off & PGOFSET) - panic("cgthreemmap"); - - if (off < 0) - return (-1); - if ((u_int)off >= NOOVERLAY) - off -= NOOVERLAY; - else if ((u_int)off >= START) - off -= START; - else - off = 0; - if ((unsigned)off >= sc->sc_fb.fb_type.fb_size) + if (offset & PGOFSET) return (-1); - /* - * I turned on PMAP_NC here to disable the cache as I was - * getting horribly broken behaviour with it on. - */ - return (REG2PHYS(&sc->sc_phys, CG3REG_MEM+off) | PMAP_NC); + + if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize) { + return (REG2PHYS(&sc->sc_phys, + CG3REG_MEM + offset) | PMAP_NC); + } + + return (-1); +} + +void +cgthree_setcolor(v, index, r, g, b) + void *v; + u_int index; + u_int8_t r, g, b; +{ + struct cgthree_softc *sc = v; + + bt_setcolor(&sc->sc_cmap, &sc->sc_fbc->fbc_dac, index, r, g, b, 0); +} + +static __inline__ void +cgthree_loadcmap_deferred(struct cgthree_softc *sc, u_int start, u_int ncolors) +{ + + sc->sc_fbc->fbc_ctrl |= FBC_IENAB; +} + +void +cgthree_burner(v, on, flags) + void *v; + u_int on, flags; +{ + struct cgthree_softc *sc = v; + int s; + + s = splhigh(); + if (on) + sc->sc_fbc->fbc_ctrl |= FBC_VENAB | FBC_TIMING; + else { + sc->sc_fbc->fbc_ctrl &= ~FBC_VENAB; + if (flags & WSDISPLAY_BURN_VBLANK) + sc->sc_fbc->fbc_ctrl &= ~FBC_TIMING; + } + splx(s); +} + +int +cgthree_intr(v) + void *v; +{ + struct cgthree_softc *sc = v; + + if (!ISSET(sc->sc_fbc->fbc_ctrl, FBC_IENAB) || + !ISSET(sc->sc_fbc->fbc_status, FBS_INTR)) { + /* Not expecting an interrupt, it's not for us. */ + return (0); + } + + /* Acknowledge the interrupt and disable it. */ + sc->sc_fbc->fbc_ctrl &= ~FBC_IENAB; + + bt_loadcmap(&sc->sc_cmap, &sc->sc_fbc->fbc_dac, 0, 256, 0); + return (1); } diff --git a/sys/arch/sparc/dev/cgtwelve.c b/sys/arch/sparc/dev/cgtwelve.c new file mode 100644 index 00000000000..5fc5627a0bb --- /dev/null +++ b/sys/arch/sparc/dev/cgtwelve.c @@ -0,0 +1,585 @@ +/* $OpenBSD: cgtwelve.c,v 1.1 2002/08/12 10:44:03 miod Exp $ */ + +/* + * Copyright (c) 2002 Miodrag Vallat. 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. + */ + +/* + * cgtwelve (GS) accelerated 24-bit framebuffer driver. + * + * Enough experiments and SMI's cg12reg.h made this possible. + */ + +/* + * The cgtwelve framebuffer is a 3-slot SBUS card, that will fit only in + * SPARCstation 1, 1+, 2 and 5, or in an xbox SBUS extension (untested). + * + * It is a 24-bit 3D accelerated framebuffer made by Matrox, featuring 4MB + * (regular model) or 8MB (high-res model) of video memory, a complex windowing + * engine, double buffering modes, three video planes (overlay, 8 bit and 24 bit + * color), and a lot of colormap combinations. + * + * All of this is driven by a set of three Bt462 ramdacs, and a couple of + * Matrox-specific chips. + * + * XXX The high res card is untested. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/buf.h> +#include <sys/device.h> +#include <sys/ioctl.h> +#include <sys/malloc.h> +#include <sys/mman.h> +#include <sys/tty.h> +#include <sys/conf.h> + +#include <uvm/uvm_extern.h> + +#include <machine/autoconf.h> +#include <machine/pmap.h> +#include <machine/cpu.h> +#include <machine/conf.h> + +#include <dev/wscons/wsconsio.h> +#include <dev/wscons/wsdisplayvar.h> +#include <dev/wscons/wscons_raster.h> +#include <dev/rasops/rasops.h> +#include <machine/fbvar.h> + +#include <sparc/dev/cgtwelvereg.h> +#include <sparc/dev/sbusvar.h> + +#include <dev/cons.h> /* for prom console hook */ + +/* + * Define CG12_MONO to only use the overlay plane of the CG12, thus having + * a very fast, though monochrome, framebuffer. + */ +#ifdef SMALL_KERNEL +#define CG12_MONO +#endif + +/* per-display variables */ +struct cgtwelve_softc { + struct sunfb sc_sunfb; /* common base device */ + struct sbusdev sc_sd; /* sbus device */ + struct rom_reg sc_phys; + + volatile struct cgtwelve_dpu *sc_dpu; + volatile struct cgtwelve_apu *sc_apu; + volatile struct cgtwelve_dac *sc_ramdac; /* RAMDAC registers */ + volatile u_char *sc_overlay; /* overlay or enable plane */ +#ifndef CG12_MONO + volatile u_long *sc_inten; /* true color plane */ +#endif + + int sc_highres; + int sc_nscreens; +}; + +struct wsscreen_descr cgtwelve_stdscreen = { + "std", + 0, 0, /* will be filled in */ + 0, + 0, 0, +#ifdef CG12_MONO + WSSCREEN_REVERSE +#else + WSSCREEN_REVERSE | WSSCREEN_WSCOLORS +#endif +}; + +const struct wsscreen_descr *cgtwelve_scrlist[] = { + &cgtwelve_stdscreen, +}; + +struct wsscreen_list cgtwelve_screenlist = { + sizeof(cgtwelve_scrlist) / sizeof(struct wsscreen_descr *), cgtwelve_scrlist +}; + +int cgtwelve_ioctl(void *, u_long, caddr_t, int, struct proc *); +int cgtwelve_alloc_screen(void *, const struct wsscreen_descr *, void **, + int *, int *, long *); +void cgtwelve_free_screen(void *, void *); +int cgtwelve_show_screen(void *, void *, int, void (*cb)(void *, int, int), + void *); +paddr_t cgtwelve_mmap(void *, off_t, int); +void cgtwelve_reset(struct cgtwelve_softc *); +#ifndef CG12_MONO +void cgtwelve_burner(void *, u_int, u_int); +void cgtwelve_prom(void *); + +static __inline__ void cgtwelve_ramdac_wraddr(struct cgtwelve_softc *sc, + u_int32_t addr); +void cgtwelve_initcmap(struct cgtwelve_softc *); +void cgtwelve_darkcmap(struct cgtwelve_softc *); +#endif + +struct wsdisplay_accessops cgtwelve_accessops = { + cgtwelve_ioctl, + cgtwelve_mmap, + cgtwelve_alloc_screen, + cgtwelve_free_screen, + cgtwelve_show_screen, +#ifndef CG12_MONO + NULL, /* load_font */ + NULL, /* scrollback */ + NULL, /* getchar */ + cgtwelve_burner, +#endif +}; + +int cgtwelvematch(struct device *, void *, void *); +void cgtwelveattach(struct device *, struct device *, void *); + +struct cfattach cgtwelve_ca = { + sizeof(struct cgtwelve_softc), cgtwelvematch, cgtwelveattach +}; + +struct cfdriver cgtwelve_cd = { + NULL, "cgtwelve", DV_DULL +}; + + +/* + * Match a cgtwelve. + */ +int +cgtwelvematch(parent, vcf, aux) + struct device *parent; + void *vcf, *aux; +{ + struct cfdata *cf = vcf; + struct confargs *ca = aux; + struct romaux *ra = &ca->ca_ra; + + /* + * Mask out invalid flags from the user. + */ + cf->cf_flags &= FB_USERMASK; + + if (strcmp(cf->cf_driver->cd_name, ra->ra_name)) + return (0); + + if (ca->ca_bustype == BUS_SBUS) + return (1); + + return (0); +} + +/* + * Attach a display. + */ +void +cgtwelveattach(parent, self, args) + struct device *parent, *self; + void *args; +{ + struct cgtwelve_softc *sc = (struct cgtwelve_softc *)self; + struct confargs *ca = args; + struct wsemuldisplaydev_attach_args waa; + int node; + int isconsole = 0; + char *ps; + + sc->sc_sunfb.sf_flags = self->dv_cfdata->cf_flags; + node = ca->ca_ra.ra_node; + + printf(": %s", getpropstring(node, "model")); + ps = getpropstring(node, "dev_id"); + if (*ps != '\0') + printf(" (%s)", ps); + printf("\n"); + + isconsole = node == fbnode; + + sc->sc_phys = ca->ca_ra.ra_reg[0]; + + /* + * Map registers + */ + sc->sc_dpu = (struct cgtwelve_dpu *)mapiodev(ca->ca_ra.ra_reg, + CG12_OFF_DPU, sizeof(struct cgtwelve_dpu)); + sc->sc_apu = (struct cgtwelve_apu *)mapiodev(ca->ca_ra.ra_reg, + CG12_OFF_APU, sizeof(struct cgtwelve_apu)); + sc->sc_ramdac = (struct cgtwelve_dac *)mapiodev(ca->ca_ra.ra_reg, + CG12_OFF_DAC, sizeof(struct cgtwelve_dac)); + + /* + * Compute framebuffer size + */ +#ifdef CG12_MONO + fb_setsize(&sc->sc_sunfb, 1, CG12_WIDTH, CG12_HEIGHT, + node, ca->ca_bustype); + + /* the prom will report depth == 32, so compensate */ + sc->sc_sunfb.sf_depth = 1; + sc->sc_sunfb.sf_linebytes = sc->sc_sunfb.sf_width / 8; + sc->sc_sunfb.sf_fbsize = sc->sc_sunfb.sf_height * + sc->sc_sunfb.sf_linebytes; +#else + fb_setsize(&sc->sc_sunfb, 32, CG12_WIDTH, CG12_HEIGHT, + node, ca->ca_bustype); +#endif + + sc->sc_highres = sc->sc_sunfb.sf_width == CG12_WIDTH_HR; + + /* + * Map planes + */ + sc->sc_overlay = mapiodev(ca->ca_ra.ra_reg, + sc->sc_highres ? CG12_OFF_OVERLAY0_HR : CG12_OFF_OVERLAY0, + round_page(sc->sc_highres ? CG12_SIZE_OVERLAY_HR : + CG12_SIZE_OVERLAY)); +#ifndef CG12_MONO + sc->sc_inten = mapiodev(ca->ca_ra.ra_reg, + sc->sc_highres ? CG12_OFF_INTEN_HR : CG12_OFF_INTEN, + round_page(sc->sc_highres ? CG12_SIZE_COLOR24_HR : + CG12_SIZE_COLOR24)); +#endif + + /* reset cursor & frame buffer controls */ + cgtwelve_reset(sc); + +#ifndef CG12_MONO + /* enable video */ + cgtwelve_burner(sc, 1, 0); +#endif + +#ifdef CG12_MONO + sc->sc_sunfb.sf_ro.ri_bits = (void *)sc->sc_overlay; +#else + sc->sc_sunfb.sf_ro.ri_bits = (void *)sc->sc_inten; +#endif + sc->sc_sunfb.sf_ro.ri_hw = sc; + fbwscons_init(&sc->sc_sunfb, isconsole); + + cgtwelve_stdscreen.nrows = sc->sc_sunfb.sf_ro.ri_rows; + cgtwelve_stdscreen.ncols = sc->sc_sunfb.sf_ro.ri_cols; + cgtwelve_stdscreen.textops = &sc->sc_sunfb.sf_ro.ri_ops; + + if (isconsole) { +#ifdef CG12_MONO + fbwscons_console_init(&sc->sc_sunfb, &cgtwelve_stdscreen, -1, + NULL, NULL); +#else + /* + * Since the screen has been cleared, restart at the top + * of the screen. + */ + fbwscons_console_init(&sc->sc_sunfb, &cgtwelve_stdscreen, 0, + NULL, cgtwelve_burner); +#endif + } + + sbus_establish(&sc->sc_sd, &sc->sc_sunfb.sf_dev); + + printf("%s: %dx%d", self->dv_xname, + sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height); + ps = getpropstring(node, "ucoderev"); + if (*ps != '\0') + printf(", microcode rev. %s", ps); + printf("\n"); + + waa.console = isconsole; + waa.scrdata = &cgtwelve_screenlist; + waa.accessops = &cgtwelve_accessops; + waa.accesscookie = sc; + config_found(self, &waa, wsemuldisplaydevprint); +} + +int +cgtwelve_ioctl(dev, cmd, data, flags, p) + void *dev; + u_long cmd; + caddr_t data; + int flags; + struct proc *p; +{ + struct cgtwelve_softc *sc = dev; + struct wsdisplay_fbinfo *wdf; + + switch (cmd) { + case WSDISPLAYIO_GTYPE: +#ifdef CG12_MONO + *(u_int *)data = WSDISPLAY_TYPE_SUNBW; +#else + *(u_int *)data = WSDISPLAY_TYPE_SUN24; +#endif + break; + case WSDISPLAYIO_GINFO: + wdf = (struct wsdisplay_fbinfo *)data; + wdf->height = sc->sc_sunfb.sf_height; + wdf->width = sc->sc_sunfb.sf_width; + wdf->depth = sc->sc_sunfb.sf_depth; + wdf->cmsize = 0; + break; + case WSDISPLAYIO_LINEBYTES: + *(u_int *)data = sc->sc_sunfb.sf_linebytes; + break; + + case WSDISPLAYIO_GETCMAP: + case WSDISPLAYIO_PUTCMAP: + break; + + case WSDISPLAYIO_SVIDEO: + case WSDISPLAYIO_GVIDEO: + case WSDISPLAYIO_GCURPOS: + case WSDISPLAYIO_SCURPOS: + case WSDISPLAYIO_GCURMAX: + case WSDISPLAYIO_GCURSOR: + case WSDISPLAYIO_SCURSOR: + default: + return (-1); /* not supported yet */ + } + + return (0); +} + +/* + * Clean up hardware state (e.g., after bootup or after X crashes). + */ +void +cgtwelve_reset(sc) + struct cgtwelve_softc *sc; +{ +#ifndef CG12_MONO + /* + * Select the overlay plane as sc_overlay. + */ + sc->sc_apu->hpage = + sc->sc_highres ? CG12_HPAGE_OVERLAY_HR : CG12_HPAGE_OVERLAY; + sc->sc_apu->haccess = CG12_HACCESS_OVERLAY; + sc->sc_dpu->pln_sl_host = CG12_PLN_SL_OVERLAY; + sc->sc_dpu->pln_rd_msk_host = CG12_PLN_RD_OVERLAY; + sc->sc_dpu->pln_wr_msk_host = CG12_PLN_WR_OVERLAY; + + /* + * Do not attempt to somewhat preserve screen contents - reading the + * overlay plane and writing to the color plane at the same time is not + * reliable, and allocating memory to save a copy of the overlay plane + * would be awful. + */ + bzero((void *)sc->sc_overlay, + sc->sc_highres ? CG12_SIZE_OVERLAY_HR : CG12_SIZE_OVERLAY); + + /* + * Select the enable plane as sc_overlay, and clear it. + */ + sc->sc_apu->hpage = + sc->sc_highres ? CG12_HPAGE_ENABLE_HR : CG12_HPAGE_ENABLE; + sc->sc_apu->haccess = CG12_HACCESS_ENABLE; + sc->sc_dpu->pln_sl_host = CG12_PLN_SL_ENABLE; + sc->sc_dpu->pln_rd_msk_host = CG12_PLN_RD_ENABLE; + sc->sc_dpu->pln_wr_msk_host = CG12_PLN_WR_ENABLE; + + bzero((void *)sc->sc_overlay, + sc->sc_highres ? CG12_SIZE_ENABLE_HR : CG12_SIZE_ENABLE); + + /* + * Select the intensity (color) plane, and clear it. + */ + sc->sc_apu->hpage = + sc->sc_highres ? CG12_HPAGE_24BIT_HR : CG12_HPAGE_24BIT; + sc->sc_apu->haccess = CG12_HACCESS_24BIT; + sc->sc_dpu->pln_sl_host = CG12_PLN_SL_24BIT; + sc->sc_dpu->pln_rd_msk_host = CG12_PLN_RD_24BIT; + sc->sc_dpu->pln_wr_msk_host = CG12_PLN_WR_24BIT; + + memset((void *)sc->sc_inten, 0x00ffffff, + sc->sc_highres ? CG12_SIZE_COLOR24_HR : CG12_SIZE_COLOR24); + + shutdownhook_establish(cgtwelve_prom, sc); +#endif +} + +/* + * Return the address that would map the given device at the given + * offset, allowing for the given protection, or return -1 for error. + */ +paddr_t +cgtwelve_mmap(v, offset, prot) + void *v; + off_t offset; + int prot; +{ + struct cgtwelve_softc *sc = v; + + if (offset & PGOFSET) + return (-1); + + /* Allow mapping as a dumb framebuffer from offset 0 */ + if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize) { +#ifdef CG12_MONO + return (REG2PHYS(&sc->sc_phys, + (sc->sc_highres ? CG12_OFF_OVERLAY0_HR : + CG12_OFF_OVERLAY0) + offset) | PMAP_NC); +#else + return (REG2PHYS(&sc->sc_phys, + (sc->sc_highres ? CG12_OFF_INTEN_HR : + CG12_OFF_INTEN) + offset) | PMAP_NC); +#endif + } + + return (-1); /* not a user-map offset */ +} + +int +cgtwelve_alloc_screen(v, type, cookiep, curxp, curyp, attrp) + void *v; + const struct wsscreen_descr *type; + void **cookiep; + int *curxp, *curyp; + long *attrp; +{ + struct cgtwelve_softc *sc = v; + + if (sc->sc_nscreens > 0) + return (ENOMEM); + + *cookiep = &sc->sc_sunfb.sf_ro; + *curyp = 0; + *curxp = 0; + sc->sc_sunfb.sf_ro.ri_ops.alloc_attr(&sc->sc_sunfb.sf_ro, + 0, 0, 0, attrp); + sc->sc_nscreens++; + return (0); +} + +void +cgtwelve_free_screen(v, cookie) + void *v; + void *cookie; +{ + struct cgtwelve_softc *sc = v; + + sc->sc_nscreens--; +} + +int +cgtwelve_show_screen(v, cookie, waitok, cb, cbarg) + void *v; + void *cookie; + int waitok; + void (*cb)(void *, int, int); + void *cbarg; +{ + return (0); +} + +#ifndef CG12_MONO +/* + * Simple Bt462 programming routines. + */ + +static __inline__ void +cgtwelve_ramdac_wraddr(struct cgtwelve_softc *sc, u_int32_t addr) +{ + sc->sc_ramdac->addr_lo = (addr & 0xff); + sc->sc_ramdac->addr_hi = ((addr >> 8) & 0xff); +} + +void +cgtwelve_initcmap(sc) + struct cgtwelve_softc *sc; +{ + u_int32_t c; + + /* + * Since we are using the framebuffer in true color mode, there is + * theoretically no ramdac initialisation to do. + * In practice, we have to load a ramp on each ramdac first. + * Fortunately they are latched on each other at this point, so by + * loading one single ramp, all of them get initialized. + */ + cgtwelve_ramdac_wraddr(sc, 0); + for (c = 0; c < 256; c++) + sc->sc_ramdac->color = c | (c << 8) | (c << 16); +} + +void +cgtwelve_darkcmap(sc) + struct cgtwelve_softc *sc; +{ + u_int32_t c; + + cgtwelve_ramdac_wraddr(sc, 0); + for (c = 0; c < 256; c++) + sc->sc_ramdac->color = 0; +} + +void cgtwelve_burner(v, on, flags) + void *v; + u_int on, flags; +{ + struct cgtwelve_softc *sc = v; + + if (on) + cgtwelve_initcmap(sc); + else + cgtwelve_darkcmap(sc); +} + +/* + * Shutdown hook used to restore PROM-compatible video mode on shutdown, + * so that the PROM prompt is visible again. + */ +void +cgtwelve_prom(v) + void *v; +{ + struct cgtwelve_softc *sc = v; + int c; + extern struct consdev consdev_prom; + + /* + * Select the overlay plane. + */ + sc->sc_apu->hpage = + sc->sc_highres ? CG12_HPAGE_OVERLAY_HR : CG12_HPAGE_OVERLAY; + sc->sc_apu->haccess = CG12_HACCESS_OVERLAY; + sc->sc_dpu->pln_sl_host = CG12_PLN_SL_OVERLAY; + sc->sc_dpu->pln_rd_msk_host = CG12_PLN_RD_OVERLAY; + sc->sc_dpu->pln_wr_msk_host = CG12_PLN_WR_OVERLAY; + + /* + * Do not touch enable and intensity planes, so that kernel + * messages can still be read when back to the prom. + * However, we need to fix the colormap, or the prompt will come + * back as white on white. + */ + cgtwelve_ramdac_wraddr(sc, 0); + sc->sc_ramdac->color = 0x00ffffff; + for (c = 1; c < 256; c++) + sc->sc_ramdac->color = 0x00000000; + + /* + * Go back to prom output for the last few messages, so they + * will be displayed correctly. + */ + cn_tab = &consdev_prom; +} +#endif diff --git a/sys/arch/sparc/dev/cgtwelvereg.h b/sys/arch/sparc/dev/cgtwelvereg.h new file mode 100644 index 00000000000..743da2b149c --- /dev/null +++ b/sys/arch/sparc/dev/cgtwelvereg.h @@ -0,0 +1,213 @@ +/* $OpenBSD: cgtwelvereg.h,v 1.1 2002/08/12 10:44:03 miod Exp $ */ + +/* + * Copyright (c) 2002 Miodrag Vallat. 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. + */ + +/* + * cgtwelve (GS) accelerated 24-bit framebuffer driver. + * + * Memory layout and scarce register information from SMI's cg12reg.h + */ + +#define CG12_HEIGHT 900 +#define CG12_WIDTH 1152 + +#define CG12_HEIGHT_HR 1024 +#define CG12_WIDTH_HR 1280 + +/* offsets from the card mapping */ +#define CG12_OFF_DPU 0x040100 +#define CG12_OFF_APU 0x040200 +#define CG12_OFF_DAC 0x040300 +#define CG12_OFF_OVERLAY0 0x700000 +#define CG12_OFF_OVERLAY1 0x780000 +#define CG12_OFF_INTEN 0xc00000 + +#define CG12_OFF_OVERLAY0_HR 0xe00000 +#define CG12_OFF_OVERLAY1_HR 0xf00000 +#define CG12_OFF_INTEN_HR 0x800000 + +/* sizes of various parts */ +#define CG12_SIZE_DPU 0x000100 +#define CG12_SIZE_APU 0x000100 +#define CG12_SIZE_DAC 0x000400 +#define CG12_SIZE_OVERLAY 0x020000 +#define CG12_SIZE_ENABLE 0x020000 +#define CG12_SIZE_COLOR8 0x100000 +#define CG12_SIZE_COLOR24 0x400000 + +#define CG12_SIZE_OVERLAY_HR 0x030000 +#define CG12_SIZE_ENABLE_HR 0x030000 +#define CG12_SIZE_COLOR8_HR 0x180000 +#define CG12_SIZE_COLOR24_HR 0x600000 + +/* + * The "direct port access" register constants. + * All HACCESSS values include noHSTXY, noHCLIP, and SWAP. + */ + +#define CG12_HPAGE_OVERLAY 0x00000700 /* overlay page */ +#define CG12_HPAGE_OVERLAY_HR 0x00000e00 +#define CG12_HACCESS_OVERLAY 0x00000020 /* 1bit/pixel */ +#define CG12_PLN_SL_OVERLAY 0x00000017 /* plane 23 */ +#define CG12_PLN_WR_OVERLAY 0x00800000 /* write mask */ +#define CG12_PLN_RD_OVERLAY 0xffffffff /* read mask */ + +#define CG12_HPAGE_ENABLE 0x00000700 /* overlay page */ +#define CG12_HPAGE_ENABLE_HR 0x00000e00 +#define CG12_HACCESS_ENABLE 0x00000020 /* 1bit/pixel */ +#define CG12_PLN_SL_ENABLE 0x00000016 /* plane 22 */ +#define CG12_PLN_WR_ENABLE 0x00400000 +#define CG12_PLN_RD_ENABLE 0xffffffff + +#define CG12_HPAGE_24BIT 0x00000500 /* intensity page */ +#define CG12_HPAGE_24BIT_HR 0x00000a00 +#define CG12_HACCESS_24BIT 0x00000025 /* 32bits/pixel */ +#define CG12_PLN_SL_24BIT 0x00000000 /* planes 0-31 */ +#define CG12_PLN_WR_24BIT 0x00ffffff +#define CG12_PLN_RD_24BIT 0x00ffffff + +#define CG12_HPAGE_8BIT 0x00000500 /* intensity page */ +#define CG12_HPAGE_8BIT_HR 0x00000a00 +#define CG12_HACCESS_8BIT 0x00000023 /* 8bits/pixel */ +#define CG12_PLN_SL_8BIT 0x00000000 /* planes 0-7 */ +#define CG12_PLN_WR_8BIT 0x00ffffff +#define CG12_PLN_RD_8BIT 0x000000ff + +#define CG12_HPAGE_WID 0x00000700 /* overlay page */ +#define CG12_HPAGE_WID_HR 0x00000e00 +#define CG12_HACCESS_WID 0x00000023 /* 8bits/pixel */ +#define CG12_PLN_SL_WID 0x00000010 /* planes 16-23 */ +#define CG12_PLN_WR_WID 0x003f0000 +#define CG12_PLN_RD_WID 0x003f0000 + +#define CG12_HPAGE_ZBUF 0x00000000 /* depth page */ +#define CG12_HPAGE_ZBUF_HR 0x00000000 +#define CG12_HACCESS_ZBUF 0x00000024 /* 16bits/pixel */ +#define CG12_PLN_SL_ZBUF 0x00000060 +#define CG12_PLN_WR_ZBUF 0xffffffff +#define CG12_PLN_RD_ZBUF 0xffffffff + +/* Direct Port Unit */ +struct cgtwelve_dpu { + u_int32_t r[8]; + u_int32_t reload_ctl; + u_int32_t reload_stb; + u_int32_t alu_ctl; + u_int32_t blu_ctl; + u_int32_t control; + u_int32_t xleft; + u_int32_t shift0; + u_int32_t shift1; + u_int32_t zoom; + u_int32_t bsr; + u_int32_t color0; + u_int32_t color1; + u_int32_t compout; + u_int32_t pln_rd_msk_host; + u_int32_t pln_wr_msk_host; + u_int32_t pln_rd_msk_local; + u_int32_t pln_wr_msk_local; + u_int32_t scis_ctl; + u_int32_t csr; + u_int32_t pln_reg_sl; + u_int32_t pln_sl_host; + u_int32_t pln_sl_local0; + u_int32_t pln_sl_local1; + u_int32_t broadcast; +}; + +/* APU */ +struct cgtwelve_apu { + u_int32_t imsg0; + u_int32_t msg0; + u_int32_t imsg1; + u_int32_t msg1; + u_int32_t ien0; + u_int32_t ien1; + u_int32_t iclear; + u_int32_t istatus; + u_int32_t cfcnt; + u_int32_t cfwptr; + u_int32_t cfrptr; + u_int32_t cfilev0; + u_int32_t cfilev1; + u_int32_t rfcnt; + u_int32_t rfwptr; + u_int32_t rfrptr; + u_int32_t rfilev0; + u_int32_t rfilev1; + u_int32_t size; + u_int32_t res0; + u_int32_t res1; + u_int32_t res2; + u_int32_t haccess; + u_int32_t hpage; + u_int32_t laccess; + u_int32_t lpage; + u_int32_t maccess; + u_int32_t ppage; + u_int32_t dwg_ctl; + u_int32_t sam; + u_int32_t sgn; + u_int32_t length; + u_int32_t dwg[8]; + u_int32_t reload_ctl; + u_int32_t reload_stb; + u_int32_t c_xleft; + u_int32_t c_ytop; + u_int32_t c_xright; + u_int32_t c_ybot; + u_int32_t f_xleft; + u_int32_t f_xright; + u_int32_t x_dst; + u_int32_t y_dst; + u_int32_t dst_ctl; + u_int32_t morigin; + u_int32_t vsg_ctl; + u_int32_t h_sync; + u_int32_t hblank; + u_int32_t v_sync; + u_int32_t vblank; + u_int32_t vdpyint; + u_int32_t vssyncs; + u_int32_t hdelays; + u_int32_t stdaddr; + u_int32_t hpitches; + u_int32_t zoom; + u_int32_t test; +}; + +struct cgtwelve_dac +{ + u_int32_t addr_lo; + u_int8_t pad1[0x100 - 4]; + u_int32_t addr_hi; + u_int8_t pad2[0x100 - 4]; + u_int32_t control; + u_int8_t pad3[0x100 - 4]; + u_int32_t color; + u_int8_t pad4[0x100 - 4]; +}; diff --git a/sys/arch/sparc/dev/cgtwo.c b/sys/arch/sparc/dev/cgtwo.c index 2204e78e2db..904a7189c24 100644 --- a/sys/arch/sparc/dev/cgtwo.c +++ b/sys/arch/sparc/dev/cgtwo.c @@ -1,7 +1,31 @@ -/* $OpenBSD: cgtwo.c,v 1.21 2002/08/02 16:13:07 millert Exp $ */ +/* $OpenBSD: cgtwo.c,v 1.22 2002/08/12 10:44:03 miod Exp $ */ /* $NetBSD: cgtwo.c,v 1.22 1997/05/24 20:16:12 pk Exp $ */ /* + * Copyright (c) 2002 Miodrag Vallat. 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. + * + * * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * @@ -65,36 +89,76 @@ #include <uvm/uvm_extern.h> -#include <machine/fbio.h> #include <machine/autoconf.h> #include <machine/pmap.h> -#include <machine/fbvar.h> #if defined(SUN4) #include <machine/eeprom.h> #endif #include <machine/conf.h> -#include <machine/cgtworeg.h> + +#include <sparc/dev/cgtworeg.h> + +#include <dev/wscons/wsconsio.h> +#include <dev/wscons/wsdisplayvar.h> +#include <dev/wscons/wscons_raster.h> +#include <dev/rasops/rasops.h> +#include <machine/fbvar.h> /* per-display variables */ struct cgtwo_softc { - struct device sc_dev; /* base device */ - struct fbdevice sc_fb; /* frame buffer device */ - struct rom_reg sc_phys; /* display RAM (phys addr) */ - int sc_bustype; /* type of bus we live on */ + struct sunfb sc_sunfb; /* common base part */ + struct rom_reg sc_phys; /* display RAM (phys addr) */ volatile struct cg2statusreg *sc_reg; /* CG2 control registers */ volatile u_short *sc_cmap; -#define sc_redmap(sc) ((sc)->sc_cmap) -#define sc_greenmap(sc) ((sc)->sc_cmap + CG2_CMSIZE) -#define sc_bluemap(sc) ((sc)->sc_cmap + 2 * CG2_CMSIZE) +#define sc_redmap(cmap) ((u_short *)(cmap)) +#define sc_greenmap(cmap) ((u_short *)(cmap) + CG2_CMSIZE) +#define sc_bluemap(cmap) ((u_short *)(cmap) + 2 * CG2_CMSIZE) + int sc_nscreens; +}; + +struct wsscreen_descr cgtwo_stdscreen = { + "std", + 0, 0, /* will be filled in */ + 0, + 0, 0, + WSSCREEN_REVERSE | WSSCREEN_WSCOLORS +}; + +const struct wsscreen_descr *cgtwo_scrlist[] = { + &cgtwo_stdscreen, +}; + +struct wsscreen_list cgtwo_screenlist = { + sizeof(cgtwo_scrlist) / sizeof(struct wsscreen_descr *), + cgtwo_scrlist }; -/* autoconfiguration driver */ -static void cgtwoattach(struct device *, struct device *, void *); -static int cgtwomatch(struct device *, void *, void *); -static void cgtwounblank(struct device *); -int cgtwogetcmap(struct cgtwo_softc *, struct fbcmap *); -int cgtwoputcmap(struct cgtwo_softc *, struct fbcmap *); +int cgtwo_ioctl(void *, u_long, caddr_t, int, struct proc *); +int cgtwo_alloc_screen(void *, const struct wsscreen_descr *, void **, + int *, int *, long *); +void cgtwo_free_screen(void *, void *); +int cgtwo_show_screen(void *, void *, int, void (*)(void *, int, int), void *); +paddr_t cgtwo_mmap(void *, off_t, int); +int cgtwo_putcmap(volatile u_short *, struct wsdisplay_cmap *); +int cgtwo_getcmap(volatile u_short *, struct wsdisplay_cmap *); +void cgtwo_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t); +void cgtwo_burner(void *, u_int, u_int); + +struct wsdisplay_accessops cgtwo_accessops = { + cgtwo_ioctl, + cgtwo_mmap, + cgtwo_alloc_screen, + cgtwo_free_screen, + cgtwo_show_screen, + NULL, /* load_font */ + NULL, /* scrollback */ + NULL, /* getchar */ + cgtwo_burner, +}; + +int cgtwomatch(struct device *, void *, void *); +void cgtwoattach(struct device *, struct device *, void *); struct cfattach cgtwo_ca = { sizeof(struct cgtwo_softc), cgtwomatch, cgtwoattach @@ -104,14 +168,6 @@ struct cfdriver cgtwo_cd = { NULL, "cgtwo", DV_DULL }; -/* frame buffer generic driver */ -static struct fbdriver cgtwofbdriver = { - cgtwounblank, cgtwoopen, cgtwoclose, cgtwoioctl, cgtwommap -}; - -extern int fbnode; -extern struct tty *fbconstty; - /* * Match a cgtwo. */ @@ -123,52 +179,44 @@ cgtwomatch(parent, vcf, aux) struct cfdata *cf = vcf; struct confargs *ca = aux; struct romaux *ra = &ca->ca_ra; -#if defined(SUN4) caddr_t tmp; -#endif /* * Mask out invalid flags from the user. */ cf->cf_flags &= FB_USERMASK; - if (ca->ca_bustype != BUS_VME16) - return (0); - if (strcmp(cf->cf_driver->cd_name, ra->ra_name)) return (0); -#if defined(SUN4) - if (!CPU_ISSUN4 || cf->cf_unit != 0) + if (!CPU_ISSUN4 || ca->ca_bustype != BUS_VME16) return (0); /* XXX - Must do our own mapping at CG2_CTLREG_OFF */ bus_untmp(); tmp = (caddr_t)mapdev(ra->ra_reg, TMPMAP_VA, CG2_CTLREG_OFF, NBPG); if (probeget(tmp, 2) != -1) - return 1; -#endif - return 0; + return (1); + + return (0); } /* - * Attach a display. We need to notice if it is the console, too. + * Attach a display. */ void cgtwoattach(parent, self, args) struct device *parent, *self; void *args; { - register struct cgtwo_softc *sc = (struct cgtwo_softc *)self; - register struct confargs *ca = args; - register int node = 0; + struct cgtwo_softc *sc = (struct cgtwo_softc *)self; + struct confargs *ca = args; + struct wsemuldisplaydev_attach_args waa; + int node = 0; int isconsole = 0; char *nam = NULL; - sc->sc_fb.fb_driver = &cgtwofbdriver; - sc->sc_fb.fb_device = &sc->sc_dev; - sc->sc_fb.fb_type.fb_type = FBTYPE_SUN2COLOR; - sc->sc_fb.fb_flags = sc->sc_dev.dv_cfdata->cf_flags; + sc->sc_sunfb.sf_flags = self->dv_cfdata->cf_flags; switch (ca->ca_bustype) { case BUS_VME16: @@ -181,22 +229,8 @@ cgtwoattach(parent, self, args) /* NOTREACHED */ } - sc->sc_fb.fb_type.fb_depth = 8; - fb_setsize(&sc->sc_fb, sc->sc_fb.fb_type.fb_depth, - 1152, 900, node, ca->ca_bustype); + printf(": %s", nam); - sc->sc_fb.fb_type.fb_cmsize = 256; - sc->sc_fb.fb_type.fb_size = round_page(CG2_MAPPED_SIZE); - printf(": %s, %d x %d", nam, - sc->sc_fb.fb_type.fb_width, sc->sc_fb.fb_type.fb_height); - - /* - * When the ROM has mapped in a cgtwo display, the address - * maps only the video RAM, so in any case we have to map the - * registers ourselves. We only need the video RAM if we are - * going to print characters via rconsole. - */ -#if defined(SUN4) if (CPU_ISSUN4) { struct eeprom *eep = (struct eeprom *)eeprom_va; /* @@ -204,21 +238,17 @@ cgtwoattach(parent, self, args) * to be found. */ if (eep == NULL || eep->eeConsole == EE_CONS_COLOR) - isconsole = (fbconstty != NULL); - else - isconsole = 0; + isconsole = 1; } -#endif + + /* + * When the ROM has mapped in a cgtwo display, the address + * maps only the video RAM, so in any case we have to map the + * registers ourselves. + */ sc->sc_phys = ca->ca_ra.ra_reg[0]; /* Apparently, the pixels are 32-bit data space */ sc->sc_phys.rr_iospace = PMAP_VME32; - sc->sc_bustype = ca->ca_bustype; - - if ((sc->sc_fb.fb_pixels = ca->ca_ra.ra_vaddr) == NULL && isconsole) { - /* this probably cannot happen, but what the heck */ - sc->sc_fb.fb_pixels = mapiodev(&sc->sc_phys, CG2_PIXMAP_OFF, - CG2_PIXMAP_SIZE); - } sc->sc_reg = (volatile struct cg2statusreg *) mapiodev(ca->ca_ra.ra_reg, @@ -230,206 +260,265 @@ cgtwoattach(parent, self, args) CG2_ROPMEM_OFF + offsetof(struct cg2fb, redmap[0]), 3 * CG2_CMSIZE); + /* enable video */ + cgtwo_burner(sc, 1, 0); + + fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, ca->ca_bustype); + sc->sc_sunfb.sf_ro.ri_bits = mapiodev(&sc->sc_phys, CG2_PIXMAP_OFF, + round_page(sc->sc_sunfb.sf_fbsize)); + sc->sc_sunfb.sf_ro.ri_hw = sc; + fbwscons_init(&sc->sc_sunfb, isconsole); + + cgtwo_stdscreen.nrows = sc->sc_sunfb.sf_ro.ri_rows; + cgtwo_stdscreen.ncols = sc->sc_sunfb.sf_ro.ri_cols; + cgtwo_stdscreen.textops = &sc->sc_sunfb.sf_ro.ri_ops; + + printf(", %dx%d\n", sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height); + if (isconsole) { - printf(" (console)\n"); -#ifdef RASTERCONSOLE - fbrcons_init(&sc->sc_fb); -#endif - } else - printf("\n"); + fbwscons_console_init(&sc->sc_sunfb, &cgtwo_stdscreen, -1, + cgtwo_setcolor, cgtwo_burner); + } - if (node == fbnode || CPU_ISSUN4) - fb_attach(&sc->sc_fb, isconsole); + waa.console = isconsole; + waa.scrdata = &cgtwo_screenlist; + waa.accessops = &cgtwo_accessops; + waa.accesscookie = sc; + config_found(self, &waa, wsemuldisplaydevprint); } int -cgtwoopen(dev, flags, mode, p) - dev_t dev; - int flags, mode; +cgtwo_ioctl(v, cmd, data, flags, p) + void *v; + u_long cmd; + caddr_t data; + int flags; struct proc *p; { - int unit = minor(dev); + struct cgtwo_softc *sc = v; + struct wsdisplay_fbinfo *wdf; + struct wsdisplay_cmap *cm; + int error; - if (unit >= cgtwo_cd.cd_ndevs || cgtwo_cd.cd_devs[unit] == NULL) - return (ENXIO); - return (0); -} + switch (cmd) { + case WSDISPLAYIO_GTYPE: + *(u_int *)data = WSDISPLAY_TYPE_UNKNOWN; + break; + case WSDISPLAYIO_GINFO: + wdf = (struct wsdisplay_fbinfo *)data; + wdf->height = sc->sc_sunfb.sf_height; + wdf->width = sc->sc_sunfb.sf_width; + wdf->depth = sc->sc_sunfb.sf_depth; + wdf->cmsize = CG2_CMSIZE; + break; + case WSDISPLAYIO_LINEBYTES: + *(u_int *)data = sc->sc_sunfb.sf_linebytes; + break; + + case WSDISPLAYIO_GETCMAP: + cm = (struct wsdisplay_cmap *)data; + error = cgtwo_getcmap(sc->sc_cmap, cm); + if (error) + return (error); + break; -int -cgtwoclose(dev, flags, mode, p) - dev_t dev; - int flags, mode; - struct proc *p; -{ + case WSDISPLAYIO_PUTCMAP: + cm = (struct wsdisplay_cmap *)data; + error = cgtwo_putcmap(sc->sc_cmap, cm); + if (error) + return (error); + break; + + case WSDISPLAYIO_SVIDEO: + case WSDISPLAYIO_GVIDEO: + case WSDISPLAYIO_GCURPOS: + case WSDISPLAYIO_SCURPOS: + case WSDISPLAYIO_GCURMAX: + case WSDISPLAYIO_GCURSOR: + case WSDISPLAYIO_SCURSOR: + default: + return (-1); /* not supported yet */ + } return (0); } int -cgtwoioctl(dev, cmd, data, flags, p) - dev_t dev; - u_long cmd; - register caddr_t data; - int flags; - struct proc *p; +cgtwo_alloc_screen(v, type, cookiep, curxp, curyp, attrp) + void *v; + const struct wsscreen_descr *type; + void **cookiep; + int *curxp, *curyp; + long *attrp; { - register struct cgtwo_softc *sc = cgtwo_cd.cd_devs[minor(dev)]; - register struct fbgattr *fba; + struct cgtwo_softc *sc = v; - switch (cmd) { + if (sc->sc_nscreens > 0) + return (ENOMEM); - case FBIOGTYPE: - *(struct fbtype *)data = sc->sc_fb.fb_type; - break; + *cookiep = &sc->sc_sunfb.sf_ro; + *curyp = 0; + *curxp = 0; + sc->sc_sunfb.sf_ro.ri_ops.alloc_attr(&sc->sc_sunfb.sf_ro, + WSCOL_BLACK, WSCOL_WHITE, WSATTR_WSCOLORS, attrp); + sc->sc_nscreens++; + return (0); +} - case FBIOGATTR: - fba = (struct fbgattr *)data; - fba->real_type = sc->sc_fb.fb_type.fb_type; - fba->owner = 0; /* XXX ??? */ - fba->fbtype = sc->sc_fb.fb_type; - fba->sattr.flags = 0; - fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type; - fba->sattr.dev_specific[0] = -1; - fba->emu_types[0] = sc->sc_fb.fb_type.fb_type; - fba->emu_types[1] = -1; - break; +void +cgtwo_free_screen(v, cookie) + void *v; + void *cookie; +{ + struct cgtwo_softc *sc = v; - case FBIOGETCMAP: - return cgtwogetcmap(sc, (struct fbcmap *) data); + sc->sc_nscreens--; +} - case FBIOPUTCMAP: - return cgtwoputcmap(sc, (struct fbcmap *) data); +int +cgtwo_show_screen(v, cookie, waitok, cb, cbarg) + void *v; + void *cookie; + int waitok; + void (*cb)(void *, int, int); + void *cbarg; +{ + return (0); +} - case FBIOGVIDEO: - *(int *)data = sc->sc_reg->video_enab; - break; +paddr_t +cgtwo_mmap(v, offset, prot) + void *v; + off_t offset; + int prot; +{ + struct cgtwo_softc *sc = v; - case FBIOSVIDEO: - sc->sc_reg->video_enab = (*(int *)data) & 1; - break; + if (offset & PGOFSET) + return (-1); - default: - return (ENOTTY); + if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize) { + return (REG2PHYS(&sc->sc_phys, + CG2_PIXMAP_OFF + offset) | PMAP_NC); } - return (0); + + return (-1); } -/* - * Undo the effect of an FBIOSVIDEO that turns the video off. - */ -static void -cgtwounblank(dev) - struct device *dev; +void +cgtwo_burner(v, on, flags) + void *v; + u_int on, flags; { - struct cgtwo_softc *sc = (struct cgtwo_softc *)dev; - sc->sc_reg->video_enab = 1; + struct cgtwo_softc *sc = v; + int s; + + s = splhigh(); + if (on) + sc->sc_reg->video_enab = 1; + else + sc->sc_reg->video_enab = 0; + splx(s); } -/* - */ int -cgtwogetcmap(sc, cmap) - register struct cgtwo_softc *sc; - register struct fbcmap *cmap; +cgtwo_getcmap(hwcmap, cmap) + volatile u_short *hwcmap; + struct wsdisplay_cmap *cmap; { + u_int index = cmap->index, count = cmap->count, i; u_char red[CG2_CMSIZE], green[CG2_CMSIZE], blue[CG2_CMSIZE]; int error; - u_int start, count, ecount; - register u_int i; - register volatile u_short *p; - - start = cmap->index; - count = cmap->count; - ecount = start + count; - if (start >= CG2_CMSIZE || count > CG2_CMSIZE - start) + volatile u_short *p; + + + if (index >= CG2_CMSIZE || count >= CG2_CMSIZE - index) return (EINVAL); /* XXX - Wait for retrace? */ /* Copy hardware to local arrays. */ - p = &sc_redmap(sc)[start]; - for (i = start; i < ecount; i++) + p = &sc_redmap(hwcmap)[index]; + for (i = 0; i < count; i++) red[i] = *p++; - p = &sc_greenmap(sc)[start]; - for (i = start; i < ecount; i++) + p = &sc_greenmap(hwcmap)[index]; + for (i = 0; i < count; i++) green[i] = *p++; - p = &sc_bluemap(sc)[start]; - for (i = start; i < ecount; i++) + p = &sc_bluemap(hwcmap)[index]; + for (i = 0; i < count; i++) blue[i] = *p++; /* Copy local arrays to user space. */ - if ((error = copyout(red + start, cmap->red, count)) != 0) + if ((error = copyout(red, cmap->red, count)) != 0) return (error); - if ((error = copyout(green + start, cmap->green, count)) != 0) + if ((error = copyout(green, cmap->green, count)) != 0) return (error); - if ((error = copyout(blue + start, cmap->blue, count)) != 0) + if ((error = copyout(blue, cmap->blue, count)) != 0) return (error); return (0); } -/* - */ int -cgtwoputcmap(sc, cmap) - register struct cgtwo_softc *sc; - register struct fbcmap *cmap; +cgtwo_putcmap(hwcmap, cmap) + volatile u_short *hwcmap; + struct wsdisplay_cmap *cmap; { + u_int index = cmap->index, count = cmap->count, i; u_char red[CG2_CMSIZE], green[CG2_CMSIZE], blue[CG2_CMSIZE]; int error; - u_int start, count, ecount; - register u_int i; - register volatile u_short *p; - - start = cmap->index; - count = cmap->count; - ecount = start + count; - if (start >= CG2_CMSIZE || count > CG2_CMSIZE - start) + volatile u_short *p; + + if (index >= CG2_CMSIZE || count >= CG2_CMSIZE - index) return (EINVAL); /* Copy from user space to local arrays. */ - if ((error = copyin(cmap->red, red + start, count)) != 0) + if ((error = copyin(cmap->red, red, count)) != 0) return (error); - if ((error = copyin(cmap->green, green + start, count)) != 0) + if ((error = copyin(cmap->green, green, count)) != 0) return (error); - if ((error = copyin(cmap->blue, blue + start, count)) != 0) + if ((error = copyin(cmap->blue, blue, count)) != 0) return (error); /* XXX - Wait for retrace? */ /* Copy from local arrays to hardware. */ - p = &sc_redmap(sc)[start]; - for (i = start; i < ecount; i++) + p = &sc_redmap(hwcmap)[index]; + for (i = 0; i < count; i++) *p++ = red[i]; - p = &sc_greenmap(sc)[start]; - for (i = start; i < ecount; i++) + p = &sc_greenmap(hwcmap)[index]; + for (i = 0; i < count; i++) *p++ = green[i]; - p = &sc_bluemap(sc)[start]; - for (i = start; i < ecount; i++) + p = &sc_bluemap(hwcmap)[index]; + for (i = 0; i < count; i++) *p++ = blue[i]; return (0); } -/* - * Return the address that would map the given device at the given - * offset, allowing for the given protection, or return -1 for error. - */ -paddr_t -cgtwommap(dev, off, prot) - dev_t dev; - off_t off; - int prot; +void +cgtwo_setcolor(v, index, r, g, b) + void *v; + u_int index; + u_int8_t r, g, b; { - register struct cgtwo_softc *sc = cgtwo_cd.cd_devs[minor(dev)]; + struct cgtwo_softc *sc = v; +#if 0 + struct wsdisplay_cmap cm; - if (off & PGOFSET) - panic("cgtwommap"); + cm.red = &r; + cm.green = &g; + cm.blue = &b; + cm.index = index; + cm.count = 1; - if (off < 0) - return (-1); - if ((unsigned)off >= sc->sc_fb.fb_type.fb_size) - return (-1); + cgtwo_putcmap(sc->sc_cmap, &cm); +#else - return (REG2PHYS(&sc->sc_phys, off) | PMAP_NC); + /* XXX - Wait for retrace? */ + + sc_redmap(sc->sc_cmap)[index] = r; + sc_greenmap(sc->sc_cmap)[index] = g; + sc_bluemap(sc->sc_cmap)[index] = b; +#endif } diff --git a/sys/arch/sparc/dev/cgtworeg.h b/sys/arch/sparc/dev/cgtworeg.h new file mode 100644 index 00000000000..430f96cf3ba --- /dev/null +++ b/sys/arch/sparc/dev/cgtworeg.h @@ -0,0 +1,267 @@ +/* $OpenBSD: cgtworeg.h,v 1.1 2002/08/12 10:44:04 miod Exp $ */ +/* $NetBSD: cgtworeg.h,v 1.3 1995/10/04 00:21:27 pk Exp $ */ + +/* + * Copyright (c) 1994 Dennis Ferguson + * 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. + */ + +/* cgtworeg.h - CG2 colour frame buffer definitions + * + * The mapped memory looks like: + * + * offset contents + * 0x000000 bit plane map - 1st (of 8) plane used by the X server in -mono mode + * 0x100000 pixel map - used by the X server in color mode + * 0x200000 raster op mode memory map - unused by X server + * 0x300000 random control registers (lots of spaces in between) + * 0x310000 shadow colour map + */ + +/* Frame buffer memory size and depth */ +#define CG2_FBSIZE (1024 * 1024) +#define CG2_N_PLANE 8 + +/* Screen dimensions */ +#define CG2_WIDTH 1152 +#define CG2_HEIGHT 900 + +/* Colourmap size */ +#define CG2_CMSIZE 256 + +#define CG2_BITPLANE_OFF 0 +#define CG2_BITPLANE_SIZE 0x100000 +#define CG2_PIXMAP_OFF (CG2_BITPLANE_OFF + CG2_BITPLANE_SIZE) +#define CG2_PIXMAP_SIZE 0x100000 +#define CG2_ROPMEM_OFF (CG2_PIXMAP_OFF + CG2_PIXMAP_SIZE) +#define CG2_ROPMEM_SIZE 0x100000 +#define CG2_CTLREG_OFF (CG2_ROPMEM_OFF + CG2_ROPMEM_SIZE) +#define CG2_CTLREG_SIZE 0x010600 +#define CG2_MAPPED_SIZE (CG2_CTLREG_OFF + CG2_CTLREG_SIZE) + + +/* arrangement of bit plane mode memory */ +union bitplane { + u_short word[CG2_HEIGHT][CG2_WIDTH/(CG2_N_PLANE * sizeof(u_short))]; + u_short plane[CG2_FBSIZE/(CG2_N_PLANE * sizeof(u_short))]; +}; + +/* arrangement of pixel mode memory */ +union byteplane { + u_char pixel[CG2_HEIGHT][CG2_WIDTH]; + u_char frame[CG2_FBSIZE]; +}; + + +/* + * Structure describing the first two megabytes of the frame buffer. + * Normal memory maps in bit plane and pixel modes + */ +struct cg2memfb { + union bitplane memplane[CG2_N_PLANE]; /* bit plane map */ + union byteplane pixplane; /* pixel map */ +}; + + +/* + * Control/status register. The X server only appears to use update_cmap + * and video_enab. + */ +struct cg2statusreg { + u_int reserved : 2; /* not used */ + u_int fastread : 1; /* r/o: has some feature I don't understand */ + u_int id : 1; /* r/o: ext status and ID registers exist */ + u_int resolution : 4; /* screen resolution, 0 means 1152x900 */ + u_int retrace : 1; /* r/o: retrace in progress */ + u_int inpend : 1; /* r/o: interrupt request */ + u_int ropmode : 3; /* ?? */ + u_int inten : 1; /* interrupt enable (for end of retrace) */ + u_int update_cmap : 1; /* copy/use shadow colour map */ + u_int video_enab : 1; /* enable video */ +}; + + +/* + * Extended status register. Unused by X server + */ +struct cg2_extstatus { + u_int gpintreq : 1; /* interrupt request */ + u_int gpintdis : 1; /* interrupt disable */ + u_int reserved : 13; /* unused */ + u_int gpbus : 1; /* bus enabled */ +}; + + +/* + * Double buffer control register. It appears that (some of?) the + * cg2 cards support a pair of memory sets, referred to as `A' and + * `B', which can be swapped to allow atomic screen updates. This + * controls them. + */ +struct dblbufreg { + u_int display_b : 1; /* display memory B (set) or A (reset) */ + u_int read_b : 1; /* accesss memory B (set) or A (reset) */ + u_int nowrite_b : 1; /* when set, writes don't update memory B */ + u_int nowrite_a : 1; /* when set, writes don't update memory A */ + u_int read_ecmap : 1; /* copy from(clear)/to(set) shadow colour map */ + u_int fast_read : 1; /* fast reads, but wrong data */ + u_int wait : 1; /* when set, remains so to end up v. retrace */ + u_int update_ecmap : 1; /* copy/use shadow colour map */ + u_int reserved : 8; +}; + + +/* + * Zoom register, apparently present on Sun-2 colour boards only. See + * the Sun documentation, I don't know anyone who still has a Sun-2. + */ +struct cg2_zoom { + union { + u_int short reg; + u_char reg_pad[4096]; + } wordpan; + union { + struct { + u_int unused : 8; + u_int lineoff : 4; + u_int pixzoom : 4; + } reg; + u_short word; + u_char reg_pad[4096]; + } zoom; + union { + struct { + u_int unused : 8; + u_int lorigin : 4; + u_int pixeloff : 4; + } reg; + u_short word; + u_char reg_pad[4096]; + } pixpan; + union { + u_short reg; + u_char reg_pad[4096]; + } varzoom; +}; + + +/* + * Miscellany. On the Sun-3 these registers exist in place of the above. + */ +struct cg2_nozoom { + union { /* double buffer register (see above) */ + struct dblbufreg reg; + u_short word; + u_char reg_pad[4096]; + } dblbuf; + union { /* start of dma window */ + u_short reg; + u_char reg_pad[4096]; + } dmabase; + union { /* dma window size */ + u_short reg; /* actually 8 bits. reg*16 == size */ + u_char reg_pad[4096]; + } dmawidth; + union { /* frame count */ + u_short reg; /* actually 8 bits only. r/o */ + u_char reg_pad[4096]; + } framecnt; +}; + + +/* + * Raster op control registers. X doesn't use this, but documented here + * for future reference. + */ +struct memropc { + u_short mrc_dest; + u_short mrc_source1; + u_short mrc_source2; + u_short mrc_pattern; + u_short mrc_mask1; + u_short mrc_mask2; + u_short mrc_shift; + u_short mrc_op; + u_short mrc_width; + u_short mrc_opcount; + u_short mrc_decoderout; + u_short mrc_x11; + u_short mrc_x12; + u_short mrc_x13; + u_short mrc_x14; + u_short mrc_x15; +}; + + +/* + * Last chunk of the frame buffer (i.e. from offset 0x200000 and above). + * Exists separately from struct cg2memfb apparently because Sun software + * avoids mapping the latter, though X uses it. + */ +struct cg2fb { + union { /* raster op mode frame memory */ + union bitplane ropplane[CG2_N_PLANE]; + union byteplane roppixel; + } ropio; + union { /* raster op control unit (1 per plane) */ + struct memropc ropregs; + struct { + u_char pad[2048]; + struct memropc ropregs; + } prime; + u_char reg_pad[4096]; + } ropcontrol[9]; + union { /* status register */ + struct cg2statusreg reg; + u_short word; + u_char reg_pad[4096]; + } status; + union { /* per-plane mask register */ + u_short reg; /* 8 bit mask register - set means plane r/w */ + u_char reg_pad[4096]; + } ppmask; + union { /* miscellaneous registers */ + struct cg2_zoom zoom; + struct cg2_nozoom nozoom; + } misc; + union { /* interrupt vector */ + u_short reg; + u_char reg_pad[32]; + } intrptvec; + union { /* board ID */ + u_short reg; + u_char reg_pad[16]; + } id; + union { /* extended status */ + struct cg2_extstatus reg; + u_short word; + u_char reg_pad[16]; + } extstatus; + union { /* auxiliary raster op mode register (?)*/ + u_short reg; + u_char reg_pad[4032]; + } ropmode; + u_short redmap[CG2_CMSIZE]; /* shadow colour maps */ + u_short greenmap[CG2_CMSIZE]; + u_short bluemap[CG2_CMSIZE]; +}; diff --git a/sys/arch/sparc/dev/cons.c b/sys/arch/sparc/dev/cons.c deleted file mode 100644 index c74a4512ff8..00000000000 --- a/sys/arch/sparc/dev/cons.c +++ /dev/null @@ -1,725 +0,0 @@ -/* $OpenBSD: cons.c,v 1.13 2002/03/14 01:26:42 millert Exp $ */ -/* $NetBSD: cons.c,v 1.30 1997/07/07 23:30:23 pk Exp $ */ - -/* - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This software was developed by the Computer Systems Engineering group - * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and - * contributed to Berkeley. - * - * 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, Lawrence Berkeley Laboratory. - * - * 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. - * - * @(#)cons.c 8.3 (Berkeley) 12/14/93 - */ - -/* - * Console (indirect) driver. - */ - -#include <sys/param.h> -#include <sys/proc.h> -#include <sys/systm.h> -#include <sys/ioctl.h> -#include <sys/tty.h> -#include <sys/file.h> -#include <sys/conf.h> -#include <sys/timeout.h> - -#include <dev/cons.h> - -#include <machine/bsd_openprom.h> -#include <machine/eeprom.h> -#include <machine/psl.h> -#include <machine/cpu.h> -#include <machine/kbd.h> -#if defined(SUN4) -#include <machine/oldmon.h> -#endif -#include <machine/autoconf.h> -#include <machine/conf.h> - -#ifdef RASTERCONSOLE -#include <machine/fbio.h> -#include <machine/fbvar.h> -#endif - -#include "zs.h" -#include "kbd.h" - -struct tty *constty = 0; /* virtual console output device */ -struct tty *fbconstty = 0; /* tty structure for frame buffer console */ -int rom_console_input; /* when set, hardclock calls cnrom() */ - -int cons_ocount; /* output byte count */ - -/* - * The output driver may munge the minor number in cons.t_dev. - */ -struct tty cons; /* rom console tty device */ -struct timeout cons_cnfbdma_tmo;/* for cnfdbma() timeouts */ -static int (*fcnstop)(struct tty *, int); - -static void cnstart(struct tty *); -int cnstop(struct tty *, int); - -static void cnfbstart(struct tty *); -static int cnfbstop(struct tty *, int); -static void cnfbdma(void *); -static struct tty *xxcntty(dev_t); - -extern char char_type[]; - -/*XXX*/ -static struct tty * -xxcntty(dev_t dev) -{ - return &cons; -} - -void -consinit() -{ - register struct tty *tp = &cons; - register int in, out; - -/*XXX*/ cdevsw[0].d_tty = xxcntty; - tp->t_dev = makedev(0, 0); /* /dev/console */ - tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED; - tp->t_param = (int (*)(struct tty *, struct termios *))nullop; - - if (promvec->pv_romvec_vers > 2) { - /* We need to probe the PROM device tree */ - register int node,fd; - char buffer[128]; - register struct nodeops *no; - register struct v2devops *op; - register char *cp; - extern int fbnode; - - in = out = -1; - no = promvec->pv_nodeops; - op = &promvec->pv_v2devops; - - node = findroot(); - if (no->no_proplen(node, "stdin-path") >= sizeof(buffer)) { - printf("consinit: increase buffer size and recompile\n"); - goto setup_output; - } - /* XXX: fix above */ - - no->no_getprop(node, "stdin-path",buffer); - - /* - * Open an "instance" of this device. - * You'd think it would be appropriate to call v2_close() - * on the handle when we're done with it. But that seems - * to cause the device to shut down somehow; for the moment, - * we simply leave it open... - */ - if ((fd = op->v2_open(buffer)) == 0 || - (node = op->v2_fd_phandle(fd)) == 0) { - printf("consinit: bogus stdin path %s.\n",buffer); - goto setup_output; - } - if (no->no_proplen(node,"keyboard") >= 0) { - in = PROMDEV_KBD; - goto setup_output; - } - if (strcmp(getpropstring(node,"device_type"),"serial") != 0) { - /* not a serial, not keyboard. what is it?!? */ - in = -1; - goto setup_output; - } - /* - * At this point we assume the device path is in the form - * ....device@x,y:a for ttya and ...device@x,y:b for ttyb. - * If it isn't, we defer to the ROM - */ - cp = buffer; - while (*cp) - cp++; - cp -= 2; -#ifdef DEBUG - if (cp < buffer) - panic("consinit: bad stdin path %s",buffer); -#endif - /* XXX: only allows tty's a->z, assumes PROMDEV_TTYx contig */ - if (cp[0]==':' && cp[1] >= 'a' && cp[1] <= 'z') - in = PROMDEV_TTYA + (cp[1] - 'a'); - /* else use rom */ -setup_output: - node = findroot(); - if (no->no_proplen(node, "stdout-path") >= sizeof(buffer)) { - printf("consinit: increase buffer size and recompile\n"); - goto setup_console; - } - /* XXX: fix above */ - - no->no_getprop(node, "stdout-path", buffer); - - if ((fd = op->v2_open(buffer)) == 0 || - (node = op->v2_fd_phandle(fd)) == 0) { - printf("consinit: bogus stdout path %s.\n",buffer); - goto setup_output; - } - if (strcmp(getpropstring(node,"device_type"),"display") == 0) { - /* frame buffer output */ - out = PROMDEV_SCREEN; - fbnode = node; - } else if (strcmp(getpropstring(node,"device_type"), "serial") - != 0) { - /* not screen, not serial. Whatzit? */ - out = -1; - } else { /* serial console. which? */ - /* - * At this point we assume the device path is in the - * form: - * ....device@x,y:a for ttya, etc. - * If it isn't, we defer to the ROM - */ - cp = buffer; - while (*cp) - cp++; - cp -= 2; -#ifdef DEBUG - if (cp < buffer) - panic("consinit: bad stdout path %s",buffer); -#endif - /* XXX: only allows tty's a->z, assumes PROMDEV_TTYx contig */ - if (cp[0]==':' && cp[1] >= 'a' && cp[1] <= 'z') - out = PROMDEV_TTYA + (cp[1] - 'a'); - else out = -1; - } - } else { - in = *promvec->pv_stdin; - out = *promvec->pv_stdout; - } -setup_console: - switch (in) { -#if NZS > 0 - case PROMDEV_TTYA: - zsconsole(tp, 0, 0, NULL); - break; - - case PROMDEV_TTYB: - zsconsole(tp, 1, 0, NULL); - break; -#endif -#if NKBD > 0 - case PROMDEV_KBD: - /* - * Tell the keyboard driver to direct ASCII input here. - */ - kbd_ascii(tp); - break; -#endif - - default: - rom_console_input = 1; - printf("unknown console input source %d; using rom\n", in); - break; - } - switch (out) { - -#if NZS > 0 - case PROMDEV_TTYA: - zsconsole(tp, 0, 1, &fcnstop); - break; - - case PROMDEV_TTYB: - zsconsole(tp, 1, 1, &fcnstop); - break; -#endif - - case PROMDEV_SCREEN: - fbconstty = tp; - tp->t_oproc = cnfbstart; - fcnstop = cnfbstop; - break; - - default: - printf("unknown console output sink %d; using rom\n", out); - tp->t_oproc = cnstart; - fcnstop = (int (*)(struct tty *, int))nullop; - break; - } -} - -/* ARGSUSED */ -int -cnopen(dev, flag, mode, p) - dev_t dev; - int flag, mode; - struct proc *p; -{ - register struct tty *tp = &cons; - static int firstopen = 1; - static int rows = 0, cols = 0; - - if (firstopen) { - clalloc(&tp->t_rawq, 1024, 1); - clalloc(&tp->t_canq, 1024, 1); - /* output queue doesn't need quoting */ - clalloc(&tp->t_outq, 1024, 0); - tty_attach(tp); - timeout_set(&cons_cnfbdma_tmo, cnfbdma, tp); - - /* - * get the console struct winsize. - */ - if (fbconstty) { -#ifdef RASTERCONSOLE - rows = fbrcons_rows(); - cols = fbrcons_cols(); -#else - if (CPU_ISSUN4COR4M) { - int i; - char *prop; - - if (rows == 0 && - (prop = getpropstring(optionsnode, - "screen-#rows"))) { - i = 0; - while (*prop != '\0') - i = i * 10 + *prop++ - '0'; - rows = (unsigned short)i; - } - if (cols == 0 && - (prop = getpropstring(optionsnode, - "screen-#columns"))) { - i = 0; - while (*prop != '\0') - i = i * 10 + *prop++ - '0'; - cols = (unsigned short)i; - } - } - if (CPU_ISSUN4) { - struct eeprom *ep = (struct eeprom *)eeprom_va; - - if (ep) { - if (rows == 0) - rows = (u_short)ep->eeTtyRows; - if (cols == 0) - cols = (u_short)ep->eeTtyCols; - } - } -#endif - } - firstopen = 0; - } - - if ((tp->t_state & TS_ISOPEN) == 0) { - /* - * Leave baud rate alone! - */ - ttychars(tp); - tp->t_iflag = TTYDEF_IFLAG; - tp->t_oflag = TTYDEF_OFLAG; - tp->t_lflag = TTYDEF_LFLAG; - tp->t_cflag = TTYDEF_CFLAG; - tp->t_state = TS_ISOPEN | TS_CARR_ON; - (void)(*tp->t_param)(tp, &tp->t_termios); - ttsetwater(tp); - tp->t_winsize.ws_row = rows; - tp->t_winsize.ws_col = cols; - } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) - return (EBUSY); - return ((*linesw[tp->t_line].l_open)(dev, tp)); -} - -/* ARGSUSED */ -int -cnclose(dev, flag, mode, p) - dev_t dev; - int flag, mode; - struct proc *p; -{ - register struct tty *tp = &cons; - - (*linesw[tp->t_line].l_close)(tp, flag); - ttyclose(tp); - return (0); -} - -/* ARGSUSED */ -int -cnread(dev, uio, flag) - dev_t dev; - struct uio *uio; - int flag; -{ - register struct tty *tp = &cons; - - return ((*linesw[tp->t_line].l_read)(tp, uio, flag)); -} - -/* ARGSUSED */ -int -cnwrite(dev, uio, flag) - dev_t dev; - struct uio *uio; - int flag; -{ - register struct tty *tp; - - if ((tp = constty) == NULL || - (tp->t_state & (TS_CARR_ON|TS_ISOPEN)) != (TS_CARR_ON|TS_ISOPEN)) - tp = &cons; - return ((*linesw[tp->t_line].l_write)(tp, uio, flag)); -} - -int -cnioctl(dev, cmd, data, flag, p) - dev_t dev; - u_long cmd; - caddr_t data; - int flag; - struct proc *p; -{ - register struct tty *tp; - int error; - - /* - * Superuser can always use this to wrest control of console - * output from the "virtual" console. - */ - if (cmd == TIOCCONS && constty) { - error = suser(p->p_ucred, (u_short *)NULL); - if (error) - return (error); - constty = NULL; - return (0); - } - tp = &cons; - if ((error = linesw[tp->t_line].l_ioctl(tp, cmd, data, flag, p)) >= 0) - return (error); - if ((error = ttioctl(tp, cmd, data, flag, p)) >= 0) - return (error); - return (ENOTTY); -} - -int -cnselect(dev, which, p) - dev_t dev; - int which; - struct proc *p; -{ - - return (ttselect(makedev(major(dev), 0), which, p)); -} - -int -cnkqfilter(dev, kn) - dev_t dev; - struct knote *kn; -{ - if (cdevsw[major(dev)].d_type & D_KQFILTER) - return ((*cdevsw[major(dev)].d_kqfilter)(makedev(major(dev), 0), kn)); - return (1); -} - -/* - * The rest of this code is run only when we are using the ROM vectors. - */ - -/* - * Generic output. We just call putchar. (Very bad for performance.) - */ -static void -cnstart(tp) - register struct tty *tp; -{ - register int c, s; - register union { - void (*v1)(int); - int (*v3)(int, void *, int); - } putc; - register int fd = 0, v; - - s = spltty(); - if (tp->t_state & (TS_TIMEOUT | TS_TTSTOP)) { - splx(s); - return; - } - if ((v = promvec->pv_romvec_vers) > 2) { - putc.v3 = promvec->pv_v2devops.v2_write; - fd = *promvec->pv_v2bootargs.v2_fd1; - } else - putc.v1 = promvec->pv_putchar; - while (tp->t_outq.c_cc) { - int ss; - - c = getc(&tp->t_outq); - /* - * *%&!*& ROM monitor console putchar is not reentrant! - * splhigh/tty around it so as not to run so long with - * clock interrupts blocked. - */ - ss = splhigh(); - if (v > 2) { - unsigned char c0 = c & 0177; - (*putc.v3)(fd, &c0, 1); - } else - (*putc.v1)(c & 0177); - splx(ss); - } - if (tp->t_state & TS_ASLEEP) { /* can't happen? */ - tp->t_state &= ~TS_ASLEEP; - wakeup((caddr_t)&tp->t_outq); - } - selwakeup(&tp->t_wsel); - splx(s); -} - -int -cnstop(tp, flag) - register struct tty *tp; - int flag; -{ - (void)(*fcnstop)(tp, flag); - return 0; -} - -/* - * Frame buffer output. - * We use pseudo-DMA, via the ROM `write string' function, called from - * software clock interrupts. - */ -static void -cnfbstart(tp) - register struct tty *tp; -{ - register int s; - - s = spltty(); /* paranoid: splsoftclock should suffice */ - if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) { - splx(s); - return; - } - /* - * If there are sleepers, and output has drained below low - * water mark, awaken. - */ - 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) { - tp->t_state |= TS_BUSY; - /* - * XXX - this is just too ugly. - */ - if (s == 0) { - (void) spllowersoftclock(); - cnfbdma((void *)tp); - } else - timeout_add(&cons_cnfbdma_tmo, 1); - } - splx(s); -} - -/* - * Stop frame buffer output: just assert TS_FLUSH if necessary. - */ -static int -cnfbstop(tp, flag) - register struct tty *tp; - int flag; -{ - register int s = spltty(); /* paranoid */ - - if ((tp->t_state & (TS_BUSY | TS_TTSTOP)) == TS_BUSY) - tp->t_state |= TS_FLUSH; - splx(s); - return 0; -} - -/* - * Do pseudo-dma (called from software interrupt). - */ -static void -cnfbdma(tpaddr) - void *tpaddr; -{ - register struct tty *tp = tpaddr; - register unsigned char *p, *q; - register int n, c, s; - - s = spltty(); /* paranoid */ - if (tp->t_state & TS_FLUSH) { - tp->t_state &= ~(TS_BUSY | TS_FLUSH); - splx(s); - } else { - tp->t_state &= ~TS_BUSY; - splx(s); - p = tp->t_outq.c_cf; - n = ndqb(&tp->t_outq, 0); - for (q = p, c = n; --c >= 0; q++) - if (*q & 0200) /* high bits seem to be bad */ - *q &= ~0200; - if (promvec->pv_romvec_vers > 2) { - (*promvec->pv_v2devops.v2_write) - (*promvec->pv_v2bootargs.v2_fd1, p, n); - } else - (*promvec->pv_putstr)((char *)p, n); - ndflush(&tp->t_outq, n); - } - if (tp->t_line) - (*linesw[tp->t_line].l_start)(tp); - else - cnfbstart(tp); -} - -/* - * The following is for rom console input. The rom will not call - * an `interrupt' routine on console input ready, so we must poll. - * This is all rather sad. - */ -volatile int cn_rxc = -1; /* XXX receive `silo' */ - -/* called from hardclock, which is above spltty, so no tty calls! */ -int -cnrom() -{ - register int c; - - if (cn_rxc >= 0) - return (1); - if (promvec->pv_romvec_vers > 2) { - unsigned char c0; - if ((*promvec->pv_v2devops.v2_read) - (*promvec->pv_v2bootargs.v2_fd0, &c0, 1) <= 0) - return (0); - c = c0; - } else if ((c = (*promvec->pv_nbgetchar)()) < 0) - return (0); - cn_rxc = c; - return (1); -} - -/* pseudo console software interrupt scheduled when cnrom() returns 1 */ -void -cnrint() -{ - register struct tty *tp; - register int c, s; - - s = splclock(); - c = cn_rxc; - cn_rxc = -1; - splx(s); - if (c < 0) - return; - tp = &cons; - if ((tp->t_cflag & CSIZE) == CS7) { - /* XXX this should be done elsewhere, if at all */ - if (tp->t_cflag & PARENB) - if (tp->t_cflag & PARODD ? - (char_type[c & 0177] & 0200) == (c & 0200) : - (char_type[c & 0177] & 0200) != (c & 0200)) - c |= TTY_PE; - c &= ~0200; - } - (*linesw[tp->t_line].l_rint)(c, tp); -} - -int -cngetc() -{ - register int s, c; - - if (promvec->pv_romvec_vers > 2) { - register int n = 0; - unsigned char c0; - s = splhigh(); - while (n <= 0) { - n = (*promvec->pv_v2devops.v2_read) - (*promvec->pv_v2bootargs.v2_fd0, &c0, 1); - } - splx(s); - c = c0; - } else { -#if defined(SUN4) - /* SUN4 PROM: must turn off echo to avoid double char echo */ - extern struct om_vector *oldpvec; - int saveecho = 0; -#endif - - s = splhigh(); -#if defined(SUN4) - if (CPU_ISSUN4) { - saveecho = *(oldpvec->echo); - *(oldpvec->echo) = 0; - } -#endif - c = (*promvec->pv_getchar)(); -#if defined(SUN4) - if (CPU_ISSUN4) - *(oldpvec->echo) = saveecho; -#endif - splx(s); - } - if (c == '\r') - c = '\n'; - return (c); -} - -void -cnputc(c) - register int c; -{ - register int s; - - if (c == '\n') - cnputc('\r'); - s = splhigh(); - if (promvec->pv_romvec_vers > 2) { - unsigned char c0 = c; - (*promvec->pv_v2devops.v2_write) - (*promvec->pv_v2bootargs.v2_fd1, &c0, 1); - } else - (*promvec->pv_putchar)(c); - splx(s); -} - -void -cnpollc(on) - int on; -{ -} diff --git a/sys/arch/sparc/dev/cons.h b/sys/arch/sparc/dev/cons.h new file mode 100644 index 00000000000..d419a73fa3a --- /dev/null +++ b/sys/arch/sparc/dev/cons.h @@ -0,0 +1,18 @@ +/* $OpenBSD: cons.h,v 1.1 2002/08/12 10:44:04 miod Exp $ */ + +struct consdev; +struct zs_chanstate; + +extern void *zs_conschan; + +extern void nullcnprobe(struct consdev *); + +extern int zs_getc(void *arg); +extern void zs_putc(void *arg, int c); + +struct zschan *zs_get_chan_addr(int zsc_unit, int channel); + +#ifdef KGDB +void zs_kgdb_init(void); +void zskgdb(struct zs_chanstate *); +#endif diff --git a/sys/arch/sparc/dev/fb.c b/sys/arch/sparc/dev/fb.c index 77e588883bc..c0dd87eb0b5 100644 --- a/sys/arch/sparc/dev/fb.c +++ b/sys/arch/sparc/dev/fb.c @@ -1,7 +1,32 @@ -/* $OpenBSD: fb.c,v 1.18 2002/03/14 01:26:42 millert Exp $ */ +/* $OpenBSD: fb.c,v 1.19 2002/08/12 10:44:04 miod Exp $ */ /* $NetBSD: fb.c,v 1.23 1997/07/07 23:30:22 pk Exp $ */ /* + * Copyright (c) 2002 Miodrag Vallat + * 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. + * + * * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * @@ -46,8 +71,7 @@ */ /* - * /dev/fb (indirect frame buffer driver). This is gross; we should - * just build cdevsw[] dynamically. + * Common wsdisplay framebuffer drivers helpers. */ #include <sys/param.h> @@ -57,148 +81,23 @@ #include <sys/conf.h> #include <machine/autoconf.h> -#include <machine/fbio.h> -#include <machine/kbd.h> -#include <machine/fbvar.h> #include <machine/conf.h> #if defined(SUN4) #include <machine/eeprom.h> #include <sparc/dev/pfourreg.h> #endif -#include "kbd.h" - -static struct fbdevice *devfb; - - -void -fb_unblank() -{ - - if (devfb) - (*devfb->fb_driver->fbd_unblank)(devfb->fb_device); -} - -void -fb_attach(fb, isconsole) - struct fbdevice *fb; - int isconsole; -{ - static int no_replace, seen_force; - - /* - * We've already had a framebuffer forced into /dev/fb. Don't - * allow any more, even if this is the console. - */ - if (seen_force) { - if (devfb) { /* sanity */ - printf("%s: /dev/fb already full\n", - fb->fb_device->dv_xname); - return; - } else - seen_force = 0; - } - - /* - * Check to see if we're being forced into /dev/fb. - */ - if (fb->fb_flags & FB_FORCE) { - if (devfb) - printf("%s: forcefully replacing %s\n", - fb->fb_device->dv_xname, - devfb->fb_device->dv_xname); - devfb = fb; - seen_force = no_replace = 1; - goto attached; - } - - /* - * Check to see if we're the console. If we are, then replace - * any currently existing framebuffer. - */ - if (isconsole) { - if (devfb) - printf("%s: replacing %s\n", fb->fb_device->dv_xname, - devfb->fb_device->dv_xname); - devfb = fb; - no_replace = 1; - goto attached; - } - - /* - * For the final case, we check to see if we can replace an - * existing framebuffer, if not, say so and return. - */ - if (no_replace) { - if (devfb) { /* sanity */ - printf("%s: /dev/fb already full\n", - fb->fb_device->dv_xname); - return; - } else - no_replace = 0; - } - - if (devfb) - printf("%s: replacing %s\n", fb->fb_device->dv_xname, - devfb->fb_device->dv_xname); - devfb = fb; - - attached: - printf("%s: attached to /dev/fb\n", devfb->fb_device->dv_xname); -} - -int -fbopen(dev, flags, mode, p) - dev_t dev; - int flags, mode; - struct proc *p; -{ - - if (devfb == NULL) - return (ENXIO); - return (devfb->fb_driver->fbd_open)(dev, flags, mode, p); -} - -int -fbclose(dev, flags, mode, p) - dev_t dev; - int flags, mode; - struct proc *p; -{ - - return (devfb->fb_driver->fbd_close)(dev, flags, mode, p); -} - -int -fbioctl(dev, cmd, data, flags, p) - dev_t dev; - u_long cmd; - caddr_t data; - int flags; - struct proc *p; -{ - - return (devfb->fb_driver->fbd_ioctl)(dev, cmd, data, flags, p); -} - -paddr_t -fbmmap(dev, off, prot) - dev_t dev; - off_t off; - int prot; -{ - paddr_t (*map)(dev_t, off_t, int) = devfb->fb_driver->fbd_mmap; - - if (map == NULL) - return (-1); - return (map(dev, off, prot)); -} +#include <dev/wscons/wsdisplayvar.h> +#include <dev/wscons/wscons_raster.h> +#include <dev/rasops/rasops.h> +#include <machine/fbvar.h> void -fb_setsize(fb, depth, def_width, def_height, node, bustype) - struct fbdevice *fb; - int depth, def_width, def_height, node, bustype; +fb_setsize(sf, def_depth, def_width, def_height, node, bustype) + struct sunfb *sf; + int def_depth, def_width, def_height, node, bustype; { + int def_linebytes; /* * The defaults below match my screen, but are not guaranteed @@ -208,18 +107,15 @@ fb_setsize(fb, depth, def_width, def_height, node, bustype) case BUS_VME16: case BUS_VME32: case BUS_OBIO: +#if defined(SUN4M) if (CPU_ISSUN4M) { /* 4m has framebuffer on obio */ - fb->fb_type.fb_width = getpropint(node, "width", - def_width); - fb->fb_type.fb_height = getpropint(node, "height", - def_height); - fb->fb_linebytes = getpropint(node, "linebytes", - (fb->fb_type.fb_width * depth) / 8); - break; + goto obpsize; } +#endif /* Set up some defaults. */ - fb->fb_type.fb_width = def_width; - fb->fb_type.fb_height = def_height; + sf->sf_width = def_width; + sf->sf_height = def_height; + sf->sf_depth = def_depth; /* * This is not particularly useful on Sun 4 VME framebuffers. @@ -233,7 +129,7 @@ fb_setsize(fb, depth, def_width, def_height, node, bustype) if (CPU_ISSUN4) { struct eeprom *eep = (struct eeprom *)eeprom_va; - if (fb->fb_flags & FB_PFOUR) { + if (ISSET(sf->sf_flags, FB_PFOUR)) { volatile u_int32_t pfour; /* @@ -245,10 +141,10 @@ fb_setsize(fb, depth, def_width, def_height, node, bustype) * the pfour register by the time this * routine is called. */ - if (fb->fb_pfour == NULL) + if (sf->sf_pfour == NULL) goto donesize; - pfour = *fb->fb_pfour; + pfour = *sf->sf_pfour; /* * Use the pfour register to determine @@ -264,33 +160,33 @@ fb_setsize(fb, depth, def_width, def_height, node, bustype) switch (PFOUR_SIZE(pfour)) { case PFOUR_SIZE_1152X900: - fb->fb_type.fb_width = 1152; - fb->fb_type.fb_height = 900; + sf->sf_width = 1152; + sf->sf_height = 900; break; case PFOUR_SIZE_1024X1024: - fb->fb_type.fb_width = 1024; - fb->fb_type.fb_height = 1024; + sf->sf_width = 1024; + sf->sf_height = 1024; break; case PFOUR_SIZE_1280X1024: - fb->fb_type.fb_width = 1280; - fb->fb_type.fb_height = 1024; + sf->sf_width = 1280; + sf->sf_height = 1024; break; case PFOUR_SIZE_1600X1280: - fb->fb_type.fb_width = 1600; - fb->fb_type.fb_height = 1280; + sf->sf_width = 1600; + sf->sf_height = 1280; break; case PFOUR_SIZE_1440X1440: - fb->fb_type.fb_width = 1440; - fb->fb_type.fb_height = 1440; + sf->sf_width = 1440; + sf->sf_height = 1440; break; case PFOUR_SIZE_640X480: - fb->fb_type.fb_width = 640; - fb->fb_type.fb_height = 480; + sf->sf_width = 640; + sf->sf_height = 480; break; default: @@ -304,23 +200,23 @@ fb_setsize(fb, depth, def_width, def_height, node, bustype) } else if (eep != NULL) { switch (eep->eeScreenSize) { case EE_SCR_1152X900: - fb->fb_type.fb_width = 1152; - fb->fb_type.fb_height = 900; + sf->sf_width = 1152; + sf->sf_height = 900; break; case EE_SCR_1024X1024: - fb->fb_type.fb_width = 1024; - fb->fb_type.fb_height = 1024; + sf->sf_width = 1024; + sf->sf_height = 1024; break; case EE_SCR_1600X1280: - fb->fb_type.fb_width = 1600; - fb->fb_type.fb_height = 1280; + sf->sf_width = 1600; + sf->sf_height = 1280; break; case EE_SCR_1440X1440: - fb->fb_type.fb_width = 1440; - fb->fb_type.fb_height = 1440; + sf->sf_width = 1440; + sf->sf_height = 1440; break; default: @@ -340,38 +236,48 @@ fb_setsize(fb, depth, def_width, def_height, node, bustype) } #endif /* SUN4M */ - donesize: - fb->fb_linebytes = (fb->fb_type.fb_width * depth) / 8; +donesize: + sf->sf_linebytes = (sf->sf_width * sf->sf_depth) / 8; break; case BUS_SBUS: - fb->fb_type.fb_width = getpropint(node, "width", def_width); - fb->fb_type.fb_height = getpropint(node, "height", def_height); - fb->fb_linebytes = getpropint(node, "linebytes", - (fb->fb_type.fb_width * depth) / 8); +#if defined(SUN4M) +obpsize: +#endif + sf->sf_depth = getpropint(node, "depth", def_depth); + sf->sf_width = getpropint(node, "width", def_width); + sf->sf_height = getpropint(node, "height", def_height); + + def_linebytes = + roundup(sf->sf_width, sf->sf_depth) * sf->sf_depth / 8; + sf->sf_linebytes = getpropint(node, "linebytes", def_linebytes); + /* + * XXX If we are configuring a board in a wider depth level + * than the mode it is currently operating in, the PROM will + * return a linebytes property tied to the current depth value, + * which is NOT what we are relying upon! + */ + if (sf->sf_linebytes < (sf->sf_width * sf->sf_depth) / 8) { + sf->sf_linebytes = def_linebytes; + } break; default: panic("fb_setsize: inappropriate bustype"); /* NOTREACHED */ } -} - - -#ifdef RASTERCONSOLE -#include <machine/kbd.h> -static void fb_bell(int); + sf->sf_fbsize = sf->sf_height * sf->sf_linebytes; +} -#if !(defined(RASTERCONS_FULLSCREEN) || defined(RASTERCONS_SMALLFONT)) -static int a2int(char *, int); +int a2int(char *, int); -static int +int a2int(cp, deflt) - register char *cp; - register int deflt; + char *cp; + int deflt; { - register int i = 0; + int i = 0; if (*cp == '\0') return (deflt); @@ -379,87 +285,127 @@ a2int(cp, deflt) i = i * 10 + *cp++ - '0'; return (i); } -#endif -static void -fb_bell(on) - int on; -{ -#if NKBD > 0 - (void)kbd_docmd(on?KBD_CMD_BELL:KBD_CMD_NOBELL, 0); -#endif -} +/* + * emergency unblank code + * XXX should be somewhat moved to wscons MI code + */ -#include <sparc/dev/rcons_font.h> +void (*fb_burner)(void *, u_int, u_int); +void *fb_cookie; void -fbrcons_init(fb) - struct fbdevice *fb; +fb_unblank() { - struct rconsole *rc = &fb->fb_rcons; + if (fb_burner != NULL) + (*fb_burner)(fb_cookie, 1, 0); +} - /* - * Common glue for rconsole initialization - * XXX - mostly duplicates values with fbdevice. - */ - rc->rc_linebytes = fb->fb_linebytes; - rc->rc_pixels = fb->fb_pixels; - rc->rc_width = fb->fb_type.fb_width; - rc->rc_height = fb->fb_type.fb_height; - rc->rc_depth = fb->fb_type.fb_depth; - /* Setup the static font, use a small font if display is < 800x600 */ - if(rc->rc_height * rc->rc_width <= 800*600) - rc->rc_font = &console_font_fixed; - else - rc->rc_font = &console_font; - - rc->rc_maxcol = rc->rc_width / rc->rc_font->width; - rc->rc_maxrow = rc->rc_height / rc->rc_font->height; -#if !defined(RASTERCONS_FULLSCREEN) && !defined(RASTERCONS_SMALLFONT) +void +fbwscons_init(sf, isconsole) + struct sunfb *sf; + int isconsole; +{ + int cols, rows; + + /* ri_hw and ri_bits must have already been setup by caller */ + sf->sf_ro.ri_flg = RI_CENTER; + if (!isconsole) + sf->sf_ro.ri_flg |= RI_CLEAR; + sf->sf_ro.ri_depth = sf->sf_depth; + sf->sf_ro.ri_stride = sf->sf_linebytes; + sf->sf_ro.ri_width = sf->sf_width; + sf->sf_ro.ri_height = sf->sf_height; + +#if defined(SUN4C) || defined(SUN4M) + if (CPU_ISSUN4COR4M) { + rows = a2int(getpropstring(optionsnode, "screen-#rows"), 34); + cols = a2int(getpropstring(optionsnode, "screen-#columns"), 80); + } +#endif #if defined(SUN4) if (CPU_ISSUN4) { - struct eeprom *eep = (struct eeprom *)eeprom_va; - - rc->rc_maxcol = min(rc->rc_maxcol, - (eep && eep->eeTtyCols) ? eep->eeTtyCols : 80); - rc->rc_maxrow = min(rc->rc_maxrow, - (eep && eep->eeTtyRows) ? eep->eeTtyRows : 34); - } -#endif /* SUN4 */ - - if (!CPU_ISSUN4) { - rc->rc_maxcol = min(rc->rc_maxcol, - a2int(getpropstring(optionsnode, "screen-#columns"), 80)); - rc->rc_maxrow = min(rc->rc_maxrow, - a2int(getpropstring(optionsnode, "screen-#rows"), 34)); + struct eeprom *ep = (struct eeprom *)eeprom_va; + + if (ep != NULL) { + rows = (u_short)ep->eeTtyRows; + cols = (u_short)ep->eeTtyCols; + /* deal with broken nvram contents... */ + if (rows == 0) + rows = 34; + if (cols == 0) + cols = 80; + } else { + rows = 34; + cols = 80; + } } -#endif /* !RASTERCONS_FULLSCREEN && !RASTERCONS_SMALLFONT */ - -#if !(defined(RASTERCONS_FULLSCREEN) || defined(RASTERCONS_SMALLFONT)) - /* Determine addresses of prom emulator row and column */ - if (CPU_ISSUN4 || - romgetcursoraddr(&rc->rc_row, &rc->rc_col)) #endif - rc->rc_row = rc->rc_col = NULL; - rc->rc_bell = fb_bell; - rcons_init(rc); - /* Hook up virtual console */ - v_putc = rcons_cnputc; + rasops_init(&sf->sf_ro, rows, cols); } -int -fbrcons_rows() +void +fbwscons_console_init(sf, wsc, row, setcolor, burner) + struct sunfb *sf; + struct wsscreen_descr *wsc; + int row; + void (*setcolor)(void *, u_int, u_int8_t, u_int8_t, u_int8_t); + void (*burner)(void *, u_int, u_int); { - return (devfb ? devfb->fb_rcons.rc_maxrow : 0); -} + long defattr; + int *ccolp, *crowp; + + if (CPU_ISSUN4 || romgetcursoraddr(&crowp, &ccolp)) + ccolp = crowp = NULL; + if (ccolp != NULL) + sf->sf_ro.ri_ccol = *ccolp; + + if (row < 0) { + if (crowp != NULL) + sf->sf_ro.ri_crow = *crowp; + else + /* assume last row */ + sf->sf_ro.ri_crow = sf->sf_ro.ri_rows - 1; + } else + sf->sf_ro.ri_crow = row; -int -fbrcons_cols() -{ - return (devfb ? devfb->fb_rcons.rc_maxcol : 0); + /* + * Select appropriate color settings to mimic a + * black on white Sun console. + */ + if (sf->sf_depth == 8 && setcolor != NULL) { + setcolor(sf, WSCOL_BLACK, 0, 0, 0); + setcolor(sf, 255, 0, 0, 0); + setcolor(sf, WSCOL_RED, 255, 0, 0); + setcolor(sf, WSCOL_GREEN, 0, 255, 0); + setcolor(sf, WSCOL_BROWN, 154, 85, 46); + setcolor(sf, WSCOL_BLUE, 0, 0, 255); + setcolor(sf, WSCOL_MAGENTA, 255, 255, 0); + setcolor(sf, WSCOL_CYAN, 0, 255, 255); + setcolor(sf, WSCOL_WHITE, 255, 255, 255); + } else if (sf->sf_depth > 8) { + wscol_white = 0; + wscol_black = 255; + wskernel_bg = 0; + wskernel_fg = 255; + } + + if (ISSET(wsc->capabilities, WSSCREEN_WSCOLORS) && + sf->sf_depth == 8) { + sf->sf_ro.ri_ops.alloc_attr(&sf->sf_ro, + WSCOL_BLACK, WSCOL_WHITE, WSATTR_WSCOLORS, &defattr); + } else { + sf->sf_ro.ri_ops.alloc_attr(&sf->sf_ro, 0, 0, 0, &defattr); + } + + wsdisplay_cnattach(wsc, &sf->sf_ro, + sf->sf_ro.ri_ccol, sf->sf_ro.ri_crow, defattr); + + /* remember screen burner routine */ + fb_burner = burner; + fb_cookie = sf; } -#endif /* RASTERCONSOLE */ #if defined(SUN4) /* @@ -498,28 +444,31 @@ fb_pfour_id(va) return (PFOUR_ID(val)); } + /* * Return the status of the video enable. */ int -fb_pfour_get_video(fb) - struct fbdevice *fb; +fb_pfour_get_video(sf) + struct sunfb *sf; { - return ((*fb->fb_pfour & PFOUR_REG_VIDEO) != 0); + return ((*sf->sf_pfour & PFOUR_REG_VIDEO) != 0); } /* * Enable or disable the framebuffer. */ void -fb_pfour_set_video(fb, enable) - struct fbdevice *fb; +fb_pfour_set_video(sf, enable) + struct sunfb *sf; int enable; { volatile u_int32_t pfour; - pfour = *fb->fb_pfour & ~(PFOUR_REG_INTCLR|PFOUR_REG_VIDEO); - *fb->fb_pfour = pfour | (enable ? PFOUR_REG_VIDEO : 0); + pfour = *sf->sf_pfour & ~(PFOUR_REG_INTCLR | PFOUR_REG_VIDEO); + *sf->sf_pfour = pfour | (enable ? PFOUR_REG_VIDEO : 0); } + #endif /* SUN4 */ + diff --git a/sys/arch/sparc/dev/kbd.c b/sys/arch/sparc/dev/kbd.c deleted file mode 100644 index 50ac48fd5f2..00000000000 --- a/sys/arch/sparc/dev/kbd.c +++ /dev/null @@ -1,1179 +0,0 @@ -/* $OpenBSD: kbd.c,v 1.17 2002/03/14 03:15:59 millert Exp $ */ -/* $NetBSD: kbd.c,v 1.28 1997/09/13 19:12:18 pk Exp $ */ - -/* - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This software was developed by the Computer Systems Engineering group - * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and - * contributed to Berkeley. - * - * 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, Lawrence Berkeley Laboratory. - * - * 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. - * - * @(#)kbd.c 8.2 (Berkeley) 10/30/93 - */ - -/* - * Keyboard driver (/dev/kbd -- note that we do not have minor numbers - * [yet?]). Translates incoming bytes to ASCII or to `firm_events' and - * passes them up to the appropriate reader. - */ - -#include <sys/param.h> -#include <sys/device.h> -#include <sys/ioctl.h> -#include <sys/kernel.h> -#include <sys/proc.h> -#include <sys/syslog.h> -#include <sys/systm.h> -#include <sys/tty.h> -#include <sys/signalvar.h> -#include <sys/conf.h> -#include <sys/timeout.h> - -#include <machine/autoconf.h> -#include <machine/conf.h> - -#include <machine/vuid_event.h> -#include <dev/sun/event_var.h> -#include <machine/kbd.h> -#include <machine/kbio.h> - -/* - * Sun keyboard definitions (from Sprite). - * These apply to type 2, 3 and 4 keyboards. - */ -#define KEY_CODE(c) ((c) & KBD_KEYMASK) /* keyboard code index */ -#define KEY_UP(c) ((c) & KBD_UP) /* true => key went up */ - -/* - * Each KEY_CODE(x) can be translated via the tables below. - * The result is either a valid ASCII value in [0..0x7f] or is one - * of the following `magic' values saying something interesting - * happened. If LSHIFT or RSHIFT has changed state the next - * lookup should come from the appropriate table; if ALLUP is - * sent all keys (including both shifts and the control key) are - * now up, and the next byte is the keyboard ID code. - * - * These tables ignore all function keys (on the theory that if you - * want these keys, you should use a window system). Note that - * `caps lock' is just mapped as `ignore' (so there!). (Only the - * type 3 and 4 keyboards have a caps lock key anyway.) - */ -#define KEY_MAGIC 0x80 /* flag => magic value */ -#define KEY_IGNORE 0x80 -#define KEY_L1 KEY_IGNORE -#define KEY_CAPSLOCK KEY_IGNORE -#define KEY_LSHIFT 0x81 -#define KEY_RSHIFT 0x82 -#define KEY_CONTROL 0x83 -#define KEY_ALLUP 0x84 /* all keys are now up; also reset */ -#define KEY_ALTGR 0x85 -#define KEY_UMLAUT 0x86 -#define KEY_CFLEX 0x87 -#define KEY_TILDE 0x88 -#define KEY_CEDILLA 0x89 -#define KEY_ACUTE 0x8a -#define KEY_GRAVE 0x8b -#define KEY_COMPOSE 0x8c -#define KEY_MAGIC_LAST 0x8c -/* - * Decode tables for type 2, 3, and 4 keyboards - * (stolen from Sprite; see also kbd.h). - */ -static u_char kbd_unshifted[] = { -/* 0 */ KEY_IGNORE, KEY_L1, KEY_IGNORE, KEY_IGNORE, -/* 4 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 8 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 12 */ KEY_IGNORE, KEY_ALTGR, KEY_IGNORE, KEY_IGNORE, -/* 16 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 20 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 24 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 28 */ KEY_IGNORE, '\033', '1', '2', -/* 32 */ '3', '4', '5', '6', -/* 36 */ '7', '8', '9', '0', -/* 40 */ '-', '=', '`', '\b', -/* 44 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 48 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 52 */ KEY_IGNORE, '\t', 'q', 'w', -/* 56 */ 'e', 'r', 't', 'y', -/* 60 */ 'u', 'i', 'o', 'p', -/* 64 */ '[', ']', '\177', KEY_COMPOSE, -/* 68 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 72 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 76 */ KEY_CONTROL, 'a', 's', 'd', -/* 80 */ 'f', 'g', 'h', 'j', -/* 84 */ 'k', 'l', ';', '\'', -/* 88 */ '\\', '\r', KEY_IGNORE, KEY_IGNORE, -/* 92 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 96 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_LSHIFT, -/* 100 */ 'z', 'x', 'c', 'v', -/* 104 */ 'b', 'n', 'm', ',', -/* 108 */ '.', '/', KEY_RSHIFT, '\n', -/* 112 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 116 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_CAPSLOCK, -/* 120 */ KEY_IGNORE, ' ', KEY_IGNORE, KEY_IGNORE, -/* 124 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_ALLUP, -}; - -static u_char kbd_shifted[] = { -/* 0 */ KEY_IGNORE, KEY_L1, KEY_IGNORE, KEY_IGNORE, -/* 4 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 8 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 12 */ KEY_IGNORE, KEY_ALTGR, KEY_IGNORE, KEY_IGNORE, -/* 16 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 20 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 24 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 28 */ KEY_IGNORE, '\033', '!', '@', -/* 32 */ '#', '$', '%', '^', -/* 36 */ '&', '*', '(', ')', -/* 40 */ '_', '+', '~', '\b', -/* 44 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 48 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 52 */ KEY_IGNORE, '\t', 'Q', 'W', -/* 56 */ 'E', 'R', 'T', 'Y', -/* 60 */ 'U', 'I', 'O', 'P', -/* 64 */ '{', '}', '\177', KEY_COMPOSE, -/* 68 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 72 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 76 */ KEY_CONTROL, 'A', 'S', 'D', -/* 80 */ 'F', 'G', 'H', 'J', -/* 84 */ 'K', 'L', ':', '"', -/* 88 */ '|', '\r', KEY_IGNORE, KEY_IGNORE, -/* 92 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 96 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_LSHIFT, -/* 100 */ 'Z', 'X', 'C', 'V', -/* 104 */ 'B', 'N', 'M', '<', -/* 108 */ '>', '?', KEY_RSHIFT, '\n', -/* 112 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 116 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_CAPSLOCK, -/* 120 */ KEY_IGNORE, ' ', KEY_IGNORE, KEY_IGNORE, -/* 124 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_ALLUP, -}; - -static u_char kbd_altgraph[] = { -/* 0 */ KEY_IGNORE, KEY_L1, KEY_IGNORE, KEY_IGNORE, -/* 4 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 8 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 12 */ KEY_IGNORE, KEY_ALTGR, KEY_IGNORE, KEY_IGNORE, -/* 16 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 20 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 24 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 28 */ KEY_IGNORE, '\033', KEY_IGNORE, KEY_IGNORE, -/* 32 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 36 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 40 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, '\b', -/* 44 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 48 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 52 */ KEY_IGNORE, '\t', KEY_IGNORE, KEY_IGNORE, -/* 56 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 60 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 64 */ KEY_IGNORE, KEY_IGNORE, '\177', KEY_COMPOSE, -/* 68 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 72 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 76 */ KEY_CONTROL, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 80 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 84 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 88 */ KEY_IGNORE, '\r', KEY_IGNORE, KEY_IGNORE, -/* 92 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 96 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_LSHIFT, -/* 100 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 104 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 108 */ KEY_IGNORE, KEY_IGNORE, KEY_RSHIFT, '\n', -/* 112 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 116 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_CAPSLOCK, -/* 120 */ KEY_IGNORE, ' ', KEY_IGNORE, KEY_IGNORE, -/* 124 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_ALLUP, -}; - -static u_char kbd_ctrl[] = { -/* 0 */ KEY_IGNORE, KEY_L1, KEY_IGNORE, KEY_IGNORE, -/* 4 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 8 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 12 */ KEY_IGNORE, KEY_ALTGR, KEY_IGNORE, KEY_IGNORE, -/* 16 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 20 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 24 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 28 */ KEY_IGNORE, '\033', '1', '\000', -/* 32 */ '3', '4', '5', '\036', -/* 36 */ '7', '8', '9', '0', -/* 40 */ '\037', '=', '\036', '\b', -/* 44 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 48 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 52 */ KEY_IGNORE, '\t', '\021', '\027', -/* 56 */ '\005', '\022', '\024', '\031', -/* 60 */ '\025', '\t', '\017', '\020', -/* 64 */ '\033', '\035', '\177', KEY_COMPOSE, -/* 68 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 72 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 76 */ KEY_CONTROL, '\001', '\023', '\004', -/* 80 */ '\006', '\007', '\b', '\n', -/* 84 */ '\013', '\014', ';', '\'', -/* 88 */ '\034', '\r', KEY_IGNORE, KEY_IGNORE, -/* 92 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 96 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_LSHIFT, -/* 100 */ '\032', '\030', '\003', '\026', -/* 104 */ '\002', '\016', '\r', ',', -/* 108 */ '.', '\037', KEY_RSHIFT, '\n', -/* 112 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, -/* 116 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_CAPSLOCK, -/* 120 */ KEY_IGNORE, '\000', KEY_IGNORE, KEY_IGNORE, -/* 124 */ KEY_IGNORE, KEY_IGNORE, KEY_IGNORE, KEY_ALLUP, -}; - -static u_char kbd_accent[] = { - 0, KEY_UMLAUT, - ' ', '¨', - 'A', 'Ä', 'E', 'Ë', 'I', 'Ï', 'O', 'Ö', 'U', 'Ü', - 'a', 'ä', 'e', 'ë', 'i', 'ï', 'o', 'ö', 'u', 'ü', 'y', 'ÿ', - 0, KEY_CFLEX, - ' ', '^', - 'A', 'Â', 'E', 'Ê', 'I', 'Î', 'O', 'Ô', 'U', 'Û', - 'a', 'â', 'e', 'ê', 'i', 'î', 'o', 'ô', 'u', 'û', - 0, KEY_TILDE, - ' ', '~', - 'A', 'Ã', 'N', 'Ñ', 'O', 'Õ', - 'a', 'ã', 'n', 'ñ', 'o', 'õ', - 0, KEY_CEDILLA, - ' ', '¸', - 'C', 'Ç', - 'c', 'ç', - 0, KEY_ACUTE, - ' ', '´', - 'A', 'Á', 'E', 'É', 'I', 'Í', 'O', 'Ó', 'U', 'Ú', 'Y', 'Ý', - 'a', 'á', 'e', 'é', 'i', 'í', 'o', 'ó', 'u', 'ú', 'y', 'ý', - 0, KEY_GRAVE, - ' ', '`', - 'A', 'À', 'E', 'È', 'I', 'Ì', 'O', 'Ò', 'U', 'Ù', - 'a', 'à', 'e', 'è', 'i', 'ì', 'o', 'ò', 'u', 'ù', - 0, 0 -}; - -static u_char kbd_compose[] = { - 0, ' ', ' ', ' ', - 0, '!', '!', '¡', - 0, '"', '"', '¨', - 0, '+', '-', '±', - 0, ',', ',', '¸', - 0, '-', ',', '¬', '-', '', ':', '÷', 'A', 'ª', 'a', 'ª', '|', '¬', - 0, '/', 'u', 'µ', - 0, '0', 'X', '¤', 'x', '¤', - 0, '1', '2', '½', '4', '¼', - 0, '3', '4', '¾', - 0, '<', '<', '«', - 0, '>', '>', '»', - 0, '?', '?', '¿', - 0, 'A', '"', 'Ä', '*', 'Å', 'E', 'Æ', '^', 'Â', - '`', 'À', '~', 'Ã', '´', 'Á', - 0, 'C', ',', 'Ç', '/', '¢', 'O', '©', - 0, 'D', '-', 'Ð', - 0, 'E', '"', 'Ë', '^', 'Ê', '`', 'È', '´', 'É', - 0, 'I', '"', 'Ï', '^', 'Î', '`', 'Ì', '´', 'Í', - 0, 'L', '-', '£', - 0, 'N', '~', 'Ñ', - 0, 'O', '"', 'Ö', '/', 'Ø', 'X', '¤', '^', 'Ô', - '`', 'Ò', '~', 'Õ', '´', 'Ó', - 0, 'P', '!', '¶', '|', 'Þ', - 0, 'R', 'O', '®', - 0, 'S', 'O', '§', - 0, 'T', 'H', 'Þ', - 0, 'U', '"', 'Ü', '^', 'Û', '`', 'Ù', '´', 'Ú', - 0, 'Y', '-', '¥', '´', 'Ý', - 0, '\\','\\','´', - 0, '^', '*', '°', '-', '¯', '.', '·', '0', '°', - '1', '¹', '2', '²', '3', '³', - 0, '_', 'O', 'º', 'o', 'º', - 0, 'a', '"', 'ä', '*', 'å', '^', 'â', '`', 'à', - 'e', 'æ', '~', 'ã', '´', 'á', - 0, 'c', ',', 'ç', '/', '¢', 'o', '©', - 0, 'd', '-', 'ð', - 0, 'e', '"', 'ë', '^', 'ê', '`', 'è', '´', 'é', - 0, 'i', '"', 'ï', '^', 'î', '`', 'ì', '´', 'í', - 0, 'l', '-', '£', - 0, 'n', '~', 'ñ', - 0, 'o', '"', 'ö', '/', 'ø', '^', 'ô', '`', 'ò', - 'x', '¤', '~', 'õ', '´', 'ó', - 0, 'p', '!', '¶', '|', 'þ', - 0, 'r', 'o', '®', - 0, 's', 'o', '§', 's', 'ß', - 0, 't', 'h', 'þ', - 0, 'u', '"', 'ü', '^', 'û', '`', 'ù', '´', 'ú', - 0, 'x', 'x', '×', - 0, 'y', '"', 'ÿ', '-', '¥', '´', 'ý', - 0, '|', '|', '¦', - 0, 0 -}; - -/* - * We need to remember the state of the keyboard's shift and control - * keys, and we need a per-type translation table. - */ -struct kbd_state { - const u_char *kbd_unshifted; /* unshifted keys */ - const u_char *kbd_shifted; /* shifted keys */ - const u_char *kbd_altgraph; /* alt gr keys */ - const u_char *kbd_ctrl; /* control keys */ - const u_char *kbd_cur; /* current keys (either of the preceding) */ - union { - char c[2]; /* left and right shift keys */ - short s; /* true => either shift key */ - } kbd_shift; -#define kbd_lshift kbd_shift.c[0] -#define kbd_rshift kbd_shift.c[1] -#define kbd_anyshift kbd_shift.s - char kbd_control; /* true => ctrl down */ - char kbd_altgr; /* true => alt gr down */ - char kbd_click; /* true => keyclick enabled */ - u_char kbd_faccent; /* "floating accent" character pressed */ - u_short kbd_compose; /* compose state */ - u_char kbd_pending; /* Another code from the keyboard is due */ - u_char kbd_id; /* a place to store the ID */ - u_char kbd_layout; /* a place to store layout */ - char kbd_leds; /* LED state */ -}; - -/* - * Keyboard driver state. The ascii and kbd links go up and down and - * we just sit in the middle doing translation. Note that it is possible - * to get just one of the two links, in which case /dev/kbd is unavailable. - * The downlink supplies us with `internal' open and close routines which - * will enable dataflow across the downlink. We promise to call open when - * we are willing to take keystrokes, and to call close when we are not. - * If /dev/kbd is not the console tty input source, we do this whenever - * /dev/kbd is in use; otherwise we just leave it open forever. - */ -struct kbd_softc { - struct tty *k_cons; /* uplink for ASCII data to console */ - struct tty *k_kbd; /* downlink for output to keyboard */ - void (*k_open)(struct tty *); /* enable dataflow */ - void (*k_close)(struct tty *); /* disable dataflow */ - int k_evmode; /* set if we should produce events */ - struct kbd_state k_state; /* ASCII decode state */ - struct evvar k_events; /* event queue state */ - int k_repeatc; /* repeated character */ - int k_repeating; /* we've called timeout() */ - struct timeout k_repeat_tmo; /* for kbd_repeat() timeouts */ -} kbd_softc; - -/* Prototypes */ -void kbd_reset(struct kbd_state *); -static int kbd_translate(int, struct kbd_state *); -void kbdattach(int); -void kbd_repeat(void *arg); -u_short kbd_cnv_entry(u_short); -u_short kbd_cnv_out(u_short); - -/* set in kbdattach() */ -int kbd_repeat_start; -int kbd_repeat_step; -int kbd_initialized; - -/* - * Attach the console keyboard ASCII (up-link) interface. - * This happens before kbd_serial. - */ -void -kbd_ascii(tp) - struct tty *tp; -{ - - kbd_softc.k_cons = tp; -} - -/* - * Attach the console keyboard serial (down-link) interface. - * We pick up the initial keyboard click state here as well. - */ -void -kbd_serial(tp, iopen, iclose) - struct tty *tp; - void (*iopen)(struct tty *); - void (*iclose)(struct tty *); -{ - register struct kbd_softc *k; - register char *cp; - - k = &kbd_softc; - k->k_kbd = tp; - k->k_open = iopen; - k->k_close = iclose; - - if (!CPU_ISSUN4) { - cp = getpropstring(optionsnode, "keyboard-click?"); - if (cp && strcmp(cp, "true") == 0) - k->k_state.kbd_click = 1; - } -} - -/* - * Called from main() during pseudo-device setup. If this keyboard is - * the console, this is our chance to open the underlying serial port and - * send a RESET, so that we can find out what kind of keyboard it is. - */ -void -kbdattach(kbd) - int kbd; -{ - register struct kbd_softc *k; - register struct tty *tp; - - kbd_repeat_start = hz/5; - kbd_repeat_step = hz/20; - - timeout_set(&kbd_softc.k_repeat_tmo, kbd_repeat, k); - kbd_initialized = 1; - - if (kbd_softc.k_cons != NULL) { - k = &kbd_softc; - tp = k->k_kbd; - (*k->k_open)(tp); /* never to be closed */ - if (ttyoutput(KBD_CMD_RESET, tp) >= 0) - panic("kbdattach"); - (*tp->t_oproc)(tp); /* get it going */ - - /* - * Wait here for the keyboard initialization to complete - * since subsequent kernel console access (ie. cnget()) - * may cause the PROM to interfere with the device. - */ - if (tsleep((caddr_t)&kbd_softc.k_state, - PZERO | PCATCH, devopn, hz) != 0) { - /* no response */ - printf("kbd: reset failed\n"); - kbd_reset(&kbd_softc.k_state); - } - printf("kbd: type = %d, layout = 0x%x\n", - kbd_softc.k_state.kbd_id, kbd_softc.k_state.kbd_layout); - } -} - -void -kbd_reset(ks) - register struct kbd_state *ks; -{ - /* - * On first identification, set up the table pointers. - */ - if (ks->kbd_unshifted == NULL) { - ks->kbd_unshifted = kbd_unshifted; - ks->kbd_shifted = kbd_shifted; - ks->kbd_altgraph = kbd_altgraph; - ks->kbd_ctrl = kbd_ctrl; - ks->kbd_faccent = 0; - ks->kbd_compose = 0; - ks->kbd_cur = ks->kbd_unshifted; - } - - /* Restore keyclick, if necessary */ - switch (ks->kbd_id) { - - case KB_SUN2: - /* Type 2 keyboards don't support keyclick */ - break; - - case KB_SUN3: - /* Type 3 keyboards come up with keyclick on */ - if (!ks->kbd_click) - (void) kbd_docmd(KBD_CMD_NOCLICK, 0); - break; - - case KB_SUN4: - /* Type 4 keyboards come up with keyclick off */ - if (ks->kbd_click) - (void) kbd_docmd(KBD_CMD_CLICK, 0); - break; - default: - printf("Unknown keyboard type %d\n", ks->kbd_id); - } - - ks->kbd_leds = 0; -} - -/* - * Turn keyboard up/down codes into ASCII. - */ -static int -kbd_translate(c, ks) - register int c; - register struct kbd_state *ks; -{ - register int down; - register u_char *p; - register int r; - - if (ks->kbd_cur == NULL) { - /* - * Do not know how to translate yet. - * We will find out when a RESET comes along. - */ - return (-1); - } - down = !KEY_UP(c); - c = ks->kbd_cur[KEY_CODE(c)]; - if ((c >= KEY_MAGIC) && (c <= KEY_MAGIC_LAST)) { - switch (c) { - - case KEY_LSHIFT: - ks->kbd_lshift = down; - break; - - case KEY_RSHIFT: - ks->kbd_rshift = down; - break; - - case KEY_ALLUP: - ks->kbd_anyshift = 0; - ks->kbd_control = 0; - ks->kbd_altgr = 0; - break; - - case KEY_ALTGR: - ks->kbd_altgr = down; - break; - - case KEY_CONTROL: - ks->kbd_control = down; - break; - - case KEY_UMLAUT: - case KEY_CFLEX: - case KEY_TILDE: - case KEY_CEDILLA: - case KEY_ACUTE: - case KEY_GRAVE: - ks->kbd_faccent = c; - return (-1); - - case KEY_COMPOSE: - ks->kbd_compose = 0xffff; - - case KEY_IGNORE: - return (-1); - - default: - panic("kbd_translate"); - } - if (ks->kbd_anyshift) - ks->kbd_cur = ks->kbd_shifted; - else - ks->kbd_cur = ks->kbd_unshifted; - if (ks->kbd_control) { - ks->kbd_cur = ks->kbd_ctrl; - } else if (ks->kbd_altgr) { - ks->kbd_cur = ks->kbd_altgraph; - } - return (-1); - } - if (!down) - return (-1); - if (ks->kbd_faccent) { - r = -1; - p = &kbd_accent[0]; - while (p != NULL) { - if (*p == 0) { - if (*++p == 0) - break; - if (*p++ != ks->kbd_faccent) - while(*(p+=2) != 0); - } else { - if (*p++ == (u_char)c) { - r = (int) *p; - break; - } - p++; - } - } - ks->kbd_faccent = 0; - if (r == -1) return(r); - c = r; - } - if (ks->kbd_compose) { - p = &kbd_compose[0]; - if (ks->kbd_compose == 0xffff) { - r = 0; - while (p != NULL) { - if (*++p == 0) - break; - if (*p++ == (u_char)c) { - r = (int)c; - break; - } - while (*(p+=2) != 0); - } - ks->kbd_compose = (u_short)r; - return (-1); - } else { - r = -1; - while (p != NULL) { - if (*p == 0) { - if (*++p == 0) - break; - if (*p++ != (u_char) ks->kbd_compose) - while (*(p+=2) != 0); - } else { - if (*p++ == (u_char)c) { - r = (int) *p; - break; - } - } - } - ks->kbd_compose = 0; - return (r); - } - } - return (c); -} - - -void -kbd_repeat(arg) - void *arg; -{ - struct kbd_softc *k = (struct kbd_softc *)arg; - int s = spltty(); - - if (k->k_repeating && k->k_repeatc >= 0 && k->k_cons != NULL) { - ttyinput(k->k_repeatc, k->k_cons); - timeout_add(&k->k_repeat_tmo, kbd_repeat_step); - } - splx(s); -} - -void -kbd_rint(c) - register int c; -{ - register struct kbd_softc *k = &kbd_softc; - register struct firm_event *fe; - register int put; - - if (!kbd_initialized) - return; - - if (k->k_repeating) { - k->k_repeating = 0; - timeout_del(&k->k_repeat_tmo); - } - - /* - * Reset keyboard after serial port overrun, so we can resynch. - * The printf below should be shortened and/or replaced with a - * call to log() after this is tested (and how will we test it?!). - */ - if (c & (TTY_FE|TTY_PE)) { - printf("keyboard input parity or framing error (0x%x)\n", c); - (void) ttyoutput(KBD_CMD_RESET, k->k_kbd); - (*k->k_kbd->t_oproc)(k->k_kbd); - return; - } - - /* Read the keyboard id if we read a KBD_RESET last time */ - if (k->k_state.kbd_pending == KBD_RESET) { - k->k_state.kbd_pending = 0; - k->k_state.kbd_id = c; - kbd_reset(&k->k_state); - if (c == KB_SUN4) { - /* Arrange to get keyboard layout as well */ - (void)ttyoutput(KBD_CMD_GLAYOUT, k->k_kbd); - (*k->k_kbd->t_oproc)(k->k_kbd); - } else - wakeup((caddr_t)&k->k_state); - return; - } - - /* Read the keyboard layout if we read a KBD_LAYOUT last time */ - if (k->k_state.kbd_pending == KBD_LAYOUT) { - k->k_state.kbd_pending = 0; - k->k_state.kbd_layout = c; - /* - * Wake up anyone waiting for type. - */ - wakeup((caddr_t)&k->k_state); - return; - } - - /* - * If reset or layout in progress, setup to grab the accompanying - * keyboard response next time (id on reset, dip switch on layout). - */ - if (c == KBD_RESET || c == KBD_LAYOUT) { - k->k_state.kbd_pending = c; - return; - } - - /* - * If /dev/kbd is not connected in event mode, but we are sending - * data to /dev/console, translate and send upstream. Note that - * we will get this while opening /dev/kbd if it is not already - * open and we do not know its type. - */ - if (!k->k_evmode) { - c = kbd_translate(c, &k->k_state); - if (c >= 0 && k->k_cons != NULL) { - ttyinput(c, k->k_cons); - k->k_repeating = 1; - k->k_repeatc = c; - timeout_add(&k->k_repeat_tmo, kbd_repeat_start); - } - return; - } - - /* - * IDLEs confuse the MIT X11R4 server badly, so we must drop them. - * This is bad as it means the server will not automatically resync - * on all-up IDLEs, but I did not drop them before, and the server - * goes crazy when it comes time to blank the screen.... - */ - if (c == KBD_IDLE) - return; - - /* - * Keyboard is generating events. Turn this keystroke into an - * event and put it in the queue. If the queue is full, the - * keystroke is lost (sorry!). - */ - put = k->k_events.ev_put; - fe = &k->k_events.ev_q[put]; - put = (put + 1) % EV_QSIZE; - if (put == k->k_events.ev_get) { - log(LOG_WARNING, "keyboard event queue overflow\n"); /* ??? */ - return; - } - fe->id = KEY_CODE(c); - fe->value = KEY_UP(c) ? VKEY_UP : VKEY_DOWN; - fe->time = time; - k->k_events.ev_put = put; - EV_WAKEUP(&k->k_events); -} - -u_short -kbd_cnv_entry(entry) - u_short entry; -{ - u_short s; - - s = entry; - - if ((entry >= 0x100) && (entry < 0x800)) { - - if (entry == SHIFTKEYS+CAPSLOCK) { - s = KEY_CAPSLOCK; - } else if (entry == SHIFTKEYS+LEFTSHIFT) { - s = KEY_LSHIFT; - } else if (entry == SHIFTKEYS+RIGHTSHIFT) { - s = KEY_RSHIFT; - } else if ((entry == SHIFTKEYS+LEFTCTRL) || - (entry == SHIFTKEYS+RIGHTCTRL)) { - s = KEY_CONTROL; - } else if (entry == SHIFTKEYS+ALTGRAPH) { - s = KEY_ALTGR; - } else if (entry == BUCKYBITS+SYSTEMBIT) { - s = KEY_L1; - } else if (entry == IDLE) { - s = KEY_ALLUP; - } else if (entry == COMPOSE) { - s = KEY_COMPOSE; - } else if (entry == FA_UMLAUT) { - s = KEY_UMLAUT; - } else if (entry == FA_CFLEX) { - s = KEY_CFLEX; - } else if (entry == FA_TILDE) { - s = KEY_TILDE; - } else if (entry == FA_CEDILLA) { - s = KEY_CEDILLA; - } else if (entry == FA_ACUTE) { - s = KEY_ACUTE; - } else if (entry == FA_GRAVE) { - s = KEY_GRAVE; - } else { - s = KEY_IGNORE; - } - - } - - return(s); -} - -u_short -kbd_cnv_out(entry) - u_short entry; -{ - u_short s; - - s = entry; - - if (entry == KEY_IGNORE) { - s = NOP; - } else if (entry == KEY_L1) { - s = BUCKYBITS+SYSTEMBIT; - } else if (entry == KEY_CAPSLOCK) { - s = SHIFTKEYS+CAPSLOCK; - } else if (entry == KEY_LSHIFT) { - s = SHIFTKEYS+LEFTSHIFT; - } else if (entry == KEY_RSHIFT) { - s = SHIFTKEYS+RIGHTSHIFT; - } else if (entry == KEY_CONTROL) { - s = SHIFTKEYS+LEFTCTRL; - } else if (entry == KEY_ALLUP) { - s = IDLE; - } else if (entry == KEY_ALTGR) { - s = SHIFTKEYS+ALTGRAPH; - } else if (entry == KEY_UMLAUT) { - s = FA_UMLAUT; - } else if (entry == KEY_CFLEX) { - s = FA_CFLEX; - } else if (entry == KEY_TILDE) { - s = FA_TILDE; - } else if (entry == KEY_CEDILLA) { - s = FA_CEDILLA; - } else if (entry == KEY_ACUTE) { - s = FA_ACUTE; - } else if (entry == KEY_GRAVE) { - s = FA_GRAVE; - } else if (entry == KEY_COMPOSE) { - s = COMPOSE; - } - - return(s); -} - -int -kbdopen(dev, flags, mode, p) - dev_t dev; - int flags; - int mode; - struct proc *p; -{ - int s, error; - struct tty *tp; - - if (kbd_softc.k_events.ev_io) - return (EBUSY); - kbd_softc.k_events.ev_io = p; - /* - * If no console keyboard, tell the device to open up, maybe for - * the first time. Then make sure we know what kind of keyboard - * it is. - */ - tp = kbd_softc.k_kbd; - if (kbd_softc.k_cons == NULL) - (*kbd_softc.k_open)(tp); - error = 0; - s = spltty(); - if (kbd_softc.k_state.kbd_cur == NULL) { - (void) ttyoutput(KBD_CMD_RESET, tp); - (*tp->t_oproc)(tp); - error = tsleep((caddr_t)&kbd_softc.k_state, PZERO | PCATCH, - devopn, hz); - if (error == EWOULDBLOCK) /* no response */ - error = ENXIO; - } - splx(s); - if (error) { - kbd_softc.k_events.ev_io = NULL; - return (error); - } - ev_init(&kbd_softc.k_events); - return (0); -} - -int -kbdclose(dev, flags, mode, p) - dev_t dev; - int flags; - int mode; - struct proc *p; -{ - - /* - * Turn off event mode, dump the queue, and close the keyboard - * unless it is supplying console input. - */ - kbd_softc.k_evmode = 0; - ev_fini(&kbd_softc.k_events); - if (kbd_softc.k_cons == NULL) - (*kbd_softc.k_close)(kbd_softc.k_kbd); - kbd_softc.k_events.ev_io = NULL; - return (0); -} - -int -kbdread(dev, uio, flags) - dev_t dev; - struct uio *uio; - int flags; -{ - - return (ev_read(&kbd_softc.k_events, uio, flags)); -} - -/* this routine should not exist, but is convenient to write here for now */ -int -kbdwrite(dev, uio, flags) - dev_t dev; - struct uio *uio; - int flags; -{ - - return (EOPNOTSUPP); -} - -int -kbdioctl(dev, cmd, data, flag, p) - dev_t dev; - u_long cmd; - register caddr_t data; - int flag; - struct proc *p; -{ - register struct kbd_softc *k = &kbd_softc; - register struct kiockey *kmp; - register u_char *tp; - - switch (cmd) { - - case KIOCTRANS: - if (*(int *)data == TR_UNTRANS_EVENT) - return (0); - break; - - case KIOCGTRANS: - /* - * Get translation mode - */ - *(int *)data = TR_UNTRANS_EVENT; - return (0); - - case KIOCGETKEY: - if (((struct okiockey *)data)->kio_station == 118) { - /* - * This is X11 asking (in an inappropriate fashion) - * if a type 3 keyboard is really a type 3 keyboard. - * Say yes (inappropriately). - */ - ((struct okiockey *)data)->kio_entry = (u_char)HOLE; - return (0); - } - break; - - case KIOCSKEY: - kmp = (struct kiockey *)data; - - switch (kmp->kio_tablemask) { - case KIOC_NOMASK: - tp = kbd_unshifted; - break; - case KIOC_SHIFTMASK: - tp = kbd_shifted; - break; - case KIOC_CTRLMASK: - tp = kbd_ctrl; - break; - case KIOC_ALTGMASK: - tp = kbd_altgraph; - break; - default: - /* Silently ignore unsupported masks */ - return (0); - } - kmp->kio_entry = kbd_cnv_entry(kmp->kio_entry); - if (kmp->kio_entry & 0xff00) - /* Silently ignore funny entries */ - return (0); - - tp[kmp->kio_station] = kmp->kio_entry; - return (0); - - case KIOCGKEY: - kmp = (struct kiockey *)data; - - switch (kmp->kio_tablemask) { - case KIOC_NOMASK: - tp = kbd_unshifted; - break; - case KIOC_SHIFTMASK: - tp = kbd_shifted; - break; - case KIOC_CTRLMASK: - tp = kbd_ctrl; - break; - case KIOC_ALTGMASK: - tp = kbd_altgraph; - break; - default: - return (0); - } - kmp->kio_entry = kbd_cnv_out(tp[kmp->kio_station]); - return (0); - - case KIOCCMD: - /* - * ``unimplemented commands are ignored'' (blech) - * so cannot check return value from kbd_docmd - */ -#ifdef notyet - while (kbd_docmd(*(int *)data, 1) == ENOSPC) /*ERESTART?*/ - (void) sleep((caddr_t)&lbolt, TTOPRI); -#else - (void) kbd_docmd(*(int *)data, 1); -#endif - return (0); - - case KIOCTYPE: - *(int *)data = k->k_state.kbd_id; - return (0); - - case KIOCSDIRECT: - k->k_evmode = *(int *)data; - return (0); - - case KIOCLAYOUT: - *(unsigned int *)data = k->k_state.kbd_layout; - return (0); - - case KIOCSLED: - if (k->k_state.kbd_id != KB_SUN4) { - /* xxx NYI */ - k->k_state.kbd_leds = *(char *)data; - } else { - int s; - char leds = *(char *)data; - struct tty *tp = kbd_softc.k_kbd; - s = spltty(); - if (tp->t_outq.c_cc > 120) - (void) tsleep((caddr_t)&lbolt, TTIPRI, - ttyout, 0); - splx(s); - if (ttyoutput(KBD_CMD_SETLED, tp) >= 0) - return (ENOSPC); /* ERESTART? */ - k->k_state.kbd_leds = leds; - if (ttyoutput(leds, tp) >= 0) - return (ENOSPC); /* ERESTART? */ - (*tp->t_oproc)(tp); - } - return (0); - - case KIOCGLED: - *(char *)data = k->k_state.kbd_leds; - return (0); - - - case FIONBIO: /* we will remove this someday (soon???) */ - return (0); - - case FIOASYNC: - k->k_events.ev_async = *(int *)data != 0; - return (0); - - case TIOCSPGRP: - if (*(int *)data != k->k_events.ev_io->p_pgid) - return (EPERM); - return (0); - - default: - return (ENOTTY); - } - - /* - * We identified the ioctl, but we do not handle it. - */ - return (EOPNOTSUPP); /* misuse, but what the heck */ -} - -int -kbdselect(dev, rw, p) - dev_t dev; - int rw; - struct proc *p; -{ - - return (ev_select(&kbd_softc.k_events, rw, p)); -} - -/* - * Execute a keyboard command; return 0 on success. - * If `isuser', force a small delay before output if output queue - * is flooding. (The keyboard runs at 1200 baud, or 120 cps.) - */ -int -kbd_docmd(cmd, isuser) - int cmd; - int isuser; -{ - register struct tty *tp = kbd_softc.k_kbd; - register struct kbd_softc *k = &kbd_softc; - int s; - - if (tp == NULL) - return (ENXIO); /* ??? */ - switch (cmd) { - - case KBD_CMD_BELL: - case KBD_CMD_NOBELL: - /* Supported by type 2, 3, and 4 keyboards */ - break; - - case KBD_CMD_CLICK: - /* Unsupported by type 2 keyboards */ - if (k->k_state.kbd_id != KB_SUN2) { - k->k_state.kbd_click = 1; - break; - } - return (EINVAL); - - case KBD_CMD_NOCLICK: - /* Unsupported by type 2 keyboards */ - if (k->k_state.kbd_id != KB_SUN2) { - k->k_state.kbd_click = 0; - break; - } - return (EINVAL); - - default: - return (EINVAL); /* ENOTTY? EOPNOTSUPP? */ - } - - if (isuser) { - s = spltty(); - if (tp->t_outq.c_cc > 120) - (void) tsleep((caddr_t)&lbolt, TTIPRI, - ttyout, 0); - splx(s); - } - if (ttyoutput(cmd, tp) >= 0) - return (ENOSPC); /* ERESTART? */ - (*tp->t_oproc)(tp); - return (0); -} diff --git a/sys/arch/sparc/dev/ms.c b/sys/arch/sparc/dev/ms.c deleted file mode 100644 index db8b58043bb..00000000000 --- a/sys/arch/sparc/dev/ms.c +++ /dev/null @@ -1,357 +0,0 @@ -/* $OpenBSD: ms.c,v 1.8 2002/03/14 01:26:43 millert Exp $ */ -/* $NetBSD: ms.c,v 1.10 1996/09/12 01:36:18 mrg Exp $ */ - -/* - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This software was developed by the Computer Systems Engineering group - * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and - * contributed to Berkeley. - * - * 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, Lawrence Berkeley Laboratory. - * - * 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. - * - * @(#)ms.c 8.1 (Berkeley) 6/11/93 - */ - -/* - * Mouse driver. - */ - -#include <sys/param.h> -#include <sys/ioctl.h> -#include <sys/kernel.h> -#include <sys/proc.h> -#include <sys/syslog.h> -#include <sys/systm.h> -#include <sys/tty.h> -#include <sys/signalvar.h> -#include <sys/conf.h> - -#include <machine/vuid_event.h> -#include <machine/cpu.h> -#include <machine/kbd.h> -#include <machine/conf.h> - -#include <dev/sun/event_var.h> - -/* - * Mouse state. A Mouse Systems mouse is a fairly simple device, - * producing five-byte blobs of the form: - * - * b dx dy dx dy - * - * where b is the button state, encoded as 0x80|(~buttons)---there are - * three buttons (4=left, 2=middle, 1=right)---and dx,dy are X and Y - * delta values, none of which have are in [0x80..0x87]. (This lets - * us sync up with the mouse after an error.) - */ -struct ms_softc { - short ms_byteno; /* input byte number, for decode */ - char ms_mb; /* mouse button state */ - char ms_ub; /* user button state */ - int ms_dx; /* delta-x */ - int ms_dy; /* delta-y */ - struct tty *ms_mouse; /* downlink for output to mouse */ - void (*ms_open)(struct tty *); /* enable dataflow */ - void (*ms_close)(struct tty *);/* disable dataflow */ - volatile int ms_ready; /* event queue is ready */ - struct evvar ms_events; /* event queue state */ -} ms_softc; - -/* - * Attach the mouse serial (down-link) interface. - * The Sun 4 needs to have the baud rate set explicitly, but we handle - * that in ms_open(). - */ -void -ms_serial(tp, iopen, iclose) - struct tty *tp; - void (*iopen)(struct tty *); - void (*iclose)(struct tty *); -{ - - ms_softc.ms_mouse = tp; - ms_softc.ms_open = iopen; - ms_softc.ms_close = iclose; -} - -void -ms_rint(c) - register int c; -{ - register struct firm_event *fe; - register struct ms_softc *ms = &ms_softc; - register int mb, ub, d, get, put, any; - static const char to_one[] = { 1, 2, 2, 4, 4, 4, 4 }; - static const int to_id[] = { MS_RIGHT, MS_MIDDLE, 0, MS_LEFT }; - - /* - * Discard input if not ready. Drop sync on parity or framing - * error; gain sync on button byte. - */ - if (ms->ms_ready == 0) - return; - if (c & (TTY_FE|TTY_PE)) { - log(LOG_WARNING, - "mouse input parity or framing error (0x%x)\n", c); - ms->ms_byteno = -1; - return; - } - if ((c & ~0x0f) == 0x80) { /* if in 0x80..0x8f */ - if (c & 8) - ms->ms_byteno = 1; /* short form (3 bytes) */ - else - ms->ms_byteno = 0; /* long form (5 bytes) */ - } - - /* - * Run the decode loop, adding to the current information. - * We add, rather than replace, deltas, so that if the event queue - * fills, we accumulate data for when it opens up again. - */ - switch (ms->ms_byteno) { - - case -1: - return; - - case 0: - /* buttons (long form) */ - ms->ms_byteno = 2; - ms->ms_mb = (~c) & 0x7; - return; - - case 1: - /* buttons (short form) */ - ms->ms_byteno = 4; - ms->ms_mb = (~c) & 0x07; - return; - - case 2: - /* first delta-x */ - ms->ms_byteno = 3; - ms->ms_dx += (char)c; - return; - - case 3: - /* first delta-y */ - ms->ms_byteno = 4; - ms->ms_dy += (char)c; - return; - - case 4: - /* second delta-x */ - ms->ms_byteno = 5; - ms->ms_dx += (char)c; - break; - - case 5: - /* second delta-y */ - ms->ms_byteno = -1; /* wait for button-byte again */ - ms->ms_dy += (char)c; - break; - - default: - panic("ms_rint"); - /* NOTREACHED */ - } - - /* - * We have at least one event (mouse button, delta-X, or - * delta-Y; possibly all three, and possibly three separate - * button events). Deliver these events until we are out - * of changes or out of room. As events get delivered, - * mark them `unchanged'. - */ - any = 0; - get = ms->ms_events.ev_get; - put = ms->ms_events.ev_put; - fe = &ms->ms_events.ev_q[put]; - - /* NEXT prepares to put the next event, backing off if necessary */ -#define NEXT \ - if ((++put) % EV_QSIZE == get) { \ - put--; \ - goto out; \ - } - /* ADVANCE completes the `put' of the event */ -#define ADVANCE \ - fe++; \ - if (put >= EV_QSIZE) { \ - put = 0; \ - fe = &ms->ms_events.ev_q[0]; \ - } \ - any = 1 - - mb = ms->ms_mb; - ub = ms->ms_ub; - while ((d = mb ^ ub) != 0) { - /* - * Mouse button change. Convert up to three changes - * to the `first' change, and drop it into the event queue. - */ - NEXT; - d = to_one[d - 1]; /* from 1..7 to {1,2,4} */ - fe->id = to_id[d - 1]; /* from {1,2,4} to ID */ - fe->value = mb & d ? VKEY_DOWN : VKEY_UP; - fe->time = time; - ADVANCE; - ub ^= d; - } - if (ms->ms_dx) { - NEXT; - fe->id = LOC_X_DELTA; - fe->value = ms->ms_dx; - fe->time = time; - ADVANCE; - ms->ms_dx = 0; - } - if (ms->ms_dy) { - NEXT; - fe->id = LOC_Y_DELTA; - fe->value = ms->ms_dy; - fe->time = time; - ADVANCE; - ms->ms_dy = 0; - } -out: - if (any) { - ms->ms_ub = ub; - ms->ms_events.ev_put = put; - EV_WAKEUP(&ms->ms_events); - } -} - -int -msopen(dev, flags, mode, p) - dev_t dev; - int flags, mode; - struct proc *p; -{ - - if (ms_softc.ms_events.ev_io) - return (EBUSY); - ms_softc.ms_events.ev_io = p; - ev_init(&ms_softc.ms_events); /* may cause sleep */ - - if (CPU_ISSUN4) { - /* We need to set the baud rate on the mouse. */ - ms_softc.ms_mouse->t_ispeed = - ms_softc.ms_mouse->t_ospeed = 1200; - } - - (*ms_softc.ms_open)(ms_softc.ms_mouse); - ms_softc.ms_ready = 1; /* start accepting events */ - return (0); -} - -int -msclose(dev, flags, mode, p) - dev_t dev; - int flags, mode; - struct proc *p; -{ - - ms_softc.ms_ready = 0; /* stop accepting events */ - ev_fini(&ms_softc.ms_events); - (*ms_softc.ms_close)(ms_softc.ms_mouse); - ms_softc.ms_events.ev_io = NULL; - return (0); -} - -int -msread(dev, uio, flags) - dev_t dev; - struct uio *uio; - int flags; -{ - - return (ev_read(&ms_softc.ms_events, uio, flags)); -} - -/* this routine should not exist, but is convenient to write here for now */ -int -mswrite(dev, uio, flags) - dev_t dev; - struct uio *uio; - int flags; -{ - - return (EOPNOTSUPP); -} - -int -msioctl(dev, cmd, data, flag, p) - dev_t dev; - u_long cmd; - register caddr_t data; - int flag; - struct proc *p; -{ - switch (cmd) { - - case FIONBIO: /* we will remove this someday (soon???) */ - return (0); - - case FIOASYNC: - ms_softc.ms_events.ev_async = *(int *)data != 0; - return (0); - - case TIOCSPGRP: - if (*(int *)data != ms_softc.ms_events.ev_io->p_pgid) - return (EPERM); - return (0); - - case VUIDGFORMAT: - /* we only do firm_events */ - *(int *)data = VUID_FIRM_EVENT; - return (0); - - case VUIDSFORMAT: - if (*(int *)data != VUID_FIRM_EVENT) - return (EINVAL); - return (0); - } - return (ENOTTY); -} - -int -msselect(dev, rw, p) - dev_t dev; - int rw; - struct proc *p; -{ - - return (ev_select(&ms_softc.ms_events, rw, p)); -} diff --git a/sys/arch/sparc/dev/p9100.c b/sys/arch/sparc/dev/p9100.c index 2c3e2c7edf9..8d61cf30260 100644 --- a/sys/arch/sparc/dev/p9100.c +++ b/sys/arch/sparc/dev/p9100.c @@ -1,4 +1,4 @@ -/* $OpenBSD: p9100.c,v 1.7 2002/03/14 01:26:43 millert Exp $ */ +/* $OpenBSD: p9100.c,v 1.8 2002/08/12 10:44:04 miod Exp $ */ /* * Copyright (c) 1999 Jason L. Wright (jason@thought.net) @@ -50,13 +50,17 @@ #include <uvm/uvm_extern.h> -#include <machine/fbio.h> #include <machine/autoconf.h> #include <machine/pmap.h> -#include <machine/fbvar.h> #include <machine/cpu.h> #include <machine/conf.h> +#include <dev/wscons/wsconsio.h> +#include <dev/wscons/wsdisplayvar.h> +#include <dev/wscons/wscons_raster.h> +#include <dev/rasops/rasops.h> +#include <machine/fbvar.h> + #include <sparc/dev/btreg.h> #include <sparc/dev/btvar.h> #include <sparc/dev/sbusvar.h> @@ -68,40 +72,66 @@ /* per-display variables */ struct p9100_softc { - struct device sc_dev; /* base device */ + struct sunfb sc_sunfb; /* common base part */ struct sbusdev sc_sd; /* sbus device */ - struct fbdevice sc_fb; /* frame buffer device */ struct rom_reg sc_phys; /* phys address description */ struct p9100_cmd *sc_cmd; /* command registers (dac, etc) */ struct p9100_ctl *sc_ctl; /* control registers (draw engine) */ union bt_cmap sc_cmap; /* Brooktree color map */ u_int32_t sc_junk; /* throwaway value */ + int sc_nscreens; }; -/* autoconfiguration driver */ -void p9100attach(struct device *, struct device *, void *); -int p9100match(struct device *, void *, void *); -void p9100unblank(struct device *); +struct wsscreen_descr p9100_stdscreen = { + "std", + 0, 0, /* will be filled in */ + 0, + 0, 0, + WSSCREEN_REVERSE | WSSCREEN_WSCOLORS +}; -struct cfattach pnozz_ca = { - sizeof(struct p9100_softc), p9100match, p9100attach +const struct wsscreen_descr *p9100_scrlist[] = { + &p9100_stdscreen, }; -struct cfdriver pnozz_cd = { - NULL, "pnozz", DV_DULL +struct wsscreen_list p9100_screenlist = { + sizeof(p9100_scrlist) / sizeof(struct wsscreen_descr *), + p9100_scrlist }; -/* frame buffer generic driver */ -struct fbdriver p9100fbdriver = { - p9100unblank, p9100open, p9100close, p9100ioctl, p9100mmap +int p9100_ioctl(void *, u_long, caddr_t, int, struct proc *); +int p9100_alloc_screen(void *, const struct wsscreen_descr *, void **, + int *, int *, long *); +void p9100_free_screen(void *, void *); +int p9100_show_screen(void *, void *, int, void (*cb)(void *, int, int), + void *); +paddr_t p9100_mmap(void *, off_t, int); +void p9100_loadcmap(struct p9100_softc *, u_int, u_int); +void p9100_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t); +void p9100_burner(void *, u_int, u_int); + +struct wsdisplay_accessops p9100_accessops = { + p9100_ioctl, + p9100_mmap, + p9100_alloc_screen, + p9100_free_screen, + p9100_show_screen, + NULL, /* load_font */ + NULL, /* scrollback */ + NULL, /* getchar */ + p9100_burner, }; -extern int fbnode; -extern struct tty *fbconstty; +int p9100match(struct device *, void *, void *); +void p9100attach(struct device *, struct device *, void *); + +struct cfattach pnozz_ca = { + sizeof (struct p9100_softc), p9100match, p9100attach +}; -void p9100loadcmap(struct p9100_softc *, int, int); -void p9100_set_video(struct p9100_softc *, int); -int p9100_get_video(struct p9100_softc *); +struct cfdriver pnozz_cd = { + NULL, "pnozz", DV_DULL +}; /* * System control and command registers @@ -195,16 +225,23 @@ p9100match(parent, vcf, aux) struct device *parent; void *vcf, *aux; { + struct cfdata *cf = vcf; struct confargs *ca = aux; - register struct romaux *ra = &ca->ca_ra; + struct romaux *ra = &ca->ca_ra; + + /* + * Mask out invalid flags from the user. + */ + cf->cf_flags &= FB_USERMASK; if (strcmp("p9100", ra->ra_name)) return (0); + return (1); } /* - * Attach a display. We need to notice if it is the console, too. + * Attach a display. */ void p9100attach(parent, self, args) @@ -213,15 +250,12 @@ p9100attach(parent, self, args) { struct p9100_softc *sc = (struct p9100_softc *)self; struct confargs *ca = args; + struct wsemuldisplaydev_attach_args waa; int node = 0, i; - int isconsole; + int isconsole, fb_depth, fb_cmsize; char *cp; - sc->sc_fb.fb_driver = &p9100fbdriver; - sc->sc_fb.fb_device = &sc->sc_dev; - sc->sc_fb.fb_flags = sc->sc_dev.dv_cfdata->cf_flags & FB_USERMASK; - sc->sc_fb.fb_type.fb_type = FBTYPE_SUN3COLOR; - + sc->sc_sunfb.sf_flags = self->dv_cfdata->cf_flags; sc->sc_phys = ca->ca_ra.ra_reg[2]; sc->sc_ctl = mapiodev(&(ca->ca_ra.ra_reg[0]), 0, @@ -229,204 +263,214 @@ p9100attach(parent, self, args) sc->sc_cmd = mapiodev(&(ca->ca_ra.ra_reg[1]), 0, ca->ca_ra.ra_reg[1].rr_len); - /* - * When the ROM has mapped in a p9100 display, the address - * maps only the video RAM, so in any case we have to map the - * registers ourselves. We only need the video RAM if we are - * going to print characters via rconsole. - */ node = ca->ca_ra.ra_node; - isconsole = node == fbnode && fbconstty != NULL; - if (ca->ca_ra.ra_nvaddrs > 0) - sc->sc_fb.fb_pixels = ca->ca_ra.ra_vaddrs[0]; - if (isconsole && sc->sc_fb.fb_pixels == NULL) - sc->sc_fb.fb_pixels = mapiodev(&(ca->ca_ra.ra_reg[2]), 0, - ca->ca_ra.ra_reg[2].rr_len); + isconsole = node == fbnode; P9100_SELECT_SCR(sc); i = sc->sc_ctl->ctl_scr.scr; switch ((i >> 26) & 7) { case 5: - sc->sc_fb.fb_type.fb_depth = 32; + fb_depth = 32; break; case 7: - sc->sc_fb.fb_type.fb_depth = 24; + fb_depth = 24; break; case 3: - sc->sc_fb.fb_type.fb_depth = 16; + fb_depth = 16; break; case 2: default: - sc->sc_fb.fb_type.fb_depth = 8; + fb_depth = 8; break; } - fb_setsize(&sc->sc_fb, sc->sc_fb.fb_type.fb_depth, 800, 600, - node, ca->ca_bustype); + fb_setsize(&sc->sc_sunfb, fb_depth, 800, 600, node, ca->ca_bustype); + sc->sc_sunfb.sf_ro.ri_bits = mapiodev(&(ca->ca_ra.ra_reg[2]), 0, + round_page(sc->sc_sunfb.sf_fbsize)); + sc->sc_sunfb.sf_ro.ri_hw = sc; + fbwscons_init(&sc->sc_sunfb, isconsole); - sbus_establish(&sc->sc_sd, &sc->sc_dev); + p9100_stdscreen.nrows = sc->sc_sunfb.sf_ro.ri_rows; + p9100_stdscreen.ncols = sc->sc_sunfb.sf_ro.ri_cols; + p9100_stdscreen.textops = &sc->sc_sunfb.sf_ro.ri_ops; - sc->sc_fb.fb_type.fb_cmsize = getpropint(node, "cmsize", 256); - sc->sc_fb.fb_type.fb_size = - sc->sc_fb.fb_type.fb_height * sc->sc_fb.fb_linebytes; - printf(": rev %x, %d x %d, depth %d", i & 7, - sc->sc_fb.fb_type.fb_width, sc->sc_fb.fb_type.fb_height, - sc->sc_fb.fb_type.fb_depth); + printf(": rev %x, %dx%d, depth %d\n", i & 7, + sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height, + sc->sc_sunfb.sf_depth); + + sbus_establish(&sc->sc_sd, &sc->sc_sunfb.sf_dev); /* initialize color map */ + fb_cmsize = getpropint(node, "cmsize", 256); cp = &sc->sc_cmap.cm_map[0][0]; cp[0] = cp[1] = cp[2] = 0; - for (i = 1, cp = &sc->sc_cmap.cm_map[i][0]; - i < sc->sc_fb.fb_type.fb_cmsize; cp += 3, i++) + for (i = 1, cp = &sc->sc_cmap.cm_map[i][0]; i < fb_cmsize; cp += 3, i++) cp[0] = cp[1] = cp[2] = 0xff; - p9100loadcmap(sc, 0, 256); + p9100_loadcmap(sc, 0, 256); - /* make sure we are not blanked */ - p9100_set_video(sc, 1); + /* enable video */ + p9100_burner(sc, 1, 0); if (isconsole) { - printf(" (console)\n"); -#ifdef RASTERCONSOLE - for (i = 0 ; i < sc->sc_fb.fb_type.fb_size; i++) { - if (sc->sc_fb.fb_pixels[i] == 0) { - sc->sc_fb.fb_pixels[i] = 1; - } else if (sc->sc_fb.fb_pixels[i] == (char) 255) { - sc->sc_fb.fb_pixels[i] = 0; - } - } - p9100loadcmap(sc, 255, 1); - fbrcons_init(&sc->sc_fb); -#endif - } else - printf("\n"); - - if (node == fbnode) - fb_attach(&sc->sc_fb, isconsole); -} - -int -p9100open(dev, flags, mode, p) - dev_t dev; - int flags, mode; - struct proc *p; -{ - int unit = minor(dev); - - if (unit >= pnozz_cd.cd_ndevs || pnozz_cd.cd_devs[unit] == NULL) - return (ENXIO); - return (0); -} + fbwscons_console_init(&sc->sc_sunfb, &p9100_stdscreen, -1, + p9100_setcolor, p9100_burner); + } -int -p9100close(dev, flags, mode, p) - dev_t dev; - int flags, mode; - struct proc *p; -{ - return (0); + waa.console = isconsole; + waa.scrdata = &p9100_screenlist; + waa.accessops = &p9100_accessops; + waa.accesscookie = sc; + config_found(self, &waa, wsemuldisplaydevprint); } int -p9100ioctl(dev, cmd, data, flags, p) - dev_t dev; +p9100_ioctl(v, cmd, data, flags, p) + void *v; u_long cmd; caddr_t data; int flags; struct proc *p; { - struct p9100_softc *sc = pnozz_cd.cd_devs[minor(dev)]; - struct fbgattr *fba; + struct p9100_softc *sc = v; + struct wsdisplay_fbinfo *wdf; + struct wsdisplay_cmap *cm; int error; switch (cmd) { - case FBIOGTYPE: - *(struct fbtype *)data = sc->sc_fb.fb_type; + case WSDISPLAYIO_GTYPE: + *(u_int *)data = WSDISPLAY_TYPE_SB_P9100; break; - case FBIOGATTR: - fba = (struct fbgattr *)data; - fba->real_type = sc->sc_fb.fb_type.fb_type; - fba->owner = 0; /* XXX ??? */ - fba->fbtype = sc->sc_fb.fb_type; - fba->sattr.flags = 0; - fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type; - fba->sattr.dev_specific[0] = -1; - fba->emu_types[0] = sc->sc_fb.fb_type.fb_type; - fba->emu_types[1] = -1; + case WSDISPLAYIO_GINFO: + wdf = (struct wsdisplay_fbinfo *)data; + wdf->height = sc->sc_sunfb.sf_height; + wdf->width = sc->sc_sunfb.sf_width; + wdf->depth = sc->sc_sunfb.sf_depth; + wdf->cmsize = 256; break; - case FBIOGETCMAP: - return (bt_getcmap((struct fbcmap *)data, &sc->sc_cmap, 256)); + case WSDISPLAYIO_LINEBYTES: + *(u_int *)data = sc->sc_sunfb.sf_linebytes; + break; - case FBIOPUTCMAP: - /* copy to software map */ -#define p ((struct fbcmap *)data) - error = bt_putcmap(p, &sc->sc_cmap, 256); + case WSDISPLAYIO_GETCMAP: + cm = (struct wsdisplay_cmap *)data; + error = bt_getcmap(&sc->sc_cmap, cm); if (error) return (error); - /* now blast them into the chip */ - /* XXX should use retrace interrupt */ - p9100loadcmap(sc, p->index, p->count); -#undef p - break; - - case FBIOGVIDEO: - *(int *)data = p9100_get_video(sc); break; - case FBIOSVIDEO: - p9100_set_video(sc, *(int *)data); + case WSDISPLAYIO_PUTCMAP: + cm = (struct wsdisplay_cmap *)data; + error = bt_putcmap(&sc->sc_cmap, cm); + if (error) + return (error); + p9100_loadcmap(sc, cm->index, cm->count); break; + case WSDISPLAYIO_SVIDEO: + case WSDISPLAYIO_GVIDEO: + case WSDISPLAYIO_GCURPOS: + case WSDISPLAYIO_SCURPOS: + case WSDISPLAYIO_GCURMAX: + case WSDISPLAYIO_GCURSOR: + case WSDISPLAYIO_SCURSOR: default: - return (ENOTTY); + return (-1); /* not supported yet */ } + return (0); } -/* - * Undo the effect of an FBIOSVIDEO that turns the video off. - */ -void -p9100unblank(dev) - struct device *dev; +int +p9100_alloc_screen(v, type, cookiep, curxp, curyp, attrp) + void *v; + const struct wsscreen_descr *type; + void **cookiep; + int *curxp, *curyp; + long *attrp; { - p9100_set_video((struct p9100_softc *)dev, 1); + struct p9100_softc *sc = v; + + if (sc->sc_nscreens > 0) + return (ENOMEM); + + *cookiep = &sc->sc_sunfb.sf_ro; + *curyp = 0; + *curxp = 0; + if (sc->sc_sunfb.sf_depth == 8) { + sc->sc_sunfb.sf_ro.ri_ops.alloc_attr(&sc->sc_sunfb.sf_ro, + WSCOL_BLACK, WSCOL_WHITE, WSATTR_WSCOLORS, attrp); + } else { + sc->sc_sunfb.sf_ro.ri_ops.alloc_attr(&sc->sc_sunfb.sf_ro, + 0, 0, 0, attrp); + } + sc->sc_nscreens++; + return (0); } void -p9100_set_video(sc, enable) - struct p9100_softc *sc; - int enable; +p9100_free_screen(v, cookie) + void *v; + void *cookie; { - u_int32_t v; + struct p9100_softc *sc = v; - P9100_SELECT_VCR(sc); - v = sc->sc_ctl->ctl_vcr.srtc1; - if (enable) - v |= SRTC1_VIDEN; - else - v &= ~SRTC1_VIDEN; - sc->sc_ctl->ctl_vcr.srtc1 = v; -#if NTCTRL > 0 - tadpole_set_video(enable); -#endif + sc->sc_nscreens--; } int -p9100_get_video(sc) - struct p9100_softc *sc; +p9100_show_screen(v, cookie, waitok, cb, cbarg) + void *v; + void *cookie; + int waitok; + void (*cb)(void *, int, int); + void *cbarg; { - return ((sc->sc_ctl->ctl_vcr.srtc1 & SRTC1_VIDEN) != 0); + return (0); } /* - * Load a subset of the current (new) colormap into the Brooktree DAC. + * Return the address that would map the given device at the given + * offset, allowing for the given protection, or return -1 for error. */ +paddr_t +p9100_mmap(v, offset, prot) + void *v; + off_t offset; + int prot; +{ + struct p9100_softc *sc = v; + + if (offset & PGOFSET) + return (-1); + + if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize) { + return (REG2PHYS(&sc->sc_phys, offset) | PMAP_NC); + } + + return (-1); +} + void -p9100loadcmap(sc, start, ncolors) +p9100_setcolor(v, index, r, g, b) + void *v; + u_int index; + u_int8_t r, g, b; +{ + struct p9100_softc *sc = v; + union bt_cmap *bcm = &sc->sc_cmap; + + bcm->cm_map[index][0] = r; + bcm->cm_map[index][1] = g; + bcm->cm_map[index][2] = b; + p9100_loadcmap(sc, index, 1); +} + +void +p9100_loadcmap(sc, start, ncolors) struct p9100_softc *sc; - int start, ncolors; + u_int start, ncolors; { u_char *p; @@ -445,32 +489,26 @@ p9100loadcmap(sc, start, ncolors) } } -/* - * Return the address that would map the given device at the given - * offset, allowing for the given protection, or return -1 for error. - */ -paddr_t -p9100mmap(dev, off, prot) - dev_t dev; - off_t off; - int prot; +void +p9100_burner(v, on, flags) + void *v; + u_int on, flags; { - struct p9100_softc *sc = pnozz_cd.cd_devs[minor(dev)]; + struct p9100_softc *sc = v; + u_int32_t vcr; + int s; - if (off & PGOFSET) - panic("p9100mmap"); - - if (off < 0) - return (-1); -#define CG3_MMAP_OFFSET 0x04000000 - /* - * Make Xsun think we are a CG3 (SUN3COLOR) - */ - if ((u_int)off >= CG3_MMAP_OFFSET && - (u_int)off < CG3_MMAP_OFFSET + 0x00200000) { - off -= CG3_MMAP_OFFSET; - return (REG2PHYS(&sc->sc_phys, off | PMAP_NC)); - } - - return (-1); + s = splhigh(); + P9100_SELECT_VCR(sc); + vcr = sc->sc_ctl->ctl_vcr.srtc1; + if (on) + vcr |= SRTC1_VIDEN; + else + vcr &= ~SRTC1_VIDEN; + /* XXX - what about WSDISPLAY_BURN_VBLANK? */ + sc->sc_ctl->ctl_vcr.srtc1 = vcr; +#if NTCTRL > 0 + tadpole_set_video(on); +#endif + splx(s); } diff --git a/sys/arch/sparc/dev/pfour.c b/sys/arch/sparc/dev/pfour.c deleted file mode 100644 index 0dfe5e3e7d3..00000000000 --- a/sys/arch/sparc/dev/pfour.c +++ /dev/null @@ -1,207 +0,0 @@ -/* $OpenBSD: pfour.c,v 1.8 2002/03/14 01:26:43 millert Exp $ */ - -/* - * Copyright (c) 1995 Theo de Raadt - * 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 Theo de Raadt. - * 4. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * 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/device.h> -#include <sys/malloc.h> - -#ifdef DEBUG -#include <sys/proc.h> -#include <sys/syslog.h> -#endif - -#include <uvm/uvm_extern.h> - -#include <machine/autoconf.h> -#include <machine/pmap.h> -#include <machine/oldmon.h> -#include <machine/cpu.h> -#include <machine/ctlreg.h> -#include <sparc/sparc/asm.h> -#include <sparc/sparc/vaddrs.h> -#include <sparc/dev/pfourreg.h> - -struct pfour_softc { - struct device sc_dev; /* base device */ - volatile u_long *sc_vaddr; /* pfour register */ - int nothing; -}; - -static int pfourmatch(struct device *, void *, void *); -static void pfourattach(struct device *, struct device *, void *); -struct cfdriver pfourcd = { NULL, "pfour", pfourmatch, pfourattach, - DV_DULL, sizeof(struct pfour_softc) -}; - -int -pfourmatch(parent, vcf, aux) - struct device *parent; - void *vcf, *aux; -{ - struct cfdata *cf = vcf; - register struct confargs *ca = aux; - register struct romaux *ra = &ca->ca_ra; - - return (strcmp(cf->cf_driver->cd_name, ra->ra_name) == 0); -} - -void -pfourattach(parent, self, args) - struct device *parent, *self; - void *args; -{ - register struct pfour_softc *sc = (struct pfour_softc *)self; - extern struct cfdata cfdata[]; - register struct confargs *ca = args; - struct confargs oca; - register short *p; - struct cfdata *cf; - u_long val; - - if (sc->sc_dev.dv_unit > 0) { - printf(" unsupported\n"); - return; - } - - sc->sc_vaddr = (u_long *)mapiodev(ca->ca_ra.ra_reg, PFOUR_REG, - NBPG, ca->ca_bustype); - if (sc->sc_vaddr == NULL) { - printf("\n"); - return; - } - val = probeget(sc->sc_vaddr, 4); - - if (val == -1) { - printf(": empty\n"); - return; - } - - printf(": cardtype 0x%02x\n", PFOUR_FBTYPE(val)); - - *sc->sc_vaddr = PFOUR_REG_VIDEO | PFOUR_REG_RESET; - *sc->sc_vaddr = PFOUR_REG_VIDEO; - - for (cf = cfdata; cf->cf_driver; cf++) { - if (cf->cf_fstate == FSTATE_FOUND) - continue; - for (p = cf->cf_parents; *p >= 0; p++) - if (self->dv_cfdata == &cfdata[*p]) { - oca.ca_ra.ra_iospace = -1; - oca.ca_ra.ra_len = 0; - oca.ca_ra.ra_nreg = 1; - oca.ca_ra.ra_pfour = val; - oca.ca_ra.ra_intr[0].int_vec = -1; - oca.ca_ra.ra_nintr = 0; - oca.ca_ra.ra_name = cf->cf_driver->cd_name; - oca.ca_ra.ra_paddr = ca->ca_ra.ra_paddr; - oca.ca_bustype = BUS_PFOUR; - - if ((*cf->cf_driver->cd_match)(self, cf, &oca) == 0) - continue; - config_attach(self, cf, &oca, NULL); - } - } -} - -void -pfour_reset() -{ - struct pfour_softc *sc = pfourcd.cd_devs[0]; - - *sc->sc_vaddr = PFOUR_REG_VIDEO | PFOUR_REG_RESET; - delay(1); - *sc->sc_vaddr = PFOUR_REG_VIDEO; -} - -int -pfour_videosize(reg, xp, yp) - int reg; - int *xp, *yp; -{ - if (PFOUR_ID(reg) == PFOUR_ID_COLOR24) { - *xp = 1152; - *yp = 900; - return 0; - } - - switch (PFOUR_SIZE(reg)) { - case PFOUR_SIZE_1152X900: - *xp = 1152; - *yp = 900; - break; - case PFOUR_SIZE_1024X1024: - *xp = 1024; - *yp = 1024; - break; - case PFOUR_SIZE_1280X1024: - *xp = 1280; - *yp = 1024; - break; - case PFOUR_SIZE_1600X1280: - *xp = 1600; - *yp = 1280; - break; - case PFOUR_SIZE_1440X1440: - *xp = 1440; - *yp = 1440; - break; - case PFOUR_SIZE_640X480: - *xp = 640; - *yp = 480; - break; - default: - *xp = 1152; /* assume, but indicate error */ - *yp = 900; - return (-1); - } - return (0); -} - -void -pfourenable(on) - int on; -{ - struct pfour_softc *sc = pfourcd.cd_devs[0]; - - if (on) - *sc->sc_vaddr |= PFOUR_REG_VIDEO; - else - *sc->sc_vaddr &= ~PFOUR_REG_VIDEO; -} - -int -pfourstatus() -{ - struct pfour_softc *sc = pfourcd.cd_devs[0]; - - return (*sc->sc_vaddr & PFOUR_REG_VIDEO); -} diff --git a/sys/arch/sparc/dev/tcx.c b/sys/arch/sparc/dev/tcx.c index ef8f0b120ce..a3eb138a941 100644 --- a/sys/arch/sparc/dev/tcx.c +++ b/sys/arch/sparc/dev/tcx.c @@ -1,13 +1,37 @@ -/* $OpenBSD: tcx.c,v 1.6 2002/03/14 01:26:43 millert Exp $ */ +/* $OpenBSD: tcx.c,v 1.7 2002/08/12 10:44:04 miod Exp $ */ /* $NetBSD: tcx.c,v 1.8 1997/07/29 09:58:14 fair Exp $ */ -/* +/* + * Copyright (c) 2002 Miodrag Vallat. 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. + * + * * Copyright (c) 1996 The NetBSD Foundation, Inc. * All rights reserved. - * + * * This code is derived from software contributed to The NetBSD Foundation * by Paul Kranenburg. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -23,7 +47,7 @@ * 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 @@ -35,78 +59,108 @@ * 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. - */ + */ /* * color display (TCX) driver. - * - * Does not handle interrupts, even though they can occur. - * - * XXX should defer colormap updates to vertical retrace interrupts */ #include <sys/param.h> #include <sys/systm.h> #include <sys/buf.h> #include <sys/device.h> -#include <machine/fbio.h> #include <sys/ioctl.h> #include <sys/malloc.h> #include <sys/mman.h> #include <sys/tty.h> #include <sys/conf.h> -#ifdef DEBUG -#include <sys/proc.h> -#include <sys/syslog.h> -#endif - #include <uvm/uvm_extern.h> #include <machine/autoconf.h> #include <machine/pmap.h> -#include <machine/fbvar.h> #include <machine/cpu.h> #include <machine/conf.h> +#include <dev/wscons/wsconsio.h> +#include <dev/wscons/wsdisplayvar.h> +#include <dev/wscons/wscons_raster.h> +#include <dev/rasops/rasops.h> +#include <machine/fbvar.h> + #include <sparc/dev/btreg.h> #include <sparc/dev/btvar.h> #include <sparc/dev/tcxreg.h> #include <sparc/dev/sbusvar.h> -#if 0 -union cursor_cmap { /* colormap, like bt_cmap, but tiny */ - u_char cm_map[2][3]; /* 2 R/G/B entries */ - u_int cm_chip[2]; /* 2 chip equivalents */ -}; +#include <dev/cons.h> /* for prom console hook */ -struct tcx_cursor { /* tcx hardware cursor status */ - short cc_enable; /* cursor is enabled */ - struct fbcurpos cc_pos; /* position */ - struct fbcurpos cc_hot; /* hot-spot */ - struct fbcurpos cc_size; /* size of mask & image fields */ - u_int cc_bits[2][32]; /* space for mask & image bits */ - union cursor_cmap cc_color; /* cursor colormap */ -}; +/* + * Define TCX_LOWDEPTH to only use the 8 bit color mode of the S24, for faster + * console output. + */ +#ifdef SMALL_KERNEL +#define TCX_LOWDEPTH #endif /* per-display variables */ struct tcx_softc { - struct device sc_dev; /* base device */ - struct sbusdev sc_sd; /* sbus device */ - struct fbdevice sc_fb; /* frame buffer device */ - struct rom_reg sc_physadr[TCX_NREG]; /* phys addr of h/w */ - int sc_bustype; /* type of bus we live on */ + struct sunfb sc_sunfb; /* common base part */ + struct sbusdev sc_sd; /* sbus device */ + struct rom_reg sc_phys[TCX_NREG]; /* phys addr of h/w */ volatile struct bt_regs *sc_bt; /* Brooktree registers */ volatile struct tcx_thc *sc_thc; /* THC registers */ - short sc_blanked; /* true if blanked */ - union bt_cmap sc_cmap; /* Brooktree color map */ + volatile u_int32_t *sc_cplane; /* S24 control plane */ + union bt_cmap sc_cmap; /* Brooktree color map */ + struct intrhand sc_ih; + int sc_nscreens; }; -/* autoconfiguration driver */ -static void tcxattach(struct device *, struct device *, void *); -static int tcxmatch(struct device *, void *, void *); -static void tcx_unblank(struct device *); +struct wsscreen_descr tcx_stdscreen = { + "std", + 0, 0, /* will be filled in */ + 0, + 0, 0, + WSSCREEN_REVERSE | WSSCREEN_WSCOLORS +}; + +const struct wsscreen_descr *tcx_scrlist[] = { + &tcx_stdscreen, + /* XXX other formats? */ +}; + +struct wsscreen_list tcx_screenlist = { + sizeof(tcx_scrlist) / sizeof(struct wsscreen_descr *), tcx_scrlist +}; + +int tcx_ioctl(void *, u_long, caddr_t, int, struct proc *); +int tcx_alloc_screen(void *, const struct wsscreen_descr *, void **, + int *, int *, long *); +void tcx_free_screen(void *, void *); +int tcx_show_screen(void *, void *, int, void (*cb)(void *, int, int), + void *); +paddr_t tcx_mmap(void *, off_t, int); +void tcx_reset(struct tcx_softc *); +void tcx_burner(void *, u_int, u_int); +void tcx_setcolor(void *, u_int, u_int8_t, u_int8_t, u_int8_t); +static __inline__ void tcx_loadcmap_deferred(struct tcx_softc *, u_int, u_int); +int tcx_intr(void *); +void tcx_prom(void *); + +struct wsdisplay_accessops tcx_accessops = { + tcx_ioctl, + tcx_mmap, + tcx_alloc_screen, + tcx_free_screen, + tcx_show_screen, + NULL, /* load_font */ + NULL, /* scrollback */ + NULL, /* getchar */ + tcx_burner, +}; + +int tcxmatch(struct device *, void *, void *); +void tcxattach(struct device *, struct device *, void *); struct cfattach tcx_ca = { sizeof(struct tcx_softc), tcxmatch, tcxattach @@ -116,17 +170,24 @@ struct cfdriver tcx_cd = { NULL, "tcx", DV_DULL }; -/* frame buffer generic driver */ -static struct fbdriver tcx_fbdriver = { - tcx_unblank, tcxopen, tcxclose, tcxioctl, tcxmmap -}; - -extern int fbnode; - -static void tcx_reset(struct tcx_softc *); -static void tcx_loadcmap(struct tcx_softc *, int, int); +/* + * There are three ways to access the framebuffer memory of the S24: + * - 26 bits per pixel, in 32-bit words; the low-order 24 bits are blue, + * green and red values, and the other two bits select the display modes, + * per pixel. + * - 24 bits per pixel, in 32-bit words; the high-order byte reads as zero, + * and is ignored on writes (so the mode bits can not be altered). + * - 8 bits per pixel, unpadded; writes to this space do not modify the + * other 18 bits, which are hidden. + * + * The entry-level tcx found on the SPARCstation 4 can only provide the 8-bit + * mode. + */ +#define TCX_CTL_8_MAPPED 0x00000000 /* 8 bits, uses colormap */ +#define TCX_CTL_24_MAPPED 0x01000000 /* 24 bits, uses colormap */ +#define TCX_CTL_24_LEVEL 0x03000000 /* 24 bits, true color */ +#define TCX_CTL_PIXELMASK 0x00ffffff /* mask for index/level */ -#define OBPNAME "SUNW,tcx" /* * Match a tcx. */ @@ -139,14 +200,14 @@ tcxmatch(parent, vcf, aux) struct confargs *ca = aux; struct romaux *ra = &ca->ca_ra; - if (strcmp(ra->ra_name, OBPNAME)) - return (0); - /* * Mask out invalid flags from the user. */ cf->cf_flags &= FB_USERMASK; + if (strcmp(ra->ra_name, "SUNW,tcx")) + return (0); + if (ca->ca_bustype == BUS_SBUS) return (1); @@ -161,337 +222,381 @@ tcxattach(parent, self, args) struct device *parent, *self; void *args; { - register struct tcx_softc *sc = (struct tcx_softc *)self; - register struct confargs *ca = args; - register int node = 0, ramsize, i; - register volatile struct bt_regs *bt; - struct fbdevice *fb = &sc->sc_fb; - int isconsole = 0, sbus = 1; - extern struct tty *fbconstty; - - fb->fb_driver = &tcx_fbdriver; - fb->fb_device = &sc->sc_dev; - fb->fb_flags = sc->sc_dev.dv_cfdata->cf_flags; + struct tcx_softc *sc = (struct tcx_softc *)self; + struct confargs *ca = args; + struct wsemuldisplaydev_attach_args waa; + int node = 0, i; + volatile struct bt_regs *bt; + int isconsole = 0; + char *nam = NULL; - /* - * XXX - should be set to FBTYPE_TCX. - * XXX For CG3 emulation to work in current (96/6) X11 servers, - * XXX `fbtype' must point to an "unregocnised" entry. - */ - fb->fb_type.fb_type = FBTYPE_RESERVED3; + sc->sc_sunfb.sf_flags = self->dv_cfdata->cf_flags; - if (ca->ca_ra.ra_nreg != TCX_NREG) - panic("tcx: oops"); + if (ca->ca_ra.ra_nreg < TCX_NREG) + panic("\ntcx: expected %d registers, got %d", TCX_NREG, + ca->ca_ra.ra_nreg); /* Copy register address spaces */ for (i = 0; i < TCX_NREG; i++) - sc->sc_physadr[i] = ca->ca_ra.ra_reg[i]; - - /* XXX - fix THC and TEC offsets */ - sc->sc_physadr[TCX_REG_TEC].rr_paddr += 0x1000; - sc->sc_physadr[TCX_REG_THC].rr_paddr += 0x1000; + sc->sc_phys[i] = ca->ca_ra.ra_reg[i]; sc->sc_bt = bt = (volatile struct bt_regs *) - mapiodev(&ca->ca_ra.ra_reg[TCX_REG_CMAP], 0, sizeof *sc->sc_bt); + mapiodev(&ca->ca_ra.ra_reg[TCX_REG_CMAP], 0, sizeof *sc->sc_bt); sc->sc_thc = (volatile struct tcx_thc *) - mapiodev(&ca->ca_ra.ra_reg[TCX_REG_THC], 0, sizeof *sc->sc_thc); + mapiodev(&ca->ca_ra.ra_reg[TCX_REG_THC], + 0x1000, sizeof *sc->sc_thc); switch (ca->ca_bustype) { case BUS_SBUS: node = ca->ca_ra.ra_node; + nam = getpropstring(node, "model"); break; - case BUS_OBIO: default: printf("TCX on bus 0x%x?\n", ca->ca_bustype); return; } - fb->fb_type.fb_depth = node_has_property(node, "tcx-24-bit") - ? 24 - : (node_has_property(node, "tcx-8-bit") - ? 8 - : 8); - - fb_setsize(fb, fb->fb_type.fb_depth, 1152, 900, - node, ca->ca_bustype); + printf(": %s\n", nam); - ramsize = fb->fb_type.fb_height * fb->fb_linebytes; - fb->fb_type.fb_cmsize = 256; - fb->fb_type.fb_size = ramsize; - printf(": %s, %d x %d", OBPNAME, - fb->fb_type.fb_width, - fb->fb_type.fb_height); + isconsole = node == fbnode; - isconsole = node == fbnode && fbconstty != NULL; +#ifdef TCX_LOWDEPTH + fb_setsize(&sc->sc_sunfb, 8, 1152, 900, node, ca->ca_bustype); +#else + fb_setsize(&sc->sc_sunfb, node_has_property(node, "tcx-8-bit") ? + 8 : 32, 1152, 900, node, ca->ca_bustype); +#endif - printf(", id %d, rev %d, sense %d", - (sc->sc_thc->thc_config & THC_CFG_FBID) >> THC_CFG_FBID_SHIFT, - (sc->sc_thc->thc_config & THC_CFG_REV) >> THC_CFG_REV_SHIFT, - (sc->sc_thc->thc_config & THC_CFG_SENSE) >> THC_CFG_SENSE_SHIFT - ); + sc->sc_sunfb.sf_ro.ri_bits = mapiodev(&ca->ca_ra.ra_reg[ + sc->sc_sunfb.sf_depth == 8 ? TCX_REG_DFB8 : TCX_REG_DFB24], + 0, round_page(sc->sc_sunfb.sf_fbsize)); + + /* map the control plane for S24 framebuffers */ + if (sc->sc_sunfb.sf_depth != 8) { + sc->sc_cplane = mapiodev(&ca->ca_ra.ra_reg[TCX_REG_RDFB32], + 0, round_page(sc->sc_sunfb.sf_fbsize)); + } /* reset cursor & frame buffer controls */ tcx_reset(sc); - /* grab initial (current) color map (DOES THIS WORK?) */ + /* grab initial (current) color map */ bt->bt_addr = 0; for (i = 0; i < 256 * 3; i++) ((char *)&sc->sc_cmap)[i] = bt->bt_cmap >> 24; /* enable video */ - sc->sc_thc->thc_hcmisc |= THC_MISC_VIDEN; + tcx_burner(sc, 1, 0); - if (isconsole) { - printf(" (console)\n"); - } else - printf("\n"); - - if (sbus) - sbus_establish(&sc->sc_sd, &sc->sc_dev); - if (node == fbnode) - fb_attach(&sc->sc_fb, isconsole); -} + sc->sc_sunfb.sf_ro.ri_hw = sc; + fbwscons_init(&sc->sc_sunfb, isconsole); -int -tcxopen(dev, flags, mode, p) - dev_t dev; - int flags, mode; - struct proc *p; -{ - int unit = minor(dev); + tcx_stdscreen.nrows = sc->sc_sunfb.sf_ro.ri_rows; + tcx_stdscreen.ncols = sc->sc_sunfb.sf_ro.ri_cols; + tcx_stdscreen.textops = &sc->sc_sunfb.sf_ro.ri_ops; - if (unit >= tcx_cd.cd_ndevs || tcx_cd.cd_devs[unit] == NULL) - return (ENXIO); - return (0); -} + sc->sc_ih.ih_fun = tcx_intr; + sc->sc_ih.ih_arg = sc; + intr_establish(ca->ca_ra.ra_intr[0].int_pri, &sc->sc_ih, IPL_FB); -int -tcxclose(dev, flags, mode, p) - dev_t dev; - int flags, mode; - struct proc *p; -{ - struct tcx_softc *sc = tcx_cd.cd_devs[minor(dev)]; + if (isconsole) { + fbwscons_console_init(&sc->sc_sunfb, &tcx_stdscreen, -1, + tcx_setcolor, tcx_burner); + } - tcx_reset(sc); - return (0); + sbus_establish(&sc->sc_sd, &sc->sc_sunfb.sf_dev); + + printf("%s: %dx%d, depth %d, id %d, rev %d, sense %d\n", + self->dv_xname, sc->sc_sunfb.sf_width, sc->sc_sunfb.sf_height, + sc->sc_sunfb.sf_depth, + (sc->sc_thc->thc_config & THC_CFG_FBID) >> THC_CFG_FBID_SHIFT, + (sc->sc_thc->thc_config & THC_CFG_REV) >> THC_CFG_REV_SHIFT, + (sc->sc_thc->thc_config & THC_CFG_SENSE) >> THC_CFG_SENSE_SHIFT + ); + + waa.console = isconsole; + waa.scrdata = &tcx_screenlist; + waa.accessops = &tcx_accessops; + waa.accesscookie = sc; + config_found(self, &waa, wsemuldisplaydevprint); } int -tcxioctl(dev, cmd, data, flags, p) - dev_t dev; +tcx_ioctl(dev, cmd, data, flags, p) + void *dev; u_long cmd; - register caddr_t data; + caddr_t data; int flags; struct proc *p; { - register struct tcx_softc *sc = tcx_cd.cd_devs[minor(dev)]; + struct tcx_softc *sc = dev; + struct wsdisplay_cmap *cm; + struct wsdisplay_fbinfo *wdf; int error; switch (cmd) { - - case FBIOGTYPE: - *(struct fbtype *)data = sc->sc_fb.fb_type; + case WSDISPLAYIO_GTYPE: + *(u_int *)data = WSDISPLAY_TYPE_SUN24; break; - - case FBIOGATTR: -#define fba ((struct fbgattr *)data) - fba->real_type = sc->sc_fb.fb_type.fb_type; - fba->owner = 0; /* XXX ??? */ - fba->fbtype = sc->sc_fb.fb_type; - fba->sattr.flags = 0; - fba->sattr.emu_type = sc->sc_fb.fb_type.fb_type; - fba->sattr.dev_specific[0] = -1; - fba->emu_types[0] = sc->sc_fb.fb_type.fb_type; - fba->emu_types[1] = FBTYPE_SUN3COLOR; - fba->emu_types[2] = -1; -#undef fba + case WSDISPLAYIO_GINFO: + wdf = (struct wsdisplay_fbinfo *)data; + wdf->height = sc->sc_sunfb.sf_height; + wdf->width = sc->sc_sunfb.sf_width; + wdf->depth = sc->sc_sunfb.sf_depth; + wdf->cmsize = (sc->sc_sunfb.sf_depth == 8) ? 256 : 0; break; - - case FBIOGETCMAP: - return (bt_getcmap((struct fbcmap *)data, &sc->sc_cmap, 256)); - - case FBIOPUTCMAP: - /* copy to software map */ -#define p ((struct fbcmap *)data) - error = bt_putcmap(p, &sc->sc_cmap, 256); - if (error) - return (error); - /* now blast them into the chip */ - /* XXX should use retrace interrupt */ - tcx_loadcmap(sc, p->index, p->count); -#undef p + case WSDISPLAYIO_LINEBYTES: + *(u_int *)data = sc->sc_sunfb.sf_linebytes; break; - case FBIOGVIDEO: - *(int *)data = sc->sc_blanked; + case WSDISPLAYIO_GETCMAP: + if (sc->sc_sunfb.sf_depth == 8) { + cm = (struct wsdisplay_cmap *)data; + error = bt_getcmap(&sc->sc_cmap, cm); + if (error) + return (error); + } break; - - case FBIOSVIDEO: - if (*(int *)data) - tcx_unblank(&sc->sc_dev); - else if (!sc->sc_blanked) { - sc->sc_blanked = 1; - sc->sc_thc->thc_hcmisc &= ~THC_MISC_VIDEN; - /* Put monitor in `power-saving mode' */ - sc->sc_thc->thc_hcmisc |= THC_MISC_VSYNC_DISABLE; - sc->sc_thc->thc_hcmisc |= THC_MISC_HSYNC_DISABLE; + case WSDISPLAYIO_PUTCMAP: + if (sc->sc_sunfb.sf_depth == 8) { + cm = (struct wsdisplay_cmap *)data; + error = bt_putcmap(&sc->sc_cmap, cm); + if (error) + return (error); + tcx_loadcmap_deferred(sc, cm->index, cm->count); } break; + case WSDISPLAYIO_SVIDEO: + case WSDISPLAYIO_GVIDEO: + case WSDISPLAYIO_GCURPOS: + case WSDISPLAYIO_SCURPOS: + case WSDISPLAYIO_GCURMAX: + case WSDISPLAYIO_GCURSOR: + case WSDISPLAYIO_SCURSOR: default: -#ifdef DEBUG - log(LOG_NOTICE, "tcxioctl(0x%lx) (%s[%d])\n", cmd, - p->p_comm, p->p_pid); -#endif - return (ENOTTY); + return (-1); /* not supported yet */ } + return (0); } /* * Clean up hardware state (e.g., after bootup or after X crashes). */ -static void +void tcx_reset(sc) - register struct tcx_softc *sc; + struct tcx_softc *sc; { - register volatile struct bt_regs *bt; + volatile struct bt_regs *bt; + + /* Hide the cursor, just in case */ + sc->sc_thc->thc_cursoraddr = THC_CURSOFF; /* Enable cursor in Brooktree DAC. */ bt = sc->sc_bt; bt->bt_addr = 0x06 << 24; bt->bt_ctrl |= 0x03 << 24; -} -/* - * Load a subset of the current (new) colormap into the color DAC. - */ -static void -tcx_loadcmap(sc, start, ncolors) - register struct tcx_softc *sc; - register int start, ncolors; -{ - register volatile struct bt_regs *bt; - register u_int *ip, i; - register int count; + /* + * Select 24-bit mode if appropriate. + */ + if (sc->sc_sunfb.sf_depth != 8) { + volatile u_int32_t *cptr; + u_int32_t pixel; + int ramsize; + + ramsize = sc->sc_sunfb.sf_fbsize / sizeof(u_int32_t); + cptr = sc->sc_cplane; + + /* + * Since the prom output so far has only been white (0) + * or black (255), we can promote the 8 bit plane contents + * to full color. + * Of course, the 24 bit plane uses 0 for black, so a + * reversal is necessary. Blame Sun. + */ + while (ramsize-- != 0) { + pixel = 255 - ((*cptr & TCX_CTL_PIXELMASK) & 0xff); + pixel = (pixel << 16) | (pixel << 8) | pixel; + *cptr++ = pixel | TCX_CTL_24_LEVEL; + } - ip = &sc->sc_cmap.cm_chip[BT_D4M3(start)]; /* start/4 * 3 */ - count = BT_D4M3(start + ncolors - 1) - BT_D4M3(start) + 3; - bt = sc->sc_bt; - bt->bt_addr = BT_D4M4(start) << 24; - while (--count >= 0) { - i = *ip++; - /* hardware that makes one want to pound boards with hammers */ - bt->bt_cmap = i; - bt->bt_cmap = i << 8; - bt->bt_cmap = i << 16; - bt->bt_cmap = i << 24; + shutdownhook_establish(tcx_prom, sc); } } -static void -tcx_unblank(dev) - struct device *dev; +void +tcx_prom(v) + void *v; { - struct tcx_softc *sc = (struct tcx_softc *)dev; + struct tcx_softc *sc = v; + extern struct consdev consdev_prom; + + /* + * Select 8-bit mode. + */ + if (sc->sc_sunfb.sf_depth != 8) { + volatile u_int32_t *cptr; + u_int32_t pixel; + int ramsize; + + ramsize = sc->sc_sunfb.sf_fbsize / sizeof(u_int32_t); + cptr = sc->sc_cplane; - if (sc->sc_blanked) { - sc->sc_blanked = 0; - sc->sc_thc->thc_hcmisc &= ~THC_MISC_VSYNC_DISABLE; - sc->sc_thc->thc_hcmisc &= ~THC_MISC_HSYNC_DISABLE; - sc->sc_thc->thc_hcmisc |= THC_MISC_VIDEN; + while (ramsize-- != 0) { + pixel = (*cptr & TCX_CTL_PIXELMASK); + *cptr++ = pixel | TCX_CTL_8_MAPPED; + } } + + /* + * Go back to prom output for the last few messages, so they + * will be displayed correctly. + */ + cn_tab = &consdev_prom; } -/* - * Base addresses at which users can mmap() the various pieces of a tcx. - */ -#define TCX_USER_RAM 0x00000000 -#define TCX_USER_RAM24 0x01000000 -#define TCX_USER_RAM_COMPAT 0x04000000 /* cg3 emulation */ -#define TCX_USER_STIP 0x10000000 -#define TCX_USER_BLIT 0x20000000 -#define TCX_USER_RDFB32 0x28000000 -#define TCX_USER_RSTIP 0x30000000 -#define TCX_USER_RBLIT 0x38000000 -#define TCX_USER_TEC 0x70001000 -#define TCX_USER_BTREGS 0x70002000 -#define TCX_USER_THC 0x70004000 -#define TCX_USER_DHC 0x70008000 -#define TCX_USER_ALT 0x7000a000 -#define TCX_USER_UART 0x7000c000 -#define TCX_USER_VRT 0x7000e000 -#define TCX_USER_ROM 0x70010000 - -struct mmo { - u_int mo_uaddr; /* user (virtual) address */ - u_int mo_size; /* size, or 0 for video ram size */ - u_int mo_bank; /* register bank number */ -}; +void +tcx_burner(v, on, flags) + void *v; + u_int on, flags; +{ + struct tcx_softc *sc = v; + int s; + u_int32_t thcm; + + s = splhigh(); + thcm = sc->sc_thc->thc_hcmisc; + if (on) { + thcm |= THC_MISC_VIDEN; + thcm &= ~(THC_MISC_VSYNC_DISABLE | THC_MISC_HSYNC_DISABLE); + } else { + thcm &= ~THC_MISC_VIDEN; + if (flags & WSDISPLAY_BURN_VBLANK) + thcm |= THC_MISC_VSYNC_DISABLE | THC_MISC_HSYNC_DISABLE; + } + sc->sc_thc->thc_hcmisc = thcm; + splx(s); +} /* * Return the address that would map the given device at the given * offset, allowing for the given protection, or return -1 for error. - * - * XXX needs testing against `demanding' applications (e.g., aviator) */ paddr_t -tcxmmap(dev, off, prot) - dev_t dev; - off_t off; +tcx_mmap(v, offset, prot) + void *v; + off_t offset; int prot; { - register struct tcx_softc *sc = tcx_cd.cd_devs[minor(dev)]; - register struct mmo *mo; - register u_int u, sz; - static struct mmo mmo[] = { - { TCX_USER_RAM, 0, TCX_REG_DFB8 }, - { TCX_USER_RAM24, 0, TCX_REG_DFB24 }, - { TCX_USER_RAM_COMPAT, 0, TCX_REG_DFB8 }, - - { TCX_USER_STIP, 1, TCX_REG_STIP }, - { TCX_USER_BLIT, 1, TCX_REG_BLIT }, - { TCX_USER_RDFB32, 1, TCX_REG_RDFB32 }, - { TCX_USER_RSTIP, 1, TCX_REG_RSTIP }, - { TCX_USER_RBLIT, 1, TCX_REG_RBLIT }, - { TCX_USER_TEC, 1, TCX_REG_TEC }, - { TCX_USER_BTREGS, 8192 /* XXX */, TCX_REG_CMAP }, - { TCX_USER_THC, sizeof(struct tcx_thc), TCX_REG_THC }, - { TCX_USER_DHC, 1, TCX_REG_DHC }, - { TCX_USER_ALT, 1, TCX_REG_ALT }, - { TCX_USER_ROM, 65536, TCX_REG_ROM }, - }; -#define NMMO (sizeof mmo / sizeof *mmo) - - if (off & PGOFSET) - panic("tcxmmap"); - - if (off < 0) + struct tcx_softc *sc = v; + int reg; + + if (offset & PGOFSET) return (-1); - /* - * Entries with size 0 map video RAM (i.e., the size in fb data). - * - * Since we work in pages, the fact that the map offset table's - * sizes are sometimes bizarre (e.g., 1) is effectively ignored: - * one byte is as good as one page. - */ - for (mo = mmo; mo < &mmo[NMMO]; mo++) { - if ((u_int)off < mo->mo_uaddr) - continue; - u = off - mo->mo_uaddr; - sz = mo->mo_size ? mo->mo_size : sc->sc_fb.fb_type.fb_size; - if (u < sz) - return (REG2PHYS(&sc->sc_physadr[mo->mo_bank], u) | - PMAP_NC); + /* Allow mapping as a dumb framebuffer from offset 0 */ + if (offset >= 0 && offset < sc->sc_sunfb.sf_fbsize) { + reg = (sc->sc_sunfb.sf_depth == 8) ? + TCX_REG_DFB8 : TCX_REG_DFB24; + return (REG2PHYS(&sc->sc_phys[reg], offset) | PMAP_NC); } -#ifdef DEBUG - { - register struct proc *p = curproc; /* XXX */ - log(LOG_NOTICE, "tcxmmap(0x%x) (%s[%d])\n", off, p->p_comm, p->p_pid); - } -#endif + return (-1); /* not a user-map offset */ } + +void +tcx_setcolor(v, index, r, g, b) + void *v; + u_int index; + u_int8_t r, g, b; +{ + struct tcx_softc *sc = v; + + bt_setcolor(&sc->sc_cmap, sc->sc_bt, index, r, g, b, 1); +} + +int +tcx_alloc_screen(v, type, cookiep, curxp, curyp, attrp) + void *v; + const struct wsscreen_descr *type; + void **cookiep; + int *curxp, *curyp; + long *attrp; +{ + struct tcx_softc *sc = v; + + if (sc->sc_nscreens > 0) + return (ENOMEM); + + *cookiep = &sc->sc_sunfb.sf_ro; + *curyp = 0; + *curxp = 0; + if (sc->sc_sunfb.sf_depth == 8) { + sc->sc_sunfb.sf_ro.ri_ops.alloc_attr(&sc->sc_sunfb.sf_ro, + WSCOL_BLACK, WSCOL_WHITE, WSATTR_WSCOLORS, attrp); + } else { + sc->sc_sunfb.sf_ro.ri_ops.alloc_attr(&sc->sc_sunfb.sf_ro, + 0, 0, 0, attrp); + } + sc->sc_nscreens++; + return (0); +} + +void +tcx_free_screen(v, cookie) + void *v; + void *cookie; +{ + struct tcx_softc *sc = v; + + sc->sc_nscreens--; +} + +int +tcx_show_screen(v, cookie, waitok, cb, cbarg) + void *v; + void *cookie; + int waitok; + void (*cb)(void *, int, int); + void *cbarg; +{ + return (0); +} + +static __inline__ void +tcx_loadcmap_deferred(struct tcx_softc *sc, u_int start, u_int ncolors) +{ + u_int32_t thcm; + + thcm = sc->sc_thc->thc_hcmisc; + thcm &= ~THC_MISC_RESET; + thcm |= THC_MISC_INTEN; + sc->sc_thc->thc_hcmisc = thcm; +} + +int +tcx_intr(v) + void *v; +{ + struct tcx_softc *sc = v; + u_int32_t thcm; + + thcm = sc->sc_thc->thc_hcmisc; + if ((thcm & (THC_MISC_INTEN | THC_MISC_INTR)) != + (THC_MISC_INTEN | THC_MISC_INTR)) { + /* Not expecting an interrupt, it's not for us. */ + return (0); + } + + /* Acknowledge the interrupt and disable it. */ + thcm &= ~(THC_MISC_RESET | THC_MISC_INTEN); + thcm |= THC_MISC_INTR; + sc->sc_thc->thc_hcmisc = thcm; + + bt_loadcmap(&sc->sc_cmap, sc->sc_bt, 0, 256, 1); + + return (1); +} diff --git a/sys/arch/sparc/dev/tcxreg.h b/sys/arch/sparc/dev/tcxreg.h index ef48a21955c..0324d4c13de 100644 --- a/sys/arch/sparc/dev/tcxreg.h +++ b/sys/arch/sparc/dev/tcxreg.h @@ -1,12 +1,13 @@ -/* $OpenBSD: tcxreg.h,v 1.1 1997/08/08 08:25:32 downsj Exp $ */ +/* $OpenBSD: tcxreg.h,v 1.2 2002/08/12 10:44:04 miod Exp $ */ /* $NetBSD: tcxreg.h,v 1.1 1996/06/19 13:17:35 pk Exp $ */ -/* + +/* * Copyright (c) 1996 The NetBSD Foundation, Inc. * All rights reserved. - * + * * This code is derived from software contributed to The NetBSD Foundation * by Paul Kranenburg. - * + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -22,7 +23,7 @@ * 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 @@ -34,7 +35,7 @@ * 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. - */ + */ /* * A TCX is composed of numerous groups of control registers, all with TLAs: @@ -73,22 +74,26 @@ * The layout of the THC. */ struct tcx_thc { - u_int thc_config; - u_int thc_xxx1[31]; - u_int thc_sensebus; - u_int thc_xxx2[3]; - u_int thc_delay; - u_int thc_strapping; - u_int thc_xxx3[1]; - u_int thc_linecount; - u_int thc_xxx4[478]; - u_int thc_hcmisc; - u_int thc_xxx5[56]; - u_int thc_cursoraddr; - u_int thc_cursorAdata[32]; - u_int thc_cursorBdata[32]; + u_int32_t thc_config; + u_int32_t thc_xxx1[31]; + u_int32_t thc_sensebus; + u_int32_t thc_xxx2[3]; + u_int32_t thc_delay; + u_int32_t thc_strapping; + u_int32_t thc_xxx3[1]; + u_int32_t thc_linecount; + u_int32_t thc_xxx4[478]; + u_int32_t thc_hcmisc; + u_int32_t thc_xxx5[56]; + u_int32_t thc_cursoraddr; + u_int32_t thc_cursorAdata[32]; + u_int32_t thc_cursorBdata[32]; }; + +/* cursor x/y position for 'off' */ +#define THC_CURSOFF ((65536-32) | ((65536-32) << 16)) + /* bits in thc_config ??? */ #define THC_CFG_FBID 0xf0000000 /* id mask */ #define THC_CFG_FBID_SHIFT 28 @@ -105,47 +110,44 @@ struct tcx_thc { #define THC_MISC_HSYNC_LEVEL 0x04000000 /* hsync level when disabled */ #define THC_MISC_VSYNC_DISABLE 0x02000000 /* vsync disable */ #define THC_MISC_HSYNC_DISABLE 0x01000000 /* hsync disable */ -#define THC_MISC_XXX1 0x00ffe000 /* unused */ -#define THC_MISC_RESET 0x00001000 /* ??? */ -#define THC_MISC_XXX2 0x00000800 /* unused */ +#define THC_MISC_RESET 0x00001000 /* reset */ #define THC_MISC_VIDEN 0x00000400 /* video enable */ #define THC_MISC_SYNC 0x00000200 /* not sure what ... */ #define THC_MISC_VSYNC 0x00000100 /* ... these really are */ #define THC_MISC_SYNCEN 0x00000080 /* sync enable */ #define THC_MISC_CURSRES 0x00000040 /* cursor resolution */ #define THC_MISC_INTEN 0x00000020 /* v.retrace intr enable */ -#define THC_MISC_INTR 0x00000010 /* intr pending / ack bit */ -#define THC_MISC_DACWAIT 0x0000000f /* ??? */ +#define THC_MISC_INTR 0x00000010 /* intr pending / ack */ +#define THC_MISC_DACWAIT 0x0000000f /* cycles before transfer */ /* * Partial description of TEC. */ struct tcx_tec { - u_int tec_config; /* what's in it? */ - u_int tec_xxx0[35]; - u_int tec_delay; /* */ + u_int32_t tec_config; /* what's in it? */ + u_int32_t tec_xxx0[35]; + u_int32_t tec_delay; /* */ #define TEC_DELAY_SYNC 0x00000f00 -#define TEC_DELAY_WR_F 0x000000c0 -#define TEC_DELAY_WR_R 0x00000030 -#define TEC_DELAY_SOE_F 0x0000000c -#define TEC_DELAY_SOE_S 0x00000003 - u_int tec_strapping; /* */ +#define TEC_DELAY_WR_F 0x000000c0 /* wr falling */ +#define TEC_DELAY_WR_R 0x00000030 /* wr rising */ +#define TEC_DELAY_SOE_F 0x0000000c /* soe falling */ +#define TEC_DELAY_SOE_S 0x00000003 /* soe sclk */ + u_int32_t tec_strapping; /* */ #define TEC_STRAP_FIFO_LIMIT 0x00f00000 #define TEC_STRAP_CACHE_EN 0x00010000 #define TEC_STRAP_ZERO_OFFSET 0x00008000 #define TEC_STRAP_REFRSH_DIS 0x00004000 #define TEC_STRAP_REF_LOAD 0x00001000 #define TEC_STRAP_REFRSH_PERIOD 0x000003ff - u_int tec_hcmisc; /* */ - u_int tec_linecount; /* */ - u_int tec_hss; /* */ - u_int tec_hse; /* */ - u_int tec_hds; /* */ - u_int tec_hsedvs; /* */ - u_int tec_hde; /* */ - u_int tec_vss; /* */ - u_int tec_vse; /* */ - u_int tec_vds; /* */ - u_int tec_vde; /* */ + u_int32_t tec_hcmisc; /* */ + u_int32_t tec_linecount; /* */ + u_int32_t tec_hss; /* */ + u_int32_t tec_hse; /* */ + u_int32_t tec_hds; /* */ + u_int32_t tec_hsedvs; /* */ + u_int32_t tec_hde; /* */ + u_int32_t tec_vss; /* */ + u_int32_t tec_vse; /* */ + u_int32_t tec_vds; /* */ + u_int32_t tec_vde; /* */ }; - diff --git a/sys/arch/sparc/dev/z8530kbd.c b/sys/arch/sparc/dev/z8530kbd.c new file mode 100644 index 00000000000..82ddc738c63 --- /dev/null +++ b/sys/arch/sparc/dev/z8530kbd.c @@ -0,0 +1,1335 @@ +/* $OpenBSD: z8530kbd.c,v 1.1 2002/08/12 10:44:04 miod Exp $ */ +/* $NetBSD: z8530tty.c,v 1.77 2001/05/30 15:24:24 lukem Exp $ */ + +/*- + * Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998, 1999 + * Charles M. Hannum. 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 Charles M. Hannum. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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. + */ + +/* + * Copyright (c) 1994 Gordon W. Ross + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * 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, Lawrence Berkeley Laboratory. + * + * 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. + * + * @(#)zs.c 8.1 (Berkeley) 7/19/93 + */ + +/* + * Zilog Z8530 Dual UART driver (tty interface) + * + * This is the "slave" driver that will be attached to + * the "zsc" driver for plain "tty" async. serial lines. + * + * Credits, history: + * + * The original version of this code was the sparc/dev/zs.c driver + * as distributed with the Berkeley 4.4 Lite release. Since then, + * Gordon Ross reorganized the code into the current parent/child + * driver scheme, separating the Sun keyboard and mouse support + * into independent child drivers. + * + * RTS/CTS flow-control support was a collaboration of: + * Gordon Ross <gwr@netbsd.org>, + * Bill Studenmund <wrstuden@loki.stanford.edu> + * Ian Dall <Ian.Dall@dsto.defence.gov.au> + * + * The driver was massively overhauled in November 1997 by Charles Hannum, + * fixing *many* bugs, and substantially improving performance. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/device.h> +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#include <sys/malloc.h> +#include <sys/tty.h> +#include <sys/time.h> +#include <sys/kernel.h> +#include <sys/syslog.h> + +#include <machine/autoconf.h> +#include <machine/conf.h> + +#include <dev/wscons/wsconsio.h> +#include <dev/wscons/wskbdvar.h> +#include <dev/wscons/wsksymdef.h> +#include <dev/wscons/wsksymvar.h> + +#include <dev/sun/sunkbdreg.h> +#include <dev/sun/sunkbdvar.h> + +#include <sparc/dev/z8530reg.h> +#include <machine/z8530var.h> + +#include <dev/cons.h> + +/* + * How many input characters we can buffer. + * The port-specific var.h may override this. + * Note: must be a power of two! + */ +#ifndef ZSKBD_RING_SIZE +#define ZSKBD_RING_SIZE 2048 +#endif + +struct cfdriver zskbd_cd = { + NULL, "zskbd", DV_TTY +}; + +/* + * Make this an option variable one can patch. + * But be warned: this must be a power of 2! + */ +u_int zskbd_rbuf_size = ZSKBD_RING_SIZE; + +/* Stop input when 3/4 of the ring is full; restart when only 1/4 is full. */ +u_int zskbd_rbuf_hiwat = (ZSKBD_RING_SIZE * 1) / 4; +u_int zskbd_rbuf_lowat = (ZSKBD_RING_SIZE * 3) / 4; + +struct zskbd_softc { + struct device zst_dev; /* required first: base device */ + struct zs_chanstate *zst_cs; + + struct timeout zst_diag_ch, zst_bellto; + + u_int zst_overflows, + zst_floods, + zst_errors; + + int zst_hwflags, /* see z8530var.h */ + zst_swflags; /* TIOCFLAG_SOFTCAR, ... <ttycom.h> */ + + u_int zst_r_hiwat, + zst_r_lowat; + u_char *volatile zst_rbget, + *volatile zst_rbput; + volatile u_int zst_rbavail; + u_char *zst_rbuf, + *zst_ebuf; + + /* + * The transmit byte count and address are used for pseudo-DMA + * output in the hardware interrupt code. PDMA can be suspended + * to get pending changes done; heldtbc is used for this. It can + * also be stopped for ^S; this sets TS_TTSTOP in tp->t_state. + */ + u_char *zst_tba; /* transmit buffer address */ + u_int zst_tbc, /* transmit byte count */ + zst_heldtbc; /* held tbc while xmission stopped */ + + u_char zst_tbuf[ZSKBD_RING_SIZE]; + u_char *zst_tbeg, *zst_tend, *zst_tbp; + + /* Flags to communicate with zskbd_softint() */ + volatile u_char zst_rx_flags, /* receiver blocked */ +#define RX_TTY_BLOCKED 0x01 +#define RX_TTY_OVERFLOWED 0x02 +#define RX_IBUF_BLOCKED 0x04 +#define RX_IBUF_OVERFLOWED 0x08 +#define RX_ANY_BLOCK 0x0f + zst_tx_busy, /* working on an output chunk */ + zst_tx_done, /* done with one output chunk */ + zst_tx_stopped, /* H/W level stop (lost CTS) */ + zst_st_check, /* got a status interrupt */ + zst_rx_ready; + + /* PPS signal on DCD, with or without inkernel clock disciplining */ + u_char zst_ppsmask; /* pps signal mask */ + u_char zst_ppsassert; /* pps leading edge */ + u_char zst_ppsclear; /* pps trailing edge */ + + struct device *zst_wskbddev; + int zst_leds; /* LED status */ + u_int8_t zst_kbdstate; /* keyboard state */ + int zst_click; /* keyclick state */ + int zst_id; /* keyboard type */ + int zst_layout; /* current layout */ + int zst_bellactive, zst_belltimeout; +}; + +/* Definition of the driver for autoconfig. */ +static int zskbd_match(struct device *, void *, void *); +static void zskbd_attach(struct device *, struct device *, void *); + +struct cfattach zskbd_ca = { + sizeof(struct zskbd_softc), zskbd_match, zskbd_attach +}; + +struct zsops zsops_kbd; + +static void zs_modem(struct zskbd_softc *, int); +static void zs_hwiflow(struct zskbd_softc *); +static void zs_maskintr(struct zskbd_softc *); + +struct zskbd_softc *zskbd_device_lookup(struct cfdriver *, int); + +/* Low-level routines. */ +static void zskbd_rxint(struct zs_chanstate *); +static void zskbd_stint(struct zs_chanstate *, int); +static void zskbd_txint(struct zs_chanstate *); +static void zskbd_softint(struct zs_chanstate *); +static void zskbd_diag(void *); + +void zskbd_init(struct zskbd_softc *); +void zskbd_putc(struct zskbd_softc *, u_int8_t); +void zskbd_raw(struct zskbd_softc *, u_int8_t); +void zskbd_reset(struct zskbd_softc *); + +/* wskbd glue */ +int zskbd_enable(void *, int); +void zskbd_set_leds(void *, int); +int zskbd_get_leds(struct zskbd_softc *); +int zskbd_ioctl(void *, u_long, caddr_t, int, struct proc *); +void zskbd_cngetc(void *, u_int *, int *); +void zskbd_cnpollc(void *, int); + +void zsstart_tx(struct zskbd_softc *); +int zsenqueue_tx(struct zskbd_softc *, u_char *, int); +void zskbd_bell(struct zskbd_softc *, u_int, u_int, u_int); +void zskbd_bellstop(void *); + +struct wskbd_accessops zskbd_accessops = { + zskbd_enable, + zskbd_set_leds, + zskbd_ioctl +}; + +struct wskbd_consops zskbd_consops = { + zskbd_cngetc, + zskbd_cnpollc +}; + +#define ZSKBDUNIT(x) (minor(x) & 0x7ffff) + +struct zskbd_softc * +zskbd_device_lookup(cf, unit) + struct cfdriver *cf; + int unit; +{ + return (struct zskbd_softc *)device_lookup(cf, unit); +} + +/* + * zskbd_match: how is this zs channel configured? + */ +int +zskbd_match(parent, vcf, aux) + struct device *parent; + void *vcf; + void *aux; +{ + struct cfdata *cf = vcf; + struct zsc_attach_args *args = aux; + int ret; + + /* If we're not looking for a keyboard, just exit */ + if (strcmp(args->type, "keyboard") != 0) + return (0); + + ret = 10; + + /* Exact match is better than wildcard. */ + if (cf->cf_loc[ZSCCF_CHANNEL] == args->channel) + ret += 2; + + /* This driver accepts wildcard. */ + if (cf->cf_loc[ZSCCF_CHANNEL] == ZSCCF_CHANNEL_DEFAULT) + ret += 1; + + return (ret); +} + +void +zskbd_attach(parent, self, aux) + struct device *parent, *self; + void *aux; + +{ + struct zsc_softc *zsc = (void *) parent; + struct zskbd_softc *zst = (void *) self; + struct cfdata *cf = self->dv_cfdata; + struct zsc_attach_args *args = aux; + struct wskbddev_attach_args a; + struct zs_chanstate *cs; + int channel, s, tty_unit, console = 0; + dev_t dev; + + timeout_set(&zst->zst_diag_ch, zskbd_diag, zst); + timeout_set(&zst->zst_bellto, zskbd_bellstop, zst); + + zst->zst_tbp = zst->zst_tba = zst->zst_tbeg = zst->zst_tbuf; + zst->zst_tend = zst->zst_tbeg + ZSKBD_RING_SIZE; + + tty_unit = zst->zst_dev.dv_unit; + channel = args->channel; + cs = &zsc->zsc_cs[channel]; + cs->cs_private = zst; + cs->cs_ops = &zsops_kbd; + + zst->zst_cs = cs; + zst->zst_swflags = cf->cf_flags; /* softcar, etc. */ + zst->zst_hwflags = args->hwflags; + dev = makedev(zs_major, tty_unit); + + if (zst->zst_swflags) + printf(", flags 0x%x", zst->zst_swflags); + + /* + * Check whether we serve as a console device. + * XXX - split console input/output channels aren't + * supported yet on /dev/console + */ + if ((zst->zst_hwflags & ZS_HWFLAG_CONSOLE_INPUT) != 0) { + if ((args->hwflags & ZS_HWFLAG_USE_CONSDEV) != 0) { + args->consdev->cn_dev = dev; + cn_tab->cn_pollc = wskbd_cnpollc; + cn_tab->cn_getc = wskbd_cngetc; + } + cn_tab->cn_dev = dev; + console = 1; + } + + zst->zst_rbuf = malloc(zskbd_rbuf_size << 1, M_DEVBUF, M_WAITOK); + zst->zst_ebuf = zst->zst_rbuf + (zskbd_rbuf_size << 1); + /* Disable the high water mark. */ + zst->zst_r_hiwat = 0; + zst->zst_r_lowat = 0; + zst->zst_rbget = zst->zst_rbput = zst->zst_rbuf; + zst->zst_rbavail = zskbd_rbuf_size; + + /* if there are no enable/disable functions, assume the device + is always enabled */ + if (!cs->enable) + cs->enabled = 1; + + /* + * Hardware init + */ + if (ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE)) { + /* Call zsparam similar to open. */ + + /* Wait a while for previous console output to complete */ + DELAY(10000); + + /* + * Turn on receiver and status interrupts. + * We defer the actual write of the register to zsparam(), + * but we must make sure status interrupts are turned on by + * the time zsparam() reads the initial rr0 state. + */ + zskbd_init(zst); + SET(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE); + zs_write_reg(cs, 1, cs->cs_creg[1]); + + s = splzs(); + + /* Make sure DTR is on now. */ + zs_modem(zst, 1); + + splx(s); + } else if (!ISSET(zst->zst_hwflags, ZS_HWFLAG_NORESET)) { + /* Not the console; may need reset. */ + int reset; + + reset = (channel == 0) ? ZSWR9_A_RESET : ZSWR9_B_RESET; + + s = splzs(); + + zs_write_reg(cs, 9, reset); + + /* Will raise DTR in open. */ + zs_modem(zst, 0); + + splx(s); + } + + /* + * XXX should provide a method to change keyclick setting + */ + zst->zst_click = 0; +#if defined(SUN4C) || defined(SUN4M) + if (!CPU_ISSUN4) { + char *cp = getpropstring(optionsnode, "keyboard-click?"); + + if (cp != NULL && strcmp(cp, "true") == 0) + zst->zst_click = 1; + } +#endif + + a.console = console; + if (ISTYPE5(zst->zst_layout)) { + printf(": keyboard, type 5, layout 0x%x", zst->zst_layout); + a.keymap = &sunkbd5_keymapdata; + } else { + printf(": keyboard, type %d", zst->zst_id); + if (zst->zst_id >= KB_SUN4) + printf(", layout 0x%x", zst->zst_layout); + a.keymap = &sunkbd_keymapdata; + } + a.accessops = &zskbd_accessops; + a.accesscookie = zst; + + printf("\n"); + + if (console) + wskbd_cnattach(&zskbd_consops, zst, a.keymap); + + zst->zst_wskbddev = config_found(self, &a, wskbddevprint); +} + +void +zskbd_init(zst) + struct zskbd_softc *zst; +{ + struct zs_chanstate *cs = zst->zst_cs; + int s, tries; + u_int8_t v3, v4, v5, rr0; + + /* setup for 1200n81 */ + if (zs_set_speed(cs, 1200)) { /* set 1200bps */ + printf(": failed to set baudrate\n"); + return; + } + if (zs_set_modes(cs, CS8 | CLOCAL)) { + printf(": failed to set modes\n"); + return; + } + + s = splzs(); + + zs_maskintr(zst); + + v3 = cs->cs_preg[3]; /* set 8 bit chars */ + v5 = cs->cs_preg[5]; + CLR(v3, ZSWR3_RXSIZE); + CLR(v5, ZSWR5_TXSIZE); + SET(v3, ZSWR3_RX_8); + SET(v5, ZSWR5_TX_8); + cs->cs_preg[3] = v3; + cs->cs_preg[5] = v5; + + v4 = cs->cs_preg[4]; /* no parity 1 stop */ + CLR(v4, ZSWR4_SBMASK | ZSWR4_PARMASK); + SET(v4, ZSWR4_ONESB | ZSWR4_EVENP); + cs->cs_preg[4] = v4; + + if (!cs->cs_heldchange) { + if (zst->zst_tx_busy) { + zst->zst_heldtbc = zst->zst_tbc; + zst->zst_tbc = 0; + cs->cs_heldchange = 1; + } else + zs_loadchannelregs(cs); + } + + /* + * Hardware flow control is disabled, turn off the buffer water + * marks and unblock any soft flow control state. Otherwise, enable + * the water marks. + */ + zst->zst_r_hiwat = 0; + zst->zst_r_lowat = 0; + if (ISSET(zst->zst_rx_flags, RX_TTY_OVERFLOWED)) { + CLR(zst->zst_rx_flags, RX_TTY_OVERFLOWED); + zst->zst_rx_ready = 1; + cs->cs_softreq = 1; + } + if (ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED)) { + CLR(zst->zst_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED); + zs_hwiflow(zst); + } + + /* + * Force a recheck of the hardware carrier and flow control status, + * since we may have changed which bits we're looking at. + */ + zskbd_stint(cs, 1); + + splx(s); + + /* + * Hardware flow control is disabled, unblock any hard flow control + * state. + */ + if (zst->zst_tx_stopped) { + zst->zst_tx_stopped = 0; + zsstart_tx(zst); + } + + zskbd_softint(cs); + + /* Ok, start the reset sequence... */ + + s = splhigh(); + + for (tries = 5; tries != 0; tries--) { + int ltries; + + zst->zst_leds = 0; + zst->zst_layout = -1; + + /* Send reset request */ + zskbd_putc(zst, SKBD_CMD_RESET); + + ltries = 1000; + while (--ltries > 0) { + rr0 = *cs->cs_reg_csr; + if (rr0 & ZSRR0_RX_READY) { + zskbd_raw(zst, *cs->cs_reg_data); + if (zst->zst_kbdstate == SKBD_STATE_RESET) + break; + } + DELAY(1000); + } + if (ltries == 0) + continue; + + /* Wait for reset to finish. */ + ltries = 1000; + while (--ltries > 0) { + rr0 = *cs->cs_reg_csr; + if (rr0 & ZSRR0_RX_READY) { + zskbd_raw(zst, *cs->cs_reg_data); + if (zst->zst_kbdstate == SKBD_STATE_GETKEY) + break; + } + DELAY(1000); + } + if (ltries == 0) + continue; + + + /* Send layout request */ + if (zst->zst_id == KB_SUN4) { + zskbd_putc(zst, SKBD_CMD_LAYOUT); + + ltries = 1000; + while (--ltries > 0) { + rr0 = *cs->cs_reg_csr; + if (rr0 & ZSRR0_RX_READY) { + zskbd_raw(zst, *cs->cs_reg_data); + if (zst->zst_layout != -1) + break; + } + DELAY(1000); + } + if (ltries == 0) + continue; + break; + } else { + zst->zst_layout = 0; + break; + } + } + if (tries == 0) + printf(": reset timeout\n"); + splx(s); +} + +void +zskbd_raw(zst, c) + struct zskbd_softc *zst; + u_int8_t c; +{ + int claimed = 0; + + if (zst->zst_kbdstate == SKBD_STATE_LAYOUT) { + zst->zst_kbdstate = SKBD_STATE_GETKEY; + zst->zst_layout = c; + return; + } + + switch (c) { + case SKBD_RSP_RESET: + zst->zst_kbdstate = SKBD_STATE_RESET; + claimed = 1; + break; + case SKBD_RSP_LAYOUT: + zst->zst_kbdstate = SKBD_STATE_LAYOUT; + claimed = 1; + break; + case SKBD_RSP_IDLE: + zst->zst_kbdstate = SKBD_STATE_GETKEY; + claimed = 1; + break; + } + + if (claimed != 0) + return; + + switch (zst->zst_kbdstate) { + case SKBD_STATE_RESET: + zst->zst_kbdstate = SKBD_STATE_GETKEY; + if (c < KB_SUN2 || c > KB_SUN4) + printf("%s: reset: invalid keyboard type %x\n", + zst->zst_dev.dv_xname, c); + else + zst->zst_id = c; + break; + case SKBD_STATE_GETKEY: + break; + } +} + +void +zskbd_putc(zst, c) + struct zskbd_softc *zst; + u_int8_t c; +{ + u_int8_t rr0; + int s; + + s = splhigh(); + do { + rr0 = *zst->zst_cs->cs_reg_csr; + } while ((rr0 & ZSRR0_TX_READY) == 0); + *zst->zst_cs->cs_reg_data = c; + delay(2); + splx(s); +} + +int +zsenqueue_tx(zst, str, len) + struct zskbd_softc *zst; + u_char *str; + int len; +{ + int s, i; + + s = splzs(); + if (zst->zst_tbc + len > ZSKBD_RING_SIZE) + return (-1); + zst->zst_tbc += len; + for (i = 0; i < len; i++) { + *zst->zst_tbp = str[i]; + if (++zst->zst_tbp == zst->zst_tend) + zst->zst_tbp = zst->zst_tbeg; + } + splx(s); + zsstart_tx(zst); + return (0); +} + +void +zsstart_tx(zst) + struct zskbd_softc *zst; +{ + struct zs_chanstate *cs = zst->zst_cs; + int s, s1; + + s = spltty(); + + if (zst->zst_tx_stopped) + goto out; + if (zst->zst_tbc == 0) + goto out; + + s1 = splzs(); + + zst->zst_tx_busy = 1; + + if (!ISSET(cs->cs_preg[1], ZSWR1_TIE)) { + SET(cs->cs_preg[1], ZSWR1_TIE); + cs->cs_creg[1] = cs->cs_preg[1]; + zs_write_reg(cs, 1, cs->cs_creg[1]); + } + + zs_write_data(cs, *zst->zst_tba); + + zst->zst_tbc--; + if (++zst->zst_tba == zst->zst_tend) + zst->zst_tba = zst->zst_tbeg; + + splx(s1); + +out: + splx(s); +} + +/* + * Compute interupt enable bits and set in the pending bits. Called both + * in zsparam() and when PPS (pulse per second timing) state changes. + * Must be called at splzs(). + */ +static void +zs_maskintr(zst) + struct zskbd_softc *zst; +{ + struct zs_chanstate *cs = zst->zst_cs; + int tmp15; + + cs->cs_rr0_mask = cs->cs_rr0_cts | cs->cs_rr0_dcd; + if (zst->zst_ppsmask != 0) + cs->cs_rr0_mask |= cs->cs_rr0_pps; + tmp15 = cs->cs_preg[15]; + if (ISSET(cs->cs_rr0_mask, ZSRR0_DCD)) + SET(tmp15, ZSWR15_DCD_IE); + else + CLR(tmp15, ZSWR15_DCD_IE); + if (ISSET(cs->cs_rr0_mask, ZSRR0_CTS)) + SET(tmp15, ZSWR15_CTS_IE); + else + CLR(tmp15, ZSWR15_CTS_IE); + cs->cs_preg[15] = tmp15; +} + + +/* + * Raise or lower modem control (DTR/RTS) signals. If a character is + * in transmission, the change is deferred. + */ +static void +zs_modem(zst, onoff) + struct zskbd_softc *zst; + int onoff; +{ + struct zs_chanstate *cs = zst->zst_cs; + + if (cs->cs_wr5_dtr == 0) + return; + + if (onoff) + SET(cs->cs_preg[5], cs->cs_wr5_dtr); + else + CLR(cs->cs_preg[5], cs->cs_wr5_dtr); + + if (!cs->cs_heldchange) { + if (zst->zst_tx_busy) { + zst->zst_heldtbc = zst->zst_tbc; + zst->zst_tbc = 0; + cs->cs_heldchange = 1; + } else + zs_loadchannelregs(cs); + } +} + +/* + * Internal version of zshwiflow + * called at splzs + */ +static void +zs_hwiflow(zst) + struct zskbd_softc *zst; +{ + struct zs_chanstate *cs = zst->zst_cs; + + if (cs->cs_wr5_rts == 0) + return; + + if (ISSET(zst->zst_rx_flags, RX_ANY_BLOCK)) { + CLR(cs->cs_preg[5], cs->cs_wr5_rts); + CLR(cs->cs_creg[5], cs->cs_wr5_rts); + } else { + SET(cs->cs_preg[5], cs->cs_wr5_rts); + SET(cs->cs_creg[5], cs->cs_wr5_rts); + } + zs_write_reg(cs, 5, cs->cs_creg[5]); +} + + +/**************************************************************** + * Interface to the lower layer (zscc) + ****************************************************************/ + +#define integrate +integrate void zskbd_rxsoft(struct zskbd_softc *); +integrate void zskbd_txsoft(struct zskbd_softc *); +integrate void zskbd_stsoft(struct zskbd_softc *); +/* + * receiver ready interrupt. + * called at splzs + */ +static void +zskbd_rxint(cs) + struct zs_chanstate *cs; +{ + struct zskbd_softc *zst = cs->cs_private; + u_char *put, *end; + u_int cc; + u_char rr0, rr1, c; + + end = zst->zst_ebuf; + put = zst->zst_rbput; + cc = zst->zst_rbavail; + + while (cc > 0) { + /* + * First read the status, because reading the received char + * destroys the status of this char. + */ + rr1 = zs_read_reg(cs, 1); + c = zs_read_data(cs); + + if (ISSET(rr1, ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) { + /* Clear the receive error. */ + zs_write_csr(cs, ZSWR0_RESET_ERRORS); + } + + put[0] = c; + put[1] = rr1; + put += 2; + if (put >= end) + put = zst->zst_rbuf; + cc--; + + rr0 = zs_read_csr(cs); + if (!ISSET(rr0, ZSRR0_RX_READY)) + break; + } + + /* + * Current string of incoming characters ended because + * no more data was available or we ran out of space. + * Schedule a receive event if any data was received. + * If we're out of space, turn off receive interrupts. + */ + zst->zst_rbput = put; + zst->zst_rbavail = cc; + if (!ISSET(zst->zst_rx_flags, RX_TTY_OVERFLOWED)) { + zst->zst_rx_ready = 1; + cs->cs_softreq = 1; + } + + /* + * See if we are in danger of overflowing a buffer. If + * so, use hardware flow control to ease the pressure. + */ + if (!ISSET(zst->zst_rx_flags, RX_IBUF_BLOCKED) && + cc < zst->zst_r_hiwat) { + SET(zst->zst_rx_flags, RX_IBUF_BLOCKED); + zs_hwiflow(zst); + } + + /* + * If we're out of space, disable receive interrupts + * until the queue has drained a bit. + */ + if (!cc) { + SET(zst->zst_rx_flags, RX_IBUF_OVERFLOWED); + CLR(cs->cs_preg[1], ZSWR1_RIE); + cs->cs_creg[1] = cs->cs_preg[1]; + zs_write_reg(cs, 1, cs->cs_creg[1]); + } +} + +/* + * transmitter ready interrupt. (splzs) + */ +static void +zskbd_txint(cs) + struct zs_chanstate *cs; +{ + struct zskbd_softc *zst = cs->cs_private; + + /* + * If we've delayed a parameter change, do it now, and restart + * output. + */ + if (cs->cs_heldchange) { + zs_loadchannelregs(cs); + cs->cs_heldchange = 0; + zst->zst_tbc = zst->zst_heldtbc; + zst->zst_heldtbc = 0; + } + + /* Output the next character in the buffer, if any. */ + if (zst->zst_tbc > 0) { + zs_write_data(cs, *zst->zst_tba); + zst->zst_tbc--; + if (++zst->zst_tba == zst->zst_tend) + zst->zst_tba = zst->zst_tbeg; + } else { + /* Disable transmit completion interrupts if necessary. */ + if (ISSET(cs->cs_preg[1], ZSWR1_TIE)) { + CLR(cs->cs_preg[1], ZSWR1_TIE); + cs->cs_creg[1] = cs->cs_preg[1]; + zs_write_reg(cs, 1, cs->cs_creg[1]); + } + if (zst->zst_tx_busy) { + zst->zst_tx_busy = 0; + zst->zst_tx_done = 1; + cs->cs_softreq = 1; + } + } +} + +/* + * status change interrupt. (splzs) + */ +static void +zskbd_stint(cs, force) + struct zs_chanstate *cs; + int force; +{ + struct zskbd_softc *zst = cs->cs_private; + u_char rr0, delta; + + rr0 = zs_read_csr(cs); + zs_write_csr(cs, ZSWR0_RESET_STATUS); + + /* + * Check here for console break, so that we can abort + * even when interrupts are locking up the machine. + */ + if (!force) + delta = rr0 ^ cs->cs_rr0; + else + delta = cs->cs_rr0_mask; + cs->cs_rr0 = rr0; + + if (ISSET(delta, cs->cs_rr0_mask)) { + SET(cs->cs_rr0_delta, delta); + + /* + * Stop output immediately if we lose the output + * flow control signal or carrier detect. + */ + if (ISSET(~rr0, cs->cs_rr0_mask)) { + zst->zst_tbc = 0; + zst->zst_heldtbc = 0; + } + + zst->zst_st_check = 1; + cs->cs_softreq = 1; + } +} + +void +zskbd_diag(arg) + void *arg; +{ + struct zskbd_softc *zst = arg; + int overflows, floods; + int s; + + s = splzs(); + overflows = zst->zst_overflows; + zst->zst_overflows = 0; + floods = zst->zst_floods; + zst->zst_floods = 0; + zst->zst_errors = 0; + splx(s); + + log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf flood%s\n", + zst->zst_dev.dv_xname, + overflows, overflows == 1 ? "" : "s", + floods, floods == 1 ? "" : "s"); +} + +integrate void +zskbd_rxsoft(zst) + struct zskbd_softc *zst; +{ + struct zs_chanstate *cs = zst->zst_cs; + u_char *get, *end; + u_int cc, scc, type; + u_char rr1; + int code, value; + int s; + + end = zst->zst_ebuf; + get = zst->zst_rbget; + scc = cc = zskbd_rbuf_size - zst->zst_rbavail; + + if (cc == zskbd_rbuf_size) { + zst->zst_floods++; + if (zst->zst_errors++ == 0) + timeout_add(&zst->zst_diag_ch, 60 * hz); + } + + while (cc) { + code = get[0]; + rr1 = get[1]; + if (ISSET(rr1, ZSRR1_DO | ZSRR1_FE | ZSRR1_PE)) { + if (ISSET(rr1, ZSRR1_DO)) { + zst->zst_overflows++; + if (zst->zst_errors++ == 0) + timeout_add(&zst->zst_diag_ch, 60 * hz); + } + if (ISSET(rr1, ZSRR1_FE)) + SET(code, TTY_FE); + if (ISSET(rr1, ZSRR1_PE)) + SET(code, TTY_PE); + } + + switch (code) { + case SKBD_RSP_IDLE: + type = WSCONS_EVENT_ALL_KEYS_UP; + value = 0; + break; + default: + type = (code & 0x80) ? + WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN; + value = code & 0x7f; + break; + } + wskbd_input(zst->zst_wskbddev, type, value); + + get += 2; + if (get >= end) + get = zst->zst_rbuf; + cc--; + } + + if (cc != scc) { + zst->zst_rbget = get; + s = splzs(); + cc = zst->zst_rbavail += scc - cc; + /* Buffers should be ok again, release possible block. */ + if (cc >= zst->zst_r_lowat) { + if (ISSET(zst->zst_rx_flags, RX_IBUF_OVERFLOWED)) { + CLR(zst->zst_rx_flags, RX_IBUF_OVERFLOWED); + SET(cs->cs_preg[1], ZSWR1_RIE); + cs->cs_creg[1] = cs->cs_preg[1]; + zs_write_reg(cs, 1, cs->cs_creg[1]); + } + if (ISSET(zst->zst_rx_flags, RX_IBUF_BLOCKED)) { + CLR(zst->zst_rx_flags, RX_IBUF_BLOCKED); + zs_hwiflow(zst); + } + } + splx(s); + } +} + +integrate void +zskbd_txsoft(zst) + struct zskbd_softc *zst; +{ +} + +integrate void +zskbd_stsoft(zst) + struct zskbd_softc *zst; +{ + struct zs_chanstate *cs = zst->zst_cs; + u_char rr0, delta; + int s; + + s = splzs(); + rr0 = cs->cs_rr0; + delta = cs->cs_rr0_delta; + cs->cs_rr0_delta = 0; + splx(s); + + if (ISSET(delta, cs->cs_rr0_cts)) { + /* Block or unblock output according to flow control. */ + if (ISSET(rr0, cs->cs_rr0_cts)) + zst->zst_tx_stopped = 0; + else + zst->zst_tx_stopped = 1; + } +} + +/* + * Software interrupt. Called at zssoft + * + * The main job to be done here is to empty the input ring + * by passing its contents up to the tty layer. The ring is + * always emptied during this operation, therefore the ring + * must not be larger than the space after "high water" in + * the tty layer, or the tty layer might drop our input. + * + * Note: an "input blockage" condition is assumed to exist if + * EITHER the TS_TBLOCK flag or zst_rx_blocked flag is set. + */ +static void +zskbd_softint(cs) + struct zs_chanstate *cs; +{ + struct zskbd_softc *zst = cs->cs_private; + int s; + + s = spltty(); + + if (zst->zst_rx_ready) { + zst->zst_rx_ready = 0; + zskbd_rxsoft(zst); + } + + if (zst->zst_st_check) { + zst->zst_st_check = 0; + zskbd_stsoft(zst); + } + + if (zst->zst_tx_done) { + zst->zst_tx_done = 0; + zskbd_txsoft(zst); + } + + splx(s); +} + +struct zsops zsops_kbd = { + zskbd_rxint, /* receive char available */ + zskbd_stint, /* external/status */ + zskbd_txint, /* xmit buffer empty */ + zskbd_softint, /* process software interrupt */ +}; + +int +zskbd_enable(v, on) + void *v; + int on; +{ + return (0); +} + +void +zskbd_set_leds(v, wled) + void *v; + int wled; +{ + struct zskbd_softc *zst = v; + u_int8_t sled = 0; + u_int8_t cmd[2]; + + zst->zst_leds = wled; + + if (wled & WSKBD_LED_CAPS) + sled |= SKBD_LED_CAPSLOCK; + if (wled & WSKBD_LED_NUM) + sled |= SKBD_LED_NUMLOCK; + if (wled & WSKBD_LED_SCROLL) + sled |= SKBD_LED_SCROLLLOCK; + if (wled & WSKBD_LED_COMPOSE) + sled |= SKBD_LED_COMPOSE; + + cmd[0] = SKBD_CMD_SETLED; + cmd[1] = sled; + zsenqueue_tx(zst, cmd, sizeof(cmd)); +} + +int +zskbd_get_leds(zst) + struct zskbd_softc *zst; +{ + return (zst->zst_leds); +} + +int +zskbd_ioctl(v, cmd, data, flag, p) + void *v; + u_long cmd; + caddr_t data; + int flag; + struct proc *p; +{ + struct zskbd_softc *zst = v; + int *d_int = (int *)data; + struct wskbd_bell_data *d_bell = (struct wskbd_bell_data *)data; + + switch (cmd) { + case WSKBDIO_GTYPE: + if (ISTYPE5(zst->zst_layout)) { + *d_int = WSKBD_TYPE_SUN5; + } else { + *d_int = WSKBD_TYPE_SUN; + } + return (0); + case WSKBDIO_SETLEDS: + zskbd_set_leds(zst, *d_int); + return (0); + case WSKBDIO_GETLEDS: + *d_int = zskbd_get_leds(zst); + return (0); + case WSKBDIO_COMPLEXBELL: + zskbd_bell(zst, d_bell->period, + d_bell->pitch, d_bell->volume); + return (0); + } + return (-1); +} + +void +zskbd_bell(zst, period, pitch, volume) + struct zskbd_softc *zst; + u_int period, pitch, volume; +{ + int ticks, s; + u_int8_t c = SKBD_CMD_BELLON; + + ticks = (period * hz)/1000; + if (ticks <= 0) + ticks = 1; + + s = splzs(); + if (zst->zst_bellactive) { + if (zst->zst_belltimeout == 0) + timeout_del(&zst->zst_bellto); + } + if (pitch == 0 || period == 0) { + zskbd_bellstop(zst); + splx(s); + return; + } + if (!zst->zst_bellactive) { + zst->zst_bellactive = 1; + zst->zst_belltimeout = 1; + zsenqueue_tx(zst, &c, 1); + timeout_add(&zst->zst_bellto, ticks); + } + splx(s); +} + +void +zskbd_bellstop(v) + void *v; +{ + struct zskbd_softc *zst = v; + int s; + u_int8_t c; + + s = splzs(); + zst->zst_belltimeout = 0; + c = SKBD_CMD_BELLOFF; + zsenqueue_tx(zst, &c, 1); + zst->zst_bellactive = 0; + splx(s); +} + +void +zskbd_cnpollc(v, on) + void *v; + int on; +{ + extern int swallow_zsintrs; + + if (on) + swallow_zsintrs++; + else + swallow_zsintrs--; +} + +void +zskbd_cngetc(v, type, data) + void *v; + u_int *type; + int *data; +{ + struct zskbd_softc *zst = v; + int s; + u_int8_t c, rr0; + + s = splhigh(); + do { + rr0 = *zst->zst_cs->cs_reg_csr; + } while ((rr0 & ZSRR0_RX_READY) == 0); + + c = *zst->zst_cs->cs_reg_data; + splx(s); + + switch (c) { + case SKBD_RSP_IDLE: + *type = WSCONS_EVENT_ALL_KEYS_UP; + *data = 0; + break; + default: + *type = (c & 0x80) ? + WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN; + *data = c & 0x7f; + break; + } +} + +void +zskbd_reset(zst) + struct zskbd_softc *zst; +{ + int s; + u_int8_t c; + + c = 0; + + /* + * Restore keyclick, if necessary + */ + + switch (zst->zst_id) { + case KB_SUN2: + /* Type 2 keyboards do not support keyclick */ + break; + case KB_SUN3: + /* Type 3 keyboards come up with keyclick on */ + if (zst->zst_click == 0) + c = SKBD_CMD_CLICKOFF; + break; + case KB_SUN4: + /* Type 4 keyboards come up with keyclick off */ + if (zst->zst_click != 0) + c = SKBD_CMD_CLICKON; + break; + } + + /* send click command whenever necessary */ + if (c != 0) { + s = splzs(); + zsenqueue_tx(zst, &c, 1); + splx(s); + } +} diff --git a/sys/arch/sparc/dev/z8530reg.h b/sys/arch/sparc/dev/z8530reg.h new file mode 100644 index 00000000000..eff0a069d89 --- /dev/null +++ b/sys/arch/sparc/dev/z8530reg.h @@ -0,0 +1,451 @@ +/* $OpenBSD: z8530reg.h,v 1.1 2002/08/12 10:44:04 miod Exp $ */ +/* $NetBSD: z8530reg.h,v 1.9 1998/07/31 05:08:38 wrstuden Exp $ */ + +/* + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * 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, Lawrence Berkeley Laboratory. + * + * 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. + * + * @(#)zsreg.h 8.1 (Berkeley) 6/11/93 + */ + +/* + * Zilog SCC registers, as implemented on the Sun-4c. + * + * Each Z8530 implements two channels (called `a' and `b'). + * + * The damnable chip was designed to fit on Z80 I/O ports, and thus + * has everything multiplexed out the wazoo. We have to select + * a register, then read or write the register, and so on. Worse, + * the parameter bits are scattered all over the register space. + * This thing is full of `miscellaneous' control registers. + * + * Worse yet, the registers have incompatible functions on read + * and write operations. We describe the registers below according + * to whether they are `read registers' (RR) or `write registers' (WR). + * As if this were not enough, some of the channel B status bits show + * up in channel A, and vice versa. The blasted thing shares write + * registers 2 and 9 across both channels, and reads registers 2 and 3 + * differently for the two channels. We can, however, ignore this much + * of the time. + * + * This file also includes flags for the Z85C30 and Z85230 enhanced scc. + * The CMOS 8530 includes extra SDLC functionality, and is used in a + * number of Macs (often in the Z85C80, an 85C30 combined w/ a SCSI + * controller). -wrs + * + * Some of the names in this files were chosen to make the hsis driver + * work unchanged (which means that they will match some in SunOS). + * + * `S.C.' stands for Special Condition, which is any of these: + * receiver overrun (aka silo overflow) + * framing error (missing stop bit, etc) + * end of frame (in synchronous modes) + * parity error (when `parity error is S.C.' is set) + * + * Registers with only a single `numeric value' get a name. + * Other registers hold bits and are only numbered; the bit + * definitions imply the register number (see below). + * + * We never use the receive and transmit data registers as + * indirects (choosing instead the zc_data register), so they + * are not defined here. + */ +#define ZSRR_IVEC 2 /* interrupt vector (channel 0) */ +#define ZSRR_IPEND 3 /* interrupt pending (ch. 0 only) */ +#define ZSRR_TXSYNC 6 /* sync transmit char (monosync mode) */ +#define ZSRR_RXSYNC 7 /* sync receive char (monosync mode) */ +#define ZSRR_SYNCLO 6 /* sync low byte (bisync mode) */ +#define ZSRR_SYNCHI 7 /* sync high byte (bisync mode) */ +#define ZSRR_SDLC_ADDR 6 /* SDLC address (SDLC mode) */ +#define ZSRR_SDLC_FLAG 7 /* SDLC flag 0x7E (SDLC mode) */ +#define ZSRR_BAUDLO 12 /* baud rate generator (low half) */ +#define ZSRR_BAUDHI 13 /* baud rate generator (high half) */ +#define ZSRR_ENHANCED 14 /* read address of WR7' - yes, it's not 7!*/ + +#define ZSWR_IVEC 2 /* interrupt vector (shared) */ +#define ZSWR_TXSYNC 6 /* sync transmit char (monosync mode) */ +#define ZSWR_RXSYNC 7 /* sync receive char (monosync mode) */ +#define ZSWR_SYNCLO 6 /* sync low byte (bisync mode) */ +#define ZSWR_SYNCHI 7 /* sync high byte (bisync mode) */ +#define ZSWR_SDLC_ADDR 6 /* SDLC address (SDLC mode) */ +#define ZSWR_SDLC_FLAG 7 /* SDLC flag 0x7E (SDLC mode) */ +#define ZSWR_BAUDLO 12 /* baud rate generator (low half) */ +#define ZSWR_BAUDHI 13 /* baud rate generator (high half) */ +#define ZSWR_ENHANCED 7 /* write address of WR7' */ + +/* + * Registers 0 through 7 may be written with any one of the 8 command + * modifiers, and/or any one of the 4 reset modifiers, defined below. + * To write registers 8 through 15, however, the command modifier must + * always be `point high'. Rather than track this bizzareness all over + * the driver, we try to avoid using any modifiers, ever (but they are + * defined here if you want them). + */ +#define ZSM_RESET_TXUEOM 0xc0 /* reset xmit underrun / eom latch */ +#define ZSM_RESET_TXCRC 0x80 /* reset xmit crc generator */ +#define ZSM_RESET_RXCRC 0x40 /* reset recv crc checker */ +#define ZSM_NULL 0x00 /* nothing special */ + +#define ZSM_RESET_IUS 0x38 /* reset interrupt under service */ +#define ZSM_RESET_ERR 0x30 /* reset error cond */ +#define ZSM_RESET_TXINT 0x28 /* reset xmit interrupt pending */ +#define ZSM_EI_NEXTRXC 0x20 /* enable int. on next rcvd char */ +#define ZSM_SEND_ABORT 0x18 /* send abort (SDLC) */ +#define ZSM_RESET_STINT 0x10 /* reset external/status interrupt */ +#define ZSM_POINTHIGH 0x08 /* `point high' (use r8-r15) */ +#define ZSM_NULL 0x00 /* nothing special */ + +/* + * Commands for Write Register 0 (`Command Register'). + * These are just the command modifiers or'ed with register number 0 + * (which of course equals the command modifier). + */ +#define ZSWR0_RESET_EOM ZSM_RESET_TXUEOM +#define ZSWR0_RESET_TXCRC ZSM_RESET_TXCRC +#define ZSWR0_RESET_RXCRC ZSM_RESET_RXCRC +#define ZSWR0_CLR_INTR ZSM_RESET_IUS +#define ZSWR0_RESET_ERRORS ZSM_RESET_ERR +#define ZSWR0_EI_NEXTRXC ZSM_EI_NEXTRXC +#define ZSWR0_SEND_ABORT ZSM_SEND_ABORT +#define ZSWR0_RESET_STATUS ZSM_RESET_STINT +#define ZSWR0_RESET_TXINT ZSM_RESET_TXINT + +/* + * Bits in Write Register 1 (`Transmit/Receive Interrupt and Data + * Transfer Mode Definition'). Note that bits 3 and 4 are taken together + * as a single unit, and bits 5 and 6 are useful only if bit 7 is set. + */ +#define ZSWR1_REQ_WAIT 0x80 /* WAIT*-REQ* pin gives WAIT* */ +#define ZSWR1_REQ_REQ 0xc0 /* WAIT*-REQ* pin gives REQ* */ +#define ZSWR1_REQ_TX 0x00 /* WAIT*-REQ* pin follows xmit buf */ +#define ZSWR1_REQ_RX 0x20 /* WAIT*-REQ* pin follows recv buf */ + +#define ZSWR1_RIE_NONE 0x00 /* disable rxint entirely */ +#define ZSWR1_RIE_FIRST 0x08 /* rxint on first char & on S.C. */ +#define ZSWR1_RIE 0x10 /* rxint per char & on S.C. */ +#define ZSWR1_RIE_SPECIAL_ONLY 0x18 /* rxint on S.C. only */ + +#define ZSWR1_PE_SC 0x04 /* parity error is special condition */ +#define ZSWR1_TIE 0x02 /* transmit interrupt enable */ +#define ZSWR1_SIE 0x01 /* external/status interrupt enable */ + +#define ZSWR1_IMASK 0x1F /* mask of all itr. enable bits. */ + +/* HSIS compat */ +#define ZSWR1_REQ_ENABLE (ZSWR1_REQ_WAIT | ZSWR1_REQ_TX) + +/* + * Bits in Write Register 3 (`Receive Parameters and Control'). + * Bits 7 and 6 are taken as a unit. Note that the receive bits + * per character ordering is insane. + * + * Here `hardware flow control' means CTS enables the transmitter + * and DCD enables the receiver. The latter is neither interesting + * nor useful, and gets in our way, making it almost unusable. + */ +#define ZSWR3_RX_5 0x00 /* receive 5 bits per char */ +#define ZSWR3_RX_7 0x40 /* receive 7 bits per char */ +#define ZSWR3_RX_6 0x80 /* receive 6 bits per char */ +#define ZSWR3_RX_8 0xc0 /* receive 8 bits per char */ +#define ZSWR3_RXSIZE 0xc0 /* receive char size mask */ + +#define ZSWR3_HFC 0x20 /* hardware flow control */ +#define ZSWR3_HUNT 0x10 /* enter hunt mode */ +#define ZSWR3_RXCRC_ENABLE 0x08 /* enable recv crc calculation */ +#define ZSWR3_ADDR_SEARCH_MODE 0x04 /* address search mode (SDLC only) */ +#define ZSWR3_SDLC_SHORT_ADDR 0x02 /* short address mode (SDLC only) */ +#define ZSWR3_SYNC_LOAD_INH 0x02 /* sync character load inhibit */ +#define ZSWR3_RX_ENABLE 0x01 /* receiver enable */ + +/* + * Bits in Write Register 4 (`Transmit/Receive Miscellaneous Parameters + * and Modes'). Bits 7&6, 5&4, and 3&2 are taken as units. + */ +#define ZSWR4_CLK_X1 0x00 /* clock divisor = 1 */ +#define ZSWR4_CLK_X16 0x40 /* clock divisor = 16 */ +#define ZSWR4_CLK_X32 0x80 /* clock divisor = 32 */ +#define ZSWR4_CLK_X64 0xc0 /* clock divisor = 64 */ +#define ZSWR4_CLK_MASK 0xc0 /* clock divisor mask */ + +#define ZSWR4_MONOSYNC 0x00 /* 8 bit sync char (sync only) */ +#define ZSWR4_BISYNC 0x10 /* 16 bit sync char (sync only) */ +#define ZSWR4_SDLC 0x20 /* SDLC mode */ +#define ZSWR4_EXTSYNC 0x30 /* external sync mode */ +#define ZSWR4_SYNC_MASK 0x30 /* sync mode bit mask */ + +#define ZSWR4_SYNCMODE 0x00 /* no stop bit (sync mode only) */ +#define ZSWR4_ONESB 0x04 /* 1 stop bit */ +#define ZSWR4_1P5SB 0x08 /* 1.5 stop bits (clk cannot be 1x) */ +#define ZSWR4_TWOSB 0x0c /* 2 stop bits */ +#define ZSWR4_SBMASK 0x0c /* mask of all stop bits */ + +#define ZSWR4_EVENP 0x02 /* check for even parity */ +#define ZSWR4_PARENB 0x01 /* enable parity checking */ +#define ZSWR4_PARMASK 0x03 /* mask of all parity bits */ + +/* + * Bits in Write Register 5 (`Transmit Parameter and Controls'). + * Bits 6 and 5 are taken as a unit; the ordering is, as with RX + * bits per char, not sensible. + */ +#define ZSWR5_DTR 0x80 /* assert (set to -12V) DTR */ + +#define ZSWR5_TX_5 0x00 /* transmit 5 or fewer bits */ +#define ZSWR5_TX_7 0x20 /* transmit 7 bits */ +#define ZSWR5_TX_6 0x40 /* transmit 6 bits */ +#define ZSWR5_TX_8 0x60 /* transmit 8 bits */ +#define ZSWR5_TXSIZE 0x60 /* transmit char size mask */ + +#define ZSWR5_BREAK 0x10 /* send break (continuous 0s) */ +#define ZSWR5_TX_ENABLE 0x08 /* enable transmitter */ +#define ZSWR5_CRC16 0x04 /* use CRC16 (off => use SDLC) */ +#define ZSWR5_RTS 0x02 /* assert RTS */ +#define ZSWR5_TXCRC_ENABLE 0x01 /* enable xmit crc calculation */ + +#ifdef not_done_here +/* + * Bits in Write Register 7 when the chip is in SDLC mode. + */ +#define ZSWR7_SDLCFLAG 0x7e /* this value makes SDLC mode work */ +#endif + +/* + * Bits in Write Register 7' (ZSWR_ENHANCED above). This register is + * only available on the 85230. Dispite the fact it contains flags + * and not a single value, the register was named as it is read + * via RR14. Weird. + */ + /* 0x80 unused */ +#define ZSWR7P_EXTEND_READ 0x40 /* modify read map; make most regs readable */ +#define ZSWR7P_TX_FIFO 0x20 /* change level for Tx FIFO empty int */ +#define ZSWR7P_DTR_TIME 0x10 /* modifies deact. speed of /DTR//REQ */ +#define ZSWR7P_RX_FIFO 0x08 /* Rx FIFO int on 1/2 full? */ +#define ZSWR7P_RTS_DEACT 0x04 /* automatically deassert RTS */ +#define ZSWR7P_AUTO_EOM_RESET 0x02 /* automatically reset EMO/Tx Underrun */ +#define ZSWR7P_AUTO_TX_FLAG 0x01 /* Auto send SDLC flag at transmit start */ + +/* + * Bits in Write Register 9 (`Master Interrupt Control'). Bits 7 & 6 + * are taken as a unit and indicate the type of reset; 00 means no reset + * (and is not defined here). + */ +#define ZSWR9_HARD_RESET 0xc0 /* force hardware reset */ +#define ZSWR9_A_RESET 0x80 /* reset channel A (0) */ +#define ZSWR9_B_RESET 0x40 /* reset channel B (1) */ +#define ZSWR9_SOFT_INTAC 0x20 /* Not in NMOS version */ + +#define ZSWR9_STATUS_HIGH 0x10 /* status in high bits of intr vec */ +#define ZSWR9_MASTER_IE 0x08 /* master interrupt enable */ +#define ZSWR9_DLC 0x04 /* disable lower chain */ +#define ZSWR9_NO_VECTOR 0x02 /* no vector */ +#define ZSWR9_VECTOR_INCL_STAT 0x01 /* vector includes status */ + +/* + * Bits in Write Register 10 (`Miscellaneous Transmitter/Receiver Control + * Bits'). Bits 6 & 5 are taken as a unit, and some of the bits are + * meaningful only in certain modes. Bleah. + */ +#define ZSWR10_PRESET_ONES 0x80 /* preset CRC to all 1 (else all 0) */ + +#define ZSWR10_NRZ 0x00 /* NRZ encoding */ +#define ZSWR10_NRZI 0x20 /* NRZI encoding */ +#define ZSWR10_FM1 0x40 /* FM1 encoding */ +#define ZSWR10_FM0 0x60 /* FM0 encoding */ + +#define ZSWR10_GA_ON_POLL 0x10 /* go active on poll (loop mode) */ +#define ZSWR10_MARK_IDLE 0x08 /* all 1s (vs flag) when idle (SDLC) */ +#define ZSWR10_ABORT_ON_UNDERRUN 0x4 /* abort on xmit underrun (SDLC) */ +#define ZSWR10_LOOP_MODE 0x02 /* loop mode (SDLC) */ +#define ZSWR10_6_BIT_SYNC 0x01 /* 6 bits per sync char (sync modes) */ + +/* + * Bits in Write Register 11 (`Clock Mode Control'). Bits 6&5, 4&3, and + * 1&0 are taken as units. Various bits depend on other bits in complex + * ways; see the Zilog manual. + */ +#define ZSWR11_XTAL 0x80 /* have xtal between RTxC* and SYNC* */ + /* (else have TTL oscil. on RTxC*) */ +#define ZSWR11_RXCLK_RTXC 0x00 /* recv clock taken from RTxC* pin */ +#define ZSWR11_RXCLK_TRXC 0x20 /* recv clock taken from TRxC* pin */ +#define ZSWR11_RXCLK_BAUD 0x40 /* recv clock taken from BRG */ +#define ZSWR11_RXCLK_DPLL 0x60 /* recv clock taken from DPLL */ + +#define ZSWR11_TXCLK_RTXC 0x00 /* xmit clock taken from RTxC* pin */ +#define ZSWR11_TXCLK_TRXC 0x08 /* xmit clock taken from TRxC* pin */ +#define ZSWR11_TXCLK_BAUD 0x10 /* xmit clock taken from BRG */ +#define ZSWR11_TXCLK_DPLL 0x18 /* xmit clock taken from DPLL */ + +#define ZSWR11_TRXC_OUT_ENA 0x04 /* TRxC* pin will be an output */ + /* (unless it is being used above) */ +#define ZSWR11_TRXC_XTAL 0x00 /* TRxC output from xtal oscillator */ +#define ZSWR11_TRXC_XMIT 0x01 /* TRxC output from xmit clock */ +#define ZSWR11_TRXC_BAUD 0x02 /* TRxC output from BRG */ +#define ZSWR11_TRXC_DPLL 0x03 /* TRxC output from DPLL */ + +/* + * Formula for Write Registers 12 and 13 (`Lower Byte of Baud Rate + * Generator Time Constant' and `Upper Byte of ...'). Inputs: + * + * f BRG input clock frequency (in Hz) AFTER division + * by 1, 16, 32, or 64 (per clock divisor in WR4) + * bps desired rate in bits per second (9600, etc) + * + * We want + * + * f + * ----- + 0.5 - 2 + * 2 bps + * + * rounded down to an integer. This can be computed entirely + * in integer arithemtic as: + * + * f + bps + * ------- - 2 + * 2 bps + */ +#define BPS_TO_TCONST(f, bps) ((((f) + (bps)) / (2 * (bps))) - 2) + +/* inverse of above: given a BRG Time Constant, return Bits Per Second */ +#define TCONST_TO_BPS(f, tc) ((f) / 2 / ((tc) + 2)) + +/* + * Bits in Write Register 14 (`Miscellaneous Control Bits'). + * Bits 7 through 5 are taken as a unit and make up a `DPLL command'. + */ +#define ZSWR14_DPLL_NOOP 0x00 /* leave DPLL alone */ +#define ZSWR14_DPLL_SEARCH 0x20 /* enter search mode */ +#define ZSWR14_DPLL_RESET_CM 0x40 /* reset `clock missing' in RR10 */ +#define ZSWR14_DPLL_DISABLE 0x60 /* disable DPLL (continuous search) */ +#define ZSWR14_DPLL_SRC_BAUD 0x80 /* set DPLL src = BRG */ +#define ZSWR14_DPLL_SRC_RTXC 0xa0 /* set DPLL src = RTxC* or xtal osc */ +#define ZSWR14_DPLL_FM 0xc0 /* operate in FM mode */ +#define ZSWR14_DPLL_NRZI 0xe0 /* operate in NRZI mode */ + +#define ZSWR14_LOCAL_LOOPBACK 0x10 /* set local loopback mode */ +#define ZSWR14_AUTO_ECHO 0x08 /* set auto echo mode */ +#define ZSWR14_DTR_REQ 0x04 /* DTR* / REQ* pin gives REQ* */ +#define ZSWR14_BAUD_FROM_PCLK 0x02 /* BRG clock taken from PCLK */ + /* (else from RTxC* pin or xtal osc) */ +#define ZSWR14_BAUD_ENA 0x01 /* enable BRG countdown */ + +/* + * Bits in Write Register 15 (`External/Status Interrupt Control'). + * Most of these cause status interrupts whenever the corresponding + * bit or pin changes state (i.e., any rising or falling edge). + * + * NOTE: ZSWR15_SDLC_FIFO & ZSWR15_ENABLE_ENHANCED should not be + * set on an NMOS 8530. Also, ZSWR15_ENABLE_ENHANCED is only + * available on the 85230. + */ +#define ZSWR15_BREAK_IE 0x80 /* enable break/abort status int */ +#define ZSWR15_TXUEOM_IE 0x40 /* enable TX underrun/EOM status int */ +#define ZSWR15_CTS_IE 0x20 /* enable CTS* pin status int */ +#define ZSWR15_SYNCHUNT_IE 0x10 /* enable SYNC* pin/hunt status int */ +#define ZSWR15_DCD_IE 0x08 /* enable DCD* pin status int */ +#define ZSWR15_SDLC_FIFO 0x04 /* enable SDLC FIFO enhancements */ +#define ZSWR15_ZERO_COUNT_IE 0x02 /* enable BRG-counter = 0 status int */ +#define ZSWR15_ENABLE_ENHANCED 0x01 /* enable writing WR7' at reg 7 */ + +/* + * Bits in Read Register 0 (`Transmit/Receive Buffer Status and External + * Status'). + */ +#define ZSRR0_BREAK 0x80 /* break/abort detected */ +#define ZSRR0_TXUNDER 0x40 /* transmit underrun/EOM (sync) */ +#define ZSRR0_CTS 0x20 /* clear to send */ +#define ZSRR0_SYNC_HUNT 0x10 /* sync/hunt (sync mode) */ +#define ZSRR0_DCD 0x08 /* data carrier detect */ +#define ZSRR0_TX_READY 0x04 /* transmit buffer empty */ +#define ZSRR0_ZERO_COUNT 0x02 /* zero count in baud clock */ +#define ZSRR0_RX_READY 0x01 /* received character ready */ + +/* + * Bits in Read Register 1 (the Zilog book does not name this one). + */ +#define ZSRR1_EOF 0x80 /* end of frame (SDLC mode) */ +#define ZSRR1_FE 0x40 /* CRC/framing error */ +#define ZSRR1_DO 0x20 /* data (receiver) overrun */ +#define ZSRR1_PE 0x10 /* parity error */ +#define ZSRR1_RC0 0x08 /* residue code 0 (SDLC mode) */ +#define ZSRR1_RC1 0x04 /* residue code 1 (SDLC mode) */ +#define ZSRR1_RC2 0x02 /* residue code 2 (SDLC mode) */ +#define ZSRR1_ALL_SENT 0x01 /* all chars out of xmitter (async) */ + +/* + * Read Register 2 in B channel contains status bits if VECTOR_INCL_STAT + * is set. + */ + +/* + * Bits in Read Register 3 (`Interrupt Pending'). Only channel A + * has an RR3. + */ + /* 0x80 unused, returned as 0 */ + /* 0x40 unused, returned as 0 */ +#define ZSRR3_IP_A_RX 0x20 /* channel A recv int pending */ +#define ZSRR3_IP_A_TX 0x10 /* channel A xmit int pending */ +#define ZSRR3_IP_A_STAT 0x08 /* channel A status int pending */ +#define ZSRR3_IP_B_RX 0x04 /* channel B recv int pending */ +#define ZSRR3_IP_B_TX 0x02 /* channel B xmit int pending */ +#define ZSRR3_IP_B_STAT 0x01 /* channel B status int pending */ + +/* + * Bits in Read Register 10 (`contains some miscellaneous status bits'). + */ +#define ZSRR10_1_CLOCK_MISSING 0x80 /* 1 clock edge missing (FM mode) */ +#define ZSRR10_2_CLOCKS_MISSING 0x40 /* 2 clock edges missing (FM mode) */ + /* 0x20 unused */ +#define ZSRR10_LOOP_SENDING 0x10 /* xmitter controls loop (SDLC loop) */ + /* 0x08 unused */ + /* 0x04 unused */ +#define ZSRR10_ON_LOOP 0x02 /* SCC is on loop (SDLC/X.21 modes) */ + +/* + * Bits in Read Register 15. This register is one of the few that + * simply reads back the corresponding Write Register. + */ +#define ZSRR15_BREAK_IE 0x80 /* break/abort status int enable */ +#define ZSRR15_TXUEOM_IE 0x40 /* TX underrun/EOM status int enable */ +#define ZSRR15_CTS_IE 0x20 /* CTS* pin status int enable */ +#define ZSRR15_SYNCHUNT_IE 0x10 /* SYNC* pin/hunt status int enable */ +#define ZSRR15_DCD_IE 0x08 /* DCD* pin status int enable */ + /* 0x04 unused, returned as zero */ +#define ZSRR15_ZERO_COUNT_IE 0x02 /* BRG-counter = 0 status int enable */ + /* 0x01 unused, returned as zero */ diff --git a/sys/arch/sparc/dev/z8530sc.c b/sys/arch/sparc/dev/z8530sc.c new file mode 100644 index 00000000000..f14286f32f9 --- /dev/null +++ b/sys/arch/sparc/dev/z8530sc.c @@ -0,0 +1,357 @@ +/* $OpenBSD: z8530sc.c,v 1.1 2002/08/12 10:44:04 miod Exp $ */ +/* $NetBSD: z8530sc.c,v 1.4 1996/05/17 19:30:34 gwr Exp $ */ + +/* + * Copyright (c) 1994 Gordon W. Ross + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * 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, Lawrence Berkeley Laboratory. + * + * 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. + * + * @(#)zs.c 8.1 (Berkeley) 7/19/93 + */ + +/* + * Zilog Z8530 Dual UART driver (common part) + * + * This file contains the machine-independent parts of the + * driver common to tty and keyboard/mouse sub-drivers. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/device.h> +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#include <sys/tty.h> +#include <sys/time.h> +#include <sys/kernel.h> +#include <sys/syslog.h> + +#include <sparc/dev/z8530reg.h> +#include <machine/z8530var.h> + +void +zs_break(cs, set) + struct zs_chanstate *cs; + int set; +{ + + if (set) { + cs->cs_preg[5] |= ZSWR5_BREAK; + cs->cs_creg[5] |= ZSWR5_BREAK; + } else { + cs->cs_preg[5] &= ~ZSWR5_BREAK; + cs->cs_creg[5] &= ~ZSWR5_BREAK; + } + zs_write_reg(cs, 5, cs->cs_creg[5]); +} + + +/* + * drain on-chip fifo + */ +void +zs_iflush(cs) + struct zs_chanstate *cs; +{ + u_char c, rr0, rr1; + int i; + + /* + * Count how many times we loop. Some systems, such as some + * Apple PowerBooks, claim to have SCC's which they really don't. + */ + for (i = 0; i < 32; i++) { + /* Is there input available? */ + rr0 = zs_read_csr(cs); + if ((rr0 & ZSRR0_RX_READY) == 0) + break; + + /* + * First read the status, because reading the data + * destroys the status of this char. + */ + rr1 = zs_read_reg(cs, 1); + c = zs_read_data(cs); + + if (rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) { + /* Clear the receive error. */ + zs_write_csr(cs, ZSWR0_RESET_ERRORS); + } + } +} + + +/* + * Write the given register set to the given zs channel in the proper order. + * The channel must not be transmitting at the time. The receiver will + * be disabled for the time it takes to write all the registers. + * Call this with interrupts disabled. + */ +void +zs_loadchannelregs(cs) + struct zs_chanstate *cs; +{ + u_char *reg; + + zs_write_csr(cs, ZSM_RESET_ERR); /* XXX: reset error condition */ + +#if 1 + /* + * XXX: Is this really a good idea? + * XXX: Should go elsewhere! -gwr + */ + zs_iflush(cs); /* XXX */ +#endif + + if (memcmp((caddr_t)cs->cs_preg, (caddr_t)cs->cs_creg, 16) == 0) + return; /* only change if values are different */ + + /* Copy "pending" regs to "current" */ + memcpy((caddr_t)cs->cs_creg, (caddr_t)cs->cs_preg, 16); + reg = cs->cs_creg; /* current regs */ + + /* disable interrupts */ + zs_write_reg(cs, 1, reg[1] & ~ZSWR1_IMASK); + + /* baud clock divisor, stop bits, parity */ + zs_write_reg(cs, 4, reg[4]); + + /* misc. TX/RX control bits */ + zs_write_reg(cs, 10, reg[10]); + + /* char size, enable (RX/TX) */ + zs_write_reg(cs, 3, reg[3] & ~ZSWR3_RX_ENABLE); + zs_write_reg(cs, 5, reg[5] & ~ZSWR5_TX_ENABLE); + + /* synchronous mode stuff */ + zs_write_reg(cs, 6, reg[6]); + zs_write_reg(cs, 7, reg[7]); + +#if 0 + /* + * Registers 2 and 9 are special because they are + * actually common to both channels, but must be + * programmed through channel A. The "zsc" attach + * function takes care of setting these registers + * and they should not be touched thereafter. + */ + /* interrupt vector */ + zs_write_reg(cs, 2, reg[2]); + /* master interrupt control */ + zs_write_reg(cs, 9, reg[9]); +#endif + + /* Shut down the BRG */ + zs_write_reg(cs, 14, reg[14] & ~ZSWR14_BAUD_ENA); + +#ifdef ZS_MD_SETCLK + /* Let the MD code setup any external clock. */ + ZS_MD_SETCLK(cs); +#endif /* ZS_MD_SETCLK */ + + /* clock mode control */ + zs_write_reg(cs, 11, reg[11]); + + /* baud rate (lo/hi) */ + zs_write_reg(cs, 12, reg[12]); + zs_write_reg(cs, 13, reg[13]); + + /* Misc. control bits */ + zs_write_reg(cs, 14, reg[14]); + + /* which lines cause status interrupts */ + zs_write_reg(cs, 15, reg[15]); + + /* + * Zilog docs recommend resetting external status twice at this + * point. Mainly as the status bits are latched, and the first + * interrupt clear might unlatch them to new values, generating + * a second interrupt request. + */ + zs_write_csr(cs, ZSM_RESET_STINT); + zs_write_csr(cs, ZSM_RESET_STINT); + + /* char size, enable (RX/TX)*/ + zs_write_reg(cs, 3, reg[3]); + zs_write_reg(cs, 5, reg[5]); + + /* interrupt enables: TX, TX, STATUS */ + zs_write_reg(cs, 1, reg[1]); +} + + +/* + * ZS hardware interrupt. Scan all ZS channels. NB: we know here that + * channels are kept in (A,B) pairs. + * + * Do just a little, then get out; set a software interrupt if more + * work is needed. + * + * We deliberately ignore the vectoring Zilog gives us, and match up + * only the number of `reset interrupt under service' operations, not + * the order. + */ +int +zsc_intr_hard(arg) + void *arg; +{ + struct zsc_softc *zsc = arg; + struct zs_chanstate *cs; + u_char rr3; + + /* First look at channel A. */ + cs = &zsc->zsc_cs[0]; + /* Note: only channel A has an RR3 */ + rr3 = zs_read_reg(cs, 3); + + /* + * Clear interrupt first to avoid a race condition. + * If a new interrupt condition happens while we are + * servicing this one, we will get another interrupt + * shortly. We can NOT just sit here in a loop, or + * we will cause horrible latency for other devices + * on this interrupt level (i.e. sun3x floppy disk). + */ + if (rr3 & (ZSRR3_IP_A_RX | ZSRR3_IP_A_TX | ZSRR3_IP_A_STAT)) { + zs_write_csr(cs, ZSWR0_CLR_INTR); + if (rr3 & ZSRR3_IP_A_RX) + (*cs->cs_ops->zsop_rxint)(cs); + if (rr3 & ZSRR3_IP_A_STAT) + (*cs->cs_ops->zsop_stint)(cs, 0); + if (rr3 & ZSRR3_IP_A_TX) + (*cs->cs_ops->zsop_txint)(cs); + } + + /* Now look at channel B. */ + cs = &zsc->zsc_cs[1]; + if (rr3 & (ZSRR3_IP_B_RX | ZSRR3_IP_B_TX | ZSRR3_IP_B_STAT)) { + zs_write_csr(cs, ZSWR0_CLR_INTR); + if (rr3 & ZSRR3_IP_B_RX) + (*cs->cs_ops->zsop_rxint)(cs); + if (rr3 & ZSRR3_IP_B_STAT) + (*cs->cs_ops->zsop_stint)(cs, 0); + if (rr3 & ZSRR3_IP_B_TX) + (*cs->cs_ops->zsop_txint)(cs); + } + + /* Note: caller will check cs_x->cs_softreq and DTRT. */ + return (rr3); +} + + +/* + * ZS software interrupt. Scan all channels for deferred interrupts. + */ +int +zsc_intr_soft(arg) + void *arg; +{ + struct zsc_softc *zsc = arg; + struct zs_chanstate *cs; + int rval, chan; + + rval = 0; + for (chan = 0; chan < 2; chan++) { + cs = &zsc->zsc_cs[chan]; + + /* + * The softint flag can be safely cleared once + * we have decided to call the softint routine. + * (No need to do splzs() first.) + */ + if (cs->cs_softreq) { + cs->cs_softreq = 0; + (*cs->cs_ops->zsop_softint)(cs); + rval++; + } + } + return (rval); +} + +/* + * Provide a null zs "ops" vector. + */ + +void zsnull_rxint(struct zs_chanstate *); +void zsnull_stint(struct zs_chanstate *, int); +void zsnull_txint(struct zs_chanstate *); +void zsnull_softint(struct zs_chanstate *); + +void +zsnull_rxint(cs) + struct zs_chanstate *cs; +{ + /* Ask for softint() call. */ + cs->cs_softreq = 1; +} + +void +zsnull_stint(cs, force) + struct zs_chanstate *cs; + int force; +{ + /* Ask for softint() call. */ + cs->cs_softreq = 1; +} + +void +zsnull_txint(cs) + struct zs_chanstate *cs; +{ + /* Ask for softint() call. */ + cs->cs_softreq = 1; +} + +void +zsnull_softint(cs) + struct zs_chanstate *cs; +{ + zs_write_reg(cs, 1, 0); + zs_write_reg(cs, 15, 0); +} + +struct zsops zsops_null = { + zsnull_rxint, /* receive char available */ + zsnull_stint, /* external/status */ + zsnull_txint, /* xmit buffer empty */ + zsnull_softint, /* process software interrupt */ +}; diff --git a/sys/arch/sparc/dev/z8530sc.h b/sys/arch/sparc/dev/z8530sc.h new file mode 100644 index 00000000000..e9f22245707 --- /dev/null +++ b/sys/arch/sparc/dev/z8530sc.h @@ -0,0 +1,158 @@ +/* $OpenBSD: z8530sc.h,v 1.1 2002/08/12 10:44:04 miod Exp $ */ +/* $NetBSD: z8530sc.h,v 1.15 2001/05/11 01:40:48 thorpej Exp $ */ + +/* + * Copyright (c) 1994 Gordon W. Ross + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * 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, Lawrence Berkeley Laboratory. + * + * 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. + * + * @(#)zsvar.h 8.1 (Berkeley) 6/11/93 + */ + + +/* + * Function vector - per channel + */ +struct zs_chanstate; +struct zsops { + void (*zsop_rxint)(struct zs_chanstate *); + /* receive char available */ + void (*zsop_stint)(struct zs_chanstate *, int); + /* external/status */ + void (*zsop_txint)(struct zs_chanstate *); + /* xmit buffer empty */ + void (*zsop_softint)(struct zs_chanstate *); + /* process software interrupt */ +}; + +extern struct zsops zsops_null; + + +/* + * Software state, per zs channel. + */ +struct zs_chanstate { + + /* Pointers to the device registers. */ + volatile u_char *cs_reg_csr; /* ctrl, status, and reg. number. */ + volatile u_char *cs_reg_data; /* data or numbered register */ + + int cs_channel; /* sub-unit number */ + void *cs_private; /* sub-driver data pointer */ + struct zsops *cs_ops; + + int cs_brg_clk; /* BAUD Rate Generator clock + * (usually PCLK / 16) */ + int cs_defspeed; /* default baud rate */ + int cs_defcflag; /* default cflag */ + + /* + * We must keep a copy of the write registers as they are + * mostly write-only and we sometimes need to set and clear + * individual bits (e.g., in WR3). Not all of these are + * needed but 16 bytes is cheap and this makes the addressing + * simpler. Unfortunately, we can only write to some registers + * when the chip is not actually transmitting, so whenever + * we are expecting a `transmit done' interrupt the preg array + * is allowed to `get ahead' of the current values. In a + * few places we must change the current value of a register, + * rather than (or in addition to) the pending value; for these + * cs_creg[] contains the current value. + */ + u_char cs_creg[16]; /* current values */ + u_char cs_preg[16]; /* pending values */ + int cs_heldchange; /* change pending (creg != preg) */ + + u_char cs_rr0; /* last rr0 processed */ + u_char cs_rr0_delta; /* rr0 changes at status intr. */ + u_char cs_rr0_mask; /* rr0 bits that stop output */ + u_char cs_rr0_dcd; /* which bit to read as DCD */ + u_char cs_rr0_cts; /* which bit to read as CTS */ + u_char cs_rr0_pps; /* which bit to use for PPS */ + /* the above is set only while CRTSCTS is enabled. */ + + u_char cs_wr5_dtr; /* which bit to write as DTR */ + u_char cs_wr5_rts; /* which bit to write as RTS */ + /* the above is set only while CRTSCTS is enabled. */ + + char cs_softreq; /* need soft interrupt call */ + char cs_spare1; /* (for skippy :) */ + + /* power management hooks */ + int (*enable)(struct zs_chanstate *); + void (*disable)(struct zs_chanstate *); + int enabled; + + /* MD code might define a larger variant of this. */ +}; + +struct consdev; +struct zsc_attach_args { + char *type; /* type name 'serial', 'keyboard', 'mouse' */ + int channel; /* two serial channels per zsc */ + int hwflags; /* see definitions below */ + /* `consdev' is only valid if ZS_HWFLAG_USE_CONSDEV is set */ + struct consdev *consdev; +}; +/* In case of split console devices, use these: */ +#define ZS_HWFLAG_CONSOLE_INPUT 1 +#define ZS_HWFLAG_CONSOLE_OUTPUT 2 +#define ZS_HWFLAG_CONSOLE \ + (ZS_HWFLAG_CONSOLE_INPUT | ZS_HWFLAG_CONSOLE_OUTPUT) +#define ZS_HWFLAG_NO_DCD 4 /* Ignore the DCD bit */ +#define ZS_HWFLAG_NO_CTS 8 /* Ignore the CTS bit */ +#define ZS_HWFLAG_RAW 16 /* advise raw mode */ +#define ZS_HWFLAG_USE_CONSDEV 32 /* Use console ops from `consdev' */ +#define ZS_HWFLAG_NORESET 64 /* Don't reset at attach time */ + +int zsc_intr_soft(void *); +int zsc_intr_hard(void *); + +void zs_abort(struct zs_chanstate *); +void zs_break(struct zs_chanstate *, int); +void zs_iflush(struct zs_chanstate *); +void zs_loadchannelregs(struct zs_chanstate *); +int zs_set_speed(struct zs_chanstate *, int); +int zs_set_modes(struct zs_chanstate *, int); + +extern int zs_major; + +int zs_check_kgdb(struct zs_chanstate *, int); + diff --git a/sys/arch/sparc/dev/z8530tty.c b/sys/arch/sparc/dev/z8530tty.c new file mode 100644 index 00000000000..642fc05cae5 --- /dev/null +++ b/sys/arch/sparc/dev/z8530tty.c @@ -0,0 +1,1637 @@ +/* $OpenBSD: z8530tty.c,v 1.1 2002/08/12 10:44:04 miod Exp $ */ +/* $NetBSD: z8530tty.c,v 1.13 1996/10/16 20:42:14 gwr Exp $ */ + +/*- + * Copyright (c) 1993, 1994, 1995, 1996, 1997, 1998, 1999 + * Charles M. Hannum. 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 Charles M. Hannum. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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. + */ + +/* + * Copyright (c) 1994 Gordon W. Ross + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This software was developed by the Computer Systems Engineering group + * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and + * contributed to Berkeley. + * + * 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, Lawrence Berkeley Laboratory. + * + * 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. + * + * @(#)zs.c 8.1 (Berkeley) 7/19/93 + */ + +/* + * Zilog Z8530 Dual UART driver (tty interface) + * + * This is the "slave" driver that will be attached to + * the "zsc" driver for plain "tty" async. serial lines. + * + * Credits, history: + * + * The original version of this code was the sparc/dev/zs.c driver + * as distributed with the Berkeley 4.4 Lite release. Since then, + * Gordon Ross reorganized the code into the current parent/child + * driver scheme, separating the Sun keyboard and mouse support + * into independent child drivers. + * + * RTS/CTS flow-control support was a collaboration of: + * Gordon Ross <gwr@netbsd.org>, + * Bill Studenmund <wrstuden@loki.stanford.edu> + * Ian Dall <Ian.Dall@dsto.defence.gov.au> + * + * The driver was massively overhauled in November 1997 by Charles Hannum, + * fixing *many* bugs, and substantially improving performance. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/device.h> +#include <sys/conf.h> +#include <sys/file.h> +#include <sys/ioctl.h> +#include <sys/malloc.h> +#include <sys/tty.h> +#include <sys/time.h> +#include <sys/kernel.h> +#include <sys/syslog.h> + +#include <sparc/dev/z8530reg.h> +#include <machine/z8530var.h> + +#include <dev/cons.h> + +#ifdef KGDB +extern int zs_check_kgdb(); +#endif + +/* + * Allow the MD var.h to override the default CFLAG so that + * console messages during boot come out with correct parity. + */ +#ifndef ZSTTY_DEF_CFLAG +#define ZSTTY_DEF_CFLAG TTYDEF_CFLAG +#endif + +/* + * How many input characters we can buffer. + * The port-specific var.h may override this. + * Note: must be a power of two! + */ +#ifndef ZSTTY_RING_SIZE +#define ZSTTY_RING_SIZE 2048 +#endif + +/* + * Make this an option variable one can patch. + * But be warned: this must be a power of 2! + */ +u_int zstty_rbuf_size = ZSTTY_RING_SIZE; + +/* Stop input when 3/4 of the ring is full; restart when only 1/4 is full. */ +u_int zstty_rbuf_hiwat = (ZSTTY_RING_SIZE * 1) / 4; +u_int zstty_rbuf_lowat = (ZSTTY_RING_SIZE * 3) / 4; + +struct zstty_softc { + struct device zst_dev; /* required first: base device */ + struct tty *zst_tty; + struct zs_chanstate *zst_cs; + + struct timeout zst_diag_ch; + + u_int zst_overflows, + zst_floods, + zst_errors; + + int zst_hwflags, /* see z8530var.h */ + zst_swflags; /* TIOCFLAG_SOFTCAR, ... <ttycom.h> */ + + u_int zst_r_hiwat, + zst_r_lowat; + u_char *volatile zst_rbget, + *volatile zst_rbput; + volatile u_int zst_rbavail; + u_char *zst_rbuf, + *zst_ebuf; + + /* + * The transmit byte count and address are used for pseudo-DMA + * output in the hardware interrupt code. PDMA can be suspended + * to get pending changes done; heldtbc is used for this. It can + * also be stopped for ^S; this sets TS_TTSTOP in tp->t_state. + */ + u_char *zst_tba; /* transmit buffer address */ + u_int zst_tbc, /* transmit byte count */ + zst_heldtbc; /* held tbc while xmission stopped */ + + /* Flags to communicate with zstty_softint() */ + volatile u_char zst_rx_flags, /* receiver blocked */ +#define RX_TTY_BLOCKED 0x01 +#define RX_TTY_OVERFLOWED 0x02 +#define RX_IBUF_BLOCKED 0x04 +#define RX_IBUF_OVERFLOWED 0x08 +#define RX_ANY_BLOCK 0x0f + zst_tx_busy, /* working on an output chunk */ + zst_tx_done, /* done with one output chunk */ + zst_tx_stopped, /* H/W level stop (lost CTS) */ + zst_st_check, /* got a status interrupt */ + zst_rx_ready; + + /* PPS signal on DCD, with or without inkernel clock disciplining */ + u_char zst_ppsmask; /* pps signal mask */ + u_char zst_ppsassert; /* pps leading edge */ + u_char zst_ppsclear; /* pps trailing edge */ +}; + + +/* Definition of the driver for autoconfig. */ +int zstty_match(struct device *, void *, void *); +void zstty_attach(struct device *, struct device *, void *); + +struct cfattach zstty_ca = { + sizeof(struct zstty_softc), zstty_match, zstty_attach +}; + +struct cfdriver zstty_cd = { + NULL, "zstty", DV_TTY +}; + +struct zsops zsops_tty; + +/* Routines called from other code. */ +cdev_decl(zs); /* open, close, read, write, ioctl, stop, ... */ + +void zs_shutdown(struct zstty_softc *); +void zsstart(struct tty *); +int zsparam(struct tty *, struct termios *); +void zs_modem(struct zstty_softc *, int); +void tiocm_to_zs(struct zstty_softc *, u_long, int); +int zs_to_tiocm(struct zstty_softc *); +int zshwiflow(struct tty *, int); +void zs_hwiflow(struct zstty_softc *); +void zs_maskintr(struct zstty_softc *); + +/* Low-level routines. */ +void zstty_rxint(struct zs_chanstate *); +void zstty_stint(struct zs_chanstate *, int); +void zstty_txint(struct zs_chanstate *); +void zstty_softint(struct zs_chanstate *); +void zstty_diag(void *); + +#define ZSUNIT(x) (minor(x) & 0x7ffff) +#define ZSDIALOUT(x) (minor(x) & 0x80000) + +/* + * zstty_match: how is this zs channel configured? + */ +int +zstty_match(parent, match, aux) + struct device *parent; + void *match, *aux; +{ + struct cfdata *cf = match; + struct zsc_attach_args *args = aux; + + /* Exact match is better than wildcard. */ + if (cf->cf_loc[ZSCCF_CHANNEL] == args->channel) + return 2; + + /* This driver accepts wildcard. */ + if (cf->cf_loc[ZSCCF_CHANNEL] == ZSCCF_CHANNEL_DEFAULT) + return 1; + + return 0; +} + +void +zstty_attach(parent, self, aux) + struct device *parent, *self; + void *aux; + +{ + struct zsc_softc *zsc = (void *) parent; + struct zstty_softc *zst = (void *) self; + struct zsc_attach_args *args = aux; + struct zs_chanstate *cs; + struct cfdata *cf; + struct tty *tp; + int channel, s, tty_unit; + dev_t dev; + char *i, *o; + + cf = zst->zst_dev.dv_cfdata; + + timeout_set(&zst->zst_diag_ch, zstty_diag, zst); + + tty_unit = zst->zst_dev.dv_unit; + channel = args->channel; + cs = &zsc->zsc_cs[channel]; + cs->cs_private = zst; + cs->cs_ops = &zsops_tty; + + zst->zst_cs = cs; + zst->zst_swflags = cf->cf_flags; /* softcar, etc. */ + zst->zst_hwflags = args->hwflags; + dev = makedev(zs_major, tty_unit); + + if (zst->zst_swflags) + printf(" flags 0x%x", zst->zst_swflags); + + /* + * Check whether we serve as a console device. + * XXX - split console input/output channels aren't + * supported yet on /dev/console + */ + i = o = NULL; + if ((zst->zst_hwflags & ZS_HWFLAG_CONSOLE_INPUT) != 0) { + i = "input"; + if ((args->hwflags & ZS_HWFLAG_USE_CONSDEV) != 0) { + args->consdev->cn_dev = dev; + cn_tab->cn_pollc = args->consdev->cn_pollc; + cn_tab->cn_getc = args->consdev->cn_getc; + } + cn_tab->cn_dev = dev; + /* Set console magic to BREAK */ + } + if ((zst->zst_hwflags & ZS_HWFLAG_CONSOLE_OUTPUT) != 0) { + o = "output"; + if ((args->hwflags & ZS_HWFLAG_USE_CONSDEV) != 0) { + cn_tab->cn_putc = args->consdev->cn_putc; + } + cn_tab->cn_dev = dev; + } + if (i != NULL || o != NULL) + printf(" (console %s)", i ? (o ? "i/o" : i) : o); + +#ifdef KGDB + /* + * Allow kgdb to "take over" this port. If this port is + * NOT the kgdb port, zs_check_kgdb() will return zero. + * If it IS the kgdb port, it will print "kgdb,...\n" + * and then return non-zero. + */ + if (zs_check_kgdb(cs, dev)) { + printf(" (kgdb)\n"); + /* + * This is the kgdb port (exclusive use) + * so skip the normal attach code. + */ + return; + } +#endif + + if (strcmp(args->type, "keyboard") == 0 || + strcmp(args->type, "mouse") == 0) + printf(": %s", args->type); + + printf("\n"); + + tp = ttymalloc(); + tp->t_dev = dev; + tp->t_oproc = zsstart; + tp->t_param = zsparam; + tp->t_hwiflow = zshwiflow; + tty_attach(tp); + + zst->zst_tty = tp; + zst->zst_rbuf = malloc(zstty_rbuf_size << 1, M_DEVBUF, M_WAITOK); + zst->zst_ebuf = zst->zst_rbuf + (zstty_rbuf_size << 1); + /* Disable the high water mark. */ + zst->zst_r_hiwat = 0; + zst->zst_r_lowat = 0; + zst->zst_rbget = zst->zst_rbput = zst->zst_rbuf; + zst->zst_rbavail = zstty_rbuf_size; + + /* if there are no enable/disable functions, assume the device + is always enabled */ + if (!cs->enable) + cs->enabled = 1; + + /* + * Hardware init + */ + if (ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE)) { + /* Call zsparam similar to open. */ + struct termios t; + + /* Wait a while for previous console output to complete */ + DELAY(10000); + + /* Setup the "new" parameters in t. */ + t.c_ispeed = 0; + t.c_ospeed = cs->cs_defspeed; + t.c_cflag = cs->cs_defcflag; + + s = splzs(); + + /* + * Turn on receiver and status interrupts. + * We defer the actual write of the register to zsparam(), + * but we must make sure status interrupts are turned on by + * the time zsparam() reads the initial rr0 state. + */ + SET(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE); + + splx(s); + + /* Make sure zsparam will see changes. */ + tp->t_ospeed = 0; + (void) zsparam(tp, &t); + + s = splzs(); + + /* Make sure DTR is on now. */ + zs_modem(zst, 1); + + splx(s); + } else if (!ISSET(zst->zst_hwflags, ZS_HWFLAG_NORESET)) { + /* Not the console; may need reset. */ + int reset; + + reset = (channel == 0) ? ZSWR9_A_RESET : ZSWR9_B_RESET; + + s = splzs(); + + zs_write_reg(cs, 9, reset); + + /* Will raise DTR in open. */ + zs_modem(zst, 0); + + splx(s); + } +} + + +/* + * Return pointer to our tty. + */ +struct tty * +zstty(dev) + dev_t dev; +{ + struct zstty_softc *zst; + int unit = minor(dev); + +#ifdef DIAGNOSTIC + if (unit >= zstty_cd.cd_ndevs) + panic("zstty"); +#endif + zst = zstty_cd.cd_devs[unit]; + return (zst->zst_tty); +} + + +void +zs_shutdown(zst) + struct zstty_softc *zst; +{ + struct zs_chanstate *cs = zst->zst_cs; + struct tty *tp = zst->zst_tty; + int s; + + s = splzs(); + + /* If we were asserting flow control, then deassert it. */ + SET(zst->zst_rx_flags, RX_IBUF_BLOCKED); + zs_hwiflow(zst); + + /* Clear any break condition set with TIOCSBRK. */ + zs_break(cs, 0); + + /* Turn off PPS capture on last close. */ + zst->zst_ppsmask = 0; + + /* + * Hang up if necessary. Wait a bit, so the other side has time to + * notice even if we immediately open the port again. + */ + if (ISSET(tp->t_cflag, HUPCL)) { + zs_modem(zst, 0); + (void) tsleep(cs, TTIPRI, ttclos, hz); + } + + /* Turn off interrupts if not the console. */ + if (!ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE)) { + CLR(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE); + cs->cs_creg[1] = cs->cs_preg[1]; + zs_write_reg(cs, 1, cs->cs_creg[1]); + } + +/* Call the power management hook. */ + if (cs->disable) { +#ifdef DIAGNOSTIC + if (!cs->enabled) + panic("zs_shutdown: not enabled?"); +#endif + (*cs->disable)(zst->zst_cs); + } + + splx(s); +} + +/* + * Open a zs serial (tty) port. + */ +int +zsopen(dev, flags, mode, p) + dev_t dev; + int flags; + int mode; + struct proc *p; +{ + register struct tty *tp; + register struct zs_chanstate *cs; + struct zstty_softc *zst; + int s, s2; + int error, unit; + + unit = minor(dev); + if (unit >= zstty_cd.cd_ndevs) + return (ENXIO); + zst = zstty_cd.cd_devs[unit]; + if (zst == NULL) + return (ENXIO); + tp = zst->zst_tty; + cs = zst->zst_cs; + + /* If KGDB took the line, then tp==NULL */ + if (tp == NULL) + return (EBUSY); + + if (ISSET(tp->t_state, TS_ISOPEN) && + ISSET(tp->t_state, TS_XCLUDE) && + p->p_ucred->cr_uid != 0) + return (EBUSY); + + s = spltty(); + + /* + * Do the following iff this is a first open. + */ + if (!ISSET(tp->t_state, TS_ISOPEN)) { + struct termios t; + + tp->t_dev = dev; + + /* Call the power management hook. */ + if (cs->enable) { + if ((*cs->enable)(cs)) { + splx(s); + printf("%s: device enable failed\n", + zst->zst_dev.dv_xname); + return (EIO); + } + } + + /* + * Initialize the termios status to the defaults. Add in the + * sticky bits from TIOCSFLAGS. + */ + t.c_ispeed = 0; + t.c_ospeed = cs->cs_defspeed; + t.c_cflag = cs->cs_defcflag; + if (ISSET(zst->zst_swflags, TIOCFLAG_CLOCAL)) + SET(t.c_cflag, CLOCAL); + if (ISSET(zst->zst_swflags, TIOCFLAG_CRTSCTS)) + SET(t.c_cflag, CRTSCTS); + if (ISSET(zst->zst_swflags, TIOCFLAG_MDMBUF)) + SET(t.c_cflag, MDMBUF); + + s2 = splzs(); + + /* + * Turn on receiver and status interrupts. + * We defer the actual write of the register to zsparam(), + * but we must make sure status interrupts are turned on by + * the time zsparam() reads the initial rr0 state. + */ + SET(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE); + + /* Clear PPS capture state on first open. */ + zst->zst_ppsmask = 0; + + splx(s2); + + /* Make sure zsparam will see changes. */ + tp->t_ospeed = 0; + (void) zsparam(tp, &t); + + /* + * Note: zsparam has done: cflag, ispeed, ospeed + * so we just need to do: iflag, oflag, lflag, cc + * For "raw" mode, just leave all zeros. + */ + if (!ISSET(zst->zst_hwflags, ZS_HWFLAG_RAW)) { + tp->t_iflag = TTYDEF_IFLAG; + tp->t_oflag = TTYDEF_OFLAG; + tp->t_lflag = TTYDEF_LFLAG; + } else { + tp->t_iflag = 0; + tp->t_oflag = 0; + tp->t_lflag = 0; + } + ttychars(tp); + ttsetwater(tp); + + s2 = splzs(); + + /* + * Turn on DTR. We must always do this, even if carrier is not + * present, because otherwise we'd have to use TIOCSDTR + * immediately after setting CLOCAL, which applications do not + * expect. We always assert DTR while the device is open + * unless explicitly requested to deassert it. + */ + zs_modem(zst, 1); + + /* Clear the input ring, and unblock. */ + zst->zst_rbget = zst->zst_rbput = zst->zst_rbuf; + zst->zst_rbavail = zstty_rbuf_size; + zs_iflush(cs); + CLR(zst->zst_rx_flags, RX_ANY_BLOCK); + zs_hwiflow(zst); + + splx(s2); + } + + splx(s); + + error = ((*linesw[tp->t_line].l_open)(dev, tp)); + if (error) + goto bad; + + return (0); + +bad: + if (!ISSET(tp->t_state, TS_ISOPEN)) { + /* + * We failed to open the device, and nobody else had it opened. + * Clean up the state as appropriate. + */ + zs_shutdown(zst); + } + + return (error); +} + +/* + * Close a zs serial port. + */ +int +zsclose(dev, flags, mode, p) + dev_t dev; + int flags; + int mode; + struct proc *p; +{ + struct zstty_softc *zst; + register struct zs_chanstate *cs; + register struct tty *tp; + + zst = zstty_cd.cd_devs[minor(dev)]; + cs = zst->zst_cs; + tp = zst->zst_tty; + + /* XXX This is for cons.c. */ + if (!ISSET(tp->t_state, TS_ISOPEN)) + return 0; + + (*linesw[tp->t_line].l_close)(tp, flags); + ttyclose(tp); + + if (!ISSET(tp->t_state, TS_ISOPEN)) { + /* + * Although we got a last close, the device may still be in + * use; e.g. if this was the dialout node, and there are still + * processes waiting for carrier on the non-dialout node. + */ + zs_shutdown(zst); + } + + return (0); +} + +/* + * Read/write zs serial port. + */ +int +zsread(dev, uio, flags) + dev_t dev; + struct uio *uio; + int flags; +{ + struct zstty_softc *zst; + struct tty *tp; + + zst = zstty_cd.cd_devs[minor(dev)]; + tp = zst->zst_tty; + + return (*linesw[tp->t_line].l_read)(tp, uio, flags); +} + +int +zswrite(dev, uio, flags) + dev_t dev; + struct uio *uio; + int flags; +{ + struct zstty_softc *zst; + struct tty *tp; + + zst = zstty_cd.cd_devs[minor(dev)]; + tp = zst->zst_tty; + + return (*linesw[tp->t_line].l_write)(tp, uio, flags); +} + +#define TIOCFLAG_ALL (TIOCFLAG_SOFTCAR | TIOCFLAG_CLOCAL | \ + TIOCFLAG_CRTSCTS | TIOCFLAG_MDMBUF ) + +int +zsioctl(dev, cmd, data, flag, p) + dev_t dev; + u_long cmd; + caddr_t data; + int flag; + struct proc *p; +{ + struct zstty_softc *zst; + struct zs_chanstate *cs; + struct tty *tp; + int error; + int s; + + zst = zstty_cd.cd_devs[minor(dev)]; + cs = zst->zst_cs; + tp = zst->zst_tty; + + 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); + +#ifdef ZS_MD_IOCTL + error = ZS_MD_IOCTL; + if (error >= 0) + return (error); +#endif /* ZS_MD_IOCTL */ + + error = 0; + + s = splzs(); + + switch (cmd) { + case TIOCSBRK: + zs_break(cs, 1); + break; + + case TIOCCBRK: + zs_break(cs, 0); + break; + + case TIOCGFLAGS: + *(int *)data = zst->zst_swflags; + break; + + case TIOCSFLAGS: + error = suser(p->p_ucred, &p->p_acflag); + if (error != 0) + break; + zst->zst_swflags = *(int *)data; + break; + + case TIOCSDTR: + zs_modem(zst, 1); + break; + + case TIOCCDTR: + zs_modem(zst, 0); + break; + + case TIOCMSET: + case TIOCMBIS: + case TIOCMBIC: + tiocm_to_zs(zst, cmd, *(int *)data); + break; + + case TIOCMGET: + *(int *)data = zs_to_tiocm(zst); + break; + + default: + error = ENOTTY; + break; + } + + splx(s); + + return (error); +} + +/* + * Start or restart transmission. + */ +void +zsstart(tp) + struct tty *tp; +{ + struct zstty_softc *zst; + struct zs_chanstate *cs; + int s; + + zst = zstty_cd.cd_devs[minor(tp->t_dev)]; + cs = zst->zst_cs; + + s = spltty(); + if (ISSET(tp->t_state, TS_BUSY | TS_TIMEOUT | TS_TTSTOP)) + goto out; + if (zst->zst_tx_stopped) + goto out; + + if (tp->t_outq.c_cc <= tp->t_lowat) { + if (ISSET(tp->t_state, TS_ASLEEP)) { + CLR(tp->t_state, TS_ASLEEP); + wakeup((caddr_t)&tp->t_outq); + } + selwakeup(&tp->t_wsel); + if (tp->t_outq.c_cc == 0) + goto out; + } + + /* Grab the first contiguous region of buffer space. */ + { + u_char *tba; + int tbc; + + tba = tp->t_outq.c_cf; + tbc = ndqb(&tp->t_outq, 0); + + (void) splzs(); + + zst->zst_tba = tba; + zst->zst_tbc = tbc; + } + + SET(tp->t_state, TS_BUSY); + zst->zst_tx_busy = 1; + + /* Enable transmit completion interrupts if necessary. */ + if (!ISSET(cs->cs_preg[1], ZSWR1_TIE)) { + SET(cs->cs_preg[1], ZSWR1_TIE); + cs->cs_creg[1] = cs->cs_preg[1]; + zs_write_reg(cs, 1, cs->cs_creg[1]); + } + + /* Output the first character of the contiguous buffer. */ + { + zs_write_data(cs, *zst->zst_tba); + zst->zst_tbc--; + zst->zst_tba++; + } +out: + splx(s); +} + +/* + * Stop output, e.g., for ^S or output flush. + */ +int +zsstop(tp, flag) + struct tty *tp; + int flag; +{ + struct zstty_softc *zst; + struct zs_chanstate *cs; + int s; + + zst = zstty_cd.cd_devs[minor(tp->t_dev)]; + cs = zst->zst_cs; + + s = splzs(); + if (ISSET(tp->t_state, TS_BUSY)) { + /* Stop transmitting at the next chunk. */ + zst->zst_tbc = 0; + zst->zst_heldtbc = 0; + if (!ISSET(tp->t_state, TS_TTSTOP)) + SET(tp->t_state, TS_FLUSH); + } + splx(s); + return (0); +} + +/* + * Set ZS tty parameters from termios. + * XXX - Should just copy the whole termios after + * making sure all the changes could be done. + */ +int +zsparam(tp, t) + struct tty *tp; + struct termios *t; +{ + struct zstty_softc *zst; + struct zs_chanstate *cs; + int ospeed, cflag; + u_char tmp3, tmp4, tmp5; + int s, error; + + zst = zstty_cd.cd_devs[minor(tp->t_dev)]; + cs = zst->zst_cs; + + ospeed = t->c_ospeed; + cflag = t->c_cflag; + + /* Check requested parameters. */ + if (ospeed < 0) + return (EINVAL); + if (t->c_ispeed && t->c_ispeed != ospeed) + return (EINVAL); + + /* + * For the console, always force CLOCAL and !HUPCL, so that the port + * is always active. + */ + if (ISSET(zst->zst_swflags, TIOCFLAG_SOFTCAR) || + ISSET(zst->zst_hwflags, ZS_HWFLAG_CONSOLE)) { + SET(cflag, CLOCAL); + CLR(cflag, HUPCL); + } + + /* + * Only whack the UART when params change. + * Some callers need to clear tp->t_ospeed + * to make sure initialization gets done. + */ + if (tp->t_ospeed == ospeed && + tp->t_cflag == cflag) + return (0); + + /* + * Call MD functions to deal with changed + * clock modes or H/W flow control modes. + * The BRG divisor is set now. (reg 12,13) + */ + error = zs_set_speed(cs, ospeed); + if (error) + return (error); + error = zs_set_modes(cs, cflag); + if (error) + return (error); + + /* + * Block interrupts so that state will not + * be altered until we are done setting it up. + * + * Initial values in cs_preg are set before + * our attach routine is called. The master + * interrupt enable is handled by zsc.c + */ + s = splzs(); + + /* + * Recalculate which status ints to enable. + */ + zs_maskintr(zst); + + /* Recompute character size bits. */ + tmp3 = cs->cs_preg[3]; + tmp5 = cs->cs_preg[5]; + CLR(tmp3, ZSWR3_RXSIZE); + CLR(tmp5, ZSWR5_TXSIZE); + switch (ISSET(cflag, CSIZE)) { + case CS5: + SET(tmp3, ZSWR3_RX_5); + SET(tmp5, ZSWR5_TX_5); + break; + case CS6: + SET(tmp3, ZSWR3_RX_6); + SET(tmp5, ZSWR5_TX_6); + break; + case CS7: + SET(tmp3, ZSWR3_RX_7); + SET(tmp5, ZSWR5_TX_7); + break; + case CS8: + SET(tmp3, ZSWR3_RX_8); + SET(tmp5, ZSWR5_TX_8); + break; + } + cs->cs_preg[3] = tmp3; + cs->cs_preg[5] = tmp5; + + /* + * Recompute the stop bits and parity bits. Note that + * zs_set_speed() may have set clock selection bits etc. + * in wr4, so those must preserved. + */ + tmp4 = cs->cs_preg[4]; + CLR(tmp4, ZSWR4_SBMASK | ZSWR4_PARMASK); + if (ISSET(cflag, CSTOPB)) + SET(tmp4, ZSWR4_TWOSB); + else + SET(tmp4, ZSWR4_ONESB); + if (!ISSET(cflag, PARODD)) + SET(tmp4, ZSWR4_EVENP); + if (ISSET(cflag, PARENB)) + SET(tmp4, ZSWR4_PARENB); + cs->cs_preg[4] = tmp4; + + /* And copy to tty. */ + tp->t_ispeed = 0; + tp->t_ospeed = ospeed; + tp->t_cflag = cflag; + + /* + * If nothing is being transmitted, set up new current values, + * else mark them as pending. + */ + if (!cs->cs_heldchange) { + if (zst->zst_tx_busy) { + zst->zst_heldtbc = zst->zst_tbc; + zst->zst_tbc = 0; + cs->cs_heldchange = 1; + } else + zs_loadchannelregs(cs); + } + + /* + * If hardware flow control is disabled, turn off the buffer water + * marks and unblock any soft flow control state. Otherwise, enable + * the water marks. + */ + if (!ISSET(cflag, CHWFLOW)) { + zst->zst_r_hiwat = 0; + zst->zst_r_lowat = 0; + if (ISSET(zst->zst_rx_flags, RX_TTY_OVERFLOWED)) { + CLR(zst->zst_rx_flags, RX_TTY_OVERFLOWED); + zst->zst_rx_ready = 1; + cs->cs_softreq = 1; + } + if (ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED)) { + CLR(zst->zst_rx_flags, RX_TTY_BLOCKED|RX_IBUF_BLOCKED); + zs_hwiflow(zst); + } + } else { + zst->zst_r_hiwat = zstty_rbuf_hiwat; + zst->zst_r_lowat = zstty_rbuf_lowat; + } + + /* + * Force a recheck of the hardware carrier and flow control status, + * since we may have changed which bits we're looking at. + */ + zstty_stint(cs, 1); + + splx(s); + + /* + * If hardware flow control is disabled, unblock any hard flow control + * state. + */ + if (!ISSET(cflag, CHWFLOW)) { + if (zst->zst_tx_stopped) { + zst->zst_tx_stopped = 0; + zsstart(tp); + } + } + + zstty_softint(cs); + + return (0); +} + +/* + * Compute interupt enable bits and set in the pending bits. Called both + * in zsparam() and when PPS (pulse per second timing) state changes. + * Must be called at splzs(). + */ +void +zs_maskintr(zst) + struct zstty_softc *zst; +{ + struct zs_chanstate *cs = zst->zst_cs; + int tmp15; + + cs->cs_rr0_mask = cs->cs_rr0_cts | cs->cs_rr0_dcd; + if (zst->zst_ppsmask != 0) + cs->cs_rr0_mask |= cs->cs_rr0_pps; + tmp15 = cs->cs_preg[15]; + if (ISSET(cs->cs_rr0_mask, ZSRR0_DCD)) + SET(tmp15, ZSWR15_DCD_IE); + else + CLR(tmp15, ZSWR15_DCD_IE); + if (ISSET(cs->cs_rr0_mask, ZSRR0_CTS)) + SET(tmp15, ZSWR15_CTS_IE); + else + CLR(tmp15, ZSWR15_CTS_IE); + cs->cs_preg[15] = tmp15; +} + +/* + * Raise or lower modem control (DTR/RTS) signals. If a character is + * in transmission, the change is deferred. + */ +void +zs_modem(zst, onoff) + struct zstty_softc *zst; + int onoff; +{ + struct zs_chanstate *cs = zst->zst_cs; + + if (cs->cs_wr5_dtr == 0) + return; + + if (onoff) + SET(cs->cs_preg[5], cs->cs_wr5_dtr); + else + CLR(cs->cs_preg[5], cs->cs_wr5_dtr); + + if (!cs->cs_heldchange) { + if (zst->zst_tx_busy) { + zst->zst_heldtbc = zst->zst_tbc; + zst->zst_tbc = 0; + cs->cs_heldchange = 1; + } else + zs_loadchannelregs(cs); + } +} + +void +tiocm_to_zs(zst, how, ttybits) + struct zstty_softc *zst; + u_long how; + int ttybits; +{ + struct zs_chanstate *cs = zst->zst_cs; + u_char zsbits; + + zsbits = 0; + if (ISSET(ttybits, TIOCM_DTR)) + SET(zsbits, ZSWR5_DTR); + if (ISSET(ttybits, TIOCM_RTS)) + SET(zsbits, ZSWR5_RTS); + + switch (how) { + case TIOCMBIC: + CLR(cs->cs_preg[5], zsbits); + break; + + case TIOCMBIS: + SET(cs->cs_preg[5], zsbits); + break; + + case TIOCMSET: + CLR(cs->cs_preg[5], ZSWR5_RTS | ZSWR5_DTR); + SET(cs->cs_preg[5], zsbits); + break; + } + + if (!cs->cs_heldchange) { + if (zst->zst_tx_busy) { + zst->zst_heldtbc = zst->zst_tbc; + zst->zst_tbc = 0; + cs->cs_heldchange = 1; + } else + zs_loadchannelregs(cs); + } +} + +int +zs_to_tiocm(zst) + struct zstty_softc *zst; +{ + struct zs_chanstate *cs = zst->zst_cs; + u_char zsbits; + int ttybits = 0; + + zsbits = cs->cs_preg[5]; + if (ISSET(zsbits, ZSWR5_DTR)) + SET(ttybits, TIOCM_DTR); + if (ISSET(zsbits, ZSWR5_RTS)) + SET(ttybits, TIOCM_RTS); + + zsbits = cs->cs_rr0; + if (ISSET(zsbits, ZSRR0_DCD)) + SET(ttybits, TIOCM_CD); + if (ISSET(zsbits, ZSRR0_CTS)) + SET(ttybits, TIOCM_CTS); + + return (ttybits); +} + +/* + * Try to block or unblock input using hardware flow-control. + * This is called by kern/tty.c if MDMBUF|CRTSCTS is set, and + * if this function returns non-zero, the TS_TBLOCK flag will + * be set or cleared according to the "block" arg passed. + */ +int +zshwiflow(tp, block) + struct tty *tp; + int block; +{ + struct zstty_softc *zst; + struct zs_chanstate *cs; + int s; + + zst = zstty_cd.cd_devs[minor(tp->t_dev)]; + cs = zst->zst_cs; + + if (cs->cs_wr5_rts == 0) + return (0); + + s = splzs(); + if (block) { + if (!ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED)) { + SET(zst->zst_rx_flags, RX_TTY_BLOCKED); + zs_hwiflow(zst); + } + } else { + if (ISSET(zst->zst_rx_flags, RX_TTY_OVERFLOWED)) { + CLR(zst->zst_rx_flags, RX_TTY_OVERFLOWED); + zst->zst_rx_ready = 1; + cs->cs_softreq = 1; + } + if (ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED)) { + CLR(zst->zst_rx_flags, RX_TTY_BLOCKED); + zs_hwiflow(zst); + } + } + splx(s); + return (1); +} + +/* + * Internal version of zshwiflow + * called at splzs + */ +void +zs_hwiflow(zst) + struct zstty_softc *zst; +{ + struct zs_chanstate *cs = zst->zst_cs; + + if (cs->cs_wr5_rts == 0) + return; + + if (ISSET(zst->zst_rx_flags, RX_ANY_BLOCK)) { + CLR(cs->cs_preg[5], cs->cs_wr5_rts); + CLR(cs->cs_creg[5], cs->cs_wr5_rts); + } else { + SET(cs->cs_preg[5], cs->cs_wr5_rts); + SET(cs->cs_creg[5], cs->cs_wr5_rts); + } + zs_write_reg(cs, 5, cs->cs_creg[5]); +} + + +/**************************************************************** + * Interface to the lower layer (zscc) + ****************************************************************/ + +void zstty_rxsoft(struct zstty_softc *, struct tty *); +void zstty_txsoft(struct zstty_softc *, struct tty *); +void zstty_stsoft(struct zstty_softc *, struct tty *); + +/* + * receiver ready interrupt. + * called at splzs + */ +void +zstty_rxint(cs) + struct zs_chanstate *cs; +{ + struct zstty_softc *zst = cs->cs_private; + u_char *put, *end; + u_int cc; + u_char rr0, rr1, c; + + end = zst->zst_ebuf; + put = zst->zst_rbput; + cc = zst->zst_rbavail; + + while (cc > 0) { + /* + * First read the status, because reading the received char + * destroys the status of this char. + */ + rr1 = zs_read_reg(cs, 1); + c = zs_read_data(cs); + + if (ISSET(rr1, ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) { + /* Clear the receive error. */ + zs_write_csr(cs, ZSWR0_RESET_ERRORS); + } + + put[0] = c; + put[1] = rr1; + put += 2; + if (put >= end) + put = zst->zst_rbuf; + cc--; + + rr0 = zs_read_csr(cs); + if (!ISSET(rr0, ZSRR0_RX_READY)) + break; + } + + /* + * Current string of incoming characters ended because + * no more data was available or we ran out of space. + * Schedule a receive event if any data was received. + * If we're out of space, turn off receive interrupts. + */ + zst->zst_rbput = put; + zst->zst_rbavail = cc; + if (!ISSET(zst->zst_rx_flags, RX_TTY_OVERFLOWED)) { + zst->zst_rx_ready = 1; + cs->cs_softreq = 1; + } + + /* + * See if we are in danger of overflowing a buffer. If + * so, use hardware flow control to ease the pressure. + */ + if (!ISSET(zst->zst_rx_flags, RX_IBUF_BLOCKED) && + cc < zst->zst_r_hiwat) { + SET(zst->zst_rx_flags, RX_IBUF_BLOCKED); + zs_hwiflow(zst); + } + + /* + * If we're out of space, disable receive interrupts + * until the queue has drained a bit. + */ + if (!cc) { + SET(zst->zst_rx_flags, RX_IBUF_OVERFLOWED); + CLR(cs->cs_preg[1], ZSWR1_RIE); + cs->cs_creg[1] = cs->cs_preg[1]; + zs_write_reg(cs, 1, cs->cs_creg[1]); + } +} + +/* + * transmitter ready interrupt. (splzs) + */ +void +zstty_txint(cs) + struct zs_chanstate *cs; +{ + struct zstty_softc *zst = cs->cs_private; + + /* + * If we've delayed a parameter change, do it now, and restart + * output. + */ + if (cs->cs_heldchange) { + zs_loadchannelregs(cs); + cs->cs_heldchange = 0; + zst->zst_tbc = zst->zst_heldtbc; + zst->zst_heldtbc = 0; + } + + /* Output the next character in the buffer, if any. */ + if (zst->zst_tbc > 0) { + zs_write_data(cs, *zst->zst_tba); + zst->zst_tbc--; + zst->zst_tba++; + } else { + /* Disable transmit completion interrupts if necessary. */ + if (ISSET(cs->cs_preg[1], ZSWR1_TIE)) { + CLR(cs->cs_preg[1], ZSWR1_TIE); + cs->cs_creg[1] = cs->cs_preg[1]; + zs_write_reg(cs, 1, cs->cs_creg[1]); + } + if (zst->zst_tx_busy) { + zst->zst_tx_busy = 0; + zst->zst_tx_done = 1; + cs->cs_softreq = 1; + } + } +} + +#ifdef DDB +#include <ddb/db_var.h> +#define DB_CONSOLE db_console +#else +#define DB_CONSOLE 1 +#endif + +/* + * status change interrupt. (splzs) + */ +void +zstty_stint(cs, force) + struct zs_chanstate *cs; + int force; +{ + struct zstty_softc *zst = cs->cs_private; + u_char rr0, delta; + + rr0 = zs_read_csr(cs); + zs_write_csr(cs, ZSWR0_RESET_STATUS); + + /* + * Check here for console break, so that we can abort + * even when interrupts are locking up the machine. + */ + if ((zst->zst_hwflags & ZS_HWFLAG_CONSOLE_INPUT) && + ISSET(rr0, ZSRR0_BREAK) && DB_CONSOLE) + zs_abort(cs); + + if (!force) + delta = rr0 ^ cs->cs_rr0; + else + delta = cs->cs_rr0_mask; + cs->cs_rr0 = rr0; + + if (ISSET(delta, cs->cs_rr0_mask)) { + SET(cs->cs_rr0_delta, delta); + + /* + * Stop output immediately if we lose the output + * flow control signal or carrier detect. + */ + if (ISSET(~rr0, cs->cs_rr0_mask)) { + zst->zst_tbc = 0; + zst->zst_heldtbc = 0; + } + + zst->zst_st_check = 1; + cs->cs_softreq = 1; + } +} + +void +zstty_diag(arg) + void *arg; +{ + struct zstty_softc *zst = arg; + int overflows, floods; + int s; + + s = splzs(); + overflows = zst->zst_overflows; + zst->zst_overflows = 0; + floods = zst->zst_floods; + zst->zst_floods = 0; + zst->zst_errors = 0; + splx(s); + + log(LOG_WARNING, "%s: %d silo overflow%s, %d ibuf flood%s\n", + zst->zst_dev.dv_xname, + overflows, overflows == 1 ? "" : "s", + floods, floods == 1 ? "" : "s"); +} + +void +zstty_rxsoft(zst, tp) + struct zstty_softc *zst; + struct tty *tp; +{ + struct zs_chanstate *cs = zst->zst_cs; + int (*rint)(int c, struct tty *tp) = linesw[tp->t_line].l_rint; + u_char *get, *end; + u_int cc, scc; + u_char rr1; + int code; + int s; + + end = zst->zst_ebuf; + get = zst->zst_rbget; + scc = cc = zstty_rbuf_size - zst->zst_rbavail; + + if (cc == zstty_rbuf_size) { + zst->zst_floods++; + if (zst->zst_errors++ == 0) + timeout_add(&zst->zst_diag_ch, 60 * hz); + } + + /* If not yet open, drop the entire buffer content here */ + if (!ISSET(tp->t_state, TS_ISOPEN)) { + get += cc << 1; + if (get >= end) + get -= zstty_rbuf_size << 1; + cc = 0; + } + while (cc) { + code = get[0]; + rr1 = get[1]; + if (ISSET(rr1, ZSRR1_DO | ZSRR1_FE | ZSRR1_PE)) { + if (ISSET(rr1, ZSRR1_DO)) { + zst->zst_overflows++; + if (zst->zst_errors++ == 0) + timeout_add(&zst->zst_diag_ch, 60 * hz); + } + if (ISSET(rr1, ZSRR1_FE)) + SET(code, TTY_FE); + if (ISSET(rr1, ZSRR1_PE)) + SET(code, TTY_PE); + } + if ((*rint)(code, tp) == -1) { + /* + * The line discipline's buffer is out of space. + */ + if (!ISSET(zst->zst_rx_flags, RX_TTY_BLOCKED)) { + /* + * We're either not using flow control, or the + * line discipline didn't tell us to block for + * some reason. Either way, we have no way to + * know when there's more space available, so + * just drop the rest of the data. + */ + get += cc << 1; + if (get >= end) + get -= zstty_rbuf_size << 1; + cc = 0; + } else { + /* + * Don't schedule any more receive processing + * until the line discipline tells us there's + * space available (through comhwiflow()). + * Leave the rest of the data in the input + * buffer. + */ + SET(zst->zst_rx_flags, RX_TTY_OVERFLOWED); + } + break; + } + get += 2; + if (get >= end) + get = zst->zst_rbuf; + cc--; + } + + if (cc != scc) { + zst->zst_rbget = get; + s = splzs(); + cc = zst->zst_rbavail += scc - cc; + /* Buffers should be ok again, release possible block. */ + if (cc >= zst->zst_r_lowat) { + if (ISSET(zst->zst_rx_flags, RX_IBUF_OVERFLOWED)) { + CLR(zst->zst_rx_flags, RX_IBUF_OVERFLOWED); + SET(cs->cs_preg[1], ZSWR1_RIE); + cs->cs_creg[1] = cs->cs_preg[1]; + zs_write_reg(cs, 1, cs->cs_creg[1]); + } + if (ISSET(zst->zst_rx_flags, RX_IBUF_BLOCKED)) { + CLR(zst->zst_rx_flags, RX_IBUF_BLOCKED); + zs_hwiflow(zst); + } + } + splx(s); + } +} + +void +zstty_txsoft(zst, tp) + struct zstty_softc *zst; + struct tty *tp; +{ + + CLR(tp->t_state, TS_BUSY); + if (ISSET(tp->t_state, TS_FLUSH)) + CLR(tp->t_state, TS_FLUSH); + else + ndflush(&tp->t_outq, (int)(zst->zst_tba - tp->t_outq.c_cf)); + (*linesw[tp->t_line].l_start)(tp); +} + +void +zstty_stsoft(zst, tp) + struct zstty_softc *zst; + struct tty *tp; +{ + struct zs_chanstate *cs = zst->zst_cs; + u_char rr0, delta; + int s; + + s = splzs(); + rr0 = cs->cs_rr0; + delta = cs->cs_rr0_delta; + cs->cs_rr0_delta = 0; + splx(s); + + if (ISSET(delta, cs->cs_rr0_dcd)) { + /* + * Inform the tty layer that carrier detect changed. + */ + (void) (*linesw[tp->t_line].l_modem)(tp, ISSET(rr0, ZSRR0_DCD)); + } + + if (ISSET(delta, cs->cs_rr0_cts)) { + /* Block or unblock output according to flow control. */ + if (ISSET(rr0, cs->cs_rr0_cts)) { + zst->zst_tx_stopped = 0; + (*linesw[tp->t_line].l_start)(tp); + } else { + zst->zst_tx_stopped = 1; + } + } +} + +/* + * Software interrupt. Called at zssoft + * + * The main job to be done here is to empty the input ring + * by passing its contents up to the tty layer. The ring is + * always emptied during this operation, therefore the ring + * must not be larger than the space after "high water" in + * the tty layer, or the tty layer might drop our input. + * + * Note: an "input blockage" condition is assumed to exist if + * EITHER the TS_TBLOCK flag or zst_rx_blocked flag is set. + */ +void +zstty_softint(cs) + struct zs_chanstate *cs; +{ + struct zstty_softc *zst = cs->cs_private; + struct tty *tp = zst->zst_tty; + int s; + + s = spltty(); + + if (zst->zst_rx_ready) { + zst->zst_rx_ready = 0; + zstty_rxsoft(zst, tp); + } + + if (zst->zst_st_check) { + zst->zst_st_check = 0; + zstty_stsoft(zst, tp); + } + + if (zst->zst_tx_done) { + zst->zst_tx_done = 0; + zstty_txsoft(zst, tp); + } + + splx(s); +} + +struct zsops zsops_tty = { + zstty_rxint, /* receive char available */ + zstty_stint, /* external/status */ + zstty_txint, /* xmit buffer empty */ + zstty_softint, /* process software interrupt */ +}; diff --git a/sys/arch/sparc/dev/zs.c b/sys/arch/sparc/dev/zs.c index 939d920573a..d04916989e6 100644 --- a/sys/arch/sparc/dev/zs.c +++ b/sys/arch/sparc/dev/zs.c @@ -1,18 +1,12 @@ -/* $OpenBSD: zs.c,v 1.35 2002/04/30 01:12:29 art Exp $ */ -/* $NetBSD: zs.c,v 1.49 1997/08/31 21:26:37 pk Exp $ */ +/* $OpenBSD: zs.c,v 1.36 2002/08/12 10:44:04 miod Exp $ */ +/* $NetBSD: zs.c,v 1.50 1997/10/18 00:00:40 gwr Exp $ */ -/* - * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. - * - * This software was developed by the Computer Systems Engineering group - * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and - * contributed to Berkeley. +/*- + * Copyright (c) 1996 The NetBSD Foundation, Inc. + * All rights reserved. * - * 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, Lawrence Berkeley Laboratory. + * This code is derived from software contributed to The NetBSD Foundation + * by Gordon W. Ross. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,82 +18,86 @@ * 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. + * 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. * - * @(#)zs.c 8.1 (Berkeley) 7/19/93 + * 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 FOUNDATION 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. */ /* - * Zilog Z8530 (ZSCC) driver. + * Zilog Z8530 Dual UART driver (machine-dependent part) * - * Runs two tty ports (ttya and ttyb) on zs0, - * and runs a keyboard and mouse on zs1, and - * possibly two more tty ports (ttyc and ttyd) on zs2. - * - * This driver knows far too much about chip to usage mappings. + * Runs two serial lines per chip using slave drivers. + * Plain tty/async lines use the zs_async slave. + * Sun keyboard/mouse uses the zs_kbd/zs_ms slaves. */ -#include "zs.h" -#include "kbd.h" #include <sys/param.h> #include <sys/systm.h> -#include <sys/proc.h> +#include <sys/conf.h> #include <sys/device.h> #include <sys/file.h> #include <sys/ioctl.h> -#include <sys/malloc.h> +#include <sys/kernel.h> +#include <sys/proc.h> #include <sys/tty.h> #include <sys/time.h> -#include <sys/kernel.h> #include <sys/syslog.h> -#include <sys/conf.h> -#ifdef DDB -#include <ddb/db_var.h> -#endif - -#include <uvm/uvm_extern.h> #include <machine/autoconf.h> +#include <machine/bsd_openprom.h> #include <machine/conf.h> #include <machine/cpu.h> -#include <machine/kbd.h> +#include <machine/eeprom.h> +#if defined(SUN4) +#include <machine/oldmon.h> +#endif +#include <machine/psl.h> +#include <machine/z8530var.h> + +#include <dev/cons.h> +#include <sparc/dev/z8530reg.h> #include <sparc/sparc/vaddrs.h> #include <sparc/sparc/auxioreg.h> -#include <dev/ic/z8530reg.h> -#include <sparc/dev/zsvar.h> +#include <sparc/dev/cons.h> -#ifdef KGDB -#include <sys/kgdb.h> -#include <machine/remote-sl.h> -#endif +#include <uvm/uvm_extern.h> -#define DEVUNIT(x) (minor(x) & 0x7f) -#define DEVCUA(x) (minor(x) & 0x80) +#include "zskbd.h" +#include "zs.h" -#define ZSMAJOR 12 /* XXX */ +/* Make life easier for the initialized arrays here. */ +#if NZS < 3 +#undef NZS +#define NZS 3 +#endif -#define ZS_KBD 2 /* XXX */ -#define ZS_MOUSE 3 /* XXX */ +/* + * Some warts needed by z8530tty.c - + * The default parity REALLY needs to be the same as the PROM uses, + * or you can not see messages done with printf during boot-up... + */ +int zs_def_cflag = (CREAD | CS8 | HUPCL); +int zs_major = 12; -/* the magic number below was stolen from the Sprite source. */ -#define PCLK (19660800/4) /* PCLK pin input clock rate */ +/* + * The Sun provides a 4.9152 MHz clock to the ZS chips. + */ +#define PCLK (9600 * 512) /* PCLK pin input clock rate */ /* * Select software interrupt bit based on TTY ipl. @@ -114,147 +112,122 @@ # error "no suitable software interrupt bit" #endif -/* - * Software state per found chip. - */ -struct zs_softc { - struct device sc_dev; /* base device */ - volatile struct zsdevice *sc_zs; /* chip registers */ - struct evcnt sc_intrcnt; /* count interrupts */ - struct zs_chanstate sc_cs[2]; /* chan A/B software state */ +#define ZS_DELAY() (CPU_ISSUN4C ? (0) : delay(2)) + +/* The layout of this is hardware-dependent (padding, order). */ +struct zschan { + volatile u_char zc_csr; /* ctrl,status, and indirect access */ + u_char zc_xxx0; + volatile u_char zc_data; /* data */ + u_char zc_xxx1; +}; +struct zsdevice { + /* Yes, they are backwards. */ + struct zschan zs_chan_b; + struct zschan zs_chan_a; }; -/* Definition of the driver for autoconfig. */ -static int zsmatch(struct device *, void *, void *); -static void zsattach(struct device *, struct device *, void *); +/* Saved PROM mappings */ +struct zsdevice *zsaddr[NZS]; -struct cfattach zs_ca = { - sizeof(struct zs_softc), zsmatch, zsattach -}; +/* Flags from cninit() */ +int zs_hwflags[NZS][2]; -struct cfdriver zs_cd = { - NULL, "zs", DV_TTY +/* Default speed for each channel */ +int zs_defspeed[NZS][2] = { + { 9600, /* ttya */ + 9600 }, /* ttyb */ + { 1200, /* keyboard */ + 1200 }, /* mouse */ + { 9600, /* ttyc */ + 9600 }, /* ttyd */ }; -/* Interrupt handlers. */ -static int zshard(void *); -static struct intrhand levelhard = { zshard }; -static int zssoft(void *); -static struct intrhand levelsoft = { zssoft }; - -struct zs_chanstate *zslist; - -/* Routines called from other code. */ -static void zsiopen(struct tty *); -static void zsiclose(struct tty *); -static void zsstart(struct tty *); -static int zsparam(struct tty *, struct termios *); - -/* Routines purely local to this driver. */ -static int zs_getspeed(volatile struct zschan *); -#ifdef KGDB -static void zs_reset(volatile struct zschan *, int, int); -#endif -static void zs_modem(struct zs_chanstate *, int); -static void zs_loadchannelregs(volatile struct zschan *, u_char *); -static void tiocm_to_zs(struct zs_chanstate *, int how, int data); - -/* Console stuff. */ -static struct tty *zs_ctty; /* console `struct tty *' */ -static int zs_consin = -1, zs_consout = -1; -static struct zs_chanstate *zs_conscs = NULL; /*console channel state */ -static void zscnputc(int); /* console putc function */ -static volatile struct zschan *zs_conschan; -static struct tty *zs_checkcons(struct zs_softc *, int, - struct zs_chanstate *); - -#ifdef KGDB -/* KGDB stuff. Must reboot to change zs_kgdbunit. */ -extern int kgdb_dev, kgdb_rate; -static int zs_kgdb_savedspeed; -static void zs_checkkgdb(int, struct zs_chanstate *, struct tty *); -void zskgdb(int); -static int zs_kgdb_getc(void *); -static void zs_kgdb_putc(void *, int); -#endif +u_char zs_init_reg[16] = { + 0, /* 0: CMD (reset, etc.) */ + 0, /* 1: No interrupts yet. */ + 0, /* 2: IVECT */ + ZSWR3_RX_8 | ZSWR3_RX_ENABLE, + ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP, + ZSWR5_TX_8 | ZSWR5_TX_ENABLE, + 0, /* 6: TXSYNC/SYNCLO */ + 0, /* 7: RXSYNC/SYNCHI */ + 0, /* 8: alias for data port */ + ZSWR9_MASTER_IE | ZSWR9_NO_VECTOR, + 0, /*10: Misc. TX/RX control bits */ + ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD, + ((PCLK/32)/9600)-2, /*12: BAUDLO (default=9600) */ + 0, /*13: BAUDHI (default=9600) */ + ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK, + ZSWR15_BREAK_IE /* | ZSWR15_DCD_IE */, +}; -static int zsrint(struct zs_chanstate *, volatile struct zschan *); -static int zsxint(struct zs_chanstate *, volatile struct zschan *); -static int zssint(struct zs_chanstate *, volatile struct zschan *); +struct zschan * +zs_get_chan_addr(zs_unit, channel) + int zs_unit, channel; +{ + struct zsdevice *addr; + struct zschan *zc; + + if (zs_unit >= NZS) + return NULL; + addr = zsaddr[zs_unit]; + if (addr == NULL) + addr = zsaddr[zs_unit] = findzs(zs_unit); + if (addr == NULL) + return NULL; + if (channel == 0) { + zc = &addr->zs_chan_a; + } else { + zc = &addr->zs_chan_b; + } + return (zc); +} -void zsabort(int); -static void zsoverrun(int, long *, char *); -static volatile struct zsdevice *zsaddr[NZS]; /* XXX, but saves work */ +/**************************************************************** + * Autoconfig + ****************************************************************/ -/* - * Console keyboard L1-A processing is done in the hardware interrupt code, - * so we need to duplicate some of the console keyboard decode state. (We - * must not use the regular state as the hardware code keeps ahead of the - * software state: the software state tracks the most recent ring input but - * the hardware state tracks the most recent ZSCC input.) See also kbd.h. - */ -static struct conk_state { /* console keyboard state */ - char conk_id; /* true => ID coming up (console only) */ - char conk_l1; /* true => L1 pressed (console only) */ -} zsconk_state; +/* Definition of the driver for autoconfig. */ +int zs_match(struct device *, void *, void *); +void zs_attach(struct device *, struct device *, void *); +int zs_print(void *, const char *nam); -int zshardscope; -int zsshortcuts; /* number of "shortcut" software interrupts */ +struct cfattach zs_ca = { + sizeof(struct zsc_softc), zs_match, zs_attach +}; -#ifdef SUN4 -static u_int zs_read(volatile struct zschan *, u_int reg); -static u_int zs_write(volatile struct zschan *, u_int, u_int); +struct cfdriver zs_cd = { + NULL, "zs", DV_DULL +}; -static u_int -zs_read(zc, reg) - volatile struct zschan *zc; - u_int reg; -{ - u_char val; +/* Interrupt handlers. */ +int zshard(void *); +int zssoft(void *); +struct intrhand levelhard = { zshard }; +struct intrhand levelsoft = { zssoft }; - zc->zc_csr = reg; - ZS_DELAY(); - val = zc->zc_csr; - ZS_DELAY(); - return val; -} +int zs_get_speed(struct zs_chanstate *); -static u_int -zs_write(zc, reg, val) - volatile struct zschan *zc; - u_int reg, val; -{ - zc->zc_csr = reg; - ZS_DELAY(); - zc->zc_csr = val; - ZS_DELAY(); - return val; -} -#endif /* SUN4 */ /* - * Match slave number to zs unit number, so that misconfiguration will - * not set up the keyboard as ttya, etc. + * Is the zs chip present? */ -static int -zsmatch(parent, vcf, aux) +int +zs_match(parent, vcf, aux) struct device *parent; void *vcf, *aux; { - struct cfdata *cf = vcf; - struct confargs *ca = aux; + struct cfdata *cf = (struct cfdata *)vcf; + struct confargs *ca = (struct confargs *)aux; struct romaux *ra = &ca->ca_ra; if (strcmp(cf->cf_driver->cd_name, ra->ra_name)) return (0); if ((ca->ca_bustype == BUS_MAIN && !CPU_ISSUN4) || - (ca->ca_bustype == BUS_OBIO && CPU_ISSUN4M)) { - if (getpropint(ra->ra_node, "slave", -2) == cf->cf_unit && - findzs(cf->cf_unit)) - return (1); - return (0); - } + (ca->ca_bustype == BUS_OBIO && CPU_ISSUN4M)) + return (getpropint(ra->ra_node, "slave", -2) == cf->cf_unit); ra->ra_len = NBPG; return (probeget(ra->ra_vaddr, 1) != -1); } @@ -265,27 +238,29 @@ zsmatch(parent, vcf, aux) * USE ROM PROPERTIES port-a-ignore-cd AND port-b-ignore-cd FOR * SOFT CARRIER, AND keyboard PROPERTY FOR KEYBOARD/MOUSE? */ -static void -zsattach(parent, dev, aux) +void +zs_attach(parent, self, aux) struct device *parent; - struct device *dev; + struct device *self; void *aux; { - register int zs = dev->dv_unit, unit; - register struct zs_softc *sc; - register struct zs_chanstate *cs; - register volatile struct zsdevice *addr; - register struct tty *tp, *ctp; - register struct confargs *ca = aux; - register struct romaux *ra = &ca->ca_ra; - int pri; + struct zsc_softc *zsc = (void *) self; + struct confargs *ca = aux; + struct romaux *ra = &ca->ca_ra; + struct zsc_attach_args zsc_args; + volatile struct zschan *zc; + struct zs_chanstate *cs; + int pri, s, zs_unit, channel; static int didintr, prevpri; - int ringsize; - if ((addr = zsaddr[zs]) == NULL) - addr = zsaddr[zs] = (volatile struct zsdevice *)findzs(zs); + zs_unit = zsc->zsc_dev.dv_unit; + + /* Use the mapping setup by the Sun PROM. */ + if (zsaddr[zs_unit] == NULL) + zsaddr[zs_unit] = findzs(zs_unit); + if (ca->ca_bustype==BUS_MAIN) - if ((void *)addr != ra->ra_vaddr) + if ((void*)zsaddr[zs_unit] != ra->ra_vaddr) panic("zsattach"); if (ra->ra_nintr != 1) { printf(": expected 1 interrupt, got %d\n", ra->ra_nintr); @@ -293,6 +268,79 @@ zsattach(parent, dev, aux) } pri = ra->ra_intr[0].int_pri; printf(" pri %d, softpri %d\n", pri, IPL_TTY); + + /* + * Initialize software state for each channel. + */ + for (channel = 0; channel < 2; channel++) { + zsc_args.type = "serial"; + /* XXX hardcoded */ + if (zs_unit == 1) { + if (channel == 0) + zsc_args.type = "keyboard"; + if (channel == 1) + zsc_args.type = "mouse"; + } + + zsc_args.channel = channel; + zsc_args.hwflags = zs_hwflags[zs_unit][channel]; + cs = &zsc->zsc_cs[channel]; + + cs->cs_channel = channel; + cs->cs_private = NULL; + cs->cs_ops = &zsops_null; + cs->cs_brg_clk = PCLK / 16; + + zc = zs_get_chan_addr(zs_unit, channel); + + cs->cs_reg_csr = &zc->zc_csr; + cs->cs_reg_data = &zc->zc_data; + + bcopy(zs_init_reg, cs->cs_creg, 16); + bcopy(zs_init_reg, cs->cs_preg, 16); + + /* XXX: Get these from the PROM properties! */ + /* XXX: See the mvme167 code. Better. */ + if (zsc_args.hwflags & ZS_HWFLAG_CONSOLE) + cs->cs_defspeed = zs_get_speed(cs); + else + cs->cs_defspeed = zs_defspeed[zs_unit][channel]; + cs->cs_defcflag = zs_def_cflag; + + /* Make these correspond to cs_defcflag (-crtscts) */ + cs->cs_rr0_dcd = ZSRR0_DCD; + cs->cs_rr0_cts = 0; + cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS; + cs->cs_wr5_rts = 0; + + /* + * Clear the master interrupt enable. + * The INTENA is common to both channels, + * so just do it on the A channel. + */ + if (channel == 0) { + zs_write_reg(cs, 9, 0); + } + + /* + * Look for a child driver for this channel. + * The child attach will setup the hardware. + */ + if (!config_found(self, (void *)&zsc_args, zs_print)) { + /* No sub-driver. Just reset it. */ + u_char reset = (channel == 0) ? + ZSWR9_A_RESET : ZSWR9_B_RESET; + s = splzs(); + zs_write_reg(cs, 9, reset); + splx(s); + } + } + + /* + * Now safe to install interrupt handlers. Note the arguments + * to the interrupt handlers aren't used. Note, we only do this + * once since both SCCs interrupt at the same level and vector. + */ if (!didintr) { didintr = 1; prevpri = pri; @@ -300,1498 +348,753 @@ zsattach(parent, dev, aux) intr_establish(IPL_TTY, &levelsoft, IPL_TTY); } else if (pri != prevpri) panic("broken zs interrupt scheme"); - sc = (struct zs_softc *)dev; - evcnt_attach(&sc->sc_dev, "intr", &sc->sc_intrcnt); - sc->sc_zs = addr; - unit = zs * 2; - cs = sc->sc_cs; - - /* link into interrupt list with order (A,B) (B=A+1) */ - cs[0].cs_next = &cs[1]; - cs[0].cs_sc = sc; - cs[1].cs_next = zslist; - cs[1].cs_sc = sc; - zslist = cs; - - cs->cs_unit = unit; - cs->cs_speed = zs_getspeed(&addr->zs_chan[ZS_CHAN_A]); - cs->cs_zc = &addr->zs_chan[ZS_CHAN_A]; - if ((ctp = zs_checkcons(sc, unit, cs)) != NULL) - tp = ctp; - else { - tp = ttymalloc(); - tp->t_dev = makedev(ZSMAJOR, unit); - tp->t_oproc = zsstart; - tp->t_param = zsparam; - } - cs->cs_ttyp = tp; -#ifdef KGDB - if (ctp == NULL) - zs_checkkgdb(unit, cs, tp); -#endif - if (unit == ZS_KBD) { - /* - * Keyboard: tell /dev/kbd driver how to talk to us. - */ - tp->t_ispeed = tp->t_ospeed = cs->cs_speed; - tp->t_cflag = CS8; -#if NKBD > 0 - kbd_serial(tp, zsiopen, zsiclose); -#endif - cs->cs_conk = 1; /* do L1-A processing */ - ringsize = 128; - } else { - if (tp != ctp) - tty_attach(tp); - ringsize = 4096; - if (unit == zs_consout) - zs_conscs = cs; - } - cs->cs_ringmask = ringsize - 1; - cs->cs_rbuf = malloc((u_long)ringsize * sizeof(*cs->cs_rbuf), - M_DEVBUF, M_NOWAIT); - if (cs->cs_rbuf == NULL) - panic("zsattach"); - - unit++; - cs++; - cs->cs_unit = unit; - cs->cs_speed = zs_getspeed(&addr->zs_chan[ZS_CHAN_B]); - cs->cs_zc = &addr->zs_chan[ZS_CHAN_B]; - if ((ctp = zs_checkcons(sc, unit, cs)) != NULL) - tp = ctp; - else { - tp = ttymalloc(); - tp->t_dev = makedev(ZSMAJOR, unit); - tp->t_oproc = zsstart; - tp->t_param = zsparam; - } - cs->cs_ttyp = tp; -#ifdef KGDB - if (ctp == NULL) - zs_checkkgdb(unit, cs, tp); -#endif - if (unit == ZS_MOUSE) { - /* - * Mouse: tell /dev/mouse driver how to talk to us. - */ - tp->t_ispeed = tp->t_ospeed = B1200; - tp->t_cflag = CS8; - ms_serial(tp, zsiopen, zsiclose); - ringsize = 128; - } else { - if (tp != ctp) - tty_attach(tp); - ringsize = 4096; - if (unit == zs_consout) - zs_conscs = cs; - } - cs->cs_ringmask = ringsize - 1; - cs->cs_rbuf = malloc((u_long)ringsize * sizeof(*cs->cs_rbuf), - M_DEVBUF, M_NOWAIT); - if (cs->cs_rbuf == NULL) - panic("zsattach"); -} - -#ifdef KGDB -/* - * Put a channel in a known state. Interrupts may be left disabled - * or enabled, as desired. - */ -static void -zs_reset(zc, inten, speed) - volatile struct zschan *zc; - int inten, speed; -{ - int tconst; - static u_char reg[16] = { - 0, - 0, - 0, - ZSWR3_RX_8 | ZSWR3_RX_ENABLE, - ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP, - ZSWR5_TX_8 | ZSWR5_TX_ENABLE, - 0, - 0, - 0, - 0, - ZSWR10_NRZ, - ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD, - 0, - 0, - ZSWR14_BAUD_FROM_PCLK | ZSWR14_BAUD_ENA, - ZSWR15_BREAK_IE | ZSWR15_DCD_IE, - }; - - reg[9] = inten ? ZSWR9_MASTER_IE | ZSWR9_NO_VECTOR : ZSWR9_NO_VECTOR; - tconst = BPS_TO_TCONST(PCLK / 16, speed); - reg[12] = tconst; - reg[13] = tconst >> 8; - zs_loadchannelregs(zc, reg); -} -#endif - -/* - * Declare the given tty (which is in fact &cons) as a console input - * or output. This happens before the zs chip is attached; the hookup - * is finished later, in zs_setcons() below. - * - * This is used only for ports a and b. The console keyboard is decoded - * independently (we always send unit-2 input to /dev/kbd, which will - * direct it to /dev/console if appropriate). - */ -void -zsconsole(tp, unit, out, fnstop) - register struct tty *tp; - register int unit; - int out; - int (**fnstop)(struct tty *, int); -{ - int zs; - volatile struct zsdevice *addr; - - if (unit >= ZS_KBD) - panic("zsconsole"); - if (out) { - zs_consout = unit; - zs = unit >> 1; - if ((addr = zsaddr[zs]) == NULL) - addr = zsaddr[zs] = (volatile struct zsdevice *)findzs(zs); - zs_conschan = (unit & 1) == 0 ? &addr->zs_chan[ZS_CHAN_A] : - &addr->zs_chan[ZS_CHAN_B]; - v_putc = zscnputc; - } else - zs_consin = unit; - if (fnstop) - *fnstop = &zsstop; - zs_ctty = tp; -} - -/* - * Polled console output putchar. - */ -static void -zscnputc(c) - int c; -{ - volatile struct zschan *zc = zs_conschan; - int s; - - if (c == '\n') - zscnputc('\r'); + evcnt_attach(&zsc->zsc_dev, "intr", &zsc->zsc_intrcnt); - s = splzs(); - while ((zc->zc_csr & ZSRR0_TX_READY) == 0) - ZS_DELAY(); /* - * If transmitter was busy doing regular tty I/O (ZSWR1_TIE on), - * defer our output until the transmit interrupt runs. We still - * sync with TX_READY so we can get by with a single-char "queue". + * Set the master interrupt enable and interrupt vector. + * (common to both channels, do it on A) */ - if (zs_conscs != NULL && (zs_conscs->cs_creg[1] & ZSWR1_TIE)) { - /* - * If previous not yet done, send it now; zsxint() - * will field the interrupt for our char, but doesn't - * care. We're running at sufficiently high spl for - * this to work. - */ - if (zs_conscs->cs_deferred_cc != 0) - zc->zc_data = zs_conscs->cs_deferred_cc; - zs_conscs->cs_deferred_cc = c; - splx(s); - return; - } - zc->zc_data = c; - delay(2); + cs = &zsc->zsc_cs[0]; + s = splhigh(); + /* interrupt vector */ + zs_write_reg(cs, 2, zs_init_reg[2]); + /* master interrupt control (enable) */ + zs_write_reg(cs, 9, zs_init_reg[9]); splx(s); -} - -/* - * Set up the given unit as console input, output, both, or neither, as - * needed. Return console tty if it is to receive console input. - */ -static struct tty * -zs_checkcons(sc, unit, cs) - struct zs_softc *sc; - int unit; - struct zs_chanstate *cs; -{ - register struct tty *tp; - char *i, *o; - - if ((tp = zs_ctty) == NULL) /* XXX */ - return (0); - i = zs_consin == unit ? "input" : NULL; - o = zs_consout == unit ? "output" : NULL; - if (i == NULL && o == NULL) - return (0); - - /* rewire the minor device (gack) */ - tp->t_dev = makedev(major(tp->t_dev), unit); +#if 0 /* - * Rewire input and/or output. Note that baud rate reflects - * input settings, not output settings, but we can do no better - * if the console is split across two ports. - * - * XXX split consoles don't work anyway -- this needs to be - * thrown away and redone + * XXX: L1A hack - We would like to be able to break into + * the debugger during the rest of autoconfiguration, so + * lower interrupts just enough to let zs interrupts in. + * This is done after both zs devices are attached. */ - if (i) { - tp->t_param = zsparam; - tp->t_ispeed = tp->t_ospeed = cs->cs_speed; - tp->t_cflag = CS8; - ttsetwater(tp); + if (zs_unit == 1) { + printf("zs1: enabling zs interrupts\n"); + (void)splfd(); /* XXX: splzs - 1 */ } - if (o) { - tp->t_oproc = zsstart; - } - printf("%s%c: console %s\n", - sc->sc_dev.dv_xname, (unit & 1) + 'a', i ? (o ? "i/o" : i) : o); - cs->cs_consio = 1; - cs->cs_brkabort = 1; - return (tp); +#endif } -#ifdef KGDB -/* - * The kgdb zs port, if any, was altered at boot time (see zs_kgdb_init). - * Pick up the current speed and character size and restore the original - * speed. - */ -static void -zs_checkkgdb(unit, cs, tp) - int unit; - struct zs_chanstate *cs; - struct tty *tp; +int +zs_print(aux, name) + void *aux; + const char *name; { + struct zsc_attach_args *args = aux; - if (kgdb_dev == makedev(ZSMAJOR, unit)) { - tp->t_ispeed = tp->t_ospeed = kgdb_rate; - tp->t_cflag = CS8; - cs->cs_kgdb = 1; - cs->cs_speed = zs_kgdb_savedspeed; - (void) zsparam(tp, &tp->t_termios); - } -} -#endif + if (name != NULL) + printf("%s:", name); -/* - * Compute the current baud rate given a ZSCC channel. - */ -static int -zs_getspeed(zc) - register volatile struct zschan *zc; -{ - register int tconst; + if (args->channel != -1) + printf(" channel %d", args->channel); - tconst = ZS_READ(zc, 12); - tconst |= ZS_READ(zc, 13) << 8; - return (TCONST_TO_BPS(PCLK / 16, tconst)); + return UNCONF; } +volatile int zssoftpending; /* - * Do an internal open. + * Our ZS chips all share a common, autovectored interrupt, + * so we have to look at all of them on each interrupt. */ -static void -zsiopen(tp) - struct tty *tp; +int +zshard(arg) + void *arg; { + struct zsc_softc *zsc; + int unit, rr3, rval, softreq; - (void) zsparam(tp, &tp->t_termios); - ttsetwater(tp); - tp->t_state = TS_ISOPEN | TS_CARR_ON; -} - -/* - * Do an internal close. Eventually we should shut off the chip when both - * ports on it are closed. - */ -static void -zsiclose(tp) - struct tty *tp; -{ + rval = softreq = 0; + for (unit = 0; unit < zs_cd.cd_ndevs; unit++) { + zsc = zs_cd.cd_devs[unit]; + if (zsc == NULL) + continue; + rr3 = zsc_intr_hard(zsc); + /* Count up the interrupts. */ + if (rr3) { + rval |= rr3; + zsc->zsc_intrcnt.ev_count++; + } + softreq |= zsc->zsc_cs[0].cs_softreq; + softreq |= zsc->zsc_cs[1].cs_softreq; + } - ttylclose(tp, 0); /* ??? */ - ttyclose(tp); /* ??? */ - tp->t_state = 0; + /* We are at splzs here, so no need to lock. */ + if (softreq && (zssoftpending == 0)) { + zssoftpending = IE_ZSSOFT; +#if defined(SUN4M) + if (CPU_ISSUN4M) + raise(0, IPL_TTY); + else +#endif + ienab_bis(IE_ZSSOFT); + } + return (rval); } - - /* - * Open a zs serial port. This interface may not be used to open - * the keyboard and mouse ports. (XXX) + * Similar scheme as for zshard (look at all of them) */ int -zsopen(dev, flags, mode, p) - dev_t dev; - int flags; - int mode; - struct proc *p; +zssoft(arg) + void *arg; { - register struct tty *tp; - register struct zs_chanstate *cs; - struct zs_softc *sc; - int unit = DEVUNIT(dev); - int zs = unit >> 1, error, s; - - if (zs >= zs_cd.cd_ndevs || (sc = zs_cd.cd_devs[zs]) == NULL || - unit == ZS_KBD || unit == ZS_MOUSE) - return (ENXIO); - cs = &sc->sc_cs[unit & 1]; - if (cs->cs_consio) - return (ENXIO); /* ??? */ - tp = cs->cs_ttyp; - s = spltty(); - 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_cflag = TTYDEF_CFLAG; - tp->t_lflag = TTYDEF_LFLAG; - tp->t_ispeed = tp->t_ospeed = cs->cs_speed; - } - (void) zsparam(tp, &tp->t_termios); - ttsetwater(tp); -/* XXX start CUA mods */ - if (DEVCUA(dev)) - SET(tp->t_state, TS_CARR_ON); - else - CLR(tp->t_state, TS_CARR_ON); -/* end CUA mods */ - - } else if (tp->t_state & TS_XCLUDE && p->p_ucred->cr_uid != 0) { - splx(s); - return (EBUSY); - } + struct zsc_softc *zsc; + int s, unit; -/* XXX start CUA mods */ - if (DEVCUA(dev)) { - if (ISSET(tp->t_state, TS_ISOPEN)) { - /* Ah, but someone already is dialed in... */ - splx(s); - return EBUSY; - } - cs->cs_cua = 1; /* We go into CUA mode */ - } - - - error = 0; - /* wait for carrier if necessary */ - if (ISSET(flags, O_NONBLOCK)) { - if (!DEVCUA(dev) && cs->cs_cua) { - /* Opening TTY non-blocking... but the CUA is busy */ - splx(s); - return EBUSY; - } - } else { - while (cs->cs_cua || - (!ISSET(tp->t_cflag, CLOCAL) && - !ISSET(tp->t_state, TS_CARR_ON))) { - register int rr0; - - error = 0; - SET(tp->t_state, TS_WOPEN); - - - if (!DEVCUA(dev) && !cs->cs_cua) { - /* loop, turning on the device, until carrier present */ - zs_modem(cs, 1); - /* May never get status intr if carrier already on. -gwr */ - rr0 = cs->cs_zc->zc_csr; - ZS_DELAY(); - if ((rr0 & ZSRR0_DCD) || cs->cs_softcar) - tp->t_state |= TS_CARR_ON; - } - - if ((tp->t_cflag & CLOCAL || tp->t_state & TS_CARR_ON) && - !cs->cs_cua) - break; + /* This is not the only ISR on this IPL. */ + if (zssoftpending == 0) + return (0); - error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH, - ttopen, 0); + /* + * The soft intr. bit will be set by zshard only if + * the variable zssoftpending is zero. The order of + * these next two statements prevents our clearing + * the soft intr bit just after zshard has set it. + */ + /* ienab_bic(IE_ZSSOFT); */ + zssoftpending = 0; - if (!DEVCUA(dev) && cs->cs_cua && error == EINTR) { - error=0; + /* Make sure we call the tty layer at spltty. */ + s = spltty(); + for (unit = 0; unit < zs_cd.cd_ndevs; unit++) { + zsc = zs_cd.cd_devs[unit]; + if (zsc == NULL) continue; - } - - if (error) { - if (!(tp->t_state & TS_ISOPEN)) { - zs_modem(cs, 0); - CLR(tp->t_state, TS_WOPEN); - ttwakeup(tp); - } -/* XXX ordering of this might be important?? */ - if (DEVCUA(dev)) - cs->cs_cua = 0; - CLR(tp->t_state, TS_WOPEN); - splx(s); - return error; - } - if (!DEVCUA(dev) && cs->cs_cua) - continue; - } - } + (void)zsc_intr_soft(zsc); + } splx(s); -/* end CUA mods */ - if (error == 0) - error = linesw[tp->t_line].l_open(dev, tp); - if (error) - zs_modem(cs, 0); - return (error); + return (1); } + /* - * Close a zs serial port. + * Compute the current baud rate given a ZS channel. */ int -zsclose(dev, flags, mode, p) - dev_t dev; - int flags; - int mode; - struct proc *p; +zs_get_speed(cs) + struct zs_chanstate *cs; { - register struct zs_chanstate *cs; - register struct tty *tp; - struct zs_softc *sc; - int unit = DEVUNIT(dev); - int s, st; - - sc = zs_cd.cd_devs[unit >> 1]; - cs = &sc->sc_cs[unit & 1]; - tp = cs->cs_ttyp; - linesw[tp->t_line].l_close(tp, flags); - -/* XXX start CUA mods */ - st = spltty(); -/* end CUA mods */ - if (tp->t_cflag & HUPCL || tp->t_state & TS_WOPEN || - (tp->t_state & TS_ISOPEN) == 0) { - zs_modem(cs, 0); - /* hold low for 1 second */ - (void) tsleep((caddr_t)cs, TTIPRI, ttclos, hz); - } - if (cs->cs_creg[5] & ZSWR5_BREAK) - { - s = splzs(); - cs->cs_preg[5] &= ~ZSWR5_BREAK; - cs->cs_creg[5] &= ~ZSWR5_BREAK; - ZS_WRITE(cs->cs_zc, 5, cs->cs_creg[5]); - splx(s); - } -/* XXX start CUA mods */ - CLR(tp->t_state, TS_CARR_ON | TS_BUSY | TS_FLUSH); - cs->cs_cua = 0; - splx(st); -/* end CUA mods */ - ttyclose(tp); -#ifdef KGDB - /* Reset the speed if we're doing kgdb on this port */ - if (cs->cs_kgdb) { - tp->t_ispeed = tp->t_ospeed = kgdb_rate; - (void) zsparam(tp, &tp->t_termios); - } -#endif - return (0); + int tconst; + + tconst = zs_read_reg(cs, 12); + tconst |= zs_read_reg(cs, 13) << 8; + return (TCONST_TO_BPS(cs->cs_brg_clk, tconst)); } /* - * Read/write zs serial port. + * MD functions for setting the baud rate and control modes. */ int -zsread(dev, uio, flags) - dev_t dev; - struct uio *uio; - int flags; +zs_set_speed(cs, bps) + struct zs_chanstate *cs; + int bps; /* bits per second */ { - register struct zs_chanstate *cs; - register struct zs_softc *sc; - register struct tty *tp; - int unit = DEVUNIT(dev); - - sc = zs_cd.cd_devs[unit >> 1]; - cs = &sc->sc_cs[unit & 1]; - tp = cs->cs_ttyp; - - return (linesw[tp->t_line].l_read(tp, uio, flags)); + int tconst, real_bps; -} + if (bps == 0) + return (0); -int -zswrite(dev, uio, flags) - dev_t dev; - struct uio *uio; - int flags; -{ - register struct zs_chanstate *cs; - register struct zs_softc *sc; - register struct tty *tp; - int unit = DEVUNIT(dev); +#ifdef DIAGNOSTIC + if (cs->cs_brg_clk == 0) + panic("zs_set_speed"); +#endif - sc = zs_cd.cd_devs[unit >> 1]; - cs = &sc->sc_cs[unit & 1]; - tp = cs->cs_ttyp; + tconst = BPS_TO_TCONST(cs->cs_brg_clk, bps); + if (tconst < 0) + return (EINVAL); - return (linesw[tp->t_line].l_write(tp, uio, flags)); -} + /* Convert back to make sure we can do it. */ + real_bps = TCONST_TO_BPS(cs->cs_brg_clk, tconst); -struct tty * -zstty(dev) - dev_t dev; -{ - register struct zs_chanstate *cs; - register struct zs_softc *sc; - int unit = DEVUNIT(dev); + /* XXX - Allow some tolerance here? */ + if (real_bps != bps) + return (EINVAL); - sc = zs_cd.cd_devs[unit >> 1]; - cs = &sc->sc_cs[unit & 1]; + cs->cs_preg[12] = tconst; + cs->cs_preg[13] = tconst >> 8; - return (cs->cs_ttyp); + /* Caller will stuff the pending registers. */ + return (0); } -static int zsrint(struct zs_chanstate *, volatile struct zschan *); -static int zsxint(struct zs_chanstate *, volatile struct zschan *); -static int zssint(struct zs_chanstate *, volatile struct zschan *); - -/* - * ZS hardware interrupt. Scan all ZS channels. NB: we know here that - * channels are kept in (A,B) pairs. - * - * Do just a little, then get out; set a software interrupt if more - * work is needed. - * - * We deliberately ignore the vectoring Zilog gives us, and match up - * only the number of `reset interrupt under service' operations, not - * the order. - */ -/* ARGSUSED */ int -zshard(intrarg) - void *intrarg; +zs_set_modes(cs, cflag) + struct zs_chanstate *cs; + int cflag; /* bits per second */ { - struct zs_chanstate *a; -#define b (a + 1) - volatile struct zschan *zc; - int rr3, intflags = 0, v, i, ringmask; - -#define ZSHARD_NEED_SOFTINTR 1 -#define ZSHARD_WAS_SERVICED 2 -#define ZSHARD_CHIP_GOTINTR 4 - - for (a = zslist; a != NULL; a = b->cs_next) { - ringmask = a->cs_ringmask; - rr3 = ZS_READ(a->cs_zc, 3); - if (rr3) - intflags |= ZSHARD_WAS_SERVICED; - if (rr3 & (ZSRR3_IP_A_RX|ZSRR3_IP_A_TX|ZSRR3_IP_A_STAT)) { - intflags |= (ZSHARD_CHIP_GOTINTR|ZSHARD_WAS_SERVICED); - zc = a->cs_zc; - i = a->cs_rbput; - if (rr3 & ZSRR3_IP_A_RX && (v = zsrint(a, zc)) != 0) { - a->cs_rbuf[i++ & ringmask] = v; - intflags |= ZSHARD_NEED_SOFTINTR; - } - if (rr3 & ZSRR3_IP_A_TX && (v = zsxint(a, zc)) != 0) { - a->cs_rbuf[i++ & ringmask] = v; - intflags |= ZSHARD_NEED_SOFTINTR; - } - if (rr3 & ZSRR3_IP_A_STAT && (v = zssint(a, zc)) != 0) { - a->cs_rbuf[i++ & ringmask] = v; - intflags |= ZSHARD_NEED_SOFTINTR; - } - a->cs_rbput = i; - } - if (rr3 & (ZSRR3_IP_B_RX|ZSRR3_IP_B_TX|ZSRR3_IP_B_STAT)) { - intflags |= (ZSHARD_CHIP_GOTINTR|ZSHARD_WAS_SERVICED); - zc = b->cs_zc; - i = b->cs_rbput; - if (rr3 & ZSRR3_IP_B_RX && (v = zsrint(b, zc)) != 0) { - b->cs_rbuf[i++ & ringmask] = v; - intflags |= ZSHARD_NEED_SOFTINTR; - } - if (rr3 & ZSRR3_IP_B_TX && (v = zsxint(b, zc)) != 0) { - b->cs_rbuf[i++ & ringmask] = v; - intflags |= ZSHARD_NEED_SOFTINTR; - } - if (rr3 & ZSRR3_IP_B_STAT && (v = zssint(b, zc)) != 0) { - b->cs_rbuf[i++ & ringmask] = v; - intflags |= ZSHARD_NEED_SOFTINTR; - } - b->cs_rbput = i; - } - if (intflags & ZSHARD_CHIP_GOTINTR) { - a->cs_sc->sc_intrcnt.ev_count++; - intflags &= ~ZSHARD_CHIP_GOTINTR; - } - } -#undef b - - if (intflags & ZSHARD_NEED_SOFTINTR) { -#if 0 /* - * seems to break things and will not work when spl* are - * converted to be only raising. - */ - if (CPU_ISSUN4COR4M) { - /* XXX -- but this will go away when zshard moves to locore.s */ - struct clockframe *p = intrarg; - - if ((p->psr & PSR_PIL) < (IPL_TTY << 8)) { - zsshortcuts++; - (void) spltty(); - if (zshardscope) { - LED_ON; - LED_OFF; - } - return (zssoft(intrarg)); - } - } -#endif + int s; -#if defined(SUN4M) - if (CPU_ISSUN4M) - raise(0, IPL_TTY); - else + /* + * Output hardware flow control on the chip is horrendous: + * if carrier detect drops, the receiver is disabled, and if + * CTS drops, the transmitter is stoped IN MID CHARACTER! + * Therefore, NEVER set the HFC bit, and instead use the + * status interrupt to detect CTS changes. + */ + s = splzs(); + cs->cs_rr0_pps = 0; + if ((cflag & (CLOCAL | MDMBUF)) != 0) { + cs->cs_rr0_dcd = 0; + if ((cflag & MDMBUF) == 0) + cs->cs_rr0_pps = ZSRR0_DCD; + } else + cs->cs_rr0_dcd = ZSRR0_DCD; + if ((cflag & CRTSCTS) != 0) { + cs->cs_wr5_dtr = ZSWR5_DTR; + cs->cs_wr5_rts = ZSWR5_RTS; + cs->cs_rr0_cts = ZSRR0_CTS; +#if 0 /* JLW */ + } else if ((cflag & CDTRCTS) != 0) { + cs->cs_wr5_dtr = 0; + cs->cs_wr5_rts = ZSWR5_DTR; + cs->cs_rr0_cts = ZSRR0_CTS; #endif - ienab_bis(IE_ZSSOFT); + } else if ((cflag & MDMBUF) != 0) { + cs->cs_wr5_dtr = 0; + cs->cs_wr5_rts = ZSWR5_DTR; + cs->cs_rr0_cts = ZSRR0_DCD; + } else { + cs->cs_wr5_dtr = ZSWR5_DTR | ZSWR5_RTS; + cs->cs_wr5_rts = 0; + cs->cs_rr0_cts = 0; } - return (intflags & ZSHARD_WAS_SERVICED) ? 1 : -1 /* XXX */; + splx(s); + + /* Caller will stuff the pending registers. */ + return (0); } -static int -zsrint(cs, zc) - register struct zs_chanstate *cs; - register volatile struct zschan *zc; -{ - register u_int c = zc->zc_data; - ZS_DELAY(); - if (cs->cs_conk) { - register struct conk_state *conk = &zsconk_state; +/* + * Read or write the chip with suitable delays. + */ - /* - * Check here for console abort function, so that we - * can abort even when interrupts are locking up the - * machine. - */ - if (c == KBD_RESET) { - conk->conk_id = 1; /* ignore next byte */ - conk->conk_l1 = 0; - } else if (conk->conk_id) - conk->conk_id = 0; /* stop ignoring bytes */ - else if (c == KBD_L1) - conk->conk_l1 = 1; /* L1 went down */ - else if (c == (KBD_L1|KBD_UP)) - conk->conk_l1 = 0; /* L1 went up */ - else if (c == KBD_A && conk->conk_l1) { - zsabort(cs->cs_unit); - conk->conk_l1 = 0; /* we never see the up */ - goto clearit; /* eat the A after L1-A */ - } - } -#ifdef KGDB - if (c == FRAME_START && cs->cs_kgdb && - (cs->cs_ttyp->t_state & TS_ISOPEN) == 0) { - zskgdb(cs->cs_unit); - goto clearit; - } -#endif - /* compose receive character and status */ - c <<= 8; - c |= ZS_READ(zc, 1); +u_char +zs_read_reg(cs, reg) + struct zs_chanstate *cs; + u_char reg; +{ + u_char val; - /* clear receive error & interrupt condition */ - zc->zc_csr = ZSWR0_RESET_ERRORS; + *cs->cs_reg_csr = reg; ZS_DELAY(); - zc->zc_csr = ZSWR0_CLR_INTR; + val = *cs->cs_reg_csr; ZS_DELAY(); + return val; +} - return (ZRING_MAKE(ZRING_RINT, c)); - -clearit: - zc->zc_csr = ZSWR0_RESET_ERRORS; +void +zs_write_reg(cs, reg, val) + struct zs_chanstate *cs; + u_char reg, val; +{ + *cs->cs_reg_csr = reg; ZS_DELAY(); - zc->zc_csr = ZSWR0_CLR_INTR; + *cs->cs_reg_csr = val; ZS_DELAY(); - return (0); } -static int -zsxint(cs, zc) - register struct zs_chanstate *cs; - register volatile struct zschan *zc; +u_char zs_read_csr(cs) + struct zs_chanstate *cs; { - register int i = cs->cs_tbc; + register u_char val; - if (cs->cs_deferred_cc != 0) { - /* Handle deferred zscnputc() output first */ - zc->zc_data = cs->cs_deferred_cc; - cs->cs_deferred_cc = 0; - ZS_DELAY(); - zc->zc_csr = ZSWR0_CLR_INTR; - ZS_DELAY(); - return (0); - } - if (i == 0) { - zc->zc_csr = ZSWR0_RESET_TXINT; - ZS_DELAY(); - zc->zc_csr = ZSWR0_CLR_INTR; - ZS_DELAY(); - return (ZRING_MAKE(ZRING_XINT, 0)); - } - cs->cs_tbc = i - 1; - zc->zc_data = *cs->cs_tba++; + val = *cs->cs_reg_csr; ZS_DELAY(); - zc->zc_csr = ZSWR0_CLR_INTR; + return val; +} + +void zs_write_csr(cs, val) + struct zs_chanstate *cs; + u_char val; +{ + *cs->cs_reg_csr = val; ZS_DELAY(); - return (0); } -static int -zssint(cs, zc) - register struct zs_chanstate *cs; - register volatile struct zschan *zc; +u_char zs_read_data(cs) + struct zs_chanstate *cs; { - register u_int rr0; + register u_char val; - rr0 = zc->zc_csr; + val = *cs->cs_reg_data; ZS_DELAY(); - zc->zc_csr = ZSWR0_RESET_STATUS; - ZS_DELAY(); - zc->zc_csr = ZSWR0_CLR_INTR; + return val; +} + +void zs_write_data(cs, val) + struct zs_chanstate *cs; + u_char val; +{ + *cs->cs_reg_data = val; ZS_DELAY(); - /* - * The chip's hardware flow control is, as noted in zsreg.h, - * busted---if the DCD line goes low the chip shuts off the - * receiver (!). If we want hardware CTS flow control but do - * not have it, and carrier is now on, turn HFC on; if we have - * HFC now but carrier has gone low, turn it off. - */ - if (rr0 & ZSRR0_DCD) { - if (cs->cs_ttyp->t_cflag & CCTS_OFLOW && - (cs->cs_creg[3] & ZSWR3_HFC) == 0) { - cs->cs_creg[3] |= ZSWR3_HFC; - ZS_WRITE(zc, 3, cs->cs_creg[3]); - } - } else { - if (cs->cs_creg[3] & ZSWR3_HFC) { - cs->cs_creg[3] &= ~ZSWR3_HFC; - ZS_WRITE(zc, 3, cs->cs_creg[3]); - } - } - if ((rr0 & ZSRR0_BREAK) && cs->cs_brkabort) { - /* - * XXX This might not be necessary. Test and - * delete if it isn't. - */ - if (CPU_ISSUN4) { - while (zc->zc_csr & ZSRR0_BREAK) - ZS_DELAY(); - } - zsabort(cs->cs_unit); - return (0); - } - return (ZRING_MAKE(ZRING_SINT, rr0)); } +/**************************************************************** + * Console support functions (Sun specific!) + * Note: this code is allowed to know about the layout of + * the chip registers, and uses that to keep things simple. + * XXX - I think I like the mvme167 code better. -gwr + ****************************************************************/ + +extern void Debugger(void); +void *zs_conschan; + +/* + * Handle user request to enter kernel debugger. + */ void -zsabort(unit) - int unit; +zs_abort(cs) + struct zs_chanstate *cs; { + volatile struct zschan *zc = zs_conschan; + int rr0; + + /* Wait for end of break to avoid PROM abort. */ + /* XXX - Limit the wait? */ + do { + rr0 = zc->zc_csr; + ZS_DELAY(); + } while (rr0 & ZSRR0_BREAK); #if defined(KGDB) - zskgdb(unit); + zskgdb(cs); #elif defined(DDB) - if (db_console) - Debugger(); + { + extern int db_active; + + if (!db_active) + Debugger(); + else + /* Debugger is probably hosed */ + callrom(); + } #else printf("stopping on keyboard abort\n"); callrom(); #endif } -#ifdef KGDB /* - * KGDB framing character received: enter kernel debugger. This probably - * should time out after a few seconds to avoid hanging on spurious input. + * Polled input char. */ -void -zskgdb(unit) - int unit; +int +zs_getc(arg) + void *arg; { + volatile struct zschan *zc = arg; + int s, c, rr0; - printf("zs%d%c: kgdb interrupt\n", unit >> 1, (unit & 1) + 'a'); - kgdb_connect(1); -} -#endif + s = splhigh(); + /* Wait for a character to arrive. */ + do { + rr0 = zc->zc_csr; + ZS_DELAY(); + } while ((rr0 & ZSRR0_RX_READY) == 0); -/* - * Print out a ring or fifo overrun error message. - */ -static void -zsoverrun(unit, ptime, what) - int unit; - long *ptime; - char *what; -{ + c = zc->zc_data; + ZS_DELAY(); + splx(s); - if (*ptime != time.tv_sec) { - *ptime = time.tv_sec; - log(LOG_WARNING, "zs%d%c: %s overrun\n", unit >> 1, - (unit & 1) + 'a', what); - } + /* + * This is used by the kd driver to read scan codes, + * so don't translate '\r' ==> '\n' here... + */ + return (c); } /* - * ZS software interrupt. Scan all channels for deferred interrupts. + * Polled output char. */ -int -zssoft(arg) +void +zs_putc(arg, c) void *arg; + int c; { - register struct zs_chanstate *cs; - register volatile struct zschan *zc; - register struct linesw *line; - register struct tty *tp; - register int get, n, c, cc, unit, s, ringmask, ringsize; - int retval = 0; - - for (cs = zslist; cs != NULL; cs = cs->cs_next) { - ringmask = cs->cs_ringmask; - get = cs->cs_rbget; -again: - n = cs->cs_rbput; /* atomic */ - if (get == n) /* nothing more on this line */ - continue; - retval = 1; - unit = cs->cs_unit; /* set up to handle interrupts */ - zc = cs->cs_zc; - tp = cs->cs_ttyp; - line = &linesw[tp->t_line]; - /* - * Compute the number of interrupts in the receive ring. - * If the count is overlarge, we lost some events, and - * must advance to the first valid one. It may get - * overwritten if more data are arriving, but this is - * too expensive to check and gains nothing (we already - * lost out; all we can do at this point is trade one - * kind of loss for another). - */ - ringsize = ringmask + 1; - n -= get; - if (n > ringsize) { - zsoverrun(unit, &cs->cs_rotime, "ring"); - get += n - ringsize; - n = ringsize; - } - while (--n >= 0) { - /* race to keep ahead of incoming interrupts */ - c = cs->cs_rbuf[get++ & ringmask]; - switch (ZRING_TYPE(c)) { - - case ZRING_RINT: - c = ZRING_VALUE(c); - if (c & ZSRR1_DO) - zsoverrun(unit, &cs->cs_fotime, "fifo"); - cc = c >> 8; - if (c & ZSRR1_FE) - cc |= TTY_FE; - if (c & ZSRR1_PE) - cc |= TTY_PE; - /* - * this should be done through - * bstreams XXX gag choke - */ - if (unit == ZS_KBD) -#if NKBD > 0 - kbd_rint(cc); -#else - ; -#endif - else if (unit == ZS_MOUSE) - ms_rint(cc); - else - line->l_rint(cc, tp); - break; - - case ZRING_XINT: - /* - * Transmit done: change registers and resume, - * or clear BUSY. - */ - if (cs->cs_heldchange) { - s = splzs(); - c = zc->zc_csr; - ZS_DELAY(); - if ((c & ZSRR0_DCD) == 0) - cs->cs_preg[3] &= ~ZSWR3_HFC; - bcopy((caddr_t)cs->cs_preg, - (caddr_t)cs->cs_creg, 16); - zs_loadchannelregs(zc, cs->cs_creg); - splx(s); - cs->cs_heldchange = 0; - if (cs->cs_heldtbc && - (tp->t_state & TS_TTSTOP) == 0) { - cs->cs_tbc = cs->cs_heldtbc - 1; - zc->zc_data = *cs->cs_tba++; - ZS_DELAY(); - goto again; - } - } - tp->t_state &= ~TS_BUSY; - if (tp->t_state & TS_FLUSH) - tp->t_state &= ~TS_FLUSH; - else - ndflush(&tp->t_outq, - cs->cs_tba - (caddr_t)tp->t_outq.c_cf); - line->l_start(tp); - break; - - case ZRING_SINT: - /* - * Status line change. HFC bit is run in - * hardware interrupt, to avoid locking - * at splzs here. - */ - c = ZRING_VALUE(c); - if ((c ^ cs->cs_rr0) & ZSRR0_DCD) { - cc = (c & ZSRR0_DCD) != 0; - if (line->l_modem(tp, cc) == 0) - zs_modem(cs, cc); - } - cs->cs_rr0 = c; - break; - - default: - log(LOG_ERR, "zs%d%c: bad ZRING_TYPE (0x%x)\n", - unit >> 1, (unit & 1) + 'a', c); - break; - } - } - cs->cs_rbget = get; - goto again; - } - return (retval); -} - -int -zsioctl(dev, cmd, data, flag, p) - dev_t dev; - u_long cmd; - caddr_t data; - int flag; - struct proc *p; -{ - int unit = DEVUNIT(dev); - struct zs_softc *sc = zs_cd.cd_devs[unit >> 1]; - register struct zs_chanstate *cs = &sc->sc_cs[unit & 1]; - register struct tty *tp = cs->cs_ttyp; - register int error, s; - - 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: - s = splzs(); - cs->cs_preg[5] |= ZSWR5_BREAK; - cs->cs_creg[5] |= ZSWR5_BREAK; - ZS_WRITE(cs->cs_zc, 5, cs->cs_creg[5]); - splx(s); - break; - case TIOCCBRK: - s = splzs(); - cs->cs_preg[5] &= ~ZSWR5_BREAK; - cs->cs_creg[5] &= ~ZSWR5_BREAK; - ZS_WRITE(cs->cs_zc, 5, cs->cs_creg[5]); - splx(s); - break; - case TIOCGFLAGS: { - int bits = 0; - - if (cs->cs_softcar) - bits |= TIOCFLAG_SOFTCAR; - if (cs->cs_creg[15] & ZSWR15_DCD_IE) - bits |= TIOCFLAG_CLOCAL; - if (cs->cs_creg[3] & ZSWR3_HFC) - bits |= TIOCFLAG_CRTSCTS; - *(int *)data = bits; - break; - } - case TIOCSFLAGS: { - int userbits; + volatile struct zschan *zc = arg; + int s, rr0; - error = suser(p->p_ucred, &p->p_acflag); - if (error != 0) - return (EPERM); + s = splhigh(); + /* Wait for transmitter to become ready. */ + do { + rr0 = zc->zc_csr; + ZS_DELAY(); + } while ((rr0 & ZSRR0_TX_READY) == 0); - userbits = *(int *)data; + /* + * Send the next character. + * Now you'd think that this could be followed by a ZS_DELAY() + * just like all the other chip accesses, but it turns out that + * the `transmit-ready' interrupt isn't de-asserted until + * some period of time after the register write completes + * (more than a couple instructions). So to avoid stray + * interrupts we put in the 2us delay regardless of cpu model. + */ + zc->zc_data = c; + delay(2); - /* - * can have `local' or `softcar', and `rtscts' or `mdmbuf' - # defaulting to software flow control. - */ - if (userbits & TIOCFLAG_SOFTCAR && userbits & TIOCFLAG_CLOCAL) - return(EINVAL); - if (userbits & TIOCFLAG_MDMBUF) /* don't support this (yet?) */ - return(ENXIO); - - s = splzs(); - if ((userbits & TIOCFLAG_SOFTCAR) || cs->cs_consio) { - cs->cs_softcar = 1; /* turn on softcar */ - cs->cs_preg[15] &= ~ZSWR15_DCD_IE; /* turn off dcd */ - cs->cs_creg[15] &= ~ZSWR15_DCD_IE; - ZS_WRITE(cs->cs_zc, 15, cs->cs_creg[15]); - } else if (userbits & TIOCFLAG_CLOCAL) { - cs->cs_softcar = 0; /* turn off softcar */ - cs->cs_preg[15] |= ZSWR15_DCD_IE; /* turn on dcd */ - cs->cs_creg[15] |= ZSWR15_DCD_IE; - ZS_WRITE(cs->cs_zc, 15, cs->cs_creg[15]); - tp->t_termios.c_cflag |= CLOCAL; - } - if (userbits & TIOCFLAG_CRTSCTS) { - cs->cs_preg[15] |= ZSWR15_CTS_IE; - cs->cs_creg[15] |= ZSWR15_CTS_IE; - ZS_WRITE(cs->cs_zc, 15, cs->cs_creg[15]); - cs->cs_preg[3] |= ZSWR3_HFC; - cs->cs_creg[3] |= ZSWR3_HFC; - ZS_WRITE(cs->cs_zc, 3, cs->cs_creg[3]); - tp->t_termios.c_cflag |= CRTSCTS; - } else { - /* no mdmbuf, so we must want software flow control */ - cs->cs_preg[15] &= ~ZSWR15_CTS_IE; - cs->cs_creg[15] &= ~ZSWR15_CTS_IE; - ZS_WRITE(cs->cs_zc, 15, cs->cs_creg[15]); - cs->cs_preg[3] &= ~ZSWR3_HFC; - cs->cs_creg[3] &= ~ZSWR3_HFC; - ZS_WRITE(cs->cs_zc, 3, cs->cs_creg[3]); - tp->t_termios.c_cflag &= ~CRTSCTS; - } - splx(s); - break; - } - case TIOCSDTR: - zs_modem(cs, 1); - break; - case TIOCCDTR: - zs_modem(cs, 0); - break; - case TIOCMSET: - tiocm_to_zs(cs, TIOCMSET, *(int *)data); - break; - case TIOCMBIS: - tiocm_to_zs(cs, TIOCMBIS, *(int *)data); - break; - case TIOCMBIC: - tiocm_to_zs(cs, TIOCMBIC, *(int *)data); - break; - case TIOCMGET: { - int bits = 0; - u_char m; - - m = cs->cs_preg[5]; - if (ISSET(m, ZSWR5_DTR)) - SET(bits, TIOCM_DTR); - if (ISSET(m, ZSWR5_RTS)) - SET(bits, TIOCM_RTS); - - m = cs->cs_zc->zc_csr; - if (m & ZSRR0_DCD) - SET(bits, TIOCM_CD); - if (m & ZSRR0_CTS) - SET(bits, TIOCM_CTS); - *(int *)data = bits; - break; - } - default: - return (ENOTTY); - } - return (0); + splx(s); } +/*****************************************************************/ + +cons_decl(zs); + /* - * Start or restart transmission. + * Console table shared by ttya, ttyb */ -static void -zsstart(tp) - register struct tty *tp; -{ - register struct zs_chanstate *cs; - register int s, ss, nch; - int unit = DEVUNIT(tp->t_dev); - struct zs_softc *sc = zs_cd.cd_devs[unit >> 1]; - - cs = &sc->sc_cs[unit & 1]; - s = spltty(); +struct consdev consdev_tty = { + zscnprobe, + zscninit, + zscngetc, + zscnputc, + zscnpollc, +}; - /* - * If currently active or delaying, no need to do anything. - */ - if (tp->t_state & (TS_TIMEOUT | TS_BUSY | TS_TTSTOP)) - goto out; +int zstty_unit; /* set in consinit() */ - /* - * If there are sleepers, and output has drained below low - * water mark, awaken. - */ - 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); - } +void +zscnprobe(cn) + struct consdev *cn; +{ + cn->cn_dev = makedev(zs_major, zstty_unit); + cn->cn_pri = CN_REMOTE; +} - nch = ndqb(&tp->t_outq, 0); /* XXX */ - ss = splzs(); - if (nch) { - register char *p = tp->t_outq.c_cf; - - /* mark busy, enable tx done interrupts, & send first byte */ - tp->t_state |= TS_BUSY; - cs->cs_preg[1] |= ZSWR1_TIE; - cs->cs_creg[1] |= ZSWR1_TIE; - ZS_WRITE(cs->cs_zc, 1, cs->cs_creg[1]); - cs->cs_zc->zc_data = *p; - ZS_DELAY(); - cs->cs_tba = p + 1; - cs->cs_tbc = nch - 1; - } else { - /* - * Nothing to send, turn off transmit done interrupts. - * This is useful if something is doing polled output. - */ - cs->cs_preg[1] &= ~ZSWR1_TIE; - cs->cs_creg[1] &= ~ZSWR1_TIE; - ZS_WRITE(cs->cs_zc, 1, cs->cs_creg[1]); - } - splx(ss); -out: - splx(s); +void +zscninit(cn) + struct consdev *cn; +{ } /* - * Stop output, e.g., for ^S or output flush. + * Polled console input putchar. */ int -zsstop(tp, flag) - register struct tty *tp; - int flag; +zscngetc(dev) + dev_t dev; { - register struct zs_chanstate *cs; - register int s, unit = DEVUNIT(tp->t_dev); - struct zs_softc *sc = zs_cd.cd_devs[unit >> 1]; - - cs = &sc->sc_cs[unit & 1]; - s = splzs(); - if (tp->t_state & TS_BUSY) { - /* - * Device is transmitting; must stop it. - */ - cs->cs_tbc = 0; - if ((tp->t_state & TS_TTSTOP) == 0) - tp->t_state |= TS_FLUSH; - } - splx(s); - return 0; + return (zs_getc(zs_conschan)); } /* - * Set ZS tty parameters from termios. - * - * This routine makes use of the fact that only registers - * 1, 3, 4, 5, 9, 10, 11, 12, 13, 14, and 15 are written. + * Polled console output putchar. */ -static int -zsparam(tp, t) - register struct tty *tp; - register struct termios *t; +void +zscnputc(dev, c) + dev_t dev; + int c; { - int unit = DEVUNIT(tp->t_dev); - struct zs_softc *sc = zs_cd.cd_devs[unit >> 1]; - register struct zs_chanstate *cs = &sc->sc_cs[unit & 1]; - register int tmp, tmp5, cflag, s; - - /* - * Because PCLK is only run at 4.9 MHz, the fastest we - * can go is 51200 baud (this corresponds to TC=1). - * This is somewhat unfortunate as there is no real - * reason we should not be able to handle higher rates. - */ - tmp = t->c_ospeed; - if (tmp < 0 || (t->c_ispeed && t->c_ispeed != tmp)) - return (EINVAL); - if (tmp == 0) { - /* stty 0 => drop DTR and RTS */ - zs_modem(cs, 0); - return (0); - } - tmp = BPS_TO_TCONST(PCLK / 16, tmp); -#ifdef ALLOW_TC_EQUAL_ZERO - if (tmp < 0) -#else - if (tmp < 1) -#endif - return (EINVAL); + zs_putc(zs_conschan, c); +} - cflag = t->c_cflag; - tp->t_ispeed = tp->t_ospeed = TCONST_TO_BPS(PCLK / 16, tmp); - tp->t_cflag = cflag; - - /* - * Block interrupts so that state will not - * be altered until we are done setting it up. - */ - s = splzs(); - cs->cs_preg[12] = tmp; - cs->cs_preg[13] = tmp >> 8; - cs->cs_preg[1] = ZSWR1_RIE | ZSWR1_TIE | ZSWR1_SIE; - switch (cflag & CSIZE) { - case CS5: - tmp = ZSWR3_RX_5; - tmp5 = ZSWR5_TX_5; - break; - case CS6: - tmp = ZSWR3_RX_6; - tmp5 = ZSWR5_TX_6; - break; - case CS7: - tmp = ZSWR3_RX_7; - tmp5 = ZSWR5_TX_7; - break; - case CS8: - default: - tmp = ZSWR3_RX_8; - tmp5 = ZSWR5_TX_8; - break; - } +int swallow_zsintrs; +void +zscnpollc(dev, on) + dev_t dev; + int on; +{ /* - * Output hardware flow control on the chip is horrendous: if - * carrier detect drops, the receiver is disabled. Hence we - * can only do this when the carrier is on. + * Need to tell zs driver to acknowledge all interrupts or we get + * annoying spurious interrupt messages. This is because mucking + * with spl() levels during polling does not prevent interrupts from + * being generated. */ - tmp |= ZSWR3_RX_ENABLE; - if (cflag & CCTS_OFLOW) { - if (cs->cs_zc->zc_csr & ZSRR0_DCD) - tmp |= ZSWR3_HFC; - ZS_DELAY(); - } - cs->cs_preg[3] = tmp; - cs->cs_preg[5] = tmp5 | ZSWR5_TX_ENABLE | ZSWR5_DTR | ZSWR5_RTS; - - tmp = ZSWR4_CLK_X16 | (cflag & CSTOPB ? ZSWR4_TWOSB : ZSWR4_ONESB); - if ((cflag & PARODD) == 0) - tmp |= ZSWR4_EVENP; - if (cflag & PARENB) - tmp |= ZSWR4_PARENB; - cs->cs_preg[4] = tmp; - cs->cs_preg[9] = ZSWR9_MASTER_IE | ZSWR9_NO_VECTOR; - cs->cs_preg[10] = ZSWR10_NRZ; - cs->cs_preg[11] = ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD; - cs->cs_preg[14] = ZSWR14_BAUD_FROM_PCLK | ZSWR14_BAUD_ENA; - cs->cs_preg[15] = ZSWR15_BREAK_IE | ZSWR15_DCD_IE; - /* - * If nothing is being transmitted, set up new current values, - * else mark them as pending. - */ - if (cs->cs_heldchange == 0) { - if (cs->cs_ttyp->t_state & TS_BUSY) { - cs->cs_heldtbc = cs->cs_tbc; - cs->cs_tbc = 0; - cs->cs_heldchange = 1; - } else { - bcopy((caddr_t)cs->cs_preg, (caddr_t)cs->cs_creg, 16); - zs_loadchannelregs(cs->cs_zc, cs->cs_creg); - } - } - splx(s); - return (0); + if (on) swallow_zsintrs++; + else swallow_zsintrs--; } +/*****************************************************************/ + +cons_decl(prom); + /* - * Raise or lower modem control (DTR/RTS) signals. If a character is - * in transmission, the change is deferred. + * The console is set to this one initially, + * which lets us use the PROM until consinit() + * is called to select a real console. */ -static void -zs_modem(cs, onoff) - struct zs_chanstate *cs; - int onoff; -{ - int s, bis, and; - - if (onoff) { - bis = ZSWR5_DTR | ZSWR5_RTS; - and = ~0; - } else { - bis = 0; - and = ~(ZSWR5_DTR | ZSWR5_RTS); - } - s = splzs(); - cs->cs_preg[5] = (cs->cs_preg[5] | bis) & and; - if (cs->cs_heldchange == 0) { - if (cs->cs_ttyp->t_state & TS_BUSY) { - cs->cs_heldtbc = cs->cs_tbc; - cs->cs_tbc = 0; - cs->cs_heldchange = 1; - } else { - cs->cs_creg[5] = (cs->cs_creg[5] | bis) & and; - ZS_WRITE(cs->cs_zc, 5, cs->cs_creg[5]); - } - } - splx(s); -} +struct consdev consdev_prom = { + promcnprobe, + promcninit, + promcngetc, + promcnputc, + nullcnpollc, +}; /* - * Write the given register set to the given zs channel in the proper order. - * The channel must not be transmitting at the time. The receiver will - * be disabled for the time it takes to write all the registers. + * The console table pointer is statically initialized + * to point to the PROM (output only) table, so that + * early calls to printf will work. */ -static void -zs_loadchannelregs(zc, reg) - volatile struct zschan *zc; - u_char *reg; +struct consdev *cn_tab = &consdev_prom; + +void +promcnprobe(cn) + struct consdev *cn; { - int i; + cn->cn_dev = makedev(0, 0); + cn->cn_pri = CN_INTERNAL; +} - zc->zc_csr = ZSM_RESET_ERR; /* reset error condition */ - ZS_DELAY(); - i = zc->zc_data; /* drain fifo */ - ZS_DELAY(); - i = zc->zc_data; - ZS_DELAY(); - i = zc->zc_data; - ZS_DELAY(); - ZS_WRITE(zc, 4, reg[4]); - ZS_WRITE(zc, 10, reg[10]); - ZS_WRITE(zc, 3, reg[3] & ~ZSWR3_RX_ENABLE); - ZS_WRITE(zc, 5, reg[5] & ~ZSWR5_TX_ENABLE); - ZS_WRITE(zc, 1, reg[1]); - ZS_WRITE(zc, 9, reg[9]); - ZS_WRITE(zc, 11, reg[11]); - ZS_WRITE(zc, 12, reg[12]); - ZS_WRITE(zc, 13, reg[13]); - ZS_WRITE(zc, 14, reg[14]); - ZS_WRITE(zc, 15, reg[15]); - ZS_WRITE(zc, 3, reg[3]); - ZS_WRITE(zc, 5, reg[5]); +void +promcninit(cn) + struct consdev *cn; +{ } -static void -tiocm_to_zs(cs, how, val) - struct zs_chanstate *cs; - int how, val; +/* + * PROM console input putchar. + */ +int +promcngetc(dev) + dev_t dev; { - int s; - u_char bits = 0; + int s, c; - if (ISSET(val,TIOCM_DTR)) - SET(bits, ZSWR5_DTR); - if (ISSET(val,TIOCM_RTS)) - SET(bits, ZSWR5_RTS); + if (promvec->pv_romvec_vers > 2) { + int n = 0; + unsigned char c0; - s = splzs(); - switch (how) { - case TIOCMBIC: - CLR(cs->cs_preg[5], bits); - break; - - case TIOCMBIS: - SET(cs->cs_preg[5], bits); - break; - - case TIOCMSET: - CLR(cs->cs_preg[5], ZSWR5_RTS | ZSWR5_DTR); - SET(cs->cs_preg[5], bits); - break; - } + s = splhigh(); + while (n <= 0) { + n = (*promvec->pv_v2devops.v2_read) + (*promvec->pv_v2bootargs.v2_fd0, &c0, 1); + } + splx(s); - if (cs->cs_heldchange == 0) { - if (cs->cs_ttyp->t_state & TS_BUSY) { - cs->cs_heldtbc = cs->cs_tbc; - cs->cs_tbc = 0; - cs->cs_heldchange = 1; - } else { - cs->cs_creg[5] = cs->cs_preg[5]; - ZS_WRITE(cs->cs_zc, 5, cs->cs_creg[5]); + c = c0; + } else { +#if defined(SUN4) + /* SUN4 PROM: must turn off local echo */ + extern struct om_vector *oldpvec; + int saveecho = 0; +#endif + s = splhigh(); +#if defined(SUN4) + if (CPU_ISSUN4) { + saveecho = *(oldpvec->echo); + *(oldpvec->echo) = 0; } +#endif + c = (*promvec->pv_getchar)(); +#if defined(SUN4) + if (CPU_ISSUN4) + *(oldpvec->echo) = saveecho; +#endif + splx(s); } - splx(s); - -} -#ifdef KGDB -/* - * Get a character from the given kgdb channel. Called at splhigh(). - */ -static int -zs_kgdb_getc(arg) - void *arg; -{ - register volatile struct zschan *zc = (volatile struct zschan *)arg; - u_char c; + if (c == '\r') + c = '\n'; - while ((zc->zc_csr & ZSRR0_RX_READY) == 0) - ZS_DELAY(); - c = zc->zc_data; - ZS_DELAY(); - return c; + return (c); } /* - * Put a character to the given kgdb channel. Called at splhigh(). + * PROM console output putchar. */ -static void -zs_kgdb_putc(arg, c) - void *arg; +void +promcnputc(dev, c) + dev_t dev; int c; { - register volatile struct zschan *zc = (volatile struct zschan *)arg; - - while ((zc->zc_csr & ZSRR0_TX_READY) == 0) - ZS_DELAY(); - zc->zc_data = c; - ZS_DELAY(); + int s; + char c0 = (c & 0x7f); + + s = splhigh(); + if (promvec->pv_romvec_vers > 2) + (*promvec->pv_v2devops.v2_write) + (*promvec->pv_v2bootargs.v2_fd1, &c0, 1); + else + (*promvec->pv_putchar)(c); + splx(s); } +/*****************************************************************/ + +#if 0 +extern struct consdev consdev_kd; +#endif + +char *prom_inSrc_name[] = { + "keyboard/display", + "ttya", "ttyb", + "ttyc", "ttyd" }; + /* - * Set up for kgdb; called at boot time before configuration. - * KGDB interrupts will be enabled later when zs0 is configured. + * This function replaces sys/dev/cninit.c + * Determine which device is the console using + * the PROM "input source" and "output sink". */ void -zs_kgdb_init() +consinit() { - volatile struct zsdevice *addr; - volatile struct zschan *zc; - int unit, zs; + struct zschan *zc; + struct consdev *console = cn_tab; + int channel, zs_unit; + int inSource, outSink; + + if (promvec->pv_romvec_vers > 2) { + /* We need to probe the PROM device tree */ + int node,fd; + char buffer[128]; + struct nodeops *no; + struct v2devops *op; + char *cp; + extern int fbnode; + + inSource = outSink = -1; + no = promvec->pv_nodeops; + op = &promvec->pv_v2devops; + + node = findroot(); + if (no->no_proplen(node, "stdin-path") >= sizeof(buffer)) { + printf("consinit: increase buffer size and recompile\n"); + goto setup_output; + } + /* XXX: fix above */ - if (major(kgdb_dev) != ZSMAJOR) - return; - unit = DEVUNIT(kgdb_dev); - /* - * Unit must be 0 or 1 (zs0). - */ - if ((unsigned)unit >= ZS_KBD) { - printf("zs_kgdb_init: bad minor dev %d\n", unit); + no->no_getprop(node, "stdin-path",buffer); + + /* + * Open an "instance" of this device. + * You'd think it would be appropriate to call v2_close() + * on the handle when we're done with it. But that seems + * to cause the device to shut down somehow; for the moment, + * we simply leave it open... + */ + if ((fd = op->v2_open(buffer)) == 0 || + (node = op->v2_fd_phandle(fd)) == 0) { + printf("consinit: bogus stdin path %s.\n",buffer); + goto setup_output; + } + if (no->no_proplen(node,"keyboard") >= 0) { + inSource = PROMDEV_KBD; + goto setup_output; + } + if (strcmp(getpropstring(node,"device_type"),"serial") != 0) { + /* not a serial, not keyboard. what is it?!? */ + inSource = -1; + goto setup_output; + } + /* + * At this point we assume the device path is in the form + * ....device@x,y:a for ttya and ...device@x,y:b for ttyb. + * If it isn't, we defer to the ROM + */ + cp = buffer; + while (*cp) + cp++; + cp -= 2; +#ifdef DEBUG + if (cp < buffer) + panic("consinit: bad stdin path %s",buffer); +#endif + /* XXX: only allows tty's a->z, assumes PROMDEV_TTYx contig */ + if (cp[0]==':' && cp[1] >= 'a' && cp[1] <= 'z') + inSource = PROMDEV_TTYA + (cp[1] - 'a'); + /* else use rom */ +setup_output: + node = findroot(); + if (no->no_proplen(node, "stdout-path") >= sizeof(buffer)) { + printf("consinit: increase buffer size and recompile\n"); + goto setup_console; + } + /* XXX: fix above */ + + no->no_getprop(node, "stdout-path", buffer); + + if ((fd = op->v2_open(buffer)) == 0 || + (node = op->v2_fd_phandle(fd)) == 0) { + printf("consinit: bogus stdout path %s.\n",buffer); + goto setup_output; + } + if (strcmp(getpropstring(node,"device_type"),"display") == 0) { + /* frame buffer output */ + outSink = PROMDEV_SCREEN; + fbnode = node; + } else if (strcmp(getpropstring(node,"device_type"), "serial") + != 0) { + /* not screen, not serial. Whatzit? */ + outSink = -1; + } else { /* serial console. which? */ + /* + * At this point we assume the device path is in the + * form: + * ....device@x,y:a for ttya, etc. + * If it isn't, we defer to the ROM + */ + cp = buffer; + while (*cp) + cp++; + cp -= 2; +#ifdef DEBUG + if (cp < buffer) + panic("consinit: bad stdout path %s",buffer); +#endif + /* XXX: only allows tty's a->z, assumes PROMDEV_TTYx contig */ + if (cp[0]==':' && cp[1] >= 'a' && cp[1] <= 'z') + outSink = PROMDEV_TTYA + (cp[1] - 'a'); + else outSink = -1; + } + } else { + inSource = *promvec->pv_stdin; + outSink = *promvec->pv_stdout; + } + +setup_console: + + if (inSource != outSink) { + printf("cninit: mismatched PROM output selector\n"); + } + + switch (inSource) { + default: + printf("cninit: invalid inSource=%d\n", inSource); + callrom(); + inSource = PROMDEV_KBD; + /* FALLTHROUGH */ + + case 0: /* keyboard/display */ +#if NZSKBD > 0 + zs_unit = 1; + channel = 0; + break; +#else /* NZSKBD */ + printf("cninit: kdb/display not configured\n"); + callrom(); + inSource = PROMDEV_TTYA; + /* FALLTHROUGH */ +#endif /* NZSKBD */ + + case PROMDEV_TTYA: + case PROMDEV_TTYB: + zstty_unit = inSource - PROMDEV_TTYA; + zs_unit = 0; + channel = zstty_unit & 1; + console = &consdev_tty; + break; + + } + /* Now that inSource has been validated, print it. */ + printf("console is %s\n", prom_inSrc_name[inSource]); + + zc = zs_get_chan_addr(zs_unit, channel); + if (zc == NULL) { + printf("cninit: zs not mapped.\n"); return; } - zs = unit >> 1; - if ((addr = zsaddr[zs]) == NULL) - addr = zsaddr[zs] = (volatile struct zsdevice *)findzs(zs); - unit &= 1; - zc = unit == 0 ? &addr->zs_chan[ZS_CHAN_A] : &addr->zs_chan[ZS_CHAN_B]; - zs_kgdb_savedspeed = zs_getspeed(zc); - printf("zs_kgdb_init: attaching zs%d%c at %d baud\n", - zs, unit + 'a', kgdb_rate); - zs_reset(zc, 1, kgdb_rate); - kgdb_attach(zs_kgdb_getc, zs_kgdb_putc, (void *)zc); + zs_conschan = zc; + zs_hwflags[zs_unit][channel] = ZS_HWFLAG_CONSOLE; + /* switch to selected console */ + cn_tab = console; + (*cn_tab->cn_probe)(cn_tab); + (*cn_tab->cn_init)(cn_tab); +#ifdef KGDB + zs_kgdb_init(); +#endif } -#endif /* KGDB */ diff --git a/sys/arch/sparc/dev/zs_kgdb.c b/sys/arch/sparc/dev/zs_kgdb.c new file mode 100644 index 00000000000..337a2dea174 --- /dev/null +++ b/sys/arch/sparc/dev/zs_kgdb.c @@ -0,0 +1,292 @@ +/* $OpenBSD: zs_kgdb.c,v 1.1 2002/08/12 10:44:04 miod Exp $ */ +/* $NetBSD: zs_kgdb.c,v 1.1 1997/10/18 00:00:51 gwr Exp $ */ + +/*- + * Copyright (c) 1996 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by 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 FOUNDATION 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. + */ + +/* + * Hooks for kgdb when attached via the z8530 driver + * + * To use this, build a kernel with: option KGDB, and + * boot that kernel with "-d". (The kernel will call + * zs_kgdb_init, kgdb_connect.) When the console prints + * "kgdb waiting..." you run "gdb -k kernel" and do: + * (gdb) set remotebaud 19200 + * (gdb) target remote /dev/ttyb + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/proc.h> +#include <sys/device.h> +#include <sys/conf.h> +#include <sys/ioctl.h> +#include <sys/kernel.h> +#include <sys/syslog.h> +#include <sys/kgdb.h> + +#include <sparc/dev/z8530reg.h> +#include <machine/z8530var.h> +#include <sparc/dev/cons.h> + +/* The Sun3 provides a 4.9152 MHz clock to the ZS chips. */ +#define PCLK (9600 * 512) /* PCLK pin input clock rate */ +#define ZSHARD_PRI 6 /* Wired on the CPU board... */ + +#define ZS_DELAY() (CPU_ISSUN4C ? (0) : delay(2)) + +/* The layout of this is hardware-dependent (padding, order). */ +struct zschan { + volatile u_char zc_csr; /* ctrl,status, and indirect access */ + u_char zc_xxx0; + volatile u_char zc_data; /* data */ + u_char zc_xxx1; +}; + +void zs_setparam(struct zs_chanstate *, int, int); +struct zsops zsops_kgdb; + +u_char zs_kgdb_regs[16] = { + 0, /* 0: CMD (reset, etc.) */ + 0, /* 1: ~(ZSWR1_RIE | ZSWR1_TIE | ZSWR1_SIE) */ + 0, /* 2: IVECT */ + ZSWR3_RX_8 | ZSWR3_RX_ENABLE, + ZSWR4_CLK_X16 | ZSWR4_ONESB | ZSWR4_EVENP, + ZSWR5_TX_8 | ZSWR5_TX_ENABLE, + 0, /* 6: TXSYNC/SYNCLO */ + 0, /* 7: RXSYNC/SYNCHI */ + 0, /* 8: alias for data port */ + ZSWR9_MASTER_IE | ZSWR9_NO_VECTOR, + 0, /*10: Misc. TX/RX control bits */ + ZSWR11_TXCLK_BAUD | ZSWR11_RXCLK_BAUD, + 14, /*12: BAUDLO (default=9600) */ + 0, /*13: BAUDHI (default=9600) */ + ZSWR14_BAUD_ENA | ZSWR14_BAUD_FROM_PCLK, + ZSWR15_BREAK_IE | ZSWR15_DCD_IE, +}; + +/* + * This replaces "zs_reset()" in the sparc driver. + */ +void +zs_setparam(cs, iena, rate) + struct zs_chanstate *cs; + int iena; + int rate; +{ + int s, tconst; + + bcopy(zs_kgdb_regs, cs->cs_preg, 16); + + if (iena) { + cs->cs_preg[1] = ZSWR1_RIE | ZSWR1_SIE; + } + + /* Initialize the speed, etc. */ + tconst = BPS_TO_TCONST(cs->cs_brg_clk, rate); + cs->cs_preg[5] |= ZSWR5_DTR | ZSWR5_RTS; + cs->cs_preg[12] = tconst; + cs->cs_preg[13] = tconst >> 8; + + s = splhigh(); + zs_loadchannelregs(cs); + splx(s); +} + +/* + * Set up for kgdb; called at boot time before configuration. + * KGDB interrupts will be enabled later when zs0 is configured. + * Called after cninit(), so printf() etc. works. + */ +void +zs_kgdb_init() +{ + struct zs_chanstate cs; + volatile struct zschan *zc; + int channel, zsc_unit; + + /* printf("zs_kgdb_init: kgdb_dev=0x%x\n", kgdb_dev); */ + if (major(kgdb_dev) != zs_major) + return; + + /* Note: (ttya,ttyb) on zsc1, and (ttyc,ttyd) on zsc0 */ + zsc_unit = (kgdb_dev & 2) ? 0 : 1; + channel = kgdb_dev & 1; + printf("zs_kgdb_init: attaching tty%c at %d baud\n", + 'a' + (kgdb_dev & 3), kgdb_rate); + + /* Setup temporary chanstate. */ + bzero((caddr_t)&cs, sizeof(cs)); + zc = zs_get_chan_addr(zsc_unit, channel); + if (zc == NULL) { + printf("zs_kgdb_init: zs not mapped.\n"); + kgdb_dev = -1; + return; + } + + cs.cs_channel = channel; + cs.cs_brg_clk = PCLK / 16; + cs.cs_reg_csr = &zc->zc_csr; + cs.cs_reg_data = &zc->zc_data; + + /* Now set parameters. (interrupts disabled) */ + zs_setparam(&cs, 0, kgdb_rate); + + /* Store the getc/putc functions and arg. */ + kgdb_attach(zs_getc, zs_putc, (void *)zc); +} + +/* + * This is a "hook" called by zstty_attach to allow the tty + * to be "taken over" for exclusive use by kgdb. + * Return non-zero if this is the kgdb port. + * + * Set the speed to kgdb_rate, CS8, etc. + */ +int +zs_check_kgdb(cs, dev) + struct zs_chanstate *cs; + int dev; +{ + + if (dev != kgdb_dev) + return (0); + + /* + * Yes, this is port in use by kgdb. + */ + cs->cs_private = NULL; + cs->cs_ops = &zsops_kgdb; + + /* Now set parameters. (interrupts enabled) */ + zs_setparam(cs, 1, kgdb_rate); + + return (1); +} + +/* + * KGDB framing character received: enter kernel debugger. This probably + * should time out after a few seconds to avoid hanging on spurious input. + */ +void +zskgdb(cs) + struct zs_chanstate *cs; +{ + int unit = minor(kgdb_dev); + + printf("zstty%d: kgdb interrupt\n", unit); + /* This will trap into the debugger. */ + kgdb_connect(1); +} + + +/**************************************************************** + * Interface to the lower layer (zscc) + ****************************************************************/ + +void zs_kgdb_rxint(struct zs_chanstate *); +void zs_kgdb_txint(struct zs_chanstate *); +void zs_kgdb_stint(struct zs_chanstate *); +void zs_kgdb_softint(struct zs_chanstate *); + +int kgdb_input_lost; + +void +zs_kgdb_rxint(cs) + struct zs_chanstate *cs; +{ + register u_char c, rr1; + + /* + * First read the status, because reading the received char + * destroys the status of this char. + */ + rr1 = zs_read_reg(cs, 1); + c = zs_read_data(cs); + + if (rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) { + /* Clear the receive error. */ + zs_write_csr(cs, ZSWR0_RESET_ERRORS); + } + + if (c == KGDB_START) { + zskgdb(cs); + } else { + kgdb_input_lost++; + } +} + +void +zs_kgdb_txint(cs) + register struct zs_chanstate *cs; +{ + register int rr0; + + rr0 = zs_read_csr(cs); + zs_write_csr(cs, ZSWR0_RESET_TXINT); +} + +void +zs_kgdb_stint(cs) + register struct zs_chanstate *cs; +{ + register int rr0; + + rr0 = zs_read_csr(cs); + zs_write_csr(cs, ZSWR0_RESET_STATUS); + + /* + * Check here for console break, so that we can abort + * even when interrupts are locking up the machine. + */ + if (rr0 & ZSRR0_BREAK) { + zskgdb(cs); + } +} + +void +zs_kgdb_softint(cs) + struct zs_chanstate *cs; +{ + printf("zs_kgdb_softint?\n"); +} + +struct zsops zsops_kgdb = { + zs_kgdb_rxint, /* receive char available */ + zs_kgdb_stint, /* external/status */ + zs_kgdb_txint, /* xmit buffer empty */ + zs_kgdb_softint, /* process software interrupt */ +}; |