Bug Summary

File:dev/usb/udl.c
Warning:line 1601, 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.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;
Although the value stored to 'padding' is used in the enclosing expression, the value is never actually read from 'padding'
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;
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