本帖最后由 forlinx2013 于 2014-1-24 09:20 编辑
欢迎大家来到飞凌爱板网专区,对嵌入式技术感兴趣的朋友不妨多多关注一下,我们提供了公司所有开发板的所有资料,也会更新大量技术文章,欢迎大家一块学习提高!!!
主机:Gentoo Linux 11.2 with linux kernel 3.0.6
硬件平台:FL2440(S3C2440)with linux kernel 2.6.35
1、mtd_notifier结构体 1 //MTD设备通知结构体 2 struct mtd_notifier { 3 void (*add)(struct mtd_info *mtd);//加入MTD原始/字符/块设备时执行 4 void (*remove)(struct mtd_info *mtd);//移除MTD原始/字符/块设备时执行 5 struct list_head list;//list是双向链表,定义在include/linux/list.h 6 }; 而struct list_head定义在/include/linux/list.h中,内核中其宏定义和函数如下 INIT_LIST_HEAD(ptr) 初始化ptr节点为表头,将前趋与后继都指向自己。
LIST_HEAD(name) 声明并初始化双向循环链表name。
static inline void __list_add(struct list_head *new, struct list_head *prev, struct list_head *next)
向链表中在prev与next之间插入元素new
static inline void list_add(struct list_head *new, struct list_head *head)
在链表中头节点后插入元素new,调用__list_add()实现。
static inline void list_add_tail(struct list_head *new, struct list_head *head)
在链表末尾插入元素new,调用__list_add()实现。
static inline void __list_del(struct list_head * prev, struct list_head * next)
删除链表中prev与next之间的元素。
static inline void list_del(struct list_head *entry)
删除链表中的元素entry。
static inline void list_del_init(struct list_head *entry)
从链表中删除元素entry,并将其初始化为新的链表。
static inline void list_move(struct list_head *list, struct list_head *head)
从链表中删除list元素,并将其加入head链表。
static inline void list_move_tail(struct list_head *list, struct list_head *head)
把list移动到链表末尾。
static inline int list_empty(const struct list_head *head)
测试链表是否为空。
static inline void __list_splice(struct list_head *list, struct list_head *head)
将链表list与head合并。
static inline void list_splice(struct list_head *list, struct list_head *head)
在list不为空的情况下,调用__list_splice()实现list与head的合并。
static inline void list_splice_init(struct list_head *list, struct list_head *head)
将两链表合并,并将list初始化。
list_entry(ptr, type, member)
list_entry的定义是怎么回事?
a. list_entry的定义在内核源文件include/linux/list.h中:
#define list_entry(ptr, type, member)
((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
b. 其功能是根据list_head型指针ptr换算成其宿主结构的起始地址,该宿主结构是type型的,而ptr在其宿主结构中定义为member成员。
2、add_mtd_device函数 7 /** 8 * add_mtd_device - register an MTD device 9 * @mtd: pointer to new MTD device info structure 10 * 11 * Add a device to the list of MTD devices present in the system, and 12 * notify each currently active MTD 'user' of its arrival. Returns 13 * zero on success or 1 on failure, which currently will only happen 14 * if there is insufficient memory or a sysfs error. 15 */ 16 //添加MTD设备函数,将MTD设备加入MTD设备链表,并通知所有的MTD user该MTD设备。返回0表示成功,返回1表示出错(内存不足或文件系统错误) 17 int add_mtd_device(struct mtd_info *mtd) 18 { 19 struct mtd_notifier *not;//定义一个MTD设备通知器 20 int i, error; 21 22 //下面是设置mtd_info结构体信息 23 if (!mtd->backing_dev_info) { 24 switch (mtd->type) { 25 case MTD_RAM://MTD_RAM定义在include/mtd/mtd-abi.h 26 mtd->backing_dev_info = &mtd_bdi_rw_mappable; 27 break; 28 case MTD_ROM: 29 mtd->backing_dev_info = &mtd_bdi_ro_mappable; 30 break; 31 default: 32 mtd->backing_dev_info = &mtd_bdi_unmappable; 33 break; 34 } 35 } 36 37 BUG_ON(mtd->writesize == 0); 38 mutex_lock(&mtd_table_mutex);//给操作mtd_table加锁 39 40 do { 41 if (!idr_pre_get(&mtd_idr, GFP_KERNEL))//为mtd_idr分配内存 42 goto fail_locked; 43 error = idr_get_new(&mtd_idr, mtd, &i);//将id号和mtd_idr关联 44 } while (error == -EAGAIN); 45 46 if (error) 47 goto fail_locked; 48 49 mtd->index = i; 50 mtd->usecount = 0; 51 52 if (is_power_of_2(mtd->erasesize)) 53 mtd->erasesize_shift = ffs(mtd->erasesize) - 1; 54 else 55 mtd->erasesize_shift = 0; 56 57 if (is_power_of_2(mtd->writesize)) 58 mtd->writesize_shift = ffs(mtd->writesize) - 1; 59 else 60 mtd->writesize_shift = 0; 61 62 mtd->erasesize_mask = (1 << mtd->erasesize_shift) - 1; 63 mtd->writesize_mask = (1 << mtd->writesize_shift) - 1; 64 65 /* Some chips always power up locked. Unlock them now */ 66 if ((mtd->flags & MTD_WRITEABLE) 67 && (mtd->flags & MTD_POWERUP_LOCK) && mtd->unlock) { 68 if (mtd->unlock(mtd, 0, mtd->size)) 69 printk(KERN_WARNING 70 "%s: unlock failed, writes may not work\n", 71 mtd->name); 72 } 73 74 /* Caller should have set dev.parent to match the 75 * physical device. 76 */ 77 mtd->dev.type = &mtd_devtype; 78 mtd->dev.class = &mtd_class; 79 mtd->dev.devt = MTD_DEVT(i); 80 //设置mtd设备名 81 dev_set_name(&mtd->dev, "mtd%d", i); 82 //设置mtd设备信息mtd_info 83 dev_set_drvdata(&mtd->dev, mtd); 84 85 //注册设备 86 if (device_register(&mtd->dev) != 0) 87 goto fail_added; 88 89 //创建设备 90 if (MTD_DEVT(i)) 91 device_create(&mtd_class, mtd->dev.parent, 92 MTD_DEVT(i) + 1, 93 NULL, "mtd%dro", i); 94 95 DEBUG(0, "mtd: Giving out device %d to %s\n", i, mtd->name); 96 /* No need to get a refcount on the module containing 97 the notifier, since we hold the mtd_table_mutex */ 98 //遍历list链表将每个mtd_notifier执行add()函数,对新加入的mtd设备操作,通知所有的MTD user新的MTD设备的到来 99 list_for_each_entry(not, &mtd_notifiers, list) 100 not->add(mtd); 101 102 //解锁信号量 103 mutex_unlock(&mtd_table_mutex); 104 /* We _know_ we aren't being removed, because 105 our caller is still holding us here. So none 106 of this try_ nonsense, and no bitching about it 107 either. */ 108 __module_get(THIS_MODULE); 109 return 0; 110 111 fail_added: 112 idr_remove(&mtd_idr, i); 113 fail_locked: 114 mutex_unlock(&mtd_table_mutex); 115 return 1; 116 } 其中用到的IDR机制如下: (1)获得idr
要在代码中使用idr,首先要包括<linux/idr.h>。接下来,我们要在代码中分配idr结构体,并初始化:
void idr_init(struct idr *idp);
其中idr定义如下:
struct idr {
struct idr_layer *top;
struct idr_layer *id_free;
int layers;
int id_free_cnt;
spinlock_t lock;
};
/* idr是idr机制的核心结构体 */
(2)为idr分配内存
int idr_pre_get(struct idr *idp, unsigned int gfp_mask);
每次通过idr获得ID号之前,需要先分配内存。
返回0表示错误,非零值代表正常
(3)分配ID号并将ID号和指针关联
int idr_get_new(struct idr *idp, void *ptr, int *id);
int idr_get_new_above(struct idr *idp, void *ptr, int start_id, int *id);
idp: 之前通过idr_init初始化的idr指针
id: 由内核自动分配的ID号
ptr: 和ID号相关联的指针
start_id: 起始ID号。内核在分配ID号时,会从start_id开始。如果为I2C节点分配ID号,可以将设备地址作为start_id
函数调用正常返回0,如果没有ID可以分配,则返回-ENOSPC
在实际中,上述函数常常采用如下方式使用:
again:
if (idr_pre_get(&my_idr, GFP_KERNEL) == 0) {
/* No memory, give up entirely */
}
spin_lock(&my_lock);
result = idr_get_new(&my_idr, &target, &id);
if (result == -EAGAIN) {
sigh();
spin_unlock(&my_lock);
goto again;
}
(4)通过ID号搜索对应的指针
void *idr_find(struct idr *idp, int id);
返回值是和给定id相关联的指针,如果没有,则返回NULL
(5)删除ID
要删除一个ID,使用:
void idr_remove(struct idr *idp, int id);
通过上面这些方法,内核代码可以为子设备,inode生成对应的ID号。这些函数都定义在lib/idr.c中 3、del_mtd_device函数 117 /** 118 * del_mtd_device - unregister an MTD device 119 * @mtd: pointer to MTD device info structure 120 * 121 * Remove a device from the list of MTD devices present in the system, 122 * and notify each currently active MTD 'user' of its departure. 123 * Returns zero on success or 1 on failure, which currently will happen 124 * if the requested device does not appear to be present in the list. 125 */ 126 //删除mtd设备函数。 127 //从MTD设备的链表中移除该MTD设备信息,并通知系统中所有的MTD user该MTD设备的移除。 128 //返回0表示成功,返回1表示出错(该设备信息不存在设备链表中) 129 int del_mtd_device (struct mtd_info *mtd) 130 { 131 int ret; 132 struct mtd_notifier *not;//定义一个mtd_notifier指针 133 134 mutex_lock(&mtd_table_mutex); 135 136 if (idr_find(&mtd_idr, mtd->index) != mtd) { 137 ret = -ENODEV; 138 goto out_error; 139 } 140 141 /* No need to get a refcount on the module containing 142 the notifier, since we hold the mtd_table_mutex */ 143 //遍历list链表,并使每个mtd_notifier执行remove函数,通知每个MTD user该设备的移除 144 list_for_each_entry(not, &mtd_notifiers, list) 145 not->remove(mtd); 146 147 if (mtd->usecount) { 148 printk(KERN_NOTICE "Removing MTD device #%d (%s) with use count %d\n", 149 mtd->index, mtd->name, mtd->usecount); 150 ret = -EBUSY; 151 } else { 152 device_unregister(&mtd->dev);//移除MTD设备 153 154 idr_remove(&mtd_idr, mtd->index);//移除mtd的id号并释放已分配的内存 155 156 module_put(THIS_MODULE); 157 ret = 0; 158 } 159 160 out_error: 161 mutex_unlock(&mtd_table_mutex); 162 return ret; 163 } 4、register_mtd_user函数 164 /** 165 * register_mtd_user - register a 'user' of MTD devices. 166 * @new: pointer to notifier info structure 167 * 168 * Registers a pair of callbacks function to be called upon addition 169 * or removal of MTD devices. Causes the 'add' callback to be immediately 170 * invoked for each MTD device currently present in the system. 171 */ 172 //MTD原始设备使用者注册MTD设备(具体的字符设备或块设备) 173 //参数是新的mtd通知器,将其加入mtd_notifiers队列,然后 174 void register_mtd_user (struct mtd_notifier *new) 175 { 176 struct mtd_info *mtd; 177 178 mutex_lock(&mtd_table_mutex); 179 180 //将new->list头插mtd_notifiers入链表 181 list_add(&new->list, &mtd_notifiers); 182 183 __module_get(THIS_MODULE); 184 185 //对每个MTD原始设备执行add函数 186 mtd_for_each_device(mtd) 187 new->add(mtd); 188 189 mutex_unlock(&mtd_table_mutex); 190 } 5、unregister_mtd_user函数 191 /** 192 * unregister_mtd_user - unregister a 'user' of MTD devices. 193 * @old: pointer to notifier info structure 194 * 195 * Removes a callback function pair from the list of 'users' to be 196 * notified upon addition or removal of MTD devices. Causes the 197 * 'remove' callback to be immediately invoked for each MTD device 198 * currently present in the system. 199 */ 200 //删除MTD设备。 201 //通知所有该MTD原始设备的MTD设备执行remove()函数,将被删除的MTD设备的通知器从mtd_notifier队列中删除 202 int unregister_mtd_user (struct mtd_notifier *old) 203 { 204 struct mtd_info *mtd; 205 206 mutex_lock(&mtd_table_mutex); 207 208 module_put(THIS_MODULE); 209 210 //通知所有该MTD原始设备的MTD设备执行remove()函数 211 mtd_for_each_device(mtd) 212 old->remove(mtd); 213 214 //将被删除的MTD设备的通知器从mtd_notifier队列中删除 215 list_del(&old->list); 216 mutex_unlock(&mtd_table_mutex); 217 return 0; 218 } 6、获取MTD设备的操作指针,只是参数不同,一个是按照设备地址,另一个是安装设备的名称来获取MTD设备的操作地址 struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num) struct mtd_info *get_mtd_device_nm(const char *name) 下面现分析第一个函数 219 /** 220 * get_mtd_device - obtain a validated handle for an MTD device 221 * @mtd: last known address of the required MTD device 222 * @num: internal device number of the required MTD device 223 * 224 * Given a number and NULL address, return the num'th entry in the device 225 * table, if any. Given an address and num == -1, search the device table 226 * for a device with that address and return if it's still present. Given 227 * both, return the num'th driver only if its address matches. Return 228 * error code if not. 229 */ 230 //根据设备地址来获取MTD设备的操作地址 231 struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num) 232 { 233 struct mtd_info *ret = NULL, *other; 234 int err = -ENODEV; 235 236 //给mtd_table加锁,以便互斥访问 237 mutex_lock(&mtd_table_mutex); 238 239 if (num == -1) {//num=-1&&链表不空,则返回mtd的地址 240 mtd_for_each_device(other) { 241 if (other == mtd) { 242 ret = mtd; 243 break; 244 } 245 } 246 } else if (num >= 0) {//num>=0,查找第num个设备,若不空,返回地址,若为空,返回NULL 247 ret = idr_find(&mtd_idr, num); 248 if (mtd && mtd != ret) 249 ret = NULL; 250 } 251 252 if (!ret) { 253 ret = ERR_PTR(err); 254 goto out; 255 } 256 257 err = __get_mtd_device(ret); 258 //错误处理 259 if (err) 260 ret = ERR_PTR(err); 261 out: 262 mutex_unlock(&mtd_table_mutex);//解锁互斥信号量 263 return ret; 264 } 265 266 267 int __get_mtd_device(struct mtd_info *mtd) 268 { 269 int err; 270 271 if (!try_module_get(mtd->owner)) 272 return -ENODEV; 273 274 if (mtd->get_device) { 275 276 err = mtd->get_device(mtd); 277 278 if (err) { 279 module_put(mtd->owner); 280 return err; 281 } 282 } 283 mtd->usecount++;//增加该MTD原始设备的使用者计数器 284 return 0; 285 } /** * 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 * error code if not. */ //根据设备地址来获取MTD设备的操作地址 struct mtd_info *get_mtd_device(struct mtd_info *mtd, int num) { struct mtd_info *ret = NULL, *other; int err = -ENODEV;
//给mtd_table加锁,以便互斥访问 mutex_lock(&mtd_table_mutex);
if (num == -1) {//num=-1&&链表不空,则返回mtd的地址 mtd_for_each_device(other) { if (other == mtd) { ret = mtd; break; } } } else if (num >= 0) {//num>=0,查找第num个设备,若不空,返回地址,若为空,返回NULL ret = idr_find(&mtd_idr, num); if (mtd && mtd != ret) ret = NULL; }
if (!ret) { ret = ERR_PTR(err); goto out; }
err = __get_mtd_device(ret); //错误处理 if (err) ret = ERR_PTR(err); out: mutex_unlock(&mtd_table_mutex);//解锁互斥信号量 return ret; }
int __get_mtd_device(struct mtd_info *mtd) { int err;
if (!try_module_get(mtd->owner)) return -ENODEV;
if (mtd->get_device) {
err = mtd->get_device(mtd);
if (err) { module_put(mtd->owner); return err; } } mtd->usecount++;//增加该MTD原始设备的使用者计数器 return 0; }
第二个函数
286 /** 287 * get_mtd_device_nm - obtain a validated handle for an MTD device by 288 * device name 289 * @name: MTD device name to open 290 * 291 * This function returns MTD device description structure in case of 292 * success and an error code in case of failure. 293 */ 294 //通过设备名来获得相应的MTD原始设备的操作地址 295 //该函数和上面的函数类似,不过就是通过循环比较MTD设备的name字段来返回 296 struct mtd_info *get_mtd_device_nm(const char *name) 297 { 298 int err = -ENODEV; 299 struct mtd_info *mtd = NULL, *other; 300 301 mutex_lock(&mtd_table_mutex); 302 303 mtd_for_each_device(other) { 304 if (!strcmp(name, other->name)) { 305 mtd = other; 306 break; 307 } 308 } 309 310 if (!mtd) 311 goto out_unlock; 312 313 if (!try_module_get(mtd->owner)) 314 goto out_unlock; 315 316 if (mtd->get_device) { 317 err = mtd->get_device(mtd); 318 if (err) 319 goto out_put; 320 } 321 322 mtd->usecount++; 323 mutex_unlock(&mtd_table_mutex); 324 return mtd; 325 326 out_put: 327 module_put(mtd->owner); 328 out_unlock: 329 mutex_unlock(&mtd_table_mutex); 330 return ERR_PTR(err); 331 }
|