LCOV - code coverage report
Current view: top level - dev/usb - udl.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 1119 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 74 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13