Chinaunix首页 | 论坛 | 博客
  • 博客访问: 428745
  • 博文数量: 123
  • 博客积分: 2686
  • 博客等级: 少校
  • 技术积分: 1349
  • 用 户 组: 普通用户
  • 注册时间: 2009-12-23 22:11
文章分类
文章存档

2012年(3)

2011年(10)

2010年(100)

2009年(10)

我的朋友

分类: LINUX

2010-03-30 11:22:30

  • 对字符设备的访问是通过文件系统内的设备名称进行的,这些名称称为特殊文件、设备文件,或则称为文件系统树的节点,他们通常位于/dev.

 

  • 主设备号标识对应的驱动程序,一个主设备号对应一个驱动程序次设备号由内核使用,用于正确确定设备文件所指的设备。可以通过次设备号获得一个指向内核设备的直接指针,也可将次设备号当做设备本地数组的索引。除了知道次设备号用来指向驱动程序所实现的设备之外,内核本身基本不关心关于次设备号的任何其他信息。
 
  • dev_t类型用来保存设备编号--包括主设备号、次设备号。

MAJOR(dev_t dev);//从dev中获取主设备号

MINOR(dev_t dev);//从dev中获取次设备号

MKDEV(int major, int minor);//构造主设备号为major,次设备号为minor的dev_t

 

  • 分配和释放设备编号.获得一个或者多个设备编号,完成该工作的必要函数是

register_chrdev_region.定义在.

int register_chrdev_region(dev_t first,unsigned int count,char *name);

其中,first是要分配的设备编号范围的起始值。first的次设备号经常设置为0.count是连续设备编号的个数.name是和该编号范围关联的设备名称,将出现在/proc/devices和sysfs中。这个函数要求提前明确知道所需要的设备编号。

int alloc_chrdev_region(dev_t*dev,unsigned int firstminor,

                        unsigned int count,char *name);

其中,dev仅仅用于输出的函数,firstminor是要使用的被请求的第一个次设备号,它通常是0.其他同上。

释放设备号:

void unregister_chrdev_region(dev_t first,unsigned int count);

 

  • 动态分配主设备号。一部分主设备号已经静态地分配给大部分常见设备。可以查看Documentation/devices.txt.对于一个新的驱动程序,强烈建议不要随机分配一个当前没有使用的设备号为主设备号,而应该使用动态分配机制获取主设备号。

 

  • 大部分基本的驱动程序操作涉及到3个重要的内核数据结构,file_operations,file,inode.

file_operations是连接设备编号和驱动程序的。

file表示一个打开的文件,系统中每个打开的文件在内核空间中都有一个对应的file结构,和具体进程相关。

inode包含大量有关文件的信息,有2个字段对编写驱动很有用:

dev_t i_rdev;//表示设备文件的inode结构,该字段包含了真正的设备编号。

struct cdev *i_cdev;//表示字符设备的内核数据结构,当inode指向一个字符设备文件时,该字段包含了指向struct cdev结构的指针。

 

  • 标记化结构初始化语法

C Primer Plus第五版中相关章节:

    已知一个结构,定义如下
struct book
{
    char title[MAXTITL];
    char author[MAXAUTL];
    float value;
};
    C99支持结构的指定初始化项目,其语法与数组的指定初始化项目近似。只是,结构的指定初始化项目使用点运算符和成员名(而不是方括号和索引值)来标识具体的元素。例如,只初始化book结构的成员value,可以这样做:
    struct book surprise = { .value = 10.99 };
    可以按照任意的顺序使用指定初始化项目:
    struct book gift = { .value = 25.99,
                                    .author = "James Broadfool",
                                    .title = "Rue for the Toad"
                                };
    正像数组一样,跟在一个指定初始化项目之后的常规初始化项目为跟在指定成员后的成员提供了初始值。另外,对特定成员的最后一次赋值是它实际获得的值。例如,考虑下列声明:
    struct book gift = { .value = 18.90,
                                    .author = "Philionna pestle",
                                    0.25
                                };
    这将把值0.25赋给成员value,因为它在结构声明中紧跟在author成员之后。新的值0.25代替了早先的赋值18.90。

 

  • 字符设备的注册。内核内部使用struct cdev结构来表示字符设备,在内核调用设备的时候之前,必须分配并注册一个或者多个上述结构。

struct cdev *my_cdev=cdev_alloc();

my_cdev->ops=&my_fops;

初始化已经分配到的数据结构:

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

在cdev结构设置好之后,最后的步骤是通过下面的调用告诉内核该结构的信息:

int cdev_add(struct *dev, dev_t num, unsigned int count);//这个函数容易失败。

从系统中移除一个字符设备,做如下调用:

void cdev_del(struct cdev *dev);

 

  • 字符设备结构体,及对此结构体操作的函数。

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 *cdev, const struct file_operations *fops)
{
 memset(cdev, 0, sizeof *cdev);
 INIT_LIST_HEAD(&cdev->list);
 kobject_init(&cdev->kobj, &ktype_cdev_default);
 cdev->ops = fops;
}

int cdev_add(struct cdev *p, dev_t dev, unsigned count)
{
 p->dev = dev;
 p->count = count;
 return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock, p);
}

 

以上内容均来自《linux设备驱动程序3》

阅读(790) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~