⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mmvideo.c

📁 LINUX内核编程的一些程序例子
💻 C
📖 第 1 页 / 共 2 页
字号:
/** mmvideo.c * * author marco corvi <marco_corvi@geocities.com> * date   may 2003 * * credits: after the stv680 driver (thanks) * */#include <linux/config.h>#include <linux/module.h>#include <linux/version.h>#include <linux/init.h>#include <linux/fs.h>#include <linux/vmalloc.h>#include <linux/slab.h>#include <linux/proc_fs.h>#include <linux/pagemap.h>#include <linux/wrapper.h>#include <linux/smp_lock.h>#include <linux/sched.h>#include <linux/signal.h>#include <linux/errno.h>#include <linux/videodev.h>#include "mmvideo.h"#define DRIVER_VERSION "v0.10"#define DRIVER_AUTHOR  "marco corvi <marco_corvi@geocities.com>"#define DRIVER_DESC    "memory based video driver"#define MMVIDEO_FPS 20 /* 10 frames per sec */MODULE_AUTHOR( DRIVER_AUTHOR );MODULE_DESCRIPTION( DRIVER_DESC );#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 4, 10)  MODULE_LICENSE( "GPL" );#endifEXPORT_NO_SYMBOLS;// #define VIDEO_DEVICE_HAVE_OWNER#define PDEBUG( fmt, args... ) printk(KERN_ALERT fmt, ## args );/* ================================================================ *//* virtual memory                                                   *//* ---------------------------------------------------------------- */static inline unsigned long uvirt_to_kva( pgd_t * pgd, unsigned long addr ){  unsigned long ret = 0UL;  pmd_t * pmd;  pte_t * pte;    if ( !pgd_none(*pgd)) {    pmd = pmd_offset( pgd, addr );    if ( !pmd_none( *pmd )) {      pte = pte_offset( pmd, addr );      if ( pte_present( *pte ) ) {        ret = (unsigned long) page_address( pte_page( *pte ) );        ret |= (addr & (PAGE_SIZE - 1));      }    }  }  return ret;}static inline unsigned long kvirt_to_pa( unsigned long addr ){  unsigned long va, kva, ret;  va = VMALLOC_VMADDR( addr ); // recast unsigned long  kva = uvirt_to_kva( pgd_offset_k(va), va );        // (init->mm)->pgd + pgd_index( va )  ret = __pa( kva ); // kva - PAGE_OFFSET  return ret;}static void * rvmalloc( unsigned long size ){  void * mem;  unsigned long addr, page;  size = (size + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);  mem = vmalloc_32( size );  if ( ! mem )     return NULL;  memset( mem, 0, size );  addr = (unsigned long) mem;  while ( size > 0 ) {    page = kvirt_to_pa( addr );    mem_map_reserve( virt_to_page( __va( page ) ) );    addr += PAGE_SIZE;    if ( size > PAGE_SIZE ) size -= PAGE_SIZE;    else                    size = 0;  }  return mem;}static void rvfree( void * mem, unsigned long size ){   unsigned long addr, page;  if ( ! mem ) return;  size = (size + (PAGE_SIZE-1)) & ~(PAGE_SIZE-1);  addr = (unsigned long)mem;  while ( size > 0 ) {    page = kvirt_to_pa( addr );    mem_map_unreserve( virt_to_page( __va( page ) ) );    addr += PAGE_SIZE;    if ( size > PAGE_SIZE ) size -= PAGE_SIZE;    else                    size = 0;  }  vfree( mem );}/* ---------------------------------------------------------------- *//* hardware                                                         *//* ---------------------------------------------------------------- */static int mmvideo_hw_reset( struct mmvideo_device * mvdev ){  // real hardware initialization  // return -1; if something goes wrong    mvdev->total_cnt = 0;  // init statistics  mvdev->error_cnt = 0;  mvdev->frame_cnt = 0;  mvdev->mmap_cnt = 0;  mvdev->drop_cnt = 0;  mvdev->vpict.brightness = 32767;  mvdev->vpict.whiteness  = 0;  mvdev->vpict.colour     = 32767;  mvdev->vpict.contrast   = 32767;  mvdev->vpict.hue        = 32767;  mvdev->vpict.palette    = MMVIDEO_PALETTE;  mvdev->vpict.depth      = MMVIDEO_DEPTH;  mvdev->cwidth  = MMVIDEO_WIDTH;  mvdev->cheight = MMVIDEO_HEIGHT;  mvdev->vwidth  = MMVIDEO_WIDTH;  mvdev->vheight = MMVIDEO_HEIGHT;  return 0;}static void mmvideo_hw_interrupt( struct mmvideo_device * mvdev ){  int  i;  // printk("mmvideo_hw_interrupt() frame %d\n", mvdev->hw_frame_nr);  mvdev->frame_to_read = -1;  for (i=0; i<MMVIDEO_NUMFRAMES; i++) {	mvdev->frame_nr = (mvdev->frame_nr + 1) % MMVIDEO_NUMFRAMES;	if ( ( mvdev->frame_flag[mvdev->frame_nr] & MMVIDEO_FRAME_MMAP ) 	  && ( mvdev->frame_flag[mvdev->frame_nr] & MMVIDEO_FRAME_MMAPUSED ) ) {	  down( & mvdev->lock );	  memcpy( mvdev->frame[mvdev->frame_nr].data,			  mvdev->hw_frame[ mvdev->hw_frame_nr ].data,			  MMVIDEO_FRAMESIZE );	  mvdev->frame_flag[mvdev->frame_nr] &= ~MMVIDEO_FRAME_MMAPUSED;	  up( & mvdev->lock );	  // increase counter of mmaped frames      mvdev->mmap_cnt ++;	  break;	}  }  if ( i == MMVIDEO_NUMFRAMES ) {    mvdev->frame_to_read = mvdev->hw_frame_nr;    wake_up_interruptible( &mvdev->wq );     // wake up any waiting process  }  // increase total number of frames  mvdev->total_cnt ++;}		// compute the new frame (hardware real acquisition)//void mmvideo_hw_newframe( unsigned long arg ){  struct mmvideo_device * mvdev = (struct mmvideo_device * )arg;  int i,j;  int f0 = mvdev->hw_frame_nr;  int f1 = (f0+1)%2;  // printk("mmvideo_hw_newframe %d (old %d)\n", f0, f1);  down( & mvdev->lock );  {    unsigned char * r0 = mvdev->hw_frame[f0].data;    unsigned char * r1 = mvdev->hw_frame[f1].data;    unsigned char * g0 = r0+1;    unsigned char * g1 = r1+1;    unsigned char * b0 = r0+2;    unsigned char * b1 = r1+2;    unsigned char rtmp, gtmp, btmp;    for (j=0; j<MMVIDEO_HEIGHT; j++) {      rtmp = *r0;      gtmp = *g0;      btmp = *b0;      for (i=0; i<MMVIDEO_WIDTH-1; i++) {        r0 += 3; *r1 = *r0; r1 += 3;        g0 += 3; *g1 = *g0; g1 += 3;        b0 += 3; *b1 = *b0; b1 += 3;      }      r0 += 3; *r1 = rtmp; r1 += 3;      g0 += 3; *g1 = gtmp; g1 += 3;      b0 += 3; *b1 = btmp; b1 += 3;    }  }  mvdev->hw_frame_nr = f1;  up( & mvdev->lock );  mod_timer( &mvdev->timer, jiffies+HZ/MMVIDEO_FPS ); // schedule next capture  mmvideo_hw_interrupt( mvdev );}        static int mmvideo_hw_mrelease( struct mmvideo_device * mvdev, int frame ){  down( & mvdev->lock );  if ( ! (mvdev->frame_flag[frame] & MMVIDEO_FRAME_MMAP) ) {    up(  & mvdev->lock );    return -EINVAL;  }  mvdev->frame_flag[frame] |= MMVIDEO_FRAME_MMAPUSED;  up(  & mvdev->lock );  return 0;}// there should be a way to end the mmap capture // and let the driver reset overwrite to 1// this should be done at the munmap() syscall, but the driver is// not invoked at that time ...static int mmvideo_hw_mcapture( struct mmvideo_device * mvdev, int frame ){  int i;  down( & mvdev->lock );  for (i=0; i<frame; i++)     mvdev->frame_flag[i] |= ( MMVIDEO_FRAME_MMAP | MMVIDEO_FRAME_MMAPUSED );  up( & mvdev->lock );  return 0;}static void mmvideo_hw_start( struct mmvideo_device * mvdev ){  int i;  for (i=0; i<MMVIDEO_NUMFRAMES; i++)     mvdev->frame_flag[i] = MMVIDEO_FRAME_READY;  mvdev->frame_nr = 0;   // start at frame 0  init_timer( &mvdev->timer );  mvdev->timer.function = mmvideo_hw_newframe;  mvdev->timer.expires  = jiffies + HZ/MMVIDEO_FPS;  mvdev->timer.data     = (unsigned long)mvdev;  add_timer(  &mvdev->timer );}static void mmvideo_hw_stop( struct mmvideo_device * mvdev ){  int i;  del_timer_sync( &mvdev->timer );  for (i=0; i<MMVIDEO_NUMFRAMES; i++)    mvdev->frame_flag[i] &= MMVIDEO_FRAME_READY;  mvdev->frame_nr = -1;}/* ---------------------------------------------------------------- *//* proc fs                                                          *//* ---------------------------------------------------------------- */#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)static struct proc_dir_entry * mmvideo_proc_dir = NULL;extern struct proc_dir_entry * video_proc_entry;static int mmvideo_proc_read(   char * page, char** start, off_t off, int cnt, int * eof, void * data ){  char * out = page;  long len;  struct mmvideo_device * mvdev = (struct mmvideo_device *)data;  out += sprintf(out, "Version   : %s\n", DRIVER_VERSION);  out += sprintf(out, "In use    : %d\n", mvdev->user);  out += sprintf(out, "Nr frames : %d\n", MMVIDEO_NUMFRAMES);  out += sprintf(out, "Size      : %dx%d\n", mvdev->vwidth, mvdev->vheight);  out += sprintf(out, "Palette   : %d\n", mvdev->vpict.palette );  out += sprintf(out, "Frame total : %d\n", mvdev->total_cnt);  out += sprintf(out, "Frame read  : %d\n", mvdev->frame_cnt);  out += sprintf(out, "Frame mmap  : %d\n", mvdev->mmap_cnt);  out += sprintf(out, "Error       : %d\n", mvdev->error_cnt);  out += sprintf(out, "Dropped     : %d\n", mvdev->drop_cnt);    len = out - page;  len -= off;  if (len < cnt) {    *eof = 1;    if (len < 0) return 0;  } else {    len = cnt;  }  *start = page + off;  return len;}static int mmvideo_proc_create_entry( struct mmvideo_device * mvdev ){  char name[12];  struct proc_dir_entry * ent;  if ( ! mmvideo_proc_dir || ! mvdev) return -1;  sprintf(name, "mmvideo%d", mvdev->vdev.minor);  ent = create_proc_entry(name, S_IFREG | S_IRUGO | S_IWUSR, mmvideo_proc_dir);  if ( ! ent ) return -1;  ent->data = mvdev;  // copy address of mmvideo_device into 'data'  ent->read_proc = mmvideo_proc_read;  mvdev->proc_entry = ent;  return 0;}static void mmvideo_proc_destroy_entry( struct mmvideo_device * mvdev ){  char name[12];  if ( ! mmvideo_proc_dir || ! mvdev) return;  sprintf(name, "mmvideo%d", mvdev->vdev.minor);  remove_proc_entry( name, mmvideo_proc_dir);  mvdev->proc_entry = NULL;}  static int mmvideo_proc_create_dir( void ){  if ( ! video_proc_entry ) return -1;  mmvideo_proc_dir = create_proc_entry("mmvideo", S_IFDIR, video_proc_entry);  if ( mmvideo_proc_dir ) {    mmvideo_proc_dir->owner = THIS_MODULE;  } else {    return -1;  }  return 0;}static void mmvideo_proc_destroy_dir( void ){  if ( ! video_proc_entry ) return;  remove_proc_entry( "mmvideo", video_proc_entry);}#endif // defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)/* ---------------------------------------------------------------- *//* video 4 linux                                                    *//* ---------------------------------------------------------------- */static int mmvideo_v4l_open( struct video_device * vdev, int flags ){  struct mmvideo_device * mvdev = (struct mmvideo_device *)(vdev->priv);  int err = 0;  // only one user at a time  if ( mvdev->user > 0 ) {    return -EINVAL;  }  MOD_INC_USE_COUNT;  mvdev->user = 1;  // initialize hw and device struct  err = mmvideo_hw_reset( mvdev );  if ( err ) {    MOD_DEC_USE_COUNT;    mvdev->user = 0;  }  // start hardware video streaming  mmvideo_hw_start( mvdev );  return err;}  static void mmvideo_v4l_close( struct video_device * vdev ) {  // called with BKL held  struct mmvideo_device * mvdev = (struct mmvideo_device *)(vdev->priv);    // stop hardware video-streaming

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -