国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統 > Linux > 正文

從零開始寫linux字符設備驅動程序(三)(基于友善之臂tiny4412開發板)

2024-06-28 16:05:24
字體:
來源:轉載
供稿:網友

這一節,我們再來看看新的知識點,這一次,我們將進一步完善這個字符設備的驅動程序。

首先,將上一節的代碼做下修改:

#include <linux/init.h>#include <linux/module.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/cdev.h>#include <linux/fs.h>#include <linux/slab.h>//創建一個字符設備struct char_dev{    struct cdev c_dev ;    dev_t dev_num ;    char buf[1024];  };int my_open(){    PRintk("cdev open");	}int my_close(){    printk("cdev del");}struct file_Operations my_ops = {	.open = my_open,	.release = my_close ,};struct char_dev *test_dev ;static int __init  cdev_test_init(void){	int ret ;	//1、給字符設備結構分配內存	test_dev = kmalloc(sizeof(*test_dev),GFP_KERNEL);	if(!test_dev){	   ret = -ENOMEM ;	   goto malloc_dev_fair;	}	//2、申請設備號并注冊字符設備	ret = alloc_chrdev_region(&test_dev->dev_num,1,1,"test_dev");	if(ret < 0){	   goto alloc_chrdev_fair ;	}	//3、初始化字符設備	cdev_init(&test_dev->dev_num , &my_ops);	//4、添加一個字符設備	ret = cdev_add(&test_dev->c_dev,test_dev->dev_num,1);		if(ret < 0){	   goto cdev_add_fair;	}	my_open();	return 0 ;	cdev_add_fair:	return ret ;	malloc_dev_fair :	return ret  ;	alloc_chrdev_fair :	return ret ;}static int __exit cdev_test_exit(void){	//刪除設備	cdev_del(&test_dev->c_dev);	//注銷驅動-->后面寫1表示從dev_no開始連續一個	unregister_chrdev_region(test_dev->dev_num,1);	return 0 ;}module_init(cdev_test_init);module_exit(cdev_test_exit);MODULE_LICENSE("GPL");在代碼中,我們要實現一個虛擬的字符設備,這個設備很簡單,只不過更加豐富了。

我們首先創建一個字符設備,用一個結構體char_dev來表示。

對結構體分配內存,然后申請設備號并注冊,最后初始化,再將這個字符設備加到內核里去,一旦這些操作成功后,將調用my_open函數。

這就是一個字符設備的最基本構成。

上節我們已經說過alloc_chrdev_region這個函數的作用。

那么這節多了file_operations這個結構體,它的功能是什么?

當一個字符設備被注冊后,我們隨即就要來操作這個字符設備,open  , read , write , close等操作。

如下代碼:

struct file_operations {	struct module *owner;	loff_t (*llseek) (struct file *, loff_t, int);	ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);	ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);	ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);	ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);	int (*readdir) (struct file *, void *, filldir_t);	unsigned int (*poll) (struct file *, struct poll_table_struct *);	long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);	long (*compat_ioctl) (struct file *, unsigned int, unsigned long);	int (*mmap) (struct file *, struct vm_area_struct *);	int (*open) (struct inode *, struct file *);	int (*flush) (struct file *, fl_owner_t id);	int (*release) (struct inode *, struct file *);	int (*fsync) (struct file *, loff_t, loff_t, int datasync);	int (*aio_fsync) (struct kiocb *, int datasync);	int (*fasync) (int, struct file *, int);	int (*lock) (struct file *, int, struct file_lock *);	ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);	unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);	int (*check_flags)(int);	int (*flock) (struct file *, int, struct file_lock *);	ssize_t (*splice_write)(struct pipe_inode_info *, struct file *, loff_t *, size_t, unsigned int);	ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);	int (*setlease)(struct file *, long, struct file_lock **);	long (*fallocate)(struct file *file, int mode, loff_t offset,			  loff_t len);};那么內核是如何去識別相應的函數呢?

是通過系統調用

在上層應用程序,打個比方。

通過open()打印相應的設備,那么syscall函數就會通過系統調用號識別到內核態里的函數,進而調用到我們這里實現的my_open,這就是內核態和用戶態相互溝通的方式。

這里我就不去寫相應的應用程序了,以前也寫過了,我就直接將open函數調用放在init函數,隨著字符設備注冊并執行。

這樣將zImage下載到開發板上,串口上也是可以打印cdev_open的。

不知道怎么用應用程序去讀寫設備的可以參考以下文章:

http://blog.csdn.net/morixinguan/article/details/50619675

接下來看看本節使用的函數:

void cdev_init(struct cdev *, const struct file_operations *);

int cdev_add(struct cdev *, dev_t, unsigned);void cdev_del(struct cdev *);

static __always_inline void *kmalloc(size_t size, gfp_t flags);

留心的小伙伴會發現,在exit函數中,我沒有對內存進行釋放,這里是故意這么做的,為了提醒粗心的伙伴,在內核中,分配的內存一定要釋放的。

釋放調用函數:

void kfree(const void *objp)


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 安塞县| 民乐县| 大连市| 荆州市| 区。| 潮州市| 尼勒克县| 蒙阴县| 雅江县| 内丘县| 连南| 维西| 南澳县| 定州市| 金华市| 堆龙德庆县| 集贤县| 文安县| 九台市| 新邵县| 会泽县| 河东区| 即墨市| 武胜县| 墨竹工卡县| 洪泽县| 嵊州市| 绥滨县| 左权县| 东丽区| 庆城县| 洱源县| 昌邑市| 拜泉县| 壤塘县| 潞城市| 贡觉县| 磐石市| 双鸭山市| 屏东县| 漠河县|