📄 hmp4d.c.svn-base
字号:
/* if you want to test the module, you obviously need to "mknod". */ PDEBUG("module init\n"); if(use_hmp4d == 0) return -ENODEV; printk(KERN_INFO "hmp4d: base_port=0x%08lx irq=%i\n", base_port, irq); hmp4d_data.iobaseaddr = base_port; hmp4d_data.iosize = DEC_IO_SIZE; hmp4d_data.irq = irq;#ifdef IRQTEST1 result = request_irq(irq, hmp4d_isr, SA_SHIRQ, "hmp4d", (void *) &hmp4d_data); if(result == -EINVAL) { printk(KERN_ERR "hmp4d: Bad irq number or handler\n"); return result; } else if(result == -EBUSY) { printk(KERN_ERR "hmp4d: IRQ %d busy, change your config\n", irq); return result; }#endif result = register_chrdev(hmp4d_major, "hmp4d", &hmp4d_fops); if(result < 0) { printk(KERN_INFO "hmp4d: unable to get major %d\n", hmp4d_major); goto err; } else if(result != 0) /* this is for dynamic major */ { hmp4d_major = result; } result = ReserveIO(); if(result < 0) { goto err; } ResetAsic(&hmp4d_data); result = AllocMemory(); if(result < 0) { ReleaseIO(); goto err; } printk(KERN_INFO "hmp4d: module inserted. Major = %d\n", hmp4d_major); //EXPORT_NO_SYMBOLS; return 0; err: printk(KERN_INFO "hmp4d: module not inserted. Major = %d\n", hmp4d_major); unregister_chrdev(hmp4d_major, "hmp4d"); return result;}void __exit hmp4d_cleanup(void){ unregister_chrdev(hmp4d_major, "hmp4d"); FreeMemory();#ifdef IRQTEST1 free_irq(irq, (void *) &hmp4d_data);#endif ReleaseIO(); printk(KERN_INFO "hmp4d: module removed\n"); return;}//arch_initcall(hmp4d_init);module_init(hmp4d_init);module_exit(hmp4d_cleanup);static int AllocMemory(void){#if !CONS_ALLOC struct page *pg; char *start_addr, *end_addr; u32 order, size; hmp4d_data.buffer = NULL;#endif hmp4d_data.buffsize = HMP4D_BUF_SIZE;#if !CONS_ALLOC for(order = 0, size = PAGE_SIZE; size < hmp4d_data.buffsize; order++, size <<= 1) ; hmp4d_data.buffsize = size; /* alloc memory */ start_addr = (char *) __get_free_pages(GFP_KERNEL, order); if(!start_addr) { printk(KERN_INFO "hmp4d: failed to alloc memory\n"); return -ENOMEM; } else { memset(start_addr, 0, hmp4d_data.buffsize); /* clear the mem */ strcpy(start_addr, "Mapping test, data written from kernel!"); hmp4d_data.buffer = start_addr; } end_addr = start_addr + hmp4d_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); }#else hmp4d_data.buffsize = (HMP4D_BUF_SIZE + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1); hmp4d_data.buffer = consistent_alloc(GFP_DMA | GFP_KERNEL, hmp4d_data.buffsize, (dma_addr_t *)&hmp4d_phys); if (!hmp4d_data.buffer) {printk("alloc %d failed\n", hmp4d_data.buffsize); return -ENOMEM; } else { memset(hmp4d_data.buffer, 0, hmp4d_data.buffsize); strcpy(hmp4d_data.buffer, "Mapping test, data written from kernel!"); }#endif return 0;}static void FreeMemory(void){#if !CONS_ALLOC struct page *pg; u32 size, order; /* first unreserve */ for(pg = virt_to_page(hmp4d_data.buffer); pg < virt_to_page(hmp4d_data.buffer + hmp4d_data.buffsize); pg++) { mem_map_unreserve(pg); } for(order = 0, size = PAGE_SIZE; size < hmp4d_data.buffsize; order++, size <<= 1) ; /* and now free */ free_pages((long) hmp4d_data.buffer, order); PDEBUG("Free buffer 0x%08lx -- 0x%08lx\n", (long) hmp4d_data.buffer, (long) (hmp4d_data.buffer + hmp4d_data.buffsize - 1));#else consistent_free(hmp4d_data.buffer, hmp4d_data.buffsize, hmp4d_phys);#endif}static int ReserveIO(void){ long int hwid; if(!request_mem_region(hmp4d_data.iobaseaddr, hmp4d_data.iosize, "hmp4d")) { printk(KERN_INFO "hmp4d: failed to reserve IO memory\n"); return -EBUSY; } hmp4d_data.hwregs = (u8 *) ioremap_nocache(hmp4d_data.iobaseaddr, (size_t)hmp4d_data.iosize); if(hmp4d_data.hwregs == NULL) { printk(KERN_INFO "hmp4d: failed to ioremap IO memory\n"); ReleaseIO(); return -EBUSY; }#if 1 hwid = readl(hmp4d_data.hwregs + 0x54); if((hwid >> 16) != DEC_HW_ID) { printk(KERN_INFO "hmp4d: HW not found at 0x%08lx\n", hmp4d_data.iobaseaddr); printk(KERN_INFO "hmp4d: HW not found at 0x%08x\n", (u32)&hmp4d_data.hwregs); #ifdef HMP4D_DEBUG dump_regs((unsigned long) &hmp4d_data); #endif ReleaseIO(); return -EBUSY; } else { printk(KERN_INFO "hmp4d: Success: HW found at 0x%08lx\n", hmp4d_data.iobaseaddr); printk(KERN_INFO "hmp4d: Value of ID REG 0x%08lx\n", hwid); } #endif return 0;}static void ReleaseIO(void){ if(hmp4d_data.hwregs) iounmap((u32 *)hmp4d_data.hwregs); release_mem_region(hmp4d_data.iobaseaddr, hmp4d_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 > hmp4d_data.buffsize) return -EINVAL; vma->vm_flags |= VM_RESERVED; vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* Remember this won't work for vmalloc()d memory ! */#if !CONS_ALLOC phys = virt_to_phys(hmp4d_data.buffer);#else phys = hmp4d_phys;#endif printk("<1>hmp4d1:remap_page_range,%x,%x,%x\n",start, phys , size); if(remap_pfn_range(vma, start, phys >> PAGE_SHIFT, size, vma->vm_page_prot))// if(remap_page_range(vma, start, phys, 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 NON_PAGE_ALIGNED int ofs; ofs = hmp4d_data.iobaseaddr & (PAGE_SIZE - 1);#endif /* 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); /* Remember this won't work for vmalloc()d memory ! */ phys = hmp4d_data.iobaseaddr;#if NON_PAGE_ALIGNED printk("<1>hmp4d2:remap_page_range,%x,%x,%x\n",start, phys -ofs, hmp4d_data.iosize+ofs);if(remap_pfn_range(vma, start, (phys - ofs) >> PAGE_SHIFT, hmp4d_data.iosize + ofs, // if(remap_page_range(vma, start, (phys - ofs) , hmp4d_data.iosize + ofs, vma->vm_page_prot))#else printk("<1>hmp4d3:remap_page_range,%x,%x,%x\n",start, phys -ofs, hmp4d_data.iosize+ofs); if(remap_pfn_range(vma, start, phys >> PAGE_SHIFT, hmp4d_data.iosize, vma->vm_page_prot))// if(remap_page_range(vma, start, phys, hmp4d_data.iosize, vma->vm_page_prot))#endif { return -EAGAIN; } return 0;}int hmp4d_isr(int irq, void *dev_id, struct pt_regs *regs){ hmp4d_t *dev = (hmp4d_t *) dev_id; /* Clear the HW Interrupt Register immediately! */ u32 irq_status = readl(dev->hwregs); writel(irq_status & (~0x02), dev->hwregs); PDEBUG("DecIRQ"); if(dev->async_queue) kill_fasync(&dev->async_queue, SIGIO, POLL_IN); if(dev->async_queue) kill_fasync(&dev->async_queue, SIGIO, POLL_IN); return IRQ_HANDLED;}void ResetAsic(hmp4d_t * dev){ #if 1 int i; writel(0, dev->hwregs); for(i = 0; i < dev->iosize; i += 4) { writel(0, dev->hwregs + i); } #else u32 tmp; tmp = readl(dev->hwregs); tmp = tmp | 0x20; writel(tmp, dev->hwregs); /* enable dec CLK */ writel(tmp & (~0x01), dev->hwregs); /* disable dec */ writel(0x20, dev->hwregs); /* clear reg 1 */ writel(0, dev->hwregs); /* disable dec CLK */ #endif}#ifdef HMP4D_DEBUGvoid dump_regs(unsigned long data){ hmp4d_t *dev = (hmp4d_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 + -