首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

ok6410学习笔记(10.硬件访问之led控制3)

ok6410学习笔记(10.硬件访问之led控制3)

这节说说linux帮我们映射好的物理地址:
dev_led.c

[cpp] view plaincopy


  • /**************************************************************************
  • 文件名:            dev_led.c
  • 日期:              2013/06/08   
  • 头文件:            led.h
  • 功能:              混杂设备驱动通过ioctl控制led
  • 环境:              Redhat企业版5  内核版本2.6.36
  • 作者:              Hao  
  • 流程:              只需注册misc_register() 会自动注册,申请,创建设备节点,是字符驱动的封装
  • ***************************************************************************/
  • #include <linux/module.h>
  • #include <linux/miscdevice.h>
  • #include <linux/types.h>
  • #include <linux/fs.h>
  • #include <linux/errno.h>
  • #include <linux/mm.h>
  • #include <linux/sched.h>
  • #include <linux/init.h>
  • #include <linux/cdev.h>
  • #include <linux/slab.h>
  • #include <linux/poll.h>
  • #include <linux/device.h>
  • #include <linux/ioport.h>
  • #include <asm/io.h>
  • #include <asm/system.h>
  • #include <asm/uaccess.h>
  • #include <asm/atomic.h>
  • #include <linux/ioctl.h>
  • #include <linux/kernel.h>
  • /*下面是内核映射好的地址的几个重要头文件*/
  • #include <mach/map.h>
  • #include <mach/regs-gpio.h>
  • #include <mach/gpio-bank-m.h>

  • #include "dev_led.h"

  • int kernel_num=1991;//用一个全局变量吧  要不不能把先写入的数据保存下来

  • #define GPIOM_CON_VA    S3C64XX_GPMCON   //这个地址是内核映射好的  不是用ioremap实现的 跟飞凌的驱动是一直的  头文件是前面那个几个带map的   
  • #define GPIOM_DAT_VA    (GPIOM_CON_VA+0x4)      
  • #define GPIOM_PUD_VA    (GPIOM_CON_VA+0x8)  

  • MODULE_AUTHOR("Hao");  
  • MODULE_LICENSE("GPL");  

  • /**************************************************************************
  • 函数名:                    ok6410_led_setup
  • 函数功能:                   ioremap映射 gpio初始化
  • 函数参数:                   无
  • 函数返回值:                  无
  • ***************************************************************************/
  • static
    void ok6410_led_setup(void)  
  • {  
  •         unsigned long temp;   
  • /****************************可以直接对地址进行操作***************************************/
  •         (*(volatile unsigned long *)GPIOM_CON_VA)&=~0xffff;   
  •         (*(volatile unsigned long *)GPIOM_CON_VA)|=0x1|(0x1<<4)|(0x1<<8)|(0x1<<12);  
  •         temp=0;  
  •         (*(volatile unsigned long*)GPIOM_DAT_VA)=temp;  //默认所有灯都亮



  • /*******************也可以用函数api进行操作  貌似这个方式更加安全***************************/
  •         /*temp&=~0xffff;
  •         temp|=0x1|(0x1<<4)|(0x1<<8)|(0x1<<12);  
  •         writel(temp, GPIOM_CON_VA);

  •         temp|=0xf;
  •         temp=0;
  •         writel(temp, GPIOM_DAT_VA);*/

  • }  


  • /**************************************************************************
  • 函数名:                     memdev_ioctl
  • 函数功能:                   ioctl实现函数  命令实习函数
  • 函数参数:                   无
  • 函数返回值:                 返回ret为正常执行   返回-EINVAL命令号不正确
  • ***************************************************************************/
  • static
    long memdev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)  
  • {  
  •     int ret=0;  
  •     int err=0;  
  •     int kernel_num=1991;  
  •     //char kernel_buf[20]="hello kernel!!!";

  •     /*先判断命令号是否正确*/
  •     if (_IOC_TYPE(cmd) != CMD_KTYPE) //获得命令的type类型是否正确
  •             return -EINVAL;  
  •         if (_IOC_NR(cmd) > LED_KCMD)    //获得命令的num类型  是否小于命令个数
  •             return -EINVAL;  

  •         /*获命令的数据传输方向   根据各自的方向判断*/
  •         if (_IOC_DIR(cmd) & _IOC_READ)  
  •              err = !access_ok(VERIFY_WRITE, (void *)arg, _IOC_SIZE(cmd));/*此函数是根据
  •              内核空间写的 是用来判断 arg应用程序传来的用户空间 是否有效的  所以对于用户空间来说是写*/
  •         else
    if (_IOC_DIR(cmd) & _IOC_WRITE)  
  •              err = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));//对于用户空间来说是读   成功返回1  失败返回0
  •         if (err)   
  •             return -EFAULT;  


  •         /*实现CMD的用法*/
  •         switch(cmd)  
  •         {  
  •             case LEDR_KCMD:   
  •                 ret=__put_user(kernel_num, (int *)arg);  //把内核中的int型数据读入用户空间   unsigned long arg就是一个地址值   kernel->arg
  •                 break;  
  •             case LEDW_KCMD:  
  •                 ret=__get_user(kernel_num, (int *)arg);   //arg->kernel_num   把用户空间的数据传递给kernel_num
  •                 printk(KERN_EMERG "WRITE_KCMD is in kernel!!!  kernel_num:%d \n",kernel_num);  
  •                 if(1==kernel_num)  
  •                     {  
  •                             writel(0x0, GPIOM_DAT_VA);//将4个led全部点亮
  •                     }  
  •                 if(0==kernel_num)  
  •                     {  
  •                             writel(0x1f, GPIOM_DAT_VA);//将4个led全部熄灭
  •                     }  
  •                 break;  
  •             default:  
  •                 return -EINVAL;  
  •                 break;  
  •         }     

  • }  


  • int mem_release(struct inode *inode, struct file *filp)  
  • {  
  •     return 0;  
  • }  

  • int mem_open(struct inode *inode,struct file *filp)  
  • {  
  •     return 0;   
  • }  

  • static
    const
    struct file_operations mem_fops =  //定义此字符设备的file_operations
  • {                       //这里是对结构体整体赋值的方式
  •     .owner = THIS_MODULE, //函数名都可以自己定义  都是函数指针
  •     .open = mem_open,  
  •     .release = mem_release,  
  •     .unlocked_ioctl=memdev_ioctl,  
  • };  

  • static
    struct miscdevice misc = {  
  •     .minor = 0,//设置为0  系统自动分配次设备号
  •     .name = "misc_led",  //我觉得这个是设备节点的名字  就是/dev路径下的文件的名字
  •     .fops = &mem_fops,  //文件操作
  • };  

  • static
    int led_init(void)  
  • {  
  •                 int ret;  
  •                 ok6410_led_setup();  
  •                 ret = misc_register(&misc);  
  •         return ret;  
  • }  

  • static
    int led_exit(void)  
  • {  
  •     misc_deregister(&misc);  
  •     return 0;  
  • }  

  • module_init(led_init);  
  • module_exit(led_exit);  


