• «
  • 1
  • 2
  • »
  • Pages: 1/2     Go
主题 : platform和IIC驱动问题 复制链接 | 浏览器收藏 | 打印
when I crossover,it's over!
级别: 新手上路
UID: 59963
精华: 0
发帖: 40
金钱: 200 两
威望: 40 点
综合积分: 80 分
注册时间: 2011-12-02
最后登录: 2015-09-29
楼主  发表于: 2012-03-02 12:37

 platform和IIC驱动问题


各位大虾,我初学LINUX,遇到一些困惑的问题,想请大家帮个小忙,多谢。

  1. 我不明白所谓的平台设备(platform)有没有主次设备号,如果有,是在哪里注册的,我用sourceinsight找了好久也没有找到,如果没有,为什么好多平台设备驱动在模块初始化的时候一句简单的Platform_driver_register()就可以了,那怎么建立设备文件呢???

  2.关于i2c-dev.c,它到底是适配器的驱动,还是挂载到i2c总线的设备驱动,具体怎么理清i2c-core,i2c总线驱动和i2c设备驱动的关系,如果用设备文件打开,是打开的总线驱动还是设备驱动??

大侠们救救我吧,太迷惑了!
*無鈳取玳
级别: 论坛版主
UID: 27
精华: 12
发帖: 5398
金钱: 40120 两
威望: 17929 点
综合积分: 11036 分
注册时间: 2008-01-16
最后登录: 2014-11-22
1楼  发表于: 2012-03-03 15:04
1. 你所看到的platform_device是Linux设备驱动模型的一部分,是用来触发platform_bus上的platform_driver的。真正的硬件初始化和设备注册是在platform_driver的probe回调函数里实现的。这在“Linux Device Driver”第三版的第14章里有详细的描述。
2. i2c-dev.c里实现的是一个实现用户空间应用程序访问挂载到i2c总线上的设备的字符型设备驱动, 它实际上对应的是i2c总线适配器的驱动。当应用程序打开"/dev/i2c-1"这样的节点时,它可以通过制定i2c设备的slave地址来访问对应i2c总线上的设备。更多这方面的描述可以参考内核源代码目录下的Documentation/i2c/dev-interface文件。
"If you have an apple and I have an apple and we exchange apples, then you and I will
still each have one apple. But if you have an idea and I have an idea and we exchange
these ideas, then each of us will have two ideas."
when I crossover,it's over!
级别: 新手上路
UID: 59963
精华: 0
发帖: 40
金钱: 200 两
威望: 40 点
综合积分: 80 分
注册时间: 2011-12-02
最后登录: 2015-09-29
2楼  发表于: 2012-03-05 12:13
谢谢版主的解答,可是我有一点不明白的就是,为什么我看的代码设备注册无论是什么设备它会全部都用platform_device这个来申明和注册呢?
而且还有就是有一些设备的注册时也没有看到关于设备号的注册代码呢。但是我看书上讲的每个设备都会有设备号的呀。
*無鈳取玳
级别: 论坛版主
UID: 27
精华: 12
发帖: 5398
金钱: 40120 两
威望: 17929 点
综合积分: 11036 分
注册时间: 2008-01-16
最后登录: 2014-11-22
3楼  发表于: 2012-03-05 13:45

谢谢版主的解答,可是我有一点不明白的就是,为什么我看的代码设备注册无论是什么设备它会全部都用platform_device这个来申明和注册呢?

这个我上面已经说过了

而且还有就是有一些设备的注册时也没有看到关于设备号的注册代码呢。但是我看书上讲的每个设备都会有设备号的呀。

