字符设备驱动------同步互斥阻塞

引入 

当设备被一个程序打开时,存在被另一个程序打开的可能,如果两个或多个程序同时对设备文件进行写操作,这就是说我们的设备资源同时被多个进程使用,对共享资源(硬件资源、和软件上的全局变量、静态变量等)的访问则很容易导致竞态。

显然这不是我们想要的,所以本节引入互斥的概念:实现同一时刻,只能一个应用程序使用驱动程序

互斥其实现很简单,就是采用一些标志,当文件被一个进程打开后,就会设置该标志,使其他进程无法打开设备文件

目的

同一时刻,只允许驱动程序被一个进程打开

1.其中的标志需要使用函数来操作,不能直接通过判断变量来操作标志

eg:

open中记录打开的次数,can_open_cnt表示运行打开的次数,定义为1表示只允许一个设备打开.

但是在汇编中一个c代码的加减实际上是分为a.读----b.修改----c.写回的过程,

当A程序执行上述的a语句时,切换到B程序执行此程序,也执行到此语句的a.读,

由于A并未修改can_open_cnt = 0,B也能正常打开,B关闭后,can_open_cnt++ = 1

继续执行A。由此看来,使用判断变量来操作标志存在篡改的过程。

1 int can_open_cnt =1;
2 // open
3 if (--can_open_cnt != 0) //先减后判断
4 {  //0-->无进程访问驱动, <0 -->已有进程访问
5     can_open_cnt++;
6     return _EBUSY
7 }
8 //close
9 can_open_cnt++;

1.1所以采用某种函数来实现,保证执行过程不被其他行为打断,有两种类型函数可以实现:

  原子操作(像原子一样不可再细分不可被中途打断)

当多个进程同时访问同一个驱动时,只能有一个进程访问成功,其它进程会退出

  互斥信号量操作

比如:A、B进程同时访问同一个驱动时,只有A进程访问成功了,B进程进入休眠等待状态,当A进程执行完毕释放后,等待状态的B进程又来访问,保证一个一个进程都能访问

2. 原子操作详解

1 常用原子操作函数举例:
2 atomic_t v = ATOMIC_INIT(0);     //定义原子变量v并初始化为0
3 atomic_read(atomic_t *v);        //返回原子变量的值
4 void atomic_inc(atomic_t *v);    //原子变量增加1
5 void atomic_dec(atomic_t *v);    //原子变量减少1
6 int atomic_dec_and_test(atomic_t *v); //自减操作后测试其是否为0,为0则返回true,否则返回false。

2.1修改驱动程序

定义原子变量:

1 /*定义原子变量canopen并初始化为1 */
2 atomic_t canopen = ATOMIC_INIT(1); 

在.open成员函数里添加:

1 /*自减操作后测试其是否为0,为0则返回true,否则返回false   */
2 if(!atomic_dec_and_test(&canopen))
3  {
4   atomic_inc(&canopen);       //++,复位
5   return -1;
6  }

在. release成员函数里添加:

 atomic_inc(&canopen);       //++,复位

