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