举个例子?
"If you have an apple and I have an apple and we exchange apples, then you and I will
still each have one apple. But if you have an idea and I have an idea and we exchange
these ideas, then each of us will have two ideas."
when I crossover,it's over!
级别: 新手上路
UID: 59963
精华: 0
发帖: 40
金钱: 200 两
威望: 40 点
综合积分: 80 分
注册时间: 2011-12-02
最后登录: 2015-09-29
4楼  发表于: 2012-03-05 20:31
/****************************************************************************
* driver functions
***************************************************************************/
static int __init leds_probe(struct platform_device *pdev)
{
    int i;
    int ret, rc;
    struct cust_led *cust_led_list = get_cust_led_list();
    LEDS_DEBUG("[LED]%s\n", __func__);

    for (i = 0; i < LED_TYPE_TOTAL; i++) {
        if (cust_led_list.mode == LED_MODE_NONE) {
            g_leds_data = NULL;
            continue;
        }

        g_leds_data = kzalloc(sizeof(struct led_data), GFP_KERNEL);
        if (!g_leds_data) {
            ret = -ENOMEM;
            goto err;
        }

        g_leds_data->cust.mode = cust_led_list.mode;
        g_leds_data->cust.data = cust_led_list.data;
        g_leds_data->cust.name = cust_led_list.name;

        g_leds_data->cdev.name = cust_led_list.name;

        g_leds_data->cdev.brightness_set = led_set;
        g_leds_data->cdev.blink_set = blink_set;

        INIT_WORK(&g_leds_data->work, led_work);

        ret = led_classdev_register(&pdev->dev, &g_leds_data->cdev);
        
        if(strcmp(g_leds_data->cdev.name,"lcd-backlight") == 0)
        {
            rc = device_create_file(g_leds_data->cdev.dev, &dev_attr_duty);
            if(rc)
            {
                LEDS_DEBUG("[LED]device_create_file duty fail!\n");
            }
            
            rc = device_create_file(g_leds_data->cdev.dev, &dev_attr_div);
            if(rc)
            {
                LEDS_DEBUG("[LED]device_create_file duty fail!\n");
            }
            
            rc = device_create_file(g_leds_data->cdev.dev, &dev_attr_frequency);
            if(rc)
            {
                LEDS_DEBUG("[LED]device_create_file duty fail!\n");
            }
            
        rc = device_create_file(g_leds_data->cdev.dev, &dev_attr_pwm_register);
            if(rc)
            {
                LEDS_DEBUG("[LED]device_create_file duty fail!\n");
            }
            bl_setting = &g_leds_data->cust;
        }

        if (ret)
            goto err;
        
    }


    return 0;

err:
    if (i) {
        for (i = i-1; i >=0; i--) {
            if (!g_leds_data)
                continue;
            led_classdev_unregister(&g_leds_data->cdev);
            cancel_work_sync(&g_leds_data->work);
            kfree(g_leds_data);
            g_leds_data = NULL;
        }
    }

    return ret;
}

=========================================================================================
=========================================================================================
static int __init leds_init(void)
{
    int ret;

    LEDS_DEBUG("[LED]%s\n", __func__);

    ret = platform_device_register(&leds_device);
    if (ret)
        printk("[LED]leds_init:dev:E%d\n", ret);

    ret = platform_driver_register(&leds_driver);

    if (ret)
    {
        printk("[LED]leds_init:drv:E%d\n", ret);
        platform_device_unregister(&leds_device);
        return ret;
    }

    wake_lock_init(&leds_suspend_lock, WAKE_LOCK_SUSPEND, "leds wakelock");

    return ret;
}

我的意思是我看到有些总线设备(如IIC设备)用的platform_device来注册device以后调用platform_driver结构体的probe函数,而这个probe里
又调用了对应的总线driver的注册(如I2C_driver_register)来注册设备的驱动。这样不是给人的感觉像是绕了一个大圈么?为什么不能直接用
i2c_driver_register来注册驱动呢?还有就是如果这样注册后那总线设备(如I2C设备)它是会认为挂在I2C总线上还是platform总线上呢?

看了一下代码,然后我理解platform_device和platform_driver是设备和驱动都会挂在platform bus虚拟总线上,然后匹配设备和驱动会进行匹配,
如果匹配成功就会调用platform_driver里定义的probe函数来初始化设备,申请内存之类的一些事情。不知道这样理解对吗?

上面一个LEDS的驱动程序,我贴了INIT和PROBE的两段,这里我就没看到PROBE里有注册设备号,只是看到它创建了一些设备文件(不确定,只是
由device_create_file函数猜测)。

现在才学习LINUX驱动,感觉很迷茫,LDD第三版也看过,不是太明白,正在反复的看。
*無鈳取玳
级别: 论坛版主
UID: 27
精华: 12
发帖: 5398
金钱: 40120 两
威望: 17929 点
综合积分: 11036 分
注册时间: 2008-01-16
最后登录: 2014-11-22
5楼  发表于: 2012-03-05 23:35
我的意思是我看到有些总线设备(如IIC设备)用的platform_device来注册device以后调用platform_driver结构体的probe函数,而这个probe里
又调用了对应的总线driver的注册(如I2C_driver_register)来注册设备的驱动。这样不是给人的感觉像是绕了一个大圈么?为什么不能直接用
i2c_driver_register来注册驱动呢?

