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

至此,我们已经跟踪了mmc/sd卡驱动的注册。。我们接着来看插入拔除卡的中断处理函数:

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, 500) ;

    return IRQ_HANDLED;
}

可 见,这里也会调用mmc_detect_change。。。我们跟着前面的分析来到mmc_setup这里,此时mmc_setup调用 mmc_discover_cards。Create a mmc_card entry for each discovered card,add new card to list.同时还会调用mmc_read_switch_caps或者mmc_process_ext_csds来实现对大容量卡的支持(>4G)
跟着程序的流程我们来到
if (!mmc_card_present(card) && !mmc_card_dead(card)) {
            if (mmc_register_card(card))
来看

int mmc_register_card( struct mmc_card * card)
{
    int ret;

    snprintf( card- > dev. bus_id, sizeof ( card- > dev. bus_id) ,
         "%s:%04x" , mmc_hostname( card- > host) , card- > rca) ;

    ret = device_add( & card- > dev) ;
    if ( ret = = 0) {
        if ( mmc_card_sd( card) ) {
            ret = device_create_file( & card- > dev, & mmc_dev_attr_scr) ;
            if ( ret)
                device_del( & card- > dev) ;
}
}
    return ret;
}

此 函数在mmc_sysfs.c中定义。 device_add(&card->dev)将到相应总线mmc_bus_type上去搜索相应驱动。找到驱动后就设置 dev->driver=drv,并调用mmc_bus_type总线的probe函数被调用,即mmmc_bus_probe函数


static int mmc_bus_probe( struct device * dev)
{
    struct mmc_driver * drv = to_mmc_driver( dev- > driver) ;
    struct mmc_card * card = dev_to_mmc_card( dev) ;

    return drv- > probe( card) ;
}

mmc_bus_probe会调用mmc_blk_probe
mmc_blk_probe()首先分配一个新的mmc_blk_data结构变量,然后调用mmc_init_queue,初始化blk队列。然后建立一个线程mmc_queue_thread()。

static int mmc_blk_probe( struct mmc_card * card)
{
    struct mmc_blk_data * md;
    int err;

    /*
     * Check that the card supports the command class(es) we need.
    */

    if ( ! ( card- > csd. cmdclass & CCC_BLOCK_READ) )
        return - ENODEV;

    md = mmc_blk_alloc( card) ; //

    if ( IS_ERR( md) )
        return PTR_ERR( md) ;

    err = mmc_blk_set_blksize( md, card) ;
    if ( err)
        goto out;

    printk( KERN_INFO "%s: %s %s %lluKiB %s/n" ,
        md- > disk- > disk_name, mmc_card_id( card) , mmc_card_name( card) ,
        ( unsigned long long ) ( get_capacity( md- > disk) > > 1) ,
        md- > read_only ? "(ro)" : "" ) ;

    mmc_set_drvdata( card, md) ;
    add_disk( md- > disk) ;
    return 0;

 out:
    mmc_blk_put( md) ;

    return err;
}

struct mmc_blk_data封装了struct gendisk  与 struct mmc_queue,而struct mmc_queue封装了struct mmc_card与struct request。


static struct mmc_blk_data * mmc_blk_alloc( struct mmc_card * card)
{
    struct mmc_blk_data * md;
    int devidx, ret;

    devidx = find_first_zero_bit( dev_use, MMC_NUM_MINORS) ;
    if ( devidx > = MMC_NUM_MINORS)
        return ERR_PTR( - ENOSPC) ;
    __set_bit( devidx, dev_use) ;

    md = kmalloc( sizeof ( struct mmc_blk_data) , GFP_KERNEL) ;
    if ( ! md) {
        ret = - ENOMEM;
        goto out;
}

    memset ( md, 0, sizeof ( struct mmc_blk_data) ) ;

    /*
     * Set the read-only status based on the supported commands
     * and the write protect switch.
    */

    md- > read_only = mmc_blk_readonly( card) ; //写保护


    /*
     * Both SD and MMC specifications state (although a bit
     * unclearly in the MMC case) that a block size of 512
     * bytes must always be supported by the card.
    */

    md- > block_bits = 9; //块大小


    md- > disk = alloc_disk( 1 < < MMC_SHIFT) ;
        //分配struct gendist,驱动程序不能自己动态分配该结构,而是必须调用

        //alloc_disk,其参数为次设备号数目,注意了,是次设备号数目,不是次设备号

    if ( md- > disk = = NULL ) {
        ret = - ENOMEM;
        goto err_kfree;
}

    spin_lock_init( & md- > lock) ;
    md- > usage = 1;

    ret = mmc_init_queue( & md- > queue , card, & md- > lock) ; //

    if ( ret)
        goto err_putdisk;

    md- > queue . prep_fn = mmc_blk_prep_rq;
    md- > queue . issue_fn = mmc_blk_issue_rq;
    md- > queue . data = md;
        //上面设置了请求队列,现在就可以初始化及安装相应的gendisk结构了

    md- > disk- > major    = major;
    md- > disk- > first_minor = devidx < < MMC_SHIFT;
    md- > disk- > fops = & mmc_bdops;
    md- > disk- > private_data = md;
    md- > disk- > queue = md- > queue . queue ;
    md- > disk- > driverfs_dev = & card- > dev;

    /*
     * As discussed on lkml, GENHD_FL_REMOVABLE should:
     *
     * - be set for removable media with permanent block devices
     * - be unset for removable block devices with permanent media
     *
     * Since MMC block devices clearly fall under the second
     * case, we do not set GENHD_FL_REMOVABLE. Userspace
     * should use the block device creation/destruction hotplug
     * messages to tell when the card is present.
    */


    sprintf ( md- > disk- > disk_name, "mmcblk%d" , devidx) ;

    blk_queue_hardsect_size( md- > queue . queue , 1 < < md- > block_bits) ;

    /*
     * The CSD capacity field is in units of read_blkbits.
     * set_capacity takes units of 512 bytes.
    */

    set_capacity( md- > disk, card- > csd. capacity < < ( card- > csd. read_blkbits - 9) ) ;
    return md;

 err_putdisk:
    put_disk( md- > disk) ;
 err_kfree:
    kfree( md) ;
 out:
    return ERR_PTR( ret) ;
}

至此,驱动向系统添加了一个块设备。
请求处理过程:
mmc_request--->mmc_queue_thread----->mmc_blk_issue_rq---->mmc_wait_for_req--->mmc_start_request---->s3cmci_requ

你可能感兴趣的:(linux2.6.20 sd/mmc卡驱动学习日记3(基于s3c2440))