zoukankan      html  css  js  c++  java
  • Linux驱动学习(二)

    注:基于Linux-2.6.38

            上一篇里介绍了Linux驱动里比较底层的内容,这里将以具体的平台(mini6410)来介绍平台设备(platform device,如IIC,UART,RTC)在初始化时是怎么注册进内核的。

            还是/arch/arm/mach-s3c64xx/mach-mini6410.c这个文件,前面有篇文章已经说了里面的mini6410_machine_init()函数是什么时候被调用的,因此在这里不再重复,直接看这个函数里面的内容:

     1 static void __init mini6410_machine_init(void)
     2 {
     3         u32 cs1;
     4 
     5         s3c_i2c0_set_platdata(NULL);
     6 #ifdef CONFIG_S3C_DEV_I2C1
     7         s3c_i2c1_set_platdata(NULL);
     8 #endif
     9         
    10         s3c_fb_set_platdata(&mini6410_lcd_pdata);
    11 
    12 #ifdef CONFIG_SAMSUNG_DEV_TS
    13         s3c24xx_ts_set_platdata(&s3c_ts_platform);
    14 #endif
    15 #ifdef CONFIG_TOUCHSCREEN_MINI6410
    16         s3c_ts_set_platdata(&s3c_ts_platform);
    17 #endif
    18 
    19         s3c_sdhci0_set_platdata(&mini6410_hsmmc0_pdata);
    20         s3c_sdhci1_set_platdata(&mini6410_hsmmc1_pdata);
    21 
    22 #ifdef CONFIG_MTD_NAND_S3C
    23         s3c_device_nand.name = "s3c6410-nand";
    24 #endif
    25         s3c_nand_set_platdata(&mini6410_nand_info);
    26 
    27         s3c64xx_ac97_setup_gpio(0);
    28 
    29         /* configure nCS1 width to 16 bits */
    30 
    31         cs1 = __raw_readl(S3C64XX_SROM_BW) &
    32                     ~(S3C64XX_SROM_BW__CS_MASK << S3C64XX_SROM_BW__NCS1__SHIFT);
    33         cs1 |= ((1 << S3C64XX_SROM_BW__DATAWIDTH__SHIFT) |
    34                 (1 << S3C64XX_SROM_BW__WAITENABLE__SHIFT) |
    35                 (1 << S3C64XX_SROM_BW__BYTEENABLE__SHIFT)) <<
    36                                                    S3C64XX_SROM_BW__NCS1__SHIFT;
    37         __raw_writel(cs1, S3C64XX_SROM_BW);
    38         /* set timing for nCS1 suitable for ethernet chip */
    39 
    40         __raw_writel((0 << S3C64XX_SROM_BCX__PMC__SHIFT) |
    41                      (6 << S3C64XX_SROM_BCX__TACP__SHIFT) |
    42                      (4 << S3C64XX_SROM_BCX__TCAH__SHIFT) |
    43                      (1 << S3C64XX_SROM_BCX__TCOH__SHIFT) |
    44                      (0xe << S3C64XX_SROM_BCX__TACC__SHIFT) |
    45                      (4 << S3C64XX_SROM_BCX__TCOS__SHIFT) |
    46                      (0 << S3C64XX_SROM_BCX__TACS__SHIFT), S3C64XX_SROM_BC1);
    47 
    48         gpio_request(S3C64XX_GPN(5), "LCD power");
    49         gpio_request(S3C64XX_GPF(13), "LCD power");
    50         gpio_request(S3C64XX_GPF(15), "LCD power");
    51 
    52         if (ARRAY_SIZE(i2c_devs0)) {
    53                 i2c_register_board_info(0, i2c_devs0, ARRAY_SIZE(i2c_devs0));
    54         }
    55         if (ARRAY_SIZE(i2c_devs1)) {
    56                 i2c_register_board_info(1, i2c_devs1, ARRAY_SIZE(i2c_devs1));
    57         }
    58 
    59 #ifdef CONFIG_S3C64XX_DEV_FIMC0
    60         s3c_fimc0_set_platdata(NULL);
    61 #endif
    62 #ifdef CONFIG_S3C64XX_DEV_FIMC1
    63         s3c_fimc1_set_platdata(NULL);
    64 #endif
    65 
    66         platform_add_devices(mini6410_devices, ARRAY_SIZE(mini6410_devices));
    67 
    68 #ifdef CONFIG_VIDEO_SAMSUNG
    69         create_proc_read_entry("videomem", 0, NULL, s3c_media_read_proc, NULL);
    70 #endif
    71 }

    虽说有点长,但不难理解,都是对平台设备相关数据的初始化还有一些寄存器的设置,重点看第66行的platform_add_devices()函数,该函数实现了平台设备的注册,第一个参数是结构体数组,第二个参数是该数组的大小,去看看它的定义:

     1 static struct platform_device *mini6410_devices[] __initdata = {
     2 #ifdef CONFIG_MINI6410_SD_CH0
     3         &s3c_device_hsmmc0,
     4 #endif
     5 #ifdef CONFIG_MINI6410_SD_CH1
     6         &s3c_device_hsmmc1,
     7 #endif
     8         &s3c_device_i2c0,
     9 #ifdef CONFIG_S3C_DEV_I2C1
    10         &s3c_device_i2c1,
    11 #endif
    12         &s3c_device_nand,
    13         //LCD设备
    14         &s3c_device_fb,
    15         &s3c_device_ohci,
    16         &s3c_device_usb_hsotg,
    17 #ifdef CONFIG_SND_SAMSUNG_AC97
    18         &s3c64xx_device_ac97,
    19 #else
    20         &s3c64xx_device_iisv4,
    21 #endif
    22         &samsung_asoc_dma,
    23         //LCD背光设备
    24         &mini6410_lcd_powerdev,
    25 
    26 #ifdef CONFIG_DM9000
    27         &s3c_device_dm9000,
    28 #endif
    29 #ifdef CONFIG_S3C_ADC
    30         &s3c_device_adc,
    31 #endif
    32 #if defined(CONFIG_TOUCHSCREEN_MINI6410) || defined(CONFIG_SAMSUNG_DEV_TS)
    33         &s3c_device_ts,
    34 #endif
    35         &s3c_device_wdt,
    36 #ifdef CONFIG_S3C_DEV_RTC
    37         &s3c_device_rtc,
    38 #endif
    39 
    40         /* Multimedia support */
    41 #ifdef CONFIG_VIDEO_SAMSUNG
    42         &s3c_device_vpp,
    43         &s3c_device_mfc,
    44         &s3c_device_tvenc,
    45         &s3c_device_tvscaler,
    46         &s3c_device_rotator,
    47         &s3c_device_jpeg,
    48         &s3c_device_fimc0,
    49         &s3c_device_fimc1,
    50         &s3c_device_g2d,
    51         &s3c_device_g3d,
    52 #endif
    53 };

    嗯,该数组里存放了很多设备,这些设备都会随着mini6410_machine_init()函数被调用而被初始化。接下来回到platform_add_devices(),它在drivers/base/platform.c里定义:

     1 int platform_add_devices(struct platform_device **devs, int num)
     2 {               
     3         int i, ret = 0;
     4         
     5         for (i = 0; i < num; i++) {
     6                 ret = platform_device_register(devs[i]);
     7                 if (ret) {
     8                         while (--i >= 0)
     9                                 platform_device_unregister(devs[i]);
    10                         break;
    11                 }
    12         }
    13 
    14         return ret;
    15 } 

    在一个for循环里通过platform_device_register()将所有定义了的平台设备逐个注册进系统。看第6行platform_device_register()的定义:

    1 int platform_device_register(struct platform_device *pdev)
    2 {
    3         device_initialize(&pdev->dev);
    4         return platform_device_add(pdev);
    5 }

    第3行的函数在上一篇已经说过,看第4行的platform_device_add():

     1 int platform_device_add(struct platform_device *pdev)
     2 {
     3         int i, ret = 0;
     4 
     5         if (!pdev)
     6                 return -EINVAL;
     7 
     8         if (!pdev->dev.parent)
     9                 pdev->dev.parent = &platform_bus;
    10 
    11         pdev->dev.bus = &platform_bus_type;
    12 
    13         if (pdev->id != -1)
    14                 dev_set_name(&pdev->dev, "%s.%d", pdev->name,  pdev->id);
    15         else
    16                 dev_set_name(&pdev->dev, "%s", pdev->name);
    17 
    18         for (i = 0; i < pdev->num_resources; i++) {
    19                 struct resource *p, *r = &pdev->resource[i];
    20 
    21                 if (r->name == NULL)
    22                         r->name = dev_name(&pdev->dev);
    23 
    24                 p = r->parent;
    25                 if (!p) {
    26                         if (resource_type(r) == IORESOURCE_MEM)
    27                                 p = &iomem_resource;
    28                         else if (resource_type(r) == IORESOURCE_IO)
    29                                 p = &ioport_resource;
    30                 }
    31 
    32                 if (p && insert_resource(p, r)) {
    33                         printk(KERN_ERR
    34                                "%s: failed to claim resource %d\n",
    35                                dev_name(&pdev->dev), i);
    36                         ret = -EBUSY;
    37                         goto failed;
    38                 }
    39         }
    40 
    41         pr_debug("Registering platform device '%s'. Parent at %s\n",
    42                  dev_name(&pdev->dev), dev_name(pdev->dev.parent));
    43 
    44         ret = device_add(&pdev->dev);
    45         if (ret == 0)
    46                 return ret;
    47 
    48  failed:
    49         while (--i >= 0) {
    50                 struct resource *r = &pdev->resource[i];
    51                 unsigned long type = resource_type(r);
    52 
    53                 if (type == IORESOURCE_MEM || type == IORESOURCE_IO)
    54                         release_resource(r);
    55         }
    56 
    57         return ret;
    58 }

    第9行,把上一篇说过的platform_bus作为当前设备的父设备;第11行,设置当前设备所在的总线;第13~16行,pdev->id这个成员在定义平台设备时已经赋值,大部分时候被置为-1;第18~39行是对当前平台设备占有的资源(如:寄存器,中断等)报告给系统,也就是说当你要使用这个设备时要先向系统申请关于这个设备的资源,然后才可以对该设备进行操作;第44行,很熟悉了,在上一篇已经说过。

  • 相关阅读:
    Chrome 29 新功能一览
    7 款免费的 Metro UI 模板
    JPG渐进 & PNG/PNG24 交错测试
    你的钱,以后是放银行还是放支付宝?
    Bise IE6 在你的网站上加上它让IE滚蛋吧
    单例模式常见场景
    10 个最新的开发者工具
    大流量网站的底层系统架构
    DNS解析全过程及原理
    IE条件注释详解
  • 原文地址:https://www.cnblogs.com/lknlfy/p/2489209.html
Copyright © 2011-2022 走看看