platform device/driver模型的一个重要作用是对于非即插即用设备(比如I2C设备)的觅。这对于嵌入式设备的内核开发是很有用的。比如,对于一个同时支持多个S3C6410开发板的内核来说,我们可以使用同一个包含各个开发板上I2C设备驱动的内核配置,加上不同board文件里的platform device列表,就可以实现用同一个内核镜像支持各个开发板上I2C设备。而不需要给每个开发板使用一个内核配置,每个配置编译生成一个内核镜像。

还有就是如果这样注册后那总线设备(如I2C设备)它是会认为挂在I2C总线上还是platform总线上呢?

这取决于你所着眼的device类型。对于platform device来说,属于platform bus. 对于i2c device来说,属于I2C bus。

看了一下代码,然后我理解platform_device和platform_driver是设备和驱动都会挂在platform bus虚拟总线上,然后匹配设备和驱动会进行匹配,
如果匹配成功就会调用platform_driver里定义的probe函数来初始化设备,申请内存之类的一些事情。不知道这样理解对吗?

是的。probe函数通常用来映射设备的IO地址空间,申请硬件时钟和中断资源等等。

上面一个LEDS的驱动程序,我贴了INIT和PROBE的两段,这里我就没看到PROBE里有注册设备号,只是看到它创建了一些设备文件(不确定,只是
由device_create_file函数猜测)。

那是因为这个例子里的led设备并不是我们通常所说的字符型或块设备。事实上,它们可以认为是class device, 属于“leds”这个class。 它们并不是通过/dev目录下的设备节点而是通过/sys/class/leds/lcd-backlight这样的文件节点访问的。对于这样的设备来说,驱动定义的不是read, write和Ioctl这样的文件操作,而是像brightness这样可以读写的设备属性。
"If you have an apple and I have an apple and we exchange apples, then you and I will
still each have one apple. But if you have an idea and I have an idea and we exchange
these ideas, then each of us will have two ideas."
when I crossover,it's over!
级别: 新手上路
UID: 59963
精华: 0
发帖: 40
金钱: 200 两
威望: 40 点
综合积分: 80 分
注册时间: 2011-12-02
最后登录: 2015-09-29
6楼  发表于: 2012-03-06 10:55

 回 5楼(kasim) 的帖子

---------platform device/driver模型的一个重要作用是对于非即插即用设备(比如I2C设备)的觅。这对于嵌入式设备的内核开发是很有用的。比如,对于一个同时支持多个S3C6410开发板的内核来说,我们可以使用同一个包含各个开发板上I2C设备驱动的内核配置,加上不同board文件里的platform device列表,就可以实现用同一个内核镜像支持各个开发板上I2C设备。而不需要给每个开发板使用一个内核配置,每个配置编译生成一个内核镜像。----

这段的意思是否可以理解为:使用platform_device和platform_driver对于相类似的板子来说,它们可以集中使用platform_device对板载设备进行注册,并且所有的外围设备也都可以使用platform_driver进行驱动的注册,让设备和驱动都挂载在platform bus上进行匹配,这样可以增加通用性,不知道是不是可以这样理解。

--------这取决于你所着眼的device类型。对于platform device来说,属于platform bus. 对于i2c device来说,属于I2C bus。-------

那有些设备(如I2C设备),它是使用platform_device和platform_driver来注册设备和驱动的,但是好像在platform_driver的probe函数里又使用了i2c_driver_register来注册该设备的i2c驱动,这种情况该怎么算呢?

-----那是因为这个例子里的led设备并不是我们通常所说的字符型或块设备。事实上,它们可以认为是class device, 属于“leds”这个class。 它们并不是通过/dev目录下的设备节点而是通过/sys/class/leds/lcd-backlight这样的文件节点访问的。对于这样的设备来说,驱动定义的不是read, write和Ioctl这样的文件操作,而是像brightness这样可以读写的设备属性。------

不是说LINUX下设备的分为char ,block,和网络设备三类么?那这个class device怎么算呢?我有些糊涂了。那像您所说的这种class device就不需要设备号了吗?那通常哪一些类型的设备会算成这种class device设备来注册呢?
*無鈳取玳
级别: 论坛版主
UID: 27
精华: 12
发帖: 5398
金钱: 40120 两
威望: 17929 点
综合积分: 11036 分
注册时间: 2008-01-16
最后登录: 2014-11-22
7楼  发表于: 2012-03-06 12:36
这段的意思是否可以理解为:使用platform_device和platform_driver对于相类似的板子来说,它们可以集中使用platform_device对板载设备进行注册,并且所有的外围设备也都可以使用platform_driver进行驱动的注册,让设备和驱动都挂载在platform bus上进行匹配,这样可以增加通用性,不知道是不是可以这样理解。

