栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

Linux驱动学习记录-新字符设备

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Linux驱动学习记录-新字符设备

        第一节介绍了字符驱动设备,开发重点是register_chrdev注册字符设备,unregister_chrdev注销字符设备。驱动加载需要mknod命令创建节点。这些都是老版本,现在学习新字符设备驱动开发。第一节提了一点点,申请设备号是用自动分配的方式就是新设备开发。

 

1.新字符设备注册

        Linux中cdev结构体表示一个字符设备,在include/linux/cdev.h中,定义如下

//字符结构体  重点是 dev和ops
struct cdev {
	struct kobject kobj;                //内嵌的内核对象
	struct module *owner;               //该字符设备所在的内核模块的对象指针.
	const struct file_operations *ops;  //操作函数结构体,描述所实现的方法,极为重要的结构体
	struct list_head list;              //用来将已经向内核注册的所有字符设备形成链表
	dev_t dev;                          //设备号结构体,主号和次号
	unsigned int count;                 //隶属于同一主设备号的次设备号的个数
};


//相关操作函数
void cdev_init(struct cdev *, const struct file_operations *);

struct cdev *cdev_alloc(void);

void cdev_put(struct cdev *p);

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

void cdev_del(struct cdev *);

void cd_forget(struct inode *);

一个简单例子介绍其结构体和函数的用法:

struct cdev devtest; //定义字符设备结构体
dev_t dev;           //定义设备号结构体

struct file_operations opstest = {
	.owner = THIS_MODULE,
};                   //定义操作函数结构体

cdev_init (&devtest, &opstest);  //初始化字符设备,加入操作函数
cdev_add (&devtest, dev, 1);     //添加字符设备,dev是设备号,添加1个
cdev_del (&devtest);             //删除字符设备结构体
2.自动创建设备节点

        以前我们通过命令mknod手动创建设备节点,一个设备节点其实就是设备文件,Linux中成为设备文件。在Linux中,所有设备的访问都是文件访问。接下来介绍自动创建设备节点,在驱动中实现后,通过modprobe加载驱动后,会自动在/dev目录下创建对应的设备文件。

        Linux下通过udev来实现设备文件的创建和删除,使用busybox构建根文件系统的时候,busybox会创建一个udev的简化版本-mdev,嵌入式linux中我们使用mdev来实现设备节点的安装删除。

        首先要创建class类结构体,然后创建设备结构体。他们的定义都在include/linux/device.h中,在353行和723行,可自行查看其结构体内成员及其作用。

//480行,定义class结构体创建的别名
extern struct class * __must_check __class_create(struct module *owner,
						  const char *name,
						  struct lock_class_key *key);
extern void class_destroy(struct class *cls);


#define class_create(owner, name)		
({						
	static struct lock_class_key __key;	
	__class_create(owner, name, &__key);	
})

//因此输入参数只有两个
struct class *class_create (struct module *owner, const char *name)
  • owner:一般为THIS_MODULE;
  • name:类的名字。
  • return:返回值是一个指向name(class结构体)的指针。

        创建好类以后,还不能实现自动创建设备节点,还需要在这个类下面创建设备(相当于mknod),使用device_create命令来创建。

struct device *device_create(struct class *class,
                            struct device *parent,
                            dev_t devt,
                            void *drvdata,
                            const char *fmt, ...)
  • class:这个设备创建在哪个类下面,class指针指向刚刚创建的“name”。
  • parent:这个设备的父设备,一般是NULL。
  • devt:设备号结构体,由主号和次号构成。
  • drvdata:设备可能会使用的一些数据,一般是NULL。
  • fmt:是设备名字,如果fmt=XXX,就会生成/dev/XXX这个设备
  • 。。。:还有其他参数略。
  • return:创建好的设备结构体指针。

参考例子如下:

struct class *led_class;    //led类的结构体
struct device *led_device;  //led设备结构体
dev_t devid;                //led设备号结构体


static int __init led_init(void)
{
    led_class = class_creat(THIS_MODULE, "led");                       //创建led类
    led_device = device_cerat(led_class, NULL, devid, NULL, "led");    //创建led设备
    return 0;
}

