18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 28c2ecf20Sopenharmony_ci// 38c2ecf20Sopenharmony_ci// Empiatech em28x1 audio extension 48c2ecf20Sopenharmony_ci// 58c2ecf20Sopenharmony_ci// Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com> 68c2ecf20Sopenharmony_ci// 78c2ecf20Sopenharmony_ci// Copyright (C) 2007-2016 Mauro Carvalho Chehab 88c2ecf20Sopenharmony_ci// - Port to work with the in-kernel driver 98c2ecf20Sopenharmony_ci// - Cleanups, fixes, alsa-controls, etc. 108c2ecf20Sopenharmony_ci// 118c2ecf20Sopenharmony_ci// This driver is based on my previous au600 usb pstn audio driver 128c2ecf20Sopenharmony_ci// and inherits all the copyrights 138c2ecf20Sopenharmony_ci// 148c2ecf20Sopenharmony_ci// This program is free software; you can redistribute it and/or modify 158c2ecf20Sopenharmony_ci// it under the terms of the GNU General Public License as published by 168c2ecf20Sopenharmony_ci// the Free Software Foundation; either version 2 of the License, or 178c2ecf20Sopenharmony_ci// (at your option) any later version. 188c2ecf20Sopenharmony_ci// 198c2ecf20Sopenharmony_ci// This program is distributed in the hope that it will be useful, 208c2ecf20Sopenharmony_ci// but WITHOUT ANY WARRANTY; without even the implied warranty of 218c2ecf20Sopenharmony_ci// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 228c2ecf20Sopenharmony_ci// GNU General Public License for more details. 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci#include "em28xx.h" 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci#include <linux/kernel.h> 278c2ecf20Sopenharmony_ci#include <linux/usb.h> 288c2ecf20Sopenharmony_ci#include <linux/init.h> 298c2ecf20Sopenharmony_ci#include <linux/sound.h> 308c2ecf20Sopenharmony_ci#include <linux/spinlock.h> 318c2ecf20Sopenharmony_ci#include <linux/soundcard.h> 328c2ecf20Sopenharmony_ci#include <linux/slab.h> 338c2ecf20Sopenharmony_ci#include <linux/module.h> 348c2ecf20Sopenharmony_ci#include <sound/core.h> 358c2ecf20Sopenharmony_ci#include <sound/pcm.h> 368c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 378c2ecf20Sopenharmony_ci#include <sound/info.h> 388c2ecf20Sopenharmony_ci#include <sound/initval.h> 398c2ecf20Sopenharmony_ci#include <sound/control.h> 408c2ecf20Sopenharmony_ci#include <sound/tlv.h> 418c2ecf20Sopenharmony_ci#include <sound/ac97_codec.h> 428c2ecf20Sopenharmony_ci#include <media/v4l2-common.h> 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic int debug; 458c2ecf20Sopenharmony_cimodule_param(debug, int, 0644); 468c2ecf20Sopenharmony_ciMODULE_PARM_DESC(debug, "activates debug info"); 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci#define EM28XX_MAX_AUDIO_BUFS 5 498c2ecf20Sopenharmony_ci#define EM28XX_MIN_AUDIO_PACKETS 64 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define dprintk(fmt, arg...) do { \ 528c2ecf20Sopenharmony_ci if (debug) \ 538c2ecf20Sopenharmony_ci dev_printk(KERN_DEBUG, &dev->intf->dev, \ 548c2ecf20Sopenharmony_ci "video: %s: " fmt, __func__, ## arg); \ 558c2ecf20Sopenharmony_ci} while (0) 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_cistatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic int em28xx_deinit_isoc_audio(struct em28xx *dev) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci int i; 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci dprintk("Stopping isoc\n"); 648c2ecf20Sopenharmony_ci for (i = 0; i < dev->adev.num_urb; i++) { 658c2ecf20Sopenharmony_ci struct urb *urb = dev->adev.urb[i]; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (!irqs_disabled()) 688c2ecf20Sopenharmony_ci usb_kill_urb(urb); 698c2ecf20Sopenharmony_ci else 708c2ecf20Sopenharmony_ci usb_unlink_urb(urb); 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci return 0; 748c2ecf20Sopenharmony_ci} 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_cistatic void em28xx_audio_isocirq(struct urb *urb) 778c2ecf20Sopenharmony_ci{ 788c2ecf20Sopenharmony_ci struct em28xx *dev = urb->context; 798c2ecf20Sopenharmony_ci int i; 808c2ecf20Sopenharmony_ci unsigned int oldptr; 818c2ecf20Sopenharmony_ci int period_elapsed = 0; 828c2ecf20Sopenharmony_ci int status; 838c2ecf20Sopenharmony_ci unsigned char *cp; 848c2ecf20Sopenharmony_ci unsigned int stride; 858c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream; 868c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime; 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci if (dev->disconnected) { 898c2ecf20Sopenharmony_ci dprintk("device disconnected while streaming. URB status=%d.\n", 908c2ecf20Sopenharmony_ci urb->status); 918c2ecf20Sopenharmony_ci atomic_set(&dev->adev.stream_started, 0); 928c2ecf20Sopenharmony_ci return; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci switch (urb->status) { 968c2ecf20Sopenharmony_ci case 0: /* success */ 978c2ecf20Sopenharmony_ci case -ETIMEDOUT: /* NAK */ 988c2ecf20Sopenharmony_ci break; 998c2ecf20Sopenharmony_ci case -ECONNRESET: /* kill */ 1008c2ecf20Sopenharmony_ci case -ENOENT: 1018c2ecf20Sopenharmony_ci case -ESHUTDOWN: 1028c2ecf20Sopenharmony_ci return; 1038c2ecf20Sopenharmony_ci default: /* error */ 1048c2ecf20Sopenharmony_ci dprintk("urb completion error %d.\n", urb->status); 1058c2ecf20Sopenharmony_ci break; 1068c2ecf20Sopenharmony_ci } 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci if (atomic_read(&dev->adev.stream_started) == 0) 1098c2ecf20Sopenharmony_ci return; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci if (dev->adev.capture_pcm_substream) { 1128c2ecf20Sopenharmony_ci substream = dev->adev.capture_pcm_substream; 1138c2ecf20Sopenharmony_ci runtime = substream->runtime; 1148c2ecf20Sopenharmony_ci stride = runtime->frame_bits >> 3; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci for (i = 0; i < urb->number_of_packets; i++) { 1178c2ecf20Sopenharmony_ci unsigned long flags; 1188c2ecf20Sopenharmony_ci int length = 1198c2ecf20Sopenharmony_ci urb->iso_frame_desc[i].actual_length / stride; 1208c2ecf20Sopenharmony_ci cp = (unsigned char *)urb->transfer_buffer + 1218c2ecf20Sopenharmony_ci urb->iso_frame_desc[i].offset; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci if (!length) 1248c2ecf20Sopenharmony_ci continue; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci oldptr = dev->adev.hwptr_done_capture; 1278c2ecf20Sopenharmony_ci if (oldptr + length >= runtime->buffer_size) { 1288c2ecf20Sopenharmony_ci unsigned int cnt = 1298c2ecf20Sopenharmony_ci runtime->buffer_size - oldptr; 1308c2ecf20Sopenharmony_ci memcpy(runtime->dma_area + oldptr * stride, cp, 1318c2ecf20Sopenharmony_ci cnt * stride); 1328c2ecf20Sopenharmony_ci memcpy(runtime->dma_area, cp + cnt * stride, 1338c2ecf20Sopenharmony_ci length * stride - cnt * stride); 1348c2ecf20Sopenharmony_ci } else { 1358c2ecf20Sopenharmony_ci memcpy(runtime->dma_area + oldptr * stride, cp, 1368c2ecf20Sopenharmony_ci length * stride); 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci snd_pcm_stream_lock_irqsave(substream, flags); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci dev->adev.hwptr_done_capture += length; 1428c2ecf20Sopenharmony_ci if (dev->adev.hwptr_done_capture >= 1438c2ecf20Sopenharmony_ci runtime->buffer_size) 1448c2ecf20Sopenharmony_ci dev->adev.hwptr_done_capture -= 1458c2ecf20Sopenharmony_ci runtime->buffer_size; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci dev->adev.capture_transfer_done += length; 1488c2ecf20Sopenharmony_ci if (dev->adev.capture_transfer_done >= 1498c2ecf20Sopenharmony_ci runtime->period_size) { 1508c2ecf20Sopenharmony_ci dev->adev.capture_transfer_done -= 1518c2ecf20Sopenharmony_ci runtime->period_size; 1528c2ecf20Sopenharmony_ci period_elapsed = 1; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci snd_pcm_stream_unlock_irqrestore(substream, flags); 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci if (period_elapsed) 1588c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(substream); 1598c2ecf20Sopenharmony_ci } 1608c2ecf20Sopenharmony_ci urb->status = 0; 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci status = usb_submit_urb(urb, GFP_ATOMIC); 1638c2ecf20Sopenharmony_ci if (status < 0) 1648c2ecf20Sopenharmony_ci dev_err(&dev->intf->dev, 1658c2ecf20Sopenharmony_ci "resubmit of audio urb failed (error=%i)\n", 1668c2ecf20Sopenharmony_ci status); 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic int em28xx_init_audio_isoc(struct em28xx *dev) 1708c2ecf20Sopenharmony_ci{ 1718c2ecf20Sopenharmony_ci int i, err; 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci dprintk("Starting isoc transfers\n"); 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci /* Start streaming */ 1768c2ecf20Sopenharmony_ci for (i = 0; i < dev->adev.num_urb; i++) { 1778c2ecf20Sopenharmony_ci memset(dev->adev.transfer_buffer[i], 0x80, 1788c2ecf20Sopenharmony_ci dev->adev.urb[i]->transfer_buffer_length); 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci err = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC); 1818c2ecf20Sopenharmony_ci if (err) { 1828c2ecf20Sopenharmony_ci dev_err(&dev->intf->dev, 1838c2ecf20Sopenharmony_ci "submit of audio urb failed (error=%i)\n", 1848c2ecf20Sopenharmony_ci err); 1858c2ecf20Sopenharmony_ci em28xx_deinit_isoc_audio(dev); 1868c2ecf20Sopenharmony_ci atomic_set(&dev->adev.stream_started, 0); 1878c2ecf20Sopenharmony_ci return err; 1888c2ecf20Sopenharmony_ci } 1898c2ecf20Sopenharmony_ci } 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_ci return 0; 1928c2ecf20Sopenharmony_ci} 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware snd_em28xx_hw_capture = { 1958c2ecf20Sopenharmony_ci .info = SNDRV_PCM_INFO_BLOCK_TRANSFER | 1968c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP | 1978c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_INTERLEAVED | 1988c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_BATCH | 1998c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID, 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S16_LE, 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_48000, 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci .rate_min = 48000, 2068c2ecf20Sopenharmony_ci .rate_max = 48000, 2078c2ecf20Sopenharmony_ci .channels_min = 2, 2088c2ecf20Sopenharmony_ci .channels_max = 2, 2098c2ecf20Sopenharmony_ci .buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */ 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci /* 2128c2ecf20Sopenharmony_ci * The period is 12.288 bytes. Allow a 10% of variation along its 2138c2ecf20Sopenharmony_ci * value, in order to avoid overruns/underruns due to some clock 2148c2ecf20Sopenharmony_ci * drift. 2158c2ecf20Sopenharmony_ci * 2168c2ecf20Sopenharmony_ci * FIXME: This period assumes 64 packets, and a 48000 PCM rate. 2178c2ecf20Sopenharmony_ci * Calculate it dynamically. 2188c2ecf20Sopenharmony_ci */ 2198c2ecf20Sopenharmony_ci .period_bytes_min = 11059, 2208c2ecf20Sopenharmony_ci .period_bytes_max = 13516, 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ci .periods_min = 2, 2238c2ecf20Sopenharmony_ci .periods_max = 98, /* 12544, */ 2248c2ecf20Sopenharmony_ci}; 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic int snd_em28xx_capture_open(struct snd_pcm_substream *substream) 2278c2ecf20Sopenharmony_ci{ 2288c2ecf20Sopenharmony_ci struct em28xx *dev = snd_pcm_substream_chip(substream); 2298c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 2308c2ecf20Sopenharmony_ci int nonblock, ret = 0; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci if (!dev) { 2338c2ecf20Sopenharmony_ci pr_err("em28xx-audio: BUG: em28xx can't find device struct. Can't proceed with open\n"); 2348c2ecf20Sopenharmony_ci return -ENODEV; 2358c2ecf20Sopenharmony_ci } 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci if (dev->disconnected) 2388c2ecf20Sopenharmony_ci return -ENODEV; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci dprintk("opening device and trying to acquire exclusive lock\n"); 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci nonblock = !!(substream->f_flags & O_NONBLOCK); 2438c2ecf20Sopenharmony_ci if (nonblock) { 2448c2ecf20Sopenharmony_ci if (!mutex_trylock(&dev->lock)) 2458c2ecf20Sopenharmony_ci return -EAGAIN; 2468c2ecf20Sopenharmony_ci } else { 2478c2ecf20Sopenharmony_ci mutex_lock(&dev->lock); 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci runtime->hw = snd_em28xx_hw_capture; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci if (dev->adev.users == 0) { 2538c2ecf20Sopenharmony_ci if (!dev->alt || dev->is_audio_only) { 2548c2ecf20Sopenharmony_ci struct usb_device *udev; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci udev = interface_to_usbdev(dev->intf); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci if (dev->is_audio_only) 2598c2ecf20Sopenharmony_ci /* audio is on a separate interface */ 2608c2ecf20Sopenharmony_ci dev->alt = 1; 2618c2ecf20Sopenharmony_ci else 2628c2ecf20Sopenharmony_ci /* audio is on the same interface as video */ 2638c2ecf20Sopenharmony_ci dev->alt = 7; 2648c2ecf20Sopenharmony_ci /* 2658c2ecf20Sopenharmony_ci * FIXME: The intention seems to be to select 2668c2ecf20Sopenharmony_ci * the alt setting with the largest 2678c2ecf20Sopenharmony_ci * wMaxPacketSize for the video endpoint. 2688c2ecf20Sopenharmony_ci * At least dev->alt should be used instead, but 2698c2ecf20Sopenharmony_ci * we should probably not touch it at all if it 2708c2ecf20Sopenharmony_ci * is already >0, because wMaxPacketSize of the 2718c2ecf20Sopenharmony_ci * audio endpoints seems to be the same for all. 2728c2ecf20Sopenharmony_ci */ 2738c2ecf20Sopenharmony_ci dprintk("changing alternate number on interface %d to %d\n", 2748c2ecf20Sopenharmony_ci dev->ifnum, dev->alt); 2758c2ecf20Sopenharmony_ci usb_set_interface(udev, dev->ifnum, dev->alt); 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci /* Sets volume, mute, etc */ 2798c2ecf20Sopenharmony_ci dev->mute = 0; 2808c2ecf20Sopenharmony_ci ret = em28xx_audio_analog_set(dev); 2818c2ecf20Sopenharmony_ci if (ret < 0) 2828c2ecf20Sopenharmony_ci goto err; 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci kref_get(&dev->ref); 2868c2ecf20Sopenharmony_ci dev->adev.users++; 2878c2ecf20Sopenharmony_ci mutex_unlock(&dev->lock); 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_ci /* Dynamically adjust the period size */ 2908c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); 2918c2ecf20Sopenharmony_ci snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 2928c2ecf20Sopenharmony_ci dev->adev.period * 95 / 100, 2938c2ecf20Sopenharmony_ci dev->adev.period * 105 / 100); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci dev->adev.capture_pcm_substream = substream; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci return 0; 2988c2ecf20Sopenharmony_cierr: 2998c2ecf20Sopenharmony_ci mutex_unlock(&dev->lock); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci dev_err(&dev->intf->dev, 3028c2ecf20Sopenharmony_ci "Error while configuring em28xx mixer\n"); 3038c2ecf20Sopenharmony_ci return ret; 3048c2ecf20Sopenharmony_ci} 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic int snd_em28xx_pcm_close(struct snd_pcm_substream *substream) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci struct em28xx *dev = snd_pcm_substream_chip(substream); 3098c2ecf20Sopenharmony_ci 3108c2ecf20Sopenharmony_ci dprintk("closing device\n"); 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci dev->mute = 1; 3138c2ecf20Sopenharmony_ci mutex_lock(&dev->lock); 3148c2ecf20Sopenharmony_ci dev->adev.users--; 3158c2ecf20Sopenharmony_ci if (atomic_read(&dev->adev.stream_started) > 0) { 3168c2ecf20Sopenharmony_ci atomic_set(&dev->adev.stream_started, 0); 3178c2ecf20Sopenharmony_ci schedule_work(&dev->adev.wq_trigger); 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci em28xx_audio_analog_set(dev); 3218c2ecf20Sopenharmony_ci mutex_unlock(&dev->lock); 3228c2ecf20Sopenharmony_ci kref_put(&dev->ref, em28xx_free_device); 3238c2ecf20Sopenharmony_ci 3248c2ecf20Sopenharmony_ci return 0; 3258c2ecf20Sopenharmony_ci} 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_cistatic int snd_em28xx_prepare(struct snd_pcm_substream *substream) 3288c2ecf20Sopenharmony_ci{ 3298c2ecf20Sopenharmony_ci struct em28xx *dev = snd_pcm_substream_chip(substream); 3308c2ecf20Sopenharmony_ci 3318c2ecf20Sopenharmony_ci if (dev->disconnected) 3328c2ecf20Sopenharmony_ci return -ENODEV; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci dev->adev.hwptr_done_capture = 0; 3358c2ecf20Sopenharmony_ci dev->adev.capture_transfer_done = 0; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci return 0; 3388c2ecf20Sopenharmony_ci} 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_cistatic void audio_trigger(struct work_struct *work) 3418c2ecf20Sopenharmony_ci{ 3428c2ecf20Sopenharmony_ci struct em28xx_audio *adev = 3438c2ecf20Sopenharmony_ci container_of(work, struct em28xx_audio, wq_trigger); 3448c2ecf20Sopenharmony_ci struct em28xx *dev = container_of(adev, struct em28xx, adev); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci if (atomic_read(&adev->stream_started)) { 3478c2ecf20Sopenharmony_ci dprintk("starting capture"); 3488c2ecf20Sopenharmony_ci em28xx_init_audio_isoc(dev); 3498c2ecf20Sopenharmony_ci } else { 3508c2ecf20Sopenharmony_ci dprintk("stopping capture"); 3518c2ecf20Sopenharmony_ci em28xx_deinit_isoc_audio(dev); 3528c2ecf20Sopenharmony_ci } 3538c2ecf20Sopenharmony_ci} 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_cistatic int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream, 3568c2ecf20Sopenharmony_ci int cmd) 3578c2ecf20Sopenharmony_ci{ 3588c2ecf20Sopenharmony_ci struct em28xx *dev = snd_pcm_substream_chip(substream); 3598c2ecf20Sopenharmony_ci int retval = 0; 3608c2ecf20Sopenharmony_ci 3618c2ecf20Sopenharmony_ci if (dev->disconnected) 3628c2ecf20Sopenharmony_ci return -ENODEV; 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci switch (cmd) { 3658c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 3668c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_RESUME: 3678c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 3688c2ecf20Sopenharmony_ci atomic_set(&dev->adev.stream_started, 1); 3698c2ecf20Sopenharmony_ci break; 3708c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 3718c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 3728c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 3738c2ecf20Sopenharmony_ci atomic_set(&dev->adev.stream_started, 0); 3748c2ecf20Sopenharmony_ci break; 3758c2ecf20Sopenharmony_ci default: 3768c2ecf20Sopenharmony_ci retval = -EINVAL; 3778c2ecf20Sopenharmony_ci } 3788c2ecf20Sopenharmony_ci schedule_work(&dev->adev.wq_trigger); 3798c2ecf20Sopenharmony_ci return retval; 3808c2ecf20Sopenharmony_ci} 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream 3838c2ecf20Sopenharmony_ci *substream) 3848c2ecf20Sopenharmony_ci{ 3858c2ecf20Sopenharmony_ci unsigned long flags; 3868c2ecf20Sopenharmony_ci struct em28xx *dev; 3878c2ecf20Sopenharmony_ci snd_pcm_uframes_t hwptr_done; 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci dev = snd_pcm_substream_chip(substream); 3908c2ecf20Sopenharmony_ci if (dev->disconnected) 3918c2ecf20Sopenharmony_ci return SNDRV_PCM_POS_XRUN; 3928c2ecf20Sopenharmony_ci 3938c2ecf20Sopenharmony_ci spin_lock_irqsave(&dev->adev.slock, flags); 3948c2ecf20Sopenharmony_ci hwptr_done = dev->adev.hwptr_done_capture; 3958c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&dev->adev.slock, flags); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci return hwptr_done; 3988c2ecf20Sopenharmony_ci} 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci/* 4018c2ecf20Sopenharmony_ci * AC97 volume control support 4028c2ecf20Sopenharmony_ci */ 4038c2ecf20Sopenharmony_cistatic int em28xx_vol_info(struct snd_kcontrol *kcontrol, 4048c2ecf20Sopenharmony_ci struct snd_ctl_elem_info *info) 4058c2ecf20Sopenharmony_ci{ 4068c2ecf20Sopenharmony_ci struct em28xx *dev = snd_kcontrol_chip(kcontrol); 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci if (dev->disconnected) 4098c2ecf20Sopenharmony_ci return -ENODEV; 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; 4128c2ecf20Sopenharmony_ci info->count = 2; 4138c2ecf20Sopenharmony_ci info->value.integer.min = 0; 4148c2ecf20Sopenharmony_ci info->value.integer.max = 0x1f; 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ci return 0; 4178c2ecf20Sopenharmony_ci} 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_cistatic int em28xx_vol_put(struct snd_kcontrol *kcontrol, 4208c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *value) 4218c2ecf20Sopenharmony_ci{ 4228c2ecf20Sopenharmony_ci struct em28xx *dev = snd_kcontrol_chip(kcontrol); 4238c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream; 4248c2ecf20Sopenharmony_ci u16 val = (0x1f - (value->value.integer.value[0] & 0x1f)) | 4258c2ecf20Sopenharmony_ci (0x1f - (value->value.integer.value[1] & 0x1f)) << 8; 4268c2ecf20Sopenharmony_ci int nonblock = 0; 4278c2ecf20Sopenharmony_ci int rc; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci if (dev->disconnected) 4308c2ecf20Sopenharmony_ci return -ENODEV; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci if (substream) 4338c2ecf20Sopenharmony_ci nonblock = !!(substream->f_flags & O_NONBLOCK); 4348c2ecf20Sopenharmony_ci if (nonblock) { 4358c2ecf20Sopenharmony_ci if (!mutex_trylock(&dev->lock)) 4368c2ecf20Sopenharmony_ci return -EAGAIN; 4378c2ecf20Sopenharmony_ci } else { 4388c2ecf20Sopenharmony_ci mutex_lock(&dev->lock); 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci rc = em28xx_read_ac97(dev, kcontrol->private_value); 4418c2ecf20Sopenharmony_ci if (rc < 0) 4428c2ecf20Sopenharmony_ci goto err; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci val |= rc & 0x8000; /* Preserve the mute flag */ 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci rc = em28xx_write_ac97(dev, kcontrol->private_value, val); 4478c2ecf20Sopenharmony_ci if (rc < 0) 4488c2ecf20Sopenharmony_ci goto err; 4498c2ecf20Sopenharmony_ci 4508c2ecf20Sopenharmony_ci dprintk("%sleft vol %d, right vol %d (0x%04x) to ac97 volume control 0x%04x\n", 4518c2ecf20Sopenharmony_ci (val & 0x8000) ? "muted " : "", 4528c2ecf20Sopenharmony_ci 0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f), 4538c2ecf20Sopenharmony_ci val, (int)kcontrol->private_value); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_cierr: 4568c2ecf20Sopenharmony_ci mutex_unlock(&dev->lock); 4578c2ecf20Sopenharmony_ci return rc; 4588c2ecf20Sopenharmony_ci} 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_cistatic int em28xx_vol_get(struct snd_kcontrol *kcontrol, 4618c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *value) 4628c2ecf20Sopenharmony_ci{ 4638c2ecf20Sopenharmony_ci struct em28xx *dev = snd_kcontrol_chip(kcontrol); 4648c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream; 4658c2ecf20Sopenharmony_ci int nonblock = 0; 4668c2ecf20Sopenharmony_ci int val; 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci if (dev->disconnected) 4698c2ecf20Sopenharmony_ci return -ENODEV; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci if (substream) 4728c2ecf20Sopenharmony_ci nonblock = !!(substream->f_flags & O_NONBLOCK); 4738c2ecf20Sopenharmony_ci if (nonblock) { 4748c2ecf20Sopenharmony_ci if (!mutex_trylock(&dev->lock)) 4758c2ecf20Sopenharmony_ci return -EAGAIN; 4768c2ecf20Sopenharmony_ci } else { 4778c2ecf20Sopenharmony_ci mutex_lock(&dev->lock); 4788c2ecf20Sopenharmony_ci } 4798c2ecf20Sopenharmony_ci val = em28xx_read_ac97(dev, kcontrol->private_value); 4808c2ecf20Sopenharmony_ci mutex_unlock(&dev->lock); 4818c2ecf20Sopenharmony_ci if (val < 0) 4828c2ecf20Sopenharmony_ci return val; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci dprintk("%sleft vol %d, right vol %d (0x%04x) from ac97 volume control 0x%04x\n", 4858c2ecf20Sopenharmony_ci (val & 0x8000) ? "muted " : "", 4868c2ecf20Sopenharmony_ci 0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f), 4878c2ecf20Sopenharmony_ci val, (int)kcontrol->private_value); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci value->value.integer.value[0] = 0x1f - (val & 0x1f); 4908c2ecf20Sopenharmony_ci value->value.integer.value[1] = 0x1f - ((val >> 8) & 0x1f); 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci return 0; 4938c2ecf20Sopenharmony_ci} 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_cistatic int em28xx_vol_put_mute(struct snd_kcontrol *kcontrol, 4968c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *value) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci struct em28xx *dev = snd_kcontrol_chip(kcontrol); 4998c2ecf20Sopenharmony_ci u16 val = value->value.integer.value[0]; 5008c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream; 5018c2ecf20Sopenharmony_ci int nonblock = 0; 5028c2ecf20Sopenharmony_ci int rc; 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci if (dev->disconnected) 5058c2ecf20Sopenharmony_ci return -ENODEV; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci if (substream) 5088c2ecf20Sopenharmony_ci nonblock = !!(substream->f_flags & O_NONBLOCK); 5098c2ecf20Sopenharmony_ci if (nonblock) { 5108c2ecf20Sopenharmony_ci if (!mutex_trylock(&dev->lock)) 5118c2ecf20Sopenharmony_ci return -EAGAIN; 5128c2ecf20Sopenharmony_ci } else { 5138c2ecf20Sopenharmony_ci mutex_lock(&dev->lock); 5148c2ecf20Sopenharmony_ci } 5158c2ecf20Sopenharmony_ci rc = em28xx_read_ac97(dev, kcontrol->private_value); 5168c2ecf20Sopenharmony_ci if (rc < 0) 5178c2ecf20Sopenharmony_ci goto err; 5188c2ecf20Sopenharmony_ci 5198c2ecf20Sopenharmony_ci if (val) 5208c2ecf20Sopenharmony_ci rc &= 0x1f1f; 5218c2ecf20Sopenharmony_ci else 5228c2ecf20Sopenharmony_ci rc |= 0x8000; 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci rc = em28xx_write_ac97(dev, kcontrol->private_value, rc); 5258c2ecf20Sopenharmony_ci if (rc < 0) 5268c2ecf20Sopenharmony_ci goto err; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci dprintk("%sleft vol %d, right vol %d (0x%04x) to ac97 volume control 0x%04x\n", 5298c2ecf20Sopenharmony_ci (val & 0x8000) ? "muted " : "", 5308c2ecf20Sopenharmony_ci 0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f), 5318c2ecf20Sopenharmony_ci val, (int)kcontrol->private_value); 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_cierr: 5348c2ecf20Sopenharmony_ci mutex_unlock(&dev->lock); 5358c2ecf20Sopenharmony_ci return rc; 5368c2ecf20Sopenharmony_ci} 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_cistatic int em28xx_vol_get_mute(struct snd_kcontrol *kcontrol, 5398c2ecf20Sopenharmony_ci struct snd_ctl_elem_value *value) 5408c2ecf20Sopenharmony_ci{ 5418c2ecf20Sopenharmony_ci struct em28xx *dev = snd_kcontrol_chip(kcontrol); 5428c2ecf20Sopenharmony_ci struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream; 5438c2ecf20Sopenharmony_ci int nonblock = 0; 5448c2ecf20Sopenharmony_ci int val; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci if (dev->disconnected) 5478c2ecf20Sopenharmony_ci return -ENODEV; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci if (substream) 5508c2ecf20Sopenharmony_ci nonblock = !!(substream->f_flags & O_NONBLOCK); 5518c2ecf20Sopenharmony_ci if (nonblock) { 5528c2ecf20Sopenharmony_ci if (!mutex_trylock(&dev->lock)) 5538c2ecf20Sopenharmony_ci return -EAGAIN; 5548c2ecf20Sopenharmony_ci } else { 5558c2ecf20Sopenharmony_ci mutex_lock(&dev->lock); 5568c2ecf20Sopenharmony_ci } 5578c2ecf20Sopenharmony_ci val = em28xx_read_ac97(dev, kcontrol->private_value); 5588c2ecf20Sopenharmony_ci mutex_unlock(&dev->lock); 5598c2ecf20Sopenharmony_ci if (val < 0) 5608c2ecf20Sopenharmony_ci return val; 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci if (val & 0x8000) 5638c2ecf20Sopenharmony_ci value->value.integer.value[0] = 0; 5648c2ecf20Sopenharmony_ci else 5658c2ecf20Sopenharmony_ci value->value.integer.value[0] = 1; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci dprintk("%sleft vol %d, right vol %d (0x%04x) from ac97 volume control 0x%04x\n", 5688c2ecf20Sopenharmony_ci (val & 0x8000) ? "muted " : "", 5698c2ecf20Sopenharmony_ci 0x1f - ((val >> 8) & 0x1f), 0x1f - (val & 0x1f), 5708c2ecf20Sopenharmony_ci val, (int)kcontrol->private_value); 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci return 0; 5738c2ecf20Sopenharmony_ci} 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_cistatic const DECLARE_TLV_DB_SCALE(em28xx_db_scale, -3450, 150, 0); 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_cistatic int em28xx_cvol_new(struct snd_card *card, struct em28xx *dev, 5788c2ecf20Sopenharmony_ci char *name, int id) 5798c2ecf20Sopenharmony_ci{ 5808c2ecf20Sopenharmony_ci int err; 5818c2ecf20Sopenharmony_ci char ctl_name[44]; 5828c2ecf20Sopenharmony_ci struct snd_kcontrol *kctl; 5838c2ecf20Sopenharmony_ci struct snd_kcontrol_new tmp; 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci memset(&tmp, 0, sizeof(tmp)); 5868c2ecf20Sopenharmony_ci tmp.iface = SNDRV_CTL_ELEM_IFACE_MIXER, 5878c2ecf20Sopenharmony_ci tmp.private_value = id, 5888c2ecf20Sopenharmony_ci tmp.name = ctl_name, 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci /* Add Mute Control */ 5918c2ecf20Sopenharmony_ci sprintf(ctl_name, "%s Switch", name); 5928c2ecf20Sopenharmony_ci tmp.get = em28xx_vol_get_mute; 5938c2ecf20Sopenharmony_ci tmp.put = em28xx_vol_put_mute; 5948c2ecf20Sopenharmony_ci tmp.info = snd_ctl_boolean_mono_info; 5958c2ecf20Sopenharmony_ci kctl = snd_ctl_new1(&tmp, dev); 5968c2ecf20Sopenharmony_ci err = snd_ctl_add(card, kctl); 5978c2ecf20Sopenharmony_ci if (err < 0) 5988c2ecf20Sopenharmony_ci return err; 5998c2ecf20Sopenharmony_ci dprintk("Added control %s for ac97 volume control 0x%04x\n", 6008c2ecf20Sopenharmony_ci ctl_name, id); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci memset(&tmp, 0, sizeof(tmp)); 6038c2ecf20Sopenharmony_ci tmp.iface = SNDRV_CTL_ELEM_IFACE_MIXER, 6048c2ecf20Sopenharmony_ci tmp.private_value = id, 6058c2ecf20Sopenharmony_ci tmp.name = ctl_name, 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_ci /* Add Volume Control */ 6088c2ecf20Sopenharmony_ci sprintf(ctl_name, "%s Volume", name); 6098c2ecf20Sopenharmony_ci tmp.get = em28xx_vol_get; 6108c2ecf20Sopenharmony_ci tmp.put = em28xx_vol_put; 6118c2ecf20Sopenharmony_ci tmp.info = em28xx_vol_info; 6128c2ecf20Sopenharmony_ci tmp.tlv.p = em28xx_db_scale, 6138c2ecf20Sopenharmony_ci kctl = snd_ctl_new1(&tmp, dev); 6148c2ecf20Sopenharmony_ci err = snd_ctl_add(card, kctl); 6158c2ecf20Sopenharmony_ci if (err < 0) 6168c2ecf20Sopenharmony_ci return err; 6178c2ecf20Sopenharmony_ci dprintk("Added control %s for ac97 volume control 0x%04x\n", 6188c2ecf20Sopenharmony_ci ctl_name, id); 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci return 0; 6218c2ecf20Sopenharmony_ci} 6228c2ecf20Sopenharmony_ci 6238c2ecf20Sopenharmony_ci/* 6248c2ecf20Sopenharmony_ci * register/unregister code and data 6258c2ecf20Sopenharmony_ci */ 6268c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_em28xx_pcm_capture = { 6278c2ecf20Sopenharmony_ci .open = snd_em28xx_capture_open, 6288c2ecf20Sopenharmony_ci .close = snd_em28xx_pcm_close, 6298c2ecf20Sopenharmony_ci .prepare = snd_em28xx_prepare, 6308c2ecf20Sopenharmony_ci .trigger = snd_em28xx_capture_trigger, 6318c2ecf20Sopenharmony_ci .pointer = snd_em28xx_capture_pointer, 6328c2ecf20Sopenharmony_ci}; 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_cistatic void em28xx_audio_free_urb(struct em28xx *dev) 6358c2ecf20Sopenharmony_ci{ 6368c2ecf20Sopenharmony_ci struct usb_device *udev = interface_to_usbdev(dev->intf); 6378c2ecf20Sopenharmony_ci int i; 6388c2ecf20Sopenharmony_ci 6398c2ecf20Sopenharmony_ci for (i = 0; i < dev->adev.num_urb; i++) { 6408c2ecf20Sopenharmony_ci struct urb *urb = dev->adev.urb[i]; 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_ci if (!urb) 6438c2ecf20Sopenharmony_ci continue; 6448c2ecf20Sopenharmony_ci 6458c2ecf20Sopenharmony_ci usb_free_coherent(udev, urb->transfer_buffer_length, 6468c2ecf20Sopenharmony_ci dev->adev.transfer_buffer[i], 6478c2ecf20Sopenharmony_ci urb->transfer_dma); 6488c2ecf20Sopenharmony_ci 6498c2ecf20Sopenharmony_ci usb_free_urb(urb); 6508c2ecf20Sopenharmony_ci } 6518c2ecf20Sopenharmony_ci kfree(dev->adev.urb); 6528c2ecf20Sopenharmony_ci kfree(dev->adev.transfer_buffer); 6538c2ecf20Sopenharmony_ci dev->adev.num_urb = 0; 6548c2ecf20Sopenharmony_ci} 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */ 6578c2ecf20Sopenharmony_cistatic int em28xx_audio_ep_packet_size(struct usb_device *udev, 6588c2ecf20Sopenharmony_ci struct usb_endpoint_descriptor *e) 6598c2ecf20Sopenharmony_ci{ 6608c2ecf20Sopenharmony_ci int size = le16_to_cpu(e->wMaxPacketSize); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci if (udev->speed == USB_SPEED_HIGH) 6638c2ecf20Sopenharmony_ci return (size & 0x7ff) * (1 + (((size) >> 11) & 0x03)); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci return size & 0x7ff; 6668c2ecf20Sopenharmony_ci} 6678c2ecf20Sopenharmony_ci 6688c2ecf20Sopenharmony_cistatic int em28xx_audio_urb_init(struct em28xx *dev) 6698c2ecf20Sopenharmony_ci{ 6708c2ecf20Sopenharmony_ci struct usb_interface *intf; 6718c2ecf20Sopenharmony_ci struct usb_endpoint_descriptor *e, *ep = NULL; 6728c2ecf20Sopenharmony_ci struct usb_device *udev = interface_to_usbdev(dev->intf); 6738c2ecf20Sopenharmony_ci int i, ep_size, interval, num_urb, npackets; 6748c2ecf20Sopenharmony_ci int urb_size, bytes_per_transfer; 6758c2ecf20Sopenharmony_ci u8 alt; 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci if (dev->ifnum) 6788c2ecf20Sopenharmony_ci alt = 1; 6798c2ecf20Sopenharmony_ci else 6808c2ecf20Sopenharmony_ci alt = 7; 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ci intf = usb_ifnum_to_if(udev, dev->ifnum); 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci if (intf->num_altsetting <= alt) { 6858c2ecf20Sopenharmony_ci dev_err(&dev->intf->dev, "alt %d doesn't exist on interface %d\n", 6868c2ecf20Sopenharmony_ci dev->ifnum, alt); 6878c2ecf20Sopenharmony_ci return -ENODEV; 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci for (i = 0; i < intf->altsetting[alt].desc.bNumEndpoints; i++) { 6918c2ecf20Sopenharmony_ci e = &intf->altsetting[alt].endpoint[i].desc; 6928c2ecf20Sopenharmony_ci if (!usb_endpoint_dir_in(e)) 6938c2ecf20Sopenharmony_ci continue; 6948c2ecf20Sopenharmony_ci if (e->bEndpointAddress == EM28XX_EP_AUDIO) { 6958c2ecf20Sopenharmony_ci ep = e; 6968c2ecf20Sopenharmony_ci break; 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci } 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci if (!ep) { 7018c2ecf20Sopenharmony_ci dev_err(&dev->intf->dev, "Couldn't find an audio endpoint"); 7028c2ecf20Sopenharmony_ci return -ENODEV; 7038c2ecf20Sopenharmony_ci } 7048c2ecf20Sopenharmony_ci 7058c2ecf20Sopenharmony_ci ep_size = em28xx_audio_ep_packet_size(udev, ep); 7068c2ecf20Sopenharmony_ci interval = 1 << (ep->bInterval - 1); 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci dev_info(&dev->intf->dev, 7098c2ecf20Sopenharmony_ci "Endpoint 0x%02x %s on intf %d alt %d interval = %d, size %d\n", 7108c2ecf20Sopenharmony_ci EM28XX_EP_AUDIO, usb_speed_string(udev->speed), 7118c2ecf20Sopenharmony_ci dev->ifnum, alt, interval, ep_size); 7128c2ecf20Sopenharmony_ci 7138c2ecf20Sopenharmony_ci /* Calculate the number and size of URBs to better fit the audio samples */ 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci /* 7168c2ecf20Sopenharmony_ci * Estimate the number of bytes per DMA transfer. 7178c2ecf20Sopenharmony_ci * 7188c2ecf20Sopenharmony_ci * This is given by the bit rate (for now, only 48000 Hz) multiplied 7198c2ecf20Sopenharmony_ci * by 2 channels and 2 bytes/sample divided by the number of microframe 7208c2ecf20Sopenharmony_ci * intervals and by the microframe rate (125 us) 7218c2ecf20Sopenharmony_ci */ 7228c2ecf20Sopenharmony_ci bytes_per_transfer = DIV_ROUND_UP(48000 * 2 * 2, 125 * interval); 7238c2ecf20Sopenharmony_ci 7248c2ecf20Sopenharmony_ci /* 7258c2ecf20Sopenharmony_ci * Estimate the number of transfer URBs. Don't let it go past the 7268c2ecf20Sopenharmony_ci * maximum number of URBs that is known to be supported by the device. 7278c2ecf20Sopenharmony_ci */ 7288c2ecf20Sopenharmony_ci num_urb = DIV_ROUND_UP(bytes_per_transfer, ep_size); 7298c2ecf20Sopenharmony_ci if (num_urb > EM28XX_MAX_AUDIO_BUFS) 7308c2ecf20Sopenharmony_ci num_urb = EM28XX_MAX_AUDIO_BUFS; 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci /* 7338c2ecf20Sopenharmony_ci * Now that we know the number of bytes per transfer and the number of 7348c2ecf20Sopenharmony_ci * URBs, estimate the typical size of an URB, in order to adjust the 7358c2ecf20Sopenharmony_ci * minimal number of packets. 7368c2ecf20Sopenharmony_ci */ 7378c2ecf20Sopenharmony_ci urb_size = bytes_per_transfer / num_urb; 7388c2ecf20Sopenharmony_ci 7398c2ecf20Sopenharmony_ci /* 7408c2ecf20Sopenharmony_ci * Now, calculate the amount of audio packets to be filled on each 7418c2ecf20Sopenharmony_ci * URB. In order to preserve the old behaviour, use a minimal 7428c2ecf20Sopenharmony_ci * threshold for this value. 7438c2ecf20Sopenharmony_ci */ 7448c2ecf20Sopenharmony_ci npackets = EM28XX_MIN_AUDIO_PACKETS; 7458c2ecf20Sopenharmony_ci if (urb_size > ep_size * npackets) 7468c2ecf20Sopenharmony_ci npackets = DIV_ROUND_UP(urb_size, ep_size); 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci dev_info(&dev->intf->dev, 7498c2ecf20Sopenharmony_ci "Number of URBs: %d, with %d packets and %d size\n", 7508c2ecf20Sopenharmony_ci num_urb, npackets, urb_size); 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci /* Estimate the bytes per period */ 7538c2ecf20Sopenharmony_ci dev->adev.period = urb_size * npackets; 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_ci /* Allocate space to store the number of URBs to be used */ 7568c2ecf20Sopenharmony_ci 7578c2ecf20Sopenharmony_ci dev->adev.transfer_buffer = kcalloc(num_urb, 7588c2ecf20Sopenharmony_ci sizeof(*dev->adev.transfer_buffer), 7598c2ecf20Sopenharmony_ci GFP_KERNEL); 7608c2ecf20Sopenharmony_ci if (!dev->adev.transfer_buffer) 7618c2ecf20Sopenharmony_ci return -ENOMEM; 7628c2ecf20Sopenharmony_ci 7638c2ecf20Sopenharmony_ci dev->adev.urb = kcalloc(num_urb, sizeof(*dev->adev.urb), GFP_KERNEL); 7648c2ecf20Sopenharmony_ci if (!dev->adev.urb) { 7658c2ecf20Sopenharmony_ci kfree(dev->adev.transfer_buffer); 7668c2ecf20Sopenharmony_ci return -ENOMEM; 7678c2ecf20Sopenharmony_ci } 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci /* Alloc memory for each URB and for each transfer buffer */ 7708c2ecf20Sopenharmony_ci dev->adev.num_urb = num_urb; 7718c2ecf20Sopenharmony_ci for (i = 0; i < num_urb; i++) { 7728c2ecf20Sopenharmony_ci struct urb *urb; 7738c2ecf20Sopenharmony_ci int j, k; 7748c2ecf20Sopenharmony_ci void *buf; 7758c2ecf20Sopenharmony_ci 7768c2ecf20Sopenharmony_ci urb = usb_alloc_urb(npackets, GFP_KERNEL); 7778c2ecf20Sopenharmony_ci if (!urb) { 7788c2ecf20Sopenharmony_ci em28xx_audio_free_urb(dev); 7798c2ecf20Sopenharmony_ci return -ENOMEM; 7808c2ecf20Sopenharmony_ci } 7818c2ecf20Sopenharmony_ci dev->adev.urb[i] = urb; 7828c2ecf20Sopenharmony_ci 7838c2ecf20Sopenharmony_ci buf = usb_alloc_coherent(udev, npackets * ep_size, GFP_KERNEL, 7848c2ecf20Sopenharmony_ci &urb->transfer_dma); 7858c2ecf20Sopenharmony_ci if (!buf) { 7868c2ecf20Sopenharmony_ci dev_err(&dev->intf->dev, 7878c2ecf20Sopenharmony_ci "usb_alloc_coherent failed!\n"); 7888c2ecf20Sopenharmony_ci em28xx_audio_free_urb(dev); 7898c2ecf20Sopenharmony_ci return -ENOMEM; 7908c2ecf20Sopenharmony_ci } 7918c2ecf20Sopenharmony_ci dev->adev.transfer_buffer[i] = buf; 7928c2ecf20Sopenharmony_ci 7938c2ecf20Sopenharmony_ci urb->dev = udev; 7948c2ecf20Sopenharmony_ci urb->context = dev; 7958c2ecf20Sopenharmony_ci urb->pipe = usb_rcvisocpipe(udev, EM28XX_EP_AUDIO); 7968c2ecf20Sopenharmony_ci urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP; 7978c2ecf20Sopenharmony_ci urb->transfer_buffer = buf; 7988c2ecf20Sopenharmony_ci urb->interval = interval; 7998c2ecf20Sopenharmony_ci urb->complete = em28xx_audio_isocirq; 8008c2ecf20Sopenharmony_ci urb->number_of_packets = npackets; 8018c2ecf20Sopenharmony_ci urb->transfer_buffer_length = ep_size * npackets; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci for (j = k = 0; j < npackets; j++, k += ep_size) { 8048c2ecf20Sopenharmony_ci urb->iso_frame_desc[j].offset = k; 8058c2ecf20Sopenharmony_ci urb->iso_frame_desc[j].length = ep_size; 8068c2ecf20Sopenharmony_ci } 8078c2ecf20Sopenharmony_ci } 8088c2ecf20Sopenharmony_ci 8098c2ecf20Sopenharmony_ci return 0; 8108c2ecf20Sopenharmony_ci} 8118c2ecf20Sopenharmony_ci 8128c2ecf20Sopenharmony_cistatic int em28xx_audio_init(struct em28xx *dev) 8138c2ecf20Sopenharmony_ci{ 8148c2ecf20Sopenharmony_ci struct em28xx_audio *adev = &dev->adev; 8158c2ecf20Sopenharmony_ci struct usb_device *udev = interface_to_usbdev(dev->intf); 8168c2ecf20Sopenharmony_ci struct snd_pcm *pcm; 8178c2ecf20Sopenharmony_ci struct snd_card *card; 8188c2ecf20Sopenharmony_ci static int devnr; 8198c2ecf20Sopenharmony_ci int err; 8208c2ecf20Sopenharmony_ci 8218c2ecf20Sopenharmony_ci if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) { 8228c2ecf20Sopenharmony_ci /* 8238c2ecf20Sopenharmony_ci * This device does not support the extension (in this case 8248c2ecf20Sopenharmony_ci * the device is expecting the snd-usb-audio module or 8258c2ecf20Sopenharmony_ci * doesn't have analog audio support at all) 8268c2ecf20Sopenharmony_ci */ 8278c2ecf20Sopenharmony_ci return 0; 8288c2ecf20Sopenharmony_ci } 8298c2ecf20Sopenharmony_ci 8308c2ecf20Sopenharmony_ci dev_info(&dev->intf->dev, "Binding audio extension\n"); 8318c2ecf20Sopenharmony_ci 8328c2ecf20Sopenharmony_ci kref_get(&dev->ref); 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci dev_info(&dev->intf->dev, 8358c2ecf20Sopenharmony_ci "em28xx-audio.c: Copyright (C) 2006 Markus Rechberger\n"); 8368c2ecf20Sopenharmony_ci dev_info(&dev->intf->dev, 8378c2ecf20Sopenharmony_ci "em28xx-audio.c: Copyright (C) 2007-2016 Mauro Carvalho Chehab\n"); 8388c2ecf20Sopenharmony_ci 8398c2ecf20Sopenharmony_ci err = snd_card_new(&dev->intf->dev, index[devnr], "Em28xx Audio", 8408c2ecf20Sopenharmony_ci THIS_MODULE, 0, &card); 8418c2ecf20Sopenharmony_ci if (err < 0) 8428c2ecf20Sopenharmony_ci return err; 8438c2ecf20Sopenharmony_ci 8448c2ecf20Sopenharmony_ci spin_lock_init(&adev->slock); 8458c2ecf20Sopenharmony_ci adev->sndcard = card; 8468c2ecf20Sopenharmony_ci adev->udev = udev; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci err = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm); 8498c2ecf20Sopenharmony_ci if (err < 0) 8508c2ecf20Sopenharmony_ci goto card_free; 8518c2ecf20Sopenharmony_ci 8528c2ecf20Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture); 8538c2ecf20Sopenharmony_ci snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, NULL, 0, 0); 8548c2ecf20Sopenharmony_ci pcm->info_flags = 0; 8558c2ecf20Sopenharmony_ci pcm->private_data = dev; 8568c2ecf20Sopenharmony_ci strscpy(pcm->name, "Empia 28xx Capture", sizeof(pcm->name)); 8578c2ecf20Sopenharmony_ci 8588c2ecf20Sopenharmony_ci strscpy(card->driver, "Em28xx-Audio", sizeof(card->driver)); 8598c2ecf20Sopenharmony_ci strscpy(card->shortname, "Em28xx Audio", sizeof(card->shortname)); 8608c2ecf20Sopenharmony_ci strscpy(card->longname, "Empia Em28xx Audio", sizeof(card->longname)); 8618c2ecf20Sopenharmony_ci 8628c2ecf20Sopenharmony_ci INIT_WORK(&adev->wq_trigger, audio_trigger); 8638c2ecf20Sopenharmony_ci 8648c2ecf20Sopenharmony_ci if (dev->audio_mode.ac97 != EM28XX_NO_AC97) { 8658c2ecf20Sopenharmony_ci em28xx_cvol_new(card, dev, "Video", AC97_VIDEO); 8668c2ecf20Sopenharmony_ci em28xx_cvol_new(card, dev, "Line In", AC97_LINE); 8678c2ecf20Sopenharmony_ci em28xx_cvol_new(card, dev, "Phone", AC97_PHONE); 8688c2ecf20Sopenharmony_ci em28xx_cvol_new(card, dev, "Microphone", AC97_MIC); 8698c2ecf20Sopenharmony_ci em28xx_cvol_new(card, dev, "CD", AC97_CD); 8708c2ecf20Sopenharmony_ci em28xx_cvol_new(card, dev, "AUX", AC97_AUX); 8718c2ecf20Sopenharmony_ci em28xx_cvol_new(card, dev, "PCM", AC97_PCM); 8728c2ecf20Sopenharmony_ci 8738c2ecf20Sopenharmony_ci em28xx_cvol_new(card, dev, "Master", AC97_MASTER); 8748c2ecf20Sopenharmony_ci em28xx_cvol_new(card, dev, "Line", AC97_HEADPHONE); 8758c2ecf20Sopenharmony_ci em28xx_cvol_new(card, dev, "Mono", AC97_MASTER_MONO); 8768c2ecf20Sopenharmony_ci em28xx_cvol_new(card, dev, "LFE", AC97_CENTER_LFE_MASTER); 8778c2ecf20Sopenharmony_ci em28xx_cvol_new(card, dev, "Surround", AC97_SURROUND_MASTER); 8788c2ecf20Sopenharmony_ci } 8798c2ecf20Sopenharmony_ci 8808c2ecf20Sopenharmony_ci err = em28xx_audio_urb_init(dev); 8818c2ecf20Sopenharmony_ci if (err) 8828c2ecf20Sopenharmony_ci goto card_free; 8838c2ecf20Sopenharmony_ci 8848c2ecf20Sopenharmony_ci err = snd_card_register(card); 8858c2ecf20Sopenharmony_ci if (err < 0) 8868c2ecf20Sopenharmony_ci goto urb_free; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci dev_info(&dev->intf->dev, "Audio extension successfully initialized\n"); 8898c2ecf20Sopenharmony_ci return 0; 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ciurb_free: 8928c2ecf20Sopenharmony_ci em28xx_audio_free_urb(dev); 8938c2ecf20Sopenharmony_ci 8948c2ecf20Sopenharmony_cicard_free: 8958c2ecf20Sopenharmony_ci snd_card_free(card); 8968c2ecf20Sopenharmony_ci adev->sndcard = NULL; 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci return err; 8998c2ecf20Sopenharmony_ci} 9008c2ecf20Sopenharmony_ci 9018c2ecf20Sopenharmony_cistatic int em28xx_audio_fini(struct em28xx *dev) 9028c2ecf20Sopenharmony_ci{ 9038c2ecf20Sopenharmony_ci if (!dev) 9048c2ecf20Sopenharmony_ci return 0; 9058c2ecf20Sopenharmony_ci 9068c2ecf20Sopenharmony_ci if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) { 9078c2ecf20Sopenharmony_ci /* 9088c2ecf20Sopenharmony_ci * This device does not support the extension (in this case 9098c2ecf20Sopenharmony_ci * the device is expecting the snd-usb-audio module or 9108c2ecf20Sopenharmony_ci * doesn't have analog audio support at all) 9118c2ecf20Sopenharmony_ci */ 9128c2ecf20Sopenharmony_ci return 0; 9138c2ecf20Sopenharmony_ci } 9148c2ecf20Sopenharmony_ci 9158c2ecf20Sopenharmony_ci dev_info(&dev->intf->dev, "Closing audio extension\n"); 9168c2ecf20Sopenharmony_ci 9178c2ecf20Sopenharmony_ci if (dev->adev.sndcard) { 9188c2ecf20Sopenharmony_ci snd_card_disconnect(dev->adev.sndcard); 9198c2ecf20Sopenharmony_ci flush_work(&dev->adev.wq_trigger); 9208c2ecf20Sopenharmony_ci 9218c2ecf20Sopenharmony_ci em28xx_audio_free_urb(dev); 9228c2ecf20Sopenharmony_ci 9238c2ecf20Sopenharmony_ci snd_card_free(dev->adev.sndcard); 9248c2ecf20Sopenharmony_ci dev->adev.sndcard = NULL; 9258c2ecf20Sopenharmony_ci } 9268c2ecf20Sopenharmony_ci 9278c2ecf20Sopenharmony_ci kref_put(&dev->ref, em28xx_free_device); 9288c2ecf20Sopenharmony_ci return 0; 9298c2ecf20Sopenharmony_ci} 9308c2ecf20Sopenharmony_ci 9318c2ecf20Sopenharmony_cistatic int em28xx_audio_suspend(struct em28xx *dev) 9328c2ecf20Sopenharmony_ci{ 9338c2ecf20Sopenharmony_ci if (!dev) 9348c2ecf20Sopenharmony_ci return 0; 9358c2ecf20Sopenharmony_ci 9368c2ecf20Sopenharmony_ci if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) 9378c2ecf20Sopenharmony_ci return 0; 9388c2ecf20Sopenharmony_ci 9398c2ecf20Sopenharmony_ci dev_info(&dev->intf->dev, "Suspending audio extension\n"); 9408c2ecf20Sopenharmony_ci em28xx_deinit_isoc_audio(dev); 9418c2ecf20Sopenharmony_ci atomic_set(&dev->adev.stream_started, 0); 9428c2ecf20Sopenharmony_ci return 0; 9438c2ecf20Sopenharmony_ci} 9448c2ecf20Sopenharmony_ci 9458c2ecf20Sopenharmony_cistatic int em28xx_audio_resume(struct em28xx *dev) 9468c2ecf20Sopenharmony_ci{ 9478c2ecf20Sopenharmony_ci if (!dev) 9488c2ecf20Sopenharmony_ci return 0; 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR) 9518c2ecf20Sopenharmony_ci return 0; 9528c2ecf20Sopenharmony_ci 9538c2ecf20Sopenharmony_ci dev_info(&dev->intf->dev, "Resuming audio extension\n"); 9548c2ecf20Sopenharmony_ci /* Nothing to do other than schedule_work() ?? */ 9558c2ecf20Sopenharmony_ci schedule_work(&dev->adev.wq_trigger); 9568c2ecf20Sopenharmony_ci return 0; 9578c2ecf20Sopenharmony_ci} 9588c2ecf20Sopenharmony_ci 9598c2ecf20Sopenharmony_cistatic struct em28xx_ops audio_ops = { 9608c2ecf20Sopenharmony_ci .id = EM28XX_AUDIO, 9618c2ecf20Sopenharmony_ci .name = "Em28xx Audio Extension", 9628c2ecf20Sopenharmony_ci .init = em28xx_audio_init, 9638c2ecf20Sopenharmony_ci .fini = em28xx_audio_fini, 9648c2ecf20Sopenharmony_ci .suspend = em28xx_audio_suspend, 9658c2ecf20Sopenharmony_ci .resume = em28xx_audio_resume, 9668c2ecf20Sopenharmony_ci}; 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_cistatic int __init em28xx_alsa_register(void) 9698c2ecf20Sopenharmony_ci{ 9708c2ecf20Sopenharmony_ci return em28xx_register_extension(&audio_ops); 9718c2ecf20Sopenharmony_ci} 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_cistatic void __exit em28xx_alsa_unregister(void) 9748c2ecf20Sopenharmony_ci{ 9758c2ecf20Sopenharmony_ci em28xx_unregister_extension(&audio_ops); 9768c2ecf20Sopenharmony_ci} 9778c2ecf20Sopenharmony_ci 9788c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 9798c2ecf20Sopenharmony_ciMODULE_AUTHOR("Markus Rechberger <mrechberger@gmail.com>"); 9808c2ecf20Sopenharmony_ciMODULE_AUTHOR("Mauro Carvalho Chehab"); 9818c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC " - audio interface"); 9828c2ecf20Sopenharmony_ciMODULE_VERSION(EM28XX_VERSION); 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_cimodule_init(em28xx_alsa_register); 9858c2ecf20Sopenharmony_cimodule_exit(em28xx_alsa_unregister); 986