diff --git a/10_lightning_node_pro_led/README.md b/10_lightning_node_pro_led/README.md
index dca7723..1ba3d39 100644
--- a/10_lightning_node_pro_led/README.md
+++ b/10_lightning_node_pro_led/README.md
@@ -16,4 +16,8 @@ If is attached to driver, it appear here.
 
 ## Usefull links
 
-- https://github.com/torvalds/linux/blob/master/drivers/hid/hid-led.c
\ No newline at end of file
+- 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
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 2f9ba8f..cc38eee 100644
--- a/10_lightning_node_pro_led/lightning_node_pro_led.c
+++ b/10_lightning_node_pro_led/lightning_node_pro_led.c
@@ -1,40 +1,505 @@
 #include <linux/init.h>
 #include <linux/hid.h>
 #include <linux/module.h>
+#include <linux/led-class-multicolor.h>
 
 #define USB_VENDOR_ID_CORSAIR 0x1b1c
 #define USB_DEVICE_ID_LIGHTNING_NODE_PRO 0x0c0b
 
-static int lightning_node_pro_led_probe(struct hid_device *hdev,
-					const struct hid_device_id *id)
+#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)
 {
-	pr_info("Détection USB pour Lightning Node Pro\n");
+	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;
+	}
 
 	return 0;
 }
 
-static void lightning_node_pro_led_remove(struct hid_device *dev)
+static int lnp_send_fans_leds_report(struct lnp_device *led_dev)
 {
-	pr_info("Retrait USB pour Lightning Node Pro\n");
+	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;
 }
 
-static struct hid_device_id lightning_node_pro_led_table[] = {
+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[] = {
 	{ HID_USB_DEVICE(USB_VENDOR_ID_CORSAIR,
 			 USB_DEVICE_ID_LIGHTNING_NODE_PRO) },
 	{} /* Entrée de terminaison */
 };
-MODULE_DEVICE_TABLE(hid, lightning_node_pro_led_table);
+MODULE_DEVICE_TABLE(hid, lnp_table);
 
-static struct hid_driver lightning_node_pro_led_driver = {
+static struct hid_driver lnp_driver = {
 	.name = "lightning-node-pro",
-	.id_table = lightning_node_pro_led_table,
-	.probe = lightning_node_pro_led_probe,
-	.remove = lightning_node_pro_led_remove,
+	.id_table = lnp_table,
+	.probe = lnp_probe,
+	.remove = lnp_remove,
 };
 
-module_hid_driver(lightning_node_pro_led_driver);
+module_hid_driver(lnp_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Florian RICHER <florian.richer@protonmail.com>");
-MODULE_DESCRIPTION("Un module noyau pour utiliser le Lightning Node Pro LED");
+MODULE_DESCRIPTION("Un module noyau pour utiliser le Lightning Node Pro");
 MODULE_VERSION("1.0");
\ No newline at end of file