162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * (Tentative) USB Audio Driver for ALSA 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2002 by Takashi Iwai <tiwai@suse.de> 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Many codes borrowed from audio.c by 862306a36Sopenharmony_ci * Alan Cox (alan@lxorguk.ukuu.org.uk) 962306a36Sopenharmony_ci * Thomas Sailer (sailer@ife.ee.ethz.ch) 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Audio Class 3.0 support by Ruslan Bilovol <ruslan.bilovol@gmail.com> 1262306a36Sopenharmony_ci * 1362306a36Sopenharmony_ci * NOTES: 1462306a36Sopenharmony_ci * 1562306a36Sopenharmony_ci * - the linked URBs would be preferred but not used so far because of 1662306a36Sopenharmony_ci * the instability of unlinking. 1762306a36Sopenharmony_ci * - type II is not supported properly. there is no device which supports 1862306a36Sopenharmony_ci * this type *correctly*. SB extigy looks as if it supports, but it's 1962306a36Sopenharmony_ci * indeed an AC3 stream packed in SPDIF frames (i.e. no real AC3 stream). 2062306a36Sopenharmony_ci */ 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include <linux/bitops.h> 2462306a36Sopenharmony_ci#include <linux/init.h> 2562306a36Sopenharmony_ci#include <linux/list.h> 2662306a36Sopenharmony_ci#include <linux/slab.h> 2762306a36Sopenharmony_ci#include <linux/string.h> 2862306a36Sopenharmony_ci#include <linux/ctype.h> 2962306a36Sopenharmony_ci#include <linux/usb.h> 3062306a36Sopenharmony_ci#include <linux/moduleparam.h> 3162306a36Sopenharmony_ci#include <linux/mutex.h> 3262306a36Sopenharmony_ci#include <linux/usb/audio.h> 3362306a36Sopenharmony_ci#include <linux/usb/audio-v2.h> 3462306a36Sopenharmony_ci#include <linux/usb/audio-v3.h> 3562306a36Sopenharmony_ci#include <linux/module.h> 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci#include <sound/control.h> 3862306a36Sopenharmony_ci#include <sound/core.h> 3962306a36Sopenharmony_ci#include <sound/info.h> 4062306a36Sopenharmony_ci#include <sound/pcm.h> 4162306a36Sopenharmony_ci#include <sound/pcm_params.h> 4262306a36Sopenharmony_ci#include <sound/initval.h> 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#include "usbaudio.h" 4562306a36Sopenharmony_ci#include "card.h" 4662306a36Sopenharmony_ci#include "midi.h" 4762306a36Sopenharmony_ci#include "midi2.h" 4862306a36Sopenharmony_ci#include "mixer.h" 4962306a36Sopenharmony_ci#include "proc.h" 5062306a36Sopenharmony_ci#include "quirks.h" 5162306a36Sopenharmony_ci#include "endpoint.h" 5262306a36Sopenharmony_ci#include "helper.h" 5362306a36Sopenharmony_ci#include "pcm.h" 5462306a36Sopenharmony_ci#include "format.h" 5562306a36Sopenharmony_ci#include "power.h" 5662306a36Sopenharmony_ci#include "stream.h" 5762306a36Sopenharmony_ci#include "media.h" 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ciMODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); 6062306a36Sopenharmony_ciMODULE_DESCRIPTION("USB Audio"); 6162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ 6462306a36Sopenharmony_cistatic char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ 6562306a36Sopenharmony_cistatic bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card */ 6662306a36Sopenharmony_ci/* Vendor/product IDs for this card */ 6762306a36Sopenharmony_cistatic int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; 6862306a36Sopenharmony_cistatic int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 }; 6962306a36Sopenharmony_cistatic int device_setup[SNDRV_CARDS]; /* device parameter for this card */ 7062306a36Sopenharmony_cistatic bool ignore_ctl_error; 7162306a36Sopenharmony_cistatic bool autoclock = true; 7262306a36Sopenharmony_cistatic bool lowlatency = true; 7362306a36Sopenharmony_cistatic char *quirk_alias[SNDRV_CARDS]; 7462306a36Sopenharmony_cistatic char *delayed_register[SNDRV_CARDS]; 7562306a36Sopenharmony_cistatic bool implicit_fb[SNDRV_CARDS]; 7662306a36Sopenharmony_cistatic unsigned int quirk_flags[SNDRV_CARDS]; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_cibool snd_usb_use_vmalloc = true; 7962306a36Sopenharmony_cibool snd_usb_skip_validation; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_cimodule_param_array(index, int, NULL, 0444); 8262306a36Sopenharmony_ciMODULE_PARM_DESC(index, "Index value for the USB audio adapter."); 8362306a36Sopenharmony_cimodule_param_array(id, charp, NULL, 0444); 8462306a36Sopenharmony_ciMODULE_PARM_DESC(id, "ID string for the USB audio adapter."); 8562306a36Sopenharmony_cimodule_param_array(enable, bool, NULL, 0444); 8662306a36Sopenharmony_ciMODULE_PARM_DESC(enable, "Enable USB audio adapter."); 8762306a36Sopenharmony_cimodule_param_array(vid, int, NULL, 0444); 8862306a36Sopenharmony_ciMODULE_PARM_DESC(vid, "Vendor ID for the USB audio device."); 8962306a36Sopenharmony_cimodule_param_array(pid, int, NULL, 0444); 9062306a36Sopenharmony_ciMODULE_PARM_DESC(pid, "Product ID for the USB audio device."); 9162306a36Sopenharmony_cimodule_param_array(device_setup, int, NULL, 0444); 9262306a36Sopenharmony_ciMODULE_PARM_DESC(device_setup, "Specific device setup (if needed)."); 9362306a36Sopenharmony_cimodule_param(ignore_ctl_error, bool, 0444); 9462306a36Sopenharmony_ciMODULE_PARM_DESC(ignore_ctl_error, 9562306a36Sopenharmony_ci "Ignore errors from USB controller for mixer interfaces."); 9662306a36Sopenharmony_cimodule_param(autoclock, bool, 0444); 9762306a36Sopenharmony_ciMODULE_PARM_DESC(autoclock, "Enable auto-clock selection for UAC2 devices (default: yes)."); 9862306a36Sopenharmony_cimodule_param(lowlatency, bool, 0444); 9962306a36Sopenharmony_ciMODULE_PARM_DESC(lowlatency, "Enable low latency playback (default: yes)."); 10062306a36Sopenharmony_cimodule_param_array(quirk_alias, charp, NULL, 0444); 10162306a36Sopenharmony_ciMODULE_PARM_DESC(quirk_alias, "Quirk aliases, e.g. 0123abcd:5678beef."); 10262306a36Sopenharmony_cimodule_param_array(delayed_register, charp, NULL, 0444); 10362306a36Sopenharmony_ciMODULE_PARM_DESC(delayed_register, "Quirk for delayed registration, given by id:iface, e.g. 0123abcd:4."); 10462306a36Sopenharmony_cimodule_param_array(implicit_fb, bool, NULL, 0444); 10562306a36Sopenharmony_ciMODULE_PARM_DESC(implicit_fb, "Apply generic implicit feedback sync mode."); 10662306a36Sopenharmony_cimodule_param_array(quirk_flags, uint, NULL, 0444); 10762306a36Sopenharmony_ciMODULE_PARM_DESC(quirk_flags, "Driver quirk bit flags."); 10862306a36Sopenharmony_cimodule_param_named(use_vmalloc, snd_usb_use_vmalloc, bool, 0444); 10962306a36Sopenharmony_ciMODULE_PARM_DESC(use_vmalloc, "Use vmalloc for PCM intermediate buffers (default: yes)."); 11062306a36Sopenharmony_cimodule_param_named(skip_validation, snd_usb_skip_validation, bool, 0444); 11162306a36Sopenharmony_ciMODULE_PARM_DESC(skip_validation, "Skip unit descriptor validation (default: no)."); 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci/* 11462306a36Sopenharmony_ci * we keep the snd_usb_audio_t instances by ourselves for merging 11562306a36Sopenharmony_ci * the all interfaces on the same card as one sound device. 11662306a36Sopenharmony_ci */ 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_cistatic DEFINE_MUTEX(register_mutex); 11962306a36Sopenharmony_cistatic struct snd_usb_audio *usb_chip[SNDRV_CARDS]; 12062306a36Sopenharmony_cistatic struct usb_driver usb_audio_driver; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci/* 12362306a36Sopenharmony_ci * disconnect streams 12462306a36Sopenharmony_ci * called from usb_audio_disconnect() 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_cistatic void snd_usb_stream_disconnect(struct snd_usb_stream *as) 12762306a36Sopenharmony_ci{ 12862306a36Sopenharmony_ci int idx; 12962306a36Sopenharmony_ci struct snd_usb_substream *subs; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci for (idx = 0; idx < 2; idx++) { 13262306a36Sopenharmony_ci subs = &as->substream[idx]; 13362306a36Sopenharmony_ci if (!subs->num_formats) 13462306a36Sopenharmony_ci continue; 13562306a36Sopenharmony_ci subs->data_endpoint = NULL; 13662306a36Sopenharmony_ci subs->sync_endpoint = NULL; 13762306a36Sopenharmony_ci } 13862306a36Sopenharmony_ci} 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_cistatic int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int interface) 14162306a36Sopenharmony_ci{ 14262306a36Sopenharmony_ci struct usb_device *dev = chip->dev; 14362306a36Sopenharmony_ci struct usb_host_interface *alts; 14462306a36Sopenharmony_ci struct usb_interface_descriptor *altsd; 14562306a36Sopenharmony_ci struct usb_interface *iface = usb_ifnum_to_if(dev, interface); 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci if (!iface) { 14862306a36Sopenharmony_ci dev_err(&dev->dev, "%u:%d : does not exist\n", 14962306a36Sopenharmony_ci ctrlif, interface); 15062306a36Sopenharmony_ci return -EINVAL; 15162306a36Sopenharmony_ci } 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_ci alts = &iface->altsetting[0]; 15462306a36Sopenharmony_ci altsd = get_iface_desc(alts); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci /* 15762306a36Sopenharmony_ci * Android with both accessory and audio interfaces enabled gets the 15862306a36Sopenharmony_ci * interface numbers wrong. 15962306a36Sopenharmony_ci */ 16062306a36Sopenharmony_ci if ((chip->usb_id == USB_ID(0x18d1, 0x2d04) || 16162306a36Sopenharmony_ci chip->usb_id == USB_ID(0x18d1, 0x2d05)) && 16262306a36Sopenharmony_ci interface == 0 && 16362306a36Sopenharmony_ci altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC && 16462306a36Sopenharmony_ci altsd->bInterfaceSubClass == USB_SUBCLASS_VENDOR_SPEC) { 16562306a36Sopenharmony_ci interface = 2; 16662306a36Sopenharmony_ci iface = usb_ifnum_to_if(dev, interface); 16762306a36Sopenharmony_ci if (!iface) 16862306a36Sopenharmony_ci return -EINVAL; 16962306a36Sopenharmony_ci alts = &iface->altsetting[0]; 17062306a36Sopenharmony_ci altsd = get_iface_desc(alts); 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci if (usb_interface_claimed(iface)) { 17462306a36Sopenharmony_ci dev_dbg(&dev->dev, "%d:%d: skipping, already claimed\n", 17562306a36Sopenharmony_ci ctrlif, interface); 17662306a36Sopenharmony_ci return -EINVAL; 17762306a36Sopenharmony_ci } 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci if ((altsd->bInterfaceClass == USB_CLASS_AUDIO || 18062306a36Sopenharmony_ci altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC) && 18162306a36Sopenharmony_ci altsd->bInterfaceSubClass == USB_SUBCLASS_MIDISTREAMING) { 18262306a36Sopenharmony_ci int err = snd_usb_midi_v2_create(chip, iface, NULL, 18362306a36Sopenharmony_ci chip->usb_id); 18462306a36Sopenharmony_ci if (err < 0) { 18562306a36Sopenharmony_ci dev_err(&dev->dev, 18662306a36Sopenharmony_ci "%u:%d: cannot create sequencer device\n", 18762306a36Sopenharmony_ci ctrlif, interface); 18862306a36Sopenharmony_ci return -EINVAL; 18962306a36Sopenharmony_ci } 19062306a36Sopenharmony_ci return usb_driver_claim_interface(&usb_audio_driver, iface, 19162306a36Sopenharmony_ci USB_AUDIO_IFACE_UNUSED); 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if ((altsd->bInterfaceClass != USB_CLASS_AUDIO && 19562306a36Sopenharmony_ci altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) || 19662306a36Sopenharmony_ci altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING) { 19762306a36Sopenharmony_ci dev_dbg(&dev->dev, 19862306a36Sopenharmony_ci "%u:%d: skipping non-supported interface %d\n", 19962306a36Sopenharmony_ci ctrlif, interface, altsd->bInterfaceClass); 20062306a36Sopenharmony_ci /* skip non-supported classes */ 20162306a36Sopenharmony_ci return -EINVAL; 20262306a36Sopenharmony_ci } 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci if (snd_usb_get_speed(dev) == USB_SPEED_LOW) { 20562306a36Sopenharmony_ci dev_err(&dev->dev, "low speed audio streaming not supported\n"); 20662306a36Sopenharmony_ci return -EINVAL; 20762306a36Sopenharmony_ci } 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (! snd_usb_parse_audio_interface(chip, interface)) { 21062306a36Sopenharmony_ci usb_set_interface(dev, interface, 0); /* reset the current interface */ 21162306a36Sopenharmony_ci return usb_driver_claim_interface(&usb_audio_driver, iface, 21262306a36Sopenharmony_ci USB_AUDIO_IFACE_UNUSED); 21362306a36Sopenharmony_ci } 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci return 0; 21662306a36Sopenharmony_ci} 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci/* 21962306a36Sopenharmony_ci * parse audio control descriptor and create pcm/midi streams 22062306a36Sopenharmony_ci */ 22162306a36Sopenharmony_cistatic int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci struct usb_device *dev = chip->dev; 22462306a36Sopenharmony_ci struct usb_host_interface *host_iface; 22562306a36Sopenharmony_ci struct usb_interface_descriptor *altsd; 22662306a36Sopenharmony_ci int i, protocol; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci /* find audiocontrol interface */ 22962306a36Sopenharmony_ci host_iface = &usb_ifnum_to_if(dev, ctrlif)->altsetting[0]; 23062306a36Sopenharmony_ci altsd = get_iface_desc(host_iface); 23162306a36Sopenharmony_ci protocol = altsd->bInterfaceProtocol; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci switch (protocol) { 23462306a36Sopenharmony_ci default: 23562306a36Sopenharmony_ci dev_warn(&dev->dev, 23662306a36Sopenharmony_ci "unknown interface protocol %#02x, assuming v1\n", 23762306a36Sopenharmony_ci protocol); 23862306a36Sopenharmony_ci fallthrough; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci case UAC_VERSION_1: { 24162306a36Sopenharmony_ci struct uac1_ac_header_descriptor *h1; 24262306a36Sopenharmony_ci int rest_bytes; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci h1 = snd_usb_find_csint_desc(host_iface->extra, 24562306a36Sopenharmony_ci host_iface->extralen, 24662306a36Sopenharmony_ci NULL, UAC_HEADER); 24762306a36Sopenharmony_ci if (!h1 || h1->bLength < sizeof(*h1)) { 24862306a36Sopenharmony_ci dev_err(&dev->dev, "cannot find UAC_HEADER\n"); 24962306a36Sopenharmony_ci return -EINVAL; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci 25262306a36Sopenharmony_ci rest_bytes = (void *)(host_iface->extra + 25362306a36Sopenharmony_ci host_iface->extralen) - (void *)h1; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci /* just to be sure -- this shouldn't hit at all */ 25662306a36Sopenharmony_ci if (rest_bytes <= 0) { 25762306a36Sopenharmony_ci dev_err(&dev->dev, "invalid control header\n"); 25862306a36Sopenharmony_ci return -EINVAL; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci if (rest_bytes < sizeof(*h1)) { 26262306a36Sopenharmony_ci dev_err(&dev->dev, "too short v1 buffer descriptor\n"); 26362306a36Sopenharmony_ci return -EINVAL; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci 26662306a36Sopenharmony_ci if (!h1->bInCollection) { 26762306a36Sopenharmony_ci dev_info(&dev->dev, "skipping empty audio interface (v1)\n"); 26862306a36Sopenharmony_ci return -EINVAL; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci if (rest_bytes < h1->bLength) { 27262306a36Sopenharmony_ci dev_err(&dev->dev, "invalid buffer length (v1)\n"); 27362306a36Sopenharmony_ci return -EINVAL; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci 27662306a36Sopenharmony_ci if (h1->bLength < sizeof(*h1) + h1->bInCollection) { 27762306a36Sopenharmony_ci dev_err(&dev->dev, "invalid UAC_HEADER (v1)\n"); 27862306a36Sopenharmony_ci return -EINVAL; 27962306a36Sopenharmony_ci } 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci for (i = 0; i < h1->bInCollection; i++) 28262306a36Sopenharmony_ci snd_usb_create_stream(chip, ctrlif, h1->baInterfaceNr[i]); 28362306a36Sopenharmony_ci 28462306a36Sopenharmony_ci break; 28562306a36Sopenharmony_ci } 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci case UAC_VERSION_2: 28862306a36Sopenharmony_ci case UAC_VERSION_3: { 28962306a36Sopenharmony_ci struct usb_interface_assoc_descriptor *assoc = 29062306a36Sopenharmony_ci usb_ifnum_to_if(dev, ctrlif)->intf_assoc; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci if (!assoc) { 29362306a36Sopenharmony_ci /* 29462306a36Sopenharmony_ci * Firmware writers cannot count to three. So to find 29562306a36Sopenharmony_ci * the IAD on the NuForce UDH-100, also check the next 29662306a36Sopenharmony_ci * interface. 29762306a36Sopenharmony_ci */ 29862306a36Sopenharmony_ci struct usb_interface *iface = 29962306a36Sopenharmony_ci usb_ifnum_to_if(dev, ctrlif + 1); 30062306a36Sopenharmony_ci if (iface && 30162306a36Sopenharmony_ci iface->intf_assoc && 30262306a36Sopenharmony_ci iface->intf_assoc->bFunctionClass == USB_CLASS_AUDIO && 30362306a36Sopenharmony_ci iface->intf_assoc->bFunctionProtocol == UAC_VERSION_2) 30462306a36Sopenharmony_ci assoc = iface->intf_assoc; 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci if (!assoc) { 30862306a36Sopenharmony_ci dev_err(&dev->dev, "Audio class v2/v3 interfaces need an interface association\n"); 30962306a36Sopenharmony_ci return -EINVAL; 31062306a36Sopenharmony_ci } 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci if (protocol == UAC_VERSION_3) { 31362306a36Sopenharmony_ci int badd = assoc->bFunctionSubClass; 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_ci if (badd != UAC3_FUNCTION_SUBCLASS_FULL_ADC_3_0 && 31662306a36Sopenharmony_ci (badd < UAC3_FUNCTION_SUBCLASS_GENERIC_IO || 31762306a36Sopenharmony_ci badd > UAC3_FUNCTION_SUBCLASS_SPEAKERPHONE)) { 31862306a36Sopenharmony_ci dev_err(&dev->dev, 31962306a36Sopenharmony_ci "Unsupported UAC3 BADD profile\n"); 32062306a36Sopenharmony_ci return -EINVAL; 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci chip->badd_profile = badd; 32462306a36Sopenharmony_ci } 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci for (i = 0; i < assoc->bInterfaceCount; i++) { 32762306a36Sopenharmony_ci int intf = assoc->bFirstInterface + i; 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci if (intf != ctrlif) 33062306a36Sopenharmony_ci snd_usb_create_stream(chip, ctrlif, intf); 33162306a36Sopenharmony_ci } 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci break; 33462306a36Sopenharmony_ci } 33562306a36Sopenharmony_ci } 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci return 0; 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_ci/* 34162306a36Sopenharmony_ci * Profile name preset table 34262306a36Sopenharmony_ci */ 34362306a36Sopenharmony_cistruct usb_audio_device_name { 34462306a36Sopenharmony_ci u32 id; 34562306a36Sopenharmony_ci const char *vendor_name; 34662306a36Sopenharmony_ci const char *product_name; 34762306a36Sopenharmony_ci const char *profile_name; /* override card->longname */ 34862306a36Sopenharmony_ci}; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci#define PROFILE_NAME(vid, pid, vendor, product, profile) \ 35162306a36Sopenharmony_ci { .id = USB_ID(vid, pid), .vendor_name = (vendor), \ 35262306a36Sopenharmony_ci .product_name = (product), .profile_name = (profile) } 35362306a36Sopenharmony_ci#define DEVICE_NAME(vid, pid, vendor, product) \ 35462306a36Sopenharmony_ci PROFILE_NAME(vid, pid, vendor, product, NULL) 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci/* vendor/product and profile name presets, sorted in device id order */ 35762306a36Sopenharmony_cistatic const struct usb_audio_device_name usb_audio_names[] = { 35862306a36Sopenharmony_ci /* HP Thunderbolt Dock Audio Headset */ 35962306a36Sopenharmony_ci PROFILE_NAME(0x03f0, 0x0269, "HP", "Thunderbolt Dock Audio Headset", 36062306a36Sopenharmony_ci "HP-Thunderbolt-Dock-Audio-Headset"), 36162306a36Sopenharmony_ci /* HP Thunderbolt Dock Audio Module */ 36262306a36Sopenharmony_ci PROFILE_NAME(0x03f0, 0x0567, "HP", "Thunderbolt Dock Audio Module", 36362306a36Sopenharmony_ci "HP-Thunderbolt-Dock-Audio-Module"), 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci /* Two entries for Gigabyte TRX40 Aorus Master: 36662306a36Sopenharmony_ci * TRX40 Aorus Master has two USB-audio devices, one for the front 36762306a36Sopenharmony_ci * headphone with ESS SABRE9218 DAC chip, while another for the rest 36862306a36Sopenharmony_ci * I/O (the rear panel and the front mic) with Realtek ALC1220-VB. 36962306a36Sopenharmony_ci * Here we provide two distinct names for making UCM profiles easier. 37062306a36Sopenharmony_ci */ 37162306a36Sopenharmony_ci PROFILE_NAME(0x0414, 0xa000, "Gigabyte", "Aorus Master Front Headphone", 37262306a36Sopenharmony_ci "Gigabyte-Aorus-Master-Front-Headphone"), 37362306a36Sopenharmony_ci PROFILE_NAME(0x0414, 0xa001, "Gigabyte", "Aorus Master Main Audio", 37462306a36Sopenharmony_ci "Gigabyte-Aorus-Master-Main-Audio"), 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci /* Gigabyte TRX40 Aorus Pro WiFi */ 37762306a36Sopenharmony_ci PROFILE_NAME(0x0414, 0xa002, 37862306a36Sopenharmony_ci "Realtek", "ALC1220-VB-DT", "Realtek-ALC1220-VB-Desktop"), 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci /* Creative/E-Mu devices */ 38162306a36Sopenharmony_ci DEVICE_NAME(0x041e, 0x3010, "Creative Labs", "Sound Blaster MP3+"), 38262306a36Sopenharmony_ci /* Creative/Toshiba Multimedia Center SB-0500 */ 38362306a36Sopenharmony_ci DEVICE_NAME(0x041e, 0x3048, "Toshiba", "SB-0500"), 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci DEVICE_NAME(0x046d, 0x0990, "Logitech, Inc.", "QuickCam Pro 9000"), 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci DEVICE_NAME(0x05e1, 0x0408, "Syntek", "STK1160"), 38862306a36Sopenharmony_ci DEVICE_NAME(0x05e1, 0x0480, "Hauppauge", "Woodbury"), 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_ci /* ASUS ROG Zenith II: this machine has also two devices, one for 39162306a36Sopenharmony_ci * the front headphone and another for the rest 39262306a36Sopenharmony_ci */ 39362306a36Sopenharmony_ci PROFILE_NAME(0x0b05, 0x1915, "ASUS", "Zenith II Front Headphone", 39462306a36Sopenharmony_ci "Zenith-II-Front-Headphone"), 39562306a36Sopenharmony_ci PROFILE_NAME(0x0b05, 0x1916, "ASUS", "Zenith II Main Audio", 39662306a36Sopenharmony_ci "Zenith-II-Main-Audio"), 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci /* ASUS ROG Strix */ 39962306a36Sopenharmony_ci PROFILE_NAME(0x0b05, 0x1917, 40062306a36Sopenharmony_ci "Realtek", "ALC1220-VB-DT", "Realtek-ALC1220-VB-Desktop"), 40162306a36Sopenharmony_ci /* ASUS PRIME TRX40 PRO-S */ 40262306a36Sopenharmony_ci PROFILE_NAME(0x0b05, 0x1918, 40362306a36Sopenharmony_ci "Realtek", "ALC1220-VB-DT", "Realtek-ALC1220-VB-Desktop"), 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci /* Dell WD15 Dock */ 40662306a36Sopenharmony_ci PROFILE_NAME(0x0bda, 0x4014, "Dell", "WD15 Dock", "Dell-WD15-Dock"), 40762306a36Sopenharmony_ci /* Dell WD19 Dock */ 40862306a36Sopenharmony_ci PROFILE_NAME(0x0bda, 0x402e, "Dell", "WD19 Dock", "Dell-WD15-Dock"), 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_ci DEVICE_NAME(0x0ccd, 0x0028, "TerraTec", "Aureon5.1MkII"), 41162306a36Sopenharmony_ci 41262306a36Sopenharmony_ci /* 41362306a36Sopenharmony_ci * The original product_name is "USB Sound Device", however this name 41462306a36Sopenharmony_ci * is also used by the CM106 based cards, so make it unique. 41562306a36Sopenharmony_ci */ 41662306a36Sopenharmony_ci DEVICE_NAME(0x0d8c, 0x0102, NULL, "ICUSBAUDIO7D"), 41762306a36Sopenharmony_ci DEVICE_NAME(0x0d8c, 0x0103, NULL, "Audio Advantage MicroII"), 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci /* MSI TRX40 Creator */ 42062306a36Sopenharmony_ci PROFILE_NAME(0x0db0, 0x0d64, 42162306a36Sopenharmony_ci "Realtek", "ALC1220-VB-DT", "Realtek-ALC1220-VB-Desktop"), 42262306a36Sopenharmony_ci /* MSI TRX40 */ 42362306a36Sopenharmony_ci PROFILE_NAME(0x0db0, 0x543d, 42462306a36Sopenharmony_ci "Realtek", "ALC1220-VB-DT", "Realtek-ALC1220-VB-Desktop"), 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_ci DEVICE_NAME(0x0fd9, 0x0008, "Hauppauge", "HVR-950Q"), 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci /* Stanton/N2IT Final Scratch v1 device ('Scratchamp') */ 42962306a36Sopenharmony_ci DEVICE_NAME(0x103d, 0x0100, "Stanton", "ScratchAmp"), 43062306a36Sopenharmony_ci DEVICE_NAME(0x103d, 0x0101, "Stanton", "ScratchAmp"), 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci /* aka. Serato Scratch Live DJ Box */ 43362306a36Sopenharmony_ci DEVICE_NAME(0x13e5, 0x0001, "Rane", "SL-1"), 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci /* Lenovo ThinkStation P620 Rear Line-in, Line-out and Microphone */ 43662306a36Sopenharmony_ci PROFILE_NAME(0x17aa, 0x1046, "Lenovo", "ThinkStation P620 Rear", 43762306a36Sopenharmony_ci "Lenovo-ThinkStation-P620-Rear"), 43862306a36Sopenharmony_ci /* Lenovo ThinkStation P620 Internal Speaker + Front Headset */ 43962306a36Sopenharmony_ci PROFILE_NAME(0x17aa, 0x104d, "Lenovo", "ThinkStation P620 Main", 44062306a36Sopenharmony_ci "Lenovo-ThinkStation-P620-Main"), 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci /* Asrock TRX40 Creator */ 44362306a36Sopenharmony_ci PROFILE_NAME(0x26ce, 0x0a01, 44462306a36Sopenharmony_ci "Realtek", "ALC1220-VB-DT", "Realtek-ALC1220-VB-Desktop"), 44562306a36Sopenharmony_ci 44662306a36Sopenharmony_ci DEVICE_NAME(0x2040, 0x7200, "Hauppauge", "HVR-950Q"), 44762306a36Sopenharmony_ci DEVICE_NAME(0x2040, 0x7201, "Hauppauge", "HVR-950Q-MXL"), 44862306a36Sopenharmony_ci DEVICE_NAME(0x2040, 0x7210, "Hauppauge", "HVR-950Q"), 44962306a36Sopenharmony_ci DEVICE_NAME(0x2040, 0x7211, "Hauppauge", "HVR-950Q-MXL"), 45062306a36Sopenharmony_ci DEVICE_NAME(0x2040, 0x7213, "Hauppauge", "HVR-950Q"), 45162306a36Sopenharmony_ci DEVICE_NAME(0x2040, 0x7217, "Hauppauge", "HVR-950Q"), 45262306a36Sopenharmony_ci DEVICE_NAME(0x2040, 0x721b, "Hauppauge", "HVR-950Q"), 45362306a36Sopenharmony_ci DEVICE_NAME(0x2040, 0x721e, "Hauppauge", "HVR-950Q"), 45462306a36Sopenharmony_ci DEVICE_NAME(0x2040, 0x721f, "Hauppauge", "HVR-950Q"), 45562306a36Sopenharmony_ci DEVICE_NAME(0x2040, 0x7240, "Hauppauge", "HVR-850"), 45662306a36Sopenharmony_ci DEVICE_NAME(0x2040, 0x7260, "Hauppauge", "HVR-950Q"), 45762306a36Sopenharmony_ci DEVICE_NAME(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), 45862306a36Sopenharmony_ci DEVICE_NAME(0x2040, 0x7280, "Hauppauge", "HVR-950Q"), 45962306a36Sopenharmony_ci DEVICE_NAME(0x2040, 0x7281, "Hauppauge", "HVR-950Q-MXL"), 46062306a36Sopenharmony_ci DEVICE_NAME(0x2040, 0x8200, "Hauppauge", "Woodbury"), 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci { } /* terminator */ 46362306a36Sopenharmony_ci}; 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic const struct usb_audio_device_name * 46662306a36Sopenharmony_cilookup_device_name(u32 id) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci static const struct usb_audio_device_name *p; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci for (p = usb_audio_names; p->id; p++) 47162306a36Sopenharmony_ci if (p->id == id) 47262306a36Sopenharmony_ci return p; 47362306a36Sopenharmony_ci return NULL; 47462306a36Sopenharmony_ci} 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci/* 47762306a36Sopenharmony_ci * free the chip instance 47862306a36Sopenharmony_ci * 47962306a36Sopenharmony_ci * here we have to do not much, since pcm and controls are already freed 48062306a36Sopenharmony_ci * 48162306a36Sopenharmony_ci */ 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cistatic void snd_usb_audio_free(struct snd_card *card) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci struct snd_usb_audio *chip = card->private_data; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci snd_usb_endpoint_free_all(chip); 48862306a36Sopenharmony_ci snd_usb_midi_v2_free_all(chip); 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci mutex_destroy(&chip->mutex); 49162306a36Sopenharmony_ci if (!atomic_read(&chip->shutdown)) 49262306a36Sopenharmony_ci dev_set_drvdata(&chip->dev->dev, NULL); 49362306a36Sopenharmony_ci} 49462306a36Sopenharmony_ci 49562306a36Sopenharmony_cistatic void usb_audio_make_shortname(struct usb_device *dev, 49662306a36Sopenharmony_ci struct snd_usb_audio *chip, 49762306a36Sopenharmony_ci const struct snd_usb_audio_quirk *quirk) 49862306a36Sopenharmony_ci{ 49962306a36Sopenharmony_ci struct snd_card *card = chip->card; 50062306a36Sopenharmony_ci const struct usb_audio_device_name *preset; 50162306a36Sopenharmony_ci const char *s = NULL; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci preset = lookup_device_name(chip->usb_id); 50462306a36Sopenharmony_ci if (preset && preset->product_name) 50562306a36Sopenharmony_ci s = preset->product_name; 50662306a36Sopenharmony_ci else if (quirk && quirk->product_name) 50762306a36Sopenharmony_ci s = quirk->product_name; 50862306a36Sopenharmony_ci if (s && *s) { 50962306a36Sopenharmony_ci strscpy(card->shortname, s, sizeof(card->shortname)); 51062306a36Sopenharmony_ci return; 51162306a36Sopenharmony_ci } 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci /* retrieve the device string as shortname */ 51462306a36Sopenharmony_ci if (!dev->descriptor.iProduct || 51562306a36Sopenharmony_ci usb_string(dev, dev->descriptor.iProduct, 51662306a36Sopenharmony_ci card->shortname, sizeof(card->shortname)) <= 0) { 51762306a36Sopenharmony_ci /* no name available from anywhere, so use ID */ 51862306a36Sopenharmony_ci sprintf(card->shortname, "USB Device %#04x:%#04x", 51962306a36Sopenharmony_ci USB_ID_VENDOR(chip->usb_id), 52062306a36Sopenharmony_ci USB_ID_PRODUCT(chip->usb_id)); 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci strim(card->shortname); 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_cistatic void usb_audio_make_longname(struct usb_device *dev, 52762306a36Sopenharmony_ci struct snd_usb_audio *chip, 52862306a36Sopenharmony_ci const struct snd_usb_audio_quirk *quirk) 52962306a36Sopenharmony_ci{ 53062306a36Sopenharmony_ci struct snd_card *card = chip->card; 53162306a36Sopenharmony_ci const struct usb_audio_device_name *preset; 53262306a36Sopenharmony_ci const char *s = NULL; 53362306a36Sopenharmony_ci int len; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci preset = lookup_device_name(chip->usb_id); 53662306a36Sopenharmony_ci 53762306a36Sopenharmony_ci /* shortcut - if any pre-defined string is given, use it */ 53862306a36Sopenharmony_ci if (preset && preset->profile_name) 53962306a36Sopenharmony_ci s = preset->profile_name; 54062306a36Sopenharmony_ci if (s && *s) { 54162306a36Sopenharmony_ci strscpy(card->longname, s, sizeof(card->longname)); 54262306a36Sopenharmony_ci return; 54362306a36Sopenharmony_ci } 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ci if (preset && preset->vendor_name) 54662306a36Sopenharmony_ci s = preset->vendor_name; 54762306a36Sopenharmony_ci else if (quirk && quirk->vendor_name) 54862306a36Sopenharmony_ci s = quirk->vendor_name; 54962306a36Sopenharmony_ci *card->longname = 0; 55062306a36Sopenharmony_ci if (s && *s) { 55162306a36Sopenharmony_ci strscpy(card->longname, s, sizeof(card->longname)); 55262306a36Sopenharmony_ci } else { 55362306a36Sopenharmony_ci /* retrieve the vendor and device strings as longname */ 55462306a36Sopenharmony_ci if (dev->descriptor.iManufacturer) 55562306a36Sopenharmony_ci usb_string(dev, dev->descriptor.iManufacturer, 55662306a36Sopenharmony_ci card->longname, sizeof(card->longname)); 55762306a36Sopenharmony_ci /* we don't really care if there isn't any vendor string */ 55862306a36Sopenharmony_ci } 55962306a36Sopenharmony_ci if (*card->longname) { 56062306a36Sopenharmony_ci strim(card->longname); 56162306a36Sopenharmony_ci if (*card->longname) 56262306a36Sopenharmony_ci strlcat(card->longname, " ", sizeof(card->longname)); 56362306a36Sopenharmony_ci } 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci strlcat(card->longname, card->shortname, sizeof(card->longname)); 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci len = strlcat(card->longname, " at ", sizeof(card->longname)); 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci if (len < sizeof(card->longname)) 57062306a36Sopenharmony_ci usb_make_path(dev, card->longname + len, sizeof(card->longname) - len); 57162306a36Sopenharmony_ci 57262306a36Sopenharmony_ci switch (snd_usb_get_speed(dev)) { 57362306a36Sopenharmony_ci case USB_SPEED_LOW: 57462306a36Sopenharmony_ci strlcat(card->longname, ", low speed", sizeof(card->longname)); 57562306a36Sopenharmony_ci break; 57662306a36Sopenharmony_ci case USB_SPEED_FULL: 57762306a36Sopenharmony_ci strlcat(card->longname, ", full speed", sizeof(card->longname)); 57862306a36Sopenharmony_ci break; 57962306a36Sopenharmony_ci case USB_SPEED_HIGH: 58062306a36Sopenharmony_ci strlcat(card->longname, ", high speed", sizeof(card->longname)); 58162306a36Sopenharmony_ci break; 58262306a36Sopenharmony_ci case USB_SPEED_SUPER: 58362306a36Sopenharmony_ci strlcat(card->longname, ", super speed", sizeof(card->longname)); 58462306a36Sopenharmony_ci break; 58562306a36Sopenharmony_ci case USB_SPEED_SUPER_PLUS: 58662306a36Sopenharmony_ci strlcat(card->longname, ", super speed plus", sizeof(card->longname)); 58762306a36Sopenharmony_ci break; 58862306a36Sopenharmony_ci default: 58962306a36Sopenharmony_ci break; 59062306a36Sopenharmony_ci } 59162306a36Sopenharmony_ci} 59262306a36Sopenharmony_ci 59362306a36Sopenharmony_ci/* 59462306a36Sopenharmony_ci * create a chip instance and set its names. 59562306a36Sopenharmony_ci */ 59662306a36Sopenharmony_cistatic int snd_usb_audio_create(struct usb_interface *intf, 59762306a36Sopenharmony_ci struct usb_device *dev, int idx, 59862306a36Sopenharmony_ci const struct snd_usb_audio_quirk *quirk, 59962306a36Sopenharmony_ci unsigned int usb_id, 60062306a36Sopenharmony_ci struct snd_usb_audio **rchip) 60162306a36Sopenharmony_ci{ 60262306a36Sopenharmony_ci struct snd_card *card; 60362306a36Sopenharmony_ci struct snd_usb_audio *chip; 60462306a36Sopenharmony_ci int err; 60562306a36Sopenharmony_ci char component[14]; 60662306a36Sopenharmony_ci 60762306a36Sopenharmony_ci *rchip = NULL; 60862306a36Sopenharmony_ci 60962306a36Sopenharmony_ci switch (snd_usb_get_speed(dev)) { 61062306a36Sopenharmony_ci case USB_SPEED_LOW: 61162306a36Sopenharmony_ci case USB_SPEED_FULL: 61262306a36Sopenharmony_ci case USB_SPEED_HIGH: 61362306a36Sopenharmony_ci case USB_SPEED_SUPER: 61462306a36Sopenharmony_ci case USB_SPEED_SUPER_PLUS: 61562306a36Sopenharmony_ci break; 61662306a36Sopenharmony_ci default: 61762306a36Sopenharmony_ci dev_err(&dev->dev, "unknown device speed %d\n", snd_usb_get_speed(dev)); 61862306a36Sopenharmony_ci return -ENXIO; 61962306a36Sopenharmony_ci } 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_ci err = snd_card_new(&intf->dev, index[idx], id[idx], THIS_MODULE, 62262306a36Sopenharmony_ci sizeof(*chip), &card); 62362306a36Sopenharmony_ci if (err < 0) { 62462306a36Sopenharmony_ci dev_err(&dev->dev, "cannot create card instance %d\n", idx); 62562306a36Sopenharmony_ci return err; 62662306a36Sopenharmony_ci } 62762306a36Sopenharmony_ci 62862306a36Sopenharmony_ci chip = card->private_data; 62962306a36Sopenharmony_ci mutex_init(&chip->mutex); 63062306a36Sopenharmony_ci init_waitqueue_head(&chip->shutdown_wait); 63162306a36Sopenharmony_ci chip->index = idx; 63262306a36Sopenharmony_ci chip->dev = dev; 63362306a36Sopenharmony_ci chip->card = card; 63462306a36Sopenharmony_ci chip->setup = device_setup[idx]; 63562306a36Sopenharmony_ci chip->generic_implicit_fb = implicit_fb[idx]; 63662306a36Sopenharmony_ci chip->autoclock = autoclock; 63762306a36Sopenharmony_ci chip->lowlatency = lowlatency; 63862306a36Sopenharmony_ci atomic_set(&chip->active, 1); /* avoid autopm during probing */ 63962306a36Sopenharmony_ci atomic_set(&chip->usage_count, 0); 64062306a36Sopenharmony_ci atomic_set(&chip->shutdown, 0); 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci chip->usb_id = usb_id; 64362306a36Sopenharmony_ci INIT_LIST_HEAD(&chip->pcm_list); 64462306a36Sopenharmony_ci INIT_LIST_HEAD(&chip->ep_list); 64562306a36Sopenharmony_ci INIT_LIST_HEAD(&chip->iface_ref_list); 64662306a36Sopenharmony_ci INIT_LIST_HEAD(&chip->clock_ref_list); 64762306a36Sopenharmony_ci INIT_LIST_HEAD(&chip->midi_list); 64862306a36Sopenharmony_ci INIT_LIST_HEAD(&chip->midi_v2_list); 64962306a36Sopenharmony_ci INIT_LIST_HEAD(&chip->mixer_list); 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci if (quirk_flags[idx]) 65262306a36Sopenharmony_ci chip->quirk_flags = quirk_flags[idx]; 65362306a36Sopenharmony_ci else 65462306a36Sopenharmony_ci snd_usb_init_quirk_flags(chip); 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_ci card->private_free = snd_usb_audio_free; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci strcpy(card->driver, "USB-Audio"); 65962306a36Sopenharmony_ci sprintf(component, "USB%04x:%04x", 66062306a36Sopenharmony_ci USB_ID_VENDOR(chip->usb_id), USB_ID_PRODUCT(chip->usb_id)); 66162306a36Sopenharmony_ci snd_component_add(card, component); 66262306a36Sopenharmony_ci 66362306a36Sopenharmony_ci usb_audio_make_shortname(dev, chip, quirk); 66462306a36Sopenharmony_ci usb_audio_make_longname(dev, chip, quirk); 66562306a36Sopenharmony_ci 66662306a36Sopenharmony_ci snd_usb_audio_create_proc(chip); 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci *rchip = chip; 66962306a36Sopenharmony_ci return 0; 67062306a36Sopenharmony_ci} 67162306a36Sopenharmony_ci 67262306a36Sopenharmony_ci/* look for a matching quirk alias id */ 67362306a36Sopenharmony_cistatic bool get_alias_id(struct usb_device *dev, unsigned int *id) 67462306a36Sopenharmony_ci{ 67562306a36Sopenharmony_ci int i; 67662306a36Sopenharmony_ci unsigned int src, dst; 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(quirk_alias); i++) { 67962306a36Sopenharmony_ci if (!quirk_alias[i] || 68062306a36Sopenharmony_ci sscanf(quirk_alias[i], "%x:%x", &src, &dst) != 2 || 68162306a36Sopenharmony_ci src != *id) 68262306a36Sopenharmony_ci continue; 68362306a36Sopenharmony_ci dev_info(&dev->dev, 68462306a36Sopenharmony_ci "device (%04x:%04x): applying quirk alias %04x:%04x\n", 68562306a36Sopenharmony_ci USB_ID_VENDOR(*id), USB_ID_PRODUCT(*id), 68662306a36Sopenharmony_ci USB_ID_VENDOR(dst), USB_ID_PRODUCT(dst)); 68762306a36Sopenharmony_ci *id = dst; 68862306a36Sopenharmony_ci return true; 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci return false; 69262306a36Sopenharmony_ci} 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_cistatic int check_delayed_register_option(struct snd_usb_audio *chip) 69562306a36Sopenharmony_ci{ 69662306a36Sopenharmony_ci int i; 69762306a36Sopenharmony_ci unsigned int id, inum; 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(delayed_register); i++) { 70062306a36Sopenharmony_ci if (delayed_register[i] && 70162306a36Sopenharmony_ci sscanf(delayed_register[i], "%x:%x", &id, &inum) == 2 && 70262306a36Sopenharmony_ci id == chip->usb_id) 70362306a36Sopenharmony_ci return inum; 70462306a36Sopenharmony_ci } 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci return -1; 70762306a36Sopenharmony_ci} 70862306a36Sopenharmony_ci 70962306a36Sopenharmony_cistatic const struct usb_device_id usb_audio_ids[]; /* defined below */ 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci/* look for the last interface that matches with our ids and remember it */ 71262306a36Sopenharmony_cistatic void find_last_interface(struct snd_usb_audio *chip) 71362306a36Sopenharmony_ci{ 71462306a36Sopenharmony_ci struct usb_host_config *config = chip->dev->actconfig; 71562306a36Sopenharmony_ci struct usb_interface *intf; 71662306a36Sopenharmony_ci int i; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci if (!config) 71962306a36Sopenharmony_ci return; 72062306a36Sopenharmony_ci for (i = 0; i < config->desc.bNumInterfaces; i++) { 72162306a36Sopenharmony_ci intf = config->interface[i]; 72262306a36Sopenharmony_ci if (usb_match_id(intf, usb_audio_ids)) 72362306a36Sopenharmony_ci chip->last_iface = intf->altsetting[0].desc.bInterfaceNumber; 72462306a36Sopenharmony_ci } 72562306a36Sopenharmony_ci usb_audio_dbg(chip, "Found last interface = %d\n", chip->last_iface); 72662306a36Sopenharmony_ci} 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci/* look for the corresponding quirk */ 72962306a36Sopenharmony_cistatic const struct snd_usb_audio_quirk * 73062306a36Sopenharmony_ciget_alias_quirk(struct usb_device *dev, unsigned int id) 73162306a36Sopenharmony_ci{ 73262306a36Sopenharmony_ci const struct usb_device_id *p; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci for (p = usb_audio_ids; p->match_flags; p++) { 73562306a36Sopenharmony_ci /* FIXME: this checks only vendor:product pair in the list */ 73662306a36Sopenharmony_ci if ((p->match_flags & USB_DEVICE_ID_MATCH_DEVICE) == 73762306a36Sopenharmony_ci USB_DEVICE_ID_MATCH_DEVICE && 73862306a36Sopenharmony_ci p->idVendor == USB_ID_VENDOR(id) && 73962306a36Sopenharmony_ci p->idProduct == USB_ID_PRODUCT(id)) 74062306a36Sopenharmony_ci return (const struct snd_usb_audio_quirk *)p->driver_info; 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci return NULL; 74462306a36Sopenharmony_ci} 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci/* register card if we reach to the last interface or to the specified 74762306a36Sopenharmony_ci * one given via option 74862306a36Sopenharmony_ci */ 74962306a36Sopenharmony_cistatic int try_to_register_card(struct snd_usb_audio *chip, int ifnum) 75062306a36Sopenharmony_ci{ 75162306a36Sopenharmony_ci if (check_delayed_register_option(chip) == ifnum || 75262306a36Sopenharmony_ci chip->last_iface == ifnum || 75362306a36Sopenharmony_ci usb_interface_claimed(usb_ifnum_to_if(chip->dev, chip->last_iface))) 75462306a36Sopenharmony_ci return snd_card_register(chip->card); 75562306a36Sopenharmony_ci return 0; 75662306a36Sopenharmony_ci} 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci/* 75962306a36Sopenharmony_ci * probe the active usb device 76062306a36Sopenharmony_ci * 76162306a36Sopenharmony_ci * note that this can be called multiple times per a device, when it 76262306a36Sopenharmony_ci * includes multiple audio control interfaces. 76362306a36Sopenharmony_ci * 76462306a36Sopenharmony_ci * thus we check the usb device pointer and creates the card instance 76562306a36Sopenharmony_ci * only at the first time. the successive calls of this function will 76662306a36Sopenharmony_ci * append the pcm interface to the corresponding card. 76762306a36Sopenharmony_ci */ 76862306a36Sopenharmony_cistatic int usb_audio_probe(struct usb_interface *intf, 76962306a36Sopenharmony_ci const struct usb_device_id *usb_id) 77062306a36Sopenharmony_ci{ 77162306a36Sopenharmony_ci struct usb_device *dev = interface_to_usbdev(intf); 77262306a36Sopenharmony_ci const struct snd_usb_audio_quirk *quirk = 77362306a36Sopenharmony_ci (const struct snd_usb_audio_quirk *)usb_id->driver_info; 77462306a36Sopenharmony_ci struct snd_usb_audio *chip; 77562306a36Sopenharmony_ci int i, err; 77662306a36Sopenharmony_ci struct usb_host_interface *alts; 77762306a36Sopenharmony_ci int ifnum; 77862306a36Sopenharmony_ci u32 id; 77962306a36Sopenharmony_ci 78062306a36Sopenharmony_ci alts = &intf->altsetting[0]; 78162306a36Sopenharmony_ci ifnum = get_iface_desc(alts)->bInterfaceNumber; 78262306a36Sopenharmony_ci id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), 78362306a36Sopenharmony_ci le16_to_cpu(dev->descriptor.idProduct)); 78462306a36Sopenharmony_ci if (get_alias_id(dev, &id)) 78562306a36Sopenharmony_ci quirk = get_alias_quirk(dev, id); 78662306a36Sopenharmony_ci if (quirk && quirk->ifnum >= 0 && ifnum != quirk->ifnum) 78762306a36Sopenharmony_ci return -ENXIO; 78862306a36Sopenharmony_ci if (quirk && quirk->ifnum == QUIRK_NODEV_INTERFACE) 78962306a36Sopenharmony_ci return -ENODEV; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci err = snd_usb_apply_boot_quirk(dev, intf, quirk, id); 79262306a36Sopenharmony_ci if (err < 0) 79362306a36Sopenharmony_ci return err; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci /* 79662306a36Sopenharmony_ci * found a config. now register to ALSA 79762306a36Sopenharmony_ci */ 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci /* check whether it's already registered */ 80062306a36Sopenharmony_ci chip = NULL; 80162306a36Sopenharmony_ci mutex_lock(®ister_mutex); 80262306a36Sopenharmony_ci for (i = 0; i < SNDRV_CARDS; i++) { 80362306a36Sopenharmony_ci if (usb_chip[i] && usb_chip[i]->dev == dev) { 80462306a36Sopenharmony_ci if (atomic_read(&usb_chip[i]->shutdown)) { 80562306a36Sopenharmony_ci dev_err(&dev->dev, "USB device is in the shutdown state, cannot create a card instance\n"); 80662306a36Sopenharmony_ci err = -EIO; 80762306a36Sopenharmony_ci goto __error; 80862306a36Sopenharmony_ci } 80962306a36Sopenharmony_ci chip = usb_chip[i]; 81062306a36Sopenharmony_ci atomic_inc(&chip->active); /* avoid autopm */ 81162306a36Sopenharmony_ci break; 81262306a36Sopenharmony_ci } 81362306a36Sopenharmony_ci } 81462306a36Sopenharmony_ci if (! chip) { 81562306a36Sopenharmony_ci err = snd_usb_apply_boot_quirk_once(dev, intf, quirk, id); 81662306a36Sopenharmony_ci if (err < 0) 81762306a36Sopenharmony_ci goto __error; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci /* it's a fresh one. 82062306a36Sopenharmony_ci * now look for an empty slot and create a new card instance 82162306a36Sopenharmony_ci */ 82262306a36Sopenharmony_ci for (i = 0; i < SNDRV_CARDS; i++) 82362306a36Sopenharmony_ci if (!usb_chip[i] && 82462306a36Sopenharmony_ci (vid[i] == -1 || vid[i] == USB_ID_VENDOR(id)) && 82562306a36Sopenharmony_ci (pid[i] == -1 || pid[i] == USB_ID_PRODUCT(id))) { 82662306a36Sopenharmony_ci if (enable[i]) { 82762306a36Sopenharmony_ci err = snd_usb_audio_create(intf, dev, i, quirk, 82862306a36Sopenharmony_ci id, &chip); 82962306a36Sopenharmony_ci if (err < 0) 83062306a36Sopenharmony_ci goto __error; 83162306a36Sopenharmony_ci break; 83262306a36Sopenharmony_ci } else if (vid[i] != -1 || pid[i] != -1) { 83362306a36Sopenharmony_ci dev_info(&dev->dev, 83462306a36Sopenharmony_ci "device (%04x:%04x) is disabled\n", 83562306a36Sopenharmony_ci USB_ID_VENDOR(id), 83662306a36Sopenharmony_ci USB_ID_PRODUCT(id)); 83762306a36Sopenharmony_ci err = -ENOENT; 83862306a36Sopenharmony_ci goto __error; 83962306a36Sopenharmony_ci } 84062306a36Sopenharmony_ci } 84162306a36Sopenharmony_ci if (!chip) { 84262306a36Sopenharmony_ci dev_err(&dev->dev, "no available usb audio device\n"); 84362306a36Sopenharmony_ci err = -ENODEV; 84462306a36Sopenharmony_ci goto __error; 84562306a36Sopenharmony_ci } 84662306a36Sopenharmony_ci find_last_interface(chip); 84762306a36Sopenharmony_ci } 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci if (chip->num_interfaces >= MAX_CARD_INTERFACES) { 85062306a36Sopenharmony_ci dev_info(&dev->dev, "Too many interfaces assigned to the single USB-audio card\n"); 85162306a36Sopenharmony_ci err = -EINVAL; 85262306a36Sopenharmony_ci goto __error; 85362306a36Sopenharmony_ci } 85462306a36Sopenharmony_ci 85562306a36Sopenharmony_ci dev_set_drvdata(&dev->dev, chip); 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci if (ignore_ctl_error) 85862306a36Sopenharmony_ci chip->quirk_flags |= QUIRK_FLAG_IGNORE_CTL_ERROR; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci if (chip->quirk_flags & QUIRK_FLAG_DISABLE_AUTOSUSPEND) 86162306a36Sopenharmony_ci usb_disable_autosuspend(interface_to_usbdev(intf)); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci /* 86462306a36Sopenharmony_ci * For devices with more than one control interface, we assume the 86562306a36Sopenharmony_ci * first contains the audio controls. We might need a more specific 86662306a36Sopenharmony_ci * check here in the future. 86762306a36Sopenharmony_ci */ 86862306a36Sopenharmony_ci if (!chip->ctrl_intf) 86962306a36Sopenharmony_ci chip->ctrl_intf = alts; 87062306a36Sopenharmony_ci 87162306a36Sopenharmony_ci err = 1; /* continue */ 87262306a36Sopenharmony_ci if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) { 87362306a36Sopenharmony_ci /* need some special handlings */ 87462306a36Sopenharmony_ci err = snd_usb_create_quirk(chip, intf, &usb_audio_driver, quirk); 87562306a36Sopenharmony_ci if (err < 0) 87662306a36Sopenharmony_ci goto __error; 87762306a36Sopenharmony_ci } 87862306a36Sopenharmony_ci 87962306a36Sopenharmony_ci if (err > 0) { 88062306a36Sopenharmony_ci /* create normal USB audio interfaces */ 88162306a36Sopenharmony_ci err = snd_usb_create_streams(chip, ifnum); 88262306a36Sopenharmony_ci if (err < 0) 88362306a36Sopenharmony_ci goto __error; 88462306a36Sopenharmony_ci err = snd_usb_create_mixer(chip, ifnum); 88562306a36Sopenharmony_ci if (err < 0) 88662306a36Sopenharmony_ci goto __error; 88762306a36Sopenharmony_ci } 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci if (chip->need_delayed_register) { 89062306a36Sopenharmony_ci dev_info(&dev->dev, 89162306a36Sopenharmony_ci "Found post-registration device assignment: %08x:%02x\n", 89262306a36Sopenharmony_ci chip->usb_id, ifnum); 89362306a36Sopenharmony_ci chip->need_delayed_register = false; /* clear again */ 89462306a36Sopenharmony_ci } 89562306a36Sopenharmony_ci 89662306a36Sopenharmony_ci err = try_to_register_card(chip, ifnum); 89762306a36Sopenharmony_ci if (err < 0) 89862306a36Sopenharmony_ci goto __error_no_register; 89962306a36Sopenharmony_ci 90062306a36Sopenharmony_ci if (chip->quirk_flags & QUIRK_FLAG_SHARE_MEDIA_DEVICE) { 90162306a36Sopenharmony_ci /* don't want to fail when snd_media_device_create() fails */ 90262306a36Sopenharmony_ci snd_media_device_create(chip, intf); 90362306a36Sopenharmony_ci } 90462306a36Sopenharmony_ci 90562306a36Sopenharmony_ci if (quirk) 90662306a36Sopenharmony_ci chip->quirk_type = quirk->type; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci usb_chip[chip->index] = chip; 90962306a36Sopenharmony_ci chip->intf[chip->num_interfaces] = intf; 91062306a36Sopenharmony_ci chip->num_interfaces++; 91162306a36Sopenharmony_ci usb_set_intfdata(intf, chip); 91262306a36Sopenharmony_ci atomic_dec(&chip->active); 91362306a36Sopenharmony_ci mutex_unlock(®ister_mutex); 91462306a36Sopenharmony_ci return 0; 91562306a36Sopenharmony_ci 91662306a36Sopenharmony_ci __error: 91762306a36Sopenharmony_ci /* in the case of error in secondary interface, still try to register */ 91862306a36Sopenharmony_ci if (chip) 91962306a36Sopenharmony_ci try_to_register_card(chip, ifnum); 92062306a36Sopenharmony_ci 92162306a36Sopenharmony_ci __error_no_register: 92262306a36Sopenharmony_ci if (chip) { 92362306a36Sopenharmony_ci /* chip->active is inside the chip->card object, 92462306a36Sopenharmony_ci * decrement before memory is possibly returned. 92562306a36Sopenharmony_ci */ 92662306a36Sopenharmony_ci atomic_dec(&chip->active); 92762306a36Sopenharmony_ci if (!chip->num_interfaces) 92862306a36Sopenharmony_ci snd_card_free(chip->card); 92962306a36Sopenharmony_ci } 93062306a36Sopenharmony_ci mutex_unlock(®ister_mutex); 93162306a36Sopenharmony_ci return err; 93262306a36Sopenharmony_ci} 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci/* 93562306a36Sopenharmony_ci * we need to take care of counter, since disconnection can be called also 93662306a36Sopenharmony_ci * many times as well as usb_audio_probe(). 93762306a36Sopenharmony_ci */ 93862306a36Sopenharmony_cistatic void usb_audio_disconnect(struct usb_interface *intf) 93962306a36Sopenharmony_ci{ 94062306a36Sopenharmony_ci struct snd_usb_audio *chip = usb_get_intfdata(intf); 94162306a36Sopenharmony_ci struct snd_card *card; 94262306a36Sopenharmony_ci struct list_head *p; 94362306a36Sopenharmony_ci 94462306a36Sopenharmony_ci if (chip == USB_AUDIO_IFACE_UNUSED) 94562306a36Sopenharmony_ci return; 94662306a36Sopenharmony_ci 94762306a36Sopenharmony_ci card = chip->card; 94862306a36Sopenharmony_ci 94962306a36Sopenharmony_ci mutex_lock(®ister_mutex); 95062306a36Sopenharmony_ci if (atomic_inc_return(&chip->shutdown) == 1) { 95162306a36Sopenharmony_ci struct snd_usb_stream *as; 95262306a36Sopenharmony_ci struct snd_usb_endpoint *ep; 95362306a36Sopenharmony_ci struct usb_mixer_interface *mixer; 95462306a36Sopenharmony_ci 95562306a36Sopenharmony_ci /* wait until all pending tasks done; 95662306a36Sopenharmony_ci * they are protected by snd_usb_lock_shutdown() 95762306a36Sopenharmony_ci */ 95862306a36Sopenharmony_ci wait_event(chip->shutdown_wait, 95962306a36Sopenharmony_ci !atomic_read(&chip->usage_count)); 96062306a36Sopenharmony_ci snd_card_disconnect(card); 96162306a36Sopenharmony_ci /* release the pcm resources */ 96262306a36Sopenharmony_ci list_for_each_entry(as, &chip->pcm_list, list) { 96362306a36Sopenharmony_ci snd_usb_stream_disconnect(as); 96462306a36Sopenharmony_ci } 96562306a36Sopenharmony_ci /* release the endpoint resources */ 96662306a36Sopenharmony_ci list_for_each_entry(ep, &chip->ep_list, list) { 96762306a36Sopenharmony_ci snd_usb_endpoint_release(ep); 96862306a36Sopenharmony_ci } 96962306a36Sopenharmony_ci /* release the midi resources */ 97062306a36Sopenharmony_ci list_for_each(p, &chip->midi_list) { 97162306a36Sopenharmony_ci snd_usbmidi_disconnect(p); 97262306a36Sopenharmony_ci } 97362306a36Sopenharmony_ci snd_usb_midi_v2_disconnect_all(chip); 97462306a36Sopenharmony_ci /* 97562306a36Sopenharmony_ci * Nice to check quirk && quirk->shares_media_device and 97662306a36Sopenharmony_ci * then call the snd_media_device_delete(). Don't have 97762306a36Sopenharmony_ci * access to the quirk here. snd_media_device_delete() 97862306a36Sopenharmony_ci * accesses mixer_list 97962306a36Sopenharmony_ci */ 98062306a36Sopenharmony_ci snd_media_device_delete(chip); 98162306a36Sopenharmony_ci 98262306a36Sopenharmony_ci /* release mixer resources */ 98362306a36Sopenharmony_ci list_for_each_entry(mixer, &chip->mixer_list, list) { 98462306a36Sopenharmony_ci snd_usb_mixer_disconnect(mixer); 98562306a36Sopenharmony_ci } 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci if (chip->quirk_flags & QUIRK_FLAG_DISABLE_AUTOSUSPEND) 98962306a36Sopenharmony_ci usb_enable_autosuspend(interface_to_usbdev(intf)); 99062306a36Sopenharmony_ci 99162306a36Sopenharmony_ci chip->num_interfaces--; 99262306a36Sopenharmony_ci if (chip->num_interfaces <= 0) { 99362306a36Sopenharmony_ci usb_chip[chip->index] = NULL; 99462306a36Sopenharmony_ci mutex_unlock(®ister_mutex); 99562306a36Sopenharmony_ci snd_card_free_when_closed(card); 99662306a36Sopenharmony_ci } else { 99762306a36Sopenharmony_ci mutex_unlock(®ister_mutex); 99862306a36Sopenharmony_ci } 99962306a36Sopenharmony_ci} 100062306a36Sopenharmony_ci 100162306a36Sopenharmony_ci/* lock the shutdown (disconnect) task and autoresume */ 100262306a36Sopenharmony_ciint snd_usb_lock_shutdown(struct snd_usb_audio *chip) 100362306a36Sopenharmony_ci{ 100462306a36Sopenharmony_ci int err; 100562306a36Sopenharmony_ci 100662306a36Sopenharmony_ci atomic_inc(&chip->usage_count); 100762306a36Sopenharmony_ci if (atomic_read(&chip->shutdown)) { 100862306a36Sopenharmony_ci err = -EIO; 100962306a36Sopenharmony_ci goto error; 101062306a36Sopenharmony_ci } 101162306a36Sopenharmony_ci err = snd_usb_autoresume(chip); 101262306a36Sopenharmony_ci if (err < 0) 101362306a36Sopenharmony_ci goto error; 101462306a36Sopenharmony_ci return 0; 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci error: 101762306a36Sopenharmony_ci if (atomic_dec_and_test(&chip->usage_count)) 101862306a36Sopenharmony_ci wake_up(&chip->shutdown_wait); 101962306a36Sopenharmony_ci return err; 102062306a36Sopenharmony_ci} 102162306a36Sopenharmony_ci 102262306a36Sopenharmony_ci/* autosuspend and unlock the shutdown */ 102362306a36Sopenharmony_civoid snd_usb_unlock_shutdown(struct snd_usb_audio *chip) 102462306a36Sopenharmony_ci{ 102562306a36Sopenharmony_ci snd_usb_autosuspend(chip); 102662306a36Sopenharmony_ci if (atomic_dec_and_test(&chip->usage_count)) 102762306a36Sopenharmony_ci wake_up(&chip->shutdown_wait); 102862306a36Sopenharmony_ci} 102962306a36Sopenharmony_ci 103062306a36Sopenharmony_ciint snd_usb_autoresume(struct snd_usb_audio *chip) 103162306a36Sopenharmony_ci{ 103262306a36Sopenharmony_ci int i, err; 103362306a36Sopenharmony_ci 103462306a36Sopenharmony_ci if (atomic_read(&chip->shutdown)) 103562306a36Sopenharmony_ci return -EIO; 103662306a36Sopenharmony_ci if (atomic_inc_return(&chip->active) != 1) 103762306a36Sopenharmony_ci return 0; 103862306a36Sopenharmony_ci 103962306a36Sopenharmony_ci for (i = 0; i < chip->num_interfaces; i++) { 104062306a36Sopenharmony_ci err = usb_autopm_get_interface(chip->intf[i]); 104162306a36Sopenharmony_ci if (err < 0) { 104262306a36Sopenharmony_ci /* rollback */ 104362306a36Sopenharmony_ci while (--i >= 0) 104462306a36Sopenharmony_ci usb_autopm_put_interface(chip->intf[i]); 104562306a36Sopenharmony_ci atomic_dec(&chip->active); 104662306a36Sopenharmony_ci return err; 104762306a36Sopenharmony_ci } 104862306a36Sopenharmony_ci } 104962306a36Sopenharmony_ci return 0; 105062306a36Sopenharmony_ci} 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_civoid snd_usb_autosuspend(struct snd_usb_audio *chip) 105362306a36Sopenharmony_ci{ 105462306a36Sopenharmony_ci int i; 105562306a36Sopenharmony_ci 105662306a36Sopenharmony_ci if (atomic_read(&chip->shutdown)) 105762306a36Sopenharmony_ci return; 105862306a36Sopenharmony_ci if (!atomic_dec_and_test(&chip->active)) 105962306a36Sopenharmony_ci return; 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_ci for (i = 0; i < chip->num_interfaces; i++) 106262306a36Sopenharmony_ci usb_autopm_put_interface(chip->intf[i]); 106362306a36Sopenharmony_ci} 106462306a36Sopenharmony_ci 106562306a36Sopenharmony_cistatic int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) 106662306a36Sopenharmony_ci{ 106762306a36Sopenharmony_ci struct snd_usb_audio *chip = usb_get_intfdata(intf); 106862306a36Sopenharmony_ci struct snd_usb_stream *as; 106962306a36Sopenharmony_ci struct snd_usb_endpoint *ep; 107062306a36Sopenharmony_ci struct usb_mixer_interface *mixer; 107162306a36Sopenharmony_ci struct list_head *p; 107262306a36Sopenharmony_ci 107362306a36Sopenharmony_ci if (chip == USB_AUDIO_IFACE_UNUSED) 107462306a36Sopenharmony_ci return 0; 107562306a36Sopenharmony_ci 107662306a36Sopenharmony_ci if (!chip->num_suspended_intf++) { 107762306a36Sopenharmony_ci list_for_each_entry(as, &chip->pcm_list, list) 107862306a36Sopenharmony_ci snd_usb_pcm_suspend(as); 107962306a36Sopenharmony_ci list_for_each_entry(ep, &chip->ep_list, list) 108062306a36Sopenharmony_ci snd_usb_endpoint_suspend(ep); 108162306a36Sopenharmony_ci list_for_each(p, &chip->midi_list) 108262306a36Sopenharmony_ci snd_usbmidi_suspend(p); 108362306a36Sopenharmony_ci list_for_each_entry(mixer, &chip->mixer_list, list) 108462306a36Sopenharmony_ci snd_usb_mixer_suspend(mixer); 108562306a36Sopenharmony_ci snd_usb_midi_v2_suspend_all(chip); 108662306a36Sopenharmony_ci } 108762306a36Sopenharmony_ci 108862306a36Sopenharmony_ci if (!PMSG_IS_AUTO(message) && !chip->system_suspend) { 108962306a36Sopenharmony_ci snd_power_change_state(chip->card, SNDRV_CTL_POWER_D3hot); 109062306a36Sopenharmony_ci chip->system_suspend = chip->num_suspended_intf; 109162306a36Sopenharmony_ci } 109262306a36Sopenharmony_ci 109362306a36Sopenharmony_ci return 0; 109462306a36Sopenharmony_ci} 109562306a36Sopenharmony_ci 109662306a36Sopenharmony_cistatic int usb_audio_resume(struct usb_interface *intf) 109762306a36Sopenharmony_ci{ 109862306a36Sopenharmony_ci struct snd_usb_audio *chip = usb_get_intfdata(intf); 109962306a36Sopenharmony_ci struct snd_usb_stream *as; 110062306a36Sopenharmony_ci struct usb_mixer_interface *mixer; 110162306a36Sopenharmony_ci struct list_head *p; 110262306a36Sopenharmony_ci int err = 0; 110362306a36Sopenharmony_ci 110462306a36Sopenharmony_ci if (chip == USB_AUDIO_IFACE_UNUSED) 110562306a36Sopenharmony_ci return 0; 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci atomic_inc(&chip->active); /* avoid autopm */ 110862306a36Sopenharmony_ci if (chip->num_suspended_intf > 1) 110962306a36Sopenharmony_ci goto out; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci list_for_each_entry(as, &chip->pcm_list, list) { 111262306a36Sopenharmony_ci err = snd_usb_pcm_resume(as); 111362306a36Sopenharmony_ci if (err < 0) 111462306a36Sopenharmony_ci goto err_out; 111562306a36Sopenharmony_ci } 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci /* 111862306a36Sopenharmony_ci * ALSA leaves material resumption to user space 111962306a36Sopenharmony_ci * we just notify and restart the mixers 112062306a36Sopenharmony_ci */ 112162306a36Sopenharmony_ci list_for_each_entry(mixer, &chip->mixer_list, list) { 112262306a36Sopenharmony_ci err = snd_usb_mixer_resume(mixer); 112362306a36Sopenharmony_ci if (err < 0) 112462306a36Sopenharmony_ci goto err_out; 112562306a36Sopenharmony_ci } 112662306a36Sopenharmony_ci 112762306a36Sopenharmony_ci list_for_each(p, &chip->midi_list) { 112862306a36Sopenharmony_ci snd_usbmidi_resume(p); 112962306a36Sopenharmony_ci } 113062306a36Sopenharmony_ci 113162306a36Sopenharmony_ci snd_usb_midi_v2_resume_all(chip); 113262306a36Sopenharmony_ci 113362306a36Sopenharmony_ci out: 113462306a36Sopenharmony_ci if (chip->num_suspended_intf == chip->system_suspend) { 113562306a36Sopenharmony_ci snd_power_change_state(chip->card, SNDRV_CTL_POWER_D0); 113662306a36Sopenharmony_ci chip->system_suspend = 0; 113762306a36Sopenharmony_ci } 113862306a36Sopenharmony_ci chip->num_suspended_intf--; 113962306a36Sopenharmony_ci 114062306a36Sopenharmony_cierr_out: 114162306a36Sopenharmony_ci atomic_dec(&chip->active); /* allow autopm after this point */ 114262306a36Sopenharmony_ci return err; 114362306a36Sopenharmony_ci} 114462306a36Sopenharmony_ci 114562306a36Sopenharmony_cistatic const struct usb_device_id usb_audio_ids [] = { 114662306a36Sopenharmony_ci#include "quirks-table.h" 114762306a36Sopenharmony_ci { .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS), 114862306a36Sopenharmony_ci .bInterfaceClass = USB_CLASS_AUDIO, 114962306a36Sopenharmony_ci .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL }, 115062306a36Sopenharmony_ci { } /* Terminating entry */ 115162306a36Sopenharmony_ci}; 115262306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, usb_audio_ids); 115362306a36Sopenharmony_ci 115462306a36Sopenharmony_ci/* 115562306a36Sopenharmony_ci * entry point for linux usb interface 115662306a36Sopenharmony_ci */ 115762306a36Sopenharmony_ci 115862306a36Sopenharmony_cistatic struct usb_driver usb_audio_driver = { 115962306a36Sopenharmony_ci .name = "snd-usb-audio", 116062306a36Sopenharmony_ci .probe = usb_audio_probe, 116162306a36Sopenharmony_ci .disconnect = usb_audio_disconnect, 116262306a36Sopenharmony_ci .suspend = usb_audio_suspend, 116362306a36Sopenharmony_ci .resume = usb_audio_resume, 116462306a36Sopenharmony_ci .reset_resume = usb_audio_resume, 116562306a36Sopenharmony_ci .id_table = usb_audio_ids, 116662306a36Sopenharmony_ci .supports_autosuspend = 1, 116762306a36Sopenharmony_ci}; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_cimodule_usb_driver(usb_audio_driver); 1170