Chinaunix首页 | 论坛 | 博客
  • 博客访问: 2764715
  • 博文数量: 505
  • 博客积分: 1552
  • 博客等级: 上尉
  • 技术积分: 2514
  • 用 户 组: 普通用户
  • 注册时间: 2007-09-23 18:24
文章分类

全部博文(505)

文章存档

2019年(12)

2018年(15)

2017年(1)

2016年(17)

2015年(14)

2014年(93)

2013年(233)

2012年(108)

2011年(1)

2009年(11)

分类:

2012-05-09 15:59:57

2012年3月25日  Sunday
 
1、内核版本号2.6.33.20
 
2、remap_pfn_range()在VIDEO Text_Video_buffer上应用的实例
(pfn=page frame number页帧号)
 
1)书中的例子在版本2.6.33.20上是不能编译通过的
书中的实例都是基于2.6.4版本内核编写的,前面的例子按书上来都没问题,这个例子要改动下才能在2.6.33.20版本的内核上通过编译和运行。
2)remap_pfn_range()与remap_page_range()
大概在2.6.9之前(不是很确定)使用remap_page_range()完成物理地址到虚拟内存地址的映射,之后替换为了remap_pfn_range()
 
remap_page_range()结构

  1. int remap_page_range(struct vm_area_struct *vma,
  2.             unsigned long from,
  3.             unsigned long phys_addr,
  4.             unsigned long size,
  5.             pgprot_t prot)

remap_fpn_range()结构

  1. int remap_pfn_range(struct vm_area_struct *vma,
  2.             unsigned long addr,
  3.             unsigned long pfn,
  4.             unsigned long size,
  5.             pgprot_t prot)

书中实例代码

  1. result=remap_pfn_range(vma,
  2.             vma->vm_start,
  3.             VIDEO_TEXT_ADDR,
  4.             VIDEO_TEXT_SIZE,
  5.             vma->vm_page_prot);

修改后实例代码

  1. result=remap_pfn_range(vma,
  2.             vma->vm_start,
  3.             VIDEO_TEXT_ADDR>>PAGE_SHIFT,
  4.             VIDEO_TEXT_SIZE,
  5.             vma->vm_page_prot);

函数中有两个参数发生变化phys_addr-->pfn、from-->addr
linux内存映射结构还搞不明白,各种的页,各种的不清楚!
pfn页帧号,页帧号=具体地址>>PAGE_SHIFT,对于PAGE_SHIFT=12就是右移3个十六进制位
PAGE_SHIFT一般根据page而定,PAGE_SHIFT=12,page=4k,即page大小=2的PAGE_SHIFT次方
 
大概理解是这样的,具体地址=页号+偏移量,PAGE_SHIFT就是一个偏移量
谁要是明白麻烦提点下!
 
from和addr也不是很明白,之间的关系与区别没搞明白,一层一层的看源码还是没理解
3、驱动模块源文件

点击(此处)折叠或打开

  1. #include <linux/init.h>
  2. #include <linux/kernel.h>
  3. #include <linux/module.h>

  4. #include <linux/fs.h>
  5. #include <linux/types.h>
  6. #include <linux/errno.h>
  7. #include <linux/fcntl.h>

  8. #include <linux/vmalloc.h>
  9. #include <asm/uaccess.h>
  10. #include <asm/io.h>

  11. #include <asm/page.h>
  12. #include <linux/mm.h>

  13. #define MMAPIOMEM_DEV_NAME "mmapiomem"
  14. #define MMAPIOMEM_DEV_MAJOR 240

  15. #define VIDEO_TEXT_ADDR 0xb8000
  16. #define VIDEO_TEXT_SIZE 0x8000

  17. int mmapiomem_open(struct inode *inode,struct file *filp)
  18. {
  19.     return 0;
  20. }

  21. int mmapiomem_release(struct inode *inode,struct file *filp)
  22. {
  23.     return 0;
  24. }

  25. int mmapiomem_mmap(struct file *filp,struct vm_area_struct *vma)
  26. {
  27.     int result;
  28.     
  29.     vma->vm_flags|=VM_RESERVED;
  30.     vma->vm_flags|=VM_IO;
  31.     
  32.     result=remap_pfn_range(vma,
  33.             vma->vm_start,
  34.             VIDEO_TEXT_ADDR>>PAGE_SHIFT,
  35.             VIDEO_TEXT_SIZE,
  36.             vma->vm_page_prot);
  37.     
  38.     if(result){
  39.         return -EAGAIN;
  40.     }
  41.     
  42.     return 0;
  43. }

  44. struct file_operations mmapiomem_fops={
  45.     .owner=THIS_MODULE,
  46.     .open=mmapiomem_open,
  47.     .release=mmapiomem_release,
  48.     .mmap=mmapiomem_mmap,
  49. };

  50. int mmapiomem_init(void)
  51. {
  52.     int result;
  53.     
  54.     result=register_chrdev(MMAPIOMEM_DEV_MAJOR,
  55.             MMAPIOMEM_DEV_NAME,
  56.             &mmapiomem_fops);
  57.     if(result<0){
  58.         return result;
  59.     }
  60.     
  61.     return 0;
  62. }

  63. void mmapiomem_exit(void)
  64. {
  65.     unregister_chrdev(MMAPIOMEM_DEV_MAJOR,MMAPIOMEM_DEV_NAME);
  66. }

  67. module_init(mmapiomem_init);
  68. module_exit(mmapiomem_exit);

  69. MODULE_LICENSE("Dual BSD/GPL");

