?? mmc_core.c
字號:
if ( !(state & STATE_INSERT) ) return 0; for ( i = 0 ; i < dev->num_slots ; i++ ) { struct mmc_slot *slot = dev->slot + i; if ( slot->flags & MMC_SLOT_FLAG_INSERT ) { if (!dev->sdrive->is_empty(i)) { slot->dev = dev; slot->state = CARD_STATE_IDLE; card_count++; } slot->flags &= ~MMC_SLOT_FLAG_INSERT; } } return card_count;}/****************************************************************** * * Hotplug callback card insertion/removal * ******************************************************************/ #if !defined(CONFIG_OMAP_INNOVATOR) && !defined(CONFIG_MACH_OMAP_PERSEUS2)#ifdef CONFIG_HOTPLUGextern char hotplug_path[];extern int call_usermodehelper(char *path, char **argv, char **envp);static void run_sbin_hotplug(struct mmc_dev *dev, int id, int insert){ int i; char *argv[3], *envp[8]; char media[64], slotnum[16]; if (!hotplug_path[0]) return; DEBUG(0,": hotplug_path=%s id=%d insert=%d\n", hotplug_path, id, insert); i = 0; argv[i++] = hotplug_path; argv[i++] = "mmc"; argv[i] = 0; /* minimal command environment */ i = 0; envp[i++] = "HOME=/"; envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; /* other stuff we want to pass to /sbin/hotplug */ sprintf(slotnum, "SLOT=%d", id ); if ( dev->slot[id].media_driver && dev->slot[id].media_driver->name ) sprintf(media, "MEDIA=%s", dev->slot[id].media_driver->name ); else sprintf(media, "MEDIA=unknown"); envp[i++] = slotnum; envp[i++] = media; if (insert) envp[i++] = "ACTION=add"; else envp[i++] = "ACTION=remove"; envp[i] = 0; call_usermodehelper (argv [0], argv, envp);}static void mmc_hotplug_task_handler( void *nr ){ int insert = ((int) nr) & 0x01; int id = ((int) nr) >> 1; DEBUG(2," id=%d insert=%d\n", id, insert ); run_sbin_hotplug(&g_mmc_dev, id, insert );}static struct tq_struct mmc_hotplug_task = { routine: mmc_hotplug_task_handler};void run_sbin_mmc_hotplug(struct mmc_dev *dev, int id, int insert ){//#ifdef CONFIG_ARCH_EZX_E680 if (first_have_card) { first_have_card = 0; return; }//#endif mmc_hotplug_task.data = (void *) ((id << 1) | insert); schedule_task( &mmc_hotplug_task );}#elsevoid run_sbin_mmc_hotplug(struct mmc_dev *sdev, int id, int insert) { }#endif /* CONFIG_HOTPLUG */#elsevoid run_sbin_mmc_hotplug(struct mmc_dev *sdev, int id, int insert) { }#endif/****************************************************************** * Common processing tasklet * Everything gets serialized through this ******************************************************************/static void mmc_tasklet_action(unsigned long data){ struct mmc_dev *dev = (struct mmc_dev *)data; unsigned long flags; int state; DEBUG(2,": dev=%p flags=%02x\n", dev, dev->state); /* Grab the current working state */ local_irq_save(flags); state = dev->state; if ( state & STATE_CMD_DONE ) dev->state = state & ~(STATE_CMD_DONE | STATE_CMD_ACTIVE); local_irq_restore(flags); /* If there is an active command, don't do anything */ if ( (state & STATE_CMD_ACTIVE) && !(state & STATE_CMD_DONE) ) return; if ( dev->protocol ) dev->protocol(dev,state);}/****************************************************************** * Callbacks from low-level driver * These run at interrupt time ******************************************************************/void mmc_cmd_complete(struct mmc_request *request){ DEBUG(2,": request=%p retval=%d\n", request, request->result); g_mmc_dev.state |= STATE_CMD_DONE; if ( !g_mmc_dev.suspended ) tasklet_schedule(&g_mmc_dev.task);}void mmc_insert(int slot){ DEBUG(2,": %d\n", slot); g_mmc_dev.state |= STATE_INSERT; g_mmc_dev.slot[slot].flags |= MMC_SLOT_FLAG_INSERT; if ( !g_mmc_dev.suspended ) tasklet_schedule(&g_mmc_dev.task); mmc_slot_enable = 1;}void mmc_eject(int slot){ DEBUG(2,": %d\n", slot); g_mmc_dev.state |= STATE_EJECT; g_mmc_dev.slot[slot].flags |= MMC_SLOT_FLAG_EJECT; if ( !g_mmc_dev.suspended ) tasklet_schedule(&g_mmc_dev.task); mmc_slot_enable = 0;}EXPORT_SYMBOL(mmc_cmd_complete);EXPORT_SYMBOL(mmc_insert);EXPORT_SYMBOL(mmc_eject);/****************************************************************** * Called from the media handler ******************************************************************/int mmc_handle_io_request( struct mmc_io_request *t ){ DEBUG(2," id=%d cmd=%d sector=%ld nr_sectors=%ld block_len=%ld buf=%p\n", t->id, t->cmd, t->sector, t->nr_sectors, t->block_len, t->buffer); if ( g_mmc_dev.io_request ) { /* FIXME : Urgly solution here */ if (g_mmc_dev.next_io_request || (g_mmc_dev.io_request->cmd == t->cmd)) { DEBUG(0,": error! io_request in progress\n"); return 0; } else { g_mmc_dev.next_io_request = t; return 1; } } g_mmc_dev.io_request = t; tasklet_schedule(&g_mmc_dev.task); return 1;}EXPORT_SYMBOL(mmc_handle_io_request);/****************************************************************** * Media handlers * Allow different drivers to register a media handler ******************************************************************/static LIST_HEAD(mmc_media_drivers);int mmc_match_media_driver( struct mmc_slot *slot ){ struct list_head *item; DEBUG(2,": slot=%p\n", slot); for ( item = mmc_media_drivers.next ; item != &mmc_media_drivers ; item = item->next ) { struct mmc_media_driver *drv = list_entry(item, struct mmc_media_driver, node ); if ( drv->probe(slot) ) { slot->media_driver = drv; drv->load(slot); return 1; } } return 0;}int mmc_register_media_driver( struct mmc_media_driver *drv ){ list_add_tail( &drv->node, &mmc_media_drivers ); return 0;}void mmc_unregister_media_driver( struct mmc_media_driver *drv ){ list_del(&drv->node);}EXPORT_SYMBOL(mmc_register_media_driver);EXPORT_SYMBOL(mmc_unregister_media_driver);/******************************************************************/int mmc_register_slot_driver( struct mmc_slot_driver *sdrive, int num_slots ){ int i; int retval; DEBUG(2," max=%d ocr=0x%08x\n", num_slots, sdrive->ocr); if ( num_slots > MMC_MAX_SLOTS ) { printk(KERN_CRIT "%s: illegal num of slots %d\n", __FUNCTION__, num_slots); return -ENOMEM; } if ( g_mmc_dev.sdrive ) { printk(KERN_ALERT "%s:: slot in use\n", __FUNCTION__); return -EBUSY; } g_mmc_dev.sdrive = sdrive; g_mmc_dev.num_slots = num_slots; for ( i = 0 ; i < num_slots ; i++ ) { struct mmc_slot *slot = &g_mmc_dev.slot[i]; memset(slot,0,sizeof(struct mmc_slot)); slot->id = i; slot->state = CARD_STATE_EMPTY; } retval = sdrive->init(); if ( retval ) return retval;#ifndef CONFIG_ARCH_EZX_HAINAN /* Generate insert events for cards */ for ( i = 0 ; i < num_slots ; i++ ) if ( !sdrive->is_empty(i) ) mmc_insert(i);#endif return 0;}void mmc_unregister_slot_driver( struct mmc_slot_driver *sdrive ){ int i; DEBUG(2,"\n"); for ( i = 0 ; i < g_mmc_dev.num_slots ; i++ ) mmc_eject(i); if ( sdrive == g_mmc_dev.sdrive ) { g_mmc_dev.sdrive->cleanup(); g_mmc_dev.sdrive = NULL; }}EXPORT_SYMBOL(mmc_register_slot_driver);EXPORT_SYMBOL(mmc_unregister_slot_driver);/******************************************************************/static struct pm_dev *mmc_pm_dev;static int mmc_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data){#ifndef CONFIG_ARCH_EZX int i; DEBUG(0,": pm callback %d\n", req ); switch (req) { case PM_SUSPEND: /* Enter D1-D3 */ g_mmc_dev.suspended = 1; break; case PM_RESUME: /* Enter D0 */ if ( g_mmc_dev.suspended ) { g_mmc_dev.suspended = 0; g_mmc_dev.state = 0; // Clear the old state for ( i = 0 ; i < g_mmc_dev.num_slots ; i++ ) { mmc_eject(i); if ( !g_mmc_dev.sdrive->is_empty(i) ) mmc_insert(i); } } break; }#endif return 0;}#ifdef CONFIG_CEE#include <linux/device.h>static int mmc_suspend(struct device *dev, u32 state, u32 level);static int mmc_resume(struct device *dev, u32 level);static struct device_driver mmc_driver_ldm = { name: "mmc", devclass: NULL, probe: NULL, suspend: mmc_suspend, resume: mmc_resume, scale: NULL, remove: NULL,};static struct device mmc_device_ldm = { name: "MMC", bus_id: "mmc", driver: NULL, power_state: DPM_POWER_ON,};static voidmmc_ldm_register(void){#ifdef CONFIG_ARCH_MAINSTONE extern void pxaopb_driver_register(struct device_driver *driver); extern void pxaopb_device_register(struct device *device); pxaopb_driver_register(&mmc_driver_ldm); pxaopb_device_register(&mmc_device_ldm);#endif#ifdef CONFIG_ARCH_OMAP extern void mpu_public_driver_register(struct device_driver *driver); extern void mpu_public_device_register(struct device *device); mpu_public_driver_register(&mmc_driver_ldm); mpu_public_device_register(&mmc_device_ldm);#endif#ifdef CONFIG_ARCH_MX2ADS extern void mx21_ldm_device_register(struct device *device); extern void mx21_ldm_driver_register(struct device_driver *driver); mx21_ldm_driver_register(&mmc_driver_ldm); mx21_ldm_device_register(&mmc_device_ldm);#endif}static voidmmc_ldm_unregister(void){#ifdef CONFIG_ARCH_MAINSTONE extern void pxaopb_driver_unregister(struct device_driver *driver); extern void pxaopb_device_unregister(struct device *device); pxaopb_device_unregister(&mmc_device_ldm); pxaopb_driver_unregister(&mmc_driver_ldm);#endif#ifdef CONFIG_ARCH_OMAP extern void mpu_public_driver_unregister(struct device_driver *driver); extern void mpu_public_device_unregister(struct device *device); mpu_public_driver_unregister(&mmc_driver_ldm); mpu_public_device_unregister(&mmc_device_ldm);#endif#ifdef CONFIG_ARCH_MX2ADS extern void mx21_ldm_device_unregister(struct device *device); extern void mx21_ldm_driver_unregister(struct device_driver *driver); mx21_ldm_device_unregister(&mmc_device_ldm); mx21_ldm_driver_unregister(&mmc_driver_ldm);#endif}static intmmc_resume(struct device *dev, u32 level){ int i; switch (level) { case RESUME_RESTORE_STATE: case RESUME_ENABLE: case RESUME_POWER_ON: /* Enter D0 */ if ( g_mmc_dev.suspended ) { g_mmc_dev.suspended = 0; g_mmc_dev.state = 0; // Clear the old state for ( i = 0 ; i < g_mmc_dev.num_slots ; i++ ) { mmc_eject(i); if ( !g_mmc_dev.sdrive->is_empty(i) ) mmc_insert(i); } } break; } return 0;}static intmmc_suspend(struct device *dev, u32 state, u32 level){ switch (level) { case SUSPEND_NOTIFY: case SUSPEND_SAVE_STATE: case SUSPEND_DISABLE: case SUSPEND_POWER_DOWN: /* Enter D1-D3 */ g_mmc_dev.suspended = 1; break; } return 0;}#endif /* CONFIG_CEE *//****************************************************************** * TODO: These would be better handled by driverfs * For the moment, we'll just eject and insert everything ******************************************************************/int mmc_do_eject(ctl_table *ctl, int write, struct file * filp, void *buffer, size_t *lenp){ mmc_eject(0); return 0;}int mmc_do_insert(ctl_table *ctl, int write, struct file * filp, void *buffer, size_t *lenp){ mmc_insert(0); return 0;}static struct ctl_table mmc_sysctl_table[] ={ { 1, "debug", &g_mmc_debug, sizeof(int), 0666, NULL, &proc_dointvec }, { 2, "eject", NULL, 0, 0600, NULL, &mmc_do_eject }, { 3, "insert", NULL, 0, 0600, NULL, &mmc_do_insert }, {0}};static struct ctl_table mmc_dir_table[] ={ {BUS_MMC, "mmc", NULL, 0, 0555, mmc_sysctl_table}, {0}};static struct ctl_table bus_dir_table[] = { {CTL_BUS, "bus", NULL, 0, 0555, mmc_dir_table}, {0}};static struct ctl_table_header *mmc_sysctl_header;#ifdef CONFIG_USBD_ISP_BUSstatic unsigned int read_request_head = 0;static unsigned int read_request_tail = 0;static struct read_request_pool_s read_request_pool[MAX_READ_AHEAD_REQUEST];static struct dma_buf_pool_s *write_request_pool[MAX_WRITE_PENDING_REQUEST];static struct mmc_io_request gg_io_read_request, gg_io_write_request[MAX_WRITE_PENDING_REQUEST];static unsigned int write_request_head = 0;static unsigned int write_request_tail = 0;void (*old_io_request_done)(struct mmc_io_request * req, int result);LIST_HEAD(dma_write_buf_pool_head);LIST_HEAD(dma_read_buf_pool_head);struct dma_buf_pool_s dma_write_buf_pool[MAX_BUF_POOL_SIZE];
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -