linux-input.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 2/2] input: bcm5974-0.61: New default mouse driver mode
@ 2008-09-01 20:08 Henrik Rydberg
  2008-09-02 13:00 ` Dmitry Torokhov
  0 siblings, 1 reply; 3+ messages in thread
From: Henrik Rydberg @ 2008-09-01 20:08 UTC (permalink / raw)
  To: akpm, Dmitry Torokhov, linux-input; +Cc: linux-kernel

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@euromail.se>
---
 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


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* Re: [PATCH 2/2] input: bcm5974-0.61: New default mouse driver mode
  2008-09-01 20:08 [PATCH 2/2] input: bcm5974-0.61: New default mouse driver mode Henrik Rydberg
@ 2008-09-02 13:00 ` Dmitry Torokhov
  2008-09-02 18:23   ` Henrik Rydberg
  0 siblings, 1 reply; 3+ messages in thread
From: Dmitry Torokhov @ 2008-09-02 13:00 UTC (permalink / raw)
  To: Henrik Rydberg; +Cc: akpm, linux-input, linux-kernel

Hi Henrik,

On Mon, Sep 01, 2008 at 10:08:35PM +0200, Henrik Rydberg wrote:
> 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.

Mousedev should provide a reasonable emulation of standard mouse
giving user chance to configure the system properly. There is no need
to task the driver to provide such emulation and therefore I will not
apply this patch.

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

This happens automatically with Synaptics hardware on newer
distributions (at least Fedora 9 does this). As far as I know
SYnaptics driver does no look for specific product but for a certain
features of the input device and so shoudl work for BCM as well.

> 
> * 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 kenel driver should only do as little translation as possible,
allowing userspace to decide how to implement more fancy features.

> * The mouse driver also works with gpm in text consoles, providing cut-and-paste functionality.
>

Does not mousedev emulation work from GPM? Also GPM has evdev protocol
support which should work very well with synaptics-like touchpads.

-- 
Dmitry

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH 2/2] input: bcm5974-0.61: New default mouse driver mode
  2008-09-02 13:00 ` Dmitry Torokhov
@ 2008-09-02 18:23   ` Henrik Rydberg
  0 siblings, 0 replies; 3+ messages in thread
From: Henrik Rydberg @ 2008-09-02 18:23 UTC (permalink / raw)
  To: Dmitry Torokhov; +Cc: akpm, linux-input, linux-kernel

Dmitry Torokhov wrote:
> Hi Henrik,
> 
> On Mon, Sep 01, 2008 at 10:08:35PM +0200, Henrik Rydberg wrote:
>> 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.
> 
> Mousedev should provide a reasonable emulation of standard mouse
> giving user chance to configure the system properly. There is no need
> to task the driver to provide such emulation and therefore I will not
> apply this patch.
> 

I see, this is what puzzled me. Currently mousedev does not work with
bcm5974, but given the statement that it should, it was not hard finding
the reason; the ABS_X/Y messages get stuck in mousedev because bcm5974 does
not fire BTN_TOUCH events. I will send a fix for it shortly. I take it the
first clean-up patch is being applied.

> 
>> * 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 kenel driver should only do as little translation as possible,
> allowing userspace to decide how to implement more fancy features.

One could argue that those features are basic rather than fancy; virtually
every mouse of today provides equivalent functionality, and multitouch
features are here to stay. It is also discouraging in particular to
first-time apple users, having to spend a lot of time configuring their
system, only to be able to right-click or scroll using the trackpad.
Could it be something for the mousedev driver, perhaps?


Many thanks,
Henrik


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2008-09-02 18:23 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-09-01 20:08 [PATCH 2/2] input: bcm5974-0.61: New default mouse driver mode Henrik Rydberg
2008-09-02 13:00 ` Dmitry Torokhov
2008-09-02 18:23   ` Henrik Rydberg

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).