/* *char.c -- the bare char module * * */ #ifndef __KERNEL__ #define __KERNEL__ #endif #ifndef MODULE #define MODULE #endif #ifndef EXPORT_SYMTAB #define EXPORT_SYMTAB #endif #include #include /* printk() */ #include #include #include #include /* kmalloc() */ #include /* everything... */ #include /* error codes */ #include /* size_t */ #include #include /* O_ACCMODE */ #include #include #include #include #include #include /* cli(), *_flags */ #include #define CHAR_IOCTL 0x1a #define I_CHAR_MMAP _IOWR(CHAR_IOCTL, 1,1024) #define debug(fmt,args...) \ printk(KERN_DEBUG "%s, %s, %d", __FILE__, __FUNCTION__, __LINE__); \ printk(KERN_DEBUG, fmt, ##args); static int perform_mmap(unsigned long); static int test_mmap(struct file*, struct vm_area_struct *); static int char_major=0; static unsigned long physical=0; static int flag=0; /* * open */ int char_open (struct inode *inode, struct file *filp) { if( inode== NULL || filp == NULL) { return -ENODEV; } /*continue only if called in read or write or both mode*/ if ( (filp->f_flags & O_ACCMODE) == O_RDWR) { return 0; /*indicate succes*/ } return -EACCES; /*returned access denied*/ } int char_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long usrptr) { int rc=0; printk(KERN_DEBUG "%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__); switch(cmd) { case I_CHAR_MMAP: rc = perform_mmap(usrptr); break; default: rc = -EACCES; break; } return rc; } /* * The different file operations */ struct file_operations char_fops = { read: NULL, write: NULL, open: char_open, ioctl: char_ioctl }; /* * Finally, the module stuff */ int init_module(void) { int result; /* * Register the major number , and accept a dynamic number */ result = register_chrdev(char_major, "simplechar", &char_fops); if (result < 0) { printk(KERN_WARNING "char: can't get major %d\n",char_major); return result; } if (char_major == 0) char_major = result; /* dynamic */ /* * allocate the devices -- we can't have them static, as the number * can be specified at load time */ printk("\ninitialization successful\n"); return 0; /* succeed */ } void cleanup_module(void) { unregister_chrdev(char_major, "simplechar"); } static int perform_mmap(unsigned long usrptr) { unsigned long virt=0; struct file_operations fops; struct file pseudofile; printk(KERN_DEBUG "%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__); physical = (unsigned long)kmalloc(4096,GFP_KERNEL); fops.mmap = test_mmap; pseudofile.f_op = &fops; pseudofile.f_mode= 0x3; for(virt = physical & PAGE_MASK; virt < physical + 4096; virt += PAGE_SIZE) mem_map_reserve(virt_to_page(virt)); printk("before do_mmap\n\n\n\n"); virt = do_mmap(&pseudofile, 0, (4096 + ~PAGE_MASK) & PAGE_MASK, PROT_READ|PROT_WRITE, MAP_SHARED, physical & PAGE_MASK); if(virt <0) { printk("error in mmap with :%d",virt); return -EACCES; } printk("after do_mmap returns with:%lx\n",virt); virt |= physical & ~PAGE_MASK; put_user( virt, (unsigned long*)usrptr); strcpy((char *) physical, "hello"); printk("virt addres:%ul and wrote:%s\n",virt, (char*)physical); return 0; } static int test_mmap(struct file *file, struct vm_area_struct *vma) { unsigned long phy; printk(KERN_DEBUG "%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__); printk("\n"); phy = vma->vm_pgoff << PAGE_SHIFT; phy = __pa(phy); printk(KERN_DEBUG "%s, %s, %d\n", __FILE__, __FUNCTION__, __LINE__); if(remap_page_range(vma->vm_start, phy, vma->vm_end- vma->vm_start, vma->vm_page_prot)) { printk("remap_page failed\n"); return -1; } vma->vm_file = NULL; return 0; }