这节说说linux帮我们映射好的物理地址:
dev_led.c
/************************************************************************** 文件名: 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 日期: 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_ */
#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; }
2.在驱动中应有
#include <mach/map.h>
#include <mach/regs-gpio.h>
#include <mach/gpio-bank-m.h>三个头文件
3.在gpio-bank-m.h文件中帮我们映射了所有gpm的端口
/* linux/arch/arm/plat-s3c64xx/include/plat/gpio-bank-m.h * * Copyright 2008 Openmoko, Inc. * Copyright 2008 Simtec Electronics * Ben Dooks <[email protected]> * 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)
4.对于2440,linux不光帮它完成了映射,还把对gpio控制的过程即对指针赋值的过程,封装成了函数。所有大家会看见好多mini2440的led驱动没有ioremap。