From 1f93a7dfd1f8d5ff7a5c53246c7534fe2332d6f4 Mon Sep 17 00:00:00 2001 From: hc <hc@nodka.com> Date: Mon, 11 Dec 2023 02:46:07 +0000 Subject: [PATCH] add audio --- kernel/sound/usb/pcm.c | 284 +++++++++++++++++++++++++++++++++----------------------- 1 files changed, 169 insertions(+), 115 deletions(-) diff --git a/kernel/sound/usb/pcm.c b/kernel/sound/usb/pcm.c index ae136dc..9e93a43 100644 --- a/kernel/sound/usb/pcm.c +++ b/kernel/sound/usb/pcm.c @@ -1,17 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include <linux/init.h> @@ -26,6 +14,8 @@ #include <sound/pcm.h> #include <sound/pcm_params.h> +#include <trace/hooks/sound.h> + #include "usbaudio.h" #include "card.h" #include "quirks.h" @@ -35,6 +25,7 @@ #include "pcm.h" #include "clock.h" #include "power.h" +#include "media.h" #define SUBSTREAM_FLAG_DATA_EP_STARTED 0 #define SUBSTREAM_FLAG_SYNC_EP_STARTED 1 @@ -145,6 +136,8 @@ found = fp; cur_attr = attr; } + + snd_vendor_set_pcm_binterval(fp, found, &cur_attr, &attr); } return found; } @@ -334,19 +327,28 @@ return 0; } -static void stop_endpoints(struct snd_usb_substream *subs, bool wait) +static void sync_pending_stops(struct snd_usb_substream *subs) { - if (test_and_clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) { - snd_usb_endpoint_stop(subs->sync_endpoint); - if (wait) - snd_usb_endpoint_sync_pending_stop(subs->sync_endpoint); - } + snd_usb_endpoint_sync_pending_stop(subs->sync_endpoint); + snd_usb_endpoint_sync_pending_stop(subs->data_endpoint); +} - if (test_and_clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) { +static void stop_endpoints(struct snd_usb_substream *subs) +{ + if (test_and_clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags)) + snd_usb_endpoint_stop(subs->sync_endpoint); + + if (test_and_clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags)) snd_usb_endpoint_stop(subs->data_endpoint); - if (wait) - snd_usb_endpoint_sync_pending_stop(subs->data_endpoint); - } +} + +/* PCM sync_stop callback */ +static int snd_usb_pcm_sync_stop(struct snd_pcm_substream *substream) +{ + struct snd_usb_substream *subs = substream->runtime->private_data; + + sync_pending_stops(subs); + return 0; } static int search_roland_implicit_fb(struct usb_device *dev, int ifnum, @@ -425,6 +427,28 @@ ep = 0x81; ifnum = 1; goto add_sync_ep_from_ifnum; + case USB_ID(0x07fd, 0x0004): /* MOTU MicroBook II/IIc */ + /* MicroBook IIc */ + if (altsd->bInterfaceClass == USB_CLASS_AUDIO) + return 0; + + /* MicroBook II */ + ep = 0x84; + ifnum = 0; + goto add_sync_ep_from_ifnum; + case USB_ID(0x07fd, 0x0008): /* MOTU M Series */ + case USB_ID(0x31e9, 0x0001): /* Solid State Logic SSL2 */ + case USB_ID(0x31e9, 0x0002): /* Solid State Logic SSL2+ */ + case USB_ID(0x0499, 0x172f): /* Steinberg UR22C */ + case USB_ID(0x0d9a, 0x00df): /* RTX6001 */ + ep = 0x81; + ifnum = 2; + goto add_sync_ep_from_ifnum; + case USB_ID(0x2b73, 0x000a): /* Pioneer DJ DJM-900NXS2 */ + case USB_ID(0x2b73, 0x0017): /* Pioneer DJ DJM-250MK2 */ + ep = 0x82; + ifnum = 0; + goto add_sync_ep_from_ifnum; case USB_ID(0x0582, 0x01d8): /* BOSS Katana */ /* BOSS Katana amplifiers do not need quirks */ return 0; @@ -458,6 +482,8 @@ SND_USB_ENDPOINT_TYPE_DATA); if (!subs->sync_endpoint) return -EINVAL; + + subs->sync_endpoint->is_implicit_feedback = 1; subs->data_endpoint->sync_master = subs->sync_endpoint; @@ -557,11 +583,14 @@ implicit_fb ? SND_USB_ENDPOINT_TYPE_DATA : SND_USB_ENDPOINT_TYPE_SYNC); + if (!subs->sync_endpoint) { if (is_playback && attr == USB_ENDPOINT_SYNC_NONE) return 0; return -EINVAL; } + + subs->sync_endpoint->is_implicit_feedback = implicit_fb; subs->data_endpoint->sync_master = subs->sync_endpoint; @@ -623,6 +652,10 @@ } dev_dbg(&dev->dev, "setting usb interface %d:%d\n", fmt->iface, fmt->altsetting); + err = snd_vendor_set_pcm_intf(iface, fmt->iface, + fmt->altsetting, subs->direction); + if (err) + return err; snd_usb_set_interface_quirk(dev); } @@ -650,12 +683,8 @@ return 0; } -/** - * snd_usb_enable_audio_stream - Enable/disable the specified usb substream. - * @subs: pointer to the usb substream. - * @datainterval: data packet interval. - * @enable: if true, enable the usb substream. Else disable. - */ +static int snd_usb_pcm_change_state(struct snd_usb_substream *subs, int state); + int snd_usb_enable_audio_stream(struct snd_usb_substream *subs, int datainterval, bool enable) { @@ -663,9 +692,6 @@ struct usb_host_interface *alts; struct usb_interface *iface; int ret; - - if (!subs || !subs->stream) - return -EINVAL; if (!enable) { if (subs->interface >= 0) { @@ -680,12 +706,17 @@ } snd_usb_autoresume(subs->stream->chip); + + ret = snd_usb_pcm_change_state(subs, UAC3_PD_STATE_D0); + if (ret < 0) + return ret; + if (datainterval != -EINVAL) fmt = find_format_and_si(subs, datainterval); else fmt = find_format(subs); if (!fmt) { - dev_dbg(&subs->dev->dev, + dev_err(&subs->dev->dev, "cannot set format: format = %#x, rate = %d, channels = %d\n", subs->pcm_format, subs->cur_rate, subs->channels); return -EINVAL; @@ -693,19 +724,12 @@ subs->altset_idx = 0; subs->interface = -1; - - if (!subs->stream->chip) - return -EINVAL; - if (atomic_read(&subs->stream->chip->shutdown)) { ret = -ENODEV; } else { ret = set_format(subs, fmt); if (ret < 0) return ret; - - if (!subs->cur_audiofmt) - return -EINVAL; iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface); if (!iface) { @@ -861,7 +885,8 @@ int ret; /* format changed */ - stop_endpoints(subs, true); + stop_endpoints(subs); + sync_pending_stops(subs); ret = snd_usb_endpoint_set_params(subs->data_endpoint, subs->pcm_format, subs->channels, @@ -945,13 +970,8 @@ struct audioformat *fmt; int ret; - if (snd_usb_use_vmalloc) - ret = snd_pcm_lib_alloc_vmalloc_buffer(substream, - params_buffer_bytes(hw_params)); - else - ret = snd_pcm_lib_malloc_pages(substream, - params_buffer_bytes(hw_params)); - if (ret < 0) + ret = snd_media_start_pipeline(subs); + if (ret) return ret; subs->pcm_format = params_format(hw_params); @@ -966,12 +986,13 @@ dev_dbg(&subs->dev->dev, "cannot set format: format = %#x, rate = %d, channels = %d\n", subs->pcm_format, subs->cur_rate, subs->channels); - return -EINVAL; + ret = -EINVAL; + goto stop_pipeline; } ret = snd_usb_lock_shutdown(subs->stream->chip); if (ret < 0) - return ret; + goto stop_pipeline; ret = snd_usb_pcm_change_state(subs, UAC3_PD_STATE_D0); if (ret < 0) @@ -987,6 +1008,12 @@ unlock: snd_usb_unlock_shutdown(subs->stream->chip); + if (ret < 0) + goto stop_pipeline; + return ret; + + stop_pipeline: + snd_media_stop_pipeline(subs); return ret; } @@ -999,20 +1026,19 @@ { struct snd_usb_substream *subs = substream->runtime->private_data; + snd_media_stop_pipeline(subs); subs->cur_audiofmt = NULL; subs->cur_rate = 0; subs->period_bytes = 0; if (!snd_usb_lock_shutdown(subs->stream->chip)) { - stop_endpoints(subs, true); + stop_endpoints(subs); + sync_pending_stops(subs); snd_usb_endpoint_deactivate(subs->sync_endpoint); snd_usb_endpoint_deactivate(subs->data_endpoint); snd_usb_unlock_shutdown(subs->stream->chip); } - if (snd_usb_use_vmalloc) - return snd_pcm_lib_free_vmalloc_buffer(substream); - else - return snd_pcm_lib_free_pages(substream); + return 0; } /* @@ -1028,6 +1054,10 @@ struct usb_interface *iface; int ret; + ret = snd_vendor_set_pcm_buf(subs->dev, subs->cur_audiofmt->iface); + if (ret) + return ret; + if (! subs->cur_audiofmt) { dev_err(&subs->dev->dev, "no format is specified!\n"); return -ENXIO; @@ -1040,9 +1070,6 @@ ret = -EIO; goto unlock; } - - snd_usb_endpoint_sync_pending_stop(subs->sync_endpoint); - snd_usb_endpoint_sync_pending_stop(subs->data_endpoint); ret = snd_usb_pcm_change_state(subs, UAC3_PD_STATE_D0); if (ret < 0) @@ -1063,6 +1090,17 @@ subs->cur_rate); if (ret < 0) goto unlock; + + if (snd_vendor_get_ops()) { + ret = snd_vendor_set_rate(iface, + subs->cur_audiofmt->iface, + subs->cur_rate, + subs->cur_audiofmt->altsetting); + if (!ret) { + subs->need_setup_ep = false; + goto unlock; + } + } ret = configure_endpoint(subs); if (ret < 0) @@ -1471,6 +1509,13 @@ struct snd_usb_stream *as = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct snd_usb_substream *subs = &as->substream[direction]; + int ret; + bool is_support = false; + + ret = snd_vendor_set_pcm_connection(subs->dev, SOUND_PCM_OPEN, + direction); + if (ret) + return ret; subs->interface = -1; subs->altset_idx = 0; @@ -1484,7 +1529,18 @@ subs->dsd_dop.channel = 0; subs->dsd_dop.marker = 1; - return setup_hw_info(runtime, subs); + ret = setup_hw_info(runtime, subs); + if (ret == 0) { + ret = snd_media_stream_init(subs, as->pcm, direction); + if (ret) + snd_usb_autosuspend(subs->stream->chip); + } + + trace_android_vh_sound_usb_support_cpu_suspend(subs->dev, direction, &is_support); + if (!ret && is_support) + snd_usb_autosuspend(subs->stream->chip); + + return ret; } static int snd_usb_pcm_close(struct snd_pcm_substream *substream) @@ -1493,13 +1549,29 @@ struct snd_usb_stream *as = snd_pcm_substream_chip(substream); struct snd_usb_substream *subs = &as->substream[direction]; int ret; + bool is_support = false; - stop_endpoints(subs, true); + ret = snd_vendor_set_pcm_connection(subs->dev, SOUND_PCM_CLOSE, + direction); + if (ret) + return ret; + + trace_android_vh_sound_usb_support_cpu_suspend(subs->dev, direction, &is_support); + if (!ret && is_support) + snd_usb_autoresume(subs->stream->chip); + + snd_media_stop_pipeline(subs); if (!as->chip->keep_iface && subs->interface >= 0 && !snd_usb_lock_shutdown(subs->stream->chip)) { usb_set_interface(subs->dev, subs->interface, 0); + ret = snd_vendor_set_pcm_intf(usb_ifnum_to_if(subs->dev, + subs->interface), + subs->interface, 0, + direction); + if (ret) + return ret; subs->interface = -1; ret = snd_usb_pcm_change_state(subs, UAC3_PD_STATE_D1); snd_usb_unlock_shutdown(subs->stream->chip); @@ -1541,6 +1613,12 @@ // continue; } bytes = urb->iso_frame_desc[i].actual_length; + if (subs->stream_offset_adj > 0) { + unsigned int adj = min(subs->stream_offset_adj, bytes); + cp += adj; + bytes -= adj; + subs->stream_offset_adj -= adj; + } frames = bytes / stride; if (!subs->txfr_quirk) bytes = frames * stride; @@ -1712,6 +1790,8 @@ for (i = 0; i < ctx->packets; i++) { if (ctx->packet_size[i]) counts = ctx->packet_size[i]; + else if (ep->sync_master) + counts = snd_usb_endpoint_slave_next_packet_size(ep); else counts = snd_usb_endpoint_next_packet_size(ep); @@ -1815,8 +1895,8 @@ int processed = urb->transfer_buffer_length / ep->stride; int est_delay; - /* ignore the delay accounting when procssed=0 is given, i.e. - * silent payloads are procssed before handling the actual data + /* ignore the delay accounting when processed=0 is given, i.e. + * silent payloads are processed before handling the actual data */ if (!processed) return; @@ -1862,22 +1942,15 @@ switch (cmd) { case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: subs->trigger_tstamp_pending_update = true; - /* fall through */ + fallthrough; case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: subs->data_endpoint->prepare_data_urb = prepare_playback_urb; subs->data_endpoint->retire_data_urb = retire_playback_urb; subs->running = 1; return 0; - case SNDRV_PCM_TRIGGER_SUSPEND: - stop_endpoints(subs, true); - subs->running = 0; - if (subs->stream->chip->setup_fmt_after_resume_quirk) - subs->need_setup_fmt = true; - return 0; case SNDRV_PCM_TRIGGER_STOP: - stop_endpoints(subs, false); + stop_endpoints(subs); subs->running = 0; return 0; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: @@ -1886,6 +1959,13 @@ subs->data_endpoint->retire_data_urb = retire_playback_urb; subs->running = 0; return 0; + case SNDRV_PCM_TRIGGER_SUSPEND: + if (subs->stream->chip->setup_fmt_after_resume_quirk) { + stop_endpoints(subs); + subs->need_setup_fmt = true; + return 0; + } + break; } return -EINVAL; @@ -1899,7 +1979,6 @@ switch (cmd) { case SNDRV_PCM_TRIGGER_START: - case SNDRV_PCM_TRIGGER_RESUME: err = start_endpoints(subs); if (err < 0) return err; @@ -1907,14 +1986,9 @@ subs->data_endpoint->retire_data_urb = retire_capture_urb; subs->running = 1; return 0; - case SNDRV_PCM_TRIGGER_SUSPEND: - stop_endpoints(subs, true); - subs->running = 0; - if (subs->stream->chip->setup_fmt_after_resume_quirk) - subs->need_setup_fmt = true; - return 0; case SNDRV_PCM_TRIGGER_STOP: - stop_endpoints(subs, false); + stop_endpoints(subs); + subs->data_endpoint->retire_data_urb = NULL; subs->running = 0; return 0; case SNDRV_PCM_TRIGGER_PAUSE_PUSH: @@ -1925,6 +1999,13 @@ subs->data_endpoint->retire_data_urb = retire_capture_urb; subs->running = 1; return 0; + case SNDRV_PCM_TRIGGER_SUSPEND: + if (subs->stream->chip->setup_fmt_after_resume_quirk) { + stop_endpoints(subs); + subs->need_setup_fmt = true; + return 0; + } + break; } return -EINVAL; @@ -1933,61 +2014,31 @@ static const struct snd_pcm_ops snd_usb_playback_ops = { .open = snd_usb_pcm_open, .close = snd_usb_pcm_close, - .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_usb_hw_params, .hw_free = snd_usb_hw_free, .prepare = snd_usb_pcm_prepare, .trigger = snd_usb_substream_playback_trigger, + .sync_stop = snd_usb_pcm_sync_stop, .pointer = snd_usb_pcm_pointer, - .page = snd_pcm_lib_get_vmalloc_page, }; static const struct snd_pcm_ops snd_usb_capture_ops = { .open = snd_usb_pcm_open, .close = snd_usb_pcm_close, - .ioctl = snd_pcm_lib_ioctl, .hw_params = snd_usb_hw_params, .hw_free = snd_usb_hw_free, .prepare = snd_usb_pcm_prepare, .trigger = snd_usb_substream_capture_trigger, + .sync_stop = snd_usb_pcm_sync_stop, .pointer = snd_usb_pcm_pointer, - .page = snd_pcm_lib_get_vmalloc_page, -}; - -static const struct snd_pcm_ops snd_usb_playback_dev_ops = { - .open = snd_usb_pcm_open, - .close = snd_usb_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_usb_hw_params, - .hw_free = snd_usb_hw_free, - .prepare = snd_usb_pcm_prepare, - .trigger = snd_usb_substream_playback_trigger, - .pointer = snd_usb_pcm_pointer, - .page = snd_pcm_sgbuf_ops_page, -}; - -static const struct snd_pcm_ops snd_usb_capture_dev_ops = { - .open = snd_usb_pcm_open, - .close = snd_usb_pcm_close, - .ioctl = snd_pcm_lib_ioctl, - .hw_params = snd_usb_hw_params, - .hw_free = snd_usb_hw_free, - .prepare = snd_usb_pcm_prepare, - .trigger = snd_usb_substream_capture_trigger, - .pointer = snd_usb_pcm_pointer, - .page = snd_pcm_sgbuf_ops_page, }; void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream) { const struct snd_pcm_ops *ops; - if (snd_usb_use_vmalloc) - ops = stream == SNDRV_PCM_STREAM_PLAYBACK ? + ops = stream == SNDRV_PCM_STREAM_PLAYBACK ? &snd_usb_playback_ops : &snd_usb_capture_ops; - else - ops = stream == SNDRV_PCM_STREAM_PLAYBACK ? - &snd_usb_playback_dev_ops : &snd_usb_capture_dev_ops; snd_pcm_set_ops(pcm, stream, ops); } @@ -1997,7 +2048,10 @@ struct snd_pcm_substream *s = pcm->streams[subs->direction].substream; struct device *dev = subs->dev->bus->sysdev; - if (!snd_usb_use_vmalloc) - snd_pcm_lib_preallocate_pages(s, SNDRV_DMA_TYPE_DEV_SG, - dev, 64*1024, 512*1024); + if (snd_usb_use_vmalloc) + snd_pcm_set_managed_buffer(s, SNDRV_DMA_TYPE_VMALLOC, + NULL, 0, 0); + else + snd_pcm_set_managed_buffer(s, SNDRV_DMA_TYPE_DEV_SG, + dev, 64*1024, 512*1024); } -- Gitblit v1.6.2