1/*	$OpenBSD: udl.c,v 1.81 2014/12/09 07:05:06 doug Exp $ */
2/*	$FreeBSD: stable/11/sys/dev/usb/video/udl.c 355578 2019-12-10 07:07:17Z hselasky $ */
3
4/*-
5 * Copyright (c) 2015 Hans Petter Selasky <hselasky@freebsd.org>
6 * Copyright (c) 2009 Marcus Glocker <mglocker@openbsd.org>
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20
21/*
22 * Driver for the "DisplayLink DL-120 / DL-160" graphic chips based on
23 * the reversed engineered specifications of Florian Echtler
24 * <floe@butterbrot.org>:
25 *
26 * 	http://floe.butterbrot.org/displaylink/doku.php
27 */
28
29#include <sys/param.h>
30#include <sys/bus.h>
31#include <sys/callout.h>
32#include <sys/conf.h>
33#include <sys/kernel.h>
34#include <sys/lock.h>
35#include <sys/module.h>
36#include <sys/mutex.h>
37#include <sys/condvar.h>
38#include <sys/sysctl.h>
39#include <sys/systm.h>
40#include <sys/consio.h>
41#include <sys/fbio.h>
42
43#include <dev/fb/fbreg.h>
44#include <dev/syscons/syscons.h>
45
46#include <dev/videomode/videomode.h>
47#include <dev/videomode/edidvar.h>
48
49#include <dev/usb/usb.h>
50#include <dev/usb/usbdi.h>
51#include <dev/usb/usbdi_util.h>
52#include "usbdevs.h"
53
54#include <dev/usb/video/udl.h>
55
56#include "fb_if.h"
57
58#undef DPRINTF
59#undef DPRINTFN
60#define	USB_DEBUG_VAR udl_debug
61#include <dev/usb/usb_debug.h>
62
63static	SYSCTL_NODE(_hw_usb, OID_AUTO, udl, CTLFLAG_RW, 0, "USB UDL");
64
65#ifdef USB_DEBUG
66static int udl_debug = 0;
67
68SYSCTL_INT(_hw_usb_udl, OID_AUTO, debug, CTLFLAG_RWTUN,
69    &udl_debug, 0, "Debug level");
70#endif
71
72#define	UDL_FPS_MAX	60
73#define	UDL_FPS_MIN	1
74
75static int udl_fps = 25;
76SYSCTL_INT(_hw_usb_udl, OID_AUTO, fps, CTLFLAG_RWTUN,
77    &udl_fps, 0, "Frames Per Second, 1-60");
78
79static struct mtx udl_buffer_mtx;
80static struct udl_buffer_head udl_buffer_head;
81
82MALLOC_DEFINE(M_USB_DL, "USB", "USB DisplayLink");
83
84/*
85 * Prototypes.
86 */
87static usb_callback_t udl_bulk_write_callback;
88
89static device_probe_t udl_probe;
90static device_attach_t udl_attach;
91static device_detach_t udl_detach;
92static fb_getinfo_t udl_fb_getinfo;
93static fb_setblankmode_t udl_fb_setblankmode;
94
95static void udl_select_chip(struct udl_softc *, struct usb_attach_arg *);
96static int udl_init_chip(struct udl_softc *);
97static void udl_select_mode(struct udl_softc *);
98static int udl_init_resolution(struct udl_softc *);
99static void udl_fbmem_alloc(struct udl_softc *);
100static int udl_cmd_write_buf_le16(struct udl_softc *, const uint8_t *, uint32_t, uint8_t, int);
101static int udl_cmd_buf_copy_le16(struct udl_softc *, uint32_t, uint32_t, uint8_t, int);
102static void udl_cmd_insert_int_1(struct udl_cmd_buf *, uint8_t);
103static void udl_cmd_insert_int_3(struct udl_cmd_buf *, uint32_t);
104static void udl_cmd_insert_buf_le16(struct udl_cmd_buf *, const uint8_t *, uint32_t);
105static void udl_cmd_write_reg_1(struct udl_cmd_buf *, uint8_t, uint8_t);
106static void udl_cmd_write_reg_3(struct udl_cmd_buf *, uint8_t, uint32_t);
107static int udl_power_save(struct udl_softc *, int, int);
108
109static const struct usb_config udl_config[UDL_N_TRANSFER] = {
110	[UDL_BULK_WRITE_0] = {
111		.type = UE_BULK,
112		.endpoint = UE_ADDR_ANY,
113		.direction = UE_DIR_TX,
114		.flags = {.pipe_bof = 1,.force_short_xfer = 1,.ext_buffer = 1,},
115		.bufsize = UDL_CMD_MAX_DATA_SIZE * UDL_CMD_MAX_FRAMES,
116		.callback = &udl_bulk_write_callback,
117		.frames = UDL_CMD_MAX_FRAMES,
118		.timeout = 5000,	/* 5 seconds */
119	},
120	[UDL_BULK_WRITE_1] = {
121		.type = UE_BULK,
122		.endpoint = UE_ADDR_ANY,
123		.direction = UE_DIR_TX,
124		.flags = {.pipe_bof = 1,.force_short_xfer = 1,.ext_buffer = 1,},
125		.bufsize = UDL_CMD_MAX_DATA_SIZE * UDL_CMD_MAX_FRAMES,
126		.callback = &udl_bulk_write_callback,
127		.frames = UDL_CMD_MAX_FRAMES,
128		.timeout = 5000,	/* 5 seconds */
129	},
130};
131
132/*
133 * Driver glue.
134 */
135static devclass_t udl_devclass;
136
137static device_method_t udl_methods[] = {
138	DEVMETHOD(device_probe, udl_probe),
139	DEVMETHOD(device_attach, udl_attach),
140	DEVMETHOD(device_detach, udl_detach),
141	DEVMETHOD(fb_getinfo, udl_fb_getinfo),
142	DEVMETHOD_END
143};
144
145static driver_t udl_driver = {
146	.name = "udl",
147	.methods = udl_methods,
148	.size = sizeof(struct udl_softc),
149};
150
151DRIVER_MODULE(udl, uhub, udl_driver, udl_devclass, NULL, NULL);
152MODULE_DEPEND(udl, usb, 1, 1, 1);
153MODULE_DEPEND(udl, fbd, 1, 1, 1);
154MODULE_DEPEND(udl, videomode, 1, 1, 1);
155MODULE_VERSION(udl, 1);
156
157/*
158 * Matching devices.
159 */
160static const STRUCT_USB_HOST_ID udl_devs[] = {
161	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LCD4300U, DL120)},
162	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LCD8000U, DL120)},
163	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_GUC2020, DL160)},
164	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LD220, DL165)},
165	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_VCUD60, DL160)},
166	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_DLDVI, DL160)},
167	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_VGA10, DL120)},
168	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_WSDVI, DLUNK)},
169	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_EC008, DL160)},
170	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_HPDOCK, DL160)},
171	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_NL571, DL160)},
172	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_M01061, DL195)},
173	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_NBDOCK, DL165)},
174	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_SWDVI, DLUNK)},
175	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_UM7X0, DL120)},
176	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_CONV, DL160)},
177	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_PLUGABLE, DL160)},
178	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LUM70, DL125)},
179	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_POLARIS2, DLUNK)},
180	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LT1421, DLUNK)},
181	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_ITEC, DL165)},
182	{USB_VPI(USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_DVI_19, DL165)},
183};
184
185static void
186udl_buffer_init(void *arg)
187{
188	mtx_init(&udl_buffer_mtx, "USB", "UDL", MTX_DEF);
189	TAILQ_INIT(&udl_buffer_head);
190}
191SYSINIT(udl_buffer_init, SI_SUB_LOCK, SI_ORDER_FIRST, udl_buffer_init, NULL);
192
193CTASSERT(sizeof(struct udl_buffer) < PAGE_SIZE);
194
195static void *
196udl_buffer_alloc(uint32_t size)
197{
198	struct udl_buffer *buf;
199	mtx_lock(&udl_buffer_mtx);
200	TAILQ_FOREACH(buf, &udl_buffer_head, entry) {
201		if (buf->size == size) {
202			TAILQ_REMOVE(&udl_buffer_head, buf, entry);
203			break;
204		}
205	}
206	mtx_unlock(&udl_buffer_mtx);
207	if (buf != NULL) {
208		uint8_t *ptr = ((uint8_t *)buf) - size;
209		/* wipe and recycle buffer */
210		memset(ptr, 0, size);
211		/* return buffer pointer */
212		return (ptr);
213	}
214	/* allocate new buffer */
215	return (malloc(size + sizeof(*buf), M_USB_DL, M_WAITOK | M_ZERO));
216}
217
218static void
219udl_buffer_free(void *_buf, uint32_t size)
220{
221	struct udl_buffer *buf;
222
223	/* check for NULL pointer */
224	if (_buf == NULL)
225		return;
226	/* compute pointer to recycle list */
227	buf = (struct udl_buffer *)(((uint8_t *)_buf) + size);
228
229	/*
230	 * Memory mapped buffers should never be freed.
231	 * Put display buffer into a recycle list.
232	 */
233	mtx_lock(&udl_buffer_mtx);
234	buf->size = size;
235	TAILQ_INSERT_TAIL(&udl_buffer_head, buf, entry);
236	mtx_unlock(&udl_buffer_mtx);
237}
238
239static uint32_t
240udl_get_fb_size(struct udl_softc *sc)
241{
242	unsigned i = sc->sc_cur_mode;
243
244	return ((uint32_t)udl_modes[i].hdisplay *
245	    (uint32_t)udl_modes[i].vdisplay * 2);
246}
247
248static uint32_t
249udl_get_fb_width(struct udl_softc *sc)
250{
251	unsigned i = sc->sc_cur_mode;
252
253	return (udl_modes[i].hdisplay);
254}
255
256static uint32_t
257udl_get_fb_height(struct udl_softc *sc)
258{
259	unsigned i = sc->sc_cur_mode;
260
261	return (udl_modes[i].vdisplay);
262}
263
264static uint32_t
265udl_get_fb_hz(struct udl_softc *sc)
266{
267	unsigned i = sc->sc_cur_mode;
268
269	return (udl_modes[i].hz);
270}
271
272static void
273udl_callout(void *arg)
274{
275	struct udl_softc *sc = arg;
276	const uint32_t max = udl_get_fb_size(sc);
277	int fps;
278
279	if (sc->sc_power_save == 0) {
280		fps = udl_fps;
281
282	  	/* figure out number of frames per second */
283		if (fps < UDL_FPS_MIN)
284			fps = UDL_FPS_MIN;
285		else if (fps > UDL_FPS_MAX)
286			fps = UDL_FPS_MAX;
287
288		if (sc->sc_sync_off >= max)
289			sc->sc_sync_off = 0;
290		usbd_transfer_start(sc->sc_xfer[UDL_BULK_WRITE_0]);
291		usbd_transfer_start(sc->sc_xfer[UDL_BULK_WRITE_1]);
292	} else {
293		fps = 1;
294	}
295	callout_reset(&sc->sc_callout, hz / fps, &udl_callout, sc);
296}
297
298static int
299udl_probe(device_t dev)
300{
301	struct usb_attach_arg *uaa = device_get_ivars(dev);
302
303	if (uaa->usb_mode != USB_MODE_HOST)
304		return (ENXIO);
305	if (uaa->info.bConfigIndex != 0)
306		return (ENXIO);
307	if (uaa->info.bIfaceIndex != 0)
308		return (ENXIO);
309
310	return (usbd_lookup_id_by_uaa(udl_devs, sizeof(udl_devs), uaa));
311}
312
313static int
314udl_attach(device_t dev)
315{
316	struct sysctl_ctx_list *ctx = device_get_sysctl_ctx(dev);
317	struct sysctl_oid *tree = device_get_sysctl_tree(dev);
318	struct udl_softc *sc = device_get_softc(dev);
319	struct usb_attach_arg *uaa = device_get_ivars(dev);
320	int error;
321	int i;
322
323	device_set_usb_desc(dev);
324
325	mtx_init(&sc->sc_mtx, "UDL lock", NULL, MTX_DEF);
326	cv_init(&sc->sc_cv, "UDLCV");
327	callout_init_mtx(&sc->sc_callout, &sc->sc_mtx, 0);
328	sc->sc_udev = uaa->device;
329
330	error = usbd_transfer_setup(uaa->device, &uaa->info.bIfaceIndex,
331	    sc->sc_xfer, udl_config, UDL_N_TRANSFER, sc, &sc->sc_mtx);
332
333	if (error) {
334		DPRINTF("usbd_transfer_setup error=%s\n", usbd_errstr(error));
335		goto detach;
336	}
337	usbd_xfer_set_priv(sc->sc_xfer[UDL_BULK_WRITE_0], &sc->sc_xfer_head[0]);
338	usbd_xfer_set_priv(sc->sc_xfer[UDL_BULK_WRITE_1], &sc->sc_xfer_head[1]);
339
340	TAILQ_INIT(&sc->sc_xfer_head[0]);
341	TAILQ_INIT(&sc->sc_xfer_head[1]);
342	TAILQ_INIT(&sc->sc_cmd_buf_free);
343	TAILQ_INIT(&sc->sc_cmd_buf_pending);
344
345	sc->sc_def_chip = -1;
346	sc->sc_chip = USB_GET_DRIVER_INFO(uaa);
347	sc->sc_def_mode = -1;
348	sc->sc_cur_mode = UDL_MAX_MODES;
349
350	/* Allow chip ID to be overwritten */
351	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "chipid_force",
352	    CTLFLAG_RWTUN, &sc->sc_def_chip, 0, "chip ID");
353
354	/* Export current chip ID */
355	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "chipid",
356	    CTLFLAG_RD, &sc->sc_chip, 0, "chip ID");
357
358	if (sc->sc_def_chip > -1 && sc->sc_def_chip <= DLMAX) {
359		device_printf(dev, "Forcing chip ID to 0x%04x\n", sc->sc_def_chip);
360		sc->sc_chip = sc->sc_def_chip;
361	}
362	/*
363	 * The product might have more than one chip
364	 */
365	if (sc->sc_chip == DLUNK)
366		udl_select_chip(sc, uaa);
367
368	for (i = 0; i != UDL_CMD_MAX_BUFFERS; i++) {
369		struct udl_cmd_buf *cb = &sc->sc_cmd_buf_temp[i];
370
371		TAILQ_INSERT_TAIL(&sc->sc_cmd_buf_free, cb, entry);
372	}
373
374	/*
375	 * Initialize chip.
376	 */
377	error = udl_init_chip(sc);
378	if (error != USB_ERR_NORMAL_COMPLETION)
379		goto detach;
380
381	/*
382	 * Select edid mode.
383	 */
384	udl_select_mode(sc);
385
386	/* Allow default mode to be overwritten */
387	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "mode_force",
388	    CTLFLAG_RWTUN, &sc->sc_def_mode, 0, "mode");
389
390	/* Export current mode */
391	SYSCTL_ADD_INT(ctx, SYSCTL_CHILDREN(tree), OID_AUTO, "mode",
392	    CTLFLAG_RD, &sc->sc_cur_mode, 0, "mode");
393
394	i = sc->sc_def_mode;
395	if (i > -1 && i < UDL_MAX_MODES) {
396		if (udl_modes[i].chip <= sc->sc_chip) {
397			device_printf(dev, "Forcing mode to %d\n", i);
398			sc->sc_cur_mode = i;
399		}
400	}
401	/* Printout current mode */
402	device_printf(dev, "Mode selected %dx%d @ %dHz\n",
403	    (int)udl_get_fb_width(sc),
404	    (int)udl_get_fb_height(sc),
405	    (int)udl_get_fb_hz(sc));
406
407	udl_init_resolution(sc);
408
409	/* Allocate frame buffer */
410	udl_fbmem_alloc(sc);
411
412	UDL_LOCK(sc);
413	udl_callout(sc);
414	UDL_UNLOCK(sc);
415
416	sc->sc_fb_info.fb_name = device_get_nameunit(dev);
417	sc->sc_fb_info.fb_size = sc->sc_fb_size;
418	sc->sc_fb_info.fb_bpp = 16;
419	sc->sc_fb_info.fb_depth = 16;
420	sc->sc_fb_info.fb_width = udl_get_fb_width(sc);
421	sc->sc_fb_info.fb_height = udl_get_fb_height(sc);
422	sc->sc_fb_info.fb_stride = sc->sc_fb_info.fb_width * 2;
423	sc->sc_fb_info.fb_pbase = 0;
424	sc->sc_fb_info.fb_vbase = (uintptr_t)sc->sc_fb_addr;
425	sc->sc_fb_info.fb_priv = sc;
426	sc->sc_fb_info.setblankmode = &udl_fb_setblankmode;
427
428	sc->sc_fbdev = device_add_child(dev, "fbd", -1);
429	if (sc->sc_fbdev == NULL)
430		goto detach;
431	if (device_probe_and_attach(sc->sc_fbdev) != 0)
432		goto detach;
433
434	return (0);
435
436detach:
437	udl_detach(dev);
438
439	return (ENXIO);
440}
441
442static int
443udl_detach(device_t dev)
444{
445	struct udl_softc *sc = device_get_softc(dev);
446
447	/* delete all child devices */
448	device_delete_children(dev);
449
450	UDL_LOCK(sc);
451	sc->sc_gone = 1;
452	callout_stop(&sc->sc_callout);
453	UDL_UNLOCK(sc);
454
455	usbd_transfer_unsetup(sc->sc_xfer, UDL_N_TRANSFER);
456
457	callout_drain(&sc->sc_callout);
458
459	mtx_destroy(&sc->sc_mtx);
460	cv_destroy(&sc->sc_cv);
461
462	/* put main framebuffer into a recycle list, if any */
463	udl_buffer_free(sc->sc_fb_addr, sc->sc_fb_size);
464
465	/* free shadow framebuffer memory, if any */
466	free(sc->sc_fb_copy, M_USB_DL);
467
468	return (0);
469}
470
471static struct fb_info *
472udl_fb_getinfo(device_t dev)
473{
474	struct udl_softc *sc = device_get_softc(dev);
475
476	return (&sc->sc_fb_info);
477}
478
479static int
480udl_fb_setblankmode(void *arg, int mode)
481{
482	struct udl_softc *sc = arg;
483
484	switch (mode) {
485	case V_DISPLAY_ON:
486		udl_power_save(sc, 1, M_WAITOK);
487		break;
488	case V_DISPLAY_BLANK:
489		udl_power_save(sc, 1, M_WAITOK);
490		if (sc->sc_fb_addr != 0) {
491			const uint32_t max = udl_get_fb_size(sc);
492
493			memset((void *)sc->sc_fb_addr, 0, max);
494		}
495		break;
496	case V_DISPLAY_STAND_BY:
497	case V_DISPLAY_SUSPEND:
498		udl_power_save(sc, 0, M_WAITOK);
499		break;
500	}
501	return (0);
502}
503
504static struct udl_cmd_buf *
505udl_cmd_buf_alloc_locked(struct udl_softc *sc, int flags)
506{
507	struct udl_cmd_buf *cb;
508
509	while ((cb = TAILQ_FIRST(&sc->sc_cmd_buf_free)) == NULL) {
510		if (flags != M_WAITOK)
511			break;
512		cv_wait(&sc->sc_cv, &sc->sc_mtx);
513	}
514	if (cb != NULL) {
515		TAILQ_REMOVE(&sc->sc_cmd_buf_free, cb, entry);
516		cb->off = 0;
517	}
518	return (cb);
519}
520
521static struct udl_cmd_buf *
522udl_cmd_buf_alloc(struct udl_softc *sc, int flags)
523{
524	struct udl_cmd_buf *cb;
525
526	UDL_LOCK(sc);
527	cb = udl_cmd_buf_alloc_locked(sc, flags);
528	UDL_UNLOCK(sc);
529	return (cb);
530}
531
532static void
533udl_cmd_buf_send(struct udl_softc *sc, struct udl_cmd_buf *cb)
534{
535	UDL_LOCK(sc);
536	if (sc->sc_gone) {
537		TAILQ_INSERT_TAIL(&sc->sc_cmd_buf_free, cb, entry);
538	} else {
539		/* mark end of command stack */
540		udl_cmd_insert_int_1(cb, UDL_BULK_SOC);
541		udl_cmd_insert_int_1(cb, UDL_BULK_CMD_EOC);
542
543		TAILQ_INSERT_TAIL(&sc->sc_cmd_buf_pending, cb, entry);
544		usbd_transfer_start(sc->sc_xfer[UDL_BULK_WRITE_0]);
545		usbd_transfer_start(sc->sc_xfer[UDL_BULK_WRITE_1]);
546	}
547	UDL_UNLOCK(sc);
548}
549
550static struct udl_cmd_buf *
551udl_fb_synchronize_locked(struct udl_softc *sc)
552{
553	const uint32_t max = udl_get_fb_size(sc);
554
555	/* check if framebuffer is not ready */
556	if (sc->sc_fb_addr == NULL ||
557	    sc->sc_fb_copy == NULL)
558		return (NULL);
559
560	while (sc->sc_sync_off < max) {
561		uint32_t delta = max - sc->sc_sync_off;
562
563		if (delta > UDL_CMD_MAX_PIXEL_COUNT * 2)
564			delta = UDL_CMD_MAX_PIXEL_COUNT * 2;
565		if (bcmp(sc->sc_fb_addr + sc->sc_sync_off, sc->sc_fb_copy + sc->sc_sync_off, delta) != 0) {
566			struct udl_cmd_buf *cb;
567
568			cb = udl_cmd_buf_alloc_locked(sc, M_NOWAIT);
569			if (cb == NULL)
570				goto done;
571			memcpy(sc->sc_fb_copy + sc->sc_sync_off,
572			    sc->sc_fb_addr + sc->sc_sync_off, delta);
573			udl_cmd_insert_int_1(cb, UDL_BULK_SOC);
574			udl_cmd_insert_int_1(cb, UDL_BULK_CMD_FB_WRITE | UDL_BULK_CMD_FB_WORD);
575			udl_cmd_insert_int_3(cb, sc->sc_sync_off);
576			udl_cmd_insert_int_1(cb, delta / 2);
577			udl_cmd_insert_buf_le16(cb, sc->sc_fb_copy + sc->sc_sync_off, delta);
578			sc->sc_sync_off += delta;
579			return (cb);
580		} else {
581			sc->sc_sync_off += delta;
582		}
583	}
584done:
585	return (NULL);
586}
587
588static void
589udl_bulk_write_callback(struct usb_xfer *xfer, usb_error_t error)
590{
591	struct udl_softc *sc = usbd_xfer_softc(xfer);
592	struct udl_cmd_head *phead = usbd_xfer_get_priv(xfer);
593	struct udl_cmd_buf *cb;
594	unsigned i;
595
596	switch (USB_GET_STATE(xfer)) {
597	case USB_ST_TRANSFERRED:
598		TAILQ_CONCAT(&sc->sc_cmd_buf_free, phead, entry);
599	case USB_ST_SETUP:
600tr_setup:
601		for (i = 0; i != UDL_CMD_MAX_FRAMES; i++) {
602			cb = TAILQ_FIRST(&sc->sc_cmd_buf_pending);
603			if (cb == NULL) {
604				cb = udl_fb_synchronize_locked(sc);
605				if (cb == NULL)
606					break;
607			} else {
608				TAILQ_REMOVE(&sc->sc_cmd_buf_pending, cb, entry);
609			}
610			TAILQ_INSERT_TAIL(phead, cb, entry);
611			usbd_xfer_set_frame_data(xfer, i, cb->buf, cb->off);
612		}
613		if (i != 0) {
614			usbd_xfer_set_frames(xfer, i);
615			usbd_transfer_submit(xfer);
616		}
617		break;
618	default:
619		TAILQ_CONCAT(&sc->sc_cmd_buf_free, phead, entry);
620		if (error != USB_ERR_CANCELLED) {
621			/* try clear stall first */
622			usbd_xfer_set_stall(xfer);
623			goto tr_setup;
624		}
625		break;
626	}
627	/* wakeup any waiters */
628	cv_signal(&sc->sc_cv);
629}
630
631static int
632udl_power_save(struct udl_softc *sc, int on, int flags)
633{
634	struct udl_cmd_buf *cb;
635
636	/* get new buffer */
637	cb = udl_cmd_buf_alloc(sc, flags);
638	if (cb == NULL)
639		return (EAGAIN);
640
641	DPRINTF("screen %s\n", on ? "ON" : "OFF");
642
643	sc->sc_power_save = on ? 0 : 1;
644
645	if (on)
646		udl_cmd_write_reg_1(cb, UDL_REG_SCREEN, UDL_REG_SCREEN_ON);
647	else
648		udl_cmd_write_reg_1(cb, UDL_REG_SCREEN, UDL_REG_SCREEN_OFF);
649
650	udl_cmd_write_reg_1(cb, UDL_REG_SYNC, 0xff);
651	udl_cmd_buf_send(sc, cb);
652	return (0);
653}
654
655static int
656udl_ctrl_msg(struct udl_softc *sc, uint8_t rt, uint8_t r,
657    uint16_t index, uint16_t value, uint8_t *buf, size_t len)
658{
659	usb_device_request_t req;
660	int error;
661
662	req.bmRequestType = rt;
663	req.bRequest = r;
664	USETW(req.wIndex, index);
665	USETW(req.wValue, value);
666	USETW(req.wLength, len);
667
668	error = usbd_do_request_flags(sc->sc_udev, NULL,
669	    &req, buf, 0, NULL, USB_DEFAULT_TIMEOUT);
670
671	DPRINTF("%s\n", usbd_errstr(error));
672
673	return (error);
674}
675
676static int
677udl_poll(struct udl_softc *sc, uint32_t *buf)
678{
679	uint32_t lbuf;
680	int error;
681
682	error = udl_ctrl_msg(sc, UT_READ_VENDOR_DEVICE,
683	    UDL_CTRL_CMD_POLL, 0x0000, 0x0000, (uint8_t *)&lbuf, sizeof(lbuf));
684	if (error == USB_ERR_NORMAL_COMPLETION)
685		*buf = le32toh(lbuf);
686	return (error);
687}
688
689static int
690udl_read_1(struct udl_softc *sc, uint16_t addr, uint8_t *buf)
691{
692	uint8_t lbuf[1];
693	int error;
694
695	error = udl_ctrl_msg(sc, UT_READ_VENDOR_DEVICE,
696	    UDL_CTRL_CMD_READ_1, addr, 0x0000, lbuf, 1);
697	if (error == USB_ERR_NORMAL_COMPLETION)
698		*buf = *(uint8_t *)lbuf;
699	return (error);
700}
701
702static int
703udl_write_1(struct udl_softc *sc, uint16_t addr, uint8_t buf)
704{
705	int error;
706
707	error = udl_ctrl_msg(sc, UT_WRITE_VENDOR_DEVICE,
708	    UDL_CTRL_CMD_WRITE_1, addr, 0x0000, &buf, 1);
709	return (error);
710}
711
712static int
713udl_read_edid(struct udl_softc *sc, uint8_t *buf)
714{
715	uint8_t lbuf[64];
716	uint16_t offset;
717	int error;
718
719	offset = 0;
720
721	error = udl_ctrl_msg(sc, UT_READ_VENDOR_DEVICE,
722	    UDL_CTRL_CMD_READ_EDID, 0x00a1, (offset << 8), lbuf, 64);
723	if (error != USB_ERR_NORMAL_COMPLETION)
724		goto fail;
725	bcopy(lbuf + 1, buf + offset, 63);
726	offset += 63;
727
728	error = udl_ctrl_msg(sc, UT_READ_VENDOR_DEVICE,
729	    UDL_CTRL_CMD_READ_EDID, 0x00a1, (offset << 8), lbuf, 64);
730	if (error != USB_ERR_NORMAL_COMPLETION)
731		goto fail;
732	bcopy(lbuf + 1, buf + offset, 63);
733	offset += 63;
734
735	error = udl_ctrl_msg(sc, UT_READ_VENDOR_DEVICE,
736	    UDL_CTRL_CMD_READ_EDID, 0x00a1, (offset << 8), lbuf, 3);
737	if (error != USB_ERR_NORMAL_COMPLETION)
738		goto fail;
739	bcopy(lbuf + 1, buf + offset, 2);
740fail:
741	return (error);
742}
743
744static uint8_t
745udl_lookup_mode(uint16_t hdisplay, uint16_t vdisplay, uint8_t hz,
746    uint16_t chip, uint32_t clock)
747{
748	uint8_t idx;
749
750	/*
751	 * Check first if we have a matching mode with pixelclock
752	 */
753	for (idx = 0; idx != UDL_MAX_MODES; idx++) {
754		if ((udl_modes[idx].hdisplay == hdisplay) &&
755		    (udl_modes[idx].vdisplay == vdisplay) &&
756		    (udl_modes[idx].clock == clock) &&
757		    (udl_modes[idx].chip <= chip)) {
758			return (idx);
759		}
760	}
761
762	/*
763	 * If not, check for matching mode with update frequency
764	 */
765	for (idx = 0; idx != UDL_MAX_MODES; idx++) {
766		if ((udl_modes[idx].hdisplay == hdisplay) &&
767		    (udl_modes[idx].vdisplay == vdisplay) &&
768		    (udl_modes[idx].hz == hz) &&
769		    (udl_modes[idx].chip <= chip)) {
770			return (idx);
771		}
772	}
773	return (idx);
774}
775
776static void
777udl_select_chip(struct udl_softc *sc, struct usb_attach_arg *uaa)
778{
779	const char *pserial;
780
781	pserial = usb_get_serial(uaa->device);
782
783	sc->sc_chip = DL120;
784
785	if ((uaa->info.idVendor == USB_VENDOR_DISPLAYLINK) &&
786	    (uaa->info.idProduct == USB_PRODUCT_DISPLAYLINK_WSDVI)) {
787
788		/*
789		 * WS Tech DVI is DL120 or DL160. All deviced uses the
790		 * same revision (0.04) so iSerialNumber must be used
791		 * to determin which chip it is.
792		 */
793
794		if (strlen(pserial) > 7) {
795			if (strncmp(pserial, "0198-13", 7) == 0)
796				sc->sc_chip = DL160;
797		}
798		DPRINTF("iSerialNumber (%s) used to select chip (%d)\n",
799		    pserial, sc->sc_chip);
800	}
801	if ((uaa->info.idVendor == USB_VENDOR_DISPLAYLINK) &&
802	    (uaa->info.idProduct == USB_PRODUCT_DISPLAYLINK_SWDVI)) {
803
804		/*
805		 * SUNWEIT DVI is DL160, DL125, DL165 or DL195. Major revision
806		 * can be used to differ between DL1x0 and DL1x5. Minor to
807		 * differ between DL1x5. iSerialNumber seems not to be uniqe.
808		 */
809
810		sc->sc_chip = DL160;
811
812		if (uaa->info.bcdDevice >= 0x100) {
813			sc->sc_chip = DL165;
814			if (uaa->info.bcdDevice == 0x104)
815				sc->sc_chip = DL195;
816			if (uaa->info.bcdDevice == 0x108)
817				sc->sc_chip = DL125;
818		}
819		DPRINTF("bcdDevice (%02x) used to select chip (%d)\n",
820		    uaa->info.bcdDevice, sc->sc_chip);
821	}
822}
823
824static int
825udl_set_enc_key(struct udl_softc *sc, uint8_t *buf, uint8_t len)
826{
827	int error;
828
829	error = udl_ctrl_msg(sc, UT_WRITE_VENDOR_DEVICE,
830	    UDL_CTRL_CMD_SET_KEY, 0x0000, 0x0000, buf, len);
831	return (error);
832}
833
834static void
835udl_fbmem_alloc(struct udl_softc *sc)
836{
837	uint32_t size;
838
839	size = udl_get_fb_size(sc);
840	size = round_page(size);
841	/* check for zero size */
842	if (size == 0)
843		size = PAGE_SIZE;
844	/*
845	 * It is assumed that allocations above PAGE_SIZE bytes will
846	 * be PAGE_SIZE aligned for use with mmap()
847	 */
848	sc->sc_fb_addr = udl_buffer_alloc(size);
849	sc->sc_fb_copy = malloc(size, M_USB_DL, M_WAITOK | M_ZERO);
850	sc->sc_fb_size = size;
851}
852
853static void
854udl_cmd_insert_int_1(struct udl_cmd_buf *cb, uint8_t value)
855{
856
857	cb->buf[cb->off] = value;
858	cb->off += 1;
859}
860
861#if 0
862static void
863udl_cmd_insert_int_2(struct udl_cmd_buf *cb, uint16_t value)
864{
865	uint16_t lvalue;
866
867	lvalue = htobe16(value);
868	bcopy(&lvalue, cb->buf + cb->off, 2);
869
870	cb->off += 2;
871}
872
873#endif
874
875static void
876udl_cmd_insert_int_3(struct udl_cmd_buf *cb, uint32_t value)
877{
878	uint32_t lvalue;
879
880#if BYTE_ORDER == BIG_ENDIAN
881	lvalue = htobe32(value) << 8;
882#else
883	lvalue = htobe32(value) >> 8;
884#endif
885	bcopy(&lvalue, cb->buf + cb->off, 3);
886
887	cb->off += 3;
888}
889
890#if 0
891static void
892udl_cmd_insert_int_4(struct udl_cmd_buf *cb, uint32_t value)
893{
894	uint32_t lvalue;
895
896	lvalue = htobe32(value);
897	bcopy(&lvalue, cb->buf + cb->off, 4);
898
899	cb->off += 4;
900}
901
902#endif
903
904static void
905udl_cmd_insert_buf_le16(struct udl_cmd_buf *cb, const uint8_t *buf, uint32_t len)
906{
907	uint32_t x;
908
909	for (x = 0; x != len; x += 2) {
910		/* byte swap from little endian to big endian */
911		cb->buf[cb->off + x + 0] = buf[x + 1];
912		cb->buf[cb->off + x + 1] = buf[x + 0];
913	}
914	cb->off += len;
915}
916
917static void
918udl_cmd_write_reg_1(struct udl_cmd_buf *cb, uint8_t reg, uint8_t val)
919{
920
921	udl_cmd_insert_int_1(cb, UDL_BULK_SOC);
922	udl_cmd_insert_int_1(cb, UDL_BULK_CMD_REG_WRITE_1);
923	udl_cmd_insert_int_1(cb, reg);
924	udl_cmd_insert_int_1(cb, val);
925}
926
927static void
928udl_cmd_write_reg_3(struct udl_cmd_buf *cb, uint8_t reg, uint32_t val)
929{
930
931	udl_cmd_write_reg_1(cb, reg + 0, (val >> 16) & 0xff);
932	udl_cmd_write_reg_1(cb, reg + 1, (val >> 8) & 0xff);
933	udl_cmd_write_reg_1(cb, reg + 2, (val >> 0) & 0xff);
934}
935
936static int
937udl_init_chip(struct udl_softc *sc)
938{
939	uint32_t ui32;
940	uint8_t ui8;
941	int error;
942
943	error = udl_poll(sc, &ui32);
944	if (error != USB_ERR_NORMAL_COMPLETION)
945		return (error);
946	DPRINTF("poll=0x%08x\n", ui32);
947
948	/* Some products may use later chip too */
949	switch (ui32 & 0xff) {
950	case 0xf1:			/* DL1x5 */
951		switch (sc->sc_chip) {
952		case DL120:
953			sc->sc_chip = DL125;
954			break;
955		case DL160:
956			sc->sc_chip = DL165;
957			break;
958		}
959		break;
960	}
961	DPRINTF("chip 0x%04x\n", sc->sc_chip);
962
963	error = udl_read_1(sc, 0xc484, &ui8);
964	if (error != USB_ERR_NORMAL_COMPLETION)
965		return (error);
966	DPRINTF("read 0x%02x from 0xc484\n", ui8);
967
968	error = udl_write_1(sc, 0xc41f, 0x01);
969	if (error != USB_ERR_NORMAL_COMPLETION)
970		return (error);
971	DPRINTF("write 0x01 to 0xc41f\n");
972
973	error = udl_read_edid(sc, sc->sc_edid);
974	if (error != USB_ERR_NORMAL_COMPLETION)
975		return (error);
976	DPRINTF("read EDID\n");
977
978	error = udl_set_enc_key(sc, __DECONST(void *, udl_null_key_1),
979	    sizeof(udl_null_key_1));
980	if (error != USB_ERR_NORMAL_COMPLETION)
981		return (error);
982	DPRINTF("set encryption key\n");
983
984	error = udl_write_1(sc, 0xc40b, 0x00);
985	if (error != USB_ERR_NORMAL_COMPLETION)
986		return (error);
987	DPRINTF("write 0x00 to 0xc40b\n");
988
989	return (USB_ERR_NORMAL_COMPLETION);
990}
991
992static void
993udl_init_fb_offsets(struct udl_cmd_buf *cb, uint32_t start16, uint32_t stride16,
994    uint32_t start8, uint32_t stride8)
995{
996	udl_cmd_write_reg_1(cb, UDL_REG_SYNC, 0x00);
997	udl_cmd_write_reg_3(cb, UDL_REG_ADDR_START16, start16);
998	udl_cmd_write_reg_3(cb, UDL_REG_ADDR_STRIDE16, stride16);
999	udl_cmd_write_reg_3(cb, UDL_REG_ADDR_START8, start8);
1000	udl_cmd_write_reg_3(cb, UDL_REG_ADDR_STRIDE8, stride8);
1001	udl_cmd_write_reg_1(cb, UDL_REG_SYNC, 0xff);
1002}
1003
1004static int
1005udl_init_resolution(struct udl_softc *sc)
1006{
1007	const uint32_t max = udl_get_fb_size(sc);
1008	const uint8_t *buf = udl_modes[sc->sc_cur_mode].mode;
1009	struct udl_cmd_buf *cb;
1010	uint32_t delta;
1011	uint32_t i;
1012	int error;
1013
1014	/* get new buffer */
1015	cb = udl_cmd_buf_alloc(sc, M_WAITOK);
1016	if (cb == NULL)
1017		return (EAGAIN);
1018
1019	/* write resolution values and set video memory offsets */
1020	udl_cmd_write_reg_1(cb, UDL_REG_SYNC, 0x00);
1021	for (i = 0; i < UDL_MODE_SIZE; i++)
1022		udl_cmd_write_reg_1(cb, i, buf[i]);
1023	udl_cmd_write_reg_1(cb, UDL_REG_SYNC, 0xff);
1024
1025	udl_init_fb_offsets(cb, 0x000000, 0x000a00, 0x555555, 0x000500);
1026	udl_cmd_buf_send(sc, cb);
1027
1028	/* fill screen with black color */
1029	for (i = 0; i < max; i += delta) {
1030		static const uint8_t udl_black[UDL_CMD_MAX_PIXEL_COUNT * 2] __aligned(4);
1031
1032		delta = max - i;
1033		if (delta > UDL_CMD_MAX_PIXEL_COUNT * 2)
1034			delta = UDL_CMD_MAX_PIXEL_COUNT * 2;
1035		if (i == 0)
1036			error = udl_cmd_write_buf_le16(sc, udl_black, i, delta / 2, M_WAITOK);
1037		else
1038			error = udl_cmd_buf_copy_le16(sc, 0, i, delta / 2, M_WAITOK);
1039		if (error)
1040			return (error);
1041	}
1042
1043	/* get new buffer */
1044	cb = udl_cmd_buf_alloc(sc, M_WAITOK);
1045	if (cb == NULL)
1046		return (EAGAIN);
1047
1048	/* show framebuffer content */
1049	udl_cmd_write_reg_1(cb, UDL_REG_SCREEN, UDL_REG_SCREEN_ON);
1050	udl_cmd_write_reg_1(cb, UDL_REG_SYNC, 0xff);
1051	udl_cmd_buf_send(sc, cb);
1052	return (0);
1053}
1054
1055static void
1056udl_select_mode(struct udl_softc *sc)
1057{
1058	struct udl_mode mode;
1059	int index = UDL_MAX_MODES;
1060	int i;
1061
1062	/* try to get the preferred mode from EDID */
1063	edid_parse(sc->sc_edid, &sc->sc_edid_info);
1064#ifdef USB_DEBUG
1065	edid_print(&sc->sc_edid_info);
1066#endif
1067	if (sc->sc_edid_info.edid_preferred_mode != NULL) {
1068		mode.hz =
1069		    (sc->sc_edid_info.edid_preferred_mode->dot_clock * 1000) /
1070		    (sc->sc_edid_info.edid_preferred_mode->htotal *
1071		    sc->sc_edid_info.edid_preferred_mode->vtotal);
1072		mode.clock =
1073		    sc->sc_edid_info.edid_preferred_mode->dot_clock / 10;
1074		mode.hdisplay =
1075		    sc->sc_edid_info.edid_preferred_mode->hdisplay;
1076		mode.vdisplay =
1077		    sc->sc_edid_info.edid_preferred_mode->vdisplay;
1078		index = udl_lookup_mode(mode.hdisplay, mode.vdisplay, mode.hz,
1079		    sc->sc_chip, mode.clock);
1080		sc->sc_cur_mode = index;
1081	} else {
1082		DPRINTF("no preferred mode found!\n");
1083	}
1084
1085	if (index == UDL_MAX_MODES) {
1086		DPRINTF("no mode line found\n");
1087
1088		i = 0;
1089		while (i < sc->sc_edid_info.edid_nmodes) {
1090			mode.hz =
1091			    (sc->sc_edid_info.edid_modes[i].dot_clock * 1000) /
1092			    (sc->sc_edid_info.edid_modes[i].htotal *
1093			    sc->sc_edid_info.edid_modes[i].vtotal);
1094			mode.clock =
1095			    sc->sc_edid_info.edid_modes[i].dot_clock / 10;
1096			mode.hdisplay =
1097			    sc->sc_edid_info.edid_modes[i].hdisplay;
1098			mode.vdisplay =
1099			    sc->sc_edid_info.edid_modes[i].vdisplay;
1100			index = udl_lookup_mode(mode.hdisplay, mode.vdisplay,
1101			    mode.hz, sc->sc_chip, mode.clock);
1102			if (index < UDL_MAX_MODES)
1103				if ((sc->sc_cur_mode == UDL_MAX_MODES) ||
1104				    (index > sc->sc_cur_mode))
1105					sc->sc_cur_mode = index;
1106			i++;
1107		}
1108	}
1109	/*
1110	 * If no mode found use default.
1111	 */
1112	if (sc->sc_cur_mode == UDL_MAX_MODES)
1113		sc->sc_cur_mode = udl_lookup_mode(800, 600, 60, sc->sc_chip, 0);
1114}
1115
1116static int
1117udl_cmd_write_buf_le16(struct udl_softc *sc, const uint8_t *buf, uint32_t off,
1118    uint8_t pixels, int flags)
1119{
1120	struct udl_cmd_buf *cb;
1121
1122	cb = udl_cmd_buf_alloc(sc, flags);
1123	if (cb == NULL)
1124		return (EAGAIN);
1125
1126	udl_cmd_insert_int_1(cb, UDL_BULK_SOC);
1127	udl_cmd_insert_int_1(cb, UDL_BULK_CMD_FB_WRITE | UDL_BULK_CMD_FB_WORD);
1128	udl_cmd_insert_int_3(cb, off);
1129	udl_cmd_insert_int_1(cb, pixels);
1130	udl_cmd_insert_buf_le16(cb, buf, 2 * pixels);
1131	udl_cmd_buf_send(sc, cb);
1132
1133	return (0);
1134}
1135
1136static int
1137udl_cmd_buf_copy_le16(struct udl_softc *sc, uint32_t src, uint32_t dst,
1138    uint8_t pixels, int flags)
1139{
1140	struct udl_cmd_buf *cb;
1141
1142	cb = udl_cmd_buf_alloc(sc, flags);
1143	if (cb == NULL)
1144		return (EAGAIN);
1145
1146	udl_cmd_insert_int_1(cb, UDL_BULK_SOC);
1147	udl_cmd_insert_int_1(cb, UDL_BULK_CMD_FB_COPY | UDL_BULK_CMD_FB_WORD);
1148	udl_cmd_insert_int_3(cb, dst);
1149	udl_cmd_insert_int_1(cb, pixels);
1150	udl_cmd_insert_int_3(cb, src);
1151	udl_cmd_buf_send(sc, cb);
1152
1153	return (0);
1154}
1155