📄 spartan_drv.c
字号:
#define __KERNEL__#define MODULE#include <linux/module.h>#include <linux/errno.h>#include <linux/kernel.h>#include <linux/pci.h>#include <asm/uaccess.h>#include <spartan_kint.h> //IOCTL definitions // define vendor and device ID here - currently this definitions specify reference designs from insight electronic#define OC_PCI_VENDOR 0x1597#define OC_PCI_DEVICE 0x0300// if someone wants specific major number assigned to spartan board - specify it here // if 0 is used, kernel assigns it automaticaly#define REQUESTED_MAJOR 0// if compiling module for kernel 2.4 - leave this defined// for kernel 2.2 - comment this out#define KERNEL_VER_24#ifndef SEEK_SET #define SEEK_SET 0 #define SEEK_CUR 1 #define SEEK_END 2#endif// io.h needed just for kernel 2.2#ifndef KERNEL_VER_24 #include <asm/io.h>#endif// memory mapped or IO mapped region definitions#define SPARTAN_MEM_MAPPED 0#define SPARTAN_IO_MAPPED 1// structure for holding board information// (6 base addresses, mapping, page etc.static struct our_dev{ int major ; u32 bases[6] ; u8 num_of_bases ; u32 base_size[6] ; u32 offset ; u32 page_addr ; u32 base_page_offset ; int current_resource ; int base_map[6] ; struct pci_dev *ppci_spartan_dev ; } pspartan_dev ;// function prototypesint spartan_open(struct inode *inode, struct file *filp); int spartan_release(struct inode *inode, struct file *filp);ssize_t spartan_read(struct file *filp, char *buf, size_t count, loff_t *offset ) ;ssize_t spartan_write(struct file *filp, const char *buf, size_t count, loff_t *offset) ;int spartan_ioctl(struct inode *pnode, struct file *filp, unsigned int cmd, unsigned long arg) ;loff_t spartan_seek(struct file *filp, loff_t offset, int what) ;// file operations structure - different for kernels 2.2 and 2.4static struct file_operations *pspartan_fops ;static struct file_operations spartan_fops = { #ifdef KERNEL_VER_24 NULL, #endif spartan_seek, spartan_read, spartan_write, NULL, NULL, spartan_ioctl, NULL, spartan_open, NULL, spartan_release,} ; int open_mem_mapped(void) ;// seek file operation functionloff_t spartan_seek(struct file *filp, loff_t offset, int origin){ loff_t requested_offset ; int resource_num = pspartan_dev.current_resource ; switch (origin) { case SEEK_CUR:requested_offset = pspartan_dev.offset + offset ; break ; case SEEK_END:requested_offset = pspartan_dev.base_size[resource_num] + offset ; break ; default:requested_offset = offset ; break ; } if ((requested_offset < 0) || (requested_offset > pspartan_dev.base_size[resource_num])) return -EFAULT ; pspartan_dev.offset = requested_offset ; return requested_offset ; }// ioctl for device// currently just a few operations are supported here - defined in spartan_kint.h headerint spartan_ioctl(struct inode *pnode, struct file *filp, unsigned int cmd, unsigned long arg) { int error = 0; int size = _IOC_SIZE(cmd) ; unsigned long base ; unsigned long base_size ; if (_IOC_TYPE(cmd) != SPARTAN_IOC_NUM) return -EINVAL ; if (_IOC_NR(cmd) > SPARTAN_IOC_MAX_NUM) return -EINVAL ; // Writes through pointers not allowed - writes only through argument if (_IOC_DIR(cmd) & _IOC_WRITE) return -EINVAL ; else if (_IOC_DIR(cmd) & _IOC_READ) error = verify_area(VERIFY_WRITE, (void *) arg, size) ; if (error) return error ; switch (cmd){ case SPARTAN_IOC_CURRESGET:return (pspartan_dev.current_resource + 1) ; // current resource - they start at 1 case SPARTAN_IOC_CURRESSET:// check if resource is in a range of implemented resources if (arg < 0 ) return -EINVAL ; // unmap previous resource if it was mapped if (pspartan_dev.current_resource >= 0) { iounmap((void *)pspartan_dev.page_addr) ; } if (arg == 0) { // previous resource unmaped - that's all pspartan_dev.current_resource = -1 ; return 0 ; } if (pspartan_dev.num_of_bases < arg) return -ENODEV ; // IO mapped not supported yet if (pspartan_dev.base_map[arg] == SPARTAN_IO_MAPPED) { // set current resource to none, since it was unmapped pspartan_dev.current_resource = -1 ; return -ENODEV ; } pspartan_dev.current_resource= (int)(arg-1) ; // remap new resource if ( (error = open_mem_mapped()) ) { pspartan_dev.current_resource = -1 ; return error ; } return 0 ; case SPARTAN_IOC_CURBASE: // check if any resource is currently activated if (pspartan_dev.current_resource>=0) base = pspartan_dev.bases[pspartan_dev.current_resource] ; else base = 0x00000000 ; *(unsigned long *)arg = base ; return 0 ; case SPARTAN_IOC_CURBASEMAP: // check if any resource is currently activated if (pspartan_dev.current_resource>=0) base = pspartan_dev.page_addr ; else base = 0x00000000 ; *(unsigned long *)arg = base ; return 0 ; case SPARTAN_IOC_CURBASESIZE: // check if any resource is currently activated if (pspartan_dev.current_resource>=0) base_size = pspartan_dev.base_size[pspartan_dev.current_resource] ; else base_size = 0x00000000 ; *(unsigned long *)arg = base_size ; return 0 ; case SPARTAN_IOC_NUMOFRES: return (pspartan_dev.num_of_bases) ; default: return -EINVAL ; }}// helper function for memory remapingint open_mem_mapped(void){ int resource_num = pspartan_dev.current_resource ; unsigned long num_of_pages = 0 ; unsigned long base = pspartan_dev.bases[resource_num] ; unsigned long size = pspartan_dev.base_size[resource_num] ; if (!(num_of_pages = (unsigned long)(size/PAGE_SIZE))) ; num_of_pages++ ; pspartan_dev.base_page_offset = base & ~PAGE_MASK ; if ((pspartan_dev.base_page_offset + size) < (num_of_pages*PAGE_SIZE)) num_of_pages++ ; // remap memory mapped space pspartan_dev.page_addr = (unsigned long)ioremap(base & PAGE_MASK, num_of_pages * PAGE_SIZE) ; if (pspartan_dev.page_addr == 0x00000000) return -ENOMEM ; return 0 ;}// add io mapped resource handler hereint open_io_mapped( void ) { return 0 ;}// open file operation functionint spartan_open(struct inode *inode, struct file *filp){ if (MOD_IN_USE) return -EBUSY ; pspartan_fops = &spartan_fops ; filp->f_op = pspartan_fops ; pspartan_dev.offset = 0 ; pspartan_dev.current_resource = -1 ; MOD_INC_USE_COUNT ; return 0 ;} // release - called by close on file descriptorint spartan_release(struct inode *inode, struct file *filp){ // unmap any remaped pages if (pspartan_dev.current_resource >= 0) iounmap((void *)pspartan_dev.page_addr) ; pspartan_dev.current_resource = -1 ; MOD_DEC_USE_COUNT ; return 0 ;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -