分类: 服务器与存储
2006-03-20 15:21:07
All are simple indeed.You just create mtd_partition, map_info(implements all functions),call do_map_probe(type,map_info) which will return struct mtd_info。Then call add_mtd_partitions(struct mtd_info *, struct mtd_partition *, int) to add partitions。
Ok,that's all..
for more details ,you can read the files s
#include
/* Partition definition structure:
*
* An array of struct partition is passed along with a MTD object to
* add_mtd_partitions() to create them.
* For each partition, these fields are available:
* name: string that will be used to label the partition's MTD device.
* size: the partition size; if defined as MTDPART_SIZ_FULL, the partition
* will extend to the end of the master MTD device.
* offset: absolute starting position within the master MTD device; if
* defined as MTDPART_OFS_APPEND, the partition will start where the previous one ended; if MTDPART_OFS_NXTBLK, at the next erase block.
* mask_flags: contains flags that have to be masked (removed) from the
* master MTD flag set for the corresponding MTD partition.
* For example, to force a read-only partition, simply adding MTD_WRITEABLE to the mask_flags will do the trick.
*
* Note: writeable partitions require their size and offset be
* erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK).
*/
struct mtd_partition {
char *name; /* identifier string */
u_int32_t size; /* partition size */
u_int32_t offset; /* offset within the master MTD space */
u_int32_t mask_flags; /* master MTD flags to mask out for this partition */
struct mtd_info **mtdp; /* pointer to store the MTD object */
}
#define MTDPART_OFS_NXTBLK (-2)
#define MTDPART_OFS_APPEND (-1)
#define MTDPART_SIZ_FULL (0)
int add_mtd_partitions(struct mtd_info *, struct mtd_partition *, int);//int表示几个分区, sizeof(s
int del_mtd_partitions(struct mtd_info *);
/*defined in include/linux/mtd/map.h*/
/* The map stuff is very simple. You fill in your struct map_info with
a handful of routines for accessing the device, making sure they handle
paging etc. correctly if your device needs it. Then you pass it off
to a chip driver which deals with a mapped device - generally either
do_cfi_probe() or do_ram_probe(), either of which will return a
struct mtd_info if they liked what they saw. At which point, you
fill in the mtd->module with your own module address, and register
it.
The mtd->priv field will point to the struct map_info, and any further
private data required by the chip driver is linked from the
mtd->priv->fldrv_priv field. This allows the map driver to get at
the destructor function map->fldrv_destroy() when it's tired
of living.
*/
struct map_info {
char *name;
unsigned long size;
int buswidth; /* in octets */
__u8 (*read8)(struct map_info *, unsigned long);
__u16 (*read16)(struct map_info *, unsigned long);
__u32 (*read32)(struct map_info *, unsigned long);
__u64 (*read64)(struct map_info *, unsigned long);
/* If it returned a 'long' I'd call it readl.
* It doesn't.
* I won't.
* dwmw2 */
void (*copy_from)(struct map_info *, void *, unsigned long, ssize_t);
void (*write8)(struct map_info *, __u8, unsigned long);
void (*write16)(struct map_info *, __u16, unsigned long);
void (*write32)(struct map_info *, __u32, unsigned long);
void (*write64)(struct map_info *, __u64, unsigned long);
void (*copy_to)(struct map_info *, unsigned long, const void *, ssize_t);
void (*set_vpp)(struct map_info *, int);
/* We put these two here rather than a single void *map_priv,
because we want mappers to be able to have quickly-accessible
cache for the 'currently-mapped page' without the _extra_
redirection that would be necessary. If you need more than
two longs, turn the second into a pointer. dwmw2 */
unsigned long map_priv_1;
unsigned long map_priv_2;
void *fldrv_priv;
struct mtd_chip_driver *fldrv;
};
struct mtd_chip_driver {
struct mtd_info *(*probe)(struct map_info *map);
void (*destroy)(struct mtd_info *);
struct module *module;
char *name;
struct list_head list;
};
struct mtd_info *do_map_probe(const char *name, struct map_info *map);
/*defined in include/linux/mtd/mtd.h*/
struct mtd_info {
u_char type;
u_int32_t flags;
u_int32_t size; // Total size of the MTD
/* "Major" erase size for the device. Na飗e users may take this
* to be the only erase size available, or may use the more detailed
* information below if they desire
*/
u_int32_t erasesize;
u_int32_t oobblock; // Size of OOB blocks (e.g. 512)
u_int32_t oobsize; // Amount of OOB data per block (e.g. 16)
u_int32_t ecctype;
u_int32_t eccsize;
// Kernel-only stuff starts here.
char *name;
int index;
/* Data for variable erase regions. If numeraseregions is zero,
* it means that the whole device has erasesize as given above.
*/
int numeraseregions;
struct mtd_erase_region_info *eraseregions;
/* This really shouldn't be here. It can go away in 2.5 */
u_int32_t bank_size;
struct module *module;
int (*erase) (struct mtd_info *mtd, struct erase_info *instr);
/* This stuff for eXecute-In-Place */
int (*point) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char **mtdbuf);
/* We probably shouldn't allow XIP if the unpoint isn't a NULL */
void (*unpoint) (struct mtd_info *mtd, u_char * addr);
int (*read) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
int (*write) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
int (*read_ecc) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf, u_char *eccbuf);
int (*write_ecc) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf, u_char *eccbuf);
int (*read_oob) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
int (*write_oob) (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf);
/*
* Methods to access the protection register area, present in some
* flash devices. The user data is one time programmable but the
* factory data is read only.
*/
int (*read_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
int (*read_fact_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
/* This function is not yet implemented */
int (*write_user_prot_reg) (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf);
/* iovec-based read/write methods. We need these especially for NAND flash,
with its limited number of write cycles per erase.
NB: The 'count' parameter is the number of _vectors_, each of
which contains an (ofs, len) tuple.
*/
int (*readv) (struct mtd_info *mtd, struct iovec *vecs, unsigned long count, loff_t from, size_t *retlen);
int (*writev) (struct mtd_info *mtd, const struct iovec *vecs, unsigned long count, loff_t to, size_t *retlen);
/* Sync */
void (*sync) (struct mtd_info *mtd);
/* Chip-supported device locking */
int (*lock) (struct mtd_info *mtd, loff_t ofs, size_t len);
int (*unlock) (struct mtd_info *mtd, loff_t ofs, size_t len);
/* Power Management functions */
int (*suspend) (struct mtd_info *mtd);
void (*resume) (struct mtd_info *mtd);
void *priv;
};
/*
* Normal mappings of chips on Samsung s
*/
#include
#include
#include
#include
#include
#include
#include
#include
#define WINDOW_ADDR 0x01000000 //禄霉
#define WINDOW_SIZE 0x01600000 //flash麓贸
#define BUSWIDTH 2
/*defined in include/linux/mtd/mtd.h*/
static struct mtd_info *mymtd;
__u8 s
{
return readb(map->map_priv_1 + ofs);
}
__u16 s
{
return readw(map->map_priv_1 + ofs);
}
__u32 s
{
return readl(map->map_priv_1 + ofs);
}
void s
{
memcpy(to, (void *)(map->map_priv_1 + from), len);
}
void s
{
writeb(d, map->map_priv_1 + adr);
}
void s
{
writew(d, map->map_priv_1 + adr);
}
void s
{
writel(d, map->map_priv_1 + adr);
}
void s
{
memcpy((void *)(map->map_priv_1 + to), from, len);
}
/*defined in include/linux/mtd/map.h*/
struct map_info s
name: "s
size: WINDOW_SIZE,
buswidth: BUSWIDTH,
read8: s
read16: s
read32: s
copy_from: s
write8: s
write16: s
write32: s
copy_to: s
/* We put these two here rather than a single void *map_priv,
because we want mappers to be able to have quickly-accessible
cache for the 'currently-mapped page' without the _extra_
redirection that would be necessary. If you need more than
two longs, turn the second into a pointer. dwmw2 */
map_priv_1: WINDOW_ADDR,
map_priv_2: -1,
};
//脪脧脢路脰酶脠拢卢碌卤然要赂霉脳录潞碌脛猫确露篓脕
static struct mtd_partition s
{
name: "reserved for bootloader",
size: 0x040000,
offset: 0x0,
mask_flags: MTD_WRITEABLE,
},
{
name: "reserved for kernel",
size: 0x0100000,
offset: 0x040000,
mask_flags: MTD_WRITEABLE,
},
{
name: "reserved for ramdisk",
size: 0x400000,
offset: 0x140000,
mask_flags: MTD_WRITEABLE,
},
{
name: "jffs2(
size: 0x700000,
offset: 0x800000,
},
{
name: "cramfs(
size:0x
offset:0x540000,
}
};
int __init init_s
{
printk(KERN_NOTICE "s
/*get line addr from physical addr*/
s
//printk("0\n");
if (!s
printk("Failed to ioremap/n");
return -EIO;
}
//printk("1\n");
mymtd = do_map_probe("jedec_probe", &s
if (!mymtd)
mymtd = do_map_probe("cfi_probe", &s
//printk("2\n");
if (mymtd) {
mymtd->module = THIS_MODULE;
mymtd->erasesize = 0x20000; //INTEL E
/*here,we need not consider mtd_parts_nb,not call
parse_cmdline_partitions,because it's 5 indeed.we can obtain the size of partitions*/
return add_mtd_partitions(mymtd, s
}
//printk("3\n");
iounmap((void *)s
return -ENXIO;
}
static void __exit cleanup_s
{
if (mymtd) {
del_mtd_partitions(mymtd);
map_destroy(mymtd);
}
if (s
iounmap((void *)s
s
}
}
module_init(init_s
module_exit(cleanup_s
JEDEC Flash Interface.
* This is an older type of interface for self programming flash. It is commonly use in older AMD chips and is obsolete compared with CFI.It is called JEDEC because the JEDEC association distributes the ID codes for the chips.This code does not support anything wider than 8 bit flash chips
Common Flash Interface:
Common code to handle map devices which are simple ROM: