JZ2440笔记:字符设备驱动程序之同步互斥阻塞

(1)原子操作

vi third_drv.c 增加原子量canopen

static atomic_t canopen = ATOMIC_INIT(1);

static int third_drv_open(struct inode *inode,struct file *file)
{
        if(!atomic_dec_and_test(&canopen))
        {
                atomic_inc(&canopen);
                return -EBUSY;
        }

        request_irq(IRQ_EINT0, buttons_irq,IRQ_TYPE_EDGE_BOTH,"S2",&pin_desc[0]);
        request_irq(IRQ_EINT2, buttons_irq,IRQ_TYPE_EDGE_BOTH,"S3",&pin_desc[1]);
        request_irq(IRQ_EINT11,buttons_irq,IRQ_TYPE_EDGE_BOTH,"S4",&pin_desc[2]);
        request_irq(IRQ_EINT19,buttons_irq,IRQ_TYPE_EDGE_BOTH,"S5",&pin_desc[3]);
        return 0;
}
static int third_drv_close(struct inode *inode,struct file *file)
{
        atomic_inc(&canopen);
        free_irq(IRQ_EINT0, &pin_desc[0]);
        free_irq(IRQ_EINT2, &pin_desc[1]);
        free_irq(IRQ_EINT11,&pin_desc[2]);
        free_irq(IRQ_EINT19,&pin_desc[3]);
        return 0;
}

测试驱动:# ./thirddrvtest &
# ./thirddrvtest &
# can't open /dev/buttons!

(2)信号量

vi third_drv.c增加信号量button_lock

static DECLARE_MUTEX(button_lock);

static int third_drv_open(struct inode *inode,struct file *file)
{
        down(&button_lock);

        request_irq(IRQ_EINT0, buttons_irq,IRQ_TYPE_EDGE_BOTH,"S2",&pin_desc[0]);
        request_irq(IRQ_EINT2, buttons_irq,IRQ_TYPE_EDGE_BOTH,"S3",&pin_desc[1]);
        request_irq(IRQ_EINT11,buttons_irq,IRQ_TYPE_EDGE_BOTH,"S4",&pin_desc[2]);
        request_irq(IRQ_EINT19,buttons_irq,IRQ_TYPE_EDGE_BOTH,"S5",&pin_desc[3]);
        return 0;
}
static int third_drv_close(struct inode *inode,struct file *file)
{
        up(&button_lock);        

        free_irq(IRQ_EINT0, &pin_desc[0]);
        free_irq(IRQ_EINT2, &pin_desc[1]);
        free_irq(IRQ_EINT11,&pin_desc[2]);
        free_irq(IRQ_EINT19,&pin_desc[3]);
        return 0;
}

make出现error: type defaults to 'int' in declaration of 'DECLARE_MUTEX' [-Werror=implicit-int],则将DECLARE_MUTEX(button_lock);更换为DEFINE_SEMAPHORE(button_lock);

测试驱动:# insmod third_drv.ko
third_drv_init
# ./thirddrvtest &
# ./thirddrvtest &
# ps
PID   USER     TIME  COMMAND
  911 0         0:00 ./thirddrvtest
  912 0         0:00 ./thirddrvtest
  913 0         0:00 ps

(3)阻塞与非阻塞

vi third_drv.c增加阻塞判断

static int third_drv_open(struct inode *inode,struct file *file)
{
       if(file->f_flags & NONBLOCK)
        {
                down_trylock(&button_lock);
                return -1;
        }
        else
                down(&button_lock);
        request_irq(IRQ_EINT0, buttons_irq,IRQ_TYPE_EDGE_BOTH,"S2",&pin_desc[0]);
        request_irq(IRQ_EINT2, buttons_irq,IRQ_TYPE_EDGE_BOTH,"S3",&pin_desc[1]);
        request_irq(IRQ_EINT11,buttons_irq,IRQ_TYPE_EDGE_BOTH,"S4",&pin_desc[2]);
        request_irq(IRQ_EINT19,buttons_irq,IRQ_TYPE_EDGE_BOTH,"S5",&pin_desc[3]);
        return 0;
}

static ssize_t third_drv_read(struct file *file,char __user *buf,size_t len,loff_t *ppos)
{
        if(len!=1)
                return -EINVAL;

        if(file->f_flags & NONBLOCK)
        {
                if(!ev_press)
                        return -1;
        }
        else
                wait_event_interruptible(button_waitq,ev_press);
        copy_to_user(buf,&key_val,1);
        ev_press = 0;
        return 1;
}

make出现error: 'NONBLOCK' undeclared (first use in this function),则NONBLOCK因为O_NONBLOCK     

vi thirddrvtest.c(阻塞)

