diff mbox

[2/3] HID: suppress the second input for the Apple Magic Mouse.

Message ID 1268083784.9018.20.camel@localhost.localdomain
State New, archived
Delegated to: Jiri Kosina
Headers show

Commit Message

Benjamin Tissoires March 8, 2010, 9:29 p.m. UTC
None
diff mbox

Patch

diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index 4a3a94f..32d90c8 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -37,6 +37,8 @@  static bool report_undeciphered;
 module_param(report_undeciphered, bool, 0644);
 MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state field using a MSC_RAW event");
 
+#define ArrayLength(a) (sizeof(a) / (sizeof((a)[0])))
+
 #define TOUCH_REPORT_ID   0x29
 /* These definitions are not precise, but they're close enough.  (Bits
  * 0x03 seem to indicate the aspect ratio of the touch, bits 0x70 seem
@@ -328,15 +330,166 @@  static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h
 	}
 }
 
+static int magicmouse_input_mapping(struct hid_device *hdev, struct hid_input *hinput,
+		struct hid_field *field, struct hid_usage *usage,
+		unsigned long **bit, int *max)
+{
+	int return_value = report_touches ? 1 : -1;
+	struct magicmouse_sc *msc = hid_get_drvdata(hdev);
+
+	if (field->report->id != TOUCH_REPORT_ID){
+		/* we let hid_input in charge of the mapping */
+		return 0;
+	}
+
+	if (usage->collection_index != 1) {
+		/* The only collection we had to map is the multitouch one.
+		 * The part containing the relatives axes has been mapped
+		 * by hid in the report given by the device. */
+		return -1;
+	}
+
+	/* we store the struct input_dev */
+	msc->input = hinput->input;
+
+	if (emulate_3button)
+	{
+		__set_bit(BTN_MIDDLE, hinput->input->keybit);
+	}
+
+	if (emulate_scroll_wheel)
+		__set_bit(REL_WHEEL, hinput->input->relbit);
+
+	__set_bit(BTN_TOOL_FINGER, hinput->input->keybit);
+
+	if (report_undeciphered) {
+		__set_bit(EV_MSC, hinput->input->evbit);
+		__set_bit(MSC_RAW, hinput->input->mscbit);
+	}
+
+	if (usage->hid == HID_UP_UNDEFINED) {
+		return -1;
+	}
+
+	switch (usage->hid & HID_USAGE_PAGE) {
+
+		case HID_UP_GENDESK:
+			switch (usage->hid) {
+			case HID_GD_X:
+				hid_map_usage(hinput, usage, bit, max,
+						EV_ABS, ABS_MT_POSITION_X);
+				return return_value;
+			case HID_GD_Y:
+				hid_map_usage(hinput, usage, bit, max,
+						EV_ABS, ABS_MT_POSITION_Y);
+				return return_value;
+			}
+			return 0;
+
+		case HID_UP_DIGITIZER:
+			switch (usage->hid) {
+				case HID_DG_INRANGE:
+				case HID_DG_CONFIDENCE:
+				case HID_DG_INPUTMODE:
+				case HID_DG_DEVICEINDEX:
+				case HID_DG_CONTACTCOUNT:
+				case HID_DG_CONTACTMAX:
+				case HID_DG_TIPPRESSURE:
+					return -1;
+
+				case HID_DG_PUCK:
+					hid_map_usage(hinput, usage, bit, max,
+							EV_ABS, ABS_MT_ORIENTATION);
+					return return_value;
+				case HID_DG_WIDTH:
+					hid_map_usage(hinput, usage, bit, max,
+							EV_ABS, ABS_MT_TOUCH_MAJOR);
+					return return_value;
+				case HID_DG_HEIGHT:
+					hid_map_usage(hinput, usage, bit, max,
+							EV_ABS, ABS_MT_TOUCH_MINOR);
+					return return_value;
+				case HID_DG_CONTACTID:
+					hid_map_usage(hinput, usage, bit, max,
+							EV_ABS, ABS_MT_TRACKING_ID);
+					return return_value;
+
+			}
+			return 0;
+	}
+
+	return 0;
+}
+
+struct magicmouse_descriptor {
+	unsigned size;
+	unsigned application;
+	unsigned hid;
+	int logical_minimum;
+	int logical_maximum;
+};
+
+static const struct magicmouse_descriptor magicmouse_multitouch_rel_desc[] = {
+	{ 8,  HID_GD_MOUSE,  HID_GD_X,           -1,    1 }, /* REL_X */
+	{ 8,  HID_GD_MOUSE,  HID_GD_Y,           -1,    1 }, /* REL_Y */
+	{ 1,  HID_GD_MOUSE,  HID_UP_BUTTON+1,    0,     1 }, /* BTN_LEFT */
+	{ 1,  HID_GD_MOUSE,  HID_UP_BUTTON+2,    0,     1 }, /* BTN_RIGHT */
+	{ 22, HID_GD_MOUSE,  HID_GD_FEATURE,     0,     0 }, /* TimeStamp */
+};
+
+
+/* Note: Touch Y position from the device is inverted relative
+ * to how pointer motion is reported (and relative to how USB
+ * HID recommends the coordinates work).  This driver keeps
+ * the origin at the same position, and just uses the additive
+ * inverse of the reported Y.
+ */
+static const struct magicmouse_descriptor magicmouse_multitouch_abs_desc[] = {
+	{ 12, HID_GD_MOUSE,  HID_GD_X,           -1100, 1358 }, /* ABS_MT_X */
+	{ 12, HID_GD_MOUSE,  HID_GD_Y,           -1589, 2047 }, /* ABS_MT_Y */
+	{ 8,  HID_GD_MOUSE,  HID_DG_WIDTH,       0,     255 }, /* ABS_MT_TOUCH_MAJOR */
+	{ 8,  HID_GD_MOUSE,  HID_DG_HEIGHT,      0,     255 }, /* ABS_MT_TOUCH_MINOR */
+	{ 6,  HID_GD_MOUSE,  HID_DG_TIPPRESSURE, 0,     63 }, /* Pressure */
+	{ 4,  HID_GD_MOUSE,  HID_DG_CONTACTID,   0,     15 }, /* Contact ID */
+	{ 6,  HID_GD_MOUSE,  HID_DG_PUCK,        -32,   31 }, /* ORIENTATION */
+	{ 4,  HID_GD_MOUSE,  HID_DG_DEVICEINDEX, 0,     15 }, /* ? */
+	{ 4,  HID_GD_MOUSE,  HID_DG_CONFIDENCE,  0,     15 }, /* State */
+};
+
+static void magicmouse_register_descriptor(const struct magicmouse_descriptor *desc,
+	int collection, struct hid_report *report)
+{
+	struct hid_field *field;
+	int offset = report->size;
+	report->size += desc->size;
+	field = hid_register_field(report, 1, 1);
+	field->physical = 0;
+	field->logical = 0;
+	field->application = desc->application;
+	field->usage[0].hid = desc->hid;
+	field->usage[0].collection_index = collection;
+	field->maxusage = 1;
+	field->flags = 2;
+	field->report_offset = offset;
+	field->report_type = 0;
+	field->report_size = desc->size;
+	field->report_count = 1;
+	field->logical_minimum = desc->logical_minimum;
+	field->logical_maximum = desc->logical_maximum;
+	field->physical_minimum = 0;
+	field->physical_maximum = 0;
+	field->unit_exponent = 0;
+	field->unit = 0;
+}
+
 static int magicmouse_probe(struct hid_device *hdev,
 	const struct hid_device_id *id)
 {
 	__u8 feature_1[] = { 0xd7, 0x01 };
 	__u8 feature_2[] = { 0xf8, 0x01, 0x32 };
-	struct input_dev *input;
 	struct magicmouse_sc *msc;
 	struct hid_report *report;
-	int ret;
+	int ret,i;
 
 	msc = kzalloc(sizeof(*msc), GFP_KERNEL);
 	if (msc == NULL) {
@@ -353,19 +506,28 @@  static int magicmouse_probe(struct hid_device *hdev,
 		goto err_free;
 	}
 
-	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
-	if (ret) {
-		dev_err(&hdev->dev, "magicmouse hw start failed\n");
-		goto err_free;
-	}
-
 	report = hid_register_report(hdev, HID_INPUT_REPORT, TOUCH_REPORT_ID);
 	if (!report) {
 		dev_err(&hdev->dev, "unable to register touch report\n");
 		ret = -ENOMEM;
 		goto err_stop_hw;
 	}
-	report->size = 6;
+
+	for (i = 0 ; i < ArrayLength(magicmouse_multitouch_rel_desc) ; ++i) {
+		magicmouse_register_descriptor(&(magicmouse_multitouch_rel_desc[i]),
+			0, report);
+	}
+
+	for (i = 0 ; i < ArrayLength(magicmouse_multitouch_abs_desc) ; ++i) {
+		magicmouse_register_descriptor(&(magicmouse_multitouch_abs_desc[i]),
+			1, report);
+	}
+
+	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+	if (ret) {
+		dev_err(&hdev->dev, "magicmouse hw start failed\n");
+		goto err_free;
+	}
 
 	ret = hdev->hid_output_raw_report(hdev, feature_1, sizeof(feature_1),
 			HID_FEATURE_REPORT);
@@ -382,24 +544,7 @@  static int magicmouse_probe(struct hid_device *hdev,
 		goto err_stop_hw;
 	}
 
-	input = input_allocate_device();
-	if (!input) {
-		dev_err(&hdev->dev, "can't alloc input device\n");
-		ret = -ENOMEM;
-		goto err_stop_hw;
-	}
-	magicmouse_setup_input(input, hdev);
-
-	ret = input_register_device(input);
-	if (ret) {
-		dev_err(&hdev->dev, "input device registration failed\n");
-		goto err_input;
-	}
-	msc->input = input;
-
 	return 0;
-err_input:
-	input_free_device(input);
 err_stop_hw:
 	hid_hw_stop(hdev);
 err_free:
@@ -426,6 +571,7 @@  static struct hid_driver magicmouse_driver = {
 	.probe = magicmouse_probe,
 	.remove = magicmouse_remove,
 	.raw_event = magicmouse_raw_event,
+	.input_mapping = magicmouse_input_mapping,
 };
 
 static int __init magicmouse_init(void)