4 * Copyright (c) 2009 FUKAUMI Naoki.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * Copyright (c) 2009 Marcus Glocker <mglocker@openbsd.org>
31 * Permission to use, copy, modify, and distribute this software for any
32 * purpose with or without fee is hereby granted, provided that the above
33 * copyright notice and this permission notice appear in all copies.
35 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
36 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
37 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
38 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
39 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
40 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
41 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
45 * Driver for the ``DisplayLink DL-1x0 / DL-1x5'' graphic chips based
46 * on the reversed engineered specifications of Florian Echtler
47 * <floe at butterbrot dot org>:
49 * http://floe.butterbrot.org/displaylink/doku.php
51 * This driver was written by Marcus Glocker for OpenBSD and ported to
52 * NetBSD by FUKAUMI Naoki with many modification.
55 #include <sys/cdefs.h>
56 __KERNEL_RCSID(0, "$NetBSD$");
58 #include <sys/param.h>
59 #include <sys/device.h>
60 #include <sys/kernel.h>
62 #include <sys/systm.h>
67 #include <sys/endian.h>
69 #include <dev/usb/usb.h>
70 #include <dev/usb/usbdi.h>
71 #include <dev/usb/usbdivar.h>
72 #include <dev/usb/usbdi_util.h>
73 #include <dev/usb/usb_mem.h>
74 #include <dev/usb/usbdevs.h>
76 #include <dev/firmload.h>
78 #include <dev/videomode/videomode.h>
79 #include <dev/videomode/edidvar.h>
81 #include <dev/wscons/wsconsio.h>
82 #include <dev/wscons/wsdisplayvar.h>
83 #include <dev/rasops/rasops.h>
85 #include <dev/usb/udl.h>
87 #include <dev/usb/udlio.h>
94 #define DPRINTF(x) do { if (udl_debug) printf x; } while (0)
95 #define DPRINTFN(n, x) do { if (udl_debug >= (n)) printf x; } while (0)
98 #define DPRINTF(x) do {} while (0)
99 #define DPRINTFN(n, x) do {} while (0)
105 static int udl_match(device_t
, cfdata_t
, void *);
106 static void udl_attach(device_t
, device_t
, void *);
107 static int udl_detach(device_t
, int);
109 static int udl_ioctl(void *, void *, u_long
, void *, int,
111 static paddr_t
udl_mmap(void *, void *, off_t
, int);
112 static int udl_alloc_screen(void *, const struct wsscreen_descr
*,
113 void **, int *, int *, long *);
114 static void udl_free_screen(void *, void *);
115 static int udl_show_screen(void *, void *, int,
116 void (*)(void *, int, int), void *);
118 static void udl_comp_load(struct udl_softc
*);
119 static void udl_comp_unload(struct udl_softc
*);
120 static int udl_fbmem_alloc(struct udl_softc
*);
121 static void udl_fbmem_free(struct udl_softc
*);
122 static int udl_cmdq_alloc(struct udl_softc
*);
123 static void udl_cmdq_free(struct udl_softc
*);
124 static struct udl_cmdq
*udl_cmdq_get(struct udl_softc
*sc
);
125 static void udl_cmdq_put(struct udl_softc
*sc
,
126 struct udl_cmdq
*cmdq
);
127 static void udl_cmdq_flush(struct udl_softc
*);
129 static void udl_cursor(void *, int, int, int);
130 static void udl_putchar(void *, int, int, u_int
, long);
131 static void udl_copycols(void *, int, int, int, int);
132 static void udl_erasecols(void *, int, int, int, long);
133 static void udl_copyrows(void *, int, int, int);
134 static void udl_eraserows(void *, int, int, long);
136 static void udl_restore_char(struct rasops_info
*);
137 static void udl_draw_char(struct rasops_info
*, uint16_t *, u_int
,
139 static void udl_copy_rect(struct udl_softc
*, int, int, int, int,
141 static void udl_fill_rect(struct udl_softc
*, uint16_t, int, int,
144 static void udl_draw_rect(struct udl_softc
*,
145 struct udl_ioctl_damage
*);
146 static void udl_draw_rect_comp(struct udl_softc
*,
147 struct udl_ioctl_damage
*);
150 static inline void udl_copy_line(struct udl_softc
*, int, int, int);
151 static inline void udl_fill_line(struct udl_softc
*, uint16_t, int, int);
152 static inline void udl_draw_line(struct udl_softc
*, uint16_t *, int,
154 static inline void udl_draw_line_comp(struct udl_softc
*, uint16_t *, int,
157 static int udl_cmd_send(struct udl_softc
*);
158 static void udl_cmd_send_async(struct udl_softc
*);
159 static void udl_cmd_send_async_cb(usbd_xfer_handle
,
160 usbd_private_handle
, usbd_status
);
162 static int udl_ctrl_msg(struct udl_softc
*, uint8_t, uint8_t,
163 uint16_t, uint16_t, uint8_t *, uint16_t);
164 static int udl_init(struct udl_softc
*);
165 static void udl_read_edid(struct udl_softc
*);
166 static void udl_set_address(struct udl_softc
*, int, int, int,
168 static void udl_blank(struct udl_softc
*, int);
169 static uint16_t udl_lfsr(uint16_t);
170 static int udl_set_resolution(struct udl_softc
*,
171 const struct videomode
*);
172 static const struct videomode
*udl_videomode_lookup(const char *);
175 udl_cmd_add_1(struct udl_softc
*sc
, uint8_t val
)
178 *sc
->sc_cmd_buf
++ = val
;
182 udl_cmd_add_2(struct udl_softc
*sc
, uint16_t val
)
185 be16enc(sc
->sc_cmd_buf
, val
);
190 udl_cmd_add_3(struct udl_softc
*sc
, uint32_t val
)
193 udl_cmd_add_2(sc
, val
>> 8);
194 udl_cmd_add_1(sc
, val
);
198 udl_cmd_add_4(struct udl_softc
*sc
, uint32_t val
)
201 be32enc(sc
->sc_cmd_buf
, val
);
206 udl_cmd_add_buf(struct udl_softc
*sc
, uint16_t *buf
, int width
)
208 #if BYTE_ORDER == BIG_ENDIAN
209 memcpy(sc
->sc_cmd_buf
, buf
, width
* 2);
210 sc
->sc_cmd_buf
+= width
* 2;
216 if (((uintptr_t)sc
->sc_cmd_buf
& 1) == 0) {
218 *(uint16_t *)sc
->sc_cmd_buf
= htobe16(*buf
++);
223 be16enc(sc
->sc_cmd_buf
, *buf
++);
231 udl_reg_write_1(struct udl_softc
*sc
, uint8_t reg
, uint8_t val
)
234 udl_cmd_add_4(sc
, (UDL_BULK_SOC
<< 24) |
235 (UDL_BULK_CMD_REG_WRITE_1
<< 16) | (reg
<< 8) | val
);
239 udl_reg_write_2(struct udl_softc
*sc
, uint8_t reg
, uint16_t val
)
242 udl_reg_write_1(sc
, reg
++, val
>> 8);
243 udl_reg_write_1(sc
, reg
, val
);
247 udl_reg_write_3(struct udl_softc
*sc
, uint8_t reg
, uint32_t val
)
250 udl_reg_write_1(sc
, reg
++, val
>> 16);
251 udl_reg_write_1(sc
, reg
++, val
>> 8);
252 udl_reg_write_1(sc
, reg
, val
);
257 firmware_load(const char *dname
, const char *iname
, uint8_t **ucodep
,
260 firmware_handle_t fh
;
263 if ((error
= firmware_open(dname
, iname
, &fh
)) != 0)
265 *sizep
= firmware_get_size(fh
);
266 if ((*ucodep
= firmware_malloc(*sizep
)) == NULL
) {
270 if ((error
= firmware_read(fh
, 0, *ucodep
, *sizep
)) != 0)
271 firmware_free(*ucodep
, *sizep
);
280 CFATTACH_DECL_NEW(udl
, sizeof(struct udl_softc
),
281 udl_match
, udl_attach
, udl_detach
, NULL
);
286 static struct wsdisplay_accessops udl_accessops
= {
300 static const struct usb_devno udl_devs
[] = {
301 { USB_VENDOR_DISPLAYLINK
, USB_PRODUCT_DISPLAYLINK_LD220
},
302 { USB_VENDOR_DISPLAYLINK
, USB_PRODUCT_DISPLAYLINK_U70
},
303 { USB_VENDOR_DISPLAYLINK
, USB_PRODUCT_DISPLAYLINK_VCUD60
},
304 { USB_VENDOR_DISPLAYLINK
, USB_PRODUCT_DISPLAYLINK_DLDVI
},
305 { USB_VENDOR_DISPLAYLINK
, USB_PRODUCT_DISPLAYLINK_USBRGB
},
306 { USB_VENDOR_DISPLAYLINK
, USB_PRODUCT_DISPLAYLINK_LCDUSB7X
},
307 { USB_VENDOR_DISPLAYLINK
, USB_PRODUCT_DISPLAYLINK_VGA10
},
308 { USB_VENDOR_DISPLAYLINK
, USB_PRODUCT_DISPLAYLINK_WSDVI
},
309 { USB_VENDOR_DISPLAYLINK
, USB_PRODUCT_DISPLAYLINK_EC008
},
310 { USB_VENDOR_DISPLAYLINK
, USB_PRODUCT_DISPLAYLINK_GXDVIU2
},
311 { USB_VENDOR_DISPLAYLINK
, USB_PRODUCT_DISPLAYLINK_LCD4300U
},
312 { USB_VENDOR_DISPLAYLINK
, USB_PRODUCT_DISPLAYLINK_LCD8000U
},
313 { USB_VENDOR_DISPLAYLINK
, USB_PRODUCT_DISPLAYLINK_HPDOCK
},
314 { USB_VENDOR_DISPLAYLINK
, USB_PRODUCT_DISPLAYLINK_M01061
},
315 { USB_VENDOR_DISPLAYLINK
, USB_PRODUCT_DISPLAYLINK_SWDVI
},
316 { USB_VENDOR_DISPLAYLINK
, USB_PRODUCT_DISPLAYLINK_LDEWX015U
},
317 { USB_VENDOR_DISPLAYLINK
, USB_PRODUCT_DISPLAYLINK_UM7X0
}
321 udl_match(device_t parent
, cfdata_t match
, void *aux
)
323 struct usb_attach_arg
*uaa
= aux
;
325 if (usb_lookup(udl_devs
, uaa
->vendor
, uaa
->product
) != NULL
)
326 return UMATCH_VENDOR_PRODUCT
;
332 udl_attach(device_t parent
, device_t self
, void *aux
)
334 struct udl_softc
*sc
= device_private(self
);
335 struct usb_attach_arg
*uaa
= aux
;
336 struct wsemuldisplaydev_attach_args aa
;
337 const struct videomode
*vmp
;
345 sc
->sc_udev
= uaa
->device
;
347 devinfop
= usbd_devinfo_alloc(sc
->sc_udev
, 0);
348 aprint_normal_dev(sc
->sc_dev
, "%s\n", devinfop
);
349 usbd_devinfo_free(devinfop
);
352 * Set device configuration descriptor number.
354 error
= usbd_set_config_no(sc
->sc_udev
, 1, 0);
355 if (error
!= USBD_NORMAL_COMPLETION
)
359 * Create device handle to interface descriptor.
361 error
= usbd_device2interface_handle(sc
->sc_udev
, 0, &sc
->sc_iface
);
362 if (error
!= USBD_NORMAL_COMPLETION
)
368 error
= usbd_open_pipe(sc
->sc_iface
, 1, USBD_EXCLUSIVE_USE
,
370 if (error
!= USBD_NORMAL_COMPLETION
)
374 * Allocate bulk command queue.
376 #ifdef UDL_EVENT_COUNTERS
377 evcnt_attach_dynamic(&sc
->sc_ev_cmdq_get
, EVCNT_TYPE_MISC
, NULL
,
378 device_xname(sc
->sc_dev
), "udl_cmdq_get");
379 evcnt_attach_dynamic(&sc
->sc_ev_cmdq_put
, EVCNT_TYPE_MISC
, NULL
,
380 device_xname(sc
->sc_dev
), "udl_cmdq_put");
381 evcnt_attach_dynamic(&sc
->sc_ev_cmdq_wait
, EVCNT_TYPE_MISC
, NULL
,
382 device_xname(sc
->sc_dev
), "udl_cmdq_wait");
383 evcnt_attach_dynamic(&sc
->sc_ev_cmdq_timeout
, EVCNT_TYPE_MISC
, NULL
,
384 device_xname(sc
->sc_dev
), "udl_cmdq_timeout");
387 if (udl_cmdq_alloc(sc
) != 0)
390 cv_init(&sc
->sc_cv
, device_xname(sc
->sc_dev
));
391 mutex_init(&sc
->sc_mtx
, MUTEX_DEFAULT
, IPL_TTY
); /* XXX for tty_lock */
393 if ((sc
->sc_cmd_cur
= udl_cmdq_get(sc
)) == NULL
)
400 if (udl_init(sc
) != 0)
406 * Initialize resolution.
408 #ifndef UDL_VIDEOMODE
409 if (sc
->sc_ei
.edid_nmodes
!= 0 &&
410 sc
->sc_ei
.edid_preferred_mode
!= NULL
)
411 vmp
= sc
->sc_ei
.edid_preferred_mode
;
413 #define UDL_VIDEOMODE "640x480x60"
415 vmp
= udl_videomode_lookup(UDL_VIDEOMODE
);
420 sc
->sc_width
= vmp
->hdisplay
;
421 sc
->sc_height
= vmp
->vdisplay
;
422 sc
->sc_offscreen
= sc
->sc_height
* 3 / 2;
425 if (udl_set_resolution(sc
, vmp
) != 0)
428 sc
->sc_defaultscreen
.name
= "default";
429 sc
->sc_screens
[0] = &sc
->sc_defaultscreen
;
430 sc
->sc_screenlist
.nscreens
= 1;
431 sc
->sc_screenlist
.screens
= sc
->sc_screens
;
434 * Set initial wsdisplay emulation mode.
436 sc
->sc_mode
= WSDISPLAYIO_MODE_EMUL
;
442 aa
.scrdata
= &sc
->sc_screenlist
;
443 aa
.accessops
= &udl_accessops
;
444 aa
.accesscookie
= sc
;
447 config_found(sc
->sc_dev
, &aa
, wsemuldisplaydevprint
);
449 usbd_add_drv_event(USB_EVENT_DRIVER_ATTACH
, sc
->sc_udev
, sc
->sc_dev
);
453 udl_detach(device_t self
, int flags
)
455 struct udl_softc
*sc
= device_private(self
);
458 * Close bulk TX pipe.
460 if (sc
->sc_tx_pipeh
!= NULL
) {
461 usbd_abort_pipe(sc
->sc_tx_pipeh
);
462 usbd_close_pipe(sc
->sc_tx_pipeh
);
466 * Free command xfer buffers.
471 cv_destroy(&sc
->sc_cv
);
472 mutex_destroy(&sc
->sc_mtx
);
475 * Free Huffman table.
480 * Free framebuffer memory.
487 if (sc
->sc_wsdisplay
!= NULL
)
488 config_detach(sc
->sc_wsdisplay
, DETACH_FORCE
);
490 usbd_add_drv_event(USB_EVENT_DRIVER_DETACH
, sc
->sc_udev
, sc
->sc_dev
);
492 #ifdef UDL_EVENT_COUNTERS
493 evcnt_detach(&sc
->sc_ev_cmdq_get
);
494 evcnt_detach(&sc
->sc_ev_cmdq_put
);
495 evcnt_detach(&sc
->sc_ev_cmdq_wait
);
496 evcnt_detach(&sc
->sc_ev_cmdq_timeout
);
503 udl_ioctl(void *v
, void *vs
, u_long cmd
, void *data
, int flag
, struct lwp
*l
)
505 struct udl_softc
*sc
= v
;
507 struct udl_ioctl_damage
*d
;
509 struct wsdisplay_fbinfo
*wdf
;
513 case WSDISPLAYIO_GTYPE
:
514 *(u_int
*)data
= WSDISPLAY_TYPE_DL
;
517 case WSDISPLAYIO_GINFO
:
518 wdf
= (struct wsdisplay_fbinfo
*)data
;
519 wdf
->height
= sc
->sc_height
;
520 wdf
->width
= sc
->sc_width
;
521 wdf
->depth
= sc
->sc_depth
;
525 case WSDISPLAYIO_GVIDEO
:
526 *(u_int
*)data
= sc
->sc_blank
;
529 case WSDISPLAYIO_SVIDEO
:
530 mode
= *(u_int
*)data
;
531 if (mode
== sc
->sc_blank
)
534 case WSDISPLAYIO_VIDEO_OFF
:
537 case WSDISPLAYIO_VIDEO_ON
:
543 udl_cmd_send_async(sc
);
548 case WSDISPLAYIO_SMODE
:
549 mode
= *(u_int
*)data
;
550 if (mode
== sc
->sc_mode
)
553 case WSDISPLAYIO_MODE_EMUL
:
555 udl_fill_rect(sc
, 0, 0, 0, sc
->sc_width
,
557 udl_cmd_send_async(sc
);
561 case WSDISPLAYIO_MODE_DUMBFB
:
562 if (UDL_CMD_BUFSIZE(sc
) > 0)
563 udl_cmd_send_async(sc
);
573 case WSDISPLAYIO_LINEBYTES
:
574 *(u_int
*)data
= sc
->sc_width
* (sc
->sc_depth
/ 8);
580 * OpenBSD allows device specific ioctl()s and use this
581 * UDLIO_DAMAGE for the damage extension ops of X servers.
582 * Before blindly pulling such interfaces, probably we should
583 * discuss how such devices should be handled which have
584 * in-direct framebuffer memories that should be transfered
585 * per updated rectangle regions via MI wscons APIs.
588 d
= (struct udl_ioctl_damage
*)data
;
589 d
->status
= UDLIO_STATUS_OK
;
590 if (sc
->sc_flags
& UDL_COMPRDY
)
591 udl_draw_rect_comp(sc
, d
);
593 udl_draw_rect(sc
, d
);
602 udl_mmap(void *v
, void *vs
, off_t off
, int prot
)
604 struct udl_softc
*sc
= v
;
609 if (off
< 0 || off
> roundup2(UDL_FBMEM_SIZE(sc
), PAGE_SIZE
))
612 /* allocate framebuffer memory */
613 if (udl_fbmem_alloc(sc
) != 0)
616 vaddr
= (vaddr_t
)sc
->sc_fbmem
+ off
;
617 rv
= pmap_extract(pmap_kernel(), vaddr
, &paddr
);
619 paddr
+= vaddr
& PGOFSET
;
621 /* XXX we need MI paddr_t -> mmap cookie API */
622 #if defined(__alpha__)
623 #define PTOMMAP(paddr) alpha_btop((char *)paddr)
624 #elif defined(__arm__)
625 #define PTOMMAP(paddr) arm_btop((u_long)paddr)
626 #elif defined(__hppa__)
627 #define PTOMMAP(paddr) btop((u_long)paddr)
628 #elif defined(__i386__) || defined(__x86_64__)
629 #define PTOMMAP(paddr) x86_btop(paddr)
630 #elif defined(__m68k__)
631 #define PTOMMAP(paddr) m68k_btop((char *)paddr)
632 #elif defined(__mips__)
633 #define PTOMMAP(paddr) mips_btop(paddr)
634 #elif defined(__powerpc__)
635 #define PTOMMAP(paddr) (paddr)
636 #elif defined(__sh__)
637 #define PTOMMAP(paddr) sh3_btop(paddr)
638 #elif defined(__sparc__)
639 #define PTOMMAP(paddr) (paddr)
640 #elif defined(__sparc64__)
641 #define PTOMMAP(paddr) atop(paddr)
642 #elif defined(__vax__)
643 #define PTOMMAP(paddr) btop((u_int)paddr)
646 return PTOMMAP(paddr
);
650 udl_alloc_screen(void *v
, const struct wsscreen_descr
*type
,
651 void **cookiep
, int *curxp
, int *curyp
, long *attrp
)
653 struct udl_softc
*sc
= v
;
655 if (sc
->sc_nscreens
> 0)
661 sc
->sc_ri
.ri_depth
= sc
->sc_depth
;
662 sc
->sc_ri
.ri_bits
= NULL
;
663 sc
->sc_ri
.ri_width
= sc
->sc_width
;
664 sc
->sc_ri
.ri_height
= sc
->sc_height
;
665 sc
->sc_ri
.ri_stride
= sc
->sc_width
* (sc
->sc_depth
/ 8);
666 sc
->sc_ri
.ri_hw
= sc
;
667 sc
->sc_ri
.ri_flg
= 0;
669 if (sc
->sc_depth
== 16) {
670 sc
->sc_ri
.ri_rnum
= 5;
671 sc
->sc_ri
.ri_gnum
= 6;
672 sc
->sc_ri
.ri_bnum
= 5;
673 sc
->sc_ri
.ri_rpos
= 11;
674 sc
->sc_ri
.ri_gpos
= 5;
675 sc
->sc_ri
.ri_bpos
= 0;
678 rasops_init(&sc
->sc_ri
, sc
->sc_height
/ 8, sc
->sc_width
/ 8);
680 sc
->sc_ri
.ri_ops
.cursor
= udl_cursor
;
681 sc
->sc_ri
.ri_ops
.putchar
= udl_putchar
;
682 sc
->sc_ri
.ri_ops
.copycols
= udl_copycols
;
683 sc
->sc_ri
.ri_ops
.erasecols
= udl_erasecols
;
684 sc
->sc_ri
.ri_ops
.copyrows
= udl_copyrows
;
685 sc
->sc_ri
.ri_ops
.eraserows
= udl_eraserows
;
687 sc
->sc_ri
.ri_ops
.allocattr(&sc
->sc_ri
, 0, 0, 0, attrp
);
689 sc
->sc_defaultscreen
.ncols
= sc
->sc_ri
.ri_cols
;
690 sc
->sc_defaultscreen
.nrows
= sc
->sc_ri
.ri_rows
;
691 sc
->sc_defaultscreen
.textops
= &sc
->sc_ri
.ri_ops
;
692 sc
->sc_defaultscreen
.fontwidth
= sc
->sc_ri
.ri_font
->fontwidth
;
693 sc
->sc_defaultscreen
.fontheight
= sc
->sc_ri
.ri_font
->fontheight
;
694 sc
->sc_defaultscreen
.capabilities
= sc
->sc_ri
.ri_caps
;
696 *cookiep
= &sc
->sc_ri
;
706 udl_free_screen(void *v
, void *cookie
)
708 struct udl_softc
*sc
= v
;
714 udl_show_screen(void *v
, void *cookie
, int waitok
,
715 void (*cb
)(void *, int, int), void *cbarg
)
722 udl_cmd_add_decomptable(struct udl_softc
*sc
, uint8_t *buf
, int len
)
725 udl_cmd_add_2(sc
, (UDL_BULK_SOC
<< 8) | UDL_BULK_CMD_DECOMP
);
726 udl_cmd_add_4(sc
, 0x263871cd); /* magic number */
727 udl_cmd_add_4(sc
, 0x00000200); /* 512 byte chunks */
728 memcpy(sc
->sc_cmd_buf
, buf
, len
);
729 sc
->sc_cmd_buf
+= len
;
733 udl_comp_load(struct udl_softc
*sc
)
735 struct udl_huffman
*h
;
740 if (!(sc
->sc_flags
& UDL_DECOMPRDY
)) {
741 error
= firmware_load("udl", "udl-decomp", &decomp
,
744 aprint_error_dev(sc
->sc_dev
,
745 "error %d, could not read decomp table %s!\n",
746 error
, "udl-decomp");
749 udl_cmd_add_decomptable(sc
, decomp
, decomp_size
);
750 firmware_free(decomp
, decomp_size
);
751 if (udl_cmd_send(sc
) != 0)
753 sc
->sc_flags
|= UDL_DECOMPRDY
;
756 if (!(sc
->sc_flags
& UDL_COMPRDY
)) {
757 error
= firmware_load("udl", "udl-comp", &sc
->sc_huffman
,
758 &sc
->sc_huffman_size
);
760 aprint_error_dev(sc
->sc_dev
,
761 "error %d, could not read huffman table %s!\n",
765 h
= (struct udl_huffman
*)sc
->sc_huffman
;
766 for (i
= 0; i
< UDL_HUFFMAN_RECORDS
; i
++)
767 h
[i
].bit_pattern
= be32toh(h
[i
].bit_pattern
);
768 sc
->sc_huffman_base
= sc
->sc_huffman
+ UDL_HUFFMAN_BASE
;
769 sc
->sc_flags
|= UDL_COMPRDY
;
774 udl_comp_unload(struct udl_softc
*sc
)
777 if (sc
->sc_flags
& UDL_COMPRDY
) {
778 firmware_free(sc
->sc_huffman
, sc
->sc_huffman_size
);
779 sc
->sc_huffman
= NULL
;
780 sc
->sc_huffman_size
= 0;
781 sc
->sc_flags
&= ~UDL_COMPRDY
;
786 udl_fbmem_alloc(struct udl_softc
*sc
)
789 if (sc
->sc_fbmem
== NULL
) {
790 sc
->sc_fbmem
= kmem_alloc(UDL_FBMEM_SIZE(sc
), KM_SLEEP
);
791 if (sc
->sc_fbmem
== NULL
)
799 udl_fbmem_free(struct udl_softc
*sc
)
802 if (sc
->sc_fbmem
!= NULL
) {
803 kmem_free(sc
->sc_fbmem
, UDL_FBMEM_SIZE(sc
));
809 udl_cmdq_alloc(struct udl_softc
*sc
)
811 struct udl_cmdq
*cmdq
;
814 TAILQ_INIT(&sc
->sc_freecmd
);
815 TAILQ_INIT(&sc
->sc_xfercmd
);
817 for (i
= 0; i
< UDL_NCMDQ
; i
++) {
818 cmdq
= &sc
->sc_cmdq
[i
];
822 cmdq
->cq_xfer
= usbd_alloc_xfer(sc
->sc_udev
);
823 if (cmdq
->cq_xfer
== NULL
) {
824 aprint_error_dev(sc
->sc_dev
,
825 "%s: can't allocate xfer handle!\n", __func__
);
830 usbd_alloc_buffer(cmdq
->cq_xfer
, UDL_CMD_BUFFER_SIZE
);
831 if (cmdq
->cq_buf
== NULL
) {
832 aprint_error_dev(sc
->sc_dev
,
833 "%s: can't allocate xfer buffer!\n", __func__
);
837 TAILQ_INSERT_TAIL(&sc
->sc_freecmd
, cmdq
, cq_chain
);
848 udl_cmdq_free(struct udl_softc
*sc
)
850 struct udl_cmdq
*cmdq
;
853 for (i
= 0; i
< UDL_NCMDQ
; i
++) {
854 cmdq
= &sc
->sc_cmdq
[i
];
856 if (cmdq
->cq_xfer
!= NULL
) {
857 usbd_free_xfer(cmdq
->cq_xfer
);
858 cmdq
->cq_xfer
= NULL
;
864 static struct udl_cmdq
*
865 udl_cmdq_get(struct udl_softc
*sc
)
867 struct udl_cmdq
*cmdq
;
869 cmdq
= TAILQ_FIRST(&sc
->sc_freecmd
);
871 TAILQ_REMOVE(&sc
->sc_freecmd
, cmdq
, cq_chain
);
872 UDL_EVCNT_INCR(&sc
->sc_ev_cmdq_get
);
879 udl_cmdq_put(struct udl_softc
*sc
, struct udl_cmdq
*cmdq
)
882 TAILQ_INSERT_TAIL(&sc
->sc_freecmd
, cmdq
, cq_chain
);
883 UDL_EVCNT_INCR(&sc
->sc_ev_cmdq_put
);
887 udl_cmdq_flush(struct udl_softc
*sc
)
890 mutex_enter(&sc
->sc_mtx
);
891 while (TAILQ_FIRST(&sc
->sc_xfercmd
) != NULL
)
892 cv_wait(&sc
->sc_cv
, &sc
->sc_mtx
);
893 mutex_exit(&sc
->sc_mtx
);
897 udl_cursor(void *cookie
, int on
, int row
, int col
)
899 struct rasops_info
*ri
= cookie
;
900 struct udl_softc
*sc
= ri
->ri_hw
;
901 int x
, y
, width
, height
;
903 if (ri
->ri_flg
& RI_CURSOR
)
904 udl_restore_char(ri
);
910 ri
->ri_flg
|= RI_CURSOR
;
912 x
= col
* ri
->ri_font
->fontwidth
;
913 y
= row
* ri
->ri_font
->fontheight
;
914 width
= ri
->ri_font
->fontwidth
;
915 height
= ri
->ri_font
->fontheight
;
917 /* save the last character block to off-screen */
918 udl_copy_rect(sc
, x
, y
, 0, sc
->sc_offscreen
, width
, height
);
921 udl_fill_rect(sc
, 0xffff, x
, y
, width
, 1);
922 udl_fill_rect(sc
, 0xffff, x
, y
+ 1, 1, height
- 2);
923 udl_fill_rect(sc
, 0xffff, x
+ width
- 1, y
+ 1, 1, height
- 2);
924 udl_fill_rect(sc
, 0xffff, x
, y
+ height
- 1, width
, 1);
926 udl_cmd_send_async(sc
);
928 ri
->ri_flg
&= ~RI_CURSOR
;
932 udl_putchar(void *cookie
, int row
, int col
, u_int uc
, long attr
)
934 struct rasops_info
*ri
= cookie
;
935 struct udl_softc
*sc
= ri
->ri_hw
;
937 int fg
, bg
, underline
, x
, y
, width
, height
;
939 rasops_unpack_attr(attr
, &fg
, &bg
, &underline
);
940 rgb16
[1] = (uint16_t)ri
->ri_devcmap
[fg
];
941 rgb16
[0] = (uint16_t)ri
->ri_devcmap
[bg
];
943 x
= col
* ri
->ri_font
->fontwidth
;
944 y
= row
* ri
->ri_font
->fontheight
;
945 width
= ri
->ri_font
->fontwidth
;
946 height
= ri
->ri_font
->fontheight
;
950 * Writting a block for the space character instead rendering
951 * it from font bits is more slim.
953 udl_fill_rect(sc
, rgb16
[0], x
, y
, width
, height
);
955 /* render a character from font bits */
956 udl_draw_char(ri
, rgb16
, uc
, x
, y
);
960 udl_fill_rect(sc
, rgb16
[1], x
, y
+ height
- 1, width
, 1);
963 udl_cmd_send_async(sc
);
968 udl_copycols(void *cookie
, int row
, int src
, int dst
, int num
)
970 struct rasops_info
*ri
= cookie
;
971 struct udl_softc
*sc
= ri
->ri_hw
;
972 int sx
, dx
, y
, width
, height
;
974 sx
= src
* ri
->ri_font
->fontwidth
;
975 dx
= dst
* ri
->ri_font
->fontwidth
;
976 y
= row
* ri
->ri_font
->fontheight
;
977 width
= num
* ri
->ri_font
->fontwidth
;
978 height
= ri
->ri_font
->fontheight
;
980 /* copy row block to off-screen first to fix overlay-copy problem */
981 udl_copy_rect(sc
, sx
, y
, 0, sc
->sc_offscreen
, width
, height
);
983 /* copy row block back from off-screen now */
984 udl_copy_rect(sc
, 0, sc
->sc_offscreen
, dx
, y
, width
, height
);
986 udl_cmd_send_async(sc
);
991 udl_erasecols(void *cookie
, int row
, int col
, int num
, long attr
)
993 struct rasops_info
*ri
= cookie
;
994 struct udl_softc
*sc
= ri
->ri_hw
;
996 int fg
, bg
, x
, y
, width
, height
;
998 rasops_unpack_attr(attr
, &fg
, &bg
, NULL
);
999 rgb16
= (uint16_t)ri
->ri_devcmap
[bg
];
1001 x
= col
* ri
->ri_font
->fontwidth
;
1002 y
= row
* ri
->ri_font
->fontheight
;
1003 width
= num
* ri
->ri_font
->fontwidth
;
1004 height
= ri
->ri_font
->fontheight
;
1006 udl_fill_rect(sc
, rgb16
, x
, y
, width
, height
);
1008 udl_cmd_send_async(sc
);
1013 udl_copyrows(void *cookie
, int src
, int dst
, int num
)
1015 struct rasops_info
*ri
= cookie
;
1016 struct udl_softc
*sc
= ri
->ri_hw
;
1017 int sy
, ey
, dy
, width
, height
;
1019 width
= ri
->ri_emuwidth
;
1020 height
= ri
->ri_font
->fontheight
;
1024 ey
= (src
+ num
) * height
;
1028 udl_copy_rect(sc
, 0, sy
, 0, dy
, width
, height
);
1033 sy
= (src
+ num
) * height
;
1035 dy
= (dst
+ num
) * height
;
1040 udl_copy_rect(sc
, 0, sy
, 0, dy
, width
, height
);
1044 udl_cmd_send_async(sc
);
1049 udl_eraserows(void *cookie
, int row
, int num
, long attr
)
1051 struct rasops_info
*ri
= cookie
;
1052 struct udl_softc
*sc
= ri
->ri_hw
;
1054 int fg
, bg
, y
, width
, height
;
1056 rasops_unpack_attr(attr
, &fg
, &bg
, NULL
);
1057 rgb16
= (uint16_t)ri
->ri_devcmap
[bg
];
1059 y
= row
* ri
->ri_font
->fontheight
;
1060 width
= ri
->ri_emuwidth
;
1061 height
= num
* ri
->ri_font
->fontheight
;
1063 udl_fill_rect(sc
, rgb16
, 0, y
, width
, height
);
1065 udl_cmd_send_async(sc
);
1070 udl_restore_char(struct rasops_info
*ri
)
1072 struct udl_softc
*sc
= ri
->ri_hw
;
1073 int x
, y
, width
, height
;
1075 x
= ri
->ri_ccol
* ri
->ri_font
->fontwidth
;
1076 y
= ri
->ri_crow
* ri
->ri_font
->fontheight
;
1077 width
= ri
->ri_font
->fontwidth
;
1078 height
= ri
->ri_font
->fontheight
;
1080 /* restore the last saved character from off-screen */
1081 udl_copy_rect(sc
, 0, sc
->sc_offscreen
, x
, y
, width
, height
);
1085 udl_draw_char(struct rasops_info
*ri
, uint16_t *rgb16
, u_int uc
, int x
, int y
)
1087 struct udl_softc
*sc
= ri
->ri_hw
;
1088 struct wsdisplay_font
*font
= ri
->ri_font
;
1090 uint16_t pixels
[32];
1094 soff
= y
* sc
->sc_width
+ x
;
1095 eoff
= (y
+ font
->fontheight
) * sc
->sc_width
+ x
;
1096 fontbase
= (uint8_t *)font
->data
+ (uc
- font
->firstchar
) *
1099 while (soff
< eoff
) {
1101 switch (font
->stride
) {
1103 fontbits
|= fontbase
[3];
1106 fontbits
|= fontbase
[2] << 8;
1109 fontbits
|= fontbase
[1] << 16;
1112 fontbits
|= fontbase
[0] << 24;
1114 fontbase
+= font
->stride
;
1116 for (i
= 0; i
< font
->fontwidth
; i
++) {
1117 pixels
[i
] = rgb16
[(fontbits
>> 31) & 1];
1121 udl_draw_line(sc
, pixels
, soff
, font
->fontwidth
);
1122 soff
+= sc
->sc_width
;
1127 udl_copy_rect(struct udl_softc
*sc
, int sx
, int sy
, int dx
, int dy
, int width
,
1130 int sbase
, soff
, ebase
, eoff
, dbase
, doff
, width_cur
;
1132 sbase
= sy
* sc
->sc_width
;
1133 ebase
= (sy
+ height
) * sc
->sc_width
;
1134 dbase
= dy
* sc
->sc_width
;
1141 if (width
>= UDL_CMD_WIDTH_MAX
)
1142 width_cur
= UDL_CMD_WIDTH_MAX
;
1146 while (soff
< eoff
) {
1147 udl_copy_line(sc
, soff
, doff
, width_cur
);
1148 soff
+= sc
->sc_width
;
1149 doff
+= sc
->sc_width
;
1159 udl_fill_rect(struct udl_softc
*sc
, uint16_t rgb16
, int x
, int y
, int width
,
1162 int sbase
, soff
, ebase
, eoff
, width_cur
;
1164 sbase
= y
* sc
->sc_width
;
1165 ebase
= (y
+ height
) * sc
->sc_width
;
1171 if (width
>= UDL_CMD_WIDTH_MAX
)
1172 width_cur
= UDL_CMD_WIDTH_MAX
;
1176 while (soff
< eoff
) {
1177 udl_fill_line(sc
, rgb16
, soff
, width_cur
);
1178 soff
+= sc
->sc_width
;
1188 udl_draw_rect(struct udl_softc
*sc
, struct udl_ioctl_damage
*d
)
1190 int sbase
, soff
, ebase
, eoff
, x
, y
, width
, width_cur
, height
;
1194 width
= d
->x2
- d
->x1
+ 1;
1195 height
= d
->y2
- d
->y1
+ 1;
1196 sbase
= y
* sc
->sc_width
;
1197 ebase
= (y
+ height
) * sc
->sc_width
;
1203 if (width
>= UDL_CMD_WIDTH_MAX
)
1204 width_cur
= UDL_CMD_WIDTH_MAX
;
1208 while (soff
< eoff
) {
1209 udl_draw_line(sc
, (uint16_t *)sc
->sc_fbmem
+ soff
,
1211 soff
+= sc
->sc_width
;
1218 udl_cmd_send_async(sc
);
1222 udl_draw_rect_comp(struct udl_softc
*sc
, struct udl_ioctl_damage
*d
)
1224 int soff
, eoff
, x
, y
, width
, height
;
1228 width
= d
->x2
- d
->x1
+ 1;
1229 height
= d
->y2
- d
->y1
+ 1;
1230 soff
= y
* sc
->sc_width
+ x
;
1231 eoff
= (y
+ height
) * sc
->sc_width
+ x
;
1233 udl_reg_write_1(sc
, UDL_REG_SYNC
, 0xff);
1234 sc
->sc_cmd_cblen
= 4;
1236 while (soff
< eoff
) {
1237 udl_draw_line_comp(sc
, (uint16_t *)sc
->sc_fbmem
+ soff
, soff
,
1239 soff
+= sc
->sc_width
;
1242 udl_cmd_send_async(sc
);
1247 udl_copy_line(struct udl_softc
*sc
, int soff
, int doff
, int width
)
1250 if (__predict_false((UDL_CMD_BUFSIZE(sc
) + UDL_CMD_COPY_SIZE
+ 2) >
1251 UDL_CMD_BUFFER_SIZE
))
1252 udl_cmd_send_async(sc
);
1254 udl_cmd_add_2(sc
, (UDL_BULK_SOC
<< 8) | UDL_BULK_CMD_FB_COPY16
);
1255 udl_cmd_add_4(sc
, ((doff
* 2) << 8) | (width
& 0xff));
1257 udl_cmd_add_3(sc
, soff
* 2);
1261 udl_fill_line(struct udl_softc
*sc
, uint16_t rgb16
, int off
, int width
)
1264 if (__predict_false((UDL_CMD_BUFSIZE(sc
) + UDL_CMD_FILL_SIZE
+ 2) >
1265 UDL_CMD_BUFFER_SIZE
))
1266 udl_cmd_send_async(sc
);
1268 udl_cmd_add_2(sc
, (UDL_BULK_SOC
<< 8) | UDL_BULK_CMD_FB_RLE16
);
1269 udl_cmd_add_4(sc
, ((off
* 2) << 8) | (width
& 0xff));
1271 udl_cmd_add_1(sc
, width
);
1272 udl_cmd_add_2(sc
, rgb16
);
1276 udl_draw_line(struct udl_softc
*sc
, uint16_t *buf
, int off
, int width
)
1279 if (__predict_false(
1280 (UDL_CMD_BUFSIZE(sc
) + UDL_CMD_DRAW_SIZE(width
) + 2) >
1281 UDL_CMD_BUFFER_SIZE
))
1282 udl_cmd_send_async(sc
);
1284 udl_cmd_add_2(sc
, (UDL_BULK_SOC
<< 8) | UDL_BULK_CMD_FB_WRITE16
);
1285 udl_cmd_add_4(sc
, ((off
* 2) << 8) | (width
& 0xff));
1287 udl_cmd_add_buf(sc
, buf
, width
);
1291 udl_cmd_add_buf_comp(struct udl_softc
*sc
, uint16_t *buf
, int width
)
1293 struct udl_huffman
*h
;
1294 uint16_t *startp
, *endp
;
1295 uint32_t bit_pattern
;
1298 uint8_t bit_count
, bit_pos
, bit_rem
, curlen
;
1301 if (width
>= UDL_CMD_WIDTH_MAX
)
1302 endp
= buf
+ UDL_CMD_WIDTH_MAX
;
1306 prev
= bit_pos
= *sc
->sc_cmd_buf
= 0;
1310 * Generate a sub-block with maximal 256 pixels compressed data.
1312 while (buf
< endp
) {
1313 /* get difference between current and previous pixel */
1316 /* get the huffman difference bit sequence */
1317 h
= (struct udl_huffman
*)sc
->sc_huffman_base
+ diff
;
1318 bit_count
= h
->bit_count
;
1319 bit_pattern
= h
->bit_pattern
;
1321 curlen
= (bit_pos
+ bit_count
+ 7) / 8;
1322 if (__predict_false((sc
->sc_cmd_cblen
+ curlen
+ 1) >
1323 UDL_CMD_COMP_BLOCK_SIZE
))
1326 /* generate one pixel compressed data */
1327 while (bit_count
>= bit_rem
) {
1328 *sc
->sc_cmd_buf
++ |=
1329 (bit_pattern
& ((1 << bit_rem
) - 1)) << bit_pos
;
1330 *sc
->sc_cmd_buf
= 0;
1332 bit_count
-= bit_rem
;
1333 bit_pattern
>>= bit_rem
;
1338 if (bit_count
> 0) {
1340 (bit_pattern
& ((1 << bit_count
) - 1)) << bit_pos
;
1341 bit_pos
+= bit_count
;
1342 bit_rem
-= bit_count
;
1349 * If we have bits left in our last byte, round up to the next
1350 * byte, so we don't overwrite them.
1357 /* return how many pixels we have compressed */
1358 return buf
- startp
;
1362 udl_draw_line_comp(struct udl_softc
*sc
, uint16_t *buf
, int off
, int width
)
1368 if (__predict_false(
1369 (sc
->sc_cmd_cblen
+ UDL_CMD_COMP_MIN_SIZE
+ 1) >
1370 UDL_CMD_COMP_BLOCK_SIZE
)) {
1371 if (UDL_CMD_BUFSIZE(sc
) < UDL_CMD_COMP_THRESHOLD
) {
1372 while (sc
->sc_cmd_cblen
<
1373 UDL_CMD_COMP_BLOCK_SIZE
) {
1374 *sc
->sc_cmd_buf
++ = 0;
1378 udl_cmd_send_async(sc
);
1379 udl_reg_write_1(sc
, UDL_REG_SYNC
, 0xff);
1380 sc
->sc_cmd_cblen
= 4;
1383 udl_cmd_add_2(sc
, (UDL_BULK_SOC
<< 8) |
1384 (UDL_BULK_CMD_FB_WRITE16
| UDL_BULK_CMD_FB_COMP
));
1385 udl_cmd_add_4(sc
, (off
* 2) << 8);
1387 widthp
= sc
->sc_cmd_buf
- 1;
1389 sc
->sc_cmd_cblen
+= UDL_CMD_HEADER_SIZE
;
1391 width_cur
= udl_cmd_add_buf_comp(sc
, buf
, width
);
1393 *widthp
= width_cur
;
1401 udl_cmd_send(struct udl_softc
*sc
)
1403 struct udl_cmdq
*cmdq
;
1407 cmdq
= sc
->sc_cmd_cur
;
1409 /* mark end of command stack */
1410 udl_cmd_add_2(sc
, (UDL_BULK_SOC
<< 8) | UDL_BULK_CMD_EOC
);
1412 len
= UDL_CMD_BUFSIZE(sc
);
1415 error
= usbd_bulk_transfer(cmdq
->cq_xfer
, sc
->sc_tx_pipeh
,
1416 USBD_NO_COPY
, USBD_NO_TIMEOUT
, cmdq
->cq_buf
, &len
, "udlcmds");
1418 UDL_CMD_BUFINIT(sc
);
1420 if (error
!= USBD_NORMAL_COMPLETION
) {
1421 aprint_error_dev(sc
->sc_dev
, "%s: %s!\n", __func__
,
1422 usbd_errstr(error
));
1430 udl_cmd_send_async(struct udl_softc
*sc
)
1432 struct udl_cmdq
*cmdq
;
1439 * All tty ops for wsemul are called with tty_lock spin mutex held,
1440 * so we can't call cv_wait(9) here to acquire a free buffer.
1441 * For now, all commands and data for wsemul ops are discarded
1442 * if there is no free command buffer, and then screen text might
1443 * be corrupted on large scroll ops etc.
1445 * Probably we have to reorganize the giant tty_lock mutex, or
1446 * change wsdisplay APIs (especially wsdisplaystart()) to return
1447 * a number of actually handled characters as OpenBSD does, but
1448 * the latter one requires whole API changes around rasops(9) etc.
1450 if (sc
->sc_mode
== WSDISPLAYIO_MODE_EMUL
) {
1451 if (TAILQ_FIRST(&sc
->sc_freecmd
) == NULL
) {
1452 UDL_CMD_BUFINIT(sc
);
1458 cmdq
= sc
->sc_cmd_cur
;
1460 /* mark end of command stack */
1461 udl_cmd_add_2(sc
, (UDL_BULK_SOC
<< 8) | UDL_BULK_CMD_EOC
);
1463 len
= UDL_CMD_BUFSIZE(sc
);
1466 mutex_enter(&sc
->sc_mtx
);
1467 usbd_setup_xfer(cmdq
->cq_xfer
, sc
->sc_tx_pipeh
, cmdq
, cmdq
->cq_buf
,
1468 len
, USBD_NO_COPY
, USBD_NO_TIMEOUT
, udl_cmd_send_async_cb
);
1469 error
= usbd_transfer(cmdq
->cq_xfer
);
1470 if (error
!= USBD_NORMAL_COMPLETION
&& error
!= USBD_IN_PROGRESS
) {
1471 aprint_error_dev(sc
->sc_dev
, "%s: %s!\n", __func__
,
1472 usbd_errstr(error
));
1473 mutex_exit(&sc
->sc_mtx
);
1477 TAILQ_INSERT_TAIL(&sc
->sc_xfercmd
, cmdq
, cq_chain
);
1478 cmdq
= udl_cmdq_get(sc
);
1479 mutex_exit(&sc
->sc_mtx
);
1480 while (cmdq
== NULL
) {
1482 UDL_EVCNT_INCR(&sc
->sc_ev_cmdq_wait
);
1483 mutex_enter(&sc
->sc_mtx
);
1484 err
= cv_timedwait(&sc
->sc_cv
, &sc
->sc_mtx
,
1485 mstohz(100) /* XXX is this needed? */);
1487 DPRINTF(("%s: %s: cv timeout (error = %d)\n",
1488 device_xname(sc
->sc_dev
), __func__
, err
));
1489 UDL_EVCNT_INCR(&sc
->sc_ev_cmdq_timeout
);
1491 cmdq
= udl_cmdq_get(sc
);
1492 mutex_exit(&sc
->sc_mtx
);
1494 sc
->sc_cmd_cur
= cmdq
;
1496 UDL_CMD_BUFINIT(sc
);
1500 udl_cmd_send_async_cb(usbd_xfer_handle xfer
, usbd_private_handle priv
,
1503 struct udl_cmdq
*cmdq
= priv
;
1504 struct udl_softc
*sc
= cmdq
->cq_sc
;
1506 if (status
!= USBD_NORMAL_COMPLETION
) {
1507 aprint_error_dev(sc
->sc_dev
, "%s: %s!\n", __func__
,
1508 usbd_errstr(status
));
1510 if (status
== USBD_NOT_STARTED
|| status
== USBD_CANCELLED
)
1512 if (status
== USBD_STALLED
)
1513 usbd_clear_endpoint_stall_async(sc
->sc_tx_pipeh
);
1516 mutex_enter(&sc
->sc_mtx
);
1517 TAILQ_REMOVE(&sc
->sc_xfercmd
, cmdq
, cq_chain
);
1518 udl_cmdq_put(sc
, cmdq
);
1520 /* wakeup xfer op that sleeps for a free xfer buffer */
1521 cv_signal(&sc
->sc_cv
);
1522 mutex_exit(&sc
->sc_mtx
);
1526 udl_ctrl_msg(struct udl_softc
*sc
, uint8_t rt
, uint8_t r
, uint16_t index
,
1527 uint16_t value
, uint8_t *buf
, uint16_t len
)
1529 usb_device_request_t req
;
1532 req
.bmRequestType
= rt
;
1534 USETW(req
.wIndex
, index
);
1535 USETW(req
.wValue
, value
);
1536 USETW(req
.wLength
, len
);
1538 error
= usbd_do_request(sc
->sc_udev
, &req
, buf
);
1539 if (error
!= USBD_NORMAL_COMPLETION
) {
1540 aprint_error_dev(sc
->sc_dev
, "%s: %s!\n", __func__
,
1541 usbd_errstr(error
));
1549 udl_init(struct udl_softc
*sc
)
1551 static uint8_t key
[16] = {
1552 0x57, 0xcd, 0xdc, 0xa7, 0x1c, 0x88, 0x5e, 0x15,
1553 0x60, 0xfe, 0xc6, 0x97, 0x16, 0x3d, 0x47, 0xf2
1555 uint8_t status
[4], val
;
1557 if (udl_ctrl_msg(sc
, UT_READ_VENDOR_DEVICE
, UDL_CTRL_CMD_READ_STATUS
,
1558 0x0000, 0x0000, status
, sizeof(status
)) != 0)
1561 if (udl_ctrl_msg(sc
, UT_READ_VENDOR_DEVICE
, UDL_CTRL_CMD_READ_1
,
1562 0xc484, 0x0000, &val
, 1) != 0)
1566 if (udl_ctrl_msg(sc
, UT_WRITE_VENDOR_DEVICE
, UDL_CTRL_CMD_WRITE_1
,
1567 0xc41f, 0x0000, &val
, 1) != 0)
1570 if (udl_ctrl_msg(sc
, UT_WRITE_VENDOR_DEVICE
, UDL_CTRL_CMD_SET_KEY
,
1571 0x0000, 0x0000, key
, sizeof(key
)) != 0)
1575 if (udl_ctrl_msg(sc
, UT_WRITE_VENDOR_DEVICE
, UDL_CTRL_CMD_WRITE_1
,
1576 0xc40b, 0x0000, &val
, 1) != 0)
1583 udl_read_edid(struct udl_softc
*sc
)
1585 uint8_t buf
[64], edid
[128];
1588 memset(&sc
->sc_ei
, 0, sizeof(struct edid_info
));
1591 if (udl_ctrl_msg(sc
, UT_READ_VENDOR_DEVICE
, UDL_CTRL_CMD_READ_EDID
,
1592 0x00a1, (offset
<< 8), buf
, 64) != 0)
1596 memcpy(&edid
[offset
], &buf
[1], 63);
1599 if (udl_ctrl_msg(sc
, UT_READ_VENDOR_DEVICE
, UDL_CTRL_CMD_READ_EDID
,
1600 0x00a1, (offset
<< 8), buf
, 64) != 0)
1604 memcpy(&edid
[offset
], &buf
[1], 63);
1607 if (udl_ctrl_msg(sc
, UT_READ_VENDOR_DEVICE
, UDL_CTRL_CMD_READ_EDID
,
1608 0x00a1, (offset
<< 8), buf
, 3) != 0)
1612 memcpy(&edid
[offset
], &buf
[1], 2);
1614 if (edid_parse(edid
, &sc
->sc_ei
) == 0) {
1616 edid_print(&sc
->sc_ei
);
1622 udl_set_address(struct udl_softc
*sc
, int start16
, int stride16
, int start8
,
1625 udl_reg_write_1(sc
, UDL_REG_SYNC
, 0x00);
1626 udl_reg_write_3(sc
, UDL_REG_ADDR_START16
, start16
);
1627 udl_reg_write_3(sc
, UDL_REG_ADDR_STRIDE16
, stride16
);
1628 udl_reg_write_3(sc
, UDL_REG_ADDR_START8
, start8
);
1629 udl_reg_write_3(sc
, UDL_REG_ADDR_STRIDE8
, stride8
);
1630 udl_reg_write_1(sc
, UDL_REG_SYNC
, 0xff);
1634 udl_blank(struct udl_softc
*sc
, int blank
)
1638 udl_reg_write_1(sc
, UDL_REG_BLANK
, UDL_REG_BLANK_ON
);
1640 udl_reg_write_1(sc
, UDL_REG_BLANK
, UDL_REG_BLANK_OFF
);
1641 udl_reg_write_1(sc
, UDL_REG_SYNC
, 0xff);
1645 udl_lfsr(uint16_t count
)
1647 uint16_t val
= 0xffff;
1650 val
= (uint16_t)(val
<< 1) | ((uint16_t)(
1651 (uint16_t)(val
<< 0) ^
1652 (uint16_t)(val
<< 11) ^
1653 (uint16_t)(val
<< 13) ^
1654 (uint16_t)(val
<< 14)
1663 udl_set_resolution(struct udl_softc
*sc
, const struct videomode
*vmp
)
1666 int start16
, stride16
, start8
, stride8
;
1668 /* set video memory offsets */
1670 stride16
= sc
->sc_width
* 2;
1671 start8
= stride16
* sc
->sc_height
;
1672 stride8
= sc
->sc_width
;
1673 udl_set_address(sc
, start16
, stride16
, start8
, stride8
);
1675 /* write resolution values */
1676 udl_reg_write_1(sc
, UDL_REG_SYNC
, 0x00);
1677 udl_reg_write_1(sc
, UDL_REG_COLORDEPTH
, UDL_REG_COLORDEPTH_16
);
1678 val
= vmp
->htotal
- vmp
->hsync_start
;
1679 udl_reg_write_2(sc
, UDL_REG_XDISPLAYSTART
, udl_lfsr(val
));
1680 val
+= vmp
->hdisplay
;
1681 udl_reg_write_2(sc
, UDL_REG_XDISPLAYEND
, udl_lfsr(val
));
1682 val
= vmp
->vtotal
- vmp
->vsync_start
;
1683 udl_reg_write_2(sc
, UDL_REG_YDISPLAYSTART
, udl_lfsr(val
));
1684 val
+= vmp
->vdisplay
;
1685 udl_reg_write_2(sc
, UDL_REG_YDISPLAYEND
, udl_lfsr(val
));
1686 val
= vmp
->htotal
- 1;
1687 udl_reg_write_2(sc
, UDL_REG_XENDCOUNT
, udl_lfsr(val
));
1688 val
= vmp
->hsync_end
- vmp
->hsync_start
+ 1;
1689 if (vmp
->flags
& VID_PHSYNC
) {
1690 udl_reg_write_2(sc
, UDL_REG_HSYNCSTART
, udl_lfsr(1));
1691 udl_reg_write_2(sc
, UDL_REG_HSYNCEND
, udl_lfsr(val
));
1693 udl_reg_write_2(sc
, UDL_REG_HSYNCSTART
, udl_lfsr(val
));
1694 udl_reg_write_2(sc
, UDL_REG_HSYNCEND
, udl_lfsr(1));
1696 val
= vmp
->hdisplay
;
1697 udl_reg_write_2(sc
, UDL_REG_HPIXELS
, val
);
1699 udl_reg_write_2(sc
, UDL_REG_YENDCOUNT
, udl_lfsr(val
));
1700 val
= vmp
->vsync_end
- vmp
->vsync_start
;
1701 if (vmp
->flags
& VID_PVSYNC
) {
1702 udl_reg_write_2(sc
, UDL_REG_VSYNCSTART
, udl_lfsr(0));
1703 udl_reg_write_2(sc
, UDL_REG_VSYNCEND
, udl_lfsr(val
));
1705 udl_reg_write_2(sc
, UDL_REG_VSYNCSTART
, udl_lfsr(val
));
1706 udl_reg_write_2(sc
, UDL_REG_VSYNCEND
, udl_lfsr(0));
1708 val
= vmp
->vdisplay
;
1709 udl_reg_write_2(sc
, UDL_REG_VPIXELS
, val
);
1710 val
= vmp
->dot_clock
/ 5;
1711 udl_reg_write_2(sc
, UDL_REG_PIXELCLOCK5KHZ
, bswap16(val
));
1712 udl_reg_write_1(sc
, UDL_REG_SYNC
, 0xff);
1714 if (udl_cmd_send(sc
) != 0)
1718 udl_fill_rect(sc
, 0, 0, 0, sc
->sc_width
, sc
->sc_height
);
1720 if (udl_cmd_send(sc
) != 0)
1723 /* show framebuffer content */
1726 if (udl_cmd_send(sc
) != 0)
1729 sc
->sc_blank
= WSDISPLAYIO_VIDEO_ON
;
1734 static const struct videomode
*
1735 udl_videomode_lookup(const char *name
)
1739 for (i
= 0; i
< videomode_count
; i
++)
1740 if (strcmp(name
, videomode_list
[i
].name
) == 0)
1741 return &videomode_list
[i
];