[PATCH 2/2] input: bcm5974-0.61: New default mouse driver mode
From: Henrik Rydberg
Date: Mon Sep 01 2008 - 16:08:49 EST
Currently, the Apple bcm5974 driver only mimics a synaptics touchpad, not a mouse.
This creates unnecessary complications on systems where the synaptics driver is absent
or not configured, such as in a completely new system, or a text console. This patch
provides a default compatibility configuration, which works as a multi-button mouse,
implemented using rudimentary multi-finger options. It yields the following benefits:
* A default Xorg configuration will pick up the mouse input interface, resulting in a
functional mouse pointer out-of-the-box on many systems.
* Two-finger scroll emulates a mouse wheel.
* Three-finger swipe emulates a horizontal mouse wheel.
* Multi-finger clicks emulate the middle and right mouse buttons.
* The mouse driver also works with gpm in text consoles, providing cut-and-paste functionality.
Signed-off-by: Henrik Rydberg <rydberg@xxxxxxxxxxx>
---
drivers/input/mouse/bcm5974.c | 238 ++++++++++++++++++++++++++++++++++------
1 files changed, 202 insertions(+), 36 deletions(-)
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index ae78bb8..7e18793 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -84,10 +84,33 @@ MODULE_LICENSE("GPL");
#define dprintk(level, format, a...)\
{ if (debug >= level) printk(KERN_DEBUG format, ##a); }
+#define MODE_MOUSE 1
+#define MODE_TOUCHPAD 2
+
static int debug = 1;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Activate debugging output");
+static int driver_mode = MODE_MOUSE;
+module_param(driver_mode, int, 0644);
+MODULE_PARM_DESC(driver_mode, "Driver mode (1 - mouse; 2 - touchpad)");
+
+static int mouse_motion_damping = 8;
+module_param(mouse_motion_damping, int, 0644);
+MODULE_PARM_DESC(mouse_motion_damping, "Mouse motion damping");
+
+static int mouse_wheel_damping = 256;
+module_param(mouse_wheel_damping, int, 0644);
+MODULE_PARM_DESC(mouse_wheel_damping, "Vertical mouse wheel damping");
+
+static int mouse_hwheel_damping = 256;
+module_param(mouse_hwheel_damping, int, 0644);
+MODULE_PARM_DESC(mouse_hwheel_damping, "Horizontal mouse wheel damping");
+
+static int mouse_button_mode = 2;
+module_param(mouse_button_mode, int, 0644);
+MODULE_PARM_DESC(mouse_button_mode, "Mouse button mode (1 - unix; 2 - macos)");
+
/* button data structure */
struct bt_data {
u8 unknown1; /* constant */
@@ -146,6 +169,15 @@ struct bcm5974_config {
struct bcm5974_param y; /* vertical limits */
};
+/* mouse driver state */
+struct bcm5974_mouse_state {
+ int fingers; /* number of fingers on trackpad */
+ int rel_x; /* horizontal relative counter */
+ int rel_y; /* vertical relative counter */
+ int wheel_x; /* horizontal wheel counter */
+ int wheel_y; /* vertical wheel counter */
+};
+
/* logical device structure */
struct bcm5974 {
char phys[64];
@@ -159,6 +191,7 @@ struct bcm5974 {
struct bt_data *bt_data; /* button transferred data */
struct urb *tp_urb; /* trackpad usb request block */
struct tp_data *tp_data; /* trackpad transferred data */
+ struct bcm5974_mouse_state ms; /* mouse state */
};
/* logical dimensions */
@@ -236,71 +269,204 @@ static inline int int2bound(const struct bcm5974_param *p, int x)
static void setup_events_to_report(struct input_dev *input_dev,
const struct bcm5974_config *cfg)
{
- __set_bit(EV_ABS, input_dev->evbit);
-
- input_set_abs_params(input_dev, ABS_PRESSURE,
- 0, cfg->p.dim, cfg->p.fuzz, 0);
- input_set_abs_params(input_dev, ABS_TOOL_WIDTH,
- 0, cfg->w.dim, cfg->w.fuzz, 0);
- input_set_abs_params(input_dev, ABS_X,
- 0, cfg->x.dim, cfg->x.fuzz, 0);
- input_set_abs_params(input_dev, ABS_Y,
- 0, cfg->y.dim, cfg->y.fuzz, 0);
-
__set_bit(EV_KEY, input_dev->evbit);
- __set_bit(BTN_TOOL_FINGER, input_dev->keybit);
- __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
- __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
__set_bit(BTN_LEFT, input_dev->keybit);
+
+ switch (driver_mode) {
+ case MODE_MOUSE:
+ __set_bit(EV_REL, input_dev->evbit);
+ __set_bit(REL_X, input_dev->relbit);
+ __set_bit(REL_Y, input_dev->relbit);
+ __set_bit(REL_HWHEEL, input_dev->relbit);
+ __set_bit(REL_WHEEL, input_dev->relbit);
+ __set_bit(BTN_MIDDLE, input_dev->keybit);
+ __set_bit(BTN_RIGHT, input_dev->keybit);
+ break;
+ case MODE_TOUCHPAD:
+ __set_bit(EV_ABS, input_dev->evbit);
+ __set_bit(BTN_TOOL_FINGER, input_dev->keybit);
+ __set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
+ __set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
+
+ input_set_abs_params(input_dev, ABS_PRESSURE,
+ 0, cfg->p.dim, cfg->p.fuzz, 0);
+ input_set_abs_params(input_dev, ABS_TOOL_WIDTH,
+ 0, cfg->w.dim, cfg->w.fuzz, 0);
+ input_set_abs_params(input_dev, ABS_X,
+ 0, cfg->x.dim, cfg->x.fuzz, 0);
+ input_set_abs_params(input_dev, ABS_Y,
+ 0, cfg->y.dim, cfg->y.fuzz, 0);
+ break;
+ }
}
-/* report button data as logical button state */
+/* update logical mouse button state */
+static void update_bt_mouse_state(struct input_dev *dev,
+ const struct bcm5974_mouse_state *ms,
+ const struct bt_data *bt)
+{
+ const int n = ms->fingers;
+
+ bool left, middle, right;
+ switch (mouse_button_mode) {
+ case 1:
+ left = n <= 1 && bt->button;
+ middle = n == 2 && bt->button;
+ right = n >= 3 && bt->button;
+ break;
+ case 2:
+ left = n <= 1 && bt->button;
+ middle = n >= 3 && bt->button;
+ right = n == 2 && bt->button;
+ break;
+ default:
+ left = bt->button;
+ middle = false;
+ right = false;
+ break;
+ };
+ input_report_key(dev, BTN_LEFT, left);
+ input_report_key(dev, BTN_MIDDLE, middle);
+ input_report_key(dev, BTN_RIGHT, right);
+}
+
+/* update logical touchpad button state */
+static void update_bt_touchpad_state(struct input_dev *dev,
+ const struct bt_data *bt)
+{
+ input_report_key(dev, BTN_LEFT, bt->button);
+}
+
+/* report button data as logical mouse/touchpad button state */
static int report_bt_state(struct bcm5974 *dev, int size)
{
if (size != sizeof(struct bt_data))
return -EIO;
- input_report_key(dev->input, BTN_LEFT, dev->bt_data->button);
+ switch (driver_mode) {
+ case MODE_MOUSE:
+ update_bt_mouse_state(dev->input, &dev->ms, dev->bt_data);
+ break;
+ case MODE_TOUCHPAD:
+ update_bt_touchpad_state(dev->input, dev->bt_data);
+ break;
+ }
+
input_sync(dev->input);
return 0;
}
-/* report trackpad data as logical trackpad state */
-static int report_tp_state(struct bcm5974 *dev, int size)
+/* update logical mouse motion state */
+static void update_tp_mouse_state(struct input_dev *dev,
+ struct bcm5974_mouse_state *ms,
+ const struct bcm5974_config *c,
+ const struct tp_finger *f,
+ int p, int n)
{
- const struct bcm5974_config *c = &dev->cfg;
- const struct tp_finger *f = dev->tp_data->finger;
- struct input_dev *input = dev->input;
- const int fingers = (size - 26) / 28;
- int p = 0, w, x, y, n = 0;
+ int dx = 0, dy = 0, sx = 0, sy = 0, swx = 0, swy = 0;
- if (size < 26 || (size - 26) % 28 != 0)
- return -EIO;
+ if (f) {
+ dx = raw2int(f->rel_x);
+ dy = raw2int(f->rel_y);
- if (fingers) {
- p = raw2int(f->force_major);
+ dprintk(9,
+ "bcm5974: p: %+05d dx: %+05d dy: %+05d n: %d\n",
+ p, dx, dy, n);
+ }
+
+ if (n >= 3) {
+ /* swipe */
+ ms->rel_x = 0;
+ ms->rel_y = 0;
+ ms->wheel_x += int2scale(&c->x, dx);
+ ms->wheel_y = 0;
+ swx = ms->wheel_x / mouse_hwheel_damping;
+ ms->wheel_x -= swx * mouse_hwheel_damping;
+ } else if (n == 2) {
+ /* scroll */
+ ms->rel_x = 0;
+ ms->rel_y = 0;
+ ms->wheel_x = 0;
+ ms->wheel_y += int2scale(&c->y, dy);
+ swy = ms->wheel_y / mouse_wheel_damping;
+ ms->wheel_y -= swy * mouse_wheel_damping;
+ } else {
+ /* pointer */
+ ms->rel_x += int2scale(&c->x, dx);
+ ms->rel_y += int2scale(&c->y, -dy);
+ ms->wheel_x = 0;
+ ms->wheel_y = 0;
+ sx = ms->rel_x / mouse_motion_damping;
+ sy = ms->rel_y / mouse_motion_damping;
+ ms->rel_x -= sx * mouse_motion_damping;
+ ms->rel_y -= sy * mouse_motion_damping;
+ }
+
+ ms->fingers = n;
+
+ input_report_rel(dev, REL_X, sx);
+ input_report_rel(dev, REL_Y, sy);
+ input_report_rel(dev, REL_HWHEEL, swx);
+ input_report_rel(dev, REL_WHEEL, swy);
+}
+
+/* update logical touchpad state */
+static void update_tp_touchpad_state(struct input_dev *dev,
+ const struct bcm5974_config *c,
+ const struct tp_finger *f,
+ int p, int n)
+{
+ int w, x, y;
+
+ if (f) {
w = raw2int(f->size_major);
x = raw2int(f->abs_x);
y = raw2int(f->abs_y);
- n = p > 0 ? fingers : 0;
dprintk(9,
"bcm5974: p: %+05d w: %+05d x: %+05d y: %+05d n: %d\n",
p, w, x, y, n);
- input_report_abs(input, ABS_TOOL_WIDTH, int2bound(&c->w, w));
- input_report_abs(input, ABS_X, int2bound(&c->x, x - c->x.devmin));
- input_report_abs(input, ABS_Y, int2bound(&c->y, c->y.devmax - y));
+ input_report_abs(dev, ABS_TOOL_WIDTH, int2bound(&c->w, w));
+ input_report_abs(dev, ABS_X, int2bound(&c->x, x - c->x.devmin));
+ input_report_abs(dev, ABS_Y, int2bound(&c->y, c->y.devmax - y));
}
- input_report_abs(input, ABS_PRESSURE, int2bound(&c->p, p));
+ input_report_abs(dev, ABS_PRESSURE, int2bound(&c->p, p));
+
+ input_report_key(dev, BTN_TOOL_FINGER, n == 1);
+ input_report_key(dev, BTN_TOOL_DOUBLETAP, n == 2);
+ input_report_key(dev, BTN_TOOL_TRIPLETAP, n > 2);
+}
+
+/* report trackpad data as logical mouse/touchpad state */
+static int report_tp_state(struct bcm5974 *dev, int size)
+{
+ const struct bcm5974_config *c = &dev->cfg;
+ const int fingers = (size - 26) / 28;
+ const struct tp_finger *f = 0;
+ int p = 0, n = 0;
+
+ if (size < 26 || (size - 26) % 28 != 0)
+ return -EIO;
+
+ if (fingers) {
+ f = dev->tp_data->finger;
+ p = raw2int(f->force_major);
+ n = p > 0 ? fingers : 0;
+ }
- input_report_key(input, BTN_TOOL_FINGER, n == 1);
- input_report_key(input, BTN_TOOL_DOUBLETAP, n == 2);
- input_report_key(input, BTN_TOOL_TRIPLETAP, n > 2);
+ switch (driver_mode) {
+ case MODE_MOUSE:
+ update_tp_mouse_state(dev->input, &dev->ms, c, f, p, n);
+ break;
+ case MODE_TOUCHPAD:
+ update_tp_touchpad_state(dev->input, c, f, p, n);
+ break;
+ }
- input_sync(input);
+ input_sync(dev->input);
return 0;
}
--
1.5.4.3
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/