linux2.6.20 sd/mmc卡驱动学习日记3(基于s3c2440)
2011-05-18 11:57
239 查看
至此,我们已经跟踪了mmc/sd卡驱动的注册。。我们接着来看插入拔除卡的中断处理函数:
可
见,这里也会调用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))
来看
此
函数在mmc_sysfs.c中定义。
device_add(&card->dev)将到相应总线mmc_bus_type上去搜索相应驱动。找到驱动后就设置
dev->driver=drv,并调用mmc_bus_type总线的probe函数被调用,即mmmc_bus_probe函数
mmc_bus_probe会调用mmc_blk_probe
mmc_blk_probe()首先分配一个新的mmc_blk_data结构变量,然后调用mmc_init_queue,初始化blk队列。然后建立一个线程mmc_queue_thread()。
struct mmc_blk_data封装了struct gendisk 与 struct mmc_queue,而struct mmc_queue封装了struct mmc_card与struct request。
至此,驱动向系统添加了一个块设备。
请求处理过程:
mmc_request--->mmc_queue_thread----->mmc_blk_issue_rq---->mmc_wait_for_req--->mmc_start_request---->s3cmci_requ
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_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; } |
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)
- linux2.6.20 sd/mmc卡驱动学习日记2(基于s3c2440)
- linux2.6.20 sd/mmc卡驱动学习日记4(基于s3c2440)
- linux2.6.20 sd/mmc卡驱动学习日记4(基于s3c2440)
- linux2.6.20 sd/mmc卡驱动学习日记4(基于s3c2440)
- linux2.6.20 sd/mmc卡驱动学习日记1(基于s3c2440)
- linux2.6.20 sd/mmc卡驱动学习日记4(基于s3c2440)
- linux2.6.20 sd/mmc卡驱动学习日记1(基于s3c2440)
- linux2.6.20 sd/mmc卡驱动学习日记2(基于s3c2440)
- linux2.6.20 sd/mmc卡驱动学习日记4(基于s3c2440)
- linux2.6.20 sd/mmc卡驱动学习日记
- linux2.6.20 sd/mmc卡驱动学习日记
- linux2.6.20 S3C2440的sd/mmc卡驱动
- 基于S3C2440的嵌入式Linux驱动——MMC/SD子系统解读(二)
- 基于S3C2440的嵌入式Linux驱动——SPI子系统解读(一)
- 基于S3C2440的嵌入式Linux驱动——DS18B20温度传感器(添加使用platform总线机制)
- 【引用】基于s3c2440和linux的gpio测试代码
- Linux下基于tty架构的串口驱动分析(S3C2440)
- 基于S3C2440的linux-3.6.6移植——内核移植,建立自己的平台系统
- 基于S3C2440的嵌入式Linux驱动——MMC/SD子系统解读(二)