驱动程序:

  1 #include <linux/module.h>
  2 #include <linux/kernel.h>
  3 #include <linux/fs.h>
  4 #include <linux/init.h>
  5 #include <linux/delay.h>
  6 #include <linux/irq.h>
  7 #include <asm/uaccess.h>
  8 #include <asm/irq.h>
  9 #include <asm/io.h>
 10 #include <asm/arch/regs-gpio.h>
 11 #include <asm/hardware.h>
 12 #include <linux/poll.h>
 13
 14
 15 static struct class *sixthdrv_class;
 16 static struct class_device    *sixthdrv_class_dev;
 17
 18 volatile unsigned long *gpfcon;
 19 volatile unsigned long *gpfdat;
 20
 21 volatile unsigned long *gpgcon;
 22 volatile unsigned long *gpgdat;
 23
 24
 25 static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
 26
 27 /* 中断事件标志, 中断服务程序将它置1,sixth_drv_read将它清0 */
 28 static volatile int ev_press = 0;
 29
 30 static struct fasync_struct *button_async;
 31
 32
 33 struct pin_desc{
 34     unsigned int pin;
 35     unsigned int key_val;
 36 };
 37
 38
 39 /* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
 40 /* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */
 41 static unsigned char key_val;
 42
 43 struct pin_desc pins_desc[4] = {
 44     {S3C2410_GPF0, 0x01},
 45     {S3C2410_GPF2, 0x02},
 46     {S3C2410_GPG3, 0x03},
 47     {S3C2410_GPG11, 0x04},
 48 };
 49
 50 static atomic_t canopen = ATOMIC_INIT(1);    //定义原子变量并初始化为1
 51 //static DECLARE_MUTEX(button_lock);     //定义互斥锁
 52
 53 /*
 54   * 确定按键值
 55   */
 56 static irqreturn_t buttons_irq(int irq, void *dev_id)
 57 {
 58     struct pin_desc * pindesc = (struct pin_desc *)dev_id;
 59     unsigned int pinval;
 60
 61     pinval = s3c2410_gpio_getpin(pindesc->pin);
 62
 63     if (pinval)
 64     {
 65         /* 松开 */
 66         key_val = 0x80 | pindesc->key_val;
 67     }
 68     else
 69     {
 70         /* 按下 */
 71         key_val = pindesc->key_val;
 72     }
 73
 74     ev_press = 1;                  /* 表示中断发生了 */
 75     wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */
 76
 77     kill_fasync (&button_async, SIGIO, POLL_IN);
 78
 79     return IRQ_RETVAL(IRQ_HANDLED);
 80 }
 81
 82 static int sixth_drv_open(struct inode *inode, struct file *file)
 83 {
 84
 85     if (!atomic_dec_and_test(&canopen))    //自减操作
 86     {
 87         atomic_inc(&canopen);    //原子变量加1
 88         return -EBUSY;
 89     }
 90
 91     /* 配置GPF0,2为输入引脚 */
 92     /* 配置GPG3,11为输入引脚 */
 93     request_irq(IRQ_EINT0,  buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[0]);
 94     request_irq(IRQ_EINT2,  buttons_irq, IRQT_BOTHEDGE, "S3", &pins_desc[1]);
 95     request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", &pins_desc[2]);
 96     request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", &pins_desc[3]);
 97
 98     return 0;
 99 }
100
101 ssize_t sixth_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
102 {
103     if (size != 1)
104         return -EINVAL;
105
106     if (file->f_flags & O_NONBLOCK)
107     {
108         if (!ev_press)
109             return -EAGAIN;
110     }
111     else
112     {
113         /* 如果没有按键动作, 休眠 */
114         wait_event_interruptible(button_waitq, ev_press);
115     }
116
117     /* 如果有按键动作, 返回键值 */
118     copy_to_user(buf, &key_val, 1);
119     ev_press = 0;
120
121     return 1;
122 }
123
124
125 int sixth_drv_close(struct inode *inode, struct file *file)
126 {
127     atomic_inc(&canopen);    //原子变量加1
128     free_irq(IRQ_EINT0, &pins_desc[0]);
129     free_irq(IRQ_EINT2, &pins_desc[1]);
130     free_irq(IRQ_EINT11, &pins_desc[2]);
131     free_irq(IRQ_EINT19, &pins_desc[3]);
132     //up(&button_lock);
133     return 0;
134 }
135
136 static unsigned sixth_drv_poll(struct file *file, poll_table *wait)
137 {
138     unsigned int mask = 0;
139     poll_wait(file, &button_waitq, wait); // 不会立即休眠
140
141     if (ev_press)
142         mask |= POLLIN | POLLRDNORM;
143
144     return mask;
145 }
146
147 static int sixth_drv_fasync (int fd, struct file *filp, int on)
148 {
149     printk("driver: sixth_drv_fasync\n");
150     return fasync_helper (fd, filp, on, &button_async);
151 }
152
153
154 static struct file_operations sencod_drv_fops = {
155     .owner   =  THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
156     .open    =  sixth_drv_open,
157     .read     =    sixth_drv_read,
158     .release =  sixth_drv_close,
159     .poll    =  sixth_drv_poll,
160     .fasync     =  sixth_drv_fasync,
161 };
162
163
164 int major;
165 static int sixth_drv_init(void)
166 {
167     major = register_chrdev(0, "sixth_drv", &sencod_drv_fops);
168
169     sixthdrv_class = class_create(THIS_MODULE, "sixth_drv");
170
171     sixthdrv_class_dev = class_device_create(sixthdrv_class, NULL, MKDEV(major, 0), NULL, "buttons"); /* /dev/buttons */
172
173     gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
174     gpfdat = gpfcon + 1;
175
176     gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
177     gpgdat = gpgcon + 1;
178
179     return 0;
180 }
181
182 static void sixth_drv_exit(void)
183 {
184     unregister_chrdev(major, "sixth_drv");
185     class_device_unregister(sixthdrv_class_dev);
186     class_destroy(sixthdrv_class);
187     iounmap(gpfcon);
188     iounmap(gpgcon);
189     return 0;
190 }
191
192
193 module_init(sixth_drv_init);
194
195 module_exit(sixth_drv_exit);
196
197 MODULE_LICENSE("GPL");

