#include <sys/param.h>
#include <sys/device.h>
#include <sys/malloc.h>
#include <sys/systm.h>
#include <uvm/uvm_extern.h>
#include <dev/usb/usb.h>
#include <dev/usb/usbdi.h>
#include <dev/usb/usbdi_util.h>
#include <dev/usb/usbdevs.h>
#include <dev/wscons/wsconsio.h>
#include <dev/wscons/wsdisplayvar.h>
#include <dev/rasops/rasops.h>
#include <dev/videomode/videomode.h>
#include <dev/videomode/edidvar.h>
#include <dev/usb/udl.h>
#include <dev/usb/udlio.h>
#if 0
#define UDL_DEBUG
#endif
#ifdef UDL_DEBUG
int udl_debug = 1;
#define DPRINTF(l, x...) do { if ((l) <= udl_debug) printf(x); } while (0)
#else
#define DPRINTF(l, x...)
#endif
#define DN(sc) ((sc)->sc_dev.dv_xname)
#define FUNC __func__
int udl_match(struct device *, void *, void *);
void udl_attach(struct device *, struct device *, void *);
void udl_attach_hook(struct device *);
int udl_detach(struct device *, int);
int udl_activate(struct device *, int);
int udl_ioctl(void *, u_long, caddr_t, int, struct proc *);
paddr_t udl_mmap(void *, off_t, int);
int udl_alloc_screen(void *, const struct wsscreen_descr *,
void **, int *, int *, uint32_t *);
void udl_free_screen(void *, void *);
int udl_show_screen(void *, void *, int,
void (*)(void *, int, int), void *);
int udl_load_font(void *, void *, struct wsdisplay_font *);
int udl_list_font(void *, struct wsdisplay_font *);
void udl_burner(void *, u_int, u_int);
int udl_copycols(void *, int, int, int, int);
int udl_copyrows(void *, int, int, int);
int udl_erasecols(void *, int, int, int, uint32_t);
int udl_eraserows(void *, int, int, uint32_t);
int udl_putchar(void *, int, int, u_int, uint32_t);
int udl_do_cursor(struct rasops_info *);
int udl_draw_char(struct udl_softc *, uint16_t, uint16_t, u_int,
uint32_t, uint32_t);
int udl_damage(struct udl_softc *, uint8_t *,
uint32_t, uint32_t, uint32_t, uint32_t);
int udl_draw_image(struct udl_softc *, uint8_t *,
uint32_t, uint32_t, uint32_t, uint32_t);
usbd_status udl_ctrl_msg(struct udl_softc *, uint8_t, uint8_t,
uint16_t, uint16_t, uint8_t *, size_t);
usbd_status udl_poll(struct udl_softc *, uint32_t *);
usbd_status udl_read_1(struct udl_softc *, uint16_t, uint8_t *);
usbd_status udl_write_1(struct udl_softc *, uint16_t, uint8_t);
usbd_status udl_read_edid(struct udl_softc *, uint8_t *);
uint8_t udl_lookup_mode(uint16_t, uint16_t, uint8_t, uint16_t,
uint32_t);
int udl_select_chip(struct udl_softc *);
usbd_status udl_set_enc_key(struct udl_softc *, uint8_t *, uint8_t);
usbd_status udl_set_decomp_table(struct udl_softc *, uint8_t *, uint16_t);
int udl_load_huffman(struct udl_softc *);
void udl_free_huffman(struct udl_softc *);
int udl_fbmem_alloc(struct udl_softc *);
void udl_fbmem_free(struct udl_softc *);
usbd_status udl_cmd_alloc_xfer(struct udl_softc *);
void udl_cmd_free_xfer(struct udl_softc *);
int udl_cmd_alloc_buf(struct udl_softc *);
void udl_cmd_free_buf(struct udl_softc *);
void udl_cmd_insert_int_1(struct udl_softc *, uint8_t);
void udl_cmd_insert_int_2(struct udl_softc *, uint16_t);
void udl_cmd_insert_int_3(struct udl_softc *, uint32_t);
void udl_cmd_insert_int_4(struct udl_softc *, uint32_t);
void udl_cmd_insert_buf(struct udl_softc *, uint8_t *, uint32_t);
int udl_cmd_insert_buf_comp(struct udl_softc *, uint8_t *,
uint32_t);
int udl_cmd_insert_head_comp(struct udl_softc *, uint32_t);
int udl_cmd_insert_check(struct udl_softc *, int);
void udl_cmd_set_xfer_type(struct udl_softc *, int);
void udl_cmd_save_offset(struct udl_softc *);
void udl_cmd_restore_offset(struct udl_softc *);
void udl_cmd_write_reg_1(struct udl_softc *, uint8_t, uint8_t);
void udl_cmd_write_reg_3(struct udl_softc *, uint8_t, uint32_t);
usbd_status udl_cmd_send(struct udl_softc *);
usbd_status udl_cmd_send_async(struct udl_softc *);
void udl_cmd_send_async_cb(struct usbd_xfer *, void *, usbd_status);
usbd_status udl_init_chip(struct udl_softc *);
void udl_init_fb_offsets(struct udl_softc *, uint32_t, uint32_t,
uint32_t, uint32_t);
usbd_status udl_init_resolution(struct udl_softc *);
usbd_status udl_clear_screen(struct udl_softc *);
void udl_select_mode(struct udl_softc *);
int udl_fb_buf_write(struct udl_softc *, uint8_t *, uint32_t,
uint32_t, uint16_t);
int udl_fb_block_write(struct udl_softc *, uint16_t, uint32_t,
uint32_t, uint32_t, uint32_t);
int udl_fb_line_write(struct udl_softc *, uint16_t, uint32_t,
uint32_t, uint32_t);
int udl_fb_off_write(struct udl_softc *, uint16_t, uint32_t,
uint16_t);
int udl_fb_block_copy(struct udl_softc *, uint32_t, uint32_t,
uint32_t, uint32_t, uint32_t, uint32_t);
int udl_fb_line_copy(struct udl_softc *, uint32_t, uint32_t,
uint32_t, uint32_t, uint32_t);
int udl_fb_off_copy(struct udl_softc *, uint32_t, uint32_t,
uint16_t);
int udl_fb_buf_write_comp(struct udl_softc *, uint8_t *, uint32_t,
uint32_t, uint16_t);
int udl_fb_block_write_comp(struct udl_softc *, uint16_t, uint32_t,
uint32_t, uint32_t, uint32_t);
int udl_fb_line_write_comp(struct udl_softc *, uint16_t, uint32_t,
uint32_t, uint32_t);
int udl_fb_off_write_comp(struct udl_softc *, uint16_t, uint32_t,
uint16_t);
int udl_fb_block_copy_comp(struct udl_softc *, uint32_t, uint32_t,
uint32_t, uint32_t, uint32_t, uint32_t);
int udl_fb_line_copy_comp(struct udl_softc *, uint32_t, uint32_t,
uint32_t, uint32_t, uint32_t);
int udl_fb_off_copy_comp(struct udl_softc *, uint32_t, uint32_t,
uint16_t);
#ifdef UDL_DEBUG
void udl_hexdump(void *, int, int);
usbd_status udl_init_test(struct udl_softc *);
#endif
struct cfdriver udl_cd = {
NULL, "udl", DV_DULL
};
const struct cfattach udl_ca = {
sizeof(struct udl_softc),
udl_match,
udl_attach,
udl_detach,
udl_activate
};
struct wsscreen_descr udl_stdscreen = {
"std",
0, 0,
NULL,
0, 0,
WSSCREEN_WSCOLORS
};
const struct wsscreen_descr *udl_scrlist[] = {
&udl_stdscreen
};
struct wsscreen_list udl_screenlist = {
sizeof(udl_scrlist) / sizeof(struct wsscreen_descr *), udl_scrlist
};
struct wsdisplay_accessops udl_accessops = {
.ioctl = udl_ioctl,
.mmap = udl_mmap,
.alloc_screen = udl_alloc_screen,
.free_screen = udl_free_screen,
.show_screen = udl_show_screen,
.load_font = udl_load_font,
.list_font = udl_list_font,
.burn_screen = udl_burner
};
struct udl_type {
struct usb_devno udl_dev;
uint16_t udl_chip;
};
static const struct udl_type udl_devs[] = {
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_GUC2020 }, DL160 },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LD220 }, DL165 },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LD190 }, DLUNK },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_U70 }, DLUNK },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_TOSHIBA }, DLUNK },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_POLARIS2 }, DLUNK },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_VCUD60 }, DL160 },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_CONV }, DL160 },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_DLDVI }, DL160 },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_USBRGB }, DLUNK },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LCDUSB7X }, DLUNK },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LCDUSB10X },
DLUNK },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_VGA10 }, DL120 },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_WSDVI }, DLUNK },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_EC008 }, DL160 },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_FYDVI2 }, DLUNK },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_GXDVIU2 }, DLUNK },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LCD4300U }, DL120 },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LCD8000U }, DL120 },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_HPDOCK }, DL160 },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_NL571 }, DL160 },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_M01061 }, DL195 },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_NBDOCK }, DL165 },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_GXDVIU2B }, DLUNK },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_SWDVI }, DLUNK },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LUM70 }, DL125 },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LCD8000UD_DVI },
DLUNK },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LDEWX015U },
DLUNK },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_KC002N }, DLUNK },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_MIMO }, DLUNK },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_PLUGABLE }, DLUNK },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_LT1421 }, DLUNK },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_SD_U2VDH }, DLUNK },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_UM7X0 }, DL120 },
{ { USB_VENDOR_DISPLAYLINK, USB_PRODUCT_DISPLAYLINK_FYDVI }, DLUNK }
};
#define udl_lookup(v, p) ((struct udl_type *)usb_lookup(udl_devs, v, p))
int
udl_match(struct device *parent, void *match, void *aux)
{
struct usb_attach_arg *uaa = aux;
if (uaa->iface == NULL || uaa->configno != 1)
return (UMATCH_NONE);
if (udl_lookup(uaa->vendor, uaa->product) != NULL)
return (UMATCH_VENDOR_PRODUCT);
return (UMATCH_NONE);
}
void
udl_attach(struct device *parent, struct device *self, void *aux)
{
struct udl_softc *sc = (struct udl_softc *)self;
struct usb_attach_arg *uaa = aux;
struct wsemuldisplaydev_attach_args aa;
usbd_status error;
int err, i;
sc->sc_udev = uaa->device;
sc->sc_chip = udl_lookup(uaa->vendor, uaa->product)->udl_chip;
sc->sc_width = 0;
sc->sc_height = 0;
sc->sc_depth = 16;
sc->sc_cur_mode = MAX_DL_MODES;
if ((sc->sc_dev.dv_cfdata->cf_flags & 0xff00) > 0) {
i = ((sc->sc_dev.dv_cfdata->cf_flags & 0xff00) >> 8) - 1;
if (i <= DLMAX) {
sc->sc_chip = i;
printf("%s: %s: cf_flags (0x%04x) forced chip to %d\n",
DN(sc), FUNC,
sc->sc_dev.dv_cfdata->cf_flags, i);
}
}
if (sc->sc_chip == DLUNK)
if (udl_select_chip(sc))
return;
error = usbd_device2interface_handle(sc->sc_udev, 0, &sc->sc_iface);
if (error != USBD_NORMAL_COMPLETION)
return;
error = udl_cmd_alloc_xfer(sc);
if (error != USBD_NORMAL_COMPLETION)
return;
err = udl_cmd_alloc_buf(sc);
if (err != 0)
return;
error = usbd_open_pipe(sc->sc_iface, 0x01, USBD_EXCLUSIVE_USE,
&sc->sc_tx_pipeh);
if (error != USBD_NORMAL_COMPLETION)
return;
udl_cmd_set_xfer_type(sc, UDL_CMD_XFER_SYNC);
error = udl_init_chip(sc);
if (error != USBD_NORMAL_COMPLETION)
return;
udl_select_mode(sc);
if ((sc->sc_dev.dv_cfdata->cf_flags & 0xff) > 0) {
i = (sc->sc_dev.dv_cfdata->cf_flags & 0xff) - 1;
if (i < MAX_DL_MODES) {
if (udl_modes[i].chip <= sc->sc_chip) {
sc->sc_width = udl_modes[i].hdisplay;
sc->sc_height = udl_modes[i].vdisplay;
printf("%s: %s: cf_flags (0x%04x) ",
DN(sc), FUNC,
sc->sc_dev.dv_cfdata->cf_flags);
printf("forced mode to %d\n", i);
sc->sc_cur_mode = i;
}
}
}
error = udl_init_resolution(sc);
if (error != USBD_NORMAL_COMPLETION)
return;
aa.console = 0;
aa.scrdata = &udl_screenlist;
aa.accessops = &udl_accessops;
aa.accesscookie = sc;
aa.defaultscreens = 0;
sc->sc_wsdisplay = config_found(self, &aa, wsemuldisplaydevprint);
config_mountroot(self, udl_attach_hook);
}
void
udl_attach_hook(struct device *self)
{
struct udl_softc *sc = (struct udl_softc *)self;
if (udl_load_huffman(sc) != 0) {
printf("%s: run in uncompressed mode\n", DN(sc));
sc->udl_fb_buf_write = udl_fb_buf_write;
sc->udl_fb_block_write = udl_fb_block_write;
sc->udl_fb_line_write = udl_fb_line_write;
sc->udl_fb_off_write = udl_fb_off_write;
sc->udl_fb_block_copy = udl_fb_block_copy;
sc->udl_fb_line_copy = udl_fb_line_copy;
sc->udl_fb_off_copy = udl_fb_off_copy;
} else {
sc->udl_fb_buf_write = udl_fb_buf_write_comp;
sc->udl_fb_block_write = udl_fb_block_write_comp;
sc->udl_fb_line_write = udl_fb_line_write_comp;
sc->udl_fb_off_write = udl_fb_off_write_comp;
sc->udl_fb_block_copy = udl_fb_block_copy_comp;
sc->udl_fb_line_copy = udl_fb_line_copy_comp;
sc->udl_fb_off_copy = udl_fb_off_copy_comp;
}
#ifdef UDL_DEBUG
if (udl_debug >= 4)
udl_init_test(sc);
#endif
udl_cmd_set_xfer_type(sc, UDL_CMD_XFER_ASYNC);
sc->sc_mode = WSDISPLAYIO_MODE_EMUL;
}
int
udl_detach(struct device *self, int flags)
{
struct udl_softc *sc = (struct udl_softc *)self;
if (sc->sc_tx_pipeh != NULL)
usbd_close_pipe(sc->sc_tx_pipeh);
udl_cmd_free_buf(sc);
udl_cmd_free_xfer(sc);
udl_free_huffman(sc);
udl_fbmem_free(sc);
if (sc->sc_wsdisplay != NULL)
config_detach(sc->sc_wsdisplay, DETACH_FORCE);
return (0);
}
int
udl_activate(struct device *self, int act)
{
struct udl_softc *sc = (struct udl_softc *)self;
int rv;
switch (act) {
case DVACT_DEACTIVATE:
usbd_deactivate(sc->sc_udev);
break;
}
rv = config_activate_children(self, act);
return (rv);
}
int
udl_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
{
struct udl_softc *sc;
struct wsdisplay_fbinfo *wdf;
struct udl_ioctl_damage *d;
int r, error, mode;
sc = v;
DPRINTF(1, "%s: %s: ('%c', %zu, %zu)\n",
DN(sc), FUNC, (int) IOCGROUP(cmd), cmd & 0xff, IOCPARM_LEN(cmd));
switch (cmd) {
case WSDISPLAYIO_GTYPE:
*(u_int *)data = WSDISPLAY_TYPE_DL;
break;
case WSDISPLAYIO_GINFO:
wdf = (struct wsdisplay_fbinfo *)data;
wdf->height = sc->sc_height;
wdf->width = sc->sc_width;
wdf->depth = sc->sc_depth;
wdf->stride = sc->sc_width * (sc->sc_depth / 8);
wdf->offset = 0;
wdf->cmsize = 0;
break;
case WSDISPLAYIO_SMODE:
mode = *(u_int *)data;
if (mode == sc->sc_mode)
break;
switch (mode) {
case WSDISPLAYIO_MODE_EMUL:
(void)udl_clear_screen(sc);
break;
case WSDISPLAYIO_MODE_DUMBFB:
break;
default:
return (EINVAL);
}
sc->sc_mode = mode;
break;
case WSDISPLAYIO_LINEBYTES:
*(u_int *)data = sc->sc_width * (sc->sc_depth / 8);
break;
case WSDISPLAYIO_SVIDEO:
case WSDISPLAYIO_GVIDEO:
break;
case UDLIO_DAMAGE:
d = (struct udl_ioctl_damage *)data;
d->status = UDLIO_STATUS_OK;
r = udl_damage(sc, sc->sc_fbmem, d->x1, d->x2, d->y1, d->y2);
if (r != 0) {
error = tsleep_nsec(sc, 0, "udlio", MSEC_TO_NSEC(10));
if (error) {
d->status = UDLIO_STATUS_FAILED;
} else {
r = udl_damage(sc, sc->sc_fbmem, d->x1, d->x2,
d->y1, d->y2);
if (r != 0)
d->status = UDLIO_STATUS_FAILED;
}
}
break;
default:
return (-1);
}
return (0);
}
paddr_t
udl_mmap(void *v, off_t off, int prot)
{
struct udl_softc *sc;
caddr_t p;
paddr_t pa;
sc = v;
DPRINTF(1, "%s: %s\n", DN(sc), FUNC);
if (udl_fbmem_alloc(sc) == -1)
return (-1);
p = sc->sc_fbmem + off;
if (pmap_extract(pmap_kernel(), (vaddr_t)p, &pa) == FALSE) {
printf("udl_mmap: invalid page\n");
udl_fbmem_free(sc);
return (-1);
}
return (pa);
}
int
udl_alloc_screen(void *v, const struct wsscreen_descr *type,
void **cookiep, int *curxp, int *curyp, uint32_t *attrp)
{
struct udl_softc *sc = v;
struct wsdisplay_font *font;
DPRINTF(1, "%s: %s\n", DN(sc), FUNC);
if (sc->sc_nscreens > 0)
return (ENOMEM);
sc->sc_ri.ri_depth = sc->sc_depth;
sc->sc_ri.ri_bits = NULL;
sc->sc_ri.ri_width = sc->sc_width;
sc->sc_ri.ri_height = sc->sc_height;
sc->sc_ri.ri_stride = sc->sc_width * sc->sc_height / 8;
sc->sc_ri.ri_hw = (void *)sc;
sc->sc_ri.ri_flg = 0;
if (sc->sc_depth == 16) {
sc->sc_ri.ri_rnum = 5;
sc->sc_ri.ri_rpos = 11;
sc->sc_ri.ri_gnum = 6;
sc->sc_ri.ri_gpos = 5;
sc->sc_ri.ri_bnum = 5;
sc->sc_ri.ri_bpos = 0;
}
rasops_init(&sc->sc_ri, 100, 200);
sc->sc_ri.ri_ops.copycols = udl_copycols;
sc->sc_ri.ri_ops.copyrows = udl_copyrows;
sc->sc_ri.ri_ops.erasecols = udl_erasecols;
sc->sc_ri.ri_ops.eraserows = udl_eraserows;
sc->sc_ri.ri_ops.putchar = udl_putchar;
sc->sc_ri.ri_do_cursor = udl_do_cursor;
sc->sc_ri.ri_ops.pack_attr(&sc->sc_ri, 0, 0, 0, attrp);
udl_stdscreen.nrows = sc->sc_ri.ri_rows;
udl_stdscreen.ncols = sc->sc_ri.ri_cols;
udl_stdscreen.textops = &sc->sc_ri.ri_ops;
udl_stdscreen.fontwidth = sc->sc_ri.ri_font->fontwidth;
udl_stdscreen.fontheight = sc->sc_ri.ri_font->fontheight;
udl_stdscreen.capabilities = sc->sc_ri.ri_caps;
*cookiep = &sc->sc_ri;
*curxp = 0;
*curyp = 0;
sc->sc_cbs = mallocarray(sc->sc_ri.ri_rows, sc->sc_ri.ri_cols *
sizeof(*sc->sc_cbs), M_USBDEV, M_NOWAIT|M_ZERO);
if (sc->sc_cbs == NULL) {
printf("%s: can't allocate mem for character backing store!\n",
DN(sc));
return (ENOMEM);
}
sc->sc_cbslen = sc->sc_ri.ri_rows * sc->sc_ri.ri_cols *
sizeof(*sc->sc_cbs);
sc->sc_nscreens++;
font = sc->sc_ri.ri_font;
DPRINTF(1, "%s: %s: using font %s (%dx%d)\n",
DN(sc), FUNC, font->name, sc->sc_ri.ri_cols, sc->sc_ri.ri_rows);
return (0);
}
void
udl_free_screen(void *v, void *cookie)
{
struct udl_softc *sc;
sc = v;
DPRINTF(1, "%s: %s\n", DN(sc), FUNC);
if (sc->sc_cbs != NULL)
free(sc->sc_cbs, M_USBDEV, sc->sc_cbslen);
sc->sc_nscreens--;
}
int
udl_show_screen(void *v, void *cookie, int waitok,
void (*cb)(void *, int, int), void *cbarg)
{
struct udl_softc *sc;
sc = v;
DPRINTF(1, "%s: %s\n", DN(sc), FUNC);
return (0);
}
int
udl_load_font(void *v, void *emulcookie, struct wsdisplay_font *font)
{
struct udl_softc *sc = v;
struct rasops_info *ri = &sc->sc_ri;
return rasops_load_font(ri, emulcookie, font);
}
int
udl_list_font(void *v, struct wsdisplay_font *font)
{
struct udl_softc *sc = v;
struct rasops_info *ri = &sc->sc_ri;
return rasops_list_font(ri, font);
}
void
udl_burner(void *v, u_int on, u_int flags)
{
struct udl_softc *sc;
sc = v;
DPRINTF(1, "%s: %s: screen %s\n", DN(sc), FUNC, on ? "ON" : "OFF");
if (on)
udl_cmd_write_reg_1(sc, UDL_REG_SCREEN, UDL_REG_SCREEN_ON);
else
udl_cmd_write_reg_1(sc, UDL_REG_SCREEN, UDL_REG_SCREEN_OFF);
udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0xff);
(void)udl_cmd_send_async(sc);
}
int
udl_copycols(void *cookie, int row, int src, int dst, int num)
{
struct rasops_info *ri = cookie;
struct udl_softc *sc;
int sx, sy, dx, dy, cx, cy, r;
usbd_status error;
sc = ri->ri_hw;
DPRINTF(2, "%s: %s: row=%d, src=%d, dst=%d, num=%d\n",
DN(sc), FUNC, row, src, dst, num);
udl_cmd_save_offset(sc);
sx = src * ri->ri_font->fontwidth;
sy = row * ri->ri_font->fontheight;
dx = dst * ri->ri_font->fontwidth;
dy = row * ri->ri_font->fontheight;
cx = num * ri->ri_font->fontwidth;
cy = ri->ri_font->fontheight;
r = (sc->udl_fb_block_copy)
(sc, sx, sy, 0, sc->sc_ri.ri_emuheight, cx, cy);
if (r != 0)
goto fail;
r = (sc->udl_fb_block_copy)
(sc, 0, sc->sc_ri.ri_emuheight, dx, dy, cx, cy);
if (r != 0)
goto fail;
error = udl_cmd_send_async(sc);
if (error != USBD_NORMAL_COMPLETION) {
fail:
udl_cmd_restore_offset(sc);
return (EAGAIN);
}
bcopy(sc->sc_cbs + ((row * sc->sc_ri.ri_cols) + src),
sc->sc_cbs + ((row * sc->sc_ri.ri_cols) + dst),
num * sizeof(*sc->sc_cbs));
return (0);
}
int
udl_copyrows(void *cookie, int src, int dst, int num)
{
struct rasops_info *ri = cookie;
struct udl_softc *sc;
int sy, dy, cx, cy, r;
usbd_status error;
sc = ri->ri_hw;
DPRINTF(2, "%s: %s: src=%d, dst=%d, num=%d\n",
DN(sc), FUNC, src, dst, num);
udl_cmd_save_offset(sc);
sy = src * sc->sc_ri.ri_font->fontheight;
dy = dst * sc->sc_ri.ri_font->fontheight;
cx = sc->sc_ri.ri_emuwidth;
cy = num * sc->sc_ri.ri_font->fontheight;
r = (sc->udl_fb_block_copy)
(sc, 0, sy, 0, sc->sc_ri.ri_emuheight, cx, cy);
if (r != 0)
goto fail;
r = (sc->udl_fb_block_copy)
(sc, 0, sc->sc_ri.ri_emuheight, 0, dy, cx, cy);
if (r != 0)
goto fail;
error = udl_cmd_send_async(sc);
if (error != USBD_NORMAL_COMPLETION) {
fail:
udl_cmd_restore_offset(sc);
return (EAGAIN);
}
bcopy(sc->sc_cbs + (src * sc->sc_ri.ri_cols),
sc->sc_cbs + (dst * sc->sc_ri.ri_cols),
(num * sc->sc_ri.ri_cols) * sizeof(*sc->sc_cbs));
return (0);
}
int
udl_erasecols(void *cookie, int row, int col, int num, uint32_t attr)
{
struct rasops_info *ri = cookie;
struct udl_softc *sc = ri->ri_hw;
uint16_t bgc;
int fg, bg;
int x, y, cx, cy, r;
usbd_status error;
sc = ri->ri_hw;
DPRINTF(2, "%s: %s: row=%d, col=%d, num=%d\n",
DN(sc), FUNC, row, col, num);
udl_cmd_save_offset(sc);
sc->sc_ri.ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
bgc = (uint16_t)sc->sc_ri.ri_devcmap[bg];
x = col * sc->sc_ri.ri_font->fontwidth;
y = row * sc->sc_ri.ri_font->fontheight;
cx = num * sc->sc_ri.ri_font->fontwidth;
cy = sc->sc_ri.ri_font->fontheight;
r = (sc->udl_fb_block_write)(sc, bgc, x, y, cx, cy);
if (r != 0)
goto fail;
error = udl_cmd_send_async(sc);
if (error != USBD_NORMAL_COMPLETION) {
fail:
udl_cmd_restore_offset(sc);
return (EAGAIN);
}
bzero(sc->sc_cbs + ((row * sc->sc_ri.ri_cols) + col),
num * sizeof(*sc->sc_cbs));
return (0);
}
int
udl_eraserows(void *cookie, int row, int num, uint32_t attr)
{
struct rasops_info *ri = cookie;
struct udl_softc *sc;
uint16_t bgc;
int fg, bg;
int x, y, cx, cy, r;
usbd_status error;
sc = ri->ri_hw;
DPRINTF(2, "%s: %s: row=%d, num=%d\n", DN(sc), FUNC, row, num);
udl_cmd_save_offset(sc);
sc->sc_ri.ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
bgc = (uint16_t)sc->sc_ri.ri_devcmap[bg];
x = 0;
y = row * sc->sc_ri.ri_font->fontheight;
cx = sc->sc_ri.ri_emuwidth;
cy = num * sc->sc_ri.ri_font->fontheight;
r = (sc->udl_fb_block_write)(sc, bgc, x, y, cx, cy);
if (r != 0)
goto fail;
error = udl_cmd_send_async(sc);
if (error != USBD_NORMAL_COMPLETION) {
fail:
udl_cmd_restore_offset(sc);
return (EAGAIN);
}
bzero(sc->sc_cbs + (row * sc->sc_ri.ri_cols),
(num * sc->sc_ri.ri_cols) * sizeof(*sc->sc_cbs));
return (0);
}
int
udl_putchar(void *cookie, int row, int col, u_int uc, uint32_t attr)
{
struct rasops_info *ri = cookie;
struct udl_softc *sc = ri->ri_hw;
int r;
uint16_t fgc, bgc;
uint32_t x, y, fg, bg;
DPRINTF(4, "%s: %s\n", DN(sc), FUNC);
udl_cmd_save_offset(sc);
sc->sc_ri.ri_ops.unpack_attr(cookie, attr, &fg, &bg, NULL);
fgc = (uint16_t)sc->sc_ri.ri_devcmap[fg];
bgc = (uint16_t)sc->sc_ri.ri_devcmap[bg];
x = col * ri->ri_font->fontwidth;
y = row * ri->ri_font->fontheight;
if (uc == ' ') {
r = (sc->udl_fb_block_write)(sc, bgc, x, y,
ri->ri_font->fontwidth, ri->ri_font->fontheight);
if (r != 0)
goto fail;
} else {
r = udl_draw_char(sc, fgc, bgc, uc, x, y);
if (r != 0)
goto fail;
}
sc->sc_cbs[(row * sc->sc_ri.ri_cols) + col] = uc;
return (0);
fail:
udl_cmd_restore_offset(sc);
return (EAGAIN);
}
int
udl_do_cursor(struct rasops_info *ri)
{
struct udl_softc *sc = ri->ri_hw;
int r, pos;
uint32_t x, y;
uint8_t save_cursor;
usbd_status error;
DPRINTF(2, "%s: %s: ccol=%d, crow=%d\n",
DN(sc), FUNC, ri->ri_ccol, ri->ri_crow);
udl_cmd_save_offset(sc);
save_cursor = sc->sc_cursor_on;
x = ri->ri_ccol * ri->ri_font->fontwidth;
y = ri->ri_crow * ri->ri_font->fontheight;
if (sc->sc_cursor_on == 0) {
r = (sc->udl_fb_block_copy)(sc, x, y, 0, sc->sc_ri.ri_emuheight,
ri->ri_font->fontwidth, ri->ri_font->fontheight);
if (r != 0)
goto fail;
pos = (ri->ri_crow * sc->sc_ri.ri_cols) + ri->ri_ccol;
if (sc->sc_cbs[pos] == 0 || sc->sc_cbs[pos] == ' ') {
r = (sc->udl_fb_block_write)(sc, 0xffff, x, y,
ri->ri_font->fontwidth, ri->ri_font->fontheight);
} else {
r = udl_draw_char(sc, 0x0000, 0xffff, sc->sc_cbs[pos],
x, y);
}
if (r != 0)
goto fail;
sc->sc_cursor_on = 1;
} else {
r = (sc->udl_fb_block_copy)(sc, 0, sc->sc_ri.ri_emuheight, x, y,
ri->ri_font->fontwidth, ri->ri_font->fontheight);
if (r != 0)
goto fail;
sc->sc_cursor_on = 0;
}
error = udl_cmd_send_async(sc);
if (error != USBD_NORMAL_COMPLETION) {
fail:
udl_cmd_restore_offset(sc);
sc->sc_cursor_on = save_cursor;
return (EAGAIN);
}
return (0);
}
int
udl_draw_char(struct udl_softc *sc, uint16_t fg, uint16_t bg, u_int uc,
uint32_t x, uint32_t y)
{
int i, j, ly, r;
uint8_t *fontchar;
uint8_t buf[UDL_CMD_MAX_DATA_SIZE];
uint16_t *line, lrgb16, fontbits, luc;
struct wsdisplay_font *font = sc->sc_ri.ri_font;
fontchar = (uint8_t *)(font->data + (uc - font->firstchar) *
sc->sc_ri.ri_fontscale);
ly = y;
for (i = 0; i < font->fontheight; i++) {
if (font->fontwidth > 8) {
fontbits = betoh16(*(uint16_t *)fontchar);
} else {
fontbits = *fontchar;
fontbits = fontbits << 8;
}
line = (uint16_t *)buf;
for (j = 15; j > (15 - font->fontwidth); j--) {
luc = 1 << j;
if (fontbits & luc)
lrgb16 = htobe16(fg);
else
lrgb16 = htobe16(bg);
bcopy(&lrgb16, line, 2);
line++;
}
r = (sc->udl_fb_buf_write)(sc, buf, x, ly, font->fontwidth);
if (r != 0)
return (r);
ly++;
fontchar += font->stride;
}
return (0);
}
int
udl_damage(struct udl_softc *sc, uint8_t *image,
uint32_t x1, uint32_t x2, uint32_t y1, uint32_t y2)
{
int r;
int x, y, width, height;
usbd_status error;
udl_cmd_save_offset(sc);
x = x1;
y = y1;
width = x2 - x1;
height = y2 - y1;
r = udl_draw_image(sc, image, x, y, width, height);
if (r != 0)
goto fail;
error = udl_cmd_send_async(sc);
if (error != USBD_NORMAL_COMPLETION) {
fail:
udl_cmd_restore_offset(sc);
return (EAGAIN);
}
return (0);
}
int
udl_draw_image(struct udl_softc *sc, uint8_t *image,
uint32_t x, uint32_t y, uint32_t width, uint32_t height)
{
int i, j, r;
int width_cur, x_cur;
uint8_t buf[UDL_CMD_MAX_DATA_SIZE];
uint16_t *image16, lrgb16;
uint32_t off, block;
for (i = 0; i < height; i++) {
off = ((y * sc->sc_width) + x) * 2;
x_cur = x;
width_cur = width;
while (width_cur) {
if (width_cur > UDL_CMD_MAX_PIXEL_COUNT)
block = UDL_CMD_MAX_PIXEL_COUNT;
else
block = width_cur;
image16 = (uint16_t *)(image + off);
for (j = 0; j < (block * 2); j += 2) {
lrgb16 = htobe16(*image16);
bcopy(&lrgb16, buf + j, 2);
image16++;
}
r = (sc->udl_fb_buf_write)(sc, buf, x_cur, y, block);
if (r != 0)
return (r);
off += block * 2;
x_cur += block;
width_cur -= block;
}
y++;
}
return (0);
}
usbd_status
udl_ctrl_msg(struct udl_softc *sc, uint8_t rt, uint8_t r,
uint16_t index, uint16_t value, uint8_t *buf, size_t len)
{
usb_device_request_t req;
usbd_status error;
req.bmRequestType = rt;
req.bRequest = r;
USETW(req.wIndex, index);
USETW(req.wValue, value);
USETW(req.wLength, len);
error = usbd_do_request(sc->sc_udev, &req, buf);
if (error != USBD_NORMAL_COMPLETION) {
printf("%s: %s: %s!\n", DN(sc), FUNC, usbd_errstr(error));
return (error);
}
return (USBD_NORMAL_COMPLETION);
}
usbd_status
udl_poll(struct udl_softc *sc, uint32_t *buf)
{
uint8_t lbuf[4];
usbd_status error;
error = udl_ctrl_msg(sc, UT_READ_VENDOR_DEVICE,
UDL_CTRL_CMD_POLL, 0x0000, 0x0000, lbuf, 4);
if (error != USBD_NORMAL_COMPLETION) {
printf("%s: %s: %s!\n", DN(sc), FUNC, usbd_errstr(error));
return (error);
}
*buf = *(uint32_t *)lbuf;
return (USBD_NORMAL_COMPLETION);
}
usbd_status
udl_read_1(struct udl_softc *sc, uint16_t addr, uint8_t *buf)
{
uint8_t lbuf[1];
usbd_status error;
error = udl_ctrl_msg(sc, UT_READ_VENDOR_DEVICE,
UDL_CTRL_CMD_READ_1, addr, 0x0000, lbuf, 1);
if (error != USBD_NORMAL_COMPLETION) {
printf("%s: %s: %s!\n", DN(sc), FUNC, usbd_errstr(error));
return (error);
}
*buf = *(uint8_t *)lbuf;
return (USBD_NORMAL_COMPLETION);
}
usbd_status
udl_write_1(struct udl_softc *sc, uint16_t addr, uint8_t buf)
{
usbd_status error;
error = udl_ctrl_msg(sc, UT_WRITE_VENDOR_DEVICE,
UDL_CTRL_CMD_WRITE_1, addr, 0x0000, &buf, 1);
if (error != USBD_NORMAL_COMPLETION) {
printf("%s: %s: %s!\n", DN(sc), FUNC, usbd_errstr(error));
return (error);
}
return (USBD_NORMAL_COMPLETION);
}
usbd_status
udl_read_edid(struct udl_softc *sc, uint8_t *buf)
{
uint8_t lbuf[64];
uint16_t offset;
usbd_status error;
offset = 0;
error = udl_ctrl_msg(sc, UT_READ_VENDOR_DEVICE,
UDL_CTRL_CMD_READ_EDID, 0x00a1, (offset << 8), lbuf, 64);
if (error != USBD_NORMAL_COMPLETION)
goto fail;
bcopy(lbuf + 1, buf + offset, 63);
offset += 63;
error = udl_ctrl_msg(sc, UT_READ_VENDOR_DEVICE,
UDL_CTRL_CMD_READ_EDID, 0x00a1, (offset << 8), lbuf, 64);
if (error != USBD_NORMAL_COMPLETION)
goto fail;
bcopy(lbuf + 1, buf + offset, 63);
offset += 63;
error = udl_ctrl_msg(sc, UT_READ_VENDOR_DEVICE,
UDL_CTRL_CMD_READ_EDID, 0x00a1, (offset << 8), lbuf, 3);
if (error != USBD_NORMAL_COMPLETION)
goto fail;
bcopy(lbuf + 1, buf + offset, 2);
return (USBD_NORMAL_COMPLETION);
fail:
printf("%s: %s: %s!\n", DN(sc), FUNC, usbd_errstr(error));
return (error);
}
uint8_t
udl_lookup_mode(uint16_t hdisplay, uint16_t vdisplay, uint8_t freq,
uint16_t chip, uint32_t clock)
{
uint8_t idx = 0;
while (idx < MAX_DL_MODES) {
if ((udl_modes[idx].hdisplay == hdisplay) &&
(udl_modes[idx].vdisplay == vdisplay) &&
(udl_modes[idx].clock == clock) &&
(udl_modes[idx].chip <= chip)) {
return(idx);
}
idx++;
}
idx = 0;
while (idx < MAX_DL_MODES) {
if ((udl_modes[idx].hdisplay == hdisplay) &&
(udl_modes[idx].vdisplay == vdisplay) &&
(udl_modes[idx].freq == freq) &&
(udl_modes[idx].chip <= chip)) {
return(idx);
}
idx++;
}
return(idx);
}
int
udl_select_chip(struct udl_softc *sc)
{
char serialnum[USB_MAX_STRING_LEN];
usb_device_descriptor_t *dd;
usb_string_descriptor_t us;
usbd_status error;
int len, i, n;
char *s;
uint16_t c;
sc->sc_chip = DL120;
dd = usbd_get_device_descriptor(sc->sc_udev);
if ((UGETW(dd->idVendor) == USB_VENDOR_DISPLAYLINK) &&
(UGETW(dd->idProduct) == USB_PRODUCT_DISPLAYLINK_WSDVI)) {
bzero(serialnum, sizeof serialnum);
error = usbd_get_string_desc(sc->sc_udev, dd->iSerialNumber,
0, &us, &len);
if (error != USBD_NORMAL_COMPLETION)
return (1);
s = &serialnum[0];
n = len / 2 - 1;
for (i = 0; i < n && i < nitems(us.bString); i++) {
c = UGETW(us.bString[i]);
if ((c & 0xff00) == 0)
*s++ = c;
else if ((c & 0x00ff) == 0)
*s++ = c >> 8;
else
*s++ = '?';
}
*s++ = 0;
if (strlen(serialnum) > 7)
if (strncmp(serialnum, "0198-13", 7) == 0)
sc->sc_chip = DL160;
DPRINTF(1, "%s: %s: iSerialNumber (%s) used to select chip (%d)\n",
DN(sc), FUNC, serialnum, sc->sc_chip);
}
if ((UGETW(dd->idVendor) == USB_VENDOR_DISPLAYLINK) &&
(UGETW(dd->idProduct) == USB_PRODUCT_DISPLAYLINK_SWDVI)) {
sc->sc_chip = DL160;
if (UGETW(dd->bcdDevice) >= 0x100) {
sc->sc_chip = DL165;
if (UGETW(dd->bcdDevice) == 0x104)
sc->sc_chip = DL195;
if (UGETW(dd->bcdDevice) == 0x108)
sc->sc_chip = DL125;
}
DPRINTF(1, "%s: %s: bcdDevice (%02x) used to select chip (%d)\n",
DN(sc), FUNC, UGETW(dd->bcdDevice), sc->sc_chip);
}
return (0);
}
usbd_status
udl_set_enc_key(struct udl_softc *sc, uint8_t *buf, uint8_t len)
{
usbd_status error;
error = udl_ctrl_msg(sc, UT_WRITE_VENDOR_DEVICE,
UDL_CTRL_CMD_SET_KEY, 0x0000, 0x0000, buf, len);
if (error != USBD_NORMAL_COMPLETION) {
printf("%s: %s: %s!\n", DN(sc), FUNC, usbd_errstr(error));
return (error);
}
return (USBD_NORMAL_COMPLETION);
}
usbd_status
udl_set_decomp_table(struct udl_softc *sc, uint8_t *buf, uint16_t len)
{
int err;
udl_cmd_insert_int_1(sc, UDL_BULK_SOC);
udl_cmd_insert_int_1(sc, UDL_BULK_CMD_DECOMP);
udl_cmd_insert_int_4(sc, 0x263871cd);
udl_cmd_insert_int_4(sc, 0x00000200);
udl_cmd_insert_buf(sc, buf, len);
err = udl_cmd_send(sc);
if (err != 0)
return (USBD_INVAL);
return (USBD_NORMAL_COMPLETION);
}
int
udl_load_huffman(struct udl_softc *sc)
{
const char *name = "udl_huffman";
int error;
if (sc->sc_huffman == NULL) {
error = loadfirmware(name, &sc->sc_huffman,
&sc->sc_huffman_size);
if (error != 0) {
printf("%s: error %d, could not read huffman table "
"%s!\n", DN(sc), error, name);
return (EIO);
}
}
DPRINTF(1, "%s: huffman table %s allocated\n", DN(sc), name);
return (0);
}
void
udl_free_huffman(struct udl_softc *sc)
{
if (sc->sc_huffman != NULL) {
free(sc->sc_huffman, M_USBDEV, sc->sc_huffman_size);
sc->sc_huffman = NULL;
sc->sc_huffman_size = 0;
DPRINTF(1, "%s: huffman table freed\n", DN(sc));
}
}
int
udl_fbmem_alloc(struct udl_softc *sc)
{
int size;
size = (sc->sc_width * sc->sc_height) * (sc->sc_depth / 8);
size = round_page(size);
if (sc->sc_fbmem == NULL) {
sc->sc_fbmem = malloc(size, M_USBDEV, M_NOWAIT|M_ZERO);
if (sc->sc_fbmem == NULL)
return (-1);
}
sc->sc_fbmemsize = size;
return (0);
}
void
udl_fbmem_free(struct udl_softc *sc)
{
if (sc->sc_fbmem != NULL) {
free(sc->sc_fbmem, M_USBDEV, sc->sc_fbmemsize);
sc->sc_fbmem = NULL;
sc->sc_fbmemsize = 0;
}
}
usbd_status
udl_cmd_alloc_xfer(struct udl_softc *sc)
{
int i;
for (i = 0; i < UDL_CMD_XFER_COUNT; i++) {
struct udl_cmd_xfer *cx = &sc->sc_cmd_xfer[i];
cx->sc = sc;
cx->xfer = usbd_alloc_xfer(sc->sc_udev);
if (cx->xfer == NULL) {
printf("%s: %s: can't allocate xfer handle!\n",
DN(sc), FUNC);
return (USBD_NOMEM);
}
cx->buf = usbd_alloc_buffer(cx->xfer, UDL_CMD_MAX_XFER_SIZE);
if (cx->buf == NULL) {
printf("%s: %s: can't allocate xfer buffer!\n",
DN(sc), FUNC);
return (USBD_NOMEM);
}
}
return (USBD_NORMAL_COMPLETION);
}
void
udl_cmd_free_xfer(struct udl_softc *sc)
{
int i;
for (i = 0; i < UDL_CMD_XFER_COUNT; i++) {
struct udl_cmd_xfer *cx = &sc->sc_cmd_xfer[i];
if (cx->xfer != NULL) {
usbd_free_xfer(cx->xfer);
cx->xfer = NULL;
}
}
}
int
udl_cmd_alloc_buf(struct udl_softc *sc)
{
struct udl_cmd_buf *cb = &sc->sc_cmd_buf;
cb->buf = malloc(UDL_CMD_MAX_XFER_SIZE, M_USBDEV, M_NOWAIT|M_ZERO);
if (cb->buf == NULL) {
printf("%s: %s: can't allocate buffer!\n",
DN(sc), FUNC);
return (ENOMEM);
}
cb->off = 0;
cb->compblock = 0;
return (0);
}
void
udl_cmd_free_buf(struct udl_softc *sc)
{
struct udl_cmd_buf *cb = &sc->sc_cmd_buf;
if (cb->buf != NULL) {
free(cb->buf, M_USBDEV, UDL_CMD_MAX_XFER_SIZE);
cb->buf = NULL;
}
cb->off = 0;
}
void
udl_cmd_insert_int_1(struct udl_softc *sc, uint8_t value)
{
struct udl_cmd_buf *cb = &sc->sc_cmd_buf;
cb->buf[cb->off] = value;
cb->off += 1;
}
void
udl_cmd_insert_int_2(struct udl_softc *sc, uint16_t value)
{
uint16_t lvalue;
struct udl_cmd_buf *cb = &sc->sc_cmd_buf;
lvalue = htobe16(value);
bcopy(&lvalue, cb->buf + cb->off, 2);
cb->off += 2;
}
void
udl_cmd_insert_int_3(struct udl_softc *sc, uint32_t value)
{
uint32_t lvalue;
struct udl_cmd_buf *cb = &sc->sc_cmd_buf;
#if BYTE_ORDER == BIG_ENDIAN
lvalue = htobe32(value) << 8;
#else
lvalue = htobe32(value) >> 8;
#endif
bcopy(&lvalue, cb->buf + cb->off, 3);
cb->off += 3;
}
void
udl_cmd_insert_int_4(struct udl_softc *sc, uint32_t value)
{
uint32_t lvalue;
struct udl_cmd_buf *cb = &sc->sc_cmd_buf;
lvalue = htobe32(value);
bcopy(&lvalue, cb->buf + cb->off, 4);
cb->off += 4;
}
void
udl_cmd_insert_buf(struct udl_softc *sc, uint8_t *buf, uint32_t len)
{
struct udl_cmd_buf *cb = &sc->sc_cmd_buf;
bcopy(buf, cb->buf + cb->off, len);
cb->off += len;
}
int
udl_cmd_insert_buf_comp(struct udl_softc *sc, uint8_t *buf, uint32_t len)
{
struct udl_cmd_buf *cb = &sc->sc_cmd_buf;
struct udl_huffman *h;
uint8_t bit_pos;
uint16_t *pixels, prev;
int16_t diff;
uint32_t bit_count, bit_pattern, bit_cur;
int i, j, bytes, eob, padding, next;
pixels = (uint16_t *)buf;
bit_pos = bytes = eob = padding = 0;
if (cb->compblock >= UDL_CB_RESTART_SIZE) {
cb->off -= UDL_CMD_WRITE_HEAD_SIZE;
cb->compblock -= UDL_CMD_WRITE_HEAD_SIZE;
eob = 1;
}
for (i = 0; i < len / 2 && eob == 0; i++) {
if (i > 0)
prev = betoh16(pixels[i - 1]);
else
prev = 0;
diff = betoh16(pixels[i]) - prev;
h = (struct udl_huffman *)(sc->sc_huffman + UDL_HUFFMAN_BASE);
h += diff;
bit_count = h->bit_count;
bit_pattern = betoh32(h->bit_pattern);
if (bit_count % 8 == 0)
next = bit_count / 8;
else
next = (bit_count / 8) + 1;
if (cb->compblock + next >= UDL_CB_BODY_SIZE) {
eob = 1;
break;
}
for (j = 0; j < bit_count; j++) {
if (bit_pos == 0)
cb->buf[cb->off] = 0;
bit_cur = (bit_pattern >> j) & 1;
cb->buf[cb->off] |= (bit_cur << bit_pos);
bit_pos++;
if (bit_pos == 8) {
bit_pos = 0;
cb->off++;
cb->compblock++;
}
}
bytes += 2;
}
if (bit_pos != 0) {
cb->off++;
cb->compblock++;
}
if (eob == 1) {
padding = (UDL_CB_BODY_SIZE - cb->compblock);
for (i = 0; i < padding; i++) {
cb->buf[cb->off] = 0;
cb->off++;
cb->compblock++;
}
udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0xff);
cb->compblock = 0;
}
return (bytes);
}
int
udl_cmd_insert_head_comp(struct udl_softc *sc, uint32_t len)
{
struct udl_cmd_buf *cb = &sc->sc_cmd_buf;
int i, padding;
if (cb->compblock > UDL_CB_BODY_SIZE) {
cb->off -= UDL_CMD_COPY_HEAD_SIZE;
cb->compblock -= UDL_CMD_COPY_HEAD_SIZE;
padding = (UDL_CB_BODY_SIZE - cb->compblock);
for (i = 0; i < padding; i++) {
cb->buf[cb->off] = 0;
cb->off++;
cb->compblock++;
}
udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0xff);
cb->compblock = 0;
return (0);
}
return (len);
}
int
udl_cmd_insert_check(struct udl_softc *sc, int len)
{
struct udl_cmd_buf *cb = &sc->sc_cmd_buf;
int total;
usbd_status error;
total = cb->off + len;
if (total > UDL_CMD_MAX_XFER_SIZE) {
if (cb->xfer_type == UDL_CMD_XFER_ASYNC)
error = udl_cmd_send_async(sc);
else
error = udl_cmd_send(sc);
if (error != USBD_NORMAL_COMPLETION) {
DPRINTF(1, "%s: %s: can't flush full command buffer\n",
DN(sc), FUNC);
return (EAGAIN);
}
}
return (0);
}
void
udl_cmd_set_xfer_type(struct udl_softc *sc, int xfer_type)
{
struct udl_cmd_buf *cb = &sc->sc_cmd_buf;
cb->xfer_type = xfer_type;
}
void
udl_cmd_save_offset(struct udl_softc *sc)
{
struct udl_cmd_buf *cb = &sc->sc_cmd_buf;
cb->off_save = cb->off;
cb->compblock_save = cb->compblock;
}
void
udl_cmd_restore_offset(struct udl_softc *sc)
{
struct udl_cmd_buf *cb = &sc->sc_cmd_buf;
cb->off = cb->off_save;
cb->compblock = cb->compblock_save;
}
void
udl_cmd_write_reg_1(struct udl_softc *sc, uint8_t reg, uint8_t val)
{
udl_cmd_insert_int_1(sc, UDL_BULK_SOC);
udl_cmd_insert_int_1(sc, UDL_BULK_CMD_REG_WRITE_1);
udl_cmd_insert_int_1(sc, reg);
udl_cmd_insert_int_1(sc, val);
}
void
udl_cmd_write_reg_3(struct udl_softc *sc, uint8_t reg, uint32_t val)
{
udl_cmd_write_reg_1(sc, reg + 0, (val >> 16) & 0xff);
udl_cmd_write_reg_1(sc, reg + 1, (val >> 8) & 0xff);
udl_cmd_write_reg_1(sc, reg + 2, (val >> 0) & 0xff);
}
usbd_status
udl_cmd_send(struct udl_softc *sc)
{
struct udl_cmd_buf *cb = &sc->sc_cmd_buf;
struct udl_cmd_xfer *cx = &sc->sc_cmd_xfer[0];
int len;
usbd_status error;
udl_cmd_insert_int_1(sc, UDL_BULK_SOC);
udl_cmd_insert_int_1(sc, UDL_BULK_CMD_EOC);
bcopy(cb->buf, cx->buf, cb->off);
len = cb->off;
usbd_setup_xfer(cx->xfer, sc->sc_tx_pipeh, 0, cx->buf, len,
USBD_NO_COPY | USBD_SHORT_XFER_OK | USBD_SYNCHRONOUS, 1000, NULL);
error = usbd_transfer(cx->xfer);
if (error != USBD_NORMAL_COMPLETION) {
printf("%s: %s: %s!\n", DN(sc), FUNC, usbd_errstr(error));
goto fail;
}
DPRINTF(1, "%s: %s: sent %d of %d bytes\n",
DN(sc), FUNC, len, cb->off);
fail:
cb->off = 0;
cb->compblock = 0;
return (error);
}
usbd_status
udl_cmd_send_async(struct udl_softc *sc)
{
struct udl_cmd_buf *cb = &sc->sc_cmd_buf;
struct udl_cmd_xfer *cx;
usbd_status error;
int i, s;
if (sc->sc_cmd_xfer_cnt == UDL_CMD_XFER_COUNT)
return (USBD_IN_USE);
s = splusb();
for (i = 0; i < UDL_CMD_XFER_COUNT; i++) {
if (sc->sc_cmd_xfer[i].busy == 0)
break;
}
if (i == UDL_CMD_XFER_COUNT) {
splx(s);
return (USBD_IN_USE);
}
cx = &sc->sc_cmd_xfer[i];
udl_cmd_insert_int_1(sc, UDL_BULK_SOC);
udl_cmd_insert_int_1(sc, UDL_BULK_CMD_EOC);
bcopy(cb->buf, cx->buf, cb->off);
usbd_setup_xfer(cx->xfer, sc->sc_tx_pipeh, cx, cx->buf, cb->off,
USBD_NO_COPY, 1000, udl_cmd_send_async_cb);
error = usbd_transfer(cx->xfer);
if (error != 0 && error != USBD_IN_PROGRESS) {
printf("%s: %s: %s!\n", DN(sc), FUNC, usbd_errstr(error));
splx(s);
return (error);
}
DPRINTF(2, "%s: %s: sending %d bytes from buffer no. %d\n",
DN(sc), FUNC, cb->off, i);
cb->off = 0;
cb->compblock = 0;
cx->busy = 1;
sc->sc_cmd_xfer_cnt++;
splx(s);
return (USBD_NORMAL_COMPLETION);
}
void
udl_cmd_send_async_cb(struct usbd_xfer *xfer, void *priv, usbd_status status)
{
struct udl_cmd_xfer *cx = priv;
struct udl_softc *sc = cx->sc;
int len;
if (status != USBD_NORMAL_COMPLETION) {
printf("%s: %s: %s!\n", DN(sc), FUNC, usbd_errstr(status));
if (status == USBD_NOT_STARTED || status == USBD_CANCELLED)
return;
if (status == USBD_STALLED)
usbd_clear_endpoint_stall_async(sc->sc_tx_pipeh);
goto skip;
}
usbd_get_xfer_status(xfer, NULL, NULL, &len, NULL);
DPRINTF(3, "%s: %s: sent %d bytes\n", DN(sc), FUNC, len);
skip:
cx->busy = 0;
sc->sc_cmd_xfer_cnt--;
wakeup(sc);
}
usbd_status
udl_init_chip(struct udl_softc *sc)
{
uint8_t ui8;
uint32_t ui32;
usbd_status error;
error = udl_poll(sc, &ui32);
if (error != USBD_NORMAL_COMPLETION)
return (error);
DPRINTF(1, "%s: %s: poll=0x%08x\n", DN(sc), FUNC, ui32);
switch (ui32 & 0xff) {
case 0xf1:
switch (sc->sc_chip) {
case DL120:
sc->sc_chip = DL125;
break;
case DL160:
sc->sc_chip = DL165;
break;
}
break;
}
DPRINTF(1, "%s: %s: chip %d\n", DN(sc), FUNC, sc->sc_chip);
error = udl_read_1(sc, 0xc484, &ui8);
if (error != USBD_NORMAL_COMPLETION)
return (error);
DPRINTF(1, "%s: %s: read 0x%02x from 0xc484\n", DN(sc), FUNC, ui8);
error = udl_write_1(sc, 0xc41f, 0x01);
if (error != USBD_NORMAL_COMPLETION)
return (error);
DPRINTF(1, "%s: %s: write 0x01 to 0xc41f\n", DN(sc), FUNC);
error = udl_read_edid(sc, sc->sc_edid);
if (error != USBD_NORMAL_COMPLETION)
return (error);
DPRINTF(1, "%s: %s: read EDID\n", DN(sc), FUNC);
error = udl_set_enc_key(sc, udl_null_key_1, sizeof(udl_null_key_1));
if (error != USBD_NORMAL_COMPLETION)
return (error);
DPRINTF(1, "%s: %s: set encryption key\n", DN(sc), FUNC);
error = udl_write_1(sc, 0xc40b, 0x00);
if (error != USBD_NORMAL_COMPLETION)
return (error);
DPRINTF(1, "%s: %s: write 0x00 to 0xc40b\n", DN(sc), FUNC);
error = udl_set_decomp_table(sc, udl_decomp_table,
sizeof(udl_decomp_table));
if (error != USBD_NORMAL_COMPLETION)
return (error);
DPRINTF(1, "%s: %s: set decompression table\n", DN(sc), FUNC);
return (USBD_NORMAL_COMPLETION);
}
void
udl_init_fb_offsets(struct udl_softc *sc, uint32_t start16, uint32_t stride16,
uint32_t start8, uint32_t stride8)
{
udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0x00);
udl_cmd_write_reg_3(sc, UDL_REG_ADDR_START16, start16);
udl_cmd_write_reg_3(sc, UDL_REG_ADDR_STRIDE16, stride16);
udl_cmd_write_reg_3(sc, UDL_REG_ADDR_START8, start8);
udl_cmd_write_reg_3(sc, UDL_REG_ADDR_STRIDE8, stride8);
udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0xff);
}
usbd_status
udl_init_resolution(struct udl_softc *sc)
{
int i;
usbd_status error;
uint8_t *buf = udl_modes[sc->sc_cur_mode].mode;
udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0x00);
for (i = 0; i < UDL_MODE_SIZE; i++)
udl_cmd_write_reg_1(sc, i, buf[i]);
udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0xff);
udl_init_fb_offsets(sc, 0x000000, 0x000a00, 0x555555, 0x000500);
error = udl_cmd_send(sc);
if (error != USBD_NORMAL_COMPLETION)
return (error);
error = udl_clear_screen(sc);
if (error != USBD_NORMAL_COMPLETION)
return (error);
udl_cmd_write_reg_1(sc, UDL_REG_SCREEN, UDL_REG_SCREEN_ON);
udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0xff);
error = udl_cmd_send(sc);
if (error != USBD_NORMAL_COMPLETION)
return (error);
return (USBD_NORMAL_COMPLETION);
}
usbd_status
udl_clear_screen(struct udl_softc *sc)
{
struct udl_cmd_buf *cb = &sc->sc_cmd_buf;
usbd_status error;
udl_fb_block_write(sc, 0x0000, 0, 0, sc->sc_width, sc->sc_height);
if (cb->xfer_type == UDL_CMD_XFER_ASYNC)
error = udl_cmd_send_async(sc);
else
error = udl_cmd_send(sc);
if (error != USBD_NORMAL_COMPLETION)
return (error);
return (USBD_NORMAL_COMPLETION);
}
void
udl_select_mode(struct udl_softc *sc)
{
struct udl_mode mode;
int index = MAX_DL_MODES, i;
edid_parse(DN(sc), sc->sc_edid, &sc->sc_edid_info);
#if defined(UDL_DEBUG) && defined(EDID_DEBUG)
edid_print(&sc->sc_edid_info);
#endif
if (sc->sc_edid_info.edid_preferred_mode != NULL) {
mode.freq =
(sc->sc_edid_info.edid_preferred_mode->dot_clock * 1000) /
(sc->sc_edid_info.edid_preferred_mode->htotal *
sc->sc_edid_info.edid_preferred_mode->vtotal);
mode.clock =
sc->sc_edid_info.edid_preferred_mode->dot_clock / 10;
mode.hdisplay =
sc->sc_edid_info.edid_preferred_mode->hdisplay;
mode.vdisplay =
sc->sc_edid_info.edid_preferred_mode->vdisplay;
index = udl_lookup_mode(mode.hdisplay, mode.vdisplay, mode.freq,
sc->sc_chip, mode.clock);
sc->sc_cur_mode = index;
} else {
DPRINTF(1, "%s: %s: no preferred mode found!\n", DN(sc), FUNC);
}
if (index == MAX_DL_MODES) {
DPRINTF(1, "%s: %s: no mode line found for %dx%d @ %dHz!\n",
DN(sc), FUNC, mode.hdisplay, mode.vdisplay, mode.freq);
i = 0;
while (i < sc->sc_edid_info.edid_nmodes) {
mode.freq =
(sc->sc_edid_info.edid_modes[i].dot_clock * 1000) /
(sc->sc_edid_info.edid_modes[i].htotal *
sc->sc_edid_info.edid_modes[i].vtotal);
mode.clock =
sc->sc_edid_info.edid_modes[i].dot_clock / 10;
mode.hdisplay =
sc->sc_edid_info.edid_modes[i].hdisplay;
mode.vdisplay =
sc->sc_edid_info.edid_modes[i].vdisplay;
index = udl_lookup_mode(mode.hdisplay, mode.vdisplay,
mode.freq, sc->sc_chip, mode.clock);
if (index < MAX_DL_MODES)
if ((sc->sc_cur_mode == MAX_DL_MODES) ||
(index > sc->sc_cur_mode))
sc->sc_cur_mode = index;
i++;
}
}
if (sc->sc_cur_mode == MAX_DL_MODES)
sc->sc_cur_mode = udl_lookup_mode(800, 600, 60, sc->sc_chip, 0);
mode = udl_modes[sc->sc_cur_mode];
sc->sc_width = mode.hdisplay;
sc->sc_height = mode.vdisplay;
sc->sc_depth = 16;
DPRINTF(1, "%s: %s: %dx%d @ %dHz\n",
DN(sc), FUNC, mode.hdisplay, mode.vdisplay, mode.freq);
}
int
udl_fb_buf_write(struct udl_softc *sc, uint8_t *buf, uint32_t x,
uint32_t y, uint16_t width)
{
uint16_t lwidth;
uint32_t off;
int r;
r = udl_cmd_insert_check(sc, UDL_CMD_WRITE_MAX_SIZE);
if (r != 0)
return (r);
off = ((y * sc->sc_width) + x) * 2;
lwidth = width * 2;
udl_cmd_insert_int_1(sc, UDL_BULK_SOC);
udl_cmd_insert_int_1(sc, UDL_BULK_CMD_FB_WRITE | UDL_BULK_CMD_FB_WORD);
udl_cmd_insert_int_3(sc, off);
udl_cmd_insert_int_1(sc, width >= UDL_CMD_MAX_PIXEL_COUNT ? 0 : width);
udl_cmd_insert_buf(sc, buf, lwidth);
return (0);
}
int
udl_fb_block_write(struct udl_softc *sc, uint16_t rgb16, uint32_t x,
uint32_t y, uint32_t width, uint32_t height)
{
uint32_t i;
int r;
for (i = 0; i < height; i++) {
r = udl_fb_line_write(sc, rgb16, x, y + i, width);
if (r != 0)
return (r);
}
return (0);
}
int
udl_fb_line_write(struct udl_softc *sc, uint16_t rgb16, uint32_t x,
uint32_t y, uint32_t width)
{
uint32_t off, block;
int r;
off = (y * sc->sc_width) + x;
while (width) {
if (width > UDL_CMD_MAX_PIXEL_COUNT)
block = UDL_CMD_MAX_PIXEL_COUNT;
else
block = width;
r = udl_fb_off_write(sc, rgb16, off, block);
if (r != 0)
return (r);
off += block;
width -= block;
}
return (0);
}
int
udl_fb_off_write(struct udl_softc *sc, uint16_t rgb16, uint32_t off,
uint16_t width)
{
uint8_t buf[UDL_CMD_MAX_DATA_SIZE];
uint16_t lwidth, lrgb16;
uint32_t loff;
int i, r;
r = udl_cmd_insert_check(sc, UDL_CMD_WRITE_MAX_SIZE);
if (r != 0)
return (r);
loff = off * 2;
lwidth = width * 2;
udl_cmd_insert_int_1(sc, UDL_BULK_SOC);
udl_cmd_insert_int_1(sc, UDL_BULK_CMD_FB_WRITE | UDL_BULK_CMD_FB_WORD);
udl_cmd_insert_int_3(sc, loff);
udl_cmd_insert_int_1(sc, width >= UDL_CMD_MAX_PIXEL_COUNT ? 0 : width);
for (i = 0; i < lwidth; i += 2) {
lrgb16 = htobe16(rgb16);
bcopy(&lrgb16, buf + i, 2);
}
udl_cmd_insert_buf(sc, buf, lwidth);
return (0);
}
int
udl_fb_block_copy(struct udl_softc *sc, uint32_t src_x, uint32_t src_y,
uint32_t dst_x, uint32_t dst_y, uint32_t width, uint32_t height)
{
int i, r;
for (i = 0; i < height; i++) {
r = udl_fb_line_copy(sc, src_x, src_y + i, dst_x, dst_y + i,
width);
if (r != 0)
return (r);
}
return (0);
}
int
udl_fb_line_copy(struct udl_softc *sc, uint32_t src_x, uint32_t src_y,
uint32_t dst_x, uint32_t dst_y, uint32_t width)
{
uint32_t src_off, dst_off, block;
int r;
src_off = (src_y * sc->sc_width) + src_x;
dst_off = (dst_y * sc->sc_width) + dst_x;
while (width) {
if (width > UDL_CMD_MAX_PIXEL_COUNT)
block = UDL_CMD_MAX_PIXEL_COUNT;
else
block = width;
r = udl_fb_off_copy(sc, src_off, dst_off, block);
if (r != 0)
return (r);
src_off += block;
dst_off += block;
width -= block;
}
return (0);
}
int
udl_fb_off_copy(struct udl_softc *sc, uint32_t src_off, uint32_t dst_off,
uint16_t width)
{
uint32_t ldst_off, lsrc_off;
int r;
r = udl_cmd_insert_check(sc, UDL_CMD_COPY_MAX_SIZE);
if (r != 0)
return (r);
ldst_off = dst_off * 2;
lsrc_off = src_off * 2;
udl_cmd_insert_int_1(sc, UDL_BULK_SOC);
udl_cmd_insert_int_1(sc, UDL_BULK_CMD_FB_COPY | UDL_BULK_CMD_FB_WORD);
udl_cmd_insert_int_3(sc, ldst_off);
udl_cmd_insert_int_1(sc, width >= UDL_CMD_MAX_PIXEL_COUNT ? 0 : width);
udl_cmd_insert_int_3(sc, lsrc_off);
return (0);
}
int
udl_fb_buf_write_comp(struct udl_softc *sc, uint8_t *buf, uint32_t x,
uint32_t y, uint16_t width)
{
struct udl_cmd_buf *cb = &sc->sc_cmd_buf;
uint8_t *count;
uint16_t lwidth;
uint32_t off;
int r, sent;
r = udl_cmd_insert_check(sc, UDL_CMD_WRITE_MAX_SIZE);
if (r != 0)
return (r);
off = ((y * sc->sc_width) + x) * 2;
lwidth = width * 2;
if (cb->off == 0)
udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0xff);
r = sent = 0;
while (sent < lwidth) {
udl_cmd_insert_int_1(sc, UDL_BULK_SOC);
udl_cmd_insert_int_1(sc,
UDL_BULK_CMD_FB_WRITE |
UDL_BULK_CMD_FB_WORD |
UDL_BULK_CMD_FB_COMP);
udl_cmd_insert_int_3(sc, off + sent);
udl_cmd_insert_int_1(sc,
width >= UDL_CMD_MAX_PIXEL_COUNT ? 0 : width);
cb->compblock += UDL_CMD_WRITE_HEAD_SIZE;
count = &cb->buf[cb->off - 1];
r = udl_cmd_insert_buf_comp(sc, buf + sent, lwidth - sent);
if (r > 0 && r != (lwidth - sent)) {
*count = r / 2;
width -= r / 2;
}
sent += r;
}
return (0);
}
int
udl_fb_block_write_comp(struct udl_softc *sc, uint16_t rgb16, uint32_t x,
uint32_t y, uint32_t width, uint32_t height)
{
uint32_t i;
int r;
for (i = 0; i < height; i++) {
r = udl_fb_line_write_comp(sc, rgb16, x, y + i, width);
if (r != 0)
return (r);
}
return (0);
}
int
udl_fb_line_write_comp(struct udl_softc *sc, uint16_t rgb16, uint32_t x,
uint32_t y, uint32_t width)
{
uint32_t off, block;
int r;
off = (y * sc->sc_width) + x;
while (width) {
if (width > UDL_CMD_MAX_PIXEL_COUNT)
block = UDL_CMD_MAX_PIXEL_COUNT;
else
block = width;
r = udl_fb_off_write_comp(sc, rgb16, off, block);
if (r != 0)
return (r);
off += block;
width -= block;
}
return (0);
}
int
udl_fb_off_write_comp(struct udl_softc *sc, uint16_t rgb16, uint32_t off,
uint16_t width)
{
struct udl_cmd_buf *cb = &sc->sc_cmd_buf;
uint8_t buf[UDL_CMD_MAX_DATA_SIZE];
uint8_t *count;
uint16_t lwidth, lrgb16;
uint32_t loff;
int i, r, sent;
r = udl_cmd_insert_check(sc, UDL_CMD_WRITE_MAX_SIZE);
if (r != 0)
return (r);
loff = off * 2;
lwidth = width * 2;
for (i = 0; i < lwidth; i += 2) {
lrgb16 = htobe16(rgb16);
bcopy(&lrgb16, buf + i, 2);
}
if (cb->off == 0)
udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0xff);
r = sent = 0;
while (sent < lwidth) {
udl_cmd_insert_int_1(sc, UDL_BULK_SOC);
udl_cmd_insert_int_1(sc,
UDL_BULK_CMD_FB_WRITE |
UDL_BULK_CMD_FB_WORD |
UDL_BULK_CMD_FB_COMP);
udl_cmd_insert_int_3(sc, loff + sent);
udl_cmd_insert_int_1(sc,
width >= UDL_CMD_MAX_PIXEL_COUNT ? 0 : width);
cb->compblock += UDL_CMD_WRITE_HEAD_SIZE;
count = &cb->buf[cb->off - 1];
r = udl_cmd_insert_buf_comp(sc, buf + sent, lwidth - sent);
if (r > 0 && r != (lwidth - sent)) {
*count = r / 2;
width -= r / 2;
}
sent += r;
}
return (0);
}
int
udl_fb_block_copy_comp(struct udl_softc *sc, uint32_t src_x, uint32_t src_y,
uint32_t dst_x, uint32_t dst_y, uint32_t width, uint32_t height)
{
int i, r;
for (i = 0; i < height; i++) {
r = udl_fb_line_copy_comp(sc, src_x, src_y + i,
dst_x, dst_y + i, width);
if (r != 0)
return (r);
}
return (0);
}
int
udl_fb_line_copy_comp(struct udl_softc *sc, uint32_t src_x, uint32_t src_y,
uint32_t dst_x, uint32_t dst_y, uint32_t width)
{
uint32_t src_off, dst_off, block;
int r;
src_off = (src_y * sc->sc_width) + src_x;
dst_off = (dst_y * sc->sc_width) + dst_x;
while (width) {
if (width > UDL_CMD_MAX_PIXEL_COUNT)
block = UDL_CMD_MAX_PIXEL_COUNT;
else
block = width;
r = udl_fb_off_copy_comp(sc, src_off, dst_off, block);
if (r != 0)
return (r);
src_off += block;
dst_off += block;
width -= block;
}
return (0);
}
int
udl_fb_off_copy_comp(struct udl_softc *sc, uint32_t src_off, uint32_t dst_off,
uint16_t width)
{
struct udl_cmd_buf *cb = &sc->sc_cmd_buf;
uint32_t ldst_off, lsrc_off;
int r;
r = udl_cmd_insert_check(sc, UDL_CMD_COPY_MAX_SIZE);
if (r != 0)
return (r);
ldst_off = dst_off * 2;
lsrc_off = src_off * 2;
if (cb->off == 0)
udl_cmd_write_reg_1(sc, UDL_REG_SYNC, 0xff);
r = 0;
while (r < 1) {
udl_cmd_insert_int_1(sc, UDL_BULK_SOC);
udl_cmd_insert_int_1(sc,
UDL_BULK_CMD_FB_COPY | UDL_BULK_CMD_FB_WORD);
udl_cmd_insert_int_3(sc, ldst_off);
udl_cmd_insert_int_1(sc,
width >= UDL_CMD_MAX_PIXEL_COUNT ? 0 : width);
udl_cmd_insert_int_3(sc, lsrc_off);
cb->compblock += UDL_CMD_COPY_HEAD_SIZE;
r = udl_cmd_insert_head_comp(sc, UDL_CMD_COPY_HEAD_SIZE);
}
return (0);
}
#ifdef UDL_DEBUG
void
udl_hexdump(void *buf, int len, int quiet)
{
int i;
for (i = 0; i < len; i++) {
if (quiet == 0) {
if (i % 16 == 0)
printf("%s%5i:", i ? "\n" : "", i);
if (i % 4 == 0)
printf(" ");
}
printf("%02x", (int)*((u_char *)buf + i));
}
printf("\n");
}
usbd_status
udl_init_test(struct udl_softc *sc)
{
int i, j, parts, loops;
uint16_t color;
uint16_t rgb24[3] = { 0xf800, 0x07e0, 0x001f };
loops = (sc->sc_width * sc->sc_height) / UDL_CMD_MAX_PIXEL_COUNT;
parts = loops / 3;
color = rgb24[0];
j = 1;
for (i = 0; i < loops; i++) {
if (i == parts) {
color = rgb24[j];
parts += parts;
j++;
}
(sc->udl_fb_off_write)(sc, color, i * UDL_CMD_MAX_PIXEL_COUNT,
UDL_CMD_MAX_PIXEL_COUNT);
}
(void)udl_cmd_send(sc);
return (USBD_NORMAL_COMPLETION);
}
#endif