linux 字符设备驱动

#ifndef _LINUX_CDEV_H
#define _LINUX_CDEV_H

#include <linux/kobject.h>
#include <linux/kdev_t.h>
#include <linux/list.h>

struct file_operations;
struct inode;
struct module;

struct cdev {
    struct kobject kobj;//内嵌的kobject对象
    struct module *owner;//所属模块
    const struct file_operations *ops;//文件操作结构体,代表一个打开的文件,它由内核在open时创建,并传递给在该文件进行操作的所有函数。
    struct list_head list;
    dev_t dev;//设备号,长度为32位,其中高12为主设备号,低20位为次设备号
    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 *); 

extern struct backing_dev_info directly_mappable_cdev_bdi;

#endif
可以使用下列宏从dev_t中获得主次设备号:MAJOR(dev_t dev);     MINOR(dev_t dev);

也可以使用下列宏通过主次设备号生成dev_t:MKDEV(int major,int minor);

struct node结构在内部表示文件,和file结构不同,后者表示打开的文件描述符。对于单个文件,可能会有很多表示打开的文件描述符的file结构,但它们都指向单个inode结构。node里边和我们驱动程序有用的字段只有两个:

dev_t i_rdev;    //对表示设备文件的inode结构,该字段包含了真正的设备编号
struct cdev *i_cdev;     //是表示字符设备的内核的内部结构。当inode指向一个字符设备文件时,该字段包含了指向struct cdev结构的指针。
可以使用下边两个宏从inode中获得主设备号和此设备号:
unsigned int iminor(struct inode *inode);
unsigned int imajor(struct inode *inode);

(1)内核中所有已分配的字符设备编号都记录在一个名为 chrdevs 散列表里,散列表中的每一个元素是一个 char_device_struct 结构
(2)register_chrdev_region()、alloc_chrdev_region() 和 register_chrdev() 三个函数都会调用一个共用的 __register_chrdev_region() 函数来注册一组设备编号范围(即一个 char_device_struct 结构)
(3)使用他们注册字符设备都需要手动创建设备节点。

542 void cdev_init(struct cdev *cdev, const struct file_operations *fops)
543 {
544     memset(cdev, 0, sizeof *cdev);
545     INIT_LIST_HEAD(&cdev->list);                                                                                                     
546     kobject_init(&cdev->kobj, &ktype_cdev_default);
547     cdev->ops = fops;
548 }

472 int cdev_add(struct cdev *p, dev_t dev, unsigned count)
473 {
474     p->dev = dev;
475     p->count = count;
/*内核中所有都字符设备都会记录在一个 kobj_map 结构的 cdev_map 变量中。这个结构的变量中包含一个散列表用来快速存取所有的对象。
kobj_map() 函数就是用来把字符设备编号和 cdev 结构变量一起保存到 cdev_map 这个散列表里。当后续要打开一个字符设备文件时,
通过调用 kobj_lookup() 函数,根据设备编号就可以找到 cdev 结构变量,从而取出其中的 ops 字段。*/
476     return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);
477 }

/*自动创建设备文件*/
 myclass = class_create(THIS_MODULE,"test_char"); /*在sys下创建类目录/sys/class/test_char*/
 device_create(myclass, NULL, MKDEV(mem_major,0), NULL, "memdev0");//设备名为memdev0

 /* 手动创建设备文件*/
"mknod /dev/memdev0 c 150 0"命令创建"/dev/globalmem"字符设备节点

int chrdev_open(struct inode * inode, struct file * filp) //path: fs/char_dev.c
/*
chrdev_open()所做的事情可以概括如下:
1. 根据设备号(inode->i_rdev), 在字符设备驱动模型中查找对应的驱动程序, 这通过kobj_lookup() 来实现, kobj_lookup()会返回对应驱动程序cdev的kobject.
2. 设置inode->i_cdev , 指向找到的cdev.
3. 将inode添加到cdev->list的链表中.
4. 使用cdev的ops 设置file对象的f_op
5. 如果ops中定义了open方法,则调用该open方法
6. 返回.
执行完chrdev_open()之后,file对象的f_op指向cdev的ops,因而之后对设备进行的read, write等操作,就会执行cdev的相应操作.
*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值