📄 hmp4e.c.svn-base
字号:
static int hmp4e_fasync(int fd, struct file *filp, int mode){ hmp4e_t *dev = (hmp4e_t *) filp->private_data; PDEBUG("fasync called\n"); return fasync_helper(fd, filp, mode, &dev->async_queue);}#ifdef HMP4E_DEBUGstatic void dump_regs(unsigned long data);#endifstatic int hmp4e_release(struct inode *inode, struct file *filp){ hmp4e_t *dev = (hmp4e_t *) filp->private_data; /* this is necessary if user process exited asynchronously */ disable_irq(dev->irq);#ifdef HMP4E_DEBUG dump_regs((unsigned long) dev); /* dump the regs */#endif ResetAsic(dev); /* reset hardware */ /* free the encoder IRQ */ free_irq(dev->irq, (void *) dev); /* remove this filp from the asynchronusly notified filp's */ hmp4e_fasync(-1, filp, 0); //MOD_DEC_USE_COUNT; PDEBUG("dev closed\n"); return 0;}/* VFS methods */static struct file_operations hmp4e_fops = { mmap:hmp4e_mmap, open:hmp4e_open, release:hmp4e_release, ioctl:hmp4e_ioctl, fasync:hmp4e_fasync,};int __init hmp4e_init(void){ int result; /* if you want to test the module, you obviously need to "mknod". */ PDEBUG("module init\n"); printk("<1>hmp4e: base_port=0x%08lx irq=%i\n", base_porte, irqe); hmp4e_data.iobaseaddr = base_porte; hmp4e_data.iosize = ENC_IO_SIZE; hmp4e_data.irq = irqe; result = register_chrdev(hmp4e_major, "hmp4e", &hmp4e_fops); if(result < 0) { printk(KERN_INFO "hmp4e: unable to get major %d\n", hmp4e_major); goto err; } else if(result != 0) /* this is for dynamic major */ { hmp4e_major = result; } result = ReserveIO(); if(result < 0) { goto err; } ResetAsic(&hmp4e_data); /* reset hardware */ result = AllocMemory(); if(result < 0) { ReleaseIO(); goto err; } printk(KERN_INFO "hmp4e: module inserted. Major = %d\n", hmp4e_major); //EXPORT_NO_SYMBOLS; return 0; err: printk(KERN_INFO "hmp4e: module not inserted\n"); unregister_chrdev(hmp4e_major, "hmp4e"); return result;}void __exit hmp4e_cleanup(void){ unregister_chrdev(hmp4e_major, "hmp4e"); FreeMemory(); ReleaseIO(); printk(KERN_INFO "hmp4e: module removed\n"); return;}module_init(hmp4e_init);module_exit(hmp4e_cleanup);static int AllocMemory(void){ struct page *pg; char *start_addr, *end_addr; u32 order, size; hmp4e_data.buffer = NULL; hmp4e_data.buffsize = HMP4E_BUF_SIZE; for(order = 0, size = PAGE_SIZE; size < hmp4e_data.buffsize; order++, size <<= 1) ; hmp4e_data.buffsize = size; /* alloc memory */ start_addr = (char *) __get_free_pages(GFP_KERNEL, order); if(!start_addr) { printk(KERN_INFO "hmp4e: failed to alloc memory\n"); return -ENOMEM; } else { memset(start_addr, 0, hmp4e_data.buffsize); /* clear the mem */ hmp4e_data.buffer = start_addr; } end_addr = start_addr + hmp4e_data.buffsize - 1; PDEBUG("Alloc buffer 0x%08lx -- 0x%08lx\n", (long) start_addr, (long) end_addr); /* now we've got the kernel memory, but it can still be * swapped out. We need to stop the VM system from removing our * pages from main memory. To do this we just need to set the PG_reserved * bit on each page, via mem_map_reserve() macro. */ /* If we don't set the reserved bit, the user-space application sees * all-zeroes pages. This is because remap_page_range() won't allow you to * map non-reserved pages (check remap_pte_range()). * The pte's will be cleared, resulting in a page faulting in a new zeroed * page instead of the pages we are trying to mmap(). */ for(pg = virt_to_page(start_addr); pg <= virt_to_page(end_addr); pg++) { mem_map_reserve(pg); } return 0;}static void FreeMemory(void){ struct page *pg; u32 size, order; /* first unreserve */ for(pg = virt_to_page(hmp4e_data.buffer); pg < virt_to_page(hmp4e_data.buffer + hmp4e_data.buffsize); pg++) { mem_map_unreserve(pg); } for(order = 0, size = PAGE_SIZE; size < hmp4e_data.buffsize; order++, size <<= 1) ; /* and now free */ free_pages((long) hmp4e_data.buffer, order); PDEBUG("Free buffer 0x%08lx -- 0x%08lx\n", (long) hmp4e_data.buffer, (long) (hmp4e_data.buffer + hmp4e_data.buffsize - 1));}static int ReserveIO(void){ long int hwid; if(!request_mem_region(hmp4e_data.iobaseaddr, hmp4e_data.iosize, "hmp4e")) { printk(KERN_INFO "hmp4e: failed to reserve HW regs\n"); return -EBUSY; } hmp4e_data.hwregs = (volatile u8 *) ioremap_nocache(hmp4e_data.iobaseaddr, hmp4e_data.iosize); if(hmp4e_data.hwregs == NULL) { printk(KERN_INFO "hmp4e: failed to ioremap HW regs\n"); ReleaseIO(); return -EBUSY; } hwid = readl(hmp4e_data.hwregs + 0x88);#if 1 /* check for correct HW */ if((hwid >> 20) != (ENC_HW_ID >> 20)) { printk(KERN_INFO "hmp4e: HW not found at 0x%08lx\n", hmp4e_data.iobaseaddr);#ifdef HMP4E_DEBUG dump_regs((unsigned long) &hmp4e_data);#endif ReleaseIO(); return -EBUSY; } else { printk(KERN_INFO "hmp4e: Valid HW found at base 0x%08lx with ID# 0x%08lx\n", hmp4e_data.iobaseaddr, hwid); }#endif return 0;}static void ReleaseIO(void){ if(hmp4e_data.hwregs) iounmap((void *) hmp4e_data.hwregs); release_mem_region(hmp4e_data.iobaseaddr, hmp4e_data.iosize);}static int MapBuffers(struct file *filp, struct vm_area_struct *vma){ unsigned long phys; unsigned long start = (unsigned long) vma->vm_start; unsigned long size = (unsigned long) (vma->vm_end - vma->vm_start); /* if userspace tries to mmap beyond end of our buffer, fail */ if(size > hmp4e_data.buffsize){ return -EINVAL; } vma->vm_flags |= VM_RESERVED | VM_IO; vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* Remember this won't work for vmalloc()d memory ! */ phys = virt_to_phys(hmp4e_data.buffer); if(remap_pfn_range(vma, start, phys >> PAGE_SHIFT, size, vma->vm_page_prot)) { printk("<1>HMP4E: MapBuffers -EAGAIN\n"); return -EAGAIN; } return 0;}static int MapHwRegs(struct file *filp, struct vm_area_struct *vma){ unsigned long phys; unsigned long start = (unsigned long) vma->vm_start; unsigned long size = (unsigned long) (vma->vm_end - vma->vm_start); /* if userspace tries to mmap beyond end of our buffer, fail */ if(size > PAGE_SIZE) return -EINVAL; vma->vm_flags |= VM_RESERVED | VM_IO; vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); phys = hmp4e_data.iobaseaddr; if(remap_pfn_range(vma, start, phys >> PAGE_SHIFT, hmp4e_data.iosize, vma->vm_page_prot)) { return -EAGAIN; } return 0;}int hmp4e_isr(int irq, void *dev_id, struct pt_regs *regs){ hmp4e_t *dev = (hmp4e_t *) dev_id; u32 irq_status = readl(dev->hwregs + 0x10); writel(irq_status & (~0x01), dev->hwregs + 0x10); /* clear enc IRQ */ if(dev->async_queue) kill_fasync(&dev->async_queue, SIGIO, POLL_IN); PDEBUG("IRQ received!\n"); return IRQ_HANDLED;}void ResetAsic(hmp4e_t * dev){ int i; writel(0, dev->hwregs + 0x10); for(i = 0; i < dev->iosize; i += 4) { writel(0, dev->hwregs + i); }}#ifdef HMP4E_DEBUGvoid dump_regs(unsigned long data){ hmp4e_t *dev = (hmp4e_t *) data; int i; PDEBUG("Reg Dump Start\n"); for(i = 0; i < dev->iosize; i += 4) { PDEBUG("\toffset %02X = %08X\n", i, readl(dev->hwregs + i)); } PDEBUG("Reg Dump End\n");}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -