diff --git a/sys/dev/usb/input/wsp.c b/sys/dev/usb/input/wsp.c index 694e0d9..21cc518 100644 --- a/sys/dev/usb/input/wsp.c +++ b/sys/dev/usb/input/wsp.c @@ -27,6 +27,8 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_evdev.h" + #include #include #include @@ -54,6 +56,11 @@ __FBSDID("$FreeBSD$"); #include +#ifdef EVDEV +#include +#include +#endif + #define WSP_DRIVER_NAME "wsp" #define WSP_BUFFER_MAX 1024 @@ -83,6 +90,7 @@ SYSCTL_INT(_hw_usb_wsp, OID_AUTO, debug, CTLFLAG_RWTUN, static struct wsp_tuning { int scale_factor; int z_factor; + int t_factor; int pressure_touch_threshold; int pressure_untouch_threshold; int pressure_tap_threshold; @@ -92,6 +100,7 @@ static struct wsp_tuning { { .scale_factor = 12, .z_factor = 5, + .t_factor = 5, .pressure_touch_threshold = 50, .pressure_untouch_threshold = 10, .pressure_tap_threshold = 120, @@ -113,6 +122,8 @@ SYSCTL_INT(_hw_usb_wsp, OID_AUTO, scale_factor, CTLFLAG_RWTUN, &wsp_tuning.scale_factor, 0, "movement scale factor"); SYSCTL_INT(_hw_usb_wsp, OID_AUTO, z_factor, CTLFLAG_RWTUN, &wsp_tuning.z_factor, 0, "Z-axis scale factor"); +SYSCTL_INT(_hw_usb_wsp, OID_AUTO, t_factor, CTLFLAG_RWTUN, + &wsp_tuning.t_factor, 0, "T-axis scale factor"); SYSCTL_INT(_hw_usb_wsp, OID_AUTO, pressure_touch_threshold, CTLFLAG_RWTUN, &wsp_tuning.pressure_touch_threshold, 0, "touch pressure threshold"); SYSCTL_INT(_hw_usb_wsp, OID_AUTO, pressure_untouch_threshold, CTLFLAG_RWTUN, @@ -541,7 +552,12 @@ struct wsp_softc { u_int sc_pollrate; mousestatus_t sc_status; u_int sc_state; + u_int sc_fflags; #define WSP_ENABLED 0x01 +#ifdef EVDEV + int sc_evflags; +#define WSP_EVDEV_OPENED 1 +#endif struct tp_finger *index[MAX_FINGERS]; /* finger index data */ int16_t pos_x[MAX_FINGERS]; /* position array */ @@ -559,9 +575,12 @@ struct wsp_softc { int dz_count; #define WSP_DZ_MAX_COUNT 32 int dt_sum; /* T-axis cumulative movement */ + int dt_count; +#define WSP_DT_MAX_COUNT 32 int rdx; /* x axis remainder of divide by scale_factor */ int rdy; /* y axis remainder of divide by scale_factor */ int rdz; /* z axis remainder of divide by scale_factor */ + int rdt; /* t axis remainder of divide by scale_factor */ int tp_datalen; uint8_t o_ntouch; /* old touch finger status */ uint8_t finger; /* 0 or 1 *, check which finger moving */ @@ -572,11 +591,15 @@ struct wsp_softc { #define MAX_DISTANCE 2500 /* the max allowed distance */ uint8_t ibtn; /* button status in tapping */ uint8_t ntaps; /* finger status in tapping */ - uint8_t scr_mode; /* scroll status in movement */ -#define WSP_SCR_NONE 0 -#define WSP_SCR_VER 1 -#define WSP_SCR_HOR 2 + uint8_t scroll_mode; /* scroll status in movement */ +#define WSP_SCROLL_NONE 0 +#define WSP_SCROLL_VER 1 +#define WSP_SCROLL_HOR 2 uint8_t tp_data[WSP_BUFFER_MAX] __aligned(4); /* trackpad transferred data */ + +#ifdef EVDEV + struct evdev_dev *sc_evdev; +#endif }; /* @@ -588,6 +611,14 @@ static usb_fifo_open_t wsp_open; static usb_fifo_close_t wsp_close; static usb_fifo_ioctl_t wsp_ioctl; +static void wsp_start_rx(struct wsp_softc *sc); +static void wsp_stop_rx(struct wsp_softc *sc); + +#ifdef EVDEV +static evdev_open_t wsp_ev_open; +static evdev_close_t wsp_ev_close; +#endif + static struct usb_fifo_methods wsp_fifo_methods = { .f_open = &wsp_open, .f_close = &wsp_close, @@ -597,13 +628,20 @@ static struct usb_fifo_methods wsp_fifo_methods = { .basename[0] = WSP_DRIVER_NAME, }; +#ifdef EVDEV +static struct evdev_methods wsp_evdev_methods = { + .ev_open = &wsp_ev_open, + .ev_close = &wsp_ev_close, +}; +#endif + /* device initialization and shutdown */ static int wsp_enable(struct wsp_softc *sc); static void wsp_disable(struct wsp_softc *sc); /* updating fifo */ static void wsp_reset_buf(struct wsp_softc *sc); -static void wsp_add_to_queue(struct wsp_softc *, int, int, int, uint32_t); +static void wsp_add_to_queue(struct wsp_softc *, int, int, int, int, uint32_t); /* Device methods. */ static device_probe_t wsp_probe; @@ -799,7 +837,29 @@ wsp_attach(device_t dev) sc->sc_mode.syncmask[1] = MOUSE_MSC_SYNC; sc->sc_touch = WSP_UNTOUCH; - sc->scr_mode = WSP_SCR_NONE; + sc->scroll_mode = WSP_SCROLL_NONE; + +#ifdef EVDEV + sc->sc_evdev = evdev_alloc(); + evdev_set_name(sc->sc_evdev, device_get_desc(dev)); + evdev_set_serial(sc->sc_evdev, "0"); + evdev_set_methods(sc->sc_evdev, sc, &wsp_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); + evdev_support_rel(sc->sc_evdev, REL_X); + evdev_support_rel(sc->sc_evdev, REL_Y); + evdev_support_rel(sc->sc_evdev, REL_WHEEL); + evdev_support_rel(sc->sc_evdev, REL_HWHEEL); + + for(int i = 0; i < sc->sc_hw.buttons; i++) + evdev_support_key(sc->sc_evdev, BTN_MOUSE + i); + + err = evdev_register(dev, sc->sc_evdev); + if (err) + goto detach; +#endif return (0); @@ -822,6 +882,11 @@ wsp_detach(device_t dev) usb_fifo_detach(&sc->sc_fifo); +#ifdef EVDEV + evdev_unregister(dev, sc->sc_evdev); + evdev_free(sc->sc_evdev); +#endif + usbd_transfer_unsetup(sc->sc_xfer, WSP_N_TRANSFER); mtx_destroy(&sc->sc_mutex); @@ -842,10 +907,12 @@ wsp_intr_callback(struct usb_xfer *xfer, usb_error_t error) int ibt = 0; /* button status */ int dx = 0; int dy = 0; - int dz = 0; + int dz = 0; + int dt = 0; int rdx = 0; int rdy = 0; int rdz = 0; + int rdt = 0; int len; int i; @@ -854,6 +921,9 @@ wsp_intr_callback(struct usb_xfer *xfer, usb_error_t error) if (sc->dz_count == 0) sc->dz_count = WSP_DZ_MAX_COUNT; + if (sc->dt_count == 0) + sc->dt_count = WSP_DT_MAX_COUNT; + usbd_xfer_status(xfer, &len, NULL, NULL, NULL); switch (USB_GET_STATE(xfer)) { @@ -967,7 +1037,7 @@ wsp_intr_callback(struct usb_xfer *xfer, usb_error_t error) switch (sc->ntaps) { case 1: if (!(params->caps & HAS_INTEGRATED_BUTTON)) { - wsp_add_to_queue(sc, 0, 0, 0, MOUSE_BUTTON1DOWN); + wsp_add_to_queue(sc, 0, 0, 0, 0, MOUSE_BUTTON1DOWN); DPRINTFN(WSP_LLEVEL_INFO, "LEFT CLICK!\n"); } break; @@ -976,21 +1046,23 @@ wsp_intr_callback(struct usb_xfer *xfer, usb_error_t error) sc->dx_sum, sc->dy_sum); if (sc->distance < MAX_DISTANCE && abs(sc->dx_sum) < 5 && abs(sc->dy_sum) < 5) { - wsp_add_to_queue(sc, 0, 0, 0, MOUSE_BUTTON3DOWN); + wsp_add_to_queue(sc, 0, 0, 0, 0, MOUSE_BUTTON3DOWN); DPRINTFN(WSP_LLEVEL_INFO, "RIGHT CLICK!\n"); } break; case 3: - wsp_add_to_queue(sc, 0, 0, 0, MOUSE_BUTTON2DOWN); + wsp_add_to_queue(sc, 0, 0, 0, 0, MOUSE_BUTTON2DOWN); break; default: /* we don't handle taps of more than three fingers */ break; } - wsp_add_to_queue(sc, 0, 0, 0, 0); /* button release */ + wsp_add_to_queue(sc, 0, 0, 0, 0, 0); /* button release */ } + +#if 0 // Replace back/forward with horizontal scroll if ((sc->dt_sum / tun.scr_hor_threshold) != 0 && - sc->ntaps == 2 && sc->scr_mode == WSP_SCR_HOR) { + sc->ntaps == 2 && sc->scroll_mode == WSP_SCROLL_HOR) { /* * translate T-axis into button presses @@ -1001,20 +1073,23 @@ wsp_intr_callback(struct usb_xfer *xfer, usb_error_t error) else if (sc->dt_sum < 0) wsp_add_to_queue(sc, 0, 0, 0, 1UL << 4); } +#endif sc->dz_count = WSP_DZ_MAX_COUNT; - sc->dz_sum = 0; + sc->dt_count = WSP_DT_MAX_COUNT; sc->intr_count = 0; sc->ibtn = 0; sc->ntaps = 0; sc->finger = 0; sc->distance = 0; - sc->dt_sum = 0; sc->dx_sum = 0; sc->dy_sum = 0; + sc->dz_sum = 0; + sc->dt_sum = 0; sc->rdx = 0; sc->rdy = 0; sc->rdz = 0; - sc->scr_mode = WSP_SCR_NONE; + sc->rdt = 0; + sc->scroll_mode = WSP_SCROLL_NONE; } else if (sc->index[0]->touch_major >= tun.pressure_touch_threshold && sc->sc_touch == WSP_UNTOUCH) { /* ignore first touch */ sc->sc_touch = WSP_FIRST_TOUCH; @@ -1079,6 +1154,7 @@ wsp_intr_callback(struct usb_xfer *xfer, usb_error_t error) DPRINTFN(WSP_LLEVEL_INFO, "dx=%5d, dy=%5d, mov=%5d\n", dx, dy, sc->finger); } + if (sc->dz_count--) { rdz = (dy + sc->rdz) % tun.scale_factor; sc->dz_sum -= (dy + sc->rdz) / tun.scale_factor; @@ -1086,6 +1162,14 @@ wsp_intr_callback(struct usb_xfer *xfer, usb_error_t error) } if ((sc->dz_sum / tun.z_factor) != 0) sc->dz_count = 0; + + if (sc->dt_count--) { + rdt = (dx + sc->rdt) % tun.scale_factor; + sc->dt_sum += (dx + sc->rdt) / tun.scale_factor; + sc->rdt = rdt; + } + if ((sc->dt_sum / tun.t_factor) != 0) + sc->dt_count = 0; } rdx = (dx + sc->rdx) % tun.scale_factor; dx = (dx + sc->rdx) / tun.scale_factor; @@ -1099,45 +1183,49 @@ wsp_intr_callback(struct usb_xfer *xfer, usb_error_t error) sc->dy_sum += dy; if (ntouch == 2 && sc->sc_status.button == 0) { - if (sc->scr_mode == WSP_SCR_NONE && + + if (sc->scroll_mode == WSP_SCROLL_NONE && abs(sc->dx_sum) + abs(sc->dy_sum) > tun.scr_hor_threshold) - sc->scr_mode = abs(sc->dx_sum) > - abs(sc->dy_sum) * 2 ? WSP_SCR_HOR : WSP_SCR_VER; - DPRINTFN(WSP_LLEVEL_INFO, "scr_mode=%5d, count=%d, dx_sum=%d, dy_sum=%d\n", - sc->scr_mode, sc->intr_count, sc->dx_sum, sc->dy_sum); - if (sc->scr_mode == WSP_SCR_HOR) - sc->dt_sum += dx; - else - sc->dt_sum = 0; + sc->scroll_mode = abs(sc->dx_sum) > + abs(sc->dy_sum) * 2 ? WSP_SCROLL_HOR : WSP_SCROLL_VER; + + DPRINTFN(WSP_LLEVEL_INFO, "scroll_mode=%5d, count=%d, dx_sum=%d, dy_sum=%d\n", + sc->scroll_mode, sc->intr_count, sc->dx_sum, sc->dy_sum); dx = dy = 0; - if (sc->dz_count == 0) + if (sc->dz_count == 0) { dz = sc->dz_sum / tun.z_factor; - if (sc->scr_mode == WSP_SCR_HOR || - abs(sc->pos_x[0] - sc->pos_x[1]) > MAX_DISTANCE || - abs(sc->pos_y[0] - sc->pos_y[1]) > MAX_DISTANCE) - dz = 0; + } + if (sc->dt_count == 0) { + dt = sc->dt_sum / tun.t_factor; + } } if (ntouch == 3) - dx = dy = dz = 0; + dx = dy = dz = dt = 0; if (sc->intr_count < WSP_TAP_MAX_COUNT && - abs(dx) < 3 && abs(dy) < 3 && abs(dz) < 3) - dx = dy = dz = 0; + abs(dx) < 3 && abs(dy) < 3 && abs(dz) < 3 && abs(dt) < 3) + dx = dy = dz = dt = 0; else sc->intr_count = WSP_TAP_MAX_COUNT; - if (dx || dy || dz) + if (dx || dy || dz || dt) sc->sc_status.flags |= MOUSE_POSCHANGED; - DPRINTFN(WSP_LLEVEL_INFO, "dx=%5d, dy=%5d, dz=%5d, sc_touch=%x, btn=%x\n", - dx, dy, dz, sc->sc_touch, sc->sc_status.button); + DPRINTFN(WSP_LLEVEL_INFO, "dx=%5d, dy=%5d, dz=%5d, dt=%5d,sc_touch=%x, btn=%x\n", + dx, dy, dz, dt, sc->sc_touch, sc->sc_status.button); sc->sc_status.dx += dx; sc->sc_status.dy += dy; sc->sc_status.dz += dz; + /* No support for dt this (yet) */ + /* sc->sc_status.dt += dt; */ - wsp_add_to_queue(sc, dx, -dy, dz, sc->sc_status.button); + wsp_add_to_queue(sc, dx, -dy, dz, dt, sc->sc_status.button); if (sc->dz_count == 0) { sc->dz_sum = 0; sc->rdz = 0; } + if (sc->dt_count == 0) { + sc->dt_sum = 0; + sc->rdt = 0; + } } sc->pre_pos_x = sc->pos_x[0]; @@ -1152,14 +1240,17 @@ wsp_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, - sc->tp_datalen); - 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, sc->tp_datalen); + usbd_transfer_submit(xfer); break; - default: /* Error */ if (error != USB_ERR_CANCELLED) { /* try clear stall first */ @@ -1172,7 +1263,7 @@ tr_setup: static void wsp_add_to_queue(struct wsp_softc *sc, int dx, int dy, int dz, - uint32_t buttons_in) + int dt, uint32_t buttons_in) { uint32_t buttons_out; uint8_t buf[8]; @@ -1183,6 +1274,8 @@ wsp_add_to_queue(struct wsp_softc *sc, int dx, int dy, int dz, dy = imax(dy, -256); dz = imin(dz, 126); dz = imax(dz, -128); + dt = imin(dt, 126); + dt = imax(dt, -128); buttons_out = MOUSE_MSC_BUTTONS; if (buttons_in & MOUSE_BUTTON1DOWN) @@ -1207,7 +1300,63 @@ wsp_add_to_queue(struct wsp_softc *sc, int dx, int dy, int dz, } usb_fifo_put_data_linear(sc->sc_fifo.fp[USB_FIFO_RX], buf, sc->sc_mode.packetsize, 1); + +#ifdef EVDEV + /* Push evdev event */ + if (dx != 0 || dy != 0) { + evdev_push_event(sc->sc_evdev, EV_REL, REL_X, dx); + evdev_push_event(sc->sc_evdev, EV_REL, REL_Y, -dy); + } + if (dz != 0) + evdev_push_event(sc->sc_evdev, EV_REL, REL_WHEEL, -dz); + if (dt != 0) { + evdev_push_event(sc->sc_evdev, EV_REL, REL_HWHEEL, dt); + } + evdev_push_mouse_btn(sc->sc_evdev, + (buttons_in & ~MOUSE_STDBUTTONS) | + (buttons_in & (1 << 2) ? MOUSE_BUTTON1DOWN : 0) | + (buttons_in & (1 << 1) ? MOUSE_BUTTON2DOWN : 0) | + (buttons_in & (1 << 0) ? MOUSE_BUTTON3DOWN : 0)); + evdev_sync(sc->sc_evdev); +#endif + +} + +#ifdef EVDEV +static int +wsp_ev_open(struct evdev_dev *evdev, void *ev_softc) +{ + struct wsp_softc *sc = (struct wsp_softc *)ev_softc; + + mtx_lock(&sc->sc_mutex); + + sc->sc_evflags = WSP_EVDEV_OPENED; + + if (sc->sc_fflags == 0) { + /* wsp_reset(sc); */ + wsp_start_rx(sc); + } + + mtx_unlock(&sc->sc_mutex); + + return (0); +} + +static void +wsp_ev_close(struct evdev_dev *evdev, void *ev_softc) +{ + struct wsp_softc *sc = (struct wsp_softc *)ev_softc; + + mtx_lock(&sc->sc_mutex); + + sc->sc_evflags = 0; + + if (sc->sc_fflags == 0) + wsp_stop_rx(sc); + + mtx_unlock(&sc->sc_mutex); } +#endif static void wsp_reset_buf(struct wsp_softc *sc) @@ -1217,9 +1366,8 @@ wsp_reset_buf(struct wsp_softc *sc) } static void -wsp_start_read(struct usb_fifo *fifo) +wsp_start_rx(struct wsp_softc *sc) { - struct wsp_softc *sc = usb_fifo_softc(fifo); int rate; /* Check if we should override the default polling interval */ @@ -1240,13 +1388,25 @@ wsp_start_read(struct usb_fifo *fifo) } static void -wsp_stop_read(struct usb_fifo *fifo) +wsp_start_read(struct usb_fifo *fifo) { struct wsp_softc *sc = usb_fifo_softc(fifo); + wsp_start_rx(sc); +} +static void +wsp_stop_rx(struct wsp_softc *sc) +{ usbd_transfer_stop(sc->sc_xfer[WSP_INTR_DT]); } +static void +wsp_stop_read(struct usb_fifo *fifo) +{ + struct wsp_softc *sc = usb_fifo_softc(fifo); + wsp_stop_rx(sc); +} + static int wsp_open(struct usb_fifo *fifo, int fflags) @@ -1255,6 +1415,7 @@ wsp_open(struct usb_fifo *fifo, int fflags) if (fflags & FREAD) { struct wsp_softc *sc = usb_fifo_softc(fifo); + sc->sc_fflags = fflags; int rc; if (sc->sc_state & WSP_ENABLED)