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:
Oleksandr Tymoshenko 2016-09-21 18:52:03 +00:00
parent 057f976d3b
commit c3af259a20
2 changed files with 205 additions and 57 deletions

View File

@ -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;

View File

@ -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>