📄 videodevx.c
字号:
* has serious privacy issues. */ vfd->devfs_handle = devfs_register (NULL, name, DEVFS_FL_DEFAULT, VIDEO_MAJOR, vfd->minor, S_IFCHR | S_IRUSR | S_IWUSR,#if LINUX_VERSION_CODE >= 0x020300 vfd->fops ? vfd->fops :#endif &video_fops, NULL);#endif#if (LINUX_VERSION_CODE >= 0x020300) && defined(CONFIG_PROC_FS) sprintf (name, "%s%d", name_base, i - base); videodev_proc_create_dev (vfd, name);#endif return 0; } } return -ENFILE;}/* * Unregister an unused video for linux device */ void video_unregister_device(struct video_device *vfd){ if(video_device[vfd->minor]!=vfd) panic("vfd: bad unregister");#if (LINUX_VERSION_CODE >= 0x020300) && defined(CONFIG_PROC_FS) videodev_proc_destroy_dev (vfd);#endif#ifdef CONFIG_DEVFS_FS devfs_unregister (vfd->devfs_handle);#endif video_device[vfd->minor]=NULL; MOD_DEC_USE_COUNT;}/* V4L2 stuff starts here *//* * Active devices */static struct v4l2_clock *masterclock;static struct v4l2_v4l_compat *v4l2_v4l_compat;/* * D E V I C E O P E R A T I O N S * *//* * Open a video device. */static intv4l2_video_open(struct inode *inode, struct file *file){ unsigned int minor = MINOR(inode->i_rdev); struct v4l2_device *vfl; int err; if (minor >= V4L2_NUM_DEVICES) return -ENODEV; vfl = v4l2_device[minor];#ifdef CONFIG_KMOD /* KMOD code by Erik Walthinsen */ if((vfl == NULL)&&(video_device[minor] == NULL)) { char modname[20]; sprintf(modname, "char-major-%d-%d", v4l2_major, minor); request_module(modname); vfl = v4l2_device[minor]; }#endif if (vfl == NULL) return video_open(inode, file); if (vfl->open == NULL) return -ENODEV; err = vfl->open(vfl, file->f_flags, &file->private_data); if (err == 0 && file->private_data == NULL) { printk(KERN_ERR"V4L2: Device returned NULL open id\n"); err = -ENODEV; } if (err == 0) ++vfl->busy; return err;}/* * Last close of a struct file */ static intv4l2_video_release(struct inode *inode, struct file *file){ struct v4l2_device *vfl = v4l2_device[MINOR(inode->i_rdev)]; if(!vfl) return video_release(inode, file); if (vfl->close) vfl->close(file->private_data); file->private_data = NULL; if (vfl->busy) --vfl->busy; return 0;}/* * Read from a video device */static ssize_tv4l2_video_read(struct file *file, char *buf, size_t count, loff_t *ppos){ struct v4l2_device *vfl = v4l2_device[MINOR(file->f_dentry->d_inode->i_rdev)]; if(!vfl) return video_read(file, buf, count, ppos); if (vfl->read) return vfl->read(file->private_data, buf, count, file->f_flags & O_NONBLOCK); return -EINVAL;}/* * Write to a video device */static ssize_tv4l2_video_write(struct file *file, const char *buf, size_t count, loff_t *ppos){ struct v4l2_device *vfl = v4l2_device[MINOR(file->f_dentry->d_inode->i_rdev)]; if(!vfl) return video_write(file, buf, count, ppos); if (vfl->write) return vfl->write(file->private_data, buf, count, file->f_flags & O_NONBLOCK); return 0;}/* * IO Control */static voidfill_ctrl_category(struct v4l2_queryctrl *qc);static intv4l2_video_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ struct v4l2_device *vfl = v4l2_device[MINOR(inode->i_rdev)]; char targ[V4L2_MAX_IOCTL_SIZE]; void *parg = (void *)arg; int err = -EINVAL; if (!vfl) return video_ioctl(inode, file, cmd, arg); if (vfl->ioctl == NULL) return -EINVAL; /* Copy arguments into temp kernel buffer */ switch (_IOC_DIR(cmd)) { case _IOC_NONE: parg = (void *)arg; break; case _IOC_WRITE: case (_IOC_WRITE | _IOC_READ): /* Some v4l ioctls that are read/write are flagged read-only */ case _IOC_READ: if (_IOC_SIZE(cmd) > sizeof(targ)) { printk(KERN_ERR"V4L2: ioctl 0x%08x arguments are " "too big, > %d\n", cmd, sizeof(targ)); break;/* Arguments are too big. */ } if (copy_from_user(targ, (void *)arg, _IOC_SIZE(cmd))) { printk(KERN_INFO"V4L2: Fault on write ioctl 0x%08x " "copying data from user buffer\n", cmd); return -EFAULT; } parg = targ; break; } /* Fill in the category for pre-defined controls */ if (cmd == VIDIOC_QUERYCTRL) fill_ctrl_category((struct v4l2_queryctrl *)parg); /* Try passing it to the driver first */ err = vfl->ioctl(file->private_data, cmd, parg); /* If the driver doesn't recognize it and it's an old ioctl, pass it through the translation layer. */ if (err == -ENOIOCTLCMD && _IOC_TYPE(cmd) == 'v' && v4l2_v4l_compat != NULL) { err = v4l2_v4l_compat->translate_ioctl( file, vfl, file->private_data, cmd, parg); } /* Copy results into user buffer */ switch (_IOC_DIR(cmd)) { case _IOC_READ: case (_IOC_WRITE | _IOC_READ): if (parg == targ && copy_to_user((void *)arg, parg, _IOC_SIZE(cmd))) { printk(KERN_INFO"V4L2: Fault on read ioctl 0x%08x " "copying results to user buffer\n", cmd); return -EFAULT; } break; } if (err != -ENOIOCTLCMD) return err; /* Handle ioctls not recognized by the driver */ return -EINVAL;}/* * Memory mapping */ static intv4l2_video_mmap(struct file *file, struct vm_area_struct *vma){ struct v4l2_device *vfl = v4l2_device[MINOR(file->f_dentry->d_inode->i_rdev)]; int err; if(!vfl) return video_mmap(file, vma); if (vfl->mmap) { /* For v4l compatibility. v4l apps typically pass zero */ /* for the offset, needs fixup. */ if (v4l2_v4l_compat != NULL) v4l2_v4l_compat->fix_offset(file, vfl, vma); vma->vm_file = file; err = vfl->mmap(file->private_data, vma);#if LINUX_VERSION_CODE < 0x020203 /* This is now done in the kernel, as it should be */ if (err == 0 && vma->vm_file != NULL) ++vma->vm_file->f_count;#endif return err; } return -ENODEV;}/* * Poll (select()) support */static unsigned intv4l2_video_poll(struct file *file, poll_table *table){ struct v4l2_device *vfl = v4l2_device[MINOR(file->f_dentry->d_inode->i_rdev)]; if(!vfl) return video_poll(file, table); if (vfl->poll) return vfl->poll(file->private_data, file, table); return POLLERR;}/* * Not used. */ static loff_tv4l2_video_llseek(struct file *file, loff_t offset, int origin){ return -ESPIPE;}/* * CONTROL CATEGORIES */static voidfill_ctrl_category(struct v4l2_queryctrl *qc){ if ((qc->id >= V4L2_CID_BRIGHTNESS && qc->id <= V4L2_CID_HUE) || (qc->id >= V4L2_CID_BLACK_LEVEL && qc->id <= V4L2_CID_LASTP1-1)) { qc->category = V4L2_CTRL_CAT_VIDEO; strcpy(qc->group, "Video"); } else if ((qc->id >= V4L2_CID_AUDIO_VOLUME && qc->id <= V4L2_CID_AUDIO_LOUDNESS)) { qc->category = V4L2_CTRL_CAT_AUDIO; strcpy(qc->group, "Audio"); } else if ((qc->id >= V4L2_CID_EFFECT_BASE && qc->id <= V4L2_CID_EFFECT_BASE + 10000)) { qc->category = V4L2_CTRL_CAT_EFFECT; strcpy(qc->group, "Effect"); } else { strcpy(qc->group, "Private"); }}#if defined(CONFIG_PROC_FS) || defined(CONFIG_DEVFS_FS)static char *device_types[] ={ "capture", "codec", "output", "effects", "vbi", "vtr", "teletext", "radio", "undef", "undef", "undef", "undef",};#endif/* * D E V I C E R E G I S T R A T I O N * * Video for Linux Two device drivers request registration here. */intv4l2_register_device(struct v4l2_device *vfl){ int i = 0; int err;#if (LINUX_VERSION_CODE >= 0x020300) && \ (defined(CONFIG_PROC_FS) || defined(CONFIG_DEVFS_FS)) char *base_name; char name[32];#endif if (vfl == NULL) { printk(KERN_ERR"V4L2: v4l2_register_device() passed" " a NULL pointer!\n"); return -1; } i = vfl->minor; if (vfl->open == NULL) { printk(KERN_ERR "V4L2: Device %d has no open method\n", i); return -1; } if (i < 0 || i >= V4L2_NUM_DEVICES) { printk(KERN_ERR"V4L2: Minor value %d is out of range\n", i); return -1; } if (v4l2_device[i] != NULL) { printk(KERN_ERR"V4L2: %s and %s have both been assigned" " minor %d\n", v4l2_device[i]->name, vfl->name, i); return 1; } if (video_device[i] != NULL) { printk(KERN_ERR"V4L2: %s(v4l1) and %s(v4l2) have both been assigned" " minor %d\n", video_device[i]->name, vfl->name, i); return 1; } v4l2_device[i] = vfl; /* The init call may sleep so we book the slot out then call */ MOD_INC_USE_COUNT; err = 0; if (vfl->initialize) err = vfl->initialize(vfl); if (err < 0) { printk(KERN_ERR "V4L2: %s initialize method failed\n", vfl->name); v4l2_device[i] = NULL; MOD_DEC_USE_COUNT; return err; } vfl->busy = 0; vfl->name[sizeof(vfl->name) - 1] = 0; printk(KERN_INFO"V4L2: Registered \"%s\" as char device %d, %d\n", vfl->name, v4l2_major, vfl->minor);#ifdef CONFIG_KMOD /* Try loading the v4l compatibility layer */ if (v4l2_v4l_compat == NULL) request_module("v4l_compat");#endif#if (LINUX_VERSION_CODE >= 0x020300) && \ defined(CONFIG_PROC_FS) || defined(CONFIG_DEVFS_FS) if (vfl->type >= 0 && vfl->type < sizeof(device_types)/sizeof(char*)) base_name = device_types[vfl->type]; else if (vfl->type >= V4L2_TYPE_PRIVATE) base_name = "private"; else base_name = "undef"; #if defined(CONFIG_PROC_FS) sprintf(name, "%s%i", base_name, i); v4l2_proc_create_dev (vfl, name);#endif /* CONFIG_PROCFS */#endif#ifdef CONFIG_DEVFS_FS /* * Start the device root only. Anything else * has serious privacy issues. */ if (vfl->devfs_devname[0]==0) sprintf (name, "v4l2/%s%d", base_name, i); else sprintf (name, "v4l2/%s", vfl->devfs_devname); vfl->devfs_handle = devfs_register (NULL, name, DEVFS_FL_DEFAULT, v4l2_major, vfl->minor, S_IFCHR | S_IRUSR | S_IWUSR, &v4l2_fops, NULL);#endif memset(vfl->v4l2_reserved, 0, sizeof(vfl->v4l2_reserved)); vfl->v4l2_priv = NULL; return 0;}/* * Unregister an unused video for linux device */voidv4l2_unregister_device(struct v4l2_device *vfl){ if (vfl->minor < 0 || vfl->minor >= V4L2_NUM_DEVICES || v4l2_device[vfl->minor] != vfl) { printk(KERN_ERR"V4L2: bad unregister\n"); return; }#if (LINUX_VERSION_CODE >= 0x020300) && defined(CONFIG_PROC_FS) /* Add the /proc entry */ v4l2_proc_destroy_dev (vfl);#endif#ifdef CONFIG_DEVFS_FS devfs_unregister (vfl->devfs_handle);#endif v4l2_device[vfl->minor] = NULL; MOD_DEC_USE_COUNT;}/* * Register/unregister v4l back compatibility layer */intv4l2_v4l_compat_register(struct v4l2_v4l_compat *v4l_c){ if (v4l_c == NULL) { printk(KERN_ERR"V4L2: v4l2_register_v4l_compat() passed" " a NULL pointer!\n"); return -1; } if (v4l2_v4l_compat != NULL) { printk(KERN_ERR"V4L2: Attempt to re-register v4l1 " "compatibility layer.\n"); return -1; } if (v4l_c->translate_ioctl == NULL) { printk(KERN_ERR "V4L2: v4l1 compatibility layer has no " "translate_ioctl() method\n"); return -1; } if (v4l_c->fix_offset == NULL) { printk(KERN_ERR "V4L2: v4l1 compatibility layer has no " "fix_offset() method\n"); return -1; } v4l2_v4l_compat = v4l_c; printk(KERN_INFO"V4L2: v4l1 backward compatibility enabled.\n"); return 0;}voidv4l2_v4l_compat_unregister(struct v4l2_v4l_compat *v4l_c){ if (v4l2_v4l_compat != v4l_c) return; v4l2_v4l_compat = NULL; printk(KERN_INFO"V4L2: v4l1 backward compatibility disabled.\n");}/* * / p r o c / v i d e o d e v H A N D L E R */#ifdef CONFIG_PROC_FS/* The actual code is the same, it's the interface what changes */#if 0static intvideo_build_proc(char *buf, char **start, off_t offset, int len, void *data){ struct v4l2_device *vfl; struct video_device *vfl1; int i; char *t;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -