18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Linux driver for M2Tech hiFace compatible devices 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2012-2013 (C) M2TECH S.r.l and Amarula Solutions B.V. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Authors: Michael Trimarchi <michael@amarulasolutions.com> 88c2ecf20Sopenharmony_ci * Antonio Ospite <ao2@amarulasolutions.com> 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * The driver is based on the work done in TerraTec DMX 6Fire USB 118c2ecf20Sopenharmony_ci */ 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <sound/pcm.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "pcm.h" 178c2ecf20Sopenharmony_ci#include "chip.h" 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci#define OUT_EP 0x2 208c2ecf20Sopenharmony_ci#define PCM_N_URBS 8 218c2ecf20Sopenharmony_ci#define PCM_PACKET_SIZE 4096 228c2ecf20Sopenharmony_ci#define PCM_BUFFER_SIZE (2 * PCM_N_URBS * PCM_PACKET_SIZE) 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_cistruct pcm_urb { 258c2ecf20Sopenharmony_ci struct hiface_chip *chip; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci struct urb instance; 288c2ecf20Sopenharmony_ci struct usb_anchor submitted; 298c2ecf20Sopenharmony_ci u8 *buffer; 308c2ecf20Sopenharmony_ci}; 318c2ecf20Sopenharmony_ci 328c2ecf20Sopenharmony_cistruct pcm_substream { 338c2ecf20Sopenharmony_ci spinlock_t lock; 348c2ecf20Sopenharmony_ci struct snd_pcm_substream *instance; 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ci bool active; 378c2ecf20Sopenharmony_ci snd_pcm_uframes_t dma_off; /* current position in alsa dma_area */ 388c2ecf20Sopenharmony_ci snd_pcm_uframes_t period_off; /* current position in current period */ 398c2ecf20Sopenharmony_ci}; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cienum { /* pcm streaming states */ 428c2ecf20Sopenharmony_ci STREAM_DISABLED, /* no pcm streaming */ 438c2ecf20Sopenharmony_ci STREAM_STARTING, /* pcm streaming requested, waiting to become ready */ 448c2ecf20Sopenharmony_ci STREAM_RUNNING, /* pcm streaming running */ 458c2ecf20Sopenharmony_ci STREAM_STOPPING 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistruct pcm_runtime { 498c2ecf20Sopenharmony_ci struct hiface_chip *chip; 508c2ecf20Sopenharmony_ci struct snd_pcm *instance; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci struct pcm_substream playback; 538c2ecf20Sopenharmony_ci bool panic; /* if set driver won't do anymore pcm on device */ 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci struct pcm_urb out_urbs[PCM_N_URBS]; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci struct mutex stream_mutex; 588c2ecf20Sopenharmony_ci u8 stream_state; /* one of STREAM_XXX */ 598c2ecf20Sopenharmony_ci u8 extra_freq; 608c2ecf20Sopenharmony_ci wait_queue_head_t stream_wait_queue; 618c2ecf20Sopenharmony_ci bool stream_wait_cond; 628c2ecf20Sopenharmony_ci}; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_cistatic const unsigned int rates[] = { 44100, 48000, 88200, 96000, 176400, 192000, 658c2ecf20Sopenharmony_ci 352800, 384000 }; 668c2ecf20Sopenharmony_cistatic const struct snd_pcm_hw_constraint_list constraints_extra_rates = { 678c2ecf20Sopenharmony_ci .count = ARRAY_SIZE(rates), 688c2ecf20Sopenharmony_ci .list = rates, 698c2ecf20Sopenharmony_ci .mask = 0, 708c2ecf20Sopenharmony_ci}; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_cistatic const struct snd_pcm_hardware pcm_hw = { 738c2ecf20Sopenharmony_ci .info = SNDRV_PCM_INFO_MMAP | 748c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_INTERLEAVED | 758c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_BLOCK_TRANSFER | 768c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_PAUSE | 778c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_MMAP_VALID | 788c2ecf20Sopenharmony_ci SNDRV_PCM_INFO_BATCH, 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ci .formats = SNDRV_PCM_FMTBIT_S32_LE, 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci .rates = SNDRV_PCM_RATE_44100 | 838c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_48000 | 848c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_88200 | 858c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_96000 | 868c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_176400 | 878c2ecf20Sopenharmony_ci SNDRV_PCM_RATE_192000, 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci .rate_min = 44100, 908c2ecf20Sopenharmony_ci .rate_max = 192000, /* changes in hiface_pcm_open to support extra rates */ 918c2ecf20Sopenharmony_ci .channels_min = 2, 928c2ecf20Sopenharmony_ci .channels_max = 2, 938c2ecf20Sopenharmony_ci .buffer_bytes_max = PCM_BUFFER_SIZE, 948c2ecf20Sopenharmony_ci .period_bytes_min = PCM_PACKET_SIZE, 958c2ecf20Sopenharmony_ci .period_bytes_max = PCM_BUFFER_SIZE, 968c2ecf20Sopenharmony_ci .periods_min = 2, 978c2ecf20Sopenharmony_ci .periods_max = 1024 988c2ecf20Sopenharmony_ci}; 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci/* message values used to change the sample rate */ 1018c2ecf20Sopenharmony_ci#define HIFACE_SET_RATE_REQUEST 0xb0 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci#define HIFACE_RATE_44100 0x43 1048c2ecf20Sopenharmony_ci#define HIFACE_RATE_48000 0x4b 1058c2ecf20Sopenharmony_ci#define HIFACE_RATE_88200 0x42 1068c2ecf20Sopenharmony_ci#define HIFACE_RATE_96000 0x4a 1078c2ecf20Sopenharmony_ci#define HIFACE_RATE_176400 0x40 1088c2ecf20Sopenharmony_ci#define HIFACE_RATE_192000 0x48 1098c2ecf20Sopenharmony_ci#define HIFACE_RATE_352800 0x58 1108c2ecf20Sopenharmony_ci#define HIFACE_RATE_384000 0x68 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic int hiface_pcm_set_rate(struct pcm_runtime *rt, unsigned int rate) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci struct usb_device *device = rt->chip->dev; 1158c2ecf20Sopenharmony_ci u16 rate_value; 1168c2ecf20Sopenharmony_ci int ret; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci /* We are already sure that the rate is supported here thanks to 1198c2ecf20Sopenharmony_ci * ALSA constraints 1208c2ecf20Sopenharmony_ci */ 1218c2ecf20Sopenharmony_ci switch (rate) { 1228c2ecf20Sopenharmony_ci case 44100: 1238c2ecf20Sopenharmony_ci rate_value = HIFACE_RATE_44100; 1248c2ecf20Sopenharmony_ci break; 1258c2ecf20Sopenharmony_ci case 48000: 1268c2ecf20Sopenharmony_ci rate_value = HIFACE_RATE_48000; 1278c2ecf20Sopenharmony_ci break; 1288c2ecf20Sopenharmony_ci case 88200: 1298c2ecf20Sopenharmony_ci rate_value = HIFACE_RATE_88200; 1308c2ecf20Sopenharmony_ci break; 1318c2ecf20Sopenharmony_ci case 96000: 1328c2ecf20Sopenharmony_ci rate_value = HIFACE_RATE_96000; 1338c2ecf20Sopenharmony_ci break; 1348c2ecf20Sopenharmony_ci case 176400: 1358c2ecf20Sopenharmony_ci rate_value = HIFACE_RATE_176400; 1368c2ecf20Sopenharmony_ci break; 1378c2ecf20Sopenharmony_ci case 192000: 1388c2ecf20Sopenharmony_ci rate_value = HIFACE_RATE_192000; 1398c2ecf20Sopenharmony_ci break; 1408c2ecf20Sopenharmony_ci case 352800: 1418c2ecf20Sopenharmony_ci rate_value = HIFACE_RATE_352800; 1428c2ecf20Sopenharmony_ci break; 1438c2ecf20Sopenharmony_ci case 384000: 1448c2ecf20Sopenharmony_ci rate_value = HIFACE_RATE_384000; 1458c2ecf20Sopenharmony_ci break; 1468c2ecf20Sopenharmony_ci default: 1478c2ecf20Sopenharmony_ci dev_err(&device->dev, "Unsupported rate %d\n", rate); 1488c2ecf20Sopenharmony_ci return -EINVAL; 1498c2ecf20Sopenharmony_ci } 1508c2ecf20Sopenharmony_ci 1518c2ecf20Sopenharmony_ci /* 1528c2ecf20Sopenharmony_ci * USBIO: Vendor 0xb0(wValue=0x0043, wIndex=0x0000) 1538c2ecf20Sopenharmony_ci * 43 b0 43 00 00 00 00 00 1548c2ecf20Sopenharmony_ci * USBIO: Vendor 0xb0(wValue=0x004b, wIndex=0x0000) 1558c2ecf20Sopenharmony_ci * 43 b0 4b 00 00 00 00 00 1568c2ecf20Sopenharmony_ci * This control message doesn't have any ack from the 1578c2ecf20Sopenharmony_ci * other side 1588c2ecf20Sopenharmony_ci */ 1598c2ecf20Sopenharmony_ci ret = usb_control_msg_send(device, 0, 1608c2ecf20Sopenharmony_ci HIFACE_SET_RATE_REQUEST, 1618c2ecf20Sopenharmony_ci USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER, 1628c2ecf20Sopenharmony_ci rate_value, 0, NULL, 0, 100, GFP_KERNEL); 1638c2ecf20Sopenharmony_ci if (ret) 1648c2ecf20Sopenharmony_ci dev_err(&device->dev, "Error setting samplerate %d.\n", rate); 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci return ret; 1678c2ecf20Sopenharmony_ci} 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_cistatic struct pcm_substream *hiface_pcm_get_substream(struct snd_pcm_substream 1708c2ecf20Sopenharmony_ci *alsa_sub) 1718c2ecf20Sopenharmony_ci{ 1728c2ecf20Sopenharmony_ci struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); 1738c2ecf20Sopenharmony_ci struct device *device = &rt->chip->dev->dev; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (alsa_sub->stream == SNDRV_PCM_STREAM_PLAYBACK) 1768c2ecf20Sopenharmony_ci return &rt->playback; 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci dev_err(device, "Error getting pcm substream slot.\n"); 1798c2ecf20Sopenharmony_ci return NULL; 1808c2ecf20Sopenharmony_ci} 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci/* call with stream_mutex locked */ 1838c2ecf20Sopenharmony_cistatic void hiface_pcm_stream_stop(struct pcm_runtime *rt) 1848c2ecf20Sopenharmony_ci{ 1858c2ecf20Sopenharmony_ci int i, time; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci if (rt->stream_state != STREAM_DISABLED) { 1888c2ecf20Sopenharmony_ci rt->stream_state = STREAM_STOPPING; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci for (i = 0; i < PCM_N_URBS; i++) { 1918c2ecf20Sopenharmony_ci time = usb_wait_anchor_empty_timeout( 1928c2ecf20Sopenharmony_ci &rt->out_urbs[i].submitted, 100); 1938c2ecf20Sopenharmony_ci if (!time) 1948c2ecf20Sopenharmony_ci usb_kill_anchored_urbs( 1958c2ecf20Sopenharmony_ci &rt->out_urbs[i].submitted); 1968c2ecf20Sopenharmony_ci usb_kill_urb(&rt->out_urbs[i].instance); 1978c2ecf20Sopenharmony_ci } 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci rt->stream_state = STREAM_DISABLED; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci/* call with stream_mutex locked */ 2048c2ecf20Sopenharmony_cistatic int hiface_pcm_stream_start(struct pcm_runtime *rt) 2058c2ecf20Sopenharmony_ci{ 2068c2ecf20Sopenharmony_ci int ret = 0; 2078c2ecf20Sopenharmony_ci int i; 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_ci if (rt->stream_state == STREAM_DISABLED) { 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci /* reset panic state when starting a new stream */ 2128c2ecf20Sopenharmony_ci rt->panic = false; 2138c2ecf20Sopenharmony_ci 2148c2ecf20Sopenharmony_ci /* submit our out urbs zero init */ 2158c2ecf20Sopenharmony_ci rt->stream_state = STREAM_STARTING; 2168c2ecf20Sopenharmony_ci for (i = 0; i < PCM_N_URBS; i++) { 2178c2ecf20Sopenharmony_ci memset(rt->out_urbs[i].buffer, 0, PCM_PACKET_SIZE); 2188c2ecf20Sopenharmony_ci usb_anchor_urb(&rt->out_urbs[i].instance, 2198c2ecf20Sopenharmony_ci &rt->out_urbs[i].submitted); 2208c2ecf20Sopenharmony_ci ret = usb_submit_urb(&rt->out_urbs[i].instance, 2218c2ecf20Sopenharmony_ci GFP_ATOMIC); 2228c2ecf20Sopenharmony_ci if (ret) { 2238c2ecf20Sopenharmony_ci hiface_pcm_stream_stop(rt); 2248c2ecf20Sopenharmony_ci return ret; 2258c2ecf20Sopenharmony_ci } 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci /* wait for first out urb to return (sent in in urb handler) */ 2298c2ecf20Sopenharmony_ci wait_event_timeout(rt->stream_wait_queue, rt->stream_wait_cond, 2308c2ecf20Sopenharmony_ci HZ); 2318c2ecf20Sopenharmony_ci if (rt->stream_wait_cond) { 2328c2ecf20Sopenharmony_ci struct device *device = &rt->chip->dev->dev; 2338c2ecf20Sopenharmony_ci dev_dbg(device, "%s: Stream is running wakeup event\n", 2348c2ecf20Sopenharmony_ci __func__); 2358c2ecf20Sopenharmony_ci rt->stream_state = STREAM_RUNNING; 2368c2ecf20Sopenharmony_ci } else { 2378c2ecf20Sopenharmony_ci hiface_pcm_stream_stop(rt); 2388c2ecf20Sopenharmony_ci return -EIO; 2398c2ecf20Sopenharmony_ci } 2408c2ecf20Sopenharmony_ci } 2418c2ecf20Sopenharmony_ci return ret; 2428c2ecf20Sopenharmony_ci} 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci/* The hardware wants word-swapped 32-bit values */ 2458c2ecf20Sopenharmony_cistatic void memcpy_swahw32(u8 *dest, u8 *src, unsigned int n) 2468c2ecf20Sopenharmony_ci{ 2478c2ecf20Sopenharmony_ci unsigned int i; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci for (i = 0; i < n / 4; i++) 2508c2ecf20Sopenharmony_ci ((u32 *)dest)[i] = swahw32(((u32 *)src)[i]); 2518c2ecf20Sopenharmony_ci} 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci/* call with substream locked */ 2548c2ecf20Sopenharmony_ci/* returns true if a period elapsed */ 2558c2ecf20Sopenharmony_cistatic bool hiface_pcm_playback(struct pcm_substream *sub, struct pcm_urb *urb) 2568c2ecf20Sopenharmony_ci{ 2578c2ecf20Sopenharmony_ci struct snd_pcm_runtime *alsa_rt = sub->instance->runtime; 2588c2ecf20Sopenharmony_ci struct device *device = &urb->chip->dev->dev; 2598c2ecf20Sopenharmony_ci u8 *source; 2608c2ecf20Sopenharmony_ci unsigned int pcm_buffer_size; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci WARN_ON(alsa_rt->format != SNDRV_PCM_FORMAT_S32_LE); 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci pcm_buffer_size = snd_pcm_lib_buffer_bytes(sub->instance); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci if (sub->dma_off + PCM_PACKET_SIZE <= pcm_buffer_size) { 2678c2ecf20Sopenharmony_ci dev_dbg(device, "%s: (1) buffer_size %#x dma_offset %#x\n", __func__, 2688c2ecf20Sopenharmony_ci (unsigned int) pcm_buffer_size, 2698c2ecf20Sopenharmony_ci (unsigned int) sub->dma_off); 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci source = alsa_rt->dma_area + sub->dma_off; 2728c2ecf20Sopenharmony_ci memcpy_swahw32(urb->buffer, source, PCM_PACKET_SIZE); 2738c2ecf20Sopenharmony_ci } else { 2748c2ecf20Sopenharmony_ci /* wrap around at end of ring buffer */ 2758c2ecf20Sopenharmony_ci unsigned int len; 2768c2ecf20Sopenharmony_ci 2778c2ecf20Sopenharmony_ci dev_dbg(device, "%s: (2) buffer_size %#x dma_offset %#x\n", __func__, 2788c2ecf20Sopenharmony_ci (unsigned int) pcm_buffer_size, 2798c2ecf20Sopenharmony_ci (unsigned int) sub->dma_off); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci len = pcm_buffer_size - sub->dma_off; 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_ci source = alsa_rt->dma_area + sub->dma_off; 2848c2ecf20Sopenharmony_ci memcpy_swahw32(urb->buffer, source, len); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci source = alsa_rt->dma_area; 2878c2ecf20Sopenharmony_ci memcpy_swahw32(urb->buffer + len, source, 2888c2ecf20Sopenharmony_ci PCM_PACKET_SIZE - len); 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci sub->dma_off += PCM_PACKET_SIZE; 2918c2ecf20Sopenharmony_ci if (sub->dma_off >= pcm_buffer_size) 2928c2ecf20Sopenharmony_ci sub->dma_off -= pcm_buffer_size; 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci sub->period_off += PCM_PACKET_SIZE; 2958c2ecf20Sopenharmony_ci if (sub->period_off >= alsa_rt->period_size) { 2968c2ecf20Sopenharmony_ci sub->period_off %= alsa_rt->period_size; 2978c2ecf20Sopenharmony_ci return true; 2988c2ecf20Sopenharmony_ci } 2998c2ecf20Sopenharmony_ci return false; 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic void hiface_pcm_out_urb_handler(struct urb *usb_urb) 3038c2ecf20Sopenharmony_ci{ 3048c2ecf20Sopenharmony_ci struct pcm_urb *out_urb = usb_urb->context; 3058c2ecf20Sopenharmony_ci struct pcm_runtime *rt = out_urb->chip->pcm; 3068c2ecf20Sopenharmony_ci struct pcm_substream *sub; 3078c2ecf20Sopenharmony_ci bool do_period_elapsed = false; 3088c2ecf20Sopenharmony_ci unsigned long flags; 3098c2ecf20Sopenharmony_ci int ret; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci if (rt->panic || rt->stream_state == STREAM_STOPPING) 3128c2ecf20Sopenharmony_ci return; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci if (unlikely(usb_urb->status == -ENOENT || /* unlinked */ 3158c2ecf20Sopenharmony_ci usb_urb->status == -ENODEV || /* device removed */ 3168c2ecf20Sopenharmony_ci usb_urb->status == -ECONNRESET || /* unlinked */ 3178c2ecf20Sopenharmony_ci usb_urb->status == -ESHUTDOWN)) { /* device disabled */ 3188c2ecf20Sopenharmony_ci goto out_fail; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci if (rt->stream_state == STREAM_STARTING) { 3228c2ecf20Sopenharmony_ci rt->stream_wait_cond = true; 3238c2ecf20Sopenharmony_ci wake_up(&rt->stream_wait_queue); 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci /* now send our playback data (if a free out urb was found) */ 3278c2ecf20Sopenharmony_ci sub = &rt->playback; 3288c2ecf20Sopenharmony_ci spin_lock_irqsave(&sub->lock, flags); 3298c2ecf20Sopenharmony_ci if (sub->active) 3308c2ecf20Sopenharmony_ci do_period_elapsed = hiface_pcm_playback(sub, out_urb); 3318c2ecf20Sopenharmony_ci else 3328c2ecf20Sopenharmony_ci memset(out_urb->buffer, 0, PCM_PACKET_SIZE); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sub->lock, flags); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci if (do_period_elapsed) 3378c2ecf20Sopenharmony_ci snd_pcm_period_elapsed(sub->instance); 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci ret = usb_submit_urb(&out_urb->instance, GFP_ATOMIC); 3408c2ecf20Sopenharmony_ci if (ret < 0) 3418c2ecf20Sopenharmony_ci goto out_fail; 3428c2ecf20Sopenharmony_ci 3438c2ecf20Sopenharmony_ci return; 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ciout_fail: 3468c2ecf20Sopenharmony_ci rt->panic = true; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_cistatic int hiface_pcm_open(struct snd_pcm_substream *alsa_sub) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); 3528c2ecf20Sopenharmony_ci struct pcm_substream *sub = NULL; 3538c2ecf20Sopenharmony_ci struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime; 3548c2ecf20Sopenharmony_ci int ret; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci if (rt->panic) 3578c2ecf20Sopenharmony_ci return -EPIPE; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci mutex_lock(&rt->stream_mutex); 3608c2ecf20Sopenharmony_ci alsa_rt->hw = pcm_hw; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci if (alsa_sub->stream == SNDRV_PCM_STREAM_PLAYBACK) 3638c2ecf20Sopenharmony_ci sub = &rt->playback; 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci if (!sub) { 3668c2ecf20Sopenharmony_ci struct device *device = &rt->chip->dev->dev; 3678c2ecf20Sopenharmony_ci mutex_unlock(&rt->stream_mutex); 3688c2ecf20Sopenharmony_ci dev_err(device, "Invalid stream type\n"); 3698c2ecf20Sopenharmony_ci return -EINVAL; 3708c2ecf20Sopenharmony_ci } 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci if (rt->extra_freq) { 3738c2ecf20Sopenharmony_ci alsa_rt->hw.rates |= SNDRV_PCM_RATE_KNOT; 3748c2ecf20Sopenharmony_ci alsa_rt->hw.rate_max = 384000; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci /* explicit constraints needed as we added SNDRV_PCM_RATE_KNOT */ 3778c2ecf20Sopenharmony_ci ret = snd_pcm_hw_constraint_list(alsa_sub->runtime, 0, 3788c2ecf20Sopenharmony_ci SNDRV_PCM_HW_PARAM_RATE, 3798c2ecf20Sopenharmony_ci &constraints_extra_rates); 3808c2ecf20Sopenharmony_ci if (ret < 0) { 3818c2ecf20Sopenharmony_ci mutex_unlock(&rt->stream_mutex); 3828c2ecf20Sopenharmony_ci return ret; 3838c2ecf20Sopenharmony_ci } 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci sub->instance = alsa_sub; 3878c2ecf20Sopenharmony_ci sub->active = false; 3888c2ecf20Sopenharmony_ci mutex_unlock(&rt->stream_mutex); 3898c2ecf20Sopenharmony_ci return 0; 3908c2ecf20Sopenharmony_ci} 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_cistatic int hiface_pcm_close(struct snd_pcm_substream *alsa_sub) 3938c2ecf20Sopenharmony_ci{ 3948c2ecf20Sopenharmony_ci struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); 3958c2ecf20Sopenharmony_ci struct pcm_substream *sub = hiface_pcm_get_substream(alsa_sub); 3968c2ecf20Sopenharmony_ci unsigned long flags; 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci if (rt->panic) 3998c2ecf20Sopenharmony_ci return 0; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci mutex_lock(&rt->stream_mutex); 4028c2ecf20Sopenharmony_ci if (sub) { 4038c2ecf20Sopenharmony_ci hiface_pcm_stream_stop(rt); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci /* deactivate substream */ 4068c2ecf20Sopenharmony_ci spin_lock_irqsave(&sub->lock, flags); 4078c2ecf20Sopenharmony_ci sub->instance = NULL; 4088c2ecf20Sopenharmony_ci sub->active = false; 4098c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sub->lock, flags); 4108c2ecf20Sopenharmony_ci 4118c2ecf20Sopenharmony_ci } 4128c2ecf20Sopenharmony_ci mutex_unlock(&rt->stream_mutex); 4138c2ecf20Sopenharmony_ci return 0; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_cistatic int hiface_pcm_prepare(struct snd_pcm_substream *alsa_sub) 4178c2ecf20Sopenharmony_ci{ 4188c2ecf20Sopenharmony_ci struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); 4198c2ecf20Sopenharmony_ci struct pcm_substream *sub = hiface_pcm_get_substream(alsa_sub); 4208c2ecf20Sopenharmony_ci struct snd_pcm_runtime *alsa_rt = alsa_sub->runtime; 4218c2ecf20Sopenharmony_ci int ret; 4228c2ecf20Sopenharmony_ci 4238c2ecf20Sopenharmony_ci if (rt->panic) 4248c2ecf20Sopenharmony_ci return -EPIPE; 4258c2ecf20Sopenharmony_ci if (!sub) 4268c2ecf20Sopenharmony_ci return -ENODEV; 4278c2ecf20Sopenharmony_ci 4288c2ecf20Sopenharmony_ci mutex_lock(&rt->stream_mutex); 4298c2ecf20Sopenharmony_ci 4308c2ecf20Sopenharmony_ci hiface_pcm_stream_stop(rt); 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci sub->dma_off = 0; 4338c2ecf20Sopenharmony_ci sub->period_off = 0; 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci if (rt->stream_state == STREAM_DISABLED) { 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci ret = hiface_pcm_set_rate(rt, alsa_rt->rate); 4388c2ecf20Sopenharmony_ci if (ret) { 4398c2ecf20Sopenharmony_ci mutex_unlock(&rt->stream_mutex); 4408c2ecf20Sopenharmony_ci return ret; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci ret = hiface_pcm_stream_start(rt); 4438c2ecf20Sopenharmony_ci if (ret) { 4448c2ecf20Sopenharmony_ci mutex_unlock(&rt->stream_mutex); 4458c2ecf20Sopenharmony_ci return ret; 4468c2ecf20Sopenharmony_ci } 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci mutex_unlock(&rt->stream_mutex); 4498c2ecf20Sopenharmony_ci return 0; 4508c2ecf20Sopenharmony_ci} 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_cistatic int hiface_pcm_trigger(struct snd_pcm_substream *alsa_sub, int cmd) 4538c2ecf20Sopenharmony_ci{ 4548c2ecf20Sopenharmony_ci struct pcm_substream *sub = hiface_pcm_get_substream(alsa_sub); 4558c2ecf20Sopenharmony_ci struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci if (rt->panic) 4588c2ecf20Sopenharmony_ci return -EPIPE; 4598c2ecf20Sopenharmony_ci if (!sub) 4608c2ecf20Sopenharmony_ci return -ENODEV; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci switch (cmd) { 4638c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_START: 4648c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: 4658c2ecf20Sopenharmony_ci spin_lock_irq(&sub->lock); 4668c2ecf20Sopenharmony_ci sub->active = true; 4678c2ecf20Sopenharmony_ci spin_unlock_irq(&sub->lock); 4688c2ecf20Sopenharmony_ci return 0; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_STOP: 4718c2ecf20Sopenharmony_ci case SNDRV_PCM_TRIGGER_PAUSE_PUSH: 4728c2ecf20Sopenharmony_ci spin_lock_irq(&sub->lock); 4738c2ecf20Sopenharmony_ci sub->active = false; 4748c2ecf20Sopenharmony_ci spin_unlock_irq(&sub->lock); 4758c2ecf20Sopenharmony_ci return 0; 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci default: 4788c2ecf20Sopenharmony_ci return -EINVAL; 4798c2ecf20Sopenharmony_ci } 4808c2ecf20Sopenharmony_ci} 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic snd_pcm_uframes_t hiface_pcm_pointer(struct snd_pcm_substream *alsa_sub) 4838c2ecf20Sopenharmony_ci{ 4848c2ecf20Sopenharmony_ci struct pcm_substream *sub = hiface_pcm_get_substream(alsa_sub); 4858c2ecf20Sopenharmony_ci struct pcm_runtime *rt = snd_pcm_substream_chip(alsa_sub); 4868c2ecf20Sopenharmony_ci unsigned long flags; 4878c2ecf20Sopenharmony_ci snd_pcm_uframes_t dma_offset; 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci if (rt->panic || !sub) 4908c2ecf20Sopenharmony_ci return SNDRV_PCM_POS_XRUN; 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci spin_lock_irqsave(&sub->lock, flags); 4938c2ecf20Sopenharmony_ci dma_offset = sub->dma_off; 4948c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&sub->lock, flags); 4958c2ecf20Sopenharmony_ci return bytes_to_frames(alsa_sub->runtime, dma_offset); 4968c2ecf20Sopenharmony_ci} 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_cistatic const struct snd_pcm_ops pcm_ops = { 4998c2ecf20Sopenharmony_ci .open = hiface_pcm_open, 5008c2ecf20Sopenharmony_ci .close = hiface_pcm_close, 5018c2ecf20Sopenharmony_ci .prepare = hiface_pcm_prepare, 5028c2ecf20Sopenharmony_ci .trigger = hiface_pcm_trigger, 5038c2ecf20Sopenharmony_ci .pointer = hiface_pcm_pointer, 5048c2ecf20Sopenharmony_ci}; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_cistatic int hiface_pcm_init_urb(struct pcm_urb *urb, 5078c2ecf20Sopenharmony_ci struct hiface_chip *chip, 5088c2ecf20Sopenharmony_ci unsigned int ep, 5098c2ecf20Sopenharmony_ci void (*handler)(struct urb *)) 5108c2ecf20Sopenharmony_ci{ 5118c2ecf20Sopenharmony_ci urb->chip = chip; 5128c2ecf20Sopenharmony_ci usb_init_urb(&urb->instance); 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_ci urb->buffer = kzalloc(PCM_PACKET_SIZE, GFP_KERNEL); 5158c2ecf20Sopenharmony_ci if (!urb->buffer) 5168c2ecf20Sopenharmony_ci return -ENOMEM; 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci usb_fill_bulk_urb(&urb->instance, chip->dev, 5198c2ecf20Sopenharmony_ci usb_sndbulkpipe(chip->dev, ep), (void *)urb->buffer, 5208c2ecf20Sopenharmony_ci PCM_PACKET_SIZE, handler, urb); 5218c2ecf20Sopenharmony_ci if (usb_urb_ep_type_check(&urb->instance)) 5228c2ecf20Sopenharmony_ci return -EINVAL; 5238c2ecf20Sopenharmony_ci init_usb_anchor(&urb->submitted); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci return 0; 5268c2ecf20Sopenharmony_ci} 5278c2ecf20Sopenharmony_ci 5288c2ecf20Sopenharmony_civoid hiface_pcm_abort(struct hiface_chip *chip) 5298c2ecf20Sopenharmony_ci{ 5308c2ecf20Sopenharmony_ci struct pcm_runtime *rt = chip->pcm; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci if (rt) { 5338c2ecf20Sopenharmony_ci rt->panic = true; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci mutex_lock(&rt->stream_mutex); 5368c2ecf20Sopenharmony_ci hiface_pcm_stream_stop(rt); 5378c2ecf20Sopenharmony_ci mutex_unlock(&rt->stream_mutex); 5388c2ecf20Sopenharmony_ci } 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_cistatic void hiface_pcm_destroy(struct hiface_chip *chip) 5428c2ecf20Sopenharmony_ci{ 5438c2ecf20Sopenharmony_ci struct pcm_runtime *rt = chip->pcm; 5448c2ecf20Sopenharmony_ci int i; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci for (i = 0; i < PCM_N_URBS; i++) 5478c2ecf20Sopenharmony_ci kfree(rt->out_urbs[i].buffer); 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci kfree(chip->pcm); 5508c2ecf20Sopenharmony_ci chip->pcm = NULL; 5518c2ecf20Sopenharmony_ci} 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_cistatic void hiface_pcm_free(struct snd_pcm *pcm) 5548c2ecf20Sopenharmony_ci{ 5558c2ecf20Sopenharmony_ci struct pcm_runtime *rt = pcm->private_data; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci if (rt) 5588c2ecf20Sopenharmony_ci hiface_pcm_destroy(rt->chip); 5598c2ecf20Sopenharmony_ci} 5608c2ecf20Sopenharmony_ci 5618c2ecf20Sopenharmony_ciint hiface_pcm_init(struct hiface_chip *chip, u8 extra_freq) 5628c2ecf20Sopenharmony_ci{ 5638c2ecf20Sopenharmony_ci int i; 5648c2ecf20Sopenharmony_ci int ret; 5658c2ecf20Sopenharmony_ci struct snd_pcm *pcm; 5668c2ecf20Sopenharmony_ci struct pcm_runtime *rt; 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci rt = kzalloc(sizeof(*rt), GFP_KERNEL); 5698c2ecf20Sopenharmony_ci if (!rt) 5708c2ecf20Sopenharmony_ci return -ENOMEM; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci rt->chip = chip; 5738c2ecf20Sopenharmony_ci rt->stream_state = STREAM_DISABLED; 5748c2ecf20Sopenharmony_ci if (extra_freq) 5758c2ecf20Sopenharmony_ci rt->extra_freq = 1; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci init_waitqueue_head(&rt->stream_wait_queue); 5788c2ecf20Sopenharmony_ci mutex_init(&rt->stream_mutex); 5798c2ecf20Sopenharmony_ci spin_lock_init(&rt->playback.lock); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci for (i = 0; i < PCM_N_URBS; i++) { 5828c2ecf20Sopenharmony_ci ret = hiface_pcm_init_urb(&rt->out_urbs[i], chip, OUT_EP, 5838c2ecf20Sopenharmony_ci hiface_pcm_out_urb_handler); 5848c2ecf20Sopenharmony_ci if (ret < 0) 5858c2ecf20Sopenharmony_ci goto error; 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci ret = snd_pcm_new(chip->card, "USB-SPDIF Audio", 0, 1, 0, &pcm); 5898c2ecf20Sopenharmony_ci if (ret < 0) { 5908c2ecf20Sopenharmony_ci dev_err(&chip->dev->dev, "Cannot create pcm instance\n"); 5918c2ecf20Sopenharmony_ci goto error; 5928c2ecf20Sopenharmony_ci } 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci pcm->private_data = rt; 5958c2ecf20Sopenharmony_ci pcm->private_free = hiface_pcm_free; 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci strlcpy(pcm->name, "USB-SPDIF Audio", sizeof(pcm->name)); 5988c2ecf20Sopenharmony_ci snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &pcm_ops); 5998c2ecf20Sopenharmony_ci snd_pcm_set_managed_buffer_all(pcm, SNDRV_DMA_TYPE_VMALLOC, 6008c2ecf20Sopenharmony_ci NULL, 0, 0); 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci rt->instance = pcm; 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci chip->pcm = rt; 6058c2ecf20Sopenharmony_ci return 0; 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cierror: 6088c2ecf20Sopenharmony_ci for (i = 0; i < PCM_N_URBS; i++) 6098c2ecf20Sopenharmony_ci kfree(rt->out_urbs[i].buffer); 6108c2ecf20Sopenharmony_ci kfree(rt); 6118c2ecf20Sopenharmony_ci return ret; 6128c2ecf20Sopenharmony_ci} 613