您的位置 首页 测评

arm 驱动linux内核驱动之中止下半部编程

本文部分参考华清远见文档中断上半部要求执行时间间隔段,所以往往将处理时间较长的代码放在中断下半部来处理中断下半部的应用:网卡驱动上…

本文部分参阅华清远见文档

中止上半部要求碑文时刻距离段,所以往往将处理时刻较长的代码放在中止下半部来处理

中止下半部的运用:网卡驱动上半部初始化网卡驱动等短时刻的作业,下半部收发数据

中止下半部:

a, 下半部发生的原因:

1,中止上下文中不能堵塞,这也约束了中止上下文中能干的事

2,中止处理函数碑文过程中仍有或许被其他中止打断,都期望中止处理函数碑文得越快越好。

根据上面的原因,内核将整个的中止处理流程分为了上半部和下半部。上半部便是之前所说的中止处理函数,它能最快的呼应中止,而且做一些有必要在中止呼应之后立刻要做的作业。而一些需求在中止处理函数后持续碑文的操作,内核主张把它放在下半部碑文。

比方:在linux内核中,当网卡一旦接受到数据,网卡会经过中止告知内核处理数据,内核会在网卡中止处理函数(上半部)碑文一些网卡硬件的必要设置,由于这是在中止呼应后急切要干的作业。接着,内核调用对应的下半部函数来处理网卡接收到的数据,由于数据处理没必要在中止处理函数晒干立刻碑文,能够将中止让出来做更急迫的作业

b,中止下半部完结的机制分类

tasklet:

workqueue:作业行列

timer:定时器

其实还有一种,叫softirq,但要写代码的话,就有必要修正本来的内核结构代码,在实践开发顶用的比较少,tasklet内部完结便是用softeirq

c, 中止下半部完结办法

1, tasklet的编程办法

1.1 : 界说并初始化结构体tasklet_struct(一般在哪里初始化:是在模块卸载办法中)

struct tasklet_struct

{

struct tasklet_struct *next; // l链表

unsigned long state;

atomic_t count;

void (*func)(unsigned long); // 下半部处理办法的完结

unsigned long data;//给处理函数的传参

};

初始化办法:

静态:DECLARE_TASKLET(name, func, data);

DCLARE_TASKLET_DISABLED初始化后的处于禁止状态,暂时不能被运用(不是中止),除非被激活

参数1:tasklet_struct 的变量姓名,自界说

参数2:中止下半部碑文的处理函数.类型为函数指针

参数3:处理函数带的参数

动态:void tasklet_init(struct tasklet_struct * t, void(* func)(unsigned long), unsigned long data);

参数1:tasklet_struct 目标

参数2:中止下半部碑文的处理函数

参数3:处理函数带的参数

1.2: 在中止上半部中调度下半部

void tasklet_schedule(struct tasklet_struct * t);

1.3: 在模块卸载时,毁掉这个tasklet_struct 目标

void tasklet_kill(struct tasklet_struct *t)

1.4:原理:初始化好struct tasklet_struct目标后,tasklet_schedule()会将tasklet目标加到链表中,内核稍后会去调度这个tasklet目标

1.5: 特色:优先级高,调度快,运行在中止上下文中,所以在处理办法中,不能碑文堵塞/睡觉的操作

2,workqueque编程办法:

2.1 :界说并初始化workqueue_struct(一个行列)和work_struct(行列中的一项作业)目标

work_struct目标的初始化

struct work_struct {

atomic_long_t data; // 传递给work的参数

struct list_head entry; // 地点行列的链表

work_func_t func; // work对应的处理办法

};

静态:DECLARE_WORK(n, f)

参数1: 变量名,自界说

参数2:work对应的处理办法,类型为函数指针

动态:INIT_WORK(_work, _func)

参数1: 指针,先声明一个struct work_struct变量,将变量地址填入

参数2:work对应的处理办法,类型为函数指针

返回值: 返回值为void

workqueue_struct目标的初始化:(其实便是一个内核线程)

1, 从头创立一个行列

create_workqueue(name)//这个自身便是一个宏

