summaryrefslogtreecommitdiff
path: root/sys/arch/sparc/dev
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2002-08-12 10:44:05 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2002-08-12 10:44:05 +0000
commit15dafe6228319925897f71b6a78bb04ebfb3abc4 (patch)
tree2bfbe764cfc6f9b1e3c6ca9d29d0881a4283149e /sys/arch/sparc/dev
parenta83486fe3ff711d8b3727f8abae7995141bb7562 (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')
-rw-r--r--sys/arch/sparc/dev/bt_subr.c123
-rw-r--r--sys/arch/sparc/dev/btvar.h10
-rw-r--r--sys/arch/sparc/dev/bwtwo.c457
-rw-r--r--sys/arch/sparc/dev/cgeight.c477
-rw-r--r--sys/arch/sparc/dev/cgfour.c464
-rw-r--r--sys/arch/sparc/dev/cgfourteen.c895
-rw-r--r--sys/arch/sparc/dev/cgfourteenreg.h35
-rw-r--r--sys/arch/sparc/dev/cgfourteenvar.h94
-rw-r--r--sys/arch/sparc/dev/cgsix.c1023
-rw-r--r--sys/arch/sparc/dev/cgsixreg.h320
-rw-r--r--sys/arch/sparc/dev/cgthree.c522
-rw-r--r--sys/arch/sparc/dev/cgtwelve.c585
-rw-r--r--sys/arch/sparc/dev/cgtwelvereg.h213
-rw-r--r--sys/arch/sparc/dev/cgtwo.c481
-rw-r--r--sys/arch/sparc/dev/cgtworeg.h267
-rw-r--r--sys/arch/sparc/dev/cons.c725
-rw-r--r--sys/arch/sparc/dev/cons.h18
-rw-r--r--sys/arch/sparc/dev/fb.c465
-rw-r--r--sys/arch/sparc/dev/kbd.c1179
-rw-r--r--sys/arch/sparc/dev/ms.c357
-rw-r--r--sys/arch/sparc/dev/p9100.c404
-rw-r--r--sys/arch/sparc/dev/pfour.c207
-rw-r--r--sys/arch/sparc/dev/tcx.c697
-rw-r--r--sys/arch/sparc/dev/tcxreg.h92
-rw-r--r--sys/arch/sparc/dev/z8530kbd.c1335
-rw-r--r--sys/arch/sparc/dev/z8530reg.h451
-rw-r--r--sys/arch/sparc/dev/z8530sc.c357
-rw-r--r--sys/arch/sparc/dev/z8530sc.h158
-rw-r--r--sys/arch/sparc/dev/z8530tty.c1637
-rw-r--r--sys/arch/sparc/dev/zs.c2343
-rw-r--r--sys/arch/sparc/dev/zs_kgdb.c292
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 */
+};