📄 mmc_core.c
字号:
}err_mmc: ret = __mmc_check_error( card, ret ); /* FIXME */ if ( ret >= 0 ) { ret = size - transfer.cnt; *paddr += ret; }err_down: mmc_release_io( ctrlr, card );error: __LEAVE( "ret=%d", ret ); return ret;}EXPORT_SYMBOL( mmc_write );int mmc_ioctl( mmc_card_t card, unsigned int cmd, unsigned long arg ){ int ret = -EINVAL; mmc_controller_t ctrlr; if ( !card ) { MMC_DEBUG( MMC_DEBUG_LEVEL0, "bad card reference\n" ) goto error; } ctrlr = card->ctrlr; if ( mmc_acquire_io( ctrlr, card ) ) { ret = -ENXIO; goto error; } switch ( cmd ) { case IOCMMCGCARDESC: if ( copy_to_user( (void *)arg, &card->info, sizeof( mmc_card_info_rec_t ) ) ) ret = -EFAULT; break;/* * 1. TODO: erase region * 2. TODO: set/unset write protection, lock/password */ default: ret = -ENOIOCTLCMD; } mmc_release_io( ctrlr, card );error: return ret;}EXPORT_SYMBOL( mmc_ioctl );/* * registry stuff */mmc_card_t mmc_get_card( int host, int slot ){ mmc_card_t ret = NULL; mmc_controller_t ctrlr = NULL; int found; __ENTER( "host=%d, card=%d", host, slot ); if ( ((host < 0) || (host >= MMC_CONTROLLERS_MAX)) && ((slot < 0) || (slot >= MMC_CARDS_MAX)) ) goto error; down_read( &mmc_controller_sem ); if ( (ctrlr = mmc_controller[host]) ) { down_write( &ctrlr->update_sem ); if ( ctrlr->stack.ncards > 0 ) { ret = ctrlr->stack.first; found = FALSE; while ( ret ) { if ( (ret->slot == slot) && (ret->state != MMC_CARD_STATE_UNPLUGGED) ) { found = TRUE; break; } ret = ret->next; } if ( found ) { if ( ctrlr->tmpl->owner ) { ++ctrlr->usage; MMC_DEBUG( MMC_DEBUG_LEVEL2, "'%s' use count increased (%d)\n", ctrlr->tmpl->name, ctrlr->usage ); __MOD_INC_USE_COUNT( ctrlr->tmpl->owner ); } ++ret->usage; } else ret = NULL; } up_write( &ctrlr->update_sem ); } up_read( &mmc_controller_sem );error: __LEAVE("ret=0x%p usage=%d", ret, ret ? ret->usage : -1 ); return ret;}EXPORT_SYMBOL( mmc_get_card );void mmc_put_card( mmc_card_t card ){ mmc_card_t tmp = NULL; mmc_controller_t ctrlr; int found; __ENTER( "card=0x%p", card ); if ( !card ) goto error; ctrlr = card->ctrlr; down_read( &mmc_controller_sem ); if ( !ctrlr || (ctrlr != mmc_controller[ctrlr->slot]) ) { MMC_ERROR( "bad controller reference: ctrlr=0x%p\n", ctrlr ); goto err_down; } down_write( &ctrlr->update_sem ); if ( ctrlr->stack.ncards > 0 ) { tmp = ctrlr->stack.first; found = FALSE; while ( tmp ) { if ( tmp == card ) { found = TRUE; break; } tmp = tmp->next; } if ( found ) { if ( tmp->usage > 0 ) { --tmp->usage; MMC_DEBUG( MMC_DEBUG_LEVEL2, "usage=%d" "owner=0x%p\n", tmp->usage, ctrlr->tmpl->owner ); if ( !tmp->usage && (ctrlr->usage > 0) && ctrlr->tmpl->owner ) { --ctrlr->usage; MMC_DEBUG( MMC_DEBUG_LEVEL2, "'%s' use count " "decreased (%d)\n", ctrlr->tmpl->name, ctrlr->usage ); __MOD_DEC_USE_COUNT( ctrlr->tmpl->owner ); } } } else MMC_DEBUG( MMC_DEBUG_LEVEL0, "bad card reference\n" ); } up_write( &ctrlr->update_sem ); err_down: up_read( &mmc_controller_sem );error: __LEAVE( "found=%d", found ); return;}EXPORT_SYMBOL( mmc_put_card );static inline void *mmc_register_user( mmc_notifier_t notifier ){ mmc_notifier_t ret = NULL, last = mmc_notifier; MOD_INC_USE_COUNT; if ( notifier ) { down_write( &mmc_notifier_sem ); notifier->next = NULL; if ( !last ) { mmc_notifier = notifier; ret = notifier; } else { while ( last->next ) { if ( last == notifier ) { MOD_DEC_USE_COUNT; break; } last = last->next; } if ( last != notifier ) { last->next = notifier; ret = notifier; } } up_write( &mmc_notifier_sem ); }/* notify new user about the cards present in the system */ if ( ret && ret->add ) { int i; down_read( &mmc_controller_sem ); for ( i = 0; i < mmc_ncontrollers; i++ ) { mmc_controller_t ctrlr = mmc_controller[i]; down_read( &ctrlr->update_sem ); /* FIXME */ __mmc_card_stack_foreach( &ctrlr->stack, ret->add, FALSE ); up_read( &ctrlr->update_sem ); /* FIXME */ } up_read( &mmc_controller_sem ); }/* error: */ __LEAVE( "mmc_notifier=0x%p, mmc_notifier->next=0x%p", mmc_notifier, mmc_notifier ? mmc_notifier->next : NULL ); return ret;}static inline mmc_controller_t mmc_register_controller( mmc_controller_tmpl_t tmpl, size_t extra ){ mmc_controller_t ret = NULL; int found; int i; MOD_INC_USE_COUNT; down_write( &mmc_controller_sem ); if ( mmc_ncontrollers >= MMC_CONTROLLERS_MAX ) { MMC_DEBUG( MMC_DEBUG_LEVEL0, "there're too many controllers\n" ); goto error; } found = FALSE; for ( i = 0; i < MMC_CONTROLLERS_MAX; i++ ) if ( !mmc_controller[i] ) { found = TRUE; break; } if ( !found ) { MMC_DEBUG( MMC_DEBUG_LEVEL0, "there're no empty slots\n" ); goto error; } if ( !tmpl->init ) { MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'init()'\n" ); goto error; } if ( !tmpl->probe ) { MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'probe()'\n" ); goto error; } if ( !tmpl->init_card_stack ) { MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'init_card_stack()'\n" ); goto error; } if ( !tmpl->update_acq ) { MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'update_acq()'\n" ); goto error; } if ( !tmpl->check_card_stack ) { MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'check_card_stack()'\n" ); goto error; } if ( !tmpl->setup_card ) { MMC_DEBUG( MMC_DEBUG_LEVEL0, "host template lacks 'setup_card()'\n" ); goto error; } ret = kmalloc( sizeof( mmc_controller_rec_t ) + extra, GFP_ATOMIC ); /* FIXME: ISA + GFP_DMA */ if ( !ret ) { MMC_DEBUG( MMC_DEBUG_LEVEL0, "out of memory\n" ); goto error; } memset( ret, 0, sizeof( mmc_controller_rec_t ) + extra ); if ( (tmpl->probe( ret ) != 1) ) { MMC_DEBUG( MMC_DEBUG_LEVEL0, "controller probe failed\n" ); goto err_free; } if ( tmpl->init( ret ) ) { MMC_DEBUG( MMC_DEBUG_LEVEL0, "controller initialization failure\n" ); goto err_free; } ret->state = MMC_CONTROLLER_FOUND; ret->slot = i; ret->tmpl = tmpl; init_MUTEX( &ret->io_sem ); init_rwsem( &ret->update_sem );#ifdef CONFIG_PROC_FS if ( mmc_proc_dir ) { snprintf( ret->proc_name, sizeof( ret->proc_name ), "host%d", ret->slot ); ret->proc = proc_mkdir( ret->proc_name, mmc_proc_dir ); }#endif /* initialize card stack */ if ( ret->tmpl->init_card_stack( ret ) ) { MMC_DEBUG( MMC_DEBUG_LEVEL0, "card stack initialization failure\n" ); if ( ret->tmpl->remove ) ret->tmpl->remove( ret ); /* FIXME */ goto err_free; } mmc_controller[ret->slot] = ret; ++mmc_ncontrollers;/* notify users */ if ( ret->stack.ncards > 0 ) { down_read( &mmc_notifier_sem ); if ( (i = __mmc_card_stack_foreach( &ret->stack, mmc_notify_add, FALSE ) ) < 0 ) MMC_ERROR( "device add notification failed at slot %d\n", -i ); up_read( &mmc_notifier_sem ); } goto out; err_free:#ifdef CONFIG_PROC_FS if ( ret->proc ) remove_proc_entry( ret->proc_name, mmc_proc_dir );#endif kfree( ret );error: ret = NULL; MOD_DEC_USE_COUNT;out: up_write( &mmc_controller_sem ); return ret;}static inline mmc_card_t mmc_register_card( mmc_card_t card ){ mmc_card_t ret = NULL; mmc_controller_t ctrlr; if ( !card || !card->ctrlr ) goto error; ctrlr = card->ctrlr;#ifdef CONFIG_PROC_FS if ( ctrlr->proc ) { snprintf( card->proc_name, sizeof( card->proc_name ), "card%d", card->slot ); card->proc = create_proc_read_entry( card->proc_name, 0444, ctrlr->proc, mmc_proc_read_card_info, card ); }#endif mmc_notify_add( card );error: return ret;}void *mmc_register( mmc_reg_type_t reg_type, void *tmpl, size_t extra ){ void *ret = NULL; switch ( reg_type ) { case MMC_REG_TYPE_CARD: ret = mmc_register_card( (mmc_card_t)tmpl ); break; case MMC_REG_TYPE_USER: ret = mmc_register_user( (mmc_notifier_t)tmpl ); break; case MMC_REG_TYPE_HOST: ret = mmc_register_controller( (mmc_controller_tmpl_t)tmpl, extra ); break; default: MMC_DEBUG( MMC_DEBUG_LEVEL0, "register request for unknown type\n" ); } return ret;}EXPORT_SYMBOL( mmc_register );static inline void mmc_unregister_user( mmc_notifier_t notifier ){ mmc_notifier_t prev = mmc_notifier; int found = FALSE; if ( notifier ) { down_write( &mmc_notifier_sem ); if ( mmc_notifier == notifier) { mmc_notifier = prev->next; found = TRUE; } else if ( mmc_notifier ) { while( prev ) { if ( prev->next == notifier ) { found = TRUE; prev->next = prev->next->next; break; } prev = prev->next; } } if ( found ) { if ( notifier->remove ) { int i; down_read( &mmc_controller_sem ); for ( i = 0; i < mmc_ncontrollers; i++ ) { mmc_controller_t ctrlr = mmc_controller[i]; down_read( &ctrlr->update_sem ); __mmc_card_stack_foreach( &ctrlr->stack, notifier->remove, FALSE ); up_read( &ctrlr->update_sem ); } up_read( &mmc_controller_sem ); } } up_write( &mmc_notifier_sem ); } MOD_DEC_USE_COUNT;}static inline void mmc_unregister_controller( mmc_controller_t ctrlr ){ if ( !ctrlr || (mmc_controller[ctrlr->slot] != ctrlr ) ) { MMC_DEBUG( MMC_DEBUG_LEVEL0, "bad unregister request\n" ); goto error; } down_write( &mmc_controller_sem );/* notify users */ if ( ctrlr->stack.ncards > 0 ) { int slot; down_read( &mmc_notifier_sem ); if ( (slot = __mmc_card_stack_foreach( &ctrlr->stack, mmc_notify_remove, FALSE ) ) ) MMC_ERROR( "device remove notification failed at slot %d\n", -slot ); up_read( &mmc_notifier_sem ); }#ifdef CONFIG_PROC_FS if ( ctrlr->proc ) remove_proc_entry( ctrlr->proc_name, mmc_proc_dir );#endif if ( ctrlr->tmpl && ctrlr->tmpl->remove ) ctrlr->tmpl->remove( ctrlr ); mmc_controller[ctrlr->slot] = NULL; --mmc_ncontrollers; __mmc_free_controller( ctrlr ); up_write( &mmc_controller_sem ); MOD_DEC_USE_COUNT;error: return;}void mmc_unregister( mmc_reg_type_t reg_type, void *tmpl ){ switch ( reg_type ) { case MMC_REG_TYPE_USER: mmc_unregister_user( (mmc_notifier_t)tmpl ); break; case MMC_REG_TYPE_HOST: mmc_unregister_controller( (mmc_controller_t)tmpl ); break; default: MMC_DEBUG( MMC_DEBUG_LEVEL0, "unregister request for unknown type\n" ); }}EXPORT_SYMBOL( mmc_unregister );#ifdef CONFIG_PM/* power management support */static int mmc_pm_callback( struct pm_dev *pmdev, pm_request_t pmreq, void *pmdata ){ int ret = -EINVAL; mmc_controller_t ctrlr; int i; __ENTER( "pmreq=%d", pmreq ); down_read( &mmc_controller_sem ); switch ( pmreq ) { case PM_SUSPEND: for ( ret = 0, i = 0; !ret && (i < mmc_ncontrollers); i++ ) { ctrlr = mmc_controller[i]; if ( ctrlr->tmpl->suspend ) ret = ctrlr->tmpl->suspend( ctrlr ); } if ( !ret ) break; case PM_RESUME: for ( i = mmc_ncontrollers - 1; i >= 0; i-- ) { ctrlr = mmc_controller[i]; if ( ctrlr->tmpl->resume ) ctrlr->tmpl->resume( ctrlr ); } ret = 0; break; default: MMC_DEBUG( MMC_DEBUG_LEVEL0, "unsupported PM request %d\n", pmreq ); } up_read( &mmc_controller_sem );/* error: */ __LEAVE( "ret=%d", ret ); return ret;}#endif/* kernel module stuff */static int __init mmc_core_module_init( void ){ int ret = -ENODEV; memset( &mmc_controller, 0, sizeof( mmc_controller ) ); init_rwsem( &mmc_controller_sem ); init_rwsem( &mmc_notifier_sem );#ifdef CONFIG_PM if ( !(mmc_pm_dev = pm_register( PM_UNKNOWN_DEV, 0, mmc_pm_callback )) ) MMC_DEBUG( MMC_DEBUG_LEVEL0, "failed to register PM callback\n" );#endif#ifdef CONFIG_PROC_FS mmc_proc_dir = proc_mkdir( "mmc", NULL );#endif ret = 0;/* error: */ return ret;}static void __exit mmc_core_module_cleanup( void ){#ifdef CONFIG_PROC_FS if ( mmc_proc_dir ) remove_proc_entry( "mmc", NULL );#endif#ifdef CONFIG_PM pm_unregister( mmc_pm_dev );#endif}module_init( mmc_core_module_init );module_exit( mmc_core_module_cleanup );MODULE_LICENSE( "GPL" );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -