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