Chinaunix首页 | 论坛 | 博客
  • 博客访问: 465350
  • 博文数量: 191
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 172
  • 用 户 组: 普通用户
  • 注册时间: 2013-10-31 14:35
个人简介

没有时间把一件事情做好,却有时间把一件事情反复做!

文章分类

全部博文(191)

文章存档

2016年(2)

2015年(74)

2014年(111)

2013年(4)

我的朋友

分类: 嵌入式

2014-03-26 15:38:16

在linux2.6内核驱动中,为设备实现一套中断处理机制提供了如下两个步骤:

1.向内核注册中断处理;2.实现中断处理函数

int request_irq(unsigned int irq,void (*handler)(int, void*, struct pt_regs *),unsigned long flags,const char *devname,void *dev_id)       //注册中断;返回0表示成功,或者返回一个错误码

参数含义

unsigned int irq          中断号

void (*handler)(int,void *,struct pt_regs *)    中断处理函数

unsigned long flags     与中断管理有关的各种选项;如IRQF_DISABLED,IRQF_SHARED

const char * devname                    设备名

void *dev_id                             共享中断时使用

注意1 共享设备就是将不同的设备挂接到同一个中断信号线上,liunx对共享的支持主要是用在PCI设备服务。且在共享中断时,dev_id必须唯一指定。

注意2  共享中断的处理程序中,不能使用 disable_irq(unsigned int irq)   因为如果使用了这个函数,共享中断信线的其它设备将同样无法使用中断,也就无法正常工作了。

handler中断处理程序

中断处理程序就是普通的C代码。特别之处在于中断处理程序是在中断上下文中运行的,它的行为受到某些限制

1. 不能向用户空间发送或接受数据   2. 不能使用可能引起阻塞的函数  3. 不能使用可能引起调度的函数

中断处理函数一个实例如下

复制代码
 1 void short_sh_interrupt(int irq, void *dev_id, struct pt_regs *regs)  2 {  3 /* 判断是否是本设备产生了中断(为什么要做这样的检测?    共享中断) */  4 value = inb(short_base);  5 if (!(value & 0x80)) return;  6 /* 清除中断位(如果设备支持自动清除,则不需要这步) */  7 outb(value & 0x7F, short_base);  8 /* 中断处理,通常是数据接收*/  9  。。。。。。。。。 10 /* 唤醒等待数据的进程*/ 11 wake_up_interruptible(&short_queue); 12 }
复制代码

释放中断函数

void free_irq(unsigned int irq, void *dev_id)   //当设备不再需要使用中断时(通常在驱动卸载时), 应当把它们返还给系统

附s3c24xx按键中断驱动程序源码:

复制代码
 1 #include   2 #include   3 #include   4 #include   5 #include   6 #include   7 #include   8 #include   9 #include   10 #include   11 #include   12 #include   13 #include   14 #include   15 #include   16 #include   17 #include   18  19 #define DEVICE_NAME     "buttons"  20  21 struct button_irq_desc {  22 int irq;  23 int pin;  24 int pin_setting;  25 int number;  26 char *name;  27 };  28  29 //#define       DEBUG  30 #undef DEBUG  31 #define QIUSHI  32 #define START_BUTTON    8  33  34 #ifdef  QIUSHI  35 static struct button_irq_desc button_irqs [] = {  36 {IRQ_EINT0, S3C2410_GPF(0),  S3C2410_GPF0_EINT0, 0, "KEY0"},  37 {IRQ_EINT1, S3C2410_GPF(1),  S3C2410_GPF1_EINT1, 1, "KEY1"},  38 {IRQ_EINT2, S3C2410_GPF(2),  S3C2410_GPF2_EINT2, 2, "KEY2"},  39 {IRQ_EINT3, S3C2410_GPF(3),  S3C2410_GPF3_EINT3, 3, "KEY3"},  40 {IRQ_EINT4, S3C2410_GPF(4),  S3C2410_GPF4_EINT4, 4, "KEY4"},  41 {IRQ_EINT5, S3C2410_GPF(5),  S3C2410_GPF5_EINT5, 5, "KEY5"},  42 {IRQ_EINT6, S3C2410_GPF(6),  S3C2410_GPF6_EINT6, 6, "KEY6"},  43 {IRQ_EINT8, S3C2410_GPG(0),  S3C2410_GPG0_EINT8, 7, "KEY7"},  44 {IRQ_EINT9, S3C2410_GPG(1),  S3C2410_GPG1_EINT9, 8, "KEY8"},  45 };  46 #else  47 static struct button_irq_desc button_irqs [] = {  48 {IRQ_EINT8 , S3C2410_GPG(0) ,  S3C2410_GPG0_EINT8  , 0, "KEY0"},  49 {IRQ_EINT11, S3C2410_GPG(3) ,  S3C2410_GPG3_EINT11 , 1, "KEY1"},  50 {IRQ_EINT13, S3C2410_GPG(5) ,  S3C2410_GPG5_EINT13 , 2, "KEY2"},  51 {IRQ_EINT14, S3C2410_GPG(6) ,  S3C2410_GPG6_EINT14 , 3, "KEY3"},  52 {IRQ_EINT15, S3C2410_GPG(7) ,  S3C2410_GPG7_EINT15 , 4, "KEY4"},  53 {IRQ_EINT19, S3C2410_GPG(11),  S3C2410_GPG11_EINT19, 5, "KEY5"},  54 };  55 #endif  56  57 static volatile char key_values [] = {'0', '0', '0', '0', '0', '0', '0', '0', '0'};  58  59 static DECLARE_WAIT_QUEUE_HEAD(button_waitq);  60  61 static volatile int ev_press = 0;  62  63  64 static irqreturn_t buttons_interrupt(int irq, void *dev_id)  65 {  66 struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id;  67 int down;  68  69 // udelay(0);  70 down = !s3c2410_gpio_getpin(button_irqs->pin);  71  72 #ifdef  DEBUG  73 printk( "%s: new=%d, old=%d\n", __FUNCTION__ , down,  (key_values[button_irqs->number] & 1));  74 #endif  75  76 if (down != (key_values[button_irqs->number] & 1)) { // Changed  77  78 key_values[button_irqs->number] = '0' + down;  79  80 ev_press = 1;  81 wake_up_interruptible(&button_waitq);  82  }  83 return IRQ_RETVAL(IRQ_HANDLED);  84 }  85  86  87 static int s3c24xx_buttons_open(struct inode *inode, struct file *file)  88 {  89 int i;  90 int err = 0;  91  92 for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) {  93 if (button_irqs[i].irq < 0) {  94 continue;  95  }  96 err = request_irq(button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_BOTH,  97 button_irqs[i].name, (void *)&button_irqs[i]);  98 if (err)  99  { 100 printk( "%s: err=%d, but=%d\n", __FUNCTION__, err, i); 101 break; 102  } 103  } 104 /*错误处理*/ 105 if (err) { 106 i--; 107 for (; i >= 0; i--) { 108 if (button_irqs[i].irq < 0) { 109 continue; 110  } 111  disable_irq(button_irqs[i].irq); 112 free_irq(button_irqs[i].irq, (void *)&button_irqs[i]); 113  } 114 return -EBUSY; 115  } 116 117 ev_press = 1; 118 119 return 0; 120 } 121 122 123 static int s3c24xx_buttons_close(struct inode *inode, struct file *file) 124 { 125 int i; 126 127 for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) { 128 if (button_irqs[i].irq < 0) { 129 continue; 130  } 131 free_irq(button_irqs[i].irq, (void *)&button_irqs[i]); 132  } 133 134 return 0; 135 } 136 137 138 static int s3c24xx_buttons_read(struct file *filp, char __user *buff, size_t count, loff_t *offp) 139 { 140 unsigned long err; 141 142 if (!ev_press) { 143 if (filp->f_flags & O_NONBLOCK) 144 return -EAGAIN; 145 else 146  wait_event_interruptible(button_waitq, ev_press); 147  } 148 149 ev_press = 0; 150 151 err = copy_to_user(buff, (const void *)key_values, min(sizeof(key_values), count)); 152 153 return err ? -EFAULT : min(sizeof(key_values), count); 154 } 155 156 /*poll做两件事?poll_wait指明使用的等待队列,返回掩码*/ 157 158 static unsigned int s3c24xx_buttons_poll( struct file *file, struct poll_table_struct *wait) 159 { 160 unsigned int mask = 0; 161 poll_wait(file, &poll_wait, wait); 162 if (ev_press) /*按下evpress为1,有数据刻可读*/ 163 mask |= POLLIN | POLLRDNORM; 164 return mask; 165 } 166 167 168 169 170 static int s3c2410_buttons_ioctl( 171 struct inode *inode, 172 struct file *file, 173 unsigned int cmd, 174 unsigned long arg) 175 { int down; 176 down = s3c2410_gpio_getpin(button_irqs[START_BUTTON].pin); 177 return down; 178 } 179 180 181 static struct file_operations dev_fops = { 182 .owner   = THIS_MODULE, 183 .open    = s3c24xx_buttons_open, 184 .release = s3c24xx_buttons_close, 185 .read    = s3c24xx_buttons_read, 186 .poll    = s3c24xx_buttons_poll, 187 .ioctl  = s3c2410_buttons_ioctl, 188 }; 189 190 191 static struct miscdevice misc = { 192 .minor = MISC_DYNAMIC_MINOR, 193 .name = DEVICE_NAME, 194 .fops = &dev_fops, 195 }; 196 197 static int __init dev_init(void) 198 { 199 int ret; 200 201 ret = misc_register(&misc); 202 203 printk (DEVICE_NAME"\tinitialized\n"); 204 205 return ret; 206 } 207 208 static void __exit dev_exit(void) 209 { 210 misc_deregister(&misc); 211 } 212 213 module_init(dev_init); 214 module_exit(dev_exit); 215 MODULE_LICENSE("GPL"); 216 MODULE_AUTHOR("QiuShi Inc.");