sixth_drv.c

测试程序:

 1 #include <sys/types.h>
 2 #include <sys/stat.h>
 3 #include <fcntl.h>
 4 #include <stdio.h>
 5 #include <poll.h>
 6 #include <signal.h>
 7 #include <sys/types.h>
 8 #include <unistd.h>
 9 #include <fcntl.h>
10
11
12 /* sixthdrvtest
13   */
14 int fd;
15
16 void my_signal_fun(int signum)
17 {
18     unsigned char key_val;
19     read(fd, &key_val, 1);
20     printf("key_val: 0x%x\n", key_val);
21 }
22
23 int main(int argc, char **argv)
24 {
25     unsigned char key_val;
26     int ret;
27     int Oflags;
28
29     //signal(SIGIO, my_signal_fun);
30
31     //fd = open("/dev/buttons", O_RDWR | O_NONBLOCK);
32     fd = open("/dev/buttons", O_RDWR);
33     if (fd < 0)
34     {
35         printf("can‘t open!\n");
36         return -1;
37     }
38
39     //fcntl(fd, F_SETOWN, getpid());
40
41     //Oflags = fcntl(fd, F_GETFL);
42
43     //fcntl(fd, F_SETFL, Oflags | FASYNC);
44
45
46     while (1)
47     {
48         ret = read(fd, &key_val, 1);
49         printf("key_val: 0x%x, ret = %d\n", key_val, ret);
50         sleep(5);
51     }
52
53     return 0;
54 }

sixthdrvtest.c

如下图,可以看到第一个进程访问驱动成功,后面的就再也不能访问成功了

3.互斥信号量详解

互斥信号量(semaphore)是用于保护临界区的一种常用方法,

应用程序在操作之前,要先申请信号量,申请不到的话,要么返回,要么等休眠

如果能申请到信号量,进程才能继续操作,操作完毕后,要释放信号量。

释放了之后,如果有其他的应用程序等待获取此信号量的话,就要去唤醒那个应用程序。

3.1信号量函数如下:

/*注意: 在2.6.36版本后这个函数DECLARE_MUTEX修改成DEFINE_SEMAPHORE了*/
1)static DECLARE_MUTEX(button_lock);         //定义互斥锁button_lock,被用来后面的down和up用

2)void down(struct semaphore * sem);            // 获取不到就进入不被中断的休眠状态(down函数中睡眠)

3)int down_interruptible(struct semaphore * sem);  //获取不到就进入可被中断的休眠状态(down函数中睡眠)

4)int down_trylock(struct semaphore * sem);       //试图获取信号量,获取不到则立刻返回正数

