배우고픈 공돌이

6. 다중화 입출력 본문

디바이스 드라이버

6. 다중화 입출력

내 마음 아홉수 2017. 11. 16. 15:42

다양한 조건에서 프로세서가 깨어나도록 설정하는 것이 다중화 입출력이다.


여기서 조건이란 인터럽트뿐만 아니라 read, write, ioctl 등의 event을 말한다.


이 조건에 따라 프로세스가 살면 선택하는 event를 찾아 실행을하는데, 


선택하기 위한 키를 poll이라한다.





블럭킹과의 차이


블럭킹은 단일 조건(인터럽트)으로 프로세스를 중간에 재우거나 깨운다.


다중화의 경우는 큰틀에서 디바이스 드라이버의 프로세스를 재우고 


이벤트가 발생하면 프로세스가 일어난다.


유형 1. 한 디라이버에서 다중 Event 조건 때, poll 사용


유형 2. 여러 드라이버에서 Event 조건 때, poll 사용



소스


D/D


#include <linux/module.h>

#include <linux/init.h>

#include <linux/kernel.h>

#include <linux/fs.h>

#include <linux/slab.h>

#include <linux/sched.h>

#include <asm/uaccess.h>

#include <linux/fdtable.h>

#include <linux/timer.h>

#include <linux/time.h>

#include <linux/interrupt.h>

#include "skeleton.h"

#include <linux/wait.h>

#include <linux/workqueue.h>

#include <linux/poll.h>



#define SK_IRQ 7

#define SK_MAJOR 240


static KERNEL_TIMER_MANAGER *ptrmng = NULL;

static DECLARE_WAIT_QUEUE_HEAD(wait_read); //wait queue for read

static DECLARE_WAIT_QUEUE_HEAD(wait_write); //wait queue for write

static DECLARE_WORK(work_queue, call_workqueue);


int result;

int condition=0; 


void call_workqueue(struct work_struct *work)

{

printk("[WORK_QUEUE] function call\n");

}


static irqreturn_t read_interrupt(int irq, void *dev_id)

{

printk("read interrupt handler\n");

wake_up_interruptible(&wait_read);

schedule_work(&work_queue);


return IRQ_HANDLED;

}


static irqreturn_t write_interrupt(int irq, void *dev_id)

{

printk("write interrupt handler\n");

wake_up_interruptible(&wait_write);

schedule_work(&work_queue);


return IRQ_HANDLED;

}


void kerneltimer_register(KERNEL_TIMER_MANAGER *ptr,unsigned long time_over)

{

init_timer(&(ptr->timer));

ptr->timer.expires = get_jiffies_64() + time_over;

ptr->timer.data    = (unsigned long)ptr;

ptr->timer.function= kerneltimer_timeover;

add_timer(&(ptr->timer));

}


void kerneltimer_timeover(unsigned long time_over)

{

KERNEL_TIMER_MANAGER *ptr = NULL;

if(time_over)

{

ptr = (KERNEL_TIMER_MANAGER *)time_over;

ptr->work++;

if(ptr->work % 10 == 0)

{

condition++;

read_interrupt(SK_IRQ,NULL);

write_interrupt(SK_IRQ,NULL);

//printk("work value is %ld\n",ptr->work);

}

}

kerneltimer_register(ptr,TIME_STEP);

}


/*

    minor1

*/

static int minor1_open(struct inode *inode, struct file *filp)

{

printk("minor1 open success!\n");

schedule_work(&work_queue);

return 0;

}


static int minor1_release(struct inode *inode, struct file *filp)

{

printk("minor1 release success!\n");

return 0;

}


static ssize_t minor1_read(struct file *filp, char * buf,size_t count,loff_t * f_pos)

{

int pid = 0;

unsigned long start_code[2] = {0};

  /*

printk("before sleep\n");

schedule_work(&work_queue);

if(!condition)

wait_event_interruptible(wait_read,condition); //don`t wake up and  be in wait queue

condition = 0;

*/


schedule_work(&work_queue);


if(count == 4)

{

pid = current->pid;

copy_to_user(buf, &pid, count);

}

else

{

start_code[0] = current->mm->start_code;

start_code[1] = current->mm->end_code;

copy_to_user(buf, start_code, count);

}


return count;

}


// minor1`s poll

static unsigned int minor1_poll(struct file *filp, poll_table *wait)

{

unsigned int mask = 0;

poll_wait(filp, &wait_read, wait);

if(condition > 0)

mask |= POLLIN|POLLRDNORM;

return mask;

}




/*

    minor2

*/

static int minor2_open(struct inode *inode, struct file *filp)

{

printk("minor2 open success!\n");

return 0;

}


static int minor2_release(struct inode *inode, struct file *filp)

{

printk("minor2 release success!\n");

return 0;

}


static ssize_t minor2_write(struct file *filp, const char * buf, size_t count, loff_t * f_pos)

{

char data[30] = {0};

copy_from_user(data, buf, count);

printk("write >>> %s\n", data);


return count;

}


// minor2`s poll

static unsigned int minor2_poll(struct file *filp, poll_table *wait)

{

unsigned int mask = 0;

poll_wait(filp, &wait_write, wait);

if(condition > 0)

mask |= POLLOUT|POLLWRNORM; // poll write normal

return mask;

}


/*

    minor3

*/


static int minor3_open(struct inode *inode, struct file *filp)

{

printk("minor3 open success!\n");

return 0;

}


static int minor3_release(struct inode *inode, struct file *filp)

{

printk("minor3 release success!\n");

return 0;

}


static long minor3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)

{

int pid, next_fd, f_flags;

unsigned long start_address[2] = {0};

unsigned long i_ino;


switch(cmd)

{

case 'a':

pid = current->pid;

copy_to_user((int *)arg, &pid,4);

break;

case 'b':

start_address[0] = current->mm->start_code;

start_address[1] = current->mm->end_code;

copy_to_user((long *)arg, start_address, 16);

break;

case 'c':

next_fd = current->files->next_fd;

copy_to_user((long *)arg,&next_fd,sizeof(next_fd)); 

printk("netx fd is %d\n", next_fd);

break;

case 'd':

f_flags = filp->f_flags;

copy_to_user((int *)arg,&f_flags,sizeof(f_flags));

printk("f_flags is %d\n", f_flags);

break;

case 'e':

i_ino = filp->f_path.dentry->d_inode->i_ino;

copy_to_user((unsigned long *)arg, &i_ino,sizeof(i_ino));

printk("i_ino is %ld\n", i_ino);

break;

}

return 0;

}



struct file_operations minor1_fops =

{

.owner = THIS_MODULE,

.open = minor1_open,

.release = minor1_release,

.read = minor1_read,

.poll = minor1_poll,

};


struct file_operations minor2_fops =

{

.owner = THIS_MODULE,

.open = minor2_open,

.release = minor2_release,

.write = minor2_write,

.poll = minor2_poll,

};


struct file_operations minor3_fops =

{

.owner = THIS_MODULE,

.open = minor3_open,

.release = minor3_release,

.unlocked_ioctl = minor3_ioctl,

};



static int master_open(struct inode *inode, struct file *filp)

{

printk("master open success\n");


switch(MINOR(inode->i_rdev))

{

case 1:

filp->f_op = &minor1_fops;

break;

case 2:

filp->f_op = &minor2_fops;

break;

case 3:

filp->f_op = &minor3_fops;

break;

default:

return -ENXIO;

}

if(filp->f_op && filp->f_op->open)

return filp->f_op->open(inode,filp);

return 0;

}


struct file_operations master_fops =

{

.owner = THIS_MODULE,

.open = master_open,

};


static int __init skeleton_init(void)

{

int ret;

printk("skeleton init success\n");

ret = register_chrdev(SK_MAJOR,"skeleton",&master_fops);

if(ret <0)

return ret;

request_irq(SK_IRQ,read_interrupt,IRQF_SHARED,"skriq_read",NULL); 

request_irq(SK_IRQ,write_interrupt,IRQF_SHARED,"skriq_write",NULL); 

//request_irq(id, function, flag, name, argument)


ptrmng = kmalloc(sizeof(KERNEL_TIMER_MANAGER),GFP_KERNEL);

if(!ptrmng)

return -ENOMEM;

else

memset(ptrmng,0,sizeof(KERNEL_TIMER_MANAGER));


kerneltimer_register(ptrmng,TIME_STEP);

return 0;

}

static void __exit skeleton_exit(void)

{

printk("skeleton exit success\n");

unregister_chrdev(SK_MAJOR,"skeleton");

if(ptrmng)

{

del_timer(&(ptrmng->timer));

kfree(ptrmng);

}

}


module_init(skeleton_init);

module_exit(skeleton_exit);


MODULE_LICENSE("GPL");


app


#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

