📄 hmp4d.c
字号:
_reg_AIPI2_PAR &= ~(0x1 << 6); _reg_CRM_PCCR0 |= 0x08008000;#endif hmp4d_data.iobaseaddr = base_port; hmp4d_data.iosize = DEC_IO_SIZE; hmp4d_data.irq = irq; /* changed to devfs */ /* register hmp4e device */ result = devfs_register_chrdev(0, "hmp4d", &hmp4d_fops); if ( result < 0 ) { printk("hmp4d error: unable to register chr driver\n"); return -ENODEV; }#ifndef NODEVFS devfs_handle = devfs_register(NULL, "hmp4d", DEVFS_FL_DEFAULT, result, 0, S_IFCHR | S_IRUSR | S_IWUSR, &hmp4d_fops, NULL); if(devfs_handle == NULL) { printk("hmp4d error: unable to register driver\n"); return -ENODEV; }#endif hmp4d_major = result; /* power management */#ifdef APM_HMP4D if ((pmdev = pm_register(PM_EMMA_DEV, PM_SYS_UNKNOWN, hmp4d_pm_handler)) == NULL) { printk("Failed to register PM... continuing with driver init\n"); } g_hmp4d_apmc = apmc_register(APMC_LEVEL_HIGHEST);#endif /* register for ipc */ /* in case other emma device want to get the status of each other */ g_hmp4d_busy = 0; inter_module_register("string_hmp4d_busy", THIS_MODULE, &g_hmp4d_busy); 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){ /* change to devfs */ if(hmp4d_major > 0) { if(devfs_unregister_chrdev(hmp4d_major, "hmp4d") < 0) { printk("hmp4d error: failed to unregister from devfs\n"); return; } }#ifndef NODEVFS if(devfs_handle != NULL) devfs_unregister(devfs_handle); else { printk("hmp4d error: failed to unregister from devfs, devfs_handle = 0x%08X\n", (int)devfs_handle); return; }#endif /* power management */#ifdef APM_HMP4D apmc_unregister(g_hmp4d_apmc); pm_unregister(pmdev);#endif /* unregister ipc */ inter_module_unregister("string_hmp4d_busy"); FreeMemory(); ReleaseIO(); printk(KERN_INFO "Decoder driver is unloaded sucessfully\n"); return;}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){ 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 = (u32 *) ioremap_nocache(hmp4d_data.iobaseaddr, hmp4d_data.iosize); if(hmp4d_data.hwregs == NULL) { printk(KERN_INFO "hmp4d: failed to ioremap IO memory\n"); ReleaseIO(); return -EBUSY; }#if 1 if((readl(hmp4d_data.hwregs + 7) & 0x0000ffff) != DEC_HW_ID) { printk(KERN_INFO "hmp4d: HW not found at 0x%08lx\n", hmp4d_data.iobaseaddr); ReleaseIO(); return -EBUSY; }#endif return 0;}static void ReleaseIO(void){ if(hmp4d_data.hwregs) iounmap(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 if(remap_page_range(start, phys, size, vma->vm_page_prot)) { 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 if(remap_page_range(start, phys - ofs, hmp4d_data.iosize + ofs, vma->vm_page_prot))#else if(remap_page_range(start, phys, hmp4d_data.iosize, vma->vm_page_prot))#endif { return -EAGAIN; } return 0;}void 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 & (~0x08), dev->hwregs); PDEBUG("DecIRQ"); if(dev->async_queue) kill_fasync(&dev->async_queue, SIGIO, POLL_IN);}void ResetAsic(hmp4d_t * dev){ 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 */}#ifdef APM_HMP4Dstatic int hmp4d_pm_handler(struct pm_dev *pmdev, pm_request_t rqst, void *data){ switch(rqst) { case PM_SUSPEND: { if(g_hmp4d_busy) { return 1; } else { printk("hmp4d suspend\n"); break; } } case PM_RESUME: { printk("hmp4d resume\n"); break; } } return 0;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -