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

📄 doc1000.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
字号:
/*======================================================================  $Id: doc1000.c,v 1.11 2000/11/24 13:43:16 dwmw2 Exp $======================================================================*/#include <linux/config.h>#include <linux/module.h>#include <asm/uaccess.h>#include <linux/types.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/ptrace.h>#include <linux/malloc.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/major.h>#include <linux/fs.h>#include <linux/ioctl.h>#include <asm/io.h>#include <asm/system.h>#include <asm/segment.h>#include <stdarg.h>#include <linux/delay.h>#include <linux/init.h>#include <linux/mtd/mtd.h>#include <linux/mtd/iflash.h>/* Parameters that can be set with 'insmod' */static u_long base              = 0xe0000;static int erase_timeout	= 10*HZ;	/* in ticks */static int retry_limit		= 4;		/* write retries */static u_long max_tries       	= 4096;		/* status polling */MODULE_PARM(base,"l");MODULE_PARM(erase_timeout, "i");MODULE_PARM(retry_limit, "i");MODULE_PARM(max_tries, "i");#define WINDOW_SIZE 0x2000#define WINDOW_MASK (WINDOW_SIZE - 1)#define PAGEREG_LO (WINDOW_SIZE)#define PAGEREG_HI (WINDOW_SIZE + 2)static struct mtd_info *mymtd;static struct timer_list flashcard_timer;#define MAX_CELLS		32#define MAX_FLASH_DEVICES       8/* A flash region is composed of one or more "cells", where we allow   simultaneous erases if they are in different cells */struct mypriv {	u_char *baseaddr;	u_short curpage;	u_char locked;	u_short numdevices;	u_char interleave;	struct erase_info *cur_erases;	wait_queue_head_t wq;	u_char devstat[MAX_FLASH_DEVICES];	u_long devshift;};static void flashcard_periodic(u_long data);static int flashcard_erase (struct mtd_info *mtd, struct erase_info *instr);static int flashcard_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);static int flashcard_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);static void flashcard_sync (struct mtd_info *mtd);static inline void resume_erase(volatile u_char *addr);static inline int suspend_erase(volatile u_char *addr);static inline int byte_write (volatile u_char *addr, u_char byte);static inline int word_write (volatile u_char *addr, __u16 word);static inline int check_write(volatile u_char *addr);static inline void block_erase (volatile u_char *addr);static inline int check_erase(volatile u_char *addr);#ifdef CONFIG_SMP#warning This is definitely not SMP safe. Lock the paging mechanism.#endifstatic u_char *pagein(struct mtd_info *mtd, u_long addr){  struct mypriv *priv=mtd->priv;  u_short page = addr >> 13;  priv->baseaddr[PAGEREG_LO] = page & 0xff;  priv->baseaddr[PAGEREG_HI] = page >> 8;  priv->curpage = page;    return &priv->baseaddr[addr & WINDOW_MASK];}void flashcard_sync (struct mtd_info *mtd){	struct mypriv *priv=mtd->priv;	flashcard_periodic((u_long) mtd);	printk("sync...");	if (priv->cur_erases)		interruptible_sleep_on(&priv->wq);	printk("Done.\n");}int flashcard_erase (struct mtd_info *mtd, struct erase_info *instr){	u_char *pageaddr;	struct mypriv *priv=mtd->priv;	struct erase_info **tmp=&priv->cur_erases;		if (instr->len != mtd->erasesize)		return -EINVAL;	if (instr->addr + instr->len > mtd->size)		return -EINVAL;	pageaddr=pagein(mtd,instr->addr);	instr->mtd = mtd;	instr->dev = instr->addr >> priv->devshift;	instr->cell = (instr->addr - (instr->dev << priv->devshift)) / mtd->erasesize;	instr->next = NULL;	instr->state = MTD_ERASE_PENDING;		while (*tmp)	{		tmp = &((*tmp) -> next);	}		*tmp = instr;	flashcard_periodic((u_long)mtd);	return 0;}int flashcard_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf){ 	u_char *pageaddr=pagein(mtd,from);	struct mypriv *priv=mtd->priv;	u_char device = from >> priv->devshift;	u_char cell = (int) (from - (device << priv->devshift)) / mtd->erasesize;	int ret = 0, timeron = 0;	if ((from & WINDOW_MASK) + len <= WINDOW_SIZE)		*retlen = len;	else		*retlen = WINDOW_SIZE - (from & WINDOW_MASK);	if (priv->devstat[device])	{				/* There is an erase in progress or pending for this device. Stop it */		timeron = del_timer(&flashcard_timer);				if (priv->cur_erases && priv->cur_erases->cell == cell) 					{			/* The erase is on the current cell. Just return all 0xff */ 			add_timer(&flashcard_timer);									printk("Cell %d currently erasing. Setting to all 0xff\n",cell);			memset(buf, 0xff, *retlen);			return 0;		}		if (priv->devstat[device] == MTD_ERASING)		{			ret = suspend_erase(pageaddr);			priv->devstat[device] = MTD_ERASE_SUSPEND;		       			if (ret) 			{				printk("flashcard: failed to suspend erase\n");				add_timer (&flashcard_timer);				return ret;			}		}	}	writew(IF_READ_ARRAY, (u_long)pageaddr & ~1);		ret = 0;	memcpy (buf, pageaddr, *retlen);		writew(IF_READ_CSR, (u_long)pageaddr & ~1);			if (priv->devstat[device] & MTD_ERASE_SUSPEND)	{		resume_erase(pageaddr);		priv->devstat[device]=MTD_ERASING;	}	if (timeron) add_timer (&flashcard_timer);			return ret;}int flashcard_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf){	struct mypriv *priv = (struct mypriv *)mtd->priv; 	u_char *endaddr, *startaddr;	register u_char *pageaddr;	u_char device = to >> priv->devshift;/*	jiffies_t oldj=jiffies;*/	int ret;	while (priv->devstat[device])	{		flashcard_sync(mtd);	}	if ((to & WINDOW_MASK) + len <= WINDOW_SIZE)		*retlen = len;	else		*retlen = WINDOW_SIZE - (to & WINDOW_MASK);		pageaddr = pagein(mtd, to);	startaddr = (u_char *)((u_long) pageaddr & ~1);	endaddr = pageaddr+(*retlen);	/* Set up to read */	writew(IF_READ_CSR, startaddr);		/* Make sure it's aligned by reading the first byte if necessary */	if (to & 1)	{		/* Unaligned access */		u_char cbuf;		cbuf = *buf;		if (!((u_long)pageaddr & 0xf))			schedule();					ret = byte_write(pageaddr, cbuf);		if (ret) return ret;		pageaddr++; buf++;	}	for ( ; pageaddr + 1 < endaddr; buf += 2, pageaddr += 2)		{			/* if ((u_long)pageaddr & 0xf) schedule();*/						ret = word_write(pageaddr, *(__u16 *)buf);			if (ret) 				return ret;		}		if (pageaddr != endaddr)	{		/* One more byte to write at the end. */		u_char cbuf;		cbuf = *buf;		ret = byte_write(pageaddr, cbuf);		if (ret) return ret;	}	return check_write(startaddr);/*	printk("Time taken in flashcard_write: %lx jiffies\n",jiffies - oldj);*/}/*====================================================================*/static inline int byte_write (volatile u_char *addr, u_char byte){	register u_char status; 	register u_short i = 0;  	 	do {		status = readb(addr);		if (status & CSR_WR_READY)		{			writeb(IF_WRITE & 0xff, addr);			writeb(byte, addr);			return 0;		}		i++;	} while(i < max_tries);			printk(KERN_NOTICE "flashcard: byte_write timed out, status 0x%x\n",status);	return -EIO;}static inline int word_write (volatile u_char *addr, __u16 word){	register u_short status;	register u_short i = 0;		do {		status = readw(addr);		if ((status & CSR_WR_READY) == CSR_WR_READY)		{			writew(IF_WRITE, addr);			writew(word, addr);			return 0;		}		i++;	} while(i < max_tries);			printk(KERN_NOTICE "flashcard: word_write timed out at %p, status 0x%x\n", addr, status);	return -EIO;}static inline void block_erase (volatile u_char *addr){	writew(IF_BLOCK_ERASE, addr);	writew(IF_CONFIRM, addr);}static inline int check_erase(volatile u_char *addr){	__u16 status;	/*	writew(IF_READ_CSR, addr);*/	status = readw(addr);		if ((status & CSR_WR_READY) != CSR_WR_READY)		return -EBUSY;		if (status & (CSR_ERA_ERR | CSR_VPP_LOW | CSR_WR_ERR)) 	{		printk(KERN_NOTICE "flashcard: erase failed, status 0x%x\n",		       status);		return -EIO;	}		return 0;}static inline int suspend_erase(volatile u_char *addr){	__u16 status;	u_long i = 0;		writew(IF_ERASE_SUSPEND, addr);	writew(IF_READ_CSR, addr);		do {		status = readw(addr);		if ((status & CSR_WR_READY) == CSR_WR_READY)			return 0;		i++;	} while(i < max_tries);	printk(KERN_NOTICE "flashcard: suspend_erase timed out, status 0x%x\n", status);	return -EIO;}static inline void resume_erase(volatile u_char *addr){	__u16 status;		writew(IF_READ_CSR, addr);	status = readw(addr);		/* Only give resume signal if the erase is really suspended */	if (status & CSR_ERA_SUSPEND)		writew(IF_CONFIRM, addr);}static inline void reset_block(volatile u_char *addr){	u_short i;	__u16 status;	writew(IF_CLEAR_CSR, addr);	for (i = 0; i < 100; i++) {		writew(IF_READ_CSR, addr);		status = readw(addr);		if (status != 0xffff) break;		udelay(1000);	}	writew(IF_READ_CSR, addr);}static inline int check_write(volatile u_char *addr){	u_short status, i = 0;		writew(IF_READ_CSR, addr);		do {		status = readw(addr);		if (status & (CSR_WR_ERR | CSR_VPP_LOW))		{			printk(KERN_NOTICE "flashcard: write failure at %p, status 0x%x\n", addr, status);			reset_block(addr);			return -EIO;		}		if ((status & CSR_WR_READY) == CSR_WR_READY)			return 0;		i++;	} while (i < max_tries);	printk(KERN_NOTICE "flashcard: write timed out at %p, status 0x%x\n", addr, status);	return -EIO;}/*====================================================================*/static void flashcard_periodic(unsigned long data){	register struct mtd_info *mtd = (struct mtd_info *)data;	register struct mypriv *priv = mtd->priv;	struct erase_info *erase = priv->cur_erases;	u_char *pageaddr;	del_timer (&flashcard_timer);	if (!erase)		return;	pageaddr = pagein(mtd, erase->addr);		if (erase->state == MTD_ERASE_PENDING)	{		block_erase(pageaddr);		priv->devstat[erase->dev] = erase->state = MTD_ERASING;		erase->time = jiffies;		erase->retries = 0;	}	else if (erase->state == MTD_ERASING)	{		/* It's trying to erase. Check whether it's finished */		int ret = check_erase(pageaddr);		if (!ret)		{			/* It's finished OK */			priv->devstat[erase->dev] = 0;			priv->cur_erases = erase->next;			erase->state = MTD_ERASE_DONE;			if (erase->callback)				(*(erase->callback))(erase);			else				kfree(erase);		}		else if (ret == -EIO)		{			if (++erase->retries > retry_limit)			{				printk("Failed too many times. Giving up\n");				priv->cur_erases = erase->next;				priv->devstat[erase->dev] = 0;				erase->state = MTD_ERASE_FAILED;				if (erase->callback)					(*(erase->callback))(erase);				else					kfree(erase);			}			else				priv->devstat[erase->dev] = erase->state = MTD_ERASE_PENDING;		}		else if (erase->time + erase_timeout < jiffies)		{			printk("Flash erase timed out. The world is broken.\n");			/* Just ignore and hope it goes away. For a while, read ops will give the CSR			   and writes won't work. */			priv->cur_erases = erase->next;			priv->devstat[erase->dev] = 0;			erase->state = MTD_ERASE_FAILED;			if (erase->callback)					(*(erase->callback))(erase);				else					kfree(erase);		}	}	if (priv->cur_erases)	{		flashcard_timer.expires = jiffies + HZ;		add_timer (&flashcard_timer);	}	else 		wake_up_interruptible(&priv->wq);}#if defined (MODULE) && LINUX_VERSION_CODE < 0x20211#define init_doc1000 init_module#define cleanup_doc1000 cleanup_module#endifint __init init_doc1000(void){	struct mypriv *priv;	if (!base)	{		printk(KERN_NOTICE "flashcard: No start address for memory device.\n");		return -EINVAL;	}	mymtd  = kmalloc(sizeof(struct mtd_info), GFP_KERNEL);	if (!mymtd)	{		printk(KERN_NOTICE "physmem: Cannot allocate memory for new MTD device.\n");		return -ENOMEM;	}	memset(mymtd,0,sizeof(struct mtd_info));	mymtd->priv = (void *) kmalloc (sizeof(struct mypriv), GFP_KERNEL);	if (!mymtd->priv)	  {	    kfree(mymtd);	    printk(KERN_NOTICE "physmem: Cannot allocate memory for new MTD device's private data.\n");	    return -ENOMEM;	  }		priv=mymtd->priv;	init_waitqueue_head(&priv->wq);	memset (priv,0,sizeof(struct mypriv));	priv->baseaddr = phys_to_virt(base);	priv->numdevices = 4;		mymtd->name = "M-Systems DiskOnChip 1000";	mymtd->size = 0x100000;	mymtd->flags = MTD_CLEAR_BITS | MTD_ERASEABLE;        mymtd->erase = flashcard_erase;	mymtd->point = NULL;	mymtd->unpoint = NULL;	mymtd->read = flashcard_read;	mymtd->write = flashcard_write;	mymtd->sync = flashcard_sync;	mymtd->erasesize = 0x10000;	//	mymtd->interleave = 2;	priv->devshift =  24;	mymtd->type = MTD_NORFLASH;		if (add_mtd_device(mymtd))	{		printk(KERN_NOTICE "MTD device registration failed!\n");		kfree(mymtd->priv);		kfree(mymtd);		return -EAGAIN;	}		init_timer(&flashcard_timer);	flashcard_timer.function = flashcard_periodic;	flashcard_timer.data = (u_long)mymtd;	return 0;}static void __init cleanup_doc1000(void){	kfree (mymtd->priv);	del_mtd_device(mymtd);	kfree(mymtd);}#if LINUX_VERSION_CODE >= 0x20211module_init(init_doc1000);module_exit(cleanup_doc1000);#endif

⌨️ 快捷键说明

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