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

📄 mmc_core.c

📁 mmc_qspi.tar.gz mmc block driver code for uClinux
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <linux/config.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/fs.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/mm.h>#include <linux/hdreg.h>#include <asm/byteorder.h>#include <asm/uaccess.h>#define DEVICE_NAME "mmc"static int mmc_blk_major = 0;#define MAJOR_NR mmc_blk_major#define DEVICE_SHIFT 4 /* 4 bits for the device number */#define DEVICE_NR(device) (MINOR(device) >> DEVICE_SHIFT)//#define DEVICE_INTR mmc_blk_intptr#define DEVICE_NO_RANDOM#define DEVICE_OFF(d)#include <linux/blk.h>#include <linux/blkdev.h>#include <linux/blkpg.h>#include <linux/genhd.h>#include "klog.h"#include "mmc_qspi.h"/* number of devices allowed to be plug in the same time  * arbitrary number... can be change depending needs */#define DFLT_NB_DEV 1#define DFLT_BLK_SIZE 16384 /* size in number of block to do : dynamic assignement */#define DFLT_BLKSIZE_SIZE 1024 /* block size */#define DFLT_HARDSECT_SIZE 512 /* default mmc sector size */#define MAX_BLK_NB 10#define DFLT_RAHEAD MAX_BLK_NB#define READ_FLAG 0#define WRITE_FLAG 1/* Version Information */#define DRIVER_AUTHOR "Simon Guinot"#define DRIVER_DESC "MMC over qspi driver for the 5282 motorola board"MODULE_PARM(nb_dev, "i");MODULE_PARM_DESC(nb_dev, "max number of devices");MODULE_PARM(mmc_blk_major, "i");MODULE_PARM_DESC(mmc_blk_major, "mmc_blk major number");static int nb_dev = DFLT_NB_DEV;struct hd_struct *mmc_blk_partitions = NULL;static int mmc_blk_size[256];static int mmc_blk_blocksizes[256];static int mmc_blk_sectorsizes[256];//static int mmc_blk_maxsectors[256];struct mmc_blk{	unsigned int open_count;	unsigned int busy;	char csd[CSD_SIZE];	char cid[CID_SIZE];	unsigned long sector_size;	unsigned long block_size;	unsigned long size;	mode_t mode;};      static struct mmc_blk *mmc_blk_dev = NULL;static int init_mmc (int, struct mmc_blk *);static int mmc_blk_open (struct inode *, struct file *);static int mmc_blk_ioctl (struct inode *, struct file *, unsigned int, unsigned long);static int mmc_blk_release (struct inode *, struct file *);static int mmc_blk_make_request (request_queue_t *, int, struct buffer_head *);static int mmc_blk_change (kdev_t);static int mmc_blk_revalidate (kdev_t);static struct block_device_operations mmc_blk_ops = {	open:           mmc_blk_open,	ioctl:          mmc_blk_ioctl,	release:        mmc_blk_release,	check_media_change: mmc_blk_change,	revalidate: 	mmc_blk_revalidate};struct gendisk mmc_blk_gendisk ={	major:		0,	major_name:	DEVICE_NAME,	minor_shift:	DEVICE_SHIFT,	max_p:		1 << DEVICE_SHIFT,	fops:		&mmc_blk_ops};/* method to call when the media has changed */static int mmc_blk_revalidate (kdev_t i_rdev){	int minor = MINOR(i_rdev);	int device_num = minor >> DEVICE_SHIFT;	int part1 = (device_num << DEVICE_SHIFT) + 1;	int npart = (1 << DEVICE_SHIFT) - 1;	struct mmc_blk *dev;	dbg("%s - minor : %d", __FUNCTION__, minor);	if ((device_num < 0) ||	    (device_num >= nb_dev))	{		err("%s : device %d don't exits", 				__FUNCTION__, device_num);		return (-ENODEV);	}		dev = (struct mmc_blk *) (mmc_blk_dev + device_num);	/* first clear old partition information */	memset (mmc_blk_gendisk.sizes + part1, 0, npart * sizeof(int));	memset (mmc_blk_gendisk.part + part1, 0, npart * sizeof (struct hd_struct));	mmc_blk_gendisk.part[device_num << DEVICE_SHIFT].nr_sects =		mmc_blk_size[device_num << DEVICE_SHIFT] 		* mmc_blk_blocksizes[device_num << DEVICE_SHIFT] 		/ mmc_blk_sectorsizes[device_num << DEVICE_SHIFT];	/* then fill new info */	info("(device %d - minor %d) check partition", device_num, minor);	/*        grok_partitions (&mmc_blk_gendisk, device_num, 			1 << DEVICE_SHIFT, mmc_blk_gendisk.sizes[device_num << DEVICE_SHIFT]);*/		register_disk (&mmc_blk_gendisk, 			MKDEV(mmc_blk_major, (device_num << DEVICE_SHIFT)), 			npart, &mmc_blk_ops, 			mmc_blk_partitions[device_num << DEVICE_SHIFT].nr_sects);        return (0); /* still valid */}/* FIXME : removable media support  * return 0 if the device is already ok  * return 1 if the device has expired */static int mmc_blk_change (kdev_t i_rdev){	int minor = MINOR(i_rdev);	int device_num = minor >> DEVICE_SHIFT;	int i;	char *cid_tmp = NULL;	struct mmc_blk *dev;	if ((device_num < 0) ||	    (device_num >= nb_dev))	{		err("%s : DEV for minor %d don't exits", 				__FUNCTION__, device_num);		return (1);	}		dev = (struct mmc_blk *) (mmc_blk_dev + device_num);	/* get the MMC CID register (Card Specific Data) */	cid_tmp = get_cid ();	if (cid_tmp == NULL)	{		err("%s - unable to get CID register", __FUNCTION__);		/* TODO : may be there is no device ? */		return (1);	}	else	{		for (i = 0; i < CID_SIZE; i++)		{			if (dev->cid[i] != cid_tmp[i])			{				err("%s - CID differ", __FUNCTION__);				kfree (cid_tmp);				return (1);			}		}	}    		/* device still ok */	kfree (cid_tmp);	return (0);}static int mmc_blk_make_request (request_queue_t *queue, int rw, struct buffer_head *bh){	int minor = MINOR(bh->b_rdev);	int device_num = minor >> DEVICE_SHIFT;	struct mmc_blk *dev;	unsigned char *block_addr_ptr[MAX_BLK_NB];	unsigned long block_addr[MAX_BLK_NB];	int i, size = 0, nb_block, status = 1, count;		if ((device_num < 0) ||	    (device_num >= nb_dev))	{		err("%s : device %d don't exits", 				__FUNCTION__, device_num);		status = 0;		goto exit;	}		dev = (struct mmc_blk *) (mmc_blk_dev + device_num);	/* only handle modulo BLKSIZE_SIZE request */	if ((bh->b_size%DFLT_HARDSECT_SIZE) != 0)	{		err("%s - can't handle a %d bytes request (not a x%d size)", 				__FUNCTION__, bh->b_size, DFLT_BLKSIZE_SIZE);		status = 0;		goto exit;	}	nb_block = bh->b_size / DFLT_HARDSECT_SIZE;	/* don't allow to treat more than MAX_BLK_NB blocks 	 * nb_block depend from MMC size and from filesystem type */	if (nb_block > MAX_BLK_NB)	{		err("%s - request to handle %d blocks (max = %d)", 				__FUNCTION__, nb_block, MAX_BLK_NB);		status = 0;		goto exit;	}	dbg("%s - request size : %d - rw : %d", 			__FUNCTION__, bh->b_size, rw);		/* don't allow MMC overflow access */	if ((bh->b_rsector + nb_block) > (mmc_blk_size[minor] 			* mmc_blk_blocksizes[device_num << DEVICE_SHIFT] 			/ mmc_blk_sectorsizes[device_num << DEVICE_SHIFT]))	{		err("%s : device %d overflow", 				__FUNCTION__, device_num);/*		status = 0;		goto exit;*/	}	for (i = 0; i < nb_block; i++)	{		/* use DFLT_BLKSIZE_SIZE instead of 		 * mmc_blk_blocksizes[device_num] 		 * hard MMC block == 512 */		block_addr[i] = (mmc_blk_partitions[minor].start_sect + 			 bh->b_rsector) * mmc_blk_sectorsizes[device_num] + 			(i * DFLT_HARDSECT_SIZE);		block_addr[i] = __cpu_to_be32(block_addr[i]); /* endianness */		block_addr_ptr[i] = (unsigned char *) &block_addr[i];			dbg("%s - block[%d] address %d %d %d %d", __FUNCTION__, i, 				block_addr_ptr[i][0], block_addr_ptr[i][1], 				block_addr_ptr[i][2], block_addr_ptr[i][3]);	}#if CONFIG_HIGHMEM	bh = create_bounce (rw, bh);#endif	schedule ();	switch (rw)	{		case READ :		case READA :		for (i = 0; i < nb_block; i++)		{			count = 2;			do			{				size = read_block (block_addr_ptr[i][0], 						block_addr_ptr[i][1], 						block_addr_ptr[i][2], 						block_addr_ptr[i][3],						bh->b_data + (i * DFLT_HARDSECT_SIZE));			}			while ((size != DFLT_HARDSECT_SIZE) && (count--));			if (size != DFLT_HARDSECT_SIZE)			{				err("failed to read block %d - %d - %d - %d", 						block_addr_ptr[i][0], 						block_addr_ptr[i][1], 						block_addr_ptr[i][2], 						block_addr_ptr[i][3]);				status = 0;				goto exit;			}		}		goto exit;			break;		case WRITE :		refile_buffer (bh);		for (i = 0; i < nb_block; i++)		{			count = 2;			do			{				size = write_block (block_addr_ptr[i][0], 					block_addr_ptr[i][1], 					block_addr_ptr[i][2], 					block_addr_ptr[i][3],					bh->b_data + (i * DFLT_HARDSECT_SIZE));			}			while ((size != DFLT_HARDSECT_SIZE) && (count--));			if (size != DFLT_HARDSECT_SIZE)			{				err("failed to write block %d - %d - %d - %d", 						block_addr_ptr[i][0], 						block_addr_ptr[i][1], 						block_addr_ptr[i][2], 						block_addr_ptr[i][3]);				status = 0;				goto exit;			}		}		mark_buffer_uptodate (bh, 1);		goto exit;		break;		default :			status = 0;			goto exit;			break;	}exit :	bh->b_end_io (bh, status);	return (0);}static int mmc_blk_open (struct inode *inode, struct file *file){	int device_num = MINOR(inode->i_rdev) >> DEVICE_SHIFT;	struct mmc_blk *dev;	int retval = 0;		dbg("enter %s", __FUNCTION__);	if ((device_num < 0) ||	    (device_num >= nb_dev))	{		err("%s : DEV for minor %d don't exits", 				__FUNCTION__, device_num);		retval = -ENODEV;		goto exit;	}		dev = (struct mmc_blk *) (mmc_blk_dev + device_num);	/* don't allow more than 1 process to open 	 * a MMC device */	if (!dev->open_count)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -