From 42f4f272746f9e4e3fecb4440dc2429822b6950b Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Wed, 15 Apr 2015 16:53:54 -0700 Subject: HID: wacom: move all quirks to wacom_setup_device_quirks It makes probe routine easy to follow. Signed-off-by: Ping Cheng Reviewed-by: Jason Gerecke Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom.h b/drivers/hid/wacom.h index 024f4d89..c76e21f 100644 --- a/drivers/hid/wacom.h +++ b/drivers/hid/wacom.h @@ -134,7 +134,7 @@ static inline void wacom_schedule_work(struct wacom_wac *wacom_wac) extern const struct hid_device_id wacom_ids[]; void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len); -void wacom_setup_device_quirks(struct wacom_features *features); +void wacom_setup_device_quirks(struct wacom *wacom); int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, struct wacom_wac *wacom_wac); int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index e8607d0..13d8c8f 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -1475,44 +1475,7 @@ static int wacom_probe(struct hid_device *hdev, /* Retrieve the physical and logical size for touch devices */ wacom_retrieve_hid_descriptor(hdev, features); - /* - * Intuos5 has no useful data about its touch interface in its - * HID descriptor. If this is the touch interface (PacketSize - * of WACOM_PKGLEN_BBTOUCH3), override the table values. - */ - if (features->type >= INTUOS5S && features->type <= INTUOSHT) { - if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) { - features->device_type = BTN_TOOL_FINGER; - - features->x_max = 4096; - features->y_max = 4096; - } else { - features->device_type = BTN_TOOL_PEN; - } - } - - /* - * Same thing for Bamboo 3rd gen. - */ - if ((features->type == BAMBOO_PT) && - (features->pktlen == WACOM_PKGLEN_BBTOUCH3) && - (features->device_type == BTN_TOOL_PEN)) { - features->device_type = BTN_TOOL_FINGER; - - features->x_max = 4096; - features->y_max = 4096; - } - - /* - * Same thing for Bamboo PAD - */ - if (features->type == BAMBOO_PAD) - features->device_type = BTN_TOOL_FINGER; - - if (hdev->bus == BUS_BLUETOOTH) - features->quirks |= WACOM_QUIRK_BATTERY; - - wacom_setup_device_quirks(features); + wacom_setup_device_quirks(wacom); /* set unit to "100th of a mm" for devices not reported by HID */ if (!features->unit) { diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index fa54d32..3609cbe 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2164,8 +2164,9 @@ static void wacom_setup_intuos(struct wacom_wac *wacom_wac) input_set_abs_params(input_dev, ABS_THROTTLE, -1023, 1023, 0, 0); } -void wacom_setup_device_quirks(struct wacom_features *features) +void wacom_setup_device_quirks(struct wacom *wacom) { + struct wacom_features *features = &wacom->wacom_wac.features; /* touch device found but size is not defined. use default */ if (features->device_type == BTN_TOOL_FINGER && !features->x_max) { @@ -2173,6 +2174,33 @@ void wacom_setup_device_quirks(struct wacom_features *features) features->y_max = 1023; } + /* + * Intuos5/Pro and Bamboo 3rd gen have no useful data about its + * touch interface in its HID descriptor. If this is the touch + * interface (PacketSize of WACOM_PKGLEN_BBTOUCH3), override the + * tablet values. + */ + if ((features->type >= INTUOS5S && features->type <= INTUOSHT) || + (features->type == BAMBOO_PT)) { + if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) { + features->device_type = BTN_TOOL_FINGER; + + features->x_max = 4096; + features->y_max = 4096; + } else { + features->device_type = BTN_TOOL_PEN; + } + } + + /* + * Same thing for Bamboo PAD + */ + if (features->type == BAMBOO_PAD) + features->device_type = BTN_TOOL_FINGER; + + if (wacom->hdev->bus == BUS_BLUETOOTH) + features->quirks |= WACOM_QUIRK_BATTERY; + /* quirk for bamboo touch with 2 low res touches */ if (features->type == BAMBOO_PT && features->pktlen == WACOM_PKGLEN_BBTOUCH) { -- cgit v0.10.2 From 3d64f54dd0de57bdbcde4b91495fb8e02c620762 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Wed, 15 Apr 2015 16:54:14 -0700 Subject: HID: wacom: move unit and unitExpo initialization to wacom_calculate_res That is where they belong... Signed-off-by: Ping Cheng Reviewed-by: Jason Gerecke Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 13d8c8f..b3c6f11 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -1369,6 +1369,12 @@ static void wacom_set_default_phy(struct wacom_features *features) static void wacom_calculate_res(struct wacom_features *features) { + /* set unit to "100th of a mm" for devices not reported by HID */ + if (!features->unit) { + features->unit = 0x11; + features->unitExpo = -3; + } + features->x_resolution = wacom_calc_hid_res(features->x_max, features->x_phy, features->unit, @@ -1476,12 +1482,6 @@ static int wacom_probe(struct hid_device *hdev, wacom_retrieve_hid_descriptor(hdev, features); wacom_setup_device_quirks(wacom); - - /* set unit to "100th of a mm" for devices not reported by HID */ - if (!features->unit) { - features->unit = 0x11; - features->unitExpo = -3; - } wacom_calculate_res(features); strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name)); -- cgit v0.10.2 From e48151a3a456b38b1029a8a7380246b53c768400 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Wed, 15 Apr 2015 16:54:58 -0700 Subject: HID: wacom: remove unused packet lengths We use generic hid_report_len() to get individual packet length now. Signed-off-by: Ping Cheng Reviewed-by: Jason Gerecke Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index 4700ac9..f5a5f68 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -18,10 +18,7 @@ #define WACOM_NAME_MAX 64 /* packet length for individual models */ -#define WACOM_PKGLEN_PENPRTN 7 -#define WACOM_PKGLEN_GRAPHIRE 8 #define WACOM_PKGLEN_BBFUN 9 -#define WACOM_PKGLEN_INTUOS 10 #define WACOM_PKGLEN_TPC1FG 5 #define WACOM_PKGLEN_TPC1FG_B 10 #define WACOM_PKGLEN_TPC2FG 14 @@ -29,9 +26,6 @@ #define WACOM_PKGLEN_BBTOUCH3 64 #define WACOM_PKGLEN_BBPEN 10 #define WACOM_PKGLEN_WIRELESS 32 -#define WACOM_PKGLEN_MTOUCH 62 -#define WACOM_PKGLEN_MTTPC 40 -#define WACOM_PKGLEN_DTUS 68 #define WACOM_PKGLEN_PENABLED 8 #define WACOM_PKGLEN_BPAD_TOUCH 32 #define WACOM_PKGLEN_BPAD_TOUCH_USB 64 -- cgit v0.10.2 From 71b5c4766c1ca4c646a90f64552b140b1368f2f1 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Wed, 15 Apr 2015 17:22:32 -0700 Subject: HID: wacom: Simplify check for presence of single-finger touch To determine if a touch is present in the single-touch case, we can simply check if the BTN_TOUCH key is active or not. This will work for both HID_GENERIC and other device types. Signed-off-by: Jason Gerecke Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 3609cbe..091bab4 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -1072,9 +1072,8 @@ static int wacom_wac_finger_count_touches(struct wacom_wac *wacom) int count = 0; int i; - /* non-HID_GENERIC single touch input doesn't call this routine */ - if ((touch_max == 1) && (wacom->features.type == HID_GENERIC)) - return wacom->hid_data.tipswitch && + if (touch_max == 1) + return test_bit(BTN_TOUCH, input->key) && !wacom->shared->stylus_in_proximity; for (i = 0; i < input->mt->num_slots; i++) { -- cgit v0.10.2 From 007760cf082392b65a05c40eb615c5f8294b441a Mon Sep 17 00:00:00 2001 From: Aaron Skomra Date: Thu, 16 Apr 2015 15:01:14 -0700 Subject: HID: wacom: Add support for DTU-1141 Signed-off-by: Aaron Skomra Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 091bab4..dff99ff 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2946,6 +2946,9 @@ static const struct wacom_features wacom_features_0x32F = { "Wacom DTU1031X", 22472, 12728, 511, 0, DTUSX, WACOM_INTUOS_RES, WACOM_INTUOS_RES, WACOM_DTU_OFFSET, WACOM_DTU_OFFSET }; +static const struct wacom_features wacom_features_0x336 = + { "Wacom DTU1141", 23472, 13203, 1023, 0, + DTUS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x57 = { "Wacom DTK2241", 95640, 54060, 2047, 63, DTK, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES, @@ -3299,6 +3302,7 @@ const struct hid_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0x32F) }, { USB_DEVICE_WACOM(0x333) }, { USB_DEVICE_WACOM(0x335) }, + { USB_DEVICE_WACOM(0x336) }, { USB_DEVICE_WACOM(0x4001) }, { USB_DEVICE_WACOM(0x4004) }, { USB_DEVICE_WACOM(0x5000) }, -- cgit v0.10.2 From d92189ebbdcd0eb180317d8cd6d46c57ac9a3dc0 Mon Sep 17 00:00:00 2001 From: Andreas Fleig Date: Thu, 23 Apr 2015 10:25:58 +0200 Subject: HID: lenovo: set INPUT_PROP_POINTING_STICK Set flags INPUT_PROP_POINTER and INPUT_PROP_POINTING_STICK for the trackpoint integrated in Lenovo USB and Bluetooth keyboards. Libinput checks these flags to enable features such as middle-button-scrolling by default. Signed-off-by: Andreas Fleig Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c index c4c3f09..78608d6 100644 --- a/drivers/hid/hid-lenovo.c +++ b/drivers/hid/hid-lenovo.c @@ -762,6 +762,24 @@ static void lenovo_remove(struct hid_device *hdev) hid_hw_stop(hdev); } +static void lenovo_input_configured(struct hid_device *hdev, + struct hid_input *hi) +{ + switch (hdev->product) { + case USB_DEVICE_ID_LENOVO_TPKBD: + case USB_DEVICE_ID_LENOVO_CUSBKBD: + case USB_DEVICE_ID_LENOVO_CBTKBD: + if (test_bit(EV_REL, hi->input->evbit)) { + /* set only for trackpoint device */ + __set_bit(INPUT_PROP_POINTER, hi->input->propbit); + __set_bit(INPUT_PROP_POINTING_STICK, + hi->input->propbit); + } + break; + } +} + + static const struct hid_device_id lenovo_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) }, { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CUSBKBD) }, @@ -774,6 +792,7 @@ MODULE_DEVICE_TABLE(hid, lenovo_devices); static struct hid_driver lenovo_driver = { .name = "lenovo", .id_table = lenovo_devices, + .input_configured = lenovo_input_configured, .input_mapping = lenovo_input_mapping, .probe = lenovo_probe, .remove = lenovo_remove, -- cgit v0.10.2 From d6ea2f88ac3659b799d8079a4fbda4f8faf6ff90 Mon Sep 17 00:00:00 2001 From: Raphael Assenat Date: Sat, 25 Apr 2015 16:30:32 -0400 Subject: HID: usbhid: Add a quirk for raphnet multi-gamepad adapters The raphnet.net 4nes4snes and 2nes2snes multi-joystick adapters use a single HID report descriptor with one report ID per controller. This has the effect that the inputs of otherwise independent game controllers get packed in one large joystick device. With this patch each controller gets its own /dev/input/jsX device, which is more natural and less confusing than having all inputs going to the same place. Signed-off-by: Raphael Assenat Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 41f167e..b24caf8 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -1038,4 +1038,11 @@ #define USB_VENDOR_ID_RISO_KAGAKU 0x1294 /* Riso Kagaku Corp. */ #define USB_DEVICE_ID_RI_KA_WEBMAIL 0x1320 /* Webmail Notifier */ +#define USB_VENDOR_ID_MULTIPLE_1781 0x1781 +#define USB_DEVICE_ID_RAPHNET_4NES4SNES_OLD 0x0a8d + +#define USB_VENDOR_ID_DRACAL_RAPHNET 0x289b +#define USB_DEVICE_ID_RAPHNET_2NES2SNES 0x0002 +#define USB_DEVICE_ID_RAPHNET_4NES4SNES 0x0003 + #endif diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index a775143..09a22a7 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -140,6 +140,9 @@ static const struct hid_blacklist { { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_QUAD_HD, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_TP_V103, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD_A096, HID_QUIRK_NO_INIT_INPUT_REPORTS }, + { USB_VENDOR_ID_MULTIPLE_1781, USB_DEVICE_ID_RAPHNET_4NES4SNES_OLD, HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_2NES2SNES, HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_4NES4SNES, HID_QUIRK_MULTI_INPUT }, { 0, 0 } }; -- cgit v0.10.2 From c24eab4e0e449845ba98e649b0605ab0450193db Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Fri, 24 Apr 2015 15:32:51 -0700 Subject: HID: wacom: retrieve name from HID descriptor for generic devices HID generic devices share the same default name, "Wacom HID". This causes userland programs to show same device names for different devices, which would confuse end users with same device names for different devices too. This patch uses name retrieved from HID descriptor, if a meaningful name is reported. Otherwise, affix its product ID to "Wacom HID". Names from descriptor may contain extra whitespaces. To comfort readers' eyes, we removed those extra whitespaces too. Signed-off-by: Ping Cheng Reviewed-by: Jason Gerecke Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index b3c6f11..9c57ac0 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -1402,6 +1402,52 @@ static size_t wacom_compute_pktlen(struct hid_device *hdev) return size; } +static void wacom_update_name(struct wacom *wacom) +{ + struct wacom_wac *wacom_wac = &wacom->wacom_wac; + struct wacom_features *features = &wacom_wac->features; + + /* Generic devices name unspecified */ + if ((features->type == HID_GENERIC) && !strcmp("Wacom HID", features->name)) { + if (strstr(wacom->hdev->name, "Wacom") || + strstr(wacom->hdev->name, "wacom") || + strstr(wacom->hdev->name, "WACOM")) { + /* name is in HID descriptor, use it */ + strlcpy(wacom_wac->name, wacom->hdev->name, + sizeof(wacom_wac->name)); + + /* strip out excess whitespaces */ + while (1) { + char *gap = strstr(wacom_wac->name, " "); + if (gap == NULL) + break; + /* shift everything including the terminator */ + memmove(gap, gap+1, strlen(gap)); + } + /* get rid of trailing whitespace */ + if (wacom_wac->name[strlen(wacom_wac->name)-1] == ' ') + wacom_wac->name[strlen(wacom_wac->name)-1] = '\0'; + } else { + /* no meaningful name retrieved. use product ID */ + snprintf(wacom_wac->name, sizeof(wacom_wac->name), + "%s %X", features->name, wacom->hdev->product); + } + } else { + strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name)); + } + + /* Append the device type to the name */ + snprintf(wacom_wac->pad_name, sizeof(wacom_wac->pad_name), + "%s Pad", wacom_wac->name); + + if (features->device_type != BTN_TOOL_FINGER) + strlcat(wacom_wac->name, " Pen", WACOM_NAME_MAX); + else if (features->touch_max) + strlcat(wacom_wac->name, " Finger", WACOM_NAME_MAX); + else + strlcat(wacom_wac->name, " Pad", WACOM_NAME_MAX); +} + static int wacom_probe(struct hid_device *hdev, const struct hid_device_id *id) { @@ -1484,17 +1530,7 @@ static int wacom_probe(struct hid_device *hdev, wacom_setup_device_quirks(wacom); wacom_calculate_res(features); - strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name)); - snprintf(wacom_wac->pad_name, sizeof(wacom_wac->pad_name), - "%s Pad", features->name); - - /* Append the device type to the name */ - if (features->device_type != BTN_TOOL_FINGER) - strlcat(wacom_wac->name, " Pen", WACOM_NAME_MAX); - else if (features->touch_max) - strlcat(wacom_wac->name, " Finger", WACOM_NAME_MAX); - else - strlcat(wacom_wac->name, " Pad", WACOM_NAME_MAX); + wacom_update_name(wacom); error = wacom_add_shared_data(hdev); if (error) -- cgit v0.10.2 From 8d80f790ecbcd0c3d55be51d867cbe4db1debd89 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Thu, 30 Apr 2015 17:51:53 -0700 Subject: HID: wacom: Do not add suffix to name of devices with an unknown type The naming logic currently assumes that all devices will be a pen, finger, or pad. Though this has historically been the case, the new HID_GENERIC catch-all may cause us to probe devices with Wacom's 056A VID which aren't any of these types (e.g. the "Cintiq 24HDT Monitor Control"). This patch updates the logic so that no suffix will be added to the device name if the device type is unknown. Signed-off-by: Jason Gerecke Reviewed-by: Ping Cheng Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 9c57ac0..222baf5 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -1440,12 +1440,15 @@ static void wacom_update_name(struct wacom *wacom) snprintf(wacom_wac->pad_name, sizeof(wacom_wac->pad_name), "%s Pad", wacom_wac->name); - if (features->device_type != BTN_TOOL_FINGER) + if (features->device_type == BTN_TOOL_PEN) { strlcat(wacom_wac->name, " Pen", WACOM_NAME_MAX); - else if (features->touch_max) - strlcat(wacom_wac->name, " Finger", WACOM_NAME_MAX); - else - strlcat(wacom_wac->name, " Pad", WACOM_NAME_MAX); + } + else if (features->device_type == BTN_TOOL_FINGER) { + if (features->touch_max) + strlcat(wacom_wac->name, " Finger", WACOM_NAME_MAX); + else + strlcat(wacom_wac->name, " Pad", WACOM_NAME_MAX); + } } static int wacom_probe(struct hid_device *hdev, -- cgit v0.10.2 From 042628abd59c9a034797bd3083f806fa17cda62d Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Thu, 30 Apr 2015 17:51:54 -0700 Subject: HID: wacom: Discover device_type from HID descriptor for all devices Currently, we assume a device_type of BTN_TOOL_PEN before scanning the HID descriptor and then change the device_type if what we discover proves that assumption wrong. This way of doing things makes it more difficult to figure out if a device (particularly a HID_GENERIC device) actually does tablet/touch input or is something completley different. This patch leaves device_type at its initial value of 0 and then calls 'wacom_parse_hid' for every device (not just those that have touch). As we map the usages, we can set the device_type as before. After we're finished, we can then check if the value is still zero and do whatever is most appropriate. Detecting the pen can be a little tricky on most Wacom devices because the descriptors describe opaque blobs. Fortunately, older Wacom tablets have the HID_DG_DIGITIZER usage on the pen's application collection and newer tablets seem to have a similar vendor-defined usage that we can trigger on. Signed-off-by: Jason Gerecke Reviewed-by: Ping Cheng Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 222baf5..157aa7a 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -181,7 +181,11 @@ static void wacom_usage_mapping(struct hid_device *hdev, * X/Y values and some cases of invalid Digitizer X/Y * values commonly reported. */ - if (!pen && !finger) + if (pen) + features->device_type = BTN_TOOL_PEN; + else if (finger) + features->device_type = BTN_TOOL_FINGER; + else return; /* @@ -198,14 +202,11 @@ static void wacom_usage_mapping(struct hid_device *hdev, case HID_GD_X: features->x_max = field->logical_maximum; if (finger) { - features->device_type = BTN_TOOL_FINGER; features->x_phy = field->physical_maximum; if (features->type != BAMBOO_PT) { features->unit = field->unit; features->unitExpo = field->unit_exponent; } - } else { - features->device_type = BTN_TOOL_PEN; } break; case HID_GD_Y: @@ -425,7 +426,6 @@ static void wacom_retrieve_hid_descriptor(struct hid_device *hdev, struct usb_interface *intf = wacom->intf; /* default features */ - features->device_type = BTN_TOOL_PEN; features->x_fuzz = 4; features->y_fuzz = 4; features->pressure_fuzz = 0; @@ -446,10 +446,6 @@ static void wacom_retrieve_hid_descriptor(struct hid_device *hdev, } } - /* only devices that support touch need to retrieve the info */ - if (features->type < BAMBOO_PT) - return; - wacom_parse_hid(hdev, features); } @@ -1529,8 +1525,15 @@ static int wacom_probe(struct hid_device *hdev, /* Retrieve the physical and logical size for touch devices */ wacom_retrieve_hid_descriptor(hdev, features); - wacom_setup_device_quirks(wacom); + + if (!features->device_type && features->type != WIRELESS) { + dev_warn(&hdev->dev, "Unknown device_type for '%s'. %s.", + hdev->name, "Assuming pen"); + + features->device_type = BTN_TOOL_PEN; + } + wacom_calculate_res(features); wacom_update_name(wacom); diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index dff99ff..a52fc25 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2186,13 +2186,15 @@ void wacom_setup_device_quirks(struct wacom *wacom) features->x_max = 4096; features->y_max = 4096; - } else { - features->device_type = BTN_TOOL_PEN; } } /* - * Same thing for Bamboo PAD + * Raw Wacom-mode pen and touch events both come from interface + * 0, whose HID descriptor has an application usage of 0xFF0D + * (i.e., WACOM_VENDORDEFINED_PEN). We route pen packets back + * out through the HID_GENERIC device created for interface 1, + * so rewrite this one to be of type BTN_TOOL_FINGER. */ if (features->type == BAMBOO_PAD) features->device_type = BTN_TOOL_FINGER; diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index f5a5f68..9a5ee62 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -72,10 +72,14 @@ #define WACOM_QUIRK_MONITOR 0x0004 #define WACOM_QUIRK_BATTERY 0x0008 +#define WACOM_VENDORDEFINED_PEN 0xff0d0001 + #define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \ ((f)->physical == HID_DG_STYLUS) || \ ((f)->physical == HID_DG_PEN) || \ - ((f)->application == HID_DG_PEN)) + ((f)->application == HID_DG_PEN) || \ + ((f)->application == HID_DG_DIGITIZER) || \ + ((f)->application == WACOM_VENDORDEFINED_PEN)) #define WACOM_FINGER_FIELD(f) (((f)->logical == HID_DG_FINGER) || \ ((f)->physical == HID_DG_FINGER) || \ ((f)->application == HID_DG_TOUCHSCREEN)) -- cgit v0.10.2 From 8e116d3169cc2b93b7eb2f44dc021a93cd3d5308 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Thu, 30 Apr 2015 17:51:55 -0700 Subject: HID: wacom: Fail probe if HID_GENERIC device has unknown device_type The last patch was careful to maintain backwards-compatible behavior by forcing device_type to BTN_TOOL_PEN (and printing a warning) if it were still uninitialized after scanning the HID descriptor and applying quirks. We should be more strict with HID_GENERIC devices, however, since there is no a priori guarantee that it is a tablet or touchpad. If the device_type is still uninitialized for a HID_GENERIC device then we assume that it isn't something the driver can work with and so fail the probe. Signed-off-by: Jason Gerecke Reviewed-by: Ping Cheng Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 157aa7a..7abf52c 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -1528,8 +1528,14 @@ static int wacom_probe(struct hid_device *hdev, wacom_setup_device_quirks(wacom); if (!features->device_type && features->type != WIRELESS) { + error = features->type == HID_GENERIC ? -ENODEV : 0; + dev_warn(&hdev->dev, "Unknown device_type for '%s'. %s.", - hdev->name, "Assuming pen"); + hdev->name, + error ? "Ignoring" : "Assuming pen"); + + if (error) + goto fail_shared_data; features->device_type = BTN_TOOL_PEN; } -- cgit v0.10.2 From 181a8b911dd26cd44dc7283d7953a2e138842767 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 1 May 2015 16:22:45 -0400 Subject: HID: lenovo: add support for Lenovo ThinkPad Keyboard Pro unit This dock is used with the Thinkpad Helix 2 but suffers from an error in the report descriptor where an usage max is 65535. Add a report fixup for it and make the keyboard working. Tested-by: Jonathan Oppenheim Tested-by: John Reid Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 722a925..c2baf8c 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1851,6 +1851,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) }, { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CUSBKBD) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CBTKBD) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPPRODOCK) }, #endif { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 41f167e..1649436 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -585,6 +585,7 @@ #define USB_DEVICE_ID_LENOVO_TPKBD 0x6009 #define USB_DEVICE_ID_LENOVO_CUSBKBD 0x6047 #define USB_DEVICE_ID_LENOVO_CBTKBD 0x6048 +#define USB_DEVICE_ID_LENOVO_TPPRODOCK 0x6067 #define USB_VENDOR_ID_LG 0x1fd2 #define USB_DEVICE_ID_LG_MULTITOUCH 0x0064 diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c index 78608d6..4e291d5 100644 --- a/drivers/hid/hid-lenovo.c +++ b/drivers/hid/hid-lenovo.c @@ -43,6 +43,35 @@ struct lenovo_drvdata_cptkbd { #define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c)) +static const __u8 lenovo_pro_dock_need_fixup_collection[] = { + 0x05, 0x88, /* Usage Page (Vendor Usage Page 0x88) */ + 0x09, 0x01, /* Usage (Vendor Usage 0x01) */ + 0xa1, 0x01, /* Collection (Application) */ + 0x85, 0x04, /* Report ID (4) */ + 0x19, 0x00, /* Usage Minimum (0) */ + 0x2a, 0xff, 0xff, /* Usage Maximum (65535) */ +}; + +static __u8 *lenovo_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) +{ + switch (hdev->product) { + case USB_DEVICE_ID_LENOVO_TPPRODOCK: + /* the fixups that need to be done: + * - get a reasonable usage max for the vendor collection + * 0x8801 from the report ID 4 + */ + if (*rsize >= 153 && + memcmp(&rdesc[140], lenovo_pro_dock_need_fixup_collection, + sizeof(lenovo_pro_dock_need_fixup_collection)) == 0) { + rdesc[151] = 0x01; + rdesc[152] = 0x00; + } + break; + } + return rdesc; +} + static int lenovo_input_mapping_tpkbd(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) @@ -784,6 +813,7 @@ static const struct hid_device_id lenovo_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) }, { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CUSBKBD) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CBTKBD) }, + { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPPRODOCK) }, { } }; @@ -797,6 +827,7 @@ static struct hid_driver lenovo_driver = { .probe = lenovo_probe, .remove = lenovo_remove, .raw_event = lenovo_raw_event, + .report_fixup = lenovo_report_fixup, }; module_hid_driver(lenovo_driver); -- cgit v0.10.2 From e03930620ae856a6ed79007207337d10011ecb36 Mon Sep 17 00:00:00 2001 From: Nicholas Mc Guire Date: Sat, 2 May 2015 17:55:15 +0200 Subject: HID: make timeout HZ independent wait_event_interruptible_timeout() expects a timeout in jiffies so the numeric constant becomes HZ dependent - put it through msecs_to_jiffies() to make it HZ independent. Signed-off-by: Nicholas Mc Guire Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index b86c18e..2671de9 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -700,7 +700,8 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) /* insert a little delay of 10 jiffies ~ 40ms */ wait_queue_head_t wait; init_waitqueue_head (&wait); - wait_event_interruptible_timeout(wait, 0, 10); + wait_event_interruptible_timeout(wait, 0, + msecs_to_jiffies(40)); /* Select random Address */ buf[1] = 0xB2; -- cgit v0.10.2 From c6f2104caaf00720a3a7a456af07f93a160693af Mon Sep 17 00:00:00 2001 From: Jiri Slaby Date: Tue, 5 May 2015 10:09:53 +0200 Subject: HID: prodikeys: remove unused variable 'key' is set but never used in the first loop. So remove the set. And indent the re-set of pm->last_key properly. Signed-off-by: Jiri Slaby Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c index 91fab97..e3e98cc 100644 --- a/drivers/hid/hid-prodikeys.c +++ b/drivers/hid/hid-prodikeys.c @@ -395,11 +395,10 @@ static int pcmidi_handle_report4(struct pcmidi_snd *pm, u8 *data) /* break keys */ for (bit_index = 0; bit_index < 24; bit_index++) { - key = pm->last_key[bit_index]; if (!((0x01 << bit_index) & bit_mask)) { input_event(pm->input_ep82, EV_KEY, pm->last_key[bit_index], 0); - pm->last_key[bit_index] = 0; + pm->last_key[bit_index] = 0; } } -- cgit v0.10.2 From 131a8a9a56f16d8d237b39a8677ccee44a355392 Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Tue, 5 May 2015 20:47:28 -0400 Subject: HID: sony: Prevent the freeing of an unitialized ida value sony_allocate_output_report() was being called before sony_set_device_id() which meant that an unallocated ida value was was freed if the output report allocation failed and the probe function jumped to err_stop. Do the device ID allocation before the output report allocation to avoid freeing an unallocated value in case of a failure. Signed-off-by: Frank Praznik Acked-by: Pavel Machek Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 6ca96ce..4c521b2 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -1993,15 +1993,15 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) return ret; } - ret = sony_allocate_output_report(sc); + ret = sony_set_device_id(sc); if (ret < 0) { - hid_err(hdev, "failed to allocate the output report buffer\n"); + hid_err(hdev, "failed to allocate the device id\n"); goto err_stop; } - ret = sony_set_device_id(sc); + ret = sony_allocate_output_report(sc); if (ret < 0) { - hid_err(hdev, "failed to allocate the device id\n"); + hid_err(hdev, "failed to allocate the output report buffer\n"); goto err_stop; } -- cgit v0.10.2 From 7c886d098d6128438e706ca4c068b8920fdac42d Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Tue, 5 May 2015 20:47:29 -0400 Subject: HID: sony: Add the product ID for the Sony Motion Controller Adds the PID for the Sony motion controller to the hardware ID list. Signed-off-by: Pavel Machek Signed-off-by: Frank Praznik Acked-by: Pavel Machek Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 722a925..2cb9ac7 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1961,6 +1961,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_BDREMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_MOTION_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 41f167e..14fcb11 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -851,6 +851,7 @@ #define USB_DEVICE_ID_SONY_PS3_BDREMOTE 0x0306 #define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268 #define USB_DEVICE_ID_SONY_PS4_CONTROLLER 0x05c4 +#define USB_DEVICE_ID_SONY_MOTION_CONTROLLER 0x03d5 #define USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER 0x042f #define USB_DEVICE_ID_SONY_BUZZ_CONTROLLER 0x0002 #define USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER 0x1000 -- cgit v0.10.2 From c5e0c1c4950f9126f7eb2fb1d3f8aa4080f05538 Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Tue, 5 May 2015 20:47:30 -0400 Subject: HID: sony: Add support for the Sony Motion Controller Add a fixed-up HID descriptor for the Sony motion controller and enable controls for the LED light as well as force-feedback. The LED is multi-colored (red, green, blue). The motion controller has a single rumble motor so the higher of the left and right values is used to set the speed. Signed-off-by: Pavel Machek Signed-off-by: Frank Praznik Acked-by: Pavel Machek Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 4c521b2..d0b18a5 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -46,14 +46,16 @@ #define PS3REMOTE BIT(4) #define DUALSHOCK4_CONTROLLER_USB BIT(5) #define DUALSHOCK4_CONTROLLER_BT BIT(6) +#define MOTION_CONTROLLER BIT(7) #define SIXAXIS_CONTROLLER (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT) #define DUALSHOCK4_CONTROLLER (DUALSHOCK4_CONTROLLER_USB |\ DUALSHOCK4_CONTROLLER_BT) #define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER | BUZZ_CONTROLLER |\ - DUALSHOCK4_CONTROLLER) + DUALSHOCK4_CONTROLLER | MOTION_CONTROLLER) #define SONY_BATTERY_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER) -#define SONY_FF_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER) +#define SONY_FF_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER |\ + MOTION_CONTROLLER) #define MAX_LEDS 4 @@ -134,6 +136,85 @@ static __u8 sixaxis_rdesc[] = { 0xC0 /* End Collection */ }; +/* PS/3 Motion controller */ +static __u8 motion_rdesc[] = { + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x04, /* Usage (Joystick), */ + 0xA1, 0x01, /* Collection (Application), */ + 0xA1, 0x02, /* Collection (Logical), */ + 0x85, 0x01, /* Report ID (1), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x01, /* Report Count (1), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ + 0x81, 0x03, /* Input (Constant, Variable), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x13, /* Report Count (19), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x35, 0x00, /* Physical Minimum (0), */ + 0x45, 0x01, /* Physical Maximum (1), */ + 0x05, 0x09, /* Usage Page (Button), */ + 0x19, 0x01, /* Usage Minimum (01h), */ + 0x29, 0x13, /* Usage Maximum (13h), */ + 0x81, 0x02, /* Input (Variable), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x0D, /* Report Count (13), */ + 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ + 0x81, 0x03, /* Input (Constant, Variable), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0xA1, 0x00, /* Collection (Physical), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x04, /* Report Count (4), */ + 0x35, 0x00, /* Physical Minimum (0), */ + 0x46, 0xFF, 0x00, /* Physical Maximum (255), */ + 0x09, 0x30, /* Usage (X), */ + 0x09, 0x31, /* Usage (Y), */ + 0x09, 0x32, /* Usage (Z), */ + 0x09, 0x35, /* Usage (Rz), */ + 0x81, 0x02, /* Input (Variable), */ + 0xC0, /* End Collection, */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x95, 0x13, /* Report Count (19), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x0C, /* Report Count (12), */ + 0x81, 0x01, /* Input (Constant), */ + 0x75, 0x10, /* Report Size (16), */ + 0x95, 0x04, /* Report Count (4), */ + 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ + 0x46, 0xFF, 0x03, /* Physical Maximum (1023), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0x81, 0x02, /* Input (Variable), */ + 0xC0, /* End Collection, */ + 0xA1, 0x02, /* Collection (Logical), */ + 0x85, 0x02, /* Report ID (2), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x30, /* Report Count (48), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0xC0, /* End Collection, */ + 0xA1, 0x02, /* Collection (Logical), */ + 0x85, 0xEE, /* Report ID (238), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x30, /* Report Count (48), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0xC0, /* End Collection, */ + 0xA1, 0x02, /* Collection (Logical), */ + 0x85, 0xEF, /* Report ID (239), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x30, /* Report Count (48), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0xC0, /* End Collection, */ + 0xC0 /* End Collection */ +}; + + /* * The default descriptor doesn't provide mapping for the accelerometers * or orientation sensors. This fixed descriptor maps the accelerometers @@ -798,6 +879,13 @@ union sixaxis_output_report_01 { __u8 buf[36]; }; +struct motion_output_report_02 { + u8 type, zero; + u8 r, g, b; + u8 zero2; + u8 rumble; +}; + #define DS4_REPORT_0x02_SIZE 37 #define DS4_REPORT_0x05_SIZE 32 #define DS4_REPORT_0x11_SIZE 78 @@ -844,6 +932,13 @@ static __u8 *sixaxis_fixup(struct hid_device *hdev, __u8 *rdesc, return sixaxis_rdesc; } +static u8 *motion_fixup(struct hid_device *hdev, u8 *rdesc, + unsigned int *rsize) +{ + *rsize = sizeof(motion_rdesc); + return motion_rdesc; +} + static __u8 *ps3remote_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { @@ -924,6 +1019,9 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc, if (sc->quirks & SIXAXIS_CONTROLLER) return sixaxis_fixup(hdev, rdesc, rsize); + if (sc->quirks & MOTION_CONTROLLER) + return motion_fixup(hdev, rdesc, rsize); + if (sc->quirks & PS3REMOTE) return ps3remote_fixup(hdev, rdesc, rsize); @@ -1454,6 +1552,12 @@ static int sony_leds_init(struct sony_sc *sc) use_ds4_names = 1; name_len = 0; name_fmt = "%s:%s"; + } else if (sc->quirks & MOTION_CONTROLLER) { + sc->led_count = 3; + memset(max_brightness, 255, 3); + use_ds4_names = 1; + name_len = 0; + name_fmt = "%s:%s"; } else { sixaxis_set_leds_from_id(sc->device_id, initial_values); sc->led_count = 4; @@ -1622,6 +1726,28 @@ static void dualshock4_state_worker(struct work_struct *work) HID_OUTPUT_REPORT, HID_REQ_SET_REPORT); } +static void motion_state_worker(struct work_struct *work) +{ + struct sony_sc *sc = container_of(work, struct sony_sc, state_worker); + struct hid_device *hdev = sc->hdev; + struct motion_output_report_02 *report = + (struct motion_output_report_02 *)sc->output_report_dmabuf; + + memset(report, 0, sizeof(struct motion_output_report_02)); + + report->type = 0x02; /* set leds */ + report->r = sc->led_state[0]; + report->g = sc->led_state[1]; + report->b = sc->led_state[2]; + +#ifdef CONFIG_SONY_FF + report->rumble = max(sc->right, sc->left); +#endif + + hid_hw_output_report(hdev, (__u8 *)report, + sizeof(struct motion_output_report_02)); +} + static int sony_allocate_output_report(struct sony_sc *sc) { if (sc->quirks & SIXAXIS_CONTROLLER) @@ -1634,6 +1760,10 @@ static int sony_allocate_output_report(struct sony_sc *sc) else if (sc->quirks & DUALSHOCK4_CONTROLLER_USB) sc->output_report_dmabuf = kmalloc(DS4_REPORT_0x05_SIZE, GFP_KERNEL); + else if (sc->quirks & MOTION_CONTROLLER) + sc->output_report_dmabuf = + kmalloc(sizeof(struct motion_output_report_02), + GFP_KERNEL); else return 0; @@ -2043,6 +2173,8 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) } sony_init_work(sc, dualshock4_state_worker); + } else if (sc->quirks & MOTION_CONTROLLER) { + sony_init_work(sc, motion_state_worker); } else { ret = 0; } @@ -2123,6 +2255,8 @@ static const struct hid_device_id sony_devices[] = { .driver_data = SIXAXIS_CONTROLLER_USB }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER), .driver_data = SIXAXIS_CONTROLLER_USB }, + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_MOTION_CONTROLLER), + .driver_data = MOTION_CONTROLLER }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER), .driver_data = SIXAXIS_CONTROLLER_BT }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE), -- cgit v0.10.2 From 8f069fdf5bbc6b300f9c88801d0d858d2a4d46e6 Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Tue, 5 May 2015 20:47:31 -0400 Subject: HID: sony: Correct Sony device ordering Rearrange Sony controller devices into alphabetical order in the hardware device list. Signed-off-by: Frank Praznik Acked-by: Pavel Machek Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 2cb9ac7..aefb248 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1959,10 +1959,10 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SMK, USB_DEVICE_ID_SMK_PS3_BDREMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_BUZZ_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_BDREMOTE) }, - { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_MOTION_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_BDREMOTE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER) }, -- cgit v0.10.2 From 221399b36535752351d4631606b427daca3dc35c Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Tue, 5 May 2015 20:47:32 -0400 Subject: HID: sony: Simplify LED initialization and eliminate redundant copies when updating LED states Directly set the initial LED states in the device state struct instead of copying them from a temporary array. This allows for the removal of a redundant "x = x" copy loop in sony_set_leds() that was taking place any time an LED was updated. It also allows for the simplifying of the parameters in functions dealing with LED initialization and updates since only a pointer to the sony_sc struct is needed now. Signed-off-by: Frank Praznik Acked-by: Pavel Machek Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index d0b18a5..9370509 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -1306,7 +1306,7 @@ static int dualshock4_set_operational_bt(struct hid_device *hdev) return ret; } -static void sixaxis_set_leds_from_id(int id, __u8 values[MAX_LEDS]) +static void sixaxis_set_leds_from_id(struct sony_sc *sc) { static const __u8 sixaxis_leds[10][4] = { { 0x01, 0x00, 0x00, 0x00 }, @@ -1321,16 +1321,18 @@ static void sixaxis_set_leds_from_id(int id, __u8 values[MAX_LEDS]) { 0x01, 0x01, 0x01, 0x01 } }; - BUG_ON(MAX_LEDS < ARRAY_SIZE(sixaxis_leds[0])); + int id = sc->device_id; + + BUILD_BUG_ON(MAX_LEDS < ARRAY_SIZE(sixaxis_leds[0])); if (id < 0) return; id %= 10; - memcpy(values, sixaxis_leds[id], sizeof(sixaxis_leds[id])); + memcpy(sc->led_state, sixaxis_leds[id], sizeof(sixaxis_leds[id])); } -static void dualshock4_set_leds_from_id(int id, __u8 values[MAX_LEDS]) +static void dualshock4_set_leds_from_id(struct sony_sc *sc) { /* The first 4 color/index entries match what the PS4 assigns */ static const __u8 color_code[7][3] = { @@ -1343,46 +1345,44 @@ static void dualshock4_set_leds_from_id(int id, __u8 values[MAX_LEDS]) /* White */ { 0x01, 0x01, 0x01 } }; - BUG_ON(MAX_LEDS < ARRAY_SIZE(color_code[0])); + int id = sc->device_id; + + BUILD_BUG_ON(MAX_LEDS < ARRAY_SIZE(color_code[0])); if (id < 0) return; id %= 7; - memcpy(values, color_code[id], sizeof(color_code[id])); + memcpy(sc->led_state, color_code[id], sizeof(color_code[id])); } -static void buzz_set_leds(struct hid_device *hdev, const __u8 *leds) +static void buzz_set_leds(struct sony_sc *sc) { + struct hid_device *hdev = sc->hdev; struct list_head *report_list = &hdev->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report = list_entry(report_list->next, struct hid_report, list); __s32 *value = report->field[0]->value; + BUILD_BUG_ON(MAX_LEDS < 4); + value[0] = 0x00; - value[1] = leds[0] ? 0xff : 0x00; - value[2] = leds[1] ? 0xff : 0x00; - value[3] = leds[2] ? 0xff : 0x00; - value[4] = leds[3] ? 0xff : 0x00; + value[1] = sc->led_state[0] ? 0xff : 0x00; + value[2] = sc->led_state[1] ? 0xff : 0x00; + value[3] = sc->led_state[2] ? 0xff : 0x00; + value[4] = sc->led_state[3] ? 0xff : 0x00; value[5] = 0x00; value[6] = 0x00; hid_hw_request(hdev, report, HID_REQ_SET_REPORT); } -static void sony_set_leds(struct sony_sc *sc, const __u8 *leds, int count) +static void sony_set_leds(struct sony_sc *sc) { - int n; - - BUG_ON(count > MAX_LEDS); - - if (sc->quirks & BUZZ_CONTROLLER && count == 4) { - buzz_set_leds(sc->hdev, leds); - } else { - for (n = 0; n < count; n++) - sc->led_state[n] = leds[n]; + if (!(sc->quirks & BUZZ_CONTROLLER)) schedule_work(&sc->state_worker); - } + else + buzz_set_leds(sc); } static void sony_led_set_brightness(struct led_classdev *led, @@ -1422,8 +1422,7 @@ static void sony_led_set_brightness(struct led_classdev *led, drv_data->led_delay_on[n] = 0; drv_data->led_delay_off[n] = 0; - sony_set_leds(drv_data, drv_data->led_state, - drv_data->led_count); + sony_set_leds(drv_data); break; } } @@ -1529,7 +1528,6 @@ static int sony_leds_init(struct sony_sc *sc) const char *name_fmt; static const char * const ds4_name_str[] = { "red", "green", "blue", "global" }; - __u8 initial_values[MAX_LEDS] = { 0 }; __u8 max_brightness[MAX_LEDS] = { [0 ... (MAX_LEDS - 1)] = 1 }; __u8 use_hw_blink[MAX_LEDS] = { 0 }; @@ -1544,8 +1542,8 @@ static int sony_leds_init(struct sony_sc *sc) if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 0, 0, 7)) return -ENODEV; } else if (sc->quirks & DUALSHOCK4_CONTROLLER) { - dualshock4_set_leds_from_id(sc->device_id, initial_values); - initial_values[3] = 1; + dualshock4_set_leds_from_id(sc); + sc->led_state[3] = 1; sc->led_count = 4; memset(max_brightness, 255, 3); use_hw_blink[3] = 1; @@ -1559,7 +1557,7 @@ static int sony_leds_init(struct sony_sc *sc) name_len = 0; name_fmt = "%s:%s"; } else { - sixaxis_set_leds_from_id(sc->device_id, initial_values); + sixaxis_set_leds_from_id(sc); sc->led_count = 4; memset(use_hw_blink, 1, 4); use_ds4_names = 0; @@ -1572,7 +1570,7 @@ static int sony_leds_init(struct sony_sc *sc) * only relevant if the driver is loaded after somebody actively set the * LEDs to on */ - sony_set_leds(sc, initial_values, sc->led_count); + sony_set_leds(sc); name_sz = strlen(dev_name(&hdev->dev)) + name_len + 1; @@ -1595,7 +1593,7 @@ static int sony_leds_init(struct sony_sc *sc) else snprintf(name, name_sz, name_fmt, dev_name(&hdev->dev), n + 1); led->name = name; - led->brightness = initial_values[n]; + led->brightness = sc->led_state[n]; led->max_brightness = max_brightness[n]; led->brightness_get = sony_led_get_brightness; led->brightness_set = sony_led_set_brightness; -- cgit v0.10.2 From 4c3e829849cc05f82c11fe9a3c662c7e1323d6cf Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Tue, 5 May 2015 20:47:33 -0400 Subject: HID: sony: Correct a typo in a HID descriptor comment and explain the odd Sixaxis axis mapping Correct a spelling mistake in the Sixaxis HID descriptor comment. Add an explanation as to why the Sixaxis has so many analog axes and why some of them are seen as multi-touch axes. Signed-off-by: Frank Praznik Acked-by: Pavel Machek Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 9370509..aeb8b41 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -59,9 +59,16 @@ #define MAX_LEDS 4 +/* + * The Sixaxis reports both digital and analog values for each button on the + * controller except for Start, Select and the PS button. The controller ends + * up reporting 27 axes which causes them to spill over into the multi-touch + * axis values. Additionally, the controller only has 20 actual, physical axes + * so there are several unused axes in between the used ones. + */ static __u8 sixaxis_rdesc[] = { 0x05, 0x01, /* Usage Page (Desktop), */ - 0x09, 0x04, /* Usage (Joystik), */ + 0x09, 0x04, /* Usage (Joystick), */ 0xA1, 0x01, /* Collection (Application), */ 0xA1, 0x02, /* Collection (Logical), */ 0x85, 0x01, /* Report ID (1), */ -- cgit v0.10.2 From 6e5e9a06a206010eabd19b523fd0833c51afc0b0 Mon Sep 17 00:00:00 2001 From: Sean Young Date: Wed, 6 May 2015 21:38:42 +0100 Subject: HID: sjoy: support Super Joy Box 4 This device supports force feedback and has two ports. Signed-off-by: Sean Young Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 722a925..1ec1e4d 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1997,6 +1997,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_3_PRO) }, { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_DUAL_BOX_PRO) }, { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SUPER_JOY_BOX_5_PRO) }, + { HID_USB_DEVICE(USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII) }, { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_Q_PAD) }, diff --git a/drivers/hid/hid-sjoy.c b/drivers/hid/hid-sjoy.c index 37845ec..36b6470 100644 --- a/drivers/hid/hid-sjoy.c +++ b/drivers/hid/hid-sjoy.c @@ -166,6 +166,9 @@ static const struct hid_device_id sjoy_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_DUAL_USB_JOYPAD), .driver_data = HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, + { HID_USB_DEVICE(USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII), + .driver_data = HID_QUIRK_MULTI_INPUT | + HID_QUIRK_SKIP_OUTPUT_REPORTS }, { } }; MODULE_DEVICE_TABLE(hid, sjoy_devices); diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index a775143..ac12a36 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -52,7 +52,6 @@ static const struct hid_blacklist { { USB_VENDOR_ID_ETURBOTOUCH, USB_DEVICE_ID_ETURBOTOUCH_2968, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_GREENASIA, USB_DEVICE_ID_GREENASIA_DUAL_USB_JOYPAD, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS }, - { USB_VENDOR_ID_PLAYDOTCOM, USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_TOUCHPACK, USB_DEVICE_ID_TOUCHPACK_RTS, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_AIREN, USB_DEVICE_ID_AIREN_SLIMPLUS, HID_QUIRK_NOGET }, -- cgit v0.10.2 From 2a552c30b2e44578b8d063e55b717ba94df84667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Mal=C3=BD?= Date: Wed, 8 Apr 2015 22:56:39 +0200 Subject: HID: hid-lg4ff: Remove double underscore prefix from numeric types MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove double underscore prefix from numeric types. This code will never be used outside the kernel so the prefixes are unnecessary. Signed-off-by: Michal Malý Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index 1232210..70e5ae6 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -72,12 +72,12 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range); static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range); struct lg4ff_device_entry { - __u32 product_id; - __u16 range; - __u16 min_range; - __u16 max_range; + u32 product_id; + u16 range; + u16 min_range; + u16 max_range; #ifdef CONFIG_LEDS_CLASS - __u8 led_state; + u8 led_state; struct led_classdev *led[5]; #endif u32 alternate_modes; @@ -95,16 +95,16 @@ static const signed short lg4ff_wheel_effects[] = { }; struct lg4ff_wheel { - const __u32 product_id; + const u32 product_id; const signed short *ff_effects; - const __u16 min_range; - const __u16 max_range; + const u16 min_range; + const u16 max_range; void (*set_range)(struct hid_device *hid, u16 range); }; struct lg4ff_compat_mode_switch { - const __u8 cmd_count; /* Number of commands to send */ - const __u8 cmd[]; + const u8 cmd_count; /* Number of commands to send */ + const u8 cmd[]; }; struct lg4ff_wheel_ident_info { @@ -245,10 +245,10 @@ static const struct lg4ff_compat_mode_switch lg4ff_mode_switch_ext16_g25 = { }; /* Recalculates X axis value accordingly to currently selected range */ -static __s32 lg4ff_adjust_dfp_x_axis(__s32 value, __u16 range) +static s32 lg4ff_adjust_dfp_x_axis(s32 value, u16 range) { - __u16 max_range; - __s32 new_value; + u16 max_range; + s32 new_value; if (range == 900) return value; @@ -269,10 +269,10 @@ static __s32 lg4ff_adjust_dfp_x_axis(__s32 value, __u16 range) } int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field, - struct hid_usage *usage, __s32 value, struct lg_drv_data *drv_data) + struct hid_usage *usage, s32 value, struct lg_drv_data *drv_data) { struct lg4ff_device_entry *entry = drv_data->device_props; - __s32 new_value = 0; + s32 new_value = 0; if (!entry) { hid_err(hid, "Device properties not found"); @@ -299,7 +299,7 @@ static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *e struct hid_device *hid = input_get_drvdata(dev); struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report = list_entry(report_list->next, struct hid_report, list); - __s32 *value = report->field[0]->value; + s32 *value = report->field[0]->value; int x; #define CLAMP(x) do { if (x < 0) x = 0; else if (x > 0xff) x = 0xff; } while (0) @@ -344,8 +344,8 @@ static void hid_lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitud struct hid_device *hid = input_get_drvdata(dev); struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report = list_entry(report_list->next, struct hid_report, list); - __s32 *value = report->field[0]->value; - __u32 expand_a, expand_b; + s32 *value = report->field[0]->value; + u32 expand_a, expand_b; struct lg4ff_device_entry *entry; struct lg_drv_data *drv_data; @@ -421,7 +421,7 @@ static void hid_lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude) struct hid_device *hid = input_get_drvdata(dev); struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report = list_entry(report_list->next, struct hid_report, list); - __s32 *value = report->field[0]->value; + s32 *value = report->field[0]->value; magnitude = magnitude * 90 / 65535; value[0] = 0xfe; @@ -440,7 +440,7 @@ static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range) { struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report = list_entry(report_list->next, struct hid_report, list); - __s32 *value = report->field[0]->value; + s32 *value = report->field[0]->value; dbg_hid("G25/G27/DFGT: setting range to %u\n", range); @@ -456,12 +456,12 @@ static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range) } /* Sends commands to set range compatible with Driving Force Pro wheel */ -static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range) +static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range) { struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report = list_entry(report_list->next, struct hid_report, list); int start_left, start_right, full_range; - __s32 *value = report->field[0]->value; + s32 *value = report->field[0]->value; dbg_hid("Driving Force Pro: setting range to %u\n", range); @@ -571,7 +571,7 @@ static int lg4ff_switch_compatibility_mode(struct hid_device *hid, const struct { struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report = list_entry(report_list->next, struct hid_report, list); - __s32 *value = report->field[0]->value; + s32 *value = report->field[0]->value; u8 i; for (i = 0; i < s->cmd_count; i++) { @@ -754,7 +754,7 @@ static ssize_t range_store(struct device *dev, struct device_attribute *attr, struct hid_device *hid = to_hid_device(dev); struct lg4ff_device_entry *entry; struct lg_drv_data *drv_data; - __u16 range = simple_strtoul(buf, NULL, 10); + u16 range = simple_strtoul(buf, NULL, 10); drv_data = hid_get_drvdata(hid); if (!drv_data) { @@ -818,11 +818,11 @@ static ssize_t lg4ff_real_id_store(struct device *dev, struct device_attribute * static DEVICE_ATTR(real_id, S_IRUGO, lg4ff_real_id_show, lg4ff_real_id_store); #ifdef CONFIG_LEDS_CLASS -static void lg4ff_set_leds(struct hid_device *hid, __u8 leds) +static void lg4ff_set_leds(struct hid_device *hid, u8 leds) { struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report = list_entry(report_list->next, struct hid_report, list); - __s32 *value = report->field[0]->value; + s32 *value = report->field[0]->value; value[0] = 0xf8; value[1] = 0x12; diff --git a/drivers/hid/hid-lg4ff.h b/drivers/hid/hid-lg4ff.h index 5b6a508..66201af 100644 --- a/drivers/hid/hid-lg4ff.h +++ b/drivers/hid/hid-lg4ff.h @@ -5,12 +5,12 @@ extern int lg4ff_no_autoswitch; /* From hid-lg.c */ int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field, - struct hid_usage *usage, __s32 value, struct lg_drv_data *drv_data); + struct hid_usage *usage, s32 value, struct lg_drv_data *drv_data); int lg4ff_init(struct hid_device *hdev); int lg4ff_deinit(struct hid_device *hdev); #else static inline int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field, - struct hid_usage *usage, __s32 value, struct lg_drv_data *drv_data) { return 0; } + struct hid_usage *usage, s32 value, struct lg_drv_data *drv_data) { return 0; } static inline int lg4ff_init(struct hid_device *hdev) { return -1; } static inline int lg4ff_deinit(struct hid_device *hdev) { return -1; } #endif -- cgit v0.10.2 From d0afd84893ebdbbe6dc022514cd6b62fbc90a034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Mal=C3=BD?= Date: Wed, 8 Apr 2015 22:56:40 +0200 Subject: HID: hid-lg4ff: Remove "hid_" prefix from some functions' names MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove "hid_" prefix from some functions' names. All internal functions of hid-lg4ff should be prefixed with just "lg4ff_" Signed-off-by: Michal Malý Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index 70e5ae6..9a0c0e5 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -68,8 +68,8 @@ #define LG4FF_FFEX_REV_MAJ 0x21 #define LG4FF_FFEX_REV_MIN 0x00 -static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range); -static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range); +static void lg4ff_set_range_dfp(struct hid_device *hid, u16 range); +static void lg4ff_set_range_g25(struct hid_device *hid, u16 range); struct lg4ff_device_entry { u32 product_id; @@ -134,10 +134,10 @@ struct lg4ff_alternate_mode { static const struct lg4ff_wheel lg4ff_devices[] = { {USB_DEVICE_ID_LOGITECH_WHEEL, lg4ff_wheel_effects, 40, 270, NULL}, {USB_DEVICE_ID_LOGITECH_MOMO_WHEEL, lg4ff_wheel_effects, 40, 270, NULL}, - {USB_DEVICE_ID_LOGITECH_DFP_WHEEL, lg4ff_wheel_effects, 40, 900, hid_lg4ff_set_range_dfp}, - {USB_DEVICE_ID_LOGITECH_G25_WHEEL, lg4ff_wheel_effects, 40, 900, hid_lg4ff_set_range_g25}, - {USB_DEVICE_ID_LOGITECH_DFGT_WHEEL, lg4ff_wheel_effects, 40, 900, hid_lg4ff_set_range_g25}, - {USB_DEVICE_ID_LOGITECH_G27_WHEEL, lg4ff_wheel_effects, 40, 900, hid_lg4ff_set_range_g25}, + {USB_DEVICE_ID_LOGITECH_DFP_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_dfp}, + {USB_DEVICE_ID_LOGITECH_G25_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25}, + {USB_DEVICE_ID_LOGITECH_DFGT_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25}, + {USB_DEVICE_ID_LOGITECH_G27_WHEEL, lg4ff_wheel_effects, 40, 900, lg4ff_set_range_g25}, {USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2, lg4ff_wheel_effects, 40, 270, NULL}, {USB_DEVICE_ID_LOGITECH_WII_WHEEL, lg4ff_wheel_effects, 40, 270, NULL} }; @@ -294,7 +294,7 @@ int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field, } } -static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *effect) +static int lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *effect) { struct hid_device *hid = input_get_drvdata(dev); struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; @@ -339,7 +339,7 @@ static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *e /* Sends default autocentering command compatible with * all wheels except Formula Force EX */ -static void hid_lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitude) +static void lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitude) { struct hid_device *hid = input_get_drvdata(dev); struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; @@ -416,7 +416,7 @@ static void hid_lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitud } /* Sends autocentering command compatible with Formula Force EX */ -static void hid_lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude) +static void lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude) { struct hid_device *hid = input_get_drvdata(dev); struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; @@ -436,7 +436,7 @@ static void hid_lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude) } /* Sends command to set range compatible with G25/G27/Driving Force GT */ -static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range) +static void lg4ff_set_range_g25(struct hid_device *hid, u16 range) { struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report = list_entry(report_list->next, struct hid_report, list); @@ -456,7 +456,7 @@ static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range) } /* Sends commands to set range compatible with Driving Force Pro wheel */ -static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range) +static void lg4ff_set_range_dfp(struct hid_device *hid, u16 range) { struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report = list_entry(report_list->next, struct hid_report, list); @@ -1043,7 +1043,7 @@ int lg4ff_init(struct hid_device *hid) for (j = 0; lg4ff_devices[i].ff_effects[j] >= 0; j++) set_bit(lg4ff_devices[i].ff_effects[j], dev->ffbit); - error = input_ff_create_memless(dev, NULL, hid_lg4ff_play); + error = input_ff_create_memless(dev, NULL, lg4ff_play); if (error) return error; @@ -1081,9 +1081,9 @@ int lg4ff_init(struct hid_device *hid) /* Formula Force EX expects different autocentering command */ if ((bcdDevice >> 8) == LG4FF_FFEX_REV_MAJ && (bcdDevice & 0xff) == LG4FF_FFEX_REV_MIN) - dev->ff->set_autocenter = hid_lg4ff_set_autocenter_ffex; + dev->ff->set_autocenter = lg4ff_set_autocenter_ffex; else - dev->ff->set_autocenter = hid_lg4ff_set_autocenter_default; + dev->ff->set_autocenter = lg4ff_set_autocenter_default; dev->ff->set_autocenter(dev, 0); } -- cgit v0.10.2 From fbf85e2ad1ade7bcc9efa0557c19bea5fffd192a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Mal=C3=BD?= Date: Wed, 8 Apr 2015 22:56:41 +0200 Subject: HID: hid-lg4ff: Replace DEVICE_ATTR_RW with DEVICE_ATTR to have all internal functions prefixed with "lg4ff_" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace DEVICE_ATTR_RW with DEVICE_ATTR to have all internal functions prefixed with "lg4ff_". All internal functions should be prefixed with just "lg4ff_". Usage of DEVICE_ATTR_RW breaks this scheme because it expects the functions' names to match the name of the respective sysfs entry. This partially reverts "2f1cec3250e38609bf9252db52dbbe61603c04a7" Signed-off-by: Michal Malý Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index 9a0c0e5..cec84a5 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -721,9 +721,9 @@ static ssize_t lg4ff_alternate_modes_store(struct device *dev, struct device_att } static DEVICE_ATTR(alternate_modes, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, lg4ff_alternate_modes_show, lg4ff_alternate_modes_store); -/* Read current range and display it in terminal */ -static ssize_t range_show(struct device *dev, struct device_attribute *attr, - char *buf) +/* Export the currently set range of the wheel */ +static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *attr, + char *buf) { struct hid_device *hid = to_hid_device(dev); struct lg4ff_device_entry *entry; @@ -748,8 +748,8 @@ static ssize_t range_show(struct device *dev, struct device_attribute *attr, /* Set range to user specified value, call appropriate function * according to the type of the wheel */ -static ssize_t range_store(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) +static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) { struct hid_device *hid = to_hid_device(dev); struct lg4ff_device_entry *entry; @@ -780,7 +780,7 @@ static ssize_t range_store(struct device *dev, struct device_attribute *attr, return count; } -static DEVICE_ATTR_RW(range); +static DEVICE_ATTR(range, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, lg4ff_range_show, lg4ff_range_store); static ssize_t lg4ff_real_id_show(struct device *dev, struct device_attribute *attr, char *buf) { -- cgit v0.10.2 From 0a33a7bcb5af29f8936b49dfe7b2b5bc932ad03d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Mal=C3=BD?= Date: Wed, 8 Apr 2015 22:56:42 +0200 Subject: HID: hid-lg4ff: Remove unused variable from the "lg4ff_device_entry" struct. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove unused variable from the "lg4ff_device_entry" struct. This is a leftover from times where hid_get|set_drvdata() was not available to hid-lg4ff so it had to keep track of the devices it managed by itself. Signed-off-by: Michal Malý Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index cec84a5..d1d5d45 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -84,7 +84,6 @@ struct lg4ff_device_entry { const char *real_tag; const char *real_name; u16 real_product_id; - struct list_head list; void (*set_range)(struct hid_device *hid, u16 range); }; -- cgit v0.10.2 From 371a1d9e1fed7dc4113386b23d92cccc3cfc6d8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Mal=C3=BD?= Date: Wed, 8 Apr 2015 22:56:43 +0200 Subject: HID: hid-lg4ff: Explicit casts from void * are not necessary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Explicit casts from void * are not necessary. Signed-off-by: Michal Malý Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index d1d5d45..5a3b3be 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -847,7 +847,7 @@ static void lg4ff_led_set_brightness(struct led_classdev *led_cdev, return; } - entry = (struct lg4ff_device_entry *)drv_data->device_props; + entry = drv_data->device_props; if (!entry) { hid_err(hid, "Device properties not found."); @@ -882,7 +882,7 @@ static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cde return LED_OFF; } - entry = (struct lg4ff_device_entry *)drv_data->device_props; + entry = drv_data->device_props; if (!entry) { hid_err(hid, "Device properties not found."); -- cgit v0.10.2 From 9c2a6bd1133f7eae42b7b4e245d2aafecaf4a082 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Mal=C3=BD?= Date: Wed, 8 Apr 2015 22:56:44 +0200 Subject: HID: hid-lg4ff: Update a warning message MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update a warning message for a case where device is incorrectly flagged to be handled by hid-lg4ff in hid-lg. The original warning message was highly misleading. This warning can be triggered only if a device is flagged to be handled by hid-lg4ff in hid-lg but hid-lg4ff lacks support for such device. Signed-off-by: Michal Malý Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index 5a3b3be..04822fb 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -1021,8 +1021,9 @@ int lg4ff_init(struct hid_device *hid) } if (i == ARRAY_SIZE(lg4ff_devices)) { - hid_err(hid, "Device is not supported by lg4ff driver. If you think it should be, consider reporting a bug to" - "LKML, Simon Wood or Michal Maly \n"); + hid_err(hid, "This device is flagged to be handled by the lg4ff module but this module does not know how to handle it. " + "Please report this as a bug to LKML, Simon Wood or " + "Michal Maly \n"); return -1; } -- cgit v0.10.2 From 2dbf635ea1c0b62a957438d72a162175680a3d4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Mal=C3=BD?= Date: Wed, 8 Apr 2015 22:56:45 +0200 Subject: HID: hid-lg: Check return values from lg[N]ff_init() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Check return values from lg[N]ff_init(). hid-lg did not check return values from the lg[N]_init() functions, possibly trying to work with a device whose initialization has failed. Signed-off-by: Michal Malý Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index 2671de9..3f01da6 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -713,13 +713,16 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) } if (drv_data->quirks & LG_FF) - lgff_init(hdev); + ret = lgff_init(hdev); if (drv_data->quirks & LG_FF2) - lg2ff_init(hdev); + ret = lg2ff_init(hdev); if (drv_data->quirks & LG_FF3) - lg3ff_init(hdev); + ret = lg3ff_init(hdev); if (drv_data->quirks & LG_FF4) - lg4ff_init(hdev); + ret = lg4ff_init(hdev); + + if (ret) + goto err_free; return 0; err_free: -- cgit v0.10.2 From 72529c65a5399be02c619ed8592e38a3e5f049f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Mal=C3=BD?= Date: Wed, 8 Apr 2015 22:56:46 +0200 Subject: HID: hid-lg4ff: Make lg4ff_wheel_data a separate structure MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make lg4ff_wheel_data a separate structure stored within lg4ff_device_entry. Adjust the initialization process accordingly. Signed-off-by: Michal Malý Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index 04822fb..0f8d726 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -71,7 +71,7 @@ static void lg4ff_set_range_dfp(struct hid_device *hid, u16 range); static void lg4ff_set_range_g25(struct hid_device *hid, u16 range); -struct lg4ff_device_entry { +struct lg4ff_wheel_data { u32 product_id; u16 range; u16 min_range; @@ -84,9 +84,14 @@ struct lg4ff_device_entry { const char *real_tag; const char *real_name; u16 real_product_id; + void (*set_range)(struct hid_device *hid, u16 range); }; +struct lg4ff_device_entry { + struct lg4ff_wheel_data wdata; +}; + static const signed short lg4ff_wheel_effects[] = { FF_CONSTANT, FF_AUTOCENTER, @@ -278,11 +283,11 @@ int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field, return 0; } - switch (entry->product_id) { + switch (entry->wdata.product_id) { case USB_DEVICE_ID_LOGITECH_DFP_WHEEL: switch (usage->code) { case ABS_X: - new_value = lg4ff_adjust_dfp_x_axis(value, entry->range); + new_value = lg4ff_adjust_dfp_x_axis(value, entry->wdata.range); input_event(field->hidinput->input, usage->type, usage->code, new_value); return 1; default: @@ -383,7 +388,7 @@ static void lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitude) } /* Adjust for non-MOMO wheels */ - switch (entry->product_id) { + switch (entry->wdata.product_id) { case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL: case USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2: break; @@ -605,23 +610,23 @@ static ssize_t lg4ff_alternate_modes_show(struct device *dev, struct device_attr return 0; } - if (!entry->real_name) { + if (!entry->wdata.real_name) { hid_err(hid, "NULL pointer to string\n"); return 0; } for (i = 0; i < LG4FF_MODE_MAX_IDX; i++) { - if (entry->alternate_modes & BIT(i)) { + if (entry->wdata.alternate_modes & BIT(i)) { /* Print tag and full name */ count += scnprintf(buf + count, PAGE_SIZE - count, "%s: %s", lg4ff_alternate_modes[i].tag, - !lg4ff_alternate_modes[i].product_id ? entry->real_name : lg4ff_alternate_modes[i].name); + !lg4ff_alternate_modes[i].product_id ? entry->wdata.real_name : lg4ff_alternate_modes[i].name); if (count >= PAGE_SIZE - 1) return count; /* Mark the currently active mode with an asterisk */ - if (lg4ff_alternate_modes[i].product_id == entry->product_id || - (lg4ff_alternate_modes[i].product_id == 0 && entry->product_id == entry->real_product_id)) + if (lg4ff_alternate_modes[i].product_id == entry->wdata.product_id || + (lg4ff_alternate_modes[i].product_id == 0 && entry->wdata.product_id == entry->wdata.real_product_id)) count += scnprintf(buf + count, PAGE_SIZE - count, " *\n"); else count += scnprintf(buf + count, PAGE_SIZE - count, "\n"); @@ -674,10 +679,10 @@ static ssize_t lg4ff_alternate_modes_store(struct device *dev, struct device_att const u16 mode_product_id = lg4ff_alternate_modes[i].product_id; const char *tag = lg4ff_alternate_modes[i].tag; - if (entry->alternate_modes & BIT(i)) { + if (entry->wdata.alternate_modes & BIT(i)) { if (!strcmp(tag, lbuf)) { if (!mode_product_id) - target_product_id = entry->real_product_id; + target_product_id = entry->wdata.real_product_id; else target_product_id = mode_product_id; break; @@ -692,24 +697,24 @@ static ssize_t lg4ff_alternate_modes_store(struct device *dev, struct device_att } kfree(lbuf); /* Not needed anymore */ - if (target_product_id == entry->product_id) /* Nothing to do */ + if (target_product_id == entry->wdata.product_id) /* Nothing to do */ return count; /* Automatic switching has to be disabled for the switch to DF-EX mode to work correctly */ if (target_product_id == USB_DEVICE_ID_LOGITECH_WHEEL && !lg4ff_no_autoswitch) { hid_info(hid, "\"%s\" cannot be switched to \"DF-EX\" mode. Load the \"hid_logitech\" module with \"lg4ff_no_autoswitch=1\" parameter set and try again\n", - entry->real_name); + entry->wdata.real_name); return -EINVAL; } /* Take care of hardware limitations */ - if ((entry->real_product_id == USB_DEVICE_ID_LOGITECH_DFP_WHEEL || entry->real_product_id == USB_DEVICE_ID_LOGITECH_G25_WHEEL) && - entry->product_id > target_product_id) { - hid_info(hid, "\"%s\" cannot be switched back into \"%s\" mode\n", entry->real_name, lg4ff_alternate_modes[i].name); + if ((entry->wdata.real_product_id == USB_DEVICE_ID_LOGITECH_DFP_WHEEL || entry->wdata.real_product_id == USB_DEVICE_ID_LOGITECH_G25_WHEEL) && + entry->wdata.product_id > target_product_id) { + hid_info(hid, "\"%s\" cannot be switched back into \"%s\" mode\n", entry->wdata.real_name, lg4ff_alternate_modes[i].name); return -EINVAL; } - s = lg4ff_get_mode_switch_command(entry->real_product_id, target_product_id); + s = lg4ff_get_mode_switch_command(entry->wdata.real_product_id, target_product_id); if (!s) { hid_err(hid, "Invalid target product ID %X\n", target_product_id); return -EINVAL; @@ -741,7 +746,7 @@ static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *att return 0; } - count = scnprintf(buf, PAGE_SIZE, "%u\n", entry->range); + count = scnprintf(buf, PAGE_SIZE, "%u\n", entry->wdata.range); return count; } @@ -768,13 +773,13 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at } if (range == 0) - range = entry->max_range; + range = entry->wdata.max_range; /* Check if the wheel supports range setting * and that the range is within limits for the wheel */ - if (entry->set_range != NULL && range >= entry->min_range && range <= entry->max_range) { - entry->set_range(hid, range); - entry->range = range; + if (entry->wdata.set_range && range >= entry->wdata.min_range && range <= entry->wdata.max_range) { + entry->wdata.set_range(hid, range); + entry->wdata.range = range; } return count; @@ -800,12 +805,12 @@ static ssize_t lg4ff_real_id_show(struct device *dev, struct device_attribute *a return 0; } - if (!entry->real_tag || !entry->real_name) { + if (!entry->wdata.real_tag || !entry->wdata.real_name) { hid_err(hid, "NULL pointer to string\n"); return 0; } - count = scnprintf(buf, PAGE_SIZE, "%s: %s\n", entry->real_tag, entry->real_name); + count = scnprintf(buf, PAGE_SIZE, "%s: %s\n", entry->wdata.real_tag, entry->wdata.real_name); return count; } @@ -855,15 +860,15 @@ static void lg4ff_led_set_brightness(struct led_classdev *led_cdev, } for (i = 0; i < 5; i++) { - if (led_cdev != entry->led[i]) + if (led_cdev != entry->wdata.led[i]) continue; - state = (entry->led_state >> i) & 1; + state = (entry->wdata.led_state >> i) & 1; if (value == LED_OFF && state) { - entry->led_state &= ~(1 << i); - lg4ff_set_leds(hid, entry->led_state); + entry->wdata.led_state &= ~(1 << i); + lg4ff_set_leds(hid, entry->wdata.led_state); } else if (value != LED_OFF && !state) { - entry->led_state |= 1 << i; - lg4ff_set_leds(hid, entry->led_state); + entry->wdata.led_state |= 1 << i; + lg4ff_set_leds(hid, entry->wdata.led_state); } break; } @@ -890,8 +895,8 @@ static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cde } for (i = 0; i < 5; i++) - if (led_cdev == entry->led[i]) { - value = (entry->led_state >> i) & 1; + if (led_cdev == entry->wdata.led[i]) { + value = (entry->wdata.led_state >> i) & 1; break; } @@ -1002,6 +1007,16 @@ int lg4ff_init(struct hid_device *hid) if (!hid_validate_values(hid, HID_OUTPUT_REPORT, 0, 0, 7)) return -1; + drv_data = hid_get_drvdata(hid); + if (!drv_data) { + hid_err(hid, "Cannot add device, private driver data not allocated\n"); + return -1; + } + entry = kzalloc(sizeof(*entry), GFP_KERNEL); + if (!entry) + return -ENOMEM; + drv_data->device_props = entry; + /* Check if a multimode wheel has been connected and * handle it appropriately */ mmode_ret = lg4ff_handle_multimode_wheel(hid, &real_product_id, bcdDevice); @@ -1011,6 +1026,11 @@ int lg4ff_init(struct hid_device *hid) */ if (mmode_ret == LG4FF_MMODE_SWITCHED) return 0; + else if (mmode_ret < 0) { + hid_err(hid, "Unable to switch device mode during initialization, errno %d\n", mmode_ret); + error = mmode_ret; + goto err_init; + } /* Check what wheel has been connected */ for (i = 0; i < ARRAY_SIZE(lg4ff_devices); i++) { @@ -1024,7 +1044,8 @@ int lg4ff_init(struct hid_device *hid) hid_err(hid, "This device is flagged to be handled by the lg4ff module but this module does not know how to handle it. " "Please report this as a bug to LKML, Simon Wood or " "Michal Maly \n"); - return -1; + error = -1; + goto err_init; } if (mmode_ret == LG4FF_MMODE_IS_MULTIMODE) { @@ -1035,7 +1056,8 @@ int lg4ff_init(struct hid_device *hid) if (mmode_idx == ARRAY_SIZE(lg4ff_multimode_wheels)) { hid_err(hid, "Device product ID %X is not listed as a multimode wheel", real_product_id); - return -1; + error = -1; + goto err_init; } } @@ -1046,33 +1068,18 @@ int lg4ff_init(struct hid_device *hid) error = input_ff_create_memless(dev, NULL, lg4ff_play); if (error) - return error; - - /* Get private driver data */ - drv_data = hid_get_drvdata(hid); - if (!drv_data) { - hid_err(hid, "Cannot add device, private driver data not allocated\n"); - return -1; - } + goto err_init; - /* Initialize device properties */ - entry = kzalloc(sizeof(struct lg4ff_device_entry), GFP_KERNEL); - if (!entry) { - hid_err(hid, "Cannot add device, insufficient memory to allocate device properties.\n"); - return -ENOMEM; - } - drv_data->device_props = entry; - - entry->product_id = lg4ff_devices[i].product_id; - entry->real_product_id = real_product_id; - entry->min_range = lg4ff_devices[i].min_range; - entry->max_range = lg4ff_devices[i].max_range; - entry->set_range = lg4ff_devices[i].set_range; + entry->wdata.product_id = lg4ff_devices[i].product_id; + entry->wdata.real_product_id = real_product_id; + entry->wdata.min_range = lg4ff_devices[i].min_range; + entry->wdata.max_range = lg4ff_devices[i].max_range; + entry->wdata.set_range = lg4ff_devices[i].set_range; if (mmode_ret == LG4FF_MMODE_IS_MULTIMODE) { BUG_ON(mmode_idx == -1); - entry->alternate_modes = lg4ff_multimode_wheels[mmode_idx].alternate_modes; - entry->real_tag = lg4ff_multimode_wheels[mmode_idx].real_tag; - entry->real_name = lg4ff_multimode_wheels[mmode_idx].real_name; + entry->wdata.alternate_modes = lg4ff_multimode_wheels[mmode_idx].alternate_modes; + entry->wdata.real_tag = lg4ff_multimode_wheels[mmode_idx].real_tag; + entry->wdata.real_name = lg4ff_multimode_wheels[mmode_idx].real_name; } /* Check if autocentering is available and @@ -1091,27 +1098,28 @@ int lg4ff_init(struct hid_device *hid) /* Create sysfs interface */ error = device_create_file(&hid->dev, &dev_attr_range); if (error) - return error; + goto err_init; if (mmode_ret == LG4FF_MMODE_IS_MULTIMODE) { error = device_create_file(&hid->dev, &dev_attr_real_id); if (error) - return error; + goto err_init; + error = device_create_file(&hid->dev, &dev_attr_alternate_modes); if (error) - return error; + goto err_init; } dbg_hid("sysfs interface created\n"); /* Set the maximum range to start with */ - entry->range = entry->max_range; - if (entry->set_range != NULL) - entry->set_range(hid, entry->range); + entry->wdata.range = entry->wdata.max_range; + if (entry->wdata.set_range) + entry->wdata.set_range(hid, entry->wdata.range); #ifdef CONFIG_LEDS_CLASS /* register led subsystem - G27 only */ - entry->led_state = 0; + entry->wdata.led_state = 0; for (j = 0; j < 5; j++) - entry->led[j] = NULL; + entry->wdata.led[j] = NULL; if (lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_G27_WHEEL) { struct led_classdev *led; @@ -1126,7 +1134,7 @@ int lg4ff_init(struct hid_device *hid) led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL); if (!led) { hid_err(hid, "can't allocate memory for LED %d\n", j); - goto err; + goto err_leds; } name = (void *)(&led[1]); @@ -1137,16 +1145,16 @@ int lg4ff_init(struct hid_device *hid) led->brightness_get = lg4ff_led_get_brightness; led->brightness_set = lg4ff_led_set_brightness; - entry->led[j] = led; + entry->wdata.led[j] = led; error = led_classdev_register(&hid->dev, led); if (error) { hid_err(hid, "failed to register LED %d. Aborting.\n", j); -err: +err_leds: /* Deregister LEDs (if any) */ for (j = 0; j < 5; j++) { - led = entry->led[j]; - entry->led[j] = NULL; + led = entry->wdata.led[j]; + entry->wdata.led[j] = NULL; if (!led) continue; led_classdev_unregister(led); @@ -1160,6 +1168,11 @@ out: #endif hid_info(hid, "Force feedback support for Logitech Gaming Wheels\n"); return 0; + +err_init: + drv_data->device_props = NULL; + kfree(entry); + return error; } int lg4ff_deinit(struct hid_device *hid) @@ -1176,14 +1189,13 @@ int lg4ff_deinit(struct hid_device *hid) if (!entry) goto out; /* Nothing more to do */ - device_remove_file(&hid->dev, &dev_attr_range); - /* Multimode devices will have at least the "MODE_NATIVE" bit set */ - if (entry->alternate_modes) { + if (entry->wdata.alternate_modes) { device_remove_file(&hid->dev, &dev_attr_real_id); device_remove_file(&hid->dev, &dev_attr_alternate_modes); } + device_remove_file(&hid->dev, &dev_attr_range); #ifdef CONFIG_LEDS_CLASS { int j; @@ -1192,8 +1204,8 @@ int lg4ff_deinit(struct hid_device *hid) /* Deregister LEDs (if any) */ for (j = 0; j < 5; j++) { - led = entry->led[j]; - entry->led[j] = NULL; + led = entry->wdata.led[j]; + entry->wdata.led[j] = NULL; if (!led) continue; led_classdev_unregister(led); @@ -1202,9 +1214,7 @@ int lg4ff_deinit(struct hid_device *hid) } #endif - /* Deallocate memory */ kfree(entry); - out: dbg_hid("Device successfully unregistered\n"); return 0; -- cgit v0.10.2 From b211a6388ca279a16a6627da2f3681a2cab18444 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Mal=C3=BD?= Date: Wed, 8 Apr 2015 22:56:47 +0200 Subject: HID: hid-lg4ff: Stop the hid device from lg4ff MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stop the hid device from lg4ff. Originally hid-lg was responsible for stopping of the device. Signed-off-by: Michal Malý Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index 3f01da6..d5022b3 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -735,8 +735,8 @@ static void lg_remove(struct hid_device *hdev) struct lg_drv_data *drv_data = hid_get_drvdata(hdev); if (drv_data->quirks & LG_FF4) lg4ff_deinit(hdev); - - hid_hw_stop(hdev); + else + hid_hw_stop(hdev); kfree(drv_data); } diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index 0f8d726..031b8ab 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -1213,6 +1213,8 @@ int lg4ff_deinit(struct hid_device *hid) } } #endif + hid_hw_stop(hid); + drv_data->device_props = NULL; kfree(entry); out: -- cgit v0.10.2 From c918fe781fab6d8bdc35f1652dc4f95f2bf6950d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Mal=C3=BD?= Date: Wed, 8 Apr 2015 22:56:48 +0200 Subject: HID: hid-lg4ff: Protect concurrent access to output HID report MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Protect concurrent access to output HID report with a spinlock. The HID report structure used to submit commands to wheels is shared amongst all functions that need to do so and some of these functions can be executed in parallel. Additionally, lg4ff_play() can be called from interrupt context by ff-memless module. Locking is necessary to prevent sending bogus data to the wheels. Signed-off-by: Michal Malý Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index 031b8ab..f7f4eb6 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -89,6 +89,7 @@ struct lg4ff_wheel_data { }; struct lg4ff_device_entry { + spinlock_t report_lock; /* Protect output HID report */ struct lg4ff_wheel_data wdata; }; @@ -303,9 +304,24 @@ static int lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *effec struct hid_device *hid = input_get_drvdata(dev); struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report = list_entry(report_list->next, struct hid_report, list); + struct lg4ff_device_entry *entry; + struct lg_drv_data *drv_data; + unsigned long flags; s32 *value = report->field[0]->value; int x; + drv_data = hid_get_drvdata(hid); + if (!drv_data) { + hid_err(hid, "Private driver data not found!\n"); + return -EINVAL; + } + + entry = drv_data->device_props; + if (!entry) { + hid_err(hid, "Device properties not found!\n"); + return -EINVAL; + } + #define CLAMP(x) do { if (x < 0) x = 0; else if (x > 0xff) x = 0xff; } while (0) switch (effect->type) { @@ -313,6 +329,7 @@ static int lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *effec x = effect->u.ramp.start_level + 0x80; /* 0x80 is no force */ CLAMP(x); + spin_lock_irqsave(&entry->report_lock, flags); if (x == 0x80) { /* De-activate force in slot-1*/ value[0] = 0x13; @@ -324,6 +341,7 @@ static int lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *effec value[6] = 0x00; hid_hw_request(hid, report, HID_REQ_SET_REPORT); + spin_unlock_irqrestore(&entry->report_lock, flags); return 0; } @@ -336,6 +354,7 @@ static int lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *effec value[6] = 0x00; hid_hw_request(hid, report, HID_REQ_SET_REPORT); + spin_unlock_irqrestore(&entry->report_lock, flags); break; } return 0; @@ -352,6 +371,7 @@ static void lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitude) u32 expand_a, expand_b; struct lg4ff_device_entry *entry; struct lg_drv_data *drv_data; + unsigned long flags; drv_data = hid_get_drvdata(hid); if (!drv_data) { @@ -366,6 +386,7 @@ static void lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitude) } /* De-activate Auto-Center */ + spin_lock_irqsave(&entry->report_lock, flags); if (magnitude == 0) { value[0] = 0xf5; value[1] = 0x00; @@ -376,6 +397,7 @@ static void lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitude) value[6] = 0x00; hid_hw_request(hid, report, HID_REQ_SET_REPORT); + spin_unlock_irqrestore(&entry->report_lock, flags); return; } @@ -417,6 +439,7 @@ static void lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitude) value[6] = 0x00; hid_hw_request(hid, report, HID_REQ_SET_REPORT); + spin_unlock_irqrestore(&entry->report_lock, flags); } /* Sends autocentering command compatible with Formula Force EX */ @@ -425,9 +448,25 @@ static void lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude) struct hid_device *hid = input_get_drvdata(dev); struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report = list_entry(report_list->next, struct hid_report, list); + struct lg4ff_device_entry *entry; + struct lg_drv_data *drv_data; + unsigned long flags; s32 *value = report->field[0]->value; magnitude = magnitude * 90 / 65535; + drv_data = hid_get_drvdata(hid); + if (!drv_data) { + hid_err(hid, "Private driver data not found!\n"); + return; + } + + entry = drv_data->device_props; + if (!entry) { + hid_err(hid, "Device properties not found!\n"); + return; + } + + spin_lock_irqsave(&entry->report_lock, flags); value[0] = 0xfe; value[1] = 0x03; value[2] = magnitude >> 14; @@ -437,6 +476,7 @@ static void lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude) value[6] = 0x00; hid_hw_request(hid, report, HID_REQ_SET_REPORT); + spin_unlock_irqrestore(&entry->report_lock, flags); } /* Sends command to set range compatible with G25/G27/Driving Force GT */ @@ -444,10 +484,26 @@ static void lg4ff_set_range_g25(struct hid_device *hid, u16 range) { struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report = list_entry(report_list->next, struct hid_report, list); + struct lg4ff_device_entry *entry; + struct lg_drv_data *drv_data; + unsigned long flags; s32 *value = report->field[0]->value; + drv_data = hid_get_drvdata(hid); + if (!drv_data) { + hid_err(hid, "Private driver data not found!\n"); + return; + } + + entry = drv_data->device_props; + if (!entry) { + hid_err(hid, "Device properties not found!\n"); + return; + } + dbg_hid("G25/G27/DFGT: setting range to %u\n", range); + spin_lock_irqsave(&entry->report_lock, flags); value[0] = 0xf8; value[1] = 0x81; value[2] = range & 0x00ff; @@ -457,6 +513,7 @@ static void lg4ff_set_range_g25(struct hid_device *hid, u16 range) value[6] = 0x00; hid_hw_request(hid, report, HID_REQ_SET_REPORT); + spin_unlock_irqrestore(&entry->report_lock, flags); } /* Sends commands to set range compatible with Driving Force Pro wheel */ @@ -465,11 +522,27 @@ static void lg4ff_set_range_dfp(struct hid_device *hid, u16 range) struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report = list_entry(report_list->next, struct hid_report, list); int start_left, start_right, full_range; + struct lg4ff_device_entry *entry; + struct lg_drv_data *drv_data; + unsigned long flags; s32 *value = report->field[0]->value; + drv_data = hid_get_drvdata(hid); + if (!drv_data) { + hid_err(hid, "Private driver data not found!\n"); + return; + } + + entry = drv_data->device_props; + if (!entry) { + hid_err(hid, "Device properties not found!\n"); + return; + } + dbg_hid("Driving Force Pro: setting range to %u\n", range); /* Prepare "coarse" limit command */ + spin_lock_irqsave(&entry->report_lock, flags); value[0] = 0xf8; value[1] = 0x00; /* Set later */ value[2] = 0x00; @@ -498,6 +571,7 @@ static void lg4ff_set_range_dfp(struct hid_device *hid, u16 range) if (range == 200 || range == 900) { /* Do not apply any fine limit */ hid_hw_request(hid, report, HID_REQ_SET_REPORT); + spin_unlock_irqrestore(&entry->report_lock, flags); return; } @@ -512,6 +586,7 @@ static void lg4ff_set_range_dfp(struct hid_device *hid, u16 range) value[6] = 0xff; hid_hw_request(hid, report, HID_REQ_SET_REPORT); + spin_unlock_irqrestore(&entry->report_lock, flags); } static const struct lg4ff_compat_mode_switch *lg4ff_get_mode_switch_command(const u16 real_product_id, const u16 target_product_id) @@ -575,9 +650,25 @@ static int lg4ff_switch_compatibility_mode(struct hid_device *hid, const struct { struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report = list_entry(report_list->next, struct hid_report, list); + struct lg4ff_device_entry *entry; + struct lg_drv_data *drv_data; + unsigned long flags; s32 *value = report->field[0]->value; u8 i; + drv_data = hid_get_drvdata(hid); + if (!drv_data) { + hid_err(hid, "Private driver data not found!\n"); + return -EINVAL; + } + + entry = drv_data->device_props; + if (!entry) { + hid_err(hid, "Device properties not found!\n"); + return -EINVAL; + } + + spin_lock_irqsave(&entry->report_lock, flags); for (i = 0; i < s->cmd_count; i++) { u8 j; @@ -586,6 +677,7 @@ static int lg4ff_switch_compatibility_mode(struct hid_device *hid, const struct hid_hw_request(hid, report, HID_REQ_SET_REPORT); } + spin_unlock_irqrestore(&entry->report_lock, flags); hid_hw_wait(hid); return 0; } @@ -826,8 +918,24 @@ static void lg4ff_set_leds(struct hid_device *hid, u8 leds) { struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; struct hid_report *report = list_entry(report_list->next, struct hid_report, list); + struct lg_drv_data *drv_data; + struct lg4ff_device_entry *entry; + unsigned long flags; s32 *value = report->field[0]->value; + drv_data = hid_get_drvdata(hid); + if (!drv_data) { + hid_err(hid, "Private driver data not found!\n"); + return; + } + + entry = drv_data->device_props; + if (!entry) { + hid_err(hid, "Device properties not found!\n"); + return; + } + + spin_lock_irqsave(&entry->report_lock, flags); value[0] = 0xf8; value[1] = 0x12; value[2] = leds; @@ -836,6 +944,7 @@ static void lg4ff_set_leds(struct hid_device *hid, u8 leds) value[5] = 0x00; value[6] = 0x00; hid_hw_request(hid, report, HID_REQ_SET_REPORT); + spin_unlock_irqrestore(&entry->report_lock, flags); } static void lg4ff_led_set_brightness(struct led_classdev *led_cdev, @@ -1015,6 +1124,7 @@ int lg4ff_init(struct hid_device *hid) entry = kzalloc(sizeof(*entry), GFP_KERNEL); if (!entry) return -ENOMEM; + spin_lock_init(&entry->report_lock); drv_data->device_props = entry; /* Check if a multimode wheel has been connected and -- cgit v0.10.2 From c28abd8c423b85e2d8be8ed33984a3ad966f1c83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Mal=C3=BD?= Date: Wed, 8 Apr 2015 22:56:49 +0200 Subject: HID: hid-lg4ff: Store pointer to the output HID report struct in the device entry struct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Store pointer to the output HID report struct in the device entry struct. This eliminates the need to look the HID report struct up every time it is needed. Signed-off-by: Michal Malý Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index f7f4eb6..d27b210 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -90,6 +90,7 @@ struct lg4ff_wheel_data { struct lg4ff_device_entry { spinlock_t report_lock; /* Protect output HID report */ + struct hid_report *report; struct lg4ff_wheel_data wdata; }; @@ -302,12 +303,10 @@ int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field, static int lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *effect) { struct hid_device *hid = input_get_drvdata(dev); - struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; - struct hid_report *report = list_entry(report_list->next, struct hid_report, list); struct lg4ff_device_entry *entry; struct lg_drv_data *drv_data; unsigned long flags; - s32 *value = report->field[0]->value; + s32 *value; int x; drv_data = hid_get_drvdata(hid); @@ -321,6 +320,7 @@ static int lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *effec hid_err(hid, "Device properties not found!\n"); return -EINVAL; } + value = entry->report->field[0]->value; #define CLAMP(x) do { if (x < 0) x = 0; else if (x > 0xff) x = 0xff; } while (0) @@ -340,7 +340,7 @@ static int lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *effec value[5] = 0x00; value[6] = 0x00; - hid_hw_request(hid, report, HID_REQ_SET_REPORT); + hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT); spin_unlock_irqrestore(&entry->report_lock, flags); return 0; } @@ -353,7 +353,7 @@ static int lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *effec value[5] = 0x00; value[6] = 0x00; - hid_hw_request(hid, report, HID_REQ_SET_REPORT); + hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT); spin_unlock_irqrestore(&entry->report_lock, flags); break; } @@ -384,6 +384,7 @@ static void lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitude) hid_err(hid, "Device properties not found!\n"); return; } + value = entry->report->field[0]->value; /* De-activate Auto-Center */ spin_lock_irqsave(&entry->report_lock, flags); @@ -396,7 +397,7 @@ static void lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitude) value[5] = 0x00; value[6] = 0x00; - hid_hw_request(hid, report, HID_REQ_SET_REPORT); + hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT); spin_unlock_irqrestore(&entry->report_lock, flags); return; } @@ -427,7 +428,7 @@ static void lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitude) value[5] = 0x00; value[6] = 0x00; - hid_hw_request(hid, report, HID_REQ_SET_REPORT); + hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT); /* Activate Auto-Center */ value[0] = 0x14; @@ -438,7 +439,7 @@ static void lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitude) value[5] = 0x00; value[6] = 0x00; - hid_hw_request(hid, report, HID_REQ_SET_REPORT); + hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT); spin_unlock_irqrestore(&entry->report_lock, flags); } @@ -446,12 +447,10 @@ static void lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitude) static void lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude) { struct hid_device *hid = input_get_drvdata(dev); - struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; - struct hid_report *report = list_entry(report_list->next, struct hid_report, list); struct lg4ff_device_entry *entry; struct lg_drv_data *drv_data; unsigned long flags; - s32 *value = report->field[0]->value; + s32 *value; magnitude = magnitude * 90 / 65535; drv_data = hid_get_drvdata(hid); @@ -465,6 +464,7 @@ static void lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude) hid_err(hid, "Device properties not found!\n"); return; } + value = entry->report->field[0]->value; spin_lock_irqsave(&entry->report_lock, flags); value[0] = 0xfe; @@ -475,19 +475,17 @@ static void lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude) value[5] = 0x00; value[6] = 0x00; - hid_hw_request(hid, report, HID_REQ_SET_REPORT); + hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT); spin_unlock_irqrestore(&entry->report_lock, flags); } /* Sends command to set range compatible with G25/G27/Driving Force GT */ static void lg4ff_set_range_g25(struct hid_device *hid, u16 range) { - struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; - struct hid_report *report = list_entry(report_list->next, struct hid_report, list); struct lg4ff_device_entry *entry; struct lg_drv_data *drv_data; unsigned long flags; - s32 *value = report->field[0]->value; + s32 *value; drv_data = hid_get_drvdata(hid); if (!drv_data) { @@ -500,7 +498,7 @@ static void lg4ff_set_range_g25(struct hid_device *hid, u16 range) hid_err(hid, "Device properties not found!\n"); return; } - + value = entry->report->field[0]->value; dbg_hid("G25/G27/DFGT: setting range to %u\n", range); spin_lock_irqsave(&entry->report_lock, flags); @@ -512,20 +510,18 @@ static void lg4ff_set_range_g25(struct hid_device *hid, u16 range) value[5] = 0x00; value[6] = 0x00; - hid_hw_request(hid, report, HID_REQ_SET_REPORT); + hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT); spin_unlock_irqrestore(&entry->report_lock, flags); } /* Sends commands to set range compatible with Driving Force Pro wheel */ static void lg4ff_set_range_dfp(struct hid_device *hid, u16 range) { - struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; - struct hid_report *report = list_entry(report_list->next, struct hid_report, list); - int start_left, start_right, full_range; struct lg4ff_device_entry *entry; struct lg_drv_data *drv_data; unsigned long flags; - s32 *value = report->field[0]->value; + int start_left, start_right, full_range; + s32 *value; drv_data = hid_get_drvdata(hid); if (!drv_data) { @@ -538,7 +534,7 @@ static void lg4ff_set_range_dfp(struct hid_device *hid, u16 range) hid_err(hid, "Device properties not found!\n"); return; } - + value = entry->report->field[0]->value; dbg_hid("Driving Force Pro: setting range to %u\n", range); /* Prepare "coarse" limit command */ @@ -552,13 +548,13 @@ static void lg4ff_set_range_dfp(struct hid_device *hid, u16 range) value[6] = 0x00; if (range > 200) { - report->field[0]->value[1] = 0x03; + value[1] = 0x03; full_range = 900; } else { - report->field[0]->value[1] = 0x02; + value[1] = 0x02; full_range = 200; } - hid_hw_request(hid, report, HID_REQ_SET_REPORT); + hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT); /* Prepare "fine" limit command */ value[0] = 0x81; @@ -570,7 +566,7 @@ static void lg4ff_set_range_dfp(struct hid_device *hid, u16 range) value[6] = 0x00; if (range == 200 || range == 900) { /* Do not apply any fine limit */ - hid_hw_request(hid, report, HID_REQ_SET_REPORT); + hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT); spin_unlock_irqrestore(&entry->report_lock, flags); return; } @@ -585,7 +581,7 @@ static void lg4ff_set_range_dfp(struct hid_device *hid, u16 range) value[5] = (start_right & 0xe) << 4 | (start_left & 0xe); value[6] = 0xff; - hid_hw_request(hid, report, HID_REQ_SET_REPORT); + hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT); spin_unlock_irqrestore(&entry->report_lock, flags); } @@ -648,12 +644,10 @@ static const struct lg4ff_compat_mode_switch *lg4ff_get_mode_switch_command(cons static int lg4ff_switch_compatibility_mode(struct hid_device *hid, const struct lg4ff_compat_mode_switch *s) { - struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; - struct hid_report *report = list_entry(report_list->next, struct hid_report, list); struct lg4ff_device_entry *entry; struct lg_drv_data *drv_data; unsigned long flags; - s32 *value = report->field[0]->value; + s32 *value; u8 i; drv_data = hid_get_drvdata(hid); @@ -667,6 +661,7 @@ static int lg4ff_switch_compatibility_mode(struct hid_device *hid, const struct hid_err(hid, "Device properties not found!\n"); return -EINVAL; } + value = entry->report->field[0]->value; spin_lock_irqsave(&entry->report_lock, flags); for (i = 0; i < s->cmd_count; i++) { @@ -675,7 +670,7 @@ static int lg4ff_switch_compatibility_mode(struct hid_device *hid, const struct for (j = 0; j < 7; j++) value[j] = s->cmd[j + (7*i)]; - hid_hw_request(hid, report, HID_REQ_SET_REPORT); + hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT); } spin_unlock_irqrestore(&entry->report_lock, flags); hid_hw_wait(hid); @@ -916,12 +911,10 @@ static DEVICE_ATTR(real_id, S_IRUGO, lg4ff_real_id_show, lg4ff_real_id_store); #ifdef CONFIG_LEDS_CLASS static void lg4ff_set_leds(struct hid_device *hid, u8 leds) { - struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; - struct hid_report *report = list_entry(report_list->next, struct hid_report, list); struct lg_drv_data *drv_data; struct lg4ff_device_entry *entry; unsigned long flags; - s32 *value = report->field[0]->value; + s32 *value; drv_data = hid_get_drvdata(hid); if (!drv_data) { @@ -934,6 +927,7 @@ static void lg4ff_set_leds(struct hid_device *hid, u8 leds) hid_err(hid, "Device properties not found!\n"); return; } + value = entry->report->field[0]->value; spin_lock_irqsave(&entry->report_lock, flags); value[0] = 0xf8; @@ -943,7 +937,7 @@ static void lg4ff_set_leds(struct hid_device *hid, u8 leds) value[4] = 0x00; value[5] = 0x00; value[6] = 0x00; - hid_hw_request(hid, report, HID_REQ_SET_REPORT); + hid_hw_request(hid, entry->report, HID_REQ_SET_REPORT); spin_unlock_irqrestore(&entry->report_lock, flags); } @@ -1104,6 +1098,8 @@ int lg4ff_init(struct hid_device *hid) { struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); struct input_dev *dev = hidinput->input; + struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; + struct hid_report *report = list_entry(report_list->next, struct hid_report, list); const struct usb_device_descriptor *udesc = &(hid_to_usb_dev(hid)->descriptor); const u16 bcdDevice = le16_to_cpu(udesc->bcdDevice); struct lg4ff_device_entry *entry; @@ -1125,6 +1121,7 @@ int lg4ff_init(struct hid_device *hid) if (!entry) return -ENOMEM; spin_lock_init(&entry->report_lock); + entry->report = report; drv_data->device_props = entry; /* Check if a multimode wheel has been connected and -- cgit v0.10.2 From 5d9d60ad308c867b271cc03233f2c93a0f5d80ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Mal=C3=BD?= Date: Wed, 8 Apr 2015 22:56:50 +0200 Subject: HID: hid-lg4ff: Constify members of lg4ff_device_entry MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Constify those members of lg4ff_device_entry struct whose value is not supposed to change. Signed-off-by: Michal Malý Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index d27b210..dcaf481 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -72,18 +72,18 @@ static void lg4ff_set_range_dfp(struct hid_device *hid, u16 range); static void lg4ff_set_range_g25(struct hid_device *hid, u16 range); struct lg4ff_wheel_data { - u32 product_id; + const u32 product_id; u16 range; - u16 min_range; - u16 max_range; + const u16 min_range; + const u16 max_range; #ifdef CONFIG_LEDS_CLASS u8 led_state; struct led_classdev *led[5]; #endif - u32 alternate_modes; - const char *real_tag; - const char *real_name; - u16 real_product_id; + const u32 alternate_modes; + const char * const real_tag; + const char * const real_name; + const u16 real_product_id; void (*set_range)(struct hid_device *hid, u16 range); }; @@ -300,6 +300,34 @@ int lg4ff_adjust_input_event(struct hid_device *hid, struct hid_field *field, } } +static void lg4ff_init_wheel_data(struct lg4ff_wheel_data * const wdata, const struct lg4ff_wheel *wheel, + const struct lg4ff_multimode_wheel *mmode_wheel, + const u16 real_product_id) +{ + u32 alternate_modes = 0; + const char *real_tag = NULL; + const char *real_name = NULL; + + if (mmode_wheel) { + alternate_modes = mmode_wheel->alternate_modes; + real_tag = mmode_wheel->real_tag; + real_name = mmode_wheel->real_name; + } + + { + struct lg4ff_wheel_data t_wdata = { .product_id = wheel->product_id, + .real_product_id = real_product_id, + .min_range = wheel->min_range, + .max_range = wheel->max_range, + .set_range = wheel->set_range, + .alternate_modes = alternate_modes, + .real_tag = real_tag, + .real_name = real_name }; + + memcpy(wdata, &t_wdata, sizeof(t_wdata)); + } +} + static int lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *effect) { struct hid_device *hid = input_get_drvdata(dev); @@ -1102,6 +1130,7 @@ int lg4ff_init(struct hid_device *hid) struct hid_report *report = list_entry(report_list->next, struct hid_report, list); const struct usb_device_descriptor *udesc = &(hid_to_usb_dev(hid)->descriptor); const u16 bcdDevice = le16_to_cpu(udesc->bcdDevice); + const struct lg4ff_multimode_wheel *mmode_wheel = NULL; struct lg4ff_device_entry *entry; struct lg_drv_data *drv_data; int error, i, j; @@ -1177,17 +1206,12 @@ int lg4ff_init(struct hid_device *hid) if (error) goto err_init; - entry->wdata.product_id = lg4ff_devices[i].product_id; - entry->wdata.real_product_id = real_product_id; - entry->wdata.min_range = lg4ff_devices[i].min_range; - entry->wdata.max_range = lg4ff_devices[i].max_range; - entry->wdata.set_range = lg4ff_devices[i].set_range; + /* Initialize device properties */ if (mmode_ret == LG4FF_MMODE_IS_MULTIMODE) { BUG_ON(mmode_idx == -1); - entry->wdata.alternate_modes = lg4ff_multimode_wheels[mmode_idx].alternate_modes; - entry->wdata.real_tag = lg4ff_multimode_wheels[mmode_idx].real_tag; - entry->wdata.real_name = lg4ff_multimode_wheels[mmode_idx].real_name; + mmode_wheel = &lg4ff_multimode_wheels[mmode_idx]; } + lg4ff_init_wheel_data(&entry->wdata, &lg4ff_devices[i], mmode_wheel, real_product_id); /* Check if autocentering is available and * set the centering force to zero by default */ -- cgit v0.10.2 From d61a70ec93251d77608864e0f6daf6dd1bfd4a6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Mal=C3=BD?= Date: Wed, 8 Apr 2015 22:56:51 +0200 Subject: HID: hid-lg4ff: Allow the driver to continue without sysfs interface MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow the driver to continue without sysfs interface. Instead of bailing out allow the driver to continue in a degraded mode. Signed-off-by: Michal Malý Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index dcaf481..02cec83 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -1229,15 +1229,14 @@ int lg4ff_init(struct hid_device *hid) /* Create sysfs interface */ error = device_create_file(&hid->dev, &dev_attr_range); if (error) - goto err_init; + hid_warn(hid, "Unable to create sysfs interface for \"range\", errno %d\n", error); if (mmode_ret == LG4FF_MMODE_IS_MULTIMODE) { error = device_create_file(&hid->dev, &dev_attr_real_id); if (error) - goto err_init; - + hid_warn(hid, "Unable to create sysfs interface for \"real_id\", errno %d\n", error); error = device_create_file(&hid->dev, &dev_attr_alternate_modes); if (error) - goto err_init; + hid_warn(hid, "Unable to create sysfs interface for \"alternate_modes\", errno %d\n", error); } dbg_hid("sysfs interface created\n"); -- cgit v0.10.2 From bbfd0ccc598ded2ec9f618f10b5bc54b1130f4d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Mal=C3=BD?= Date: Wed, 8 Apr 2015 22:56:52 +0200 Subject: HID: hid-lg4ff: Update respective sysfs interface documentation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update respective sysfs interface documentation - Refer to the sysfs interface for "range" using "/sys/bus/..." - Update contact email address Signed-off-by: Michal Malý Signed-off-by: Jiri Kosina diff --git a/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff b/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff index b3f6a2a..db197a8 100644 --- a/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff +++ b/Documentation/ABI/testing/sysfs-driver-hid-logitech-lg4ff @@ -1,7 +1,7 @@ -What: /sys/module/hid_logitech/drivers/hid:logitech//range. +What: /sys/bus/hid/drivers/logitech//range Date: July 2011 KernelVersion: 3.2 -Contact: Michal Malý +Contact: Michal Malý Description: Display minimum, maximum and current range of the steering wheel. Writing a value within min and max boundaries sets the range of the wheel. @@ -9,7 +9,7 @@ Description: Display minimum, maximum and current range of the steering What: /sys/bus/hid/drivers/logitech//alternate_modes Date: Feb 2015 KernelVersion: 4.1 -Contact: Michal Malý +Contact: Michal Malý Description: Displays a set of alternate modes supported by a wheel. Each mode is listed as follows: Tag: Mode Name @@ -45,7 +45,7 @@ Description: Displays a set of alternate modes supported by a wheel. Each What: /sys/bus/hid/drivers/logitech//real_id Date: Feb 2015 KernelVersion: 4.1 -Contact: Michal Malý +Contact: Michal Malý Description: Displays the real model of the wheel regardless of any alternate mode the wheel might be switched to. It is a read-only value. -- cgit v0.10.2 From f4e1eb966256b15335054fac7b304f14e4965b5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20Mal=C3=BD?= Date: Wed, 8 Apr 2015 22:56:53 +0200 Subject: HID: hid-lg: Only one of LG_FF flags can be set for a given device MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Only one of LG_FF flags can be set for a given device. Signed-off-by: Michal Malý Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index d5022b3..429340d 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -714,11 +714,11 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) if (drv_data->quirks & LG_FF) ret = lgff_init(hdev); - if (drv_data->quirks & LG_FF2) + else if (drv_data->quirks & LG_FF2) ret = lg2ff_init(hdev); - if (drv_data->quirks & LG_FF3) + else if (drv_data->quirks & LG_FF3) ret = lg3ff_init(hdev); - if (drv_data->quirks & LG_FF4) + else if (drv_data->quirks & LG_FF4) ret = lg4ff_init(hdev); if (ret) -- cgit v0.10.2 From d0091f5749eadfce87ce0436994584637a353e2c Mon Sep 17 00:00:00 2001 From: Sean Young Date: Fri, 8 May 2015 10:29:58 +0100 Subject: HID: core: remove phidgets from ignore list Once there were kernel drivers for some of the phidgets devices, and for those kernel drivers to work the hid system needed exceptions. Now the kernel drivers are long gone in favour of the user-space drivers. The user-space drivers support many more phidget devices and uses libusb. The udev rules set up permissions so that the kernel hid driver can be unbound from libusb, as it does for many devices not in hid_ignore_list. http://www.phidgets.com/docs/OS_-_Linux Signed-off-by: Sean Young Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 722a925..e880769 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2265,14 +2265,6 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0001) }, { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0002) }, { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0004) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_4_PHIDGETSERVO_30) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_1_PHIDGETSERVO_30) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_0_4_IF_KIT) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_16_16_IF_KIT) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_8_8_8_IF_KIT) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_7_IF_KIT) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_0_8_8_IF_KIT) }, - { HID_USB_DEVICE(USB_VENDOR_ID_GLAB, USB_DEVICE_ID_PHIDGET_MOTORCONTROL) }, { HID_USB_DEVICE(USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_SUPER_Q2) }, { HID_USB_DEVICE(USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_GOGOPEN) }, { HID_USB_DEVICE(USB_VENDOR_ID_GOTOP, USB_DEVICE_ID_PENPOWER) }, @@ -2404,9 +2396,6 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) }, { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS) }, { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LCSPEC) }, - { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_4_PHIDGETSERVO_20) }, - { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20) }, - { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT) }, { HID_USB_DEVICE(USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K) }, { HID_USB_DEVICE(USB_VENDOR_ID_RISO_KAGAKU, USB_DEVICE_ID_RI_KA_WEBMAIL) }, { } diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index b24caf8..cf0a537 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -362,16 +362,6 @@ #define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_010A 0x010a #define USB_DEVICE_ID_GENERAL_TOUCH_WIN8_PIT_E100 0xe100 -#define USB_VENDOR_ID_GLAB 0x06c2 -#define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038 -#define USB_DEVICE_ID_1_PHIDGETSERVO_30 0x0039 -#define USB_DEVICE_ID_0_0_4_IF_KIT 0x0040 -#define USB_DEVICE_ID_0_16_16_IF_KIT 0x0044 -#define USB_DEVICE_ID_8_8_8_IF_KIT 0x0045 -#define USB_DEVICE_ID_0_8_7_IF_KIT 0x0051 -#define USB_DEVICE_ID_0_8_8_IF_KIT 0x0053 -#define USB_DEVICE_ID_PHIDGET_MOTORCONTROL 0x0058 - #define USB_VENDOR_ID_GOODTOUCH 0x1aad #define USB_DEVICE_ID_GOODTOUCH_000f 0x000f @@ -982,9 +972,6 @@ #define USB_VENDOR_ID_WISEGROUP 0x0925 #define USB_DEVICE_ID_SMARTJOY_PLUS 0x0005 -#define USB_DEVICE_ID_1_PHIDGETSERVO_20 0x8101 -#define USB_DEVICE_ID_4_PHIDGETSERVO_20 0x8104 -#define USB_DEVICE_ID_8_8_4_IF_KIT 0x8201 #define USB_DEVICE_ID_SUPER_JOY_BOX_3 0x8888 #define USB_DEVICE_ID_QUAD_USB_JOYPAD 0x8800 #define USB_DEVICE_ID_DUAL_USB_JOYPAD 0x8866 -- cgit v0.10.2 From 30ee72f0d28721da4bbe2be850fcd0bd269f238f Mon Sep 17 00:00:00 2001 From: Srinivas Pandruvada Date: Fri, 15 May 2015 11:35:38 -0700 Subject: HID: MAINTAINERS: Add HID SENSOR HUB drivers Added additional entry for hid sensor hub drivers, which includes core hid sensor hub MFD driver and IIO drivers for individual sensors. Signed-off-by: Srinivas Pandruvada Acked-by: Jonathan Cameron Signed-off-by: Jiri Kosina diff --git a/MAINTAINERS b/MAINTAINERS index 38579ac..61153f3 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4605,6 +4605,18 @@ F: drivers/hid/ F: include/linux/hid* F: include/uapi/linux/hid* +HID SENSOR HUB DRIVERS +M: Jiri Kosina +M: Jonathan Cameron +M: Srinivas Pandruvada +L: linux-input@vger.kernel.org +L: linux-iio@vger.kernel.org +S: Maintained +F: Documentation/hid/hid-sensor* +F: drivers/hid/hid-sensor-* +F: drivers/iio/*/hid-* +F: include/linux/hid-sensor-* + HIGH-RESOLUTION TIMERS, CLOCKEVENTS, DYNTICKS M: Thomas Gleixner L: linux-kernel@vger.kernel.org -- cgit v0.10.2 From af43c4086cf24c3eb74a968195351163750c82b6 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 14 May 2015 11:32:56 +0300 Subject: HID: rmi: fix some harmless BIT() mistakes These defines are used like this: if (!(test_bit(RMI_STARTED, &hdata->flags))) So the intent was to use bits 0, 1 and 2 but because of the extra BIT() shifts we're actually using 1, 2 and 4. It's harmless because it's done consistently but static checkers will complain. Fixes: 9fb6bf02e3ad ('HID: rmi: introduce RMI driver for Synaptics touchpads') Signed-off-by: Dan Carpenter Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index 368ffdf..2f3e51d 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -29,9 +29,9 @@ #define RMI_SET_RMI_MODE_REPORT_ID 0x0f /* Feature Report */ /* flags */ -#define RMI_READ_REQUEST_PENDING BIT(0) -#define RMI_READ_DATA_PENDING BIT(1) -#define RMI_STARTED BIT(2) +#define RMI_READ_REQUEST_PENDING 0 +#define RMI_READ_DATA_PENDING 1 +#define RMI_STARTED 2 /* device flags */ #define RMI_DEVICE BIT(0) -- cgit v0.10.2 From c8fd51dc12c6e22bb97d5e273babcf339770aba5 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 14 May 2015 11:33:30 +0300 Subject: HID: i2c-hid: fix harmless test_bit() issue These defines are used like this: if (test_bit(I2C_HID_STARTED, &ihid->flags)) The intent was to use bits 0, 1, and 2 but because of the extra shifts we're using bits 1, 2, and 4. It's harmless becuase it's done consistently but it's not the intent and static checkers will complain. Fixes: 4a200c3b9a40 ('HID: i2c-hid: introduce HID over i2c specification implementation') Signed-off-by: Dan Carpenter Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index ab4dd95..ea5ce75 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -42,9 +42,9 @@ #include /* flags */ -#define I2C_HID_STARTED (1 << 0) -#define I2C_HID_RESET_PENDING (1 << 1) -#define I2C_HID_READ_PENDING (1 << 2) +#define I2C_HID_STARTED 0 +#define I2C_HID_RESET_PENDING 1 +#define I2C_HID_READ_PENDING 2 #define I2C_HID_PWR_ON 0x00 #define I2C_HID_PWR_SLEEP 0x01 -- cgit v0.10.2 From aef3156d7294ac878c10ca8f02539b49adee9624 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Thu, 21 May 2015 10:44:31 -0700 Subject: HID: wacom: Have wacom_{get,set}_report retry on -EAGAIN, not -EPIPE Retrying on -EPIPE makes very little sense since this typically indicates a problem that will not just disappear on its own. For instance, the USB documentation states that it will be sent if the endpoint is stalled or the device has disconnected. Instead, we should retry if -EAGAIN is received since this indicates a temporary error condition such as a busy bus. In addition to adjusting the conditions we retry under, we also log an error on failure so that we can be aware of what's going on. Signed-off-by: Jason Gerecke Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 7abf52c..109312f 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -35,7 +35,11 @@ static int wacom_get_report(struct hid_device *hdev, u8 type, u8 *buf, do { retval = hid_hw_raw_request(hdev, buf[0], buf, size, type, HID_REQ_GET_REPORT); - } while ((retval == -ETIMEDOUT || retval == -EPIPE) && --retries); + } while ((retval == -ETIMEDOUT || retval == -EAGAIN) && --retries); + + if (retval < 0) + hid_err(hdev, "wacom_get_report: ran out of retries " + "(last error = %d)\n", retval); return retval; } @@ -48,7 +52,11 @@ static int wacom_set_report(struct hid_device *hdev, u8 type, u8 *buf, do { retval = hid_hw_raw_request(hdev, buf[0], buf, size, type, HID_REQ_SET_REPORT); - } while ((retval == -ETIMEDOUT || retval == -EPIPE) && --retries); + } while ((retval == -ETIMEDOUT || retval == -EAGAIN) && --retries); + + if (retval < 0) + hid_err(hdev, "wacom_set_report: ran out of retries " + "(last error = %d)\n", retval); return retval; } -- cgit v0.10.2 From 05e8fd9202247ac6cdc26f6bafb5453120065490 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Thu, 21 May 2015 10:44:32 -0700 Subject: HID: wacom: Handle failing HID_DG_CONTACTMAX requests Hardware may not respond to a request for the HID_DG_CONTACTMAX feature and we should be tolerant of such a failure. This is especially true when using hid-replay where the hardware doesn't exist, but also for devices attached to a flaky bus. This patch increases the number of allowable retries to match other calls to 'wacom_get_report' and also provides a fallback which forces 'touch_max = 16' (enough for any Wacom device seen so far). Signed-off-by: Jason Gerecke Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 109312f..eea18a6 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -125,9 +125,16 @@ static void wacom_feature_mapping(struct hid_device *hdev, break; data[0] = field->report->id; ret = wacom_get_report(hdev, HID_FEATURE_REPORT, - data, 2, 0); - if (ret == 2) + data, 2, WAC_CMD_RETRIES); + if (ret == 2) { features->touch_max = data[1]; + } else { + features->touch_max = 16; + hid_warn(hdev, "wacom_feature_mapping: " + "could not get HID_DG_CONTACTMAX, " + "defaulting to %d\n", + features->touch_max); + } kfree(data); } break; -- cgit v0.10.2 From 7250dc3fee806eb2b7560ab7d6072302e7ae8cf8 Mon Sep 17 00:00:00 2001 From: "Herton R. Krzesinski" Date: Thu, 21 May 2015 15:04:15 -0300 Subject: HID: usbhid: add Chicony/Pixart usb optical mouse that needs QUIRK_ALWAYS_POLL I received a report from an user of following mouse which needs this quirk: usb 1-1.6: USB disconnect, device number 58 usb 1-1.6: new low speed USB device number 59 using ehci_hcd usb 1-1.6: New USB device found, idVendor=04f2, idProduct=1053 usb 1-1.6: New USB device strings: Mfr=1, Product=2, SerialNumber=0 usb 1-1.6: Product: USB Optical Mouse usb 1-1.6: Manufacturer: PixArt usb 1-1.6: configuration #1 chosen from 1 choice input: PixArt USB Optical Mouse as /devices/pci0000:00/0000:00:1a.0/usb1/1-1/1-1.6/1-1.6:1.0/input/input5887 generic-usb 0003:04F2:1053.16FE: input,hidraw2: USB HID v1.11 Mouse [PixArt USB Optical Mouse] on usb-0000:00:1a.0-1.6/input0 The quirk was tested by the reporter and it fixed the frequent disconnections etc. [jkosina@suse.cz: reorder the position in hid-ids.h] Signed-off-by: Herton R. Krzesinski Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 7ce93d9..51028ae 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -227,6 +227,7 @@ #define USB_DEVICE_ID_CHICONY_TACTICAL_PAD 0x0418 #define USB_DEVICE_ID_CHICONY_MULTI_TOUCH 0xb19d #define USB_DEVICE_ID_CHICONY_WIRELESS 0x0618 +#define USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE 0x1053 #define USB_DEVICE_ID_CHICONY_WIRELESS2 0x1123 #define USB_DEVICE_ID_CHICONY_AK1D 0x1125 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 4696895e..fbe46ca 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -70,6 +70,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_PRO_PEDALS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_3AXIS_5BUTTON_STICK, HID_QUIRK_NOGET }, { USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_PIXART_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET }, { USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ELAN_TOUCHSCREEN_009B, HID_QUIRK_ALWAYS_POLL }, -- cgit v0.10.2 From 6e01d531c9603d591826e842298a539d17436fa8 Mon Sep 17 00:00:00 2001 From: Antonio Ospite Date: Tue, 28 Apr 2015 13:11:20 +0200 Subject: HID: Makefile: fix alignment of objs-* entries Most of the entries are aligned with TABs, fix those which are not. Signed-off-by: Antonio Ospite Signed-off-by: Jiri Kosina diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index e4a21df..2f8a41d 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -24,7 +24,7 @@ obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o obj-$(CONFIG_HID_ACRUX) += hid-axff.o obj-$(CONFIG_HID_APPLE) += hid-apple.o obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o -obj-$(CONFIG_HID_AUREAL) += hid-aureal.o +obj-$(CONFIG_HID_AUREAL) += hid-aureal.o obj-$(CONFIG_HID_BELKIN) += hid-belkin.o obj-$(CONFIG_HID_BETOP_FF) += hid-betopff.o obj-$(CONFIG_HID_CHERRY) += hid-cherry.o @@ -46,12 +46,12 @@ obj-$(CONFIG_HID_ICADE) += hid-icade.o obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o obj-$(CONFIG_HID_KEYTOUCH) += hid-keytouch.o obj-$(CONFIG_HID_KYE) += hid-kye.o -obj-$(CONFIG_HID_LCPOWER) += hid-lcpower.o +obj-$(CONFIG_HID_LCPOWER) += hid-lcpower.o obj-$(CONFIG_HID_LENOVO) += hid-lenovo.o obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o obj-$(CONFIG_HID_LOGITECH_DJ) += hid-logitech-dj.o obj-$(CONFIG_HID_LOGITECH_HIDPP) += hid-logitech-hidpp.o -obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o +obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o obj-$(CONFIG_HID_MULTITOUCH) += hid-multitouch.o -- cgit v0.10.2 From 09a5c34e8d6b05663ec4c3d22b1fbd9fec89aaf9 Mon Sep 17 00:00:00 2001 From: James C Boyd Date: Wed, 27 May 2015 17:09:06 -0500 Subject: HID: hid-input: Add parentheses to quell gcc warning GCC reports a -Wlogical-not-parentheses warning here; therefore add parentheses to shut it up and to express our intent more. Signed-off-by: James C Boyd Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 008e89b..714b758 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1157,7 +1157,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct return; /* report the usage code as scancode if the key status has changed */ - if (usage->type == EV_KEY && !!test_bit(usage->code, input->key) != value) + if (usage->type == EV_KEY && (!!test_bit(usage->code, input->key)) != value) input_event(input, EV_MSC, MSC_SCAN, usage->hid); input_event(input, usage->type, usage->code, value); -- cgit v0.10.2 From 2c54c86a674979e2bd9dc3663d329ee56368a218 Mon Sep 17 00:00:00 2001 From: James C Boyd Date: Wed, 27 May 2015 17:09:07 -0500 Subject: HID: hid-input: Simplify conditional expression There are too many bangs in this conditional; therefore remove them while still maintaining the same logic. Signed-off-by: James C Boyd Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 714b758..abf4fc6 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1157,7 +1157,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct return; /* report the usage code as scancode if the key status has changed */ - if (usage->type == EV_KEY && (!!test_bit(usage->code, input->key)) != value) + if (usage->type == EV_KEY && (!test_bit(usage->code, input->key)) == value) input_event(input, EV_MSC, MSC_SCAN, usage->hid); input_event(input, usage->type, usage->code, value); -- cgit v0.10.2 From 323ddaa84f003a0c1d49f3ce5d106bc3cef070d5 Mon Sep 17 00:00:00 2001 From: James C Boyd Date: Wed, 27 May 2015 17:09:08 -0500 Subject: HID: hid-input: Fix coding style issue This line is too long; split it up. Signed-off-by: James C Boyd Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index abf4fc6..3511bbab 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1157,7 +1157,8 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct return; /* report the usage code as scancode if the key status has changed */ - if (usage->type == EV_KEY && (!test_bit(usage->code, input->key)) == value) + if (usage->type == EV_KEY && + (!test_bit(usage->code, input->key)) == value) input_event(input, EV_MSC, MSC_SCAN, usage->hid); input_event(input, usage->type, usage->code, value); -- cgit v0.10.2 From b721260085533a9bead1fd853c0aead7d82ce763 Mon Sep 17 00:00:00 2001 From: Alexey Khoroshilov Date: Fri, 29 May 2015 03:39:31 +0300 Subject: HID: lenovo: Remove sysfs group on failure path There is no sysfs_group_remove() on failure path in lenovo_probe_tpkbd(). Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c index c4c3f09..64ed3e3 100644 --- a/drivers/hid/hid-lenovo.c +++ b/drivers/hid/hid-lenovo.c @@ -599,7 +599,8 @@ static int lenovo_probe_tpkbd(struct hid_device *hdev) GFP_KERNEL); if (data_pointer == NULL) { hid_err(hdev, "Could not allocate memory for driver data\n"); - return -ENOMEM; + ret = -ENOMEM; + goto err; } // set same default values as windows driver @@ -610,7 +611,8 @@ static int lenovo_probe_tpkbd(struct hid_device *hdev) name_micmute = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL); if (name_mute == NULL || name_micmute == NULL) { hid_err(hdev, "Could not allocate memory for led data\n"); - return -ENOMEM; + ret = -ENOMEM; + goto err; } snprintf(name_mute, name_sz, "%s:amber:mute", dev_name(dev)); snprintf(name_micmute, name_sz, "%s:amber:micmute", dev_name(dev)); @@ -634,6 +636,9 @@ static int lenovo_probe_tpkbd(struct hid_device *hdev) lenovo_features_set_tpkbd(hdev); return 0; +err: + sysfs_remove_group(&hdev->dev.kobj, &lenovo_attr_group_tpkbd); + return ret; } static int lenovo_probe_cptkbd(struct hid_device *hdev) -- cgit v0.10.2 From 04fba7864ffcceae8a5f78d88ae1fd8d682a5123 Mon Sep 17 00:00:00 2001 From: Goffredo Baroncelli Date: Sat, 30 May 2015 11:00:26 +0200 Subject: HID: Export hid_field_extract() Rename the function extract() to hid_field_extract(), make it external linkage to allow the use from other modules. Suggested-by: Jiri Kosina Signed-off-by: Goffredo Baroncelli Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 722a925..fe33f9e 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1061,13 +1061,13 @@ static u32 s32ton(__s32 value, unsigned n) * Search linux-kernel and linux-usb-devel archives for "hid-core extract". */ -static __u32 extract(const struct hid_device *hid, __u8 *report, +__u32 hid_field_extract(const struct hid_device *hid, __u8 *report, unsigned offset, unsigned n) { u64 x; if (n > 32) - hid_warn(hid, "extract() called with n (%d) > 32! (%s)\n", + hid_warn(hid, "hid_field_extract() called with n (%d) > 32! (%s)\n", n, current->comm); report += offset >> 3; /* adjust byte index */ @@ -1076,6 +1076,7 @@ static __u32 extract(const struct hid_device *hid, __u8 *report, x = (x >> offset) & ((1ULL << n) - 1); /* extract bit field */ return (u32) x; } +EXPORT_SYMBOL_GPL(hid_field_extract); /* * "implement" : set bits in a little endian bit stream. @@ -1221,9 +1222,9 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field, for (n = 0; n < count; n++) { value[n] = min < 0 ? - snto32(extract(hid, data, offset + n * size, size), - size) : - extract(hid, data, offset + n * size, size); + snto32(hid_field_extract(hid, data, offset + n * size, + size), size) : + hid_field_extract(hid, data, offset + n * size, size); /* Ignore report if ErrorRollOver */ if (!(field->flags & HID_MAIN_ITEM_VARIABLE) && diff --git a/include/linux/hid.h b/include/linux/hid.h index 176b436..f17980d 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -815,6 +815,8 @@ void hid_disconnect(struct hid_device *hid); const struct hid_device_id *hid_match_id(struct hid_device *hdev, const struct hid_device_id *id); s32 hid_snto32(__u32 value, unsigned n); +__u32 hid_field_extract(const struct hid_device *hid, __u8 *report, + unsigned offset, unsigned n); /** * hid_device_io_start - enable HID input during probe, remove -- cgit v0.10.2 From 8a09b4fadf320cef081e1539975a97793cfb9076 Mon Sep 17 00:00:00 2001 From: Goffredo Baroncelli Date: Sat, 30 May 2015 11:00:27 +0200 Subject: HID: hidpp: Add driver for mouse logitech M560 The Logitech M560 is a wireless mouse designed for windows 8 which uses the unifying receiver. Compared to a standard one, some buttons (the middle one and the two ones placed on the side) are bound to a key combination instead of a generating classic "mouse" button events. The device shows up as a mouse and keyboard combination: when the middle button is pressed it sends a key (as keyboard) combination, the same happens for the two side button. The left/right/wheel work as expected from a mouse. To complicate things further, the middle button sends different keys combinations between odd and even presses. In the "even" press it also sends a left click. But the worst thing is that no event is generated when the middle button is released. It is possible to re-configure the mouse sending a command (see function m560_send_config_command()). After this command the mouse sends some useful data when the buttons are pressed and/or released. [jkosina@suse.cz: fix build breakage due to leftover from previous patch version] Signed-off-by: Goffredo Baroncelli Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index b3cf6fd..394a6f4 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -40,8 +40,9 @@ MODULE_PARM_DESC(disable_raw_mode, #define HIDPP_REPORT_LONG_LENGTH 20 #define HIDPP_QUIRK_CLASS_WTP BIT(0) +#define HIDPP_QUIRK_CLASS_M560 BIT(1) -/* bits 1..20 are reserved for classes */ +/* bits 2..20 are reserved for classes */ #define HIDPP_QUIRK_DELAYED_INIT BIT(21) #define HIDPP_QUIRK_WTP_PHYSICAL_BUTTONS BIT(22) #define HIDPP_QUIRK_MULTI_INPUT BIT(23) @@ -941,6 +942,207 @@ static int wtp_connect(struct hid_device *hdev, bool connected) true, true); } +/* ------------------------------------------------------------------------- */ +/* Logitech M560 devices */ +/* ------------------------------------------------------------------------- */ + +/* + * Logitech M560 protocol overview + * + * The Logitech M560 mouse, is designed for windows 8. When the middle and/or + * the sides buttons are pressed, it sends some keyboard keys events + * instead of buttons ones. + * To complicate things further, the middle button keys sequence + * is different from the odd press and the even press. + * + * forward button -> Super_R + * backward button -> Super_L+'d' (press only) + * middle button -> 1st time: Alt_L+SuperL+XF86TouchpadOff (press only) + * 2nd time: left-click (press only) + * NB: press-only means that when the button is pressed, the + * KeyPress/ButtonPress and KeyRelease/ButtonRelease events are generated + * together sequentially; instead when the button is released, no event is + * generated ! + * + * With the command + * 100a 3500af03 (where is the mouse id), + * the mouse reacts differently: + * - it never sends a keyboard key event + * - for the three mouse button it sends: + * middle button press 110a 3500af00... + * side 1 button (forward) press 110a 3500b000... + * side 2 button (backward) press 110a 3500ae00... + * middle/side1/side2 button release 110a 35000000... + */ + +static const u8 m560_config_parameter[] = {0x00, 0xaf, 0x03}; + +struct m560_private_data { + struct input_dev *input; +}; + +/* how buttons are mapped in the report */ +#define M560_MOUSE_BTN_LEFT 0x01 +#define M560_MOUSE_BTN_RIGHT 0x02 +#define M560_MOUSE_BTN_WHEEL_LEFT 0x08 +#define M560_MOUSE_BTN_WHEEL_RIGHT 0x10 + +#define M560_SUB_ID 0x0a +#define M560_BUTTON_MODE_REGISTER 0x35 + +static int m560_send_config_command(struct hid_device *hdev, bool connected) +{ + struct hidpp_report response; + struct hidpp_device *hidpp_dev; + + hidpp_dev = hid_get_drvdata(hdev); + + if (!connected) + return -ENODEV; + + return hidpp_send_rap_command_sync( + hidpp_dev, + REPORT_ID_HIDPP_SHORT, + M560_SUB_ID, + M560_BUTTON_MODE_REGISTER, + (u8 *)m560_config_parameter, + sizeof(m560_config_parameter), + &response + ); +} + +static int m560_allocate(struct hid_device *hdev) +{ + struct hidpp_device *hidpp = hid_get_drvdata(hdev); + struct m560_private_data *d; + + d = devm_kzalloc(&hdev->dev, sizeof(struct m560_private_data), + GFP_KERNEL); + if (!d) + return -ENOMEM; + + hidpp->private_data = d; + + return 0; +}; + +static int m560_raw_event(struct hid_device *hdev, u8 *data, int size) +{ + struct hidpp_device *hidpp = hid_get_drvdata(hdev); + struct m560_private_data *mydata = hidpp->private_data; + + /* sanity check */ + if (!mydata || !mydata->input) { + hid_err(hdev, "error in parameter\n"); + return -EINVAL; + } + + if (size < 7) { + hid_err(hdev, "error in report\n"); + return 0; + } + + if (data[0] == REPORT_ID_HIDPP_LONG && + data[2] == M560_SUB_ID && data[6] == 0x00) { + /* + * m560 mouse report for middle, forward and backward button + * + * data[0] = 0x11 + * data[1] = device-id + * data[2] = 0x0a + * data[5] = 0xaf -> middle + * 0xb0 -> forward + * 0xae -> backward + * 0x00 -> release all + * data[6] = 0x00 + */ + + switch (data[5]) { + case 0xaf: + input_report_key(mydata->input, BTN_MIDDLE, 1); + break; + case 0xb0: + input_report_key(mydata->input, BTN_FORWARD, 1); + break; + case 0xae: + input_report_key(mydata->input, BTN_BACK, 1); + break; + case 0x00: + input_report_key(mydata->input, BTN_BACK, 0); + input_report_key(mydata->input, BTN_FORWARD, 0); + input_report_key(mydata->input, BTN_MIDDLE, 0); + break; + default: + hid_err(hdev, "error in report\n"); + return 0; + } + input_sync(mydata->input); + + } else if (data[0] == 0x02) { + /* + * Logitech M560 mouse report + * + * data[0] = type (0x02) + * data[1..2] = buttons + * data[3..5] = xy + * data[6] = wheel + */ + + int v; + + input_report_key(mydata->input, BTN_LEFT, + !!(data[1] & M560_MOUSE_BTN_LEFT)); + input_report_key(mydata->input, BTN_RIGHT, + !!(data[1] & M560_MOUSE_BTN_RIGHT)); + + if (data[1] & M560_MOUSE_BTN_WHEEL_LEFT) + input_report_rel(mydata->input, REL_HWHEEL, -1); + else if (data[1] & M560_MOUSE_BTN_WHEEL_RIGHT) + input_report_rel(mydata->input, REL_HWHEEL, 1); + + v = hid_snto32(hid_field_extract(hdev, data+3, 0, 12), 12); + input_report_rel(mydata->input, REL_X, v); + + v = hid_snto32(hid_field_extract(hdev, data+3, 12, 12), 12); + input_report_rel(mydata->input, REL_Y, v); + + v = hid_snto32(data[6], 8); + input_report_rel(mydata->input, REL_WHEEL, v); + + input_sync(mydata->input); + } + + return 1; +} + +static void m560_populate_input(struct hidpp_device *hidpp, + struct input_dev *input_dev, bool origin_is_hid_core) +{ + struct m560_private_data *mydata = hidpp->private_data; + + mydata->input = input_dev; + + __set_bit(EV_KEY, mydata->input->evbit); + __set_bit(BTN_MIDDLE, mydata->input->keybit); + __set_bit(BTN_RIGHT, mydata->input->keybit); + __set_bit(BTN_LEFT, mydata->input->keybit); + __set_bit(BTN_BACK, mydata->input->keybit); + __set_bit(BTN_FORWARD, mydata->input->keybit); + + __set_bit(EV_REL, mydata->input->evbit); + __set_bit(REL_X, mydata->input->relbit); + __set_bit(REL_Y, mydata->input->relbit); + __set_bit(REL_WHEEL, mydata->input->relbit); + __set_bit(REL_HWHEEL, mydata->input->relbit); +} + +static int m560_input_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + return -1; +} + /* -------------------------------------------------------------------------- */ /* Generic HID++ devices */ /* -------------------------------------------------------------------------- */ @@ -953,6 +1155,9 @@ static int hidpp_input_mapping(struct hid_device *hdev, struct hid_input *hi, if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) return wtp_input_mapping(hdev, hi, field, usage, bit, max); + else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560 && + field->application != HID_GD_MOUSE) + return m560_input_mapping(hdev, hi, field, usage, bit, max); return 0; } @@ -962,6 +1167,8 @@ static void hidpp_populate_input(struct hidpp_device *hidpp, { if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) wtp_populate_input(hidpp, input, origin_is_hid_core); + else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560) + m560_populate_input(hidpp, input, origin_is_hid_core); } static void hidpp_input_configured(struct hid_device *hdev, @@ -1049,6 +1256,8 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report, if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) return wtp_raw_event(hdev, data, size); + else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560) + return m560_raw_event(hdev, data, size); return 0; } @@ -1126,6 +1335,10 @@ static void hidpp_connect_event(struct hidpp_device *hidpp) ret = wtp_connect(hdev, connected); if (ret) return; + } else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560) { + ret = m560_send_config_command(hdev, connected); + if (ret) + return; } if (!connected || hidpp->delayed_input) @@ -1201,7 +1414,11 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id) if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) { ret = wtp_allocate(hdev, id); if (ret) - goto wtp_allocate_fail; + goto allocate_fail; + } else if (hidpp->quirks & HIDPP_QUIRK_CLASS_M560) { + ret = m560_allocate(hdev); + if (ret) + goto allocate_fail; } INIT_WORK(&hidpp->work, delayed_work_cb); @@ -1268,7 +1485,7 @@ hid_hw_start_fail: hid_parse_fail: cancel_work_sync(&hidpp->work); mutex_destroy(&hidpp->send_mutex); -wtp_allocate_fail: +allocate_fail: hid_set_drvdata(hdev, NULL); return ret; } @@ -1301,6 +1518,10 @@ static const struct hid_device_id hidpp_devices[] = { USB_VENDOR_ID_LOGITECH, 0x4102), .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_MULTI_INPUT | HIDPP_QUIRK_CLASS_WTP }, + { /* Mouse logitech M560 */ + HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, + USB_VENDOR_ID_LOGITECH, 0x402d), + .driver_data = HIDPP_QUIRK_DELAYED_INIT | HIDPP_QUIRK_CLASS_M560 }, { HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE, USB_VENDOR_ID_LOGITECH, HID_ANY_ID)}, -- cgit v0.10.2 From 0317a65b94770c953480970f67db0a716778c6a7 Mon Sep 17 00:00:00 2001 From: Dennis O'Brien Date: Sun, 31 May 2015 09:19:59 -0700 Subject: usb, HID: Remove Vernier devices from lsusb and hid_ignore_list Removes Vernier Software & Technology devices from the ldusb driver and the hid_ignore_list table of the usbhid driver in the Linux tree. These devices will now be supported via the hidraw driver. A user space driver for these devices will be found in the Go! Software Development Kit from Vernier at http://www.vernier.com/downloads/software-development-kits/go-sdk/. These devices are also be supported by the LabQuest2 standalone interface shown at http://www.vernier.com/products/interfaces/labq2/ and the LoggerPro for Linux software shown at http://www.vernier.com/downloads/logger-pro-linux/. Signed-off-by: Dennis O'Brien Acked-by: Greg Kroah-Hartman Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index e880769..2a0bd8e 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2391,11 +2391,6 @@ static const struct hid_device_id hid_ignore_list[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_WTP) }, { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_DPAD) }, #endif - { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO) }, - { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) }, - { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) }, - { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS) }, - { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LCSPEC) }, { HID_USB_DEVICE(USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K) }, { HID_USB_DEVICE(USB_VENDOR_ID_RISO_KAGAKU, USB_DEVICE_ID_RI_KA_WEBMAIL) }, { } diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index cf0a537..005335e 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -947,13 +947,6 @@ #define USB_DEVICE_ID_VELLEMAN_K8061_FIRST 0x8061 #define USB_DEVICE_ID_VELLEMAN_K8061_LAST 0x8068 -#define USB_VENDOR_ID_VERNIER 0x08f7 -#define USB_DEVICE_ID_VERNIER_LABPRO 0x0001 -#define USB_DEVICE_ID_VERNIER_GOTEMP 0x0002 -#define USB_DEVICE_ID_VERNIER_SKIP 0x0003 -#define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004 -#define USB_DEVICE_ID_VERNIER_LCSPEC 0x0006 - #define USB_VENDOR_ID_VTL 0x0306 #define USB_DEVICE_ID_VTL_MULTITOUCH_FF3F 0xff3f diff --git a/drivers/usb/misc/ldusb.c b/drivers/usb/misc/ldusb.c index 82503a7..cce22ff 100644 --- a/drivers/usb/misc/ldusb.c +++ b/drivers/usb/misc/ldusb.c @@ -69,12 +69,6 @@ #define USB_DEVICE_ID_LD_HYBRID 0x2090 /* USB Product ID of Automotive Hybrid */ #define USB_DEVICE_ID_LD_HEATCONTROL 0x20A0 /* USB Product ID of Heat control */ -#define USB_VENDOR_ID_VERNIER 0x08f7 -#define USB_DEVICE_ID_VERNIER_GOTEMP 0x0002 -#define USB_DEVICE_ID_VERNIER_SKIP 0x0003 -#define USB_DEVICE_ID_VERNIER_CYCLOPS 0x0004 -#define USB_DEVICE_ID_VERNIER_LCSPEC 0x0006 - #ifdef CONFIG_USB_DYNAMIC_MINORS #define USB_LD_MINOR_BASE 0 #else @@ -115,10 +109,6 @@ static const struct usb_device_id ld_usb_table[] = { { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_MCT) }, { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HYBRID) }, { USB_DEVICE(USB_VENDOR_ID_LD, USB_DEVICE_ID_LD_HEATCONTROL) }, - { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) }, - { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) }, - { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_CYCLOPS) }, - { USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LCSPEC) }, { } /* Terminating entry */ }; MODULE_DEVICE_TABLE(usb, ld_usb_table); -- cgit v0.10.2 From 3e48138c2c66d8ff7d96c87a0535cd50078c742f Mon Sep 17 00:00:00 2001 From: Andrew Duggan Date: Tue, 2 Jun 2015 14:46:20 -0700 Subject: HID: i2c-hid: Do not set the ACPI companion field in the HID device The HID device does not need to know about the ACPI device associated with the underlying i2c device. Setting the ACPI companion field in the HID device also has the side effect of causing HID to be set as wake capable, since acpi_bind_one uses's the companion ACPI device's wakeup flags to set the device as wake capable. Which results in power/wakeup files in sysfs for the HID device which do not do anything. Signed-off-by: Andrew Duggan Reviewed-by: Benson Leung Tested-by: Benson Leung Acked-by: Mika Westerberg Signed-off-by: Jiri Kosina diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 92d6cdf..0dfb5d1 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -1019,7 +1019,6 @@ static int i2c_hid_probe(struct i2c_client *client, hid->driver_data = client; hid->ll_driver = &i2c_hid_ll_driver; hid->dev.parent = &client->dev; - ACPI_COMPANION_SET(&hid->dev, ACPI_COMPANION(&client->dev)); hid->bus = BUS_I2C; hid->version = le16_to_cpu(ihid->hdesc.bcdVersion); hid->vendor = le16_to_cpu(ihid->hdesc.wVendorID); -- cgit v0.10.2 From a4afa8544d49237a7d9e492ead047501de69aa25 Mon Sep 17 00:00:00 2001 From: Simon Wood Date: Wed, 3 Jun 2015 09:45:19 -0600 Subject: HID: sony: Support PS3 Move Controller when connected via Bluetooth Signed-off-by: Simon Wood Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index aefb248..044e96a 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1960,6 +1960,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_BUZZ_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_MOTION_CONTROLLER) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_MOTION_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_BDREMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index aeb8b41..6fcc2b4 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -2262,6 +2262,8 @@ static const struct hid_device_id sony_devices[] = { .driver_data = SIXAXIS_CONTROLLER_USB }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_MOTION_CONTROLLER), .driver_data = MOTION_CONTROLLER }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_MOTION_CONTROLLER), + .driver_data = MOTION_CONTROLLER }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER), .driver_data = SIXAXIS_CONTROLLER_BT }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE), -- cgit v0.10.2 From b3bca326fa813e4770f74f9ceffe97b72e281475 Mon Sep 17 00:00:00 2001 From: Simon Wood Date: Tue, 9 Jun 2015 21:27:04 -0600 Subject: HID: sony: Add quirk for MOTION_CONTROLLER_BT Split quirk for PS Move Controller as it has to be treated differently when connected via BT. Signed-off-by: Simon Wood Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 6fcc2b4..28dba6c 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -46,9 +46,11 @@ #define PS3REMOTE BIT(4) #define DUALSHOCK4_CONTROLLER_USB BIT(5) #define DUALSHOCK4_CONTROLLER_BT BIT(6) -#define MOTION_CONTROLLER BIT(7) +#define MOTION_CONTROLLER_USB BIT(7) +#define MOTION_CONTROLLER_BT BIT(8) #define SIXAXIS_CONTROLLER (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT) +#define MOTION_CONTROLLER (MOTION_CONTROLLER_USB | MOTION_CONTROLLER_BT) #define DUALSHOCK4_CONTROLLER (DUALSHOCK4_CONTROLLER_USB |\ DUALSHOCK4_CONTROLLER_BT) #define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER | BUZZ_CONTROLLER |\ @@ -2261,9 +2263,9 @@ static const struct hid_device_id sony_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER), .driver_data = SIXAXIS_CONTROLLER_USB }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_MOTION_CONTROLLER), - .driver_data = MOTION_CONTROLLER }, + .driver_data = MOTION_CONTROLLER_USB }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_MOTION_CONTROLLER), - .driver_data = MOTION_CONTROLLER }, + .driver_data = MOTION_CONTROLLER_BT }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER), .driver_data = SIXAXIS_CONTROLLER_BT }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE), -- cgit v0.10.2 From 12e9a6d72b3ac33e542b6001ccd891d7b41fff10 Mon Sep 17 00:00:00 2001 From: Simon Wood Date: Tue, 9 Jun 2015 21:27:05 -0600 Subject: HID: sony: Add support PS3 Move Battery via BT Add support for the battery charge level and state to be read via BT. This is not support via USB as there is no know way to get the device sending 'input' reports over USB. Signed-off-by: Simon Wood Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 28dba6c..d9fa804 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -55,7 +55,8 @@ DUALSHOCK4_CONTROLLER_BT) #define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER | BUZZ_CONTROLLER |\ DUALSHOCK4_CONTROLLER | MOTION_CONTROLLER) -#define SONY_BATTERY_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER) +#define SONY_BATTERY_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER |\ + MOTION_CONTROLLER_BT) #define SONY_FF_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER |\ MOTION_CONTROLLER) @@ -1041,6 +1042,7 @@ static void sixaxis_parse_report(struct sony_sc *sc, __u8 *rd, int size) { static const __u8 sixaxis_battery_capacity[] = { 0, 1, 25, 50, 75, 100 }; unsigned long flags; + int offset; __u8 cable_state, battery_capacity, battery_charging; /* @@ -1049,12 +1051,14 @@ static void sixaxis_parse_report(struct sony_sc *sc, __u8 *rd, int size) * It does not report the actual level while charging so it * is set to 100% while charging is in progress. */ - if (rd[30] >= 0xee) { + offset = (sc->quirks & MOTION_CONTROLLER) ? 12 : 30; + + if (rd[offset] >= 0xee) { battery_capacity = 100; - battery_charging = !(rd[30] & 0x01); + battery_charging = !(rd[offset] & 0x01); cable_state = 1; } else { - __u8 index = rd[30] <= 5 ? rd[30] : 5; + __u8 index = rd[offset] <= 5 ? rd[offset] : 5; battery_capacity = sixaxis_battery_capacity[index]; battery_charging = 0; cable_state = 0; @@ -1155,6 +1159,8 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report, swap(rd[47], rd[48]); sixaxis_parse_report(sc, rd, size); + } else if ((sc->quirks & MOTION_CONTROLLER_BT) && rd[0] == 0x01 && size == 49) { + sixaxis_parse_report(sc, rd, size); } else if (((sc->quirks & DUALSHOCK4_CONTROLLER_USB) && rd[0] == 0x01 && size == 64) || ((sc->quirks & DUALSHOCK4_CONTROLLER_BT) && rd[0] == 0x11 && size == 78)) { @@ -1976,6 +1982,7 @@ static int sony_check_add(struct sony_sc *sc) int n, ret; if ((sc->quirks & DUALSHOCK4_CONTROLLER_BT) || + (sc->quirks & MOTION_CONTROLLER_BT) || (sc->quirks & SIXAXIS_CONTROLLER_BT)) { /* * sony_get_bt_devaddr() attempts to parse the Bluetooth MAC -- cgit v0.10.2 From 41d2d42534e79561930aa831870352a80cd2e72c Mon Sep 17 00:00:00 2001 From: Simon Wood Date: Tue, 9 Jun 2015 21:27:06 -0600 Subject: HID: sony: PS3 Move enable LEDs and Rumble via BT The LED and Rumble control only function via BT if the full output report is sent. The large report still functions via USB. Signed-off-by: Simon Wood Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index d9fa804..51cb1ac 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -902,6 +902,7 @@ struct motion_output_report_02 { #define DS4_REPORT_0x81_SIZE 7 #define SIXAXIS_REPORT_0xF2_SIZE 17 #define SIXAXIS_REPORT_0xF5_SIZE 8 +#define MOTION_REPORT_0x02_SIZE 49 static DEFINE_SPINLOCK(sony_dev_list_lock); static LIST_HEAD(sony_device_list); @@ -1746,7 +1747,7 @@ static void motion_state_worker(struct work_struct *work) struct motion_output_report_02 *report = (struct motion_output_report_02 *)sc->output_report_dmabuf; - memset(report, 0, sizeof(struct motion_output_report_02)); + memset(report, 0, MOTION_REPORT_0x02_SIZE); report->type = 0x02; /* set leds */ report->r = sc->led_state[0]; @@ -1757,8 +1758,7 @@ static void motion_state_worker(struct work_struct *work) report->rumble = max(sc->right, sc->left); #endif - hid_hw_output_report(hdev, (__u8 *)report, - sizeof(struct motion_output_report_02)); + hid_hw_output_report(hdev, (__u8 *)report, MOTION_REPORT_0x02_SIZE); } static int sony_allocate_output_report(struct sony_sc *sc) @@ -1774,9 +1774,8 @@ static int sony_allocate_output_report(struct sony_sc *sc) sc->output_report_dmabuf = kmalloc(DS4_REPORT_0x05_SIZE, GFP_KERNEL); else if (sc->quirks & MOTION_CONTROLLER) - sc->output_report_dmabuf = - kmalloc(sizeof(struct motion_output_report_02), - GFP_KERNEL); + sc->output_report_dmabuf = kmalloc(MOTION_REPORT_0x02_SIZE, + GFP_KERNEL); else return 0; -- cgit v0.10.2 From 8b2513c313612541085a19551139e68ccab13b3f Mon Sep 17 00:00:00 2001 From: Simon Wood Date: Tue, 9 Jun 2015 21:27:07 -0600 Subject: HID: sony: PS Move fix report descriptor Fix the report descriptor so that the buttons and trigger are correctly reported. The format of the input report is described here: https://github.com/nitsch/moveonpc/wiki/Input-report The Accelerometers and Gyros (1st frame only) are also reported as axis, but the Magnetometers are NOT as 'fixing' their byte order would break user-space drivers such as PSMoveAPI. It is hoped to resolve this at a future time. Signed-off-by: Simon Wood Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 51cb1ac..2ce0295 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -153,52 +153,71 @@ static __u8 motion_rdesc[] = { 0xA1, 0x01, /* Collection (Application), */ 0xA1, 0x02, /* Collection (Logical), */ 0x85, 0x01, /* Report ID (1), */ - 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x01, /* Report Count (1), */ - 0x15, 0x00, /* Logical Minimum (0), */ - 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ - 0x81, 0x03, /* Input (Constant, Variable), */ 0x75, 0x01, /* Report Size (1), */ - 0x95, 0x13, /* Report Count (19), */ + 0x95, 0x15, /* Report Count (21), */ 0x15, 0x00, /* Logical Minimum (0), */ 0x25, 0x01, /* Logical Maximum (1), */ 0x35, 0x00, /* Physical Minimum (0), */ 0x45, 0x01, /* Physical Maximum (1), */ 0x05, 0x09, /* Usage Page (Button), */ 0x19, 0x01, /* Usage Minimum (01h), */ - 0x29, 0x13, /* Usage Maximum (13h), */ - 0x81, 0x02, /* Input (Variable), */ - 0x75, 0x01, /* Report Size (1), */ - 0x95, 0x0D, /* Report Count (13), */ + 0x29, 0x15, /* Usage Maximum (15h), */ + 0x81, 0x02, /* Input (Variable), * Buttons */ + 0x95, 0x0B, /* Report Count (11), */ 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ - 0x81, 0x03, /* Input (Constant, Variable), */ + 0x81, 0x03, /* Input (Constant, Variable), * Padding */ 0x15, 0x00, /* Logical Minimum (0), */ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ 0x05, 0x01, /* Usage Page (Desktop), */ - 0x09, 0x01, /* Usage (Pointer), */ 0xA1, 0x00, /* Collection (Physical), */ 0x75, 0x08, /* Report Size (8), */ - 0x95, 0x04, /* Report Count (4), */ + 0x95, 0x01, /* Report Count (1), */ 0x35, 0x00, /* Physical Minimum (0), */ 0x46, 0xFF, 0x00, /* Physical Maximum (255), */ 0x09, 0x30, /* Usage (X), */ - 0x09, 0x31, /* Usage (Y), */ - 0x09, 0x32, /* Usage (Z), */ - 0x09, 0x35, /* Usage (Rz), */ - 0x81, 0x02, /* Input (Variable), */ + 0x81, 0x02, /* Input (Variable), * Trigger */ 0xC0, /* End Collection, */ - 0x05, 0x01, /* Usage Page (Desktop), */ - 0x95, 0x13, /* Report Count (19), */ - 0x09, 0x01, /* Usage (Pointer), */ + 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x07, /* Report Count (7), * skip 7 bytes */ 0x81, 0x02, /* Input (Variable), */ - 0x95, 0x0C, /* Report Count (12), */ - 0x81, 0x01, /* Input (Constant), */ + 0x05, 0x01, /* Usage Page (Desktop), */ 0x75, 0x10, /* Report Size (16), */ - 0x95, 0x04, /* Report Count (4), */ - 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */ - 0x46, 0xFF, 0x03, /* Physical Maximum (1023), */ + 0x46, 0xFF, 0xFF, /* Physical Maximum (65535), */ + 0x27, 0xFF, 0xFF, 0x00, 0x00, /* Logical Maximum (65535), */ + 0x95, 0x03, /* Report Count (3), * 3x Accels */ + 0x09, 0x33, /* Usage (rX), */ + 0x09, 0x34, /* Usage (rY), */ + 0x09, 0x35, /* Usage (rZ), */ + 0x81, 0x02, /* Input (Variable), */ + 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ + 0x95, 0x03, /* Report Count (3), * Skip Accels 2nd frame */ + 0x81, 0x02, /* Input (Variable), */ + 0x05, 0x01, /* Usage Page (Desktop), */ 0x09, 0x01, /* Usage (Pointer), */ + 0x95, 0x03, /* Report Count (3), * 3x Gyros */ + 0x81, 0x02, /* Input (Variable), */ + 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ + 0x95, 0x03, /* Report Count (3), * Skip Gyros 2nd frame */ 0x81, 0x02, /* Input (Variable), */ + 0x75, 0x0C, /* Report Size (12), */ + 0x46, 0xFF, 0x0F, /* Physical Maximum (4095), */ + 0x26, 0xFF, 0x0F, /* Logical Maximum (4095), */ + 0x95, 0x04, /* Report Count (4), * Skip Temp and Magnetometers */ + 0x81, 0x02, /* Input (Variable), */ + 0x75, 0x08, /* Report Size (8), */ + 0x46, 0xFF, 0x00, /* Physical Maximum (255), */ + 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ + 0x95, 0x06, /* Report Count (6), * Skip Timestamp and Extension Bytes */ + 0x81, 0x02, /* Input (Variable), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x30, /* Report Count (48), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0x91, 0x02, /* Output (Variable), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x30, /* Report Count (48), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0xB1, 0x02, /* Feature (Variable), */ 0xC0, /* End Collection, */ 0xA1, 0x02, /* Collection (Logical), */ 0x85, 0x02, /* Report ID (2), */ -- cgit v0.10.2 From 81bb773faed7f5f0e82f14cdfcfe4e89fbea0e19 Mon Sep 17 00:00:00 2001 From: Terry Junge Date: Mon, 8 Jun 2015 14:27:57 -0700 Subject: HID: plantronics: Update to map volume up/down controls Update Kconfig with enhanced help text for hid-plantronics driver. Update hid-plantronics.c to identify device type and correctly map either the vendor unique or consumer control volume up/down usages to KEY_VOLUMEUP and KEY_VOLUMEDOWN events. Unmapped usages are ignored to prevent core mapping of unknown usages to random mouse events. Tested on ChromeBox/ChromeBook with various Plantronics devices. Signed-off-by: Terry Junge Signed-off-by: Jiri Kosina diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 15338af..cc4c664 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -634,7 +634,12 @@ config HID_PLANTRONICS tristate "Plantronics USB HID Driver" depends on HID ---help--- - Provides HID support for Plantronics telephony devices. + Provides HID support for Plantronics USB audio devices. + Correctly maps vendor unique volume up/down HID usages to + KEY_VOLUMEUP and KEY_VOLUMEDOWN events and prevents core mapping + of other vendor unique HID usages to random mouse events. + + Say M here if you may ever plug in a Plantronics USB audio device. config HID_PRIMAX tristate "Primax non-fully HID-compliant devices" diff --git a/drivers/hid/hid-plantronics.c b/drivers/hid/hid-plantronics.c index 2180e07..febb21e 100644 --- a/drivers/hid/hid-plantronics.c +++ b/drivers/hid/hid-plantronics.c @@ -2,7 +2,7 @@ * Plantronics USB HID Driver * * Copyright (c) 2014 JD Cole - * Copyright (c) 2014 Terry Junge + * Copyright (c) 2015 Terry Junge */ /* @@ -17,23 +17,138 @@ #include #include +#define PLT_HID_1_0_PAGE 0xffa00000 +#define PLT_HID_2_0_PAGE 0xffa20000 + +#define PLT_BASIC_TELEPHONY 0x0003 +#define PLT_BASIC_EXCEPTION 0x0005 + +#define PLT_VOL_UP 0x00b1 +#define PLT_VOL_DOWN 0x00b2 + +#define PLT1_VOL_UP (PLT_HID_1_0_PAGE | PLT_VOL_UP) +#define PLT1_VOL_DOWN (PLT_HID_1_0_PAGE | PLT_VOL_DOWN) +#define PLT2_VOL_UP (PLT_HID_2_0_PAGE | PLT_VOL_UP) +#define PLT2_VOL_DOWN (PLT_HID_2_0_PAGE | PLT_VOL_DOWN) + +#define PLT_DA60 0xda60 +#define PLT_BT300_MIN 0x0413 +#define PLT_BT300_MAX 0x0418 + + +#define PLT_ALLOW_CONSUMER (field->application == HID_CP_CONSUMERCONTROL && \ + (usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER) + static int plantronics_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { - if (field->application == HID_CP_CONSUMERCONTROL - && (usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER) { - hid_dbg(hdev, "usage: %08x (appl: %08x) - defaulted\n", - usage->hid, field->application); - return 0; + unsigned short mapped_key; + unsigned long plt_type = (unsigned long)hid_get_drvdata(hdev); + + /* handle volume up/down mapping */ + /* non-standard types or multi-HID interfaces - plt_type is PID */ + if (!(plt_type & HID_USAGE_PAGE)) { + switch (plt_type) { + case PLT_DA60: + if (PLT_ALLOW_CONSUMER) + goto defaulted; + goto ignored; + default: + if (PLT_ALLOW_CONSUMER) + goto defaulted; + } + } + /* handle standard types - plt_type is 0xffa0uuuu or 0xffa2uuuu */ + /* 'basic telephony compliant' - allow default consumer page map */ + else if ((plt_type & HID_USAGE) >= PLT_BASIC_TELEPHONY && + (plt_type & HID_USAGE) != PLT_BASIC_EXCEPTION) { + if (PLT_ALLOW_CONSUMER) + goto defaulted; + } + /* not 'basic telephony' - apply legacy mapping */ + /* only map if the field is in the device's primary vendor page */ + else if (!((field->application ^ plt_type) & HID_USAGE_PAGE)) { + switch (usage->hid) { + case PLT1_VOL_UP: + case PLT2_VOL_UP: + mapped_key = KEY_VOLUMEUP; + goto mapped; + case PLT1_VOL_DOWN: + case PLT2_VOL_DOWN: + mapped_key = KEY_VOLUMEDOWN; + goto mapped; + } } - hid_dbg(hdev, "usage: %08x (appl: %08x) - ignored\n", - usage->hid, field->application); +/* + * Future mapping of call control or other usages, + * if and when keys are defined would go here + * otherwise, ignore everything else that was not mapped + */ +ignored: return -1; + +defaulted: + hid_dbg(hdev, "usage: %08x (appl: %08x) - defaulted\n", + usage->hid, field->application); + return 0; + +mapped: + hid_map_usage_clear(hi, usage, bit, max, EV_KEY, mapped_key); + hid_dbg(hdev, "usage: %08x (appl: %08x) - mapped to key %d\n", + usage->hid, field->application, mapped_key); + return 1; +} + +static unsigned long plantronics_device_type(struct hid_device *hdev) +{ + unsigned i, col_page; + unsigned long plt_type = hdev->product; + + /* multi-HID interfaces? - plt_type is PID */ + if (plt_type >= PLT_BT300_MIN && plt_type <= PLT_BT300_MAX) + goto exit; + + /* determine primary vendor page */ + for (i = 0; i < hdev->maxcollection; i++) { + col_page = hdev->collection[i].usage & HID_USAGE_PAGE; + if (col_page == PLT_HID_2_0_PAGE) { + plt_type = hdev->collection[i].usage; + break; + } + if (col_page == PLT_HID_1_0_PAGE) + plt_type = hdev->collection[i].usage; + } + +exit: + hid_dbg(hdev, "plt_type decoded as: %08lx\n", plt_type); + return plt_type; +} + +static int plantronics_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + int ret; + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "parse failed\n"); + goto err; + } + + hid_set_drvdata(hdev, (void *)plantronics_device_type(hdev)); + + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT | + HID_CONNECT_HIDINPUT_FORCE | HID_CONNECT_HIDDEV_FORCE); + if (ret) + hid_err(hdev, "hw start failed\n"); + +err: + return ret; } static const struct hid_device_id plantronics_devices[] = { @@ -46,6 +161,7 @@ static struct hid_driver plantronics_driver = { .name = "plantronics", .id_table = plantronics_devices, .input_mapping = plantronics_input_mapping, + .probe = plantronics_probe, }; module_hid_driver(plantronics_driver); -- cgit v0.10.2 From 10e87dc42a086c256b25334b6c1c89214feba9a7 Mon Sep 17 00:00:00 2001 From: Andrew Duggan Date: Tue, 16 Jun 2015 14:08:41 -0700 Subject: HID: rmi: Disable populating F30 when the touchpad has physical buttons Physical buttons do not use F30 to report their state and in some cases the data reported in F30 is incorrect and inconsistent with what is reported by the HID descriptor. When physical buttons are present, ignore F30 and let hid-input report buttons based on what is defined in the HID descriptor. Signed-off-by: Andrew Duggan Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index 368ffdf..721f7f9 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -1013,6 +1013,7 @@ static int rmi_populate_f30(struct hid_device *hdev) static int rmi_populate(struct hid_device *hdev) { + struct rmi_data *data = hid_get_drvdata(hdev); int ret; ret = rmi_scan_pdt(hdev); @@ -1033,9 +1034,11 @@ static int rmi_populate(struct hid_device *hdev) return ret; } - ret = rmi_populate_f30(hdev); - if (ret) - hid_warn(hdev, "Error while initializing F30 (%d).\n", ret); + if (!(data->device_flags & RMI_DEVICE_HAS_PHYS_BUTTONS)) { + ret = rmi_populate_f30(hdev); + if (ret) + hid_warn(hdev, "Error while initializing F30 (%d).\n", ret); + } return 0; } -- cgit v0.10.2 From 44b5250b97a0e5c3a257430ea28b10cf73899bd4 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Mon, 15 Jun 2015 18:01:41 -0700 Subject: HID: wacom: Simplify 'wacom_update_name' A little bit of cleanup work for 'wacom_update_name' to make it easier on the eyes. Creates a temporary 'name' variable on which we'll perform our edits. Once the name is in its final form, it will be copied (with appropriate suffix) to 'wacom_wac->name' and 'wacom_wac->pad_name'. Signed-off-by: Jason Gerecke Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index eea18a6..bdf31c9 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -1417,6 +1417,7 @@ static void wacom_update_name(struct wacom *wacom) { struct wacom_wac *wacom_wac = &wacom->wacom_wac; struct wacom_features *features = &wacom_wac->features; + char name[WACOM_NAME_MAX]; /* Generic devices name unspecified */ if ((features->type == HID_GENERIC) && !strcmp("Wacom HID", features->name)) { @@ -1424,41 +1425,43 @@ static void wacom_update_name(struct wacom *wacom) strstr(wacom->hdev->name, "wacom") || strstr(wacom->hdev->name, "WACOM")) { /* name is in HID descriptor, use it */ - strlcpy(wacom_wac->name, wacom->hdev->name, - sizeof(wacom_wac->name)); + strlcpy(name, wacom->hdev->name, sizeof(name)); /* strip out excess whitespaces */ while (1) { - char *gap = strstr(wacom_wac->name, " "); + char *gap = strstr(name, " "); if (gap == NULL) break; /* shift everything including the terminator */ memmove(gap, gap+1, strlen(gap)); } /* get rid of trailing whitespace */ - if (wacom_wac->name[strlen(wacom_wac->name)-1] == ' ') - wacom_wac->name[strlen(wacom_wac->name)-1] = '\0'; + if (name[strlen(name)-1] == ' ') + name[strlen(name)-1] = '\0'; } else { /* no meaningful name retrieved. use product ID */ - snprintf(wacom_wac->name, sizeof(wacom_wac->name), + snprintf(name, sizeof(name), "%s %X", features->name, wacom->hdev->product); } } else { - strlcpy(wacom_wac->name, features->name, sizeof(wacom_wac->name)); + strlcpy(name, features->name, sizeof(name)); } /* Append the device type to the name */ snprintf(wacom_wac->pad_name, sizeof(wacom_wac->pad_name), - "%s Pad", wacom_wac->name); + "%s Pad", name); if (features->device_type == BTN_TOOL_PEN) { - strlcat(wacom_wac->name, " Pen", WACOM_NAME_MAX); + snprintf(wacom_wac->name, sizeof(wacom_wac->name), + "%s Pen", name); } else if (features->device_type == BTN_TOOL_FINGER) { if (features->touch_max) - strlcat(wacom_wac->name, " Finger", WACOM_NAME_MAX); + snprintf(wacom_wac->name, sizeof(wacom_wac->name), + "%s Finger", name); else - strlcat(wacom_wac->name, " Pad", WACOM_NAME_MAX); + snprintf(wacom_wac->name, sizeof(wacom_wac->name), + "%s Pad", name); } } -- cgit v0.10.2 From aa86b18cc9cd147b40412a2d57b383a5e16fe3b5 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Mon, 15 Jun 2015 18:01:42 -0700 Subject: HID: wacom: Treat features->device_type values as flags The USB devices that this driver has historically supported segregate the pen and touch portions of the tablet. Oftentimes the segregation would be done at the interface level, though on occasion (e.g. Cintiq 24HDT) the tablet would combine two totally independent USB devices behind an internal USB hub. Because pen and touch never shared the same interface, it made sense for the 'device_type' to store a single value: "pen" or "touch". Recently, however, some I2C devices have been created which combine the two. A first step to accomodating this is to expand 'device_type' so that it can represent two (or potentially more) types simultaneously. To do this, we treat it as a bitfield and set/check individual bits rather than using the '=' and '==' operators. This should not result in any functional change since no supported devices (that I'm aware of, at least) have HID descriptors that indicate both pen and touch reports on a single interface. Signed-off-by: Jason Gerecke Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index bdf31c9..2b4cbd8 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -197,9 +197,9 @@ static void wacom_usage_mapping(struct hid_device *hdev, * values commonly reported. */ if (pen) - features->device_type = BTN_TOOL_PEN; + features->device_type |= WACOM_DEVICETYPE_PEN; else if (finger) - features->device_type = BTN_TOOL_FINGER; + features->device_type |= WACOM_DEVICETYPE_TOUCH; else return; @@ -411,7 +411,7 @@ static int wacom_query_tablet_data(struct hid_device *hdev, if (features->type == HID_GENERIC) return wacom_hid_set_device_mode(hdev); - if (features->device_type == BTN_TOOL_FINGER) { + if (features->device_type & WACOM_DEVICETYPE_TOUCH) { if (features->type > TABLETPC) { /* MT Tablet PC touch */ return wacom_set_device_mode(hdev, 3, 4, 4); @@ -425,7 +425,7 @@ static int wacom_query_tablet_data(struct hid_device *hdev, else if (features->type == BAMBOO_PAD) { return wacom_set_device_mode(hdev, 2, 2, 2); } - } else if (features->device_type == BTN_TOOL_PEN) { + } else if (features->device_type & WACOM_DEVICETYPE_PEN) { if (features->type <= BAMBOO_PT && features->type != WIRELESS) { return wacom_set_device_mode(hdev, 2, 2, 2); } @@ -454,9 +454,9 @@ static void wacom_retrieve_hid_descriptor(struct hid_device *hdev, */ if (features->type == WIRELESS) { if (intf->cur_altsetting->desc.bInterfaceNumber == 0) { - features->device_type = 0; + features->device_type = WACOM_DEVICETYPE_NONE; } else if (intf->cur_altsetting->desc.bInterfaceNumber == 2) { - features->device_type = BTN_TOOL_FINGER; + features->device_type |= WACOM_DEVICETYPE_TOUCH; features->pktlen = WACOM_PKGLEN_BBTOUCH3; } } @@ -538,9 +538,9 @@ static int wacom_add_shared_data(struct hid_device *hdev) wacom_wac->shared = &data->shared; - if (wacom_wac->features.device_type == BTN_TOOL_FINGER) + if (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH) wacom_wac->shared->touch = hdev; - else if (wacom_wac->features.device_type == BTN_TOOL_PEN) + else if (wacom_wac->features.device_type & WACOM_DEVICETYPE_PEN) wacom_wac->shared->pen = hdev; out: @@ -892,7 +892,7 @@ static int wacom_initialize_leds(struct wacom *wacom) case INTUOSPS: case INTUOSPM: case INTUOSPL: - if (wacom->wacom_wac.features.device_type == BTN_TOOL_PEN) { + if (wacom->wacom_wac.features.device_type & WACOM_DEVICETYPE_PEN) { wacom->led.select[0] = 0; wacom->led.select[1] = 0; wacom->led.llv = 32; @@ -948,7 +948,7 @@ static void wacom_destroy_leds(struct wacom *wacom) case INTUOSPS: case INTUOSPM: case INTUOSPL: - if (wacom->wacom_wac.features.device_type == BTN_TOOL_PEN) + if (wacom->wacom_wac.features.device_type & WACOM_DEVICETYPE_PEN) sysfs_remove_group(&wacom->hdev->dev.kobj, &intuos5_led_attr_group); break; @@ -1296,7 +1296,7 @@ static void wacom_wireless_work(struct work_struct *work) /* Stylus interface */ wacom_wac1->features = *((struct wacom_features *)id->driver_data); - wacom_wac1->features.device_type = BTN_TOOL_PEN; + wacom_wac1->features.device_type |= WACOM_DEVICETYPE_PEN; snprintf(wacom_wac1->name, WACOM_NAME_MAX, "%s (WL) Pen", wacom_wac1->features.name); snprintf(wacom_wac1->pad_name, WACOM_NAME_MAX, "%s (WL) Pad", @@ -1315,7 +1315,7 @@ static void wacom_wireless_work(struct work_struct *work) wacom_wac2->features = *((struct wacom_features *)id->driver_data); wacom_wac2->features.pktlen = WACOM_PKGLEN_BBTOUCH3; - wacom_wac2->features.device_type = BTN_TOOL_FINGER; + wacom_wac2->features.device_type |= WACOM_DEVICETYPE_TOUCH; wacom_wac2->features.x_max = wacom_wac2->features.y_max = 4096; if (wacom_wac2->features.touch_max) snprintf(wacom_wac2->name, WACOM_NAME_MAX, @@ -1451,11 +1451,11 @@ static void wacom_update_name(struct wacom *wacom) snprintf(wacom_wac->pad_name, sizeof(wacom_wac->pad_name), "%s Pad", name); - if (features->device_type == BTN_TOOL_PEN) { + if (features->device_type & WACOM_DEVICETYPE_PEN) { snprintf(wacom_wac->name, sizeof(wacom_wac->name), "%s Pen", name); } - else if (features->device_type == BTN_TOOL_FINGER) { + else if (features->device_type & WACOM_DEVICETYPE_TOUCH) { if (features->touch_max) snprintf(wacom_wac->name, sizeof(wacom_wac->name), "%s Finger", name); @@ -1545,7 +1545,8 @@ static int wacom_probe(struct hid_device *hdev, wacom_retrieve_hid_descriptor(hdev, features); wacom_setup_device_quirks(wacom); - if (!features->device_type && features->type != WIRELESS) { + if (features->device_type == WACOM_DEVICETYPE_NONE && + features->type != WIRELESS) { error = features->type == HID_GENERIC ? -ENODEV : 0; dev_warn(&hdev->dev, "Unknown device_type for '%s'. %s.", @@ -1555,7 +1556,7 @@ static int wacom_probe(struct hid_device *hdev, if (error) goto fail_shared_data; - features->device_type = BTN_TOOL_PEN; + features->device_type |= WACOM_DEVICETYPE_PEN; } wacom_calculate_res(features); @@ -1604,7 +1605,7 @@ static int wacom_probe(struct hid_device *hdev, error = hid_hw_open(hdev); if (wacom_wac->features.type == INTUOSHT && wacom_wac->features.touch_max) { - if (wacom_wac->features.device_type == BTN_TOOL_FINGER) + if (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH) wacom_wac->shared->touch_input = wacom_wac->input; } diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index a52fc25..5e7710d 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2168,7 +2168,7 @@ void wacom_setup_device_quirks(struct wacom *wacom) struct wacom_features *features = &wacom->wacom_wac.features; /* touch device found but size is not defined. use default */ - if (features->device_type == BTN_TOOL_FINGER && !features->x_max) { + if (features->device_type & WACOM_DEVICETYPE_TOUCH && !features->x_max) { features->x_max = 1023; features->y_max = 1023; } @@ -2182,7 +2182,7 @@ void wacom_setup_device_quirks(struct wacom *wacom) if ((features->type >= INTUOS5S && features->type <= INTUOSHT) || (features->type == BAMBOO_PT)) { if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) { - features->device_type = BTN_TOOL_FINGER; + features->device_type |= WACOM_DEVICETYPE_TOUCH; features->x_max = 4096; features->y_max = 4096; @@ -2197,7 +2197,7 @@ void wacom_setup_device_quirks(struct wacom *wacom) * so rewrite this one to be of type BTN_TOOL_FINGER. */ if (features->type == BAMBOO_PAD) - features->device_type = BTN_TOOL_FINGER; + features->device_type |= WACOM_DEVICETYPE_TOUCH; if (wacom->hdev->bus == BUS_BLUETOOTH) features->quirks |= WACOM_QUIRK_BATTERY; @@ -2218,7 +2218,7 @@ void wacom_setup_device_quirks(struct wacom *wacom) features->quirks |= WACOM_QUIRK_NO_INPUT; /* must be monitor interface if no device_type set */ - if (!features->device_type) { + if (features->device_type == WACOM_DEVICETYPE_NONE) { features->quirks |= WACOM_QUIRK_MONITOR; features->quirks |= WACOM_QUIRK_BATTERY; } @@ -2230,7 +2230,7 @@ static void wacom_abs_set_axis(struct input_dev *input_dev, { struct wacom_features *features = &wacom_wac->features; - if (features->device_type == BTN_TOOL_PEN) { + if (features->device_type & WACOM_DEVICETYPE_PEN) { input_set_abs_params(input_dev, ABS_X, features->x_min, features->x_max, features->x_fuzz, 0); input_set_abs_params(input_dev, ABS_Y, features->y_min, @@ -2349,7 +2349,7 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, case INTUOSPS: __set_bit(INPUT_PROP_POINTER, input_dev->propbit); - if (features->device_type == BTN_TOOL_PEN) { + if (features->device_type & WACOM_DEVICETYPE_PEN) { input_set_abs_params(input_dev, ABS_DISTANCE, 0, features->distance_max, 0, 0); @@ -2358,7 +2358,7 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, input_abs_set_res(input_dev, ABS_Z, 287); wacom_setup_intuos(wacom_wac); - } else if (features->device_type == BTN_TOOL_FINGER) { + } else if (features->device_type & WACOM_DEVICETYPE_TOUCH) { __clear_bit(ABS_MISC, input_dev->absbit); input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, @@ -2370,7 +2370,7 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, break; case WACOM_24HDT: - if (features->device_type == BTN_TOOL_FINGER) { + if (features->device_type & WACOM_DEVICETYPE_TOUCH) { input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, features->x_max, 0, 0); input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, features->x_max, 0, 0); input_set_abs_params(input_dev, ABS_MT_WIDTH_MINOR, 0, features->y_max, 0, 0); @@ -2383,7 +2383,7 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, case MTTPC: case MTTPC_B: case TABLETPC2FG: - if (features->device_type == BTN_TOOL_FINGER && features->touch_max > 1) + if (features->device_type & WACOM_DEVICETYPE_TOUCH && features->touch_max > 1) input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_DIRECT); /* fall through */ @@ -2393,7 +2393,7 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); - if (features->device_type != BTN_TOOL_PEN) + if (!(features->device_type & WACOM_DEVICETYPE_PEN)) break; /* no need to process stylus stuff */ /* fall through */ @@ -2424,7 +2424,7 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, case INTUOSHT: if (features->touch_max && - features->device_type == BTN_TOOL_FINGER) { + features->device_type & WACOM_DEVICETYPE_TOUCH) { input_dev->evbit[0] |= BIT_MASK(EV_SW); __set_bit(SW_MUTE_DEVICE, input_dev->swbit); } @@ -2433,7 +2433,7 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, case BAMBOO_PT: __clear_bit(ABS_MISC, input_dev->absbit); - if (features->device_type == BTN_TOOL_FINGER) { + if (features->device_type & WACOM_DEVICETYPE_TOUCH) { if (features->touch_max) { if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) { @@ -2454,7 +2454,7 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, /* PAD is setup by wacom_setup_pad_input_capabilities later */ return 1; } - } else if (features->device_type == BTN_TOOL_PEN) { + } else if (features->device_type & WACOM_DEVICETYPE_PEN) { __set_bit(INPUT_PROP_POINTER, input_dev->propbit); __set_bit(BTN_TOOL_RUBBER, input_dev->keybit); __set_bit(BTN_TOOL_PEN, input_dev->keybit); @@ -2619,7 +2619,7 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, case INTUOS5S: case INTUOSPS: /* touch interface does not have the pad device */ - if (features->device_type != BTN_TOOL_PEN) + if (!(features->device_type & WACOM_DEVICETYPE_PEN)) return -ENODEV; for (i = 0; i < 7; i++) @@ -2664,7 +2664,7 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, case INTUOSHT: case BAMBOO_PT: /* pad device is on the touch interface */ - if ((features->device_type != BTN_TOOL_FINGER) || + if (!(features->device_type & WACOM_DEVICETYPE_TOUCH) || /* Bamboo Pen only tablet does not have pad */ ((features->type == BAMBOO_PT) && !features->touch_max)) return -ENODEV; diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index 9a5ee62..da2b309 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -72,6 +72,11 @@ #define WACOM_QUIRK_MONITOR 0x0004 #define WACOM_QUIRK_BATTERY 0x0008 +/* device types */ +#define WACOM_DEVICETYPE_NONE 0x0000 +#define WACOM_DEVICETYPE_PEN 0x0001 +#define WACOM_DEVICETYPE_TOUCH 0x0002 + #define WACOM_VENDORDEFINED_PEN 0xff0d0001 #define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \ -- cgit v0.10.2 From 862cf5535c0cf4b39ce71a3b7e9a1c22ae4f70ae Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Mon, 15 Jun 2015 18:01:43 -0700 Subject: HID: wacom: Introduce a new WACOM_DEVICETYPE_PAD device_type Historically, both the touch and pad tools would have shared the 'BTN_TOOL_FINGER' type. Any time you needed to distinguish the two, you had to use some other bit of knowledge (e.g. that the pad was on the same interface as the pen, and thus 'touch_max' would be zero). To make these checks more readable, we introduce WACOM_DEVICETYPE_PAD. Although we still have to rely on other bits of knowledge to set this bit on the right interface (since it cannot be detected from the HID descriptor), it can be done just once inside 'wacom_setup_device_quirks'. This patch introduces no functional changes. Signed-off-by: Jason Gerecke Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 2b4cbd8..aaa9c84 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -859,6 +859,9 @@ static int wacom_initialize_leds(struct wacom *wacom) { int error; + if (!(wacom->wacom_wac.features.device_type & WACOM_DEVICETYPE_PAD)) + return 0; + /* Initialize default values */ switch (wacom->wacom_wac.features.type) { case INTUOS4S: @@ -892,17 +895,14 @@ static int wacom_initialize_leds(struct wacom *wacom) case INTUOSPS: case INTUOSPM: case INTUOSPL: - if (wacom->wacom_wac.features.device_type & WACOM_DEVICETYPE_PEN) { - wacom->led.select[0] = 0; - wacom->led.select[1] = 0; - wacom->led.llv = 32; - wacom->led.hlv = 0; - wacom->led.img_lum = 0; - - error = sysfs_create_group(&wacom->hdev->dev.kobj, - &intuos5_led_attr_group); - } else - return 0; + wacom->led.select[0] = 0; + wacom->led.select[1] = 0; + wacom->led.llv = 32; + wacom->led.hlv = 0; + wacom->led.img_lum = 0; + + error = sysfs_create_group(&wacom->hdev->dev.kobj, + &intuos5_led_attr_group); break; default: @@ -925,6 +925,9 @@ static void wacom_destroy_leds(struct wacom *wacom) if (!wacom->led_initialized) return; + if (!(wacom->wacom_wac.features.device_type & WACOM_DEVICETYPE_PAD)) + return; + wacom->led_initialized = false; switch (wacom->wacom_wac.features.type) { @@ -948,9 +951,8 @@ static void wacom_destroy_leds(struct wacom *wacom) case INTUOSPS: case INTUOSPM: case INTUOSPL: - if (wacom->wacom_wac.features.device_type & WACOM_DEVICETYPE_PEN) - sysfs_remove_group(&wacom->hdev->dev.kobj, - &intuos5_led_attr_group); + sysfs_remove_group(&wacom->hdev->dev.kobj, + &intuos5_led_attr_group); break; } } @@ -1297,6 +1299,9 @@ static void wacom_wireless_work(struct work_struct *work) wacom_wac1->features = *((struct wacom_features *)id->driver_data); wacom_wac1->features.device_type |= WACOM_DEVICETYPE_PEN; + if (wacom_wac1->features.type != INTUOSHT && + wacom_wac1->features.type != BAMBOO_PT) + wacom_wac1->features.device_type |= WACOM_DEVICETYPE_PAD; snprintf(wacom_wac1->name, WACOM_NAME_MAX, "%s (WL) Pen", wacom_wac1->features.name); snprintf(wacom_wac1->pad_name, WACOM_NAME_MAX, "%s (WL) Pad", @@ -1315,16 +1320,16 @@ static void wacom_wireless_work(struct work_struct *work) wacom_wac2->features = *((struct wacom_features *)id->driver_data); wacom_wac2->features.pktlen = WACOM_PKGLEN_BBTOUCH3; - wacom_wac2->features.device_type |= WACOM_DEVICETYPE_TOUCH; wacom_wac2->features.x_max = wacom_wac2->features.y_max = 4096; - if (wacom_wac2->features.touch_max) - snprintf(wacom_wac2->name, WACOM_NAME_MAX, - "%s (WL) Finger",wacom_wac2->features.name); - else - snprintf(wacom_wac2->name, WACOM_NAME_MAX, - "%s (WL) Pad",wacom_wac2->features.name); + snprintf(wacom_wac2->name, WACOM_NAME_MAX, + "%s (WL) Finger",wacom_wac2->features.name); snprintf(wacom_wac2->pad_name, WACOM_NAME_MAX, - "%s (WL) Pad", wacom_wac2->features.name); + "%s (WL) Pad",wacom_wac2->features.name); + if (wacom_wac1->features.touch_max) + wacom_wac2->features.device_type |= WACOM_DEVICETYPE_TOUCH; + if (wacom_wac1->features.type == INTUOSHT || + wacom_wac1->features.type == BAMBOO_PT) + wacom_wac2->features.device_type |= WACOM_DEVICETYPE_PAD; wacom_wac2->pid = wacom_wac->pid; error = wacom_allocate_inputs(wacom2) || wacom_register_inputs(wacom2); @@ -1456,12 +1461,12 @@ static void wacom_update_name(struct wacom *wacom) "%s Pen", name); } else if (features->device_type & WACOM_DEVICETYPE_TOUCH) { - if (features->touch_max) - snprintf(wacom_wac->name, sizeof(wacom_wac->name), - "%s Finger", name); - else - snprintf(wacom_wac->name, sizeof(wacom_wac->name), - "%s Pad", name); + snprintf(wacom_wac->name, sizeof(wacom_wac->name), + "%s Finger", name); + } + else if (features->device_type & WACOM_DEVICETYPE_PAD) { + snprintf(wacom_wac->name, sizeof(wacom_wac->name), + "%s Pad", name); } } @@ -1604,8 +1609,8 @@ static int wacom_probe(struct hid_device *hdev, if (features->quirks & WACOM_QUIRK_MONITOR) error = hid_hw_open(hdev); - if (wacom_wac->features.type == INTUOSHT && wacom_wac->features.touch_max) { - if (wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH) + if (wacom_wac->features.type == INTUOSHT && + wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH) { wacom_wac->shared->touch_input = wacom_wac->input; } diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 5e7710d..564a06d 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2167,6 +2167,15 @@ void wacom_setup_device_quirks(struct wacom *wacom) { struct wacom_features *features = &wacom->wacom_wac.features; + /* The pen and pad share the same interface on most devices */ + if (features->type == GRAPHIRE_BT || features->type == WACOM_G4 || + features->type == DTUS || features->type == WACOM_MO || + (features->type >= INTUOS3S && features->type <= WACOM_13HD && + features->type != INTUOSHT)) { + if (features->device_type & WACOM_DEVICETYPE_PEN) + features->device_type |= WACOM_DEVICETYPE_PAD; + } + /* touch device found but size is not defined. use default */ if (features->device_type & WACOM_DEVICETYPE_TOUCH && !features->x_max) { features->x_max = 1023; @@ -2182,7 +2191,10 @@ void wacom_setup_device_quirks(struct wacom *wacom) if ((features->type >= INTUOS5S && features->type <= INTUOSHT) || (features->type == BAMBOO_PT)) { if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) { - features->device_type |= WACOM_DEVICETYPE_TOUCH; + if (features->touch_max) + features->device_type |= WACOM_DEVICETYPE_TOUCH; + if (features->type == BAMBOO_PT || features->type == INTUOSHT) + features->device_type |= WACOM_DEVICETYPE_PAD; features->x_max = 4096; features->y_max = 4096; @@ -2241,7 +2253,7 @@ static void wacom_abs_set_axis(struct input_dev *input_dev, /* penabled devices have fixed resolution for each model */ input_abs_set_res(input_dev, ABS_X, features->x_resolution); input_abs_set_res(input_dev, ABS_Y, features->y_resolution); - } else { + } else if (features->device_type & WACOM_DEVICETYPE_TOUCH) { if (features->touch_max == 1) { input_set_abs_params(input_dev, ABS_X, 0, features->x_max, features->x_fuzz, 0); @@ -2423,8 +2435,7 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, break; case INTUOSHT: - if (features->touch_max && - features->device_type & WACOM_DEVICETYPE_TOUCH) { + if (features->device_type & WACOM_DEVICETYPE_TOUCH) { input_dev->evbit[0] |= BIT_MASK(EV_SW); __set_bit(SW_MUTE_DEVICE, input_dev->swbit); } @@ -2434,27 +2445,26 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, __clear_bit(ABS_MISC, input_dev->absbit); if (features->device_type & WACOM_DEVICETYPE_TOUCH) { - - if (features->touch_max) { - if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) { - input_set_abs_params(input_dev, - ABS_MT_TOUCH_MAJOR, - 0, features->x_max, 0, 0); - input_set_abs_params(input_dev, - ABS_MT_TOUCH_MINOR, - 0, features->y_max, 0, 0); - } - input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_POINTER); - } else { - /* buttons/keys only interface */ - __clear_bit(ABS_X, input_dev->absbit); - __clear_bit(ABS_Y, input_dev->absbit); - __clear_bit(BTN_TOUCH, input_dev->keybit); - - /* PAD is setup by wacom_setup_pad_input_capabilities later */ - return 1; + if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) { + input_set_abs_params(input_dev, + ABS_MT_TOUCH_MAJOR, + 0, features->x_max, 0, 0); + input_set_abs_params(input_dev, + ABS_MT_TOUCH_MINOR, + 0, features->y_max, 0, 0); } - } else if (features->device_type & WACOM_DEVICETYPE_PEN) { + input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_POINTER); + } + if (features->device_type & WACOM_DEVICETYPE_PAD) { + /* buttons/keys only interface */ + __clear_bit(ABS_X, input_dev->absbit); + __clear_bit(ABS_Y, input_dev->absbit); + __clear_bit(BTN_TOUCH, input_dev->keybit); + + /* PAD is setup by wacom_setup_pad_input_capabilities later */ + return 1; + } + if (features->device_type & WACOM_DEVICETYPE_PEN) { __set_bit(INPUT_PROP_POINTER, input_dev->propbit); __set_bit(BTN_TOOL_RUBBER, input_dev->keybit); __set_bit(BTN_TOOL_PEN, input_dev->keybit); @@ -2482,6 +2492,9 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, struct wacom_features *features = &wacom_wac->features; int i; + if (!(features->device_type & WACOM_DEVICETYPE_PAD)) + return -ENODEV; + input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); /* kept for making legacy xf86-input-wacom working with the wheels */ @@ -2618,10 +2631,6 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, case INTUOS5S: case INTUOSPS: - /* touch interface does not have the pad device */ - if (!(features->device_type & WACOM_DEVICETYPE_PEN)) - return -ENODEV; - for (i = 0; i < 7; i++) __set_bit(BTN_0 + i, input_dev->keybit); @@ -2663,12 +2672,6 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, case INTUOSHT: case BAMBOO_PT: - /* pad device is on the touch interface */ - if (!(features->device_type & WACOM_DEVICETYPE_TOUCH) || - /* Bamboo Pen only tablet does not have pad */ - ((features->type == BAMBOO_PT) && !features->touch_max)) - return -ENODEV; - __clear_bit(ABS_MISC, input_dev->absbit); __set_bit(BTN_LEFT, input_dev->keybit); diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index da2b309..c873c9f 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -76,6 +76,7 @@ #define WACOM_DEVICETYPE_NONE 0x0000 #define WACOM_DEVICETYPE_PEN 0x0001 #define WACOM_DEVICETYPE_TOUCH 0x0002 +#define WACOM_DEVICETYPE_PAD 0x0004 #define WACOM_VENDORDEFINED_PEN 0xff0d0001 -- cgit v0.10.2 From 2636a3f2d1421e3e629dfc96489c23727bab17d7 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Mon, 15 Jun 2015 18:01:44 -0700 Subject: HID: wacom: Split apart 'wacom_setup_pentouch_input_capabilites' This splits the 'wacom_setup_pentouch_input_capabilites' function into pieces dedicated to doing setup for just the pen interface and just the touch interface. This makes it easier to focus on the relevant piece when making changes. This patch introduces no functional changes. Signed-off-by: Jason Gerecke Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom.h b/drivers/hid/wacom.h index c76e21f..a533787 100644 --- a/drivers/hid/wacom.h +++ b/drivers/hid/wacom.h @@ -135,7 +135,9 @@ extern const struct hid_device_id wacom_ids[]; void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len); void wacom_setup_device_quirks(struct wacom *wacom); -int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, +int wacom_setup_pen_input_capabilities(struct input_dev *input_dev, + struct wacom_wac *wacom_wac); +int wacom_setup_touch_input_capabilities(struct input_dev *input_dev, struct wacom_wac *wacom_wac); int wacom_setup_pad_input_capabilities(struct input_dev *input_dev, struct wacom_wac *wacom_wac); diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index aaa9c84..ca15c7f 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -1199,7 +1199,8 @@ static int wacom_register_inputs(struct wacom *wacom) { struct input_dev *input_dev, *pad_input_dev; struct wacom_wac *wacom_wac = &(wacom->wacom_wac); - int error; + struct wacom_features *features = &wacom_wac->features; + int error = 0; input_dev = wacom_wac->input; pad_input_dev = wacom_wac->pad_input; @@ -1207,7 +1208,10 @@ static int wacom_register_inputs(struct wacom *wacom) if (!input_dev || !pad_input_dev) return -EINVAL; - error = wacom_setup_pentouch_input_capabilities(input_dev, wacom_wac); + if (features->device_type & WACOM_DEVICETYPE_PEN) + error = wacom_setup_pen_input_capabilities(input_dev, wacom_wac); + if (!error && features->device_type & WACOM_DEVICETYPE_TOUCH) + error = wacom_setup_touch_input_capabilities(input_dev, wacom_wac); if (!error) { error = input_register_device(input_dev); if (error) diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 564a06d..b80a67a 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2237,54 +2237,16 @@ void wacom_setup_device_quirks(struct wacom *wacom) } } -static void wacom_abs_set_axis(struct input_dev *input_dev, - struct wacom_wac *wacom_wac) -{ - struct wacom_features *features = &wacom_wac->features; - - if (features->device_type & WACOM_DEVICETYPE_PEN) { - input_set_abs_params(input_dev, ABS_X, features->x_min, - features->x_max, features->x_fuzz, 0); - input_set_abs_params(input_dev, ABS_Y, features->y_min, - features->y_max, features->y_fuzz, 0); - input_set_abs_params(input_dev, ABS_PRESSURE, 0, - features->pressure_max, features->pressure_fuzz, 0); - - /* penabled devices have fixed resolution for each model */ - input_abs_set_res(input_dev, ABS_X, features->x_resolution); - input_abs_set_res(input_dev, ABS_Y, features->y_resolution); - } else if (features->device_type & WACOM_DEVICETYPE_TOUCH) { - if (features->touch_max == 1) { - input_set_abs_params(input_dev, ABS_X, 0, - features->x_max, features->x_fuzz, 0); - input_set_abs_params(input_dev, ABS_Y, 0, - features->y_max, features->y_fuzz, 0); - input_abs_set_res(input_dev, ABS_X, - features->x_resolution); - input_abs_set_res(input_dev, ABS_Y, - features->y_resolution); - } - - if (features->touch_max > 1) { - input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, - features->x_max, features->x_fuzz, 0); - input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, - features->y_max, features->y_fuzz, 0); - input_abs_set_res(input_dev, ABS_MT_POSITION_X, - features->x_resolution); - input_abs_set_res(input_dev, ABS_MT_POSITION_Y, - features->y_resolution); - } - } -} - -int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, +int wacom_setup_pen_input_capabilities(struct input_dev *input_dev, struct wacom_wac *wacom_wac) { struct wacom_features *features = &wacom_wac->features; input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + if (!(features->device_type & WACOM_DEVICETYPE_PEN)) + return -ENODEV; + if (features->type == HID_GENERIC) /* setup has already been done */ return 0; @@ -2292,7 +2254,17 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, __set_bit(BTN_TOUCH, input_dev->keybit); __set_bit(ABS_MISC, input_dev->absbit); - wacom_abs_set_axis(input_dev, wacom_wac); + input_set_abs_params(input_dev, ABS_X, features->x_min, + features->x_max, features->x_fuzz, 0); + input_set_abs_params(input_dev, ABS_Y, features->y_min, + features->y_max, features->y_fuzz, 0); + input_set_abs_params(input_dev, ABS_PRESSURE, 0, + features->pressure_max, features->pressure_fuzz, 0); + + /* penabled devices have fixed resolution for each model */ + input_abs_set_res(input_dev, ABS_X, features->x_resolution); + input_abs_set_res(input_dev, ABS_Y, features->y_resolution); + switch (features->type) { case GRAPHIRE_BT: @@ -2361,53 +2333,25 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, case INTUOSPS: __set_bit(INPUT_PROP_POINTER, input_dev->propbit); - if (features->device_type & WACOM_DEVICETYPE_PEN) { - input_set_abs_params(input_dev, ABS_DISTANCE, 0, - features->distance_max, - 0, 0); - - input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); - input_abs_set_res(input_dev, ABS_Z, 287); + input_set_abs_params(input_dev, ABS_DISTANCE, 0, + features->distance_max, + 0, 0); - wacom_setup_intuos(wacom_wac); - } else if (features->device_type & WACOM_DEVICETYPE_TOUCH) { - __clear_bit(ABS_MISC, input_dev->absbit); + input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); + input_abs_set_res(input_dev, ABS_Z, 287); - input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, - 0, features->x_max, 0, 0); - input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, - 0, features->y_max, 0, 0); - input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_POINTER); - } + wacom_setup_intuos(wacom_wac); break; case WACOM_24HDT: - if (features->device_type & WACOM_DEVICETYPE_TOUCH) { - input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, features->x_max, 0, 0); - input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, features->x_max, 0, 0); - input_set_abs_params(input_dev, ABS_MT_WIDTH_MINOR, 0, features->y_max, 0, 0); - input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0); - } - /* fall through */ - case WACOM_27QHDT: case MTSCREEN: case MTTPC: case MTTPC_B: case TABLETPC2FG: - if (features->device_type & WACOM_DEVICETYPE_TOUCH && features->touch_max > 1) - input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_DIRECT); - /* fall through */ - case TABLETPC: case TABLETPCE: __clear_bit(ABS_MISC, input_dev->absbit); - - __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); - - if (!(features->device_type & WACOM_DEVICETYPE_PEN)) - break; /* no need to process stylus stuff */ - /* fall through */ case DTUS: @@ -2435,48 +2379,114 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev, break; case INTUOSHT: - if (features->device_type & WACOM_DEVICETYPE_TOUCH) { - input_dev->evbit[0] |= BIT_MASK(EV_SW); - __set_bit(SW_MUTE_DEVICE, input_dev->swbit); - } - /* fall through */ - case BAMBOO_PT: __clear_bit(ABS_MISC, input_dev->absbit); - if (features->device_type & WACOM_DEVICETYPE_TOUCH) { - if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) { - input_set_abs_params(input_dev, - ABS_MT_TOUCH_MAJOR, - 0, features->x_max, 0, 0); - input_set_abs_params(input_dev, - ABS_MT_TOUCH_MINOR, - 0, features->y_max, 0, 0); - } - input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_POINTER); - } - if (features->device_type & WACOM_DEVICETYPE_PAD) { - /* buttons/keys only interface */ - __clear_bit(ABS_X, input_dev->absbit); - __clear_bit(ABS_Y, input_dev->absbit); - __clear_bit(BTN_TOUCH, input_dev->keybit); + __set_bit(INPUT_PROP_POINTER, input_dev->propbit); + __set_bit(BTN_TOOL_RUBBER, input_dev->keybit); + __set_bit(BTN_TOOL_PEN, input_dev->keybit); + __set_bit(BTN_STYLUS, input_dev->keybit); + __set_bit(BTN_STYLUS2, input_dev->keybit); + input_set_abs_params(input_dev, ABS_DISTANCE, 0, + features->distance_max, + 0, 0); + break; + case BAMBOO_PAD: + __clear_bit(ABS_MISC, input_dev->absbit); + break; + } + return 0; +} - /* PAD is setup by wacom_setup_pad_input_capabilities later */ - return 1; - } - if (features->device_type & WACOM_DEVICETYPE_PEN) { - __set_bit(INPUT_PROP_POINTER, input_dev->propbit); - __set_bit(BTN_TOOL_RUBBER, input_dev->keybit); - __set_bit(BTN_TOOL_PEN, input_dev->keybit); - __set_bit(BTN_STYLUS, input_dev->keybit); - __set_bit(BTN_STYLUS2, input_dev->keybit); - input_set_abs_params(input_dev, ABS_DISTANCE, 0, - features->distance_max, - 0, 0); +int wacom_setup_touch_input_capabilities(struct input_dev *input_dev, + struct wacom_wac *wacom_wac) +{ + struct wacom_features *features = &wacom_wac->features; + + input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); + + if (!(features->device_type & WACOM_DEVICETYPE_TOUCH)) + return -ENODEV; + + if (features->type == HID_GENERIC) + /* setup has already been done */ + return 0; + + __set_bit(BTN_TOUCH, input_dev->keybit); + + if (features->touch_max == 1) { + input_set_abs_params(input_dev, ABS_X, 0, + features->x_max, features->x_fuzz, 0); + input_set_abs_params(input_dev, ABS_Y, 0, + features->y_max, features->y_fuzz, 0); + input_abs_set_res(input_dev, ABS_X, + features->x_resolution); + input_abs_set_res(input_dev, ABS_Y, + features->y_resolution); + } + else if (features->touch_max > 1) { + input_set_abs_params(input_dev, ABS_MT_POSITION_X, 0, + features->x_max, features->x_fuzz, 0); + input_set_abs_params(input_dev, ABS_MT_POSITION_Y, 0, + features->y_max, features->y_fuzz, 0); + input_abs_set_res(input_dev, ABS_MT_POSITION_X, + features->x_resolution); + input_abs_set_res(input_dev, ABS_MT_POSITION_Y, + features->y_resolution); + } + + switch (features->type) { + case INTUOS5: + case INTUOS5L: + case INTUOSPM: + case INTUOSPL: + case INTUOS5S: + case INTUOSPS: + __set_bit(INPUT_PROP_POINTER, input_dev->propbit); + + input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, features->x_max, 0, 0); + input_set_abs_params(input_dev, ABS_MT_TOUCH_MINOR, 0, features->y_max, 0, 0); + input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_POINTER); + break; + + case WACOM_24HDT: + input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, features->x_max, 0, 0); + input_set_abs_params(input_dev, ABS_MT_WIDTH_MAJOR, 0, features->x_max, 0, 0); + input_set_abs_params(input_dev, ABS_MT_WIDTH_MINOR, 0, features->y_max, 0, 0); + input_set_abs_params(input_dev, ABS_MT_ORIENTATION, 0, 1, 0, 0); + /* fall through */ + + case WACOM_27QHDT: + case MTSCREEN: + case MTTPC: + case MTTPC_B: + case TABLETPC2FG: + input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_DIRECT); + /*fall through */ + + case TABLETPC: + case TABLETPCE: + __set_bit(INPUT_PROP_DIRECT, input_dev->propbit); + break; + + case INTUOSHT: + input_dev->evbit[0] |= BIT_MASK(EV_SW); + __set_bit(SW_MUTE_DEVICE, input_dev->swbit); + /* fall through */ + + case BAMBOO_PT: + if (features->pktlen == WACOM_PKGLEN_BBTOUCH3) { + input_set_abs_params(input_dev, + ABS_MT_TOUCH_MAJOR, + 0, features->x_max, 0, 0); + input_set_abs_params(input_dev, + ABS_MT_TOUCH_MINOR, + 0, features->y_max, 0, 0); } + input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_POINTER); break; + case BAMBOO_PAD: - __clear_bit(ABS_MISC, input_dev->absbit); input_mt_init_slots(input_dev, features->touch_max, INPUT_MT_POINTER); __set_bit(BTN_LEFT, input_dev->keybit); -- cgit v0.10.2 From 2a6cdbdd4cc0da0b0190b9a43648dff7b44adc0a Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Mon, 15 Jun 2015 18:01:45 -0700 Subject: HID: wacom: Introduce new 'touch_input' device Instead of having a single 'input_dev' device that will take either pen or touch data depending on the type of the device, create seperate devices devices for each. By splitting things like this, we can support devices (e.g. the I2C "AES" sensors in some newer tablet PCs) that send both pen and touch reports from a single endpoint. Signed-off-by: Jason Gerecke Signed-off-by: Jiri Kosina diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index ca15c7f..4c0ffca 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -253,7 +253,7 @@ static void wacom_post_parse_hid(struct hid_device *hdev, if (features->type == HID_GENERIC) { /* Any last-minute generic device setup */ if (features->touch_max > 1) { - input_mt_init_slots(wacom_wac->input, wacom_wac->features.touch_max, + input_mt_init_slots(wacom_wac->touch_input, wacom_wac->features.touch_max, INPUT_MT_DIRECT); } } @@ -1130,7 +1130,7 @@ static struct input_dev *wacom_allocate_input(struct wacom *wacom) if (!input_dev) return NULL; - input_dev->name = wacom_wac->name; + input_dev->name = wacom_wac->pen_name; input_dev->phys = hdev->phys; input_dev->dev.parent = &hdev->dev; input_dev->open = wacom_open; @@ -1149,27 +1149,33 @@ static void wacom_free_inputs(struct wacom *wacom) { struct wacom_wac *wacom_wac = &(wacom->wacom_wac); - if (wacom_wac->input) - input_free_device(wacom_wac->input); + if (wacom_wac->pen_input) + input_free_device(wacom_wac->pen_input); + if (wacom_wac->touch_input) + input_free_device(wacom_wac->touch_input); if (wacom_wac->pad_input) input_free_device(wacom_wac->pad_input); - wacom_wac->input = NULL; + wacom_wac->pen_input = NULL; + wacom_wac->touch_input = NULL; wacom_wac->pad_input = NULL; } static int wacom_allocate_inputs(struct wacom *wacom) { - struct input_dev *input_dev, *pad_input_dev; + struct input_dev *pen_input_dev, *touch_input_dev, *pad_input_dev; struct wacom_wac *wacom_wac = &(wacom->wacom_wac); - input_dev = wacom_allocate_input(wacom); + pen_input_dev = wacom_allocate_input(wacom); + touch_input_dev = wacom_allocate_input(wacom); pad_input_dev = wacom_allocate_input(wacom); - if (!input_dev || !pad_input_dev) { + if (!pen_input_dev || !touch_input_dev || !pad_input_dev) { wacom_free_inputs(wacom); return -ENOMEM; } - wacom_wac->input = input_dev; + wacom_wac->pen_input = pen_input_dev; + wacom_wac->touch_input = touch_input_dev; + wacom_wac->touch_input->name = wacom_wac->touch_name; wacom_wac->pad_input = pad_input_dev; wacom_wac->pad_input->name = wacom_wac->pad_name; @@ -1178,11 +1184,17 @@ static int wacom_allocate_inputs(struct wacom *wacom) static void wacom_clean_inputs(struct wacom *wacom) { - if (wacom->wacom_wac.input) { - if (wacom->wacom_wac.input_registered) - input_unregister_device(wacom->wacom_wac.input); + if (wacom->wacom_wac.pen_input) { + if (wacom->wacom_wac.pen_registered) + input_unregister_device(wacom->wacom_wac.pen_input); else - input_free_device(wacom->wacom_wac.input); + input_free_device(wacom->wacom_wac.pen_input); + } + if (wacom->wacom_wac.touch_input) { + if (wacom->wacom_wac.touch_registered) + input_unregister_device(wacom->wacom_wac.touch_input); + else + input_free_device(wacom->wacom_wac.touch_input); } if (wacom->wacom_wac.pad_input) { if (wacom->wacom_wac.pad_registered) @@ -1190,33 +1202,49 @@ static void wacom_clean_inputs(struct wacom *wacom) else input_free_device(wacom->wacom_wac.pad_input); } - wacom->wacom_wac.input = NULL; + wacom->wacom_wac.pen_input = NULL; + wacom->wacom_wac.touch_input = NULL; wacom->wacom_wac.pad_input = NULL; wacom_destroy_leds(wacom); } static int wacom_register_inputs(struct wacom *wacom) { - struct input_dev *input_dev, *pad_input_dev; + struct input_dev *pen_input_dev, *touch_input_dev, *pad_input_dev; struct wacom_wac *wacom_wac = &(wacom->wacom_wac); - struct wacom_features *features = &wacom_wac->features; int error = 0; - input_dev = wacom_wac->input; + pen_input_dev = wacom_wac->pen_input; + touch_input_dev = wacom_wac->touch_input; pad_input_dev = wacom_wac->pad_input; - if (!input_dev || !pad_input_dev) + if (!pen_input_dev || !touch_input_dev || !pad_input_dev) return -EINVAL; - if (features->device_type & WACOM_DEVICETYPE_PEN) - error = wacom_setup_pen_input_capabilities(input_dev, wacom_wac); - if (!error && features->device_type & WACOM_DEVICETYPE_TOUCH) - error = wacom_setup_touch_input_capabilities(input_dev, wacom_wac); - if (!error) { - error = input_register_device(input_dev); + error = wacom_setup_pen_input_capabilities(pen_input_dev, wacom_wac); + if (error) { + /* no pen in use on this interface */ + input_free_device(pen_input_dev); + wacom_wac->pen_input = NULL; + pen_input_dev = NULL; + } else { + error = input_register_device(pen_input_dev); + if (error) + goto fail_register_pen_input; + wacom_wac->pen_registered = true; + } + + error = wacom_setup_touch_input_capabilities(touch_input_dev, wacom_wac); + if (error) { + /* no touch in use on this interface */ + input_free_device(touch_input_dev); + wacom_wac->touch_input = NULL; + touch_input_dev = NULL; + } else { + error = input_register_device(touch_input_dev); if (error) - return error; - wacom_wac->input_registered = true; + goto fail_register_touch_input; + wacom_wac->touch_registered = true; } error = wacom_setup_pad_input_capabilities(pad_input_dev, wacom_wac); @@ -1243,9 +1271,14 @@ fail_leds: pad_input_dev = NULL; wacom_wac->pad_registered = false; fail_register_pad_input: - input_unregister_device(input_dev); - wacom_wac->input = NULL; - wacom_wac->input_registered = false; + input_unregister_device(touch_input_dev); + wacom_wac->touch_input = NULL; + wacom_wac->touch_registered = false; +fail_register_touch_input: + input_unregister_device(pen_input_dev); + wacom_wac->pen_input = NULL; + wacom_wac->pen_registered = false; +fail_register_pen_input: return error; } @@ -1306,7 +1339,7 @@ static void wacom_wireless_work(struct work_struct *work) if (wacom_wac1->features.type != INTUOSHT && wacom_wac1->features.type != BAMBOO_PT) wacom_wac1->features.device_type |= WACOM_DEVICETYPE_PAD; - snprintf(wacom_wac1->name, WACOM_NAME_MAX, "%s (WL) Pen", + snprintf(wacom_wac1->pen_name, WACOM_NAME_MAX, "%s (WL) Pen", wacom_wac1->features.name); snprintf(wacom_wac1->pad_name, WACOM_NAME_MAX, "%s (WL) Pad", wacom_wac1->features.name); @@ -1325,7 +1358,7 @@ static void wacom_wireless_work(struct work_struct *work) *((struct wacom_features *)id->driver_data); wacom_wac2->features.pktlen = WACOM_PKGLEN_BBTOUCH3; wacom_wac2->features.x_max = wacom_wac2->features.y_max = 4096; - snprintf(wacom_wac2->name, WACOM_NAME_MAX, + snprintf(wacom_wac2->touch_name, WACOM_NAME_MAX, "%s (WL) Finger",wacom_wac2->features.name); snprintf(wacom_wac2->pad_name, WACOM_NAME_MAX, "%s (WL) Pad",wacom_wac2->features.name); @@ -1342,7 +1375,7 @@ static void wacom_wireless_work(struct work_struct *work) if (wacom_wac1->features.type == INTUOSHT && wacom_wac1->features.touch_max) - wacom_wac->shared->touch_input = wacom_wac2->input; + wacom_wac->shared->touch_input = wacom_wac2->touch_input; } error = wacom_initialize_battery(wacom); @@ -1457,21 +1490,12 @@ static void wacom_update_name(struct wacom *wacom) } /* Append the device type to the name */ + snprintf(wacom_wac->pen_name, sizeof(wacom_wac->pen_name), + "%s Pen", name); + snprintf(wacom_wac->touch_name, sizeof(wacom_wac->touch_name), + "%s Finger", name); snprintf(wacom_wac->pad_name, sizeof(wacom_wac->pad_name), "%s Pad", name); - - if (features->device_type & WACOM_DEVICETYPE_PEN) { - snprintf(wacom_wac->name, sizeof(wacom_wac->name), - "%s Pen", name); - } - else if (features->device_type & WACOM_DEVICETYPE_TOUCH) { - snprintf(wacom_wac->name, sizeof(wacom_wac->name), - "%s Finger", name); - } - else if (features->device_type & WACOM_DEVICETYPE_PAD) { - snprintf(wacom_wac->name, sizeof(wacom_wac->name), - "%s Pad", name); - } } static int wacom_probe(struct hid_device *hdev, @@ -1615,7 +1639,7 @@ static int wacom_probe(struct hid_device *hdev, if (wacom_wac->features.type == INTUOSHT && wacom_wac->features.device_type & WACOM_DEVICETYPE_TOUCH) { - wacom_wac->shared->touch_input = wacom_wac->input; + wacom_wac->shared->touch_input = wacom_wac->touch_input; } return 0; diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index b80a67a..d811e87 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -69,7 +69,7 @@ static void wacom_notify_battery(struct wacom_wac *wacom_wac, static int wacom_penpartner_irq(struct wacom_wac *wacom) { unsigned char *data = wacom->data; - struct input_dev *input = wacom->input; + struct input_dev *input = wacom->pen_input; switch (data[0]) { case 1: @@ -114,7 +114,7 @@ static int wacom_pl_irq(struct wacom_wac *wacom) { struct wacom_features *features = &wacom->features; unsigned char *data = wacom->data; - struct input_dev *input = wacom->input; + struct input_dev *input = wacom->pen_input; int prox, pressure; if (data[0] != WACOM_REPORT_PENABLED) { @@ -186,7 +186,7 @@ static int wacom_pl_irq(struct wacom_wac *wacom) static int wacom_ptu_irq(struct wacom_wac *wacom) { unsigned char *data = wacom->data; - struct input_dev *input = wacom->input; + struct input_dev *input = wacom->pen_input; if (data[0] != WACOM_REPORT_PENABLED) { dev_dbg(input->dev.parent, @@ -215,7 +215,7 @@ static int wacom_ptu_irq(struct wacom_wac *wacom) static int wacom_dtu_irq(struct wacom_wac *wacom) { unsigned char *data = wacom->data; - struct input_dev *input = wacom->input; + struct input_dev *input = wacom->pen_input; int prox = data[1] & 0x20; dev_dbg(input->dev.parent, @@ -245,7 +245,7 @@ static int wacom_dtu_irq(struct wacom_wac *wacom) static int wacom_dtus_irq(struct wacom_wac *wacom) { char *data = wacom->data; - struct input_dev *input = wacom->input; + struct input_dev *input = wacom->pen_input; unsigned short prox, pressure = 0; if (data[0] != WACOM_REPORT_DTUS && data[0] != WACOM_REPORT_DTUSPAD) { @@ -297,7 +297,7 @@ static int wacom_graphire_irq(struct wacom_wac *wacom) { struct wacom_features *features = &wacom->features; unsigned char *data = wacom->data; - struct input_dev *input = wacom->input; + struct input_dev *input = wacom->pen_input; struct input_dev *pad_input = wacom->pad_input; int battery_capacity, ps_connected; int prox; @@ -464,7 +464,7 @@ static int wacom_intuos_inout(struct wacom_wac *wacom) { struct wacom_features *features = &wacom->features; unsigned char *data = wacom->data; - struct input_dev *input = wacom->input; + struct input_dev *input = wacom->pen_input; int idx = 0; /* tool number */ @@ -649,7 +649,7 @@ static void wacom_intuos_general(struct wacom_wac *wacom) { struct wacom_features *features = &wacom->features; unsigned char *data = wacom->data; - struct input_dev *input = wacom->input; + struct input_dev *input = wacom->pen_input; unsigned int t; /* general pen packet */ @@ -681,7 +681,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) { struct wacom_features *features = &wacom->features; unsigned char *data = wacom->data; - struct input_dev *input = wacom->input; + struct input_dev *input = wacom->pen_input; unsigned int t; int idx = 0, result; @@ -1025,7 +1025,7 @@ static void wacom_intuos_bt_process_data(struct wacom_wac *wacom, memcpy(wacom->data, data, 10); wacom_intuos_irq(wacom); - input_sync(wacom->input); + input_sync(wacom->pen_input); if (wacom->pad_input) input_sync(wacom->pad_input); } @@ -1057,7 +1057,7 @@ static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len) ps_connected); break; default: - dev_dbg(wacom->input->dev.parent, + dev_dbg(wacom->pen_input->dev.parent, "Unknown report: %d,%d size:%zu\n", data[0], data[1], len); return 0; @@ -1067,7 +1067,7 @@ static int wacom_intuos_bt_irq(struct wacom_wac *wacom, size_t len) static int wacom_wac_finger_count_touches(struct wacom_wac *wacom) { - struct input_dev *input = wacom->input; + struct input_dev *input = wacom->touch_input; unsigned touch_max = wacom->features.touch_max; int count = 0; int i; @@ -1088,7 +1088,7 @@ static int wacom_wac_finger_count_touches(struct wacom_wac *wacom) static int wacom_24hdt_irq(struct wacom_wac *wacom) { - struct input_dev *input = wacom->input; + struct input_dev *input = wacom->touch_input; unsigned char *data = wacom->data; int i; int current_num_contacts = data[61]; @@ -1156,7 +1156,7 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom) static int wacom_mt_touch(struct wacom_wac *wacom) { - struct input_dev *input = wacom->input; + struct input_dev *input = wacom->touch_input; unsigned char *data = wacom->data; int i; int current_num_contacts = data[2]; @@ -1207,7 +1207,7 @@ static int wacom_mt_touch(struct wacom_wac *wacom) static int wacom_tpc_mt_touch(struct wacom_wac *wacom) { - struct input_dev *input = wacom->input; + struct input_dev *input = wacom->touch_input; unsigned char *data = wacom->data; int i; @@ -1236,7 +1236,7 @@ static int wacom_tpc_mt_touch(struct wacom_wac *wacom) static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len) { unsigned char *data = wacom->data; - struct input_dev *input = wacom->input; + struct input_dev *input = wacom->touch_input; bool prox = !wacom->shared->stylus_in_proximity; int x = 0, y = 0; @@ -1272,7 +1272,7 @@ static int wacom_tpc_single_touch(struct wacom_wac *wacom, size_t len) static int wacom_tpc_pen(struct wacom_wac *wacom) { unsigned char *data = wacom->data; - struct input_dev *input = wacom->input; + struct input_dev *input = wacom->pen_input; bool prox = data[1] & 0x20; if (!wacom->shared->stylus_in_proximity) /* first in prox */ @@ -1301,8 +1301,12 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) { unsigned char *data = wacom->data; - dev_dbg(wacom->input->dev.parent, - "%s: received report #%d\n", __func__, data[0]); + if (wacom->pen_input) + dev_dbg(wacom->pen_input->dev.parent, + "%s: received report #%d\n", __func__, data[0]); + else if (wacom->touch_input) + dev_dbg(wacom->touch_input->dev.parent, + "%s: received report #%d\n", __func__, data[0]); switch (len) { case WACOM_PKGLEN_TPC1FG: @@ -1334,11 +1338,9 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) return 0; } -static void wacom_map_usage(struct wacom *wacom, struct hid_usage *usage, +static void wacom_map_usage(struct input_dev *input, struct hid_usage *usage, struct hid_field *field, __u8 type, __u16 code, int fuzz) { - struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct input_dev *input = wacom_wac->input; int fmin = field->logical_minimum; int fmax = field->logical_maximum; @@ -1366,36 +1368,38 @@ static void wacom_wac_pen_usage_mapping(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage) { struct wacom *wacom = hid_get_drvdata(hdev); + struct wacom_wac *wacom_wac = &wacom->wacom_wac; + struct input_dev *input = wacom_wac->pen_input; switch (usage->hid) { case HID_GD_X: - wacom_map_usage(wacom, usage, field, EV_ABS, ABS_X, 4); + wacom_map_usage(input, usage, field, EV_ABS, ABS_X, 4); break; case HID_GD_Y: - wacom_map_usage(wacom, usage, field, EV_ABS, ABS_Y, 4); + wacom_map_usage(input, usage, field, EV_ABS, ABS_Y, 4); break; case HID_DG_TIPPRESSURE: - wacom_map_usage(wacom, usage, field, EV_ABS, ABS_PRESSURE, 0); + wacom_map_usage(input, usage, field, EV_ABS, ABS_PRESSURE, 0); break; case HID_DG_INRANGE: - wacom_map_usage(wacom, usage, field, EV_KEY, BTN_TOOL_PEN, 0); + wacom_map_usage(input, usage, field, EV_KEY, BTN_TOOL_PEN, 0); break; case HID_DG_INVERT: - wacom_map_usage(wacom, usage, field, EV_KEY, + wacom_map_usage(input, usage, field, EV_KEY, BTN_TOOL_RUBBER, 0); break; case HID_DG_ERASER: case HID_DG_TIPSWITCH: - wacom_map_usage(wacom, usage, field, EV_KEY, BTN_TOUCH, 0); + wacom_map_usage(input, usage, field, EV_KEY, BTN_TOUCH, 0); break; case HID_DG_BARRELSWITCH: - wacom_map_usage(wacom, usage, field, EV_KEY, BTN_STYLUS, 0); + wacom_map_usage(input, usage, field, EV_KEY, BTN_STYLUS, 0); break; case HID_DG_BARRELSWITCH2: - wacom_map_usage(wacom, usage, field, EV_KEY, BTN_STYLUS2, 0); + wacom_map_usage(input, usage, field, EV_KEY, BTN_STYLUS2, 0); break; case HID_DG_TOOLSERIALNUMBER: - wacom_map_usage(wacom, usage, field, EV_MSC, MSC_SERIAL, 0); + wacom_map_usage(input, usage, field, EV_MSC, MSC_SERIAL, 0); break; } } @@ -1405,7 +1409,7 @@ static int wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field, { struct wacom *wacom = hid_get_drvdata(hdev); struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct input_dev *input = wacom_wac->input; + struct input_dev *input = wacom_wac->pen_input; /* checking which Tool / tip switch to send */ switch (usage->hid) { @@ -1435,7 +1439,7 @@ static void wacom_wac_pen_report(struct hid_device *hdev, { struct wacom *wacom = hid_get_drvdata(hdev); struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct input_dev *input = wacom_wac->input; + struct input_dev *input = wacom_wac->pen_input; bool prox = wacom_wac->hid_data.inrange_state; if (!wacom_wac->shared->stylus_in_proximity) /* first in prox */ @@ -1464,23 +1468,24 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev, struct wacom *wacom = hid_get_drvdata(hdev); struct wacom_wac *wacom_wac = &wacom->wacom_wac; struct wacom_features *features = &wacom_wac->features; + struct input_dev *input = wacom_wac->touch_input; unsigned touch_max = wacom_wac->features.touch_max; switch (usage->hid) { case HID_GD_X: features->last_slot_field = usage->hid; if (touch_max == 1) - wacom_map_usage(wacom, usage, field, EV_ABS, ABS_X, 4); + wacom_map_usage(input, usage, field, EV_ABS, ABS_X, 4); else - wacom_map_usage(wacom, usage, field, EV_ABS, + wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_POSITION_X, 4); break; case HID_GD_Y: features->last_slot_field = usage->hid; if (touch_max == 1) - wacom_map_usage(wacom, usage, field, EV_ABS, ABS_Y, 4); + wacom_map_usage(input, usage, field, EV_ABS, ABS_Y, 4); else - wacom_map_usage(wacom, usage, field, EV_ABS, + wacom_map_usage(input, usage, field, EV_ABS, ABS_MT_POSITION_Y, 4); break; case HID_DG_CONTACTID: @@ -1494,7 +1499,7 @@ static void wacom_wac_finger_usage_mapping(struct hid_device *hdev, break; case HID_DG_TIPSWITCH: features->last_slot_field = usage->hid; - wacom_map_usage(wacom, usage, field, EV_KEY, BTN_TOUCH, 0); + wacom_map_usage(input, usage, field, EV_KEY, BTN_TOUCH, 0); break; } } @@ -1550,7 +1555,7 @@ static int wacom_wac_finger_event(struct hid_device *hdev, if (usage->usage_index + 1 == field->report_count) { if (usage->hid == wacom_wac->features.last_slot_field) - wacom_wac_finger_slot(wacom_wac, wacom_wac->input); + wacom_wac_finger_slot(wacom_wac, wacom_wac->touch_input); } return 0; @@ -1561,7 +1566,7 @@ static void wacom_wac_finger_report(struct hid_device *hdev, { struct wacom *wacom = hid_get_drvdata(hdev); struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct input_dev *input = wacom_wac->input; + struct input_dev *input = wacom_wac->touch_input; unsigned touch_max = wacom_wac->features.touch_max; if (touch_max > 1) @@ -1578,10 +1583,10 @@ void wacom_wac_usage_mapping(struct hid_device *hdev, { struct wacom *wacom = hid_get_drvdata(hdev); struct wacom_wac *wacom_wac = &wacom->wacom_wac; - struct input_dev *input = wacom_wac->input; /* currently, only direct devices have proper hid report descriptors */ - __set_bit(INPUT_PROP_DIRECT, input->propbit); + __set_bit(INPUT_PROP_DIRECT, wacom_wac->pen_input->propbit); + __set_bit(INPUT_PROP_DIRECT, wacom_wac->touch_input->propbit); if (WACOM_PEN_FIELD(field)) return wacom_wac_pen_usage_mapping(hdev, field, usage); @@ -1626,7 +1631,7 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report) static int wacom_bpt_touch(struct wacom_wac *wacom) { struct wacom_features *features = &wacom->features; - struct input_dev *input = wacom->input; + struct input_dev *input = wacom->touch_input; struct input_dev *pad_input = wacom->pad_input; unsigned char *data = wacom->data; int i; @@ -1674,7 +1679,7 @@ static int wacom_bpt_touch(struct wacom_wac *wacom) static void wacom_bpt3_touch_msg(struct wacom_wac *wacom, unsigned char *data) { struct wacom_features *features = &wacom->features; - struct input_dev *input = wacom->input; + struct input_dev *input = wacom->touch_input; bool touch = data[1] & 0x80; int slot = input_mt_get_slot_by_key(input, data[0]); @@ -1732,7 +1737,6 @@ static void wacom_bpt3_button_msg(struct wacom_wac *wacom, unsigned char *data) static int wacom_bpt3_touch(struct wacom_wac *wacom) { - struct input_dev *input = wacom->input; unsigned char *data = wacom->data; int count = data[1] & 0x07; int i; @@ -1751,8 +1755,12 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom) wacom_bpt3_button_msg(wacom, data + offset); } - input_mt_sync_frame(input); - wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom); + + /* only update the touch if we actually have a touchpad */ + if (wacom->touch_registered) { + input_mt_sync_frame(wacom->touch_input); + wacom->shared->touch_down = wacom_wac_finger_count_touches(wacom); + } return 1; } @@ -1760,7 +1768,7 @@ static int wacom_bpt3_touch(struct wacom_wac *wacom) static int wacom_bpt_pen(struct wacom_wac *wacom) { struct wacom_features *features = &wacom->features; - struct input_dev *input = wacom->input; + struct input_dev *input = wacom->pen_input; unsigned char *data = wacom->data; int prox = 0, x = 0, y = 0, p = 0, d = 0, pen = 0, btn1 = 0, btn2 = 0; @@ -1869,7 +1877,7 @@ static void wacom_bamboo_pad_pen_event(struct wacom_wac *wacom, static int wacom_bamboo_pad_touch_event(struct wacom_wac *wacom, unsigned char *data) { - struct input_dev *input = wacom->input; + struct input_dev *input = wacom->touch_input; unsigned char *finger_data, prefix; unsigned id; int x, y; @@ -2113,7 +2121,10 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len) } if (sync) { - input_sync(wacom_wac->input); + if (wacom_wac->pen_input) + input_sync(wacom_wac->pen_input); + if (wacom_wac->touch_input) + input_sync(wacom_wac->touch_input); if (wacom_wac->pad_input) input_sync(wacom_wac->pad_input); } @@ -2121,7 +2132,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len) static void wacom_setup_cintiq(struct wacom_wac *wacom_wac) { - struct input_dev *input_dev = wacom_wac->input; + struct input_dev *input_dev = wacom_wac->pen_input; input_set_capability(input_dev, EV_MSC, MSC_SERIAL); @@ -2144,7 +2155,7 @@ static void wacom_setup_cintiq(struct wacom_wac *wacom_wac) static void wacom_setup_intuos(struct wacom_wac *wacom_wac) { - struct input_dev *input_dev = wacom_wac->input; + struct input_dev *input_dev = wacom_wac->pen_input; input_set_capability(input_dev, EV_REL, REL_WHEEL); diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index c873c9f..2978c30 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -196,7 +196,8 @@ struct hid_data { }; struct wacom_wac { - char name[WACOM_NAME_MAX]; + char pen_name[WACOM_NAME_MAX]; + char touch_name[WACOM_NAME_MAX]; char pad_name[WACOM_NAME_MAX]; char bat_name[WACOM_NAME_MAX]; char ac_name[WACOM_NAME_MAX]; @@ -207,9 +208,11 @@ struct wacom_wac { bool reporting_data; struct wacom_features features; struct wacom_shared *shared; - struct input_dev *input; + struct input_dev *pen_input; + struct input_dev *touch_input; struct input_dev *pad_input; - bool input_registered; + bool pen_registered; + bool touch_registered; bool pad_registered; int pid; int battery_capacity; -- cgit v0.10.2 From 6eabaaa09128169f42d97d6a3502729f8ad27c4a Mon Sep 17 00:00:00 2001 From: Simon Wood Date: Wed, 17 Jun 2015 00:08:51 -0600 Subject: HID: hid-sony: Add BT support for Navigation Controller Signed-off-by: Simon Wood Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 044e96a..a64f862 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1962,6 +1962,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_MOTION_CONTROLLER) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_MOTION_CONTROLLER) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_BDREMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) }, diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 2ce0295..3fba2dca 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -2287,6 +2287,8 @@ static const struct hid_device_id sony_devices[] = { .driver_data = SIXAXIS_CONTROLLER_USB }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER), .driver_data = SIXAXIS_CONTROLLER_USB }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER), + .driver_data = SIXAXIS_CONTROLLER_BT }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_MOTION_CONTROLLER), .driver_data = MOTION_CONTROLLER_USB }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_MOTION_CONTROLLER), -- cgit v0.10.2 From 4545ee0a70e49b7d355181540a77c0a1aa2a7fe4 Mon Sep 17 00:00:00 2001 From: Simon Wood Date: Wed, 17 Jun 2015 00:08:52 -0600 Subject: HID: hid-sony: Navigation controller only has 1 LED and no rumble Signed-off-by: Simon Wood Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 3fba2dca..af02139 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -48,15 +48,20 @@ #define DUALSHOCK4_CONTROLLER_BT BIT(6) #define MOTION_CONTROLLER_USB BIT(7) #define MOTION_CONTROLLER_BT BIT(8) +#define NAVIGATION_CONTROLLER_USB BIT(9) +#define NAVIGATION_CONTROLLER_BT BIT(10) #define SIXAXIS_CONTROLLER (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT) #define MOTION_CONTROLLER (MOTION_CONTROLLER_USB | MOTION_CONTROLLER_BT) +#define NAVIGATION_CONTROLLER (NAVIGATION_CONTROLLER_USB |\ + NAVIGATION_CONTROLLER_BT) #define DUALSHOCK4_CONTROLLER (DUALSHOCK4_CONTROLLER_USB |\ DUALSHOCK4_CONTROLLER_BT) #define SONY_LED_SUPPORT (SIXAXIS_CONTROLLER | BUZZ_CONTROLLER |\ - DUALSHOCK4_CONTROLLER | MOTION_CONTROLLER) + DUALSHOCK4_CONTROLLER | MOTION_CONTROLLER |\ + NAVIGATION_CONTROLLER) #define SONY_BATTERY_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER |\ - MOTION_CONTROLLER_BT) + MOTION_CONTROLLER_BT | NAVIGATION_CONTROLLER) #define SONY_FF_SUPPORT (SIXAXIS_CONTROLLER | DUALSHOCK4_CONTROLLER |\ MOTION_CONTROLLER) @@ -1052,6 +1057,9 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc, if (sc->quirks & MOTION_CONTROLLER) return motion_fixup(hdev, rdesc, rsize); + if (sc->quirks & NAVIGATION_CONTROLLER) + return sixaxis_fixup(hdev, rdesc, rsize); + if (sc->quirks & PS3REMOTE) return ps3remote_fixup(hdev, rdesc, rsize); @@ -1181,6 +1189,9 @@ static int sony_raw_event(struct hid_device *hdev, struct hid_report *report, sixaxis_parse_report(sc, rd, size); } else if ((sc->quirks & MOTION_CONTROLLER_BT) && rd[0] == 0x01 && size == 49) { sixaxis_parse_report(sc, rd, size); + } else if ((sc->quirks & NAVIGATION_CONTROLLER) && rd[0] == 0x01 && + size == 49) { + sixaxis_parse_report(sc, rd, size); } else if (((sc->quirks & DUALSHOCK4_CONTROLLER_USB) && rd[0] == 0x01 && size == 64) || ((sc->quirks & DUALSHOCK4_CONTROLLER_BT) && rd[0] == 0x11 && size == 78)) { @@ -1591,6 +1602,15 @@ static int sony_leds_init(struct sony_sc *sc) use_ds4_names = 1; name_len = 0; name_fmt = "%s:%s"; + } else if (sc->quirks & NAVIGATION_CONTROLLER) { + static const __u8 navigation_leds[4] = {0x01, 0x00, 0x00, 0x00}; + + memcpy(sc->led_state, navigation_leds, sizeof(navigation_leds)); + sc->led_count = 1; + memset(use_hw_blink, 1, 4); + use_ds4_names = 0; + name_len = strlen("::sony#"); + name_fmt = "%s::sony%d"; } else { sixaxis_set_leds_from_id(sc); sc->led_count = 4; @@ -1782,7 +1802,8 @@ static void motion_state_worker(struct work_struct *work) static int sony_allocate_output_report(struct sony_sc *sc) { - if (sc->quirks & SIXAXIS_CONTROLLER) + if ((sc->quirks & SIXAXIS_CONTROLLER) || + (sc->quirks & NAVIGATION_CONTROLLER)) sc->output_report_dmabuf = kmalloc(sizeof(union sixaxis_output_report_01), GFP_KERNEL); @@ -2001,6 +2022,7 @@ static int sony_check_add(struct sony_sc *sc) if ((sc->quirks & DUALSHOCK4_CONTROLLER_BT) || (sc->quirks & MOTION_CONTROLLER_BT) || + (sc->quirks & NAVIGATION_CONTROLLER_BT) || (sc->quirks & SIXAXIS_CONTROLLER_BT)) { /* * sony_get_bt_devaddr() attempts to parse the Bluetooth MAC @@ -2033,7 +2055,8 @@ static int sony_check_add(struct sony_sc *sc) } memcpy(sc->mac_address, &buf[1], sizeof(sc->mac_address)); - } else if (sc->quirks & SIXAXIS_CONTROLLER_USB) { + } else if ((sc->quirks & SIXAXIS_CONTROLLER_USB) || + (sc->quirks & NAVIGATION_CONTROLLER_USB)) { buf = kmalloc(SIXAXIS_REPORT_0xF2_SIZE, GFP_KERNEL); if (!buf) return -ENOMEM; @@ -2167,7 +2190,8 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) goto err_stop; } - if (sc->quirks & SIXAXIS_CONTROLLER_USB) { + if ((sc->quirks & SIXAXIS_CONTROLLER_USB) || + (sc->quirks & NAVIGATION_CONTROLLER_USB)) { /* * The Sony Sixaxis does not handle HID Output Reports on the * Interrupt EP like it could, so we need to force HID Output @@ -2182,7 +2206,8 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) hdev->quirks |= HID_QUIRK_SKIP_OUTPUT_REPORT_ID; ret = sixaxis_set_operational_usb(hdev); sony_init_work(sc, sixaxis_state_worker); - } else if (sc->quirks & SIXAXIS_CONTROLLER_BT) { + } else if ((sc->quirks & SIXAXIS_CONTROLLER_BT) || + (sc->quirks & NAVIGATION_CONTROLLER_BT)) { /* * The Sixaxis wants output reports sent on the ctrl endpoint * when connected via Bluetooth. @@ -2286,9 +2311,9 @@ static const struct hid_device_id sony_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER), .driver_data = SIXAXIS_CONTROLLER_USB }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER), - .driver_data = SIXAXIS_CONTROLLER_USB }, + .driver_data = NAVIGATION_CONTROLLER_USB }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_NAVIGATION_CONTROLLER), - .driver_data = SIXAXIS_CONTROLLER_BT }, + .driver_data = NAVIGATION_CONTROLLER_BT }, { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_MOTION_CONTROLLER), .driver_data = MOTION_CONTROLLER_USB }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_MOTION_CONTROLLER), -- cgit v0.10.2 From b2723eb73c6dc014980beb0f3e5f47d6cac57939 Mon Sep 17 00:00:00 2001 From: Simon Wood Date: Wed, 17 Jun 2015 00:08:53 -0600 Subject: HID: hid-sony: Fix report descriptor for Navigation Controller Patch report descriptor to remove unused and ramdomly changing axis. Original report descriptor (via BT) was as follows: 00000000 05 01 09 04 a1 01 a1 02 85 01 75 08 95 01 15 00 |..........u.....| 00000010 26 ff 00 81 03 75 01 95 13 15 00 25 01 35 00 45 |&....u.....%.5.E| 00000020 01 05 09 19 01 29 13 81 02 75 01 95 0d 06 00 ff |.....)...u......| 00000030 81 03 15 00 26 ff 00 05 01 09 01 a1 00 75 08 95 |....&........u..| 00000040 04 35 00 46 ff 00 09 30 09 31 09 32 09 35 81 02 |.5.F...0.1.2.5..| 00000050 c0 05 01 75 08 95 27 09 01 81 02 75 08 95 30 09 |...u..'....u..0.| 00000060 01 91 02 75 08 95 30 09 01 b1 02 c0 a1 02 85 02 |...u..0.........| 00000070 75 08 95 30 09 01 b1 02 c0 a1 02 85 ee 75 08 95 |u..0.........u..| 00000080 30 09 01 b1 02 c0 a1 02 85 ef 75 08 95 30 09 01 |0.........u..0..| 00000090 b1 02 c0 c0 00 |.....| 00000095 Signed-off-by: Simon Wood Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index af02139..ed2f008 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -248,6 +248,88 @@ static __u8 motion_rdesc[] = { 0xC0 /* End Collection */ }; +/* PS/3 Navigation controller */ +static __u8 navigation_rdesc[] = { + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x04, /* Usage (Joystik), */ + 0xA1, 0x01, /* Collection (Application), */ + 0xA1, 0x02, /* Collection (Logical), */ + 0x85, 0x01, /* Report ID (1), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x01, /* Report Count (1), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ + 0x81, 0x03, /* Input (Constant, Variable), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x13, /* Report Count (19), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x35, 0x00, /* Physical Minimum (0), */ + 0x45, 0x01, /* Physical Maximum (1), */ + 0x05, 0x09, /* Usage Page (Button), */ + 0x19, 0x01, /* Usage Minimum (01h), */ + 0x29, 0x13, /* Usage Maximum (13h), */ + 0x81, 0x02, /* Input (Variable), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x0D, /* Report Count (13), */ + 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ + 0x81, 0x03, /* Input (Constant, Variable), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0xA1, 0x00, /* Collection (Physical), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x02, /* Report Count (2), */ + 0x35, 0x00, /* Physical Minimum (0), */ + 0x46, 0xFF, 0x00, /* Physical Maximum (255), */ + 0x09, 0x30, /* Usage (X), */ + 0x09, 0x31, /* Usage (Y), */ + 0x81, 0x02, /* Input (Variable), */ + 0xC0, /* End Collection, */ + 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ + 0x95, 0x06, /* Report Count (6), */ + 0x81, 0x03, /* Input (Constant, Variable), */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x05, /* Report Count (5), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0x81, 0x02, /* Input (Variable), */ + 0x06, 0x00, 0xFF, /* Usage Page (FF00h), */ + 0x95, 0x20, /* Report Count (26), */ + 0x81, 0x02, /* Input (Variable), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x30, /* Report Count (48), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0x91, 0x02, /* Output (Variable), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x30, /* Report Count (48), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0xC0, /* End Collection, */ + 0xA1, 0x02, /* Collection (Logical), */ + 0x85, 0x02, /* Report ID (2), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x30, /* Report Count (48), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0xC0, /* End Collection, */ + 0xA1, 0x02, /* Collection (Logical), */ + 0x85, 0xEE, /* Report ID (238), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x30, /* Report Count (48), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0xC0, /* End Collection, */ + 0xA1, 0x02, /* Collection (Logical), */ + 0x85, 0xEF, /* Report ID (239), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x30, /* Report Count (48), */ + 0x09, 0x01, /* Usage (Pointer), */ + 0xB1, 0x02, /* Feature (Variable), */ + 0xC0, /* End Collection, */ + 0xC0 /* End Collection */ +}; /* * The default descriptor doesn't provide mapping for the accelerometers @@ -974,6 +1056,13 @@ static u8 *motion_fixup(struct hid_device *hdev, u8 *rdesc, return motion_rdesc; } +static u8 *navigation_fixup(struct hid_device *hdev, u8 *rdesc, + unsigned int *rsize) +{ + *rsize = sizeof(navigation_rdesc); + return navigation_rdesc; +} + static __u8 *ps3remote_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { @@ -1058,7 +1147,7 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc, return motion_fixup(hdev, rdesc, rsize); if (sc->quirks & NAVIGATION_CONTROLLER) - return sixaxis_fixup(hdev, rdesc, rsize); + return navigation_fixup(hdev, rdesc, rsize); if (sc->quirks & PS3REMOTE) return ps3remote_fixup(hdev, rdesc, rsize); -- cgit v0.10.2 From 18eec2cd7e9746cd672ada102987534ae16f0f44 Mon Sep 17 00:00:00 2001 From: Raimund Roth Date: Mon, 8 Jun 2015 11:11:38 +0200 Subject: HID: microsoft: Add Surface Power Cover Adding support for the Microsoft Surface Pro Power Cover. Signed-off-by: Raimund Roth Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 2a0bd8e..d596a06 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -706,7 +706,8 @@ static void hid_scan_collection(struct hid_parser *parser, unsigned type) if (hid->vendor == USB_VENDOR_ID_MICROSOFT && (hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 || - hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3_JP) && + hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3_JP || + hid->product == USB_DEVICE_ID_MS_POWER_COVER) && hid->group == HID_GROUP_MULTITOUCH) hid->group = HID_GROUP_GENERIC; @@ -1901,6 +1902,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP) }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) }, { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 005335e..4c81b07 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -662,6 +662,7 @@ #define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9 #define USB_DEVICE_ID_MS_TYPE_COVER_3 0x07dc #define USB_DEVICE_ID_MS_TYPE_COVER_3_JP 0x07dd +#define USB_DEVICE_ID_MS_POWER_COVER 0x07da #define USB_VENDOR_ID_MOJO 0x8282 #define USB_DEVICE_ID_RETRO_ADAPTER 0x3201 diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c index af935eb..32a596f 100644 --- a/drivers/hid/hid-microsoft.c +++ b/drivers/hid/hid-microsoft.c @@ -280,6 +280,8 @@ static const struct hid_device_id ms_devices[] = { .driver_data = MS_HIDINPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP), .driver_data = MS_HIDINPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER), + .driver_data = MS_HIDINPUT }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT), .driver_data = MS_PRESENTER }, diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 09a22a7..70dbf61 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -88,6 +88,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP, HID_QUIRK_NO_INIT_REPORTS }, + { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_POWER_COVER, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS }, -- cgit v0.10.2 From 74a3e0c719dcfc66333f43a8414a9c5bfc50bf95 Mon Sep 17 00:00:00 2001 From: Fabian Frederick Date: Wed, 10 Jun 2015 18:32:05 +0200 Subject: HID: cypress: use swap() in cp_report_fixup() Use kernel.h macro definition. Thanks to Julia Lawall for Coccinelle scripting support. Signed-off-by: Fabian Frederick Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-cypress.c b/drivers/hid/hid-cypress.c index c4ef3bc..1b764d1 100644 --- a/drivers/hid/hid-cypress.c +++ b/drivers/hid/hid-cypress.c @@ -41,13 +41,9 @@ static __u8 *cp_report_fixup(struct hid_device *hdev, __u8 *rdesc, for (i = 0; i < *rsize - 4; i++) if (rdesc[i] == 0x29 && rdesc[i + 2] == 0x19) { - __u8 tmp; - rdesc[i] = 0x19; rdesc[i + 2] = 0x29; - tmp = rdesc[i + 3]; - rdesc[i + 3] = rdesc[i + 1]; - rdesc[i + 1] = tmp; + swap(rdesc[i + 3], rdesc[i + 1]); } return rdesc; } -- cgit v0.10.2