在对于led控制驱动方式上,我看见了6种方式:
在用户空间角度上说有两种:
1.mmap驱动自己写的设备,来把物理地址映射到用户空间。
2.mmap驱动linux内核提供的mem设备,来把物理地址映射到用户空间。
在内核空间角度上说有四种:
1.ioremap的字符设备驱动中或者在混杂设备驱动中的应用,把物理地址映射到内核空间。
2.在不管是国嵌的移植好的内核,还是飞凌移植好的内核中,在/driver/char中都有飞凌写好的驱动,直接调用这个第三方驱动。
3.在linux内核中其实系统早就把地址映射到了内核空间,我们的ioremap只是重新映射了一边,所有我们也可以直接操作这些地址,linux有对S3c6410和S3c2440的映射,还把对2440的gpio操作方法进行了封装。
4.I/O内存静态映射,是在宋保华linux设备驱动中的11.5章的 没有尝试过,不是很了解。
mmap自己的驱动见前面 mmap控制led的那节
mem设备:
/*利用linux自身的设备驱动 mem设备进行 用户空间和物理地址的映射*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#define uint unsigned int
#define uchar unsigned char
void delay(volatile unsigned int time)
{
volatile unsigned int x,y;
for(x=0;x<2000;x++)
for(y=0;y<time;y++);
}
int main()
{
int fd;
int i;
volatile unsigned char *map;
volatile unsigned int *GPMCON;
volatile unsigned int *GPMDAT;
volatile unsigned int *GPMPUD;
char buf[100];
if(-1==(fd=open ("/dev/mem", O_RDWR))) //要利用mem设备
{
printf("open dev0 error\n");
_exit(EXIT_FAILURE);
}
/*这个过程是在mem驱动中完成的 map传递的物理地址是通过vma->vm_pgoff即偏移量进行传递的*/
/*但是这里PAGE_SHIFT的问题不知道解决没有 不行就用0x7f008000地址进行传递吧*/
map = (volatile unsigned char*)mmap(NULL,1024*5, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0x7f008000);
if(map == NULL)
{
printf("mmap err!\n");
return 0;
}
/*GPMCON=(volatile unsigned int*)(map+0x0);
GPMDAT=(volatile unsigned int*)(map+0x04);
GPMPUD=(volatile unsigned int*)(map+0x08);*/
GPMCON=(volatile unsigned int*)(map+0x820);
GPMDAT=(volatile unsigned int*)(map+0x824);
GPMPUD=(volatile unsigned int*)(map+0x828);
*GPMCON&=~0xffff;
*GPMCON|=0x1|(0x1<<4)|(0x1<<8)|(0x1<<12);
*GPMDAT|=0xf;
printf("init is finishing!\n");
while(1)
{
for(i=0;i<4;i++)
{
*GPMDAT=~(1<<i);
delay(1500);
}
}
munmap((char*)map,1024*5);
close(fd);
}
注意:1.物理地址的参数传递是通过vma->vm_pgoff进行的
2.貌似还存在PAGE_SHIFT的问题 我试了0x7f008820地址 不行。
此应用程序的驱动在\drivers\char\mem.c里面
此应用程序的驱动在\drivers\char\mem.c里面
static ssize_t write_mem(struct file *file, const char __user *buf,
size_t count, loff_t *ppos)
{
unsigned long p = *ppos;
ssize_t written, sz;
unsigned long copied;
void *ptr;
if (!valid_phys_addr_range(p, count))
return -EFAULT;
written = 0;
#ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED
/* we don't have page 0 mapped on sparc and m68k.. */
if (p < PAGE_SIZE) {
sz = size_inside_page(p, count);
/* Hmm. Do something? */
buf += sz;
p += sz;
count -= sz;
written += sz;
}
#endif
while (count > 0) {
sz = size_inside_page(p, count);
if (!range_is_allowed(p >> PAGE_SHIFT, sz))
return -EPERM;
/*
* On ia64 if a page has been mapped somewhere as uncached, then
* it must also be accessed uncached by the kernel or data
* corruption may occur.
*/
ptr = xlate_dev_mem_ptr(p);
if (!ptr) {
if (written)
break;
return -EFAULT;
}
copied = copy_from_user(ptr, buf, sz);
unxlate_dev_mem_ptr(p, ptr);
if (copied) {
written += sz - copied;
if (written)
break;
return -EFAULT;
}
buf += sz;
p += sz;
count -= sz;
written += sz;
}
*ppos += written;
return written;
}