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