http://topic.youkuaiyun.com/u/20070208/19/51C3C55C-8A56-44CD-AA2F-F789587BC9A4.html
是的,终于明白并且实验成功了,在用户空间不能直接访问的,还好开发板提供了一个内存映射的字符设备,我映射到用户空间了.不过将来要做更多事情的话,还得恶补一下Linux下的驱动编写.
以下分享一下通过内存映射访问字符设备的方法:
这段程序是在网上下载的,但是编译时有点问题,我修改过之后就可以运行了.
//以下是gpio_test.c文件,在RedHat9上编译通过,在405EP的taihu开发板运行通过,点亮LED.
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <unistd.h>
void *mapDirectIoRegister(unsigned long addr, size_t length);
int iounmap(volatile void *start, size_t length);
void sysLedSet(unsigned char value);
#define MAP_SIZE 4096UL
#define MAP_MASK (MAP_SIZE - 1) //4095
#define HCU3_LED_REGISTER 0xEF600700
volatile unsigned long *ledRegister;
#define __PPC4xx__
#ifdef __PPC4xx__
inline void out_32(volatile unsigned long *addr, unsigned val)
{
__asm__ __volatile__( "stw%U0%X0 %1,%0; eieio " : "=m " (*addr) : "r "
(val));
}
#else
extern inline void out_32(volatile unsigned long *addr, unsigned val)
{ * which shows you how to use PPC assembler code to ensure correct IO
ordering.
*addr = val & 0xff;
}
#endif
void *mapDirectIoRegister(unsigned long addr, size_t length)
{
void *map_base, * virtAddr;
off_t target = ((unsigned int) addr) & ~MAP_MASK; //off_t就是int类型; MAP_MASK=4095UL=> ~MAP_MASK=0xFFFFF000UL
int fd;
if ((fd = open( "/dev/mem ", O_RDWR | O_SYNC)) == -1) //打开内存文件(驱动)
{
printf( "/dev/mem could not be opened./n ");
exit(1);
}
// Map one page
map_base = mmap((void *)target, length, PROT_READ | PROT_WRITE, MAP_SHARED,fd, target);
if(map_base == (void *) -1)
{
printf( "Memory map failed for address 0x%lx/n ", addr);
return map_base;
}
virtAddr = (void *) ((unsigned long)map_base + ( (unsigned long)addr & MAP_MASK)); //基地址+偏移量
printf( "Memory map 0x%lx -> %p offset 0x%lx virtual %p/n ", addr, map_base,addr & MAP_MASK, virtAddr);
//输出:Memory map 0xef600700 -> 0x30001000 offset 0x700 virtual 0x30001700
return virtAddr;
}
int iounmap(volatile void *start, size_t length)
{
unsigned long ofs_addr;
ofs_addr = (unsigned long)start & (getpagesize()-1);
return munmap((void*)start-ofs_addr, length+ofs_addr);
}
void sysLedSet(unsigned char value)
{
*ledRegister = (( unsigned long ) ~value < <23) ;
out_32(ledRegister, ( unsigned long ) ~value < <23 );
}
int main (int argc, char *argv[])
{
unsigned char j;
printf( "%s: %s %s/n ", __FUNCTION__, __DATE__, __TIME__ ); //输出main: Feb 9 2007 18:13:55
ledRegister = (unsigned long *)mapDirectIoRegister(HCU3_LED_REGISTER, MAP_SIZE); //MAP_SIZE=4096UL
//上面一行输出:Memory map 0xef600700 -> 0x30001000 offset 0x700 virtual 0x30001700
//ledRegister[1] = 0x7ffe0000;
*ledRegister = 0x7fffffff;
//out_32(ledRegister, 0x7fffffff );
sleep(1);
*ledRegister = 0x0;
//out_32(ledRegister, 0x0 );
iounmap((volatile void *)HCU3_LED_REGISTER, MAP_SIZE);
printf( "/n%s:done/n ", __FUNCTION__); //输出:main:done
return 0;
}
以下是dev_gpio.c
#include "dev_gpio.h "
static ioport_device_t gpio_devices[256];
int __init gpio_init(void)
{
int i;
register_chrdev(IOPORT_MAJOR, "gpiotest ", &gpio_ctl_fops);
return 0;
}
__initcall(gpio_init);
int gpio_open(struct inode *inode, struct file *filp)
{
int minor;
minor = MINOR(inode-> i_rdev);
*(volatile unsigned short*)(0xfff00000+0x962)&=~0x0080;
*(volatile unsigned short*)(0xfff00000+0x960)|=0x0080;
gpio_devices[minor]++;
return 0;
}
//__ioremap
int gpio_release(struct inode *inode, struct file *filp)
{
int minor;
minor = MINOR(inode-> i_rdev);
if (gpio_devices[minor])
gpio_devices[minor]--;
*(volatile unsigned short*)(0xfff00000+0x960)&=~0x0080;
*(volatile unsigned short*)(0xfff00000+0x962)|=0x0080;
return 0;
}
int gpio_ctl_ioctl(struct inode *inode,struct file *flip,unsigned int command,unsigned long arg)
{
int err = 0;
int minor = MINOR(inode-> i_rdev);
switch (command)
{
case IOWRITE:
*(volatile unsigned short*)(0xfff00000+0x966)&=~0x0080;
return 0;
case IOCLEAR:
*(volatile unsigned short*)(0xfff00000+0x966)|=0x0080;
return 0;
default:
err = -EINVAL;
}
return err;
}
//以下是dev_gpio.h
#include <linux/fs.h>
#include <linux/iobuf.h>
#include <linux/major.h>
#include <linux/blkdev.h>
#include <linux/capability.h>
#include <linux/smp_lock.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <linux/vmalloc.h>
#define dprintk(x...)
#define IOPORT_MAJOR 220
typedef char ioport_device_t;
int gpio_open(struct inode *, struct file *);
int gpio_release(struct inode *, struct file *);
int gpio_ctl_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
static struct file_operations gpio_fops =
{
open: gpio_open,
release: gpio_release,
};
static struct file_operations gpio_ctl_fops =
{
ioctl: gpio_ctl_ioctl,
open: gpio_open,
release: gpio_release,
};