static void __exit led_exit(void)
{
    device_destroy(led_class, devid);   //注销led设备
    class_destroy(led_class);           //注销led类
}

module_init(led_init);
module_exit(led_exit);
3.设置设备文件私有数据

        列举一下前两小节涉及的变量类型:

  1. struct cdev          //cdev设备结构体
  2. dev_t                   //设备号结构体
  3. struct class          //类结构体
  4. struct device        //设备结构体

现在我们把这些变量设置为结构体属性,用来描述一个驱动设备。

struct test_dev{
                dev_t devid;             
                struct cdev cdev;        
                struct class *class;     
                struct device *device;   
                int major;               
                int minor;               
};

struct test_dev testdev;



static int test_open(struct inode *inode, struct file *filp)
{
    filp->private_data = &testdev; 
    return 0;
}

        这里做出补充:struct inode结构体用于描述设备文件的静态属性,包含但不限于dev_t 、cdev等变量描述。mknod每创建一个节点,都会对应一个唯一的inode结构体。struct file是文件结构体代表打开的文件,系统中每个打开的文件在内核空间中都会对应一个file结构体,在文件关闭后,内核会释放这个数据结构。详见:Linux--struct file结构体 - Sophie_h - 博客园。

        下图展示各个部分的调用关系:

4.程序编写

下面摘取正点原子的部分程序/03_newchrled。

#define NEWCHRLED_CNT			1		  	
#define NEWCHRLED_NAME			"newchrled"	
#define LEDOFF 					0			
#define LEDON 					1			
 





struct newchrled_dev{
	dev_t devid;			
	struct cdev cdev;		
	struct class *class;		
	struct device *device;	
	int major;				
	int minor;				
};

struct newchrled_dev newchrled;	


static int led_open(struct inode *inode, struct file *filp)
{
	filp->private_data = &newchrled; 
	return 0;
}



static struct file_operations newchrled_fops = {
	.owner = THIS_MODULE,
	.open = led_open,
	.read = led_read,
	.write = led_write,
	.release = 	led_release,
};


static int __init led_init(void)
{
	u32 val = 0;

	
	

	

	
	 
	

	

	
	
	if (newchrled.major) {		
		newchrled.devid = MKDEV(newchrled.major, 0);
		register_chrdev_region(newchrled.devid, NEWCHRLED_CNT, NEWCHRLED_NAME);
	} else {						
		alloc_chrdev_region(&newchrled.devid, 0, NEWCHRLED_CNT, NEWCHRLED_NAME);	
		newchrled.major = MAJOR(newchrled.devid);	
		newchrled.minor = MINOR(newchrled.devid);	
	}
	printk("newcheled major=%d,minor=%drn",newchrled.major, newchrled.minor);	
	
	
	newchrled.cdev.owner = THIS_MODULE;
	cdev_init(&newchrled.cdev, &newchrled_fops);
	
	
	cdev_add(&newchrled.cdev, newchrled.devid, NEWCHRLED_CNT);

	
	newchrled.class = class_create(THIS_MODULE, NEWCHRLED_NAME);
	if (IS_ERR(newchrled.class)) {
		return PTR_ERR(newchrled.class);
	}

	
	newchrled.device = device_create(newchrled.class, NULL, newchrled.devid, NULL, NEWCHRLED_NAME);
	if (IS_ERR(newchrled.device)) {
		return PTR_ERR(newchrled.device);
	}
	
	return 0;
}


static void __exit led_exit(void)
{
	
	iounmap(IMX6U_CCM_CCGR1);
	iounmap(SW_MUX_GPIO1_IO03);
	iounmap(SW_PAD_GPIO1_IO03);
	iounmap(GPIO1_DR);
	iounmap(GPIO1_GDIR);

	
	cdev_del(&newchrled.cdev);
	unregister_chrdev_region(newchrled.devid, NEWCHRLED_CNT); 

	device_destroy(newchrled.class, newchrled.devid);
	class_destroy(newchrled.class);
}

module_init(led_init);
module_exit(led_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("zuozhongkai");
5.测试

与第三小节一样。

6.附录结构图

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/291079.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号