参数:姓名,自界说,用于辨认

返回值:struct workqueue_struct *

2, 体系在开机的时分主动创立一个行列

2.2 将作业目标参加作业行列中,并参加调度(留意不是立刻调度,该过程也是中止上半部中调用)

int queue_work(struct workqueue_struct *wq, struct work_struct *work)

参数1:作业行列

参数2: 作业目标

返回值: 0一共现已放到行列上了(也即时说本次归于重复操作),其实一般咱们都不会去做犯错处理

2.3 在模块刊出的时分,毁掉作业行列和作业目标

void flush_workqueue(struct workqueue_struct * wq)

该函数会一向等候,知道指定的等候行列中所有的使命都碑文结束并从等候行列中移除。

void destroy_workqueue(struct workqueue_struct * wq);

该函数是是创立等候行列的反操作,刊出掉指定的等候行列。

2.4: 关于运用内核自带的作业行列events, 操作过程如下:

2.4.1 初始化作业目标,无需创立行列了

静态:DECLARE_WORK(n, f)

动态:INIT_WORK(_work, _func)

2.4.2将作业参加行列并调度(在中止上半部中调度)

int schedule_work(struct work_struct * work)

只需两过程就完结,也不需求改写,也不要毁掉,由于这个作业行列是体系管理的,咱们不必管

2.5:原理整理:在作业行列中,有专门的作业者线程来处理参加到作业对列中的使命。作业对列对应的作业者线程或许不止一个,每个处理器有且仅有一个作业行列 对应的作业者线程,在内核中有一个默许的作业行列events,关于单处理器只要一个对应的作业者线程

3, 定时器timer编程办法:(以上两个下半部处理都是内核在一个特定的时分进行调度,时刻不定,而timer能够指定某个时刻点碑文)

3.1, jiffies,一共从体系启动到当时的时刻值,一般做加法(+5HZ(5s),)

3.2, 界说并初始化 timer_list目标

struct timer_list {

struct list_head entry; // 链表

unsigned long expires; // 过期时刻。也及时在什么时分碑文处理办法

struct tvec_base *base;

void (*function)(unsigned long); // 处理办法

unsigned long data; // 处理办法能够传递的参数

int slack;

};

静态初始化:TIMER_INITIALIZER(_function, _expires, _data)

动态初始化:void init_timer(timer)

参数:为一个指针,需求传递一个struct timer_list目标的地址

该函数仅仅初始化了timer_list目标的部分成员,还有以下成员是需求编程的:

struct timer_list mytimer;

init_timer(&mytimer);

mytimer.expires = jiffies + 2HZ

mytimer.fuction = my_timer_func; // 自己去完结

mytimer.data = (unsigned long)99; // 能够传递参数

3.3, 激活timer,开端计时 (一般也是放在中止上半部完结)

void add_timer(&mytimer);

3.4 计时结束是,也便是要碑文处理函数时,碑文函数中要下一次计时的话,有必要修正timer

mod_timer(&my_timer, jiffies + 2*HZ);

// 2s之后再来,相当于如下:

my_timer.expires = jiffies + 2*HZ; //从头设定时刻,在两秒后再碑文

add_timer(&my_timer); //再次激活定时器

3.5 定时器的毁掉

int del_timer(struct timer_list *timer) // 该函数用来删去还没超时的定时器

timer定时器的中止上下半部代码

#include #include #include #include #include #include #include #include interrupt.h>
#include

#include arm/param.h>
#include
#include
#define VIRTUAL_MAJOR 250
int major = VIRTUAL_MAJOR;

struct myirq_desc{
int irq_id;
char *irq_name;
int irq_code;
};

struct myirq_desc myirq_descs[3]= {
{S3C2410_GPF0, “s2”, KEY_A},
{S3C2410_GPF2, “s3”, KEY_K},
{S3C2410_GPG3, “s4”, KEY_Z},
};
struct VirtualDisk{
struct class *mycdevclass;//在/sys/class创立类
struct class_device *mycdevclassdevice;//在/dev下创立设备
struct cdev mycdev;//给设备增加相关的fileoption
struct timer_list mytimer;
};
struct VirtualDisk *myvirtualdisk;

static struct file_operations mydev_fops = {
.owner = THIS_MODULE,
};
static void mytimer_func(unsigned long fundata){
printk(“*******%s********\n”, __FUNCTION__);
struct VirtualDisk *myvirtualdisk_fun = (struct VirtualDisk *)(fundata);
myvirtualdisk_fun->mytimer.expires =jiffies + 2 * HZ;
add_timer(&myvirtualdisk_fun->mytimer);
printk(“timer func happened!\n”);
}
static irqreturn_t myirq_handle(int irq, void *dev_id){
struct myirq_desc *myirq_descone = (struct myirq_desc *)dev_id;
printk(“*******%s********\n”, __FUNCTION__);
printk(“irq = %d, irq_id = %d,irq_name = %s, irq_code = %c\n”, irq, myirq_descone->irq_id, myirq_descone->irq_name, myirq_descone->irq_code);
mod_timer(&myvirtualdisk->mytimer, jiffies + 2*HZ);
return IRQ_RETVAL(IRQ_HANDLED);
}

static int __init cdevtest_init(void){
dev_t mydev = MKDEV(major, 0);
int ret;
int i = 0;
printk(“*******%s********\n”, __FUNCTION__);
if(major){//注册proc/devices
ret = register_chrdev_region(mydev, 1, “mynewdriver”);
}else{
ret = alloc_chrdev_region(&mydev, 0, 1, “mynewdriver”);
major = MAJOR(mydev);
}
if(ret < 0){
printk(KERN_ERR “register_chrdev_region failed!\n”);
ret = -EINVAL;
return ret;
}
myvirtualdisk = kmalloc(sizeof(struct VirtualDisk), GFP_KERNEL);
if(!myvirtualdisk){
ret = -ENOMEM;
printk(KERN_ERR “kmalloc myvirtualdisk failed!\n”);
goto release_chrdev;
}
myvirtualdisk->mycdevclass = class_create(THIS_MODULE, “mynewdriver”);
if(IS_ERR(myvirtualdisk->mycdevclass)){
ret = PTR_ERR(myvirtualdisk->mycdevclass);
printk(KERN_ERR “class_create failed!\n”);
goto release_mem_malloc;

}
myvirtualdisk->mycdevclassdevice = class_device_create(myvirtualdisk->mycdevclass, NULL, MKDEV(major, 0), NULL, “mynewdriver”);
if(IS_ERR(myvirtualdisk->mycdevclassdevice)){
ret = PTR_ERR(myvirtualdisk->mycdevclassdevice);
printk(KERN_ERR “class_device_create failed!\n”);
goto release_class_create;
}

cdev_init(&(myvirtualdisk->mycdev), &mydev_fops);
myvirtualdisk->mycdev.owner = THIS_MODULE;
ret = cdev_add(&myvirtualdisk->mycdev, MKDEV(major, 0), 1);

//这儿把timer相关的放在irq前面,否则会有bug呈现(当在insmod时分按下按钮就会犯错)
init_timer(&myvirtualdisk->mytimer);
myvirtualdisk->mytimer.function = mytimer_func;
myvirtualdisk->mytimer.data = (unsigned long)myvirtualdisk;

if(ret < 0){
goto release_device_class_create;
}
for(i = 0; i < 3; i++)
{
ret = request_irq(gpio_to_irq(myirq_descs[i].irq_id), myirq_handle, IRQF_TRIGGER_FALLING, myirq_descs[i].irq_name, &myirq_descs[i]);
if(ret < 0){
printk(KERN_ERR “request irq failed!\n”);
ret =-EFAULT;
goto release_cdevandtimer;
}
}

return 0;
release_cdevandtimer:
del_timer(&myvirtualdisk->mytimer);
cdev_del(&myvirtualdisk->mycdev);
release_device_class_create:
class_device_unregister(myvirtualdisk->mycdevclassdevice);
release_class_create:
class_destroy(myvirtualdisk->mycdevclass);
release_mem_malloc:
kfree(myvirtualdisk);
release_chrdev:
unregister_chrdev_region(MKDEV(major, 0), 1);
return ret;
}

