Friday, 4 September 2015

https://lwn.net/Kernel/LDD3/

https://lwn.net/Kernel/LDD3/

ls /dev/s

cat /dev/switch0




Jiffy is ticks

Hz is 1000

Schedule is for yielding for next task

jiffies = 8 ;
while(time_before(jiffies,j1))
schedule();

schedule_timeout();

Switch_LED.c complete Interrupt based program to switch ON LED when BUTTON is pressed

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/errno.h>
#include <linux/sched.h> /* current and everything */
#include <linux/types.h> /* size_t */
#include <linux/wait.h>     /* Wait Q, ... */
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>

#define FIRST_MINOR 0
#define MINOR_CNT 1

static dev_t dev;
static struct cdev c_dev;
static struct class *cl;

static unsigned int sw_gpio_num = 72; // GPIO 2_8
static unsigned int led_gpio_num = 56; // GPIO 1_24
static DECLARE_WAIT_QUEUE_HEAD(wq);
static int flag = 0;
static unsigned char c;

static irqreturn_t sw_irq_handler(int irq, void *data)
{
    int val;

    val = !gpio_get_value(sw_gpio_num);
    gpio_set_value(led_gpio_num, val);
    c = '0' + val;

    //printk(KERN_INFO "Awakening the readers...\n");
    flag = 1;
    wake_up_interruptible(&wq);

    return IRQ_HANDLED;
}

static int swl_char_open(struct inode *i, struct file *f)
{
    int ret;
    int irq;

    if ((ret = gpio_request_one(sw_gpio_num, GPIOF_IN, "sw_int")) < 0)
    {
        printk(KERN_ERR "GPIO %d is already in use\n", sw_gpio_num);
        return ret;
    }
    if ((irq = gpio_to_irq(sw_gpio_num)) < 0)
    {
        printk(KERN_ALERT "GPIO %d cannot be used as interrupt", sw_gpio_num);
        gpio_free(sw_gpio_num);
        return irq;
    }
    if ((ret = request_irq(irq, sw_irq_handler,
                        IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "sw_int", NULL)) < 0)
    {
        printk(KERN_ERR "Registering irq %d failed\n", irq);
        gpio_free(sw_gpio_num);
        return ret;
    }
    return 0;
}

static int swl_char_close(struct inode *i, struct file *f)
{
    free_irq(gpio_to_irq(sw_gpio_num), NULL);
    gpio_free(sw_gpio_num);
    return 0;
}

static ssize_t swl_char_read (struct file *filp, char __user *buf, size_t count, loff_t *pos)
{
    //printk(KERN_INFO "Process %i (%s) going to sleep\n", current->pid, current->comm);
    wait_event_interruptible(wq, flag != 0);
    flag = 0;
    //printk(KERN_INFO "Awoken %i (%s)\n", current->pid, current->comm);
    if (copy_to_user(buf, &c, 1))
    {
        return -EFAULT;
    }
    return 1;
}

static struct file_operations swl_char_fops =
{
    .owner = THIS_MODULE,
    .open = swl_char_open,
    .release = swl_char_close,
    .read = swl_char_read,
};

static int __init swl_char_init(void)
{
    int ret;
    struct device *dev_ret;

    if ((ret = alloc_chrdev_region(&dev, FIRST_MINOR, MINOR_CNT, "switch")) < 0)
    {
        return ret;
    }

    cdev_init(&c_dev, &swl_char_fops);

    if ((ret = cdev_add(&c_dev, dev, MINOR_CNT)) < 0)
    {
        unregister_chrdev_region(dev, MINOR_CNT);
        return ret;
    }
   
    if (IS_ERR(cl = class_create(THIS_MODULE, "char")))
    {
        cdev_del(&c_dev);
        unregister_chrdev_region(dev, MINOR_CNT);
        return PTR_ERR(cl);
    }
    if (IS_ERR(dev_ret = device_create(cl, NULL, dev, NULL, "switch%d", 0)))
    {
        class_destroy(cl);
        cdev_del(&c_dev);
        unregister_chrdev_region(dev, MINOR_CNT);
        return PTR_ERR(dev_ret);
    }

    return 0;
}

static void __exit swl_char_exit(void)
{
    device_destroy(cl, dev);
    class_destroy(cl);
    cdev_del(&c_dev);
    unregister_chrdev_region(dev, MINOR_CNT);
}

