Linux驱动开发基础__阻塞与非阻塞
创始人
2024-05-23 00:30:13
0

目录

1 引入

2 应用编程

3 驱动编程

4 代码

4.1 gpio_key_drv.c

4.2 button_test.c


1 引入

所谓阻塞,就是等待某件事情发生。比如调用 read 读取按键时,如果没有按键数据则 read 函数不会返回,它会让线程休眠等待。 
使用 poll 时,如果传入的超时时间不为 0,这种访问方法也是阻塞的。 
使用 poll 时,可以设置超时时间为 0,这样即使没有数据它也会立刻返回,这就是非阻塞方式。能不能让 read 函数既能工作于阻塞方式,也可以工作于非阻塞方式?可以! 
APP 调用 open 函数时,传入 O_NONBLOCK,就表示要使用非阻塞方式;默认是阻塞方式。 
注意:对于普通文件、块设备文件,O_NONBLOCK 不起作用。 
注 意 : 对 于 字 符 设 备 文 件 , O_NONBLOCK 起 作 用 的 前 提 是 驱 动 程 序 针 O_NONBLOCK 做了处理。 
只能在 open 时表明 O_NONBLOCK 吗?在 open 之后,也可以通过 fcntl 修改为阻塞或非阻塞。 

2 应用编程

open 时设置: 

int  fd = open(“/dev/xxx”, O_RDWR | O_NONBLOCK);  /* 非阻塞方式 */ 
int  fd = open(“/dev/xxx”, O_RDWR );  /* 阻塞方式 */ 

open 之后设置: 

int flags = fcntl(fd, F_GETFL); 
fcntl(fd, F_SETFL, flags | O_NONBLOCK);  /* 非阻塞方式 */ 
fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);  /* 阻塞方式 */ 

 3 驱动编程

以 drv_read 为例: 

static ssize_t drv_read(struct file *fp, char __user *buf, size_t count, loff_t *ppo
s) 
{   
if (queue_empty(&as->queue) && fp->f_flags & O_NONBLOCK) return -EAGAIN; wait_event_interruptible(apm_waitqueue, !queue_empty(&as->queue)); …… 
} 

从驱动代码也可以看出来,当 APP 打开某个驱动时,在内核中会有一个struct  file 结构体对应这个驱动,这个结构体中有 f_flags,就是打开文件时的标记位;可以设置 f_flasgs 的 O_NONBLOCK 位,表示非阻塞;也可以清除这个位表示阻塞。 
驱动程序要根据这个标记位决定事件未就绪时是休眠和还是立刻返回。 

4 代码

4.1 gpio_key_drv.c