static void __exit cdevtest_exit(void){
int i = 0;
printk(“*******%s****1****\n”, __FUNCTION__);
del_timer(&myvirtualdisk->mytimer);
printk(“*******%s*****2***\n”, __FUNCTION__);
for(i = 0; i < 3; i++)free_irq(gpio_to_irq(myirq_descs[i].irq_id), &myirq_descs[i]);
printk(“*******%s*****3***\n”, __FUNCTION__);
cdev_del(&myvirtualdisk->mycdev);
printk(“*******%s*****4***\n”, __FUNCTION__);
class_device_unregister(myvirtualdisk->mycdevclassdevice);
printk(“*******%s*****5***\n”, __FUNCTION__);
class_destroy(myvirtualdisk->mycdevclass);
printk(“*******%s*****6***\n”, __FUNCTION__);
kfree(myvirtualdisk);
printk(“*******%s********\n”, __FUNCTION__);
unregister_chrdev_region(MKDEV(major, 0), 1);
printk(“*******%s*****7***\n”, __FUNCTION__);
}

module_init(cdevtest_init);
module_exit(cdevtest_exit);
MODULE_LICENSE(“GPL”);

完好的tasklet使命中止上下半部代码

#include #include #include #include #include #include #include #include #include

#include
#include
#include
#define VIRTUAL_MAJOR 250
int major = VIRTUAL_MAJOR;

struct myirq_desc{
int irq_id;
char *irq_name;
int irq_code;
};

struct myirq_desc myirq_descs[3]= {
{S3C2410_GPF0, “s2”, KEY_J},
{S3C2410_GPF2, “s3”, KEY_K},
{S3C2410_GPG3, “s4”, KEY_Z},
};
struct VirtualDisk{
struct class *mycdevclass;//在/sys/class创立类
struct class_device *mycdevclassdevice;//在/dev下创立设备
struct cdev mycdev;//给设备增加相关的fileoption
struct timer_list mytimer;
struct tasklet_struct mytasklet;
};
struct VirtualDisk *myvirtualdisk;

static struct file_operations mydev_fops = {
.owner = THIS_MODULE,
};
static void mytasklet_func(unsigned long fundata){
printk(“*****%s******,date = %ld\n”, __FUNCTION__, fundata);
}
static void mytimer_func(unsigned long fundata){
printk(“*******%s********\n”, __FUNCTION__);
struct VirtualDisk *myvirtualdisk_fun = (struct VirtualDisk *)(fundata);
//myvirtualdisk_fun->mytimer.expires =jiffies + 2 * HZ;
//add_timer(&myvirtualdisk_fun->mytimer);
printk(“timer func happened!\n”);
}
static irqreturn_t myirq_handle(int irq, void *dev_id){
struct myirq_desc *myirq_descone = (struct myirq_desc *)dev_id;
printk(“*******%s********\n”, __FUNCTION__);
printk(“irq = %d, irq_id = %d,irq_name = %s, irq_code = %c\n”, irq, myirq_descone->irq_id, myirq_descone->irq_name, myirq_descone->irq_code);
tasklet_schedule(&myvirtualdisk->mytasklet);//激起使命,将mytasklet_func参加体系使命
mod_timer(&myvirtualdisk->mytimer, jiffies + 2*HZ);
return IRQ_RETVAL(IRQ_HANDLED);
}

