歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> 普通字符設備LED驅動程序(IO映射內存實現)

普通字符設備LED驅動程序(IO映射內存實現)

日期:2017/3/1 11:15:09   编辑:Linux編程
驅動程序:
  1. #include <linux/module.h> //內核模塊頭文件
  2. #include <linux/moduleparam.h> //內核模塊參數頭文件
  3. #include <linux/kernel.h> //printk頭文件
  4. #include<asm/io.h>//ioremap需要
  5. //包含有可裝載模塊需要的大量符合和函數的定義;
  6. #include <linux/init.h>
  7. //指定初始化和清除函數;
  8. //struct file_operactions 相關頭文件
  9. #include <linux/fs.h>
  10. #include <asm/uaccess.h>
  11. //struct cdev 相關頭文件
  12. #include <linux/types.h>
  13. #include <linux/cdev.h>
  14. //定義設備名稱
  15. #define DEVICE_NAME "led2"
  16. //定義主次設備號
  17. static unsigned int LedMajor=0;
  18. static unsigned int LedMinor=0;
  19. /* 注冊字符設備 */
  20. static struct cdev *led_cdev;
  21. static dev_t dev; //設備號
  22. volatile unsigned int long *gpb_con = NULL;
  23. volatile unsigned int long *gpb_data = NULL;
  24. static int led_ioctl(struct inode *inode, struct file *file,
  25. unsigned int cmd, unsigned long arg)
  26. {
  27. if((cmd>1) | (cmd<0) | (arg>3) | (arg<0))
  28. return -EINVAL;
  29. switch(cmd)
  30. {
  31. case 0:
  32. *gpb_data&= ~(1<<(arg+5)); //0
  33. break;
  34. case 1:
  35. *gpb_data|= (1<<(arg+5)); //1
  36. break;
  37. default:
  38. return -EINVAL;
  39. }
  40. return 0;
  41. }
  42. static int led_open(struct inode *inode, struct file *file)
  43. {
  44. printk("led_open\n");
  45. //映射I/O內存
  46. gpb_con = (volatile unsigned long *)ioremap(0x56000010,16); //0x56000010為GPIOB控制寄存器的物理地址
  47. gpb_data = gpb_con+1; //這裡+1是加了4個字節,因為指針+1是以指針的長度為單位的(unsigned long *)
  48. /* 配置GPB5,6,7,8為輸出 */
  49. *gpb_con |= (1<<(5*2)) | (1<<(6*2)) | (1<<(7*2)) | (1<<(8*2));
  50. /* 初始化為滅 */
  51. *gpb_data |=(1<<5) | (1<<6) | (1<<7) | (1<<8);
  52. printk("leaving led_open\n");
  53. return 0;
  54. }
  55. static int led_release(struct inode *inode,struct file *file)
  56. {
  57. printk("close major=%d, minor=%d\n", imajor(inode), iminor(inode));
  58. return 0;
  59. }
  60. static struct file_operations chardev_fops={
  61. .owner = THIS_MODULE,
  62. .open = led_open,
  63. .release = led_release,
  64. .ioctl = led_ioctl,
  65. };
  66. static int __init dev_init(void)
  67. {
  68. int result;
  69. /*分配設備編號*/
  70. if(LedMajor)
  71. {
  72. dev=MKDEV(LedMajor,LedMinor);//創建設備編號
  73. result=register_chrdev_region(dev,1,DEVICE_NAME);
  74. }
  75. else
  76. {
  77. result=alloc_chrdev_region(&dev,LedMinor,1,DEVICE_NAME);
  78. LedMajor=MAJOR(dev);
  79. }
  80. if(result<0)
  81. {
  82. printk(KERN_WARNING"LED: cannot get major %d \n",LedMajor);
  83. return result;
  84. }
  85. /* 注冊字符設備 */
  86. led_cdev=cdev_alloc();//為struct cdev 分配空間
  87. cdev_init(led_cdev,&chardev_fops);//初始化struct cdev
  88. led_cdev->owner=THIS_MODULE;
  89. result=cdev_add(led_cdev,dev,1);
  90. if(result)
  91. printk("<1>Error %d while register led device!\n",result);
  92. printk("initialzed.\n");
  93. return 0;
  94. }
  95. static void __exit dev_exit(void)
  96. {
  97. unregister_chrdev_region(MKDEV(LedMajor,LedMinor),1);
  98. cdev_del(led_cdev);
  99. }
  100. module_init(dev_init);
  101. module_exit(dev_exit);
  102. MODULE_LICENSE("GPL");
  103. MODULE_AUTHOR("Bai");

這段代碼把GPB寄存器的物理地址映射到內存上,再進行操作。

注冊一個獨立的cdev設備的基本過程如下:

1、為struct cdev 分配空間
struct cdev *my_cdev = cdev_alloc();

2、初始化struct cdev ,主要是對 file_operations成員賦值,

void cdev_init(struct cdev *cdev, const struct file_operations *fops)

3、初始化cdev.owner 指針,實現模塊管理時的指針引用

cdev.owner = THIS_MODULE;

4、cdev設置完成後,向內核字符設備數組添加新的struct cdev的信息(在執行這步之前必須確定你對struct cdev的以上設置已經完成)

int cdev_add(struct cdev *dev, dev_t devno, unsigned count)

dev 是 cdev 結構, devno是這個設備響應的第一個設備號, count 是應當關聯到設備的設備號的數目.

5、從系統中移除一個字符設備:
void cdev_del(struct cdev *dev)

Copyright © Linux教程網 All Rights Reserved