summaryrefslogtreecommitdiff
path: root/sys/dev/pcmcia
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2006-04-16 20:45:01 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2006-04-16 20:45:01 +0000
commitd105cf31eb9e601911439f943234005022f2fffc (patch)
treec5c2177e2819abafb0a582108c557f96bfd95ac0 /sys/dev/pcmcia
parent9814cc09896824c76461742feedf2a2faf252afb (diff)
Preliminary driver for the Colorgraphic VoyagerVGA pcmcia frame buffer;
more like a proof of concept than anything useful, due to the slowness of the beast, but deraadt@ insists this gets in the tree. Written with matthieu@'s help.
Diffstat (limited to 'sys/dev/pcmcia')
-rw-r--r--sys/dev/pcmcia/cfxga.c896
-rw-r--r--sys/dev/pcmcia/cfxgareg.h55
-rw-r--r--sys/dev/pcmcia/files.pcmcia7
3 files changed, 957 insertions, 1 deletions
diff --git a/sys/dev/pcmcia/cfxga.c b/sys/dev/pcmcia/cfxga.c
new file mode 100644
index 00000000000..1eca9c713ec
--- /dev/null
+++ b/sys/dev/pcmcia/cfxga.c
@@ -0,0 +1,896 @@
+/* $OpenBSD: cfxga.c,v 1.1 2006/04/16 20:45:00 miod Exp $ */
+
+/*
+ * Copyright (c) 2005 Matthieu Herrb and Miodrag Vallat
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * Work-in-progress display driver for the Colorgraphic CompactFlash
+ * ``VoyagerVGA'' card.
+ *
+ * Our goals are:
+ * - to provide a somewhat usable emulation mode for extra text display.
+ * - to let an application (such as an X server) map the controller registers
+ * in order to do its own display game.
+ *
+ * Driving this card is somewhat a challenge since:
+ * - its video memory is not directly accessible.
+ * - no operation can make use of DMA.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/systm.h>
+#include <sys/malloc.h>
+#include <sys/conf.h>
+
+#include <dev/pcmcia/pcmciavar.h>
+#include <dev/pcmcia/pcmciareg.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wsdisplayvar.h>
+#include <dev/rasops/rasops.h>
+
+#include <dev/pcmcia/cfxgareg.h>
+
+/* #define CFXGADEBUG */
+
+#ifdef CFXGADEBUG
+#define DPRINTF(arg) printf arg
+#else
+#define DPRINTF(arg)
+#endif
+
+struct cfxga_screen;
+
+struct cfxga_softc {
+ struct device sc_dev;
+ struct pcmcia_function *sc_pf;
+ int sc_state;
+#define CS_MAPPED 0x0001
+#define CS_RESET 0x0002
+
+ struct pcmcia_mem_handle sc_pmemh;
+ int sc_memwin;
+ bus_addr_t sc_offset;
+
+ int sc_mode;
+
+ int sc_nscreens;
+ LIST_HEAD(, cfxga_screen) sc_scr;
+ struct cfxga_screen *sc_active;
+
+ struct device *sc_wsd;
+};
+
+int cfxga_match(struct device *, void *, void *);
+void cfxga_attach(struct device *, struct device *, void *);
+int cfxga_detach(struct device *, int);
+int cfxga_activate(struct device *, enum devact);
+
+struct cfattach cfxga_ca = {
+ sizeof(struct cfxga_softc), cfxga_match, cfxga_attach,
+ cfxga_detach, cfxga_activate
+};
+
+struct cfdriver cfxga_cd = {
+ NULL, "cfxga", DV_DULL
+};
+
+int cfxga_alloc_screen(void *, const struct wsscreen_descr *, void **,
+ int *, int *, long *);
+void cfxga_burner(void *, u_int, u_int);
+void cfxga_free_screen(void *, void *);
+int cfxga_ioctl(void *, u_long, caddr_t, int, struct proc *);
+paddr_t cfxga_mmap(void *, off_t, int);
+int cfxga_show_screen(void *, void *, int, void (*)(void *, int, int),
+ void *);
+
+struct wsdisplay_accessops cfxga_accessops = {
+ cfxga_ioctl,
+ cfxga_mmap,
+ cfxga_alloc_screen,
+ cfxga_free_screen,
+ cfxga_show_screen,
+ NULL,
+ NULL,
+ NULL,
+ cfxga_burner
+};
+
+struct wsscreen_descr cfxga_scr = {
+ "std"
+};
+
+const struct wsscreen_descr *cfxga_scr_descr[] = {
+ &cfxga_scr
+};
+
+const struct wsscreen_list cfxga_scr_list = {
+ sizeof cfxga_scr_descr / sizeof cfxga_scr_descr[0],
+ cfxga_scr_descr
+};
+
+/*
+ * Per-screen structure
+ */
+
+struct cfxga_screen {
+ LIST_ENTRY(cfxga_screen) scr_link;
+
+ /* parent reference */
+ struct cfxga_softc *scr_sc;
+
+ /* raster op glue */
+ struct rasops_info scr_ri;
+ struct wsdisplay_emulops scr_ops; /* old ri_ops */
+ void (*scr_do_cursor)(struct rasops_info *); /* old ri_do_cursor */
+
+ /* backing memory */
+ u_int8_t *scr_mem;
+};
+
+void cfxga_copycols(void *, int, int, int, int);
+void cfxga_copyrows(void *, int, int, int);
+void cfxga_do_cursor(struct rasops_info *);
+void cfxga_erasecols(void *, int, int, int, long);
+void cfxga_eraserows(void *, int, int, long);
+void cfxga_putchar(void *, int, int, u_int, long);
+
+int cfxga_install_function(struct pcmcia_function *);
+int cfxga_memory_rop(struct cfxga_softc *, struct cfxga_screen *, u_int,
+ int, int, int, int);
+void cfxga_remove_function(struct pcmcia_function *);
+void cfxga_reset_video(struct cfxga_softc *);
+void cfxga_reset_and_repaint(struct cfxga_softc *);
+int cfxga_standalone_rop(struct cfxga_softc *, u_int, int, int, int, int,
+ u_int16_t);
+u_int cfxga_wait(struct cfxga_softc *, u_int, u_int);
+
+#define cfxga_clear_screen(sc) \
+ cfxga_standalone_rop(sc, CROP_SOLIDFILL, 0, 0, 640, 480, 0)
+#define cfxga_repaint_screen(sc) \
+ cfxga_memory_rop(sc, sc->sc_active, CROP_EXTCOPY, 0, 0, 640, 480)
+
+#define cfxga_read(sc, addr) \
+ bus_space_read_2((sc)->sc_pmemh.memt, (sc)->sc_pmemh.memh, \
+ (sc)->sc_offset + (addr))
+#define cfxga_write(sc, addr, val) \
+ bus_space_write_2((sc)->sc_pmemh.memt, (sc)->sc_pmemh.memh, \
+ (sc)->sc_offset + (addr), (val))
+
+/*
+ * This card is very poorly engineered, specificationwise. It does not
+ * provide any CIS information, and has no vendor/product numbers as
+ * well: as such, there is no easy way to differentiate it from any
+ * other cheapo PCMCIA card.
+ *
+ * The best we can do is probe for a chip ID. This is not perfect but better
+ * than matching blindly. Of course this requires us to play some nasty games
+ * behind the PCMCIA framework to be able to do this probe, and correctly fail
+ * if this is not the card we are looking for.
+ *
+ * In shorter words: some card designers ought to be shot, as a service
+ * to the community.
+ */
+
+/*
+ * Create the necessary pcmcia function structures to alleviate the lack
+ * of any CIS information on this device.
+ * Actually, we hijack the fake function created by the pcmcia framework.
+ */
+int
+cfxga_install_function(struct pcmcia_function *pf)
+{
+ struct pcmcia_config_entry *cfe;
+
+ /* Get real. */
+ pf->pf_flags &= ~PFF_FAKE;
+
+ /* Tell the pcmcia framework where the CCR is. */
+ pf->ccr_base = 0x800;
+ pf->ccr_mask = 0x67;
+
+ /* Create a simple cfe. */
+ cfe = (struct pcmcia_config_entry *)malloc(sizeof *cfe,
+ M_DEVBUF, M_NOWAIT);
+ if (cfe == NULL) {
+ DPRINTF(("%s: cfe allocation failed\n", __func__));
+ return (ENOMEM);
+ }
+
+ bzero(cfe, sizeof *cfe);
+ cfe->number = 42; /* have to put some value... */
+ cfe->flags = PCMCIA_CFE_IO16;
+ cfe->iftype = PCMCIA_IFTYPE_MEMORY;
+
+ SIMPLEQ_INSERT_TAIL(&pf->cfe_head, cfe, cfe_list);
+
+ pcmcia_function_init(pf, cfe);
+ return (0);
+}
+
+/*
+ * Undo the changes done above.
+ * Such a function is necessary since we need a full-blown pcmcia world
+ * set up in order to do the device probe, but if we don't match the card,
+ * leaving this state will cause trouble during other probes.
+ */
+void
+cfxga_remove_function(struct pcmcia_function *pf)
+{
+ struct pcmcia_config_entry *cfe;
+
+ /* we are the first and only entry... */
+ cfe = SIMPLEQ_FIRST(&pf->cfe_head);
+ SIMPLEQ_REMOVE_HEAD(&pf->cfe_head, cfe_list);
+ free(cfe, M_DEVBUF);
+
+ /* And we're a figment of the kernel's imagination again. */
+ pf->pf_flags |= PFF_FAKE;
+}
+
+int
+cfxga_match(struct device *parent, void *match, void *aux)
+{
+ struct pcmcia_attach_args *pa = aux;
+ struct pcmcia_function *pf = pa->pf;
+ struct pcmcia_mem_handle h;
+ int rc;
+ int win;
+ bus_addr_t ptr;
+ u_int8_t id = 0;
+
+ if (pa->product != PCMCIA_PRODUCT_INVALID ||
+ pa->manufacturer != PCMCIA_VENDOR_INVALID)
+ return (0);
+
+ /* Only a card with no CIS will have a fake function... */
+ if ((pf->pf_flags & PFF_FAKE) == 0)
+ return (0);
+
+ if (cfxga_install_function(pf) != 0)
+ return (0);
+
+ if (pcmcia_function_enable(pf) != 0) {
+ DPRINTF(("%s: function enable failed\n"));
+ return (0);
+ }
+
+ rc = pcmcia_mem_alloc(pf, CFXGA_MEM_RANGE, &h);
+ if (rc != 0)
+ goto out;
+
+ rc = pcmcia_mem_map(pf, PCMCIA_MEM_ATTR, 0, CFXGA_MEM_RANGE,
+ &h, &ptr, &win);
+ if (rc != 0)
+ goto out2;
+
+ id = bus_space_read_1(h.memt, h.memh, ptr) & CR_ID_MASK;
+
+ pcmcia_mem_unmap(pa->pf, win);
+out2:
+ pcmcia_mem_free(pa->pf, &h);
+out:
+ pcmcia_function_disable(pf);
+ cfxga_remove_function(pf);
+
+ /*
+ * Be sure to return a value greater than pccom's if we match,
+ * otherwise it can win due to the way config(8) will order devices...
+ */
+ return (id == CR_ID ? 10 : 0);
+}
+
+int
+cfxga_activate(struct device *dev, enum devact act)
+{
+ struct cfxga_softc *sc = (void *)dev;
+
+ switch (act) {
+ case DVACT_ACTIVATE:
+ if (pcmcia_function_enable(sc->sc_pf) != 0) {
+ printf("%s: function enable failed\n",
+ sc->sc_dev.dv_xname);
+ } else {
+ cfxga_reset_and_repaint(sc);
+ }
+ break;
+ case DVACT_DEACTIVATE:
+ pcmcia_function_disable(sc->sc_pf);
+ break;
+ }
+ return (0);
+}
+
+void
+cfxga_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct cfxga_softc *sc = (void *)self;
+ struct pcmcia_attach_args *pa = aux;
+ struct pcmcia_function *pf = pa->pf;
+ struct wsemuldisplaydev_attach_args waa;
+
+ LIST_INIT(&sc->sc_scr);
+ sc->sc_nscreens = 0;
+ sc->sc_pf = pf;
+
+ if (cfxga_install_function(pf) != 0) {
+ printf(": pcmcia function setup failed\n");
+ return;
+ }
+
+ if (pcmcia_function_enable(pf)) {
+ printf(": function enable failed\n");
+ return;
+ }
+
+ if (pcmcia_mem_alloc(pf, CFXGA_MEM_RANGE, &sc->sc_pmemh) != 0) {
+ printf(": can't allocate memory space\n");
+ return;
+ }
+
+ if (pcmcia_mem_map(pf, PCMCIA_MEM_ATTR, 0, CFXGA_MEM_RANGE,
+ &sc->sc_pmemh, &sc->sc_offset, &sc->sc_memwin) != 0) {
+ printf(": can't map frame buffer registers\n");
+ pcmcia_mem_free(pf, &sc->sc_pmemh);
+ return;
+ }
+
+ SET(sc->sc_state, CS_MAPPED);
+
+ printf("\n");
+
+ sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
+
+ cfxga_reset_video(sc);
+
+ waa.console = 0;
+ waa.scrdata = &cfxga_scr_list;
+ waa.accessops = &cfxga_accessops;
+ waa.accesscookie = sc;
+
+ if ((sc->sc_wsd = config_found(self, &waa, wsemuldisplaydevprint)) ==
+ NULL)
+ cfxga_clear_screen(sc); /* otherwise wscons will do this */
+}
+
+int
+cfxga_detach(struct device *dev, int flags)
+{
+ struct cfxga_softc *sc = (void *)dev;
+
+ /*
+ * Detach all children, and hope wsdisplay detach code is correct...
+ */
+ if (sc->sc_wsd != NULL) {
+ config_detach(sc->sc_wsd, DETACH_FORCE);
+ /* sc->sc_wsd = NULL; */
+ }
+
+ if (ISSET(sc->sc_state, CS_MAPPED)) {
+ pcmcia_mem_unmap(sc->sc_pf, sc->sc_memwin);
+ pcmcia_mem_free(sc->sc_pf, &sc->sc_pmemh);
+ /* CLR(sc->sc_state, CS_MAPPED); */
+ }
+
+ return (0);
+}
+
+/*
+ * Wscons operations
+ */
+
+int
+cfxga_alloc_screen(void *v, const struct wsscreen_descr *type, void **cookiep,
+ int *curxp, int *curyp, long *attrp)
+{
+ struct cfxga_softc *sc = v;
+ struct cfxga_screen *scr;
+ struct rasops_info *ri;
+
+ scr = malloc(sizeof *scr, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
+ if (scr == NULL)
+ return (ENOMEM);
+ bzero(scr, sizeof *scr);
+
+ scr->scr_mem = malloc(640 * 480 * 16 / 8, M_DEVBUF,
+ cold ? M_NOWAIT : M_WAITOK);
+ if (scr->scr_mem == NULL) {
+ free(scr, M_DEVBUF);
+ return (ENOMEM);
+ }
+ bzero(scr->scr_mem, 640 * 480 * 16 / 8);
+
+ ri = &scr->scr_ri;
+ ri->ri_hw = (void *)scr;
+ ri->ri_bits = scr->scr_mem;
+ ri->ri_depth = 16;
+ ri->ri_width = 640;
+ ri->ri_height = 480;
+ ri->ri_stride = 640 * 16 / 8;
+ /* ri->ri_flg = RI_FULLCLEAR; */
+
+ /* swap B and R */
+ ri->ri_rnum = 5;
+ ri->ri_rpos = 11;
+ ri->ri_gnum = 6;
+ ri->ri_gpos = 5;
+ ri->ri_bnum = 5;
+ ri->ri_bpos = 0;
+
+ if (cfxga_scr.nrows == 0) {
+ rasops_init(ri, 100, 100);
+
+ cfxga_scr.nrows = ri->ri_rows;
+ cfxga_scr.ncols = ri->ri_cols;
+ cfxga_scr.capabilities = ri->ri_caps;
+ cfxga_scr.textops = &ri->ri_ops;
+ } else {
+ rasops_init(ri, cfxga_scr.nrows, cfxga_scr.ncols);
+ }
+
+ scr->scr_ops = ri->ri_ops;
+ ri->ri_ops.copycols = cfxga_copycols;
+ ri->ri_ops.copyrows = cfxga_copyrows;
+ ri->ri_ops.erasecols = cfxga_erasecols;
+ ri->ri_ops.eraserows = cfxga_eraserows;
+ ri->ri_ops.putchar = cfxga_putchar;
+ scr->scr_do_cursor = ri->ri_do_cursor;
+ ri->ri_do_cursor = cfxga_do_cursor;
+
+ scr->scr_sc = sc;
+ LIST_INSERT_HEAD(&sc->sc_scr, scr, scr_link);
+ sc->sc_nscreens++;
+
+ ri->ri_ops.alloc_attr(ri, 0, 0, 0, attrp);
+
+ *cookiep = ri;
+ *curxp = *curyp = 0;
+
+ return (0);
+}
+
+void
+cfxga_burner(void *v, u_int on, u_int flags)
+{
+ struct cfxga_softc *sc = (void *)v;
+ u_int16_t ven;
+
+ ven = cfxga_read(sc, CFREG_VIDEO);
+
+ if (on)
+ cfxga_write(sc, CFREG_VIDEO, ven | CV_VIDEO_VGA);
+ else
+ cfxga_write(sc, CFREG_VIDEO, ven & ~CV_VIDEO_VGA);
+}
+
+void
+cfxga_free_screen(void *v, void *cookie)
+{
+ struct cfxga_softc *sc = v;
+ struct rasops_info *ri = cookie;
+ struct cfxga_screen *scr = ri->ri_hw;
+
+ LIST_REMOVE(scr, scr_link);
+ sc->sc_nscreens--;
+
+ if (scr == sc->sc_active) {
+ sc->sc_active = NULL;
+ cfxga_burner(sc, 0, 0);
+ }
+
+ free(scr->scr_mem, M_DEVBUF);
+ free(scr, M_DEVBUF);
+}
+
+int
+cfxga_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+ struct cfxga_softc *sc = v;
+ struct wsdisplay_fbinfo *wdf;
+ int mode;
+
+ switch (cmd) {
+ case WSDISPLAYIO_GTYPE:
+ *(u_int *)data = WSDISPLAY_TYPE_CFXGA;
+ break;
+
+ case WSDISPLAYIO_GINFO:
+ /* it's not worth using sc->sc_active->scr_ri fields... */
+ wdf = (struct wsdisplay_fbinfo *)data;
+ wdf->height = 640;
+ wdf->width = 480;
+ wdf->depth = 16;
+ wdf->cmsize = 0;
+ break;
+
+ case WSDISPLAYIO_SMODE:
+ mode = *(u_int *)data;
+ if (mode == sc->sc_mode)
+ break;
+ switch (mode) {
+ case WSDISPLAYIO_MODE_EMUL:
+ cfxga_reset_and_repaint(sc);
+ break;
+ case WSDISPLAYIO_MODE_MAPPED:
+ break;
+ default:
+ return (EINVAL);
+ }
+ sc->sc_mode = mode;
+ break;
+
+ /* these operations are handled by the wscons code... */
+ case WSDISPLAYIO_GVIDEO:
+ case WSDISPLAYIO_SVIDEO:
+ break;
+
+ /* these operations are not supported... */
+ case WSDISPLAYIO_GETCMAP:
+ case WSDISPLAYIO_PUTCMAP:
+ case WSDISPLAYIO_LINEBYTES:
+ case WSDISPLAYIO_GCURPOS:
+ case WSDISPLAYIO_SCURPOS:
+ case WSDISPLAYIO_GCURMAX:
+ case WSDISPLAYIO_GCURSOR:
+ case WSDISPLAYIO_SCURSOR:
+ default:
+ return (-1);
+ }
+
+ return (0);
+}
+
+paddr_t
+cfxga_mmap(void *v, off_t off, int prot)
+{
+ return (-1);
+}
+
+int
+cfxga_show_screen(void *v, void *cookie, int waitok,
+ void (*cb)(void *, int, int), void *cbarg)
+{
+ struct cfxga_softc *sc = v;
+ struct rasops_info *ri = cookie;
+ struct cfxga_screen *scr = ri->ri_hw, *old;
+
+ old = sc->sc_active;
+ if (old == scr)
+ return (0);
+
+ sc->sc_active = scr;
+ cfxga_repaint_screen(sc);
+
+ /* turn back video on as well if necessary... */
+ if (old == NULL)
+ cfxga_burner(sc, 1, 0);
+
+ return (0);
+}
+
+/*
+ * Real frame buffer operations
+ */
+
+void
+cfxga_reset_video(struct cfxga_softc *sc)
+{
+ /* reset controller */
+ cfxga_write(sc, CFREG_BLT_CTRL, 0);
+ cfxga_write(sc, CFREG_RESET, CR_RESET);
+ delay(25000);
+ cfxga_write(sc, CFREG_RESET, 0);
+ delay(25000);
+ cfxga_write(sc, CFREG_BLT_CTRL, 0);
+ (void)cfxga_read(sc, CFREG_BLT_DATA);
+
+ /*
+ * Setup video mode - magic values taken from the linux so-called
+ * driver source.
+ */
+
+ /* clock */
+ cfxga_write(sc, 0x10, 2);
+ cfxga_write(sc, 0x14, 0);
+ cfxga_write(sc, 0x1c, 2);
+ /* memory configuration */
+ cfxga_write(sc, 0x20, 0x0380);
+ cfxga_write(sc, 0x2a, 0x100);
+ /* CRT and TV settings */
+ cfxga_write(sc, 0x62, 0);
+ cfxga_write(sc, 0x64, 0);
+ cfxga_write(sc, 0x68, 0);
+ cfxga_write(sc, 0x6a, 0);
+ /* cursor */
+ cfxga_write(sc, 0x80, 0);
+ cfxga_write(sc, 0x82, 0x259);
+ cfxga_write(sc, 0x84, 0x190);
+ cfxga_write(sc, 0x86, 0);
+ cfxga_write(sc, 0x88, 0);
+ cfxga_write(sc, 0x8a, 0x3f1f);
+ cfxga_write(sc, 0x8c, 0x1f);
+ cfxga_write(sc, 0x8e, 0);
+ /* unknown */
+ cfxga_write(sc, 0x1f0, 0x210);
+ cfxga_write(sc, 0x1f4, 0);
+
+ /* 640x480x72x16 specific values */
+ /* gpio */
+ cfxga_write(sc, 0x04, 0x07);
+ cfxga_write(sc, 0x08, 0x1ffe);
+ /* more clock */
+ cfxga_write(sc, 0x18, 0);
+ cfxga_write(sc, 0x1e, 2);
+ /* more CRT and TV settings */
+ cfxga_write(sc, 0x50, 0x4f);
+ cfxga_write(sc, 0x52, 0x217);
+ cfxga_write(sc, 0x54, 0x4);
+ cfxga_write(sc, 0x56, 0x1df);
+ cfxga_write(sc, 0x58, 0x827);
+ cfxga_write(sc, 0x5a, 0x1202);
+ cfxga_write(sc, 0x60, 5);
+ cfxga_write(sc, 0x66, 640);
+
+ cfxga_write(sc, CFREG_VIDEO, CV_VIDEO_VGA);
+ delay(25000);
+}
+
+void
+cfxga_reset_and_repaint(struct cfxga_softc *sc)
+{
+ cfxga_reset_video(sc);
+ if (sc->sc_active != NULL)
+ cfxga_repaint_screen(sc);
+ else
+ cfxga_clear_screen(sc);
+}
+
+u_int
+cfxga_wait(struct cfxga_softc *sc, u_int mask, u_int result)
+{
+ u_int tries;
+
+ for (tries = 100000; tries != 0; tries--) {
+ if ((bus_space_read_1(sc->sc_pmemh.memt, sc->sc_pmemh.memh,
+ sc->sc_offset + CFREG_BLT_CTRL) & mask) == result)
+ break;
+ delay(10);
+ }
+
+ return (tries);
+}
+
+int
+cfxga_memory_rop(struct cfxga_softc *sc, struct cfxga_screen *scr, u_int rop,
+ int x, int y, int cx, int cy)
+{
+ u_int pos;
+ u_int16_t *data;
+
+ pos = (y * 640 + x) * (16 / 8);
+ data = (u_int16_t *)(scr->scr_mem + pos);
+
+ if (cfxga_wait(sc, CC_BLT_BUSY, 0) == 0) {
+ DPRINTF(("%s: not ready\n", __func__));
+ if (ISSET(sc->sc_state, CS_RESET))
+ return (EAGAIN);
+ else {
+ DPRINTF(("%s: resetting...\n", sc->sc_dev.dv_xname));
+ SET(sc->sc_state, CS_RESET);
+ cfxga_reset_and_repaint(sc);
+ CLR(sc->sc_state, CS_RESET);
+ return (0);
+ }
+ }
+ (void)cfxga_read(sc, CFREG_BLT_DATA);
+
+ cfxga_write(sc, CFREG_BLT_ROP, rop);
+ cfxga_write(sc, CFREG_BLT_UNK1, 0);
+ cfxga_write(sc, CFREG_BLT_UNK2, 0);
+ cfxga_write(sc, CFREG_BLT_SRCLOW, pos);
+ cfxga_write(sc, CFREG_BLT_SRCHIGH, pos >> 16);
+ cfxga_write(sc, CFREG_BLT_STRIDE, 640);
+ cfxga_write(sc, CFREG_BLT_WIDTH, cx - 1);
+ cfxga_write(sc, CFREG_BLT_HEIGHT, cy - 1);
+ cfxga_write(sc, CFREG_BLT_CTRL, CC_BLT_BUSY | CC_BPP_16);
+
+ (void)cfxga_wait(sc, CC_BLT_BUSY, CC_BLT_BUSY);
+ while (cy-- != 0) {
+ for (x = 0; x < cx; x++) {
+ cfxga_write(sc, CFREG_BLT_DATA, *data++);
+
+ /*
+ * Let the cheap breathe.
+ * If this is not enough to let it recover,
+ * abort the operation.
+ */
+ if (cfxga_wait(sc, CC_FIFO_BUSY, 0) == 0) {
+ DPRINTF(("%s: abort\n", __func__));
+ cfxga_write(sc, CFREG_BLT_CTRL, 0);
+ return (EINTR);
+ }
+ }
+ data += (640 - cx);
+ }
+
+ return (0);
+}
+
+int
+cfxga_standalone_rop(struct cfxga_softc *sc, u_int rop, int x, int y,
+ int cx, int cy, u_int16_t srccolor)
+{
+ u_int pos;
+
+ pos = (y * 640 + x) * (16 / 8);
+
+ if (cfxga_wait(sc, CC_BLT_BUSY, 0) == 0) {
+ DPRINTF(("%s: not ready\n", __func__));
+ if (ISSET(sc->sc_state, CS_RESET))
+ return (EAGAIN);
+ else {
+ DPRINTF(("%s: resetting...\n", sc->sc_dev.dv_xname));
+ SET(sc->sc_state, CS_RESET);
+ cfxga_reset_and_repaint(sc);
+ CLR(sc->sc_state, CS_RESET);
+ return (0);
+ }
+ }
+
+ cfxga_write(sc, CFREG_BLT_ROP, rop);
+ cfxga_write(sc, CFREG_BLT_UNK1, 0);
+ cfxga_write(sc, CFREG_BLT_UNK2, 0);
+ cfxga_write(sc, CFREG_BLT_SRCLOW, pos);
+ cfxga_write(sc, CFREG_BLT_SRCHIGH, pos >> 16);
+ cfxga_write(sc, CFREG_BLT_STRIDE, 640);
+ cfxga_write(sc, CFREG_BLT_WIDTH, cx - 1);
+ cfxga_write(sc, CFREG_BLT_HEIGHT, cy - 1);
+ cfxga_write(sc, CFREG_BLT_SRCCOLOR, srccolor);
+ cfxga_write(sc, CFREG_BLT_CTRL, CC_BLT_BUSY | CC_BPP_16);
+
+ return (0);
+}
+
+/*
+ * Text console raster operations
+ *
+ * For all operations, we need first to run them on the memory frame buffer
+ * (by means of the rasops primitives), then decide what to send to the
+ * controller.
+ *
+ * For now we end up sending every operation to the device. But this could
+ * be improved, based on actual knowledge of what sequences of operations
+ * the wscons emulations perform. This is far from trivial...
+ *
+ * Another approach worth trying would be to use a timeout and reblt the
+ * whole screen if it has changed, i.e. set a flag in all raster op routines
+ * below, and have the timeout callback do a blt if the flag is set.
+ * However, since a whole blt takes close to a second (or maybe more) it
+ * is probably not a good idea.
+ */
+
+void
+cfxga_copycols(void *cookie, int row, int src, int dst, int num)
+{
+ struct rasops_info *ri = cookie;
+ struct cfxga_screen *scr = ri->ri_hw;
+ int x, y, cx, cy;
+
+ (*scr->scr_ops.copycols)(ri, row, src, dst, num);
+ x = dst * ri->ri_font->fontwidth + ri->ri_xorigin;
+ y = row * ri->ri_font->fontheight + ri->ri_yorigin;
+ cx = num * ri->ri_font->fontwidth;
+ cy = ri->ri_font->fontheight;
+ cfxga_memory_rop(scr->scr_sc, scr, CROP_EXTCOPY, x, y, cx, cy);
+}
+
+void
+cfxga_copyrows(void *cookie, int src, int dst, int num)
+{
+ struct rasops_info *ri = cookie;
+ struct cfxga_screen *scr = ri->ri_hw;
+ int x, y, cx, cy;
+
+ (*scr->scr_ops.copyrows)(ri, src, dst, num);
+
+ x = ri->ri_xorigin;
+ y = dst * ri->ri_font->fontheight + ri->ri_yorigin;
+ cx = ri->ri_emuwidth;
+ cy = num * ri->ri_font->fontheight;
+ cfxga_memory_rop(scr->scr_sc, scr, CROP_EXTCOPY, x, y, cx, cy);
+}
+
+void
+cfxga_do_cursor(struct rasops_info *ri)
+{
+ struct cfxga_screen *scr = ri->ri_hw;
+ int x, y, cx, cy;
+
+ x = ri->ri_ccol * ri->ri_font->fontwidth + ri->ri_xorigin;
+ y = ri->ri_crow * ri->ri_font->fontheight + ri->ri_yorigin;
+ cx = ri->ri_font->fontwidth;
+ cy = ri->ri_font->fontheight;
+#if 0
+ cfxga_standalone_rop(scr->scr_sc, CROP_SRCXORDST, x, y, cx, cy, 0);
+#else
+ (*scr->scr_do_cursor)(ri);
+ cfxga_memory_rop(scr->scr_sc, scr, CROP_EXTCOPY, x, y, cx, cy);
+#endif
+}
+
+void
+cfxga_erasecols(void *cookie, int row, int col, int num, long attr)
+{
+ struct rasops_info *ri = cookie;
+ struct cfxga_screen *scr = ri->ri_hw;
+ int fg, bg, uline;
+ int x, y, cx, cy;
+
+ (*scr->scr_ops.erasecols)(ri, row, col, num, attr);
+
+ rasops_unpack_attr(attr, &fg, &bg, &uline);
+ x = col * ri->ri_font->fontwidth + ri->ri_xorigin;
+ y = row * ri->ri_font->fontheight + ri->ri_yorigin;
+ cx = num * ri->ri_font->fontwidth;
+ cy = ri->ri_font->fontheight;
+ cfxga_standalone_rop(scr->scr_sc, CROP_SOLIDFILL, x, y, cx, cy,
+ ri->ri_devcmap[bg]);
+}
+
+void
+cfxga_eraserows(void *cookie, int row, int num, long attr)
+{
+ struct rasops_info *ri = cookie;
+ struct cfxga_screen *scr = ri->ri_hw;
+ int fg, bg, uline;
+ int x, y, cx, cy;
+
+ (*scr->scr_ops.eraserows)(ri, row, num, attr);
+
+ rasops_unpack_attr(attr, &fg, &bg, &uline);
+ x = ri->ri_xorigin;
+ y = row * ri->ri_font->fontheight + ri->ri_yorigin;
+ cx = ri->ri_emuwidth;
+ cy = num * ri->ri_font->fontheight;
+ cfxga_standalone_rop(scr->scr_sc, CROP_SOLIDFILL, x, y, cx, cy,
+ ri->ri_devcmap[bg]);
+}
+
+void
+cfxga_putchar(void *cookie, int row, int col, u_int uc, long attr)
+{
+ struct rasops_info *ri = cookie;
+ struct cfxga_screen *scr = ri->ri_hw;
+ int x, y, cx, cy;
+
+ (*scr->scr_ops.putchar)(ri, row, col, uc, attr);
+
+ x = col * ri->ri_font->fontwidth + ri->ri_xorigin;
+ y = row * ri->ri_font->fontheight + ri->ri_yorigin;
+ cx = ri->ri_font->fontwidth;
+ cy = ri->ri_font->fontheight;
+
+ if (uc == ' ') {
+ int fg, bg, uline;
+
+ rasops_unpack_attr(attr, &fg, &bg, &uline);
+ cfxga_standalone_rop(scr->scr_sc, CROP_SOLIDFILL, x, y, cx, cy,
+ ri->ri_devcmap[bg]);
+ } else
+ cfxga_memory_rop(scr->scr_sc, scr, CROP_EXTCOPY, x, y, cx, cy);
+}
diff --git a/sys/dev/pcmcia/cfxgareg.h b/sys/dev/pcmcia/cfxgareg.h
new file mode 100644
index 00000000000..c925c6a750e
--- /dev/null
+++ b/sys/dev/pcmcia/cfxgareg.h
@@ -0,0 +1,55 @@
+/* $OpenBSD: cfxgareg.h,v 1.1 2006/04/16 20:45:00 miod Exp $ */
+
+/*
+ * Copyright (c) 2005 Matthieu Herrb and Miodrag Vallat
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+/*
+ * (very scarce) registers layout. Actual chip documentation would be immensely
+ * appreciated.
+ */
+#define CFREG_RESET 0x0000 /* reset and ID register */
+#define CR_RESET 0x8080
+#define CR_ID_MASK 0x00fc
+#define CR_ID 0x001c
+
+#define CFREG_BLT_CTRL 0x0100 /* control/status */
+#define CC_FIFO_BUSY 0x0010
+#define CC_BLT_BUSY 0x0080
+#define CC_BPP_8 0x0000
+#define CC_BPP_16 0x0180
+#define CFREG_BLT_ROP 0x0102 /* raster op */
+#if 0
+#define CROP_SRCXORDST 0x0606 /* not so right... */
+#endif
+#define CROP_SOLIDFILL 0x0c0c
+#define CROP_EXTCOPY 0x000c
+#define CFREG_BLT_UNK1 0x0104
+#define CFREG_BLT_UNK2 0x0106
+#define CFREG_BLT_SRCLOW 0x0108
+#define CFREG_BLT_SRCHIGH 0x010a
+#define CFREG_BLT_STRIDE 0x010c
+#define CFREG_BLT_WIDTH 0x0110
+#define CFREG_BLT_HEIGHT 0x0112
+#define CFREG_BLT_SRCCOLOR 0x0118
+
+#define CFREG_VIDEO 0x01fc
+#define CV_VIDEO_VGA 0x0002
+
+#define CFREG_BLT_DATA 0x0400
+
+#ifdef _KERNEL
+#define CFXGA_MEM_RANGE 0x0800
+#endif
diff --git a/sys/dev/pcmcia/files.pcmcia b/sys/dev/pcmcia/files.pcmcia
index c2258786138..bad941f812c 100644
--- a/sys/dev/pcmcia/files.pcmcia
+++ b/sys/dev/pcmcia/files.pcmcia
@@ -1,4 +1,4 @@
-# $OpenBSD: files.pcmcia,v 1.38 2005/03/08 20:00:25 tdeval Exp $
+# $OpenBSD: files.pcmcia,v 1.39 2006/04/16 20:45:00 miod Exp $
# $NetBSD: files.pcmcia,v 1.9 1998/06/21 18:45:41 christos Exp $
#
# Config.new file and device description for machine-independent PCMCIA code.
@@ -95,3 +95,8 @@ file dev/pcmcia/if_an_pcmcia.c an_pcmcia
device gpr
attach gpr at pcmcia with gpr
file dev/pcmcia/gpr.c gpr needs-flag
+
+# IODATA CFXGA Compact flash VGA card
+device cfxga: wsemuldisplaydev, rasops16
+attach cfxga at pcmcia with cfxga
+file dev/pcmcia/cfxga.c cfxga