//------------------------------------------------------------------- // mysis.c // // programmer: ALLAN CRUSE // written on: 22 APR 2003 // revised on: 25 APR 2003 -- to correct and clarify 'mmap()' //------------------------------------------------------------------- #define __KERNEL__ #define MODULE #include // for init_module() #include // for pci_find_class() #include // for remap_page_range() #define VGA_CLASS 0x030000 // for VGA Display Adapters static char modname[] = "mysis"; static char devname[] = "/dev/vram"; static int my_major = 99; // driver's assigned major number static unsigned long fb_base; // physical address of frame buffer static unsigned long fb_size; // size of the frame buffer (bytes) static int my_mmap( struct file *file, struct vm_area_struct *vma ) { unsigned long region_length = vma->vm_end - vma->vm_start; unsigned long region_origin = vma->vm_pgoff * PAGE_SIZE; unsigned long phys_addr = fb_base + region_origin; unsigned long virt_addr = vma->vm_start; // cannot map a file-region that extends past end-of-file if ( region_origin + region_length > fb_size ) return -EINVAL; // tell kernel not to try swapping out this device-memory vma->vm_flags |= VM_RESERVED; // request the kernel to set up the necessary page-tables if ( remap_page_range( virt_addr, phys_addr, region_length, vma->vm_page_prot ) ) return -EAGAIN; return 0; // SUCCESS; } static loff_t my_llseek( struct file *file, loff_t offset, int whence ) { loff_t newpos = -1; switch( whence ) { case 0: newpos = offset; break; // SEEK_SET case 1: newpos = file->f_pos + offset; break; // SEEK_CUR case 2: newpos = fb_size + offset; break; // SEEK_END } if (( newpos < 0 )||( newpos > fb_base )) return -EINVAL; file->f_pos = newpos; return newpos; } static struct file_operations my_fops = { owner: THIS_MODULE, llseek: my_llseek, mmap: my_mmap, }; int init_module( void ) { struct pci_dev *devp = NULL; u32 save, temp; int i; printk( "<1>\nInstalling \'%s\' module ", modname ); printk( "(major=%d) \n", my_major ); devp = pci_find_class( VGA_CLASS, devp ); if ( !devp ) return -ENODEV; fb_base = pci_resource_start( devp, 0 ); temp = ~0; pci_read_config_dword( devp, 0x10, &save ); pci_write_config_dword( devp, 0x10, temp ); pci_read_config_dword( devp, 0x10, &temp ); pci_write_config_dword( devp, 0x10, save ); for (i = 4; i < 32; i++) if ( temp & (1< VGA Device: %s \n", devp->name ); printk( "<1> frame-buffer starts at %08X ", fb_base ); printk( "(%d MB)\n", fb_size >> 20 ); return register_chrdev( my_major, modname, &my_fops ); } void cleanup_module( void ) { unregister_chrdev( my_major, modname ); printk( "<1>Removing \'%s\' module\n", modname ); } MODULE_LICENSE("GPL"); // Thanks to Qing Huang for pointing out a flaw in 'mmap()' earlier.