diff options
Diffstat (limited to 'drivers/media/pci/cx18')
-rw-r--r-- | drivers/media/pci/cx18/cx18-alsa-main.c | 2 | ||||
-rw-r--r-- | drivers/media/pci/cx18/cx18-driver.h | 3 | ||||
-rw-r--r-- | drivers/media/pci/cx18/cx18-fileops.c | 27 | ||||
-rw-r--r-- | drivers/media/pci/cx18/cx18-ioctl.c | 58 | ||||
-rw-r--r-- | drivers/media/pci/cx18/cx18-streams.c | 66 | ||||
-rw-r--r-- | drivers/media/pci/cx18/cx18-streams.h | 2 |
6 files changed, 82 insertions, 76 deletions
diff --git a/drivers/media/pci/cx18/cx18-alsa-main.c b/drivers/media/pci/cx18/cx18-alsa-main.c index ea272bcb38df..0b0e8015ad34 100644 --- a/drivers/media/pci/cx18/cx18-alsa-main.c +++ b/drivers/media/pci/cx18/cx18-alsa-main.c @@ -216,7 +216,7 @@ static int cx18_alsa_load(struct cx18 *cx) } s = &cx->streams[CX18_ENC_STREAM_TYPE_PCM]; - if (s->video_dev == NULL) { + if (s->video_dev.v4l2_dev == NULL) { CX18_DEBUG_ALSA_INFO("%s: PCM stream for card is disabled - " "skipping\n", __func__); return 0; diff --git a/drivers/media/pci/cx18/cx18-driver.h b/drivers/media/pci/cx18/cx18-driver.h index 207d6e82403b..b15beed2dc14 100644 --- a/drivers/media/pci/cx18/cx18-driver.h +++ b/drivers/media/pci/cx18/cx18-driver.h @@ -373,7 +373,7 @@ struct cx18_in_work_order { struct cx18_stream { /* These first five fields are always set, even if the stream is not actually created. */ - struct video_device *video_dev; /* NULL when stream not created */ + struct video_device video_dev; /* v4l2_dev is NULL when stream not created */ struct cx18_dvb *dvb; /* DVB / Digital Transport */ struct cx18 *cx; /* for ease of use */ const char *name; /* name of the stream */ @@ -409,6 +409,7 @@ struct cx18_stream { /* Videobuf for YUV video */ u32 pixelformat; u32 vb_bytes_per_frame; + u32 vb_bytes_per_line; struct list_head vb_capture; /* video capture queue */ spinlock_t vb_lock; struct timer_list vb_timeout; diff --git a/drivers/media/pci/cx18/cx18-fileops.c b/drivers/media/pci/cx18/cx18-fileops.c index 76a3b4ac541e..df837408efd5 100644 --- a/drivers/media/pci/cx18/cx18-fileops.c +++ b/drivers/media/pci/cx18/cx18-fileops.c @@ -34,6 +34,7 @@ #include "cx18-controls.h" #include "cx18-ioctl.h" #include "cx18-cards.h" +#include <media/v4l2-event.h> /* This function tries to claim the stream for a specific file descriptor. If no one else is using this stream then the stream is claimed and @@ -609,13 +610,16 @@ ssize_t cx18_v4l2_read(struct file *filp, char __user *buf, size_t count, unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait) { + unsigned long req_events = poll_requested_events(wait); struct cx18_open_id *id = file2id(filp); struct cx18 *cx = id->cx; struct cx18_stream *s = &cx->streams[id->type]; int eof = test_bit(CX18_F_S_STREAMOFF, &s->s_flags); + unsigned res = 0; /* Start a capture if there is none */ - if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags)) { + if (!eof && !test_bit(CX18_F_S_STREAMING, &s->s_flags) && + (req_events & (POLLIN | POLLRDNORM))) { int rc; mutex_lock(&cx->serialize_lock); @@ -632,21 +636,26 @@ unsigned int cx18_v4l2_enc_poll(struct file *filp, poll_table *wait) if ((s->vb_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) && (id->type == CX18_ENC_STREAM_TYPE_YUV)) { int videobuf_poll = videobuf_poll_stream(filp, &s->vbuf_q, wait); + + if (v4l2_event_pending(&id->fh)) + res |= POLLPRI; if (eof && videobuf_poll == POLLERR) - return POLLHUP; - else - return videobuf_poll; + return res | POLLHUP; + return res | videobuf_poll; } /* add stream's waitq to the poll list */ CX18_DEBUG_HI_FILE("Encoder poll\n"); - poll_wait(filp, &s->waitq, wait); + if (v4l2_event_pending(&id->fh)) + res |= POLLPRI; + else + poll_wait(filp, &s->waitq, wait); if (atomic_read(&s->q_full.depth)) - return POLLIN | POLLRDNORM; + return res | POLLIN | POLLRDNORM; if (eof) - return POLLHUP; - return 0; + return res | POLLHUP; + return res; } int cx18_v4l2_mmap(struct file *file, struct vm_area_struct *vma) @@ -797,7 +806,7 @@ static int cx18_serialized_open(struct cx18_stream *s, struct file *filp) CX18_DEBUG_WARN("nomem on v4l2 open\n"); return -ENOMEM; } - v4l2_fh_init(&item->fh, s->video_dev); + v4l2_fh_init(&item->fh, &s->video_dev); item->cx = cx; item->type = s->type; diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index b8e4b68a9196..79aee30d5fd8 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.c +++ b/drivers/media/pci/cx18/cx18-ioctl.c @@ -39,6 +39,7 @@ #include "cx18-cards.h" #include "cx18-av-core.h" #include <media/tveeprom.h> +#include <media/v4l2-event.h> u16 cx18_service2vbi(int type) { @@ -159,7 +160,7 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh, if (id->type == CX18_ENC_STREAM_TYPE_YUV) { pixfmt->pixelformat = s->pixelformat; pixfmt->sizeimage = s->vb_bytes_per_frame; - pixfmt->bytesperline = 720; + pixfmt->bytesperline = s->vb_bytes_per_line; } else { pixfmt->pixelformat = V4L2_PIX_FMT_MPEG; pixfmt->sizeimage = 128 * 1024; @@ -287,10 +288,13 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh, s->pixelformat = fmt->fmt.pix.pixelformat; /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2))) UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */ - if (s->pixelformat == V4L2_PIX_FMT_HM12) + if (s->pixelformat == V4L2_PIX_FMT_HM12) { s->vb_bytes_per_frame = h * 720 * 3 / 2; - else + s->vb_bytes_per_line = 720; /* First plane */ + } else { s->vb_bytes_per_frame = h * 720 * 2; + s->vb_bytes_per_line = 1440; /* Packed */ + } mbus_fmt.width = cx->cxhdl.width = w; mbus_fmt.height = cx->cxhdl.height = h; @@ -447,34 +451,29 @@ static int cx18_cropcap(struct file *file, void *fh, if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - cropcap->bounds.top = cropcap->bounds.left = 0; - cropcap->bounds.width = 720; - cropcap->bounds.height = cx->is_50hz ? 576 : 480; cropcap->pixelaspect.numerator = cx->is_50hz ? 59 : 10; cropcap->pixelaspect.denominator = cx->is_50hz ? 54 : 11; - cropcap->defrect = cropcap->bounds; return 0; } -static int cx18_s_crop(struct file *file, void *fh, const struct v4l2_crop *crop) -{ - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) - return -EINVAL; - CX18_DEBUG_WARN("VIDIOC_S_CROP not implemented\n"); - return -EINVAL; -} - -static int cx18_g_crop(struct file *file, void *fh, struct v4l2_crop *crop) +static int cx18_g_selection(struct file *file, void *fh, + struct v4l2_selection *sel) { struct cx18 *cx = fh2id(fh)->cx; - if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) + if (sel->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; - CX18_DEBUG_WARN("VIDIOC_G_CROP not implemented\n"); - return -EINVAL; + switch (sel->target) { + case V4L2_SEL_TGT_CROP_BOUNDS: + case V4L2_SEL_TGT_CROP_DEFAULT: + sel->r.top = sel->r.left = 0; + sel->r.width = 720; + sel->r.height = cx->is_50hz ? 576 : 480; + break; + default: + return -EINVAL; + } + return 0; } static int cx18_enum_fmt_vid_cap(struct file *file, void *fh, @@ -510,6 +509,9 @@ int cx18_s_input(struct file *file, void *fh, unsigned int inp) { struct cx18_open_id *id = fh2id(fh); struct cx18 *cx = id->cx; + v4l2_std_id std = V4L2_STD_ALL; + const struct cx18_card_video_input *card_input = + cx->card->video_inputs + inp; if (inp >= cx->nof_inputs) return -EINVAL; @@ -525,6 +527,11 @@ int cx18_s_input(struct file *file, void *fh, unsigned int inp) cx->active_input = inp; /* Set the audio input to whatever is appropriate for the input type. */ cx->audio_input = cx->card->video_inputs[inp].audio_index; + if (card_input->video_type == V4L2_INPUT_TYPE_TUNER) + std = cx->tuner_std; + cx->streams[CX18_ENC_STREAM_TYPE_MPG].video_dev.tvnorms = std; + cx->streams[CX18_ENC_STREAM_TYPE_YUV].video_dev.tvnorms = std; + cx->streams[CX18_ENC_STREAM_TYPE_VBI].video_dev.tvnorms = std; /* prevent others from messing with the streams until we're finished changing inputs. */ @@ -1036,7 +1043,7 @@ static int cx18_log_status(struct file *file, void *fh) for (i = 0; i < CX18_MAX_STREAMS; i++) { struct cx18_stream *s = &cx->streams[i]; - if (s->video_dev == NULL || s->buffers == 0) + if (s->video_dev.v4l2_dev == NULL || s->buffers == 0) continue; CX18_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags, @@ -1078,8 +1085,7 @@ static const struct v4l2_ioctl_ops cx18_ioctl_ops = { .vidioc_enumaudio = cx18_enumaudio, .vidioc_enum_input = cx18_enum_input, .vidioc_cropcap = cx18_cropcap, - .vidioc_s_crop = cx18_s_crop, - .vidioc_g_crop = cx18_g_crop, + .vidioc_g_selection = cx18_g_selection, .vidioc_g_input = cx18_g_input, .vidioc_s_input = cx18_s_input, .vidioc_g_frequency = cx18_g_frequency, @@ -1114,6 +1120,8 @@ static const struct v4l2_ioctl_ops cx18_ioctl_ops = { .vidioc_querybuf = cx18_querybuf, .vidioc_qbuf = cx18_qbuf, .vidioc_dqbuf = cx18_dqbuf, + .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, + .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; void cx18_set_funcs(struct video_device *vdev) diff --git a/drivers/media/pci/cx18/cx18-streams.c b/drivers/media/pci/cx18/cx18-streams.c index 369445fcf3e5..c82d25d53341 100644 --- a/drivers/media/pci/cx18/cx18-streams.c +++ b/drivers/media/pci/cx18/cx18-streams.c @@ -254,11 +254,8 @@ static struct videobuf_queue_ops cx18_videobuf_qops = { static void cx18_stream_init(struct cx18 *cx, int type) { struct cx18_stream *s = &cx->streams[type]; - struct video_device *video_dev = s->video_dev; - /* we need to keep video_dev, so restore it afterwards */ memset(s, 0, sizeof(*s)); - s->video_dev = video_dev; /* initialize cx18_stream fields */ s->dvb = NULL; @@ -307,6 +304,7 @@ static void cx18_stream_init(struct cx18 *cx, int type) /* Assume the previous pixel default */ s->pixelformat = V4L2_PIX_FMT_HM12; s->vb_bytes_per_frame = cx->cxhdl.height * 720 * 3 / 2; + s->vb_bytes_per_line = 720; } } @@ -319,12 +317,12 @@ static int cx18_prep_dev(struct cx18 *cx, int type) /* * These five fields are always initialized. - * For analog capture related streams, if video_dev == NULL then the + * For analog capture related streams, if video_dev.v4l2_dev == NULL then the * stream is not in use. * For the TS stream, if dvb == NULL then the stream is not in use. * In those cases no other fields but these four can be used. */ - s->video_dev = NULL; + s->video_dev.v4l2_dev = NULL; s->dvb = NULL; s->cx = cx; s->type = type; @@ -367,24 +365,20 @@ static int cx18_prep_dev(struct cx18 *cx, int type) if (num_offset == -1) return 0; - /* allocate and initialize the v4l2 video device structure */ - s->video_dev = video_device_alloc(); - if (s->video_dev == NULL) { - CX18_ERR("Couldn't allocate v4l2 video_device for %s\n", - s->name); - return -ENOMEM; - } - - snprintf(s->video_dev->name, sizeof(s->video_dev->name), "%s %s", + /* initialize the v4l2 video device structure */ + snprintf(s->video_dev.name, sizeof(s->video_dev.name), "%s %s", cx->v4l2_dev.name, s->name); - s->video_dev->num = num; - s->video_dev->v4l2_dev = &cx->v4l2_dev; - s->video_dev->fops = &cx18_v4l2_enc_fops; - s->video_dev->release = video_device_release; - s->video_dev->tvnorms = V4L2_STD_ALL; - s->video_dev->lock = &cx->serialize_lock; - cx18_set_funcs(s->video_dev); + s->video_dev.num = num; + s->video_dev.v4l2_dev = &cx->v4l2_dev; + s->video_dev.fops = &cx18_v4l2_enc_fops; + s->video_dev.release = video_device_release_empty; + if (cx->card->video_inputs->video_type == CX18_CARD_INPUT_VID_TUNER) + s->video_dev.tvnorms = cx->tuner_std; + else + s->video_dev.tvnorms = V4L2_STD_ALL; + s->video_dev.lock = &cx->serialize_lock; + cx18_set_funcs(&s->video_dev); return 0; } @@ -428,31 +422,30 @@ static int cx18_reg_dev(struct cx18 *cx, int type) } } - if (s->video_dev == NULL) + if (s->video_dev.v4l2_dev == NULL) return 0; - num = s->video_dev->num; + num = s->video_dev.num; /* card number + user defined offset + device offset */ if (type != CX18_ENC_STREAM_TYPE_MPG) { struct cx18_stream *s_mpg = &cx->streams[CX18_ENC_STREAM_TYPE_MPG]; - if (s_mpg->video_dev) - num = s_mpg->video_dev->num + if (s_mpg->video_dev.v4l2_dev) + num = s_mpg->video_dev.num + cx18_stream_info[type].num_offset; } - video_set_drvdata(s->video_dev, s); + video_set_drvdata(&s->video_dev, s); /* Register device. First try the desired minor, then any free one. */ - ret = video_register_device_no_warn(s->video_dev, vfl_type, num); + ret = video_register_device_no_warn(&s->video_dev, vfl_type, num); if (ret < 0) { CX18_ERR("Couldn't register v4l2 device for %s (device node number %d)\n", s->name, num); - video_device_release(s->video_dev); - s->video_dev = NULL; + s->video_dev.v4l2_dev = NULL; return ret; } - name = video_device_node_name(s->video_dev); + name = video_device_node_name(&s->video_dev); switch (vfl_type) { case VFL_TYPE_GRABBER: @@ -542,10 +535,9 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister) } /* If struct video_device exists, can have buffers allocated */ - vdev = cx->streams[type].video_dev; + vdev = &cx->streams[type].video_dev; - cx->streams[type].video_dev = NULL; - if (vdev == NULL) + if (vdev->v4l2_dev == NULL) continue; if (type == CX18_ENC_STREAM_TYPE_YUV) @@ -553,11 +545,7 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister) cx18_stream_free(&cx->streams[type]); - /* Unregister or release device */ - if (unregister) - video_unregister_device(vdev); - else - video_device_release(vdev); + video_unregister_device(vdev); } } @@ -1042,7 +1030,7 @@ u32 cx18_find_handle(struct cx18 *cx) for (i = 0; i < CX18_MAX_STREAMS; i++) { struct cx18_stream *s = &cx->streams[i]; - if (s->video_dev && (s->handle != CX18_INVALID_TASK_HANDLE)) + if (s->video_dev.v4l2_dev && (s->handle != CX18_INVALID_TASK_HANDLE)) return s->handle; } return CX18_INVALID_TASK_HANDLE; diff --git a/drivers/media/pci/cx18/cx18-streams.h b/drivers/media/pci/cx18/cx18-streams.h index 713b0e61536d..27f8af9b11cd 100644 --- a/drivers/media/pci/cx18/cx18-streams.h +++ b/drivers/media/pci/cx18/cx18-streams.h @@ -33,7 +33,7 @@ void cx18_stream_rotate_idx_mdls(struct cx18 *cx); static inline bool cx18_stream_enabled(struct cx18_stream *s) { - return s->video_dev || + return s->video_dev.v4l2_dev || (s->dvb && s->dvb->enabled) || (s->type == CX18_ENC_STREAM_TYPE_IDX && s->cx->stream_buffers[CX18_ENC_STREAM_TYPE_IDX] != 0); |