dev_led.h

[cpp] view plaincopy


  • /**************************************************************************
  • 文件名:            dev_led.h
  • 日期:              2013/06/08   
  • 头文件:            led.h
  • 功能:              混杂设备驱动的头文件   
  • 环境:              Redhat企业版5  内核版本2.6.36  
  • 作者:              Hao  
  • ***************************************************************************/
  • #ifndef _LED_H_
  • #define _LED_H_

  • #include <linux/ioctl.h>

  • #define CMD_KTYPE 'k' //定义命令幻数   也叫命令类型

  • #define LEDR_KCMD   _IOR(CMD_KTYPE,1,int)   //定义读方向的命令
  • #define LEDW_KCMD  _IOW(CMD_KTYPE,2,int)  //定义写方向的命令

  • #define LED_KCMD 2  //命令个数  后面判断命令是否有效 用的


  • #endif /* _MEMDEV_H_ */


app_led.c

[cpp] view plaincopy


  • #include <stdio.h>
  • #include <string.h>
  • #include <stdlib.h>
  • #include <unistd.h>
  • #include<sys/types.h>
  • #include<sys/stat.h>
  • #include<fcntl.h>
  • #include "dev_led.h"

  • int main(int argc, char *argv[])  
  • {  
  •     int fd=0;  
  •     printf("\n%d\n",*argv[1]);  
  •     unsigned int arg=(unsigned int)(*argv[1]-'0');  
  •     char buf[40]="WRITE_STR_KCMD is in kernel";  
  •     if(-1==(fd=open("/dev/misc_led",O_RDWR)))  //设备节点名称为memdev0
  •     {  
  •         printf("Open Dev Mem0 Error!\n");  
  •         _exit(EXIT_FAILURE);  
  •     }  
  •     printf("begin WRITE_KCMD!!!\n");  //写入一个int型arg
  •     ioctl(fd,LEDW_KCMD,&arg);  
  •     close(fd);  
  •     return 0;  
  • }  


1.首先说说linux帮映射好的文件在\arch\arm\mach-s3c64xx,里面有各种外设,寄存器等的地址。
2.在驱动中应有
#include <mach/map.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-bank-m.h>三个头文件

