如何在没有内核崩溃的情况下优雅地禁用中断线?

我已经实现了一个从keyboad读取的程序,并扫描代码并将其放入tasklet中。 tasklet取消阻塞read()。 因此,我的QT应用程序可以读取数据,如果它找到l的扫描代码,它会触发对Qt-webkit的回调。 但是,当我在做我的角色驱动程序的rmmod时。 整个内核崩溃了。 我的角色驱动程序有什么问题。

#include  #include  /** needed by all modules **/ #include  /** This is for KERN_ALERT **/ #include  /** for file operations **/ #include  /** character device **/ #include  /** for sys device registration in /dev/ and /sys/class **/ /** for copy_to_user **/ #include  /** kernel thread */ #include  /** spin lock essential here **/ #include  #include  #include  /** For class registration to work, you need GPL license **/ MODULE_LICENSE("GPL"); #define NUMBER_OF_MINOR_DEVICE (0) /** to avoid namespace pollution, make everything static **/ static struct cdev basicCdev; static struct class *basicDriverClass; /** Created thread **/ static struct task_struct *basicCharThread = NULL; static wait_queue_head_t chrDriverQueue; static spinlock_t mLock; static int read_unblock_flag = 0; static int basicMajorNumber = 0; /** Just for debugging, whether bottom half (tasklet) is executed or not **/ static char my_tasklet_data[]="my_tasklet_function was called"; /** scan code that will be return by read **/ static unsigned char scancode; static unsigned char status; static void my_tasklet_function( unsigned long data ); DECLARE_TASKLET( my_tasklet, my_tasklet_function,(unsigned long) &my_tasklet_data ); /** Prototype for read, this will be invoked when the read function is done on to the driver **/ /** The declaration type is file operations based function pointer - read **/ static ssize_t basicRead(struct file *filp, char *buffer, size_t length,loff_t *offset); static int basicOspen(struct inode *inode, struct file *file); /** File Operations function pointer table **/ /** There are plenty of file operations **/ static struct file_operations fops = { .read = basicRead, .write = NULL, .open = basicOspen, .release = NULL }; static ssize_t basicRead(struct file *filp, char *buffer, size_t length, loff_t *offset) { unsigned long flags; char msg[] = "Hello SJ_read\0"; /** lock it **/ spin_lock_irqsave( &mLock, flags ); printk(KERN_ALERT "The Read operation called\r\n"); spin_unlock_irqrestore( &mLock, flags ); wait_event_interruptible(chrDriverQueue, read_unblock_flag != 0); /** set it back to original for sleep **/ read_unblock_flag = 0; printk(KERN_ALERT "Read out of sleep\r\n"); if( signal_pending( current ) ) { printk(KERN_ALERT "Signal pending error\r\n"); return -1; } spin_lock_irqsave( &mLock, flags ); if ( 0 != copy_to_user( buffer, &scancode, sizeof(scancode) )) { printk(KERN_ALERT "Copy_to_user failed !!\r\n"); } spin_unlock_irqrestore( &mLock, flags ); return sizeof(msg); } static int basicOspen(struct inode *inode, struct file *file) { printk("Kernel.Basic Driver Opened now!!\r\n"); return 0; } static void setup_cdev(struct cdev *dev, int minor, struct file_operations *fops) { int err = -1; /** MKDEV call creates a device number ie combination of major and minor number **/ int devno = MKDEV(basicMajorNumber, minor); /** Initiliaze character dev with fops **/ cdev_init(dev, fops); /**owner and operations initialized **/ dev->owner = THIS_MODULE; dev->ops = fops; /** add the character device to the system**/ /** Here 1 means only 1 minor number, you can give 2 for 2 minor device, the last param is the count of minor number enrolled **/ err = cdev_add (dev, devno, 1); if (err) { printk (KERN_NOTICE "Couldn't add cdev"); } } /** Un-used Kernel Thread here **/ static int basicCharThread_fn (void *data) { unsigned long j0,j1; int delay = 30*HZ; unsigned long flags; j0 = jiffies; j1 = j0 + delay; /** this loop will run till the jiffies is equal to the (old jiffies + 60Hz delay) , this is a 1 minute delay in total **/ while (time_before(jiffies, j1)) { //printk("The thread is started\r\n"); schedule(); } spin_lock_irqsave( &mLock, flags ); read_unblock_flag = 1; spin_unlock_irqrestore( &mLock, flags ); wake_up_interruptible( &chrDriverQueue ); printk("The process is moved out of wait queue now\r\n"); return 0; } /* Bottom Half Function - Tasklet */ void my_tasklet_function( unsigned long data ) { unsigned long flags; printk( "%s\n", (char *)data ); /** Scan Code 1c Pressed **/ printk(KERN_INFO "Scan Code %x %s.\n", scancode& 0x7F, scancode & 0x80 ? "Released" : "Pressed"); spin_lock_irqsave( &mLock, flags ); read_unblock_flag = 1; spin_unlock_irqrestore( &mLock, flags ); wake_up_interruptible( &chrDriverQueue ); return; } /*** Interrupt Handler ***/ irqreturn_t irq_handler(int irq, void *dev_id, struct pt_regs *regs) { /* * Read keyboard status */ status = inb(0x64); scancode = inb(0x60); /** BH scheduled **/ tasklet_schedule( &my_tasklet ); return IRQ_HANDLED; } /** character Driver load - Main Entry Function - Module_Init() - called on insmod **/ static int chrDriverInit(void) { int result = -1; dev_t dev; /** Initialize the kernel thread **/ char kthreadBasic[]="kthreadBasic"; printk("Welcome!! Device Init now.."); /** int alloc_chrdev_region(dev_t *dev, unsigned int firstminor,unsigned int count, char *name); **/ /** dev -> The dev_t variable type,which will get the major number that the kernel allocates. **/ /**The same name will appear in /proc/devices. **/ /** it is registering the character device **/ /** a major number will be dynamically allocated here **/ /** alloc_chrdev_region(&dev_num, FIRST_MINOR, COUNT, DEVICE_NAME); **/ result = alloc_chrdev_region(&dev, 0, NUMBER_OF_MINOR_DEVICE, "pSeudoDrv"); if( result < 0 ) { printk("Error in allocating device"); return -1; } /** From these two if's we are avoiding the manual mknod command to create the /dev/ **/ /** creating class, and then device created removes the dependency of calling mknod **/ /** A good method - the mknod way is depreciated **/ /** mknod way is - mknod /dev/ c   */ /** add the driver to /-sys/class/chardrv */ if ((basicDriverClass = class_create(THIS_MODULE, "chardrv")) == NULL) //$ls /sys/class { unregister_chrdev_region(dev, 1); return -1; } /** add the driver to /dev/pSeudoDrv -- here **/ if (device_create(basicDriverClass, NULL, dev, NULL, "pSeudoDrv") == NULL) //$ls /dev/ { class_destroy(basicDriverClass); unregister_chrdev_region(dev, 1); return -1; } /** let's see what major number was assigned by the Kernel **/ basicMajorNumber = MAJOR(dev); printk("Kernel assigned major number is %d ..\r\n",basicMajorNumber ); /** Now setup the cdev **/ setup_cdev(&basicCdev,NUMBER_OF_MINOR_DEVICE, &fops); /** Linux thread is just another process, and is treated like that only **/ /** string that stores the name - kthreadBasic**/ /** struct task_struct *kthread_create(int (*function)(void *data),void *data const char name[], ...)**/ basicCharThread = kthread_create(basicCharThread_fn,(void *)NULL,kthreadBasic); /** To run the process, we need to call wake_up_process by passing the thread-id, obtained by kthread_create **/ /** To stop the thread, call kthread_stop pass the thread-id **/ if( basicCharThread == NULL) { printk( KERN_ALERT "Thread creation failed\r\n"); return -1; } /** inialize spin lock **/ spin_lock_init( &mLock); /** Initialize wait queue **/ init_waitqueue_head(&chrDriverQueue); /** Start executing the thread now **/ /** Disabled thread here- not in use **/ //wake_up_process(basicCharThread); /** Free IRQ - if already registered **/ free_irq(1, NULL); /** register the keyboard IRQ on shared mode,note this is specific to X86 architecture **/ return request_irq(1, /* The number of the keyboard IRQ on PCs */ (irqreturn_t *)irq_handler, /* our handler */ IRQF_SHARED, "test_keyboard_irq_handler", (void *)(irq_handler)); return 0; } /** Driver Exit - Module_Exit() .. called on rmmod **/ static void chrDriverExit(void) { //free_irq(1, NULL); /** stop the running thread **/ tasklet_kill( &my_tasklet ); //kthread_stop(basicCharThread); /** A reverse - destroy mechansim -- the way it was created **/ printk("Releasing Simple Devs -- %s\r\n", __FUNCTION__); /** delete the character driver added **/ cdev_del(&basicCdev); /** destroy the device created **/ device_destroy(basicDriverClass, MKDEV(basicMajorNumber, 0)); /** destroy the class created **/ class_destroy(basicDriverClass); /** unregister the chr dev **/ unregister_chrdev(basicMajorNumber, NUMBER_OF_MINOR_DEVICE); } /** Module Entry and Exit ***/ module_init(chrDriverInit); module_exit(chrDriverExit); 

什么是崩溃消息? 当你终止它时,my_tasklet可能在运行Q中。 您可以在退出例程中设置一些printk调试消息。