18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci */ 48c2ecf20Sopenharmony_ci 58c2ecf20Sopenharmony_ci#include <linux/init.h> 68c2ecf20Sopenharmony_ci#include <linux/slab.h> 78c2ecf20Sopenharmony_ci#include <linux/bitrev.h> 88c2ecf20Sopenharmony_ci#include <linux/ratelimit.h> 98c2ecf20Sopenharmony_ci#include <linux/usb.h> 108c2ecf20Sopenharmony_ci#include <linux/usb/audio.h> 118c2ecf20Sopenharmony_ci#include <linux/usb/audio-v2.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <sound/core.h> 148c2ecf20Sopenharmony_ci#include <sound/pcm.h> 158c2ecf20Sopenharmony_ci#include <sound/pcm_params.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include "usbaudio.h" 188c2ecf20Sopenharmony_ci#include "card.h" 198c2ecf20Sopenharmony_ci#include "quirks.h" 208c2ecf20Sopenharmony_ci#include "debug.h" 218c2ecf20Sopenharmony_ci#include "endpoint.h" 228c2ecf20Sopenharmony_ci#include "helper.h" 238c2ecf20Sopenharmony_ci#include "pcm.h" 248c2ecf20Sopenharmony_ci#include "clock.h" 258c2ecf20Sopenharmony_ci#include "power.h" 268c2ecf20Sopenharmony_ci#include "media.h" 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci#define SUBSTREAM_FLAG_DATA_EP_STARTED 0 298c2ecf20Sopenharmony_ci#define SUBSTREAM_FLAG_SYNC_EP_STARTED 1 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci/* return the estimated delay based on USB frame counters */ 328c2ecf20Sopenharmony_cisnd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs, 338c2ecf20Sopenharmony_ci unsigned int rate) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci int current_frame_number; 368c2ecf20Sopenharmony_ci int frame_diff; 378c2ecf20Sopenharmony_ci int est_delay; 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci if (!subs->last_delay) 408c2ecf20Sopenharmony_ci return 0; /* short path */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci current_frame_number = usb_get_current_frame_number(subs->dev); 438c2ecf20Sopenharmony_ci /* 448c2ecf20Sopenharmony_ci * HCD implementations use different widths, use lower 8 bits. 458c2ecf20Sopenharmony_ci * The delay will be managed up to 256ms, which is more than 468c2ecf20Sopenharmony_ci * enough 478c2ecf20Sopenharmony_ci */ 488c2ecf20Sopenharmony_ci frame_diff = (current_frame_number - subs->last_frame_number) & 0xff; 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci /* Approximation based on number of samples per USB frame (ms), 518c2ecf20Sopenharmony_ci some truncation for 44.1 but the estimate is good enough */ 528c2ecf20Sopenharmony_ci est_delay = frame_diff * rate / 1000; 538c2ecf20Sopenharmony_ci if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) 548c2ecf20Sopenharmony_ci est_delay = subs->last_delay - est_delay; 558c2ecf20Sopenharmony_ci else 568c2ecf20Sopenharmony_ci est_delay = subs->last_delay + est_delay; 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_ci if (est_delay < 0) 598c2ecf20Sopenharmony_ci est_delay = 0; 608c2ecf20Sopenharmony_ci return est_delay; 618c2ecf20Sopenharmony_ci} 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci/* 648c2ecf20Sopenharmony_ci * return the current pcm pointer. just based on the hwptr_done value. 658c2ecf20Sopenharmony_ci */ 668c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream) 678c2ecf20Sopenharmony_ci{ 688c2ecf20Sopenharmony_ci struct snd_usb_substream *subs = substream->runtime->private_data; 698c2ecf20Sopenharmony_ci unsigned int hwptr_done; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_ci if (atomic_read(&subs->stream->chip->shutdown)) 728c2ecf20Sopenharmony_ci return SNDRV_PCM_POS_XRUN; 738c2ecf20Sopenharmony_ci spin_lock(&subs->lock); 748c2ecf20Sopenharmony_ci hwptr_done = subs->hwptr_done; 758c2ecf20Sopenharmony_ci substream->runtime->delay = snd_usb_pcm_delay(subs, 768c2ecf20Sopenharmony_ci substream->runtime->rate); 778c2ecf20Sopenharmony_ci spin_unlock(&subs->lock); 788c2ecf20Sopenharmony_ci return hwptr_done / (substream->runtime->frame_bits >> 3); 798c2ecf20Sopenharmony_ci} 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci/* 828c2ecf20Sopenharmony_ci * find a matching audio format 838c2ecf20Sopenharmony_ci */ 848c2ecf20Sopenharmony_cistatic struct audioformat *find_format(struct snd_usb_substream *subs) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci struct audioformat *fp; 878c2ecf20Sopenharmony_ci struct audioformat *found = NULL; 888c2ecf20Sopenharmony_ci int cur_attr = 0, attr; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci list_for_each_entry(fp, &subs->fmt_list, list) { 918c2ecf20Sopenharmony_ci if (!(fp->formats & pcm_format_to_bits(subs->pcm_format))) 928c2ecf20Sopenharmony_ci continue; 938c2ecf20Sopenharmony_ci if (fp->channels != subs->channels) 948c2ecf20Sopenharmony_ci continue; 958c2ecf20Sopenharmony_ci if (subs->cur_rate < fp->rate_min || 968c2ecf20Sopenharmony_ci subs->cur_rate > fp->rate_max) 978c2ecf20Sopenharmony_ci continue; 988c2ecf20Sopenharmony_ci if (! (fp->rates & SNDRV_PCM_RATE_CONTINUOUS)) { 998c2ecf20Sopenharmony_ci unsigned int i; 1008c2ecf20Sopenharmony_ci for (i = 0; i < fp->nr_rates; i++) 1018c2ecf20Sopenharmony_ci if (fp->rate_table[i] == subs->cur_rate) 1028c2ecf20Sopenharmony_ci break; 1038c2ecf20Sopenharmony_ci if (i >= fp->nr_rates) 1048c2ecf20Sopenharmony_ci continue; 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci attr = fp->ep_attr & USB_ENDPOINT_SYNCTYPE; 1078c2ecf20Sopenharmony_ci if (! found) { 1088c2ecf20Sopenharmony_ci found = fp; 1098c2ecf20Sopenharmony_ci cur_attr = attr; 1108c2ecf20Sopenharmony_ci continue; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci /* avoid async out and adaptive in if the other method 1138c2ecf20Sopenharmony_ci * supports the same format. 1148c2ecf20Sopenharmony_ci * this is a workaround for the case like 1158c2ecf20Sopenharmony_ci * M-audio audiophile USB. 1168c2ecf20Sopenharmony_ci */ 1178c2ecf20Sopenharmony_ci if (attr != cur_attr) { 1188c2ecf20Sopenharmony_ci if ((attr == USB_ENDPOINT_SYNC_ASYNC && 1198c2ecf20Sopenharmony_ci subs->direction == SNDRV_PCM_STREAM_PLAYBACK) || 1208c2ecf20Sopenharmony_ci (attr == USB_ENDPOINT_SYNC_ADAPTIVE && 1218c2ecf20Sopenharmony_ci subs->direction == SNDRV_PCM_STREAM_CAPTURE)) 1228c2ecf20Sopenharmony_ci continue; 1238c2ecf20Sopenharmony_ci if ((cur_attr == USB_ENDPOINT_SYNC_ASYNC && 1248c2ecf20Sopenharmony_ci subs->direction == SNDRV_PCM_STREAM_PLAYBACK) || 1258c2ecf20Sopenharmony_ci (cur_attr == USB_ENDPOINT_SYNC_ADAPTIVE && 1268c2ecf20Sopenharmony_ci subs->direction == SNDRV_PCM_STREAM_CAPTURE)) { 1278c2ecf20Sopenharmony_ci found = fp; 1288c2ecf20Sopenharmony_ci cur_attr = attr; 1298c2ecf20Sopenharmony_ci continue; 1308c2ecf20Sopenharmony_ci } 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci /* find the format with the largest max. packet size */ 1338c2ecf20Sopenharmony_ci if (fp->maxpacksize > found->maxpacksize) { 1348c2ecf20Sopenharmony_ci found = fp; 1358c2ecf20Sopenharmony_ci cur_attr = attr; 1368c2ecf20Sopenharmony_ci } 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci return found; 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic int init_pitch_v1(struct snd_usb_audio *chip, int iface, 1428c2ecf20Sopenharmony_ci struct usb_host_interface *alts, 1438c2ecf20Sopenharmony_ci struct audioformat *fmt) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci struct usb_device *dev = chip->dev; 1468c2ecf20Sopenharmony_ci unsigned int ep; 1478c2ecf20Sopenharmony_ci unsigned char data[1]; 1488c2ecf20Sopenharmony_ci int err; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci if (get_iface_desc(alts)->bNumEndpoints < 1) 1518c2ecf20Sopenharmony_ci return -EINVAL; 1528c2ecf20Sopenharmony_ci ep = get_endpoint(alts, 0)->bEndpointAddress; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci data[0] = 1; 1558c2ecf20Sopenharmony_ci err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, 1568c2ecf20Sopenharmony_ci USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, 1578c2ecf20Sopenharmony_ci UAC_EP_CS_ATTR_PITCH_CONTROL << 8, ep, 1588c2ecf20Sopenharmony_ci data, sizeof(data)); 1598c2ecf20Sopenharmony_ci if (err < 0) { 1608c2ecf20Sopenharmony_ci usb_audio_err(chip, "%d:%d: cannot set enable PITCH\n", 1618c2ecf20Sopenharmony_ci iface, ep); 1628c2ecf20Sopenharmony_ci return err; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci return 0; 1668c2ecf20Sopenharmony_ci} 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_cistatic int init_pitch_v2(struct snd_usb_audio *chip, int iface, 1698c2ecf20Sopenharmony_ci struct usb_host_interface *alts, 1708c2ecf20Sopenharmony_ci struct audioformat *fmt) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci struct usb_device *dev = chip->dev; 1738c2ecf20Sopenharmony_ci unsigned char data[1]; 1748c2ecf20Sopenharmony_ci int err; 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_ci data[0] = 1; 1778c2ecf20Sopenharmony_ci err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, 1788c2ecf20Sopenharmony_ci USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, 1798c2ecf20Sopenharmony_ci UAC2_EP_CS_PITCH << 8, 0, 1808c2ecf20Sopenharmony_ci data, sizeof(data)); 1818c2ecf20Sopenharmony_ci if (err < 0) { 1828c2ecf20Sopenharmony_ci usb_audio_err(chip, "%d:%d: cannot set enable PITCH (v2)\n", 1838c2ecf20Sopenharmony_ci iface, fmt->altsetting); 1848c2ecf20Sopenharmony_ci return err; 1858c2ecf20Sopenharmony_ci } 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci return 0; 1888c2ecf20Sopenharmony_ci} 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci/* 1918c2ecf20Sopenharmony_ci * initialize the pitch control and sample rate 1928c2ecf20Sopenharmony_ci */ 1938c2ecf20Sopenharmony_ciint snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, 1948c2ecf20Sopenharmony_ci struct usb_host_interface *alts, 1958c2ecf20Sopenharmony_ci struct audioformat *fmt) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci /* if endpoint doesn't have pitch control, bail out */ 1988c2ecf20Sopenharmony_ci if (!(fmt->attributes & UAC_EP_CS_ATTR_PITCH_CONTROL)) 1998c2ecf20Sopenharmony_ci return 0; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci switch (fmt->protocol) { 2028c2ecf20Sopenharmony_ci case UAC_VERSION_1: 2038c2ecf20Sopenharmony_ci default: 2048c2ecf20Sopenharmony_ci return init_pitch_v1(chip, iface, alts, fmt); 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci case UAC_VERSION_2: 2078c2ecf20Sopenharmony_ci return init_pitch_v2(chip, iface, alts, fmt); 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci} 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_cistatic int start_endpoints(struct snd_usb_substream *subs) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci int err; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (!subs->data_endpoint) 2168c2ecf20Sopenharmony_ci return -EINVAL; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci if (!test_and_set_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) { 2198c2ecf20Sopenharmony_ci struct snd_usb_endpoint *ep = subs->data_endpoint; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci dev_dbg(&subs->dev->dev, "Starting data EP @%p\n", ep); 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci ep->data_subs = subs; 2248c2ecf20Sopenharmony_ci err = snd_usb_endpoint_start(ep); 2258c2ecf20Sopenharmony_ci if (err < 0) { 2268c2ecf20Sopenharmony_ci clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags); 2278c2ecf20Sopenharmony_ci return err; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (subs->sync_endpoint && 2328c2ecf20Sopenharmony_ci !test_and_set_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) { 2338c2ecf20Sopenharmony_ci struct snd_usb_endpoint *ep = subs->sync_endpoint; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci if (subs->data_endpoint->iface != subs->sync_endpoint->iface || 2368c2ecf20Sopenharmony_ci subs->data_endpoint->altsetting != subs->sync_endpoint->altsetting) { 2378c2ecf20Sopenharmony_ci err = usb_set_interface(subs->dev, 2388c2ecf20Sopenharmony_ci subs->sync_endpoint->iface, 2398c2ecf20Sopenharmony_ci subs->sync_endpoint->altsetting); 2408c2ecf20Sopenharmony_ci if (err < 0) { 2418c2ecf20Sopenharmony_ci clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags); 2428c2ecf20Sopenharmony_ci dev_err(&subs->dev->dev, 2438c2ecf20Sopenharmony_ci "%d:%d: cannot set interface (%d)\n", 2448c2ecf20Sopenharmony_ci subs->sync_endpoint->iface, 2458c2ecf20Sopenharmony_ci subs->sync_endpoint->altsetting, err); 2468c2ecf20Sopenharmony_ci return -EIO; 2478c2ecf20Sopenharmony_ci } 2488c2ecf20Sopenharmony_ci } 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci dev_dbg(&subs->dev->dev, "Starting sync EP @%p\n", ep); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci ep->sync_slave = subs->data_endpoint; 2538c2ecf20Sopenharmony_ci err = snd_usb_endpoint_start(ep); 2548c2ecf20Sopenharmony_ci if (err < 0) { 2558c2ecf20Sopenharmony_ci clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags); 2568c2ecf20Sopenharmony_ci return err; 2578c2ecf20Sopenharmony_ci } 2588c2ecf20Sopenharmony_ci } 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci return 0; 2618c2ecf20Sopenharmony_ci} 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_cistatic void sync_pending_stops(struct snd_usb_substream *subs) 2648c2ecf20Sopenharmony_ci{ 2658c2ecf20Sopenharmony_ci snd_usb_endpoint_sync_pending_stop(subs->sync_endpoint); 2668c2ecf20Sopenharmony_ci snd_usb_endpoint_sync_pending_stop(subs->data_endpoint); 2678c2ecf20Sopenharmony_ci} 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_cistatic void stop_endpoints(struct snd_usb_substream *subs) 2708c2ecf20Sopenharmony_ci{ 2718c2ecf20Sopenharmony_ci if (test_and_clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) 2728c2ecf20Sopenharmony_ci snd_usb_endpoint_stop(subs->sync_endpoint); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci if (test_and_clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) 2758c2ecf20Sopenharmony_ci snd_usb_endpoint_stop(subs->data_endpoint); 2768c2ecf20Sopenharmony_ci} 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci/* PCM sync_stop callback */ 2798c2ecf20Sopenharmony_cistatic int snd_usb_pcm_sync_stop(struct snd_pcm_substream *substream) 2808c2ecf20Sopenharmony_ci{ 2818c2ecf20Sopenharmony_ci struct snd_usb_substream *subs = substream->runtime->private_data; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci sync_pending_stops(subs); 2848c2ecf20Sopenharmony_ci return 0; 2858c2ecf20Sopenharmony_ci} 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_cistatic int search_roland_implicit_fb(struct usb_device *dev, int ifnum, 2888c2ecf20Sopenharmony_ci unsigned int altsetting, 2898c2ecf20Sopenharmony_ci struct usb_host_interface **alts, 2908c2ecf20Sopenharmony_ci unsigned int *ep) 2918c2ecf20Sopenharmony_ci{ 2928c2ecf20Sopenharmony_ci struct usb_interface *iface; 2938c2ecf20Sopenharmony_ci struct usb_interface_descriptor *altsd; 2948c2ecf20Sopenharmony_ci struct usb_endpoint_descriptor *epd; 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_ci iface = usb_ifnum_to_if(dev, ifnum); 2978c2ecf20Sopenharmony_ci if (!iface || iface->num_altsetting < altsetting + 1) 2988c2ecf20Sopenharmony_ci return -ENOENT; 2998c2ecf20Sopenharmony_ci *alts = &iface->altsetting[altsetting]; 3008c2ecf20Sopenharmony_ci altsd = get_iface_desc(*alts); 3018c2ecf20Sopenharmony_ci if (altsd->bAlternateSetting != altsetting || 3028c2ecf20Sopenharmony_ci altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC || 3038c2ecf20Sopenharmony_ci (altsd->bInterfaceSubClass != 2 && 3048c2ecf20Sopenharmony_ci altsd->bInterfaceProtocol != 2 ) || 3058c2ecf20Sopenharmony_ci altsd->bNumEndpoints < 1) 3068c2ecf20Sopenharmony_ci return -ENOENT; 3078c2ecf20Sopenharmony_ci epd = get_endpoint(*alts, 0); 3088c2ecf20Sopenharmony_ci if (!usb_endpoint_is_isoc_in(epd) || 3098c2ecf20Sopenharmony_ci (epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) != 3108c2ecf20Sopenharmony_ci USB_ENDPOINT_USAGE_IMPLICIT_FB) 3118c2ecf20Sopenharmony_ci return -ENOENT; 3128c2ecf20Sopenharmony_ci *ep = epd->bEndpointAddress; 3138c2ecf20Sopenharmony_ci return 0; 3148c2ecf20Sopenharmony_ci} 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci/* Setup an implicit feedback endpoint from a quirk. Returns 0 if no quirk 3178c2ecf20Sopenharmony_ci * applies. Returns 1 if a quirk was found. 3188c2ecf20Sopenharmony_ci */ 3198c2ecf20Sopenharmony_cistatic int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs, 3208c2ecf20Sopenharmony_ci struct usb_device *dev, 3218c2ecf20Sopenharmony_ci struct usb_interface_descriptor *altsd, 3228c2ecf20Sopenharmony_ci unsigned int attr) 3238c2ecf20Sopenharmony_ci{ 3248c2ecf20Sopenharmony_ci struct usb_host_interface *alts; 3258c2ecf20Sopenharmony_ci struct usb_interface *iface; 3268c2ecf20Sopenharmony_ci unsigned int ep; 3278c2ecf20Sopenharmony_ci unsigned int ifnum; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci /* Implicit feedback sync EPs consumers are always playback EPs */ 3308c2ecf20Sopenharmony_ci if (subs->direction != SNDRV_PCM_STREAM_PLAYBACK) 3318c2ecf20Sopenharmony_ci return 0; 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci switch (subs->stream->chip->usb_id) { 3348c2ecf20Sopenharmony_ci case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */ 3358c2ecf20Sopenharmony_ci case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C600 */ 3368c2ecf20Sopenharmony_ci case USB_ID(0x22f0, 0x0006): /* Allen&Heath Qu-16 */ 3378c2ecf20Sopenharmony_ci ep = 0x81; 3388c2ecf20Sopenharmony_ci ifnum = 3; 3398c2ecf20Sopenharmony_ci goto add_sync_ep_from_ifnum; 3408c2ecf20Sopenharmony_ci case USB_ID(0x0763, 0x2080): /* M-Audio FastTrack Ultra */ 3418c2ecf20Sopenharmony_ci case USB_ID(0x0763, 0x2081): 3428c2ecf20Sopenharmony_ci ep = 0x81; 3438c2ecf20Sopenharmony_ci ifnum = 2; 3448c2ecf20Sopenharmony_ci goto add_sync_ep_from_ifnum; 3458c2ecf20Sopenharmony_ci case USB_ID(0x2466, 0x8003): /* Fractal Audio Axe-Fx II */ 3468c2ecf20Sopenharmony_ci case USB_ID(0x0499, 0x172a): /* Yamaha MODX */ 3478c2ecf20Sopenharmony_ci ep = 0x86; 3488c2ecf20Sopenharmony_ci ifnum = 2; 3498c2ecf20Sopenharmony_ci goto add_sync_ep_from_ifnum; 3508c2ecf20Sopenharmony_ci case USB_ID(0x2466, 0x8010): /* Fractal Audio Axe-Fx III */ 3518c2ecf20Sopenharmony_ci ep = 0x81; 3528c2ecf20Sopenharmony_ci ifnum = 2; 3538c2ecf20Sopenharmony_ci goto add_sync_ep_from_ifnum; 3548c2ecf20Sopenharmony_ci case USB_ID(0x1686, 0xf029): /* Zoom UAC-2 */ 3558c2ecf20Sopenharmony_ci ep = 0x82; 3568c2ecf20Sopenharmony_ci ifnum = 2; 3578c2ecf20Sopenharmony_ci goto add_sync_ep_from_ifnum; 3588c2ecf20Sopenharmony_ci case USB_ID(0x1397, 0x0001): /* Behringer UFX1604 */ 3598c2ecf20Sopenharmony_ci case USB_ID(0x1397, 0x0002): /* Behringer UFX1204 */ 3608c2ecf20Sopenharmony_ci ep = 0x81; 3618c2ecf20Sopenharmony_ci ifnum = 1; 3628c2ecf20Sopenharmony_ci goto add_sync_ep_from_ifnum; 3638c2ecf20Sopenharmony_ci case USB_ID(0x07fd, 0x0004): /* MOTU MicroBook II/IIc */ 3648c2ecf20Sopenharmony_ci /* MicroBook IIc */ 3658c2ecf20Sopenharmony_ci if (altsd->bInterfaceClass == USB_CLASS_AUDIO) 3668c2ecf20Sopenharmony_ci return 0; 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci /* MicroBook II */ 3698c2ecf20Sopenharmony_ci ep = 0x84; 3708c2ecf20Sopenharmony_ci ifnum = 0; 3718c2ecf20Sopenharmony_ci goto add_sync_ep_from_ifnum; 3728c2ecf20Sopenharmony_ci case USB_ID(0x07fd, 0x0008): /* MOTU M Series */ 3738c2ecf20Sopenharmony_ci case USB_ID(0x31e9, 0x0001): /* Solid State Logic SSL2 */ 3748c2ecf20Sopenharmony_ci case USB_ID(0x31e9, 0x0002): /* Solid State Logic SSL2+ */ 3758c2ecf20Sopenharmony_ci case USB_ID(0x0499, 0x172f): /* Steinberg UR22C */ 3768c2ecf20Sopenharmony_ci case USB_ID(0x0d9a, 0x00df): /* RTX6001 */ 3778c2ecf20Sopenharmony_ci ep = 0x81; 3788c2ecf20Sopenharmony_ci ifnum = 2; 3798c2ecf20Sopenharmony_ci goto add_sync_ep_from_ifnum; 3808c2ecf20Sopenharmony_ci case USB_ID(0x2b73, 0x000a): /* Pioneer DJ DJM-900NXS2 */ 3818c2ecf20Sopenharmony_ci case USB_ID(0x2b73, 0x0017): /* Pioneer DJ DJM-250MK2 */ 3828c2ecf20Sopenharmony_ci ep = 0x82; 3838c2ecf20Sopenharmony_ci ifnum = 0; 3848c2ecf20Sopenharmony_ci goto add_sync_ep_from_ifnum; 3858c2ecf20Sopenharmony_ci case USB_ID(0x0582, 0x01d8): /* BOSS Katana */ 3868c2ecf20Sopenharmony_ci /* BOSS Katana amplifiers do not need quirks */ 3878c2ecf20Sopenharmony_ci return 0; 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci if (attr == USB_ENDPOINT_SYNC_ASYNC && 3918c2ecf20Sopenharmony_ci altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC && 3928c2ecf20Sopenharmony_ci altsd->bInterfaceProtocol == 2 && 3938c2ecf20Sopenharmony_ci altsd->bNumEndpoints == 1 && 3948c2ecf20Sopenharmony_ci USB_ID_VENDOR(subs->stream->chip->usb_id) == 0x0582 /* Roland */ && 3958c2ecf20Sopenharmony_ci search_roland_implicit_fb(dev, altsd->bInterfaceNumber + 1, 3968c2ecf20Sopenharmony_ci altsd->bAlternateSetting, 3978c2ecf20Sopenharmony_ci &alts, &ep) >= 0) { 3988c2ecf20Sopenharmony_ci goto add_sync_ep; 3998c2ecf20Sopenharmony_ci } 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci /* No quirk */ 4028c2ecf20Sopenharmony_ci return 0; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ciadd_sync_ep_from_ifnum: 4058c2ecf20Sopenharmony_ci iface = usb_ifnum_to_if(dev, ifnum); 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci if (!iface || iface->num_altsetting < 2) 4088c2ecf20Sopenharmony_ci return -EINVAL; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci alts = &iface->altsetting[1]; 4118c2ecf20Sopenharmony_ci 4128c2ecf20Sopenharmony_ciadd_sync_ep: 4138c2ecf20Sopenharmony_ci subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip, 4148c2ecf20Sopenharmony_ci alts, ep, !subs->direction, 4158c2ecf20Sopenharmony_ci SND_USB_ENDPOINT_TYPE_DATA); 4168c2ecf20Sopenharmony_ci if (!subs->sync_endpoint) 4178c2ecf20Sopenharmony_ci return -EINVAL; 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci subs->sync_endpoint->is_implicit_feedback = 1; 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci subs->data_endpoint->sync_master = subs->sync_endpoint; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci return 1; 4248c2ecf20Sopenharmony_ci} 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_cistatic int set_sync_endpoint(struct snd_usb_substream *subs, 4278c2ecf20Sopenharmony_ci struct audioformat *fmt, 4288c2ecf20Sopenharmony_ci struct usb_device *dev, 4298c2ecf20Sopenharmony_ci struct usb_host_interface *alts, 4308c2ecf20Sopenharmony_ci struct usb_interface_descriptor *altsd) 4318c2ecf20Sopenharmony_ci{ 4328c2ecf20Sopenharmony_ci int is_playback = subs->direction == SNDRV_PCM_STREAM_PLAYBACK; 4338c2ecf20Sopenharmony_ci unsigned int ep, attr; 4348c2ecf20Sopenharmony_ci bool implicit_fb; 4358c2ecf20Sopenharmony_ci int err; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci /* we need a sync pipe in async OUT or adaptive IN mode */ 4388c2ecf20Sopenharmony_ci /* check the number of EP, since some devices have broken 4398c2ecf20Sopenharmony_ci * descriptors which fool us. if it has only one EP, 4408c2ecf20Sopenharmony_ci * assume it as adaptive-out or sync-in. 4418c2ecf20Sopenharmony_ci */ 4428c2ecf20Sopenharmony_ci attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci if ((is_playback && (attr != USB_ENDPOINT_SYNC_ASYNC)) || 4458c2ecf20Sopenharmony_ci (!is_playback && (attr != USB_ENDPOINT_SYNC_ADAPTIVE))) { 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci /* 4488c2ecf20Sopenharmony_ci * In these modes the notion of sync_endpoint is irrelevant. 4498c2ecf20Sopenharmony_ci * Reset pointers to avoid using stale data from previously 4508c2ecf20Sopenharmony_ci * used settings, e.g. when configuration and endpoints were 4518c2ecf20Sopenharmony_ci * changed 4528c2ecf20Sopenharmony_ci */ 4538c2ecf20Sopenharmony_ci 4548c2ecf20Sopenharmony_ci subs->sync_endpoint = NULL; 4558c2ecf20Sopenharmony_ci subs->data_endpoint->sync_master = NULL; 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_ci err = set_sync_ep_implicit_fb_quirk(subs, dev, altsd, attr); 4598c2ecf20Sopenharmony_ci if (err < 0) 4608c2ecf20Sopenharmony_ci return err; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci /* endpoint set by quirk */ 4638c2ecf20Sopenharmony_ci if (err > 0) 4648c2ecf20Sopenharmony_ci return 0; 4658c2ecf20Sopenharmony_ci 4668c2ecf20Sopenharmony_ci if (altsd->bNumEndpoints < 2) 4678c2ecf20Sopenharmony_ci return 0; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci if ((is_playback && (attr == USB_ENDPOINT_SYNC_SYNC || 4708c2ecf20Sopenharmony_ci attr == USB_ENDPOINT_SYNC_ADAPTIVE)) || 4718c2ecf20Sopenharmony_ci (!is_playback && attr != USB_ENDPOINT_SYNC_ADAPTIVE)) 4728c2ecf20Sopenharmony_ci return 0; 4738c2ecf20Sopenharmony_ci 4748c2ecf20Sopenharmony_ci /* 4758c2ecf20Sopenharmony_ci * In case of illegal SYNC_NONE for OUT endpoint, we keep going to see 4768c2ecf20Sopenharmony_ci * if we don't find a sync endpoint, as on M-Audio Transit. In case of 4778c2ecf20Sopenharmony_ci * error fall back to SYNC mode and don't create sync endpoint 4788c2ecf20Sopenharmony_ci */ 4798c2ecf20Sopenharmony_ci 4808c2ecf20Sopenharmony_ci /* check sync-pipe endpoint */ 4818c2ecf20Sopenharmony_ci /* ... and check descriptor size before accessing bSynchAddress 4828c2ecf20Sopenharmony_ci because there is a version of the SB Audigy 2 NX firmware lacking 4838c2ecf20Sopenharmony_ci the audio fields in the endpoint descriptors */ 4848c2ecf20Sopenharmony_ci if ((get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) != USB_ENDPOINT_XFER_ISOC || 4858c2ecf20Sopenharmony_ci (get_endpoint(alts, 1)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && 4868c2ecf20Sopenharmony_ci get_endpoint(alts, 1)->bSynchAddress != 0)) { 4878c2ecf20Sopenharmony_ci dev_err(&dev->dev, 4888c2ecf20Sopenharmony_ci "%d:%d : invalid sync pipe. bmAttributes %02x, bLength %d, bSynchAddress %02x\n", 4898c2ecf20Sopenharmony_ci fmt->iface, fmt->altsetting, 4908c2ecf20Sopenharmony_ci get_endpoint(alts, 1)->bmAttributes, 4918c2ecf20Sopenharmony_ci get_endpoint(alts, 1)->bLength, 4928c2ecf20Sopenharmony_ci get_endpoint(alts, 1)->bSynchAddress); 4938c2ecf20Sopenharmony_ci if (is_playback && attr == USB_ENDPOINT_SYNC_NONE) 4948c2ecf20Sopenharmony_ci return 0; 4958c2ecf20Sopenharmony_ci return -EINVAL; 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci ep = get_endpoint(alts, 1)->bEndpointAddress; 4988c2ecf20Sopenharmony_ci if (get_endpoint(alts, 0)->bLength >= USB_DT_ENDPOINT_AUDIO_SIZE && 4998c2ecf20Sopenharmony_ci get_endpoint(alts, 0)->bSynchAddress != 0 && 5008c2ecf20Sopenharmony_ci ((is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress | USB_DIR_IN)) || 5018c2ecf20Sopenharmony_ci (!is_playback && ep != (unsigned int)(get_endpoint(alts, 0)->bSynchAddress & ~USB_DIR_IN)))) { 5028c2ecf20Sopenharmony_ci dev_err(&dev->dev, 5038c2ecf20Sopenharmony_ci "%d:%d : invalid sync pipe. is_playback %d, ep %02x, bSynchAddress %02x\n", 5048c2ecf20Sopenharmony_ci fmt->iface, fmt->altsetting, 5058c2ecf20Sopenharmony_ci is_playback, ep, get_endpoint(alts, 0)->bSynchAddress); 5068c2ecf20Sopenharmony_ci if (is_playback && attr == USB_ENDPOINT_SYNC_NONE) 5078c2ecf20Sopenharmony_ci return 0; 5088c2ecf20Sopenharmony_ci return -EINVAL; 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci implicit_fb = (get_endpoint(alts, 1)->bmAttributes & USB_ENDPOINT_USAGE_MASK) 5128c2ecf20Sopenharmony_ci == USB_ENDPOINT_USAGE_IMPLICIT_FB; 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip, 5158c2ecf20Sopenharmony_ci alts, ep, !subs->direction, 5168c2ecf20Sopenharmony_ci implicit_fb ? 5178c2ecf20Sopenharmony_ci SND_USB_ENDPOINT_TYPE_DATA : 5188c2ecf20Sopenharmony_ci SND_USB_ENDPOINT_TYPE_SYNC); 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci if (!subs->sync_endpoint) { 5218c2ecf20Sopenharmony_ci if (is_playback && attr == USB_ENDPOINT_SYNC_NONE) 5228c2ecf20Sopenharmony_ci return 0; 5238c2ecf20Sopenharmony_ci return -EINVAL; 5248c2ecf20Sopenharmony_ci } 5258c2ecf20Sopenharmony_ci 5268c2ecf20Sopenharmony_ci subs->sync_endpoint->is_implicit_feedback = implicit_fb; 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_ci subs->data_endpoint->sync_master = subs->sync_endpoint; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci return 0; 5318c2ecf20Sopenharmony_ci} 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci/* 5348c2ecf20Sopenharmony_ci * find a matching format and set up the interface 5358c2ecf20Sopenharmony_ci */ 5368c2ecf20Sopenharmony_cistatic int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) 5378c2ecf20Sopenharmony_ci{ 5388c2ecf20Sopenharmony_ci struct usb_device *dev = subs->dev; 5398c2ecf20Sopenharmony_ci struct usb_host_interface *alts; 5408c2ecf20Sopenharmony_ci struct usb_interface_descriptor *altsd; 5418c2ecf20Sopenharmony_ci struct usb_interface *iface; 5428c2ecf20Sopenharmony_ci int err; 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci iface = usb_ifnum_to_if(dev, fmt->iface); 5458c2ecf20Sopenharmony_ci if (WARN_ON(!iface)) 5468c2ecf20Sopenharmony_ci return -EINVAL; 5478c2ecf20Sopenharmony_ci alts = usb_altnum_to_altsetting(iface, fmt->altsetting); 5488c2ecf20Sopenharmony_ci if (WARN_ON(!alts)) 5498c2ecf20Sopenharmony_ci return -EINVAL; 5508c2ecf20Sopenharmony_ci altsd = get_iface_desc(alts); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci if (fmt == subs->cur_audiofmt && !subs->need_setup_fmt) 5538c2ecf20Sopenharmony_ci return 0; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci /* close the old interface */ 5568c2ecf20Sopenharmony_ci if (subs->interface >= 0 && (subs->interface != fmt->iface || subs->need_setup_fmt)) { 5578c2ecf20Sopenharmony_ci if (!subs->stream->chip->keep_iface) { 5588c2ecf20Sopenharmony_ci err = usb_set_interface(subs->dev, subs->interface, 0); 5598c2ecf20Sopenharmony_ci if (err < 0) { 5608c2ecf20Sopenharmony_ci dev_err(&dev->dev, 5618c2ecf20Sopenharmony_ci "%d:%d: return to setting 0 failed (%d)\n", 5628c2ecf20Sopenharmony_ci fmt->iface, fmt->altsetting, err); 5638c2ecf20Sopenharmony_ci return -EIO; 5648c2ecf20Sopenharmony_ci } 5658c2ecf20Sopenharmony_ci } 5668c2ecf20Sopenharmony_ci subs->interface = -1; 5678c2ecf20Sopenharmony_ci subs->altset_idx = 0; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci if (subs->need_setup_fmt) 5718c2ecf20Sopenharmony_ci subs->need_setup_fmt = false; 5728c2ecf20Sopenharmony_ci 5738c2ecf20Sopenharmony_ci /* set interface */ 5748c2ecf20Sopenharmony_ci if (iface->cur_altsetting != alts) { 5758c2ecf20Sopenharmony_ci err = snd_usb_select_mode_quirk(subs, fmt); 5768c2ecf20Sopenharmony_ci if (err < 0) 5778c2ecf20Sopenharmony_ci return -EIO; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci err = usb_set_interface(dev, fmt->iface, fmt->altsetting); 5808c2ecf20Sopenharmony_ci if (err < 0) { 5818c2ecf20Sopenharmony_ci dev_err(&dev->dev, 5828c2ecf20Sopenharmony_ci "%d:%d: usb_set_interface failed (%d)\n", 5838c2ecf20Sopenharmony_ci fmt->iface, fmt->altsetting, err); 5848c2ecf20Sopenharmony_ci return -EIO; 5858c2ecf20Sopenharmony_ci } 5868c2ecf20Sopenharmony_ci dev_dbg(&dev->dev, "setting usb interface %d:%d\n", 5878c2ecf20Sopenharmony_ci fmt->iface, fmt->altsetting); 5888c2ecf20Sopenharmony_ci snd_usb_set_interface_quirk(dev); 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci subs->interface = fmt->iface; 5928c2ecf20Sopenharmony_ci subs->altset_idx = fmt->altset_idx; 5938c2ecf20Sopenharmony_ci subs->data_endpoint = snd_usb_add_endpoint(subs->stream->chip, 5948c2ecf20Sopenharmony_ci alts, fmt->endpoint, subs->direction, 5958c2ecf20Sopenharmony_ci SND_USB_ENDPOINT_TYPE_DATA); 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci if (!subs->data_endpoint) 5988c2ecf20Sopenharmony_ci return -EINVAL; 5998c2ecf20Sopenharmony_ci 6008c2ecf20Sopenharmony_ci err = set_sync_endpoint(subs, fmt, dev, alts, altsd); 6018c2ecf20Sopenharmony_ci if (err < 0) 6028c2ecf20Sopenharmony_ci return err; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci err = snd_usb_init_pitch(subs->stream->chip, fmt->iface, alts, fmt); 6058c2ecf20Sopenharmony_ci if (err < 0) 6068c2ecf20Sopenharmony_ci return err; 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ci subs->cur_audiofmt = fmt; 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci snd_usb_set_format_quirk(subs, fmt); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci return 0; 6138c2ecf20Sopenharmony_ci} 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci/* 6168c2ecf20Sopenharmony_ci * Return the score of matching two audioformats. 6178c2ecf20Sopenharmony_ci * Veto the audioformat if: 6188c2ecf20Sopenharmony_ci * - It has no channels for some reason. 6198c2ecf20Sopenharmony_ci * - Requested PCM format is not supported. 6208c2ecf20Sopenharmony_ci * - Requested sample rate is not supported. 6218c2ecf20Sopenharmony_ci */ 6228c2ecf20Sopenharmony_cistatic int match_endpoint_audioformats(struct snd_usb_substream *subs, 6238c2ecf20Sopenharmony_ci struct audioformat *fp, 6248c2ecf20Sopenharmony_ci struct audioformat *match, int rate, 6258c2ecf20Sopenharmony_ci snd_pcm_format_t pcm_format) 6268c2ecf20Sopenharmony_ci{ 6278c2ecf20Sopenharmony_ci int i; 6288c2ecf20Sopenharmony_ci int score = 0; 6298c2ecf20Sopenharmony_ci 6308c2ecf20Sopenharmony_ci if (fp->channels < 1) { 6318c2ecf20Sopenharmony_ci dev_dbg(&subs->dev->dev, 6328c2ecf20Sopenharmony_ci "%s: (fmt @%p) no channels\n", __func__, fp); 6338c2ecf20Sopenharmony_ci return 0; 6348c2ecf20Sopenharmony_ci } 6358c2ecf20Sopenharmony_ci 6368c2ecf20Sopenharmony_ci if (!(fp->formats & pcm_format_to_bits(pcm_format))) { 6378c2ecf20Sopenharmony_ci dev_dbg(&subs->dev->dev, 6388c2ecf20Sopenharmony_ci "%s: (fmt @%p) no match for format %d\n", __func__, 6398c2ecf20Sopenharmony_ci fp, pcm_format); 6408c2ecf20Sopenharmony_ci return 0; 6418c2ecf20Sopenharmony_ci } 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci for (i = 0; i < fp->nr_rates; i++) { 6448c2ecf20Sopenharmony_ci if (fp->rate_table[i] == rate) { 6458c2ecf20Sopenharmony_ci score++; 6468c2ecf20Sopenharmony_ci break; 6478c2ecf20Sopenharmony_ci } 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci if (!score) { 6508c2ecf20Sopenharmony_ci dev_dbg(&subs->dev->dev, 6518c2ecf20Sopenharmony_ci "%s: (fmt @%p) no match for rate %d\n", __func__, 6528c2ecf20Sopenharmony_ci fp, rate); 6538c2ecf20Sopenharmony_ci return 0; 6548c2ecf20Sopenharmony_ci } 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci if (fp->channels == match->channels) 6578c2ecf20Sopenharmony_ci score++; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci dev_dbg(&subs->dev->dev, 6608c2ecf20Sopenharmony_ci "%s: (fmt @%p) score %d\n", __func__, fp, score); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci return score; 6638c2ecf20Sopenharmony_ci} 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci/* 6668c2ecf20Sopenharmony_ci * Configure the sync ep using the rate and pcm format of the data ep. 6678c2ecf20Sopenharmony_ci */ 6688c2ecf20Sopenharmony_cistatic int configure_sync_endpoint(struct snd_usb_substream *subs) 6698c2ecf20Sopenharmony_ci{ 6708c2ecf20Sopenharmony_ci int ret; 6718c2ecf20Sopenharmony_ci struct audioformat *fp; 6728c2ecf20Sopenharmony_ci struct audioformat *sync_fp = NULL; 6738c2ecf20Sopenharmony_ci int cur_score = 0; 6748c2ecf20Sopenharmony_ci int sync_period_bytes = subs->period_bytes; 6758c2ecf20Sopenharmony_ci struct snd_usb_substream *sync_subs = 6768c2ecf20Sopenharmony_ci &subs->stream->substream[subs->direction ^ 1]; 6778c2ecf20Sopenharmony_ci 6788c2ecf20Sopenharmony_ci if (subs->sync_endpoint->type != SND_USB_ENDPOINT_TYPE_DATA || 6798c2ecf20Sopenharmony_ci !subs->stream) 6808c2ecf20Sopenharmony_ci return snd_usb_endpoint_set_params(subs->sync_endpoint, 6818c2ecf20Sopenharmony_ci subs->pcm_format, 6828c2ecf20Sopenharmony_ci subs->channels, 6838c2ecf20Sopenharmony_ci subs->period_bytes, 6848c2ecf20Sopenharmony_ci 0, 0, 6858c2ecf20Sopenharmony_ci subs->cur_rate, 6868c2ecf20Sopenharmony_ci subs->cur_audiofmt, 6878c2ecf20Sopenharmony_ci NULL); 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci /* Try to find the best matching audioformat. */ 6908c2ecf20Sopenharmony_ci list_for_each_entry(fp, &sync_subs->fmt_list, list) { 6918c2ecf20Sopenharmony_ci int score = match_endpoint_audioformats(subs, 6928c2ecf20Sopenharmony_ci fp, subs->cur_audiofmt, 6938c2ecf20Sopenharmony_ci subs->cur_rate, subs->pcm_format); 6948c2ecf20Sopenharmony_ci 6958c2ecf20Sopenharmony_ci if (score > cur_score) { 6968c2ecf20Sopenharmony_ci sync_fp = fp; 6978c2ecf20Sopenharmony_ci cur_score = score; 6988c2ecf20Sopenharmony_ci } 6998c2ecf20Sopenharmony_ci } 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci if (unlikely(sync_fp == NULL)) { 7028c2ecf20Sopenharmony_ci dev_err(&subs->dev->dev, 7038c2ecf20Sopenharmony_ci "%s: no valid audioformat for sync ep %x found\n", 7048c2ecf20Sopenharmony_ci __func__, sync_subs->ep_num); 7058c2ecf20Sopenharmony_ci return -EINVAL; 7068c2ecf20Sopenharmony_ci } 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci /* 7098c2ecf20Sopenharmony_ci * Recalculate the period bytes if channel number differ between 7108c2ecf20Sopenharmony_ci * data and sync ep audioformat. 7118c2ecf20Sopenharmony_ci */ 7128c2ecf20Sopenharmony_ci if (sync_fp->channels != subs->channels) { 7138c2ecf20Sopenharmony_ci sync_period_bytes = (subs->period_bytes / subs->channels) * 7148c2ecf20Sopenharmony_ci sync_fp->channels; 7158c2ecf20Sopenharmony_ci dev_dbg(&subs->dev->dev, 7168c2ecf20Sopenharmony_ci "%s: adjusted sync ep period bytes (%d -> %d)\n", 7178c2ecf20Sopenharmony_ci __func__, subs->period_bytes, sync_period_bytes); 7188c2ecf20Sopenharmony_ci } 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci ret = snd_usb_endpoint_set_params(subs->sync_endpoint, 7218c2ecf20Sopenharmony_ci subs->pcm_format, 7228c2ecf20Sopenharmony_ci sync_fp->channels, 7238c2ecf20Sopenharmony_ci sync_period_bytes, 7248c2ecf20Sopenharmony_ci 0, 0, 7258c2ecf20Sopenharmony_ci subs->cur_rate, 7268c2ecf20Sopenharmony_ci sync_fp, 7278c2ecf20Sopenharmony_ci NULL); 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_ci return ret; 7308c2ecf20Sopenharmony_ci} 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci/* 7338c2ecf20Sopenharmony_ci * configure endpoint params 7348c2ecf20Sopenharmony_ci * 7358c2ecf20Sopenharmony_ci * called during initial setup and upon resume 7368c2ecf20Sopenharmony_ci */ 7378c2ecf20Sopenharmony_cistatic int configure_endpoint(struct snd_usb_substream *subs) 7388c2ecf20Sopenharmony_ci{ 7398c2ecf20Sopenharmony_ci int ret; 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_ci /* format changed */ 7428c2ecf20Sopenharmony_ci stop_endpoints(subs); 7438c2ecf20Sopenharmony_ci sync_pending_stops(subs); 7448c2ecf20Sopenharmony_ci ret = snd_usb_endpoint_set_params(subs->data_endpoint, 7458c2ecf20Sopenharmony_ci subs->pcm_format, 7468c2ecf20Sopenharmony_ci subs->channels, 7478c2ecf20Sopenharmony_ci subs->period_bytes, 7488c2ecf20Sopenharmony_ci subs->period_frames, 7498c2ecf20Sopenharmony_ci subs->buffer_periods, 7508c2ecf20Sopenharmony_ci subs->cur_rate, 7518c2ecf20Sopenharmony_ci subs->cur_audiofmt, 7528c2ecf20Sopenharmony_ci subs->sync_endpoint); 7538c2ecf20Sopenharmony_ci if (ret < 0) 7548c2ecf20Sopenharmony_ci return ret; 7558c2ecf20Sopenharmony_ci 7568c2ecf20Sopenharmony_ci if (subs->sync_endpoint) 7578c2ecf20Sopenharmony_ci ret = configure_sync_endpoint(subs); 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci return ret; 7608c2ecf20Sopenharmony_ci} 7618c2ecf20Sopenharmony_ci 7628c2ecf20Sopenharmony_cistatic int snd_usb_pcm_change_state(struct snd_usb_substream *subs, int state) 7638c2ecf20Sopenharmony_ci{ 7648c2ecf20Sopenharmony_ci int ret; 7658c2ecf20Sopenharmony_ci 7668c2ecf20Sopenharmony_ci if (!subs->str_pd) 7678c2ecf20Sopenharmony_ci return 0; 7688c2ecf20Sopenharmony_ci 7698c2ecf20Sopenharmony_ci ret = snd_usb_power_domain_set(subs->stream->chip, subs->str_pd, state); 7708c2ecf20Sopenharmony_ci if (ret < 0) { 7718c2ecf20Sopenharmony_ci dev_err(&subs->dev->dev, 7728c2ecf20Sopenharmony_ci "Cannot change Power Domain ID: %d to state: %d. Err: %d\n", 7738c2ecf20Sopenharmony_ci subs->str_pd->pd_id, state, ret); 7748c2ecf20Sopenharmony_ci return ret; 7758c2ecf20Sopenharmony_ci } 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_ci return 0; 7788c2ecf20Sopenharmony_ci} 7798c2ecf20Sopenharmony_ci 7808c2ecf20Sopenharmony_ciint snd_usb_pcm_suspend(struct snd_usb_stream *as) 7818c2ecf20Sopenharmony_ci{ 7828c2ecf20Sopenharmony_ci int ret; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci ret = snd_usb_pcm_change_state(&as->substream[0], UAC3_PD_STATE_D2); 7858c2ecf20Sopenharmony_ci if (ret < 0) 7868c2ecf20Sopenharmony_ci return ret; 7878c2ecf20Sopenharmony_ci 7888c2ecf20Sopenharmony_ci ret = snd_usb_pcm_change_state(&as->substream[1], UAC3_PD_STATE_D2); 7898c2ecf20Sopenharmony_ci if (ret < 0) 7908c2ecf20Sopenharmony_ci return ret; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_ci return 0; 7938c2ecf20Sopenharmony_ci} 7948c2ecf20Sopenharmony_ci 7958c2ecf20Sopenharmony_ciint snd_usb_pcm_resume(struct snd_usb_stream *as) 7968c2ecf20Sopenharmony_ci{ 7978c2ecf20Sopenharmony_ci int ret; 7988c2ecf20Sopenharmony_ci 7998c2ecf20Sopenharmony_ci ret = snd_usb_pcm_change_state(&as->substream[0], UAC3_PD_STATE_D1); 8008c2ecf20Sopenharmony_ci if (ret < 0) 8018c2ecf20Sopenharmony_ci return ret; 8028c2ecf20Sopenharmony_ci 8038c2ecf20Sopenharmony_ci ret = snd_usb_pcm_change_state(&as->substream[1], UAC3_PD_STATE_D1); 8048c2ecf20Sopenharmony_ci if (ret < 0) 8058c2ecf20Sopenharmony_ci return ret; 8068c2ecf20Sopenharmony_ci 8078c2ecf20Sopenharmony_ci return 0; 8088c2ecf20Sopenharmony_ci} 8098c2ecf20Sopenharmony_ci 8108c2ecf20Sopenharmony_ci/* 8118c2ecf20Sopenharmony_ci * hw_params callback 8128c2ecf20Sopenharmony_ci * 8138c2ecf20Sopenharmony_ci * allocate a buffer and set the given audio format. 8148c2ecf20Sopenharmony_ci * 8158c2ecf20Sopenharmony_ci * so far we use a physically linear buffer although packetize transfer 8168c2ecf20Sopenharmony_ci * doesn't need a continuous area. 8178c2ecf20Sopenharmony_ci * if sg buffer is supported on the later version of alsa, we'll follow 8188c2ecf20Sopenharmony_ci * that. 8198c2ecf20Sopenharmony_ci */ 8208c2ecf20Sopenharmony_cistatic int snd_usb_hw_params(struct snd_pcm_substream *substream, 8218c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *hw_params) 8228c2ecf20Sopenharmony_ci{ 8238c2ecf20Sopenharmony_ci struct snd_usb_substream *subs = substream->runtime->private_data; 8248c2ecf20Sopenharmony_ci struct audioformat *fmt; 8258c2ecf20Sopenharmony_ci int ret; 8268c2ecf20Sopenharmony_ci 8278c2ecf20Sopenharmony_ci ret = snd_media_start_pipeline(subs); 8288c2ecf20Sopenharmony_ci if (ret) 8298c2ecf20Sopenharmony_ci return ret; 8308c2ecf20Sopenharmony_ci 8318c2ecf20Sopenharmony_ci subs->pcm_format = params_format(hw_params); 8328c2ecf20Sopenharmony_ci subs->period_bytes = params_period_bytes(hw_params); 8338c2ecf20Sopenharmony_ci subs->period_frames = params_period_size(hw_params); 8348c2ecf20Sopenharmony_ci subs->buffer_periods = params_periods(hw_params); 8358c2ecf20Sopenharmony_ci subs->channels = params_channels(hw_params); 8368c2ecf20Sopenharmony_ci subs->cur_rate = params_rate(hw_params); 8378c2ecf20Sopenharmony_ci 8388c2ecf20Sopenharmony_ci fmt = find_format(subs); 8398c2ecf20Sopenharmony_ci if (!fmt) { 8408c2ecf20Sopenharmony_ci dev_dbg(&subs->dev->dev, 8418c2ecf20Sopenharmony_ci "cannot set format: format = %#x, rate = %d, channels = %d\n", 8428c2ecf20Sopenharmony_ci subs->pcm_format, subs->cur_rate, subs->channels); 8438c2ecf20Sopenharmony_ci ret = -EINVAL; 8448c2ecf20Sopenharmony_ci goto stop_pipeline; 8458c2ecf20Sopenharmony_ci } 8468c2ecf20Sopenharmony_ci 8478c2ecf20Sopenharmony_ci ret = snd_usb_lock_shutdown(subs->stream->chip); 8488c2ecf20Sopenharmony_ci if (ret < 0) 8498c2ecf20Sopenharmony_ci goto stop_pipeline; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci ret = snd_usb_pcm_change_state(subs, UAC3_PD_STATE_D0); 8528c2ecf20Sopenharmony_ci if (ret < 0) 8538c2ecf20Sopenharmony_ci goto unlock; 8548c2ecf20Sopenharmony_ci 8558c2ecf20Sopenharmony_ci ret = set_format(subs, fmt); 8568c2ecf20Sopenharmony_ci if (ret < 0) 8578c2ecf20Sopenharmony_ci goto unlock; 8588c2ecf20Sopenharmony_ci 8598c2ecf20Sopenharmony_ci subs->interface = fmt->iface; 8608c2ecf20Sopenharmony_ci subs->altset_idx = fmt->altset_idx; 8618c2ecf20Sopenharmony_ci subs->need_setup_ep = true; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci unlock: 8648c2ecf20Sopenharmony_ci snd_usb_unlock_shutdown(subs->stream->chip); 8658c2ecf20Sopenharmony_ci if (ret < 0) 8668c2ecf20Sopenharmony_ci goto stop_pipeline; 8678c2ecf20Sopenharmony_ci return ret; 8688c2ecf20Sopenharmony_ci 8698c2ecf20Sopenharmony_ci stop_pipeline: 8708c2ecf20Sopenharmony_ci snd_media_stop_pipeline(subs); 8718c2ecf20Sopenharmony_ci return ret; 8728c2ecf20Sopenharmony_ci} 8738c2ecf20Sopenharmony_ci 8748c2ecf20Sopenharmony_ci/* 8758c2ecf20Sopenharmony_ci * hw_free callback 8768c2ecf20Sopenharmony_ci * 8778c2ecf20Sopenharmony_ci * reset the audio format and release the buffer 8788c2ecf20Sopenharmony_ci */ 8798c2ecf20Sopenharmony_cistatic int snd_usb_hw_free(struct snd_pcm_substream *substream) 8808c2ecf20Sopenharmony_ci{ 8818c2ecf20Sopenharmony_ci struct snd_usb_substream *subs = substream->runtime->private_data; 8828c2ecf20Sopenharmony_ci 8838c2ecf20Sopenharmony_ci snd_media_stop_pipeline(subs); 8848c2ecf20Sopenharmony_ci subs->cur_audiofmt = NULL; 8858c2ecf20Sopenharmony_ci subs->cur_rate = 0; 8868c2ecf20Sopenharmony_ci subs->period_bytes = 0; 8878c2ecf20Sopenharmony_ci if (!snd_usb_lock_shutdown(subs->stream->chip)) { 8888c2ecf20Sopenharmony_ci stop_endpoints(subs); 8898c2ecf20Sopenharmony_ci sync_pending_stops(subs); 8908c2ecf20Sopenharmony_ci snd_usb_endpoint_deactivate(subs->sync_endpoint); 8918c2ecf20Sopenharmony_ci snd_usb_endpoint_deactivate(subs->data_endpoint); 8928c2ecf20Sopenharmony_ci snd_usb_unlock_shutdown(subs->stream->chip); 8938c2ecf20Sopenharmony_ci } 8948c2ecf20Sopenharmony_ci 8958c2ecf20Sopenharmony_ci return 0; 8968c2ecf20Sopenharmony_ci} 8978c2ecf20Sopenharmony_ci 8988c2ecf20Sopenharmony_ci/* 8998c2ecf20Sopenharmony_ci * prepare callback 9008c2ecf20Sopenharmony_ci * 9018c2ecf20Sopenharmony_ci * only a few subtle things... 9028c2ecf20Sopenharmony_ci */ 9038c2ecf20Sopenharmony_cistatic int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) 9048c2ecf20Sopenharmony_ci{ 9058c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 9068c2ecf20Sopenharmony_ci struct snd_usb_substream *subs = runtime->private_data; 9078c2ecf20Sopenharmony_ci struct usb_host_interface *alts; 9088c2ecf20Sopenharmony_ci struct usb_interface *iface; 9098c2ecf20Sopenharmony_ci int ret; 9108c2ecf20Sopenharmony_ci 9118c2ecf20Sopenharmony_ci if (! subs->cur_audiofmt) { 9128c2ecf20Sopenharmony_ci dev_err(&subs->dev->dev, "no format is specified!\n"); 9138c2ecf20Sopenharmony_ci return -ENXIO; 9148c2ecf20Sopenharmony_ci } 9158c2ecf20Sopenharmony_ci 9168c2ecf20Sopenharmony_ci ret = snd_usb_lock_shutdown(subs->stream->chip); 9178c2ecf20Sopenharmony_ci if (ret < 0) 9188c2ecf20Sopenharmony_ci return ret; 9198c2ecf20Sopenharmony_ci if (snd_BUG_ON(!subs->data_endpoint)) { 9208c2ecf20Sopenharmony_ci ret = -EIO; 9218c2ecf20Sopenharmony_ci goto unlock; 9228c2ecf20Sopenharmony_ci } 9238c2ecf20Sopenharmony_ci 9248c2ecf20Sopenharmony_ci ret = snd_usb_pcm_change_state(subs, UAC3_PD_STATE_D0); 9258c2ecf20Sopenharmony_ci if (ret < 0) 9268c2ecf20Sopenharmony_ci goto unlock; 9278c2ecf20Sopenharmony_ci 9288c2ecf20Sopenharmony_ci ret = set_format(subs, subs->cur_audiofmt); 9298c2ecf20Sopenharmony_ci if (ret < 0) 9308c2ecf20Sopenharmony_ci goto unlock; 9318c2ecf20Sopenharmony_ci 9328c2ecf20Sopenharmony_ci if (subs->need_setup_ep) { 9338c2ecf20Sopenharmony_ci 9348c2ecf20Sopenharmony_ci iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface); 9358c2ecf20Sopenharmony_ci alts = &iface->altsetting[subs->cur_audiofmt->altset_idx]; 9368c2ecf20Sopenharmony_ci ret = snd_usb_init_sample_rate(subs->stream->chip, 9378c2ecf20Sopenharmony_ci subs->cur_audiofmt->iface, 9388c2ecf20Sopenharmony_ci alts, 9398c2ecf20Sopenharmony_ci subs->cur_audiofmt, 9408c2ecf20Sopenharmony_ci subs->cur_rate); 9418c2ecf20Sopenharmony_ci if (ret < 0) 9428c2ecf20Sopenharmony_ci goto unlock; 9438c2ecf20Sopenharmony_ci 9448c2ecf20Sopenharmony_ci ret = configure_endpoint(subs); 9458c2ecf20Sopenharmony_ci if (ret < 0) 9468c2ecf20Sopenharmony_ci goto unlock; 9478c2ecf20Sopenharmony_ci subs->need_setup_ep = false; 9488c2ecf20Sopenharmony_ci } 9498c2ecf20Sopenharmony_ci 9508c2ecf20Sopenharmony_ci /* some unit conversions in runtime */ 9518c2ecf20Sopenharmony_ci subs->data_endpoint->maxframesize = 9528c2ecf20Sopenharmony_ci bytes_to_frames(runtime, subs->data_endpoint->maxpacksize); 9538c2ecf20Sopenharmony_ci subs->data_endpoint->curframesize = 9548c2ecf20Sopenharmony_ci bytes_to_frames(runtime, subs->data_endpoint->curpacksize); 9558c2ecf20Sopenharmony_ci 9568c2ecf20Sopenharmony_ci /* reset the pointer */ 9578c2ecf20Sopenharmony_ci subs->hwptr_done = 0; 9588c2ecf20Sopenharmony_ci subs->transfer_done = 0; 9598c2ecf20Sopenharmony_ci subs->last_delay = 0; 9608c2ecf20Sopenharmony_ci subs->last_frame_number = 0; 9618c2ecf20Sopenharmony_ci runtime->delay = 0; 9628c2ecf20Sopenharmony_ci 9638c2ecf20Sopenharmony_ci /* for playback, submit the URBs now; otherwise, the first hwptr_done 9648c2ecf20Sopenharmony_ci * updates for all URBs would happen at the same time when starting */ 9658c2ecf20Sopenharmony_ci if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) 9668c2ecf20Sopenharmony_ci ret = start_endpoints(subs); 9678c2ecf20Sopenharmony_ci 9688c2ecf20Sopenharmony_ci unlock: 9698c2ecf20Sopenharmony_ci snd_usb_unlock_shutdown(subs->stream->chip); 9708c2ecf20Sopenharmony_ci return ret; 9718c2ecf20Sopenharmony_ci} 9728c2ecf20Sopenharmony_ci 9738c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware snd_usb_hardware = 9748c2ecf20Sopenharmony_ci{ 9758c2ecf20Sopenharmony_ci .info = SNDRV_PCM_INFO_MMAP | 9768c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 9778c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_BATCH | 9788c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_INTERLEAVED | 9798c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_BLOCK_TRANSFER | 9808c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_PAUSE, 9818c2ecf20Sopenharmony_ci .buffer_bytes_max = 1024 * 1024, 9828c2ecf20Sopenharmony_ci .period_bytes_min = 64, 9838c2ecf20Sopenharmony_ci .period_bytes_max = 512 * 1024, 9848c2ecf20Sopenharmony_ci .periods_min = 2, 9858c2ecf20Sopenharmony_ci .periods_max = 1024, 9868c2ecf20Sopenharmony_ci}; 9878c2ecf20Sopenharmony_ci 9888c2ecf20Sopenharmony_cistatic int hw_check_valid_format(struct snd_usb_substream *subs, 9898c2ecf20Sopenharmony_ci struct snd_pcm_hw_params *params, 9908c2ecf20Sopenharmony_ci struct audioformat *fp) 9918c2ecf20Sopenharmony_ci{ 9928c2ecf20Sopenharmony_ci struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 9938c2ecf20Sopenharmony_ci struct snd_interval *ct = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 9948c2ecf20Sopenharmony_ci struct snd_mask *fmts = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 9958c2ecf20Sopenharmony_ci struct snd_interval *pt = hw_param_interval(params, SNDRV_PCM_HW_PARAM_PERIOD_TIME); 9968c2ecf20Sopenharmony_ci struct snd_mask check_fmts; 9978c2ecf20Sopenharmony_ci unsigned int ptime; 9988c2ecf20Sopenharmony_ci 9998c2ecf20Sopenharmony_ci /* check the format */ 10008c2ecf20Sopenharmony_ci snd_mask_none(&check_fmts); 10018c2ecf20Sopenharmony_ci check_fmts.bits[0] = (u32)fp->formats; 10028c2ecf20Sopenharmony_ci check_fmts.bits[1] = (u32)(fp->formats >> 32); 10038c2ecf20Sopenharmony_ci snd_mask_intersect(&check_fmts, fmts); 10048c2ecf20Sopenharmony_ci if (snd_mask_empty(&check_fmts)) { 10058c2ecf20Sopenharmony_ci hwc_debug(" > check: no supported format %d\n", fp->format); 10068c2ecf20Sopenharmony_ci return 0; 10078c2ecf20Sopenharmony_ci } 10088c2ecf20Sopenharmony_ci /* check the channels */ 10098c2ecf20Sopenharmony_ci if (fp->channels < ct->min || fp->channels > ct->max) { 10108c2ecf20Sopenharmony_ci hwc_debug(" > check: no valid channels %d (%d/%d)\n", fp->channels, ct->min, ct->max); 10118c2ecf20Sopenharmony_ci return 0; 10128c2ecf20Sopenharmony_ci } 10138c2ecf20Sopenharmony_ci /* check the rate is within the range */ 10148c2ecf20Sopenharmony_ci if (fp->rate_min > it->max || (fp->rate_min == it->max && it->openmax)) { 10158c2ecf20Sopenharmony_ci hwc_debug(" > check: rate_min %d > max %d\n", fp->rate_min, it->max); 10168c2ecf20Sopenharmony_ci return 0; 10178c2ecf20Sopenharmony_ci } 10188c2ecf20Sopenharmony_ci if (fp->rate_max < it->min || (fp->rate_max == it->min && it->openmin)) { 10198c2ecf20Sopenharmony_ci hwc_debug(" > check: rate_max %d < min %d\n", fp->rate_max, it->min); 10208c2ecf20Sopenharmony_ci return 0; 10218c2ecf20Sopenharmony_ci } 10228c2ecf20Sopenharmony_ci /* check whether the period time is >= the data packet interval */ 10238c2ecf20Sopenharmony_ci if (subs->speed != USB_SPEED_FULL) { 10248c2ecf20Sopenharmony_ci ptime = 125 * (1 << fp->datainterval); 10258c2ecf20Sopenharmony_ci if (ptime > pt->max || (ptime == pt->max && pt->openmax)) { 10268c2ecf20Sopenharmony_ci hwc_debug(" > check: ptime %u > max %u\n", ptime, pt->max); 10278c2ecf20Sopenharmony_ci return 0; 10288c2ecf20Sopenharmony_ci } 10298c2ecf20Sopenharmony_ci } 10308c2ecf20Sopenharmony_ci return 1; 10318c2ecf20Sopenharmony_ci} 10328c2ecf20Sopenharmony_ci 10338c2ecf20Sopenharmony_cistatic int hw_rule_rate(struct snd_pcm_hw_params *params, 10348c2ecf20Sopenharmony_ci struct snd_pcm_hw_rule *rule) 10358c2ecf20Sopenharmony_ci{ 10368c2ecf20Sopenharmony_ci struct snd_usb_substream *subs = rule->private; 10378c2ecf20Sopenharmony_ci struct audioformat *fp; 10388c2ecf20Sopenharmony_ci struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); 10398c2ecf20Sopenharmony_ci unsigned int rmin, rmax; 10408c2ecf20Sopenharmony_ci int changed; 10418c2ecf20Sopenharmony_ci 10428c2ecf20Sopenharmony_ci hwc_debug("hw_rule_rate: (%d,%d)\n", it->min, it->max); 10438c2ecf20Sopenharmony_ci changed = 0; 10448c2ecf20Sopenharmony_ci rmin = rmax = 0; 10458c2ecf20Sopenharmony_ci list_for_each_entry(fp, &subs->fmt_list, list) { 10468c2ecf20Sopenharmony_ci if (!hw_check_valid_format(subs, params, fp)) 10478c2ecf20Sopenharmony_ci continue; 10488c2ecf20Sopenharmony_ci if (changed++) { 10498c2ecf20Sopenharmony_ci if (rmin > fp->rate_min) 10508c2ecf20Sopenharmony_ci rmin = fp->rate_min; 10518c2ecf20Sopenharmony_ci if (rmax < fp->rate_max) 10528c2ecf20Sopenharmony_ci rmax = fp->rate_max; 10538c2ecf20Sopenharmony_ci } else { 10548c2ecf20Sopenharmony_ci rmin = fp->rate_min; 10558c2ecf20Sopenharmony_ci rmax = fp->rate_max; 10568c2ecf20Sopenharmony_ci } 10578c2ecf20Sopenharmony_ci } 10588c2ecf20Sopenharmony_ci 10598c2ecf20Sopenharmony_ci if (!changed) { 10608c2ecf20Sopenharmony_ci hwc_debug(" --> get empty\n"); 10618c2ecf20Sopenharmony_ci it->empty = 1; 10628c2ecf20Sopenharmony_ci return -EINVAL; 10638c2ecf20Sopenharmony_ci } 10648c2ecf20Sopenharmony_ci 10658c2ecf20Sopenharmony_ci changed = 0; 10668c2ecf20Sopenharmony_ci if (it->min < rmin) { 10678c2ecf20Sopenharmony_ci it->min = rmin; 10688c2ecf20Sopenharmony_ci it->openmin = 0; 10698c2ecf20Sopenharmony_ci changed = 1; 10708c2ecf20Sopenharmony_ci } 10718c2ecf20Sopenharmony_ci if (it->max > rmax) { 10728c2ecf20Sopenharmony_ci it->max = rmax; 10738c2ecf20Sopenharmony_ci it->openmax = 0; 10748c2ecf20Sopenharmony_ci changed = 1; 10758c2ecf20Sopenharmony_ci } 10768c2ecf20Sopenharmony_ci if (snd_interval_checkempty(it)) { 10778c2ecf20Sopenharmony_ci it->empty = 1; 10788c2ecf20Sopenharmony_ci return -EINVAL; 10798c2ecf20Sopenharmony_ci } 10808c2ecf20Sopenharmony_ci hwc_debug(" --> (%d, %d) (changed = %d)\n", it->min, it->max, changed); 10818c2ecf20Sopenharmony_ci return changed; 10828c2ecf20Sopenharmony_ci} 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci 10858c2ecf20Sopenharmony_cistatic int hw_rule_channels(struct snd_pcm_hw_params *params, 10868c2ecf20Sopenharmony_ci struct snd_pcm_hw_rule *rule) 10878c2ecf20Sopenharmony_ci{ 10888c2ecf20Sopenharmony_ci struct snd_usb_substream *subs = rule->private; 10898c2ecf20Sopenharmony_ci struct audioformat *fp; 10908c2ecf20Sopenharmony_ci struct snd_interval *it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); 10918c2ecf20Sopenharmony_ci unsigned int rmin, rmax; 10928c2ecf20Sopenharmony_ci int changed; 10938c2ecf20Sopenharmony_ci 10948c2ecf20Sopenharmony_ci hwc_debug("hw_rule_channels: (%d,%d)\n", it->min, it->max); 10958c2ecf20Sopenharmony_ci changed = 0; 10968c2ecf20Sopenharmony_ci rmin = rmax = 0; 10978c2ecf20Sopenharmony_ci list_for_each_entry(fp, &subs->fmt_list, list) { 10988c2ecf20Sopenharmony_ci if (!hw_check_valid_format(subs, params, fp)) 10998c2ecf20Sopenharmony_ci continue; 11008c2ecf20Sopenharmony_ci if (changed++) { 11018c2ecf20Sopenharmony_ci if (rmin > fp->channels) 11028c2ecf20Sopenharmony_ci rmin = fp->channels; 11038c2ecf20Sopenharmony_ci if (rmax < fp->channels) 11048c2ecf20Sopenharmony_ci rmax = fp->channels; 11058c2ecf20Sopenharmony_ci } else { 11068c2ecf20Sopenharmony_ci rmin = fp->channels; 11078c2ecf20Sopenharmony_ci rmax = fp->channels; 11088c2ecf20Sopenharmony_ci } 11098c2ecf20Sopenharmony_ci } 11108c2ecf20Sopenharmony_ci 11118c2ecf20Sopenharmony_ci if (!changed) { 11128c2ecf20Sopenharmony_ci hwc_debug(" --> get empty\n"); 11138c2ecf20Sopenharmony_ci it->empty = 1; 11148c2ecf20Sopenharmony_ci return -EINVAL; 11158c2ecf20Sopenharmony_ci } 11168c2ecf20Sopenharmony_ci 11178c2ecf20Sopenharmony_ci changed = 0; 11188c2ecf20Sopenharmony_ci if (it->min < rmin) { 11198c2ecf20Sopenharmony_ci it->min = rmin; 11208c2ecf20Sopenharmony_ci it->openmin = 0; 11218c2ecf20Sopenharmony_ci changed = 1; 11228c2ecf20Sopenharmony_ci } 11238c2ecf20Sopenharmony_ci if (it->max > rmax) { 11248c2ecf20Sopenharmony_ci it->max = rmax; 11258c2ecf20Sopenharmony_ci it->openmax = 0; 11268c2ecf20Sopenharmony_ci changed = 1; 11278c2ecf20Sopenharmony_ci } 11288c2ecf20Sopenharmony_ci if (snd_interval_checkempty(it)) { 11298c2ecf20Sopenharmony_ci it->empty = 1; 11308c2ecf20Sopenharmony_ci return -EINVAL; 11318c2ecf20Sopenharmony_ci } 11328c2ecf20Sopenharmony_ci hwc_debug(" --> (%d, %d) (changed = %d)\n", it->min, it->max, changed); 11338c2ecf20Sopenharmony_ci return changed; 11348c2ecf20Sopenharmony_ci} 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_cistatic int hw_rule_format(struct snd_pcm_hw_params *params, 11378c2ecf20Sopenharmony_ci struct snd_pcm_hw_rule *rule) 11388c2ecf20Sopenharmony_ci{ 11398c2ecf20Sopenharmony_ci struct snd_usb_substream *subs = rule->private; 11408c2ecf20Sopenharmony_ci struct audioformat *fp; 11418c2ecf20Sopenharmony_ci struct snd_mask *fmt = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); 11428c2ecf20Sopenharmony_ci u64 fbits; 11438c2ecf20Sopenharmony_ci u32 oldbits[2]; 11448c2ecf20Sopenharmony_ci int changed; 11458c2ecf20Sopenharmony_ci 11468c2ecf20Sopenharmony_ci hwc_debug("hw_rule_format: %x:%x\n", fmt->bits[0], fmt->bits[1]); 11478c2ecf20Sopenharmony_ci fbits = 0; 11488c2ecf20Sopenharmony_ci list_for_each_entry(fp, &subs->fmt_list, list) { 11498c2ecf20Sopenharmony_ci if (!hw_check_valid_format(subs, params, fp)) 11508c2ecf20Sopenharmony_ci continue; 11518c2ecf20Sopenharmony_ci fbits |= fp->formats; 11528c2ecf20Sopenharmony_ci } 11538c2ecf20Sopenharmony_ci 11548c2ecf20Sopenharmony_ci oldbits[0] = fmt->bits[0]; 11558c2ecf20Sopenharmony_ci oldbits[1] = fmt->bits[1]; 11568c2ecf20Sopenharmony_ci fmt->bits[0] &= (u32)fbits; 11578c2ecf20Sopenharmony_ci fmt->bits[1] &= (u32)(fbits >> 32); 11588c2ecf20Sopenharmony_ci if (!fmt->bits[0] && !fmt->bits[1]) { 11598c2ecf20Sopenharmony_ci hwc_debug(" --> get empty\n"); 11608c2ecf20Sopenharmony_ci return -EINVAL; 11618c2ecf20Sopenharmony_ci } 11628c2ecf20Sopenharmony_ci changed = (oldbits[0] != fmt->bits[0] || oldbits[1] != fmt->bits[1]); 11638c2ecf20Sopenharmony_ci hwc_debug(" --> %x:%x (changed = %d)\n", fmt->bits[0], fmt->bits[1], changed); 11648c2ecf20Sopenharmony_ci return changed; 11658c2ecf20Sopenharmony_ci} 11668c2ecf20Sopenharmony_ci 11678c2ecf20Sopenharmony_cistatic int hw_rule_period_time(struct snd_pcm_hw_params *params, 11688c2ecf20Sopenharmony_ci struct snd_pcm_hw_rule *rule) 11698c2ecf20Sopenharmony_ci{ 11708c2ecf20Sopenharmony_ci struct snd_usb_substream *subs = rule->private; 11718c2ecf20Sopenharmony_ci struct audioformat *fp; 11728c2ecf20Sopenharmony_ci struct snd_interval *it; 11738c2ecf20Sopenharmony_ci unsigned char min_datainterval; 11748c2ecf20Sopenharmony_ci unsigned int pmin; 11758c2ecf20Sopenharmony_ci int changed; 11768c2ecf20Sopenharmony_ci 11778c2ecf20Sopenharmony_ci it = hw_param_interval(params, SNDRV_PCM_HW_PARAM_PERIOD_TIME); 11788c2ecf20Sopenharmony_ci hwc_debug("hw_rule_period_time: (%u,%u)\n", it->min, it->max); 11798c2ecf20Sopenharmony_ci min_datainterval = 0xff; 11808c2ecf20Sopenharmony_ci list_for_each_entry(fp, &subs->fmt_list, list) { 11818c2ecf20Sopenharmony_ci if (!hw_check_valid_format(subs, params, fp)) 11828c2ecf20Sopenharmony_ci continue; 11838c2ecf20Sopenharmony_ci min_datainterval = min(min_datainterval, fp->datainterval); 11848c2ecf20Sopenharmony_ci } 11858c2ecf20Sopenharmony_ci if (min_datainterval == 0xff) { 11868c2ecf20Sopenharmony_ci hwc_debug(" --> get empty\n"); 11878c2ecf20Sopenharmony_ci it->empty = 1; 11888c2ecf20Sopenharmony_ci return -EINVAL; 11898c2ecf20Sopenharmony_ci } 11908c2ecf20Sopenharmony_ci pmin = 125 * (1 << min_datainterval); 11918c2ecf20Sopenharmony_ci changed = 0; 11928c2ecf20Sopenharmony_ci if (it->min < pmin) { 11938c2ecf20Sopenharmony_ci it->min = pmin; 11948c2ecf20Sopenharmony_ci it->openmin = 0; 11958c2ecf20Sopenharmony_ci changed = 1; 11968c2ecf20Sopenharmony_ci } 11978c2ecf20Sopenharmony_ci if (snd_interval_checkempty(it)) { 11988c2ecf20Sopenharmony_ci it->empty = 1; 11998c2ecf20Sopenharmony_ci return -EINVAL; 12008c2ecf20Sopenharmony_ci } 12018c2ecf20Sopenharmony_ci hwc_debug(" --> (%u,%u) (changed = %d)\n", it->min, it->max, changed); 12028c2ecf20Sopenharmony_ci return changed; 12038c2ecf20Sopenharmony_ci} 12048c2ecf20Sopenharmony_ci 12058c2ecf20Sopenharmony_ci/* 12068c2ecf20Sopenharmony_ci * If the device supports unusual bit rates, does the request meet these? 12078c2ecf20Sopenharmony_ci */ 12088c2ecf20Sopenharmony_cistatic int snd_usb_pcm_check_knot(struct snd_pcm_runtime *runtime, 12098c2ecf20Sopenharmony_ci struct snd_usb_substream *subs) 12108c2ecf20Sopenharmony_ci{ 12118c2ecf20Sopenharmony_ci struct audioformat *fp; 12128c2ecf20Sopenharmony_ci int *rate_list; 12138c2ecf20Sopenharmony_ci int count = 0, needs_knot = 0; 12148c2ecf20Sopenharmony_ci int err; 12158c2ecf20Sopenharmony_ci 12168c2ecf20Sopenharmony_ci kfree(subs->rate_list.list); 12178c2ecf20Sopenharmony_ci subs->rate_list.list = NULL; 12188c2ecf20Sopenharmony_ci 12198c2ecf20Sopenharmony_ci list_for_each_entry(fp, &subs->fmt_list, list) { 12208c2ecf20Sopenharmony_ci if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) 12218c2ecf20Sopenharmony_ci return 0; 12228c2ecf20Sopenharmony_ci count += fp->nr_rates; 12238c2ecf20Sopenharmony_ci if (fp->rates & SNDRV_PCM_RATE_KNOT) 12248c2ecf20Sopenharmony_ci needs_knot = 1; 12258c2ecf20Sopenharmony_ci } 12268c2ecf20Sopenharmony_ci if (!needs_knot) 12278c2ecf20Sopenharmony_ci return 0; 12288c2ecf20Sopenharmony_ci 12298c2ecf20Sopenharmony_ci subs->rate_list.list = rate_list = 12308c2ecf20Sopenharmony_ci kmalloc_array(count, sizeof(int), GFP_KERNEL); 12318c2ecf20Sopenharmony_ci if (!subs->rate_list.list) 12328c2ecf20Sopenharmony_ci return -ENOMEM; 12338c2ecf20Sopenharmony_ci subs->rate_list.count = count; 12348c2ecf20Sopenharmony_ci subs->rate_list.mask = 0; 12358c2ecf20Sopenharmony_ci count = 0; 12368c2ecf20Sopenharmony_ci list_for_each_entry(fp, &subs->fmt_list, list) { 12378c2ecf20Sopenharmony_ci int i; 12388c2ecf20Sopenharmony_ci for (i = 0; i < fp->nr_rates; i++) 12398c2ecf20Sopenharmony_ci rate_list[count++] = fp->rate_table[i]; 12408c2ecf20Sopenharmony_ci } 12418c2ecf20Sopenharmony_ci err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 12428c2ecf20Sopenharmony_ci &subs->rate_list); 12438c2ecf20Sopenharmony_ci if (err < 0) 12448c2ecf20Sopenharmony_ci return err; 12458c2ecf20Sopenharmony_ci 12468c2ecf20Sopenharmony_ci return 0; 12478c2ecf20Sopenharmony_ci} 12488c2ecf20Sopenharmony_ci 12498c2ecf20Sopenharmony_ci 12508c2ecf20Sopenharmony_ci/* 12518c2ecf20Sopenharmony_ci * set up the runtime hardware information. 12528c2ecf20Sopenharmony_ci */ 12538c2ecf20Sopenharmony_ci 12548c2ecf20Sopenharmony_cistatic int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substream *subs) 12558c2ecf20Sopenharmony_ci{ 12568c2ecf20Sopenharmony_ci struct audioformat *fp; 12578c2ecf20Sopenharmony_ci unsigned int pt, ptmin; 12588c2ecf20Sopenharmony_ci int param_period_time_if_needed; 12598c2ecf20Sopenharmony_ci int err; 12608c2ecf20Sopenharmony_ci 12618c2ecf20Sopenharmony_ci runtime->hw.formats = subs->formats; 12628c2ecf20Sopenharmony_ci 12638c2ecf20Sopenharmony_ci runtime->hw.rate_min = 0x7fffffff; 12648c2ecf20Sopenharmony_ci runtime->hw.rate_max = 0; 12658c2ecf20Sopenharmony_ci runtime->hw.channels_min = 256; 12668c2ecf20Sopenharmony_ci runtime->hw.channels_max = 0; 12678c2ecf20Sopenharmony_ci runtime->hw.rates = 0; 12688c2ecf20Sopenharmony_ci ptmin = UINT_MAX; 12698c2ecf20Sopenharmony_ci /* check min/max rates and channels */ 12708c2ecf20Sopenharmony_ci list_for_each_entry(fp, &subs->fmt_list, list) { 12718c2ecf20Sopenharmony_ci runtime->hw.rates |= fp->rates; 12728c2ecf20Sopenharmony_ci if (runtime->hw.rate_min > fp->rate_min) 12738c2ecf20Sopenharmony_ci runtime->hw.rate_min = fp->rate_min; 12748c2ecf20Sopenharmony_ci if (runtime->hw.rate_max < fp->rate_max) 12758c2ecf20Sopenharmony_ci runtime->hw.rate_max = fp->rate_max; 12768c2ecf20Sopenharmony_ci if (runtime->hw.channels_min > fp->channels) 12778c2ecf20Sopenharmony_ci runtime->hw.channels_min = fp->channels; 12788c2ecf20Sopenharmony_ci if (runtime->hw.channels_max < fp->channels) 12798c2ecf20Sopenharmony_ci runtime->hw.channels_max = fp->channels; 12808c2ecf20Sopenharmony_ci if (fp->fmt_type == UAC_FORMAT_TYPE_II && fp->frame_size > 0) { 12818c2ecf20Sopenharmony_ci /* FIXME: there might be more than one audio formats... */ 12828c2ecf20Sopenharmony_ci runtime->hw.period_bytes_min = runtime->hw.period_bytes_max = 12838c2ecf20Sopenharmony_ci fp->frame_size; 12848c2ecf20Sopenharmony_ci } 12858c2ecf20Sopenharmony_ci pt = 125 * (1 << fp->datainterval); 12868c2ecf20Sopenharmony_ci ptmin = min(ptmin, pt); 12878c2ecf20Sopenharmony_ci } 12888c2ecf20Sopenharmony_ci 12898c2ecf20Sopenharmony_ci param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; 12908c2ecf20Sopenharmony_ci if (subs->speed == USB_SPEED_FULL) 12918c2ecf20Sopenharmony_ci /* full speed devices have fixed data packet interval */ 12928c2ecf20Sopenharmony_ci ptmin = 1000; 12938c2ecf20Sopenharmony_ci if (ptmin == 1000) 12948c2ecf20Sopenharmony_ci /* if period time doesn't go below 1 ms, no rules needed */ 12958c2ecf20Sopenharmony_ci param_period_time_if_needed = -1; 12968c2ecf20Sopenharmony_ci 12978c2ecf20Sopenharmony_ci err = snd_pcm_hw_constraint_minmax(runtime, 12988c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIOD_TIME, 12998c2ecf20Sopenharmony_ci ptmin, UINT_MAX); 13008c2ecf20Sopenharmony_ci if (err < 0) 13018c2ecf20Sopenharmony_ci return err; 13028c2ecf20Sopenharmony_ci 13038c2ecf20Sopenharmony_ci err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, 13048c2ecf20Sopenharmony_ci hw_rule_rate, subs, 13058c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_FORMAT, 13068c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, 13078c2ecf20Sopenharmony_ci param_period_time_if_needed, 13088c2ecf20Sopenharmony_ci -1); 13098c2ecf20Sopenharmony_ci if (err < 0) 13108c2ecf20Sopenharmony_ci return err; 13118c2ecf20Sopenharmony_ci err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 13128c2ecf20Sopenharmony_ci hw_rule_channels, subs, 13138c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_FORMAT, 13148c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, 13158c2ecf20Sopenharmony_ci param_period_time_if_needed, 13168c2ecf20Sopenharmony_ci -1); 13178c2ecf20Sopenharmony_ci if (err < 0) 13188c2ecf20Sopenharmony_ci return err; 13198c2ecf20Sopenharmony_ci err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, 13208c2ecf20Sopenharmony_ci hw_rule_format, subs, 13218c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, 13228c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, 13238c2ecf20Sopenharmony_ci param_period_time_if_needed, 13248c2ecf20Sopenharmony_ci -1); 13258c2ecf20Sopenharmony_ci if (err < 0) 13268c2ecf20Sopenharmony_ci return err; 13278c2ecf20Sopenharmony_ci if (param_period_time_if_needed >= 0) { 13288c2ecf20Sopenharmony_ci err = snd_pcm_hw_rule_add(runtime, 0, 13298c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_PERIOD_TIME, 13308c2ecf20Sopenharmony_ci hw_rule_period_time, subs, 13318c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_FORMAT, 13328c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_CHANNELS, 13338c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, 13348c2ecf20Sopenharmony_ci -1); 13358c2ecf20Sopenharmony_ci if (err < 0) 13368c2ecf20Sopenharmony_ci return err; 13378c2ecf20Sopenharmony_ci } 13388c2ecf20Sopenharmony_ci err = snd_usb_pcm_check_knot(runtime, subs); 13398c2ecf20Sopenharmony_ci if (err < 0) 13408c2ecf20Sopenharmony_ci return err; 13418c2ecf20Sopenharmony_ci 13428c2ecf20Sopenharmony_ci return snd_usb_autoresume(subs->stream->chip); 13438c2ecf20Sopenharmony_ci} 13448c2ecf20Sopenharmony_ci 13458c2ecf20Sopenharmony_cistatic int snd_usb_pcm_open(struct snd_pcm_substream *substream) 13468c2ecf20Sopenharmony_ci{ 13478c2ecf20Sopenharmony_ci int direction = substream->stream; 13488c2ecf20Sopenharmony_ci struct snd_usb_stream *as = snd_pcm_substream_chip(substream); 13498c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = substream->runtime; 13508c2ecf20Sopenharmony_ci struct snd_usb_substream *subs = &as->substream[direction]; 13518c2ecf20Sopenharmony_ci int ret; 13528c2ecf20Sopenharmony_ci 13538c2ecf20Sopenharmony_ci subs->interface = -1; 13548c2ecf20Sopenharmony_ci subs->altset_idx = 0; 13558c2ecf20Sopenharmony_ci runtime->hw = snd_usb_hardware; 13568c2ecf20Sopenharmony_ci runtime->private_data = subs; 13578c2ecf20Sopenharmony_ci subs->pcm_substream = substream; 13588c2ecf20Sopenharmony_ci /* runtime PM is also done there */ 13598c2ecf20Sopenharmony_ci 13608c2ecf20Sopenharmony_ci /* initialize DSD/DOP context */ 13618c2ecf20Sopenharmony_ci subs->dsd_dop.byte_idx = 0; 13628c2ecf20Sopenharmony_ci subs->dsd_dop.channel = 0; 13638c2ecf20Sopenharmony_ci subs->dsd_dop.marker = 1; 13648c2ecf20Sopenharmony_ci 13658c2ecf20Sopenharmony_ci ret = setup_hw_info(runtime, subs); 13668c2ecf20Sopenharmony_ci if (ret == 0) { 13678c2ecf20Sopenharmony_ci ret = snd_media_stream_init(subs, as->pcm, direction); 13688c2ecf20Sopenharmony_ci if (ret) 13698c2ecf20Sopenharmony_ci snd_usb_autosuspend(subs->stream->chip); 13708c2ecf20Sopenharmony_ci } 13718c2ecf20Sopenharmony_ci return ret; 13728c2ecf20Sopenharmony_ci} 13738c2ecf20Sopenharmony_ci 13748c2ecf20Sopenharmony_cistatic int snd_usb_pcm_close(struct snd_pcm_substream *substream) 13758c2ecf20Sopenharmony_ci{ 13768c2ecf20Sopenharmony_ci int direction = substream->stream; 13778c2ecf20Sopenharmony_ci struct snd_usb_stream *as = snd_pcm_substream_chip(substream); 13788c2ecf20Sopenharmony_ci struct snd_usb_substream *subs = &as->substream[direction]; 13798c2ecf20Sopenharmony_ci int ret; 13808c2ecf20Sopenharmony_ci 13818c2ecf20Sopenharmony_ci snd_media_stop_pipeline(subs); 13828c2ecf20Sopenharmony_ci 13838c2ecf20Sopenharmony_ci if (!as->chip->keep_iface && 13848c2ecf20Sopenharmony_ci subs->interface >= 0 && 13858c2ecf20Sopenharmony_ci !snd_usb_lock_shutdown(subs->stream->chip)) { 13868c2ecf20Sopenharmony_ci usb_set_interface(subs->dev, subs->interface, 0); 13878c2ecf20Sopenharmony_ci subs->interface = -1; 13888c2ecf20Sopenharmony_ci ret = snd_usb_pcm_change_state(subs, UAC3_PD_STATE_D1); 13898c2ecf20Sopenharmony_ci snd_usb_unlock_shutdown(subs->stream->chip); 13908c2ecf20Sopenharmony_ci if (ret < 0) 13918c2ecf20Sopenharmony_ci return ret; 13928c2ecf20Sopenharmony_ci } 13938c2ecf20Sopenharmony_ci 13948c2ecf20Sopenharmony_ci subs->pcm_substream = NULL; 13958c2ecf20Sopenharmony_ci snd_usb_autosuspend(subs->stream->chip); 13968c2ecf20Sopenharmony_ci 13978c2ecf20Sopenharmony_ci return 0; 13988c2ecf20Sopenharmony_ci} 13998c2ecf20Sopenharmony_ci 14008c2ecf20Sopenharmony_ci/* Since a URB can handle only a single linear buffer, we must use double 14018c2ecf20Sopenharmony_ci * buffering when the data to be transferred overflows the buffer boundary. 14028c2ecf20Sopenharmony_ci * To avoid inconsistencies when updating hwptr_done, we use double buffering 14038c2ecf20Sopenharmony_ci * for all URBs. 14048c2ecf20Sopenharmony_ci */ 14058c2ecf20Sopenharmony_cistatic void retire_capture_urb(struct snd_usb_substream *subs, 14068c2ecf20Sopenharmony_ci struct urb *urb) 14078c2ecf20Sopenharmony_ci{ 14088c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; 14098c2ecf20Sopenharmony_ci unsigned int stride, frames, bytes, oldptr; 14108c2ecf20Sopenharmony_ci int i, period_elapsed = 0; 14118c2ecf20Sopenharmony_ci unsigned long flags; 14128c2ecf20Sopenharmony_ci unsigned char *cp; 14138c2ecf20Sopenharmony_ci int current_frame_number; 14148c2ecf20Sopenharmony_ci 14158c2ecf20Sopenharmony_ci /* read frame number here, update pointer in critical section */ 14168c2ecf20Sopenharmony_ci current_frame_number = usb_get_current_frame_number(subs->dev); 14178c2ecf20Sopenharmony_ci 14188c2ecf20Sopenharmony_ci stride = runtime->frame_bits >> 3; 14198c2ecf20Sopenharmony_ci 14208c2ecf20Sopenharmony_ci for (i = 0; i < urb->number_of_packets; i++) { 14218c2ecf20Sopenharmony_ci cp = (unsigned char *)urb->transfer_buffer + urb->iso_frame_desc[i].offset + subs->pkt_offset_adj; 14228c2ecf20Sopenharmony_ci if (urb->iso_frame_desc[i].status && printk_ratelimit()) { 14238c2ecf20Sopenharmony_ci dev_dbg(&subs->dev->dev, "frame %d active: %d\n", 14248c2ecf20Sopenharmony_ci i, urb->iso_frame_desc[i].status); 14258c2ecf20Sopenharmony_ci // continue; 14268c2ecf20Sopenharmony_ci } 14278c2ecf20Sopenharmony_ci bytes = urb->iso_frame_desc[i].actual_length; 14288c2ecf20Sopenharmony_ci if (subs->stream_offset_adj > 0) { 14298c2ecf20Sopenharmony_ci unsigned int adj = min(subs->stream_offset_adj, bytes); 14308c2ecf20Sopenharmony_ci cp += adj; 14318c2ecf20Sopenharmony_ci bytes -= adj; 14328c2ecf20Sopenharmony_ci subs->stream_offset_adj -= adj; 14338c2ecf20Sopenharmony_ci } 14348c2ecf20Sopenharmony_ci frames = bytes / stride; 14358c2ecf20Sopenharmony_ci if (!subs->txfr_quirk) 14368c2ecf20Sopenharmony_ci bytes = frames * stride; 14378c2ecf20Sopenharmony_ci if (bytes % (runtime->sample_bits >> 3) != 0) { 14388c2ecf20Sopenharmony_ci int oldbytes = bytes; 14398c2ecf20Sopenharmony_ci bytes = frames * stride; 14408c2ecf20Sopenharmony_ci dev_warn_ratelimited(&subs->dev->dev, 14418c2ecf20Sopenharmony_ci "Corrected urb data len. %d->%d\n", 14428c2ecf20Sopenharmony_ci oldbytes, bytes); 14438c2ecf20Sopenharmony_ci } 14448c2ecf20Sopenharmony_ci /* update the current pointer */ 14458c2ecf20Sopenharmony_ci spin_lock_irqsave(&subs->lock, flags); 14468c2ecf20Sopenharmony_ci oldptr = subs->hwptr_done; 14478c2ecf20Sopenharmony_ci subs->hwptr_done += bytes; 14488c2ecf20Sopenharmony_ci if (subs->hwptr_done >= runtime->buffer_size * stride) 14498c2ecf20Sopenharmony_ci subs->hwptr_done -= runtime->buffer_size * stride; 14508c2ecf20Sopenharmony_ci frames = (bytes + (oldptr % stride)) / stride; 14518c2ecf20Sopenharmony_ci subs->transfer_done += frames; 14528c2ecf20Sopenharmony_ci if (subs->transfer_done >= runtime->period_size) { 14538c2ecf20Sopenharmony_ci subs->transfer_done -= runtime->period_size; 14548c2ecf20Sopenharmony_ci period_elapsed = 1; 14558c2ecf20Sopenharmony_ci } 14568c2ecf20Sopenharmony_ci /* capture delay is by construction limited to one URB, 14578c2ecf20Sopenharmony_ci * reset delays here 14588c2ecf20Sopenharmony_ci */ 14598c2ecf20Sopenharmony_ci runtime->delay = subs->last_delay = 0; 14608c2ecf20Sopenharmony_ci 14618c2ecf20Sopenharmony_ci /* realign last_frame_number */ 14628c2ecf20Sopenharmony_ci subs->last_frame_number = current_frame_number; 14638c2ecf20Sopenharmony_ci subs->last_frame_number &= 0xFF; /* keep 8 LSBs */ 14648c2ecf20Sopenharmony_ci 14658c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&subs->lock, flags); 14668c2ecf20Sopenharmony_ci /* copy a data chunk */ 14678c2ecf20Sopenharmony_ci if (oldptr + bytes > runtime->buffer_size * stride) { 14688c2ecf20Sopenharmony_ci unsigned int bytes1 = 14698c2ecf20Sopenharmony_ci runtime->buffer_size * stride - oldptr; 14708c2ecf20Sopenharmony_ci memcpy(runtime->dma_area + oldptr, cp, bytes1); 14718c2ecf20Sopenharmony_ci memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1); 14728c2ecf20Sopenharmony_ci } else { 14738c2ecf20Sopenharmony_ci memcpy(runtime->dma_area + oldptr, cp, bytes); 14748c2ecf20Sopenharmony_ci } 14758c2ecf20Sopenharmony_ci } 14768c2ecf20Sopenharmony_ci 14778c2ecf20Sopenharmony_ci if (period_elapsed) 14788c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(subs->pcm_substream); 14798c2ecf20Sopenharmony_ci} 14808c2ecf20Sopenharmony_ci 14818c2ecf20Sopenharmony_cistatic inline void fill_playback_urb_dsd_dop(struct snd_usb_substream *subs, 14828c2ecf20Sopenharmony_ci struct urb *urb, unsigned int bytes) 14838c2ecf20Sopenharmony_ci{ 14848c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; 14858c2ecf20Sopenharmony_ci unsigned int stride = runtime->frame_bits >> 3; 14868c2ecf20Sopenharmony_ci unsigned int dst_idx = 0; 14878c2ecf20Sopenharmony_ci unsigned int src_idx = subs->hwptr_done; 14888c2ecf20Sopenharmony_ci unsigned int wrap = runtime->buffer_size * stride; 14898c2ecf20Sopenharmony_ci u8 *dst = urb->transfer_buffer; 14908c2ecf20Sopenharmony_ci u8 *src = runtime->dma_area; 14918c2ecf20Sopenharmony_ci u8 marker[] = { 0x05, 0xfa }; 14928c2ecf20Sopenharmony_ci 14938c2ecf20Sopenharmony_ci /* 14948c2ecf20Sopenharmony_ci * The DSP DOP format defines a way to transport DSD samples over 14958c2ecf20Sopenharmony_ci * normal PCM data endpoints. It requires stuffing of marker bytes 14968c2ecf20Sopenharmony_ci * (0x05 and 0xfa, alternating per sample frame), and then expects 14978c2ecf20Sopenharmony_ci * 2 additional bytes of actual payload. The whole frame is stored 14988c2ecf20Sopenharmony_ci * LSB. 14998c2ecf20Sopenharmony_ci * 15008c2ecf20Sopenharmony_ci * Hence, for a stereo transport, the buffer layout looks like this, 15018c2ecf20Sopenharmony_ci * where L refers to left channel samples and R to right. 15028c2ecf20Sopenharmony_ci * 15038c2ecf20Sopenharmony_ci * L1 L2 0x05 R1 R2 0x05 L3 L4 0xfa R3 R4 0xfa 15048c2ecf20Sopenharmony_ci * L5 L6 0x05 R5 R6 0x05 L7 L8 0xfa R7 R8 0xfa 15058c2ecf20Sopenharmony_ci * ..... 15068c2ecf20Sopenharmony_ci * 15078c2ecf20Sopenharmony_ci */ 15088c2ecf20Sopenharmony_ci 15098c2ecf20Sopenharmony_ci while (bytes--) { 15108c2ecf20Sopenharmony_ci if (++subs->dsd_dop.byte_idx == 3) { 15118c2ecf20Sopenharmony_ci /* frame boundary? */ 15128c2ecf20Sopenharmony_ci dst[dst_idx++] = marker[subs->dsd_dop.marker]; 15138c2ecf20Sopenharmony_ci src_idx += 2; 15148c2ecf20Sopenharmony_ci subs->dsd_dop.byte_idx = 0; 15158c2ecf20Sopenharmony_ci 15168c2ecf20Sopenharmony_ci if (++subs->dsd_dop.channel % runtime->channels == 0) { 15178c2ecf20Sopenharmony_ci /* alternate the marker */ 15188c2ecf20Sopenharmony_ci subs->dsd_dop.marker++; 15198c2ecf20Sopenharmony_ci subs->dsd_dop.marker %= ARRAY_SIZE(marker); 15208c2ecf20Sopenharmony_ci subs->dsd_dop.channel = 0; 15218c2ecf20Sopenharmony_ci } 15228c2ecf20Sopenharmony_ci } else { 15238c2ecf20Sopenharmony_ci /* stuff the DSD payload */ 15248c2ecf20Sopenharmony_ci int idx = (src_idx + subs->dsd_dop.byte_idx - 1) % wrap; 15258c2ecf20Sopenharmony_ci 15268c2ecf20Sopenharmony_ci if (subs->cur_audiofmt->dsd_bitrev) 15278c2ecf20Sopenharmony_ci dst[dst_idx++] = bitrev8(src[idx]); 15288c2ecf20Sopenharmony_ci else 15298c2ecf20Sopenharmony_ci dst[dst_idx++] = src[idx]; 15308c2ecf20Sopenharmony_ci 15318c2ecf20Sopenharmony_ci subs->hwptr_done++; 15328c2ecf20Sopenharmony_ci } 15338c2ecf20Sopenharmony_ci } 15348c2ecf20Sopenharmony_ci if (subs->hwptr_done >= runtime->buffer_size * stride) 15358c2ecf20Sopenharmony_ci subs->hwptr_done -= runtime->buffer_size * stride; 15368c2ecf20Sopenharmony_ci} 15378c2ecf20Sopenharmony_ci 15388c2ecf20Sopenharmony_cistatic void copy_to_urb(struct snd_usb_substream *subs, struct urb *urb, 15398c2ecf20Sopenharmony_ci int offset, int stride, unsigned int bytes) 15408c2ecf20Sopenharmony_ci{ 15418c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; 15428c2ecf20Sopenharmony_ci 15438c2ecf20Sopenharmony_ci if (subs->hwptr_done + bytes > runtime->buffer_size * stride) { 15448c2ecf20Sopenharmony_ci /* err, the transferred area goes over buffer boundary. */ 15458c2ecf20Sopenharmony_ci unsigned int bytes1 = 15468c2ecf20Sopenharmony_ci runtime->buffer_size * stride - subs->hwptr_done; 15478c2ecf20Sopenharmony_ci memcpy(urb->transfer_buffer + offset, 15488c2ecf20Sopenharmony_ci runtime->dma_area + subs->hwptr_done, bytes1); 15498c2ecf20Sopenharmony_ci memcpy(urb->transfer_buffer + offset + bytes1, 15508c2ecf20Sopenharmony_ci runtime->dma_area, bytes - bytes1); 15518c2ecf20Sopenharmony_ci } else { 15528c2ecf20Sopenharmony_ci memcpy(urb->transfer_buffer + offset, 15538c2ecf20Sopenharmony_ci runtime->dma_area + subs->hwptr_done, bytes); 15548c2ecf20Sopenharmony_ci } 15558c2ecf20Sopenharmony_ci subs->hwptr_done += bytes; 15568c2ecf20Sopenharmony_ci if (subs->hwptr_done >= runtime->buffer_size * stride) 15578c2ecf20Sopenharmony_ci subs->hwptr_done -= runtime->buffer_size * stride; 15588c2ecf20Sopenharmony_ci} 15598c2ecf20Sopenharmony_ci 15608c2ecf20Sopenharmony_cistatic unsigned int copy_to_urb_quirk(struct snd_usb_substream *subs, 15618c2ecf20Sopenharmony_ci struct urb *urb, int stride, 15628c2ecf20Sopenharmony_ci unsigned int bytes) 15638c2ecf20Sopenharmony_ci{ 15648c2ecf20Sopenharmony_ci __le32 packet_length; 15658c2ecf20Sopenharmony_ci int i; 15668c2ecf20Sopenharmony_ci 15678c2ecf20Sopenharmony_ci /* Put __le32 length descriptor at start of each packet. */ 15688c2ecf20Sopenharmony_ci for (i = 0; i < urb->number_of_packets; i++) { 15698c2ecf20Sopenharmony_ci unsigned int length = urb->iso_frame_desc[i].length; 15708c2ecf20Sopenharmony_ci unsigned int offset = urb->iso_frame_desc[i].offset; 15718c2ecf20Sopenharmony_ci 15728c2ecf20Sopenharmony_ci packet_length = cpu_to_le32(length); 15738c2ecf20Sopenharmony_ci offset += i * sizeof(packet_length); 15748c2ecf20Sopenharmony_ci urb->iso_frame_desc[i].offset = offset; 15758c2ecf20Sopenharmony_ci urb->iso_frame_desc[i].length += sizeof(packet_length); 15768c2ecf20Sopenharmony_ci memcpy(urb->transfer_buffer + offset, 15778c2ecf20Sopenharmony_ci &packet_length, sizeof(packet_length)); 15788c2ecf20Sopenharmony_ci copy_to_urb(subs, urb, offset + sizeof(packet_length), 15798c2ecf20Sopenharmony_ci stride, length); 15808c2ecf20Sopenharmony_ci } 15818c2ecf20Sopenharmony_ci /* Adjust transfer size accordingly. */ 15828c2ecf20Sopenharmony_ci bytes += urb->number_of_packets * sizeof(packet_length); 15838c2ecf20Sopenharmony_ci return bytes; 15848c2ecf20Sopenharmony_ci} 15858c2ecf20Sopenharmony_ci 15868c2ecf20Sopenharmony_cistatic void prepare_playback_urb(struct snd_usb_substream *subs, 15878c2ecf20Sopenharmony_ci struct urb *urb) 15888c2ecf20Sopenharmony_ci{ 15898c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; 15908c2ecf20Sopenharmony_ci struct snd_usb_endpoint *ep = subs->data_endpoint; 15918c2ecf20Sopenharmony_ci struct snd_urb_ctx *ctx = urb->context; 15928c2ecf20Sopenharmony_ci unsigned int counts, frames, bytes; 15938c2ecf20Sopenharmony_ci int i, stride, period_elapsed = 0; 15948c2ecf20Sopenharmony_ci unsigned long flags; 15958c2ecf20Sopenharmony_ci 15968c2ecf20Sopenharmony_ci stride = runtime->frame_bits >> 3; 15978c2ecf20Sopenharmony_ci 15988c2ecf20Sopenharmony_ci frames = 0; 15998c2ecf20Sopenharmony_ci urb->number_of_packets = 0; 16008c2ecf20Sopenharmony_ci spin_lock_irqsave(&subs->lock, flags); 16018c2ecf20Sopenharmony_ci subs->frame_limit += ep->max_urb_frames; 16028c2ecf20Sopenharmony_ci for (i = 0; i < ctx->packets; i++) { 16038c2ecf20Sopenharmony_ci if (ctx->packet_size[i]) 16048c2ecf20Sopenharmony_ci counts = ctx->packet_size[i]; 16058c2ecf20Sopenharmony_ci else if (ep->sync_master) 16068c2ecf20Sopenharmony_ci counts = snd_usb_endpoint_slave_next_packet_size(ep); 16078c2ecf20Sopenharmony_ci else 16088c2ecf20Sopenharmony_ci counts = snd_usb_endpoint_next_packet_size(ep); 16098c2ecf20Sopenharmony_ci 16108c2ecf20Sopenharmony_ci /* set up descriptor */ 16118c2ecf20Sopenharmony_ci urb->iso_frame_desc[i].offset = frames * ep->stride; 16128c2ecf20Sopenharmony_ci urb->iso_frame_desc[i].length = counts * ep->stride; 16138c2ecf20Sopenharmony_ci frames += counts; 16148c2ecf20Sopenharmony_ci urb->number_of_packets++; 16158c2ecf20Sopenharmony_ci subs->transfer_done += counts; 16168c2ecf20Sopenharmony_ci if (subs->transfer_done >= runtime->period_size) { 16178c2ecf20Sopenharmony_ci subs->transfer_done -= runtime->period_size; 16188c2ecf20Sopenharmony_ci subs->frame_limit = 0; 16198c2ecf20Sopenharmony_ci period_elapsed = 1; 16208c2ecf20Sopenharmony_ci if (subs->fmt_type == UAC_FORMAT_TYPE_II) { 16218c2ecf20Sopenharmony_ci if (subs->transfer_done > 0) { 16228c2ecf20Sopenharmony_ci /* FIXME: fill-max mode is not 16238c2ecf20Sopenharmony_ci * supported yet */ 16248c2ecf20Sopenharmony_ci frames -= subs->transfer_done; 16258c2ecf20Sopenharmony_ci counts -= subs->transfer_done; 16268c2ecf20Sopenharmony_ci urb->iso_frame_desc[i].length = 16278c2ecf20Sopenharmony_ci counts * ep->stride; 16288c2ecf20Sopenharmony_ci subs->transfer_done = 0; 16298c2ecf20Sopenharmony_ci } 16308c2ecf20Sopenharmony_ci i++; 16318c2ecf20Sopenharmony_ci if (i < ctx->packets) { 16328c2ecf20Sopenharmony_ci /* add a transfer delimiter */ 16338c2ecf20Sopenharmony_ci urb->iso_frame_desc[i].offset = 16348c2ecf20Sopenharmony_ci frames * ep->stride; 16358c2ecf20Sopenharmony_ci urb->iso_frame_desc[i].length = 0; 16368c2ecf20Sopenharmony_ci urb->number_of_packets++; 16378c2ecf20Sopenharmony_ci } 16388c2ecf20Sopenharmony_ci break; 16398c2ecf20Sopenharmony_ci } 16408c2ecf20Sopenharmony_ci } 16418c2ecf20Sopenharmony_ci /* finish at the period boundary or after enough frames */ 16428c2ecf20Sopenharmony_ci if ((period_elapsed || 16438c2ecf20Sopenharmony_ci subs->transfer_done >= subs->frame_limit) && 16448c2ecf20Sopenharmony_ci !snd_usb_endpoint_implicit_feedback_sink(ep)) 16458c2ecf20Sopenharmony_ci break; 16468c2ecf20Sopenharmony_ci } 16478c2ecf20Sopenharmony_ci bytes = frames * ep->stride; 16488c2ecf20Sopenharmony_ci 16498c2ecf20Sopenharmony_ci if (unlikely(subs->pcm_format == SNDRV_PCM_FORMAT_DSD_U16_LE && 16508c2ecf20Sopenharmony_ci subs->cur_audiofmt->dsd_dop)) { 16518c2ecf20Sopenharmony_ci fill_playback_urb_dsd_dop(subs, urb, bytes); 16528c2ecf20Sopenharmony_ci } else if (unlikely(subs->pcm_format == SNDRV_PCM_FORMAT_DSD_U8 && 16538c2ecf20Sopenharmony_ci subs->cur_audiofmt->dsd_bitrev)) { 16548c2ecf20Sopenharmony_ci /* bit-reverse the bytes */ 16558c2ecf20Sopenharmony_ci u8 *buf = urb->transfer_buffer; 16568c2ecf20Sopenharmony_ci for (i = 0; i < bytes; i++) { 16578c2ecf20Sopenharmony_ci int idx = (subs->hwptr_done + i) 16588c2ecf20Sopenharmony_ci % (runtime->buffer_size * stride); 16598c2ecf20Sopenharmony_ci buf[i] = bitrev8(runtime->dma_area[idx]); 16608c2ecf20Sopenharmony_ci } 16618c2ecf20Sopenharmony_ci 16628c2ecf20Sopenharmony_ci subs->hwptr_done += bytes; 16638c2ecf20Sopenharmony_ci if (subs->hwptr_done >= runtime->buffer_size * stride) 16648c2ecf20Sopenharmony_ci subs->hwptr_done -= runtime->buffer_size * stride; 16658c2ecf20Sopenharmony_ci } else { 16668c2ecf20Sopenharmony_ci /* usual PCM */ 16678c2ecf20Sopenharmony_ci if (!subs->tx_length_quirk) 16688c2ecf20Sopenharmony_ci copy_to_urb(subs, urb, 0, stride, bytes); 16698c2ecf20Sopenharmony_ci else 16708c2ecf20Sopenharmony_ci bytes = copy_to_urb_quirk(subs, urb, stride, bytes); 16718c2ecf20Sopenharmony_ci /* bytes is now amount of outgoing data */ 16728c2ecf20Sopenharmony_ci } 16738c2ecf20Sopenharmony_ci 16748c2ecf20Sopenharmony_ci /* update delay with exact number of samples queued */ 16758c2ecf20Sopenharmony_ci runtime->delay = subs->last_delay; 16768c2ecf20Sopenharmony_ci runtime->delay += frames; 16778c2ecf20Sopenharmony_ci subs->last_delay = runtime->delay; 16788c2ecf20Sopenharmony_ci 16798c2ecf20Sopenharmony_ci /* realign last_frame_number */ 16808c2ecf20Sopenharmony_ci subs->last_frame_number = usb_get_current_frame_number(subs->dev); 16818c2ecf20Sopenharmony_ci subs->last_frame_number &= 0xFF; /* keep 8 LSBs */ 16828c2ecf20Sopenharmony_ci 16838c2ecf20Sopenharmony_ci if (subs->trigger_tstamp_pending_update) { 16848c2ecf20Sopenharmony_ci /* this is the first actual URB submitted, 16858c2ecf20Sopenharmony_ci * update trigger timestamp to reflect actual start time 16868c2ecf20Sopenharmony_ci */ 16878c2ecf20Sopenharmony_ci snd_pcm_gettime(runtime, &runtime->trigger_tstamp); 16888c2ecf20Sopenharmony_ci subs->trigger_tstamp_pending_update = false; 16898c2ecf20Sopenharmony_ci } 16908c2ecf20Sopenharmony_ci 16918c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&subs->lock, flags); 16928c2ecf20Sopenharmony_ci urb->transfer_buffer_length = bytes; 16938c2ecf20Sopenharmony_ci if (period_elapsed) 16948c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(subs->pcm_substream); 16958c2ecf20Sopenharmony_ci} 16968c2ecf20Sopenharmony_ci 16978c2ecf20Sopenharmony_ci/* 16988c2ecf20Sopenharmony_ci * process after playback data complete 16998c2ecf20Sopenharmony_ci * - decrease the delay count again 17008c2ecf20Sopenharmony_ci */ 17018c2ecf20Sopenharmony_cistatic void retire_playback_urb(struct snd_usb_substream *subs, 17028c2ecf20Sopenharmony_ci struct urb *urb) 17038c2ecf20Sopenharmony_ci{ 17048c2ecf20Sopenharmony_ci unsigned long flags; 17058c2ecf20Sopenharmony_ci struct snd_pcm_runtime *runtime = subs->pcm_substream->runtime; 17068c2ecf20Sopenharmony_ci struct snd_usb_endpoint *ep = subs->data_endpoint; 17078c2ecf20Sopenharmony_ci int processed = urb->transfer_buffer_length / ep->stride; 17088c2ecf20Sopenharmony_ci int est_delay; 17098c2ecf20Sopenharmony_ci 17108c2ecf20Sopenharmony_ci /* ignore the delay accounting when processed=0 is given, i.e. 17118c2ecf20Sopenharmony_ci * silent payloads are processed before handling the actual data 17128c2ecf20Sopenharmony_ci */ 17138c2ecf20Sopenharmony_ci if (!processed) 17148c2ecf20Sopenharmony_ci return; 17158c2ecf20Sopenharmony_ci 17168c2ecf20Sopenharmony_ci spin_lock_irqsave(&subs->lock, flags); 17178c2ecf20Sopenharmony_ci if (!subs->last_delay) 17188c2ecf20Sopenharmony_ci goto out; /* short path */ 17198c2ecf20Sopenharmony_ci 17208c2ecf20Sopenharmony_ci est_delay = snd_usb_pcm_delay(subs, runtime->rate); 17218c2ecf20Sopenharmony_ci /* update delay with exact number of samples played */ 17228c2ecf20Sopenharmony_ci if (processed > subs->last_delay) 17238c2ecf20Sopenharmony_ci subs->last_delay = 0; 17248c2ecf20Sopenharmony_ci else 17258c2ecf20Sopenharmony_ci subs->last_delay -= processed; 17268c2ecf20Sopenharmony_ci runtime->delay = subs->last_delay; 17278c2ecf20Sopenharmony_ci 17288c2ecf20Sopenharmony_ci /* 17298c2ecf20Sopenharmony_ci * Report when delay estimate is off by more than 2ms. 17308c2ecf20Sopenharmony_ci * The error should be lower than 2ms since the estimate relies 17318c2ecf20Sopenharmony_ci * on two reads of a counter updated every ms. 17328c2ecf20Sopenharmony_ci */ 17338c2ecf20Sopenharmony_ci if (abs(est_delay - subs->last_delay) * 1000 > runtime->rate * 2) 17348c2ecf20Sopenharmony_ci dev_dbg_ratelimited(&subs->dev->dev, 17358c2ecf20Sopenharmony_ci "delay: estimated %d, actual %d\n", 17368c2ecf20Sopenharmony_ci est_delay, subs->last_delay); 17378c2ecf20Sopenharmony_ci 17388c2ecf20Sopenharmony_ci if (!subs->running) { 17398c2ecf20Sopenharmony_ci /* update last_frame_number for delay counting here since 17408c2ecf20Sopenharmony_ci * prepare_playback_urb won't be called during pause 17418c2ecf20Sopenharmony_ci */ 17428c2ecf20Sopenharmony_ci subs->last_frame_number = 17438c2ecf20Sopenharmony_ci usb_get_current_frame_number(subs->dev) & 0xff; 17448c2ecf20Sopenharmony_ci } 17458c2ecf20Sopenharmony_ci 17468c2ecf20Sopenharmony_ci out: 17478c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&subs->lock, flags); 17488c2ecf20Sopenharmony_ci} 17498c2ecf20Sopenharmony_ci 17508c2ecf20Sopenharmony_cistatic int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, 17518c2ecf20Sopenharmony_ci int cmd) 17528c2ecf20Sopenharmony_ci{ 17538c2ecf20Sopenharmony_ci struct snd_usb_substream *subs = substream->runtime->private_data; 17548c2ecf20Sopenharmony_ci 17558c2ecf20Sopenharmony_ci switch (cmd) { 17568c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 17578c2ecf20Sopenharmony_ci subs->trigger_tstamp_pending_update = true; 17588c2ecf20Sopenharmony_ci fallthrough; 17598c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 17608c2ecf20Sopenharmony_ci subs->data_endpoint->prepare_data_urb = prepare_playback_urb; 17618c2ecf20Sopenharmony_ci subs->data_endpoint->retire_data_urb = retire_playback_urb; 17628c2ecf20Sopenharmony_ci subs->running = 1; 17638c2ecf20Sopenharmony_ci return 0; 17648c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 17658c2ecf20Sopenharmony_ci stop_endpoints(subs); 17668c2ecf20Sopenharmony_ci subs->running = 0; 17678c2ecf20Sopenharmony_ci return 0; 17688c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 17698c2ecf20Sopenharmony_ci subs->data_endpoint->prepare_data_urb = NULL; 17708c2ecf20Sopenharmony_ci /* keep retire_data_urb for delay calculation */ 17718c2ecf20Sopenharmony_ci subs->data_endpoint->retire_data_urb = retire_playback_urb; 17728c2ecf20Sopenharmony_ci subs->running = 0; 17738c2ecf20Sopenharmony_ci return 0; 17748c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 17758c2ecf20Sopenharmony_ci if (subs->stream->chip->setup_fmt_after_resume_quirk) { 17768c2ecf20Sopenharmony_ci stop_endpoints(subs); 17778c2ecf20Sopenharmony_ci subs->need_setup_fmt = true; 17788c2ecf20Sopenharmony_ci return 0; 17798c2ecf20Sopenharmony_ci } 17808c2ecf20Sopenharmony_ci break; 17818c2ecf20Sopenharmony_ci } 17828c2ecf20Sopenharmony_ci 17838c2ecf20Sopenharmony_ci return -EINVAL; 17848c2ecf20Sopenharmony_ci} 17858c2ecf20Sopenharmony_ci 17868c2ecf20Sopenharmony_cistatic int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, 17878c2ecf20Sopenharmony_ci int cmd) 17888c2ecf20Sopenharmony_ci{ 17898c2ecf20Sopenharmony_ci int err; 17908c2ecf20Sopenharmony_ci struct snd_usb_substream *subs = substream->runtime->private_data; 17918c2ecf20Sopenharmony_ci 17928c2ecf20Sopenharmony_ci switch (cmd) { 17938c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 17948c2ecf20Sopenharmony_ci err = start_endpoints(subs); 17958c2ecf20Sopenharmony_ci if (err < 0) 17968c2ecf20Sopenharmony_ci return err; 17978c2ecf20Sopenharmony_ci 17988c2ecf20Sopenharmony_ci subs->data_endpoint->retire_data_urb = retire_capture_urb; 17998c2ecf20Sopenharmony_ci subs->running = 1; 18008c2ecf20Sopenharmony_ci return 0; 18018c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 18028c2ecf20Sopenharmony_ci stop_endpoints(subs); 18038c2ecf20Sopenharmony_ci subs->data_endpoint->retire_data_urb = NULL; 18048c2ecf20Sopenharmony_ci subs->running = 0; 18058c2ecf20Sopenharmony_ci return 0; 18068c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 18078c2ecf20Sopenharmony_ci subs->data_endpoint->retire_data_urb = NULL; 18088c2ecf20Sopenharmony_ci subs->running = 0; 18098c2ecf20Sopenharmony_ci return 0; 18108c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 18118c2ecf20Sopenharmony_ci subs->data_endpoint->retire_data_urb = retire_capture_urb; 18128c2ecf20Sopenharmony_ci subs->running = 1; 18138c2ecf20Sopenharmony_ci return 0; 18148c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_SUSPEND: 18158c2ecf20Sopenharmony_ci if (subs->stream->chip->setup_fmt_after_resume_quirk) { 18168c2ecf20Sopenharmony_ci stop_endpoints(subs); 18178c2ecf20Sopenharmony_ci subs->need_setup_fmt = true; 18188c2ecf20Sopenharmony_ci return 0; 18198c2ecf20Sopenharmony_ci } 18208c2ecf20Sopenharmony_ci break; 18218c2ecf20Sopenharmony_ci } 18228c2ecf20Sopenharmony_ci 18238c2ecf20Sopenharmony_ci return -EINVAL; 18248c2ecf20Sopenharmony_ci} 18258c2ecf20Sopenharmony_ci 18268c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_usb_playback_ops = { 18278c2ecf20Sopenharmony_ci .open = snd_usb_pcm_open, 18288c2ecf20Sopenharmony_ci .close = snd_usb_pcm_close, 18298c2ecf20Sopenharmony_ci .hw_params = snd_usb_hw_params, 18308c2ecf20Sopenharmony_ci .hw_free = snd_usb_hw_free, 18318c2ecf20Sopenharmony_ci .prepare = snd_usb_pcm_prepare, 18328c2ecf20Sopenharmony_ci .trigger = snd_usb_substream_playback_trigger, 18338c2ecf20Sopenharmony_ci .sync_stop = snd_usb_pcm_sync_stop, 18348c2ecf20Sopenharmony_ci .pointer = snd_usb_pcm_pointer, 18358c2ecf20Sopenharmony_ci}; 18368c2ecf20Sopenharmony_ci 18378c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops snd_usb_capture_ops = { 18388c2ecf20Sopenharmony_ci .open = snd_usb_pcm_open, 18398c2ecf20Sopenharmony_ci .close = snd_usb_pcm_close, 18408c2ecf20Sopenharmony_ci .hw_params = snd_usb_hw_params, 18418c2ecf20Sopenharmony_ci .hw_free = snd_usb_hw_free, 18428c2ecf20Sopenharmony_ci .prepare = snd_usb_pcm_prepare, 18438c2ecf20Sopenharmony_ci .trigger = snd_usb_substream_capture_trigger, 18448c2ecf20Sopenharmony_ci .sync_stop = snd_usb_pcm_sync_stop, 18458c2ecf20Sopenharmony_ci .pointer = snd_usb_pcm_pointer, 18468c2ecf20Sopenharmony_ci}; 18478c2ecf20Sopenharmony_ci 18488c2ecf20Sopenharmony_civoid snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream) 18498c2ecf20Sopenharmony_ci{ 18508c2ecf20Sopenharmony_ci const struct snd_pcm_ops *ops; 18518c2ecf20Sopenharmony_ci 18528c2ecf20Sopenharmony_ci ops = stream == SNDRV_PCM_STREAM_PLAYBACK ? 18538c2ecf20Sopenharmony_ci &snd_usb_playback_ops : &snd_usb_capture_ops; 18548c2ecf20Sopenharmony_ci snd_pcm_set_ops(pcm, stream, ops); 18558c2ecf20Sopenharmony_ci} 18568c2ecf20Sopenharmony_ci 18578c2ecf20Sopenharmony_civoid snd_usb_preallocate_buffer(struct snd_usb_substream *subs) 18588c2ecf20Sopenharmony_ci{ 18598c2ecf20Sopenharmony_ci struct snd_pcm *pcm = subs->stream->pcm; 18608c2ecf20Sopenharmony_ci struct snd_pcm_substream *s = pcm->streams[subs->direction].substream; 18618c2ecf20Sopenharmony_ci struct device *dev = subs->dev->bus->sysdev; 18628c2ecf20Sopenharmony_ci 18638c2ecf20Sopenharmony_ci if (snd_usb_use_vmalloc) 18648c2ecf20Sopenharmony_ci snd_pcm_set_managed_buffer(s, SNDRV_DMA_TYPE_VMALLOC, 18658c2ecf20Sopenharmony_ci NULL, 0, 0); 18668c2ecf20Sopenharmony_ci else 18678c2ecf20Sopenharmony_ci snd_pcm_set_managed_buffer(s, SNDRV_DMA_TYPE_DEV_SG, 18688c2ecf20Sopenharmony_ci dev, 64*1024, 512*1024); 18698c2ecf20Sopenharmony_ci} 1870