HID: hid-led: add support for Delcom Visual Signal Indicator G2
authorHeiner Kallweit <hkallweit1@gmail.com>
Mon, 4 Jul 2016 19:45:54 +0000 (21:45 +0200)
committerJiri Kosina <jkosina@suse.cz>
Thu, 7 Jul 2016 09:17:12 +0000 (11:17 +0200)
Add support for the HID-compliant Delcom Visual Signal Indicator
generation 2 devices.

Successfully tested with part no 904000 from the family of these devices.

Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
drivers/hid/Kconfig
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hid-led.c

index 8b1eb47930bc1d2a01218135b629e6f0d0060ca1..e33ccefe3e54cffe881c916e76fa056ad4152c7d 100644 (file)
@@ -397,6 +397,7 @@ config HID_LED
        - Riso Kagaku Webmail Notifier
        - Dream Cheeky Webmail Notifier and Friends Alert
        - ThingM blink(1)
+       - Delcom Visual Signal Indicator Generation 2
 
        To compile this driver as a module, choose M here: the
        module will be called hid-led.
index eb674ce75fabc5400b8e06baf576276a1cf9af2c..f808ae71f9a1c585246be566ffb8b3ebd3b6808b 100644 (file)
@@ -1877,6 +1877,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_4) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_DELCOM, USB_DEVICE_ID_DELCOM_VISUAL_IND) },
        { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
        { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) },
        { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, USB_DEVICE_ID_DREAM_CHEEKY_WN) },
index e104abae0dadf27b9b73530b3fc97567fd5fb57a..ffefbd09fb4ce0401c5f3181a0b0faab707d03fc 100644 (file)
 #define USB_VENDOR_ID_DEALEXTREAME     0x10c5
 #define USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701        0x819a
 
+#define USB_VENDOR_ID_DELCOM           0x0fc5
+#define USB_DEVICE_ID_DELCOM_VISUAL_IND        0xb080
+
 #define USB_VENDOR_ID_DELORME          0x1163
 #define USB_DEVICE_ID_DELORME_EARTHMATE        0x0100
 #define USB_DEVICE_ID_DELORME_EM_LT20  0x0200
index fce2a03cb6471fa525d914857cebab5d38ca8f8f..d793ecefb8b6060b34d02c2badbc914cb5aeec00 100644 (file)
@@ -27,6 +27,7 @@ enum hidled_type {
        RISO_KAGAKU,
        DREAM_CHEEKY,
        THINGM,
+       DELCOM,
 };
 
 static unsigned const char riso_kagaku_tbl[] = {
@@ -43,6 +44,28 @@ static unsigned const char riso_kagaku_tbl[] = {
 
 #define RISO_KAGAKU_IX(r, g, b) riso_kagaku_tbl[((r)?1:0)+((g)?2:0)+((b)?4:0)]
 
+union delcom_packet {
+       __u8 data[8];
+       struct {
+               __u8 major_cmd;
+               __u8 minor_cmd;
+               __u8 data_lsb;
+               __u8 data_msb;
+       } tx;
+       struct {
+               __u8 cmd;
+       } rx;
+       struct {
+               __le16 family_code;
+               __le16 security_code;
+               __u8 fw_version;
+       } fw;
+};
+
+#define DELCOM_GREEN_LED       0
+#define DELCOM_RED_LED         1
+#define DELCOM_BLUE_LED                2
+
 struct hidled_device;
 struct hidled_rgb;
 
@@ -244,6 +267,68 @@ static int thingm_init(struct hidled_device *ldev)
        return 0;
 }
 
+static inline int delcom_get_lednum(const struct hidled_led *led)
+{
+       if (led == &led->rgb->red)
+               return DELCOM_RED_LED;
+       else if (led == &led->rgb->green)
+               return DELCOM_GREEN_LED;
+       else
+               return DELCOM_BLUE_LED;
+}
+
+static int delcom_enable_led(struct hidled_led *led)
+{
+       union delcom_packet dp = { .tx.major_cmd = 101, .tx.minor_cmd = 12 };
+
+       dp.tx.data_lsb = 1 << delcom_get_lednum(led);
+       dp.tx.data_msb = 0;
+
+       return hidled_send(led->rgb->ldev, dp.data);
+}
+
+static int delcom_set_pwm(struct hidled_led *led)
+{
+       union delcom_packet dp = { .tx.major_cmd = 101, .tx.minor_cmd = 34 };
+
+       dp.tx.data_lsb = delcom_get_lednum(led);
+       dp.tx.data_msb = led->cdev.brightness;
+
+       return hidled_send(led->rgb->ldev, dp.data);
+}
+
+static int delcom_write(struct led_classdev *cdev, enum led_brightness br)
+{
+       struct hidled_led *led = to_hidled_led(cdev);
+       int ret;
+
+       /*
+        * enable LED
+        * We can't do this in the init function already because the device
+        * is internally reset later.
+        */
+       ret = delcom_enable_led(led);
+       if (ret)
+               return ret;
+
+       return delcom_set_pwm(led);
+}
+
+static int delcom_init(struct hidled_device *ldev)
+{
+       union delcom_packet dp = { .rx.cmd = 104 };
+       int ret;
+
+       ret = hidled_recv(ldev, dp.data);
+       if (ret)
+               return ret;
+       /*
+        * Several Delcom devices share the same USB VID/PID
+        * Check for family id 2 for Visual Signal Indicator
+        */
+       return dp.fw.family_code == 2 ? 0 : -ENODEV;
+}
+
 static const struct hidled_config hidled_configs[] = {
        {
                .type = RISO_KAGAKU,
@@ -277,6 +362,17 @@ static const struct hidled_config hidled_configs[] = {
                .init = thingm_init,
                .write = thingm_write,
        },
+       {
+               .type = DELCOM,
+               .name = "Delcom Visual Signal Indicator G2",
+               .short_name = "delcom",
+               .max_brightness = 100,
+               .num_leds = 1,
+               .report_size = 8,
+               .report_type = RAW_REQUEST,
+               .init = delcom_init,
+               .write = delcom_write,
+       },
 };
 
 static int hidled_init_led(struct hidled_led *led, const char *color_name,
@@ -382,6 +478,8 @@ static const struct hid_device_id hidled_table[] = {
          USB_DEVICE_ID_DREAM_CHEEKY_FA), .driver_data = DREAM_CHEEKY },
        { HID_USB_DEVICE(USB_VENDOR_ID_THINGM,
          USB_DEVICE_ID_BLINK1), .driver_data = THINGM },
+       { HID_USB_DEVICE(USB_VENDOR_ID_DELCOM,
+         USB_DEVICE_ID_DELCOM_VISUAL_IND), .driver_data = DELCOM },
        { }
 };
 MODULE_DEVICE_TABLE(hid, hidled_table);