#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc,char *argv[])
{
        int fd;
        int ret;

        fd = open("/dev/buttons",O_RDWR);
        if(fd<0)
        {
                printf("can't open /dev/buttons!\n");
                return -1;
        }

        while(1)
        {
                read(fd,&retval,1);
                printf("key_value = 0x%x\n",ret);
                sleep(1000);
        }
        return 0;
}

测试驱动:

# insmod third_drv.ko
third_drv_init
# ./thirddrvtest &
# 按键
key_value = 0x1
 

vi thirddrvtest.c(非阻塞)

#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc,char *argv[])
{
        int fd;
        unsigned char ret;

        fd = open("/dev/buttons",O_RDWR|O_NONBLOCK);
        if(fd<0)
        {
                printf("can't open /dev/buttons!\n");
                return -1;
        }

        while(1)
        {
                read(fd,&ret,1);
                printf("key_value = 0x%x\n",ret);
                sleep(1000);
        }
        return 0;
}

测试驱动:# ./thirddrvtest &
# can't open /dev/buttons!

在驱动程序中third_drv_open(struct inode *inode,struct file *file)
       if(file->f_flags & O_NONBLOCK)
        {
                down_trylock(&button_lock);
                return -1;
        }
     写错了,应该是 if(file->f_flags & O_NONBLOCK)
        {
                if (down_trylock(&button_lock))
                        return -1;
        }

注意:semaphore:down_trylock() 函数尝试原子地获取信号量sem,成功或不成功获取信号量,函数都将立即返回;成功返回0,失败返回1。

重新编译后测试:

# insmod third_drv.ko
third_drv: loading out-of-tree module taints kernel.
third_drv_init
# ./thirddrvtest &
key_value = 0x0, oflags = -1
key_value = 0x0, oflags = -1
key_value = 0x81, oflags = 1

如果要打印错误原因,如下操作

#include <fcntl.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

int main() {
    int fd = open("/dev/buttons", O_RDWR | O_NONBLOCK);
    if (fd == -1) {
        printf("Failed to open /dev/buttons: %s\n", strerror(errno));
        return 1;
    }
    // 其他操作
    close(fd);
    return 0;
}

(4)定时器防抖动

vi third_drv.c增加定时器

static struct timer_list button_timer;

static  struct pin_desc *irq_pd;
static irqreturn_t buttons_irq(int irq,void *dev_id)
{
        irq_pd = (struct pin_desc *)dev_id;
        mod_timer(&button_timer,jiffies+HZ/100);
        return IRQ_HANDLED;
}

static void button_timer_function(unsigned long data)
{
        unsigned int pinval;
        struct pin_desc *pindesc = irq_pd;

        if(!pindesc)
                return;

        pinval = gpio_get_value(pindesc->pin);
        if(pinval)
        {
                key_val = 0x80|pindesc->key_val;
        }
        else
        {
                key_val = pindesc->key_val;
        }
        ev_press = 1;
        wake_up_interruptible(&button_waitq);
        kill_fasync(&button_fasync,SIGIO,POLL_IN);
}


static int third_drv_init(void)
{
        init_timer(&button_timer);
        button_timer.function = button_timer_function;
        add_timer(&button_timer);

        major = register_chrdev(0,"third_drv",&third_drv_fops);
        thirddrv_class = class_create(THIS_MODULE,"thirddrv");
        thirddrv_device = device_create(thirddrv_class,NULL,MKDEV(major,0),NULL,"buttons");
        printk("third_drv_init\n");
        return 0;
}

make出现error: implicit declaration of function 'init_timer',

error: passing argument 2 of 'init_timer_key' from incompatible pointer type [-Werror=incompatible-pointer-types]

参考Linxu内核编程报错:implicit declaration of function ‘init_timer’_linux implicit declaration of function itoa-CSDN博客将init_timer(&button_timer);button_timer.function = button_timer_function;add_timer(&button_timer);变更为timer_setup(&button_timer,button_timer_function,0);

将static void button_timer_function(unsigned long data){}变更为static void button_timer_function(struct timer_list *t){}

编译通过。

测试驱动:# insmod third_drv.ko
third_drv_init
# ./thirddrvtest &
key_value = 0x1, oflags = 1
key_value = 0x81, oflags = 1
key_value = 0x1, oflags = 1
key_value = 0x81, oflags = 1

驱动代码:

#include <asm/mach/map.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/gpio.h>
#include <mach/gpio-samsung.h>
/*
volatile unsigned long *gpfcon = NULL;
volatile unsigned long *gpgcon = NULL;
volatile unsigned long *gpfdat = NULL;
volatile unsigned long *gpgdat = NULL;
*/

static struct timer_list button_timer;
//static atomic_t canopen = ATOMIC_INIT(1);
static DEFINE_SEMAPHORE(button_lock);
static struct fasync_struct *button_fasync;
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
static volatile int ev_press = 0;