static int __init cdevtest_init(void){
dev_t mydev = MKDEV(major, 0);
int ret;
int i = 0;
printk(“*******%s********\n”, __FUNCTION__);
if(major){//注册proc/devices
ret = register_chrdev_region(mydev, 1, “mynewdriver”);
}else{
ret = alloc_chrdev_region(&mydev, 0, 1, “mynewdriver”);
major = MAJOR(mydev);
}
if(ret < 0){
printk(KERN_ERR “register_chrdev_region failed!\n”);
ret = -EINVAL;
return ret;
}
myvirtualdisk = kmalloc(sizeof(struct VirtualDisk), GFP_KERNEL);
if(!myvirtualdisk){
ret = -ENOMEM;
printk(KERN_ERR “kmalloc myvirtualdisk failed!\n”);
goto release_chrdev;
}
myvirtualdisk->mycdevclass = class_create(THIS_MODULE, “mynewdriver”);
if(IS_ERR(myvirtualdisk->mycdevclass)){
ret = PTR_ERR(myvirtualdisk->mycdevclass);
printk(KERN_ERR “class_create failed!\n”);
goto release_mem_malloc;

}
myvirtualdisk->mycdevclassdevice = class_device_create(myvirtualdisk->mycdevclass, NULL, MKDEV(major, 0), NULL, “mynewdriver”);
if(IS_ERR(myvirtualdisk->mycdevclassdevice)){
ret = PTR_ERR(myvirtualdisk->mycdevclassdevice);
printk(KERN_ERR “class_device_create failed!\n”);
goto release_class_create;
}

cdev_init(&(myvirtualdisk->mycdev), &mydev_fops);
myvirtualdisk->mycdev.owner = THIS_MODULE;
ret = cdev_add(&myvirtualdisk->mycdev, MKDEV(major, 0), 1);

//tasklet 使命调度
tasklet_init(&myvirtualdisk->mytasklet, mytasklet_func, (unsigned long) 90);

//这儿把timer相关的放在irq前面,否则会有bug呈现(当在insmod时分按下按钮就会犯错)
init_timer(&myvirtualdisk->mytimer);
myvirtualdisk->mytimer.function = mytimer_func;
myvirtualdisk->mytimer.data = (unsigned long)myvirtualdisk;

if(ret < 0){
goto release_device_class_create;
}
for(i = 0; i < 3; i++)
{
ret = request_irq(gpio_to_irq(myirq_descs[i].irq_id), myirq_handle, IRQF_TRIGGER_FALLING, myirq_descs[i].irq_name, &myirq_descs[i]);
if(ret < 0){
printk(KERN_ERR “request irq failed!\n”);
ret =-EFAULT;
goto release_cdevandtimer;
}
}

return 0;
release_cdevandtimer:
tasklet_kill(&myvirtualdisk->mytasklet);//删去使命
del_timer(&myvirtualdisk->mytimer);
cdev_del(&myvirtualdisk->mycdev);
release_device_class_create:
class_device_unregister(myvirtualdisk->mycdevclassdevice);
release_class_create:
class_destroy(myvirtualdisk->mycdevclass);
release_mem_malloc:
kfree(myvirtualdisk);
release_chrdev:
unregister_chrdev_region(MKDEV(major, 0), 1);
return ret;
}

static void __exit cdevtest_exit(void){
int i = 0;
printk(“*******%s****1****\n”, __FUNCTION__);
tasklet_kill(&myvirtualdisk->mytasklet);//删去使命
del_timer(&myvirtualdisk->mytimer);
printk(“*******%s*****2***\n”, __FUNCTION__);
for(i = 0; i < 3; i++)free_irq(gpio_to_irq(myirq_descs[i].irq_id), &myirq_descs[i]);
printk(“*******%s*****3***\n”, __FUNCTION__);
cdev_del(&myvirtualdisk->mycdev);
printk(“*******%s*****4***\n”, __FUNCTION__);
class_device_unregister(myvirtualdisk->mycdevclassdevice);
printk(“*******%s*****5***\n”, __FUNCTION__);
class_destroy(myvirtualdisk->mycdevclass);
printk(“*******%s*****6***\n”, __FUNCTION__);
kfree(myvirtualdisk);
printk(“*******%s********\n”, __FUNCTION__);
unregister_chrdev_region(MKDEV(major, 0), 1);
printk(“*******%s*****7***\n”, __FUNCTION__);
}

module_init(cdevtest_init);
module_exit(cdevtest_exit);
MODULE_LICENSE(“GPL”);

完好的workqueue作业行列中止上下半部代码

#include #include #include #include #include #include #include #include #include #include

#include
#include
#include
#define VIRTUAL_MAJOR 250
int major = VIRTUAL_MAJOR;

