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 + -
显示快捷键?