是的,你可以这么理解

那有些设备(如I2C设备),它是使用platform_device和platform_driver来注册设备和驱动的,但是好像在platform_driver的probe函数里又使用了i2c_driver_register来注册该设备的i2c驱动,这种情况该怎么算呢?

这样的驱动有双重角色,它既是platform bus上的platform driver,又是i2c bus上的i2c driver。platform driver是用来"触发"真正的i2c driver的注册的。

不是说LINUX下设备的分为char ,block,和网络设备三类么?那这个class device怎么算呢?我有些糊涂了。那像您所说的这种class device就不需要设备号了吗?那通常哪一些类型的设备会算成这种class device设备来注册呢?

那是传统上对设备的分类。事实上,从Linux 2.6引入Linux Device Model以来,就出现了所谓的device class以及作为它的实例的class device。class device没有主,从设备号。基本上可以实现功能抽象的设备都可以用class device来实现。比如led(所有的led都可以抽象为brightness的控制,包括开,关),power supply(AC电源,电池,都可以抽象为电压,电流,容量等参数的读取)等等。你可以在内核源代码的drivers目录下搜索关键字"struct class", 会发现很多内核中定义的device class。
需要注意的是,class device和传统的字符设备,块设备并不冲突。事实上大部分字符设备或者块设备都属于一个device class,也就是说,它们都可以认为是class device,只是它们还定义文件系统里的操作符,并且通过文件系统按照主,从设备号来访问。
"If you have an apple and I have an apple and we exchange apples, then you and I will
still each have one apple. But if you have an idea and I have an idea and we exchange
these ideas, then each of us will have two ideas."
when I crossover,it's over!
级别: 新手上路
UID: 59963
精华: 0
发帖: 40
金钱: 200 两
威望: 40 点
综合积分: 80 分
注册时间: 2011-12-02
最后登录: 2015-09-29
8楼  发表于: 2012-03-06 21:21
引用第7楼kasim于2012-03-06 12:36发表的  :

这样的驱动有双重角色,它既是platform bus上的platform driver,又是i2c bus上的i2c driver。platform driver是用来"触发"真正的i2c driver的注册的。


如您所说的这种驱动具有双重角色,platform driver和I2C_driver都同时对应于platform bus上的platform_device吗?如果是这样的话,那由platfrom driver解发i2c driver注册时只使用了add_i2c_driver这个函数。内核也可以将I2C driverplatform device绑定的吗?这样好像讲不通吧?

static int kpd_pdrv_probe(struct platform_device *pdev)
{
    int i, r;

    /* initialize and register input device (/dev/input/eventX) */
    kpd_input_dev = input_allocate_device();
    if (!kpd_input_dev)
        return -ENOMEM;

    kpd_input_dev->name = KPD_NAME;
    kpd_input_dev->id.bustype = BUS_HOST;
    kpd_input_dev->id.vendor = 0x2454;
    kpd_input_dev->id.product = 0x6573;
    kpd_input_dev->id.version = 0x0010;
    kpd_input_dev->open = kpd_open;

    __set_bit(EV_KEY, kpd_input_dev->evbit);


    for (i = 17; i < KPD_NUM_KEYS; i += 9)    /* only [8] works for Power key */
        kpd_keymap = 0;

    for (i = 0; i < KPD_NUM_KEYS; i++) {
        if (kpd_keymap != 0)
            __set_bit(kpd_keymap, kpd_input_dev->keybit);
    }

#if KPD_AUTOTEST
    for (i = 0; i < ARRAY_SIZE(kpd_auto_keymap); i++)
        __set_bit(kpd_auto_keymap, kpd_input_dev->keybit);
#endif

#if KPD_HAS_SLIDE_QWERTY
    __set_bit(EV_SW, kpd_input_dev->evbit);
    __set_bit(SW_LID, kpd_input_dev->swbit);
    __set_bit(SW_LID, kpd_input_dev->sw);    /* 1: lid shut => closed */
#endif

    kpd_input_dev->dev.parent = &pdev->dev;
    r = input_register_device(kpd_input_dev);
    if (r) {
        printk(KPD_SAY "register input device failed (%d)\n", r);
        input_free_device(kpd_input_dev);
        return r;
    }

    /* register device  */
    kpd_dev.parent = &pdev->dev;
    r = misc_register(&kpd_dev);
    if (r) {
        printk(KPD_SAY "register device failed (%d)\n", r);
        input_unregister_device(kpd_input_dev);
        return r;
    }

    /* register IRQ and EINT */
    kpd_set_debounce(KPD_KEY_DEBOUNCE);
    r = request_irq(KEYPAD_IRQ_LINE, (irq_handler_t)kpd_irq_handler, 0, KPD_NAME, NULL);
    if (r) {
        printk(KPD_SAY "register IRQ failed (%d)\n", r);
        misc_deregister(&kpd_dev);
        input_unregister_device(kpd_input_dev);
        return r;
    }

    return 0;
}

