📄 mmc_media.c
字号:
dev = mmc_media_locate_device(CURRENT); if ( !dev ) { end_request(0); continue; } DEBUG(2," (%p): cmd %i sec %li (nr. %li)\n", CURRENT, CURRENT->cmd, CURRENT->sector, CURRENT->current_nr_sectors); if ( mmc_media_transfer(dev,CURRENT) ) { g_busy = 1; return; } end_request(0); /* There was a problem with the request */ }}void mmc_media_transfer_done( struct mmc_io_request *trans, int result ){ unsigned long flags; int nsect,nr_sectors; struct request *req = CURRENT; struct buffer_head *bh = req->bh, *next; unsigned char *data = (unsigned char *)bh_pages; DEBUG(3,": result=%d\n", result); spin_lock_irqsave(&io_request_lock, flags); nr_sectors = trans->nr_sectors; for (;;) { if ((req->cmd == READ) && data) { memcpy(bh->b_data,data,bh->b_size); data += bh->b_size; } if (!(next = bh->b_reqnext)) break; if (!(nr_sectors - (next->b_size >> 9))) break; nsect = bh->b_size >> 9; blk_finished_io(nsect); bh->b_reqnext = NULL; bh->b_end_io(bh,result); req->bh = bh = next; next = bh->b_reqnext; req->hard_sector += nsect; req->hard_nr_sectors -= nsect; req->sector = req->hard_sector; req->nr_sectors = req->hard_nr_sectors; req->current_nr_sectors = bh->b_size >> 9; req->hard_cur_sectors = req->current_nr_sectors; if (req->nr_sectors < req->current_nr_sectors) { req->nr_sectors = req->current_nr_sectors; printk("end_request:buffer-list destroyed\n"); } req->buffer = bh->b_data; nr_sectors -= nsect; }//#ifdef CONFIG_ARCH_EZX_E680 /* add by w20598 */ if (!mmc_slot_enable) if (MMC_IO_READ == trans->cmd) end_request(0); else end_request(1); else /* add end */ //#endif end_request(result); g_busy = 0; if (!QUEUE_EMPTY) mmc_media_request(NULL); // Start the next transfer spin_unlock_irqrestore(&io_request_lock, flags);}static struct block_device_operations mmc_bdops = { open: mmc_media_open, release: mmc_media_release, ioctl: mmc_media_ioctl, check_media_change: mmc_media_check_change, revalidate: mmc_media_revalidate};//#ifdef CONFIG_ARCH_EZX_E680/*********************************************************************//* add by w20598 for hotplug support *//* if user unplugs the card, driver will prevent from flushing datas *//* create a new inferface to set driver enable *//*********************************************************************//******************************************************************************* * Function name: mmcsysif_open * Arguments: struct inode * * struct file * * Return: int : 0 for successful, * negative number signaling a error * Comments: open operation *******************************************************************************/static int mmcsysif_open(struct inode * inode, struct file * file){ DEBUG(2,": mmcsysif_usage=%d\n", mmcsysif_usage); if (mmcsysif_usage > 2) return -1; mmcsysif_usage++; return 0;}/******************************************************************************* * Function name: mmcsysif_release * Arguments: struct inode * * struct file * * Return: int : 0 for successful, * negative number signaling a error * Comments: release operation *******************************************************************************/static int mmcsysif_release(struct inode * inode, struct file * file){ if (mmcsysif_usage > 2) return -1; mmcsysif_usage--; DEBUG(2,": mmcsysif_usage=%d\n", mmcsysif_usage); return 0;}/* ioctl for tcmd. ap_tcmd can run as ezx user */static int mmcsysif_ioctl_ext(unsigned int cmd, unsigned long arg){ int num = 0; struct mmc_media_dev *dev; struct mmc_slot *slot; unsigned long status; dev = &g_media_dev[num]; if (dev->slot == NULL) return -ENODEV; slot = g_media_dev[num].slot; switch(cmd) { case IOCMMCGETSIZE: if (!access_ok(VERIFY_WRITE, arg, sizeof(long))) return -EFAULT; return put_user(dev->nr_sects * dev->read_block_len, (long *)arg); case IOCMMCGETCARDCID: if (!access_ok(VERIFY_WRITE, arg, sizeof(struct mmc_cid))) return -EFAULT; if (copy_to_user ((void *) arg, &(slot->cid), sizeof(struct mmc_cid))) return -EFAULT; return 0; case IOCMMCGETCARDCSD: if (!access_ok(VERIFY_WRITE, arg, sizeof(struct mmc_csd))) return -EFAULT; if (copy_to_user ((void *) arg, &(slot->csd), sizeof(struct mmc_csd))) return -EFAULT; return 0; case IOCMMCGETCARDSTATUS: if (!access_ok(VERIFY_WRITE, arg, sizeof(int))) return -EFAULT; status = 0; if (slot->dev->sdrive->is_wp && slot->dev->sdrive->is_wp(num)) status |= 0x1; if (copy_to_user((void*) arg, & status, sizeof(unsigned long))) return -EFAULT; return 0; case IOCMMCGETCARDTYPE: if (!access_ok(VERIFY_WRITE, arg, sizeof(long))) return -EFAULT; return put_user(g_media_dev[num].slot->sd,(long *)arg); default: break; } return -ENOTTY; }static int mmcsysif_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg){ DEBUG(2," ioctl 0x%x 0x%lx\n", cmd, arg); switch(cmd) { case IOCMMCSETENABLE: if (!access_ok(VERIFY_WRITE, arg, sizeof(long))) return -EFAULT; if (mmc_slot_enable) { DEBUG(3, "slot%d is already enable.\n",arg); return 0; } DEBUG(3, "set slot%d enable\n",arg); mmc_slot_enable = 1; return 0; case IOCSETERROR: panicdev = (unsigned short)MKDEV(mmc_major,1); complete(&fatpanic_completion); return 0; case IOCMMCEXIST: if (!access_ok(VERIFY_WRITE, arg, sizeof(long))) return -EFAULT; #ifdef CONFIG_ARCH_EZX_A780 return put_user(( GPLR(GPIO_MMC_DATA3) & GPIO_bit(GPIO_MMC_DATA3)),(long *)arg);#else return put_user(( GPLR(GPIO_MMC_DETECT) & GPIO_bit(GPIO_MMC_DETECT)),(long *)arg);#endif case IOCMMCGETSIZE: case IOCMMCGETCARDCID: case IOCMMCGETCARDCSD: case IOCMMCGETCARDSTATUS: case IOCMMCGETCARDTYPE: return mmcsysif_ioctl_ext(cmd,arg); default: break; } return -ENOTTY; /* should never get here */}static ssize_t mmcsysif_read(struct file * filp, char * buf, size_t count, loff_t *ppos){ panicdev = 0; init_completion(&fatpanic_completion); wait_for_completion(&fatpanic_completion); if (!copy_to_user(buf,kdevname((kdev_t) panicdev),5)) return 0; return -1; /* error */ }static struct file_operations mmcsysif_bdops = { ioctl: mmcsysif_ioctl, open: mmcsysif_open, read: mmcsysif_read, release: mmcsysif_release};//#endif/******************************************************************//* TODO: We have a race condition if two slots need to be revalidated at the same time. Perhaps we should walk the list of devices and look for change flags?*/static void mmc_media_load_task_handler( void *nr ){ int slot_id = (int) nr; DEBUG(2," slot_id=%d\n", slot_id ); mmc_media_revalidate(MKDEV(mmc_major,(slot_id<<MMC_SHIFT)));}static struct tq_struct mmc_media_load_task = { routine: mmc_media_load_task_handler};static void mmc_media_load( struct mmc_slot *slot ){ unsigned long flags; struct mmc_media_dev *dev = &g_media_dev[slot->id]; int i; long nr_sects; int write_block_len; int read_block_len; spin_lock_irqsave(&dev->lock, flags); nr_sects = (1 + slot->csd.c_size) * (1 << (slot->csd.c_size_mult + 2)); write_block_len = 1 << slot->csd.write_bl_len; read_block_len = 1 << slot->csd.read_bl_len; MOD_INC_USE_COUNT; DEBUG(1, " slot=%p nr_sect=%ld write_block_length=%d read_block_len=%d\n", slot, nr_sects, write_block_len, read_block_len ); dev->slot = slot; dev->nr_sects = nr_sects; dev->read_block_len = read_block_len; dev->write_block_len = write_block_len; dev->changed = 1; mmc_gendisk.nr_real++; /* Fix up the block size to match read_block_len */ /* TODO: can we really do this? Right now we're affecting blksize_size and hardsect_size */ for ( i = 0 ; i < (1 << MMC_SHIFT) ; i++ ) mmc_blk[(slot->id << MMC_SHIFT) + i] = read_block_len; mmc_media_load_task.data = (void *) slot->id; schedule_task( &mmc_media_load_task ); spin_unlock_irqrestore(&dev->lock, flags);}/* TODO: This is a problem area. We've lost our card, so we'd like to flush all outstanding buffers and requests, remove the partitions from the file system, and generally shut everything down.*/static void mmc_media_unload( struct mmc_slot *slot ){ unsigned long flags; struct mmc_media_dev *dev = &g_media_dev[slot->id]; spin_lock_irqsave(&dev->lock, flags);// for ( i = 0 ; i < MMC_SHIFT ; i++ )// fsync_dev(MKDEV(mmc_major,slot->id,i)); MOD_DEC_USE_COUNT; DEBUG(1," slot=%p id=%d\n", slot, slot->id); dev->slot = NULL; dev->nr_sects = 0; dev->changed = 1; mmc_gendisk.nr_real--; mmc_media_load_task.data = (void *) slot->id; schedule_task( &mmc_media_load_task ); spin_unlock_irqrestore(&dev->lock, flags);}/* Called once the device has a valid CSD structure In the future this should determine what type of card we have For the moment, everything is a memory card */static int mmc_media_probe( struct mmc_slot *slot ){ return 1;}static struct mmc_media_driver mmc_driver = { name: "flash", load: mmc_media_load, unload: mmc_media_unload, probe: mmc_media_probe, io_request_done: mmc_media_transfer_done,};/******************************************************************/static int __init mmc_media_init( void ){ int i, result,order; DEBUG(0,"Init MMC media\n"); #ifdef CONFIG_DEVFS_FS mmc_devfs_handle = devfs_mk_dir(NULL, DEVICE_NAME, NULL); if (!mmc_devfs_handle) return -EBUSY; result = devfs_register_blkdev(mmc_major, DEVICE_NAME, &mmc_bdops);#else result = register_blkdev(mmc_major, DEVICE_NAME, &mmc_bdops); #endif if (result < 0) { printk(KERN_WARNING "Unable to get major %d for MMC media\n", mmc_major); return result; } if ( !mmc_major ) mmc_major = result; DEBUG(3, "register block device /dev/%s* layer with major %d\n", DEVICE_NAME, mmc_major);//#ifdef CONFIG_ARCH_EZX_E680/* add by w20598 for mmcsysif */#ifdef CONFIG_DEVFS_FS mmcsysif_de = devfs_register(NULL,"midicomm",DEVFS_FL_AUTO_DEVNUM, 0, 0, S_IFCHR | S_IRUGO | S_IWUGO, &mmcsysif_bdops,NULL); if( NULL == mmcsysif_de) DEBUG(0,":devfs_register mmcsysif failed");#else result = register_chrdev(mmcsysif_major, "mmcsysif", &mmcsysif_bdops); if (result < 0) { DEBUG(0," :mmcsysif can not get major %d",mmcsysif_major); return result; } if( 0 == mmcsysif_major) { mmcsysif_major = result; DEBUG(2," :mmcsysif:mmcsysif_major = %d",mmcsysif_major); } DEBUG(2,": register mmcsysif success. major = %d",mmcsysif_major);#endif/* add end *///#endif /* Set up global block arrays */ read_ahead[mmc_major] = rahead; for(i=0 ; i < MMC_NDISK; i++) mmc_blk[i] = 512; hardsect_size[mmc_major] = mmc_blk; for(i=0; i < MMC_NDISK; i++) mmc_max[i] = maxsectors; max_sectors[mmc_major] = mmc_max; /* Start with zero-sized partitions : we'll fix this later */ memset(mmc_sizes, 0, sizeof(int) * MMC_NDISK); blk_size[mmc_major] = mmc_sizes; /* Fix up the gendisk structure */ mmc_gendisk.part = mmc_partitions; mmc_gendisk.sizes = mmc_sizes; mmc_gendisk.nr_real = 0; #ifdef CONFIG_DEVFS_FS mmc_gendisk.de_arr = &mmc_devfs_handle;#endif mmc_gendisk.flags = &mmc_gendisk_flags; mmc_gendisk.fops = &mmc_bdops; /* Add ourselves to the global list */ mmc_gendisk.major = mmc_major; add_gendisk(&mmc_gendisk); order = 0; while (maxsectors > (1<< (order + 2))) order++; bh_pages = __get_free_pages(GFP_KERNEL,order); blk_init_queue(BLK_DEFAULT_QUEUE(mmc_major), DEVICE_REQUEST); return mmc_register_media_driver(&mmc_driver);}static void mmc_media_cleanup( void ){ int i,order; DEBUG(0,"\n"); flush_scheduled_tasks(); unregister_blkdev(mmc_major, DEVICE_NAME); for ( i = 0 ; i < MMC_NDISK; i++ ) fsync_dev(MKDEV(mmc_major,i)); mmc_unregister_media_driver(&mmc_driver); blk_cleanup_queue(BLK_DEFAULT_QUEUE(mmc_major)); blk_size[mmc_major] = NULL; hardsect_size[mmc_major] = NULL; max_sectors[mmc_major] = NULL; del_gendisk(&mmc_gendisk); order = 0; while (maxsectors > (1<< (order + 2))) order++; if (bh_pages) free_pages(bh_pages,order);//#ifdef CONFIG_ARCH_EZX_E680 /* add by w20598 */#ifdef CONFIG_DEVFS_FS devfs_unregister(mmcsysif_de);#else unregister_chrdev(mmcsysif_major,"mmcsysif");#endif DEBUG(3,":mmcsysif quit");/* add end *///#endif#ifdef CONFIG_DEVFS_FS devfs_unregister(mmc_devfs_handle);#endif }struct mmc_media_module media_module = { init: mmc_media_init, cleanup: mmc_media_cleanup};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -