在线看毛片网站电影-亚洲国产欧美日韩精品一区二区三区,国产欧美乱夫不卡无乱码,国产精品欧美久久久天天影视,精品一区二区三区视频在线观看,亚洲国产精品人成乱码天天看,日韩久久久一区,91精品国产91免费

<menu id="6qfwx"><li id="6qfwx"></li></menu>
    1. <menu id="6qfwx"><dl id="6qfwx"></dl></menu>

      <label id="6qfwx"><ol id="6qfwx"></ol></label><menu id="6qfwx"></menu><object id="6qfwx"><strike id="6qfwx"><noscript id="6qfwx"></noscript></strike></object>
        1. <center id="6qfwx"><dl id="6qfwx"></dl></center>

            新聞中心

            EEPW首頁(yè) > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > arm 驅(qū)動(dòng)linux內(nèi)核驅(qū)動(dòng)之中斷下半部編程

            arm 驅(qū)動(dòng)linux內(nèi)核驅(qū)動(dòng)之中斷下半部編程

            作者: 時(shí)間:2016-11-19 來(lái)源:網(wǎng)絡(luò) 收藏
            本文部分參考華清遠(yuǎn)見(jiàn)文檔

            中斷上半部要求執(zhí)行時(shí)間間隔段,所以往往將處理時(shí)間較長(zhǎng)的代碼放在中斷下半部來(lái)處理

            本文引用地址:http://www.biyoush.com/article/201611/318223.htm

            中斷下半部的應(yīng)用:網(wǎng)卡驅(qū)動(dòng)上半部初始化網(wǎng)卡驅(qū)動(dòng)等短時(shí)間的事件,下半部收發(fā)數(shù)據(jù)

            中斷下半部:

            a, 下半部產(chǎn)生的原因:

            1,中斷上下文中不能阻塞,這也限制了中斷上下文中能干的事

            2,中斷處理函數(shù)執(zhí)行過(guò)程中仍有可能被其他中斷打斷,都希望中斷處理函數(shù)執(zhí)行得越快越好。

            基于上面的原因,內(nèi)核將整個(gè)的中斷處理流程分為了上半部和下半部。上半部就是之前所說(shuō)的中斷處理函數(shù),它能最快的響應(yīng)中斷,并且做一些必須在中斷響應(yīng)之后馬上要做的事情。而一些需要在中斷處理函數(shù)后繼續(xù)執(zhí)行的操作,內(nèi)核建議把它放在下半部執(zhí)行。

            比如:在linux內(nèi)核中,當(dāng)網(wǎng)卡一旦接受到數(shù)據(jù),網(wǎng)卡會(huì)通過(guò)中斷告訴內(nèi)核處理數(shù)據(jù),內(nèi)核會(huì)在網(wǎng)卡中斷處理函數(shù)(上半部)執(zhí)行一些網(wǎng)卡硬件的必要設(shè)置,因?yàn)檫@是在中斷響應(yīng)后急切要干的事情。接著,內(nèi)核調(diào)用對(duì)應(yīng)的下半部函數(shù)來(lái)處理網(wǎng)卡接收到的數(shù)據(jù),因?yàn)閿?shù)據(jù)處理沒(méi)必要在中斷處理函數(shù)里面馬上執(zhí)行,可以將中斷讓出來(lái)做更緊迫的事情

            b,中斷下半部實(shí)現(xiàn)的機(jī)制分類(lèi)

            tasklet:

            workqueue:工作隊(duì)列

            timer:定時(shí)器

            其實(shí)還有一種,叫softirq,但要寫(xiě)代碼的話(huà),就必須修改原來(lái)的內(nèi)核框架代碼,在實(shí)際開(kāi)發(fā)中用的比較少,tasklet內(nèi)部實(shí)現(xiàn)就是用softeirq

            c, 中斷下半部實(shí)現(xiàn)方法

            1, tasklet的編程方式

            1.1 : 定義并初始化結(jié)構(gòu)體tasklet_struct(一般在哪里初始化:是在模塊卸載方法中)

            struct tasklet_struct

            {

            struct tasklet_struct *next; // l鏈表

            unsigned long state;

            atomic_t count;

            void (*func)(unsigned long); // 下半部處理方法的實(shí)現(xiàn)

            unsigned long data;//給處理函數(shù)的傳參

            };

            初始化方式:

            靜態(tài):DECLARE_TASKLET(name, func, data);

            DCLARE_TASKLET_DISABLED初始化后的處于禁止?fàn)顟B(tài),暫時(shí)不能被使用(不是中斷),除非被激活

            參數(shù)1:tasklet_struct 的變量名字,自定義

            參數(shù)2:中斷下半部執(zhí)行的處理函數(shù).類(lèi)型為函數(shù)指針

            參數(shù)3:處理函數(shù)帶的參數(shù)

            動(dòng)態(tài):void tasklet_init(struct tasklet_struct * t, void(* func)(unsigned long), unsigned long data);

            參數(shù)1:tasklet_struct 對(duì)象

            參數(shù)2:中斷下半部執(zhí)行的處理函數(shù)

            參數(shù)3:處理函數(shù)帶的參數(shù)

            1.2: 在中斷上半部中調(diào)度下半部

            void tasklet_schedule(struct tasklet_struct * t);

            1.3: 在模塊卸載時(shí),銷(xiāo)毀這個(gè)tasklet_struct 對(duì)象

            void tasklet_kill(struct tasklet_struct *t)

            1.4:原理:初始化好struct tasklet_struct對(duì)象后,tasklet_schedule()會(huì)將tasklet對(duì)象加到鏈表中,內(nèi)核稍后會(huì)去調(diào)度這個(gè)tasklet對(duì)象

            1.5: 特點(diǎn):優(yōu)先級(jí)高,調(diào)度快,運(yùn)行在中斷上下文中,所以在處理方法中,不能執(zhí)行阻塞/睡眠的操作

            2,workqueque編程方式:

            2.1 :定義并初始化workqueue_struct(一個(gè)隊(duì)列)和work_struct(隊(duì)列中的一項(xiàng)工作)對(duì)象

            work_struct對(duì)象的初始化

            struct work_struct {

            atomic_long_t data; // 傳遞給work的參數(shù)

            struct list_head entry; // 所在隊(duì)列的鏈表

            work_func_t func; // work對(duì)應(yīng)的處理方法

            };

            靜態(tài):DECLARE_WORK(n, f)

            參數(shù)1: 變量名,自定義

            參數(shù)2:work對(duì)應(yīng)的處理方法,類(lèi)型為函數(shù)指針

            動(dòng)態(tài):INIT_WORK(_work, _func)

            參數(shù)1: 指針,先聲明一個(gè)struct work_struct變量,將變量地址填入

            參數(shù)2:work對(duì)應(yīng)的處理方法,類(lèi)型為函數(shù)指針

            返回值: 返回值為void

            workqueue_struct對(duì)象的初始化:(其實(shí)就是一個(gè)內(nèi)核線(xiàn)程)

            1, 重新創(chuàng)建一個(gè)隊(duì)列

            create_workqueue(name)//這個(gè)本身就是一個(gè)宏

            參數(shù):名字,自定義,用于識(shí)別

            返回值:struct workqueue_struct *

            2, 系統(tǒng)在開(kāi)機(jī)的時(shí)候自動(dòng)創(chuàng)建一個(gè)隊(duì)列

            2.2 將工作對(duì)象加入工作隊(duì)列中,并參與調(diào)度(注意不是馬上調(diào)度,該步驟也是中斷上半部中調(diào)用)

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

            參數(shù)1:工作隊(duì)列

            參數(shù)2: 工作對(duì)象

            返回值: 0表示已經(jīng)放到隊(duì)列上了(也即時(shí)說(shuō)本次屬于重復(fù)操作),其實(shí)一般我們都不會(huì)去做出錯(cuò)處理

            2.3 在模塊注銷(xiāo)的時(shí)候,銷(xiāo)毀工作隊(duì)列和工作對(duì)象

            void flush_workqueue(struct workqueue_struct * wq)

            該函數(shù)會(huì)一直等待,知道指定的等待隊(duì)列中所有的任務(wù)都執(zhí)行完畢并從等待隊(duì)列中移除。

            void destroy_workqueue(struct workqueue_struct * wq);

            該函數(shù)是是創(chuàng)建等待隊(duì)列的反操作,注銷(xiāo)掉指定的等待隊(duì)列。

            2.4: 對(duì)于使用內(nèi)核自帶的工作隊(duì)列events, 操作步驟如下:

            2.4.1 初始化工作對(duì)象,無(wú)需創(chuàng)建隊(duì)列了

            靜態(tài):DECLARE_WORK(n, f)

            動(dòng)態(tài):INIT_WORK(_work, _func)

            2.4.2將工作加入隊(duì)列并調(diào)度(在中斷上半部中調(diào)度)

            int schedule_work(struct work_struct * work)

            只要兩步驟就完成,也不需要刷新,也不要銷(xiāo)毀,因?yàn)檫@個(gè)工作隊(duì)列是系統(tǒng)管理的,我們不用管

            2.5:原理梳理:在工作隊(duì)列中,有專(zhuān)門(mén)的工作者線(xiàn)程來(lái)處理加入到工作對(duì)列中的任務(wù)。工作對(duì)列對(duì)應(yīng)的工作者線(xiàn)程可能不止一個(gè),每個(gè)處理器有且僅有一個(gè)工作隊(duì)列 對(duì)應(yīng)的工作者線(xiàn)程,在內(nèi)核中有一個(gè)默認(rèn)的工作隊(duì)列events,對(duì)于單處理器只有一個(gè)對(duì)應(yīng)的工作者線(xiàn)程

            3, 定時(shí)器timer編程方式:(以上兩個(gè)下半部處理都是內(nèi)核在一個(gè)特定的時(shí)候進(jìn)行調(diào)度,時(shí)間不定,而timer可以指定某個(gè)時(shí)間點(diǎn)執(zhí)行)

            3.1, jiffies,表示從系統(tǒng)啟動(dòng)到當(dāng)前的時(shí)間值,一般做加法(+5HZ(5s),)

            3.2, 定義并初始化 timer_list對(duì)象

            struct timer_list {

            struct list_head entry; // 鏈表

            unsigned long expires; // 過(guò)期時(shí)間。也及時(shí)在什么時(shí)候執(zhí)行處理方法

            struct tvec_base *base;

            void (*function)(unsigned long); // 處理方法

            unsigned long data; // 處理方法可以傳遞的參數(shù)

            int slack;

            };

            靜態(tài)初始化:TIMER_INITIALIZER(_function, _expires, _data)

            動(dòng)態(tài)初始化:void init_timer(timer)

            參數(shù):為一個(gè)指針,需要傳遞一個(gè)struct timer_list對(duì)象的地址

            該函數(shù)只是初始化了timer_list對(duì)象的部分成員,還有以下成員是需要編程的:

            struct timer_list mytimer;

            init_timer(&mytimer);

            mytimer.expires = jiffies + 2HZ

            mytimer.fuction = my_timer_func; // 自己去實(shí)現(xiàn)

            mytimer.data = (unsigned long)99; // 可以傳遞參數(shù)

            3.3, 激活timer,開(kāi)始計(jì)時(shí) (一般也是放在中斷上半部完成)

            void add_timer(&mytimer);

            3.4 計(jì)時(shí)結(jié)束是,也就是要執(zhí)行處理函數(shù)時(shí),執(zhí)行函數(shù)中要下一次計(jì)時(shí)的話(huà),必須修改timer

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

            // 2s之后再來(lái),相當(dāng)于如下:

            my_timer.expires = jiffies + 2*HZ; //重新設(shè)定時(shí)間,在兩秒后再執(zhí)行

            add_timer(&my_timer); //再次激活定時(shí)器

            3.5 定時(shí)器的銷(xiāo)毀

            int del_timer(struct timer_list *timer) // 該函數(shù)用來(lái)刪除還沒(méi)超時(shí)的定時(shí)器

            timer定時(shí)器的中斷上下半部代碼

            #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創(chuàng)建類(lèi)
            struct class_device *mycdevclassdevice;//在/dev下創(chuàng)建設(shè)備
            struct cdev mycdev;//給設(shè)備添加相關(guān)的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 = %cn", 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){//注冊(cè)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相關(guān)的放在irq前面,不然會(huì)有bug出現(xiàn)(當(dāng)在insmod時(shí)候按下按鈕就會(huì)出錯(cuò))
            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任務(wù)中斷上下半部代碼

            #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創(chuàng)建類(lèi)
            struct class_device *mycdevclassdevice;//在/dev下創(chuàng)建設(shè)備
            struct cdev mycdev;//給設(shè)備添加相關(guān)的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 = %ldn", __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 = %cn", irq, myirq_descone->irq_id, myirq_descone->irq_name, myirq_descone->irq_code);
            tasklet_schedule(&myvirtualdisk->mytasklet);//激發(fā)任務(wù),將mytasklet_func加入系統(tǒng)任務(wù)
            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){//注冊(cè)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 任務(wù)調(diào)度
            tasklet_init(&myvirtualdisk->mytasklet, mytasklet_func, (unsigned long) 90);

            //這里把timer相關(guān)的放在irq前面,不然會(huì)有bug出現(xiàn)(當(dāng)在insmod時(shí)候按下按鈕就會(huì)出錯(cuò))
            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);//刪除任務(wù)
            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);//刪除任務(wù)
            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工作隊(duì)列中斷上下半部代碼

            #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創(chuàng)建類(lèi)
            struct class_device *mycdevclassdevice;//在/dev下創(chuàng)建設(shè)備
            struct cdev mycdev;//給設(shè)備添加相關(guān)的fileoption
            struct timer_list mytimer;
            struct tasklet_struct mytasklet;
            struct workqueue_struct *myworkqueue;//工作隊(duì)列
            struct work_struct mywork;//工作;工作隊(duì)列中的一項(xiàng)工作
            };
            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 = %ldn", __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 = %cn", irq, myirq_descone->irq_id, myirq_descone->irq_name, myirq_descone->irq_code);
            queue_work(myvirtualdisk->myworkqueue, &myvirtualdisk->mywork);
            tasklet_schedule(&myvirtualdisk->mytasklet);//激發(fā)任務(wù),將mytasklet_func加入系統(tǒng)任務(wù)
            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){//注冊(cè)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;
            }

            //工作和工作隊(duì)列
            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 任務(wù)調(diào)度
            tasklet_init(&myvirtualdisk->mytasklet, mytasklet_func, (unsigned long) 90);

            //這里把timer相關(guān)的放在irq前面,不然會(huì)有bug出現(xiàn)(當(dāng)在insmod時(shí)候按下按鈕就會(huì)出錯(cuò))
            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;
            }
            }

            /*在模塊注銷(xiāo)的時(shí)候,銷(xiāo)毀工作隊(duì)列和工作對(duì)象
            void flush_workqueue(struct workqueue_struct * wq)
            該函數(shù)會(huì)一直等待,知道指定的等待隊(duì)列中所有的任務(wù)都執(zhí)行完畢并從等待隊(duì)列中移除。
            void destroy_workqueue(struct workqueue_struct * wq);
            該函數(shù)是是創(chuàng)建等待隊(duì)列的反操作,注銷(xiāo)掉指定的等待隊(duì)列。*/

            return 0;
            release_cdevandtimer:
            tasklet_kill(&myvirtualdisk->mytasklet);//刪除任務(wù)
            del_timer(&myvirtualdisk->mytimer);
            cdev_del(&myvirtualdisk->mycdev);
            /*在模塊注銷(xiāo)的時(shí)候,銷(xiāo)毀工作隊(duì)列和工作對(duì)象
            void flush_workqueue(struct workqueue_struct * wq)
            該函數(shù)會(huì)一直等待,知道指定的等待隊(duì)列中所有的任務(wù)都執(zhí)行完畢并從等待隊(duì)列中移除。
            void destroy_workqueue(struct workqueue_struct * wq);
            該函數(shù)是是創(chuàng)建等待隊(duì)列的反操作,注銷(xiāo)掉指定的等待隊(duì)列。*/
            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);//刪除任務(wù)
            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);

            //刪除工作和工作隊(duì)列
            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");



            評(píng)論


            技術(shù)專(zhuān)區(qū)

            關(guān)閉