Commit bc23416c authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6:
  ALSA: hda-intel - fix wallclk variable update and condition
  ALSA: asihpi - Fix uninitialized variable
  ALSA: hda: Use LPIB for ASUS M2V
  usb/gadget: Replace the old USB audio FU definitions in f_audio.c
  ASoC: MX31ads sound support should depend on MACH_MX31ADS_WM1133_EV1
  ASoC: Add missing Kconfig entry for Phytec boards
  ALSA: usb-audio: export UAC2 clock selectors as mixer controls
  ALSA: usb-audio: clean up find_audio_control_unit()
  ALSA: usb-audio: add UAC2 sepecific Feature Unit controls
  ALSA: usb-audio: unify constants from specification
  ALSA: usb-audio: parse clock topology of UAC2 devices
  ALSA: usb-audio: fix selector unit string index accessor
  include/linux/usb/audio-v2.h: add more UAC2 details
  ALSA: usb-audio: support partially write-protected UAC2 controls
  ALSA: usb-audio: UAC2: clean up parsing of bmaControls
  ALSA: hda: Use LPIB for another mainboard
  ALSA: hda: Use mb31 quirk for an iMac model
  ALSA: hda: Use LPIB for an ASUS device
parents ad845636 d4376802
...@@ -101,7 +101,7 @@ static struct uac_feature_unit_descriptor_0 feature_unit_desc = { ...@@ -101,7 +101,7 @@ static struct uac_feature_unit_descriptor_0 feature_unit_desc = {
static struct usb_audio_control mute_control = { static struct usb_audio_control mute_control = {
.list = LIST_HEAD_INIT(mute_control.list), .list = LIST_HEAD_INIT(mute_control.list),
.name = "Mute Control", .name = "Mute Control",
.type = UAC_MUTE_CONTROL, .type = UAC_FU_MUTE,
/* Todo: add real Mute control code */ /* Todo: add real Mute control code */
.set = generic_set_cmd, .set = generic_set_cmd,
.get = generic_get_cmd, .get = generic_get_cmd,
...@@ -110,7 +110,7 @@ static struct usb_audio_control mute_control = { ...@@ -110,7 +110,7 @@ static struct usb_audio_control mute_control = {
static struct usb_audio_control volume_control = { static struct usb_audio_control volume_control = {
.list = LIST_HEAD_INIT(volume_control.list), .list = LIST_HEAD_INIT(volume_control.list),
.name = "Volume Control", .name = "Volume Control",
.type = UAC_VOLUME_CONTROL, .type = UAC_FU_VOLUME,
/* Todo: add real Volume control code */ /* Todo: add real Volume control code */
.set = generic_set_cmd, .set = generic_set_cmd,
.get = generic_get_cmd, .get = generic_get_cmd,
......
...@@ -18,6 +18,16 @@ ...@@ -18,6 +18,16 @@
/* v1.0 and v2.0 of this standard have many things in common. For the rest /* v1.0 and v2.0 of this standard have many things in common. For the rest
* of the definitions, please refer to audio.h */ * of the definitions, please refer to audio.h */
static inline bool uac2_control_is_readable(u32 bmControls, u8 control)
{
return (bmControls >> (control * 2)) & 0x1;
}
static inline bool uac2_control_is_writeable(u32 bmControls, u8 control)
{
return (bmControls >> (control * 2)) & 0x2;
}
/* 4.7.2.1 Clock Source Descriptor */ /* 4.7.2.1 Clock Source Descriptor */
struct uac_clock_source_descriptor { struct uac_clock_source_descriptor {
...@@ -31,6 +41,13 @@ struct uac_clock_source_descriptor { ...@@ -31,6 +41,13 @@ struct uac_clock_source_descriptor {
__u8 iClockSource; __u8 iClockSource;
} __attribute__((packed)); } __attribute__((packed));
/* bmAttribute fields */
#define UAC_CLOCK_SOURCE_TYPE_EXT 0x0
#define UAC_CLOCK_SOURCE_TYPE_INT_FIXED 0x1
#define UAC_CLOCK_SOURCE_TYPE_INT_VAR 0x2
#define UAC_CLOCK_SOURCE_TYPE_INT_PROG 0x3
#define UAC_CLOCK_SOURCE_SYNCED_TO_SOF (1 << 2)
/* 4.7.2.2 Clock Source Descriptor */ /* 4.7.2.2 Clock Source Descriptor */
struct uac_clock_selector_descriptor { struct uac_clock_selector_descriptor {
...@@ -39,8 +56,20 @@ struct uac_clock_selector_descriptor { ...@@ -39,8 +56,20 @@ struct uac_clock_selector_descriptor {
__u8 bDescriptorSubtype; __u8 bDescriptorSubtype;
__u8 bClockID; __u8 bClockID;
__u8 bNrInPins; __u8 bNrInPins;
__u8 bmControls;
__u8 baCSourceID[]; __u8 baCSourceID[];
/* bmControls, bAssocTerminal and iClockSource omitted */
} __attribute__((packed));
/* 4.7.2.3 Clock Multiplier Descriptor */
struct uac_clock_multiplier_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubtype;
__u8 bClockID;
__u8 bCSourceID;
__u8 bmControls;
__u8 iClockMultiplier;
} __attribute__((packed)); } __attribute__((packed));
/* 4.7.2.4 Input terminal descriptor */ /* 4.7.2.4 Input terminal descriptor */
......
...@@ -47,6 +47,15 @@ ...@@ -47,6 +47,15 @@
#define UAC_FORMAT_TYPE 0x02 #define UAC_FORMAT_TYPE 0x02
#define UAC_FORMAT_SPECIFIC 0x03 #define UAC_FORMAT_SPECIFIC 0x03
/* A.7 Processing Unit Process Types */
#define UAC_PROCESS_UNDEFINED 0x00
#define UAC_PROCESS_UP_DOWNMIX 0x01
#define UAC_PROCESS_DOLBY_PROLOGIC 0x02
#define UAC_PROCESS_STEREO_EXTENDER 0x03
#define UAC_PROCESS_REVERB 0x04
#define UAC_PROCESS_CHORUS 0x05
#define UAC_PROCESS_DYN_RANGE_COMP 0x06
/* A.8 Audio Class-Specific Endpoint Descriptor Subtypes */ /* A.8 Audio Class-Specific Endpoint Descriptor Subtypes */
#define UAC_EP_GENERAL 0x01 #define UAC_EP_GENERAL 0x01
...@@ -73,6 +82,60 @@ ...@@ -73,6 +82,60 @@
#define UAC_GET_STAT 0xff #define UAC_GET_STAT 0xff
/* A.10 Control Selector Codes */
/* A.10.1 Terminal Control Selectors */
#define UAC_TERM_COPY_PROTECT 0x01
/* A.10.2 Feature Unit Control Selectors */
#define UAC_FU_MUTE 0x01
#define UAC_FU_VOLUME 0x02
#define UAC_FU_BASS 0x03
#define UAC_FU_MID 0x04
#define UAC_FU_TREBLE 0x05
#define UAC_FU_GRAPHIC_EQUALIZER 0x06
#define UAC_FU_AUTOMATIC_GAIN 0x07
#define UAC_FU_DELAY 0x08
#define UAC_FU_BASS_BOOST 0x09
#define UAC_FU_LOUDNESS 0x0a
#define UAC_CONTROL_BIT(CS) (1 << ((CS) - 1))
/* A.10.3.1 Up/Down-mix Processing Unit Controls Selectors */
#define UAC_UD_ENABLE 0x01
#define UAC_UD_MODE_SELECT 0x02
/* A.10.3.2 Dolby Prologic (tm) Processing Unit Controls Selectors */
#define UAC_DP_ENABLE 0x01
#define UAC_DP_MODE_SELECT 0x02
/* A.10.3.3 3D Stereo Extender Processing Unit Control Selectors */
#define UAC_3D_ENABLE 0x01
#define UAC_3D_SPACE 0x02
/* A.10.3.4 Reverberation Processing Unit Control Selectors */
#define UAC_REVERB_ENABLE 0x01
#define UAC_REVERB_LEVEL 0x02
#define UAC_REVERB_TIME 0x03
#define UAC_REVERB_FEEDBACK 0x04
/* A.10.3.5 Chorus Processing Unit Control Selectors */
#define UAC_CHORUS_ENABLE 0x01
#define UAC_CHORUS_LEVEL 0x02
#define UAC_CHORUS_RATE 0x03
#define UAC_CHORUS_DEPTH 0x04
/* A.10.3.6 Dynamic Range Compressor Unit Control Selectors */
#define UAC_DCR_ENABLE 0x01
#define UAC_DCR_RATE 0x02
#define UAC_DCR_MAXAMPL 0x03
#define UAC_DCR_THRESHOLD 0x04
#define UAC_DCR_ATTACK_TIME 0x05
#define UAC_DCR_RELEASE_TIME 0x06
/* A.10.4 Extension Unit Control Selectors */
#define UAC_XU_ENABLE 0x01
/* MIDI - A.1 MS Class-Specific Interface Descriptor Subtypes */ /* MIDI - A.1 MS Class-Specific Interface Descriptor Subtypes */
#define UAC_MS_HEADER 0x01 #define UAC_MS_HEADER 0x01
#define UAC_MIDI_IN_JACK 0x02 #define UAC_MIDI_IN_JACK 0x02
...@@ -244,7 +307,7 @@ struct uac_selector_unit_descriptor { ...@@ -244,7 +307,7 @@ struct uac_selector_unit_descriptor {
static inline __u8 uac_selector_unit_iSelector(struct uac_selector_unit_descriptor *desc) static inline __u8 uac_selector_unit_iSelector(struct uac_selector_unit_descriptor *desc)
{ {
__u8 *raw = (__u8 *) desc; __u8 *raw = (__u8 *) desc;
return raw[9 + desc->bLength - 1]; return raw[desc->bLength - 1];
} }
/* 4.3.2.5 Feature Unit Descriptor */ /* 4.3.2.5 Feature Unit Descriptor */
...@@ -463,31 +526,6 @@ struct uac_iso_endpoint_descriptor { ...@@ -463,31 +526,6 @@ struct uac_iso_endpoint_descriptor {
#define UAC_EP_CS_ATTR_PITCH_CONTROL 0x02 #define UAC_EP_CS_ATTR_PITCH_CONTROL 0x02
#define UAC_EP_CS_ATTR_FILL_MAX 0x80 #define UAC_EP_CS_ATTR_FILL_MAX 0x80
/* A.10.2 Feature Unit Control Selectors */
#define UAC_FU_CONTROL_UNDEFINED 0x00
#define UAC_MUTE_CONTROL 0x01
#define UAC_VOLUME_CONTROL 0x02
#define UAC_BASS_CONTROL 0x03
#define UAC_MID_CONTROL 0x04
#define UAC_TREBLE_CONTROL 0x05
#define UAC_GRAPHIC_EQUALIZER_CONTROL 0x06
#define UAC_AUTOMATIC_GAIN_CONTROL 0x07
#define UAC_DELAY_CONTROL 0x08
#define UAC_BASS_BOOST_CONTROL 0x09
#define UAC_LOUDNESS_CONTROL 0x0a
#define UAC_FU_MUTE (1 << (UAC_MUTE_CONTROL - 1))
#define UAC_FU_VOLUME (1 << (UAC_VOLUME_CONTROL - 1))
#define UAC_FU_BASS (1 << (UAC_BASS_CONTROL - 1))
#define UAC_FU_MID (1 << (UAC_MID_CONTROL - 1))
#define UAC_FU_TREBLE (1 << (UAC_TREBLE_CONTROL - 1))
#define UAC_FU_GRAPHIC_EQ (1 << (UAC_GRAPHIC_EQUALIZER_CONTROL - 1))
#define UAC_FU_AUTO_GAIN (1 << (UAC_AUTOMATIC_GAIN_CONTROL - 1))
#define UAC_FU_DELAY (1 << (UAC_DELAY_CONTROL - 1))
#define UAC_FU_BASS_BOOST (1 << (UAC_BASS_BOOST_CONTROL - 1))
#define UAC_FU_LOUDNESS (1 << (UAC_LOUDNESS_CONTROL - 1))
/* status word format (3.7.1.1) */ /* status word format (3.7.1.1) */
#define UAC1_STATUS_TYPE_ORIG_MASK 0x0f #define UAC1_STATUS_TYPE_ORIG_MASK 0x0f
......
...@@ -2578,6 +2578,9 @@ static int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi) ...@@ -2578,6 +2578,9 @@ static int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)
if (err) if (err)
return -err; return -err;
memset(&prev_ctl, 0, sizeof(prev_ctl));
prev_ctl.control_type = -1;
for (idx = 0; idx < 2000; idx++) { for (idx = 0; idx < 2000; idx++) {
err = hpi_mixer_get_control_by_index( err = hpi_mixer_get_control_by_index(
ss, asihpi->h_mixer, ss, asihpi->h_mixer,
......
...@@ -1913,11 +1913,11 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) ...@@ -1913,11 +1913,11 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
if (WARN_ONCE(!azx_dev->period_bytes, if (WARN_ONCE(!azx_dev->period_bytes,
"hda-intel: zero azx_dev->period_bytes")) "hda-intel: zero azx_dev->period_bytes"))
return -1; /* this shouldn't happen! */ return -1; /* this shouldn't happen! */
if (wallclk <= azx_dev->period_wallclk && if (wallclk < (azx_dev->period_wallclk * 5) / 4 &&
pos % azx_dev->period_bytes > azx_dev->period_bytes / 2) pos % azx_dev->period_bytes > azx_dev->period_bytes / 2)
/* NG - it's below the first next period boundary */ /* NG - it's below the first next period boundary */
return bdl_pos_adj[chip->dev_index] ? 0 : -1; return bdl_pos_adj[chip->dev_index] ? 0 : -1;
azx_dev->start_wallclk = wallclk; azx_dev->start_wallclk += wallclk;
return 1; /* OK, it's fine */ return 1; /* OK, it's fine */
} }
...@@ -2288,6 +2288,8 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = { ...@@ -2288,6 +2288,8 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = {
SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB), SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB),
SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB), SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB), SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS M2V", POS_FIX_LPIB),
SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB), SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB), SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba A100-259", POS_FIX_LPIB), SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba A100-259", POS_FIX_LPIB),
...@@ -2296,6 +2298,7 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = { ...@@ -2296,6 +2298,7 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = {
SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB), SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1565, 0x820f, "Biostar Microtech", POS_FIX_LPIB), SND_PCI_QUIRK(0x1565, 0x820f, "Biostar Microtech", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1565, 0x8218, "Biostar Microtech", POS_FIX_LPIB), SND_PCI_QUIRK(0x1565, 0x8218, "Biostar Microtech", POS_FIX_LPIB),
SND_PCI_QUIRK(0x1849, 0x0888, "775Dual-VSTA", POS_FIX_LPIB),
SND_PCI_QUIRK(0x8086, 0x2503, "DG965OT AAD63733-203", POS_FIX_LPIB), SND_PCI_QUIRK(0x8086, 0x2503, "DG965OT AAD63733-203", POS_FIX_LPIB),
SND_PCI_QUIRK(0x8086, 0xd601, "eMachines T5212", POS_FIX_LPIB), SND_PCI_QUIRK(0x8086, 0xd601, "eMachines T5212", POS_FIX_LPIB),
{} {}
......
...@@ -9476,6 +9476,7 @@ static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = { ...@@ -9476,6 +9476,7 @@ static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = {
SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24), SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24),
SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24), SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24),
SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3), SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3),
SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31),
SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31), SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31),
SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3), SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3),
SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24), SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24),
......
...@@ -13,9 +13,18 @@ config SND_MXC_SOC_SSI ...@@ -13,9 +13,18 @@ config SND_MXC_SOC_SSI
config SND_MXC_SOC_WM1133_EV1 config SND_MXC_SOC_WM1133_EV1
tristate "Audio on the the i.MX31ADS with WM1133-EV1 fitted" tristate "Audio on the the i.MX31ADS with WM1133-EV1 fitted"
depends on SND_IMX_SOC && EXPERIMENTAL depends on SND_IMX_SOC && MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL
select SND_SOC_WM8350 select SND_SOC_WM8350
select SND_MXC_SOC_SSI select SND_MXC_SOC_SSI
help help
Enable support for audio on the i.MX31ADS with the WM1133-EV1 Enable support for audio on the i.MX31ADS with the WM1133-EV1
PMIC board with WM8835x fitted. PMIC board with WM8835x fitted.
config SND_SOC_PHYCORE_AC97
tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards"
depends on MACH_PCM043 || MACH_PCA100
select SND_MXC_SOC_SSI
select SND_SOC_WM9712
help
Say Y if you want to add support for SoC audio on Phytec phyCORE
and phyCARD boards in AC97 mode
...@@ -11,7 +11,8 @@ snd-usb-audio-objs := card.o \ ...@@ -11,7 +11,8 @@ snd-usb-audio-objs := card.o \
endpoint.o \ endpoint.o \
urb.o \ urb.o \
pcm.o \ pcm.o \
helper.o helper.o \
clock.o
snd-usbmidi-lib-objs := midi.o snd-usbmidi-lib-objs := midi.o
......
...@@ -236,7 +236,6 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) ...@@ -236,7 +236,6 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
} }
case UAC_VERSION_2: { case UAC_VERSION_2: {
struct uac_clock_source_descriptor *cs;
struct usb_interface_assoc_descriptor *assoc = struct usb_interface_assoc_descriptor *assoc =
usb_ifnum_to_if(dev, ctrlif)->intf_assoc; usb_ifnum_to_if(dev, ctrlif)->intf_assoc;
...@@ -245,21 +244,6 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) ...@@ -245,21 +244,6 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
return -EINVAL; return -EINVAL;
} }
/* FIXME: for now, we expect there is at least one clock source
* descriptor and we always take the first one.
* We should properly support devices with multiple clock sources,
* clock selectors and sample rate conversion units. */
cs = snd_usb_find_csint_desc(host_iface->extra, host_iface->extralen,
NULL, UAC2_CLOCK_SOURCE);
if (!cs) {
snd_printk(KERN_ERR "CLOCK_SOURCE descriptor not found\n");
return -EINVAL;
}
chip->clock_id = cs->bClockID;
for (i = 0; i < assoc->bInterfaceCount; i++) { for (i = 0; i < assoc->bInterfaceCount; i++) {
int intf = assoc->bFirstInterface + i; int intf = assoc->bFirstInterface + i;
...@@ -481,6 +465,8 @@ static void *snd_usb_audio_probe(struct usb_device *dev, ...@@ -481,6 +465,8 @@ static void *snd_usb_audio_probe(struct usb_device *dev,
goto __error; goto __error;
} }
chip->ctrl_intf = alts;
if (err > 0) { if (err > 0) {
/* create normal USB audio interfaces */ /* create normal USB audio interfaces */
if (snd_usb_create_streams(chip, ifnum) < 0 || if (snd_usb_create_streams(chip, ifnum) < 0 ||
......
...@@ -25,6 +25,7 @@ struct audioformat { ...@@ -25,6 +25,7 @@ struct audioformat {
unsigned int rate_min, rate_max; /* min/max rates */ unsigned int rate_min, rate_max; /* min/max rates */
unsigned int nr_rates; /* number of rate table entries */ unsigned int nr_rates; /* number of rate table entries */
unsigned int *rate_table; /* rate table */ unsigned int *rate_table; /* rate table */
unsigned char clock; /* associated clock */
}; };
struct snd_usb_substream; struct snd_usb_substream;
......
/*
* Clock domain and sample rate management functions
*
* 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/bitops.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/usb.h>
#include <linux/moduleparam.h>
#include <linux/mutex.h>
#include <linux/usb/audio.h>
#include <linux/usb/audio-v2.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
#include <sound/initval.h>
#include "usbaudio.h"
#include "card.h"
#include "midi.h"
#include "mixer.h"
#include "proc.h"
#include "quirks.h"
#include "endpoint.h"
#include "helper.h"
#include "debug.h"
#include "pcm.h"
#include "urb.h"
#include "format.h"
static struct uac_clock_source_descriptor *
snd_usb_find_clock_source(struct usb_host_interface *ctrl_iface,
int clock_id)
{
struct uac_clock_source_descriptor *cs = NULL;
while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra,
ctrl_iface->extralen,
cs, UAC2_CLOCK_SOURCE))) {
if (cs->bClockID == clock_id)
return cs;
}
return NULL;
}
static struct uac_clock_selector_descriptor *
snd_usb_find_clock_selector(struct usb_host_interface *ctrl_iface,
int clock_id)
{
struct uac_clock_selector_descriptor *cs = NULL;
while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra,
ctrl_iface->extralen,
cs, UAC2_CLOCK_SELECTOR))) {
if (cs->bClockID == clock_id)
return cs;
}
return NULL;
}
static struct uac_clock_multiplier_descriptor *
snd_usb_find_clock_multiplier(struct usb_host_interface *ctrl_iface,
int clock_id)
{
struct uac_clock_multiplier_descriptor *cs = NULL;
while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra,
ctrl_iface->extralen,
cs, UAC2_CLOCK_MULTIPLIER))) {
if (cs->bClockID == clock_id)
return cs;
}
return NULL;
}
static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id)
{
unsigned char buf;
int ret;
ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0),
UAC2_CS_CUR,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
UAC2_CX_CLOCK_SELECTOR << 8, selector_id << 8,
&buf, sizeof(buf), 1000);
if (ret < 0)
return ret;
return buf;
}
static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id)
{
int err;
unsigned char data;
struct usb_device *dev = chip->dev;
err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
UAC2_CS_CONTROL_CLOCK_VALID << 8, source_id << 8,
&data, sizeof(data), 1000);
if (err < 0) {
snd_printk(KERN_WARNING "%s(): cannot get clock validity for id %d\n",
__func__, source_id);
return err;
}
return !!data;
}
/* Try to find the clock source ID of a given clock entity */
static int __uac_clock_find_source(struct snd_usb_audio *chip,
struct usb_host_interface *host_iface,
int entity_id, unsigned long *visited)
{
struct uac_clock_source_descriptor *source;
struct uac_clock_selector_descriptor *selector;
struct uac_clock_multiplier_descriptor *multiplier;
entity_id &= 0xff;
if (test_and_set_bit(entity_id, visited)) {
snd_printk(KERN_WARNING
"%s(): recursive clock topology detected, id %d.\n",
__func__, entity_id);
return -EINVAL;
}
/* first, see if the ID we're looking for is a clock source already */
source = snd_usb_find_clock_source(host_iface, entity_id);
if (source)
return source->bClockID;
selector = snd_usb_find_clock_selector(host_iface, entity_id);
if (selector) {
int ret;
/* the entity ID we are looking for is a selector.
* find out what it currently selects */
ret = uac_clock_selector_get_val(chip, selector->bClockID);
if (ret < 0)
return ret;
if (ret > selector->bNrInPins || ret < 1) {
printk(KERN_ERR
"%s(): selector reported illegal value, id %d, ret %d\n",
__func__, selector->bClockID, ret);
return -EINVAL;
}
return __uac_clock_find_source(chip, host_iface,
selector->baCSourceID[ret-1],
visited);
}
/* FIXME: multipliers only act as pass-thru element for now */
multiplier = snd_usb_find_clock_multiplier(host_iface, entity_id);
if (multiplier)
return __uac_clock_find_source(chip, host_iface,
multiplier->bCSourceID, visited);
return -EINVAL;
}
int snd_usb_clock_find_source(struct snd_usb_audio *chip,
struct usb_host_interface *host_iface,
int entity_id)
{
DECLARE_BITMAP(visited, 256);
memset(visited, 0, sizeof(visited));
return __uac_clock_find_source(chip, host_iface, entity_id, visited);
}
static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface,
struct usb_host_interface *alts,
struct audioformat *fmt, int rate)
{
struct usb_device *dev = chip->dev;
unsigned int ep;
unsigned char data[3];
int err, crate;
ep = get_endpoint(alts, 0)->bEndpointAddress;
/* if endpoint doesn't have sampling rate control, bail out */
if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE)) {
snd_printk(KERN_WARNING "%d:%d:%d: endpoint lacks sample rate attribute bit, cannot set.\n",
dev->devnum, iface, fmt->altsetting);
return 0;
}
data[0] = rate;
data[1] = rate >> 8;
data[2] = rate >> 16;
if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR,
USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT,
UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
data, sizeof(data), 1000)) < 0) {
snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n",
dev->devnum, iface, fmt->altsetting, rate, ep);
return err;
}
if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR,
USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN,
UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
data, sizeof(data), 1000)) < 0) {
snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n",
dev->devnum, iface, fmt->altsetting, ep);
return 0; /* some devices don't support reading */
}
crate = data[0] | (data[1] << 8) | (data[2] << 16);
if (crate != rate) {
snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate);
// runtime->rate = crate;
}
return 0;
}
static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface,
struct usb_host_interface *alts,
struct audioformat *fmt, int rate)
{
struct usb_device *dev = chip->dev;
unsigned char data[4];
int err, crate;
int clock = snd_usb_clock_find_source(chip, chip->ctrl_intf, fmt->clock);
if (clock < 0)
return clock;
if (!uac_clock_source_is_valid(chip, clock)) {
snd_printk(KERN_ERR "%d:%d:%d: clock source %d is not valid, cannot use\n",
dev->devnum, iface, fmt->altsetting, clock);
return -ENXIO;
}
data[0] = rate;
data[1] = rate >> 8;
data[2] = rate >> 16;
data[3] = rate >> 24;
if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
UAC2_CS_CONTROL_SAM_FREQ << 8, clock << 8,
data, sizeof(data), 1000)) < 0) {
snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2)\n",
dev->devnum, iface, fmt->altsetting, rate);
return err;
}
if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
UAC2_CS_CONTROL_SAM_FREQ << 8, clock << 8,
data, sizeof(data), 1000)) < 0) {
snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n",
dev->devnum, iface, fmt->altsetting);
return err;
}
crate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
if (crate != rate)
snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate);
return 0;
}
int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,
struct usb_host_interface *alts,
struct audioformat *fmt, int rate)
{
struct usb_interface_descriptor *altsd = get_iface_desc(alts);
switch (altsd->bInterfaceProtocol) {
case UAC_VERSION_1:
return set_sample_rate_v1(chip, iface, alts, fmt, rate);
case UAC_VERSION_2:
return set_sample_rate_v2(chip, iface, alts, fmt, rate);
}
return -EINVAL;
}
#ifndef __USBAUDIO_CLOCK_H
#define __USBAUDIO_CLOCK_H
int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,
struct usb_host_interface *alts,
struct audioformat *fmt, int rate);
int snd_usb_clock_find_source(struct snd_usb_audio *chip,
struct usb_host_interface *host_iface,
int entity_id);
#endif /* __USBAUDIO_CLOCK_H */
...@@ -190,6 +190,38 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, ...@@ -190,6 +190,38 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip,
return attributes; return attributes;
} }
static struct uac2_input_terminal_descriptor *
snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface,
int terminal_id)
{
struct uac2_input_terminal_descriptor *term = NULL;
while ((term = snd_usb_find_csint_desc(ctrl_iface->extra,
ctrl_iface->extralen,
term, UAC_INPUT_TERMINAL))) {
if (term->bTerminalID == terminal_id)
return term;
}
return NULL;
}
static struct uac2_output_terminal_descriptor *
snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface,
int terminal_id)
{
struct uac2_output_terminal_descriptor *term = NULL;
while ((term = snd_usb_find_csint_desc(ctrl_iface->extra,
ctrl_iface->extralen,
term, UAC_OUTPUT_TERMINAL))) {
if (term->bTerminalID == terminal_id)
return term;
}
return NULL;
}
int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
{ {
struct usb_device *dev; struct usb_device *dev;
...@@ -199,7 +231,7 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) ...@@ -199,7 +231,7 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
int i, altno, err, stream; int i, altno, err, stream;
int format = 0, num_channels = 0; int format = 0, num_channels = 0;
struct audioformat *fp = NULL; struct audioformat *fp = NULL;
int num, protocol; int num, protocol, clock = 0;
struct uac_format_type_i_continuous_descriptor *fmt; struct uac_format_type_i_continuous_descriptor *fmt;
dev = chip->dev; dev = chip->dev;
...@@ -263,6 +295,8 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) ...@@ -263,6 +295,8 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
} }
case UAC_VERSION_2: { case UAC_VERSION_2: {
struct uac2_input_terminal_descriptor *input_term;
struct uac2_output_terminal_descriptor *output_term;
struct uac_as_header_descriptor_v2 *as = struct uac_as_header_descriptor_v2 *as =
snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL);
...@@ -281,7 +315,25 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) ...@@ -281,7 +315,25 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
num_channels = as->bNrChannels; num_channels = as->bNrChannels;
format = le32_to_cpu(as->bmFormats); format = le32_to_cpu(as->bmFormats);
break; /* lookup the terminal associated to this interface
* to extract the clock */
input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf,
as->bTerminalLink);
if (input_term) {
clock = input_term->bCSourceID;
break;
}
output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf,
as->bTerminalLink);
if (output_term) {
clock = output_term->bCSourceID;
break;
}
snd_printk(KERN_ERR "%d:%u:%d : bogus bTerminalLink %d\n",
dev->devnum, iface_no, altno, as->bTerminalLink);
continue;
} }
default: default:
...@@ -338,6 +390,7 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) ...@@ -338,6 +390,7 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no)
fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1)
* (fp->maxpacksize & 0x7ff); * (fp->maxpacksize & 0x7ff);
fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no); fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no);
fp->clock = clock;
/* some quirks for attributes here */ /* some quirks for attributes here */
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include "quirks.h" #include "quirks.h"
#include "helper.h" #include "helper.h"
#include "debug.h" #include "debug.h"
#include "clock.h"
/* /*
* parse the audio format type I descriptor * parse the audio format type I descriptor
...@@ -215,15 +216,17 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip, ...@@ -215,15 +216,17 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,
struct usb_device *dev = chip->dev; struct usb_device *dev = chip->dev;
unsigned char tmp[2], *data; unsigned char tmp[2], *data;
int i, nr_rates, data_size, ret = 0; int i, nr_rates, data_size, ret = 0;
int clock = snd_usb_clock_find_source(chip, chip->ctrl_intf, fp->clock);
/* get the number of sample rates first by only fetching 2 bytes */ /* get the number of sample rates first by only fetching 2 bytes */
ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE, ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8, UAC2_CS_CONTROL_SAM_FREQ << 8, clock << 8,
tmp, sizeof(tmp), 1000); tmp, sizeof(tmp), 1000);
if (ret < 0) { if (ret < 0) {
snd_printk(KERN_ERR "unable to retrieve number of sample rates\n"); snd_printk(KERN_ERR "%s(): unable to retrieve number of sample rates (clock %d)\n",
__func__, clock);
goto err; goto err;
} }
...@@ -237,12 +240,13 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip, ...@@ -237,12 +240,13 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip,
/* now get the full information */ /* now get the full information */
ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE, ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8, UAC2_CS_CONTROL_SAM_FREQ << 8, clock << 8,
data, data_size, 1000); data, data_size, 1000);
if (ret < 0) { if (ret < 0) {
snd_printk(KERN_ERR "unable to retrieve sample rate range\n"); snd_printk(KERN_ERR "%s(): unable to retrieve sample rate range (clock %d)\n",
__func__, clock);
ret = -EINVAL; ret = -EINVAL;
goto err_free; goto err_free;
} }
......
This diff is collapsed.
...@@ -34,6 +34,8 @@ struct usb_mixer_elem_info { ...@@ -34,6 +34,8 @@ struct usb_mixer_elem_info {
unsigned int id; unsigned int id;
unsigned int control; /* CS or ICN (high byte) */ unsigned int control; /* CS or ICN (high byte) */
unsigned int cmask; /* channel mask bitmap: 0 = master */ unsigned int cmask; /* channel mask bitmap: 0 = master */
unsigned int ch_readonly;
unsigned int master_readonly;
int channels; int channels;
int val_type; int val_type;
int min, max, res; int min, max, res;
......
...@@ -85,8 +85,8 @@ static struct usbmix_name_map extigy_map[] = { ...@@ -85,8 +85,8 @@ static struct usbmix_name_map extigy_map[] = {
/* 16: MU (w/o controls) */ /* 16: MU (w/o controls) */
{ 17, NULL, 1 }, /* DISABLED: PU-switch (any effect?) */ { 17, NULL, 1 }, /* DISABLED: PU-switch (any effect?) */
{ 17, "Channel Routing", 2 }, /* PU: mode select */ { 17, "Channel Routing", 2 }, /* PU: mode select */
{ 18, "Tone Control - Bass", UAC_BASS_CONTROL }, /* FU */ { 18, "Tone Control - Bass", UAC_FU_BASS }, /* FU */
{ 18, "Tone Control - Treble", UAC_TREBLE_CONTROL }, /* FU */ { 18, "Tone Control - Treble", UAC_FU_TREBLE }, /* FU */
{ 18, "Master Playback" }, /* FU; others */ { 18, "Master Playback" }, /* FU; others */
/* 19: OT speaker */ /* 19: OT speaker */
/* 20: OT headphone */ /* 20: OT headphone */
......
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "urb.h" #include "urb.h"
#include "helper.h" #include "helper.h"
#include "pcm.h" #include "pcm.h"
#include "clock.h"
/* /*
* return the current pcm pointer. just based on the hwptr_done value. * return the current pcm pointer. just based on the hwptr_done value.
...@@ -181,103 +182,6 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, ...@@ -181,103 +182,6 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
return -EINVAL; return -EINVAL;
} }
static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface,
struct usb_host_interface *alts,
struct audioformat *fmt, int rate)
{
struct usb_device *dev = chip->dev;
unsigned int ep;
unsigned char data[3];
int err, crate;
ep = get_endpoint(alts, 0)->bEndpointAddress;
/* if endpoint doesn't have sampling rate control, bail out */
if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE)) {
snd_printk(KERN_WARNING "%d:%d:%d: endpoint lacks sample rate attribute bit, cannot set.\n",
dev->devnum, iface, fmt->altsetting);
return 0;
}
data[0] = rate;
data[1] = rate >> 8;
data[2] = rate >> 16;
if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR,
USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT,
UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
data, sizeof(data), 1000)) < 0) {
snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n",
dev->devnum, iface, fmt->altsetting, rate, ep);
return err;
}
if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR,
USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN,
UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep,
data, sizeof(data), 1000)) < 0) {
snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n",
dev->devnum, iface, fmt->altsetting, ep);
return 0; /* some devices don't support reading */
}
crate = data[0] | (data[1] << 8) | (data[2] << 16);
if (crate != rate) {
snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate);
// runtime->rate = crate;
}
return 0;
}
static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface,
struct usb_host_interface *alts,
struct audioformat *fmt, int rate)
{
struct usb_device *dev = chip->dev;
unsigned char data[4];
int err, crate;
data[0] = rate;
data[1] = rate >> 8;
data[2] = rate >> 16;
data[3] = rate >> 24;
if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8,
data, sizeof(data), 1000)) < 0) {
snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2)\n",
dev->devnum, iface, fmt->altsetting, rate);
return err;
}
if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8,
data, sizeof(data), 1000)) < 0) {
snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n",
dev->devnum, iface, fmt->altsetting);
return err;
}
crate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
if (crate != rate)
snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate);
return 0;
}
int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,
struct usb_host_interface *alts,
struct audioformat *fmt, int rate)
{
struct usb_interface_descriptor *altsd = get_iface_desc(alts);
switch (altsd->bInterfaceProtocol) {
case UAC_VERSION_1:
return set_sample_rate_v1(chip, iface, alts, fmt, rate);
case UAC_VERSION_2:
return set_sample_rate_v2(chip, iface, alts, fmt, rate);
}
return -EINVAL;
}
/* /*
* find a matching format and set up the interface * find a matching format and set up the interface
*/ */
......
...@@ -40,9 +40,6 @@ struct snd_usb_audio { ...@@ -40,9 +40,6 @@ struct snd_usb_audio {
int num_interfaces; int num_interfaces;
int num_suspended_intf; int num_suspended_intf;
/* for audio class v2 */
int clock_id;
struct list_head pcm_list; /* list of pcm streams */ struct list_head pcm_list; /* list of pcm streams */
int pcm_devs; int pcm_devs;
...@@ -53,6 +50,8 @@ struct snd_usb_audio { ...@@ -53,6 +50,8 @@ struct snd_usb_audio {
int setup; /* from the 'device_setup' module param */ int setup; /* from the 'device_setup' module param */
int nrpacks; /* from the 'nrpacks' module param */ int nrpacks; /* from the 'nrpacks' module param */
int async_unlink; /* from the 'async_unlink' module param */ int async_unlink; /* from the 'async_unlink' module param */
struct usb_host_interface *ctrl_intf; /* the audio control interface */
}; };
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment