在对于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; }