复制代码

 

platform总线是linux2.6内核后加入的一条虚拟总线,由两部分组成:platform_device和platform_driver;优势在于platform机制将设备本身的资源注册进内核,由内核统一管理,在驱动程序使用这些资源时使用统一的接口,提高可可移植性。

结构体平台设备 struct platform_device

复制代码
 1 struct platform_device {  2 const char * name;  3 int id;  4 struct device    dev;  5  u32        num_resources;  6 struct resource    * resource;  7  8 const struct platform_device_id    *id_entry;  9 10 /* arch specific additions */ 11 struct pdev_archdata    archdata; 12 };
复制代码

struct platform_device*platform_device_alloc(const char *name, int id)  //平台设备分配函数

int platform_device_add(struct platform_device *pdev)   平台设备注册函数

平台设备资源 结构体 struct resource

复制代码
1 struct resource { 2  resource_size_t start;   //资源的起始物理地址 3  resource_size_t end;    //资源的结束物理地址 4 const char *name;       //资源的名称 5 unsigned long flags;     //资源的类型;常用有MEM,IO,IRQ等 6 struct resource *parent, *sibling, *child;  //资源的链表指针 7 };
设备资源分配实例:
复制代码
 1 static struct resource s3c_wdt_resource1 = {  2  3 .start = 0x44100000,  4  5 .end   = 0x44200000,  6  7 .flags = IORESOURCE_MEM,  8  9  } 10 11 static struct resource s3c_wdt_resource2 = { 12 13 .start = 20, 14 15 .end   = 20, 16 17 .flags = IORESOURCE_IRQ, 18 19 } 
复制代码

 

复制代码

struct resource *platform_get_resource(struct platform_device *dev, unsigned int type, unsigned int num)                       //获取资源分配函数

参数:

vdev: 资源所属的设备

vtype: 获取的资源类型

vnum: 获取的资源数

例:

platform_get_resource(pdev, IORESOURCE_IRQ, 0)                  //获取中断

 

结构体平台驱动 struct platform_driver

复制代码
1 struct platform_driver { 2 int (*probe)(struct platform_device *); 3 int (*remove)(struct platform_device *); 4 void (*shutdown)(struct platform_device *); 5 int (*suspend)(struct platform_device *, pm_message_t state); 6 int (*resume)(struct platform_device *); 7 struct device_driver driver; 8 const struct platform_device_id *id_table; 9 };
复制代码

int platform_driver_register(struct platform_driver *)     //平台驱动注册使用函数

void platform_driver_unregister(struct platform_driver *);  //平台驱动卸载使用函数

下例结合mini2440利用平台驱动模型来分析按键中断程序

plat_device.c

复制代码
 1 #include   2 #include   3 #include   4 #include   5 #include   6 #include   7 #include   8 #include   9 #include  10 11 /*平台资源的定义*/ 12 static struct resource s3c_buttons_resource[] = { 13 [0]={ 14 .start = S3C24XX_PA_GPIO, 15 .end   = S3C24XX_PA_GPIO + S3C24XX_SZ_GPIO - 1, 16 .flags = IORESOURCE_MEM, 17  }, 18 19 [1]={ 20 .start = IRQ_EINT8, 21 .end   = IRQ_EINT8, 22 .flags = IORESOURCE_IRQ, 23  }, 24 [2]={ 25 .start = IRQ_EINT11, 26 .end   = IRQ_EINT11, 27 .flags = IORESOURCE_IRQ, 28  }, 29 [3]={ 30 .start = IRQ_EINT13, 31 .end   = IRQ_EINT13, 32 .flags = IORESOURCE_IRQ, 33  }, 34 [4]={ 35 .start = IRQ_EINT14, 36 .end   = IRQ_EINT14, 37 .flags = IORESOURCE_IRQ, 38  }, 39 [5]={ 40 .start = IRQ_EINT15, 41 .end   = IRQ_EINT15, 42 .flags = IORESOURCE_IRQ, 43  }, 44 [6]={ 45 .start = IRQ_EINT19, 46 .end   = IRQ_EINT19, 47 .flags = IORESOURCE_IRQ, 48  } 49 }; 50 51 static struct platform_device *s3c_buttons; 52 53 54 static int __init platform_init(void) 55 { 56 57 s3c_buttons = platform_device_alloc("mini2440-buttons",-1); 58 59 platform_device_add_resources(s3c_buttons,&s3c_buttons_resource,7); 60 61 /*平台设备的注册*/ 62  platform_device_add(s3c_buttons); 63 64 65 } 66 67 static void __exit platform_exit(void) 68 { 69  platform_device_unregister(s3c_buttons); 70 } 71 72 module_init(platform_init); 73 module_exit(platform_exit); 74 75 MODULE_AUTHOR("David Xie"); 76 MODULE_LICENSE("GPL"); 77 MODULE_ALIAS("platform:mini2440buttons");
复制代码

plat_buttons.c

复制代码
 1 #include   2 #include   3 #include   4 #include   5 #include   6 #include   7 #include   8 #include   9 #include   10 #include   11 #include   12 #include   13 #include   14 #include   15 #include   16 #include   17  18  19 static DECLARE_WAIT_QUEUE_HEAD(button_waitq);  20  21 static volatile int ev_press = 0;  22  23  24 static int key_value;  25 static struct device     *buttons_dev; /* platform device attached to */  26 static struct resource    *buttons_mem;  27 static struct resource   *buttons_irq;  28 static void __iomem        *buttons_base;  29  30  31 static int button_irqs[6];  32  33 static irqreturn_t buttons_interrupt(int irq, void *dev_id)  34 {  35 int i;  36 for(i=0; i<6; i++){  37 if(irq == button_irqs[i]){  38 //printk("==>interrput number:%d\n",irq);   39 key_value = i;  40 ev_press =1;  41 wake_up_interruptible(&button_waitq);  42  }  43  }  44  45 return IRQ_RETVAL(IRQ_HANDLED);  46  47 }  48  49 static int s3c24xx_buttons_open(struct inode *inode, struct file *file)  50 {  51 int i;  52 int err = 0;  53 /*注册中断*/  54 for(i=0; i<6; i++){  55 if (button_irqs[i] < 0)  56 continue;  57  58 /*中断触发方式:上升沿触发*/  59 err = request_irq(button_irqs[i],buttons_interrupt,IRQ_TYPE_EDGE_RISING,NULL,NULL);  60 if(err)  61 break;  62  }  63  64 if (err) {  65 i--;  66 for (; i >= 0; i--) {  67 if (button_irqs[i] < 0) {  68 continue;  69  }  70  disable_irq(button_irqs[i]);  71  free_irq(button_irqs[i], NULL);  72  }  73 return -EBUSY;  74  }  75  76 ev_press = 0;  77 return 0;  78 }  79  80 static int s3c24xx_buttons_close(struct inode *inode, struct file *file)  81 {  82 int i;  83 for (i=0; i<6; i++) {  84 if (button_irqs[i] < 0) {  85 continue;  86  }  87  free_irq(button_irqs[i],NULL);  88  }  89 return 0;  90 }  91  92 static int s3c24xx_buttons_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)  93 {  94 unsigned long err;  95 if (!ev_press) {  96 if (filp->f_flags & O_NONBLOCK)  97 return -EAGAIN;  98 else  99  wait_event_interruptible(button_waitq, ev_press); 100  } 101 ev_press = 0; 102 err = copy_to_user(buff, &key_value, sizeof(key_value)); 103 return sizeof(key_value); 104 } 105 //轮询poll要做两件事:poll_wait指明使用的等待队列;返回掩码 106 static unsigned int s3c24xx_buttons_poll( struct file *file, struct poll_table_struct *wait) 107 { 108 unsigned int mask = 0; 109 poll_wait(file, &button_waitq, wait); 110 if (ev_press){ 111 mask |= POLLIN | POLLRDNORM; /*按下evpress为1,有数据刻可读*/ 112  } 113 return mask; 114 } 115 116 117 118 static struct file_operations mini2440buttons_fops = { 119 .owner   = THIS_MODULE, 120 .open    = s3c24xx_buttons_open, 121 .release = s3c24xx_buttons_close, 122 .read    = s3c24xx_buttons_read, 123 .poll    = s3c24xx_buttons_poll, 124 }; 125 126 static struct miscdevice mini2440_miscdev = { 127 128 .minor = MISC_DYNAMIC_MINOR, 129 .name ="buttons", 130 .fops = &mini2440buttons_fops, 131 }; 132 133 /* device interface */ 134 static int mini2440_buttons_probe(struct platform_device *pdev) 135 { 136 struct resource *res; 137 struct device *dev; 138 int ret; 139 int size; 140 int i; 141 142 printk("probe:%s\n", __func__); 143 dev = &pdev->dev; 144 buttons_dev = &pdev->dev; 145 146 /*平台资源获取*/ 147 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 148 if (res == NULL) { 149 dev_err(dev, "no memory resource specified\n"); 150 return -ENOENT; 151  } 152 153 size = (res->end - res->start) + 1; 154 buttons_mem = request_mem_region(res->start, size, pdev->name); 155 if (buttons_mem == NULL) { 156 dev_err(dev, "failed to get memory region\n"); 157 ret = -ENOENT; 158 goto err_req; 159  } 160 161 buttons_base = ioremap(res->start, size); 162 if (buttons_base == NULL) { 163 dev_err(dev, "failed to ioremap() region\n"); 164 ret = -EINVAL; 165 goto err_req; 166  } 167 printk(KERN_DEBUG"probe: mapped buttons_base=%p\n", buttons_base); 168 169 /*get irq number*/ 170 for(i=0; i<6; i++){ 171 buttons_irq = platform_get_resource(pdev,IORESOURCE_IRQ,i); 172 if(buttons_irq == NULL){ 173 dev_err(dev,"no irq resource specified\n"); 174 ret = -ENOENT; 175 goto err_map; 176  } 177 button_irqs[i] = buttons_irq->start; 178 //printk("button_irqs[%d]=%d\n",i,button_irqs[i]);  179  } 180 ret = misc_register(&mini2440_miscdev); //混杂设备注册 181 182 return 0; 183 184  err_map: 185  iounmap(buttons_base); 186 187  err_req: 188  release_resource(buttons_mem); 189  kfree(buttons_mem); 190 191 return ret; 192 } 193 194 static int mini2440_buttons_remove(struct platform_device *dev) 195 { 196  release_resource(buttons_mem); 197  kfree(buttons_mem); 198 buttons_mem = NULL; 199 200  iounmap(buttons_base); 201 misc_deregister(&mini2440_miscdev); 202 return 0; 203 } 204 205 /*平台驱动定义*/ 206 static struct platform_driver mini2440buttons_driver = { 207 .probe        = mini2440_buttons_probe, 208 .remove        = mini2440_buttons_remove, 209 .driver        = { 210 .owner    = THIS_MODULE, 211 .name    = "mini2440-buttons", 212  }, 213 }; 214 215 static char banner[] __initdata = 216 "Mini2440 Buttons Driver\n"; 217 /* 218 宏 __init作用与 __initdata作用: 219 此宏定义可知标记后的函数或数据其实是放到了特定的(代码或数据)段中。 220 标记为初始化的函数,表明该函数供在初始化期间使用。在模块装载之后, 221 模块装载就会将初始化函数扔掉。这样可以将该函数占用的内存释放出来。 222 */ 223 static int __init buttons_init(void) 224 { 225  printk(banner); 226 /*平台驱动注册*/ 227 platform_driver_register(&mini2440buttons_driver); 228 return 0; 229 } 230 231 static void __exit buttons_exit(void) 232 { 233 platform_driver_unregister(&mini2440buttons_driver); 234 } 235 236 module_init(buttons_init); 237 module_exit(buttons_exit); 238 239 MODULE_AUTHOR("David Xie"); 240 MODULE_DESCRIPTION("Mini2440 Buttons Driver"); 241 MODULE_LICENSE("GPL");
复制代码
阅读(1020) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~