2008-01-05 20:55:47 +08:00
|
|
|
/*
|
|
|
|
* Empiatech em28x1 audio extension
|
|
|
|
*
|
|
|
|
* Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com>
|
|
|
|
*
|
2013-12-29 08:16:26 +08:00
|
|
|
* Copyright (C) 2007-2014 Mauro Carvalho Chehab
|
2008-01-05 20:57:31 +08:00
|
|
|
* - Port to work with the in-kernel driver
|
2011-06-18 02:15:12 +08:00
|
|
|
* - Cleanups, fixes, alsa-controls, etc.
|
2008-01-05 20:57:31 +08:00
|
|
|
*
|
2008-01-05 20:55:47 +08:00
|
|
|
* This driver is based on my previous au600 usb pstn audio driver
|
|
|
|
* and inherits all the copyrights
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/kernel.h>
|
|
|
|
#include <linux/usb.h>
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/sound.h>
|
|
|
|
#include <linux/spinlock.h>
|
|
|
|
#include <linux/soundcard.h>
|
|
|
|
#include <linux/slab.h>
|
|
|
|
#include <linux/vmalloc.h>
|
|
|
|
#include <linux/proc_fs.h>
|
2008-01-05 20:57:31 +08:00
|
|
|
#include <linux/module.h>
|
2008-01-05 20:55:47 +08:00
|
|
|
#include <sound/core.h>
|
|
|
|
#include <sound/pcm.h>
|
|
|
|
#include <sound/pcm_params.h>
|
|
|
|
#include <sound/info.h>
|
|
|
|
#include <sound/initval.h>
|
|
|
|
#include <sound/control.h>
|
2011-06-20 00:06:40 +08:00
|
|
|
#include <sound/tlv.h>
|
2012-06-12 02:17:23 +08:00
|
|
|
#include <sound/ac97_codec.h>
|
2008-01-05 20:55:47 +08:00
|
|
|
#include <media/v4l2-common.h>
|
|
|
|
#include "em28xx.h"
|
|
|
|
|
2008-01-05 20:57:31 +08:00
|
|
|
static int debug;
|
|
|
|
module_param(debug, int, 0644);
|
|
|
|
MODULE_PARM_DESC(debug, "activates debug info");
|
2008-01-05 20:55:47 +08:00
|
|
|
|
[media] em28xx-audio: don't hardcode audio URB calculus
The current code hardcodes the number of audio URBs, the number
of packets per URB and the maximum URB size.
This is not a good idea, as it:
- wastes more bandwidth than necessary, by using a very
large number of packets;
- those constants are bound to an specific scenario, with
a bandwidth of 48 kHz;
- don't take the maximum endpoint size into account;
- with urb->interval = 1 on xHCI, those constraints cause a "funny"
setup: URBs with 64 packets inside, with only 24 bytes total. E. g.
a complete waste of space.
Change the code to do dynamic URB audio calculus and allocation.
For now, use the same constraints as used before this patch, to
avoid regressions.
A good scenario (tested) seems to use those defines, instead:
#define EM28XX_MAX_AUDIO_BUFS 8
#define EM28XX_MIN_AUDIO_PACKETS 2
But let's not do such change here, letting the optimization to
happen on latter patches, after more tests.
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
2014-01-10 16:53:24 +08:00
|
|
|
#define EM28XX_MAX_AUDIO_BUFS 5
|
|
|
|
#define EM28XX_MIN_AUDIO_PACKETS 64
|
[media] em28xx-audio: fix the period size in bytes
If the period size is wrong, userspace will assume a wrong delay
any may negociate an inadequate value.
The em28xx devices use 8 for URB interval, in microframes,
and the driver programs it to have 64 packets.
That means that the IRQ sampling period is 125 * 8 * 64,
with is equal to 64 ms.
So, that's the minimal latency with the current settings. It is
possible to program a lower latency, by using less than 64 packets,
but that increases the amount of bandwitdh used, and the number of
IRQ events per second.
In any case, in order to support it, the driver logic should be
changed to fill those parameters in realtime.
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
2014-01-11 00:29:16 +08:00
|
|
|
|
2008-01-05 20:57:31 +08:00
|
|
|
#define dprintk(fmt, arg...) do { \
|
|
|
|
if (debug) \
|
|
|
|
printk(KERN_INFO "em28xx-audio %s: " fmt, \
|
2008-04-09 10:20:00 +08:00
|
|
|
__func__, ##arg); \
|
2008-01-05 20:57:31 +08:00
|
|
|
} while (0)
|
2008-01-05 20:55:47 +08:00
|
|
|
|
2008-01-05 20:57:31 +08:00
|
|
|
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
|
2008-01-05 20:55:47 +08:00
|
|
|
|
2009-02-09 00:09:11 +08:00
|
|
|
static int em28xx_deinit_isoc_audio(struct em28xx *dev)
|
2008-01-05 20:55:47 +08:00
|
|
|
{
|
2008-01-05 20:57:31 +08:00
|
|
|
int i;
|
2008-01-05 20:55:47 +08:00
|
|
|
|
2008-01-05 20:57:31 +08:00
|
|
|
dprintk("Stopping isoc\n");
|
[media] em28xx-audio: don't hardcode audio URB calculus
The current code hardcodes the number of audio URBs, the number
of packets per URB and the maximum URB size.
This is not a good idea, as it:
- wastes more bandwidth than necessary, by using a very
large number of packets;
- those constants are bound to an specific scenario, with
a bandwidth of 48 kHz;
- don't take the maximum endpoint size into account;
- with urb->interval = 1 on xHCI, those constraints cause a "funny"
setup: URBs with 64 packets inside, with only 24 bytes total. E. g.
a complete waste of space.
Change the code to do dynamic URB audio calculus and allocation.
For now, use the same constraints as used before this patch, to
avoid regressions.
A good scenario (tested) seems to use those defines, instead:
#define EM28XX_MAX_AUDIO_BUFS 8
#define EM28XX_MIN_AUDIO_PACKETS 2
But let's not do such change here, letting the optimization to
happen on latter patches, after more tests.
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
2014-01-10 16:53:24 +08:00
|
|
|
for (i = 0; i < dev->adev.num_urb; i++) {
|
2013-12-28 22:47:16 +08:00
|
|
|
struct urb *urb = dev->adev.urb[i];
|
|
|
|
|
2009-01-26 00:08:07 +08:00
|
|
|
if (!irqs_disabled())
|
2013-12-28 22:47:16 +08:00
|
|
|
usb_kill_urb(urb);
|
2009-01-26 00:08:07 +08:00
|
|
|
else
|
2013-12-28 22:47:16 +08:00
|
|
|
usb_unlink_urb(urb);
|
2008-01-05 20:55:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void em28xx_audio_isocirq(struct urb *urb)
|
|
|
|
{
|
2008-01-05 20:57:31 +08:00
|
|
|
struct em28xx *dev = urb->context;
|
|
|
|
int i;
|
|
|
|
unsigned int oldptr;
|
|
|
|
int period_elapsed = 0;
|
|
|
|
int status;
|
|
|
|
unsigned char *cp;
|
|
|
|
unsigned int stride;
|
2008-01-05 20:55:47 +08:00
|
|
|
struct snd_pcm_substream *substream;
|
2008-01-05 20:57:31 +08:00
|
|
|
struct snd_pcm_runtime *runtime;
|
2009-02-09 00:09:11 +08:00
|
|
|
|
2014-01-12 21:21:42 +08:00
|
|
|
if (dev->disconnected) {
|
|
|
|
dprintk("device disconnected while streaming. URB status=%d.\n", urb->status);
|
|
|
|
atomic_set(&dev->stream_started, 0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-02-09 00:09:11 +08:00
|
|
|
switch (urb->status) {
|
|
|
|
case 0: /* success */
|
|
|
|
case -ETIMEDOUT: /* NAK */
|
|
|
|
break;
|
|
|
|
case -ECONNRESET: /* kill */
|
|
|
|
case -ENOENT:
|
|
|
|
case -ESHUTDOWN:
|
|
|
|
return;
|
|
|
|
default: /* error */
|
|
|
|
dprintk("urb completition error %d.\n", urb->status);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2010-10-10 02:53:58 +08:00
|
|
|
if (atomic_read(&dev->stream_started) == 0)
|
|
|
|
return;
|
|
|
|
|
2008-12-31 20:37:33 +08:00
|
|
|
if (dev->adev.capture_pcm_substream) {
|
|
|
|
substream = dev->adev.capture_pcm_substream;
|
2008-01-05 20:56:24 +08:00
|
|
|
runtime = substream->runtime;
|
2008-01-05 20:55:47 +08:00
|
|
|
stride = runtime->frame_bits >> 3;
|
2008-01-05 20:57:31 +08:00
|
|
|
|
2008-01-05 20:56:24 +08:00
|
|
|
for (i = 0; i < urb->number_of_packets; i++) {
|
|
|
|
int length =
|
|
|
|
urb->iso_frame_desc[i].actual_length / stride;
|
|
|
|
cp = (unsigned char *)urb->transfer_buffer +
|
|
|
|
urb->iso_frame_desc[i].offset;
|
2008-01-05 20:55:47 +08:00
|
|
|
|
2008-01-05 20:56:24 +08:00
|
|
|
if (!length)
|
2008-01-05 20:55:47 +08:00
|
|
|
continue;
|
|
|
|
|
2008-12-31 20:37:33 +08:00
|
|
|
oldptr = dev->adev.hwptr_done_capture;
|
2008-11-24 19:45:57 +08:00
|
|
|
if (oldptr + length >= runtime->buffer_size) {
|
|
|
|
unsigned int cnt =
|
|
|
|
runtime->buffer_size - oldptr;
|
|
|
|
memcpy(runtime->dma_area + oldptr * stride, cp,
|
|
|
|
cnt * stride);
|
|
|
|
memcpy(runtime->dma_area, cp + cnt * stride,
|
|
|
|
length * stride - cnt * stride);
|
|
|
|
} else {
|
|
|
|
memcpy(runtime->dma_area + oldptr * stride, cp,
|
|
|
|
length * stride);
|
|
|
|
}
|
|
|
|
|
|
|
|
snd_pcm_stream_lock(substream);
|
|
|
|
|
2008-12-31 20:37:33 +08:00
|
|
|
dev->adev.hwptr_done_capture += length;
|
|
|
|
if (dev->adev.hwptr_done_capture >=
|
2008-01-05 20:56:24 +08:00
|
|
|
runtime->buffer_size)
|
2008-12-31 20:37:33 +08:00
|
|
|
dev->adev.hwptr_done_capture -=
|
2008-01-05 20:56:24 +08:00
|
|
|
runtime->buffer_size;
|
2008-01-05 20:55:47 +08:00
|
|
|
|
2008-12-31 20:37:33 +08:00
|
|
|
dev->adev.capture_transfer_done += length;
|
|
|
|
if (dev->adev.capture_transfer_done >=
|
2008-01-05 20:56:24 +08:00
|
|
|
runtime->period_size) {
|
2008-12-31 20:37:33 +08:00
|
|
|
dev->adev.capture_transfer_done -=
|
2008-01-05 20:56:24 +08:00
|
|
|
runtime->period_size;
|
|
|
|
period_elapsed = 1;
|
2008-01-05 20:55:47 +08:00
|
|
|
}
|
2008-01-05 20:57:31 +08:00
|
|
|
|
2008-11-24 19:45:57 +08:00
|
|
|
snd_pcm_stream_unlock(substream);
|
2008-01-05 20:55:47 +08:00
|
|
|
}
|
2008-01-05 20:57:31 +08:00
|
|
|
if (period_elapsed)
|
2008-01-05 20:55:47 +08:00
|
|
|
snd_pcm_period_elapsed(substream);
|
|
|
|
}
|
|
|
|
urb->status = 0;
|
2008-01-05 20:56:24 +08:00
|
|
|
|
2008-01-05 20:57:31 +08:00
|
|
|
status = usb_submit_urb(urb, GFP_ATOMIC);
|
2014-01-15 01:34:13 +08:00
|
|
|
if (status < 0)
|
2008-01-05 20:56:24 +08:00
|
|
|
em28xx_errdev("resubmit of audio urb failed (error=%i)\n",
|
|
|
|
status);
|
2008-01-05 20:55:47 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int em28xx_init_audio_isoc(struct em28xx *dev)
|
|
|
|
{
|
2008-01-05 20:57:31 +08:00
|
|
|
int i, errCode;
|
|
|
|
|
|
|
|
dprintk("Starting isoc transfers\n");
|
2008-01-05 20:55:47 +08:00
|
|
|
|
2013-12-29 08:16:26 +08:00
|
|
|
/* Start streaming */
|
[media] em28xx-audio: don't hardcode audio URB calculus
The current code hardcodes the number of audio URBs, the number
of packets per URB and the maximum URB size.
This is not a good idea, as it:
- wastes more bandwidth than necessary, by using a very
large number of packets;
- those constants are bound to an specific scenario, with
a bandwidth of 48 kHz;
- don't take the maximum endpoint size into account;
- with urb->interval = 1 on xHCI, those constraints cause a "funny"
setup: URBs with 64 packets inside, with only 24 bytes total. E. g.
a complete waste of space.
Change the code to do dynamic URB audio calculus and allocation.
For now, use the same constraints as used before this patch, to
avoid regressions.
A good scenario (tested) seems to use those defines, instead:
#define EM28XX_MAX_AUDIO_BUFS 8
#define EM28XX_MIN_AUDIO_PACKETS 2
But let's not do such change here, letting the optimization to
happen on latter patches, after more tests.
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
2014-01-10 16:53:24 +08:00
|
|
|
for (i = 0; i < dev->adev.num_urb; i++) {
|
2013-12-29 08:16:26 +08:00
|
|
|
memset(dev->adev.transfer_buffer[i], 0x80,
|
|
|
|
dev->adev.urb[i]->transfer_buffer_length);
|
2008-01-05 20:57:31 +08:00
|
|
|
|
2008-12-31 20:37:33 +08:00
|
|
|
errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
|
2008-01-05 20:56:24 +08:00
|
|
|
if (errCode) {
|
2014-01-15 01:34:13 +08:00
|
|
|
em28xx_errdev("submit of audio urb failed (error=%i)\n",
|
|
|
|
errCode);
|
2009-02-09 00:09:11 +08:00
|
|
|
em28xx_deinit_isoc_audio(dev);
|
2011-06-19 21:15:35 +08:00
|
|
|
atomic_set(&dev->stream_started, 0);
|
2008-01-05 20:55:47 +08:00
|
|
|
return errCode;
|
|
|
|
}
|
2011-06-19 21:15:35 +08:00
|
|
|
|
2008-01-05 20:55:47 +08:00
|
|
|
}
|
2008-01-05 20:57:31 +08:00
|
|
|
|
2008-01-05 20:55:47 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2008-01-05 20:57:31 +08:00
|
|
|
static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
|
|
|
|
size_t size)
|
|
|
|
{
|
|
|
|
struct snd_pcm_runtime *runtime = subs->runtime;
|
|
|
|
|
2009-02-11 10:28:24 +08:00
|
|
|
dprintk("Allocating vbuffer\n");
|
2008-01-05 20:57:31 +08:00
|
|
|
if (runtime->dma_area) {
|
|
|
|
if (runtime->dma_bytes > size)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
vfree(runtime->dma_area);
|
|
|
|
}
|
|
|
|
runtime->dma_area = vmalloc(size);
|
|
|
|
if (!runtime->dma_area)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
runtime->dma_bytes = size;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct snd_pcm_hardware snd_em28xx_hw_capture = {
|
|
|
|
.info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
|
|
|
SNDRV_PCM_INFO_MMAP |
|
|
|
|
SNDRV_PCM_INFO_INTERLEAVED |
|
2011-06-20 00:39:31 +08:00
|
|
|
SNDRV_PCM_INFO_BATCH |
|
2008-01-05 20:57:31 +08:00
|
|
|
SNDRV_PCM_INFO_MMAP_VALID,
|
|
|
|
|
|
|
|
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
|
|
|
|
[media] em28xx-audio: fix the period size in bytes
If the period size is wrong, userspace will assume a wrong delay
any may negociate an inadequate value.
The em28xx devices use 8 for URB interval, in microframes,
and the driver programs it to have 64 packets.
That means that the IRQ sampling period is 125 * 8 * 64,
with is equal to 64 ms.
So, that's the minimal latency with the current settings. It is
possible to program a lower latency, by using less than 64 packets,
but that increases the amount of bandwitdh used, and the number of
IRQ events per second.
In any case, in order to support it, the driver logic should be
changed to fill those parameters in realtime.
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
2014-01-11 00:29:16 +08:00
|
|
|
.rates = SNDRV_PCM_RATE_48000,
|
2008-01-05 20:57:31 +08:00
|
|
|
|
|
|
|
.rate_min = 48000,
|
|
|
|
.rate_max = 48000,
|
|
|
|
.channels_min = 2,
|
|
|
|
.channels_max = 2,
|
|
|
|
.buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */
|
[media] em28xx-audio: fix the period size in bytes
If the period size is wrong, userspace will assume a wrong delay
any may negociate an inadequate value.
The em28xx devices use 8 for URB interval, in microframes,
and the driver programs it to have 64 packets.
That means that the IRQ sampling period is 125 * 8 * 64,
with is equal to 64 ms.
So, that's the minimal latency with the current settings. It is
possible to program a lower latency, by using less than 64 packets,
but that increases the amount of bandwitdh used, and the number of
IRQ events per second.
In any case, in order to support it, the driver logic should be
changed to fill those parameters in realtime.
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
2014-01-11 00:29:16 +08:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The period is 12.288 bytes. Allow a 10% of variation along its
|
|
|
|
* value, in order to avoid overruns/underruns due to some clock
|
|
|
|
* drift.
|
|
|
|
*
|
|
|
|
* FIXME: This period assumes 64 packets, and a 48000 PCM rate.
|
|
|
|
* Calculate it dynamically.
|
|
|
|
*/
|
|
|
|
.period_bytes_min = 11059,
|
|
|
|
.period_bytes_max = 13516,
|
|
|
|
|
2008-01-05 20:57:31 +08:00
|
|
|
.periods_min = 2,
|
|
|
|
.periods_max = 98, /* 12544, */
|
|
|
|
};
|
|
|
|
|
|
|
|
static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
|
|
|
|
{
|
|
|
|
struct em28xx *dev = snd_pcm_substream_chip(substream);
|
|
|
|
struct snd_pcm_runtime *runtime = substream->runtime;
|
2014-01-18 01:18:42 +08:00
|
|
|
int nonblock, ret = 0;
|
2008-01-05 20:57:31 +08:00
|
|
|
|
2008-06-14 20:41:18 +08:00
|
|
|
if (!dev) {
|
2009-11-05 02:31:25 +08:00
|
|
|
em28xx_err("BUG: em28xx can't find device struct."
|
2008-06-14 20:41:18 +08:00
|
|
|
" Can't proceed with open\n");
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
2014-01-12 21:21:42 +08:00
|
|
|
if (dev->disconnected)
|
|
|
|
return -ENODEV;
|
|
|
|
|
|
|
|
dprintk("opening device and trying to acquire exclusive lock\n");
|
|
|
|
|
2014-01-18 01:18:42 +08:00
|
|
|
nonblock = !!(substream->f_flags & O_NONBLOCK);
|
|
|
|
if (nonblock) {
|
|
|
|
if (!mutex_trylock(&dev->lock))
|
|
|
|
return -EAGAIN;
|
|
|
|
} else
|
|
|
|
mutex_lock(&dev->lock);
|
|
|
|
|
2011-06-18 02:15:12 +08:00
|
|
|
runtime->hw = snd_em28xx_hw_capture;
|
2014-01-18 01:18:43 +08:00
|
|
|
|
|
|
|
if (dev->adev.users == 0) {
|
|
|
|
if (dev->alt == 0 || dev->is_audio_only) {
|
|
|
|
if (dev->is_audio_only)
|
|
|
|
/* audio is on a separate interface */
|
|
|
|
dev->alt = 1;
|
|
|
|
else
|
|
|
|
/* audio is on the same interface as video */
|
|
|
|
dev->alt = 7;
|
|
|
|
/*
|
|
|
|
* FIXME: The intention seems to be to select
|
|
|
|
* the alt setting with the largest
|
|
|
|
* wMaxPacketSize for the video endpoint.
|
|
|
|
* At least dev->alt should be used instead, but
|
|
|
|
* we should probably not touch it at all if it
|
|
|
|
* is already >0, because wMaxPacketSize of the
|
|
|
|
* audio endpoints seems to be the same for all.
|
|
|
|
*/
|
|
|
|
dprintk("changing alternate number on interface %d to %d\n",
|
|
|
|
dev->ifnum, dev->alt);
|
|
|
|
usb_set_interface(dev->udev, dev->ifnum, dev->alt);
|
|
|
|
}
|
2008-01-05 20:57:31 +08:00
|
|
|
|
2011-06-18 02:15:12 +08:00
|
|
|
/* Sets volume, mute, etc */
|
|
|
|
dev->mute = 0;
|
|
|
|
ret = em28xx_audio_analog_set(dev);
|
|
|
|
if (ret < 0)
|
|
|
|
goto err;
|
|
|
|
}
|
2008-01-05 20:57:31 +08:00
|
|
|
|
2014-03-05 22:21:07 +08:00
|
|
|
kref_get(&dev->ref);
|
2014-01-18 01:18:42 +08:00
|
|
|
dev->adev.users++;
|
|
|
|
mutex_unlock(&dev->lock);
|
|
|
|
|
2014-01-13 14:34:23 +08:00
|
|
|
/* Dynamically adjust the period size */
|
2008-01-05 20:57:31 +08:00
|
|
|
snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
|
2014-01-13 14:34:23 +08:00
|
|
|
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
|
|
|
|
dev->adev.period * 95 / 100,
|
|
|
|
dev->adev.period * 105 / 100);
|
|
|
|
|
2008-12-31 20:37:33 +08:00
|
|
|
dev->adev.capture_pcm_substream = substream;
|
2008-01-05 20:57:31 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
err:
|
2010-10-10 02:53:58 +08:00
|
|
|
mutex_unlock(&dev->lock);
|
|
|
|
|
2009-11-05 02:31:25 +08:00
|
|
|
em28xx_err("Error while configuring em28xx mixer\n");
|
2008-01-05 20:57:31 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
|
|
|
|
{
|
|
|
|
struct em28xx *dev = snd_pcm_substream_chip(substream);
|
|
|
|
|
|
|
|
dprintk("closing device\n");
|
|
|
|
|
|
|
|
dev->mute = 1;
|
2008-02-07 05:52:15 +08:00
|
|
|
mutex_lock(&dev->lock);
|
2009-02-08 12:11:13 +08:00
|
|
|
dev->adev.users--;
|
2010-10-10 02:53:58 +08:00
|
|
|
if (atomic_read(&dev->stream_started) > 0) {
|
|
|
|
atomic_set(&dev->stream_started, 0);
|
|
|
|
schedule_work(&dev->wq_trigger);
|
|
|
|
}
|
|
|
|
|
2008-01-05 20:57:31 +08:00
|
|
|
em28xx_audio_analog_set(dev);
|
2009-05-28 22:16:19 +08:00
|
|
|
if (substream->runtime->dma_area) {
|
|
|
|
dprintk("freeing\n");
|
|
|
|
vfree(substream->runtime->dma_area);
|
|
|
|
substream->runtime->dma_area = NULL;
|
|
|
|
}
|
2008-02-07 05:52:15 +08:00
|
|
|
mutex_unlock(&dev->lock);
|
2014-03-05 22:21:07 +08:00
|
|
|
kref_put(&dev->ref, em28xx_free_device);
|
2008-01-05 20:57:31 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream,
|
|
|
|
struct snd_pcm_hw_params *hw_params)
|
|
|
|
{
|
|
|
|
int ret;
|
2014-01-12 21:21:42 +08:00
|
|
|
struct em28xx *dev = snd_pcm_substream_chip(substream);
|
|
|
|
|
|
|
|
if (dev->disconnected)
|
|
|
|
return -ENODEV;
|
2008-01-05 20:57:31 +08:00
|
|
|
|
|
|
|
dprintk("Setting capture parameters\n");
|
|
|
|
|
|
|
|
ret = snd_pcm_alloc_vmalloc_buffer(substream,
|
|
|
|
params_buffer_bytes(hw_params));
|
2011-06-18 07:28:51 +08:00
|
|
|
if (ret < 0)
|
|
|
|
return ret;
|
2012-05-14 21:17:35 +08:00
|
|
|
#if 0
|
|
|
|
/* TODO: set up em28xx audio chip to deliver the correct audio format,
|
|
|
|
current default is 48000hz multiplexed => 96000hz mono
|
|
|
|
which shouldn't matter since analogue TV only supports mono */
|
|
|
|
unsigned int channels, rate, format;
|
|
|
|
|
2008-01-05 20:57:31 +08:00
|
|
|
format = params_format(hw_params);
|
|
|
|
rate = params_rate(hw_params);
|
|
|
|
channels = params_channels(hw_params);
|
2012-05-14 21:17:35 +08:00
|
|
|
#endif
|
2008-01-05 20:57:31 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int snd_em28xx_hw_capture_free(struct snd_pcm_substream *substream)
|
|
|
|
{
|
|
|
|
struct em28xx *dev = snd_pcm_substream_chip(substream);
|
|
|
|
|
|
|
|
dprintk("Stop capture, if needed\n");
|
|
|
|
|
2010-10-10 02:53:58 +08:00
|
|
|
if (atomic_read(&dev->stream_started) > 0) {
|
|
|
|
atomic_set(&dev->stream_started, 0);
|
|
|
|
schedule_work(&dev->wq_trigger);
|
|
|
|
}
|
2008-01-05 20:57:31 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int snd_em28xx_prepare(struct snd_pcm_substream *substream)
|
|
|
|
{
|
2009-10-15 12:14:34 +08:00
|
|
|
struct em28xx *dev = snd_pcm_substream_chip(substream);
|
|
|
|
|
2014-01-12 21:21:42 +08:00
|
|
|
if (dev->disconnected)
|
|
|
|
return -ENODEV;
|
|
|
|
|
2009-10-15 12:14:34 +08:00
|
|
|
dev->adev.hwptr_done_capture = 0;
|
|
|
|
dev->adev.capture_transfer_done = 0;
|
|
|
|
|
2008-01-05 20:57:31 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-10-10 02:53:58 +08:00
|
|
|
static void audio_trigger(struct work_struct *work)
|
|
|
|
{
|
|
|
|
struct em28xx *dev = container_of(work, struct em28xx, wq_trigger);
|
|
|
|
|
|
|
|
if (atomic_read(&dev->stream_started)) {
|
|
|
|
dprintk("starting capture");
|
|
|
|
em28xx_init_audio_isoc(dev);
|
|
|
|
} else {
|
|
|
|
dprintk("stopping capture");
|
|
|
|
em28xx_deinit_isoc_audio(dev);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-01-05 20:57:31 +08:00
|
|
|
static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream,
|
|
|
|
int cmd)
|
|
|
|
{
|
|
|
|
struct em28xx *dev = snd_pcm_substream_chip(substream);
|
2011-06-18 07:28:51 +08:00
|
|
|
int retval = 0;
|
2008-01-05 20:57:31 +08:00
|
|
|
|
2014-01-12 21:21:42 +08:00
|
|
|
if (dev->disconnected)
|
|
|
|
return -ENODEV;
|
|
|
|
|
2008-01-05 20:57:31 +08:00
|
|
|
switch (cmd) {
|
2011-06-20 00:39:31 +08:00
|
|
|
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
|
|
|
|
case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
|
2008-01-05 20:57:31 +08:00
|
|
|
case SNDRV_PCM_TRIGGER_START:
|
2010-10-10 02:53:58 +08:00
|
|
|
atomic_set(&dev->stream_started, 1);
|
2009-02-09 01:17:15 +08:00
|
|
|
break;
|
2011-06-20 00:39:31 +08:00
|
|
|
case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
|
|
|
|
case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
|
2008-01-05 20:57:31 +08:00
|
|
|
case SNDRV_PCM_TRIGGER_STOP:
|
2011-06-20 00:39:31 +08:00
|
|
|
atomic_set(&dev->stream_started, 0);
|
2009-02-09 01:17:15 +08:00
|
|
|
break;
|
2008-01-05 20:57:31 +08:00
|
|
|
default:
|
2009-02-09 01:17:15 +08:00
|
|
|
retval = -EINVAL;
|
2008-01-05 20:57:31 +08:00
|
|
|
}
|
2010-10-10 02:53:58 +08:00
|
|
|
schedule_work(&dev->wq_trigger);
|
2011-06-18 07:28:51 +08:00
|
|
|
return retval;
|
2008-01-05 20:57:31 +08:00
|
|
|
}
|
|
|
|
|
2008-01-05 20:56:24 +08:00
|
|
|
static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream
|
|
|
|
*substream)
|
2008-01-05 20:55:47 +08:00
|
|
|
{
|
2009-02-11 10:28:24 +08:00
|
|
|
unsigned long flags;
|
2009-01-16 22:23:25 +08:00
|
|
|
struct em28xx *dev;
|
2008-01-05 20:55:47 +08:00
|
|
|
snd_pcm_uframes_t hwptr_done;
|
2009-01-16 22:23:25 +08:00
|
|
|
|
2008-01-05 20:55:47 +08:00
|
|
|
dev = snd_pcm_substream_chip(substream);
|
2014-01-12 21:21:42 +08:00
|
|
|
if (dev->disconnected)
|
2014-01-12 23:57:08 +08:00
|
|
|
return SNDRV_PCM_POS_XRUN;
|
2014-01-12 21:21:42 +08:00
|
|
|
|
2009-01-26 02:12:29 +08:00
|
|
|
spin_lock_irqsave(&dev->adev.slock, flags);
|
2008-12-31 20:37:33 +08:00
|
|
|
hwptr_done = dev->adev.hwptr_done_capture;
|
2009-01-26 02:12:29 +08:00
|
|
|
spin_unlock_irqrestore(&dev->adev.slock, flags);
|
2008-01-05 20:57:31 +08:00
|
|
|
|
2008-01-05 20:55:47 +08:00
|
|
|
return hwptr_done;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
|
|
|
|
unsigned long offset)
|
|
|
|
{
|
|
|
|
void *pageptr = subs->runtime->dma_area + offset;
|
2008-01-05 20:57:31 +08:00
|
|
|
|
2008-01-05 20:55:47 +08:00
|
|
|
return vmalloc_to_page(pageptr);
|
|
|
|
}
|
|
|
|
|
2011-06-20 00:06:40 +08:00
|
|
|
/*
|
|
|
|
* AC97 volume control support
|
|
|
|
*/
|
|
|
|
static int em28xx_vol_info(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_info *info)
|
|
|
|
{
|
2014-01-12 21:21:42 +08:00
|
|
|
struct em28xx *dev = snd_kcontrol_chip(kcontrol);
|
|
|
|
|
|
|
|
if (dev->disconnected)
|
|
|
|
return -ENODEV;
|
|
|
|
|
2011-06-20 00:06:40 +08:00
|
|
|
info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
|
|
|
info->count = 2;
|
|
|
|
info->value.integer.min = 0;
|
|
|
|
info->value.integer.max = 0x1f;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int em28xx_vol_put(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *value)
|
|
|
|
{
|
|
|
|
struct em28xx *dev = snd_kcontrol_chip(kcontrol);
|
2014-01-12 20:22:29 +08:00
|
|
|
struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream;
|
2011-06-20 00:14:07 +08:00
|
|
|
u16 val = (0x1f - (value->value.integer.value[0] & 0x1f)) |
|
|
|
|
(0x1f - (value->value.integer.value[1] & 0x1f)) << 8;
|
2014-01-12 20:22:29 +08:00
|
|
|
int nonblock = 0;
|
2011-06-20 00:06:40 +08:00
|
|
|
int rc;
|
|
|
|
|
2014-01-12 21:21:42 +08:00
|
|
|
if (dev->disconnected)
|
|
|
|
return -ENODEV;
|
|
|
|
|
2014-01-12 20:22:29 +08:00
|
|
|
if (substream)
|
|
|
|
nonblock = !!(substream->f_flags & O_NONBLOCK);
|
|
|
|
if (nonblock) {
|
|
|
|
if (!mutex_trylock(&dev->lock))
|
|
|
|
return -EAGAIN;
|
|
|
|
} else
|
|
|
|
mutex_lock(&dev->lock);
|
2011-06-20 00:06:40 +08:00
|
|
|
rc = em28xx_read_ac97(dev, kcontrol->private_value);
|
|
|
|
if (rc < 0)
|
|
|
|
goto err;
|
|
|
|
|
2011-06-20 00:08:46 +08:00
|
|
|
val |= rc & 0x8000; /* Preserve the mute flag */
|
2011-06-20 00:06:40 +08:00
|
|
|
|
|
|
|
rc = em28xx_write_ac97(dev, kcontrol->private_value, val);
|
2011-06-18 22:00:20 +08:00
|
|
|
if (rc < 0)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
dprintk("%sleft vol %d, right vol %d (0x%04x) to ac97 volume control 0x%04x\n",
|
|
|
|
(val & 0x8000) ? "muted " : "",
|
|
|
|
0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f),
|
|
|
|
val, (int)kcontrol->private_value);
|
2011-06-20 00:06:40 +08:00
|
|
|
|
|
|
|
err:
|
|
|
|
mutex_unlock(&dev->lock);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int em28xx_vol_get(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *value)
|
|
|
|
{
|
|
|
|
struct em28xx *dev = snd_kcontrol_chip(kcontrol);
|
2014-01-12 20:22:29 +08:00
|
|
|
struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream;
|
|
|
|
int nonblock = 0;
|
2011-06-20 00:06:40 +08:00
|
|
|
int val;
|
|
|
|
|
2014-01-12 21:21:42 +08:00
|
|
|
if (dev->disconnected)
|
|
|
|
return -ENODEV;
|
|
|
|
|
2014-01-12 20:22:29 +08:00
|
|
|
if (substream)
|
|
|
|
nonblock = !!(substream->f_flags & O_NONBLOCK);
|
|
|
|
if (nonblock) {
|
|
|
|
if (!mutex_trylock(&dev->lock))
|
|
|
|
return -EAGAIN;
|
|
|
|
} else
|
|
|
|
mutex_lock(&dev->lock);
|
2011-06-20 00:06:40 +08:00
|
|
|
val = em28xx_read_ac97(dev, kcontrol->private_value);
|
|
|
|
mutex_unlock(&dev->lock);
|
|
|
|
if (val < 0)
|
|
|
|
return val;
|
|
|
|
|
2011-06-18 22:00:20 +08:00
|
|
|
dprintk("%sleft vol %d, right vol %d (0x%04x) from ac97 volume control 0x%04x\n",
|
|
|
|
(val & 0x8000) ? "muted " : "",
|
|
|
|
0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f),
|
|
|
|
val, (int)kcontrol->private_value);
|
|
|
|
|
2011-06-20 00:14:07 +08:00
|
|
|
value->value.integer.value[0] = 0x1f - (val & 0x1f);
|
|
|
|
value->value.integer.value[1] = 0x1f - ((val << 8) & 0x1f);
|
2011-06-20 00:06:40 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-06-20 00:08:46 +08:00
|
|
|
static int em28xx_vol_put_mute(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *value)
|
|
|
|
{
|
|
|
|
struct em28xx *dev = snd_kcontrol_chip(kcontrol);
|
|
|
|
u16 val = value->value.integer.value[0];
|
2014-01-12 20:22:29 +08:00
|
|
|
struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream;
|
|
|
|
int nonblock = 0;
|
2011-06-20 00:08:46 +08:00
|
|
|
int rc;
|
|
|
|
|
2014-01-12 21:21:42 +08:00
|
|
|
if (dev->disconnected)
|
|
|
|
return -ENODEV;
|
|
|
|
|
2014-01-12 20:22:29 +08:00
|
|
|
if (substream)
|
|
|
|
nonblock = !!(substream->f_flags & O_NONBLOCK);
|
|
|
|
if (nonblock) {
|
|
|
|
if (!mutex_trylock(&dev->lock))
|
|
|
|
return -EAGAIN;
|
|
|
|
} else
|
|
|
|
mutex_lock(&dev->lock);
|
2011-06-20 00:08:46 +08:00
|
|
|
rc = em28xx_read_ac97(dev, kcontrol->private_value);
|
|
|
|
if (rc < 0)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
if (val)
|
2011-06-20 00:14:07 +08:00
|
|
|
rc &= 0x1f1f;
|
2011-06-20 00:08:46 +08:00
|
|
|
else
|
2011-06-20 00:14:07 +08:00
|
|
|
rc |= 0x8000;
|
2011-06-20 00:08:46 +08:00
|
|
|
|
|
|
|
rc = em28xx_write_ac97(dev, kcontrol->private_value, rc);
|
2011-06-18 22:00:20 +08:00
|
|
|
if (rc < 0)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
dprintk("%sleft vol %d, right vol %d (0x%04x) to ac97 volume control 0x%04x\n",
|
|
|
|
(val & 0x8000) ? "muted " : "",
|
|
|
|
0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f),
|
|
|
|
val, (int)kcontrol->private_value);
|
2011-06-20 00:08:46 +08:00
|
|
|
|
|
|
|
err:
|
|
|
|
mutex_unlock(&dev->lock);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int em28xx_vol_get_mute(struct snd_kcontrol *kcontrol,
|
|
|
|
struct snd_ctl_elem_value *value)
|
|
|
|
{
|
|
|
|
struct em28xx *dev = snd_kcontrol_chip(kcontrol);
|
2014-01-12 20:22:29 +08:00
|
|
|
struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream;
|
|
|
|
int nonblock = 0;
|
2011-06-20 00:08:46 +08:00
|
|
|
int val;
|
|
|
|
|
2014-01-12 21:21:42 +08:00
|
|
|
if (dev->disconnected)
|
|
|
|
return -ENODEV;
|
|
|
|
|
2014-01-12 20:22:29 +08:00
|
|
|
if (substream)
|
|
|
|
nonblock = !!(substream->f_flags & O_NONBLOCK);
|
|
|
|
if (nonblock) {
|
|
|
|
if (!mutex_trylock(&dev->lock))
|
|
|
|
return -EAGAIN;
|
|
|
|
} else
|
|
|
|
mutex_lock(&dev->lock);
|
2011-06-20 00:08:46 +08:00
|
|
|
val = em28xx_read_ac97(dev, kcontrol->private_value);
|
|
|
|
mutex_unlock(&dev->lock);
|
|
|
|
if (val < 0)
|
|
|
|
return val;
|
|
|
|
|
|
|
|
if (val & 0x8000)
|
|
|
|
value->value.integer.value[0] = 0;
|
2011-06-20 00:14:07 +08:00
|
|
|
else
|
|
|
|
value->value.integer.value[0] = 1;
|
2011-06-20 00:08:46 +08:00
|
|
|
|
2011-06-18 22:00:20 +08:00
|
|
|
dprintk("%sleft vol %d, right vol %d (0x%04x) from ac97 volume control 0x%04x\n",
|
|
|
|
(val & 0x8000) ? "muted " : "",
|
|
|
|
0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f),
|
|
|
|
val, (int)kcontrol->private_value);
|
|
|
|
|
2011-06-20 00:08:46 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2011-06-20 00:06:40 +08:00
|
|
|
static const DECLARE_TLV_DB_SCALE(em28xx_db_scale, -3450, 150, 0);
|
|
|
|
|
|
|
|
static int em28xx_cvol_new(struct snd_card *card, struct em28xx *dev,
|
|
|
|
char *name, int id)
|
|
|
|
{
|
|
|
|
int err;
|
2011-06-20 00:08:46 +08:00
|
|
|
char ctl_name[44];
|
2011-06-20 00:06:40 +08:00
|
|
|
struct snd_kcontrol *kctl;
|
2011-06-20 00:08:46 +08:00
|
|
|
struct snd_kcontrol_new tmp;
|
|
|
|
|
|
|
|
memset (&tmp, 0, sizeof(tmp));
|
|
|
|
tmp.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
|
|
|
tmp.private_value = id,
|
|
|
|
tmp.name = ctl_name,
|
|
|
|
|
|
|
|
/* Add Mute Control */
|
|
|
|
sprintf(ctl_name, "%s Switch", name);
|
|
|
|
tmp.get = em28xx_vol_get_mute;
|
|
|
|
tmp.put = em28xx_vol_put_mute;
|
|
|
|
tmp.info = snd_ctl_boolean_mono_info;
|
2011-06-20 00:06:40 +08:00
|
|
|
kctl = snd_ctl_new1(&tmp, dev);
|
2011-06-20 00:08:46 +08:00
|
|
|
err = snd_ctl_add(card, kctl);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
2011-06-18 22:00:20 +08:00
|
|
|
dprintk("Added control %s for ac97 volume control 0x%04x\n",
|
|
|
|
ctl_name, id);
|
2011-06-20 00:06:40 +08:00
|
|
|
|
2011-06-20 00:08:46 +08:00
|
|
|
memset (&tmp, 0, sizeof(tmp));
|
|
|
|
tmp.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
|
|
|
tmp.private_value = id,
|
|
|
|
tmp.name = ctl_name,
|
|
|
|
|
|
|
|
/* Add Volume Control */
|
|
|
|
sprintf(ctl_name, "%s Volume", name);
|
|
|
|
tmp.get = em28xx_vol_get;
|
|
|
|
tmp.put = em28xx_vol_put;
|
|
|
|
tmp.info = em28xx_vol_info;
|
|
|
|
tmp.tlv.p = em28xx_db_scale,
|
|
|
|
kctl = snd_ctl_new1(&tmp, dev);
|
2011-06-20 00:06:40 +08:00
|
|
|
err = snd_ctl_add(card, kctl);
|
|
|
|
if (err < 0)
|
|
|
|
return err;
|
2011-06-18 22:00:20 +08:00
|
|
|
dprintk("Added control %s for ac97 volume control 0x%04x\n",
|
|
|
|
ctl_name, id);
|
2011-06-20 00:06:40 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* register/unregister code and data
|
|
|
|
*/
|
2008-01-05 20:55:47 +08:00
|
|
|
static struct snd_pcm_ops snd_em28xx_pcm_capture = {
|
2008-01-05 20:57:31 +08:00
|
|
|
.open = snd_em28xx_capture_open,
|
|
|
|
.close = snd_em28xx_pcm_close,
|
|
|
|
.ioctl = snd_pcm_lib_ioctl,
|
2008-01-05 20:55:47 +08:00
|
|
|
.hw_params = snd_em28xx_hw_capture_params,
|
2008-01-05 20:57:31 +08:00
|
|
|
.hw_free = snd_em28xx_hw_capture_free,
|
|
|
|
.prepare = snd_em28xx_prepare,
|
|
|
|
.trigger = snd_em28xx_capture_trigger,
|
|
|
|
.pointer = snd_em28xx_capture_pointer,
|
|
|
|
.page = snd_pcm_get_vmalloc_page,
|
2008-01-05 20:55:47 +08:00
|
|
|
};
|
|
|
|
|
2013-12-29 08:16:26 +08:00
|
|
|
static void em28xx_audio_free_urb(struct em28xx *dev)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
[media] em28xx-audio: don't hardcode audio URB calculus
The current code hardcodes the number of audio URBs, the number
of packets per URB and the maximum URB size.
This is not a good idea, as it:
- wastes more bandwidth than necessary, by using a very
large number of packets;
- those constants are bound to an specific scenario, with
a bandwidth of 48 kHz;
- don't take the maximum endpoint size into account;
- with urb->interval = 1 on xHCI, those constraints cause a "funny"
setup: URBs with 64 packets inside, with only 24 bytes total. E. g.
a complete waste of space.
Change the code to do dynamic URB audio calculus and allocation.
For now, use the same constraints as used before this patch, to
avoid regressions.
A good scenario (tested) seems to use those defines, instead:
#define EM28XX_MAX_AUDIO_BUFS 8
#define EM28XX_MIN_AUDIO_PACKETS 2
But let's not do such change here, letting the optimization to
happen on latter patches, after more tests.
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
2014-01-10 16:53:24 +08:00
|
|
|
for (i = 0; i < dev->adev.num_urb; i++) {
|
2013-12-29 08:16:26 +08:00
|
|
|
struct urb *urb = dev->adev.urb[i];
|
|
|
|
|
[media] em28xx-audio: don't hardcode audio URB calculus
The current code hardcodes the number of audio URBs, the number
of packets per URB and the maximum URB size.
This is not a good idea, as it:
- wastes more bandwidth than necessary, by using a very
large number of packets;
- those constants are bound to an specific scenario, with
a bandwidth of 48 kHz;
- don't take the maximum endpoint size into account;
- with urb->interval = 1 on xHCI, those constraints cause a "funny"
setup: URBs with 64 packets inside, with only 24 bytes total. E. g.
a complete waste of space.
Change the code to do dynamic URB audio calculus and allocation.
For now, use the same constraints as used before this patch, to
avoid regressions.
A good scenario (tested) seems to use those defines, instead:
#define EM28XX_MAX_AUDIO_BUFS 8
#define EM28XX_MIN_AUDIO_PACKETS 2
But let's not do such change here, letting the optimization to
happen on latter patches, after more tests.
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
2014-01-10 16:53:24 +08:00
|
|
|
if (!urb)
|
2013-12-29 08:16:26 +08:00
|
|
|
continue;
|
|
|
|
|
2014-01-15 13:52:12 +08:00
|
|
|
usb_free_coherent(dev->udev, urb->transfer_buffer_length,
|
|
|
|
dev->adev.transfer_buffer[i],
|
|
|
|
urb->transfer_dma);
|
2013-12-29 08:16:26 +08:00
|
|
|
|
|
|
|
usb_free_urb(urb);
|
|
|
|
}
|
[media] em28xx-audio: don't hardcode audio URB calculus
The current code hardcodes the number of audio URBs, the number
of packets per URB and the maximum URB size.
This is not a good idea, as it:
- wastes more bandwidth than necessary, by using a very
large number of packets;
- those constants are bound to an specific scenario, with
a bandwidth of 48 kHz;
- don't take the maximum endpoint size into account;
- with urb->interval = 1 on xHCI, those constraints cause a "funny"
setup: URBs with 64 packets inside, with only 24 bytes total. E. g.
a complete waste of space.
Change the code to do dynamic URB audio calculus and allocation.
For now, use the same constraints as used before this patch, to
avoid regressions.
A good scenario (tested) seems to use those defines, instead:
#define EM28XX_MAX_AUDIO_BUFS 8
#define EM28XX_MIN_AUDIO_PACKETS 2
But let's not do such change here, letting the optimization to
happen on latter patches, after more tests.
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
2014-01-10 16:53:24 +08:00
|
|
|
kfree(dev->adev.urb);
|
|
|
|
kfree(dev->adev.transfer_buffer);
|
|
|
|
dev->adev.num_urb = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
|
|
|
|
static int em28xx_audio_ep_packet_size(struct usb_device *udev,
|
|
|
|
struct usb_endpoint_descriptor *e)
|
|
|
|
{
|
|
|
|
int size = le16_to_cpu(e->wMaxPacketSize);
|
|
|
|
|
|
|
|
if (udev->speed == USB_SPEED_HIGH)
|
|
|
|
return (size & 0x7ff) * (1 + (((size) >> 11) & 0x03));
|
|
|
|
|
|
|
|
return size & 0x7ff;
|
2013-12-29 08:16:26 +08:00
|
|
|
}
|
|
|
|
|
2014-01-12 21:10:34 +08:00
|
|
|
static int em28xx_audio_urb_init(struct em28xx *dev)
|
2008-01-05 20:55:47 +08:00
|
|
|
{
|
2014-01-10 16:43:09 +08:00
|
|
|
struct usb_interface *intf;
|
|
|
|
struct usb_endpoint_descriptor *e, *ep = NULL;
|
2014-01-12 21:10:34 +08:00
|
|
|
int i, ep_size, interval, num_urb, npackets;
|
[media] em28xx-audio: don't hardcode audio URB calculus
The current code hardcodes the number of audio URBs, the number
of packets per URB and the maximum URB size.
This is not a good idea, as it:
- wastes more bandwidth than necessary, by using a very
large number of packets;
- those constants are bound to an specific scenario, with
a bandwidth of 48 kHz;
- don't take the maximum endpoint size into account;
- with urb->interval = 1 on xHCI, those constraints cause a "funny"
setup: URBs with 64 packets inside, with only 24 bytes total. E. g.
a complete waste of space.
Change the code to do dynamic URB audio calculus and allocation.
For now, use the same constraints as used before this patch, to
avoid regressions.
A good scenario (tested) seems to use those defines, instead:
#define EM28XX_MAX_AUDIO_BUFS 8
#define EM28XX_MIN_AUDIO_PACKETS 2
But let's not do such change here, letting the optimization to
happen on latter patches, after more tests.
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
2014-01-10 16:53:24 +08:00
|
|
|
int urb_size, bytes_per_transfer;
|
2014-01-10 16:43:09 +08:00
|
|
|
u8 alt;
|
2008-01-05 20:57:31 +08:00
|
|
|
|
2014-01-14 06:02:06 +08:00
|
|
|
if (dev->ifnum)
|
2014-01-10 16:43:09 +08:00
|
|
|
alt = 1;
|
|
|
|
else
|
|
|
|
alt = 7;
|
|
|
|
|
2014-01-14 06:02:06 +08:00
|
|
|
intf = usb_ifnum_to_if(dev->udev, dev->ifnum);
|
2014-01-10 16:43:09 +08:00
|
|
|
|
|
|
|
if (intf->num_altsetting <= alt) {
|
|
|
|
em28xx_errdev("alt %d doesn't exist on interface %d\n",
|
2014-01-14 06:02:06 +08:00
|
|
|
dev->ifnum, alt);
|
2014-01-10 16:43:09 +08:00
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < intf->altsetting[alt].desc.bNumEndpoints; i++) {
|
|
|
|
e = &intf->altsetting[alt].endpoint[i].desc;
|
|
|
|
if (!usb_endpoint_dir_in(e))
|
|
|
|
continue;
|
|
|
|
if (e->bEndpointAddress == EM28XX_EP_AUDIO) {
|
|
|
|
ep = e;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ep) {
|
|
|
|
em28xx_errdev("Couldn't find an audio endpoint");
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
|
|
|
|
[media] em28xx-audio: don't hardcode audio URB calculus
The current code hardcodes the number of audio URBs, the number
of packets per URB and the maximum URB size.
This is not a good idea, as it:
- wastes more bandwidth than necessary, by using a very
large number of packets;
- those constants are bound to an specific scenario, with
a bandwidth of 48 kHz;
- don't take the maximum endpoint size into account;
- with urb->interval = 1 on xHCI, those constraints cause a "funny"
setup: URBs with 64 packets inside, with only 24 bytes total. E. g.
a complete waste of space.
Change the code to do dynamic URB audio calculus and allocation.
For now, use the same constraints as used before this patch, to
avoid regressions.
A good scenario (tested) seems to use those defines, instead:
#define EM28XX_MAX_AUDIO_BUFS 8
#define EM28XX_MIN_AUDIO_PACKETS 2
But let's not do such change here, letting the optimization to
happen on latter patches, after more tests.
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
2014-01-10 16:53:24 +08:00
|
|
|
ep_size = em28xx_audio_ep_packet_size(dev->udev, ep);
|
|
|
|
interval = 1 << (ep->bInterval - 1);
|
|
|
|
|
|
|
|
em28xx_info("Endpoint 0x%02x %s on intf %d alt %d interval = %d, size %d\n",
|
|
|
|
EM28XX_EP_AUDIO, usb_speed_string(dev->udev->speed),
|
2014-01-14 06:02:06 +08:00
|
|
|
dev->ifnum, alt,
|
[media] em28xx-audio: don't hardcode audio URB calculus
The current code hardcodes the number of audio URBs, the number
of packets per URB and the maximum URB size.
This is not a good idea, as it:
- wastes more bandwidth than necessary, by using a very
large number of packets;
- those constants are bound to an specific scenario, with
a bandwidth of 48 kHz;
- don't take the maximum endpoint size into account;
- with urb->interval = 1 on xHCI, those constraints cause a "funny"
setup: URBs with 64 packets inside, with only 24 bytes total. E. g.
a complete waste of space.
Change the code to do dynamic URB audio calculus and allocation.
For now, use the same constraints as used before this patch, to
avoid regressions.
A good scenario (tested) seems to use those defines, instead:
#define EM28XX_MAX_AUDIO_BUFS 8
#define EM28XX_MIN_AUDIO_PACKETS 2
But let's not do such change here, letting the optimization to
happen on latter patches, after more tests.
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
2014-01-10 16:53:24 +08:00
|
|
|
interval,
|
|
|
|
ep_size);
|
|
|
|
|
|
|
|
/* Calculate the number and size of URBs to better fit the audio samples */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Estimate the number of bytes per DMA transfer.
|
|
|
|
*
|
|
|
|
* This is given by the bit rate (for now, only 48000 Hz) multiplied
|
|
|
|
* by 2 channels and 2 bytes/sample divided by the number of microframe
|
|
|
|
* intervals and by the microframe rate (125 us)
|
|
|
|
*/
|
|
|
|
bytes_per_transfer = DIV_ROUND_UP(48000 * 2 * 2, 125 * interval);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Estimate the number of transfer URBs. Don't let it go past the
|
|
|
|
* maximum number of URBs that is known to be supported by the device.
|
|
|
|
*/
|
|
|
|
num_urb = DIV_ROUND_UP(bytes_per_transfer, ep_size);
|
|
|
|
if (num_urb > EM28XX_MAX_AUDIO_BUFS)
|
|
|
|
num_urb = EM28XX_MAX_AUDIO_BUFS;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now that we know the number of bytes per transfer and the number of
|
|
|
|
* URBs, estimate the typical size of an URB, in order to adjust the
|
|
|
|
* minimal number of packets.
|
|
|
|
*/
|
|
|
|
urb_size = bytes_per_transfer / num_urb;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now, calculate the amount of audio packets to be filled on each
|
|
|
|
* URB. In order to preserve the old behaviour, use a minimal
|
|
|
|
* threshold for this value.
|
|
|
|
*/
|
|
|
|
npackets = EM28XX_MIN_AUDIO_PACKETS;
|
|
|
|
if (urb_size > ep_size * npackets)
|
|
|
|
npackets = DIV_ROUND_UP(urb_size, ep_size);
|
|
|
|
|
|
|
|
em28xx_info("Number of URBs: %d, with %d packets and %d size",
|
|
|
|
num_urb, npackets, urb_size);
|
|
|
|
|
2014-01-13 14:34:23 +08:00
|
|
|
/* Estimate the bytes per period */
|
|
|
|
dev->adev.period = urb_size * npackets;
|
|
|
|
|
[media] em28xx-audio: don't hardcode audio URB calculus
The current code hardcodes the number of audio URBs, the number
of packets per URB and the maximum URB size.
This is not a good idea, as it:
- wastes more bandwidth than necessary, by using a very
large number of packets;
- those constants are bound to an specific scenario, with
a bandwidth of 48 kHz;
- don't take the maximum endpoint size into account;
- with urb->interval = 1 on xHCI, those constraints cause a "funny"
setup: URBs with 64 packets inside, with only 24 bytes total. E. g.
a complete waste of space.
Change the code to do dynamic URB audio calculus and allocation.
For now, use the same constraints as used before this patch, to
avoid regressions.
A good scenario (tested) seems to use those defines, instead:
#define EM28XX_MAX_AUDIO_BUFS 8
#define EM28XX_MIN_AUDIO_PACKETS 2
But let's not do such change here, letting the optimization to
happen on latter patches, after more tests.
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
2014-01-10 16:53:24 +08:00
|
|
|
/* Allocate space to store the number of URBs to be used */
|
|
|
|
|
|
|
|
dev->adev.transfer_buffer = kcalloc(num_urb,
|
|
|
|
sizeof(*dev->adev.transfer_buffer),
|
|
|
|
GFP_ATOMIC);
|
|
|
|
if (!dev->adev.transfer_buffer) {
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
dev->adev.urb = kcalloc(num_urb, sizeof(*dev->adev.urb), GFP_ATOMIC);
|
|
|
|
if (!dev->adev.urb) {
|
|
|
|
kfree(dev->adev.transfer_buffer);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Alloc memory for each URB and for each transfer buffer */
|
|
|
|
dev->adev.num_urb = num_urb;
|
|
|
|
for (i = 0; i < num_urb; i++) {
|
2013-12-29 08:16:26 +08:00
|
|
|
struct urb *urb;
|
|
|
|
int j, k;
|
|
|
|
void *buf;
|
|
|
|
|
[media] em28xx-audio: don't hardcode audio URB calculus
The current code hardcodes the number of audio URBs, the number
of packets per URB and the maximum URB size.
This is not a good idea, as it:
- wastes more bandwidth than necessary, by using a very
large number of packets;
- those constants are bound to an specific scenario, with
a bandwidth of 48 kHz;
- don't take the maximum endpoint size into account;
- with urb->interval = 1 on xHCI, those constraints cause a "funny"
setup: URBs with 64 packets inside, with only 24 bytes total. E. g.
a complete waste of space.
Change the code to do dynamic URB audio calculus and allocation.
For now, use the same constraints as used before this patch, to
avoid regressions.
A good scenario (tested) seems to use those defines, instead:
#define EM28XX_MAX_AUDIO_BUFS 8
#define EM28XX_MIN_AUDIO_PACKETS 2
But let's not do such change here, letting the optimization to
happen on latter patches, after more tests.
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
2014-01-10 16:53:24 +08:00
|
|
|
urb = usb_alloc_urb(npackets, GFP_ATOMIC);
|
2013-12-29 08:16:26 +08:00
|
|
|
if (!urb) {
|
|
|
|
em28xx_errdev("usb_alloc_urb failed!\n");
|
|
|
|
em28xx_audio_free_urb(dev);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
dev->adev.urb[i] = urb;
|
|
|
|
|
[media] em28xx-audio: don't hardcode audio URB calculus
The current code hardcodes the number of audio URBs, the number
of packets per URB and the maximum URB size.
This is not a good idea, as it:
- wastes more bandwidth than necessary, by using a very
large number of packets;
- those constants are bound to an specific scenario, with
a bandwidth of 48 kHz;
- don't take the maximum endpoint size into account;
- with urb->interval = 1 on xHCI, those constraints cause a "funny"
setup: URBs with 64 packets inside, with only 24 bytes total. E. g.
a complete waste of space.
Change the code to do dynamic URB audio calculus and allocation.
For now, use the same constraints as used before this patch, to
avoid regressions.
A good scenario (tested) seems to use those defines, instead:
#define EM28XX_MAX_AUDIO_BUFS 8
#define EM28XX_MIN_AUDIO_PACKETS 2
But let's not do such change here, letting the optimization to
happen on latter patches, after more tests.
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
2014-01-10 16:53:24 +08:00
|
|
|
buf = usb_alloc_coherent(dev->udev, npackets * ep_size, GFP_ATOMIC,
|
2013-12-29 08:16:26 +08:00
|
|
|
&urb->transfer_dma);
|
|
|
|
if (!buf) {
|
|
|
|
em28xx_errdev("usb_alloc_coherent failed!\n");
|
|
|
|
em28xx_audio_free_urb(dev);
|
|
|
|
return -ENOMEM;
|
|
|
|
}
|
|
|
|
dev->adev.transfer_buffer[i] = buf;
|
|
|
|
|
|
|
|
urb->dev = dev->udev;
|
|
|
|
urb->context = dev;
|
|
|
|
urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
|
|
|
|
urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
|
[media] em28xx-audio: don't hardcode audio URB calculus
The current code hardcodes the number of audio URBs, the number
of packets per URB and the maximum URB size.
This is not a good idea, as it:
- wastes more bandwidth than necessary, by using a very
large number of packets;
- those constants are bound to an specific scenario, with
a bandwidth of 48 kHz;
- don't take the maximum endpoint size into account;
- with urb->interval = 1 on xHCI, those constraints cause a "funny"
setup: URBs with 64 packets inside, with only 24 bytes total. E. g.
a complete waste of space.
Change the code to do dynamic URB audio calculus and allocation.
For now, use the same constraints as used before this patch, to
avoid regressions.
A good scenario (tested) seems to use those defines, instead:
#define EM28XX_MAX_AUDIO_BUFS 8
#define EM28XX_MIN_AUDIO_PACKETS 2
But let's not do such change here, letting the optimization to
happen on latter patches, after more tests.
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
2014-01-10 16:53:24 +08:00
|
|
|
urb->transfer_buffer = buf;
|
|
|
|
urb->interval = interval;
|
2013-12-29 08:16:26 +08:00
|
|
|
urb->complete = em28xx_audio_isocirq;
|
[media] em28xx-audio: don't hardcode audio URB calculus
The current code hardcodes the number of audio URBs, the number
of packets per URB and the maximum URB size.
This is not a good idea, as it:
- wastes more bandwidth than necessary, by using a very
large number of packets;
- those constants are bound to an specific scenario, with
a bandwidth of 48 kHz;
- don't take the maximum endpoint size into account;
- with urb->interval = 1 on xHCI, those constraints cause a "funny"
setup: URBs with 64 packets inside, with only 24 bytes total. E. g.
a complete waste of space.
Change the code to do dynamic URB audio calculus and allocation.
For now, use the same constraints as used before this patch, to
avoid regressions.
A good scenario (tested) seems to use those defines, instead:
#define EM28XX_MAX_AUDIO_BUFS 8
#define EM28XX_MIN_AUDIO_PACKETS 2
But let's not do such change here, letting the optimization to
happen on latter patches, after more tests.
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
2014-01-10 16:53:24 +08:00
|
|
|
urb->number_of_packets = npackets;
|
|
|
|
urb->transfer_buffer_length = ep_size * npackets;
|
2014-01-10 16:43:09 +08:00
|
|
|
|
[media] em28xx-audio: don't hardcode audio URB calculus
The current code hardcodes the number of audio URBs, the number
of packets per URB and the maximum URB size.
This is not a good idea, as it:
- wastes more bandwidth than necessary, by using a very
large number of packets;
- those constants are bound to an specific scenario, with
a bandwidth of 48 kHz;
- don't take the maximum endpoint size into account;
- with urb->interval = 1 on xHCI, those constraints cause a "funny"
setup: URBs with 64 packets inside, with only 24 bytes total. E. g.
a complete waste of space.
Change the code to do dynamic URB audio calculus and allocation.
For now, use the same constraints as used before this patch, to
avoid regressions.
A good scenario (tested) seems to use those defines, instead:
#define EM28XX_MAX_AUDIO_BUFS 8
#define EM28XX_MIN_AUDIO_PACKETS 2
But let's not do such change here, letting the optimization to
happen on latter patches, after more tests.
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
2014-01-10 16:53:24 +08:00
|
|
|
for (j = k = 0; j < npackets; j++, k += ep_size) {
|
2013-12-29 08:16:26 +08:00
|
|
|
urb->iso_frame_desc[j].offset = k;
|
[media] em28xx-audio: don't hardcode audio URB calculus
The current code hardcodes the number of audio URBs, the number
of packets per URB and the maximum URB size.
This is not a good idea, as it:
- wastes more bandwidth than necessary, by using a very
large number of packets;
- those constants are bound to an specific scenario, with
a bandwidth of 48 kHz;
- don't take the maximum endpoint size into account;
- with urb->interval = 1 on xHCI, those constraints cause a "funny"
setup: URBs with 64 packets inside, with only 24 bytes total. E. g.
a complete waste of space.
Change the code to do dynamic URB audio calculus and allocation.
For now, use the same constraints as used before this patch, to
avoid regressions.
A good scenario (tested) seems to use those defines, instead:
#define EM28XX_MAX_AUDIO_BUFS 8
#define EM28XX_MIN_AUDIO_PACKETS 2
But let's not do such change here, letting the optimization to
happen on latter patches, after more tests.
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
2014-01-10 16:53:24 +08:00
|
|
|
urb->iso_frame_desc[j].length = ep_size;
|
2013-12-29 08:16:26 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-12 21:10:34 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int em28xx_audio_init(struct em28xx *dev)
|
|
|
|
{
|
|
|
|
struct em28xx_audio *adev = &dev->adev;
|
|
|
|
struct snd_pcm *pcm;
|
|
|
|
struct snd_card *card;
|
|
|
|
static int devnr;
|
|
|
|
int err;
|
|
|
|
|
2014-01-14 06:02:06 +08:00
|
|
|
if (!dev->has_alsa_audio) {
|
2014-01-12 21:10:34 +08:00
|
|
|
/* This device does not support the extension (in this case
|
|
|
|
the device is expecting the snd-usb-audio module or
|
|
|
|
doesn't have analog audio support at all) */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
em28xx_info("Binding audio extension\n");
|
|
|
|
|
2014-03-05 22:21:07 +08:00
|
|
|
kref_get(&dev->ref);
|
|
|
|
|
2014-01-12 21:10:34 +08:00
|
|
|
printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
|
|
|
|
"Rechberger\n");
|
|
|
|
printk(KERN_INFO
|
|
|
|
"em28xx-audio.c: Copyright (C) 2007-2014 Mauro Carvalho Chehab\n");
|
|
|
|
|
2014-01-29 21:48:43 +08:00
|
|
|
err = snd_card_new(&dev->udev->dev, index[devnr], "Em28xx Audio",
|
|
|
|
THIS_MODULE, 0, &card);
|
2014-01-12 21:10:34 +08:00
|
|
|
if (err < 0)
|
|
|
|
return err;
|
|
|
|
|
|
|
|
spin_lock_init(&adev->slock);
|
|
|
|
adev->sndcard = card;
|
|
|
|
adev->udev = dev->udev;
|
|
|
|
|
|
|
|
err = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm);
|
2014-01-13 04:20:31 +08:00
|
|
|
if (err < 0)
|
|
|
|
goto card_free;
|
2014-01-12 21:10:34 +08:00
|
|
|
|
|
|
|
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture);
|
|
|
|
pcm->info_flags = 0;
|
|
|
|
pcm->private_data = dev;
|
|
|
|
strcpy(pcm->name, "Empia 28xx Capture");
|
|
|
|
|
|
|
|
strcpy(card->driver, "Em28xx-Audio");
|
|
|
|
strcpy(card->shortname, "Em28xx Audio");
|
|
|
|
strcpy(card->longname, "Empia Em28xx Audio");
|
|
|
|
|
|
|
|
INIT_WORK(&dev->wq_trigger, audio_trigger);
|
|
|
|
|
|
|
|
if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
|
|
|
|
em28xx_cvol_new(card, dev, "Video", AC97_VIDEO);
|
|
|
|
em28xx_cvol_new(card, dev, "Line In", AC97_LINE);
|
|
|
|
em28xx_cvol_new(card, dev, "Phone", AC97_PHONE);
|
|
|
|
em28xx_cvol_new(card, dev, "Microphone", AC97_MIC);
|
|
|
|
em28xx_cvol_new(card, dev, "CD", AC97_CD);
|
|
|
|
em28xx_cvol_new(card, dev, "AUX", AC97_AUX);
|
|
|
|
em28xx_cvol_new(card, dev, "PCM", AC97_PCM);
|
|
|
|
|
|
|
|
em28xx_cvol_new(card, dev, "Master", AC97_MASTER);
|
|
|
|
em28xx_cvol_new(card, dev, "Line", AC97_HEADPHONE);
|
|
|
|
em28xx_cvol_new(card, dev, "Mono", AC97_MASTER_MONO);
|
|
|
|
em28xx_cvol_new(card, dev, "LFE", AC97_CENTER_LFE_MASTER);
|
|
|
|
em28xx_cvol_new(card, dev, "Surround", AC97_SURROUND_MASTER);
|
|
|
|
}
|
|
|
|
|
|
|
|
err = em28xx_audio_urb_init(dev);
|
2014-01-13 04:20:31 +08:00
|
|
|
if (err)
|
|
|
|
goto card_free;
|
2014-01-12 21:10:34 +08:00
|
|
|
|
2008-01-05 20:57:31 +08:00
|
|
|
err = snd_card_register(card);
|
2014-01-13 04:20:31 +08:00
|
|
|
if (err < 0)
|
|
|
|
goto urb_free;
|
2008-01-05 20:57:31 +08:00
|
|
|
|
2013-12-26 23:41:03 +08:00
|
|
|
em28xx_info("Audio extension successfully initialized\n");
|
2008-01-05 20:55:47 +08:00
|
|
|
return 0;
|
2014-01-13 04:20:31 +08:00
|
|
|
|
|
|
|
urb_free:
|
|
|
|
em28xx_audio_free_urb(dev);
|
|
|
|
|
|
|
|
card_free:
|
|
|
|
snd_card_free(card);
|
2014-01-15 00:49:04 +08:00
|
|
|
adev->sndcard = NULL;
|
2014-01-13 04:20:31 +08:00
|
|
|
|
|
|
|
return err;
|
2008-01-05 20:55:47 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int em28xx_audio_fini(struct em28xx *dev)
|
|
|
|
{
|
2008-01-05 20:56:24 +08:00
|
|
|
if (dev == NULL)
|
2008-01-05 20:55:47 +08:00
|
|
|
return 0;
|
2008-01-05 20:57:31 +08:00
|
|
|
|
2014-03-05 22:21:07 +08:00
|
|
|
if (!dev->has_alsa_audio) {
|
2008-06-10 23:34:35 +08:00
|
|
|
/* This device does not support the extension (in this case
|
2008-11-12 13:05:19 +08:00
|
|
|
the device is expecting the snd-usb-audio module or
|
|
|
|
doesn't have analog audio support at all) */
|
2008-06-10 23:34:35 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-01-13 06:22:07 +08:00
|
|
|
em28xx_info("Closing audio extension");
|
|
|
|
|
2014-01-15 00:49:04 +08:00
|
|
|
if (dev->adev.sndcard) {
|
|
|
|
snd_card_disconnect(dev->adev.sndcard);
|
|
|
|
flush_work(&dev->wq_trigger);
|
2014-01-13 22:32:00 +08:00
|
|
|
|
2014-01-15 00:49:04 +08:00
|
|
|
em28xx_audio_free_urb(dev);
|
2013-12-29 08:16:26 +08:00
|
|
|
|
2008-12-31 20:37:33 +08:00
|
|
|
snd_card_free(dev->adev.sndcard);
|
|
|
|
dev->adev.sndcard = NULL;
|
2008-01-05 20:55:47 +08:00
|
|
|
}
|
2008-01-05 20:57:31 +08:00
|
|
|
|
2014-03-05 22:21:07 +08:00
|
|
|
kref_put(&dev->ref, em28xx_free_device);
|
2008-01-05 20:55:47 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-02-22 08:50:14 +08:00
|
|
|
static int em28xx_audio_suspend(struct em28xx *dev)
|
|
|
|
{
|
|
|
|
if (dev == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!dev->has_alsa_audio)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
em28xx_info("Suspending audio extension");
|
|
|
|
em28xx_deinit_isoc_audio(dev);
|
|
|
|
atomic_set(&dev->stream_started, 0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int em28xx_audio_resume(struct em28xx *dev)
|
|
|
|
{
|
|
|
|
if (dev == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (!dev->has_alsa_audio)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
em28xx_info("Resuming audio extension");
|
|
|
|
/* Nothing to do other than schedule_work() ?? */
|
|
|
|
schedule_work(&dev->wq_trigger);
|
2008-01-05 20:55:47 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct em28xx_ops audio_ops = {
|
2008-01-05 20:57:31 +08:00
|
|
|
.id = EM28XX_AUDIO,
|
2008-01-05 20:56:24 +08:00
|
|
|
.name = "Em28xx Audio Extension",
|
|
|
|
.init = em28xx_audio_init,
|
|
|
|
.fini = em28xx_audio_fini,
|
2014-02-22 08:50:14 +08:00
|
|
|
.suspend = em28xx_audio_suspend,
|
|
|
|
.resume = em28xx_audio_resume,
|
2008-01-05 20:55:47 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static int __init em28xx_alsa_register(void)
|
|
|
|
{
|
|
|
|
return em28xx_register_extension(&audio_ops);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit em28xx_alsa_unregister(void)
|
|
|
|
{
|
|
|
|
em28xx_unregister_extension(&audio_ops);
|
|
|
|
}
|
|
|
|
|
|
|
|
MODULE_LICENSE("GPL");
|
|
|
|
MODULE_AUTHOR("Markus Rechberger <mrechberger@gmail.com>");
|
2014-02-07 18:03:07 +08:00
|
|
|
MODULE_AUTHOR("Mauro Carvalho Chehab");
|
2013-12-27 22:14:59 +08:00
|
|
|
MODULE_DESCRIPTION(DRIVER_DESC " - audio interface");
|
|
|
|
MODULE_VERSION(EM28XX_VERSION);
|
2008-01-05 20:55:47 +08:00
|
|
|
|
|
|
|
module_init(em28xx_alsa_register);
|
|
|
|
module_exit(em28xx_alsa_unregister);
|