1*c3de6240Smiod /* $OpenBSD: udl.c,v 1.103 2024/11/09 08:26:29 miod Exp $ */ 2c197399bSmglocker 3c197399bSmglocker /* 4c197399bSmglocker * Copyright (c) 2009 Marcus Glocker <mglocker@openbsd.org> 5c197399bSmglocker * 6c197399bSmglocker * Permission to use, copy, modify, and distribute this software for any 7c197399bSmglocker * purpose with or without fee is hereby granted, provided that the above 8c197399bSmglocker * copyright notice and this permission notice appear in all copies. 9c197399bSmglocker * 10c197399bSmglocker * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11c197399bSmglocker * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12c197399bSmglocker * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13c197399bSmglocker * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14c197399bSmglocker * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15c197399bSmglocker * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16c197399bSmglocker * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17c197399bSmglocker */ 18c197399bSmglocker 19c197399bSmglocker /* 20c197399bSmglocker * Driver for the ``DisplayLink DL-120 / DL-160'' graphic chips based 21c197399bSmglocker * on the reversed engineered specifications of Florian Echtler 22c197399bSmglocker * <floe@butterbrot.org>: 23c197399bSmglocker * 24c197399bSmglocker * http://floe.butterbrot.org/displaylink/doku.php 25c197399bSmglocker * 26c197399bSmglocker * This driver has been inspired by the cfxga(4) driver because we have 27c197399bSmglocker * to deal with similar challenges, like no direct access to the video 28c197399bSmglocker * memory. 29c197399bSmglocker */ 30c197399bSmglocker 31c197399bSmglocker #include <sys/param.h> 32c197399bSmglocker #include <sys/device.h> 33c197399bSmglocker #include <sys/malloc.h> 349448a446Stedu #include <sys/systm.h> 359448a446Stedu 369448a446Stedu #include <uvm/uvm_extern.h> 37c197399bSmglocker 38c197399bSmglocker #include <dev/usb/usb.h> 39c197399bSmglocker #include <dev/usb/usbdi.h> 40c197399bSmglocker #include <dev/usb/usbdi_util.h> 41c197399bSmglocker #include <dev/usb/usbdevs.h> 42c197399bSmglocker 43c197399bSmglocker #include <dev/wscons/wsconsio.h> 44c197399bSmglocker #include <dev/wscons/wsdisplayvar.h> 45c197399bSmglocker #include <dev/rasops/rasops.h> 46c197399bSmglocker 476e641510Smaja #include <dev/videomode/videomode.h> 486e641510Smaja #include <dev/videomode/edidvar.h> 496e641510Smaja 50c197399bSmglocker #include <dev/usb/udl.h> 5119a86cbaSmglocker #include <dev/usb/udlio.h> 52c197399bSmglocker 53c197399bSmglocker /* 54c197399bSmglocker * Defines. 55c197399bSmglocker */ 56c197399bSmglocker #if 0 57c197399bSmglocker #define UDL_DEBUG 58c197399bSmglocker #endif 59c197399bSmglocker #ifdef UDL_DEBUG 60c197399bSmglocker int udl_debug = 1; 61c197399bSmglocker #define DPRINTF(l, x...) do { if ((l) <= udl_debug) printf(x); } while (0) 62c197399bSmglocker #else 63c197399bSmglocker #define DPRINTF(l, x...) 64c197399bSmglocker #endif 65c197399bSmglocker 66c197399bSmglocker #define DN(sc) ((sc)->sc_dev.dv_xname) 67c197399bSmglocker #define FUNC __func__ 68c197399bSmglocker 69c197399bSmglocker /* 70c197399bSmglocker * Prototypes. 71c197399bSmglocker */ 72c197399bSmglocker int udl_match(struct device *, void *, void *); 73c197399bSmglocker void udl_attach(struct device *, struct device *, void *); 74ef89f9e6Smpi void udl_attach_hook(struct device *); 75c197399bSmglocker int udl_detach(struct device *, int); 76e78728c7Spirofti int udl_activate(struct device *, int); 77c197399bSmglocker 78c197399bSmglocker int udl_ioctl(void *, u_long, caddr_t, int, struct proc *); 79c197399bSmglocker paddr_t udl_mmap(void *, off_t, int); 80c197399bSmglocker int udl_alloc_screen(void *, const struct wsscreen_descr *, 81e0c3e559Sjsg void **, int *, int *, uint32_t *); 82c197399bSmglocker void udl_free_screen(void *, void *); 83c197399bSmglocker int udl_show_screen(void *, void *, int, 84c197399bSmglocker void (*)(void *, int, int), void *); 8583275742Smiod int udl_load_font(void *, void *, struct wsdisplay_font *); 8683275742Smiod int udl_list_font(void *, struct wsdisplay_font *); 87c197399bSmglocker void udl_burner(void *, u_int, u_int); 88c197399bSmglocker 89072953e3Smiod int udl_copycols(void *, int, int, int, int); 90072953e3Smiod int udl_copyrows(void *, int, int, int); 91e0c3e559Sjsg int udl_erasecols(void *, int, int, int, uint32_t); 92e0c3e559Sjsg int udl_eraserows(void *, int, int, uint32_t); 93e0c3e559Sjsg int udl_putchar(void *, int, int, u_int, uint32_t); 94072953e3Smiod int udl_do_cursor(struct rasops_info *); 9523e0be93Smglocker int udl_draw_char(struct udl_softc *, uint16_t, uint16_t, u_int, 9623e0be93Smglocker uint32_t, uint32_t); 97fa695a51Smglocker int udl_damage(struct udl_softc *, uint8_t *, 98fa695a51Smglocker uint32_t, uint32_t, uint32_t, uint32_t); 99fa695a51Smglocker int udl_draw_image(struct udl_softc *, uint8_t *, 100fa695a51Smglocker uint32_t, uint32_t, uint32_t, uint32_t); 101c197399bSmglocker 102c197399bSmglocker usbd_status udl_ctrl_msg(struct udl_softc *, uint8_t, uint8_t, 103c197399bSmglocker uint16_t, uint16_t, uint8_t *, size_t); 104c197399bSmglocker usbd_status udl_poll(struct udl_softc *, uint32_t *); 105c197399bSmglocker usbd_status udl_read_1(struct udl_softc *, uint16_t, uint8_t *); 106c197399bSmglocker usbd_status udl_write_1(struct udl_softc *, uint16_t, uint8_t); 107c197399bSmglocker usbd_status udl_read_edid(struct udl_softc *, uint8_t *); 1086e641510Smaja uint8_t udl_lookup_mode(uint16_t, uint16_t, uint8_t, uint16_t, 1096e641510Smaja uint32_t); 1106e641510Smaja int udl_select_chip(struct udl_softc *); 111c197399bSmglocker usbd_status udl_set_enc_key(struct udl_softc *, uint8_t *, uint8_t); 112c197399bSmglocker usbd_status udl_set_decomp_table(struct udl_softc *, uint8_t *, uint16_t); 113c197399bSmglocker 1142fa8dc63Smglocker int udl_load_huffman(struct udl_softc *); 1152fa8dc63Smglocker void udl_free_huffman(struct udl_softc *); 116fa695a51Smglocker int udl_fbmem_alloc(struct udl_softc *); 117fa695a51Smglocker void udl_fbmem_free(struct udl_softc *); 118c197399bSmglocker usbd_status udl_cmd_alloc_xfer(struct udl_softc *); 119c197399bSmglocker void udl_cmd_free_xfer(struct udl_softc *); 120c197399bSmglocker int udl_cmd_alloc_buf(struct udl_softc *); 121c197399bSmglocker void udl_cmd_free_buf(struct udl_softc *); 122c197399bSmglocker void udl_cmd_insert_int_1(struct udl_softc *, uint8_t); 123c197399bSmglocker void udl_cmd_insert_int_2(struct udl_softc *, uint16_t); 124c197399bSmglocker void udl_cmd_insert_int_3(struct udl_softc *, uint32_t); 125c197399bSmglocker void udl_cmd_insert_int_4(struct udl_softc *, uint32_t); 126c197399bSmglocker void udl_cmd_insert_buf(struct udl_softc *, uint8_t *, uint32_t); 1272fa8dc63Smglocker int udl_cmd_insert_buf_comp(struct udl_softc *, uint8_t *, 1282fa8dc63Smglocker uint32_t); 1292fa8dc63Smglocker int udl_cmd_insert_head_comp(struct udl_softc *, uint32_t); 130fc15257dSmglocker int udl_cmd_insert_check(struct udl_softc *, int); 131b1107686Smglocker void udl_cmd_set_xfer_type(struct udl_softc *, int); 1328e027a9aSmglocker void udl_cmd_save_offset(struct udl_softc *); 1338e027a9aSmglocker void udl_cmd_restore_offset(struct udl_softc *); 134c197399bSmglocker void udl_cmd_write_reg_1(struct udl_softc *, uint8_t, uint8_t); 135c197399bSmglocker void udl_cmd_write_reg_3(struct udl_softc *, uint8_t, uint32_t); 136c197399bSmglocker usbd_status udl_cmd_send(struct udl_softc *); 137c197399bSmglocker usbd_status udl_cmd_send_async(struct udl_softc *); 138ab0b1be7Smglocker void udl_cmd_send_async_cb(struct usbd_xfer *, void *, usbd_status); 139c197399bSmglocker 140c197399bSmglocker usbd_status udl_init_chip(struct udl_softc *); 141c197399bSmglocker void udl_init_fb_offsets(struct udl_softc *, uint32_t, uint32_t, 142c197399bSmglocker uint32_t, uint32_t); 1436e641510Smaja usbd_status udl_init_resolution(struct udl_softc *); 144082da39dSmglocker usbd_status udl_clear_screen(struct udl_softc *); 1456e641510Smaja void udl_select_mode(struct udl_softc *); 146fc15257dSmglocker int udl_fb_buf_write(struct udl_softc *, uint8_t *, uint32_t, 1474be1f5e5Smglocker uint32_t, uint16_t); 14823e0be93Smglocker int udl_fb_block_write(struct udl_softc *, uint16_t, uint32_t, 149c197399bSmglocker uint32_t, uint32_t, uint32_t); 15023e0be93Smglocker int udl_fb_line_write(struct udl_softc *, uint16_t, uint32_t, 15123e0be93Smglocker uint32_t, uint32_t); 15223e0be93Smglocker int udl_fb_off_write(struct udl_softc *, uint16_t, uint32_t, 15323e0be93Smglocker uint16_t); 154fc15257dSmglocker int udl_fb_block_copy(struct udl_softc *, uint32_t, uint32_t, 155c197399bSmglocker uint32_t, uint32_t, uint32_t, uint32_t); 15623e0be93Smglocker int udl_fb_line_copy(struct udl_softc *, uint32_t, uint32_t, 1572fa8dc63Smglocker uint32_t, uint32_t, uint32_t); 15823e0be93Smglocker int udl_fb_off_copy(struct udl_softc *, uint32_t, uint32_t, 15923e0be93Smglocker uint16_t); 160fc15257dSmglocker int udl_fb_buf_write_comp(struct udl_softc *, uint8_t *, uint32_t, 1612fa8dc63Smglocker uint32_t, uint16_t); 16223e0be93Smglocker int udl_fb_block_write_comp(struct udl_softc *, uint16_t, uint32_t, 1632fa8dc63Smglocker uint32_t, uint32_t, uint32_t); 16423e0be93Smglocker int udl_fb_line_write_comp(struct udl_softc *, uint16_t, uint32_t, 16523e0be93Smglocker uint32_t, uint32_t); 16623e0be93Smglocker int udl_fb_off_write_comp(struct udl_softc *, uint16_t, uint32_t, 16723e0be93Smglocker uint16_t); 168fc15257dSmglocker int udl_fb_block_copy_comp(struct udl_softc *, uint32_t, uint32_t, 1692fa8dc63Smglocker uint32_t, uint32_t, uint32_t, uint32_t); 17023e0be93Smglocker int udl_fb_line_copy_comp(struct udl_softc *, uint32_t, uint32_t, 17123e0be93Smglocker uint32_t, uint32_t, uint32_t); 17223e0be93Smglocker int udl_fb_off_copy_comp(struct udl_softc *, uint32_t, uint32_t, 17323e0be93Smglocker uint16_t); 174c197399bSmglocker #ifdef UDL_DEBUG 175c197399bSmglocker void udl_hexdump(void *, int, int); 176c197399bSmglocker usbd_status udl_init_test(struct udl_softc *); 177c197399bSmglocker #endif 178c197399bSmglocker 179c197399bSmglocker /* 180c197399bSmglocker * Driver glue. 181c197399bSmglocker */ 182c197399bSmglocker struct cfdriver udl_cd = { 183c197399bSmglocker NULL, "udl", DV_DULL 184c197399bSmglocker }; 185c197399bSmglocker 186c197399bSmglocker const struct cfattach udl_ca = { 187c197399bSmglocker sizeof(struct udl_softc), 188c197399bSmglocker udl_match, 189c197399bSmglocker udl_attach, 190c197399bSmglocker udl_detach, 191c197399bSmglocker udl_activate 192c197399bSmglocker }; 193c197399bSmglocker 194c197399bSmglocker /* 195c197399bSmglocker * wsdisplay glue. 196c197399bSmglocker */ 197c197399bSmglocker struct wsscreen_descr udl_stdscreen = { 198c197399bSmglocker "std", /* name */ 199c197399bSmglocker 0, 0, /* ncols, nrows */ 200c197399bSmglocker NULL, /* textops */ 201c197399bSmglocker 0, 0, /* fontwidth, fontheight */ 202c197399bSmglocker WSSCREEN_WSCOLORS /* capabilities */ 203c197399bSmglocker }; 204c197399bSmglocker 205c197399bSmglocker const struct wsscreen_descr *udl_scrlist[] = { 206c197399bSmglocker &udl_stdscreen 207c197399bSmglocker }; 208c197399bSmglocker 209c197399bSmglocker struct wsscreen_list udl_screenlist = { 210c197399bSmglocker sizeof(udl_scrlist) / sizeof(struct wsscreen_descr *), udl_scrlist 211c197399bSmglocker }; 212c197399bSmglocker 213c197399bSmglocker struct wsdisplay_accessops udl_accessops = { 21487eec248Smiod .ioctl = udl_ioctl, 21587eec248Smiod .mmap = udl_mmap, 21687eec248Smiod .alloc_screen = udl_alloc_screen, 21787eec248Smiod .free_screen = udl_free_screen, 21887eec248Smiod .show_screen = udl_show_screen, 21983275742Smiod .load_font = udl_load_font, 22083275742Smiod .list_font = udl_list_font, 22187eec248Smiod .burn_screen = udl_burner 222c197399bSmglocker }; 223c197399bSmglocker 224c197399bSmglocker /* 225c197399bSmglocker * Matching devices. 226c197399bSmglocker */ 2276e641510Smaja struct udl_type { 2286e641510Smaja struct usb_devno udl_dev; 22953fd709fSmglocker uint16_t udl_chip; 230c197399bSmglocker }; 231c197399bSmglocker 2326e641510Smaja static const struct udl_type udl_devs[] = { 233a5a22e49Smaja { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_GUC2020 }, DL160 }, 2346e641510Smaja { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LD220 }, DL165 }, 235*c3de6240Smiod { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LD190 }, DLUNK }, 236*c3de6240Smiod { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_U70 }, DLUNK }, 237*c3de6240Smiod { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_TOSHIBA }, DLUNK }, 238*c3de6240Smiod { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_POLARIS2 }, DLUNK }, 2396e641510Smaja { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_VCUD60 }, DL160 }, 240*c3de6240Smiod { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_CONV }, DL160 }, 2416e641510Smaja { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_DLDVI }, DL160 }, 242*c3de6240Smiod { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_USBRGB }, DLUNK }, 243*c3de6240Smiod { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LCDUSB7X }, DLUNK }, 244*c3de6240Smiod { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LCDUSB10X }, 245*c3de6240Smiod DLUNK }, 2466e641510Smaja { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_VGA10 }, DL120 }, 2476e641510Smaja { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_WSDVI }, DLUNK }, 2486e641510Smaja { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_EC008 }, DL160 }, 249*c3de6240Smiod { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_FYDVI2 }, DLUNK }, 250*c3de6240Smiod { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_GXDVIU2 }, DLUNK }, 251*c3de6240Smiod { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LCD4300U }, DL120 }, 252*c3de6240Smiod { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LCD8000U }, DL120 }, 2536e641510Smaja { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_HPDOCK }, DL160 }, 254a5a22e49Smaja { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_NL571 }, DL160 }, 2556e641510Smaja { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_M01061 }, DL195 }, 256a5a22e49Smaja { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_NBDOCK }, DL165 }, 257*c3de6240Smiod { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_GXDVIU2B }, DLUNK }, 258825f6ef7Smaja { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_SWDVI }, DLUNK }, 259712154e1Sclaudio { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LUM70 }, DL125 }, 260*c3de6240Smiod { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LCD8000UD_DVI }, 261*c3de6240Smiod DLUNK }, 262*c3de6240Smiod { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LDEWX015U }, 263*c3de6240Smiod DLUNK }, 264*c3de6240Smiod { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_KC002N }, DLUNK }, 265*c3de6240Smiod { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_MIMO }, DLUNK }, 266*c3de6240Smiod { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_PLUGABLE }, DLUNK }, 2671f0c4d66Smiod { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LT1421 }, DLUNK }, 268*c3de6240Smiod { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_SD_U2VDH }, DLUNK }, 269*c3de6240Smiod { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_UM7X0 }, DL120 }, 270*c3de6240Smiod { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_FYDVI }, DLUNK } 2716e641510Smaja }; 2726e641510Smaja #define udl_lookup(v, p) ((struct udl_type *)usb_lookup(udl_devs, v, p)) 2736e641510Smaja 274c197399bSmglocker int 275c197399bSmglocker udl_match(struct device *parent, void *match, void *aux) 276c197399bSmglocker { 277c197399bSmglocker struct usb_attach_arg *uaa = aux; 278c197399bSmglocker 279f4b7d08eSmpi if (uaa->iface == NULL || uaa->configno != 1) 280c197399bSmglocker return (UMATCH_NONE); 281c197399bSmglocker 2826e641510Smaja if (udl_lookup(uaa->vendor, uaa->product) != NULL) 283c197399bSmglocker return (UMATCH_VENDOR_PRODUCT); 284c197399bSmglocker 285c197399bSmglocker return (UMATCH_NONE); 286c197399bSmglocker } 287c197399bSmglocker 288c197399bSmglocker void 289c197399bSmglocker udl_attach(struct device *parent, struct device *self, void *aux) 290c197399bSmglocker { 291c197399bSmglocker struct udl_softc *sc = (struct udl_softc *)self; 292c197399bSmglocker struct usb_attach_arg *uaa = aux; 293c197399bSmglocker struct wsemuldisplaydev_attach_args aa; 294c197399bSmglocker usbd_status error; 29553fd709fSmglocker int err, i; 296c197399bSmglocker 297c197399bSmglocker sc->sc_udev = uaa->device; 2986e641510Smaja sc->sc_chip = udl_lookup(uaa->vendor, uaa->product)->udl_chip; 2996e641510Smaja sc->sc_width = 0; 3006e641510Smaja sc->sc_height = 0; 3016e641510Smaja sc->sc_depth = 16; 3026e641510Smaja sc->sc_cur_mode = MAX_DL_MODES; 3036e641510Smaja 3046e641510Smaja /* 3056e641510Smaja * Override chip if requested. 3066e641510Smaja */ 3076e641510Smaja if ((sc->sc_dev.dv_cfdata->cf_flags & 0xff00) > 0) { 3086e641510Smaja i = ((sc->sc_dev.dv_cfdata->cf_flags & 0xff00) >> 8) - 1; 3096e641510Smaja if (i <= DLMAX) { 3106e641510Smaja sc->sc_chip = i; 3116e641510Smaja printf("%s: %s: cf_flags (0x%04x) forced chip to %d\n", 3126e641510Smaja DN(sc), FUNC, 3136e641510Smaja sc->sc_dev.dv_cfdata->cf_flags, i); 3146e641510Smaja } 3156e641510Smaja } 3166e641510Smaja 3176e641510Smaja /* 3186e641510Smaja * The product might have more than one chip 3196e641510Smaja */ 3206e641510Smaja if (sc->sc_chip == DLUNK) 3216e641510Smaja if (udl_select_chip(sc)) 3226e641510Smaja return; 323c197399bSmglocker 324c197399bSmglocker 325c197399bSmglocker /* 326c197399bSmglocker * Create device handle to interface descriptor. 327c197399bSmglocker */ 328c197399bSmglocker error = usbd_device2interface_handle(sc->sc_udev, 0, &sc->sc_iface); 329c197399bSmglocker if (error != USBD_NORMAL_COMPLETION) 330c197399bSmglocker return; 331c197399bSmglocker 332c197399bSmglocker /* 333c197399bSmglocker * Allocate bulk command xfer. 334c197399bSmglocker */ 335c197399bSmglocker error = udl_cmd_alloc_xfer(sc); 336c197399bSmglocker if (error != USBD_NORMAL_COMPLETION) 337c197399bSmglocker return; 338c197399bSmglocker 339c197399bSmglocker /* 340c197399bSmglocker * Allocate command buffer. 341c197399bSmglocker */ 342c197399bSmglocker err = udl_cmd_alloc_buf(sc); 343c197399bSmglocker if (err != 0) 344c197399bSmglocker return; 345c197399bSmglocker 346c197399bSmglocker /* 347c197399bSmglocker * Open bulk TX pipe. 348c197399bSmglocker */ 349c197399bSmglocker error = usbd_open_pipe(sc->sc_iface, 0x01, USBD_EXCLUSIVE_USE, 350c197399bSmglocker &sc->sc_tx_pipeh); 351c197399bSmglocker if (error != USBD_NORMAL_COMPLETION) 352c197399bSmglocker return; 353c197399bSmglocker 354c197399bSmglocker /* 355fc15257dSmglocker * Device initialization is done per synchronous xfers. 356fc15257dSmglocker */ 357b1107686Smglocker udl_cmd_set_xfer_type(sc, UDL_CMD_XFER_SYNC); 358fc15257dSmglocker 359fc15257dSmglocker /* 360c197399bSmglocker * Initialize chip. 361c197399bSmglocker */ 362c197399bSmglocker error = udl_init_chip(sc); 363c197399bSmglocker if (error != USBD_NORMAL_COMPLETION) 364c197399bSmglocker return; 365c197399bSmglocker 366c197399bSmglocker /* 3676e641510Smaja * Select edid mode. 368c197399bSmglocker */ 3696e641510Smaja udl_select_mode(sc); 370c197399bSmglocker 3716e641510Smaja /* 3726e641510Smaja * Override mode if requested. 3736e641510Smaja */ 3746e641510Smaja if ((sc->sc_dev.dv_cfdata->cf_flags & 0xff) > 0) { 37553fd709fSmglocker i = (sc->sc_dev.dv_cfdata->cf_flags & 0xff) - 1; 3766e641510Smaja 3776e641510Smaja if (i < MAX_DL_MODES) { 3786e641510Smaja if (udl_modes[i].chip <= sc->sc_chip) { 3796e641510Smaja sc->sc_width = udl_modes[i].hdisplay; 3806e641510Smaja sc->sc_height = udl_modes[i].vdisplay; 38153fd709fSmglocker printf("%s: %s: cf_flags (0x%04x) ", 3826e641510Smaja DN(sc), FUNC, 38353fd709fSmglocker sc->sc_dev.dv_cfdata->cf_flags); 38453fd709fSmglocker printf("forced mode to %d\n", i); 3856e641510Smaja sc->sc_cur_mode = i; 3866e641510Smaja } 3876e641510Smaja } 3886e641510Smaja } 3896e641510Smaja 3906e641510Smaja error = udl_init_resolution(sc); 391c197399bSmglocker if (error != USBD_NORMAL_COMPLETION) 392c197399bSmglocker return; 393c197399bSmglocker 394c197399bSmglocker /* 395c197399bSmglocker * Attach wsdisplay. 396c197399bSmglocker */ 397c197399bSmglocker aa.console = 0; 398c197399bSmglocker aa.scrdata = &udl_screenlist; 399c197399bSmglocker aa.accessops = &udl_accessops; 400c197399bSmglocker aa.accesscookie = sc; 401c197399bSmglocker aa.defaultscreens = 0; 402c197399bSmglocker 403c197399bSmglocker sc->sc_wsdisplay = config_found(self, &aa, wsemuldisplaydevprint); 404c197399bSmglocker 4052fa8dc63Smglocker /* 4062fa8dc63Smglocker * Load Huffman table. 4072fa8dc63Smglocker */ 408ef89f9e6Smpi config_mountroot(self, udl_attach_hook); 4092fa8dc63Smglocker } 4102fa8dc63Smglocker 4112fa8dc63Smglocker void 412ef89f9e6Smpi udl_attach_hook(struct device *self) 4132fa8dc63Smglocker { 414ef89f9e6Smpi struct udl_softc *sc = (struct udl_softc *)self; 4152fa8dc63Smglocker 4162fa8dc63Smglocker if (udl_load_huffman(sc) != 0) { 4172fa8dc63Smglocker /* compression not possible */ 4182fa8dc63Smglocker printf("%s: run in uncompressed mode\n", DN(sc)); 4192fa8dc63Smglocker sc->udl_fb_buf_write = udl_fb_buf_write; 4209f2543cfSmglocker sc->udl_fb_block_write = udl_fb_block_write; 4219f2543cfSmglocker sc->udl_fb_line_write = udl_fb_line_write; 4229f2543cfSmglocker sc->udl_fb_off_write = udl_fb_off_write; 4232fa8dc63Smglocker sc->udl_fb_block_copy = udl_fb_block_copy; 4249f2543cfSmglocker sc->udl_fb_line_copy = udl_fb_line_copy; 4259f2543cfSmglocker sc->udl_fb_off_copy = udl_fb_off_copy; 4262fa8dc63Smglocker } else { 4272fa8dc63Smglocker /* compression possible */ 4282fa8dc63Smglocker sc->udl_fb_buf_write = udl_fb_buf_write_comp; 4299f2543cfSmglocker sc->udl_fb_block_write = udl_fb_block_write_comp; 4309f2543cfSmglocker sc->udl_fb_line_write = udl_fb_line_write_comp; 4319f2543cfSmglocker sc->udl_fb_off_write = udl_fb_off_write_comp; 4322fa8dc63Smglocker sc->udl_fb_block_copy = udl_fb_block_copy_comp; 4339f2543cfSmglocker sc->udl_fb_line_copy = udl_fb_line_copy_comp; 4349f2543cfSmglocker sc->udl_fb_off_copy = udl_fb_off_copy_comp; 4352fa8dc63Smglocker } 4362fa8dc63Smglocker #ifdef UDL_DEBUG 437ab5cedacSmglocker if (udl_debug >= 4) 4382fa8dc63Smglocker udl_init_test(sc); 4392fa8dc63Smglocker #endif 440fc15257dSmglocker /* 441fc15257dSmglocker * From this point on we do asynchronous xfers. 442fc15257dSmglocker */ 443b1107686Smglocker udl_cmd_set_xfer_type(sc, UDL_CMD_XFER_ASYNC); 444082da39dSmglocker 445082da39dSmglocker /* 446082da39dSmglocker * Set initial wsdisplay emulation mode. 447082da39dSmglocker */ 448082da39dSmglocker sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 449c197399bSmglocker } 450c197399bSmglocker 451c197399bSmglocker int 452c197399bSmglocker udl_detach(struct device *self, int flags) 453c197399bSmglocker { 454c197399bSmglocker struct udl_softc *sc = (struct udl_softc *)self; 455c197399bSmglocker 456c197399bSmglocker /* 457c197399bSmglocker * Close bulk TX pipe. 458c197399bSmglocker */ 459f88cb03eSmglocker if (sc->sc_tx_pipeh != NULL) 460c197399bSmglocker usbd_close_pipe(sc->sc_tx_pipeh); 461c197399bSmglocker 462c197399bSmglocker /* 463c197399bSmglocker * Free command buffer. 464c197399bSmglocker */ 465c197399bSmglocker udl_cmd_free_buf(sc); 466c197399bSmglocker 467c197399bSmglocker /* 468c197399bSmglocker * Free command xfer. 469c197399bSmglocker */ 470c197399bSmglocker udl_cmd_free_xfer(sc); 471c197399bSmglocker 472c197399bSmglocker /* 4732fa8dc63Smglocker * Free Huffman table. 4742fa8dc63Smglocker */ 4752fa8dc63Smglocker udl_free_huffman(sc); 4762fa8dc63Smglocker 4772fa8dc63Smglocker /* 478fa695a51Smglocker * Free framebuffer memory. 479fa695a51Smglocker */ 480fa695a51Smglocker udl_fbmem_free(sc); 481fa695a51Smglocker 482fa695a51Smglocker /* 483c197399bSmglocker * Detach wsdisplay. 484c197399bSmglocker */ 485c197399bSmglocker if (sc->sc_wsdisplay != NULL) 486c197399bSmglocker config_detach(sc->sc_wsdisplay, DETACH_FORCE); 487c197399bSmglocker 488c197399bSmglocker return (0); 489c197399bSmglocker } 490c197399bSmglocker 491c197399bSmglocker int 492e78728c7Spirofti udl_activate(struct device *self, int act) 493c197399bSmglocker { 494e447d11aSjakemsr struct udl_softc *sc = (struct udl_softc *)self; 49537ecb596Sderaadt int rv; 496e447d11aSjakemsr 497c197399bSmglocker switch (act) { 498c197399bSmglocker case DVACT_DEACTIVATE: 499e447d11aSjakemsr usbd_deactivate(sc->sc_udev); 500c197399bSmglocker break; 501c197399bSmglocker } 50237ecb596Sderaadt rv = config_activate_children(self, act); 50337ecb596Sderaadt return (rv); 504c197399bSmglocker } 505c197399bSmglocker 506c197399bSmglocker /* ---------- */ 507c197399bSmglocker 508c197399bSmglocker int 509c197399bSmglocker udl_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 510c197399bSmglocker { 511c197399bSmglocker struct udl_softc *sc; 512fa695a51Smglocker struct wsdisplay_fbinfo *wdf; 513fa695a51Smglocker struct udl_ioctl_damage *d; 514f4611ff0Smglocker int r, error, mode; 515c197399bSmglocker 516c197399bSmglocker sc = v; 517c197399bSmglocker 51836a555e0Smglocker DPRINTF(1, "%s: %s: ('%c', %zu, %zu)\n", 51936a555e0Smglocker DN(sc), FUNC, (int) IOCGROUP(cmd), cmd & 0xff, IOCPARM_LEN(cmd)); 520c197399bSmglocker 521c197399bSmglocker switch (cmd) { 522c197399bSmglocker case WSDISPLAYIO_GTYPE: 523c197399bSmglocker *(u_int *)data = WSDISPLAY_TYPE_DL; 524c197399bSmglocker break; 525fa695a51Smglocker case WSDISPLAYIO_GINFO: 526fa695a51Smglocker wdf = (struct wsdisplay_fbinfo *)data; 527fa695a51Smglocker wdf->height = sc->sc_height; 528fa695a51Smglocker wdf->width = sc->sc_width; 529fa695a51Smglocker wdf->depth = sc->sc_depth; 53063294167Skettenis wdf->stride = sc->sc_width * (sc->sc_depth / 8); 53163294167Skettenis wdf->offset = 0; 532fa695a51Smglocker wdf->cmsize = 0; /* XXX fill up colormap size */ 533fa695a51Smglocker break; 5345c18bb44Smglocker case WSDISPLAYIO_SMODE: 5355c18bb44Smglocker mode = *(u_int *)data; 5365c18bb44Smglocker if (mode == sc->sc_mode) 5375c18bb44Smglocker break; 5385c18bb44Smglocker switch (mode) { 5395c18bb44Smglocker case WSDISPLAYIO_MODE_EMUL: 540541a4372Smglocker /* clear screen */ 541082da39dSmglocker (void)udl_clear_screen(sc); 5425c18bb44Smglocker break; 5435c18bb44Smglocker case WSDISPLAYIO_MODE_DUMBFB: 5445c18bb44Smglocker /* TODO */ 5455c18bb44Smglocker break; 546082da39dSmglocker default: 547082da39dSmglocker return (EINVAL); 5485c18bb44Smglocker } 5495c18bb44Smglocker sc->sc_mode = mode; 5505c18bb44Smglocker break; 551fa695a51Smglocker case WSDISPLAYIO_LINEBYTES: 552fa695a51Smglocker *(u_int *)data = sc->sc_width * (sc->sc_depth / 8); 553fa695a51Smglocker break; 5545c18bb44Smglocker case WSDISPLAYIO_SVIDEO: 5555c18bb44Smglocker case WSDISPLAYIO_GVIDEO: 5565c18bb44Smglocker /* handled for us by wscons */ 5575c18bb44Smglocker break; 558fa695a51Smglocker case UDLIO_DAMAGE: 559fa695a51Smglocker d = (struct udl_ioctl_damage *)data; 560f4611ff0Smglocker d->status = UDLIO_STATUS_OK; 561fa695a51Smglocker r = udl_damage(sc, sc->sc_fbmem, d->x1, d->x2, d->y1, d->y2); 562fa695a51Smglocker if (r != 0) { 5631394fe5fSmpi error = tsleep_nsec(sc, 0, "udlio", MSEC_TO_NSEC(10)); 564f4611ff0Smglocker if (error) { 56503b640e7Smglocker d->status = UDLIO_STATUS_FAILED; 56603b640e7Smglocker } else { 567f4611ff0Smglocker r = udl_damage(sc, sc->sc_fbmem, d->x1, d->x2, 568f4611ff0Smglocker d->y1, d->y2); 569f4611ff0Smglocker if (r != 0) 570f4611ff0Smglocker d->status = UDLIO_STATUS_FAILED; 571f4611ff0Smglocker } 572fa695a51Smglocker } 573fa695a51Smglocker break; 574c197399bSmglocker default: 575c197399bSmglocker return (-1); 576c197399bSmglocker } 577c197399bSmglocker 578c197399bSmglocker return (0); 579c197399bSmglocker } 580c197399bSmglocker 581c197399bSmglocker paddr_t 582c197399bSmglocker udl_mmap(void *v, off_t off, int prot) 583c197399bSmglocker { 584c197399bSmglocker struct udl_softc *sc; 585fa695a51Smglocker caddr_t p; 586fa695a51Smglocker paddr_t pa; 587c197399bSmglocker 588c197399bSmglocker sc = v; 589c197399bSmglocker 590c197399bSmglocker DPRINTF(1, "%s: %s\n", DN(sc), FUNC); 591c197399bSmglocker 592fa695a51Smglocker /* allocate framebuffer memory */ 593fa695a51Smglocker if (udl_fbmem_alloc(sc) == -1) 594699280b1Smglocker return (-1); 595fa695a51Smglocker 596fa695a51Smglocker /* return memory address to userland process */ 597fa695a51Smglocker p = sc->sc_fbmem + off; 598fa695a51Smglocker if (pmap_extract(pmap_kernel(), (vaddr_t)p, &pa) == FALSE) { 599fa695a51Smglocker printf("udl_mmap: invalid page\n"); 600fa695a51Smglocker udl_fbmem_free(sc); 601fa695a51Smglocker return (-1); 602fa695a51Smglocker } 603fa695a51Smglocker return (pa); 604c197399bSmglocker } 605c197399bSmglocker 606c197399bSmglocker int 607c197399bSmglocker udl_alloc_screen(void *v, const struct wsscreen_descr *type, 608e0c3e559Sjsg void **cookiep, int *curxp, int *curyp, uint32_t *attrp) 609c197399bSmglocker { 610c197399bSmglocker struct udl_softc *sc = v; 611c197399bSmglocker struct wsdisplay_font *font; 612c197399bSmglocker 613c197399bSmglocker DPRINTF(1, "%s: %s\n", DN(sc), FUNC); 614c197399bSmglocker 615c197399bSmglocker if (sc->sc_nscreens > 0) 616c197399bSmglocker return (ENOMEM); 617c197399bSmglocker 618c197399bSmglocker /* 619c197399bSmglocker * Initialize rasops. 620c197399bSmglocker */ 621c197399bSmglocker sc->sc_ri.ri_depth = sc->sc_depth; 622c197399bSmglocker sc->sc_ri.ri_bits = NULL; 623c197399bSmglocker sc->sc_ri.ri_width = sc->sc_width; 624c197399bSmglocker sc->sc_ri.ri_height = sc->sc_height; 625c197399bSmglocker sc->sc_ri.ri_stride = sc->sc_width * sc->sc_height / 8; 626c197399bSmglocker sc->sc_ri.ri_hw = (void *)sc; 627c197399bSmglocker sc->sc_ri.ri_flg = 0; 628c197399bSmglocker 629c197399bSmglocker /* swap B and R at 16 bpp */ 630c197399bSmglocker if (sc->sc_depth == 16) { 631c197399bSmglocker sc->sc_ri.ri_rnum = 5; 632c197399bSmglocker sc->sc_ri.ri_rpos = 11; 633c197399bSmglocker sc->sc_ri.ri_gnum = 6; 634c197399bSmglocker sc->sc_ri.ri_gpos = 5; 635c197399bSmglocker sc->sc_ri.ri_bnum = 5; 636c197399bSmglocker sc->sc_ri.ri_bpos = 0; 637c197399bSmglocker } 638c197399bSmglocker 6396e641510Smaja rasops_init(&sc->sc_ri, 100, 200); 640c197399bSmglocker 641c197399bSmglocker sc->sc_ri.ri_ops.copycols = udl_copycols; 642c197399bSmglocker sc->sc_ri.ri_ops.copyrows = udl_copyrows; 643c197399bSmglocker sc->sc_ri.ri_ops.erasecols = udl_erasecols; 644c197399bSmglocker sc->sc_ri.ri_ops.eraserows = udl_eraserows; 645c197399bSmglocker sc->sc_ri.ri_ops.putchar = udl_putchar; 646c197399bSmglocker sc->sc_ri.ri_do_cursor = udl_do_cursor; 647c197399bSmglocker 648fc223b23Sjsg sc->sc_ri.ri_ops.pack_attr(&sc->sc_ri, 0, 0, 0, attrp); 649c197399bSmglocker 650c197399bSmglocker udl_stdscreen.nrows = sc->sc_ri.ri_rows; 651c197399bSmglocker udl_stdscreen.ncols = sc->sc_ri.ri_cols; 652c197399bSmglocker udl_stdscreen.textops = &sc->sc_ri.ri_ops; 653c197399bSmglocker udl_stdscreen.fontwidth = sc->sc_ri.ri_font->fontwidth; 654c197399bSmglocker udl_stdscreen.fontheight = sc->sc_ri.ri_font->fontheight; 655c197399bSmglocker udl_stdscreen.capabilities = sc->sc_ri.ri_caps; 656c197399bSmglocker 657c197399bSmglocker *cookiep = &sc->sc_ri; 658c197399bSmglocker *curxp = 0; 659c197399bSmglocker *curyp = 0; 660c197399bSmglocker 661c91d565bSmglocker /* allocate character backing store */ 6620f0d0f95Sdoug sc->sc_cbs = mallocarray(sc->sc_ri.ri_rows, sc->sc_ri.ri_cols * 6638985a220Smglocker sizeof(*sc->sc_cbs), M_USBDEV, M_NOWAIT|M_ZERO); 664c91d565bSmglocker if (sc->sc_cbs == NULL) { 665c91d565bSmglocker printf("%s: can't allocate mem for character backing store!\n", 666c91d565bSmglocker DN(sc)); 667c91d565bSmglocker return (ENOMEM); 668c91d565bSmglocker } 669234dfda1Sderaadt sc->sc_cbslen = sc->sc_ri.ri_rows * sc->sc_ri.ri_cols * 670234dfda1Sderaadt sizeof(*sc->sc_cbs); 671c91d565bSmglocker 672c197399bSmglocker sc->sc_nscreens++; 673c197399bSmglocker 674c197399bSmglocker font = sc->sc_ri.ri_font; 675c197399bSmglocker DPRINTF(1, "%s: %s: using font %s (%dx%d)\n", 676c197399bSmglocker DN(sc), FUNC, font->name, sc->sc_ri.ri_cols, sc->sc_ri.ri_rows); 677c197399bSmglocker 678c197399bSmglocker return (0); 679c197399bSmglocker } 680c197399bSmglocker 681c197399bSmglocker void 682c197399bSmglocker udl_free_screen(void *v, void *cookie) 683c197399bSmglocker { 684c197399bSmglocker struct udl_softc *sc; 685c197399bSmglocker 686c197399bSmglocker sc = v; 687c197399bSmglocker 688c197399bSmglocker DPRINTF(1, "%s: %s\n", DN(sc), FUNC); 6896e641510Smaja 690c91d565bSmglocker /* free character backing store */ 691c91d565bSmglocker if (sc->sc_cbs != NULL) 6928985a220Smglocker free(sc->sc_cbs, M_USBDEV, sc->sc_cbslen); 693c91d565bSmglocker 6946e641510Smaja sc->sc_nscreens--; 695c197399bSmglocker } 696c197399bSmglocker 697c197399bSmglocker int 698c197399bSmglocker udl_show_screen(void *v, void *cookie, int waitok, 699c197399bSmglocker void (*cb)(void *, int, int), void *cbarg) 700c197399bSmglocker { 701c197399bSmglocker struct udl_softc *sc; 702c197399bSmglocker 703c197399bSmglocker sc = v; 704c197399bSmglocker 705c197399bSmglocker DPRINTF(1, "%s: %s\n", DN(sc), FUNC); 706c197399bSmglocker 707c197399bSmglocker return (0); 708c197399bSmglocker } 709c197399bSmglocker 71083275742Smiod int 71183275742Smiod udl_load_font(void *v, void *emulcookie, struct wsdisplay_font *font) 71283275742Smiod { 71383275742Smiod struct udl_softc *sc = v; 71483275742Smiod struct rasops_info *ri = &sc->sc_ri; 71583275742Smiod 71683275742Smiod return rasops_load_font(ri, emulcookie, font); 71783275742Smiod } 71883275742Smiod 71983275742Smiod int 72083275742Smiod udl_list_font(void *v, struct wsdisplay_font *font) 72183275742Smiod { 72283275742Smiod struct udl_softc *sc = v; 72383275742Smiod struct rasops_info *ri = &sc->sc_ri; 72483275742Smiod 72583275742Smiod return rasops_list_font(ri, font); 72683275742Smiod } 72783275742Smiod 728c197399bSmglocker void 729c197399bSmglocker udl_burner(void *v, u_int on, u_int flags) 730c197399bSmglocker { 731c197399bSmglocker struct udl_softc *sc; 732c197399bSmglocker 733c197399bSmglocker sc = v; 734c197399bSmglocker 73592fdbf9fSmglocker DPRINTF(1, "%s: %s: screen %s\n", DN(sc), FUNC, on ? "ON" : "OFF"); 736c197399bSmglocker 737c197399bSmglocker if (on) 73892fdbf9fSmglocker udl_cmd_write_reg_1(sc, UDL_REG_SCREEN, UDL_REG_SCREEN_ON); 739c197399bSmglocker else 74092fdbf9fSmglocker udl_cmd_write_reg_1(sc, UDL_REG_SCREEN, UDL_REG_SCREEN_OFF); 741c197399bSmglocker 742c197399bSmglocker udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0xff); 743c197399bSmglocker 74492fdbf9fSmglocker (void)udl_cmd_send_async(sc); 745c197399bSmglocker } 746c197399bSmglocker 747c197399bSmglocker /* ---------- */ 748c197399bSmglocker 749072953e3Smiod int 750c197399bSmglocker udl_copycols(void *cookie, int row, int src, int dst, int num) 751c197399bSmglocker { 752c197399bSmglocker struct rasops_info *ri = cookie; 753c197399bSmglocker struct udl_softc *sc; 754fc15257dSmglocker int sx, sy, dx, dy, cx, cy, r; 7558c7540bbSmglocker usbd_status error; 756c197399bSmglocker 757c197399bSmglocker sc = ri->ri_hw; 758c197399bSmglocker 759c197399bSmglocker DPRINTF(2, "%s: %s: row=%d, src=%d, dst=%d, num=%d\n", 760c197399bSmglocker DN(sc), FUNC, row, src, dst, num); 761c197399bSmglocker 7628e027a9aSmglocker udl_cmd_save_offset(sc); 7638c7540bbSmglocker 764c197399bSmglocker sx = src * ri->ri_font->fontwidth; 765c197399bSmglocker sy = row * ri->ri_font->fontheight; 766c197399bSmglocker dx = dst * ri->ri_font->fontwidth; 767c197399bSmglocker dy = row * ri->ri_font->fontheight; 768c197399bSmglocker cx = num * ri->ri_font->fontwidth; 769c197399bSmglocker cy = ri->ri_font->fontheight; 770c197399bSmglocker 77137b91793Smglocker /* copy row block to off-screen first to fix overlay-copy problem */ 772fc15257dSmglocker r = (sc->udl_fb_block_copy) 773fc15257dSmglocker (sc, sx, sy, 0, sc->sc_ri.ri_emuheight, cx, cy); 774fc15257dSmglocker if (r != 0) 775fc15257dSmglocker goto fail; 77637b91793Smglocker 77737b91793Smglocker /* copy row block back from off-screen now */ 778fc15257dSmglocker r = (sc->udl_fb_block_copy) 779fc15257dSmglocker (sc, 0, sc->sc_ri.ri_emuheight, dx, dy, cx, cy); 780fc15257dSmglocker if (r != 0) 781fc15257dSmglocker goto fail; 782c197399bSmglocker 7838c7540bbSmglocker error = udl_cmd_send_async(sc); 7848c7540bbSmglocker if (error != USBD_NORMAL_COMPLETION) { 785fc15257dSmglocker fail: 7868e027a9aSmglocker udl_cmd_restore_offset(sc); 7878c7540bbSmglocker return (EAGAIN); 7888c7540bbSmglocker } 789072953e3Smiod 790c91d565bSmglocker /* update character backing store */ 791c91d565bSmglocker bcopy(sc->sc_cbs + ((row * sc->sc_ri.ri_cols) + src), 792c91d565bSmglocker sc->sc_cbs + ((row * sc->sc_ri.ri_cols) + dst), 793c91d565bSmglocker num * sizeof(*sc->sc_cbs)); 794c91d565bSmglocker 7958c7540bbSmglocker return (0); 796c197399bSmglocker } 797c197399bSmglocker 798072953e3Smiod int 799c197399bSmglocker udl_copyrows(void *cookie, int src, int dst, int num) 800c197399bSmglocker { 801c197399bSmglocker struct rasops_info *ri = cookie; 802c197399bSmglocker struct udl_softc *sc; 803fc15257dSmglocker int sy, dy, cx, cy, r; 8048c7540bbSmglocker usbd_status error; 805c197399bSmglocker 806c197399bSmglocker sc = ri->ri_hw; 807c197399bSmglocker 808c197399bSmglocker DPRINTF(2, "%s: %s: src=%d, dst=%d, num=%d\n", 809c197399bSmglocker DN(sc), FUNC, src, dst, num); 810c197399bSmglocker 8118e027a9aSmglocker udl_cmd_save_offset(sc); 8128c7540bbSmglocker 813c197399bSmglocker sy = src * sc->sc_ri.ri_font->fontheight; 814c197399bSmglocker dy = dst * sc->sc_ri.ri_font->fontheight; 815c197399bSmglocker cx = sc->sc_ri.ri_emuwidth; 816c197399bSmglocker cy = num * sc->sc_ri.ri_font->fontheight; 817c197399bSmglocker 818c197399bSmglocker /* copy row block to off-screen first to fix overlay-copy problem */ 819fc15257dSmglocker r = (sc->udl_fb_block_copy) 820fc15257dSmglocker (sc, 0, sy, 0, sc->sc_ri.ri_emuheight, cx, cy); 821fc15257dSmglocker if (r != 0) 822fc15257dSmglocker goto fail; 823c197399bSmglocker 824c197399bSmglocker /* copy row block back from off-screen now */ 825fc15257dSmglocker r = (sc->udl_fb_block_copy) 826fc15257dSmglocker (sc, 0, sc->sc_ri.ri_emuheight, 0, dy, cx, cy); 827fc15257dSmglocker if (r != 0) 828fc15257dSmglocker goto fail; 829c197399bSmglocker 8308c7540bbSmglocker error = udl_cmd_send_async(sc); 8318c7540bbSmglocker if (error != USBD_NORMAL_COMPLETION) { 832fc15257dSmglocker fail: 8338e027a9aSmglocker udl_cmd_restore_offset(sc); 8348c7540bbSmglocker return (EAGAIN); 8358c7540bbSmglocker } 836072953e3Smiod 837c91d565bSmglocker /* update character backing store */ 838c91d565bSmglocker bcopy(sc->sc_cbs + (src * sc->sc_ri.ri_cols), 839c91d565bSmglocker sc->sc_cbs + (dst * sc->sc_ri.ri_cols), 840c91d565bSmglocker (num * sc->sc_ri.ri_cols) * sizeof(*sc->sc_cbs)); 841c91d565bSmglocker 8428c7540bbSmglocker return (0); 843c197399bSmglocker } 844c197399bSmglocker 845072953e3Smiod int 846e0c3e559Sjsg udl_erasecols(void *cookie, int row, int col, int num, uint32_t attr) 847c197399bSmglocker { 848c197399bSmglocker struct rasops_info *ri = cookie; 849c197399bSmglocker struct udl_softc *sc = ri->ri_hw; 85001d017baSmglocker uint16_t bgc; 851c197399bSmglocker int fg, bg; 852fc15257dSmglocker int x, y, cx, cy, r; 8538c7540bbSmglocker usbd_status error; 854c197399bSmglocker 855c197399bSmglocker sc = ri->ri_hw; 856c197399bSmglocker 857c197399bSmglocker DPRINTF(2, "%s: %s: row=%d, col=%d, num=%d\n", 858c197399bSmglocker DN(sc), FUNC, row, col, num); 859c197399bSmglocker 8608e027a9aSmglocker udl_cmd_save_offset(sc); 8618c7540bbSmglocker 862c197399bSmglocker sc->sc_ri.ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); 86301d017baSmglocker bgc = (uint16_t)sc->sc_ri.ri_devcmap[bg]; 864c197399bSmglocker 865c197399bSmglocker x = col * sc->sc_ri.ri_font->fontwidth; 866c197399bSmglocker y = row * sc->sc_ri.ri_font->fontheight; 867c197399bSmglocker cx = num * sc->sc_ri.ri_font->fontwidth; 868c197399bSmglocker cy = sc->sc_ri.ri_font->fontheight; 869c197399bSmglocker 870c6a68e4cSmglocker r = (sc->udl_fb_block_write)(sc, bgc, x, y, cx, cy); 871fc15257dSmglocker if (r != 0) 872fc15257dSmglocker goto fail; 873c197399bSmglocker 8748c7540bbSmglocker error = udl_cmd_send_async(sc); 8758c7540bbSmglocker if (error != USBD_NORMAL_COMPLETION) { 876fc15257dSmglocker fail: 8778e027a9aSmglocker udl_cmd_restore_offset(sc); 8788c7540bbSmglocker return (EAGAIN); 8798c7540bbSmglocker } 880072953e3Smiod 881c91d565bSmglocker /* update character backing store */ 882c91d565bSmglocker bzero(sc->sc_cbs + ((row * sc->sc_ri.ri_cols) + col), 883c91d565bSmglocker num * sizeof(*sc->sc_cbs)); 884c91d565bSmglocker 8858c7540bbSmglocker return (0); 886c197399bSmglocker } 887c197399bSmglocker 888072953e3Smiod int 889e0c3e559Sjsg udl_eraserows(void *cookie, int row, int num, uint32_t attr) 890c197399bSmglocker { 891c197399bSmglocker struct rasops_info *ri = cookie; 892c197399bSmglocker struct udl_softc *sc; 89301d017baSmglocker uint16_t bgc; 89401d017baSmglocker int fg, bg; 895fc15257dSmglocker int x, y, cx, cy, r; 8968c7540bbSmglocker usbd_status error; 897c197399bSmglocker 898c197399bSmglocker sc = ri->ri_hw; 899c197399bSmglocker 900c197399bSmglocker DPRINTF(2, "%s: %s: row=%d, num=%d\n", DN(sc), FUNC, row, num); 901c197399bSmglocker 9028e027a9aSmglocker udl_cmd_save_offset(sc); 9038c7540bbSmglocker 90401d017baSmglocker sc->sc_ri.ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); 90501d017baSmglocker bgc = (uint16_t)sc->sc_ri.ri_devcmap[bg]; 90601d017baSmglocker 907c197399bSmglocker x = 0; 908c197399bSmglocker y = row * sc->sc_ri.ri_font->fontheight; 909c197399bSmglocker cx = sc->sc_ri.ri_emuwidth; 910c197399bSmglocker cy = num * sc->sc_ri.ri_font->fontheight; 911c197399bSmglocker 912c6a68e4cSmglocker r = (sc->udl_fb_block_write)(sc, bgc, x, y, cx, cy); 913fc15257dSmglocker if (r != 0) 914fc15257dSmglocker goto fail; 915c197399bSmglocker 9168c7540bbSmglocker error = udl_cmd_send_async(sc); 9178c7540bbSmglocker if (error != USBD_NORMAL_COMPLETION) { 918fc15257dSmglocker fail: 9198e027a9aSmglocker udl_cmd_restore_offset(sc); 9208c7540bbSmglocker return (EAGAIN); 9218c7540bbSmglocker } 922072953e3Smiod 923c91d565bSmglocker /* update character backing store */ 924c91d565bSmglocker bzero(sc->sc_cbs + (row * sc->sc_ri.ri_cols), 925c91d565bSmglocker (num * sc->sc_ri.ri_cols) * sizeof(*sc->sc_cbs)); 926c91d565bSmglocker 9278c7540bbSmglocker return (0); 928c197399bSmglocker } 929c197399bSmglocker 930072953e3Smiod int 931e0c3e559Sjsg udl_putchar(void *cookie, int row, int col, u_int uc, uint32_t attr) 932c197399bSmglocker { 933c197399bSmglocker struct rasops_info *ri = cookie; 934c197399bSmglocker struct udl_softc *sc = ri->ri_hw; 935fc15257dSmglocker int r; 936c197399bSmglocker uint16_t fgc, bgc; 937c197399bSmglocker uint32_t x, y, fg, bg; 938c197399bSmglocker 939ab5cedacSmglocker DPRINTF(4, "%s: %s\n", DN(sc), FUNC); 940c197399bSmglocker 9418e027a9aSmglocker udl_cmd_save_offset(sc); 942fc15257dSmglocker 943c197399bSmglocker sc->sc_ri.ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); 944c197399bSmglocker fgc = (uint16_t)sc->sc_ri.ri_devcmap[fg]; 945c197399bSmglocker bgc = (uint16_t)sc->sc_ri.ri_devcmap[bg]; 946c197399bSmglocker 947c197399bSmglocker x = col * ri->ri_font->fontwidth; 948c197399bSmglocker y = row * ri->ri_font->fontheight; 949c197399bSmglocker 950c197399bSmglocker if (uc == ' ') { 951c197399bSmglocker /* 952c8ebe74cSjasper * Writing a block for the space character instead rendering 953c197399bSmglocker * it from font bits is more slim. 954c197399bSmglocker */ 955fc15257dSmglocker r = (sc->udl_fb_block_write)(sc, bgc, x, y, 956c197399bSmglocker ri->ri_font->fontwidth, ri->ri_font->fontheight); 957fc15257dSmglocker if (r != 0) 958fc15257dSmglocker goto fail; 959c197399bSmglocker } else { 960c197399bSmglocker /* render a character from font bits */ 961fc15257dSmglocker r = udl_draw_char(sc, fgc, bgc, uc, x, y); 962fc15257dSmglocker if (r != 0) 963fc15257dSmglocker goto fail; 964c197399bSmglocker } 965c197399bSmglocker 966c197399bSmglocker /* 967c197399bSmglocker * We don't call udl_cmd_send_async() here, since sending each 968c197399bSmglocker * character by itself gets the performance down bad. Instead the 969c197399bSmglocker * character will be buffered until another rasops function flush 970c197399bSmglocker * the buffer. 971c197399bSmglocker */ 972072953e3Smiod 973c91d565bSmglocker /* update character backing store */ 974c91d565bSmglocker sc->sc_cbs[(row * sc->sc_ri.ri_cols) + col] = uc; 975c91d565bSmglocker 9768c7540bbSmglocker return (0); 977fc15257dSmglocker 978fc15257dSmglocker fail: 9798e027a9aSmglocker udl_cmd_restore_offset(sc); 980fc15257dSmglocker return (EAGAIN); 981c197399bSmglocker } 982c197399bSmglocker 983072953e3Smiod int 984c197399bSmglocker udl_do_cursor(struct rasops_info *ri) 985c197399bSmglocker { 986c197399bSmglocker struct udl_softc *sc = ri->ri_hw; 987c91d565bSmglocker int r, pos; 988c197399bSmglocker uint32_t x, y; 9898c7540bbSmglocker uint8_t save_cursor; 9908c7540bbSmglocker usbd_status error; 991c197399bSmglocker 992c197399bSmglocker DPRINTF(2, "%s: %s: ccol=%d, crow=%d\n", 993c197399bSmglocker DN(sc), FUNC, ri->ri_ccol, ri->ri_crow); 994c197399bSmglocker 9958e027a9aSmglocker udl_cmd_save_offset(sc); 9968c7540bbSmglocker save_cursor = sc->sc_cursor_on; 9978c7540bbSmglocker 998c197399bSmglocker x = ri->ri_ccol * ri->ri_font->fontwidth; 999c197399bSmglocker y = ri->ri_crow * ri->ri_font->fontheight; 1000c197399bSmglocker 1001c197399bSmglocker if (sc->sc_cursor_on == 0) { 1002487911f5Smglocker /* save the last character block to off-screen */ 1003fc15257dSmglocker r = (sc->udl_fb_block_copy)(sc, x, y, 0, sc->sc_ri.ri_emuheight, 1004c197399bSmglocker ri->ri_font->fontwidth, ri->ri_font->fontheight); 1005fc15257dSmglocker if (r != 0) 1006fc15257dSmglocker goto fail; 1007c197399bSmglocker 1008c197399bSmglocker /* draw cursor */ 1009c91d565bSmglocker pos = (ri->ri_crow * sc->sc_ri.ri_cols) + ri->ri_ccol; 1010c91d565bSmglocker if (sc->sc_cbs[pos] == 0 || sc->sc_cbs[pos] == ' ') { 1011fc15257dSmglocker r = (sc->udl_fb_block_write)(sc, 0xffff, x, y, 1012c197399bSmglocker ri->ri_font->fontwidth, ri->ri_font->fontheight); 1013c91d565bSmglocker } else { 1014c91d565bSmglocker r = udl_draw_char(sc, 0x0000, 0xffff, sc->sc_cbs[pos], 1015c91d565bSmglocker x, y); 1016c91d565bSmglocker } 1017fc15257dSmglocker if (r != 0) 1018fc15257dSmglocker goto fail; 1019c197399bSmglocker 1020c197399bSmglocker sc->sc_cursor_on = 1; 1021c197399bSmglocker } else { 1022487911f5Smglocker /* restore the last saved character from off-screen */ 1023fc15257dSmglocker r = (sc->udl_fb_block_copy)(sc, 0, sc->sc_ri.ri_emuheight, x, y, 1024c197399bSmglocker ri->ri_font->fontwidth, ri->ri_font->fontheight); 1025fc15257dSmglocker if (r != 0) 1026fc15257dSmglocker goto fail; 1027c197399bSmglocker 1028c197399bSmglocker sc->sc_cursor_on = 0; 1029c197399bSmglocker } 1030c197399bSmglocker 10318c7540bbSmglocker error = udl_cmd_send_async(sc); 10328c7540bbSmglocker if (error != USBD_NORMAL_COMPLETION) { 1033fc15257dSmglocker fail: 10348e027a9aSmglocker udl_cmd_restore_offset(sc); 10358c7540bbSmglocker sc->sc_cursor_on = save_cursor; 10368c7540bbSmglocker return (EAGAIN); 10378c7540bbSmglocker } 1038072953e3Smiod 10398c7540bbSmglocker return (0); 1040c197399bSmglocker } 1041c197399bSmglocker 104223e0be93Smglocker int 104323e0be93Smglocker udl_draw_char(struct udl_softc *sc, uint16_t fg, uint16_t bg, u_int uc, 104423e0be93Smglocker uint32_t x, uint32_t y) 104523e0be93Smglocker { 104623e0be93Smglocker int i, j, ly, r; 104723e0be93Smglocker uint8_t *fontchar; 104823e0be93Smglocker uint8_t buf[UDL_CMD_MAX_DATA_SIZE]; 104923e0be93Smglocker uint16_t *line, lrgb16, fontbits, luc; 105023e0be93Smglocker struct wsdisplay_font *font = sc->sc_ri.ri_font; 105123e0be93Smglocker 105223e0be93Smglocker fontchar = (uint8_t *)(font->data + (uc - font->firstchar) * 105323e0be93Smglocker sc->sc_ri.ri_fontscale); 105423e0be93Smglocker 105523e0be93Smglocker ly = y; 105623e0be93Smglocker for (i = 0; i < font->fontheight; i++) { 105723e0be93Smglocker if (font->fontwidth > 8) { 105823e0be93Smglocker fontbits = betoh16(*(uint16_t *)fontchar); 105923e0be93Smglocker } else { 106023e0be93Smglocker fontbits = *fontchar; 106123e0be93Smglocker fontbits = fontbits << 8; 106223e0be93Smglocker } 106323e0be93Smglocker line = (uint16_t *)buf; 106423e0be93Smglocker 106523e0be93Smglocker for (j = 15; j > (15 - font->fontwidth); j--) { 106623e0be93Smglocker luc = 1 << j; 106723e0be93Smglocker if (fontbits & luc) 106823e0be93Smglocker lrgb16 = htobe16(fg); 106923e0be93Smglocker else 107023e0be93Smglocker lrgb16 = htobe16(bg); 107123e0be93Smglocker bcopy(&lrgb16, line, 2); 107223e0be93Smglocker line++; 107323e0be93Smglocker } 107423e0be93Smglocker r = (sc->udl_fb_buf_write)(sc, buf, x, ly, font->fontwidth); 107523e0be93Smglocker if (r != 0) 107623e0be93Smglocker return (r); 107723e0be93Smglocker ly++; 107823e0be93Smglocker 107923e0be93Smglocker fontchar += font->stride; 108023e0be93Smglocker } 108123e0be93Smglocker 108223e0be93Smglocker return (0); 108323e0be93Smglocker } 108423e0be93Smglocker 1085fa695a51Smglocker int 1086fa695a51Smglocker udl_damage(struct udl_softc *sc, uint8_t *image, 1087fa695a51Smglocker uint32_t x1, uint32_t x2, uint32_t y1, uint32_t y2) 1088fa695a51Smglocker { 1089fa695a51Smglocker int r; 1090fa695a51Smglocker int x, y, width, height; 109103b640e7Smglocker usbd_status error; 109203b640e7Smglocker 10938e027a9aSmglocker udl_cmd_save_offset(sc); 1094fa695a51Smglocker 1095fa695a51Smglocker x = x1; 1096fa695a51Smglocker y = y1; 1097fa695a51Smglocker width = x2 - x1; 1098fa695a51Smglocker height = y2 - y1; 1099fa695a51Smglocker 1100fa695a51Smglocker r = udl_draw_image(sc, image, x, y, width, height); 1101fa695a51Smglocker if (r != 0) 110203b640e7Smglocker goto fail; 1103fa695a51Smglocker 110403b640e7Smglocker error = udl_cmd_send_async(sc); 110503b640e7Smglocker if (error != USBD_NORMAL_COMPLETION) { 110603b640e7Smglocker fail: 11078e027a9aSmglocker udl_cmd_restore_offset(sc); 110803b640e7Smglocker return (EAGAIN); 110903b640e7Smglocker } 1110fa695a51Smglocker 1111fa695a51Smglocker return (0); 1112fa695a51Smglocker } 1113fa695a51Smglocker 1114fa695a51Smglocker int 1115fa695a51Smglocker udl_draw_image(struct udl_softc *sc, uint8_t *image, 1116fa695a51Smglocker uint32_t x, uint32_t y, uint32_t width, uint32_t height) 1117fa695a51Smglocker { 1118fa695a51Smglocker int i, j, r; 1119fa695a51Smglocker int width_cur, x_cur; 1120fa695a51Smglocker uint8_t buf[UDL_CMD_MAX_DATA_SIZE]; 1121fa695a51Smglocker uint16_t *image16, lrgb16; 1122fa695a51Smglocker uint32_t off, block; 1123fa695a51Smglocker 1124fa695a51Smglocker for (i = 0; i < height; i++) { 1125fa695a51Smglocker off = ((y * sc->sc_width) + x) * 2; 1126fa695a51Smglocker x_cur = x; 1127fa695a51Smglocker width_cur = width; 1128fa695a51Smglocker 1129fa695a51Smglocker while (width_cur) { 1130fa695a51Smglocker if (width_cur > UDL_CMD_MAX_PIXEL_COUNT) 1131fa695a51Smglocker block = UDL_CMD_MAX_PIXEL_COUNT; 1132fa695a51Smglocker else 1133fa695a51Smglocker block = width_cur; 1134fa695a51Smglocker 1135fa695a51Smglocker /* fix RGB ordering */ 1136fa695a51Smglocker image16 = (uint16_t *)(image + off); 1137fa695a51Smglocker for (j = 0; j < (block * 2); j += 2) { 1138fa695a51Smglocker lrgb16 = htobe16(*image16); 1139fa695a51Smglocker bcopy(&lrgb16, buf + j, 2); 1140fa695a51Smglocker image16++; 1141fa695a51Smglocker } 1142fa695a51Smglocker 1143fa695a51Smglocker r = (sc->udl_fb_buf_write)(sc, buf, x_cur, y, block); 1144fa695a51Smglocker if (r != 0) 1145fa695a51Smglocker return (r); 1146fa695a51Smglocker 1147fa695a51Smglocker off += block * 2; 1148fa695a51Smglocker x_cur += block; 1149fa695a51Smglocker width_cur -= block; 1150fa695a51Smglocker } 1151fa695a51Smglocker y++; 1152fa695a51Smglocker } 1153fa695a51Smglocker 1154fa695a51Smglocker return (0); 1155fa695a51Smglocker } 1156fa695a51Smglocker 1157c197399bSmglocker /* ---------- */ 1158c197399bSmglocker 1159c197399bSmglocker usbd_status 1160c197399bSmglocker udl_ctrl_msg(struct udl_softc *sc, uint8_t rt, uint8_t r, 1161c197399bSmglocker uint16_t index, uint16_t value, uint8_t *buf, size_t len) 1162c197399bSmglocker { 1163c197399bSmglocker usb_device_request_t req; 1164c197399bSmglocker usbd_status error; 1165c197399bSmglocker 1166c197399bSmglocker req.bmRequestType = rt; 1167c197399bSmglocker req.bRequest = r; 1168c197399bSmglocker USETW(req.wIndex, index); 1169c197399bSmglocker USETW(req.wValue, value); 1170c197399bSmglocker USETW(req.wLength, len); 1171c197399bSmglocker 1172c197399bSmglocker error = usbd_do_request(sc->sc_udev, &req, buf); 1173c197399bSmglocker if (error != USBD_NORMAL_COMPLETION) { 1174c197399bSmglocker printf("%s: %s: %s!\n", DN(sc), FUNC, usbd_errstr(error)); 1175c197399bSmglocker return (error); 1176c197399bSmglocker } 1177c197399bSmglocker 1178c197399bSmglocker return (USBD_NORMAL_COMPLETION); 1179c197399bSmglocker } 1180c197399bSmglocker 1181c197399bSmglocker usbd_status 1182c197399bSmglocker udl_poll(struct udl_softc *sc, uint32_t *buf) 1183c197399bSmglocker { 1184c197399bSmglocker uint8_t lbuf[4]; 1185c197399bSmglocker usbd_status error; 1186c197399bSmglocker 1187c197399bSmglocker error = udl_ctrl_msg(sc, UT_READ_VENDOR_DEVICE, 1188c197399bSmglocker UDL_CTRL_CMD_POLL, 0x0000, 0x0000, lbuf, 4); 1189c197399bSmglocker if (error != USBD_NORMAL_COMPLETION) { 1190c197399bSmglocker printf("%s: %s: %s!\n", DN(sc), FUNC, usbd_errstr(error)); 1191c197399bSmglocker return (error); 1192c197399bSmglocker } 1193c197399bSmglocker *buf = *(uint32_t *)lbuf; 1194c197399bSmglocker 1195c197399bSmglocker return (USBD_NORMAL_COMPLETION); 1196c197399bSmglocker } 1197c197399bSmglocker 1198c197399bSmglocker usbd_status 1199c197399bSmglocker udl_read_1(struct udl_softc *sc, uint16_t addr, uint8_t *buf) 1200c197399bSmglocker { 1201c197399bSmglocker uint8_t lbuf[1]; 1202c197399bSmglocker usbd_status error; 1203c197399bSmglocker 1204c197399bSmglocker error = udl_ctrl_msg(sc, UT_READ_VENDOR_DEVICE, 1205c197399bSmglocker UDL_CTRL_CMD_READ_1, addr, 0x0000, lbuf, 1); 1206c197399bSmglocker if (error != USBD_NORMAL_COMPLETION) { 1207c197399bSmglocker printf("%s: %s: %s!\n", DN(sc), FUNC, usbd_errstr(error)); 1208c197399bSmglocker return (error); 1209c197399bSmglocker } 1210c197399bSmglocker *buf = *(uint8_t *)lbuf; 1211c197399bSmglocker 1212c197399bSmglocker return (USBD_NORMAL_COMPLETION); 1213c197399bSmglocker } 1214c197399bSmglocker 1215c197399bSmglocker usbd_status 1216c197399bSmglocker udl_write_1(struct udl_softc *sc, uint16_t addr, uint8_t buf) 1217c197399bSmglocker { 1218c197399bSmglocker usbd_status error; 1219c197399bSmglocker 1220c197399bSmglocker error = udl_ctrl_msg(sc, UT_WRITE_VENDOR_DEVICE, 1221c197399bSmglocker UDL_CTRL_CMD_WRITE_1, addr, 0x0000, &buf, 1); 1222c197399bSmglocker if (error != USBD_NORMAL_COMPLETION) { 1223c197399bSmglocker printf("%s: %s: %s!\n", DN(sc), FUNC, usbd_errstr(error)); 1224c197399bSmglocker return (error); 1225c197399bSmglocker } 1226c197399bSmglocker 1227c197399bSmglocker return (USBD_NORMAL_COMPLETION); 1228c197399bSmglocker } 1229c197399bSmglocker 1230c197399bSmglocker usbd_status 1231c197399bSmglocker udl_read_edid(struct udl_softc *sc, uint8_t *buf) 1232c197399bSmglocker { 1233c197399bSmglocker uint8_t lbuf[64]; 1234c197399bSmglocker uint16_t offset; 1235c197399bSmglocker usbd_status error; 1236c197399bSmglocker 1237c197399bSmglocker offset = 0; 1238c197399bSmglocker 1239c197399bSmglocker error = udl_ctrl_msg(sc, UT_READ_VENDOR_DEVICE, 1240c197399bSmglocker UDL_CTRL_CMD_READ_EDID, 0x00a1, (offset << 8), lbuf, 64); 1241c197399bSmglocker if (error != USBD_NORMAL_COMPLETION) 1242c197399bSmglocker goto fail; 1243c197399bSmglocker bcopy(lbuf + 1, buf + offset, 63); 1244c197399bSmglocker offset += 63; 1245c197399bSmglocker 1246c197399bSmglocker error = udl_ctrl_msg(sc, UT_READ_VENDOR_DEVICE, 1247c197399bSmglocker UDL_CTRL_CMD_READ_EDID, 0x00a1, (offset << 8), lbuf, 64); 1248c197399bSmglocker if (error != USBD_NORMAL_COMPLETION) 1249c197399bSmglocker goto fail; 1250c197399bSmglocker bcopy(lbuf + 1, buf + offset, 63); 1251c197399bSmglocker offset += 63; 1252c197399bSmglocker 1253c197399bSmglocker error = udl_ctrl_msg(sc, UT_READ_VENDOR_DEVICE, 1254c197399bSmglocker UDL_CTRL_CMD_READ_EDID, 0x00a1, (offset << 8), lbuf, 3); 1255c197399bSmglocker if (error != USBD_NORMAL_COMPLETION) 1256c197399bSmglocker goto fail; 1257c197399bSmglocker bcopy(lbuf + 1, buf + offset, 2); 1258c197399bSmglocker 1259c197399bSmglocker return (USBD_NORMAL_COMPLETION); 1260c197399bSmglocker fail: 1261c197399bSmglocker printf("%s: %s: %s!\n", DN(sc), FUNC, usbd_errstr(error)); 1262c197399bSmglocker return (error); 1263c197399bSmglocker } 1264c197399bSmglocker 12656e641510Smaja uint8_t 1266af3c181fSmpi udl_lookup_mode(uint16_t hdisplay, uint16_t vdisplay, uint8_t freq, 12676e641510Smaja uint16_t chip, uint32_t clock) 12686e641510Smaja { 12696e641510Smaja uint8_t idx = 0; 12706e641510Smaja 12716e641510Smaja /* 12726e641510Smaja * Check first if we have a matching mode with pixelclock 12736e641510Smaja */ 12746e641510Smaja while (idx < MAX_DL_MODES) { 12756e641510Smaja if ((udl_modes[idx].hdisplay == hdisplay) && 12766e641510Smaja (udl_modes[idx].vdisplay == vdisplay) && 12776e641510Smaja (udl_modes[idx].clock == clock) && 12786e641510Smaja (udl_modes[idx].chip <= chip)) { 12796e641510Smaja return(idx); 12806e641510Smaja } 12816e641510Smaja idx++; 12826e641510Smaja } 12836e641510Smaja 12846e641510Smaja /* 12856e641510Smaja * If not, check for matching mode with update frequency 12866e641510Smaja */ 12876e641510Smaja idx = 0; 12886e641510Smaja while (idx < MAX_DL_MODES) { 12896e641510Smaja if ((udl_modes[idx].hdisplay == hdisplay) && 12906e641510Smaja (udl_modes[idx].vdisplay == vdisplay) && 1291af3c181fSmpi (udl_modes[idx].freq == freq) && 12926e641510Smaja (udl_modes[idx].chip <= chip)) { 12936e641510Smaja return(idx); 12946e641510Smaja } 12956e641510Smaja idx++; 12966e641510Smaja } 129753fd709fSmglocker 12986e641510Smaja return(idx); 12996e641510Smaja } 13006e641510Smaja 13016e641510Smaja int 13026e641510Smaja udl_select_chip(struct udl_softc *sc) 13036e641510Smaja { 13046e641510Smaja char serialnum[USB_MAX_STRING_LEN]; 13056e641510Smaja usb_device_descriptor_t *dd; 13066e641510Smaja usb_string_descriptor_t us; 13076e641510Smaja usbd_status error; 13086e641510Smaja int len, i, n; 13096e641510Smaja char *s; 131053fd709fSmglocker uint16_t c; 13116e641510Smaja 13126e641510Smaja sc->sc_chip = DL120; 13136e641510Smaja 13146e641510Smaja dd = usbd_get_device_descriptor(sc->sc_udev); 13156e641510Smaja 1316825f6ef7Smaja if ((UGETW(dd->idVendor) == USB_VENDOR_DISPLAYLINK) && 1317825f6ef7Smaja (UGETW(dd->idProduct) == USB_PRODUCT_DISPLAYLINK_WSDVI)) { 1318825f6ef7Smaja 1319825f6ef7Smaja /* 1320825f6ef7Smaja * WS Tech DVI is DL120 or DL160. All deviced uses the 1321825f6ef7Smaja * same revision (0.04) so iSerialNumber must be used 13224b1a56afSjsg * to determine which chip it is. 1323825f6ef7Smaja */ 1324825f6ef7Smaja 13256e641510Smaja bzero(serialnum, sizeof serialnum); 13266e641510Smaja error = usbd_get_string_desc(sc->sc_udev, dd->iSerialNumber, 13276e641510Smaja 0, &us, &len); 13286e641510Smaja if (error != USBD_NORMAL_COMPLETION) 13296e641510Smaja return (1); 13306e641510Smaja 13316e641510Smaja s = &serialnum[0]; 13326e641510Smaja n = len / 2 - 1; 1333397525a8Sjsg for (i = 0; i < n && i < nitems(us.bString); i++) { 13346e641510Smaja c = UGETW(us.bString[i]); 13356e641510Smaja /* Convert from Unicode, handle buggy strings. */ 13366e641510Smaja if ((c & 0xff00) == 0) 13376e641510Smaja *s++ = c; 13386e641510Smaja else if ((c & 0x00ff) == 0) 13396e641510Smaja *s++ = c >> 8; 13406e641510Smaja else 13416e641510Smaja *s++ = '?'; 13426e641510Smaja } 13436e641510Smaja *s++ = 0; 13446e641510Smaja 13456e641510Smaja if (strlen(serialnum) > 7) 13466e641510Smaja if (strncmp(serialnum, "0198-13", 7) == 0) 13476e641510Smaja sc->sc_chip = DL160; 13486e641510Smaja 13496e641510Smaja DPRINTF(1, "%s: %s: iSerialNumber (%s) used to select chip (%d)\n", 13506e641510Smaja DN(sc), FUNC, serialnum, sc->sc_chip); 13516e641510Smaja 1352825f6ef7Smaja } 1353825f6ef7Smaja 1354825f6ef7Smaja if ((UGETW(dd->idVendor) == USB_VENDOR_DISPLAYLINK) && 1355825f6ef7Smaja (UGETW(dd->idProduct) == USB_PRODUCT_DISPLAYLINK_SWDVI)) { 1356825f6ef7Smaja 1357825f6ef7Smaja /* 1358825f6ef7Smaja * SUNWEIT DVI is DL160, DL125, DL165 or DL195. Major revision 1359825f6ef7Smaja * can be used to differ between DL1x0 and DL1x5. Minor to 13604b1a56afSjsg * differ between DL1x5. iSerialNumber seems not to be unique. 1361825f6ef7Smaja */ 1362825f6ef7Smaja 1363825f6ef7Smaja sc->sc_chip = DL160; 1364825f6ef7Smaja 1365825f6ef7Smaja if (UGETW(dd->bcdDevice) >= 0x100) { 1366825f6ef7Smaja sc->sc_chip = DL165; 1367825f6ef7Smaja if (UGETW(dd->bcdDevice) == 0x104) 1368825f6ef7Smaja sc->sc_chip = DL195; 1369825f6ef7Smaja if (UGETW(dd->bcdDevice) == 0x108) 1370825f6ef7Smaja sc->sc_chip = DL125; 1371825f6ef7Smaja } 1372825f6ef7Smaja 1373825f6ef7Smaja DPRINTF(1, "%s: %s: bcdDevice (%02x) used to select chip (%d)\n", 1374825f6ef7Smaja DN(sc), FUNC, UGETW(dd->bcdDevice), sc->sc_chip); 1375825f6ef7Smaja 1376825f6ef7Smaja } 1377825f6ef7Smaja 13786e641510Smaja return (0); 13796e641510Smaja } 13806e641510Smaja 1381c197399bSmglocker usbd_status 1382c197399bSmglocker udl_set_enc_key(struct udl_softc *sc, uint8_t *buf, uint8_t len) 1383c197399bSmglocker { 1384c197399bSmglocker usbd_status error; 1385c197399bSmglocker 1386c197399bSmglocker error = udl_ctrl_msg(sc, UT_WRITE_VENDOR_DEVICE, 1387c197399bSmglocker UDL_CTRL_CMD_SET_KEY, 0x0000, 0x0000, buf, len); 1388c197399bSmglocker if (error != USBD_NORMAL_COMPLETION) { 1389c197399bSmglocker printf("%s: %s: %s!\n", DN(sc), FUNC, usbd_errstr(error)); 1390c197399bSmglocker return (error); 1391c197399bSmglocker } 1392c197399bSmglocker 1393c197399bSmglocker return (USBD_NORMAL_COMPLETION); 1394c197399bSmglocker } 1395c197399bSmglocker 1396c197399bSmglocker usbd_status 1397c197399bSmglocker udl_set_decomp_table(struct udl_softc *sc, uint8_t *buf, uint16_t len) 1398c197399bSmglocker { 1399c197399bSmglocker int err; 1400c197399bSmglocker 1401c197399bSmglocker udl_cmd_insert_int_1(sc, UDL_BULK_SOC); 1402c197399bSmglocker udl_cmd_insert_int_1(sc, UDL_BULK_CMD_DECOMP); 1403c197399bSmglocker udl_cmd_insert_int_4(sc, 0x263871cd); /* magic number */ 1404c197399bSmglocker udl_cmd_insert_int_4(sc, 0x00000200); /* 512 byte chunks */ 1405c197399bSmglocker udl_cmd_insert_buf(sc, buf, len); 1406c197399bSmglocker 1407c197399bSmglocker err = udl_cmd_send(sc); 1408c197399bSmglocker if (err != 0) 1409c197399bSmglocker return (USBD_INVAL); 1410c197399bSmglocker 1411c197399bSmglocker return (USBD_NORMAL_COMPLETION); 1412c197399bSmglocker } 1413c197399bSmglocker 1414c197399bSmglocker /* ---------- */ 1415c197399bSmglocker 14162fa8dc63Smglocker int 14172fa8dc63Smglocker udl_load_huffman(struct udl_softc *sc) 14182fa8dc63Smglocker { 14192fa8dc63Smglocker const char *name = "udl_huffman"; 14202fa8dc63Smglocker int error; 14212fa8dc63Smglocker 14222fa8dc63Smglocker if (sc->sc_huffman == NULL) { 14232fa8dc63Smglocker error = loadfirmware(name, &sc->sc_huffman, 14242fa8dc63Smglocker &sc->sc_huffman_size); 14252fa8dc63Smglocker if (error != 0) { 14262fa8dc63Smglocker printf("%s: error %d, could not read huffman table " 14272fa8dc63Smglocker "%s!\n", DN(sc), error, name); 14282fa8dc63Smglocker return (EIO); 14292fa8dc63Smglocker } 14302fa8dc63Smglocker } 14312fa8dc63Smglocker 14322fa8dc63Smglocker DPRINTF(1, "%s: huffman table %s allocated\n", DN(sc), name); 14332fa8dc63Smglocker 14342fa8dc63Smglocker return (0); 14352fa8dc63Smglocker } 14362fa8dc63Smglocker 14372fa8dc63Smglocker void 14382fa8dc63Smglocker udl_free_huffman(struct udl_softc *sc) 14392fa8dc63Smglocker { 14402fa8dc63Smglocker if (sc->sc_huffman != NULL) { 14418985a220Smglocker free(sc->sc_huffman, M_USBDEV, sc->sc_huffman_size); 14422fa8dc63Smglocker sc->sc_huffman = NULL; 14432fa8dc63Smglocker sc->sc_huffman_size = 0; 14442fa8dc63Smglocker DPRINTF(1, "%s: huffman table freed\n", DN(sc)); 14452fa8dc63Smglocker } 14462fa8dc63Smglocker } 14472fa8dc63Smglocker 1448fa695a51Smglocker int 1449fa695a51Smglocker udl_fbmem_alloc(struct udl_softc *sc) 1450fa695a51Smglocker { 1451fa695a51Smglocker int size; 1452fa695a51Smglocker 1453fa695a51Smglocker size = (sc->sc_width * sc->sc_height) * (sc->sc_depth / 8); 1454fa695a51Smglocker size = round_page(size); 1455fa695a51Smglocker 1456fa695a51Smglocker if (sc->sc_fbmem == NULL) { 14578985a220Smglocker sc->sc_fbmem = malloc(size, M_USBDEV, M_NOWAIT|M_ZERO); 1458fa695a51Smglocker if (sc->sc_fbmem == NULL) 1459fa695a51Smglocker return (-1); 1460fa695a51Smglocker } 1461c9ee9455Sderaadt sc->sc_fbmemsize = size; 1462fa695a51Smglocker return (0); 1463fa695a51Smglocker } 1464fa695a51Smglocker 1465fa695a51Smglocker void 1466fa695a51Smglocker udl_fbmem_free(struct udl_softc *sc) 1467fa695a51Smglocker { 1468fa695a51Smglocker if (sc->sc_fbmem != NULL) { 14698985a220Smglocker free(sc->sc_fbmem, M_USBDEV, sc->sc_fbmemsize); 1470fa695a51Smglocker sc->sc_fbmem = NULL; 1471c9ee9455Sderaadt sc->sc_fbmemsize = 0; 1472fa695a51Smglocker } 1473fa695a51Smglocker } 1474fa695a51Smglocker 1475c197399bSmglocker usbd_status 1476c197399bSmglocker udl_cmd_alloc_xfer(struct udl_softc *sc) 1477c197399bSmglocker { 1478c197399bSmglocker int i; 1479c197399bSmglocker 1480c197399bSmglocker for (i = 0; i < UDL_CMD_XFER_COUNT; i++) { 1481c197399bSmglocker struct udl_cmd_xfer *cx = &sc->sc_cmd_xfer[i]; 1482c197399bSmglocker 1483c197399bSmglocker cx->sc = sc; 1484c197399bSmglocker 1485c197399bSmglocker cx->xfer = usbd_alloc_xfer(sc->sc_udev); 1486c197399bSmglocker if (cx->xfer == NULL) { 1487c197399bSmglocker printf("%s: %s: can't allocate xfer handle!\n", 1488c197399bSmglocker DN(sc), FUNC); 1489c197399bSmglocker return (USBD_NOMEM); 1490c197399bSmglocker } 1491c197399bSmglocker 1492c197399bSmglocker cx->buf = usbd_alloc_buffer(cx->xfer, UDL_CMD_MAX_XFER_SIZE); 1493c197399bSmglocker if (cx->buf == NULL) { 1494c197399bSmglocker printf("%s: %s: can't allocate xfer buffer!\n", 1495c197399bSmglocker DN(sc), FUNC); 1496c197399bSmglocker return (USBD_NOMEM); 1497c197399bSmglocker } 1498c197399bSmglocker } 1499c197399bSmglocker 1500c197399bSmglocker return (USBD_NORMAL_COMPLETION); 1501c197399bSmglocker } 1502c197399bSmglocker 1503c197399bSmglocker void 1504c197399bSmglocker udl_cmd_free_xfer(struct udl_softc *sc) 1505c197399bSmglocker { 1506c197399bSmglocker int i; 1507c197399bSmglocker 1508c197399bSmglocker for (i = 0; i < UDL_CMD_XFER_COUNT; i++) { 1509c197399bSmglocker struct udl_cmd_xfer *cx = &sc->sc_cmd_xfer[i]; 1510c197399bSmglocker 1511c197399bSmglocker if (cx->xfer != NULL) { 1512c197399bSmglocker usbd_free_xfer(cx->xfer); 1513c197399bSmglocker cx->xfer = NULL; 1514c197399bSmglocker } 1515c197399bSmglocker } 1516c197399bSmglocker } 1517c197399bSmglocker 1518c197399bSmglocker int 1519c197399bSmglocker udl_cmd_alloc_buf(struct udl_softc *sc) 1520c197399bSmglocker { 1521c197399bSmglocker struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 1522c197399bSmglocker 15238985a220Smglocker cb->buf = malloc(UDL_CMD_MAX_XFER_SIZE, M_USBDEV, M_NOWAIT|M_ZERO); 1524c197399bSmglocker if (cb->buf == NULL) { 1525c197399bSmglocker printf("%s: %s: can't allocate buffer!\n", 1526c197399bSmglocker DN(sc), FUNC); 1527c197399bSmglocker return (ENOMEM); 1528c197399bSmglocker } 1529c197399bSmglocker cb->off = 0; 15302fa8dc63Smglocker cb->compblock = 0; 1531c197399bSmglocker 1532c197399bSmglocker return (0); 1533c197399bSmglocker } 1534c197399bSmglocker 1535c197399bSmglocker void 1536c197399bSmglocker udl_cmd_free_buf(struct udl_softc *sc) 1537c197399bSmglocker { 1538c197399bSmglocker struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 1539c197399bSmglocker 15409fe656fbSmglocker if (cb->buf != NULL) { 15418985a220Smglocker free(cb->buf, M_USBDEV, UDL_CMD_MAX_XFER_SIZE); 15429fe656fbSmglocker cb->buf = NULL; 15439fe656fbSmglocker } 1544c197399bSmglocker cb->off = 0; 1545c197399bSmglocker } 1546c197399bSmglocker 1547c197399bSmglocker void 1548c197399bSmglocker udl_cmd_insert_int_1(struct udl_softc *sc, uint8_t value) 1549c197399bSmglocker { 1550c197399bSmglocker struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 1551c197399bSmglocker 1552c197399bSmglocker cb->buf[cb->off] = value; 1553c197399bSmglocker 1554c197399bSmglocker cb->off += 1; 1555c197399bSmglocker } 1556c197399bSmglocker 1557c197399bSmglocker void 1558c197399bSmglocker udl_cmd_insert_int_2(struct udl_softc *sc, uint16_t value) 1559c197399bSmglocker { 1560c197399bSmglocker uint16_t lvalue; 1561c197399bSmglocker struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 1562c197399bSmglocker 1563c197399bSmglocker lvalue = htobe16(value); 1564a2cff4d1Smglocker bcopy(&lvalue, cb->buf + cb->off, 2); 1565c197399bSmglocker 1566c197399bSmglocker cb->off += 2; 1567c197399bSmglocker } 1568c197399bSmglocker 1569c197399bSmglocker void 1570c197399bSmglocker udl_cmd_insert_int_3(struct udl_softc *sc, uint32_t value) 1571c197399bSmglocker { 1572c197399bSmglocker uint32_t lvalue; 1573c197399bSmglocker struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 1574c197399bSmglocker #if BYTE_ORDER == BIG_ENDIAN 1575c197399bSmglocker lvalue = htobe32(value) << 8; 1576c197399bSmglocker #else 1577c197399bSmglocker lvalue = htobe32(value) >> 8; 1578c197399bSmglocker #endif 1579a2cff4d1Smglocker bcopy(&lvalue, cb->buf + cb->off, 3); 1580c197399bSmglocker 1581c197399bSmglocker cb->off += 3; 1582c197399bSmglocker } 1583c197399bSmglocker 1584c197399bSmglocker void 1585c197399bSmglocker udl_cmd_insert_int_4(struct udl_softc *sc, uint32_t value) 1586c197399bSmglocker { 1587c197399bSmglocker uint32_t lvalue; 1588c197399bSmglocker struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 1589c197399bSmglocker 1590c197399bSmglocker lvalue = htobe32(value); 1591a2cff4d1Smglocker bcopy(&lvalue, cb->buf + cb->off, 4); 1592c197399bSmglocker 1593c197399bSmglocker cb->off += 4; 1594c197399bSmglocker } 1595c197399bSmglocker 1596c197399bSmglocker void 1597c197399bSmglocker udl_cmd_insert_buf(struct udl_softc *sc, uint8_t *buf, uint32_t len) 1598c197399bSmglocker { 1599c197399bSmglocker struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 1600c197399bSmglocker 1601c197399bSmglocker bcopy(buf, cb->buf + cb->off, len); 1602c197399bSmglocker 1603c197399bSmglocker cb->off += len; 1604c197399bSmglocker } 1605c197399bSmglocker 16062fa8dc63Smglocker int 16072fa8dc63Smglocker udl_cmd_insert_buf_comp(struct udl_softc *sc, uint8_t *buf, uint32_t len) 16082fa8dc63Smglocker { 16092fa8dc63Smglocker struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 16102fa8dc63Smglocker struct udl_huffman *h; 161128d90ff9Smglocker uint8_t bit_pos; 16122fa8dc63Smglocker uint16_t *pixels, prev; 16132fa8dc63Smglocker int16_t diff; 161428d90ff9Smglocker uint32_t bit_count, bit_pattern, bit_cur; 1615f34f9b4cSmglocker int i, j, bytes, eob, padding, next; 16162fa8dc63Smglocker 16172fa8dc63Smglocker pixels = (uint16_t *)buf; 16182fa8dc63Smglocker bit_pos = bytes = eob = padding = 0; 16192fa8dc63Smglocker 16202fa8dc63Smglocker /* 16212fa8dc63Smglocker * If the header doesn't fit into the 512 byte main-block anymore, 16222fa8dc63Smglocker * skip the header and finish up the main-block. We return zero 16232fa8dc63Smglocker * to signal our caller that the header has been skipped. 16242fa8dc63Smglocker */ 162529d27783Smglocker if (cb->compblock >= UDL_CB_RESTART_SIZE) { 16262fa8dc63Smglocker cb->off -= UDL_CMD_WRITE_HEAD_SIZE; 16272fa8dc63Smglocker cb->compblock -= UDL_CMD_WRITE_HEAD_SIZE; 16282fa8dc63Smglocker eob = 1; 16292fa8dc63Smglocker } 16302fa8dc63Smglocker 16312fa8dc63Smglocker /* 16322fa8dc63Smglocker * Generate a sub-block with maximal 256 pixels compressed data. 16332fa8dc63Smglocker */ 16342fa8dc63Smglocker for (i = 0; i < len / 2 && eob == 0; i++) { 16352fa8dc63Smglocker /* get difference between current and previous pixel */ 16362fa8dc63Smglocker if (i > 0) 16372fa8dc63Smglocker prev = betoh16(pixels[i - 1]); 16382fa8dc63Smglocker else 16392fa8dc63Smglocker prev = 0; 16402fa8dc63Smglocker 16412fa8dc63Smglocker /* get the huffman difference bit sequence */ 16422fa8dc63Smglocker diff = betoh16(pixels[i]) - prev; 16432fa8dc63Smglocker h = (struct udl_huffman *)(sc->sc_huffman + UDL_HUFFMAN_BASE); 16442fa8dc63Smglocker h += diff; 16452fa8dc63Smglocker bit_count = h->bit_count; 16462fa8dc63Smglocker bit_pattern = betoh32(h->bit_pattern); 16472fa8dc63Smglocker 1648f34f9b4cSmglocker 1649f34f9b4cSmglocker /* we are near the end of the main-block, so quit loop */ 1650f34f9b4cSmglocker if (bit_count % 8 == 0) 1651f34f9b4cSmglocker next = bit_count / 8; 1652f34f9b4cSmglocker else 1653f34f9b4cSmglocker next = (bit_count / 8) + 1; 1654f34f9b4cSmglocker 1655f34f9b4cSmglocker if (cb->compblock + next >= UDL_CB_BODY_SIZE) { 1656f34f9b4cSmglocker eob = 1; 1657f34f9b4cSmglocker break; 1658f34f9b4cSmglocker } 1659f34f9b4cSmglocker 16602fa8dc63Smglocker /* generate one pixel compressed data */ 16612fa8dc63Smglocker for (j = 0; j < bit_count; j++) { 16622fa8dc63Smglocker if (bit_pos == 0) 16632fa8dc63Smglocker cb->buf[cb->off] = 0; 16642fa8dc63Smglocker bit_cur = (bit_pattern >> j) & 1; 16652fa8dc63Smglocker cb->buf[cb->off] |= (bit_cur << bit_pos); 16662fa8dc63Smglocker bit_pos++; 16672fa8dc63Smglocker 16682fa8dc63Smglocker if (bit_pos == 8) { 16692fa8dc63Smglocker bit_pos = 0; 16702fa8dc63Smglocker cb->off++; 16712fa8dc63Smglocker cb->compblock++; 16722fa8dc63Smglocker } 16732fa8dc63Smglocker } 16742fa8dc63Smglocker bytes += 2; 16752fa8dc63Smglocker } 16762fa8dc63Smglocker 16772fa8dc63Smglocker /* 16782fa8dc63Smglocker * If we have bits left in our last byte, round up to the next 16792fa8dc63Smglocker * byte, so we don't overwrite them. 16802fa8dc63Smglocker */ 16812fa8dc63Smglocker if (bit_pos != 0) { 16822fa8dc63Smglocker cb->off++; 16832fa8dc63Smglocker cb->compblock++; 16842fa8dc63Smglocker } 16852fa8dc63Smglocker 16862fa8dc63Smglocker /* 16872fa8dc63Smglocker * Finish up a 512 byte main-block. The leftover space gets 1688c8ebe74cSjasper * padded to zero. Finally terminate the block by writing the 16892fa8dc63Smglocker * 0xff-into-UDL_REG_SYNC-register sequence. 16902fa8dc63Smglocker */ 16912fa8dc63Smglocker if (eob == 1) { 16922fa8dc63Smglocker padding = (UDL_CB_BODY_SIZE - cb->compblock); 16932fa8dc63Smglocker for (i = 0; i < padding; i++) { 16942fa8dc63Smglocker cb->buf[cb->off] = 0; 16952fa8dc63Smglocker cb->off++; 16962fa8dc63Smglocker cb->compblock++; 16972fa8dc63Smglocker } 16982fa8dc63Smglocker udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0xff); 16992fa8dc63Smglocker cb->compblock = 0; 17002fa8dc63Smglocker } 17012fa8dc63Smglocker 17022fa8dc63Smglocker /* return how many bytes we have compressed */ 17032fa8dc63Smglocker return (bytes); 17042fa8dc63Smglocker } 17052fa8dc63Smglocker 17062fa8dc63Smglocker int 17072fa8dc63Smglocker udl_cmd_insert_head_comp(struct udl_softc *sc, uint32_t len) 17082fa8dc63Smglocker { 17092fa8dc63Smglocker struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 17102fa8dc63Smglocker int i, padding; 17112fa8dc63Smglocker 1712f34f9b4cSmglocker if (cb->compblock > UDL_CB_BODY_SIZE) { 17132fa8dc63Smglocker cb->off -= UDL_CMD_COPY_HEAD_SIZE; 17142fa8dc63Smglocker cb->compblock -= UDL_CMD_COPY_HEAD_SIZE; 17152fa8dc63Smglocker 17162fa8dc63Smglocker padding = (UDL_CB_BODY_SIZE - cb->compblock); 17172fa8dc63Smglocker for (i = 0; i < padding; i++) { 17182fa8dc63Smglocker cb->buf[cb->off] = 0; 17192fa8dc63Smglocker cb->off++; 17202fa8dc63Smglocker cb->compblock++; 17212fa8dc63Smglocker } 17222fa8dc63Smglocker udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0xff); 17232fa8dc63Smglocker cb->compblock = 0; 17242fa8dc63Smglocker return (0); 17252fa8dc63Smglocker } 17262fa8dc63Smglocker 17272fa8dc63Smglocker return (len); 17282fa8dc63Smglocker } 17292fa8dc63Smglocker 1730fc15257dSmglocker int 1731fc15257dSmglocker udl_cmd_insert_check(struct udl_softc *sc, int len) 1732c197399bSmglocker { 1733fc15257dSmglocker struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 1734c197399bSmglocker int total; 1735fc15257dSmglocker usbd_status error; 1736c197399bSmglocker 1737c197399bSmglocker total = cb->off + len; 1738c197399bSmglocker 1739fc15257dSmglocker if (total > UDL_CMD_MAX_XFER_SIZE) { 1740fc15257dSmglocker /* command buffer is almost full, try to flush it */ 1741b1107686Smglocker if (cb->xfer_type == UDL_CMD_XFER_ASYNC) 1742fc15257dSmglocker error = udl_cmd_send_async(sc); 1743fc15257dSmglocker else 1744fc15257dSmglocker error = udl_cmd_send(sc); 1745fc15257dSmglocker if (error != USBD_NORMAL_COMPLETION) { 1746fc15257dSmglocker DPRINTF(1, "%s: %s: can't flush full command buffer\n", 1747fc15257dSmglocker DN(sc), FUNC); 1748fc15257dSmglocker return (EAGAIN); 1749c197399bSmglocker } 1750c197399bSmglocker } 1751c197399bSmglocker 1752fc15257dSmglocker return (0); 1753fc15257dSmglocker } 1754fc15257dSmglocker 1755fc15257dSmglocker void 1756b1107686Smglocker udl_cmd_set_xfer_type(struct udl_softc *sc, int xfer_type) 1757fc15257dSmglocker { 1758fc15257dSmglocker struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 1759fc15257dSmglocker 1760b1107686Smglocker cb->xfer_type = xfer_type; 1761fc15257dSmglocker } 1762fc15257dSmglocker 17633a801951Smglocker void 17648e027a9aSmglocker udl_cmd_save_offset(struct udl_softc *sc) 17658c7540bbSmglocker { 17668c7540bbSmglocker struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 17678c7540bbSmglocker 17683a801951Smglocker cb->off_save = cb->off; 17693a801951Smglocker cb->compblock_save = cb->compblock; 17708c7540bbSmglocker } 17718c7540bbSmglocker 17728c7540bbSmglocker void 17738e027a9aSmglocker udl_cmd_restore_offset(struct udl_softc *sc) 17748c7540bbSmglocker { 17758c7540bbSmglocker struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 17768c7540bbSmglocker 17773a801951Smglocker cb->off = cb->off_save; 17783a801951Smglocker cb->compblock = cb->compblock_save; 17798c7540bbSmglocker } 17808c7540bbSmglocker 1781c197399bSmglocker void 1782c197399bSmglocker udl_cmd_write_reg_1(struct udl_softc *sc, uint8_t reg, uint8_t val) 1783c197399bSmglocker { 1784c197399bSmglocker udl_cmd_insert_int_1(sc, UDL_BULK_SOC); 1785c197399bSmglocker udl_cmd_insert_int_1(sc, UDL_BULK_CMD_REG_WRITE_1); 1786c197399bSmglocker udl_cmd_insert_int_1(sc, reg); 1787c197399bSmglocker udl_cmd_insert_int_1(sc, val); 1788c197399bSmglocker } 1789c197399bSmglocker 1790c197399bSmglocker void 1791c197399bSmglocker udl_cmd_write_reg_3(struct udl_softc *sc, uint8_t reg, uint32_t val) 1792c197399bSmglocker { 1793c197399bSmglocker udl_cmd_write_reg_1(sc, reg + 0, (val >> 16) & 0xff); 1794c197399bSmglocker udl_cmd_write_reg_1(sc, reg + 1, (val >> 8) & 0xff); 1795c197399bSmglocker udl_cmd_write_reg_1(sc, reg + 2, (val >> 0) & 0xff); 1796c197399bSmglocker } 1797c197399bSmglocker 1798c197399bSmglocker usbd_status 1799c197399bSmglocker udl_cmd_send(struct udl_softc *sc) 1800c197399bSmglocker { 1801c197399bSmglocker struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 1802c197399bSmglocker struct udl_cmd_xfer *cx = &sc->sc_cmd_xfer[0]; 1803c197399bSmglocker int len; 1804c197399bSmglocker usbd_status error; 1805c197399bSmglocker 1806c197399bSmglocker /* mark end of command stack */ 1807c197399bSmglocker udl_cmd_insert_int_1(sc, UDL_BULK_SOC); 1808c197399bSmglocker udl_cmd_insert_int_1(sc, UDL_BULK_CMD_EOC); 1809c197399bSmglocker 1810c197399bSmglocker bcopy(cb->buf, cx->buf, cb->off); 1811c197399bSmglocker 1812c197399bSmglocker len = cb->off; 1813431119e5Smpi usbd_setup_xfer(cx->xfer, sc->sc_tx_pipeh, 0, cx->buf, len, 1814431119e5Smpi USBD_NO_COPY | USBD_SHORT_XFER_OK | USBD_SYNCHRONOUS, 1000, NULL); 1815431119e5Smpi error = usbd_transfer(cx->xfer); 1816c197399bSmglocker if (error != USBD_NORMAL_COMPLETION) { 1817c197399bSmglocker printf("%s: %s: %s!\n", DN(sc), FUNC, usbd_errstr(error)); 1818c197399bSmglocker /* we clear our buffer now to avoid growing out of bounds */ 1819c197399bSmglocker goto fail; 1820c197399bSmglocker } 1821c197399bSmglocker DPRINTF(1, "%s: %s: sent %d of %d bytes\n", 1822c197399bSmglocker DN(sc), FUNC, len, cb->off); 1823c197399bSmglocker fail: 1824c197399bSmglocker cb->off = 0; 18252fa8dc63Smglocker cb->compblock = 0; 1826c197399bSmglocker 1827c197399bSmglocker return (error); 1828c197399bSmglocker } 1829c197399bSmglocker 1830c197399bSmglocker usbd_status 1831c197399bSmglocker udl_cmd_send_async(struct udl_softc *sc) 1832c197399bSmglocker { 1833c197399bSmglocker struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 1834c197399bSmglocker struct udl_cmd_xfer *cx; 1835c197399bSmglocker usbd_status error; 1836c197399bSmglocker int i, s; 1837c197399bSmglocker 183823e0be93Smglocker /* check if command xfer queue is full */ 18398c7540bbSmglocker if (sc->sc_cmd_xfer_cnt == UDL_CMD_XFER_COUNT) 18408c7540bbSmglocker return (USBD_IN_USE); 1841c197399bSmglocker 1842c197399bSmglocker s = splusb(); /* no callbacks please until accounting is done */ 1843c197399bSmglocker 184423e0be93Smglocker /* find a free command xfer buffer */ 1845c197399bSmglocker for (i = 0; i < UDL_CMD_XFER_COUNT; i++) { 1846c197399bSmglocker if (sc->sc_cmd_xfer[i].busy == 0) 1847c197399bSmglocker break; 1848c197399bSmglocker } 1849c197399bSmglocker if (i == UDL_CMD_XFER_COUNT) { 1850a3f1f5adSmglocker /* this shouldn't happen */ 1851a8359cd7Sjsg splx(s); 1852a3f1f5adSmglocker return (USBD_IN_USE); 1853c197399bSmglocker } 1854c197399bSmglocker cx = &sc->sc_cmd_xfer[i]; 1855c197399bSmglocker 1856dba6ed21Smglocker /* mark end of command stack */ 1857dba6ed21Smglocker udl_cmd_insert_int_1(sc, UDL_BULK_SOC); 1858dba6ed21Smglocker udl_cmd_insert_int_1(sc, UDL_BULK_CMD_EOC); 1859dba6ed21Smglocker 1860c197399bSmglocker /* copy command buffer to xfer buffer */ 1861c197399bSmglocker bcopy(cb->buf, cx->buf, cb->off); 1862c197399bSmglocker 1863c197399bSmglocker /* do xfer */ 1864c197399bSmglocker usbd_setup_xfer(cx->xfer, sc->sc_tx_pipeh, cx, cx->buf, cb->off, 1865c197399bSmglocker USBD_NO_COPY, 1000, udl_cmd_send_async_cb); 1866c197399bSmglocker error = usbd_transfer(cx->xfer); 1867c197399bSmglocker if (error != 0 && error != USBD_IN_PROGRESS) { 1868c197399bSmglocker printf("%s: %s: %s!\n", DN(sc), FUNC, usbd_errstr(error)); 18698c7540bbSmglocker splx(s); 1870c197399bSmglocker return (error); 1871c197399bSmglocker } 187214a356fdSmglocker DPRINTF(2, "%s: %s: sending %d bytes from buffer no. %d\n", 1873c197399bSmglocker DN(sc), FUNC, cb->off, i); 1874c197399bSmglocker 1875c197399bSmglocker /* free command buffer, lock xfer buffer */ 1876c197399bSmglocker cb->off = 0; 18772fa8dc63Smglocker cb->compblock = 0; 1878c197399bSmglocker cx->busy = 1; 1879c197399bSmglocker sc->sc_cmd_xfer_cnt++; 1880c197399bSmglocker 1881c197399bSmglocker splx(s); 1882c197399bSmglocker 1883c197399bSmglocker return (USBD_NORMAL_COMPLETION); 1884c197399bSmglocker } 1885c197399bSmglocker 1886c197399bSmglocker void 1887ab0b1be7Smglocker udl_cmd_send_async_cb(struct usbd_xfer *xfer, void *priv, usbd_status status) 1888c197399bSmglocker { 1889c197399bSmglocker struct udl_cmd_xfer *cx = priv; 1890c197399bSmglocker struct udl_softc *sc = cx->sc; 1891c197399bSmglocker int len; 1892c197399bSmglocker 1893c197399bSmglocker if (status != USBD_NORMAL_COMPLETION) { 1894c197399bSmglocker printf("%s: %s: %s!\n", DN(sc), FUNC, usbd_errstr(status)); 1895c197399bSmglocker 1896c197399bSmglocker if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 1897c197399bSmglocker return; 1898c197399bSmglocker if (status == USBD_STALLED) 1899c197399bSmglocker usbd_clear_endpoint_stall_async(sc->sc_tx_pipeh); 1900c197399bSmglocker goto skip; 1901c197399bSmglocker } 1902c197399bSmglocker usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL); 1903c197399bSmglocker 1904ab5cedacSmglocker DPRINTF(3, "%s: %s: sent %d bytes\n", DN(sc), FUNC, len); 1905c197399bSmglocker skip: 1906c197399bSmglocker /* free xfer buffer */ 1907c197399bSmglocker cx->busy = 0; 1908c197399bSmglocker sc->sc_cmd_xfer_cnt--; 1909f4611ff0Smglocker 1910f4611ff0Smglocker /* wakeup UDLIO_DAMAGE if it sleeps for a free xfer buffer */ 1911f4611ff0Smglocker wakeup(sc); 1912c197399bSmglocker } 1913c197399bSmglocker 1914c197399bSmglocker /* ---------- */ 1915c197399bSmglocker 1916c197399bSmglocker usbd_status 1917c197399bSmglocker udl_init_chip(struct udl_softc *sc) 1918c197399bSmglocker { 1919c197399bSmglocker uint8_t ui8; 1920c197399bSmglocker uint32_t ui32; 1921c197399bSmglocker usbd_status error; 1922c197399bSmglocker 1923c197399bSmglocker error = udl_poll(sc, &ui32); 1924c197399bSmglocker if (error != USBD_NORMAL_COMPLETION) 1925c197399bSmglocker return (error); 1926c197399bSmglocker DPRINTF(1, "%s: %s: poll=0x%08x\n", DN(sc), FUNC, ui32); 1927c197399bSmglocker 1928825f6ef7Smaja /* Some products may use later chip too */ 1929825f6ef7Smaja switch (ui32 & 0xff) { 1930825f6ef7Smaja case 0xf1: /* DL1x5 */ 1931825f6ef7Smaja switch (sc->sc_chip) { 1932825f6ef7Smaja case DL120: 1933825f6ef7Smaja sc->sc_chip = DL125; 1934825f6ef7Smaja break; 1935825f6ef7Smaja case DL160: 1936825f6ef7Smaja sc->sc_chip = DL165; 1937825f6ef7Smaja break; 1938825f6ef7Smaja } 1939825f6ef7Smaja break; 1940825f6ef7Smaja } 1941825f6ef7Smaja DPRINTF(1, "%s: %s: chip %d\n", DN(sc), FUNC, sc->sc_chip); 1942825f6ef7Smaja 1943c197399bSmglocker error = udl_read_1(sc, 0xc484, &ui8); 1944c197399bSmglocker if (error != USBD_NORMAL_COMPLETION) 1945c197399bSmglocker return (error); 1946c197399bSmglocker DPRINTF(1, "%s: %s: read 0x%02x from 0xc484\n", DN(sc), FUNC, ui8); 1947c197399bSmglocker 1948c197399bSmglocker error = udl_write_1(sc, 0xc41f, 0x01); 1949c197399bSmglocker if (error != USBD_NORMAL_COMPLETION) 1950c197399bSmglocker return (error); 1951c197399bSmglocker DPRINTF(1, "%s: %s: write 0x01 to 0xc41f\n", DN(sc), FUNC); 1952c197399bSmglocker 19536e641510Smaja error = udl_read_edid(sc, sc->sc_edid); 1954c197399bSmglocker if (error != USBD_NORMAL_COMPLETION) 1955c197399bSmglocker return (error); 19566e641510Smaja DPRINTF(1, "%s: %s: read EDID\n", DN(sc), FUNC); 19576e641510Smaja 1958c197399bSmglocker error = udl_set_enc_key(sc, udl_null_key_1, sizeof(udl_null_key_1)); 1959c197399bSmglocker if (error != USBD_NORMAL_COMPLETION) 1960c197399bSmglocker return (error); 1961c197399bSmglocker DPRINTF(1, "%s: %s: set encryption key\n", DN(sc), FUNC); 1962c197399bSmglocker 1963c197399bSmglocker error = udl_write_1(sc, 0xc40b, 0x00); 1964c197399bSmglocker if (error != USBD_NORMAL_COMPLETION) 1965c197399bSmglocker return (error); 196636a555e0Smglocker DPRINTF(1, "%s: %s: write 0x00 to 0xc40b\n", DN(sc), FUNC); 1967c197399bSmglocker 1968c197399bSmglocker error = udl_set_decomp_table(sc, udl_decomp_table, 1969c197399bSmglocker sizeof(udl_decomp_table)); 1970c197399bSmglocker if (error != USBD_NORMAL_COMPLETION) 1971c197399bSmglocker return (error); 1972c197399bSmglocker DPRINTF(1, "%s: %s: set decompression table\n", DN(sc), FUNC); 1973c197399bSmglocker 1974c197399bSmglocker return (USBD_NORMAL_COMPLETION); 1975c197399bSmglocker } 1976c197399bSmglocker 1977c197399bSmglocker void 1978c197399bSmglocker udl_init_fb_offsets(struct udl_softc *sc, uint32_t start16, uint32_t stride16, 1979c197399bSmglocker uint32_t start8, uint32_t stride8) 1980c197399bSmglocker { 1981c197399bSmglocker udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0x00); 1982c197399bSmglocker udl_cmd_write_reg_3(sc, UDL_REG_ADDR_START16, start16); 1983c197399bSmglocker udl_cmd_write_reg_3(sc, UDL_REG_ADDR_STRIDE16, stride16); 1984c197399bSmglocker udl_cmd_write_reg_3(sc, UDL_REG_ADDR_START8, start8); 1985c197399bSmglocker udl_cmd_write_reg_3(sc, UDL_REG_ADDR_STRIDE8, stride8); 1986c197399bSmglocker udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0xff); 1987c197399bSmglocker } 1988c197399bSmglocker 1989c197399bSmglocker usbd_status 19906e641510Smaja udl_init_resolution(struct udl_softc *sc) 1991c197399bSmglocker { 1992c197399bSmglocker int i; 1993c197399bSmglocker usbd_status error; 19946e641510Smaja uint8_t *buf = udl_modes[sc->sc_cur_mode].mode; 1995c197399bSmglocker 1996c197399bSmglocker /* write resolution values and set video memory offsets */ 1997c197399bSmglocker udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0x00); 19986e641510Smaja for (i = 0; i < UDL_MODE_SIZE; i++) 1999c197399bSmglocker udl_cmd_write_reg_1(sc, i, buf[i]); 2000c197399bSmglocker udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0xff); 2001c197399bSmglocker 2002c197399bSmglocker udl_init_fb_offsets(sc, 0x000000, 0x000a00, 0x555555, 0x000500); 2003c197399bSmglocker error = udl_cmd_send(sc); 2004c197399bSmglocker if (error != USBD_NORMAL_COMPLETION) 2005c197399bSmglocker return (error); 2006c197399bSmglocker 2007c197399bSmglocker /* clear screen */ 2008082da39dSmglocker error = udl_clear_screen(sc); 2009c197399bSmglocker if (error != USBD_NORMAL_COMPLETION) 2010c197399bSmglocker return (error); 2011c197399bSmglocker 2012c197399bSmglocker /* show framebuffer content */ 201392fdbf9fSmglocker udl_cmd_write_reg_1(sc, UDL_REG_SCREEN, UDL_REG_SCREEN_ON); 2014c197399bSmglocker udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0xff); 2015c197399bSmglocker error = udl_cmd_send(sc); 2016c197399bSmglocker if (error != USBD_NORMAL_COMPLETION) 2017c197399bSmglocker return (error); 2018c197399bSmglocker 2019c197399bSmglocker return (USBD_NORMAL_COMPLETION); 2020c197399bSmglocker } 2021c197399bSmglocker 2022082da39dSmglocker usbd_status 2023082da39dSmglocker udl_clear_screen(struct udl_softc *sc) 2024082da39dSmglocker { 2025082da39dSmglocker struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 2026082da39dSmglocker usbd_status error; 2027082da39dSmglocker 2028082da39dSmglocker /* clear screen */ 2029082da39dSmglocker udl_fb_block_write(sc, 0x0000, 0, 0, sc->sc_width, sc->sc_height); 2030082da39dSmglocker if (cb->xfer_type == UDL_CMD_XFER_ASYNC) 2031082da39dSmglocker error = udl_cmd_send_async(sc); 2032082da39dSmglocker else 2033082da39dSmglocker error = udl_cmd_send(sc); 2034082da39dSmglocker if (error != USBD_NORMAL_COMPLETION) 2035082da39dSmglocker return (error); 2036082da39dSmglocker 2037082da39dSmglocker return (USBD_NORMAL_COMPLETION); 2038082da39dSmglocker } 2039082da39dSmglocker 20406e641510Smaja void 20416e641510Smaja udl_select_mode(struct udl_softc *sc) 20426e641510Smaja { 20436e641510Smaja struct udl_mode mode; 20446e641510Smaja int index = MAX_DL_MODES, i; 20456e641510Smaja 20466e641510Smaja /* try to get the preferred mode from EDID */ 20470c9d3924Smiod edid_parse(DN(sc), sc->sc_edid, &sc->sc_edid_info); 2048c07d3a0fSmiod #if defined(UDL_DEBUG) && defined(EDID_DEBUG) 20496e641510Smaja edid_print(&sc->sc_edid_info); 20506e641510Smaja #endif 20516e641510Smaja if (sc->sc_edid_info.edid_preferred_mode != NULL) { 2052af3c181fSmpi mode.freq = 20536e641510Smaja (sc->sc_edid_info.edid_preferred_mode->dot_clock * 1000) / 20546e641510Smaja (sc->sc_edid_info.edid_preferred_mode->htotal * 20556e641510Smaja sc->sc_edid_info.edid_preferred_mode->vtotal); 20566e641510Smaja mode.clock = 20576e641510Smaja sc->sc_edid_info.edid_preferred_mode->dot_clock / 10; 20586e641510Smaja mode.hdisplay = 20596e641510Smaja sc->sc_edid_info.edid_preferred_mode->hdisplay; 20606e641510Smaja mode.vdisplay = 20616e641510Smaja sc->sc_edid_info.edid_preferred_mode->vdisplay; 2062af3c181fSmpi index = udl_lookup_mode(mode.hdisplay, mode.vdisplay, mode.freq, 20636e641510Smaja sc->sc_chip, mode.clock); 20646e641510Smaja sc->sc_cur_mode = index; 20656e641510Smaja } else { 20666e641510Smaja DPRINTF(1, "%s: %s: no preferred mode found!\n", DN(sc), FUNC); 20676e641510Smaja } 20686e641510Smaja 20696e641510Smaja if (index == MAX_DL_MODES) { 20706e641510Smaja DPRINTF(1, "%s: %s: no mode line found for %dx%d @ %dHz!\n", 2071af3c181fSmpi DN(sc), FUNC, mode.hdisplay, mode.vdisplay, mode.freq); 20726e641510Smaja 20736e641510Smaja i = 0; 20746e641510Smaja while (i < sc->sc_edid_info.edid_nmodes) { 2075af3c181fSmpi mode.freq = 20766e641510Smaja (sc->sc_edid_info.edid_modes[i].dot_clock * 1000) / 20776e641510Smaja (sc->sc_edid_info.edid_modes[i].htotal * 20786e641510Smaja sc->sc_edid_info.edid_modes[i].vtotal); 20796e641510Smaja mode.clock = 20806e641510Smaja sc->sc_edid_info.edid_modes[i].dot_clock / 10; 20816e641510Smaja mode.hdisplay = 20826e641510Smaja sc->sc_edid_info.edid_modes[i].hdisplay; 20836e641510Smaja mode.vdisplay = 20846e641510Smaja sc->sc_edid_info.edid_modes[i].vdisplay; 20856e641510Smaja index = udl_lookup_mode(mode.hdisplay, mode.vdisplay, 2086af3c181fSmpi mode.freq, sc->sc_chip, mode.clock); 20876e641510Smaja if (index < MAX_DL_MODES) 20886e641510Smaja if ((sc->sc_cur_mode == MAX_DL_MODES) || 20896e641510Smaja (index > sc->sc_cur_mode)) 20906e641510Smaja sc->sc_cur_mode = index; 20916e641510Smaja i++; 20926e641510Smaja } 20936e641510Smaja } 20946e641510Smaja 20956e641510Smaja /* 209653fd709fSmglocker * If no mode found use default. 20976e641510Smaja */ 209853fd709fSmglocker if (sc->sc_cur_mode == MAX_DL_MODES) 20996e641510Smaja sc->sc_cur_mode = udl_lookup_mode(800, 600, 60, sc->sc_chip, 0); 21006e641510Smaja 21016e641510Smaja mode = udl_modes[sc->sc_cur_mode]; 21026e641510Smaja sc->sc_width = mode.hdisplay; 21036e641510Smaja sc->sc_height = mode.vdisplay; 21046e641510Smaja 21056e641510Smaja /* 210653fd709fSmglocker * We always use 16bit color depth for now. 21076e641510Smaja */ 21086e641510Smaja sc->sc_depth = 16; 21096e641510Smaja 21106e641510Smaja DPRINTF(1, "%s: %s: %dx%d @ %dHz\n", 2111af3c181fSmpi DN(sc), FUNC, mode.hdisplay, mode.vdisplay, mode.freq); 21126e641510Smaja } 21136e641510Smaja 2114fc15257dSmglocker int 211523e0be93Smglocker udl_fb_buf_write(struct udl_softc *sc, uint8_t *buf, uint32_t x, 211623e0be93Smglocker uint32_t y, uint16_t width) 2117c197399bSmglocker { 211823e0be93Smglocker uint16_t lwidth; 211923e0be93Smglocker uint32_t off; 212023e0be93Smglocker int r; 2121fc15257dSmglocker 2122fc15257dSmglocker r = udl_cmd_insert_check(sc, UDL_CMD_WRITE_MAX_SIZE); 2123fc15257dSmglocker if (r != 0) 2124fc15257dSmglocker return (r); 2125c197399bSmglocker 212623e0be93Smglocker off = ((y * sc->sc_width) + x) * 2; 2127c197399bSmglocker lwidth = width * 2; 2128c197399bSmglocker 2129c197399bSmglocker udl_cmd_insert_int_1(sc, UDL_BULK_SOC); 2130c197399bSmglocker udl_cmd_insert_int_1(sc, UDL_BULK_CMD_FB_WRITE | UDL_BULK_CMD_FB_WORD); 213123e0be93Smglocker udl_cmd_insert_int_3(sc, off); 2132b1f23cbdSmglocker udl_cmd_insert_int_1(sc, width >= UDL_CMD_MAX_PIXEL_COUNT ? 0 : width); 2133c197399bSmglocker 213423e0be93Smglocker udl_cmd_insert_buf(sc, buf, lwidth); 213523e0be93Smglocker 213623e0be93Smglocker return (0); 2137c197399bSmglocker } 2138c197399bSmglocker 213923e0be93Smglocker int 214023e0be93Smglocker udl_fb_block_write(struct udl_softc *sc, uint16_t rgb16, uint32_t x, 214123e0be93Smglocker uint32_t y, uint32_t width, uint32_t height) 214223e0be93Smglocker { 214323e0be93Smglocker uint32_t i; 214423e0be93Smglocker int r; 214523e0be93Smglocker 214623e0be93Smglocker for (i = 0; i < height; i++) { 214723e0be93Smglocker r = udl_fb_line_write(sc, rgb16, x, y + i, width); 214823e0be93Smglocker if (r != 0) 214923e0be93Smglocker return (r); 215023e0be93Smglocker } 2151fc15257dSmglocker 2152fc15257dSmglocker return (0); 2153c197399bSmglocker } 2154c197399bSmglocker 2155fc15257dSmglocker int 21562c2babadSmglocker udl_fb_line_write(struct udl_softc *sc, uint16_t rgb16, uint32_t x, 2157c197399bSmglocker uint32_t y, uint32_t width) 2158c197399bSmglocker { 2159c197399bSmglocker uint32_t off, block; 2160fc15257dSmglocker int r; 2161c197399bSmglocker 2162c197399bSmglocker off = (y * sc->sc_width) + x; 2163c197399bSmglocker 2164c197399bSmglocker while (width) { 2165c197399bSmglocker if (width > UDL_CMD_MAX_PIXEL_COUNT) 2166c197399bSmglocker block = UDL_CMD_MAX_PIXEL_COUNT; 2167c197399bSmglocker else 2168c197399bSmglocker block = width; 2169c197399bSmglocker 2170fc15257dSmglocker r = udl_fb_off_write(sc, rgb16, off, block); 2171fc15257dSmglocker if (r != 0) 2172fc15257dSmglocker return (r); 2173c197399bSmglocker 2174c197399bSmglocker off += block; 2175c197399bSmglocker width -= block; 2176c197399bSmglocker } 2177fc15257dSmglocker 2178fc15257dSmglocker return (0); 2179c197399bSmglocker } 2180c197399bSmglocker 2181fc15257dSmglocker int 218223e0be93Smglocker udl_fb_off_write(struct udl_softc *sc, uint16_t rgb16, uint32_t off, 218323e0be93Smglocker uint16_t width) 2184c197399bSmglocker { 218523e0be93Smglocker uint8_t buf[UDL_CMD_MAX_DATA_SIZE]; 218623e0be93Smglocker uint16_t lwidth, lrgb16; 218723e0be93Smglocker uint32_t loff; 218823e0be93Smglocker int i, r; 2189fc15257dSmglocker 2190fc15257dSmglocker r = udl_cmd_insert_check(sc, UDL_CMD_WRITE_MAX_SIZE); 2191fc15257dSmglocker if (r != 0) 2192fc15257dSmglocker return (r); 21934be1f5e5Smglocker 219423e0be93Smglocker loff = off * 2; 21954be1f5e5Smglocker lwidth = width * 2; 21964be1f5e5Smglocker 21974be1f5e5Smglocker udl_cmd_insert_int_1(sc, UDL_BULK_SOC); 21984be1f5e5Smglocker udl_cmd_insert_int_1(sc, UDL_BULK_CMD_FB_WRITE | UDL_BULK_CMD_FB_WORD); 219923e0be93Smglocker udl_cmd_insert_int_3(sc, loff); 22004be1f5e5Smglocker udl_cmd_insert_int_1(sc, width >= UDL_CMD_MAX_PIXEL_COUNT ? 0 : width); 22014be1f5e5Smglocker 220223e0be93Smglocker for (i = 0; i < lwidth; i += 2) { 220323e0be93Smglocker lrgb16 = htobe16(rgb16); 220423e0be93Smglocker bcopy(&lrgb16, buf + i, 2); 220523e0be93Smglocker } 220623e0be93Smglocker 22074be1f5e5Smglocker udl_cmd_insert_buf(sc, buf, lwidth); 2208fc15257dSmglocker 2209fc15257dSmglocker return (0); 22104be1f5e5Smglocker } 22114be1f5e5Smglocker 2212fc15257dSmglocker int 221323e0be93Smglocker udl_fb_block_copy(struct udl_softc *sc, uint32_t src_x, uint32_t src_y, 221423e0be93Smglocker uint32_t dst_x, uint32_t dst_y, uint32_t width, uint32_t height) 2215c197399bSmglocker { 221623e0be93Smglocker int i, r; 2217fc15257dSmglocker 221823e0be93Smglocker for (i = 0; i < height; i++) { 221923e0be93Smglocker r = udl_fb_line_copy(sc, src_x, src_y + i, dst_x, dst_y + i, 222023e0be93Smglocker width); 2221fc15257dSmglocker if (r != 0) 2222fc15257dSmglocker return (r); 222323e0be93Smglocker } 2224fc15257dSmglocker 2225fc15257dSmglocker return (0); 2226c197399bSmglocker } 2227c197399bSmglocker 222823e0be93Smglocker 2229fc15257dSmglocker int 22302c2babadSmglocker udl_fb_line_copy(struct udl_softc *sc, uint32_t src_x, uint32_t src_y, 2231c197399bSmglocker uint32_t dst_x, uint32_t dst_y, uint32_t width) 2232c197399bSmglocker { 2233c197399bSmglocker uint32_t src_off, dst_off, block; 2234fc15257dSmglocker int r; 2235c197399bSmglocker 2236c197399bSmglocker src_off = (src_y * sc->sc_width) + src_x; 2237c197399bSmglocker dst_off = (dst_y * sc->sc_width) + dst_x; 2238c197399bSmglocker 2239c197399bSmglocker while (width) { 2240c197399bSmglocker if (width > UDL_CMD_MAX_PIXEL_COUNT) 2241c197399bSmglocker block = UDL_CMD_MAX_PIXEL_COUNT; 2242c197399bSmglocker else 2243c197399bSmglocker block = width; 2244c197399bSmglocker 2245fc15257dSmglocker r = udl_fb_off_copy(sc, src_off, dst_off, block); 2246fc15257dSmglocker if (r != 0) 2247fc15257dSmglocker return (r); 2248c197399bSmglocker 2249c197399bSmglocker src_off += block; 2250c197399bSmglocker dst_off += block; 2251c197399bSmglocker width -= block; 2252c197399bSmglocker } 2253fc15257dSmglocker 2254fc15257dSmglocker return (0); 2255c197399bSmglocker } 2256c197399bSmglocker 2257fc15257dSmglocker int 225823e0be93Smglocker udl_fb_off_copy(struct udl_softc *sc, uint32_t src_off, uint32_t dst_off, 225923e0be93Smglocker uint16_t width) 2260c197399bSmglocker { 226123e0be93Smglocker uint32_t ldst_off, lsrc_off; 226223e0be93Smglocker int r; 2263c197399bSmglocker 226423e0be93Smglocker r = udl_cmd_insert_check(sc, UDL_CMD_COPY_MAX_SIZE); 2265fc15257dSmglocker if (r != 0) 2266fc15257dSmglocker return (r); 226723e0be93Smglocker 226823e0be93Smglocker ldst_off = dst_off * 2; 226923e0be93Smglocker lsrc_off = src_off * 2; 227023e0be93Smglocker 227123e0be93Smglocker udl_cmd_insert_int_1(sc, UDL_BULK_SOC); 227223e0be93Smglocker udl_cmd_insert_int_1(sc, UDL_BULK_CMD_FB_COPY | UDL_BULK_CMD_FB_WORD); 227323e0be93Smglocker udl_cmd_insert_int_3(sc, ldst_off); 227423e0be93Smglocker udl_cmd_insert_int_1(sc, width >= UDL_CMD_MAX_PIXEL_COUNT ? 0 : width); 227523e0be93Smglocker udl_cmd_insert_int_3(sc, lsrc_off); 227623e0be93Smglocker 227723e0be93Smglocker return (0); 227823e0be93Smglocker } 227923e0be93Smglocker 228023e0be93Smglocker int 228123e0be93Smglocker udl_fb_buf_write_comp(struct udl_softc *sc, uint8_t *buf, uint32_t x, 228223e0be93Smglocker uint32_t y, uint16_t width) 228323e0be93Smglocker { 228423e0be93Smglocker struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 228523e0be93Smglocker uint8_t *count; 228623e0be93Smglocker uint16_t lwidth; 228723e0be93Smglocker uint32_t off; 228823e0be93Smglocker int r, sent; 228923e0be93Smglocker 229023e0be93Smglocker r = udl_cmd_insert_check(sc, UDL_CMD_WRITE_MAX_SIZE); 229123e0be93Smglocker if (r != 0) 229223e0be93Smglocker return (r); 229323e0be93Smglocker 229423e0be93Smglocker off = ((y * sc->sc_width) + x) * 2; 229523e0be93Smglocker lwidth = width * 2; 229623e0be93Smglocker 229723e0be93Smglocker /* 229823e0be93Smglocker * A new compressed stream needs the 0xff-into-UDL_REG_SYNC-register 229923e0be93Smglocker * sequence always as first command. 230023e0be93Smglocker */ 230123e0be93Smglocker if (cb->off == 0) 230223e0be93Smglocker udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0xff); 230323e0be93Smglocker 230423e0be93Smglocker r = sent = 0; 230523e0be93Smglocker while (sent < lwidth) { 230623e0be93Smglocker udl_cmd_insert_int_1(sc, UDL_BULK_SOC); 230723e0be93Smglocker udl_cmd_insert_int_1(sc, 230823e0be93Smglocker UDL_BULK_CMD_FB_WRITE | 230923e0be93Smglocker UDL_BULK_CMD_FB_WORD | 231023e0be93Smglocker UDL_BULK_CMD_FB_COMP); 231123e0be93Smglocker udl_cmd_insert_int_3(sc, off + sent); 231223e0be93Smglocker udl_cmd_insert_int_1(sc, 231323e0be93Smglocker width >= UDL_CMD_MAX_PIXEL_COUNT ? 0 : width); 231423e0be93Smglocker cb->compblock += UDL_CMD_WRITE_HEAD_SIZE; 231523e0be93Smglocker 231623e0be93Smglocker count = &cb->buf[cb->off - 1]; 231723e0be93Smglocker r = udl_cmd_insert_buf_comp(sc, buf + sent, lwidth - sent); 231823e0be93Smglocker if (r > 0 && r != (lwidth - sent)) { 231923e0be93Smglocker *count = r / 2; 232023e0be93Smglocker width -= r / 2; 232123e0be93Smglocker } 232223e0be93Smglocker sent += r; 232323e0be93Smglocker } 232423e0be93Smglocker 232523e0be93Smglocker return (0); 232623e0be93Smglocker } 232723e0be93Smglocker 232823e0be93Smglocker int 232923e0be93Smglocker udl_fb_block_write_comp(struct udl_softc *sc, uint16_t rgb16, uint32_t x, 233023e0be93Smglocker uint32_t y, uint32_t width, uint32_t height) 233123e0be93Smglocker { 233223e0be93Smglocker uint32_t i; 233323e0be93Smglocker int r; 233423e0be93Smglocker 233523e0be93Smglocker for (i = 0; i < height; i++) { 233623e0be93Smglocker r = udl_fb_line_write_comp(sc, rgb16, x, y + i, width); 233723e0be93Smglocker if (r != 0) 233823e0be93Smglocker return (r); 233923e0be93Smglocker } 234023e0be93Smglocker 234123e0be93Smglocker return (0); 234223e0be93Smglocker } 234323e0be93Smglocker 234423e0be93Smglocker int 234523e0be93Smglocker udl_fb_line_write_comp(struct udl_softc *sc, uint16_t rgb16, uint32_t x, 234623e0be93Smglocker uint32_t y, uint32_t width) 234723e0be93Smglocker { 234823e0be93Smglocker uint32_t off, block; 234923e0be93Smglocker int r; 235023e0be93Smglocker 235123e0be93Smglocker off = (y * sc->sc_width) + x; 235223e0be93Smglocker 235323e0be93Smglocker while (width) { 235423e0be93Smglocker if (width > UDL_CMD_MAX_PIXEL_COUNT) 235523e0be93Smglocker block = UDL_CMD_MAX_PIXEL_COUNT; 235623e0be93Smglocker else 235723e0be93Smglocker block = width; 235823e0be93Smglocker 2359034172a0Smglocker r = udl_fb_off_write_comp(sc, rgb16, off, block); 236023e0be93Smglocker if (r != 0) 236123e0be93Smglocker return (r); 236223e0be93Smglocker 236323e0be93Smglocker off += block; 236423e0be93Smglocker width -= block; 2365c197399bSmglocker } 2366c197399bSmglocker 2367fc15257dSmglocker return (0); 2368fc15257dSmglocker } 2369fc15257dSmglocker 2370fc15257dSmglocker int 23712fa8dc63Smglocker udl_fb_off_write_comp(struct udl_softc *sc, uint16_t rgb16, uint32_t off, 23722fa8dc63Smglocker uint16_t width) 23732fa8dc63Smglocker { 23742fa8dc63Smglocker struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 23752fa8dc63Smglocker uint8_t buf[UDL_CMD_MAX_DATA_SIZE]; 23762fa8dc63Smglocker uint8_t *count; 23772fa8dc63Smglocker uint16_t lwidth, lrgb16; 23782fa8dc63Smglocker uint32_t loff; 23792fa8dc63Smglocker int i, r, sent; 23802fa8dc63Smglocker 2381fc15257dSmglocker r = udl_cmd_insert_check(sc, UDL_CMD_WRITE_MAX_SIZE); 2382fc15257dSmglocker if (r != 0) 2383fc15257dSmglocker return (r); 2384fc15257dSmglocker 23852fa8dc63Smglocker loff = off * 2; 23862fa8dc63Smglocker lwidth = width * 2; 23872fa8dc63Smglocker 23882fa8dc63Smglocker for (i = 0; i < lwidth; i += 2) { 23892fa8dc63Smglocker lrgb16 = htobe16(rgb16); 2390a2cff4d1Smglocker bcopy(&lrgb16, buf + i, 2); 23912fa8dc63Smglocker } 23922fa8dc63Smglocker 23932fa8dc63Smglocker /* 23942fa8dc63Smglocker * A new compressed stream needs the 0xff-into-UDL_REG_SYNC-register 23952fa8dc63Smglocker * sequence always as first command. 23962fa8dc63Smglocker */ 23972fa8dc63Smglocker if (cb->off == 0) 23982fa8dc63Smglocker udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0xff); 23992fa8dc63Smglocker 24002fa8dc63Smglocker r = sent = 0; 24012fa8dc63Smglocker while (sent < lwidth) { 24022fa8dc63Smglocker udl_cmd_insert_int_1(sc, UDL_BULK_SOC); 24032fa8dc63Smglocker udl_cmd_insert_int_1(sc, 24042fa8dc63Smglocker UDL_BULK_CMD_FB_WRITE | 24052fa8dc63Smglocker UDL_BULK_CMD_FB_WORD | 24062fa8dc63Smglocker UDL_BULK_CMD_FB_COMP); 24072fa8dc63Smglocker udl_cmd_insert_int_3(sc, loff + sent); 24082fa8dc63Smglocker udl_cmd_insert_int_1(sc, 24092fa8dc63Smglocker width >= UDL_CMD_MAX_PIXEL_COUNT ? 0 : width); 24102fa8dc63Smglocker cb->compblock += UDL_CMD_WRITE_HEAD_SIZE; 24112fa8dc63Smglocker 24122fa8dc63Smglocker count = &cb->buf[cb->off - 1]; 24132fa8dc63Smglocker r = udl_cmd_insert_buf_comp(sc, buf + sent, lwidth - sent); 24142fa8dc63Smglocker if (r > 0 && r != (lwidth - sent)) { 24152fa8dc63Smglocker *count = r / 2; 24162fa8dc63Smglocker width -= r / 2; 24172fa8dc63Smglocker } 24182fa8dc63Smglocker sent += r; 24192fa8dc63Smglocker } 2420fc15257dSmglocker 2421fc15257dSmglocker return (0); 24222fa8dc63Smglocker } 24232fa8dc63Smglocker 2424fc15257dSmglocker int 242523e0be93Smglocker udl_fb_block_copy_comp(struct udl_softc *sc, uint32_t src_x, uint32_t src_y, 242623e0be93Smglocker uint32_t dst_x, uint32_t dst_y, uint32_t width, uint32_t height) 24272fa8dc63Smglocker { 242823e0be93Smglocker int i, r; 242923e0be93Smglocker 243023e0be93Smglocker for (i = 0; i < height; i++) { 243123e0be93Smglocker r = udl_fb_line_copy_comp(sc, src_x, src_y + i, 243223e0be93Smglocker dst_x, dst_y + i, width); 243323e0be93Smglocker if (r != 0) 243423e0be93Smglocker return (r); 243523e0be93Smglocker } 243623e0be93Smglocker 243723e0be93Smglocker return (0); 243823e0be93Smglocker } 243923e0be93Smglocker 244023e0be93Smglocker int 244123e0be93Smglocker udl_fb_line_copy_comp(struct udl_softc *sc, uint32_t src_x, uint32_t src_y, 244223e0be93Smglocker uint32_t dst_x, uint32_t dst_y, uint32_t width) 244323e0be93Smglocker { 244423e0be93Smglocker uint32_t src_off, dst_off, block; 2445fc15257dSmglocker int r; 24462fa8dc63Smglocker 244723e0be93Smglocker src_off = (src_y * sc->sc_width) + src_x; 244823e0be93Smglocker dst_off = (dst_y * sc->sc_width) + dst_x; 24492fa8dc63Smglocker 24502fa8dc63Smglocker while (width) { 24512fa8dc63Smglocker if (width > UDL_CMD_MAX_PIXEL_COUNT) 24522fa8dc63Smglocker block = UDL_CMD_MAX_PIXEL_COUNT; 24532fa8dc63Smglocker else 24542fa8dc63Smglocker block = width; 24552fa8dc63Smglocker 245623e0be93Smglocker r = udl_fb_off_copy_comp(sc, src_off, dst_off, block); 2457fc15257dSmglocker if (r != 0) 2458fc15257dSmglocker return (r); 24592fa8dc63Smglocker 246023e0be93Smglocker src_off += block; 246123e0be93Smglocker dst_off += block; 24622fa8dc63Smglocker width -= block; 24632fa8dc63Smglocker } 2464fc15257dSmglocker 2465fc15257dSmglocker return (0); 24662fa8dc63Smglocker } 24672fa8dc63Smglocker 2468fc15257dSmglocker int 24692fa8dc63Smglocker udl_fb_off_copy_comp(struct udl_softc *sc, uint32_t src_off, uint32_t dst_off, 24702fa8dc63Smglocker uint16_t width) 24712fa8dc63Smglocker { 24722fa8dc63Smglocker struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 24732fa8dc63Smglocker uint32_t ldst_off, lsrc_off; 24742fa8dc63Smglocker int r; 24752fa8dc63Smglocker 2476fc15257dSmglocker r = udl_cmd_insert_check(sc, UDL_CMD_COPY_MAX_SIZE); 2477fc15257dSmglocker if (r != 0) 2478fc15257dSmglocker return (r); 2479fc15257dSmglocker 24802fa8dc63Smglocker ldst_off = dst_off * 2; 24812fa8dc63Smglocker lsrc_off = src_off * 2; 24822fa8dc63Smglocker 24832fa8dc63Smglocker /* 24842fa8dc63Smglocker * A new compressed stream needs the 0xff-into-UDL_REG_SYNC-register 24852fa8dc63Smglocker * sequence always as first command. 24862fa8dc63Smglocker */ 24872fa8dc63Smglocker if (cb->off == 0) 24882fa8dc63Smglocker udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0xff); 24892fa8dc63Smglocker 24902fa8dc63Smglocker r = 0; 24912fa8dc63Smglocker while (r < 1) { 24922fa8dc63Smglocker udl_cmd_insert_int_1(sc, UDL_BULK_SOC); 24932fa8dc63Smglocker udl_cmd_insert_int_1(sc, 24942fa8dc63Smglocker UDL_BULK_CMD_FB_COPY | UDL_BULK_CMD_FB_WORD); 24952fa8dc63Smglocker udl_cmd_insert_int_3(sc, ldst_off); 24962fa8dc63Smglocker udl_cmd_insert_int_1(sc, 24972fa8dc63Smglocker width >= UDL_CMD_MAX_PIXEL_COUNT ? 0 : width); 24982fa8dc63Smglocker udl_cmd_insert_int_3(sc, lsrc_off); 24992fa8dc63Smglocker cb->compblock += UDL_CMD_COPY_HEAD_SIZE; 25002fa8dc63Smglocker 25012fa8dc63Smglocker r = udl_cmd_insert_head_comp(sc, UDL_CMD_COPY_HEAD_SIZE); 25022fa8dc63Smglocker } 2503fc15257dSmglocker 2504fc15257dSmglocker return (0); 25052fa8dc63Smglocker } 25062fa8dc63Smglocker 2507c197399bSmglocker /* ---------- */ 2508c197399bSmglocker #ifdef UDL_DEBUG 2509c197399bSmglocker void 2510c197399bSmglocker udl_hexdump(void *buf, int len, int quiet) 2511c197399bSmglocker { 2512c197399bSmglocker int i; 2513c197399bSmglocker 2514c197399bSmglocker for (i = 0; i < len; i++) { 2515c197399bSmglocker if (quiet == 0) { 2516c197399bSmglocker if (i % 16 == 0) 2517c197399bSmglocker printf("%s%5i:", i ? "\n" : "", i); 2518c197399bSmglocker if (i % 4 == 0) 2519c197399bSmglocker printf(" "); 2520c197399bSmglocker } 2521c197399bSmglocker printf("%02x", (int)*((u_char *)buf + i)); 2522c197399bSmglocker } 2523c197399bSmglocker printf("\n"); 2524c197399bSmglocker } 2525c197399bSmglocker 2526c197399bSmglocker usbd_status 2527c197399bSmglocker udl_init_test(struct udl_softc *sc) 2528c197399bSmglocker { 2529c197399bSmglocker int i, j, parts, loops; 2530c197399bSmglocker uint16_t color; 2531c197399bSmglocker uint16_t rgb24[3] = { 0xf800, 0x07e0, 0x001f }; 2532c197399bSmglocker 2533b1f23cbdSmglocker loops = (sc->sc_width * sc->sc_height) / UDL_CMD_MAX_PIXEL_COUNT; 2534c197399bSmglocker parts = loops / 3; 2535c197399bSmglocker color = rgb24[0]; 2536c197399bSmglocker 2537c197399bSmglocker j = 1; 2538c197399bSmglocker for (i = 0; i < loops; i++) { 2539c197399bSmglocker if (i == parts) { 2540c197399bSmglocker color = rgb24[j]; 2541c197399bSmglocker parts += parts; 2542c197399bSmglocker j++; 2543c197399bSmglocker } 25442fa8dc63Smglocker (sc->udl_fb_off_write)(sc, color, i * UDL_CMD_MAX_PIXEL_COUNT, 2545c197399bSmglocker UDL_CMD_MAX_PIXEL_COUNT); 2546c197399bSmglocker } 2547c197399bSmglocker (void)udl_cmd_send(sc); 2548c197399bSmglocker 2549c197399bSmglocker return (USBD_NORMAL_COMPLETION); 2550c197399bSmglocker } 2551c197399bSmglocker #endif 2552