@@ -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)