struct myirq_desc{
int irq_id;
char *irq_name;
int irq_code;
};

struct myirq_desc myirq_descs[3]= {
{S3C2410_GPF0, “s2”, KEY_J},
{S3C2410_GPF2, “s3”, KEY_K},
{S3C2410_GPG3, “s4”, KEY_Z},
};
struct VirtualDisk{
struct class *mycdevclass;//在/sys/class创立类
struct class_device *mycdevclassdevice;//在/dev下创立设备
struct cdev mycdev;//给设备增加相关的fileoption
struct timer_list mytimer;
struct tasklet_struct mytasklet;
struct workqueue_struct *myworkqueue;//作业行列
struct work_struct mywork;//作业;作业行列中的一项作业
};
struct VirtualDisk *myvirtualdisk;

static struct file_operations mydev_fops = {
.owner = THIS_MODULE,
};

static void mywork_func(struct work_struct *work){
printk(“*******%s********\n”, __FUNCTION__);
}
static void mytasklet_func(unsigned long fundata){
printk(“*****%s******,date = %ld\n”, __FUNCTION__, fundata);
}
static void mytimer_func(unsigned long fundata){
printk(“*******%s********\n”, __FUNCTION__);
//struct VirtualDisk *myvirtualdisk_fun = (struct VirtualDisk *)(fundata);
//myvirtualdisk_fun->mytimer.expires =jiffies + 2 * HZ;
//add_timer(&myvirtualdisk_fun->mytimer);
printk(“timer func happened!\n”);
}
static irqreturn_t myirq_handle(int irq, void *dev_id){
struct myirq_desc *myirq_descone = (struct myirq_desc *)dev_id;
printk(“*******%s********\n”, __FUNCTION__);
printk(“irq = %d, irq_id = %d,irq_name = %s, irq_code = %c\n”, irq, myirq_descone->irq_id, myirq_descone->irq_name, myirq_descone->irq_code);
queue_work(myvirtualdisk->myworkqueue, &myvirtualdisk->mywork);
tasklet_schedule(&myvirtualdisk->mytasklet);//激起使命,将mytasklet_func参加体系使命
mod_timer(&myvirtualdisk->mytimer, jiffies + 2*HZ);
return IRQ_RETVAL(IRQ_HANDLED);
}

