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