2. 字符设备驱动的传统写法

硬件平台:AM335x

编写驱动分下面几步:
       a -- 查看原理图、数据手册,了解设备的操作方法;
       b -- 在内核中找到相近的驱动程序,以它为模板进行开发,有时候需要从零开始;
       c -- 实现驱动程序的初始化:比如向内核注册这个驱动程序,这样应用程序传入文件名,内核才能找到相应的驱动程序;
       d -- 设计所要实现的操作,比如 open、close、read、write 等函数;
       e -- 实现中断服务(中断不是每个设备驱动所必须的);
       f -- 编译该驱动程序到内核中,或者用 insmod 命令加载;
       g-- 测试驱动程序;

我们以点灯驱动程序作为示例:

第一步,当然是查看原理图,查看手册,找到相应寄存器;

通信指示灯为例,当GPIO3_20输出低电平时,COM灯亮。

因此,我们驱动要做的任务是:

  • a. 将gpio3_20设置为输出模式;
    • 配置GPIO_OE[32:0](0x481A_E134)的位[20]都等于0(输出模式)
      
  • b. 设置gpio3_20的状态寄存器,控制引脚输出高低电平;
    • 配置GPIO_DATEOUT[32:0](0x481A_E13C)的位[20]来控制亮灭;
      

查看am335x白皮书:AM335x Technical Reference Manual 手册 <2 Memory Map> 章节 [ARM Cortex-A8 Memory Map] 表,gpio3 物理基地址为 0x481A_E000

点击GPIO3(上图红框),查看寄存器列表:

首先将对应引脚设置为输出引脚,看输出寄存器的描述:

所以需要将将GPIO_OE寄存器的第20位写0;(输出模式)



接下来对引脚状态的设定:

拉高:GPIO3_DATAOUT |= (1<<20)
拉低:GPIO3_DATAOUT &= ~(1<<20)

这里要注意:arm体系架构是io内存,必须要映射 ioremap( ); 其作用是物理内存向虚拟内存的映射。

第二步,写代码

在字符设备模型上添加我们的具体硬件操作,关于字符设备模型的编写请移步:Linux 字符设备驱动模型。

  1. 添加全局变量:
volatile unsigned long *GPIO3_OE=NULL;       
volatile unsigned long *GPIO3_DATAOUT =NULL;
  1. 入口函数中使用ioremap()映射虚拟地址:
GPIO3_OE = ioremap(0x481AE134, sizeof(GPIO3_OE));   //ioremap:物理地址映射,返回虚拟地址
//GPIO3_DATAOUT = (volatile unsigned long *)ioremap(0x481AE13C, GPIO3_OE);
GPIO3_DATAOUT = GPIO3_OE+2;
  1. 出口函数中注销虚拟地址:
iounmap(GPIO3_OE);          //注销虚拟地址
  1. open函数中添加配置GPIO3_OE:
  *GPIO3_OE &= ~(1<<20);
  1. write函数中添加拷贝应用层数据,然后来控制GPIO3_DATAOUT:
/*copy_to_user():将数据上给用户*/
copy_from_user(&val,buf,count);  //从用户(应用层)拷贝数据                                                            
 if(val==1)                  //点灯(低电平亮)
 {  
      *GPIO3_DATAOUT &=  ~(1<<20)
 }
 else                    //灭灯
 {
     *GPIO3_DATAOUT |=  (1<<20)
 }

接下来编写测试程序:

#include 
#include 
#include 
#include 

/*
*  ledtest on
*  ledtest off
*/
int main(int argc,char **argv) //argc:参数个数,argv数组
{
      int fd1, fd2;
      int val=1;
      fd1 = open("/dev/led",O_RDWR);  //打开/dev/xxx设备节点
      if(fd1<0)                   //无法打开,返回-1
        printf("can't open%d!\n", fd1); 
       if(argc!=2)
       {
            printf("Usage:\n");
            printf("%s ",argv[0]);
            return 0;
       }

      if(strcmp(argv[1],"on")==0)   //开灯
      {
          printf("led on...\n");
          val=1;
      } 
      else                         //关灯
      {
          printf("led off...\n");
          val=0;
      }

      write(fd1, &val, 4);
      return 0;
}

你可能感兴趣的:(2. 字符设备驱动的传统写法)