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