----------------------------------------------------------
sd卡driver最关键的是host部分,各个厂商需要根据自己平台的特性,定制自己的host
部分,当然内核也会提供一个专用的描述结构,在这里就是:
struct mmc_host {
171 struct device *parent;
172 struct device class_dev;
173 int index; //编号
174 const struct mmc_host_ops *ops; //特定控制器的操作函数,这个很重要
175 unsigned int f_min;
176 unsigned int f_max;
177 unsigned int f_init;
178 u32 ocr_avail; //支持电压范围
179 u32 ocr_avail_sdio; /* SDIO-specific OCR */
180 u32 ocr_avail_sd; /* SD-specific OCR */
181 u32 ocr_avail_mmc; /* MMC-specific OCR */
182 struct notifier_block pm_notify;
183
184 #define MMC_VDD_165_195 0x00000080 /* VDD voltage 1.65 - 1.95 */
185 #define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */
186 #define MMC_VDD_21_22 0x00000200 /* VDD voltage 2.1 ~ 2.2 */
187 #define MMC_VDD_22_23 0x00000400 /* VDD voltage 2.2 ~ 2.3 */
188 #define MMC_VDD_23_24 0x00000800 /* VDD voltage 2.3 ~ 2.4 */
189 #define MMC_VDD_24_25 0x00001000 /* VDD voltage 2.4 ~ 2.5 */
190 #define MMC_VDD_25_26 0x00002000 /* VDD voltage 2.5 ~ 2.6 */
191 #define MMC_VDD_26_27 0x00004000 /* VDD voltage 2.6 ~ 2.7 */
192 #define MMC_VDD_27_28 0x00008000 /* VDD voltage 2.7 ~ 2.8 */
193 #define MMC_VDD_28_29 0x00010000 /* VDD voltage 2.8 ~ 2.9 */
194 #define MMC_VDD_29_30 0x00020000 /* VDD voltage 2.9 ~ 3.0 */
195 #define MMC_VDD_30_31 0x00040000 /* VDD voltage 3.0 ~ 3.1 */
196 #define MMC_VDD_31_32 0x00080000 /* VDD voltage 3.1 ~ 3.2 */
197 #define MMC_VDD_32_33 0x00100000 /* VDD voltage 3.2 ~ 3.3 */
198 #define MMC_VDD_33_34 0x00200000 /* VDD voltage 3.3 ~ 3.4 */
199 #define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */
200 #define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */
201
202 unsigned long caps; /* Host capabilities */
203
204 #define MMC_CAP_4_BIT_DATA (1 << 0) /* Can the host do 4 bit transfers */
205 #define MMC_CAP_MMC_HIGHSPEED (1 << 1) /* Can do MMC high-speed timing */
206 #define MMC_CAP_SD_HIGHSPEED (1 << 2) /* Can do SD high-speed timing */
207 #define MMC_CAP_SDIO_IRQ (1 << 3) /* Can signal pending SDIO IRQs */
208 #define MMC_CAP_SPI (1 << 4) /* Talks only SPI protocols */
209 #define MMC_CAP_NEEDS_POLL (1 << 5) /* Needs polling for card-detection */
210 #define MMC_CAP_8_BIT_DATA (1 << 6) /* Can the host do 8 bit transfers */
211 #define MMC_CAP_DISABLE (1 << 7) /* Can the host be disabled */
212 #define MMC_CAP_NONREMOVABLE (1 << 8) /* Nonremovable e.g. eMMC */
213 #define MMC_CAP_WAIT_WHILE_BUSY (1 << 9) /* Waits while card is busy */
214 #define MMC_CAP_ERASE (1 << 10) /* Allow erase/trim commands */
215 #define MMC_CAP_1_8V_DDR (1 << 11) /* can support */
216 /* DDR mode at 1.8V */
217 #define MMC_CAP_1_2V_DDR (1 << 12) /* can support */
218 /* DDR mode at 1.2V */
219 #define MMC_CAP_POWER_OFF_CARD (1 << 13) /* Can power off after boot */
220 #define MMC_CAP_BUS_WIDTH_TEST (1 << 14) /* CMD14/CMD19 bus width ok */
221 #define MMC_CAP_UHS_SDR12 (1 << 15) /* Host supports UHS SDR12 mode */
222 #define MMC_CAP_UHS_SDR25 (1 << 16) /* Host supports UHS SDR25 mode */
223 #define MMC_CAP_UHS_SDR50 (1 << 17) /* Host supports UHS SDR50 mode */
224 #define MMC_CAP_UHS_SDR104 (1 << 18) /* Host supports UHS SDR104 mode */
225 #define MMC_CAP_UHS_DDR50 (1 << 19) /* Host supports UHS DDR50 mode */
226 #define MMC_CAP_SET_XPC_330 (1 << 20) /* Host supports >150mA current at 3.3V */
227 #define MMC_CAP_SET_XPC_300 (1 << 21) /* Host supports >150mA current at 3.0V */
228 #define MMC_CAP_SET_XPC_180 (1 << 22) /* Host supports >150mA current at 1.8V */
229 #define MMC_CAP_DRIVER_TYPE_A (1 << 23) /* Host supports Driver Type A */
230 #define MMC_CAP_DRIVER_TYPE_C (1 << 24) /* Host supports Driver Type C */
231 #define MMC_CAP_DRIVER_TYPE_D (1 << 25) /* Host supports Driver Type D */
232 #define MMC_CAP_MAX_CURRENT_200 (1 << 26) /* Host max current limit is 200mA */
233 #define MMC_CAP_MAX_CURRENT_400 (1 << 27) /* Host max current limit is 400mA */
234 #define MMC_CAP_MAX_CURRENT_600 (1 << 28) /* Host max current limit is 600mA */
235 #define MMC_CAP_MAX_CURRENT_800 (1 << 29) /* Host max current limit is 800mA */
236 #define MMC_CAP_CMD23 (1 << 30) /* CMD23 supported. */
237 #define MMC_CAP_HW_RESET (1 << 31) /* Hardware reset */
238
239 unsigned int caps2; /* More host capabilities */
240
241 #define MMC_CAP2_BOOTPART_NOACC (1 << 0) /* Boot partition no access */
242 #define MMC_CAP2_CACHE_CTRL (1 << 1) /* Allow cache control */
243 #define MMC_CAP2_POWEROFF_NOTIFY (1 << 2) /* Notify poweroff supported */
244 #define MMC_CAP2_NO_MULTI_READ (1 << 3) /* Multiblock reads don't work */
245
246 mmc_pm_flag_t pm_caps; /* supported pm features */
247 unsigned int power_notify_type;
248 #define MMC_HOST_PW_NOTIFY_NONE 0
249 #define MMC_HOST_PW_NOTIFY_SHORT 1
250 #define MMC_HOST_PW_NOTIFY_LONG 2
251
252 #ifdef CONFIG_MMC_CLKGATE
253 int clk_requests; /* internal reference counter */
254 unsigned int clk_delay; /* number of MCI clk hold cycles */
255 bool clk_gated; /* clock gated */
256 struct work_struct clk_gate_work; /* delayed clock gate */
257 unsigned int clk_old; /* old clock value cache */
258 spinlock_t clk_lock; /* lock for clk fields */
259 struct mutex clk_gate_mutex; /* mutex for clock gating */
260 #endif
261
262 /* host specific block data */
263 unsigned int max_seg_size; /* see blk_queue_max_segment_size */
264 unsigned short max_segs; /* see blk_queue_max_segments */
265 unsigned short unused;
266 unsigned int max_req_size; /* maximum number of bytes in one req */
267 unsigned int max_blk_size; /* maximum size of one mmc block */
268 unsigned int max_blk_count; /* maximum number of blocks in one req */
269 unsigned int max_discard_to; /* max. discard timeout in ms */
270
271 /* private data */
272 spinlock_t lock; /* lock for claim and bus ops */
273
274 struct mmc_ios ios; /* current io bus settings */
275 u32 ocr; /* the current OCR setting */
276
277 /* group bitfields together to minimize padding */
278 unsigned int use_spi_crc:1;
279 unsigned int claimed:1; /* host exclusively claimed */
280 unsigned int bus_dead:1; /* bus has been released */
281 #ifdef CONFIG_MMC_DEBUG
282 unsigned int removed:1; /* host is being removed */
283 #endif
284
285 /* Only used with MMC_CAP_DISABLE */
286 int enabled; /* host is enabled */
287 int rescan_disable; /* disable card detection */
288 int nesting_cnt; /* "enable" nesting count */
289 int en_dis_recurs; /* detect recursion */
290 unsigned int disable_delay; /* disable delay in msecs */
291 struct delayed_work disable; /* disabling work */
292
293 struct mmc_card *card; /* device attached to this host */
294
295 wait_queue_head_t wq;
296 struct task_struct *claimer; /* task that has host claimed */
297 int claim_cnt; /* "claim" nesting count */
298
299 struct delayed_work detect;
300
301 const struct mmc_bus_ops *bus_ops; /* current bus driver */
302 unsigned int bus_refs; /* reference counter */
303
304 unsigned int sdio_irqs;
305 struct task_struct *sdio_irq_thread;
306 atomic_t sdio_irq_thread_abort;
307
308 mmc_pm_flag_t pm_flags; /* requested pm features */
309
310 #ifdef CONFIG_LEDS_TRIGGERS
311 struct led_trigger *led; /* activity led */
312 #endif
313
314 #ifdef CONFIG_REGULATOR
315 bool regulator_enabled; /* regulator state */
316 #endif
317
318 struct dentry *debugfs_root;
319
320 struct mmc_async_req *areq; /* active async req */
321
322 #ifdef CONFIG_FAIL_MMC_REQUEST
323 struct fault_attr fail_mmc_request;
324 #endif
325
326 unsigned long private[0] ____cacheline_aligned;
327 };
#厂商不会直接拿这个结构体来用,一般都是在这基础上封装出自己的结构,还是拿满街都是的mini来看吧,
struct s3cmci_host {
struct platform_device *pdev;
struct s3c24xx_mci_pdata *pdata;
struct mmc_host *mmc; //内嵌标准的结构
struct resource *mem;
struct clk *clk; 、
void __iomem *base;
int irq;
int irq_cd;
int dma; //dma通道
unsigned long clk_rate; //频率
unsigned long clk_div; //分频
unsigned long real_rate;
u8 prescaler;
int is2440; //平台判断
unsigned sdiimsk;
unsigned sdidata;
int dodma;
int dmatogo;
bool irq_disabled; //irq相关
bool irq_enabled;
bool irq_state;
int sdio_irqen;
struct mmc_request *mrq;
int cmd_is_stop;
spinlock_t complete_lock;
enum s3cmci_waitfor complete_what;
int dma_complete;
u32 pio_sgptr;
u32 pio_bytes;
u32 pio_count;
u32 *pio_ptr;
#define XFER_NONE 0
#define XFER_READ 1
#define XFER_WRITE 2
u32 pio_active;
int bus_width;
char dbgmsg_cmd[301];
char dbgmsg_dat[301];
char *status;
unsigned int ccnt, dcnt;
struct tasklet_struct pio_tasklet;
#ifdef CONFIG_DEBUG_FS
struct dentry *debug_root;
struct dentry *debug_state;
struct dentry *debug_regs;
#endif
#ifdef CONFIG_CPU_FREQ
struct notifier_block freq_transition;
#endif
};
#看一下host的注册过程吧,怎么进入mmc框架的,
#host对应的文件driver/mmc/host/s3cmci.c
#host的初始化
static int __init s3cmci_init(void)
{
return platform_driver_register(&s3cmci_driver);
}
static struct platform_driver s3cmci_driver = {
.driver = {
.name = "s3c-sdi",
.owner = THIS_MODULE,
.pm = s3cmci_pm_ops,
},
.id_table = s3cmci_driver_ids, //支持的列表
.probe = s3cmci_probe,
.remove = __devexit_p(s3cmci_remove),
.shutdown = s3cmci_shutdown,
};
#有了driver,把设备也翻出来,
#mach-mini2440.c
/* MMC/SD */
platform_add_devices(mini2440_devices, ARRAY_SIZE(mini2440_devices));
static struct platform_device *mini2440_devices[] __initdata = {
&s3c_device_ohci,
&s3c_device_wdt,
&s3c_device_i2c0,
&s3c_device_rtc,
&s3c_device_usbgadget,
&mini2440_device_eth,
&mini2440_led1,
&mini2440_led2,
&mini2440_led3,
&mini2440_led4,
&mini2440_button_device,
&s3c_device_nand,
&s3c_device_sdi,
&s3c_device_iis,
&uda1340_codec,
&mini2440_audio,
&samsung_asoc_dma,
};
struct platform_device s3c_device_sdi = {
.name = "s3c2410-sdi",
.id = -1,
.num_resources = ARRAY_SIZE(s3c_sdi_resource),
.resource = s3c_sdi_resource,
};
static struct resource s3c_sdi_resource[] = {
[0] = DEFINE_RES_MEM(S3C24XX_PA_SDI, S3C24XX_SZ_SDI),
[1] = DEFINE_RES_IRQ(IRQ_SDI),
};
#匹配后会调用probe,
#即:
static int __devinit s3cmci_probe(struct platform_device *pdev)
{
struct s3cmci_host *host; //封装的结构体
struct mmc_host *mmc; //标准mmc host
int ret;
int is2440;
int i;
is2440 = platform_get_device_id(pdev)->driver_data; //得到id号,判断具体平台
mmc = mmc_alloc_host(sizeof(struct s3cmci_host), &pdev->dev); //为host结构分配空间,id号,加入sys文件系统,还有个很重要的操作
if (!mmc) { //初始化了工作队列,mmc_rescan.
ret = -ENOMEM;
goto probe_out;
}
for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++) { //特定于平台的gpio配置
ret = gpio_request(i, dev_name(&pdev->dev));
if (ret) {
dev_err(&pdev->dev, "failed to get gpio %d\n", i);
for (i--; i >= S3C2410_GPE(5); i--)
gpio_free(i);
goto probe_free_host;
}
}
host = mmc_priv(mmc);
host->mmc = mmc;
host->pdev = pdev;
host->is2440 = is2440;
host->pdata = pdev->dev.platform_data;
if (!host->pdata) {
pdev->dev.platform_data = &s3cmci_def_pdata;
host->pdata = &s3cmci_def_pdata;
}
spin_lock_init(&host->complete_lock);
tasklet_init(&host->pio_tasklet, pio_tasklet, (unsigned long) host);
if (is2440) {
host->sdiimsk = S3C2440_SDIIMSK;
host->sdidata = S3C2440_SDIDATA;
host->clk_div = 1;
} else {
host->sdiimsk = S3C2410_SDIIMSK;
host->sdidata = S3C2410_SDIDATA;
host->clk_div = 2;
}
host->complete_what = COMPLETION_NONE;
host->pio_active = XFER_NONE;
#ifdef CONFIG_MMC_S3C_PIODMA
host->dodma = host->pdata->use_dma;
#endif
host->mem = platform_get_resource(pdev, IORESOURCE_MEM, 0); //io资源映射以及配置
if (!host->mem) {
dev_err(&pdev->dev,
"failed to get io memory region resouce.\n");
ret = -ENOENT;
goto probe_free_gpio;
}
host->mem = request_mem_region(host->mem->start,
resource_size(host->mem), pdev->name);
if (!host->mem) {
dev_err(&pdev->dev, "failed to request io memory region.\n");
ret = -ENOENT;
goto probe_free_gpio;
}
host->base = ioremap(host->mem->start, resource_size(host->mem));
if (!host->base) {
dev_err(&pdev->dev, "failed to ioremap() io memory region.\n");
ret = -EINVAL;
goto probe_free_mem_region;
}
host->irq = platform_get_irq(pdev,
0);
//中断的申请及配置,这个是控制器
//的中断信息,如命令成功与否,crc校验信息错误
if (host->irq == 0) {
dev_err(&pdev->dev, "failed to get interrupt resouce.\n");
ret = -EINVAL;
goto probe_iounmap;
}
if (request_irq(host->irq, s3cmci_irq, 0, DRIVER_NAME, host)) {
dev_err(&pdev->dev, "failed to request mci interrupt.\n");
ret = -ENOENT;
goto probe_iounmap;
}
/* We get spurious interrupts even when we have set the IMSK
* register to ignore everything, so use disable_irq() to make
* ensure we don't lock the system with un-serviceable requests. */
disable_irq(host->irq); //先disable该中断
host->irq_state = false;
if (!host->pdata->no_detect) { //插拔卡探测中断
ret = gpio_request(host->pdata->gpio_detect, "s3cmci detect");
if (ret) {
dev_err(&pdev->dev, "failed to get detect gpio\n");
goto probe_free_irq;
}
host->irq_cd = gpio_to_irq(host->pdata->gpio_detect);
if (host->irq_cd >= 0) { //必须双延触发,假如插入后为高,拔出则为低
if (request_irq(host->irq_cd, s3cmci_irq_cd,
IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING,
DRIVER_NAME, host)) {
dev_err(&pdev->dev,
"can't get card detect irq.\n");
ret = -ENOENT;
goto probe_free_gpio_cd;
}
} else {
dev_warn(&pdev->dev,
"host detect has no irq available\n");
gpio_direction_input(host->pdata->gpio_detect);
}
} else
host->irq_cd = -1;
//写保护???
if (!host->pdata->no_wprotect) {
ret = gpio_request(host->pdata->gpio_wprotect, "s3cmci wp");
if (ret) {
dev_err(&pdev->dev, "failed to get writeprotect\n");
goto probe_free_irq_cd;
}
gpio_direction_input(host->pdata->gpio_wprotect);
}
/* depending on the dma state, get a dma channel to use. */
//dma通道请求
if (s3cmci_host_usedma(host)) {
host->dma = s3c2410_dma_request(DMACH_SDI, &s3cmci_dma_client,
host);
if (host->dma < 0) {
dev_err(&pdev->dev, "cannot get DMA channel.\n");
if (!s3cmci_host_canpio()) {
ret = -EBUSY;
goto probe_free_gpio_wp;
} else {
dev_warn(&pdev->dev, "falling back to PIO.\n");
host->dodma = 0;
}
}
}
//io clk
host->clk = clk_get(&pdev->dev, "sdi");
if (IS_ERR(host->clk)) {
dev_err(&pdev->dev, "failed to find clock source.\n");
ret = PTR_ERR(host->clk);
host->clk = NULL;
goto probe_free_dma;
}
//使能
ret = clk_enable(host->clk);
if (ret) {
dev_err(&pdev->dev, "failed to enable clock source.\n");
goto clk_free;
}
host->clk_rate = clk_get_rate(host->clk);
mmc->ops = &s3cmci_ops; //mmc操作函数,重要
mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34; //支持电压范围,预定义值
#ifdef CONFIG_MMC_S3C_HW_SDIO_IRQ
mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
#else
mmc->caps = MMC_CAP_4_BIT_DATA;
#endif
mmc->f_min = host->clk_rate / (host->clk_div * 256);
mmc->f_max = host->clk_rate / host->clk_div;
if (host->pdata->ocr_avail)
mmc->ocr_avail = host->pdata->ocr_avail; //平台相关自己设定值
mmc->max_blk_count = 4095; //块数量,大小
mmc->max_blk_size = 4095;
mmc->max_req_size = 4095 * 512;
mmc->max_seg_size = mmc->max_req_size;
mmc->max_segs = 128;
dbg(host, dbg_debug,
"probe: mode:%s mapped mci_base:%p irq:%u irq_cd:%u dma:%u.\n",
(host->is2440?"2440":""),
host->base, host->irq, host->irq_cd, host->dma);
ret = s3cmci_cpufreq_register(host); //通知链,状态改变
if (ret) {
dev_err(&pdev->dev, "failed to register cpufreq\n");
goto free_dmabuf;
}
ret = mmc_add_host(mmc);
//把host加入,每个平台都会调用该函数把host真正加入linux子系统,下文会介绍
if (ret) {
dev_err(&pdev->dev, "failed to add mmc host.\n");
goto free_cpufreq;
}
s3cmci_debugfs_attach(host);
platform_set_drvdata(pdev, mmc);
dev_info(&pdev->dev, "%s - using %s, %s SDIO IRQ\n", mmc_hostname(mmc),
s3cmci_host_usedma(host) ? "dma" : "pio",
mmc->caps & MMC_CAP_SDIO_IRQ ? "hw" : "sw");
return 0;
free_cpufreq:
s3cmci_cpufreq_deregister(host);
free_dmabuf:
clk_disable(host->clk);
clk_free:
clk_put(host->clk);
probe_free_dma:
if (s3cmci_host_usedma(host))
s3c2410_dma_free(host->dma, &s3cmci_dma_client);
probe_free_gpio_wp:
if (!host->pdata->no_wprotect)
gpio_free(host->pdata->gpio_wprotect);
probe_free_gpio_cd:
if (!host->pdata->no_detect)
gpio_free(host->pdata->gpio_detect);
probe_free_irq_cd:
if (host->irq_cd >= 0)
free_irq(host->irq_cd, host);
probe_free_irq:
free_irq(host->irq, host);
probe_iounmap:
iounmap(host->base);
probe_free_mem_region:
release_mem_region(host->mem->start, resource_size(host->mem));
probe_free_gpio:
for (i = S3C2410_GPE(5); i <= S3C2410_GPE(10); i++)
gpio_free(i);
probe_free_host:
mmc_free_host(mmc);
probe_out:
return ret;
}
#重点是mmc_add_host函数,
#drivers/mmc/core/host.c
/**
* mmc_add_host - initialise host hardware
* @host: mmc host
*
* Register the host with the driver model. The host must be
* prepared to start servicing requests before this function
* completes.
*/
int mmc_add_host(struct mmc_host *host)
{
int err;
WARN_ON((host->caps & MMC_CAP_SDIO_IRQ) &&
!host->ops->enable_sdio_irq);
err = device_add(&host->class_dev); //加入bus
if (err)
return err;
led_trigger_register_simple(dev_name(&host->class_dev), &host->led);
//用于显示卡状态的led
#ifdef CONFIG_DEBUG_FS
mmc_add_host_debugfs(host);
#endif
mmc_start_host(host);
register_pm_notifier(&host->pm_notify); //加入块设备通知链
return 0;
}
EXPORT_SYMBOL(mmc_add_host);
#继续mmc_start_host(host);
/drivers/mmc/core/core.c
void mmc_start_host(struct mmc_host *host)
{
mmc_power_off(host); //host power off
mmc_detect_change(host, 0); //detect
}
这两个函数都很重要,放到下文来说明。
总结:概要的说明了添加一个mmc host的过程,下文会重点分析一些很重要的函数,包括mmc_rescan.
Thanks
----------------------------------------------------------
继续上一篇文章,先看一个重点结构,平台相关,真正对host的设置都会回调到这里
static struct mmc_host_ops s3cmci_ops = {
.request = s3cmci_request, //用于命令和数据的发送接收
.set_ios = s3cmci_set_ios, //用于设置io
.get_ro = s3cmci_get_ro, //用于判断写保护
.get_cd = s3cmci_card_present, //判断卡是否存在
.enable_sdio_irq = s3cmci_enable_sdio_irq,
};
####先看最复杂的命令请求
static void s3cmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
{
struct s3cmci_host *host = mmc_priv(mmc);
host->status = "mmc request"; //设置状态
host->cmd_is_stop = 0;
host->mrq = mrq; //请求结构描述
if (s3cmci_card_present(mmc) == 0) { //卡是否存在
dbg(host, dbg_err, "%s: no medium present\n", __func__);
host->mrq->cmd->error = -ENOMEDIUM;
mmc_request_done(mmc, mrq); //无卡结束
} else
s3cmci_send_request(mmc); //有卡发送
}
@继续
static void s3cmci_send_request(struct mmc_host *mmc)
{
struct s3cmci_host *host = mmc_priv(mmc);
struct mmc_request *mrq = host->mrq;
struct mmc_command *cmd = host->cmd_is_stop ? mrq->stop : mrq->cmd;
//只有stop和命令请求?
host->ccnt++;
prepare_dbgmsg(host, cmd, host->cmd_is_stop);
/* Clear command, data and fifo status registers
Fifo clear only necessary on 2440, but doesn't hurt on 2410
请求状态
*/
writel(0xFFFFFFFF, host->base + S3C2410_SDICMDSTAT);
writel(0xFFFFFFFF, host->base + S3C2410_SDIDSTA);
writel(0xFFFFFFFF, host->base + S3C2410_SDIFSTA);
if (cmd->data) {
int res = s3cmci_setup_data(host, cmd->data);
host->dcnt++;
if (res) {
dbg(host, dbg_err, "setup data error %d\n", res);
cmd->error = res;
cmd->data->error = res;
mmc_request_done(mmc, mrq);
return;
}
if (s3cmci_host_usedma(host)) //是否用dma
res = s3cmci_prepare_dma(host, cmd->data);
else
res = s3cmci_prepare_pio(host, cmd->data);
if (res) {
dbg(host, dbg_err, "data prepare error %d\n", res);
cmd->error = res;
cmd->data->error = res;
mmc_request_done(mmc, mrq);
return;
}
}
/* Send command */
s3cmci_send_command(host, cmd); //发送命令
/* Enable Interrupt */
s3cmci_enable_irq(host, true); //使能中断
}
###设置命令数据到相应寄存器
static int s3cmci_setup_data(struct s3cmci_host *host, struct mmc_data *data)
{
u32 dcon, imsk, stoptries = 3;
/* write DCON register */
if (!data) {
writel(0, host->base + S3C2410_SDIDCON);
return 0;
}
if ((data->blksz & 3) != 0) {
/* We cannot deal with unaligned blocks with more than
* one block being transferred. */
if (data->blocks > 1) {
pr_warning("%s: can't do non-word sized block transfers (blksz %d)\n", __func__, data->blksz);
return -EINVAL;
}
}
while (readl(host->base + S3C2410_SDIDSTA) &
(S3C2410_SDIDSTA_TXDATAON | S3C2410_SDIDSTA_RXDATAON)) {
dbg(host, dbg_err,
"mci_setup_data() transfer stillin progress.\n");
writel(S3C2410_SDIDCON_STOP, host->base + S3C2410_SDIDCON);
s3cmci_reset(host);
if ((stoptries--) == 0) {
dbg_dumpregs(host, "DRF");
return -EINVAL;
}
}
dcon = data->blocks & S3C2410_SDIDCON_BLKNUM_MASK;
if (s3cmci_host_usedma(host))
dcon |= S3C2410_SDIDCON_DMAEN;
if (host->bus_width == MMC_BUS_WIDTH_4)
dcon |= S3C2410_SDIDCON_WIDEBUS;
if (!(data->flags & MMC_DATA_STREAM))
dcon |= S3C2410_SDIDCON_BLOCKMODE;
if (data->flags & MMC_DATA_WRITE) {
dcon |= S3C2410_SDIDCON_TXAFTERRESP;
dcon |= S3C2410_SDIDCON_XFER_TXSTART;
}
if (data->flags & MMC_DATA_READ) {
dcon |= S3C2410_SDIDCON_RXAFTERCMD;
dcon |= S3C2410_SDIDCON_XFER_RXSTART;
}
if (host->is2440) {
dcon |= S3C2440_SDIDCON_DS_WORD;
dcon |= S3C2440_SDIDCON_DATSTART;
}
writel(dcon, host->base + S3C2410_SDIDCON);
/* write BSIZE register */
writel(data->blksz, host->base + S3C2410_SDIBSIZE);
/* add to IMASK register */
imsk = S3C2410_SDIIMSK_FIFOFAIL | S3C2410_SDIIMSK_DATACRC |
S3C2410_SDIIMSK_DATATIMEOUT | S3C2410_SDIIMSK_DATAFINISH;
enable_imask(host, imsk);
/* write TIMER register */
if (host->is2440) {
writel(0x007FFFFF, host->base + S3C2410_SDITIMER);
} else {
writel(0x0000FFFF, host->base + S3C2410_SDITIMER);
/* FIX: set slow clock to prevent timeouts on read */
if (data->flags & MMC_DATA_READ)
writel(0xFF, host->base + S3C2410_SDIPRE);
}
return 0;
}
####发送命令
static void s3cmci_send_command(struct s3cmci_host *host,
struct mmc_command *cmd)
{
u32 ccon, imsk;
imsk = S3C2410_SDIIMSK_CRCSTATUS | S3C2410_SDIIMSK_CMDTIMEOUT |
S3C2410_SDIIMSK_RESPONSEND | S3C2410_SDIIMSK_CMDSENT |
S3C2410_SDIIMSK_RESPONSECRC;
enable_imask(host, imsk);
if (cmd->data) //完成标志
host->complete_what = COMPLETION_XFERFINISH_RSPFIN;
else if (cmd->flags & MMC_RSP_PRESENT)
host->complete_what = COMPLETION_RSPFIN;
else
host->complete_what = COMPLETION_CMDSENT;
writel(cmd->arg, host->base + S3C2410_SDICMDARG);
ccon = cmd->opcode & S3C2410_SDICMDCON_INDEX;
ccon |= S3C2410_SDICMDCON_SENDERHOST | S3C2410_SDICMDCON_CMDSTART;
if (cmd->flags & MMC_RSP_PRESENT)
ccon |= S3C2410_SDICMDCON_WAITRSP;
if (cmd->flags & MMC_RSP_136)
ccon |= S3C2410_SDICMDCON_LONGRSP;
writel(ccon, host->base + S3C2410_SDICMDCON);
}
####使能中断,对接上前一篇文章的irq申请部分,
/**
* s3cmci_enable_irq - enable IRQ, after having disabled it.
* @host: The device state.
* @more: True if more IRQs are expected from transfer.
*
* Enable the main IRQ if needed after it has been disabled.
*
* The IRQ can be one of the following states:
* - disabled during IDLE
* - disabled whilst processing data
* - enabled during transfer
* - enabled whilst awaiting SDIO interrupt detection
*/
static void s3cmci_enable_irq(struct s3cmci_host *host, bool more)
{
unsigned long flags;
bool enable = false;
local_irq_save(flags);
host->irq_enabled = more;
host->irq_disabled = false;
enable = more | host->sdio_irqen;
if (host->irq_state != enable) {
host->irq_state = enable;
if (enable)
enable_irq(host->irq);
else
disable_irq(host->irq);
}
local_irq_restore(flags);
}
#####set_ios函数,
static void s3cmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
{
struct s3cmci_host *host = mmc_priv(mmc);
u32 mci_con;
/* Set the power state */
mci_con = readl(host->base + S3C2410_SDICON);
switch (ios->power_mode) { //设置模式选择
case MMC_POWER_ON:
case MMC_POWER_UP: //打开或者增强都对应于配置gpio
s3c2410_gpio_cfgpin(S3C2410_GPE(5), S3C2410_GPE5_SDCLK);
s3c2410_gpio_cfgpin(S3C2410_GPE(6), S3C2410_GPE6_SDCMD);
s3c2410_gpio_cfgpin(S3C2410_GPE(7), S3C2410_GPE7_SDDAT0);
s3c2410_gpio_cfgpin(S3C2410_GPE(8), S3C2410_GPE8_SDDAT1);
s3c2410_gpio_cfgpin(S3C2410_GPE(9), S3C2410_GPE9_SDDAT2);
s3c2410_gpio_cfgpin(S3C2410_GPE(10), S3C2410_GPE10_SDDAT3);
if (host->pdata->set_power) //2440比较简单,没有verg对应设置
host->pdata->set_power(ios->power_mode, ios->vdd);
if (!host->is2440)
mci_con |= S3C2410_SDICON_FIFORESET;
break;
case MMC_POWER_OFF: //关闭部分
default:
gpio_direction_output(S3C2410_GPE(5), 0);
if (host->is2440)
mci_con |= S3C2440_SDICON_SDRESET;
if (host->pdata->set_power)
host->pdata->set_power(ios->power_mode, ios->vdd);
break;
}
s3cmci_set_clk(host, ios); //设置clk
/* Set CLOCK_ENABLE */
if (ios->clock)
mci_con |= S3C2410_SDICON_CLOCKTYPE;
else
mci_con &= ~S3C2410_SDICON_CLOCKTYPE;
writel(mci_con, host->base + S3C2410_SDICON);
if ((ios->power_mode == MMC_POWER_ON) ||
(ios->power_mode == MMC_POWER_UP)) {
dbg(host, dbg_conf, "running at %lukHz (requested: %ukHz).\n",
host->real_rate/1000, ios->clock/1000);
} else {
dbg(host, dbg_conf, "powered down.\n");
}
host->bus_width = ios->bus_width;
}
####设置clock函数
static void s3cmci_set_clk(struct s3cmci_host *host, struct mmc_ios *ios)
{
u32 mci_psc;
/* Set clock */
for (mci_psc = 0; mci_psc < 255; mci_psc++) {
host->real_rate = host->clk_rate / (host->clk_div*(mci_psc+1));
if (host->real_rate <= ios->clock)
break;
}
if (mci_psc > 255)
mci_psc = 255;
host->prescaler = mci_psc;
writel(host->prescaler, host->base + S3C2410_SDIPRE);
/* If requested clock is 0, real_rate will be 0, too */
if (ios->clock == 0)
host->real_rate = 0;
}
######写保护函数:
static int s3cmci_get_ro(struct mmc_host *mmc)
{
struct s3cmci_host *host = mmc_priv(mmc);
struct s3c24xx_mci_pdata *pdata = host->pdata;
int ret;
if (pdata->no_wprotect)
return 0;
ret = gpio_get_value(pdata->gpio_wprotect) ? 1 : 0;
ret ^= pdata->wprotect_invert;
return ret;
}
######探测卡函数
static int s3cmci_card_present(struct mmc_host *mmc)
{
struct s3cmci_host *host = mmc_priv(mmc);
struct s3c24xx_mci_pdata *pdata = host->pdata;
int ret;
if (pdata->no_detect) //没有探测函数
return -ENOSYS;
ret = gpio_get_value(pdata->gpio_detect) ? 0 : 1; //直接读取gpio值
return ret ^ pdata->detect_invert;
}
#####下面说一下上文遗留几个函数,
/drivers/mmc/core/core.c
void mmc_start_host(struct mmc_host *host)
{
mmc_power_off(host); //host power off
mmc_detect_change(host, 0); //detect
}
#####首先是mmc_power_off(host),
#####同文件下的
void mmc_power_off(struct mmc_host *host)
{
mmc_host_clk_hold(host); //clk可能恢复到先前的一个值,
host->ios.clock = 0; //强制设置成0?
host->ios.vdd = 0;
mmc_poweroff_notify(host);
/*
* Reset ocr mask to be the highest possible voltage supported for
* this mmc host. This value will be used at next power up.
*/
host->ocr = 1 << (fls(host->ocr_avail) - 1); //支持的最大电压
if (!mmc_host_is_spi(host)) { //不是spi
host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN; //漏极开路式
host->ios.chip_select = MMC_CS_DONTCARE; //不关心cs
}
host->ios.power_mode = MMC_POWER_OFF; //状态power_off
host->ios.bus_width = MMC_BUS_WIDTH_1;
host->ios.timing = MMC_TIMING_LEGACY;
mmc_set_ios(host); //关闭电压,真正设置成0
/*
* Some configurations, such as the 802.11 SDIO card in the OLPC
* XO-1.5, require a short delay after poweroff before the card
* can be successfully turned on again.
*/
mmc_delay(1); //短暂延迟
mmc_host_clk_release(host); //disable
}
######同文件夹下
/**
* mmc_host_clk_hold - ungate hardware MCI clocks
* @host: host to ungate.
* //gate用于限制保证有最低clk???
* Makes sure the host ios.clock is restored to a non-zero value
* past this call. Increase clock reference count and ungate clock
* if we're the first user.
*/
void mmc_host_clk_hold(struct mmc_host *host)
{
unsigned long flags;
mutex_lock(&host->clk_gate_mutex);
spin_lock_irqsave(&host->clk_lock, flags);
if (host->clk_gated) {
spin_unlock_irqrestore(&host->clk_lock, flags);
mmc_ungate_clock(host);
spin_lock_irqsave(&host->clk_lock, flags);
pr_debug("%s: ungated MCI clock\n", mmc_hostname(host));
}
host->clk_requests++;
spin_unlock_irqrestore(&host->clk_lock, flags);
mutex_unlock(&host->clk_gate_mutex);
}
########位于drivers/mmc/core/core.c
/*
* This restores the clock from gating by using the cached
* clock value.
*/
void mmc_ungate_clock(struct mmc_host *host)
{
/*
* We should previously have gated the clock, so the clock shall
* be 0 here! The clock may however be 0 during initialization,
* when some request operations are performed before setting
* the frequency. When ungate is requested in that situation
* we just ignore the call.
*/
if (host->clk_old) {
BUG_ON(host->ios.clock);
/* This call will also set host->clk_gated to false */
__mmc_set_clock(host, host->clk_old);
}
}
#####看样子gate缓存了clk值,可以恢复到上一个clk值.
#####跟进去
/*
* Sets the host clock to the highest possible frequency that
* is below "hz".
*/
static void __mmc_set_clock(struct mmc_host *host, unsigned int hz)
{
WARN_ON(hz < host->f_min);
if (hz > host->f_max)
hz = host->f_max;
host->ios.clock = hz;
mmc_set_ios(host);
}
######把clock设置成传进的值
/*
* Internal function that does the actual ios call to the host driver,
* optionally printing some debug output.
*/
static inline void mmc_set_ios(struct mmc_host *host)
{
struct mmc_ios *ios = &host->ios;
pr_debug("%s: clock %uHz busmode %u powermode %u cs %u Vdd %u "
"width %u timing %u\n",
mmc_hostname(host), ios->clock, ios->bus_mode,
ios->power_mode, ios->chip_select, ios->vdd,
ios->bus_width, ios->timing);
if (ios->clock > 0) //此时的clock如果不是0,那么clk_gate = false,
mmc_set_ungated(host); //只有0时才能再gate?
host->ops->set_ios(host, ios); //调用平台相关函数真正设置io
}
#####另外一个函数mmc_detect_change(host, 0);
#####在core.c中,
/**
* mmc_detect_change - process change of state on a MMC socket
* @host: host which changed state.
* @delay: optional delay to wait before detection (jiffies)
*
* MMC drivers should call this when they detect a card has been
* inserted or removed. The MMC layer will confirm that any
* present card is still functional, and initialize any newly
* inserted.
*/
void mmc_detect_change(struct mmc_host *host, unsigned long delay)
{
#ifdef CONFIG_MMC_DEBUG
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
WARN_ON(host->removed);
spin_unlock_irqrestore(&host->lock, flags);
#endif
mmc_schedule_delayed_work(&host->detect, delay);
}
#####这个地方对应于上面alloc_host时候的mmc_rescan,
#####注册完毕执行一次探测,确认默认是否sd卡被插入,
#####而插入卡后中断触发也会执行到这里,下面直接看插卡后isr函数函数了,
#####在s3cmci.c中,
/*
* ISR for the CardDetect Pin
*/
static irqreturn_t s3cmci_irq_cd(int irq, void *dev_id)
{
struct s3cmci_host *host = (struct s3cmci_host *)dev_id;
dbg(host, dbg_irq, "card detect\n");
mmc_detect_change(host->mmc, msecs_to_jiffies(500));
return IRQ_HANDLED;
}
#####都走到mmc_detect_change,只不过多了个延迟,
#####继续追下去,core.c中,
/**
* mmc_detect_change - process change of state on a MMC socket
* @host: host which changed state.
* @delay: optional delay to wait before detection (jiffies)
*
* MMC drivers should call this when they detect a card has been
* inserted or removed. The MMC layer will confirm that any
* present card is still functional, and initialize any newly
* inserted.
*/
void mmc_detect_change(struct mmc_host *host, unsigned long delay)
{
#ifdef CONFIG_MMC_DEBUG
unsigned long flags;
spin_lock_irqsave(&host->lock, flags);
WARN_ON(host->removed);
spin_unlock_irqrestore(&host->lock, flags);
#endif
mmc_schedule_delayed_work(&host->detect, delay);
}
#####会调用mmc_schedule_delayed_work(&host->detect, delay);
#####host->detect这个延迟队列的初始化位于/drivers/mmc/core/host.c中,
#####INIT_DELAYED_WORK(&host->detect, mmc_rescan);
#####探测函数都会调用mmc_rescan这个系统提供的扫描sd卡函数,
#####核心扫描函数,下面就是重点的扫描卡函数了,放到下篇单独来说;
总结,概览了平台最相关的几个函数,接下来的都通用函数了,写的比较粗糙,还望见谅^.^!
-----------------------------------------------------------
####看一下重要的卡扫描函数,mmc_rescan,卡就指着他
####活着呢,
/driver/mmc/core/core.c
void mmc_rescan(struct work_struct *work)
{
static const unsigned freqs[] = { 400000, 300000, 200000, 100000 }; //扫描试验的频率段
struct mmc_host *host =
container_of(work, struct mmc_host, detect.work);
int i;
if (host->rescan_disable) //disable 直接返回
return;
mmc_bus_get(host); //增加bus引用计数
/*
* if there is a _removable_ card registered, check whether it is
* still present
*/
if (host->bus_ops && host->bus_ops->detect && !host->bus_dead
&& !(host->caps & MMC_CAP_NONREMOVABLE))
host->bus_ops->detect(host); //存在热插拔卡,不包括emmc,调用探测函数
/*
* Let mmc_bus_put() free the bus/bus_ops if we've found that
* the card is no longer present.
*/
mmc_bus_put(host); //减少引用技术,就释放
mmc_bus_get(host); //重新增加引用计数
/* if there still is a card present, stop here */
if (host->bus_ops != NULL) {
mmc_bus_put(host); //如果卡仍然存在,减少引用计数,不必探测了
goto out;
}
/*
* Only we can add a new handler, so it's safe to
* release the lock here.
*/
mmc_bus_put(host); //减少引用计数
if (host->ops->get_cd && host->ops->get_cd(host) == 0) //有卡,退出
goto out;
mmc_claim_host(host); //用于检测host是否被占用,占用则退出,否则标记成占用
for (i = 0; i < ARRAY_SIZE(freqs); i++) {
if (!mmc_rescan_try_freq(host, max(freqs[i], host->f_min))) //利用不同的频率探测卡
break;
if (freqs[i] <= host->f_min)
break;
}
mmc_release_host(host);
out:
if (host->caps & MMC_CAP_NEEDS_POLL) //轮询标志,设置了就会轮询
mmc_schedule_delayed_work(&host->detect, HZ);
}
#####
/**
* mmc_claim_host - exclusively claim a host
* @host: mmc host to claim
*
* Claim a host for a set of operations.
*/
static inline void mmc_claim_host(struct mmc_host *host)
{
__mmc_claim_host(host, NULL);
}
#####
/**
* __mmc_claim_host - exclusively claim a host
* @host: mmc host to claim
* @abort: whether or not the operation should be aborted
*
* Claim a host for a set of operations. If @abort is non null and
* dereference a non-zero value then this will return prematurely with
* that non-zero value without acquiring the lock. Returns zero
* with the lock held otherwise.
*/
int __mmc_claim_host(struct mmc_host *host, atomic_t *abort)
{
DECLARE_WAITQUEUE(wait, current); //定义一个等待队列
unsigned long flags;
int stop;
might_sleep(); //调度点
add_wait_queue(&host->wq, &wait);
spin_lock_irqsave(&host->lock, flags);
while (1) {
set_current_state(TASK_UNINTERRUPTIBLE);
stop = abort ? atomic_read(abort) : 0;
if (stop || !host->claimed || host->claimer == current)
break;
spin_unlock_irqrestore(&host->lock, flags);
schedule();
spin_lock_irqsave(&host->lock, flags);
} //只有claim为空的时候还会跳出循环,否则就一直等待释放
set_current_state(TASK_RUNNING);
if (!stop) {
host->claimed = 1;
host->claimer = current;
host->claim_cnt += 1;
} else
wake_up(&host->wq);
spin_unlock_irqrestore(&host->lock, flags);
remove_wait_queue(&host->wq, &wait);
if (!stop)
mmc_host_enable(host); //使能该host
return stop;
}
#####
mmc_host_enable函数可以做一些底电流工作
#####
/**
* mmc_host_enable - enable a host.
* @host: mmc host to enable
*
* Hosts that support power saving can use the 'enable' and 'disable'
* methods to exit and enter power saving states. For more information
* see comments for struct mmc_host_ops.
*/
int mmc_host_enable(struct mmc_host *host)
{
if (!(host->caps & MMC_CAP_DISABLE))
return 0;
if (host->en_dis_recurs)
return 0;
if (host->nesting_cnt++)
return 0;
cancel_delayed_work_sync(&host->disable);
if (host->enabled)
return 0;
if (host->ops->enable) {
int err;
host->en_dis_recurs = 1;
err = host->ops->enable(host);
host->en_dis_recurs = 0;
if (err) {
pr_debug("%s: enable error %d\n",
mmc_hostname(host), err);
return err;
}
}
host->enabled = 1;
return 0;
}
#####
重点的卡探测函数,
#####
static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
{
host->f_init = freq;
#ifdef CONFIG_MMC_DEBUG
pr_info("%s: %s: trying to init card at %u Hz\n",
mmc_hostname(host), __func__, host->f_init);
#endif
mmc_power_up(host); //电源启用
/*
* Some eMMCs (with VCCQ always on) may not be reset after power up, so
* do a hardware reset if possible.
*/
mmc_hw_reset_for_init(host); //针对emmc的硬件reset
/*
* sdio_reset sends CMD52 to reset card. Since we do not know
* if the card is being re-initialized, just send it. CMD52
* should be ignored by SD/eMMC cards.
*/
sdio_reset(host);
mmc_go_idle(host); //这部分与sd协议相关,可以结合前面内容来看
mmc_send_if_cond(host, host->ocr_avail);
/* Order's important: probe SDIO, then SD, then MMC */
if (!mmc_attach_sdio(host)) //各种卡类型探测初始化
return 0;
if (!mmc_attach_sd(host))
return 0;
if (!mmc_attach_mmc(host))
return 0;
mmc_power_off(host); //关电
return -EIO;
}
####在卡类型探测初始化过程中,重要的一个环节是和块设备的关联,这部分代码大致相同,
####例如mmc_attach_sd中,会有,
/drivers/mmc/core/sd.c
/*
* Starting point for SD card init.
*/
int mmc_attach_sd(struct mmc_host *host)
{
int err;
u32 ocr;
BUG_ON(!host);
WARN_ON(!host->claimed);
/* Make sure we are at 3.3V signalling voltage */
err = mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330, false);
if (err)
return err;
/* Disable preset value enable if already set since last time */
if (host->ops->enable_preset_value)
host->ops->enable_preset_value(host, false);
err = mmc_send_app_op_cond(host, 0, &ocr);
if (err)
return err;
mmc_sd_attach_bus_ops(host); //重要,bus操作的绑定
if (host->ocr_avail_sd)
host->ocr_avail = host->ocr_avail_sd;
/*
* We need to get OCR a different way for SPI.
*/
if (mmc_host_is_spi(host)) {
mmc_go_idle(host);
err = mmc_spi_read_ocr(host, 0, &ocr);
if (err)
goto err;
}
/*
* Sanity check the voltages that the card claims to
* support.
*/
if (ocr & 0x7F) {
pr_warning("%s: card claims to support voltages "
"below the defined range. These will be ignored.\n",
mmc_hostname(host));
ocr &= ~0x7F;
}
if ((ocr & MMC_VDD_165_195) &&
!(host->ocr_avail_sd & MMC_VDD_165_195)) {
pr_warning("%s: SD card claims to support the "
"incompletely defined 'low voltage range'. This "
"will be ignored.\n", mmc_hostname(host));
ocr &= ~MMC_VDD_165_195;
}
host->ocr = mmc_select_voltage(host, ocr);
/*
* Can we support the voltage(s) of the card(s)?
*/
if (!host->ocr) {
err = -EINVAL;
goto err;
}
/*
* Detect and init the card.
*/
err = mmc_sd_init_card(host, host->ocr, NULL);
if (err)
goto err;
mmc_release_host(host);
err = mmc_add_card(host->card); //将卡加入
mmc_claim_host(host);
if (err)
goto remove_card;
return 0;
remove_card:
mmc_release_host(host);
mmc_remove_card(host->card);
host->card = NULL;
mmc_claim_host(host);
err:
mmc_detach_bus(host);
pr_err("%s: error %d whilst initialising SD card\n",
mmc_hostname(host), err);
return err;
}
#######首先是绑定操作mmc_sd_attach_bus_ops
static void mmc_sd_attach_bus_ops(struct mmc_host *host)
{
const struct mmc_bus_ops *bus_ops;
if (!mmc_card_is_removable(host)) //emmc和sd区别对待
bus_ops = &mmc_sd_ops_unsafe;
else
bus_ops = &mmc_sd_ops;
mmc_attach_bus(host, bus_ops);
}
####mmc_attach_bus函数会将bus的操作绑定到host上.
####core.c中
/*
* Assign a mmc bus handler to a host. Only one bus handler may control a
* host at any given time.
*/
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops)
{
unsigned long flags;
BUG_ON(!host);
BUG_ON(!ops);
WARN_ON(!host->claimed);
spin_lock_irqsave(&host->lock, flags);
BUG_ON(host->bus_ops);
BUG_ON(host->bus_refs);
host->bus_ops = ops; //指向对应的操作结构
host->bus_refs = 1;
host->bus_dead = 0;
spin_unlock_irqrestore(&host->lock, flags);
}
#####再看另外一个函数mmc_add_card,
####这个函数在bus.c 中,
/*
* Register a new MMC card with the driver model.
*/
int mmc_add_card(struct mmc_card *card)
{
int ret;
const char *type;
dev_set_name(&card->dev, "%s:%04x", mmc_hostname(card->host), card->rca);
switch (card->type) {
case MMC_TYPE_MMC:
type = "MMC";
break;
case MMC_TYPE_SD:
type = "SD";
if (mmc_card_blockaddr(card)) {
if (mmc_card_ext_capacity(card))
type = "SDXC";
else
type = "SDHC";
}
break;
case MMC_TYPE_SDIO:
type = "SDIO";
break;
case MMC_TYPE_SD_COMBO:
type = "SD-combo";
if (mmc_card_blockaddr(card))
type = "SDHC-combo";
break;
default:
type = "?";
break;
}
if (mmc_host_is_spi(card->host)) {
pr_info("%s: new %s%s%s card on SPI\n",
mmc_hostname(card->host),
mmc_card_highspeed(card) ? "high speed " : "",
mmc_card_ddr_mode(card) ? "DDR " : "",
type);
} else {
printk(KERN_INFO "%s: new %s%s%s card at address %04x\n",
mmc_hostname(card->host),
mmc_sd_card_uhs(card) ? "ultra high speed " :
(mmc_card_highspeed(card) ? "high speed " : ""),
mmc_card_ddr_mode(card) ? "DDR " : "",
type, card->rca);
}
#ifdef CONFIG_DEBUG_FS
mmc_add_card_debugfs(card);
#endif
ret = device_add(&card->dev);
if (ret)
return ret;
mmc_card_set_present(card);
return 0;
}
####关注一下device_add(&card->dev);会把卡作为一个设备注册,
####这个注册会触发到bus里的match操作,这部分不理解的可以回顾前面讲到的设备模型,
####这里的bus对应mmc,调用的match函数对应于bus.c中
static struct bus_type mmc_bus_type = {
.name = "mmc",
.dev_attrs = mmc_dev_attrs,
.match = mmc_bus_match,
.uevent = mmc_bus_uevent,
.probe = mmc_bus_probe,
.remove = mmc_bus_remove,
.suspend = mmc_bus_suspend,
.resume = mmc_bus_resume,
.pm = MMC_PM_OPS_PTR,
};
/*
* This currently matches any MMC driver to any MMC card - drivers
* themselves make the decision whether to drive this card in their
* probe method.
*/
static int mmc_bus_match(struct device *dev, struct device_driver *drv)
{
return 1;
}
####总为真,那么直接会触发bus的probe操作,
####
static int mmc_bus_probe(struct device *dev)
{
struct mmc_driver *drv = to_mmc_driver(dev->driver);
struct mmc_card *card = mmc_dev_to_card(dev);
return drv->probe(card);
}
####会调用mmc_driver 里的probe,
####这里的mmc_driver就指的是block.c中的mmc_driver,
####还是看一下,这个过程吧,
####drivers/mmc/card/block.c
static int __init mmc_blk_init(void)
{
int res;
if (perdev_minors != CONFIG_MMC_BLOCK_MINORS)
pr_info("mmcblk: using %d minors per device\n", perdev_minors);
max_devices = 256 / perdev_minors;
res = register_blkdev(MMC_BLOCK_MAJOR, "mmc"); //注册mmc块设备,这个后面来讲
if (res)
goto out;
res = mmc_register_driver(&mmc_driver); //重点是这个
if (res)
goto out2;
return 0;
out2:
unregister_blkdev(MMC_BLOCK_MAJOR, "mmc");
out:
return res;
}
#####
static struct mmc_driver mmc_driver = {
.drv = {
.name = "mmcblk",
},
.probe = mmc_blk_probe,
.remove = mmc_blk_remove,
.suspend = mmc_blk_suspend,
.resume = mmc_blk_resume,
};
####在bus.c中
/**
* mmc_register_driver - register a media driver
* @drv: MMC media driver
*/
int mmc_register_driver(struct mmc_driver *drv)
{
drv->drv.bus = &mmc_bus_type;
return driver_register(&drv->drv);
}
####bus类型被指定成了mmc,也就是挂到了mmc上,这样刚才的卡注册默认全部匹配,
####所以也就会直接触发block里的probe,mmc_blk_probe
####下面的东西块设备关联比较多,放到下一章来讲
总结:描述了卡的识别阶段,并没有深入到卡的具体探测,这部分结合前面的协议转换图就不难理解,这部分主要集中在sd到块设备部分的过度
下一篇主要是针对mmc中的块设备。
Thanks
浙公网安备 33010602011771号