1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#include <linux/init.h>
27#include <linux/kernel.h>
28#include <linux/vmalloc.h>
29
30#include <media/v4l2-device.h>
31
32#include <sound/core.h>
33#include <sound/pcm.h>
34
35#include "ivtv-driver.h"
36#include "ivtv-queue.h"
37#include "ivtv-streams.h"
38#include "ivtv-fileops.h"
39#include "ivtv-alsa.h"
40#include "ivtv-alsa-pcm.h"
41
42static unsigned int pcm_debug;
43module_param(pcm_debug, int, 0644);
44MODULE_PARM_DESC(pcm_debug, "enable debug messages for pcm");
45
46#define dprintk(fmt, arg...) \
47 do { \
48 if (pcm_debug) \
49 pr_info("ivtv-alsa-pcm %s: " fmt, __func__, ##arg); \
50 } while (0)
51
52static struct snd_pcm_hardware snd_ivtv_hw_capture = {
53 .info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
54 SNDRV_PCM_INFO_MMAP |
55 SNDRV_PCM_INFO_INTERLEAVED |
56 SNDRV_PCM_INFO_MMAP_VALID,
57
58 .formats = SNDRV_PCM_FMTBIT_S16_LE,
59
60 .rates = SNDRV_PCM_RATE_48000,
61
62 .rate_min = 48000,
63 .rate_max = 48000,
64 .channels_min = 2,
65 .channels_max = 2,
66 .buffer_bytes_max = 62720 * 8,
67 .period_bytes_min = 64,
68 .period_bytes_max = 12544,
69 .periods_min = 2,
70 .periods_max = 98,
71};
72
73static void ivtv_alsa_announce_pcm_data(struct snd_ivtv_card *itvsc,
74 u8 *pcm_data,
75 size_t num_bytes)
76{
77 struct snd_pcm_substream *substream;
78 struct snd_pcm_runtime *runtime;
79 unsigned int oldptr;
80 unsigned int stride;
81 int period_elapsed = 0;
82 int length;
83
84 dprintk("ivtv alsa announce ptr=%p data=%p num_bytes=%zd\n", itvsc,
85 pcm_data, num_bytes);
86
87 substream = itvsc->capture_pcm_substream;
88 if (substream == NULL) {
89 dprintk("substream was NULL\n");
90 return;
91 }
92
93 runtime = substream->runtime;
94 if (runtime == NULL) {
95 dprintk("runtime was NULL\n");
96 return;
97 }
98
99 stride = runtime->frame_bits >> 3;
100 if (stride == 0) {
101 dprintk("stride is zero\n");
102 return;
103 }
104
105 length = num_bytes / stride;
106 if (length == 0) {
107 dprintk("%s: length was zero\n", __func__);
108 return;
109 }
110
111 if (runtime->dma_area == NULL) {
112 dprintk("dma area was NULL - ignoring\n");
113 return;
114 }
115
116 oldptr = itvsc->hwptr_done_capture;
117 if (oldptr + length >= runtime->buffer_size) {
118 unsigned int cnt =
119 runtime->buffer_size - oldptr;
120 memcpy(runtime->dma_area + oldptr * stride, pcm_data,
121 cnt * stride);
122 memcpy(runtime->dma_area, pcm_data + cnt * stride,
123 length * stride - cnt * stride);
124 } else {
125 memcpy(runtime->dma_area + oldptr * stride, pcm_data,
126 length * stride);
127 }
128 snd_pcm_stream_lock(substream);
129
130 itvsc->hwptr_done_capture += length;
131 if (itvsc->hwptr_done_capture >=
132 runtime->buffer_size)
133 itvsc->hwptr_done_capture -=
134 runtime->buffer_size;
135
136 itvsc->capture_transfer_done += length;
137 if (itvsc->capture_transfer_done >=
138 runtime->period_size) {
139 itvsc->capture_transfer_done -=
140 runtime->period_size;
141 period_elapsed = 1;
142 }
143
144 snd_pcm_stream_unlock(substream);
145
146 if (period_elapsed)
147 snd_pcm_period_elapsed(substream);
148}
149
150static int snd_ivtv_pcm_capture_open(struct snd_pcm_substream *substream)
151{
152 struct snd_ivtv_card *itvsc = snd_pcm_substream_chip(substream);
153 struct snd_pcm_runtime *runtime = substream->runtime;
154 struct v4l2_device *v4l2_dev = itvsc->v4l2_dev;
155 struct ivtv *itv = to_ivtv(v4l2_dev);
156 struct ivtv_stream *s;
157 struct ivtv_open_id item;
158 int ret;
159
160
161 snd_ivtv_lock(itvsc);
162 s = &itv->streams[IVTV_ENC_STREAM_TYPE_PCM];
163
164 v4l2_fh_init(&item.fh, s->vdev);
165 item.itv = itv;
166 item.type = s->type;
167
168
169 if (ivtv_claim_stream(&item, item.type)) {
170
171 snd_ivtv_unlock(itvsc);
172 return -EBUSY;
173 }
174
175 if (test_bit(IVTV_F_S_STREAMOFF, &s->s_flags) ||
176 test_and_set_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
177
178 snd_ivtv_unlock(itvsc);
179 return 0;
180 }
181
182
183 runtime->hw = snd_ivtv_hw_capture;
184 snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
185 itvsc->capture_pcm_substream = substream;
186 runtime->private_data = itv;
187
188 itv->pcm_announce_callback = ivtv_alsa_announce_pcm_data;
189
190
191 set_bit(IVTV_F_S_STREAMING, &s->s_flags);
192 ret = ivtv_start_v4l2_encode_stream(s);
193 snd_ivtv_unlock(itvsc);
194
195 return ret;
196}
197
198static int snd_ivtv_pcm_capture_close(struct snd_pcm_substream *substream)
199{
200 struct snd_ivtv_card *itvsc = snd_pcm_substream_chip(substream);
201 struct v4l2_device *v4l2_dev = itvsc->v4l2_dev;
202 struct ivtv *itv = to_ivtv(v4l2_dev);
203 struct ivtv_stream *s;
204
205
206 snd_ivtv_lock(itvsc);
207 s = &itv->streams[IVTV_ENC_STREAM_TYPE_PCM];
208 ivtv_stop_v4l2_encode_stream(s, 0);
209 clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
210
211 ivtv_release_stream(s);
212
213 itv->pcm_announce_callback = NULL;
214 snd_ivtv_unlock(itvsc);
215
216 return 0;
217}
218
219static int snd_ivtv_pcm_ioctl(struct snd_pcm_substream *substream,
220 unsigned int cmd, void *arg)
221{
222 struct snd_ivtv_card *itvsc = snd_pcm_substream_chip(substream);
223 int ret;
224
225 snd_ivtv_lock(itvsc);
226 ret = snd_pcm_lib_ioctl(substream, cmd, arg);
227 snd_ivtv_unlock(itvsc);
228 return ret;
229}
230
231
232static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
233 size_t size)
234{
235 struct snd_pcm_runtime *runtime = subs->runtime;
236
237 dprintk("Allocating vbuffer\n");
238 if (runtime->dma_area) {
239 if (runtime->dma_bytes > size)
240 return 0;
241
242 vfree(runtime->dma_area);
243 }
244 runtime->dma_area = vmalloc(size);
245 if (!runtime->dma_area)
246 return -ENOMEM;
247
248 runtime->dma_bytes = size;
249
250 return 0;
251}
252
253static int snd_ivtv_pcm_hw_params(struct snd_pcm_substream *substream,
254 struct snd_pcm_hw_params *params)
255{
256 dprintk("%s called\n", __func__);
257
258 return snd_pcm_alloc_vmalloc_buffer(substream,
259 params_buffer_bytes(params));
260}
261
262static int snd_ivtv_pcm_hw_free(struct snd_pcm_substream *substream)
263{
264 struct snd_ivtv_card *itvsc = snd_pcm_substream_chip(substream);
265 unsigned long flags;
266
267 spin_lock_irqsave(&itvsc->slock, flags);
268 if (substream->runtime->dma_area) {
269 dprintk("freeing pcm capture region\n");
270 vfree(substream->runtime->dma_area);
271 substream->runtime->dma_area = NULL;
272 }
273 spin_unlock_irqrestore(&itvsc->slock, flags);
274
275 return 0;
276}
277
278static int snd_ivtv_pcm_prepare(struct snd_pcm_substream *substream)
279{
280 struct snd_ivtv_card *itvsc = snd_pcm_substream_chip(substream);
281
282 itvsc->hwptr_done_capture = 0;
283 itvsc->capture_transfer_done = 0;
284
285 return 0;
286}
287
288static int snd_ivtv_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
289{
290 return 0;
291}
292
293static
294snd_pcm_uframes_t snd_ivtv_pcm_pointer(struct snd_pcm_substream *substream)
295{
296 unsigned long flags;
297 snd_pcm_uframes_t hwptr_done;
298 struct snd_ivtv_card *itvsc = snd_pcm_substream_chip(substream);
299
300 spin_lock_irqsave(&itvsc->slock, flags);
301 hwptr_done = itvsc->hwptr_done_capture;
302 spin_unlock_irqrestore(&itvsc->slock, flags);
303
304 return hwptr_done;
305}
306
307static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
308 unsigned long offset)
309{
310 void *pageptr = subs->runtime->dma_area + offset;
311
312 return vmalloc_to_page(pageptr);
313}
314
315static struct snd_pcm_ops snd_ivtv_pcm_capture_ops = {
316 .open = snd_ivtv_pcm_capture_open,
317 .close = snd_ivtv_pcm_capture_close,
318 .ioctl = snd_ivtv_pcm_ioctl,
319 .hw_params = snd_ivtv_pcm_hw_params,
320 .hw_free = snd_ivtv_pcm_hw_free,
321 .prepare = snd_ivtv_pcm_prepare,
322 .trigger = snd_ivtv_pcm_trigger,
323 .pointer = snd_ivtv_pcm_pointer,
324 .page = snd_pcm_get_vmalloc_page,
325};
326
327int snd_ivtv_pcm_create(struct snd_ivtv_card *itvsc)
328{
329 struct snd_pcm *sp;
330 struct snd_card *sc = itvsc->sc;
331 struct v4l2_device *v4l2_dev = itvsc->v4l2_dev;
332 struct ivtv *itv = to_ivtv(v4l2_dev);
333 int ret;
334
335 ret = snd_pcm_new(sc, "CX2341[56] PCM",
336 0,
337 0,
338 1,
339 &sp);
340 if (ret) {
341 IVTV_ALSA_ERR("%s: snd_ivtv_pcm_create() failed with err %d\n",
342 __func__, ret);
343 goto err_exit;
344 }
345
346 spin_lock_init(&itvsc->slock);
347
348 snd_pcm_set_ops(sp, SNDRV_PCM_STREAM_CAPTURE,
349 &snd_ivtv_pcm_capture_ops);
350 sp->info_flags = 0;
351 sp->private_data = itvsc;
352 strlcpy(sp->name, itv->card_name, sizeof(sp->name));
353
354 return 0;
355
356err_exit:
357 return ret;
358}
359