mactel-support team mailing list archive
-
mactel-support team
-
Mailing list archive
-
Message #00399
[PATCH] Intrepid: Mouse pointer frozen by default on bcm5974-based macbooks (#263451)
Starting up the CD on a Macbook Air or Macbook Pro Penryn, both of
which use the bcm5974 trackpad driver, the mouse pointer is initially
frozen. The reason is that the bcm5974 driver only mimics a synaptics
touchpad, not a mouse. After configuring the synaptics driver
everything is fine, but the default behavior is simply not going to
work well for first time users. This patch upgrades Intrepid to
bcm5974-0.6, which by default operates as a regular mouse.
Bug: https://bugs.launchpad.net/ubuntu/+source/linux-meta/+bug/263451
Signed-off-by: Henrik Rydberg <rydberg@xxxxxxxxxxx>
---
drivers/input/mouse/bcm5974.c | 230 ++++++++++++++++++++++++++++++++++-------
1 files changed, 193 insertions(+), 37 deletions(-)
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index 2ec921b..adc7102 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -63,7 +63,7 @@
}
/* table of devices that work with this driver */
-static const struct usb_device_id bcm5974_table [] = {
+static const struct usb_device_id bcm5974_table[] = {
/* MacbookAir1.1 */
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_ANSI),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_ISO),
@@ -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,13 @@ struct bcm5974_config {
struct bcm5974_param y; /* vertical limits */
};
+/* mouse driver state */
+struct bcm5974_mouse_state {
+ int fingers; /* number of fingers on trackpad */
+ int wheel; /* vertical wheel counter */
+ int hwheel; /* horizontal wheel counter */
+};
+
/* logical device structure */
struct bcm5974 {
char phys[64];
@@ -159,6 +189,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 +267,196 @@ 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_WHEEL, input_dev->relbit);
+ __set_bit(REL_HWHEEL, 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, sw = 0, shw = 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->wheel = 0;
+ ms->hwheel += int2scale(&c->x, dx);
+ shw = ms->hwheel / mouse_hwheel_damping;
+ ms->hwheel -= shw * mouse_hwheel_damping;
+ } else if (n == 2) {
+ /* scroll */
+ ms->wheel += int2scale(&c->y, dy);
+ ms->hwheel = 0;
+ sw = ms->wheel / mouse_wheel_damping;
+ ms->wheel -= sw * mouse_wheel_damping;
+ } else {
+ /* pointer */
+ ms->wheel = 0;
+ ms->hwheel = 0;
+ sx = int2scale(&c->x, dx) / mouse_motion_damping;
+ sy = int2scale(&c->y, -dy) / 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_WHEEL, sw);
+ input_report_rel(dev, REL_HWHEEL, shw);
+}
+
+/* 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