#include <sys/types.h> #include <sys/stat.h> #include <sys/mman.h> #include <sys/poll.h> #include <sys/ioctl.h> #include <unistd.h> #include <fcntl.h> #include <stdio.h>
#include "simple_ioctl.h"
#define SIMPLE_MAJOR 500 #define SIMPLE_MINOR 100
#define SIMPLE_DEV_NAME "/dev/simple"
#define SIMPLE_DEV_ADDR 0x80000000 #define SIMPLE_DEV_SIZE 0x8000
int main() { int fd, ret, rVal = 0, wVal = 200; char rBuf[80] = ""; char wBuf[] = "98765432109876543210"; char *addr; struct pollfd pfd[1]; dev_t simple_dev; char tmp[40] = "";
simple_dev = makedev(SIMPLE_MAJOR, SIMPLE_MINOR); ret = mknod(SIMPLE_DEV_NAME, S_IFCHR|0666, simple_dev);
fd = open(SIMPLE_DEV_NAME, O_RDWR); printf("open: %d\n", fd);
ret = read(fd, rBuf, 15); rBuf[ret] = '\0'; printf("read: %s, reg: %d\n", rBuf, ret);
ret = write(fd, wBuf, 15); printf("write ret: %d\n", ret);
ret = ioctl(fd, SIMPLE_INIT); printf("ioctl[SIMPLE_INIT] ret: %d\n", ret);
ret = ioctl(fd, SIMPLE_READ, &rVal); printf("ioctl[SIMPLE_READ] data: %d, ret: %d\n", rVal, ret);
ret = ioctl(fd, SIMPLE_WRITE, &wVal); printf("ioctl[SIMPLE_WRITE] ret: %d\n", ret);
printf("ioctl[SIMPLE_RDWR] before-> wVal: %d\n", wVal); ret = ioctl(fd, SIMPLE_RDWR, &wVal); printf("ioctl[SIMPLE_RDWR] after -> wVal : %d, ret: %d\n", wVal, ret); printf("--------------before mmap\n"); sprintf(tmp, "pmap -x %d", getpid() ); system(tmp); addr = (char *)mmap(0, SIMPLE_DEV_SIZE, PROT_READ|PROT_WRITE, MAP_SHARED, fd, SIMPLE_DEV_ADDR); printf("mmap addr: %p\n", addr);
printf("--------------after mmap\n"); system(tmp);
munmap(addr, SIMPLE_DEV_SIZE); printf("--------------after munmap\n"); system(tmp);
pfd[0].fd = fd; pfd[0].events = POLLIN|POLLOUT|POLLERR;
while(1) { ret = poll((struct pollfd *)&pfd, 1, 3000);
if(pfd[0].revents & POLLIN) { ret = read(fd, rBuf, 10); } else if(pfd[0].revents & POLLOUT) { ret = write(fd, wBuf, 10); } else if(pfd[0].revents & POLLERR) { printf("poll error!!\n"); }
if(ret == 0) { printf("poll timeout occured\n"); break; }
}
close(fd); return 0; }
[simple_app.c] #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/fs.h> #include <linux/interrupt.h> #include <linux/delay.h> #include <linux/mman.h> #include <linux/sched.h>
#include <asm/page.h> #include <asm/io.h> #include <asm/uaccess.h> #include <linux/poll.h>
#ifdef ARCH_ARM #include <mach/irgs.h> #include <mach/reg_gpio.h> #endif
#include "simple_ioctl.h"
#define DEV_MAJOR 245 #define DEV_NAME "Simple Driver"
#define DEV_ADDR 0x80000000 #define DEV_SIZE 0x8000 #define IRQF_DISABLED 0x20
int simple_major;
int simple_open(struct inode *inode, struct file *filp) { int major, minor; major = MAJOR(inode->i_rdev); major = MINOR(inode->i_rdev); printk("Simple Driver : open\n"); printk("--> major : %d, minor : %d\n", major, minor); return 0; }
int simple_release(struct inode *inode, struct file *filp) { printk("Simple Driver : release\n"); return 0; }
ssize_t simple_read(struct file *filp, char *buf, size_t size, loff_t *pos) { char data[] = "12345678901234567890";
printk("Simple Driver : read\n");
copy_to_user(buf, data, size);
return 0x11; }
ssize_t simple_write(struct file *filp, const char *buf, size_t size, loff_t *pos) { char data[40];
copy_from_user(data, buf, size);
printk("Simple Driver : write\n");
data[size] = '\0'; printk("--> from user : %s\n", data);
udelay(100);
return 0x22; }
long simple_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { int size; int rval = 0; int wval = 100; int ret;
printk("Simple Driver: ioctl\n");
if(_IOC_TYPE(cmd) != SIMPLE_IOCTL_MAGIC) return -EINVAL; if(_IOC_NR(cmd) >= SIMPLE_IOCTL_MAX) return -EINVAL;
size = _IOC_SIZE(cmd);
if(size) { if(_IOC_DIR(cmd) & _IOC_READ) if(access_ok(VERIFY_WRITE, (void *)arg, size) < 0) return -EINVAL; if(_IOC_DIR(cmd) & _IOC_WRITE) if(access_ok(VERIFY_READ, (void *)arg, size) < 0) return -EINVAL; }
switch(cmd) { case SIMPLE_INIT: printk("-->SIMPLE_INIT\n"); ret = 0x31; break; case SIMPLE_READ: printk("-->SIMPLE_READ\n"); copy_to_user( (void *)arg, &wval, sizeof(int) ); ret = 0x32; break; case SIMPLE_WRITE: printk("-->SIMPLE_WRITE\n"); copy_from_user( &rval, (void *)arg, sizeof(int) ); printk("----> from user : %d\n", rval); ret = 0x33; break; case SIMPLE_RDWR: printk("-->SIMPLE_RDWR\n"); ret = 0x34; break; }
return ret; }
int simple_mmap(struct file *filp, struct vm_area_struct *vma) { printk("Simple Driver : mmap\n");
remap_pfn_range(vma, vma->vm_start, DEV_ADDR >> PAGE_SHIFT, DEV_SIZE, vma->vm_page_prot);
printk("--> start : 0x%x, end: 0x%x\n", (unsigned int)vma->vm_start, (unsigned int)vma->vm_end); return 0; }
int readCnt = 0; int writeCnt = 0; DECLARE_WAIT_QUEUE_HEAD(readQueue); DECLARE_WAIT_QUEUE_HEAD(writeQueue);
int simple_poll(struct file *filp, struct poll_table_struct *pt) { unsigned int state = 0;
printk("Simple Driver : poll\n");
poll_wait(filp, &readQueue, pt); poll_wait(filp, &writeQueue, pt);
if(readCnt > 0) { state |= POLLIN | POLLRDNORM; } if(writeCnt > 0) { state |= POLLIN | POLLWRNORM; }
return state;
}
irqreturn_t simple_handler(int irq, void *dev_id) { printk("Simple Interrupt handler\n"); printk("--> irq number : %d\n", irq); return IRQ_HANDLED; }
struct file_operations simple_fops = { .open = simple_open, .release = simple_release, .read = simple_read, .write = simple_write, .unlocked_ioctl = simple_ioctl, .mmap = simple_mmap, .poll = simple_poll, };
int simple_drv_init(void) { simple_major = register_chrdev(DEV_MAJOR, DEV_NAME, &simple_fops);
printk("Simple Driver : registered\n"); printk("--> major : %d\n", simple_major);
if(request_irq(10, simple_handler, IRQF_DISABLED, "Simple Interrupt", NULL) < 0) printk("--> request irq failed\n");
return simple_major; }
void simple_drv_exit(void) { unregister_chrdev(simple_major, DEV_NAME); printk("Simple Driver : unregistered\n"); return; }
module_init(simple_drv_init); module_exit(simple_drv_exit); MODULE_LICENSE("Dual BSD/GPL");
[simple_ioctl.h]
#define SIMPLE_IOCTL_MAGIC 's'
#define SIMPLE_INIT _IO(SIMPLE_IOCTL_MAGIC, 0) #define SIMPLE_READ _IOR(SIMPLE_IOCTL_MAGIC, 1, int) #define SIMPLE_WRITE _IOW(SIMPLE_IOCTL_MAGIC, 2, int) #define SIMPLE_RDWR _IOWR(SIMPLE_IOCTL_MAGIC, 3, int)
#define SIMPLE_IOCTL_MAX 4
[Makefile] obj-m := simple_drv.o
ifeq ($(ARCH), xxx) KDIR :=/usr/src/linux CROSS_COMPILE :=arm-none-linux-gnueabi- CCFLAGS := -static else KDIR :=/lib/modules/$(shell uname -r)/build endif
TARGET := simple_app PWD := $(shell pwd) CC := ${CROSS_COMPILE}gcc LD := ${CROSS_COMPILE}ld AR := ${CROSS_COMPILE}ar
all: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules $(TARGET): simple_app.c $(CC) $(CCFLAGS) -o $@ $^
clean: $(MAKE) -C $(KDIR) SUBDIRS=$(PWD) clean rm -f $(TARGET)
|