linux2.6.20 sd/mmc卡驱动学习日记2(基于s3c2440)

我们接着来到s3cmci.c文件
s3cmci_init----->platform_driver_register(&s3cmci_driver_2440)------------>s3cmci_probe_2440----->s3cmci_probe

在s3cmci_probe中主要是分配及初始化
    struct mmc_host     *mmc;
    struct s3cmci_host     *host;
这两个结构体。分配DMA通道,注册irq中断。
以下对个别函数的作用进行说明:
1:    clk_get

    系统初始化的时候外围总线上的设备不是都给时钟的,主要是为了省电。
    在2.6.20中,我们在文件arch/arm/mach-s3c2410/s3c2410-clock中可以看到nand,sdi,adc,i2c,iis这些是不给时钟的
    lcd,gpio,usb,uart这些是给时钟的
    clk_get在arch/arm/mach-s3c2410/clock.c中定义
   


2:     mmc_alloc_host
    mmc_alloc_host分配sizeof(struct mmc_host)+extra这么大的空间,并做以下初始化
    host = mmc_alloc_host_sysfs(extra, dev);
    host->parent = dev;
    host->class_dev.parent = dev;
    host->class_dev.class = &mmc_host_class;
    device_initialize(&host->class_dev);

    spin_lock_init(&host->lock);
    init_waitqueue_head(&host->wq);
    INIT_LIST_HEAD(&host->cards);
    INIT_DELAYED_WORK(&host->detect, mmc_rescan);

       
    * By default, hosts do not support SGIO or large requests.
    * They have to set these according to their abilities.
       
    host->max_hw_segs = 1;
    host->max_phys_segs = 1;
    host->max_sectors = 1 << (PAGE_CACHE_SHIFT - 9);
    host->max_seg_size = PAGE_CACHE_SIZE;

3:
    mmc_add_host
    调用mmc_add_host的最终结果是device_add(&host->class->dev)(所以在/sys/class/mmc/目录下出现mmc0文件)。
    并会调用mmc_power_off(host);mmc_detect_change(host, 0);
    mmc_power_off函数比较简单,顾名思义,它是让SD/MMC卡停止工作的,相应的,此函数就会配置相应的IO口以及时钟等。
我们来看看mmc_detect_change函数吧。
void mmc_detect_change(struct mmc_host *host, unsigned long delay)
{
    mmc_schedule_delayed_work(&host->detect, delay);
}
int mmc_schedule_delayed_work(struct delayed_work *work, unsigned long delay)
{
    return queue_delayed_work(workqueue, work, delay);
}
queue_delayed_work把host->detect提交到workqueue工作对列中。
相应定义:
INIT_DELAYED_WORK(&host->detect, mmc_rescan);
workqueue = create_singlethread_workqueue("kmmcd");
所以,当此delayed_work执行的时候,mmc_rescan将会被调用



