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