4、Makefile

点击(此处)折叠或打开

  1. obj-m += mmapiomem_dev.o

  2. CURRENT_PATH := $(shell pwd)

  3. LINUX_KERNEL := $(shell uname -r)

  4. LINUX_KERNEL_PATH := /usr/src/linux-$(LINUX_KERNEL)

  5. all:
  6.     make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
  7. clean:
  8.     #make -C $(LINUX_KERNEL_PAHT) M=$(CURRENT_PATH) clean
  9.     rm *.mod.*
  10.     rm *.order
  11.     rm *.o
  12.     rm *.symvers

5、应用程序源文件

点击(此处)折叠或打开

  1. #include <stdio.h>
  2. #include <sys/types.h>
  3. #include <sys/stat.h>
  4. #include <sys/ioctl.h>
  5. #include <fcntl.h>
  6. #include <unistd.h>
  7. #include <sys/mman.h>
  8. #include <linux/vt.h>

  9. #define DEVICE_FILENAME "/dev/mmapiomem"

  10. #define MMAP_SIZE 0x8000

  11. int main()
  12. {
  13.     int ttydev;
  14.     
  15.     int dev;
  16.     int loop,loop2;
  17.     char *ptrdata;
  18.     
  19.     ttydev=open("/dev/tty0",O_RDWR|O_NDELAY);
  20.     
  21.     if(ttydev>=0){
  22.         printf("ACT %d\n",ioctl(ttydev,VT_ACTIVATE,2));
  23.         printf("ACT %d\n",ioctl(ttydev,VT_ACTIVATE,1));
  24.         close(ttydev);
  25.     }
  26.     
  27.     dev=open(DEVICE_FILENAME,O_RDWR|O_NDELAY);
  28.     
  29.     /*printf("1)here after dev open\n");*/
  30.     
  31.     if(dev>=0){
  32.         /*printf("2)open the dev success\n");*/
  33.         ptrdata=(char*)mmap(0,
  34.                 MMAP_SIZE,
  35.                 PROT_READ|PROT_WRITE,
  36.                 MAP_SHARED,
  37.                 dev,
  38.                 0);
  39.         /*printf("3)printf ptrdata [%x]\n",ptrdata);*/
  40.         if(ptrdata!=NULL){
  41.             for(loop2=0;loop2<=5;loop2++){
  42.                 for(loop=0;loop<80*25;loop++){
  43.                     ptrdata[loop*2]=loop2+'0';
  44.                 }
  45.                 ptrdata[80*25*2-4]='o';
  46.                 ptrdata[80*25*2-2]='k';
  47.                 /*printf("4)show the nums on screen\n");*/
  48.                 sleep(1);
  49.             }
  50.             munmap(ptrdata,MMAP_SIZE);
  51.         }
  52.         /*printf("5)show the nums over\n");*/
  53.         close(dev);
  54.         /*printf("6)here close the dev\n");*/
  55.         
  56.     }
  57.     /*printf("7)the end of process\n");*/
  58.     return 0;
  59. }

6、实施方法及运行结果
实施过程比较复杂
1)实例是在Text_buffer模式下实现的,桌面linux一般情况下默认是Graph_buffer模式,即使打开控制台,其控制台也已被从新设定,即已不是标准模式,最好是用Text_buffer模式实施实例
2)ubuntu开机默认直接进入Text模式控制台,
①编辑/etc/default/grub文件,在其末行加入GRUB_CMDLINE_LINUX_DEFAULT="quiet text"
②终端执行命令update-grub2更新grub
③reboot重启电脑
3)控制台操作

  1. ~/video_mmap# mknod /dev/mmapiomem c 240 0 //创建设备文件
  2. ~/video_mmap# make //编译驱动模块
  3. ~/video_mmap# make clean //清理不用到的生成文件
  4. ~/video_mmap# gcc mmapiomem_app.c -o mmapiomem_app //编译应用程序
  5. ~/video_mmap# insmod mmapiomem_dev.ko //插入驱动模块
  6. ~/video_mmap# ./mmapiomem_app //运行app及结果

4)运行效果截图
 
在控制台整个屏幕以1s为单位显示“0”到“4”,右下角显“ok”
 
 
7、移除模块及设备文件

  1. ~/video_mmap# rm /dev/mmapiomem //删除设备文件
  2. ~/video_mmap# rmmod mmapiomem_dev.ko //移除驱动模块

阅读(1947) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~