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; }
static int snd_cx18_pcm_capture_open(struct snd_pcm_substream *substream) { struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct v4l2_device *v4l2_dev = cxsc->v4l2_dev; struct cx18 *cx = to_cx18(v4l2_dev); struct cx18_stream *s; struct cx18_open_id item; int ret; /* Instruct the cx18 to start sending packets */ snd_cx18_lock(cxsc); s = &cx->streams[CX18_ENC_STREAM_TYPE_PCM]; item.cx = cx; item.type = s->type; item.open_id = cx->open_id++; /* See if the stream is available */ if (cx18_claim_stream(&item, item.type)) { /* No, it's already in use */ snd_cx18_unlock(cxsc); return -EBUSY; } if (test_bit(CX18_F_S_STREAMOFF, &s->s_flags) || test_and_set_bit(CX18_F_S_STREAMING, &s->s_flags)) { /* We're already streaming. No additional action required */ snd_cx18_unlock(cxsc); return 0; } runtime->hw = snd_cx18_hw_capture; snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); cxsc->capture_pcm_substream = substream; runtime->private_data = cx; cx->pcm_announce_callback = cx18_alsa_announce_pcm_data; /* Not currently streaming, so start it up */ set_bit(CX18_F_S_STREAMING, &s->s_flags); ret = cx18_start_v4l2_encode_stream(s); snd_cx18_unlock(cxsc); return ret; }
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; }