📄 diopsis.c
字号:
/* Sean Haycock 26/03/2009Char device Driver 'diopsis' to load module and indicate to a user application when a genlock pulse has arrived at the ioport 'genlock'. This will trigger aninterrupt which will call kill_fasync() to send SIGIO to the application thatmust catch the SIGIO with the command signal(). This will indicate to the applicationto read the encoder data from the device.16/04/2009 SH added - mmap function so that user can access data in enc_buf30/04/2009 SH added - actually encoder ioports*/#include <linux/init.h>#include <linux/module.h>#include <linux/version.h>#include <linux/kernel.h> /* printk() */#include <linux/slab.h> /* kmalloc() */#include <linux/fs.h> /* everything... */#include <linux/errno.h> /* error codes */#include <linux/types.h> /* size_t */#include <linux/fcntl.h> /* O_ACCMODE */#include <asm/system.h> /* cli(), *_flags */#include <asm/uaccess.h> /* copy_from/to_user */#include <linux/interrupt.h> /* interrupt headers */#include <linux/signal.h> /*interrupt arguments */#include <linux/ioport.h> /* allocating io ports */#include <linux/socket.h>#include <asm/semaphore.h> /* mutex */#include <linux/delay.h> /* delay to test read blocking */#include <linux/cdev.h>#include <linux/mm.h>#include <asm/io.h>#define SA_INTERRUPT 0 /* declares 'fast interrupt' */#define SUCCESS 0 /* return value */#define MEM_SIZE 100#define PORT_SIZE 1 /* size of io port */#define LEN 16/* Definitions for MESA encoder 4I36 board */ #define BASE 0x220#define MESA_INDEX_OFFSET 0x00#define MSA_COUNTLO_OFFSET 0x02#define MSA_COUNTHI_OFFSET 0x04#define IDXAutoInc_bit 0x4000MODULE_AUTHOR("Sean Haycock");MODULE_DESCRIPTION("Char device driver for diopsis board"); MODULE_LICENSE("Dual BSD/GPL"); /* Declarations of functions */int diopsis_open(struct inode *inode, struct file *filp); int diopsis_release(struct inode *inode, struct file *filp); ssize_t diopsis_read(struct file *filp, char *buf, size_t count, loff_t *f_pos); ssize_t diopsis_write(struct file *filp, char *buf, size_t count, loff_t *f_pos);int diopsis_init(void); /* intialise */void diopsis_exit(void); /* clean up */static irqreturn_t diopsis_interrupt(int irq, void *dev_id, struct pt_regs *regs);/*interrupt */static int dev_fasync(int fd, struct file *filp, int on); /* user space communication*/static int diopsis_mmap(struct file *filp, struct vm_area_struct *vma);/* prototype for mapping each encoder buffers pages for shared memory */static int diopsis_mmap_c0(struct file *filp, struct vm_area_struct *vma);static int diopsis_mmap_c1(struct file *filp, struct vm_area_struct *vma);static int diopsis_mmap_c2(struct file *filp, struct vm_area_struct *vma);static int diopsis_mmap_c3(struct file *filp, struct vm_area_struct *vma);/* Module init and exit declarations */module_init(diopsis_init); /* installs modules */module_exit(diopsis_exit); /* uninstalls module */ /* file operations for driver */struct file_operations diopsis_fops = { .owner = THIS_MODULE, /* prevents module from being unloaded whilst in use */ .read = diopsis_read, /* read function*/ .write = diopsis_write, /* write function */ .open = diopsis_open, /* open function*/ .release = diopsis_release, /* release function*/ .fasync = dev_fasync, /* to notify device of change in FASYNC flag */ .mmap = diopsis_mmap, /* memory map */};static struct fasync_struct *dev_async_queue;struct semaphore sem, sem2;/* MESA board address offsets */int index = BASE + MESA_INDEX_OFFSET; /* index register */int countLow = BASE + MSA_COUNTLO_OFFSET; /* counter low register */int countHigh= BASE + MSA_COUNTHI_OFFSET; /* counter high register *//* Global variables */int diopsis_major = 111; /* Major number */ int diopsis_irq = 15; /* interrupt number */int gen_port = 0x400; /* Genlock io port 0xXXX */int index_reg = 0x220; /* Index register on MESA board */int counterlow_reg = 0x222; /* counter low register on MESA board */int counterhigh_reg = 0x224; /* counter high register on MESA board */int gen_io; /* check genlock ioport return value */int enc_io; /* check encoder ioport return value *///int interrupt_cnt=0; /* counts number of interrupts -for TEST purpos*///int read_cnt=0; /* counts number of reads- for TEST purpose *//* input data values from MESA board encoder channels */int enc_0_hi, enc_0_lo; /* channel 0 upper and lower word values */int enc_1_hi, enc_1_lo; /* channel 1 upper and lower word values */int enc_2_hi, enc_2_lo; /* channel 2 upper and lower word values */int enc_3_hi, enc_3_lo; /* channel 3 upper and lower word values */ /*-------------------------------------------- | pointers to each encoder buffer data | -------------------------------------------- */ /* encoder bit 0 buffer pointer */ int *enc_buf_0; /* kmalloc pointer */ static int *kmalloc_area_0; /* rounded up page boundry pointer of kmalloc */ /* encoder bit 1 buffer pointer */ int *enc_buf_1; static int *kmalloc_area_1; /* encoder bit 2 buffer pointer */ int *enc_buf_2; static int *kmalloc_area_2; /* encoder bit 3 buffer pointer */ int *enc_buf_3; static int *kmalloc_area_3; /*----------------------------------------------------*/ /*--------------------------------------------------------- | Page Memory Mapping for Encoder Buffers | ----------------------------------------------------------*//* memory mapping function */static int diopsis_mmap(struct file *filp, struct vm_area_struct *vma){ if(vma->vm_pgoff == 0) /* offset of 0 */ { return diopsis_mmap_c0(filp,vma); } if(vma->vm_pgoff == LEN) /* offset of 16 */ { return diopsis_mmap_c1(filp,vma); } if(vma->vm_pgoff == 2*LEN) /* offset of 32 */ { return diopsis_mmap_c2(filp,vma); } if(vma->vm_pgoff == 3*LEN) /* offset of 48 */ { return diopsis_mmap_c3(filp,vma); }}/* ----------encoder channel 0 buffer page mapping-------------------*/static int diopsis_mmap_c0(struct file *filp, struct vm_area_struct *vma){ int ret; long length = vma->vm_end - vma->vm_start; printk(KERN_INFO "mmap function c0\n"); ret = remap_pfn_range(vma, vma->vm_start, virt_to_phys((void *)kmalloc_area_0) >> PAGE_SHIFT, length, vma->vm_page_prot); return 0;}/* ----------encoder channel 1 buffer page mapping-------------------*/static int diopsis_mmap_c1(struct file *filp, struct vm_area_struct *vma){ int ret; long length = vma->vm_end - vma->vm_start; printk(KERN_INFO "mmap function c1\n"); ret = remap_pfn_range(vma, vma->vm_start, virt_to_phys((void *)kmalloc_area_1) >> PAGE_SHIFT, length, vma->vm_page_prot); return 0;}/* ----------encoder channel 2 buffer page mapping-------------------*/static int diopsis_mmap_c2(struct file *filp, struct vm_area_struct *vma){ int ret; long length = vma->vm_end - vma->vm_start; printk(KERN_INFO "mmap function c2\n"); ret = remap_pfn_range(vma, vma->vm_start, virt_to_phys((void *)kmalloc_area_2) >> PAGE_SHIFT, length, vma->vm_page_prot); return 0;}/* ----------encoder channel 3 buffer page mapping-------------------*/static int diopsis_mmap_c3(struct file *filp, struct vm_area_struct *vma){ int ret; long length = vma->vm_end - vma->vm_start; printk(KERN_INFO "mmap function c3\n"); ret = remap_pfn_range(vma, vma->vm_start, virt_to_phys((void *)kmalloc_area_3) >> PAGE_SHIFT, length, vma->vm_page_prot); return 0;}/*-------------------------------------------------------------*//* initialisation */int diopsis_init(void) { int result; int irq_result; int i; printk(KERN_INFO "Inserting diopsis module\n"); /* Registering device */ result = register_chrdev(diopsis_major, "diopsis", &diopsis_fops); printk(KERN_INFO "Diopsis register with major number: %d\n", diopsis_major); if (result < 0) { printk(KERN_INFO "Diopsis: cannot obtain major number %d\n", diopsis_major); return result; } /* Requesting interrupt for device interrupt can be seen by cat /proc/interrupts */ irq_result = request_irq(diopsis_irq, diopsis_interrupt, SA_INTERRUPT, "genlock", NULL); printk(KERN_INFO "Diopsis interrupt: %d\n", diopsis_irq); if(irq_result) { printk(KERN_INFO "Genlock: can't get assigned irq: %d\n", diopsis_irq); } /*------------------------------------------------------ | ALLOCATING IO PORTS FOR ENCODER DATA | |-----------------------------------------------------| | i) check to see if io region is free | | ii) allocate io region if free | ------------------------------------------------------*//*---------- allocationg io port for genlock -----------*/ gen_io = check_region(gen_port, PORT_SIZE); /* check if region is free? */ if(gen_io) { printk(KERN_INFO "cannot reserve genlock io: %x\n", gen_port); } request_region(gen_port, PORT_SIZE, "genlock"); /* allocate io region for genlock *//* ---------allocationg io port for MESA index register channel -------*/ enc_io = check_region(index_reg, PORT_SIZE); /* check if region is free? */ if(enc_io) { printk(KERN_INFO "cannot reserve encoder io: %x\n", index_reg); } request_region(index_reg, PORT_SIZE, "mesa_index"); /* allocate io region for encoder *//* --------allocationg io port for MESA counter low register ----------*/ enc_io = check_region(counterlow_reg, PORT_SIZE); /* check if region is free? */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -