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

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

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