学院栏目导航: 业界新闻 网页设计 程序设计 数据库类 网络技术 操作系统 图形图像 办公软件 考试认证 多媒体类 硬件资讯

您的位置:首页-> 资讯中心-> 操作系统-> Linux-> Linux设备驱动编程之内存与I/O操作(3)

→ Linux

  注册表
经验技巧
Linux
Win9x/ME
Win2000/NT
Windows XP
windows2003
Unix
Windows Vista

广告专栏


本类阅读TOP10
·LINUX 常见问题1000个详细解答
·Linux命令集
·国产中文操作系统OpenDesktop
·Linux无盘工作站架设实例
·利用vnc远程图形界面控制Linux
·再谈远程控制linux下
·Linux下的代理服务器设置
·安装LINUX的详细过程 1
·Linux99问(上)
·Linux下架FTP

Linux设备驱动编程之内存与I/O操作(3)

来源:天极网 发表时间:2006-10-28 【ovo.com.cn

下面的程序在启动的时候保留一段内存,然后使用ioremap将它映射到内核虚拟空间,同时又用remap_page_range映射到用户虚拟空间,这样一来,内核和用户都能访问。如果在内核虚拟地址将这段内存初始化串"abcd",那么在用户虚拟地址能够读出来:

/************mmap_ioremap.c**************/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/wrapper.h> /* for mem_map_(un)reserve */
#include <asm/io.h> /* for virt_to_phys */
#include <linux/slab.h> /* for kmalloc and kfree */

MODULE_PARM(mem_start, "i");
MODULE_PARM(mem_size, "i");

static int mem_start = 101, mem_size = 10;
static char *reserve_virt_addr;
static int major;

int mmapdrv_open(struct inode *inode, struct file *file);
int mmapdrv_release(struct inode *inode, struct file *file);
int mmapdrv_mmap(struct file *file, struct vm_area_struct *vma);

static struct file_operations mmapdrv_fops =
{
 owner: THIS_MODULE, mmap: mmapdrv_mmap, open: mmapdrv_open, release:
 mmapdrv_release,
};

int init_module(void)
{
 if ((major = register_chrdev(0, "mmapdrv", &mmapdrv_fops)) < 0)
 {
  printk("mmapdrv: unable to register character device\n");
  return ( - EIO);
 }
 printk("mmap device major = %d\n", major);

 printk("high memory physical address 0x%ldM\n", virt_to_phys(high_memory) /
1024 / 1024);

 reserve_virt_addr = ioremap(mem_start *1024 * 1024, mem_size *1024 * 1024);
 printk("reserve_virt_addr = 0x%lx\n", (unsigned long)reserve_virt_addr);
 if (reserve_virt_addr)
 {
  int i;
  for (i = 0; i < mem_size *1024 * 1024; i += 4)
  {
   reserve_virt_addr[i] = 'a';
   reserve_virt_addr[i + 1] = 'b';
   reserve_virt_addr[i + 2] = 'c';
   reserve_virt_addr[i + 3] = 'd';
  }
 }
 else
 {
  unregister_chrdev(major, "mmapdrv");
  return - ENODEV;
 }
 return 0;
}

/* remove the module */
void cleanup_module(void)
{
 if (reserve_virt_addr)
  iounmap(reserve_virt_addr);

 unregister_chrdev(major, "mmapdrv");
 return ;
}

int mmapdrv_open(struct inode *inode, struct file *file)
{
 MOD_INC_USE_COUNT;
 return (0);
}

int mmapdrv_release(struct inode *inode, struct file *file)
{
 MOD_DEC_USE_COUNT;
 return (0);
}

int mmapdrv_mmap(struct file *file, struct vm_area_struct *vma)
{
 unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
 unsigned long size = vma->vm_end - vma->vm_start;

 if (size > mem_size *1024 * 1024)
 {
  printk("size too big\n");
  return ( - ENXIO);
 }

 offset = offset + mem_start * 1024 * 1024;

 /* we do not want to have this area swapped out, lock it */
 vma->vm_flags |= VM_LOCKED;
 if (remap_page_range(vma, vma->vm_start, offset, size, PAGE_SHARED))
 {
  printk("remap page range failed\n");
  return - ENXIO;
 }
 return (0);
}

  remap_page_range函数的功能是构造用于映射一段物理地址的新页表,实现了内核空间与用户空间的映射,其原型如下:

int remap_page_range(vma_area_struct *vma, unsigned long from, unsigned long to, unsigned long size, pgprot_tprot);

  使用mmap最典型的例子是显示卡的驱动,将显存空间直接从内核映射到用户空间将可提供显存的读写效率。

※相关文章:

※相关软件: