* [PATCH] HID: hid-lg4ff: Add support for G27 LEDs [not found] <1649210.pcO5IpzBEF@qosmio-x300> @ 2012-04-09 16:08 ` Simon Wood 2012-04-13 12:59 ` Jiri Kosina 0 siblings, 1 reply; 10+ messages in thread From: Simon Wood @ 2012-04-09 16:08 UTC (permalink / raw) To: linux-input Cc: linux-kernel, Jiri Kosina, Michael Bauer, Michal Maly, Simon Wood This patch adds supports for controlling the LED 'tachometer' on the G27 wheel, via the LED subsystem. The 5 LEDs are arranged from right (1=grn, 2=grn, 3=yel, 4=yel, 5=red) and 'mirrored' to the left (10 LEDs in total). Signed-off-by: Simon Wood <simon@mungewell.org> --- drivers/hid/hid-lg4ff.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 148 insertions(+), 1 deletions(-) diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index 32c173f..8960347 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -55,7 +55,8 @@ struct lg4ff_device_entry { __u16 range; __u16 min_range; __u16 max_range; - __u8 leds; + __u8 led_state; + struct led_classdev *led[5]; struct list_head list; void (*set_range)(struct hid_device *hid, u16 range); }; @@ -335,6 +336,86 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at return count; } +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); + + report->field[0]->value[0] = 0xf8; + report->field[0]->value[1] = 0x12; + report->field[0]->value[2] = leds; + report->field[0]->value[3] = 0x00; + report->field[0]->value[4] = 0x00; + report->field[0]->value[5] = 0x00; + report->field[0]->value[6] = 0x00; + usbhid_submit_report(hid, report, USB_DIR_OUT); +} + +static void lg4ff_led_set_brightness(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct device *dev = led_cdev->dev->parent; + struct hid_device *hid = container_of(dev, struct hid_device, dev); + struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hid); + struct lg4ff_device_entry *entry; + int i, state = 0; + + if (!drv_data) { + hid_err(hid, "Device data not found."); + return; + } + + entry = (struct lg4ff_device_entry *)drv_data->device_props; + + if (!entry) { + hid_err(hid, "Device properties not found."); + return; + } + + for (i = 0; i < 5; i++) { + if (led_cdev != entry->led[i]) + continue; + state = (entry->led_state >> i) & 1; + if (value == LED_OFF && state) { + entry->led_state &= ~(1 << i); + lg4ff_set_leds(hid, entry->led_state); + } else if (value != LED_OFF && !state) { + entry->led_state |= 1 << i; + lg4ff_set_leds(hid, entry->led_state); + } + break; + } +} + +static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cdev) +{ + struct device *dev = led_cdev->dev->parent; + struct hid_device *hid = container_of(dev, struct hid_device, dev); + struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hid); + struct lg4ff_device_entry *entry; + int i, value = 0; + + if (!drv_data) { + hid_err(hid, "Device data not found."); + return LED_OFF; + } + + entry = (struct lg4ff_device_entry *)drv_data->device_props; + + if (!entry) { + hid_err(hid, "Device properties not found."); + return LED_OFF; + } + + for (i = 0; i < 5; i++) + if (led_cdev == entry->led[i]) { + value = (entry->led_state >> i) & 1; + break; + } + + return value ? LED_FULL : LED_OFF; +} + int lg4ff_init(struct hid_device *hid) { struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); @@ -347,6 +428,9 @@ int lg4ff_init(struct hid_device *hid) struct usb_device_descriptor *udesc; int error, i, j; __u16 bcdDevice, rev_maj, rev_min; + struct led_classdev *led; + size_t name_sz; + char *name; /* Find the report to use */ if (list_empty(report_list)) { @@ -453,14 +537,66 @@ int lg4ff_init(struct hid_device *hid) if (entry->set_range != NULL) entry->set_range(hid, entry->range); + /* register led subsystem - G27 only */ + entry->led_state = 0; + for (j = 0; j < 5; j++) + entry->led[j] = NULL; + + if (lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_G27_WHEEL) { + lg4ff_set_leds(hid, 0); + + name_sz = strlen(dev_name(&hid->dev)) + 8; + + for (j = 0; j < 5; j++) { + led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL); + if (!led) { + hid_err(hid, "can't allocate memory for LED %d\n", j); + error = -ENOMEM; + goto err; + } + + name = (void *)(&led[1]); + snprintf(name, name_sz, "%s::RPM%d", dev_name(&hid->dev), j+1); + led->name = name; + led->brightness = 0; + led->max_brightness = 1; + led->brightness_get = lg4ff_led_get_brightness; + led->brightness_set = lg4ff_led_set_brightness; + + entry->led[j] = led; + error = led_classdev_register(&hid->dev, led); + if (error) { + hid_err(hid, "failed to register LED %d. Aborting.\n", j); + goto err; + } + } + + dbg_hid("sysfs interface created for leds\n"); + } + hid_info(hid, "Force feedback for Logitech Speed Force Wireless by Simon Wood <simon@mungewell.org>\n"); return 0; + +err: + /* Deregister LEDs (if any) but let the driver continue */ + for (j = 0; j < 5; j++) { + led = entry->led[j]; + entry->led[j] = NULL; + if (!led) + continue; + led_classdev_unregister(led); + kfree(led); + } + + return 0; } int lg4ff_deinit(struct hid_device *hid) { struct lg4ff_device_entry *entry; struct lg_drv_data *drv_data; + int j; + struct led_classdev *led; device_remove_file(&hid->dev, &dev_attr_range); @@ -474,6 +610,17 @@ int lg4ff_deinit(struct hid_device *hid) hid_err(hid, "Error while deinitializing device, no device properties data.\n"); return -1; } + + /* Deregister LEDs (if any) */ + for (j = 0; j < 5; j++) { + led = entry->led[j]; + entry->led[j] = NULL; + if (!led) + continue; + led_classdev_unregister(led); + kfree(led); + } + /* Deallocate memory */ kfree(entry); -- 1.7.4.1 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH] HID: hid-lg4ff: Add support for G27 LEDs 2012-04-09 16:08 ` [PATCH] HID: hid-lg4ff: Add support for G27 LEDs Simon Wood @ 2012-04-13 12:59 ` Jiri Kosina 2012-04-18 7:03 ` [PATCH 1/2] " Simon Wood 0 siblings, 1 reply; 10+ messages in thread From: Jiri Kosina @ 2012-04-13 12:59 UTC (permalink / raw) To: Simon Wood; +Cc: linux-input, linux-kernel, Michael Bauer, Michal Maly On Mon, 9 Apr 2012, Simon Wood wrote: > This patch adds supports for controlling the LED 'tachometer' on > the G27 wheel, via the LED subsystem. > > The 5 LEDs are arranged from right (1=grn, 2=grn, 3=yel, 4=yel, 5=red) > and 'mirrored' to the left (10 LEDs in total). > > Signed-off-by: Simon Wood <simon@mungewell.org> > --- > drivers/hid/hid-lg4ff.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++- > 1 files changed, 148 insertions(+), 1 deletions(-) This patch introduces a clear dependency of hid-lg4ff driver on CONFIG_LEDS_CLASS, but the code doesn't reflect it. So either you have to put #ifdef into source to compile the leds part out if leds subsystem is not enabled, or you have to introduce Kconfig rule to cover this. -- Jiri Kosina SUSE Labs ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 1/2] HID: hid-lg4ff: Add support for G27 LEDs 2012-04-13 12:59 ` Jiri Kosina @ 2012-04-18 7:03 ` Simon Wood 2012-04-18 7:03 ` [PATCH 2/2] HID: hid-lg4ff: Updated Comments Simon Wood 2012-04-18 11:24 ` [PATCH 1/2] HID: hid-lg4ff: Add support for G27 LEDs Jiri Kosina 0 siblings, 2 replies; 10+ messages in thread From: Simon Wood @ 2012-04-18 7:03 UTC (permalink / raw) To: linux-input Cc: linux-kernel, Jiri Kosina, Michael Bauer, Michal Maly, Simon Wood This patch adds supports for controlling the LED 'tachometer' on the G27 wheel, via the LED subsystem. The 5 LEDs are arranged from right (1=grn, 2=grn, 3=yel, 4=yel, 5=red) and 'mirrored' to the left (10 LEDs in total). Signed-off-by: Simon Wood <simon@mungewell.org> --- drivers/hid/hid-lg4ff.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 154 insertions(+), 1 deletions(-) diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index 32c173f..ab5232e 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -55,7 +55,8 @@ struct lg4ff_device_entry { __u16 range; __u16 min_range; __u16 max_range; - __u8 leds; + __u8 led_state; + struct led_classdev *led[5]; struct list_head list; void (*set_range)(struct hid_device *hid, u16 range); }; @@ -335,6 +336,88 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at return count; } +#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); + + report->field[0]->value[0] = 0xf8; + report->field[0]->value[1] = 0x12; + report->field[0]->value[2] = leds; + report->field[0]->value[3] = 0x00; + report->field[0]->value[4] = 0x00; + report->field[0]->value[5] = 0x00; + report->field[0]->value[6] = 0x00; + usbhid_submit_report(hid, report, USB_DIR_OUT); +} + +static void lg4ff_led_set_brightness(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct device *dev = led_cdev->dev->parent; + struct hid_device *hid = container_of(dev, struct hid_device, dev); + struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hid); + struct lg4ff_device_entry *entry; + int i, state = 0; + + if (!drv_data) { + hid_err(hid, "Device data not found."); + return; + } + + entry = (struct lg4ff_device_entry *)drv_data->device_props; + + if (!entry) { + hid_err(hid, "Device properties not found."); + return; + } + + for (i = 0; i < 5; i++) { + if (led_cdev != entry->led[i]) + continue; + state = (entry->led_state >> i) & 1; + if (value == LED_OFF && state) { + entry->led_state &= ~(1 << i); + lg4ff_set_leds(hid, entry->led_state); + } else if (value != LED_OFF && !state) { + entry->led_state |= 1 << i; + lg4ff_set_leds(hid, entry->led_state); + } + break; + } +} + +static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cdev) +{ + struct device *dev = led_cdev->dev->parent; + struct hid_device *hid = container_of(dev, struct hid_device, dev); + struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hid); + struct lg4ff_device_entry *entry; + int i, value = 0; + + if (!drv_data) { + hid_err(hid, "Device data not found."); + return LED_OFF; + } + + entry = (struct lg4ff_device_entry *)drv_data->device_props; + + if (!entry) { + hid_err(hid, "Device properties not found."); + return LED_OFF; + } + + for (i = 0; i < 5; i++) + if (led_cdev == entry->led[i]) { + value = (entry->led_state >> i) & 1; + break; + } + + return value ? LED_FULL : LED_OFF; +} +#endif + int lg4ff_init(struct hid_device *hid) { struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); @@ -453,6 +536,57 @@ int lg4ff_init(struct hid_device *hid) if (entry->set_range != NULL) entry->set_range(hid, entry->range); + /* register led subsystem - G27 only */ + entry->led_state = 0; + for (j = 0; j < 5; j++) + entry->led[j] = NULL; + +#ifdef CONFIG_LEDS_CLASS + if (lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_G27_WHEEL) { + struct led_classdev *led; + size_t name_sz; + char *name; + + lg4ff_set_leds(hid, 0); + + name_sz = strlen(dev_name(&hid->dev)) + 8; + + for (j = 0; j < 5; j++) { + 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; + } + + name = (void *)(&led[1]); + snprintf(name, name_sz, "%s::RPM%d", dev_name(&hid->dev), j+1); + led->name = name; + led->brightness = 0; + led->max_brightness = 1; + led->brightness_get = lg4ff_led_get_brightness; + led->brightness_set = lg4ff_led_set_brightness; + + entry->led[j] = led; + error = led_classdev_register(&hid->dev, led); + + if (error) { + hid_err(hid, "failed to register LED %d. Aborting.\n", j); +err: + /* Deregister LEDs (if any) but let the driver continue */ + for (j = 0; j < 5; j++) { + led = entry->led[j]; + entry->led[j] = NULL; + if (!led) + continue; + led_classdev_unregister(led); + kfree(led); + } + break; /* Don't create any more LEDs */ + } + } + } +#endif + hid_info(hid, "Force feedback for Logitech Speed Force Wireless by Simon Wood <simon@mungewell.org>\n"); return 0; } @@ -474,6 +608,25 @@ int lg4ff_deinit(struct hid_device *hid) hid_err(hid, "Error while deinitializing device, no device properties data.\n"); return -1; } + +#ifdef CONFIG_LEDS_CLASS + { + int j; + struct led_classdev *led; + + /* Deregister LEDs (if any) */ + for (j = 0; j < 5; j++) { + + led = entry->led[j]; + entry->led[j] = NULL; + if (!led) + continue; + led_classdev_unregister(led); + kfree(led); + } + } +#endif + /* Deallocate memory */ kfree(entry); -- 1.7.4.1 ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 2/2] HID: hid-lg4ff: Updated Comments 2012-04-18 7:03 ` [PATCH 1/2] " Simon Wood @ 2012-04-18 7:03 ` Simon Wood 2012-04-18 11:24 ` [PATCH 1/2] HID: hid-lg4ff: Add support for G27 LEDs Jiri Kosina 1 sibling, 0 replies; 10+ messages in thread From: Simon Wood @ 2012-04-18 7:03 UTC (permalink / raw) To: linux-input Cc: linux-kernel, Jiri Kosina, Michael Bauer, Michal Maly, Simon Wood Updated comments to say that this driver now supports all Logitech gaming wheels, and not just the WiiWheel Signed-off-by: Simon Wood <simon@mungewell.org> --- drivers/hid/hid-lg4ff.c | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index ab5232e..cbafb46 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -1,7 +1,8 @@ /* - * Force feedback support for Logitech Speed Force Wireless + * Force feedback support for Logitech Gaming Wheels * - * http://wiibrew.org/wiki/Logitech_USB_steering_wheel + * Including G27, G25, DFP, DFGT, FFEX, Momo, Momo2 & + * Wireless Speed Force (WiiWheel) * * Copyright (c) 2010 Simon Wood <simon@mungewell.org> */ @@ -587,7 +588,7 @@ err: } #endif - hid_info(hid, "Force feedback for Logitech Speed Force Wireless by Simon Wood <simon@mungewell.org>\n"); + hid_info(hid, "Force feedback for Logitech Gaming Wheels\n"); return 0; } -- 1.7.4.1 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 1/2] HID: hid-lg4ff: Add support for G27 LEDs 2012-04-18 7:03 ` [PATCH 1/2] " Simon Wood 2012-04-18 7:03 ` [PATCH 2/2] HID: hid-lg4ff: Updated Comments Simon Wood @ 2012-04-18 11:24 ` Jiri Kosina 2012-04-18 14:58 ` simon 1 sibling, 1 reply; 10+ messages in thread From: Jiri Kosina @ 2012-04-18 11:24 UTC (permalink / raw) To: Simon Wood; +Cc: linux-input, linux-kernel, Michael Bauer, Michal Maly On Wed, 18 Apr 2012, Simon Wood wrote: > This patch adds supports for controlling the LED 'tachometer' on > the G27 wheel, via the LED subsystem. > > The 5 LEDs are arranged from right (1=grn, 2=grn, 3=yel, 4=yel, 5=red) > and 'mirrored' to the left (10 LEDs in total). > > Signed-off-by: Simon Wood <simon@mungewell.org> > --- > drivers/hid/hid-lg4ff.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++- > 1 files changed, 154 insertions(+), 1 deletions(-) > > diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c > index 32c173f..ab5232e 100644 > --- a/drivers/hid/hid-lg4ff.c > +++ b/drivers/hid/hid-lg4ff.c > @@ -55,7 +55,8 @@ struct lg4ff_device_entry { > __u16 range; > __u16 min_range; > __u16 max_range; > - __u8 leds; > + __u8 led_state; > + struct led_classdev *led[5]; Why not put this under the CONFIG_LEDS_CLASS condition as well? > struct list_head list; > void (*set_range)(struct hid_device *hid, u16 range); > }; > @@ -335,6 +336,88 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at > return count; > } > > +#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); > + > + report->field[0]->value[0] = 0xf8; > + report->field[0]->value[1] = 0x12; > + report->field[0]->value[2] = leds; > + report->field[0]->value[3] = 0x00; > + report->field[0]->value[4] = 0x00; > + report->field[0]->value[5] = 0x00; > + report->field[0]->value[6] = 0x00; > + usbhid_submit_report(hid, report, USB_DIR_OUT); > +} > + > +static void lg4ff_led_set_brightness(struct led_classdev *led_cdev, > + enum led_brightness value) > +{ > + struct device *dev = led_cdev->dev->parent; > + struct hid_device *hid = container_of(dev, struct hid_device, dev); > + struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hid); > + struct lg4ff_device_entry *entry; > + int i, state = 0; > + > + if (!drv_data) { > + hid_err(hid, "Device data not found."); > + return; > + } > + > + entry = (struct lg4ff_device_entry *)drv_data->device_props; > + > + if (!entry) { > + hid_err(hid, "Device properties not found."); > + return; > + } > + > + for (i = 0; i < 5; i++) { > + if (led_cdev != entry->led[i]) > + continue; > + state = (entry->led_state >> i) & 1; > + if (value == LED_OFF && state) { > + entry->led_state &= ~(1 << i); > + lg4ff_set_leds(hid, entry->led_state); > + } else if (value != LED_OFF && !state) { > + entry->led_state |= 1 << i; > + lg4ff_set_leds(hid, entry->led_state); > + } > + break; > + } > +} > + > +static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cdev) > +{ > + struct device *dev = led_cdev->dev->parent; > + struct hid_device *hid = container_of(dev, struct hid_device, dev); > + struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hid); > + struct lg4ff_device_entry *entry; > + int i, value = 0; > + > + if (!drv_data) { > + hid_err(hid, "Device data not found."); > + return LED_OFF; > + } > + > + entry = (struct lg4ff_device_entry *)drv_data->device_props; > + > + if (!entry) { > + hid_err(hid, "Device properties not found."); > + return LED_OFF; > + } > + > + for (i = 0; i < 5; i++) > + if (led_cdev == entry->led[i]) { > + value = (entry->led_state >> i) & 1; > + break; > + } > + > + return value ? LED_FULL : LED_OFF; > +} > +#endif > + > int lg4ff_init(struct hid_device *hid) > { > struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); > @@ -453,6 +536,57 @@ int lg4ff_init(struct hid_device *hid) > if (entry->set_range != NULL) > entry->set_range(hid, entry->range); > > + /* register led subsystem - G27 only */ > + entry->led_state = 0; > + for (j = 0; j < 5; j++) > + entry->led[j] = NULL; > + The same here. > +#ifdef CONFIG_LEDS_CLASS > + if (lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_G27_WHEEL) { > + struct led_classdev *led; > + size_t name_sz; > + char *name; > + > + lg4ff_set_leds(hid, 0); > + > + name_sz = strlen(dev_name(&hid->dev)) + 8; > + > + for (j = 0; j < 5; j++) { > + 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; > + } > + > + name = (void *)(&led[1]); > + snprintf(name, name_sz, "%s::RPM%d", dev_name(&hid->dev), j+1); > + led->name = name; > + led->brightness = 0; > + led->max_brightness = 1; > + led->brightness_get = lg4ff_led_get_brightness; > + led->brightness_set = lg4ff_led_set_brightness; > + > + entry->led[j] = led; > + error = led_classdev_register(&hid->dev, led); > + > + if (error) { > + hid_err(hid, "failed to register LED %d. Aborting.\n", j); > +err: > + /* Deregister LEDs (if any) but let the driver continue */ > + for (j = 0; j < 5; j++) { > + led = entry->led[j]; > + entry->led[j] = NULL; > + if (!led) > + continue; > + led_classdev_unregister(led); > + kfree(led); Indentation seems to be wrong here. > + } > + break; /* Don't create any more LEDs */ Putting the whole err: label outside the outer for cycle would make the whole thing much more readable (and would save you the break). Could you please redo this? > + } > + } > + } > +#endif > + > hid_info(hid, "Force feedback for Logitech Speed Force Wireless by Simon Wood <simon@mungewell.org>\n"); > return 0; > } > @@ -474,6 +608,25 @@ int lg4ff_deinit(struct hid_device *hid) > hid_err(hid, "Error while deinitializing device, no device properties data.\n"); > return -1; > } > + > +#ifdef CONFIG_LEDS_CLASS > + { > + int j; > + struct led_classdev *led; > + > + /* Deregister LEDs (if any) */ > + for (j = 0; j < 5; j++) { > + > + led = entry->led[j]; > + entry->led[j] = NULL; > + if (!led) > + continue; > + led_classdev_unregister(led); > + kfree(led); > + } > + } > +#endif > + > /* Deallocate memory */ > kfree(entry); > Thanks, -- Jiri Kosina SUSE Labs ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 1/2] HID: hid-lg4ff: Add support for G27 LEDs 2012-04-18 11:24 ` [PATCH 1/2] HID: hid-lg4ff: Add support for G27 LEDs Jiri Kosina @ 2012-04-18 14:58 ` simon 2012-04-20 10:05 ` Jiri Kosina 0 siblings, 1 reply; 10+ messages in thread From: simon @ 2012-04-18 14:58 UTC (permalink / raw) To: Jiri Kosina Cc: Simon Wood, linux-input, linux-kernel, Michael Bauer, Michal Maly >> + __u8 led_state; >> + struct led_classdev *led[5]; > > Why not put this under the CONFIG_LEDS_CLASS condition as well? Can do, I don't think these are referenced anywhere else. >> + /* register led subsystem - G27 only */ >> + entry->led_state = 0; >> + for (j = 0; j < 5; j++) >> + entry->led[j] = NULL; >> + > > The same here. OK. >> + if (error) { >> + hid_err(hid, "failed to register LED %d. Aborting.\n", j); >> +err: >> + /* Deregister LEDs (if any) but let the driver continue */ >> + for (j = 0; j < 5; j++) { >> + led = entry->led[j]; >> + entry->led[j] = NULL; >> + if (!led) >> + continue; >> + led_classdev_unregister(led); >> + kfree(led); > > Indentation seems to be wrong here. Bugger... > >> + } >> + break; /* Don't create any more LEDs */ > > Putting the whole err: label outside the outer for cycle would make the > whole thing much more readable (and would save you the break). Could you > please redo this? The 'break' is actually not needed as 'j' has reached maximum value and the outer for loop would be at completion. I put the 'break' there just to highlight this fact. Maybe just a comment would be OK, such as 'on error fall though to driver completion'. The reason I'd like this code here is that it seems traditional to output the following 'hid_info' line once the driver is fully active. >> hid_info(hid, "Force feedback for Logitech Speed Force Wireless by >> Simon Wood <simon@mungewell.org>\n"); Moving the 'err:' code would have to: 1). Jump back to hit this hid_info line 2). Duplicate the hid_info line 3). Have err code called as a function Any major objections to keeping it as is? Man, it seems to be taking me ages to get this code right.... Simon ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 1/2] HID: hid-lg4ff: Add support for G27 LEDs 2012-04-18 14:58 ` simon @ 2012-04-20 10:05 ` Jiri Kosina 2012-04-21 12:41 ` Simon Wood 0 siblings, 1 reply; 10+ messages in thread From: Jiri Kosina @ 2012-04-20 10:05 UTC (permalink / raw) To: Simon Wood; +Cc: linux-input, linux-kernel, Michael Bauer, Michal Maly On Wed, 18 Apr 2012, simon@mungewell.org wrote: > > Putting the whole err: label outside the outer for cycle would make the > > whole thing much more readable (and would save you the break). Could you > > please redo this? > > The 'break' is actually not needed as 'j' has reached maximum value and > the outer for loop would be at completion. Ah, right, I have even missed this fact, that you are using the same index in the inner loop as in the outter loop. Quite unreadable indeed :) > I put the 'break' there just to highlight this fact. > > Maybe just a comment would be OK, such as 'on error fall though to driver > completion'. > > The reason I'd like this code here is that it seems traditional to output > the following 'hid_info' line once the driver is fully active. > > >> hid_info(hid, "Force feedback for Logitech Speed Force Wireless by > >> Simon Wood <simon@mungewell.org>\n"); > > Moving the 'err:' code would have to: > 1). Jump back to hit this hid_info line > 2). Duplicate the hid_info line > 3). Have err code called as a function I am not getting it. Why can't you do just something like for ( .... ) { /* outter loop */ if (error) { for ( ... ) { /* inner loop */ } goto out; } } out: hid_info(....); return; -- Jiri Kosina SUSE Labs ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 1/2] HID: hid-lg4ff: Add support for G27 LEDs 2012-04-20 10:05 ` Jiri Kosina @ 2012-04-21 12:41 ` Simon Wood 2012-04-21 12:41 ` [PATCH 2/2] HID: hid-lg4ff: Updated Comments Simon Wood 2012-04-23 18:55 ` [PATCH 1/2] HID: hid-lg4ff: Add support for G27 LEDs Jiri Kosina 0 siblings, 2 replies; 10+ messages in thread From: Simon Wood @ 2012-04-21 12:41 UTC (permalink / raw) To: linux-input Cc: linux-kernel, Jiri Kosina, Michael Bauer, Michal Maly, Simon Wood This patch adds supports for controlling the LED 'tachometer' on the G27 wheel, via the LED subsystem. The 5 LEDs are arranged from right (1=grn, 2=grn, 3=yel, 4=yel, 5=red) and 'mirrored' to the left (10 LEDs in total). Signed-off-by: Simon Wood <simon@mungewell.org> --- drivers/hid/hid-lg4ff.c | 158 ++++++++++++++++++++++++++++++++++++++++++++++- 1 files changed, 157 insertions(+), 1 deletions(-) diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index 32c173f..1e942a0 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -55,7 +55,10 @@ struct lg4ff_device_entry { __u16 range; __u16 min_range; __u16 max_range; - __u8 leds; +#ifdef CONFIG_LEDS_CLASS + __u8 led_state; + struct led_classdev *led[5]; +#endif struct list_head list; void (*set_range)(struct hid_device *hid, u16 range); }; @@ -335,6 +338,88 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at return count; } +#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); + + report->field[0]->value[0] = 0xf8; + report->field[0]->value[1] = 0x12; + report->field[0]->value[2] = leds; + report->field[0]->value[3] = 0x00; + report->field[0]->value[4] = 0x00; + report->field[0]->value[5] = 0x00; + report->field[0]->value[6] = 0x00; + usbhid_submit_report(hid, report, USB_DIR_OUT); +} + +static void lg4ff_led_set_brightness(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct device *dev = led_cdev->dev->parent; + struct hid_device *hid = container_of(dev, struct hid_device, dev); + struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hid); + struct lg4ff_device_entry *entry; + int i, state = 0; + + if (!drv_data) { + hid_err(hid, "Device data not found."); + return; + } + + entry = (struct lg4ff_device_entry *)drv_data->device_props; + + if (!entry) { + hid_err(hid, "Device properties not found."); + return; + } + + for (i = 0; i < 5; i++) { + if (led_cdev != entry->led[i]) + continue; + state = (entry->led_state >> i) & 1; + if (value == LED_OFF && state) { + entry->led_state &= ~(1 << i); + lg4ff_set_leds(hid, entry->led_state); + } else if (value != LED_OFF && !state) { + entry->led_state |= 1 << i; + lg4ff_set_leds(hid, entry->led_state); + } + break; + } +} + +static enum led_brightness lg4ff_led_get_brightness(struct led_classdev *led_cdev) +{ + struct device *dev = led_cdev->dev->parent; + struct hid_device *hid = container_of(dev, struct hid_device, dev); + struct lg_drv_data *drv_data = (struct lg_drv_data *)hid_get_drvdata(hid); + struct lg4ff_device_entry *entry; + int i, value = 0; + + if (!drv_data) { + hid_err(hid, "Device data not found."); + return LED_OFF; + } + + entry = (struct lg4ff_device_entry *)drv_data->device_props; + + if (!entry) { + hid_err(hid, "Device properties not found."); + return LED_OFF; + } + + for (i = 0; i < 5; i++) + if (led_cdev == entry->led[i]) { + value = (entry->led_state >> i) & 1; + break; + } + + return value ? LED_FULL : LED_OFF; +} +#endif + int lg4ff_init(struct hid_device *hid) { struct hid_input *hidinput = list_entry(hid->inputs.next, struct hid_input, list); @@ -453,6 +538,58 @@ int lg4ff_init(struct hid_device *hid) if (entry->set_range != NULL) entry->set_range(hid, entry->range); +#ifdef CONFIG_LEDS_CLASS + /* register led subsystem - G27 only */ + entry->led_state = 0; + for (j = 0; j < 5; j++) + entry->led[j] = NULL; + + if (lg4ff_devices[i].product_id == USB_DEVICE_ID_LOGITECH_G27_WHEEL) { + struct led_classdev *led; + size_t name_sz; + char *name; + + lg4ff_set_leds(hid, 0); + + name_sz = strlen(dev_name(&hid->dev)) + 8; + + for (j = 0; j < 5; j++) { + 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; + } + + name = (void *)(&led[1]); + snprintf(name, name_sz, "%s::RPM%d", dev_name(&hid->dev), j+1); + led->name = name; + led->brightness = 0; + led->max_brightness = 1; + led->brightness_get = lg4ff_led_get_brightness; + led->brightness_set = lg4ff_led_set_brightness; + + entry->led[j] = led; + error = led_classdev_register(&hid->dev, led); + + if (error) { + hid_err(hid, "failed to register LED %d. Aborting.\n", j); +err: + /* Deregister LEDs (if any) */ + for (j = 0; j < 5; j++) { + led = entry->led[j]; + entry->led[j] = NULL; + if (!led) + continue; + led_classdev_unregister(led); + kfree(led); + } + goto out; /* Let the driver continue without LEDs */ + } + } + } +#endif + +out: hid_info(hid, "Force feedback for Logitech Speed Force Wireless by Simon Wood <simon@mungewell.org>\n"); return 0; } @@ -474,6 +611,25 @@ int lg4ff_deinit(struct hid_device *hid) hid_err(hid, "Error while deinitializing device, no device properties data.\n"); return -1; } + +#ifdef CONFIG_LEDS_CLASS + { + int j; + struct led_classdev *led; + + /* Deregister LEDs (if any) */ + for (j = 0; j < 5; j++) { + + led = entry->led[j]; + entry->led[j] = NULL; + if (!led) + continue; + led_classdev_unregister(led); + kfree(led); + } + } +#endif + /* Deallocate memory */ kfree(entry); -- 1.7.4.1 ^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 2/2] HID: hid-lg4ff: Updated Comments 2012-04-21 12:41 ` Simon Wood @ 2012-04-21 12:41 ` Simon Wood 2012-04-23 18:55 ` [PATCH 1/2] HID: hid-lg4ff: Add support for G27 LEDs Jiri Kosina 1 sibling, 0 replies; 10+ messages in thread From: Simon Wood @ 2012-04-21 12:41 UTC (permalink / raw) To: linux-input Cc: linux-kernel, Jiri Kosina, Michael Bauer, Michal Maly, Simon Wood Updated comments to say that this driver now supports all Logitech gaming wheels, and not just the WiiWheel. Signed-off-by: Simon Wood <simon@mungewell.org> --- drivers/hid/hid-lg4ff.c | 7 ++++--- 1 files changed, 4 insertions(+), 3 deletions(-) diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index 1e942a0..24cf037 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -1,7 +1,8 @@ /* - * Force feedback support for Logitech Speed Force Wireless + * Force feedback support for Logitech Gaming Wheels * - * http://wiibrew.org/wiki/Logitech_USB_steering_wheel + * Including G27, G25, DFP, DFGT, FFEX, Momo, Momo2 & + * Speed Force Wireless (WiiWheel) * * Copyright (c) 2010 Simon Wood <simon@mungewell.org> */ @@ -590,7 +591,7 @@ err: #endif out: - hid_info(hid, "Force feedback for Logitech Speed Force Wireless by Simon Wood <simon@mungewell.org>\n"); + hid_info(hid, "Force feedback support for Logitech Gaming Wheels\n"); return 0; } -- 1.7.4.1 ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 1/2] HID: hid-lg4ff: Add support for G27 LEDs 2012-04-21 12:41 ` Simon Wood 2012-04-21 12:41 ` [PATCH 2/2] HID: hid-lg4ff: Updated Comments Simon Wood @ 2012-04-23 18:55 ` Jiri Kosina 1 sibling, 0 replies; 10+ messages in thread From: Jiri Kosina @ 2012-04-23 18:55 UTC (permalink / raw) To: Simon Wood; +Cc: linux-input, linux-kernel, Michael Bauer, Michal Maly On Sat, 21 Apr 2012, Simon Wood wrote: > This patch adds supports for controlling the LED 'tachometer' on > the G27 wheel, via the LED subsystem. > > The 5 LEDs are arranged from right (1=grn, 2=grn, 3=yel, 4=yel, 5=red) > and 'mirrored' to the left (10 LEDs in total). > > Signed-off-by: Simon Wood <simon@mungewell.org> Both patches applied, thanks. -- Jiri Kosina SUSE Labs ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2012-04-23 18:55 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
[not found] <1649210.pcO5IpzBEF@qosmio-x300>
2012-04-09 16:08 ` [PATCH] HID: hid-lg4ff: Add support for G27 LEDs Simon Wood
2012-04-13 12:59 ` Jiri Kosina
2012-04-18 7:03 ` [PATCH 1/2] " Simon Wood
2012-04-18 7:03 ` [PATCH 2/2] HID: hid-lg4ff: Updated Comments Simon Wood
2012-04-18 11:24 ` [PATCH 1/2] HID: hid-lg4ff: Add support for G27 LEDs Jiri Kosina
2012-04-18 14:58 ` simon
2012-04-20 10:05 ` Jiri Kosina
2012-04-21 12:41 ` Simon Wood
2012-04-21 12:41 ` [PATCH 2/2] HID: hid-lg4ff: Updated Comments Simon Wood
2012-04-23 18:55 ` [PATCH 1/2] HID: hid-lg4ff: Add support for G27 LEDs Jiri Kosina
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®