Chinaunix首页 | 论坛 | 博客
  • 博客访问: 93612
  • 博文数量: 24
  • 博客积分: 1066
  • 博客等级: 少尉
  • 技术积分: 277
  • 用 户 组: 普通用户
  • 注册时间: 2010-06-02 21:07
文章分类
文章存档

2012年(1)

2011年(19)

2010年(4)

我的朋友

分类: LINUX

2011-03-02 21:39:17

关于字符设备的基础知识:
  对于字符驱动程序来说,首先要注册一个设备号,设备号包括主设备和次设备,一般来讲,主设备标志与设备相对应的驱动程序,而次设备则是被内核用来标志所指向是那个设备。内核除了知道次设备指向驱动所对应的设备外,对于次设备其它的一无所知。
  如果事先就知道你要注册的设备号,你可以使用宏MKDEV(  )来生成设备号,结构是dev_t, 以后就可以通过MAJOR( )和MINOR可以查看相应的主设备和次设备
MKDEV(int major, int minor);
MAJOR(dev_t dev);
MAJOR(dev_t  dev);
  定义好设备号后并且想让他工作的话就必须让内核知道,这里首先要了解几个函数和数据结构:
int register_chrdev_region(dev_t first , unsigned int count , char* name );
first 是你想注册的设备号,其中的minor一般为0,count为你设备号临近的设备号的总和,这里需要注意的是,如果count设置的比较大的话,可能使得设备号的major超出你开始分配的major number。name为设备的名称,将会出现在/proc/divices中。注册成功的话将会将会返回0。
一般而言,开发着一般都不能确定主设备应该选择什么,如果是这样的话,可以使用下个这个函数
int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char* name);
  这个函数可以动态分配主设备,count 和name与上面那个函数的含义一样,firstminor为需要使用的第一个次设备号,通常为0,使用这个函数后,dev为内核为你分配的设备号,可以通过上面的二个宏来获得主设备和次设备号。然而使用这个函数也有个缺点,即不能事先创建设备节点,也就是说不能在/dev显示出相应的设备。不过可以通过读取/proc/devices来创建。
  下面是几个重要的数据结构file_operations, file, inode
  file_operations是一个字符设备把驱动的操作和设备号联系在一起的纽带,是一系列指针的集合,每个被打开的文件都对应于一系列的操作,这就是file_operations,用来执行一系列的系统调用。
struct file_operations {
        struct module *owner;  //防止模块还在被使用的时候被卸载
        loff_t (*llseek) (struct file *, loff_t, int);
        ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
        ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t);
        ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);//同步读
        ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t);
             ......
}
file代表一个打开的文件,在执行file_operation中的open操作时被创建,这里需要注意的是与用户空间file指针的区别,一个在内核,而file指针在用户空间,由c库来定义。
struct file {
        struct list_head        f_list;
        struct dentry           *f_dentry;
        struct vfsmount         *f_vfsmnt;
        struct file_operations  *f_op;   //这就是上面所说的file_oeprations
        atomic_t                f_count;
        unsigned int            f_flags;
        mode_t                  f_mode;   //文件是否可读、可写
        int                     f_error;
        loff_t                  f_pos;      //当前读写位置
        struct fown_struct      f_owner;
        unsigned int            f_uid, f_gid;
        struct file_ra_state    f_ra;
        unsigned long           f_version;
        void                    *f_security;
        /* needed for tty driver, and maybe others */
        void                    *private_data;    
#ifdef CONFIG_EPOLL
        /* Used by fs/eventpoll.c to link all the hooks to this file */
        struct list_head        f_ep_links;
        spinlock_t              f_ep_lock;
#endif /* #ifdef CONFIG_EPOLL */
        struct address_space    *f_mapping;
};
inode被内核用来代表一个文件,注意和file的区别,一个是代表文件,一个是代表打开的文件
inode包括很重要的二个成员:
dev_t i_rdev   设备文件的设备号
struct cdev *i_cdev  代表字符设备的数据结构
Inode结构是用来在内核内部表示文件的.同一个文件可以被打开好多次,所以可以对应很多struct file,但是只对应一个struct inode
好了,现在可以注册字符设备了
可以有两种方法注册
    struct cdev *my_cdev=cdev_alloc();
    my_cdev->ops=&my_fops;

    void cdev_init(struct cdev *cdev,struct file_operations *fops);
注册完后还要通知内核一声,通过调用
    int cdev_add(struct cdev *dev,dev_t num,unsigned int count);
count 一般是 1.
删除字符设备,调用
    void cdev_del(struct cdev *dev);
参考资料
驱动读书笔记
Linux Device Driver 3rd Edition
阅读(370) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~