コード例 #1
0
static int cx18_serialized_open(struct cx18_stream *s, struct file *filp)
{
    struct cx18 *cx = s->cx;
    struct cx18_open_id *item;

    CX18_DEBUG_FILE("open %s\n", s->name);

    /* Allocate memory */
    item = kmalloc(sizeof(struct cx18_open_id), GFP_KERNEL);
    if (NULL == item) {
        CX18_DEBUG_WARN("nomem on v4l2 open\n");
        return -ENOMEM;
    }
    item->cx = cx;
    item->type = s->type;
    v4l2_prio_open(&cx->prio, &item->prio);

    item->open_id = cx->open_id++;
    filp->private_data = item;

    if (item->type == CX18_ENC_STREAM_TYPE_RAD) {
        /* Try to claim this stream */
        if (cx18_claim_stream(item, item->type)) {
            /* No, it's already in use */
            kfree(item);
            return -EBUSY;
        }

        if (!test_bit(CX18_F_I_RADIO_USER, &cx->i_flags)) {
            if (atomic_read(&cx->ana_capturing) > 0) {
                /* switching to radio while capture is
                   in progress is not polite */
                cx18_release_stream(s);
                kfree(item);
                return -EBUSY;
            }
        }

        /* Mark that the radio is being used. */
        set_bit(CX18_F_I_RADIO_USER, &cx->i_flags);
        /* We have the radio */
        cx18_mute(cx);
        /* Switch tuner to radio */
        cx18_call_i2c_clients(cx, AUDC_SET_RADIO, NULL);
        /* Select the correct audio input (i.e. radio tuner) */
        cx18_audio_set_io(cx);
        /* Done! Unmute and continue. */
        cx18_unmute(cx);
    }
    return 0;
}
コード例 #2
0
int cx18_v4l2_close(struct inode *inode, struct file *filp)
{
    struct cx18_open_id *id = filp->private_data;
    struct cx18 *cx = id->cx;
    struct cx18_stream *s = &cx->streams[id->type];

    CX18_DEBUG_IOCTL("close() of %s\n", s->name);

    v4l2_prio_close(&cx->prio, &id->prio);

    /* Easy case first: this stream was never claimed by us */
    if (s->id != id->open_id) {
        kfree(id);
        return 0;
    }

    /* 'Unclaim' this stream */

    /* Stop radio */
    mutex_lock(&cx->serialize_lock);
    if (id->type == CX18_ENC_STREAM_TYPE_RAD) {
        /* Closing radio device, return to TV mode */
        cx18_mute(cx);
        /* Mark that the radio is no longer in use */
        clear_bit(CX18_F_I_RADIO_USER, &cx->i_flags);
        /* Switch tuner to TV */
        cx18_call_i2c_clients(cx, VIDIOC_S_STD, &cx->std);
        /* Select correct audio input (i.e. TV tuner or Line in) */
        cx18_audio_set_io(cx);
        if (atomic_read(&cx->ana_capturing) > 0) {
            /* Undo video mute */
            cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle,
                      cx->params.video_mute |
                      (cx->params.video_mute_yuv << 8));
        }
        /* Done! Unmute and continue. */
        cx18_unmute(cx);
        cx18_release_stream(s);
    } else {
        cx18_stop_capture(id, 0);
    }
    kfree(id);
    mutex_unlock(&cx->serialize_lock);
    return 0;
}
コード例 #3
0
ファイル: cx18-alsa-pcm.c プロジェクト: acton393/linux
static int snd_cx18_pcm_capture_close(struct snd_pcm_substream *substream)
{
	struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream);
	struct v4l2_device *v4l2_dev = cxsc->v4l2_dev;
	struct cx18 *cx = to_cx18(v4l2_dev);
	struct cx18_stream *s;

	/* Instruct the cx18 to stop sending packets */
	snd_cx18_lock(cxsc);
	s = &cx->streams[CX18_ENC_STREAM_TYPE_PCM];
	cx18_stop_v4l2_encode_stream(s, 0);
	clear_bit(CX18_F_S_STREAMING, &s->s_flags);

	cx18_release_stream(s);

	cx->pcm_announce_callback = NULL;
	snd_cx18_unlock(cxsc);

	return 0;
}
コード例 #4
0
void cx18_stop_capture(struct cx18_open_id *id, int gop_end)
{
    struct cx18 *cx = id->cx;
    struct cx18_stream *s = &cx->streams[id->type];

    CX18_DEBUG_IOCTL("close() of %s\n", s->name);

    /* 'Unclaim' this stream */

    /* Stop capturing */
    if (test_bit(CX18_F_S_STREAMING, &s->s_flags)) {
        struct cx18_stream *s_vbi =
                &cx->streams[CX18_ENC_STREAM_TYPE_VBI];

        CX18_DEBUG_INFO("close stopping capture\n");
        /* Special case: a running VBI capture for VBI insertion
           in the mpeg stream. Need to stop that too. */
        if (id->type == CX18_ENC_STREAM_TYPE_MPG &&
                test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags) &&
                !test_bit(CX18_F_S_APPL_IO, &s_vbi->s_flags)) {
            CX18_DEBUG_INFO("close stopping embedded VBI capture\n");
            cx18_stop_v4l2_encode_stream(s_vbi, 0);
        }
        if (id->type == CX18_ENC_STREAM_TYPE_VBI &&
                test_bit(CX18_F_S_INTERNAL_USE, &s->s_flags))
            /* Also used internally, don't stop capturing */
            s->id = -1;
        else
            cx18_stop_v4l2_encode_stream(s, gop_end);
    }
    if (!gop_end) {
        clear_bit(CX18_F_S_APPL_IO, &s->s_flags);
        clear_bit(CX18_F_S_STREAMOFF, &s->s_flags);
        cx18_release_stream(s);
    }
}
コード例 #5
0
int cx18_start_capture(struct cx18_open_id *id)
{
    struct cx18 *cx = id->cx;
    struct cx18_stream *s = &cx->streams[id->type];
    struct cx18_stream *s_vbi;

    if (s->type == CX18_ENC_STREAM_TYPE_RAD) {
        /* you cannot read from these stream types. */
        return -EPERM;
    }

    /* Try to claim this stream. */
    if (cx18_claim_stream(id, s->type))
        return -EBUSY;

    /* If capture is already in progress, then we also have to
       do nothing extra. */
    if (test_bit(CX18_F_S_STREAMOFF, &s->s_flags) ||
            test_and_set_bit(CX18_F_S_STREAMING, &s->s_flags)) {
        set_bit(CX18_F_S_APPL_IO, &s->s_flags);
        return 0;
    }

    /* Start VBI capture if required */
    s_vbi = &cx->streams[CX18_ENC_STREAM_TYPE_VBI];
    if (s->type == CX18_ENC_STREAM_TYPE_MPG &&
            test_bit(CX18_F_S_INTERNAL_USE, &s_vbi->s_flags) &&
            !test_and_set_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) {
        /* Note: the CX18_ENC_STREAM_TYPE_VBI is claimed
           automatically when the MPG stream is claimed.
           We only need to start the VBI capturing. */
        if (cx18_start_v4l2_encode_stream(s_vbi)) {
            CX18_DEBUG_WARN("VBI capture start failed\n");

            /* Failure, clean up and return an error */
            clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags);
            clear_bit(CX18_F_S_STREAMING, &s->s_flags);
            /* also releases the associated VBI stream */
            cx18_release_stream(s);
            return -EIO;
        }
        CX18_DEBUG_INFO("VBI insertion started\n");
    }

    /* Tell the card to start capturing */
    if (!cx18_start_v4l2_encode_stream(s)) {
        /* We're done */
        set_bit(CX18_F_S_APPL_IO, &s->s_flags);
        /* Resume a possibly paused encoder */
        if (test_and_clear_bit(CX18_F_I_ENC_PAUSED, &cx->i_flags))
            cx18_vapi(cx, CX18_CPU_CAPTURE_PAUSE, 1, s->handle);
        return 0;
    }

    /* failure, clean up */
    CX18_DEBUG_WARN("Failed to start capturing for stream %s\n", s->name);

    /* Note: the CX18_ENC_STREAM_TYPE_VBI is released
       automatically when the MPG stream is released.
       We only need to stop the VBI capturing. */
    if (s->type == CX18_ENC_STREAM_TYPE_MPG &&
            test_bit(CX18_F_S_STREAMING, &s_vbi->s_flags)) {
        cx18_stop_v4l2_encode_stream(s_vbi, 0);
        clear_bit(CX18_F_S_STREAMING, &s_vbi->s_flags);
    }
    clear_bit(CX18_F_S_STREAMING, &s->s_flags);
    cx18_release_stream(s);
    return -EIO;
}
コード例 #6
0
static ssize_t cx18_read(struct cx18_stream *s, char __user *ubuf,
                         size_t tot_count, int non_block)
{
    struct cx18 *cx = s->cx;
    size_t tot_written = 0;
    int single_frame = 0;

    if (atomic_read(&cx->ana_capturing) == 0 && s->id == -1) {
        /* shouldn't happen */
        CX18_DEBUG_WARN("Stream %s not initialized before read\n",
                        s->name);
        return -EIO;
    }

    /* Each VBI buffer is one frame, the v4l2 API says that for VBI the
       frames should arrive one-by-one, so make sure we never output more
       than one VBI frame at a time */
    if (s->type == CX18_ENC_STREAM_TYPE_VBI &&
            cx->vbi.sliced_in->service_set)
        single_frame = 1;

    for (;;) {
        struct cx18_buffer *buf;
        int rc;

        buf = cx18_get_buffer(s, non_block, &rc);
        /* if there is no data available... */
        if (buf == NULL) {
            /* if we got data, then return that regardless */
            if (tot_written)
                break;
            /* EOS condition */
            if (rc == 0) {
                clear_bit(CX18_F_S_STREAMOFF, &s->s_flags);
                clear_bit(CX18_F_S_APPL_IO, &s->s_flags);
                cx18_release_stream(s);
            }
            /* set errno */
            return rc;
        }

        rc = cx18_copy_buf_to_user(s, buf, ubuf + tot_written,
                                   tot_count - tot_written);

        if (buf != &cx->vbi.sliced_mpeg_buf) {
            if (buf->readpos == buf->bytesused) {
                cx18_buf_sync_for_device(s, buf);
                cx18_enqueue(s, buf, &s->q_free);
                cx18_vapi(cx, CX18_CPU_DE_SET_MDL, 5,
                          s->handle,
                          (void __iomem *)&cx->scb->cpu_mdl[buf->id] -
                          cx->enc_mem,
                          1, buf->id, s->buf_size);
            } else
                cx18_enqueue(s, buf, &s->q_io);
        } else if (buf->readpos == buf->bytesused) {
            int idx = cx->vbi.inserted_frame % CX18_VBI_FRAMES;

            cx->vbi.sliced_mpeg_size[idx] = 0;
            cx->vbi.inserted_frame++;
            cx->vbi_data_inserted += buf->bytesused;
        }
        if (rc < 0)
            return rc;
        tot_written += rc;

        if (tot_written == tot_count || single_frame)
            break;
    }
    return tot_written;
}