Bug Summary

File:dev/usb/udl.c
Warning:line 1598, column 26
Although the value stored to 'padding' is used in the enclosing expression, the value is never actually read from 'padding'

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;
Although the value stored to 'padding' is used in the enclosing expression, the value is never actually read from 'padding'
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;
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