MTD源代码分析(二)

源码分析

下面具体介绍每个文件的内容和作用:

 

 

头文件分析

 

mtd.h

MTD_CHAR_MAJOR

#define MTD_CHAR_MAJOR 90         MTD字符设备的主设备号

MTD_BLOCK_MAJOR

#define MTD_BLOCK_MAJOR 31       MTD块设备的主设备号

MAX_MTD_DEVICES

#define MAX_MTD_DEVICES 16       最大MTD原始设备数

 

 

mtd_info

表示MTD原始设备的结构,每个分区也被实现为一个mtd_info,如果有两个MTD原始设备,每个上有三个分区,在系统中就一共有6mtd_info结构,这些mtd_info的指针被存放在名为mtd_table的数组里。

struct mtd_info {         

       u_char type;          内存技术的类型

       u_int32_t flags;      标志位

       u_int32_t size; // Total size of the MTD             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;“主要的”erasesize(同一个mtd设备可能有数种不同的erasesize

 

       u_int32_t oobblock;  // Size of OOB blocks (e.g. 512)             oob块大小

       u_int32_t oobsize;   // Amount of OOB data per block (e.g. 16)              oob特别数据大小

       u_int32_t ecctype;         ecc类型

       u_int32_t eccsize;          自动ecc可以工作的范围

 

       // 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.

        */不同的erasesize的区域

       int numeraseregions; 不同erasesize的区域的数目(通常是1

       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);

                     routine用于将一个erase_info加入erase queue

       /* 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);

 

       /* 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;                    //指向map_info结构

}

 

mtd_info.type的取值

#define MTD_ABSENT        0

#define MTD_RAM                     1

#define MTD_ROM                     2

#define MTD_NORFLASH           3

#define MTD_NANDFLASH        4

#define MTD_PEROM          5

#define MTD_OTHER          14

#define MTD_UNKNOWN           15

 

mtd_info.flags的取值

#define MTD_CLEAR_BITS        1       // Bits can be cleared (flash)

#define MTD_SET_BITS             2       // Bits can be set

#define MTD_ERASEABLE          4       // Has an erase function

#define MTD_WRITEB_WRITEABLE 8       // Direct IO is possible

#define MTD_VOLATILE            16      // Set for RAMs

#define MTD_XIP                32    // eXecute-In-Place possible

#define MTD_OOB                     64    // Out-of-band data (NAND flash)

#define MTD_ECC               128  // Device capable of automatic ECC

 

// Some common devices / combinations of capabilities

#define MTD_CAP_ROM            0

#define MTD_CAP_RAM             (MTD_CLEAR_BITS|MTD_SET_BITS|MTD_WRITEB_WRITEABLE)

#define MTD_CAP_NORFLASH        (MTD_CLEAR_BITS|MTD_ERASEABLE)

#define MTD_CAP_NANDFLASH       (MTD_CLEAR_BITS|MTD_ERASEABLE|MTD_OOB)

#define MTD_WRITEABLE         (MTD_CLEAR_BITS|MTD_SET_BITS)

 

mtd_info.ecctype的取值

#define MTD_ECC_NONE           0     // No automatic ECC available

#define MTD_ECC_RS_DiskOnChip    1     // Automatic ECC on DiskOnChip

#define MTD_ECC_SW        2     // SW ECC for Toshiba & Samsung devices

 

erase_info

表示erase动作的结构,由设备层调用mtd_info->erase函数传递给原始设备层

struct erase_info {        

       struct mtd_info *mtd;    被操作的MTD原始设备

       u_int32_t addr;              被操作的地址(byte

       u_int32_t len;                长度

       u_long time;

       u_long retries;

       u_int dev;

       u_int cell;

       void (*callback) (struct erase_info *self);   

callback函数指针,当erase结束后该函数被调用

       u_long priv;                  user模块提供的private数据

       u_char state;                 当前状态

       struct erase_info *next;  erase队列中的下一个erase_info

};

 

erase_info.state的取值

#define MTD_ERASE_PENDING          0x01

#define MTD_ERASING                                   0x02

#define MTD_ERASE_SUSPEND               0x04

#define MTD_ERASE_DONE             0x08

#define MTD_ERASE_FAILED            0x10

驱动模块在erase要求进入erase 队列时将state设置为MTD_ERASE_PENDING,当callback被调用时设置为MTD_ERASE_DONEMTD_ERASE_FAILED

 

 

mtd_notifier

MTD通知器(这个名字很古怪,但我找不到更好的词来翻译),加入/删除MTD设备和原始设备时调用的函数,在设备层,当MTD字符设备或块设备注册时,如果定义了CONFIG_DEVFS_FS,则会将一个mtd_notifier加入MTD原始设备层的mtd_notifiers链表,其中的函数会在两种情况下被调用,一是加入/删除新的MTD字符/块设备时,此时调用该MTD字符/块设备的notifier对下层所有的MTD原始设备操作一遍,二是加入/删除新的MTD原始设备时,此时调用所有的notifier对该原始设备执行一遍。

struct mtd_notifier {                   

void (*add)(struct mtd_info *mtd);      加入时调用

void (*remove)(struct mtd_info *mtd); 删除时调用

       struct mtd_notifier *next;      指向mtd_notifiers队列中的下一个mtd_notifier

};

 

 

get_mtd_device

格式:

       static inline struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num)

注释:

      

功能:

       获得一个MTD设备

说明:

       调用__get_mtd_device()

参数:

       __get_mtd_device()

返回:

       要求的MTD原始设备

调用:

       __get_mtd_device()

被调用:

       设备层函数,在设备层的open函数中被调用以获得一个MTD原始设备

源代码:

{

       struct mtd_info *ret;

      

       ret = __get_mtd_device(mtd, num);

 

       if (ret && ret->module && !try_inc_mod_count(ret->module))

              return NULL;

 

       return ret;

}

 

put_mtd_device

格式:

       static inline void put_mtd_device(struct mtd_info *mtd)

注释:

      

功能:

       归还(put)一个使用完的MTD设备

说明:

      

参数:

       MTD设备

返回:

      

调用:

      

被调用:

       设备层函数,通常在设备层的release函数中调用。

源代码:

{

       if (mtd->module)

              __MOD_DEC_USE_COUNT(mtd->module);

}

 

 

partitions.h

此文件中的数据用来从/maps子目录下的文件向原始设备层传递分区信息

 

mtd_partition

/*

 * 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.

 * 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.

 */

struct mtd_partition {    描述mtd设备分区的结构,在MTD原始设备层调用add_mtd_partions

传递分区信息

       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 */将被掩去的标

志位,(例如如果在分区时置mask_flagsWRITEABLE,则此分区为只读分区)

};

 

 

MTDPART_OFS_APPEND

#define MTDPART_OFS_APPEND      (-1)         如果mtd_partition.offset取此值,表示此分区

offset紧接上一个分区的结束

MTDPART_SIZ_FULL

#define MTDPART_SIZ_FULL     (0)                 如果mtd_partion.size取此值,表示此分区一

直到MTD原始设备的最后结束

 

 

 

map.h

 

map_info

 

struct map_info {

       char *name;

       unsigned long size;

       int buswidth; /* in octets */

       __u8 (*read8)(struct map_info *, unsigned long);              Flash的读写函数,(NORFlash

       __u16 (*read16)(struct map_info *, unsigned long);   可以像内存一样进行读写),read8

