普通字符设备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)

  • 1
  • 2
  • 下一页

相关内容