Bug Summary

File:dev/usb/udl.c
Warning:line 2284, column 2
Value stored to 'r' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

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