5)void up(struct semaphore * sem);               //释放信号量

3.2修改驱动程序(以down函数获取为例)

(1)定义互斥锁变量:

/*定义互斥锁button_lock,被用来后面的down()和up()使用 */
static DECLARE_MUTEX(button_lock); 

(2)在.open成员函数里添加:

/* 获取不到就进入不被中断的休眠状态(down函数中睡眠) */
          down(&button_lock);

(3)在. release成员函数里添加:

 /*         释放信号量          */
          up(&button_lock);     

驱动程序如下:

  1 #include <linux/module.h>
  2 #include <linux/kernel.h>
  3 #include <linux/fs.h>
  4 #include <linux/init.h>
  5 #include <linux/delay.h>
  6 #include <linux/irq.h>
  7 #include <asm/uaccess.h>
  8 #include <asm/irq.h>
  9 #include <asm/io.h>
 10 #include <asm/arch/regs-gpio.h>
 11 #include <asm/hardware.h>
 12 #include <linux/poll.h>
 13
 14
 15 static struct class *sixthdrv_class;
 16 static struct class_device    *sixthdrv_class_dev;
 17
 18 volatile unsigned long *gpfcon;
 19 volatile unsigned long *gpfdat;
 20
 21 volatile unsigned long *gpgcon;
 22 volatile unsigned long *gpgdat;
 23
 24
 25 static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
 26
 27 /* 中断事件标志, 中断服务程序将它置1,sixth_drv_read将它清0 */
 28 static volatile int ev_press = 0;
 29
 30 static struct fasync_struct *button_async;
 31
 32
 33 struct pin_desc{
 34     unsigned int pin;
 35     unsigned int key_val;
 36 };
 37
 38
 39 /* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
 40 /* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */
 41 static unsigned char key_val;
 42
 43 struct pin_desc pins_desc[4] = {
 44     {S3C2410_GPF0, 0x01},
 45     {S3C2410_GPF2, 0x02},
 46     {S3C2410_GPG3, 0x03},
 47     {S3C2410_GPG11, 0x04},
 48 };
 49
 50 static DECLARE_MUTEX(button_lock);    //定义互斥锁
 51 /*
 52  * 确定按键值
 53  */
 54 static irqreturn_t buttons_irq(int irq, void *dev_id)
 55 {
 56     struct pin_desc * pindesc = (struct pin_desc *)dev_id;
 57     unsigned int pinval;
 58
 59     pinval = s3c2410_gpio_getpin(pindesc->pin);
 60
 61     if (pinval)
 62     {
 63         /* 松开 */
 64         key_val = 0x80 | pindesc->key_val;
 65     }
 66     else
 67     {
 68         /* 按下 */
 69         key_val = pindesc->key_val;
 70     }
 71
 72     ev_press = 1;                  /* 表示中断发生了 */
 73     wake_up_interruptible(&button_waitq);   /* 唤醒休眠的进程 */
 74
 75     kill_fasync (&button_async, SIGIO, POLL_IN);
 76
 77     return IRQ_RETVAL(IRQ_HANDLED);
 78 }
 79
 80 static int sixth_drv_open(struct inode *inode, struct file *file)
 81 {
 82 #if 0
 83     if (!atomic_dec_and_test(&canopen))    //自减操作
 84     {
 85         atomic_inc(&canopen);    //原子变量加1
 86         return -EBUSY;
 87     }
 88 #endif
 89     /*获取信号量*/
 90     down(&button_lock);
 91     //若为第一次执行,则会获得信号量,第二次打开的话,就会进入休眠
 92
 93     /* 配置GPF0,2为输入引脚 */
 94     /* 配置GPG3,11为输入引脚 */
 95     request_irq(IRQ_EINT0,  buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[0]);
 96     request_irq(IRQ_EINT2,  buttons_irq, IRQT_BOTHEDGE, "S3", &pins_desc[1]);
 97     request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", &pins_desc[2]);
 98     request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", &pins_desc[3]);
 99
100     return 0;
101 }
102
103 ssize_t sixth_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
104 {
105     if (size != 1)
106         return -EINVAL;
107
108     if (file->f_flags & O_NONBLOCK)
109     {
110         if (!ev_press)
111             return -EAGAIN;
112     }
113     else
114     {
115         /* 如果没有按键动作, 休眠 */
116         wait_event_interruptible(button_waitq, ev_press);
117     }
118
119     /* 如果有按键动作, 返回键值 */
120     copy_to_user(buf, &key_val, 1);
121     ev_press = 0;
122
123     return 1;
124 }
125
126
127 int sixth_drv_close(struct inode *inode, struct file *file)
128 {
129     free_irq(IRQ_EINT0, &pins_desc[0]);
130     free_irq(IRQ_EINT2, &pins_desc[1]);
131     free_irq(IRQ_EINT11, &pins_desc[2]);
132     free_irq(IRQ_EINT19, &pins_desc[3]);
133     up(&button_lock);    /*释放信号量*/
134     return 0;
135 }
136
137 static unsigned sixth_drv_poll(struct file *file, poll_table *wait)
138 {
139     unsigned int mask = 0;
140     poll_wait(file, &button_waitq, wait); // 不会立即休眠
141
142     if (ev_press)
143         mask |= POLLIN | POLLRDNORM;
144
145     return mask;
146 }
147
148 static int sixth_drv_fasync (int fd, struct file *filp, int on)
149 {
150     printk("driver: sixth_drv_fasync\n");
151     return fasync_helper (fd, filp, on, &button_async);
152 }
153
154
155 static struct file_operations sencod_drv_fops = {
156     .owner   =  THIS_MODULE,    /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
157     .open    =  sixth_drv_open,
158     .read     =    sixth_drv_read,
159     .release =  sixth_drv_close,
160     .poll    =  sixth_drv_poll,
161     .fasync     =  sixth_drv_fasync,
162 };
163
164
165 int major;
166 static int sixth_drv_init(void)
167 {
168     major = register_chrdev(0, "sixth_drv", &sencod_drv_fops);
169
170     sixthdrv_class = class_create(THIS_MODULE, "sixth_drv");
171
172     sixthdrv_class_dev = class_device_create(sixthdrv_class, NULL, MKDEV(major, 0), NULL, "buttons"); /* /dev/buttons */
173
174     gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
175     gpfdat = gpfcon + 1;
176
177     gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
178     gpgdat = gpgcon + 1;
179
180     return 0;
181 }
182
183 static void sixth_drv_exit(void)
184 {
185     unregister_chrdev(major, "sixth_drv");
186     class_device_unregister(sixthdrv_class_dev);
187     class_destroy(sixthdrv_class);
188     iounmap(gpfcon);
189     iounmap(gpgcon);
190     return 0;
191 }
192
193
194 module_init(sixth_drv_init);
195
196 module_exit(sixth_drv_exit);
197
198 MODULE_LICENSE("GPL");

