aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/Kconfig6
-rw-r--r--drivers/hid/hid-picolcd.c163
2 files changed, 166 insertions, 3 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 399edc53963e..34f6593ea3b6 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -278,11 +278,11 @@ config HID_PICOLCD
278 - Keypad 278 - Keypad
279 - Switching between Firmware and Flash mode 279 - Switching between Firmware and Flash mode
280 - Framebuffer for monochrome 256x64 display 280 - Framebuffer for monochrome 256x64 display
281 - Backlight control (needs CONFIG_BACKLIGHT_CLASS_DEVICE) 281 - Backlight control (needs CONFIG_BACKLIGHT_CLASS_DEVICE)
282 - Contrast control (needs CONFIG_LCD_CLASS_DEVICE) 282 - Contrast control (needs CONFIG_LCD_CLASS_DEVICE)
283 - General purpose outputs (needs CONFIG_LEDS_CLASS)
283 Features that are not (yet) supported: 284 Features that are not (yet) supported:
284 - IR 285 - IR
285 - General purpose outputs
286 - EEProm / Flash access 286 - EEProm / Flash access
287 287
288config HID_QUANTA 288config HID_QUANTA
diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c
index 99a488363a4e..517677305ef9 100644
--- a/drivers/hid/hid-picolcd.c
+++ b/drivers/hid/hid-picolcd.c
@@ -29,6 +29,8 @@
29#include <linux/backlight.h> 29#include <linux/backlight.h>
30#include <linux/lcd.h> 30#include <linux/lcd.h>
31 31
32#include <linux/leds.h>
33
32#include <linux/seq_file.h> 34#include <linux/seq_file.h>
33#include <linux/debugfs.h> 35#include <linux/debugfs.h>
34 36
@@ -194,6 +196,11 @@ struct picolcd_data {
194 u8 lcd_brightness; 196 u8 lcd_brightness;
195 u8 lcd_power; 197 u8 lcd_power;
196#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */ 198#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */
199#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
200 /* LED stuff */
201 u8 led_state;
202 struct led_classdev *led[8];
203#endif /* CONFIG_LEDS_CLASS */
197 204
198 /* Housekeeping stuff */ 205 /* Housekeeping stuff */
199 spinlock_t lock; 206 spinlock_t lock;
@@ -947,6 +954,153 @@ static inline int picolcd_resume_lcd(struct picolcd_data *data)
947} 954}
948#endif /* CONFIG_LCD_CLASS_DEVICE */ 955#endif /* CONFIG_LCD_CLASS_DEVICE */
949 956
957#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
958/**
959 * LED class device
960 */
961static void picolcd_leds_set(struct picolcd_data *data)
962{
963 struct hid_report *report;
964 unsigned long flags;
965
966 if (!data->led[0])
967 return;
968 report = picolcd_out_report(REPORT_LED_STATE, data->hdev);
969 if (!report || report->maxfield != 1 || report->field[0]->report_count != 1)
970 return;
971
972 spin_lock_irqsave(&data->lock, flags);
973 hid_set_field(report->field[0], 0, data->led_state);
974 usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
975 spin_unlock_irqrestore(&data->lock, flags);
976}
977
978static void picolcd_led_set_brightness(struct led_classdev *led_cdev,
979 enum led_brightness value)
980{
981 struct device *dev;
982 struct hid_device *hdev;
983 struct picolcd_data *data;
984 int i, state = 0;
985
986 dev = led_cdev->dev->parent;
987 hdev = container_of(dev, struct hid_device, dev);
988 data = hid_get_drvdata(hdev);
989 for (i = 0; i < 8; i++) {
990 if (led_cdev != data->led[i])
991 continue;
992 state = (data->led_state >> i) & 1;
993 if (value == LED_OFF && state) {
994 data->led_state &= ~(1 << i);
995 picolcd_leds_set(data);
996 } else if (value != LED_OFF && !state) {
997 data->led_state |= 1 << i;
998 picolcd_leds_set(data);
999 }
1000 break;
1001 }
1002}
1003
1004static enum led_brightness picolcd_led_get_brightness(struct led_classdev *led_cdev)
1005{
1006 struct device *dev;
1007 struct hid_device *hdev;
1008 struct picolcd_data *data;
1009 int i, value = 0;
1010
1011 dev = led_cdev->dev->parent;
1012 hdev = container_of(dev, struct hid_device, dev);
1013 data = hid_get_drvdata(hdev);
1014 for (i = 0; i < 8; i++)
1015 if (led_cdev == data->led[i]) {
1016 value = (data->led_state >> i) & 1;
1017 break;
1018 }
1019 return value ? LED_FULL : LED_OFF;
1020}
1021
1022static int picolcd_init_leds(struct picolcd_data *data, struct hid_report *report)
1023{
1024 struct device *dev = &data->hdev->dev;
1025 struct led_classdev *led;
1026 size_t name_sz = strlen(dev_name(dev)) + 8;
1027 char *name;
1028 int i, ret = 0;
1029
1030 if (!report)
1031 return -ENODEV;
1032 if (report->maxfield != 1 || report->field[0]->report_count != 1 ||
1033 report->field[0]->report_size != 8) {
1034 dev_err(dev, "unsupported LED_STATE report");
1035 return -EINVAL;
1036 }
1037
1038 for (i = 0; i < 8; i++) {
1039 led = kzalloc(sizeof(struct led_classdev)+name_sz, GFP_KERNEL);
1040 if (!led) {
1041 dev_err(dev, "can't allocate memory for LED %d\n", i);
1042 ret = -ENOMEM;
1043 goto err;
1044 }
1045 name = (void *)(&led[1]);
1046 snprintf(name, name_sz, "%s::GPO%d", dev_name(dev), i);
1047 led->name = name;
1048 led->brightness = 0;
1049 led->max_brightness = 1;
1050 led->brightness_get = picolcd_led_get_brightness;
1051 led->brightness_set = picolcd_led_set_brightness;
1052
1053 data->led[i] = led;
1054 ret = led_classdev_register(dev, data->led[i]);
1055 if (ret) {
1056 data->led[i] = NULL;
1057 kfree(led);
1058 dev_err(dev, "can't register LED %d\n", i);
1059 goto err;
1060 }
1061 }
1062 return 0;
1063err:
1064 for (i = 0; i < 8; i++)
1065 if (data->led[i]) {
1066 led = data->led[i];
1067 data->led[i] = NULL;
1068 led_classdev_unregister(led);
1069 kfree(led);
1070 }
1071 return ret;
1072}
1073
1074static void picolcd_exit_leds(struct picolcd_data *data)
1075{
1076 struct led_classdev *led;
1077 int i;
1078
1079 for (i = 0; i < 8; i++) {
1080 led = data->led[i];
1081 data->led[i] = NULL;
1082 if (!led)
1083 continue;
1084 led_classdev_unregister(led);
1085 kfree(led);
1086 }
1087}
1088
1089#else
1090static inline int picolcd_init_leds(struct picolcd_data *data,
1091 struct hid_report *report)
1092{
1093 return 0;
1094}
1095static void picolcd_exit_leds(struct picolcd_data *data)
1096{
1097}
1098static inline int picolcd_leds_set(struct picolcd_data *data)
1099{
1100 return 0;
1101}
1102#endif /* CONFIG_LEDS_CLASS */
1103
950/* 1104/*
951 * input class device 1105 * input class device
952 */ 1106 */
@@ -1089,6 +1243,7 @@ static int picolcd_reset(struct hid_device *hdev)
1089 schedule_delayed_work(&data->fb_info->deferred_work, 0); 1243 schedule_delayed_work(&data->fb_info->deferred_work, 0);
1090#endif /* CONFIG_FB */ 1244#endif /* CONFIG_FB */
1091 1245
1246 picolcd_leds_set(data);
1092 return 0; 1247 return 0;
1093} 1248}
1094 1249
@@ -1782,6 +1937,11 @@ static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data)
1782 if (error) 1937 if (error)
1783 goto err; 1938 goto err;
1784 1939
1940 /* Setup the LED class devices */
1941 error = picolcd_init_leds(data, picolcd_out_report(REPORT_LED_STATE, hdev));
1942 if (error)
1943 goto err;
1944
1785#ifdef CONFIG_DEBUG_FS 1945#ifdef CONFIG_DEBUG_FS
1786 report = picolcd_out_report(REPORT_READ_MEMORY, hdev); 1946 report = picolcd_out_report(REPORT_READ_MEMORY, hdev);
1787 if (report && report->maxfield == 1 && report->field[0]->report_size == 8) 1947 if (report && report->maxfield == 1 && report->field[0]->report_size == 8)
@@ -1791,6 +1951,7 @@ static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data)
1791#endif 1951#endif
1792 return 0; 1952 return 0;
1793err: 1953err:
1954 picolcd_exit_leds(data);
1794 picolcd_exit_backlight(data); 1955 picolcd_exit_backlight(data);
1795 picolcd_exit_lcd(data); 1956 picolcd_exit_lcd(data);
1796 picolcd_exit_framebuffer(data); 1957 picolcd_exit_framebuffer(data);
@@ -1923,6 +2084,8 @@ static void picolcd_remove(struct hid_device *hdev)
1923 complete(&data->pending->ready); 2084 complete(&data->pending->ready);
1924 spin_unlock_irqrestore(&data->lock, flags); 2085 spin_unlock_irqrestore(&data->lock, flags);
1925 2086
2087 /* Cleanup LED */
2088 picolcd_exit_leds(data);
1926 /* Clean up the framebuffer */ 2089 /* Clean up the framebuffer */
1927 picolcd_exit_backlight(data); 2090 picolcd_exit_backlight(data);
1928 picolcd_exit_lcd(data); 2091 picolcd_exit_lcd(data);