1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-or-later
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Conexant Cx231xx audio extension
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
6*4882a593Smuzhiyun * Based on em28xx driver
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include "cx231xx.h"
10*4882a593Smuzhiyun #include <linux/kernel.h>
11*4882a593Smuzhiyun #include <linux/init.h>
12*4882a593Smuzhiyun #include <linux/sound.h>
13*4882a593Smuzhiyun #include <linux/spinlock.h>
14*4882a593Smuzhiyun #include <linux/soundcard.h>
15*4882a593Smuzhiyun #include <linux/slab.h>
16*4882a593Smuzhiyun #include <linux/module.h>
17*4882a593Smuzhiyun #include <sound/core.h>
18*4882a593Smuzhiyun #include <sound/pcm.h>
19*4882a593Smuzhiyun #include <sound/pcm_params.h>
20*4882a593Smuzhiyun #include <sound/info.h>
21*4882a593Smuzhiyun #include <sound/initval.h>
22*4882a593Smuzhiyun #include <sound/control.h>
23*4882a593Smuzhiyun #include <media/v4l2-common.h>
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun static int debug;
26*4882a593Smuzhiyun module_param(debug, int, 0644);
27*4882a593Smuzhiyun MODULE_PARM_DESC(debug, "activates debug info");
28*4882a593Smuzhiyun
29*4882a593Smuzhiyun static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
30*4882a593Smuzhiyun
cx231xx_isoc_audio_deinit(struct cx231xx * dev)31*4882a593Smuzhiyun static int cx231xx_isoc_audio_deinit(struct cx231xx *dev)
32*4882a593Smuzhiyun {
33*4882a593Smuzhiyun int i;
34*4882a593Smuzhiyun
35*4882a593Smuzhiyun dev_dbg(dev->dev, "Stopping isoc\n");
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
38*4882a593Smuzhiyun if (dev->adev.urb[i]) {
39*4882a593Smuzhiyun if (!irqs_disabled())
40*4882a593Smuzhiyun usb_kill_urb(dev->adev.urb[i]);
41*4882a593Smuzhiyun else
42*4882a593Smuzhiyun usb_unlink_urb(dev->adev.urb[i]);
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun usb_free_urb(dev->adev.urb[i]);
45*4882a593Smuzhiyun dev->adev.urb[i] = NULL;
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun kfree(dev->adev.transfer_buffer[i]);
48*4882a593Smuzhiyun dev->adev.transfer_buffer[i] = NULL;
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun }
51*4882a593Smuzhiyun
52*4882a593Smuzhiyun return 0;
53*4882a593Smuzhiyun }
54*4882a593Smuzhiyun
cx231xx_bulk_audio_deinit(struct cx231xx * dev)55*4882a593Smuzhiyun static int cx231xx_bulk_audio_deinit(struct cx231xx *dev)
56*4882a593Smuzhiyun {
57*4882a593Smuzhiyun int i;
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun dev_dbg(dev->dev, "Stopping bulk\n");
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
62*4882a593Smuzhiyun if (dev->adev.urb[i]) {
63*4882a593Smuzhiyun if (!irqs_disabled())
64*4882a593Smuzhiyun usb_kill_urb(dev->adev.urb[i]);
65*4882a593Smuzhiyun else
66*4882a593Smuzhiyun usb_unlink_urb(dev->adev.urb[i]);
67*4882a593Smuzhiyun
68*4882a593Smuzhiyun usb_free_urb(dev->adev.urb[i]);
69*4882a593Smuzhiyun dev->adev.urb[i] = NULL;
70*4882a593Smuzhiyun
71*4882a593Smuzhiyun kfree(dev->adev.transfer_buffer[i]);
72*4882a593Smuzhiyun dev->adev.transfer_buffer[i] = NULL;
73*4882a593Smuzhiyun }
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun return 0;
77*4882a593Smuzhiyun }
78*4882a593Smuzhiyun
cx231xx_audio_isocirq(struct urb * urb)79*4882a593Smuzhiyun static void cx231xx_audio_isocirq(struct urb *urb)
80*4882a593Smuzhiyun {
81*4882a593Smuzhiyun struct cx231xx *dev = urb->context;
82*4882a593Smuzhiyun int i;
83*4882a593Smuzhiyun unsigned int oldptr;
84*4882a593Smuzhiyun int period_elapsed = 0;
85*4882a593Smuzhiyun int status;
86*4882a593Smuzhiyun unsigned char *cp;
87*4882a593Smuzhiyun unsigned int stride;
88*4882a593Smuzhiyun struct snd_pcm_substream *substream;
89*4882a593Smuzhiyun struct snd_pcm_runtime *runtime;
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun if (dev->state & DEV_DISCONNECTED)
92*4882a593Smuzhiyun return;
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun switch (urb->status) {
95*4882a593Smuzhiyun case 0: /* success */
96*4882a593Smuzhiyun case -ETIMEDOUT: /* NAK */
97*4882a593Smuzhiyun break;
98*4882a593Smuzhiyun case -ECONNRESET: /* kill */
99*4882a593Smuzhiyun case -ENOENT:
100*4882a593Smuzhiyun case -ESHUTDOWN:
101*4882a593Smuzhiyun return;
102*4882a593Smuzhiyun default: /* error */
103*4882a593Smuzhiyun dev_dbg(dev->dev, "urb completion error %d.\n",
104*4882a593Smuzhiyun urb->status);
105*4882a593Smuzhiyun break;
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun if (atomic_read(&dev->stream_started) == 0)
109*4882a593Smuzhiyun return;
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun if (dev->adev.capture_pcm_substream) {
112*4882a593Smuzhiyun substream = dev->adev.capture_pcm_substream;
113*4882a593Smuzhiyun runtime = substream->runtime;
114*4882a593Smuzhiyun stride = runtime->frame_bits >> 3;
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun for (i = 0; i < urb->number_of_packets; i++) {
117*4882a593Smuzhiyun unsigned long flags;
118*4882a593Smuzhiyun int length = urb->iso_frame_desc[i].actual_length /
119*4882a593Smuzhiyun stride;
120*4882a593Smuzhiyun cp = (unsigned char *)urb->transfer_buffer +
121*4882a593Smuzhiyun urb->iso_frame_desc[i].offset;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun if (!length)
124*4882a593Smuzhiyun continue;
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun oldptr = dev->adev.hwptr_done_capture;
127*4882a593Smuzhiyun if (oldptr + length >= runtime->buffer_size) {
128*4882a593Smuzhiyun unsigned int cnt;
129*4882a593Smuzhiyun
130*4882a593Smuzhiyun cnt = runtime->buffer_size - oldptr;
131*4882a593Smuzhiyun memcpy(runtime->dma_area + oldptr * stride, cp,
132*4882a593Smuzhiyun cnt * stride);
133*4882a593Smuzhiyun memcpy(runtime->dma_area, cp + cnt * stride,
134*4882a593Smuzhiyun length * stride - cnt * stride);
135*4882a593Smuzhiyun } else {
136*4882a593Smuzhiyun memcpy(runtime->dma_area + oldptr * stride, cp,
137*4882a593Smuzhiyun length * stride);
138*4882a593Smuzhiyun }
139*4882a593Smuzhiyun
140*4882a593Smuzhiyun snd_pcm_stream_lock_irqsave(substream, flags);
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun dev->adev.hwptr_done_capture += length;
143*4882a593Smuzhiyun if (dev->adev.hwptr_done_capture >=
144*4882a593Smuzhiyun runtime->buffer_size)
145*4882a593Smuzhiyun dev->adev.hwptr_done_capture -=
146*4882a593Smuzhiyun runtime->buffer_size;
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun dev->adev.capture_transfer_done += length;
149*4882a593Smuzhiyun if (dev->adev.capture_transfer_done >=
150*4882a593Smuzhiyun runtime->period_size) {
151*4882a593Smuzhiyun dev->adev.capture_transfer_done -=
152*4882a593Smuzhiyun runtime->period_size;
153*4882a593Smuzhiyun period_elapsed = 1;
154*4882a593Smuzhiyun }
155*4882a593Smuzhiyun snd_pcm_stream_unlock_irqrestore(substream, flags);
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun if (period_elapsed)
158*4882a593Smuzhiyun snd_pcm_period_elapsed(substream);
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun urb->status = 0;
161*4882a593Smuzhiyun
162*4882a593Smuzhiyun status = usb_submit_urb(urb, GFP_ATOMIC);
163*4882a593Smuzhiyun if (status < 0) {
164*4882a593Smuzhiyun dev_err(dev->dev,
165*4882a593Smuzhiyun "resubmit of audio urb failed (error=%i)\n",
166*4882a593Smuzhiyun status);
167*4882a593Smuzhiyun }
168*4882a593Smuzhiyun return;
169*4882a593Smuzhiyun }
170*4882a593Smuzhiyun
cx231xx_audio_bulkirq(struct urb * urb)171*4882a593Smuzhiyun static void cx231xx_audio_bulkirq(struct urb *urb)
172*4882a593Smuzhiyun {
173*4882a593Smuzhiyun struct cx231xx *dev = urb->context;
174*4882a593Smuzhiyun unsigned int oldptr;
175*4882a593Smuzhiyun int period_elapsed = 0;
176*4882a593Smuzhiyun int status;
177*4882a593Smuzhiyun unsigned char *cp;
178*4882a593Smuzhiyun unsigned int stride;
179*4882a593Smuzhiyun struct snd_pcm_substream *substream;
180*4882a593Smuzhiyun struct snd_pcm_runtime *runtime;
181*4882a593Smuzhiyun
182*4882a593Smuzhiyun if (dev->state & DEV_DISCONNECTED)
183*4882a593Smuzhiyun return;
184*4882a593Smuzhiyun
185*4882a593Smuzhiyun switch (urb->status) {
186*4882a593Smuzhiyun case 0: /* success */
187*4882a593Smuzhiyun case -ETIMEDOUT: /* NAK */
188*4882a593Smuzhiyun break;
189*4882a593Smuzhiyun case -ECONNRESET: /* kill */
190*4882a593Smuzhiyun case -ENOENT:
191*4882a593Smuzhiyun case -ESHUTDOWN:
192*4882a593Smuzhiyun return;
193*4882a593Smuzhiyun default: /* error */
194*4882a593Smuzhiyun dev_dbg(dev->dev, "urb completion error %d.\n",
195*4882a593Smuzhiyun urb->status);
196*4882a593Smuzhiyun break;
197*4882a593Smuzhiyun }
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun if (atomic_read(&dev->stream_started) == 0)
200*4882a593Smuzhiyun return;
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun if (dev->adev.capture_pcm_substream) {
203*4882a593Smuzhiyun substream = dev->adev.capture_pcm_substream;
204*4882a593Smuzhiyun runtime = substream->runtime;
205*4882a593Smuzhiyun stride = runtime->frame_bits >> 3;
206*4882a593Smuzhiyun
207*4882a593Smuzhiyun if (1) {
208*4882a593Smuzhiyun unsigned long flags;
209*4882a593Smuzhiyun int length = urb->actual_length /
210*4882a593Smuzhiyun stride;
211*4882a593Smuzhiyun cp = (unsigned char *)urb->transfer_buffer;
212*4882a593Smuzhiyun
213*4882a593Smuzhiyun oldptr = dev->adev.hwptr_done_capture;
214*4882a593Smuzhiyun if (oldptr + length >= runtime->buffer_size) {
215*4882a593Smuzhiyun unsigned int cnt;
216*4882a593Smuzhiyun
217*4882a593Smuzhiyun cnt = runtime->buffer_size - oldptr;
218*4882a593Smuzhiyun memcpy(runtime->dma_area + oldptr * stride, cp,
219*4882a593Smuzhiyun cnt * stride);
220*4882a593Smuzhiyun memcpy(runtime->dma_area, cp + cnt * stride,
221*4882a593Smuzhiyun length * stride - cnt * stride);
222*4882a593Smuzhiyun } else {
223*4882a593Smuzhiyun memcpy(runtime->dma_area + oldptr * stride, cp,
224*4882a593Smuzhiyun length * stride);
225*4882a593Smuzhiyun }
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun snd_pcm_stream_lock_irqsave(substream, flags);
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun dev->adev.hwptr_done_capture += length;
230*4882a593Smuzhiyun if (dev->adev.hwptr_done_capture >=
231*4882a593Smuzhiyun runtime->buffer_size)
232*4882a593Smuzhiyun dev->adev.hwptr_done_capture -=
233*4882a593Smuzhiyun runtime->buffer_size;
234*4882a593Smuzhiyun
235*4882a593Smuzhiyun dev->adev.capture_transfer_done += length;
236*4882a593Smuzhiyun if (dev->adev.capture_transfer_done >=
237*4882a593Smuzhiyun runtime->period_size) {
238*4882a593Smuzhiyun dev->adev.capture_transfer_done -=
239*4882a593Smuzhiyun runtime->period_size;
240*4882a593Smuzhiyun period_elapsed = 1;
241*4882a593Smuzhiyun }
242*4882a593Smuzhiyun snd_pcm_stream_unlock_irqrestore(substream, flags);
243*4882a593Smuzhiyun }
244*4882a593Smuzhiyun if (period_elapsed)
245*4882a593Smuzhiyun snd_pcm_period_elapsed(substream);
246*4882a593Smuzhiyun }
247*4882a593Smuzhiyun urb->status = 0;
248*4882a593Smuzhiyun
249*4882a593Smuzhiyun status = usb_submit_urb(urb, GFP_ATOMIC);
250*4882a593Smuzhiyun if (status < 0) {
251*4882a593Smuzhiyun dev_err(dev->dev,
252*4882a593Smuzhiyun "resubmit of audio urb failed (error=%i)\n",
253*4882a593Smuzhiyun status);
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun return;
256*4882a593Smuzhiyun }
257*4882a593Smuzhiyun
cx231xx_init_audio_isoc(struct cx231xx * dev)258*4882a593Smuzhiyun static int cx231xx_init_audio_isoc(struct cx231xx *dev)
259*4882a593Smuzhiyun {
260*4882a593Smuzhiyun int i, errCode;
261*4882a593Smuzhiyun int sb_size;
262*4882a593Smuzhiyun
263*4882a593Smuzhiyun dev_dbg(dev->dev,
264*4882a593Smuzhiyun "%s: Starting ISO AUDIO transfers\n", __func__);
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun if (dev->state & DEV_DISCONNECTED)
267*4882a593Smuzhiyun return -ENODEV;
268*4882a593Smuzhiyun
269*4882a593Smuzhiyun sb_size = CX231XX_ISO_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size;
270*4882a593Smuzhiyun
271*4882a593Smuzhiyun for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
272*4882a593Smuzhiyun struct urb *urb;
273*4882a593Smuzhiyun int j, k;
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC);
276*4882a593Smuzhiyun if (!dev->adev.transfer_buffer[i])
277*4882a593Smuzhiyun return -ENOMEM;
278*4882a593Smuzhiyun
279*4882a593Smuzhiyun memset(dev->adev.transfer_buffer[i], 0x80, sb_size);
280*4882a593Smuzhiyun urb = usb_alloc_urb(CX231XX_ISO_NUM_AUDIO_PACKETS, GFP_ATOMIC);
281*4882a593Smuzhiyun if (!urb) {
282*4882a593Smuzhiyun for (j = 0; j < i; j++) {
283*4882a593Smuzhiyun usb_free_urb(dev->adev.urb[j]);
284*4882a593Smuzhiyun kfree(dev->adev.transfer_buffer[j]);
285*4882a593Smuzhiyun }
286*4882a593Smuzhiyun return -ENOMEM;
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun urb->dev = dev->udev;
290*4882a593Smuzhiyun urb->context = dev;
291*4882a593Smuzhiyun urb->pipe = usb_rcvisocpipe(dev->udev,
292*4882a593Smuzhiyun dev->adev.end_point_addr);
293*4882a593Smuzhiyun urb->transfer_flags = URB_ISO_ASAP;
294*4882a593Smuzhiyun urb->transfer_buffer = dev->adev.transfer_buffer[i];
295*4882a593Smuzhiyun urb->interval = 1;
296*4882a593Smuzhiyun urb->complete = cx231xx_audio_isocirq;
297*4882a593Smuzhiyun urb->number_of_packets = CX231XX_ISO_NUM_AUDIO_PACKETS;
298*4882a593Smuzhiyun urb->transfer_buffer_length = sb_size;
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun for (j = k = 0; j < CX231XX_ISO_NUM_AUDIO_PACKETS;
301*4882a593Smuzhiyun j++, k += dev->adev.max_pkt_size) {
302*4882a593Smuzhiyun urb->iso_frame_desc[j].offset = k;
303*4882a593Smuzhiyun urb->iso_frame_desc[j].length = dev->adev.max_pkt_size;
304*4882a593Smuzhiyun }
305*4882a593Smuzhiyun dev->adev.urb[i] = urb;
306*4882a593Smuzhiyun }
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
309*4882a593Smuzhiyun errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
310*4882a593Smuzhiyun if (errCode < 0) {
311*4882a593Smuzhiyun cx231xx_isoc_audio_deinit(dev);
312*4882a593Smuzhiyun return errCode;
313*4882a593Smuzhiyun }
314*4882a593Smuzhiyun }
315*4882a593Smuzhiyun
316*4882a593Smuzhiyun return errCode;
317*4882a593Smuzhiyun }
318*4882a593Smuzhiyun
cx231xx_init_audio_bulk(struct cx231xx * dev)319*4882a593Smuzhiyun static int cx231xx_init_audio_bulk(struct cx231xx *dev)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun int i, errCode;
322*4882a593Smuzhiyun int sb_size;
323*4882a593Smuzhiyun
324*4882a593Smuzhiyun dev_dbg(dev->dev,
325*4882a593Smuzhiyun "%s: Starting BULK AUDIO transfers\n", __func__);
326*4882a593Smuzhiyun
327*4882a593Smuzhiyun if (dev->state & DEV_DISCONNECTED)
328*4882a593Smuzhiyun return -ENODEV;
329*4882a593Smuzhiyun
330*4882a593Smuzhiyun sb_size = CX231XX_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size;
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
333*4882a593Smuzhiyun struct urb *urb;
334*4882a593Smuzhiyun int j;
335*4882a593Smuzhiyun
336*4882a593Smuzhiyun dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC);
337*4882a593Smuzhiyun if (!dev->adev.transfer_buffer[i])
338*4882a593Smuzhiyun return -ENOMEM;
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun memset(dev->adev.transfer_buffer[i], 0x80, sb_size);
341*4882a593Smuzhiyun urb = usb_alloc_urb(CX231XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
342*4882a593Smuzhiyun if (!urb) {
343*4882a593Smuzhiyun for (j = 0; j < i; j++) {
344*4882a593Smuzhiyun usb_free_urb(dev->adev.urb[j]);
345*4882a593Smuzhiyun kfree(dev->adev.transfer_buffer[j]);
346*4882a593Smuzhiyun }
347*4882a593Smuzhiyun return -ENOMEM;
348*4882a593Smuzhiyun }
349*4882a593Smuzhiyun
350*4882a593Smuzhiyun urb->dev = dev->udev;
351*4882a593Smuzhiyun urb->context = dev;
352*4882a593Smuzhiyun urb->pipe = usb_rcvbulkpipe(dev->udev,
353*4882a593Smuzhiyun dev->adev.end_point_addr);
354*4882a593Smuzhiyun urb->transfer_flags = 0;
355*4882a593Smuzhiyun urb->transfer_buffer = dev->adev.transfer_buffer[i];
356*4882a593Smuzhiyun urb->complete = cx231xx_audio_bulkirq;
357*4882a593Smuzhiyun urb->transfer_buffer_length = sb_size;
358*4882a593Smuzhiyun
359*4882a593Smuzhiyun dev->adev.urb[i] = urb;
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
364*4882a593Smuzhiyun errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
365*4882a593Smuzhiyun if (errCode < 0) {
366*4882a593Smuzhiyun cx231xx_bulk_audio_deinit(dev);
367*4882a593Smuzhiyun return errCode;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun return errCode;
372*4882a593Smuzhiyun }
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun static const struct snd_pcm_hardware snd_cx231xx_hw_capture = {
375*4882a593Smuzhiyun .info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
376*4882a593Smuzhiyun SNDRV_PCM_INFO_MMAP |
377*4882a593Smuzhiyun SNDRV_PCM_INFO_INTERLEAVED |
378*4882a593Smuzhiyun SNDRV_PCM_INFO_MMAP_VALID,
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun .formats = SNDRV_PCM_FMTBIT_S16_LE,
381*4882a593Smuzhiyun
382*4882a593Smuzhiyun .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT,
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun .rate_min = 48000,
385*4882a593Smuzhiyun .rate_max = 48000,
386*4882a593Smuzhiyun .channels_min = 2,
387*4882a593Smuzhiyun .channels_max = 2,
388*4882a593Smuzhiyun .buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */
389*4882a593Smuzhiyun .period_bytes_min = 64, /* 12544/2, */
390*4882a593Smuzhiyun .period_bytes_max = 12544,
391*4882a593Smuzhiyun .periods_min = 2,
392*4882a593Smuzhiyun .periods_max = 98, /* 12544, */
393*4882a593Smuzhiyun };
394*4882a593Smuzhiyun
snd_cx231xx_capture_open(struct snd_pcm_substream * substream)395*4882a593Smuzhiyun static int snd_cx231xx_capture_open(struct snd_pcm_substream *substream)
396*4882a593Smuzhiyun {
397*4882a593Smuzhiyun struct cx231xx *dev = snd_pcm_substream_chip(substream);
398*4882a593Smuzhiyun struct snd_pcm_runtime *runtime = substream->runtime;
399*4882a593Smuzhiyun int ret = 0;
400*4882a593Smuzhiyun
401*4882a593Smuzhiyun dev_dbg(dev->dev,
402*4882a593Smuzhiyun "opening device and trying to acquire exclusive lock\n");
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun if (dev->state & DEV_DISCONNECTED) {
405*4882a593Smuzhiyun dev_err(dev->dev,
406*4882a593Smuzhiyun "Can't open. the device was removed.\n");
407*4882a593Smuzhiyun return -ENODEV;
408*4882a593Smuzhiyun }
409*4882a593Smuzhiyun
410*4882a593Smuzhiyun /* set alternate setting for audio interface */
411*4882a593Smuzhiyun /* 1 - 48000 samples per sec */
412*4882a593Smuzhiyun mutex_lock(&dev->lock);
413*4882a593Smuzhiyun if (dev->USE_ISO)
414*4882a593Smuzhiyun ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 1);
415*4882a593Smuzhiyun else
416*4882a593Smuzhiyun ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 0);
417*4882a593Smuzhiyun mutex_unlock(&dev->lock);
418*4882a593Smuzhiyun if (ret < 0) {
419*4882a593Smuzhiyun dev_err(dev->dev,
420*4882a593Smuzhiyun "failed to set alternate setting !\n");
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun return ret;
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun runtime->hw = snd_cx231xx_hw_capture;
426*4882a593Smuzhiyun
427*4882a593Smuzhiyun mutex_lock(&dev->lock);
428*4882a593Smuzhiyun /* inform hardware to start streaming */
429*4882a593Smuzhiyun ret = cx231xx_capture_start(dev, 1, Audio);
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun dev->adev.users++;
432*4882a593Smuzhiyun mutex_unlock(&dev->lock);
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
435*4882a593Smuzhiyun dev->adev.capture_pcm_substream = substream;
436*4882a593Smuzhiyun runtime->private_data = dev;
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun return 0;
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun
snd_cx231xx_pcm_close(struct snd_pcm_substream * substream)441*4882a593Smuzhiyun static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream)
442*4882a593Smuzhiyun {
443*4882a593Smuzhiyun int ret;
444*4882a593Smuzhiyun struct cx231xx *dev = snd_pcm_substream_chip(substream);
445*4882a593Smuzhiyun
446*4882a593Smuzhiyun dev_dbg(dev->dev, "closing device\n");
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun /* inform hardware to stop streaming */
449*4882a593Smuzhiyun mutex_lock(&dev->lock);
450*4882a593Smuzhiyun ret = cx231xx_capture_start(dev, 0, Audio);
451*4882a593Smuzhiyun
452*4882a593Smuzhiyun /* set alternate setting for audio interface */
453*4882a593Smuzhiyun /* 1 - 48000 samples per sec */
454*4882a593Smuzhiyun ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 0);
455*4882a593Smuzhiyun if (ret < 0) {
456*4882a593Smuzhiyun dev_err(dev->dev,
457*4882a593Smuzhiyun "failed to set alternate setting !\n");
458*4882a593Smuzhiyun
459*4882a593Smuzhiyun mutex_unlock(&dev->lock);
460*4882a593Smuzhiyun return ret;
461*4882a593Smuzhiyun }
462*4882a593Smuzhiyun
463*4882a593Smuzhiyun dev->adev.users--;
464*4882a593Smuzhiyun mutex_unlock(&dev->lock);
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun if (dev->adev.users == 0 && dev->adev.shutdown == 1) {
467*4882a593Smuzhiyun dev_dbg(dev->dev, "audio users: %d\n", dev->adev.users);
468*4882a593Smuzhiyun dev_dbg(dev->dev, "disabling audio stream!\n");
469*4882a593Smuzhiyun dev->adev.shutdown = 0;
470*4882a593Smuzhiyun dev_dbg(dev->dev, "released lock\n");
471*4882a593Smuzhiyun if (atomic_read(&dev->stream_started) > 0) {
472*4882a593Smuzhiyun atomic_set(&dev->stream_started, 0);
473*4882a593Smuzhiyun schedule_work(&dev->wq_trigger);
474*4882a593Smuzhiyun }
475*4882a593Smuzhiyun }
476*4882a593Smuzhiyun return 0;
477*4882a593Smuzhiyun }
478*4882a593Smuzhiyun
snd_cx231xx_prepare(struct snd_pcm_substream * substream)479*4882a593Smuzhiyun static int snd_cx231xx_prepare(struct snd_pcm_substream *substream)
480*4882a593Smuzhiyun {
481*4882a593Smuzhiyun struct cx231xx *dev = snd_pcm_substream_chip(substream);
482*4882a593Smuzhiyun
483*4882a593Smuzhiyun dev->adev.hwptr_done_capture = 0;
484*4882a593Smuzhiyun dev->adev.capture_transfer_done = 0;
485*4882a593Smuzhiyun
486*4882a593Smuzhiyun return 0;
487*4882a593Smuzhiyun }
488*4882a593Smuzhiyun
audio_trigger(struct work_struct * work)489*4882a593Smuzhiyun static void audio_trigger(struct work_struct *work)
490*4882a593Smuzhiyun {
491*4882a593Smuzhiyun struct cx231xx *dev = container_of(work, struct cx231xx, wq_trigger);
492*4882a593Smuzhiyun
493*4882a593Smuzhiyun if (atomic_read(&dev->stream_started)) {
494*4882a593Smuzhiyun dev_dbg(dev->dev, "starting capture");
495*4882a593Smuzhiyun if (is_fw_load(dev) == 0)
496*4882a593Smuzhiyun cx25840_call(dev, core, load_fw);
497*4882a593Smuzhiyun if (dev->USE_ISO)
498*4882a593Smuzhiyun cx231xx_init_audio_isoc(dev);
499*4882a593Smuzhiyun else
500*4882a593Smuzhiyun cx231xx_init_audio_bulk(dev);
501*4882a593Smuzhiyun } else {
502*4882a593Smuzhiyun dev_dbg(dev->dev, "stopping capture");
503*4882a593Smuzhiyun cx231xx_isoc_audio_deinit(dev);
504*4882a593Smuzhiyun }
505*4882a593Smuzhiyun }
506*4882a593Smuzhiyun
snd_cx231xx_capture_trigger(struct snd_pcm_substream * substream,int cmd)507*4882a593Smuzhiyun static int snd_cx231xx_capture_trigger(struct snd_pcm_substream *substream,
508*4882a593Smuzhiyun int cmd)
509*4882a593Smuzhiyun {
510*4882a593Smuzhiyun struct cx231xx *dev = snd_pcm_substream_chip(substream);
511*4882a593Smuzhiyun int retval = 0;
512*4882a593Smuzhiyun
513*4882a593Smuzhiyun if (dev->state & DEV_DISCONNECTED)
514*4882a593Smuzhiyun return -ENODEV;
515*4882a593Smuzhiyun
516*4882a593Smuzhiyun spin_lock(&dev->adev.slock);
517*4882a593Smuzhiyun switch (cmd) {
518*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_START:
519*4882a593Smuzhiyun atomic_set(&dev->stream_started, 1);
520*4882a593Smuzhiyun break;
521*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_STOP:
522*4882a593Smuzhiyun atomic_set(&dev->stream_started, 0);
523*4882a593Smuzhiyun break;
524*4882a593Smuzhiyun default:
525*4882a593Smuzhiyun retval = -EINVAL;
526*4882a593Smuzhiyun break;
527*4882a593Smuzhiyun }
528*4882a593Smuzhiyun spin_unlock(&dev->adev.slock);
529*4882a593Smuzhiyun
530*4882a593Smuzhiyun schedule_work(&dev->wq_trigger);
531*4882a593Smuzhiyun
532*4882a593Smuzhiyun return retval;
533*4882a593Smuzhiyun }
534*4882a593Smuzhiyun
snd_cx231xx_capture_pointer(struct snd_pcm_substream * substream)535*4882a593Smuzhiyun static snd_pcm_uframes_t snd_cx231xx_capture_pointer(struct snd_pcm_substream
536*4882a593Smuzhiyun *substream)
537*4882a593Smuzhiyun {
538*4882a593Smuzhiyun struct cx231xx *dev;
539*4882a593Smuzhiyun unsigned long flags;
540*4882a593Smuzhiyun snd_pcm_uframes_t hwptr_done;
541*4882a593Smuzhiyun
542*4882a593Smuzhiyun dev = snd_pcm_substream_chip(substream);
543*4882a593Smuzhiyun
544*4882a593Smuzhiyun spin_lock_irqsave(&dev->adev.slock, flags);
545*4882a593Smuzhiyun hwptr_done = dev->adev.hwptr_done_capture;
546*4882a593Smuzhiyun spin_unlock_irqrestore(&dev->adev.slock, flags);
547*4882a593Smuzhiyun
548*4882a593Smuzhiyun return hwptr_done;
549*4882a593Smuzhiyun }
550*4882a593Smuzhiyun
551*4882a593Smuzhiyun static const struct snd_pcm_ops snd_cx231xx_pcm_capture = {
552*4882a593Smuzhiyun .open = snd_cx231xx_capture_open,
553*4882a593Smuzhiyun .close = snd_cx231xx_pcm_close,
554*4882a593Smuzhiyun .prepare = snd_cx231xx_prepare,
555*4882a593Smuzhiyun .trigger = snd_cx231xx_capture_trigger,
556*4882a593Smuzhiyun .pointer = snd_cx231xx_capture_pointer,
557*4882a593Smuzhiyun };
558*4882a593Smuzhiyun
cx231xx_audio_init(struct cx231xx * dev)559*4882a593Smuzhiyun static int cx231xx_audio_init(struct cx231xx *dev)
560*4882a593Smuzhiyun {
561*4882a593Smuzhiyun struct cx231xx_audio *adev = &dev->adev;
562*4882a593Smuzhiyun struct snd_pcm *pcm;
563*4882a593Smuzhiyun struct snd_card *card;
564*4882a593Smuzhiyun static int devnr;
565*4882a593Smuzhiyun int err;
566*4882a593Smuzhiyun struct usb_interface *uif;
567*4882a593Smuzhiyun int i, isoc_pipe = 0;
568*4882a593Smuzhiyun
569*4882a593Smuzhiyun if (dev->has_alsa_audio != 1) {
570*4882a593Smuzhiyun /* This device does not support the extension (in this case
571*4882a593Smuzhiyun the device is expecting the snd-usb-audio module or
572*4882a593Smuzhiyun doesn't have analog audio support at all) */
573*4882a593Smuzhiyun return 0;
574*4882a593Smuzhiyun }
575*4882a593Smuzhiyun
576*4882a593Smuzhiyun dev_dbg(dev->dev,
577*4882a593Smuzhiyun "probing for cx231xx non standard usbaudio\n");
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun err = snd_card_new(dev->dev, index[devnr], "Cx231xx Audio",
580*4882a593Smuzhiyun THIS_MODULE, 0, &card);
581*4882a593Smuzhiyun if (err < 0)
582*4882a593Smuzhiyun return err;
583*4882a593Smuzhiyun
584*4882a593Smuzhiyun spin_lock_init(&adev->slock);
585*4882a593Smuzhiyun err = snd_pcm_new(card, "Cx231xx Audio", 0, 0, 1, &pcm);
586*4882a593Smuzhiyun if (err < 0)
587*4882a593Smuzhiyun goto err_free_card;
588*4882a593Smuzhiyun
589*4882a593Smuzhiyun snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE,
590*4882a593Smuzhiyun &snd_cx231xx_pcm_capture);
591*4882a593Smuzhiyun snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);
592*4882a593Smuzhiyun pcm->info_flags = 0;
593*4882a593Smuzhiyun pcm->private_data = dev;
594*4882a593Smuzhiyun strscpy(pcm->name, "Conexant cx231xx Capture", sizeof(pcm->name));
595*4882a593Smuzhiyun strscpy(card->driver, "Cx231xx-Audio", sizeof(card->driver));
596*4882a593Smuzhiyun strscpy(card->shortname, "Cx231xx Audio", sizeof(card->shortname));
597*4882a593Smuzhiyun strscpy(card->longname, "Conexant cx231xx Audio", sizeof(card->longname));
598*4882a593Smuzhiyun
599*4882a593Smuzhiyun INIT_WORK(&dev->wq_trigger, audio_trigger);
600*4882a593Smuzhiyun
601*4882a593Smuzhiyun err = snd_card_register(card);
602*4882a593Smuzhiyun if (err < 0)
603*4882a593Smuzhiyun goto err_free_card;
604*4882a593Smuzhiyun
605*4882a593Smuzhiyun adev->sndcard = card;
606*4882a593Smuzhiyun adev->udev = dev->udev;
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun /* compute alternate max packet sizes for Audio */
609*4882a593Smuzhiyun uif =
610*4882a593Smuzhiyun dev->udev->actconfig->interface[dev->current_pcb_config.
611*4882a593Smuzhiyun hs_config_info[0].interface_info.
612*4882a593Smuzhiyun audio_index + 1];
613*4882a593Smuzhiyun
614*4882a593Smuzhiyun if (uif->altsetting[0].desc.bNumEndpoints < isoc_pipe + 1) {
615*4882a593Smuzhiyun err = -ENODEV;
616*4882a593Smuzhiyun goto err_free_card;
617*4882a593Smuzhiyun }
618*4882a593Smuzhiyun
619*4882a593Smuzhiyun adev->end_point_addr =
620*4882a593Smuzhiyun uif->altsetting[0].endpoint[isoc_pipe].desc.
621*4882a593Smuzhiyun bEndpointAddress;
622*4882a593Smuzhiyun
623*4882a593Smuzhiyun adev->num_alt = uif->num_altsetting;
624*4882a593Smuzhiyun dev_info(dev->dev,
625*4882a593Smuzhiyun "audio EndPoint Addr 0x%x, Alternate settings: %i\n",
626*4882a593Smuzhiyun adev->end_point_addr, adev->num_alt);
627*4882a593Smuzhiyun adev->alt_max_pkt_size = kmalloc_array(32, adev->num_alt, GFP_KERNEL);
628*4882a593Smuzhiyun if (!adev->alt_max_pkt_size) {
629*4882a593Smuzhiyun err = -ENOMEM;
630*4882a593Smuzhiyun goto err_free_card;
631*4882a593Smuzhiyun }
632*4882a593Smuzhiyun
633*4882a593Smuzhiyun for (i = 0; i < adev->num_alt; i++) {
634*4882a593Smuzhiyun u16 tmp;
635*4882a593Smuzhiyun
636*4882a593Smuzhiyun if (uif->altsetting[i].desc.bNumEndpoints < isoc_pipe + 1) {
637*4882a593Smuzhiyun err = -ENODEV;
638*4882a593Smuzhiyun goto err_free_pkt_size;
639*4882a593Smuzhiyun }
640*4882a593Smuzhiyun
641*4882a593Smuzhiyun tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc.
642*4882a593Smuzhiyun wMaxPacketSize);
643*4882a593Smuzhiyun adev->alt_max_pkt_size[i] =
644*4882a593Smuzhiyun (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
645*4882a593Smuzhiyun dev_dbg(dev->dev,
646*4882a593Smuzhiyun "audio alternate setting %i, max size= %i\n", i,
647*4882a593Smuzhiyun adev->alt_max_pkt_size[i]);
648*4882a593Smuzhiyun }
649*4882a593Smuzhiyun
650*4882a593Smuzhiyun return 0;
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun err_free_pkt_size:
653*4882a593Smuzhiyun kfree(adev->alt_max_pkt_size);
654*4882a593Smuzhiyun err_free_card:
655*4882a593Smuzhiyun snd_card_free(card);
656*4882a593Smuzhiyun
657*4882a593Smuzhiyun return err;
658*4882a593Smuzhiyun }
659*4882a593Smuzhiyun
cx231xx_audio_fini(struct cx231xx * dev)660*4882a593Smuzhiyun static int cx231xx_audio_fini(struct cx231xx *dev)
661*4882a593Smuzhiyun {
662*4882a593Smuzhiyun if (dev == NULL)
663*4882a593Smuzhiyun return 0;
664*4882a593Smuzhiyun
665*4882a593Smuzhiyun if (dev->has_alsa_audio != 1) {
666*4882a593Smuzhiyun /* This device does not support the extension (in this case
667*4882a593Smuzhiyun the device is expecting the snd-usb-audio module or
668*4882a593Smuzhiyun doesn't have analog audio support at all) */
669*4882a593Smuzhiyun return 0;
670*4882a593Smuzhiyun }
671*4882a593Smuzhiyun
672*4882a593Smuzhiyun if (dev->adev.sndcard) {
673*4882a593Smuzhiyun snd_card_free(dev->adev.sndcard);
674*4882a593Smuzhiyun kfree(dev->adev.alt_max_pkt_size);
675*4882a593Smuzhiyun dev->adev.sndcard = NULL;
676*4882a593Smuzhiyun }
677*4882a593Smuzhiyun
678*4882a593Smuzhiyun return 0;
679*4882a593Smuzhiyun }
680*4882a593Smuzhiyun
681*4882a593Smuzhiyun static struct cx231xx_ops audio_ops = {
682*4882a593Smuzhiyun .id = CX231XX_AUDIO,
683*4882a593Smuzhiyun .name = "Cx231xx Audio Extension",
684*4882a593Smuzhiyun .init = cx231xx_audio_init,
685*4882a593Smuzhiyun .fini = cx231xx_audio_fini,
686*4882a593Smuzhiyun };
687*4882a593Smuzhiyun
cx231xx_alsa_register(void)688*4882a593Smuzhiyun static int __init cx231xx_alsa_register(void)
689*4882a593Smuzhiyun {
690*4882a593Smuzhiyun return cx231xx_register_extension(&audio_ops);
691*4882a593Smuzhiyun }
692*4882a593Smuzhiyun
cx231xx_alsa_unregister(void)693*4882a593Smuzhiyun static void __exit cx231xx_alsa_unregister(void)
694*4882a593Smuzhiyun {
695*4882a593Smuzhiyun cx231xx_unregister_extension(&audio_ops);
696*4882a593Smuzhiyun }
697*4882a593Smuzhiyun
698*4882a593Smuzhiyun MODULE_LICENSE("GPL");
699*4882a593Smuzhiyun MODULE_AUTHOR("Srinivasa Deevi <srinivasa.deevi@conexant.com>");
700*4882a593Smuzhiyun MODULE_DESCRIPTION("Cx231xx Audio driver");
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun module_init(cx231xx_alsa_register);
703*4882a593Smuzhiyun module_exit(cx231xx_alsa_unregister);
704