📄 mmc_core.c
字号:
#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 + -