* [PATCH v2] leds: USB: Add support for MSI GT683R led panels @ 2014-06-05 21:29 Janne Kanniainen 2014-06-06 9:47 ` Johan Hovold 0 siblings, 1 reply; 81+ messages in thread From: Janne Kanniainen @ 2014-06-05 21:29 UTC (permalink / raw) To: cooloney, rpurdie; +Cc: linux-kernel, linux-leds, Janne Kanniainen This driver adds support for USB controlled led panels that exist in MSI GT683R laptop. Changes in v2: - sorted headers to alphabetic order - using devm_kzalloc - using BIT(n) - using usb_control_msg instead of usb_submit_urb - removing unneeded code Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> --- drivers/leds/Kconfig | 6 ++ drivers/leds/Makefile | 1 + drivers/leds/leds-gt683r.c | 158 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 165 insertions(+) create mode 100644 drivers/leds/leds-gt683r.c diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 6de9dfb..2cffa0c 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig @@ -487,6 +487,12 @@ config LEDS_BLINKM This option enables support for the BlinkM RGB LED connected through I2C. Say Y to enable support for the BlinkM LED. +config LEDS_GT683R + tristate "LED support for the MSI GT683R" + depends on LEDS_CLASS && USB + help + This option enables support for the MSI GT683R LEDS + comment "LED Triggers" source "drivers/leds/trigger/Kconfig" diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index 3cd76db..af5fb4e 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile @@ -54,6 +54,7 @@ obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o obj-$(CONFIG_LEDS_MAX8997) += leds-max8997.o obj-$(CONFIG_LEDS_LM355x) += leds-lm355x.o obj-$(CONFIG_LEDS_BLINKM) += leds-blinkm.o +obj-$(CONFIG_LEDS_GT683R) += leds-gt683r.o # LED SPI Drivers obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o diff --git a/drivers/leds/leds-gt683r.c b/drivers/leds/leds-gt683r.c new file mode 100644 index 0000000..5a204ea --- /dev/null +++ b/drivers/leds/leds-gt683r.c @@ -0,0 +1,158 @@ +/* + * MSI GT683R led driver + * + * Copyright (c) 2014 Janne Kanniainen <janne.kanniainen@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/kernel.h> +#include <linux/leds.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/usb.h> + +#define USB_DEVICE_ID_MSI_GT683R_LED_PANEL 0xff00 +#define USB_VENDOR_ID_MSI 0x1770 + +#define GT683R_LED_BACK BIT(0) +#define GT683R_LED_SIDE BIT(1) +#define GT683R_LED_FRONT BIT(2) +#define GT683R_LED_ALL (GT683R_LED_BACK | GT683R_LED_SIDE | GT683R_LED_FRONT) + +#define GT683R_LED_OFF 0 +#define GT683R_LED_AUDIO 2 +#define GT683R_LED_BREATHING 3 +#define GT683R_LED_NORMAL 5 + +struct gt683r_led { + struct usb_device *usb_dev; + struct usb_endpoint_descriptor *ep; + struct led_classdev led_dev; + struct mutex lock; + struct work_struct work; + enum led_brightness brightness; +}; + +static const struct usb_device_id gt683r_led_id[] = { + { USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, + { } +}; + +static const u64 gt683r_led_select_leds = 0x300201ULL; +static const u64 gt683r_led_select_type = 0x100200201ULL; + +static void gt683r_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct gt683r_led *led = + container_of(led_cdev, struct gt683r_led, led_dev); + + mutex_lock(&led->lock); + + led->brightness = brightness; + + schedule_work(&led->work); +} + +static int gt683r_led_snd_msg(struct gt683r_led *led, u64 msg) +{ + int result = usb_control_msg(led->usb_dev, + usb_sndctrlpipe(led->usb_dev, + led->ep->bEndpointAddress), + 0x09, 0x22, 0x0301, 0x0000, + &msg, sizeof(u64), USB_CTRL_SET_TIMEOUT); + if (result) + dev_err(&led->usb_dev->dev, + "Failed to send control message: %i\n", result); + + return result; +} + +static void gt683r_led_set(struct gt683r_led *led, char type) +{ + gt683r_led_snd_msg(led, gt683r_led_select_leds | + (GT683R_LED_ALL << 24)); + gt683r_led_snd_msg(led, gt683r_led_select_type | + (type << 24)); +} + +static void gt683r_led_work(struct work_struct *work) +{ + struct gt683r_led *led = + container_of(work, struct gt683r_led, work); + + if (led->brightness) + gt683r_led_set(led, GT683R_LED_NORMAL); + else + gt683r_led_set(led, GT683R_LED_OFF); + + mutex_unlock(&led->lock); +} + +static struct led_classdev gt683r_led_dev = { + .name = "gt683r-led", + .brightness_set = gt683r_brightness_set, + .max_brightness = 1, + .flags = LED_CORE_SUSPENDRESUME, +}; + +static int gt683r_led_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + int ret = 0; + struct gt683r_led *led = + devm_kzalloc(&intf->dev, sizeof(struct gt683r_led), GFP_KERNEL); + if (!led) + return -ENOMEM; + + led->usb_dev = interface_to_usbdev(intf); + usb_set_intfdata(intf, led); + + led->ep = &led->usb_dev->ep0.desc; + if (!usb_endpoint_xfer_control(led->ep) || + usb_endpoint_maxp(led->ep) != sizeof(u64)) + return -EINVAL; + + led->led_dev = gt683r_led_dev; + ret = led_classdev_register(&led->usb_dev->dev, &led->led_dev); + if (ret) { + dev_err(&led->usb_dev->dev, "Could not register led_classdev\n"); + return ret; + } + + mutex_init(&led->lock); + INIT_WORK(&led->work, gt683r_led_work); + + return 0; +} + +static void gt683r_led_disconnect(struct usb_interface *intf) +{ + struct gt683r_led *led = usb_get_intfdata(intf); + + led_classdev_unregister(&led->led_dev); + cancel_work_sync(&led->work); +} + +static struct usb_driver gt683r_led_driver = { + .probe = gt683r_led_probe, + .disconnect = gt683r_led_disconnect, + .name = "GT683R Led Driver", + .id_table = gt683r_led_id, +}; + +module_usb_driver(gt683r_led_driver); + +MODULE_AUTHOR("Janne Kanniainen"); +MODULE_DESCRIPTION("MSI GT683R led driver"); +MODULE_LICENSE("GPL"); -- 1.9.2 ^ permalink raw reply related [flat|nested] 81+ messages in thread
* Re: [PATCH v2] leds: USB: Add support for MSI GT683R led panels 2014-06-05 21:29 [PATCH v2] leds: USB: Add support for MSI GT683R led panels Janne Kanniainen @ 2014-06-06 9:47 ` Johan Hovold 2014-06-07 10:12 ` Janne Kanniainen 0 siblings, 1 reply; 81+ messages in thread From: Johan Hovold @ 2014-06-06 9:47 UTC (permalink / raw) To: Janne Kanniainen Cc: cooloney, rpurdie, linux-kernel, linux-leds, linux-usb, Jiri Kosina, linux-input, Johan Hovold [ +CC: Jiri, linux-input, linux-usb (again) ] First of all, please reply to the original thread and make sure to not drop people or lists from CC. On Fri, Jun 06, 2014 at 12:29:06AM +0300, Janne Kanniainen wrote: > This driver adds support for USB controlled led panels that exist in > MSI GT683R laptop. I had a change to look at bit closer at this today and it turns out this is a HID device and as such is already claimed by the HID driver. There was a quirk added for this particular VID/PID by commit 620ae90ed8ca ("HID: usbhid: quirk for MSI GX680R led panel") in order to avoid a 10s delay at boot due to missing report descriptors: https://bugzilla.redhat.com/show_bug.cgi?id=907221 http://www.spinics.net/lists/linux-usb/msg54756.html Since this is a HID device (and the control requests you're doing are Set_Report requests) you should probably implement this as a specific HID driver if there's no generic support you can use directly. I've added Jiri Kosina (and linux-input) who knows a lot more about the HID layer and how this is supposed to be implemented as CC. > Changes in v2: > - sorted headers to alphabetic order > - using devm_kzalloc > - using BIT(n) > - using usb_control_msg instead of usb_submit_urb > - removing unneeded code There are still some issues in the code below, but I'll only point out the more problematic ones for now. > Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> > --- > drivers/leds/Kconfig | 6 ++ > drivers/leds/Makefile | 1 + > drivers/leds/leds-gt683r.c | 158 +++++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 165 insertions(+) > create mode 100644 drivers/leds/leds-gt683r.c > > diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig > index 6de9dfb..2cffa0c 100644 > --- a/drivers/leds/Kconfig > +++ b/drivers/leds/Kconfig > @@ -487,6 +487,12 @@ config LEDS_BLINKM > This option enables support for the BlinkM RGB LED connected > through I2C. Say Y to enable support for the BlinkM LED. > > +config LEDS_GT683R > + tristate "LED support for the MSI GT683R" > + depends on LEDS_CLASS && USB > + help > + This option enables support for the MSI GT683R LEDS > + > comment "LED Triggers" > source "drivers/leds/trigger/Kconfig" > > diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile > index 3cd76db..af5fb4e 100644 > --- a/drivers/leds/Makefile > +++ b/drivers/leds/Makefile > @@ -54,6 +54,7 @@ obj-$(CONFIG_LEDS_ASIC3) += leds-asic3.o > obj-$(CONFIG_LEDS_MAX8997) += leds-max8997.o > obj-$(CONFIG_LEDS_LM355x) += leds-lm355x.o > obj-$(CONFIG_LEDS_BLINKM) += leds-blinkm.o > +obj-$(CONFIG_LEDS_GT683R) += leds-gt683r.o > > # LED SPI Drivers > obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o > diff --git a/drivers/leds/leds-gt683r.c b/drivers/leds/leds-gt683r.c > new file mode 100644 > index 0000000..5a204ea > --- /dev/null > +++ b/drivers/leds/leds-gt683r.c > @@ -0,0 +1,158 @@ > +/* > + * MSI GT683R led driver > + * > + * Copyright (c) 2014 Janne Kanniainen <janne.kanniainen@gmail.com> > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation; either version 2 of > + * the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + */ > + > +#include <linux/kernel.h> > +#include <linux/leds.h> > +#include <linux/module.h> > +#include <linux/slab.h> > +#include <linux/usb.h> > + > +#define USB_DEVICE_ID_MSI_GT683R_LED_PANEL 0xff00 > +#define USB_VENDOR_ID_MSI 0x1770 > + > +#define GT683R_LED_BACK BIT(0) > +#define GT683R_LED_SIDE BIT(1) > +#define GT683R_LED_FRONT BIT(2) > +#define GT683R_LED_ALL (GT683R_LED_BACK | GT683R_LED_SIDE | GT683R_LED_FRONT) > + > +#define GT683R_LED_OFF 0 > +#define GT683R_LED_AUDIO 2 > +#define GT683R_LED_BREATHING 3 > +#define GT683R_LED_NORMAL 5 > + > +struct gt683r_led { > + struct usb_device *usb_dev; > + struct usb_endpoint_descriptor *ep; > + struct led_classdev led_dev; > + struct mutex lock; > + struct work_struct work; > + enum led_brightness brightness; > +}; > + > +static const struct usb_device_id gt683r_led_id[] = { > + { USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, > + { } > +}; > + > +static const u64 gt683r_led_select_leds = 0x300201ULL; > +static const u64 gt683r_led_select_type = 0x100200201ULL; No, you'd still want to use byte arrays for this in order to handle endianess (if you are to keep these at all). For arrays you can use the ARRAY_SIZE() macro if that was the reason for this change. I should have mentioned that when I pointed out that you cannot use strlen(). Where did you get these (HID report) values from by the way? > + > +static void gt683r_brightness_set(struct led_classdev *led_cdev, > + enum led_brightness brightness) > +{ > + struct gt683r_led *led = > + container_of(led_cdev, struct gt683r_led, led_dev); > + > + mutex_lock(&led->lock); You cannot grab a mutex here since this function can be called from interrupt context (if I remember correctly). Either way, you shouldn't be holding the lock until the work task has finished... > + > + led->brightness = brightness; > + > + schedule_work(&led->work); > +} > + > +static int gt683r_led_snd_msg(struct gt683r_led *led, u64 msg) > +{ > + int result = usb_control_msg(led->usb_dev, > + usb_sndctrlpipe(led->usb_dev, > + led->ep->bEndpointAddress), No need to store the endpoint in the led struct as the address of endpoint 0 is 0. > + 0x09, 0x22, 0x0301, 0x0000, > + &msg, sizeof(u64), USB_CTRL_SET_TIMEOUT); You cannot use a stack allocated buffer (msg) for the data transfer as some platforms can't do DMA from the stack. > + if (result) > + dev_err(&led->usb_dev->dev, > + "Failed to send control message: %i\n", result); > + > + return result; > +} > + > +static void gt683r_led_set(struct gt683r_led *led, char type) > +{ > + gt683r_led_snd_msg(led, gt683r_led_select_leds | > + (GT683R_LED_ALL << 24)); > + gt683r_led_snd_msg(led, gt683r_led_select_type | > + (type << 24)); > +} > + > +static void gt683r_led_work(struct work_struct *work) > +{ > + struct gt683r_led *led = > + container_of(work, struct gt683r_led, work); > + > + if (led->brightness) > + gt683r_led_set(led, GT683R_LED_NORMAL); > + else > + gt683r_led_set(led, GT683R_LED_OFF); > + > + mutex_unlock(&led->lock); > +} > + > +static struct led_classdev gt683r_led_dev = { > + .name = "gt683r-led", > + .brightness_set = gt683r_brightness_set, > + .max_brightness = 1, > + .flags = LED_CORE_SUSPENDRESUME, > +}; > + > +static int gt683r_led_probe(struct usb_interface *intf, > + const struct usb_device_id *id) > +{ > + int ret = 0; > + struct gt683r_led *led = > + devm_kzalloc(&intf->dev, sizeof(struct gt683r_led), GFP_KERNEL); Again, please split definition and allocation. > + if (!led) > + return -ENOMEM; > + > + led->usb_dev = interface_to_usbdev(intf); > + usb_set_intfdata(intf, led); > + > + led->ep = &led->usb_dev->ep0.desc; > + if (!usb_endpoint_xfer_control(led->ep) || > + usb_endpoint_maxp(led->ep) != sizeof(u64)) > + return -EINVAL; EP0 is a control endpoint, and you probably don't need the max-packet-size test either. > + > + led->led_dev = gt683r_led_dev; > + ret = led_classdev_register(&led->usb_dev->dev, &led->led_dev); > + if (ret) { > + dev_err(&led->usb_dev->dev, "Could not register led_classdev\n"); > + return ret; > + } > + > + mutex_init(&led->lock); > + INIT_WORK(&led->work, gt683r_led_work); > + > + return 0; > +} > + > +static void gt683r_led_disconnect(struct usb_interface *intf) > +{ > + struct gt683r_led *led = usb_get_intfdata(intf); > + > + led_classdev_unregister(&led->led_dev); > + cancel_work_sync(&led->work); > +} > + > +static struct usb_driver gt683r_led_driver = { > + .probe = gt683r_led_probe, > + .disconnect = gt683r_led_disconnect, > + .name = "GT683R Led Driver", > + .id_table = gt683r_led_id, > +}; > + > +module_usb_driver(gt683r_led_driver); > + > +MODULE_AUTHOR("Janne Kanniainen"); > +MODULE_DESCRIPTION("MSI GT683R led driver"); > +MODULE_LICENSE("GPL"); Johan ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v2] leds: USB: Add support for MSI GT683R led panels 2014-06-06 9:47 ` Johan Hovold @ 2014-06-07 10:12 ` Janne Kanniainen 2014-06-09 11:42 ` Johan Hovold 0 siblings, 1 reply; 81+ messages in thread From: Janne Kanniainen @ 2014-06-07 10:12 UTC (permalink / raw) To: Johan Hovold Cc: Bryan Wu, rpurdie, linux-kernel, linux-leds, linux-usb, Jiri Kosina, linux-input > First of all, please reply to the original thread and make sure to not > drop people or lists from CC. Sorry this is my first patch and i didn't know that. Now I know. > For arrays you can use the ARRAY_SIZE() macro if that was the reason for > this change. I should have mentioned that when I pointed out that you > cannot use strlen(). That wasn't the reason. I just thought it might be better to use u64 than char[8]. I know why I can't use strlen and that was only careless error. And there was lot of them :( I will be more careful next time. > Where did you get these (HID report) values from by the way? I got them by reverse engineering. >> + >> +static void gt683r_brightness_set(struct led_classdev *led_cdev, >> + enum led_brightness brightness) >> +{ >> + struct gt683r_led *led = >> + container_of(led_cdev, struct gt683r_led, led_dev); >> + >> + mutex_lock(&led->lock); > > You cannot grab a mutex here since this function can be called from > interrupt context (if I remember correctly). Either way, you shouldn't > be holding the lock until the work task has finished... I thought use asked me to put some lock there: >> + >> +static void gt683r_brightness_set(struct led_classdev *led_cdev, >> + enum led_brightness brightness) >> +{ >> + struct gt683r_led *led = >> + container_of(led_cdev, struct gt683r_led, led_dev); >> + >> + led->brightness = brightness; > > Missing locking? Janne ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v2] leds: USB: Add support for MSI GT683R led panels 2014-06-07 10:12 ` Janne Kanniainen @ 2014-06-09 11:42 ` Johan Hovold 2014-06-10 21:10 ` Janne Kanniainen 0 siblings, 1 reply; 81+ messages in thread From: Johan Hovold @ 2014-06-09 11:42 UTC (permalink / raw) To: Janne Kanniainen Cc: Johan Hovold, Bryan Wu, rpurdie, linux-kernel, linux-leds, linux-usb, Jiri Kosina, linux-input On Sat, Jun 07, 2014 at 01:12:39PM +0300, Janne Kanniainen wrote: > > First of all, please reply to the original thread and make sure to not > > drop people or lists from CC. > > Sorry this is my first patch and i didn't know that. Now I know. > > > For arrays you can use the ARRAY_SIZE() macro if that was the reason for > > this change. I should have mentioned that when I pointed out that you > > cannot use strlen(). > > That wasn't the reason. I just thought it might be better to use u64 > than char[8]. I know why I can't use strlen and that was only careless > error. And there was lot of them :( I will be more careful next time. No problem, that's what review is for, and the second version was much cleaner even if there were still a few issues (some hard to know about, such as the DMA from stack issue, which is also a very common error). > > Where did you get these (HID report) values from by the way? > > I got them by reverse engineering. Traffic sniffing? > >> + > >> +static void gt683r_brightness_set(struct led_classdev *led_cdev, > >> + enum led_brightness brightness) > >> +{ > >> + struct gt683r_led *led = > >> + container_of(led_cdev, struct gt683r_led, led_dev); > >> + > >> + mutex_lock(&led->lock); > > > > You cannot grab a mutex here since this function can be called from > > interrupt context (if I remember correctly). Either way, you shouldn't > > be holding the lock until the work task has finished... > > I thought use asked me to put some lock there: > > >> + > >> +static void gt683r_brightness_set(struct led_classdev *led_cdev, > >> + enum led_brightness brightness) > >> +{ > >> + struct gt683r_led *led = > >> + container_of(led_cdev, struct gt683r_led, led_dev); > >> + > >> + led->brightness = brightness; > > > > Missing locking? I asked if locking was missing and did not specify how you should be adding it. ;) In fact, it seems you can get away with not adding any locking here. Just do the (mutex) locking in gt683r_led_set (or gt683r_led_work). Johan ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v2] leds: USB: Add support for MSI GT683R led panels 2014-06-09 11:42 ` Johan Hovold @ 2014-06-10 21:10 ` Janne Kanniainen 2014-06-10 21:21 ` [PATCH v3] leds: USB: HID: " Janne Kanniainen 0 siblings, 1 reply; 81+ messages in thread From: Janne Kanniainen @ 2014-06-10 21:10 UTC (permalink / raw) To: Johan Hovold Cc: Bryan Wu, rpurdie, linux-kernel, linux-leds, linux-usb, Jiri Kosina, linux-input >> > Where did you get these (HID report) values from by the way? >> >> I got them by reverse engineering. > > Traffic sniffing? > Yes. > In fact, it seems you can get away with not adding any locking here. > Just do the (mutex) locking in gt683r_led_set (or gt683r_led_work). Ok I will fix it. Janne ^ permalink raw reply [flat|nested] 81+ messages in thread
* [PATCH v3] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-10 21:10 ` Janne Kanniainen @ 2014-06-10 21:21 ` Janne Kanniainen 2014-06-11 11:25 ` Jiri Kosina [not found] ` <1402435299-16410-1-git-send-email-janne.kanniainen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 0 siblings, 2 replies; 81+ messages in thread From: Janne Kanniainen @ 2014-06-10 21:21 UTC (permalink / raw) To: jkosina Cc: cooloney, linux-kernel, linux-leds, linux-usb, linux-input, johan, Janne Kanniainen This driver adds support for USB controlled led panels that exists in MSI GT683R laptop Changes in v2: - sorted headers to alphabetic order - using devm_kzalloc - using BIT(n) - using usb_control_msg instead of usb_submit_urb - removing unneeded code Changes in v3: - implemented as HID device - some cleanups and bug fixes Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> --- drivers/hid/Kconfig | 6 ++ drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-gt683r.c | 186 ++++++++++++++++++++++++++++++++++++++++ drivers/hid/hid-ids.h | 1 + drivers/hid/usbhid/hid-quirks.c | 1 + 6 files changed, 196 insertions(+) create mode 100644 drivers/hid/hid-gt683r.c diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 7af9d0b..6ecc527 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -210,6 +210,12 @@ config DRAGONRISE_FF Say Y here if you want to enable force feedback support for DragonRise Inc. game controllers. +config HID_GT683R + tristate "LED support for the MSI GT683R" + depends on LEDS_CLASS && USB_HID + ---help--- + Say Y here if you want to enable support for the MSI GT683R LEDS + config HID_EMS_FF tristate "EMS Production Inc. force feedback support" depends on HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index fc712dd..111304e 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -44,6 +44,7 @@ obj-$(CONFIG_HID_CHICONY) += hid-chicony.o obj-$(CONFIG_HID_CP2112) += hid-cp2112.o obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o obj-$(CONFIG_HID_DRAGONRISE) += hid-dr.o +obj-$(CONFIG_HID_GT683R) += hid-gt683r.o obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o obj-$(CONFIG_HID_ELECOM) += hid-elecom.o obj-$(CONFIG_HID_ELO) += hid-elo.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index da52279..ec88fdb 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1827,6 +1827,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, { 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) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2) }, diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c new file mode 100644 index 0000000..4baaa36 --- /dev/null +++ b/drivers/hid/hid-gt683r.c @@ -0,0 +1,186 @@ +/* + * MSI GT683R led driver + * + * Copyright (c) 2014 Janne Kanniainen <janne.kanniainen@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/hid.h> +#include <linux/kernel.h> +#include <linux/leds.h> +#include <linux/module.h> + +#include "hid-ids.h" + +#define GT683R_LED_BACK BIT(0) +#define GT683R_LED_SIDE BIT(1) +#define GT683R_LED_FRONT BIT(2) +#define GT683R_LED_ALL (GT683R_LED_BACK | GT683R_LED_SIDE | GT683R_LED_FRONT) + +#define GT683R_LED_OFF 0 +#define GT683R_LED_AUDIO 2 +#define GT683R_LED_BREATHING 3 +#define GT683R_LED_NORMAL 5 + +#define GT683R_BUFFER_SIZE 8 + +struct gt683r_led { + struct hid_device *hdev; + struct led_classdev led_dev; + struct mutex lock; + struct work_struct work; + enum led_brightness brightness; +}; + +static const struct hid_device_id gt683r_led_id[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, + { } +}; + +static const char gt683r_led_select_leds[GT683R_BUFFER_SIZE] = { 0x01, 0x02, 0x30, 0x00, + 0x00, 0x00, 0x00, 0x00 }; +static const char gt683r_led_select_type[GT683R_BUFFER_SIZE] = { 0x01, 0x02, 0x20, 0x00, + 0x01, 0x00, 0x00, 0x00 }; + +static void gt683r_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + struct gt683r_led *led = + container_of(led_cdev, struct gt683r_led, led_dev); + + led->brightness = brightness; + + schedule_work(&led->work); +} + +static int gt683r_led_snd_msg(struct gt683r_led *led, char *msg) +{ + int ret; + + ret = hid_hw_raw_request(led->hdev, 0x01, msg, GT683R_BUFFER_SIZE, + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); + if (ret < 0) { + hid_err(led->hdev, + "failed to send set report request: %i\n", ret); + return ret; + } + + return 0; +} + +static void gt683r_led_set(struct gt683r_led *led, char type) +{ + char *buffer; + + buffer = kmalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); + if (!buffer) { + hid_err(led->hdev, "can\'t allocate buffer\n"); + return; + } + + memcpy(buffer, gt683r_led_select_leds, GT683R_BUFFER_SIZE); + buffer[3] = GT683R_LED_ALL; + gt683r_led_snd_msg(led, buffer); + + memcpy(buffer, gt683r_led_select_type, GT683R_BUFFER_SIZE); + buffer[3] = type; + gt683r_led_snd_msg(led, buffer); + + kfree(buffer); +} + +static void gt683r_led_work(struct work_struct *work) +{ + struct gt683r_led *led = + container_of(work, struct gt683r_led, work); + + mutex_lock(&led->lock); + + if (led->brightness) + gt683r_led_set(led, GT683R_LED_NORMAL); + else + gt683r_led_set(led, GT683R_LED_OFF); + + mutex_unlock(&led->lock); +} + +static struct led_classdev gt683r_led_dev = { + .name = "gt683r-led", + .brightness_set = gt683r_brightness_set, + .max_brightness = 1, + .flags = LED_CORE_SUSPENDRESUME, +}; + +static int gt683r_led_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + int ret; + struct gt683r_led *led; + + led = devm_kzalloc(&hdev->dev, sizeof(struct gt683r_led), GFP_KERNEL); + if (!led) + return -ENOMEM; + + led->hdev = hdev; + hid_set_drvdata(hdev, led); + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "hid parsing failed\n"); + goto fail; + } + + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); + if (ret) { + hid_err(hdev, "hw start failed\n"); + goto fail; + } + + led->led_dev = gt683r_led_dev; + ret = led_classdev_register(&hdev->dev, &led->led_dev); + if (ret) { + hid_err(hdev, "could not register led device\n"); + goto stop; + } + + mutex_init(&led->lock); + INIT_WORK(&led->work, gt683r_led_work); + + return 0; +stop: + hid_hw_stop(hdev); +fail: + return ret; +} + +static void gt683r_led_remove(struct hid_device *hdev) +{ + struct gt683r_led *led = hid_get_drvdata(hdev); + + led_classdev_unregister(&led->led_dev); + cancel_work_sync(&led->work); + hid_hw_stop(hdev); +} + +static struct hid_driver gt683r_led_driver = { + .probe = gt683r_led_probe, + .remove = gt683r_led_remove, + .name = "gt683r_led", + .id_table = gt683r_led_id, +}; + +module_hid_driver(gt683r_led_driver); + +MODULE_AUTHOR("Janne Kanniainen"); +MODULE_DESCRIPTION("MSI GT683R led driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 34bb220..e2097f7 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -641,6 +641,7 @@ #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 #define USB_VENDOR_ID_MSI 0x1770 +#define USB_DEVICE_ID_MSI_GT683R_LED_PANEL 0xff00 #define USB_DEVICE_ID_MSI_GX680R_LED_PANEL 0xff00 #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 8e4ddb3..927e7be 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -73,6 +73,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, + { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_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 }, -- 1.9.2 ^ permalink raw reply related [flat|nested] 81+ messages in thread
* Re: [PATCH v3] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-10 21:21 ` [PATCH v3] leds: USB: HID: " Janne Kanniainen @ 2014-06-11 11:25 ` Jiri Kosina 2014-06-11 14:06 ` Johan Hovold [not found] ` <1402435299-16410-1-git-send-email-janne.kanniainen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 1 sibling, 1 reply; 81+ messages in thread From: Jiri Kosina @ 2014-06-11 11:25 UTC (permalink / raw) To: Janne Kanniainen Cc: cooloney, linux-kernel, linux-leds, linux-usb, linux-input, johan On Wed, 11 Jun 2014, Janne Kanniainen wrote: > This driver adds support for USB controlled led panels that exists in MSI GT683R laptop > > Changes in v2: > - sorted headers to alphabetic order > - using devm_kzalloc > - using BIT(n) > - using usb_control_msg instead of usb_submit_urb > - removing unneeded code > > Changes in v3: > - implemented as HID device > - some cleanups and bug fixes > > Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> Thanks for the driver. Johan, as you did a very good job reviewing this before I managed to get to it, I'd be glad to put your Reviewed-by: to the commit before commiting it, if you are going to provide it. Thanks, -- Jiri Kosina SUSE Labs ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v3] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-11 11:25 ` Jiri Kosina @ 2014-06-11 14:06 ` Johan Hovold 0 siblings, 0 replies; 81+ messages in thread From: Johan Hovold @ 2014-06-11 14:06 UTC (permalink / raw) To: Jiri Kosina Cc: Janne Kanniainen, cooloney, linux-kernel, linux-leds, linux-usb, linux-input, johan On Wed, Jun 11, 2014 at 01:25:49PM +0200, Jiri Kosina wrote: > On Wed, 11 Jun 2014, Janne Kanniainen wrote: > > > This driver adds support for USB controlled led panels that exists in MSI GT683R laptop > > > > Changes in v2: > > - sorted headers to alphabetic order > > - using devm_kzalloc > > - using BIT(n) > > - using usb_control_msg instead of usb_submit_urb > > - removing unneeded code > > > > Changes in v3: > > - implemented as HID device > > - some cleanups and bug fixes > > > > Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> > > Thanks for the driver. Johan, as you did a very good job reviewing this > before I managed to get to it, I'd be glad to put your Reviewed-by: to the > commit before commiting it, if you are going to provide it. I had a few more comments to v3, but I'll make sure to reply with a Reviewed-by-tag before you apply. Thanks, Johan ^ permalink raw reply [flat|nested] 81+ messages in thread
[parent not found: <1402435299-16410-1-git-send-email-janne.kanniainen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>]
* Re: [PATCH v3] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-10 21:21 ` [PATCH v3] leds: USB: HID: " Janne Kanniainen @ 2014-06-11 14:05 ` Johan Hovold [not found] ` <1402435299-16410-1-git-send-email-janne.kanniainen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 1 sibling, 0 replies; 81+ messages in thread From: Johan Hovold @ 2014-06-11 14:05 UTC (permalink / raw) To: Janne Kanniainen Cc: jkosina-AlSwsSmVLrQ, cooloney-Re5JQEeQqe8AvxtiuMwx3w, linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-leds-u79uwXL29TY76Z2rM5mHXA, linux-usb-u79uwXL29TY76Z2rM5mHXA, linux-input-u79uwXL29TY76Z2rM5mHXA, johan-DgEjT+Ai2ygdnm+yROfE0A On Wed, Jun 11, 2014 at 12:21:39AM +0300, Janne Kanniainen wrote: > This driver adds support for USB controlled led panels that exists in MSI GT683R laptop Can you break this line by 72 columns or so as well? > Changes in v2: > - sorted headers to alphabetic order > - using devm_kzalloc > - using BIT(n) > - using usb_control_msg instead of usb_submit_urb > - removing unneeded code > > Changes in v3: > - implemented as HID device > - some cleanups and bug fixes Thanks for the update, Janne. It looks really good now. Please put the changelog entries after the cut-off line below as it's not really needed in the git logs. You should also always run your patches through scripts/checkpatch.pl before submitting. It currently reports 8 warnings of which you should fix all but possible the ones about device id entries exceeding 80 chars (which is usually considered acceptable). A few more comments follow below. > Signed-off-by: Janne Kanniainen <janne.kanniainen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > --- > drivers/hid/Kconfig | 6 ++ > drivers/hid/Makefile | 1 + > drivers/hid/hid-core.c | 1 + > drivers/hid/hid-gt683r.c | 186 ++++++++++++++++++++++++++++++++++++++++ > drivers/hid/hid-ids.h | 1 + > drivers/hid/usbhid/hid-quirks.c | 1 + > 6 files changed, 196 insertions(+) > create mode 100644 drivers/hid/hid-gt683r.c > > diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig > index 7af9d0b..6ecc527 100644 > --- a/drivers/hid/Kconfig > +++ b/drivers/hid/Kconfig > @@ -210,6 +210,12 @@ config DRAGONRISE_FF > Say Y here if you want to enable force feedback support for DragonRise Inc. > game controllers. > > +config HID_GT683R > + tristate "LED support for the MSI GT683R" How about rephrasing this description as "MSI GT683R LED support" as this should make entry easier to find in Kconfig. As there appears to be more models that could use this driver (and uses the same PID) perhaps you should use "MSI GT68xR" or similar depending on what models there are. We now of at least GX680R (having the same PID, at least). There's no need to rename the driver and every function or variable below though (i.e. a gt683r prefix is still perfectly fine). > + depends on LEDS_CLASS && USB_HID > + ---help--- > + Say Y here if you want to enable support for the MSI GT683R LEDS > + checkpatch.pl suggests adding descriptive paragraph here. > config HID_EMS_FF > tristate "EMS Production Inc. force feedback support" > depends on HID > diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile > index fc712dd..111304e 100644 > --- a/drivers/hid/Makefile > +++ b/drivers/hid/Makefile > @@ -44,6 +44,7 @@ obj-$(CONFIG_HID_CHICONY) += hid-chicony.o > obj-$(CONFIG_HID_CP2112) += hid-cp2112.o > obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o > obj-$(CONFIG_HID_DRAGONRISE) += hid-dr.o > +obj-$(CONFIG_HID_GT683R) += hid-gt683r.o Keep the entries sorted? > obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o > obj-$(CONFIG_HID_ELECOM) += hid-elecom.o > obj-$(CONFIG_HID_ELO) += hid-elo.o > diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c > index da52279..ec88fdb 100644 > --- a/drivers/hid/hid-core.c > +++ b/drivers/hid/hid-core.c > @@ -1827,6 +1827,7 @@ static const struct hid_device_id hid_have_special_driver[] = { > { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, > { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, > { 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) }, > { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) }, > { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2) }, > diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c > new file mode 100644 > index 0000000..4baaa36 > --- /dev/null > +++ b/drivers/hid/hid-gt683r.c > @@ -0,0 +1,186 @@ > +/* > + * MSI GT683R led driver > + * > + * Copyright (c) 2014 Janne Kanniainen <janne.kanniainen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation; either version 2 of > + * the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + */ > + > +#include <linux/hid.h> > +#include <linux/kernel.h> > +#include <linux/leds.h> > +#include <linux/module.h> > + > +#include "hid-ids.h" > + > +#define GT683R_LED_BACK BIT(0) > +#define GT683R_LED_SIDE BIT(1) > +#define GT683R_LED_FRONT BIT(2) > +#define GT683R_LED_ALL (GT683R_LED_BACK | GT683R_LED_SIDE | GT683R_LED_FRONT) Since it seems you are able to control these three LEDs independently, shouldn't you consider registering three LEDs? > + > +#define GT683R_LED_OFF 0 > +#define GT683R_LED_AUDIO 2 > +#define GT683R_LED_BREATHING 3 > +#define GT683R_LED_NORMAL 5 What are AUDIO and BREATHING for? Perhaps add a descriptive comment? > + > +#define GT683R_BUFFER_SIZE 8 > + > +struct gt683r_led { > + struct hid_device *hdev; > + struct led_classdev led_dev; > + struct mutex lock; > + struct work_struct work; > + enum led_brightness brightness; > +}; > + > +static const struct hid_device_id gt683r_led_id[] = { > + { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, > + { } > +}; > + > +static const char gt683r_led_select_leds[GT683R_BUFFER_SIZE] = { 0x01, 0x02, 0x30, 0x00, > + 0x00, 0x00, 0x00, 0x00 }; > +static const char gt683r_led_select_type[GT683R_BUFFER_SIZE] = { 0x01, 0x02, 0x20, 0x00, > + 0x01, 0x00, 0x00, 0x00 }; 80 char limit. Perhaps move these to gt683r_led_set, which is the only place where they are used? > + > +static void gt683r_brightness_set(struct led_classdev *led_cdev, > + enum led_brightness brightness) > +{ > + struct gt683r_led *led = > + container_of(led_cdev, struct gt683r_led, led_dev); > + > + led->brightness = brightness; > + > + schedule_work(&led->work); > +} > + > +static int gt683r_led_snd_msg(struct gt683r_led *led, char *msg) > +{ > + int ret; > + > + ret = hid_hw_raw_request(led->hdev, 0x01, msg, GT683R_BUFFER_SIZE, > + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); > + if (ret < 0) { > + hid_err(led->hdev, > + "failed to send set report request: %i\n", ret); > + return ret; > + } > + > + return 0; > +} > + > +static void gt683r_led_set(struct gt683r_led *led, char type) > +{ > + char *buffer; > + > + buffer = kmalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); > + if (!buffer) { > + hid_err(led->hdev, "can\'t allocate buffer\n"); No need to log OOM messages as this would already have been taken care of by the memory subsystem. > + return; > + } > + > + memcpy(buffer, gt683r_led_select_leds, GT683R_BUFFER_SIZE); > + buffer[3] = GT683R_LED_ALL; > + gt683r_led_snd_msg(led, buffer); Error handling? Perhaps there's no point in sending the "type" report if select_leds failed? > + > + memcpy(buffer, gt683r_led_select_type, GT683R_BUFFER_SIZE); > + buffer[3] = type; > + gt683r_led_snd_msg(led, buffer); You don't have to change this if you don't want, but wouldn't "set_state" be more descriptive than "select_type"? > + > + kfree(buffer); > +} > + > +static void gt683r_led_work(struct work_struct *work) > +{ > + struct gt683r_led *led = > + container_of(work, struct gt683r_led, work); > + > + mutex_lock(&led->lock); > + > + if (led->brightness) > + gt683r_led_set(led, GT683R_LED_NORMAL); > + else > + gt683r_led_set(led, GT683R_LED_OFF); > + > + mutex_unlock(&led->lock); > +} > + > +static struct led_classdev gt683r_led_dev = { > + .name = "gt683r-led", > + .brightness_set = gt683r_brightness_set, > + .max_brightness = 1, > + .flags = LED_CORE_SUSPENDRESUME, > +}; > + > +static int gt683r_led_probe(struct hid_device *hdev, > + const struct hid_device_id *id) > +{ > + int ret; > + struct gt683r_led *led; > + > + led = devm_kzalloc(&hdev->dev, sizeof(struct gt683r_led), GFP_KERNEL); > + if (!led) > + return -ENOMEM; > + > + led->hdev = hdev; > + hid_set_drvdata(hdev, led); > + > + ret = hid_parse(hdev); > + if (ret) { > + hid_err(hdev, "hid parsing failed\n"); > + goto fail; > + } > + > + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); > + if (ret) { > + hid_err(hdev, "hw start failed\n"); > + goto fail; > + } > + > + led->led_dev = gt683r_led_dev; > + ret = led_classdev_register(&hdev->dev, &led->led_dev); > + if (ret) { > + hid_err(hdev, "could not register led device\n"); > + goto stop; > + } > + > + mutex_init(&led->lock); > + INIT_WORK(&led->work, gt683r_led_work); > + > + return 0; > +stop: > + hid_hw_stop(hdev); > +fail: > + return ret; > +} > + > +static void gt683r_led_remove(struct hid_device *hdev) > +{ > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + led_classdev_unregister(&led->led_dev); > + cancel_work_sync(&led->work); > + hid_hw_stop(hdev); > +} > + > +static struct hid_driver gt683r_led_driver = { > + .probe = gt683r_led_probe, > + .remove = gt683r_led_remove, > + .name = "gt683r_led", > + .id_table = gt683r_led_id, > +}; > + > +module_hid_driver(gt683r_led_driver); > + > +MODULE_AUTHOR("Janne Kanniainen"); > +MODULE_DESCRIPTION("MSI GT683R led driver"); > +MODULE_LICENSE("GPL"); > diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h > index 34bb220..e2097f7 100644 > --- a/drivers/hid/hid-ids.h > +++ b/drivers/hid/hid-ids.h > @@ -641,6 +641,7 @@ > #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 > > #define USB_VENDOR_ID_MSI 0x1770 > +#define USB_DEVICE_ID_MSI_GT683R_LED_PANEL 0xff00 > #define USB_DEVICE_ID_MSI_GX680R_LED_PANEL 0xff00 As these device have the same PID you shouldn't be adding a duplicate entry to the blacklist_table below. Perhaps you can rename the original one as GC68XR instead (or just remove the old one). > > #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400 > diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c > index 8e4ddb3..927e7be 100644 > --- a/drivers/hid/usbhid/hid-quirks.c > +++ b/drivers/hid/usbhid/hid-quirks.c > @@ -73,6 +73,7 @@ static const struct hid_blacklist { > { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, > { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, > { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, > + { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS }, > { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_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 }, Thanks, Johan -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v3] leds: USB: HID: Add support for MSI GT683R led panels @ 2014-06-11 14:05 ` Johan Hovold 0 siblings, 0 replies; 81+ messages in thread From: Johan Hovold @ 2014-06-11 14:05 UTC (permalink / raw) To: Janne Kanniainen Cc: jkosina, cooloney, linux-kernel, linux-leds, linux-usb, linux-input, johan On Wed, Jun 11, 2014 at 12:21:39AM +0300, Janne Kanniainen wrote: > This driver adds support for USB controlled led panels that exists in MSI GT683R laptop Can you break this line by 72 columns or so as well? > Changes in v2: > - sorted headers to alphabetic order > - using devm_kzalloc > - using BIT(n) > - using usb_control_msg instead of usb_submit_urb > - removing unneeded code > > Changes in v3: > - implemented as HID device > - some cleanups and bug fixes Thanks for the update, Janne. It looks really good now. Please put the changelog entries after the cut-off line below as it's not really needed in the git logs. You should also always run your patches through scripts/checkpatch.pl before submitting. It currently reports 8 warnings of which you should fix all but possible the ones about device id entries exceeding 80 chars (which is usually considered acceptable). A few more comments follow below. > Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> > --- > drivers/hid/Kconfig | 6 ++ > drivers/hid/Makefile | 1 + > drivers/hid/hid-core.c | 1 + > drivers/hid/hid-gt683r.c | 186 ++++++++++++++++++++++++++++++++++++++++ > drivers/hid/hid-ids.h | 1 + > drivers/hid/usbhid/hid-quirks.c | 1 + > 6 files changed, 196 insertions(+) > create mode 100644 drivers/hid/hid-gt683r.c > > diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig > index 7af9d0b..6ecc527 100644 > --- a/drivers/hid/Kconfig > +++ b/drivers/hid/Kconfig > @@ -210,6 +210,12 @@ config DRAGONRISE_FF > Say Y here if you want to enable force feedback support for DragonRise Inc. > game controllers. > > +config HID_GT683R > + tristate "LED support for the MSI GT683R" How about rephrasing this description as "MSI GT683R LED support" as this should make entry easier to find in Kconfig. As there appears to be more models that could use this driver (and uses the same PID) perhaps you should use "MSI GT68xR" or similar depending on what models there are. We now of at least GX680R (having the same PID, at least). There's no need to rename the driver and every function or variable below though (i.e. a gt683r prefix is still perfectly fine). > + depends on LEDS_CLASS && USB_HID > + ---help--- > + Say Y here if you want to enable support for the MSI GT683R LEDS > + checkpatch.pl suggests adding descriptive paragraph here. > config HID_EMS_FF > tristate "EMS Production Inc. force feedback support" > depends on HID > diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile > index fc712dd..111304e 100644 > --- a/drivers/hid/Makefile > +++ b/drivers/hid/Makefile > @@ -44,6 +44,7 @@ obj-$(CONFIG_HID_CHICONY) += hid-chicony.o > obj-$(CONFIG_HID_CP2112) += hid-cp2112.o > obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o > obj-$(CONFIG_HID_DRAGONRISE) += hid-dr.o > +obj-$(CONFIG_HID_GT683R) += hid-gt683r.o Keep the entries sorted? > obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o > obj-$(CONFIG_HID_ELECOM) += hid-elecom.o > obj-$(CONFIG_HID_ELO) += hid-elo.o > diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c > index da52279..ec88fdb 100644 > --- a/drivers/hid/hid-core.c > +++ b/drivers/hid/hid-core.c > @@ -1827,6 +1827,7 @@ static const struct hid_device_id hid_have_special_driver[] = { > { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, > { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, > { 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) }, > { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) }, > { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2) }, > diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c > new file mode 100644 > index 0000000..4baaa36 > --- /dev/null > +++ b/drivers/hid/hid-gt683r.c > @@ -0,0 +1,186 @@ > +/* > + * MSI GT683R led driver > + * > + * Copyright (c) 2014 Janne Kanniainen <janne.kanniainen@gmail.com> > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation; either version 2 of > + * the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + */ > + > +#include <linux/hid.h> > +#include <linux/kernel.h> > +#include <linux/leds.h> > +#include <linux/module.h> > + > +#include "hid-ids.h" > + > +#define GT683R_LED_BACK BIT(0) > +#define GT683R_LED_SIDE BIT(1) > +#define GT683R_LED_FRONT BIT(2) > +#define GT683R_LED_ALL (GT683R_LED_BACK | GT683R_LED_SIDE | GT683R_LED_FRONT) Since it seems you are able to control these three LEDs independently, shouldn't you consider registering three LEDs? > + > +#define GT683R_LED_OFF 0 > +#define GT683R_LED_AUDIO 2 > +#define GT683R_LED_BREATHING 3 > +#define GT683R_LED_NORMAL 5 What are AUDIO and BREATHING for? Perhaps add a descriptive comment? > + > +#define GT683R_BUFFER_SIZE 8 > + > +struct gt683r_led { > + struct hid_device *hdev; > + struct led_classdev led_dev; > + struct mutex lock; > + struct work_struct work; > + enum led_brightness brightness; > +}; > + > +static const struct hid_device_id gt683r_led_id[] = { > + { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, > + { } > +}; > + > +static const char gt683r_led_select_leds[GT683R_BUFFER_SIZE] = { 0x01, 0x02, 0x30, 0x00, > + 0x00, 0x00, 0x00, 0x00 }; > +static const char gt683r_led_select_type[GT683R_BUFFER_SIZE] = { 0x01, 0x02, 0x20, 0x00, > + 0x01, 0x00, 0x00, 0x00 }; 80 char limit. Perhaps move these to gt683r_led_set, which is the only place where they are used? > + > +static void gt683r_brightness_set(struct led_classdev *led_cdev, > + enum led_brightness brightness) > +{ > + struct gt683r_led *led = > + container_of(led_cdev, struct gt683r_led, led_dev); > + > + led->brightness = brightness; > + > + schedule_work(&led->work); > +} > + > +static int gt683r_led_snd_msg(struct gt683r_led *led, char *msg) > +{ > + int ret; > + > + ret = hid_hw_raw_request(led->hdev, 0x01, msg, GT683R_BUFFER_SIZE, > + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); > + if (ret < 0) { > + hid_err(led->hdev, > + "failed to send set report request: %i\n", ret); > + return ret; > + } > + > + return 0; > +} > + > +static void gt683r_led_set(struct gt683r_led *led, char type) > +{ > + char *buffer; > + > + buffer = kmalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); > + if (!buffer) { > + hid_err(led->hdev, "can\'t allocate buffer\n"); No need to log OOM messages as this would already have been taken care of by the memory subsystem. > + return; > + } > + > + memcpy(buffer, gt683r_led_select_leds, GT683R_BUFFER_SIZE); > + buffer[3] = GT683R_LED_ALL; > + gt683r_led_snd_msg(led, buffer); Error handling? Perhaps there's no point in sending the "type" report if select_leds failed? > + > + memcpy(buffer, gt683r_led_select_type, GT683R_BUFFER_SIZE); > + buffer[3] = type; > + gt683r_led_snd_msg(led, buffer); You don't have to change this if you don't want, but wouldn't "set_state" be more descriptive than "select_type"? > + > + kfree(buffer); > +} > + > +static void gt683r_led_work(struct work_struct *work) > +{ > + struct gt683r_led *led = > + container_of(work, struct gt683r_led, work); > + > + mutex_lock(&led->lock); > + > + if (led->brightness) > + gt683r_led_set(led, GT683R_LED_NORMAL); > + else > + gt683r_led_set(led, GT683R_LED_OFF); > + > + mutex_unlock(&led->lock); > +} > + > +static struct led_classdev gt683r_led_dev = { > + .name = "gt683r-led", > + .brightness_set = gt683r_brightness_set, > + .max_brightness = 1, > + .flags = LED_CORE_SUSPENDRESUME, > +}; > + > +static int gt683r_led_probe(struct hid_device *hdev, > + const struct hid_device_id *id) > +{ > + int ret; > + struct gt683r_led *led; > + > + led = devm_kzalloc(&hdev->dev, sizeof(struct gt683r_led), GFP_KERNEL); > + if (!led) > + return -ENOMEM; > + > + led->hdev = hdev; > + hid_set_drvdata(hdev, led); > + > + ret = hid_parse(hdev); > + if (ret) { > + hid_err(hdev, "hid parsing failed\n"); > + goto fail; > + } > + > + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); > + if (ret) { > + hid_err(hdev, "hw start failed\n"); > + goto fail; > + } > + > + led->led_dev = gt683r_led_dev; > + ret = led_classdev_register(&hdev->dev, &led->led_dev); > + if (ret) { > + hid_err(hdev, "could not register led device\n"); > + goto stop; > + } > + > + mutex_init(&led->lock); > + INIT_WORK(&led->work, gt683r_led_work); > + > + return 0; > +stop: > + hid_hw_stop(hdev); > +fail: > + return ret; > +} > + > +static void gt683r_led_remove(struct hid_device *hdev) > +{ > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + led_classdev_unregister(&led->led_dev); > + cancel_work_sync(&led->work); > + hid_hw_stop(hdev); > +} > + > +static struct hid_driver gt683r_led_driver = { > + .probe = gt683r_led_probe, > + .remove = gt683r_led_remove, > + .name = "gt683r_led", > + .id_table = gt683r_led_id, > +}; > + > +module_hid_driver(gt683r_led_driver); > + > +MODULE_AUTHOR("Janne Kanniainen"); > +MODULE_DESCRIPTION("MSI GT683R led driver"); > +MODULE_LICENSE("GPL"); > diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h > index 34bb220..e2097f7 100644 > --- a/drivers/hid/hid-ids.h > +++ b/drivers/hid/hid-ids.h > @@ -641,6 +641,7 @@ > #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 > > #define USB_VENDOR_ID_MSI 0x1770 > +#define USB_DEVICE_ID_MSI_GT683R_LED_PANEL 0xff00 > #define USB_DEVICE_ID_MSI_GX680R_LED_PANEL 0xff00 As these device have the same PID you shouldn't be adding a duplicate entry to the blacklist_table below. Perhaps you can rename the original one as GC68XR instead (or just remove the old one). > > #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400 > diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c > index 8e4ddb3..927e7be 100644 > --- a/drivers/hid/usbhid/hid-quirks.c > +++ b/drivers/hid/usbhid/hid-quirks.c > @@ -73,6 +73,7 @@ static const struct hid_blacklist { > { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, > { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, > { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, > + { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS }, > { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_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 }, Thanks, Johan ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v3] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-11 14:05 ` Johan Hovold (?) @ 2014-06-11 15:30 ` Johan Hovold -1 siblings, 0 replies; 81+ messages in thread From: Johan Hovold @ 2014-06-11 15:30 UTC (permalink / raw) To: Janne Kanniainen Cc: jkosina, cooloney, linux-kernel, linux-leds, linux-usb, linux-input, johan On Wed, Jun 11, 2014 at 04:05:42PM +0200, Johan Hovold wrote: > On Wed, Jun 11, 2014 at 12:21:39AM +0300, Janne Kanniainen wrote: > > +static const char gt683r_led_select_leds[GT683R_BUFFER_SIZE] = { 0x01, 0x02, 0x30, 0x00, > > + 0x00, 0x00, 0x00, 0x00 }; > > +static const char gt683r_led_select_type[GT683R_BUFFER_SIZE] = { 0x01, 0x02, 0x20, 0x00, > > + 0x01, 0x00, 0x00, 0x00 }; > > 80 char limit. > > Perhaps move these to gt683r_led_set, which is the only place where they > are used? Or, as I hinted earlier, just allocate the 8-byte buffer using kzalloc and only initialise the non-zero bytes directly. The first byte should be the report id (0x01). I noticed that some hid-drivers use this fact when sending the raw request (see below). > > + > > +static void gt683r_brightness_set(struct led_classdev *led_cdev, > > + enum led_brightness brightness) > > +{ > > + struct gt683r_led *led = > > + container_of(led_cdev, struct gt683r_led, led_dev); > > + > > + led->brightness = brightness; > > + > > + schedule_work(&led->work); > > +} > > + > > +static int gt683r_led_snd_msg(struct gt683r_led *led, char *msg) > > +{ > > + int ret; > > + > > + ret = hid_hw_raw_request(led->hdev, 0x01, msg, GT683R_BUFFER_SIZE, > > + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); That is, you could use msg[0] here instead of 0x01. > > + if (ret < 0) { > > + hid_err(led->hdev, > > + "failed to send set report request: %i\n", ret); > > + return ret; > > + } > > + > > + return 0; > > +} Johan ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v3] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-11 14:05 ` Johan Hovold (?) (?) @ 2014-06-11 17:34 ` Johan Hovold 2014-06-11 22:48 ` [PATCH v4] " Janne Kanniainen -1 siblings, 1 reply; 81+ messages in thread From: Johan Hovold @ 2014-06-11 17:34 UTC (permalink / raw) To: Janne Kanniainen Cc: jkosina, cooloney, linux-kernel, linux-leds, linux-usb, linux-input, johan On Wed, Jun 11, 2014 at 04:05:42PM +0200, Johan Hovold wrote: > On Wed, Jun 11, 2014 at 12:21:39AM +0300, Janne Kanniainen wrote: > > +static int gt683r_led_snd_msg(struct gt683r_led *led, char *msg) > > +{ > > + int ret; > > + > > + ret = hid_hw_raw_request(led->hdev, 0x01, msg, GT683R_BUFFER_SIZE, > > + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); > > + if (ret < 0) { > > + hid_err(led->hdev, > > + "failed to send set report request: %i\n", ret); And here's one more: You need to check if ret != GT683R_BUFFER_SIZE and make sure to return an error (e.g. -EIO) even if ret >= 0 in that case. > > + return ret; > > + } > > + > > + return 0; > > +} Johan ^ permalink raw reply [flat|nested] 81+ messages in thread
* [PATCH v4] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-11 17:34 ` Johan Hovold @ 2014-06-11 22:48 ` Janne Kanniainen 2014-06-12 9:06 ` Johan Hovold 0 siblings, 1 reply; 81+ messages in thread From: Janne Kanniainen @ 2014-06-11 22:48 UTC (permalink / raw) To: jkosina Cc: cooloney, johan, linux-kernel, linux-leds, linux-usb, linux-input, Janne Kanniainen This driver adds support for USB controlled led panels that exists in MSI GT683R laptop Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> --- Changes in v2: - sorted headers to alphabetic order - using devm_kzalloc - using BIT(n) - using usb_control_msg instead of usb_submit_urb - removing unneeded code Changes in v3: - implemented as HID device - some cleanups and bug fixes Changes in v4: - more cleanups - support for selecting leds - support for selecting status drivers/hid/Kconfig | 11 ++ drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-gt683r.c | 320 ++++++++++++++++++++++++++++++++++++++++ drivers/hid/hid-ids.h | 2 +- drivers/hid/usbhid/hid-quirks.c | 2 +- 6 files changed, 335 insertions(+), 2 deletions(-) create mode 100644 drivers/hid/hid-gt683r.c diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 7af9d0b..d93e0ae 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -261,6 +261,17 @@ config HOLTEK_FF Say Y here if you have a Holtek On Line Grip based game controller and want to have force feedback support for it. +config HID_GT683R + tristate "MSI GT68xR LED support" + depends on LEDS_CLASS && USB_HID + ---help--- + Say Y here if you want to enable support for the MSI GT68xR LEDS + + This driver support following states normal, breathing and audio. + You can also select which leds you want to enable. + Currently the following devices are know to be supported: + - MSI GT683R + config HID_HUION tristate "Huion tablets" depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index fc712dd..7129311 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o obj-$(CONFIG_HID_ELECOM) += hid-elecom.o obj-$(CONFIG_HID_ELO) += hid-elo.o obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o +obj-$(CONFIG_HID_GT683R) += hid-gt683r.o obj-$(CONFIG_HID_GYRATION) += hid-gyration.o obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o obj-$(CONFIG_HID_HOLTEK) += hid-holtek-mouse.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index da52279..ec88fdb 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1827,6 +1827,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, { 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) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2) }, diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c new file mode 100644 index 0000000..04e4cc2 --- /dev/null +++ b/drivers/hid/hid-gt683r.c @@ -0,0 +1,320 @@ +/* + * MSI GT683R led driver + * + * Copyright (c) 2014 Janne Kanniainen <janne.kanniainen@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/device.h> +#include <linux/hid.h> +#include <linux/kernel.h> +#include <linux/leds.h> +#include <linux/module.h> + +#include "hid-ids.h" + +#define GT683R_LED_BACK BIT(0) +#define GT683R_LED_SIDE BIT(1) +#define GT683R_LED_FRONT BIT(2) + +#define GT683R_BUFFER_SIZE 8 + +/* + * GT683R_LED_OFF: all LEDs are off + * GT683R_LED_AUDIO: the status of LEDs depends + * on sound level + * GT683R_LED_BREATHING: LEDs brightness varies + * at human breathing rate + * GT683R_LED_NORMAL: LEDs are on + */ +enum gt683r_led_state { + GT683R_LED_OFF = 0, + GT683R_LED_AUDIO = 2, + GT683R_LED_BREATHING = 3, + GT683R_LED_NORMAL = 5 +}; + +struct gt683r_led { + struct hid_device *hdev; + struct led_classdev led_dev_back; + struct led_classdev led_dev_side; + struct led_classdev led_dev_front; + struct mutex lock; + struct mutex state_lock; + struct work_struct work; + enum led_brightness brightness_back; + enum led_brightness brightness_side; + enum led_brightness brightness_front; + enum gt683r_led_state state; +}; + +static const struct hid_device_id gt683r_led_id[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, + { } +}; + +#define GT683R_BRIGHTNESS_SET(name) \ +static void gt683r_brightness_set_##name(struct led_classdev *led_cdev, \ + enum led_brightness brightness) \ +{ \ + struct gt683r_led *led = \ + container_of(led_cdev, struct gt683r_led, \ + led_dev_##name); \ + \ + led->brightness_##name = brightness; \ + \ + schedule_work(&led->work); \ +} + +GT683R_BRIGHTNESS_SET(back); +GT683R_BRIGHTNESS_SET(side); +GT683R_BRIGHTNESS_SET(front); + +static ssize_t gt683r_show_state(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hid_device *hdev = + container_of(dev, struct hid_device, dev); + struct gt683r_led *led = hid_get_drvdata(hdev); + + if (led->state == GT683R_LED_OFF) + return sprintf(buf, "off\n"); + else if (led->state == GT683R_LED_AUDIO) + return sprintf(buf, "audio\n"); + else if (led->state == GT683R_LED_BREATHING) + return sprintf(buf, "breathing\n"); + else + return sprintf(buf, "normal\n"); +} + +static ssize_t gt683r_store_state(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct hid_device *hdev = + container_of(dev, struct hid_device, dev); + struct gt683r_led *led = hid_get_drvdata(hdev); + + mutex_lock(&led->state_lock); + if (!strncmp("off", buf, strlen("off"))) { + led->state = GT683R_LED_OFF; + } else if (!strncmp("audio", buf, strlen("audio"))) { + led->state = GT683R_LED_AUDIO; + } else if (!strncmp("breathing", buf, strlen("breathing"))) { + led->state = GT683R_LED_BREATHING; + } else if (!strncmp("normal", buf, strlen("normal"))) { + led->state = GT683R_LED_NORMAL; + } else { + count = -EINVAL; + goto fail; + } + + schedule_work(&led->work); + +fail: + mutex_unlock(&led->state_lock); + + return count; +} + +static int gt683r_led_snd_msg(struct gt683r_led *led, char *msg) +{ + int ret; + + ret = hid_hw_raw_request(led->hdev, msg[0], msg, GT683R_BUFFER_SIZE, + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); + if (ret != GT683R_BUFFER_SIZE) { + hid_err(led->hdev, + "failed to send set report request: %i\n", ret); + return ret < 0 ? ret : -EIO; + } + + return 0; +} + +static void gt683r_led_set(struct gt683r_led *led, char leds, char state) +{ + char *buffer; + + buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); + if (!buffer) + return; + + buffer[0] = 0x01; + buffer[1] = 0x02; + buffer[2] = 0x30; + buffer[3] = leds; + if (gt683r_led_snd_msg(led, buffer)) + goto fail; + + buffer[2] = 0x20; + buffer[3] = state; + buffer[4] = 0x01; + gt683r_led_snd_msg(led, buffer); + +fail: + kfree(buffer); +} + +static void gt683r_led_work(struct work_struct *work) +{ + struct gt683r_led *led = + container_of(work, struct gt683r_led, work); + char leds = 0; + + mutex_lock(&led->lock); + + if (led->brightness_back) + leds |= GT683R_LED_BACK; + + if (led->brightness_side) + leds |= GT683R_LED_SIDE; + + if (led->brightness_front) + leds |= GT683R_LED_FRONT; + + if (leds) + gt683r_led_set(led, leds, led->state); + else + gt683r_led_set(led, leds, GT683R_LED_OFF); + + mutex_unlock(&led->lock); +} + +static struct led_classdev gt683r_led_dev_back = { + .name = "gt683r-led:back", + .brightness_set = gt683r_brightness_set_back, + .max_brightness = 1, + .flags = LED_CORE_SUSPENDRESUME, +}; + +static struct led_classdev gt683r_led_dev_side = { + .name = "gt683r-led:side", + .brightness_set = gt683r_brightness_set_side, + .max_brightness = 1, + .flags = LED_CORE_SUSPENDRESUME, +}; + +static struct led_classdev gt683r_led_dev_front = { + .name = "gt683r-led:front", + .brightness_set = gt683r_brightness_set_front, + .max_brightness = 1, + .flags = LED_CORE_SUSPENDRESUME, +}; + +static struct device_attribute gt683r_led_state_attribute = { + .attr = { + .name = "state", + .mode = 0644, + }, + .show = gt683r_show_state, + .store = gt683r_store_state, +}; + +static int gt683r_led_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + int ret; + struct gt683r_led *led; + + led = devm_kzalloc(&hdev->dev, sizeof(struct gt683r_led), GFP_KERNEL); + if (!led) + return -ENOMEM; + + led->hdev = hdev; + hid_set_drvdata(hdev, led); + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "hid parsing failed\n"); + goto fail; + } + + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); + if (ret) { + hid_err(hdev, "hw start failed\n"); + goto fail; + } + + led->led_dev_back = gt683r_led_dev_back; + ret = led_classdev_register(&hdev->dev, &led->led_dev_back); + if (ret) { + hid_err(hdev, "could not register led device\n"); + goto fail_back; + } + + led->led_dev_side = gt683r_led_dev_side; + ret = led_classdev_register(&hdev->dev, &led->led_dev_side); + if (ret) { + hid_err(hdev, "could not register led device\n"); + goto fail_side; + } + + led->led_dev_front = gt683r_led_dev_front; + ret = led_classdev_register(&hdev->dev, &led->led_dev_front); + if (ret) { + hid_err(hdev, "could not register led device\n"); + goto fail_front; + } + + ret = device_create_file(&led->hdev->dev, + >683r_led_state_attribute); + if (ret) { + hid_err(hdev, "could not make state attribute file\n"); + goto fail_create_file; + } + + mutex_init(&led->lock); + mutex_init(&led->state_lock); + INIT_WORK(&led->work, gt683r_led_work); + + return 0; + +fail_create_file: + led_classdev_unregister(&led->led_dev_front); +fail_front: + led_classdev_unregister(&led->led_dev_side); +fail_side: + led_classdev_unregister(&led->led_dev_back); +fail_back: + hid_hw_stop(hdev); +fail: + return ret; +} + +static void gt683r_led_remove(struct hid_device *hdev) +{ + struct gt683r_led *led = hid_get_drvdata(hdev); + + led_classdev_unregister(&led->led_dev_side); + led_classdev_unregister(&led->led_dev_back); + led_classdev_unregister(&led->led_dev_front); + cancel_work_sync(&led->work); + device_remove_file(&hdev->dev, + >683r_led_state_attribute); + hid_hw_stop(hdev); +} + +static struct hid_driver gt683r_led_driver = { + .probe = gt683r_led_probe, + .remove = gt683r_led_remove, + .name = "gt683r_led", + .id_table = gt683r_led_id, +}; + +module_hid_driver(gt683r_led_driver); + +MODULE_AUTHOR("Janne Kanniainen"); +MODULE_DESCRIPTION("MSI GT683R led driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 34bb220..3692d37 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -641,7 +641,7 @@ #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 #define USB_VENDOR_ID_MSI 0x1770 -#define USB_DEVICE_ID_MSI_GX680R_LED_PANEL 0xff00 +#define USB_DEVICE_ID_MSI_GT683R_LED_PANEL 0xff00 #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400 #define USB_DEVICE_ID_N_S_HARMONY 0xc359 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 8e4ddb3..c640e1d 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -73,7 +73,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, - { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, 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 }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS }, -- 1.9.2 ^ permalink raw reply related [flat|nested] 81+ messages in thread
* Re: [PATCH v4] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-11 22:48 ` [PATCH v4] " Janne Kanniainen @ 2014-06-12 9:06 ` Johan Hovold 2014-06-12 20:34 ` [PATCH v5] " Janne Kanniainen 0 siblings, 1 reply; 81+ messages in thread From: Johan Hovold @ 2014-06-12 9:06 UTC (permalink / raw) To: Janne Kanniainen Cc: jkosina, cooloney, johan, linux-kernel, linux-leds, linux-usb, linux-input On Thu, Jun 12, 2014 at 01:48:41AM +0300, Janne Kanniainen wrote: > This driver adds support for USB controlled led panels that exists in MSI GT683R laptop You forgot to break this line. > > Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> > --- > Changes in v2: > - sorted headers to alphabetic order > - using devm_kzalloc > - using BIT(n) > - using usb_control_msg instead of usb_submit_urb > - removing unneeded code > > Changes in v3: > - implemented as HID device > - some cleanups and bug fixes > > Changes in v4: > - more cleanups > - support for selecting leds > - support for selecting status That was fast. :) > > drivers/hid/Kconfig | 11 ++ > drivers/hid/Makefile | 1 + > drivers/hid/hid-core.c | 1 + > drivers/hid/hid-gt683r.c | 320 ++++++++++++++++++++++++++++++++++++++++ > drivers/hid/hid-ids.h | 2 +- > drivers/hid/usbhid/hid-quirks.c | 2 +- > 6 files changed, 335 insertions(+), 2 deletions(-) > create mode 100644 drivers/hid/hid-gt683r.c > > diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig > index 7af9d0b..d93e0ae 100644 > --- a/drivers/hid/Kconfig > +++ b/drivers/hid/Kconfig > @@ -261,6 +261,17 @@ config HOLTEK_FF > Say Y here if you have a Holtek On Line Grip based game controller > and want to have force feedback support for it. > > +config HID_GT683R > + tristate "MSI GT68xR LED support" > + depends on LEDS_CLASS && USB_HID > + ---help--- > + Say Y here if you want to enable support for the MSI GT68xR LEDS > + > + This driver support following states normal, breathing and audio. > + You can also select which leds you want to enable. > + Currently the following devices are know to be supported: > + - MSI GT683R > + > config HID_HUION > tristate "Huion tablets" > depends on USB_HID > diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile > index fc712dd..7129311 100644 > --- a/drivers/hid/Makefile > +++ b/drivers/hid/Makefile > @@ -48,6 +48,7 @@ obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o > obj-$(CONFIG_HID_ELECOM) += hid-elecom.o > obj-$(CONFIG_HID_ELO) += hid-elo.o > obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o > +obj-$(CONFIG_HID_GT683R) += hid-gt683r.o > obj-$(CONFIG_HID_GYRATION) += hid-gyration.o > obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o > obj-$(CONFIG_HID_HOLTEK) += hid-holtek-mouse.o > diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c > index da52279..ec88fdb 100644 > --- a/drivers/hid/hid-core.c > +++ b/drivers/hid/hid-core.c > @@ -1827,6 +1827,7 @@ static const struct hid_device_id hid_have_special_driver[] = { > { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, > { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, > { 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) }, > { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) }, > { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2) }, > diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c > new file mode 100644 > index 0000000..04e4cc2 > --- /dev/null > +++ b/drivers/hid/hid-gt683r.c > @@ -0,0 +1,320 @@ > +/* > + * MSI GT683R led driver > + * > + * Copyright (c) 2014 Janne Kanniainen <janne.kanniainen@gmail.com> > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation; either version 2 of > + * the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + */ > + > +#include <linux/device.h> > +#include <linux/hid.h> > +#include <linux/kernel.h> > +#include <linux/leds.h> > +#include <linux/module.h> > + > +#include "hid-ids.h" > + > +#define GT683R_LED_BACK BIT(0) > +#define GT683R_LED_SIDE BIT(1) > +#define GT683R_LED_FRONT BIT(2) > + > +#define GT683R_BUFFER_SIZE 8 > + > +/* > + * GT683R_LED_OFF: all LEDs are off > + * GT683R_LED_AUDIO: the status of LEDs depends > + * on sound level > + * GT683R_LED_BREATHING: LEDs brightness varies > + * at human breathing rate > + * GT683R_LED_NORMAL: LEDs are on > + */ > +enum gt683r_led_state { > + GT683R_LED_OFF = 0, > + GT683R_LED_AUDIO = 2, > + GT683R_LED_BREATHING = 3, > + GT683R_LED_NORMAL = 5 > +}; > + > +struct gt683r_led { > + struct hid_device *hdev; > + struct led_classdev led_dev_back; > + struct led_classdev led_dev_side; > + struct led_classdev led_dev_front; You could store these as an array, and add an enum for back, side, and front (more below). > + struct mutex lock; > + struct mutex state_lock; You should be able to use only one lock. > + struct work_struct work; > + enum led_brightness brightness_back; > + enum led_brightness brightness_side; > + enum led_brightness brightness_front; These could then also be in an array. > + enum gt683r_led_state state; > +}; > + > +static const struct hid_device_id gt683r_led_id[] = { > + { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, > + { } > +}; > + > +#define GT683R_BRIGHTNESS_SET(name) \ > +static void gt683r_brightness_set_##name(struct led_classdev *led_cdev, \ > + enum led_brightness brightness) \ > +{ \ > + struct gt683r_led *led = \ > + container_of(led_cdev, struct gt683r_led, \ > + led_dev_##name); \ > + \ > + led->brightness_##name = brightness; \ > + \ > + schedule_work(&led->work); \ > +} > + > +GT683R_BRIGHTNESS_SET(back); > +GT683R_BRIGHTNESS_SET(side); > +GT683R_BRIGHTNESS_SET(front); This is one way of solving this, but it's better to have one set_brightness function and determine which led it is called for by accessing the driver data of the hid device (via the parent device) and iterate over the available leds. See drivers/hid/hid-lg4ff.c for an example of how this can be implemented. > + > +static ssize_t gt683r_show_state(struct device *dev, > + struct device_attribute *attr, > + char *buf) > +{ > + struct hid_device *hdev = > + container_of(dev, struct hid_device, dev); > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + if (led->state == GT683R_LED_OFF) > + return sprintf(buf, "off\n"); You should always use scnprintf (with a size of PAGE_SIZE) in show callbacks. > + else if (led->state == GT683R_LED_AUDIO) > + return sprintf(buf, "audio\n"); > + else if (led->state == GT683R_LED_BREATHING) > + return sprintf(buf, "breathing\n"); > + else > + return sprintf(buf, "normal\n"); > +} Ok, so the blink mode (or type rather than state, I understand now -- sorry for the confusion) is common for all three LEDs. You shouldn't allow the LEDs to be disabled through this attribute, but rather set the mode that will be used for any enabled LEDs (e.g. the attribute should only have three possible values). Would it even be sufficient to only set the blink mode (type, state) to NORMAL at probe and then only update it if it changes (in store_state below)? In particular, will all three LEDs stay off if they are masked out in gt683r_let_set? (Otherwise, you could only set OFF mode when all three LEDs are disabled.) Note that any new attribute has to be documented under Documentation/ABI. > + > +static ssize_t gt683r_store_state(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t count) > +{ > + struct hid_device *hdev = > + container_of(dev, struct hid_device, dev); > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + mutex_lock(&led->state_lock); > + if (!strncmp("off", buf, strlen("off"))) { > + led->state = GT683R_LED_OFF; > + } else if (!strncmp("audio", buf, strlen("audio"))) { > + led->state = GT683R_LED_AUDIO; > + } else if (!strncmp("breathing", buf, strlen("breathing"))) { > + led->state = GT683R_LED_BREATHING; > + } else if (!strncmp("normal", buf, strlen("normal"))) { > + led->state = GT683R_LED_NORMAL; > + } else { > + count = -EINVAL; > + goto fail; > + } > + > + schedule_work(&led->work); > + > +fail: > + mutex_unlock(&led->state_lock); > + > + return count; > +} I think you should use an integer value (and snprintf) for the three modes (e.g. 0: normal, 1: audio, 2: breathing) and just document that in the ABI files mentioned above. > + > +static int gt683r_led_snd_msg(struct gt683r_led *led, char *msg) I didn't notice before, but you should be using the unsigned u8 type for msg (and leds and state below). > +{ > + int ret; > + > + ret = hid_hw_raw_request(led->hdev, msg[0], msg, GT683R_BUFFER_SIZE, > + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); > + if (ret != GT683R_BUFFER_SIZE) { > + hid_err(led->hdev, > + "failed to send set report request: %i\n", ret); > + return ret < 0 ? ret : -EIO; I try to avoid ?: constructs. > + } > + > + return 0; > +} > + > +static void gt683r_led_set(struct gt683r_led *led, char leds, char state) > +{ > + char *buffer; > + > + buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); > + if (!buffer) > + return; > + > + buffer[0] = 0x01; > + buffer[1] = 0x02; > + buffer[2] = 0x30; > + buffer[3] = leds; > + if (gt683r_led_snd_msg(led, buffer)) > + goto fail; > + > + buffer[2] = 0x20; > + buffer[3] = state; > + buffer[4] = 0x01; > + gt683r_led_snd_msg(led, buffer); > + > +fail: > + kfree(buffer); > +} > + > +static void gt683r_led_work(struct work_struct *work) > +{ > + struct gt683r_led *led = > + container_of(work, struct gt683r_led, work); > + char leds = 0; > + > + mutex_lock(&led->lock); > + > + if (led->brightness_back) > + leds |= GT683R_LED_BACK; > + > + if (led->brightness_side) > + leds |= GT683R_LED_SIDE; > + > + if (led->brightness_front) > + leds |= GT683R_LED_FRONT; > + > + if (leds) > + gt683r_led_set(led, leds, led->state); > + else > + gt683r_led_set(led, leds, GT683R_LED_OFF); > + > + mutex_unlock(&led->lock); > +} > + > +static struct led_classdev gt683r_led_dev_back = { > + .name = "gt683r-led:back", > + .brightness_set = gt683r_brightness_set_back, > + .max_brightness = 1, > + .flags = LED_CORE_SUSPENDRESUME, > +}; > + > +static struct led_classdev gt683r_led_dev_side = { > + .name = "gt683r-led:side", > + .brightness_set = gt683r_brightness_set_side, > + .max_brightness = 1, > + .flags = LED_CORE_SUSPENDRESUME, > +}; > + > +static struct led_classdev gt683r_led_dev_front = { > + .name = "gt683r-led:front", > + .brightness_set = gt683r_brightness_set_front, > + .max_brightness = 1, > + .flags = LED_CORE_SUSPENDRESUME, > +}; You should remove these three as you only use them for initialising the dynamically allocated instances, which could be initialised directly in probe instead. You can find examples of this under drivers/hid (e.g. drivers/hid/hid-lg4ff.c) including how to initialise the name field. Note that the recommended naming scheme is "devicename:colour:function", but you can leave the colour out (but still keep the two ':'). > + > +static struct device_attribute gt683r_led_state_attribute = { > + .attr = { > + .name = "state", > + .mode = 0644, > + }, > + .show = gt683r_show_state, > + .store = gt683r_store_state, > +}; You should use the DEVICE_ATTR macro instead. > + > +static int gt683r_led_probe(struct hid_device *hdev, > + const struct hid_device_id *id) > +{ > + int ret; > + struct gt683r_led *led; > + > + led = devm_kzalloc(&hdev->dev, sizeof(struct gt683r_led), GFP_KERNEL); > + if (!led) > + return -ENOMEM; > + > + led->hdev = hdev; > + hid_set_drvdata(hdev, led); > + > + ret = hid_parse(hdev); > + if (ret) { > + hid_err(hdev, "hid parsing failed\n"); > + goto fail; > + } > + > + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); > + if (ret) { > + hid_err(hdev, "hw start failed\n"); > + goto fail; > + } > + > + led->led_dev_back = gt683r_led_dev_back; > + ret = led_classdev_register(&hdev->dev, &led->led_dev_back); > + if (ret) { > + hid_err(hdev, "could not register led device\n"); > + goto fail_back; > + } > + > + led->led_dev_side = gt683r_led_dev_side; > + ret = led_classdev_register(&hdev->dev, &led->led_dev_side); > + if (ret) { > + hid_err(hdev, "could not register led device\n"); > + goto fail_side; > + } > + > + led->led_dev_front = gt683r_led_dev_front; > + ret = led_classdev_register(&hdev->dev, &led->led_dev_front); > + if (ret) { > + hid_err(hdev, "could not register led device\n"); > + goto fail_front; > + } With the enum an arrays mentioned above this could be implemented as a loop. > + > + ret = device_create_file(&led->hdev->dev, > + >683r_led_state_attribute); > + if (ret) { > + hid_err(hdev, "could not make state attribute file\n"); > + goto fail_create_file; > + } > + > + mutex_init(&led->lock); > + mutex_init(&led->state_lock); > + INIT_WORK(&led->work, gt683r_led_work); > + > + return 0; > + > +fail_create_file: > + led_classdev_unregister(&led->led_dev_front); > +fail_front: > + led_classdev_unregister(&led->led_dev_side); > +fail_side: > + led_classdev_unregister(&led->led_dev_back); ...with a roll-back loop here. > +fail_back: > + hid_hw_stop(hdev); > +fail: > + return ret; > +} > + > +static void gt683r_led_remove(struct hid_device *hdev) > +{ > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + led_classdev_unregister(&led->led_dev_side); > + led_classdev_unregister(&led->led_dev_back); > + led_classdev_unregister(&led->led_dev_front); > + cancel_work_sync(&led->work); > + device_remove_file(&hdev->dev, > + >683r_led_state_attribute); > + hid_hw_stop(hdev); > +} > + > +static struct hid_driver gt683r_led_driver = { > + .probe = gt683r_led_probe, > + .remove = gt683r_led_remove, > + .name = "gt683r_led", > + .id_table = gt683r_led_id, > +}; > + > +module_hid_driver(gt683r_led_driver); > + > +MODULE_AUTHOR("Janne Kanniainen"); > +MODULE_DESCRIPTION("MSI GT683R led driver"); > +MODULE_LICENSE("GPL"); > diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h > index 34bb220..3692d37 100644 > --- a/drivers/hid/hid-ids.h > +++ b/drivers/hid/hid-ids.h > @@ -641,7 +641,7 @@ > #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 > > #define USB_VENDOR_ID_MSI 0x1770 > -#define USB_DEVICE_ID_MSI_GX680R_LED_PANEL 0xff00 > +#define USB_DEVICE_ID_MSI_GT683R_LED_PANEL 0xff00 > > #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400 > #define USB_DEVICE_ID_N_S_HARMONY 0xc359 > diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c > index 8e4ddb3..c640e1d 100644 > --- a/drivers/hid/usbhid/hid-quirks.c > +++ b/drivers/hid/usbhid/hid-quirks.c > @@ -73,7 +73,7 @@ static const struct hid_blacklist { > { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, > { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, > { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, > - { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, 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 }, > { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS }, Thanks, Johan ^ permalink raw reply [flat|nested] 81+ messages in thread
* [PATCH v5] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-12 9:06 ` Johan Hovold @ 2014-06-12 20:34 ` Janne Kanniainen 2014-06-13 7:54 ` Johan Hovold 2014-06-14 22:42 ` [PATCH v5] " Pavel Machek 0 siblings, 2 replies; 81+ messages in thread From: Janne Kanniainen @ 2014-06-12 20:34 UTC (permalink / raw) To: jkosina Cc: johan, cooloney, linux-kernel, linux-leds, linux-usb, linux-input, Janne Kanniainen This driver adds support for USB controlled led panels that exists in MSI GT683R laptop Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> --- Changes in v2: - sorted headers to alphabetic order - using devm_kzalloc - using BIT(n) - using usb_control_msg instead of usb_submit_urb - removing unneeded code Changes in v3: - implemented as HID device - some cleanups and bug fixes Changes in v4: - more cleanups - support for selecting leds - suppport for selecting status Changes in v5: - mode attribute documented under Documentation/ABI - made array for led_classdev - led devices uses now recommended naming scheme .../ABI/testing/sysfs-class-hid-driver-gt683r | 10 + drivers/hid/Kconfig | 11 + drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-gt683r.c | 294 +++++++++++++++++++++ drivers/hid/hid-ids.h | 2 +- drivers/hid/usbhid/hid-quirks.c | 2 +- 7 files changed, 319 insertions(+), 2 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-class-hid-driver-gt683r create mode 100644 drivers/hid/hid-gt683r.c diff --git a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r new file mode 100644 index 0000000..c4d604e --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r @@ -0,0 +1,10 @@ +What: /sys/class/hidraw/<hidraw>/device/state +Date: Jun 2014 +KernelVersion: 3.15 +Contact: Janne Kanniainen <janne.kanniainen@gmail.com> +Description: + Set the mode of LEDs + + 0 - normal + 1 - audio + 2 - breathing diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 7af9d0b..d93e0ae 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -261,6 +261,17 @@ config HOLTEK_FF Say Y here if you have a Holtek On Line Grip based game controller and want to have force feedback support for it. +config HID_GT683R + tristate "MSI GT68xR LED support" + depends on LEDS_CLASS && USB_HID + ---help--- + Say Y here if you want to enable support for the MSI GT68xR LEDS + + This driver support following states normal, breathing and audio. + You can also select which leds you want to enable. + Currently the following devices are know to be supported: + - MSI GT683R + config HID_HUION tristate "Huion tablets" depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index fc712dd..7129311 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o obj-$(CONFIG_HID_ELECOM) += hid-elecom.o obj-$(CONFIG_HID_ELO) += hid-elo.o obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o +obj-$(CONFIG_HID_GT683R) += hid-gt683r.o obj-$(CONFIG_HID_GYRATION) += hid-gyration.o obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o obj-$(CONFIG_HID_HOLTEK) += hid-holtek-mouse.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index da52279..ec88fdb 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1827,6 +1827,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, { 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) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2) }, diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c new file mode 100644 index 0000000..6dffb76 --- /dev/null +++ b/drivers/hid/hid-gt683r.c @@ -0,0 +1,294 @@ +/* + * MSI GT683R led driver + * + * Copyright (c) 2014 Janne Kanniainen <janne.kanniainen@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/device.h> +#include <linux/hid.h> +#include <linux/kernel.h> +#include <linux/leds.h> +#include <linux/module.h> + +#include "hid-ids.h" + +#define GT683R_LED_BACK BIT(0) +#define GT683R_LED_SIDE BIT(1) +#define GT683R_LED_FRONT BIT(2) + +#define GT683R_BUFFER_SIZE 8 + +/* + * GT683R_LED_OFF: all LEDs are off + * GT683R_LED_AUDIO: the status of LEDs depends + * on sound level + * GT683R_LED_BREATHING: LEDs brightness varies + * at human breathing rate + * GT683R_LED_NORMAL: LEDs are on + */ +enum gt683r_led_mode { + GT683R_LED_OFF = 0, + GT683R_LED_AUDIO = 2, + GT683R_LED_BREATHING = 3, + GT683R_LED_NORMAL = 5 +}; + +enum gt683r_panels { + back, + side, + front, +}; + +const char *gt683r_panel_names[] = { + "gt683r::back", + "gt683r::side", + "gt683r::front", +}; + +struct gt683r_led { + struct hid_device *hdev; + struct led_classdev *led_devs[3]; + struct mutex lock; + struct work_struct work; + enum led_brightness brightnesses[3]; + enum gt683r_led_mode mode; +}; + +static const struct hid_device_id gt683r_led_id[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, + { } +}; + +static void gt683r_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + int i; + struct device *dev = led_cdev->dev->parent; + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct gt683r_led *led = hid_get_drvdata(hdev); + + for (i = 0; i < 3; i++) { + if (led->led_devs[i] != led_cdev) + continue; + + led->brightnesses[i] = brightness; + schedule_work(&led->work); + break; + } +} + +static ssize_t gt683r_show_mode(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct hid_device *hdev = + container_of(dev, struct hid_device, dev); + struct gt683r_led *led = hid_get_drvdata(hdev); + + if (led->mode == GT683R_LED_NORMAL) + return scnprintf(buf, PAGE_SIZE, "0\n"); + else if (led->mode == GT683R_LED_AUDIO) + return scnprintf(buf, PAGE_SIZE, "1\n"); + else + return scnprintf(buf, PAGE_SIZE, "2\n"); + +} + +static ssize_t gt683r_store_mode(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct hid_device *hdev = + container_of(dev, struct hid_device, dev); + struct gt683r_led *led = hid_get_drvdata(hdev); + + mutex_lock(&led->lock); + + if (!strncmp("0", buf, strlen("0"))) { + led->mode = GT683R_LED_NORMAL; + } else if (!strncmp("1", buf, strlen("1"))) { + led->mode = GT683R_LED_AUDIO; + } else if (!strncmp("2", buf, strlen("2"))) { + led->mode = GT683R_LED_BREATHING; + } else { + count = -EINVAL; + goto fail; + } + + schedule_work(&led->work); +fail: + mutex_unlock(&led->lock); + + return count; +} + +static int gt683r_led_snd_msg(struct gt683r_led *led, u8 *msg) +{ + int ret; + + ret = hid_hw_raw_request(led->hdev, msg[0], msg, GT683R_BUFFER_SIZE, + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); + if (ret != GT683R_BUFFER_SIZE) { + hid_err(led->hdev, + "failed to send set report request: %i\n", ret); + if (ret < 0) + return ret; + return -EIO; + } + + return 0; +} + +static void gt683r_led_set(struct gt683r_led *led, u8 leds, u8 mode) +{ + u8 *buffer; + + buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); + if (!buffer) + return; + + buffer[0] = 0x01; + buffer[1] = 0x02; + buffer[2] = 0x30; + buffer[3] = leds; + if (gt683r_led_snd_msg(led, buffer)) + goto fail; + + buffer[2] = 0x20; + buffer[3] = mode; + buffer[4] = 0x01; + gt683r_led_snd_msg(led, buffer); + +fail: + kfree(buffer); +} + +static void gt683r_led_work(struct work_struct *work) +{ + struct gt683r_led *led = + container_of(work, struct gt683r_led, work); + u8 leds = 0; + + mutex_lock(&led->lock); + + if (led->brightnesses[back]) + leds |= GT683R_LED_BACK; + + if (led->brightnesses[side]) + leds |= GT683R_LED_SIDE; + + if (led->brightnesses[front]) + leds |= GT683R_LED_FRONT; + + if (leds) + gt683r_led_set(led, leds, led->mode); + else + gt683r_led_set(led, leds, GT683R_LED_OFF); + + mutex_unlock(&led->lock); +} + +static DEVICE_ATTR(mode, 0644, gt683r_show_mode, gt683r_store_mode); + +static int gt683r_led_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + int ret, i; + struct gt683r_led *led; + + led = devm_kzalloc(&hdev->dev, sizeof(struct gt683r_led), GFP_KERNEL); + if (!led) + return -ENOMEM; + + led->mode = GT683R_LED_NORMAL; + led->hdev = hdev; + hid_set_drvdata(hdev, led); + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "hid parsing failed\n"); + goto fail; + } + + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); + if (ret) { + hid_err(hdev, "hw start failed\n"); + goto fail; + } + + for (i = 0; i < 3; i++) { + led->led_devs[i] = kzalloc(sizeof(struct led_classdev) + + strlen(gt683r_panel_names[i]) + 1, + GFP_KERNEL); + if (!led->led_devs[i]) + goto fail2; + led->led_devs[i]->name = gt683r_panel_names[i]; + led->led_devs[i]->max_brightness = 1; + led->led_devs[i]->brightness_set = gt683r_brightness_set; + ret = led_classdev_register(&hdev->dev, led->led_devs[i]); + if (ret) { + hid_err(hdev, "could not register led device\n"); + goto fail2; + } + } + + ret = device_create_file(&led->hdev->dev, + &dev_attr_mode); + if (ret) { + hid_err(hdev, "could not make mode attribute file\n"); + goto fail2; + } + + mutex_init(&led->lock); + INIT_WORK(&led->work, gt683r_led_work); + + return 0; + +fail2: + while (i-- > 0) { + led_classdev_unregister(led->led_devs[i]); + kfree(led->led_devs[i]); + } + hid_hw_stop(hdev); +fail: + return ret; +} + +static void gt683r_led_remove(struct hid_device *hdev) +{ + int i; + struct gt683r_led *led = hid_get_drvdata(hdev); + + for (i = 0; i < 3; i++) { + led_classdev_unregister(led->led_devs[i]); + kfree(led->led_devs[i]); + } + cancel_work_sync(&led->work); + device_remove_file(&hdev->dev, + &dev_attr_mode); + hid_hw_stop(hdev); +} + +static struct hid_driver gt683r_led_driver = { + .probe = gt683r_led_probe, + .remove = gt683r_led_remove, + .name = "gt683r_led", + .id_table = gt683r_led_id, +}; + +module_hid_driver(gt683r_led_driver); + +MODULE_AUTHOR("Janne Kanniainen"); +MODULE_DESCRIPTION("MSI GT683R led driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 34bb220..3692d37 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -641,7 +641,7 @@ #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 #define USB_VENDOR_ID_MSI 0x1770 -#define USB_DEVICE_ID_MSI_GX680R_LED_PANEL 0xff00 +#define USB_DEVICE_ID_MSI_GT683R_LED_PANEL 0xff00 #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400 #define USB_DEVICE_ID_N_S_HARMONY 0xc359 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 8e4ddb3..c640e1d 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -73,7 +73,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, - { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, 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 }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS }, -- 1.9.2 ^ permalink raw reply related [flat|nested] 81+ messages in thread
* Re: [PATCH v5] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-12 20:34 ` [PATCH v5] " Janne Kanniainen @ 2014-06-13 7:54 ` Johan Hovold 2014-06-13 17:19 ` Janne Kanniainen 2014-06-16 17:23 ` [PATCH v6] " Janne Kanniainen 2014-06-14 22:42 ` [PATCH v5] " Pavel Machek 1 sibling, 2 replies; 81+ messages in thread From: Johan Hovold @ 2014-06-13 7:54 UTC (permalink / raw) To: Janne Kanniainen Cc: jkosina, johan, cooloney, linux-kernel, linux-leds, linux-usb, linux-input On Thu, Jun 12, 2014 at 11:34:12PM +0300, Janne Kanniainen wrote: > This driver adds support for USB controlled led panels that exists in > MSI GT683R laptop > > Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> > --- > Changes in v2: > - sorted headers to alphabetic order > - using devm_kzalloc > - using BIT(n) > - using usb_control_msg instead of usb_submit_urb > - removing unneeded code > > Changes in v3: > - implemented as HID device > - some cleanups and bug fixes > > Changes in v4: > - more cleanups > - support for selecting leds > - suppport for selecting status > > Changes in v5: > - mode attribute documented under Documentation/ABI > - made array for led_classdev > - led devices uses now recommended naming scheme > > .../ABI/testing/sysfs-class-hid-driver-gt683r | 10 + > drivers/hid/Kconfig | 11 + > drivers/hid/Makefile | 1 + > drivers/hid/hid-core.c | 1 + > drivers/hid/hid-gt683r.c | 294 +++++++++++++++++++++ > drivers/hid/hid-ids.h | 2 +- > drivers/hid/usbhid/hid-quirks.c | 2 +- > 7 files changed, 319 insertions(+), 2 deletions(-) > create mode 100644 Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > create mode 100644 drivers/hid/hid-gt683r.c > > diff --git a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > new file mode 100644 > index 0000000..c4d604e > --- /dev/null > +++ b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > @@ -0,0 +1,10 @@ > +What: /sys/class/hidraw/<hidraw>/device/state You should probably stick to "mode" (rather than "state") throughout (it seems you just forgot to update a few uses). > +Date: Jun 2014 > +KernelVersion: 3.15 This should be 3.17. > +Contact: Janne Kanniainen <janne.kanniainen@gmail.com> > +Description: > + Set the mode of LEDs > + > + 0 - normal > + 1 - audio > + 2 - breathing Perhaps expand this with a short paragraph describing the different modes. > diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig > index 7af9d0b..d93e0ae 100644 > --- a/drivers/hid/Kconfig > +++ b/drivers/hid/Kconfig > @@ -261,6 +261,17 @@ config HOLTEK_FF > Say Y here if you have a Holtek On Line Grip based game controller > and want to have force feedback support for it. > > +config HID_GT683R > + tristate "MSI GT68xR LED support" > + depends on LEDS_CLASS && USB_HID > + ---help--- > + Say Y here if you want to enable support for the MSI GT68xR LEDS > + > + This driver support following states normal, breathing and audio. You could also use "modes" and expand this with the same description. > + You can also select which leds you want to enable. > + Currently the following devices are know to be supported: > + - MSI GT683R > + > config HID_HUION > tristate "Huion tablets" > depends on USB_HID > diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile > index fc712dd..7129311 100644 > --- a/drivers/hid/Makefile > +++ b/drivers/hid/Makefile > @@ -48,6 +48,7 @@ obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o > obj-$(CONFIG_HID_ELECOM) += hid-elecom.o > obj-$(CONFIG_HID_ELO) += hid-elo.o > obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o > +obj-$(CONFIG_HID_GT683R) += hid-gt683r.o > obj-$(CONFIG_HID_GYRATION) += hid-gyration.o > obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o > obj-$(CONFIG_HID_HOLTEK) += hid-holtek-mouse.o > diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c > index da52279..ec88fdb 100644 > --- a/drivers/hid/hid-core.c > +++ b/drivers/hid/hid-core.c > @@ -1827,6 +1827,7 @@ static const struct hid_device_id hid_have_special_driver[] = { > { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, > { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, > { 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) }, > { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) }, > { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2) }, > diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c > new file mode 100644 > index 0000000..6dffb76 > --- /dev/null > +++ b/drivers/hid/hid-gt683r.c > @@ -0,0 +1,294 @@ > +/* > + * MSI GT683R led driver > + * > + * Copyright (c) 2014 Janne Kanniainen <janne.kanniainen@gmail.com> > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation; either version 2 of > + * the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + */ > + > +#include <linux/device.h> > +#include <linux/hid.h> > +#include <linux/kernel.h> > +#include <linux/leds.h> > +#include <linux/module.h> > + > +#include "hid-ids.h" > + > +#define GT683R_LED_BACK BIT(0) > +#define GT683R_LED_SIDE BIT(1) > +#define GT683R_LED_FRONT BIT(2) > + > +#define GT683R_BUFFER_SIZE 8 > + > +/* > + * GT683R_LED_OFF: all LEDs are off > + * GT683R_LED_AUDIO: the status of LEDs depends > + * on sound level > + * GT683R_LED_BREATHING: LEDs brightness varies > + * at human breathing rate > + * GT683R_LED_NORMAL: LEDs are on > + */ > +enum gt683r_led_mode { > + GT683R_LED_OFF = 0, > + GT683R_LED_AUDIO = 2, > + GT683R_LED_BREATHING = 3, > + GT683R_LED_NORMAL = 5 > +}; > + > +enum gt683r_panels { > + back, > + side, > + front, > +}; How about calling these GT683R_LED_BACK, etc, and simply do BIT(GT683R_LED_BACK) in gt683r_led_setset_led below (and drop the bitmask defines above). You should also add a count enum/define rather than hard-code 3 throughout the driver, for example: enum gt683r_panels { GT683R_LED_BACK = 0, GT683R_LED_SIDE = 1, GT683R_LED_FRONT = 2, GT683R_LED_COUNT }; > + > +const char *gt683r_panel_names[] = { > + "gt683r::back", > + "gt683r::side", > + "gt683r::front", > +}; Your forgot to declare this static. I don't think you should hard-code the device-part (i.e. "gt683r") but rather derive it from the hid device (as in the driver I referred to as an example). Just store the description here (e.g. "back"). More details below. > + > +struct gt683r_led { > + struct hid_device *hdev; > + struct led_classdev *led_devs[3]; You could keep these as embedded structs (an array of structs) rather than do individual allocations in probe. > + struct mutex lock; > + struct work_struct work; > + enum led_brightness brightnesses[3]; > + enum gt683r_led_mode mode; > +}; > + > +static const struct hid_device_id gt683r_led_id[] = { > + { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, > + { } > +}; > + > +static void gt683r_brightness_set(struct led_classdev *led_cdev, > + enum led_brightness brightness) > +{ > + int i; > + struct device *dev = led_cdev->dev->parent; > + struct hid_device *hdev = container_of(dev, struct hid_device, dev); > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + for (i = 0; i < 3; i++) { > + if (led->led_devs[i] != led_cdev) > + continue; > + > + led->brightnesses[i] = brightness; > + schedule_work(&led->work); > + break; I'd move the assignment and work scheduling out of the loop (and add an explicit check for LED-not-found, if at all needed). > + } > +} > + > +static ssize_t gt683r_show_mode(struct device *dev, > + struct device_attribute *attr, > + char *buf) > +{ > + struct hid_device *hdev = > + container_of(dev, struct hid_device, dev); > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + if (led->mode == GT683R_LED_NORMAL) > + return scnprintf(buf, PAGE_SIZE, "0\n"); > + else if (led->mode == GT683R_LED_AUDIO) > + return scnprintf(buf, PAGE_SIZE, "1\n"); > + else > + return scnprintf(buf, PAGE_SIZE, "2\n"); How about mapping led->mode to sysfs mode in a temporary variable and the just do one: return scnprintf(buf, PAGE_SIZE, "%u\n", sysfs_mode); at the end? > + > +} > + > +static ssize_t gt683r_store_mode(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t count) > +{ > + struct hid_device *hdev = > + container_of(dev, struct hid_device, dev); > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + mutex_lock(&led->lock); > + > + if (!strncmp("0", buf, strlen("0"))) { > + led->mode = GT683R_LED_NORMAL; > + } else if (!strncmp("1", buf, strlen("1"))) { > + led->mode = GT683R_LED_AUDIO; > + } else if (!strncmp("2", buf, strlen("2"))) { > + led->mode = GT683R_LED_BREATHING; > + } else { > + count = -EINVAL; > + goto fail; > + } Here you should use snprintf to parse buf as I already mentioned. With the current implementation "22" would be accepted as a valid mode. > + > + schedule_work(&led->work); > +fail: > + mutex_unlock(&led->lock); You should unlock before scheduling. > + > + return count; > +} > + > +static int gt683r_led_snd_msg(struct gt683r_led *led, u8 *msg) > +{ > + int ret; > + > + ret = hid_hw_raw_request(led->hdev, msg[0], msg, GT683R_BUFFER_SIZE, > + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); > + if (ret != GT683R_BUFFER_SIZE) { > + hid_err(led->hdev, > + "failed to send set report request: %i\n", ret); > + if (ret < 0) > + return ret; > + return -EIO; > + } > + > + return 0; > +} > + > +static void gt683r_led_set(struct gt683r_led *led, u8 leds, u8 mode) > +{ > + u8 *buffer; > + > + buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); > + if (!buffer) > + return; > + > + buffer[0] = 0x01; > + buffer[1] = 0x02; > + buffer[2] = 0x30; > + buffer[3] = leds; > + if (gt683r_led_snd_msg(led, buffer)) > + goto fail; > + > + buffer[2] = 0x20; > + buffer[3] = mode; > + buffer[4] = 0x01; > + gt683r_led_snd_msg(led, buffer); Ok, so you decided to continue setting mode on every LED brightness update. That should be fine, but you never answered my question about whether it is necessary? > + > +fail: > + kfree(buffer); > +} > + > +static void gt683r_led_work(struct work_struct *work) > +{ > + struct gt683r_led *led = > + container_of(work, struct gt683r_led, work); > + u8 leds = 0; > + > + mutex_lock(&led->lock); > + > + if (led->brightnesses[back]) > + leds |= GT683R_LED_BACK; > + > + if (led->brightnesses[side]) > + leds |= GT683R_LED_SIDE; > + > + if (led->brightnesses[front]) > + leds |= GT683R_LED_FRONT; > + > + if (leds) > + gt683r_led_set(led, leds, led->mode); > + else > + gt683r_led_set(led, leds, GT683R_LED_OFF); > + > + mutex_unlock(&led->lock); > +} > + > +static DEVICE_ATTR(mode, 0644, gt683r_show_mode, gt683r_store_mode); It is even recommended to use the new DEVICE_ATTR_RW macro here rather (forgot about that). > + > +static int gt683r_led_probe(struct hid_device *hdev, > + const struct hid_device_id *id) > +{ > + int ret, i; > + struct gt683r_led *led; > + > + led = devm_kzalloc(&hdev->dev, sizeof(struct gt683r_led), GFP_KERNEL); > + if (!led) > + return -ENOMEM; > + > + led->mode = GT683R_LED_NORMAL; > + led->hdev = hdev; > + hid_set_drvdata(hdev, led); > + > + ret = hid_parse(hdev); > + if (ret) { > + hid_err(hdev, "hid parsing failed\n"); > + goto fail; > + } > + > + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); > + if (ret) { > + hid_err(hdev, "hw start failed\n"); > + goto fail; > + } > + > + for (i = 0; i < 3; i++) { > + led->led_devs[i] = kzalloc(sizeof(struct led_classdev) + > + strlen(gt683r_panel_names[i]) + 1, Why are you allocating space for the panel names here? Oh, now I see, that's how it's done in the example I referred to. :) Just embed the struct led_classdevs directly in struct gt683r_led, and use devm_kzalloc(&hdev->dev, ...) to allocate the name buffers. > + GFP_KERNEL); > + if (!led->led_devs[i]) > + goto fail2; > + led->led_devs[i]->name = gt683r_panel_names[i]; The other hid leds use dev_name(&hdev->dev) for the device name part of the name. So determine the buffer length: strlen(dev_name(&hdev->dev)) + strlen(gt683r_panel_names[i]) + 3 and use snprintf with the following format "%s::%s". > + led->led_devs[i]->max_brightness = 1; > + led->led_devs[i]->brightness_set = gt683r_brightness_set; > + ret = led_classdev_register(&hdev->dev, led->led_devs[i]); > + if (ret) { > + hid_err(hdev, "could not register led device\n"); > + goto fail2; > + } > + } > + > + ret = device_create_file(&led->hdev->dev, > + &dev_attr_mode); > + if (ret) { > + hid_err(hdev, "could not make mode attribute file\n"); > + goto fail2; > + } > + > + mutex_init(&led->lock); > + INIT_WORK(&led->work, gt683r_led_work); > + > + return 0; > + > +fail2: > + while (i-- > 0) { Please use a for-loop instead (for readability). > + led_classdev_unregister(led->led_devs[i]); > + kfree(led->led_devs[i]); This would currently leak memory if led_classdev_register fails, but will work if you use devm_kzalloc as suggested above. > + } > + hid_hw_stop(hdev); > +fail: > + return ret; > +} > + > +static void gt683r_led_remove(struct hid_device *hdev) > +{ > + int i; > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + for (i = 0; i < 3; i++) { > + led_classdev_unregister(led->led_devs[i]); > + kfree(led->led_devs[i]); > + } > + cancel_work_sync(&led->work); > + device_remove_file(&hdev->dev, > + &dev_attr_mode); > + hid_hw_stop(hdev); > +} > + > +static struct hid_driver gt683r_led_driver = { > + .probe = gt683r_led_probe, > + .remove = gt683r_led_remove, > + .name = "gt683r_led", > + .id_table = gt683r_led_id, > +}; > + > +module_hid_driver(gt683r_led_driver); > + > +MODULE_AUTHOR("Janne Kanniainen"); > +MODULE_DESCRIPTION("MSI GT683R led driver"); > +MODULE_LICENSE("GPL"); > diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h > index 34bb220..3692d37 100644 > --- a/drivers/hid/hid-ids.h > +++ b/drivers/hid/hid-ids.h > @@ -641,7 +641,7 @@ > #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 > > #define USB_VENDOR_ID_MSI 0x1770 > -#define USB_DEVICE_ID_MSI_GX680R_LED_PANEL 0xff00 > +#define USB_DEVICE_ID_MSI_GT683R_LED_PANEL 0xff00 > > #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400 > #define USB_DEVICE_ID_N_S_HARMONY 0xc359 > diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c > index 8e4ddb3..c640e1d 100644 > --- a/drivers/hid/usbhid/hid-quirks.c > +++ b/drivers/hid/usbhid/hid-quirks.c > @@ -73,7 +73,7 @@ static const struct hid_blacklist { > { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, > { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, > { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, > - { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, 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 }, > { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS }, You're almost done. One last update? :) Thanks, Johan ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v5] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-13 7:54 ` Johan Hovold @ 2014-06-13 17:19 ` Janne Kanniainen 2014-06-15 14:59 ` Janne Kanniainen 2014-06-16 17:23 ` [PATCH v6] " Janne Kanniainen 1 sibling, 1 reply; 81+ messages in thread From: Janne Kanniainen @ 2014-06-13 17:19 UTC (permalink / raw) To: Johan Hovold Cc: Jiri Kosina, Bryan Wu, linux-kernel, linux-leds, linux-usb, linux-input > Ok, so you decided to continue setting mode on every LED brightness > update. That should be fine, but you never answered my question about > whether it is necessary? I decided to do it that way because official driver did it as well. I can check if it is necessary. > You're almost done. One last update? :) Yeah, I hope so :) ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v5] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-13 17:19 ` Janne Kanniainen @ 2014-06-15 14:59 ` Janne Kanniainen 2014-06-16 7:39 ` Johan Hovold 0 siblings, 1 reply; 81+ messages in thread From: Janne Kanniainen @ 2014-06-15 14:59 UTC (permalink / raw) To: Johan Hovold Cc: Jiri Kosina, Bryan Wu, linux-kernel, linux-leds, linux-usb, linux-input >> Ok, so you decided to continue setting mode on every LED brightness >> update. That should be fine, but you never answered my question about >> whether it is necessary? > > I decided to do it that way because official driver did it as well. I > can check if it is necessary. Ok, I checked this one and every time you update LEDs brightness you will need to update mode also. ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v5] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-15 14:59 ` Janne Kanniainen @ 2014-06-16 7:39 ` Johan Hovold 0 siblings, 0 replies; 81+ messages in thread From: Johan Hovold @ 2014-06-16 7:39 UTC (permalink / raw) To: Janne Kanniainen Cc: Johan Hovold, Jiri Kosina, Bryan Wu, linux-kernel, linux-leds, linux-usb, linux-input On Sun, Jun 15, 2014 at 05:59:40PM +0300, Janne Kanniainen wrote: > >> Ok, so you decided to continue setting mode on every LED brightness > >> update. That should be fine, but you never answered my question about > >> whether it is necessary? > > > > I decided to do it that way because official driver did it as well. I > > can check if it is necessary. > > Ok, I checked this one and every time you update LEDs brightness you > will need to update mode also. Ok, great. Then we know. Johan ^ permalink raw reply [flat|nested] 81+ messages in thread
* [PATCH v6] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-13 7:54 ` Johan Hovold 2014-06-13 17:19 ` Janne Kanniainen @ 2014-06-16 17:23 ` Janne Kanniainen 2014-06-16 22:01 ` Janne Kanniainen 1 sibling, 1 reply; 81+ messages in thread From: Janne Kanniainen @ 2014-06-16 17:23 UTC (permalink / raw) To: jkosina Cc: johan, cooloney, linux-kernel, linux-leds, linux-usb, linux-input, Janne Kanniainen This driver adds support for USB controlled led panels that exists in MSI GT683R laptop Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> --- Changes in v2: - sorted headers to alphabetic order - using devm_kzalloc - using BIT(n) - using usb_control_msg instead of usb_submit_urb - removing unneeded code Changes in v3: - implemented as HID device - some cleanups and bug fixes Changes in v4: - more cleanups - support for selecting leds - suppport for selecting status Changes in v5: - mode attribute documented under Documentation/ABI - made array for led_classdev - led devices uses now recommended naming scheme Changes in v6: - flush_work added - using hid device name instead of hard coded gt683r - allocating name buffers with devm_kzalloc .../ABI/testing/sysfs-class-hid-driver-gt683r | 14 + drivers/hid/Kconfig | 16 ++ drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-gt683r.c | 318 +++++++++++++++++++++ drivers/hid/hid-ids.h | 2 +- drivers/hid/usbhid/hid-quirks.c | 2 +- 7 files changed, 352 insertions(+), 2 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-class-hid-driver-gt683r create mode 100644 drivers/hid/hid-gt683r.c diff --git a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r new file mode 100644 index 0000000..6d0bd80 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r @@ -0,0 +1,14 @@ +What: /sys/class/hidraw/<hidraw>/device/mode +Date: Jun 2014 +KernelVersion: 3.17 +Contact: Janne Kanniainen <janne.kanniainen@gmail.com> +Description: + Set the mode of LEDs + + 0 - normal + 1 - audio + 2 - breathing + + Normal: LEDs are on + Audio: LEDs brightness depends on sound level + Breathing: LEDs brightness varies at human breathing rate \ No newline at end of file diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 7af9d0b..b88cabd 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -261,6 +261,22 @@ config HOLTEK_FF Say Y here if you have a Holtek On Line Grip based game controller and want to have force feedback support for it. +config HID_GT683R + tristate "MSI GT68xR LED support" + depends on LEDS_CLASS && USB_HID + ---help--- + Say Y here if you want to enable support for the MSI GT68xR LEDS + + This driver support following modes: + - Normal: LEDs are on + - Audio: LEDs brightness depends on sound level + - Breathing: LEDs brightness varies at human breathing rate + + You can also select which leds you want to enable. + + Currently the following devices are know to be supported: + - MSI GT683R + config HID_HUION tristate "Huion tablets" depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index fc712dd..7129311 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o obj-$(CONFIG_HID_ELECOM) += hid-elecom.o obj-$(CONFIG_HID_ELO) += hid-elo.o obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o +obj-$(CONFIG_HID_GT683R) += hid-gt683r.o obj-$(CONFIG_HID_GYRATION) += hid-gyration.o obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o obj-$(CONFIG_HID_HOLTEK) += hid-holtek-mouse.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index da52279..ec88fdb 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1827,6 +1827,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, { 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) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2) }, diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c new file mode 100644 index 0000000..132cc54 --- /dev/null +++ b/drivers/hid/hid-gt683r.c @@ -0,0 +1,318 @@ +/* + * MSI GT683R led driver + * + * Copyright (c) 2014 Janne Kanniainen <janne.kanniainen@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/device.h> +#include <linux/hid.h> +#include <linux/kernel.h> +#include <linux/leds.h> +#include <linux/module.h> + +#include "hid-ids.h" + +#define GT683R_BUFFER_SIZE 8 + +/* + * GT683R_LED_OFF: all LEDs are off + * GT683R_LED_AUDIO: LEDs brightness depends + * on sound level + * GT683R_LED_BREATHING: LEDs brightness varies + * at human breathing rate + * GT683R_LED_NORMAL: LEDs are on + */ +enum gt683r_led_mode { + GT683R_LED_OFF = 0, + GT683R_LED_AUDIO = 2, + GT683R_LED_BREATHING = 3, + GT683R_LED_NORMAL = 5 +}; + +enum gt683r_panels { + GT683R_LED_BACK, + GT683R_LED_SIDE, + GT683R_LED_FRONT, + GT683R_LED_COUNT, +}; + +static const char * const gt683r_panel_names[] = { + "back", + "side", + "front", +}; + +struct gt683r_led { + struct hid_device *hdev; + struct led_classdev led_devs[GT683R_LED_COUNT]; + struct mutex lock; + struct work_struct work; + enum led_brightness brightnesses[GT683R_LED_COUNT]; + enum gt683r_led_mode mode; +}; + +static const struct hid_device_id gt683r_led_id[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, + { } +}; + +static void gt683r_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + int i; + struct device *dev = led_cdev->dev->parent; + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct gt683r_led *led = hid_get_drvdata(hdev); + + for (i = 0; i < GT683R_LED_COUNT; i++) { + if (&led->led_devs[i] == led_cdev) + break; + } + + if (i < GT683R_LED_COUNT) { + led->brightnesses[i] = brightness; + schedule_work(&led->work); + } +} + +static ssize_t mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + u8 sysfs_mode; + struct hid_device *hdev = + container_of(dev, struct hid_device, dev); + struct gt683r_led *led = hid_get_drvdata(hdev); + + if (led->mode == GT683R_LED_NORMAL) + sysfs_mode = 0; + else if (led->mode == GT683R_LED_AUDIO) + sysfs_mode = 1; + else + sysfs_mode = 2; + + return scnprintf(buf, PAGE_SIZE, "%u\n", sysfs_mode); +} + +static ssize_t mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + u8 sysfs_mode; + struct hid_device *hdev = + container_of(dev, struct hid_device, dev); + struct gt683r_led *led = hid_get_drvdata(hdev); + + mutex_lock(&led->lock); + + if (kstrtou8(buf, 10, &sysfs_mode) || sysfs_mode > 2) { + count = -EINVAL; + goto fail; + } + + if (sysfs_mode == 0) + led->mode = GT683R_LED_NORMAL; + else if (sysfs_mode == 1) + led->mode = GT683R_LED_AUDIO; + else + led->mode = GT683R_LED_BREATHING; + +fail: + mutex_unlock(&led->lock); + + if (count != -EINVAL) + schedule_work(&led->work); + + return count; +} + +static int gt683r_led_snd_msg(struct gt683r_led *led, u8 *msg) +{ + int ret; + + ret = hid_hw_raw_request(led->hdev, msg[0], msg, GT683R_BUFFER_SIZE, + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); + if (ret != GT683R_BUFFER_SIZE) { + hid_err(led->hdev, + "failed to send set report request: %i\n", ret); + if (ret < 0) + return ret; + return -EIO; + } + + return 0; +} + +static int gt683r_leds_set(struct gt683r_led *led, u8 leds) +{ + int ret; + u8 *buffer; + + buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + buffer[0] = 0x01; + buffer[1] = 0x02; + buffer[2] = 0x30; + buffer[3] = leds; + ret = gt683r_led_snd_msg(led, buffer); + + kfree(buffer); + return ret; +} + +static int gt683r_mode_set(struct gt683r_led *led, u8 mode) +{ + int ret; + u8 *buffer; + + buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + buffer[0] = 0x01; + buffer[1] = 0x02; + buffer[2] = 0x20; + buffer[3] = mode; + buffer[4] = 0x01; + ret = gt683r_led_snd_msg(led, buffer); + + kfree(buffer); + return ret; +} + +static void gt683r_led_work(struct work_struct *work) +{ + u8 leds = 0, mode; + struct gt683r_led *led = + container_of(work, struct gt683r_led, work); + + mutex_lock(&led->lock); + + if (led->brightnesses[GT683R_LED_BACK]) + leds |= BIT(GT683R_LED_BACK); + + if (led->brightnesses[GT683R_LED_SIDE]) + leds |= BIT(GT683R_LED_SIDE); + + if (led->brightnesses[GT683R_LED_FRONT]) + leds |= BIT(GT683R_LED_FRONT); + + if (gt683r_leds_set(led, leds)) + goto fail; + + if (leds) + mode = led->mode; + else + mode = GT683R_LED_OFF; + + gt683r_mode_set(led, mode); +fail: + mutex_unlock(&led->lock); +} + +static DEVICE_ATTR_RW(mode); + +static int gt683r_led_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + int ret, i, name_sz; + char *name; + struct gt683r_led *led; + + led = devm_kzalloc(&hdev->dev, sizeof(struct gt683r_led), GFP_KERNEL); + if (!led) + return -ENOMEM; + + led->mode = GT683R_LED_NORMAL; + led->hdev = hdev; + hid_set_drvdata(hdev, led); + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "hid parsing failed\n"); + goto fail; + } + + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); + if (ret) { + hid_err(hdev, "hw start failed\n"); + goto fail; + } + + for (i = 0; i < GT683R_LED_COUNT; i++) { + name_sz = strlen(dev_name(&hdev->dev)) + + strlen(gt683r_panel_names[i]) + 3; + + name = devm_kzalloc(&hdev->dev, sizeof(char) * name_sz, + GFP_KERNEL); + + snprintf(name, name_sz, "%s::%s", + dev_name(&hdev->dev), gt683r_panel_names[i]); + led->led_devs[i].name = name; + led->led_devs[i].max_brightness = 1; + led->led_devs[i].brightness_set = gt683r_brightness_set; + ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); + if (ret) { + hid_err(hdev, "could not register led device\n"); + goto fail2; + } + } + + ret = device_create_file(&led->hdev->dev, + &dev_attr_mode); + if (ret) { + hid_err(hdev, "could not make mode attribute file\n"); + goto fail2; + } + + mutex_init(&led->lock); + INIT_WORK(&led->work, gt683r_led_work); + + return 0; + +fail2: + for (; i > 0; i--) + led_classdev_unregister(&led->led_devs[i]); + hid_hw_stop(hdev); +fail: + return ret; +} + +static void gt683r_led_remove(struct hid_device *hdev) +{ + int i; + struct gt683r_led *led = hid_get_drvdata(hdev); + + for (i = 0; i < GT683R_LED_COUNT; i++) + led_classdev_unregister(&led->led_devs[i]); + device_remove_file(&hdev->dev, + &dev_attr_mode); + flush_work(&led->work); + hid_hw_stop(hdev); +} + +static struct hid_driver gt683r_led_driver = { + .probe = gt683r_led_probe, + .remove = gt683r_led_remove, + .name = "gt683r_led", + .id_table = gt683r_led_id, +}; + +module_hid_driver(gt683r_led_driver); + +MODULE_AUTHOR("Janne Kanniainen"); +MODULE_DESCRIPTION("MSI GT683R led driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 34bb220..3692d37 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -641,7 +641,7 @@ #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 #define USB_VENDOR_ID_MSI 0x1770 -#define USB_DEVICE_ID_MSI_GX680R_LED_PANEL 0xff00 +#define USB_DEVICE_ID_MSI_GT683R_LED_PANEL 0xff00 #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400 #define USB_DEVICE_ID_N_S_HARMONY 0xc359 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 8e4ddb3..c640e1d 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -73,7 +73,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, - { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, 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 }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS }, -- 1.9.2 ^ permalink raw reply related [flat|nested] 81+ messages in thread
* [PATCH v6] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-16 17:23 ` [PATCH v6] " Janne Kanniainen @ 2014-06-16 22:01 ` Janne Kanniainen 2014-06-17 13:46 ` Johan Hovold 0 siblings, 1 reply; 81+ messages in thread From: Janne Kanniainen @ 2014-06-16 22:01 UTC (permalink / raw) To: jkosina Cc: johan, cooloney, linux-kernel, linux-leds, linux-usb, linux-input, Janne Kanniainen This driver adds support for USB controlled led panels that exists in MSI GT683R laptop Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> --- Changes in v2: - sorted headers to alphabetic order - using devm_kzalloc - using BIT(n) - using usb_control_msg instead of usb_submit_urb - removing unneeded code Changes in v3: - implemented as HID device - some cleanups and bug fixes Changes in v4: - more cleanups - support for selecting leds - suppport for selecting status Changes in v5: - mode attribute documented under Documentation/ABI - made array for led_classdev - led devices uses now recommended naming scheme Changes in v6: - flush_work added - using hid device name instead of hard coded gt683r - allocating name buffers with devm_kzalloc There was a bug with "for", so I fixed it. .../ABI/testing/sysfs-class-hid-driver-gt683r | 14 + drivers/hid/Kconfig | 16 ++ drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-gt683r.c | 318 +++++++++++++++++++++ drivers/hid/hid-ids.h | 2 +- drivers/hid/usbhid/hid-quirks.c | 2 +- 7 files changed, 352 insertions(+), 2 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-class-hid-driver-gt683r create mode 100644 drivers/hid/hid-gt683r.c diff --git a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r new file mode 100644 index 0000000..6d0bd80 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r @@ -0,0 +1,14 @@ +What: /sys/class/hidraw/<hidraw>/device/mode +Date: Jun 2014 +KernelVersion: 3.17 +Contact: Janne Kanniainen <janne.kanniainen@gmail.com> +Description: + Set the mode of LEDs + + 0 - normal + 1 - audio + 2 - breathing + + Normal: LEDs are on + Audio: LEDs brightness depends on sound level + Breathing: LEDs brightness varies at human breathing rate \ No newline at end of file diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 7af9d0b..b88cabd 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -261,6 +261,22 @@ config HOLTEK_FF Say Y here if you have a Holtek On Line Grip based game controller and want to have force feedback support for it. +config HID_GT683R + tristate "MSI GT68xR LED support" + depends on LEDS_CLASS && USB_HID + ---help--- + Say Y here if you want to enable support for the MSI GT68xR LEDS + + This driver support following modes: + - Normal: LEDs are on + - Audio: LEDs brightness depends on sound level + - Breathing: LEDs brightness varies at human breathing rate + + You can also select which leds you want to enable. + + Currently the following devices are know to be supported: + - MSI GT683R + config HID_HUION tristate "Huion tablets" depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index fc712dd..7129311 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o obj-$(CONFIG_HID_ELECOM) += hid-elecom.o obj-$(CONFIG_HID_ELO) += hid-elo.o obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o +obj-$(CONFIG_HID_GT683R) += hid-gt683r.o obj-$(CONFIG_HID_GYRATION) += hid-gyration.o obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o obj-$(CONFIG_HID_HOLTEK) += hid-holtek-mouse.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index da52279..ec88fdb 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1827,6 +1827,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, { 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) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2) }, diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c new file mode 100644 index 0000000..1b16250 --- /dev/null +++ b/drivers/hid/hid-gt683r.c @@ -0,0 +1,318 @@ +/* + * MSI GT683R led driver + * + * Copyright (c) 2014 Janne Kanniainen <janne.kanniainen@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/device.h> +#include <linux/hid.h> +#include <linux/kernel.h> +#include <linux/leds.h> +#include <linux/module.h> + +#include "hid-ids.h" + +#define GT683R_BUFFER_SIZE 8 + +/* + * GT683R_LED_OFF: all LEDs are off + * GT683R_LED_AUDIO: LEDs brightness depends + * on sound level + * GT683R_LED_BREATHING: LEDs brightness varies + * at human breathing rate + * GT683R_LED_NORMAL: LEDs are on + */ +enum gt683r_led_mode { + GT683R_LED_OFF = 0, + GT683R_LED_AUDIO = 2, + GT683R_LED_BREATHING = 3, + GT683R_LED_NORMAL = 5 +}; + +enum gt683r_panels { + GT683R_LED_BACK, + GT683R_LED_SIDE, + GT683R_LED_FRONT, + GT683R_LED_COUNT, +}; + +static const char * const gt683r_panel_names[] = { + "back", + "side", + "front", +}; + +struct gt683r_led { + struct hid_device *hdev; + struct led_classdev led_devs[GT683R_LED_COUNT]; + struct mutex lock; + struct work_struct work; + enum led_brightness brightnesses[GT683R_LED_COUNT]; + enum gt683r_led_mode mode; +}; + +static const struct hid_device_id gt683r_led_id[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, + { } +}; + +static void gt683r_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + int i; + struct device *dev = led_cdev->dev->parent; + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct gt683r_led *led = hid_get_drvdata(hdev); + + for (i = 0; i < GT683R_LED_COUNT; i++) { + if (&led->led_devs[i] == led_cdev) + break; + } + + if (i < GT683R_LED_COUNT) { + led->brightnesses[i] = brightness; + schedule_work(&led->work); + } +} + +static ssize_t mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + u8 sysfs_mode; + struct hid_device *hdev = + container_of(dev, struct hid_device, dev); + struct gt683r_led *led = hid_get_drvdata(hdev); + + if (led->mode == GT683R_LED_NORMAL) + sysfs_mode = 0; + else if (led->mode == GT683R_LED_AUDIO) + sysfs_mode = 1; + else + sysfs_mode = 2; + + return scnprintf(buf, PAGE_SIZE, "%u\n", sysfs_mode); +} + +static ssize_t mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + u8 sysfs_mode; + struct hid_device *hdev = + container_of(dev, struct hid_device, dev); + struct gt683r_led *led = hid_get_drvdata(hdev); + + mutex_lock(&led->lock); + + if (kstrtou8(buf, 10, &sysfs_mode) || sysfs_mode > 2) { + count = -EINVAL; + goto fail; + } + + if (sysfs_mode == 0) + led->mode = GT683R_LED_NORMAL; + else if (sysfs_mode == 1) + led->mode = GT683R_LED_AUDIO; + else + led->mode = GT683R_LED_BREATHING; + +fail: + mutex_unlock(&led->lock); + + if (count != -EINVAL) + schedule_work(&led->work); + + return count; +} + +static int gt683r_led_snd_msg(struct gt683r_led *led, u8 *msg) +{ + int ret; + + ret = hid_hw_raw_request(led->hdev, msg[0], msg, GT683R_BUFFER_SIZE, + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); + if (ret != GT683R_BUFFER_SIZE) { + hid_err(led->hdev, + "failed to send set report request: %i\n", ret); + if (ret < 0) + return ret; + return -EIO; + } + + return 0; +} + +static int gt683r_leds_set(struct gt683r_led *led, u8 leds) +{ + int ret; + u8 *buffer; + + buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + buffer[0] = 0x01; + buffer[1] = 0x02; + buffer[2] = 0x30; + buffer[3] = leds; + ret = gt683r_led_snd_msg(led, buffer); + + kfree(buffer); + return ret; +} + +static int gt683r_mode_set(struct gt683r_led *led, u8 mode) +{ + int ret; + u8 *buffer; + + buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + buffer[0] = 0x01; + buffer[1] = 0x02; + buffer[2] = 0x20; + buffer[3] = mode; + buffer[4] = 0x01; + ret = gt683r_led_snd_msg(led, buffer); + + kfree(buffer); + return ret; +} + +static void gt683r_led_work(struct work_struct *work) +{ + u8 leds = 0, mode; + struct gt683r_led *led = + container_of(work, struct gt683r_led, work); + + mutex_lock(&led->lock); + + if (led->brightnesses[GT683R_LED_BACK]) + leds |= BIT(GT683R_LED_BACK); + + if (led->brightnesses[GT683R_LED_SIDE]) + leds |= BIT(GT683R_LED_SIDE); + + if (led->brightnesses[GT683R_LED_FRONT]) + leds |= BIT(GT683R_LED_FRONT); + + if (gt683r_leds_set(led, leds)) + goto fail; + + if (leds) + mode = led->mode; + else + mode = GT683R_LED_OFF; + + gt683r_mode_set(led, mode); +fail: + mutex_unlock(&led->lock); +} + +static DEVICE_ATTR_RW(mode); + +static int gt683r_led_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + int ret, i, name_sz; + char *name; + struct gt683r_led *led; + + led = devm_kzalloc(&hdev->dev, sizeof(struct gt683r_led), GFP_KERNEL); + if (!led) + return -ENOMEM; + + led->mode = GT683R_LED_NORMAL; + led->hdev = hdev; + hid_set_drvdata(hdev, led); + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "hid parsing failed\n"); + goto fail; + } + + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); + if (ret) { + hid_err(hdev, "hw start failed\n"); + goto fail; + } + + for (i = 0; i < GT683R_LED_COUNT; i++) { + name_sz = strlen(dev_name(&hdev->dev)) + + strlen(gt683r_panel_names[i]) + 3; + + name = devm_kzalloc(&hdev->dev, sizeof(char) * name_sz, + GFP_KERNEL); + + snprintf(name, name_sz, "%s::%s", + dev_name(&hdev->dev), gt683r_panel_names[i]); + led->led_devs[i].name = name; + led->led_devs[i].max_brightness = 1; + led->led_devs[i].brightness_set = gt683r_brightness_set; + ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); + if (ret) { + hid_err(hdev, "could not register led device\n"); + goto fail2; + } + } + + ret = device_create_file(&led->hdev->dev, + &dev_attr_mode); + if (ret) { + hid_err(hdev, "could not make mode attribute file\n"); + goto fail2; + } + + mutex_init(&led->lock); + INIT_WORK(&led->work, gt683r_led_work); + + return 0; + +fail2: + for (; i >= 0; i--) + led_classdev_unregister(&led->led_devs[i]); + hid_hw_stop(hdev); +fail: + return ret; +} + +static void gt683r_led_remove(struct hid_device *hdev) +{ + int i; + struct gt683r_led *led = hid_get_drvdata(hdev); + + for (i = 0; i < GT683R_LED_COUNT; i++) + led_classdev_unregister(&led->led_devs[i]); + device_remove_file(&hdev->dev, + &dev_attr_mode); + flush_work(&led->work); + hid_hw_stop(hdev); +} + +static struct hid_driver gt683r_led_driver = { + .probe = gt683r_led_probe, + .remove = gt683r_led_remove, + .name = "gt683r_led", + .id_table = gt683r_led_id, +}; + +module_hid_driver(gt683r_led_driver); + +MODULE_AUTHOR("Janne Kanniainen"); +MODULE_DESCRIPTION("MSI GT683R led driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 34bb220..3692d37 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -641,7 +641,7 @@ #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 #define USB_VENDOR_ID_MSI 0x1770 -#define USB_DEVICE_ID_MSI_GX680R_LED_PANEL 0xff00 +#define USB_DEVICE_ID_MSI_GT683R_LED_PANEL 0xff00 #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400 #define USB_DEVICE_ID_N_S_HARMONY 0xc359 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 8e4ddb3..c640e1d 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -73,7 +73,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, - { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, 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 }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS }, -- 1.9.2 ^ permalink raw reply related [flat|nested] 81+ messages in thread
* Re: [PATCH v6] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-16 22:01 ` Janne Kanniainen @ 2014-06-17 13:46 ` Johan Hovold 2014-06-17 16:41 ` [PATCH v8] " Janne Kanniainen 0 siblings, 1 reply; 81+ messages in thread From: Johan Hovold @ 2014-06-17 13:46 UTC (permalink / raw) To: Janne Kanniainen Cc: jkosina, johan, cooloney, linux-kernel, linux-leds, linux-usb, linux-input On Tue, Jun 17, 2014 at 01:01:55AM +0300, Janne Kanniainen wrote: > This driver adds support for USB controlled led panels that exists in > MSI GT683R laptop > > Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> > --- > Changes in v2: > - sorted headers to alphabetic order > - using devm_kzalloc > - using BIT(n) > - using usb_control_msg instead of usb_submit_urb > - removing unneeded code > > Changes in v3: > - implemented as HID device > - some cleanups and bug fixes > > Changes in v4: > - more cleanups > - support for selecting leds > - suppport for selecting status > > Changes in v5: > - mode attribute documented under Documentation/ABI > - made array for led_classdev > - led devices uses now recommended naming scheme > > Changes in v6: > - flush_work added > - using hid device name instead of hard coded gt683r > - allocating name buffers with devm_kzalloc > > There was a bug with "for", so I fixed it. Then it really was a v7 and should have been marked as such, right? > .../ABI/testing/sysfs-class-hid-driver-gt683r | 14 + > drivers/hid/Kconfig | 16 ++ > drivers/hid/Makefile | 1 + > drivers/hid/hid-core.c | 1 + > drivers/hid/hid-gt683r.c | 318 +++++++++++++++++++++ > drivers/hid/hid-ids.h | 2 +- > drivers/hid/usbhid/hid-quirks.c | 2 +- > 7 files changed, 352 insertions(+), 2 deletions(-) > create mode 100644 Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > create mode 100644 drivers/hid/hid-gt683r.c > > diff --git a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > new file mode 100644 > index 0000000..6d0bd80 > --- /dev/null > +++ b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > @@ -0,0 +1,14 @@ > +What: /sys/class/hidraw/<hidraw>/device/mode Perhaps you should name this "leds_mode" or "led_panel_mode", or similar (only change the attribute name, code is fine otherwise). This is an attribute of the parent HID device, but it's not really apparent what just "mode" would mean for such a device. > +Date: Jun 2014 > +KernelVersion: 3.17 > +Contact: Janne Kanniainen <janne.kanniainen@gmail.com> > +Description: > + Set the mode of LEDs > + > + 0 - normal > + 1 - audio > + 2 - breathing > + > + Normal: LEDs are on Change this to "LEDs are fully on when enabled", or similar? > + Audio: LEDs brightness depends on sound level > + Breathing: LEDs brightness varies at human breathing rate > \ No newline at end of file > diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig > index 7af9d0b..b88cabd 100644 > --- a/drivers/hid/Kconfig > +++ b/drivers/hid/Kconfig > @@ -261,6 +261,22 @@ config HOLTEK_FF > Say Y here if you have a Holtek On Line Grip based game controller > and want to have force feedback support for it. > > +config HID_GT683R > + tristate "MSI GT68xR LED support" > + depends on LEDS_CLASS && USB_HID > + ---help--- > + Say Y here if you want to enable support for the MSI GT68xR LEDS > + > + This driver support following modes: > + - Normal: LEDs are on > + - Audio: LEDs brightness depends on sound level > + - Breathing: LEDs brightness varies at human breathing rate This might need an update as well. > + > + You can also select which leds you want to enable. You could drop this line, and just say "enable support for the three MSI" LEDs above? > + > + Currently the following devices are know to be supported: > + - MSI GT683R > + > config HID_HUION > tristate "Huion tablets" > depends on USB_HID > diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile > index fc712dd..7129311 100644 > --- a/drivers/hid/Makefile > +++ b/drivers/hid/Makefile > @@ -48,6 +48,7 @@ obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o > obj-$(CONFIG_HID_ELECOM) += hid-elecom.o > obj-$(CONFIG_HID_ELO) += hid-elo.o > obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o > +obj-$(CONFIG_HID_GT683R) += hid-gt683r.o > obj-$(CONFIG_HID_GYRATION) += hid-gyration.o > obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o > obj-$(CONFIG_HID_HOLTEK) += hid-holtek-mouse.o > diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c > index da52279..ec88fdb 100644 > --- a/drivers/hid/hid-core.c > +++ b/drivers/hid/hid-core.c > @@ -1827,6 +1827,7 @@ static const struct hid_device_id hid_have_special_driver[] = { > { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, > { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, > { 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) }, > { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) }, > { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2) }, > diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c > new file mode 100644 > index 0000000..1b16250 > --- /dev/null > +++ b/drivers/hid/hid-gt683r.c > @@ -0,0 +1,318 @@ > +/* > + * MSI GT683R led driver > + * > + * Copyright (c) 2014 Janne Kanniainen <janne.kanniainen@gmail.com> > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation; either version 2 of > + * the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + */ > + > +#include <linux/device.h> > +#include <linux/hid.h> > +#include <linux/kernel.h> > +#include <linux/leds.h> > +#include <linux/module.h> > + > +#include "hid-ids.h" > + > +#define GT683R_BUFFER_SIZE 8 > + > +/* > + * GT683R_LED_OFF: all LEDs are off > + * GT683R_LED_AUDIO: LEDs brightness depends > + * on sound level > + * GT683R_LED_BREATHING: LEDs brightness varies > + * at human breathing rate No need to break these two lines (they would still be below 80 cols wide). > + * GT683R_LED_NORMAL: LEDs are on > + */ > +enum gt683r_led_mode { > + GT683R_LED_OFF = 0, > + GT683R_LED_AUDIO = 2, > + GT683R_LED_BREATHING = 3, > + GT683R_LED_NORMAL = 5 > +}; > + > +enum gt683r_panels { > + GT683R_LED_BACK, > + GT683R_LED_SIDE, > + GT683R_LED_FRONT, Perhaps initialise these three explicitly as the order really isn't arbitrary? > + GT683R_LED_COUNT, > +}; > + > +static const char * const gt683r_panel_names[] = { > + "back", > + "side", > + "front", > +}; > + > +struct gt683r_led { > + struct hid_device *hdev; > + struct led_classdev led_devs[GT683R_LED_COUNT]; > + struct mutex lock; > + struct work_struct work; > + enum led_brightness brightnesses[GT683R_LED_COUNT]; > + enum gt683r_led_mode mode; > +}; > + > +static const struct hid_device_id gt683r_led_id[] = { > + { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, > + { } > +}; > + > +static void gt683r_brightness_set(struct led_classdev *led_cdev, > + enum led_brightness brightness) > +{ > + int i; > + struct device *dev = led_cdev->dev->parent; > + struct hid_device *hdev = container_of(dev, struct hid_device, dev); > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + for (i = 0; i < GT683R_LED_COUNT; i++) { > + if (&led->led_devs[i] == led_cdev) > + break; > + } > + > + if (i < GT683R_LED_COUNT) { > + led->brightnesses[i] = brightness; > + schedule_work(&led->work); > + } > +} > + > +static ssize_t mode_show(struct device *dev, > + struct device_attribute *attr, > + char *buf) > +{ > + u8 sysfs_mode; > + struct hid_device *hdev = > + container_of(dev, struct hid_device, dev); No need to break this (still < 80 cols). > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + if (led->mode == GT683R_LED_NORMAL) > + sysfs_mode = 0; > + else if (led->mode == GT683R_LED_AUDIO) > + sysfs_mode = 1; > + else > + sysfs_mode = 2; > + > + return scnprintf(buf, PAGE_SIZE, "%u\n", sysfs_mode); > +} > + > +static ssize_t mode_store(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t count) > +{ > + u8 sysfs_mode; > + struct hid_device *hdev = > + container_of(dev, struct hid_device, dev); No need to break this (still < 80 cols). > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + mutex_lock(&led->lock); > + > + if (kstrtou8(buf, 10, &sysfs_mode) || sysfs_mode > 2) { > + count = -EINVAL; > + goto fail; > + } > + > + if (sysfs_mode == 0) > + led->mode = GT683R_LED_NORMAL; > + else if (sysfs_mode == 1) > + led->mode = GT683R_LED_AUDIO; > + else > + led->mode = GT683R_LED_BREATHING; > + > +fail: > + mutex_unlock(&led->lock); > + > + if (count != -EINVAL) > + schedule_work(&led->work); > + > + return count; > +} This could be simplified somewhat as the lock only needs to protect the assignment to led->mode. (Glad to see you realised I meant kstrouX when I wrote snprintf. ;)) > + > +static int gt683r_led_snd_msg(struct gt683r_led *led, u8 *msg) > +{ > + int ret; > + > + ret = hid_hw_raw_request(led->hdev, msg[0], msg, GT683R_BUFFER_SIZE, > + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); > + if (ret != GT683R_BUFFER_SIZE) { > + hid_err(led->hdev, > + "failed to send set report request: %i\n", ret); > + if (ret < 0) > + return ret; > + return -EIO; > + } > + > + return 0; > +} > + > +static int gt683r_leds_set(struct gt683r_led *led, u8 leds) > +{ > + int ret; > + u8 *buffer; > + > + buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); > + if (!buffer) > + return -ENOMEM; > + > + buffer[0] = 0x01; > + buffer[1] = 0x02; > + buffer[2] = 0x30; > + buffer[3] = leds; > + ret = gt683r_led_snd_msg(led, buffer); > + > + kfree(buffer); > + return ret; > +} > + > +static int gt683r_mode_set(struct gt683r_led *led, u8 mode) > +{ > + int ret; > + u8 *buffer; > + > + buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); > + if (!buffer) > + return -ENOMEM; > + > + buffer[0] = 0x01; > + buffer[1] = 0x02; > + buffer[2] = 0x20; > + buffer[3] = mode; > + buffer[4] = 0x01; > + ret = gt683r_led_snd_msg(led, buffer); > + > + kfree(buffer); > + return ret; > +} > + > +static void gt683r_led_work(struct work_struct *work) > +{ > + u8 leds = 0, mode; Try to stick to one definition per line (throughout), especially if you're initialising as well. > + struct gt683r_led *led = > + container_of(work, struct gt683r_led, work); > + > + mutex_lock(&led->lock); > + > + if (led->brightnesses[GT683R_LED_BACK]) > + leds |= BIT(GT683R_LED_BACK); > + > + if (led->brightnesses[GT683R_LED_SIDE]) > + leds |= BIT(GT683R_LED_SIDE); > + > + if (led->brightnesses[GT683R_LED_FRONT]) > + leds |= BIT(GT683R_LED_FRONT); This could of course be implemented as a loop as well, if you want... > + > + if (gt683r_leds_set(led, leds)) > + goto fail; > + > + if (leds) > + mode = led->mode; > + else > + mode = GT683R_LED_OFF; > + > + gt683r_mode_set(led, mode); > +fail: > + mutex_unlock(&led->lock); > +} > + > +static DEVICE_ATTR_RW(mode); > + > +static int gt683r_led_probe(struct hid_device *hdev, > + const struct hid_device_id *id) > +{ > + int ret, i, name_sz; > + char *name; > + struct gt683r_led *led; > + > + led = devm_kzalloc(&hdev->dev, sizeof(struct gt683r_led), GFP_KERNEL); > + if (!led) > + return -ENOMEM; > + > + led->mode = GT683R_LED_NORMAL; > + led->hdev = hdev; > + hid_set_drvdata(hdev, led); > + > + ret = hid_parse(hdev); > + if (ret) { > + hid_err(hdev, "hid parsing failed\n"); > + goto fail; Just return ret here. > + } > + > + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); > + if (ret) { > + hid_err(hdev, "hw start failed\n"); > + goto fail; > + } > + > + for (i = 0; i < GT683R_LED_COUNT; i++) { > + name_sz = strlen(dev_name(&hdev->dev)) + > + strlen(gt683r_panel_names[i]) + 3; > + > + name = devm_kzalloc(&hdev->dev, sizeof(char) * name_sz, > + GFP_KERNEL); Must check for allocation failure still. > + > + snprintf(name, name_sz, "%s::%s", > + dev_name(&hdev->dev), gt683r_panel_names[i]); > + led->led_devs[i].name = name; > + led->led_devs[i].max_brightness = 1; > + led->led_devs[i].brightness_set = gt683r_brightness_set; > + ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); > + if (ret) { > + hid_err(hdev, "could not register led device\n"); > + goto fail2; > + } > + } > + > + ret = device_create_file(&led->hdev->dev, > + &dev_attr_mode); No need to break line. > + if (ret) { > + hid_err(hdev, "could not make mode attribute file\n"); > + goto fail2; > + } > + > + mutex_init(&led->lock); > + INIT_WORK(&led->work, gt683r_led_work); > + > + return 0; > + > +fail2: > + for (; i >= 0; i--) You must initialise i to (i - 1) as well (either led_class_devregister failed or i == GT683R_LED_COUNT here). > + led_classdev_unregister(&led->led_devs[i]); > + hid_hw_stop(hdev); > +fail: > + return ret; > +} > + > +static void gt683r_led_remove(struct hid_device *hdev) > +{ > + int i; > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + for (i = 0; i < GT683R_LED_COUNT; i++) > + led_classdev_unregister(&led->led_devs[i]); > + device_remove_file(&hdev->dev, > + &dev_attr_mode); No need to break line. Perhaps do the removal before unregistering to reverse probe. > + flush_work(&led->work); > + hid_hw_stop(hdev); > +} > + > +static struct hid_driver gt683r_led_driver = { > + .probe = gt683r_led_probe, > + .remove = gt683r_led_remove, > + .name = "gt683r_led", > + .id_table = gt683r_led_id, > +}; > + > +module_hid_driver(gt683r_led_driver); > + > +MODULE_AUTHOR("Janne Kanniainen"); > +MODULE_DESCRIPTION("MSI GT683R led driver"); > +MODULE_LICENSE("GPL"); > diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h > index 34bb220..3692d37 100644 > --- a/drivers/hid/hid-ids.h > +++ b/drivers/hid/hid-ids.h > @@ -641,7 +641,7 @@ > #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 > > #define USB_VENDOR_ID_MSI 0x1770 > -#define USB_DEVICE_ID_MSI_GX680R_LED_PANEL 0xff00 > +#define USB_DEVICE_ID_MSI_GT683R_LED_PANEL 0xff00 > > #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400 > #define USB_DEVICE_ID_N_S_HARMONY 0xc359 > diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c > index 8e4ddb3..c640e1d 100644 > --- a/drivers/hid/usbhid/hid-quirks.c > +++ b/drivers/hid/usbhid/hid-quirks.c > @@ -73,7 +73,7 @@ static const struct hid_blacklist { > { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, > { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, > { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, > - { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, 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 }, > { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS }, Johan ^ permalink raw reply [flat|nested] 81+ messages in thread
* [PATCH v8] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-17 13:46 ` Johan Hovold @ 2014-06-17 16:41 ` Janne Kanniainen [not found] ` <1403023304-7953-1-git-send-email-janne.kanniainen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 0 siblings, 1 reply; 81+ messages in thread From: Janne Kanniainen @ 2014-06-17 16:41 UTC (permalink / raw) To: jkosina Cc: johan, cooloney, linux-kernel, linux-leds, linux-usb, linux-input, Janne Kanniainen This driver adds support for USB controlled led panels that exists in MSI GT683R laptop Changes in v2: - sorted headers to alphabetic order - using devm_kzalloc - using BIT(n) - using usb_control_msg instead of usb_submit_urb - removing unneeded code Changes in v3: - implemented as HID device - some cleanups and bug fixes Changes in v4: - more cleanups - support for selecting leds - suppport for selecting status Changes in v5: - mode attribute documented under Documentation/ABI - made array for led_classdev - led devices uses now recommended naming scheme Changes in v6: - flush_work added - using hid device name instead of hard coded gt683r - allocating name buffers with devm_kzalloc Changes in v7: - buf with for fixed Changes in v8: - some cleanups and bugs fixed Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> --- .../ABI/testing/sysfs-class-hid-driver-gt683r | 14 + drivers/hid/Kconfig | 14 + drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-gt683r.c | 308 +++++++++++++++++++++ drivers/hid/hid-ids.h | 2 +- drivers/hid/usbhid/hid-quirks.c | 2 +- 7 files changed, 340 insertions(+), 2 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-class-hid-driver-gt683r create mode 100644 drivers/hid/hid-gt683r.c diff --git a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r new file mode 100644 index 0000000..317e9d5 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r @@ -0,0 +1,14 @@ +What: /sys/class/hidraw/<hidraw>/device/leds_mode +Date: Jun 2014 +KernelVersion: 3.17 +Contact: Janne Kanniainen <janne.kanniainen@gmail.com> +Description: + Set the mode of LEDs + + 0 - normal + 1 - audio + 2 - breathing + + Normal: LEDs are fully on when enabled + Audio: LEDs brightness depends on sound level + Breathing: LEDs brightness varies at human breathing rate \ No newline at end of file diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 7af9d0b..e2f4590 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -261,6 +261,20 @@ config HOLTEK_FF Say Y here if you have a Holtek On Line Grip based game controller and want to have force feedback support for it. +config HID_GT683R + tristate "MSI GT68xR LED support" + depends on LEDS_CLASS && USB_HID + ---help--- + Say Y here if you want to enable support for the three MSI GT68xR LEDs + + This driver support following modes: + - Normal: LEDs are fully on when enabled + - Audio: LEDs brightness depends on sound level + - Breathing: LEDs brightness varies at human breathing rate + + Currently the following devices are know to be supported: + - MSI GT683R + config HID_HUION tristate "Huion tablets" depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index fc712dd..7129311 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o obj-$(CONFIG_HID_ELECOM) += hid-elecom.o obj-$(CONFIG_HID_ELO) += hid-elo.o obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o +obj-$(CONFIG_HID_GT683R) += hid-gt683r.o obj-$(CONFIG_HID_GYRATION) += hid-gyration.o obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o obj-$(CONFIG_HID_HOLTEK) += hid-holtek-mouse.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index da52279..ec88fdb 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1827,6 +1827,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, { 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) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2) }, diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c new file mode 100644 index 0000000..19959ac --- /dev/null +++ b/drivers/hid/hid-gt683r.c @@ -0,0 +1,308 @@ +/* + * MSI GT683R led driver + * + * Copyright (c) 2014 Janne Kanniainen <janne.kanniainen@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/device.h> +#include <linux/hid.h> +#include <linux/kernel.h> +#include <linux/leds.h> +#include <linux/module.h> + +#include "hid-ids.h" + +#define GT683R_BUFFER_SIZE 8 + +/* + * GT683R_LED_OFF: all LEDs are off + * GT683R_LED_AUDIO: LEDs brightness depends on sound level + * GT683R_LED_BREATHING: LEDs brightness varies at human breathing rate + * GT683R_LED_NORMAL: LEDs are fully on when enabled + */ +enum gt683r_led_mode { + GT683R_LED_OFF = 0, + GT683R_LED_AUDIO = 2, + GT683R_LED_BREATHING = 3, + GT683R_LED_NORMAL = 5 +}; + +enum gt683r_panels { + GT683R_LED_BACK = 0, + GT683R_LED_SIDE = 1, + GT683R_LED_FRONT = 2, + GT683R_LED_COUNT, +}; + +static const char * const gt683r_panel_names[] = { + "back", + "side", + "front", +}; + +struct gt683r_led { + struct hid_device *hdev; + struct led_classdev led_devs[GT683R_LED_COUNT]; + struct mutex lock; + struct work_struct work; + enum led_brightness brightnesses[GT683R_LED_COUNT]; + enum gt683r_led_mode mode; +}; + +static const struct hid_device_id gt683r_led_id[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, + { } +}; + +static void gt683r_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + int i; + struct device *dev = led_cdev->dev->parent; + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct gt683r_led *led = hid_get_drvdata(hdev); + + for (i = 0; i < GT683R_LED_COUNT; i++) { + if (&led->led_devs[i] == led_cdev) + break; + } + + if (i < GT683R_LED_COUNT) { + led->brightnesses[i] = brightness; + schedule_work(&led->work); + } +} + +static ssize_t leds_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + u8 sysfs_mode; + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct gt683r_led *led = hid_get_drvdata(hdev); + + if (led->mode == GT683R_LED_NORMAL) + sysfs_mode = 0; + else if (led->mode == GT683R_LED_AUDIO) + sysfs_mode = 1; + else + sysfs_mode = 2; + + return scnprintf(buf, PAGE_SIZE, "%u\n", sysfs_mode); +} + +static ssize_t leds_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + u8 sysfs_mode; + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct gt683r_led *led = hid_get_drvdata(hdev); + + + if (kstrtou8(buf, 10, &sysfs_mode) || sysfs_mode > 2) + return -EINVAL; + + mutex_lock(&led->lock); + + if (sysfs_mode == 0) + led->mode = GT683R_LED_NORMAL; + else if (sysfs_mode == 1) + led->mode = GT683R_LED_AUDIO; + else + led->mode = GT683R_LED_BREATHING; + + mutex_unlock(&led->lock); + schedule_work(&led->work); + + return count; +} + +static int gt683r_led_snd_msg(struct gt683r_led *led, u8 *msg) +{ + int ret; + + ret = hid_hw_raw_request(led->hdev, msg[0], msg, GT683R_BUFFER_SIZE, + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); + if (ret != GT683R_BUFFER_SIZE) { + hid_err(led->hdev, + "failed to send set report request: %i\n", ret); + if (ret < 0) + return ret; + return -EIO; + } + + return 0; +} + +static int gt683r_leds_set(struct gt683r_led *led, u8 leds) +{ + int ret; + u8 *buffer; + + buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + buffer[0] = 0x01; + buffer[1] = 0x02; + buffer[2] = 0x30; + buffer[3] = leds; + ret = gt683r_led_snd_msg(led, buffer); + + kfree(buffer); + return ret; +} + +static int gt683r_mode_set(struct gt683r_led *led, u8 mode) +{ + int ret; + u8 *buffer; + + buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + buffer[0] = 0x01; + buffer[1] = 0x02; + buffer[2] = 0x20; + buffer[3] = mode; + buffer[4] = 0x01; + ret = gt683r_led_snd_msg(led, buffer); + + kfree(buffer); + return ret; +} + +static void gt683r_led_work(struct work_struct *work) +{ + int i; + u8 leds = 0; + u8 mode; + struct gt683r_led *led = container_of(work, struct gt683r_led, work); + + mutex_lock(&led->lock); + + for (i = 0; i < GT683R_LED_COUNT; i++) { + if (led->brightnesses[i]) + leds |= BIT(i); + } + + if (gt683r_leds_set(led, leds)) + goto fail; + + if (leds) + mode = led->mode; + else + mode = GT683R_LED_OFF; + + gt683r_mode_set(led, mode); +fail: + mutex_unlock(&led->lock); +} + +static DEVICE_ATTR_RW(leds_mode); + +static int gt683r_led_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + int i, ret, name_sz; + char *name; + struct gt683r_led *led; + + led = devm_kzalloc(&hdev->dev, sizeof(struct gt683r_led), GFP_KERNEL); + if (!led) + return -ENOMEM; + + led->mode = GT683R_LED_NORMAL; + led->hdev = hdev; + hid_set_drvdata(hdev, led); + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "hid parsing failed\n"); + return ret; + } + + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); + if (ret) { + hid_err(hdev, "hw start failed\n"); + return ret; + } + + for (i = 0; i < GT683R_LED_COUNT; i++) { + name_sz = strlen(dev_name(&hdev->dev)) + + strlen(gt683r_panel_names[i]) + 3; + + name = devm_kzalloc(&hdev->dev, sizeof(char) * name_sz, + GFP_KERNEL); + if (!name) { + ret = -ENOMEM; + goto fail; + } + + snprintf(name, name_sz, "%s::%s", + dev_name(&hdev->dev), gt683r_panel_names[i]); + led->led_devs[i].name = name; + led->led_devs[i].max_brightness = 1; + led->led_devs[i].brightness_set = gt683r_brightness_set; + ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); + if (ret) { + hid_err(hdev, "could not register led device\n"); + goto fail; + } + } + + ret = device_create_file(&led->hdev->dev, &dev_attr_leds_mode); + if (ret) { + hid_err(hdev, "could not make mode attribute file\n"); + goto fail; + } + + mutex_init(&led->lock); + INIT_WORK(&led->work, gt683r_led_work); + + return 0; + +fail: + for (i = i - 1; i >= 0; i--) + led_classdev_unregister(&led->led_devs[i]); + hid_hw_stop(hdev); + return ret; +} + +static void gt683r_led_remove(struct hid_device *hdev) +{ + int i; + struct gt683r_led *led = hid_get_drvdata(hdev); + + device_remove_file(&hdev->dev, &dev_attr_leds_mode); + for (i = 0; i < GT683R_LED_COUNT; i++) + led_classdev_unregister(&led->led_devs[i]); + flush_work(&led->work); + hid_hw_stop(hdev); +} + +static struct hid_driver gt683r_led_driver = { + .probe = gt683r_led_probe, + .remove = gt683r_led_remove, + .name = "gt683r_led", + .id_table = gt683r_led_id, +}; + +module_hid_driver(gt683r_led_driver); + +MODULE_AUTHOR("Janne Kanniainen"); +MODULE_DESCRIPTION("MSI GT683R led driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 34bb220..3692d37 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -641,7 +641,7 @@ #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 #define USB_VENDOR_ID_MSI 0x1770 -#define USB_DEVICE_ID_MSI_GX680R_LED_PANEL 0xff00 +#define USB_DEVICE_ID_MSI_GT683R_LED_PANEL 0xff00 #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400 #define USB_DEVICE_ID_N_S_HARMONY 0xc359 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 8e4ddb3..c640e1d 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -73,7 +73,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, - { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, 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 }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS }, -- 1.9.2 ^ permalink raw reply related [flat|nested] 81+ messages in thread
[parent not found: <1403023304-7953-1-git-send-email-janne.kanniainen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>]
* Re: [PATCH v8] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-17 16:41 ` [PATCH v8] " Janne Kanniainen @ 2014-06-18 7:39 ` Johan Hovold 0 siblings, 0 replies; 81+ messages in thread From: Johan Hovold @ 2014-06-18 7:39 UTC (permalink / raw) To: Janne Kanniainen Cc: jkosina-AlSwsSmVLrQ, johan-DgEjT+Ai2ygdnm+yROfE0A, cooloney-Re5JQEeQqe8AvxtiuMwx3w, linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-leds-u79uwXL29TY76Z2rM5mHXA, linux-usb-u79uwXL29TY76Z2rM5mHXA, linux-input-u79uwXL29TY76Z2rM5mHXA On Tue, Jun 17, 2014 at 07:41:44PM +0300, Janne Kanniainen wrote: > This driver adds support for USB controlled led panels that exists in > MSI GT683R laptop > > Changes in v2: > - sorted headers to alphabetic order > - using devm_kzalloc > - using BIT(n) > - using usb_control_msg instead of usb_submit_urb > - removing unneeded code > Changes in v3: > - implemented as HID device > - some cleanups and bug fixes > > Changes in v4: > - more cleanups > - support for selecting leds > - suppport for selecting status > > Changes in v5: > - mode attribute documented under Documentation/ABI > - made array for led_classdev > - led devices uses now recommended naming scheme > > Changes in v6: > - flush_work added > - using hid device name instead of hard coded gt683r > - allocating name buffers with devm_kzalloc > > Changes in v7: > - buf with for fixed > > Changes in v8: > - some cleanups and bugs fixed Great job, Janne. I have a few really minor style issues I just noted and that I point out below, but that's it. > Signed-off-by: Janne Kanniainen <janne.kanniainen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > --- > .../ABI/testing/sysfs-class-hid-driver-gt683r | 14 + > drivers/hid/Kconfig | 14 + > drivers/hid/Makefile | 1 + > drivers/hid/hid-core.c | 1 + > drivers/hid/hid-gt683r.c | 308 +++++++++++++++++++++ > drivers/hid/hid-ids.h | 2 +- > drivers/hid/usbhid/hid-quirks.c | 2 +- > 7 files changed, 340 insertions(+), 2 deletions(-) > create mode 100644 Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > create mode 100644 drivers/hid/hid-gt683r.c > > diff --git a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > new file mode 100644 > index 0000000..317e9d5 > --- /dev/null > +++ b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > @@ -0,0 +1,14 @@ > +What: /sys/class/hidraw/<hidraw>/device/leds_mode > +Date: Jun 2014 > +KernelVersion: 3.17 > +Contact: Janne Kanniainen <janne.kanniainen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > +Description: > + Set the mode of LEDs > + > + 0 - normal > + 1 - audio > + 2 - breathing > + > + Normal: LEDs are fully on when enabled > + Audio: LEDs brightness depends on sound level > + Breathing: LEDs brightness varies at human breathing rate > \ No newline at end of file > diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig > index 7af9d0b..e2f4590 100644 > --- a/drivers/hid/Kconfig > +++ b/drivers/hid/Kconfig > @@ -261,6 +261,20 @@ config HOLTEK_FF > Say Y here if you have a Holtek On Line Grip based game controller > and want to have force feedback support for it. > > +config HID_GT683R > + tristate "MSI GT68xR LED support" > + depends on LEDS_CLASS && USB_HID > + ---help--- > + Say Y here if you want to enable support for the three MSI GT68xR LEDs > + > + This driver support following modes: > + - Normal: LEDs are fully on when enabled > + - Audio: LEDs brightness depends on sound level > + - Breathing: LEDs brightness varies at human breathing rate > + > + Currently the following devices are know to be supported: > + - MSI GT683R > + > config HID_HUION > tristate "Huion tablets" > depends on USB_HID > diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile > index fc712dd..7129311 100644 > --- a/drivers/hid/Makefile > +++ b/drivers/hid/Makefile > @@ -48,6 +48,7 @@ obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o > obj-$(CONFIG_HID_ELECOM) += hid-elecom.o > obj-$(CONFIG_HID_ELO) += hid-elo.o > obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o > +obj-$(CONFIG_HID_GT683R) += hid-gt683r.o > obj-$(CONFIG_HID_GYRATION) += hid-gyration.o > obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o > obj-$(CONFIG_HID_HOLTEK) += hid-holtek-mouse.o > diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c > index da52279..ec88fdb 100644 > --- a/drivers/hid/hid-core.c > +++ b/drivers/hid/hid-core.c > @@ -1827,6 +1827,7 @@ static const struct hid_device_id hid_have_special_driver[] = { > { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, > { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, > { 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) }, > { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) }, > { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2) }, > diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c > new file mode 100644 > index 0000000..19959ac > --- /dev/null > +++ b/drivers/hid/hid-gt683r.c > @@ -0,0 +1,308 @@ > +/* > + * MSI GT683R led driver > + * > + * Copyright (c) 2014 Janne Kanniainen <janne.kanniainen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation; either version 2 of > + * the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + */ > + > +#include <linux/device.h> > +#include <linux/hid.h> > +#include <linux/kernel.h> > +#include <linux/leds.h> > +#include <linux/module.h> > + > +#include "hid-ids.h" > + > +#define GT683R_BUFFER_SIZE 8 > + > +/* > + * GT683R_LED_OFF: all LEDs are off > + * GT683R_LED_AUDIO: LEDs brightness depends on sound level > + * GT683R_LED_BREATHING: LEDs brightness varies at human breathing rate > + * GT683R_LED_NORMAL: LEDs are fully on when enabled > + */ > +enum gt683r_led_mode { > + GT683R_LED_OFF = 0, > + GT683R_LED_AUDIO = 2, > + GT683R_LED_BREATHING = 3, > + GT683R_LED_NORMAL = 5 > +}; > + > +enum gt683r_panels { > + GT683R_LED_BACK = 0, > + GT683R_LED_SIDE = 1, > + GT683R_LED_FRONT = 2, > + GT683R_LED_COUNT, > +}; > + > +static const char * const gt683r_panel_names[] = { > + "back", > + "side", > + "front", > +}; > + > +struct gt683r_led { > + struct hid_device *hdev; > + struct led_classdev led_devs[GT683R_LED_COUNT]; > + struct mutex lock; > + struct work_struct work; > + enum led_brightness brightnesses[GT683R_LED_COUNT]; > + enum gt683r_led_mode mode; > +}; > + > +static const struct hid_device_id gt683r_led_id[] = { > + { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, > + { } > +}; > + > +static void gt683r_brightness_set(struct led_classdev *led_cdev, > + enum led_brightness brightness) > +{ > + int i; > + struct device *dev = led_cdev->dev->parent; > + struct hid_device *hdev = container_of(dev, struct hid_device, dev); > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + for (i = 0; i < GT683R_LED_COUNT; i++) { > + if (&led->led_devs[i] == led_cdev) I'd prefer to have led_cdev on the left here comparing against the "constant" structs on the right. > + break; > + } > + > + if (i < GT683R_LED_COUNT) { > + led->brightnesses[i] = brightness; > + schedule_work(&led->work); > + } > +} > + > +static ssize_t leds_mode_show(struct device *dev, > + struct device_attribute *attr, > + char *buf) > +{ > + u8 sysfs_mode; > + struct hid_device *hdev = container_of(dev, struct hid_device, dev); > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + if (led->mode == GT683R_LED_NORMAL) > + sysfs_mode = 0; > + else if (led->mode == GT683R_LED_AUDIO) > + sysfs_mode = 1; > + else > + sysfs_mode = 2; > + > + return scnprintf(buf, PAGE_SIZE, "%u\n", sysfs_mode); > +} > + > +static ssize_t leds_mode_store(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t count) > +{ > + u8 sysfs_mode; > + struct hid_device *hdev = container_of(dev, struct hid_device, dev); > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + > + if (kstrtou8(buf, 10, &sysfs_mode) || sysfs_mode > 2) > + return -EINVAL; > + > + mutex_lock(&led->lock); > + > + if (sysfs_mode == 0) > + led->mode = GT683R_LED_NORMAL; > + else if (sysfs_mode == 1) > + led->mode = GT683R_LED_AUDIO; > + else > + led->mode = GT683R_LED_BREATHING; > + > + mutex_unlock(&led->lock); > + schedule_work(&led->work); > + > + return count; > +} > + > +static int gt683r_led_snd_msg(struct gt683r_led *led, u8 *msg) > +{ > + int ret; > + > + ret = hid_hw_raw_request(led->hdev, msg[0], msg, GT683R_BUFFER_SIZE, > + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); > + if (ret != GT683R_BUFFER_SIZE) { > + hid_err(led->hdev, > + "failed to send set report request: %i\n", ret); > + if (ret < 0) > + return ret; > + return -EIO; > + } > + > + return 0; > +} > + > +static int gt683r_leds_set(struct gt683r_led *led, u8 leds) > +{ > + int ret; > + u8 *buffer; > + > + buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); > + if (!buffer) > + return -ENOMEM; > + > + buffer[0] = 0x01; > + buffer[1] = 0x02; > + buffer[2] = 0x30; > + buffer[3] = leds; > + ret = gt683r_led_snd_msg(led, buffer); > + > + kfree(buffer); > + return ret; > +} > + > +static int gt683r_mode_set(struct gt683r_led *led, u8 mode) > +{ > + int ret; > + u8 *buffer; > + > + buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); > + if (!buffer) > + return -ENOMEM; > + > + buffer[0] = 0x01; > + buffer[1] = 0x02; > + buffer[2] = 0x20; > + buffer[3] = mode; > + buffer[4] = 0x01; > + ret = gt683r_led_snd_msg(led, buffer); > + > + kfree(buffer); > + return ret; > +} > + > +static void gt683r_led_work(struct work_struct *work) > +{ > + int i; > + u8 leds = 0; > + u8 mode; > + struct gt683r_led *led = container_of(work, struct gt683r_led, work); > + > + mutex_lock(&led->lock); > + > + for (i = 0; i < GT683R_LED_COUNT; i++) { > + if (led->brightnesses[i]) > + leds |= BIT(i); > + } > + > + if (gt683r_leds_set(led, leds)) > + goto fail; > + > + if (leds) > + mode = led->mode; > + else > + mode = GT683R_LED_OFF; > + > + gt683r_mode_set(led, mode); > +fail: > + mutex_unlock(&led->lock); > +} > + > +static DEVICE_ATTR_RW(leds_mode); > + > +static int gt683r_led_probe(struct hid_device *hdev, > + const struct hid_device_id *id) > +{ > + int i, ret, name_sz; One declaration per line. > + char *name; > + struct gt683r_led *led; > + > + led = devm_kzalloc(&hdev->dev, sizeof(struct gt683r_led), GFP_KERNEL); Preferred form for passing the size to kmalloc and friends is sizeof(*led) (in case the type of led ever changes). It's also shorter and often more readable. > + if (!led) > + return -ENOMEM; > + > + led->mode = GT683R_LED_NORMAL; > + led->hdev = hdev; > + hid_set_drvdata(hdev, led); > + > + ret = hid_parse(hdev); > + if (ret) { > + hid_err(hdev, "hid parsing failed\n"); > + return ret; > + } > + > + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); > + if (ret) { > + hid_err(hdev, "hw start failed\n"); > + return ret; > + } > + > + for (i = 0; i < GT683R_LED_COUNT; i++) { > + name_sz = strlen(dev_name(&hdev->dev)) + > + strlen(gt683r_panel_names[i]) + 3; Try to indent continuation lines at least two tabs further than the preceding line. > + > + name = devm_kzalloc(&hdev->dev, sizeof(char) * name_sz, > + GFP_KERNEL); No need to do sizeof(char) which is always 1 (so no need to break this line either). > + if (!name) { > + ret = -ENOMEM; > + goto fail; > + } > + > + snprintf(name, name_sz, "%s::%s", > + dev_name(&hdev->dev), gt683r_panel_names[i]); On more tab here. > + led->led_devs[i].name = name; > + led->led_devs[i].max_brightness = 1; > + led->led_devs[i].brightness_set = gt683r_brightness_set; > + ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); > + if (ret) { > + hid_err(hdev, "could not register led device\n"); > + goto fail; > + } > + } > + > + ret = device_create_file(&led->hdev->dev, &dev_attr_leds_mode); > + if (ret) { > + hid_err(hdev, "could not make mode attribute file\n"); > + goto fail; > + } > + > + mutex_init(&led->lock); > + INIT_WORK(&led->work, gt683r_led_work); > + > + return 0; > + > +fail: > + for (i = i - 1; i >= 0; i--) > + led_classdev_unregister(&led->led_devs[i]); > + hid_hw_stop(hdev); > + return ret; > +} > + > +static void gt683r_led_remove(struct hid_device *hdev) > +{ > + int i; > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + device_remove_file(&hdev->dev, &dev_attr_leds_mode); > + for (i = 0; i < GT683R_LED_COUNT; i++) > + led_classdev_unregister(&led->led_devs[i]); > + flush_work(&led->work); > + hid_hw_stop(hdev); > +} > + > +static struct hid_driver gt683r_led_driver = { > + .probe = gt683r_led_probe, > + .remove = gt683r_led_remove, > + .name = "gt683r_led", > + .id_table = gt683r_led_id, > +}; > + > +module_hid_driver(gt683r_led_driver); > + > +MODULE_AUTHOR("Janne Kanniainen"); > +MODULE_DESCRIPTION("MSI GT683R led driver"); > +MODULE_LICENSE("GPL"); > diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h > index 34bb220..3692d37 100644 > --- a/drivers/hid/hid-ids.h > +++ b/drivers/hid/hid-ids.h > @@ -641,7 +641,7 @@ > #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 > > #define USB_VENDOR_ID_MSI 0x1770 > -#define USB_DEVICE_ID_MSI_GX680R_LED_PANEL 0xff00 > +#define USB_DEVICE_ID_MSI_GT683R_LED_PANEL 0xff00 > > #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400 > #define USB_DEVICE_ID_N_S_HARMONY 0xc359 > diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c > index 8e4ddb3..c640e1d 100644 > --- a/drivers/hid/usbhid/hid-quirks.c > +++ b/drivers/hid/usbhid/hid-quirks.c > @@ -73,7 +73,7 @@ static const struct hid_blacklist { > { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, > { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, > { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, > - { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, 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 }, > { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS }, Thanks, Johan -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v8] leds: USB: HID: Add support for MSI GT683R led panels @ 2014-06-18 7:39 ` Johan Hovold 0 siblings, 0 replies; 81+ messages in thread From: Johan Hovold @ 2014-06-18 7:39 UTC (permalink / raw) To: Janne Kanniainen Cc: jkosina, johan, cooloney, linux-kernel, linux-leds, linux-usb, linux-input On Tue, Jun 17, 2014 at 07:41:44PM +0300, Janne Kanniainen wrote: > This driver adds support for USB controlled led panels that exists in > MSI GT683R laptop > > Changes in v2: > - sorted headers to alphabetic order > - using devm_kzalloc > - using BIT(n) > - using usb_control_msg instead of usb_submit_urb > - removing unneeded code > Changes in v3: > - implemented as HID device > - some cleanups and bug fixes > > Changes in v4: > - more cleanups > - support for selecting leds > - suppport for selecting status > > Changes in v5: > - mode attribute documented under Documentation/ABI > - made array for led_classdev > - led devices uses now recommended naming scheme > > Changes in v6: > - flush_work added > - using hid device name instead of hard coded gt683r > - allocating name buffers with devm_kzalloc > > Changes in v7: > - buf with for fixed > > Changes in v8: > - some cleanups and bugs fixed Great job, Janne. I have a few really minor style issues I just noted and that I point out below, but that's it. > Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> > --- > .../ABI/testing/sysfs-class-hid-driver-gt683r | 14 + > drivers/hid/Kconfig | 14 + > drivers/hid/Makefile | 1 + > drivers/hid/hid-core.c | 1 + > drivers/hid/hid-gt683r.c | 308 +++++++++++++++++++++ > drivers/hid/hid-ids.h | 2 +- > drivers/hid/usbhid/hid-quirks.c | 2 +- > 7 files changed, 340 insertions(+), 2 deletions(-) > create mode 100644 Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > create mode 100644 drivers/hid/hid-gt683r.c > > diff --git a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > new file mode 100644 > index 0000000..317e9d5 > --- /dev/null > +++ b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > @@ -0,0 +1,14 @@ > +What: /sys/class/hidraw/<hidraw>/device/leds_mode > +Date: Jun 2014 > +KernelVersion: 3.17 > +Contact: Janne Kanniainen <janne.kanniainen@gmail.com> > +Description: > + Set the mode of LEDs > + > + 0 - normal > + 1 - audio > + 2 - breathing > + > + Normal: LEDs are fully on when enabled > + Audio: LEDs brightness depends on sound level > + Breathing: LEDs brightness varies at human breathing rate > \ No newline at end of file > diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig > index 7af9d0b..e2f4590 100644 > --- a/drivers/hid/Kconfig > +++ b/drivers/hid/Kconfig > @@ -261,6 +261,20 @@ config HOLTEK_FF > Say Y here if you have a Holtek On Line Grip based game controller > and want to have force feedback support for it. > > +config HID_GT683R > + tristate "MSI GT68xR LED support" > + depends on LEDS_CLASS && USB_HID > + ---help--- > + Say Y here if you want to enable support for the three MSI GT68xR LEDs > + > + This driver support following modes: > + - Normal: LEDs are fully on when enabled > + - Audio: LEDs brightness depends on sound level > + - Breathing: LEDs brightness varies at human breathing rate > + > + Currently the following devices are know to be supported: > + - MSI GT683R > + > config HID_HUION > tristate "Huion tablets" > depends on USB_HID > diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile > index fc712dd..7129311 100644 > --- a/drivers/hid/Makefile > +++ b/drivers/hid/Makefile > @@ -48,6 +48,7 @@ obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o > obj-$(CONFIG_HID_ELECOM) += hid-elecom.o > obj-$(CONFIG_HID_ELO) += hid-elo.o > obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o > +obj-$(CONFIG_HID_GT683R) += hid-gt683r.o > obj-$(CONFIG_HID_GYRATION) += hid-gyration.o > obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o > obj-$(CONFIG_HID_HOLTEK) += hid-holtek-mouse.o > diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c > index da52279..ec88fdb 100644 > --- a/drivers/hid/hid-core.c > +++ b/drivers/hid/hid-core.c > @@ -1827,6 +1827,7 @@ static const struct hid_device_id hid_have_special_driver[] = { > { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, > { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, > { 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) }, > { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) }, > { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2) }, > diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c > new file mode 100644 > index 0000000..19959ac > --- /dev/null > +++ b/drivers/hid/hid-gt683r.c > @@ -0,0 +1,308 @@ > +/* > + * MSI GT683R led driver > + * > + * Copyright (c) 2014 Janne Kanniainen <janne.kanniainen@gmail.com> > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation; either version 2 of > + * the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + */ > + > +#include <linux/device.h> > +#include <linux/hid.h> > +#include <linux/kernel.h> > +#include <linux/leds.h> > +#include <linux/module.h> > + > +#include "hid-ids.h" > + > +#define GT683R_BUFFER_SIZE 8 > + > +/* > + * GT683R_LED_OFF: all LEDs are off > + * GT683R_LED_AUDIO: LEDs brightness depends on sound level > + * GT683R_LED_BREATHING: LEDs brightness varies at human breathing rate > + * GT683R_LED_NORMAL: LEDs are fully on when enabled > + */ > +enum gt683r_led_mode { > + GT683R_LED_OFF = 0, > + GT683R_LED_AUDIO = 2, > + GT683R_LED_BREATHING = 3, > + GT683R_LED_NORMAL = 5 > +}; > + > +enum gt683r_panels { > + GT683R_LED_BACK = 0, > + GT683R_LED_SIDE = 1, > + GT683R_LED_FRONT = 2, > + GT683R_LED_COUNT, > +}; > + > +static const char * const gt683r_panel_names[] = { > + "back", > + "side", > + "front", > +}; > + > +struct gt683r_led { > + struct hid_device *hdev; > + struct led_classdev led_devs[GT683R_LED_COUNT]; > + struct mutex lock; > + struct work_struct work; > + enum led_brightness brightnesses[GT683R_LED_COUNT]; > + enum gt683r_led_mode mode; > +}; > + > +static const struct hid_device_id gt683r_led_id[] = { > + { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, > + { } > +}; > + > +static void gt683r_brightness_set(struct led_classdev *led_cdev, > + enum led_brightness brightness) > +{ > + int i; > + struct device *dev = led_cdev->dev->parent; > + struct hid_device *hdev = container_of(dev, struct hid_device, dev); > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + for (i = 0; i < GT683R_LED_COUNT; i++) { > + if (&led->led_devs[i] == led_cdev) I'd prefer to have led_cdev on the left here comparing against the "constant" structs on the right. > + break; > + } > + > + if (i < GT683R_LED_COUNT) { > + led->brightnesses[i] = brightness; > + schedule_work(&led->work); > + } > +} > + > +static ssize_t leds_mode_show(struct device *dev, > + struct device_attribute *attr, > + char *buf) > +{ > + u8 sysfs_mode; > + struct hid_device *hdev = container_of(dev, struct hid_device, dev); > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + if (led->mode == GT683R_LED_NORMAL) > + sysfs_mode = 0; > + else if (led->mode == GT683R_LED_AUDIO) > + sysfs_mode = 1; > + else > + sysfs_mode = 2; > + > + return scnprintf(buf, PAGE_SIZE, "%u\n", sysfs_mode); > +} > + > +static ssize_t leds_mode_store(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t count) > +{ > + u8 sysfs_mode; > + struct hid_device *hdev = container_of(dev, struct hid_device, dev); > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + > + if (kstrtou8(buf, 10, &sysfs_mode) || sysfs_mode > 2) > + return -EINVAL; > + > + mutex_lock(&led->lock); > + > + if (sysfs_mode == 0) > + led->mode = GT683R_LED_NORMAL; > + else if (sysfs_mode == 1) > + led->mode = GT683R_LED_AUDIO; > + else > + led->mode = GT683R_LED_BREATHING; > + > + mutex_unlock(&led->lock); > + schedule_work(&led->work); > + > + return count; > +} > + > +static int gt683r_led_snd_msg(struct gt683r_led *led, u8 *msg) > +{ > + int ret; > + > + ret = hid_hw_raw_request(led->hdev, msg[0], msg, GT683R_BUFFER_SIZE, > + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); > + if (ret != GT683R_BUFFER_SIZE) { > + hid_err(led->hdev, > + "failed to send set report request: %i\n", ret); > + if (ret < 0) > + return ret; > + return -EIO; > + } > + > + return 0; > +} > + > +static int gt683r_leds_set(struct gt683r_led *led, u8 leds) > +{ > + int ret; > + u8 *buffer; > + > + buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); > + if (!buffer) > + return -ENOMEM; > + > + buffer[0] = 0x01; > + buffer[1] = 0x02; > + buffer[2] = 0x30; > + buffer[3] = leds; > + ret = gt683r_led_snd_msg(led, buffer); > + > + kfree(buffer); > + return ret; > +} > + > +static int gt683r_mode_set(struct gt683r_led *led, u8 mode) > +{ > + int ret; > + u8 *buffer; > + > + buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); > + if (!buffer) > + return -ENOMEM; > + > + buffer[0] = 0x01; > + buffer[1] = 0x02; > + buffer[2] = 0x20; > + buffer[3] = mode; > + buffer[4] = 0x01; > + ret = gt683r_led_snd_msg(led, buffer); > + > + kfree(buffer); > + return ret; > +} > + > +static void gt683r_led_work(struct work_struct *work) > +{ > + int i; > + u8 leds = 0; > + u8 mode; > + struct gt683r_led *led = container_of(work, struct gt683r_led, work); > + > + mutex_lock(&led->lock); > + > + for (i = 0; i < GT683R_LED_COUNT; i++) { > + if (led->brightnesses[i]) > + leds |= BIT(i); > + } > + > + if (gt683r_leds_set(led, leds)) > + goto fail; > + > + if (leds) > + mode = led->mode; > + else > + mode = GT683R_LED_OFF; > + > + gt683r_mode_set(led, mode); > +fail: > + mutex_unlock(&led->lock); > +} > + > +static DEVICE_ATTR_RW(leds_mode); > + > +static int gt683r_led_probe(struct hid_device *hdev, > + const struct hid_device_id *id) > +{ > + int i, ret, name_sz; One declaration per line. > + char *name; > + struct gt683r_led *led; > + > + led = devm_kzalloc(&hdev->dev, sizeof(struct gt683r_led), GFP_KERNEL); Preferred form for passing the size to kmalloc and friends is sizeof(*led) (in case the type of led ever changes). It's also shorter and often more readable. > + if (!led) > + return -ENOMEM; > + > + led->mode = GT683R_LED_NORMAL; > + led->hdev = hdev; > + hid_set_drvdata(hdev, led); > + > + ret = hid_parse(hdev); > + if (ret) { > + hid_err(hdev, "hid parsing failed\n"); > + return ret; > + } > + > + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); > + if (ret) { > + hid_err(hdev, "hw start failed\n"); > + return ret; > + } > + > + for (i = 0; i < GT683R_LED_COUNT; i++) { > + name_sz = strlen(dev_name(&hdev->dev)) + > + strlen(gt683r_panel_names[i]) + 3; Try to indent continuation lines at least two tabs further than the preceding line. > + > + name = devm_kzalloc(&hdev->dev, sizeof(char) * name_sz, > + GFP_KERNEL); No need to do sizeof(char) which is always 1 (so no need to break this line either). > + if (!name) { > + ret = -ENOMEM; > + goto fail; > + } > + > + snprintf(name, name_sz, "%s::%s", > + dev_name(&hdev->dev), gt683r_panel_names[i]); On more tab here. > + led->led_devs[i].name = name; > + led->led_devs[i].max_brightness = 1; > + led->led_devs[i].brightness_set = gt683r_brightness_set; > + ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); > + if (ret) { > + hid_err(hdev, "could not register led device\n"); > + goto fail; > + } > + } > + > + ret = device_create_file(&led->hdev->dev, &dev_attr_leds_mode); > + if (ret) { > + hid_err(hdev, "could not make mode attribute file\n"); > + goto fail; > + } > + > + mutex_init(&led->lock); > + INIT_WORK(&led->work, gt683r_led_work); > + > + return 0; > + > +fail: > + for (i = i - 1; i >= 0; i--) > + led_classdev_unregister(&led->led_devs[i]); > + hid_hw_stop(hdev); > + return ret; > +} > + > +static void gt683r_led_remove(struct hid_device *hdev) > +{ > + int i; > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + device_remove_file(&hdev->dev, &dev_attr_leds_mode); > + for (i = 0; i < GT683R_LED_COUNT; i++) > + led_classdev_unregister(&led->led_devs[i]); > + flush_work(&led->work); > + hid_hw_stop(hdev); > +} > + > +static struct hid_driver gt683r_led_driver = { > + .probe = gt683r_led_probe, > + .remove = gt683r_led_remove, > + .name = "gt683r_led", > + .id_table = gt683r_led_id, > +}; > + > +module_hid_driver(gt683r_led_driver); > + > +MODULE_AUTHOR("Janne Kanniainen"); > +MODULE_DESCRIPTION("MSI GT683R led driver"); > +MODULE_LICENSE("GPL"); > diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h > index 34bb220..3692d37 100644 > --- a/drivers/hid/hid-ids.h > +++ b/drivers/hid/hid-ids.h > @@ -641,7 +641,7 @@ > #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 > > #define USB_VENDOR_ID_MSI 0x1770 > -#define USB_DEVICE_ID_MSI_GX680R_LED_PANEL 0xff00 > +#define USB_DEVICE_ID_MSI_GT683R_LED_PANEL 0xff00 > > #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400 > #define USB_DEVICE_ID_N_S_HARMONY 0xc359 > diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c > index 8e4ddb3..c640e1d 100644 > --- a/drivers/hid/usbhid/hid-quirks.c > +++ b/drivers/hid/usbhid/hid-quirks.c > @@ -73,7 +73,7 @@ static const struct hid_blacklist { > { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, > { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, > { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, > - { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, 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 }, > { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS }, Thanks, Johan ^ permalink raw reply [flat|nested] 81+ messages in thread
* [PATCH v9] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-18 7:39 ` Johan Hovold (?) @ 2014-06-18 16:05 ` Janne Kanniainen [not found] ` <1403107502-14106-1-git-send-email-janne.kanniainen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2014-06-23 14:35 ` Oliver Neukum -1 siblings, 2 replies; 81+ messages in thread From: Janne Kanniainen @ 2014-06-18 16:05 UTC (permalink / raw) To: jkosina Cc: johan, cooloney, linux-kernel, linux-leds, linux-usb, linux-input, Janne Kanniainen This driver adds support for USB controlled led panels that exists in MSI GT683R laptop Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> --- Changes in v2: - sorted headers to alphabetic order - using devm_kzalloc - using BIT(n) - using usb_control_msg instead of usb_submit_urb - removing unneeded code Changes in v3: - implemented as HID device - some cleanups and bug fixes Changes in v4: - more cleanups - support for selecting leds - suppport for selecting status Changes in v5: - mode attribute documented under Documentation/ABI - made array for led_classdev - led devices uses now recommended naming scheme Changes in v6: - flush_work added - using hid device name instead of hard coded gt683r - allocating name buffers with devm_kzalloc Changes in v7: - buf with for fixed Changes in v8: - some cleanups and bugs fixed Changes in v9: - few style issues fixed .../ABI/testing/sysfs-class-hid-driver-gt683r | 14 + drivers/hid/Kconfig | 14 + drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-gt683r.c | 309 +++++++++++++++++++++ drivers/hid/hid-ids.h | 2 +- drivers/hid/usbhid/hid-quirks.c | 2 +- 7 files changed, 341 insertions(+), 2 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-class-hid-driver-gt683r create mode 100644 drivers/hid/hid-gt683r.c diff --git a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r new file mode 100644 index 0000000..317e9d5 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r @@ -0,0 +1,14 @@ +What: /sys/class/hidraw/<hidraw>/device/leds_mode +Date: Jun 2014 +KernelVersion: 3.17 +Contact: Janne Kanniainen <janne.kanniainen@gmail.com> +Description: + Set the mode of LEDs + + 0 - normal + 1 - audio + 2 - breathing + + Normal: LEDs are fully on when enabled + Audio: LEDs brightness depends on sound level + Breathing: LEDs brightness varies at human breathing rate \ No newline at end of file diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 7af9d0b..e2f4590 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -261,6 +261,20 @@ config HOLTEK_FF Say Y here if you have a Holtek On Line Grip based game controller and want to have force feedback support for it. +config HID_GT683R + tristate "MSI GT68xR LED support" + depends on LEDS_CLASS && USB_HID + ---help--- + Say Y here if you want to enable support for the three MSI GT68xR LEDs + + This driver support following modes: + - Normal: LEDs are fully on when enabled + - Audio: LEDs brightness depends on sound level + - Breathing: LEDs brightness varies at human breathing rate + + Currently the following devices are know to be supported: + - MSI GT683R + config HID_HUION tristate "Huion tablets" depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index fc712dd..7129311 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o obj-$(CONFIG_HID_ELECOM) += hid-elecom.o obj-$(CONFIG_HID_ELO) += hid-elo.o obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o +obj-$(CONFIG_HID_GT683R) += hid-gt683r.o obj-$(CONFIG_HID_GYRATION) += hid-gyration.o obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o obj-$(CONFIG_HID_HOLTEK) += hid-holtek-mouse.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index da52279..ec88fdb 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1827,6 +1827,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, { 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) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2) }, diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c new file mode 100644 index 0000000..077f7a1 --- /dev/null +++ b/drivers/hid/hid-gt683r.c @@ -0,0 +1,309 @@ +/* + * MSI GT683R led driver + * + * Copyright (c) 2014 Janne Kanniainen <janne.kanniainen@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/device.h> +#include <linux/hid.h> +#include <linux/kernel.h> +#include <linux/leds.h> +#include <linux/module.h> + +#include "hid-ids.h" + +#define GT683R_BUFFER_SIZE 8 + +/* + * GT683R_LED_OFF: all LEDs are off + * GT683R_LED_AUDIO: LEDs brightness depends on sound level + * GT683R_LED_BREATHING: LEDs brightness varies at human breathing rate + * GT683R_LED_NORMAL: LEDs are fully on when enabled + */ +enum gt683r_led_mode { + GT683R_LED_OFF = 0, + GT683R_LED_AUDIO = 2, + GT683R_LED_BREATHING = 3, + GT683R_LED_NORMAL = 5 +}; + +enum gt683r_panels { + GT683R_LED_BACK = 0, + GT683R_LED_SIDE = 1, + GT683R_LED_FRONT = 2, + GT683R_LED_COUNT, +}; + +static const char * const gt683r_panel_names[] = { + "back", + "side", + "front", +}; + +struct gt683r_led { + struct hid_device *hdev; + struct led_classdev led_devs[GT683R_LED_COUNT]; + struct mutex lock; + struct work_struct work; + enum led_brightness brightnesses[GT683R_LED_COUNT]; + enum gt683r_led_mode mode; +}; + +static const struct hid_device_id gt683r_led_id[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, + { } +}; + +static void gt683r_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + int i; + struct device *dev = led_cdev->dev->parent; + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct gt683r_led *led = hid_get_drvdata(hdev); + + for (i = 0; i < GT683R_LED_COUNT; i++) { + if (led_cdev == &led->led_devs[i]) + break; + } + + if (i < GT683R_LED_COUNT) { + led->brightnesses[i] = brightness; + schedule_work(&led->work); + } +} + +static ssize_t leds_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + u8 sysfs_mode; + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct gt683r_led *led = hid_get_drvdata(hdev); + + if (led->mode == GT683R_LED_NORMAL) + sysfs_mode = 0; + else if (led->mode == GT683R_LED_AUDIO) + sysfs_mode = 1; + else + sysfs_mode = 2; + + return scnprintf(buf, PAGE_SIZE, "%u\n", sysfs_mode); +} + +static ssize_t leds_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + u8 sysfs_mode; + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct gt683r_led *led = hid_get_drvdata(hdev); + + + if (kstrtou8(buf, 10, &sysfs_mode) || sysfs_mode > 2) + return -EINVAL; + + mutex_lock(&led->lock); + + if (sysfs_mode == 0) + led->mode = GT683R_LED_NORMAL; + else if (sysfs_mode == 1) + led->mode = GT683R_LED_AUDIO; + else + led->mode = GT683R_LED_BREATHING; + + mutex_unlock(&led->lock); + schedule_work(&led->work); + + return count; +} + +static int gt683r_led_snd_msg(struct gt683r_led *led, u8 *msg) +{ + int ret; + + ret = hid_hw_raw_request(led->hdev, msg[0], msg, GT683R_BUFFER_SIZE, + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); + if (ret != GT683R_BUFFER_SIZE) { + hid_err(led->hdev, + "failed to send set report request: %i\n", ret); + if (ret < 0) + return ret; + return -EIO; + } + + return 0; +} + +static int gt683r_leds_set(struct gt683r_led *led, u8 leds) +{ + int ret; + u8 *buffer; + + buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + buffer[0] = 0x01; + buffer[1] = 0x02; + buffer[2] = 0x30; + buffer[3] = leds; + ret = gt683r_led_snd_msg(led, buffer); + + kfree(buffer); + return ret; +} + +static int gt683r_mode_set(struct gt683r_led *led, u8 mode) +{ + int ret; + u8 *buffer; + + buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + buffer[0] = 0x01; + buffer[1] = 0x02; + buffer[2] = 0x20; + buffer[3] = mode; + buffer[4] = 0x01; + ret = gt683r_led_snd_msg(led, buffer); + + kfree(buffer); + return ret; +} + +static void gt683r_led_work(struct work_struct *work) +{ + int i; + u8 leds = 0; + u8 mode; + struct gt683r_led *led = container_of(work, struct gt683r_led, work); + + mutex_lock(&led->lock); + + for (i = 0; i < GT683R_LED_COUNT; i++) { + if (led->brightnesses[i]) + leds |= BIT(i); + } + + if (gt683r_leds_set(led, leds)) + goto fail; + + if (leds) + mode = led->mode; + else + mode = GT683R_LED_OFF; + + gt683r_mode_set(led, mode); +fail: + mutex_unlock(&led->lock); +} + +static DEVICE_ATTR_RW(leds_mode); + +static int gt683r_led_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + int i; + int ret; + int name_sz; + char *name; + struct gt683r_led *led; + + led = devm_kzalloc(&hdev->dev, sizeof(*led), GFP_KERNEL); + if (!led) + return -ENOMEM; + + led->mode = GT683R_LED_NORMAL; + led->hdev = hdev; + hid_set_drvdata(hdev, led); + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "hid parsing failed\n"); + return ret; + } + + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); + if (ret) { + hid_err(hdev, "hw start failed\n"); + return ret; + } + + for (i = 0; i < GT683R_LED_COUNT; i++) { + name_sz = strlen(dev_name(&hdev->dev)) + + strlen(gt683r_panel_names[i]) + 3; + + name = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL); + if (!name) { + ret = -ENOMEM; + goto fail; + } + + snprintf(name, name_sz, "%s::%s", + dev_name(&hdev->dev), gt683r_panel_names[i]); + led->led_devs[i].name = name; + led->led_devs[i].max_brightness = 1; + led->led_devs[i].brightness_set = gt683r_brightness_set; + ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); + if (ret) { + hid_err(hdev, "could not register led device\n"); + goto fail; + } + } + + ret = device_create_file(&led->hdev->dev, &dev_attr_leds_mode); + if (ret) { + hid_err(hdev, "could not make mode attribute file\n"); + goto fail; + } + + mutex_init(&led->lock); + INIT_WORK(&led->work, gt683r_led_work); + + return 0; + +fail: + for (i = i - 1; i >= 0; i--) + led_classdev_unregister(&led->led_devs[i]); + hid_hw_stop(hdev); + return ret; +} + +static void gt683r_led_remove(struct hid_device *hdev) +{ + int i; + struct gt683r_led *led = hid_get_drvdata(hdev); + + device_remove_file(&hdev->dev, &dev_attr_leds_mode); + for (i = 0; i < GT683R_LED_COUNT; i++) + led_classdev_unregister(&led->led_devs[i]); + flush_work(&led->work); + hid_hw_stop(hdev); +} + +static struct hid_driver gt683r_led_driver = { + .probe = gt683r_led_probe, + .remove = gt683r_led_remove, + .name = "gt683r_led", + .id_table = gt683r_led_id, +}; + +module_hid_driver(gt683r_led_driver); + +MODULE_AUTHOR("Janne Kanniainen"); +MODULE_DESCRIPTION("MSI GT683R led driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 34bb220..3692d37 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -641,7 +641,7 @@ #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 #define USB_VENDOR_ID_MSI 0x1770 -#define USB_DEVICE_ID_MSI_GX680R_LED_PANEL 0xff00 +#define USB_DEVICE_ID_MSI_GT683R_LED_PANEL 0xff00 #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400 #define USB_DEVICE_ID_N_S_HARMONY 0xc359 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 8e4ddb3..c640e1d 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -73,7 +73,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, - { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, 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 }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS }, -- 1.9.2 ^ permalink raw reply related [flat|nested] 81+ messages in thread
[parent not found: <1403107502-14106-1-git-send-email-janne.kanniainen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>]
* Re: [PATCH v9] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-18 16:05 ` [PATCH v9] " Janne Kanniainen @ 2014-06-18 16:11 ` Johan Hovold 2014-06-23 14:35 ` Oliver Neukum 1 sibling, 0 replies; 81+ messages in thread From: Johan Hovold @ 2014-06-18 16:11 UTC (permalink / raw) To: Janne Kanniainen Cc: jkosina-AlSwsSmVLrQ, johan-DgEjT+Ai2ygdnm+yROfE0A, cooloney-Re5JQEeQqe8AvxtiuMwx3w, linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-leds-u79uwXL29TY76Z2rM5mHXA, linux-usb-u79uwXL29TY76Z2rM5mHXA, linux-input-u79uwXL29TY76Z2rM5mHXA On Wed, Jun 18, 2014 at 07:05:02PM +0300, Janne Kanniainen wrote: > This driver adds support for USB controlled led panels that exists in > MSI GT683R laptop > > Signed-off-by: Janne Kanniainen <janne.kanniainen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> Reviewed-by: Johan Hovold <johan-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org> Thanks, Janne! Johan > --- > Changes in v2: > - sorted headers to alphabetic order > - using devm_kzalloc > - using BIT(n) > - using usb_control_msg instead of usb_submit_urb > - removing unneeded code > Changes in v3: > - implemented as HID device > - some cleanups and bug fixes > > Changes in v4: > - more cleanups > - support for selecting leds > - suppport for selecting status > > Changes in v5: > - mode attribute documented under Documentation/ABI > - made array for led_classdev > - led devices uses now recommended naming scheme > > Changes in v6: > - flush_work added > - using hid device name instead of hard coded gt683r > - allocating name buffers with devm_kzalloc > > Changes in v7: > - buf with for fixed > > Changes in v8: > - some cleanups and bugs fixed > > Changes in v9: > - few style issues fixed > > .../ABI/testing/sysfs-class-hid-driver-gt683r | 14 + > drivers/hid/Kconfig | 14 + > drivers/hid/Makefile | 1 + > drivers/hid/hid-core.c | 1 + > drivers/hid/hid-gt683r.c | 309 +++++++++++++++++++++ > drivers/hid/hid-ids.h | 2 +- > drivers/hid/usbhid/hid-quirks.c | 2 +- > 7 files changed, 341 insertions(+), 2 deletions(-) > create mode 100644 Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > create mode 100644 drivers/hid/hid-gt683r.c > > diff --git a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > new file mode 100644 > index 0000000..317e9d5 > --- /dev/null > +++ b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > @@ -0,0 +1,14 @@ > +What: /sys/class/hidraw/<hidraw>/device/leds_mode > +Date: Jun 2014 > +KernelVersion: 3.17 > +Contact: Janne Kanniainen <janne.kanniainen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > +Description: > + Set the mode of LEDs > + > + 0 - normal > + 1 - audio > + 2 - breathing > + > + Normal: LEDs are fully on when enabled > + Audio: LEDs brightness depends on sound level > + Breathing: LEDs brightness varies at human breathing rate > \ No newline at end of file > diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig > index 7af9d0b..e2f4590 100644 > --- a/drivers/hid/Kconfig > +++ b/drivers/hid/Kconfig > @@ -261,6 +261,20 @@ config HOLTEK_FF > Say Y here if you have a Holtek On Line Grip based game controller > and want to have force feedback support for it. > > +config HID_GT683R > + tristate "MSI GT68xR LED support" > + depends on LEDS_CLASS && USB_HID > + ---help--- > + Say Y here if you want to enable support for the three MSI GT68xR LEDs > + > + This driver support following modes: > + - Normal: LEDs are fully on when enabled > + - Audio: LEDs brightness depends on sound level > + - Breathing: LEDs brightness varies at human breathing rate > + > + Currently the following devices are know to be supported: > + - MSI GT683R > + > config HID_HUION > tristate "Huion tablets" > depends on USB_HID > diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile > index fc712dd..7129311 100644 > --- a/drivers/hid/Makefile > +++ b/drivers/hid/Makefile > @@ -48,6 +48,7 @@ obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o > obj-$(CONFIG_HID_ELECOM) += hid-elecom.o > obj-$(CONFIG_HID_ELO) += hid-elo.o > obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o > +obj-$(CONFIG_HID_GT683R) += hid-gt683r.o > obj-$(CONFIG_HID_GYRATION) += hid-gyration.o > obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o > obj-$(CONFIG_HID_HOLTEK) += hid-holtek-mouse.o > diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c > index da52279..ec88fdb 100644 > --- a/drivers/hid/hid-core.c > +++ b/drivers/hid/hid-core.c > @@ -1827,6 +1827,7 @@ static const struct hid_device_id hid_have_special_driver[] = { > { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, > { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, > { 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) }, > { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) }, > { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2) }, > diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c > new file mode 100644 > index 0000000..077f7a1 > --- /dev/null > +++ b/drivers/hid/hid-gt683r.c > @@ -0,0 +1,309 @@ > +/* > + * MSI GT683R led driver > + * > + * Copyright (c) 2014 Janne Kanniainen <janne.kanniainen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation; either version 2 of > + * the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + */ > + > +#include <linux/device.h> > +#include <linux/hid.h> > +#include <linux/kernel.h> > +#include <linux/leds.h> > +#include <linux/module.h> > + > +#include "hid-ids.h" > + > +#define GT683R_BUFFER_SIZE 8 > + > +/* > + * GT683R_LED_OFF: all LEDs are off > + * GT683R_LED_AUDIO: LEDs brightness depends on sound level > + * GT683R_LED_BREATHING: LEDs brightness varies at human breathing rate > + * GT683R_LED_NORMAL: LEDs are fully on when enabled > + */ > +enum gt683r_led_mode { > + GT683R_LED_OFF = 0, > + GT683R_LED_AUDIO = 2, > + GT683R_LED_BREATHING = 3, > + GT683R_LED_NORMAL = 5 > +}; > + > +enum gt683r_panels { > + GT683R_LED_BACK = 0, > + GT683R_LED_SIDE = 1, > + GT683R_LED_FRONT = 2, > + GT683R_LED_COUNT, > +}; > + > +static const char * const gt683r_panel_names[] = { > + "back", > + "side", > + "front", > +}; > + > +struct gt683r_led { > + struct hid_device *hdev; > + struct led_classdev led_devs[GT683R_LED_COUNT]; > + struct mutex lock; > + struct work_struct work; > + enum led_brightness brightnesses[GT683R_LED_COUNT]; > + enum gt683r_led_mode mode; > +}; > + > +static const struct hid_device_id gt683r_led_id[] = { > + { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, > + { } > +}; > + > +static void gt683r_brightness_set(struct led_classdev *led_cdev, > + enum led_brightness brightness) > +{ > + int i; > + struct device *dev = led_cdev->dev->parent; > + struct hid_device *hdev = container_of(dev, struct hid_device, dev); > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + for (i = 0; i < GT683R_LED_COUNT; i++) { > + if (led_cdev == &led->led_devs[i]) > + break; > + } > + > + if (i < GT683R_LED_COUNT) { > + led->brightnesses[i] = brightness; > + schedule_work(&led->work); > + } > +} > + > +static ssize_t leds_mode_show(struct device *dev, > + struct device_attribute *attr, > + char *buf) > +{ > + u8 sysfs_mode; > + struct hid_device *hdev = container_of(dev, struct hid_device, dev); > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + if (led->mode == GT683R_LED_NORMAL) > + sysfs_mode = 0; > + else if (led->mode == GT683R_LED_AUDIO) > + sysfs_mode = 1; > + else > + sysfs_mode = 2; > + > + return scnprintf(buf, PAGE_SIZE, "%u\n", sysfs_mode); > +} > + > +static ssize_t leds_mode_store(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t count) > +{ > + u8 sysfs_mode; > + struct hid_device *hdev = container_of(dev, struct hid_device, dev); > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + > + if (kstrtou8(buf, 10, &sysfs_mode) || sysfs_mode > 2) > + return -EINVAL; > + > + mutex_lock(&led->lock); > + > + if (sysfs_mode == 0) > + led->mode = GT683R_LED_NORMAL; > + else if (sysfs_mode == 1) > + led->mode = GT683R_LED_AUDIO; > + else > + led->mode = GT683R_LED_BREATHING; > + > + mutex_unlock(&led->lock); > + schedule_work(&led->work); > + > + return count; > +} > + > +static int gt683r_led_snd_msg(struct gt683r_led *led, u8 *msg) > +{ > + int ret; > + > + ret = hid_hw_raw_request(led->hdev, msg[0], msg, GT683R_BUFFER_SIZE, > + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); > + if (ret != GT683R_BUFFER_SIZE) { > + hid_err(led->hdev, > + "failed to send set report request: %i\n", ret); > + if (ret < 0) > + return ret; > + return -EIO; > + } > + > + return 0; > +} > + > +static int gt683r_leds_set(struct gt683r_led *led, u8 leds) > +{ > + int ret; > + u8 *buffer; > + > + buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); > + if (!buffer) > + return -ENOMEM; > + > + buffer[0] = 0x01; > + buffer[1] = 0x02; > + buffer[2] = 0x30; > + buffer[3] = leds; > + ret = gt683r_led_snd_msg(led, buffer); > + > + kfree(buffer); > + return ret; > +} > + > +static int gt683r_mode_set(struct gt683r_led *led, u8 mode) > +{ > + int ret; > + u8 *buffer; > + > + buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); > + if (!buffer) > + return -ENOMEM; > + > + buffer[0] = 0x01; > + buffer[1] = 0x02; > + buffer[2] = 0x20; > + buffer[3] = mode; > + buffer[4] = 0x01; > + ret = gt683r_led_snd_msg(led, buffer); > + > + kfree(buffer); > + return ret; > +} > + > +static void gt683r_led_work(struct work_struct *work) > +{ > + int i; > + u8 leds = 0; > + u8 mode; > + struct gt683r_led *led = container_of(work, struct gt683r_led, work); > + > + mutex_lock(&led->lock); > + > + for (i = 0; i < GT683R_LED_COUNT; i++) { > + if (led->brightnesses[i]) > + leds |= BIT(i); > + } > + > + if (gt683r_leds_set(led, leds)) > + goto fail; > + > + if (leds) > + mode = led->mode; > + else > + mode = GT683R_LED_OFF; > + > + gt683r_mode_set(led, mode); > +fail: > + mutex_unlock(&led->lock); > +} > + > +static DEVICE_ATTR_RW(leds_mode); > + > +static int gt683r_led_probe(struct hid_device *hdev, > + const struct hid_device_id *id) > +{ > + int i; > + int ret; > + int name_sz; > + char *name; > + struct gt683r_led *led; > + > + led = devm_kzalloc(&hdev->dev, sizeof(*led), GFP_KERNEL); > + if (!led) > + return -ENOMEM; > + > + led->mode = GT683R_LED_NORMAL; > + led->hdev = hdev; > + hid_set_drvdata(hdev, led); > + > + ret = hid_parse(hdev); > + if (ret) { > + hid_err(hdev, "hid parsing failed\n"); > + return ret; > + } > + > + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); > + if (ret) { > + hid_err(hdev, "hw start failed\n"); > + return ret; > + } > + > + for (i = 0; i < GT683R_LED_COUNT; i++) { > + name_sz = strlen(dev_name(&hdev->dev)) + > + strlen(gt683r_panel_names[i]) + 3; > + > + name = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL); > + if (!name) { > + ret = -ENOMEM; > + goto fail; > + } > + > + snprintf(name, name_sz, "%s::%s", > + dev_name(&hdev->dev), gt683r_panel_names[i]); > + led->led_devs[i].name = name; > + led->led_devs[i].max_brightness = 1; > + led->led_devs[i].brightness_set = gt683r_brightness_set; > + ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); > + if (ret) { > + hid_err(hdev, "could not register led device\n"); > + goto fail; > + } > + } > + > + ret = device_create_file(&led->hdev->dev, &dev_attr_leds_mode); > + if (ret) { > + hid_err(hdev, "could not make mode attribute file\n"); > + goto fail; > + } > + > + mutex_init(&led->lock); > + INIT_WORK(&led->work, gt683r_led_work); > + > + return 0; > + > +fail: > + for (i = i - 1; i >= 0; i--) > + led_classdev_unregister(&led->led_devs[i]); > + hid_hw_stop(hdev); > + return ret; > +} > + > +static void gt683r_led_remove(struct hid_device *hdev) > +{ > + int i; > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + device_remove_file(&hdev->dev, &dev_attr_leds_mode); > + for (i = 0; i < GT683R_LED_COUNT; i++) > + led_classdev_unregister(&led->led_devs[i]); > + flush_work(&led->work); > + hid_hw_stop(hdev); > +} > + > +static struct hid_driver gt683r_led_driver = { > + .probe = gt683r_led_probe, > + .remove = gt683r_led_remove, > + .name = "gt683r_led", > + .id_table = gt683r_led_id, > +}; > + > +module_hid_driver(gt683r_led_driver); > + > +MODULE_AUTHOR("Janne Kanniainen"); > +MODULE_DESCRIPTION("MSI GT683R led driver"); > +MODULE_LICENSE("GPL"); > diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h > index 34bb220..3692d37 100644 > --- a/drivers/hid/hid-ids.h > +++ b/drivers/hid/hid-ids.h > @@ -641,7 +641,7 @@ > #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 > > #define USB_VENDOR_ID_MSI 0x1770 > -#define USB_DEVICE_ID_MSI_GX680R_LED_PANEL 0xff00 > +#define USB_DEVICE_ID_MSI_GT683R_LED_PANEL 0xff00 > > #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400 > #define USB_DEVICE_ID_N_S_HARMONY 0xc359 > diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c > index 8e4ddb3..c640e1d 100644 > --- a/drivers/hid/usbhid/hid-quirks.c > +++ b/drivers/hid/usbhid/hid-quirks.c > @@ -73,7 +73,7 @@ static const struct hid_blacklist { > { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, > { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, > { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, > - { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, 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 }, > { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS }, -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v9] leds: USB: HID: Add support for MSI GT683R led panels @ 2014-06-18 16:11 ` Johan Hovold 0 siblings, 0 replies; 81+ messages in thread From: Johan Hovold @ 2014-06-18 16:11 UTC (permalink / raw) To: Janne Kanniainen Cc: jkosina, johan, cooloney, linux-kernel, linux-leds, linux-usb, linux-input On Wed, Jun 18, 2014 at 07:05:02PM +0300, Janne Kanniainen wrote: > This driver adds support for USB controlled led panels that exists in > MSI GT683R laptop > > Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> Reviewed-by: Johan Hovold <johan@kernel.org> Thanks, Janne! Johan > --- > Changes in v2: > - sorted headers to alphabetic order > - using devm_kzalloc > - using BIT(n) > - using usb_control_msg instead of usb_submit_urb > - removing unneeded code > Changes in v3: > - implemented as HID device > - some cleanups and bug fixes > > Changes in v4: > - more cleanups > - support for selecting leds > - suppport for selecting status > > Changes in v5: > - mode attribute documented under Documentation/ABI > - made array for led_classdev > - led devices uses now recommended naming scheme > > Changes in v6: > - flush_work added > - using hid device name instead of hard coded gt683r > - allocating name buffers with devm_kzalloc > > Changes in v7: > - buf with for fixed > > Changes in v8: > - some cleanups and bugs fixed > > Changes in v9: > - few style issues fixed > > .../ABI/testing/sysfs-class-hid-driver-gt683r | 14 + > drivers/hid/Kconfig | 14 + > drivers/hid/Makefile | 1 + > drivers/hid/hid-core.c | 1 + > drivers/hid/hid-gt683r.c | 309 +++++++++++++++++++++ > drivers/hid/hid-ids.h | 2 +- > drivers/hid/usbhid/hid-quirks.c | 2 +- > 7 files changed, 341 insertions(+), 2 deletions(-) > create mode 100644 Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > create mode 100644 drivers/hid/hid-gt683r.c > > diff --git a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > new file mode 100644 > index 0000000..317e9d5 > --- /dev/null > +++ b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > @@ -0,0 +1,14 @@ > +What: /sys/class/hidraw/<hidraw>/device/leds_mode > +Date: Jun 2014 > +KernelVersion: 3.17 > +Contact: Janne Kanniainen <janne.kanniainen@gmail.com> > +Description: > + Set the mode of LEDs > + > + 0 - normal > + 1 - audio > + 2 - breathing > + > + Normal: LEDs are fully on when enabled > + Audio: LEDs brightness depends on sound level > + Breathing: LEDs brightness varies at human breathing rate > \ No newline at end of file > diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig > index 7af9d0b..e2f4590 100644 > --- a/drivers/hid/Kconfig > +++ b/drivers/hid/Kconfig > @@ -261,6 +261,20 @@ config HOLTEK_FF > Say Y here if you have a Holtek On Line Grip based game controller > and want to have force feedback support for it. > > +config HID_GT683R > + tristate "MSI GT68xR LED support" > + depends on LEDS_CLASS && USB_HID > + ---help--- > + Say Y here if you want to enable support for the three MSI GT68xR LEDs > + > + This driver support following modes: > + - Normal: LEDs are fully on when enabled > + - Audio: LEDs brightness depends on sound level > + - Breathing: LEDs brightness varies at human breathing rate > + > + Currently the following devices are know to be supported: > + - MSI GT683R > + > config HID_HUION > tristate "Huion tablets" > depends on USB_HID > diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile > index fc712dd..7129311 100644 > --- a/drivers/hid/Makefile > +++ b/drivers/hid/Makefile > @@ -48,6 +48,7 @@ obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o > obj-$(CONFIG_HID_ELECOM) += hid-elecom.o > obj-$(CONFIG_HID_ELO) += hid-elo.o > obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o > +obj-$(CONFIG_HID_GT683R) += hid-gt683r.o > obj-$(CONFIG_HID_GYRATION) += hid-gyration.o > obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o > obj-$(CONFIG_HID_HOLTEK) += hid-holtek-mouse.o > diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c > index da52279..ec88fdb 100644 > --- a/drivers/hid/hid-core.c > +++ b/drivers/hid/hid-core.c > @@ -1827,6 +1827,7 @@ static const struct hid_device_id hid_have_special_driver[] = { > { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, > { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, > { 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) }, > { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) }, > { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2) }, > diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c > new file mode 100644 > index 0000000..077f7a1 > --- /dev/null > +++ b/drivers/hid/hid-gt683r.c > @@ -0,0 +1,309 @@ > +/* > + * MSI GT683R led driver > + * > + * Copyright (c) 2014 Janne Kanniainen <janne.kanniainen@gmail.com> > + * > + * This program is free software; you can redistribute it and/or > + * modify it under the terms of the GNU General Public License as > + * published by the Free Software Foundation; either version 2 of > + * the License, or (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + */ > + > +#include <linux/device.h> > +#include <linux/hid.h> > +#include <linux/kernel.h> > +#include <linux/leds.h> > +#include <linux/module.h> > + > +#include "hid-ids.h" > + > +#define GT683R_BUFFER_SIZE 8 > + > +/* > + * GT683R_LED_OFF: all LEDs are off > + * GT683R_LED_AUDIO: LEDs brightness depends on sound level > + * GT683R_LED_BREATHING: LEDs brightness varies at human breathing rate > + * GT683R_LED_NORMAL: LEDs are fully on when enabled > + */ > +enum gt683r_led_mode { > + GT683R_LED_OFF = 0, > + GT683R_LED_AUDIO = 2, > + GT683R_LED_BREATHING = 3, > + GT683R_LED_NORMAL = 5 > +}; > + > +enum gt683r_panels { > + GT683R_LED_BACK = 0, > + GT683R_LED_SIDE = 1, > + GT683R_LED_FRONT = 2, > + GT683R_LED_COUNT, > +}; > + > +static const char * const gt683r_panel_names[] = { > + "back", > + "side", > + "front", > +}; > + > +struct gt683r_led { > + struct hid_device *hdev; > + struct led_classdev led_devs[GT683R_LED_COUNT]; > + struct mutex lock; > + struct work_struct work; > + enum led_brightness brightnesses[GT683R_LED_COUNT]; > + enum gt683r_led_mode mode; > +}; > + > +static const struct hid_device_id gt683r_led_id[] = { > + { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, > + { } > +}; > + > +static void gt683r_brightness_set(struct led_classdev *led_cdev, > + enum led_brightness brightness) > +{ > + int i; > + struct device *dev = led_cdev->dev->parent; > + struct hid_device *hdev = container_of(dev, struct hid_device, dev); > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + for (i = 0; i < GT683R_LED_COUNT; i++) { > + if (led_cdev == &led->led_devs[i]) > + break; > + } > + > + if (i < GT683R_LED_COUNT) { > + led->brightnesses[i] = brightness; > + schedule_work(&led->work); > + } > +} > + > +static ssize_t leds_mode_show(struct device *dev, > + struct device_attribute *attr, > + char *buf) > +{ > + u8 sysfs_mode; > + struct hid_device *hdev = container_of(dev, struct hid_device, dev); > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + if (led->mode == GT683R_LED_NORMAL) > + sysfs_mode = 0; > + else if (led->mode == GT683R_LED_AUDIO) > + sysfs_mode = 1; > + else > + sysfs_mode = 2; > + > + return scnprintf(buf, PAGE_SIZE, "%u\n", sysfs_mode); > +} > + > +static ssize_t leds_mode_store(struct device *dev, > + struct device_attribute *attr, > + const char *buf, size_t count) > +{ > + u8 sysfs_mode; > + struct hid_device *hdev = container_of(dev, struct hid_device, dev); > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + > + if (kstrtou8(buf, 10, &sysfs_mode) || sysfs_mode > 2) > + return -EINVAL; > + > + mutex_lock(&led->lock); > + > + if (sysfs_mode == 0) > + led->mode = GT683R_LED_NORMAL; > + else if (sysfs_mode == 1) > + led->mode = GT683R_LED_AUDIO; > + else > + led->mode = GT683R_LED_BREATHING; > + > + mutex_unlock(&led->lock); > + schedule_work(&led->work); > + > + return count; > +} > + > +static int gt683r_led_snd_msg(struct gt683r_led *led, u8 *msg) > +{ > + int ret; > + > + ret = hid_hw_raw_request(led->hdev, msg[0], msg, GT683R_BUFFER_SIZE, > + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); > + if (ret != GT683R_BUFFER_SIZE) { > + hid_err(led->hdev, > + "failed to send set report request: %i\n", ret); > + if (ret < 0) > + return ret; > + return -EIO; > + } > + > + return 0; > +} > + > +static int gt683r_leds_set(struct gt683r_led *led, u8 leds) > +{ > + int ret; > + u8 *buffer; > + > + buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); > + if (!buffer) > + return -ENOMEM; > + > + buffer[0] = 0x01; > + buffer[1] = 0x02; > + buffer[2] = 0x30; > + buffer[3] = leds; > + ret = gt683r_led_snd_msg(led, buffer); > + > + kfree(buffer); > + return ret; > +} > + > +static int gt683r_mode_set(struct gt683r_led *led, u8 mode) > +{ > + int ret; > + u8 *buffer; > + > + buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); > + if (!buffer) > + return -ENOMEM; > + > + buffer[0] = 0x01; > + buffer[1] = 0x02; > + buffer[2] = 0x20; > + buffer[3] = mode; > + buffer[4] = 0x01; > + ret = gt683r_led_snd_msg(led, buffer); > + > + kfree(buffer); > + return ret; > +} > + > +static void gt683r_led_work(struct work_struct *work) > +{ > + int i; > + u8 leds = 0; > + u8 mode; > + struct gt683r_led *led = container_of(work, struct gt683r_led, work); > + > + mutex_lock(&led->lock); > + > + for (i = 0; i < GT683R_LED_COUNT; i++) { > + if (led->brightnesses[i]) > + leds |= BIT(i); > + } > + > + if (gt683r_leds_set(led, leds)) > + goto fail; > + > + if (leds) > + mode = led->mode; > + else > + mode = GT683R_LED_OFF; > + > + gt683r_mode_set(led, mode); > +fail: > + mutex_unlock(&led->lock); > +} > + > +static DEVICE_ATTR_RW(leds_mode); > + > +static int gt683r_led_probe(struct hid_device *hdev, > + const struct hid_device_id *id) > +{ > + int i; > + int ret; > + int name_sz; > + char *name; > + struct gt683r_led *led; > + > + led = devm_kzalloc(&hdev->dev, sizeof(*led), GFP_KERNEL); > + if (!led) > + return -ENOMEM; > + > + led->mode = GT683R_LED_NORMAL; > + led->hdev = hdev; > + hid_set_drvdata(hdev, led); > + > + ret = hid_parse(hdev); > + if (ret) { > + hid_err(hdev, "hid parsing failed\n"); > + return ret; > + } > + > + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); > + if (ret) { > + hid_err(hdev, "hw start failed\n"); > + return ret; > + } > + > + for (i = 0; i < GT683R_LED_COUNT; i++) { > + name_sz = strlen(dev_name(&hdev->dev)) + > + strlen(gt683r_panel_names[i]) + 3; > + > + name = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL); > + if (!name) { > + ret = -ENOMEM; > + goto fail; > + } > + > + snprintf(name, name_sz, "%s::%s", > + dev_name(&hdev->dev), gt683r_panel_names[i]); > + led->led_devs[i].name = name; > + led->led_devs[i].max_brightness = 1; > + led->led_devs[i].brightness_set = gt683r_brightness_set; > + ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); > + if (ret) { > + hid_err(hdev, "could not register led device\n"); > + goto fail; > + } > + } > + > + ret = device_create_file(&led->hdev->dev, &dev_attr_leds_mode); > + if (ret) { > + hid_err(hdev, "could not make mode attribute file\n"); > + goto fail; > + } > + > + mutex_init(&led->lock); > + INIT_WORK(&led->work, gt683r_led_work); > + > + return 0; > + > +fail: > + for (i = i - 1; i >= 0; i--) > + led_classdev_unregister(&led->led_devs[i]); > + hid_hw_stop(hdev); > + return ret; > +} > + > +static void gt683r_led_remove(struct hid_device *hdev) > +{ > + int i; > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + device_remove_file(&hdev->dev, &dev_attr_leds_mode); > + for (i = 0; i < GT683R_LED_COUNT; i++) > + led_classdev_unregister(&led->led_devs[i]); > + flush_work(&led->work); > + hid_hw_stop(hdev); > +} > + > +static struct hid_driver gt683r_led_driver = { > + .probe = gt683r_led_probe, > + .remove = gt683r_led_remove, > + .name = "gt683r_led", > + .id_table = gt683r_led_id, > +}; > + > +module_hid_driver(gt683r_led_driver); > + > +MODULE_AUTHOR("Janne Kanniainen"); > +MODULE_DESCRIPTION("MSI GT683R led driver"); > +MODULE_LICENSE("GPL"); > diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h > index 34bb220..3692d37 100644 > --- a/drivers/hid/hid-ids.h > +++ b/drivers/hid/hid-ids.h > @@ -641,7 +641,7 @@ > #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 > > #define USB_VENDOR_ID_MSI 0x1770 > -#define USB_DEVICE_ID_MSI_GX680R_LED_PANEL 0xff00 > +#define USB_DEVICE_ID_MSI_GT683R_LED_PANEL 0xff00 > > #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400 > #define USB_DEVICE_ID_N_S_HARMONY 0xc359 > diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c > index 8e4ddb3..c640e1d 100644 > --- a/drivers/hid/usbhid/hid-quirks.c > +++ b/drivers/hid/usbhid/hid-quirks.c > @@ -73,7 +73,7 @@ static const struct hid_blacklist { > { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, > { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, > { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, > - { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, 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 }, > { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS }, ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v9] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-18 16:11 ` Johan Hovold (?) @ 2014-06-18 18:41 ` Janne Kanniainen 2014-06-18 18:46 ` Johan Hovold -1 siblings, 1 reply; 81+ messages in thread From: Janne Kanniainen @ 2014-06-18 18:41 UTC (permalink / raw) To: Johan Hovold Cc: Jiri Kosina, Bryan Wu, linux-kernel, linux-leds, linux-usb, linux-input >> This driver adds support for USB controlled led panels that exists in >> MSI GT683R laptop >> >> Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> > > Reviewed-by: Johan Hovold <johan@kernel.org> > > Thanks, Janne! > > Johan Thank you for reviewing my patch :) I sure learnt a lot from you and if I ever send patch in future, it is for sure much easier (Maybe I get it trough in 8th time ;)) Janne ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v9] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-18 18:41 ` Janne Kanniainen @ 2014-06-18 18:46 ` Johan Hovold 0 siblings, 0 replies; 81+ messages in thread From: Johan Hovold @ 2014-06-18 18:46 UTC (permalink / raw) To: Janne Kanniainen Cc: Johan Hovold, Jiri Kosina, Bryan Wu, linux-kernel, linux-leds, linux-usb, linux-input On Wed, Jun 18, 2014 at 09:41:35PM +0300, Janne Kanniainen wrote: > >> This driver adds support for USB controlled led panels that exists in > >> MSI GT683R laptop > >> > >> Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> > > > > Reviewed-by: Johan Hovold <johan@kernel.org> > > > > Thanks, Janne! > > > > Johan > > Thank you for reviewing my patch :) I sure learnt a > lot from you and if I ever send patch in future, it is for sure much > easier (Maybe I get it trough in 8th time ;)) My pleasure. It's indeed a very good first patch you have created. Good luck with the next one! ;) Johan ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v9] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-18 16:11 ` Johan Hovold (?) (?) @ 2014-06-18 22:10 ` Jiri Kosina -1 siblings, 0 replies; 81+ messages in thread From: Jiri Kosina @ 2014-06-18 22:10 UTC (permalink / raw) To: Johan Hovold Cc: Janne Kanniainen, cooloney, linux-kernel, linux-leds, linux-usb, linux-input On Wed, 18 Jun 2014, Johan Hovold wrote: > > This driver adds support for USB controlled led panels that exists in > > MSI GT683R laptop > > > > Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> > > Reviewed-by: Johan Hovold <johan@kernel.org> > > Thanks, Janne! Now applied. Thanks Janne for the driver, and thanks a lot Johan for a very careful review, I really appreciate it. -- Jiri Kosina SUSE Labs ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v9] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-18 16:05 ` [PATCH v9] " Janne Kanniainen [not found] ` <1403107502-14106-1-git-send-email-janne.kanniainen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> @ 2014-06-23 14:35 ` Oliver Neukum 2014-06-23 14:42 ` Johan Hovold 1 sibling, 1 reply; 81+ messages in thread From: Oliver Neukum @ 2014-06-23 14:35 UTC (permalink / raw) To: Janne Kanniainen Cc: jkosina, johan, cooloney, linux-kernel, linux-leds, linux-usb, linux-input On Wed, 2014-06-18 at 19:05 +0300, Janne Kanniainen wrote: > This driver adds support for USB controlled led panels that exists in > MSI GT683R laptop > > +static int gt683r_led_probe(struct hid_device *hdev, > + const struct hid_device_id *id) > +{ > + int i; > + int ret; > + int name_sz; > + char *name; > + struct gt683r_led *led; > + > + led = devm_kzalloc(&hdev->dev, sizeof(*led), GFP_KERNEL); > + if (!led) > + return -ENOMEM; > + > + led->mode = GT683R_LED_NORMAL; > + led->hdev = hdev; > + hid_set_drvdata(hdev, led); > + > + ret = hid_parse(hdev); > + if (ret) { > + hid_err(hdev, "hid parsing failed\n"); > + return ret; > + } > + > + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); > + if (ret) { > + hid_err(hdev, "hw start failed\n"); > + return ret; > + } > + > + for (i = 0; i < GT683R_LED_COUNT; i++) { > + name_sz = strlen(dev_name(&hdev->dev)) + > + strlen(gt683r_panel_names[i]) + 3; > + > + name = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL); > + if (!name) { > + ret = -ENOMEM; > + goto fail; > + } > + > + snprintf(name, name_sz, "%s::%s", > + dev_name(&hdev->dev), gt683r_panel_names[i]); > + led->led_devs[i].name = name; > + led->led_devs[i].max_brightness = 1; > + led->led_devs[i].brightness_set = gt683r_brightness_set; > + ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); > + if (ret) { > + hid_err(hdev, "could not register led device\n"); > + goto fail; > + } > + } > + > + ret = device_create_file(&led->hdev->dev, &dev_attr_leds_mode); > + if (ret) { > + hid_err(hdev, "could not make mode attribute file\n"); > + goto fail; > + } > + This is the window. > + mutex_init(&led->lock); > + INIT_WORK(&led->work, gt683r_led_work); > + And here we have a problem. This is a race condition. At this time you've already created the sysfs files. So their methods can be called. They will lock a mutex and/or schedule work that hasn't been initialized. The initialization must be done before anything in sysfs is created. > + return 0; > + > +fail: > + for (i = i - 1; i >= 0; i--) > + led_classdev_unregister(&led->led_devs[i]); > + hid_hw_stop(hdev); > + return ret; > +} > + Sorry for noticing this thread late. Regards Oliver ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v9] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-23 14:35 ` Oliver Neukum @ 2014-06-23 14:42 ` Johan Hovold 2014-06-23 16:17 ` Greg KH 2014-06-23 16:20 ` [PATCH v9] leds: USB: HID: Add support for MSI GT683R led panels Janne Kanniainen 0 siblings, 2 replies; 81+ messages in thread From: Johan Hovold @ 2014-06-23 14:42 UTC (permalink / raw) To: Oliver Neukum Cc: Janne Kanniainen, jkosina, johan, cooloney, linux-kernel, linux-leds, linux-usb, linux-input On Mon, Jun 23, 2014 at 04:35:13PM +0200, Oliver Neukum wrote: > On Wed, 2014-06-18 at 19:05 +0300, Janne Kanniainen wrote: > > This driver adds support for USB controlled led panels that exists in > > MSI GT683R laptop > > > > > +static int gt683r_led_probe(struct hid_device *hdev, > > + const struct hid_device_id *id) > > +{ > > + int i; > > + int ret; > > + int name_sz; > > + char *name; > > + struct gt683r_led *led; > > + > > + led = devm_kzalloc(&hdev->dev, sizeof(*led), GFP_KERNEL); > > + if (!led) > > + return -ENOMEM; > > + > > + led->mode = GT683R_LED_NORMAL; > > + led->hdev = hdev; > > + hid_set_drvdata(hdev, led); > > + > > + ret = hid_parse(hdev); > > + if (ret) { > > + hid_err(hdev, "hid parsing failed\n"); > > + return ret; > > + } > > + > > + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); > > + if (ret) { > > + hid_err(hdev, "hw start failed\n"); > > + return ret; > > + } > > + > > + for (i = 0; i < GT683R_LED_COUNT; i++) { > > + name_sz = strlen(dev_name(&hdev->dev)) + > > + strlen(gt683r_panel_names[i]) + 3; > > + > > + name = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL); > > + if (!name) { > > + ret = -ENOMEM; > > + goto fail; > > + } > > + > > + snprintf(name, name_sz, "%s::%s", > > + dev_name(&hdev->dev), gt683r_panel_names[i]); > > + led->led_devs[i].name = name; > > + led->led_devs[i].max_brightness = 1; > > + led->led_devs[i].brightness_set = gt683r_brightness_set; > > + ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); > > + if (ret) { > > + hid_err(hdev, "could not register led device\n"); > > + goto fail; > > + } > > + } > > + > > + ret = device_create_file(&led->hdev->dev, &dev_attr_leds_mode); > > + if (ret) { > > + hid_err(hdev, "could not make mode attribute file\n"); > > + goto fail; > > + } > > + > > This is the window. > > > + mutex_init(&led->lock); > > + INIT_WORK(&led->work, gt683r_led_work); > > + > > And here we have a problem. This is a race condition. > At this time you've already created the sysfs files. So > their methods can be called. They will lock a mutex and/or > schedule work that hasn't been initialized. > The initialization must be done before anything in sysfs > is created. Just move the initialisation of the lock and work to the other private data initialisations directly after it's allocated. Can you send a follow up patch, Janne? Thanks Oliver! Johan ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v9] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-23 14:42 ` Johan Hovold @ 2014-06-23 16:17 ` Greg KH 2014-06-23 17:16 ` [PATCH v10] " Janne Kanniainen 2014-06-23 16:20 ` [PATCH v9] leds: USB: HID: Add support for MSI GT683R led panels Janne Kanniainen 1 sibling, 1 reply; 81+ messages in thread From: Greg KH @ 2014-06-23 16:17 UTC (permalink / raw) To: Johan Hovold Cc: Oliver Neukum, Janne Kanniainen, jkosina, cooloney, linux-kernel, linux-leds, linux-usb, linux-input On Mon, Jun 23, 2014 at 04:42:55PM +0200, Johan Hovold wrote: > On Mon, Jun 23, 2014 at 04:35:13PM +0200, Oliver Neukum wrote: > > On Wed, 2014-06-18 at 19:05 +0300, Janne Kanniainen wrote: > > > This driver adds support for USB controlled led panels that exists in > > > MSI GT683R laptop > > > > > > > > +static int gt683r_led_probe(struct hid_device *hdev, > > > + const struct hid_device_id *id) > > > +{ > > > + int i; > > > + int ret; > > > + int name_sz; > > > + char *name; > > > + struct gt683r_led *led; > > > + > > > + led = devm_kzalloc(&hdev->dev, sizeof(*led), GFP_KERNEL); > > > + if (!led) > > > + return -ENOMEM; > > > + > > > + led->mode = GT683R_LED_NORMAL; > > > + led->hdev = hdev; > > > + hid_set_drvdata(hdev, led); > > > + > > > + ret = hid_parse(hdev); > > > + if (ret) { > > > + hid_err(hdev, "hid parsing failed\n"); > > > + return ret; > > > + } > > > + > > > + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); > > > + if (ret) { > > > + hid_err(hdev, "hw start failed\n"); > > > + return ret; > > > + } > > > + > > > + for (i = 0; i < GT683R_LED_COUNT; i++) { > > > + name_sz = strlen(dev_name(&hdev->dev)) + > > > + strlen(gt683r_panel_names[i]) + 3; > > > + > > > + name = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL); > > > + if (!name) { > > > + ret = -ENOMEM; > > > + goto fail; > > > + } > > > + > > > + snprintf(name, name_sz, "%s::%s", > > > + dev_name(&hdev->dev), gt683r_panel_names[i]); > > > + led->led_devs[i].name = name; > > > + led->led_devs[i].max_brightness = 1; > > > + led->led_devs[i].brightness_set = gt683r_brightness_set; > > > + ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); > > > + if (ret) { > > > + hid_err(hdev, "could not register led device\n"); > > > + goto fail; > > > + } > > > + } > > > + > > > + ret = device_create_file(&led->hdev->dev, &dev_attr_leds_mode); > > > + if (ret) { > > > + hid_err(hdev, "could not make mode attribute file\n"); > > > + goto fail; > > > + } > > > + > > > > This is the window. > > > > > + mutex_init(&led->lock); > > > + INIT_WORK(&led->work, gt683r_led_work); > > > + > > > > And here we have a problem. This is a race condition. > > At this time you've already created the sysfs files. So > > their methods can be called. They will lock a mutex and/or > > schedule work that hasn't been initialized. > > The initialization must be done before anything in sysfs > > is created. > > Just move the initialisation of the lock and work to the other private > data initialisations directly after it's allocated. > > Can you send a follow up patch, Janne? No driver should be creating sysfs files directly, use the proper attribute group interface instead. That way the files are created _before_ the device is announced to userspace, instead of after, which is a race condition there as well. thanks, greg k-h ^ permalink raw reply [flat|nested] 81+ messages in thread
* [PATCH v10] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-23 16:17 ` Greg KH @ 2014-06-23 17:16 ` Janne Kanniainen 2014-06-23 17:27 ` Johan Hovold [not found] ` <1403543808-8228-1-git-send-email-janne.kanniainen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 0 siblings, 2 replies; 81+ messages in thread From: Janne Kanniainen @ 2014-06-23 17:16 UTC (permalink / raw) To: johan, greg, jkosina Cc: cooloney, linux-kernel, linux-leds, linux-usb, linux-input, Janne Kanniainen This driver adds support for USB controlled led panels that exists in MSI GT683R laptop Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> --- Changes in v2: - sorted headers to alphabetic order - using devm_kzalloc - using BIT(n) - using usb_control_msg instead of usb_submit_urb - removing unneeded code Changes in v3: - implemented as HID device - some cleanups and bug fixes Changes in v4: - more cleanups - support for selecting leds - suppport for selecting status Changes in v5: - mode attribute documented under Documentation/ABI - made array for led_classdev - led devices uses now recommended naming scheme Changes in v6: - flush_work added - using hid device name instead of hard coded gt683r - allocating name buffers with devm_kzalloc Changes in v7: - buf with for fixed Changes in v8: - some cleanups and bugs fixed Changes in v9: - few style issues fixed Changes in v10: - race condition fixed - using proper attribute group .../ABI/testing/sysfs-class-hid-driver-gt683r | 14 + drivers/hid/Kconfig | 14 + drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-gt683r.c | 318 +++++++++++++++++++++ drivers/hid/hid-ids.h | 2 +- drivers/hid/usbhid/hid-quirks.c | 2 +- 7 files changed, 350 insertions(+), 2 deletions(-) create mode 100644 Documentation/ABI/testing/sysfs-class-hid-driver-gt683r create mode 100644 drivers/hid/hid-gt683r.c diff --git a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r new file mode 100644 index 0000000..317e9d5 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r @@ -0,0 +1,14 @@ +What: /sys/class/hidraw/<hidraw>/device/leds_mode +Date: Jun 2014 +KernelVersion: 3.17 +Contact: Janne Kanniainen <janne.kanniainen@gmail.com> +Description: + Set the mode of LEDs + + 0 - normal + 1 - audio + 2 - breathing + + Normal: LEDs are fully on when enabled + Audio: LEDs brightness depends on sound level + Breathing: LEDs brightness varies at human breathing rate \ No newline at end of file diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 7af9d0b..e2f4590 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -261,6 +261,20 @@ config HOLTEK_FF Say Y here if you have a Holtek On Line Grip based game controller and want to have force feedback support for it. +config HID_GT683R + tristate "MSI GT68xR LED support" + depends on LEDS_CLASS && USB_HID + ---help--- + Say Y here if you want to enable support for the three MSI GT68xR LEDs + + This driver support following modes: + - Normal: LEDs are fully on when enabled + - Audio: LEDs brightness depends on sound level + - Breathing: LEDs brightness varies at human breathing rate + + Currently the following devices are know to be supported: + - MSI GT683R + config HID_HUION tristate "Huion tablets" depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index fc712dd..7129311 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -48,6 +48,7 @@ obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o obj-$(CONFIG_HID_ELECOM) += hid-elecom.o obj-$(CONFIG_HID_ELO) += hid-elo.o obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o +obj-$(CONFIG_HID_GT683R) += hid-gt683r.o obj-$(CONFIG_HID_GYRATION) += hid-gyration.o obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.o obj-$(CONFIG_HID_HOLTEK) += hid-holtek-mouse.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index da52279..ec88fdb 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1827,6 +1827,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) }, { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) }, { 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) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1) }, { HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2) }, diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c new file mode 100644 index 0000000..5bd0113 --- /dev/null +++ b/drivers/hid/hid-gt683r.c @@ -0,0 +1,318 @@ +/* + * MSI GT683R led driver + * + * Copyright (c) 2014 Janne Kanniainen <janne.kanniainen@gmail.com> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#include <linux/device.h> +#include <linux/hid.h> +#include <linux/kernel.h> +#include <linux/leds.h> +#include <linux/module.h> + +#include "hid-ids.h" + +#define GT683R_BUFFER_SIZE 8 + +/* + * GT683R_LED_OFF: all LEDs are off + * GT683R_LED_AUDIO: LEDs brightness depends on sound level + * GT683R_LED_BREATHING: LEDs brightness varies at human breathing rate + * GT683R_LED_NORMAL: LEDs are fully on when enabled + */ +enum gt683r_led_mode { + GT683R_LED_OFF = 0, + GT683R_LED_AUDIO = 2, + GT683R_LED_BREATHING = 3, + GT683R_LED_NORMAL = 5 +}; + +enum gt683r_panels { + GT683R_LED_BACK = 0, + GT683R_LED_SIDE = 1, + GT683R_LED_FRONT = 2, + GT683R_LED_COUNT, +}; + +static const char * const gt683r_panel_names[] = { + "back", + "side", + "front", +}; + +struct gt683r_led { + struct hid_device *hdev; + struct led_classdev led_devs[GT683R_LED_COUNT]; + struct mutex lock; + struct work_struct work; + enum led_brightness brightnesses[GT683R_LED_COUNT]; + enum gt683r_led_mode mode; +}; + +static const struct hid_device_id gt683r_led_id[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, + { } +}; + +static void gt683r_brightness_set(struct led_classdev *led_cdev, + enum led_brightness brightness) +{ + int i; + struct device *dev = led_cdev->dev->parent; + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct gt683r_led *led = hid_get_drvdata(hdev); + + for (i = 0; i < GT683R_LED_COUNT; i++) { + if (led_cdev == &led->led_devs[i]) + break; + } + + if (i < GT683R_LED_COUNT) { + led->brightnesses[i] = brightness; + schedule_work(&led->work); + } +} + +static ssize_t leds_mode_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + u8 sysfs_mode; + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct gt683r_led *led = hid_get_drvdata(hdev); + + if (led->mode == GT683R_LED_NORMAL) + sysfs_mode = 0; + else if (led->mode == GT683R_LED_AUDIO) + sysfs_mode = 1; + else + sysfs_mode = 2; + + return scnprintf(buf, PAGE_SIZE, "%u\n", sysfs_mode); +} + +static ssize_t leds_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + u8 sysfs_mode; + struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct gt683r_led *led = hid_get_drvdata(hdev); + + + if (kstrtou8(buf, 10, &sysfs_mode) || sysfs_mode > 2) + return -EINVAL; + + mutex_lock(&led->lock); + + if (sysfs_mode == 0) + led->mode = GT683R_LED_NORMAL; + else if (sysfs_mode == 1) + led->mode = GT683R_LED_AUDIO; + else + led->mode = GT683R_LED_BREATHING; + + mutex_unlock(&led->lock); + schedule_work(&led->work); + + return count; +} + +static int gt683r_led_snd_msg(struct gt683r_led *led, u8 *msg) +{ + int ret; + + ret = hid_hw_raw_request(led->hdev, msg[0], msg, GT683R_BUFFER_SIZE, + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); + if (ret != GT683R_BUFFER_SIZE) { + hid_err(led->hdev, + "failed to send set report request: %i\n", ret); + if (ret < 0) + return ret; + return -EIO; + } + + return 0; +} + +static int gt683r_leds_set(struct gt683r_led *led, u8 leds) +{ + int ret; + u8 *buffer; + + buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + buffer[0] = 0x01; + buffer[1] = 0x02; + buffer[2] = 0x30; + buffer[3] = leds; + ret = gt683r_led_snd_msg(led, buffer); + + kfree(buffer); + return ret; +} + +static int gt683r_mode_set(struct gt683r_led *led, u8 mode) +{ + int ret; + u8 *buffer; + + buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); + if (!buffer) + return -ENOMEM; + + buffer[0] = 0x01; + buffer[1] = 0x02; + buffer[2] = 0x20; + buffer[3] = mode; + buffer[4] = 0x01; + ret = gt683r_led_snd_msg(led, buffer); + + kfree(buffer); + return ret; +} + +static void gt683r_led_work(struct work_struct *work) +{ + int i; + u8 leds = 0; + u8 mode; + struct gt683r_led *led = container_of(work, struct gt683r_led, work); + + mutex_lock(&led->lock); + + for (i = 0; i < GT683R_LED_COUNT; i++) { + if (led->brightnesses[i]) + leds |= BIT(i); + } + + if (gt683r_leds_set(led, leds)) + goto fail; + + if (leds) + mode = led->mode; + else + mode = GT683R_LED_OFF; + + gt683r_mode_set(led, mode); +fail: + mutex_unlock(&led->lock); +} + +static DEVICE_ATTR_RW(leds_mode); + +static struct attribute *gt683r_attributes[] = { + &dev_attr_leds_mode.attr, + NULL, +}; + +static struct attribute_group gt683r_attribute_group = { + .attrs = gt683r_attributes +}; + +static int gt683r_led_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + int i; + int ret; + int name_sz; + char *name; + struct gt683r_led *led; + + led = devm_kzalloc(&hdev->dev, sizeof(*led), GFP_KERNEL); + if (!led) + return -ENOMEM; + + mutex_init(&led->lock); + INIT_WORK(&led->work, gt683r_led_work); + + led->mode = GT683R_LED_NORMAL; + led->hdev = hdev; + hid_set_drvdata(hdev, led); + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "hid parsing failed\n"); + return ret; + } + + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); + if (ret) { + hid_err(hdev, "hw start failed\n"); + return ret; + } + + for (i = 0; i < GT683R_LED_COUNT; i++) { + name_sz = strlen(dev_name(&hdev->dev)) + + strlen(gt683r_panel_names[i]) + 3; + + name = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL); + if (!name) { + ret = -ENOMEM; + goto fail; + } + + snprintf(name, name_sz, "%s::%s", + dev_name(&hdev->dev), gt683r_panel_names[i]); + led->led_devs[i].name = name; + led->led_devs[i].max_brightness = 1; + led->led_devs[i].brightness_set = gt683r_brightness_set; + ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); + if (ret) { + hid_err(hdev, "could not register led device\n"); + goto fail; + } + } + + ret = sysfs_create_group(&led->hdev->dev.kobj, >683r_attribute_group); + if (ret) { + hid_err(hdev, "failed to create sysfs attributes\n"); + goto fail; + } + + return 0; + +fail: + for (i = i - 1; i >= 0; i--) + led_classdev_unregister(&led->led_devs[i]); + hid_hw_stop(hdev); + return ret; +} + +static void gt683r_led_remove(struct hid_device *hdev) +{ + int i; + struct gt683r_led *led = hid_get_drvdata(hdev); + + sysfs_remove_group(&led->hdev->dev.kobj, >683r_attribute_group); + for (i = 0; i < GT683R_LED_COUNT; i++) + led_classdev_unregister(&led->led_devs[i]); + flush_work(&led->work); + hid_hw_stop(hdev); +} + +static struct hid_driver gt683r_led_driver = { + .probe = gt683r_led_probe, + .remove = gt683r_led_remove, + .name = "gt683r_led", + .id_table = gt683r_led_id, +}; + +module_hid_driver(gt683r_led_driver); + +MODULE_AUTHOR("Janne Kanniainen"); +MODULE_DESCRIPTION("MSI GT683R led driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 34bb220..3692d37 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -641,7 +641,7 @@ #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 #define USB_VENDOR_ID_MSI 0x1770 -#define USB_DEVICE_ID_MSI_GX680R_LED_PANEL 0xff00 +#define USB_DEVICE_ID_MSI_GT683R_LED_PANEL 0xff00 #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400 #define USB_DEVICE_ID_N_S_HARMONY 0xc359 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 8e4ddb3..c640e1d 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -73,7 +73,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, - { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, 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 }, { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS }, -- 1.9.2 ^ permalink raw reply related [flat|nested] 81+ messages in thread
* Re: [PATCH v10] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-23 17:16 ` [PATCH v10] " Janne Kanniainen @ 2014-06-23 17:27 ` Johan Hovold [not found] ` <1403543808-8228-1-git-send-email-janne.kanniainen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 1 sibling, 0 replies; 81+ messages in thread From: Johan Hovold @ 2014-06-23 17:27 UTC (permalink / raw) To: Janne Kanniainen Cc: johan, greg, jkosina, cooloney, linux-kernel, linux-leds, linux-usb, linux-input On Mon, Jun 23, 2014 at 08:16:48PM +0300, Janne Kanniainen wrote: > This driver adds support for USB controlled led panels that exists in > MSI GT683R laptop > > Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> > --- > Changes in v2: > - sorted headers to alphabetic order > - using devm_kzalloc > - using BIT(n) > - using usb_control_msg instead of usb_submit_urb > - removing unneeded code > Changes in v3: > - implemented as HID device > - some cleanups and bug fixes > Changes in v4: > - more cleanups > - support for selecting leds > - suppport for selecting status > > Changes in v5: > - mode attribute documented under Documentation/ABI > - made array for led_classdev > - led devices uses now recommended naming scheme > > Changes in v6: > - flush_work added > - using hid device name instead of hard coded gt683r > - allocating name buffers with devm_kzalloc > > Changes in v7: > - buf with for fixed > > Changes in v8: > - some cleanups and bugs fixed > > Changes in v9: > - few style issues fixed > > Changes in v10: > - race condition fixed > - using proper attribute group You need to send a separate patch on top of v9, which Jiri has already applied to his tree. <snip> > +static DEVICE_ATTR_RW(leds_mode); > + > +static struct attribute *gt683r_attributes[] = { > + &dev_attr_leds_mode.attr, > + NULL, > +}; > + > +static struct attribute_group gt683r_attribute_group = { > + .attrs = gt683r_attributes > +}; > + > +static int gt683r_led_probe(struct hid_device *hdev, > + const struct hid_device_id *id) > +{ > + int i; > + int ret; > + int name_sz; > + char *name; > + struct gt683r_led *led; > + > + led = devm_kzalloc(&hdev->dev, sizeof(*led), GFP_KERNEL); > + if (!led) > + return -ENOMEM; > + > + mutex_init(&led->lock); > + INIT_WORK(&led->work, gt683r_led_work); > + > + led->mode = GT683R_LED_NORMAL; > + led->hdev = hdev; > + hid_set_drvdata(hdev, led); > + > + ret = hid_parse(hdev); > + if (ret) { > + hid_err(hdev, "hid parsing failed\n"); > + return ret; > + } > + > + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); > + if (ret) { > + hid_err(hdev, "hw start failed\n"); > + return ret; > + } > + > + for (i = 0; i < GT683R_LED_COUNT; i++) { > + name_sz = strlen(dev_name(&hdev->dev)) + > + strlen(gt683r_panel_names[i]) + 3; > + > + name = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL); > + if (!name) { > + ret = -ENOMEM; > + goto fail; > + } > + > + snprintf(name, name_sz, "%s::%s", > + dev_name(&hdev->dev), gt683r_panel_names[i]); > + led->led_devs[i].name = name; > + led->led_devs[i].max_brightness = 1; > + led->led_devs[i].brightness_set = gt683r_brightness_set; > + ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); > + if (ret) { > + hid_err(hdev, "could not register led device\n"); > + goto fail; > + } > + } > + > + ret = sysfs_create_group(&led->hdev->dev.kobj, >683r_attribute_group); > + if (ret) { > + hid_err(hdev, "failed to create sysfs attributes\n"); > + goto fail; > + } This does not solve the race Greg is referring to. There's some more info here: http://kroah.com/log/blog/2013/06/26/how-to-create-a-sysfs-file-correctly/ but I'm not sure exactly how you'd apply that to an HID driver. Perhaps you could use the struct device_driver in struct hid_driver (although it is currently marked as "private"). Johan > + > + return 0; > + > +fail: > + for (i = i - 1; i >= 0; i--) > + led_classdev_unregister(&led->led_devs[i]); > + hid_hw_stop(hdev); > + return ret; > +} > + > +static void gt683r_led_remove(struct hid_device *hdev) > +{ > + int i; > + struct gt683r_led *led = hid_get_drvdata(hdev); > + > + sysfs_remove_group(&led->hdev->dev.kobj, >683r_attribute_group); > + for (i = 0; i < GT683R_LED_COUNT; i++) > + led_classdev_unregister(&led->led_devs[i]); > + flush_work(&led->work); > + hid_hw_stop(hdev); > +} > + > +static struct hid_driver gt683r_led_driver = { > + .probe = gt683r_led_probe, > + .remove = gt683r_led_remove, > + .name = "gt683r_led", > + .id_table = gt683r_led_id, > +}; > + > +module_hid_driver(gt683r_led_driver); > + > +MODULE_AUTHOR("Janne Kanniainen"); > +MODULE_DESCRIPTION("MSI GT683R led driver"); > +MODULE_LICENSE("GPL"); > diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h > index 34bb220..3692d37 100644 > --- a/drivers/hid/hid-ids.h > +++ b/drivers/hid/hid-ids.h > @@ -641,7 +641,7 @@ > #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 > > #define USB_VENDOR_ID_MSI 0x1770 > -#define USB_DEVICE_ID_MSI_GX680R_LED_PANEL 0xff00 > +#define USB_DEVICE_ID_MSI_GT683R_LED_PANEL 0xff00 > > #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400 > #define USB_DEVICE_ID_N_S_HARMONY 0xc359 > diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c > index 8e4ddb3..c640e1d 100644 > --- a/drivers/hid/usbhid/hid-quirks.c > +++ b/drivers/hid/usbhid/hid-quirks.c > @@ -73,7 +73,7 @@ static const struct hid_blacklist { > { USB_VENDOR_ID_FORMOSA, USB_DEVICE_ID_FORMOSA_IR_RECEIVER, HID_QUIRK_NO_INIT_REPORTS }, > { USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET }, > { USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET }, > - { USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GX680R_LED_PANEL, 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 }, > { USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS }, ^ permalink raw reply [flat|nested] 81+ messages in thread
[parent not found: <1403543808-8228-1-git-send-email-janne.kanniainen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>]
* Re: [PATCH v10] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-23 17:16 ` [PATCH v10] " Janne Kanniainen @ 2014-06-23 18:23 ` Greg KH [not found] ` <1403543808-8228-1-git-send-email-janne.kanniainen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 1 sibling, 0 replies; 81+ messages in thread From: Greg KH @ 2014-06-23 18:23 UTC (permalink / raw) To: Janne Kanniainen Cc: johan-DgEjT+Ai2ygdnm+yROfE0A, jkosina-AlSwsSmVLrQ, cooloney-Re5JQEeQqe8AvxtiuMwx3w, linux-kernel-u79uwXL29TY76Z2rM5mHXA, linux-leds-u79uwXL29TY76Z2rM5mHXA, linux-usb-u79uwXL29TY76Z2rM5mHXA, linux-input-u79uwXL29TY76Z2rM5mHXA On Mon, Jun 23, 2014 at 08:16:48PM +0300, Janne Kanniainen wrote: > + ret = sysfs_create_group(&led->hdev->dev.kobj, >683r_attribute_group); > + if (ret) { > + hid_err(hdev, "failed to create sysfs attributes\n"); > + goto fail; > + } No, you need to set the attribute group _before_ you call led_classdev_register, as that is where the device will be created in sysfs. Surely the other led drivers already do this? I'm almost afraid to go look... You also have to document your sysfs file in Documentation/ABI/ thanks, greg k-h -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v10] leds: USB: HID: Add support for MSI GT683R led panels @ 2014-06-23 18:23 ` Greg KH 0 siblings, 0 replies; 81+ messages in thread From: Greg KH @ 2014-06-23 18:23 UTC (permalink / raw) To: Janne Kanniainen Cc: johan, jkosina, cooloney, linux-kernel, linux-leds, linux-usb, linux-input On Mon, Jun 23, 2014 at 08:16:48PM +0300, Janne Kanniainen wrote: > + ret = sysfs_create_group(&led->hdev->dev.kobj, >683r_attribute_group); > + if (ret) { > + hid_err(hdev, "failed to create sysfs attributes\n"); > + goto fail; > + } No, you need to set the attribute group _before_ you call led_classdev_register, as that is where the device will be created in sysfs. Surely the other led drivers already do this? I'm almost afraid to go look... You also have to document your sysfs file in Documentation/ABI/ thanks, greg k-h ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v10] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-23 18:23 ` Greg KH (?) @ 2014-06-23 18:24 ` Greg KH 2014-06-23 19:31 ` Johan Hovold -1 siblings, 1 reply; 81+ messages in thread From: Greg KH @ 2014-06-23 18:24 UTC (permalink / raw) To: Janne Kanniainen Cc: johan, jkosina, cooloney, linux-kernel, linux-leds, linux-usb, linux-input On Mon, Jun 23, 2014 at 02:23:24PM -0400, Greg KH wrote: > On Mon, Jun 23, 2014 at 08:16:48PM +0300, Janne Kanniainen wrote: > > + ret = sysfs_create_group(&led->hdev->dev.kobj, >683r_attribute_group); > > + if (ret) { > > + hid_err(hdev, "failed to create sysfs attributes\n"); > > + goto fail; > > + } > > No, you need to set the attribute group _before_ you call > led_classdev_register, as that is where the device will be created in > sysfs. Surely the other led drivers already do this? I'm almost afraid > to go look... Yes, they do it already, set .dev_attr_group and you should be fine. thanks, greg k-h ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v10] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-23 18:24 ` Greg KH @ 2014-06-23 19:31 ` Johan Hovold 2014-06-23 19:40 ` Greg KH 0 siblings, 1 reply; 81+ messages in thread From: Johan Hovold @ 2014-06-23 19:31 UTC (permalink / raw) To: Greg KH Cc: Janne Kanniainen, johan, jkosina, cooloney, linux-kernel, linux-leds, linux-usb, linux-input On Mon, Jun 23, 2014 at 02:24:32PM -0400, Greg KH wrote: > On Mon, Jun 23, 2014 at 02:23:24PM -0400, Greg KH wrote: > > On Mon, Jun 23, 2014 at 08:16:48PM +0300, Janne Kanniainen wrote: > > > + ret = sysfs_create_group(&led->hdev->dev.kobj, >683r_attribute_group); > > > + if (ret) { > > > + hid_err(hdev, "failed to create sysfs attributes\n"); > > > + goto fail; > > > + } > > > > No, you need to set the attribute group _before_ you call > > led_classdev_register, as that is where the device will be created in > > sysfs. Surely the other led drivers already do this? I'm almost afraid > > to go look... > > Yes, they do it already, set .dev_attr_group and you should be fine. But this isn't an attribute of the LEDs but rather of the parent HID device that is being probed (the led_mode is common to all three LEDs and thus belongs in the parent device, right?). Johan ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v10] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-23 19:31 ` Johan Hovold @ 2014-06-23 19:40 ` Greg KH 2014-06-23 19:52 ` Johan Hovold 0 siblings, 1 reply; 81+ messages in thread From: Greg KH @ 2014-06-23 19:40 UTC (permalink / raw) To: Johan Hovold Cc: Janne Kanniainen, jkosina, cooloney, linux-kernel, linux-leds, linux-usb, linux-input On Mon, Jun 23, 2014 at 09:31:34PM +0200, Johan Hovold wrote: > On Mon, Jun 23, 2014 at 02:24:32PM -0400, Greg KH wrote: > > On Mon, Jun 23, 2014 at 02:23:24PM -0400, Greg KH wrote: > > > On Mon, Jun 23, 2014 at 08:16:48PM +0300, Janne Kanniainen wrote: > > > > + ret = sysfs_create_group(&led->hdev->dev.kobj, >683r_attribute_group); > > > > + if (ret) { > > > > + hid_err(hdev, "failed to create sysfs attributes\n"); > > > > + goto fail; > > > > + } > > > > > > No, you need to set the attribute group _before_ you call > > > led_classdev_register, as that is where the device will be created in > > > sysfs. Surely the other led drivers already do this? I'm almost afraid > > > to go look... > > > > Yes, they do it already, set .dev_attr_group and you should be fine. > > But this isn't an attribute of the LEDs but rather of the parent HID > device that is being probed (the led_mode is common to all three LEDs > and thus belongs in the parent device, right?). Then that's even worse :( The sysfs attribute should be on the class device here for the LED, you should not put an attribute on a device you are not the driver for. greg k-h ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v10] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-23 19:40 ` Greg KH @ 2014-06-23 19:52 ` Johan Hovold 2014-06-23 20:24 ` Greg KH 0 siblings, 1 reply; 81+ messages in thread From: Johan Hovold @ 2014-06-23 19:52 UTC (permalink / raw) To: Greg KH Cc: Johan Hovold, Janne Kanniainen, jkosina, cooloney, linux-kernel, linux-leds, linux-usb, linux-input On Mon, Jun 23, 2014 at 03:40:59PM -0400, Greg KH wrote: > On Mon, Jun 23, 2014 at 09:31:34PM +0200, Johan Hovold wrote: > > On Mon, Jun 23, 2014 at 02:24:32PM -0400, Greg KH wrote: > > > On Mon, Jun 23, 2014 at 02:23:24PM -0400, Greg KH wrote: > > > > On Mon, Jun 23, 2014 at 08:16:48PM +0300, Janne Kanniainen wrote: > > > > > + ret = sysfs_create_group(&led->hdev->dev.kobj, >683r_attribute_group); > > > > > + if (ret) { > > > > > + hid_err(hdev, "failed to create sysfs attributes\n"); > > > > > + goto fail; > > > > > + } > > > > > > > > No, you need to set the attribute group _before_ you call > > > > led_classdev_register, as that is where the device will be created in > > > > sysfs. Surely the other led drivers already do this? I'm almost afraid > > > > to go look... > > > > > > Yes, they do it already, set .dev_attr_group and you should be fine. > > > > But this isn't an attribute of the LEDs but rather of the parent HID > > device that is being probed (the led_mode is common to all three LEDs > > and thus belongs in the parent device, right?). > > Then that's even worse :( > > The sysfs attribute should be on the class device here for the LED, you > should not put an attribute on a device you are not the driver for. But this is the driver for the HID device, which then in turn has three individual LEDs. This particular device isn't really an input device (the actual keyboard in this case appears to be connected over PS2), but there are several HID drivers which are primarily input devices with LEDs as sub-devices (e.g. drivers/hid/hid-lg4ff.c). Johan ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v10] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-23 19:52 ` Johan Hovold @ 2014-06-23 20:24 ` Greg KH 2014-06-23 20:44 ` Johan Hovold 0 siblings, 1 reply; 81+ messages in thread From: Greg KH @ 2014-06-23 20:24 UTC (permalink / raw) To: Johan Hovold Cc: Janne Kanniainen, jkosina, cooloney, linux-kernel, linux-leds, linux-usb, linux-input On Mon, Jun 23, 2014 at 09:52:12PM +0200, Johan Hovold wrote: > On Mon, Jun 23, 2014 at 03:40:59PM -0400, Greg KH wrote: > > On Mon, Jun 23, 2014 at 09:31:34PM +0200, Johan Hovold wrote: > > > On Mon, Jun 23, 2014 at 02:24:32PM -0400, Greg KH wrote: > > > > On Mon, Jun 23, 2014 at 02:23:24PM -0400, Greg KH wrote: > > > > > On Mon, Jun 23, 2014 at 08:16:48PM +0300, Janne Kanniainen wrote: > > > > > > + ret = sysfs_create_group(&led->hdev->dev.kobj, >683r_attribute_group); > > > > > > + if (ret) { > > > > > > + hid_err(hdev, "failed to create sysfs attributes\n"); > > > > > > + goto fail; > > > > > > + } > > > > > > > > > > No, you need to set the attribute group _before_ you call > > > > > led_classdev_register, as that is where the device will be created in > > > > > sysfs. Surely the other led drivers already do this? I'm almost afraid > > > > > to go look... > > > > > > > > Yes, they do it already, set .dev_attr_group and you should be fine. > > > > > > But this isn't an attribute of the LEDs but rather of the parent HID > > > device that is being probed (the led_mode is common to all three LEDs > > > and thus belongs in the parent device, right?). > > > > Then that's even worse :( > > > > The sysfs attribute should be on the class device here for the LED, you > > should not put an attribute on a device you are not the driver for. > > But this is the driver for the HID device, which then in turn has three > individual LEDs. This particular device isn't really an input device > (the actual keyboard in this case appears to be connected over PS2), but > there are several HID drivers which are primarily input devices with > LEDs as sub-devices (e.g. drivers/hid/hid-lg4ff.c). I don't know the specifics here, but as you just created a class device, why aren't the attributes on that class device? Shouldn't that be the logical place for it, instead of having them on some "random" other type of device? Userspace will never be notified that the attribute is on that device due to the file being created "later", and tools using libudev and the like will be looking at the LED class device, not the "parent" device for any specific LED stuff. but if this really is the way that all LED devices work, and userspace programs are expecting this, that's seems odd. greg k-h ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v10] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-23 20:24 ` Greg KH @ 2014-06-23 20:44 ` Johan Hovold 2014-06-24 13:10 ` Bjørn Mork 0 siblings, 1 reply; 81+ messages in thread From: Johan Hovold @ 2014-06-23 20:44 UTC (permalink / raw) To: Greg KH Cc: Johan Hovold, Janne Kanniainen, jkosina, cooloney, linux-kernel, linux-leds, linux-usb, linux-input On Mon, Jun 23, 2014 at 04:24:48PM -0400, Greg KH wrote: > On Mon, Jun 23, 2014 at 09:52:12PM +0200, Johan Hovold wrote: > > On Mon, Jun 23, 2014 at 03:40:59PM -0400, Greg KH wrote: > > > On Mon, Jun 23, 2014 at 09:31:34PM +0200, Johan Hovold wrote: > > > > On Mon, Jun 23, 2014 at 02:24:32PM -0400, Greg KH wrote: > > > > > On Mon, Jun 23, 2014 at 02:23:24PM -0400, Greg KH wrote: > > > > > > On Mon, Jun 23, 2014 at 08:16:48PM +0300, Janne Kanniainen wrote: > > > > > > > + ret = sysfs_create_group(&led->hdev->dev.kobj, >683r_attribute_group); > > > > > > > + if (ret) { > > > > > > > + hid_err(hdev, "failed to create sysfs attributes\n"); > > > > > > > + goto fail; > > > > > > > + } > > > > > > > > > > > > No, you need to set the attribute group _before_ you call > > > > > > led_classdev_register, as that is where the device will be created in > > > > > > sysfs. Surely the other led drivers already do this? I'm almost afraid > > > > > > to go look... > > > > > > > > > > Yes, they do it already, set .dev_attr_group and you should be fine. > > > > > > > > But this isn't an attribute of the LEDs but rather of the parent HID > > > > device that is being probed (the led_mode is common to all three LEDs > > > > and thus belongs in the parent device, right?). > > > > > > Then that's even worse :( > > > > > > The sysfs attribute should be on the class device here for the LED, you > > > should not put an attribute on a device you are not the driver for. > > > > But this is the driver for the HID device, which then in turn has three > > individual LEDs. This particular device isn't really an input device > > (the actual keyboard in this case appears to be connected over PS2), but > > there are several HID drivers which are primarily input devices with > > LEDs as sub-devices (e.g. drivers/hid/hid-lg4ff.c). > > I don't know the specifics here, but as you just created a class device, > why aren't the attributes on that class device? Shouldn't that be the > logical place for it, instead of having them on some "random" other type > of device? This is a non-standard attribute of this particular laptop. It has three individual LEDs that can be enabled separately (using standard LED class attributes), but they will all three be in the same "mode" (which here apparently means that they can be fully on, vary with the volume(?!), or pulse synchronously when enabled). If we were to implement this mode attribute as a class attribute, changing the mode of of one LED would also change the mode of the other two devices (LEDs). Therefore I think it has to be an attribute of the parent HID device (that the driver is for). > Userspace will never be notified that the attribute is on > that device due to the file being created "later", and tools using > libudev and the like will be looking at the LED class device, not the > "parent" device for any specific LED stuff. Yeah, that seems to be the case. I doubt anyone will care much about this particular custom attribute, but sure, setting the led_mode of the HID device from an udev rule could be problematic. > but if this really is the way that all LED devices work, and userspace > programs are expecting this, that's seems odd. Johan ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v10] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-23 20:44 ` Johan Hovold @ 2014-06-24 13:10 ` Bjørn Mork 0 siblings, 0 replies; 81+ messages in thread From: Bjørn Mork @ 2014-06-24 13:10 UTC (permalink / raw) To: Johan Hovold Cc: Greg KH, Janne Kanniainen, jkosina, cooloney, linux-kernel, linux-leds, linux-usb, linux-input Johan Hovold <johan@kernel.org> writes: > This is a non-standard attribute of this particular laptop. It has three > individual LEDs that can be enabled separately (using standard LED class > attributes), but they will all three be in the same "mode" (which here > apparently means that they can be fully on, vary with the volume(?!), or > pulse synchronously when enabled). > > If we were to implement this mode attribute as a class attribute, > changing the mode of of one LED would also change the mode of the other > two devices (LEDs). Document this behaviour and it becomes a feature. Bjørn -- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v10] leds: USB: HID: Add support for MSI GT683R led panels @ 2014-06-24 13:10 ` Bjørn Mork 0 siblings, 0 replies; 81+ messages in thread From: Bjørn Mork @ 2014-06-24 13:10 UTC (permalink / raw) To: Johan Hovold Cc: Greg KH, Janne Kanniainen, jkosina, cooloney, linux-kernel, linux-leds, linux-usb, linux-input Johan Hovold <johan@kernel.org> writes: > This is a non-standard attribute of this particular laptop. It has three > individual LEDs that can be enabled separately (using standard LED class > attributes), but they will all three be in the same "mode" (which here > apparently means that they can be fully on, vary with the volume(?!), or > pulse synchronously when enabled). > > If we were to implement this mode attribute as a class attribute, > changing the mode of of one LED would also change the mode of the other > two devices (LEDs). Document this behaviour and it becomes a feature. Bjørn ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v10] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-24 13:10 ` Bjørn Mork (?) @ 2014-06-24 14:50 ` Johan Hovold 2014-06-24 19:38 ` [PATCH 1/2] HID: leds: fix race condition in MSI GT683R driver Janne Kanniainen -1 siblings, 1 reply; 81+ messages in thread From: Johan Hovold @ 2014-06-24 14:50 UTC (permalink / raw) To: Bjørn Mork Cc: Johan Hovold, Greg KH, Janne Kanniainen, jkosina, cooloney, linux-kernel, linux-leds, linux-usb, linux-input On Tue, Jun 24, 2014 at 03:10:43PM +0200, Bjørn Mork wrote: > Johan Hovold <johan@kernel.org> writes: > > > This is a non-standard attribute of this particular laptop. It has three > > individual LEDs that can be enabled separately (using standard LED class > > attributes), but they will all three be in the same "mode" (which here > > apparently means that they can be fully on, vary with the volume(?!), or > > pulse synchronously when enabled). > > > > If we were to implement this mode attribute as a class attribute, > > changing the mode of of one LED would also change the mode of the other > > two devices (LEDs). > > Document this behaviour and it becomes a feature. Yeah, you're right. That is probably the best way to handle this. Janne, could you send two separate patches on top of v9 that fixes the use-before-initialisation (reported by Oliver) and moves the led_mode attribute from the parent HID device to the led-class devices (thereby fixing the race reported by Greg)? As the "led_"-prefix will then be redundant, you should probably rename the attribute as "msi_mode" or similar (just "mode" might be too generic). Remember to update the ABI documentation as well, including mentioning the fact that changing the mode of one LED will update the mode of its two sibling devices as well (as suggested by Bjørn). Thanks, Johan ^ permalink raw reply [flat|nested] 81+ messages in thread
* [PATCH 1/2] HID: leds: fix race condition in MSI GT683R driver 2014-06-24 14:50 ` Johan Hovold @ 2014-06-24 19:38 ` Janne Kanniainen 2014-06-24 19:38 ` [PATCH 2/2] HID: leds: move led_mode attribute to led-class devices " Janne Kanniainen 0 siblings, 1 reply; 81+ messages in thread From: Janne Kanniainen @ 2014-06-24 19:38 UTC (permalink / raw) To: johan Cc: greg, bjorn, jkosina, cooloney, linux-kernel, linux-leds, linux-usb, linux-input, Janne Kanniainen This will fix race condition noticed by Oliver Neukum. Sysfs files are created before mutex and work are initialized. Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> --- drivers/hid/hid-gt683r.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c index 077f7a1..073bd80 100644 --- a/drivers/hid/hid-gt683r.c +++ b/drivers/hid/hid-gt683r.c @@ -227,6 +227,9 @@ static int gt683r_led_probe(struct hid_device *hdev, if (!led) return -ENOMEM; + mutex_init(&led->lock); + INIT_WORK(&led->work, gt683r_led_work); + led->mode = GT683R_LED_NORMAL; led->hdev = hdev; hid_set_drvdata(hdev, led); @@ -271,9 +274,6 @@ static int gt683r_led_probe(struct hid_device *hdev, goto fail; } - mutex_init(&led->lock); - INIT_WORK(&led->work, gt683r_led_work); - return 0; fail: -- 1.9.2 ^ permalink raw reply related [flat|nested] 81+ messages in thread
* [PATCH 2/2] HID: leds: move led_mode attribute to led-class devices in MSI GT683R driver 2014-06-24 19:38 ` [PATCH 1/2] HID: leds: fix race condition in MSI GT683R driver Janne Kanniainen @ 2014-06-24 19:38 ` Janne Kanniainen 2014-06-24 19:56 ` Greg KH 0 siblings, 1 reply; 81+ messages in thread From: Janne Kanniainen @ 2014-06-24 19:38 UTC (permalink / raw) To: johan Cc: greg, bjorn, jkosina, cooloney, linux-kernel, linux-leds, linux-usb, linux-input, Janne Kanniainen Move led_mode attribute from HID device to led-class devices and rename it msi_mode. Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> --- .../ABI/testing/sysfs-class-hid-driver-gt683r | 6 ++- drivers/hid/hid-gt683r.c | 50 +++++++++++++++++----- 2 files changed, 43 insertions(+), 13 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r index 317e9d5..c97970a 100644 --- a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r +++ b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r @@ -1,9 +1,11 @@ -What: /sys/class/hidraw/<hidraw>/device/leds_mode +What: /sys/class/leds/<led>/msi_mode Date: Jun 2014 KernelVersion: 3.17 Contact: Janne Kanniainen <janne.kanniainen@gmail.com> Description: - Set the mode of LEDs + Set the mode of LEDs. You should notice that changing the mode + of one LED will update the mode of its two sibling devices as + well 0 - normal 1 - audio diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c index 073bd80..1c942eb 100644 --- a/drivers/hid/hid-gt683r.c +++ b/drivers/hid/hid-gt683r.c @@ -58,6 +58,7 @@ struct gt683r_led { struct work_struct work; enum led_brightness brightnesses[GT683R_LED_COUNT]; enum gt683r_led_mode mode; + const struct attribute_group *dev_attr_group[GT683R_LED_COUNT]; }; static const struct hid_device_id gt683r_led_id[] = { @@ -84,12 +85,13 @@ static void gt683r_brightness_set(struct led_classdev *led_cdev, } } -static ssize_t leds_mode_show(struct device *dev, +static ssize_t msi_mode_show(struct device *led_dev, struct device_attribute *attr, char *buf) { u8 sysfs_mode; - struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct hid_device *hdev = container_of(led_dev->parent, + struct hid_device, dev); struct gt683r_led *led = hid_get_drvdata(hdev); if (led->mode == GT683R_LED_NORMAL) @@ -102,15 +104,15 @@ static ssize_t leds_mode_show(struct device *dev, return scnprintf(buf, PAGE_SIZE, "%u\n", sysfs_mode); } -static ssize_t leds_mode_store(struct device *dev, +static ssize_t msi_mode_store(struct device *led_dev, struct device_attribute *attr, const char *buf, size_t count) { u8 sysfs_mode; - struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct hid_device *hdev = container_of(led_dev->parent, + struct hid_device, dev); struct gt683r_led *led = hid_get_drvdata(hdev); - if (kstrtou8(buf, 10, &sysfs_mode) || sysfs_mode > 2) return -EINVAL; @@ -212,7 +214,16 @@ fail: mutex_unlock(&led->lock); } -static DEVICE_ATTR_RW(leds_mode); +static DEVICE_ATTR_RW(msi_mode); + +static struct attribute *gt683r_attributes[] = { + &dev_attr_msi_mode.attr, + NULL +}; + +static const struct attribute_group gt683r_group = { + .attrs = gt683r_attributes +}; static int gt683r_led_probe(struct hid_device *hdev, const struct hid_device_id *id) @@ -261,6 +272,7 @@ static int gt683r_led_probe(struct hid_device *hdev, led->led_devs[i].name = name; led->led_devs[i].max_brightness = 1; led->led_devs[i].brightness_set = gt683r_brightness_set; + ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); if (ret) { hid_err(hdev, "could not register led device\n"); @@ -268,17 +280,29 @@ static int gt683r_led_probe(struct hid_device *hdev, } } - ret = device_create_file(&led->hdev->dev, &dev_attr_leds_mode); - if (ret) { - hid_err(hdev, "could not make mode attribute file\n"); - goto fail; + for (i = 0; i < GT683R_LED_COUNT; i++) { + led->dev_attr_group[i] = >683r_group; + + ret = sysfs_create_group(&led->led_devs[i].dev->kobj, + led->dev_attr_group[i]); + if (ret) { + hid_err(hdev, "could not create attribute file\n"); + goto sysfs_create_fail; + } } return 0; +sysfs_create_fail: + for (i = i - 1; i >= 0; i--) + sysfs_remove_group(&led->led_devs[i].dev->kobj, + led->dev_attr_group[i]); + + i = GT683R_LED_COUNT; fail: for (i = i - 1; i >= 0; i--) led_classdev_unregister(&led->led_devs[i]); + hid_hw_stop(hdev); return ret; } @@ -288,9 +312,13 @@ static void gt683r_led_remove(struct hid_device *hdev) int i; struct gt683r_led *led = hid_get_drvdata(hdev); - device_remove_file(&hdev->dev, &dev_attr_leds_mode); + for (i = 0; i < GT683R_LED_COUNT; i++) + sysfs_remove_group(&led->led_devs[i].dev->kobj, + led->dev_attr_group[i]); + for (i = 0; i < GT683R_LED_COUNT; i++) led_classdev_unregister(&led->led_devs[i]); + flush_work(&led->work); hid_hw_stop(hdev); } -- 1.9.2 ^ permalink raw reply related [flat|nested] 81+ messages in thread
* Re: [PATCH 2/2] HID: leds: move led_mode attribute to led-class devices in MSI GT683R driver 2014-06-24 19:38 ` [PATCH 2/2] HID: leds: move led_mode attribute to led-class devices " Janne Kanniainen @ 2014-06-24 19:56 ` Greg KH 2014-06-25 11:55 ` Johan Hovold 0 siblings, 1 reply; 81+ messages in thread From: Greg KH @ 2014-06-24 19:56 UTC (permalink / raw) To: Janne Kanniainen Cc: johan, bjorn, jkosina, cooloney, linux-kernel, linux-leds, linux-usb, linux-input On Tue, Jun 24, 2014 at 10:38:38PM +0300, Janne Kanniainen wrote: > Move led_mode attribute from HID device to led-class devices and rename it > msi_mode. > > Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> > --- > .../ABI/testing/sysfs-class-hid-driver-gt683r | 6 ++- > drivers/hid/hid-gt683r.c | 50 +++++++++++++++++----- > 2 files changed, 43 insertions(+), 13 deletions(-) > > diff --git a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > index 317e9d5..c97970a 100644 > --- a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > +++ b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > @@ -1,9 +1,11 @@ > -What: /sys/class/hidraw/<hidraw>/device/leds_mode > +What: /sys/class/leds/<led>/msi_mode > Date: Jun 2014 > KernelVersion: 3.17 > Contact: Janne Kanniainen <janne.kanniainen@gmail.com> > Description: > - Set the mode of LEDs > + Set the mode of LEDs. You should notice that changing the mode > + of one LED will update the mode of its two sibling devices as > + well > > 0 - normal > 1 - audio > diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c > index 073bd80..1c942eb 100644 > --- a/drivers/hid/hid-gt683r.c > +++ b/drivers/hid/hid-gt683r.c > @@ -58,6 +58,7 @@ struct gt683r_led { > struct work_struct work; > enum led_brightness brightnesses[GT683R_LED_COUNT]; > enum gt683r_led_mode mode; > + const struct attribute_group *dev_attr_group[GT683R_LED_COUNT]; > }; > > static const struct hid_device_id gt683r_led_id[] = { > @@ -84,12 +85,13 @@ static void gt683r_brightness_set(struct led_classdev *led_cdev, > } > } > > -static ssize_t leds_mode_show(struct device *dev, > +static ssize_t msi_mode_show(struct device *led_dev, > struct device_attribute *attr, > char *buf) > { > u8 sysfs_mode; > - struct hid_device *hdev = container_of(dev, struct hid_device, dev); > + struct hid_device *hdev = container_of(led_dev->parent, > + struct hid_device, dev); > struct gt683r_led *led = hid_get_drvdata(hdev); > > if (led->mode == GT683R_LED_NORMAL) > @@ -102,15 +104,15 @@ static ssize_t leds_mode_show(struct device *dev, > return scnprintf(buf, PAGE_SIZE, "%u\n", sysfs_mode); > } > > -static ssize_t leds_mode_store(struct device *dev, > +static ssize_t msi_mode_store(struct device *led_dev, > struct device_attribute *attr, > const char *buf, size_t count) > { > u8 sysfs_mode; > - struct hid_device *hdev = container_of(dev, struct hid_device, dev); > + struct hid_device *hdev = container_of(led_dev->parent, > + struct hid_device, dev); > struct gt683r_led *led = hid_get_drvdata(hdev); > > - > if (kstrtou8(buf, 10, &sysfs_mode) || sysfs_mode > 2) > return -EINVAL; > > @@ -212,7 +214,16 @@ fail: > mutex_unlock(&led->lock); > } > > -static DEVICE_ATTR_RW(leds_mode); > +static DEVICE_ATTR_RW(msi_mode); > + > +static struct attribute *gt683r_attributes[] = { > + &dev_attr_msi_mode.attr, > + NULL > +}; > + > +static const struct attribute_group gt683r_group = { > + .attrs = gt683r_attributes > +}; > > static int gt683r_led_probe(struct hid_device *hdev, > const struct hid_device_id *id) > @@ -261,6 +272,7 @@ static int gt683r_led_probe(struct hid_device *hdev, > led->led_devs[i].name = name; > led->led_devs[i].max_brightness = 1; > led->led_devs[i].brightness_set = gt683r_brightness_set; > + > ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); > if (ret) { > hid_err(hdev, "could not register led device\n"); > @@ -268,17 +280,29 @@ static int gt683r_led_probe(struct hid_device *hdev, > } > } > > - ret = device_create_file(&led->hdev->dev, &dev_attr_leds_mode); > - if (ret) { > - hid_err(hdev, "could not make mode attribute file\n"); > - goto fail; > + for (i = 0; i < GT683R_LED_COUNT; i++) { > + led->dev_attr_group[i] = >683r_group; > + > + ret = sysfs_create_group(&led->led_devs[i].dev->kobj, > + led->dev_attr_group[i]); why not use sysfs_create_groups()? And why are you doing it this way, the led device should have the attribute group and it should be created automatically by the driver core, no driver should need to create it like you are doing so here. thanks, greg k-h ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH 2/2] HID: leds: move led_mode attribute to led-class devices in MSI GT683R driver 2014-06-24 19:56 ` Greg KH @ 2014-06-25 11:55 ` Johan Hovold 2014-06-25 15:59 ` [PATCH 2/2 v2] HID: leds: Use attribute-groups " Janne Kanniainen 0 siblings, 1 reply; 81+ messages in thread From: Johan Hovold @ 2014-06-25 11:55 UTC (permalink / raw) To: Greg KH Cc: Janne Kanniainen, johan, bjorn, jkosina, cooloney, linux-kernel, linux-leds, linux-usb, linux-input On Tue, Jun 24, 2014 at 03:56:51PM -0400, Greg KH wrote: > On Tue, Jun 24, 2014 at 10:38:38PM +0300, Janne Kanniainen wrote: > > static int gt683r_led_probe(struct hid_device *hdev, > > const struct hid_device_id *id) > > @@ -261,6 +272,7 @@ static int gt683r_led_probe(struct hid_device *hdev, > > led->led_devs[i].name = name; > > led->led_devs[i].max_brightness = 1; > > led->led_devs[i].brightness_set = gt683r_brightness_set; > > + > > ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); > > if (ret) { > > hid_err(hdev, "could not register led device\n"); > > @@ -268,17 +280,29 @@ static int gt683r_led_probe(struct hid_device *hdev, > > } > > } > > > > - ret = device_create_file(&led->hdev->dev, &dev_attr_leds_mode); > > - if (ret) { > > - hid_err(hdev, "could not make mode attribute file\n"); > > - goto fail; > > + for (i = 0; i < GT683R_LED_COUNT; i++) { > > + led->dev_attr_group[i] = >683r_group; > > + > > + ret = sysfs_create_group(&led->led_devs[i].dev->kobj, > > + led->dev_attr_group[i]); > > why not use sysfs_create_groups()? > > And why are you doing it this way, the led device should have the > attribute group and it should be created automatically by the driver > core, no driver should need to create it like you are doing so here. Turns out it was easier said than done when I asked Janne to move the attribute. And all led drivers with custom attributes currently suffer from this race. Janne, you'll need to apply patch below and then set the groups field of the led_devs before registering them. You can use the ATTRIBUTE_GROUPS macro in the following way: static struct attribute *gt683r_led_attrs[] = { &dev_attr_msi_mode.attr, NULL, }; ATTRIBUTE_GROUPS(gt683r_led); and then set .groups to gt683r_led_groups. I have started fixing some of the other led drivers and I'll try to submit a series (including the below patch) later today. Thanks, Johan >From 226f1de5e094f2ec99f45d486652505ef915af73 Mon Sep 17 00:00:00 2001 From: Johan Hovold <johan@kernel.org> Date: Wed, 25 Jun 2014 12:33:18 +0200 Subject: [PATCH] leds: add led-class attribute-group support Allow led-class devices to be created with optional attribute groups. This is needed in order to allow led drivers to create custom device attributes in a race-free manner. Signed-off-by: Johan Hovold <johan@kernel.org> --- drivers/leds/led-class.c | 5 +++-- include/linux/leds.h | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index f37d63cf726b..aa29198fca3e 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -210,8 +210,9 @@ static const struct dev_pm_ops leds_class_dev_pm_ops = { */ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev) { - led_cdev->dev = device_create(leds_class, parent, 0, led_cdev, - "%s", led_cdev->name); + led_cdev->dev = device_create_with_groups(leds_class, parent, 0, + led_cdev, led_cdev->groups, + "%s", led_cdev->name); if (IS_ERR(led_cdev->dev)) return PTR_ERR(led_cdev->dev); diff --git a/include/linux/leds.h b/include/linux/leds.h index 0287ab296689..e43686472197 100644 --- a/include/linux/leds.h +++ b/include/linux/leds.h @@ -63,6 +63,8 @@ struct led_classdev { unsigned long *delay_off); struct device *dev; + const struct attribute_group **groups; + struct list_head node; /* LED Device list */ const char *default_trigger; /* Trigger to use */ -- 1.8.5.5 ^ permalink raw reply related [flat|nested] 81+ messages in thread
* [PATCH 2/2 v2] HID: leds: Use attribute-groups in MSI GT683R driver 2014-06-25 11:55 ` Johan Hovold @ 2014-06-25 15:59 ` Janne Kanniainen 2014-06-25 17:41 ` Johan Hovold 0 siblings, 1 reply; 81+ messages in thread From: Janne Kanniainen @ 2014-06-25 15:59 UTC (permalink / raw) To: johan Cc: greg, bjorn, jkosina, cooloney, linux-kernel, linux-leds, linux-usb, linux-input, Janne Kanniainen Use attribute-groups to fix race condition. Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> --- .../ABI/testing/sysfs-class-hid-driver-gt683r | 6 +++-- drivers/hid/hid-gt683r.c | 31 +++++++++++++--------- 2 files changed, 22 insertions(+), 15 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r index 317e9d5..c97970a 100644 --- a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r +++ b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r @@ -1,9 +1,11 @@ -What: /sys/class/hidraw/<hidraw>/device/leds_mode +What: /sys/class/leds/<led>/msi_mode Date: Jun 2014 KernelVersion: 3.17 Contact: Janne Kanniainen <janne.kanniainen@gmail.com> Description: - Set the mode of LEDs + Set the mode of LEDs. You should notice that changing the mode + of one LED will update the mode of its two sibling devices as + well 0 - normal 1 - audio diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c index 073bd80..aba6636 100644 --- a/drivers/hid/hid-gt683r.c +++ b/drivers/hid/hid-gt683r.c @@ -84,12 +84,13 @@ static void gt683r_brightness_set(struct led_classdev *led_cdev, } } -static ssize_t leds_mode_show(struct device *dev, +static ssize_t msi_mode_show(struct device *led_dev, struct device_attribute *attr, char *buf) { u8 sysfs_mode; - struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct hid_device *hdev = container_of(led_dev->parent, + struct hid_device, dev); struct gt683r_led *led = hid_get_drvdata(hdev); if (led->mode == GT683R_LED_NORMAL) @@ -102,15 +103,15 @@ static ssize_t leds_mode_show(struct device *dev, return scnprintf(buf, PAGE_SIZE, "%u\n", sysfs_mode); } -static ssize_t leds_mode_store(struct device *dev, +static ssize_t msi_mode_store(struct device *led_dev, struct device_attribute *attr, const char *buf, size_t count) { u8 sysfs_mode; - struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct hid_device *hdev = container_of(led_dev->parent, + struct hid_device, dev); struct gt683r_led *led = hid_get_drvdata(hdev); - if (kstrtou8(buf, 10, &sysfs_mode) || sysfs_mode > 2) return -EINVAL; @@ -212,7 +213,14 @@ fail: mutex_unlock(&led->lock); } -static DEVICE_ATTR_RW(leds_mode); +static DEVICE_ATTR_RW(msi_mode); + +static struct attribute *gt683r_led_attrs[] = { + &dev_attr_msi_mode.attr, + NULL +}; + +ATTRIBUTE_GROUPS(gt683r_led); static int gt683r_led_probe(struct hid_device *hdev, const struct hid_device_id *id) @@ -261,6 +269,8 @@ static int gt683r_led_probe(struct hid_device *hdev, led->led_devs[i].name = name; led->led_devs[i].max_brightness = 1; led->led_devs[i].brightness_set = gt683r_brightness_set; + led->led_devs[i].groups = gt683r_led_groups; + ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); if (ret) { hid_err(hdev, "could not register led device\n"); @@ -268,17 +278,12 @@ static int gt683r_led_probe(struct hid_device *hdev, } } - ret = device_create_file(&led->hdev->dev, &dev_attr_leds_mode); - if (ret) { - hid_err(hdev, "could not make mode attribute file\n"); - goto fail; - } - return 0; fail: for (i = i - 1; i >= 0; i--) led_classdev_unregister(&led->led_devs[i]); + hid_hw_stop(hdev); return ret; } @@ -288,9 +293,9 @@ static void gt683r_led_remove(struct hid_device *hdev) int i; struct gt683r_led *led = hid_get_drvdata(hdev); - device_remove_file(&hdev->dev, &dev_attr_leds_mode); for (i = 0; i < GT683R_LED_COUNT; i++) led_classdev_unregister(&led->led_devs[i]); + flush_work(&led->work); hid_hw_stop(hdev); } -- 1.9.2 ^ permalink raw reply related [flat|nested] 81+ messages in thread
* Re: [PATCH 2/2 v2] HID: leds: Use attribute-groups in MSI GT683R driver 2014-06-25 15:59 ` [PATCH 2/2 v2] HID: leds: Use attribute-groups " Janne Kanniainen @ 2014-06-25 17:41 ` Johan Hovold 2014-06-25 18:13 ` [PATCH 2/2 v3] HID: leds: move led_mode attribute to led-class devices " Janne Kanniainen 2014-06-25 19:09 ` [PATCH 2/2 v2] HID: leds: Use attribute-groups in MSI GT683R driver Jiri Kosina 0 siblings, 2 replies; 81+ messages in thread From: Johan Hovold @ 2014-06-25 17:41 UTC (permalink / raw) To: Janne Kanniainen, Jiri Kosina Cc: johan, greg, bjorn, cooloney, linux-kernel, linux-leds, linux-usb, linux-input On Wed, Jun 25, 2014 at 06:59:26PM +0300, Janne Kanniainen wrote: > Use attribute-groups to fix race condition. The primary thing you're doing here is moving and renaming the attribute to the led class devices, so you need to mention that (and update the patch subject). But you can mention the race as well. > Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> > --- > .../ABI/testing/sysfs-class-hid-driver-gt683r | 6 +++-- > drivers/hid/hid-gt683r.c | 31 +++++++++++++--------- > 2 files changed, 22 insertions(+), 15 deletions(-) > > diff --git a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > index 317e9d5..c97970a 100644 > --- a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > +++ b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r I think you need to rename this file as well to sysfs-class-leds-driver-gt683r (use git mv). > @@ -1,9 +1,11 @@ > -What: /sys/class/hidraw/<hidraw>/device/leds_mode > +What: /sys/class/leds/<led>/msi_mode > Date: Jun 2014 > KernelVersion: 3.17 > Contact: Janne Kanniainen <janne.kanniainen@gmail.com> > Description: > - Set the mode of LEDs > + Set the mode of LEDs. You should notice that changing the mode > + of one LED will update the mode of its two sibling devices as > + well Missing period ('.'). > > 0 - normal > 1 - audio > diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c > index 073bd80..aba6636 100644 > --- a/drivers/hid/hid-gt683r.c > +++ b/drivers/hid/hid-gt683r.c > @@ -84,12 +84,13 @@ static void gt683r_brightness_set(struct led_classdev *led_cdev, > } > } > > -static ssize_t leds_mode_show(struct device *dev, > +static ssize_t msi_mode_show(struct device *led_dev, No need to rename dev. > struct device_attribute *attr, > char *buf) > { > u8 sysfs_mode; > - struct hid_device *hdev = container_of(dev, struct hid_device, dev); > + struct hid_device *hdev = container_of(led_dev->parent, > + struct hid_device, dev); > struct gt683r_led *led = hid_get_drvdata(hdev); > > if (led->mode == GT683R_LED_NORMAL) > @@ -102,15 +103,15 @@ static ssize_t leds_mode_show(struct device *dev, > return scnprintf(buf, PAGE_SIZE, "%u\n", sysfs_mode); > } > > -static ssize_t leds_mode_store(struct device *dev, > +static ssize_t msi_mode_store(struct device *led_dev, Same here. > struct device_attribute *attr, > const char *buf, size_t count) > { > u8 sysfs_mode; > - struct hid_device *hdev = container_of(dev, struct hid_device, dev); > + struct hid_device *hdev = container_of(led_dev->parent, > + struct hid_device, dev); > struct gt683r_led *led = hid_get_drvdata(hdev); > > - You should not include random whitespace fixes in your patches (there are two more below). If needed you can do that in a separate patch. > if (kstrtou8(buf, 10, &sysfs_mode) || sysfs_mode > 2) > return -EINVAL; > > @@ -212,7 +213,14 @@ fail: > mutex_unlock(&led->lock); > } > > -static DEVICE_ATTR_RW(leds_mode); > +static DEVICE_ATTR_RW(msi_mode); > + > +static struct attribute *gt683r_led_attrs[] = { > + &dev_attr_msi_mode.attr, > + NULL > +}; > + > +ATTRIBUTE_GROUPS(gt683r_led); > > static int gt683r_led_probe(struct hid_device *hdev, > const struct hid_device_id *id) > @@ -261,6 +269,8 @@ static int gt683r_led_probe(struct hid_device *hdev, > led->led_devs[i].name = name; > led->led_devs[i].max_brightness = 1; > led->led_devs[i].brightness_set = gt683r_brightness_set; > + led->led_devs[i].groups = gt683r_led_groups; > + Great. This fixes the race with userspace. Did you see the attribute-race series I posted? Not sure how best to handle the dependency, as those patches should probably go in through the LEDs tree, while the first patch in that series (adding the groups field) is a dependency for this patch. Jiri, how would this best be solved? Thanks, Johan > ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); > if (ret) { > hid_err(hdev, "could not register led device\n"); > @@ -268,17 +278,12 @@ static int gt683r_led_probe(struct hid_device *hdev, > } > } > > - ret = device_create_file(&led->hdev->dev, &dev_attr_leds_mode); > - if (ret) { > - hid_err(hdev, "could not make mode attribute file\n"); > - goto fail; > - } > - > return 0; > > fail: > for (i = i - 1; i >= 0; i--) > led_classdev_unregister(&led->led_devs[i]); > + > hid_hw_stop(hdev); > return ret; > } > @@ -288,9 +293,9 @@ static void gt683r_led_remove(struct hid_device *hdev) > int i; > struct gt683r_led *led = hid_get_drvdata(hdev); > > - device_remove_file(&hdev->dev, &dev_attr_leds_mode); > for (i = 0; i < GT683R_LED_COUNT; i++) > led_classdev_unregister(&led->led_devs[i]); > + > flush_work(&led->work); > hid_hw_stop(hdev); > } ^ permalink raw reply [flat|nested] 81+ messages in thread
* [PATCH 2/2 v3] HID: leds: move led_mode attribute to led-class devices in MSI GT683R driver 2014-06-25 17:41 ` Johan Hovold @ 2014-06-25 18:13 ` Janne Kanniainen 2014-06-30 10:39 ` Johan Hovold 2014-06-25 19:09 ` [PATCH 2/2 v2] HID: leds: Use attribute-groups in MSI GT683R driver Jiri Kosina 1 sibling, 1 reply; 81+ messages in thread From: Janne Kanniainen @ 2014-06-25 18:13 UTC (permalink / raw) To: johan, jkosina Cc: greg, bjorn, cooloney, linux-kernel, linux-leds, linux-usb, linux-input, Janne Kanniainen Move led_mode attribute from HID device to led-class devices and rename it msi_mode. This will also fix race condition by using attribute-groups. Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> --- Changes in v3: - Style fixes - Rename sysfs-class-hid-driver-gt683r to sysfs-class-leds-driver-gt683r .../ABI/testing/sysfs-class-hid-driver-gt683r | 14 ----------- .../ABI/testing/sysfs-class-leds-driver-gt683r | 16 +++++++++++++ drivers/hid/hid-gt683r.c | 28 ++++++++++++---------- 3 files changed, 32 insertions(+), 26 deletions(-) delete mode 100644 Documentation/ABI/testing/sysfs-class-hid-driver-gt683r create mode 100644 Documentation/ABI/testing/sysfs-class-leds-driver-gt683r diff --git a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r deleted file mode 100644 index 317e9d5..0000000 --- a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r +++ /dev/null @@ -1,14 +0,0 @@ -What: /sys/class/hidraw/<hidraw>/device/leds_mode -Date: Jun 2014 -KernelVersion: 3.17 -Contact: Janne Kanniainen <janne.kanniainen@gmail.com> -Description: - Set the mode of LEDs - - 0 - normal - 1 - audio - 2 - breathing - - Normal: LEDs are fully on when enabled - Audio: LEDs brightness depends on sound level - Breathing: LEDs brightness varies at human breathing rate \ No newline at end of file diff --git a/Documentation/ABI/testing/sysfs-class-leds-driver-gt683r b/Documentation/ABI/testing/sysfs-class-leds-driver-gt683r new file mode 100644 index 0000000..29769fb --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-leds-driver-gt683r @@ -0,0 +1,16 @@ +What: /sys/class/leds/<led>/msi_mode +Date: Jun 2014 +KernelVersion: 3.17 +Contact: Janne Kanniainen <janne.kanniainen@gmail.com> +Description: + Set the mode of LEDs. You should notice that changing the mode + of one LED will update the mode of its two sibling devices as + well. + + 0 - normal + 1 - audio + 2 - breathing + + Normal: LEDs are fully on when enabled + Audio: LEDs brightness depends on sound level + Breathing: LEDs brightness varies at human breathing rate \ No newline at end of file diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c index 073bd80..ba27ee1 100644 --- a/drivers/hid/hid-gt683r.c +++ b/drivers/hid/hid-gt683r.c @@ -84,12 +84,13 @@ static void gt683r_brightness_set(struct led_classdev *led_cdev, } } -static ssize_t leds_mode_show(struct device *dev, +static ssize_t msi_mode_show(struct device *dev, struct device_attribute *attr, char *buf) { u8 sysfs_mode; - struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct hid_device *hdev = container_of(dev->parent, + struct hid_device, dev); struct gt683r_led *led = hid_get_drvdata(hdev); if (led->mode == GT683R_LED_NORMAL) @@ -102,12 +103,13 @@ static ssize_t leds_mode_show(struct device *dev, return scnprintf(buf, PAGE_SIZE, "%u\n", sysfs_mode); } -static ssize_t leds_mode_store(struct device *dev, +static ssize_t msi_mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { u8 sysfs_mode; - struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct hid_device *hdev = container_of(dev->parent, + struct hid_device, dev); struct gt683r_led *led = hid_get_drvdata(hdev); @@ -212,7 +214,14 @@ fail: mutex_unlock(&led->lock); } -static DEVICE_ATTR_RW(leds_mode); +static DEVICE_ATTR_RW(msi_mode); + +static struct attribute *gt683r_led_attrs[] = { + &dev_attr_msi_mode.attr, + NULL +}; + +ATTRIBUTE_GROUPS(gt683r_led); static int gt683r_led_probe(struct hid_device *hdev, const struct hid_device_id *id) @@ -261,6 +270,8 @@ static int gt683r_led_probe(struct hid_device *hdev, led->led_devs[i].name = name; led->led_devs[i].max_brightness = 1; led->led_devs[i].brightness_set = gt683r_brightness_set; + led->led_devs[i].groups = gt683r_led_groups; + ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); if (ret) { hid_err(hdev, "could not register led device\n"); @@ -268,12 +279,6 @@ static int gt683r_led_probe(struct hid_device *hdev, } } - ret = device_create_file(&led->hdev->dev, &dev_attr_leds_mode); - if (ret) { - hid_err(hdev, "could not make mode attribute file\n"); - goto fail; - } - return 0; fail: @@ -288,7 +293,6 @@ static void gt683r_led_remove(struct hid_device *hdev) int i; struct gt683r_led *led = hid_get_drvdata(hdev); - device_remove_file(&hdev->dev, &dev_attr_leds_mode); for (i = 0; i < GT683R_LED_COUNT; i++) led_classdev_unregister(&led->led_devs[i]); flush_work(&led->work); -- 1.9.2 ^ permalink raw reply related [flat|nested] 81+ messages in thread
* Re: [PATCH 2/2 v3] HID: leds: move led_mode attribute to led-class devices in MSI GT683R driver 2014-06-25 18:13 ` [PATCH 2/2 v3] HID: leds: move led_mode attribute to led-class devices " Janne Kanniainen @ 2014-06-30 10:39 ` Johan Hovold 2014-07-01 17:50 ` [PATCH 2/2 v4] " Janne Kanniainen 0 siblings, 1 reply; 81+ messages in thread From: Johan Hovold @ 2014-06-30 10:39 UTC (permalink / raw) To: Janne Kanniainen Cc: johan, jkosina, greg, bjorn, cooloney, linux-kernel, linux-leds, linux-usb, linux-input On Wed, Jun 25, 2014 at 09:13:09PM +0300, Janne Kanniainen wrote: > Move led_mode attribute from HID device to led-class devices and rename it > msi_mode. This will also fix race condition by using attribute-groups. > > Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> > --- > > Changes in v3: > - Style fixes > - Rename sysfs-class-hid-driver-gt683r to sysfs-class-leds-driver-gt683r > > .../ABI/testing/sysfs-class-hid-driver-gt683r | 14 ----------- > .../ABI/testing/sysfs-class-leds-driver-gt683r | 16 +++++++++++++ > drivers/hid/hid-gt683r.c | 28 ++++++++++++---------- > 3 files changed, 32 insertions(+), 26 deletions(-) > delete mode 100644 Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > create mode 100644 Documentation/ABI/testing/sysfs-class-leds-driver-gt683r > > diff --git a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > deleted file mode 100644 > index 317e9d5..0000000 > --- a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > +++ /dev/null > @@ -1,14 +0,0 @@ > -What: /sys/class/hidraw/<hidraw>/device/leds_mode > -Date: Jun 2014 > -KernelVersion: 3.17 > -Contact: Janne Kanniainen <janne.kanniainen@gmail.com> > -Description: > - Set the mode of LEDs > - > - 0 - normal > - 1 - audio > - 2 - breathing > - > - Normal: LEDs are fully on when enabled > - Audio: LEDs brightness depends on sound level > - Breathing: LEDs brightness varies at human breathing rate > \ No newline at end of file > diff --git a/Documentation/ABI/testing/sysfs-class-leds-driver-gt683r b/Documentation/ABI/testing/sysfs-class-leds-driver-gt683r > new file mode 100644 > index 0000000..29769fb > --- /dev/null > +++ b/Documentation/ABI/testing/sysfs-class-leds-driver-gt683r > @@ -0,0 +1,16 @@ > +What: /sys/class/leds/<led>/msi_mode The ABI-file name now sort of matches the attribute path and there are examples of attributes being documented in this particular way, but naming is far from consistent in Documentation/ABI. Perhaps we should use the name field of the attribute group and kill two birds with one stone by making the sysfs file name match the attribute path, while also making it even more obvious that the mode attribute is a driver specific attribute (and not a common led class one) by placing it in a subdirectory. That is, if you set the .name field to "gt683r" (and rename the attribute and ABI-file again) then the file name and attribute path could match: Documentation/ABI/testing/sysfs-class-leds-gt683r What: /sys/class/leds/<led>/gt683r/mode Both patches look good otherwise. Johan ^ permalink raw reply [flat|nested] 81+ messages in thread
* [PATCH 2/2 v4] HID: leds: move led_mode attribute to led-class devices in MSI GT683R driver 2014-06-30 10:39 ` Johan Hovold @ 2014-07-01 17:50 ` Janne Kanniainen 2014-07-01 20:16 ` Johan Hovold 0 siblings, 1 reply; 81+ messages in thread From: Janne Kanniainen @ 2014-07-01 17:50 UTC (permalink / raw) To: johan Cc: cooloney, jkosina, greg, bjorn, linux-kernel, linux-leds, linux-usb, linux-input, Janne Kanniainen Move led_mode attribute from HID device to led-class devices and rename it msi_mode. This will also fix race condition by using attribute-groups. Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> --- Changes in v3: - Style fixes - Rename sysfs-class-hid-driver-gt683r to sysfs-class-leds-driver-gt683r Changes in v4: - Rename sysfs-class-leds-driver-gt683r to sysfs-class-leds-gt683r - Change "What: " to /sys/class/leds/<led>/gt683r/mode - Change .name from gt683r_led to gt683r .../ABI/testing/sysfs-class-hid-driver-gt683r | 14 ---------- Documentation/ABI/testing/sysfs-class-leds-gt683r | 16 ++++++++++++ drivers/hid/hid-gt683r.c | 30 ++++++++++++---------- 3 files changed, 33 insertions(+), 27 deletions(-) delete mode 100644 Documentation/ABI/testing/sysfs-class-hid-driver-gt683r create mode 100644 Documentation/ABI/testing/sysfs-class-leds-gt683r diff --git a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r deleted file mode 100644 index 317e9d5..0000000 --- a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r +++ /dev/null @@ -1,14 +0,0 @@ -What: /sys/class/hidraw/<hidraw>/device/leds_mode -Date: Jun 2014 -KernelVersion: 3.17 -Contact: Janne Kanniainen <janne.kanniainen@gmail.com> -Description: - Set the mode of LEDs - - 0 - normal - 1 - audio - 2 - breathing - - Normal: LEDs are fully on when enabled - Audio: LEDs brightness depends on sound level - Breathing: LEDs brightness varies at human breathing rate \ No newline at end of file diff --git a/Documentation/ABI/testing/sysfs-class-leds-gt683r b/Documentation/ABI/testing/sysfs-class-leds-gt683r new file mode 100644 index 0000000..e4fae60 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-leds-gt683r @@ -0,0 +1,16 @@ +What: /sys/class/leds/<led>/gt683r/mode +Date: Jun 2014 +KernelVersion: 3.17 +Contact: Janne Kanniainen <janne.kanniainen@gmail.com> +Description: + Set the mode of LEDs. You should notice that changing the mode + of one LED will update the mode of its two sibling devices as + well. + + 0 - normal + 1 - audio + 2 - breathing + + Normal: LEDs are fully on when enabled + Audio: LEDs brightness depends on sound level + Breathing: LEDs brightness varies at human breathing rate \ No newline at end of file diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c index 073bd80..f743444 100644 --- a/drivers/hid/hid-gt683r.c +++ b/drivers/hid/hid-gt683r.c @@ -84,12 +84,13 @@ static void gt683r_brightness_set(struct led_classdev *led_cdev, } } -static ssize_t leds_mode_show(struct device *dev, +static ssize_t mode_show(struct device *dev, struct device_attribute *attr, char *buf) { u8 sysfs_mode; - struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct hid_device *hdev = container_of(dev->parent, + struct hid_device, dev); struct gt683r_led *led = hid_get_drvdata(hdev); if (led->mode == GT683R_LED_NORMAL) @@ -102,12 +103,13 @@ static ssize_t leds_mode_show(struct device *dev, return scnprintf(buf, PAGE_SIZE, "%u\n", sysfs_mode); } -static ssize_t leds_mode_store(struct device *dev, +static ssize_t mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { u8 sysfs_mode; - struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct hid_device *hdev = container_of(dev->parent, + struct hid_device, dev); struct gt683r_led *led = hid_get_drvdata(hdev); @@ -212,7 +214,14 @@ fail: mutex_unlock(&led->lock); } -static DEVICE_ATTR_RW(leds_mode); +static DEVICE_ATTR_RW(mode); + +static struct attribute *gt683r_led_attrs[] = { + &dev_attr_mode.attr, + NULL +}; + +ATTRIBUTE_GROUPS(gt683r_led); static int gt683r_led_probe(struct hid_device *hdev, const struct hid_device_id *id) @@ -261,6 +270,8 @@ static int gt683r_led_probe(struct hid_device *hdev, led->led_devs[i].name = name; led->led_devs[i].max_brightness = 1; led->led_devs[i].brightness_set = gt683r_brightness_set; + led->led_devs[i].groups = gt683r_led_groups; + ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); if (ret) { hid_err(hdev, "could not register led device\n"); @@ -268,12 +279,6 @@ static int gt683r_led_probe(struct hid_device *hdev, } } - ret = device_create_file(&led->hdev->dev, &dev_attr_leds_mode); - if (ret) { - hid_err(hdev, "could not make mode attribute file\n"); - goto fail; - } - return 0; fail: @@ -288,7 +293,6 @@ static void gt683r_led_remove(struct hid_device *hdev) int i; struct gt683r_led *led = hid_get_drvdata(hdev); - device_remove_file(&hdev->dev, &dev_attr_leds_mode); for (i = 0; i < GT683R_LED_COUNT; i++) led_classdev_unregister(&led->led_devs[i]); flush_work(&led->work); @@ -298,7 +302,7 @@ static void gt683r_led_remove(struct hid_device *hdev) static struct hid_driver gt683r_led_driver = { .probe = gt683r_led_probe, .remove = gt683r_led_remove, - .name = "gt683r_led", + .name = "gt683r", .id_table = gt683r_led_id, }; -- 1.9.2 Did you mean like this? ^ permalink raw reply related [flat|nested] 81+ messages in thread
* Re: [PATCH 2/2 v4] HID: leds: move led_mode attribute to led-class devices in MSI GT683R driver 2014-07-01 17:50 ` [PATCH 2/2 v4] " Janne Kanniainen @ 2014-07-01 20:16 ` Johan Hovold 2014-07-02 17:37 ` [PATCH 2/2 v5] " Janne Kanniainen 0 siblings, 1 reply; 81+ messages in thread From: Johan Hovold @ 2014-07-01 20:16 UTC (permalink / raw) To: Janne Kanniainen Cc: johan, cooloney, jkosina, greg, bjorn, linux-kernel, linux-leds, linux-usb, linux-input On Tue, Jul 01, 2014 at 08:50:54PM +0300, Janne Kanniainen wrote: > -static DEVICE_ATTR_RW(leds_mode); > +static DEVICE_ATTR_RW(mode); > + > +static struct attribute *gt683r_led_attrs[] = { > + &dev_attr_mode.attr, > + NULL > +}; > + > +ATTRIBUTE_GROUPS(gt683r_led); I was referring to the name field of struct attribute_group (and not of struct hid_driver). Specifically, that means that you cannot use the ATTRIBUTE_GROUPS macro (which leaves the name field unset), but rather should define the two corresponding structs directly as follows: static const struct attribute_group gt683r_led_group = { .name = "gt683r", .attrs = gt683r_led_attrs, }; static const struct attribute_group *gt683r_led_groups[] = { >683r_led_group, NULL }; That way the mode attribute will be created in a subdirectory (named gt683r) of the led class device. > static int gt683r_led_probe(struct hid_device *hdev, > const struct hid_device_id *id) > @@ -261,6 +270,8 @@ static int gt683r_led_probe(struct hid_device *hdev, > led->led_devs[i].name = name; > led->led_devs[i].max_brightness = 1; > led->led_devs[i].brightness_set = gt683r_brightness_set; > + led->led_devs[i].groups = gt683r_led_groups; > + > ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); > if (ret) { > hid_err(hdev, "could not register led device\n"); > @@ -268,12 +279,6 @@ static int gt683r_led_probe(struct hid_device *hdev, > } > } <snip> > @@ -298,7 +302,7 @@ static void gt683r_led_remove(struct hid_device *hdev) > static struct hid_driver gt683r_led_driver = { > .probe = gt683r_led_probe, > .remove = gt683r_led_remove, > - .name = "gt683r_led", > + .name = "gt683r", So you should skip this bit. > .id_table = gt683r_led_id, > }; Johan ^ permalink raw reply [flat|nested] 81+ messages in thread
* [PATCH 2/2 v5] HID: leds: move led_mode attribute to led-class devices in MSI GT683R driver 2014-07-01 20:16 ` Johan Hovold @ 2014-07-02 17:37 ` Janne Kanniainen 2014-07-03 8:28 ` Johan Hovold 0 siblings, 1 reply; 81+ messages in thread From: Janne Kanniainen @ 2014-07-02 17:37 UTC (permalink / raw) To: johan Cc: cooloney, jkosina, greg, bjorn, linux-kernel, linux-leds, linux-usb, linux-input, Janne Kanniainen Move led_mode attribute from HID device to led-class devices. This will also fix race condition by using attribute-groups. Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> --- Changes in v3: - Style fixes - Rename sysfs-class-hid-driver-gt683r to sysfs-class-leds-driver-gt683r Changes in v4: - Rename sysfs-class-leds-driver-gt683r to sysfs-class-leds-gt683r - Change "What: " to /sys/class/leds/<led>/gt683r/mode - Change .name from gt683r_led to gt683r Changes in v5: - Move mode attribute to gt683r/mode .../ABI/testing/sysfs-class-hid-driver-gt683r | 14 --------- Documentation/ABI/testing/sysfs-class-leds-gt683r | 16 ++++++++++ drivers/hid/hid-gt683r.c | 36 ++++++++++++++-------- 3 files changed, 40 insertions(+), 26 deletions(-) delete mode 100644 Documentation/ABI/testing/sysfs-class-hid-driver-gt683r create mode 100644 Documentation/ABI/testing/sysfs-class-leds-gt683r diff --git a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r deleted file mode 100644 index 317e9d5..0000000 --- a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r +++ /dev/null @@ -1,14 +0,0 @@ -What: /sys/class/hidraw/<hidraw>/device/leds_mode -Date: Jun 2014 -KernelVersion: 3.17 -Contact: Janne Kanniainen <janne.kanniainen@gmail.com> -Description: - Set the mode of LEDs - - 0 - normal - 1 - audio - 2 - breathing - - Normal: LEDs are fully on when enabled - Audio: LEDs brightness depends on sound level - Breathing: LEDs brightness varies at human breathing rate \ No newline at end of file diff --git a/Documentation/ABI/testing/sysfs-class-leds-gt683r b/Documentation/ABI/testing/sysfs-class-leds-gt683r new file mode 100644 index 0000000..e4fae60 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-leds-gt683r @@ -0,0 +1,16 @@ +What: /sys/class/leds/<led>/gt683r/mode +Date: Jun 2014 +KernelVersion: 3.17 +Contact: Janne Kanniainen <janne.kanniainen@gmail.com> +Description: + Set the mode of LEDs. You should notice that changing the mode + of one LED will update the mode of its two sibling devices as + well. + + 0 - normal + 1 - audio + 2 - breathing + + Normal: LEDs are fully on when enabled + Audio: LEDs brightness depends on sound level + Breathing: LEDs brightness varies at human breathing rate \ No newline at end of file diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c index 073bd80..0d6f135 100644 --- a/drivers/hid/hid-gt683r.c +++ b/drivers/hid/hid-gt683r.c @@ -84,12 +84,13 @@ static void gt683r_brightness_set(struct led_classdev *led_cdev, } } -static ssize_t leds_mode_show(struct device *dev, +static ssize_t mode_show(struct device *dev, struct device_attribute *attr, char *buf) { u8 sysfs_mode; - struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct hid_device *hdev = container_of(dev->parent, + struct hid_device, dev); struct gt683r_led *led = hid_get_drvdata(hdev); if (led->mode == GT683R_LED_NORMAL) @@ -102,12 +103,13 @@ static ssize_t leds_mode_show(struct device *dev, return scnprintf(buf, PAGE_SIZE, "%u\n", sysfs_mode); } -static ssize_t leds_mode_store(struct device *dev, +static ssize_t mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { u8 sysfs_mode; - struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct hid_device *hdev = container_of(dev->parent, + struct hid_device, dev); struct gt683r_led *led = hid_get_drvdata(hdev); @@ -212,7 +214,22 @@ fail: mutex_unlock(&led->lock); } -static DEVICE_ATTR_RW(leds_mode); +static DEVICE_ATTR_RW(mode); + +static struct attribute *gt683r_led_attrs[] = { + &dev_attr_mode.attr, + NULL +}; + +static const struct attribute_group gt683r_led_group = { + .name = "gt683r", + .attrs = gt683r_led_attrs, +}; + +static const struct attribute_group *gt683r_led_groups[] = { + >683r_led_group, + NULL +}; static int gt683r_led_probe(struct hid_device *hdev, const struct hid_device_id *id) @@ -261,6 +278,8 @@ static int gt683r_led_probe(struct hid_device *hdev, led->led_devs[i].name = name; led->led_devs[i].max_brightness = 1; led->led_devs[i].brightness_set = gt683r_brightness_set; + led->led_devs[i].groups = gt683r_led_groups; + ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); if (ret) { hid_err(hdev, "could not register led device\n"); @@ -268,12 +287,6 @@ static int gt683r_led_probe(struct hid_device *hdev, } } - ret = device_create_file(&led->hdev->dev, &dev_attr_leds_mode); - if (ret) { - hid_err(hdev, "could not make mode attribute file\n"); - goto fail; - } - return 0; fail: @@ -288,7 +301,6 @@ static void gt683r_led_remove(struct hid_device *hdev) int i; struct gt683r_led *led = hid_get_drvdata(hdev); - device_remove_file(&hdev->dev, &dev_attr_leds_mode); for (i = 0; i < GT683R_LED_COUNT; i++) led_classdev_unregister(&led->led_devs[i]); flush_work(&led->work); -- 1.9.2 ^ permalink raw reply related [flat|nested] 81+ messages in thread
* Re: [PATCH 2/2 v5] HID: leds: move led_mode attribute to led-class devices in MSI GT683R driver 2014-07-02 17:37 ` [PATCH 2/2 v5] " Janne Kanniainen @ 2014-07-03 8:28 ` Johan Hovold 2014-07-03 17:17 ` [PATCH 1/2 v6] HID: gt683r: fix race condition Janne Kanniainen 0 siblings, 1 reply; 81+ messages in thread From: Johan Hovold @ 2014-07-03 8:28 UTC (permalink / raw) To: Janne Kanniainen Cc: johan, cooloney, jkosina, greg, bjorn, linux-kernel, linux-leds, linux-usb, linux-input On Wed, Jul 02, 2014 at 08:37:59PM +0300, Janne Kanniainen wrote: > Move led_mode attribute from HID device to led-class devices. This will also fix race condition by using attribute-groups. > > Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> Looks good now. Thanks! Perhaps you can resend both patches as a series (call both v6) so it's easy to figure which version that is to be applied. I also noticed that your subject line is a bit long (will end up as the commit summary). Using for example HID: gt683r: move mode attribute to led-class devices would make it more concise. Oh, and your commit message lacks line breaks (around 72 cols). You could fix that as well. Thanks again, Johan ^ permalink raw reply [flat|nested] 81+ messages in thread
* [PATCH 1/2 v6] HID: gt683r: fix race condition 2014-07-03 8:28 ` Johan Hovold @ 2014-07-03 17:17 ` Janne Kanniainen 2014-07-03 17:17 ` [PATCH 2/2 v6] HID: gt683r: move mode attribute to led-class devices Janne Kanniainen 2014-07-03 17:34 ` Johan Hovold 0 siblings, 2 replies; 81+ messages in thread From: Janne Kanniainen @ 2014-07-03 17:17 UTC (permalink / raw) To: johan Cc: cooloney, jkosina, greg, bjorn, linux-kernel, linux-leds, linux-usb, linux-input, Janne Kanniainen This will fix race condition noticed by Oliver Neukum. Sysfs files are created before mutex and work are initialized. Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> --- drivers/hid/hid-gt683r.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c index 077f7a1..073bd80 100644 --- a/drivers/hid/hid-gt683r.c +++ b/drivers/hid/hid-gt683r.c @@ -227,6 +227,9 @@ static int gt683r_led_probe(struct hid_device *hdev, if (!led) return -ENOMEM; + mutex_init(&led->lock); + INIT_WORK(&led->work, gt683r_led_work); + led->mode = GT683R_LED_NORMAL; led->hdev = hdev; hid_set_drvdata(hdev, led); @@ -271,9 +274,6 @@ static int gt683r_led_probe(struct hid_device *hdev, goto fail; } - mutex_init(&led->lock); - INIT_WORK(&led->work, gt683r_led_work); - return 0; fail: -- 1.9.2 ^ permalink raw reply related [flat|nested] 81+ messages in thread
* [PATCH 2/2 v6] HID: gt683r: move mode attribute to led-class devices 2014-07-03 17:17 ` [PATCH 1/2 v6] HID: gt683r: fix race condition Janne Kanniainen @ 2014-07-03 17:17 ` Janne Kanniainen 2014-07-03 17:40 ` Johan Hovold 2014-07-03 17:34 ` Johan Hovold 1 sibling, 1 reply; 81+ messages in thread From: Janne Kanniainen @ 2014-07-03 17:17 UTC (permalink / raw) To: johan Cc: cooloney, jkosina, greg, bjorn, linux-kernel, linux-leds, linux-usb, linux-input, Janne Kanniainen Move led_mode attribute from HID device to led-class devices and rename it msi_mode. This will also fix race condition by using attribute-groups. Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> --- Changes in v3: - Style fixes - Rename sysfs-class-hid-driver-gt683r to sysfs-class-leds-driver-gt683r Changes in v4: - Rename sysfs-class-leds-driver-gt683r to sysfs-class-leds-gt683r - Change "What: " to /sys/class/leds/<led>/gt683r/mode - Change .name from gt683r_led to gt683r Changes in v5: - Move mode attribute to gt683r/mode Changes in v6: - Fix subject and commit message .../ABI/testing/sysfs-class-hid-driver-gt683r | 14 --------- Documentation/ABI/testing/sysfs-class-leds-gt683r | 16 ++++++++++ drivers/hid/hid-gt683r.c | 36 ++++++++++++++-------- 3 files changed, 40 insertions(+), 26 deletions(-) delete mode 100644 Documentation/ABI/testing/sysfs-class-hid-driver-gt683r create mode 100644 Documentation/ABI/testing/sysfs-class-leds-gt683r diff --git a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r deleted file mode 100644 index 317e9d5..0000000 --- a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r +++ /dev/null @@ -1,14 +0,0 @@ -What: /sys/class/hidraw/<hidraw>/device/leds_mode -Date: Jun 2014 -KernelVersion: 3.17 -Contact: Janne Kanniainen <janne.kanniainen@gmail.com> -Description: - Set the mode of LEDs - - 0 - normal - 1 - audio - 2 - breathing - - Normal: LEDs are fully on when enabled - Audio: LEDs brightness depends on sound level - Breathing: LEDs brightness varies at human breathing rate \ No newline at end of file diff --git a/Documentation/ABI/testing/sysfs-class-leds-gt683r b/Documentation/ABI/testing/sysfs-class-leds-gt683r new file mode 100644 index 0000000..e4fae60 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-class-leds-gt683r @@ -0,0 +1,16 @@ +What: /sys/class/leds/<led>/gt683r/mode +Date: Jun 2014 +KernelVersion: 3.17 +Contact: Janne Kanniainen <janne.kanniainen@gmail.com> +Description: + Set the mode of LEDs. You should notice that changing the mode + of one LED will update the mode of its two sibling devices as + well. + + 0 - normal + 1 - audio + 2 - breathing + + Normal: LEDs are fully on when enabled + Audio: LEDs brightness depends on sound level + Breathing: LEDs brightness varies at human breathing rate \ No newline at end of file diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c index 073bd80..0d6f135 100644 --- a/drivers/hid/hid-gt683r.c +++ b/drivers/hid/hid-gt683r.c @@ -84,12 +84,13 @@ static void gt683r_brightness_set(struct led_classdev *led_cdev, } } -static ssize_t leds_mode_show(struct device *dev, +static ssize_t mode_show(struct device *dev, struct device_attribute *attr, char *buf) { u8 sysfs_mode; - struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct hid_device *hdev = container_of(dev->parent, + struct hid_device, dev); struct gt683r_led *led = hid_get_drvdata(hdev); if (led->mode == GT683R_LED_NORMAL) @@ -102,12 +103,13 @@ static ssize_t leds_mode_show(struct device *dev, return scnprintf(buf, PAGE_SIZE, "%u\n", sysfs_mode); } -static ssize_t leds_mode_store(struct device *dev, +static ssize_t mode_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { u8 sysfs_mode; - struct hid_device *hdev = container_of(dev, struct hid_device, dev); + struct hid_device *hdev = container_of(dev->parent, + struct hid_device, dev); struct gt683r_led *led = hid_get_drvdata(hdev); @@ -212,7 +214,22 @@ fail: mutex_unlock(&led->lock); } -static DEVICE_ATTR_RW(leds_mode); +static DEVICE_ATTR_RW(mode); + +static struct attribute *gt683r_led_attrs[] = { + &dev_attr_mode.attr, + NULL +}; + +static const struct attribute_group gt683r_led_group = { + .name = "gt683r", + .attrs = gt683r_led_attrs, +}; + +static const struct attribute_group *gt683r_led_groups[] = { + >683r_led_group, + NULL +}; static int gt683r_led_probe(struct hid_device *hdev, const struct hid_device_id *id) @@ -261,6 +278,8 @@ static int gt683r_led_probe(struct hid_device *hdev, led->led_devs[i].name = name; led->led_devs[i].max_brightness = 1; led->led_devs[i].brightness_set = gt683r_brightness_set; + led->led_devs[i].groups = gt683r_led_groups; + ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); if (ret) { hid_err(hdev, "could not register led device\n"); @@ -268,12 +287,6 @@ static int gt683r_led_probe(struct hid_device *hdev, } } - ret = device_create_file(&led->hdev->dev, &dev_attr_leds_mode); - if (ret) { - hid_err(hdev, "could not make mode attribute file\n"); - goto fail; - } - return 0; fail: @@ -288,7 +301,6 @@ static void gt683r_led_remove(struct hid_device *hdev) int i; struct gt683r_led *led = hid_get_drvdata(hdev); - device_remove_file(&hdev->dev, &dev_attr_leds_mode); for (i = 0; i < GT683R_LED_COUNT; i++) led_classdev_unregister(&led->led_devs[i]); flush_work(&led->work); -- 1.9.2 ^ permalink raw reply related [flat|nested] 81+ messages in thread
* Re: [PATCH 2/2 v6] HID: gt683r: move mode attribute to led-class devices 2014-07-03 17:17 ` [PATCH 2/2 v6] HID: gt683r: move mode attribute to led-class devices Janne Kanniainen @ 2014-07-03 17:40 ` Johan Hovold 0 siblings, 0 replies; 81+ messages in thread From: Johan Hovold @ 2014-07-03 17:40 UTC (permalink / raw) To: Janne Kanniainen Cc: johan, cooloney, jkosina, greg, bjorn, linux-kernel, linux-leds, linux-usb, linux-input On Thu, Jul 03, 2014 at 08:17:09PM +0300, Janne Kanniainen wrote: > Move led_mode attribute from HID device to led-class devices and rename > it msi_mode. This will also fix race condition by using There's a typo here (s/msi_mode/mode) but perhaps Bryan can just fix that up before applying? > attribute-groups. > > Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> Reviewed-by: Johan Hovold <johan@kernel.org> Otherwise both patches (v6) are ready to be merged, Bryan. Thanks, Janne! Johan > --- > > Changes in v3: > - Style fixes > - Rename sysfs-class-hid-driver-gt683r to sysfs-class-leds-driver-gt683r > > Changes in v4: > - Rename sysfs-class-leds-driver-gt683r to sysfs-class-leds-gt683r > - Change "What: " to /sys/class/leds/<led>/gt683r/mode > - Change .name from gt683r_led to gt683r > > Changes in v5: > - Move mode attribute to gt683r/mode > > Changes in v6: > - Fix subject and commit message > > .../ABI/testing/sysfs-class-hid-driver-gt683r | 14 --------- > Documentation/ABI/testing/sysfs-class-leds-gt683r | 16 ++++++++++ > drivers/hid/hid-gt683r.c | 36 ++++++++++++++-------- > 3 files changed, 40 insertions(+), 26 deletions(-) > delete mode 100644 Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > create mode 100644 Documentation/ABI/testing/sysfs-class-leds-gt683r > > diff --git a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > deleted file mode 100644 > index 317e9d5..0000000 > --- a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > +++ /dev/null > @@ -1,14 +0,0 @@ > -What: /sys/class/hidraw/<hidraw>/device/leds_mode > -Date: Jun 2014 > -KernelVersion: 3.17 > -Contact: Janne Kanniainen <janne.kanniainen@gmail.com> > -Description: > - Set the mode of LEDs > - > - 0 - normal > - 1 - audio > - 2 - breathing > - > - Normal: LEDs are fully on when enabled > - Audio: LEDs brightness depends on sound level > - Breathing: LEDs brightness varies at human breathing rate > \ No newline at end of file > diff --git a/Documentation/ABI/testing/sysfs-class-leds-gt683r b/Documentation/ABI/testing/sysfs-class-leds-gt683r > new file mode 100644 > index 0000000..e4fae60 > --- /dev/null > +++ b/Documentation/ABI/testing/sysfs-class-leds-gt683r > @@ -0,0 +1,16 @@ > +What: /sys/class/leds/<led>/gt683r/mode > +Date: Jun 2014 > +KernelVersion: 3.17 > +Contact: Janne Kanniainen <janne.kanniainen@gmail.com> > +Description: > + Set the mode of LEDs. You should notice that changing the mode > + of one LED will update the mode of its two sibling devices as > + well. > + > + 0 - normal > + 1 - audio > + 2 - breathing > + > + Normal: LEDs are fully on when enabled > + Audio: LEDs brightness depends on sound level > + Breathing: LEDs brightness varies at human breathing rate > \ No newline at end of file > diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c > index 073bd80..0d6f135 100644 > --- a/drivers/hid/hid-gt683r.c > +++ b/drivers/hid/hid-gt683r.c > @@ -84,12 +84,13 @@ static void gt683r_brightness_set(struct led_classdev *led_cdev, > } > } > > -static ssize_t leds_mode_show(struct device *dev, > +static ssize_t mode_show(struct device *dev, > struct device_attribute *attr, > char *buf) > { > u8 sysfs_mode; > - struct hid_device *hdev = container_of(dev, struct hid_device, dev); > + struct hid_device *hdev = container_of(dev->parent, > + struct hid_device, dev); > struct gt683r_led *led = hid_get_drvdata(hdev); > > if (led->mode == GT683R_LED_NORMAL) > @@ -102,12 +103,13 @@ static ssize_t leds_mode_show(struct device *dev, > return scnprintf(buf, PAGE_SIZE, "%u\n", sysfs_mode); > } > > -static ssize_t leds_mode_store(struct device *dev, > +static ssize_t mode_store(struct device *dev, > struct device_attribute *attr, > const char *buf, size_t count) > { > u8 sysfs_mode; > - struct hid_device *hdev = container_of(dev, struct hid_device, dev); > + struct hid_device *hdev = container_of(dev->parent, > + struct hid_device, dev); > struct gt683r_led *led = hid_get_drvdata(hdev); > > > @@ -212,7 +214,22 @@ fail: > mutex_unlock(&led->lock); > } > > -static DEVICE_ATTR_RW(leds_mode); > +static DEVICE_ATTR_RW(mode); > + > +static struct attribute *gt683r_led_attrs[] = { > + &dev_attr_mode.attr, > + NULL > +}; > + > +static const struct attribute_group gt683r_led_group = { > + .name = "gt683r", > + .attrs = gt683r_led_attrs, > +}; > + > +static const struct attribute_group *gt683r_led_groups[] = { > + >683r_led_group, > + NULL > +}; > > static int gt683r_led_probe(struct hid_device *hdev, > const struct hid_device_id *id) > @@ -261,6 +278,8 @@ static int gt683r_led_probe(struct hid_device *hdev, > led->led_devs[i].name = name; > led->led_devs[i].max_brightness = 1; > led->led_devs[i].brightness_set = gt683r_brightness_set; > + led->led_devs[i].groups = gt683r_led_groups; > + > ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); > if (ret) { > hid_err(hdev, "could not register led device\n"); > @@ -268,12 +287,6 @@ static int gt683r_led_probe(struct hid_device *hdev, > } > } > > - ret = device_create_file(&led->hdev->dev, &dev_attr_leds_mode); > - if (ret) { > - hid_err(hdev, "could not make mode attribute file\n"); > - goto fail; > - } > - > return 0; > > fail: > @@ -288,7 +301,6 @@ static void gt683r_led_remove(struct hid_device *hdev) > int i; > struct gt683r_led *led = hid_get_drvdata(hdev); > > - device_remove_file(&hdev->dev, &dev_attr_leds_mode); > for (i = 0; i < GT683R_LED_COUNT; i++) > led_classdev_unregister(&led->led_devs[i]); > flush_work(&led->work); ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH 2/2 v6] HID: gt683r: move mode attribute to led-class devices @ 2014-07-03 17:40 ` Johan Hovold 0 siblings, 0 replies; 81+ messages in thread From: Johan Hovold @ 2014-07-03 17:40 UTC (permalink / raw) To: Janne Kanniainen, cooloney Cc: johan, cooloney, jkosina, greg, bjorn, linux-kernel, linux-leds, linux-usb, linux-input On Thu, Jul 03, 2014 at 08:17:09PM +0300, Janne Kanniainen wrote: > Move led_mode attribute from HID device to led-class devices and rename > it msi_mode. This will also fix race condition by using There's a typo here (s/msi_mode/mode) but perhaps Bryan can just fix that up before applying? > attribute-groups. > > Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> Reviewed-by: Johan Hovold <johan@kernel.org> Otherwise both patches (v6) are ready to be merged, Bryan. Thanks, Janne! Johan > --- > > Changes in v3: > - Style fixes > - Rename sysfs-class-hid-driver-gt683r to sysfs-class-leds-driver-gt683r > > Changes in v4: > - Rename sysfs-class-leds-driver-gt683r to sysfs-class-leds-gt683r > - Change "What: " to /sys/class/leds/<led>/gt683r/mode > - Change .name from gt683r_led to gt683r > > Changes in v5: > - Move mode attribute to gt683r/mode > > Changes in v6: > - Fix subject and commit message > > .../ABI/testing/sysfs-class-hid-driver-gt683r | 14 --------- > Documentation/ABI/testing/sysfs-class-leds-gt683r | 16 ++++++++++ > drivers/hid/hid-gt683r.c | 36 ++++++++++++++-------- > 3 files changed, 40 insertions(+), 26 deletions(-) > delete mode 100644 Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > create mode 100644 Documentation/ABI/testing/sysfs-class-leds-gt683r > > diff --git a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > deleted file mode 100644 > index 317e9d5..0000000 > --- a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > +++ /dev/null > @@ -1,14 +0,0 @@ > -What: /sys/class/hidraw/<hidraw>/device/leds_mode > -Date: Jun 2014 > -KernelVersion: 3.17 > -Contact: Janne Kanniainen <janne.kanniainen@gmail.com> > -Description: > - Set the mode of LEDs > - > - 0 - normal > - 1 - audio > - 2 - breathing > - > - Normal: LEDs are fully on when enabled > - Audio: LEDs brightness depends on sound level > - Breathing: LEDs brightness varies at human breathing rate > \ No newline at end of file > diff --git a/Documentation/ABI/testing/sysfs-class-leds-gt683r b/Documentation/ABI/testing/sysfs-class-leds-gt683r > new file mode 100644 > index 0000000..e4fae60 > --- /dev/null > +++ b/Documentation/ABI/testing/sysfs-class-leds-gt683r > @@ -0,0 +1,16 @@ > +What: /sys/class/leds/<led>/gt683r/mode > +Date: Jun 2014 > +KernelVersion: 3.17 > +Contact: Janne Kanniainen <janne.kanniainen@gmail.com> > +Description: > + Set the mode of LEDs. You should notice that changing the mode > + of one LED will update the mode of its two sibling devices as > + well. > + > + 0 - normal > + 1 - audio > + 2 - breathing > + > + Normal: LEDs are fully on when enabled > + Audio: LEDs brightness depends on sound level > + Breathing: LEDs brightness varies at human breathing rate > \ No newline at end of file > diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c > index 073bd80..0d6f135 100644 > --- a/drivers/hid/hid-gt683r.c > +++ b/drivers/hid/hid-gt683r.c > @@ -84,12 +84,13 @@ static void gt683r_brightness_set(struct led_classdev *led_cdev, > } > } > > -static ssize_t leds_mode_show(struct device *dev, > +static ssize_t mode_show(struct device *dev, > struct device_attribute *attr, > char *buf) > { > u8 sysfs_mode; > - struct hid_device *hdev = container_of(dev, struct hid_device, dev); > + struct hid_device *hdev = container_of(dev->parent, > + struct hid_device, dev); > struct gt683r_led *led = hid_get_drvdata(hdev); > > if (led->mode == GT683R_LED_NORMAL) > @@ -102,12 +103,13 @@ static ssize_t leds_mode_show(struct device *dev, > return scnprintf(buf, PAGE_SIZE, "%u\n", sysfs_mode); > } > > -static ssize_t leds_mode_store(struct device *dev, > +static ssize_t mode_store(struct device *dev, > struct device_attribute *attr, > const char *buf, size_t count) > { > u8 sysfs_mode; > - struct hid_device *hdev = container_of(dev, struct hid_device, dev); > + struct hid_device *hdev = container_of(dev->parent, > + struct hid_device, dev); > struct gt683r_led *led = hid_get_drvdata(hdev); > > > @@ -212,7 +214,22 @@ fail: > mutex_unlock(&led->lock); > } > > -static DEVICE_ATTR_RW(leds_mode); > +static DEVICE_ATTR_RW(mode); > + > +static struct attribute *gt683r_led_attrs[] = { > + &dev_attr_mode.attr, > + NULL > +}; > + > +static const struct attribute_group gt683r_led_group = { > + .name = "gt683r", > + .attrs = gt683r_led_attrs, > +}; > + > +static const struct attribute_group *gt683r_led_groups[] = { > + >683r_led_group, > + NULL > +}; > > static int gt683r_led_probe(struct hid_device *hdev, > const struct hid_device_id *id) > @@ -261,6 +278,8 @@ static int gt683r_led_probe(struct hid_device *hdev, > led->led_devs[i].name = name; > led->led_devs[i].max_brightness = 1; > led->led_devs[i].brightness_set = gt683r_brightness_set; > + led->led_devs[i].groups = gt683r_led_groups; > + > ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); > if (ret) { > hid_err(hdev, "could not register led device\n"); > @@ -268,12 +287,6 @@ static int gt683r_led_probe(struct hid_device *hdev, > } > } > > - ret = device_create_file(&led->hdev->dev, &dev_attr_leds_mode); > - if (ret) { > - hid_err(hdev, "could not make mode attribute file\n"); > - goto fail; > - } > - > return 0; > > fail: > @@ -288,7 +301,6 @@ static void gt683r_led_remove(struct hid_device *hdev) > int i; > struct gt683r_led *led = hid_get_drvdata(hdev); > > - device_remove_file(&hdev->dev, &dev_attr_leds_mode); > for (i = 0; i < GT683R_LED_COUNT; i++) > led_classdev_unregister(&led->led_devs[i]); > flush_work(&led->work); ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH 2/2 v6] HID: gt683r: move mode attribute to led-class devices 2014-07-03 17:40 ` Johan Hovold (?) @ 2014-07-03 18:17 ` Bryan Wu 2014-07-03 18:28 ` Janne Kanniainen -1 siblings, 1 reply; 81+ messages in thread From: Bryan Wu @ 2014-07-03 18:17 UTC (permalink / raw) To: Johan Hovold Cc: Janne Kanniainen, Jiri Kosina, Greg Kroah-Hartman, Bjørn Mork, lkml, Linux LED Subsystem, linux-usb, linux-input On Thu, Jul 3, 2014 at 10:40 AM, Johan Hovold <johan@kernel.org> wrote: > On Thu, Jul 03, 2014 at 08:17:09PM +0300, Janne Kanniainen wrote: >> Move led_mode attribute from HID device to led-class devices and rename >> it msi_mode. This will also fix race condition by using > > There's a typo here (s/msi_mode/mode) but perhaps Bryan can just fix > that up before applying? > >> attribute-groups. >> >> Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> > > Reviewed-by: Johan Hovold <johan@kernel.org> > > Otherwise both patches (v6) are ready to be merged, Bryan. > > Thanks, Janne! > No problem. I fixed the typo and merged it. Thanks, -Bryan >> --- >> >> Changes in v3: >> - Style fixes >> - Rename sysfs-class-hid-driver-gt683r to sysfs-class-leds-driver-gt683r >> >> Changes in v4: >> - Rename sysfs-class-leds-driver-gt683r to sysfs-class-leds-gt683r >> - Change "What: " to /sys/class/leds/<led>/gt683r/mode >> - Change .name from gt683r_led to gt683r >> >> Changes in v5: >> - Move mode attribute to gt683r/mode >> >> Changes in v6: >> - Fix subject and commit message >> >> .../ABI/testing/sysfs-class-hid-driver-gt683r | 14 --------- >> Documentation/ABI/testing/sysfs-class-leds-gt683r | 16 ++++++++++ >> drivers/hid/hid-gt683r.c | 36 ++++++++++++++-------- >> 3 files changed, 40 insertions(+), 26 deletions(-) >> delete mode 100644 Documentation/ABI/testing/sysfs-class-hid-driver-gt683r >> create mode 100644 Documentation/ABI/testing/sysfs-class-leds-gt683r >> >> diff --git a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r >> deleted file mode 100644 >> index 317e9d5..0000000 >> --- a/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r >> +++ /dev/null >> @@ -1,14 +0,0 @@ >> -What: /sys/class/hidraw/<hidraw>/device/leds_mode >> -Date: Jun 2014 >> -KernelVersion: 3.17 >> -Contact: Janne Kanniainen <janne.kanniainen@gmail.com> >> -Description: >> - Set the mode of LEDs >> - >> - 0 - normal >> - 1 - audio >> - 2 - breathing >> - >> - Normal: LEDs are fully on when enabled >> - Audio: LEDs brightness depends on sound level >> - Breathing: LEDs brightness varies at human breathing rate >> \ No newline at end of file >> diff --git a/Documentation/ABI/testing/sysfs-class-leds-gt683r b/Documentation/ABI/testing/sysfs-class-leds-gt683r >> new file mode 100644 >> index 0000000..e4fae60 >> --- /dev/null >> +++ b/Documentation/ABI/testing/sysfs-class-leds-gt683r >> @@ -0,0 +1,16 @@ >> +What: /sys/class/leds/<led>/gt683r/mode >> +Date: Jun 2014 >> +KernelVersion: 3.17 >> +Contact: Janne Kanniainen <janne.kanniainen@gmail.com> >> +Description: >> + Set the mode of LEDs. You should notice that changing the mode >> + of one LED will update the mode of its two sibling devices as >> + well. >> + >> + 0 - normal >> + 1 - audio >> + 2 - breathing >> + >> + Normal: LEDs are fully on when enabled >> + Audio: LEDs brightness depends on sound level >> + Breathing: LEDs brightness varies at human breathing rate >> \ No newline at end of file >> diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c >> index 073bd80..0d6f135 100644 >> --- a/drivers/hid/hid-gt683r.c >> +++ b/drivers/hid/hid-gt683r.c >> @@ -84,12 +84,13 @@ static void gt683r_brightness_set(struct led_classdev *led_cdev, >> } >> } >> >> -static ssize_t leds_mode_show(struct device *dev, >> +static ssize_t mode_show(struct device *dev, >> struct device_attribute *attr, >> char *buf) >> { >> u8 sysfs_mode; >> - struct hid_device *hdev = container_of(dev, struct hid_device, dev); >> + struct hid_device *hdev = container_of(dev->parent, >> + struct hid_device, dev); >> struct gt683r_led *led = hid_get_drvdata(hdev); >> >> if (led->mode == GT683R_LED_NORMAL) >> @@ -102,12 +103,13 @@ static ssize_t leds_mode_show(struct device *dev, >> return scnprintf(buf, PAGE_SIZE, "%u\n", sysfs_mode); >> } >> >> -static ssize_t leds_mode_store(struct device *dev, >> +static ssize_t mode_store(struct device *dev, >> struct device_attribute *attr, >> const char *buf, size_t count) >> { >> u8 sysfs_mode; >> - struct hid_device *hdev = container_of(dev, struct hid_device, dev); >> + struct hid_device *hdev = container_of(dev->parent, >> + struct hid_device, dev); >> struct gt683r_led *led = hid_get_drvdata(hdev); >> >> >> @@ -212,7 +214,22 @@ fail: >> mutex_unlock(&led->lock); >> } >> >> -static DEVICE_ATTR_RW(leds_mode); >> +static DEVICE_ATTR_RW(mode); >> + >> +static struct attribute *gt683r_led_attrs[] = { >> + &dev_attr_mode.attr, >> + NULL >> +}; >> + >> +static const struct attribute_group gt683r_led_group = { >> + .name = "gt683r", >> + .attrs = gt683r_led_attrs, >> +}; >> + >> +static const struct attribute_group *gt683r_led_groups[] = { >> + >683r_led_group, >> + NULL >> +}; >> >> static int gt683r_led_probe(struct hid_device *hdev, >> const struct hid_device_id *id) >> @@ -261,6 +278,8 @@ static int gt683r_led_probe(struct hid_device *hdev, >> led->led_devs[i].name = name; >> led->led_devs[i].max_brightness = 1; >> led->led_devs[i].brightness_set = gt683r_brightness_set; >> + led->led_devs[i].groups = gt683r_led_groups; >> + >> ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); >> if (ret) { >> hid_err(hdev, "could not register led device\n"); >> @@ -268,12 +287,6 @@ static int gt683r_led_probe(struct hid_device *hdev, >> } >> } >> >> - ret = device_create_file(&led->hdev->dev, &dev_attr_leds_mode); >> - if (ret) { >> - hid_err(hdev, "could not make mode attribute file\n"); >> - goto fail; >> - } >> - >> return 0; >> >> fail: >> @@ -288,7 +301,6 @@ static void gt683r_led_remove(struct hid_device *hdev) >> int i; >> struct gt683r_led *led = hid_get_drvdata(hdev); >> >> - device_remove_file(&hdev->dev, &dev_attr_leds_mode); >> for (i = 0; i < GT683R_LED_COUNT; i++) >> led_classdev_unregister(&led->led_devs[i]); >> flush_work(&led->work); ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH 2/2 v6] HID: gt683r: move mode attribute to led-class devices 2014-07-03 18:17 ` Bryan Wu @ 2014-07-03 18:28 ` Janne Kanniainen 0 siblings, 0 replies; 81+ messages in thread From: Janne Kanniainen @ 2014-07-03 18:28 UTC (permalink / raw) To: Bryan Wu Cc: Johan Hovold, Jiri Kosina, Greg Kroah-Hartman, Bjørn Mork, lkml, Linux LED Subsystem, linux-usb, linux-input 2014-07-03 21:17 GMT+03:00 Bryan Wu <cooloney@gmail.com>: > On Thu, Jul 3, 2014 at 10:40 AM, Johan Hovold <johan@kernel.org> wrote: >> On Thu, Jul 03, 2014 at 08:17:09PM +0300, Janne Kanniainen wrote: >>> Move led_mode attribute from HID device to led-class devices and rename >>> it msi_mode. This will also fix race condition by using >> >> There's a typo here (s/msi_mode/mode) but perhaps Bryan can just fix >> that up before applying? >> >>> attribute-groups. >>> >>> Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> >> >> Reviewed-by: Johan Hovold <johan@kernel.org> >> >> Otherwise both patches (v6) are ready to be merged, Bryan. >> >> Thanks, Janne! >> > > No problem. I fixed the typo and merged it. > > Thanks, > -Bryan Thanks again to both of you! Janne ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH 1/2 v6] HID: gt683r: fix race condition 2014-07-03 17:17 ` [PATCH 1/2 v6] HID: gt683r: fix race condition Janne Kanniainen @ 2014-07-03 17:34 ` Johan Hovold 2014-07-03 17:34 ` Johan Hovold 1 sibling, 0 replies; 81+ messages in thread From: Johan Hovold @ 2014-07-03 17:34 UTC (permalink / raw) To: Janne Kanniainen Cc: johan, cooloney, jkosina, greg, bjorn, linux-kernel, linux-leds, linux-usb, linux-input On Thu, Jul 03, 2014 at 08:17:08PM +0300, Janne Kanniainen wrote: > This will fix race condition noticed by Oliver Neukum. Sysfs files are > created before mutex and work are initialized. > > Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> Reviewed-by: Johan Hovold <johan@kernel.org> > --- > drivers/hid/hid-gt683r.c | 6 +++--- > 1 file changed, 3 insertions(+), 3 deletions(-) > > diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c > index 077f7a1..073bd80 100644 > --- a/drivers/hid/hid-gt683r.c > +++ b/drivers/hid/hid-gt683r.c > @@ -227,6 +227,9 @@ static int gt683r_led_probe(struct hid_device *hdev, > if (!led) > return -ENOMEM; > > + mutex_init(&led->lock); > + INIT_WORK(&led->work, gt683r_led_work); > + > led->mode = GT683R_LED_NORMAL; > led->hdev = hdev; > hid_set_drvdata(hdev, led); > @@ -271,9 +274,6 @@ static int gt683r_led_probe(struct hid_device *hdev, > goto fail; > } > > - mutex_init(&led->lock); > - INIT_WORK(&led->work, gt683r_led_work); > - > return 0; > > fail: ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH 1/2 v6] HID: gt683r: fix race condition @ 2014-07-03 17:34 ` Johan Hovold 0 siblings, 0 replies; 81+ messages in thread From: Johan Hovold @ 2014-07-03 17:34 UTC (permalink / raw) To: Janne Kanniainen, cooloney Cc: johan, cooloney, jkosina, greg, bjorn, linux-kernel, linux-leds, linux-usb, linux-input On Thu, Jul 03, 2014 at 08:17:08PM +0300, Janne Kanniainen wrote: > This will fix race condition noticed by Oliver Neukum. Sysfs files are > created before mutex and work are initialized. > > Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> Reviewed-by: Johan Hovold <johan@kernel.org> > --- > drivers/hid/hid-gt683r.c | 6 +++--- > 1 file changed, 3 insertions(+), 3 deletions(-) > > diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c > index 077f7a1..073bd80 100644 > --- a/drivers/hid/hid-gt683r.c > +++ b/drivers/hid/hid-gt683r.c > @@ -227,6 +227,9 @@ static int gt683r_led_probe(struct hid_device *hdev, > if (!led) > return -ENOMEM; > > + mutex_init(&led->lock); > + INIT_WORK(&led->work, gt683r_led_work); > + > led->mode = GT683R_LED_NORMAL; > led->hdev = hdev; > hid_set_drvdata(hdev, led); > @@ -271,9 +274,6 @@ static int gt683r_led_probe(struct hid_device *hdev, > goto fail; > } > > - mutex_init(&led->lock); > - INIT_WORK(&led->work, gt683r_led_work); > - > return 0; > > fail: ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH 1/2 v6] HID: gt683r: fix race condition 2014-07-03 17:34 ` Johan Hovold (?) @ 2014-07-03 18:13 ` Bryan Wu -1 siblings, 0 replies; 81+ messages in thread From: Bryan Wu @ 2014-07-03 18:13 UTC (permalink / raw) To: Johan Hovold Cc: Janne Kanniainen, Jiri Kosina, Greg Kroah-Hartman, Bjørn Mork, lkml, Linux LED Subsystem, linux-usb, linux-input On Thu, Jul 3, 2014 at 10:34 AM, Johan Hovold <johan@kernel.org> wrote: > On Thu, Jul 03, 2014 at 08:17:08PM +0300, Janne Kanniainen wrote: >> This will fix race condition noticed by Oliver Neukum. Sysfs files are >> created before mutex and work are initialized. >> >> Signed-off-by: Janne Kanniainen <janne.kanniainen@gmail.com> > > Reviewed-by: Johan Hovold <johan@kernel.org> > Good, merged to my tree. -Bryan >> --- >> drivers/hid/hid-gt683r.c | 6 +++--- >> 1 file changed, 3 insertions(+), 3 deletions(-) >> >> diff --git a/drivers/hid/hid-gt683r.c b/drivers/hid/hid-gt683r.c >> index 077f7a1..073bd80 100644 >> --- a/drivers/hid/hid-gt683r.c >> +++ b/drivers/hid/hid-gt683r.c >> @@ -227,6 +227,9 @@ static int gt683r_led_probe(struct hid_device *hdev, >> if (!led) >> return -ENOMEM; >> >> + mutex_init(&led->lock); >> + INIT_WORK(&led->work, gt683r_led_work); >> + >> led->mode = GT683R_LED_NORMAL; >> led->hdev = hdev; >> hid_set_drvdata(hdev, led); >> @@ -271,9 +274,6 @@ static int gt683r_led_probe(struct hid_device *hdev, >> goto fail; >> } >> >> - mutex_init(&led->lock); >> - INIT_WORK(&led->work, gt683r_led_work); >> - >> return 0; >> >> fail: ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH 2/2 v2] HID: leds: Use attribute-groups in MSI GT683R driver 2014-06-25 17:41 ` Johan Hovold 2014-06-25 18:13 ` [PATCH 2/2 v3] HID: leds: move led_mode attribute to led-class devices " Janne Kanniainen @ 2014-06-25 19:09 ` Jiri Kosina 2014-06-25 22:55 ` Bryan Wu 1 sibling, 1 reply; 81+ messages in thread From: Jiri Kosina @ 2014-06-25 19:09 UTC (permalink / raw) To: Johan Hovold Cc: Janne Kanniainen, greg, bjorn, cooloney, linux-kernel, linux-leds, linux-usb, linux-input On Wed, 25 Jun 2014, Johan Hovold wrote: > Did you see the attribute-race series I posted? Not sure how best to > handle the dependency, as those patches should probably go in through > the LEDs tree, while the first patch in that series (adding the groups > field) is a dependency for this patch. > > Jiri, how would this best be solved? I think the best course of action here is to gather Acks from the respective maintainers, and take the whole lot trough a single tree (probably the leds tree in this case) to avoid unnecessary intra-tree dependencies in a rather straighforward situation like this. Thanks, -- Jiri Kosina SUSE Labs ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH 2/2 v2] HID: leds: Use attribute-groups in MSI GT683R driver 2014-06-25 19:09 ` [PATCH 2/2 v2] HID: leds: Use attribute-groups in MSI GT683R driver Jiri Kosina @ 2014-06-25 22:55 ` Bryan Wu 2014-06-30 10:47 ` Johan Hovold 0 siblings, 1 reply; 81+ messages in thread From: Bryan Wu @ 2014-06-25 22:55 UTC (permalink / raw) To: Jiri Kosina Cc: Johan Hovold, Janne Kanniainen, Greg Kroah-Hartman, Bjørn Mork, lkml, Linux LED Subsystem, linux-usb, linux-input On Wed, Jun 25, 2014 at 12:09 PM, Jiri Kosina <jkosina@suse.cz> wrote: > On Wed, 25 Jun 2014, Johan Hovold wrote: > >> Did you see the attribute-race series I posted? Not sure how best to >> handle the dependency, as those patches should probably go in through >> the LEDs tree, while the first patch in that series (adding the groups >> field) is a dependency for this patch. >> >> Jiri, how would this best be solved? > > I think the best course of action here is to gather Acks from the > respective maintainers, and take the whole lot trough a single tree > (probably the leds tree in this case) to avoid unnecessary intra-tree > dependencies in a rather straighforward situation like this. > I think the better place is HID/input tree, since this patch depends on the initial one which is not in my tree. I'm going to merge Johan's whole patchset and this patch probably depends Johan's work too. -Bryan ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH 2/2 v2] HID: leds: Use attribute-groups in MSI GT683R driver 2014-06-25 22:55 ` Bryan Wu @ 2014-06-30 10:47 ` Johan Hovold 2014-06-30 11:33 ` Jiri Kosina 0 siblings, 1 reply; 81+ messages in thread From: Johan Hovold @ 2014-06-30 10:47 UTC (permalink / raw) To: Bryan Wu Cc: Jiri Kosina, Johan Hovold, Janne Kanniainen, Greg Kroah-Hartman, Bjørn Mork, lkml, Linux LED Subsystem, linux-usb, linux-input On Wed, Jun 25, 2014 at 03:55:10PM -0700, Bryan Wu wrote: > On Wed, Jun 25, 2014 at 12:09 PM, Jiri Kosina <jkosina@suse.cz> wrote: > > On Wed, 25 Jun 2014, Johan Hovold wrote: > > > >> Did you see the attribute-race series I posted? Not sure how best to > >> handle the dependency, as those patches should probably go in through > >> the LEDs tree, while the first patch in that series (adding the groups > >> field) is a dependency for this patch. > >> > >> Jiri, how would this best be solved? > > > > I think the best course of action here is to gather Acks from the > > respective maintainers, and take the whole lot trough a single tree > > (probably the leds tree in this case) to avoid unnecessary intra-tree > > dependencies in a rather straighforward situation like this. > > I think the better place is HID/input tree, since this patch depends > on the initial one which is not in my tree. > I'm going to merge Johan's whole patchset and this patch probably > depends Johan's work too. Dmitry has ACKed the input-patch and Bryan has applied that one and the leds-patches to his tree (of which the first one is a dependency of this patch). Jiri, are you saying that the gt683r-driver should go in through his tree as well, that is all three patches including the first that you have already applied? I just assumed your for-next branch was immutable, but perhaps I was mistaken. Thanks, Johan ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH 2/2 v2] HID: leds: Use attribute-groups in MSI GT683R driver 2014-06-30 10:47 ` Johan Hovold @ 2014-06-30 11:33 ` Jiri Kosina 2014-06-30 23:17 ` Bryan Wu 0 siblings, 1 reply; 81+ messages in thread From: Jiri Kosina @ 2014-06-30 11:33 UTC (permalink / raw) To: Johan Hovold Cc: Bryan Wu, Janne Kanniainen, Greg Kroah-Hartman, Bjørn Mork, lkml, Linux LED Subsystem, linux-usb, linux-input On Mon, 30 Jun 2014, Johan Hovold wrote: > > I think the better place is HID/input tree, since this patch depends > > on the initial one which is not in my tree. > > I'm going to merge Johan's whole patchset and this patch probably > > depends Johan's work too. > > Dmitry has ACKed the input-patch and Bryan has applied that one and the > leds-patches to his tree (of which the first one is a dependency of this > patch). > > Jiri, are you saying that the gt683r-driver should go in through his > tree as well, that is all three patches including the first that you > have already applied? I just assumed your for-next branch was immutable, > but perhaps I was mistaken. Well, for-next branch is a collection of all the topic branches I am queuing for the following merge window. I am never really rebasing it, but I can definitely not include 'for-3.17/hid-gt683r' topic branch in the pile I will be sending to Linus (all the scheduled branches are getting merged into 'for-linus' only when merge window open). So the only potential conflict between hid.git and Bryan's tree would be in linux-next (and probably there will be none, git can handle duplicate patches nicely). So once Bryan confirms he's queued it (please preserve my Signoff from my tree), then I will just not include for-3.17/hid-gt683r branch in pull request to Linus and all is fine. Thanks, -- Jiri Kosina SUSE Labs ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH 2/2 v2] HID: leds: Use attribute-groups in MSI GT683R driver 2014-06-30 11:33 ` Jiri Kosina @ 2014-06-30 23:17 ` Bryan Wu 2014-07-01 8:48 ` Johan Hovold 0 siblings, 1 reply; 81+ messages in thread From: Bryan Wu @ 2014-06-30 23:17 UTC (permalink / raw) To: Jiri Kosina Cc: Johan Hovold, Janne Kanniainen, Greg Kroah-Hartman, Bjørn Mork, lkml, Linux LED Subsystem, linux-usb, linux-input On Mon, Jun 30, 2014 at 4:33 AM, Jiri Kosina <jkosina@suse.cz> wrote: > On Mon, 30 Jun 2014, Johan Hovold wrote: > >> > I think the better place is HID/input tree, since this patch depends >> > on the initial one which is not in my tree. >> > I'm going to merge Johan's whole patchset and this patch probably >> > depends Johan's work too. >> >> Dmitry has ACKed the input-patch and Bryan has applied that one and the >> leds-patches to his tree (of which the first one is a dependency of this >> patch). >> >> Jiri, are you saying that the gt683r-driver should go in through his >> tree as well, that is all three patches including the first that you >> have already applied? I just assumed your for-next branch was immutable, >> but perhaps I was mistaken. > > Well, for-next branch is a collection of all the topic branches I am > queuing for the following merge window. > > I am never really rebasing it, but I can definitely not include > 'for-3.17/hid-gt683r' topic branch in the pile I will be sending to Linus > (all the scheduled branches are getting merged into 'for-linus' only when > merge window open). So the only potential conflict between hid.git and > Bryan's tree would be in linux-next (and probably there will be none, git > can handle duplicate patches nicely). > > So once Bryan confirms he's queued it (please preserve my Signoff from my > tree), then I will just not include for-3.17/hid-gt683r branch in pull > request to Linus and all is fine. > I'm OK to merge Janne's first patch for HID GT683R through my tree with you guys' SOB. I'm also OK to merge this incremental patchset here. Please confirm it if I didn't misunderstand here. Also Janne or someone, can you post the original first patch to me or point me where is it? Thanks, -Bryan ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH 2/2 v2] HID: leds: Use attribute-groups in MSI GT683R driver 2014-06-30 23:17 ` Bryan Wu @ 2014-07-01 8:48 ` Johan Hovold 2014-07-01 15:48 ` Bryan Wu 0 siblings, 1 reply; 81+ messages in thread From: Johan Hovold @ 2014-07-01 8:48 UTC (permalink / raw) To: Bryan Wu Cc: Jiri Kosina, Johan Hovold, Janne Kanniainen, Greg Kroah-Hartman, Bjørn Mork, lkml, Linux LED Subsystem, linux-usb, linux-input On Mon, Jun 30, 2014 at 04:17:10PM -0700, Bryan Wu wrote: > On Mon, Jun 30, 2014 at 4:33 AM, Jiri Kosina <jkosina@suse.cz> wrote: > > On Mon, 30 Jun 2014, Johan Hovold wrote: > > > >> > I think the better place is HID/input tree, since this patch depends > >> > on the initial one which is not in my tree. > >> > I'm going to merge Johan's whole patchset and this patch probably > >> > depends Johan's work too. > >> > >> Dmitry has ACKed the input-patch and Bryan has applied that one and the > >> leds-patches to his tree (of which the first one is a dependency of this > >> patch). > >> > >> Jiri, are you saying that the gt683r-driver should go in through his > >> tree as well, that is all three patches including the first that you > >> have already applied? I just assumed your for-next branch was immutable, > >> but perhaps I was mistaken. > > > > Well, for-next branch is a collection of all the topic branches I am > > queuing for the following merge window. > > > > I am never really rebasing it, but I can definitely not include > > 'for-3.17/hid-gt683r' topic branch in the pile I will be sending to Linus > > (all the scheduled branches are getting merged into 'for-linus' only when > > merge window open). So the only potential conflict between hid.git and > > Bryan's tree would be in linux-next (and probably there will be none, git > > can handle duplicate patches nicely). > > > > So once Bryan confirms he's queued it (please preserve my Signoff from my > > tree), then I will just not include for-3.17/hid-gt683r branch in pull > > request to Linus and all is fine. > > > > I'm OK to merge Janne's first patch for HID GT683R through my tree > with you guys' SOB. > I'm also OK to merge this incremental patchset here. Please confirm it > if I didn't misunderstand here. That's correct. But the incremental patch set might need one more spin before it is ready to be applied. > Also Janne or someone, can you post the original first patch to me or > point me where is it? You could cherry-pick it from Jiri's for-3.17/hid-gt683r branch at git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid.git commit 4e3ed79670e0 ("HID: add support for MSI GT683R led panels"). Otherwise, the patch is here: http://marc.info/?l=linux-usb&m=140310755911256&w=2 Thanks, Johan ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH 2/2 v2] HID: leds: Use attribute-groups in MSI GT683R driver 2014-07-01 8:48 ` Johan Hovold @ 2014-07-01 15:48 ` Bryan Wu 2014-07-01 17:53 ` Janne Kanniainen 2014-07-02 8:56 ` Jiri Kosina 0 siblings, 2 replies; 81+ messages in thread From: Bryan Wu @ 2014-07-01 15:48 UTC (permalink / raw) To: Johan Hovold Cc: Jiri Kosina, Janne Kanniainen, Greg Kroah-Hartman, Bjørn Mork, lkml, Linux LED Subsystem, linux-usb, linux-input On Tue, Jul 1, 2014 at 1:48 AM, Johan Hovold <johan@kernel.org> wrote: > On Mon, Jun 30, 2014 at 04:17:10PM -0700, Bryan Wu wrote: >> On Mon, Jun 30, 2014 at 4:33 AM, Jiri Kosina <jkosina@suse.cz> wrote: >> > On Mon, 30 Jun 2014, Johan Hovold wrote: >> > >> >> > I think the better place is HID/input tree, since this patch depends >> >> > on the initial one which is not in my tree. >> >> > I'm going to merge Johan's whole patchset and this patch probably >> >> > depends Johan's work too. >> >> >> >> Dmitry has ACKed the input-patch and Bryan has applied that one and the >> >> leds-patches to his tree (of which the first one is a dependency of this >> >> patch). >> >> >> >> Jiri, are you saying that the gt683r-driver should go in through his >> >> tree as well, that is all three patches including the first that you >> >> have already applied? I just assumed your for-next branch was immutable, >> >> but perhaps I was mistaken. >> > >> > Well, for-next branch is a collection of all the topic branches I am >> > queuing for the following merge window. >> > >> > I am never really rebasing it, but I can definitely not include >> > 'for-3.17/hid-gt683r' topic branch in the pile I will be sending to Linus >> > (all the scheduled branches are getting merged into 'for-linus' only when >> > merge window open). So the only potential conflict between hid.git and >> > Bryan's tree would be in linux-next (and probably there will be none, git >> > can handle duplicate patches nicely). >> > >> > So once Bryan confirms he's queued it (please preserve my Signoff from my >> > tree), then I will just not include for-3.17/hid-gt683r branch in pull >> > request to Linus and all is fine. >> > >> >> I'm OK to merge Janne's first patch for HID GT683R through my tree >> with you guys' SOB. >> I'm also OK to merge this incremental patchset here. Please confirm it >> if I didn't misunderstand here. > > That's correct. But the incremental patch set might need one more spin > before it is ready to be applied. > >> Also Janne or someone, can you post the original first patch to me or >> point me where is it? > > You could cherry-pick it from Jiri's for-3.17/hid-gt683r branch at > > git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid.git > > commit 4e3ed79670e0 ("HID: add support for MSI GT683R led panels"). > > Otherwise, the patch is here: > > http://marc.info/?l=linux-usb&m=140310755911256&w=2 > Great, I just cherry-picked and applied to my tree http://git.kernel.org/cgit/linux/kernel/git/cooloney/linux-leds.git/commit/?h=for-next&id=f471d9480275796dea2ac7ec249b050e70a2888d Thanks, -Bryan ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH 2/2 v2] HID: leds: Use attribute-groups in MSI GT683R driver 2014-07-01 15:48 ` Bryan Wu @ 2014-07-01 17:53 ` Janne Kanniainen 2014-07-02 8:56 ` Jiri Kosina 1 sibling, 0 replies; 81+ messages in thread From: Janne Kanniainen @ 2014-07-01 17:53 UTC (permalink / raw) To: Bryan Wu Cc: Johan Hovold, Jiri Kosina, Greg Kroah-Hartman, Bjørn Mork, lkml, Linux LED Subsystem, linux-usb, linux-input > Great, I just cherry-picked and applied to my tree > http://git.kernel.org/cgit/linux/kernel/git/cooloney/linux-leds.git/commit/?h=for-next&id=f471d9480275796dea2ac7ec249b050e70a2888d > > Thanks, > -Bryan Ok, thank you! Janne ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH 2/2 v2] HID: leds: Use attribute-groups in MSI GT683R driver 2014-07-01 15:48 ` Bryan Wu 2014-07-01 17:53 ` Janne Kanniainen @ 2014-07-02 8:56 ` Jiri Kosina 1 sibling, 0 replies; 81+ messages in thread From: Jiri Kosina @ 2014-07-02 8:56 UTC (permalink / raw) To: Bryan Wu Cc: Johan Hovold, Janne Kanniainen, Greg Kroah-Hartman, Bjørn Mork, lkml, Linux LED Subsystem, linux-usb, linux-input On Tue, 1 Jul 2014, Bryan Wu wrote: > Great, I just cherry-picked and applied to my tree > http://git.kernel.org/cgit/linux/kernel/git/cooloney/linux-leds.git/commit/?h=for-next&id=f471d9480275796dea2ac7ec249b050e70a2888d Ok, perfect, thanks. I am marking my 'for-3.17/hid-gt683r' so that it wouldn't be contained in the for-linus merge window pile. -- Jiri Kosina SUSE Labs ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v9] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-23 14:42 ` Johan Hovold 2014-06-23 16:17 ` Greg KH @ 2014-06-23 16:20 ` Janne Kanniainen 1 sibling, 0 replies; 81+ messages in thread From: Janne Kanniainen @ 2014-06-23 16:20 UTC (permalink / raw) To: Johan Hovold Cc: Oliver Neukum, Jiri Kosina, Bryan Wu, linux-kernel, linux-leds, linux-usb, linux-input >> Sorry for noticing this thread late. No problem. Good that you noticed it now! Thank you. > Just move the initialisation of the lock and work to the other private > data initialisations directly after it's allocated. > > Can you send a follow up patch, Janne? Yes I can. Just a moment. Janne ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v5] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-12 20:34 ` [PATCH v5] " Janne Kanniainen 2014-06-13 7:54 ` Johan Hovold @ 2014-06-14 22:42 ` Pavel Machek 2014-06-14 23:23 ` Janne Kanniainen 1 sibling, 1 reply; 81+ messages in thread From: Pavel Machek @ 2014-06-14 22:42 UTC (permalink / raw) To: Janne Kanniainen Cc: jkosina, johan, cooloney, linux-kernel, linux-leds, linux-usb, linux-input On Thu 2014-06-12 23:34:12, Janne Kanniainen wrote: > This driver adds support for USB controlled led panels that exists in > MSI GT683R laptop Hi! > --- /dev/null > +++ b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > @@ -0,0 +1,10 @@ > +What: /sys/class/hidraw/<hidraw>/device/state > +Date: Jun 2014 > +KernelVersion: 3.15 > +Contact: Janne Kanniainen <janne.kanniainen@gmail.com> > +Description: > + Set the mode of LEDs > + > + 0 - normal > + 1 - audio > + 2 - breathing THat's some strange interface. Don't we normally use led triggers for this? And the mode of the LED should really be in /sys/class/leds, not in hidraw somewhere... Pavel -- (english) http://www.livejournal.com/~pavelmachek (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v5] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-14 22:42 ` [PATCH v5] " Pavel Machek @ 2014-06-14 23:23 ` Janne Kanniainen 2014-06-16 7:45 ` Johan Hovold 0 siblings, 1 reply; 81+ messages in thread From: Janne Kanniainen @ 2014-06-14 23:23 UTC (permalink / raw) To: Pavel Machek Cc: Jiri Kosina, Johan Hovold, Bryan Wu, linux-kernel, linux-leds, linux-usb, linux-input > Hi! Hi. >> --- /dev/null >> +++ b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r >> @@ -0,0 +1,10 @@ >> +What: /sys/class/hidraw/<hidraw>/device/state >> +Date: Jun 2014 >> +KernelVersion: 3.15 >> +Contact: Janne Kanniainen <janne.kanniainen@gmail.com> >> +Description: >> + Set the mode of LEDs >> + >> + 0 - normal >> + 1 - audio >> + 2 - breathing > > THat's some strange interface. Don't we normally use led triggers for this? I can implement it that way, if you all think that it is correct way. What do Jiri and Johan thinks of it? > And the mode of the LED should really be in /sys/class/leds, not in hidraw somewhere... The problem is that all panels can only be in one mode at the time. For example front panel can't be in breathing mode while side panel is in normal mode. Janne ^ permalink raw reply [flat|nested] 81+ messages in thread
* Re: [PATCH v5] leds: USB: HID: Add support for MSI GT683R led panels 2014-06-14 23:23 ` Janne Kanniainen @ 2014-06-16 7:45 ` Johan Hovold 0 siblings, 0 replies; 81+ messages in thread From: Johan Hovold @ 2014-06-16 7:45 UTC (permalink / raw) To: Janne Kanniainen Cc: Pavel Machek, Jiri Kosina, Johan Hovold, Bryan Wu, linux-kernel, linux-leds, linux-usb, linux-input On Sun, Jun 15, 2014 at 02:23:25AM +0300, Janne Kanniainen wrote: > > Hi! > > Hi. > > >> --- /dev/null > >> +++ b/Documentation/ABI/testing/sysfs-class-hid-driver-gt683r > >> @@ -0,0 +1,10 @@ > >> +What: /sys/class/hidraw/<hidraw>/device/state > >> +Date: Jun 2014 > >> +KernelVersion: 3.15 > >> +Contact: Janne Kanniainen <janne.kanniainen@gmail.com> > >> +Description: > >> + Set the mode of LEDs > >> + > >> + 0 - normal > >> + 1 - audio > >> + 2 - breathing > > > > THat's some strange interface. Don't we normally use led triggers > > for this? > > I can implement it that way, if you all think that it is correct way. > What do Jiri and Johan thinks of it? > > > And the mode of the LED should really be in /sys/class/leds, not in > > hidraw somewhere... > > The problem is that all panels can only be in one mode at the time. > For example front panel can't be in breathing mode while side panel is > in normal mode. As Janne explained above, it's really an attribute of the parent device and not the individual LEDs. The latter could still use the software timer trigger to blink independently. Johan ^ permalink raw reply [flat|nested] 81+ messages in thread
end of thread, other threads:[~2014-07-03 18:28 UTC | newest] Thread overview: 81+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2014-06-05 21:29 [PATCH v2] leds: USB: Add support for MSI GT683R led panels Janne Kanniainen 2014-06-06 9:47 ` Johan Hovold 2014-06-07 10:12 ` Janne Kanniainen 2014-06-09 11:42 ` Johan Hovold 2014-06-10 21:10 ` Janne Kanniainen 2014-06-10 21:21 ` [PATCH v3] leds: USB: HID: " Janne Kanniainen 2014-06-11 11:25 ` Jiri Kosina 2014-06-11 14:06 ` Johan Hovold [not found] ` <1402435299-16410-1-git-send-email-janne.kanniainen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2014-06-11 14:05 ` Johan Hovold 2014-06-11 14:05 ` Johan Hovold 2014-06-11 15:30 ` Johan Hovold 2014-06-11 17:34 ` Johan Hovold 2014-06-11 22:48 ` [PATCH v4] " Janne Kanniainen 2014-06-12 9:06 ` Johan Hovold 2014-06-12 20:34 ` [PATCH v5] " Janne Kanniainen 2014-06-13 7:54 ` Johan Hovold 2014-06-13 17:19 ` Janne Kanniainen 2014-06-15 14:59 ` Janne Kanniainen 2014-06-16 7:39 ` Johan Hovold 2014-06-16 17:23 ` [PATCH v6] " Janne Kanniainen 2014-06-16 22:01 ` Janne Kanniainen 2014-06-17 13:46 ` Johan Hovold 2014-06-17 16:41 ` [PATCH v8] " Janne Kanniainen [not found] ` <1403023304-7953-1-git-send-email-janne.kanniainen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2014-06-18 7:39 ` Johan Hovold 2014-06-18 7:39 ` Johan Hovold 2014-06-18 16:05 ` [PATCH v9] " Janne Kanniainen [not found] ` <1403107502-14106-1-git-send-email-janne.kanniainen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2014-06-18 16:11 ` Johan Hovold 2014-06-18 16:11 ` Johan Hovold 2014-06-18 18:41 ` Janne Kanniainen 2014-06-18 18:46 ` Johan Hovold 2014-06-18 22:10 ` Jiri Kosina 2014-06-23 14:35 ` Oliver Neukum 2014-06-23 14:42 ` Johan Hovold 2014-06-23 16:17 ` Greg KH 2014-06-23 17:16 ` [PATCH v10] " Janne Kanniainen 2014-06-23 17:27 ` Johan Hovold [not found] ` <1403543808-8228-1-git-send-email-janne.kanniainen-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> 2014-06-23 18:23 ` Greg KH 2014-06-23 18:23 ` Greg KH 2014-06-23 18:24 ` Greg KH 2014-06-23 19:31 ` Johan Hovold 2014-06-23 19:40 ` Greg KH 2014-06-23 19:52 ` Johan Hovold 2014-06-23 20:24 ` Greg KH 2014-06-23 20:44 ` Johan Hovold 2014-06-24 13:10 ` Bjørn Mork 2014-06-24 13:10 ` Bjørn Mork 2014-06-24 14:50 ` Johan Hovold 2014-06-24 19:38 ` [PATCH 1/2] HID: leds: fix race condition in MSI GT683R driver Janne Kanniainen 2014-06-24 19:38 ` [PATCH 2/2] HID: leds: move led_mode attribute to led-class devices " Janne Kanniainen 2014-06-24 19:56 ` Greg KH 2014-06-25 11:55 ` Johan Hovold 2014-06-25 15:59 ` [PATCH 2/2 v2] HID: leds: Use attribute-groups " Janne Kanniainen 2014-06-25 17:41 ` Johan Hovold 2014-06-25 18:13 ` [PATCH 2/2 v3] HID: leds: move led_mode attribute to led-class devices " Janne Kanniainen 2014-06-30 10:39 ` Johan Hovold 2014-07-01 17:50 ` [PATCH 2/2 v4] " Janne Kanniainen 2014-07-01 20:16 ` Johan Hovold 2014-07-02 17:37 ` [PATCH 2/2 v5] " Janne Kanniainen 2014-07-03 8:28 ` Johan Hovold 2014-07-03 17:17 ` [PATCH 1/2 v6] HID: gt683r: fix race condition Janne Kanniainen 2014-07-03 17:17 ` [PATCH 2/2 v6] HID: gt683r: move mode attribute to led-class devices Janne Kanniainen 2014-07-03 17:40 ` Johan Hovold 2014-07-03 17:40 ` Johan Hovold 2014-07-03 18:17 ` Bryan Wu 2014-07-03 18:28 ` Janne Kanniainen 2014-07-03 17:34 ` [PATCH 1/2 v6] HID: gt683r: fix race condition Johan Hovold 2014-07-03 17:34 ` Johan Hovold 2014-07-03 18:13 ` Bryan Wu 2014-06-25 19:09 ` [PATCH 2/2 v2] HID: leds: Use attribute-groups in MSI GT683R driver Jiri Kosina 2014-06-25 22:55 ` Bryan Wu 2014-06-30 10:47 ` Johan Hovold 2014-06-30 11:33 ` Jiri Kosina 2014-06-30 23:17 ` Bryan Wu 2014-07-01 8:48 ` Johan Hovold 2014-07-01 15:48 ` Bryan Wu 2014-07-01 17:53 ` Janne Kanniainen 2014-07-02 8:56 ` Jiri Kosina 2014-06-23 16:20 ` [PATCH v9] leds: USB: HID: Add support for MSI GT683R led panels Janne Kanniainen 2014-06-14 22:42 ` [PATCH v5] " Pavel Machek 2014-06-14 23:23 ` Janne Kanniainen 2014-06-16 7:45 ` Johan Hovold
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.