⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 patch-2.4.19-mmc

📁 linux2.4.19内核关于MMC/SD卡驱动的补丁
💻 19-MMC
📖 第 1 页 / 共 5 页
字号:
+ * 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 + -