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

📄 mmc_block.c

📁 linux下mmc_sd卡的驱动.rar
💻 C
📖 第 1 页 / 共 2 页
字号:
/* *  linux/drivers/mmc/mmc_block.c  *  	 driver for the block device on the MMC card * *  Author:	Vladimir Shebordaev	 *  Copyright:	MontaVista Software Inc. * *	$Id: mmc_block.c,v 0.3.1.16 2002/09/27 17:36:09 ted Exp ted $ * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License version 2 as *  published by the Free Software Foundation. */#include <linux/version.h>#include <linux/config.h>#include <linux/types.h>#include <linux/module.h>#include <linux/init.h>#include <linux/devfs_fs_kernel.h>#include <linux/kernel.h>#include <linux/slab.h>#include <linux/hdreg.h>#include <linux/blkpg.h>#include <asm/uaccess.h>#include <mmc/types.h>#include <mmc/mmc.h>#include "types.h"#include "mmc.h"#include "error.h"#define MAJOR_NR MMC_BLOCK_MAJOR#define MAJOR_NAME "mmc"#define DEVICE_NAME "mmc_block"#define DEVICE_REQUEST mmc_block_request#define DEVICE_NR(device) (device)#define DEVICE_ON(device)#define DEVICE_OFF(device)#define DEVICE_NO_RANDOM#include <linux/blk.h>/* for old kernels... */#ifndef QUEUE_EMPTY#define QUEUE_EMPTY  (!CURRENT)#endif#if LINUX_VERSION_CODE < 0x20300#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].plug_tq.sync)#else#define QUEUE_PLUGGED (blk_dev[MAJOR_NR].request_queue.plugged)#endif#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,14)#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT#else#define BLK_INC_USE_COUNT do {} while(0)#define BLK_DEC_USE_COUNT do {} while(0)#endif#define MMC_BLOCK_RAW_DEVICE( device ) ((device>>MMC_BLOCK_PARTNBITS)<<MMC_BLOCK_PARTNBITS)#define MMC_BLOCK_MKDEV( host, slot ) \	MKDEV( MMC_BLOCK_MAJOR, \	(host<<MMC_MINOR_HOST_SHIFT) \	| (slot<<MMC_BLOCK_PARTNBITS) )typedef struct _mmc_block_device mmc_block_device_rec_t;typedef struct _mmc_block_device *mmc_block_device_t;struct _mmc_block_device {	mmc_card_t card;	int host;	int slot;	kdev_t rdev;	int usage;	semaphore_t sem;};static int mmc_block_blk_sizes[1<<MINORBITS];static int mmc_block_blk_blksizes[1<<MINORBITS];static int mmc_block_hardsect_sizes[1<<MINORBITS];static struct hd_struct mmc_block_partitions[1<<MINORBITS];/* Accessed under device table lock */static gendisk_rec_t mmc_block_gendisk = {	major:		MMC_BLOCK_MAJOR,	major_name:	MAJOR_NAME,	minor_shift:	MMC_BLOCK_PARTNBITS,	max_p:		(1<<MMC_BLOCK_PARTNBITS),	sizes:		mmc_block_blk_sizes,	part:		mmc_block_partitions};static mmc_block_device_rec_t mmc_block_device[1<<MINORBITS];static rwsemaphore_t mmc_block_device_sem;static inline void __mmc_block_rdlock_devices( void ){	down_read( &mmc_block_device_sem );}static inline void __mmc_block_rdunlock_devices( void ){	up_read( &mmc_block_device_sem );}static inline void __mmc_block_wrlock_devices( void ){	down_write( &mmc_block_device_sem );}static inline void __mmc_block_wrunlock_devices( void ){	up_write( &mmc_block_device_sem );}static inline void __mmc_block_lock_device( kdev_t rdev ){	__mmc_block_rdlock_devices();	down( &mmc_block_device[MINOR( rdev )].sem );}static inline void __mmc_block_unlock_device( kdev_t rdev ){	up( &mmc_block_device[MINOR( rdev )].sem );	__mmc_block_rdunlock_devices();}static inline void __mmc_block_device_init( int minor ){	mmc_block_device_t dev = &mmc_block_device[minor];		dev->usage = 0;	dev->card = NULL;	dev->host = minor >> MMC_MINOR_HOST_SHIFT;	dev->slot = (minor & MMC_MINOR_CARD_MASK)>>MMC_BLOCK_PARTNBITS;	dev->rdev = MKDEV( MMC_BLOCK_MAJOR, minor );}static inline int __mmc_block_validate_device( kdev_t rdev ){	int ret = -1;	int minor = MINOR( rdev );		if ( mmc_block_device[minor].card 			&& (mmc_block_gendisk.part[minor].nr_sects > 0) )		ret = 0;	return ret;}static inline int __mmc_block_invalidate_card( mmc_card_t card, int invalidate ){	int ret = 0;	kdev_t start;	int minor;	__ENTER( "card = 0x%p", card );		if ( card && card->ctrlr ) {		register int i;				start = MMC_BLOCK_MKDEV( card->ctrlr->slot, card->slot );		minor = MINOR( start );		__mmc_block_wrlock_devices();		for ( i = mmc_block_gendisk.max_p - 1; i >= 0; --i ) {			if ( invalidate )				invalidate_device( start + i, 0 );						__mmc_block_device_init( minor + i );						mmc_block_gendisk.part[minor + i].nr_sects = 0;			mmc_block_gendisk.part[minor + i].start_sect = 0;		}		__mmc_block_wrunlock_devices();	}		__LEAVE( "ret=%d", ret );	return ret;}static inline int mmc_block_invalidate_card( int host, int slot, int invalidate ){	int ret = 0;	kdev_t start;	int minor;	__ENTER( "host=%d slot=%d", host, slot );		if ( (host >= 0) && (slot >= 0) ) {		register int i;		mmc_card_t card = NULL;				start = MMC_BLOCK_MKDEV( host, slot );		minor = MINOR( start );		__mmc_block_wrlock_devices();		for ( i = mmc_block_gendisk.max_p - 1; i >= 0; --i ) {			if ( !card ) 				card = mmc_block_device[minor + i].card;						if ( invalidate )				invalidate_device( start + i, 0 );						__mmc_block_device_init( minor + i );						mmc_block_gendisk.part[minor + i].nr_sects = 0;			mmc_block_gendisk.part[minor + i].start_sect = 0;		}		if ( card )			mmc_put_card( card );		__mmc_block_wrunlock_devices();	}		__LEAVE( "ret=%d", ret );	return ret;}/* Get device reference locked for writing */static inline mmc_block_device_t __mmc_block_get_device( kdev_t rdev ){	mmc_block_device_t ret = NULL;	u8 minor = MINOR( rdev );	int host_no, card_no;	__ENTER( "rdev=%x:%x", MAJOR( rdev ), MINOR( rdev ) );	host_no = minor >> MMC_MINOR_HOST_SHIFT;	if ( host_no >= MMC_CONTROLLERS_MAX )		goto error;	card_no = (minor & MMC_MINOR_CARD_MASK)>>MMC_BLOCK_PARTNBITS;	if ( card_no >= MMC_CARDS_MAX )		goto error;		__mmc_block_lock_device( rdev );	if ( __mmc_block_validate_device( rdev ) ) {		__mmc_block_unlock_device( rdev );			goto error;	}	ret = &mmc_block_device[minor];	MMC_DEBUG( MMC_DEBUG_LEVEL2, "(%x:%x) card=%p, dusage=%d\n",			MAJOR( ret->rdev ), MINOR( ret->rdev ), 			ret->card, ret->usage );error:	__LEAVE( "ret=0x%p", ret );	return ret;}/* Unlocks the device */static inline void __mmc_block_put_device( mmc_block_device_t dev ){	__ENTER0();		if ( dev ) {		MMC_DEBUG( MMC_DEBUG_LEVEL2, "(%x:%x) card=%p, dusage=%d\n",				MAJOR( dev->rdev ), MINOR( dev->rdev ), 				dev->card, dev->usage );		__mmc_block_unlock_device( dev->rdev );	}		__LEAVE0();}/* Atomically increases use count of the valid device */static inline mmc_block_device_t mmc_block_get_device( kdev_t rdev ){	mmc_block_device_t ret = NULL;		__ENTER0();		ret = __mmc_block_get_device( rdev );	if ( !ret )		goto error;		ret->usage++;	__mmc_block_put_device( ret );error:	__LEAVE( "ret=0x%p dusage=%d card=0x%p cusage=%d",			ret, ret ? ret->usage : -1, 			ret ? ret->card : NULL, 			ret ? (ret->card ? ret->card->usage : -1) : -1 );	return ret;}/* Check is there references to the card */static inline int __mmc_block_check_card( kdev_t rdev ) {	int ret = TRUE;	int start = MINOR( MMC_BLOCK_RAW_DEVICE( rdev ) );	register int i;	for ( i = 0; i < mmc_block_gendisk.max_p; i++ )		if ( mmc_block_device[start + i].usage > 0 ) {			ret = FALSE;			break;		}	return ret;}/* Atomically decreases device use count */static inline void mmc_block_put_device( mmc_block_device_t dev ){	__ENTER0();		if ( dev ) {		int invalidate = FALSE;				__mmc_block_get_device( dev->rdev );		if ( dev->usage > 0 )			--dev->usage;				if ( dev->usage ) {			__mmc_block_put_device( dev );			goto out;		} else {			int host, slot;			mmc_card_t card = NULL;						invalidate = __mmc_block_check_card( dev->rdev );				if ( invalidate ) {				host = dev->card->ctrlr->slot;				slot = dev->card->slot;				if ( dev->card ) {					card = dev->card;					mmc_put_card( dev->card );					dev->card = NULL;				}			}			__mmc_block_put_device( dev );			if ( invalidate )				__mmc_block_invalidate_card( card, TRUE );		}			}out:	__LEAVE0();}static int mmc_block_open( struct inode *inode, struct file *file ){	int ret = -ENODEV;	mmc_block_device_t dev = NULL;		__ENTER0();	if ( !inode || !file )		goto error;		BLK_INC_USE_COUNT;		check_disk_change( inode->i_rdev );		dev = mmc_block_get_device( inode->i_rdev );	if ( !dev )		goto error;		dev = __mmc_block_get_device( inode->i_rdev );	if ( !dev )		goto error;		if ( file->f_mode & FMODE_WRITE ) { /* FIXME */		if ( dev->usage > 1 ) {			ret = -EBUSY;			__mmc_block_put_device( dev );			mmc_block_put_device( dev );			goto error;		}	}		__mmc_block_put_device( dev );		if ( file )		file->private_data = dev;	ret = 0;	goto out;error:	BLK_DEC_USE_COUNT;out:	__LEAVE( "ret=%d", ret );	return ret;}static int mmc_block_release( struct inode *inode, struct file *file ){	int ret = -EINVAL;	mmc_block_device_t dev = NULL;		__ENTER( "inode=0x%p file=0x%p rdev=(%x:%x)", inode, file,			inode ? MAJOR( inode->i_rdev ) : 0xff,			inode ? MINOR( inode->i_rdev ) : 0xff );	if ( !file && !inode )		goto error;		if ( file )		dev = file->private_data;	else		dev = __mmc_block_get_device( inode->i_rdev );	if ( !dev ) {		MMC_DEBUG( MMC_DEBUG_LEVEL0, "invalid device\n" );		goto error;	}		if ( file ) {		mmc_block_put_device( dev );		file->private_data = NULL;	} else {		int invalidate = FALSE;				if ( dev->usage > 0 )			--dev->usage;				if ( dev->usage ) {			__mmc_block_put_device( dev );			goto out;					} else {			int host, slot;			mmc_card_t card = NULL;						invalidate = __mmc_block_check_card( dev->rdev );				if ( invalidate ) {				host = dev->card->ctrlr->slot;				slot = dev->card->slot;				if ( dev->card ) {					card = dev->card;					mmc_put_card( dev->card );					dev->card = NULL;				}			}			__mmc_block_put_device( dev );			if ( invalidate )				__mmc_block_invalidate_card( card, TRUE );			}	}	out:	BLK_DEC_USE_COUNT;	ret = 0;error:	__LEAVE0();	return ret;}  static int mmc_block_check_disk_change( kdev_t rdev ){	int ret = 0;#if 0	mmc_block_device_t dev = &mmc_block_device[MINOR( rdev )];		__mmc_block_lock_device( rdev );	if ( !dev->card )		ret = 1;	__mmc_block_unlock_device( rdev );#else	ret = 1;#endif	return ret;}static int mmc_block_revalidate( kdev_t rdev ){	int ret = 1;	mmc_card_t card;	mmc_block_device_t dev;	kdev_t start = MMC_BLOCK_RAW_DEVICE( rdev );	int minor = MINOR( start );	int host, slot;	int i;		__ENTER0();	(void)mmc_update_card_stack( MINOR( start )>>MMC_MINOR_HOST_SHIFT );	__mmc_block_wrlock_devices();	dev = &mmc_block_device[minor];	host = dev->host;	slot = dev->slot;	if ( dev->card ) { /* card has not been changed actually */		__mmc_block_wrunlock_devices();

⌨️ 快捷键说明

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