📄 kllad.c
字号:
} break; case DIRECT_IOCTL_GBUS_GET_LOCKED_AREA: { struct gbus_lock_area param; unsigned long i; if (cfu(¶m, (char *)arg, sizeof(param)) != 0) return -EFAULT; rc = 0; i = get_locked_area(¶m); /* printk("get_locked area %p %d %d %d\n", param.byte_address, param.offset, param.size, i); */ if (i==DIRECT_REGION_COUNT) rc = -EINVAL; if (ctu((char *) arg, ¶m, sizeof(param)) != 0) return -EFAULT; } break; case DIRECT_IOCTL_GBUS_GET_SYSTEM_PAGE_COUNT: { struct gbus_region_count param; unsigned long region_index, system_page_count; if (cfu(¶m, (char *)arg, sizeof(param)) != 0) return -EFAULT; rc = 0; region_index=param.region_index; if (region_index >= DIRECT_REGION_COUNT) { return -EINVAL; } system_page_count=R.region_info[region_index].region_count; /* printk("get_system_page_count: region=%i, count=%i\n", region_index, system_page_count); */ param.region_count=system_page_count; if (ctu((char *) arg, ¶m, sizeof(param)) != 0) return -EFAULT; } break;#endif // EM86XX_CHIP default: rc = -EINVAL; }done: return rc;}#if (EM86XX_CHIP==EM86XX_CHIPID_TANGO2)#define DIRECT_MMAP_MASK 0xff000000#define DIRECT_MMAP_DMAPOOL 0x02000000#define DIRECT_MMAP_REGION 0x03000000#define DIRECT_MMAP_DMAPOOL_SHIFT 12#define DIRECT_MMAP_REGION_SHIFT 12#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)struct page *kdmapool_vma_nopage(struct vm_area_struct *vma, unsigned long addr, int *type);#elsestruct page *kdmapool_vma_nopage(struct vm_area_struct *vma, unsigned long addr, int unused);#endif#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)static struct page *direct_vma_nopage(struct vm_area_struct *vma, unsigned long addr, int *type)#elsestatic struct page *direct_vma_nopage(struct vm_area_struct *vma, unsigned long addr, int type)#endif{ unsigned long offset = vma->vm_pgoff << PAGE_SHIFT; struct page *page = NULL; if ((offset & DIRECT_MMAP_MASK) == DIRECT_MMAP_DMAPOOL) page = kdmapool_vma_nopage(vma, addr, type);#if 0 /* this is only true if the region mapped is under kernel control */ else if ((offset & DIRECT_MMAP_MASK) == DIRECT_MMAP_REGION) { unsigned long region_index, base, vaddr; region_index = (offset - DIRECT_MMAP_REGION) >> DIRECT_MMAP_REGION_SHIFT; base = XLAT_G2P(R.region_info[region_index].direct_map); offset = (addr - vma->vm_start); /* absolute offset */ vaddr = (base + offset) & PAGE_MASK; page = virt_to_page(vaddr); }#endif if (page) get_page(page); return page;}static struct vm_operations_struct direct_vm_ops = { .nopage = direct_vma_nopage};static int minor_mmap(struct file *filp, struct vm_area_struct *vma){ int rc = 0; unsigned long offset; unsigned long dmapool_id, region_index; offset = vma->vm_pgoff << PAGE_SHIFT; /* printk("mmap at offset 0x%x\n", offset); */ switch (offset & DIRECT_MMAP_MASK) { case DIRECT_MMAP_DMAPOOL: dmapool_id = (offset - DIRECT_MMAP_DMAPOOL) >> DIRECT_MMAP_DMAPOOL_SHIFT; rc = kdmapool_mmap((struct llad *) NULL, (struct kc_vm_area_struct *)vma, dmapool_id, vma->vm_start, vma->vm_end-vma->vm_start,(struct kc_pgprot_t *)&(vma->vm_page_prot)); break; case DIRECT_MMAP_REGION: /* printk("mmaping region: %p 0x%08lx\n", vma->vm_start, vma->vm_end-vma->vm_start); */ region_index = (offset - DIRECT_MMAP_REGION) >> DIRECT_MMAP_REGION_SHIFT; /* because we run on MIPS */ vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); /* from linux-2.6.10 remap_page_range is replaced by remap_pfn_range */#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10) rc = remap_page_range(vma->vm_start, XLAT_G2P(R.region_info[region_index].direct_map), vma->vm_end - vma->vm_start, vma->vm_page_prot);#else rc = remap_pfn_range(vma, vma->vm_start, XLAT_G2P(R.region_info[region_index].direct_map) >> PAGE_SHIFT, vma->vm_end - vma->vm_start, vma->vm_page_prot);#endif // LINUX_VERSION_CODE if (rc) { printk("failed to mmap region\n"); return -EAGAIN; } break; default: printk("Unknown offset\n"); rc = -EINVAL; break; } if (rc >= 0) { vma->vm_ops = &direct_vm_ops; vma->vm_flags |= VM_RESERVED; } return rc;}#endif // EM86XX_CHIPstatic int minor_open(struct inode *i_node, struct file *filp){ int i; spin_lock(&open_lock); // find direct_id in the table for (i=0;i<MAX_OPENERS;i++) if (R.openers[i].direct_id==CURRENT_DIRECT_ID) break; if (i==MAX_OPENERS) { // find empty entry for (i=0;i<MAX_OPENERS;i++) if (R.openers[i].direct_id==0) break; if (i==MAX_OPENERS) { printk("minor_open: too many openers (increase MAX_OPENERS)\n"); spin_unlock(&open_lock); return -EINVAL; } R.openers[i].direct_id=CURRENT_DIRECT_ID; //printk("minor_open: #%d new mum_id %d\n", i,R.openers[i].direct_id); } R.openers[i].open_count ++; R.total_open_count ++; spin_unlock(&open_lock); return 0;}static int minor_release(struct inode *i_node, struct file *filp){ int i; spin_lock(&open_lock); // find direct_id in the table for (i=0;i<MAX_OPENERS;i++) if (R.openers[i].direct_id==CURRENT_DIRECT_ID) break; if (i>=MAX_OPENERS) { printk("minor_release: too many openers (increase MAX_OPENERS)\n"); spin_unlock_bh(&open_lock); return -EINVAL; } R.openers[i].open_count --; if (R.openers[i].open_count == 0) { /* close openned dmapools */ int j=0; while (R.openers[i].dmapool_usage_mask) { if (test_and_clear_bit(j, (void *)&(R.openers[i].dmapool_usage_mask))) { kdmapool_close((struct llad *) NULL, j); } j++; } R.openers[i].direct_id = 0; } R.total_open_count --; spin_unlock(&open_lock); return 0;}static struct file_operations direct_fops = { // this replaces MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT pain owner: THIS_MODULE, ioctl:minor_ioctl, #if (EM86XX_CHIP==EM86XX_CHIPID_TANGO2) mmap:minor_mmap,#endif // EM86XX_CHIP open:minor_open, release:minor_release, };#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)#define IRQ_FLAGS_INTERRUPT (SA_INTERRUPT)#define IRQ_FLAGS_SHIRQ (SA_INTERRUPT | SA_SHIRQ)#else#define IRQ_FLAGS_INTERRUPT (IRQF_DISABLED)#define IRQ_FLAGS_SHIRQ (IRQF_DISABLED | IRQF_SHARED)#endifint llad_init(void){ int res,i; init_waitqueue_head(&(R.irq_queue)); sema_init(&gbus_buf_sem, 1); spin_lock_init(&open_lock); R.total_open_count = 0; for (i=0 ; i<MAX_OPENERS ; i++) { R.openers[i].direct_id = 0; R.openers[i].open_count = 0; R.openers[i].dmapool_usage_mask = 0; } #if (EM86XX_CHIP==EM86XX_CHIPID_TANGO2) for (res=0 ; res<DIRECT_REGION_COUNT ; res++) { R.region_info[res].direct_map =0; R.region_info[res].region_count=0; R.region_info[res].map_refcount=0; R.region_info[res].area_offset=0; R.region_info[res].area_size=0; R.region_info[res].area_byte_address=0; }#endif // EM86XX_CHIP#if (EM86XX_CHIP<EM86XX_CHIPID_TANGO2) && defined WITH_IRQHANDLER_BOOTLOADER { /* when linux boots, it has overwritten irq and undef; in case of bootirq we put it back. */ RMuint32 val, table; table = gbus_read_uint32(pGBus, JUMPTABLE_ADDRESS); val = gbus_read_uint32(pGBus, IRQHANDLER_ENTRY); overload_IRQHandler(pGBus, val, table); val = gbus_read_uint32(pGBus, UNDEFHANDLER_ENTRY); overload_UNDEFHandler(pGBus, val, table); }#else /* when not using irqhandler from bootloader, clear all events/interrupts before enabling the SOFTINT. */ gbus_write_uint32(pGBus, HOST_INTERRUPT_STATUS, 0); gbus_write_uint32(pGBus, REG_BASE_cpu_block + CPU_irq_softclr, ~SOFTIRQMASK_VALID); /* We need to initialize the UCLINUX_LLAD_IRQHANDLER_HANDSHAKE parmater to 0 since we are going to register an IRQ that cannot be handled by the emhwlib IRQ handler yet since the emhwlib will be loaded only later. */ gbus_write_uint32(pGBus, UCLINUX_LLAD_IRQHANDLER_HANDSHAKE, 0);#endif res = kdmapool_init((struct llad *) NULL); if (res < 0) return res; if ((res = request_irq(IRQ_SOFTINT, tophalf, IRQ_FLAGS_SHIRQ, DIRECT_DEVICE_NAME, &R)) != 0) goto free_irq_softint; if ((res = request_irq(IRQ_MBUS_W1, dummy_isr, IRQ_FLAGS_INTERRUPT, "mbus_w1", &R)) != 0) goto free_irq_mbus_w1; if ((res = request_irq(IRQ_GRAPHICACCEL, dummy_isr, IRQ_FLAGS_INTERRUPT, "gfx", &R)) != 0) goto free_irq_graphicaccel; if ((res = request_irq(IRQ_MBUS_R1, dummy_isr, IRQ_FLAGS_INTERRUPT, "mbus_r1", &R)) != 0) goto free_irq_mbus_r1; if ((res = request_irq(IRQ_TIMER1, dummy_isr, IRQ_FLAGS_INTERRUPT, "timer1", &R)) != 0) goto free_irq_timer1;#if (EM86XX_CHIP == EM86XX_CHIPID_TANGOLIGHT) || (EM86XX_CHIP == EM86XX_CHIPID_MAMBOLIGHT) || (EM86XX_CHIP == EM86XX_CHIPID_MAMBO) if ((res = request_irq(IRQ_RTC, dummy_isr, IRQ_FLAGS_INTERRUPT, "rtc", &R)) != 0) goto free_irq_rtc;#endif#if (EM86XX_CHIP==EM86XX_CHIPID_TANGO2) if ((res = request_irq(IRQ_VSYNC0, tango2_vsync_intr, IRQ_FLAGS_INTERRUPT, "vsync0", &R)) != 0) goto free_irq_vsync0; if ((res = request_irq(IRQ_VSYNC1, tango2_vsync_intr, IRQ_FLAGS_INTERRUPT, "vsync1", &R)) != 0) goto free_irq_vsync1; if ((res = request_irq(IRQ_VSYNC2, tango2_vsync_intr, IRQ_FLAGS_INTERRUPT, "vsync2", &R)) != 0) goto free_irq_vsync2; if ((res = request_irq(IRQ_VSYNC3, tango2_vsync_intr, IRQ_FLAGS_INTERRUPT, "vsync3", &R)) != 0) goto free_irq_vsync3;#endif res = register_chrdev(major, DIRECT_DEVICE_NAME, &direct_fops); if (res < 0) { printk("Cannot register module major=%d for %s\n", major, DIRECT_DEVICE_NAME);#if (EM86XX_CHIP==EM86XX_CHIPID_TANGO2)free_irq_vsync3: free_irq(IRQ_VSYNC3, &R);free_irq_vsync2: free_irq(IRQ_VSYNC2, &R);free_irq_vsync1: free_irq(IRQ_VSYNC1, &R);free_irq_vsync0: free_irq(IRQ_VSYNC0, &R);#endif#if (EM86XX_CHIP == EM86XX_CHIPID_TANGOLIGHT) || (EM86XX_CHIP == EM86XX_CHIPID_MAMBOLIGHT) || (EM86XX_CHIP == EM86XX_CHIPID_MAMBO)free_irq_rtc: free_irq(IRQ_RTC, &R);#endiffree_irq_timer1: free_irq(IRQ_TIMER1, &R);free_irq_mbus_r1: free_irq(IRQ_MBUS_R1, &R);free_irq_graphicaccel: free_irq(IRQ_GRAPHICACCEL, &R);free_irq_mbus_w1: free_irq(IRQ_MBUS_W1, &R);free_irq_softint: free_irq(IRQ_SOFTINT, &R); return res; } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) /* does nothing if CONFIG_DEVFS_FS is undefined */ R.devfs_handle = devfs_register(NULL, DIRECT_DEVICE_NAME, DEVFS_FL_AUTO_DEVNUM, major, 0, S_IFCHR | S_IRUGO | S_IWUGO, &direct_fops, NULL); if (R.devfs_handle == NULL) { printk("devfs module not registered\n"); }#endif#ifdef WITH_PROC#ifdef WITH_MONITORING /* Add /proc/driver/mum/ entries */ add_driver_proc_entry(); add_driver_proc_files();#endif#endif return res;}void llad_exit(void){#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0) /* does nothing if CONFIG_DEVFS_FS is undefined */ if (R.devfs_handle != NULL) devfs_unregister(R.devfs_handle);#endif unregister_chrdev(major, DIRECT_DEVICE_NAME); free_irq(IRQ_SOFTINT, &R); free_irq(IRQ_MBUS_W1, &R); free_irq(IRQ_GRAPHICACCEL, &R);#if (EM86XX_CHIP == EM86XX_CHIPID_TANGOLIGHT) || (EM86XX_CHIP == EM86XX_CHIPID_MAMBOLIGHT) || (EM86XX_CHIP == EM86XX_CHIPID_MAMBO) free_irq(IRQ_RTC, &R);#endif free_irq(IRQ_MBUS_R1, &R); free_irq(IRQ_TIMER1, &R);#if (EM86XX_CHIP==EM86XX_CHIPID_TANGO2) free_irq(IRQ_VSYNC3, &R); free_irq(IRQ_VSYNC2, &R); free_irq(IRQ_VSYNC1, &R); free_irq(IRQ_VSYNC0, &R);#endif kdmapool_deinit((struct llad *) NULL);#ifdef WITH_PROC#ifdef WITH_MONITORING /* Add /proc/driver/mum/ entries */ rm_driver_proc_entry(); rm_driver_proc_files();#endif#endif #if (EM86XX_CHIP<EM86XX_CHIPID_TANGO2) && defined WITH_IRQHANDLER_BOOTLOADER restore_IRQHandler(pGBus); restore_UNDEFHandler(pGBus);#endif}module_init(llad_init);module_exit(llad_exit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -