יום שישי, 24 במאי 2013

Leds module

One of the simples drive module found in the Linux kernel is the Led module that:”Provides control of the front LED on SPARC systems”
The code of the module can be found here.
Follow a brief description and explanations about the module code.

The module init
static
int __init led_init(void)
{
    init_timer(&led_blink_timer);
    led_blink_timer.function = led_blink;

    led = proc_create("led", 0, NULL, &led_proc_fops);
    if (!led)
            return -ENOMEM;

    printk(KERN_INFO
           "led: version %s, Lars Kotthoff <metalhead@metalhead.ws>\n",
           LED_VERSION);

    return 0;
}

The led_init procedure is calling the  proc_create in order to register the module to the proc virtual directory .
After this call the led virtual file is present in the proc directory and it’s properties can be obtained by using the following command:
$ ls -l /proc/led
The call for proc_create although register file_operation structure allowing to read and write to the device (by cat etc)
The init method init the blinking timer list : led_blinking_timer and attach its time callback function led_blink.

The module exit

static
void __exit led_exit(void)
{
    remove_proc_entry("led", NULL);
    del_timer_sync(&led_blink_timer);
}
the led_exit procedure deletes the proc entry form the proc virtual files directory and free the timer proc.
Note:The del_timer_sync waits for any of the led timer callbacks currently executing in other processor to finish executing before it return.

The module  file operation structure
static
const struct file_operations led_proc_fops = {
         .owner          = THIS_MODULE,
         .open           = led_proc_open,
         .read           = seq_read,
         .llseek         = seq_lseek,
         .release        = single_release,
         .write          = led_proc_write,
};
Some of the operations in the file  structure operations  are the module concrete operations that  are implements in the module and  some operations  use the  common seq  file .


The module write operation
static
ssize_t led_proc_write(struct file *file, const char __user *buffer,
                              size_t count, loff_t *ppos)
{
    char *buf = NULL;

    if (count > LED_MAX_LENGTH)
            count = LED_MAX_LENGTH;

    buf = kmalloc(sizeof(char) * (count + 1), GFP_KERNEL);
    if (!buf)
            return -ENOMEM;

    if (copy_from_user(buf, buffer, count)) {
            kfree(buf);
            return -EFAULT;
    }

    buf[count] = '\0';

    /* work around \n when echo'ing into proc */
    if (buf[count - 1] == '\n')
            buf[count - 1] = '\0';

    /* before we change anything we want to stop any running timers,
     * otherwise calls such as on will have no persistent effect
     */
    del_timer_sync(&led_blink_timer);

    if (!strcmp(buf, "on")) {
            auxio_set_led(AUXIO_LED_ON);
    } else if (!strcmp(buf, "toggle")) {
            led_toggle();
    } else if ((*buf > '') && (*buf <= '9')) {
            led_blink(simple_strtoul(buf, NULL, 10));
    } else if (!strcmp(buf, "load")) {
            led_blink(0);
    } else {
            auxio_set_led(AUXIO_LED_OFF);
    }

    kfree(buf);

    return count;
}
The module led_proc_wrtie procedure goal is to operate the led in a specific manner :
Blinking , off , on , toggle , blink like a crazy (load).
The input for the method is a string that is parsed be series of strcmp methods that determent the led operations for an example if the input string is a number the method operate the led in blinking mode with timeout according to to the parsed string.
Note:Before parsing the string the method make sure that the blinking timer is off and convert the input parse from user mode memory to kernel mode memory .
The method frees the kernel mode memory that was allocated to contain the parse at the end of the operation.The method make sure that the input parse is null terminated and without \n

The timer callback
static
void led_blink(unsigned long timeout)
{
    led_toggle();

    /* reschedule */
    if (!timeout) { /* blink according to load */
            led_blink_timer.expires = jiffies +
                    ((1 + (avenrun[0] >> FSHIFT)) * HZ);
            led_blink_timer.data = 0;
    } else { /* blink at user specified interval */
            led_blink_timer.expires = jiffies + (timeout * HZ);
            led_blink_timer.data = timeout;
    }
    add_timer(&led_blink_timer);
}
The timer callback method led_blink has two duties:
1.Call to toggle the led state
2.Rescale the timer
According to the  callback input parameter (timeout ) the method determent the operation mode if > 0 the method calculate the next timer expiring by adding the timeout to the current jiffies elsewhere the timeout is determent by the system load.the avenrun is the avg loading of the system.

The module read operation The module read operation  is pointed to the seq file  standard read operation that returns a buffer  containing a string indicates if the module is on or off .
The module open operation The  led_proc_open operation  calls the  seq_file single_open operation passing  a callback  pointed to the led_proc_show method.
The led_proc_show  method updates the  seq file  data  whether  the led in on or off.
static int led_proc_show(struct seq_file *m, void *v)
{
     if (get_auxio() & AUXIO_LED)
             seq_puts(m, "on\n");
     else
             seq_puts(m, "off\n");
     return 0;
 }

The release operation The release operation  points the standart seq file release oeprat
ion  used to realse the buffers .
 



 

אין תגובות:

הוסף רשומת תגובה