Linux设备驱动程序简介

简介

1.总线系统分类

总线名称特点
PCI支持热插拔
ISA古老的总线,IBM引入
SBusSUN公司设计
IEEE1394(FireWare)
USB通用外部总线
SCSI用于寻址硬盘
并口和串口简单效率低下

2.与外设的交互方法

  1. I/O端口
  2. I/O内存映射
  3. 轮讯和中断

3. 访问设备

内核采用主从设备号来标记匹配的驱动程序 ,b为块设备,c为字符设备。/dev中的设备节点在基于磁盘的文件系统中动态创建,由udevd守护进程负责管理(创建和删除)这些设备节点。引入udev机制后,/dev放置到tmpfs中。通过ioctl例程实现设备控制数据和普通文件读写数据分离。
注: 设备号的统一标准列表

3.1 设备的注册

注册机制实质上就是要维护一个数据库,以便内核知道哪些设备可用,哪些不可用。该数据库需留出接

3.1.1 字符设备

  • 注册或分配一个设备号范围
    驱动程序使用register_chrdev_region()来使用特定范围的设备号
    内核使用alloc_chrdev_region()来选择合适范围
  • 添加设备到设备数据库
    使用cdev_init()初始化cdev实例,然后使用cdev_add()注册设备

3.1.2 块设备

采用add_disk()即可

4. 关联文件系统

除少数情况外,设备文件也采用标准函数处理,由虚拟文件系统管理。 在虚拟文件系统中,每个文件关联一个inode,用于管理文件属性。

struct inode {
	dev_t i_rdev;                           //主从设备号
	umode_t i_mode;                          //设备类型 unsigined short
	const struct file_operations	*i_fop; //文件操作函数指针集合
	....
}

在打开一个设备文件时,文件系统会调用init_special_inode()函数,为设备文件创建一个inode

//mode是设备类型(块or字符), rdev是设备号,这个函数相当于inode的初始化
void init_special_inode(struct inode *inode, umode_t mode, dev_t rdev) 
{
	inode->i_mode = mode;
	if (S_ISCHR(mode)) {
		inode->i_fop = &def_chr_fops; //字符设备对应的操作函数集
		inode->i_rdev = rdev;
	} else if (S_ISBLK(mode)) {
		inode->i_fop = &def_blk_fops;
		inode->i_rdev = rdev;
	} else if (S_ISFIFO(mode))
		inode->i_fop = &pipefifo_fops;
	else if (S_ISSOCK(mode))
		;	/* leave it no_open_fops */
	else
		printk(KERN_DEBUG "init_special_inode: bogus i_mode (%o) for"
				  " inode %s:%lu\n", mode, inode->i_sb->s_id,
				  inode->i_ino);
}

5.字符设备的操作

字符设备由struct cdev表示,内核中维护一个数据库,包括所有活动的cedv实例。

struct cdev {
	struct kobject kobj; //内核通用对象
	struct module *owner; //提供驱动程序的模块
	const struct file_operations *ops; // 一组文件操作
	struct list_head list; //所有表示该设备的设备特殊文件的inode
	dev_t dev; //主从设备号
	unsigned int count;
};

打开字符设备的函数chrdev_open():

static int chrdev_open(struct inode *inode, struct file *filp)
{
	const struct file_operations *fops;
	struct cdev *p;
	struct cdev *new = NULL;
	int ret = 0;

	spin_lock(&cdev_lock);
	p = inode->i_cdev;
	if (!p) {
		struct kobject *kobj;
		int idx;
		spin_unlock(&cdev_lock);
		kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx);
		if (!kobj)
			return -ENXIO;
		new = container_of(kobj, struct cdev, kobj);
		spin_lock(&cdev_lock);
		/* Check i_cdev again in case somebody beat us to it while
		   we dropped the lock. */
		p = inode->i_cdev;
		if (!p) {
			inode->i_cdev = p = new;
			list_add(&inode->i_devices, &p->list);
			new = NULL;
		} else if (!cdev_get(p))
			ret = -ENXIO;
	} else if (!cdev_get(p))
		ret = -ENXIO;
	spin_unlock(&cdev_lock);
	cdev_put(new);
	if (ret)
		return ret;

	ret = -ENXIO;
	fops = fops_get(p->ops);
	if (!fops)
		goto out_cdev_put;

	replace_fops(filp, fops);
	if (filp->f_op->open) {
		ret = filp->f_op->open(inode, filp);
		if (ret)
			goto out_cdev_put;
	}

	return 0;

 out_cdev_put:
	cdev_put(p);
	return ret;
}

6 块设备操作

块设备的实例为Struct block_device, 与块设备关联的inode结构为bdev_inode, 每个块设备都关联了请求队列由struct request_queue表示。一个块设备会有好几个分区,它的实例为struct hd_struct, 用于描述该分区在设备内的键。块设备的操作函数集合都在结构体block_device_operation中。对于已经分区的硬盘,采用Struct gendisk表示。

struct block_device {
	dev_t			bd_dev;  /* not a kdev_t - it's a search key */
	int			bd_openers;
	struct inode *		bd_inode;	/* will die */
	struct super_block *	bd_super;
	struct mutex		bd_mutex;	/* open/close mutex */
	struct list_head	bd_inodes;
	void *			bd_claiming;
	void *			bd_holder;
	int			bd_holders;
	bool			bd_write_holder;
#ifdef CONFIG_SYSFS
	struct list_head	bd_holder_disks;
#endif
	struct block_device *	bd_contains;
	unsigned		bd_block_size;
	struct hd_struct *	bd_part;
	/* number of times partitions within this device have been opened. */
	unsigned		bd_part_count;
	int			bd_invalidated;
	struct gendisk *	bd_disk;
	struct request_queue *  bd_queue;
	struct list_head	bd_list;
	/*
	 * Private data.  You must have bd_claim'ed the block_device
	 * to use this.  NOTE:  bd_claim allows an owner to claim
	 * the same device multiple times, the owner must take special
	 * care to not mess up bd_private for that case.
	 */
	unsigned long		bd_private;

	/* The counter of freeze processes */
	int			bd_fsfreeze_count;
	/* Mutex for freeze */
	struct mutex		bd_fsfreeze_mutex;
};

为系统添加磁盘和分区,采用add_partition向gendisk添加hd_struct。
添加磁盘采用add_disk

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值