title: How to implement memory map feature in device drivers in linux?
body: <p>I am trying to learn device drivers and I started with char device driver. I implemented a small program which is able to read/write from/to kernel buffer. Further, I tried to implement memory mapping and this is not working properly. When I am trying to read through a simple process by mapping my kernel module, it is giving me garbage value. Can any one help with this?</p>
  
  <pre><code>#include&lt;linux/init.h&gt;
  #include&lt;linux/module.h&gt;
  #include&lt;linux/kernel.h&gt; //printk()
  #include&lt;linux/errno.h&gt;
  #include&lt;linux/types.h&gt; 
  #include&lt;linux/proc_fs.h&gt;
  #include&lt;asm/uaccess.h&gt; //copy_from,to_user
  
  #include&lt;linux/mm.h&gt; //remap_pfn_range
  //#include&lt;linux/mman.h&gt; //private_mapping_ok
  #define BUFF_SIZE 128
  #define DEV_NAME "MyDevice"
  MODULE_LICENSE("GPL");
  
  //Method declarations
  int mod_open(struct inode *,struct file *);
  int mod_release(struct inode *,struct file *);
  ssize_t mod_read(struct file *,char *,size_t ,loff_t *);
  ssize_t mod_write(struct file *,char *,size_t ,loff_t *);
  int mod_mmap(struct file *, struct vm_area_struct *);
  
  
  void mod_exit(void);
  int mod_init(void);
  
  //Structure that declares the usual file access functions
  
  struct file_operations mod_fops = {
      read: mod_read,
      write: mod_write,
      open: mod_open,
      release: mod_release,
      mmap: mod_mmap
  };
  
  static const struct vm_operations_struct mod_mem_ops = {
  
  };
  
  
  module_init(mod_init);
  module_exit(mod_exit);
  
  char *read_buf;
  char *write_buf;
  
  static int Major;
  //static int Device_Open = 0;
  int buffsize = 0;
  
  int mod_init(void)
  {
      Major = register_chrdev(0,DEV_NAME,&amp;mod_fops);
      if(Major &lt; 0)
      {
          printk(KERN_ALERT "Can not register %s. No major number alloted",DEV_NAME);
          return Major;
      }
      //allocate memory to buffers
      read_buf = kmalloc(BUFF_SIZE, GFP_KERNEL);
      write_buf = kmalloc(BUFF_SIZE, GFP_KERNEL);
  
      if(!read_buf || !write_buf)
      {
          mod_exit();
          return -ENOMEM;
      }
      //reset buffers
      memset(read_buf,0, BUFF_SIZE);
      memset(write_buf,0, BUFF_SIZE);
      printk(KERN_INFO "I was assigned major number %d. To talk to\n", Major);
          printk(KERN_INFO "the driver, create a dev file with\n");
          printk(KERN_INFO "'mknod /dev/%s c %d 0'.\n",DEV_NAME, Major);
          printk(KERN_INFO "Try various minor numbers. Try to cat and echo to\n");
          printk(KERN_INFO "the device file.\n");
          printk(KERN_INFO "Remove the device file and module when done.\n");
      return 0;
  
  
  }
  
  void mod_exit(void)
  {
      unregister_chrdev(Major,"memory");
      if(read_buf) kfree(read_buf);
      if(write_buf) kfree(write_buf);
      printk(KERN_INFO "removing module\n");
  }
  
  int mod_mmap(struct file *filp, struct vm_area_struct *vma)
  {
      size_t size = vma-&gt;vm_end - vma-&gt;vm_start;
      vma-&gt;vm_ops = &amp;mod_mem_ops;
  
      /* Remap-pfn-range will mark the range VM_IO */
      if (remap_pfn_range(vma, vma-&gt;vm_start, vma-&gt;vm_pgoff, size, vma-&gt;vm_page_prot)) {
          return -EAGAIN;
      }
      printk(KERN_INFO "VMA Open. Virt_addr: %lx, phy_addr: %lx\n",vma-&gt;vm_start, vma-&gt;vm_pgoff&lt;&lt;PAGE_SHIFT);
  
  
  
      return 0;
  }
  
  
  ssize_t mod_read(struct file *filp, char *buf, size_t len, loff_t *f_pos)
  {
      ssize_t bytes;
      if(buffsize &lt; len)
          bytes = buffsize;
      else
          bytes = len;
      printk(KERN_INFO "Buffer size availabe: %d\n", buffsize);
      printk(KERN_INFO "VMA Open. read buffer initial: %lx\n",read_buf);
  
      if(bytes == 0)
          return 0;
      int retval = copy_to_user(buf,read_buf,bytes);
      if(retval)
      {
          printk(KERN_INFO "copy_to_user fail");
          return -EFAULT;
      }
      else
      {
          printk(KERN_INFO "copy_to_user succeeded\n");
          buffsize -= bytes;
          return bytes;
      }
  }
  
  ssize_t mod_write( struct file *filp,char *buf, size_t len, loff_t *f_pos)
  {
      memset(read_buf,0,BUFF_SIZE);
      memset(write_buf,0,BUFF_SIZE);
      if(len &gt; BUFF_SIZE)
      {
          printk(KERN_ALERT "Buffer not available. Writing only %d bytes.\n",BUFF_SIZE);
          len = BUFF_SIZE;
      }
      printk(KERN_INFO "User space msg size: %d\n",len);
      int retval = copy_from_user(read_buf,buf,len);
      printk(KERN_INFO "read %d bytes as: %s\n", retval,read_buf);
  
  //  memcpy(write_buf,read_buf,len);
  //  printk(KERN_INFO "written: %s\n", write_buf);
      buffsize = len;
      return len;
  }
  
  int mod_open(struct inode *inode, struct file *filp){return 0;}
  int mod_release(struct inode *inode, struct file *filp) {return 0;}
  </code></pre>
  
  <p>The program which is trying to access this device driver:</p>
  
  <pre><code>#include&lt;stdio.h&gt;
  #include&lt;sys/fcntl.h&gt;
  #include&lt;stdlib.h&gt;
  #include&lt;errno.h&gt;
  #include&lt;string.h&gt;
  #include&lt;sys/types.h&gt;
  #include&lt;sys/mman.h&gt;
  int main(int argc,char *argv[])
  {
      int fd,n,len;
      char *buff;
      if(argc != 3)
      {
          printf("Too few arguments.\n");
          exit(EXIT_FAILURE);
      }
      buff = (char *)malloc(128);
      if(strcmp(argv[1],"read")==0)
      {
          if(-1 == (fd = open("/dev/MyDevice",O_RDONLY)))
          {
              printf("Device open fail. Error: %s",strerror(errno));
              exit(EXIT_FAILURE);
          }
          memset(buff,0,128);
          if(-1 == (buff = mmap(0,128,PROT_READ,MAP_SHARED | MAP_NORESERVE,fd,0)))
          {
              printf("Mapping failed. Error: %s\n", strerror(errno));
              exit(EXIT_FAILURE);
          }
      /*  if(-1 == (n = read(fd,buff,128)))
          {
              printf("Device read fail. Error: %s",strerror(errno));
              exit(EXIT_FAILURE);
          }
          */
  
          printf("Read from device:\n%s\n",buff);
          close(fd);
  
      }
      else if(strcmp(argv[1],"write")==0)
      {
          len = strlen(argv[2]);
          if(-1 == (fd = open("/dev/MyDevice",O_WRONLY)))
          {
              printf("Device open fail. Error: %s",strerror(errno));
              exit(EXIT_FAILURE);
          }
          if(-1 == (n = write(fd,argv[2],len)))
          {
              printf("Device write fail. Error: %s",strerror(errno));
              exit(EXIT_FAILURE);
          }
          printf("Written %d bytes successfully.\n",n);
          close(fd);
  
      }
      else
      {
          printf("Invalid argument..\n");
          exit(EXIT_FAILURE);
      }
      return 0;
  }
  </code></pre>