1f22e9e71SMauro Carvalho Chehab // SPDX-License-Identifier: GPL-2.0+
2f22e9e71SMauro Carvalho Chehab //
3f22e9e71SMauro Carvalho Chehab // Empiatech em28x1 audio extension
4f22e9e71SMauro Carvalho Chehab //
5f22e9e71SMauro Carvalho Chehab // Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com>
6f22e9e71SMauro Carvalho Chehab //
7f22e9e71SMauro Carvalho Chehab // Copyright (C) 2007-2016 Mauro Carvalho Chehab
8f22e9e71SMauro Carvalho Chehab // - Port to work with the in-kernel driver
9f22e9e71SMauro Carvalho Chehab // - Cleanups, fixes, alsa-controls, etc.
10f22e9e71SMauro Carvalho Chehab //
11f22e9e71SMauro Carvalho Chehab // This driver is based on my previous au600 usb pstn audio driver
12f22e9e71SMauro Carvalho Chehab // and inherits all the copyrights
130c0d06caSMauro Carvalho Chehab
148314d402SMauro Carvalho Chehab #include "em28xx.h"
158314d402SMauro Carvalho Chehab
160c0d06caSMauro Carvalho Chehab #include <linux/kernel.h>
170c0d06caSMauro Carvalho Chehab #include <linux/usb.h>
180c0d06caSMauro Carvalho Chehab #include <linux/init.h>
190c0d06caSMauro Carvalho Chehab #include <linux/sound.h>
200c0d06caSMauro Carvalho Chehab #include <linux/spinlock.h>
210c0d06caSMauro Carvalho Chehab #include <linux/soundcard.h>
220c0d06caSMauro Carvalho Chehab #include <linux/slab.h>
230c0d06caSMauro Carvalho Chehab #include <linux/module.h>
240c0d06caSMauro Carvalho Chehab #include <sound/core.h>
250c0d06caSMauro Carvalho Chehab #include <sound/pcm.h>
260c0d06caSMauro Carvalho Chehab #include <sound/pcm_params.h>
270c0d06caSMauro Carvalho Chehab #include <sound/info.h>
280c0d06caSMauro Carvalho Chehab #include <sound/initval.h>
290c0d06caSMauro Carvalho Chehab #include <sound/control.h>
300c0d06caSMauro Carvalho Chehab #include <sound/tlv.h>
310c0d06caSMauro Carvalho Chehab #include <sound/ac97_codec.h>
320c0d06caSMauro Carvalho Chehab #include <media/v4l2-common.h>
330c0d06caSMauro Carvalho Chehab
340c0d06caSMauro Carvalho Chehab static int debug;
350c0d06caSMauro Carvalho Chehab module_param(debug, int, 0644);
360c0d06caSMauro Carvalho Chehab MODULE_PARM_DESC(debug, "activates debug info");
370c0d06caSMauro Carvalho Chehab
381b3fd2d3SMauro Carvalho Chehab #define EM28XX_MAX_AUDIO_BUFS 5
391b3fd2d3SMauro Carvalho Chehab #define EM28XX_MIN_AUDIO_PACKETS 64
4049677aefSMauro Carvalho Chehab
410c0d06caSMauro Carvalho Chehab #define dprintk(fmt, arg...) do { \
420c0d06caSMauro Carvalho Chehab if (debug) \
4329b05e22SMauro Carvalho Chehab dev_printk(KERN_DEBUG, &dev->intf->dev, \
44ce8591ffSMauro Carvalho Chehab "video: %s: " fmt, __func__, ## arg); \
45ce8591ffSMauro Carvalho Chehab } while (0)
460c0d06caSMauro Carvalho Chehab
470c0d06caSMauro Carvalho Chehab static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
480c0d06caSMauro Carvalho Chehab
em28xx_deinit_isoc_audio(struct em28xx * dev)490c0d06caSMauro Carvalho Chehab static int em28xx_deinit_isoc_audio(struct em28xx *dev)
500c0d06caSMauro Carvalho Chehab {
510c0d06caSMauro Carvalho Chehab int i;
520c0d06caSMauro Carvalho Chehab
530c0d06caSMauro Carvalho Chehab dprintk("Stopping isoc\n");
541b3fd2d3SMauro Carvalho Chehab for (i = 0; i < dev->adev.num_urb; i++) {
5546c704d7SMauro Carvalho Chehab struct urb *urb = dev->adev.urb[i];
5646c704d7SMauro Carvalho Chehab
570c0d06caSMauro Carvalho Chehab if (!irqs_disabled())
5846c704d7SMauro Carvalho Chehab usb_kill_urb(urb);
590c0d06caSMauro Carvalho Chehab else
6046c704d7SMauro Carvalho Chehab usb_unlink_urb(urb);
610c0d06caSMauro Carvalho Chehab }
620c0d06caSMauro Carvalho Chehab
630c0d06caSMauro Carvalho Chehab return 0;
640c0d06caSMauro Carvalho Chehab }
650c0d06caSMauro Carvalho Chehab
em28xx_audio_isocirq(struct urb * urb)660c0d06caSMauro Carvalho Chehab static void em28xx_audio_isocirq(struct urb *urb)
670c0d06caSMauro Carvalho Chehab {
680c0d06caSMauro Carvalho Chehab struct em28xx *dev = urb->context;
690c0d06caSMauro Carvalho Chehab int i;
700c0d06caSMauro Carvalho Chehab unsigned int oldptr;
710c0d06caSMauro Carvalho Chehab int period_elapsed = 0;
720c0d06caSMauro Carvalho Chehab int status;
730c0d06caSMauro Carvalho Chehab unsigned char *cp;
740c0d06caSMauro Carvalho Chehab unsigned int stride;
750c0d06caSMauro Carvalho Chehab struct snd_pcm_substream *substream;
760c0d06caSMauro Carvalho Chehab struct snd_pcm_runtime *runtime;
770c0d06caSMauro Carvalho Chehab
788b1fa579SMauro Carvalho Chehab if (dev->disconnected) {
79ce8591ffSMauro Carvalho Chehab dprintk("device disconnected while streaming. URB status=%d.\n",
80ce8591ffSMauro Carvalho Chehab urb->status);
81a5c075cfSFrank Schaefer atomic_set(&dev->adev.stream_started, 0);
828b1fa579SMauro Carvalho Chehab return;
838b1fa579SMauro Carvalho Chehab }
848b1fa579SMauro Carvalho Chehab
850c0d06caSMauro Carvalho Chehab switch (urb->status) {
860c0d06caSMauro Carvalho Chehab case 0: /* success */
870c0d06caSMauro Carvalho Chehab case -ETIMEDOUT: /* NAK */
880c0d06caSMauro Carvalho Chehab break;
890c0d06caSMauro Carvalho Chehab case -ECONNRESET: /* kill */
900c0d06caSMauro Carvalho Chehab case -ENOENT:
910c0d06caSMauro Carvalho Chehab case -ESHUTDOWN:
920c0d06caSMauro Carvalho Chehab return;
930c0d06caSMauro Carvalho Chehab default: /* error */
949f90f537SMauro Carvalho Chehab dprintk("urb completion error %d.\n", urb->status);
950c0d06caSMauro Carvalho Chehab break;
960c0d06caSMauro Carvalho Chehab }
970c0d06caSMauro Carvalho Chehab
98a5c075cfSFrank Schaefer if (atomic_read(&dev->adev.stream_started) == 0)
990c0d06caSMauro Carvalho Chehab return;
1000c0d06caSMauro Carvalho Chehab
1010c0d06caSMauro Carvalho Chehab if (dev->adev.capture_pcm_substream) {
1020c0d06caSMauro Carvalho Chehab substream = dev->adev.capture_pcm_substream;
1030c0d06caSMauro Carvalho Chehab runtime = substream->runtime;
1040c0d06caSMauro Carvalho Chehab stride = runtime->frame_bits >> 3;
1050c0d06caSMauro Carvalho Chehab
1060c0d06caSMauro Carvalho Chehab for (i = 0; i < urb->number_of_packets; i++) {
107273925c7SSebastian Andrzej Siewior unsigned long flags;
1080c0d06caSMauro Carvalho Chehab int length =
1090c0d06caSMauro Carvalho Chehab urb->iso_frame_desc[i].actual_length / stride;
1100c0d06caSMauro Carvalho Chehab cp = (unsigned char *)urb->transfer_buffer +
1110c0d06caSMauro Carvalho Chehab urb->iso_frame_desc[i].offset;
1120c0d06caSMauro Carvalho Chehab
1130c0d06caSMauro Carvalho Chehab if (!length)
1140c0d06caSMauro Carvalho Chehab continue;
1150c0d06caSMauro Carvalho Chehab
1160c0d06caSMauro Carvalho Chehab oldptr = dev->adev.hwptr_done_capture;
1170c0d06caSMauro Carvalho Chehab if (oldptr + length >= runtime->buffer_size) {
1180c0d06caSMauro Carvalho Chehab unsigned int cnt =
1190c0d06caSMauro Carvalho Chehab runtime->buffer_size - oldptr;
1200c0d06caSMauro Carvalho Chehab memcpy(runtime->dma_area + oldptr * stride, cp,
1210c0d06caSMauro Carvalho Chehab cnt * stride);
1220c0d06caSMauro Carvalho Chehab memcpy(runtime->dma_area, cp + cnt * stride,
1230c0d06caSMauro Carvalho Chehab length * stride - cnt * stride);
1240c0d06caSMauro Carvalho Chehab } else {
1250c0d06caSMauro Carvalho Chehab memcpy(runtime->dma_area + oldptr * stride, cp,
1260c0d06caSMauro Carvalho Chehab length * stride);
1270c0d06caSMauro Carvalho Chehab }
1280c0d06caSMauro Carvalho Chehab
129273925c7SSebastian Andrzej Siewior snd_pcm_stream_lock_irqsave(substream, flags);
1300c0d06caSMauro Carvalho Chehab
1310c0d06caSMauro Carvalho Chehab dev->adev.hwptr_done_capture += length;
1320c0d06caSMauro Carvalho Chehab if (dev->adev.hwptr_done_capture >=
1330c0d06caSMauro Carvalho Chehab runtime->buffer_size)
1340c0d06caSMauro Carvalho Chehab dev->adev.hwptr_done_capture -=
1350c0d06caSMauro Carvalho Chehab runtime->buffer_size;
1360c0d06caSMauro Carvalho Chehab
1370c0d06caSMauro Carvalho Chehab dev->adev.capture_transfer_done += length;
1380c0d06caSMauro Carvalho Chehab if (dev->adev.capture_transfer_done >=
1390c0d06caSMauro Carvalho Chehab runtime->period_size) {
1400c0d06caSMauro Carvalho Chehab dev->adev.capture_transfer_done -=
1410c0d06caSMauro Carvalho Chehab runtime->period_size;
1420c0d06caSMauro Carvalho Chehab period_elapsed = 1;
1430c0d06caSMauro Carvalho Chehab }
1440c0d06caSMauro Carvalho Chehab
145273925c7SSebastian Andrzej Siewior snd_pcm_stream_unlock_irqrestore(substream, flags);
1460c0d06caSMauro Carvalho Chehab }
1470c0d06caSMauro Carvalho Chehab if (period_elapsed)
1480c0d06caSMauro Carvalho Chehab snd_pcm_period_elapsed(substream);
1490c0d06caSMauro Carvalho Chehab }
1500c0d06caSMauro Carvalho Chehab urb->status = 0;
1510c0d06caSMauro Carvalho Chehab
1520c0d06caSMauro Carvalho Chehab status = usb_submit_urb(urb, GFP_ATOMIC);
153bf6e8aaaSMauro Carvalho Chehab if (status < 0)
15429b05e22SMauro Carvalho Chehab dev_err(&dev->intf->dev,
155ce8591ffSMauro Carvalho Chehab "resubmit of audio urb failed (error=%i)\n",
1560c0d06caSMauro Carvalho Chehab status);
1570c0d06caSMauro Carvalho Chehab }
1580c0d06caSMauro Carvalho Chehab
em28xx_init_audio_isoc(struct em28xx * dev)1590c0d06caSMauro Carvalho Chehab static int em28xx_init_audio_isoc(struct em28xx *dev)
1600c0d06caSMauro Carvalho Chehab {
1619f90f537SMauro Carvalho Chehab int i, err;
1620c0d06caSMauro Carvalho Chehab
1630c0d06caSMauro Carvalho Chehab dprintk("Starting isoc transfers\n");
1640c0d06caSMauro Carvalho Chehab
165f5f894d1SMauro Carvalho Chehab /* Start streaming */
1661b3fd2d3SMauro Carvalho Chehab for (i = 0; i < dev->adev.num_urb; i++) {
167f5f894d1SMauro Carvalho Chehab memset(dev->adev.transfer_buffer[i], 0x80,
168f5f894d1SMauro Carvalho Chehab dev->adev.urb[i]->transfer_buffer_length);
1690c0d06caSMauro Carvalho Chehab
1709f90f537SMauro Carvalho Chehab err = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
1719f90f537SMauro Carvalho Chehab if (err) {
17229b05e22SMauro Carvalho Chehab dev_err(&dev->intf->dev,
173ce8591ffSMauro Carvalho Chehab "submit of audio urb failed (error=%i)\n",
1749f90f537SMauro Carvalho Chehab err);
1750c0d06caSMauro Carvalho Chehab em28xx_deinit_isoc_audio(dev);
176a5c075cfSFrank Schaefer atomic_set(&dev->adev.stream_started, 0);
1779f90f537SMauro Carvalho Chehab return err;
1780c0d06caSMauro Carvalho Chehab }
1790c0d06caSMauro Carvalho Chehab }
1800c0d06caSMauro Carvalho Chehab
1810c0d06caSMauro Carvalho Chehab return 0;
1820c0d06caSMauro Carvalho Chehab }
1830c0d06caSMauro Carvalho Chehab
18438c4f03aSBhumika Goyal static const struct snd_pcm_hardware snd_em28xx_hw_capture = {
1850c0d06caSMauro Carvalho Chehab .info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
1860c0d06caSMauro Carvalho Chehab SNDRV_PCM_INFO_MMAP |
1870c0d06caSMauro Carvalho Chehab SNDRV_PCM_INFO_INTERLEAVED |
1880c0d06caSMauro Carvalho Chehab SNDRV_PCM_INFO_BATCH |
1890c0d06caSMauro Carvalho Chehab SNDRV_PCM_INFO_MMAP_VALID,
1900c0d06caSMauro Carvalho Chehab
1910c0d06caSMauro Carvalho Chehab .formats = SNDRV_PCM_FMTBIT_S16_LE,
1920c0d06caSMauro Carvalho Chehab
19349677aefSMauro Carvalho Chehab .rates = SNDRV_PCM_RATE_48000,
1940c0d06caSMauro Carvalho Chehab
1950c0d06caSMauro Carvalho Chehab .rate_min = 48000,
1960c0d06caSMauro Carvalho Chehab .rate_max = 48000,
1970c0d06caSMauro Carvalho Chehab .channels_min = 2,
1980c0d06caSMauro Carvalho Chehab .channels_max = 2,
1990c0d06caSMauro Carvalho Chehab .buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */
20049677aefSMauro Carvalho Chehab
20149677aefSMauro Carvalho Chehab /*
20249677aefSMauro Carvalho Chehab * The period is 12.288 bytes. Allow a 10% of variation along its
20349677aefSMauro Carvalho Chehab * value, in order to avoid overruns/underruns due to some clock
20449677aefSMauro Carvalho Chehab * drift.
20549677aefSMauro Carvalho Chehab *
20649677aefSMauro Carvalho Chehab * FIXME: This period assumes 64 packets, and a 48000 PCM rate.
20749677aefSMauro Carvalho Chehab * Calculate it dynamically.
20849677aefSMauro Carvalho Chehab */
20949677aefSMauro Carvalho Chehab .period_bytes_min = 11059,
21049677aefSMauro Carvalho Chehab .period_bytes_max = 13516,
21149677aefSMauro Carvalho Chehab
2120c0d06caSMauro Carvalho Chehab .periods_min = 2,
2130c0d06caSMauro Carvalho Chehab .periods_max = 98, /* 12544, */
2140c0d06caSMauro Carvalho Chehab };
2150c0d06caSMauro Carvalho Chehab
snd_em28xx_capture_open(struct snd_pcm_substream * substream)2160c0d06caSMauro Carvalho Chehab static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
2170c0d06caSMauro Carvalho Chehab {
2180c0d06caSMauro Carvalho Chehab struct em28xx *dev = snd_pcm_substream_chip(substream);
2190c0d06caSMauro Carvalho Chehab struct snd_pcm_runtime *runtime = substream->runtime;
22001ae3b51SFrank Schaefer int nonblock, ret = 0;
2210c0d06caSMauro Carvalho Chehab
2220c0d06caSMauro Carvalho Chehab if (!dev) {
223257e29f8SMauro Carvalho Chehab pr_err("em28xx-audio: BUG: em28xx can't find device struct. Can't proceed with open\n");
2240c0d06caSMauro Carvalho Chehab return -ENODEV;
2250c0d06caSMauro Carvalho Chehab }
2260c0d06caSMauro Carvalho Chehab
2278b1fa579SMauro Carvalho Chehab if (dev->disconnected)
2288b1fa579SMauro Carvalho Chehab return -ENODEV;
2298b1fa579SMauro Carvalho Chehab
2308b1fa579SMauro Carvalho Chehab dprintk("opening device and trying to acquire exclusive lock\n");
2318b1fa579SMauro Carvalho Chehab
23201ae3b51SFrank Schaefer nonblock = !!(substream->f_flags & O_NONBLOCK);
23334906633SMauro Carvalho Chehab if (nonblock) {
23434906633SMauro Carvalho Chehab if (!mutex_trylock(&dev->lock))
23534906633SMauro Carvalho Chehab return -EAGAIN;
2369f90f537SMauro Carvalho Chehab } else {
23734906633SMauro Carvalho Chehab mutex_lock(&dev->lock);
2389f90f537SMauro Carvalho Chehab }
23901ae3b51SFrank Schaefer
24001ae3b51SFrank Schaefer runtime->hw = snd_em28xx_hw_capture;
241ba35ca07SFrank Schaefer
242ba35ca07SFrank Schaefer if (dev->adev.users == 0) {
2439f90f537SMauro Carvalho Chehab if (!dev->alt || dev->is_audio_only) {
2449f90f537SMauro Carvalho Chehab struct usb_device *udev;
2459f90f537SMauro Carvalho Chehab
2469f90f537SMauro Carvalho Chehab udev = interface_to_usbdev(dev->intf);
247c6d48134SMauro Carvalho Chehab
2480191a2a2SFrank Schaefer if (dev->is_audio_only)
249ba35ca07SFrank Schaefer /* audio is on a separate interface */
2500c0d06caSMauro Carvalho Chehab dev->alt = 1;
2510c0d06caSMauro Carvalho Chehab else
252ba35ca07SFrank Schaefer /* audio is on the same interface as video */
2530c0d06caSMauro Carvalho Chehab dev->alt = 7;
2540191a2a2SFrank Schaefer /*
255ba35ca07SFrank Schaefer * FIXME: The intention seems to be to select
256ba35ca07SFrank Schaefer * the alt setting with the largest
257ba35ca07SFrank Schaefer * wMaxPacketSize for the video endpoint.
258ba35ca07SFrank Schaefer * At least dev->alt should be used instead, but
259ba35ca07SFrank Schaefer * we should probably not touch it at all if it
260ba35ca07SFrank Schaefer * is already >0, because wMaxPacketSize of the
261ba35ca07SFrank Schaefer * audio endpoints seems to be the same for all.
2620191a2a2SFrank Schaefer */
2630c0d06caSMauro Carvalho Chehab dprintk("changing alternate number on interface %d to %d\n",
264961717b4SFrank Schaefer dev->ifnum, dev->alt);
265c6d48134SMauro Carvalho Chehab usb_set_interface(udev, dev->ifnum, dev->alt);
266ba35ca07SFrank Schaefer }
2670c0d06caSMauro Carvalho Chehab
2680c0d06caSMauro Carvalho Chehab /* Sets volume, mute, etc */
2690c0d06caSMauro Carvalho Chehab dev->mute = 0;
2700c0d06caSMauro Carvalho Chehab ret = em28xx_audio_analog_set(dev);
2710c0d06caSMauro Carvalho Chehab if (ret < 0)
2720c0d06caSMauro Carvalho Chehab goto err;
27301ae3b51SFrank Schaefer }
2740c0d06caSMauro Carvalho Chehab
27547677e51SMauro Carvalho Chehab kref_get(&dev->ref);
2760c0d06caSMauro Carvalho Chehab dev->adev.users++;
2770c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->lock);
2780c0d06caSMauro Carvalho Chehab
279a02b9c23SMauro Carvalho Chehab /* Dynamically adjust the period size */
2800c0d06caSMauro Carvalho Chehab snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
281a02b9c23SMauro Carvalho Chehab snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
282a02b9c23SMauro Carvalho Chehab dev->adev.period * 95 / 100,
283a02b9c23SMauro Carvalho Chehab dev->adev.period * 105 / 100);
284a02b9c23SMauro Carvalho Chehab
2850c0d06caSMauro Carvalho Chehab dev->adev.capture_pcm_substream = substream;
2860c0d06caSMauro Carvalho Chehab
2870c0d06caSMauro Carvalho Chehab return 0;
2880c0d06caSMauro Carvalho Chehab err:
2890c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->lock);
2900c0d06caSMauro Carvalho Chehab
29129b05e22SMauro Carvalho Chehab dev_err(&dev->intf->dev,
292ce8591ffSMauro Carvalho Chehab "Error while configuring em28xx mixer\n");
2930c0d06caSMauro Carvalho Chehab return ret;
2940c0d06caSMauro Carvalho Chehab }
2950c0d06caSMauro Carvalho Chehab
snd_em28xx_pcm_close(struct snd_pcm_substream * substream)2960c0d06caSMauro Carvalho Chehab static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
2970c0d06caSMauro Carvalho Chehab {
2980c0d06caSMauro Carvalho Chehab struct em28xx *dev = snd_pcm_substream_chip(substream);
2990c0d06caSMauro Carvalho Chehab
3000c0d06caSMauro Carvalho Chehab dprintk("closing device\n");
3010c0d06caSMauro Carvalho Chehab
3020c0d06caSMauro Carvalho Chehab dev->mute = 1;
3030c0d06caSMauro Carvalho Chehab mutex_lock(&dev->lock);
3040c0d06caSMauro Carvalho Chehab dev->adev.users--;
305a5c075cfSFrank Schaefer if (atomic_read(&dev->adev.stream_started) > 0) {
306a5c075cfSFrank Schaefer atomic_set(&dev->adev.stream_started, 0);
307a5c075cfSFrank Schaefer schedule_work(&dev->adev.wq_trigger);
3080c0d06caSMauro Carvalho Chehab }
3090c0d06caSMauro Carvalho Chehab
3100c0d06caSMauro Carvalho Chehab em28xx_audio_analog_set(dev);
3110c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->lock);
31247677e51SMauro Carvalho Chehab kref_put(&dev->ref, em28xx_free_device);
3130c0d06caSMauro Carvalho Chehab
3140c0d06caSMauro Carvalho Chehab return 0;
3150c0d06caSMauro Carvalho Chehab }
3160c0d06caSMauro Carvalho Chehab
snd_em28xx_prepare(struct snd_pcm_substream * substream)3170c0d06caSMauro Carvalho Chehab static int snd_em28xx_prepare(struct snd_pcm_substream *substream)
3180c0d06caSMauro Carvalho Chehab {
3190c0d06caSMauro Carvalho Chehab struct em28xx *dev = snd_pcm_substream_chip(substream);
3200c0d06caSMauro Carvalho Chehab
3218b1fa579SMauro Carvalho Chehab if (dev->disconnected)
3228b1fa579SMauro Carvalho Chehab return -ENODEV;
3238b1fa579SMauro Carvalho Chehab
3240c0d06caSMauro Carvalho Chehab dev->adev.hwptr_done_capture = 0;
3250c0d06caSMauro Carvalho Chehab dev->adev.capture_transfer_done = 0;
3260c0d06caSMauro Carvalho Chehab
3270c0d06caSMauro Carvalho Chehab return 0;
3280c0d06caSMauro Carvalho Chehab }
3290c0d06caSMauro Carvalho Chehab
audio_trigger(struct work_struct * work)3300c0d06caSMauro Carvalho Chehab static void audio_trigger(struct work_struct *work)
3310c0d06caSMauro Carvalho Chehab {
332a5c075cfSFrank Schaefer struct em28xx_audio *adev =
333a5c075cfSFrank Schaefer container_of(work, struct em28xx_audio, wq_trigger);
334a5c075cfSFrank Schaefer struct em28xx *dev = container_of(adev, struct em28xx, adev);
3350c0d06caSMauro Carvalho Chehab
336a5c075cfSFrank Schaefer if (atomic_read(&adev->stream_started)) {
3370c0d06caSMauro Carvalho Chehab dprintk("starting capture");
3380c0d06caSMauro Carvalho Chehab em28xx_init_audio_isoc(dev);
3390c0d06caSMauro Carvalho Chehab } else {
3400c0d06caSMauro Carvalho Chehab dprintk("stopping capture");
3410c0d06caSMauro Carvalho Chehab em28xx_deinit_isoc_audio(dev);
3420c0d06caSMauro Carvalho Chehab }
3430c0d06caSMauro Carvalho Chehab }
3440c0d06caSMauro Carvalho Chehab
snd_em28xx_capture_trigger(struct snd_pcm_substream * substream,int cmd)3450c0d06caSMauro Carvalho Chehab static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream,
3460c0d06caSMauro Carvalho Chehab int cmd)
3470c0d06caSMauro Carvalho Chehab {
3480c0d06caSMauro Carvalho Chehab struct em28xx *dev = snd_pcm_substream_chip(substream);
3490c0d06caSMauro Carvalho Chehab int retval = 0;
3500c0d06caSMauro Carvalho Chehab
3518b1fa579SMauro Carvalho Chehab if (dev->disconnected)
3528b1fa579SMauro Carvalho Chehab return -ENODEV;
3538b1fa579SMauro Carvalho Chehab
3540c0d06caSMauro Carvalho Chehab switch (cmd) {
3551771e9fbSGustavo A. R. Silva case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
3561771e9fbSGustavo A. R. Silva case SNDRV_PCM_TRIGGER_RESUME:
3570c0d06caSMauro Carvalho Chehab case SNDRV_PCM_TRIGGER_START:
358a5c075cfSFrank Schaefer atomic_set(&dev->adev.stream_started, 1);
3590c0d06caSMauro Carvalho Chehab break;
3601771e9fbSGustavo A. R. Silva case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
3611771e9fbSGustavo A. R. Silva case SNDRV_PCM_TRIGGER_SUSPEND:
3620c0d06caSMauro Carvalho Chehab case SNDRV_PCM_TRIGGER_STOP:
363a5c075cfSFrank Schaefer atomic_set(&dev->adev.stream_started, 0);
3640c0d06caSMauro Carvalho Chehab break;
3650c0d06caSMauro Carvalho Chehab default:
3660c0d06caSMauro Carvalho Chehab retval = -EINVAL;
3670c0d06caSMauro Carvalho Chehab }
368a5c075cfSFrank Schaefer schedule_work(&dev->adev.wq_trigger);
3690c0d06caSMauro Carvalho Chehab return retval;
3700c0d06caSMauro Carvalho Chehab }
3710c0d06caSMauro Carvalho Chehab
snd_em28xx_capture_pointer(struct snd_pcm_substream * substream)3720c0d06caSMauro Carvalho Chehab static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream
3730c0d06caSMauro Carvalho Chehab *substream)
3740c0d06caSMauro Carvalho Chehab {
3750c0d06caSMauro Carvalho Chehab unsigned long flags;
3760c0d06caSMauro Carvalho Chehab struct em28xx *dev;
3770c0d06caSMauro Carvalho Chehab snd_pcm_uframes_t hwptr_done;
3780c0d06caSMauro Carvalho Chehab
3790c0d06caSMauro Carvalho Chehab dev = snd_pcm_substream_chip(substream);
3808b1fa579SMauro Carvalho Chehab if (dev->disconnected)
381229295f1SMauro Carvalho Chehab return SNDRV_PCM_POS_XRUN;
3828b1fa579SMauro Carvalho Chehab
3830c0d06caSMauro Carvalho Chehab spin_lock_irqsave(&dev->adev.slock, flags);
3840c0d06caSMauro Carvalho Chehab hwptr_done = dev->adev.hwptr_done_capture;
3850c0d06caSMauro Carvalho Chehab spin_unlock_irqrestore(&dev->adev.slock, flags);
3860c0d06caSMauro Carvalho Chehab
3870c0d06caSMauro Carvalho Chehab return hwptr_done;
3880c0d06caSMauro Carvalho Chehab }
3890c0d06caSMauro Carvalho Chehab
3900c0d06caSMauro Carvalho Chehab /*
3910c0d06caSMauro Carvalho Chehab * AC97 volume control support
3920c0d06caSMauro Carvalho Chehab */
em28xx_vol_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * info)3930c0d06caSMauro Carvalho Chehab static int em28xx_vol_info(struct snd_kcontrol *kcontrol,
3940c0d06caSMauro Carvalho Chehab struct snd_ctl_elem_info *info)
3950c0d06caSMauro Carvalho Chehab {
3968b1fa579SMauro Carvalho Chehab struct em28xx *dev = snd_kcontrol_chip(kcontrol);
3978b1fa579SMauro Carvalho Chehab
3988b1fa579SMauro Carvalho Chehab if (dev->disconnected)
3998b1fa579SMauro Carvalho Chehab return -ENODEV;
4008b1fa579SMauro Carvalho Chehab
4010c0d06caSMauro Carvalho Chehab info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
4020c0d06caSMauro Carvalho Chehab info->count = 2;
4030c0d06caSMauro Carvalho Chehab info->value.integer.min = 0;
4040c0d06caSMauro Carvalho Chehab info->value.integer.max = 0x1f;
4050c0d06caSMauro Carvalho Chehab
4060c0d06caSMauro Carvalho Chehab return 0;
4070c0d06caSMauro Carvalho Chehab }
4080c0d06caSMauro Carvalho Chehab
em28xx_vol_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * value)4090c0d06caSMauro Carvalho Chehab static int em28xx_vol_put(struct snd_kcontrol *kcontrol,
4100c0d06caSMauro Carvalho Chehab struct snd_ctl_elem_value *value)
4110c0d06caSMauro Carvalho Chehab {
4120c0d06caSMauro Carvalho Chehab struct em28xx *dev = snd_kcontrol_chip(kcontrol);
41334906633SMauro Carvalho Chehab struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream;
4140c0d06caSMauro Carvalho Chehab u16 val = (0x1f - (value->value.integer.value[0] & 0x1f)) |
4150c0d06caSMauro Carvalho Chehab (0x1f - (value->value.integer.value[1] & 0x1f)) << 8;
41634906633SMauro Carvalho Chehab int nonblock = 0;
4170c0d06caSMauro Carvalho Chehab int rc;
4180c0d06caSMauro Carvalho Chehab
4198b1fa579SMauro Carvalho Chehab if (dev->disconnected)
4208b1fa579SMauro Carvalho Chehab return -ENODEV;
4218b1fa579SMauro Carvalho Chehab
42234906633SMauro Carvalho Chehab if (substream)
42334906633SMauro Carvalho Chehab nonblock = !!(substream->f_flags & O_NONBLOCK);
42434906633SMauro Carvalho Chehab if (nonblock) {
42534906633SMauro Carvalho Chehab if (!mutex_trylock(&dev->lock))
42634906633SMauro Carvalho Chehab return -EAGAIN;
4279f90f537SMauro Carvalho Chehab } else {
4280c0d06caSMauro Carvalho Chehab mutex_lock(&dev->lock);
4299f90f537SMauro Carvalho Chehab }
4300c0d06caSMauro Carvalho Chehab rc = em28xx_read_ac97(dev, kcontrol->private_value);
4310c0d06caSMauro Carvalho Chehab if (rc < 0)
4320c0d06caSMauro Carvalho Chehab goto err;
4330c0d06caSMauro Carvalho Chehab
4340c0d06caSMauro Carvalho Chehab val |= rc & 0x8000; /* Preserve the mute flag */
4350c0d06caSMauro Carvalho Chehab
4360c0d06caSMauro Carvalho Chehab rc = em28xx_write_ac97(dev, kcontrol->private_value, val);
4370c0d06caSMauro Carvalho Chehab if (rc < 0)
4380c0d06caSMauro Carvalho Chehab goto err;
4390c0d06caSMauro Carvalho Chehab
4400c0d06caSMauro Carvalho Chehab dprintk("%sleft vol %d, right vol %d (0x%04x) to ac97 volume control 0x%04x\n",
4410c0d06caSMauro Carvalho Chehab (val & 0x8000) ? "muted " : "",
4420c0d06caSMauro Carvalho Chehab 0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f),
4430c0d06caSMauro Carvalho Chehab val, (int)kcontrol->private_value);
4440c0d06caSMauro Carvalho Chehab
4450c0d06caSMauro Carvalho Chehab err:
4460c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->lock);
4470c0d06caSMauro Carvalho Chehab return rc;
4480c0d06caSMauro Carvalho Chehab }
4490c0d06caSMauro Carvalho Chehab
em28xx_vol_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * value)4500c0d06caSMauro Carvalho Chehab static int em28xx_vol_get(struct snd_kcontrol *kcontrol,
4510c0d06caSMauro Carvalho Chehab struct snd_ctl_elem_value *value)
4520c0d06caSMauro Carvalho Chehab {
4530c0d06caSMauro Carvalho Chehab struct em28xx *dev = snd_kcontrol_chip(kcontrol);
45434906633SMauro Carvalho Chehab struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream;
45534906633SMauro Carvalho Chehab int nonblock = 0;
4560c0d06caSMauro Carvalho Chehab int val;
4570c0d06caSMauro Carvalho Chehab
4588b1fa579SMauro Carvalho Chehab if (dev->disconnected)
4598b1fa579SMauro Carvalho Chehab return -ENODEV;
4608b1fa579SMauro Carvalho Chehab
46134906633SMauro Carvalho Chehab if (substream)
46234906633SMauro Carvalho Chehab nonblock = !!(substream->f_flags & O_NONBLOCK);
46334906633SMauro Carvalho Chehab if (nonblock) {
46434906633SMauro Carvalho Chehab if (!mutex_trylock(&dev->lock))
46534906633SMauro Carvalho Chehab return -EAGAIN;
4669f90f537SMauro Carvalho Chehab } else {
4670c0d06caSMauro Carvalho Chehab mutex_lock(&dev->lock);
4689f90f537SMauro Carvalho Chehab }
4690c0d06caSMauro Carvalho Chehab val = em28xx_read_ac97(dev, kcontrol->private_value);
4700c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->lock);
4710c0d06caSMauro Carvalho Chehab if (val < 0)
4720c0d06caSMauro Carvalho Chehab return val;
4730c0d06caSMauro Carvalho Chehab
4740c0d06caSMauro Carvalho Chehab dprintk("%sleft vol %d, right vol %d (0x%04x) from ac97 volume control 0x%04x\n",
4750c0d06caSMauro Carvalho Chehab (val & 0x8000) ? "muted " : "",
4760c0d06caSMauro Carvalho Chehab 0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f),
4770c0d06caSMauro Carvalho Chehab val, (int)kcontrol->private_value);
4780c0d06caSMauro Carvalho Chehab
4790c0d06caSMauro Carvalho Chehab value->value.integer.value[0] = 0x1f - (val & 0x1f);
480801e3659SColin Ian King value->value.integer.value[1] = 0x1f - ((val >> 8) & 0x1f);
4810c0d06caSMauro Carvalho Chehab
4820c0d06caSMauro Carvalho Chehab return 0;
4830c0d06caSMauro Carvalho Chehab }
4840c0d06caSMauro Carvalho Chehab
em28xx_vol_put_mute(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * value)4850c0d06caSMauro Carvalho Chehab static int em28xx_vol_put_mute(struct snd_kcontrol *kcontrol,
4860c0d06caSMauro Carvalho Chehab struct snd_ctl_elem_value *value)
4870c0d06caSMauro Carvalho Chehab {
4880c0d06caSMauro Carvalho Chehab struct em28xx *dev = snd_kcontrol_chip(kcontrol);
4890c0d06caSMauro Carvalho Chehab u16 val = value->value.integer.value[0];
49034906633SMauro Carvalho Chehab struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream;
49134906633SMauro Carvalho Chehab int nonblock = 0;
4920c0d06caSMauro Carvalho Chehab int rc;
4930c0d06caSMauro Carvalho Chehab
4948b1fa579SMauro Carvalho Chehab if (dev->disconnected)
4958b1fa579SMauro Carvalho Chehab return -ENODEV;
4968b1fa579SMauro Carvalho Chehab
49734906633SMauro Carvalho Chehab if (substream)
49834906633SMauro Carvalho Chehab nonblock = !!(substream->f_flags & O_NONBLOCK);
49934906633SMauro Carvalho Chehab if (nonblock) {
50034906633SMauro Carvalho Chehab if (!mutex_trylock(&dev->lock))
50134906633SMauro Carvalho Chehab return -EAGAIN;
5029f90f537SMauro Carvalho Chehab } else {
5030c0d06caSMauro Carvalho Chehab mutex_lock(&dev->lock);
5049f90f537SMauro Carvalho Chehab }
5050c0d06caSMauro Carvalho Chehab rc = em28xx_read_ac97(dev, kcontrol->private_value);
5060c0d06caSMauro Carvalho Chehab if (rc < 0)
5070c0d06caSMauro Carvalho Chehab goto err;
5080c0d06caSMauro Carvalho Chehab
5090c0d06caSMauro Carvalho Chehab if (val)
5100c0d06caSMauro Carvalho Chehab rc &= 0x1f1f;
5110c0d06caSMauro Carvalho Chehab else
5120c0d06caSMauro Carvalho Chehab rc |= 0x8000;
5130c0d06caSMauro Carvalho Chehab
5140c0d06caSMauro Carvalho Chehab rc = em28xx_write_ac97(dev, kcontrol->private_value, rc);
5150c0d06caSMauro Carvalho Chehab if (rc < 0)
5160c0d06caSMauro Carvalho Chehab goto err;
5170c0d06caSMauro Carvalho Chehab
5180c0d06caSMauro Carvalho Chehab dprintk("%sleft vol %d, right vol %d (0x%04x) to ac97 volume control 0x%04x\n",
5190c0d06caSMauro Carvalho Chehab (val & 0x8000) ? "muted " : "",
5200c0d06caSMauro Carvalho Chehab 0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f),
5210c0d06caSMauro Carvalho Chehab val, (int)kcontrol->private_value);
5220c0d06caSMauro Carvalho Chehab
5230c0d06caSMauro Carvalho Chehab err:
5240c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->lock);
5250c0d06caSMauro Carvalho Chehab return rc;
5260c0d06caSMauro Carvalho Chehab }
5270c0d06caSMauro Carvalho Chehab
em28xx_vol_get_mute(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * value)5280c0d06caSMauro Carvalho Chehab static int em28xx_vol_get_mute(struct snd_kcontrol *kcontrol,
5290c0d06caSMauro Carvalho Chehab struct snd_ctl_elem_value *value)
5300c0d06caSMauro Carvalho Chehab {
5310c0d06caSMauro Carvalho Chehab struct em28xx *dev = snd_kcontrol_chip(kcontrol);
53234906633SMauro Carvalho Chehab struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream;
53334906633SMauro Carvalho Chehab int nonblock = 0;
5340c0d06caSMauro Carvalho Chehab int val;
5350c0d06caSMauro Carvalho Chehab
5368b1fa579SMauro Carvalho Chehab if (dev->disconnected)
5378b1fa579SMauro Carvalho Chehab return -ENODEV;
5388b1fa579SMauro Carvalho Chehab
53934906633SMauro Carvalho Chehab if (substream)
54034906633SMauro Carvalho Chehab nonblock = !!(substream->f_flags & O_NONBLOCK);
54134906633SMauro Carvalho Chehab if (nonblock) {
54234906633SMauro Carvalho Chehab if (!mutex_trylock(&dev->lock))
54334906633SMauro Carvalho Chehab return -EAGAIN;
5449f90f537SMauro Carvalho Chehab } else {
5450c0d06caSMauro Carvalho Chehab mutex_lock(&dev->lock);
5469f90f537SMauro Carvalho Chehab }
5470c0d06caSMauro Carvalho Chehab val = em28xx_read_ac97(dev, kcontrol->private_value);
5480c0d06caSMauro Carvalho Chehab mutex_unlock(&dev->lock);
5490c0d06caSMauro Carvalho Chehab if (val < 0)
5500c0d06caSMauro Carvalho Chehab return val;
5510c0d06caSMauro Carvalho Chehab
5520c0d06caSMauro Carvalho Chehab if (val & 0x8000)
5530c0d06caSMauro Carvalho Chehab value->value.integer.value[0] = 0;
5540c0d06caSMauro Carvalho Chehab else
5550c0d06caSMauro Carvalho Chehab value->value.integer.value[0] = 1;
5560c0d06caSMauro Carvalho Chehab
5570c0d06caSMauro Carvalho Chehab dprintk("%sleft vol %d, right vol %d (0x%04x) from ac97 volume control 0x%04x\n",
5580c0d06caSMauro Carvalho Chehab (val & 0x8000) ? "muted " : "",
5590c0d06caSMauro Carvalho Chehab 0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f),
5600c0d06caSMauro Carvalho Chehab val, (int)kcontrol->private_value);
5610c0d06caSMauro Carvalho Chehab
5620c0d06caSMauro Carvalho Chehab return 0;
5630c0d06caSMauro Carvalho Chehab }
5640c0d06caSMauro Carvalho Chehab
5650c0d06caSMauro Carvalho Chehab static const DECLARE_TLV_DB_SCALE(em28xx_db_scale, -3450, 150, 0);
5660c0d06caSMauro Carvalho Chehab
em28xx_cvol_new(struct snd_card * card,struct em28xx * dev,char * name,int id)5670c0d06caSMauro Carvalho Chehab static int em28xx_cvol_new(struct snd_card *card, struct em28xx *dev,
5680c0d06caSMauro Carvalho Chehab char *name, int id)
5690c0d06caSMauro Carvalho Chehab {
5700c0d06caSMauro Carvalho Chehab int err;
5710c0d06caSMauro Carvalho Chehab char ctl_name[44];
5720c0d06caSMauro Carvalho Chehab struct snd_kcontrol *kctl;
5730c0d06caSMauro Carvalho Chehab struct snd_kcontrol_new tmp;
5740c0d06caSMauro Carvalho Chehab
5750c0d06caSMauro Carvalho Chehab memset(&tmp, 0, sizeof(tmp));
576*973c960dSJulia Lawall tmp.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
577*973c960dSJulia Lawall tmp.private_value = id;
578*973c960dSJulia Lawall tmp.name = ctl_name;
5790c0d06caSMauro Carvalho Chehab
5800c0d06caSMauro Carvalho Chehab /* Add Mute Control */
5810c0d06caSMauro Carvalho Chehab sprintf(ctl_name, "%s Switch", name);
5820c0d06caSMauro Carvalho Chehab tmp.get = em28xx_vol_get_mute;
5830c0d06caSMauro Carvalho Chehab tmp.put = em28xx_vol_put_mute;
5840c0d06caSMauro Carvalho Chehab tmp.info = snd_ctl_boolean_mono_info;
5850c0d06caSMauro Carvalho Chehab kctl = snd_ctl_new1(&tmp, dev);
5860c0d06caSMauro Carvalho Chehab err = snd_ctl_add(card, kctl);
5870c0d06caSMauro Carvalho Chehab if (err < 0)
5880c0d06caSMauro Carvalho Chehab return err;
5890c0d06caSMauro Carvalho Chehab dprintk("Added control %s for ac97 volume control 0x%04x\n",
5900c0d06caSMauro Carvalho Chehab ctl_name, id);
5910c0d06caSMauro Carvalho Chehab
5920c0d06caSMauro Carvalho Chehab memset(&tmp, 0, sizeof(tmp));
593*973c960dSJulia Lawall tmp.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
594*973c960dSJulia Lawall tmp.private_value = id;
595*973c960dSJulia Lawall tmp.name = ctl_name;
5960c0d06caSMauro Carvalho Chehab
5970c0d06caSMauro Carvalho Chehab /* Add Volume Control */
5980c0d06caSMauro Carvalho Chehab sprintf(ctl_name, "%s Volume", name);
5990c0d06caSMauro Carvalho Chehab tmp.get = em28xx_vol_get;
6000c0d06caSMauro Carvalho Chehab tmp.put = em28xx_vol_put;
6010c0d06caSMauro Carvalho Chehab tmp.info = em28xx_vol_info;
602*973c960dSJulia Lawall tmp.tlv.p = em28xx_db_scale;
6030c0d06caSMauro Carvalho Chehab kctl = snd_ctl_new1(&tmp, dev);
6040c0d06caSMauro Carvalho Chehab err = snd_ctl_add(card, kctl);
6050c0d06caSMauro Carvalho Chehab if (err < 0)
6060c0d06caSMauro Carvalho Chehab return err;
6070c0d06caSMauro Carvalho Chehab dprintk("Added control %s for ac97 volume control 0x%04x\n",
6080c0d06caSMauro Carvalho Chehab ctl_name, id);
6090c0d06caSMauro Carvalho Chehab
6100c0d06caSMauro Carvalho Chehab return 0;
6110c0d06caSMauro Carvalho Chehab }
6120c0d06caSMauro Carvalho Chehab
6130c0d06caSMauro Carvalho Chehab /*
6140c0d06caSMauro Carvalho Chehab * register/unregister code and data
6150c0d06caSMauro Carvalho Chehab */
61622511cfaSJulia Lawall static const struct snd_pcm_ops snd_em28xx_pcm_capture = {
6170c0d06caSMauro Carvalho Chehab .open = snd_em28xx_capture_open,
6180c0d06caSMauro Carvalho Chehab .close = snd_em28xx_pcm_close,
6190c0d06caSMauro Carvalho Chehab .prepare = snd_em28xx_prepare,
6200c0d06caSMauro Carvalho Chehab .trigger = snd_em28xx_capture_trigger,
6210c0d06caSMauro Carvalho Chehab .pointer = snd_em28xx_capture_pointer,
6220c0d06caSMauro Carvalho Chehab };
6230c0d06caSMauro Carvalho Chehab
em28xx_audio_free_urb(struct em28xx * dev)624f5f894d1SMauro Carvalho Chehab static void em28xx_audio_free_urb(struct em28xx *dev)
625f5f894d1SMauro Carvalho Chehab {
626c6d48134SMauro Carvalho Chehab struct usb_device *udev = interface_to_usbdev(dev->intf);
627f5f894d1SMauro Carvalho Chehab int i;
628f5f894d1SMauro Carvalho Chehab
6291b3fd2d3SMauro Carvalho Chehab for (i = 0; i < dev->adev.num_urb; i++) {
630f5f894d1SMauro Carvalho Chehab struct urb *urb = dev->adev.urb[i];
631f5f894d1SMauro Carvalho Chehab
6321b3fd2d3SMauro Carvalho Chehab if (!urb)
633f5f894d1SMauro Carvalho Chehab continue;
634f5f894d1SMauro Carvalho Chehab
635c6d48134SMauro Carvalho Chehab usb_free_coherent(udev, urb->transfer_buffer_length,
636f5f894d1SMauro Carvalho Chehab dev->adev.transfer_buffer[i],
637f5f894d1SMauro Carvalho Chehab urb->transfer_dma);
638f5f894d1SMauro Carvalho Chehab
639f5f894d1SMauro Carvalho Chehab usb_free_urb(urb);
640f5f894d1SMauro Carvalho Chehab }
6411b3fd2d3SMauro Carvalho Chehab kfree(dev->adev.urb);
6421b3fd2d3SMauro Carvalho Chehab kfree(dev->adev.transfer_buffer);
6431b3fd2d3SMauro Carvalho Chehab dev->adev.num_urb = 0;
6441b3fd2d3SMauro Carvalho Chehab }
6451b3fd2d3SMauro Carvalho Chehab
6461b3fd2d3SMauro Carvalho Chehab /* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
em28xx_audio_ep_packet_size(struct usb_device * udev,struct usb_endpoint_descriptor * e)6471b3fd2d3SMauro Carvalho Chehab static int em28xx_audio_ep_packet_size(struct usb_device *udev,
6481b3fd2d3SMauro Carvalho Chehab struct usb_endpoint_descriptor *e)
6491b3fd2d3SMauro Carvalho Chehab {
6501b3fd2d3SMauro Carvalho Chehab int size = le16_to_cpu(e->wMaxPacketSize);
6511b3fd2d3SMauro Carvalho Chehab
6521b3fd2d3SMauro Carvalho Chehab if (udev->speed == USB_SPEED_HIGH)
6531b3fd2d3SMauro Carvalho Chehab return (size & 0x7ff) * (1 + (((size) >> 11) & 0x03));
6541b3fd2d3SMauro Carvalho Chehab
6551b3fd2d3SMauro Carvalho Chehab return size & 0x7ff;
656f5f894d1SMauro Carvalho Chehab }
657f5f894d1SMauro Carvalho Chehab
em28xx_audio_urb_init(struct em28xx * dev)658966f4163SMauro Carvalho Chehab static int em28xx_audio_urb_init(struct em28xx *dev)
659966f4163SMauro Carvalho Chehab {
660966f4163SMauro Carvalho Chehab struct usb_interface *intf;
661966f4163SMauro Carvalho Chehab struct usb_endpoint_descriptor *e, *ep = NULL;
662c6d48134SMauro Carvalho Chehab struct usb_device *udev = interface_to_usbdev(dev->intf);
663966f4163SMauro Carvalho Chehab int i, ep_size, interval, num_urb, npackets;
664966f4163SMauro Carvalho Chehab int urb_size, bytes_per_transfer;
665966f4163SMauro Carvalho Chehab u8 alt;
666966f4163SMauro Carvalho Chehab
667961717b4SFrank Schaefer if (dev->ifnum)
668966f4163SMauro Carvalho Chehab alt = 1;
669966f4163SMauro Carvalho Chehab else
670966f4163SMauro Carvalho Chehab alt = 7;
671966f4163SMauro Carvalho Chehab
672c6d48134SMauro Carvalho Chehab intf = usb_ifnum_to_if(udev, dev->ifnum);
673966f4163SMauro Carvalho Chehab
674966f4163SMauro Carvalho Chehab if (intf->num_altsetting <= alt) {
67529b05e22SMauro Carvalho Chehab dev_err(&dev->intf->dev, "alt %d doesn't exist on interface %d\n",
676961717b4SFrank Schaefer dev->ifnum, alt);
677966f4163SMauro Carvalho Chehab return -ENODEV;
678966f4163SMauro Carvalho Chehab }
679966f4163SMauro Carvalho Chehab
680966f4163SMauro Carvalho Chehab for (i = 0; i < intf->altsetting[alt].desc.bNumEndpoints; i++) {
681966f4163SMauro Carvalho Chehab e = &intf->altsetting[alt].endpoint[i].desc;
682966f4163SMauro Carvalho Chehab if (!usb_endpoint_dir_in(e))
683966f4163SMauro Carvalho Chehab continue;
684966f4163SMauro Carvalho Chehab if (e->bEndpointAddress == EM28XX_EP_AUDIO) {
685966f4163SMauro Carvalho Chehab ep = e;
686966f4163SMauro Carvalho Chehab break;
687966f4163SMauro Carvalho Chehab }
688966f4163SMauro Carvalho Chehab }
689966f4163SMauro Carvalho Chehab
690966f4163SMauro Carvalho Chehab if (!ep) {
69129b05e22SMauro Carvalho Chehab dev_err(&dev->intf->dev, "Couldn't find an audio endpoint");
692966f4163SMauro Carvalho Chehab return -ENODEV;
693966f4163SMauro Carvalho Chehab }
694966f4163SMauro Carvalho Chehab
695c6d48134SMauro Carvalho Chehab ep_size = em28xx_audio_ep_packet_size(udev, ep);
696966f4163SMauro Carvalho Chehab interval = 1 << (ep->bInterval - 1);
697966f4163SMauro Carvalho Chehab
69829b05e22SMauro Carvalho Chehab dev_info(&dev->intf->dev,
699ce8591ffSMauro Carvalho Chehab "Endpoint 0x%02x %s on intf %d alt %d interval = %d, size %d\n",
700c6d48134SMauro Carvalho Chehab EM28XX_EP_AUDIO, usb_speed_string(udev->speed),
701ce8591ffSMauro Carvalho Chehab dev->ifnum, alt, interval, ep_size);
702966f4163SMauro Carvalho Chehab
703966f4163SMauro Carvalho Chehab /* Calculate the number and size of URBs to better fit the audio samples */
704966f4163SMauro Carvalho Chehab
705966f4163SMauro Carvalho Chehab /*
706966f4163SMauro Carvalho Chehab * Estimate the number of bytes per DMA transfer.
707966f4163SMauro Carvalho Chehab *
708966f4163SMauro Carvalho Chehab * This is given by the bit rate (for now, only 48000 Hz) multiplied
709966f4163SMauro Carvalho Chehab * by 2 channels and 2 bytes/sample divided by the number of microframe
710966f4163SMauro Carvalho Chehab * intervals and by the microframe rate (125 us)
711966f4163SMauro Carvalho Chehab */
712966f4163SMauro Carvalho Chehab bytes_per_transfer = DIV_ROUND_UP(48000 * 2 * 2, 125 * interval);
713966f4163SMauro Carvalho Chehab
714966f4163SMauro Carvalho Chehab /*
715966f4163SMauro Carvalho Chehab * Estimate the number of transfer URBs. Don't let it go past the
716966f4163SMauro Carvalho Chehab * maximum number of URBs that is known to be supported by the device.
717966f4163SMauro Carvalho Chehab */
718966f4163SMauro Carvalho Chehab num_urb = DIV_ROUND_UP(bytes_per_transfer, ep_size);
719966f4163SMauro Carvalho Chehab if (num_urb > EM28XX_MAX_AUDIO_BUFS)
720966f4163SMauro Carvalho Chehab num_urb = EM28XX_MAX_AUDIO_BUFS;
721966f4163SMauro Carvalho Chehab
722966f4163SMauro Carvalho Chehab /*
723966f4163SMauro Carvalho Chehab * Now that we know the number of bytes per transfer and the number of
724966f4163SMauro Carvalho Chehab * URBs, estimate the typical size of an URB, in order to adjust the
725966f4163SMauro Carvalho Chehab * minimal number of packets.
726966f4163SMauro Carvalho Chehab */
727966f4163SMauro Carvalho Chehab urb_size = bytes_per_transfer / num_urb;
728966f4163SMauro Carvalho Chehab
729966f4163SMauro Carvalho Chehab /*
730966f4163SMauro Carvalho Chehab * Now, calculate the amount of audio packets to be filled on each
731966f4163SMauro Carvalho Chehab * URB. In order to preserve the old behaviour, use a minimal
732966f4163SMauro Carvalho Chehab * threshold for this value.
733966f4163SMauro Carvalho Chehab */
734966f4163SMauro Carvalho Chehab npackets = EM28XX_MIN_AUDIO_PACKETS;
735966f4163SMauro Carvalho Chehab if (urb_size > ep_size * npackets)
736966f4163SMauro Carvalho Chehab npackets = DIV_ROUND_UP(urb_size, ep_size);
737966f4163SMauro Carvalho Chehab
73829b05e22SMauro Carvalho Chehab dev_info(&dev->intf->dev,
739ce8591ffSMauro Carvalho Chehab "Number of URBs: %d, with %d packets and %d size\n",
740966f4163SMauro Carvalho Chehab num_urb, npackets, urb_size);
741966f4163SMauro Carvalho Chehab
742a02b9c23SMauro Carvalho Chehab /* Estimate the bytes per period */
743a02b9c23SMauro Carvalho Chehab dev->adev.period = urb_size * npackets;
744a02b9c23SMauro Carvalho Chehab
745966f4163SMauro Carvalho Chehab /* Allocate space to store the number of URBs to be used */
746966f4163SMauro Carvalho Chehab
747966f4163SMauro Carvalho Chehab dev->adev.transfer_buffer = kcalloc(num_urb,
748966f4163SMauro Carvalho Chehab sizeof(*dev->adev.transfer_buffer),
749fc8af4fbSSebastian Andrzej Siewior GFP_KERNEL);
7509f90f537SMauro Carvalho Chehab if (!dev->adev.transfer_buffer)
751966f4163SMauro Carvalho Chehab return -ENOMEM;
752966f4163SMauro Carvalho Chehab
753fc8af4fbSSebastian Andrzej Siewior dev->adev.urb = kcalloc(num_urb, sizeof(*dev->adev.urb), GFP_KERNEL);
754966f4163SMauro Carvalho Chehab if (!dev->adev.urb) {
755966f4163SMauro Carvalho Chehab kfree(dev->adev.transfer_buffer);
756966f4163SMauro Carvalho Chehab return -ENOMEM;
757966f4163SMauro Carvalho Chehab }
758966f4163SMauro Carvalho Chehab
759966f4163SMauro Carvalho Chehab /* Alloc memory for each URB and for each transfer buffer */
760966f4163SMauro Carvalho Chehab dev->adev.num_urb = num_urb;
761966f4163SMauro Carvalho Chehab for (i = 0; i < num_urb; i++) {
762966f4163SMauro Carvalho Chehab struct urb *urb;
763966f4163SMauro Carvalho Chehab int j, k;
764966f4163SMauro Carvalho Chehab void *buf;
765966f4163SMauro Carvalho Chehab
766fc8af4fbSSebastian Andrzej Siewior urb = usb_alloc_urb(npackets, GFP_KERNEL);
767966f4163SMauro Carvalho Chehab if (!urb) {
768966f4163SMauro Carvalho Chehab em28xx_audio_free_urb(dev);
769966f4163SMauro Carvalho Chehab return -ENOMEM;
770966f4163SMauro Carvalho Chehab }
771966f4163SMauro Carvalho Chehab dev->adev.urb[i] = urb;
772966f4163SMauro Carvalho Chehab
773fc8af4fbSSebastian Andrzej Siewior buf = usb_alloc_coherent(udev, npackets * ep_size, GFP_KERNEL,
774966f4163SMauro Carvalho Chehab &urb->transfer_dma);
775966f4163SMauro Carvalho Chehab if (!buf) {
77629b05e22SMauro Carvalho Chehab dev_err(&dev->intf->dev,
777ce8591ffSMauro Carvalho Chehab "usb_alloc_coherent failed!\n");
778966f4163SMauro Carvalho Chehab em28xx_audio_free_urb(dev);
779966f4163SMauro Carvalho Chehab return -ENOMEM;
780966f4163SMauro Carvalho Chehab }
781966f4163SMauro Carvalho Chehab dev->adev.transfer_buffer[i] = buf;
782966f4163SMauro Carvalho Chehab
783c6d48134SMauro Carvalho Chehab urb->dev = udev;
784966f4163SMauro Carvalho Chehab urb->context = dev;
785c6d48134SMauro Carvalho Chehab urb->pipe = usb_rcvisocpipe(udev, EM28XX_EP_AUDIO);
786966f4163SMauro Carvalho Chehab urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
787966f4163SMauro Carvalho Chehab urb->transfer_buffer = buf;
788966f4163SMauro Carvalho Chehab urb->interval = interval;
789966f4163SMauro Carvalho Chehab urb->complete = em28xx_audio_isocirq;
790966f4163SMauro Carvalho Chehab urb->number_of_packets = npackets;
791966f4163SMauro Carvalho Chehab urb->transfer_buffer_length = ep_size * npackets;
792966f4163SMauro Carvalho Chehab
793966f4163SMauro Carvalho Chehab for (j = k = 0; j < npackets; j++, k += ep_size) {
794966f4163SMauro Carvalho Chehab urb->iso_frame_desc[j].offset = k;
795966f4163SMauro Carvalho Chehab urb->iso_frame_desc[j].length = ep_size;
796966f4163SMauro Carvalho Chehab }
797966f4163SMauro Carvalho Chehab }
798966f4163SMauro Carvalho Chehab
799966f4163SMauro Carvalho Chehab return 0;
800966f4163SMauro Carvalho Chehab }
801966f4163SMauro Carvalho Chehab
em28xx_audio_init(struct em28xx * dev)8020c0d06caSMauro Carvalho Chehab static int em28xx_audio_init(struct em28xx *dev)
8030c0d06caSMauro Carvalho Chehab {
8040c0d06caSMauro Carvalho Chehab struct em28xx_audio *adev = &dev->adev;
805c6d48134SMauro Carvalho Chehab struct usb_device *udev = interface_to_usbdev(dev->intf);
8060c0d06caSMauro Carvalho Chehab struct snd_pcm *pcm;
8070c0d06caSMauro Carvalho Chehab struct snd_card *card;
8080c0d06caSMauro Carvalho Chehab static int devnr;
809966f4163SMauro Carvalho Chehab int err;
8100c0d06caSMauro Carvalho Chehab
811c5874208SFrank Schaefer if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) {
8129f90f537SMauro Carvalho Chehab /*
8139f90f537SMauro Carvalho Chehab * This device does not support the extension (in this case
8149f90f537SMauro Carvalho Chehab * the device is expecting the snd-usb-audio module or
8159f90f537SMauro Carvalho Chehab * doesn't have analog audio support at all)
8169f90f537SMauro Carvalho Chehab */
8170c0d06caSMauro Carvalho Chehab return 0;
8180c0d06caSMauro Carvalho Chehab }
8190c0d06caSMauro Carvalho Chehab
82029b05e22SMauro Carvalho Chehab dev_info(&dev->intf->dev, "Binding audio extension\n");
8219634614fSMauro Carvalho Chehab
82247677e51SMauro Carvalho Chehab kref_get(&dev->ref);
82347677e51SMauro Carvalho Chehab
82429b05e22SMauro Carvalho Chehab dev_info(&dev->intf->dev,
825ce8591ffSMauro Carvalho Chehab "em28xx-audio.c: Copyright (C) 2006 Markus Rechberger\n");
82629b05e22SMauro Carvalho Chehab dev_info(&dev->intf->dev,
827ce8591ffSMauro Carvalho Chehab "em28xx-audio.c: Copyright (C) 2007-2016 Mauro Carvalho Chehab\n");
8280c0d06caSMauro Carvalho Chehab
82929b05e22SMauro Carvalho Chehab err = snd_card_new(&dev->intf->dev, index[devnr], "Em28xx Audio",
830e7356888STakashi Iwai THIS_MODULE, 0, &card);
8310c0d06caSMauro Carvalho Chehab if (err < 0)
8320c0d06caSMauro Carvalho Chehab return err;
8330c0d06caSMauro Carvalho Chehab
8340c0d06caSMauro Carvalho Chehab spin_lock_init(&adev->slock);
8351b3fd2d3SMauro Carvalho Chehab adev->sndcard = card;
836c6d48134SMauro Carvalho Chehab adev->udev = udev;
8371b3fd2d3SMauro Carvalho Chehab
8380c0d06caSMauro Carvalho Chehab err = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm);
8390cd03a0cSMauro Carvalho Chehab if (err < 0)
8400cd03a0cSMauro Carvalho Chehab goto card_free;
8410c0d06caSMauro Carvalho Chehab
8420c0d06caSMauro Carvalho Chehab snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture);
8432abb1b2dSTakashi Iwai snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0);
8440c0d06caSMauro Carvalho Chehab pcm->info_flags = 0;
8450c0d06caSMauro Carvalho Chehab pcm->private_data = dev;
846cc1e6315SMauro Carvalho Chehab strscpy(pcm->name, "Empia 28xx Capture", sizeof(pcm->name));
8470c0d06caSMauro Carvalho Chehab
848cc1e6315SMauro Carvalho Chehab strscpy(card->driver, "Em28xx-Audio", sizeof(card->driver));
849cc1e6315SMauro Carvalho Chehab strscpy(card->shortname, "Em28xx Audio", sizeof(card->shortname));
850cc1e6315SMauro Carvalho Chehab strscpy(card->longname, "Empia Em28xx Audio", sizeof(card->longname));
8510c0d06caSMauro Carvalho Chehab
852a5c075cfSFrank Schaefer INIT_WORK(&adev->wq_trigger, audio_trigger);
8530c0d06caSMauro Carvalho Chehab
8540c0d06caSMauro Carvalho Chehab if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
8550c0d06caSMauro Carvalho Chehab em28xx_cvol_new(card, dev, "Video", AC97_VIDEO);
8560c0d06caSMauro Carvalho Chehab em28xx_cvol_new(card, dev, "Line In", AC97_LINE);
8570c0d06caSMauro Carvalho Chehab em28xx_cvol_new(card, dev, "Phone", AC97_PHONE);
8580c0d06caSMauro Carvalho Chehab em28xx_cvol_new(card, dev, "Microphone", AC97_MIC);
8590c0d06caSMauro Carvalho Chehab em28xx_cvol_new(card, dev, "CD", AC97_CD);
8600c0d06caSMauro Carvalho Chehab em28xx_cvol_new(card, dev, "AUX", AC97_AUX);
8610c0d06caSMauro Carvalho Chehab em28xx_cvol_new(card, dev, "PCM", AC97_PCM);
8620c0d06caSMauro Carvalho Chehab
8630c0d06caSMauro Carvalho Chehab em28xx_cvol_new(card, dev, "Master", AC97_MASTER);
8640c0d06caSMauro Carvalho Chehab em28xx_cvol_new(card, dev, "Line", AC97_HEADPHONE);
8650c0d06caSMauro Carvalho Chehab em28xx_cvol_new(card, dev, "Mono", AC97_MASTER_MONO);
8660c0d06caSMauro Carvalho Chehab em28xx_cvol_new(card, dev, "LFE", AC97_CENTER_LFE_MASTER);
8670c0d06caSMauro Carvalho Chehab em28xx_cvol_new(card, dev, "Surround", AC97_SURROUND_MASTER);
8680c0d06caSMauro Carvalho Chehab }
8690c0d06caSMauro Carvalho Chehab
870966f4163SMauro Carvalho Chehab err = em28xx_audio_urb_init(dev);
8710cd03a0cSMauro Carvalho Chehab if (err)
8720cd03a0cSMauro Carvalho Chehab goto card_free;
873d2849fa5SMauro Carvalho Chehab
8740c0d06caSMauro Carvalho Chehab err = snd_card_register(card);
8750cd03a0cSMauro Carvalho Chehab if (err < 0)
8760cd03a0cSMauro Carvalho Chehab goto urb_free;
8770c0d06caSMauro Carvalho Chehab
87829b05e22SMauro Carvalho Chehab dev_info(&dev->intf->dev, "Audio extension successfully initialized\n");
8790c0d06caSMauro Carvalho Chehab return 0;
8800cd03a0cSMauro Carvalho Chehab
8810cd03a0cSMauro Carvalho Chehab urb_free:
8820cd03a0cSMauro Carvalho Chehab em28xx_audio_free_urb(dev);
8830cd03a0cSMauro Carvalho Chehab
8840cd03a0cSMauro Carvalho Chehab card_free:
8850cd03a0cSMauro Carvalho Chehab snd_card_free(card);
886452f236fSMauro Carvalho Chehab adev->sndcard = NULL;
8870cd03a0cSMauro Carvalho Chehab
8880cd03a0cSMauro Carvalho Chehab return err;
8890c0d06caSMauro Carvalho Chehab }
8900c0d06caSMauro Carvalho Chehab
em28xx_audio_fini(struct em28xx * dev)8910c0d06caSMauro Carvalho Chehab static int em28xx_audio_fini(struct em28xx *dev)
8920c0d06caSMauro Carvalho Chehab {
8939f90f537SMauro Carvalho Chehab if (!dev)
8940c0d06caSMauro Carvalho Chehab return 0;
8950c0d06caSMauro Carvalho Chehab
896c5874208SFrank Schaefer if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) {
8979f90f537SMauro Carvalho Chehab /*
8989f90f537SMauro Carvalho Chehab * This device does not support the extension (in this case
8999f90f537SMauro Carvalho Chehab * the device is expecting the snd-usb-audio module or
9009f90f537SMauro Carvalho Chehab * doesn't have analog audio support at all)
9019f90f537SMauro Carvalho Chehab */
9020c0d06caSMauro Carvalho Chehab return 0;
9030c0d06caSMauro Carvalho Chehab }
9040c0d06caSMauro Carvalho Chehab
90529b05e22SMauro Carvalho Chehab dev_info(&dev->intf->dev, "Closing audio extension\n");
906aa929ad7SMauro Carvalho Chehab
907452f236fSMauro Carvalho Chehab if (dev->adev.sndcard) {
9081fe2e3bfSMauro Carvalho Chehab snd_card_disconnect(dev->adev.sndcard);
909a5c075cfSFrank Schaefer flush_work(&dev->adev.wq_trigger);
910b49eb2bdSMauro Carvalho Chehab
911f5f894d1SMauro Carvalho Chehab em28xx_audio_free_urb(dev);
912f5f894d1SMauro Carvalho Chehab
9130c0d06caSMauro Carvalho Chehab snd_card_free(dev->adev.sndcard);
9140c0d06caSMauro Carvalho Chehab dev->adev.sndcard = NULL;
9150c0d06caSMauro Carvalho Chehab }
9160c0d06caSMauro Carvalho Chehab
91747677e51SMauro Carvalho Chehab kref_put(&dev->ref, em28xx_free_device);
9180c0d06caSMauro Carvalho Chehab return 0;
9190c0d06caSMauro Carvalho Chehab }
9200c0d06caSMauro Carvalho Chehab
em28xx_audio_suspend(struct em28xx * dev)9216d746f91SShuah Khan static int em28xx_audio_suspend(struct em28xx *dev)
9226d746f91SShuah Khan {
9239f90f537SMauro Carvalho Chehab if (!dev)
9246d746f91SShuah Khan return 0;
9256d746f91SShuah Khan
926c5874208SFrank Schaefer if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR)
9276d746f91SShuah Khan return 0;
9286d746f91SShuah Khan
92929b05e22SMauro Carvalho Chehab dev_info(&dev->intf->dev, "Suspending audio extension\n");
9306d746f91SShuah Khan em28xx_deinit_isoc_audio(dev);
931a5c075cfSFrank Schaefer atomic_set(&dev->adev.stream_started, 0);
9326d746f91SShuah Khan return 0;
9336d746f91SShuah Khan }
9346d746f91SShuah Khan
em28xx_audio_resume(struct em28xx * dev)9356d746f91SShuah Khan static int em28xx_audio_resume(struct em28xx *dev)
9366d746f91SShuah Khan {
9379f90f537SMauro Carvalho Chehab if (!dev)
9386d746f91SShuah Khan return 0;
9396d746f91SShuah Khan
940c5874208SFrank Schaefer if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR)
9416d746f91SShuah Khan return 0;
9426d746f91SShuah Khan
94329b05e22SMauro Carvalho Chehab dev_info(&dev->intf->dev, "Resuming audio extension\n");
9446d746f91SShuah Khan /* Nothing to do other than schedule_work() ?? */
945a5c075cfSFrank Schaefer schedule_work(&dev->adev.wq_trigger);
9460c0d06caSMauro Carvalho Chehab return 0;
9470c0d06caSMauro Carvalho Chehab }
9480c0d06caSMauro Carvalho Chehab
9490c0d06caSMauro Carvalho Chehab static struct em28xx_ops audio_ops = {
9500c0d06caSMauro Carvalho Chehab .id = EM28XX_AUDIO,
9510c0d06caSMauro Carvalho Chehab .name = "Em28xx Audio Extension",
9520c0d06caSMauro Carvalho Chehab .init = em28xx_audio_init,
9530c0d06caSMauro Carvalho Chehab .fini = em28xx_audio_fini,
9546d746f91SShuah Khan .suspend = em28xx_audio_suspend,
9556d746f91SShuah Khan .resume = em28xx_audio_resume,
9560c0d06caSMauro Carvalho Chehab };
9570c0d06caSMauro Carvalho Chehab
em28xx_alsa_register(void)9580c0d06caSMauro Carvalho Chehab static int __init em28xx_alsa_register(void)
9590c0d06caSMauro Carvalho Chehab {
9600c0d06caSMauro Carvalho Chehab return em28xx_register_extension(&audio_ops);
9610c0d06caSMauro Carvalho Chehab }
9620c0d06caSMauro Carvalho Chehab
em28xx_alsa_unregister(void)9630c0d06caSMauro Carvalho Chehab static void __exit em28xx_alsa_unregister(void)
9640c0d06caSMauro Carvalho Chehab {
9650c0d06caSMauro Carvalho Chehab em28xx_unregister_extension(&audio_ops);
9660c0d06caSMauro Carvalho Chehab }
9670c0d06caSMauro Carvalho Chehab
968f22e9e71SMauro Carvalho Chehab MODULE_LICENSE("GPL v2");
9690c0d06caSMauro Carvalho Chehab MODULE_AUTHOR("Markus Rechberger <mrechberger@gmail.com>");
97037e59f87SMauro Carvalho Chehab MODULE_AUTHOR("Mauro Carvalho Chehab");
971d8992b09SMauro Carvalho Chehab MODULE_DESCRIPTION(DRIVER_DESC " - audio interface");
972d8992b09SMauro Carvalho Chehab MODULE_VERSION(EM28XX_VERSION);
9730c0d06caSMauro Carvalho Chehab
9740c0d06caSMauro Carvalho Chehab module_init(em28xx_alsa_register);
9750c0d06caSMauro Carvalho Chehab module_exit(em28xx_alsa_unregister);
976