3.在gpio-bank-m.h文件中帮我们映射了所有gpm的端口

[cpp] view plaincopy


  • /* linux/arch/arm/plat-s3c64xx/include/plat/gpio-bank-m.h
  • *
  • * Copyright 2008 Openmoko, Inc.
  • * Copyright 2008 Simtec Electronics
  • *  Ben Dooks <ben@simtec.co.uk>
  • *  http://armlinux.simtec.co.uk/
  • *
  • * GPIO Bank M register and configuration definitions
  • *
  • * This program is free software; you can redistribute it and/or modify
  • * it under the terms of the GNU General Public License version 2 as
  • * published by the Free Software Foundation.
  • */

  • #define S3C64XX_GPMCON          (S3C64XX_GPM_BASE + 0x00)
  • #define S3C64XX_GPMDAT          (S3C64XX_GPM_BASE + 0x04)
  • #define S3C64XX_GPMPUD          (S3C64XX_GPM_BASE + 0x08)

  • #define S3C64XX_GPM_CONMASK(__gpio) (0x3 << ((__gpio) * 2))
  • #define S3C64XX_GPM_INPUT(__gpio)   (0x0 << ((__gpio) * 2))
  • #define S3C64XX_GPM_OUTPUT(__gpio)  (0x1 << ((__gpio) * 2))

  • #define S3C64XX_GPM0_HOSTIF_CS      (0x02 << 0)
  • #define S3C64XX_GPM0_EINT23      (0x03 << 0)
  • #define S3C64XX_GPM0_RESERVED1      (0x04 << 0)
  • #define S3C64XX_GPM0_DATA_CF10      (0x05 << 0)
  • #define S3C64XX_GPM0_CE_CF0      (0x06 << 0)
  • #define S3C64XX_GPM0_RESERVED2      (0x07 << 0)

  • #define S3C64XX_GPM1_HOSTIF_CS_M      (0x02 << 0)
  • #define S3C64XX_GPM1_EINT24      (0x03 << 0)
  • #define S3C64XX_GPM1_RESERVED1      (0x04 << 0)
  • #define S3C64XX_GPM1_DATA_CF11      (0x05 << 0)
  • #define S3C64XX_GPM1_CE_CF1      (0x06 << 0)
  • #define S3C64XX_GPM1_RESERVED2      (0x07 << 0)

  • #define S3C64XX_GPM2_HOSTIF_IF_CS_S      (0x02 << 0)
  • #define S3C64XX_GPM2_EINT25      (0x03 << 0)
  • #define S3C64XX_GPM2_HOSTIF_MDP_VSYNC      (0x04 << 0)
  • #define S3C64XX_GPM2_DATA_CF12      (0x05 << 0)
  • #define S3C64XX_GPM2_IORD_CF      (0x06 << 0)
  • #define S3C64XX_GPM2_RESERVED2      (0x07 << 0)

  • #define S3C64XX_GPM3_HOSTIF_WE      (0x02 << 0)
  • #define S3C64XX_GPM3_EINT26      (0x03 << 0)
  • #define S3C64XX_GPM3_RESERVED1      (0x04 << 0)
  • #define S3C64XX_GPM3_DATA_CF13      (0x05 << 0)
  • #define S3C64XX_GPM3_IOWR_CF      (0x06 << 0)
  • #define S3C64XX_GPM3_RESERVED2      (0x07 << 0)

  • #define S3C64XX_GPM4_HOSTIF_OE      (0x02 << 0)
  • #define S3C64XX_GPM4_EINT27      (0x03 << 0)
  • #define S3C64XX_GPM4_RESERVED1      (0x04 << 0)
  • #define S3C64XX_GPM4_DATA_CF14      (0x05 << 0)
  • #define S3C64XX_GPM4_IORDY_CF      (0x06 << 0)
  • #define S3C64XX_GPM4_RESERVED2      (0x07 << 0)

  • #define S3C64XX_GPM5_HOSTIF_INTR      (0x02 << 0)
  • #define S3C64XX_GPM5_CF_DATA_DIR      (0x03 << 0)
  • #define S3C64XX_GPM5_RESERVED1      (0x04 << 0)
  • #define S3C64XX_GPM5_DATA_CF15      (0x05 << 0)
  • #define S3C64XX_GPM5_RESERVED2      (0x06 << 0)
  • #define S3C64XX_GPM5_RESERVED3      (0x07 << 0)


我们只要直接拿过来用就好了,这些都是linux完成的。
4.对于2440,linux不光帮它完成了映射,还把对gpio控制的过程即对指针赋值的过程,封装成了函数。所有大家会看见好多mini2440的led驱动没有ioremap。
返回列表