Chinaunix首页 | 论坛 | 博客
  • 博客访问: 362763
  • 博文数量: 81
  • 博客积分: 4016
  • 博客等级: 上校
  • 技术积分: 800
  • 用 户 组: 普通用户
  • 注册时间: 2006-03-17 18:38
文章分类

全部博文(81)

文章存档

2016年(5)

2015年(2)

2010年(1)

2008年(1)

2007年(4)

2006年(68)

我的朋友

分类: 服务器与存储

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 s3c2410_llg.c and physmap.c under the directory /drivers/mtd/maps..

 

#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(s3c2410_partitions) / sizeof(struct mtd_partition)

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. Nae 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 s3c2410 in physical memory

 */

 

#include

#include

#include

#include

#include

#include

#include

#include

 

#define WINDOW_ADDR 0x01000000 //禄霉

#define WINDOW_SIZE 0x01600000   //flash麓贸16M

#define BUSWIDTH 2

 

/*defined in include/linux/mtd/mtd.h*/

static struct mtd_info *mymtd;

 

__u8 s3c2410_read8(struct map_info *map, unsigned long ofs)

{

        return readb(map->map_priv_1 + ofs);

}

 

__u16 s3c2410_read16(struct map_info *map, unsigned long ofs)

{

        return readw(map->map_priv_1 + ofs);

               }

 

__u32 s3c2410_read32(struct map_info *map, unsigned long ofs)

{

        return readl(map->map_priv_1 + ofs);

}

 

void s3c2410_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len)

{

        memcpy(to, (void *)(map->map_priv_1 + from), len);

}

 

void s3c2410_write8(struct map_info *map, __u8 d, unsigned long adr)

{

        writeb(d, map->map_priv_1 + adr);

}

 

void s3c2410_write16(struct map_info *map, __u16 d, unsigned long adr)

{

        writew(d, map->map_priv_1 + adr);

}

void s3c2410_write32(struct map_info *map, __u32 d, unsigned long adr)

{

        writel(d, map->map_priv_1 + adr);

}

 

void s3c2410_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len)

{

        memcpy((void *)(map->map_priv_1 + to), from, len);

}

/*defined in include/linux/mtd/map.h*/

struct map_info s3c2410_map = {

        name: "s3c2410 flash device",

        size: WINDOW_SIZE,

        buswidth: BUSWIDTH,

        read8: s3c2410_read8,

        read16: s3c2410_read16,

        read32: s3c2410_read32,

        copy_from: s3c2410_copy_from,

        write8: s3c2410_write8,

        write16: s3c2410_write16,

             write32: s3c2410_write32,

        copy_to: s3c2410_copy_to,

    /* 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 s3c2410_partitions[] = {

    {

            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(8M)",

                size: 0x700000,

                offset: 0x800000,

        },

    {

        name: "cramfs(2.75M)",

        size:0x2c0000,

        offset:0x540000,

    }

 

};

 

int __init init_s3c2410(void)

{

    printk(KERN_NOTICE "s3c2410 flash device: %x at %x\n", WINDOW_SIZE, WINDOW_ADDR);

/*get line addr from physical addr*/

        s3c2410_map.map_priv_1 = (unsigned long)ioremap(WINDOW_ADDR, WINDOW_SIZE);

        //printk("0\n");

        if (!s3c2410_map.map_priv_1) {

                printk("Failed to ioremap/n");

                return -EIO;

                         }

        //printk("1\n");

        mymtd = do_map_probe("jedec_probe", &s3c2410_map);

        if (!mymtd)

        mymtd = do_map_probe("cfi_probe", &s3c2410_map);

        //printk("2\n");

        if (mymtd) {

                mymtd->module = THIS_MODULE;

                mymtd->erasesize = 0x20000; //INTEL E28F128J3A-150:128kb

/*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, s3c2410_partitions, sizeof(s3c2410_partitions) / sizeof(struct mtd_partition));

        }

        //printk("3\n");

        iounmap((void *)s3c2410_map.map_priv_1);

        return -ENXIO;

}

 

static void __exit cleanup_s3c2410(void)

{

        if (mymtd) {

                del_mtd_partitions(mymtd);

                  map_destroy(mymtd);

        }

        if (s3c2410_map.map_priv_1) {

                iounmap((void *)s3c2410_map.map_priv_1);

                s3c2410_map.map_priv_1 = 0;

        }

}

 

module_init(init_s3c2410);

module_exit(cleanup_s3c2410);

 

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:

 

 

阅读(1346) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~