歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

字符設備驅動模塊 之 基本通用模塊

字符設備驅動模塊 之 基本通用模塊

  1. #include <linux/module.h>  
  2. #include <linux/types.h>  
  3. #include <linux/fs.h>  
  4. #include <linux/errno.h>  
  5. #include <linux/mm.h>  
  6. #include <linux/sched.h>  
  7. #include <linux/init.h>  
  8. #include <linux/cdev.h>  
  9. #include <asm/io.h>  
  10. #include <asm/system.h>  
  11. #include <asm/uaccess.h>  
  12. #include <linux/device.h> /* device_create()*/  
  13.   
  14. #define ADC_SIZE 0x1000 /*全局內存最大4K字節*/  
  15. #define MEM_CLEAR 0x1 /*清0全局內存*/  
  16. #define ADC_MAJOR 250 /*預設的adc的主設備號*/  
  17.   
  18. static int adc_major = ADC_MAJOR;  
  19. /*adc設備結構體*/  
  20. struct adc_dev {  
  21.   
  22.   
  23.  struct cdev cdev; /*cdev結構體*/  
  24.  unsigned char mem[ADC_SIZE]; /*全局內存*/  
  25. };  
  26.   
  27. struct adc_dev *adc_devp; /*設備結構體指針*/  
  28. /*文件打開函數*/  
  29. int adc_open(struct inode *inode, struct file *filp)  
  30. {  
  31.  /*將設備結構體指針賦值給文件私有數據指針*/  
  32.  filp->private_data = adc_devp;  
  33.  return 0;  
  34. }  
  35. /*文件釋放函數*/  
  36. int adc_release(struct inode *inode, struct file *filp)  
  37. {  
  38.  return 0;  
  39. }  
  40.   
  41. /* ioctl設備控制函數 */  
  42. static int adc_ioctl(struct inode *inodep, struct file *filp, unsigned  
  43.  int cmd, unsigned long arg)  
  44. {  
  45.  struct adc_dev *dev = filp->private_data;/*獲得設備結構體指針*/  
  46.   
  47.  switch (cmd) {  
  48.  case MEM_CLEAR:  
  49.   memset(dev->mem, 0, ADC_SIZE);  
  50.   printk(KERN_INFO "adc is set to zero\n");  
  51.   break;  
  52.   
  53.  default:  
  54.   return  - EINVAL;  
  55.  }  
  56.   
  57.  return 0;  
  58. }  
  59.   
  60. /*讀函數*/  
  61. static ssize_t adc_read(struct file *filp, char __user *buf, size_t size,  
  62.  loff_t *ppos)  
  63. {  
  64.  unsigned long p =  *ppos;  
  65.  unsigned int count = size;  
  66.  int ret = 0;  
  67.  struct adc_dev *dev = filp->private_data; /*獲得設備結構體指針*/  
  68.   
  69.  /*分析和獲取有效的寫長度*/  
  70.  if (p >= ADC_SIZE)  
  71.   return 0;  
  72.  if (count > ADC_SIZE - p)  
  73.   count = ADC_SIZE - p;  
  74.   
  75.  /*內核空間->用戶空間*/  
  76.  if (copy_to_user(buf, (void *)(dev->mem + p), count)) {  
  77.   ret =  - EFAULT;  
  78.  } else {  
  79.   *ppos += count;  
  80.   ret = count;  
  81.   
  82.   printk(KERN_INFO "read %u bytes(s) from %lu\n", count, p);  
  83.  }  
  84.   
  85.  return ret;  
  86. }  
  87.   
  88. /*寫函數*/  
  89. static ssize_t adc_write(struct file *filp, const char __user *buf,  
  90.  size_t size, loff_t *ppos)  
  91. {  
  92.  unsigned long p =  *ppos;  
  93.  unsigned int count = size;  
  94.  int ret = 0;  
  95.  struct adc_dev *dev = filp->private_data; /*獲得設備結構體指針*/  
  96.   
  97.  /*分析和獲取有效的寫長度*/  
  98.  if (p >= ADC_SIZE)  
  99.   return 0;  
  100.  if (count > ADC_SIZE - p)  
  101.   count = ADC_SIZE - p;  
  102.   
  103.  /*用戶空間->內核空間*/  
  104.  if (copy_from_user(dev->mem + p, buf, count))  
  105.   ret =  - EFAULT;  
  106.  else {  
  107.   *ppos += count;  
  108.   ret = count;  
  109.   
  110.   printk(KERN_INFO "written %u bytes(s) from %lu\n", count, p);  
  111.  }  
  112.   
  113.  return ret;  
  114. }  
  115.   
  116. /* seek文件定位函數 */  
  117. static loff_t adc_llseek(struct file *filp, loff_t offset, int orig)  
  118. {  
  119.  loff_t ret = 0;  
  120.  switch (orig) {  
  121.  case 0:   /*相對文件開始位置偏移*/  
  122.   if (offset < 0) {  
  123.    ret =  - EINVAL;  
  124.    break;  
  125.   }  
  126.   if ((unsigned int)offset > ADC_SIZE) {  
  127.    ret =  - EINVAL;  
  128.    break;  
  129.   }  
  130.   filp->f_pos = (unsigned int)offset;  
  131.   ret = filp->f_pos;  
  132.   break;  
  133.  case 1:   /*相對文件當前位置偏移*/  
  134.   if ((filp->f_pos + offset) > ADC_SIZE) {  
  135.    ret =  - EINVAL;  
  136.    break;  
  137.   }  
  138.   if ((filp->f_pos + offset) < 0) {  
  139.    ret =  - EINVAL;  
  140.    break;  
  141.   }  
  142.   filp->f_pos += offset;  
  143.   ret = filp->f_pos;  
  144.   break;  
  145.  default:  
  146.   ret =  - EINVAL;  
  147.   break;  
  148.  }  
  149.  return ret;  
  150. }  
  151.   
  152. /*文件操作結構體*/  
  153. static const struct file_operations adc_fops = {  
  154.  .owner = THIS_MODULE,  
  155.  .llseek = adc_llseek,  
  156.  .read = adc_read,  
  157.  .write = adc_write,  
  158.  .ioctl = adc_ioctl,  
  159.  .open = adc_open,  
  160.  .release = adc_release,  
  161. };  
  162.   
  163. /*初始化並注冊cdev*/  
  164. static void adc_setup_cdev(struct adc_dev *dev, int index)  
  165. {  
  166.  int err, devno = MKDEV(adc_major, index);  
  167.   
  168.  cdev_init(&dev->cdev, &adc_fops);  
  169.  dev->cdev.owner = THIS_MODULE;  
  170.  err = cdev_add(&dev->cdev, devno, 1);  
  171.  if (err)  
  172.   printk(KERN_NOTICE "Error %d adding LED%d", err, index);  
  173. }  
  174.   
  175. struct class *myclass;  
  176.   
  177.   
  178. /*設備驅動模塊加載函數*/  
  179. int adc_init(void)  
  180. {  
  181.  int result;  
  182.  dev_t devno = MKDEV(adc_major, 0);  
  183.   
  184.  /* 申請設備號*/  
  185.  if (adc_major)  
  186.   result = register_chrdev_region(devno, 1, "adc");  
  187.  else { /* 動態申請設備號 */  
  188.   result = alloc_chrdev_region(&devno, 0, 1, "adc");  
  189.   adc_major = MAJOR(devno);  
  190.  }  
  191.  if (result < 0)  
  192.   return result;  
  193.   
  194.  /* 動態申請設備結構體的內存*/  
  195.  adc_devp = kmalloc(sizeof(struct adc_dev), GFP_KERNEL);  
  196.  if (!adc_devp) {    /*申請失敗*/  
  197.   result =  - ENOMEM;  
  198.   goto fail_malloc;  
  199.  }  
  200.   
  201.  memset(adc_devp, 0, sizeof(struct adc_dev));  
  202.   
  203.  adc_setup_cdev(adc_devp, 0);  
  204.   
  205.    /*自動創建設備文件*/  
  206.  myclass = class_create(THIS_MODULE,"test_char"); /*在sys下創建類目錄/sys/class/test_char*/  
  207.  device_create(myclass, NULL, MKDEV(adc_major,0), NULL, "adc");    
  208.    
  209.  return 0;  
  210.   
  211. fail_malloc:  
  212.  unregister_chrdev_region(devno, 1);  
  213.  return result;  
  214. }  
  215.   
  216. /*模塊卸載函數*/  
  217. void adc_exit(void)  
  218. {  
  219.  cdev_del(&adc_devp->cdev);   /*注銷cdev*/  
  220.  kfree(adc_devp);     /*釋放設備結構體內存*/  
  221.  unregister_chrdev_region(MKDEV(adc_major, 0), 1); /*釋放設備號*/  
  222.  class_destroy(myclass);  
  223.  device_destroy(myclass,MKDEV(adc_major,0));  
  224. }  
  225.   
  226. MODULE_AUTHOR("Barry Song <21cnbao@gmail.com>");  
  227. MODULE_LICENSE("Dual BSD/GPL");  
  228.   
  229. module_param(adc_major, int, S_IRUGO);  
  230.   
  231. module_init(adc_init);  
  232. module_exit(adc_exit);  
  233.   
  234.    
  235.   
  236.    
  237.   
  238. 用戶程序:  
  239.   
  240. #include <stdio.h>  
  241. #include <stdlib.h>  
  242. #include <fcntl.h>  
  243. #include <unistd.h>  
  244. #include <string.h>  
  245. int main()  
  246. {  
  247.  int fd;  
  248.  char buf[4096];  
  249.   
  250.  strcpy(buf,"Mem is char dev!");  
  251.  printf("Buf: %s\n",buf);  
  252.   
  253.  fd=open("/dev/adc",O_RDWR);  
  254.  if(fd<0)  
  255.  {  
  256.    printf("open failed!\n");  
  257.   return -1;  
  258.  }  
  259.  else  
  260.   printf("open /dev/adc is success!\n");  
  261.  if(write(fd,buf,sizeof(buf))<0)  
  262.  {  
  263.   printf("write failed!\n");  
  264.   return -1;  
  265.  }  
  266.  else  
  267.   printf("write: %s\n",buf);  
  268.  lseek(fd,0,SEEK_SET);  
  269.    
  270.  strcpy(buf,"Buf is NULL!\n");  
  271.  printf("Buf: %s\n",buf);  
  272.    
  273.  read(fd,buf,sizeof(buf));  
  274.    
  275.  printf("Buf: %s\n",buf);  
  276.   
  277.  return 0;  

Copyright © Linux教程網 All Rights Reserved