Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F154668560
D35508.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
16 KB
Referenced Files
None
Subscribers
None
D35508.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D35508: Mouse support for textmode VirtualBox
Attached
Detach File
Event Timeline
Log In to Comment