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()结构
- int remap_page_range(struct vm_area_struct *vma,
- unsigned long from,
- unsigned long phys_addr,
- unsigned long size,
- pgprot_t prot)
remap_fpn_range()结构
- int remap_pfn_range(struct vm_area_struct *vma,
- unsigned long addr,
- unsigned long pfn,
- unsigned long size,
- pgprot_t prot)
书中实例代码
- result=remap_pfn_range(vma,
- vma->vm_start,
- VIDEO_TEXT_ADDR,
- VIDEO_TEXT_SIZE,
- vma->vm_page_prot);
修改后实例代码
- result=remap_pfn_range(vma,
- vma->vm_start,
- VIDEO_TEXT_ADDR>>PAGE_SHIFT,
- VIDEO_TEXT_SIZE,
- 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、驱动模块源文件
- #include <linux/init.h>
- #include <linux/kernel.h>
- #include <linux/module.h>
- #include <linux/fs.h>
- #include <linux/types.h>
- #include <linux/errno.h>
- #include <linux/fcntl.h>
- #include <linux/vmalloc.h>
- #include <asm/uaccess.h>
- #include <asm/io.h>
- #include <asm/page.h>
- #include <linux/mm.h>
- #define MMAPIOMEM_DEV_NAME "mmapiomem"
- #define MMAPIOMEM_DEV_MAJOR 240
- #define VIDEO_TEXT_ADDR 0xb8000
- #define VIDEO_TEXT_SIZE 0x8000
- int mmapiomem_open(struct inode *inode,struct file *filp)
- {
- return 0;
- }
- int mmapiomem_release(struct inode *inode,struct file *filp)
- {
- return 0;
- }
- int mmapiomem_mmap(struct file *filp,struct vm_area_struct *vma)
- {
- int result;
-
- vma->vm_flags|=VM_RESERVED;
- vma->vm_flags|=VM_IO;
-
- result=remap_pfn_range(vma,
- vma->vm_start,
- VIDEO_TEXT_ADDR>>PAGE_SHIFT,
- VIDEO_TEXT_SIZE,
- vma->vm_page_prot);
-
- if(result){
- return -EAGAIN;
- }
-
- return 0;
- }
- struct file_operations mmapiomem_fops={
- .owner=THIS_MODULE,
- .open=mmapiomem_open,
- .release=mmapiomem_release,
- .mmap=mmapiomem_mmap,
- };
- int mmapiomem_init(void)
- {
- int result;
-
- result=register_chrdev(MMAPIOMEM_DEV_MAJOR,
- MMAPIOMEM_DEV_NAME,
- &mmapiomem_fops);
- if(result<0){
- return result;
- }
-
- return 0;
- }
- void mmapiomem_exit(void)
- {
- unregister_chrdev(MMAPIOMEM_DEV_MAJOR,MMAPIOMEM_DEV_NAME);
- }
- module_init(mmapiomem_init);
- module_exit(mmapiomem_exit);
- MODULE_LICENSE("Dual BSD/GPL");
4、Makefile
- obj-m += mmapiomem_dev.o
- CURRENT_PATH := $(shell pwd)
- LINUX_KERNEL := $(shell uname -r)
- LINUX_KERNEL_PATH := /usr/src/linux-$(LINUX_KERNEL)
- all:
- make -C $(LINUX_KERNEL_PATH) M=$(CURRENT_PATH) modules
- clean:
- #make -C $(LINUX_KERNEL_PAHT) M=$(CURRENT_PATH) clean
- rm *.mod.*
- rm *.order
- rm *.o
- rm *.symvers
5、应用程序源文件
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <sys/ioctl.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <sys/mman.h>
- #include <linux/vt.h>
- #define DEVICE_FILENAME "/dev/mmapiomem"
- #define MMAP_SIZE 0x8000
- int main()
- {
- int ttydev;
-
- int dev;
- int loop,loop2;
- char *ptrdata;
-
- ttydev=open("/dev/tty0",O_RDWR|O_NDELAY);
-
- if(ttydev>=0){
- printf("ACT %d\n",ioctl(ttydev,VT_ACTIVATE,2));
- printf("ACT %d\n",ioctl(ttydev,VT_ACTIVATE,1));
- close(ttydev);
- }
-
- dev=open(DEVICE_FILENAME,O_RDWR|O_NDELAY);
-
- /*printf("1)here after dev open\n");*/
-
- if(dev>=0){
- /*printf("2)open the dev success\n");*/
- ptrdata=(char*)mmap(0,
- MMAP_SIZE,
- PROT_READ|PROT_WRITE,
- MAP_SHARED,
- dev,
- 0);
- /*printf("3)printf ptrdata [%x]\n",ptrdata);*/
- if(ptrdata!=NULL){
- for(loop2=0;loop2<=5;loop2++){
- for(loop=0;loop<80*25;loop++){
- ptrdata[loop*2]=loop2+'0';
- }
- ptrdata[80*25*2-4]='o';
- ptrdata[80*25*2-2]='k';
- /*printf("4)show the nums on screen\n");*/
- sleep(1);
- }
- munmap(ptrdata,MMAP_SIZE);
- }
- /*printf("5)show the nums over\n");*/
- close(dev);
- /*printf("6)here close the dev\n");*/
-
- }
- /*printf("7)the end of process\n");*/
- return 0;
- }
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)控制台操作
- ~/video_mmap# mknod /dev/mmapiomem c 240 0 //创建设备文件
- ~/video_mmap# make //编译驱动模块
- ~/video_mmap# make clean //清理不用到的生成文件
- ~/video_mmap# gcc mmapiomem_app.c -o mmapiomem_app //编译应用程序
- ~/video_mmap# insmod mmapiomem_dev.ko //插入驱动模块
- ~/video_mmap# ./mmapiomem_app //运行app及结果
4)运行效果截图
在控制台整个屏幕以1s为单位显示“0”到“4”,右下角显“ok”
7、移除模块及设备文件
- ~/video_mmap# rm /dev/mmapiomem //删除设备文件
- ~/video_mmap# rmmod mmapiomem_dev.ko //移除驱动模块
阅读(1947) | 评论(0) | 转发(0) |