#include 
#include #include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include struct gpio_key{int gpio;struct gpio_desc *gpiod;int flag;int irq;
} ;static struct gpio_key *gpio_keys_100ask;/* 主设备号                                                                 */
static int major = 0;
static struct class *gpio_key_class;/* 环形缓冲区 */
#define BUF_LEN 128
static int g_keys[BUF_LEN];
static int r, w;struct fasync_struct *button_fasync;#define NEXT_POS(x) ((x+1) % BUF_LEN)static int is_key_buf_empty(void)
{return (r == w);
}static int is_key_buf_full(void)
{return (r == NEXT_POS(w));
}static void put_key(int key)
{if (!is_key_buf_full()){g_keys[w] = key;w = NEXT_POS(w);}
}static int get_key(void)
{int key = 0;if (!is_key_buf_empty()){key = g_keys[r];r = NEXT_POS(r);}return key;
}static DECLARE_WAIT_QUEUE_HEAD(gpio_key_wait);/* 实现对应的open/read/write等函数,填入file_operations结构体                   */
static ssize_t gpio_key_drv_read (struct file *file, char __user *buf, size_t size, loff_t *offset)
{//printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);int err;int key;if (is_key_buf_empty() && (file->f_flags & O_NONBLOCK))return -EAGAIN;wait_event_interruptible(gpio_key_wait, !is_key_buf_empty());key = get_key();err = copy_to_user(buf, &key, 4);return 4;
}static unsigned int gpio_key_drv_poll(struct file *fp, poll_table * wait)
{printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);poll_wait(fp, &gpio_key_wait, wait);return is_key_buf_empty() ? 0 : POLLIN | POLLRDNORM;
}static int gpio_key_drv_fasync(int fd, struct file *file, int on)
{if (fasync_helper(fd, file, on, &button_fasync) >= 0)return 0;elsereturn -EIO;
}/* 定义自己的file_operations结构体                                              */
static struct file_operations gpio_key_drv = {.owner	 = THIS_MODULE,.read    = gpio_key_drv_read,.poll    = gpio_key_drv_poll,.fasync  = gpio_key_drv_fasync,
};static irqreturn_t gpio_key_isr(int irq, void *dev_id)
{struct gpio_key *gpio_key = dev_id;int val;int key;val = gpiod_get_value(gpio_key->gpiod);printk("key %d %d\n", gpio_key->gpio, val);key = (gpio_key->gpio << 8) | val;put_key(key);wake_up_interruptible(&gpio_key_wait);kill_fasync(&button_fasync, SIGIO, POLL_IN);return IRQ_HANDLED;
}/* 1. 从platform_device获得GPIO* 2. gpio=>irq* 3. request_irq*/
static int gpio_key_probe(struct platform_device *pdev)
{int err;struct device_node *node = pdev->dev.of_node;int count;int i;enum of_gpio_flags flag;printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);count = of_gpio_count(node);if (!count){printk("%s %s line %d, there isn't any gpio available\n", __FILE__, __FUNCTION__, __LINE__);return -1;}gpio_keys_100ask = kzalloc(sizeof(struct gpio_key) * count, GFP_KERNEL);for (i = 0; i < count; i++){gpio_keys_100ask[i].gpio = of_get_gpio_flags(node, i, &flag);if (gpio_keys_100ask[i].gpio < 0){printk("%s %s line %d, of_get_gpio_flags fail\n", __FILE__, __FUNCTION__, __LINE__);return -1;}gpio_keys_100ask[i].gpiod = gpio_to_desc(gpio_keys_100ask[i].gpio);gpio_keys_100ask[i].flag = flag & OF_GPIO_ACTIVE_LOW;gpio_keys_100ask[i].irq  = gpio_to_irq(gpio_keys_100ask[i].gpio);}for (i = 0; i < count; i++){err = request_irq(gpio_keys_100ask[i].irq, gpio_key_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, "100ask_gpio_key", &gpio_keys_100ask[i]);}/* 注册file_operations 	*/major = register_chrdev(0, "100ask_gpio_key", &gpio_key_drv);  /* /dev/gpio_key */gpio_key_class = class_create(THIS_MODULE, "100ask_gpio_key_class");if (IS_ERR(gpio_key_class)) {printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);unregister_chrdev(major, "100ask_gpio_key");return PTR_ERR(gpio_key_class);}device_create(gpio_key_class, NULL, MKDEV(major, 0), NULL, "100ask_gpio_key"); /* /dev/100ask_gpio_key */return 0;}static int gpio_key_remove(struct platform_device *pdev)
{//int err;struct device_node *node = pdev->dev.of_node;int count;int i;device_destroy(gpio_key_class, MKDEV(major, 0));class_destroy(gpio_key_class);unregister_chrdev(major, "100ask_gpio_key");count = of_gpio_count(node);for (i = 0; i < count; i++){free_irq(gpio_keys_100ask[i].irq, &gpio_keys_100ask[i]);}kfree(gpio_keys_100ask);return 0;
}static const struct of_device_id ask100_keys[] = {{ .compatible = "100ask,gpio_key" },{ },
};/* 1. 定义platform_driver */
static struct platform_driver gpio_keys_driver = {.probe      = gpio_key_probe,.remove     = gpio_key_remove,.driver     = {.name   = "100ask_gpio_key",.of_match_table = ask100_keys,},
};/* 2. 在入口函数注册platform_driver */
static int __init gpio_key_init(void)
{int err;printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);err = platform_driver_register(&gpio_keys_driver); return err;
}/* 3. 有入口函数就应该有出口函数:卸载驱动程序时,就会去调用这个出口函数*     卸载platform_driver*/
static void __exit gpio_key_exit(void)
{printk("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__);platform_driver_unregister(&gpio_keys_driver);
}/* 7. 其他完善:提供设备信息,自动创建设备节点                                     */module_init(gpio_key_init);
module_exit(gpio_key_exit);MODULE_LICENSE("GPL");

4.2 button_test.c


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include static int fd;/** ./button_test /dev/100ask_button0**/
int main(int argc, char **argv)
{int val;struct pollfd fds[1];int timeout_ms = 5000;int ret;int	flags;int i;/* 1. 判断参数 */if (argc != 2) {printf("Usage: %s \n", argv[0]);return -1;}/* 2. 打开文件 */fd = open(argv[1], O_RDWR | O_NONBLOCK);if (fd == -1){printf("can not open file %s\n", argv[1]);return -1;}for (i = 0; i < 10; i++) {if (read(fd, &val, 4) == 4)printf("get button: 0x%x\n", val);elseprintf("get button: -1\n");}flags = fcntl(fd, F_GETFL);fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);while (1){if (read(fd, &val, 4) == 4)printf("get button: 0x%x\n", val);elseprintf("while get button: -1\n");}close(fd);return 0;
}

