1,内核代码
#include <linux/init.h> #include <linux/version.h> #include <linux/module.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> #define STRING_LEN 256 char global_buffer[STRING_LEN] = {0}; #if 1 static irqreturn_t my_interrupt(int irq, void *dev_id) { struct uio_info *info = (struct uio_info *)dev_id; unsigned long *ret_val_add = (unsigned long *)(info->mem[0].addr); *ret_val_add = 222; printk("my_interrupt: %d \n" ,(int)(*ret_val_add)); return IRQ_RETVAL(IRQ_HANDLED); } struct uio_info kpart_info = { .name = "kpart", .version = "0.1", .irq = 10, //unused .handler = my_interrupt, //unused .irq_flags = IRQ_TYPE_EDGE_RISING, //unused }; static int drv_kpart_probe(struct device *dev); static int drv_kpart_remove(struct device *dev); static struct device_driver uio_dummy_driver = { .name = "kpart", .bus = &platform_bus_type, .probe = drv_kpart_probe, .remove = drv_kpart_remove, }; #ifdef HW_ENABLE struct button_irq_desc { int irq; int num; char *name; }; static struct button_irq_desc button_irqs [] = { {8 , 1, "KEY0"}, {11, 2, "KEY1"}, {13, 3, "KEY2"}, {14, 4, "KEY3"}, {15, 5, "KEY4"}, }; static irqreturn_t buttons_interrupt(int irq, void *dev_id) { struct button_irq_desc *button_irqs = (struct button_irq_desc *)dev_id; unsigned long *ret_val_add = (unsigned long *)(kpart_info.mem[1].addr); *ret_val_add = button_irqs->num; printk("%s is being pressed ..... \n", button_irqs->name); uio_event_notify(&kpart_info); return IRQ_RETVAL(IRQ_HANDLED); } #endif static int drv_kpart_probe(struct device *dev) { unsigned long *ret_val_addr; kpart_info.mem[0].addr = (unsigned long)kmalloc(1024, GFP_KERNEL); if(kpart_info.mem[0].addr == 0) return -ENOMEM; kpart_info.mem[0].memtype = UIO_MEM_LOGICAL; kpart_info.mem[0].size = 1024; ret_val_addr = (unsigned long *)(kpart_info.mem[0].addr); *ret_val_addr = 222; if(uio_register_device(dev, &kpart_info)){ kfree((void *)kpart_info.mem[0].addr); return -ENODEV; } #ifdef HW_ENABLE int i = 0 ,err = 0; for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) { err = request_irq(button_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_RISING, button_irqs[i].name, (void *)&button_irqs[i]); if (err) break; } #endif return 0; } static int drv_kpart_remove(struct device *dev) { kfree((void *)kpart_info.mem[0].addr); uio_unregister_device(&kpart_info); return 0; } #endif #if 1 static int user_cmd_proc(char *user_cmd) { if(strncmp(user_cmd, "sendsig", 7) == 0) { unsigned long *ret_val_add = (unsigned long *)(kpart_info.mem[0].addr); *ret_val_add = 333; uio_event_notify(&kpart_info); } return 0; } static int my_proc_show(struct seq_file *seq, void *v) { seq_printf(seq, "current kernel time is %ld\n", jiffies); seq_printf(seq, "last cmd: %s", global_buffer); return 0; } static int my_proc_open(struct inode *inode, struct file *file) { return single_open(file, my_proc_show, inode->i_private); } static ssize_t my_proc_write(struct file *file, const char __user *buffer, size_t count, loff_t *pos) { if (count > 0) { printk("my_proc_write called\n"); copy_from_user(global_buffer, buffer, count); user_cmd_proc(global_buffer); } return count; } struct file_operations proc_fops = { .open = my_proc_open, .read = seq_read, .write = my_proc_write, .llseek = seq_lseek, .release = single_release, }; static struct proc_dir_entry *proc_dir = NULL; static struct proc_dir_entry *proc_file = NULL; static struct platform_device * uio_dummy_device; static int __init proc_test_init(void) { proc_dir = proc_mkdir("my_proc", NULL); if (!proc_dir) { printk(KERN_DEBUG"proc_mkdir failed"); return 0; } proc_file = proc_create("buffer", 0666, proc_dir, &proc_fops); if (!proc_file) { printk(KERN_DEBUG"proc_create failed"); return 0; } uio_dummy_device = platform_device_register_simple("kpart", -1, NULL, 0); driver_register(&uio_dummy_driver); return 0; } static void __exit proc_test_exit(void) { remove_proc_entry("buffer", proc_dir); remove_proc_entry("my_proc", NULL); platform_device_unregister(uio_dummy_device); driver_unregister(&uio_dummy_driver); } #endif module_init(proc_test_init); module_exit(proc_test_exit); MODULE_AUTHOR("derek.yi"); MODULE_LICENSE("GPL");
2,用户代码
#include <stdio.h> #include <fcntl.h> #include <stdlib.h> #include <string.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> #define UIO_DEV "/dev/uio0" ///sys/class/uio/uio0/name: kpart #define UIO_ADDR0 "/sys/class/uio/uio0/maps/map0/addr" #define UIO_SIZE0 "/sys/class/uio/uio0/maps/map0/size" #define UIO_ADDR1 "/sys/class/uio/uio0/maps/map1/addr" #define UIO_SIZE1 "/sys/class/uio/uio0/maps/map1/size" static char uio_addr_buf[16], uio_size_buf[16]; int main() { int uio_fd, addr_fd, size_fd; int uio_size; void *uio_addr, *access_address; fd_set rd_fds, tmp_fds; int c, ret; uio_fd = open(UIO_DEV, O_RDWR); addr_fd = open(UIO_ADDR0, O_RDONLY); size_fd = open(UIO_SIZE0, O_RDONLY); if(addr_fd < 0 || size_fd < 0 || uio_fd < 0 ) { fprintf(stderr, "mmap: %s\n", strerror(errno)); exit(-1); } #if 0 read(addr_fd, uio_addr_buf, sizeof(uio_addr_buf)); read(size_fd, uio_size_buf, sizeof(uio_size_buf)); uio_addr = (void*)strtoul(uio_addr_buf, NULL, 0); uio_size = (int)strtol(uio_size_buf, NULL, 0); #endif access_address = mmap(NULL, 1024, PROT_READ | PROT_WRITE, MAP_SHARED, uio_fd, 0); if (access_address == (void*) -1 ) { fprintf(stderr, "mmap: %s\n", strerror(errno)); exit(-1); } while (1) { FD_ZERO(&rd_fds); FD_SET(uio_fd, &rd_fds); tmp_fds = rd_fds; ret = select(uio_fd+1, &tmp_fds, NULL, NULL, NULL); if (ret > 0) { if (FD_ISSET(uio_fd, &tmp_fds)) { read(uio_fd, &c, sizeof(int)); printf("current event count %d, data %d\n", c, *(int *)access_address); } } } close(uio_fd); return 0; }
3,测试脚本
sudo modprobe uio sudo insmod myuio.ko echo "sendsig" > /proc/my_proc/buffer cat /proc/my_proc/buffer [email protected]:~/share/ldd5$ gcc app.c [email protected]:~/share/ldd5$ sudo ./a.out current event count 10, data 333 current event count 11, data 333 current event count 12, data 333
时间: 2024-10-03 12:47:26