中断处理体系结构
来源:互联网 发布:阿里云服务器机房地址 编辑:程序博客网 时间:2024/05/22 15:08
在裸板程序按键中断工程int下interrupt.c包含中断处理函数EINT_Handle( )的实现:
#include "s3c24xx.h"void EINT_Handle(){ unsigned long oft = INTOFFSET; unsigned long val; switch( oft ) { // S2被按下 case 0: { GPFDAT |= (0x7<<4); // 所有LED熄灭 GPFDAT &= ~(1<<4); // LED1点亮 break; } // S3被按下 case 2: { GPFDAT |= (0x7<<4); // 所有LED熄灭 GPFDAT &= ~(1<<5); // LED2点亮 break; } // K4被按下 case 5: { GPFDAT |= (0x7<<4); // 所有LED熄灭 GPFDAT &= ~(1<<6); // LED4点亮 break; } default: break; } //清中断 if( oft == 5 ) EINTPEND = (1<<11); // EINT8_23合用IRQ5 SRCPND = 1<<oft; INTPND = 1<<oft;}由此程序可知,分3步
⑴读取寄存器INTOFFSET,分辨是哪个中断
⑵对不同的中断调用中断服务函数或者相应的处理
⑶清中断
其中步骤⑶可以再⑴之前
同样,在内核中中断程序处理流程也类似,下面分析中断处理函数asm_do_IRQ:
Linux内核将所有中断统一编号,使用irq_desc结构体数组来描述这些中断,每个数组项对应一个中断或一组中断(共用一个中断号),位于include/linux/irq.h
struct irq_desc {irq_flow_handler_thandle_irq;struct irq_chip*chip;struct msi_desc*msi_desc;void*handler_data;void*chip_data;struct irqaction*action;/* IRQ action list */unsigned intstatus;/* IRQ status */unsigned intdepth;/* nested irq disables */unsigned intwake_depth;/* nested wake enables */unsigned intirq_count;/* For detecting broken IRQs */unsigned intirqs_unhandled;spinlock_tlock;struct proc_dir_entry*dir;const char*name;} ____cacheline_internodealigned_in_smp;
其中handle_irq为这个或这组中断的处理函数入口。中断发生是,总入口函数asm_do_IRQ根据中断号调用对应的irq_desc数组项中的handle_irq.
asmlinkage void __exception asm_do_IRQ(unsigned int irq, struct pt_regs *regs){struct irq_desc *desc = irq_desc + irq;desc_handle_irq(irq, desc);}
其中irq是用户注册相应中断处理函数传入的实参,
request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char * devname, void * dev_id)
irq_desc为irq_desc数组项irq_desc[0]的地址,irq_desc为全局变量,其定义并初始化在kernel/irq/handle.c中,所以irq_desc[0]的地址是已知的即irq_desc结构体分配了内存空间,其数组首地址是确定的,对应相应的中断desc指针值是已知的,所以desc_handle_irq的参数irq, desc均是已知的:
struct irq_desc irq_desc[NR_IRQS] __cacheline_aligned_in_smp = {[0 ... NR_IRQS-1] = {.status = IRQ_DISABLED,.chip = &no_irq_chip,.handle_irq = handle_bad_irq,.depth = 1,.lock = __SPIN_LOCK_UNLOCKED(irq_desc->lock),#ifdef CONFIG_SMP.affinity = CPU_MASK_ALL#endif}};
static inline void desc_handle_irq(unsigned int irq, struct irq_desc *desc){desc->handle_irq(irq, desc);}
然而中断号为irq这个中断或这组中断入口函数handle_irq还没有初始化(即将另一函数地址赋值给handle_irq)
void __set_irq_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,const char *name){struct irq_desc *desc;unsigned long flags;desc->handle_irq = handle;desc->name = name;}
handle_irq=handle,handle是__set_irq_handler的形参, handle函数是由linux/irq.h中的set_irq_handler传给__set_irq_handler的
static inline void set_irq_handler(unsigned int irq, irq_flow_handler_t handle){__set_irq_handler(irq, handle, 0, NULL);}对应外部中断EINT4来说:
void __init s3c24xx_init_irq(void){unsigned long pend;unsigned long last;int irqno;int i;/* external interrupts */for (irqno = IRQ_EINT4; irqno <= IRQ_EINT23; irqno++) {irqdbf("registering irq %d (extended s3c irq)\n", irqno);set_irq_chip(irqno, &s3c_irqext_chip);set_irq_handler(irqno, handle_edge_irq);set_irq_flags(irqno, IRQF_VALID);}}
irq_desc[irq]数组项的成员chip, handle_irq由set_irq_chip和set_irq_handler初始化即:
desc->handle_irq = handle_edge_irq
desc->chip = s3c_irqext_chip
继续分析handle_edge_irq函数和s3c_irqext_chip的实现:
<span style="font-family: Arial, Helvetica, sans-serif;"></span>
/** *handle_edge_irq - edge type IRQ handler *@irq:the interrupt number *@desc:the interrupt description structure for this irq * *Interrupt occures on the falling and/or rising edge of a hardware *signal. The occurence is latched into the irq controller hardware *and must be acked in order to be reenabled. After the ack another *interrupt can happen on the same source even before the first one *is handled by the assosiacted event handler. If this happens it *might be necessary to disable (mask) the interrupt depending on the *controller hardware. This requires to reenable the interrupt inside *of the loop which handles the interrupts which have arrived while *the handler was running. If all pending interrupts are handled, the *loop is left. */void fastcallhandle_edge_irq(unsigned int irq, struct irq_desc *desc){const unsigned int cpu = smp_processor_id();spin_lock(&desc->lock);desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);/* * If we're currently running this IRQ, or its disabled, * we shouldn't process the IRQ. Mark it pending, handle * the necessary masking and go out */if (unlikely((desc->status & (IRQ_INPROGRESS | IRQ_DISABLED)) || !desc->action)) {desc->status |= (IRQ_PENDING | IRQ_MASKED);mask_ack_irq(desc, irq);goto out_unlock;}kstat_cpu(cpu).irqs[irq]++;/* Start handling the irq */desc->chip->ack(irq); /*xyc:清中断*//* Mark the IRQ currently in progress.*/desc->status |= IRQ_INPROGRESS;do {struct irqaction *action = desc->action;irqreturn_t action_ret;if (unlikely(!action)) {desc->chip->mask(irq);goto out_unlock;}/* * When another irq arrived while we were handling * one, we could have masked the irq. * Renable it, if it was not disabled in meantime. */if (unlikely((desc->status & (IRQ_PENDING | IRQ_MASKED | IRQ_DISABLED)) == (IRQ_PENDING | IRQ_MASKED))) {desc->chip->unmask(irq);desc->status &= ~IRQ_MASKED;}desc->status &= ~IRQ_PENDING;spin_unlock(&desc->lock);action_ret = handle_IRQ_event(irq, action); /*handle_IRQ_event:处理中断*/if (!noirqdebug)note_interrupt(irq, desc, action_ret);spin_lock(&desc->lock);} while ((desc->status & (IRQ_PENDING | IRQ_DISABLED)) == IRQ_PENDING);desc->status &= ~IRQ_INPROGRESS;out_unlock:spin_unlock(&desc->lock);}
包括:
①desc->chip->ack(irq); /*xyc:清中断*/
②action_ret = handle_IRQ_event(irq, action); /*handle_IRQ_event:处理中断*/
继续分析handle_IRQ_event函数:
</pre><pre name="code" class="cpp">/** * handle_IRQ_event - irq action chain handler * @irq:the interrupt number * @action:the interrupt action chain for this irq * * Handles the action chain of an irq event */irqreturn_t handle_IRQ_event(unsigned int irq, struct irqaction *action){irqreturn_t ret, retval = IRQ_NONE;unsigned int status = 0;handle_dynamic_tick(action);if (!(action->flags & IRQF_DISABLED))local_irq_enable_in_hardirq();do {request_irqret = action->handler(irq, action->dev_id); /*调用action中的成语handler处理中断*/if (ret == IRQ_HANDLED)status |= action->flags;retval |= ret;action = action->next;} while (action);if (status & IRQF_SAMPLE_RANDOM)add_interrupt_randomness(irq);local_irq_disable();return retval;}
</pre><p>handle_IRQ_event调用action->handler,即desc->action->handler,而action->handler还没初始化,用户需要编写中断处理函数handler,action结构的声明如下:</p><p></p><pre code_snippet_id="376473" snippet_file_name="blog_20140604_13_2229378" name="code" class="cpp"><pre name="code" class="cpp">struct irqaction {irq_handler_t handler;/*需要用户编写中断服务函数*/unsigned long flags;/*用户确定触发条件,比如低电平,双边沿*/cpumask_t mask;const char *name;/*cat /proc/interrupts显示的中断名称*/void *dev_id;/*对使用同一中断号的一组中断,action出链时,free_irq(irq, dev_id)需要dev_id判断是哪个action出链*/struct irqaction *next;int irq;/*内核统一编码的中断号,需要用户看原理图确定*/struct proc_dir_entry *dir;};
现在需要用户调用request_irq分配action结构体,然后用request_irq的实参填充action结构体,request_irq的实现内核做好了,所以用户需要确定request_irq的实参,然后编写驱动时调用request_irq函数:
int request_irq(unsigned int irq, irq_handler_t handler,unsigned long irqflags, const char *devname, void *dev_id){struct irqaction *action;int retval;action = kmalloc(sizeof(struct irqaction), GFP_ATOMIC);if (!action)return -ENOMEM;action->handler = handler;action->flags = irqflags;cpus_clear(action->mask);action->name = devname;action->next = NULL;action->dev_id = dev_id;select_smp_affinity(irq);retval = setup_irq(irq, action);if (retval)kfree(action);return retval;}首先①kmalloc分配action结构体,②然后用request_irq的参数填充action,现在这个新分配的action还没有挂载到desc->action数组项的irqaction链表中:
action->handler = handler;action->flags = irqflags;cpus_clear(action->mask);action->name = devname;action->next = NULL;action->dev_id = dev_id;
action结构注册到desc->action中,由request_irq调用setup_irq实现:
/* * Internal function to register an irqaction - typically used to * allocate special interrupts that are part of the architecture. */int setup_irq(unsigned int irq, struct irqaction *new){struct irq_desc *desc = irq_desc + irq;struct irqaction *old, **p;const char *old_name = NULL;unsigned long flags;int shared = 0;if (irq >= NR_IRQS)return -EINVAL;if (desc->chip == &no_irq_chip)return -ENOSYS;/* * Some drivers like serial.c use request_irq() heavily, * so we have to be careful not to interfere with a * running system. */if (new->flags & IRQF_SAMPLE_RANDOM) {/* * This function might sleep, we want to call it first, * outside of the atomic block. * Yes, this might clear the entropy pool if the wrong * driver is attempted to be loaded, without actually * installing a new handler, but is this really a problem, * only the sysadmin is able to do this. */rand_initialize_irq(irq);}/* * The following block of code has to be executed atomically */spin_lock_irqsave(&desc->lock, flags);p = &desc->action;old = *p;if (old) {/* * Can't share interrupts unless both agree to and are * the same type (level, edge, polarity). So both flag * fields must have IRQF_SHARED set and the bits which * set the trigger type must match. */ /* action不为空,但是不允许共享中断,就mismatch*/if (!((old->flags & new->flags) & IRQF_SHARED) || ((old->flags ^ new->flags) & IRQF_TRIGGER_MASK)) {old_name = old->name;goto mismatch;}#if defined(CONFIG_IRQ_PER_CPU)/* All handlers must agree on per-cpuness */if ((old->flags & IRQF_PERCPU) != (new->flags & IRQF_PERCPU))goto mismatch;#endif/*不为空,且允许共享中断号,shared由0变为1,经过do{}while,此时p等于最后一个irqaction结构成员next的地址*//* add new interrupt at end of irq queue */do {p = &old->next;old = *p;} while (old);shared = 1;}*p = new;/*将request_irq分配的action加入到irqaction链表中*//* Exclude IRQ from balancing */if (new->flags & IRQF_NOBALANCING)desc->status |= IRQ_NO_BALANCING;/*shared为1表示 action链表中有2个 action项了,包括刚加的一个*//*shared为0表示链表中只要刚刚加入的new irqaction结构,这时需要设置默认的使能屏蔽等函数*/if (!shared) {irq_chip_set_defaults(desc->chip);#if defined(CONFIG_IRQ_PER_CPU)if (new->flags & IRQF_PERCPU)desc->status |= IRQ_PER_CPU;#endif/* Setup the type (level, edge polarity) if configured: */if (new->flags & IRQF_TRIGGER_MASK) {if (desc->chip && desc->chip->set_type)desc->chip->set_type(irq, new->flags & IRQF_TRIGGER_MASK); /*设置为中断引脚,触发方式为水平,单边沿,双边沿等等*/else/* * IRQF_TRIGGER_* but the PIC does not support * multiple flow-types? */printk(KERN_WARNING "No IRQF_TRIGGER set_type " "function for IRQ %d (%s)\n", irq, desc->chip ? desc->chip->name : "unknown");} elsecompat_irq_chip_set_default_handler(desc);desc->status &= ~(IRQ_AUTODETECT | IRQ_WAITING | IRQ_INPROGRESS);if (!(desc->status & IRQ_NOAUTOEN)) {desc->depth = 0;desc->status &= ~IRQ_DISABLED;if (desc->chip->startup)desc->chip->startup(irq);/*使能中断*/elsedesc->chip->enable(irq);} else/* Undo nested disables: */desc->depth = 1;}/* Reset broken irq detection when installing new handler */desc->irq_count = 0;desc->irqs_unhandled = 0;spin_unlock_irqrestore(&desc->lock, flags);new->irq = irq;register_irq_proc(irq);new->dir = NULL;register_handler_proc(irq, new);return 0;mismatch:#ifdef CONFIG_DEBUG_SHIRQif (!(new->flags & IRQF_PROBE_SHARED)) {printk(KERN_ERR "IRQ handler type mismatch for IRQ %d\n", irq);if (old_name)printk(KERN_ERR "current handler: %s\n", old_name);dump_stack();}#endifspin_unlock_irqrestore(&desc->lock, flags);return -EBUSY;}
set_irq会找到desc->action挂载的链表irqaction的链表尾,然后将request_irq分配的action挂载在链表尾,其分为两种情况:
①如果先前有挂载irqaction,这次action如果不允许共享此中断号,则挂载失败
②如果可以共享此中断号,p等于链表尾成员next的地址,且shared由0变为1,
最后通过*p =new将action挂载到链表中,然后根据shared的值可以判断new是第一个链表项,还是2和2以后的链表项,若是第一个链表项(此时shared = 0),则需要设置此中断其对应引脚为中断引脚,触发方式,最后使能中断,若是还是2和2以后的链表项,则先前第一个链表项已经设置了这3项功能(中断引脚,触发方式,使能中断)
到了这里,若对于EINT4来说,内核帮我们初始化了handle_irq, chip, :
struct irq_desc {irq_flow_handler_thandle_irq; /*内核初始化handle_irq = handle_edge_irq*/struct irq_chip*chip;/*内核初始化为chip = s3c_irq_eint0t4*/struct msi_desc*msi_desc;void*handler_data;void*chip_data;struct irqaction*action;/* 内核用request_irq构造action链表,action链表项中的成员值由用户确定 */unsigned intstatus;/* IRQ status */unsigned intdepth;/* nested irq disables */unsigned intwake_depth;/* nested wake enables */unsigned intirq_count;/* For detecting broken IRQs */unsigned intirqs_unhandled;spinlock_tlock;struct proc_dir_entry*dir;const char*name;} ____cacheline_internodealigned_in_smp;
内核初始化handle_irq后,发生中断就会调用handle_edge_irq,其完成①清中断,②调用action->handler,而用户调用request_irq时用其实参构造并初始化了action结构体
<pre name="code" class="cpp">struct irqaction {irq_handler_t handler; /*需要用户编写中断服务函数*/unsigned long flags;/*用户确定触发条件,比如低电平,双边沿*/cpumask_t mask;const char *name;/*cat /proc/interrupts显示的中断名称*/void *dev_id;/*对使用同一中断号的一组中断,action出链时,free_irq(irq, dev_id)需要dev_id判断是哪个action出链*/struct irqaction *next;int irq;/*内核统一编码的中断号,需要用户看原理图和asm-arm/s3c2410/irqs.h确定*/struct proc_dir_entry *dir;};
整个中断处理函数框架为下图:
由上述可知,需要确定request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char * devname, void * dev_id)各个参数项,对应action结构体主要成员,然后调用request_irq,比如对于EINT4来说可以这样调用
request_irq(IRQ_EINT4, buttons_irq, IRQT_BOTHEDGE, "s4", 1);
buttons_irq函数需要用户编写:
编写的通过中断获取按键值的驱动源码third_drv.c如下:
/****************************************************************filename: third_drv.c*description:通过中断的方法获取按键值*author: xyc*create time:2014/6/5*version: 1*modify info:****************************************************************/#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/delay.h>#include <linux/irqreturn.h>#include <linux/irq.h>#include <linux/wait.h>#include <asm/irq.h>#include <asm/arch/regs-gpio.h>#include <asm/hardware.h>#include <asm-arm/io.h>#include <asm-arm/uaccess.h>static struct class *thirddrv_class;static struct class_device*thirddrv_class_dev;static unsigned char key_val;static DECLARE_WAIT_QUEUE_HEAD(buttons_waitq); struct pin_desc {unsigned int pin;unsigned int key_val;};/* *按下:0x01, 0x02 *松开:0x81, 0x82 */static struct pin_desc pins_desc[2] = {{S3C2410_GPF0,0x01},{S3C2410_GPF2,0x02},};static volatile unsigned int condition= 0;static irqreturn_t buttons_irq(int irq, void *dev_id){struct pin_desc * pindesc= (struct pin_desc * )dev_id;unsigned int pinval;/*读取引脚值*/pinval = s3c2410_gpio_getpin(pindesc->pin);/*确定键值*/if(pinval){/*松开*/key_val = 0x80 | pindesc->key_val ;//printk("kernel key_val = 0x%x\n", key_val);}else{/*按下*/key_val = pindesc->key_val ;//printk("kernel key_val = 0x%x\n", key_val);}/*按键按下或松开中断发生将condition = 1使得满足wait_event_interruptible唤醒的条件*/condition = 1;/*唤醒休眠的进程./third_drv_test */wake_up_interruptible(&buttons_waitq);return IRQ_HANDLED;}static int third_drv_open(struct inode *inode, struct file *file){request_irq(IRQ_EINT0, buttons_irq, IRQT_BOTHEDGE, "s2", &pins_desc[0]);request_irq(IRQ_EINT2, buttons_irq, IRQT_BOTHEDGE, "s3", &pins_desc[1]);return 0;}static ssize_t third_drv_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos){if(nbytes != 1)return EINVAL;/*没有按键按下时,./third_drv_test 进程休眠,*/wait_event_interruptible(buttons_waitq, condition);/*有按键按下或松开时,结束休眠,并将键值传给应用程序*/copy_to_user(buf, &key_val, 1);/*当下一次应用调用read时,condition = 0使得./third_drv_test 进程休眠*/condition = 0;return 1;}static int third_drv_release(struct inode * inode, struct file * file){free_irq(IRQ_EINT0, &pins_desc[0]);free_irq(IRQ_EINT2, &pins_desc[1]);return 0;}static const struct file_operations third_drv_fops = {.owner= THIS_MODULE,.read= third_drv_read,.open= third_drv_open,.release=third_drv_release,};int major;static int __init third_drv_init(void){major = register_chrdev(0, "third_drv", &third_drv_fops);thirddrv_class = class_create(THIS_MODULE, "third_drv"); thirddrv_class_dev = class_device_create(thirddrv_class, NULL, MKDEV(major, 0), NULL, "buttons");return 0;}static void __exit third_drv_exit(void){ /* 卸载驱动程序 */ unregister_chrdev(major, "third_drv"); class_device_unregister(thirddrv_class_dev); class_destroy(thirddrv_class);}/* 这两行指定驱动程序的初始化函数和卸载函数 */module_init(third_drv_init);module_exit(third_drv_exit);MODULE_LICENSE("GPL");
third_drv.c编译成third_drv.ko的Makefile为
KERN_DIR = /work/system/linux-2.6.22.6all: make -C $(KERN_DIR) M=`pwd` modules clean: make -C $(KERN_DIR) M=`pwd` modules clean rm -rf modules.orderobj-m += third_drv.o
测试代码third_drv_test.c代码为:
#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>int main(int argc, char *argv[]){int fd1;unsigned char keys_val;fd1 = open("/dev/buttons", O_RDWR);if(fd1<0)printf("open failed\n");while(1){read(fd1, &keys_val, 1);printf("keys_val = 0x%x\n", keys_val);}return 0;}
测试:
可以单独测试驱动源码third_drv.c中的third_drv_open和buttons_irq函数,当然buttons_irq中的2行相同打印应该打开:
printk("kernel key_val = 0x%x\n", key_val);当然应该先lsmod看是否有旧的third_drv.ko模块,若有,则 rmmod third_drv.ko
# insmod third_drv.ko# exec 5</dev/buttons # cat proc/interrupts CPU0 16: 8 s3c-ext0 s2 18: 4 s3c-ext0 s3 30: 58489 s3c S3C2410 Timer Tick 32: 0 s3c s3c2410-lcd 33: 0 s3c s3c-mci 34: 0 s3c I2SSDI 35: 0 s3c I2SSDO 37: 12 s3c s3c-mci 42: 0 s3c ohci_hcd:usb1 43: 0 s3c s3c2440-i2c 51: 1416 s3c-ext eth0 60: 0 s3c-ext s3c-mci 70: 319 s3c-uart0 s3c2440-uart 71: 369 s3c-uart0 s3c2440-uart 79: 0 s3c-adc s3c2410_action 80: 0 s3c-adc s3c2410_action 83: 0 - s3c2410-wdtErr: 0# ps PID Uid VSZ Stat Command 1 0 3092 S init 2 0 SW< [kthreadd] 3 0 SWN [ksoftirqd/0] 4 0 SW< [watchdog/0] 5 0 SW< [events/0] 6 0 SW< [khelper] 55 0 SW< [kblockd/0] 56 0 SW< [ksuspend_usbd] 59 0 SW< [khubd] 61 0 SW< [kseriod] 73 0 SW [pdflush] 74 0 SW [pdflush] 75 0 SW< [kswapd0] 76 0 SW< [aio/0] 710 0 SW< [mtdblockd] 745 0 SW< [kmmcd] 762 0 SW< [rpciod/0] 770 0 3096 S -sh 788 0 3096 R ps # ls -l proc/770/fdproc/770/fd/ proc/770/fdinfo/# ls -l proc/770/fd/*ls: proc/770/fd/3: No such file or directorylrwx------ 1 0 0 64 Jan 1 00:03 proc/770/fd/0 -> /dev/consolelrwx------ 1 0 0 64 Jan 1 00:03 proc/770/fd/1 -> /dev/consolelrwx------ 1 0 0 64 Jan 1 00:03 proc/770/fd/10 -> /dev/ttylrwx------ 1 0 0 64 Jan 1 00:03 proc/770/fd/2 -> /dev/consolelr-x------ 1 0 0 64 Jan 1 00:03 proc/770/fd/5 -> /dev/buttons
打开/dev/buttons设备用exec命令,exec 5</dev/buttons表示将设备/dev/buttons打开并重定位到文件描述符5,即操作文件描述符5就是操作/dev/buttons
关闭/dev/buttons用exec 5<&- 这时文件描述符5和/dev/buttons脱钩了(用rmmod之前必须 exec 5<&- 用来关闭dev/buttons)
快速按键和慢速按键:
# kernel key_val = 0x1kernel key_val = 0x81kernel key_val = 0x1kernel key_val = 0x1kernel key_val = 0x81kernel key_val = 0x1kernel key_val = 0x1kernel key_val = 0x81kernel key_val = 0x1kernel key_val = 0x81kernel key_val = 0x1kernel key_val = 0x1kernel key_val = 0x81kernel key_val = 0x81kernel key_val = 0x1kernel key_val = 0x81kernel key_val = 0x1kernel key_val = 0x81
存在问题:可知因按键是机械的,存在抖动,所以存在将按下或松开动作当作了发生了多个动作
用测试代码测试,将刚刚的2行驱动打印屏蔽掉,然后编译并复制third_drv.ko到网络根文件系统下:
#exec 5<&-
#rmmod third_drv
# insmod third_drv.ko# ./third_drv_test &# keys_val = 0x2keys_val = 0x82keys_val = 0x2keys_val = 0x2keys_val = 0x82keys_val = 0x2keys_val = 0x82keys_val = 0x2keys_val = 0x82# topMem: 6724K used, 54460K free, 0K shrd, 0K buff, 2100K cachedCPU: 0% usr 0% sys 0% nice 99% idle 0% io 0% irq 0% softirqLoad average: 0.00 0.00 0.00 PID PPID USER STAT VSZ %MEM %CPU COMMAND 801 770 0 R 3092 5% 1% top 770 1 0 S 3096 5% 0% -sh 1 0 0 S 3092 5% 0% init 800 770 0 S 1312 2% 0% ./third_drv_test 6 2 0 SW< 0 0% 0% [khelper] 762 2 0 SW< 0 0% 0% [rpciod/0] 745 2 0 SW< 0 0% 0% [kmmcd] 2 0 0 SW< 0 0% 0% [kthreadd] 3 2 0 SWN 0 0% 0% [ksoftirqd/0] 4 2 0 SW< 0 0% 0% [watchdog/0] 5 2 0 SW< 0 0% 0% [events/0] 55 2 0 SW< 0 0% 0% [kblockd/0] 56 2 0 SW< 0 0% 0% [ksuspend_usbd] 59 2 0 SW< 0 0% 0% [khubd] 61 2 0 SW< 0 0% 0% [kseriod] 73 2 0 SW 0 0% 0% [pdflush] 74 2 0 SW 0 0% 0% [pdflush] 75 2 0 SW< 0 0% 0% [kswapd0] 76 2 0 SW< 0 0% 0% [aio/0] 710 2 0 SW< 0 0% 0% [mtdblockd]
由top可知按键使用中断上报键值和休眠后,./third_drv_test进程所占CPU接近%0,但是却存在2个问题
①按键抖动--可用定时器去抖动
②如果没有按键,测试代码的read进程./third_drv_test一直休眠,不会返回,如果我想5s没有按键中断发生同样返回(在5s内发生的中断当然立刻返回键值),就需要用到poll机制,
NOTE:关于应用read返回值,和third_drv_read的return 语句的返回值相同,如果将return 1;改为,return 4;测试代码中打印出read的返回值则为4,添加的代码由注释说明,测试代码为:
#include <sys/types.h>#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>int main(int argc, char *argv[]){/*用于测试read的返回值和驱动函数third_drv_read返回值是否相同*/int fd1, ret;unsigned char keys_val;fd1 = open("/dev/buttons", O_RDWR);if(fd1<0)printf("open failed\n");while(1){ret = read(fd1, &keys_val, 1); /*增加取出返回值*/printf("ret =0x%x\n", ret); /*打印返回值*/printf("keys_val = 0x%x\n", keys_val);}return 0;}
# rmmod third_drv
rmmod: third_drv: Resource temporarily unavailable
是因为这个驱动模块还有用户使用,可以用lsmod 查看third_drv模块使用的用户数为2,比如./third_drv_test测试进程调用了third_drv_read,而后执行完wait_event_interruptible(buttons_waitq, condition);这行时,进程休眠了
# lsmod
Module Size Used by Not tainted
third_drv 3124 2
因此需要杀掉这个使用third_drv模块的进程./third_drv_test ,使用kill -9 pid ,用ps查看./third_drv_test的pid
# ps PID Uid VSZ Stat Command 1 0 3092 S init 2 0 SW< [kthreadd] 3 0 SWN [ksoftirqd/0] 4 0 SW< [watchdog/0] 5 0 SW< [events/0] 6 0 SW< [khelper] 55 0 SW< [kblockd/0] 56 0 SW< [ksuspend_usbd] 59 0 SW< [khubd] 61 0 SW< [kseriod] 73 0 SW [pdflush] 74 0 SW [pdflush] 75 0 SW< [kswapd0] 76 0 SW< [aio/0] 710 0 SW< [mtdblockd] 745 0 SW< [kmmcd] 762 0 SW< [rpciod/0] 770 0 3096 S -sh 783 0 1312 S ./third_drv_test
kill -9 783
这时rmmod third_drv/rmmod third_drv.ko均可卸载(第一个为register_chdev中的第二个参数,模块名,cat /proc/devices可显示)
如果只改变了测试代码,而驱动代码没变,只需要杀掉测试进程./third_drv_test ,而不需要用rmmod third_drv来卸载驱动模块
- Linux中断处理体系结构
- Linux中断处理体系结构
- linux中断处理体系结构
- linux中断处理体系结构
- Linux中断处理体系结构
- 中断处理体系结构
- Linux中断处理体系结构
- Linux中断处理体系结构分析
- Linux中断处理体系结构2
- Linux中断处理体系结构分析(一)
- linux中断处理体系结构分析(二)
- Linux中断处理体系结构分析(1)
- Linux中断处理体系结构分析(2)
- Linux中断处理体系结构分析(一)
- Linux中断处理体系结构分析(二)
- linux中断处理体系结构--看懂了三分之一
- Linux中断处理体系结构分析(一)
- Linux中断处理体系结构分析(二)
- Making User-Managed Backups-17.3、Making User-Managed Backups of Offline Tablespaces and Datafiles
- JSON 字符串 与 java 对象的转换
- 对苹果“五仁”编程语言Swift的简单分析
- setDescendantFocusability,在父View和子View间处理焦点关系
- 根据结构体某个成员的地址求出结构体所有成员的值
- 中断处理体系结构
- jquery $.get $.post的区别
- 利用图像中物体轮廓做简单的图像匹配
- 一个简单的自动化测试报告
- hadoop学习笔记之数据排序
- usaco 4.4.2 Pollutant Control
- 杭电 1421 搬寝室
- 适用于kali linux的远程桌面开启方法(从windows xp 远程登录到kali linux )
- cocos2dx 多线程