📄 patch-2.4.19-mmc
字号:
+ * Many thanks to Alessandro Rubini and Jonathan Corbet!+ *+ * Author: Andrew Christian+ * 28 May 2002+ */++#include <linux/config.h>+#include <linux/module.h>++#include <linux/sched.h>+#include <linux/kernel.h> /* printk() */+#include <linux/fs.h> /* everything... */+#include <linux/errno.h> /* error codes */+#include <linux/types.h> /* size_t */+#include <linux/fcntl.h> /* O_ACCMODE */+#include <linux/hdreg.h> /* HDIO_GETGEO */+#include <linux/init.h>+#include <linux/devfs_fs_kernel.h>++#include <asm/system.h>+#include <asm/uaccess.h>++#include "mmc_media.h"++#define MAJOR_NR mmc_major /* force definitions on in blk.h */+static int mmc_major; /* must be declared before including blk.h */++#define MMC_SHIFT 3 /* max 8 partitions per card */++#define DEVICE_NR(device) (MINOR(device)>>MMC_SHIFT)+#define DEVICE_NAME "mmc" /* name for messaging */+#define DEVICE_INTR mmc_intrptr /* pointer to the bottom half */+#define DEVICE_NO_RANDOM /* no entropy to contribute */+#define DEVICE_REQUEST mmc_media_request+#define DEVICE_OFF(d) /* do-nothing */++#include <linux/blk.h>+#include <linux/blkpg.h>++static int rahead = 8;+static int maxsectors = 4;++MODULE_PARM(maxsectors,"i");+MODULE_PARM_DESC(maxsectors,"Maximum number of sectors for a single request");+MODULE_PARM(rahead,"i");+MODULE_PARM_DESC(rahead,"Default sector read ahead");++#define MMC_NDISK (MMC_MAX_SLOTS << MMC_SHIFT)++/* + Don't bother messing with blksize_size....it gets changed by various filesystems.+ You're better off dealing with arbitrary blksize's+*/ +static int mmc_blk[MMC_NDISK]; /* Used for hardsect_size - should be 512 bytes */+static int mmc_max[MMC_NDISK]; /* Used for max_sectors[] - limit size of individual request */++static int mmc_sizes[MMC_NDISK]; /* Used in gendisk - gives whole size of partition */+static struct hd_struct mmc_partitions[MMC_NDISK]; /* Used in gendisk - gives particular partition information */++static char mmc_gendisk_flags;+static devfs_handle_t mmc_devfs_handle;++// There is one mmc_media_dev per inserted card+struct mmc_media_dev {+ int usage;+ struct mmc_slot *slot;+ spinlock_t lock;+ int changed;+ long nr_sects; // In total number of sectors++ int read_block_len; // Valid read block length+ int write_block_len; // Valid write block length+};++static struct mmc_media_dev g_media_dev[MMC_MAX_SLOTS];+static struct mmc_io_request g_io_request;+static int g_busy;++static struct gendisk mmc_gendisk = {+ major: 0, /* major number dynamically assigned */+ major_name: DEVICE_NAME,+ minor_shift: MMC_SHIFT, /* shift to get device number */+ max_p: 1 << MMC_SHIFT, /* Number of partiions */+ /* The remainder will be filled in dynamically */+};++/*************************************************************************/+/* TODO: O_EXCL, O_NDELAY, invalidate_buffers */+static int mmc_media_open( struct inode *inode, struct file *filp )+{+ struct mmc_media_dev *dev;+ int num = DEVICE_NR(inode->i_rdev);++ DEBUG(1,": num=%d\n", num);++ if ( num >= MMC_MAX_SLOTS) + return -ENODEV;++ dev = &g_media_dev[num];+ if ( !dev->slot ) + return -ENODEV;++ spin_lock(&dev->lock);+ if (!dev->usage)+ check_disk_change(inode->i_rdev);+ dev->usage++;+ MOD_INC_USE_COUNT;+ spin_unlock(&dev->lock);+ return 0;+}++static int mmc_media_release( struct inode *inode, struct file *filep )+{+ struct mmc_media_dev *dev = &g_media_dev[DEVICE_NR(inode->i_rdev)];++ DEBUG(1,": num=%d\n", DEVICE_NR(inode->i_rdev));++ spin_lock(&dev->lock);+ dev->usage--;+ /* Is this worth doing? */+ if (!dev->usage) { + fsync_dev(inode->i_rdev);+ invalidate_buffers(inode->i_rdev);+ }+ MOD_DEC_USE_COUNT;+ spin_unlock(&dev->lock);+ return 0;+}++static int mmc_media_revalidate(kdev_t i_rdev)+{+ int index, max_p, start, i;+ struct mmc_media_dev *dev;++ index = DEVICE_NR(i_rdev);+ DEBUG(2,": index=%d\n", index);++ max_p = mmc_gendisk.max_p;+ start = index << MMC_SHIFT;+ dev = &g_media_dev[index];++ for ( i = max_p - 1 ; i >= 0 ; i-- ) {+ int item = start + i;+ invalidate_device(MKDEV(mmc_major,item),1);+ mmc_gendisk.part[item].start_sect = 0;+ mmc_gendisk.part[item].nr_sects = 0;+ /* TODO: Fix the blocksize? */+ }++ register_disk(&mmc_gendisk, i_rdev, 1 << MMC_SHIFT, mmc_gendisk.fops, dev->nr_sects);+ return 0;+}++static int mmc_media_ioctl (struct inode *inode, struct file *filp,+ unsigned int cmd, unsigned long arg)+{+ int num = DEVICE_NR(inode->i_rdev);+ int size;+ struct hd_geometry geo;++ DEBUG(1," ioctl 0x%x 0x%lx\n", cmd, arg);++ switch(cmd) {+ case BLKGETSIZE:+ /* Return the device size, expressed in sectors */+ /* Not really necessary, but this is faster than walking the gendisk list */+ if (!access_ok(VERIFY_WRITE, arg, sizeof(long)))+ return -EFAULT;+ return put_user(mmc_partitions[MINOR(inode->i_rdev)].nr_sects, (long *)arg);++ case BLKRRPART: /* re-read partition table */+ if (!capable(CAP_SYS_ADMIN)) + return -EACCES;+ return mmc_media_revalidate(inode->i_rdev);++ case HDIO_GETGEO:+ if (!access_ok(VERIFY_WRITE, arg, sizeof(geo)))+ return -EFAULT;+ /* Grab the size from the 0 partition for this minor */+ /* TODO: is this the right thing? Or should we do it by partition??? */+ size = mmc_sizes[num << MMC_SHIFT] / mmc_blk[num << MMC_SHIFT];+ geo.cylinders = (size & ~0x3f) >> 6;+ geo.heads = 4;+ geo.sectors = 16;+ geo.start = mmc_partitions[MINOR(inode->i_rdev)].start_sect;+ if (copy_to_user((void *) arg, &geo, sizeof(geo)))+ return -EFAULT;+ return 0;++ default:+ return blk_ioctl(inode->i_rdev, cmd, arg);+ }++ return -ENOTTY; /* should never get here */+}++static int mmc_media_check_change(kdev_t i_rdev) +{+ int index, retval;+ struct mmc_media_dev *dev;+ unsigned long flags;++ index = DEVICE_NR(i_rdev);+ DEBUG(2," device=%d\n", index);+ if (index >= MMC_MAX_SLOTS) + return 0;++ dev = &g_media_dev[index];++ spin_lock_irqsave(&dev->lock, flags);+ retval = (dev->changed ? 1 : 0);+ dev->changed = 0;+ spin_unlock_irqrestore(&dev->lock, flags);++ return retval;+}++static struct mmc_media_dev * mmc_media_locate_device(const struct request *req)+{+ int num = DEVICE_NR(req->rq_dev);+ if ( num >= MMC_MAX_SLOTS) {+ static int count = 0;+ if (count++ < 5) /* print the message at most five times */+ printk(KERN_WARNING "mmc: request for unknown device\n");+ return NULL;+ }+ return &g_media_dev[num];+}++static int mmc_media_transfer( struct mmc_media_dev *dev, const struct request *req )+{+ int minor = MINOR(req->rq_dev);+ unsigned long flags;++ DEBUG(2,": minor=%d\n", minor);++ if ( req->sector + req->current_nr_sectors > mmc_partitions[minor].nr_sects ) {+ static int count = 0;+ if (count++ < 5)+ printk(KERN_WARNING __FUNCTION__ ": request past end of partition\n");+ return 0;+ }+ + spin_lock_irqsave(&dev->lock, flags);++ g_io_request.id = DEVICE_NR(req->rq_dev);+ g_io_request.cmd = req->cmd;+ g_io_request.sector = mmc_partitions[minor].start_sect + req->sector;+ g_io_request.nr_sectors = req->current_nr_sectors;+ g_io_request.block_len = mmc_blk[minor];+ g_io_request.buffer = req->buffer;++ DEBUG(2,": id=%d cmd=%d sector=%ld nr_sectors=%ld block_len=%ld buf=%p\n",+ g_io_request.id, g_io_request.cmd, g_io_request.sector, g_io_request.nr_sectors,+ g_io_request.block_len, g_io_request.buffer );++ mmc_handle_io_request(&g_io_request);+ spin_unlock_irqrestore(&dev->lock, flags);+ return 1;+}++static void mmc_media_request( request_queue_t *q )+{+ struct mmc_media_dev *dev;++ if ( g_busy )+ return;++ while(1) {+ INIT_REQUEST; /* returns when queue is empty */+ 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 */+ }+}++static void mmc_media_transfer_done( struct mmc_io_request *trans, int result )+{+ unsigned long flags;+ DEBUG(3,": result=%d\n", result);+ spin_lock_irqsave(&io_request_lock, flags);+ 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+};++/******************************************************************/+/* 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,+};+
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -