📄 mmc_block.c
字号:
/* * 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 + -