Bug Summary

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

Annotated Source Code

Press '?' to see keyboard shortcuts

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