       __u32 (*read32)(struct map_info *, unsigned long);  read16read32分别用于buswidth

124字节的情况(write同理)

       /* 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 (*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;           指向cfi_private结构

       struct mtd_chip_driver *fldrv;

};

 

 

mtd_chip_driver

struct mtd_chip_driver {

       struct mtd_info *(*probe)(struct map_info *map);     该芯片的probe程序

       void (*destroy)(struct mtd_info *);

       struct module *module;         模块

       char *name;           芯片名

       struct list_head list;

};

MTD芯片驱动器的结构

 

 

 

gen_probe.h

 

chip_probe

struct chip_probe {

       char *name;

       int (*probe_chip)(struct map_info *map, __u32 base,

                       struct flchip *chips, struct cfi_private *cfi);   

 

};

通用探测程序的参数结构,此结构类型将作为参数传进mtd_do_chip_probe()中,mtd_do_chip_probe()将间接调用其中的probe_chip函数

 

 

 

cfi.h

cfi_private

CFI私有信息

struct cfi_private {       

       __u16 cmdset;

       void *cmdset_priv;

       int interleave;         芯片交错数,interleave片芯片交织连接成一个芯片

       int device_type;      每一片Flash的类型(18bits216bits432bits

       int cfi_mode;         /* Are we a JEDEC device pretending to be CFI? */    CFI的模式

       int addr_unlock1;   命令地址,所谓“unlock”是指无论Flash处于读模式或写模式,都

       int addr_unlock2;          可向该地址写命令

       int fast_prog;         允许Fast Program模式

       struct mtd_info *(*cmdset_setup)(struct map_info *);

       struct cfi_ident *cfiq; /* For now only one. We insist that all devs     每个芯片的信息

                              must be of the same type. */                   (所有芯片是同类型的)

       int mfr, id;

       int numchips;         Flash芯片个数(N interleave算一块芯片)

       unsigned long chipshift; /* Because they're of the same type */

每块芯片大小*interleave=2chipshift次方

       const char *im_name;    /* inter_module name for cmdset_setup */

       struct flchip chips[0];  /* per-chip data structure for each chip */每一块芯片的信息

};

 

 

cfi_private.cfi_mode的取值

#define CFI_MODE_CFI      0            真的是CFI

#define CFI_MODE_JEDEC  1            JEDEC仿真CFI

 

cfi_ident

CFI接口芯片的查询结构,从芯片起始地址+0x10开始的0x2C个字节

/* Basic Query Structure */

struct cfi_ident {

  __u8  qry[3];           QRY       0x10,0x11,0x12

  __u16 P_ID;             制造商ID      Primary ID            0x13,0x14

  __u16 P_ADR;                               Primary Address    0x15,0x16

  __u16 A_ID;                                  Alternate ID          0x17,0x18     

  __u16 A_ADR;                               Alternate Address   0x19,0x1A

  __u8  VccMin;         逻辑供电Vcc最小电压       0x1B

  __u8  VccMax;        逻辑供电Vcc最大电压       0x1C

  __u8  VppMin;         编程/擦除供电Vpp最小电压      0x1D

  __u8  VppMax;        编程/擦除供电Vpp最大电压      0x1E

  __u8  WordWriteTimeoutTyp;         典型单字节/字写周期定时时间          0x1F

  __u8  BufWriteTimeoutTyp;                                              0x20

  __u8  BlockEraseTimeoutTyp; 典型单块擦除定时时间       0x21

  __u8  ChipEraseTimeoutTyp;   典型整片擦除定时时间       0x22

  __u8  WordWriteTimeoutMax; 单字节/字写周期最大定时时间         0x23

  __u8  BufWriteTimeoutMax;                                              0x24

  __u8  BlockEraseTimeoutMax; 单块擦除最大定时时间      0x25

  __u8  ChipEraseTimeoutMax; 整片擦除最大定时时间       0x26

  __u8  DevSize;                      器件体积                            0x27

  __u16 InterfaceDesc;               Flash器件接口识别码ID     0x28,0x29

  __u16 MaxBufWriteSize;                                                    0x2A,0x2B

  __u8  NumEraseRegions;       器件可擦除块区域个数       0x2C

