歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> 字符設備驅動模塊 之 基本通用模塊

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

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

Copyright © Linux教程網 All Rights Reserved