imx6 android4.4.2内核sd卡platform_device注册加载原理
来源:互联网 发布:linux ftp 指定目录 编辑:程序博客网 时间:2024/05/18 20:34
linux内核:3.0.8
安卓:4.4.2
作者:254008829@qq.com
1.概述
此版飞思卡尔imx6SDK的内核是3.0.8还没有引入设备树,所以还是传统的platform_device和platform_driver方式进行注册和驱动加载的。
2.platform_device的 注册入口点
arch/arm/mach-mx6/board-mx6q_sabresd.c文件中函数mx6_sabresd_board_init调用imx6q_add_sdhci_usdhc_imx现实的。关系如下:
board-mx6q_sabresd.cmx6_sabresd_board_inimx6q_add_sdhci_usdhc_imx
imx6q_add_sdhci_usdhc_imx是一个宏函数,它有两个参数,@arg1:id,@arg2:pdata。
id表示sdio的通道号,如我们单板SDIO1(从1开始数)外接的是SD卡,其对应的id等于0。
pdata是conststruct esdhc_platform_data类型的指针。
3.struct esdhc_platform_data结构详解
struct esdhc_platform_data {unsigned int wp_gpio;unsigned int cd_gpio;enum cd_types cd_type;unsigned int always_present;unsigned int support_18v;unsigned int support_8bit;unsigned int keep_power_at_suspend;unsigned int delay_line;bool runtime_pm;int (*platform_pad_change)(unsigned int index, int clock);};
wp_gpio:如果外设芯片有写保护引脚接到IMXCPU,则将它的值赋值给它,否则填-EINVAL。imx6引脚值都统一用宏IMX_GPIO_NR来定义,如GPIO_5_7,则其值为IMX_GPIO_NR(5,7)。
cd_gpio:如果外设是有中断检测引脚来检测外设是否插入,则需要给此成员赋值。典型的应用是SD卡,一般都是需要支持热插拔的,有中断检测引脚。将引脚值用IMX_GPIO_NR来定义。
cd_type:
enum cd_types {ESDHC_CD_NONE, /* no CD, neither controller nor gpio */ESDHC_CD_CONTROLLER, /* mmc controller internal CD */ESDHC_CD_GPIO, /* external gpio pin for CD */ESDHC_CD_PERMANENT, /* no CD, card permanently wired to host */};
如果cd_gpio定义了,则cd_type填ESDHC_CD_GPIO。
always_present:是否一直在卡槽里,或者一直和IMXCPU的SDIO连接,如果是则填1,否则为0。
support_8bit:这是一个关键的参数。一般SD卡是4bit数据线,EMMC是8bit数据线,如果是8bit则为1,否则为0。我的外设是SD卡所以此值为0。
在board-mx6q_sabresd.c中定义一个自己的conststruct esdhc_platform_data变量,如下:
// sdcardstatic const struct esdhc_platform_data mx6q_sabresd_sd1_data __initconst = { .cd_gpio = T6_V2_SD_DET, .wp_gpio = -EINVAL,.keep_power_at_suspend = 1,.support_8bit = 0,.delay_line = 0, .cd_type = ESDHC_CD_GPIO, .runtime_pm = 1,};
调用函数将之注册:imx6q_add_sdhci_usdhc_imx(0,&mx6q_sabresd_sd1_data);
4.深度解析imx6q_add_sdhci_usdhc_imx
此函数是一个宏函数,定义如下:
#defineimx6q_add_sdhci_usdhc_imx(id, pdata) \
imx_add_sdhci_esdhc_imx(&imx6q_sdhci_usdhc_imx_data[id],pdata)
接着会调用imx_add_sdhci_esdhc_imx,其中第一个参数变成了一个数组的第id个元素的指针。
关键点在于imx6q_sdhci_usdhc_imx_data是干什么的?
往后追代码:
const struct imx_sdhci_esdhc_imx_data imx6q_sdhci_usdhc_imx_data[] = {#define imx6q_sdhci_usdhc_imx_data_entry(_id, _hwid)\imx_sdhci_usdhc_imx_data_entry(MX6Q, _id, _hwid)imx6q_sdhci_usdhc_imx_data_entry(0, 1),imx6q_sdhci_usdhc_imx_data_entry(1, 2),imx6q_sdhci_usdhc_imx_data_entry(2, 3),imx6q_sdhci_usdhc_imx_data_entry(3, 4),};
结构数据中对应结构的定义为:
struct imx_sdhci_esdhc_imx_data {int id;resource_size_t iobase;resource_size_t irq;};
imx_sdhci_usdhc_imx_data_entry这个宏从字面上来看就是imxsd数据项,这种和具体平台相关的数据有哪些呢,无非是控制器的iobase,irq的编号等等。层层解剖马上就见真面目了。
#define imx_sdhci_esdhc_imx_data_entry(soc, id, hwid)\[id] = imx_sdhci_esdhc_imx_data_entry_single(soc, id, hwid)#define imx_sdhci_esdhc_imx_data_entry_single(soc, _id, hwid) \{\.id = _id,\.iobase = soc ## _ESDHC ## hwid ## _BASE_ADDR,\.irq = soc ## _INT_ESDHC ## hwid,\}
至此总结下:imx6q_add_sdhci_usdhc_imx函数通过id,pdata。将一个和imx6平台相关的structimx_sdhci_esdhc_imx_data的结构指针和mx6q_sabresd_sd1_data(&mx6q_sabresd_sd1_data就是下文多次提到的pdata)的地址传给了调用者imx_add_sdhci_esdhc_imx。
5.imx_add_sdhci_esdhc_imx函数什么的干活
定义如下:
struct platform_device *__init imx_add_sdhci_esdhc_imx(const struct imx_sdhci_esdhc_imx_data *data,const struct esdhc_platform_data *pdata){struct resource res[] = {{.start = data->iobase,.end = data->iobase + SZ_16K - 1,.flags = IORESOURCE_MEM,}, {.start = data->irq,.end = data->irq,.flags = IORESOURCE_IRQ,},};return imx_add_platform_device_dmamask("sdhci-esdhc-imx", data->id, res,ARRAY_SIZE(res), pdata, sizeof(*pdata), DMA_BIT_MASK(32));}
此函数将iobase,irq等硬件资源生成一个linux标准的structresource res对象。
终极调用者为imx_add_platform_device_dmamask,此函数指定了platform_device的名字,id,资源对象,以及在board-mx6q_sabresd.c中定义的一个pdata(&mx6q_sabresd_sd1_data)。最后一个参数DMA_BIT_MASK(32)是设定DMA的工作位数。
imx_add_platform_device_dmamask函数定义:
struct platform_device *__init imx_add_platform_device_dmamask(const char *name, int id,const struct resource *res, unsigned int num_resources,const void *data, size_t size_data, u64 dmamask){int ret = -ENOMEM;struct platform_device *pdev;pdev = platform_device_alloc(name, id);if (!pdev)goto err;if (dmamask) {/* * This memory isn't freed when the device is put, * I don't have a nice idea for that though. Conceptually * dma_mask in struct device should not be a pointer. * See http://thread.gmane.org/gmane.linux.kernel.pci/9081 */pdev->dev.dma_mask =kmalloc(sizeof(*pdev->dev.dma_mask), GFP_KERNEL);if (!pdev->dev.dma_mask)/* ret is still -ENOMEM; */goto err;*pdev->dev.dma_mask = dmamask;pdev->dev.coherent_dma_mask = dmamask;}if (res) {ret = platform_device_add_resources(pdev, res, num_resources);if (ret)goto err;}if (data) {ret = platform_device_add_data(pdev, data, size_data);if (ret)goto err;}ret = platform_device_add(pdev);if (ret) {err:if (dmamask)kfree(pdev->dev.dma_mask);platform_device_put(pdev);return ERR_PTR(ret);}return pdev;}
这函数比较容易,定义一个structplatform_device类型的指针pdev。将传入的res和pdata添加进入pdev成员里。最后调用platform_device_add(pdev)将之注册进linux系统。
- imx6 android4.4.2内核sd卡platform_device注册加载原理
- imx6 android SD卡启动
- 新路程------imx6 sd卡部分摘要
- acpi 自动注册platform_device
- SD卡加载和引导WinCE内核映像的实现
- Android4.4.2 外置SD卡 无法写入问题
- IMX6DL 在Android4.4.2版本插入SD卡不能开机
- imx6 android4.4增加ethernet
- 基于linux 3.10.49内核 从dts文件里注册platform_device流程分析
- Android4.0实现双sd卡
- 关于android4.4外置sd卡读写
- Android4.4之后SD卡存储方案
- android4.4.4访问sd卡问题
- imx6.内核Makefile编写
- platform_device的注册过程分析
- platform_device的注册详情分析
- acpi 自动注册platform_device 2
- 手动注册platform_device 测试rtc
- js判断设备类型,微信浏览器
- 用SQLLDR来装载CLOB/BLOB列的控制文件例子
- Downloads for Apple Developers (Apple开发工具,Xcode safari等)
- Spring Cloud和Docker 来构建微服务
- SQL查询按某字段排序的最大值
- imx6 android4.4.2内核sd卡platform_device注册加载原理
- 在arc模式下 CGImage 释放问题
- 关于java中几个CP的一点说明--stringBuilder和stringBuffer与hashTable和hashMap
- 面试准备,待补充
- 从头开始
- linux下统计当前文件夹中文件的数目以及如何查看文件夹的大小
- 程序员及嵌入式的一些学习建议
- asp.net 网页抓取内容
- Android开发常见异常与错误系列(一)