tdfx_vid.c
来自「君正早期ucos系统(只有早期的才不没有打包成库),MPLAYER,文件系统,图」· C语言 代码 · 共 1,029 行 · 第 1/2 页
C
1,029 行
return 0;}static int tdfx_vid_set_overlay(unsigned long arg) { tdfx_vid_overlay_t ov; uint32_t screen_w,screen_h; uint32_t vidcfg,stride,vidbuf; int disp_w,disp_h; if(copy_from_user(&ov,(tdfx_vid_overlay_t*)arg,sizeof(tdfx_vid_overlay_t))) { printk(KERN_DEBUG "tdfx_vid:failed copy from userspace\n"); return(-EFAULT); } if(ov.dst_y < 0) { int shift; if(-ov.dst_y >= ov.src_height) { printk(KERN_DEBUG "tdfx_vid: Overlay outside of the screen ????\n"); return(-EFAULT); } shift = (-ov.dst_y)/(double)ov.dst_height*ov.src_height; ov.src[0] += shift*ov.src_stride; ov.src_height -= shift; ov.dst_height += ov.dst_y; ov.dst_y = 0; } if(ov.dst_x < 0) { int shift; if(-ov.dst_x >= ov.src_width) { printk(KERN_DEBUG "tdfx_vid: Overlay outside of the screen ????\n"); return(-EFAULT); } shift = (-ov.dst_x)/(double)ov.dst_width*ov.src_width; shift = ((shift+3)/2)*2; ov.src[0] += shift*2; ov.src_width -= shift; ov.dst_width += ov.dst_x; ov.dst_x = 0; } vidcfg = tdfx_inl(VIDPROCCFG); // clear the overlay fmt vidcfg &= ~(7 << 21); switch(ov.format) { case TDFX_VID_FORMAT_BGR15: vidcfg |= (1 << 21); break; case TDFX_VID_FORMAT_BGR16: vidcfg |= (7 << 21); break; case TDFX_VID_FORMAT_YUY2: vidcfg |= (5 << 21); break; case TDFX_VID_FORMAT_UYVY: vidcfg |= (6 << 21); break; default: printk(KERN_DEBUG "tdfx_vid: Invalid overlay fmt 0x%x\n",ov.format); return (-EFAULT); } // YUV422 need 4 bytes aligned stride and address if((ov.format == TDFX_VID_FORMAT_YUY2 || ov.format == TDFX_VID_FORMAT_UYVY)) { if((ov.src_stride & ~0x3) != ov.src_stride) { printk(KERN_DEBUG "tdfx_vid: YUV need a 4 bytes aligned stride %d\n",ov.src_stride); return(-EFAULT); } if((ov.src[0] & ~0x3) != ov.src[0] || (ov.src[1] & ~0x3) != ov.src[1]){ printk(KERN_DEBUG "tdfx_vid: YUV need a 4 bytes aligned address 0x%x 0x%x\n",ov.src[0],ov.src[1]); return(-EFAULT); } } // Now we have a good input format // but first get the screen size to check a bit // if the size/position is valid screen_w = tdfx_inl(VIDSCREENSIZE); screen_h = (screen_w >> 12) & 0xFFF; screen_w &= 0xFFF; disp_w = ov.dst_x + ov.dst_width >= screen_w ? screen_w - ov.dst_x : ov.dst_width; disp_h = ov.dst_y + ov.dst_height >= screen_h ? screen_h - ov.dst_y : ov.dst_height; if(ov.dst_x >= screen_w || ov.dst_y >= screen_h || disp_h <= 0 || disp_h > screen_h || disp_w <= 0 || disp_w > screen_w) { printk(KERN_DEBUG "tdfx_vid: Invalid overlay dimension and/or position\n"); return (-EFAULT); } // Setup the vidproc // H scaling if(ov.src_width < ov.dst_width) vidcfg |= (1<<14); else vidcfg &= ~(1<<14); // V scaling if(ov.src_height < ov.dst_height) vidcfg |= (1<<15); else vidcfg &= ~(1<<15); // Filtering can only be used in 1x mode if(!(vidcfg | (1<<26))) vidcfg |= (3<<16); else vidcfg &= ~(3<<16); // disable overlay stereo mode vidcfg &= ~(1<<2); // Colorkey on/off if(ov.use_colorkey) { // Colorkey inversion if(ov.invert_colorkey) vidcfg |= (1<<6); else vidcfg &= ~(1<<6); vidcfg |= (1<<5); } else vidcfg &= ~(1<<5); // Overlay isn't VidIn vidcfg &= ~(1<<9); // vidcfg |= (1<<8); tdfx_outl(VIDPROCCFG,vidcfg); // Start coord //printk(KERN_DEBUG "tdfx_vid: start %dx%d\n",ov.dst_x & 0xFFF,ov.dst_y & 0xFFF); tdfx_outl(VIDOVRSTARTCRD,(ov.dst_x & 0xFFF)|((ov.dst_y & 0xFFF)<<12)); // End coord tdfx_outl(VIDOVRENDCRD, ((ov.dst_x + disp_w-1) & 0xFFF)| (((ov.dst_y + disp_h-1) & 0xFFF)<<12)); // H Scaling tdfx_outl(VIDOVRDUDX,( ((u32)ov.src_width) << 20) / ov.dst_width); // Src offset and width (in bytes) tdfx_outl(VIDOVRDUDXOFF,((ov.src_width<<1) & 0xFFF) << 19); // V Scaling tdfx_outl(VIDOVRDVDY, ( ((u32)ov.src_height) << 20) / ov.dst_height); //else // tdfx_outl(VIDOVRDVDY,0); // V Offset tdfx_outl(VIDOVRDVDYOFF,0); // Overlay stride stride = tdfx_inl(VIDDESKSTRIDE) & 0xFFFF; tdfx_outl(VIDDESKSTRIDE,stride | (((u32)ov.src_stride) << 16)); // Buffers address tdfx_outl(LEFTOVBUF, ov.src[0]); tdfx_outl(RIGHTOVBUF, ov.src[1]); // Send a swap buffer cmd if we are not on one of the 2 buffers vidbuf = tdfx_inl(VIDCUROVRSTART); if(vidbuf != ov.src[0] && vidbuf != ov.src[1]) { tdfx_outl(SWAPPENDING,0); tdfx_outl(SWAPBUFCMD, 1); } //printk(KERN_DEBUG "tdfx_vid: Buf0=0x%x Buf1=0x%x Current=0x%x\n", // ov.src[0],ov.src[1],tdfx_inl(VIDCUROVRSTART)); // Colorkey if(ov.use_colorkey) { tdfx_outl(VIDCHRMIN,ov.colorkey[0]); tdfx_outl(VIDCHRMAX,ov.colorkey[1]); } return 0;}static int tdfx_vid_overlay_on(void) { uint32_t vidcfg = tdfx_inl(VIDPROCCFG); //return 0; if(vidcfg & (1<<8)) { // Overlay is already on //printk(KERN_DEBUG "tdfx_vid: Overlay is already on.\n"); return (-EFAULT); } vidcfg |= (1<<8); tdfx_outl(VIDPROCCFG,vidcfg); return 0;}static int tdfx_vid_overlay_off(void) { uint32_t vidcfg = tdfx_inl(VIDPROCCFG); if(vidcfg & (1<<8)) { vidcfg &= ~(1<<8); tdfx_outl(VIDPROCCFG,vidcfg); return 0; } printk(KERN_DEBUG "tdfx_vid: Overlay is already off.\n"); return (-EFAULT); }static int tdfx_vid_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ tdfx_vid_agp_move_t move; tdfx_vid_config_t cfg; tdfx_vid_blit_t blit; u16 int16; switch(cmd) { case TDFX_VID_AGP_MOVE: if(copy_from_user(&move,(tdfx_vid_agp_move_t*)arg,sizeof(tdfx_vid_agp_move_t))) { printk(KERN_INFO "tdfx_vid:failed copy from userspace\n"); return(-EFAULT); } return agp_move(&move); case TDFX_VID_BUMP0: if(copy_from_user(&int16,(u16*)arg,sizeof(u16))) { printk(KERN_INFO "tdfx_vid:failed copy from userspace\n"); return(-EFAULT); } return bump_fifo(int16); case TDFX_VID_BLIT: if(copy_from_user(&blit,(tdfx_vid_blit_t*)arg,sizeof(tdfx_vid_blit_t))) { printk(KERN_INFO "tdfx_vid:failed copy from userspace\n"); return(-EFAULT); } if(!tdfx_vid_blit(&blit)) { printk(KERN_INFO "tdfx_vid: Blit failed\n"); return(-EFAULT); } return 0; case TDFX_VID_GET_CONFIG: if(copy_from_user(&cfg,(tdfx_vid_config_t*)arg,sizeof(tdfx_vid_config_t))) { printk(KERN_INFO "tdfx_vid:failed copy from userspace\n"); return(-EFAULT); } tdfx_vid_get_config(&cfg); if(copy_to_user((tdfx_vid_config_t*)arg,&cfg,sizeof(tdfx_vid_config_t))) { printk(KERN_INFO "tdfx_vid:failed copy to userspace\n"); return(-EFAULT); } return 0; case TDFX_VID_SET_YUV: return tdfx_vid_set_yuv(arg); case TDFX_VID_GET_YUV: return tdfx_vid_get_yuv(arg); case TDFX_VID_SET_OVERLAY: return tdfx_vid_set_overlay(arg); case TDFX_VID_OVERLAY_ON: return tdfx_vid_overlay_on(); case TDFX_VID_OVERLAY_OFF: return tdfx_vid_overlay_off(); default: printk(KERN_ERR "tdfx_vid: Invalid ioctl %d\n",cmd); return (-EINVAL); } return 0;}static ssize_t tdfx_vid_read(struct file *file, char *buf, size_t count, loff_t *ppos){ return 0;}static ssize_t tdfx_vid_write(struct file *file, const char *buf, size_t count, loff_t *ppos){ return 0;}static void tdfx_vid_mopen(struct vm_area_struct *vma) { int i; struct page *page; unsigned long phys; printk(KERN_DEBUG "tdfx_vid: mopen\n"); for(i = 0 ; i < agp_mem->page_count ; i++) { phys = agp_mem->memory[i] & ~(0x00000fff); page = virt_to_page(phys_to_virt(phys)); if(!page) { printk(KERN_DEBUG "tdfx_vid: Can't get the page %d\%d\n",i,agp_mem->page_count); return; } get_page(page); } MOD_INC_USE_COUNT;}static void tdfx_vid_mclose(struct vm_area_struct *vma) { int i; struct page *page; unsigned long phys; printk(KERN_DEBUG "tdfx_vid: mclose\n"); for(i = 0 ; i < agp_mem->page_count ; i++) { phys = agp_mem->memory[i] & ~(0x00000fff); page = virt_to_page(phys_to_virt(phys)); if(!page) { printk(KERN_DEBUG "tdfx_vid: Can't get the page %d\%d\n",i,agp_mem->page_count); return; } put_page(page); } MOD_DEC_USE_COUNT;}static struct page *tdfx_vid_nopage(struct vm_area_struct *vma, unsigned long address, int write_access) { unsigned long off; uint32_t n; struct page *page; unsigned long phys; off = address - vma->vm_start + (vma->vm_pgoff<<PAGE_SHIFT); n = off / PAGE_SIZE; if(n >= agp_mem->page_count) { printk(KERN_DEBUG "tdfx_vid: Too far away\n"); return ((struct page *)0UL); } phys = agp_mem->memory[n] & ~(0x00000fff); page = virt_to_page(phys_to_virt(phys)); if(!page) { printk(KERN_DEBUG "tdfx_vid: Can't get the page\n"); return ((struct page *)0UL); } return page;}/* memory handler functions */static struct vm_operations_struct tdfx_vid_vm_ops = { open: tdfx_vid_mopen, /* mmap-open */ close: tdfx_vid_mclose,/* mmap-close */ nopage: tdfx_vid_nopage, /* no-page fault handler */};static int tdfx_vid_mmap(struct file *file, struct vm_area_struct *vma){ size_t size;#ifdef MP_DEBUG printk(KERN_DEBUG "tdfx_vid: mapping agp memory into userspace\n");#endif size = (vma->vm_end-vma->vm_start + PAGE_SIZE - 1) / PAGE_SIZE; if(map_start) { // Ok we map directly in the physcal ram if(size*PAGE_SIZE > map_max) { printk(KERN_ERR "tdfx_vid: Not enouth mem\n"); return(-EAGAIN); }#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,3) if(remap_page_range(vma, vma->vm_start,map_start, vma->vm_end - vma->vm_start, vma->vm_page_prot)) #else if(remap_page_range(vma->vm_start, (unsigned long)map_start, vma->vm_end - vma->vm_start, vma->vm_page_prot)) #endif { printk(KERN_ERR "tdfx_vid: error mapping video memory\n"); return(-EAGAIN); } printk(KERN_INFO "Physical mem 0x%lx mapped in userspace\n",map_start); return 0; } if(agp_mem) return(-EAGAIN); agp_mem = drm_agp->allocate_memory(size,AGP_NORMAL_MEMORY); if(!agp_mem) { printk(KERN_ERR "Failed to allocate AGP memory\n"); return(-ENOMEM); } if(drm_agp->bind_memory(agp_mem,0)) { printk(KERN_ERR "Failed to bind the AGP memory\n"); drm_agp->free_memory(agp_mem); agp_mem = NULL; return(-ENOMEM); } printk(KERN_INFO "%d pages of AGP mem allocated (%ld/%ld bytes) :)))\n", size,vma->vm_end-vma->vm_start,size*PAGE_SIZE); if(tdfx_map_io) {#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,3) if(remap_page_range(vma, vma->vm_start,agp_info.aper_base, vma->vm_end - vma->vm_start, vma->vm_page_prot)) #else if(remap_page_range(vma->vm_start, (unsigned long)agp_info.aper_base, vma->vm_end - vma->vm_start, vma->vm_page_prot)) #endif { printk(KERN_ERR "tdfx_vid: error mapping video memory\n"); return(-EAGAIN); } } else { // Never swap it out vma->vm_flags |= VM_LOCKED | VM_IO; vma->vm_ops = &tdfx_vid_vm_ops; vma->vm_ops->open(vma); printk(KERN_INFO "Page fault handler ready !!!!!\n"); } return 0;}static int tdfx_vid_release(struct inode *inode, struct file *file){#ifdef MP_DEBUG printk(KERN_DEBUG "tdfx_vid: Video OFF (release)\n");#endif // Release the agp mem if(agp_mem) { drm_agp->unbind_memory(agp_mem); drm_agp->free_memory(agp_mem); agp_mem = NULL; } tdfx_vid_in_use = 0; MOD_DEC_USE_COUNT; return 0;}static long long tdfx_vid_lseek(struct file *file, long long offset, int origin){ return -ESPIPE;} static int tdfx_vid_open(struct inode *inode, struct file *file){#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,2) int minor = MINOR(inode->i_rdev.value);#else int minor = MINOR(inode->i_rdev);#endif if(minor != 0) return(-ENXIO); if(tdfx_vid_in_use == 1) return(-EBUSY); tdfx_vid_in_use = 1; MOD_INC_USE_COUNT; return(0);}#if LINUX_VERSION_CODE >= 0x020400static struct file_operations tdfx_vid_fops ={ llseek: tdfx_vid_lseek, read: tdfx_vid_read, write: tdfx_vid_write, ioctl: tdfx_vid_ioctl, mmap: tdfx_vid_mmap, open: tdfx_vid_open, release: tdfx_vid_release};#elsestatic struct file_operations tdfx_vid_fops ={ tdfx_vid_lseek, tdfx_vid_read, tdfx_vid_write, NULL, NULL, tdfx_vid_ioctl, tdfx_vid_mmap, tdfx_vid_open, NULL, tdfx_vid_release};#endifint init_module(void){ tdfx_vid_in_use = 0; if(register_chrdev(TDFX_VID_MAJOR, "tdfx_vid", &tdfx_vid_fops)) { printk(KERN_ERR "tdfx_vid: unable to get major: %d\n", TDFX_VID_MAJOR); return -EIO; } if(!agp_init()) { printk(KERN_ERR "tdfx_vid: AGP init failed\n"); unregister_chrdev(TDFX_VID_MAJOR, "tdfx_vid"); return -EINVAL; } if (!tdfx_vid_find_card()) { printk(KERN_ERR "tdfx_vid: no supported devices found\n"); agp_close(); unregister_chrdev(TDFX_VID_MAJOR, "tdfx_vid"); return -EINVAL; } return (0);}void cleanup_module(void){ if(tdfx_mmio_base) iounmap(tdfx_mmio_base); agp_close(); printk(KERN_INFO "tdfx_vid: Cleaning up module\n"); unregister_chrdev(TDFX_VID_MAJOR, "tdfx_vid");}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?