Chinaunix首页 | 论坛 | 博客
  • 博客访问: 716889
  • 博文数量: 67
  • 博客积分: 994
  • 博客等级: 准尉
  • 技术积分: 1749
  • 用 户 组: 普通用户
  • 注册时间: 2011-08-03 14:10
文章分类
文章存档

2014年(11)

2013年(14)

2012年(14)

2011年(28)

分类: LINUX

2012-01-03 10:01:42

      linux设备分为:字符设备和块设备。
     字符设备:就是那些像键盘那样以字符为单位、逐个字符进行输入/输出的设备。
      块设备:像磁盘那样以块或扇区为单位、成块进行输入/输出的设备。
      之所以把设备分为字符设备和块设备是因为一方面描述比较方便,另一方面是为技术上方便。
      建立一个设备可以通过mknod()系统调用实现。比如mknod  /dev/mycdev  c  123  0
其中c代表字符设备,123代表主设备号,0代表次设备号。一个设备可以通过主设备号+次设备号唯一确定。

     載内核里面使用cedv结构描述一个字符设备,其具体定义如下:
2 struct cdev {
  3         struct kobject kobj;
  4         struct module *owner;
  5         const struct file_operations *ops;
  6         struct list_head list;
  7         dev_t dev;
  8         unsigned int count;
  9 };
其中kobj为内嵌的kobject对象,module为所属模块,字段file_operations定义了字符设备驱动提供给虚拟文件系统的接口函数,dev_t定义了dev设备号,为32位,其中12位为主设备号,而20位次设备号。我们可以使用宏MAJOR(dev_t dev)和MINOR(dev_t dev)获得主设备号和次设备号。

内核中提供了一组用于操作cdev结构体的函数,如下:
 21 void cdev_init(struct cdev *, const struct file_operations *);
 22
 23 struct cdev *cdev_alloc(void);
 24
 25 void cdev_put(struct cdev *p);
 26
 27 int cdev_add(struct cdev *, dev_t, unsigned);
 28
 29 void cdev_del(struct cdev *);
 30
 31 void cd_forget(struct inode *);
 32
 33 extern struct backing_dev_info directly_mappable_cdev_bdi;

cdev_init用于初始化cdev成员,具体定义如下:
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 }
注意:Initializes @cdev, remembering @fops, making it ready to add to the
 system with cdev_add().

cdev_alloc()函数用于动态申请一个cdev内存,具体定义如下:
524 struct cdev *cdev_alloc(void)
525 {
526         struct cdev *p = kzalloc(sizeof(struct cdev), GFP_KERNEL);
527         if (p) {
528                 INIT_LIST_HEAD(&p->list);
529                 kobject_init(&p->kobj, &ktype_cdev_dynamic);
530         }
531         return p;
532 }
申请成功就会返回cdev结构体大小的空间,如果失败就返回NULL。

cdev_put用于生成一个模块
void cdev_put(struct cdev *p)
358 {
359         if (p) {
360                 struct module *owner = p->owner;
361                 kobject_put(&p->kobj);
362                 module_put(owner);
363         }
364 }

cdev_add()函数向系统添加一个cdev。,具体定义如下:
472 int cdev_add(struct cdev *p, dev_t dev, unsigned count)
473 {
474         p->dev = dev;
475         p->count = count;
476         return kobj_map(cdev_map, dev, count, NULL, exact_match, exact_lock,     p);
477 }

cdev_del()函数向系统删除一个cdev。,具体定义如下:
 void cdev_del(struct cdev *p)
492 {
493         cdev_unmap(p->dev, p->count);
494         kobject_put(&p->kobj);
495 }
cdev_add()函数和cdev_del()函数完成了字符设备的注册和注销。对cdev_add()函数调用通常发生在字符设备驱动的加载函数中,而对cdev_del()函数的使用通常发生載字符设备驱动模块的卸载函数中。載调用cdev_add()函数向系统注册字符设备之前,硬先调用register_chrdev_region()或alloc_chrdev_region()函数向系统申请设备号。
 
字符设备驱动模块除了加载和卸载部分,最主要的就是file_operations结构体中成员函数的实现。
包括open()、read()、write()、release()等等。
具体实现如下:
static int mycdev_open(struct inode *inode, struct file *fp)
{
    return 0;                                  /*由系统实现open操作*/
}

static int mycdev_release(struct inode *inode, struct file *fp)
{
    return 0;                                    /*由系统实现release操作*/
}

static ssize_t mycdev_read(struct file *fp, char __user *buf, size_t size, loff_t *pos)
{
    unsigned long p = *pos;
    unsigned int count = size;
    char kernel_buf[MYCDEV_SIZE] = "This is mycdev!";

    if(p >= MYCDEV_SIZE)
        return -1;
    if(count > MYCDEV_SIZE-p)
        count = MYCDEV_SIZE - p;
   
    if (copy_to_user(buf, kernel_buf, count) != 0) {
        printk("read error!\n");
        return -1;
    }
}                                          /*read中copy_to_user操作实现了从内核向用户态空间的拷贝*/
write操作和读操作差不多,它通过copy_from_user实现了从用户空间向内核空间的拷贝。
实现了上述函数之后要 定义一个file_operations实例。并将具体设备驱动的函数赋值给file_operations的成员。具体模板如下:
static const struct file_operations mycdev_fops =
{
    .owner = THIS_MODULE,
    .read = mycdev_read,
    .write = mycdev_write,
    .open = mycdev_open,
    .release = mycdev_release,
};

好了具体字符设备驱动模块讲的差不多了,你可以动手实现你的模块了。哦对了,模块写好后,还需要写一个用户态程序验证。

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