1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun * Copyright (c) 2013 Federico Simoncelli
3*4882a593Smuzhiyun * All rights reserved.
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Redistribution and use in source and binary forms, with or without
6*4882a593Smuzhiyun * modification, are permitted provided that the following conditions
7*4882a593Smuzhiyun * are met:
8*4882a593Smuzhiyun * 1. Redistributions of source code must retain the above copyright
9*4882a593Smuzhiyun * notice, this list of conditions, and the following disclaimer,
10*4882a593Smuzhiyun * without modification.
11*4882a593Smuzhiyun * 2. The name of the author may not be used to endorse or promote products
12*4882a593Smuzhiyun * derived from this software without specific prior written permission.
13*4882a593Smuzhiyun *
14*4882a593Smuzhiyun * Alternatively, this software may be distributed under the terms of the
15*4882a593Smuzhiyun * GNU General Public License ("GPL").
16*4882a593Smuzhiyun *
17*4882a593Smuzhiyun * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*4882a593Smuzhiyun * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*4882a593Smuzhiyun * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*4882a593Smuzhiyun * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*4882a593Smuzhiyun * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*4882a593Smuzhiyun * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*4882a593Smuzhiyun * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*4882a593Smuzhiyun * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*4882a593Smuzhiyun * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*4882a593Smuzhiyun * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*4882a593Smuzhiyun * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*4882a593Smuzhiyun */
29*4882a593Smuzhiyun /*
30*4882a593Smuzhiyun * Fushicai USBTV007 Audio-Video Grabber Driver
31*4882a593Smuzhiyun *
32*4882a593Smuzhiyun * Product web site:
33*4882a593Smuzhiyun * http://www.fushicai.com/products_detail/&productId=d05449ee-b690-42f9-a661-aa7353894bed.html
34*4882a593Smuzhiyun *
35*4882a593Smuzhiyun * No physical hardware was harmed running Windows during the
36*4882a593Smuzhiyun * reverse-engineering activity
37*4882a593Smuzhiyun */
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun #include <sound/core.h>
40*4882a593Smuzhiyun #include <sound/initval.h>
41*4882a593Smuzhiyun #include <sound/ac97_codec.h>
42*4882a593Smuzhiyun #include <sound/pcm_params.h>
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun #include "usbtv.h"
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun static const struct snd_pcm_hardware snd_usbtv_digital_hw = {
47*4882a593Smuzhiyun .info = SNDRV_PCM_INFO_BATCH |
48*4882a593Smuzhiyun SNDRV_PCM_INFO_MMAP |
49*4882a593Smuzhiyun SNDRV_PCM_INFO_INTERLEAVED |
50*4882a593Smuzhiyun SNDRV_PCM_INFO_BLOCK_TRANSFER |
51*4882a593Smuzhiyun SNDRV_PCM_INFO_MMAP_VALID,
52*4882a593Smuzhiyun .formats = SNDRV_PCM_FMTBIT_S16_LE,
53*4882a593Smuzhiyun .rates = SNDRV_PCM_RATE_48000,
54*4882a593Smuzhiyun .rate_min = 48000,
55*4882a593Smuzhiyun .rate_max = 48000,
56*4882a593Smuzhiyun .channels_min = 2,
57*4882a593Smuzhiyun .channels_max = 2,
58*4882a593Smuzhiyun .period_bytes_min = 11059,
59*4882a593Smuzhiyun .period_bytes_max = 13516,
60*4882a593Smuzhiyun .periods_min = 2,
61*4882a593Smuzhiyun .periods_max = 98,
62*4882a593Smuzhiyun .buffer_bytes_max = 62720 * 8, /* value in usbaudio.c */
63*4882a593Smuzhiyun };
64*4882a593Smuzhiyun
snd_usbtv_pcm_open(struct snd_pcm_substream * substream)65*4882a593Smuzhiyun static int snd_usbtv_pcm_open(struct snd_pcm_substream *substream)
66*4882a593Smuzhiyun {
67*4882a593Smuzhiyun struct usbtv *chip = snd_pcm_substream_chip(substream);
68*4882a593Smuzhiyun struct snd_pcm_runtime *runtime = substream->runtime;
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun chip->snd_substream = substream;
71*4882a593Smuzhiyun runtime->hw = snd_usbtv_digital_hw;
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun return 0;
74*4882a593Smuzhiyun }
75*4882a593Smuzhiyun
snd_usbtv_pcm_close(struct snd_pcm_substream * substream)76*4882a593Smuzhiyun static int snd_usbtv_pcm_close(struct snd_pcm_substream *substream)
77*4882a593Smuzhiyun {
78*4882a593Smuzhiyun struct usbtv *chip = snd_pcm_substream_chip(substream);
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun if (atomic_read(&chip->snd_stream)) {
81*4882a593Smuzhiyun atomic_set(&chip->snd_stream, 0);
82*4882a593Smuzhiyun schedule_work(&chip->snd_trigger);
83*4882a593Smuzhiyun }
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun return 0;
86*4882a593Smuzhiyun }
87*4882a593Smuzhiyun
snd_usbtv_prepare(struct snd_pcm_substream * substream)88*4882a593Smuzhiyun static int snd_usbtv_prepare(struct snd_pcm_substream *substream)
89*4882a593Smuzhiyun {
90*4882a593Smuzhiyun struct usbtv *chip = snd_pcm_substream_chip(substream);
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun chip->snd_buffer_pos = 0;
93*4882a593Smuzhiyun chip->snd_period_pos = 0;
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun return 0;
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun
usbtv_audio_urb_received(struct urb * urb)98*4882a593Smuzhiyun static void usbtv_audio_urb_received(struct urb *urb)
99*4882a593Smuzhiyun {
100*4882a593Smuzhiyun struct usbtv *chip = urb->context;
101*4882a593Smuzhiyun struct snd_pcm_substream *substream = chip->snd_substream;
102*4882a593Smuzhiyun struct snd_pcm_runtime *runtime = substream->runtime;
103*4882a593Smuzhiyun size_t i, frame_bytes, chunk_length, buffer_pos, period_pos;
104*4882a593Smuzhiyun int period_elapsed;
105*4882a593Smuzhiyun unsigned long flags;
106*4882a593Smuzhiyun void *urb_current;
107*4882a593Smuzhiyun
108*4882a593Smuzhiyun switch (urb->status) {
109*4882a593Smuzhiyun case 0:
110*4882a593Smuzhiyun case -ETIMEDOUT:
111*4882a593Smuzhiyun break;
112*4882a593Smuzhiyun case -ENOENT:
113*4882a593Smuzhiyun case -EPROTO:
114*4882a593Smuzhiyun case -ECONNRESET:
115*4882a593Smuzhiyun case -ESHUTDOWN:
116*4882a593Smuzhiyun return;
117*4882a593Smuzhiyun default:
118*4882a593Smuzhiyun dev_warn(chip->dev, "unknown audio urb status %i\n",
119*4882a593Smuzhiyun urb->status);
120*4882a593Smuzhiyun }
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun if (!atomic_read(&chip->snd_stream))
123*4882a593Smuzhiyun return;
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun frame_bytes = runtime->frame_bits >> 3;
126*4882a593Smuzhiyun chunk_length = USBTV_CHUNK / frame_bytes;
127*4882a593Smuzhiyun
128*4882a593Smuzhiyun buffer_pos = chip->snd_buffer_pos;
129*4882a593Smuzhiyun period_pos = chip->snd_period_pos;
130*4882a593Smuzhiyun period_elapsed = 0;
131*4882a593Smuzhiyun
132*4882a593Smuzhiyun for (i = 0; i < urb->actual_length; i += USBTV_CHUNK_SIZE) {
133*4882a593Smuzhiyun urb_current = urb->transfer_buffer + i + USBTV_AUDIO_HDRSIZE;
134*4882a593Smuzhiyun
135*4882a593Smuzhiyun if (buffer_pos + chunk_length >= runtime->buffer_size) {
136*4882a593Smuzhiyun size_t cnt = (runtime->buffer_size - buffer_pos) *
137*4882a593Smuzhiyun frame_bytes;
138*4882a593Smuzhiyun memcpy(runtime->dma_area + buffer_pos * frame_bytes,
139*4882a593Smuzhiyun urb_current, cnt);
140*4882a593Smuzhiyun memcpy(runtime->dma_area, urb_current + cnt,
141*4882a593Smuzhiyun chunk_length * frame_bytes - cnt);
142*4882a593Smuzhiyun } else {
143*4882a593Smuzhiyun memcpy(runtime->dma_area + buffer_pos * frame_bytes,
144*4882a593Smuzhiyun urb_current, chunk_length * frame_bytes);
145*4882a593Smuzhiyun }
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun buffer_pos += chunk_length;
148*4882a593Smuzhiyun period_pos += chunk_length;
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun if (buffer_pos >= runtime->buffer_size)
151*4882a593Smuzhiyun buffer_pos -= runtime->buffer_size;
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun if (period_pos >= runtime->period_size) {
154*4882a593Smuzhiyun period_pos -= runtime->period_size;
155*4882a593Smuzhiyun period_elapsed = 1;
156*4882a593Smuzhiyun }
157*4882a593Smuzhiyun }
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun snd_pcm_stream_lock_irqsave(substream, flags);
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun chip->snd_buffer_pos = buffer_pos;
162*4882a593Smuzhiyun chip->snd_period_pos = period_pos;
163*4882a593Smuzhiyun
164*4882a593Smuzhiyun snd_pcm_stream_unlock_irqrestore(substream, flags);
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun if (period_elapsed)
167*4882a593Smuzhiyun snd_pcm_period_elapsed(substream);
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun usb_submit_urb(urb, GFP_ATOMIC);
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun
usbtv_audio_start(struct usbtv * chip)172*4882a593Smuzhiyun static int usbtv_audio_start(struct usbtv *chip)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun unsigned int pipe;
175*4882a593Smuzhiyun static const u16 setup[][2] = {
176*4882a593Smuzhiyun /* These seem to enable the device. */
177*4882a593Smuzhiyun { USBTV_BASE + 0x0008, 0x0001 },
178*4882a593Smuzhiyun { USBTV_BASE + 0x01d0, 0x00ff },
179*4882a593Smuzhiyun { USBTV_BASE + 0x01d9, 0x0002 },
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun { USBTV_BASE + 0x01da, 0x0013 },
182*4882a593Smuzhiyun { USBTV_BASE + 0x01db, 0x0012 },
183*4882a593Smuzhiyun { USBTV_BASE + 0x01e9, 0x0002 },
184*4882a593Smuzhiyun { USBTV_BASE + 0x01ec, 0x006c },
185*4882a593Smuzhiyun { USBTV_BASE + 0x0294, 0x0020 },
186*4882a593Smuzhiyun { USBTV_BASE + 0x0255, 0x00cf },
187*4882a593Smuzhiyun { USBTV_BASE + 0x0256, 0x0020 },
188*4882a593Smuzhiyun { USBTV_BASE + 0x01eb, 0x0030 },
189*4882a593Smuzhiyun { USBTV_BASE + 0x027d, 0x00a6 },
190*4882a593Smuzhiyun { USBTV_BASE + 0x0280, 0x0011 },
191*4882a593Smuzhiyun { USBTV_BASE + 0x0281, 0x0040 },
192*4882a593Smuzhiyun { USBTV_BASE + 0x0282, 0x0011 },
193*4882a593Smuzhiyun { USBTV_BASE + 0x0283, 0x0040 },
194*4882a593Smuzhiyun { 0xf891, 0x0010 },
195*4882a593Smuzhiyun
196*4882a593Smuzhiyun /* this sets the input from composite */
197*4882a593Smuzhiyun { USBTV_BASE + 0x0284, 0x00aa },
198*4882a593Smuzhiyun };
199*4882a593Smuzhiyun
200*4882a593Smuzhiyun chip->snd_bulk_urb = usb_alloc_urb(0, GFP_KERNEL);
201*4882a593Smuzhiyun if (chip->snd_bulk_urb == NULL)
202*4882a593Smuzhiyun goto err_alloc_urb;
203*4882a593Smuzhiyun
204*4882a593Smuzhiyun pipe = usb_rcvbulkpipe(chip->udev, USBTV_AUDIO_ENDP);
205*4882a593Smuzhiyun
206*4882a593Smuzhiyun chip->snd_bulk_urb->transfer_buffer = kzalloc(
207*4882a593Smuzhiyun USBTV_AUDIO_URBSIZE, GFP_KERNEL);
208*4882a593Smuzhiyun if (chip->snd_bulk_urb->transfer_buffer == NULL)
209*4882a593Smuzhiyun goto err_transfer_buffer;
210*4882a593Smuzhiyun
211*4882a593Smuzhiyun usb_fill_bulk_urb(chip->snd_bulk_urb, chip->udev, pipe,
212*4882a593Smuzhiyun chip->snd_bulk_urb->transfer_buffer, USBTV_AUDIO_URBSIZE,
213*4882a593Smuzhiyun usbtv_audio_urb_received, chip);
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun /* starting the stream */
216*4882a593Smuzhiyun usbtv_set_regs(chip, setup, ARRAY_SIZE(setup));
217*4882a593Smuzhiyun
218*4882a593Smuzhiyun usb_clear_halt(chip->udev, pipe);
219*4882a593Smuzhiyun usb_submit_urb(chip->snd_bulk_urb, GFP_ATOMIC);
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun return 0;
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun err_transfer_buffer:
224*4882a593Smuzhiyun usb_free_urb(chip->snd_bulk_urb);
225*4882a593Smuzhiyun chip->snd_bulk_urb = NULL;
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun err_alloc_urb:
228*4882a593Smuzhiyun return -ENOMEM;
229*4882a593Smuzhiyun }
230*4882a593Smuzhiyun
usbtv_audio_stop(struct usbtv * chip)231*4882a593Smuzhiyun static int usbtv_audio_stop(struct usbtv *chip)
232*4882a593Smuzhiyun {
233*4882a593Smuzhiyun static const u16 setup[][2] = {
234*4882a593Smuzhiyun /* The original windows driver sometimes sends also:
235*4882a593Smuzhiyun * { USBTV_BASE + 0x00a2, 0x0013 }
236*4882a593Smuzhiyun * but it seems useless and its real effects are untested at
237*4882a593Smuzhiyun * the moment.
238*4882a593Smuzhiyun */
239*4882a593Smuzhiyun { USBTV_BASE + 0x027d, 0x0000 },
240*4882a593Smuzhiyun { USBTV_BASE + 0x0280, 0x0010 },
241*4882a593Smuzhiyun { USBTV_BASE + 0x0282, 0x0010 },
242*4882a593Smuzhiyun };
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun if (chip->snd_bulk_urb) {
245*4882a593Smuzhiyun usb_kill_urb(chip->snd_bulk_urb);
246*4882a593Smuzhiyun kfree(chip->snd_bulk_urb->transfer_buffer);
247*4882a593Smuzhiyun usb_free_urb(chip->snd_bulk_urb);
248*4882a593Smuzhiyun chip->snd_bulk_urb = NULL;
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun usbtv_set_regs(chip, setup, ARRAY_SIZE(setup));
252*4882a593Smuzhiyun
253*4882a593Smuzhiyun return 0;
254*4882a593Smuzhiyun }
255*4882a593Smuzhiyun
usbtv_audio_suspend(struct usbtv * usbtv)256*4882a593Smuzhiyun void usbtv_audio_suspend(struct usbtv *usbtv)
257*4882a593Smuzhiyun {
258*4882a593Smuzhiyun if (atomic_read(&usbtv->snd_stream) && usbtv->snd_bulk_urb)
259*4882a593Smuzhiyun usb_kill_urb(usbtv->snd_bulk_urb);
260*4882a593Smuzhiyun }
261*4882a593Smuzhiyun
usbtv_audio_resume(struct usbtv * usbtv)262*4882a593Smuzhiyun void usbtv_audio_resume(struct usbtv *usbtv)
263*4882a593Smuzhiyun {
264*4882a593Smuzhiyun if (atomic_read(&usbtv->snd_stream) && usbtv->snd_bulk_urb)
265*4882a593Smuzhiyun usb_submit_urb(usbtv->snd_bulk_urb, GFP_ATOMIC);
266*4882a593Smuzhiyun }
267*4882a593Smuzhiyun
snd_usbtv_trigger(struct work_struct * work)268*4882a593Smuzhiyun static void snd_usbtv_trigger(struct work_struct *work)
269*4882a593Smuzhiyun {
270*4882a593Smuzhiyun struct usbtv *chip = container_of(work, struct usbtv, snd_trigger);
271*4882a593Smuzhiyun
272*4882a593Smuzhiyun if (!chip->snd)
273*4882a593Smuzhiyun return;
274*4882a593Smuzhiyun
275*4882a593Smuzhiyun if (atomic_read(&chip->snd_stream))
276*4882a593Smuzhiyun usbtv_audio_start(chip);
277*4882a593Smuzhiyun else
278*4882a593Smuzhiyun usbtv_audio_stop(chip);
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun
snd_usbtv_card_trigger(struct snd_pcm_substream * substream,int cmd)281*4882a593Smuzhiyun static int snd_usbtv_card_trigger(struct snd_pcm_substream *substream, int cmd)
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun struct usbtv *chip = snd_pcm_substream_chip(substream);
284*4882a593Smuzhiyun
285*4882a593Smuzhiyun switch (cmd) {
286*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_START:
287*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_RESUME:
288*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
289*4882a593Smuzhiyun atomic_set(&chip->snd_stream, 1);
290*4882a593Smuzhiyun break;
291*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_STOP:
292*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_SUSPEND:
293*4882a593Smuzhiyun case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
294*4882a593Smuzhiyun atomic_set(&chip->snd_stream, 0);
295*4882a593Smuzhiyun break;
296*4882a593Smuzhiyun default:
297*4882a593Smuzhiyun return -EINVAL;
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun
300*4882a593Smuzhiyun schedule_work(&chip->snd_trigger);
301*4882a593Smuzhiyun
302*4882a593Smuzhiyun return 0;
303*4882a593Smuzhiyun }
304*4882a593Smuzhiyun
snd_usbtv_pointer(struct snd_pcm_substream * substream)305*4882a593Smuzhiyun static snd_pcm_uframes_t snd_usbtv_pointer(struct snd_pcm_substream *substream)
306*4882a593Smuzhiyun {
307*4882a593Smuzhiyun struct usbtv *chip = snd_pcm_substream_chip(substream);
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun return chip->snd_buffer_pos;
310*4882a593Smuzhiyun }
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun static const struct snd_pcm_ops snd_usbtv_pcm_ops = {
313*4882a593Smuzhiyun .open = snd_usbtv_pcm_open,
314*4882a593Smuzhiyun .close = snd_usbtv_pcm_close,
315*4882a593Smuzhiyun .prepare = snd_usbtv_prepare,
316*4882a593Smuzhiyun .trigger = snd_usbtv_card_trigger,
317*4882a593Smuzhiyun .pointer = snd_usbtv_pointer,
318*4882a593Smuzhiyun };
319*4882a593Smuzhiyun
usbtv_audio_init(struct usbtv * usbtv)320*4882a593Smuzhiyun int usbtv_audio_init(struct usbtv *usbtv)
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun int rv;
323*4882a593Smuzhiyun struct snd_card *card;
324*4882a593Smuzhiyun struct snd_pcm *pcm;
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun INIT_WORK(&usbtv->snd_trigger, snd_usbtv_trigger);
327*4882a593Smuzhiyun atomic_set(&usbtv->snd_stream, 0);
328*4882a593Smuzhiyun
329*4882a593Smuzhiyun rv = snd_card_new(&usbtv->udev->dev, SNDRV_DEFAULT_IDX1, "usbtv",
330*4882a593Smuzhiyun THIS_MODULE, 0, &card);
331*4882a593Smuzhiyun if (rv < 0)
332*4882a593Smuzhiyun return rv;
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun strscpy(card->driver, usbtv->dev->driver->name, sizeof(card->driver));
335*4882a593Smuzhiyun strscpy(card->shortname, "usbtv", sizeof(card->shortname));
336*4882a593Smuzhiyun snprintf(card->longname, sizeof(card->longname),
337*4882a593Smuzhiyun "USBTV Audio at bus %d device %d", usbtv->udev->bus->busnum,
338*4882a593Smuzhiyun usbtv->udev->devnum);
339*4882a593Smuzhiyun
340*4882a593Smuzhiyun snd_card_set_dev(card, usbtv->dev);
341*4882a593Smuzhiyun
342*4882a593Smuzhiyun usbtv->snd = card;
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun rv = snd_pcm_new(card, "USBTV Audio", 0, 0, 1, &pcm);
345*4882a593Smuzhiyun if (rv < 0)
346*4882a593Smuzhiyun goto err;
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun strscpy(pcm->name, "USBTV Audio Input", sizeof(pcm->name));
349*4882a593Smuzhiyun pcm->info_flags = 0;
350*4882a593Smuzhiyun pcm->private_data = usbtv;
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_usbtv_pcm_ops);
353*4882a593Smuzhiyun snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
354*4882a593Smuzhiyun NULL, USBTV_AUDIO_BUFFER, USBTV_AUDIO_BUFFER);
355*4882a593Smuzhiyun
356*4882a593Smuzhiyun rv = snd_card_register(card);
357*4882a593Smuzhiyun if (rv)
358*4882a593Smuzhiyun goto err;
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun return 0;
361*4882a593Smuzhiyun
362*4882a593Smuzhiyun err:
363*4882a593Smuzhiyun usbtv->snd = NULL;
364*4882a593Smuzhiyun snd_card_free(card);
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun return rv;
367*4882a593Smuzhiyun }
368*4882a593Smuzhiyun
usbtv_audio_free(struct usbtv * usbtv)369*4882a593Smuzhiyun void usbtv_audio_free(struct usbtv *usbtv)
370*4882a593Smuzhiyun {
371*4882a593Smuzhiyun cancel_work_sync(&usbtv->snd_trigger);
372*4882a593Smuzhiyun
373*4882a593Smuzhiyun if (usbtv->snd && usbtv->udev) {
374*4882a593Smuzhiyun snd_card_free_when_closed(usbtv->snd);
375*4882a593Smuzhiyun usbtv->snd = NULL;
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun }
378