//------------------------------------------------------------------- // sischip.c // // This module demonstrates the creation of a '/proc' file that // has both read-and-write capabilities. Applications may read // or write the value of the Screen Start-Address Offset in the // SiS 315 VGA Graphics Display hardware used in our classroom. // // NOTE: Written and tested using Linux kernel version 2.4.20. // // programmer: ALLAN CRUSE // written on: 08 MAY 2003 //------------------------------------------------------------------- #define __KERNEL__ #define MODULE #include // for init_module() #include // for create_proc_entry() #include // for pci_find_device() #include // copy_to_user() #define SUCCESS 0 #define PROC_DIR NULL #define PROC_MODE 0666 #define VENDOR_ID PCI_VENDOR_ID_SI #define DEVICE_ID 0x6325 #define VGA_SEQN_PORT 0x3C4 #define VGA_CRTC_PORT 0x3D4 static char modname[] = "sischip"; static struct pci_dev *devp = NULL; static unsigned long fb_base; static unsigned long fb_size = (32<<20); static unsigned long sis_get_start_address_offset( void ) { unsigned long temp, start_offset = 0; // bits 23..16 outb( 13, VGA_SEQN_PORT ); temp = inw( VGA_SEQN_PORT ); start_offset |= ((temp>>8)<<16); // bits 15..8 outb( 12, VGA_CRTC_PORT ); temp = inw( VGA_CRTC_PORT ); start_offset |= ((temp>>8)<<8); // bits 7..0 outb( 13, VGA_CRTC_PORT ); temp = inw( VGA_CRTC_PORT ); start_offset |= ((temp>>8)<<0); return start_offset; } static void sis_set_start_address_offset( unsigned long start_offset ) { unsigned short temp; // bits 7..0 temp = ((start_offset>>0)&0xFF)<<8; temp |= 13; outw( temp, VGA_CRTC_PORT ); // bits 15..8 temp = ((start_offset>>8)&0xFF)<<8; temp |= 12; outw( temp, VGA_CRTC_PORT ); // bits 23..16 temp = ((start_offset>>16)&0xFF)<<8; temp |= 13; outw( temp, VGA_SEQN_PORT ); } static ssize_t my_write( struct file *file, const char *buf, size_t len, loff_t *pos ) { unsigned long start_address_offset; int more; more = copy_from_user( &start_address_offset, buf, 4 ); sis_set_start_address_offset( start_address_offset ); return len; } static ssize_t my_read( struct file *file, char *buf, size_t len, loff_t *pos ) { unsigned long start_address_offset; int more; start_address_offset = sis_get_start_address_offset(); more = copy_to_user( buf, &start_address_offset, 4 ); if ( more ) return -EFAULT; return len; } static struct file_operations my_fops = { owner: THIS_MODULE, write: my_write, read: my_read, }; int init_module( void ) { struct proc_dir_entry *entry; printk( "<1>\nInstalling \'%s\' module\n", modname ); devp = pci_find_device( VENDOR_ID, DEVICE_ID, devp ); if ( !devp ) return -ENODEV; printk( "<1> %s \n", devp->name ); fb_base = pci_resource_start( devp, 0 ); entry = create_proc_entry( modname, PROC_MODE, PROC_DIR ); entry->proc_fops = &my_fops; return SUCCESS; } void cleanup_module( void ) { remove_proc_entry( modname, PROC_DIR ); printk( "<1>Removing \'%s\' module\n", modname ); } MODULE_LICENSE("GPL");