배우고픈 공돌이

예제. 본문

디바이스 드라이버

예제.

내 마음 아홉수 2017. 11. 20. 15:01

1. 다중화 입출력을 사용해서 디바이스를 제어한다.

2. 타이머 인터럽트로 5초마다 한 번씩 화면에 나타낸다. read 장치 1

3. 장치에 타이머 시간을 준다.    write 장치 1

4. 지정 시간 후, 커널의 정보를 화면에 띄우며 종료한다. read 장치 2



#ifndef _SKELETON_H_

#define _SKELETON_H_

#define TIME_STEP (10 * HZ / 10)


typedef struct

{

struct timer_list timer;

unsigned long work;

}__attribute((packed))KERNEL_TIMER_MANAGER;


typedef struct 

{

int pid;

int next_fd;

int f_flags;

unsigned long start_code;

unsigned long end_code;

unsigned long i_ino;

}__attribute((packed))PUSH_DATA;



void kerneltimer_timeover(unsigned long);

void kerneltimer_register(KERNEL_TIMER_MANAGER *, unsigned long);

void call_workqueue(struct work_struct *);


#endif


#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 "skeleton.h"

#include <linux/interrupt.h>

#include <linux/wait.h>

#include <linux/workqueue.h>

#include <linux/poll.h>



#define SK_IRQ 7

#define SK_MAJOR 240


static DECLARE_WAIT_QUEUE_HEAD(wait_read1);

static DECLARE_WAIT_QUEUE_HEAD(wait_read2);

static DECLARE_WAIT_QUEUE_HEAD(wait_write);

static KERNEL_TIMER_MANAGER *ptrmng = NULL;


static int sec;

static int time_limit;

static int input_time[3];


int read1_condition = 0;

int read2_condition = 0;

int write_condition = 0;


/* 장치 인터럽트 */

static irqreturn_t read1_interrupt(int irq, void *dev_id)

{

sec+=5;

read1_condition++;

wake_up_interruptible(&wait_read1);

return IRQ_HANDLED;

}


static irqreturn_t read2_interrupt(int irq, void *dev_id)

{

time_limit++;

if(time_limit == input_time[2])

{

read2_condition++;

wake_up_interruptible(&wait_read2);

}

return IRQ_HANDLED;

}


static irqreturn_t write_interrupt(int irq, void *dev_id)

{

write_condition++;

wake_up_interruptible(&wait_write);


return IRQ_HANDLED;

}

// ===========================


/* 타이머 셋팅 */

void kerneltimer_register(KERNEL_TIMER_MANAGER *ptr, unsigned long timeover)

{

init_timer(&(ptr->timer));

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

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

ptr->timer.function = kerneltimer_timeover;

add_timer(&(ptr->timer));

}


void kerneltimer_timeover(unsigned long arg)

{

KERNEL_TIMER_MANAGER *ptr = NULL;

if(arg)

{

ptr = (KERNEL_TIMER_MANAGER *)arg;

ptr->work++;

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

{

read1_interrupt(SK_IRQ, NULL);

write_interrupt(SK_IRQ, NULL);

}

read2_interrupt(SK_IRQ, NULL);

}

kerneltimer_register(ptr, TIME_STEP);

}

// ===========================


/* Minor 1 */


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

{

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

sec=0;

return 0;

}


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

{

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

sec=0;

return 0;

}


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

{

copy_to_user(buf, &sec, count);

read1_condition = 0;


return count;

}


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

{

unsigned int mask = 0;


poll_wait(filp, &wait_read1, wait);


if(read1_condition > 0)

mask |= POLLIN | POLLRDNORM;


return mask;

}

// ===========================


/* Minor 2 */


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)

{

copy_from_user(input_time, buf, count);

printk("current TIME write >>> %d\n", input_time[0]);

printk("expire TIME write >>> %d\n", input_time[1]);

input_time[2] = time_limit+input_time[1]-input_time[0];

sec = 0;

write_condition=0;

return count;

}


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

{

unsigned int mask = 0;


poll_wait(filp, &wait_write, wait);


if(write_condition > 0)

mask |= POLLOUT | POLLWRNORM;


return mask;

}

// ===========================


/* Minor 3 */


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 ssize_t minor3_read(struct file *filp, char * buf,size_t count,loff_t * f_pos)

