📄 usbvision-video.c
字号:
vfd->pixelformat = usbvision_v4l2_format[vfd->index].format; memset(vfd->reserved, 0, sizeof(vfd->reserved)); return 0;}static int vidioc_g_fmt_vid_cap (struct file *file, void *priv, struct v4l2_format *vf){ struct usb_usbvision *usbvision = video_drvdata(file); vf->fmt.pix.width = usbvision->curwidth; vf->fmt.pix.height = usbvision->curheight; vf->fmt.pix.pixelformat = usbvision->palette.format; vf->fmt.pix.bytesperline = usbvision->curwidth*usbvision->palette.bytes_per_pixel; vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*usbvision->curheight; vf->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; vf->fmt.pix.field = V4L2_FIELD_NONE; /* Always progressive image */ return 0;}static int vidioc_try_fmt_vid_cap (struct file *file, void *priv, struct v4l2_format *vf){ struct usb_usbvision *usbvision = video_drvdata(file); int formatIdx; /* Find requested format in available ones */ for(formatIdx=0;formatIdx<USBVISION_SUPPORTED_PALETTES;formatIdx++) { if(vf->fmt.pix.pixelformat == usbvision_v4l2_format[formatIdx].format) { usbvision->palette = usbvision_v4l2_format[formatIdx]; break; } } /* robustness */ if(formatIdx == USBVISION_SUPPORTED_PALETTES) { return -EINVAL; } RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH); RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT); vf->fmt.pix.bytesperline = vf->fmt.pix.width* usbvision->palette.bytes_per_pixel; vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*vf->fmt.pix.height; return 0;}static int vidioc_s_fmt_vid_cap(struct file *file, void *priv, struct v4l2_format *vf){ struct usb_usbvision *usbvision = video_drvdata(file); int ret; if( 0 != (ret=vidioc_try_fmt_vid_cap (file, priv, vf)) ) { return ret; } /* stop io in case it is already in progress */ if(usbvision->streaming == Stream_On) { if ((ret = usbvision_stream_interrupt(usbvision))) return ret; } usbvision_frames_free(usbvision); usbvision_empty_framequeues(usbvision); usbvision->curFrame = NULL; /* by now we are committed to the new data... */ mutex_lock(&usbvision->lock); usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height); mutex_unlock(&usbvision->lock); return 0;}static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf, size_t count, loff_t *ppos){ struct usb_usbvision *usbvision = video_drvdata(file); int noblock = file->f_flags & O_NONBLOCK; unsigned long lock_flags; int ret,i; struct usbvision_frame *frame; PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __func__, (unsigned long)count, noblock); if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL)) return -EFAULT; /* This entry point is compatible with the mmap routines so that a user can do either VIDIOC_QBUF/VIDIOC_DQBUF to get frames or call read on the device. */ if(!usbvision->num_frames) { /* First, allocate some frames to work with if this has not been done with VIDIOC_REQBUF */ usbvision_frames_free(usbvision); usbvision_empty_framequeues(usbvision); usbvision_frames_alloc(usbvision,USBVISION_NUMFRAMES); } if(usbvision->streaming != Stream_On) { /* no stream is running, make it running ! */ usbvision->streaming = Stream_On; call_i2c_clients(usbvision,VIDIOC_STREAMON , NULL); } /* Then, enqueue as many frames as possible (like a user of VIDIOC_QBUF would do) */ for(i=0;i<usbvision->num_frames;i++) { frame = &usbvision->frame[i]; if(frame->grabstate == FrameState_Unused) { /* Mark it as ready and enqueue frame */ frame->grabstate = FrameState_Ready; frame->scanstate = ScanState_Scanning; /* Accumulated in usbvision_parse_data() */ frame->scanlength = 0; /* set v4l2_format index */ frame->v4l2_format = usbvision->palette; spin_lock_irqsave(&usbvision->queue_lock, lock_flags); list_add_tail(&frame->frame, &usbvision->inqueue); spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); } } /* Then try to steal a frame (like a VIDIOC_DQBUF would do) */ if (list_empty(&(usbvision->outqueue))) { if(noblock) return -EAGAIN; ret = wait_event_interruptible (usbvision->wait_frame, !list_empty(&(usbvision->outqueue))); if (ret) return ret; } spin_lock_irqsave(&usbvision->queue_lock, lock_flags); frame = list_entry(usbvision->outqueue.next, struct usbvision_frame, frame); list_del(usbvision->outqueue.next); spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags); /* An error returns an empty frame */ if (frame->grabstate == FrameState_Error) { frame->bytes_read = 0; return 0; } PDEBUG(DBG_IO, "%s: frmx=%d, bytes_read=%ld, scanlength=%ld", __func__, frame->index, frame->bytes_read, frame->scanlength); /* copy bytes to user space; we allow for partials reads */ if ((count + frame->bytes_read) > (unsigned long)frame->scanlength) count = frame->scanlength - frame->bytes_read; if (copy_to_user(buf, frame->data + frame->bytes_read, count)) { return -EFAULT; } frame->bytes_read += count; PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld", __func__, (unsigned long)count, frame->bytes_read); /* For now, forget the frame if it has not been read in one shot. *//* if (frame->bytes_read >= frame->scanlength) {// All data has been read */ frame->bytes_read = 0; /* Mark it as available to be used again. */ frame->grabstate = FrameState_Unused;/* } */ return count;}static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma){ unsigned long size = vma->vm_end - vma->vm_start, start = vma->vm_start; void *pos; u32 i; struct usb_usbvision *usbvision = video_drvdata(file); PDEBUG(DBG_MMAP, "mmap"); mutex_lock(&usbvision->lock); if (!USBVISION_IS_OPERATIONAL(usbvision)) { mutex_unlock(&usbvision->lock); return -EFAULT; } if (!(vma->vm_flags & VM_WRITE) || size != PAGE_ALIGN(usbvision->max_frame_size)) { mutex_unlock(&usbvision->lock); return -EINVAL; } for (i = 0; i < usbvision->num_frames; i++) { if (((PAGE_ALIGN(usbvision->max_frame_size)*i) >> PAGE_SHIFT) == vma->vm_pgoff) break; } if (i == usbvision->num_frames) { PDEBUG(DBG_MMAP, "mmap: user supplied mapping address is out of range"); mutex_unlock(&usbvision->lock); return -EINVAL; } /* VM_IO is eventually going to replace PageReserved altogether */ vma->vm_flags |= VM_IO; vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */ pos = usbvision->frame[i].data; while (size > 0) { if (vm_insert_page(vma, start, vmalloc_to_page(pos))) { PDEBUG(DBG_MMAP, "mmap: vm_insert_page failed"); mutex_unlock(&usbvision->lock); return -EAGAIN; } start += PAGE_SIZE; pos += PAGE_SIZE; size -= PAGE_SIZE; } mutex_unlock(&usbvision->lock); return 0;}/* * Here comes the stuff for radio on usbvision based devices * */static int usbvision_radio_open(struct inode *inode, struct file *file){ struct usb_usbvision *usbvision = video_drvdata(file); int errCode = 0; PDEBUG(DBG_IO, "%s:", __func__); mutex_lock(&usbvision->lock); if (usbvision->user) { err("%s: Someone tried to open an already opened USBVision Radio!", __func__); errCode = -EBUSY; } else { if(PowerOnAtOpen) { usbvision_reset_powerOffTimer(usbvision); if (usbvision->power == 0) { usbvision_power_on(usbvision); usbvision_i2c_register(usbvision); } } /* Alternate interface 1 is is the biggest frame size */ errCode = usbvision_set_alternate(usbvision); if (errCode < 0) { usbvision->last_error = errCode; errCode = -EBUSY; goto out; } // If so far no errors then we shall start the radio usbvision->radio = 1; call_i2c_clients(usbvision,AUDC_SET_RADIO,&usbvision->tuner_type); usbvision_set_audio(usbvision, USBVISION_AUDIO_RADIO); usbvision->user++; } if (errCode) { if (PowerOnAtOpen) { usbvision_i2c_unregister(usbvision); usbvision_power_off(usbvision); usbvision->initialized = 0; } }out: mutex_unlock(&usbvision->lock); return errCode;}static int usbvision_radio_close(struct inode *inode, struct file *file){ struct usb_usbvision *usbvision = video_drvdata(file); int errCode = 0; PDEBUG(DBG_IO, ""); mutex_lock(&usbvision->lock); /* Set packet size to 0 */ usbvision->ifaceAlt=0; errCode = usb_set_interface(usbvision->dev, usbvision->iface, usbvision->ifaceAlt); usbvision_audio_off(usbvision); usbvision->radio=0; usbvision->user--; if (PowerOnAtOpen) { usbvision_set_powerOffTimer(usbvision); usbvision->initialized = 0; } mutex_unlock(&usbvision->lock); if (usbvision->remove_pending) { printk(KERN_INFO "%s: Final disconnect\n", __func__); usbvision_release(usbvision); } PDEBUG(DBG_IO, "success"); return errCode;}/* * Here comes the stuff for vbi on usbvision based devices * */static int usbvision_vbi_open(struct inode *inode, struct file *file){ /* TODO */ return -ENODEV;}static int usbvision_vbi_close(struct inode *inode, struct file *file){ /* TODO */ return -ENODEV;}static int usbvision_do_vbi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, void *arg){ /* TODO */ return -ENOIOCTLCMD;}static int usbvision_vbi_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ return video_usercopy(inode, file, cmd, arg, usbvision_do_vbi_ioctl);}//// Video registration stuff//// Video templatestatic const struct file_operations usbvision_fops = { .owner = THIS_MODULE, .open = usbvision_v4l2_open, .release = usbvision_v4l2_close, .read = usbvision_v4l2_read, .mmap = usbvision_v4l2_mmap, .ioctl = video_ioctl2, .llseek = no_llseek,/* .poll = video_poll, */ .compat_ioctl = v4l_compat_ioctl32,};static const struct v4l2_ioctl_ops usbvision_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap, .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap, .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap, .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap, .vidioc_reqbufs = vidioc_reqbufs, .vidioc_querybuf = vidioc_querybuf, .vidioc_qbuf = vidioc_qbuf, .vidioc_dqbuf = vidioc_dqbuf, .vidioc_s_std = vidioc_s_std, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, .vidioc_queryctrl = vidioc_queryctrl, .vidioc_g_audio = vidioc_g_audio, .vidioc_s_audio = vidioc_s_audio, .vidioc_g_ctrl = vidioc_g_ctrl, .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_streamon = vidioc_streamon, .vidioc_streamoff = vidioc_streamoff,#ifdef CONFIG_VIDEO_V4L1_COMPAT/* .vidiocgmbuf = vidiocgmbuf, */#endif .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency,#ifdef CONFIG_VIDEO_ADV_DEBUG .vidioc_g_register = vidioc_g_register, .vidioc_s_register = vidioc_s_register,#endif};static struct video_device usbvision_video_template = { .fops = &usbvision_fops, .ioctl_ops = &usbvision_ioctl_ops, .name = "usbvision-video", .release = video_device_release, .minor = -1, .tvnorms = USBVISION_NORMS, .current_norm = V4L2_STD_PAL};// Radio templatestatic const struct file_operations usbvision_radio_fops = { .owner = THIS_MODULE, .open = usbvision_radio_open, .release = usbvision_radio_close, .ioctl = video_ioctl2, .llseek = no_llseek, .compat_ioctl = v4l_compat_ioctl32,};static const struct v4l2_ioctl_ops usbvision_radio_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_enum_input = vidioc_enum_input, .vidioc_g_input = vidioc_g_input, .vidioc_s_input = vidioc_s_input, .vidioc_queryctrl = vidioc_queryctrl, .vidioc_g_audio = vidioc_g_audio, .vidioc_s_audio = vidioc_s_audio, .vidioc_g_ctrl = vidioc_g_ctrl, .vidioc_s_ctrl = vidioc_s_ctrl, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, .vidioc_g_frequency = vidioc_g_frequency, .vidioc_s_frequency = vidioc_s_frequency,};static struct video_device usbvision_radio_template = { .fops = &usbvision_radio_fops, .name = "usbvision-radio", .release = video_device_release, .minor = -1, .ioctl_ops = &usbvision_radio_ioctl_ops, .tvnorms = USBVISION_NORMS, .current_norm = V4L2_STD_PAL};// vbi templatestatic const struct file_operations usbvision_vbi_fops = { .owner = THIS_MODULE, .open = usbvision_vbi_open, .release = usbvision_vbi_close, .ioctl = usbvision_vbi_ioctl, .llseek = no_llseek, .compat_ioctl = v4l_compat_ioctl32,};static struct video_device usbvision_vbi_template=
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -