• 内核驱动模块分布编译


    内核驱动模块代码

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. #include
    10. #include "fsmp157a_led_head.h"
    11. unsigned int *vir_gpioe_moder;
    12. unsigned int *vir_gpioe_odr;
    13. unsigned int *vir_gpiof_moder;
    14. unsigned int *vir_gpiof_odr;
    15. unsigned int *vir_rcc;
    16. char kbuf[128] = "";
    17. //封装操作方法
    18. //int (*open) (struct inode *, struct file *);
    19. //ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
    20. //ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
    21. //int (*release) (struct inode *, struct file *);
    22. //long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
    23. int mycdev_open(struct inode *inode, struct file *file)
    24. {
    25. int min = MINOR(inode->i_rdev);
    26. file->private_data = (void *)min;
    27. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    28. return 0;
    29. }
    30. ssize_t mycdev_read(struct file *file, char *ubuf, size_t size, loff_t *lof)
    31. {
    32. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    33. return 0;
    34. }
    35. ssize_t mycdev_write(struct file *fiile,const char *ubuf, size_t size, loff_t *lof)
    36. {
    37. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    38. int ret;
    39. //将用户空间的数据传递到内核
    40. ret = copy_from_user(kbuf, ubuf, size);
    41. if(ret)
    42. {
    43. printk("copy_from_user is filed\n");
    44. return -EIO;
    45. }
    46. /*
    47. switch(kbuf[0])
    48. {
    49. //LED1
    50. case '1':
    51. switch(kbuf[1])
    52. {
    53. case '0':
    54. //关灯逻辑
    55. (*vir_gpioe_odr) &= (~(0x1 << 10));
    56. break;
    57. case '1':
    58. //开灯逻辑
    59. (*vir_gpioe_odr) |= (0x1 << 10);
    60. break;
    61. }
    62. break;
    63. //LED2
    64. case '2':
    65. switch(kbuf[1])
    66. {
    67. case '0':
    68. //关灯逻辑
    69. (*vir_gpiof_odr) &= (~(0x1 << 10));
    70. break;
    71. case '1':
    72. //开灯逻辑
    73. (*vir_gpiof_odr) |= (0x1 << 10);
    74. break;
    75. }
    76. break;
    77. //LED3
    78. case '3':
    79. switch(kbuf[1])
    80. {
    81. case '0':
    82. //关灯逻辑
    83. (*vir_gpioe_odr) &= (~(0x1 << 8));
    84. break;
    85. case '1':
    86. //开灯逻辑
    87. (*vir_gpioe_odr) |= (0x1 << 8);
    88. break;
    89. }
    90. break;
    91. }
    92. */
    93. return 0;
    94. }
    95. int mycdev_close(struct inode *inode, struct file *file)
    96. {
    97. printk("%s:%s:%d\n", __FILE__, __func__, __LINE__);
    98. return 0;
    99. }
    100. //long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
    101. long mycdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
    102. {
    103. // int which;
    104. // int ret;
    105. // ret = copy_from_user(&which , (void *) arg, 4);
    106. // if(ret)
    107. // {
    108. // printk("copy_from_user is filed\n");
    109. // return -EIO;
    110. // }
    111. int min = (int)file->private_data;
    112. switch(min)
    113. {
    114. case 0:
    115. switch(cmd)
    116. {
    117. case LED_OFF:
    118. (*vir_gpioe_odr) &= (~(0x1 << 10));
    119. break;
    120. case LED_ON:
    121. (*vir_gpioe_odr) |= (0x1 << 10);
    122. break;
    123. }
    124. break;
    125. case 1:
    126. switch(cmd)
    127. {
    128. case LED_OFF:
    129. (*vir_gpiof_odr) &= (~(0x1 << 10));
    130. break;
    131. case LED_ON:
    132. (*vir_gpiof_odr) |= (0x1 << 10);
    133. break;
    134. }
    135. break;
    136. case 2:
    137. switch(cmd)
    138. {
    139. case LED_OFF:
    140. (*vir_gpioe_odr) &= (~(0x1 << 8));
    141. break;
    142. case LED_ON:
    143. (*vir_gpioe_odr) |= (0x1 << 8);
    144. break;
    145. }
    146. break;
    147. }
    148. return 0;
    149. }
    150. //定义一个操作方法结构体对象
    151. struct file_operations fos = {
    152. .open = mycdev_open,
    153. .read = mycdev_read,
    154. .write = mycdev_write,
    155. .release = mycdev_close,
    156. .unlocked_ioctl = mycdev_ioctl,
    157. };
    158. //定义变量,存放major
    159. unsigned int major;
    160. //定义变量,接收class_create()函数得到的对象指针
    161. struct class *cls;
    162. //定义变量,接收device_create()函数得到的对象指针
    163. struct device *dev;
    164. //定义变量,主设备号,次设备号
    165. unsigned int major=0;
    166. unsigned int minor=0;
    167. //定义变量,设备号
    168. dev_t devnum;
    169. //定义变量,存放申请类对象空间的首地址
    170. struct cdev *cdev;
    171. //定义变量,接收返回值
    172. int ret;
    173. //int __register_file(struct cdev *cdev, dev_t devnum, unsigned int major, unsigned int minor, struct class *cls, struct device *dev, struct file_operations *fos);
    174. int __register_file(void);
    175. //入口函数
    176. static int __init mycdev_init(void)
    177. {
    178. // __register_file(cdev, devnum, major, minor, cls, dev, &fos);
    179. __register_file();
    180. /*
    181. //注册设备驱动,申请0-255共256个资源(次设备号)
    182. major = register_chrdev(0, "mychardev", &fos);
    183. if(major < 0)
    184. {
    185. printk("注册设备驱动失败\n");
    186. return major;
    187. }
    188. printk("注册设备驱动成功:major = %d\n", major);
    189. //向上提供目录
    190. //函数原型struct class *class_create(owner, name);
    191. //功能:向上提供目录信息,申请一个struct class类对象空间并初始化
    192. //参数1:owner:指向当前模块自身的一个指针,填写THIS_MODULE
    193. //参数2:name:向上提交的目录名
    194. //返回值:成功返回申请到的class对象的首地址,失败返回一个指向内核顶层4k空间的指针
    195. cls = class_create(THIS_MODULE, "mychrdev");
    196. if(IS_ERR(cls))
    197. {
    198. printk("向上提供目录失败\n");
    199. return -PTR_ERR(cls);
    200. }
    201. printk("向上提供目录成功\n");
    202. //向上提供设备节点信息
    203. //函数原型struct device *device_create(struct class *cls, struct device *parent, dev_t devt, void *drvdata, const char *fmt, ...);
    204. int i;
    205. for(i=0; i<3; i++)
    206. {
    207. dev = device_create(cls, NULL, MKDEV(major, i), NULL, "myled%d", i);
    208. if(IS_ERR(dev))
    209. {
    210. printk("向上提供设备节点信息失败\n");
    211. return -PTR_ERR(dev);
    212. }
    213. }
    214. printk("向上提供设备节点信息成功\n");
    215. */
    216. //物理内存映射到虚拟地址
    217. //GOIOE_MODER寄存器地址映射
    218. vir_gpioe_moder = ioremap(PHY_GPIOE_MODER, 4);
    219. if(NULL == vir_gpioe_moder)
    220. {
    221. printk("物理内存地址映射失败%d\n", __LINE__);
    222. return -EFAULT;
    223. }
    224. //GOIOE_ODR寄存器地址映射
    225. vir_gpioe_odr = ioremap(PHY_GPIOE_ODR, 4);
    226. if(NULL == vir_gpioe_odr)
    227. {
    228. printk("物理内存地址映射失败%d\n", __LINE__);
    229. return -EFAULT;
    230. }
    231. //GOIOF_MODER寄存器地址映射
    232. vir_gpiof_moder = ioremap(PHY_GPIOF_MODER, 4);
    233. if(NULL == vir_gpiof_moder)
    234. {
    235. printk("物理内存地址映射失败%d\n", __LINE__);
    236. return -EFAULT;
    237. }
    238. //GOIOF_ODR寄存器地址映射
    239. vir_gpiof_odr = ioremap(PHY_GPIOF_ODR, 4);
    240. if(NULL == vir_gpiof_odr)
    241. {
    242. printk("物理内存地址映射失败%d\n", __LINE__);
    243. return -EFAULT;
    244. }
    245. //RCC_AHB4ENSETR寄存器地址映射
    246. vir_rcc = ioremap(PHY_RCC, 4);
    247. if(NULL == vir_rcc)
    248. {
    249. printk("物理内存地址映射失败%d\n", __LINE__);
    250. return -EFAULT;
    251. }
    252. printk("物理内存地址映射成功\n");
    253. //寄存器初始化工作
    254. //RCC使能GPIOE/GPIOF组控制器
    255. (*vir_rcc) |= (0x3 << 4);
    256. return 0;
    257. }
    258. //出口函数
    259. static void __exit mycdev_exit(void)
    260. {
    261. //取消内存映射
    262. iounmap(vir_gpioe_moder);
    263. iounmap(vir_gpioe_odr);
    264. iounmap(vir_gpiof_moder);
    265. iounmap(vir_gpiof_odr);
    266. iounmap(vir_rcc);
    267. //销毁设备节点信息
    268. int i;
    269. for(i=0; i<3; i++)
    270. {
    271. device_destroy(cls, MKDEV(major, i));
    272. }
    273. //删除目录信息
    274. class_destroy(cls);
    275. //注销字符设备驱动对象
    276. cdev_del(cdev);
    277. //释放设备号
    278. unregister_chrdev_region(MKDEV(major, major), 3);
    279. //释放申请到的字符设备驱动对象空间
    280. kfree(cdev);
    281. //删除信息
    282. // //销毁设备节点信息
    283. // int i;
    284. // for(i=0; i<3; i++)
    285. // {
    286. // device_destroy(cls, MKDEV(major, i));
    287. // }
    288. // //销毁目录信息
    289. // class_destroy(cls);
    290. // //注销字符设备驱动
    291. // unregister_chrdev(major, "mychrdev");
    292. }
    293. //声明入口函数
    294. module_init(mycdev_init);
    295. //声明出口函数
    296. module_exit(mycdev_exit);
    297. //声明内核模块遵循GPL协议
    298. MODULE_LICENSE("GPL");
    299. //注册设备驱动,创建设备文件
    300. //int __register_file(struct cdev *cdev, dev_t devnum, unsigned int major, unsigned int minor, struct class *cls, struct device *dev, struct file_operations *fos)
    301. int __register_file(void)
    302. {
    303. //1.申请字符设备驱动对象空间
    304. cdev = cdev_alloc();
    305. if(NULL == cdev)
    306. {
    307. printk("申请字符设备驱动对象空间失败\n");
    308. goto out1;
    309. }
    310. printk("申请字符设备驱动成功\n");
    311. //2.初始化对象
    312. //函数原型: cdev_init(struct cdev *, const struct file_operations *);
    313. cdev_init(cdev, &fos);
    314. //3.申请设备号
    315. if(0 == major)
    316. {
    317. ret = alloc_chrdev_region(&devnum, minor, 3, "mychrdev");
    318. if(ret)
    319. {
    320. printk("申请设备号失败\n");
    321. goto out2;
    322. }
    323. major = MAJOR(devnum);
    324. minor = MINOR(devnum);
    325. printk("动态申请设备号成功\n");
    326. }
    327. else
    328. {
    329. ret = register_chrdev_region(MKDEV(major, minor), 3, "mychrdev");
    330. if(ret)
    331. {
    332. printk("申请设备号失败\n");
    333. goto out2;
    334. }
    335. printk("静态申请设备号成功\n");
    336. }
    337. //4.注册设备驱动到内核
    338. ret = cdev_add(cdev, MKDEV(major, minor), 3);
    339. if(ret)
    340. {
    341. printk("注册设备驱动到内核失败\n");
    342. goto out3;
    343. }
    344. printk("注册设备驱动到内核成功\n");
    345. //5.向上提交目录信息
    346. cls = class_create(THIS_MODULE, "mychrdev");
    347. if(IS_ERR(cls))
    348. {
    349. printk("向上提交目录失败\n");
    350. goto out4;
    351. }
    352. printk("向上提交目录成功\n");
    353. //6.向上提交设备节点信息
    354. int i;
    355. for(i=0; i<3; i++)
    356. {
    357. dev = device_create(cls, NULL, MKDEV(major, i), NULL, "mychrdev%d", i);
    358. if(IS_ERR(dev))
    359. {
    360. printk("向上提交设备节点信息失败\n");
    361. goto out5;
    362. }
    363. }
    364. printk("向上提交设备节点信息成功\n");
    365. return 0;
    366. out5:
    367. //删除设备节点信息
    368. for(--i; i>=0; i--)
    369. {
    370. device_destroy(cls, MKDEV(major, i));
    371. return -PTR_ERR(dev);
    372. }
    373. //删除设备目录
    374. class_destroy(cls);
    375. return -PTR_ERR(cls);
    376. out4:
    377. //注销设备驱动
    378. cdev_del(cdev);
    379. out3:
    380. //释放设备号
    381. unregister_chrdev_region(MKDEV(major, major), 3);
    382. out2:
    383. //释放字符设备驱动对象空间
    384. kfree(cdev);
    385. out1:
    386. return ret;
    387. }

    应用层测试代码

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include "fsmp157a_led_head.h"
    8. int main(int argc, char const *argv[])
    9. {
    10. char buf[128] = "";
    11. char filename[128] = "";
    12. printf("请输入操作的设备文件\n");
    13. fgets(filename, sizeof(filename), stdin);
    14. filename[strlen(filename) - 1] = '\0';
    15. int fd = open(filename, O_RDWR);
    16. if(fd < 0)
    17. {
    18. printf("打开设备文件失败\n");
    19. return -1;
    20. }
    21. printf("打开设备文件成功\n");
    22. while(1)
    23. {
    24. while(1)
    25. {
    26. ioctl(fd, LED_ON);
    27. sleep(1);
    28. ioctl(fd, LED_OFF);
    29. sleep(1);
    30. }
    31. }
    32. return 0;
    33. }

    头文件

    1. #ifndef __HEAD_H__
    2. #define __HEAD_H__
    3. //GPIOE_MODER寄存器地址
    4. #define PHY_GPIOE_MODER 0x50006000
    5. //GPIOE_ODR寄存器地址
    6. #define PHY_GPIOE_ODR 0X50006014
    7. //GPIOF_MODER寄存器地址
    8. #define PHY_GPIOF_MODER 0X50007000
    9. //GPIOF_ODR寄存器地址
    10. #define PHY_GPIOF_ODR 0X50007014
    11. //RCC_AHB4ENSETR寄存器地址
    12. #define PHY_RCC 0x50000A28
    13. //构建开关等的功能码
    14. #define LED_ON _IO('l', 1)
    15. #define LED_OFF _IO('l', 0)
    16. #endif

  • 相关阅读:
    计算机毕设 SpringBoot+Vue校园博客系统 博客管理系统 开源博客系统 个人博客系统Java Vue MySQL数据库 远程调试 代码讲解
    gzip 压缩优化大 XML 响应的处理方法
    责任链模式
    通过Shell脚本自动安装Hive&JDBC测试&提供CDH5网盘地址
    爬虫入门教程:爬虫概述
    C语言学习笔记 —— 内存管理
    大模型高级 RAG 检索策略:自动合并检索
    流媒体技术优化
    传奇战盟GOM引擎登录器配置教程
    工具篇--分布式定时任务springBoot--elasticjob简单使用(1)
  • 原文地址:https://blog.csdn.net/qq_46766479/article/details/134000950