  __u32 EraseRegionInfo[0]; /* Not host ordered */   擦除块区域信息:       0x2D0x3C

} __attribute__((packed));`           bit15-0=y该擦除块区域内含同样体积擦除块的个数=y+1

bit31-16=z该区域每个擦除块体积=z x 256字节

 

 

 

 

 

 

 

cfi_ident.P_ID的取值

#define P_ID_NONE 0

#define P_ID_INTEL_EXT 1

#define P_ID_AMD_STD 2

#define P_ID_INTEL_STD 3

#define P_ID_AMD_EXT 4

#define P_ID_MITSUBISHI_STD 256

#define P_ID_MITSUBISHI_EXT 257

#define P_ID_RESERVED 65535

 

 

flashchip.h

 

 

flchip

struct flchip {

       unsigned long start; /* Offset within the map */

       //     unsigned long len;          假设所有的Flash chip都是相同的,所以没有定义len

       /* We omit len for now, because when we group them together

          we insist that they're all of the same size, and the chip size

          is held in the next level up. If we get more versatile later,

          it'll make it a damn sight harder to find which chip we want from

          a given offset, and we'll want to add the per-chip length field

          back in.

       */

       flstate_t state;

       flstate_t oldstate;

       spinlock_t *mutex;

       spinlock_t _spinlock; /* We do it like this because sometimes they'll be shared. */

       wait_queue_head_t wq; /* Wait on here when we're waiting for the chip

                          to be ready */

       int word_write_time;

       int buffer_write_time;

       int erase_time;

};

 

 

 

/drivers/mtd/子目录

 

 

mtdcore.c

本文件主要实现了MTD原始设备层的数据结构mtd_table和对其的操作函数,主要包括add_mtd_device()(加入MTD原始设备)、del_mtd_device()(删除MTD原始设备)

mtd_table

static struct mtd_info *mtd_table[MAX_MTD_DEVICES];

标示MTD设备的数组,最多可以有MAX_MTD_DEVICES个设备(每一个MTD分区也算一个MTD设备)

 

mtd_notifiers

static struct mtd_notifier *mtd_notifiers = NULL;

标示mtd_notifier队列的指针

 

 

add_mtd_device

格式:

int add_mtd_device(struct mtd_info *mtd)

注释:

/**

 *    add_mtd_device - register an MTD device

 *    @mtd: pointer to new MTD device info structure

 *

 *    Add a device to the list of MTD devices present in the system, and

 *    notify each currently active MTD 'user' of its arrival. Returns

 *    zero on success or 1 on failure, which currently will only happen

 *    if the number of present devices exceeds MAX_MTD_DEVICES (i.e. 16)

 */

功能:

加入一个MTD原始设备。

参数:

mtd:被加入的原始设备

返回:

       成功:返回0

       mtd_table已满:返回1

说明:

1.  加入此原始设备的mtd_infomtd_table中,

2.  notify所有的MTD设备一个mtd被加入(调用所有的notifier->add(mtd))。

调用:

       notifers->add(mtd)

被调用:

       Flash相关文件(your-flash.c)初始化时(maps子目录下的文件中的init_xxx函数)

源代码:

{

       int i;

 

       down(&mtd_table_mutex);

 

       for (i=0; i< MAX_MTD_DEVICES; i++)

              if (!mtd_table[i])                         //找到mtd_table中的空项

              {

                     struct mtd_notifier *not=mtd_notifiers;

 

                     mtd_table[i] = mtd;               //将其指向新加入的MTD原始设备

                     mtd->index = i;

                     DEBUG(0, "mtd: Giving out device %d to %s/n",i, mtd->name);

                     while (not)                                  //如果有notifier,调用所有的notifier对新加

                     {                                               //入的MTD原始设备操作一遍

                            (*(not->add))(mtd);

                            not = not->next;

                     }

                     up(&mtd_table_mutex);

                     MOD_INC_USE_COUNT;

                     return 0;

              }

      

       up(&mtd_table_mutex);

       return 1;

}    

 

del_mtd_device

格式:

       int del_mtd_device (struct mtd_info *mtd)

注释:

/**

 *    del_mtd_device - unregister an MTD device

 *    @mtd: pointer to MTD device info structure

 *

 *    Remove a device from the list of MTD devices present in the system,

 *    and notify each currently active MTD 'user' of its departure.

 *    Returns zero on success or 1 on failure, which currently will happen

 *    if the requested device does not appear to be present in the list.

 */

 

功能:

       删除一个mtd设备。

说明:

       mtd_table中删除此设备的mtd_info,通知所有的MTD设备(调用所有的notifier.removemtd))

参数:

       mtd:描述此设备的mtd_info

返回:

       成功:返回0

       此设备不在mtd_table中:返回1

调用:

       notifiers->remove(mtd)

被调用:

       Flash相关文件(your-flash.c)清除设备时(drivers/mtd/maps子目录下的文件中的cleanupt_xxx函数)

源代码:

{

       struct mtd_notifier *not=mtd_notifiers;

       int i;

      

       down(&mtd_table_mutex);

 

       for (i=0; i < MAX_MTD_DEVICES; i++)

       {

              if (mtd_table[i] == mtd)

              {

                     while (not)                                         //如果有notifier,调用所有的notifier

                     {                                                      //被删除的MTD原始设备操作一遍

                            (*(not->remove))(mtd);

                            not = not->next;

                     }

                     mtd_table[i] = NULL;

                     up (&mtd_table_mutex);

                     MOD_DEC_USE_COUNT;

                     return 0;

              }

       }

 

       up(&mtd_table_mutex);

       return 1;

}

 

 

register_mtd_user

格式:

       void register_mtd_user (struct mtd_notifier *new)

注释:

/**

 *    register_mtd_user - register a 'user' of MTD devices.

 *    @new: pointer to notifier info structure

 *

 *    Registers a pair of callbacks function to be called upon addition

 *    or removal of MTD devices. Causes the 'add' callback to be immediately

 *    invoked for each MTD device currently present in the system.

 */

 

功能:

       加入一个MTD原始设备的使用者(即MTD设备,MTD块设备或字符设备)。

说明:

1.  将新的mtd通知器new加入notifer队列中,

2.  增加模块的use count

3.  对所有已有的MTD原始设备调用new->add()

参数:

       new:新MTD设备的mtd_notifier

返回:

      

调用:

       new->add()

被调用:

       (如果定义了CONFIG_DEVFSMTD设备级的初始化(mtdblock.cmtdchar.cftl.c中的init_xxx

源代码:

{

       int i;

 

       down(&mtd_table_mutex);

 

       new->next = mtd_notifiers;

       mtd_notifiers = new;

 

      MOD_INC_USE_COUNT;

      

       for (i=0; i< MAX_MTD_DEVICES; i++)     //对所有的MTD原始设备操作一遍

              if (mtd_table[i])

                     new->add(mtd_table[i]);

 

       up(&mtd_table_mutex);

}

 

 

unregister_mtd_user

格式:

       int unregister_mtd_user (struct mtd_notifier *old)

注释:

/**

 *    unregister_mtd_user - unregister a 'user' of MTD devices.

 *    @new: pointer to notifier info structure

 *

 *    Removes a callback function pair from the list of 'users' to be

 *    notified upon addition or removal of MTD devices. Causes the

 *    'remove' callback to be immediately invoked for each MTD device

 *    currently present in the system.

 */

功能:

       删除一个MTD设备

说明:

1.  将被删除MTD设备的通知器oldnotifer队列中删除

2.  减模块的use count

3.  对所有已有的MTD原始设备调用old->remove()

参数:

       old:被删除MTD设备的mtd_notifier

返回:

       成功:返回0

       notifiers队列中无此设备的notifier:返回1

调用:

       old->remove()

被调用:

       (如果定义了CONFIG_DEVFSMTD设备级的清除(mtdblock.cmtdchar.cftl.c中的cleanup_xxx

源代码:

{

       struct mtd_notifier **prev = &mtd_notifiers;

       struct mtd_notifier *cur;

       int i;

 

       down(&mtd_table_mutex);

 

       while ((cur = *prev)) {

              if (cur == old) {

                     *prev = cur->next;

 

                     MOD_DEC_USE_COUNT;

 

                     for (i=0; i< MAX_MTD_DEVICES; i++)     //对所有的MTD原始设备调用一遍

                            if (mtd_table[i])                                  //remove函数

                                   old->remove(mtd_table[i]);

                    

                     up(&mtd_table_mutex);

                     return 0;

              }

              prev = &cur->next;

       }

       up(&mtd_table_mutex);

       return 1;

}

 

 

__get_mtd_device

格式:

       struct mtd_info *__get_mtd_device(struct mtd_info *mtd, int num)

注释:

/**

 *    __get_mtd_device - obtain a validated handle for an MTD device

 *    @mtd: last known address of the required MTD device

 *    @num: internal device number of the required MTD device

 *

 *    Given a number and NULL address, return the num'th entry in the device

 *    table, if any.    Given an address and num == -1, search the device table

 *    for a device with that address and return if it's still present. Given

 *    both, return the num'th driver only if its address matches. Return NULL

 *    if not. get_mtd_device() increases the use count, but

 *    __get_mtd_device() doesn't - you should generally use get_mtd_device().

 */

功能:

       返回指定的MTD原始设备的handler

说明:

       num==-1&mtd!=NULL:返回与mtd地址相同的设备

       0<num<MAX_MTD_DEVICES&mtd==NULL:返回mtd_table中的第numMTD设备

       0<num<MAX_MTD_DEVICES&mtd!=NULL:如果mtd_table中第num个设备为mtd

返回mtd;否则返回空。

       其余情况:返回NULL

参数:

       mtd:指定MTD原始设备的指针

       num:见说明

返回:

       见说明

调用:

      

被调用:

       get_mtd_device()

源代码:

{

       struct mtd_info *ret = NULL;

       int i;

 

       down(&mtd_table_mutex);

 

       if (num == -1) {

              for (i=0; i< MAX_MTD_DEVICES; i++)

                     if (mtd_table[i] == mtd)

                            ret = mtd_table[i];

       } else if (num < MAX_MTD_DEVICES) {

              ret = mtd_table[num];

              if (mtd && mtd != ret)

                     ret = NULL;

       }

      

       up(&mtd_table_mutex);

       return ret;

}

 

 

mtdpart.c

       MTD原始设备层分区的实现,mtd_part结构是用于描述分区的,由mtd_partitonsmtd_part中的list成员链成一个链表。每个mtd_part结构中的mtd_info结构用于描述本分区,被加入mtd_table中,其中大部分成员由其主分区mtd_part->master决定,各种函数也指向主分区的相应函数。而主分区(其大小涵盖所有分区)则不作为一个MTD原始设备加入mtd_table

       本文件向外提供的add_mtd_partitions()del_mtd_partitions()根据参数map_info结构将所有的分区加入mtd_table

       mtdpart.c中还实现了part_readpart_write等函数,这些函数注册在每个分区中,指向主分区的readwrite函数,之所以这样做而不直接将主分区的readwrite函数连接到每个分区中的原因是因为函数中的参数mtd_info会被调用者置为函数所属的mtd_info,即mtd->read(mtd…),而参数mtd_info其实应该指向主分区。

mtd_partitions

/* Our partition linked list */

static LIST_HEAD(mtd_partitions);                    MTD原始设备分区的链表

 

 

mtd_part

描述分区的结构

/* Our partition node structure */

struct mtd_part {         

       struct mtd_info mtd;             分区的信息(大部分由其master决定)

       struct mtd_info *master;              该分区的主分区

       u_int32_t offset;                   该分区的偏移地址

       int index;                             分区号

       struct list_head list;

};

 

 

PART(x)

/*

 * Given a pointer to the MTD object in the mtd_part structure, we can retrieve

 * the pointer to that structure with this macro.

 */

#define PART(x)  ((struct mtd_part *)(x))         mtd_info结构转换为mtd_part结构

 

 

add_mtd_partitions

格式:

       int add_mtd_partitions(struct mtd_info *master, struct mtd_partition *parts, int nbparts)

注释:

/*

 * This function, given a master MTD object and a partition table, creates

 * and registers slave MTD objects which are bound to the master according to

 * the partition definitions.

 * (Q: should we register the master MTD object as well?)

 */

功能:

       MTD原始设备分区

说明:

       打印信息(型如“Creating 3 MTD partitions on "Your Flash map”),

       对每一个新建分区{

建立一个新的mtd_part结构,并将其加入mtd_partitions中,

根据master设置mtd_part.mtd_info的成员,

              打印信息(型如“0x00020000-0x00800000 : "Your Kernel"”),

              进行安全性检查,

              根据master->numeraseregions处理多erasesize区域的事务,

              调用add_mtd_device将此分区作为MTD设备加入mtd_table

       }

参数:

       master:指定的MTD设备

       parts:关于分区信息的指针

       nbparts:分区的数目

返回:

       成功:返回0

       分配mtd_part时内存不足:返回-ENOMEM

调用:

       add_mtd_device()

       del_mtd_partitions()

被调用:

       flash相关的初始化函数中(maps子目录下的文件的函数init_xxx中)

源代码:

{

       struct mtd_part *slave;

       u_int32_t cur_offset = 0;

       int i;

 

       printk (KERN_NOTICE "Creating %d MTD partitions on /"%s/":/n", nbparts, master->name);

 

       for (i = 0; i < nbparts; i++) {

 

              /* allocate the partition structure */

              slave = kmalloc (sizeof(*slave), GFP_KERNEL);

              if (!slave) {

                     printk ("memory allocation error while creating partitions for /"%s/"/n",

                            master->name);

                     del_mtd_partitions(master);

                     return -ENOMEM;

              }

              memset(slave, 0, sizeof(*slave));

              list_add(&slave->list, &mtd_partitions);

 

              /* set up the MTD object for this partition */

              slave->mtd.type = master->type;

              slave->mtd.flags = master->flags & ~parts[i].mask_flags;

              slave->mtd.size = parts[i].size;

              slave->mtd.oobblock = master->oobblock;

              slave->mtd.oobsize = master->oobsize;

              slave->mtd.ecctype = master->ecctype;

              slave->mtd.eccsize = master->eccsize;

 

              slave->mtd.name = parts[i].name;

              slave->mtd.bank_size = master->bank_size;

 

              slave->mtd.module = master->module;

 

              slave->mtd.read = part_read;

              slave->mtd.write = part_write;

              if (master->sync)

                     slave->mtd.sync = part_sync;

              if (!i && master->suspend && master->resume) {

                            slave->mtd.suspend = part_suspend;

                            slave->mtd.resume = part_resume;

              }

 

              if (master->writev)

                     slave->mtd.writev = part_writev;

              if (master->readv)

                     slave->mtd.readv = part_readv;

              if (master->lock)

                     slave->mtd.lock = part_lock;

              if (master->unlock)

                     slave->mtd.unlock = part_unlock;

              slave->mtd.erase = part_erase;

              slave->master = master;

              slave->offset = parts[i].offset;

              slave->index = i;

 

              if (slave->offset == MTDPART_OFS_APPEND)

                     slave->offset = cur_offset;

              if (slave->mtd.size == MTDPART_SIZ_FULL)

                     slave->mtd.size = master->size - slave->offset;

              cur_offset = slave->offset + slave->mtd.size;

      

              printk (KERN_NOTICE "0x%08x-0x%08x : /"%s/"/n", slave->offset,

                     slave->offset + slave->mtd.size, slave->mtd.name);

 

              /* let's do some sanity checks */          //安全检查

              if (slave->offset >= master->size) {

                            /* let's register it anyway to preserve ordering */

                     slave->offset = 0;

                     slave->mtd.size = 0;

                     printk ("mtd: partition /"%s/" is out of reach -- disabled/n",

                            parts[i].name);

              }

              if (slave->offset + slave->mtd.size > master->size) {

                     slave->mtd.size = master->size - slave->offset;

                     printk ("mtd: partition /"%s/" extends beyond the end of device /"%s/" -- size truncated to %#x/n",

                            parts[i].name, master->name, slave->mtd.size);

              }

              if (master->numeraseregions>1) {

                     /* Deal with variable erase size stuff */

                     int i;

                     struct mtd_erase_region_info *regions = master->eraseregions;

                    

                     /* Find the first erase regions which is part of this partition. */

                     for (i=0; i < master->numeraseregions && slave->offset >= regions[i].offset; i++)

                            ;

 

                     for (i--; i < master->numeraseregions && slave->offset + slave->mtd.size > regions[i].offset; i++) {

                            if (slave->mtd.erasesize < regions[i].erasesize) {

                                   slave->mtd.erasesize = regions[i].erasesize;

                            }

                     }

              } else {

                     /* Single erase size */

                     slave->mtd.erasesize = master->erasesize;

              }

 

              if ((slave->mtd.flags & MTD_WRITEABLE) &&

                  (slave->offset % slave->mtd.erasesize)) {

                     /* Doesn't start on a boundary of major erase size */

                     /* FIXME: Let it be writable if it is on a boundary of _minor_ erase size though */

                     slave->mtd.flags &= ~MTD_WRITEABLE;

                     printk ("mtd: partition /"%s/" doesn't start on an erase block boundary -- force read-only/n",parts[i].name);

              }

              if ((slave->mtd.flags & MTD_WRITEABLE) &&

                  (slave->mtd.size % slave->mtd.erasesize)) {

                     slave->mtd.flags &= ~MTD_WRITEABLE;

                     printk ("mtd: partition /"%s/" doesn't end on an erase block -- force read-only/n", parts[i].name);

              }

 

              /* register our partition */

              add_mtd_device(&slave->mtd);

       }

 

       return 0;

}

 

 

del_mtd_partitions

格式:

       int del_mtd_partitions(struct mtd_info *master)

注释:

/*

 * This function unregisters and destroy all slave MTD objects which are

 * attached to the given master MTD object.

 */  

功能:

       删除master上的所有分区。

说明:

       mtd_partitions上的每一个分区{

       如果它的主分区是master,将它从mtd_partitionsmtd_table中删除并free

}

参数:

       master:被删除分区的主分区

返回:

       返回0

调用:

       del_mtd_device()

       kfree()

被调用:

       flash相关的清除函数(maps子目录下的文件中的cleanup_xxx函数)

源代码:

{

       struct list_head *node;

       struct mtd_part *slave;

 

       for (node = mtd_partitions.next;

            node != &mtd_partitions;

            node = node->next) {

              slave = list_entry(node, struct mtd_part, list);

              if (slave->master == master) {

                     struct list_head *prev = node->prev;

                     __list_del(prev, node->next);        //mtd_partitions中删除

                     del_mtd_device(&slave->mtd);     //mtd_table中删除

                     kfree(slave);

                     node = prev;

              }

       }

 

       return 0;

}

 

 

part_read

part_write

part_readv

part_writev

part_erase

part_lock

part_unlock

part_sync

part_suspend

part_resume

格式:

      

注释:

/*

 * MTD methods which simply translate the effective address and pass through

 * to the _real_ device.

 */

功能:

       非主分区的xxxx函数。

说明:

       进行安全性检查,

       调用主分区的xxxx函数

参数:

      

返回:

      

调用:

      

被调用:

       add_mtd_partitions中被注册进非主分区的md_info

源代码:

      

 

 

mtdblock.c

       MTD设备层的块设备的相关数据结构和程序,其中定义了MTD块设备的notifierMTD块设备的结构mtdblk_dev类型的mtdblks数组,该数组中的每个成员与MTD原始设备层的mtd_table数组中的每个成员一一对应。

notifier

       设备层的mtdblcok设备的notifier

static struct mtd_notifier notifier = {   

        mtd_notify_add,

        mtd_notify_remove,

        NULL

};

 

 

mtdblk_dev

设备层的块设备的结构(and its private , I think),MTD字符设备没有相对应的结构。

struct mtdblk_dev {                    

       struct mtd_info *mtd; /* Locked */      下层原始设备层的MTD设备结构

       int count;

       struct semaphore cache_sem;

       unsigned char *cache_data;                 缓冲区(与MTD设备块对齐)

       unsigned long cache_offset;                缓冲区内数据在原始设备层MTD设备内的偏移

       unsigned int cache_size;                      缓冲区大小(通常被设置为MTD设备的erasesize

       enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state;        缓冲区状态

}           

 

mtdblks

设备层(块)设备数组(与原始设备层的MAX_MTD_DEVICESMTD设备一一对应)

static struct mtdblk_dev *mtdblks[MAX_MTD_DEVICES];     

 

 

erase_callback

格式:

       static void erase_callback(struct erase_info *done)

注释:

/*

 * Cache stuff...

 *

 * Since typical flash erasable sectors are much larger than what Linux's

 * buffer cache can handle, we must implement read-modify-write on flash

 * sectors for each block write requests.  To avoid over-erasing flash sectors

 * and to speed things up, we locally cache a whole flash sector while it is

 * being written to until a different sector is required.

 */

功能:

       回调函数,当写完时被调用。

说明:

       erase_write中被赋给erase_info结构

参数:

       done

返回:

      

调用:

       wake_up

被调用:

       erase_write中被注册

源代码:

{

       wait_queue_head_t *wait_q = (wait_queue_head_t *)done->priv;

       wake_up(wait_q);

}

 

 

erase_write

格式:

       static int erase_write (struct mtd_info *mtd, unsigned long pos,       int len, const char *buf)

注释:

      

功能:

       擦除并写flash

说明:

1.  声明一个erase_info变量erase并给其赋值,

2.  调用原始设备层函数mtd_info->erase(mtd,erase)

3.  调用原始设备层函数mtd_info->write()

参数:

       mtd:被操作的MTD原始设备

       posMTD原始设备的起始位置

       len:长度

       buf:被写入的内容

返回:

       FIXME

调用:

       mtd_info->erase

       mtd_info->write

被调用:

       write_cached_data

       do_cached_write

源代码:

{

       struct erase_info erase;

       DECLARE_WAITQUEUE(wait, current);

       wait_queue_head_t wait_q;

       size_t retlen;

       int ret;

 

       /*

        * First, let's erase the flash block.

        */

 

       init_waitqueue_head(&wait_q);

       erase.mtd = mtd;

       erase.callback = erase_callback;

       erase.addr = pos;

       erase.len = len;

       erase.priv = (u_long)&wait_q;

 

       set_current_state(TASK_INTERRUPTIBLE);

       add_wait_queue(&wait_q, &wait);

 

       ret = MTD_ERASE(mtd, &erase);              //调用mtd->erase()

       if (ret) {

              set_current_state(TASK_RUNNING);

              remove_wait_queue(&wait_q, &wait);

              printk (KERN_WARNING "mtdblock: erase of region [0x%lx, 0x%x] "

                                 "on /"%s/" failed/n",

                     pos, len, mtd->name);

              return ret;

       }

 

       schedule();  /* Wait for erase to finish. */

       remove_wait_queue(&wait_q, &wait);

 

       /*

        * Next, writhe data to flash.

        */

 

       ret = MTD_WRITE (mtd, pos, len, &retlen, buf);              //调用mtd->write()

       if (ret)

              return ret;

       if (retlen != len)

              return -EIO;

       return 0;

}

 

 

write_cached_data

格式:

       static int write_cached_data (struct mtdblk_dev *mtdblk)

注释:

      

功能:

       将指定设备层MTD块设备缓冲区内的数据写入MTD设备

说明:

      

参数:

       mtdblk:指定的设备层MTD块设备结构

返回:

       成功:返回0

       失败:FIXME

调用:

       erase_write()写入MTD设备

被调用:

       do_cached_write()

       mtdblock_release()

       mtdblock_ioctl()

源代码:

{

       struct mtd_info *mtd = mtdblk->mtd;

       int ret;

 

       if (mtdblk->cache_state != STATE_DIRTY)

              return 0;

 

       DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: writing cached data for /"%s/" "

                     "at 0x%lx, size 0x%x/n", mtd->name,

                     mtdblk->cache_offset, mtdblk->cache_size);

      

       ret = erase_write (mtd, mtdblk->cache_offset,

                        mtdblk->cache_size, mtdblk->cache_data);

       if (ret)

              return ret;

 

       /*

        * Here we could argably set the cache state to STATE_CLEAN.

        * However this could lead to inconsistency since we will not

        * be notified if this content is altered on the flash by other

        * means.  Let's declare it empty and leave buffering tasks to

        * the buffer cache instead.

        */

       mtdblk->cache_state = STATE_EMPTY;

       return 0;

}

 

do_cached_write

格式:

       static int do_cached_write (struct mtdblk_dev *mtdblk, unsigned long pos,

                         int len, const char *buf)

注释:

      

功能:

       buf向指定的设备层MTD块设备中缓冲写

说明:

       如果缓冲区大小为0,则调用mtd_info->write()直接向MTD设备中写,

       当(len>0{

              如果是整块block,则直接向MTD设备中写

              否则{

先调用write_cached_data()将缓冲内的数据写入MTD设备

                     在调用mtd_info->readMTD设备中将对应块的数据读入缓冲

                     buf的数据(非整块)写入缓冲

              }

              len自减

       }

参数:

       mtdblk:指定的MTD块设备

       pos:写入原始设备层MTD设备的位置

       len:数据长度

       buf:被写入的数据

返回:

       成功:返回0

       失败:返回错误码

调用:

       erase_write()用于直接写MTD设备

       write_cached_data()用于清空MTD块设备的缓冲区

       mtd_info->read()用于从MTD设备中读数据

       mtd_info->write()用于向MTD设备中写数据

被调用:

       handle_mtdblock_request()

源代码:

{

       struct mtd_info *mtd = mtdblk->mtd;

       unsigned int sect_size = mtdblk->cache_size;

       size_t retlen;

       int ret;

 

       DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: write on /"%s/" at 0x%lx, size 0x%x/n",

              mtd->name, pos, len);

      

       if (!sect_size)

              return MTD_WRITE (mtd, pos, len, &retlen, buf);

 

       while (len > 0) {

              unsigned long sect_start = (pos/sect_size)*sect_size;//we should write by erase block

              unsigned int offset = pos - sect_start;//real start address

              unsigned int size = sect_size - offset;

              if( size > len )

                     size = len;

 

              if (size == sect_size) {

                     /*

                      * We are covering a whole sector.  Thus there is no

                      * need to bother with the cache while it may still be

                      * useful for other partial writes.

                      */

                     ret = erase_write (mtd, pos, size, buf);

                     if (ret)

                            return ret;

              } else {

                     /* Partial sector: need to use the cache */

 

                     if (mtdblk->cache_state == STATE_DIRTY &&

                         mtdblk->cache_offset != sect_start) {

                            ret = write_cached_data(mtdblk);

                            if (ret)

                                   return ret;

                     }

 

                     if (mtdblk->cache_state == STATE_EMPTY ||

                         mtdblk->cache_offset != sect_start) {

                            /* fill the cache with the current sector */

                            mtdblk->cache_state = STATE_EMPTY;

                            ret = MTD_READ(mtd, sect_start, sect_size, &retlen, mtdblk->cache_data);

                            if (ret)

                                   return ret;

                            if (retlen != sect_size)

                                   return -EIO;

 

                            mtdblk->cache_offset = sect_start;

                            mtdblk->cache_size = sect_size;

                            mtdblk->cache_state = STATE_CLEAN;

                     }

 

                     /* write data to our local cache */

                     memcpy (mtdblk->cache_data + offset, buf, size);

                     mtdblk->cache_state = STATE_DIRTY;

              }

 

              buf += size;

              pos += size;

              len -= size;

       }

 

       return 0;

}

 

 

do_cached_read

格式:

       static int do_cached_read (struct mtdblk_dev *mtdblk, unsigned long pos,

                        int len, char *buf)

注释:

      

功能:

       从指定的MTD块设备中缓冲读到指定位置buf

说明:

       如果缓冲区大小为0,调用mtd_info->read()直接从原始设备层MTD设备中读取

       否则当(len>0{

              如果缓冲区不为空且其中数据正好是所需数据,则从缓冲区拷贝到buf

              否则调用mtd_info->read()MTD中读

       }

参数:

       mtdblk:指定的MTD块设备

       posMTD设备中指定的位置

       len:长度

       buf:被写入的地址

返回:

       成功:返回0

       失败:返回错误码

调用:

       mtd_info->read()从指定的MTD设备中读

被调用:

       handle_mtdblock_request()

源代码:

{

       struct mtd_info *mtd = mtdblk->mtd;

       unsigned int sect_size = mtdblk->cache_size;

       size_t retlen;

       int ret;

 

       DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: read on /"%s/" at 0x%lx, size 0x%x/n",

                     mtd->name, pos, len);

      

       if (!sect_size)

              return MTD_READ (mtd, pos, len, &retlen, buf);

 

       while (len > 0) {

              unsigned long sect_start = (pos/sect_size)*sect_size;

              unsigned int offset = pos - sect_start;

              unsigned int size = sect_size - offset;

              if (size > len)

                     size = len;

 

              /*

               * Check if the requested data is already cached

               * Read the requested amount of data from our internal cache if it

               * contains what we want, otherwise we read the data directly

               * from flash.

               */

              if (mtdblk->cache_state != STATE_EMPTY &&

                  mtdblk->cache_offset == sect_start) {

                     memcpy (buf, mtdblk->cache_data + offset, size);

              } else {

                     ret = MTD_READ (mtd, pos, size, &retlen, buf);

                     if (ret)

                            return ret;

                     if (retlen != size)

                            return -EIO;

              }

 

              buf += size;

              pos += size;

              len -= size;

       }

 

       return 0;

}

 

 

mtdblock_open

格式:

       static int mtdblock_open(struct inode *inode, struct file *file)

注释:

      

功能:

       打开一个MTD块设备(设备层)

说明:

       获得指定节点在原始设备层的MTD设备(mtd_table),

如果 其在设备层的对应块设备(mtdblks)被打开,返回,

否则 将其打开并初始化,

MTD设备的大小/1024赋给对应的mtd_sizes

MTD设备的erasesizePAGE_SIZE中较小的一个赋给对应的mtd_blksizes

参数:

       inode:指定的索引节点

       file:没用

返回:

       成功:返回0

       失败:返回错误码

调用:

       get_mtd_device()put_mtd_device()获取原始设备层的MTD设备

被调用:

       注册进mtd_fops结构

源代码:

{

       struct mtdblk_dev *mtdblk;

       struct mtd_info *mtd;

       int dev;

 

       DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open/n");

      

       if (!inode)

              return -EINVAL;

      

       dev = MINOR(inode->i_rdev);

       if (dev >= MAX_MTD_DEVICES)

              return -EINVAL;

 

       MOD_INC_USE_COUNT;

 

       mtd = get_mtd_device(NULL, dev);

       if (!mtd)

              return -ENODEV;

       if (MTD_ABSENT == mtd->type) {

              put_mtd_device(mtd);

              MOD_DEC_USE_COUNT;

              return -ENODEV;

       }

      

       spin_lock(&mtdblks_lock);

 

       /* If it's already open, no need to piss about. */

       if (mtdblks[dev]) {

              mtdblks[dev]->count++;

              spin_unlock(&mtdblks_lock);

              return 0;

       }

      

       /* OK, it's not open. Try to find it */

 

       /* First we have to drop the lock, because we have to

          to things which might sleep.

       */

       spin_unlock(&mtdblks_lock);

 

       mtdblk = kmalloc(sizeof(struct mtdblk_dev), GFP_KERNEL);

       if (!mtdblk) {

              put_mtd_device(mtd);

              MOD_DEC_USE_COUNT;

              return -ENOMEM;

       }

       memset(mtdblk, 0, sizeof(*mtdblk));

       mtdblk->count = 1;

       mtdblk->mtd = mtd;

 

       init_MUTEX (&mtdblk->cache_sem);

       mtdblk->cache_state = STATE_EMPTY;

       if ((mtdblk->mtd->flags & MTD_CAP_RAM) != MTD_CAP_RAM &&

           mtdblk->mtd->erasesize) {

              mtdblk->cache_size = mtdblk->mtd->erasesize;

              mtdblk->cache_data = vmalloc(mtdblk->mtd->erasesize);

              if (!mtdblk->cache_data) {

                     put_mtd_device(mtdblk->mtd);

                     kfree(mtdblk);

                     MOD_DEC_USE_COUNT;

                     return -ENOMEM;

              }

       }

 

       /* OK, we've created a new one. Add it to the list. */

 

       spin_lock(&mtdblks_lock);

 

       if (mtdblks[dev]) {

              /* Another CPU made one at the same time as us. */

              mtdblks[dev]->count++;

              spin_unlock(&mtdblks_lock);

              put_mtd_device(mtdblk->mtd);

              vfree(mtdblk->cache_data);

              kfree(mtdblk);

              return 0;

       }

 

       mtdblks[dev] = mtdblk;

       mtd_sizes[dev] = mtdblk->mtd->size/1024;

       if (mtdblk->mtd->erasesize)

              mtd_blksizes[dev] = mtdblk->mtd->erasesize;

       if (mtd_blksizes[dev] > PAGE_SIZE)

              mtd_blksizes[dev] = PAGE_SIZE;

       set_device_ro (inode->i_rdev, !(mtdblk->mtd->flags & MTD_WRITEABLE));

      

       spin_unlock(&mtdblks_lock);

      

       DEBUG(MTD_DEBUG_LEVEL1, "ok/n");

 

       return 0;

}

 

      

 

mtdblock_release

格式:

       static release_t mtdblock_release(struct inode *inode, struct file *file)

注释:

      

功能:

       释放一个设备层的MTD块设备

说明:

       调用write_cached_data刷新缓冲区,

       MTD块设备使用数减1,如果变为0,释放原始设备层的MTD设备

参数:

       inode:指定的索引节点

       file:无用

返回:

       成功:返回0

       inodeNULL:返回-ENODEV

调用:

       write_cached_data()刷新缓冲

       put_mtd_device()释放MTD设备

被调用:

       注册进mtd_fops结构

源代码:

{

       int dev;

       struct mtdblk_dev *mtdblk;

     DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release/n");

 

       if (inode == NULL)

              release_return(-ENODEV);

 

       invalidate_device(inode->i_rdev, 1);

 

       dev = MINOR(inode->i_rdev);

       mtdblk = mtdblks[dev];

 

       down(&mtdblk->cache_sem);

       write_cached_data(mtdblk);

       up(&mtdblk->cache_sem);

 

       spin_lock(&mtdblks_lock);

       if (!--mtdblk->count) {

              /* It was the last usage. Free the device */

              mtdblks[dev] = NULL;

              spin_unlock(&mtdblks_lock);

              if (mtdblk->mtd->sync)

                     mtdblk->mtd->sync(mtdblk->mtd);

              put_mtd_device(mtdblk->mtd);

              vfree(mtdblk->cache_data);

              kfree(mtdblk);

       } else {

              spin_unlock(&mtdblks_lock);

       }

 

       DEBUG(MTD_DEBUG_LEVEL1, "ok/n");

 

       MOD_DEC_USE_COUNT;

       release_return(0);

} 

 

 

handle_mtdblock_request

格式:

       static void handle_mtdblock_request(void)

注释:

/*

 * This is a special request_fn because it is executed in a process context

 * to be able to sleep independently of the caller.  The io_request_lock

 * is held upon entry and exit.

 * The head of our request queue is considered active so there is no need

 * to dequeue requests before we are done.

 */

功能:

       处理对MTD块设备的请求

说明:

       获取当前请求,分情况处理

参数:

      

返回:

      

调用:

       do_cached_read()处理读请求

       do_cached_write()处理写请求

被调用:

       mtdblock_thread()

源代码:

{

       struct request *req;

       struct mtdblk_dev *mtdblk;

       unsigned int res;

 

       for (;;) {

              INIT_REQUEST;

              req = CURRENT;

              spin_unlock_irq(&io_request_lock);

              mtdblk = mtdblks[MINOR(req->rq_dev)];

              res = 0;

 

              if (MINOR(req->rq_dev) >= MAX_MTD_DEVICES)

                     panic(__FUNCTION__": minor out of bound");

 

              if ((req->sector + req->current_nr_sectors) > (mtdblk->mtd->size >> 9))

                     goto end_req;

 

              // Handle the request

              switch (req->cmd)

              {

                     int err;

 

                     case READ:

                     down(&mtdblk->cache_sem);

                     err = do_cached_read (mtdblk, req->sector << 9,

                                   req->current_nr_sectors << 9,

                                   req->buffer);

                     up(&mtdblk->cache_sem);

                     if (!err)

                            res = 1;

                     break;

 

                     case WRITE:

                     // Read only device

                     if ( !(mtdblk->mtd->flags & MTD_WRITEABLE) )

                            break;

 

                     // Do the write

                     down(&mtdblk->cache_sem);

                     err = do_cached_write (mtdblk, req->sector << 9,

                                   req->current_nr_sectors << 9,

                                   req->buffer);

                     up(&mtdblk->cache_sem);

                     if (!err)

                            res = 1;

                     break;

              }

 

end_req:

              spin_lock_irq(&io_request_lock);

              end_request(res);

       }

}

 

leaving

static volatile int leaving = 0;         控制线程的变量,在mtdblock_thread作为测试条件,在cleanup_mtdblock中被赋1

mtdblock_thread

格式:

       int mtdblock_thread(void *dummy)

注释:

      

功能:

       启动一个MTD块设备线程

说明:

       调用handle_mtdblock_request()处理对MTD块设备的读写

参数:

       dummyFIXME

返回:

       线程结束:返回0

调用:

       handle_mtdblock_request()

被调用:

       init_mtdblock()

源代码:

{

       struct task_struct *tsk = current;

       DECLARE_WAITQUEUE(wait, tsk);

 

       tsk->session = 1;

       tsk->pgrp = 1;

       /* we might get involved when memory gets low, so use PF_MEMALLOC */

       tsk->flags |= PF_MEMALLOC;

       strcpy(tsk->comm, "mtdblockd");

       tsk->tty = NULL;

       spin_lock_irq(&tsk->sigmask_lock);

       sigfillset(&tsk->blocked);

       recalc_sigpending(tsk);

       spin_unlock_irq(&tsk->sigmask_lock);

       exit_mm(tsk);

       exit_files(tsk);

       exit_sighand(tsk);

       exit_fs(tsk);

 

       while (!leaving) {

              add_wait_queue(&thr_wq, &wait);

              set_current_state(TASK_INTERRUPTIBLE);

              spin_lock_irq(&io_request_lock);

              if (QUEUE_EMPTY || QUEUE_PLUGGED) {

                     spin_unlock_irq(&io_request_lock);

                     schedule();

                     remove_wait_queue(&thr_wq, &wait);

              } else {

                     remove_wait_queue(&thr_wq, &wait);

                     set_current_state(TASK_RUNNING);

                     handle_mtdblock_request();

                     spin_unlock_irq(&io_request_lock);

              }

       }

 

       up(&thread_sem);

       return 0;

}

 

 

mtdblock_ioctl

格式:

static int mtdblock_ioctl(struct inode * inode, struct file * file,

                    unsigned int cmd, unsigned long arg)

注释:

      

功能:

       MTD块设备的IO控制

说明:

      

参数:

       FIXME

返回:

       成功:返回0

       失败:返回错误码

调用:

       write_cached_data()

被调用:

       被注册进mtd_fops结构

源代码:

{

       struct mtdblk_dev *mtdblk;

 

       mtdblk = mtdblks[MINOR(inode->i_rdev)];

 

#ifdef PARANOIA

       if (!mtdblk)

              BUG();

#endif

 

       switch (cmd) {

       case BLKGETSIZE:   /* Return device size */

              return put_user((mtdblk->mtd->size >> 9), (long *) arg);

 

#ifdef BLKGETSIZE64

       case BLKGETSIZE64:

              return put_user((u64)mtdblk->mtd->size, (u64 *)arg);

#endif

             

       case BLKFLSBUF:

#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,0)

              if(!capable(CAP_SYS_ADMIN))

                     return -EACCES;

#endif

              fsync_dev(inode->i_rdev);

              invalidate_buffers(inode->i_rdev);

              down(&mtdblk->cache_sem);

              write_cached_data(mtdblk);

              up(&mtdblk->cache_sem);

              if (mtdblk->mtd->sync)

                     mtdblk->mtd->sync(mtdblk->mtd);

              return 0;

 

       default:

              return -EINVAL;

       }

}

 

mtd_fops

MTD块设备操作的函数结构

static struct block_device_operations mtd_fops =     

{

       open: mtdblock_open,

       release: mtdblock_release,

       ioctl: mtdblock_ioctl

};

 

 

init_mtdblock

格式:

       int __init init_mtdblock(void)

注释:

      

功能:

       初始化MTD块设备

说明:

       如果定义了CONFIG_DEVFS_FS{

              调用devfs_register_blkdev()注册块设备,

              调用register_mtd_user()将设备层MTD块设备的notifier注册进原始设备层

}

否则调用register_blkdev()注册块设备,

       初始化mtd_sizesmtd_blksizes数组,

       启动mtdblock_thread线程

参数:

      

返回:

       成功:返回0

       注册块设备失败:返回-EAGAIN

调用:

       kernel_thread()启动mtdblock_thread线程

       register_blkdev()注册块设备

被调用:

       module_init

       __init

源代码:

{

       int i;

 

       spin_lock_init(&mtdblks_lock);

#ifdef CONFIG_DEVFS_FS

       if (devfs_register_blkdev(MTD_BLOCK_MAJOR, DEVICE_NAME, &mtd_fops))

       {

              printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices./n",

                     MTD_BLOCK_MAJOR);

              return -EAGAIN;

       }

 

       devfs_dir_handle = devfs_mk_dir(NULL, DEVICE_NAME, NULL);

       register_mtd_user(&notifier);

#else

       if (register_blkdev(MAJOR_NR,DEVICE_NAME,&mtd_fops)) {

              printk(KERN_NOTICE "Can't allocate major number %d for Memory Technology Devices./n",

                     MTD_BLOCK_MAJOR);

              return -EAGAIN;

       }

#endif

      

       /* We fill it in at open() time. */

       for (i=0; i< MAX_MTD_DEVICES; i++) {

              mtd_sizes[i] = 0;

              mtd_blksizes[i] = BLOCK_SIZE;

       }

       init_waitqueue_head(&thr_wq);

       /* Allow the block size to default to BLOCK_SIZE. */

       blksize_size[MAJOR_NR] = mtd_blksizes;

       blk_size[MAJOR_NR] = mtd_sizes;

      

       blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &mtdblock_request);

       kernel_thread (mtdblock_thread, NULL, CLONE_FS|CLONE_FILES|CLONE_SIGHAND);

       return 0;

}

 

cleanup_mtdblock

格式:

       static void __exit cleanup_mtdblock(void)

注释:

      

功能:

       清除MTD块设备

说明:

       如果定义了CONFIG_DEVFS_FS{

              调用unregister_mtd_user()注销MTD块设备的notifier

              调用devfs_unregister_blkdev()注销MTD块设备

       }

否则调用unregister_blkdev()注销MTD块设备

参数:

      

返回:

      

调用:

       unregister_blkdev()注销MTD块设备

被调用:

       __exit

       module_exit

源代码:

{

       leaving = 1;

       wake_up(&thr_wq);

       down(&thread_sem);

#ifdef CONFIG_DEVFS_FS

       unregister_mtd_user(&notifier);

       devfs_unregister(devfs_dir_handle);

       devfs_unregister_blkdev(MTD_BLOCK_MAJOR, DEVICE_NAME);

#else

       unregister_blkdev(MAJOR_NR,DEVICE_NAME);

#endif

       blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));

       blksize_size[MAJOR_NR] = NULL;

       blk_size[MAJOR_NR] = NULL;

}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MTD(Moving Target Detection)是一种常见的目标检测算法,可以用于雷达、光学等多种传感器。以下是MTD的Matlab代码实现: ```matlab % 读取雷达数据 data = load('radar_data.mat'); radar_data = data.data; % 设置参数 num_pulses = size(radar_data, 1); num_range_bins = size(radar_data, 2); num_doppler_bins = 32; threshold = 2.5; pfa = 1e-6; % 初始化变量 mtd_data = zeros(num_pulses, num_range_bins); cfar_data = zeros(num_pulses, num_range_bins); % MTD算法 for i = 1:num_pulses for j = 1:num_range_bins % 计算Doppler频移 doppler_bins = round((j-1) / num_range_bins * num_doppler_bins) + 1; doppler_data = radar_data(i, j) .* exp(-1j*2*pi*(0:num_pulses-1)'*doppler_bins/num_pulses); doppler_data_fft = fft(doppler_data); % 计算MTI滤波器 mti_filter = (1 - exp(-1j*2*pi*(0:num_pulses-1)'/(num_pulses-1))).^3; doppler_data_filtered = ifft(doppler_data_fft .* mti_filter); % 计算MTDmtd_data(i, j) = abs(doppler_data_filtered(1)) / mean(abs(doppler_data_filtered(2:end))); end end % CFAR算法 for i = 1:num_pulses for j = 1:num_range_bins % 计算检测窗口 window_range_bins = max(1, j-4):min(num_range_bins, j+4); window_pulses = max(1, i-4):min(num_pulses, i+4); window_data = mtd_data(window_pulses, window_range_bins); % 计算局部均值和标准差 local_mean = mean(window_data(:)); local_std = std(window_data(:)); % 计算CFAR值 cfar_data(i, j) = (mtd_data(i, j) - local_mean) / local_std; end end % 检测目标 threshold_value = threshold * std(cfar_data(:)); detection_map = cfar_data > threshold_value; detection_indices = find(detection_map); % 计算PFA num_noise_samples = num_pulses * num_range_bins - length(detection_indices); pfa_value = num_noise_samples / (num_pulses * num_range_bins); % 显示结果 figure(); imagesc(abs(radar_data)); title('Radar Data'); colorbar(); figure(); imagesc(mtd_data); title('MTD Data'); colorbar(); figure(); imagesc(cfar_data); title('CFAR Data'); colorbar(); figure(); imagesc(detection_map); title(sprintf('Detection Map (PFA=%.2e)', pfa_value)); colorbar(); ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值