📄 nand.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 + -