Add evdev support to ums(4)
event generation is disabled by default in favour of sysmouse. This behavoiur is controlled by kern.evdev.rcpt_mask sysctl, bit 2 should be set to give priority to hw over sysmouse Submitted by: Vladimir Kondratiev <wulf@cicgroup.ru> Reviewed by: hans Differential Revision: https://reviews.freebsd.org/D7863
This commit is contained in:
parent
057f976d3b
commit
c3af259a20
@ -35,6 +35,8 @@ __FBSDID("$FreeBSD$");
|
||||
* HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
|
||||
*/
|
||||
|
||||
#include "opt_evdev.h"
|
||||
|
||||
#include <sys/stdint.h>
|
||||
#include <sys/stddef.h>
|
||||
#include <sys/param.h>
|
||||
@ -68,6 +70,11 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
#include <dev/usb/quirk/usb_quirk.h>
|
||||
|
||||
#ifdef EVDEV
|
||||
#include <dev/evdev/input.h>
|
||||
#include <dev/evdev/evdev.h>
|
||||
#endif
|
||||
|
||||
#include <sys/ioccom.h>
|
||||
#include <sys/filio.h>
|
||||
#include <sys/tty.h>
|
||||
@ -135,10 +142,18 @@ struct ums_softc {
|
||||
|
||||
int sc_pollrate;
|
||||
int sc_fflags;
|
||||
#ifdef EVDEV
|
||||
int sc_evflags;
|
||||
#define UMS_EVDEV_OPENED 1
|
||||
#endif
|
||||
|
||||
uint8_t sc_buttons;
|
||||
uint8_t sc_iid;
|
||||
uint8_t sc_temp[64];
|
||||
|
||||
#ifdef EVDEV
|
||||
struct evdev_dev *sc_evdev;
|
||||
#endif
|
||||
};
|
||||
|
||||
static void ums_put_queue_timeout(void *__sc);
|
||||
@ -149,25 +164,39 @@ static device_probe_t ums_probe;
|
||||
static device_attach_t ums_attach;
|
||||
static device_detach_t ums_detach;
|
||||
|
||||
static usb_fifo_cmd_t ums_start_read;
|
||||
static usb_fifo_cmd_t ums_stop_read;
|
||||
static usb_fifo_open_t ums_open;
|
||||
static usb_fifo_close_t ums_close;
|
||||
static usb_fifo_ioctl_t ums_ioctl;
|
||||
static usb_fifo_cmd_t ums_fifo_start_read;
|
||||
static usb_fifo_cmd_t ums_fifo_stop_read;
|
||||
static usb_fifo_open_t ums_fifo_open;
|
||||
static usb_fifo_close_t ums_fifo_close;
|
||||
static usb_fifo_ioctl_t ums_fifo_ioctl;
|
||||
|
||||
#ifdef EVDEV
|
||||
static evdev_open_t ums_ev_open;
|
||||
static evdev_close_t ums_ev_close;
|
||||
#endif
|
||||
|
||||
static void ums_start_rx(struct ums_softc *);
|
||||
static void ums_stop_rx(struct ums_softc *);
|
||||
static void ums_put_queue(struct ums_softc *, int32_t, int32_t,
|
||||
int32_t, int32_t, int32_t);
|
||||
static int ums_sysctl_handler_parseinfo(SYSCTL_HANDLER_ARGS);
|
||||
|
||||
static struct usb_fifo_methods ums_fifo_methods = {
|
||||
.f_open = &ums_open,
|
||||
.f_close = &ums_close,
|
||||
.f_ioctl = &ums_ioctl,
|
||||
.f_start_read = &ums_start_read,
|
||||
.f_stop_read = &ums_stop_read,
|
||||
.f_open = &ums_fifo_open,
|
||||
.f_close = &ums_fifo_close,
|
||||
.f_ioctl = &ums_fifo_ioctl,
|
||||
.f_start_read = &ums_fifo_start_read,
|
||||
.f_stop_read = &ums_fifo_stop_read,
|
||||
.basename[0] = "ums",
|
||||
};
|
||||
|
||||
#ifdef EVDEV
|
||||
static struct evdev_methods ums_evdev_methods = {
|
||||
.ev_open = &ums_ev_open,
|
||||
.ev_close = &ums_ev_close,
|
||||
};
|
||||
#endif
|
||||
|
||||
static void
|
||||
ums_put_queue_timeout(void *__sc)
|
||||
{
|
||||
@ -327,11 +356,17 @@ ums_intr_callback(struct usb_xfer *xfer, usb_error_t error)
|
||||
case USB_ST_SETUP:
|
||||
tr_setup:
|
||||
/* check if we can put more data into the FIFO */
|
||||
if (usb_fifo_put_bytes_max(
|
||||
sc->sc_fifo.fp[USB_FIFO_RX]) != 0) {
|
||||
usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
|
||||
usbd_transfer_submit(xfer);
|
||||
if (usb_fifo_put_bytes_max(sc->sc_fifo.fp[USB_FIFO_RX]) == 0) {
|
||||
#ifdef EVDEV
|
||||
if (sc->sc_evflags == 0)
|
||||
break;
|
||||
#else
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
|
||||
usbd_transfer_submit(xfer);
|
||||
break;
|
||||
|
||||
default: /* Error */
|
||||
@ -655,6 +690,41 @@ ums_attach(device_t dev)
|
||||
if (err)
|
||||
goto detach;
|
||||
|
||||
#ifdef EVDEV
|
||||
sc->sc_evdev = evdev_alloc();
|
||||
evdev_set_name(sc->sc_evdev, device_get_desc(dev));
|
||||
evdev_set_phys(sc->sc_evdev, device_get_nameunit(dev));
|
||||
evdev_set_id(sc->sc_evdev, BUS_USB, uaa->info.idVendor,
|
||||
uaa->info.idProduct, 0);
|
||||
evdev_set_serial(sc->sc_evdev, usb_get_serial(uaa->device));
|
||||
evdev_set_methods(sc->sc_evdev, sc, &ums_evdev_methods);
|
||||
evdev_support_prop(sc->sc_evdev, INPUT_PROP_POINTER);
|
||||
evdev_support_event(sc->sc_evdev, EV_SYN);
|
||||
evdev_support_event(sc->sc_evdev, EV_REL);
|
||||
evdev_support_event(sc->sc_evdev, EV_KEY);
|
||||
|
||||
info = &sc->sc_info[0];
|
||||
|
||||
if (info->sc_flags & UMS_FLAG_X_AXIS)
|
||||
evdev_support_rel(sc->sc_evdev, REL_X);
|
||||
|
||||
if (info->sc_flags & UMS_FLAG_Y_AXIS)
|
||||
evdev_support_rel(sc->sc_evdev, REL_Y);
|
||||
|
||||
if (info->sc_flags & UMS_FLAG_Z_AXIS)
|
||||
evdev_support_rel(sc->sc_evdev, REL_WHEEL);
|
||||
|
||||
if (info->sc_flags & UMS_FLAG_T_AXIS)
|
||||
evdev_support_rel(sc->sc_evdev, REL_HWHEEL);
|
||||
|
||||
for (i = 0; i < info->sc_buttons; i++)
|
||||
evdev_support_key(sc->sc_evdev, BTN_MOUSE + i);
|
||||
|
||||
err = evdev_register(sc->sc_evdev);
|
||||
if (err)
|
||||
goto detach;
|
||||
#endif
|
||||
|
||||
SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
|
||||
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
|
||||
OID_AUTO, "parseinfo", CTLTYPE_STRING|CTLFLAG_RD,
|
||||
@ -680,6 +750,10 @@ ums_detach(device_t self)
|
||||
|
||||
usb_fifo_detach(&sc->sc_fifo);
|
||||
|
||||
#ifdef EVDEV
|
||||
evdev_free(sc->sc_evdev);
|
||||
#endif
|
||||
|
||||
usbd_transfer_unsetup(sc->sc_xfer, UMS_N_TRANSFER);
|
||||
|
||||
usb_callout_drain(&sc->sc_callout);
|
||||
@ -690,9 +764,44 @@ ums_detach(device_t self)
|
||||
}
|
||||
|
||||
static void
|
||||
ums_start_read(struct usb_fifo *fifo)
|
||||
ums_reset(struct ums_softc *sc)
|
||||
{
|
||||
|
||||
/* reset all USB mouse parameters */
|
||||
|
||||
if (sc->sc_buttons > MOUSE_MSC_MAXBUTTON)
|
||||
sc->sc_hw.buttons = MOUSE_MSC_MAXBUTTON;
|
||||
else
|
||||
sc->sc_hw.buttons = sc->sc_buttons;
|
||||
|
||||
sc->sc_hw.iftype = MOUSE_IF_USB;
|
||||
sc->sc_hw.type = MOUSE_MOUSE;
|
||||
sc->sc_hw.model = MOUSE_MODEL_GENERIC;
|
||||
sc->sc_hw.hwid = 0;
|
||||
|
||||
sc->sc_mode.protocol = MOUSE_PROTO_MSC;
|
||||
sc->sc_mode.rate = -1;
|
||||
sc->sc_mode.resolution = MOUSE_RES_UNKNOWN;
|
||||
sc->sc_mode.accelfactor = 0;
|
||||
sc->sc_mode.level = 0;
|
||||
sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE;
|
||||
sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK;
|
||||
sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC;
|
||||
|
||||
/* reset status */
|
||||
|
||||
sc->sc_status.flags = 0;
|
||||
sc->sc_status.button = 0;
|
||||
sc->sc_status.obutton = 0;
|
||||
sc->sc_status.dx = 0;
|
||||
sc->sc_status.dy = 0;
|
||||
sc->sc_status.dz = 0;
|
||||
/* sc->sc_status.dt = 0; */
|
||||
}
|
||||
|
||||
static void
|
||||
ums_start_rx(struct ums_softc *sc)
|
||||
{
|
||||
struct ums_softc *sc = usb_fifo_softc(fifo);
|
||||
int rate;
|
||||
|
||||
/* Check if we should override the default polling interval */
|
||||
@ -715,12 +824,26 @@ ums_start_read(struct usb_fifo *fifo)
|
||||
}
|
||||
|
||||
static void
|
||||
ums_stop_read(struct usb_fifo *fifo)
|
||||
ums_stop_rx(struct ums_softc *sc)
|
||||
{
|
||||
usbd_transfer_stop(sc->sc_xfer[UMS_INTR_DT]);
|
||||
usb_callout_stop(&sc->sc_callout);
|
||||
}
|
||||
|
||||
static void
|
||||
ums_fifo_start_read(struct usb_fifo *fifo)
|
||||
{
|
||||
struct ums_softc *sc = usb_fifo_softc(fifo);
|
||||
|
||||
usbd_transfer_stop(sc->sc_xfer[UMS_INTR_DT]);
|
||||
usb_callout_stop(&sc->sc_callout);
|
||||
ums_start_rx(sc);
|
||||
}
|
||||
|
||||
static void
|
||||
ums_fifo_stop_read(struct usb_fifo *fifo)
|
||||
{
|
||||
struct ums_softc *sc = usb_fifo_softc(fifo);
|
||||
|
||||
ums_stop_rx(sc);
|
||||
}
|
||||
|
||||
|
||||
@ -769,6 +892,21 @@ ums_put_queue(struct ums_softc *sc, int32_t dx, int32_t dy,
|
||||
usb_fifo_put_data_linear(sc->sc_fifo.fp[USB_FIFO_RX], buf,
|
||||
sc->sc_mode.packetsize, 1);
|
||||
|
||||
#ifdef EVDEV
|
||||
if (evdev_rcpt_mask & EVDEV_RCPT_HW_MOUSE) {
|
||||
/* Push evdev event */
|
||||
evdev_push_event(sc->sc_evdev, EV_REL, REL_X, dx);
|
||||
evdev_push_event(sc->sc_evdev, EV_REL, REL_Y, -dy);
|
||||
evdev_push_event(sc->sc_evdev, EV_REL, REL_WHEEL, -dz);
|
||||
evdev_push_event(sc->sc_evdev, EV_REL, REL_HWHEEL, dt);
|
||||
evdev_push_mouse_btn(sc->sc_evdev,
|
||||
(buttons & ~MOUSE_STDBUTTONS) |
|
||||
(buttons & (1 << 2) ? MOUSE_BUTTON1DOWN : 0) |
|
||||
(buttons & (1 << 1) ? MOUSE_BUTTON2DOWN : 0) |
|
||||
(buttons & (1 << 0) ? MOUSE_BUTTON3DOWN : 0));
|
||||
evdev_sync(sc->sc_evdev);
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
DPRINTF("Buffer full, discarded packet\n");
|
||||
}
|
||||
@ -781,8 +919,44 @@ ums_reset_buf(struct ums_softc *sc)
|
||||
usb_fifo_reset(sc->sc_fifo.fp[USB_FIFO_RX]);
|
||||
}
|
||||
|
||||
#ifdef EVDEV
|
||||
static int
|
||||
ums_open(struct usb_fifo *fifo, int fflags)
|
||||
ums_ev_open(struct evdev_dev *evdev, void *ev_softc)
|
||||
{
|
||||
struct ums_softc *sc = (struct ums_softc *)ev_softc;
|
||||
|
||||
mtx_lock(&sc->sc_mtx);
|
||||
|
||||
sc->sc_evflags = UMS_EVDEV_OPENED;
|
||||
|
||||
if (sc->sc_fflags == 0) {
|
||||
ums_reset(sc);
|
||||
ums_start_rx(sc);
|
||||
}
|
||||
|
||||
mtx_unlock(&sc->sc_mtx);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
ums_ev_close(struct evdev_dev *evdev, void *ev_softc)
|
||||
{
|
||||
struct ums_softc *sc = (struct ums_softc *)ev_softc;
|
||||
|
||||
mtx_lock(&sc->sc_mtx);
|
||||
|
||||
sc->sc_evflags = 0;
|
||||
|
||||
if (sc->sc_fflags == 0)
|
||||
ums_stop_rx(sc);
|
||||
|
||||
mtx_unlock(&sc->sc_mtx);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int
|
||||
ums_fifo_open(struct usb_fifo *fifo, int fflags)
|
||||
{
|
||||
struct ums_softc *sc = usb_fifo_softc(fifo);
|
||||
|
||||
@ -793,39 +967,13 @@ ums_open(struct usb_fifo *fifo, int fflags)
|
||||
return (EBUSY);
|
||||
|
||||
/* check for first open */
|
||||
if (sc->sc_fflags == 0) {
|
||||
|
||||
/* reset all USB mouse parameters */
|
||||
|
||||
if (sc->sc_buttons > MOUSE_MSC_MAXBUTTON)
|
||||
sc->sc_hw.buttons = MOUSE_MSC_MAXBUTTON;
|
||||
else
|
||||
sc->sc_hw.buttons = sc->sc_buttons;
|
||||
|
||||
sc->sc_hw.iftype = MOUSE_IF_USB;
|
||||
sc->sc_hw.type = MOUSE_MOUSE;
|
||||
sc->sc_hw.model = MOUSE_MODEL_GENERIC;
|
||||
sc->sc_hw.hwid = 0;
|
||||
|
||||
sc->sc_mode.protocol = MOUSE_PROTO_MSC;
|
||||
sc->sc_mode.rate = -1;
|
||||
sc->sc_mode.resolution = MOUSE_RES_UNKNOWN;
|
||||
sc->sc_mode.accelfactor = 0;
|
||||
sc->sc_mode.level = 0;
|
||||
sc->sc_mode.packetsize = MOUSE_MSC_PACKETSIZE;
|
||||
sc->sc_mode.syncmask[0] = MOUSE_MSC_SYNCMASK;
|
||||
sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC;
|
||||
|
||||
/* reset status */
|
||||
|
||||
sc->sc_status.flags = 0;
|
||||
sc->sc_status.button = 0;
|
||||
sc->sc_status.obutton = 0;
|
||||
sc->sc_status.dx = 0;
|
||||
sc->sc_status.dy = 0;
|
||||
sc->sc_status.dz = 0;
|
||||
/* sc->sc_status.dt = 0; */
|
||||
}
|
||||
#ifdef EVDEV
|
||||
if (sc->sc_fflags == 0 && sc->sc_evflags == 0)
|
||||
ums_reset(sc);
|
||||
#else
|
||||
if (sc->sc_fflags == 0)
|
||||
ums_reset(sc);
|
||||
#endif
|
||||
|
||||
if (fflags & FREAD) {
|
||||
/* allocate RX buffer */
|
||||
@ -840,7 +988,7 @@ ums_open(struct usb_fifo *fifo, int fflags)
|
||||
}
|
||||
|
||||
static void
|
||||
ums_close(struct usb_fifo *fifo, int fflags)
|
||||
ums_fifo_close(struct usb_fifo *fifo, int fflags)
|
||||
{
|
||||
struct ums_softc *sc = usb_fifo_softc(fifo);
|
||||
|
||||
@ -853,7 +1001,7 @@ ums_close(struct usb_fifo *fifo, int fflags)
|
||||
}
|
||||
|
||||
static int
|
||||
ums_ioctl(struct usb_fifo *fifo, u_long cmd, void *addr, int fflags)
|
||||
ums_fifo_ioctl(struct usb_fifo *fifo, u_long cmd, void *addr, int fflags)
|
||||
{
|
||||
struct ums_softc *sc = usb_fifo_softc(fifo);
|
||||
mousemode_t mode;
|
||||
|
@ -30,7 +30,7 @@ S= ${.CURDIR}/../../..
|
||||
.PATH: $S/dev/usb/input
|
||||
|
||||
KMOD= ums
|
||||
SRCS= opt_bus.h opt_usb.h device_if.h bus_if.h usb_if.h vnode_if.h usbdevs.h \
|
||||
ums.c
|
||||
SRCS= opt_bus.h opt_evdev.h opt_usb.h device_if.h bus_if.h usb_if.h \
|
||||
vnode_if.h usbdevs.h ums.c
|
||||
|
||||
.include <bsd.kmod.mk>
|
||||
|
Loading…
Reference in New Issue
Block a user