본문 바로가기
코스웨어/15년 스마트컨트롤러

20151104 2번 강동조[커널 빌드와 디바이스 드라이버]

by 알 수 없는 사용자 2015. 11. 5.
728x90
반응형

make 를 하게 되면 컴파일로부터 생성된 파일을 확인할수 있습니다



simple_app컴파일을 위해서 만들어 놓은 Make file을 다시 실행한다




실행 파일이 생성 된것을 확인 할 수 있다




/Proc/devices 파일을 통해서도 simple_drv정보를 확인 할 수 있습니다




실행을 시켜 결과값을 알아 본다



소스

simple_drv.c

 #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, 13000);

         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, 1int)
 #define SIMPLE_WRITE        _IOW(SIMPLE_IOCTL_MAGIC, 2int)
 #define SIMPLE_RDWR         _IOWR(SIMPLE_IOCTL_MAGIC, 3int)

 #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) 




도움을 주신 반장 형님 감사합니다



728x90