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