(转)ok6410学习笔记(10.硬件访问之led控制1)
 
- UID
- 852665
|

(转)ok6410学习笔记(10.硬件访问之led控制1)
在对于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设备:[cpp] view plaincopy
- /*利用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里面
[cpp] view plaincopy
- 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;
- }
http://blog.csdn.net/mbh_1991/article/details/9063267 |
|
|
|
|
|