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