diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/dev/usb/udl.c | 145 | ||||
-rw-r--r-- | sys/dev/usb/udl.h | 14 |
2 files changed, 156 insertions, 3 deletions
diff --git a/sys/dev/usb/udl.c b/sys/dev/usb/udl.c index 51d4f2c92e2..6960caf7234 100644 --- a/sys/dev/usb/udl.c +++ b/sys/dev/usb/udl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: udl.c,v 1.41 2009/09/13 18:16:15 mglocker Exp $ */ +/* $OpenBSD: udl.c,v 1.42 2009/09/19 11:54:16 mglocker Exp $ */ /* * Copyright (c) 2009 Marcus Glocker <mglocker@openbsd.org> @@ -88,6 +88,10 @@ int udl_putchar(void *, int, int, u_int, long); int udl_do_cursor(struct rasops_info *); int udl_draw_char(struct udl_softc *, uint16_t, uint16_t, u_int, uint32_t, uint32_t); +int udl_damage(struct udl_softc *, uint8_t *, + uint32_t, uint32_t, uint32_t, uint32_t); +int udl_draw_image(struct udl_softc *, uint8_t *, + uint32_t, uint32_t, uint32_t, uint32_t); usbd_status udl_ctrl_msg(struct udl_softc *, uint8_t, uint8_t, uint16_t, uint16_t, uint8_t *, size_t); @@ -100,6 +104,8 @@ usbd_status udl_set_decomp_table(struct udl_softc *, uint8_t *, uint16_t); int udl_load_huffman(struct udl_softc *); void udl_free_huffman(struct udl_softc *); +int udl_fbmem_alloc(struct udl_softc *); +void udl_fbmem_free(struct udl_softc *); usbd_status udl_cmd_alloc_xfer(struct udl_softc *); void udl_cmd_free_xfer(struct udl_softc *); int udl_cmd_alloc_buf(struct udl_softc *); @@ -395,6 +401,11 @@ udl_detach(struct device *self, int flags) udl_free_huffman(sc); /* + * Free framebuffer memory. + */ + udl_fbmem_free(sc); + + /* * Detach wsdisplay. */ if (sc->sc_wsdisplay != NULL) @@ -424,6 +435,9 @@ int udl_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) { struct udl_softc *sc; + struct wsdisplay_fbinfo *wdf; + struct udl_ioctl_damage *d; + int r; sc = v; @@ -435,6 +449,24 @@ udl_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) case WSDISPLAYIO_GTYPE: *(u_int *)data = WSDISPLAY_TYPE_DL; break; + case WSDISPLAYIO_GINFO: + wdf = (struct wsdisplay_fbinfo *)data; + wdf->height = sc->sc_height; + wdf->width = sc->sc_width; + wdf->depth = sc->sc_depth; + wdf->cmsize = 0; /* XXX fill up colormap size */ + break; + case WSDISPLAYIO_LINEBYTES: + *(u_int *)data = sc->sc_width * (sc->sc_depth / 8); + break; + case UDLIO_DAMAGE: + d = (struct udl_ioctl_damage *)data; + r = udl_damage(sc, sc->sc_fbmem, d->x1, d->x2, d->y1, d->y2); + if (r != 0) { + /* XXX we need to inform X11 when we failed to draw */ + printf("%s: %s: damage draw failed!\n", DN(sc), FUNC); + } + break; default: return (-1); } @@ -446,12 +478,29 @@ paddr_t udl_mmap(void *v, off_t off, int prot) { struct udl_softc *sc; + caddr_t p; + paddr_t pa; sc = v; DPRINTF(1, "%s: %s\n", DN(sc), FUNC); - return (-1); + /* allocate framebuffer memory */ + if (udl_fbmem_alloc(sc) == -1) + return (-1); + + /* return memory address to userland process */ + p = sc->sc_fbmem + off; + if (pmap_extract(pmap_kernel(), (vaddr_t)p, &pa) == FALSE) { + printf("udl_mmap: invalid page\n"); + udl_fbmem_free(sc); + return (-1); + } +#if defined(__powerpc__) || defined(__sparc64__) + return (pa); +#else + return (atop(pa)); +#endif } int @@ -879,6 +928,72 @@ udl_draw_char(struct udl_softc *sc, uint16_t fg, uint16_t bg, u_int uc, return (0); } +int +udl_damage(struct udl_softc *sc, uint8_t *image, + uint32_t x1, uint32_t x2, uint32_t y1, uint32_t y2) +{ + int r; + int x, y, width, height; + + x = x1; + y = y1; + width = x2 - x1; + height = y2 - y1; + + r = udl_draw_image(sc, image, x, y, width, height); + if (r != 0) + return (r); + + r = udl_cmd_send_async(sc); + if (r != 0) + return (r); + + return (0); +} + +int +udl_draw_image(struct udl_softc *sc, uint8_t *image, + uint32_t x, uint32_t y, uint32_t width, uint32_t height) +{ + int i, j, r; + int width_cur, x_cur; + uint8_t buf[UDL_CMD_MAX_DATA_SIZE]; + uint16_t *image16, lrgb16; + uint32_t off, block; + + for (i = 0; i < height; i++) { + off = ((y * sc->sc_width) + x) * 2; + x_cur = x; + width_cur = width; + + while (width_cur) { + if (width_cur > UDL_CMD_MAX_PIXEL_COUNT) + block = UDL_CMD_MAX_PIXEL_COUNT; + else + block = width_cur; + + /* fix RGB ordering */ + image16 = (uint16_t *)(image + off); + for (j = 0; j < (block * 2); j += 2) { + lrgb16 = htobe16(*image16); + bcopy(&lrgb16, buf + j, 2); + image16++; + } + + r = (sc->udl_fb_buf_write)(sc, buf, x_cur, y, block); + if (r != 0) + return (r); + + off += block * 2; + x_cur += block; + width_cur -= block; + } + y++; + } + + return (0); +} + /* ---------- */ usbd_status @@ -1054,6 +1169,32 @@ udl_free_huffman(struct udl_softc *sc) } } +int +udl_fbmem_alloc(struct udl_softc *sc) +{ + int size; + + size = (sc->sc_width * sc->sc_height) * (sc->sc_depth / 8); + size = round_page(size); + + if (sc->sc_fbmem == NULL) { + sc->sc_fbmem = malloc(size, M_DEVBUF, M_ZERO); + if (sc->sc_fbmem == NULL) + return (-1); + } + + return (0); +} + +void +udl_fbmem_free(struct udl_softc *sc) +{ + if (sc->sc_fbmem != NULL) { + free(sc->sc_fbmem, M_DEVBUF); + sc->sc_fbmem = NULL; + } +} + usbd_status udl_cmd_alloc_xfer(struct udl_softc *sc) { diff --git a/sys/dev/usb/udl.h b/sys/dev/usb/udl.h index 2a225bc7d98..32f8fa1d036 100644 --- a/sys/dev/usb/udl.h +++ b/sys/dev/usb/udl.h @@ -1,4 +1,4 @@ -/* $OpenBSD: udl.h,v 1.8 2009/09/13 10:40:08 mglocker Exp $ */ +/* $OpenBSD: udl.h,v 1.9 2009/09/19 11:54:16 mglocker Exp $ */ /* * Copyright (c) 2009 Marcus Glocker <mglocker@openbsd.org> @@ -70,6 +70,7 @@ struct udl_softc { uint16_t sc_height; uint8_t sc_depth; uint8_t sc_cursor_on; + uint8_t *sc_fbmem; /* framebuffer for X11 */ /* * We use function pointers to the framebuffer manipulation @@ -100,6 +101,17 @@ struct udl_softc { }; /* + * udl IOCTLs. + */ +struct udl_ioctl_damage { + int x1; + int x2; + int y1; + int y2; +}; +#define UDLIO_DAMAGE _IOWR('W', 0, struct udl_ioctl_damage) + +/* * Chip commands. */ #define UDL_CTRL_CMD_READ_EDID 0x02 |