videodev.c
来自「linux 内核源代码」· C语言 代码 · 共 1,829 行 · 第 1/3 页
C
1,829 行
ret=vfd->vidioc_enumaudout(file, fh, p); if (!ret) dbgarg2("index=%d, name=%s, capability=%d, " "mode=%d\n", p->index, p->name, p->capability,p->mode); break; } case VIDIOC_G_AUDOUT: { struct v4l2_audioout *p=arg; if (!vfd->vidioc_g_audout) break; dbgarg(cmd, "Enum for index=%d\n", p->index); ret=vfd->vidioc_g_audout(file, fh, p); if (!ret) dbgarg2("index=%d, name=%s, capability=%d, " "mode=%d\n", p->index, p->name, p->capability,p->mode); break; } case VIDIOC_S_AUDOUT: { struct v4l2_audioout *p=arg; if (!vfd->vidioc_s_audout) break; dbgarg(cmd, "index=%d, name=%s, capability=%d, " "mode=%d\n", p->index, p->name, p->capability,p->mode); ret=vfd->vidioc_s_audout(file, fh, p); break; } case VIDIOC_G_MODULATOR: { struct v4l2_modulator *p=arg; if (!vfd->vidioc_g_modulator) break; ret=vfd->vidioc_g_modulator(file, fh, p); if (!ret) dbgarg(cmd, "index=%d, name=%s, " "capability=%d, rangelow=%d," " rangehigh=%d, txsubchans=%d\n", p->index, p->name,p->capability, p->rangelow, p->rangehigh, p->txsubchans); break; } case VIDIOC_S_MODULATOR: { struct v4l2_modulator *p=arg; if (!vfd->vidioc_s_modulator) break; dbgarg(cmd, "index=%d, name=%s, capability=%d, " "rangelow=%d, rangehigh=%d, txsubchans=%d\n", p->index, p->name,p->capability,p->rangelow, p->rangehigh,p->txsubchans); ret=vfd->vidioc_s_modulator(file, fh, p); break; } case VIDIOC_G_CROP: { struct v4l2_crop *p=arg; if (!vfd->vidioc_g_crop) break; ret=vfd->vidioc_g_crop(file, fh, p); if (!ret) { dbgarg(cmd, "type=%d\n", p->type); dbgrect(vfd, "", &p->c); } break; } case VIDIOC_S_CROP: { struct v4l2_crop *p=arg; if (!vfd->vidioc_s_crop) break; dbgarg(cmd, "type=%d\n", p->type); dbgrect(vfd, "", &p->c); ret=vfd->vidioc_s_crop(file, fh, p); break; } case VIDIOC_CROPCAP: { struct v4l2_cropcap *p=arg; /*FIXME: Should also show v4l2_fract pixelaspect */ if (!vfd->vidioc_cropcap) break; dbgarg(cmd, "type=%d\n", p->type); dbgrect(vfd, "bounds ", &p->bounds); dbgrect(vfd, "defrect ", &p->defrect); ret=vfd->vidioc_cropcap(file, fh, p); break; } case VIDIOC_G_JPEGCOMP: { struct v4l2_jpegcompression *p=arg; if (!vfd->vidioc_g_jpegcomp) break; ret=vfd->vidioc_g_jpegcomp(file, fh, p); if (!ret) dbgarg (cmd, "quality=%d, APPn=%d, " "APP_len=%d, COM_len=%d, " "jpeg_markers=%d\n", p->quality,p->APPn,p->APP_len, p->COM_len,p->jpeg_markers); break; } case VIDIOC_S_JPEGCOMP: { struct v4l2_jpegcompression *p=arg; if (!vfd->vidioc_g_jpegcomp) break; dbgarg (cmd, "quality=%d, APPn=%d, APP_len=%d, " "COM_len=%d, jpeg_markers=%d\n", p->quality,p->APPn,p->APP_len, p->COM_len,p->jpeg_markers); ret=vfd->vidioc_s_jpegcomp(file, fh, p); break; } case VIDIOC_G_ENC_INDEX: { struct v4l2_enc_idx *p=arg; if (!vfd->vidioc_g_enc_index) break; ret=vfd->vidioc_g_enc_index(file, fh, p); if (!ret) dbgarg (cmd, "entries=%d, entries_cap=%d\n", p->entries,p->entries_cap); break; } case VIDIOC_ENCODER_CMD: { struct v4l2_encoder_cmd *p=arg; if (!vfd->vidioc_encoder_cmd) break; ret=vfd->vidioc_encoder_cmd(file, fh, p); if (!ret) dbgarg (cmd, "cmd=%d, flags=%d\n", p->cmd,p->flags); break; } case VIDIOC_TRY_ENCODER_CMD: { struct v4l2_encoder_cmd *p=arg; if (!vfd->vidioc_try_encoder_cmd) break; ret=vfd->vidioc_try_encoder_cmd(file, fh, p); if (!ret) dbgarg (cmd, "cmd=%d, flags=%d\n", p->cmd,p->flags); break; } case VIDIOC_G_PARM: { struct v4l2_streamparm *p=arg; __u32 type=p->type; memset(p,0,sizeof(*p)); p->type=type; if (vfd->vidioc_g_parm) { ret=vfd->vidioc_g_parm(file, fh, p); } else { struct v4l2_standard s; if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; v4l2_video_std_construct(&s, vfd->current_norm, v4l2_norm_to_name(vfd->current_norm)); p->parm.capture.timeperframe = s.frameperiod; ret=0; } dbgarg (cmd, "type=%d\n", p->type); break; } case VIDIOC_S_PARM: { struct v4l2_streamparm *p=arg; if (!vfd->vidioc_s_parm) break; dbgarg (cmd, "type=%d\n", p->type); ret=vfd->vidioc_s_parm(file, fh, p); break; } case VIDIOC_G_TUNER: { struct v4l2_tuner *p=arg; __u32 index=p->index; if (!vfd->vidioc_g_tuner) break; memset(p,0,sizeof(*p)); p->index=index; ret=vfd->vidioc_g_tuner(file, fh, p); if (!ret) dbgarg (cmd, "index=%d, name=%s, type=%d, " "capability=%d, rangelow=%d, " "rangehigh=%d, signal=%d, afc=%d, " "rxsubchans=%d, audmode=%d\n", p->index, p->name, p->type, p->capability, p->rangelow, p->rangehigh, p->rxsubchans, p->audmode, p->signal, p->afc); break; } case VIDIOC_S_TUNER: { struct v4l2_tuner *p=arg; if (!vfd->vidioc_s_tuner) break; dbgarg (cmd, "index=%d, name=%s, type=%d, " "capability=%d, rangelow=%d, rangehigh=%d, " "signal=%d, afc=%d, rxsubchans=%d, " "audmode=%d\n",p->index, p->name, p->type, p->capability, p->rangelow,p->rangehigh, p->rxsubchans, p->audmode, p->signal, p->afc); ret=vfd->vidioc_s_tuner(file, fh, p); break; } case VIDIOC_G_FREQUENCY: { struct v4l2_frequency *p=arg; if (!vfd->vidioc_g_frequency) break; memset(p,0,sizeof(*p)); ret=vfd->vidioc_g_frequency(file, fh, p); if (!ret) dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n", p->tuner,p->type,p->frequency); break; } case VIDIOC_S_FREQUENCY: { struct v4l2_frequency *p=arg; if (!vfd->vidioc_s_frequency) break; dbgarg (cmd, "tuner=%d, type=%d, frequency=%d\n", p->tuner,p->type,p->frequency); ret=vfd->vidioc_s_frequency(file, fh, p); break; } case VIDIOC_G_SLICED_VBI_CAP: { struct v4l2_sliced_vbi_cap *p=arg; if (!vfd->vidioc_g_sliced_vbi_cap) break; ret=vfd->vidioc_g_sliced_vbi_cap(file, fh, p); if (!ret) dbgarg (cmd, "service_set=%d\n", p->service_set); break; } case VIDIOC_LOG_STATUS: { if (!vfd->vidioc_log_status) break; ret=vfd->vidioc_log_status(file, fh); break; }#ifdef CONFIG_VIDEO_ADV_DEBUG case VIDIOC_DBG_G_REGISTER: { struct v4l2_register *p=arg; if (!capable(CAP_SYS_ADMIN)) ret=-EPERM; else if (vfd->vidioc_g_register) ret=vfd->vidioc_g_register(file, fh, p); break; } case VIDIOC_DBG_S_REGISTER: { struct v4l2_register *p=arg; if (!capable(CAP_SYS_ADMIN)) ret=-EPERM; else if (vfd->vidioc_s_register) ret=vfd->vidioc_s_register(file, fh, p); break; }#endif case VIDIOC_G_CHIP_IDENT: { struct v4l2_chip_ident *p=arg; if (!vfd->vidioc_g_chip_ident) break; ret=vfd->vidioc_g_chip_ident(file, fh, p); if (!ret) dbgarg (cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision); break; } } /* switch */ if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { if (ret<0) { printk ("%s: err:\n", vfd->name); v4l_print_ioctl(vfd->name, cmd); } } return ret;}int video_ioctl2 (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ char sbuf[128]; void *mbuf = NULL; void *parg = NULL; int err = -EINVAL; int is_ext_ctrl; size_t ctrls_size = 0; void __user *user_ptr = NULL;#ifdef __OLD_VIDIOC_ cmd = video_fix_command(cmd);#endif is_ext_ctrl = (cmd == VIDIOC_S_EXT_CTRLS || cmd == VIDIOC_G_EXT_CTRLS || cmd == VIDIOC_TRY_EXT_CTRLS); /* Copy arguments into temp kernel buffer */ switch (_IOC_DIR(cmd)) { case _IOC_NONE: parg = NULL; break; case _IOC_READ: case _IOC_WRITE: case (_IOC_WRITE | _IOC_READ): if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { parg = sbuf; } else { /* too big to allocate from stack */ mbuf = kmalloc(_IOC_SIZE(cmd),GFP_KERNEL); if (NULL == mbuf) return -ENOMEM; parg = mbuf; } err = -EFAULT; if (_IOC_DIR(cmd) & _IOC_WRITE) if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) goto out; break; } if (is_ext_ctrl) { struct v4l2_ext_controls *p = parg; /* In case of an error, tell the caller that it wasn't a specific control that caused it. */ p->error_idx = p->count; user_ptr = (void __user *)p->controls; if (p->count) { ctrls_size = sizeof(struct v4l2_ext_control) * p->count; /* Note: v4l2_ext_controls fits in sbuf[] so mbuf is still NULL. */ mbuf = kmalloc(ctrls_size, GFP_KERNEL); err = -ENOMEM; if (NULL == mbuf) goto out_ext_ctrl; err = -EFAULT; if (copy_from_user(mbuf, user_ptr, ctrls_size)) goto out_ext_ctrl; p->controls = mbuf; } } /* Handles IOCTL */ err = __video_do_ioctl(inode, file, cmd, parg); if (err == -ENOIOCTLCMD) err = -EINVAL; if (is_ext_ctrl) { struct v4l2_ext_controls *p = parg; p->controls = (void *)user_ptr; if (p->count && err == 0 && copy_to_user(user_ptr, mbuf, ctrls_size)) err = -EFAULT; goto out_ext_ctrl; } if (err < 0) goto out;out_ext_ctrl: /* Copy results into user buffer */ switch (_IOC_DIR(cmd)) { case _IOC_READ: case (_IOC_WRITE | _IOC_READ): if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) err = -EFAULT; break; }out: kfree(mbuf); return err;}static const struct file_operations video_fops;/** * video_register_device - register video4linux devices * @vfd: video device structure we want to register * @type: type of device to register * @nr: which device number (0 == /dev/video0, 1 == /dev/video1, ... * -1 == first free) * * The registration code assigns minor numbers based on the type * requested. -ENFILE is returned in all the device slots for this * category are full. If not then the minor field is set and the * driver initialize function is called (if non %NULL). * * Zero is returned on success. * * Valid types are * * %VFL_TYPE_GRABBER - A frame grabber * * %VFL_TYPE_VTX - A teletext device * * %VFL_TYPE_VBI - Vertical blank data (undecoded) * * %VFL_TYPE_RADIO - A radio card */int video_register_device(struct video_device *vfd, int type, int nr){ int i=0; int base; int end; int ret; char *name_base; switch(type) { case VFL_TYPE_GRABBER: base=MINOR_VFL_TYPE_GRABBER_MIN; end=MINOR_VFL_TYPE_GRABBER_MAX+1; name_base = "video"; break; case VFL_TYPE_VTX: base=MINOR_VFL_TYPE_VTX_MIN; end=MINOR_VFL_TYPE_VTX_MAX+1; name_base = "vtx"; break; case VFL_TYPE_VBI: base=MINOR_VFL_TYPE_VBI_MIN; end=MINOR_VFL_TYPE_VBI_MAX+1; name_base = "vbi"; break; case VFL_TYPE_RADIO: base=MINOR_VFL_TYPE_RADIO_MIN; end=MINOR_VFL_TYPE_RADIO_MAX+1; name_base = "radio"; break; default: printk(KERN_ERR "%s called with unknown type: %d\n", __FUNCTION__, type); return -1; } /* pick a minor number */ mutex_lock(&videodev_lock); if (nr >= 0 && nr < end-base) { /* use the one the driver asked for */ i = base+nr; if (NULL != video_device[i]) { mutex_unlock(&videodev_lock); return -ENFILE; } } else { /* use first free */ for(i=base;i<end;i++) if (NULL == video_device[i]) break; if (i == end) { mutex_unlock(&videodev_lock); return -ENFILE; } } video_device[i]=vfd; vfd->minor=i; mutex_unlock(&videodev_lock); mutex_init(&vfd->lock); /* sysfs class */ memset(&vfd->class_dev, 0x00, sizeof(vfd->class_dev)); if (vfd->dev) vfd->class_dev.parent = vfd->dev; vfd->class_dev.class = &video_class; vfd->class_dev.devt = MKDEV(VIDEO_MAJOR, vfd->minor); sprintf(vfd->class_dev.bus_id, "%s%d", name_base, i - base); ret = device_register(&vfd->class_dev); if (ret < 0) { printk(KERN_ERR "%s: device_register failed\n", __FUNCTION__); goto fail_minor; }#if 1 /* needed until all drivers are fixed */ if (!vfd->release) printk(KERN_WARNING "videodev: \"%s\" has no release callback. " "Please fix your driver for proper sysfs support, see " "http://lwn.net/Articles/36850/\n", vfd->name);#endif return 0;fail_minor: mutex_lock(&videodev_lock); video_device[vfd->minor] = NULL; vfd->minor = -1; mutex_unlock(&videodev_lock); return ret;}/** * video_unregister_device - unregister a video4linux device * @vfd: the device to unregister * * This unregisters the passed device and deassigns the minor * number. Future open calls will be met with errors. */void video_unregister_device(struct video_device *vfd){ mutex_lock(&videodev_lock); if(video_device[vfd->minor]!=vfd) panic("videodev: bad unregister"); video_device[vfd->minor]=NULL; device_unregister(&vfd->class_dev); mutex_unlock(&videodev_lock);}/* * Video fs operations */static const struct file_operations video_fops={ .owner = THIS_MODULE, .llseek = no_llseek, .open = video_open,};/* * Initialise video for linux */static int __init videodev_init(void){ int ret; printk(KERN_INFO "Linux video capture interface: v2.00\n"); if (register_chrdev(VIDEO_MAJOR, VIDEO_NAME, &video_fops)) { printk(KERN_WARNING "video_dev: unable to get major %d\n", VIDEO_MAJOR); return -EIO; } ret = class_register(&video_class); if (ret < 0) { unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME); printk(KERN_WARNING "video_dev: class_register failed\n"); return -EIO; } return 0;}static void __exit videodev_exit(void){ class_unregister(&video_class); unregister_chrdev(VIDEO_MAJOR, VIDEO_NAME);}module_init(videodev_init)module_exit(videodev_exit)EXPORT_SYMBOL(video_register_device);EXPORT_SYMBOL(video_unregister_device);EXPORT_SYMBOL(video_devdata);EXPORT_SYMBOL(video_usercopy);EXPORT_SYMBOL(video_exclusive_open);EXPORT_SYMBOL(video_exclusive_release);EXPORT_SYMBOL(video_ioctl2);EXPORT_SYMBOL(video_device_alloc);EXPORT_SYMBOL(video_device_release);MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>");MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2");MODULE_LICENSE("GPL");/* * Local variables: * c-basic-offset: 8 * End: */
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?