Device Driver March 24, 2004 Kim, ki-hyeon
목차 1. 인터럽트처리복습
1. 인터럽트복습 입력검출방법 인터럽트방식, 폴링 (polling) 방식 인터럽트서비스등록함수 ( 커널에등록 ) int request_irq(unsigned int irq, void(*handler)(int,void*,struct pt_regs*), unsigned long frags, const char *device, void *dev_id); 인터럽트서비스제거함수 void free_irq(unsigned int irq, void *dev_id); 인터럽트금지및허용 하나의인터럽트처리중이나두개가동시발생시우선권을준다. request_irq() 에서 frags부분에 SA_INTERRUPT를포함시켜주어서인터럽트처리에우선권을준다. 그래서 SA_INTERRUPT가포함된서비스루틴을빠른인터럽트핸들러라고하고없는것은느린인터럽트핸들러라고한다. 일반함수수행시에인터럽트발생을금지하고자한다면 Void disable_irq(int irq); Void enable_irq(int irq);
프로세스 실행상태에있는프로그램의인스턴스 프로세스가잔다? 프로그램에게할당된시간을다른프로그램에게넘기고수행을중지함을뜻한다. 프로세스처리함수 변수선언및초기화 대기큐 (WaitQueue) : linked list 구조로이루어져있다. 을경우, 동일한장치파일을두개이상의프로세스가동시에열었 하나의프로세스만을선택적으로깨우기위해프로세스의정보를가지는변수. 선언 : wait_queue_head_t waitqueue;
struct wait_queue_head wq_lock_t lock; struct list_head task_list; #if WAITQUEUE_DEBUG long magic; long creator; #endif ; typedef struct wait_queue_head wait_queue_head_t; struct wait_queue unsigned int flags; struct task_struct * task; struct list_head task_list; ; typedef struct wait_queue wait_queue_t;
초기화함수 init_waitqueue_head(&waitqueue); static inline void init_waitqueue_head(wait_queue_head_t *q) #if WAITQUEUE_DEBUG if (!q) WQ_BUG(); #endif q->lock = WAITQUEUE_RW_LOCK_UNLOCKED; INIT_LIST_HEAD(&q->task_list); #if WAITQUEUE_DEBUG q-> magic = (long)&q-> magic; q-> creator = (long)current_text_addr(); #endif
INIT_LIST_HEAD() #define INIT_LIST_HEAD(ptr) do (ptr)->next =(ptr); (ptr)->prev =(ptr); while(0) * struct list_head struct list_head struct list_head *next, *prev; ; * DECLARE_WAIT_QUEUE_HEAD(waitQueue); * #define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x = NULL
프로세스를재우는함수 Interruptible_sleep_on(&waitQueue); Interruptible_sleep_on_timeout(&waitQueue, msecwait); void sleep_on(wait_queue_head_t *q) unsigned long flags; wait_queue_t wait; wait.flags =0; wait.task =current; current->state = TASK_UNINTERRUPTIBLE; add_wait_queue(q, &wait); schedule(); remove_wait_queue(q, &wait);
프로세스를깨우기위한함수 wake_up_interruptible(&waitqueue); wake_up(&waitqueue); 대기큐에저장된프로세스들을깨운다. #define wake_up_interruptible(x) wake_up((x),task_interruptible, 1)
소스분석 wait_queue_head_t waitqueue; // 인터럽트처리함수 void PRN_interrupt(int irq, void *dev_id, struct pt_regs *regs) // 잠든프로세스를깨운다. wake_up_interruptible(waitqueue);
// 어플리케이션에서 read 함수호출시호출됨 ssize_t PRN_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) unsigned char prnstat; int loop; // 프로세스를잠들어버린다. interruptible_sleep_on(&waitqueue); for(loop=0; loop<count; loop++) prnstat = inb(prn_address_status); put_user(prnstat, (char *)&buf[loop]; return count;
// 어플리케이션에서 open 함수호출시호출 int PRN_open(struct inode *inode, struct file *filp) // 인터럽트핸들러를등록한다. //linux/sched.h 에선언한다. if(!request_irq(prnsleep_irq, PRN_interrupt, SA_INTERRUPT, PRN_DEV_NAME, NULL)) outb(irq_enable, PRN_ADDRESS_CTRL); printk("interrupt Register OK... n"); MOD_INC_USE_COUNT; return 0;
// 어플리케이션에서 write 함수호출시호출 ssize_t PRN_write(struct file *filp, const char *buf, size_t count, loff_t *f_pos) unsigned char c; get_user(c, (char *)buf); outb(c, PRN_ADDRESS); return 1; // 어플리케이션에서 close 함수호출시호출 int PRN_release(struct inode *inode, struct file *flip) // 인터럽트해제 outb(0x00, PRN_ADDRESS_CTRL); free_irq(prnsleep_irq,null); MOD_DEC_USE_COUNT; return 0;
// 함수구조체 struct file_operations PRN_fops = read : PRN_read, write : PRN_write, open : PRN_open, release : PRN_release, ; //insmod 에의해호출되는함수 int PRN_init(void) int result; init_waitqueue_head(&waitqueue); result = register_chrdev(prn_dev_major, PRN_DEV_NAME, &PRN_fops); if(result < 0) return result; return 0;
//rmmdo에의해호출되는함수 void PRN_exit(void) unregister_chrdev(prn_dev_major,prn_dev_name); module_init(prn_init); module_exit(prn_exit);