📄 fpga_driver.c
字号:
/* FPGA device driver, remap physical addr to kernel virtual addr, then to user space addr// Kernel Module// marxuxp@gmail.com// for v2.6 kernel */#include <linux/module.h>#include <linux/init.h>#include <linux/version.h>#include <linux/errno.h>#include <linux/fs.h>#include <linux/mm.h>#include <linux/interrupt.h>#include <linux/sched.h>#include <linux/vmalloc.h>#include <linux/mman.h>#include <linux/slab.h>#include <linux/cdev.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>#include <linux/types.h>#include <linux/delay.h>#include <linux/moduleparam.h>#include <linux/ioctl.h>#include <linux/string.h>#include <linux/list.h>#include <linux/pci.h>#include <asm/atomic.h>#include <asm/unistd.h>#include <asm/uaccess.h>#include <asm/io.h>#include <asm/delay.h>#include <asm/hardware.h>#include <asm/io.h>#include <asm/arch/gpio.h>#include <asm/uaccess.h>#undef DEBUG#define DEBUG#ifdef DEBUG#define DPRINTK(x) printk(x)#else#define DPRINTK(x)#endif #ifndef FPGA_MAJOR#define FPGA_MAJOR 253 /* if 0, it is allocated by kernel */#endif/*high addr, and non-cache area*/#define FPGA_PHY_START 0x4000000/*length = 1k*/#define FPGA_PHY_SIZE 0x400//for download firmware#define FPGA_IO_DATA AT91_PIN_PD30#define FPGA_IO_CLK AT91_PIN_PD31#define BUFFER_SIZE 512u#define DEVICE_NAME "AT91_FPGA_Driver"static int FPGA_Major = FPGA_MAJOR;static int FPGA_Minor = 0;struct cdev* FPGA_cdev = NULL;struct class* FPGA_class = NULL; static unsigned char FPGA_DATA[BUFFER_SIZE];static int WriteByte(unsigned char Byte){ int i; for(i = 0; i < sizeof(unsigned char); i++) { if(Byte & (1 << i)) { at91_set_gpio_value(FPGA_IO_DATA, 1);/*here to simulate I2C*/ at91_set_gpio_value(FPGA_IO_CLK, 1); } else { at91_set_gpio_value(FPGA_IO_DATA, 0); at91_set_gpio_value(FPGA_IO_CLK, 1); } } return 0;}static int FPGA_open(struct inode *inode, struct file* filp){ DPRINTK("open\n"); return 0;}static int FPGA_release(struct inode * inode, struct file * filp){ DPRINTK("release\n"); return 0;}static int FPGA_mmap(struct file * filp, struct vm_area_struct * vma) { unsigned long off = vma->vm_pgoff << PAGE_SHIFT; unsigned long physical = FPGA_PHY_START + off; unsigned long vsize = vma->vm_end - vma->vm_start; unsigned long psize = FPGA_PHY_SIZE - off; if(vsize > psize) return -EINVAL; /*spans too high*/ vma->vm_flags |= VM_IO|VM_RESERVED; vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /*remap physic addr to kernel virtual addr*/ remap_pfn_range(vma, vma->vm_start, physical, vsize, vma->vm_page_prot); DPRINTK("memory mapped to user space\n"); return 0;}static int FPGA_ioctl(struct inode * fnode, struct file* filp, unsigned int param1, unsigned long param2) { DPRINTK("no ctl command\n"); return -EINVAL;}static ssize_t FPGA_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos){ DPRINTK("FPGA read\n"); return 0;} static ssize_t FPGA_write(struct file *filp, const char __user *buf, size_t count, loff_t *f_pos){ int i, j; int ret; int loop = count/BUFFER_SIZE; int left = count - loop*BUFFER_SIZE; /*init FPGA here*/ for(i = 0; i < loop; i++) { ret = copy_from_user(FPGA_DATA, buf+i*BUFFER_SIZE, BUFFER_SIZE); if(ret) { return -EFAULT; } for(j = 0; j < BUFFER_SIZE; j++) { WriteByte(FPGA_DATA[j]); } } /*copy left data */ if(left != 0) { ret = copy_from_user(FPGA_DATA, buf+loop*BUFFER_SIZE, left); if(ret) { return -EFAULT; } for(j = 0; j < left; j++) { WriteByte(FPGA_DATA[j]); } } printk("FPGA write, size: %d\n", count); return count;} static struct file_operations at9200_fops={.owner = THIS_MODULE,.open = FPGA_open,.mmap = FPGA_mmap,.ioctl = FPGA_ioctl,.read = FPGA_read,.write = FPGA_write,.release = FPGA_release,};static int __init at9200_FPGA_init(void){ int ret; dev_t dev = 0; FPGA_cdev = cdev_alloc(); printk(DEVICE_NAME"start init\n"); /*register device, if FPGA_Major is not 0, it will get this major number, or allocated by kernel * register_chrdev_region instead of register_chrdev for v2.6 kernel*/ if (FPGA_Major) { dev = MKDEV(FPGA_Major, FPGA_Minor); ret = register_chrdev_region(dev, 1, DEVICE_NAME); } else { ret = alloc_chrdev_region(&dev, FPGA_Minor, 1, DEVICE_NAME); FPGA_Major = MAJOR(dev); } if (ret < 0) { printk(KERN_WARNING "FPGA: can't get major %d\n", FPGA_Major); return ret; } /*ret = register_chrdev(DEVICE_MAJOR, DEVICE_NAME, &at9200_fops); if(ret < 0) { printk(DEVICE_NAME "can't get major number \n"); return ret; } DbLedMajor = ret;*/ cdev_init(FPGA_cdev, &at9200_fops); FPGA_cdev->owner = THIS_MODULE; FPGA_cdev->ops = &at9200_fops; ret = cdev_add (FPGA_cdev, MKDEV(FPGA_Major, FPGA_Minor), 1); /* Fail gracefully if need be */ if (ret) { printk(KERN_NOTICE "Error %d adding FPGA", ret); return ret; } /* creating your own class */ FPGA_class = class_create(THIS_MODULE, DEVICE_NAME); if(IS_ERR(FPGA_class)) { printk("Err: failed in creating class.\n"); return -1; } /* register your own device in sysfs, and this will cause udevd to create corresponding device node */ class_device_create(FPGA_class, NULL, MKDEV(FPGA_Major, FPGA_Minor), NULL, DEVICE_NAME"%d", FPGA_Minor); /*if(!ret) { printk(KERN_NOTICE "Error %d class_device_create", ret); return ret; }*/ printk(DEVICE_NAME"inited\n"); return 0;}static void __exit at9200_FPGA_exit(void){ dev_t dev; dev = MKDEV(FPGA_Major, FPGA_Minor); unregister_chrdev_region(dev, 1);/* unregister_chrdev(FPGA_Major, DEVICE_NAME);*/ if(FPGA_cdev) { cdev_del(FPGA_cdev); printk(DEVICE_NAME"delete cdev\n"); } if(FPGA_class) { class_device_destroy(FPGA_class, MKDEV(FPGA_Major, FPGA_Minor)); class_destroy(FPGA_class); printk(DEVICE_NAME"delete class\n"); } printk(DEVICE_NAME"exit\n"); return;}module_init(at9200_FPGA_init);module_exit(at9200_FPGA_exit);MODULE_LICENSE("GPL");MODULE_AUTHOR("marxuxp@gmail.com");MODULE_DESCRIPTION("FPGA for at9200");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -