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

📄 nand.c

📁 linux下nand flash驱动
💻 C
字号:
#include <linux/sched.h>
#include <linux/kernel.h>
#include <asm/MC68VZ328.h>
#include <asm/segment.h>
#include <linux/fs.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/tqueue.h>
#include <linux/interrupt.h>
#include <linux/hdreg.h>

#include "NandFlash.h"

#define MAJOR_NR	nandmajor
int nandmajor=97;

#define DEVICE_NR(device)	MINOR(device)
#define DEVICE_NAME	"nandflish"
#define DEVICE_NO_RANDOM

/* end_request函数在结束后调用这个宏 */
#define DEVICE_OFF(d)

#include <linux/blk.h>



int nand_major;

int nand_devs,nand_rahead,nand_size,nand_blksize,nand_hardsect;

int nand_open (struct inode *inode, struct file *filp)
{
//	printk("nanddisk is opened!\n");
	return 0;          /* success */
}


/*
 * The ioctl() implementation
 */

int nand_ioctl (struct inode *inode, struct file *filp,
                 unsigned int cmd, unsigned long arg)
{
	int err, size;
	struct hd_geometry *geo = (struct hd_geometry *)arg;
	
	//    PDEBUG("ioctl 0x%x 0x%lx\n", cmd, arg);
	//	printk("ioctl!!!!!!!!!!!!!!!\n");
	
	switch(cmd)
	{
	
	case BLKGETSIZE:
		//        printk("i/o control:ask the nand disk size\n");
		/* Return the device size, expressed in sectors */
		if (!arg) return -EINVAL; /* NULL pointer: not valid */
		err=verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
		if (err) return err;
		put_user ( nand_size,(long *) arg);
		return 0;
	
	case BLKFLSBUF: /* flush */
		//        printk("i/o control:demand to flush buffer\n");
		if (!suser()) return -EACCES; /* only root */
		fsync_dev(inode->i_rdev);
		invalidate_buffers(inode->i_rdev);
		return 0;
	
	case BLKRAGET: /* return the readahead value */
		//      	printk("i/o control:get the ahead\n");
		if (!arg)  return -EINVAL;
		err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
		if (err) return err;
		put_user(read_ahead[MAJOR(inode->i_rdev)],(long *) arg);
		return 0;
	
	case BLKRASET: /* set the readahead value */
		//      	printk("i/o control:set the ahead\n");
		if (!suser()) return -EACCES;
		if (arg > 0xff) return -EINVAL; /* limit it */
		read_ahead[MAJOR(inode->i_rdev)] = arg;
		return 0;
	
	case BLKRRPART: /* re-read partition table: can't do it */
	return -EINVAL;
	
	RO_IOCTLS(inode->i_rdev, arg); /* the default RO operations */
	
	case HDIO_GETGEO:
		/*
		* get geometry: we have to fake one...  trim the size to a
		* multiple of 64 (32k): tell we have 16 sectors, 4 heads,
		* whatever cylinders. Tell also that data starts at sector. 4.
		*/
		//        printk("i/o control:get the general information\n");
		size = nand_size * 2;
		size &= ~0x3f; /* multiple of 64 */
		if (geo==NULL) 
		return -EINVAL;
		err = verify_area(VERIFY_WRITE, geo, sizeof(*geo));
		if (err)
		return err;
		put_user(1024, &geo->cylinders);
		put_user(        2, &geo->heads);
		put_user(       32, &geo->sectors);
		put_user(        0, &geo->start);
		return 0;
	}
	
	return -EINVAL; /* unknown command */
}

void nand_release(struct inode *inode,struct file *filp)
{
	fsync_dev(inode->i_rdev);
	invalidate_buffers(inode->i_rdev);
}

/*
 * The file operations
 */

struct file_operations nand_fops = {
    NULL,          /* lseek: default */
    block_read,
    block_write,
    NULL,          /* spull_readdir */
    NULL,          /* spull_select */
    nand_ioctl,
    NULL,          /* spull_mmap */
    nand_open,
    nand_release,
    block_fsync,
    NULL,          /* spull_fasync */
    NULL,//spull_check_change,
    NULL,//spull_revalidate
};


/*
 * Block-driver specific functions
 */

void nand_request(void)
{
	unsigned long tmp;
	while(1)
	{
        	INIT_REQUEST;
//		printk("request!!!!!!!!!!!!!!!!!!\n");
		if (DEVICE_NR(CURRENT_DEV) > 1)
		{
			printk("device number error!\n");
			end_request(0);
			continue;
		}

//		cli();
        	switch(CURRENT->cmd)
        	{
        	case READ:
//        		printk("READ:start:%d,count:%d\n",CURRENT->sector,CURRENT->current_nr_sectors);
			cli();
			if (ReadSector1(CURRENT->buffer,CURRENT->sector,CURRENT->current_nr_sectors))
        			end_request(0);
			sti();

			break;
		case WRITE:
//			printk("WRITE:start:%d,count:%d\n",CURRENT->sector,CURRENT->current_nr_sectors);
			cli();
			if(WriteSector1(CURRENT->buffer,CURRENT->sector,CURRENT->current_nr_sectors))
        			end_request(0);
			sti();
			break;
		default:
			end_request(0);
			continue;
        	}
//		sti();

        	end_request(1); /* success */
        }
}



int init_nand(void)
{
	int result;
	/*
	 * Copy the (static) cfg variables to public prefixed ones to allow
	 * snoozing with a debugger.
	 */

	nand_major    = 97;
	nand_devs     = 1;
	nand_rahead   = 16;		// 提前读取的扇区数
	nand_size     = 32768;	// nandflash的大小(以KB为单位)
	nand_blksize  = 512;		// 块大小(以字节计)
	nand_hardsect = 512;		// 扇区大小(以字节计)


	/*
	 * Register your major, and accept a dynamic number
	 */
	result = register_blkdev(nand_major, "nand", &nand_fops);
	if (result < 0)
	{
		printk("#####################################################\n");
		printk(KERN_WARNING "sbull: can't get major %d\n",nand_major);
		return result;
	}

	/*
	* Assign the other needed values: request, rahead, size, blksize,
	* hardsect. All the minor devices feature the same value.
	* Note that `sbull' defines all of them to allow testing non-default
	* values. A real device could well avoid setting values in global
	* arrays if it uses the default values.
	*/
	InitNandFlash();
	printk("Samsung K9F5608U0A NandFlash Support. (E-World Technology Ltd.)\n");

	blk_dev[nand_major].request_fn = nand_request;
	read_ahead[nand_major] = nand_rahead;

	blk_size[nand_major] = &nand_size;

	blksize_size[nand_major] = &nand_blksize;

	hardsect_size[nand_major] = &nand_hardsect;
    
	return 0; /* succeed */
}

⌨️ 快捷键说明

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