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