1、内核态
struct uio_info irq_info =
{
.name = "fpga_irq2",
.version = "0.1",
.irq = 155,
.irq_flags = IRQ_TYPE_LEVEL_HIGH | IRQF_SHARED | IRQF_DISABLED,
.handler = irq2_handler, //disable_irq_nosync(irq);uio_event_notify(info);
.irqcontrol = irq_irqcontrol,//case: enable_irq(info->irq);disable_irq_nosync
};
uio_register_device(pdev, &irq_info); //pdev指向一个字符设备
2、用户态
fd = open(xx)
while(1) { read , handle, write}
内核态:
#include <linux/init.h> #include <linux/version.h> #include <linux/module.h> #include <linux/mm.h> #include <linux/cdev.h> #include <linux/sched.h> #include <linux/uaccess.h> #include <linux/proc_fs.h> #include <linux/fs.h> #include <linux/seq_file.h> #include <linux/platform_device.h> #include <linux/uio_driver.h> #include <asm/io.h> #include <linux/slab.h> /* kmalloc, kfree */ #include <linux/irq.h> /* IRQ_TYPE_EDGE_BOTH */ #include <asm/uaccess.h> #if 1 static irqreturn_t my_interrupt(int irq, void *dev_id) { struct uio_info *info = (struct uio_info *)dev_id; disable_irq_nosync(info->irq); uio_event_notify(info); return IRQ_RETVAL(IRQ_HANDLED); } static int irq_control(struct uio_info *info, s32 irq_on) { if(irq_on) enable_irq(info->irq); else disable_irq_nosync(info->irq); return 0; } struct uio_info irq_info = { .name = "uio_irq", .version = "0.1", .irq = 10, .handler = my_interrupt, .irq_flags = IRQ_TYPE_EDGE_RISING, .irqcontrol = irq_control, }; #endif #if 1 #define IO_CMD_LEN 256 #define CHAR_DEV_NAME "kdev" static int user_cmd_proc(char *user_cmd, char *out_str) { if(strncmp(user_cmd, "sendsig", 7) == 0) { uio_event_notify(&irq_info); sprintf(out_str, "send ok\n"); } return 0; } int mem_open(struct inode *inode, struct file *filp) { return 0; } int mem_release(struct inode *inode, struct file *filp) { return 0; } char user_cmd[IO_CMD_LEN] = {0}; char out_str[IO_CMD_LEN] = {0}; static int mem_ioctl( struct file *file, unsigned int cmd, unsigned long arg) { printk("mem_ioctl: %d \n", cmd); if(copy_from_user(user_cmd, (int *)arg, IO_CMD_LEN)) return -EFAULT; user_cmd_proc(user_cmd, out_str); if(copy_to_user( (int *)arg, out_str, IO_CMD_LEN)) return -EFAULT; return 0; } static int mem_major = 0; struct class *pclass = NULL; struct cdev my_dev; struct device *pdev; static const struct file_operations mem_fops = { .owner = THIS_MODULE, .unlocked_ioctl = mem_ioctl, .open = mem_open, .release = mem_release, }; static int memdev_init(void) { int result; dev_t devno = MKDEV(mem_major, 0); if (mem_major) { /* 静态申请设备号*/ result = register_chrdev_region(devno, 2, CHAR_DEV_NAME); } else { /* 动态分配设备号 */ result = alloc_chrdev_region(&devno, 0, 2, CHAR_DEV_NAME); mem_major = MAJOR(devno); } if (result < 0) { printk("alloc_chrdev failed!\n"); return result; } cdev_init(&my_dev, &mem_fops); my_dev.owner = THIS_MODULE; my_dev.ops = &mem_fops; cdev_add(&my_dev, MKDEV(mem_major, 0), 2); /*设备数2*/ pclass = class_create(THIS_MODULE, CHAR_DEV_NAME); if (IS_ERR(pclass)) { printk("class_create failed!\n"); goto failed; } pdev = device_create(pclass, NULL, devno, NULL, CHAR_DEV_NAME); uio_register_device(pdev, &irq_info); //todo return 0; failed: cdev_del(&my_dev); unregister_chrdev_region(devno, 1); return result; } static void memdev_exit(void) { uio_unregister_device(&irq_info); //todo device_destroy(pclass, MKDEV(mem_major, 0)); class_destroy(pclass); cdev_del(&my_dev); unregister_chrdev_region(MKDEV(mem_major, 0), 2); } #endif MODULE_AUTHOR("derek yi"); MODULE_LICENSE("GPL"); module_init(memdev_init); module_exit(memdev_exit);
用户态:
#include <stdio.h> #include <fcntl.h> #include <stdlib.h> #include <pthread.h> #include <string.h> #include <sys/syscall.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> #include <sys/ioctl.h> #include <fcntl.h> #include <errno.h> #include <signal.h> #include <sys/syscall.h> #include <sys/mman.h> int thread_1(void) { int uio_fd; int c, ret; uio_fd = open("/dev/uio0", O_RDWR); ///sys/class/uio/uio0/name: uio_irq if(uio_fd < 0) { fprintf(stderr, "open: %s\n", strerror(errno)); exit(-1); } while (1) { ret = read(uio_fd, &c, sizeof(int)); if (ret > 0) { printf("current event count %d\n", c); c = 1; write(uio_fd, &c, sizeof(int)); } } close(uio_fd); return 0; } #define IO_CMD_LEN 256 char kdev_io_buf[IO_CMD_LEN] = {0}; int main() { pthread_t my_thread; int char_fd, ret, i; char_fd = open("/dev/kdev", O_RDWR); if(char_fd < 0) { fprintf(stderr, "open: %s\n", strerror(errno)); exit(-1); } ret = pthread_create(&my_thread, NULL, (void *)thread_1, NULL); if(ret != 0) { printf("Create pthread error!\n"); return -1; } sleep(1); for(i = 0; i < 10; i++){ sprintf(kdev_io_buf, "sendsig"); ret = ioctl(char_fd, 0, kdev_io_buf); printf("ioctl: ret=%d rdata:%s\n", ret, kdev_io_buf); sleep(1); } close(char_fd); return 0; }
测试:
derek@ubox:~/share/ldd5$ sudo insmod myuio.ko derek@ubox:~/share/ldd5$ gcc app.c -lpthread derek@ubox:~/share/ldd5$ sudo ./a.out ioctl: ret=0 rdata:send ok current event count 1 ioctl: ret=0 rdata:send ok current event count 2 ioctl: ret=0 rdata:send ok current event count 3 ioctl: ret=0 rdata:send ok current event count 4 ioctl: ret=0 rdata:send ok current event count 5 ioctl: ret=0 rdata:send ok current event count 6 ioctl: ret=0 rdata:send ok current event count 7 ioctl: ret=0 rdata:send ok current event count 8 ioctl: ret=0 rdata:send ok current event count 9 ioctl: ret=0 rdata:send ok current event count 10