* [RFC 1/5] INPUT: xpad: Add minimal support for Logitech G920 Wheel
@ 2015-10-23 17:27 Simon Wood
2015-10-23 17:27 ` [RFC 2/5] HID: hid-logitech-hidpp: Add support for very long packets Simon Wood
` (4 more replies)
0 siblings, 5 replies; 7+ messages in thread
From: Simon Wood @ 2015-10-23 17:27 UTC (permalink / raw)
To: linux-input
Cc: linux-kernel, Jiri Kosina, Edwin, Michal Malý,
elias vanderstuyft, Simon Wood
When plugged in the Logitech G920 wheel starts with USBID 046d:c261
and behaviors as a vendor specific class. If a 'magic' byte sequence
is sent the wheel will detach and reconnect as a HID device with the
USBID 046d:c262.
---
drivers/input/joystick/xpad.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/input/joystick/xpad.c b/drivers/input/joystick/xpad.c
index f8850f9..af83f7e 100644
--- a/drivers/input/joystick/xpad.c
+++ b/drivers/input/joystick/xpad.c
@@ -93,6 +93,7 @@
#define MAP_STICKS_TO_NULL (1 << 2)
#define DANCEPAD_MAP_CONFIG (MAP_DPAD_TO_BUTTONS | \
MAP_TRIGGERS_TO_BUTTONS | MAP_STICKS_TO_NULL)
+#define SWITCH_G920_TO_HID_MODE (1 << 3)
#define XTYPE_XBOX 0
#define XTYPE_XBOX360 1
@@ -133,6 +134,7 @@ static const struct xpad_device {
{ 0x046d, 0xc21e, "Logitech Gamepad F510", 0, XTYPE_XBOX360 },
{ 0x046d, 0xc21f, "Logitech Gamepad F710", 0, XTYPE_XBOX360 },
{ 0x046d, 0xc242, "Logitech Chillstream Controller", 0, XTYPE_XBOX360 },
+ { 0x046d, 0xc261, "Logitech G920 Driving Force Racing Wheel", SWITCH_G920_TO_HID_MODE, XTYPE_XBOXONE },
{ 0x046d, 0xca84, "Logitech Xbox Cordless Controller", 0, XTYPE_XBOX },
{ 0x046d, 0xca88, "Logitech Compact Controller for Xbox", 0, XTYPE_XBOX },
{ 0x05fd, 0x1007, "Mad Catz Controller (unverified)", 0, XTYPE_XBOX },
@@ -299,6 +301,7 @@ static struct usb_device_id xpad_table[] = {
XPAD_XBOX360_VENDOR(0x045e), /* Microsoft X-Box 360 controllers */
XPAD_XBOXONE_VENDOR(0x045e), /* Microsoft X-Box One controllers */
XPAD_XBOX360_VENDOR(0x046d), /* Logitech X-Box 360 style controllers */
+ XPAD_XBOXONE_VENDOR(0x046d), /* Logitech X-Box One style controllers */
XPAD_XBOX360_VENDOR(0x0738), /* Mad Catz X-Box 360 controllers */
{ USB_DEVICE(0x0738, 0x4540) }, /* Mad Catz Beat Pad */
XPAD_XBOX360_VENDOR(0x0e6f), /* 0x0e6f X-Box 360 controllers */
@@ -1021,6 +1024,19 @@ static int xpad_open(struct input_dev *dev)
if (usb_submit_urb(xpad->irq_in, GFP_KERNEL))
return -EIO;
+ /* Logitect G920 wheel starts in XBOX mode, but is reconfigured to be HID */
+ /* device with USBID of 046D:C262. Wheel will detach when 'magic' is sent. */
+ if (xpad->mapping & SWITCH_G920_TO_HID_MODE) {
+ xpad->odata[0] = 0x0F;
+ xpad->odata[1] = 0x00;
+ xpad->odata[2] = 0x01;
+ xpad->odata[3] = 0x01;
+ xpad->odata[4] = 0x42;
+ xpad->irq_out->transfer_buffer_length = 5;
+
+ return usb_submit_urb(xpad->irq_out, GFP_KERNEL);
+ }
+
if (xpad->xtype == XTYPE_XBOXONE) {
/* Xbox one controller needs to be initialized. */
xpad->odata[0] = 0x05;
--
2.1.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [RFC 2/5] HID: hid-logitech-hidpp: Add support for very long packets
2015-10-23 17:27 [RFC 1/5] INPUT: xpad: Add minimal support for Logitech G920 Wheel Simon Wood
@ 2015-10-23 17:27 ` Simon Wood
2015-10-23 17:27 ` [RFC 3/5] HID: hid-logitech-hidpp: Add basic support for Logitech G920 Simon Wood
` (3 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Simon Wood @ 2015-10-23 17:27 UTC (permalink / raw)
To: linux-input
Cc: linux-kernel, Jiri Kosina, Edwin, Michal Malý,
elias vanderstuyft, Simon Wood
Patch add support for the 'very long' HID++ packets, which are
64 bytes in length.
---
drivers/hid/hid-logitech-hidpp.c | 59 ++++++++++++++++++++++++++++++++--------
1 file changed, 48 insertions(+), 11 deletions(-)
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index 4841964..c343b23 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -35,9 +35,11 @@ MODULE_PARM_DESC(disable_raw_mode,
#define REPORT_ID_HIDPP_SHORT 0x10
#define REPORT_ID_HIDPP_LONG 0x11
+#define REPORT_ID_HIDPP_VERY_LONG 0x12
#define HIDPP_REPORT_SHORT_LENGTH 7
#define HIDPP_REPORT_LONG_LENGTH 20
+#define HIDPP_REPORT_VERY_LONG_LENGTH 64
#define HIDPP_QUIRK_CLASS_WTP BIT(0)
#define HIDPP_QUIRK_CLASS_M560 BIT(1)
@@ -71,13 +73,13 @@ MODULE_PARM_DESC(disable_raw_mode,
struct fap {
u8 feature_index;
u8 funcindex_clientid;
- u8 params[HIDPP_REPORT_LONG_LENGTH - 4U];
+ u8 params[HIDPP_REPORT_VERY_LONG_LENGTH - 4U];
};
struct rap {
u8 sub_id;
u8 reg_address;
- u8 params[HIDPP_REPORT_LONG_LENGTH - 4U];
+ u8 params[HIDPP_REPORT_VERY_LONG_LENGTH - 4U];
};
struct hidpp_report {
@@ -143,6 +145,9 @@ static int __hidpp_send_report(struct hid_device *hdev,
case REPORT_ID_HIDPP_LONG:
fields_count = HIDPP_REPORT_LONG_LENGTH;
break;
+ case REPORT_ID_HIDPP_VERY_LONG:
+ fields_count = HIDPP_REPORT_VERY_LONG_LENGTH;
+ break;
default:
return -ENODEV;
}
@@ -207,8 +212,9 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp,
goto exit;
}
- if (response->report_id == REPORT_ID_HIDPP_LONG &&
- response->fap.feature_index == HIDPP20_ERROR) {
+ if ((response->report_id == REPORT_ID_HIDPP_LONG ||
+ response->report_id == REPORT_ID_HIDPP_VERY_LONG) &&
+ response->fap.feature_index == HIDPP20_ERROR) {
ret = response->fap.params[1];
dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret);
goto exit;
@@ -233,7 +239,11 @@ static int hidpp_send_fap_command_sync(struct hidpp_device *hidpp,
message = kzalloc(sizeof(struct hidpp_report), GFP_KERNEL);
if (!message)
return -ENOMEM;
- message->report_id = REPORT_ID_HIDPP_LONG;
+
+ if (param_count > (HIDPP_REPORT_LONG_LENGTH - 4))
+ message->report_id = REPORT_ID_HIDPP_VERY_LONG;
+ else
+ message->report_id = REPORT_ID_HIDPP_LONG;
message->fap.feature_index = feat_index;
message->fap.funcindex_clientid = funcindex_clientid;
memcpy(&message->fap.params, params, param_count);
@@ -248,13 +258,23 @@ static int hidpp_send_rap_command_sync(struct hidpp_device *hidpp_dev,
struct hidpp_report *response)
{
struct hidpp_report *message;
- int ret;
+ int ret, max_count;
- if ((report_id != REPORT_ID_HIDPP_SHORT) &&
- (report_id != REPORT_ID_HIDPP_LONG))
+ switch (report_id) {
+ case REPORT_ID_HIDPP_SHORT:
+ max_count = HIDPP_REPORT_SHORT_LENGTH - 4;
+ break;
+ case REPORT_ID_HIDPP_LONG:
+ max_count = HIDPP_REPORT_LONG_LENGTH - 4;
+ break;
+ case REPORT_ID_HIDPP_VERY_LONG:
+ max_count = HIDPP_REPORT_VERY_LONG_LENGTH - 4;
+ break;
+ default:
return -EINVAL;
+ }
- if (param_count > sizeof(message->rap.params))
+ if (param_count > max_count)
return -EINVAL;
message = kzalloc(sizeof(struct hidpp_report), GFP_KERNEL);
@@ -498,10 +518,19 @@ static int hidpp_devicenametype_get_device_name(struct hidpp_device *hidpp,
if (ret)
return ret;
- if (response.report_id == REPORT_ID_HIDPP_LONG)
+ switch (response.report_id) {
+ case REPORT_ID_HIDPP_VERY_LONG:
+ count = HIDPP_REPORT_VERY_LONG_LENGTH - 4;
+ break;
+ case REPORT_ID_HIDPP_LONG:
count = HIDPP_REPORT_LONG_LENGTH - 4;
- else
+ break;
+ case REPORT_ID_HIDPP_SHORT:
count = HIDPP_REPORT_SHORT_LENGTH - 4;
+ break;
+ default:
+ return -EPROTO;
+ }
if (len_buf < count)
count = len_buf;
@@ -1220,6 +1249,14 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,
/* Generic HID++ processing. */
switch (data[0]) {
+ case REPORT_ID_HIDPP_VERY_LONG:
+ if (size != HIDPP_REPORT_VERY_LONG_LENGTH) {
+ hid_err(hdev, "received hid++ report of bad size (%d)",
+ size);
+ return 1;
+ }
+ ret = hidpp_raw_hidpp_event(hidpp, data, size);
+ break;
case REPORT_ID_HIDPP_LONG:
if (size != HIDPP_REPORT_LONG_LENGTH) {
hid_err(hdev, "received hid++ report of bad size (%d)",
--
2.1.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [RFC 3/5] HID: hid-logitech-hidpp: Add basic support for Logitech G920
2015-10-23 17:27 [RFC 1/5] INPUT: xpad: Add minimal support for Logitech G920 Wheel Simon Wood
2015-10-23 17:27 ` [RFC 2/5] HID: hid-logitech-hidpp: Add support for very long packets Simon Wood
@ 2015-10-23 17:27 ` Simon Wood
2015-10-23 17:27 ` [RFC 4/5] HID: hid-logitech-hidpp: Add range sysfs " Simon Wood
` (2 subsequent siblings)
4 siblings, 0 replies; 7+ messages in thread
From: Simon Wood @ 2015-10-23 17:27 UTC (permalink / raw)
To: linux-input
Cc: linux-kernel, Jiri Kosina, Edwin, Michal Malý,
elias vanderstuyft, Simon Wood
This patch adds basic support for the Logitech G920 wheel when in HID
mode. This wheel 'speaks' the HID++ protocol, and therefor is driven
with hid-logitech-hidpp.
At this stage the driver only shows that it can communicate with the
wheel by outputting the name discovered over HID++.
The normal HID functions work to give input functionality using
joystick/event interface.
---
drivers/hid/hid-core.c | 1 +
drivers/hid/hid-ids.h | 1 +
drivers/hid/hid-logitech-hidpp.c | 69 +++++++++++++++++++++++++++++++---------
3 files changed, 56 insertions(+), 15 deletions(-)
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 70a11ac..fe53b0a 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1896,6 +1896,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD_CORD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_F3D) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FORCE3D_PRO) },
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index f769208..d3500c4 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -614,6 +614,7 @@
#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2 0xc218
#define USB_DEVICE_ID_LOGITECH_RUMBLEPAD2_2 0xc219
#define USB_DEVICE_ID_LOGITECH_G29_WHEEL 0xc24f
+#define USB_DEVICE_ID_LOGITECH_G920_WHEEL 0xc262
#define USB_DEVICE_ID_LOGITECH_WINGMAN_F3D 0xc283
#define USB_DEVICE_ID_LOGITECH_FORCE3D_PRO 0xc286
#define USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940 0xc287
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index c343b23..76d7267 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -43,10 +43,12 @@ MODULE_PARM_DESC(disable_raw_mode,
#define HIDPP_QUIRK_CLASS_WTP BIT(0)
#define HIDPP_QUIRK_CLASS_M560 BIT(1)
+#define HIDPP_QUIRK_CLASS_G920 BIT(2)
/* 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_FORCE_OUTPUT_REPORTS BIT(23)
/*
* There are two hidpp protocols in use, the first version hidpp10 is known
@@ -136,8 +138,11 @@ static void hidpp_connect_event(struct hidpp_device *hidpp_dev);
static int __hidpp_send_report(struct hid_device *hdev,
struct hidpp_report *hidpp_report)
{
+ struct hidpp_device *hidpp = hid_get_drvdata(hdev);
int fields_count, ret;
+ hidpp = hid_get_drvdata(hdev);
+
switch (hidpp_report->report_id) {
case REPORT_ID_HIDPP_SHORT:
fields_count = HIDPP_REPORT_SHORT_LENGTH;
@@ -158,9 +163,13 @@ static int __hidpp_send_report(struct hid_device *hdev,
*/
hidpp_report->device_index = 0xff;
- ret = hid_hw_raw_request(hdev, hidpp_report->report_id,
- (u8 *)hidpp_report, fields_count, HID_OUTPUT_REPORT,
- HID_REQ_SET_REPORT);
+ if (hidpp->quirks & HIDPP_QUIRK_FORCE_OUTPUT_REPORTS) {
+ ret = hid_hw_output_report(hdev, (u8 *)hidpp_report, fields_count);
+ } else {
+ ret = hid_hw_raw_request(hdev, hidpp_report->report_id,
+ (u8 *)hidpp_report, fields_count, HID_OUTPUT_REPORT,
+ HID_REQ_SET_REPORT);
+ }
return ret == fields_count ? 0 : -1;
}
@@ -1305,8 +1314,10 @@ static void hidpp_overwrite_name(struct hid_device *hdev, bool use_unifying)
if (!name)
hid_err(hdev, "unable to retrieve the name of the device");
- else
+ else {
+ dbg_hid("HID++: Got name: %s\n", name);
snprintf(hdev->name, sizeof(hdev->name), "%s", name);
+ }
kfree(name);
}
@@ -1457,6 +1468,25 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
goto hid_parse_fail;
}
+ if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT)
+ connect_mask &= ~HID_CONNECT_HIDINPUT;
+
+ if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
+ ret = hid_hw_start(hdev, connect_mask);
+ if (ret) {
+ hid_err(hdev, "hw start failed\n");
+ goto hid_hw_start_fail;
+ }
+ ret = hid_hw_open(hdev);
+ if (ret < 0) {
+ dev_err(&hdev->dev, "%s:hid_hw_open returned error:%d\n",
+ __func__, ret);
+ hid_hw_stop(hdev);
+ goto hid_hw_start_fail;
+ }
+ }
+
+
/* Allow incoming packets */
hid_device_io_start(hdev);
@@ -1465,8 +1495,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (!connected) {
ret = -ENODEV;
hid_err(hdev, "Device not connected");
- hid_device_io_stop(hdev);
- goto hid_parse_fail;
+ goto hid_hw_open_failed;
}
hid_info(hdev, "HID++ %u.%u device connected.\n",
@@ -1479,19 +1508,18 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (connected && (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)) {
ret = wtp_get_config(hidpp);
if (ret)
- goto hid_parse_fail;
+ goto hid_hw_open_failed;
}
/* Block incoming packets */
hid_device_io_stop(hdev);
- if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT)
- connect_mask &= ~HID_CONNECT_HIDINPUT;
-
- ret = hid_hw_start(hdev, connect_mask);
- if (ret) {
- hid_err(hdev, "%s:hid_hw_start returned error\n", __func__);
- goto hid_hw_start_fail;
+ if (!(hidpp->quirks & HIDPP_QUIRK_CLASS_G920)) {
+ ret = hid_hw_start(hdev, connect_mask);
+ if (ret) {
+ hid_err(hdev, "%s:hid_hw_start returned error\n", __func__);
+ goto hid_hw_start_fail;
+ }
}
if (hidpp->quirks & HIDPP_QUIRK_DELAYED_INIT) {
@@ -1503,6 +1531,12 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
return ret;
+hid_hw_open_failed:
+ hid_device_io_stop(hdev);
+ if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
+ hid_hw_close(hdev);
+ hid_hw_stop(hdev);
+ }
hid_hw_start_fail:
hid_parse_fail:
cancel_work_sync(&hidpp->work);
@@ -1516,9 +1550,11 @@ static void hidpp_remove(struct hid_device *hdev)
{
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
+ if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920)
+ hid_hw_close(hdev);
+ hid_hw_stop(hdev);
cancel_work_sync(&hidpp->work);
mutex_destroy(&hidpp->send_mutex);
- hid_hw_stop(hdev);
}
static const struct hid_device_id hidpp_devices[] = {
@@ -1542,6 +1578,9 @@ static const struct hid_device_id hidpp_devices[] = {
{ HID_DEVICE(BUS_USB, HID_GROUP_LOGITECH_DJ_DEVICE,
USB_VENDOR_ID_LOGITECH, HID_ANY_ID)},
+
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL),
+ .driver_data = HIDPP_QUIRK_CLASS_G920 | HIDPP_QUIRK_FORCE_OUTPUT_REPORTS},
{}
};
--
2.1.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [RFC 4/5] HID: hid-logitech-hidpp: Add range sysfs for Logitech G920
2015-10-23 17:27 [RFC 1/5] INPUT: xpad: Add minimal support for Logitech G920 Wheel Simon Wood
2015-10-23 17:27 ` [RFC 2/5] HID: hid-logitech-hidpp: Add support for very long packets Simon Wood
2015-10-23 17:27 ` [RFC 3/5] HID: hid-logitech-hidpp: Add basic support for Logitech G920 Simon Wood
@ 2015-10-23 17:27 ` Simon Wood
2015-10-23 17:27 ` [RFC 5/5] HID: Add vendor specific usage pages " Simon Wood
2015-10-30 13:51 ` [RFC 1/5] INPUT: xpad: Add minimal support for Logitech G920 Wheel Jiri Kosina
4 siblings, 0 replies; 7+ messages in thread
From: Simon Wood @ 2015-10-23 17:27 UTC (permalink / raw)
To: linux-input
Cc: linux-kernel, Jiri Kosina, Edwin, Michal Malý,
elias vanderstuyft, Simon Wood
The G920 can adjust the amount of 'turn' it permits, this patch adds
a sysfs file 'range' to control this.
---
drivers/hid/hid-logitech-hidpp.c | 140 ++++++++++++++++++++++++++++++++++++++-
1 file changed, 139 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index 76d7267..db05f55 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -1170,6 +1170,133 @@ static int m560_input_mapping(struct hid_device *hdev, struct hid_input *hi,
return -1;
}
+/* ------------------------------------------------------------------------- */
+/* Logitech G920 Driving Force Racing Wheel for Xbox One */
+/* ------------------------------------------------------------------------- */
+
+#define HIDPP_PAGE_G920_FORCE_FEEDBACK 0x8123
+
+/* Using session ID = 1 */
+#define CMD_G920_FORCE_GET_APERTURE 0x51
+#define CMD_G920_FORCE_SET_APERTURE 0x61
+
+struct g920_private_data {
+ u8 force_feature;
+ u16 range;
+};
+
+#define to_hid_device(pdev) container_of(pdev, struct hid_device, dev)
+
+static ssize_t g920_range_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct hid_device *hid = to_hid_device(dev);
+ struct hidpp_device *hidpp = hid_get_drvdata(hid);
+ struct g920_private_data *pdata;
+
+ pdata = hidpp->private_data;
+ if (!pdata) {
+ hid_err(hid, "Private driver data not found!\n");
+ return -EINVAL;
+ }
+
+ return scnprintf(buf, PAGE_SIZE, "%u\n", pdata->range);
+}
+
+static ssize_t g920_range_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct hid_device *hid = to_hid_device(dev);
+ struct hidpp_device *hidpp = hid_get_drvdata(hid);
+ struct g920_private_data *pdata;
+ struct hidpp_report response;
+ u8 params[2];
+ int ret;
+ u16 range = simple_strtoul(buf, NULL, 10);
+
+ pdata = hidpp->private_data;
+ if (!pdata) {
+ hid_err(hid, "Private driver data not found!\n");
+ return -EINVAL;
+ }
+
+ if (range < 180)
+ range = 180;
+ else if (range > 900)
+ range = 900;
+
+ params[0] = range >> 8;
+ params[1] = range & 0x00FF;
+
+ ret = hidpp_send_fap_command_sync(hidpp, pdata->force_feature,
+ CMD_G920_FORCE_SET_APERTURE, params, 2, &response);
+ if (ret)
+ return ret;
+
+ pdata->range = range;
+ return count;
+}
+
+static DEVICE_ATTR(range, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH, g920_range_show, g920_range_store);
+
+static int g920_allocate(struct hid_device *hdev)
+{
+ struct hidpp_device *hidpp = hid_get_drvdata(hdev);
+ struct g920_private_data *pdata;
+
+ pdata = devm_kzalloc(&hdev->dev, sizeof(struct g920_private_data),
+ GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ hidpp->private_data = pdata;
+
+ return 0;
+}
+
+static int g920_get_config(struct hidpp_device *hidpp)
+{
+ struct g920_private_data *pdata = hidpp->private_data;
+ struct hidpp_report response;
+ u8 feature_type;
+ u8 feature_index;
+ int ret;
+
+ pdata = hidpp->private_data;
+ if (!pdata) {
+ hid_err(hidpp->hid_dev, "Private driver data not found!\n");
+ return -EINVAL;
+ }
+
+ /* Find feature and store for later use */
+ ret = hidpp_root_get_feature(hidpp, HIDPP_PAGE_G920_FORCE_FEEDBACK,
+ &feature_index, &feature_type);
+ if (ret)
+ return ret;
+
+ pdata->force_feature = feature_index;
+
+ /* Read current Range */
+ ret = hidpp_send_fap_command_sync(hidpp, feature_index,
+ CMD_G920_FORCE_GET_APERTURE, NULL, 0, &response);
+ if (ret > 0) {
+ hid_err(hidpp->hid_dev, "%s: received protocol error 0x%02x\n",
+ __func__, ret);
+ return -EPROTO;
+ }
+ if (ret)
+ return ret;
+
+ pdata->range = get_unaligned_be16(&response.fap.params[0]);
+
+ /* Create sysfs interface */
+ ret = device_create_file(&(hidpp->hid_dev->dev), &dev_attr_range);
+ if (ret)
+ hid_warn(hidpp->hid_dev, "Unable to create sysfs interface for \"range\", errno %d\n", ret);
+
+ return 0;
+}
+
/* -------------------------------------------------------------------------- */
/* Generic HID++ devices */
/* -------------------------------------------------------------------------- */
@@ -1456,6 +1583,10 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = m560_allocate(hdev);
if (ret)
goto allocate_fail;
+ } else if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
+ ret = g920_allocate(hdev);
+ if (ret)
+ goto allocate_fail;
}
INIT_WORK(&hidpp->work, delayed_work_cb);
@@ -1509,6 +1640,10 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = wtp_get_config(hidpp);
if (ret)
goto hid_hw_open_failed;
+ } else if (connected && (hidpp->quirks & HIDPP_QUIRK_CLASS_G920)) {
+ ret = g920_get_config(hidpp);
+ if (ret)
+ goto hid_hw_open_failed;
}
/* Block incoming packets */
@@ -1534,6 +1669,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
hid_hw_open_failed:
hid_device_io_stop(hdev);
if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
+ device_remove_file(&hdev->dev, &dev_attr_range);
hid_hw_close(hdev);
hid_hw_stop(hdev);
}
@@ -1550,8 +1686,10 @@ static void hidpp_remove(struct hid_device *hdev)
{
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
- if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920)
+ if (hidpp->quirks & HIDPP_QUIRK_CLASS_G920) {
+ device_remove_file(&hdev->dev, &dev_attr_range);
hid_hw_close(hdev);
+ }
hid_hw_stop(hdev);
cancel_work_sync(&hidpp->work);
mutex_destroy(&hidpp->send_mutex);
--
2.1.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [RFC 5/5] HID: Add vendor specific usage pages for Logitech G920
2015-10-23 17:27 [RFC 1/5] INPUT: xpad: Add minimal support for Logitech G920 Wheel Simon Wood
` (2 preceding siblings ...)
2015-10-23 17:27 ` [RFC 4/5] HID: hid-logitech-hidpp: Add range sysfs " Simon Wood
@ 2015-10-23 17:27 ` Simon Wood
2015-10-30 13:51 ` [RFC 1/5] INPUT: xpad: Add minimal support for Logitech G920 Wheel Jiri Kosina
4 siblings, 0 replies; 7+ messages in thread
From: Simon Wood @ 2015-10-23 17:27 UTC (permalink / raw)
To: linux-input
Cc: linux-kernel, Jiri Kosina, Edwin, Michal Malý,
elias vanderstuyft, Simon Wood
The Logitech G920 uses a couple of vendor specific usage pages,
which results in incorrect number of axis/buttons being detected.
This patch adds these pages to the 'ignore' list.
Reported-by: Elias Vanderstuyft <elias.vds@gmail.com>
---
drivers/hid/hid-input.c | 2 +-
include/linux/hid.h | 2 ++
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 53aeaf6..c120be5 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -959,7 +959,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
set_bit(EV_REP, input->evbit);
goto ignore;
- case HID_UP_LOGIVENDOR:
+ case HID_UP_LOGIVENDOR: case HID_UP_LOGIVENDOR2: case HID_UP_LOGIVENDOR3:
goto ignore;
case HID_UP_PID:
diff --git a/include/linux/hid.h b/include/linux/hid.h
index f17980d..ce1d883 100644
--- a/include/linux/hid.h
+++ b/include/linux/hid.h
@@ -168,6 +168,8 @@ struct hid_item {
#define HID_UP_MSVENDOR 0xff000000
#define HID_UP_CUSTOM 0x00ff0000
#define HID_UP_LOGIVENDOR 0xffbc0000
+#define HID_UP_LOGIVENDOR2 0xff090000
+#define HID_UP_LOGIVENDOR3 0xff430000
#define HID_UP_LNVENDOR 0xffa00000
#define HID_UP_SENSOR 0x00200000
--
2.1.4
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [RFC 1/5] INPUT: xpad: Add minimal support for Logitech G920 Wheel
2015-10-23 17:27 [RFC 1/5] INPUT: xpad: Add minimal support for Logitech G920 Wheel Simon Wood
` (3 preceding siblings ...)
2015-10-23 17:27 ` [RFC 5/5] HID: Add vendor specific usage pages " Simon Wood
@ 2015-10-30 13:51 ` Jiri Kosina
2015-11-09 7:54 ` Benjamin Tissoires
4 siblings, 1 reply; 7+ messages in thread
From: Jiri Kosina @ 2015-10-30 13:51 UTC (permalink / raw)
To: Simon Wood
Cc: linux-input, linux-kernel, Edwin, Michal Malý,
elias vanderstuyft, Benjamin Tissoires
On Fri, 23 Oct 2015, Simon Wood wrote:
> When plugged in the Logitech G920 wheel starts with USBID 046d:c261
> and behaviors as a vendor specific class. If a 'magic' byte sequence
> is sent the wheel will detach and reconnect as a HID device with the
> USBID 046d:c262.
[ Benjamin added to CC ]
Benjamin, before I proceed with this series, I'd like you to have review
the HID++ bits at least, if possible. Thanks,
--
Jiri Kosina
SUSE Labs
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [RFC 1/5] INPUT: xpad: Add minimal support for Logitech G920 Wheel
2015-10-30 13:51 ` [RFC 1/5] INPUT: xpad: Add minimal support for Logitech G920 Wheel Jiri Kosina
@ 2015-11-09 7:54 ` Benjamin Tissoires
0 siblings, 0 replies; 7+ messages in thread
From: Benjamin Tissoires @ 2015-11-09 7:54 UTC (permalink / raw)
To: Jiri Kosina
Cc: Simon Wood, linux-input, linux-kernel, Edwin, Michal Malý,
elias vanderstuyft, Benjamin Tissoires
Hi,
----- Original Message -----
> From: "Jiri Kosina" <jikos@kernel.org>
> To: "Simon Wood" <simon@mungewell.org>
> Cc: linux-input@vger.kernel.org, linux-kernel@vger.kernel.org, "Edwin" <Edwin@Velds.nl>, "Michal Malý"
> <madcatxster@devoid-pointer.net>, "elias vanderstuyft" <elias.vds@gmail.com>, "Benjamin Tissoires"
> <benjamin.tissoires@redhat.com>
> Sent: Friday, October 30, 2015 2:51:47 PM
> Subject: Re: [RFC 1/5] INPUT: xpad: Add minimal support for Logitech G920 Wheel
>
> On Fri, 23 Oct 2015, Simon Wood wrote:
>
> > When plugged in the Logitech G920 wheel starts with USBID 046d:c261
> > and behaviors as a vendor specific class. If a 'magic' byte sequence
> > is sent the wheel will detach and reconnect as a HID device with the
> > USBID 046d:c262.
>
> [ Benjamin added to CC ]
>
> Benjamin, before I proceed with this series, I'd like you to have review
> the HID++ bits at least, if possible. Thanks,
>
Sorry for the lag everybody. I have been busy the past week with my move across the Atlantic. I'll review it in a few minutes.
Just so you know Jiri, I have seen preliminary patches of this series while it was still embargoed by Logitech, and IIRC Simon already included changes I requested at the time.
Cheers,
Benjamin
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2015-11-09 7:56 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-10-23 17:27 [RFC 1/5] INPUT: xpad: Add minimal support for Logitech G920 Wheel Simon Wood
2015-10-23 17:27 ` [RFC 2/5] HID: hid-logitech-hidpp: Add support for very long packets Simon Wood
2015-10-23 17:27 ` [RFC 3/5] HID: hid-logitech-hidpp: Add basic support for Logitech G920 Simon Wood
2015-10-23 17:27 ` [RFC 4/5] HID: hid-logitech-hidpp: Add range sysfs " Simon Wood
2015-10-23 17:27 ` [RFC 5/5] HID: Add vendor specific usage pages " Simon Wood
2015-10-30 13:51 ` [RFC 1/5] INPUT: xpad: Add minimal support for Logitech G920 Wheel Jiri Kosina
2015-11-09 7:54 ` Benjamin Tissoires
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).