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