sixdrv2.c

测试程序同上一个。

测试:

下图,只有831进程在处于静止状态(没有中断触发)

832进程处于down休眠状态,直至831释放掉信号

灭掉进程831

多个信号量访问时, 会一个一个进程来排序访问

4.阻塞与非阻塞

4.1概念

  1. 阻塞,

    如果不满足条件会挂起,直到满足可操作的条件后再进行操作。

    被挂起的进程进入休眠状态,被从调度器的运行队列移走,直到等待的条件被满足。

    2. 非阻塞,

    不满足条件返回,进程在不能进行设备操作时并不挂起,它或者放弃,或者不停地查询,直至可以进行操作为止

4.2 怎么来判断阻塞与非阻塞操作?

1.在用户层open时,默认为阻塞操作,如果添加了” O_NONBLOCK”,表示使open()、read()、write()不被阻塞

实例:

fd = open("/dev/buttons",O_RDWR);    //使用阻塞操作
fd = open("/dev/buttons ", O_RDWR | O_NONBLOCK);   //非阻塞操作   

2.然后在驱动设备中,通过file_operations成员函数.open、.read、.write带的参数file->f_flags 来查看用户层访问时带的参数

实例:

1  if(  file->f_flags & O_NONBLOCK )   //非阻塞操作,获取不到则退出
2   {
3      ... ...
4   }
5   else   //阻塞操作,获取不到则进入休眠
6   {
7      ... ...
8   

4.3 修改应用程序,通过判断file->f_flags来使用阻塞操作还是非阻塞操作

(1)定义互斥锁变量:

/*定义互斥锁button_lock,被用来后面的down()和up()使用 */
static DECLARE_MUTEX(button_lock); 

(2)在.open成员函数里添加:

if( file->f_flags & O_NONBLOCK )   //非阻塞操作
  {
   if(down_trylock(&button_lock) )       //尝试获取信号量,获取不到则退出
            return -1;
  }
else   //阻塞操作
  {
     down(&button_lock);         //获取信号量,获取不到则进入休眠
  }

(3)在read成员函数里添加

ssize_t sixth_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
{
    if (size != 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;
}

(4)在. release成员函数里添加:

  /*释放信号量*/
  up(&button_lock);     

测试阻塞:

 1 int main(int argc,char **argv)
 2 {
 3   int oflag;
 4   unsigned int val=0;
 5   fd=open("/dev/buttons",O_RDWR);           //使用阻塞操作
 6   if(fd<0)
 7        {printf("can‘t open, fd=%d\n",fd);
 8        return -1;}
 9   else
10        {
11        printf("can open,PID=%d\n",getpid());    //打开成功,打印pid进程号
12        }
13
14    while(1)
15    {
16     val=read( fd, &ret, 1);              //读取驱动层数据
17      printf("key_vale=0X%x,retrun=%d\r\n",ret,val);
18    }
19    return 0;

测试非阻塞:

上面的测试程序

第5行:

fd=open("/dev/buttons",O_RDWR | O_NONBLOCK);

参考

原文地址:https://www.cnblogs.com/y4247464/p/10113869.html

时间: 2024-08-28 15:50:23

字符设备驱动------同步互斥阻塞的相关文章

Linux 设备驱动--- 阻塞型字符设备驱动 --- O_NONBLOCK --- 非阻塞标志【转】

转自:http://blog.csdn.net/yikai2009/article/details/8653697 版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[-] 阻塞 阻塞操作 非阻塞操作 阻塞方式-read- 实现 阻塞方式-write- 实现 非阻塞方式的读写操作 实例 --- 读阻塞的实现 实例 --- 按键驱动阻塞实现 1在 open 函数 查看看是 阻塞方式 还是 非阻塞方式 2在 read 函数中同样查看 3应用程序中 1以阻塞方式运行 2以非阻塞方式运行

字符驱动程序之——同步互斥阻塞

1. 原子操作 原子操作指的是在执行过程中不会被别的代码路径所中断的操作.常用原子操作函数举例:atomic_t v = ATOMIC_INIT(0); //定义原子变量v并初始化为0atomic_read(atomic_t *v); //返回原子变量的值void atomic_inc(atomic_t *v); //原子变量增加1void atomic_dec(atomic_t *v); //原子变量减少1int atomic_dec_and_test(atomic_t *v); //自减操作

入门级的按键驱动——按键驱动笔记之poll机制-异步通知-同步互斥阻塞-定时器防抖

文章对应视频的第12课,第5.6.7.8节. 在这之前还有查询方式的驱动编写,中断方式的驱动编写,这篇文章中暂时没有这些类容.但这篇文章是以这些为基础写的,前面的内容有空补上. 按键驱动——按下按键,打印键值: 目录 概要 poll机制 异步通知 同步互斥阻塞 定时器防抖 概要: 查询方式: 12-3 缺点:占用CPU99%的资源.中断方式:12-4 缺点:调用read函数后如果没有按键按下,该函数永远不会结束,一直在等待按键按下. 优点:使用到了休眠机制,占用cpu资源极少.poll机制: 1

Linux设备驱动中的阻塞和非阻塞I/O

[基本概念] 1.阻塞 阻塞操作是指在执行设备操作时,托不能获得资源,则挂起进程直到满足操作所需的条件后再进行操作.被挂起的进程进入休眠状态(不占用cpu资源),从调度器的运行队列转移到等待队列,直到条件满足. 2.非阻塞 非阻塞操作是指在进行设备操作是,若操作条件不满足并不会挂起,而是直接返回或重新查询(一直占用CPU资源)直到操作条件满足为止. 当用户空间的应用程序调用read(),write()等方法时,若设备的资源不能被获取,而用户又希望以阻塞的方式来访问设备,驱动程序应当在设备驱动层的

深入浅出~Linux设备驱动之字符设备驱动

一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用驱动程序: 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面向流的设备,常见的字符设备有鼠标.键盘.串口.控制台和LED设备等. 块设备:是指可以从设备的任意位置读取一定长度数据的设备.块设备包括硬盘.磁盘.U盘和SD卡等. 每一个字符设备或块设备都在/dev目录下对应一个设备文件.linux用户程序通过设备文件(或称设备节点)来使用驱动程序操作字符设备和块设备

【转】深入浅出:Linux设备驱动之字符设备驱动

深入浅出:Linux设备驱动之字符设备驱动 一.linux系统将设备分为3类:字符设备.块设备.网络设备.使用驱动程序: 字符设备:是指只能一个字节一个字节读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后数据.字符设备是面向流的设备,常见的字符设备有鼠标.键盘.串口.控制台和LED设备等. 块设备:是指可以从设备的任意位置读取一定长度数据的设备.块设备包括硬盘.磁盘.U盘和SD卡等. 每一个字符设备或块设备都在/dev目录下对应一个设备文件.linux用户程序通过设备文件(或称

Linux设备驱动之字符设备驱动

一.linux系统将设备分为3类:字符设备.块设备.网络设备. 应用程序调用的流程框图: 三种设备的定义分别如下, 字符设备:只能一个字节一个字节的读写的设备,不能随机读取设备内存中的某一数据,读取数据需要按照先后顺序进行.字符设备是面向流的设备,常见的字符设备如鼠标.键盘.串口.控制台.LED等. 块设备:是指可以从设备的任意位置读取一定长度的数据设备.块设备如硬盘.磁盘.U盘和SD卡等存储设备. 网络设备:网络设备比较特殊,不在是对文件进行操作,而是由专门的网络接口来实现.应用程序不能直接访

20150518 字符设备驱动

20150518 字符设备驱动 2015-05-18 Lover雪儿 经过这两个月的学习,相信对设备驱动的编写已经有一个大概的了解了,温故而知新,此处我们再一次的系统性的复习一下字符设备驱动,然后,我们来尝试着自己从零实战写一个AD采集的字符设备驱动. 以前学习使用的是老方法来注册字符设备驱动,此处我们使用字符设备的新方法来学习. 本文参考:华清远见的Linux 设备驱动开发详解-字符设备驱动,具体还请看作者原书 一.cdev结构体 1 struct cdev{ 2 struct kobject

linux驱动学习(1)——字符设备驱动开发

(一)驱动程序介绍 (a)Linux驱动程序学习 知识结构: 1. Linux驱动程序设计模式(40%) 2. 内核相关知识(30%) 3. 硬件相关知识(30%) (b)驱动分类: ①字符设备: 字符设备是一种按字节来访问的设备,字符驱动则负责驱动字符设备,这样的驱动通常实现 open, close,read和 write 系统调用. ②块设备: 在大部分的 Unix 系统, 块设备不能按字节处理数据,只能一次传送一个或多个长度是512字节( 或一个更大的 2 次幂的数 )的整块数据,而Lin