diff options
author | Takashi Iwai <tiwai@suse.de> | 2010-06-23 10:07:34 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2010-06-23 10:07:34 -0400 |
commit | 1240e6b5532358257c52351639a8d2382fe58f84 (patch) | |
tree | 43d374ce976a41c6dcd12a70a51e0289093f8d07 /sound | |
parent | c9ff921abecda352e987a6aae169118a3fc9aa5d (diff) | |
parent | a5c7d797dcce3be5e77cd6ea62cc4920ededc32b (diff) |
Merge branch 'fix/misc' into topic/misc
Diffstat (limited to 'sound')
-rw-r--r-- | sound/aoa/soundbus/i2sbus/core.c | 8 | ||||
-rw-r--r-- | sound/atmel/ac97c.c | 2 | ||||
-rw-r--r-- | sound/pci/asihpi/asihpi.c | 3 | ||||
-rw-r--r-- | sound/pci/asihpi/hpi6205.c | 22 | ||||
-rw-r--r-- | sound/pci/hda/hda_intel.c | 7 | ||||
-rw-r--r-- | sound/pci/hda/patch_realtek.c | 1 | ||||
-rw-r--r-- | sound/soc/imx/Kconfig | 11 | ||||
-rw-r--r-- | sound/spi/at73c213.c | 1 | ||||
-rw-r--r-- | sound/usb/Makefile | 3 | ||||
-rw-r--r-- | sound/usb/card.c | 18 | ||||
-rw-r--r-- | sound/usb/card.h | 1 | ||||
-rw-r--r-- | sound/usb/clock.c | 315 | ||||
-rw-r--r-- | sound/usb/clock.h | 12 | ||||
-rw-r--r-- | sound/usb/endpoint.c | 58 | ||||
-rw-r--r-- | sound/usb/format.c | 116 | ||||
-rw-r--r-- | sound/usb/helper.h | 4 | ||||
-rw-r--r-- | sound/usb/mixer.c | 245 | ||||
-rw-r--r-- | sound/usb/mixer.h | 2 | ||||
-rw-r--r-- | sound/usb/mixer_maps.c | 4 | ||||
-rw-r--r-- | sound/usb/pcm.c | 98 | ||||
-rw-r--r-- | sound/usb/usbaudio.h | 5 |
21 files changed, 670 insertions, 266 deletions
diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c index 67893372173..3ff8cc5f487 100644 --- a/sound/aoa/soundbus/i2sbus/core.c +++ b/sound/aoa/soundbus/i2sbus/core.c | |||
@@ -437,9 +437,11 @@ static int i2sbus_shutdown(struct macio_dev* dev) | |||
437 | } | 437 | } |
438 | 438 | ||
439 | static struct macio_driver i2sbus_drv = { | 439 | static struct macio_driver i2sbus_drv = { |
440 | .name = "soundbus-i2s", | 440 | .driver = { |
441 | .owner = THIS_MODULE, | 441 | .name = "soundbus-i2s", |
442 | .match_table = i2sbus_match, | 442 | .owner = THIS_MODULE, |
443 | .of_match_table = i2sbus_match, | ||
444 | }, | ||
443 | .probe = i2sbus_probe, | 445 | .probe = i2sbus_probe, |
444 | .remove = i2sbus_remove, | 446 | .remove = i2sbus_remove, |
445 | #ifdef CONFIG_PM | 447 | #ifdef CONFIG_PM |
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c index 428121a7e70..10c3a871a12 100644 --- a/sound/atmel/ac97c.c +++ b/sound/atmel/ac97c.c | |||
@@ -657,7 +657,7 @@ static irqreturn_t atmel_ac97c_interrupt(int irq, void *dev) | |||
657 | if (sr & AC97C_SR_CAEVT) { | 657 | if (sr & AC97C_SR_CAEVT) { |
658 | struct snd_pcm_runtime *runtime; | 658 | struct snd_pcm_runtime *runtime; |
659 | int offset, next_period, block_size; | 659 | int offset, next_period, block_size; |
660 | dev_info(&chip->pdev->dev, "channel A event%s%s%s%s%s%s\n", | 660 | dev_dbg(&chip->pdev->dev, "channel A event%s%s%s%s%s%s\n", |
661 | casr & AC97C_CSR_OVRUN ? " OVRUN" : "", | 661 | casr & AC97C_CSR_OVRUN ? " OVRUN" : "", |
662 | casr & AC97C_CSR_RXRDY ? " RXRDY" : "", | 662 | casr & AC97C_CSR_RXRDY ? " RXRDY" : "", |
663 | casr & AC97C_CSR_UNRUN ? " UNRUN" : "", | 663 | casr & AC97C_CSR_UNRUN ? " UNRUN" : "", |
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index f74c7372b3d..1db586af4f9 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c | |||
@@ -2578,6 +2578,9 @@ static int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi) | |||
2578 | if (err) | 2578 | if (err) |
2579 | return -err; | 2579 | return -err; |
2580 | 2580 | ||
2581 | memset(&prev_ctl, 0, sizeof(prev_ctl)); | ||
2582 | prev_ctl.control_type = -1; | ||
2583 | |||
2581 | for (idx = 0; idx < 2000; idx++) { | 2584 | for (idx = 0; idx < 2000; idx++) { |
2582 | err = hpi_mixer_get_control_by_index( | 2585 | err = hpi_mixer_get_control_by_index( |
2583 | ss, asihpi->h_mixer, | 2586 | ss, asihpi->h_mixer, |
diff --git a/sound/pci/asihpi/hpi6205.c b/sound/pci/asihpi/hpi6205.c index e89991ea354..3b441344822 100644 --- a/sound/pci/asihpi/hpi6205.c +++ b/sound/pci/asihpi/hpi6205.c | |||
@@ -941,11 +941,11 @@ static void outstream_host_buffer_free(struct hpi_adapter_obj *pao, | |||
941 | 941 | ||
942 | } | 942 | } |
943 | 943 | ||
944 | static long outstream_get_space_available(struct hpi_hostbuffer_status | 944 | static u32 outstream_get_space_available(struct hpi_hostbuffer_status |
945 | *status) | 945 | *status) |
946 | { | 946 | { |
947 | return status->size_in_bytes - ((long)(status->host_index) - | 947 | return status->size_in_bytes - (status->host_index - |
948 | (long)(status->dSP_index)); | 948 | status->dSP_index); |
949 | } | 949 | } |
950 | 950 | ||
951 | static void outstream_write(struct hpi_adapter_obj *pao, | 951 | static void outstream_write(struct hpi_adapter_obj *pao, |
@@ -954,7 +954,7 @@ static void outstream_write(struct hpi_adapter_obj *pao, | |||
954 | struct hpi_hw_obj *phw = pao->priv; | 954 | struct hpi_hw_obj *phw = pao->priv; |
955 | struct bus_master_interface *interface = phw->p_interface_buffer; | 955 | struct bus_master_interface *interface = phw->p_interface_buffer; |
956 | struct hpi_hostbuffer_status *status; | 956 | struct hpi_hostbuffer_status *status; |
957 | long space_available; | 957 | u32 space_available; |
958 | 958 | ||
959 | if (!phw->outstream_host_buffer_size[phm->obj_index]) { | 959 | if (!phw->outstream_host_buffer_size[phm->obj_index]) { |
960 | /* there is no BBM buffer, write via message */ | 960 | /* there is no BBM buffer, write via message */ |
@@ -1007,7 +1007,7 @@ static void outstream_write(struct hpi_adapter_obj *pao, | |||
1007 | } | 1007 | } |
1008 | 1008 | ||
1009 | space_available = outstream_get_space_available(status); | 1009 | space_available = outstream_get_space_available(status); |
1010 | if (space_available < (long)phm->u.d.u.data.data_size) { | 1010 | if (space_available < phm->u.d.u.data.data_size) { |
1011 | phr->error = HPI_ERROR_INVALID_DATASIZE; | 1011 | phr->error = HPI_ERROR_INVALID_DATASIZE; |
1012 | return; | 1012 | return; |
1013 | } | 1013 | } |
@@ -1018,7 +1018,7 @@ static void outstream_write(struct hpi_adapter_obj *pao, | |||
1018 | && hpios_locked_mem_valid(&phw->outstream_host_buffers[phm-> | 1018 | && hpios_locked_mem_valid(&phw->outstream_host_buffers[phm-> |
1019 | obj_index])) { | 1019 | obj_index])) { |
1020 | u8 *p_bbm_data; | 1020 | u8 *p_bbm_data; |
1021 | long l_first_write; | 1021 | u32 l_first_write; |
1022 | u8 *p_app_data = (u8 *)phm->u.d.u.data.pb_data; | 1022 | u8 *p_app_data = (u8 *)phm->u.d.u.data.pb_data; |
1023 | 1023 | ||
1024 | if (hpios_locked_mem_get_virt_addr(&phw-> | 1024 | if (hpios_locked_mem_get_virt_addr(&phw-> |
@@ -1248,9 +1248,9 @@ static void instream_start(struct hpi_adapter_obj *pao, | |||
1248 | hw_message(pao, phm, phr); | 1248 | hw_message(pao, phm, phr); |
1249 | } | 1249 | } |
1250 | 1250 | ||
1251 | static long instream_get_bytes_available(struct hpi_hostbuffer_status *status) | 1251 | static u32 instream_get_bytes_available(struct hpi_hostbuffer_status *status) |
1252 | { | 1252 | { |
1253 | return (long)(status->dSP_index) - (long)(status->host_index); | 1253 | return status->dSP_index - status->host_index; |
1254 | } | 1254 | } |
1255 | 1255 | ||
1256 | static void instream_read(struct hpi_adapter_obj *pao, | 1256 | static void instream_read(struct hpi_adapter_obj *pao, |
@@ -1259,9 +1259,9 @@ static void instream_read(struct hpi_adapter_obj *pao, | |||
1259 | struct hpi_hw_obj *phw = pao->priv; | 1259 | struct hpi_hw_obj *phw = pao->priv; |
1260 | struct bus_master_interface *interface = phw->p_interface_buffer; | 1260 | struct bus_master_interface *interface = phw->p_interface_buffer; |
1261 | struct hpi_hostbuffer_status *status; | 1261 | struct hpi_hostbuffer_status *status; |
1262 | long data_available; | 1262 | u32 data_available; |
1263 | u8 *p_bbm_data; | 1263 | u8 *p_bbm_data; |
1264 | long l_first_read; | 1264 | u32 l_first_read; |
1265 | u8 *p_app_data = (u8 *)phm->u.d.u.data.pb_data; | 1265 | u8 *p_app_data = (u8 *)phm->u.d.u.data.pb_data; |
1266 | 1266 | ||
1267 | if (!phw->instream_host_buffer_size[phm->obj_index]) { | 1267 | if (!phw->instream_host_buffer_size[phm->obj_index]) { |
@@ -1272,7 +1272,7 @@ static void instream_read(struct hpi_adapter_obj *pao, | |||
1272 | 1272 | ||
1273 | status = &interface->instream_host_buffer_status[phm->obj_index]; | 1273 | status = &interface->instream_host_buffer_status[phm->obj_index]; |
1274 | data_available = instream_get_bytes_available(status); | 1274 | data_available = instream_get_bytes_available(status); |
1275 | if (data_available < (long)phm->u.d.u.data.data_size) { | 1275 | if (data_available < phm->u.d.u.data.data_size) { |
1276 | phr->error = HPI_ERROR_INVALID_DATASIZE; | 1276 | phr->error = HPI_ERROR_INVALID_DATASIZE; |
1277 | return; | 1277 | return; |
1278 | } | 1278 | } |
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index dc79564fea3..1df25cf5ce3 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -1913,11 +1913,11 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) | |||
1913 | if (WARN_ONCE(!azx_dev->period_bytes, | 1913 | if (WARN_ONCE(!azx_dev->period_bytes, |
1914 | "hda-intel: zero azx_dev->period_bytes")) | 1914 | "hda-intel: zero azx_dev->period_bytes")) |
1915 | return -1; /* this shouldn't happen! */ | 1915 | return -1; /* this shouldn't happen! */ |
1916 | if (wallclk <= azx_dev->period_wallclk && | 1916 | if (wallclk < (azx_dev->period_wallclk * 5) / 4 && |
1917 | pos % azx_dev->period_bytes > azx_dev->period_bytes / 2) | 1917 | pos % azx_dev->period_bytes > azx_dev->period_bytes / 2) |
1918 | /* NG - it's below the first next period boundary */ | 1918 | /* NG - it's below the first next period boundary */ |
1919 | return bdl_pos_adj[chip->dev_index] ? 0 : -1; | 1919 | return bdl_pos_adj[chip->dev_index] ? 0 : -1; |
1920 | azx_dev->start_wallclk = wallclk; | 1920 | azx_dev->start_wallclk += wallclk; |
1921 | return 1; /* OK, it's fine */ | 1921 | return 1; /* OK, it's fine */ |
1922 | } | 1922 | } |
1923 | 1923 | ||
@@ -2288,6 +2288,8 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = { | |||
2288 | SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB), | 2288 | SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB), |
2289 | SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB), | 2289 | SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB), |
2290 | SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB), | 2290 | SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB), |
2291 | SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB), | ||
2292 | SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS M2V", POS_FIX_LPIB), | ||
2291 | SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB), | 2293 | SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB), |
2292 | SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB), | 2294 | SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB), |
2293 | SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba A100-259", POS_FIX_LPIB), | 2295 | 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 | SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB), | 2298 | SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB), |
2297 | SND_PCI_QUIRK(0x1565, 0x820f, "Biostar Microtech", POS_FIX_LPIB), | 2299 | SND_PCI_QUIRK(0x1565, 0x820f, "Biostar Microtech", POS_FIX_LPIB), |
2298 | SND_PCI_QUIRK(0x1565, 0x8218, "Biostar Microtech", POS_FIX_LPIB), | 2300 | SND_PCI_QUIRK(0x1565, 0x8218, "Biostar Microtech", POS_FIX_LPIB), |
2301 | SND_PCI_QUIRK(0x1849, 0x0888, "775Dual-VSTA", POS_FIX_LPIB), | ||
2299 | SND_PCI_QUIRK(0x8086, 0x2503, "DG965OT AAD63733-203", POS_FIX_LPIB), | 2302 | SND_PCI_QUIRK(0x8086, 0x2503, "DG965OT AAD63733-203", POS_FIX_LPIB), |
2300 | SND_PCI_QUIRK(0x8086, 0xd601, "eMachines T5212", POS_FIX_LPIB), | 2303 | SND_PCI_QUIRK(0x8086, 0xd601, "eMachines T5212", POS_FIX_LPIB), |
2301 | {} | 2304 | {} |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 17d4548cc35..d792cddbf4c 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -9476,6 +9476,7 @@ static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = { | |||
9476 | SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24), | 9476 | SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24), |
9477 | SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24), | 9477 | SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24), |
9478 | SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3), | 9478 | SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3), |
9479 | SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31), | ||
9479 | SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31), | 9480 | SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31), |
9480 | SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3), | 9481 | SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3), |
9481 | SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24), | 9482 | SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24), |
diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig index eba9b9d257a..252defea93b 100644 --- a/sound/soc/imx/Kconfig +++ b/sound/soc/imx/Kconfig | |||
@@ -13,9 +13,18 @@ config SND_MXC_SOC_SSI | |||
13 | 13 | ||
14 | config SND_MXC_SOC_WM1133_EV1 | 14 | config SND_MXC_SOC_WM1133_EV1 |
15 | tristate "Audio on the the i.MX31ADS with WM1133-EV1 fitted" | 15 | tristate "Audio on the the i.MX31ADS with WM1133-EV1 fitted" |
16 | depends on SND_IMX_SOC && EXPERIMENTAL | 16 | depends on SND_IMX_SOC && MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL |
17 | select SND_SOC_WM8350 | 17 | select SND_SOC_WM8350 |
18 | select SND_MXC_SOC_SSI | 18 | select SND_MXC_SOC_SSI |
19 | help | 19 | help |
20 | Enable support for audio on the i.MX31ADS with the WM1133-EV1 | 20 | Enable support for audio on the i.MX31ADS with the WM1133-EV1 |
21 | PMIC board with WM8835x fitted. | 21 | PMIC board with WM8835x fitted. |
22 | |||
23 | config SND_SOC_PHYCORE_AC97 | ||
24 | tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards" | ||
25 | depends on MACH_PCM043 || MACH_PCA100 | ||
26 | select SND_MXC_SOC_SSI | ||
27 | select SND_SOC_WM9712 | ||
28 | help | ||
29 | Say Y if you want to add support for SoC audio on Phytec phyCORE | ||
30 | and phyCARD boards in AC97 mode | ||
diff --git a/sound/spi/at73c213.c b/sound/spi/at73c213.c index 4c7b051f9d1..1bc56b2b94e 100644 --- a/sound/spi/at73c213.c +++ b/sound/spi/at73c213.c | |||
@@ -69,7 +69,6 @@ struct snd_at73c213 { | |||
69 | int irq; | 69 | int irq; |
70 | int period; | 70 | int period; |
71 | unsigned long bitrate; | 71 | unsigned long bitrate; |
72 | struct clk *bitclk; | ||
73 | struct ssc_device *ssc; | 72 | struct ssc_device *ssc; |
74 | struct spi_device *spi; | 73 | struct spi_device *spi; |
75 | u8 spi_wbuffer[2]; | 74 | u8 spi_wbuffer[2]; |
diff --git a/sound/usb/Makefile b/sound/usb/Makefile index e7ac7f493a8..1e362bf8834 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile | |||
@@ -11,7 +11,8 @@ snd-usb-audio-objs := card.o \ | |||
11 | endpoint.o \ | 11 | endpoint.o \ |
12 | urb.o \ | 12 | urb.o \ |
13 | pcm.o \ | 13 | pcm.o \ |
14 | helper.o | 14 | helper.o \ |
15 | clock.o | ||
15 | 16 | ||
16 | snd-usbmidi-lib-objs := midi.o | 17 | snd-usbmidi-lib-objs := midi.o |
17 | 18 | ||
diff --git a/sound/usb/card.c b/sound/usb/card.c index da1346bd485..7a8ac1d81be 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c | |||
@@ -236,7 +236,6 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) | |||
236 | } | 236 | } |
237 | 237 | ||
238 | case UAC_VERSION_2: { | 238 | case UAC_VERSION_2: { |
239 | struct uac_clock_source_descriptor *cs; | ||
240 | struct usb_interface_assoc_descriptor *assoc = | 239 | struct usb_interface_assoc_descriptor *assoc = |
241 | usb_ifnum_to_if(dev, ctrlif)->intf_assoc; | 240 | usb_ifnum_to_if(dev, ctrlif)->intf_assoc; |
242 | 241 | ||
@@ -245,21 +244,6 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) | |||
245 | return -EINVAL; | 244 | return -EINVAL; |
246 | } | 245 | } |
247 | 246 | ||
248 | /* FIXME: for now, we expect there is at least one clock source | ||
249 | * descriptor and we always take the first one. | ||
250 | * We should properly support devices with multiple clock sources, | ||
251 | * clock selectors and sample rate conversion units. */ | ||
252 | |||
253 | cs = snd_usb_find_csint_desc(host_iface->extra, host_iface->extralen, | ||
254 | NULL, UAC2_CLOCK_SOURCE); | ||
255 | |||
256 | if (!cs) { | ||
257 | snd_printk(KERN_ERR "CLOCK_SOURCE descriptor not found\n"); | ||
258 | return -EINVAL; | ||
259 | } | ||
260 | |||
261 | chip->clock_id = cs->bClockID; | ||
262 | |||
263 | for (i = 0; i < assoc->bInterfaceCount; i++) { | 247 | for (i = 0; i < assoc->bInterfaceCount; i++) { |
264 | int intf = assoc->bFirstInterface + i; | 248 | int intf = assoc->bFirstInterface + i; |
265 | 249 | ||
@@ -481,6 +465,8 @@ static void *snd_usb_audio_probe(struct usb_device *dev, | |||
481 | goto __error; | 465 | goto __error; |
482 | } | 466 | } |
483 | 467 | ||
468 | chip->ctrl_intf = alts; | ||
469 | |||
484 | if (err > 0) { | 470 | if (err > 0) { |
485 | /* create normal USB audio interfaces */ | 471 | /* create normal USB audio interfaces */ |
486 | if (snd_usb_create_streams(chip, ifnum) < 0 || | 472 | if (snd_usb_create_streams(chip, ifnum) < 0 || |
diff --git a/sound/usb/card.h b/sound/usb/card.h index ed92420c109..1febf2f2375 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h | |||
@@ -25,6 +25,7 @@ struct audioformat { | |||
25 | unsigned int rate_min, rate_max; /* min/max rates */ | 25 | unsigned int rate_min, rate_max; /* min/max rates */ |
26 | unsigned int nr_rates; /* number of rate table entries */ | 26 | unsigned int nr_rates; /* number of rate table entries */ |
27 | unsigned int *rate_table; /* rate table */ | 27 | unsigned int *rate_table; /* rate table */ |
28 | unsigned char clock; /* associated clock */ | ||
28 | }; | 29 | }; |
29 | 30 | ||
30 | struct snd_usb_substream; | 31 | struct snd_usb_substream; |
diff --git a/sound/usb/clock.c b/sound/usb/clock.c new file mode 100644 index 00000000000..b5855114667 --- /dev/null +++ b/sound/usb/clock.c | |||
@@ -0,0 +1,315 @@ | |||
1 | /* | ||
2 | * Clock domain and sample rate management functions | ||
3 | * | ||
4 | * This program is free software; you can redistribute it and/or modify | ||
5 | * it under the terms of the GNU General Public License as published by | ||
6 | * the Free Software Foundation; either version 2 of the License, or | ||
7 | * (at your option) any later version. | ||
8 | * | ||
9 | * This program is distributed in the hope that it will be useful, | ||
10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | * GNU General Public License for more details. | ||
13 | * | ||
14 | * You should have received a copy of the GNU General Public License | ||
15 | * along with this program; if not, write to the Free Software | ||
16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
17 | * | ||
18 | */ | ||
19 | |||
20 | #include <linux/bitops.h> | ||
21 | #include <linux/init.h> | ||
22 | #include <linux/list.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/string.h> | ||
25 | #include <linux/usb.h> | ||
26 | #include <linux/moduleparam.h> | ||
27 | #include <linux/mutex.h> | ||
28 | #include <linux/usb/audio.h> | ||
29 | #include <linux/usb/audio-v2.h> | ||
30 | |||
31 | #include <sound/core.h> | ||
32 | #include <sound/info.h> | ||
33 | #include <sound/pcm.h> | ||
34 | #include <sound/pcm_params.h> | ||
35 | #include <sound/initval.h> | ||
36 | |||
37 | #include "usbaudio.h" | ||
38 | #include "card.h" | ||
39 | #include "midi.h" | ||
40 | #include "mixer.h" | ||
41 | #include "proc.h" | ||
42 | #include "quirks.h" | ||
43 | #include "endpoint.h" | ||
44 | #include "helper.h" | ||
45 | #include "debug.h" | ||
46 | #include "pcm.h" | ||
47 | #include "urb.h" | ||
48 | #include "format.h" | ||
49 | |||
50 | static struct uac_clock_source_descriptor * | ||
51 | snd_usb_find_clock_source(struct usb_host_interface *ctrl_iface, | ||
52 | int clock_id) | ||
53 | { | ||
54 | struct uac_clock_source_descriptor *cs = NULL; | ||
55 | |||
56 | while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra, | ||
57 | ctrl_iface->extralen, | ||
58 | cs, UAC2_CLOCK_SOURCE))) { | ||
59 | if (cs->bClockID == clock_id) | ||
60 | return cs; | ||
61 | } | ||
62 | |||
63 | return NULL; | ||
64 | } | ||
65 | |||
66 | static struct uac_clock_selector_descriptor * | ||
67 | snd_usb_find_clock_selector(struct usb_host_interface *ctrl_iface, | ||
68 | int clock_id) | ||
69 | { | ||
70 | struct uac_clock_selector_descriptor *cs = NULL; | ||
71 | |||
72 | while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra, | ||
73 | ctrl_iface->extralen, | ||
74 | cs, UAC2_CLOCK_SELECTOR))) { | ||
75 | if (cs->bClockID == clock_id) | ||
76 | return cs; | ||
77 | } | ||
78 | |||
79 | return NULL; | ||
80 | } | ||
81 | |||
82 | static struct uac_clock_multiplier_descriptor * | ||
83 | snd_usb_find_clock_multiplier(struct usb_host_interface *ctrl_iface, | ||
84 | int clock_id) | ||
85 | { | ||
86 | struct uac_clock_multiplier_descriptor *cs = NULL; | ||
87 | |||
88 | while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra, | ||
89 | ctrl_iface->extralen, | ||
90 | cs, UAC2_CLOCK_MULTIPLIER))) { | ||
91 | if (cs->bClockID == clock_id) | ||
92 | return cs; | ||
93 | } | ||
94 | |||
95 | return NULL; | ||
96 | } | ||
97 | |||
98 | static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id) | ||
99 | { | ||
100 | unsigned char buf; | ||
101 | int ret; | ||
102 | |||
103 | ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), | ||
104 | UAC2_CS_CUR, | ||
105 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, | ||
106 | UAC2_CX_CLOCK_SELECTOR << 8, | ||
107 | snd_usb_ctrl_intf(chip) | (selector_id << 8), | ||
108 | &buf, sizeof(buf), 1000); | ||
109 | |||
110 | if (ret < 0) | ||
111 | return ret; | ||
112 | |||
113 | return buf; | ||
114 | } | ||
115 | |||
116 | static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id) | ||
117 | { | ||
118 | int err; | ||
119 | unsigned char data; | ||
120 | struct usb_device *dev = chip->dev; | ||
121 | |||
122 | err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, | ||
123 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | ||
124 | UAC2_CS_CONTROL_CLOCK_VALID << 8, | ||
125 | snd_usb_ctrl_intf(chip) | (source_id << 8), | ||
126 | &data, sizeof(data), 1000); | ||
127 | |||
128 | if (err < 0) { | ||
129 | snd_printk(KERN_WARNING "%s(): cannot get clock validity for id %d\n", | ||
130 | __func__, source_id); | ||
131 | return err; | ||
132 | } | ||
133 | |||
134 | return !!data; | ||
135 | } | ||
136 | |||
137 | /* Try to find the clock source ID of a given clock entity */ | ||
138 | |||
139 | static int __uac_clock_find_source(struct snd_usb_audio *chip, | ||
140 | struct usb_host_interface *host_iface, | ||
141 | int entity_id, unsigned long *visited) | ||
142 | { | ||
143 | struct uac_clock_source_descriptor *source; | ||
144 | struct uac_clock_selector_descriptor *selector; | ||
145 | struct uac_clock_multiplier_descriptor *multiplier; | ||
146 | |||
147 | entity_id &= 0xff; | ||
148 | |||
149 | if (test_and_set_bit(entity_id, visited)) { | ||
150 | snd_printk(KERN_WARNING | ||
151 | "%s(): recursive clock topology detected, id %d.\n", | ||
152 | __func__, entity_id); | ||
153 | return -EINVAL; | ||
154 | } | ||
155 | |||
156 | /* first, see if the ID we're looking for is a clock source already */ | ||
157 | source = snd_usb_find_clock_source(host_iface, entity_id); | ||
158 | if (source) | ||
159 | return source->bClockID; | ||
160 | |||
161 | selector = snd_usb_find_clock_selector(host_iface, entity_id); | ||
162 | if (selector) { | ||
163 | int ret; | ||
164 | |||
165 | /* the entity ID we are looking for is a selector. | ||
166 | * find out what it currently selects */ | ||
167 | ret = uac_clock_selector_get_val(chip, selector->bClockID); | ||
168 | if (ret < 0) | ||
169 | return ret; | ||
170 | |||
171 | if (ret > selector->bNrInPins || ret < 1) { | ||
172 | printk(KERN_ERR | ||
173 | "%s(): selector reported illegal value, id %d, ret %d\n", | ||
174 | __func__, selector->bClockID, ret); | ||
175 | |||
176 | return -EINVAL; | ||
177 | } | ||
178 | |||
179 | return __uac_clock_find_source(chip, host_iface, | ||
180 | selector->baCSourceID[ret-1], | ||
181 | visited); | ||
182 | } | ||
183 | |||
184 | /* FIXME: multipliers only act as pass-thru element for now */ | ||
185 | multiplier = snd_usb_find_clock_multiplier(host_iface, entity_id); | ||
186 | if (multiplier) | ||
187 | return __uac_clock_find_source(chip, host_iface, | ||
188 | multiplier->bCSourceID, visited); | ||
189 | |||
190 | return -EINVAL; | ||
191 | } | ||
192 | |||
193 | int snd_usb_clock_find_source(struct snd_usb_audio *chip, | ||
194 | struct usb_host_interface *host_iface, | ||
195 | int entity_id) | ||
196 | { | ||
197 | DECLARE_BITMAP(visited, 256); | ||
198 | memset(visited, 0, sizeof(visited)); | ||
199 | return __uac_clock_find_source(chip, host_iface, entity_id, visited); | ||
200 | } | ||
201 | |||
202 | static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, | ||
203 | struct usb_host_interface *alts, | ||
204 | struct audioformat *fmt, int rate) | ||
205 | { | ||
206 | struct usb_device *dev = chip->dev; | ||
207 | unsigned int ep; | ||
208 | unsigned char data[3]; | ||
209 | int err, crate; | ||
210 | |||
211 | ep = get_endpoint(alts, 0)->bEndpointAddress; | ||
212 | |||
213 | /* if endpoint doesn't have sampling rate control, bail out */ | ||
214 | if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE)) { | ||
215 | snd_printk(KERN_WARNING "%d:%d:%d: endpoint lacks sample rate attribute bit, cannot set.\n", | ||
216 | dev->devnum, iface, fmt->altsetting); | ||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | data[0] = rate; | ||
221 | data[1] = rate >> 8; | ||
222 | data[2] = rate >> 16; | ||
223 | if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, | ||
224 | USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, | ||
225 | UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, | ||
226 | data, sizeof(data), 1000)) < 0) { | ||
227 | snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n", | ||
228 | dev->devnum, iface, fmt->altsetting, rate, ep); | ||
229 | return err; | ||
230 | } | ||
231 | |||
232 | if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, | ||
233 | USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN, | ||
234 | UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, | ||
235 | data, sizeof(data), 1000)) < 0) { | ||
236 | snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n", | ||
237 | dev->devnum, iface, fmt->altsetting, ep); | ||
238 | return 0; /* some devices don't support reading */ | ||
239 | } | ||
240 | |||
241 | crate = data[0] | (data[1] << 8) | (data[2] << 16); | ||
242 | if (crate != rate) { | ||
243 | snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate); | ||
244 | // runtime->rate = crate; | ||
245 | } | ||
246 | |||
247 | return 0; | ||
248 | } | ||
249 | |||
250 | static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface, | ||
251 | struct usb_host_interface *alts, | ||
252 | struct audioformat *fmt, int rate) | ||
253 | { | ||
254 | struct usb_device *dev = chip->dev; | ||
255 | unsigned char data[4]; | ||
256 | int err, crate; | ||
257 | int clock = snd_usb_clock_find_source(chip, chip->ctrl_intf, fmt->clock); | ||
258 | |||
259 | if (clock < 0) | ||
260 | return clock; | ||
261 | |||
262 | if (!uac_clock_source_is_valid(chip, clock)) { | ||
263 | snd_printk(KERN_ERR "%d:%d:%d: clock source %d is not valid, cannot use\n", | ||
264 | dev->devnum, iface, fmt->altsetting, clock); | ||
265 | return -ENXIO; | ||
266 | } | ||
267 | |||
268 | data[0] = rate; | ||
269 | data[1] = rate >> 8; | ||
270 | data[2] = rate >> 16; | ||
271 | data[3] = rate >> 24; | ||
272 | if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, | ||
273 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, | ||
274 | UAC2_CS_CONTROL_SAM_FREQ << 8, | ||
275 | snd_usb_ctrl_intf(chip) | (clock << 8), | ||
276 | data, sizeof(data), 1000)) < 0) { | ||
277 | snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2)\n", | ||
278 | dev->devnum, iface, fmt->altsetting, rate); | ||
279 | return err; | ||
280 | } | ||
281 | |||
282 | if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, | ||
283 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | ||
284 | UAC2_CS_CONTROL_SAM_FREQ << 8, | ||
285 | snd_usb_ctrl_intf(chip) | (clock << 8), | ||
286 | data, sizeof(data), 1000)) < 0) { | ||
287 | snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n", | ||
288 | dev->devnum, iface, fmt->altsetting); | ||
289 | return err; | ||
290 | } | ||
291 | |||
292 | crate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); | ||
293 | if (crate != rate) | ||
294 | snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate); | ||
295 | |||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, | ||
300 | struct usb_host_interface *alts, | ||
301 | struct audioformat *fmt, int rate) | ||
302 | { | ||
303 | struct usb_interface_descriptor *altsd = get_iface_desc(alts); | ||
304 | |||
305 | switch (altsd->bInterfaceProtocol) { | ||
306 | case UAC_VERSION_1: | ||
307 | return set_sample_rate_v1(chip, iface, alts, fmt, rate); | ||
308 | |||
309 | case UAC_VERSION_2: | ||
310 | return set_sample_rate_v2(chip, iface, alts, fmt, rate); | ||
311 | } | ||
312 | |||
313 | return -EINVAL; | ||
314 | } | ||
315 | |||
diff --git a/sound/usb/clock.h b/sound/usb/clock.h new file mode 100644 index 00000000000..beb253684e2 --- /dev/null +++ b/sound/usb/clock.h | |||
@@ -0,0 +1,12 @@ | |||
1 | #ifndef __USBAUDIO_CLOCK_H | ||
2 | #define __USBAUDIO_CLOCK_H | ||
3 | |||
4 | int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, | ||
5 | struct usb_host_interface *alts, | ||
6 | struct audioformat *fmt, int rate); | ||
7 | |||
8 | int snd_usb_clock_find_source(struct snd_usb_audio *chip, | ||
9 | struct usb_host_interface *host_iface, | ||
10 | int entity_id); | ||
11 | |||
12 | #endif /* __USBAUDIO_CLOCK_H */ | ||
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 28ee1ce3971..6f6596cf2b1 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c | |||
@@ -190,6 +190,38 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, | |||
190 | return attributes; | 190 | return attributes; |
191 | } | 191 | } |
192 | 192 | ||
193 | static struct uac2_input_terminal_descriptor * | ||
194 | snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface, | ||
195 | int terminal_id) | ||
196 | { | ||
197 | struct uac2_input_terminal_descriptor *term = NULL; | ||
198 | |||
199 | while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, | ||
200 | ctrl_iface->extralen, | ||
201 | term, UAC_INPUT_TERMINAL))) { | ||
202 | if (term->bTerminalID == terminal_id) | ||
203 | return term; | ||
204 | } | ||
205 | |||
206 | return NULL; | ||
207 | } | ||
208 | |||
209 | static struct uac2_output_terminal_descriptor * | ||
210 | snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface, | ||
211 | int terminal_id) | ||
212 | { | ||
213 | struct uac2_output_terminal_descriptor *term = NULL; | ||
214 | |||
215 | while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, | ||
216 | ctrl_iface->extralen, | ||
217 | term, UAC_OUTPUT_TERMINAL))) { | ||
218 | if (term->bTerminalID == terminal_id) | ||
219 | return term; | ||
220 | } | ||
221 | |||
222 | return NULL; | ||
223 | } | ||
224 | |||
193 | int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | 225 | int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) |
194 | { | 226 | { |
195 | struct usb_device *dev; | 227 | struct usb_device *dev; |
@@ -199,7 +231,7 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
199 | int i, altno, err, stream; | 231 | int i, altno, err, stream; |
200 | int format = 0, num_channels = 0; | 232 | int format = 0, num_channels = 0; |
201 | struct audioformat *fp = NULL; | 233 | struct audioformat *fp = NULL; |
202 | int num, protocol; | 234 | int num, protocol, clock = 0; |
203 | struct uac_format_type_i_continuous_descriptor *fmt; | 235 | struct uac_format_type_i_continuous_descriptor *fmt; |
204 | 236 | ||
205 | dev = chip->dev; | 237 | dev = chip->dev; |
@@ -263,6 +295,8 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
263 | } | 295 | } |
264 | 296 | ||
265 | case UAC_VERSION_2: { | 297 | case UAC_VERSION_2: { |
298 | struct uac2_input_terminal_descriptor *input_term; | ||
299 | struct uac2_output_terminal_descriptor *output_term; | ||
266 | struct uac_as_header_descriptor_v2 *as = | 300 | struct uac_as_header_descriptor_v2 *as = |
267 | snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); | 301 | snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); |
268 | 302 | ||
@@ -281,7 +315,25 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
281 | num_channels = as->bNrChannels; | 315 | num_channels = as->bNrChannels; |
282 | format = le32_to_cpu(as->bmFormats); | 316 | format = le32_to_cpu(as->bmFormats); |
283 | 317 | ||
284 | break; | 318 | /* lookup the terminal associated to this interface |
319 | * to extract the clock */ | ||
320 | input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, | ||
321 | as->bTerminalLink); | ||
322 | if (input_term) { | ||
323 | clock = input_term->bCSourceID; | ||
324 | break; | ||
325 | } | ||
326 | |||
327 | output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, | ||
328 | as->bTerminalLink); | ||
329 | if (output_term) { | ||
330 | clock = output_term->bCSourceID; | ||
331 | break; | ||
332 | } | ||
333 | |||
334 | snd_printk(KERN_ERR "%d:%u:%d : bogus bTerminalLink %d\n", | ||
335 | dev->devnum, iface_no, altno, as->bTerminalLink); | ||
336 | continue; | ||
285 | } | 337 | } |
286 | 338 | ||
287 | default: | 339 | default: |
@@ -338,6 +390,7 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
338 | fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) | 390 | fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) |
339 | * (fp->maxpacksize & 0x7ff); | 391 | * (fp->maxpacksize & 0x7ff); |
340 | fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no); | 392 | fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no); |
393 | fp->clock = clock; | ||
341 | 394 | ||
342 | /* some quirks for attributes here */ | 395 | /* some quirks for attributes here */ |
343 | 396 | ||
@@ -374,6 +427,7 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
374 | if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream, alts) < 0) { | 427 | if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream, alts) < 0) { |
375 | kfree(fp->rate_table); | 428 | kfree(fp->rate_table); |
376 | kfree(fp); | 429 | kfree(fp); |
430 | fp = NULL; | ||
377 | continue; | 431 | continue; |
378 | } | 432 | } |
379 | 433 | ||
diff --git a/sound/usb/format.c b/sound/usb/format.c index fe29d61de19..30364aba79c 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include "quirks.h" | 29 | #include "quirks.h" |
30 | #include "helper.h" | 30 | #include "helper.h" |
31 | #include "debug.h" | 31 | #include "debug.h" |
32 | #include "clock.h" | ||
32 | 33 | ||
33 | /* | 34 | /* |
34 | * parse the audio format type I descriptor | 35 | * parse the audio format type I descriptor |
@@ -205,6 +206,60 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof | |||
205 | } | 206 | } |
206 | 207 | ||
207 | /* | 208 | /* |
209 | * Helper function to walk the array of sample rate triplets reported by | ||
210 | * the device. The problem is that we need to parse whole array first to | ||
211 | * get to know how many sample rates we have to expect. | ||
212 | * Then fp->rate_table can be allocated and filled. | ||
213 | */ | ||
214 | static int parse_uac2_sample_rate_range(struct audioformat *fp, int nr_triplets, | ||
215 | const unsigned char *data) | ||
216 | { | ||
217 | int i, nr_rates = 0; | ||
218 | |||
219 | fp->rates = fp->rate_min = fp->rate_max = 0; | ||
220 | |||
221 | for (i = 0; i < nr_triplets; i++) { | ||
222 | int min = combine_quad(&data[2 + 12 * i]); | ||
223 | int max = combine_quad(&data[6 + 12 * i]); | ||
224 | int res = combine_quad(&data[10 + 12 * i]); | ||
225 | int rate; | ||
226 | |||
227 | if ((max < 0) || (min < 0) || (res < 0) || (max < min)) | ||
228 | continue; | ||
229 | |||
230 | /* | ||
231 | * for ranges with res == 1, we announce a continuous sample | ||
232 | * rate range, and this function should return 0 for no further | ||
233 | * parsing. | ||
234 | */ | ||
235 | if (res == 1) { | ||
236 | fp->rate_min = min; | ||
237 | fp->rate_max = max; | ||
238 | fp->rates = SNDRV_PCM_RATE_CONTINUOUS; | ||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | for (rate = min; rate <= max; rate += res) { | ||
243 | if (fp->rate_table) | ||
244 | fp->rate_table[nr_rates] = rate; | ||
245 | if (!fp->rate_min || rate < fp->rate_min) | ||
246 | fp->rate_min = rate; | ||
247 | if (!fp->rate_max || rate > fp->rate_max) | ||
248 | fp->rate_max = rate; | ||
249 | fp->rates |= snd_pcm_rate_to_rate_bit(rate); | ||
250 | |||
251 | nr_rates++; | ||
252 | |||
253 | /* avoid endless loop */ | ||
254 | if (res == 0) | ||
255 | break; | ||
256 | } | ||
257 | } | ||
258 | |||
259 | return nr_rates; | ||
260 | } | ||
261 | |||
262 | /* | ||
208 | * parse the format descriptor and stores the possible sample rates | 263 | * parse the format descriptor and stores the possible sample rates |
209 | * on the audioformat table (audio class v2). | 264 | * on the audioformat table (audio class v2). |
210 | */ | 265 | */ |
@@ -214,21 +269,30 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip, | |||
214 | { | 269 | { |
215 | struct usb_device *dev = chip->dev; | 270 | struct usb_device *dev = chip->dev; |
216 | unsigned char tmp[2], *data; | 271 | unsigned char tmp[2], *data; |
217 | int i, nr_rates, data_size, ret = 0; | 272 | int nr_triplets, data_size, ret = 0; |
273 | int clock = snd_usb_clock_find_source(chip, chip->ctrl_intf, fp->clock); | ||
274 | |||
275 | if (clock < 0) { | ||
276 | snd_printk(KERN_ERR "%s(): unable to find clock source (clock %d)\n", | ||
277 | __func__, clock); | ||
278 | goto err; | ||
279 | } | ||
218 | 280 | ||
219 | /* get the number of sample rates first by only fetching 2 bytes */ | 281 | /* get the number of sample rates first by only fetching 2 bytes */ |
220 | ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE, | 282 | ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE, |
221 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | 283 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, |
222 | UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8, | 284 | UAC2_CS_CONTROL_SAM_FREQ << 8, |
285 | snd_usb_ctrl_intf(chip) | (clock << 8), | ||
223 | tmp, sizeof(tmp), 1000); | 286 | tmp, sizeof(tmp), 1000); |
224 | 287 | ||
225 | if (ret < 0) { | 288 | if (ret < 0) { |
226 | snd_printk(KERN_ERR "unable to retrieve number of sample rates\n"); | 289 | snd_printk(KERN_ERR "%s(): unable to retrieve number of sample rates (clock %d)\n", |
290 | __func__, clock); | ||
227 | goto err; | 291 | goto err; |
228 | } | 292 | } |
229 | 293 | ||
230 | nr_rates = (tmp[1] << 8) | tmp[0]; | 294 | nr_triplets = (tmp[1] << 8) | tmp[0]; |
231 | data_size = 2 + 12 * nr_rates; | 295 | data_size = 2 + 12 * nr_triplets; |
232 | data = kzalloc(data_size, GFP_KERNEL); | 296 | data = kzalloc(data_size, GFP_KERNEL); |
233 | if (!data) { | 297 | if (!data) { |
234 | ret = -ENOMEM; | 298 | ret = -ENOMEM; |
@@ -237,36 +301,40 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip, | |||
237 | 301 | ||
238 | /* now get the full information */ | 302 | /* now get the full information */ |
239 | ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE, | 303 | ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE, |
240 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | 304 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, |
241 | UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8, | 305 | UAC2_CS_CONTROL_SAM_FREQ << 8, |
242 | data, data_size, 1000); | 306 | snd_usb_ctrl_intf(chip) | (clock << 8), |
307 | data, data_size, 1000); | ||
243 | 308 | ||
244 | if (ret < 0) { | 309 | if (ret < 0) { |
245 | snd_printk(KERN_ERR "unable to retrieve sample rate range\n"); | 310 | snd_printk(KERN_ERR "%s(): unable to retrieve sample rate range (clock %d)\n", |
311 | __func__, clock); | ||
246 | ret = -EINVAL; | 312 | ret = -EINVAL; |
247 | goto err_free; | 313 | goto err_free; |
248 | } | 314 | } |
249 | 315 | ||
250 | fp->rate_table = kmalloc(sizeof(int) * nr_rates, GFP_KERNEL); | 316 | /* Call the triplet parser, and make sure fp->rate_table is NULL. |
317 | * We just use the return value to know how many sample rates we | ||
318 | * will have to deal with. */ | ||
319 | kfree(fp->rate_table); | ||
320 | fp->rate_table = NULL; | ||
321 | fp->nr_rates = parse_uac2_sample_rate_range(fp, nr_triplets, data); | ||
322 | |||
323 | if (fp->nr_rates == 0) { | ||
324 | /* SNDRV_PCM_RATE_CONTINUOUS */ | ||
325 | ret = 0; | ||
326 | goto err_free; | ||
327 | } | ||
328 | |||
329 | fp->rate_table = kmalloc(sizeof(int) * fp->nr_rates, GFP_KERNEL); | ||
251 | if (!fp->rate_table) { | 330 | if (!fp->rate_table) { |
252 | ret = -ENOMEM; | 331 | ret = -ENOMEM; |
253 | goto err_free; | 332 | goto err_free; |
254 | } | 333 | } |
255 | 334 | ||
256 | fp->nr_rates = 0; | 335 | /* Call the triplet parser again, but this time, fp->rate_table is |
257 | fp->rate_min = fp->rate_max = 0; | 336 | * allocated, so the rates will be stored */ |
258 | 337 | parse_uac2_sample_rate_range(fp, nr_triplets, data); | |
259 | for (i = 0; i < nr_rates; i++) { | ||
260 | int rate = combine_quad(&data[2 + 12 * i]); | ||
261 | |||
262 | fp->rate_table[fp->nr_rates] = rate; | ||
263 | if (!fp->rate_min || rate < fp->rate_min) | ||
264 | fp->rate_min = rate; | ||
265 | if (!fp->rate_max || rate > fp->rate_max) | ||
266 | fp->rate_max = rate; | ||
267 | fp->rates |= snd_pcm_rate_to_rate_bit(rate); | ||
268 | fp->nr_rates++; | ||
269 | } | ||
270 | 338 | ||
271 | err_free: | 339 | err_free: |
272 | kfree(data); | 340 | kfree(data); |
diff --git a/sound/usb/helper.h b/sound/usb/helper.h index a6b0e51b3a9..09bd943c43b 100644 --- a/sound/usb/helper.h +++ b/sound/usb/helper.h | |||
@@ -28,5 +28,9 @@ unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip, | |||
28 | #define snd_usb_get_speed(dev) ((dev)->speed) | 28 | #define snd_usb_get_speed(dev) ((dev)->speed) |
29 | #endif | 29 | #endif |
30 | 30 | ||
31 | static inline int snd_usb_ctrl_intf(struct snd_usb_audio *chip) | ||
32 | { | ||
33 | return get_iface_desc(chip->ctrl_intf)->bInterfaceNumber; | ||
34 | } | ||
31 | 35 | ||
32 | #endif /* __USBAUDIO_HELPER_H */ | 36 | #endif /* __USBAUDIO_HELPER_H */ |
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 03ce971e002..736d134cc03 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c | |||
@@ -78,39 +78,6 @@ enum { | |||
78 | USB_MIXER_U16, | 78 | USB_MIXER_U16, |
79 | }; | 79 | }; |
80 | 80 | ||
81 | enum { | ||
82 | USB_PROC_UPDOWN = 1, | ||
83 | USB_PROC_UPDOWN_SWITCH = 1, | ||
84 | USB_PROC_UPDOWN_MODE_SEL = 2, | ||
85 | |||
86 | USB_PROC_PROLOGIC = 2, | ||
87 | USB_PROC_PROLOGIC_SWITCH = 1, | ||
88 | USB_PROC_PROLOGIC_MODE_SEL = 2, | ||
89 | |||
90 | USB_PROC_3DENH = 3, | ||
91 | USB_PROC_3DENH_SWITCH = 1, | ||
92 | USB_PROC_3DENH_SPACE = 2, | ||
93 | |||
94 | USB_PROC_REVERB = 4, | ||
95 | USB_PROC_REVERB_SWITCH = 1, | ||
96 | USB_PROC_REVERB_LEVEL = 2, | ||
97 | USB_PROC_REVERB_TIME = 3, | ||
98 | USB_PROC_REVERB_DELAY = 4, | ||
99 | |||
100 | USB_PROC_CHORUS = 5, | ||
101 | USB_PROC_CHORUS_SWITCH = 1, | ||
102 | USB_PROC_CHORUS_LEVEL = 2, | ||
103 | USB_PROC_CHORUS_RATE = 3, | ||
104 | USB_PROC_CHORUS_DEPTH = 4, | ||
105 | |||
106 | USB_PROC_DCR = 6, | ||
107 | USB_PROC_DCR_SWITCH = 1, | ||
108 | USB_PROC_DCR_RATIO = 2, | ||
109 | USB_PROC_DCR_MAX_AMP = 3, | ||
110 | USB_PROC_DCR_THRESHOLD = 4, | ||
111 | USB_PROC_DCR_ATTACK = 5, | ||
112 | USB_PROC_DCR_RELEASE = 6, | ||
113 | }; | ||
114 | 81 | ||
115 | /*E-mu 0202(0404) eXtension Unit(XU) control*/ | 82 | /*E-mu 0202(0404) eXtension Unit(XU) control*/ |
116 | enum { | 83 | enum { |
@@ -198,22 +165,24 @@ static int check_mapped_selector_name(struct mixer_build *state, int unitid, | |||
198 | 165 | ||
199 | /* | 166 | /* |
200 | * find an audio control unit with the given unit id | 167 | * find an audio control unit with the given unit id |
201 | * this doesn't return any clock related units, so they need to be handled elsewhere | ||
202 | */ | 168 | */ |
203 | static void *find_audio_control_unit(struct mixer_build *state, unsigned char unit) | 169 | static void *find_audio_control_unit(struct mixer_build *state, unsigned char unit) |
204 | { | 170 | { |
205 | unsigned char *p; | 171 | /* we just parse the header */ |
172 | struct uac_feature_unit_descriptor *hdr = NULL; | ||
206 | 173 | ||
207 | p = NULL; | 174 | while ((hdr = snd_usb_find_desc(state->buffer, state->buflen, hdr, |
208 | while ((p = snd_usb_find_desc(state->buffer, state->buflen, p, | 175 | USB_DT_CS_INTERFACE)) != NULL) { |
209 | USB_DT_CS_INTERFACE)) != NULL) { | 176 | if (hdr->bLength >= 4 && |
210 | if (p[0] >= 4 && p[2] >= UAC_INPUT_TERMINAL && p[2] <= UAC2_EXTENSION_UNIT_V2 && p[3] == unit) | 177 | hdr->bDescriptorSubtype >= UAC_INPUT_TERMINAL && |
211 | return p; | 178 | hdr->bDescriptorSubtype <= UAC2_SAMPLE_RATE_CONVERTER && |
179 | hdr->bUnitID == unit) | ||
180 | return hdr; | ||
212 | } | 181 | } |
182 | |||
213 | return NULL; | 183 | return NULL; |
214 | } | 184 | } |
215 | 185 | ||
216 | |||
217 | /* | 186 | /* |
218 | * copy a string with the given id | 187 | * copy a string with the given id |
219 | */ | 188 | */ |
@@ -328,27 +297,36 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request, int v | |||
328 | 297 | ||
329 | static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret) | 298 | static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int validx, int *value_ret) |
330 | { | 299 | { |
331 | unsigned char buf[14]; /* enough space for one range of 4 bytes */ | 300 | unsigned char buf[2 + 3*sizeof(__u16)]; /* enough space for one range */ |
332 | unsigned char *val; | 301 | unsigned char *val; |
333 | int ret; | 302 | int ret, size; |
334 | __u8 bRequest; | 303 | __u8 bRequest; |
335 | 304 | ||
336 | bRequest = (request == UAC_GET_CUR) ? | 305 | if (request == UAC_GET_CUR) { |
337 | UAC2_CS_CUR : UAC2_CS_RANGE; | 306 | bRequest = UAC2_CS_CUR; |
307 | size = sizeof(__u16); | ||
308 | } else { | ||
309 | bRequest = UAC2_CS_RANGE; | ||
310 | size = sizeof(buf); | ||
311 | } | ||
312 | |||
313 | memset(buf, 0, sizeof(buf)); | ||
338 | 314 | ||
339 | ret = snd_usb_ctl_msg(cval->mixer->chip->dev, | 315 | ret = snd_usb_ctl_msg(cval->mixer->chip->dev, |
340 | usb_rcvctrlpipe(cval->mixer->chip->dev, 0), | 316 | usb_rcvctrlpipe(cval->mixer->chip->dev, 0), |
341 | bRequest, | 317 | bRequest, |
342 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, | 318 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, |
343 | validx, cval->mixer->ctrlif | (cval->id << 8), | 319 | validx, cval->mixer->ctrlif | (cval->id << 8), |
344 | buf, sizeof(buf), 1000); | 320 | buf, size, 1000); |
345 | 321 | ||
346 | if (ret < 0) { | 322 | if (ret < 0) { |
347 | snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", | 323 | snd_printk(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", |
348 | request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type); | 324 | request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type); |
349 | return ret; | 325 | return ret; |
350 | } | 326 | } |
351 | 327 | ||
328 | /* FIXME: how should we handle multiple triplets here? */ | ||
329 | |||
352 | switch (request) { | 330 | switch (request) { |
353 | case UAC_GET_CUR: | 331 | case UAC_GET_CUR: |
354 | val = buf; | 332 | val = buf; |
@@ -462,6 +440,16 @@ static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, | |||
462 | int index, int value) | 440 | int index, int value) |
463 | { | 441 | { |
464 | int err; | 442 | int err; |
443 | unsigned int read_only = (channel == 0) ? | ||
444 | cval->master_readonly : | ||
445 | cval->ch_readonly & (1 << (channel - 1)); | ||
446 | |||
447 | if (read_only) { | ||
448 | snd_printdd(KERN_INFO "%s(): channel %d of control %d is read_only\n", | ||
449 | __func__, channel, cval->control); | ||
450 | return 0; | ||
451 | } | ||
452 | |||
465 | err = snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, (cval->control << 8) | channel, | 453 | err = snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, (cval->control << 8) | channel, |
466 | value); | 454 | value); |
467 | if (err < 0) | 455 | if (err < 0) |
@@ -631,6 +619,7 @@ static int get_term_name(struct mixer_build *state, struct usb_audio_term *iterm | |||
631 | */ | 619 | */ |
632 | static int check_input_term(struct mixer_build *state, int id, struct usb_audio_term *term) | 620 | static int check_input_term(struct mixer_build *state, int id, struct usb_audio_term *term) |
633 | { | 621 | { |
622 | int err; | ||
634 | void *p1; | 623 | void *p1; |
635 | 624 | ||
636 | memset(term, 0, sizeof(*term)); | 625 | memset(term, 0, sizeof(*term)); |
@@ -651,6 +640,11 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_ | |||
651 | term->channels = d->bNrChannels; | 640 | term->channels = d->bNrChannels; |
652 | term->chconfig = le32_to_cpu(d->bmChannelConfig); | 641 | term->chconfig = le32_to_cpu(d->bmChannelConfig); |
653 | term->name = d->iTerminal; | 642 | term->name = d->iTerminal; |
643 | |||
644 | /* call recursively to get the clock selectors */ | ||
645 | err = check_input_term(state, d->bCSourceID, term); | ||
646 | if (err < 0) | ||
647 | return err; | ||
654 | } | 648 | } |
655 | return 0; | 649 | return 0; |
656 | case UAC_FEATURE_UNIT: { | 650 | case UAC_FEATURE_UNIT: { |
@@ -667,7 +661,8 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_ | |||
667 | term->name = uac_mixer_unit_iMixer(d); | 661 | term->name = uac_mixer_unit_iMixer(d); |
668 | return 0; | 662 | return 0; |
669 | } | 663 | } |
670 | case UAC_SELECTOR_UNIT: { | 664 | case UAC_SELECTOR_UNIT: |
665 | case UAC2_CLOCK_SELECTOR: { | ||
671 | struct uac_selector_unit_descriptor *d = p1; | 666 | struct uac_selector_unit_descriptor *d = p1; |
672 | /* call recursively to retrieve the channel info */ | 667 | /* call recursively to retrieve the channel info */ |
673 | if (check_input_term(state, d->baSourceID[0], term) < 0) | 668 | if (check_input_term(state, d->baSourceID[0], term) < 0) |
@@ -690,6 +685,13 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_ | |||
690 | term->name = uac_processing_unit_iProcessing(d, state->mixer->protocol); | 685 | term->name = uac_processing_unit_iProcessing(d, state->mixer->protocol); |
691 | return 0; | 686 | return 0; |
692 | } | 687 | } |
688 | case UAC2_CLOCK_SOURCE: { | ||
689 | struct uac_clock_source_descriptor *d = p1; | ||
690 | term->type = d->bDescriptorSubtype << 16; /* virtual type */ | ||
691 | term->id = id; | ||
692 | term->name = d->iClockSource; | ||
693 | return 0; | ||
694 | } | ||
693 | default: | 695 | default: |
694 | return -ENODEV; | 696 | return -ENODEV; |
695 | } | 697 | } |
@@ -709,16 +711,20 @@ struct usb_feature_control_info { | |||
709 | }; | 711 | }; |
710 | 712 | ||
711 | static struct usb_feature_control_info audio_feature_info[] = { | 713 | static struct usb_feature_control_info audio_feature_info[] = { |
712 | { "Mute", USB_MIXER_INV_BOOLEAN }, | 714 | { "Mute", USB_MIXER_INV_BOOLEAN }, |
713 | { "Volume", USB_MIXER_S16 }, | 715 | { "Volume", USB_MIXER_S16 }, |
714 | { "Tone Control - Bass", USB_MIXER_S8 }, | 716 | { "Tone Control - Bass", USB_MIXER_S8 }, |
715 | { "Tone Control - Mid", USB_MIXER_S8 }, | 717 | { "Tone Control - Mid", USB_MIXER_S8 }, |
716 | { "Tone Control - Treble", USB_MIXER_S8 }, | 718 | { "Tone Control - Treble", USB_MIXER_S8 }, |
717 | { "Graphic Equalizer", USB_MIXER_S8 }, /* FIXME: not implemeted yet */ | 719 | { "Graphic Equalizer", USB_MIXER_S8 }, /* FIXME: not implemeted yet */ |
718 | { "Auto Gain Control", USB_MIXER_BOOLEAN }, | 720 | { "Auto Gain Control", USB_MIXER_BOOLEAN }, |
719 | { "Delay Control", USB_MIXER_U16 }, | 721 | { "Delay Control", USB_MIXER_U16 }, |
720 | { "Bass Boost", USB_MIXER_BOOLEAN }, | 722 | { "Bass Boost", USB_MIXER_BOOLEAN }, |
721 | { "Loudness", USB_MIXER_BOOLEAN }, | 723 | { "Loudness", USB_MIXER_BOOLEAN }, |
724 | /* UAC2 specific */ | ||
725 | { "Input Gain Control", USB_MIXER_U16 }, | ||
726 | { "Input Gain Pad Control", USB_MIXER_BOOLEAN }, | ||
727 | { "Phase Inverter Control", USB_MIXER_BOOLEAN }, | ||
722 | }; | 728 | }; |
723 | 729 | ||
724 | 730 | ||
@@ -958,7 +964,7 @@ static size_t append_ctl_name(struct snd_kcontrol *kctl, const char *str) | |||
958 | static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | 964 | static void build_feature_ctl(struct mixer_build *state, void *raw_desc, |
959 | unsigned int ctl_mask, int control, | 965 | unsigned int ctl_mask, int control, |
960 | struct usb_audio_term *iterm, int unitid, | 966 | struct usb_audio_term *iterm, int unitid, |
961 | int read_only) | 967 | int readonly_mask) |
962 | { | 968 | { |
963 | struct uac_feature_unit_descriptor *desc = raw_desc; | 969 | struct uac_feature_unit_descriptor *desc = raw_desc; |
964 | unsigned int len = 0; | 970 | unsigned int len = 0; |
@@ -970,7 +976,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
970 | 976 | ||
971 | control++; /* change from zero-based to 1-based value */ | 977 | control++; /* change from zero-based to 1-based value */ |
972 | 978 | ||
973 | if (control == UAC_GRAPHIC_EQUALIZER_CONTROL) { | 979 | if (control == UAC_FU_GRAPHIC_EQUALIZER) { |
974 | /* FIXME: not supported yet */ | 980 | /* FIXME: not supported yet */ |
975 | return; | 981 | return; |
976 | } | 982 | } |
@@ -989,20 +995,25 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
989 | cval->control = control; | 995 | cval->control = control; |
990 | cval->cmask = ctl_mask; | 996 | cval->cmask = ctl_mask; |
991 | cval->val_type = audio_feature_info[control-1].type; | 997 | cval->val_type = audio_feature_info[control-1].type; |
992 | if (ctl_mask == 0) | 998 | if (ctl_mask == 0) { |
993 | cval->channels = 1; /* master channel */ | 999 | cval->channels = 1; /* master channel */ |
994 | else { | 1000 | cval->master_readonly = readonly_mask; |
1001 | } else { | ||
995 | int i, c = 0; | 1002 | int i, c = 0; |
996 | for (i = 0; i < 16; i++) | 1003 | for (i = 0; i < 16; i++) |
997 | if (ctl_mask & (1 << i)) | 1004 | if (ctl_mask & (1 << i)) |
998 | c++; | 1005 | c++; |
999 | cval->channels = c; | 1006 | cval->channels = c; |
1007 | cval->ch_readonly = readonly_mask; | ||
1000 | } | 1008 | } |
1001 | 1009 | ||
1002 | /* get min/max values */ | 1010 | /* get min/max values */ |
1003 | get_min_max(cval, 0); | 1011 | get_min_max(cval, 0); |
1004 | 1012 | ||
1005 | if (read_only) | 1013 | /* if all channels in the mask are marked read-only, make the control |
1014 | * read-only. set_cur_mix_value() will check the mask again and won't | ||
1015 | * issue write commands to read-only channels. */ | ||
1016 | if (cval->channels == readonly_mask) | ||
1006 | kctl = snd_ctl_new1(&usb_feature_unit_ctl_ro, cval); | 1017 | kctl = snd_ctl_new1(&usb_feature_unit_ctl_ro, cval); |
1007 | else | 1018 | else |
1008 | kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); | 1019 | kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); |
@@ -1021,8 +1032,8 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
1021 | kctl->id.name, sizeof(kctl->id.name)); | 1032 | kctl->id.name, sizeof(kctl->id.name)); |
1022 | 1033 | ||
1023 | switch (control) { | 1034 | switch (control) { |
1024 | case UAC_MUTE_CONTROL: | 1035 | case UAC_FU_MUTE: |
1025 | case UAC_VOLUME_CONTROL: | 1036 | case UAC_FU_VOLUME: |
1026 | /* determine the control name. the rule is: | 1037 | /* determine the control name. the rule is: |
1027 | * - if a name id is given in descriptor, use it. | 1038 | * - if a name id is given in descriptor, use it. |
1028 | * - if the connected input can be determined, then use the name | 1039 | * - if the connected input can be determined, then use the name |
@@ -1049,9 +1060,9 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
1049 | len = append_ctl_name(kctl, " Playback"); | 1060 | len = append_ctl_name(kctl, " Playback"); |
1050 | } | 1061 | } |
1051 | } | 1062 | } |
1052 | append_ctl_name(kctl, control == UAC_MUTE_CONTROL ? | 1063 | append_ctl_name(kctl, control == UAC_FU_MUTE ? |
1053 | " Switch" : " Volume"); | 1064 | " Switch" : " Volume"); |
1054 | if (control == UAC_VOLUME_CONTROL) { | 1065 | if (control == UAC_FU_VOLUME) { |
1055 | kctl->tlv.c = mixer_vol_tlv; | 1066 | kctl->tlv.c = mixer_vol_tlv; |
1056 | kctl->vd[0].access |= | 1067 | kctl->vd[0].access |= |
1057 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | | 1068 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | |
@@ -1096,6 +1107,19 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
1096 | } | 1107 | } |
1097 | break; | 1108 | break; |
1098 | 1109 | ||
1110 | case USB_ID(0x046d, 0x0809): | ||
1111 | case USB_ID(0x046d, 0x0991): | ||
1112 | /* Most audio usb devices lie about volume resolution. | ||
1113 | * Most Logitech webcams have res = 384. | ||
1114 | * Proboly there is some logitech magic behind this number --fishor | ||
1115 | */ | ||
1116 | if (!strcmp(kctl->id.name, "Mic Capture Volume")) { | ||
1117 | snd_printk(KERN_INFO | ||
1118 | "set resolution quirk: cval->res = 384\n"); | ||
1119 | cval->res = 384; | ||
1120 | } | ||
1121 | break; | ||
1122 | |||
1099 | } | 1123 | } |
1100 | 1124 | ||
1101 | snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", | 1125 | snd_printdd(KERN_INFO "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", |
@@ -1150,7 +1174,7 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void | |||
1150 | snd_printk(KERN_INFO | 1174 | snd_printk(KERN_INFO |
1151 | "usbmixer: master volume quirk for PCM2702 chip\n"); | 1175 | "usbmixer: master volume quirk for PCM2702 chip\n"); |
1152 | /* disable non-functional volume control */ | 1176 | /* disable non-functional volume control */ |
1153 | master_bits &= ~UAC_FU_VOLUME; | 1177 | master_bits &= ~UAC_CONTROL_BIT(UAC_FU_VOLUME); |
1154 | break; | 1178 | break; |
1155 | } | 1179 | } |
1156 | if (channels > 0) | 1180 | if (channels > 0) |
@@ -1188,19 +1212,22 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void | |||
1188 | 1212 | ||
1189 | for (j = 0; j < channels; j++) { | 1213 | for (j = 0; j < channels; j++) { |
1190 | unsigned int mask = snd_usb_combine_bytes(bmaControls + csize * (j+1), csize); | 1214 | unsigned int mask = snd_usb_combine_bytes(bmaControls + csize * (j+1), csize); |
1191 | if (mask & (1 << (i * 2))) { | 1215 | if (uac2_control_is_readable(mask, i)) { |
1192 | ch_bits |= (1 << j); | 1216 | ch_bits |= (1 << j); |
1193 | if (~mask & (1 << ((i * 2) + 1))) | 1217 | if (!uac2_control_is_writeable(mask, i)) |
1194 | ch_read_only |= (1 << j); | 1218 | ch_read_only |= (1 << j); |
1195 | } | 1219 | } |
1196 | } | 1220 | } |
1197 | 1221 | ||
1198 | /* FIXME: the whole unit is read-only if any of the channels is marked read-only */ | 1222 | /* NOTE: build_feature_ctl() will mark the control read-only if all channels |
1223 | * are marked read-only in the descriptors. Otherwise, the control will be | ||
1224 | * reported as writeable, but the driver will not actually issue a write | ||
1225 | * command for read-only channels */ | ||
1199 | if (ch_bits & 1) /* the first channel must be set (for ease of programming) */ | 1226 | if (ch_bits & 1) /* the first channel must be set (for ease of programming) */ |
1200 | build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid, !!ch_read_only); | 1227 | build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid, ch_read_only); |
1201 | if (master_bits & (1 << i * 2)) | 1228 | if (uac2_control_is_readable(master_bits, i)) |
1202 | build_feature_ctl(state, _ftr, 0, i, &iterm, unitid, | 1229 | build_feature_ctl(state, _ftr, 0, i, &iterm, unitid, |
1203 | ~master_bits & (1 << ((i * 2) + 1))); | 1230 | !uac2_control_is_writeable(master_bits, i)); |
1204 | } | 1231 | } |
1205 | } | 1232 | } |
1206 | 1233 | ||
@@ -1392,51 +1419,51 @@ struct procunit_info { | |||
1392 | }; | 1419 | }; |
1393 | 1420 | ||
1394 | static struct procunit_value_info updown_proc_info[] = { | 1421 | static struct procunit_value_info updown_proc_info[] = { |
1395 | { USB_PROC_UPDOWN_SWITCH, "Switch", USB_MIXER_BOOLEAN }, | 1422 | { UAC_UD_ENABLE, "Switch", USB_MIXER_BOOLEAN }, |
1396 | { USB_PROC_UPDOWN_MODE_SEL, "Mode Select", USB_MIXER_U8, 1 }, | 1423 | { UAC_UD_MODE_SELECT, "Mode Select", USB_MIXER_U8, 1 }, |
1397 | { 0 } | 1424 | { 0 } |
1398 | }; | 1425 | }; |
1399 | static struct procunit_value_info prologic_proc_info[] = { | 1426 | static struct procunit_value_info prologic_proc_info[] = { |
1400 | { USB_PROC_PROLOGIC_SWITCH, "Switch", USB_MIXER_BOOLEAN }, | 1427 | { UAC_DP_ENABLE, "Switch", USB_MIXER_BOOLEAN }, |
1401 | { USB_PROC_PROLOGIC_MODE_SEL, "Mode Select", USB_MIXER_U8, 1 }, | 1428 | { UAC_DP_MODE_SELECT, "Mode Select", USB_MIXER_U8, 1 }, |
1402 | { 0 } | 1429 | { 0 } |
1403 | }; | 1430 | }; |
1404 | static struct procunit_value_info threed_enh_proc_info[] = { | 1431 | static struct procunit_value_info threed_enh_proc_info[] = { |
1405 | { USB_PROC_3DENH_SWITCH, "Switch", USB_MIXER_BOOLEAN }, | 1432 | { UAC_3D_ENABLE, "Switch", USB_MIXER_BOOLEAN }, |
1406 | { USB_PROC_3DENH_SPACE, "Spaciousness", USB_MIXER_U8 }, | 1433 | { UAC_3D_SPACE, "Spaciousness", USB_MIXER_U8 }, |
1407 | { 0 } | 1434 | { 0 } |
1408 | }; | 1435 | }; |
1409 | static struct procunit_value_info reverb_proc_info[] = { | 1436 | static struct procunit_value_info reverb_proc_info[] = { |
1410 | { USB_PROC_REVERB_SWITCH, "Switch", USB_MIXER_BOOLEAN }, | 1437 | { UAC_REVERB_ENABLE, "Switch", USB_MIXER_BOOLEAN }, |
1411 | { USB_PROC_REVERB_LEVEL, "Level", USB_MIXER_U8 }, | 1438 | { UAC_REVERB_LEVEL, "Level", USB_MIXER_U8 }, |
1412 | { USB_PROC_REVERB_TIME, "Time", USB_MIXER_U16 }, | 1439 | { UAC_REVERB_TIME, "Time", USB_MIXER_U16 }, |
1413 | { USB_PROC_REVERB_DELAY, "Delay", USB_MIXER_U8 }, | 1440 | { UAC_REVERB_FEEDBACK, "Feedback", USB_MIXER_U8 }, |
1414 | { 0 } | 1441 | { 0 } |
1415 | }; | 1442 | }; |
1416 | static struct procunit_value_info chorus_proc_info[] = { | 1443 | static struct procunit_value_info chorus_proc_info[] = { |
1417 | { USB_PROC_CHORUS_SWITCH, "Switch", USB_MIXER_BOOLEAN }, | 1444 | { UAC_CHORUS_ENABLE, "Switch", USB_MIXER_BOOLEAN }, |
1418 | { USB_PROC_CHORUS_LEVEL, "Level", USB_MIXER_U8 }, | 1445 | { UAC_CHORUS_LEVEL, "Level", USB_MIXER_U8 }, |
1419 | { USB_PROC_CHORUS_RATE, "Rate", USB_MIXER_U16 }, | 1446 | { UAC_CHORUS_RATE, "Rate", USB_MIXER_U16 }, |
1420 | { USB_PROC_CHORUS_DEPTH, "Depth", USB_MIXER_U16 }, | 1447 | { UAC_CHORUS_DEPTH, "Depth", USB_MIXER_U16 }, |
1421 | { 0 } | 1448 | { 0 } |
1422 | }; | 1449 | }; |
1423 | static struct procunit_value_info dcr_proc_info[] = { | 1450 | static struct procunit_value_info dcr_proc_info[] = { |
1424 | { USB_PROC_DCR_SWITCH, "Switch", USB_MIXER_BOOLEAN }, | 1451 | { UAC_DCR_ENABLE, "Switch", USB_MIXER_BOOLEAN }, |
1425 | { USB_PROC_DCR_RATIO, "Ratio", USB_MIXER_U16 }, | 1452 | { UAC_DCR_RATE, "Ratio", USB_MIXER_U16 }, |
1426 | { USB_PROC_DCR_MAX_AMP, "Max Amp", USB_MIXER_S16 }, | 1453 | { UAC_DCR_MAXAMPL, "Max Amp", USB_MIXER_S16 }, |
1427 | { USB_PROC_DCR_THRESHOLD, "Threshold", USB_MIXER_S16 }, | 1454 | { UAC_DCR_THRESHOLD, "Threshold", USB_MIXER_S16 }, |
1428 | { USB_PROC_DCR_ATTACK, "Attack Time", USB_MIXER_U16 }, | 1455 | { UAC_DCR_ATTACK_TIME, "Attack Time", USB_MIXER_U16 }, |
1429 | { USB_PROC_DCR_RELEASE, "Release Time", USB_MIXER_U16 }, | 1456 | { UAC_DCR_RELEASE_TIME, "Release Time", USB_MIXER_U16 }, |
1430 | { 0 } | 1457 | { 0 } |
1431 | }; | 1458 | }; |
1432 | 1459 | ||
1433 | static struct procunit_info procunits[] = { | 1460 | static struct procunit_info procunits[] = { |
1434 | { USB_PROC_UPDOWN, "Up Down", updown_proc_info }, | 1461 | { UAC_PROCESS_UP_DOWNMIX, "Up Down", updown_proc_info }, |
1435 | { USB_PROC_PROLOGIC, "Dolby Prologic", prologic_proc_info }, | 1462 | { UAC_PROCESS_DOLBY_PROLOGIC, "Dolby Prologic", prologic_proc_info }, |
1436 | { USB_PROC_3DENH, "3D Stereo Extender", threed_enh_proc_info }, | 1463 | { UAC_PROCESS_STEREO_EXTENDER, "3D Stereo Extender", threed_enh_proc_info }, |
1437 | { USB_PROC_REVERB, "Reverb", reverb_proc_info }, | 1464 | { UAC_PROCESS_REVERB, "Reverb", reverb_proc_info }, |
1438 | { USB_PROC_CHORUS, "Chorus", chorus_proc_info }, | 1465 | { UAC_PROCESS_CHORUS, "Chorus", chorus_proc_info }, |
1439 | { USB_PROC_DCR, "DCR", dcr_proc_info }, | 1466 | { UAC_PROCESS_DYN_RANGE_COMP, "DCR", dcr_proc_info }, |
1440 | { 0 }, | 1467 | { 0 }, |
1441 | }; | 1468 | }; |
1442 | /* | 1469 | /* |
@@ -1524,7 +1551,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw | |||
1524 | cval->channels = 1; | 1551 | cval->channels = 1; |
1525 | 1552 | ||
1526 | /* get min/max values */ | 1553 | /* get min/max values */ |
1527 | if (type == USB_PROC_UPDOWN && cval->control == USB_PROC_UPDOWN_MODE_SEL) { | 1554 | if (type == UAC_PROCESS_UP_DOWNMIX && cval->control == UAC_UD_MODE_SELECT) { |
1528 | __u8 *control_spec = uac_processing_unit_specific(desc, state->mixer->protocol); | 1555 | __u8 *control_spec = uac_processing_unit_specific(desc, state->mixer->protocol); |
1529 | /* FIXME: hard-coded */ | 1556 | /* FIXME: hard-coded */ |
1530 | cval->min = 1; | 1557 | cval->min = 1; |
@@ -1619,7 +1646,7 @@ static int mixer_ctl_selector_get(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
1619 | struct usb_mixer_elem_info *cval = kcontrol->private_data; | 1646 | struct usb_mixer_elem_info *cval = kcontrol->private_data; |
1620 | int val, err; | 1647 | int val, err; |
1621 | 1648 | ||
1622 | err = get_cur_ctl_value(cval, 0, &val); | 1649 | err = get_cur_ctl_value(cval, cval->control << 8, &val); |
1623 | if (err < 0) { | 1650 | if (err < 0) { |
1624 | if (cval->mixer->ignore_ctl_error) { | 1651 | if (cval->mixer->ignore_ctl_error) { |
1625 | ucontrol->value.enumerated.item[0] = 0; | 1652 | ucontrol->value.enumerated.item[0] = 0; |
@@ -1638,7 +1665,7 @@ static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
1638 | struct usb_mixer_elem_info *cval = kcontrol->private_data; | 1665 | struct usb_mixer_elem_info *cval = kcontrol->private_data; |
1639 | int val, oval, err; | 1666 | int val, oval, err; |
1640 | 1667 | ||
1641 | err = get_cur_ctl_value(cval, 0, &oval); | 1668 | err = get_cur_ctl_value(cval, cval->control << 8, &oval); |
1642 | if (err < 0) { | 1669 | if (err < 0) { |
1643 | if (cval->mixer->ignore_ctl_error) | 1670 | if (cval->mixer->ignore_ctl_error) |
1644 | return 0; | 1671 | return 0; |
@@ -1647,7 +1674,7 @@ static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
1647 | val = ucontrol->value.enumerated.item[0]; | 1674 | val = ucontrol->value.enumerated.item[0]; |
1648 | val = get_abs_value(cval, val); | 1675 | val = get_abs_value(cval, val); |
1649 | if (val != oval) { | 1676 | if (val != oval) { |
1650 | set_cur_ctl_value(cval, 0, val); | 1677 | set_cur_ctl_value(cval, cval->control << 8, val); |
1651 | return 1; | 1678 | return 1; |
1652 | } | 1679 | } |
1653 | return 0; | 1680 | return 0; |
@@ -1729,6 +1756,11 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void | |||
1729 | cval->res = 1; | 1756 | cval->res = 1; |
1730 | cval->initialized = 1; | 1757 | cval->initialized = 1; |
1731 | 1758 | ||
1759 | if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR) | ||
1760 | cval->control = UAC2_CX_CLOCK_SELECTOR; | ||
1761 | else | ||
1762 | cval->control = 0; | ||
1763 | |||
1732 | namelist = kmalloc(sizeof(char *) * desc->bNrInPins, GFP_KERNEL); | 1764 | namelist = kmalloc(sizeof(char *) * desc->bNrInPins, GFP_KERNEL); |
1733 | if (! namelist) { | 1765 | if (! namelist) { |
1734 | snd_printk(KERN_ERR "cannot malloc\n"); | 1766 | snd_printk(KERN_ERR "cannot malloc\n"); |
@@ -1778,7 +1810,9 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void | |||
1778 | if (! len) | 1810 | if (! len) |
1779 | strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name)); | 1811 | strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name)); |
1780 | 1812 | ||
1781 | if ((state->oterm.type & 0xff00) == 0x0100) | 1813 | if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR) |
1814 | append_ctl_name(kctl, " Clock Source"); | ||
1815 | else if ((state->oterm.type & 0xff00) == 0x0100) | ||
1782 | append_ctl_name(kctl, " Capture Source"); | 1816 | append_ctl_name(kctl, " Capture Source"); |
1783 | else | 1817 | else |
1784 | append_ctl_name(kctl, " Playback Source"); | 1818 | append_ctl_name(kctl, " Playback Source"); |
@@ -1812,10 +1846,12 @@ static int parse_audio_unit(struct mixer_build *state, int unitid) | |||
1812 | 1846 | ||
1813 | switch (p1[2]) { | 1847 | switch (p1[2]) { |
1814 | case UAC_INPUT_TERMINAL: | 1848 | case UAC_INPUT_TERMINAL: |
1849 | case UAC2_CLOCK_SOURCE: | ||
1815 | return 0; /* NOP */ | 1850 | return 0; /* NOP */ |
1816 | case UAC_MIXER_UNIT: | 1851 | case UAC_MIXER_UNIT: |
1817 | return parse_audio_mixer_unit(state, unitid, p1); | 1852 | return parse_audio_mixer_unit(state, unitid, p1); |
1818 | case UAC_SELECTOR_UNIT: | 1853 | case UAC_SELECTOR_UNIT: |
1854 | case UAC2_CLOCK_SELECTOR: | ||
1819 | return parse_audio_selector_unit(state, unitid, p1); | 1855 | return parse_audio_selector_unit(state, unitid, p1); |
1820 | case UAC_FEATURE_UNIT: | 1856 | case UAC_FEATURE_UNIT: |
1821 | return parse_audio_feature_unit(state, unitid, p1); | 1857 | return parse_audio_feature_unit(state, unitid, p1); |
@@ -1912,6 +1948,11 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) | |||
1912 | err = parse_audio_unit(&state, desc->bSourceID); | 1948 | err = parse_audio_unit(&state, desc->bSourceID); |
1913 | if (err < 0) | 1949 | if (err < 0) |
1914 | return err; | 1950 | return err; |
1951 | |||
1952 | /* for UAC2, use the same approach to also add the clock selectors */ | ||
1953 | err = parse_audio_unit(&state, desc->bCSourceID); | ||
1954 | if (err < 0) | ||
1955 | return err; | ||
1915 | } | 1956 | } |
1916 | } | 1957 | } |
1917 | 1958 | ||
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index 130123854a6..a7cf1007fbb 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h | |||
@@ -34,6 +34,8 @@ struct usb_mixer_elem_info { | |||
34 | unsigned int id; | 34 | unsigned int id; |
35 | unsigned int control; /* CS or ICN (high byte) */ | 35 | unsigned int control; /* CS or ICN (high byte) */ |
36 | unsigned int cmask; /* channel mask bitmap: 0 = master */ | 36 | unsigned int cmask; /* channel mask bitmap: 0 = master */ |
37 | unsigned int ch_readonly; | ||
38 | unsigned int master_readonly; | ||
37 | int channels; | 39 | int channels; |
38 | int val_type; | 40 | int val_type; |
39 | int min, max, res; | 41 | int min, max, res; |
diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index d93fc89beba..f1324c42383 100644 --- a/sound/usb/mixer_maps.c +++ b/sound/usb/mixer_maps.c | |||
@@ -85,8 +85,8 @@ static struct usbmix_name_map extigy_map[] = { | |||
85 | /* 16: MU (w/o controls) */ | 85 | /* 16: MU (w/o controls) */ |
86 | { 17, NULL, 1 }, /* DISABLED: PU-switch (any effect?) */ | 86 | { 17, NULL, 1 }, /* DISABLED: PU-switch (any effect?) */ |
87 | { 17, "Channel Routing", 2 }, /* PU: mode select */ | 87 | { 17, "Channel Routing", 2 }, /* PU: mode select */ |
88 | { 18, "Tone Control - Bass", UAC_BASS_CONTROL }, /* FU */ | 88 | { 18, "Tone Control - Bass", UAC_FU_BASS }, /* FU */ |
89 | { 18, "Tone Control - Treble", UAC_TREBLE_CONTROL }, /* FU */ | 89 | { 18, "Tone Control - Treble", UAC_FU_TREBLE }, /* FU */ |
90 | { 18, "Master Playback" }, /* FU; others */ | 90 | { 18, "Master Playback" }, /* FU; others */ |
91 | /* 19: OT speaker */ | 91 | /* 19: OT speaker */ |
92 | /* 20: OT headphone */ | 92 | /* 20: OT headphone */ |
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 056587de7be..456829882f4 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include "urb.h" | 31 | #include "urb.h" |
32 | #include "helper.h" | 32 | #include "helper.h" |
33 | #include "pcm.h" | 33 | #include "pcm.h" |
34 | #include "clock.h" | ||
34 | 35 | ||
35 | /* | 36 | /* |
36 | * return the current pcm pointer. just based on the hwptr_done value. | 37 | * 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 | return -EINVAL; | 182 | return -EINVAL; |
182 | } | 183 | } |
183 | 184 | ||
184 | static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, | ||
185 | struct usb_host_interface *alts, | ||
186 | struct audioformat *fmt, int rate) | ||
187 | { | ||
188 | struct usb_device *dev = chip->dev; | ||
189 | unsigned int ep; | ||
190 | unsigned char data[3]; | ||
191 | int err, crate; | ||
192 | |||
193 | ep = get_endpoint(alts, 0)->bEndpointAddress; | ||
194 | /* if endpoint doesn't have sampling rate control, bail out */ | ||
195 | if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE)) { | ||
196 | snd_printk(KERN_WARNING "%d:%d:%d: endpoint lacks sample rate attribute bit, cannot set.\n", | ||
197 | dev->devnum, iface, fmt->altsetting); | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | data[0] = rate; | ||
202 | data[1] = rate >> 8; | ||
203 | data[2] = rate >> 16; | ||
204 | if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, | ||
205 | USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, | ||
206 | UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, | ||
207 | data, sizeof(data), 1000)) < 0) { | ||
208 | snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n", | ||
209 | dev->devnum, iface, fmt->altsetting, rate, ep); | ||
210 | return err; | ||
211 | } | ||
212 | if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, | ||
213 | USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN, | ||
214 | UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, | ||
215 | data, sizeof(data), 1000)) < 0) { | ||
216 | snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n", | ||
217 | dev->devnum, iface, fmt->altsetting, ep); | ||
218 | return 0; /* some devices don't support reading */ | ||
219 | } | ||
220 | crate = data[0] | (data[1] << 8) | (data[2] << 16); | ||
221 | if (crate != rate) { | ||
222 | snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate); | ||
223 | // runtime->rate = crate; | ||
224 | } | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface, | ||
230 | struct usb_host_interface *alts, | ||
231 | struct audioformat *fmt, int rate) | ||
232 | { | ||
233 | struct usb_device *dev = chip->dev; | ||
234 | unsigned char data[4]; | ||
235 | int err, crate; | ||
236 | |||
237 | data[0] = rate; | ||
238 | data[1] = rate >> 8; | ||
239 | data[2] = rate >> 16; | ||
240 | data[3] = rate >> 24; | ||
241 | if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, | ||
242 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, | ||
243 | UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8, | ||
244 | data, sizeof(data), 1000)) < 0) { | ||
245 | snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2)\n", | ||
246 | dev->devnum, iface, fmt->altsetting, rate); | ||
247 | return err; | ||
248 | } | ||
249 | if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, | ||
250 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | ||
251 | UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8, | ||
252 | data, sizeof(data), 1000)) < 0) { | ||
253 | snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n", | ||
254 | dev->devnum, iface, fmt->altsetting); | ||
255 | return err; | ||
256 | } | ||
257 | crate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); | ||
258 | if (crate != rate) | ||
259 | snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate); | ||
260 | |||
261 | return 0; | ||
262 | } | ||
263 | |||
264 | int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, | ||
265 | struct usb_host_interface *alts, | ||
266 | struct audioformat *fmt, int rate) | ||
267 | { | ||
268 | struct usb_interface_descriptor *altsd = get_iface_desc(alts); | ||
269 | |||
270 | switch (altsd->bInterfaceProtocol) { | ||
271 | case UAC_VERSION_1: | ||
272 | return set_sample_rate_v1(chip, iface, alts, fmt, rate); | ||
273 | |||
274 | case UAC_VERSION_2: | ||
275 | return set_sample_rate_v2(chip, iface, alts, fmt, rate); | ||
276 | } | ||
277 | |||
278 | return -EINVAL; | ||
279 | } | ||
280 | |||
281 | /* | 185 | /* |
282 | * find a matching format and set up the interface | 186 | * find a matching format and set up the interface |
283 | */ | 187 | */ |
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 06ebf24d3a4..24d3319cc34 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h | |||
@@ -40,9 +40,6 @@ struct snd_usb_audio { | |||
40 | int num_interfaces; | 40 | int num_interfaces; |
41 | int num_suspended_intf; | 41 | int num_suspended_intf; |
42 | 42 | ||
43 | /* for audio class v2 */ | ||
44 | int clock_id; | ||
45 | |||
46 | struct list_head pcm_list; /* list of pcm streams */ | 43 | struct list_head pcm_list; /* list of pcm streams */ |
47 | int pcm_devs; | 44 | int pcm_devs; |
48 | 45 | ||
@@ -53,6 +50,8 @@ struct snd_usb_audio { | |||
53 | int setup; /* from the 'device_setup' module param */ | 50 | int setup; /* from the 'device_setup' module param */ |
54 | int nrpacks; /* from the 'nrpacks' module param */ | 51 | int nrpacks; /* from the 'nrpacks' module param */ |
55 | int async_unlink; /* from the 'async_unlink' module param */ | 52 | int async_unlink; /* from the 'async_unlink' module param */ |
53 | |||
54 | struct usb_host_interface *ctrl_intf; /* the audio control interface */ | ||
56 | }; | 55 | }; |
57 | 56 | ||
58 | /* | 57 | /* |