DSP

内核和用户空间异步通信

2019-07-13 17:36发布

异步通信主要又两种方式:信号和netlink。下面例子主要是讲述驱动通过中断方式异步通知用户程序: 1、驱动 /* * * dsp p6a interrupt * author: helb * date: 2018-08-08 * */ #include #include #include #include #include #include #include #include #include #define DRIVER_NAME "p6a" #define P6A_IOC_MAGIC 'A' #define P6A_IOCDTBSIZE _IO(P6A_IOC_MAGIC, 0) #define P6A_IOCGETDTB _IO(P6A_IOC_MAGIC, 1) #define DSP_P6A_PHYS_ADDR 0xfb007400 #define IOREMAP_SIZE 1024 struct irq_dev { char *name; unsigned int irq; void *reg_base; }; static struct fasync_struct *p6a_async; struct irq_dev p6airq= {"p6airq", 9}; static int p6a_open(struct inode *inode, struct file *file) { printk("Do nothing "); return 0; } static int p6a_release(struct inode *inode, struct file *file) { printk("Do nothing "); return 0; } static ssize_t p6a_write(struct file *file, const char __user *data, size_t len, loff_t *ppos) { printk("Do nothing "); return 0; } static long p6a_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { printk("Do nothing "); return 0; } static int p6a_fasync(int fd, struct file *filp, int on) { printk("p6a fasync "); return fasync_helper(fd, filp, on, &p6a_async); } static irqreturn_t p6a_interrupt(int irq, void *dev) { u32 reg; reg = readl(p6airq.reg_base + 0x50); reg &= ~(1<<0); writel(reg, p6airq.reg_base + 0x50); kill_fasync(&p6a_async, SIGIO, POLL_IN); return IRQ_HANDLED; } /* * Kernel Interfaces */ static struct file_operations p6a_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .write = p6a_write, .unlocked_ioctl = p6a_unlocked_ioctl, .open = p6a_open, .release = p6a_release, .fasync = p6a_fasync, }; static struct miscdevice p6a_miscdev = { .minor = MISC_DYNAMIC_MINOR, .name = DRIVER_NAME, .fops = &p6a_fops, }; static int __init p6a_init(void) { int ret = 0; ret = misc_register(&p6a_miscdev); if(ret) { printk (KERN_ERR "cannot register miscdev (err=%d) ", ret); return ret; } p6airq.reg_base = ioremap(DSP_P6A_PHYS_ADDR, IOREMAP_SIZE); if(p6airq.reg_base == NULL){ printk("p6a ioremap:%#x failed ", DSP_P6A_PHYS_ADDR); goto error; } ret = request_irq(p6airq.irq, p6a_interrupt, IRQF_SHARED, p6airq.name, (void *)&p6airq); if(ret < 0){ printk("p6a request_irq failed "); goto error; } return 0; error: misc_deregister(&p6a_miscdev); return -1; } static void __exit p6a_exit(void) { iounmap(p6airq.reg_base); free_irq(p6airq.irq, (void *)&p6airq); misc_deregister(&p6a_miscdev); } module_init(p6a_init); module_exit(p6a_exit); MODULE_AUTHOR("Byavs"); MODULE_DESCRIPTION("Byavs p6a irq event Device Driver"); MODULE_LICENSE("GPL"); 2、用户测试用例 #include #include #include #include #define DEV_NAME "/dev/p6a" void sig_handler(int sig) { if(sig == SIGIO){ printf("Receive io signal from kernel! "); } } int main(void) { int fd; signal(SIGIO, sig_handler); fd = open(DEV_NAME, O_RDWR); if(fd < 0){ printf("open %s failed ", DEV_NAME); return -1; } fcntl(fd, F_SETOWN, getpid()); fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | FASYNC); printf("waiting p6a interrupt "); while(1){ sleep(1); } return 0; }