----------------------------------------------------------

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

posted on 2013-02-18 08:40  爱哎唉  阅读(3328)  评论(0)    收藏  举报