diff --git a/10_lightning_node_pro_led/README.md b/10_lightning_node_pro_led/README.md index 1ba3d39..dca7723 100644 --- a/10_lightning_node_pro_led/README.md +++ b/10_lightning_node_pro_led/README.md @@ -16,8 +16,4 @@ If is attached to driver, it appear here. ## Usefull links -- https://github.com/torvalds/linux/blob/master/drivers/hid/hid-led.c -- https://github.com/torvalds/linux/blob/master/drivers/hid/hid-playstation.c -- https://gitlab.com/CalcProgrammer1/OpenRGB/-/blob/master/Controllers/CorsairLightingNodeController/CorsairLightingNodeController.cpp -- https://github.com/benburkhart1/lighting-node-pro -- https://github.com/Legion2/CorsairLightingProtocol \ No newline at end of file +- https://github.com/torvalds/linux/blob/master/drivers/hid/hid-led.c \ No newline at end of file diff --git a/10_lightning_node_pro_led/lightning_node_pro_led.c b/10_lightning_node_pro_led/lightning_node_pro_led.c index cc38eee..2f9ba8f 100644 --- a/10_lightning_node_pro_led/lightning_node_pro_led.c +++ b/10_lightning_node_pro_led/lightning_node_pro_led.c @@ -1,505 +1,40 @@ #include #include #include -#include #define USB_VENDOR_ID_CORSAIR 0x1b1c #define USB_DEVICE_ID_LIGHTNING_NODE_PRO 0x0c0b -#define NUMBER_OF_LEDS_PER_LL120_FAN 16 -#define LIGHTNODE_PRO_MAX_FAN 6 - -#define MSG_SIZE 64 - -static short int number_of_fan = 1; -module_param(number_of_fan, short, 0000); -MODULE_PARM_DESC(number_of_fan, - "Number of LL120 FAN connected to the lightning node pro"); - -enum LNP_LED_TYPE { - LNP_LED_LL120, -}; - -enum { - LNP_PACKET_ID_FIRMWARE = - 0x02, /* Get firmware version */ - LNP_PACKET_ID_DIRECT = 0x32, /* Direct mode LED update packet */ - LNP_PACKET_ID_COMMIT = 0x33, /* Commit changes packet */ - LNP_PACKET_ID_BEGIN = 0x34, /* Begin effect packet */ - LNP_PACKET_ID_EFFECT_CONFIG = - 0x35, /* Effect mode configuration packet */ - LNP_PACKET_ID_TEMPERATURE = - 0x36, /* Update temperature value packet */ - LNP_PACKET_ID_RESET = 0x37, /* Reset channel packet */ - LNP_PACKET_ID_PORT_STATE = - 0x38, /* Set port state packet */ - LNP_PACKET_ID_BRIGHTNESS = - 0x39, /* Set brightness packet */ - LNP_PACKET_ID_LED_COUNT = - 0x3A, /* Set LED count packet */ - LNP_PACKET_ID_PROTOCOL = - 0x3B, /* Set protocol packet */ -}; - -enum { - LNP_DIRECT_CHANNEL_RED = - 0x00, /* Red channel for direct update */ - LNP_DIRECT_CHANNEL_GREEN = - 0x01, /* Green channel for direct update */ - LNP_DIRECT_CHANNEL_BLUE = - 0x02, /* Blue channel for direct update */ -}; - -enum { - LNP_PORT_STATE_HARDWARE = - 0x01, /* Effect hardware control of channel */ - LNP_PORT_STATE_SOFTWARE = - 0x02, /* Direct software control of channel */ -}; - -enum { - LNP_LED_TYPE_LED_STRIP = - 0x0A, /* Corsair LED Strip Type */ - LNP_LED_TYPE_HD_FAN = 0x0C, /* Corsair HD-series Fan Type */ - LNP_LED_TYPE_SP_FAN = 0x01, /* Corsair SP-series Fan Type */ - LNP_LED_TYPE_ML_FAN = 0x02, /* Corsair ML-series Fan Type */ -}; - -enum { - LNP_CHANNEL_1 = 0x00, /* Channel 1 */ - LNP_CHANNEL_2 = 0x01, /* Channel 2 */ - LNP_NUM_CHANNELS = 0x02, /* Number of channels */ -}; - -enum { - LNP_SPEED_FAST = 0x00, /* Fast speed */ - LNP_SPEED_MEDIUM = 0x01, /* Medium speed */ - LNP_SPEED_SLOW = 0x02, /* Slow speed */ -}; - -enum { - LNP_MODE_RAINBOW_WAVE = 0x00, /* Rainbow Wave mode */ - LNP_MODE_COLOR_SHIFT = 0x01, /* Color Shift mode */ - LNP_MODE_COLOR_PULSE = 0x02, /* Color Pulse mode */ - LNP_MODE_COLOR_WAVE = 0x03, /* Color Wave mode */ - LNP_MODE_STATIC = 0x04, /* Static mode */ - LNP_MODE_TEMPERATURE = 0x05, /* Temperature mode */ - LNP_MODE_VISOR = 0x06, /* Visor mode */ - LNP_MODE_MARQUEE = 0x07, /* Marquee mode */ - LNP_MODE_BLINK = 0x08, /* Blink mode */ - LNP_MODE_SEQUENTIAL = 0x09, /* Sequential mode */ - LNP_MODE_RAINBOW = 0x0A, /* Rainbow mode */ -}; - -struct lnp_rgb_led { - struct led_classdev_mc cdev; - int led_index; - uint8_t red; - uint8_t green; - uint8_t blue; -}; - -struct lnp_fan { - int fan_index; - struct lnp_rgb_led *rgb_leds_data; -}; - -struct lnp_device { - struct hid_device *hdev; - spinlock_t lock; - - const char *dev_name; - - enum LNP_LED_TYPE type; - int fans_count; - int rgb_leds_per_fan_count; - void *fans_data; - bool update_fans_leds; - - struct work_struct output_worker; - bool output_worker_initialized; -}; - -static int lnp_send_reports(struct hid_device *hdev, u8 **pkts, u8 pkts_count) +static int lightning_node_pro_led_probe(struct hid_device *hdev, + const struct hid_device_id *id) { - int i, ret; - - for (i = 0; i < pkts_count; i++) { - u8 *pkt = *(pkts + i); - - ret = hid_hw_output_report(hdev, pkt, MSG_SIZE); - if (ret < 0) - return ret; - } + pr_info("Détection USB pour Lightning Node Pro\n"); return 0; } -static int lnp_send_fans_leds_report(struct lnp_device *led_dev) +static void lightning_node_pro_led_remove(struct hid_device *dev) { - int ret; - - u8 *packets[7]; - u8 pktcolors[6][MSG_SIZE]; - - // INDEX 1 = r, 2 = g, 3 = b, 4 = s, 5 = t, 6 = u - // s, t, u are R, G, B extended for fans 3-6 - for (u8 i = 1; i <= 6; i++) { - // Prepare the packet in pktcolors[i] - u8 *pktcolor = pktcolors[i]; - - // Initialize the first 4 bytes - pktcolor[0] = 0x32; - pktcolor[1] = 0x00; - // For Fan [1-3]: 0x32, 0x00, 0x00, 0x32 - // For Fan [4-6]: 0x32, 0x00, 0x32, 0x2e - pktcolor[2] = (i > 2) ? 0x32 : 0x00; - pktcolor[3] = (i > 2) ? 0x2e : 0x32; - - // For red color the fifth Bytes must be equals to 0x00 - // For green color the fifth Bytes must be equals to 0x01 - // For blue color the fifth Bytes must be equals to 0x02 - if (i == 1 || i == 4) { - pktcolor[4] = LNP_DIRECT_CHANNEL_RED; - } - if (i == 2 || i == 5) { - pktcolor[4] = LNP_DIRECT_CHANNEL_GREEN; - } - if (i == 3 || i == 6) { - pktcolor[4] = LNP_DIRECT_CHANNEL_BLUE; - } - - packets[i - 1] = pktcolor; - } - - u8 pktend[MSG_SIZE] = { 0x33, 0xff }; - packets[6] = &pktend[0]; - - ret = lnp_send_reports(led_dev->hdev, &packets[0], - 7); // TODO: Check if 2d array usage is correct - if (ret < 0) - return ret; - - return 0; + pr_info("Retrait USB pour Lightning Node Pro\n"); } -static int lnp_send_init_report(struct hid_device *hdev) -{ - int ret; - - u8 pkt1[MSG_SIZE] = { LNP_PACKET_ID_RESET }; - // 0x35 - Init - u8 pkt2[MSG_SIZE] = { 0x35, 0x00, 0x00, number_of_fan << 4, - 0x00, 0x01, 0x01 }; - u8 pkt3[MSG_SIZE] = { 0x3b, 0x00, 0x01 }; - u8 pkt4[MSG_SIZE] = { 0x38, 0x00, 0x02 }; - u8 pkt5[MSG_SIZE] = { 0x34 }; - u8 pkt6[MSG_SIZE] = { 0x37, 0x01 }; - u8 pkt7[MSG_SIZE] = { 0x34, 0x01 }; - u8 pkt8[MSG_SIZE] = { 0x38, 0x01, 0x01 }; - u8 pkt9[MSG_SIZE] = { 0x33, 0xff }; - - u8 *pkts[9] = { &pkt1[0], &pkt2[0], &pkt3[0], &pkt4[0], &pkt5[0], - &pkt6[0], &pkt7[0], &pkt8[0], &pkt9[0] }; - - ret = lnp_send_reports(hdev, &pkts[0], 9); - if (ret < 0) - return ret; - - return 0; -} - -static inline void lnp_schedule_work(struct lnp_device *lnp_dev) -{ - unsigned long flags; - - spin_lock_irqsave(&lnp_dev->lock, flags); - if (lnp_dev->output_worker_initialized) - schedule_work(&lnp_dev->output_worker); - spin_unlock_irqrestore(&lnp_dev->lock, flags); -} - -static void lnp_set_led_colors(struct lnp_device *lnp_dev, - struct lnp_rgb_led *lnp_rgb_led, uint8_t red, - uint8_t green, uint8_t blue) -{ - unsigned long flags; - - spin_lock_irqsave(&lnp_dev->lock, flags); - lnp_dev->update_fans_leds = true; - lnp_rgb_led->red = red; - lnp_rgb_led->green = green; - lnp_rgb_led->blue = blue; - spin_unlock_irqrestore(&lnp_dev->lock, flags); -} - -static inline int lnp_extract_fan_and_led_index(struct led_classdev *cdev, - int *fan_index, int *led_index) -{ - int ret; - - char *substr = strstr(cdev->name, "fan-"); - if (!substr) - return -EINVAL; - - ret = sscanf(substr, "fan-%d-led-%d", fan_index, led_index); - if (ret != 2) - return -EINVAL; - - return 0; -} - -static int lnp_rgb_let_brightness_set(struct led_classdev *cdev, - enum led_brightness brightness) -{ - struct hid_device *hdev = to_hid_device(cdev->dev->parent); - struct led_classdev_mc *mc_cdev = lcdev_to_mccdev(cdev); - struct lnp_device *lnp_dev = hid_get_drvdata(hdev); - - int ret, fan_index, led_index; - - ret = lnp_extract_fan_and_led_index(cdev, &fan_index, &led_index); - if (ret) { - hid_warn(hdev, "Failed to get fan index and led_index for %s", - lnp_dev->dev_name); - return ret; - } - - struct lnp_fan *lnp_fan = lnp_dev->fans_data + fan_index; - struct lnp_rgb_led *lnp_rgb_led = lnp_fan->rgb_leds_data + led_index; - uint8_t red, green, blue; - - led_mc_calc_color_components(mc_cdev, brightness); - - red = mc_cdev->subled_info[0].brightness; - green = mc_cdev->subled_info[1].brightness; - blue = mc_cdev->subled_info[2].brightness; - - lnp_set_led_colors(lnp_dev, lnp_rgb_led, red, green, blue); - - return 0; -} - -static inline int lnp_register_rgb_led(struct lnp_device *lnp_dev, - struct lnp_fan *fan_data, - struct lnp_rgb_led *rgb_led_data) -{ - struct hid_device *hdev = lnp_dev->hdev; - struct mc_subled *mc_leds_info; - struct led_classdev *led_cdev; - int ret; - - mc_leds_info = devm_kmalloc_array(&hdev->dev, 3, sizeof(*mc_leds_info), - GFP_KERNEL); - - if (!mc_leds_info) { - hid_err(lnp_dev->hdev, - "Failed to allocate multicolor leds info for LED %d on FAN %d\n", - rgb_led_data->led_index, fan_data->fan_index); - return -ENOMEM; - } - - mc_leds_info[0].color_index = LED_COLOR_ID_RED; - mc_leds_info[1].color_index = LED_COLOR_ID_GREEN; - mc_leds_info[2].color_index = LED_COLOR_ID_BLUE; - - rgb_led_data->cdev.subled_info = mc_leds_info; - rgb_led_data->cdev.num_colors = 3; - - led_cdev = &rgb_led_data->cdev.led_cdev; - led_cdev->name = devm_kasprintf(&hdev->dev, GFP_KERNEL, - "%s:rgb:fan-%d-led-%d", - lnp_dev->dev_name, fan_data->fan_index, - rgb_led_data->led_index); - - if (!led_cdev->name) { - hid_err(lnp_dev->hdev, - "Failed to allocate name for LED %d on FAN %d\n", - rgb_led_data->led_index, fan_data->fan_index); - return -ENOMEM; - } - - led_cdev->brightness = 0; - led_cdev->max_brightness = 255; - led_cdev->brightness_set_blocking = lnp_rgb_let_brightness_set; - - ret = devm_led_classdev_multicolor_register(&hdev->dev, - &rgb_led_data->cdev); - if (ret < 0) { - hid_err(hdev, - "Cannot register multicolor LED device for LED %d on FAN %d\n", - rgb_led_data->led_index, fan_data->fan_index); - return ret; - } - - return 0; -} - -static inline int lnp_register_fan(struct lnp_device *lnp_dev, - struct lnp_fan *fan_data) -{ - int ret, led_index; - - fan_data->rgb_leds_data = devm_kmalloc_array( - &lnp_dev->hdev->dev, lnp_dev->rgb_leds_per_fan_count, - sizeof(struct lnp_rgb_led), GFP_KERNEL | __GFP_ZERO); - - if (!fan_data->rgb_leds_data) { - hid_err(lnp_dev->hdev, - "Failed to allocate rgb leds data for FAN %d\n", - fan_data->fan_index); - return -ENOMEM; - } - - for (led_index = 0; led_index < lnp_dev->rgb_leds_per_fan_count; - led_index++) { - struct lnp_rgb_led *rgb_led_data = - fan_data->rgb_leds_data + led_index; - rgb_led_data->led_index = led_index; - - ret = lnp_register_rgb_led(lnp_dev, fan_data, rgb_led_data); - if (ret) - return ret; - } - - return 0; -} - -static inline int lnp_register_fans(struct lnp_device *lnp_dev) -{ - int ret, fan_index; - struct lnp_fan *fans_data = lnp_dev->fans_data; - - for (fan_index = 0; fan_index < lnp_dev->fans_count; fan_index++) { - struct lnp_fan *fan_data = fans_data + fan_index; - fan_data->fan_index = fan_index; - - ret = lnp_register_fan(lnp_dev, fan_data); - if (ret) - return ret; - } - - return 0; -} - -static void lnp_output_worker(struct work_struct *work) -{ - struct lnp_device *lnp_dev = - container_of(work, struct lnp_device, output_worker); - unsigned long flags; - - spin_lock_irqsave(&lnp_dev->lock, flags); - - spin_unlock_irqrestore(&lnp_dev->lock, flags); - - // hid_hw_output_report(lnp_dev->hdev, data, len); -} - -static inline int lnp_init(struct hid_device *hdev) -{ - int ret; - struct lnp_device *lnp_dev; - - lnp_dev = devm_kzalloc(&hdev->dev, sizeof(*lnp_dev), GFP_KERNEL); - if (!lnp_dev) { - hid_err(hdev, "Failed to allocate lnp device data\n"); - return -ENOMEM; - } - - lnp_dev->hdev = hdev; - lnp_dev->dev_name = dev_name(&hdev->dev); - lnp_dev->type = LNP_LED_LL120; // Only support LL120 for now - lnp_dev->fans_count = number_of_fan; - spin_lock_init(&lnp_dev->lock); - INIT_WORK(&lnp_dev->output_worker, lnp_output_worker); - lnp_dev->output_worker_initialized = true; - - if (lnp_dev->type == LNP_LED_LL120) { - lnp_dev->rgb_leds_per_fan_count = NUMBER_OF_LEDS_PER_LL120_FAN; - } else { - hid_err(lnp_dev->hdev, "Invalid fan type %d\n", lnp_dev->type); - return -ENOSYS; - } - - lnp_dev->fans_data = devm_kmalloc_array(&lnp_dev->hdev->dev, - lnp_dev->fans_count, - sizeof(struct lnp_fan), - GFP_KERNEL | __GFP_ZERO); - - if (!lnp_dev->fans_data) { - hid_err(hdev, "Failed to allocate fans data\n"); - return -ENOMEM; - } - - ret = lnp_register_fans(lnp_dev); - if (ret) { - hid_err(lnp_dev->hdev, "Failed to register device\n"); - return ret; - } - - hid_set_drvdata(hdev, lnp_dev); - - return 0; -} - -static int lnp_probe(struct hid_device *hdev, const struct hid_device_id *id) -{ - int ret; - - ret = hid_parse(hdev); - if (ret) { - hid_err(hdev, "Parse failed\n"); - return ret; - } - - ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); - if (ret) { - hid_err(hdev, "Failed to start HID device\n"); - return ret; - } - - ret = hid_hw_open(hdev); - if (ret) { - hid_err(hdev, "Failed to open HID device\n"); - goto err_stop; - } - - ret = lnp_init(hdev); - if (ret) - goto err_close; - - return 0; - -err_close: - hid_hw_close(hdev); -err_stop: - hid_hw_stop(hdev); - return ret; -} - -static void lnp_remove(struct hid_device *hdev) -{ - hid_hw_close(hdev); - hid_hw_stop(hdev); -} - -static struct hid_device_id lnp_table[] = { +static struct hid_device_id lightning_node_pro_led_table[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR, USB_DEVICE_ID_LIGHTNING_NODE_PRO) }, {} /* Entrée de terminaison */ }; -MODULE_DEVICE_TABLE(hid, lnp_table); +MODULE_DEVICE_TABLE(hid, lightning_node_pro_led_table); -static struct hid_driver lnp_driver = { +static struct hid_driver lightning_node_pro_led_driver = { .name = "lightning-node-pro", - .id_table = lnp_table, - .probe = lnp_probe, - .remove = lnp_remove, + .id_table = lightning_node_pro_led_table, + .probe = lightning_node_pro_led_probe, + .remove = lightning_node_pro_led_remove, }; -module_hid_driver(lnp_driver); +module_hid_driver(lightning_node_pro_led_driver); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Florian RICHER "); -MODULE_DESCRIPTION("Un module noyau pour utiliser le Lightning Node Pro"); +MODULE_DESCRIPTION("Un module noyau pour utiliser le Lightning Node Pro LED"); MODULE_VERSION("1.0"); \ No newline at end of file