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

📄 ssfdc.c

📁 nandflash k9g808u0a在pxa270的驱动,由于pxa270没有nandflash接口
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  drivers/mtd/ssfdc.c * *  Copyright (C) 2003 Simon Haynes (simon@baydel.con) *                     Baydel Ltd * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * version 2.1 as published by the Free Software Foundation. * * This module provides a translation layer, via mtd, for smart * media card access. It essentially enables the possibility  * of using cards on a hardware which does not have a hardware translation * layer and interchanging them with hardware that does ie: PC card readers * * I had to write this module for a specific task and in a short timeframe * for this reason I have imposed some restricions to make the job easier. * * To build an compile the driver I added the following lines * to mtd/Config.in * *  dep_tristate '  SSFDC support' CONFIG_SSFDC $CONFIG_MTD * * to /mtd/Makefile * * obj-$(CONFIG_SSFDC)             += ssfdc.o * * and compiled the kernel via the usual methods. * * I am sure that there are many problems I don't know about but here are * some that I know of * * Currently the driver uses MAJOR number 44 which I think is FTL or NFTL * I did this because I wanted a static number and I didn't know * how to go about getting a new one. This needs addressing * The dev nodes required are like standard. I only use minor 0 * (/dev/ssfdca), and minor 1 (/dev/ssfdca1). * You should be able to run fdisk on /dev/ssfdca and the first partition * is /dev/ssfdca1. There is no working code in the module for changing the * SMC and rebuilding the maps so the card should not be changed once the * module is loaded. At present I only look for 1 partition. But this is a * small commented hack. * * There is no support cards which do not have a 512 byte page size with 16 * bytes of oob and an erase size of 16K. * There are no checks for this at present. In addition the MTD reported size * must be 16M or a multiple. * * Code to handle multiple partitions or multiple cards is incomplete * Need to allocate data buffer and oob buffer on a per partition basis. * As I am only concerned with one partition I will do this if I ever need to. * The cached physical address variable also needs this attention. * * Recently I have started to work on media changes. Some of this is specific * to my hardware and you will see references to pt_ssfdc_smc and smc_status. * This code is incomplete and does not work. I have commented it for the moment * but it should give an indication of what I think is required. Maybe there is * something it mtd that can help * * 17th August 2004 MHB * * Following updating CVS I noticed some single bit data corruption. I believe * that this was down to the fact that I was using mtd->read instead of mtd->read_ecc * and that mtd->read was applying it's own error corretion from the wrong ecc bytes * I have now corrected this. * * During this time I noticed that while in allocate new I only seem to look for blocks * in 1 zone. So this limits the partition size to 16MB with all the other SMC size * restrictions*/#include <linux/config.h>#include <linux/types.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/slab.h>#include <linux/vmalloc.h>#include <linux/mtd/mtd.h>#include <linux/mtd/blktrans.h>#include <linux/mtd/nand_ecc.h>#include <linux/sched.h>#include <linux/ptrace.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/major.h>#include <linux/ioctl.h>#include <linux/hdreg.h>#include <linux/list.h>#include <asm/semaphore.h>#include <asm/uaccess.h>#if (LINUX_VERSION_CODE >= 0x20100)#include <linux/vmalloc.h>#endif#if (LINUX_VERSION_CODE >= 0x20303)#include <linux/blkpg.h>#endif#include <asm/semaphore.h>#define SSFDC_FORMAT 1#define PDEBUG(fmt, args...)#define BLK_INC_USE_COUNT MOD_INC_USE_COUNT#define BLK_DEC_USE_COUNT MOD_DEC_USE_COUNT#if (LINUX_VERSION_CODE < 0x20320)#define BLK_DEFAULT_QUEUE(n)    blk_dev[n].request_fn#define blk_init_queue(q, req)  q = (req)#define blk_cleanup_queue(q)    q = NULL#define request_arg_t           void#else#define request_arg_t           request_queue_t *q#endif#define TRUE 1#define FALSE 0#define SSFDC_MAJOR	44#define MAJOR_NR		SSFDC_MAJOR#define DEVICE_NAME		"ssfdc"#define DEVICE_REQUEST		do_ssfdc_request#define DEVICE_ON(device)#define DEVICE_OFF(device)#include <linux/blk.h>#include "/home/simon/ebony/dbwhatu/dbwhatu/smccontrol.h"#define ZONE_SIZE 		(16 * 1024 * 1024)#define SMC_BLOCK_SIZE 		(16 * 1024)#define SECTOR_SIZE 		512#define SECTORS_PER_ZONE  	(ZONE_SIZE / SECTOR_SIZE)#define BLOCKS_PER_ZONE	    	(ZONE_SIZE / SMC_BLOCK_SIZE)#define SECTORS_PER_BLOCK	(SMC_BLOCK_SIZE / SECTOR_SIZE)#define OOB_SIZE		16#define MAX_DEVICES 	4#define MAX_PARTITIONS 	8#define PARTITION_BITS 	3#define MAX_ZONES 	8int ssfdc_major = SSFDC_MAJOR;unsigned int ssfdc_cached = 0xFFFFFFFF;static unsigned char ssfdc_scratch[16384];static unsigned char ssfdc_buffer[16];static unsigned char ssfdc_ffoob_buf[OOB_SIZE * SECTORS_PER_BLOCK];static unsigned char ssfdc_oob_buf[OOB_SIZE * SECTORS_PER_BLOCK];static struct nand_oobinfo ssfdc_ffoob_info = {	.useecc = 0,};typedef struct minor_t {	atomic_t open;	int cached;	unsigned char * pt_data;	unsigned char * pt_oob;} minor_t;typedef struct partition_t {	int type;    	struct mtd_info	*mtd;    	int count;	unsigned int *zone;	unsigned int zoneCount;	minor_t minor[MAX_PARTITIONS];	unsigned int last_written[MAX_ZONES];} partition_t;partition_t SMCParts[MAX_DEVICES];static unsigned char ssfdc_ecc[] = {14, 13, 15, 9, 8, 10};static struct hd_struct ssfdc_hd[MAX_DEVICES * MAX_PARTITIONS];static int ssfdc_sizes[MAX_DEVICES * MAX_PARTITIONS];static int ssfdc_blocksizes[MAX_DEVICES * MAX_PARTITIONS];smc_control * pt_ssfdc_smc;static struct gendisk ssfdc_gendisk = {    major:		SSFDC_MAJOR,    major_name:		"ssfdc",    minor_shift:	PARTITION_BITS,    max_p:		MAX_PARTITIONS,    part:		ssfdc_hd,    sizes:		ssfdc_sizes,};static int	ssfdc_ioctl(struct inode *inode, struct file *file, u_int cmd, u_long arg);static int 	ssfdc_open(struct inode *inode, struct file *file);static int 	ssfdc_close(struct inode *inode, struct file *file);static int 	ssfdc_write(partition_t *part, caddr_t buffer, u_long sector, u_long nblocks);static int 	ssfdc_read(partition_t *part, caddr_t buffer, u_long sector, u_long nblocks);static int 	ssfdc_physical(partition_t * pt_smcpart, int zone, int block);static int 	ssfdc_erase(partition_t *pt_smcpart, unsigned int offset);static int 	ssfdc_read_partitions(partition_t * pt_smcpart);static void 	ssfdc_notify_add(struct mtd_info *mtd);static void 	ssfdc_notify_remove(struct mtd_info *mtd);static void 	ssfdc_tables(partition_t * pt_smcpart);static int 	ssfdc_sector_blank(partition_t * pt_smcpart, int sc);static int  	ssfdc_allocate_new(partition_t * pt_smcpart, int zone);int 		ssfdc_parity(int number);static void 	ssfdc_erase_callback(struct erase_info *erase);static DECLARE_WAIT_QUEUE_HEAD(ssfdc_wq);static struct mtd_notifier ssfdc_notifier = {	add:		ssfdc_notify_add,	remove:		ssfdc_notify_remove,};static struct block_device_operations ssfdc_fops = {    open:	ssfdc_open,    release:	ssfdc_close,    ioctl:	ssfdc_ioctl,};                                               static struct semaphore ssfdc_semaphore;static void ssfdc_notify_add(struct mtd_info *mtd) {		if(mtd->index >= 1) return;   // Hack to limit SSFDC to 1 partition	if( ((mtd->size % ZONE_SIZE) != 0) && (mtd->size < (ZONE_SIZE * MAX_ZONES)) ){		PDEBUG("ssfdc_notify_add : mtd partition %d is not modulus 16M, not SSFDC\n", mtd->index);		}	else {		memset((void *)&SMCParts[mtd->index].type, 0, sizeof(partition_t));			SMCParts[mtd->index].mtd = mtd;		SMCParts[mtd->index].count = mtd->index;		SMCParts[mtd->index].type = 1;		SMCParts[mtd->index].zoneCount = mtd->size / ZONE_SIZE;		SMCParts[mtd->index].zone = kmalloc(SMCParts[mtd->index].zoneCount * 8192, GFP_KERNEL);				if(!SMCParts[mtd->index].zone) {			printk(KERN_NOTICE "ssfdc_notify_add : mtd partition %d, failed to allocate mapping table\n", mtd->index);			SMCParts[mtd->index].type = 0;		}		else {			memset((void *)SMCParts[mtd->index].zone, 0xFF, SMCParts[mtd->index].zoneCount * 8192);		}			ssfdc_read_partitions((partition_t *)&SMCParts[mtd->index].type);	}	return;}static int ssfdc_read_partitions(partition_t * pt_smcpart) {	int whole, i, j, size;//=printk("ssfdc_read_partitions : start\n");	for(i=0; i<MAX_PARTITIONS; i++)	   	if ((atomic_read(&pt_smcpart->minor[i].open) > 1)) {//=printk("ssfdc_read_partitions : part %d busy\n", i);    		return -EBUSY;   		}//=printk("ssfdc_read_partitions : tables start\n");	ssfdc_tables(pt_smcpart);//=printk("ssfdc_read_partitions : tables end\n");   	whole = pt_smcpart->count << PARTITION_BITS;         		   	j = MAX_PARTITIONS - 1;   	while (j-- > 0) {		if (ssfdc_hd[whole+j].nr_sects > 0) {    			kdev_t rdev = MKDEV(SSFDC_MAJOR, whole+j);    			invalidate_device(rdev, 1);		}		ssfdc_hd[whole+j].start_sect = 0;		ssfdc_hd[whole+j].nr_sects = 0;   	}	size = (((pt_smcpart->mtd->size / 16384) * 1000) / 1024) * 32;	size /= (0x8 * 0x20);	size = size * (0x8 * 0x20);//=printk("ssfdc_read_partitions : register start\n");    register_disk(&ssfdc_gendisk, whole >> PARTITION_BITS, MAX_PARTITIONS,		  &ssfdc_fops, size);//=printk("ssfdc_read_partitions : register end\n");    	return 0;}static void ssfdc_notify_remove(struct mtd_info *mtd) {int i, j, whole;	i=mtd->index;	whole = i << PARTITION_BITS;   	if(SMCParts[i].mtd == mtd) {       		if(SMCParts[i].zone)kfree(SMCParts[i].zone);		memset((void *)&SMCParts[i].type, 0, sizeof(partition_t));    		for (j = 0; j < MAX_PARTITIONS; j++) {			if (ssfdc_hd[whole+j].nr_sects > 0) {		   		ssfdc_hd[whole+j].start_sect = 0;	   			ssfdc_hd[whole+j].nr_sects=0;			}    		}		return;	}	return;}static int ssfdc_ioctl(struct inode *inode, struct file *file,		u_int cmd, u_long arg) {    int minor = MINOR(inode->i_rdev);    int ret = -EINVAL;    partition_t * pt_smcpart = (partition_t *)&SMCParts[(minor & ~(MAX_PARTITIONS -1)) >> PARTITION_BITS].type;    struct hd_geometry geo;    int size;/*	unsigned char smc_status;  	smc_status = in_8((void *)&pt_ssfdc_smc->smc_status);  	if(!(smc_status & SMC_PRESENT)) {		printk("ssfdc : media not present\n");		ret = 1;		goto ssfdc_ioctl_error;	}  	if(smc_status & SMC_CHANGED) {   		out_8((void *)&pt_ssfdc_smc->smc_status, smc_status);		if(minor & ((1<< PARTITION_BITS) - 1)) return -ENOTTY;			ssfdc_read_partitions(pt_smcpart);		printk("ssfdc : media change\n");  	}*/	switch(cmd) {	    case HDIO_GETGEO:		   	memset(&geo, 0, sizeof(geo));			size = (((pt_smcpart->mtd->size / 16384) * 1000) / 1024) * 32;			size /= (0x8 * 0x20);			geo.heads = 0x8;			geo.sectors = 0x20;			geo.cylinders = size;			geo.start = ssfdc_hd[minor].start_sect;

⌨️ 快捷键说明

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