Search code examples
linuxlinux-kernellinux-device-driverkernel-moduleled

How can I control list of LEDs in kernel space


I am trying to build a kernel module for Linux to try to control a list of LED devices that will turn them on/off in a sequence. For example, green --> red --> green --> orange, and then repeat.

I know it can be done simply in userspace, but this LED sequence needs to be happening when CPU is used intensively where the sequence will be slowed down dramatically, so I need to control it through Hardware. I've using delay_on/delay_off, with usleep(), but just cannot get the timing right between 3 LEDs.

I know how to trigger each LEDs and assign them pattern individually, but I cannot do it collectively.

Can anyone show me how to obtain a list of LED devices?


Solution

  • To list the available LEDs in kernel code:

    extern struct rw_semaphore leds_list_lock;
    extern struct list_head leds_list;
    ...
    struct led_classdev *led_cdev;
    ...
    down_write(&leds_list_lock);
    list_for_each_entry(led_cdev, &leds_list, node) {
        printk(KERN_INFO "LED %s\n", led_cdev->name);
    }
    up_write(&leds_list_lock);
    

    In kernel code, you can use the following function to retrieve a 'struct led_classdev' matching a given LED name:

    struct led_classdev *led_get_by_name(const char *name)
    {
        struct led_classdev *led_cdev0 = NULL;
        struct led_classdev *led_cdev;
    
        if (name == NULL) {
            return NULL;
        }
    
        down_write(&leds_list_lock);
        list_for_each_entry(led_cdev, &leds_list, node) {
            if ((led_cdev->name != NULL) && (strcmp(led_cdev->name, name) == 0)) {
                led_cdev0 = led_cdev;
                break;
            }
        }
        up_write(&leds_list_lock);
    
        return led_cdev0;
    }
    

    Once the 'struct led_classdev' retrieved, all kernel LED APIs can be used.

    Pay attention that the LED name may be null in the registered 'struct led_classdev' while the LED name appears under /sys/class/leds. E.g., this the case for the ACT and PWR LEDs on my Raspberry PI 4 under Debian 12.