static void mmc_rescan( struct work_struct * work)
{
    struct mmc_host * host =
        container_of( work, struct mmc_host, detect. work) ; //返回指向s3cmci_probe中分配的mmc_host结构的指针

    struct list_head * l, * n;
    unsigned char power_mode;

    mmc_claim_host( host) ;
    /*
    驱动中使用mmc_claim_host(host);来得知,当前mmc控制器是否被占用,当前mmc控制器如果被占用,那么 host->claimed = 1;否则为0,如果为1,那么会在for(;;)循环中调用schedule切换出自己,当占用mmc控制器的操作完成之后,执行 mmc_release_host()的时候,会激活登记到等待队列&host->wq中的其他程序获得mmc主控制器的物理使用权
    */

    /*
     * Check for removed cards and newly inserted ones. We check for
     * removed cards first so we can intelligently re-select the VDD.
    */

    power_mode = host- > ios . power_mode;
    if ( power_mode = = MMC_POWER_ON)
        mmc_check_cards( host) ;
    mmc_setup( host) ;
    /*
     * Some broken cards process CMD1 even in stand-by state. There is
     * no reply, but an ILLEGAL_COMMAND error is cached and returned
     * after next command. We poll for card status here to clear any
     * possibly pending error.
    */

    if ( power_mode = = MMC_POWER_ON)
        mmc_check_cards( host) ;

    if ( ! list_empty( & host- > cards) ) {
        /*
         * (Re-)calculate the fastest clock rate which the
         * attached cards and the host support.
        */

        host- > ios . clock = mmc_calculate_clock( host) ;
        mmc_set_ios( host) ;
    }

    mmc_release_host( host) ;

    list_for_each_safe( l, n, & host- > cards) {
        struct mmc_card * card = mmc_list_to_card( l) ;

        /*
         * If this is a new and good card, register it.
        */

        if ( ! mmc_card_present( card) & & ! mmc_card_dead( card) ) {
            if ( mmc_register_card( card) )
                mmc_card_set_dead( card) ;
            else
                mmc_card_set_present( card) ;
        }

        /*s
         * If this card is dead, destroy it.
        */

        if ( mmc_card_dead( card) ) {
            list_del( & card- > node) ;
            mmc_remove_card( card) ;
        }
    }

    /*
     * If we discover that there are no cards on the
     * bus, turn off the clock and power down.
    */

    if ( list_empty( & host- > cards) )
        mmc_power_off( host) ;
}

起 初,power_mode = MMC_POWER_OFF,故第一个mmc_check_cards(host)是不会执行的。但mmc_setup函数中设置了power_mode = MMC_POWER_ON。故第二个mmc_check_cards(host)是会执行的。
在mmc_setup中,会调用mmc_discover_cards.如果发现有卡,则add new card to list.
因为现在没有发现卡,host->card=NULL,故mmc_check_cards与mmc_rescan中的list_for_each_safe循环体中的内容也是不会执行的。

static void mmc_check_cards( struct mmc_host * host)
{
    struct list_head * l, * n;

    mmc_deselect_cards( host) ; // Ensure that no card is selected.


    list_for_each_safe( l, n, & host- > cards) {
        struct mmc_card * card = mmc_list_to_card( l) ;
        struct mmc_command cmd;
        int err;

        cmd. opcode = MMC_SEND_STATUS;
        cmd. arg = card- > rca < < 16;
        cmd. flags = MMC_RSP_R1 | MMC_CMD_AC;

        err = mmc_wait_for_cmd( host, & cmd, CMD_RETRIES) ;
        if ( err = = MMC_ERR_NONE)
            continue ;

        mmc_card_set_dead( card) ;
}
}

执行完s3cmci_probe后,在终端会有以下信息:
s3c2410-sdi s3c2410-sdi: powered down.
s3c2410-sdi s3c2410-sdi: initialisation done.
s3c2410-sdi s3c2410-sdi: running at 0kHz (requested: 0kHz).
s3c2410-sdi s3c2410-sdi: running at 198kHz (requested: 197kHz).
s3c2410-sdi s3c2410-sdi: running at 198kHz (requested: 197kHz).
s3c2410-sdi s3c2410-sdi: running at 198kHz (requested: 197kHz).
s3c2410-sdi s3c2410-sdi: CMD[TIMEOUT] #2 op:APP_CMD(55) arg:0x00000000 flags:0xe
s3c2410-sdi s3c2410-sdi: CMD[TIMEOUT] #3 op:APP_CMD(55) arg:0x00000000 flags:0xe
s3c2410-sdi s3c2410-sdi: CMD[TIMEOUT] #4 op:APP_CMD(55) arg:0x00000000 flags:0xe
s3c2410-sdi s3c2410-sdi: CMD[TIMEOUT] #5 op:APP_CMD(55) arg:0x00000000 flags:0xe
s3c2410-sdi s3c2410-sdi: CMD[TIMEOUT] #6 op:ALL_SEND_OCR(1) arg:0x00000000 flage
s3c2410-sdi s3c2410-sdi: powered down.

------------------------------------未完待续------------------------------------

 

http://blog.chinaunix.net/space.php?uid=14782631&do=blog&id=111889

你可能感兴趣的:(Linux/os,防骗指南)