嵌入式系统驱动高级【1】——设备模型

# 一、起源

仅devfs,导致开发不方便以及一些功能难以支持:

1. 热插拔

    2. 不支持一些针对所有设备的统一操作(如电源管理)

    3. 不能自动mknod

    4. 用户查看不了设备信息

    5. 设备信息硬编码,导致驱动代码通用性差,即没有分离设备和驱动

# 二、新方案

uevent机制:sysfs + uevent + udevd(上层app)

## 2.1 sysfs: 一种用内存模拟的文件系统,系统启动时mount到/sys目录

sysfs用途:(类似于windows的设备管理器)

1. 建立系统中总线、驱动、设备三者之间的桥梁

2. 向用户空间展示内核中各种设备的拓扑图

3. 提供给用户空间对设备获取信息和操作的接口,部分取代ioctl功能

| **sysfs在内核中的组成要素** | **在用户空间/sys下的显示** |

| --------------------------- | -------------------------- |

| 内核对象(kobject)         | 目录                       |

| 对象属性(attribute)       | 文件                       |

| 对象关系(relationship)    | 链接(Symbolic Link)      |

四个基本结构

 

目录组织结构:

 



 

## 2.2 uevent

 





 

# 三、代码中自动mknod

```c

struct class *class_create(struct module *owner, const char *name);

/*

 * 功能:在/sys/class生成一个目录,目录名由name指定

 * 参数:

    struct module *owner - THIS_MODULE

    const char *name - 目录名

 * 返回值  成功:class指针   失败:NULL

*/

/*

辅助接口:可以定义一个struct class 的指针变量cls来接受返回值,然后通过IS_ERR(cls)判断是否失败;

IS_ERR(cls);成功----------------->0

IS_ERR(cls);失败----------------->非0

PTR_ERR(cls);来获得失败的返回错误码;

*/

```

```c

void class_destroy(struct class *cls)

/*

* 功能:删除class_create生成目录

* 参数:

    struct class *cls - class指针

* 返回值

*/

```

```c

struct device *device_create(struct class *class, struct device *parent,

                 dev_t devt, void *drvdata, const char *fmt, ...)

/*

 * 功能:在/sys/class目录下class_create生成目录再生成一个子目录与该设备相对应,发uevent让应用程序udevd创建设备文件

 * 参数:

    struct class *class - class指针

    struct device *parent - 父对象,一般NULL

    dev_t devt - 设备号

    void *drvdata - 驱动私有数据,一般NULL

    const char *fmt - 字符串的格式

     ... - 不定参数

 * 返回值

    成功:device指针

    失败:NULL

 */

```

```c

void device_destroy(struct class *class, dev_t devt)

/*

 * 功能:删除device_create生成目录

 * 参数:

    struct class *class - class指针

    dev_t devt - 设备号

 * 返回值

*/

```

结构体新加两个成员

在init中添加: 

exit中: 

 

 

.c驱动代码:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <asm/atomic.h>
#include <linux/sched.h>
#include <linux/device.h>
#include <asm/uaccess.h>

#define BUF_LEN 100


struct mysecond_dev {
	struct cdev mydev;
	struct timer_list timer;
	atomic_t open_flag;
	int second;
	struct class *pcls;
	struct device *pdev;
};

int major = 11;
int minor = 0;
int num = 1;

struct mysecond_dev gmydev;

void Timer_function(unsigned long arg)
{
	struct mysecond_dev *pgmydev = (struct mysecond_dev *) arg;
	pgmydev->second ++;
	
	mod_timer(&gmydev.timer, jiffies + 1*HZ);
}

int myopen (struct inode *pnode, struct file *pfile)
{
	struct mysecond_dev *pgmydev = NULL;
	pfile->private_data = (void *)container_of(pnode->i_cdev,struct mysecond_dev,mydev);
	pgmydev = (struct mysecond_dev *)pfile->private_data;

	if(atomic_dec_and_test(&pgmydev->open_flag))
	{
		pgmydev->timer.expires = jiffies + 1*HZ;
		pgmydev->timer.function = Timer_function;
		pgmydev->timer.data = (unsigned long)pgmydev;
		add_timer(&pgmydev->timer);	
		
		return 0;
	}
	else
	{
		atomic_inc(&pgmydev->open_flag);
		printk("The device is open already\n");
		return -1;
	}
	

	return 0;
}
 
int myclose (struct inode *pnode, struct file *pfile)
{
	struct mysecond_dev *pgmydev = (struct mysecond_dev *)pfile->private_data;
	atomic_set(&gmydev.open_flag,1);
	del_timer(&pgmydev->timer);

	return 0;
}

ssize_t myread(struct file *filp, char __user *pbuf, size_t count, loff_t *ppos)
{
	struct mysecond_dev *pgmydev = (struct mysecond_dev *)filp->private_data;
	int ret = 0;
	
	if(count < sizeof(int))
	{
		printk("the expect read count is invalid.\n");
		return -1;
	}
	if(count >= sizeof(int))
	{
		count = sizeof(int);
	}

	ret = copy_to_user(pbuf,&pgmydev->second,count);
	if(ret)
	{
		printk("myread copy_to_user failed.\n");
		return -1;
	}	

	return count;
}

struct file_operations myops = {
	.owner = THIS_MODULE,
	.open = myopen,
	.read = myread,
	.release = myclose,
};


int __init atomic_init(void)
{
	int ret = 0;

	dev_t devno = MKDEV(major,minor);
	ret = register_chrdev_region(devno,num,"mysecond");
 
	if(ret)
	{
		ret = alloc_chrdev_region(&devno,minor,num,"mysecond");
		if(ret)
		{
			printk("devno failed.\n");
			return -1;
		}
		major = MAJOR(devno);
		minor = MINOR(devno);
	}
 
	/*给mydev指定操作函数集*/
	cdev_init(&gmydev.mydev,&myops);

	/*将mydev添加到内核对应的数据结构里*/
	gmydev.mydev.owner = THIS_MODULE;
	cdev_add(&gmydev.mydev,devno,num);

	atomic_set(&gmydev.open_flag,1);
	init_timer(&gmydev.timer);

	gmydev.pcls = class_create(THIS_MODULE,"mysecond");
	if(IS_ERR(gmydev.pcls))
	{
		printk("class_create failed.\n");
		cdev_del(&gmydev.mydev);
		unregister_chrdev_region(devno, num);
		return -1;
	}

	gmydev.pdev = device_create(gmydev.pcls, NULL, devno, NULL, "mysec");
	if(gmydev.pdev == NULL)
	{
		class_destroy(gmydev.pcls);
		printk("class_create failed.\n");
		cdev_del(&gmydev.mydev);
		unregister_chrdev_region(devno, num);
		return -1;
	}
	return 0;
}

void __exit atomic_exit(void)
{	
	dev_t devno = MKDEV(major,minor);
 
	device_destroy(gmydev.pcls, devno);
	class_destroy(gmydev.pcls);

	cdev_del(&gmydev.mydev);
 
	unregister_chrdev_region(devno, num);
}


MODULE_LICENSE("GPL");
MODULE_AUTHOR("imysy_22");
MODULE_DESCRIPTION("This is a script explained by the author who's name is imysy_22.");
MODULE_ALIAS("HI");

module_init(atomic_init);
module_exit(atomic_exit);


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值