Chinaunix首页 | 论坛 | 博客
  • 博客访问: 194560
  • 博文数量: 44
  • 博客积分: 1515
  • 博客等级: 上尉
  • 技术积分: 480
  • 用 户 组: 普通用户
  • 注册时间: 2007-11-06 16:39
文章分类

全部博文(44)

文章存档

2013年(3)

2012年(2)

2011年(2)

2009年(20)

2008年(17)

我的朋友

分类: LINUX

2009-06-12 18:04:04

                             关于register_chrdev函数
最近在alsa的架构,看的是一头雾水,尤其是关于设备注册的地方。仔细研究register_chrdev函数。
其在内核中的原型为:
    int register_chrdev(unsigned int major, const char *name,
            const struct file_operations *fops);
    根据个人理解,该函数根据major(主设备号)申请并注册设备号,次设备号为0~255,因此理论上该驱动程序可以处理256个设备。主要是通过fops中的open函数指针实现。
    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 (*write) (struct file *, const char __user *, size_t, loff_t *);
    ssize_t (*aio_read) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
    ssize_t (*aio_write) (struct kiocb *, const struct iovec *, unsigned long, loff_t);
    int (*readdir) (struct file *, void *, filldir_t);
   ...........................................
    int (*open) (struct inode *, struct file *);
    ....................................
    int (*fsetattr)(struct file *, struct iattr *);
};

通常情况下在open例程的实现中,要根据次设备号重新对file结构的fops属性重新复制,以alsa为例:

static int __init alsa_sound_init(void)
{
    snd_major = major;
    snd_ecards_limit = cards_limit;
    if (register_chrdev(major, "alsa", &snd_fops)) {
        snd_printk(KERN_ERR "unable to register native major device number %d\n", major);
        return -EIO;
    }
    if (snd_info_init() < 0) {
        unregister_chrdev(major, "alsa");
        return -ENOMEM;
    }
    snd_info_minor_register();
#ifndef MODULE
    printk(KERN_INFO "Advanced Linux Sound Architecture Driver Version " CONFIG_SND_VERSION CONFIG_SND_DATE ".\n");
#endif
    return 0;
}

声卡的主设备号为116,该函数以116为主设备号,注册256个字符设备,对应的文件操作集为:snd_fops,定义如下:

static const struct file_operations snd_fops =
{
    .owner =    THIS_MODULE,
    .open =        snd_open
};


函数snd_open的主要执行代码如下:


if (minor >= ARRAY_SIZE(snd_minors))
        return -ENODEV;
    mptr = snd_minors[minor];
    if (mptr == NULL) {
#ifdef CONFIG_MODULES
        int dev = SNDRV_MINOR_DEVICE(minor);
        if (dev == SNDRV_MINOR_CONTROL) {
            /* /dev/aloadC? */
            int card = SNDRV_MINOR_CARD(minor);
            if (snd_cards[card] == NULL)
                snd_request_card(card);
        } else if (dev == SNDRV_MINOR_GLOBAL) {
            /* /dev/aloadSEQ */
            snd_request_other(minor);
        }
#ifndef CONFIG_SND_DYNAMIC_MINORS
        /* /dev/snd/{controlC?,seq} */
        mptr = snd_minors[minor];
        if (mptr == NULL)
#endif
#endif
            return -ENODEV;
    }
    old_fops = file->f_op;
    file->f_op = fops_get(mptr->f_ops);
    if (file->f_op == NULL) {
        file->f_op = old_fops;
        return -ENODEV;
    }
    if (file->f_op->open)
        err = file->f_op->open(inode, file);
    if (err) {
        fops_put(file->f_op);
        file->f_op = fops_get(old_fops);
    }
    fops_put(old_fops);
    return err;


该函数根据此设备号从全局变量snd_minors中选择合适的f_op指针对file_fop重新赋值,选择正确的设备操作。
 
通过device_create添加新的设备。

阅读关于miscdev的代码可以发现,miscdev的实现也是基于 register_chrdev 和 device_create两个函数







阅读(1863) | 评论(0) | 转发(0) |
0

上一篇:旧友相逢

下一篇:Michael Jackson gone

给主人留下些什么吧!~~