1 /* $OpenBSD: udl.c,v 1.99 2023/05/10 18:28:04 miod Exp $ */ 2 3 /* 4 * Copyright (c) 2009 Marcus Glocker <mglocker@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 /* 20 * Driver for the ``DisplayLink DL-120 / DL-160'' graphic chips based 21 * on the reversed engineered specifications of Florian Echtler 22 * <floe@butterbrot.org>: 23 * 24 * http://floe.butterbrot.org/displaylink/doku.php 25 * 26 * This driver has been inspired by the cfxga(4) driver because we have 27 * to deal with similar challenges, like no direct access to the video 28 * memory. 29 */ 30 31 #include <sys/param.h> 32 #include <sys/device.h> 33 #include <sys/kernel.h> 34 #include <sys/malloc.h> 35 #include <sys/systm.h> 36 37 #include <uvm/uvm_extern.h> 38 39 #include <dev/usb/usb.h> 40 #include <dev/usb/usbdi.h> 41 #include <dev/usb/usbdi_util.h> 42 #include <dev/usb/usbdevs.h> 43 44 #include <dev/wscons/wsconsio.h> 45 #include <dev/wscons/wsdisplayvar.h> 46 #include <dev/rasops/rasops.h> 47 48 #include <dev/videomode/videomode.h> 49 #include <dev/videomode/edidvar.h> 50 51 #include <dev/usb/udl.h> 52 #include <dev/usb/udlio.h> 53 54 /* 55 * Defines. 56 */ 57 #if 0 58 #define UDL_DEBUG 59 #endif 60 #ifdef UDL_DEBUG 61 int udl_debug = 1; 62 #define DPRINTF(l, x...) do { if ((l) <= udl_debug) printf(x); } while (0) 63 #else 64 #define DPRINTF(l, x...) 65 #endif 66 67 #define DN(sc) ((sc)->sc_dev.dv_xname) 68 #define FUNC __func__ 69 70 /* 71 * Prototypes. 72 */ 73 int udl_match(struct device *, void *, void *); 74 void udl_attach(struct device *, struct device *, void *); 75 void udl_attach_hook(struct device *); 76 int udl_detach(struct device *, int); 77 int udl_activate(struct device *, int); 78 79 int udl_ioctl(void *, u_long, caddr_t, int, struct proc *); 80 paddr_t udl_mmap(void *, off_t, int); 81 int udl_alloc_screen(void *, const struct wsscreen_descr *, 82 void **, int *, int *, uint32_t *); 83 void udl_free_screen(void *, void *); 84 int udl_show_screen(void *, void *, int, 85 void (*)(void *, int, int), void *); 86 int udl_load_font(void *, void *, struct wsdisplay_font *); 87 int udl_list_font(void *, struct wsdisplay_font *); 88 void udl_burner(void *, u_int, u_int); 89 90 int udl_copycols(void *, int, int, int, int); 91 int udl_copyrows(void *, int, int, int); 92 int udl_erasecols(void *, int, int, int, uint32_t); 93 int udl_eraserows(void *, int, int, uint32_t); 94 int udl_putchar(void *, int, int, u_int, uint32_t); 95 int udl_do_cursor(struct rasops_info *); 96 int udl_draw_char(struct udl_softc *, uint16_t, uint16_t, u_int, 97 uint32_t, uint32_t); 98 int udl_damage(struct udl_softc *, uint8_t *, 99 uint32_t, uint32_t, uint32_t, uint32_t); 100 int udl_draw_image(struct udl_softc *, uint8_t *, 101 uint32_t, uint32_t, uint32_t, uint32_t); 102 103 usbd_status udl_ctrl_msg(struct udl_softc *, uint8_t, uint8_t, 104 uint16_t, uint16_t, uint8_t *, size_t); 105 usbd_status udl_poll(struct udl_softc *, uint32_t *); 106 usbd_status udl_read_1(struct udl_softc *, uint16_t, uint8_t *); 107 usbd_status udl_write_1(struct udl_softc *, uint16_t, uint8_t); 108 usbd_status udl_read_edid(struct udl_softc *, uint8_t *); 109 uint8_t udl_lookup_mode(uint16_t, uint16_t, uint8_t, uint16_t, 110 uint32_t); 111 int udl_select_chip(struct udl_softc *); 112 usbd_status udl_set_enc_key(struct udl_softc *, uint8_t *, uint8_t); 113 usbd_status udl_set_decomp_table(struct udl_softc *, uint8_t *, uint16_t); 114 115 int udl_load_huffman(struct udl_softc *); 116 void udl_free_huffman(struct udl_softc *); 117 int udl_fbmem_alloc(struct udl_softc *); 118 void udl_fbmem_free(struct udl_softc *); 119 usbd_status udl_cmd_alloc_xfer(struct udl_softc *); 120 void udl_cmd_free_xfer(struct udl_softc *); 121 int udl_cmd_alloc_buf(struct udl_softc *); 122 void udl_cmd_free_buf(struct udl_softc *); 123 void udl_cmd_insert_int_1(struct udl_softc *, uint8_t); 124 void udl_cmd_insert_int_2(struct udl_softc *, uint16_t); 125 void udl_cmd_insert_int_3(struct udl_softc *, uint32_t); 126 void udl_cmd_insert_int_4(struct udl_softc *, uint32_t); 127 void udl_cmd_insert_buf(struct udl_softc *, uint8_t *, uint32_t); 128 int udl_cmd_insert_buf_comp(struct udl_softc *, uint8_t *, 129 uint32_t); 130 int udl_cmd_insert_head_comp(struct udl_softc *, uint32_t); 131 int udl_cmd_insert_check(struct udl_softc *, int); 132 void udl_cmd_set_xfer_type(struct udl_softc *, int); 133 void udl_cmd_save_offset(struct udl_softc *); 134 void udl_cmd_restore_offset(struct udl_softc *); 135 void udl_cmd_write_reg_1(struct udl_softc *, uint8_t, uint8_t); 136 void udl_cmd_write_reg_3(struct udl_softc *, uint8_t, uint32_t); 137 usbd_status udl_cmd_send(struct udl_softc *); 138 usbd_status udl_cmd_send_async(struct udl_softc *); 139 void udl_cmd_send_async_cb(struct usbd_xfer *, void *, usbd_status); 140 141 usbd_status udl_init_chip(struct udl_softc *); 142 void udl_init_fb_offsets(struct udl_softc *, uint32_t, uint32_t, 143 uint32_t, uint32_t); 144 usbd_status udl_init_resolution(struct udl_softc *); 145 usbd_status udl_clear_screen(struct udl_softc *); 146 void udl_select_mode(struct udl_softc *); 147 int udl_fb_buf_write(struct udl_softc *, uint8_t *, uint32_t, 148 uint32_t, uint16_t); 149 int udl_fb_block_write(struct udl_softc *, uint16_t, uint32_t, 150 uint32_t, uint32_t, uint32_t); 151 int udl_fb_line_write(struct udl_softc *, uint16_t, uint32_t, 152 uint32_t, uint32_t); 153 int udl_fb_off_write(struct udl_softc *, uint16_t, uint32_t, 154 uint16_t); 155 int udl_fb_block_copy(struct udl_softc *, uint32_t, uint32_t, 156 uint32_t, uint32_t, uint32_t, uint32_t); 157 int udl_fb_line_copy(struct udl_softc *, uint32_t, uint32_t, 158 uint32_t, uint32_t, uint32_t); 159 int udl_fb_off_copy(struct udl_softc *, uint32_t, uint32_t, 160 uint16_t); 161 int udl_fb_buf_write_comp(struct udl_softc *, uint8_t *, uint32_t, 162 uint32_t, uint16_t); 163 int udl_fb_block_write_comp(struct udl_softc *, uint16_t, uint32_t, 164 uint32_t, uint32_t, uint32_t); 165 int udl_fb_line_write_comp(struct udl_softc *, uint16_t, uint32_t, 166 uint32_t, uint32_t); 167 int udl_fb_off_write_comp(struct udl_softc *, uint16_t, uint32_t, 168 uint16_t); 169 int udl_fb_block_copy_comp(struct udl_softc *, uint32_t, uint32_t, 170 uint32_t, uint32_t, uint32_t, uint32_t); 171 int udl_fb_line_copy_comp(struct udl_softc *, uint32_t, uint32_t, 172 uint32_t, uint32_t, uint32_t); 173 int udl_fb_off_copy_comp(struct udl_softc *, uint32_t, uint32_t, 174 uint16_t); 175 #ifdef UDL_DEBUG 176 void udl_hexdump(void *, int, int); 177 usbd_status udl_init_test(struct udl_softc *); 178 #endif 179 180 /* 181 * Driver glue. 182 */ 183 struct cfdriver udl_cd = { 184 NULL, "udl", DV_DULL 185 }; 186 187 const struct cfattach udl_ca = { 188 sizeof(struct udl_softc), 189 udl_match, 190 udl_attach, 191 udl_detach, 192 udl_activate 193 }; 194 195 /* 196 * wsdisplay glue. 197 */ 198 struct wsscreen_descr udl_stdscreen = { 199 "std", /* name */ 200 0, 0, /* ncols, nrows */ 201 NULL, /* textops */ 202 0, 0, /* fontwidth, fontheight */ 203 WSSCREEN_WSCOLORS /* capabilities */ 204 }; 205 206 const struct wsscreen_descr *udl_scrlist[] = { 207 &udl_stdscreen 208 }; 209 210 struct wsscreen_list udl_screenlist = { 211 sizeof(udl_scrlist) / sizeof(struct wsscreen_descr *), udl_scrlist 212 }; 213 214 struct wsdisplay_accessops udl_accessops = { 215 .ioctl = udl_ioctl, 216 .mmap = udl_mmap, 217 .alloc_screen = udl_alloc_screen, 218 .free_screen = udl_free_screen, 219 .show_screen = udl_show_screen, 220 .load_font = udl_load_font, 221 .list_font = udl_list_font, 222 .burn_screen = udl_burner 223 }; 224 225 /* 226 * Matching devices. 227 */ 228 struct udl_type { 229 struct usb_devno udl_dev; 230 uint16_t udl_chip; 231 }; 232 233 static const struct udl_type udl_devs[] = { 234 { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LCD4300U }, DL120 }, 235 { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LCD8000U }, DL120 }, 236 { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_GUC2020 }, DL160 }, 237 { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LD220 }, DL165 }, 238 { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_VCUD60 }, DL160 }, 239 { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_DLDVI }, DL160 }, 240 { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_VGA10 }, DL120 }, 241 { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_WSDVI }, DLUNK }, 242 { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_EC008 }, DL160 }, 243 { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_HPDOCK }, DL160 }, 244 { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_NL571 }, DL160 }, 245 { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_M01061 }, DL195 }, 246 { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_NBDOCK }, DL165 }, 247 { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_SWDVI }, DLUNK }, 248 { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_UM7X0 }, DL120 }, 249 { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_CONV }, DL160 }, 250 { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LUM70 }, DL125 }, 251 { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_POLARIS2 }, DLUNK }, 252 { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LT1421 }, DLUNK }, 253 { { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_TOSHIBA }, DLUNK } 254 }; 255 #define udl_lookup(v, p) ((struct udl_type *)usb_lookup(udl_devs, v, p)) 256 257 int 258 udl_match(struct device *parent, void *match, void *aux) 259 { 260 struct usb_attach_arg *uaa = aux; 261 262 if (uaa->iface == NULL || uaa->configno != 1) 263 return (UMATCH_NONE); 264 265 if (udl_lookup(uaa->vendor, uaa->product) != NULL) 266 return (UMATCH_VENDOR_PRODUCT); 267 268 return (UMATCH_NONE); 269 } 270 271 void 272 udl_attach(struct device *parent, struct device *self, void *aux) 273 { 274 struct udl_softc *sc = (struct udl_softc *)self; 275 struct usb_attach_arg *uaa = aux; 276 struct wsemuldisplaydev_attach_args aa; 277 usbd_status error; 278 int err, i; 279 280 sc->sc_udev = uaa->device; 281 sc->sc_chip = udl_lookup(uaa->vendor, uaa->product)->udl_chip; 282 sc->sc_width = 0; 283 sc->sc_height = 0; 284 sc->sc_depth = 16; 285 sc->sc_cur_mode = MAX_DL_MODES; 286 287 /* 288 * Override chip if requested. 289 */ 290 if ((sc->sc_dev.dv_cfdata->cf_flags & 0xff00) > 0) { 291 i = ((sc->sc_dev.dv_cfdata->cf_flags & 0xff00) >> 8) - 1; 292 if (i <= DLMAX) { 293 sc->sc_chip = i; 294 printf("%s: %s: cf_flags (0x%04x) forced chip to %d\n", 295 DN(sc), FUNC, 296 sc->sc_dev.dv_cfdata->cf_flags, i); 297 } 298 } 299 300 /* 301 * The product might have more than one chip 302 */ 303 if (sc->sc_chip == DLUNK) 304 if (udl_select_chip(sc)) 305 return; 306 307 308 /* 309 * Create device handle to interface descriptor. 310 */ 311 error = usbd_device2interface_handle(sc->sc_udev, 0, &sc->sc_iface); 312 if (error != USBD_NORMAL_COMPLETION) 313 return; 314 315 /* 316 * Allocate bulk command xfer. 317 */ 318 error = udl_cmd_alloc_xfer(sc); 319 if (error != USBD_NORMAL_COMPLETION) 320 return; 321 322 /* 323 * Allocate command buffer. 324 */ 325 err = udl_cmd_alloc_buf(sc); 326 if (err != 0) 327 return; 328 329 /* 330 * Open bulk TX pipe. 331 */ 332 error = usbd_open_pipe(sc->sc_iface, 0x01, USBD_EXCLUSIVE_USE, 333 &sc->sc_tx_pipeh); 334 if (error != USBD_NORMAL_COMPLETION) 335 return; 336 337 /* 338 * Device initialization is done per synchronous xfers. 339 */ 340 udl_cmd_set_xfer_type(sc, UDL_CMD_XFER_SYNC); 341 342 /* 343 * Initialize chip. 344 */ 345 error = udl_init_chip(sc); 346 if (error != USBD_NORMAL_COMPLETION) 347 return; 348 349 /* 350 * Select edid mode. 351 */ 352 udl_select_mode(sc); 353 354 /* 355 * Override mode if requested. 356 */ 357 if ((sc->sc_dev.dv_cfdata->cf_flags & 0xff) > 0) { 358 i = (sc->sc_dev.dv_cfdata->cf_flags & 0xff) - 1; 359 360 if (i < MAX_DL_MODES) { 361 if (udl_modes[i].chip <= sc->sc_chip) { 362 sc->sc_width = udl_modes[i].hdisplay; 363 sc->sc_height = udl_modes[i].vdisplay; 364 printf("%s: %s: cf_flags (0x%04x) ", 365 DN(sc), FUNC, 366 sc->sc_dev.dv_cfdata->cf_flags); 367 printf("forced mode to %d\n", i); 368 sc->sc_cur_mode = i; 369 } 370 } 371 } 372 373 error = udl_init_resolution(sc); 374 if (error != USBD_NORMAL_COMPLETION) 375 return; 376 377 /* 378 * Attach wsdisplay. 379 */ 380 aa.console = 0; 381 aa.scrdata = &udl_screenlist; 382 aa.accessops = &udl_accessops; 383 aa.accesscookie = sc; 384 aa.defaultscreens = 0; 385 386 sc->sc_wsdisplay = config_found(self, &aa, wsemuldisplaydevprint); 387 388 /* 389 * Load Huffman table. 390 */ 391 config_mountroot(self, udl_attach_hook); 392 } 393 394 void 395 udl_attach_hook(struct device *self) 396 { 397 struct udl_softc *sc = (struct udl_softc *)self; 398 399 if (udl_load_huffman(sc) != 0) { 400 /* compression not possible */ 401 printf("%s: run in uncompressed mode\n", DN(sc)); 402 sc->udl_fb_buf_write = udl_fb_buf_write; 403 sc->udl_fb_block_write = udl_fb_block_write; 404 sc->udl_fb_line_write = udl_fb_line_write; 405 sc->udl_fb_off_write = udl_fb_off_write; 406 sc->udl_fb_block_copy = udl_fb_block_copy; 407 sc->udl_fb_line_copy = udl_fb_line_copy; 408 sc->udl_fb_off_copy = udl_fb_off_copy; 409 } else { 410 /* compression possible */ 411 sc->udl_fb_buf_write = udl_fb_buf_write_comp; 412 sc->udl_fb_block_write = udl_fb_block_write_comp; 413 sc->udl_fb_line_write = udl_fb_line_write_comp; 414 sc->udl_fb_off_write = udl_fb_off_write_comp; 415 sc->udl_fb_block_copy = udl_fb_block_copy_comp; 416 sc->udl_fb_line_copy = udl_fb_line_copy_comp; 417 sc->udl_fb_off_copy = udl_fb_off_copy_comp; 418 } 419 #ifdef UDL_DEBUG 420 if (udl_debug >= 4) 421 udl_init_test(sc); 422 #endif 423 /* 424 * From this point on we do asynchronous xfers. 425 */ 426 udl_cmd_set_xfer_type(sc, UDL_CMD_XFER_ASYNC); 427 428 /* 429 * Set initial wsdisplay emulation mode. 430 */ 431 sc->sc_mode = WSDISPLAYIO_MODE_EMUL; 432 } 433 434 int 435 udl_detach(struct device *self, int flags) 436 { 437 struct udl_softc *sc = (struct udl_softc *)self; 438 439 /* 440 * Close bulk TX pipe. 441 */ 442 if (sc->sc_tx_pipeh != NULL) 443 usbd_close_pipe(sc->sc_tx_pipeh); 444 445 /* 446 * Free command buffer. 447 */ 448 udl_cmd_free_buf(sc); 449 450 /* 451 * Free command xfer. 452 */ 453 udl_cmd_free_xfer(sc); 454 455 /* 456 * Free Huffman table. 457 */ 458 udl_free_huffman(sc); 459 460 /* 461 * Free framebuffer memory. 462 */ 463 udl_fbmem_free(sc); 464 465 /* 466 * Detach wsdisplay. 467 */ 468 if (sc->sc_wsdisplay != NULL) 469 config_detach(sc->sc_wsdisplay, DETACH_FORCE); 470 471 return (0); 472 } 473 474 int 475 udl_activate(struct device *self, int act) 476 { 477 struct udl_softc *sc = (struct udl_softc *)self; 478 int rv; 479 480 switch (act) { 481 case DVACT_DEACTIVATE: 482 usbd_deactivate(sc->sc_udev); 483 break; 484 } 485 rv = config_activate_children(self, act); 486 return (rv); 487 } 488 489 /* ---------- */ 490 491 int 492 udl_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) 493 { 494 struct udl_softc *sc; 495 struct wsdisplay_fbinfo *wdf; 496 struct udl_ioctl_damage *d; 497 int r, error, mode; 498 499 sc = v; 500 501 DPRINTF(1, "%s: %s: ('%c', %zu, %zu)\n", 502 DN(sc), FUNC, (int) IOCGROUP(cmd), cmd & 0xff, IOCPARM_LEN(cmd)); 503 504 switch (cmd) { 505 case WSDISPLAYIO_GTYPE: 506 *(u_int *)data = WSDISPLAY_TYPE_DL; 507 break; 508 case WSDISPLAYIO_GINFO: 509 wdf = (struct wsdisplay_fbinfo *)data; 510 wdf->height = sc->sc_height; 511 wdf->width = sc->sc_width; 512 wdf->depth = sc->sc_depth; 513 wdf->stride = sc->sc_width * (sc->sc_depth / 8); 514 wdf->offset = 0; 515 wdf->cmsize = 0; /* XXX fill up colormap size */ 516 break; 517 case WSDISPLAYIO_SMODE: 518 mode = *(u_int *)data; 519 if (mode == sc->sc_mode) 520 break; 521 switch (mode) { 522 case WSDISPLAYIO_MODE_EMUL: 523 /* clear screen */ 524 (void)udl_clear_screen(sc); 525 break; 526 case WSDISPLAYIO_MODE_DUMBFB: 527 /* TODO */ 528 break; 529 default: 530 return (EINVAL); 531 } 532 sc->sc_mode = mode; 533 break; 534 case WSDISPLAYIO_LINEBYTES: 535 *(u_int *)data = sc->sc_width * (sc->sc_depth / 8); 536 break; 537 case WSDISPLAYIO_SVIDEO: 538 case WSDISPLAYIO_GVIDEO: 539 /* handled for us by wscons */ 540 break; 541 case UDLIO_DAMAGE: 542 d = (struct udl_ioctl_damage *)data; 543 d->status = UDLIO_STATUS_OK; 544 r = udl_damage(sc, sc->sc_fbmem, d->x1, d->x2, d->y1, d->y2); 545 if (r != 0) { 546 error = tsleep_nsec(sc, 0, "udlio", MSEC_TO_NSEC(10)); 547 if (error) { 548 d->status = UDLIO_STATUS_FAILED; 549 } else { 550 r = udl_damage(sc, sc->sc_fbmem, d->x1, d->x2, 551 d->y1, d->y2); 552 if (r != 0) 553 d->status = UDLIO_STATUS_FAILED; 554 } 555 } 556 break; 557 default: 558 return (-1); 559 } 560 561 return (0); 562 } 563 564 paddr_t 565 udl_mmap(void *v, off_t off, int prot) 566 { 567 struct udl_softc *sc; 568 caddr_t p; 569 paddr_t pa; 570 571 sc = v; 572 573 DPRINTF(1, "%s: %s\n", DN(sc), FUNC); 574 575 /* allocate framebuffer memory */ 576 if (udl_fbmem_alloc(sc) == -1) 577 return (-1); 578 579 /* return memory address to userland process */ 580 p = sc->sc_fbmem + off; 581 if (pmap_extract(pmap_kernel(), (vaddr_t)p, &pa) == FALSE) { 582 printf("udl_mmap: invalid page\n"); 583 udl_fbmem_free(sc); 584 return (-1); 585 } 586 return (pa); 587 } 588 589 int 590 udl_alloc_screen(void *v, const struct wsscreen_descr *type, 591 void **cookiep, int *curxp, int *curyp, uint32_t *attrp) 592 { 593 struct udl_softc *sc = v; 594 struct wsdisplay_font *font; 595 596 DPRINTF(1, "%s: %s\n", DN(sc), FUNC); 597 598 if (sc->sc_nscreens > 0) 599 return (ENOMEM); 600 601 /* 602 * Initialize rasops. 603 */ 604 sc->sc_ri.ri_depth = sc->sc_depth; 605 sc->sc_ri.ri_bits = NULL; 606 sc->sc_ri.ri_width = sc->sc_width; 607 sc->sc_ri.ri_height = sc->sc_height; 608 sc->sc_ri.ri_stride = sc->sc_width * sc->sc_height / 8; 609 sc->sc_ri.ri_hw = (void *)sc; 610 sc->sc_ri.ri_flg = 0; 611 612 /* swap B and R at 16 bpp */ 613 if (sc->sc_depth == 16) { 614 sc->sc_ri.ri_rnum = 5; 615 sc->sc_ri.ri_rpos = 11; 616 sc->sc_ri.ri_gnum = 6; 617 sc->sc_ri.ri_gpos = 5; 618 sc->sc_ri.ri_bnum = 5; 619 sc->sc_ri.ri_bpos = 0; 620 } 621 622 rasops_init(&sc->sc_ri, 100, 200); 623 624 sc->sc_ri.ri_ops.copycols = udl_copycols; 625 sc->sc_ri.ri_ops.copyrows = udl_copyrows; 626 sc->sc_ri.ri_ops.erasecols = udl_erasecols; 627 sc->sc_ri.ri_ops.eraserows = udl_eraserows; 628 sc->sc_ri.ri_ops.putchar = udl_putchar; 629 sc->sc_ri.ri_do_cursor = udl_do_cursor; 630 631 sc->sc_ri.ri_ops.pack_attr(&sc->sc_ri, 0, 0, 0, attrp); 632 633 udl_stdscreen.nrows = sc->sc_ri.ri_rows; 634 udl_stdscreen.ncols = sc->sc_ri.ri_cols; 635 udl_stdscreen.textops = &sc->sc_ri.ri_ops; 636 udl_stdscreen.fontwidth = sc->sc_ri.ri_font->fontwidth; 637 udl_stdscreen.fontheight = sc->sc_ri.ri_font->fontheight; 638 udl_stdscreen.capabilities = sc->sc_ri.ri_caps; 639 640 *cookiep = &sc->sc_ri; 641 *curxp = 0; 642 *curyp = 0; 643 644 /* allocate character backing store */ 645 sc->sc_cbs = mallocarray(sc->sc_ri.ri_rows, sc->sc_ri.ri_cols * 646 sizeof(*sc->sc_cbs), M_USBDEV, M_NOWAIT|M_ZERO); 647 if (sc->sc_cbs == NULL) { 648 printf("%s: can't allocate mem for character backing store!\n", 649 DN(sc)); 650 return (ENOMEM); 651 } 652 sc->sc_cbslen = sc->sc_ri.ri_rows * sc->sc_ri.ri_cols * 653 sizeof(*sc->sc_cbs); 654 655 sc->sc_nscreens++; 656 657 font = sc->sc_ri.ri_font; 658 DPRINTF(1, "%s: %s: using font %s (%dx%d)\n", 659 DN(sc), FUNC, font->name, sc->sc_ri.ri_cols, sc->sc_ri.ri_rows); 660 661 return (0); 662 } 663 664 void 665 udl_free_screen(void *v, void *cookie) 666 { 667 struct udl_softc *sc; 668 669 sc = v; 670 671 DPRINTF(1, "%s: %s\n", DN(sc), FUNC); 672 673 /* free character backing store */ 674 if (sc->sc_cbs != NULL) 675 free(sc->sc_cbs, M_USBDEV, sc->sc_cbslen); 676 677 sc->sc_nscreens--; 678 } 679 680 int 681 udl_show_screen(void *v, void *cookie, int waitok, 682 void (*cb)(void *, int, int), void *cbarg) 683 { 684 struct udl_softc *sc; 685 686 sc = v; 687 688 DPRINTF(1, "%s: %s\n", DN(sc), FUNC); 689 690 return (0); 691 } 692 693 int 694 udl_load_font(void *v, void *emulcookie, struct wsdisplay_font *font) 695 { 696 struct udl_softc *sc = v; 697 struct rasops_info *ri = &sc->sc_ri; 698 699 return rasops_load_font(ri, emulcookie, font); 700 } 701 702 int 703 udl_list_font(void *v, struct wsdisplay_font *font) 704 { 705 struct udl_softc *sc = v; 706 struct rasops_info *ri = &sc->sc_ri; 707 708 return rasops_list_font(ri, font); 709 } 710 711 void 712 udl_burner(void *v, u_int on, u_int flags) 713 { 714 struct udl_softc *sc; 715 716 sc = v; 717 718 DPRINTF(1, "%s: %s: screen %s\n", DN(sc), FUNC, on ? "ON" : "OFF"); 719 720 if (on) 721 udl_cmd_write_reg_1(sc, UDL_REG_SCREEN, UDL_REG_SCREEN_ON); 722 else 723 udl_cmd_write_reg_1(sc, UDL_REG_SCREEN, UDL_REG_SCREEN_OFF); 724 725 udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0xff); 726 727 (void)udl_cmd_send_async(sc); 728 } 729 730 /* ---------- */ 731 732 int 733 udl_copycols(void *cookie, int row, int src, int dst, int num) 734 { 735 struct rasops_info *ri = cookie; 736 struct udl_softc *sc; 737 int sx, sy, dx, dy, cx, cy, r; 738 usbd_status error; 739 740 sc = ri->ri_hw; 741 742 DPRINTF(2, "%s: %s: row=%d, src=%d, dst=%d, num=%d\n", 743 DN(sc), FUNC, row, src, dst, num); 744 745 udl_cmd_save_offset(sc); 746 747 sx = src * ri->ri_font->fontwidth; 748 sy = row * ri->ri_font->fontheight; 749 dx = dst * ri->ri_font->fontwidth; 750 dy = row * ri->ri_font->fontheight; 751 cx = num * ri->ri_font->fontwidth; 752 cy = ri->ri_font->fontheight; 753 754 /* copy row block to off-screen first to fix overlay-copy problem */ 755 r = (sc->udl_fb_block_copy) 756 (sc, sx, sy, 0, sc->sc_ri.ri_emuheight, cx, cy); 757 if (r != 0) 758 goto fail; 759 760 /* copy row block back from off-screen now */ 761 r = (sc->udl_fb_block_copy) 762 (sc, 0, sc->sc_ri.ri_emuheight, dx, dy, cx, cy); 763 if (r != 0) 764 goto fail; 765 766 error = udl_cmd_send_async(sc); 767 if (error != USBD_NORMAL_COMPLETION) { 768 fail: 769 udl_cmd_restore_offset(sc); 770 return (EAGAIN); 771 } 772 773 /* update character backing store */ 774 bcopy(sc->sc_cbs + ((row * sc->sc_ri.ri_cols) + src), 775 sc->sc_cbs + ((row * sc->sc_ri.ri_cols) + dst), 776 num * sizeof(*sc->sc_cbs)); 777 778 return (0); 779 } 780 781 int 782 udl_copyrows(void *cookie, int src, int dst, int num) 783 { 784 struct rasops_info *ri = cookie; 785 struct udl_softc *sc; 786 int sy, dy, cx, cy, r; 787 usbd_status error; 788 789 sc = ri->ri_hw; 790 791 DPRINTF(2, "%s: %s: src=%d, dst=%d, num=%d\n", 792 DN(sc), FUNC, src, dst, num); 793 794 udl_cmd_save_offset(sc); 795 796 sy = src * sc->sc_ri.ri_font->fontheight; 797 dy = dst * sc->sc_ri.ri_font->fontheight; 798 cx = sc->sc_ri.ri_emuwidth; 799 cy = num * sc->sc_ri.ri_font->fontheight; 800 801 /* copy row block to off-screen first to fix overlay-copy problem */ 802 r = (sc->udl_fb_block_copy) 803 (sc, 0, sy, 0, sc->sc_ri.ri_emuheight, cx, cy); 804 if (r != 0) 805 goto fail; 806 807 /* copy row block back from off-screen now */ 808 r = (sc->udl_fb_block_copy) 809 (sc, 0, sc->sc_ri.ri_emuheight, 0, dy, cx, cy); 810 if (r != 0) 811 goto fail; 812 813 error = udl_cmd_send_async(sc); 814 if (error != USBD_NORMAL_COMPLETION) { 815 fail: 816 udl_cmd_restore_offset(sc); 817 return (EAGAIN); 818 } 819 820 /* update character backing store */ 821 bcopy(sc->sc_cbs + (src * sc->sc_ri.ri_cols), 822 sc->sc_cbs + (dst * sc->sc_ri.ri_cols), 823 (num * sc->sc_ri.ri_cols) * sizeof(*sc->sc_cbs)); 824 825 return (0); 826 } 827 828 int 829 udl_erasecols(void *cookie, int row, int col, int num, uint32_t attr) 830 { 831 struct rasops_info *ri = cookie; 832 struct udl_softc *sc = ri->ri_hw; 833 uint16_t bgc; 834 int fg, bg; 835 int x, y, cx, cy, r; 836 usbd_status error; 837 838 sc = ri->ri_hw; 839 840 DPRINTF(2, "%s: %s: row=%d, col=%d, num=%d\n", 841 DN(sc), FUNC, row, col, num); 842 843 udl_cmd_save_offset(sc); 844 845 sc->sc_ri.ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); 846 bgc = (uint16_t)sc->sc_ri.ri_devcmap[bg]; 847 848 x = col * sc->sc_ri.ri_font->fontwidth; 849 y = row * sc->sc_ri.ri_font->fontheight; 850 cx = num * sc->sc_ri.ri_font->fontwidth; 851 cy = sc->sc_ri.ri_font->fontheight; 852 853 r = (sc->udl_fb_block_write)(sc, bgc, x, y, cx, cy); 854 if (r != 0) 855 goto fail; 856 857 error = udl_cmd_send_async(sc); 858 if (error != USBD_NORMAL_COMPLETION) { 859 fail: 860 udl_cmd_restore_offset(sc); 861 return (EAGAIN); 862 } 863 864 /* update character backing store */ 865 bzero(sc->sc_cbs + ((row * sc->sc_ri.ri_cols) + col), 866 num * sizeof(*sc->sc_cbs)); 867 868 return (0); 869 } 870 871 int 872 udl_eraserows(void *cookie, int row, int num, uint32_t attr) 873 { 874 struct rasops_info *ri = cookie; 875 struct udl_softc *sc; 876 uint16_t bgc; 877 int fg, bg; 878 int x, y, cx, cy, r; 879 usbd_status error; 880 881 sc = ri->ri_hw; 882 883 DPRINTF(2, "%s: %s: row=%d, num=%d\n", DN(sc), FUNC, row, num); 884 885 udl_cmd_save_offset(sc); 886 887 sc->sc_ri.ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); 888 bgc = (uint16_t)sc->sc_ri.ri_devcmap[bg]; 889 890 x = 0; 891 y = row * sc->sc_ri.ri_font->fontheight; 892 cx = sc->sc_ri.ri_emuwidth; 893 cy = num * sc->sc_ri.ri_font->fontheight; 894 895 r = (sc->udl_fb_block_write)(sc, bgc, x, y, cx, cy); 896 if (r != 0) 897 goto fail; 898 899 error = udl_cmd_send_async(sc); 900 if (error != USBD_NORMAL_COMPLETION) { 901 fail: 902 udl_cmd_restore_offset(sc); 903 return (EAGAIN); 904 } 905 906 /* update character backing store */ 907 bzero(sc->sc_cbs + (row * sc->sc_ri.ri_cols), 908 (num * sc->sc_ri.ri_cols) * sizeof(*sc->sc_cbs)); 909 910 return (0); 911 } 912 913 int 914 udl_putchar(void *cookie, int row, int col, u_int uc, uint32_t attr) 915 { 916 struct rasops_info *ri = cookie; 917 struct udl_softc *sc = ri->ri_hw; 918 int r; 919 uint16_t fgc, bgc; 920 uint32_t x, y, fg, bg; 921 922 DPRINTF(4, "%s: %s\n", DN(sc), FUNC); 923 924 udl_cmd_save_offset(sc); 925 926 sc->sc_ri.ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL); 927 fgc = (uint16_t)sc->sc_ri.ri_devcmap[fg]; 928 bgc = (uint16_t)sc->sc_ri.ri_devcmap[bg]; 929 930 x = col * ri->ri_font->fontwidth; 931 y = row * ri->ri_font->fontheight; 932 933 if (uc == ' ') { 934 /* 935 * Writing a block for the space character instead rendering 936 * it from font bits is more slim. 937 */ 938 r = (sc->udl_fb_block_write)(sc, bgc, x, y, 939 ri->ri_font->fontwidth, ri->ri_font->fontheight); 940 if (r != 0) 941 goto fail; 942 } else { 943 /* render a character from font bits */ 944 r = udl_draw_char(sc, fgc, bgc, uc, x, y); 945 if (r != 0) 946 goto fail; 947 } 948 949 /* 950 * We don't call udl_cmd_send_async() here, since sending each 951 * character by itself gets the performance down bad. Instead the 952 * character will be buffered until another rasops function flush 953 * the buffer. 954 */ 955 956 /* update character backing store */ 957 sc->sc_cbs[(row * sc->sc_ri.ri_cols) + col] = uc; 958 959 return (0); 960 961 fail: 962 udl_cmd_restore_offset(sc); 963 return (EAGAIN); 964 } 965 966 int 967 udl_do_cursor(struct rasops_info *ri) 968 { 969 struct udl_softc *sc = ri->ri_hw; 970 int r, pos; 971 uint32_t x, y; 972 uint8_t save_cursor; 973 usbd_status error; 974 975 DPRINTF(2, "%s: %s: ccol=%d, crow=%d\n", 976 DN(sc), FUNC, ri->ri_ccol, ri->ri_crow); 977 978 udl_cmd_save_offset(sc); 979 save_cursor = sc->sc_cursor_on; 980 981 x = ri->ri_ccol * ri->ri_font->fontwidth; 982 y = ri->ri_crow * ri->ri_font->fontheight; 983 984 if (sc->sc_cursor_on == 0) { 985 /* save the last character block to off-screen */ 986 r = (sc->udl_fb_block_copy)(sc, x, y, 0, sc->sc_ri.ri_emuheight, 987 ri->ri_font->fontwidth, ri->ri_font->fontheight); 988 if (r != 0) 989 goto fail; 990 991 /* draw cursor */ 992 pos = (ri->ri_crow * sc->sc_ri.ri_cols) + ri->ri_ccol; 993 if (sc->sc_cbs[pos] == 0 || sc->sc_cbs[pos] == ' ') { 994 r = (sc->udl_fb_block_write)(sc, 0xffff, x, y, 995 ri->ri_font->fontwidth, ri->ri_font->fontheight); 996 } else { 997 r = udl_draw_char(sc, 0x0000, 0xffff, sc->sc_cbs[pos], 998 x, y); 999 } 1000 if (r != 0) 1001 goto fail; 1002 1003 sc->sc_cursor_on = 1; 1004 } else { 1005 /* restore the last saved character from off-screen */ 1006 r = (sc->udl_fb_block_copy)(sc, 0, sc->sc_ri.ri_emuheight, x, y, 1007 ri->ri_font->fontwidth, ri->ri_font->fontheight); 1008 if (r != 0) 1009 goto fail; 1010 1011 sc->sc_cursor_on = 0; 1012 } 1013 1014 error = udl_cmd_send_async(sc); 1015 if (error != USBD_NORMAL_COMPLETION) { 1016 fail: 1017 udl_cmd_restore_offset(sc); 1018 sc->sc_cursor_on = save_cursor; 1019 return (EAGAIN); 1020 } 1021 1022 return (0); 1023 } 1024 1025 int 1026 udl_draw_char(struct udl_softc *sc, uint16_t fg, uint16_t bg, u_int uc, 1027 uint32_t x, uint32_t y) 1028 { 1029 int i, j, ly, r; 1030 uint8_t *fontchar; 1031 uint8_t buf[UDL_CMD_MAX_DATA_SIZE]; 1032 uint16_t *line, lrgb16, fontbits, luc; 1033 struct wsdisplay_font *font = sc->sc_ri.ri_font; 1034 1035 fontchar = (uint8_t *)(font->data + (uc - font->firstchar) * 1036 sc->sc_ri.ri_fontscale); 1037 1038 ly = y; 1039 for (i = 0; i < font->fontheight; i++) { 1040 if (font->fontwidth > 8) { 1041 fontbits = betoh16(*(uint16_t *)fontchar); 1042 } else { 1043 fontbits = *fontchar; 1044 fontbits = fontbits << 8; 1045 } 1046 line = (uint16_t *)buf; 1047 1048 for (j = 15; j > (15 - font->fontwidth); j--) { 1049 luc = 1 << j; 1050 if (fontbits & luc) 1051 lrgb16 = htobe16(fg); 1052 else 1053 lrgb16 = htobe16(bg); 1054 bcopy(&lrgb16, line, 2); 1055 line++; 1056 } 1057 r = (sc->udl_fb_buf_write)(sc, buf, x, ly, font->fontwidth); 1058 if (r != 0) 1059 return (r); 1060 ly++; 1061 1062 fontchar += font->stride; 1063 } 1064 1065 return (0); 1066 } 1067 1068 int 1069 udl_damage(struct udl_softc *sc, uint8_t *image, 1070 uint32_t x1, uint32_t x2, uint32_t y1, uint32_t y2) 1071 { 1072 int r; 1073 int x, y, width, height; 1074 usbd_status error; 1075 1076 udl_cmd_save_offset(sc); 1077 1078 x = x1; 1079 y = y1; 1080 width = x2 - x1; 1081 height = y2 - y1; 1082 1083 r = udl_draw_image(sc, image, x, y, width, height); 1084 if (r != 0) 1085 goto fail; 1086 1087 error = udl_cmd_send_async(sc); 1088 if (error != USBD_NORMAL_COMPLETION) { 1089 fail: 1090 udl_cmd_restore_offset(sc); 1091 return (EAGAIN); 1092 } 1093 1094 return (0); 1095 } 1096 1097 int 1098 udl_draw_image(struct udl_softc *sc, uint8_t *image, 1099 uint32_t x, uint32_t y, uint32_t width, uint32_t height) 1100 { 1101 int i, j, r; 1102 int width_cur, x_cur; 1103 uint8_t buf[UDL_CMD_MAX_DATA_SIZE]; 1104 uint16_t *image16, lrgb16; 1105 uint32_t off, block; 1106 1107 for (i = 0; i < height; i++) { 1108 off = ((y * sc->sc_width) + x) * 2; 1109 x_cur = x; 1110 width_cur = width; 1111 1112 while (width_cur) { 1113 if (width_cur > UDL_CMD_MAX_PIXEL_COUNT) 1114 block = UDL_CMD_MAX_PIXEL_COUNT; 1115 else 1116 block = width_cur; 1117 1118 /* fix RGB ordering */ 1119 image16 = (uint16_t *)(image + off); 1120 for (j = 0; j < (block * 2); j += 2) { 1121 lrgb16 = htobe16(*image16); 1122 bcopy(&lrgb16, buf + j, 2); 1123 image16++; 1124 } 1125 1126 r = (sc->udl_fb_buf_write)(sc, buf, x_cur, y, block); 1127 if (r != 0) 1128 return (r); 1129 1130 off += block * 2; 1131 x_cur += block; 1132 width_cur -= block; 1133 } 1134 y++; 1135 } 1136 1137 return (0); 1138 } 1139 1140 /* ---------- */ 1141 1142 usbd_status 1143 udl_ctrl_msg(struct udl_softc *sc, uint8_t rt, uint8_t r, 1144 uint16_t index, uint16_t value, uint8_t *buf, size_t len) 1145 { 1146 usb_device_request_t req; 1147 usbd_status error; 1148 1149 req.bmRequestType = rt; 1150 req.bRequest = r; 1151 USETW(req.wIndex, index); 1152 USETW(req.wValue, value); 1153 USETW(req.wLength, len); 1154 1155 error = usbd_do_request(sc->sc_udev, &req, buf); 1156 if (error != USBD_NORMAL_COMPLETION) { 1157 printf("%s: %s: %s!\n", DN(sc), FUNC, usbd_errstr(error)); 1158 return (error); 1159 } 1160 1161 return (USBD_NORMAL_COMPLETION); 1162 } 1163 1164 usbd_status 1165 udl_poll(struct udl_softc *sc, uint32_t *buf) 1166 { 1167 uint8_t lbuf[4]; 1168 usbd_status error; 1169 1170 error = udl_ctrl_msg(sc, UT_READ_VENDOR_DEVICE, 1171 UDL_CTRL_CMD_POLL, 0x0000, 0x0000, lbuf, 4); 1172 if (error != USBD_NORMAL_COMPLETION) { 1173 printf("%s: %s: %s!\n", DN(sc), FUNC, usbd_errstr(error)); 1174 return (error); 1175 } 1176 *buf = *(uint32_t *)lbuf; 1177 1178 return (USBD_NORMAL_COMPLETION); 1179 } 1180 1181 usbd_status 1182 udl_read_1(struct udl_softc *sc, uint16_t addr, uint8_t *buf) 1183 { 1184 uint8_t lbuf[1]; 1185 usbd_status error; 1186 1187 error = udl_ctrl_msg(sc, UT_READ_VENDOR_DEVICE, 1188 UDL_CTRL_CMD_READ_1, addr, 0x0000, lbuf, 1); 1189 if (error != USBD_NORMAL_COMPLETION) { 1190 printf("%s: %s: %s!\n", DN(sc), FUNC, usbd_errstr(error)); 1191 return (error); 1192 } 1193 *buf = *(uint8_t *)lbuf; 1194 1195 return (USBD_NORMAL_COMPLETION); 1196 } 1197 1198 usbd_status 1199 udl_write_1(struct udl_softc *sc, uint16_t addr, uint8_t buf) 1200 { 1201 usbd_status error; 1202 1203 error = udl_ctrl_msg(sc, UT_WRITE_VENDOR_DEVICE, 1204 UDL_CTRL_CMD_WRITE_1, addr, 0x0000, &buf, 1); 1205 if (error != USBD_NORMAL_COMPLETION) { 1206 printf("%s: %s: %s!\n", DN(sc), FUNC, usbd_errstr(error)); 1207 return (error); 1208 } 1209 1210 return (USBD_NORMAL_COMPLETION); 1211 } 1212 1213 usbd_status 1214 udl_read_edid(struct udl_softc *sc, uint8_t *buf) 1215 { 1216 uint8_t lbuf[64]; 1217 uint16_t offset; 1218 usbd_status error; 1219 1220 offset = 0; 1221 1222 error = udl_ctrl_msg(sc, UT_READ_VENDOR_DEVICE, 1223 UDL_CTRL_CMD_READ_EDID, 0x00a1, (offset << 8), lbuf, 64); 1224 if (error != USBD_NORMAL_COMPLETION) 1225 goto fail; 1226 bcopy(lbuf + 1, buf + offset, 63); 1227 offset += 63; 1228 1229 error = udl_ctrl_msg(sc, UT_READ_VENDOR_DEVICE, 1230 UDL_CTRL_CMD_READ_EDID, 0x00a1, (offset << 8), lbuf, 64); 1231 if (error != USBD_NORMAL_COMPLETION) 1232 goto fail; 1233 bcopy(lbuf + 1, buf + offset, 63); 1234 offset += 63; 1235 1236 error = udl_ctrl_msg(sc, UT_READ_VENDOR_DEVICE, 1237 UDL_CTRL_CMD_READ_EDID, 0x00a1, (offset << 8), lbuf, 3); 1238 if (error != USBD_NORMAL_COMPLETION) 1239 goto fail; 1240 bcopy(lbuf + 1, buf + offset, 2); 1241 1242 return (USBD_NORMAL_COMPLETION); 1243 fail: 1244 printf("%s: %s: %s!\n", DN(sc), FUNC, usbd_errstr(error)); 1245 return (error); 1246 } 1247 1248 uint8_t 1249 udl_lookup_mode(uint16_t hdisplay, uint16_t vdisplay, uint8_t freq, 1250 uint16_t chip, uint32_t clock) 1251 { 1252 uint8_t idx = 0; 1253 1254 /* 1255 * Check first if we have a matching mode with pixelclock 1256 */ 1257 while (idx < MAX_DL_MODES) { 1258 if ((udl_modes[idx].hdisplay == hdisplay) && 1259 (udl_modes[idx].vdisplay == vdisplay) && 1260 (udl_modes[idx].clock == clock) && 1261 (udl_modes[idx].chip <= chip)) { 1262 return(idx); 1263 } 1264 idx++; 1265 } 1266 1267 /* 1268 * If not, check for matching mode with update frequency 1269 */ 1270 idx = 0; 1271 while (idx < MAX_DL_MODES) { 1272 if ((udl_modes[idx].hdisplay == hdisplay) && 1273 (udl_modes[idx].vdisplay == vdisplay) && 1274 (udl_modes[idx].freq == freq) && 1275 (udl_modes[idx].chip <= chip)) { 1276 return(idx); 1277 } 1278 idx++; 1279 } 1280 1281 return(idx); 1282 } 1283 1284 int 1285 udl_select_chip(struct udl_softc *sc) 1286 { 1287 char serialnum[USB_MAX_STRING_LEN]; 1288 usb_device_descriptor_t *dd; 1289 usb_string_descriptor_t us; 1290 usbd_status error; 1291 int len, i, n; 1292 char *s; 1293 uint16_t c; 1294 1295 sc->sc_chip = DL120; 1296 1297 dd = usbd_get_device_descriptor(sc->sc_udev); 1298 1299 if ((UGETW(dd->idVendor) == USB_VENDOR_DISPLAYLINK) && 1300 (UGETW(dd->idProduct) == USB_PRODUCT_DISPLAYLINK_WSDVI)) { 1301 1302 /* 1303 * WS Tech DVI is DL120 or DL160. All deviced uses the 1304 * same revision (0.04) so iSerialNumber must be used 1305 * to determine which chip it is. 1306 */ 1307 1308 bzero(serialnum, sizeof serialnum); 1309 error = usbd_get_string_desc(sc->sc_udev, dd->iSerialNumber, 1310 0, &us, &len); 1311 if (error != USBD_NORMAL_COMPLETION) 1312 return (1); 1313 1314 s = &serialnum[0]; 1315 n = len / 2 - 1; 1316 for (i = 0; i < n && i < nitems(us.bString); i++) { 1317 c = UGETW(us.bString[i]); 1318 /* Convert from Unicode, handle buggy strings. */ 1319 if ((c & 0xff00) == 0) 1320 *s++ = c; 1321 else if ((c & 0x00ff) == 0) 1322 *s++ = c >> 8; 1323 else 1324 *s++ = '?'; 1325 } 1326 *s++ = 0; 1327 1328 if (strlen(serialnum) > 7) 1329 if (strncmp(serialnum, "0198-13", 7) == 0) 1330 sc->sc_chip = DL160; 1331 1332 DPRINTF(1, "%s: %s: iSerialNumber (%s) used to select chip (%d)\n", 1333 DN(sc), FUNC, serialnum, sc->sc_chip); 1334 1335 } 1336 1337 if ((UGETW(dd->idVendor) == USB_VENDOR_DISPLAYLINK) && 1338 (UGETW(dd->idProduct) == USB_PRODUCT_DISPLAYLINK_SWDVI)) { 1339 1340 /* 1341 * SUNWEIT DVI is DL160, DL125, DL165 or DL195. Major revision 1342 * can be used to differ between DL1x0 and DL1x5. Minor to 1343 * differ between DL1x5. iSerialNumber seems not to be unique. 1344 */ 1345 1346 sc->sc_chip = DL160; 1347 1348 if (UGETW(dd->bcdDevice) >= 0x100) { 1349 sc->sc_chip = DL165; 1350 if (UGETW(dd->bcdDevice) == 0x104) 1351 sc->sc_chip = DL195; 1352 if (UGETW(dd->bcdDevice) == 0x108) 1353 sc->sc_chip = DL125; 1354 } 1355 1356 DPRINTF(1, "%s: %s: bcdDevice (%02x) used to select chip (%d)\n", 1357 DN(sc), FUNC, UGETW(dd->bcdDevice), sc->sc_chip); 1358 1359 } 1360 1361 return (0); 1362 } 1363 1364 usbd_status 1365 udl_set_enc_key(struct udl_softc *sc, uint8_t *buf, uint8_t len) 1366 { 1367 usbd_status error; 1368 1369 error = udl_ctrl_msg(sc, UT_WRITE_VENDOR_DEVICE, 1370 UDL_CTRL_CMD_SET_KEY, 0x0000, 0x0000, buf, len); 1371 if (error != USBD_NORMAL_COMPLETION) { 1372 printf("%s: %s: %s!\n", DN(sc), FUNC, usbd_errstr(error)); 1373 return (error); 1374 } 1375 1376 return (USBD_NORMAL_COMPLETION); 1377 } 1378 1379 usbd_status 1380 udl_set_decomp_table(struct udl_softc *sc, uint8_t *buf, uint16_t len) 1381 { 1382 int err; 1383 1384 udl_cmd_insert_int_1(sc, UDL_BULK_SOC); 1385 udl_cmd_insert_int_1(sc, UDL_BULK_CMD_DECOMP); 1386 udl_cmd_insert_int_4(sc, 0x263871cd); /* magic number */ 1387 udl_cmd_insert_int_4(sc, 0x00000200); /* 512 byte chunks */ 1388 udl_cmd_insert_buf(sc, buf, len); 1389 1390 err = udl_cmd_send(sc); 1391 if (err != 0) 1392 return (USBD_INVAL); 1393 1394 return (USBD_NORMAL_COMPLETION); 1395 } 1396 1397 /* ---------- */ 1398 1399 int 1400 udl_load_huffman(struct udl_softc *sc) 1401 { 1402 const char *name = "udl_huffman"; 1403 int error; 1404 1405 if (sc->sc_huffman == NULL) { 1406 error = loadfirmware(name, &sc->sc_huffman, 1407 &sc->sc_huffman_size); 1408 if (error != 0) { 1409 printf("%s: error %d, could not read huffman table " 1410 "%s!\n", DN(sc), error, name); 1411 return (EIO); 1412 } 1413 } 1414 1415 DPRINTF(1, "%s: huffman table %s allocated\n", DN(sc), name); 1416 1417 return (0); 1418 } 1419 1420 void 1421 udl_free_huffman(struct udl_softc *sc) 1422 { 1423 if (sc->sc_huffman != NULL) { 1424 free(sc->sc_huffman, M_USBDEV, sc->sc_huffman_size); 1425 sc->sc_huffman = NULL; 1426 sc->sc_huffman_size = 0; 1427 DPRINTF(1, "%s: huffman table freed\n", DN(sc)); 1428 } 1429 } 1430 1431 int 1432 udl_fbmem_alloc(struct udl_softc *sc) 1433 { 1434 int size; 1435 1436 size = (sc->sc_width * sc->sc_height) * (sc->sc_depth / 8); 1437 size = round_page(size); 1438 1439 if (sc->sc_fbmem == NULL) { 1440 sc->sc_fbmem = malloc(size, M_USBDEV, M_NOWAIT|M_ZERO); 1441 if (sc->sc_fbmem == NULL) 1442 return (-1); 1443 } 1444 sc->sc_fbmemsize = size; 1445 return (0); 1446 } 1447 1448 void 1449 udl_fbmem_free(struct udl_softc *sc) 1450 { 1451 if (sc->sc_fbmem != NULL) { 1452 free(sc->sc_fbmem, M_USBDEV, sc->sc_fbmemsize); 1453 sc->sc_fbmem = NULL; 1454 sc->sc_fbmemsize = 0; 1455 } 1456 } 1457 1458 usbd_status 1459 udl_cmd_alloc_xfer(struct udl_softc *sc) 1460 { 1461 int i; 1462 1463 for (i = 0; i < UDL_CMD_XFER_COUNT; i++) { 1464 struct udl_cmd_xfer *cx = &sc->sc_cmd_xfer[i]; 1465 1466 cx->sc = sc; 1467 1468 cx->xfer = usbd_alloc_xfer(sc->sc_udev); 1469 if (cx->xfer == NULL) { 1470 printf("%s: %s: can't allocate xfer handle!\n", 1471 DN(sc), FUNC); 1472 return (USBD_NOMEM); 1473 } 1474 1475 cx->buf = usbd_alloc_buffer(cx->xfer, UDL_CMD_MAX_XFER_SIZE); 1476 if (cx->buf == NULL) { 1477 printf("%s: %s: can't allocate xfer buffer!\n", 1478 DN(sc), FUNC); 1479 return (USBD_NOMEM); 1480 } 1481 } 1482 1483 return (USBD_NORMAL_COMPLETION); 1484 } 1485 1486 void 1487 udl_cmd_free_xfer(struct udl_softc *sc) 1488 { 1489 int i; 1490 1491 for (i = 0; i < UDL_CMD_XFER_COUNT; i++) { 1492 struct udl_cmd_xfer *cx = &sc->sc_cmd_xfer[i]; 1493 1494 if (cx->xfer != NULL) { 1495 usbd_free_xfer(cx->xfer); 1496 cx->xfer = NULL; 1497 } 1498 } 1499 } 1500 1501 int 1502 udl_cmd_alloc_buf(struct udl_softc *sc) 1503 { 1504 struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 1505 1506 cb->buf = malloc(UDL_CMD_MAX_XFER_SIZE, M_USBDEV, M_NOWAIT|M_ZERO); 1507 if (cb->buf == NULL) { 1508 printf("%s: %s: can't allocate buffer!\n", 1509 DN(sc), FUNC); 1510 return (ENOMEM); 1511 } 1512 cb->off = 0; 1513 cb->compblock = 0; 1514 1515 return (0); 1516 } 1517 1518 void 1519 udl_cmd_free_buf(struct udl_softc *sc) 1520 { 1521 struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 1522 1523 if (cb->buf != NULL) { 1524 free(cb->buf, M_USBDEV, UDL_CMD_MAX_XFER_SIZE); 1525 cb->buf = NULL; 1526 } 1527 cb->off = 0; 1528 } 1529 1530 void 1531 udl_cmd_insert_int_1(struct udl_softc *sc, uint8_t value) 1532 { 1533 struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 1534 1535 cb->buf[cb->off] = value; 1536 1537 cb->off += 1; 1538 } 1539 1540 void 1541 udl_cmd_insert_int_2(struct udl_softc *sc, uint16_t value) 1542 { 1543 uint16_t lvalue; 1544 struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 1545 1546 lvalue = htobe16(value); 1547 bcopy(&lvalue, cb->buf + cb->off, 2); 1548 1549 cb->off += 2; 1550 } 1551 1552 void 1553 udl_cmd_insert_int_3(struct udl_softc *sc, uint32_t value) 1554 { 1555 uint32_t lvalue; 1556 struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 1557 #if BYTE_ORDER == BIG_ENDIAN 1558 lvalue = htobe32(value) << 8; 1559 #else 1560 lvalue = htobe32(value) >> 8; 1561 #endif 1562 bcopy(&lvalue, cb->buf + cb->off, 3); 1563 1564 cb->off += 3; 1565 } 1566 1567 void 1568 udl_cmd_insert_int_4(struct udl_softc *sc, uint32_t value) 1569 { 1570 uint32_t lvalue; 1571 struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 1572 1573 lvalue = htobe32(value); 1574 bcopy(&lvalue, cb->buf + cb->off, 4); 1575 1576 cb->off += 4; 1577 } 1578 1579 void 1580 udl_cmd_insert_buf(struct udl_softc *sc, uint8_t *buf, uint32_t len) 1581 { 1582 struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 1583 1584 bcopy(buf, cb->buf + cb->off, len); 1585 1586 cb->off += len; 1587 } 1588 1589 int 1590 udl_cmd_insert_buf_comp(struct udl_softc *sc, uint8_t *buf, uint32_t len) 1591 { 1592 struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 1593 struct udl_huffman *h; 1594 uint8_t bit_pos; 1595 uint16_t *pixels, prev; 1596 int16_t diff; 1597 uint32_t bit_count, bit_pattern, bit_cur; 1598 int i, j, bytes, eob, padding, next; 1599 1600 pixels = (uint16_t *)buf; 1601 bit_pos = bytes = eob = padding = 0; 1602 1603 /* 1604 * If the header doesn't fit into the 512 byte main-block anymore, 1605 * skip the header and finish up the main-block. We return zero 1606 * to signal our caller that the header has been skipped. 1607 */ 1608 if (cb->compblock >= UDL_CB_RESTART_SIZE) { 1609 cb->off -= UDL_CMD_WRITE_HEAD_SIZE; 1610 cb->compblock -= UDL_CMD_WRITE_HEAD_SIZE; 1611 eob = 1; 1612 } 1613 1614 /* 1615 * Generate a sub-block with maximal 256 pixels compressed data. 1616 */ 1617 for (i = 0; i < len / 2 && eob == 0; i++) { 1618 /* get difference between current and previous pixel */ 1619 if (i > 0) 1620 prev = betoh16(pixels[i - 1]); 1621 else 1622 prev = 0; 1623 1624 /* get the huffman difference bit sequence */ 1625 diff = betoh16(pixels[i]) - prev; 1626 h = (struct udl_huffman *)(sc->sc_huffman + UDL_HUFFMAN_BASE); 1627 h += diff; 1628 bit_count = h->bit_count; 1629 bit_pattern = betoh32(h->bit_pattern); 1630 1631 1632 /* we are near the end of the main-block, so quit loop */ 1633 if (bit_count % 8 == 0) 1634 next = bit_count / 8; 1635 else 1636 next = (bit_count / 8) + 1; 1637 1638 if (cb->compblock + next >= UDL_CB_BODY_SIZE) { 1639 eob = 1; 1640 break; 1641 } 1642 1643 /* generate one pixel compressed data */ 1644 for (j = 0; j < bit_count; j++) { 1645 if (bit_pos == 0) 1646 cb->buf[cb->off] = 0; 1647 bit_cur = (bit_pattern >> j) & 1; 1648 cb->buf[cb->off] |= (bit_cur << bit_pos); 1649 bit_pos++; 1650 1651 if (bit_pos == 8) { 1652 bit_pos = 0; 1653 cb->off++; 1654 cb->compblock++; 1655 } 1656 } 1657 bytes += 2; 1658 } 1659 1660 /* 1661 * If we have bits left in our last byte, round up to the next 1662 * byte, so we don't overwrite them. 1663 */ 1664 if (bit_pos != 0) { 1665 cb->off++; 1666 cb->compblock++; 1667 } 1668 1669 /* 1670 * Finish up a 512 byte main-block. The leftover space gets 1671 * padded to zero. Finally terminate the block by writing the 1672 * 0xff-into-UDL_REG_SYNC-register sequence. 1673 */ 1674 if (eob == 1) { 1675 padding = (UDL_CB_BODY_SIZE - cb->compblock); 1676 for (i = 0; i < padding; i++) { 1677 cb->buf[cb->off] = 0; 1678 cb->off++; 1679 cb->compblock++; 1680 } 1681 udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0xff); 1682 cb->compblock = 0; 1683 } 1684 1685 /* return how many bytes we have compressed */ 1686 return (bytes); 1687 } 1688 1689 int 1690 udl_cmd_insert_head_comp(struct udl_softc *sc, uint32_t len) 1691 { 1692 struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 1693 int i, padding; 1694 1695 if (cb->compblock > UDL_CB_BODY_SIZE) { 1696 cb->off -= UDL_CMD_COPY_HEAD_SIZE; 1697 cb->compblock -= UDL_CMD_COPY_HEAD_SIZE; 1698 1699 padding = (UDL_CB_BODY_SIZE - cb->compblock); 1700 for (i = 0; i < padding; i++) { 1701 cb->buf[cb->off] = 0; 1702 cb->off++; 1703 cb->compblock++; 1704 } 1705 udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0xff); 1706 cb->compblock = 0; 1707 return (0); 1708 } 1709 1710 return (len); 1711 } 1712 1713 int 1714 udl_cmd_insert_check(struct udl_softc *sc, int len) 1715 { 1716 struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 1717 int total; 1718 usbd_status error; 1719 1720 total = cb->off + len; 1721 1722 if (total > UDL_CMD_MAX_XFER_SIZE) { 1723 /* command buffer is almost full, try to flush it */ 1724 if (cb->xfer_type == UDL_CMD_XFER_ASYNC) 1725 error = udl_cmd_send_async(sc); 1726 else 1727 error = udl_cmd_send(sc); 1728 if (error != USBD_NORMAL_COMPLETION) { 1729 DPRINTF(1, "%s: %s: can't flush full command buffer\n", 1730 DN(sc), FUNC); 1731 return (EAGAIN); 1732 } 1733 } 1734 1735 return (0); 1736 } 1737 1738 void 1739 udl_cmd_set_xfer_type(struct udl_softc *sc, int xfer_type) 1740 { 1741 struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 1742 1743 cb->xfer_type = xfer_type; 1744 } 1745 1746 void 1747 udl_cmd_save_offset(struct udl_softc *sc) 1748 { 1749 struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 1750 1751 cb->off_save = cb->off; 1752 cb->compblock_save = cb->compblock; 1753 } 1754 1755 void 1756 udl_cmd_restore_offset(struct udl_softc *sc) 1757 { 1758 struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 1759 1760 cb->off = cb->off_save; 1761 cb->compblock = cb->compblock_save; 1762 } 1763 1764 void 1765 udl_cmd_write_reg_1(struct udl_softc *sc, uint8_t reg, uint8_t val) 1766 { 1767 udl_cmd_insert_int_1(sc, UDL_BULK_SOC); 1768 udl_cmd_insert_int_1(sc, UDL_BULK_CMD_REG_WRITE_1); 1769 udl_cmd_insert_int_1(sc, reg); 1770 udl_cmd_insert_int_1(sc, val); 1771 } 1772 1773 void 1774 udl_cmd_write_reg_3(struct udl_softc *sc, uint8_t reg, uint32_t val) 1775 { 1776 udl_cmd_write_reg_1(sc, reg + 0, (val >> 16) & 0xff); 1777 udl_cmd_write_reg_1(sc, reg + 1, (val >> 8) & 0xff); 1778 udl_cmd_write_reg_1(sc, reg + 2, (val >> 0) & 0xff); 1779 } 1780 1781 usbd_status 1782 udl_cmd_send(struct udl_softc *sc) 1783 { 1784 struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 1785 struct udl_cmd_xfer *cx = &sc->sc_cmd_xfer[0]; 1786 int len; 1787 usbd_status error; 1788 1789 /* mark end of command stack */ 1790 udl_cmd_insert_int_1(sc, UDL_BULK_SOC); 1791 udl_cmd_insert_int_1(sc, UDL_BULK_CMD_EOC); 1792 1793 bcopy(cb->buf, cx->buf, cb->off); 1794 1795 len = cb->off; 1796 usbd_setup_xfer(cx->xfer, sc->sc_tx_pipeh, 0, cx->buf, len, 1797 USBD_NO_COPY | USBD_SHORT_XFER_OK | USBD_SYNCHRONOUS, 1000, NULL); 1798 error = usbd_transfer(cx->xfer); 1799 if (error != USBD_NORMAL_COMPLETION) { 1800 printf("%s: %s: %s!\n", DN(sc), FUNC, usbd_errstr(error)); 1801 /* we clear our buffer now to avoid growing out of bounds */ 1802 goto fail; 1803 } 1804 DPRINTF(1, "%s: %s: sent %d of %d bytes\n", 1805 DN(sc), FUNC, len, cb->off); 1806 fail: 1807 cb->off = 0; 1808 cb->compblock = 0; 1809 1810 return (error); 1811 } 1812 1813 usbd_status 1814 udl_cmd_send_async(struct udl_softc *sc) 1815 { 1816 struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 1817 struct udl_cmd_xfer *cx; 1818 usbd_status error; 1819 int i, s; 1820 1821 /* check if command xfer queue is full */ 1822 if (sc->sc_cmd_xfer_cnt == UDL_CMD_XFER_COUNT) 1823 return (USBD_IN_USE); 1824 1825 s = splusb(); /* no callbacks please until accounting is done */ 1826 1827 /* find a free command xfer buffer */ 1828 for (i = 0; i < UDL_CMD_XFER_COUNT; i++) { 1829 if (sc->sc_cmd_xfer[i].busy == 0) 1830 break; 1831 } 1832 if (i == UDL_CMD_XFER_COUNT) { 1833 /* this shouldn't happen */ 1834 splx(s); 1835 return (USBD_IN_USE); 1836 } 1837 cx = &sc->sc_cmd_xfer[i]; 1838 1839 /* mark end of command stack */ 1840 udl_cmd_insert_int_1(sc, UDL_BULK_SOC); 1841 udl_cmd_insert_int_1(sc, UDL_BULK_CMD_EOC); 1842 1843 /* copy command buffer to xfer buffer */ 1844 bcopy(cb->buf, cx->buf, cb->off); 1845 1846 /* do xfer */ 1847 usbd_setup_xfer(cx->xfer, sc->sc_tx_pipeh, cx, cx->buf, cb->off, 1848 USBD_NO_COPY, 1000, udl_cmd_send_async_cb); 1849 error = usbd_transfer(cx->xfer); 1850 if (error != 0 && error != USBD_IN_PROGRESS) { 1851 printf("%s: %s: %s!\n", DN(sc), FUNC, usbd_errstr(error)); 1852 splx(s); 1853 return (error); 1854 } 1855 DPRINTF(2, "%s: %s: sending %d bytes from buffer no. %d\n", 1856 DN(sc), FUNC, cb->off, i); 1857 1858 /* free command buffer, lock xfer buffer */ 1859 cb->off = 0; 1860 cb->compblock = 0; 1861 cx->busy = 1; 1862 sc->sc_cmd_xfer_cnt++; 1863 1864 splx(s); 1865 1866 return (USBD_NORMAL_COMPLETION); 1867 } 1868 1869 void 1870 udl_cmd_send_async_cb(struct usbd_xfer *xfer, void *priv, usbd_status status) 1871 { 1872 struct udl_cmd_xfer *cx = priv; 1873 struct udl_softc *sc = cx->sc; 1874 int len; 1875 1876 if (status != USBD_NORMAL_COMPLETION) { 1877 printf("%s: %s: %s!\n", DN(sc), FUNC, usbd_errstr(status)); 1878 1879 if (status == USBD_NOT_STARTED || status == USBD_CANCELLED) 1880 return; 1881 if (status == USBD_STALLED) 1882 usbd_clear_endpoint_stall_async(sc->sc_tx_pipeh); 1883 goto skip; 1884 } 1885 usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL); 1886 1887 DPRINTF(3, "%s: %s: sent %d bytes\n", DN(sc), FUNC, len); 1888 skip: 1889 /* free xfer buffer */ 1890 cx->busy = 0; 1891 sc->sc_cmd_xfer_cnt--; 1892 1893 /* wakeup UDLIO_DAMAGE if it sleeps for a free xfer buffer */ 1894 wakeup(sc); 1895 } 1896 1897 /* ---------- */ 1898 1899 usbd_status 1900 udl_init_chip(struct udl_softc *sc) 1901 { 1902 uint8_t ui8; 1903 uint32_t ui32; 1904 usbd_status error; 1905 1906 error = udl_poll(sc, &ui32); 1907 if (error != USBD_NORMAL_COMPLETION) 1908 return (error); 1909 DPRINTF(1, "%s: %s: poll=0x%08x\n", DN(sc), FUNC, ui32); 1910 1911 /* Some products may use later chip too */ 1912 switch (ui32 & 0xff) { 1913 case 0xf1: /* DL1x5 */ 1914 switch (sc->sc_chip) { 1915 case DL120: 1916 sc->sc_chip = DL125; 1917 break; 1918 case DL160: 1919 sc->sc_chip = DL165; 1920 break; 1921 } 1922 break; 1923 } 1924 DPRINTF(1, "%s: %s: chip %d\n", DN(sc), FUNC, sc->sc_chip); 1925 1926 error = udl_read_1(sc, 0xc484, &ui8); 1927 if (error != USBD_NORMAL_COMPLETION) 1928 return (error); 1929 DPRINTF(1, "%s: %s: read 0x%02x from 0xc484\n", DN(sc), FUNC, ui8); 1930 1931 error = udl_write_1(sc, 0xc41f, 0x01); 1932 if (error != USBD_NORMAL_COMPLETION) 1933 return (error); 1934 DPRINTF(1, "%s: %s: write 0x01 to 0xc41f\n", DN(sc), FUNC); 1935 1936 error = udl_read_edid(sc, sc->sc_edid); 1937 if (error != USBD_NORMAL_COMPLETION) 1938 return (error); 1939 DPRINTF(1, "%s: %s: read EDID\n", DN(sc), FUNC); 1940 1941 error = udl_set_enc_key(sc, udl_null_key_1, sizeof(udl_null_key_1)); 1942 if (error != USBD_NORMAL_COMPLETION) 1943 return (error); 1944 DPRINTF(1, "%s: %s: set encryption key\n", DN(sc), FUNC); 1945 1946 error = udl_write_1(sc, 0xc40b, 0x00); 1947 if (error != USBD_NORMAL_COMPLETION) 1948 return (error); 1949 DPRINTF(1, "%s: %s: write 0x00 to 0xc40b\n", DN(sc), FUNC); 1950 1951 error = udl_set_decomp_table(sc, udl_decomp_table, 1952 sizeof(udl_decomp_table)); 1953 if (error != USBD_NORMAL_COMPLETION) 1954 return (error); 1955 DPRINTF(1, "%s: %s: set decompression table\n", DN(sc), FUNC); 1956 1957 return (USBD_NORMAL_COMPLETION); 1958 } 1959 1960 void 1961 udl_init_fb_offsets(struct udl_softc *sc, uint32_t start16, uint32_t stride16, 1962 uint32_t start8, uint32_t stride8) 1963 { 1964 udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0x00); 1965 udl_cmd_write_reg_3(sc, UDL_REG_ADDR_START16, start16); 1966 udl_cmd_write_reg_3(sc, UDL_REG_ADDR_STRIDE16, stride16); 1967 udl_cmd_write_reg_3(sc, UDL_REG_ADDR_START8, start8); 1968 udl_cmd_write_reg_3(sc, UDL_REG_ADDR_STRIDE8, stride8); 1969 udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0xff); 1970 } 1971 1972 usbd_status 1973 udl_init_resolution(struct udl_softc *sc) 1974 { 1975 int i; 1976 usbd_status error; 1977 uint8_t *buf = udl_modes[sc->sc_cur_mode].mode; 1978 1979 /* write resolution values and set video memory offsets */ 1980 udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0x00); 1981 for (i = 0; i < UDL_MODE_SIZE; i++) 1982 udl_cmd_write_reg_1(sc, i, buf[i]); 1983 udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0xff); 1984 1985 udl_init_fb_offsets(sc, 0x000000, 0x000a00, 0x555555, 0x000500); 1986 error = udl_cmd_send(sc); 1987 if (error != USBD_NORMAL_COMPLETION) 1988 return (error); 1989 1990 /* clear screen */ 1991 error = udl_clear_screen(sc); 1992 if (error != USBD_NORMAL_COMPLETION) 1993 return (error); 1994 1995 /* show framebuffer content */ 1996 udl_cmd_write_reg_1(sc, UDL_REG_SCREEN, UDL_REG_SCREEN_ON); 1997 udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0xff); 1998 error = udl_cmd_send(sc); 1999 if (error != USBD_NORMAL_COMPLETION) 2000 return (error); 2001 2002 return (USBD_NORMAL_COMPLETION); 2003 } 2004 2005 usbd_status 2006 udl_clear_screen(struct udl_softc *sc) 2007 { 2008 struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 2009 usbd_status error; 2010 2011 /* clear screen */ 2012 udl_fb_block_write(sc, 0x0000, 0, 0, sc->sc_width, sc->sc_height); 2013 if (cb->xfer_type == UDL_CMD_XFER_ASYNC) 2014 error = udl_cmd_send_async(sc); 2015 else 2016 error = udl_cmd_send(sc); 2017 if (error != USBD_NORMAL_COMPLETION) 2018 return (error); 2019 2020 return (USBD_NORMAL_COMPLETION); 2021 } 2022 2023 void 2024 udl_select_mode(struct udl_softc *sc) 2025 { 2026 struct udl_mode mode; 2027 int index = MAX_DL_MODES, i; 2028 2029 /* try to get the preferred mode from EDID */ 2030 edid_parse(sc->sc_edid, &sc->sc_edid_info); 2031 #ifdef UDL_DEBUG 2032 edid_print(&sc->sc_edid_info); 2033 #endif 2034 if (sc->sc_edid_info.edid_preferred_mode != NULL) { 2035 mode.freq = 2036 (sc->sc_edid_info.edid_preferred_mode->dot_clock * 1000) / 2037 (sc->sc_edid_info.edid_preferred_mode->htotal * 2038 sc->sc_edid_info.edid_preferred_mode->vtotal); 2039 mode.clock = 2040 sc->sc_edid_info.edid_preferred_mode->dot_clock / 10; 2041 mode.hdisplay = 2042 sc->sc_edid_info.edid_preferred_mode->hdisplay; 2043 mode.vdisplay = 2044 sc->sc_edid_info.edid_preferred_mode->vdisplay; 2045 index = udl_lookup_mode(mode.hdisplay, mode.vdisplay, mode.freq, 2046 sc->sc_chip, mode.clock); 2047 sc->sc_cur_mode = index; 2048 } else { 2049 DPRINTF(1, "%s: %s: no preferred mode found!\n", DN(sc), FUNC); 2050 } 2051 2052 if (index == MAX_DL_MODES) { 2053 DPRINTF(1, "%s: %s: no mode line found for %dx%d @ %dHz!\n", 2054 DN(sc), FUNC, mode.hdisplay, mode.vdisplay, mode.freq); 2055 2056 i = 0; 2057 while (i < sc->sc_edid_info.edid_nmodes) { 2058 mode.freq = 2059 (sc->sc_edid_info.edid_modes[i].dot_clock * 1000) / 2060 (sc->sc_edid_info.edid_modes[i].htotal * 2061 sc->sc_edid_info.edid_modes[i].vtotal); 2062 mode.clock = 2063 sc->sc_edid_info.edid_modes[i].dot_clock / 10; 2064 mode.hdisplay = 2065 sc->sc_edid_info.edid_modes[i].hdisplay; 2066 mode.vdisplay = 2067 sc->sc_edid_info.edid_modes[i].vdisplay; 2068 index = udl_lookup_mode(mode.hdisplay, mode.vdisplay, 2069 mode.freq, sc->sc_chip, mode.clock); 2070 if (index < MAX_DL_MODES) 2071 if ((sc->sc_cur_mode == MAX_DL_MODES) || 2072 (index > sc->sc_cur_mode)) 2073 sc->sc_cur_mode = index; 2074 i++; 2075 } 2076 } 2077 2078 /* 2079 * If no mode found use default. 2080 */ 2081 if (sc->sc_cur_mode == MAX_DL_MODES) 2082 sc->sc_cur_mode = udl_lookup_mode(800, 600, 60, sc->sc_chip, 0); 2083 2084 mode = udl_modes[sc->sc_cur_mode]; 2085 sc->sc_width = mode.hdisplay; 2086 sc->sc_height = mode.vdisplay; 2087 2088 /* 2089 * We always use 16bit color depth for now. 2090 */ 2091 sc->sc_depth = 16; 2092 2093 DPRINTF(1, "%s: %s: %dx%d @ %dHz\n", 2094 DN(sc), FUNC, mode.hdisplay, mode.vdisplay, mode.freq); 2095 } 2096 2097 int 2098 udl_fb_buf_write(struct udl_softc *sc, uint8_t *buf, uint32_t x, 2099 uint32_t y, uint16_t width) 2100 { 2101 uint16_t lwidth; 2102 uint32_t off; 2103 int r; 2104 2105 r = udl_cmd_insert_check(sc, UDL_CMD_WRITE_MAX_SIZE); 2106 if (r != 0) 2107 return (r); 2108 2109 off = ((y * sc->sc_width) + x) * 2; 2110 lwidth = width * 2; 2111 2112 udl_cmd_insert_int_1(sc, UDL_BULK_SOC); 2113 udl_cmd_insert_int_1(sc, UDL_BULK_CMD_FB_WRITE | UDL_BULK_CMD_FB_WORD); 2114 udl_cmd_insert_int_3(sc, off); 2115 udl_cmd_insert_int_1(sc, width >= UDL_CMD_MAX_PIXEL_COUNT ? 0 : width); 2116 2117 udl_cmd_insert_buf(sc, buf, lwidth); 2118 2119 return (0); 2120 } 2121 2122 int 2123 udl_fb_block_write(struct udl_softc *sc, uint16_t rgb16, uint32_t x, 2124 uint32_t y, uint32_t width, uint32_t height) 2125 { 2126 uint32_t i; 2127 int r; 2128 2129 for (i = 0; i < height; i++) { 2130 r = udl_fb_line_write(sc, rgb16, x, y + i, width); 2131 if (r != 0) 2132 return (r); 2133 } 2134 2135 return (0); 2136 } 2137 2138 int 2139 udl_fb_line_write(struct udl_softc *sc, uint16_t rgb16, uint32_t x, 2140 uint32_t y, uint32_t width) 2141 { 2142 uint32_t off, block; 2143 int r; 2144 2145 off = (y * sc->sc_width) + x; 2146 2147 while (width) { 2148 if (width > UDL_CMD_MAX_PIXEL_COUNT) 2149 block = UDL_CMD_MAX_PIXEL_COUNT; 2150 else 2151 block = width; 2152 2153 r = udl_fb_off_write(sc, rgb16, off, block); 2154 if (r != 0) 2155 return (r); 2156 2157 off += block; 2158 width -= block; 2159 } 2160 2161 return (0); 2162 } 2163 2164 int 2165 udl_fb_off_write(struct udl_softc *sc, uint16_t rgb16, uint32_t off, 2166 uint16_t width) 2167 { 2168 uint8_t buf[UDL_CMD_MAX_DATA_SIZE]; 2169 uint16_t lwidth, lrgb16; 2170 uint32_t loff; 2171 int i, r; 2172 2173 r = udl_cmd_insert_check(sc, UDL_CMD_WRITE_MAX_SIZE); 2174 if (r != 0) 2175 return (r); 2176 2177 loff = off * 2; 2178 lwidth = width * 2; 2179 2180 udl_cmd_insert_int_1(sc, UDL_BULK_SOC); 2181 udl_cmd_insert_int_1(sc, UDL_BULK_CMD_FB_WRITE | UDL_BULK_CMD_FB_WORD); 2182 udl_cmd_insert_int_3(sc, loff); 2183 udl_cmd_insert_int_1(sc, width >= UDL_CMD_MAX_PIXEL_COUNT ? 0 : width); 2184 2185 for (i = 0; i < lwidth; i += 2) { 2186 lrgb16 = htobe16(rgb16); 2187 bcopy(&lrgb16, buf + i, 2); 2188 } 2189 2190 udl_cmd_insert_buf(sc, buf, lwidth); 2191 2192 return (0); 2193 } 2194 2195 int 2196 udl_fb_block_copy(struct udl_softc *sc, uint32_t src_x, uint32_t src_y, 2197 uint32_t dst_x, uint32_t dst_y, uint32_t width, uint32_t height) 2198 { 2199 int i, r; 2200 2201 for (i = 0; i < height; i++) { 2202 r = udl_fb_line_copy(sc, src_x, src_y + i, dst_x, dst_y + i, 2203 width); 2204 if (r != 0) 2205 return (r); 2206 } 2207 2208 return (0); 2209 } 2210 2211 2212 int 2213 udl_fb_line_copy(struct udl_softc *sc, uint32_t src_x, uint32_t src_y, 2214 uint32_t dst_x, uint32_t dst_y, uint32_t width) 2215 { 2216 uint32_t src_off, dst_off, block; 2217 int r; 2218 2219 src_off = (src_y * sc->sc_width) + src_x; 2220 dst_off = (dst_y * sc->sc_width) + dst_x; 2221 2222 while (width) { 2223 if (width > UDL_CMD_MAX_PIXEL_COUNT) 2224 block = UDL_CMD_MAX_PIXEL_COUNT; 2225 else 2226 block = width; 2227 2228 r = udl_fb_off_copy(sc, src_off, dst_off, block); 2229 if (r != 0) 2230 return (r); 2231 2232 src_off += block; 2233 dst_off += block; 2234 width -= block; 2235 } 2236 2237 return (0); 2238 } 2239 2240 int 2241 udl_fb_off_copy(struct udl_softc *sc, uint32_t src_off, uint32_t dst_off, 2242 uint16_t width) 2243 { 2244 uint32_t ldst_off, lsrc_off; 2245 int r; 2246 2247 r = udl_cmd_insert_check(sc, UDL_CMD_COPY_MAX_SIZE); 2248 if (r != 0) 2249 return (r); 2250 2251 ldst_off = dst_off * 2; 2252 lsrc_off = src_off * 2; 2253 2254 udl_cmd_insert_int_1(sc, UDL_BULK_SOC); 2255 udl_cmd_insert_int_1(sc, UDL_BULK_CMD_FB_COPY | UDL_BULK_CMD_FB_WORD); 2256 udl_cmd_insert_int_3(sc, ldst_off); 2257 udl_cmd_insert_int_1(sc, width >= UDL_CMD_MAX_PIXEL_COUNT ? 0 : width); 2258 udl_cmd_insert_int_3(sc, lsrc_off); 2259 2260 return (0); 2261 } 2262 2263 int 2264 udl_fb_buf_write_comp(struct udl_softc *sc, uint8_t *buf, uint32_t x, 2265 uint32_t y, uint16_t width) 2266 { 2267 struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 2268 uint8_t *count; 2269 uint16_t lwidth; 2270 uint32_t off; 2271 int r, sent; 2272 2273 r = udl_cmd_insert_check(sc, UDL_CMD_WRITE_MAX_SIZE); 2274 if (r != 0) 2275 return (r); 2276 2277 off = ((y * sc->sc_width) + x) * 2; 2278 lwidth = width * 2; 2279 2280 /* 2281 * A new compressed stream needs the 0xff-into-UDL_REG_SYNC-register 2282 * sequence always as first command. 2283 */ 2284 if (cb->off == 0) 2285 udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0xff); 2286 2287 r = sent = 0; 2288 while (sent < lwidth) { 2289 udl_cmd_insert_int_1(sc, UDL_BULK_SOC); 2290 udl_cmd_insert_int_1(sc, 2291 UDL_BULK_CMD_FB_WRITE | 2292 UDL_BULK_CMD_FB_WORD | 2293 UDL_BULK_CMD_FB_COMP); 2294 udl_cmd_insert_int_3(sc, off + sent); 2295 udl_cmd_insert_int_1(sc, 2296 width >= UDL_CMD_MAX_PIXEL_COUNT ? 0 : width); 2297 cb->compblock += UDL_CMD_WRITE_HEAD_SIZE; 2298 2299 count = &cb->buf[cb->off - 1]; 2300 r = udl_cmd_insert_buf_comp(sc, buf + sent, lwidth - sent); 2301 if (r > 0 && r != (lwidth - sent)) { 2302 *count = r / 2; 2303 width -= r / 2; 2304 } 2305 sent += r; 2306 } 2307 2308 return (0); 2309 } 2310 2311 int 2312 udl_fb_block_write_comp(struct udl_softc *sc, uint16_t rgb16, uint32_t x, 2313 uint32_t y, uint32_t width, uint32_t height) 2314 { 2315 uint32_t i; 2316 int r; 2317 2318 for (i = 0; i < height; i++) { 2319 r = udl_fb_line_write_comp(sc, rgb16, x, y + i, width); 2320 if (r != 0) 2321 return (r); 2322 } 2323 2324 return (0); 2325 } 2326 2327 int 2328 udl_fb_line_write_comp(struct udl_softc *sc, uint16_t rgb16, uint32_t x, 2329 uint32_t y, uint32_t width) 2330 { 2331 uint32_t off, block; 2332 int r; 2333 2334 off = (y * sc->sc_width) + x; 2335 2336 while (width) { 2337 if (width > UDL_CMD_MAX_PIXEL_COUNT) 2338 block = UDL_CMD_MAX_PIXEL_COUNT; 2339 else 2340 block = width; 2341 2342 r = udl_fb_off_write_comp(sc, rgb16, off, block); 2343 if (r != 0) 2344 return (r); 2345 2346 off += block; 2347 width -= block; 2348 } 2349 2350 return (0); 2351 } 2352 2353 int 2354 udl_fb_off_write_comp(struct udl_softc *sc, uint16_t rgb16, uint32_t off, 2355 uint16_t width) 2356 { 2357 struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 2358 uint8_t buf[UDL_CMD_MAX_DATA_SIZE]; 2359 uint8_t *count; 2360 uint16_t lwidth, lrgb16; 2361 uint32_t loff; 2362 int i, r, sent; 2363 2364 r = udl_cmd_insert_check(sc, UDL_CMD_WRITE_MAX_SIZE); 2365 if (r != 0) 2366 return (r); 2367 2368 loff = off * 2; 2369 lwidth = width * 2; 2370 2371 for (i = 0; i < lwidth; i += 2) { 2372 lrgb16 = htobe16(rgb16); 2373 bcopy(&lrgb16, buf + i, 2); 2374 } 2375 2376 /* 2377 * A new compressed stream needs the 0xff-into-UDL_REG_SYNC-register 2378 * sequence always as first command. 2379 */ 2380 if (cb->off == 0) 2381 udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0xff); 2382 2383 r = sent = 0; 2384 while (sent < lwidth) { 2385 udl_cmd_insert_int_1(sc, UDL_BULK_SOC); 2386 udl_cmd_insert_int_1(sc, 2387 UDL_BULK_CMD_FB_WRITE | 2388 UDL_BULK_CMD_FB_WORD | 2389 UDL_BULK_CMD_FB_COMP); 2390 udl_cmd_insert_int_3(sc, loff + sent); 2391 udl_cmd_insert_int_1(sc, 2392 width >= UDL_CMD_MAX_PIXEL_COUNT ? 0 : width); 2393 cb->compblock += UDL_CMD_WRITE_HEAD_SIZE; 2394 2395 count = &cb->buf[cb->off - 1]; 2396 r = udl_cmd_insert_buf_comp(sc, buf + sent, lwidth - sent); 2397 if (r > 0 && r != (lwidth - sent)) { 2398 *count = r / 2; 2399 width -= r / 2; 2400 } 2401 sent += r; 2402 } 2403 2404 return (0); 2405 } 2406 2407 int 2408 udl_fb_block_copy_comp(struct udl_softc *sc, uint32_t src_x, uint32_t src_y, 2409 uint32_t dst_x, uint32_t dst_y, uint32_t width, uint32_t height) 2410 { 2411 int i, r; 2412 2413 for (i = 0; i < height; i++) { 2414 r = udl_fb_line_copy_comp(sc, src_x, src_y + i, 2415 dst_x, dst_y + i, width); 2416 if (r != 0) 2417 return (r); 2418 } 2419 2420 return (0); 2421 } 2422 2423 int 2424 udl_fb_line_copy_comp(struct udl_softc *sc, uint32_t src_x, uint32_t src_y, 2425 uint32_t dst_x, uint32_t dst_y, uint32_t width) 2426 { 2427 uint32_t src_off, dst_off, block; 2428 int r; 2429 2430 src_off = (src_y * sc->sc_width) + src_x; 2431 dst_off = (dst_y * sc->sc_width) + dst_x; 2432 2433 while (width) { 2434 if (width > UDL_CMD_MAX_PIXEL_COUNT) 2435 block = UDL_CMD_MAX_PIXEL_COUNT; 2436 else 2437 block = width; 2438 2439 r = udl_fb_off_copy_comp(sc, src_off, dst_off, block); 2440 if (r != 0) 2441 return (r); 2442 2443 src_off += block; 2444 dst_off += block; 2445 width -= block; 2446 } 2447 2448 return (0); 2449 } 2450 2451 int 2452 udl_fb_off_copy_comp(struct udl_softc *sc, uint32_t src_off, uint32_t dst_off, 2453 uint16_t width) 2454 { 2455 struct udl_cmd_buf *cb = &sc->sc_cmd_buf; 2456 uint32_t ldst_off, lsrc_off; 2457 int r; 2458 2459 r = udl_cmd_insert_check(sc, UDL_CMD_COPY_MAX_SIZE); 2460 if (r != 0) 2461 return (r); 2462 2463 ldst_off = dst_off * 2; 2464 lsrc_off = src_off * 2; 2465 2466 /* 2467 * A new compressed stream needs the 0xff-into-UDL_REG_SYNC-register 2468 * sequence always as first command. 2469 */ 2470 if (cb->off == 0) 2471 udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0xff); 2472 2473 r = 0; 2474 while (r < 1) { 2475 udl_cmd_insert_int_1(sc, UDL_BULK_SOC); 2476 udl_cmd_insert_int_1(sc, 2477 UDL_BULK_CMD_FB_COPY | UDL_BULK_CMD_FB_WORD); 2478 udl_cmd_insert_int_3(sc, ldst_off); 2479 udl_cmd_insert_int_1(sc, 2480 width >= UDL_CMD_MAX_PIXEL_COUNT ? 0 : width); 2481 udl_cmd_insert_int_3(sc, lsrc_off); 2482 cb->compblock += UDL_CMD_COPY_HEAD_SIZE; 2483 2484 r = udl_cmd_insert_head_comp(sc, UDL_CMD_COPY_HEAD_SIZE); 2485 } 2486 2487 return (0); 2488 } 2489 2490 /* ---------- */ 2491 #ifdef UDL_DEBUG 2492 void 2493 udl_hexdump(void *buf, int len, int quiet) 2494 { 2495 int i; 2496 2497 for (i = 0; i < len; i++) { 2498 if (quiet == 0) { 2499 if (i % 16 == 0) 2500 printf("%s%5i:", i ? "\n" : "", i); 2501 if (i % 4 == 0) 2502 printf(" "); 2503 } 2504 printf("%02x", (int)*((u_char *)buf + i)); 2505 } 2506 printf("\n"); 2507 } 2508 2509 usbd_status 2510 udl_init_test(struct udl_softc *sc) 2511 { 2512 int i, j, parts, loops; 2513 uint16_t color; 2514 uint16_t rgb24[3] = { 0xf800, 0x07e0, 0x001f }; 2515 2516 loops = (sc->sc_width * sc->sc_height) / UDL_CMD_MAX_PIXEL_COUNT; 2517 parts = loops / 3; 2518 color = rgb24[0]; 2519 2520 j = 1; 2521 for (i = 0; i < loops; i++) { 2522 if (i == parts) { 2523 color = rgb24[j]; 2524 parts += parts; 2525 j++; 2526 } 2527 (sc->udl_fb_off_write)(sc, color, i * UDL_CMD_MAX_PIXEL_COUNT, 2528 UDL_CMD_MAX_PIXEL_COUNT); 2529 } 2530 (void)udl_cmd_send(sc); 2531 2532 return (USBD_NORMAL_COMPLETION); 2533 } 2534 #endif 2535