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