================================================================================================
================================================================================================
static int __init kpd_mod_init(void)
{
    int r;

    r = platform_driver_register(&kpd_pdrv);
    if (r) {
        printk(KPD_SAY "register driver failed (%d)\n", r);
        return r;
    }

#ifdef CONFIG_HAS_EARLYSUSPEND
    register_early_suspend(&kpd_early_suspend_desc);
#endif
    return 0;
}


我有看到这段代码我也觉得很奇怪,有些理解不了,这里注册了platform_driver后由它的probe里又注册了一个input_register_device和使用
misc_register一个注册杂项设备,那这个设备的DRIVER也没有看到有注册呢,难道这个input_register_device和misc_register又是一种特殊
的类型吗?这里也没有看到主,次设备号呢。但是对这个设备确实使用了file operations。
*無鈳取玳
级别: 论坛版主
UID: 27
精华: 12
发帖: 5398
金钱: 40120 两
威望: 17929 点
综合积分: 11036 分
注册时间: 2008-01-16
最后登录: 2014-11-22
9楼  发表于: 2012-03-06 22:00
如您所说的这种驱动具有双重角色,platform driver和I2C_driver都同时对应于platform bus上的platform_device吗?如果是这样的话,那由platfrom driver解发i2c driver注册时只使用了add_i2c_driver这个函数。内核也可以将I2C driverplatform device绑定的吗?这样好像讲不通吧?

platform driver对应的是platform bus上的platform device;i2c driver对应的是i2c bus上的i2c device。

我有看到这段代码我也觉得很奇怪,有些理解不了,这里注册了platform_driver后由它的probe里又注册了一个input_register_device和使用
misc_register一个注册杂项设备,那这个设备的DRIVER也没有看到有注册呢,难道这个input_register_device和misc_register又是一种特殊
的类型吗?这里也没有看到主,次设备号呢。但是对这个设备确实使用了file operations。

以misc_register来说,注意下面红色部分的代码:
187int misc_register(struct miscdevice * misc)
188{
189        struct miscdevice *c;
190        dev_t dev;
191        int err = 0;
192
193        INIT_LIST_HEAD(&misc->list);
194
195        mutex_lock(&misc_mtx);
196        list_for_each_entry(c, &misc_list, list) {
197                if (c->minor == misc->minor) {
198                        mutex_unlock(&misc_mtx);
199                        return -EBUSY;
200                }
201        }
202
203        if (misc->minor == MISC_DYNAMIC_MINOR) {
204                int i = DYNAMIC_MINORS;
205                while (--i >= 0)
206                        if ( (misc_minors[i>>3] & (1 << (i&7))) == 0)
207                                break;
208                if (i<0) {
209                        mutex_unlock(&misc_mtx);
210                        return -EBUSY;
211                }
212                misc->minor = i;
213        }
214
215        if (misc->minor < DYNAMIC_MINORS)
216                misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7);
217        dev = MKDEV(MISC_MAJOR, misc->minor);
218
219        misc->this_device = device_create(misc_class, misc->parent, dev,
220                                          misc, "%s", misc->name);
221        if (IS_ERR(misc->this_device)) {
222                err = PTR_ERR(misc->this_device);
223                goto out;
224        }
225
"If you have an apple and I have an apple and we exchange apples, then you and I will
still each have one apple. But if you have an idea and I have an idea and we exchange
these ideas, then each of us will have two ideas."
  • «
  • 1
  • 2
  • »
  • Pages: 1/2     Go