主机:Gentoo Linux 11.2 with linux kernel 3.0.6
硬件渠道:FL2440(S3C2440)with linux kernel 2.6.35
1、mtd_notifier结构体
- //MTD设备告诉结构体
- structmtd_notifier{
- void(*add)(structmtd_info*mtd);//参加MTD原始/字符/块设备时碑文
- void(*remove)(structmtd_info*mtd);//移除MTD原始/字符/块设备时碑文
- structlist_headlist;//list是双向链表,界说在include/linux/list.h
- };
而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函数
- /**
- *add_mtd_device-registeranMTDdevice
- *@mtd:pointertonewMTDdeviceinfostructure
- *
- *AddadevicetothelistofMTDdevicespresentinthesystem,and
- *notifyeachcurrentlyactiveMTDuserofitsarrival.Returns
- *zeroonsuccessor1onfailure,whichcurrentlywillonlyhappen
- *ifthereisinsufficientmemoryorasysfserror.
- */
- //添加MTD设备函数,将MTD设备参加MTD设备链表,并告诉一切的MTDuser该MTD设备。回来0一共成功,回来1一共犯错(内存不足或文件体系过错)
- intadd_mtd_device(structmtd_info*mtd)
- {
- structmtd_notifier*not;//界说一个MTD设备告诉器
- inti,error;
- //下面是设置mtd_info结构体信息
- if(!mtd->backing_dev_info){
- switch(mtd->type){
- caseMTD_RAM://MTD_RAM界说在include/mtd/mtd-abi.h
- mtd->backing_dev_info=&mtd_bdi_rw_mappable;
- break;
- caseMTD_ROM:
- mtd->backing_dev_info=&mtd_bdi_ro_mappable;
- break;
- default:
- mtd->backing_dev_info=&mtd_bdi_unmappable;
- break;
- }
- }
- BUG_ON(mtd->writesize==0);
- mutex_lock(&mtd_table_mutex);//给操作mtd_table加锁
- do{
- if(!idr_pre_get(&mtd_idr,GFP_KERNEL))//为mtd_idr分配内存
- gotofail_locked;
- error=idr_get_new(&mtd_idr,mtd,&i);//将id号和mtd_idr相关
- }while(error==-EAGAIN);
- if(error)
- gotofail_locked;
- mtd->index=i;
- mtd->usecount=0;
- if(is_power_of_2(mtd->erasesize))
- mtd->erasesize_shift=ffs(mtd->erasesize)-1;
- else
- mtd->erasesize_shift=0;
- if(is_power_of_2(mtd->writesize))
- mtd->writesize_shift=ffs(mtd->writesize)-1;
- else
- mtd->writesize_shift=0;
- mtd->erasesize_mask=(1<
erasesize_shift)-1; - mtd->writesize_mask=(1<
writesize_shift)-1; - /*Somechipsalwayspoweruplocked.Unlockthemnow*/
- if((mtd->flags&MTD_WRITEABLE)
- &&(mtd->flags&MTD_POWERUP_LOCK)&&mtd->unlock){
- if(mtd->unlock(mtd,0,mtd->size))
- printk(KERN_WARNING
- “%s:unlockfailed,writesmaynotwork\n”,
- mtd->name);
- }
- /*Callershouldhavesetdev.parenttomatchthe
- *physicaldevice.
- */
- mtd->dev.type=&mtd_devtype;
- mtd->dev.class=&mtd_class;
- mtd->dev.devt=MTD_DEVT(i);
- //设置mtd设备名
- dev_set_name(&mtd->dev,”mtd%d”,i);
- //设置mtd设备信息mtd_info
- dev_set_drvdata(&mtd->dev,mtd);
- //注册设备
- if(device_register(&mtd->dev)!=0)
- gotofail_added;
- //创立设备
- if(MTD_DEVT(i))
- device_create(&mtd_class,mtd->dev.parent,
- MTD_DEVT(i)+1,
- NULL,”mtd%dro”,i);
- DEBUG(0,”mtd:Givingoutdevice%dto%s\n”,i,mtd->name);
- /*Noneedtogetarefcountonthemodulecontaining
- thenotifier,sinceweholdthemtd_table_mutex*/
- //遍历list链表将每个mtd_notifier碑文add()函数,对新参加的mtd设备操作,告诉一切的MTDuser新的MTD设备的到来
- list_for_each_entry(not,&mtd_notifiers,list)
- not->add(mtd);
- //解锁信号量
- mutex_unlock(&mtd_table_mutex);
- /*We_know_wearentbeingremoved,because
- ourcallerisstillholdingushere.Sonone
- ofthistry_nonsense,andnobitchingaboutit
- either.:)*/
- __module_get(THIS_MODULE);
- return0;
- fail_added:
- idr_remove(&mtd_idr,i);
- fail_locked:
- mutex_unlock(&mtd_table_mutex);
- return1;
- }
其间用到的IDR机制如下:
(1)取得idr
要在代码中运用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函数
- /**
- *del_mtd_device-unregisteranMTDdevice
- *@mtd:pointertoMTDdeviceinfostructure
- *
- *RemoveadevicefromthelistofMTDdevicespresentinthesystem,
- *andnotifyeachcurrentlyactiveMTDuserofitsdeparture.
- *Returnszeroonsuccessor1onfailure,whichcurrentlywillhappen
- *iftherequesteddevicedoesnotappeartobepresentinthelist.
- */
- //删去mtd设备函数。
- //从MTD设备的链表中移除该MTD设备信息,并告诉体系中一切的MTDuser该MTD设备的移除。
- //回来0一共成功,回来1一共犯错(该设备信息不存在设备链表中)
- intdel_mtd_device(structmtd_info*mtd)
- {
- intret;
- structmtd_notifier*not;//界说一个mtd_notifier指针
- mutex_lock(&mtd_table_mutex);
- if(idr_find(&mtd_idr,mtd->index)!=mtd){
- ret=-ENODEV;
- gotoout_error;
- }
- /*Noneedtogetarefcountonthemodulecontaining
- thenotifier,sinceweholdthemtd_table_mutex*/
- //遍历list链表,并使每个mtd_notifier碑文remove函数,告诉每个MTDuser该设备的移除
- list_for_each_entry(not,&mtd_notifiers,list)
- not->remove(mtd);
- if(mtd->usecount){
- printk(KERN_NOTICE”RemovingMTDdevice#%d(%s)withusecount%d\n”,
- mtd->index,mtd->name,mtd->usecount);
- ret=-EBUSY;
- }else{
- device_unregister(&mtd->dev);//移除MTD设备
- idr_remove(&mtd_idr,mtd->index);//移除mtd的id号并开释已分配的内存
- module_put(THIS_MODULE);
- ret=0;
- }
- out_error:
- mutex_unlock(&mtd_table_mutex);
- returnret;
- }
4、register_mtd_user函数
- /**
- *register_mtd_user-registerauserofMTDdevices.
- *@new:pointertonotifierinfostructure
- *
- *Registersapairofcallbacksfunctiontobecalleduponaddition
- *orremovalofMTDdevices.Causestheaddcallbacktobeimmediately
- *invokedforeachMTDdevicecurrentlypresentinthesystem.
- */
- //MTD原始设备运用者注册MTD设备(详细的字符设备或块设备)
- //参数是新的mtd告诉器,将其参加mtd_notifiers行列,然后
- voidregister_mtd_user(structmtd_notifier*new)
- {
- structmtd_info*mtd;
- mutex_lock(&mtd_table_mutex);
- //将new->list头插mtd_notifiers入链表
- list_add(&new->list,&mtd_notifiers);
- __module_get(THIS_MODULE);
- //对每个MTD原始设备碑文add函数
- mtd_for_each_device(mtd)
- new->add(mtd);
- mutex_unlock(&mtd_table_mutex);
- }
5、unregister_mtd_user函数
- /**
- *unregister_mtd_user-unregisterauserofMTDdevices.
- *@old:pointertonotifierinfostructure
- *
- *Removesacallbackfunctionpairfromthelistofuserstobe
- *notifieduponadditionorremovalofMTDdevices.Causesthe
- *removecallbacktobeimmediatelyinvokedforeachMTDdevice
- *currentlypresentinthesystem.
- */
- //删去MTD设备。
- //告诉一切该MTD原始设备的MTD设备碑文remove()函数,将被删去的MTD设备的告诉器从mtd_notifier行列中删去
- intunregister_mtd_user(structmtd_notifier*old)
- {
- structmtd_info*mtd;
- mutex_lock(&mtd_table_mutex);
- module_put(THIS_MODULE);
- //告诉一切该MTD原始设备的MTD设备碑文remove()函数
- mtd_for_each_device(mtd)
- old->remove(mtd);
- //将被删去的MTD设备的告诉器从mtd_notifier行列中删去
- list_del(&old->list);
- mutex_unlock(&mtd_table_mutex);
- return0;
- }
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)
下面现剖析第一个函数
- /**
- *get_mtd_device-obtainavalidatedhandleforanMTDdevice
- *@mtd:lastknownaddressoftherequiredMTDdevice
- *@num:internaldevicenumberoftherequiredMTDdevice
- *
- *GivenanumberandNULLaddress,returnthenumthentryinthedevice
- *table,ifany.Givenanaddressandnum==-1,searchthedevicetable
- *foradevicewiththataddressandreturnifitsstillpresent.Given
- *both,returnthenumthdriveronlyifitsaddressmatches.Return
- *errorcodeifnot.
- */
- //依据设备地址来获取MTD设备的操作地址
- structmtd_info*get_mtd_device(structmtd_info*mtd,intnum)
- {
- structmtd_info*ret=NULL,*other;
- interr=-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;
- }
- }
- }elseif(num>=0){//num>=0,查找第num个设备,若不空,回来地址,若为空,回来NULL
- ret=idr_find(&mtd_idr,num);
- if(mtd&&mtd!=ret)
- ret=NULL;
- }
- if(!ret){
- ret=ERR_PTR(err);
- gotoout;
- }
- err=__get_mtd_device(ret);
- //过错处理
- if(err)
- ret=ERR_PTR(err);
- out:
- mutex_unlock(&mtd_table_mutex);//解锁互斥信号量
- returnret;
- }
- int__get_mtd_device(structmtd_info*mtd)
- {
- interr;
- if(!try_module_get(mtd->owner))
- return-ENODEV;
- if(mtd->get_device){
- err=mtd->get_device(mtd);
- if(err){
- module_put(mtd->owner);
- returnerr;
- }
- }
- mtd->usecount++;//添加该MTD原始设备的运用者计数器
- return0;
- }
第二个函数
- /**
- *get_mtd_device_nm-obtainavalidatedhandleforanMTDdeviceby
- *devicename
- *@name:MTDdevicenametoopen
- *
- *ThisfunctionreturnsMTDdevicedescriptionstructureincaseof
- *successandanerrorcodeincaseoffailure.
- */
- //经过设备名来取得相应的MTD原始设备的操作地址
- //该函数和上面的函数相似,不过便是经过循环比较MTD设备的name字段来回来
- structmtd_info*get_mtd_device_nm(constchar*name)
- {
- interr=-ENODEV;
- structmtd_info*mtd=NULL,*other;
- mutex_lock(&mtd_table_mutex);
- mtd_for_each_device(other){
- if(!strcmp(name,other->name)){
- mtd=other;
- break;
- }
- }
- if(!mtd)
- gotoout_unlock;
- if(!try_module_get(mtd->owner))
- gotoout_unlock;
- if(mtd->get_device){
- err=mtd->get_device(mtd);
- if(err)
- gotoout_put;
- }
- mtd->usecount++;
- mutex_unlock(&mtd_table_mutex);
- returnmtd;
- out_put:
- module_put(mtd->owner);
- out_unlock:
- mutex_unlock(&mtd_table_mutex);
- returnERR_PTR(err);
- }