Page MenuHomeFreeBSD

D35508.diff
No OneTemporary

D35508.diff

Index: sys/amd64/conf/GENERIC
===================================================================
--- sys/amd64/conf/GENERIC
+++ sys/amd64/conf/GENERIC
@@ -344,6 +344,7 @@
device usb # USB Bus (required)
device ukbd # Keyboard
device umass # Disks/Mass storage - Requires scbus and da
+device vbmouse # VirtualBox mouse support
# Sound support
device sound # Generic sound driver (required)
Index: sys/conf/files
===================================================================
--- sys/conf/files
+++ sys/conf/files
@@ -3445,6 +3445,7 @@
dev/usb/input/usbhid.c optional usbhid
dev/usb/input/wmt.c optional wmt
dev/usb/input/wsp.c optional wsp
+dev/usb/input/vbmouse.c optional vbmouse
#
# USB quirks
#
Index: sys/dev/usb/input/vbmouse.c
===================================================================
--- sys/dev/usb/input/vbmouse.c
+++ sys/dev/usb/input/vbmouse.c
@@ -0,0 +1,528 @@
+/*-
+ * Copyright (c) 2018 - 2022 Soren Schmidt <sos@DeepCore.dk>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$Id$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/conf.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/stddef.h>
+#include <sys/sysctl.h>
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+#include <dev/usb/usbhid.h>
+#include "usbdevs.h"
+#include <dev/vt/vt.h>
+
+#define VBMOUSE_MAX_BUT 8
+
+enum {
+ VBMOUSE_INTR_DT,
+ VBMOUSE_N_TRANS,
+};
+
+struct vbmouse_softc
+{
+ device_t sc_dev;
+ struct mtx sc_mtx;
+ struct usb_xfer *sc_xfer[VBMOUSE_N_TRANS];
+ struct hid_location sc_loc_x;
+ struct hid_location sc_loc_y;
+ struct hid_location sc_loc_z;
+ struct hid_location sc_loc_btn[VBMOUSE_MAX_BUT];
+ uint8_t sc_iid_x;
+ uint8_t sc_iid_y;
+ uint8_t sc_iid_z;
+ uint8_t sc_iid_btn[VBMOUSE_MAX_BUT];
+ uint8_t sc_nbuttons;
+ uint32_t sc_flags;
+#define VBMOUSE_FLAG_X_AXIS 0x0001
+#define VBMOUSE_FLAG_Y_AXIS 0x0002
+#define VBMOUSE_FLAG_Z_AXIS 0x0004
+#define VBMOUSE_FLAG_OPENED 0x0008
+
+ uint8_t sc_temp[64];
+};
+
+static device_probe_t vbmouse_probe;
+static device_attach_t vbmouse_attach;
+static device_detach_t vbmouse_detach;
+static usb_callback_t vbmouse_intr_callback;
+
+static int vbmouse_hid_test(const void *, uint16_t);
+static void vbmouse_hid_parse(struct vbmouse_softc *, const void *, uint16_t);
+
+static void vbmouse_control(int, int, int, int);
+extern struct vt_device *main_vd;
+
+static MALLOC_DEFINE(M_VBM, "vbmouse", "vbmouse vt buffer");
+
+static const struct usb_config vbmouse_config[VBMOUSE_N_TRANS] = {
+ [VBMOUSE_INTR_DT] = {
+ .type = UE_INTERRUPT,
+ .endpoint = UE_ADDR_ANY,
+ .direction = UE_DIR_IN,
+ .flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
+ .bufsize = 0,
+ .callback = &vbmouse_intr_callback,
+ },
+};
+
+static int
+vbmouse_probe(device_t dev)
+{
+ struct usb_attach_arg *uaa = device_get_ivars(dev);
+ uint16_t len;
+ void *ptr;
+ int err;
+
+ if (uaa->usb_mode != USB_MODE_HOST)
+ return ENXIO;
+
+ if (uaa->info.bInterfaceClass != UICLASS_HID)
+ return ENXIO;
+
+ err = usbd_req_get_hid_desc(uaa->device, NULL, &ptr, &len, M_TEMP,
+ uaa->info.bIfaceIndex);
+ if (err != USB_ERR_NORMAL_COMPLETION)
+ return ENXIO;
+
+ if (vbmouse_hid_test(ptr, len))
+ err = BUS_PROBE_DEFAULT;
+ else
+ err = ENXIO;
+
+ free(ptr, M_TEMP);
+ return err;
+}
+
+static int
+vbmouse_attach(device_t dev)
+{
+ struct usb_attach_arg *uaa = device_get_ivars(dev);
+ struct vbmouse_softc *sc = device_get_softc(dev);
+ struct vt_device *vd = main_vd;
+ void *ptr = NULL;
+ uint16_t len;
+ int err;
+
+ device_set_usb_desc(dev);
+ sc->sc_dev = dev;
+
+ mtx_init(&sc->sc_mtx, "vbmouse lock", NULL, MTX_DEF | MTX_RECURSE);
+
+ err = usbd_transfer_setup(uaa->device, &uaa->info.bIfaceIndex, sc->sc_xfer,
+ vbmouse_config, VBMOUSE_N_TRANS, sc, &sc->sc_mtx);
+ if (err != USB_ERR_NORMAL_COMPLETION) {
+ usbd_transfer_unsetup(sc->sc_xfer, VBMOUSE_N_TRANS);
+ mtx_destroy(&sc->sc_mtx);
+ return ENXIO;
+ }
+
+ err = usbd_req_get_hid_desc(uaa->device, NULL, &ptr, &len, M_TEMP,
+ uaa->info.bIfaceIndex);
+ if (err != USB_ERR_NORMAL_COMPLETION) {
+ usbd_transfer_unsetup(sc->sc_xfer, VBMOUSE_N_TRANS);
+ mtx_destroy(&sc->sc_mtx);
+ return ENXIO;
+ }
+
+ vbmouse_hid_parse(sc, ptr, len);
+ free(ptr, M_TEMP);
+
+ /* enable and show mouse */
+ vd->vd_flags |= VDF_MOUSECURSOR;
+ vt_mouse_state(VT_MOUSE_SHOW);
+
+ /* allocate 64kb cut&paste buffer */
+ VD_PASTEBUF(vd) = malloc(65536, M_VBM, M_WAITOK | M_ZERO);
+ VD_PASTEBUFSZ(vd) = 65536;
+ VD_PASTEBUFLEN(vd) = 0;
+
+ usbd_transfer_start(sc->sc_xfer[VBMOUSE_INTR_DT]);
+ return 0;
+}
+
+static int
+vbmouse_detach(device_t dev)
+{
+ struct vbmouse_softc *sc = device_get_softc(dev);
+ struct vt_device *vd = main_vd;
+
+ usbd_transfer_unsetup(sc->sc_xfer, VBMOUSE_N_TRANS);
+ mtx_destroy(&sc->sc_mtx);
+
+ /* disable and hide mouse */
+ vd->vd_flags &= ~VDF_MOUSECURSOR;
+ vt_mouse_state(VT_MOUSE_HIDE);
+
+ /* free cut&paste buffer */
+ free(VD_PASTEBUF(vd), M_VBM);
+
+ return 0;
+}
+
+static void
+vbmouse_intr_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+ struct vbmouse_softc *sc = usbd_xfer_softc(xfer);
+ struct usb_page_cache *pc;
+ uint8_t *buf = sc->sc_temp;
+ uint8_t id;
+ int len, i;
+ int x = 0, y = 0, z = 0, buttons = 0;
+
+ usbd_xfer_status(xfer, &len, NULL, NULL, NULL);
+
+ switch (USB_GET_STATE(xfer)) {
+ case USB_ST_SETUP:
+ break;
+
+ case USB_ST_TRANSFERRED:
+ if (len > (int)sizeof(sc->sc_temp))
+ len = sizeof(sc->sc_temp);
+
+ if (!len)
+ break;
+
+ pc = usbd_xfer_get_frame(xfer, 0);
+ usbd_copy_out(pc, 0, buf, len);
+
+ id = 0;
+ if (sc->sc_iid_x > 0 || sc->sc_iid_y > 0) {
+ id = *buf;
+ len--;
+ buf++;
+ }
+
+ x = hid_get_data(buf, len, &sc->sc_loc_x);
+ y = hid_get_data(buf, len, &sc->sc_loc_y);
+ z = hid_get_data(buf, len, &sc->sc_loc_z);
+
+ for (i = 0; i < sc->sc_nbuttons; i++)
+ if (id == sc->sc_iid_btn[i]) {
+ if (hid_get_data(buf, len, &sc->sc_loc_btn[i]))
+ buttons |= (1<<i);
+ }
+
+ vbmouse_control(x, y, z, buttons);
+ break;
+
+ default:
+ if (error == USB_ERR_CANCELLED)
+ return;
+ usbd_xfer_set_stall(xfer);
+ break;
+ }
+ usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
+ usbd_transfer_submit(xfer);
+}
+
+static int
+vbmouse_hid_test(const void *d_ptr, uint16_t d_len)
+{
+ struct hid_data *hd;
+ struct hid_item hi;
+ int mdepth = 0, found = 0;
+
+ if (!(hd = hid_start_parse(d_ptr, d_len, 1 << hid_input)))
+ return 0;
+
+ while (hid_get_item(hd, &hi)) {
+ switch (hi.kind) {
+ case hid_collection:
+ if (mdepth != 0)
+ mdepth++;
+ else if (hi.collection == 1 &&
+ hi.usage == HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))
+ mdepth++;
+ break;
+ case hid_endcollection:
+ if (mdepth)
+ mdepth--;
+ break;
+ case hid_input:
+ if (!mdepth)
+ break;
+ if (hi.usage == HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X) &&
+ (hi.flags&(HIO_CONST|HIO_VARIABLE|HIO_RELATIVE))==HIO_VARIABLE)
+ found++;
+ if (hi.usage == HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y) &&
+ (hi.flags&(HIO_CONST|HIO_VARIABLE|HIO_RELATIVE))==HIO_VARIABLE)
+ found++;
+ break;
+ default:
+ break;
+ }
+ }
+ hid_end_parse(hd);
+ return found;
+}
+
+static void
+vbmouse_hid_parse(struct vbmouse_softc *sc, const void *buf, uint16_t len)
+{
+ struct hid_data *hd;
+ struct hid_item hi;
+ uint32_t flags;
+ uint8_t i;
+ int mdepth = 0;
+
+ if (!(hd = hid_start_parse(buf, len, 1 << hid_input)))
+ return;
+
+ while (hid_get_item(hd, &hi)) {
+ switch (hi.kind) {
+ case hid_collection:
+ if (mdepth)
+ mdepth++;
+ else if (hi.collection == 1 &&
+ hi.usage == HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE))
+ mdepth++;
+ break;
+ case hid_endcollection:
+ if (mdepth)
+ mdepth--;
+ break;
+ case hid_input:
+ if (!mdepth)
+ break;
+ if (hi.usage == HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X) &&
+ (hi.flags&(HIO_CONST|HIO_VARIABLE|HIO_RELATIVE))==HIO_VARIABLE){
+ sc->sc_flags |= VBMOUSE_FLAG_X_AXIS;
+ sc->sc_loc_x = hi.loc;
+ sc->sc_iid_x = hi.report_ID;
+ }
+ if (hi.usage == HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y) &&
+ (hi.flags&(HIO_CONST|HIO_VARIABLE|HIO_RELATIVE))==HIO_VARIABLE){
+ sc->sc_flags |= VBMOUSE_FLAG_Y_AXIS;
+ sc->sc_loc_y = hi.loc;
+ sc->sc_iid_y = hi.report_ID;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ hid_end_parse(hd);
+
+ /* try wheel as the Z activator */
+ if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_WHEEL),
+ hid_input, 0, &sc->sc_loc_z, &flags, &sc->sc_iid_z) ||
+ hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_TWHEEL),
+ hid_input, 0, &sc->sc_loc_z, &flags, &sc->sc_iid_z)) {
+ if (flags & HIO_VARIABLE)
+ sc->sc_flags |= VBMOUSE_FLAG_Z_AXIS;
+ }
+
+ /* find number of buttons */
+ for (i = 0; i < VBMOUSE_MAX_BUT; i++) {
+ if (!hid_locate(buf, len, HID_USAGE2(HUP_BUTTON, (i + 1)),
+ hid_input, 0, &sc->sc_loc_btn[i], NULL, &sc->sc_iid_btn[i]))
+ break;
+ }
+ sc->sc_nbuttons = i;
+
+ if (!sc->sc_flags)
+ return;
+
+ /* announce ourself */
+ device_printf(sc->sc_dev, "%d buttons and [%s%s%s] axes\n",
+ (sc->sc_nbuttons),
+ (sc->sc_flags & VBMOUSE_FLAG_X_AXIS) ? "X" : "",
+ (sc->sc_flags & VBMOUSE_FLAG_Y_AXIS) ? "Y" : "",
+ (sc->sc_flags & VBMOUSE_FLAG_Z_AXIS) ? "Z" : "");
+}
+
+static void
+vbmouse_control(int x, int y, int z, int buttons)
+{
+ struct vt_device *vd = main_vd;
+ struct vt_window *vw = vd->vd_curwindow;
+ struct vt_font *vf = vw->vw_font;
+ struct vt_buf *vb = &vw->vw_buf;
+ struct mouse_info mi;
+ term_pos_t size;
+ int changed = 0, len = 0;
+ static int lx = 0, ly = 0;
+
+ /* convert absolute values to fit screen size */
+ vt_termsize(vd, vf, &size);
+ vd->vd_mx = x / (32768 / (size.tp_col * vf->vf_width));
+ vd->vd_my = y / (32768 / (size.tp_row * vf->vf_height));
+
+ /* send info to sysmouse driver */
+ mi.operation = MOUSE_ACTION;
+ mi.u.data.buttons = buttons;
+ mi.u.data.x = (vd->vd_mx - lx); lx = vd->vd_mx;
+ mi.u.data.y = (vd->vd_my - ly); ly = vd->vd_my;
+ mi.u.data.z = z;
+ sysmouse_process_event(&mi);
+
+ /* if mousepointer is hidden, do not update framebuffer */
+ if (vw->vw_flags & VWF_MOUSE_HIDE)
+ return;
+
+ /* if !scrollmode && z != 0 -> enter scroll mode */
+ if (!(vb->vb_flags & VBF_SCROLL) && z) {
+ vtbuf_scroll_mode(vb, 1);
+ vw->vw_flags |= VWF_SCROLL;
+ return;
+ }
+
+ /* if scrollmode && z -> scroll up/down */
+ if ((vb->vb_flags & VBF_SCROLL) && z) {
+ vd_drawrect_t *drawrect = vd->vd_driver->vd_drawrect;
+
+ if (vthistory_seek(vb, z * -1, VHS_CUR))
+ vd->vd_flags |= VDF_INVALID;
+ if (drawrect) {
+ int pos, but, top;
+
+ pos = vb->vb_curroffset - vb->vb_roffset;
+ if (pos <= 0)
+ pos += vb->vb_history_size;
+ pos = ((pos * vd->vd_height) / vb->vb_history_size);
+ top = pos;
+ if (top >= vd->vd_height)
+ top = 0;
+ else
+ top = vd->vd_height - (pos + 16);
+ but = vd->vd_height - pos;
+ drawrect(vd, vd->vd_width - 10, top,
+ vd->vd_width - 5, but, 1, TC_WHITE);
+ }
+ vt_resume_flush_timer(vw, 0);
+ return;
+ }
+
+ /* if scrollmode && leftbutton down -> leave scroll mode */
+ if ((vb->vb_flags & VBF_SCROLL) && (buttons & MOUSE_BUTTON1DOWN)) {
+ vw->vw_flags &= ~VWF_SCROLL;
+ vtbuf_scroll_mode(vb, 0);
+ vthistory_seek(vb, 0, VHS_END);
+ vd->vd_flags |= VDF_INVALID;
+ vt_resume_flush_timer(vw, 0);
+ return;
+ }
+
+ /* update selection while active c&p mode*/
+ if (vd->vd_mstate & MOUSE_BUTTON1DOWN)
+ vtbuf_set_mark(&vw->vw_buf, VTB_MARK_MOVE,
+ vd->vd_mx / vf->vf_width, vd->vd_my / vf->vf_height);
+
+ /* update screen */
+ vt_resume_flush_timer(vw, 0);
+
+ /* if not in scroll mode and buttons pressed */
+ if (!(vb->vb_flags & VBF_SCROLL) && (changed = (buttons ^ vd->vd_mstate))) {
+
+ /* start/end of selection */
+ if (changed & MOUSE_BUTTON1DOWN) {
+ if (buttons & MOUSE_BUTTON1DOWN)
+ vtbuf_set_mark(&vw->vw_buf, VTB_MARK_START,
+ vd->vd_mx/vf->vf_width, vd->vd_my/vf->vf_height);
+ else {
+ if (vtbuf_set_mark(&vw->vw_buf, VTB_MARK_END,
+ vd->vd_mx/vf->vf_width,
+ vd->vd_my/vf->vf_height)) {
+ len = MIN(65535, abs(vtbuf_get_marked_len(&vw->vw_buf)));
+ if (len) {
+ VD_PASTEBUFLEN(vd) = len;
+ vtbuf_extract_marked(&vw->vw_buf, VD_PASTEBUF(vd),
+ VD_PASTEBUFSZ(vd));
+ }
+ }
+ }
+ }
+
+ /* update selection */
+ if (changed & MOUSE_BUTTON2DOWN) {
+ if (buttons & MOUSE_BUTTON2DOWN)
+ if (vtbuf_set_mark(&vw->vw_buf, VTB_MARK_EXTEND,
+ (vd->vd_mx / vf->vf_width) + 1,
+ vd->vd_my / vf->vf_height)) {
+ len = MIN(65535, abs(vtbuf_get_marked_len(&vw->vw_buf)));
+ if (len) {
+ VD_PASTEBUFLEN(vd) = len;
+ vtbuf_extract_marked(&vw->vw_buf, VD_PASTEBUF(vd),
+ VD_PASTEBUFSZ(vd));
+ }
+ }
+ }
+
+ /* paste selection */
+ if (changed & MOUSE_BUTTON3DOWN) {
+ if (buttons & MOUSE_BUTTON3DOWN) {
+ term_char_t *buf = VD_PASTEBUF(main_vd);
+ int i;
+
+ len = VD_PASTEBUFLEN(main_vd) / sizeof(term_char_t);
+ for (i = 0; i < len; i++) {
+ if (buf[i] == '\0')
+ continue;
+ terminal_input_char(main_vd->vd_curwindow->vw_terminal,
+ buf[i]);
+ }
+ }
+ }
+
+ /* save new state */
+ vd->vd_mstate = buttons;
+ }
+}
+
+static const STRUCT_USB_HOST_ID vbmouse_devs[] = {
+ {USB_IFACE_CLASS(UICLASS_HID), USB_IFACE_SUBCLASS(0),},
+};
+
+static devclass_t vbmouse_devclass;
+
+static device_method_t vbmouse_methods[] = {
+ DEVMETHOD(device_probe, vbmouse_probe),
+ DEVMETHOD(device_attach, vbmouse_attach),
+ DEVMETHOD(device_detach, vbmouse_detach),
+ DEVMETHOD_END
+};
+
+static driver_t vbmouse_driver = {
+ .name = "vbmouse",
+ .methods = vbmouse_methods,
+ .size = sizeof(struct vbmouse_softc),
+};
+
+DRIVER_MODULE(vbmouse, uhub, vbmouse_driver, vbmouse_devclass, NULL, 0);
+MODULE_DEPEND(vbmouse, usb, 1, 1, 1);
+MODULE_VERSION(vbmouse, 1);
+USB_PNP_HOST_INFO(vbmouse_devs);

File Metadata

Mime Type
text/plain
Expires
Thu, Apr 30, 4:30 AM (16 h, 59 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
32346145
Default Alt Text
D35508.diff (16 KB)

Event Timeline