• Linux内核之workqueue机制


    中断下半部机制之一,workqueue。

    概要

    workqueue运行在进程上下文,因为其允许用户创建内核线程,所以其必须运行在process context中,且其允许sleep睡眠,并且可调度。

    如何判断使用workqueue还是softirq/tasklet

    1. 如何该中断下半部任务需要sleep,则使用workqueue
    2. 如果该中断下半部任务不能sleep,则使用softirq/tasklet

    Linux中使用workqueue的两种方法:

    • 使用全局的workqueue
    • 创建自有的workqueue

    Global workqueue

    该方式下无需用户再创建workqueue,只需要初始化work,有两种方式:

    • static
    • dynamic
    static

    还是基于IRQ11,创建/dev/workq_dev,每次读取该文件,都会触发中断11,然后触发workqueue内核线程

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include                 //kmalloc()
    #include              //copy_to/from_user()
    #include 
    #include 
    #include 
    #include 
    #include 
    #include             // Required for workqueues
     
     
    #define IRQ_NO 11
     
     
    void workqueue_fn(struct work_struct *work); 
     
    /*Creating work by Static Method */
    DECLARE_WORK(workqueue,workqueue_fn);
     
    /*Workqueue Function*/
    void workqueue_fn(struct work_struct *work)
    {
            printk(KERN_INFO "Executing Workqueue Function\n");
    }
     
     
    //Interrupt handler for IRQ 11. 
    static irqreturn_t irq_handler(int irq,void *dev_id) {
            printk(KERN_INFO "Shared IRQ: Interrupt Occurred");
            schedule_work(&workqueue);
            
            return IRQ_HANDLED;
    }
     
     
    volatile int workq_value = 0;
     
     
    dev_t dev = 0;
    static struct class *dev_class;
    static struct cdev workq_cdev;
    struct kobject *kobj_ref;
    /*
    ** Function Prototypes
    */
    static int __init workq_driver_init(void);
    static void __exit workq_driver_exit(void);
     
    /*************** Driver Fuctions **********************/
    static int workq_open(struct inode *inode, struct file *file);
    static int workq_release(struct inode *inode, struct file *file);
    static ssize_t workq_read(struct file *filp, 
                    char __user *buf, size_t len,loff_t * off);
    static ssize_t workq_write(struct file *filp, 
                    const char *buf, size_t len, loff_t * off);
     
    /*************** Sysfs Fuctions **********************/
    static ssize_t sysfs_show(struct kobject *kobj, 
                    struct kobj_attribute *attr, char *buf);
    static ssize_t sysfs_store(struct kobject *kobj, 
                    struct kobj_attribute *attr,const char *buf, size_t count);
     
    struct kobj_attribute workq_attr = __ATTR(workq_value, 0660, sysfs_show, sysfs_store);
    /*
    ** File operation sturcture
    */
    static struct file_operations fops =
    {
            .owner          = THIS_MODULE,
            .read           = workq_read,
            .write          = workq_write,
            .open           = workq_open,
            .release        = workq_release,
    };
    /*
    ** This function will be called when we read the sysfs file
    */ 
    static ssize_t sysfs_show(struct kobject *kobj, 
                    struct kobj_attribute *attr, char *buf)
    {
            printk(KERN_INFO "Sysfs - Read!!!\n");
            return sprintf(buf, "%d", workq_value);
    }
    /*
    ** This function will be called when we write the sysfsfs file
    */
    static ssize_t sysfs_store(struct kobject *kobj, 
                    struct kobj_attribute *attr,const char *buf, size_t count)
    {
            printk(KERN_INFO "Sysfs - Write!!!\n");
            sscanf(buf,"%d",&workq_value);
            return count;
    }
    /*
    ** This function will be called when we open the Device file
    */  
    static int workq_open(struct inode *inode, struct file *file)
    {
            printk(KERN_INFO "Device File Opened...!!!\n");
            return 0;
    }
    /*
    ** This function will be called when we close the Device file
    */  
    static int workq_release(struct inode *inode, struct file *file)
    {
            printk(KERN_INFO "Device File Closed...!!!\n");
            return 0;
    }
    /*
    ** This function will be called when we read the Device file
    */
    static ssize_t workq_read(struct file *filp, 
                    char __user *buf, size_t len, loff_t *off)
    {
            struct irq_desc *desc;
            printk(KERN_INFO "Read function\n");
            desc = irq_to_desc(11);
            if (!desc)
            {
                return -EINVAL;
            }
            __this_cpu_write(vector_irq[59], desc);
            asm("int $0x3B");  // Corresponding to irq 11
            return 0;
    }
    /*
    ** This function will be called when we write the Device file
    */
    static ssize_t workq_write(struct file *filp, 
                    const char __user *buf, size_t len, loff_t *off)
    {
            printk(KERN_INFO "Write Function\n");
            return len;
    }
     
    /*
    ** Module Init function
    */
    static int __init workq_driver_init(void)
    {
            /*Allocating Major number*/
            if((alloc_chrdev_region(&dev, 0, 1, "workq_Dev")) <0){
                    printk(KERN_INFO "Cannot allocate major number\n");
                    return -1;
            }
            printk(KERN_INFO "Major = %d Minor = %d \n",MAJOR(dev), MINOR(dev));
     
            /*Creating cdev structure*/
            cdev_init(&workq_cdev,&fops);
     
            /*Adding character device to the system*/
            if((cdev_add(&workq_cdev,dev,1)) < 0){
                printk(KERN_INFO "Cannot add the device to the system\n");
                goto r_class;
            }
     
            /*Creating struct class*/
            if((dev_class = class_create(THIS_MODULE,"workq_class")) == NULL){
                printk(KERN_INFO "Cannot create the struct class\n");
                goto r_class;
            }
     
            /*Creating device*/
            if((device_create(dev_class,NULL,dev,NULL,"workq_device")) == NULL){
                printk(KERN_INFO "Cannot create the Device 1\n");
                goto r_device;
            }
     
            /*Creating a directory in /sys/kernel/ */
            kobj_ref = kobject_create_and_add("workq_sysfs",kernel_kobj);
     
            /*Creating sysfs file for workq_value*/
            if(sysfs_create_file(kobj_ref,&workq_attr.attr)){
                    printk(KERN_INFO"Cannot create sysfs file......\n");
                    goto r_sysfs;
            }
            if (request_irq(IRQ_NO, irq_handler, IRQF_SHARED, "workq_device", (void *)(irq_handler))) {
                printk(KERN_INFO "my_device: cannot register IRQ ");
                        goto irq;
            }
            printk(KERN_INFO "Device Driver Insert...Done!!!\n");
            return 0;
     
    irq:
            free_irq(IRQ_NO,(void *)(irq_handler));
     
    r_sysfs:
            kobject_put(kobj_ref); 
            sysfs_remove_file(kernel_kobj, &workq_attr.attr);
     
    r_device:
            class_destroy(dev_class);
    r_class:
            unregister_chrdev_region(dev,1);
            cdev_del(&workq_cdev);
            return -1;
    }
    /*
    ** Module exit function
    */ 
    static void __exit workq_driver_exit(void)
    {
            free_irq(IRQ_NO,(void *)(irq_handler));
            kobject_put(kobj_ref); 
            sysfs_remove_file(kernel_kobj, &workq_attr.attr);
            device_destroy(dev_class,dev);
            class_destroy(dev_class);
            cdev_del(&workq_cdev);
            unregister_chrdev_region(dev, 1);
            printk(KERN_INFO "Device Driver Remove...Done!!!\n");
    }
     
    module_init(workq_driver_init);
    module_exit(workq_driver_exit);
     
    MODULE_LICENSE("GPL");
    MODULE_DESCRIPTION("Simple Linux device driver (Global Workqueue - Static method)");
    MODULE_VERSION("1.10");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225

    运行效果

    [  933.667513] Major = 237 Minor = 0 
    [  933.667797] Device Driver Insert...Done!!!
    [  949.604759] Shared IRQ: Interrupt Occurred
    [  949.604858] Executing Workqueue Function
    [  950.264724] Device File Opened...!!!
    [  950.264754] Read function
    [  950.264809] Shared IRQ: Interrupt Occurred
    [  950.264935] Executing Workqueue Function
    [  950.264970] Device File Closed...!!!
    [  960.093059] Device Driver Remove...Done!!!
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    **问题:**中断11每次来时,都会触发workqueue,怎么才能做到只有读取/dev/workq_dev才会触发该workqueue呢?

    dynamic
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include                 //kmalloc()
    #include              //copy_to/from_user()
    #include 
    #include 
    #include 
    #include 
    #include 
    #include             // Required for workqueues
     
     
    #define IRQ_NO 11
     
    /* Work structure */
    static struct work_struct workqueue;
     
    void workqueue_fn(struct work_struct *work); 
     
    /*Workqueue Function*/
    void workqueue_fn(struct work_struct *work)
    {
            printk(KERN_INFO "Executing Workqueue Function\n");
    }
     
    //Interrupt handler for IRQ 11. 
    static irqreturn_t irq_handler(int irq,void *dev_id) {
            printk(KERN_INFO "Shared IRQ: Interrupt Occurred");
            /*Allocating work to queue*/
            schedule_work(&workqueue);
            
            return IRQ_HANDLED;
    }
     
    volatile int workq_value = 0;
    dev_t dev = 0;
    static struct class *dev_class;
    static struct cdev workq_cdev;
    struct kobject *kobj_ref;
    /*
    ** Function Prototypes
    */
    static int __init workq_driver_init(void);
    static void __exit workq_driver_exit(void);
     
    /*************** Driver Fuctions **********************/
    static int workq_open(struct inode *inode, struct file *file);
    static int workq_release(struct inode *inode, struct file *file);
    static ssize_t workq_read(struct file *filp, 
                    char __user *buf, size_t len,loff_t * off);
    static ssize_t workq_write(struct file *filp, 
                    const char *buf, size_t len, loff_t * off);
     
    /*************** Sysfs Fuctions **********************/
    static ssize_t sysfs_show(struct kobject *kobj, 
                    struct kobj_attribute *attr, char *buf);
    static ssize_t sysfs_store(struct kobject *kobj, 
                    struct kobj_attribute *attr,const char *buf, size_t count);
     
    struct kobj_attribute workq_attr = __ATTR(workq_value, 0660, sysfs_show, sysfs_store);
    /*
    ** File operation sturcture
    */ 
    static struct file_operations fops =
    {
            .owner          = THIS_MODULE,
            .read           = workq_read,
            .write          = workq_write,
            .open           = workq_open,
            .release        = workq_release,
    };
    /*
    ** This fuction will be called when we read the sysfs file
    */
    static ssize_t sysfs_show(struct kobject *kobj, 
                    struct kobj_attribute *attr, char *buf)
    {
            printk(KERN_INFO "Sysfs - Read!!!\n");
            return sprintf(buf, "%d", workq_value);
    }
     
    /*
    ** This fuction will be called when we write the sysfsfs file
    */
    static ssize_t sysfs_store(struct kobject *kobj, 
                    struct kobj_attribute *attr,const char *buf, size_t count)
    {
            printk(KERN_INFO "Sysfs - Write!!!\n");
            sscanf(buf,"%d",&workq_value);
            return count;
    }
    /*
    ** This fuction will be called when we open the Device file
    */  
    static int workq_open(struct inode *inode, struct file *file)
    {
            printk(KERN_INFO "Device File Opened...!!!\n");
            return 0;
    }
    /*
    ** This fuction will be called when we close the Device file
    */  
    static int workq_release(struct inode *inode, struct file *file)
    {
            printk(KERN_INFO "Device File Closed...!!!\n");
            return 0;
    }
    /*
    ** This fuction will be called when we read the Device file
    */ 
    static ssize_t workq_read(struct file *filp, 
                    char __user *buf, size_t len, loff_t *off)
    {
            struct irq_desc *desc;
            printk(KERN_INFO "Read function\n");
            desc = irq_to_desc(11);
            if (!desc)
            {
                return -EINVAL;
            }
            __this_cpu_write(vector_irq[59], desc);
            asm("int $0x3B");  // Corresponding to irq 11
            return 0;
    }
    /*
    ** This fuction will be called when we write the Device file
    */
    static ssize_t workq_write(struct file *filp, 
                    const char __user *buf, size_t len, loff_t *off)
    {
            printk(KERN_INFO "Write Function\n");
            return 0;
    }
     
    /*
    ** Module Init function
    */ 
    static int __init workq_driver_init(void)
    {
            /*Allocating Major number*/
            if((alloc_chrdev_region(&dev, 0, 1, "workq_Dev")) <0){
                    printk(KERN_INFO "Cannot allocate major number\n");
                    return -1;
            }
            printk(KERN_INFO "Major = %d Minor = %d \n",MAJOR(dev), MINOR(dev));
     
            /*Creating cdev structure*/
            cdev_init(&workq_cdev,&fops);
     
            /*Adding character device to the system*/
            if((cdev_add(&workq_cdev,dev,1)) < 0){
                printk(KERN_INFO "Cannot add the device to the system\n");
                goto r_class;
            }
     
            /*Creating struct class*/
            if((dev_class = class_create(THIS_MODULE,"workq_class")) == NULL){
                printk(KERN_INFO "Cannot create the struct class\n");
                goto r_class;
            }
     
            /*Creating device*/
            if((device_create(dev_class,NULL,dev,NULL,"workq_device")) == NULL){
                printk(KERN_INFO "Cannot create the Device 1\n");
                goto r_device;
            }
     
            /*Creating a directory in /sys/kernel/ */
            kobj_ref = kobject_create_and_add("workq_sysfs",kernel_kobj);
     
            /*Creating sysfs file for workq_value*/
            if(sysfs_create_file(kobj_ref,&workq_attr.attr)){
                    printk(KERN_INFO"Cannot create sysfs file......\n");
                    goto r_sysfs;
            }
            if (request_irq(IRQ_NO, irq_handler, IRQF_SHARED, "workq_device", (void *)(irq_handler))) {
                printk(KERN_INFO "my_device: cannot register IRQ ");
                        goto irq;
            }
     
            /*Creating work by Dynamic Method */
            INIT_WORK(&workqueue,workqueue_fn);
     
            printk(KERN_INFO "Device Driver Insert...Done!!!\n");
            return 0;
     
    irq:
            free_irq(IRQ_NO,(void *)(irq_handler));
     
    r_sysfs:
            kobject_put(kobj_ref); 
            sysfs_remove_file(kernel_kobj, &workq_attr.attr);
     
    r_device:
            class_destroy(dev_class);
    r_class:
            unregister_chrdev_region(dev,1);
            cdev_del(&workq_cdev);
            return -1;
    }
    /*
    ** Module exit function
    */ 
    static void __exit workq_driver_exit(void)
    {
            free_irq(IRQ_NO,(void *)(irq_handler));
            kobject_put(kobj_ref); 
            sysfs_remove_file(kernel_kobj, &workq_attr.attr);
            device_destroy(dev_class,dev);
            class_destroy(dev_class);
            cdev_del(&workq_cdev);
            unregister_chrdev_region(dev, 1);
            printk(KERN_INFO "Device Driver Remove...Done!!!\n");
    }
     
    module_init(workq_driver_init);
    module_exit(workq_driver_exit);
     
    MODULE_LICENSE("GPL");
    MODULE_DESCRIPTION("Simple Linux device driver (Global Workqueue - Dynamic method)");
    MODULE_VERSION("1.11");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226

    Own Workqueue

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    #include                 //kmalloc()
    #include              //copy_to/from_user()
    #include 
    #include 
    #include 
    #include 
    #include 
    #include             // Required for workqueues
     
     
    #define IRQ_NO 11
     
    static struct workqueue_struct *own_workqueue;
     
    static void workqueue_fn(struct work_struct *work); 
     
    static DECLARE_WORK(work, workqueue_fn);
     
     
    /*Workqueue Function*/
    static void workqueue_fn(struct work_struct *work)
    {
        printk(KERN_INFO "Executing Workqueue Function\n");
        return;
            
    }
     
     
    //Interrupt handler for IRQ 11. 
    static irqreturn_t irq_handler(int irq,void *dev_id) {
            printk(KERN_INFO "Shared IRQ: Interrupt Occurred\n");
            /*Allocating work to queue*/
            queue_work(own_workqueue, &work);
            
            return IRQ_HANDLED;
    }
     
     
    volatile int workq_value = 0;
     
     
    dev_t dev = 0;
    static struct class *dev_class;
    static struct cdev workq_cdev;
    struct kobject *kobj_ref;
    /*
    ** Function Prototypes
    */ 
    static int __init workq_driver_init(void);
    static void __exit workq_driver_exit(void);
     
    /*************** Driver Fuctions **********************/
    static int workq_open(struct inode *inode, struct file *file);
    static int workq_release(struct inode *inode, struct file *file);
    static ssize_t workq_read(struct file *filp, 
                    char __user *buf, size_t len,loff_t * off);
    static ssize_t workq_write(struct file *filp, 
                    const char *buf, size_t len, loff_t * off);
     
    /*************** Sysfs Fuctions **********************/
    static ssize_t sysfs_show(struct kobject *kobj, 
                    struct kobj_attribute *attr, char *buf);
    static ssize_t sysfs_store(struct kobject *kobj, 
                    struct kobj_attribute *attr,const char *buf, size_t count);
     
    struct kobj_attribute workq_attr = __ATTR(workq_value, 0660, sysfs_show, sysfs_store);
    /*
    ** File operation sturcture
    */
    static struct file_operations fops =
    {
            .owner          = THIS_MODULE,
            .read           = workq_read,
            .write          = workq_write,
            .open           = workq_open,
            .release        = workq_release,
    };
    /*
    ** This fuction will be called when we read the sysfs file
    */  
    static ssize_t sysfs_show(struct kobject *kobj, 
                    struct kobj_attribute *attr, char *buf)
    {
            printk(KERN_INFO "Sysfs - Read!!!\n");
            return sprintf(buf, "%d", workq_value);
    }
    /*
    ** This fuction will be called when we write the sysfsfs file
    */ 
    static ssize_t sysfs_store(struct kobject *kobj, 
                    struct kobj_attribute *attr,const char *buf, size_t count)
    {
            printk(KERN_INFO "Sysfs - Write!!!\n");
            sscanf(buf,"%d",&workq_value);
            return count;
    }
    /*
    ** This fuction will be called when we open the Device file
    */ 
    static int workq_open(struct inode *inode, struct file *file)
    {
            printk(KERN_INFO "Device File Opened...!!!\n");
            return 0;
    }
    /*
    ** This fuction will be called when we close the Device file
    */  
    static int workq_release(struct inode *inode, struct file *file)
    {
            printk(KERN_INFO "Device File Closed...!!!\n");
            return 0;
    }
    /*
    ** This fuction will be called when we read the Device file
    */ 
    static ssize_t workq_read(struct file *filp, 
                    char __user *buf, size_t len, loff_t *off)
    {
            struct irq_desc *desc;
            printk(KERN_INFO "Read function\n");
            desc = irq_to_desc(11);
            if (!desc)
            {
                return -EINVAL;
            }
            __this_cpu_write(vector_irq[59], desc);
            asm("int $0x3B");  // Corresponding to irq 11
            return 0;
    }
    /*
    ** This fuction will be called when we write the Device file
    */
    static ssize_t workq_write(struct file *filp, 
                    const char __user *buf, size_t len, loff_t *off)
    {
            printk(KERN_INFO "Write Function\n");
            return 0;
    }
     
    /*
    ** Module Init function
    */ 
    static int __init workq_driver_init(void)
    {
            /*Allocating Major number*/
            if((alloc_chrdev_region(&dev, 0, 1, "workq_Dev")) <0){
                    printk(KERN_INFO "Cannot allocate major number\n");
                    return -1;
            }
            printk(KERN_INFO "Major = %d Minor = %d \n",MAJOR(dev), MINOR(dev));
     
            /*Creating cdev structure*/
            cdev_init(&workq_cdev,&fops);
     
            /*Adding character device to the system*/
            if((cdev_add(&workq_cdev,dev,1)) < 0){
                printk(KERN_INFO "Cannot add the device to the system\n");
                goto r_class;
            }
     
            /*Creating struct class*/
            if((dev_class = class_create(THIS_MODULE,"workq_class")) == NULL){
                printk(KERN_INFO "Cannot create the struct class\n");
                goto r_class;
            }
     
            /*Creating device*/
            if((device_create(dev_class,NULL,dev,NULL,"workq_device")) == NULL){
                printk(KERN_INFO "Cannot create the Device 1\n");
                goto r_device;
            }
     
            /*Creating a directory in /sys/kernel/ */
            kobj_ref = kobject_create_and_add("workq_sysfs",kernel_kobj);
     
            /*Creating sysfs file for workq_value*/
            if(sysfs_create_file(kobj_ref,&workq_attr.attr)){
                    printk(KERN_INFO"Cannot create sysfs file......\n");
                    goto r_sysfs;
            }
            if (request_irq(IRQ_NO, irq_handler, IRQF_SHARED, "workq_device", (void *)(irq_handler))) {
                printk(KERN_INFO "my_device: cannot register IRQ \n");
                        goto irq;
            }
     
            /*Creating workqueue */
            own_workqueue = create_workqueue("own_wq");
            
            printk(KERN_INFO "Device Driver Insert...Done!!!\n");
            return 0;
     
    irq:
            free_irq(IRQ_NO,(void *)(irq_handler));
     
    r_sysfs:
            kobject_put(kobj_ref); 
            sysfs_remove_file(kernel_kobj, &workq_attr.attr);
     
    r_device:
            class_destroy(dev_class);
    r_class:
            unregister_chrdev_region(dev,1);
            cdev_del(&workq_cdev);
            return -1;
    }
    /*
    ** Module exit function
    */ 
    static void __exit workq_driver_exit(void)
    {
            /* Delete workqueue */
            destroy_workqueue(own_workqueue);
            free_irq(IRQ_NO,(void *)(irq_handler));
            kobject_put(kobj_ref); 
            sysfs_remove_file(kernel_kobj, &workq_attr.attr);
            device_destroy(dev_class,dev);
            class_destroy(dev_class);
            cdev_del(&workq_cdev);
            unregister_chrdev_region(dev, 1);
            printk(KERN_INFO "Device Driver Remove...Done!!!\n");
    }
     
    module_init(workq_driver_init);
    module_exit(workq_driver_exit);
     
    MODULE_LICENSE("GPL");
    MODULE_DESCRIPTION("Simple Linux device driver (Own Workqueue)");
    MODULE_VERSION("1.12");
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235

    reference

    Linux device driver tutorials- ch14~16

  • 相关阅读:
    linux常用命令
    应用计量经济学问题~
    服务器怎么被远程桌面连接不上,远程桌面连接不上服务器的问题有效解决方案
    伦敦银代码什么意思
    [python]使用标准库logging实现多进程安全的日志模块
    BM4 合并两个排序的链表
    系统架构常用的工具
    C#面:as 和 is 的区别
    电容笔和触控笔有哪些区别?超高性价比电容笔排行
    【EMC专题】传导骚扰源和辐射骚扰源2
  • 原文地址:https://blog.csdn.net/qq_23662505/article/details/126888936