#include <fcntl.h>

#include <string.h>

#include <sys/ioctl.h>

#include <sys/poll.h>


int main_menu(void);


int main(void)

{

int rfd, wfd, iofd, ret;

int pid, next_fd, f_flags;

unsigned long i_ino;

unsigned long address_code[2] = {0};

char buff1[30] = "write data!!\n";

char buff2[30] = {0};

char key;


struct pollfd Events[1];

int retval;


while((key=main_menu()) != 0)

{

system("clear");

switch(key)

{

case 'a':

ioctl(iofd, key, &pid);

printf("PID is %d\n", pid);

break;

case 'b':

ioctl(iofd, key, address_code);

printf("start address %p\n", (void *)address_code[0]);

printf("end address %p\n", (void *)address_code[1]);

break;

case 'c':

ioctl(iofd, key, &next_fd);

printf("Next File Desc is %d\n", next_fd);

break;

case 'd':

ioctl(iofd, key, &f_flags);

printf("file struct f_lags is %d\n", f_flags);

break;

case 'e':

ioctl(iofd, key,&i_ino);

printf("inode i_ino is %ld\n", i_ino);

break;

case 'o':

printf("read open\n");

rfd=open("/dev/sk1", O_RDWR);

if(rfd < 0)

{

perror("/dev/sk1");

exit(-1);

}

printf("rfd number is %d\n", rfd); 

printf("write open\n");

wfd=open("/dev/sk2", O_RDWR);

if(wfd < 0)

{

perror("/dev/sk2");

exit(-1);

}

printf("wfd number is %d\n", wfd);


printf("ioctl open\n");

iofd=open("/dev/sk3", O_RDWR);

if(iofd < 0)

{

perror("/dev/sk3");

exit(-1);

}

printf("iofd number is %d\n", iofd); 


break;

case 'q':

printf("close to quit\n");

close(rfd);

close(wfd);

close(iofd);

return 0;

case 'w':

while(1)

{

memset(Events,0, sizeof(Events));


Events[0].fd = wfd;

Events[0].events = POLLOUT;


retval = poll((struct pollfd *)&Events, 1, 20000);

if(retval < 0)

{

perror("poll error\n");

exit(EXIT_FAILURE);

}

if(retval == 0)

{

printf("Time over\n");

continue;

}

if(Events[0].revents & POLLERR)

{

printf("Device Error\n");

exit(EXIT_FAILURE);

}

if(Events[0].revents & POLLOUT)

{

printf("write\n");

write(wfd, buff1,30);

break;

}

}


break;

case 'r':

while(1)

{

memset(Events,0, sizeof(Events));


Events[0].fd = rfd;

Events[0].events = POLLIN;


retval = poll((struct pollfd *)&Events, 1, 20000);

if(retval < 0)

{

perror("poll error\n");

exit(EXIT_FAILURE);

}

if(retval == 0)

{

printf("Time over\n");

continue;

}

if(Events[0].revents & POLLERR)

{

printf("Device Error\n");

exit(EXIT_FAILURE);

}

if(Events[0].revents & POLLIN)

{

printf("read\n");

read(rfd, &pid, 4);

printf("read data is >> %d \n", pid);

read(rfd, address_code, sizeof(address_code));

printf("start address is %p\n",(void *)address_code[0]);

printf("end code is %p\n", (void *)address_code[1]);

break;

}

}

break;

}

}

return 0;

}


int main_menu(void)

{

char  key;

printf("-------------------------------------------------\n");

printf(" MAIN MENU\n");

printf("-------------------------------------------------\n");

printf(" a. Read task_struct PID\n");

printf(" b. Read mm_struct start_code\n");

printf(" c. Read files_struct next_fd\n");

printf(" d. Read file f_flags\n");

printf(" e. Read inode i_ino\n");

printf(" o. SKELETON OPEN\n");

printf(" q. SKELETON CLOSE\n");

printf(" w. SKELETON WRITE\n");

printf(" r. SKELETON READ\n");

printf("-------------------------------------------------\n");

printf("SELECT THE COMMAND : ");

scanf("%c", &key);

while(getchar() != '\n');

return key;

}












'디바이스 드라이버' 카테고리의 다른 글

예제.  (0) 2017.11.20
5.워크 큐  (0) 2017.11.16
4. 블럭킹 io  (0) 2017.11.15
3. 인터럽트  (0) 2017.11.15
2. 타이머  (0) 2017.11.15
Comments