Version:  2.0.40 2.2.26 2.4.37 2.6.39 3.0 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 3.12 3.13 3.14 3.15

Linux/drivers/hid/hid-thingm.c

  1 /*
  2  * ThingM blink(1) USB RGB LED driver
  3  *
  4  * Copyright 2013 Savoir-faire Linux Inc.
  5  *      Vivien Didelot <vivien.didelot@savoirfairelinux.com>
  6  *
  7  * This program is free software; you can redistribute it and/or
  8  * modify it under the terms of the GNU General Public License as
  9  * published by the Free Software Foundation, version 2.
 10  */
 11 
 12 #include <linux/hid.h>
 13 #include <linux/leds.h>
 14 #include <linux/module.h>
 15 
 16 #include "hid-ids.h"
 17 
 18 #define BLINK1_CMD_SIZE         9
 19 
 20 #define blink1_rgb_to_r(rgb)    ((rgb & 0xFF0000) >> 16)
 21 #define blink1_rgb_to_g(rgb)    ((rgb & 0x00FF00) >> 8)
 22 #define blink1_rgb_to_b(rgb)    ((rgb & 0x0000FF) >> 0)
 23 
 24 /**
 25  * struct blink1_data - blink(1) device specific data
 26  * @hdev:               HID device.
 27  * @led_cdev:           LED class instance.
 28  * @rgb:                8-bit per channel RGB notation.
 29  * @fade:               fade time in hundredths of a second.
 30  * @brightness:         brightness coefficient.
 31  * @play:               play/pause in-memory patterns.
 32  */
 33 struct blink1_data {
 34         struct hid_device *hdev;
 35         struct led_classdev led_cdev;
 36         u32 rgb;
 37         u16 fade;
 38         u8 brightness;
 39         bool play;
 40 };
 41 
 42 static int blink1_send_command(struct blink1_data *data,
 43                 u8 buf[BLINK1_CMD_SIZE])
 44 {
 45         int ret;
 46 
 47         hid_dbg(data->hdev, "command: %d%c%.2x%.2x%.2x%.2x%.2x%.2x%.2x\n",
 48                         buf[0], buf[1], buf[2], buf[3], buf[4],
 49                         buf[5], buf[6], buf[7], buf[8]);
 50 
 51         ret = hid_hw_raw_request(data->hdev, buf[0], buf, BLINK1_CMD_SIZE,
 52                                  HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
 53 
 54         return ret < 0 ? ret : 0;
 55 }
 56 
 57 static int blink1_update_color(struct blink1_data *data)
 58 {
 59         u8 buf[BLINK1_CMD_SIZE] = { 1, 'n', 0, 0, 0, 0, 0, 0, 0 };
 60 
 61         if (data->brightness) {
 62                 unsigned int coef = DIV_ROUND_CLOSEST(255, data->brightness);
 63 
 64                 buf[2] = DIV_ROUND_CLOSEST(blink1_rgb_to_r(data->rgb), coef);
 65                 buf[3] = DIV_ROUND_CLOSEST(blink1_rgb_to_g(data->rgb), coef);
 66                 buf[4] = DIV_ROUND_CLOSEST(blink1_rgb_to_b(data->rgb), coef);
 67         }
 68 
 69         if (data->fade) {
 70                 buf[1] = 'c';
 71                 buf[5] = (data->fade & 0xFF00) >> 8;
 72                 buf[6] = (data->fade & 0x00FF);
 73         }
 74 
 75         return blink1_send_command(data, buf);
 76 }
 77 
 78 static void blink1_led_set(struct led_classdev *led_cdev,
 79                 enum led_brightness brightness)
 80 {
 81         struct blink1_data *data = dev_get_drvdata(led_cdev->dev->parent);
 82 
 83         data->brightness = brightness;
 84         if (blink1_update_color(data))
 85                 hid_err(data->hdev, "failed to update color\n");
 86 }
 87 
 88 static enum led_brightness blink1_led_get(struct led_classdev *led_cdev)
 89 {
 90         struct blink1_data *data = dev_get_drvdata(led_cdev->dev->parent);
 91 
 92         return data->brightness;
 93 }
 94 
 95 static ssize_t blink1_show_rgb(struct device *dev,
 96                 struct device_attribute *attr, char *buf)
 97 {
 98         struct blink1_data *data = dev_get_drvdata(dev->parent);
 99 
100         return sprintf(buf, "%.6X\n", data->rgb);
101 }
102 
103 static ssize_t blink1_store_rgb(struct device *dev,
104                 struct device_attribute *attr, const char *buf, size_t count)
105 {
106         struct blink1_data *data = dev_get_drvdata(dev->parent);
107         long unsigned int rgb;
108         int ret;
109 
110         ret = kstrtoul(buf, 16, &rgb);
111         if (ret)
112                 return ret;
113 
114         /* RGB triplet notation is 24-bit hexadecimal */
115         if (rgb > 0xFFFFFF)
116                 return -EINVAL;
117 
118         data->rgb = rgb;
119         ret = blink1_update_color(data);
120 
121         return ret ? ret : count;
122 }
123 
124 static DEVICE_ATTR(rgb, S_IRUGO | S_IWUSR, blink1_show_rgb, blink1_store_rgb);
125 
126 static ssize_t blink1_show_fade(struct device *dev,
127                 struct device_attribute *attr, char *buf)
128 {
129         struct blink1_data *data = dev_get_drvdata(dev->parent);
130 
131         return sprintf(buf, "%d\n", data->fade * 10);
132 }
133 
134 static ssize_t blink1_store_fade(struct device *dev,
135                 struct device_attribute *attr, const char *buf, size_t count)
136 {
137         struct blink1_data *data = dev_get_drvdata(dev->parent);
138         long unsigned int fade;
139         int ret;
140 
141         ret = kstrtoul(buf, 10, &fade);
142         if (ret)
143                 return ret;
144 
145         /* blink(1) accepts 16-bit fade time, number of 10ms ticks */
146         fade = DIV_ROUND_CLOSEST(fade, 10);
147         if (fade > 65535)
148                 return -EINVAL;
149 
150         data->fade = fade;
151 
152         return count;
153 }
154 
155 static DEVICE_ATTR(fade, S_IRUGO | S_IWUSR,
156                 blink1_show_fade, blink1_store_fade);
157 
158 static ssize_t blink1_show_play(struct device *dev,
159                 struct device_attribute *attr, char *buf)
160 {
161         struct blink1_data *data = dev_get_drvdata(dev->parent);
162 
163         return sprintf(buf, "%d\n", data->play);
164 }
165 
166 static ssize_t blink1_store_play(struct device *dev,
167                 struct device_attribute *attr, const char *buf, size_t count)
168 {
169         struct blink1_data *data = dev_get_drvdata(dev->parent);
170         u8 cmd[BLINK1_CMD_SIZE] = { 1, 'p', 0, 0, 0, 0, 0, 0, 0 };
171         long unsigned int play;
172         int ret;
173 
174         ret = kstrtoul(buf, 10, &play);
175         if (ret)
176                 return ret;
177 
178         data->play = !!play;
179         cmd[2] = data->play;
180         ret = blink1_send_command(data, cmd);
181 
182         return ret ? ret : count;
183 }
184 
185 static DEVICE_ATTR(play, S_IRUGO | S_IWUSR,
186                 blink1_show_play, blink1_store_play);
187 
188 static const struct attribute_group blink1_sysfs_group = {
189         .attrs = (struct attribute *[]) {
190                 &dev_attr_rgb.attr,
191                 &dev_attr_fade.attr,
192                 &dev_attr_play.attr,
193                 NULL
194         },
195 };
196 
197 static int thingm_probe(struct hid_device *hdev, const struct hid_device_id *id)
198 {
199         struct blink1_data *data;
200         struct led_classdev *led;
201         char led_name[13];
202         int ret;
203 
204         data = devm_kzalloc(&hdev->dev, sizeof(struct blink1_data), GFP_KERNEL);
205         if (!data)
206                 return -ENOMEM;
207 
208         hid_set_drvdata(hdev, data);
209         data->hdev = hdev;
210         data->rgb = 0xFFFFFF; /* set a default white color */
211 
212         ret = hid_parse(hdev);
213         if (ret)
214                 goto error;
215 
216         ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
217         if (ret)
218                 goto error;
219 
220         /* blink(1) serial numbers range is 0x1A001000 to 0x1A002FFF */
221         led = &data->led_cdev;
222         snprintf(led_name, sizeof(led_name), "blink1::%s", hdev->uniq + 4);
223         led->name = led_name;
224         led->brightness_set = blink1_led_set;
225         led->brightness_get = blink1_led_get;
226         ret = led_classdev_register(&hdev->dev, led);
227         if (ret)
228                 goto stop;
229 
230         ret = sysfs_create_group(&led->dev->kobj, &blink1_sysfs_group);
231         if (ret)
232                 goto remove_led;
233 
234         return 0;
235 
236 remove_led:
237         led_classdev_unregister(led);
238 stop:
239         hid_hw_stop(hdev);
240 error:
241         return ret;
242 }
243 
244 static void thingm_remove(struct hid_device *hdev)
245 {
246         struct blink1_data *data = hid_get_drvdata(hdev);
247         struct led_classdev *led = &data->led_cdev;
248 
249         sysfs_remove_group(&led->dev->kobj, &blink1_sysfs_group);
250         led_classdev_unregister(led);
251         hid_hw_stop(hdev);
252 }
253 
254 static const struct hid_device_id thingm_table[] = {
255         { HID_USB_DEVICE(USB_VENDOR_ID_THINGM, USB_DEVICE_ID_BLINK1) },
256         { }
257 };
258 MODULE_DEVICE_TABLE(hid, thingm_table);
259 
260 static struct hid_driver thingm_driver = {
261         .name = "thingm",
262         .probe = thingm_probe,
263         .remove = thingm_remove,
264         .id_table = thingm_table,
265 };
266 
267 module_hid_driver(thingm_driver);
268 
269 MODULE_LICENSE("GPL");
270 MODULE_AUTHOR("Vivien Didelot <vivien.didelot@savoirfairelinux.com>");
271 MODULE_DESCRIPTION("ThingM blink(1) USB RGB LED driver");
272 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us