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