相关内容

热门资讯

圣诞晚会主持词开场白 圣诞晚会主持词开场白(通用12篇)  在社会发展不断提速的今天,我们使用到开场白的机会越来越多,独具...
新春年会主持词 新春年会主持词范文(精选5篇)  主持词的写作要突出活动的主旨并贯穿始终。在当下的社会中,各种集会中...
老年人生日司仪主持词 老年人生日司仪主持词  主持词要把握好吸引观众、导入主题、创设情境等环节以吸引观众。我们眼下的社会,...
庆元旦主持词 精选庆元旦主持词3篇  主持人在台上表演的灵魂就表现在主持词中。在当下的中国社会,各种场合中活跃现场...
农村结婚典礼司仪主持词 农村结婚典礼司仪主持词(通用6篇)  主持词是主持人在台上表演的灵魂之所在。在人们越来越多的参与各种...
升学宴学生家长致辞 升学宴学生家长致辞  在日复一日的学习、工作或生活中,要用到致辞的地方还是很多的,致辞具有能伸能缩,...
家长道德讲堂主持词 家长道德讲堂主持词  道德讲堂就是一个引导人们讲道德,让人长好心的地方。崇德向善是我们中华民族的传统...
沙龙活动主持词 沙龙活动主持词(通用9篇)  主持词是各种演出活动和集会中主持人串联节目的串联词。在人们越来越多的参...
《纨绔》的经典台词 《纨绔》的经典台词  1、庸脂俗粉算得了什么?狐王才是真绝色。傻一时且说天作孽。傻一世便是自作孽了。...
电影王家卫堕落天使经典台词 电影王家卫堕落天使经典台词  李嘉欣和黎明相对无言。  李嘉欣扬着脸,拿烟的手略微颤抖,一枚偌大的闪...
升旗仪式主持词 升旗仪式主持词  主持词是各种演出活动和集会中主持人串联节目的串联词。在当今不断发展的世界,主持词是...
欢乐颂的经典台词有哪些 欢乐颂的经典台词有哪些  《欢乐颂》讲述了同住在欢乐颂小区22楼的五个来自不同家庭、性格迥异的女孩们...
女儿出嫁父母致辞 女儿出嫁父母致辞女儿出嫁父母致辞中国有句老话——“当众教子,背后教妻”。因此,在今天这个场合,请允许...
六一主持词 六一主持词15篇  主持词分为会议主持词、晚会主持词、活动主持词、婚庆主持词等。在当今社会生活中,主...
教育机构开业主持词 教育机构开业主持词  主持词分为会议主持词、晚会主持词、活动主持词、婚庆主持词等。在当今不断发展的世...
琅玡榜经典台词 琅玡榜经典台词  1、人只会被朋友背叛,敌人是永远都没有‘出卖’和‘背叛’的机会的。  2、只要你没...
王家卫经典台词 王家卫经典台词  王家卫相信大家都熟悉,他是香港电影导演、监制及编剧,擅长文艺电影。给我们带来了许多...
甄嬛传的经典台词合集 甄嬛传的经典台词合集  在社会发展不断提速的今天,需要使用台词的场合越来越多,台词是用以展示剧情,刻...
追悼会告别仪式主持词 追悼会告别仪式主持词  一位熟识的人突然离开,我们的心情总是沉重,怀着不舍之情为他办一场追悼会,对追...
mc天开场麦词 mc天开场麦词集锦  篇一:MC麦词开场  1.在这个穿越时尚魅力的快乐都市 让我的音乐点缀魅力的极...