首页 > 代码库 > uio设备:发送中断&共享内存

uio设备:发送中断&共享内存

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

derek@ubox:~/share/ldd5$ gcc app.c 
derek@ubox:~/share/ldd5$ sudo ./a.out 
current event count 10, data 333
current event count 11, data 333
current event count 12, data 333

 

uio设备:发送中断&共享内存