Device driver

2,558 views

Published on

옛날에 했던 linux device driver 정리...-_-)

Published in: Technology, Business
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
2,558
On SlideShare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
0
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Device driver

  1. 1. Device Driver <ul><li>정현환 </li></ul><ul><li>최용재 </li></ul>
  2. 2. Device <ul><li>물리적 또는 논리적인 장치 </li></ul><ul><li>물리적인 장치 </li></ul><ul><ul><li>키보드 , USB, 메모리 , HDD 등등 </li></ul></ul><ul><li>논리적인 장치 </li></ul><ul><ul><li>가상의 장치라고도 할 수 있다 . </li></ul></ul><ul><ul><li>가상 콘솔 , 파이프등 </li></ul></ul>
  3. 3. Device <ul><li>유닉스에서는 장치도 파일 </li></ul><ul><li>보통 /dev/ 에 위치함 </li></ul>
  4. 4. Device Driver <ul><li>각각의 Device 를 제어할 수 있는 프로그램 </li></ul><ul><li>커널영역에서 커널의 리소스를 사용함 </li></ul><ul><li>어플리케이션에게 서비스를 제공함 </li></ul>
  5. 5. Character Device <ul><li>바이트 단위의 I/O 가 가능함 </li></ul><ul><li>단방향 데이터참조만 가능 ( 일반 파일과의 차이점 ) </li></ul><ul><li>문자 콘솔 , 키보드등 </li></ul>
  6. 6. Block Device <ul><li>블럭단위의 I/O 가 가능함 </li></ul><ul><ul><li>블럭이란 1 바이트 이상의 데이터 덩어리 </li></ul></ul><ul><li>리눅스에서는 한 번에 전송하는 데이터의 양에 제한이 없음 </li></ul><ul><li>문자 디바이스와 비교하여 커널과의 인터페이스만 다르다 ( 버퍼 캐시의 유무 / 처리 방법 ) </li></ul>
  7. 7. Network Device <ul><li>실제로 장치파일이 존재하지 않음 </li></ul><ul><li>socket 을 이용해서 사용 </li></ul>
  8. 8. Device number <ul><li>Device 들은 Major number 와 Minor number 가 할당되어 있음 </li></ul><ul><li>Major number 는 Device 가 Driver 를 구분하기 위해서 존재한다 . </li></ul><ul><li>Minor number 는 Driver 에 할당된 여러 Device 들을 구분하기 위해 할당됨 . </li></ul><ul><li>동적 할당과 정적 할당이 가능함 . </li></ul>
  9. 9. Device number Old
  10. 10. Device number New
  11. 11. Device number
  12. 12. Device number
  13. 13. Driver stacking <ul><li>device driver 는 원하는 리소스를 밖에서 사용할 수 있도록 export 할 수 있다 .(windows 의 dll 처럼 ) </li></ul><ul><li>device driver 는 다른 device driver 의 리소스를 사용할 수 있다 . </li></ul><ul><li>따라서 driver 들 간의 dependency 가 생긴다 . </li></ul><ul><li>이러한 관계들을 driver stacking 이라 한다 . </li></ul>
  14. 14. File operations <ul><li>driver 는 다른 모듈과는 달리 파일로 추상화 되어야 하므로 file operation 을 정의해줘야 한다 . </li></ul>struct file_operations { int (* open ) (struct inode *, struct file *); ssize_t (* read ) (struct file *, char *, size_t, loff_t *); ssize_t (* write ) (struct file *, const char *, size_t, loff_t *); ... }
  15. 15. Mechanism
  16. 16. Simple Character Utility for Loading Localities
  17. 17. scull device
  18. 18. Device number 의 내부 표현 <ul><li>MAJOR(dev_t dev) </li></ul><ul><li>MINOR(dev_t dev) </li></ul><ul><li>MKDEV(int major, int minor) </li></ul>
  19. 19. Device number 의 할당 / 해제 <ul><li>할당 </li></ul><ul><ul><li>int register_chrdev_region(dev_t first, unsigned int count, char *name); </li></ul></ul><ul><ul><ul><li>Static </li></ul></ul></ul><ul><ul><li>int alloc_chrdev_region(dev_t *dev, unsigned int firstminor, unsigned int count, char *name); </li></ul></ul><ul><ul><ul><li>Dynamic </li></ul></ul></ul><ul><li>해제 </li></ul><ul><ul><li>void unregister_chrdev_region(dev_t first, unsigned int count); </li></ul></ul>
  20. 20. Device node 생성 (scull_load) <ul><li>mknod /dev/${device}0 c $major 0 </li></ul><ul><li>major=$(awk &quot;$2= = &quot;$module&quot; {print $1}&quot; /proc/devices) </li></ul>
  21. 21. Major number 얻어오기 <ul><li>if (scull_major) { </li></ul><ul><li>  dev = MKDEV(scull_major, scull_minor); </li></ul><ul><li>  result = register_chrdev_region(dev, scull_nr_devs, &quot;scull&quot;); </li></ul><ul><li>} else { </li></ul><ul><li>result = alloc_chrdev_region(&dev, scull_minor, scull_nr_devs,&quot;scull&quot;); </li></ul><ul><li>  scull_major = MAJOR(dev); </li></ul><ul><li>} </li></ul><ul><li>if (result < 0) { </li></ul><ul><li>  printk(KERN_WARNING &quot;scull: can't get major %dn&quot;, scull_major); </li></ul><ul><li>   return result; </li></ul><ul><li>} </li></ul>
  22. 22. file_operation 구조체 <ul><li>struct file_operations scull_fops = { </li></ul><ul><li>.owner = THIS_MODULE, </li></ul><ul><li>.llseek = scull_llseek, </li></ul><ul><li>.read = scull_read, </li></ul><ul><li>.write = scull_write, </li></ul><ul><li>.ioctl = scull_ioctl, </li></ul><ul><li>.open = scull_open, </li></ul><ul><li>.release = scull_release, </li></ul><ul><li>}; </li></ul>
  23. 23. file 구조체 <ul><li>mode_t f_mode </li></ul><ul><li>loff_t f_pos </li></ul><ul><li>unsigned int f_flags </li></ul><ul><li>struct file_operation *f_op </li></ul><ul><li>void *private_data </li></ul>
  24. 24. inode 구조체 <ul><li>dev_t i_rdev </li></ul><ul><li>struct cdev *i_cdev </li></ul>
  25. 25. device 등록 <ul><li>struct scull_dev { </li></ul><ul><li>struct scull_qset *data; </li></ul><ul><li>int quantum; </li></ul><ul><li>int qset; </li></ul><ul><li>unsigned long size; </li></ul><ul><li>struct cdev cdev; </li></ul><ul><li>}; </li></ul>
  26. 26. device 등록 <ul><li>static void scull_setup_cdev(struct scull_dev *dev, int index) </li></ul><ul><li>{ </li></ul><ul><li>int err, devno = MKDEV(scull_major, scull_minor + index); </li></ul><ul><li>cdev_init(&dev->cdev, &scull_fops); </li></ul><ul><li>dev->cdev.owner = THIS_MODULE; </li></ul><ul><li>dev->cdev.ops = &scull_fops; </li></ul><ul><li>err = cdev_add (&dev->cdev, devno, 1); </li></ul><ul><li>if (err) </li></ul><ul><li>printk(KERN_NOTICE &quot;Err : %d at scull%d&quot;, err, index); </li></ul><ul><li>} </li></ul>
  27. 27. scull_open <ul><li>open 에서 일어나는 일 </li></ul><ul><ul><li>디바이스 관련 오류 확인 </li></ul></ul><ul><ul><li>처음 디바이스를 열게 될 경우 초기화 </li></ul></ul><ul><ul><li>f_op 포인터 갱신 </li></ul></ul><ul><ul><li>자료구조 할당 및 filp->private_data 에 들어갈 값을 채움 </li></ul></ul>
  28. 28. scull_open <ul><li>int scull_open(struct inode *inode, struct file *filp) </li></ul><ul><li>{ </li></ul><ul><li>struct scull_dev *dev; </li></ul><ul><li>dev = container_of(inode->i_cdev, struct scull_dev, cdev); </li></ul><ul><li>filp->private_data = dev; </li></ul><ul><li>if ( (filp->f_flags & O_ACCMODE) == O_WRONLY) { </li></ul><ul><li>scull_trim(dev); </li></ul><ul><li>} </li></ul><ul><li>return 0; </li></ul><ul><li>} </li></ul>
  29. 29. scull 에서 메모리 사용
  30. 30. scull_qset <ul><li>struct scull_qset { </li></ul><ul><li>void **data; </li></ul><ul><li>struct scull_qset *next; </li></ul><ul><li>}; </li></ul>
  31. 31. scull_trim <ul><li>int scull_trim(struct scull_dev *dev) { </li></ul><ul><li>struct scull_qset *next, *dptr; </li></ul><ul><li>int qset = dev->qset, i; </li></ul><ul><li>for (dptr = dev->data; dptr; dptr = next) { </li></ul><ul><li>if (dptr->data) { </li></ul><ul><li>for (i = 0; i < qset; i++) kfree(dptr->data[i]); </li></ul><ul><li>kfree(dptr->data); dptr->data = NULL; </li></ul><ul><li>} </li></ul><ul><li>next = dptr->next; kfree(dptr); </li></ul><ul><li>} </li></ul><ul><li>dev->size = 0; dev->quantum = scull_quantum; </li></ul><ul><li>dev->qset = scull_qset; dev->data = NULL; </li></ul><ul><li>return 0; </li></ul><ul><li>} </li></ul>
  32. 32. read/write <ul><li>Prototype </li></ul><ul><ul><li>ssize_t read(struct file *filp, char __user *buff, size_t count, loff_t *offp); </li></ul></ul><ul><ul><li>ssize_t write(struct file *filp, const char __user *buff, size_t count, loff_t *offp); </li></ul></ul>
  33. 33. read/write <ul><li>Copy function </li></ul><ul><ul><li>unsigned long copy_to_user(void __user *to, const void *from, unsigned long count); </li></ul></ul><ul><ul><li>unsigned long copy_from_user(void *to, const void __user *from, unsigned long count); </li></ul></ul>
  34. 34. read/write
  35. 35. scull_read <ul><li>ssize_t scull_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { </li></ul><ul><li>struct scull_dev *dev = filp->private_data; </li></ul><ul><li>struct scull_qset *dptr; </li></ul><ul><li>int quantum = dev->quantum, qset = dev->qset; </li></ul><ul><li>int itemsize = quantum * qset; </li></ul><ul><li>int item, s_pos, q_pos, rest; </li></ul><ul><li>ssize_t retval = 0; </li></ul>
  36. 36. scull_read <ul><li>if (down_interruptible(&dev->sem)) </li></ul><ul><li>return -ERESTARTSYS; </li></ul><ul><li>if (*f_pos >= dev->size) </li></ul><ul><li>goto out; </li></ul><ul><li>if (*f_pos + count > dev->size) </li></ul><ul><li>count = dev->size - *f_pos; </li></ul><ul><li>item = (long)*f_pos / itemsize; </li></ul><ul><li>rest = (long)*f_pos % itemsize; </li></ul><ul><li>s_pos = rest / quantum; q_pos = rest % quantum; </li></ul>
  37. 37. scull_read <ul><li>dptr = scull_follow(dev, item); </li></ul><ul><li>if (dptr == NULL || !dptr->data || ! dptr->data[s_pos]) goto out; </li></ul><ul><li>if (count > quantum - q_pos) count = quantum - q_pos; </li></ul><ul><li>if (copy_to_user(buf, dptr->data[s_pos] + q_pos, count)) { </li></ul><ul><li>retval = -EFAULT; </li></ul><ul><li>goto out; </li></ul><ul><li>} </li></ul><ul><li>*f_pos += count; </li></ul><ul><li>retval = count; </li></ul>
  38. 38. scull_read <ul><li>out: </li></ul><ul><li>up(&dev->sem); </li></ul><ul><li>return retval; </li></ul><ul><li>} </li></ul>
  39. 39. scull_write <ul><li>ssize_t scull_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos) </li></ul><ul><li>{ </li></ul><ul><li>struct scull_dev *dev = filp->private_data; </li></ul><ul><li>struct scull_qset *dptr; </li></ul><ul><li>int quantum = dev->quantum, qset = dev->qset; </li></ul><ul><li>int itemsize = quantum * qset; </li></ul><ul><li>int item, s_pos, q_pos, rest; </li></ul><ul><li>ssize_t retval = -ENOMEM; </li></ul>
  40. 40. scull_write <ul><li>if (down_interruptible(&dev->sem)) </li></ul><ul><li>return -ERESTARTSYS; </li></ul><ul><li>item = (long)*f_pos / itemsize; </li></ul><ul><li>rest = (long)*f_pos % itemsize; </li></ul><ul><li>s_pos = rest / quantum; q_pos = rest % quantum; </li></ul>
  41. 41. scull_write <ul><li>dptr = scull_follow(dev, item); </li></ul><ul><li>if (dptr == NULL) </li></ul><ul><li>goto out; </li></ul><ul><li>if (!dptr->data) { </li></ul><ul><li>dptr->data = kmalloc(qset * sizeof(char *), GFP_KERNEL); </li></ul><ul><li>if (!dptr->data) goto out; </li></ul><ul><li>memset(dptr->data, 0, qset * sizeof(char *)); </li></ul><ul><li>} </li></ul>
  42. 42. scull_write <ul><li>if (!dptr->data[s_pos]) { </li></ul><ul><li>dptr->data[s_pos] = kmalloc(quantum, GFP_KERNEL); </li></ul><ul><li>if (!dptr->data[s_pos]) </li></ul><ul><li>goto out; </li></ul><ul><li>} </li></ul><ul><li>if (count > quantum - q_pos) </li></ul><ul><li>count = quantum - q_pos; </li></ul>
  43. 43. scull_write <ul><li>if (copy_from_user(dptr->data[s_pos]+q_pos, buf, count)) { </li></ul><ul><li>retval = -EFAULT; </li></ul><ul><li>goto out; </li></ul><ul><li>} </li></ul><ul><li>*f_pos += count; </li></ul><ul><li>retval = count; </li></ul><ul><li>if (dev->size < *f_pos) dev->size = *f_pos; </li></ul><ul><li>out: </li></ul><ul><li>up(&dev->sem); </li></ul><ul><li>return retval; </li></ul><ul><li>} </li></ul>

×