diff options
Diffstat (limited to 'drivers/input/mouse/bcm5974.c')
| -rw-r--r-- | drivers/input/mouse/bcm5974.c | 108 | 
1 files changed, 81 insertions, 27 deletions
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c index 2998a6ac9ae..2d8fc0bf692 100644 --- a/drivers/input/mouse/bcm5974.c +++ b/drivers/input/mouse/bcm5974.c @@ -51,6 +51,10 @@  #define USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI	0x0230  #define USB_DEVICE_ID_APPLE_WELLSPRING2_ISO	0x0231  #define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS	0x0232 +/* Macbook5,1 (unibody), aka wellspring3 */ +#define USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI	0x0236 +#define USB_DEVICE_ID_APPLE_WELLSPRING3_ISO	0x0237 +#define USB_DEVICE_ID_APPLE_WELLSPRING3_JIS	0x0238  #define BCM5974_DEVICE(prod) {					\  	.match_flags = (USB_DEVICE_ID_MATCH_DEVICE |		\ @@ -72,6 +76,10 @@ static const struct usb_device_id bcm5974_table[] = {  	BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI),  	BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_ISO),  	BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_JIS), +	/* Macbook5,1 */ +	BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI), +	BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_ISO), +	BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING3_JIS),  	/* Terminating entry */  	{}  }; @@ -96,14 +104,23 @@ struct bt_data {  	u8 rel_y;		/* relative y coordinate */  }; -/* trackpad header structure */ -struct tp_header { -	u8 unknown1[16];	/* constants, timers, etc */ -	u8 fingers;		/* number of fingers on trackpad */ -	u8 unknown2[9];		/* constants, timers, etc */ +/* trackpad header types */ +enum tp_type { +	TYPE1,			/* plain trackpad */ +	TYPE2			/* button integrated in trackpad */  }; -/* trackpad finger structure */ +/* trackpad finger data offsets, le16-aligned */ +#define FINGER_TYPE1		(13 * sizeof(__le16)) +#define FINGER_TYPE2		(15 * sizeof(__le16)) + +/* trackpad button data offsets */ +#define BUTTON_TYPE2		15 + +/* list of device capability bits */ +#define HAS_INTEGRATED_BUTTON	1 + +/* trackpad finger structure, le16-aligned */  struct tp_finger {  	__le16 origin;		/* zero when switching track finger */  	__le16 abs_x;		/* absolute x coodinate */ @@ -117,13 +134,11 @@ struct tp_finger {  	__le16 force_minor;	/* trackpad force, minor axis? */  	__le16 unused[3];	/* zeros */  	__le16 multi;		/* one finger: varies, more fingers: constant */ -}; +} __attribute__((packed,aligned(2))); -/* trackpad data structure, empirically at least ten fingers */ -struct tp_data { -	struct tp_header header; -	struct tp_finger finger[16]; -}; +/* trackpad finger data size, empirically at least ten fingers */ +#define SIZEOF_FINGER		sizeof(struct tp_finger) +#define SIZEOF_ALL_FINGERS	(16 * SIZEOF_FINGER)  /* device-specific parameters */  struct bcm5974_param { @@ -136,9 +151,12 @@ struct bcm5974_param {  /* device-specific configuration */  struct bcm5974_config {  	int ansi, iso, jis;	/* the product id of this device */ +	int caps;		/* device capability bitmask */  	int bt_ep;		/* the endpoint of the button interface */  	int bt_datalen;		/* data length of the button interface */  	int tp_ep;		/* the endpoint of the trackpad interface */ +	enum tp_type tp_type;	/* type of trackpad interface */ +	int tp_offset;		/* offset to trackpad finger data */  	int tp_datalen;		/* data length of the trackpad interface */  	struct bcm5974_param p;	/* finger pressure limits */  	struct bcm5974_param w;	/* finger width limits */ @@ -158,7 +176,7 @@ struct bcm5974 {  	struct urb *bt_urb;		/* button usb request block */  	struct bt_data *bt_data;	/* button transferred data */  	struct urb *tp_urb;		/* trackpad usb request block */ -	struct tp_data *tp_data;	/* trackpad transferred data */ +	u8 *tp_data;			/* trackpad transferred data */  	int fingers;			/* number of fingers on trackpad */  }; @@ -183,8 +201,9 @@ static const struct bcm5974_config bcm5974_config_table[] = {  		USB_DEVICE_ID_APPLE_WELLSPRING_ANSI,  		USB_DEVICE_ID_APPLE_WELLSPRING_ISO,  		USB_DEVICE_ID_APPLE_WELLSPRING_JIS, +		0,  		0x84, sizeof(struct bt_data), -		0x81, sizeof(struct tp_data), +		0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS,  		{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 },  		{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },  		{ DIM_X, DIM_X / SN_COORD, -4824, 5342 }, @@ -194,13 +213,26 @@ static const struct bcm5974_config bcm5974_config_table[] = {  		USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI,  		USB_DEVICE_ID_APPLE_WELLSPRING2_ISO,  		USB_DEVICE_ID_APPLE_WELLSPRING2_JIS, +		0,  		0x84, sizeof(struct bt_data), -		0x81, sizeof(struct tp_data), +		0x81, TYPE1, FINGER_TYPE1, FINGER_TYPE1 + SIZEOF_ALL_FINGERS,  		{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 },  		{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },  		{ DIM_X, DIM_X / SN_COORD, -4824, 4824 },  		{ DIM_Y, DIM_Y / SN_COORD, -172, 4290 }  	}, +	{ +		USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI, +		USB_DEVICE_ID_APPLE_WELLSPRING3_ISO, +		USB_DEVICE_ID_APPLE_WELLSPRING3_JIS, +		HAS_INTEGRATED_BUTTON, +		0x84, sizeof(struct bt_data), +		0x81, TYPE2, FINGER_TYPE2, FINGER_TYPE2 + SIZEOF_ALL_FINGERS, +		{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 300 }, +		{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 }, +		{ DIM_X, DIM_X / SN_COORD, -4460, 5166 }, +		{ DIM_Y, DIM_Y / SN_COORD, -75, 6700 } +	},  	{}  }; @@ -257,6 +289,7 @@ static void setup_events_to_report(struct input_dev *input_dev,  	__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_TOOL_QUADTAP, input_dev->keybit);  	__set_bit(BTN_LEFT, input_dev->keybit);  } @@ -266,6 +299,11 @@ static int report_bt_state(struct bcm5974 *dev, int size)  	if (size != sizeof(struct bt_data))  		return -EIO; +	dprintk(7, +		"bcm5974: button data: %x %x %x %x\n", +		dev->bt_data->unknown1, dev->bt_data->button, +		dev->bt_data->rel_x, dev->bt_data->rel_y); +  	input_report_key(dev->input, BTN_LEFT, dev->bt_data->button);  	input_sync(dev->input); @@ -276,29 +314,37 @@ static int report_bt_state(struct bcm5974 *dev, int size)  static int report_tp_state(struct bcm5974 *dev, int size)  {  	const struct bcm5974_config *c = &dev->cfg; -	const struct tp_finger *f = dev->tp_data->finger; +	const struct tp_finger *f;  	struct input_dev *input = dev->input; -	const int fingers = (size - 26) / 28; -	int raw_p, raw_w, raw_x, raw_y; -	int ptest = 0, origin = 0, nmin = 0, nmax = 0; +	int raw_p, raw_w, raw_x, raw_y, raw_n; +	int ptest = 0, origin = 0, ibt = 0, nmin = 0, nmax = 0;  	int abs_p = 0, abs_w = 0, abs_x = 0, abs_y = 0; -	if (size < 26 || (size - 26) % 28 != 0) +	if (size < c->tp_offset || (size - c->tp_offset) % SIZEOF_FINGER != 0)  		return -EIO; +	/* finger data, le16-aligned */ +	f = (const struct tp_finger *)(dev->tp_data + c->tp_offset); +	raw_n = (size - c->tp_offset) / SIZEOF_FINGER; +  	/* always track the first finger; when detached, start over */ -	if (fingers) { +	if (raw_n) {  		raw_p = raw2int(f->force_major);  		raw_w = raw2int(f->size_major);  		raw_x = raw2int(f->abs_x);  		raw_y = raw2int(f->abs_y);  		dprintk(9, -			"bcm5974: raw: p: %+05d w: %+05d x: %+05d y: %+05d\n", -			raw_p, raw_w, raw_x, raw_y); +			"bcm5974: " +			"raw: p: %+05d w: %+05d x: %+05d y: %+05d n: %d\n", +			raw_p, raw_w, raw_x, raw_y, raw_n);  		ptest = int2bound(&c->p, raw_p);  		origin = raw2int(f->origin); + +		/* set the integrated button if applicable */ +		if (c->tp_type == TYPE2) +			ibt = raw2int(dev->tp_data[BUTTON_TYPE2]);  	}  	/* while tracking finger still valid, count all fingers */ @@ -307,12 +353,13 @@ static int report_tp_state(struct bcm5974 *dev, int size)  		abs_w = int2bound(&c->w, raw_w);  		abs_x = int2bound(&c->x, raw_x - c->x.devmin);  		abs_y = int2bound(&c->y, c->y.devmax - raw_y); -		for (; f != dev->tp_data->finger + fingers; f++) { +		while (raw_n--) {  			ptest = int2bound(&c->p, raw2int(f->force_major));  			if (ptest > PRESSURE_LOW)  				nmax++;  			if (ptest > PRESSURE_HIGH)  				nmin++; +			f++;  		}  	} @@ -324,7 +371,8 @@ static int report_tp_state(struct bcm5974 *dev, int size)  	input_report_key(input, BTN_TOUCH, dev->fingers > 0);  	input_report_key(input, BTN_TOOL_FINGER, dev->fingers == 1);  	input_report_key(input, BTN_TOOL_DOUBLETAP, dev->fingers == 2); -	input_report_key(input, BTN_TOOL_TRIPLETAP, dev->fingers > 2); +	input_report_key(input, BTN_TOOL_TRIPLETAP, dev->fingers == 3); +	input_report_key(input, BTN_TOOL_QUADTAP, dev->fingers > 3);  	input_report_abs(input, ABS_PRESSURE, abs_p);  	input_report_abs(input, ABS_TOOL_WIDTH, abs_w); @@ -335,11 +383,15 @@ static int report_tp_state(struct bcm5974 *dev, int size)  		dprintk(8,  			"bcm5974: abs: p: %+05d w: %+05d x: %+05d y: %+05d " -			"nmin: %d nmax: %d n: %d\n", -			abs_p, abs_w, abs_x, abs_y, nmin, nmax, dev->fingers); +			"nmin: %d nmax: %d n: %d ibt: %d\n", abs_p, abs_w, +			abs_x, abs_y, nmin, nmax, dev->fingers, ibt);  	} +	/* type 2 reports button events via ibt only */ +	if (c->tp_type == TYPE2) +		input_report_key(input, BTN_LEFT, ibt); +  	input_sync(input);  	return 0; @@ -649,6 +701,8 @@ static int bcm5974_probe(struct usb_interface *iface,  	input_dev->name = "bcm5974";  	input_dev->phys = dev->phys;  	usb_to_input_id(dev->udev, &input_dev->id); +	/* report driver capabilities via the version field */ +	input_dev->id.version = cfg->caps;  	input_dev->dev.parent = &iface->dev;  	input_set_drvdata(input_dev, dev);  |