// Device driver code for the FPGA adder #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) #include #endif #define adder_MAJOR 246 #define adder_NAME "adder" #define adder_BASE 0xD3000000 #define adder_MASK 0x1FFFF #define adder_SIZE 0x20000 #define WRITE_COMMAND1 0x80000000 #define WRITE_COMMAND2 0x40000000 #undef DEBUG volatile unsigned int *adder_ptr; static int adder_open1 (struct inode *inode, struct file *file) { return 0; } static int adder_release1 (struct inode *inode, struct file *file) { return 0; } static int adder_ioctl1(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { int retval = 0; unsigned int offset; static int counter=0; unsigned long addr1, addr2, addr0; addr0 = 0xd3000000ul; addr1 = 0xd3000004ul; addr2 = 0xd3000008ul; switch(cmd) { case 0: //read if(!access_ok(VERIFY_READ, (unsigned int *)arg, sizeof(int))) return -EFAULT; offset = (addr0 & adder_MASK)>>2; *(unsigned int *)arg = readl((volatile unsigned int *)&adder_ptr[offset]); break; case WRITE_COMMAND1: //write if(!access_ok(VERIFY_WRITE, (unsigned int *)arg, sizeof(int))) return -EFAULT; offset = (addr1 & adder_MASK)>>2; writel(*(unsigned int *)arg,(volatile unsigned int *)&adder_ptr[offset]); break; case WRITE_COMMAND2: //write if(!access_ok(VERIFY_WRITE, (unsigned int *)arg, sizeof(int))) return -EFAULT; offset = (addr2 & adder_MASK)>>2; writel(*(unsigned int *)arg,(volatile unsigned int *)&adder_ptr[offset]); break; default: retval = 111111; } return retval; } // define which file operations are supported struct file_operations adder_fops = { .owner = THIS_MODULE, .llseek = NULL, .read = NULL, .write = NULL, .readdir = NULL, .poll = NULL, .ioctl = adder_ioctl1, .mmap = NULL, .open = adder_open1, .flush = NULL, .release = adder_release1, .fsync = NULL, .fasync = NULL, .lock = NULL, .readv = NULL, .writev = NULL, }; // initialize module static int __init adder_init_module (void) { printk("Adder Module\n"); printk(KERN_INFO "\nAdder: Driver Loading.\n"); printk(KERN_INFO "Adder: Using Major Number %d on %s\n", adder_MAJOR, adder_NAME); if (register_chrdev(adder_MAJOR, adder_NAME, &adder_fops)) { printk("Adder: unable to get major %d. ABORTING!\n", adder_MAJOR); return -EBUSY; } // Perform Memory REMAP if (check_mem_region(adder_BASE, adder_SIZE)) { printk(KERN_ERR "Adder: Unable to acquire adder address.\n"); return -EBUSY; } request_mem_region(adder_BASE, adder_SIZE, adder_NAME); adder_ptr = (volatile unsigned int *)__ioremap(adder_BASE, adder_SIZE, 0); if (!adder_ptr) { printk(KERN_ERR "Adder: Unable to map the adder.\n"); release_mem_region(adder_BASE, adder_SIZE); return -EBUSY; } printk("Adder: 0x%.4x size 0x%.4x mapped to 0x%.4x\n", adder_BASE, adder_SIZE, (unsigned int)adder_ptr); return 0; } static void __exit adder_cleanup_module (void) { iounmap((void *)adder_ptr); release_mem_region(adder_BASE, adder_SIZE); printk("Adder: Device released.\n"); unregister_chrdev (adder_MAJOR, adder_NAME); } module_init(adder_init_module); module_exit(adder_cleanup_module); MODULE_AUTHOR("tarun@virtualcogs.com; modified by sambamur@cerc.utexas.edu"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Adder Device Driver");