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