博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Linux驱动学习(二)
阅读量:5999 次
发布时间:2019-06-20

本文共 7293 字,大约阅读时间需要 24 分钟。

注:基于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_TS13         s3c24xx_ts_set_platdata(&s3c_ts_platform);14 #endif15 #ifdef CONFIG_TOUCHSCREEN_MINI641016         s3c_ts_set_platdata(&s3c_ts_platform);17 #endif18 19         s3c_sdhci0_set_platdata(&mini6410_hsmmc0_pdata);20         s3c_sdhci1_set_platdata(&mini6410_hsmmc1_pdata);21 22 #ifdef CONFIG_MTD_NAND_S3C23         s3c_device_nand.name = "s3c6410-nand";24 #endif25         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_FIMC060         s3c_fimc0_set_platdata(NULL);61 #endif62 #ifdef CONFIG_S3C64XX_DEV_FIMC163         s3c_fimc1_set_platdata(NULL);64 #endif65 66         platform_add_devices(mini6410_devices, ARRAY_SIZE(mini6410_devices));67 68 #ifdef CONFIG_VIDEO_SAMSUNG69         create_proc_read_entry("videomem", 0, NULL, s3c_media_read_proc, NULL);70 #endif71 }

虽说有点长,但不难理解,都是对平台设备相关数据的初始化还有一些寄存器的设置,重点看第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_I2C110         &s3c_device_i2c1,11 #endif12         &s3c_device_nand,13         //LCD设备14         &s3c_device_fb,15         &s3c_device_ohci,16         &s3c_device_usb_hsotg,17 #ifdef CONFIG_SND_SAMSUNG_AC9718         &s3c64xx_device_ac97,19 #else20         &s3c64xx_device_iisv4,21 #endif22         &samsung_asoc_dma,23         //LCD背光设备24         &mini6410_lcd_powerdev,25 26 #ifdef CONFIG_DM900027         &s3c_device_dm9000,28 #endif29 #ifdef CONFIG_S3C_ADC30         &s3c_device_adc,31 #endif32 #if defined(CONFIG_TOUCHSCREEN_MINI6410) || defined(CONFIG_SAMSUNG_DEV_TS)33         &s3c_device_ts,34 #endif35         &s3c_device_wdt,36 #ifdef CONFIG_S3C_DEV_RTC37         &s3c_device_rtc,38 #endif39 40         /* Multimedia support */41 #ifdef CONFIG_VIDEO_SAMSUNG42         &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 #endif53 };

嗯,该数组里存放了很多设备,这些设备都会随着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         else16                 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_ERR34                                "%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行,很熟悉了,在上一篇已经说过。

 

转载于:https://www.cnblogs.com/lknlfy/archive/2012/05/08/2489209.html

你可能感兴趣的文章
HTTP Analyzer——WEB调试代理
查看>>
shell date 命令整理
查看>>
史上最全Java表单验证封装类
查看>>
nuget命令的用法:
查看>>
矩阵构造方法(转载)
查看>>
UIView下使用Animation控制动画
查看>>
Lowest Common Ancestor of Two Nodes in a Binary Tree
查看>>
(笔记)Linux 如何查看线程数最佳解决方案
查看>>
careercup-排序和查找 11.5
查看>>
Tomcat 生产服务器性能优化
查看>>
【开源一个小工具】一键将网页内容推送到Kindle
查看>>
Android -- Gradle
查看>>
Java的递归算法
查看>>
Kali Linux Web 渗透测试— 第二十课-metasploit.meterpreter
查看>>
程序员必须知道的几个Git代码托管平台
查看>>
MyBatis学习总结(四)——解决字段名与实体类属性名不相同的冲突
查看>>
Jenkins使用FTP进行一键部署及回滚2(Windows)(项目实践)
查看>>
【leetcode】solution in java——Easy2
查看>>
定义一个不能被继承的类
查看>>
STL容器之map
查看>>