static int __init cdevtest_init(void){
dev_t mydev = MKDEV(major, 0);
int ret;
int i = 0;
printk(“*******%s********\n”, __FUNCTION__);
if(major){//注册proc/devices
ret = register_chrdev_region(mydev, 1, “mynewdriver”);
}else{
ret = alloc_chrdev_region(&mydev, 0, 1, “mynewdriver”);
major = MAJOR(mydev);
}
if(ret < 0){
printk(KERN_ERR “register_chrdev_region failed!\n”);
ret = -EINVAL;
return ret;
}
myvirtualdisk = kmalloc(sizeof(struct VirtualDisk), GFP_KERNEL);
if(!myvirtualdisk){
ret = -ENOMEM;
printk(KERN_ERR “kmalloc myvirtualdisk failed!\n”);
goto release_chrdev;
}
myvirtualdisk->mycdevclass = class_create(THIS_MODULE, “mynewdriver”);
if(IS_ERR(myvirtualdisk->mycdevclass)){
ret = PTR_ERR(myvirtualdisk->mycdevclass);
printk(KERN_ERR “class_create failed!\n”);
goto release_mem_malloc;

}
myvirtualdisk->mycdevclassdevice = class_device_create(myvirtualdisk->mycdevclass, NULL, MKDEV(major, 0), NULL, “mynewdriver”);
if(IS_ERR(myvirtualdisk->mycdevclassdevice)){
ret = PTR_ERR(myvirtualdisk->mycdevclassdevice);
printk(KERN_ERR “class_device_create failed!\n”);
goto release_class_create;
}

//作业和作业行列
INIT_WORK(&myvirtualdisk->mywork, mywork_func);
myvirtualdisk->myworkqueue = create_workqueue(“myworkqueue”);
if (!myvirtualdisk->myworkqueue) {
ret = -ENOMEM;
goto release_class_create;
}

cdev_init(&(myvirtualdisk->mycdev), &mydev_fops);
myvirtualdisk->mycdev.owner = THIS_MODULE;
ret = cdev_add(&myvirtualdisk->mycdev, MKDEV(major, 0), 1);

//tasklet 使命调度
tasklet_init(&myvirtualdisk->mytasklet, mytasklet_func, (unsigned long) 90);

//这儿把timer相关的放在irq前面,否则会有bug呈现(当在insmod时分按下按钮就会犯错)
init_timer(&myvirtualdisk->mytimer);
myvirtualdisk->mytimer.function = mytimer_func;
myvirtualdisk->mytimer.data = (unsigned long)myvirtualdisk;

if(ret < 0){
goto release_device_class_create;
}
for(i = 0; i < 3; i++)
{
ret = request_irq(gpio_to_irq(myirq_descs[i].irq_id), myirq_handle, IRQF_TRIGGER_FALLING, myirq_descs[i].irq_name, &myirq_descs[i]);
if(ret < 0){
printk(KERN_ERR “request irq failed!\n”);
ret =-EFAULT;
goto release_cdevandtimer;
}
}

/*在模块刊出的时分,毁掉作业行列和作业目标
void flush_workqueue(struct workqueue_struct * wq)
该函数会一向等候,知道指定的等候行列中所有的使命都碑文结束并从等候行列中移除。
void destroy_workqueue(struct workqueue_struct * wq);
该函数是是创立等候行列的反操作,刊出掉指定的等候行列。*/

return 0;
release_cdevandtimer:
tasklet_kill(&myvirtualdisk->mytasklet);//删去使命
del_timer(&myvirtualdisk->mytimer);
cdev_del(&myvirtualdisk->mycdev);
/*在模块刊出的时分,毁掉作业行列和作业目标
void flush_workqueue(struct workqueue_struct * wq)
该函数会一向等候,知道指定的等候行列中所有的使命都碑文结束并从等候行列中移除。
void destroy_workqueue(struct workqueue_struct * wq);
该函数是是创立等候行列的反操作,刊出掉指定的等候行列。*/
flush_workqueue(myvirtualdisk->myworkqueue);
destroy_workqueue(myvirtualdisk->myworkqueue);
release_device_class_create:
class_device_unregister(myvirtualdisk->mycdevclassdevice);
release_class_create:
class_destroy(myvirtualdisk->mycdevclass);
release_mem_malloc:
kfree(myvirtualdisk);
release_chrdev:
unregister_chrdev_region(MKDEV(major, 0), 1);
return ret;
}

static void __exit cdevtest_exit(void){
int i = 0;
printk(“*******%s****1****\n”, __FUNCTION__);
tasklet_kill(&myvirtualdisk->mytasklet);//删去使命
del_timer(&myvirtualdisk->mytimer);
printk(“*******%s*****2***\n”, __FUNCTION__);
for(i = 0; i < 3; i++)free_irq(gpio_to_irq(myirq_descs[i].irq_id), &myirq_descs[i]);
printk(“*******%s*****3***\n”, __FUNCTION__);
cdev_del(&myvirtualdisk->mycdev);

//删去作业和作业行列
flush_workqueue(myvirtualdisk->myworkqueue);
destroy_workqueue(myvirtualdisk->myworkqueue);

printk(“*******%s*****4***\n”, __FUNCTION__);
class_device_unregister(myvirtualdisk->mycdevclassdevice);
printk(“*******%s*****5***\n”, __FUNCTION__);
class_destroy(myvirtualdisk->mycdevclass);
printk(“*******%s*****6***\n”, __FUNCTION__);
kfree(myvirtualdisk);
printk(“*******%s********\n”, __FUNCTION__);
unregister_chrdev_region(MKDEV(major, 0), 1);
printk(“*******%s*****7***\n”, __FUNCTION__);
}

module_init(cdevtest_init);
module_exit(cdevtest_exit);
MODULE_LICENSE(“GPL”);

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/ceping/265204.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部