{

PUSH_DATA stream;

stream.pid = current->pid;

stream.start_code = current->mm->start_code;

stream.end_code = current->mm->end_code;

stream.next_fd = current->files->next_fd;

stream.f_secs = filp->f_secs;

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

copy_to_user((unsigned long *)buf,&stream,sizeof(stream));

read2_condition=0;

return count;

}


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

{

unsigned int mask = 0;


poll_wait(filp, &wait_read2, wait);


if(read2_condition > 0)

mask |= POLLIN | POLLRDNORM;


return mask;

}

// ===========================



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,

.read = minor3_read,

.poll = minor3_poll,

};


/* 부번호 처리 루틴 */


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, read1_interrupt, IRQF_SHARED, "skirq_read", NULL);

request_irq(SK_IRQ, read2_interrupt, IRQF_SHARED, "skirq_read", NULL);

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


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


if(ptrmng == NULL)

return -ENOMEM;


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 != NULL)

{

del_timer(&(ptrmng->timer));

kfree(ptrmng);

}

}


module_init(skeleton_init);

module_exit(skeleton_exit);


MODULE_LICENSE("GPL");

read 1와 write 1 의 인터럽트는 5초마다 발생한다.

read 2의 인터럽트는 매초마다 발생한다.


#include <stdio.h>

#include <unistd.h>

#include <stdlib.h>

#include <fcntl.h>

#include <string.h>

#include <sys/ioctl.h>

#include <sys/poll.h>


typedef struct 

{

int pid;

int next_fd;

int f_times;

unsigned long start_code;

unsigned long end_code;

unsigned long i_ino;

}__attribute((packed))PUSH_DATA;



int main_menu(void);

void open_dev(void);

void read_dev(void);

void write_dev(void);

void close_dev(void);


PUSH_DATA data;


int rfd1, wfd, rfd2, ret;

int pid, next_fd, f_times;

int time, flag,read_exit;

unsigned long i_ino;

unsigned long address_code[2] = {0};

int buff[2];

char key;


struct pollfd Events[2];


int retval,retval2;

int main(void)

{

open_dev();

write_dev();

while(1)

{

read_dev();

if(flag)

break;

}

close_dev();

return 0;

}


/* device open */

void open_dev(void)

{

printf("read open\n");

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

if(rfd1 < 0)

{

perror("/dev/sk1");

exit(-1);

}

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

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");

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

if(rfd2 < 0)

{

perror("/dev/sk3");

exit(-1);

}

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

}


/* read device */

void read_dev(void)

{

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


Events[0].fd = rfd1;

Events[0].events = POLLIN;

Events[1].fd = rfd2;

Events[1].events = POLLIN;

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

  //poll(이벤트 배열 주소,장치 갯수, 응답 대기 시간) 

  //예외처리

  if(retval < 0)

{

perror("poll error\n");

exit(EXIT_FAILURE);

}

if(retval == 0)

{

printf("Time over\n");

}

if(Events[0].revents & POLLERR)

{

printf("Device Error\n");

exit(EXIT_FAILURE);

}

if(Events[0].revents & POLLIN)

{

read(rfd1, &time, 4);

printf("%dsec... \n",time);

printf("press any key for stop\n");

}

if(Events[1].revents & POLLERR)

{

printf("Device Error\n");

exit(EXIT_FAILURE);

}

if(Events[1].revents & POLLIN)

{

read(rfd2, &data, sizeof(data));

printf("pid        : %d\n",data.pid);

printf("next_fd    : %d\n",data.next_fd);

printf("f_times    : %d\n",data.f_times);

printf("Start_code : %ld\n",data.start_code);

printf("end_code   : %ld\n",data.end_code);

printf("i_ino      : %ld\n",data.i_ino);

flag=1;

}

}


/* write device  */

void write_dev(void)

{

printf("input start time>>");

scanf("%d",&buff[0]);

printf("input end time>>");

scanf("%d",&buff[1]);

write(wfd, buff,sizeof(buff));

}


/* device close */

void close_dev(void)

{

printf("close dev\n");

close(rfd1);

close(wfd);

close(rfd2);

}


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

6. 다중화 입출력  (0) 2017.11.16
5.워크 큐  (0) 2017.11.16
4. 블럭킹 io  (0) 2017.11.15
3. 인터럽트  (0) 2017.11.15
2. 타이머  (0) 2017.11.15
Comments