static unsigned char key_val;
struct pin_desc{
        unsigned int pin;
        unsigned int key_val;
};
struct pin_desc pin_desc[4]={
        {S3C2410_GPF(0), 0X01},
        {S3C2410_GPF(2), 0X02},
        {S3C2410_GPG(3), 0X03},
        {S3C2410_GPG(11),0X04},
};

static  struct pin_desc *irq_pd;
static irqreturn_t buttons_irq(int irq,void *dev_id)
{
        irq_pd = (struct pin_desc *)dev_id;
        mod_timer(&button_timer,jiffies+HZ/100);
        return IRQ_HANDLED;
}


static void button_timer_function(struct timer_list *t)
{
        unsigned int pinval;
        struct pin_desc *pindesc = irq_pd;

        if(!pindesc)
                return;

        pinval = gpio_get_value(pindesc->pin);
        if(pinval)
        {
                key_val = 0x80|pindesc->key_val;
        }
        else
        {
                key_val = pindesc->key_val;
        }
        ev_press = 1;
        wake_up_interruptible(&button_waitq);
        kill_fasync(&button_fasync,SIGIO,POLL_IN);
}


static int third_drv_open(struct inode *inode,struct file *file)
{
        /*if(!atomic_dec_and_test(&canopen))
        {
                atomic_inc(&canopen);
                return -1;
        }
*/
        if(file->f_flags & O_NONBLOCK)
        {
                if(down_trylock(&button_lock))
                        return -EBUSY;
        }
        else
                down(&button_lock);
        request_irq(IRQ_EINT0, buttons_irq,IRQ_TYPE_EDGE_BOTH,"S2",&pin_desc[0]);
        request_irq(IRQ_EINT2, buttons_irq,IRQ_TYPE_EDGE_BOTH,"S3",&pin_desc[1]);
        request_irq(IRQ_EINT11,buttons_irq,IRQ_TYPE_EDGE_BOTH,"S4",&pin_desc[2]);
        request_irq(IRQ_EINT19,buttons_irq,IRQ_TYPE_EDGE_BOTH,"S5",&pin_desc[3]);
        return 0;
}

static ssize_t third_drv_read(struct file *file,char __user *buf,size_t len,loff_t *ppos)
{
        if(len!=1)
                return -EINVAL;

        if(file->f_flags & O_NONBLOCK)
        {
                     if(!ev_press)
                        return -EAGAIN;
        }
        else
                wait_event_interruptible(button_waitq,ev_press);
        copy_to_user(buf,&key_val,1);
        ev_press = 0;
        return 1;
}


static int third_drv_close(struct inode *inode,struct file *file)
{
//      atomic_inc(&canopen);
        up(&button_lock);
        free_irq(IRQ_EINT0, &pin_desc[0]);
        free_irq(IRQ_EINT2, &pin_desc[1]);
        free_irq(IRQ_EINT11,&pin_desc[2]);
        free_irq(IRQ_EINT19,&pin_desc[3]);
        return 0;
}

static int third_drv_fasync (int fd, struct file *file, int on)
{
        return fasync_helper(fd,file,on,&button_fasync);
}



static struct file_operations third_drv_fops = {
        .owner = THIS_MODULE,
        .open = third_drv_open,
        .read = third_drv_read,
        .fasync = third_drv_fasync,
        .release = third_drv_close,
};

int major;
static struct class *thirddrv_class;
static struct device *thirddrv_device;
static int third_drv_init(void)
{
/*      init_timer(&button_timer);
        button_timer.function = button_timer_function;
        add_timer(&button_timer);
*/
        timer_setup(&button_timer,button_timer_function,0);

        major = register_chrdev(0,"third_drv",&third_drv_fops);
        thirddrv_class = class_create(THIS_MODULE,"thirddrv");
        thirddrv_device = device_create(thirddrv_class,NULL,MKDEV(major,0),NULL,"buttons");
/*
        gpfcon = (volatile unsigned long *)ioremap(0x56000050,16);
        gpfdat = gpfcon + 1;
        gpgcon = (volatile unsigned long *)ioremap(0x56000060,16);
        gpgdat = gpgcon + 1;
*/
        printk("third_drv_init\n");
        return 0;
}

static void third_drv_exit(void)
{
//      iounmap(gpfcon);
//      iounmap(gpgcon);

        unregister_chrdev(major,"third_drv");
        device_destroy(thirddrv_class,MKDEV(major,0));
        class_destroy(thirddrv_class);
        printk("third_drv_exit\n");
}

module_init(third_drv_init);
module_exit(third_drv_exit);

MODULE_LICENSE("GPL");

  • 14
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值