存储卡具有体积小巧、携带方便、使用简单等优点,在嵌入式系统当中,一般作为独立的存储介质。Linux内核已经支持s3c2416的hsmmc控制器,可以支持mmc卡、sd卡等的读写。
1. hsmmc设备
hsmmc设备包含了名字、独有的资源等等一些驱动程序的硬件或自定义信息。通过platform_add_devices(platform_device_register)函数将定义的平台设备注册到内核中,用于匹配设备驱动。
内核在drivers\mmc\host\sdhci-s3c.c中实现了s3c2416 hsmmc驱动,hsmmc设备的平台代码如下。
#ifdef CONFIG_S3C_DEV_HSMMCstatic struct resources3c_hsmmc_resource[] = {[0]= DEFINE_RES_MEM(S3C_PA_HSMMC0, SZ_4K),[1]= DEFINE_RES_IRQ(IRQ_HSMMC0),};struct s3c_sdhci_platdatas3c_hsmmc0_def_platdata = {.max_width = 4,.host_caps = (MMC_CAP_4_BIT_DATA |MMC_CAP_MMC_HIGHSPEED |MMC_CAP_SD_HIGHSPEED),};struct platform_device s3c_device_hsmmc0= {.name = "s3c-sdhci",.id = 0,.num_resources = ARRAY_SIZE(s3c_hsmmc_resource),.resource = s3c_hsmmc_resource,.dev = {.dma_mask = &samsung_device_dma_mask,.coherent_dma_mask = DMA_BIT_MASK(32),.platform_data = &s3c_hsmmc0_def_platdata,},};void s3c_sdhci0_set_platdata(structs3c_sdhci_platdata *pd){s3c_sdhci_set_platdata(pd,&s3c_hsmmc0_def_platdata);}#endif /* CONFIG_S3C_DEV_HSMMC */#ifdef CONFIG_S3C_DEV_HSMMC1static struct resources3c_hsmmc1_resource[] = {[0]= DEFINE_RES_MEM(S3C_PA_HSMMC1, SZ_4K),[1]= DEFINE_RES_IRQ(IRQ_HSMMC1),};struct s3c_sdhci_platdatas3c_hsmmc1_def_platdata = {.max_width = 4,.host_caps = (MMC_CAP_4_BIT_DATA |MMC_CAP_MMC_HIGHSPEED |MMC_CAP_SD_HIGHSPEED),};struct platform_device s3c_device_hsmmc1= {.name = "s3c-sdhci",.id = 1,.num_resources = ARRAY_SIZE(s3c_hsmmc1_resource),.resource = s3c_hsmmc1_resource,.dev = {.dma_mask = &samsung_device_dma_mask,.coherent_dma_mask = DMA_BIT_MASK(32),.platform_data = &s3c_hsmmc1_def_platdata,},};void s3c_sdhci1_set_platdata(structs3c_sdhci_platdata *pd){s3c_sdhci_set_platdata(pd,&s3c_hsmmc1_def_platdata);}#endif /* CONFIG_S3C_DEV_HSMMC1 */static struct s3c_sdhci_platdatahome2416_hsmmc0_pdata __initdata = {.max_width = 4,.cd_type = S3C_SDHCI_CD_NONE,};static struct s3c_sdhci_platdatahome2416_hsmmc1_pdata __initdata = {.max_width = 4,.cd_type = S3C_SDHCI_CD_GPIO,.ext_cd_gpio = S3C2410_GPF(3),.ext_cd_gpio_invert = 1,};
在板级初始化函数home2416_machine_init ()中加入hsmmc平台数据s3c_sdhci0_set_platdata(&home2416_hsmmc0_pdata)和s3c_sdhci1_set_platdata(&home2416_hsmmc1_pdata)。在static struct platform_device *home2416_devices[]板级平台设备列表中加入&s3c_device_hsmmc0和&s3c_device_hsmmc1,使hcmmc0、hcmmc1设备能够注册到内核中。
修改并更正驱动文件sdhci-s3c.c。
在sdhci_s3c_probe()函数中,加入gpio检测sd卡。
#include <linux/mmc/slot-gpio.h>// addif(pdata->cd_type == S3C_SDHCI_CD_PERMANENT)host->mmc->caps= MMC_CAP_NONREMOVABLE;//addif(pdata->cd_type == S3C_SDHCI_CD_GPIO) {if(gpio_is_valid(pdata->ext_cd_gpio)) {ret= mmc_gpio_request_cd(host->mmc, pdata->ext_cd_gpio,0);if(ret) {dev_err(mmc_dev(host->mmc),"failedto allocate card detect gpio\n");gotoerr_req_regs;}}}
在sdhci_s3c_ops结构体中加入读sd卡写保护的实现.get_ro = sdhci_s3c_get_ro,本例sd卡没有硬件写保护。
// addstatic unsigned intsdhci_s3c_get_ro(struct sdhci_host *host){return 0; // write enable}static struct sdhci_ops sdhci_s3c_ops ={.get_ro = sdhci_s3c_get_ro, // add.get_max_clock = sdhci_s3c_get_max_clk,.set_clock = sdhci_s3c_set_clock,.get_min_clock = sdhci_s3c_get_min_clock,.set_bus_width = sdhci_s3c_set_bus_width,.reset = sdhci_reset,.set_uhs_signaling = sdhci_set_uhs_signaling,};
2. 内核配置
Linux内核配置支持hsmmc设备驱动,选中Device Drivers->MMC/SD/SDIO cardsupport->SDHCI support on Samsung S3C SoC。

sd卡使用fat32文件系统,配置内核支持vfat文件系统。File systems->DOS/FAT/NT Filesystems->VFAT (Windows-95) fssupport。

3. sd卡测试
cat/proc/devices可以知道hsmmc1的主设备好为179,次设备号为0,在/dev/block目录中创建mmcblk1设备文件。
mknod /dev/mmcblk1 b 179 0
cat/proc/partitions查看sd卡分区,先对sd卡格式化成vfat文件系统。
mkfs.vfat /dev/mmcblk1
挂载mmcblk1设备。
mkdir /mnt/sdmount /dev/mmcblk1 /mnt/sd
对sd卡读写文件。
echo This is file test. > /mnt/sd/test.txtcat /mnt/sd/test.txt

4. 应用编程
应用程序可以通过设备文件访问sd卡,hsmmc应用测试代码hsmmc_test.c如下。
#include "fcntl.h"#include "unistd.h"#include "sys/types.h"#include "stdio.h"#include "stdlib.h"#include "string.h"int main(void){intret;intfd;charwrite_buf[64] = "This is file test.";charread_buf[64];fd= open("/mnt/sd/test.txt", O_RDWR|O_CREAT);if(fd == -1) {printf("Openfile failed\n");exit(1);}ret= write(fd, write_buf, strlen(write_buf));if(ret == -1) {printf("Writefile failed\n");close(fd);exit(1);}close(fd);printf("write:%s\n", write_buf);fd= open("/mnt/sd/test.txt", O_RDONLY);ret= read(fd, read_buf, strlen(write_buf));if(ret == -1) {printf("Readfile failed\n");close(fd);exit(1);}read_buf[strlen(write_buf)]= 0;printf("read:%s\n", read_buf);close(fd);return0;}
用arm-linux-gcc静态编译,使之生成arm cpu可执行的指令,并且可脱离任何库独立运行,arm-linux-gcc -static -o hsmmc_test hsmmc_test.c,生成hsmmc_test可执行文件。复制可执行文件到根文件系统,目标板启动后在目录输入./hsmmc_test即可执行。