module_init(swl_char_init);
module_exit(swl_char_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Anil Kumar Pugalia <anil@sysplay.in>");
MODULE_DESCRIPTION("Switch Char Driver Demo");

BEAGLE BONE BLACK Push Switch Turn on LED

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/fs.h>
#include <linux/types.h>
#include <linux/kdev_t.h>
#include <linux/errno.h>
#include <linux/cdev.h>
#include <linux/device.h>
#include <linux/gpio.h>
#include <asm/uaccess.h>


static u8 sw_gpio_num = 72; // GPIO 2_8
static unsigned int gpio_number[] = {53,54,55,56}; // TODO: Fill the GPIO numbers for User LED 0-3: GPIO1_21-24

static irqreturn_t sw_irq_handler(int irq, void *data)
{
    printk(KERN_INFO "GPIO %d IRQ %d Value %d\n", sw_gpio_num, irq, gpio_get_value(sw_gpio_num));
        /* Set Led high if value is 0 */
        if(gpio_get_value(sw_gpio_num))
    gpio_set_value(gpio_number[1], 1 /* TODO: Pass the user value here */);
    else
        gpio_set_value(gpio_number[1], 0 /* TODO: Pass the user value here */);
    return IRQ_HANDLED;
}

static int __init sw_int_init(void)
{
    int ret;
    int irq;

#if 1
    if ((ret = gpio_request(sw_gpio_num, "sw_int")) < 0)
    {
        printk(KERN_ERR "GPIO %d is already in use\n", sw_gpio_num);
        return ret;
    }

    if ((ret = gpio_direction_input(sw_gpio_num)) < 0)
    {
        printk(KERN_ERR "GPIO %d is not set as input\n", sw_gpio_num);
        return ret;
    }
#else
    if ((ret = gpio_request_one(sw_gpio_num, GPIOF_IN, "sw_int")) < 0)
    {
        printk(KERN_ERR "GPIO %d is already in use\n", sw_gpio_num);
        return ret;
    }
#endif

    if ((irq = gpio_to_irq(sw_gpio_num)) < 0)
    {
        printk(KERN_ALERT "GPIO %d cannot be used as interrupt", sw_gpio_num);
        gpio_free(sw_gpio_num);
        return irq;
    }

    if ((ret = request_irq(irq, sw_irq_handler,
                        IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "sw_int", NULL)) < 0)
    {
        printk(KERN_ERR "Registering irq %d failed\n", irq);
        gpio_free(sw_gpio_num);
        return ret;
    }
   
    printk(KERN_INFO "GPIO %d IRQ %d Value %d\n", sw_gpio_num, irq, gpio_get_value(sw_gpio_num));

    printk(KERN_INFO "Switch Interrupt Driver loaded\n");

    return 0;
}

static void __exit sw_int_exit(void)
{
    free_irq(gpio_to_irq(sw_gpio_num), NULL);
    gpio_free(sw_gpio_num);
    printk(KERN_INFO "Switch Interrupt Driver unloaded\n");
}

module_init(sw_int_init);
module_exit(sw_int_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Anil Kumar Pugalia <anil@sysplay.in>");
MODULE_DESCRIPTION("Switch Interrupt Driver");

Thursday, 3 September 2015

interrupt_switch.c

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>

static u8 sw_gpio_num = 72; // GPIO 2_8

static irqreturn_t sw_irq_handler(int irq, void *data)
{
    printk(KERN_INFO "GPIO %d IRQ %d Value %d\n", sw_gpio_num, irq, gpio_get_value(sw_gpio_num));

    return IRQ_HANDLED;
}

static int __init sw_int_init(void)
{
    int ret;
    int irq;

#if 1
    if ((ret = gpio_request(sw_gpio_num, "sw_int")) < 0)
    {
        printk(KERN_ERR "GPIO %d is already in use\n", sw_gpio_num);
        return ret;
    }

    if ((ret = gpio_direction_input(sw_gpio_num)) < 0)
    {
        printk(KERN_ERR "GPIO %d is not set as input\n", sw_gpio_num);
        return ret;
    }
#else
    if ((ret = gpio_request_one(sw_gpio_num, GPIOF_IN, "sw_int")) < 0)
    {
        printk(KERN_ERR "GPIO %d is already in use\n", sw_gpio_num);
        return ret;
    }
#endif

    if ((irq = gpio_to_irq(sw_gpio_num)) < 0)
    {
        printk(KERN_ALERT "GPIO %d cannot be used as interrupt", sw_gpio_num);
        gpio_free(sw_gpio_num);
        return irq;
    }

    if ((ret = request_irq(irq, sw_irq_handler,
                        IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "sw_int", NULL)) < 0)
    {
        printk(KERN_ERR "Registering irq %d failed\n", irq);
        gpio_free(sw_gpio_num);
        return ret;
    }
   
    printk(KERN_INFO "GPIO %d IRQ %d Value %d\n", sw_gpio_num, irq, gpio_get_value(sw_gpio_num));

    printk(KERN_INFO "Switch Interrupt Driver loaded\n");

    return 0;
}

static void __exit sw_int_exit(void)
{
    free_irq(gpio_to_irq(sw_gpio_num), NULL);
    gpio_free(sw_gpio_num);
    printk(KERN_INFO "Switch Interrupt Driver unloaded\n");
}

module_init(sw_int_init);
module_exit(sw_int_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("Anil Kumar Pugalia <anil@sysplay.in>");
MODULE_DESCRIPTION("Switch Interrupt Driver");