diff options
158 files changed, 7098 insertions, 2325 deletions
diff --git a/Documentation/sound/alsa/ALSA-Configuration.txt b/Documentation/sound/alsa/ALSA-Configuration.txt index 8923597bd2bd..33df82e3a398 100644 --- a/Documentation/sound/alsa/ALSA-Configuration.txt +++ b/Documentation/sound/alsa/ALSA-Configuration.txt | |||
| @@ -482,6 +482,9 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
| 482 | 482 | ||
| 483 | reference_rate - reference sample rate, 44100 or 48000 (default) | 483 | reference_rate - reference sample rate, 44100 or 48000 (default) |
| 484 | multiple - multiple to ref. sample rate, 1 or 2 (default) | 484 | multiple - multiple to ref. sample rate, 1 or 2 (default) |
| 485 | subsystem - override the PCI SSID for probing; the value | ||
| 486 | consists of SSVID << 16 | SSDID. The default is | ||
| 487 | zero, which means no override. | ||
| 485 | 488 | ||
| 486 | This module supports multiple cards. | 489 | This module supports multiple cards. |
| 487 | 490 | ||
| @@ -1123,6 +1126,21 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
| 1123 | 1126 | ||
| 1124 | This module supports multiple cards, autoprobe and ISA PnP. | 1127 | This module supports multiple cards, autoprobe and ISA PnP. |
| 1125 | 1128 | ||
| 1129 | Module snd-jazz16 | ||
| 1130 | ------------------- | ||
| 1131 | |||
| 1132 | Module for Media Vision Jazz16 chipset. The chipset consists of 3 chips: | ||
| 1133 | MVD1216 + MVA416 + MVA514. | ||
| 1134 | |||
| 1135 | port - port # for SB DSP chip (0x210,0x220,0x230,0x240,0x250,0x260) | ||
| 1136 | irq - IRQ # for SB DSP chip (3,5,7,9,10,15) | ||
| 1137 | dma8 - DMA # for SB DSP chip (1,3) | ||
| 1138 | dma16 - DMA # for SB DSP chip (5,7) | ||
| 1139 | mpu_port - MPU-401 port # (0x300,0x310,0x320,0x330) | ||
| 1140 | mpu_irq - MPU-401 irq # (2,3,5,7) | ||
| 1141 | |||
| 1142 | This module supports multiple cards. | ||
| 1143 | |||
| 1126 | Module snd-korg1212 | 1144 | Module snd-korg1212 |
| 1127 | ------------------- | 1145 | ------------------- |
| 1128 | 1146 | ||
| @@ -1791,6 +1809,13 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
| 1791 | 1809 | ||
| 1792 | The power-management is supported. | 1810 | The power-management is supported. |
| 1793 | 1811 | ||
| 1812 | Module snd-ua101 | ||
| 1813 | ---------------- | ||
| 1814 | |||
| 1815 | Module for the Edirol UA-101 audio/MIDI interface. | ||
| 1816 | |||
| 1817 | This module supports multiple devices, autoprobe and hotplugging. | ||
| 1818 | |||
| 1794 | Module snd-usb-audio | 1819 | Module snd-usb-audio |
| 1795 | -------------------- | 1820 | -------------------- |
| 1796 | 1821 | ||
| @@ -1923,7 +1948,7 @@ Prior to version 0.9.0rc4 options had a 'snd_' prefix. This was removed. | |||
| 1923 | ------------------- | 1948 | ------------------- |
| 1924 | 1949 | ||
| 1925 | Module for sound cards based on the Asus AV100/AV200 chips, | 1950 | Module for sound cards based on the Asus AV100/AV200 chips, |
| 1926 | i.e., Xonar D1, DX, D2, D2X, HDAV1.3 (Deluxe), Essence ST | 1951 | i.e., Xonar D1, DX, D2, D2X, DS, HDAV1.3 (Deluxe), Essence ST |
| 1927 | (Deluxe) and Essence STX. | 1952 | (Deluxe) and Essence STX. |
| 1928 | 1953 | ||
| 1929 | This module supports autoprobe and multiple cards. | 1954 | This module supports autoprobe and multiple cards. |
diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c index df77f6131c73..f1e3aad76c37 100644 --- a/drivers/usb/gadget/f_audio.c +++ b/drivers/usb/gadget/f_audio.c | |||
| @@ -60,7 +60,7 @@ DECLARE_UAC_AC_HEADER_DESCRIPTOR(2); | |||
| 60 | #define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH + UAC_DT_INPUT_TERMINAL_SIZE \ | 60 | #define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH + UAC_DT_INPUT_TERMINAL_SIZE \ |
| 61 | + UAC_DT_OUTPUT_TERMINAL_SIZE + UAC_DT_FEATURE_UNIT_SIZE(0)) | 61 | + UAC_DT_OUTPUT_TERMINAL_SIZE + UAC_DT_FEATURE_UNIT_SIZE(0)) |
| 62 | /* B.3.2 Class-Specific AC Interface Descriptor */ | 62 | /* B.3.2 Class-Specific AC Interface Descriptor */ |
| 63 | static struct uac_ac_header_descriptor_2 ac_header_desc = { | 63 | static struct uac_ac_header_descriptor_v1_2 ac_header_desc = { |
| 64 | .bLength = UAC_DT_AC_HEADER_LENGTH, | 64 | .bLength = UAC_DT_AC_HEADER_LENGTH, |
| 65 | .bDescriptorType = USB_DT_CS_INTERFACE, | 65 | .bDescriptorType = USB_DT_CS_INTERFACE, |
| 66 | .bDescriptorSubtype = UAC_HEADER, | 66 | .bDescriptorSubtype = UAC_HEADER, |
| @@ -124,7 +124,7 @@ static struct usb_audio_control_selector feature_unit = { | |||
| 124 | }; | 124 | }; |
| 125 | 125 | ||
| 126 | #define OUTPUT_TERMINAL_ID 3 | 126 | #define OUTPUT_TERMINAL_ID 3 |
| 127 | static struct uac_output_terminal_descriptor output_terminal_desc = { | 127 | static struct uac_output_terminal_descriptor_v1 output_terminal_desc = { |
| 128 | .bLength = UAC_DT_OUTPUT_TERMINAL_SIZE, | 128 | .bLength = UAC_DT_OUTPUT_TERMINAL_SIZE, |
| 129 | .bDescriptorType = USB_DT_CS_INTERFACE, | 129 | .bDescriptorType = USB_DT_CS_INTERFACE, |
| 130 | .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, | 130 | .bDescriptorSubtype = UAC_OUTPUT_TERMINAL, |
| @@ -154,7 +154,7 @@ static struct usb_interface_descriptor as_interface_alt_1_desc = { | |||
| 154 | }; | 154 | }; |
| 155 | 155 | ||
| 156 | /* B.4.2 Class-Specific AS Interface Descriptor */ | 156 | /* B.4.2 Class-Specific AS Interface Descriptor */ |
| 157 | static struct uac_as_header_descriptor as_header_desc = { | 157 | static struct uac_as_header_descriptor_v1 as_header_desc = { |
| 158 | .bLength = UAC_DT_AS_HEADER_SIZE, | 158 | .bLength = UAC_DT_AS_HEADER_SIZE, |
| 159 | .bDescriptorType = USB_DT_CS_INTERFACE, | 159 | .bDescriptorType = USB_DT_CS_INTERFACE, |
| 160 | .bDescriptorSubtype = UAC_AS_GENERAL, | 160 | .bDescriptorSubtype = UAC_AS_GENERAL, |
diff --git a/drivers/usb/gadget/gmidi.c b/drivers/usb/gadget/gmidi.c index d0b1e836f0e0..5f6a2e0a9357 100644 --- a/drivers/usb/gadget/gmidi.c +++ b/drivers/usb/gadget/gmidi.c | |||
| @@ -237,7 +237,7 @@ static const struct usb_interface_descriptor ac_interface_desc = { | |||
| 237 | }; | 237 | }; |
| 238 | 238 | ||
| 239 | /* B.3.2 Class-Specific AC Interface Descriptor */ | 239 | /* B.3.2 Class-Specific AC Interface Descriptor */ |
| 240 | static const struct uac_ac_header_descriptor_1 ac_header_desc = { | 240 | static const struct uac_ac_header_descriptor_v1_1 ac_header_desc = { |
| 241 | .bLength = UAC_DT_AC_HEADER_SIZE(1), | 241 | .bLength = UAC_DT_AC_HEADER_SIZE(1), |
| 242 | .bDescriptorType = USB_DT_CS_INTERFACE, | 242 | .bDescriptorType = USB_DT_CS_INTERFACE, |
| 243 | .bDescriptorSubtype = USB_MS_HEADER, | 243 | .bDescriptorSubtype = USB_MS_HEADER, |
diff --git a/include/linux/usb/audio.h b/include/linux/usb/audio.h index eaf9dffe0a01..6bb293684eb8 100644 --- a/include/linux/usb/audio.h +++ b/include/linux/usb/audio.h | |||
| @@ -25,6 +25,9 @@ | |||
| 25 | #define USB_SUBCLASS_AUDIOSTREAMING 0x02 | 25 | #define USB_SUBCLASS_AUDIOSTREAMING 0x02 |
| 26 | #define USB_SUBCLASS_MIDISTREAMING 0x03 | 26 | #define USB_SUBCLASS_MIDISTREAMING 0x03 |
| 27 | 27 | ||
| 28 | #define UAC_VERSION_1 0x00 | ||
| 29 | #define UAC_VERSION_2 0x20 | ||
| 30 | |||
| 28 | /* A.5 Audio Class-Specific AC Interface Descriptor Subtypes */ | 31 | /* A.5 Audio Class-Specific AC Interface Descriptor Subtypes */ |
| 29 | #define UAC_HEADER 0x01 | 32 | #define UAC_HEADER 0x01 |
| 30 | #define UAC_INPUT_TERMINAL 0x02 | 33 | #define UAC_INPUT_TERMINAL 0x02 |
| @@ -32,8 +35,17 @@ | |||
| 32 | #define UAC_MIXER_UNIT 0x04 | 35 | #define UAC_MIXER_UNIT 0x04 |
| 33 | #define UAC_SELECTOR_UNIT 0x05 | 36 | #define UAC_SELECTOR_UNIT 0x05 |
| 34 | #define UAC_FEATURE_UNIT 0x06 | 37 | #define UAC_FEATURE_UNIT 0x06 |
| 35 | #define UAC_PROCESSING_UNIT 0x07 | 38 | #define UAC_PROCESSING_UNIT_V1 0x07 |
| 36 | #define UAC_EXTENSION_UNIT 0x08 | 39 | #define UAC_EXTENSION_UNIT_V1 0x08 |
| 40 | |||
| 41 | /* UAC v2.0 types */ | ||
| 42 | #define UAC_EFFECT_UNIT 0x07 | ||
| 43 | #define UAC_PROCESSING_UNIT_V2 0x08 | ||
| 44 | #define UAC_EXTENSION_UNIT_V2 0x09 | ||
| 45 | #define UAC_CLOCK_SOURCE 0x0a | ||
| 46 | #define UAC_CLOCK_SELECTOR 0x0b | ||
| 47 | #define UAC_CLOCK_MULTIPLIER 0x0c | ||
| 48 | #define UAC_SAMPLE_RATE_CONVERTER 0x0d | ||
| 37 | 49 | ||
| 38 | /* A.6 Audio Class-Specific AS Interface Descriptor Subtypes */ | 50 | /* A.6 Audio Class-Specific AS Interface Descriptor Subtypes */ |
| 39 | #define UAC_AS_GENERAL 0x01 | 51 | #define UAC_AS_GENERAL 0x01 |
| @@ -66,6 +78,10 @@ | |||
| 66 | 78 | ||
| 67 | #define UAC_GET_STAT 0xff | 79 | #define UAC_GET_STAT 0xff |
| 68 | 80 | ||
| 81 | /* Audio class v2.0 handles all the parameter calls differently */ | ||
| 82 | #define UAC2_CS_CUR 0x01 | ||
| 83 | #define UAC2_CS_RANGE 0x02 | ||
| 84 | |||
| 69 | /* MIDI - A.1 MS Class-Specific Interface Descriptor Subtypes */ | 85 | /* MIDI - A.1 MS Class-Specific Interface Descriptor Subtypes */ |
| 70 | #define UAC_MS_HEADER 0x01 | 86 | #define UAC_MS_HEADER 0x01 |
| 71 | #define UAC_MIDI_IN_JACK 0x02 | 87 | #define UAC_MIDI_IN_JACK 0x02 |
| @@ -81,7 +97,7 @@ | |||
| 81 | 97 | ||
| 82 | /* Terminal Control Selectors */ | 98 | /* Terminal Control Selectors */ |
| 83 | /* 4.3.2 Class-Specific AC Interface Descriptor */ | 99 | /* 4.3.2 Class-Specific AC Interface Descriptor */ |
| 84 | struct uac_ac_header_descriptor { | 100 | struct uac_ac_header_descriptor_v1 { |
| 85 | __u8 bLength; /* 8 + n */ | 101 | __u8 bLength; /* 8 + n */ |
| 86 | __u8 bDescriptorType; /* USB_DT_CS_INTERFACE */ | 102 | __u8 bDescriptorType; /* USB_DT_CS_INTERFACE */ |
| 87 | __u8 bDescriptorSubtype; /* UAC_MS_HEADER */ | 103 | __u8 bDescriptorSubtype; /* UAC_MS_HEADER */ |
| @@ -95,7 +111,7 @@ struct uac_ac_header_descriptor { | |||
| 95 | 111 | ||
| 96 | /* As above, but more useful for defining your own descriptors: */ | 112 | /* As above, but more useful for defining your own descriptors: */ |
| 97 | #define DECLARE_UAC_AC_HEADER_DESCRIPTOR(n) \ | 113 | #define DECLARE_UAC_AC_HEADER_DESCRIPTOR(n) \ |
| 98 | struct uac_ac_header_descriptor_##n { \ | 114 | struct uac_ac_header_descriptor_v1_##n { \ |
| 99 | __u8 bLength; \ | 115 | __u8 bLength; \ |
| 100 | __u8 bDescriptorType; \ | 116 | __u8 bDescriptorType; \ |
| 101 | __u8 bDescriptorSubtype; \ | 117 | __u8 bDescriptorSubtype; \ |
| @@ -130,8 +146,12 @@ struct uac_input_terminal_descriptor { | |||
| 130 | #define UAC_INPUT_TERMINAL_MICROPHONE_ARRAY 0x205 | 146 | #define UAC_INPUT_TERMINAL_MICROPHONE_ARRAY 0x205 |
| 131 | #define UAC_INPUT_TERMINAL_PROC_MICROPHONE_ARRAY 0x206 | 147 | #define UAC_INPUT_TERMINAL_PROC_MICROPHONE_ARRAY 0x206 |
| 132 | 148 | ||
| 149 | /* Terminals - control selectors */ | ||
| 150 | |||
| 151 | #define UAC_TERMINAL_CS_COPY_PROTECT_CONTROL 0x01 | ||
| 152 | |||
| 133 | /* 4.3.2.2 Output Terminal Descriptor */ | 153 | /* 4.3.2.2 Output Terminal Descriptor */ |
| 134 | struct uac_output_terminal_descriptor { | 154 | struct uac_output_terminal_descriptor_v1 { |
| 135 | __u8 bLength; /* in bytes: 9 */ | 155 | __u8 bLength; /* in bytes: 9 */ |
| 136 | __u8 bDescriptorType; /* CS_INTERFACE descriptor type */ | 156 | __u8 bDescriptorType; /* CS_INTERFACE descriptor type */ |
| 137 | __u8 bDescriptorSubtype; /* OUTPUT_TERMINAL descriptor subtype */ | 157 | __u8 bDescriptorSubtype; /* OUTPUT_TERMINAL descriptor subtype */ |
| @@ -171,7 +191,7 @@ struct uac_feature_unit_descriptor_##ch { \ | |||
| 171 | } __attribute__ ((packed)) | 191 | } __attribute__ ((packed)) |
| 172 | 192 | ||
| 173 | /* 4.5.2 Class-Specific AS Interface Descriptor */ | 193 | /* 4.5.2 Class-Specific AS Interface Descriptor */ |
| 174 | struct uac_as_header_descriptor { | 194 | struct uac_as_header_descriptor_v1 { |
| 175 | __u8 bLength; /* in bytes: 7 */ | 195 | __u8 bLength; /* in bytes: 7 */ |
| 176 | __u8 bDescriptorType; /* USB_DT_CS_INTERFACE */ | 196 | __u8 bDescriptorType; /* USB_DT_CS_INTERFACE */ |
| 177 | __u8 bDescriptorSubtype; /* AS_GENERAL */ | 197 | __u8 bDescriptorSubtype; /* AS_GENERAL */ |
| @@ -180,6 +200,19 @@ struct uac_as_header_descriptor { | |||
| 180 | __le16 wFormatTag; /* The Audio Data Format */ | 200 | __le16 wFormatTag; /* The Audio Data Format */ |
| 181 | } __attribute__ ((packed)); | 201 | } __attribute__ ((packed)); |
| 182 | 202 | ||
| 203 | struct uac_as_header_descriptor_v2 { | ||
| 204 | __u8 bLength; | ||
| 205 | __u8 bDescriptorType; | ||
| 206 | __u8 bDescriptorSubtype; | ||
| 207 | __u8 bTerminalLink; | ||
| 208 | __u8 bmControls; | ||
| 209 | __u8 bFormatType; | ||
| 210 | __u32 bmFormats; | ||
| 211 | __u8 bNrChannels; | ||
| 212 | __u32 bmChannelConfig; | ||
| 213 | __u8 iChannelNames; | ||
| 214 | } __attribute__((packed)); | ||
| 215 | |||
| 183 | #define UAC_DT_AS_HEADER_SIZE 7 | 216 | #define UAC_DT_AS_HEADER_SIZE 7 |
| 184 | 217 | ||
| 185 | /* Formats - A.1.1 Audio Data Format Type I Codes */ | 218 | /* Formats - A.1.1 Audio Data Format Type I Codes */ |
| @@ -232,11 +265,62 @@ struct uac_format_type_i_discrete_descriptor_##n { \ | |||
| 232 | 265 | ||
| 233 | #define UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(n) (8 + (n * 3)) | 266 | #define UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(n) (8 + (n * 3)) |
| 234 | 267 | ||
| 268 | struct uac_format_type_i_ext_descriptor { | ||
| 269 | __u8 bLength; | ||
| 270 | __u8 bDescriptorType; | ||
| 271 | __u8 bDescriptorSubtype; | ||
| 272 | __u8 bSubslotSize; | ||
| 273 | __u8 bFormatType; | ||
| 274 | __u8 bBitResolution; | ||
| 275 | __u8 bHeaderLength; | ||
| 276 | __u8 bControlSize; | ||
| 277 | __u8 bSideBandProtocol; | ||
| 278 | } __attribute__((packed)); | ||
| 279 | |||
| 280 | |||
| 281 | /* Formats - Audio Data Format Type I Codes */ | ||
| 282 | |||
| 283 | #define UAC_FORMAT_TYPE_II_MPEG 0x1001 | ||
| 284 | #define UAC_FORMAT_TYPE_II_AC3 0x1002 | ||
| 285 | |||
| 286 | struct uac_format_type_ii_discrete_descriptor { | ||
| 287 | __u8 bLength; | ||
| 288 | __u8 bDescriptorType; | ||
| 289 | __u8 bDescriptorSubtype; | ||
| 290 | __u8 bFormatType; | ||
| 291 | __le16 wMaxBitRate; | ||
| 292 | __le16 wSamplesPerFrame; | ||
| 293 | __u8 bSamFreqType; | ||
| 294 | __u8 tSamFreq[][3]; | ||
| 295 | } __attribute__((packed)); | ||
| 296 | |||
| 297 | struct uac_format_type_ii_ext_descriptor { | ||
| 298 | __u8 bLength; | ||
| 299 | __u8 bDescriptorType; | ||
| 300 | __u8 bDescriptorSubtype; | ||
| 301 | __u8 bFormatType; | ||
| 302 | __u16 wMaxBitRate; | ||
| 303 | __u16 wSamplesPerFrame; | ||
| 304 | __u8 bHeaderLength; | ||
| 305 | __u8 bSideBandProtocol; | ||
| 306 | } __attribute__((packed)); | ||
| 307 | |||
| 308 | /* type III */ | ||
| 309 | #define UAC_FORMAT_TYPE_III_IEC1937_AC3 0x2001 | ||
| 310 | #define UAC_FORMAT_TYPE_III_IEC1937_MPEG1_LAYER1 0x2002 | ||
| 311 | #define UAC_FORMAT_TYPE_III_IEC1937_MPEG2_NOEXT 0x2003 | ||
| 312 | #define UAC_FORMAT_TYPE_III_IEC1937_MPEG2_EXT 0x2004 | ||
| 313 | #define UAC_FORMAT_TYPE_III_IEC1937_MPEG2_LAYER1_LS 0x2005 | ||
| 314 | #define UAC_FORMAT_TYPE_III_IEC1937_MPEG2_LAYER23_LS 0x2006 | ||
| 315 | |||
| 235 | /* Formats - A.2 Format Type Codes */ | 316 | /* Formats - A.2 Format Type Codes */ |
| 236 | #define UAC_FORMAT_TYPE_UNDEFINED 0x0 | 317 | #define UAC_FORMAT_TYPE_UNDEFINED 0x0 |
| 237 | #define UAC_FORMAT_TYPE_I 0x1 | 318 | #define UAC_FORMAT_TYPE_I 0x1 |
| 238 | #define UAC_FORMAT_TYPE_II 0x2 | 319 | #define UAC_FORMAT_TYPE_II 0x2 |
| 239 | #define UAC_FORMAT_TYPE_III 0x3 | 320 | #define UAC_FORMAT_TYPE_III 0x3 |
| 321 | #define UAC_EXT_FORMAT_TYPE_I 0x81 | ||
| 322 | #define UAC_EXT_FORMAT_TYPE_II 0x82 | ||
| 323 | #define UAC_EXT_FORMAT_TYPE_III 0x83 | ||
| 240 | 324 | ||
| 241 | struct uac_iso_endpoint_descriptor { | 325 | struct uac_iso_endpoint_descriptor { |
| 242 | __u8 bLength; /* in bytes: 7 */ | 326 | __u8 bLength; /* in bytes: 7 */ |
| @@ -252,7 +336,31 @@ struct uac_iso_endpoint_descriptor { | |||
| 252 | #define UAC_EP_CS_ATTR_PITCH_CONTROL 0x02 | 336 | #define UAC_EP_CS_ATTR_PITCH_CONTROL 0x02 |
| 253 | #define UAC_EP_CS_ATTR_FILL_MAX 0x80 | 337 | #define UAC_EP_CS_ATTR_FILL_MAX 0x80 |
| 254 | 338 | ||
| 339 | /* Audio class v2.0: CLOCK_SOURCE descriptor */ | ||
| 340 | |||
| 341 | struct uac_clock_source_descriptor { | ||
| 342 | __u8 bLength; | ||
| 343 | __u8 bDescriptorType; | ||
| 344 | __u8 bDescriptorSubtype; | ||
| 345 | __u8 bClockID; | ||
| 346 | __u8 bmAttributes; | ||
| 347 | __u8 bmControls; | ||
| 348 | __u8 bAssocTerminal; | ||
| 349 | __u8 iClockSource; | ||
| 350 | } __attribute__((packed)); | ||
| 351 | |||
| 255 | /* A.10.2 Feature Unit Control Selectors */ | 352 | /* A.10.2 Feature Unit Control Selectors */ |
| 353 | |||
| 354 | struct uac_feature_unit_descriptor { | ||
| 355 | __u8 bLength; | ||
| 356 | __u8 bDescriptorType; | ||
| 357 | __u8 bDescriptorSubtype; | ||
| 358 | __u8 bUnitID; | ||
| 359 | __u8 bSourceID; | ||
| 360 | __u8 bControlSize; | ||
| 361 | __u8 controls[0]; /* variable length */ | ||
| 362 | } __attribute__((packed)); | ||
| 363 | |||
| 256 | #define UAC_FU_CONTROL_UNDEFINED 0x00 | 364 | #define UAC_FU_CONTROL_UNDEFINED 0x00 |
| 257 | #define UAC_MUTE_CONTROL 0x01 | 365 | #define UAC_MUTE_CONTROL 0x01 |
| 258 | #define UAC_VOLUME_CONTROL 0x02 | 366 | #define UAC_VOLUME_CONTROL 0x02 |
diff --git a/include/sound/core.h b/include/sound/core.h index a61499c22b0b..89e0ac17f44a 100644 --- a/include/sound/core.h +++ b/include/sound/core.h | |||
| @@ -458,5 +458,8 @@ struct snd_pci_quirk { | |||
| 458 | const struct snd_pci_quirk * | 458 | const struct snd_pci_quirk * |
| 459 | snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list); | 459 | snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list); |
| 460 | 460 | ||
| 461 | const struct snd_pci_quirk * | ||
| 462 | snd_pci_quirk_lookup_id(u16 vendor, u16 device, | ||
| 463 | const struct snd_pci_quirk *list); | ||
| 461 | 464 | ||
| 462 | #endif /* __SOUND_CORE_H */ | 465 | #endif /* __SOUND_CORE_H */ |
diff --git a/include/sound/cs46xx_dsp_spos.h b/include/sound/cs46xx_dsp_spos.h index 7c44667e79a6..49b03c9e5e55 100644 --- a/include/sound/cs46xx_dsp_spos.h +++ b/include/sound/cs46xx_dsp_spos.h | |||
| @@ -118,9 +118,11 @@ struct dsp_scb_descriptor { | |||
| 118 | 118 | ||
| 119 | struct snd_info_entry *proc_info; | 119 | struct snd_info_entry *proc_info; |
| 120 | int ref_count; | 120 | int ref_count; |
| 121 | spinlock_t lock; | ||
| 122 | 121 | ||
| 123 | int deleted; | 122 | u16 volume[2]; |
| 123 | unsigned int deleted :1; | ||
| 124 | unsigned int updated :1; | ||
| 125 | unsigned int volume_set :1; | ||
| 124 | }; | 126 | }; |
| 125 | 127 | ||
| 126 | struct dsp_task_descriptor { | 128 | struct dsp_task_descriptor { |
diff --git a/include/sound/pcm.h b/include/sound/pcm.h index c83a4a79f16b..8b611a561985 100644 --- a/include/sound/pcm.h +++ b/include/sound/pcm.h | |||
| @@ -262,6 +262,8 @@ struct snd_pcm_hw_constraint_list { | |||
| 262 | unsigned int mask; | 262 | unsigned int mask; |
| 263 | }; | 263 | }; |
| 264 | 264 | ||
| 265 | struct snd_pcm_hwptr_log; | ||
| 266 | |||
| 265 | struct snd_pcm_runtime { | 267 | struct snd_pcm_runtime { |
| 266 | /* -- Status -- */ | 268 | /* -- Status -- */ |
| 267 | struct snd_pcm_substream *trigger_master; | 269 | struct snd_pcm_substream *trigger_master; |
| @@ -310,7 +312,9 @@ struct snd_pcm_runtime { | |||
| 310 | struct snd_pcm_mmap_control *control; | 312 | struct snd_pcm_mmap_control *control; |
| 311 | 313 | ||
| 312 | /* -- locking / scheduling -- */ | 314 | /* -- locking / scheduling -- */ |
| 313 | wait_queue_head_t sleep; | 315 | unsigned int twake: 1; /* do transfer (!poll) wakeup */ |
| 316 | wait_queue_head_t sleep; /* poll sleep */ | ||
| 317 | wait_queue_head_t tsleep; /* transfer sleep */ | ||
| 314 | struct fasync_struct *fasync; | 318 | struct fasync_struct *fasync; |
| 315 | 319 | ||
| 316 | /* -- private section -- */ | 320 | /* -- private section -- */ |
| @@ -340,6 +344,10 @@ struct snd_pcm_runtime { | |||
| 340 | /* -- OSS things -- */ | 344 | /* -- OSS things -- */ |
| 341 | struct snd_pcm_oss_runtime oss; | 345 | struct snd_pcm_oss_runtime oss; |
| 342 | #endif | 346 | #endif |
| 347 | |||
| 348 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG | ||
| 349 | struct snd_pcm_hwptr_log *hwptr_log; | ||
| 350 | #endif | ||
| 343 | }; | 351 | }; |
| 344 | 352 | ||
| 345 | struct snd_pcm_group { /* keep linked substreams */ | 353 | struct snd_pcm_group { /* keep linked substreams */ |
| @@ -834,6 +842,8 @@ void snd_pcm_set_sync(struct snd_pcm_substream *substream); | |||
| 834 | int snd_pcm_lib_interleave_len(struct snd_pcm_substream *substream); | 842 | int snd_pcm_lib_interleave_len(struct snd_pcm_substream *substream); |
| 835 | int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, | 843 | int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream, |
| 836 | unsigned int cmd, void *arg); | 844 | unsigned int cmd, void *arg); |
| 845 | int snd_pcm_update_state(struct snd_pcm_substream *substream, | ||
| 846 | struct snd_pcm_runtime *runtime); | ||
| 837 | int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream); | 847 | int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream); |
| 838 | int snd_pcm_playback_xrun_check(struct snd_pcm_substream *substream); | 848 | int snd_pcm_playback_xrun_check(struct snd_pcm_substream *substream); |
| 839 | int snd_pcm_capture_xrun_check(struct snd_pcm_substream *substream); | 849 | int snd_pcm_capture_xrun_check(struct snd_pcm_substream *substream); |
| @@ -905,6 +915,44 @@ int snd_pcm_lib_preallocate_pages_for_all(struct snd_pcm *pcm, | |||
| 905 | int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size); | 915 | int snd_pcm_lib_malloc_pages(struct snd_pcm_substream *substream, size_t size); |
| 906 | int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream); | 916 | int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream); |
| 907 | 917 | ||
| 918 | int _snd_pcm_lib_alloc_vmalloc_buffer(struct snd_pcm_substream *substream, | ||
| 919 | size_t size, gfp_t gfp_flags); | ||
| 920 | int snd_pcm_lib_free_vmalloc_buffer(struct snd_pcm_substream *substream); | ||
| 921 | struct page *snd_pcm_lib_get_vmalloc_page(struct snd_pcm_substream *substream, | ||
| 922 | unsigned long offset); | ||
| 923 | #if 0 /* for kernel-doc */ | ||
| 924 | /** | ||
| 925 | * snd_pcm_lib_alloc_vmalloc_buffer - allocate virtual DMA buffer | ||
| 926 | * @substream: the substream to allocate the buffer to | ||
| 927 | * @size: the requested buffer size, in bytes | ||
| 928 | * | ||
| 929 | * Allocates the PCM substream buffer using vmalloc(), i.e., the memory is | ||
| 930 | * contiguous in kernel virtual space, but not in physical memory. Use this | ||
| 931 | * if the buffer is accessed by kernel code but not by device DMA. | ||
| 932 | * | ||
| 933 | * Returns 1 if the buffer was changed, 0 if not changed, or a negative error | ||
| 934 | * code. | ||
| 935 | */ | ||
| 936 | static int snd_pcm_lib_alloc_vmalloc_buffer | ||
| 937 | (struct snd_pcm_substream *substream, size_t size); | ||
| 938 | /** | ||
| 939 | * snd_pcm_lib_alloc_vmalloc_32_buffer - allocate 32-bit-addressable buffer | ||
| 940 | * @substream: the substream to allocate the buffer to | ||
| 941 | * @size: the requested buffer size, in bytes | ||
| 942 | * | ||
| 943 | * This function works like snd_pcm_lib_alloc_vmalloc_buffer(), but uses | ||
| 944 | * vmalloc_32(), i.e., the pages are allocated from 32-bit-addressable memory. | ||
| 945 | */ | ||
| 946 | static int snd_pcm_lib_alloc_vmalloc_32_buffer | ||
| 947 | (struct snd_pcm_substream *substream, size_t size); | ||
| 948 | #endif | ||
| 949 | #define snd_pcm_lib_alloc_vmalloc_buffer(subs, size) \ | ||
| 950 | _snd_pcm_lib_alloc_vmalloc_buffer \ | ||
| 951 | (subs, size, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO) | ||
| 952 | #define snd_pcm_lib_alloc_vmalloc_32_buffer(subs, size) \ | ||
| 953 | _snd_pcm_lib_alloc_vmalloc_buffer \ | ||
| 954 | (subs, size, GFP_KERNEL | GFP_DMA32 | __GFP_ZERO) | ||
| 955 | |||
| 908 | #ifdef CONFIG_SND_DMA_SGBUF | 956 | #ifdef CONFIG_SND_DMA_SGBUF |
| 909 | /* | 957 | /* |
| 910 | * SG-buffer handling | 958 | * SG-buffer handling |
| @@ -975,6 +1023,10 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, struct vm_area_s | |||
| 975 | #define snd_pcm_lib_mmap_iomem NULL | 1023 | #define snd_pcm_lib_mmap_iomem NULL |
| 976 | #endif | 1024 | #endif |
| 977 | 1025 | ||
| 1026 | int snd_pcm_lib_mmap_noncached(struct snd_pcm_substream *substream, | ||
| 1027 | struct vm_area_struct *area); | ||
| 1028 | #define snd_pcm_lib_mmap_vmalloc snd_pcm_lib_mmap_noncached | ||
| 1029 | |||
| 978 | static inline void snd_pcm_limit_isa_dma_size(int dma, size_t *max) | 1030 | static inline void snd_pcm_limit_isa_dma_size(int dma, size_t *max) |
| 979 | { | 1031 | { |
| 980 | *max = dma < 4 ? 64 * 1024 : 128 * 1024; | 1032 | *max = dma < 4 ? 64 * 1024 : 128 * 1024; |
diff --git a/include/sound/pcm_oss.h b/include/sound/pcm_oss.h index cc4e226f35fd..760c969d885d 100644 --- a/include/sound/pcm_oss.h +++ b/include/sound/pcm_oss.h | |||
| @@ -61,7 +61,7 @@ struct snd_pcm_oss_runtime { | |||
| 61 | struct snd_pcm_plugin *plugin_first; | 61 | struct snd_pcm_plugin *plugin_first; |
| 62 | struct snd_pcm_plugin *plugin_last; | 62 | struct snd_pcm_plugin *plugin_last; |
| 63 | #endif | 63 | #endif |
| 64 | unsigned int prev_hw_ptr_interrupt; | 64 | unsigned int prev_hw_ptr_period; |
| 65 | }; | 65 | }; |
| 66 | 66 | ||
| 67 | struct snd_pcm_oss_file { | 67 | struct snd_pcm_oss_file { |
diff --git a/include/sound/sb.h b/include/sound/sb.h index 4e62ee1e4115..95353542256a 100644 --- a/include/sound/sb.h +++ b/include/sound/sb.h | |||
| @@ -33,6 +33,7 @@ enum sb_hw_type { | |||
| 33 | SB_HW_20, | 33 | SB_HW_20, |
| 34 | SB_HW_201, | 34 | SB_HW_201, |
| 35 | SB_HW_PRO, | 35 | SB_HW_PRO, |
| 36 | SB_HW_JAZZ16, /* Media Vision Jazz16 */ | ||
| 36 | SB_HW_16, | 37 | SB_HW_16, |
| 37 | SB_HW_16CSP, /* SB16 with CSP chip */ | 38 | SB_HW_16CSP, /* SB16 with CSP chip */ |
| 38 | SB_HW_ALS100, /* Avance Logic ALS100 chip */ | 39 | SB_HW_ALS100, /* Avance Logic ALS100 chip */ |
diff --git a/include/sound/version.h b/include/sound/version.h index 22939142dd23..7fed23442db8 100644 --- a/include/sound/version.h +++ b/include/sound/version.h | |||
| @@ -1,3 +1,3 @@ | |||
| 1 | /* include/version.h */ | 1 | /* include/version.h */ |
| 2 | #define CONFIG_SND_VERSION "1.0.21" | 2 | #define CONFIG_SND_VERSION "1.0.22.1" |
| 3 | #define CONFIG_SND_DATE "" | 3 | #define CONFIG_SND_DATE "" |
diff --git a/sound/core/control.c b/sound/core/control.c index 268ab7471224..439ce64f9d82 100644 --- a/sound/core/control.c +++ b/sound/core/control.c | |||
| @@ -237,8 +237,9 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol, | |||
| 237 | access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : | 237 | access = ncontrol->access == 0 ? SNDRV_CTL_ELEM_ACCESS_READWRITE : |
| 238 | (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE| | 238 | (ncontrol->access & (SNDRV_CTL_ELEM_ACCESS_READWRITE| |
| 239 | SNDRV_CTL_ELEM_ACCESS_INACTIVE| | 239 | SNDRV_CTL_ELEM_ACCESS_INACTIVE| |
| 240 | SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE| | 240 | SNDRV_CTL_ELEM_ACCESS_TLV_READWRITE| |
| 241 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)); | 241 | SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND| |
| 242 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK)); | ||
| 242 | kctl.info = ncontrol->info; | 243 | kctl.info = ncontrol->info; |
| 243 | kctl.get = ncontrol->get; | 244 | kctl.get = ncontrol->get; |
| 244 | kctl.put = ncontrol->put; | 245 | kctl.put = ncontrol->put; |
| @@ -1099,7 +1100,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file, | |||
| 1099 | 1100 | ||
| 1100 | if (copy_from_user(&tlv, _tlv, sizeof(tlv))) | 1101 | if (copy_from_user(&tlv, _tlv, sizeof(tlv))) |
| 1101 | return -EFAULT; | 1102 | return -EFAULT; |
| 1102 | if (tlv.length < sizeof(unsigned int) * 3) | 1103 | if (tlv.length < sizeof(unsigned int) * 2) |
| 1103 | return -EINVAL; | 1104 | return -EINVAL; |
| 1104 | down_read(&card->controls_rwsem); | 1105 | down_read(&card->controls_rwsem); |
| 1105 | kctl = snd_ctl_find_numid(card, tlv.numid); | 1106 | kctl = snd_ctl_find_numid(card, tlv.numid); |
diff --git a/sound/core/misc.c b/sound/core/misc.c index 23a032c6d487..3da4f92427d8 100644 --- a/sound/core/misc.c +++ b/sound/core/misc.c | |||
| @@ -101,8 +101,9 @@ EXPORT_SYMBOL_GPL(__snd_printk); | |||
| 101 | #ifdef CONFIG_PCI | 101 | #ifdef CONFIG_PCI |
| 102 | #include <linux/pci.h> | 102 | #include <linux/pci.h> |
| 103 | /** | 103 | /** |
| 104 | * snd_pci_quirk_lookup - look up a PCI SSID quirk list | 104 | * snd_pci_quirk_lookup_id - look up a PCI SSID quirk list |
| 105 | * @pci: pci_dev handle | 105 | * @vendor: PCI SSV id |
| 106 | * @device: PCI SSD id | ||
| 106 | * @list: quirk list, terminated by a null entry | 107 | * @list: quirk list, terminated by a null entry |
| 107 | * | 108 | * |
| 108 | * Look through the given quirk list and finds a matching entry | 109 | * Look through the given quirk list and finds a matching entry |
| @@ -112,18 +113,39 @@ EXPORT_SYMBOL_GPL(__snd_printk); | |||
| 112 | * Returns the matched entry pointer, or NULL if nothing matched. | 113 | * Returns the matched entry pointer, or NULL if nothing matched. |
| 113 | */ | 114 | */ |
| 114 | const struct snd_pci_quirk * | 115 | const struct snd_pci_quirk * |
| 115 | snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list) | 116 | snd_pci_quirk_lookup_id(u16 vendor, u16 device, |
| 117 | const struct snd_pci_quirk *list) | ||
| 116 | { | 118 | { |
| 117 | const struct snd_pci_quirk *q; | 119 | const struct snd_pci_quirk *q; |
| 118 | 120 | ||
| 119 | for (q = list; q->subvendor; q++) { | 121 | for (q = list; q->subvendor; q++) { |
| 120 | if (q->subvendor != pci->subsystem_vendor) | 122 | if (q->subvendor != vendor) |
| 121 | continue; | 123 | continue; |
| 122 | if (!q->subdevice || | 124 | if (!q->subdevice || |
| 123 | (pci->subsystem_device & q->subdevice_mask) == q->subdevice) | 125 | (device & q->subdevice_mask) == q->subdevice) |
| 124 | return q; | 126 | return q; |
| 125 | } | 127 | } |
| 126 | return NULL; | 128 | return NULL; |
| 127 | } | 129 | } |
| 130 | EXPORT_SYMBOL(snd_pci_quirk_lookup_id); | ||
| 131 | |||
| 132 | /** | ||
| 133 | * snd_pci_quirk_lookup - look up a PCI SSID quirk list | ||
| 134 | * @pci: pci_dev handle | ||
| 135 | * @list: quirk list, terminated by a null entry | ||
| 136 | * | ||
| 137 | * Look through the given quirk list and finds a matching entry | ||
| 138 | * with the same PCI SSID. When subdevice is 0, all subdevice | ||
| 139 | * values may match. | ||
| 140 | * | ||
| 141 | * Returns the matched entry pointer, or NULL if nothing matched. | ||
| 142 | */ | ||
| 143 | const struct snd_pci_quirk * | ||
| 144 | snd_pci_quirk_lookup(struct pci_dev *pci, const struct snd_pci_quirk *list) | ||
| 145 | { | ||
| 146 | return snd_pci_quirk_lookup_id(pci->subsystem_vendor, | ||
| 147 | pci->subsystem_device, | ||
| 148 | list); | ||
| 149 | } | ||
| 128 | EXPORT_SYMBOL(snd_pci_quirk_lookup); | 150 | EXPORT_SYMBOL(snd_pci_quirk_lookup); |
| 129 | #endif | 151 | #endif |
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index d9c96353121a..82d4e3329b3d 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c | |||
| @@ -632,6 +632,12 @@ static long snd_pcm_alsa_frames(struct snd_pcm_substream *substream, long bytes) | |||
| 632 | return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes); | 632 | return bytes_to_frames(runtime, (buffer_size * bytes) / runtime->oss.buffer_bytes); |
| 633 | } | 633 | } |
| 634 | 634 | ||
| 635 | static inline | ||
| 636 | snd_pcm_uframes_t get_hw_ptr_period(struct snd_pcm_runtime *runtime) | ||
| 637 | { | ||
| 638 | return runtime->hw_ptr_interrupt; | ||
| 639 | } | ||
| 640 | |||
| 635 | /* define extended formats in the recent OSS versions (if any) */ | 641 | /* define extended formats in the recent OSS versions (if any) */ |
| 636 | /* linear formats */ | 642 | /* linear formats */ |
| 637 | #define AFMT_S32_LE 0x00001000 | 643 | #define AFMT_S32_LE 0x00001000 |
| @@ -1102,7 +1108,7 @@ static int snd_pcm_oss_prepare(struct snd_pcm_substream *substream) | |||
| 1102 | return err; | 1108 | return err; |
| 1103 | } | 1109 | } |
| 1104 | runtime->oss.prepare = 0; | 1110 | runtime->oss.prepare = 0; |
| 1105 | runtime->oss.prev_hw_ptr_interrupt = 0; | 1111 | runtime->oss.prev_hw_ptr_period = 0; |
| 1106 | runtime->oss.period_ptr = 0; | 1112 | runtime->oss.period_ptr = 0; |
| 1107 | runtime->oss.buffer_used = 0; | 1113 | runtime->oss.buffer_used = 0; |
| 1108 | 1114 | ||
| @@ -1950,7 +1956,8 @@ static int snd_pcm_oss_get_caps(struct snd_pcm_oss_file *pcm_oss_file) | |||
| 1950 | return result; | 1956 | return result; |
| 1951 | } | 1957 | } |
| 1952 | 1958 | ||
| 1953 | static void snd_pcm_oss_simulate_fill(struct snd_pcm_substream *substream, snd_pcm_uframes_t hw_ptr) | 1959 | static void snd_pcm_oss_simulate_fill(struct snd_pcm_substream *substream, |
| 1960 | snd_pcm_uframes_t hw_ptr) | ||
| 1954 | { | 1961 | { |
| 1955 | struct snd_pcm_runtime *runtime = substream->runtime; | 1962 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 1956 | snd_pcm_uframes_t appl_ptr; | 1963 | snd_pcm_uframes_t appl_ptr; |
| @@ -1986,7 +1993,8 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr | |||
| 1986 | if (runtime->oss.trigger) | 1993 | if (runtime->oss.trigger) |
| 1987 | goto _skip1; | 1994 | goto _skip1; |
| 1988 | if (atomic_read(&psubstream->mmap_count)) | 1995 | if (atomic_read(&psubstream->mmap_count)) |
| 1989 | snd_pcm_oss_simulate_fill(psubstream, runtime->hw_ptr_interrupt); | 1996 | snd_pcm_oss_simulate_fill(psubstream, |
| 1997 | get_hw_ptr_period(runtime)); | ||
| 1990 | runtime->oss.trigger = 1; | 1998 | runtime->oss.trigger = 1; |
| 1991 | runtime->start_threshold = 1; | 1999 | runtime->start_threshold = 1; |
| 1992 | cmd = SNDRV_PCM_IOCTL_START; | 2000 | cmd = SNDRV_PCM_IOCTL_START; |
| @@ -2105,11 +2113,12 @@ static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream | |||
| 2105 | info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size); | 2113 | info.ptr = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr % runtime->buffer_size); |
| 2106 | if (atomic_read(&substream->mmap_count)) { | 2114 | if (atomic_read(&substream->mmap_count)) { |
| 2107 | snd_pcm_sframes_t n; | 2115 | snd_pcm_sframes_t n; |
| 2108 | n = (delay = runtime->hw_ptr_interrupt) - runtime->oss.prev_hw_ptr_interrupt; | 2116 | delay = get_hw_ptr_period(runtime); |
| 2117 | n = delay - runtime->oss.prev_hw_ptr_period; | ||
| 2109 | if (n < 0) | 2118 | if (n < 0) |
| 2110 | n += runtime->boundary; | 2119 | n += runtime->boundary; |
| 2111 | info.blocks = n / runtime->period_size; | 2120 | info.blocks = n / runtime->period_size; |
| 2112 | runtime->oss.prev_hw_ptr_interrupt = delay; | 2121 | runtime->oss.prev_hw_ptr_period = delay; |
| 2113 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 2122 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) |
| 2114 | snd_pcm_oss_simulate_fill(substream, delay); | 2123 | snd_pcm_oss_simulate_fill(substream, delay); |
| 2115 | info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr) & INT_MAX; | 2124 | info.bytes = snd_pcm_oss_bytes(substream, runtime->status->hw_ptr) & INT_MAX; |
| @@ -2673,18 +2682,22 @@ static int snd_pcm_oss_playback_ready(struct snd_pcm_substream *substream) | |||
| 2673 | { | 2682 | { |
| 2674 | struct snd_pcm_runtime *runtime = substream->runtime; | 2683 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 2675 | if (atomic_read(&substream->mmap_count)) | 2684 | if (atomic_read(&substream->mmap_count)) |
| 2676 | return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt; | 2685 | return runtime->oss.prev_hw_ptr_period != |
| 2686 | get_hw_ptr_period(runtime); | ||
| 2677 | else | 2687 | else |
| 2678 | return snd_pcm_playback_avail(runtime) >= runtime->oss.period_frames; | 2688 | return snd_pcm_playback_avail(runtime) >= |
| 2689 | runtime->oss.period_frames; | ||
| 2679 | } | 2690 | } |
| 2680 | 2691 | ||
| 2681 | static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream) | 2692 | static int snd_pcm_oss_capture_ready(struct snd_pcm_substream *substream) |
| 2682 | { | 2693 | { |
| 2683 | struct snd_pcm_runtime *runtime = substream->runtime; | 2694 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 2684 | if (atomic_read(&substream->mmap_count)) | 2695 | if (atomic_read(&substream->mmap_count)) |
| 2685 | return runtime->oss.prev_hw_ptr_interrupt != runtime->hw_ptr_interrupt; | 2696 | return runtime->oss.prev_hw_ptr_period != |
| 2697 | get_hw_ptr_period(runtime); | ||
| 2686 | else | 2698 | else |
| 2687 | return snd_pcm_capture_avail(runtime) >= runtime->oss.period_frames; | 2699 | return snd_pcm_capture_avail(runtime) >= |
| 2700 | runtime->oss.period_frames; | ||
| 2688 | } | 2701 | } |
| 2689 | 2702 | ||
| 2690 | static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait) | 2703 | static unsigned int snd_pcm_oss_poll(struct file *file, poll_table * wait) |
diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 6884ae031f6f..0d428d0896db 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c | |||
| @@ -894,6 +894,7 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream, | |||
| 894 | memset((void*)runtime->control, 0, size); | 894 | memset((void*)runtime->control, 0, size); |
| 895 | 895 | ||
| 896 | init_waitqueue_head(&runtime->sleep); | 896 | init_waitqueue_head(&runtime->sleep); |
| 897 | init_waitqueue_head(&runtime->tsleep); | ||
| 897 | 898 | ||
| 898 | runtime->status->state = SNDRV_PCM_STATE_OPEN; | 899 | runtime->status->state = SNDRV_PCM_STATE_OPEN; |
| 899 | 900 | ||
| @@ -921,6 +922,10 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream) | |||
| 921 | snd_free_pages((void*)runtime->control, | 922 | snd_free_pages((void*)runtime->control, |
| 922 | PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control))); | 923 | PAGE_ALIGN(sizeof(struct snd_pcm_mmap_control))); |
| 923 | kfree(runtime->hw_constraints.rules); | 924 | kfree(runtime->hw_constraints.rules); |
| 925 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG | ||
| 926 | if (runtime->hwptr_log) | ||
| 927 | kfree(runtime->hwptr_log); | ||
| 928 | #endif | ||
| 924 | kfree(runtime); | 929 | kfree(runtime); |
| 925 | substream->runtime = NULL; | 930 | substream->runtime = NULL; |
| 926 | put_pid(substream->pid); | 931 | put_pid(substream->pid); |
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index a27545b23ee9..b546ac2660f9 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c | |||
| @@ -126,17 +126,6 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram | |||
| 126 | } | 126 | } |
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG | ||
| 130 | #define xrun_debug(substream, mask) ((substream)->pstr->xrun_debug & (mask)) | ||
| 131 | #else | ||
| 132 | #define xrun_debug(substream, mask) 0 | ||
| 133 | #endif | ||
| 134 | |||
| 135 | #define dump_stack_on_xrun(substream) do { \ | ||
| 136 | if (xrun_debug(substream, 2)) \ | ||
| 137 | dump_stack(); \ | ||
| 138 | } while (0) | ||
| 139 | |||
| 140 | static void pcm_debug_name(struct snd_pcm_substream *substream, | 129 | static void pcm_debug_name(struct snd_pcm_substream *substream, |
| 141 | char *name, size_t len) | 130 | char *name, size_t len) |
| 142 | { | 131 | { |
| @@ -147,6 +136,24 @@ static void pcm_debug_name(struct snd_pcm_substream *substream, | |||
| 147 | substream->number); | 136 | substream->number); |
| 148 | } | 137 | } |
| 149 | 138 | ||
| 139 | #define XRUN_DEBUG_BASIC (1<<0) | ||
| 140 | #define XRUN_DEBUG_STACK (1<<1) /* dump also stack */ | ||
| 141 | #define XRUN_DEBUG_JIFFIESCHECK (1<<2) /* do jiffies check */ | ||
| 142 | #define XRUN_DEBUG_PERIODUPDATE (1<<3) /* full period update info */ | ||
| 143 | #define XRUN_DEBUG_HWPTRUPDATE (1<<4) /* full hwptr update info */ | ||
| 144 | #define XRUN_DEBUG_LOG (1<<5) /* show last 10 positions on err */ | ||
| 145 | #define XRUN_DEBUG_LOGONCE (1<<6) /* do above only once */ | ||
| 146 | |||
| 147 | #ifdef CONFIG_SND_PCM_XRUN_DEBUG | ||
| 148 | |||
| 149 | #define xrun_debug(substream, mask) \ | ||
| 150 | ((substream)->pstr->xrun_debug & (mask)) | ||
| 151 | |||
| 152 | #define dump_stack_on_xrun(substream) do { \ | ||
| 153 | if (xrun_debug(substream, XRUN_DEBUG_STACK)) \ | ||
| 154 | dump_stack(); \ | ||
| 155 | } while (0) | ||
| 156 | |||
| 150 | static void xrun(struct snd_pcm_substream *substream) | 157 | static void xrun(struct snd_pcm_substream *substream) |
| 151 | { | 158 | { |
| 152 | struct snd_pcm_runtime *runtime = substream->runtime; | 159 | struct snd_pcm_runtime *runtime = substream->runtime; |
| @@ -154,7 +161,7 @@ static void xrun(struct snd_pcm_substream *substream) | |||
| 154 | if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) | 161 | if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) |
| 155 | snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); | 162 | snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); |
| 156 | snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); | 163 | snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); |
| 157 | if (xrun_debug(substream, 1)) { | 164 | if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { |
| 158 | char name[16]; | 165 | char name[16]; |
| 159 | pcm_debug_name(substream, name, sizeof(name)); | 166 | pcm_debug_name(substream, name, sizeof(name)); |
| 160 | snd_printd(KERN_DEBUG "XRUN: %s\n", name); | 167 | snd_printd(KERN_DEBUG "XRUN: %s\n", name); |
| @@ -162,32 +169,102 @@ static void xrun(struct snd_pcm_substream *substream) | |||
| 162 | } | 169 | } |
| 163 | } | 170 | } |
| 164 | 171 | ||
| 165 | static snd_pcm_uframes_t | 172 | #define hw_ptr_error(substream, fmt, args...) \ |
| 166 | snd_pcm_update_hw_ptr_pos(struct snd_pcm_substream *substream, | 173 | do { \ |
| 167 | struct snd_pcm_runtime *runtime) | 174 | if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \ |
| 168 | { | 175 | xrun_log_show(substream); \ |
| 176 | if (printk_ratelimit()) { \ | ||
| 177 | snd_printd("PCM: " fmt, ##args); \ | ||
| 178 | } \ | ||
| 179 | dump_stack_on_xrun(substream); \ | ||
| 180 | } \ | ||
| 181 | } while (0) | ||
| 182 | |||
| 183 | #define XRUN_LOG_CNT 10 | ||
| 184 | |||
| 185 | struct hwptr_log_entry { | ||
| 186 | unsigned long jiffies; | ||
| 169 | snd_pcm_uframes_t pos; | 187 | snd_pcm_uframes_t pos; |
| 188 | snd_pcm_uframes_t period_size; | ||
| 189 | snd_pcm_uframes_t buffer_size; | ||
| 190 | snd_pcm_uframes_t old_hw_ptr; | ||
| 191 | snd_pcm_uframes_t hw_ptr_base; | ||
| 192 | }; | ||
| 170 | 193 | ||
| 171 | pos = substream->ops->pointer(substream); | 194 | struct snd_pcm_hwptr_log { |
| 172 | if (pos == SNDRV_PCM_POS_XRUN) | 195 | unsigned int idx; |
| 173 | return pos; /* XRUN */ | 196 | unsigned int hit: 1; |
| 174 | if (pos >= runtime->buffer_size) { | 197 | struct hwptr_log_entry entries[XRUN_LOG_CNT]; |
| 175 | if (printk_ratelimit()) { | 198 | }; |
| 176 | char name[16]; | 199 | |
| 177 | pcm_debug_name(substream, name, sizeof(name)); | 200 | static void xrun_log(struct snd_pcm_substream *substream, |
| 178 | snd_printd(KERN_ERR "BUG: %s, pos = 0x%lx, " | 201 | snd_pcm_uframes_t pos) |
| 179 | "buffer size = 0x%lx, period size = 0x%lx\n", | 202 | { |
| 180 | name, pos, runtime->buffer_size, | 203 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 181 | runtime->period_size); | 204 | struct snd_pcm_hwptr_log *log = runtime->hwptr_log; |
| 182 | } | 205 | struct hwptr_log_entry *entry; |
| 183 | pos = 0; | 206 | |
| 207 | if (log == NULL) { | ||
| 208 | log = kzalloc(sizeof(*log), GFP_ATOMIC); | ||
| 209 | if (log == NULL) | ||
| 210 | return; | ||
| 211 | runtime->hwptr_log = log; | ||
| 212 | } else { | ||
| 213 | if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit) | ||
| 214 | return; | ||
| 184 | } | 215 | } |
| 185 | pos -= pos % runtime->min_align; | 216 | entry = &log->entries[log->idx]; |
| 186 | return pos; | 217 | entry->jiffies = jiffies; |
| 218 | entry->pos = pos; | ||
| 219 | entry->period_size = runtime->period_size; | ||
| 220 | entry->buffer_size = runtime->buffer_size;; | ||
| 221 | entry->old_hw_ptr = runtime->status->hw_ptr; | ||
| 222 | entry->hw_ptr_base = runtime->hw_ptr_base; | ||
| 223 | log->idx = (log->idx + 1) % XRUN_LOG_CNT; | ||
| 224 | } | ||
| 225 | |||
| 226 | static void xrun_log_show(struct snd_pcm_substream *substream) | ||
| 227 | { | ||
| 228 | struct snd_pcm_hwptr_log *log = substream->runtime->hwptr_log; | ||
| 229 | struct hwptr_log_entry *entry; | ||
| 230 | char name[16]; | ||
| 231 | unsigned int idx; | ||
| 232 | int cnt; | ||
| 233 | |||
| 234 | if (log == NULL) | ||
| 235 | return; | ||
| 236 | if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit) | ||
| 237 | return; | ||
| 238 | pcm_debug_name(substream, name, sizeof(name)); | ||
| 239 | for (cnt = 0, idx = log->idx; cnt < XRUN_LOG_CNT; cnt++) { | ||
| 240 | entry = &log->entries[idx]; | ||
| 241 | if (entry->period_size == 0) | ||
| 242 | break; | ||
| 243 | snd_printd("hwptr log: %s: j=%lu, pos=%ld/%ld/%ld, " | ||
| 244 | "hwptr=%ld/%ld\n", | ||
| 245 | name, entry->jiffies, (unsigned long)entry->pos, | ||
| 246 | (unsigned long)entry->period_size, | ||
| 247 | (unsigned long)entry->buffer_size, | ||
| 248 | (unsigned long)entry->old_hw_ptr, | ||
| 249 | (unsigned long)entry->hw_ptr_base); | ||
| 250 | idx++; | ||
| 251 | idx %= XRUN_LOG_CNT; | ||
| 252 | } | ||
| 253 | log->hit = 1; | ||
| 187 | } | 254 | } |
| 188 | 255 | ||
| 189 | static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream, | 256 | #else /* ! CONFIG_SND_PCM_XRUN_DEBUG */ |
| 190 | struct snd_pcm_runtime *runtime) | 257 | |
| 258 | #define xrun_debug(substream, mask) 0 | ||
| 259 | #define xrun(substream) do { } while (0) | ||
| 260 | #define hw_ptr_error(substream, fmt, args...) do { } while (0) | ||
| 261 | #define xrun_log(substream, pos) do { } while (0) | ||
| 262 | #define xrun_log_show(substream) do { } while (0) | ||
| 263 | |||
| 264 | #endif | ||
| 265 | |||
| 266 | int snd_pcm_update_state(struct snd_pcm_substream *substream, | ||
| 267 | struct snd_pcm_runtime *runtime) | ||
| 191 | { | 268 | { |
| 192 | snd_pcm_uframes_t avail; | 269 | snd_pcm_uframes_t avail; |
| 193 | 270 | ||
| @@ -209,88 +286,94 @@ static int snd_pcm_update_hw_ptr_post(struct snd_pcm_substream *substream, | |||
| 209 | } | 286 | } |
| 210 | } | 287 | } |
| 211 | if (avail >= runtime->control->avail_min) | 288 | if (avail >= runtime->control->avail_min) |
| 212 | wake_up(&runtime->sleep); | 289 | wake_up(runtime->twake ? &runtime->tsleep : &runtime->sleep); |
| 213 | return 0; | 290 | return 0; |
| 214 | } | 291 | } |
| 215 | 292 | ||
| 216 | #define hw_ptr_error(substream, fmt, args...) \ | 293 | static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, |
| 217 | do { \ | 294 | unsigned int in_interrupt) |
| 218 | if (xrun_debug(substream, 1)) { \ | ||
| 219 | if (printk_ratelimit()) { \ | ||
| 220 | snd_printd("PCM: " fmt, ##args); \ | ||
| 221 | } \ | ||
| 222 | dump_stack_on_xrun(substream); \ | ||
| 223 | } \ | ||
| 224 | } while (0) | ||
| 225 | |||
| 226 | static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) | ||
| 227 | { | 295 | { |
| 228 | struct snd_pcm_runtime *runtime = substream->runtime; | 296 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 229 | snd_pcm_uframes_t pos; | 297 | snd_pcm_uframes_t pos; |
| 230 | snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_ptr_interrupt, hw_base; | 298 | snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base; |
| 231 | snd_pcm_sframes_t hdelta, delta; | 299 | snd_pcm_sframes_t hdelta, delta; |
| 232 | unsigned long jdelta; | 300 | unsigned long jdelta; |
| 233 | 301 | ||
| 234 | old_hw_ptr = runtime->status->hw_ptr; | 302 | old_hw_ptr = runtime->status->hw_ptr; |
| 235 | pos = snd_pcm_update_hw_ptr_pos(substream, runtime); | 303 | pos = substream->ops->pointer(substream); |
| 236 | if (pos == SNDRV_PCM_POS_XRUN) { | 304 | if (pos == SNDRV_PCM_POS_XRUN) { |
| 237 | xrun(substream); | 305 | xrun(substream); |
| 238 | return -EPIPE; | 306 | return -EPIPE; |
| 239 | } | 307 | } |
| 240 | if (xrun_debug(substream, 8)) { | 308 | if (pos >= runtime->buffer_size) { |
| 241 | char name[16]; | 309 | if (printk_ratelimit()) { |
| 242 | pcm_debug_name(substream, name, sizeof(name)); | 310 | char name[16]; |
| 243 | snd_printd("period_update: %s: pos=0x%x/0x%x/0x%x, " | 311 | pcm_debug_name(substream, name, sizeof(name)); |
| 244 | "hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n", | 312 | xrun_log_show(substream); |
| 245 | name, (unsigned int)pos, | 313 | snd_printd(KERN_ERR "BUG: %s, pos = %ld, " |
| 246 | (unsigned int)runtime->period_size, | 314 | "buffer size = %ld, period size = %ld\n", |
| 247 | (unsigned int)runtime->buffer_size, | 315 | name, pos, runtime->buffer_size, |
| 248 | (unsigned long)old_hw_ptr, | 316 | runtime->period_size); |
| 249 | (unsigned long)runtime->hw_ptr_base, | 317 | } |
| 250 | (unsigned long)runtime->hw_ptr_interrupt); | 318 | pos = 0; |
| 251 | } | 319 | } |
| 320 | pos -= pos % runtime->min_align; | ||
| 321 | if (xrun_debug(substream, XRUN_DEBUG_LOG)) | ||
| 322 | xrun_log(substream, pos); | ||
| 252 | hw_base = runtime->hw_ptr_base; | 323 | hw_base = runtime->hw_ptr_base; |
| 253 | new_hw_ptr = hw_base + pos; | 324 | new_hw_ptr = hw_base + pos; |
| 254 | hw_ptr_interrupt = runtime->hw_ptr_interrupt + runtime->period_size; | 325 | if (in_interrupt) { |
| 255 | delta = new_hw_ptr - hw_ptr_interrupt; | 326 | /* we know that one period was processed */ |
| 256 | if (hw_ptr_interrupt >= runtime->boundary) { | 327 | /* delta = "expected next hw_ptr" for in_interrupt != 0 */ |
| 257 | hw_ptr_interrupt -= runtime->boundary; | 328 | delta = runtime->hw_ptr_interrupt + runtime->period_size; |
| 258 | if (hw_base < runtime->boundary / 2) | 329 | if (delta > new_hw_ptr) { |
| 259 | /* hw_base was already lapped; recalc delta */ | ||
| 260 | delta = new_hw_ptr - hw_ptr_interrupt; | ||
| 261 | } | ||
| 262 | if (delta < 0) { | ||
| 263 | if (runtime->periods == 1 || new_hw_ptr < old_hw_ptr) | ||
| 264 | delta += runtime->buffer_size; | ||
| 265 | if (delta < 0) { | ||
| 266 | hw_ptr_error(substream, | ||
| 267 | "Unexpected hw_pointer value " | ||
| 268 | "(stream=%i, pos=%ld, intr_ptr=%ld)\n", | ||
| 269 | substream->stream, (long)pos, | ||
| 270 | (long)hw_ptr_interrupt); | ||
| 271 | #if 1 | ||
| 272 | /* simply skipping the hwptr update seems more | ||
| 273 | * robust in some cases, e.g. on VMware with | ||
| 274 | * inaccurate timer source | ||
| 275 | */ | ||
| 276 | return 0; /* skip this update */ | ||
| 277 | #else | ||
| 278 | /* rebase to interrupt position */ | ||
| 279 | hw_base = new_hw_ptr = hw_ptr_interrupt; | ||
| 280 | /* align hw_base to buffer_size */ | ||
| 281 | hw_base -= hw_base % runtime->buffer_size; | ||
| 282 | delta = 0; | ||
| 283 | #endif | ||
| 284 | } else { | ||
| 285 | hw_base += runtime->buffer_size; | 330 | hw_base += runtime->buffer_size; |
| 286 | if (hw_base >= runtime->boundary) | 331 | if (hw_base >= runtime->boundary) |
| 287 | hw_base = 0; | 332 | hw_base = 0; |
| 288 | new_hw_ptr = hw_base + pos; | 333 | new_hw_ptr = hw_base + pos; |
| 334 | goto __delta; | ||
| 289 | } | 335 | } |
| 290 | } | 336 | } |
| 337 | /* new_hw_ptr might be lower than old_hw_ptr in case when */ | ||
| 338 | /* pointer crosses the end of the ring buffer */ | ||
| 339 | if (new_hw_ptr < old_hw_ptr) { | ||
| 340 | hw_base += runtime->buffer_size; | ||
| 341 | if (hw_base >= runtime->boundary) | ||
| 342 | hw_base = 0; | ||
| 343 | new_hw_ptr = hw_base + pos; | ||
| 344 | } | ||
| 345 | __delta: | ||
| 346 | delta = (new_hw_ptr - old_hw_ptr) % runtime->boundary; | ||
| 347 | if (xrun_debug(substream, in_interrupt ? | ||
| 348 | XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) { | ||
| 349 | char name[16]; | ||
| 350 | pcm_debug_name(substream, name, sizeof(name)); | ||
| 351 | snd_printd("%s_update: %s: pos=%u/%u/%u, " | ||
| 352 | "hwptr=%ld/%ld/%ld/%ld\n", | ||
| 353 | in_interrupt ? "period" : "hwptr", | ||
| 354 | name, | ||
| 355 | (unsigned int)pos, | ||
| 356 | (unsigned int)runtime->period_size, | ||
| 357 | (unsigned int)runtime->buffer_size, | ||
| 358 | (unsigned long)delta, | ||
| 359 | (unsigned long)old_hw_ptr, | ||
| 360 | (unsigned long)new_hw_ptr, | ||
| 361 | (unsigned long)runtime->hw_ptr_base); | ||
| 362 | } | ||
| 363 | /* something must be really wrong */ | ||
| 364 | if (delta >= runtime->buffer_size + runtime->period_size) { | ||
| 365 | hw_ptr_error(substream, | ||
| 366 | "Unexpected hw_pointer value %s" | ||
| 367 | "(stream=%i, pos=%ld, new_hw_ptr=%ld, " | ||
| 368 | "old_hw_ptr=%ld)\n", | ||
| 369 | in_interrupt ? "[Q] " : "[P]", | ||
| 370 | substream->stream, (long)pos, | ||
| 371 | (long)new_hw_ptr, (long)old_hw_ptr); | ||
| 372 | return 0; | ||
| 373 | } | ||
| 291 | 374 | ||
| 292 | /* Do jiffies check only in xrun_debug mode */ | 375 | /* Do jiffies check only in xrun_debug mode */ |
| 293 | if (!xrun_debug(substream, 4)) | 376 | if (!xrun_debug(substream, XRUN_DEBUG_JIFFIESCHECK)) |
| 294 | goto no_jiffies_check; | 377 | goto no_jiffies_check; |
| 295 | 378 | ||
| 296 | /* Skip the jiffies check for hardwares with BATCH flag. | 379 | /* Skip the jiffies check for hardwares with BATCH flag. |
| @@ -299,7 +382,7 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) | |||
| 299 | */ | 382 | */ |
| 300 | if (runtime->hw.info & SNDRV_PCM_INFO_BATCH) | 383 | if (runtime->hw.info & SNDRV_PCM_INFO_BATCH) |
| 301 | goto no_jiffies_check; | 384 | goto no_jiffies_check; |
| 302 | hdelta = new_hw_ptr - old_hw_ptr; | 385 | hdelta = delta; |
| 303 | if (hdelta < runtime->delay) | 386 | if (hdelta < runtime->delay) |
| 304 | goto no_jiffies_check; | 387 | goto no_jiffies_check; |
| 305 | hdelta -= runtime->delay; | 388 | hdelta -= runtime->delay; |
| @@ -308,130 +391,68 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream) | |||
| 308 | delta = jdelta / | 391 | delta = jdelta / |
| 309 | (((runtime->period_size * HZ) / runtime->rate) | 392 | (((runtime->period_size * HZ) / runtime->rate) |
| 310 | + HZ/100); | 393 | + HZ/100); |
| 394 | /* move new_hw_ptr according jiffies not pos variable */ | ||
| 395 | new_hw_ptr = old_hw_ptr; | ||
| 396 | hw_base = delta; | ||
| 397 | /* use loop to avoid checks for delta overflows */ | ||
| 398 | /* the delta value is small or zero in most cases */ | ||
| 399 | while (delta > 0) { | ||
| 400 | new_hw_ptr += runtime->period_size; | ||
| 401 | if (new_hw_ptr >= runtime->boundary) | ||
| 402 | new_hw_ptr -= runtime->boundary; | ||
| 403 | delta--; | ||
| 404 | } | ||
| 405 | /* align hw_base to buffer_size */ | ||
| 311 | hw_ptr_error(substream, | 406 | hw_ptr_error(substream, |
| 312 | "hw_ptr skipping! [Q] " | 407 | "hw_ptr skipping! %s" |
| 313 | "(pos=%ld, delta=%ld, period=%ld, " | 408 | "(pos=%ld, delta=%ld, period=%ld, " |
| 314 | "jdelta=%lu/%lu/%lu)\n", | 409 | "jdelta=%lu/%lu/%lu, hw_ptr=%ld/%ld)\n", |
| 410 | in_interrupt ? "[Q] " : "", | ||
| 315 | (long)pos, (long)hdelta, | 411 | (long)pos, (long)hdelta, |
| 316 | (long)runtime->period_size, jdelta, | 412 | (long)runtime->period_size, jdelta, |
| 317 | ((hdelta * HZ) / runtime->rate), delta); | 413 | ((hdelta * HZ) / runtime->rate), hw_base, |
| 318 | hw_ptr_interrupt = runtime->hw_ptr_interrupt + | 414 | (unsigned long)old_hw_ptr, |
| 319 | runtime->period_size * delta; | 415 | (unsigned long)new_hw_ptr); |
| 320 | if (hw_ptr_interrupt >= runtime->boundary) | 416 | /* reset values to proper state */ |
| 321 | hw_ptr_interrupt -= runtime->boundary; | ||
| 322 | /* rebase to interrupt position */ | ||
| 323 | hw_base = new_hw_ptr = hw_ptr_interrupt; | ||
| 324 | /* align hw_base to buffer_size */ | ||
| 325 | hw_base -= hw_base % runtime->buffer_size; | ||
| 326 | delta = 0; | 417 | delta = 0; |
| 418 | hw_base = new_hw_ptr - (new_hw_ptr % runtime->buffer_size); | ||
| 327 | } | 419 | } |
| 328 | no_jiffies_check: | 420 | no_jiffies_check: |
| 329 | if (delta > runtime->period_size + runtime->period_size / 2) { | 421 | if (delta > runtime->period_size + runtime->period_size / 2) { |
| 330 | hw_ptr_error(substream, | 422 | hw_ptr_error(substream, |
| 331 | "Lost interrupts? " | 423 | "Lost interrupts? %s" |
| 332 | "(stream=%i, delta=%ld, intr_ptr=%ld)\n", | 424 | "(stream=%i, delta=%ld, new_hw_ptr=%ld, " |
| 425 | "old_hw_ptr=%ld)\n", | ||
| 426 | in_interrupt ? "[Q] " : "", | ||
| 333 | substream->stream, (long)delta, | 427 | substream->stream, (long)delta, |
| 334 | (long)hw_ptr_interrupt); | 428 | (long)new_hw_ptr, |
| 335 | /* rebase hw_ptr_interrupt */ | 429 | (long)old_hw_ptr); |
| 336 | hw_ptr_interrupt = | ||
| 337 | new_hw_ptr - new_hw_ptr % runtime->period_size; | ||
| 338 | } | 430 | } |
| 339 | runtime->hw_ptr_interrupt = hw_ptr_interrupt; | 431 | |
| 432 | if (runtime->status->hw_ptr == new_hw_ptr) | ||
| 433 | return 0; | ||
| 340 | 434 | ||
| 341 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && | 435 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && |
| 342 | runtime->silence_size > 0) | 436 | runtime->silence_size > 0) |
| 343 | snd_pcm_playback_silence(substream, new_hw_ptr); | 437 | snd_pcm_playback_silence(substream, new_hw_ptr); |
| 344 | 438 | ||
| 345 | if (runtime->status->hw_ptr == new_hw_ptr) | 439 | if (in_interrupt) { |
| 346 | return 0; | 440 | runtime->hw_ptr_interrupt = new_hw_ptr - |
| 347 | 441 | (new_hw_ptr % runtime->period_size); | |
| 442 | } | ||
| 348 | runtime->hw_ptr_base = hw_base; | 443 | runtime->hw_ptr_base = hw_base; |
| 349 | runtime->status->hw_ptr = new_hw_ptr; | 444 | runtime->status->hw_ptr = new_hw_ptr; |
| 350 | runtime->hw_ptr_jiffies = jiffies; | 445 | runtime->hw_ptr_jiffies = jiffies; |
| 351 | if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) | 446 | if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) |
| 352 | snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); | 447 | snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); |
| 353 | 448 | ||
| 354 | return snd_pcm_update_hw_ptr_post(substream, runtime); | 449 | return snd_pcm_update_state(substream, runtime); |
| 355 | } | 450 | } |
| 356 | 451 | ||
| 357 | /* CAUTION: call it with irq disabled */ | 452 | /* CAUTION: call it with irq disabled */ |
| 358 | int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream) | 453 | int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream) |
| 359 | { | 454 | { |
| 360 | struct snd_pcm_runtime *runtime = substream->runtime; | 455 | return snd_pcm_update_hw_ptr0(substream, 0); |
| 361 | snd_pcm_uframes_t pos; | ||
| 362 | snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base; | ||
| 363 | snd_pcm_sframes_t delta; | ||
| 364 | unsigned long jdelta; | ||
| 365 | |||
| 366 | old_hw_ptr = runtime->status->hw_ptr; | ||
| 367 | pos = snd_pcm_update_hw_ptr_pos(substream, runtime); | ||
| 368 | if (pos == SNDRV_PCM_POS_XRUN) { | ||
| 369 | xrun(substream); | ||
| 370 | return -EPIPE; | ||
| 371 | } | ||
| 372 | if (xrun_debug(substream, 16)) { | ||
| 373 | char name[16]; | ||
| 374 | pcm_debug_name(substream, name, sizeof(name)); | ||
| 375 | snd_printd("hw_update: %s: pos=0x%x/0x%x/0x%x, " | ||
| 376 | "hwptr=0x%lx, hw_base=0x%lx, hw_intr=0x%lx\n", | ||
| 377 | name, (unsigned int)pos, | ||
| 378 | (unsigned int)runtime->period_size, | ||
| 379 | (unsigned int)runtime->buffer_size, | ||
| 380 | (unsigned long)old_hw_ptr, | ||
| 381 | (unsigned long)runtime->hw_ptr_base, | ||
| 382 | (unsigned long)runtime->hw_ptr_interrupt); | ||
| 383 | } | ||
| 384 | |||
| 385 | hw_base = runtime->hw_ptr_base; | ||
| 386 | new_hw_ptr = hw_base + pos; | ||
| 387 | |||
| 388 | delta = new_hw_ptr - old_hw_ptr; | ||
| 389 | jdelta = jiffies - runtime->hw_ptr_jiffies; | ||
| 390 | if (delta < 0) { | ||
| 391 | delta += runtime->buffer_size; | ||
| 392 | if (delta < 0) { | ||
| 393 | hw_ptr_error(substream, | ||
| 394 | "Unexpected hw_pointer value [2] " | ||
| 395 | "(stream=%i, pos=%ld, old_ptr=%ld, jdelta=%li)\n", | ||
| 396 | substream->stream, (long)pos, | ||
| 397 | (long)old_hw_ptr, jdelta); | ||
| 398 | return 0; | ||
| 399 | } | ||
| 400 | hw_base += runtime->buffer_size; | ||
| 401 | if (hw_base >= runtime->boundary) | ||
| 402 | hw_base = 0; | ||
| 403 | new_hw_ptr = hw_base + pos; | ||
| 404 | } | ||
| 405 | /* Do jiffies check only in xrun_debug mode */ | ||
| 406 | if (!xrun_debug(substream, 4)) | ||
| 407 | goto no_jiffies_check; | ||
| 408 | if (delta < runtime->delay) | ||
| 409 | goto no_jiffies_check; | ||
| 410 | delta -= runtime->delay; | ||
| 411 | if (((delta * HZ) / runtime->rate) > jdelta + HZ/100) { | ||
| 412 | hw_ptr_error(substream, | ||
| 413 | "hw_ptr skipping! " | ||
| 414 | "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu)\n", | ||
| 415 | (long)pos, (long)delta, | ||
| 416 | (long)runtime->period_size, jdelta, | ||
| 417 | ((delta * HZ) / runtime->rate)); | ||
| 418 | return 0; | ||
| 419 | } | ||
| 420 | no_jiffies_check: | ||
| 421 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && | ||
| 422 | runtime->silence_size > 0) | ||
| 423 | snd_pcm_playback_silence(substream, new_hw_ptr); | ||
| 424 | |||
| 425 | if (runtime->status->hw_ptr == new_hw_ptr) | ||
| 426 | return 0; | ||
| 427 | |||
| 428 | runtime->hw_ptr_base = hw_base; | ||
| 429 | runtime->status->hw_ptr = new_hw_ptr; | ||
| 430 | runtime->hw_ptr_jiffies = jiffies; | ||
| 431 | if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE) | ||
| 432 | snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp); | ||
| 433 | |||
| 434 | return snd_pcm_update_hw_ptr_post(substream, runtime); | ||
| 435 | } | 456 | } |
| 436 | 457 | ||
| 437 | /** | 458 | /** |
| @@ -745,10 +766,13 @@ int snd_interval_ratnum(struct snd_interval *i, | |||
| 745 | unsigned int rats_count, struct snd_ratnum *rats, | 766 | unsigned int rats_count, struct snd_ratnum *rats, |
| 746 | unsigned int *nump, unsigned int *denp) | 767 | unsigned int *nump, unsigned int *denp) |
| 747 | { | 768 | { |
| 748 | unsigned int best_num, best_diff, best_den; | 769 | unsigned int best_num, best_den; |
| 770 | int best_diff; | ||
| 749 | unsigned int k; | 771 | unsigned int k; |
| 750 | struct snd_interval t; | 772 | struct snd_interval t; |
| 751 | int err; | 773 | int err; |
| 774 | unsigned int result_num, result_den; | ||
| 775 | int result_diff; | ||
| 752 | 776 | ||
| 753 | best_num = best_den = best_diff = 0; | 777 | best_num = best_den = best_diff = 0; |
| 754 | for (k = 0; k < rats_count; ++k) { | 778 | for (k = 0; k < rats_count; ++k) { |
| @@ -770,6 +794,8 @@ int snd_interval_ratnum(struct snd_interval *i, | |||
| 770 | den -= r; | 794 | den -= r; |
| 771 | } | 795 | } |
| 772 | diff = num - q * den; | 796 | diff = num - q * den; |
| 797 | if (diff < 0) | ||
| 798 | diff = -diff; | ||
| 773 | if (best_num == 0 || | 799 | if (best_num == 0 || |
| 774 | diff * best_den < best_diff * den) { | 800 | diff * best_den < best_diff * den) { |
| 775 | best_diff = diff; | 801 | best_diff = diff; |
| @@ -784,6 +810,9 @@ int snd_interval_ratnum(struct snd_interval *i, | |||
| 784 | t.min = div_down(best_num, best_den); | 810 | t.min = div_down(best_num, best_den); |
| 785 | t.openmin = !!(best_num % best_den); | 811 | t.openmin = !!(best_num % best_den); |
| 786 | 812 | ||
| 813 | result_num = best_num; | ||
| 814 | result_diff = best_diff; | ||
| 815 | result_den = best_den; | ||
| 787 | best_num = best_den = best_diff = 0; | 816 | best_num = best_den = best_diff = 0; |
| 788 | for (k = 0; k < rats_count; ++k) { | 817 | for (k = 0; k < rats_count; ++k) { |
| 789 | unsigned int num = rats[k].num; | 818 | unsigned int num = rats[k].num; |
| @@ -806,6 +835,8 @@ int snd_interval_ratnum(struct snd_interval *i, | |||
| 806 | den += rats[k].den_step - r; | 835 | den += rats[k].den_step - r; |
| 807 | } | 836 | } |
| 808 | diff = q * den - num; | 837 | diff = q * den - num; |
| 838 | if (diff < 0) | ||
| 839 | diff = -diff; | ||
| 809 | if (best_num == 0 || | 840 | if (best_num == 0 || |
| 810 | diff * best_den < best_diff * den) { | 841 | diff * best_den < best_diff * den) { |
| 811 | best_diff = diff; | 842 | best_diff = diff; |
| @@ -825,10 +856,14 @@ int snd_interval_ratnum(struct snd_interval *i, | |||
| 825 | return err; | 856 | return err; |
| 826 | 857 | ||
| 827 | if (snd_interval_single(i)) { | 858 | if (snd_interval_single(i)) { |
| 859 | if (best_diff * result_den < result_diff * best_den) { | ||
| 860 | result_num = best_num; | ||
| 861 | result_den = best_den; | ||
| 862 | } | ||
| 828 | if (nump) | 863 | if (nump) |
| 829 | *nump = best_num; | 864 | *nump = result_num; |
| 830 | if (denp) | 865 | if (denp) |
| 831 | *denp = best_den; | 866 | *denp = result_den; |
| 832 | } | 867 | } |
| 833 | return err; | 868 | return err; |
| 834 | } | 869 | } |
| @@ -1643,7 +1678,7 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream) | |||
| 1643 | 1678 | ||
| 1644 | snd_pcm_stream_lock_irqsave(substream, flags); | 1679 | snd_pcm_stream_lock_irqsave(substream, flags); |
| 1645 | if (!snd_pcm_running(substream) || | 1680 | if (!snd_pcm_running(substream) || |
| 1646 | snd_pcm_update_hw_ptr_interrupt(substream) < 0) | 1681 | snd_pcm_update_hw_ptr0(substream, 1) < 0) |
| 1647 | goto _end; | 1682 | goto _end; |
| 1648 | 1683 | ||
| 1649 | if (substream->timer_running) | 1684 | if (substream->timer_running) |
| @@ -1674,7 +1709,7 @@ static int wait_for_avail_min(struct snd_pcm_substream *substream, | |||
| 1674 | long tout; | 1709 | long tout; |
| 1675 | 1710 | ||
| 1676 | init_waitqueue_entry(&wait, current); | 1711 | init_waitqueue_entry(&wait, current); |
| 1677 | add_wait_queue(&runtime->sleep, &wait); | 1712 | add_wait_queue(&runtime->tsleep, &wait); |
| 1678 | for (;;) { | 1713 | for (;;) { |
| 1679 | if (signal_pending(current)) { | 1714 | if (signal_pending(current)) { |
| 1680 | err = -ERESTARTSYS; | 1715 | err = -ERESTARTSYS; |
| @@ -1717,7 +1752,7 @@ static int wait_for_avail_min(struct snd_pcm_substream *substream, | |||
| 1717 | break; | 1752 | break; |
| 1718 | } | 1753 | } |
| 1719 | _endloop: | 1754 | _endloop: |
| 1720 | remove_wait_queue(&runtime->sleep, &wait); | 1755 | remove_wait_queue(&runtime->tsleep, &wait); |
| 1721 | *availp = avail; | 1756 | *availp = avail; |
| 1722 | return err; | 1757 | return err; |
| 1723 | } | 1758 | } |
| @@ -1776,6 +1811,7 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, | |||
| 1776 | goto _end_unlock; | 1811 | goto _end_unlock; |
| 1777 | } | 1812 | } |
| 1778 | 1813 | ||
| 1814 | runtime->twake = 1; | ||
| 1779 | while (size > 0) { | 1815 | while (size > 0) { |
| 1780 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; | 1816 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; |
| 1781 | snd_pcm_uframes_t avail; | 1817 | snd_pcm_uframes_t avail; |
| @@ -1797,15 +1833,17 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, | |||
| 1797 | if (frames > cont) | 1833 | if (frames > cont) |
| 1798 | frames = cont; | 1834 | frames = cont; |
| 1799 | if (snd_BUG_ON(!frames)) { | 1835 | if (snd_BUG_ON(!frames)) { |
| 1836 | runtime->twake = 0; | ||
| 1800 | snd_pcm_stream_unlock_irq(substream); | 1837 | snd_pcm_stream_unlock_irq(substream); |
| 1801 | return -EINVAL; | 1838 | return -EINVAL; |
| 1802 | } | 1839 | } |
| 1803 | appl_ptr = runtime->control->appl_ptr; | 1840 | appl_ptr = runtime->control->appl_ptr; |
| 1804 | appl_ofs = appl_ptr % runtime->buffer_size; | 1841 | appl_ofs = appl_ptr % runtime->buffer_size; |
| 1805 | snd_pcm_stream_unlock_irq(substream); | 1842 | snd_pcm_stream_unlock_irq(substream); |
| 1806 | if ((err = transfer(substream, appl_ofs, data, offset, frames)) < 0) | 1843 | err = transfer(substream, appl_ofs, data, offset, frames); |
| 1807 | goto _end; | ||
| 1808 | snd_pcm_stream_lock_irq(substream); | 1844 | snd_pcm_stream_lock_irq(substream); |
| 1845 | if (err < 0) | ||
| 1846 | goto _end_unlock; | ||
| 1809 | switch (runtime->status->state) { | 1847 | switch (runtime->status->state) { |
| 1810 | case SNDRV_PCM_STATE_XRUN: | 1848 | case SNDRV_PCM_STATE_XRUN: |
| 1811 | err = -EPIPE; | 1849 | err = -EPIPE; |
| @@ -1834,8 +1872,10 @@ static snd_pcm_sframes_t snd_pcm_lib_write1(struct snd_pcm_substream *substream, | |||
| 1834 | } | 1872 | } |
| 1835 | } | 1873 | } |
| 1836 | _end_unlock: | 1874 | _end_unlock: |
| 1875 | runtime->twake = 0; | ||
| 1876 | if (xfer > 0 && err >= 0) | ||
| 1877 | snd_pcm_update_state(substream, runtime); | ||
| 1837 | snd_pcm_stream_unlock_irq(substream); | 1878 | snd_pcm_stream_unlock_irq(substream); |
| 1838 | _end: | ||
| 1839 | return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; | 1879 | return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; |
| 1840 | } | 1880 | } |
| 1841 | 1881 | ||
| @@ -1993,6 +2033,7 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, | |||
| 1993 | goto _end_unlock; | 2033 | goto _end_unlock; |
| 1994 | } | 2034 | } |
| 1995 | 2035 | ||
| 2036 | runtime->twake = 1; | ||
| 1996 | while (size > 0) { | 2037 | while (size > 0) { |
| 1997 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; | 2038 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; |
| 1998 | snd_pcm_uframes_t avail; | 2039 | snd_pcm_uframes_t avail; |
| @@ -2021,15 +2062,17 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, | |||
| 2021 | if (frames > cont) | 2062 | if (frames > cont) |
| 2022 | frames = cont; | 2063 | frames = cont; |
| 2023 | if (snd_BUG_ON(!frames)) { | 2064 | if (snd_BUG_ON(!frames)) { |
| 2065 | runtime->twake = 0; | ||
| 2024 | snd_pcm_stream_unlock_irq(substream); | 2066 | snd_pcm_stream_unlock_irq(substream); |
| 2025 | return -EINVAL; | 2067 | return -EINVAL; |
| 2026 | } | 2068 | } |
| 2027 | appl_ptr = runtime->control->appl_ptr; | 2069 | appl_ptr = runtime->control->appl_ptr; |
| 2028 | appl_ofs = appl_ptr % runtime->buffer_size; | 2070 | appl_ofs = appl_ptr % runtime->buffer_size; |
| 2029 | snd_pcm_stream_unlock_irq(substream); | 2071 | snd_pcm_stream_unlock_irq(substream); |
| 2030 | if ((err = transfer(substream, appl_ofs, data, offset, frames)) < 0) | 2072 | err = transfer(substream, appl_ofs, data, offset, frames); |
| 2031 | goto _end; | ||
| 2032 | snd_pcm_stream_lock_irq(substream); | 2073 | snd_pcm_stream_lock_irq(substream); |
| 2074 | if (err < 0) | ||
| 2075 | goto _end_unlock; | ||
| 2033 | switch (runtime->status->state) { | 2076 | switch (runtime->status->state) { |
| 2034 | case SNDRV_PCM_STATE_XRUN: | 2077 | case SNDRV_PCM_STATE_XRUN: |
| 2035 | err = -EPIPE; | 2078 | err = -EPIPE; |
| @@ -2052,8 +2095,10 @@ static snd_pcm_sframes_t snd_pcm_lib_read1(struct snd_pcm_substream *substream, | |||
| 2052 | xfer += frames; | 2095 | xfer += frames; |
| 2053 | } | 2096 | } |
| 2054 | _end_unlock: | 2097 | _end_unlock: |
| 2098 | runtime->twake = 0; | ||
| 2099 | if (xfer > 0 && err >= 0) | ||
| 2100 | snd_pcm_update_state(substream, runtime); | ||
| 2055 | snd_pcm_stream_unlock_irq(substream); | 2101 | snd_pcm_stream_unlock_irq(substream); |
| 2056 | _end: | ||
| 2057 | return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; | 2102 | return xfer > 0 ? (snd_pcm_sframes_t)xfer : err; |
| 2058 | } | 2103 | } |
| 2059 | 2104 | ||
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index caa7796bc2f5..d6d49d6651f9 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c | |||
| @@ -23,6 +23,7 @@ | |||
| 23 | #include <linux/time.h> | 23 | #include <linux/time.h> |
| 24 | #include <linux/init.h> | 24 | #include <linux/init.h> |
| 25 | #include <linux/moduleparam.h> | 25 | #include <linux/moduleparam.h> |
| 26 | #include <linux/vmalloc.h> | ||
| 26 | #include <sound/core.h> | 27 | #include <sound/core.h> |
| 27 | #include <sound/pcm.h> | 28 | #include <sound/pcm.h> |
| 28 | #include <sound/info.h> | 29 | #include <sound/info.h> |
| @@ -434,3 +435,57 @@ int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream) | |||
| 434 | } | 435 | } |
| 435 | 436 | ||
| 436 | EXPORT_SYMBOL(snd_pcm_lib_free_pages); | 437 | EXPORT_SYMBOL(snd_pcm_lib_free_pages); |
| 438 | |||
| 439 | int _snd_pcm_lib_alloc_vmalloc_buffer(struct snd_pcm_substream *substream, | ||
| 440 | size_t size, gfp_t gfp_flags) | ||
| 441 | { | ||
| 442 | struct snd_pcm_runtime *runtime; | ||
| 443 | |||
| 444 | if (PCM_RUNTIME_CHECK(substream)) | ||
| 445 | return -EINVAL; | ||
| 446 | runtime = substream->runtime; | ||
| 447 | if (runtime->dma_area) { | ||
| 448 | if (runtime->dma_bytes >= size) | ||
| 449 | return 0; /* already large enough */ | ||
| 450 | vfree(runtime->dma_area); | ||
| 451 | } | ||
| 452 | runtime->dma_area = __vmalloc(size, gfp_flags, PAGE_KERNEL); | ||
| 453 | if (!runtime->dma_area) | ||
| 454 | return -ENOMEM; | ||
| 455 | runtime->dma_bytes = size; | ||
| 456 | return 1; | ||
| 457 | } | ||
| 458 | EXPORT_SYMBOL(_snd_pcm_lib_alloc_vmalloc_buffer); | ||
| 459 | |||
| 460 | /** | ||
| 461 | * snd_pcm_lib_free_vmalloc_buffer - free vmalloc buffer | ||
| 462 | * @substream: the substream with a buffer allocated by | ||
| 463 | * snd_pcm_lib_alloc_vmalloc_buffer() | ||
| 464 | */ | ||
| 465 | int snd_pcm_lib_free_vmalloc_buffer(struct snd_pcm_substream *substream) | ||
| 466 | { | ||
| 467 | struct snd_pcm_runtime *runtime; | ||
| 468 | |||
| 469 | if (PCM_RUNTIME_CHECK(substream)) | ||
| 470 | return -EINVAL; | ||
| 471 | runtime = substream->runtime; | ||
| 472 | vfree(runtime->dma_area); | ||
| 473 | runtime->dma_area = NULL; | ||
| 474 | return 0; | ||
| 475 | } | ||
| 476 | EXPORT_SYMBOL(snd_pcm_lib_free_vmalloc_buffer); | ||
| 477 | |||
| 478 | /** | ||
| 479 | * snd_pcm_lib_get_vmalloc_page - map vmalloc buffer offset to page struct | ||
| 480 | * @substream: the substream with a buffer allocated by | ||
| 481 | * snd_pcm_lib_alloc_vmalloc_buffer() | ||
| 482 | * @offset: offset in the buffer | ||
| 483 | * | ||
| 484 | * This function is to be used as the page callback in the PCM ops. | ||
| 485 | */ | ||
| 486 | struct page *snd_pcm_lib_get_vmalloc_page(struct snd_pcm_substream *substream, | ||
| 487 | unsigned long offset) | ||
| 488 | { | ||
| 489 | return vmalloc_to_page(substream->runtime->dma_area + offset); | ||
| 490 | } | ||
| 491 | EXPORT_SYMBOL(snd_pcm_lib_get_vmalloc_page); | ||
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index f7e1c9f0d3ed..872887624030 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c | |||
| @@ -27,6 +27,7 @@ | |||
| 27 | #include <linux/pm_qos_params.h> | 27 | #include <linux/pm_qos_params.h> |
| 28 | #include <linux/uio.h> | 28 | #include <linux/uio.h> |
| 29 | #include <linux/dma-mapping.h> | 29 | #include <linux/dma-mapping.h> |
| 30 | #include <linux/math64.h> | ||
| 30 | #include <sound/core.h> | 31 | #include <sound/core.h> |
| 31 | #include <sound/control.h> | 32 | #include <sound/control.h> |
| 32 | #include <sound/info.h> | 33 | #include <sound/info.h> |
| @@ -366,6 +367,38 @@ static int period_to_usecs(struct snd_pcm_runtime *runtime) | |||
| 366 | return usecs; | 367 | return usecs; |
| 367 | } | 368 | } |
| 368 | 369 | ||
| 370 | static int calc_boundary(struct snd_pcm_runtime *runtime) | ||
| 371 | { | ||
| 372 | u_int64_t boundary; | ||
| 373 | |||
| 374 | boundary = (u_int64_t)runtime->buffer_size * | ||
| 375 | (u_int64_t)runtime->period_size; | ||
| 376 | #if BITS_PER_LONG < 64 | ||
| 377 | /* try to find lowest common multiple for buffer and period */ | ||
| 378 | if (boundary > LONG_MAX - runtime->buffer_size) { | ||
| 379 | u_int32_t remainder = -1; | ||
| 380 | u_int32_t divident = runtime->buffer_size; | ||
| 381 | u_int32_t divisor = runtime->period_size; | ||
| 382 | while (remainder) { | ||
| 383 | remainder = divident % divisor; | ||
| 384 | if (remainder) { | ||
| 385 | divident = divisor; | ||
| 386 | divisor = remainder; | ||
| 387 | } | ||
| 388 | } | ||
| 389 | boundary = div_u64(boundary, divisor); | ||
| 390 | if (boundary > LONG_MAX - runtime->buffer_size) | ||
| 391 | return -ERANGE; | ||
| 392 | } | ||
| 393 | #endif | ||
| 394 | if (boundary == 0) | ||
| 395 | return -ERANGE; | ||
| 396 | runtime->boundary = boundary; | ||
| 397 | while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size) | ||
| 398 | runtime->boundary *= 2; | ||
| 399 | return 0; | ||
| 400 | } | ||
| 401 | |||
| 369 | static int snd_pcm_hw_params(struct snd_pcm_substream *substream, | 402 | static int snd_pcm_hw_params(struct snd_pcm_substream *substream, |
| 370 | struct snd_pcm_hw_params *params) | 403 | struct snd_pcm_hw_params *params) |
| 371 | { | 404 | { |
| @@ -441,9 +474,9 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream, | |||
| 441 | runtime->stop_threshold = runtime->buffer_size; | 474 | runtime->stop_threshold = runtime->buffer_size; |
| 442 | runtime->silence_threshold = 0; | 475 | runtime->silence_threshold = 0; |
| 443 | runtime->silence_size = 0; | 476 | runtime->silence_size = 0; |
| 444 | runtime->boundary = runtime->buffer_size; | 477 | err = calc_boundary(runtime); |
| 445 | while (runtime->boundary * 2 <= LONG_MAX - runtime->buffer_size) | 478 | if (err < 0) |
| 446 | runtime->boundary *= 2; | 479 | goto _error; |
| 447 | 480 | ||
| 448 | snd_pcm_timer_resolution_change(substream); | 481 | snd_pcm_timer_resolution_change(substream); |
| 449 | runtime->status->state = SNDRV_PCM_STATE_SETUP; | 482 | runtime->status->state = SNDRV_PCM_STATE_SETUP; |
| @@ -516,6 +549,7 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, | |||
| 516 | struct snd_pcm_sw_params *params) | 549 | struct snd_pcm_sw_params *params) |
| 517 | { | 550 | { |
| 518 | struct snd_pcm_runtime *runtime; | 551 | struct snd_pcm_runtime *runtime; |
| 552 | int err; | ||
| 519 | 553 | ||
| 520 | if (PCM_RUNTIME_CHECK(substream)) | 554 | if (PCM_RUNTIME_CHECK(substream)) |
| 521 | return -ENXIO; | 555 | return -ENXIO; |
| @@ -540,6 +574,7 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, | |||
| 540 | if (params->silence_threshold > runtime->buffer_size) | 574 | if (params->silence_threshold > runtime->buffer_size) |
| 541 | return -EINVAL; | 575 | return -EINVAL; |
| 542 | } | 576 | } |
| 577 | err = 0; | ||
| 543 | snd_pcm_stream_lock_irq(substream); | 578 | snd_pcm_stream_lock_irq(substream); |
| 544 | runtime->tstamp_mode = params->tstamp_mode; | 579 | runtime->tstamp_mode = params->tstamp_mode; |
| 545 | runtime->period_step = params->period_step; | 580 | runtime->period_step = params->period_step; |
| @@ -553,10 +588,10 @@ static int snd_pcm_sw_params(struct snd_pcm_substream *substream, | |||
| 553 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && | 588 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK && |
| 554 | runtime->silence_size > 0) | 589 | runtime->silence_size > 0) |
| 555 | snd_pcm_playback_silence(substream, ULONG_MAX); | 590 | snd_pcm_playback_silence(substream, ULONG_MAX); |
| 556 | wake_up(&runtime->sleep); | 591 | err = snd_pcm_update_state(substream, runtime); |
| 557 | } | 592 | } |
| 558 | snd_pcm_stream_unlock_irq(substream); | 593 | snd_pcm_stream_unlock_irq(substream); |
| 559 | return 0; | 594 | return err; |
| 560 | } | 595 | } |
| 561 | 596 | ||
| 562 | static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream, | 597 | static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream, |
| @@ -917,6 +952,7 @@ static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state) | |||
| 917 | runtime->status->state = state; | 952 | runtime->status->state = state; |
| 918 | } | 953 | } |
| 919 | wake_up(&runtime->sleep); | 954 | wake_up(&runtime->sleep); |
| 955 | wake_up(&runtime->tsleep); | ||
| 920 | } | 956 | } |
| 921 | 957 | ||
| 922 | static struct action_ops snd_pcm_action_stop = { | 958 | static struct action_ops snd_pcm_action_stop = { |
| @@ -1002,6 +1038,7 @@ static void snd_pcm_post_pause(struct snd_pcm_substream *substream, int push) | |||
| 1002 | SNDRV_TIMER_EVENT_MPAUSE, | 1038 | SNDRV_TIMER_EVENT_MPAUSE, |
| 1003 | &runtime->trigger_tstamp); | 1039 | &runtime->trigger_tstamp); |
| 1004 | wake_up(&runtime->sleep); | 1040 | wake_up(&runtime->sleep); |
| 1041 | wake_up(&runtime->tsleep); | ||
| 1005 | } else { | 1042 | } else { |
| 1006 | runtime->status->state = SNDRV_PCM_STATE_RUNNING; | 1043 | runtime->status->state = SNDRV_PCM_STATE_RUNNING; |
| 1007 | if (substream->timer) | 1044 | if (substream->timer) |
| @@ -1059,6 +1096,7 @@ static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state) | |||
| 1059 | runtime->status->suspended_state = runtime->status->state; | 1096 | runtime->status->suspended_state = runtime->status->state; |
| 1060 | runtime->status->state = SNDRV_PCM_STATE_SUSPENDED; | 1097 | runtime->status->state = SNDRV_PCM_STATE_SUSPENDED; |
| 1061 | wake_up(&runtime->sleep); | 1098 | wake_up(&runtime->sleep); |
| 1099 | wake_up(&runtime->tsleep); | ||
| 1062 | } | 1100 | } |
| 1063 | 1101 | ||
| 1064 | static struct action_ops snd_pcm_action_suspend = { | 1102 | static struct action_ops snd_pcm_action_suspend = { |
| @@ -3162,9 +3200,7 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, | |||
| 3162 | long size; | 3200 | long size; |
| 3163 | unsigned long offset; | 3201 | unsigned long offset; |
| 3164 | 3202 | ||
| 3165 | #ifdef pgprot_noncached | ||
| 3166 | area->vm_page_prot = pgprot_noncached(area->vm_page_prot); | 3203 | area->vm_page_prot = pgprot_noncached(area->vm_page_prot); |
| 3167 | #endif | ||
| 3168 | area->vm_flags |= VM_IO; | 3204 | area->vm_flags |= VM_IO; |
| 3169 | size = area->vm_end - area->vm_start; | 3205 | size = area->vm_end - area->vm_start; |
| 3170 | offset = area->vm_pgoff << PAGE_SHIFT; | 3206 | offset = area->vm_pgoff << PAGE_SHIFT; |
| @@ -3178,6 +3214,15 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, | |||
| 3178 | EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem); | 3214 | EXPORT_SYMBOL(snd_pcm_lib_mmap_iomem); |
| 3179 | #endif /* SNDRV_PCM_INFO_MMAP */ | 3215 | #endif /* SNDRV_PCM_INFO_MMAP */ |
| 3180 | 3216 | ||
| 3217 | /* mmap callback with pgprot_noncached */ | ||
| 3218 | int snd_pcm_lib_mmap_noncached(struct snd_pcm_substream *substream, | ||
| 3219 | struct vm_area_struct *area) | ||
| 3220 | { | ||
| 3221 | area->vm_page_prot = pgprot_noncached(area->vm_page_prot); | ||
| 3222 | return snd_pcm_default_mmap(substream, area); | ||
| 3223 | } | ||
| 3224 | EXPORT_SYMBOL(snd_pcm_lib_mmap_noncached); | ||
| 3225 | |||
| 3181 | /* | 3226 | /* |
| 3182 | * mmap DMA buffer | 3227 | * mmap DMA buffer |
| 3183 | */ | 3228 | */ |
diff --git a/sound/core/seq/seq_clientmgr.c b/sound/core/seq/seq_clientmgr.c index 8ca2be339f3b..48eca9ff9ee7 100644 --- a/sound/core/seq/seq_clientmgr.c +++ b/sound/core/seq/seq_clientmgr.c | |||
| @@ -2190,7 +2190,7 @@ static int snd_seq_do_ioctl(struct snd_seq_client *client, unsigned int cmd, | |||
| 2190 | if (p->cmd == cmd) | 2190 | if (p->cmd == cmd) |
| 2191 | return p->func(client, arg); | 2191 | return p->func(client, arg); |
| 2192 | } | 2192 | } |
| 2193 | snd_printd("seq unknown ioctl() 0x%x (type='%c', number=0x%2x)\n", | 2193 | snd_printd("seq unknown ioctl() 0x%x (type='%c', number=0x%02x)\n", |
| 2194 | cmd, _IOC_TYPE(cmd), _IOC_NR(cmd)); | 2194 | cmd, _IOC_TYPE(cmd), _IOC_NR(cmd)); |
| 2195 | return -ENOTTY; | 2195 | return -ENOTTY; |
| 2196 | } | 2196 | } |
diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index f745c317d6af..160b1bd0cd62 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c | |||
| @@ -33,22 +33,21 @@ | |||
| 33 | 33 | ||
| 34 | #define SKEW_BASE 0x10000 /* 16bit shift */ | 34 | #define SKEW_BASE 0x10000 /* 16bit shift */ |
| 35 | 35 | ||
| 36 | static void snd_seq_timer_set_tick_resolution(struct snd_seq_timer_tick *tick, | 36 | static void snd_seq_timer_set_tick_resolution(struct snd_seq_timer *tmr) |
| 37 | int tempo, int ppq) | ||
| 38 | { | 37 | { |
| 39 | if (tempo < 1000000) | 38 | if (tmr->tempo < 1000000) |
| 40 | tick->resolution = (tempo * 1000) / ppq; | 39 | tmr->tick.resolution = (tmr->tempo * 1000) / tmr->ppq; |
| 41 | else { | 40 | else { |
| 42 | /* might overflow.. */ | 41 | /* might overflow.. */ |
| 43 | unsigned int s; | 42 | unsigned int s; |
| 44 | s = tempo % ppq; | 43 | s = tmr->tempo % tmr->ppq; |
| 45 | s = (s * 1000) / ppq; | 44 | s = (s * 1000) / tmr->ppq; |
| 46 | tick->resolution = (tempo / ppq) * 1000; | 45 | tmr->tick.resolution = (tmr->tempo / tmr->ppq) * 1000; |
| 47 | tick->resolution += s; | 46 | tmr->tick.resolution += s; |
| 48 | } | 47 | } |
| 49 | if (tick->resolution <= 0) | 48 | if (tmr->tick.resolution <= 0) |
| 50 | tick->resolution = 1; | 49 | tmr->tick.resolution = 1; |
| 51 | snd_seq_timer_update_tick(tick, 0); | 50 | snd_seq_timer_update_tick(&tmr->tick, 0); |
| 52 | } | 51 | } |
| 53 | 52 | ||
| 54 | /* create new timer (constructor) */ | 53 | /* create new timer (constructor) */ |
| @@ -96,7 +95,7 @@ void snd_seq_timer_defaults(struct snd_seq_timer * tmr) | |||
| 96 | /* setup defaults */ | 95 | /* setup defaults */ |
| 97 | tmr->ppq = 96; /* 96 PPQ */ | 96 | tmr->ppq = 96; /* 96 PPQ */ |
| 98 | tmr->tempo = 500000; /* 120 BPM */ | 97 | tmr->tempo = 500000; /* 120 BPM */ |
| 99 | snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq); | 98 | snd_seq_timer_set_tick_resolution(tmr); |
| 100 | tmr->running = 0; | 99 | tmr->running = 0; |
| 101 | 100 | ||
| 102 | tmr->type = SNDRV_SEQ_TIMER_ALSA; | 101 | tmr->type = SNDRV_SEQ_TIMER_ALSA; |
| @@ -180,7 +179,7 @@ int snd_seq_timer_set_tempo(struct snd_seq_timer * tmr, int tempo) | |||
| 180 | spin_lock_irqsave(&tmr->lock, flags); | 179 | spin_lock_irqsave(&tmr->lock, flags); |
| 181 | if ((unsigned int)tempo != tmr->tempo) { | 180 | if ((unsigned int)tempo != tmr->tempo) { |
| 182 | tmr->tempo = tempo; | 181 | tmr->tempo = tempo; |
| 183 | snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq); | 182 | snd_seq_timer_set_tick_resolution(tmr); |
| 184 | } | 183 | } |
| 185 | spin_unlock_irqrestore(&tmr->lock, flags); | 184 | spin_unlock_irqrestore(&tmr->lock, flags); |
| 186 | return 0; | 185 | return 0; |
| @@ -205,7 +204,7 @@ int snd_seq_timer_set_ppq(struct snd_seq_timer * tmr, int ppq) | |||
| 205 | } | 204 | } |
| 206 | 205 | ||
| 207 | tmr->ppq = ppq; | 206 | tmr->ppq = ppq; |
| 208 | snd_seq_timer_set_tick_resolution(&tmr->tick, tmr->tempo, tmr->ppq); | 207 | snd_seq_timer_set_tick_resolution(tmr); |
| 209 | spin_unlock_irqrestore(&tmr->lock, flags); | 208 | spin_unlock_irqrestore(&tmr->lock, flags); |
| 210 | return 0; | 209 | return 0; |
| 211 | } | 210 | } |
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 252e04ce602f..7f41990ed68b 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c | |||
| @@ -45,109 +45,23 @@ MODULE_SUPPORTED_DEVICE("{{ALSA,Dummy soundcard}}"); | |||
| 45 | #define MAX_PCM_SUBSTREAMS 128 | 45 | #define MAX_PCM_SUBSTREAMS 128 |
| 46 | #define MAX_MIDI_DEVICES 2 | 46 | #define MAX_MIDI_DEVICES 2 |
| 47 | 47 | ||
| 48 | #if 0 /* emu10k1 emulation */ | ||
| 49 | #define MAX_BUFFER_SIZE (128 * 1024) | ||
| 50 | static int emu10k1_playback_constraints(struct snd_pcm_runtime *runtime) | ||
| 51 | { | ||
| 52 | int err; | ||
| 53 | err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); | ||
| 54 | if (err < 0) | ||
| 55 | return err; | ||
| 56 | err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX); | ||
| 57 | if (err < 0) | ||
| 58 | return err; | ||
| 59 | return 0; | ||
| 60 | } | ||
| 61 | #define add_playback_constraints emu10k1_playback_constraints | ||
| 62 | #endif | ||
| 63 | |||
| 64 | #if 0 /* RME9652 emulation */ | ||
| 65 | #define MAX_BUFFER_SIZE (26 * 64 * 1024) | ||
| 66 | #define USE_FORMATS SNDRV_PCM_FMTBIT_S32_LE | ||
| 67 | #define USE_CHANNELS_MIN 26 | ||
| 68 | #define USE_CHANNELS_MAX 26 | ||
| 69 | #define USE_PERIODS_MIN 2 | ||
| 70 | #define USE_PERIODS_MAX 2 | ||
| 71 | #endif | ||
| 72 | |||
| 73 | #if 0 /* ICE1712 emulation */ | ||
| 74 | #define MAX_BUFFER_SIZE (256 * 1024) | ||
| 75 | #define USE_FORMATS SNDRV_PCM_FMTBIT_S32_LE | ||
| 76 | #define USE_CHANNELS_MIN 10 | ||
| 77 | #define USE_CHANNELS_MAX 10 | ||
| 78 | #define USE_PERIODS_MIN 1 | ||
| 79 | #define USE_PERIODS_MAX 1024 | ||
| 80 | #endif | ||
| 81 | |||
| 82 | #if 0 /* UDA1341 emulation */ | ||
| 83 | #define MAX_BUFFER_SIZE (16380) | ||
| 84 | #define USE_FORMATS SNDRV_PCM_FMTBIT_S16_LE | ||
| 85 | #define USE_CHANNELS_MIN 2 | ||
| 86 | #define USE_CHANNELS_MAX 2 | ||
| 87 | #define USE_PERIODS_MIN 2 | ||
| 88 | #define USE_PERIODS_MAX 255 | ||
| 89 | #endif | ||
| 90 | |||
| 91 | #if 0 /* simple AC97 bridge (intel8x0) with 48kHz AC97 only codec */ | ||
| 92 | #define USE_FORMATS SNDRV_PCM_FMTBIT_S16_LE | ||
| 93 | #define USE_CHANNELS_MIN 2 | ||
| 94 | #define USE_CHANNELS_MAX 2 | ||
| 95 | #define USE_RATE SNDRV_PCM_RATE_48000 | ||
| 96 | #define USE_RATE_MIN 48000 | ||
| 97 | #define USE_RATE_MAX 48000 | ||
| 98 | #endif | ||
| 99 | |||
| 100 | #if 0 /* CA0106 */ | ||
| 101 | #define USE_FORMATS SNDRV_PCM_FMTBIT_S16_LE | ||
| 102 | #define USE_CHANNELS_MIN 2 | ||
| 103 | #define USE_CHANNELS_MAX 2 | ||
| 104 | #define USE_RATE (SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_96000|SNDRV_PCM_RATE_192000) | ||
| 105 | #define USE_RATE_MIN 48000 | ||
| 106 | #define USE_RATE_MAX 192000 | ||
| 107 | #define MAX_BUFFER_SIZE ((65536-64)*8) | ||
| 108 | #define MAX_PERIOD_SIZE (65536-64) | ||
| 109 | #define USE_PERIODS_MIN 2 | ||
| 110 | #define USE_PERIODS_MAX 8 | ||
| 111 | #endif | ||
| 112 | |||
| 113 | |||
| 114 | /* defaults */ | 48 | /* defaults */ |
| 115 | #ifndef MAX_BUFFER_SIZE | ||
| 116 | #define MAX_BUFFER_SIZE (64*1024) | 49 | #define MAX_BUFFER_SIZE (64*1024) |
| 117 | #endif | 50 | #define MIN_PERIOD_SIZE 64 |
| 118 | #ifndef MAX_PERIOD_SIZE | ||
| 119 | #define MAX_PERIOD_SIZE MAX_BUFFER_SIZE | 51 | #define MAX_PERIOD_SIZE MAX_BUFFER_SIZE |
| 120 | #endif | ||
| 121 | #ifndef USE_FORMATS | ||
| 122 | #define USE_FORMATS (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE) | 52 | #define USE_FORMATS (SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S16_LE) |
| 123 | #endif | ||
| 124 | #ifndef USE_RATE | ||
| 125 | #define USE_RATE SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000 | 53 | #define USE_RATE SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_8000_48000 |
| 126 | #define USE_RATE_MIN 5500 | 54 | #define USE_RATE_MIN 5500 |
| 127 | #define USE_RATE_MAX 48000 | 55 | #define USE_RATE_MAX 48000 |
| 128 | #endif | ||
| 129 | #ifndef USE_CHANNELS_MIN | ||
| 130 | #define USE_CHANNELS_MIN 1 | 56 | #define USE_CHANNELS_MIN 1 |
| 131 | #endif | ||
| 132 | #ifndef USE_CHANNELS_MAX | ||
| 133 | #define USE_CHANNELS_MAX 2 | 57 | #define USE_CHANNELS_MAX 2 |
| 134 | #endif | ||
| 135 | #ifndef USE_PERIODS_MIN | ||
| 136 | #define USE_PERIODS_MIN 1 | 58 | #define USE_PERIODS_MIN 1 |
| 137 | #endif | ||
| 138 | #ifndef USE_PERIODS_MAX | ||
| 139 | #define USE_PERIODS_MAX 1024 | 59 | #define USE_PERIODS_MAX 1024 |
| 140 | #endif | ||
| 141 | #ifndef add_playback_constraints | ||
| 142 | #define add_playback_constraints(x) 0 | ||
| 143 | #endif | ||
| 144 | #ifndef add_capture_constraints | ||
| 145 | #define add_capture_constraints(x) 0 | ||
| 146 | #endif | ||
| 147 | 60 | ||
| 148 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | 61 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ |
| 149 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | 62 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ |
| 150 | static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0}; | 63 | static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 0}; |
| 64 | static char *model[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = NULL}; | ||
| 151 | static int pcm_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; | 65 | static int pcm_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 1}; |
| 152 | static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8}; | 66 | static int pcm_substreams[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 8}; |
| 153 | //static int midi_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2}; | 67 | //static int midi_devs[SNDRV_CARDS] = {[0 ... (SNDRV_CARDS - 1)] = 2}; |
| @@ -162,6 +76,8 @@ module_param_array(id, charp, NULL, 0444); | |||
| 162 | MODULE_PARM_DESC(id, "ID string for dummy soundcard."); | 76 | MODULE_PARM_DESC(id, "ID string for dummy soundcard."); |
| 163 | module_param_array(enable, bool, NULL, 0444); | 77 | module_param_array(enable, bool, NULL, 0444); |
| 164 | MODULE_PARM_DESC(enable, "Enable this dummy soundcard."); | 78 | MODULE_PARM_DESC(enable, "Enable this dummy soundcard."); |
| 79 | module_param_array(model, charp, NULL, 0444); | ||
| 80 | MODULE_PARM_DESC(model, "Soundcard model."); | ||
| 165 | module_param_array(pcm_devs, int, NULL, 0444); | 81 | module_param_array(pcm_devs, int, NULL, 0444); |
| 166 | MODULE_PARM_DESC(pcm_devs, "PCM devices # (0-4) for dummy driver."); | 82 | MODULE_PARM_DESC(pcm_devs, "PCM devices # (0-4) for dummy driver."); |
| 167 | module_param_array(pcm_substreams, int, NULL, 0444); | 83 | module_param_array(pcm_substreams, int, NULL, 0444); |
| @@ -193,9 +109,28 @@ struct dummy_timer_ops { | |||
| 193 | snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *); | 109 | snd_pcm_uframes_t (*pointer)(struct snd_pcm_substream *); |
| 194 | }; | 110 | }; |
| 195 | 111 | ||
| 112 | struct dummy_model { | ||
| 113 | const char *name; | ||
| 114 | int (*playback_constraints)(struct snd_pcm_runtime *runtime); | ||
| 115 | int (*capture_constraints)(struct snd_pcm_runtime *runtime); | ||
| 116 | u64 formats; | ||
| 117 | size_t buffer_bytes_max; | ||
| 118 | size_t period_bytes_min; | ||
| 119 | size_t period_bytes_max; | ||
| 120 | unsigned int periods_min; | ||
| 121 | unsigned int periods_max; | ||
| 122 | unsigned int rates; | ||
| 123 | unsigned int rate_min; | ||
| 124 | unsigned int rate_max; | ||
| 125 | unsigned int channels_min; | ||
| 126 | unsigned int channels_max; | ||
| 127 | }; | ||
| 128 | |||
| 196 | struct snd_dummy { | 129 | struct snd_dummy { |
| 197 | struct snd_card *card; | 130 | struct snd_card *card; |
| 131 | struct dummy_model *model; | ||
| 198 | struct snd_pcm *pcm; | 132 | struct snd_pcm *pcm; |
| 133 | struct snd_pcm_hardware pcm_hw; | ||
| 199 | spinlock_t mixer_lock; | 134 | spinlock_t mixer_lock; |
| 200 | int mixer_volume[MIXER_ADDR_LAST+1][2]; | 135 | int mixer_volume[MIXER_ADDR_LAST+1][2]; |
| 201 | int capture_source[MIXER_ADDR_LAST+1][2]; | 136 | int capture_source[MIXER_ADDR_LAST+1][2]; |
| @@ -203,6 +138,92 @@ struct snd_dummy { | |||
| 203 | }; | 138 | }; |
| 204 | 139 | ||
| 205 | /* | 140 | /* |
| 141 | * card models | ||
| 142 | */ | ||
| 143 | |||
| 144 | static int emu10k1_playback_constraints(struct snd_pcm_runtime *runtime) | ||
| 145 | { | ||
| 146 | int err; | ||
| 147 | err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS); | ||
| 148 | if (err < 0) | ||
| 149 | return err; | ||
| 150 | err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 256, UINT_MAX); | ||
| 151 | if (err < 0) | ||
| 152 | return err; | ||
| 153 | return 0; | ||
| 154 | } | ||
| 155 | |||
| 156 | struct dummy_model model_emu10k1 = { | ||
| 157 | .name = "emu10k1", | ||
| 158 | .playback_constraints = emu10k1_playback_constraints, | ||
| 159 | .buffer_bytes_max = 128 * 1024, | ||
| 160 | }; | ||
| 161 | |||
| 162 | struct dummy_model model_rme9652 = { | ||
| 163 | .name = "rme9652", | ||
| 164 | .buffer_bytes_max = 26 * 64 * 1024, | ||
| 165 | .formats = SNDRV_PCM_FMTBIT_S32_LE, | ||
| 166 | .channels_min = 26, | ||
| 167 | .channels_max = 26, | ||
| 168 | .periods_min = 2, | ||
| 169 | .periods_max = 2, | ||
| 170 | }; | ||
| 171 | |||
| 172 | struct dummy_model model_ice1712 = { | ||
| 173 | .name = "ice1712", | ||
| 174 | .buffer_bytes_max = 256 * 1024, | ||
| 175 | .formats = SNDRV_PCM_FMTBIT_S32_LE, | ||
| 176 | .channels_min = 10, | ||
| 177 | .channels_max = 10, | ||
| 178 | .periods_min = 1, | ||
| 179 | .periods_max = 1024, | ||
| 180 | }; | ||
| 181 | |||
| 182 | struct dummy_model model_uda1341 = { | ||
| 183 | .name = "uda1341", | ||
| 184 | .buffer_bytes_max = 16380, | ||
| 185 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
| 186 | .channels_min = 2, | ||
| 187 | .channels_max = 2, | ||
| 188 | .periods_min = 2, | ||
| 189 | .periods_max = 255, | ||
| 190 | }; | ||
| 191 | |||
| 192 | struct dummy_model model_ac97 = { | ||
| 193 | .name = "ac97", | ||
| 194 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
| 195 | .channels_min = 2, | ||
| 196 | .channels_max = 2, | ||
| 197 | .rates = SNDRV_PCM_RATE_48000, | ||
| 198 | .rate_min = 48000, | ||
| 199 | .rate_max = 48000, | ||
| 200 | }; | ||
| 201 | |||
| 202 | struct dummy_model model_ca0106 = { | ||
| 203 | .name = "ca0106", | ||
| 204 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
| 205 | .buffer_bytes_max = ((65536-64)*8), | ||
| 206 | .period_bytes_max = (65536-64), | ||
| 207 | .periods_min = 2, | ||
| 208 | .periods_max = 8, | ||
| 209 | .channels_min = 2, | ||
| 210 | .channels_max = 2, | ||
| 211 | .rates = SNDRV_PCM_RATE_48000|SNDRV_PCM_RATE_96000|SNDRV_PCM_RATE_192000, | ||
| 212 | .rate_min = 48000, | ||
| 213 | .rate_max = 192000, | ||
| 214 | }; | ||
| 215 | |||
| 216 | struct dummy_model *dummy_models[] = { | ||
| 217 | &model_emu10k1, | ||
| 218 | &model_rme9652, | ||
| 219 | &model_ice1712, | ||
| 220 | &model_uda1341, | ||
| 221 | &model_ac97, | ||
| 222 | &model_ca0106, | ||
| 223 | NULL | ||
| 224 | }; | ||
| 225 | |||
| 226 | /* | ||
| 206 | * system timer interface | 227 | * system timer interface |
| 207 | */ | 228 | */ |
| 208 | 229 | ||
| @@ -509,7 +530,7 @@ static struct snd_pcm_hardware dummy_pcm_hardware = { | |||
| 509 | .channels_min = USE_CHANNELS_MIN, | 530 | .channels_min = USE_CHANNELS_MIN, |
| 510 | .channels_max = USE_CHANNELS_MAX, | 531 | .channels_max = USE_CHANNELS_MAX, |
| 511 | .buffer_bytes_max = MAX_BUFFER_SIZE, | 532 | .buffer_bytes_max = MAX_BUFFER_SIZE, |
| 512 | .period_bytes_min = 64, | 533 | .period_bytes_min = MIN_PERIOD_SIZE, |
| 513 | .period_bytes_max = MAX_PERIOD_SIZE, | 534 | .period_bytes_max = MAX_PERIOD_SIZE, |
| 514 | .periods_min = USE_PERIODS_MIN, | 535 | .periods_min = USE_PERIODS_MIN, |
| 515 | .periods_max = USE_PERIODS_MAX, | 536 | .periods_max = USE_PERIODS_MAX, |
| @@ -538,6 +559,7 @@ static int dummy_pcm_hw_free(struct snd_pcm_substream *substream) | |||
| 538 | static int dummy_pcm_open(struct snd_pcm_substream *substream) | 559 | static int dummy_pcm_open(struct snd_pcm_substream *substream) |
| 539 | { | 560 | { |
| 540 | struct snd_dummy *dummy = snd_pcm_substream_chip(substream); | 561 | struct snd_dummy *dummy = snd_pcm_substream_chip(substream); |
| 562 | struct dummy_model *model = dummy->model; | ||
| 541 | struct snd_pcm_runtime *runtime = substream->runtime; | 563 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 542 | int err; | 564 | int err; |
| 543 | 565 | ||
| @@ -551,7 +573,7 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream) | |||
| 551 | if (err < 0) | 573 | if (err < 0) |
| 552 | return err; | 574 | return err; |
| 553 | 575 | ||
| 554 | runtime->hw = dummy_pcm_hardware; | 576 | runtime->hw = dummy->pcm_hw; |
| 555 | if (substream->pcm->device & 1) { | 577 | if (substream->pcm->device & 1) { |
| 556 | runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED; | 578 | runtime->hw.info &= ~SNDRV_PCM_INFO_INTERLEAVED; |
| 557 | runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED; | 579 | runtime->hw.info |= SNDRV_PCM_INFO_NONINTERLEAVED; |
| @@ -560,10 +582,16 @@ static int dummy_pcm_open(struct snd_pcm_substream *substream) | |||
| 560 | runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP | | 582 | runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP | |
| 561 | SNDRV_PCM_INFO_MMAP_VALID); | 583 | SNDRV_PCM_INFO_MMAP_VALID); |
| 562 | 584 | ||
| 563 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 585 | if (model == NULL) |
| 564 | err = add_playback_constraints(substream->runtime); | 586 | return 0; |
| 565 | else | 587 | |
| 566 | err = add_capture_constraints(substream->runtime); | 588 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { |
| 589 | if (model->playback_constraints) | ||
| 590 | err = model->playback_constraints(substream->runtime); | ||
| 591 | } else { | ||
| 592 | if (model->capture_constraints) | ||
| 593 | err = model->capture_constraints(substream->runtime); | ||
| 594 | } | ||
| 567 | if (err < 0) { | 595 | if (err < 0) { |
| 568 | dummy->timer_ops->free(substream); | 596 | dummy->timer_ops->free(substream); |
| 569 | return err; | 597 | return err; |
| @@ -823,17 +851,19 @@ static int __devinit snd_card_dummy_new_mixer(struct snd_dummy *dummy) | |||
| 823 | /* | 851 | /* |
| 824 | * proc interface | 852 | * proc interface |
| 825 | */ | 853 | */ |
| 826 | static void print_formats(struct snd_info_buffer *buffer) | 854 | static void print_formats(struct snd_dummy *dummy, |
| 855 | struct snd_info_buffer *buffer) | ||
| 827 | { | 856 | { |
| 828 | int i; | 857 | int i; |
| 829 | 858 | ||
| 830 | for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) { | 859 | for (i = 0; i < SNDRV_PCM_FORMAT_LAST; i++) { |
| 831 | if (dummy_pcm_hardware.formats & (1ULL << i)) | 860 | if (dummy->pcm_hw.formats & (1ULL << i)) |
| 832 | snd_iprintf(buffer, " %s", snd_pcm_format_name(i)); | 861 | snd_iprintf(buffer, " %s", snd_pcm_format_name(i)); |
| 833 | } | 862 | } |
| 834 | } | 863 | } |
| 835 | 864 | ||
| 836 | static void print_rates(struct snd_info_buffer *buffer) | 865 | static void print_rates(struct snd_dummy *dummy, |
| 866 | struct snd_info_buffer *buffer) | ||
| 837 | { | 867 | { |
| 838 | static int rates[] = { | 868 | static int rates[] = { |
| 839 | 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, | 869 | 5512, 8000, 11025, 16000, 22050, 32000, 44100, 48000, |
| @@ -841,19 +871,19 @@ static void print_rates(struct snd_info_buffer *buffer) | |||
| 841 | }; | 871 | }; |
| 842 | int i; | 872 | int i; |
| 843 | 873 | ||
| 844 | if (dummy_pcm_hardware.rates & SNDRV_PCM_RATE_CONTINUOUS) | 874 | if (dummy->pcm_hw.rates & SNDRV_PCM_RATE_CONTINUOUS) |
| 845 | snd_iprintf(buffer, " continuous"); | 875 | snd_iprintf(buffer, " continuous"); |
| 846 | if (dummy_pcm_hardware.rates & SNDRV_PCM_RATE_KNOT) | 876 | if (dummy->pcm_hw.rates & SNDRV_PCM_RATE_KNOT) |
| 847 | snd_iprintf(buffer, " knot"); | 877 | snd_iprintf(buffer, " knot"); |
| 848 | for (i = 0; i < ARRAY_SIZE(rates); i++) | 878 | for (i = 0; i < ARRAY_SIZE(rates); i++) |
| 849 | if (dummy_pcm_hardware.rates & (1 << i)) | 879 | if (dummy->pcm_hw.rates & (1 << i)) |
| 850 | snd_iprintf(buffer, " %d", rates[i]); | 880 | snd_iprintf(buffer, " %d", rates[i]); |
| 851 | } | 881 | } |
| 852 | 882 | ||
| 853 | #define get_dummy_int_ptr(ofs) \ | 883 | #define get_dummy_int_ptr(dummy, ofs) \ |
| 854 | (unsigned int *)((char *)&dummy_pcm_hardware + (ofs)) | 884 | (unsigned int *)((char *)&((dummy)->pcm_hw) + (ofs)) |
| 855 | #define get_dummy_ll_ptr(ofs) \ | 885 | #define get_dummy_ll_ptr(dummy, ofs) \ |
| 856 | (unsigned long long *)((char *)&dummy_pcm_hardware + (ofs)) | 886 | (unsigned long long *)((char *)&((dummy)->pcm_hw) + (ofs)) |
| 857 | 887 | ||
| 858 | struct dummy_hw_field { | 888 | struct dummy_hw_field { |
| 859 | const char *name; | 889 | const char *name; |
| @@ -884,20 +914,21 @@ static struct dummy_hw_field fields[] = { | |||
| 884 | static void dummy_proc_read(struct snd_info_entry *entry, | 914 | static void dummy_proc_read(struct snd_info_entry *entry, |
| 885 | struct snd_info_buffer *buffer) | 915 | struct snd_info_buffer *buffer) |
| 886 | { | 916 | { |
| 917 | struct snd_dummy *dummy = entry->private_data; | ||
| 887 | int i; | 918 | int i; |
| 888 | 919 | ||
| 889 | for (i = 0; i < ARRAY_SIZE(fields); i++) { | 920 | for (i = 0; i < ARRAY_SIZE(fields); i++) { |
| 890 | snd_iprintf(buffer, "%s ", fields[i].name); | 921 | snd_iprintf(buffer, "%s ", fields[i].name); |
| 891 | if (fields[i].size == sizeof(int)) | 922 | if (fields[i].size == sizeof(int)) |
| 892 | snd_iprintf(buffer, fields[i].format, | 923 | snd_iprintf(buffer, fields[i].format, |
| 893 | *get_dummy_int_ptr(fields[i].offset)); | 924 | *get_dummy_int_ptr(dummy, fields[i].offset)); |
| 894 | else | 925 | else |
| 895 | snd_iprintf(buffer, fields[i].format, | 926 | snd_iprintf(buffer, fields[i].format, |
| 896 | *get_dummy_ll_ptr(fields[i].offset)); | 927 | *get_dummy_ll_ptr(dummy, fields[i].offset)); |
| 897 | if (!strcmp(fields[i].name, "formats")) | 928 | if (!strcmp(fields[i].name, "formats")) |
| 898 | print_formats(buffer); | 929 | print_formats(dummy, buffer); |
| 899 | else if (!strcmp(fields[i].name, "rates")) | 930 | else if (!strcmp(fields[i].name, "rates")) |
| 900 | print_rates(buffer); | 931 | print_rates(dummy, buffer); |
| 901 | snd_iprintf(buffer, "\n"); | 932 | snd_iprintf(buffer, "\n"); |
| 902 | } | 933 | } |
| 903 | } | 934 | } |
| @@ -905,6 +936,7 @@ static void dummy_proc_read(struct snd_info_entry *entry, | |||
| 905 | static void dummy_proc_write(struct snd_info_entry *entry, | 936 | static void dummy_proc_write(struct snd_info_entry *entry, |
| 906 | struct snd_info_buffer *buffer) | 937 | struct snd_info_buffer *buffer) |
| 907 | { | 938 | { |
| 939 | struct snd_dummy *dummy = entry->private_data; | ||
| 908 | char line[64]; | 940 | char line[64]; |
| 909 | 941 | ||
| 910 | while (!snd_info_get_line(buffer, line, sizeof(line))) { | 942 | while (!snd_info_get_line(buffer, line, sizeof(line))) { |
| @@ -924,9 +956,9 @@ static void dummy_proc_write(struct snd_info_entry *entry, | |||
| 924 | if (strict_strtoull(item, 0, &val)) | 956 | if (strict_strtoull(item, 0, &val)) |
| 925 | continue; | 957 | continue; |
| 926 | if (fields[i].size == sizeof(int)) | 958 | if (fields[i].size == sizeof(int)) |
| 927 | *get_dummy_int_ptr(fields[i].offset) = val; | 959 | *get_dummy_int_ptr(dummy, fields[i].offset) = val; |
| 928 | else | 960 | else |
| 929 | *get_dummy_ll_ptr(fields[i].offset) = val; | 961 | *get_dummy_ll_ptr(dummy, fields[i].offset) = val; |
| 930 | } | 962 | } |
| 931 | } | 963 | } |
| 932 | 964 | ||
| @@ -938,6 +970,7 @@ static void __devinit dummy_proc_init(struct snd_dummy *chip) | |||
| 938 | snd_info_set_text_ops(entry, chip, dummy_proc_read); | 970 | snd_info_set_text_ops(entry, chip, dummy_proc_read); |
| 939 | entry->c.text.write = dummy_proc_write; | 971 | entry->c.text.write = dummy_proc_write; |
| 940 | entry->mode |= S_IWUSR; | 972 | entry->mode |= S_IWUSR; |
| 973 | entry->private_data = chip; | ||
| 941 | } | 974 | } |
| 942 | } | 975 | } |
| 943 | #else | 976 | #else |
| @@ -948,6 +981,7 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr) | |||
| 948 | { | 981 | { |
| 949 | struct snd_card *card; | 982 | struct snd_card *card; |
| 950 | struct snd_dummy *dummy; | 983 | struct snd_dummy *dummy; |
| 984 | struct dummy_model *m = NULL, **mdl; | ||
| 951 | int idx, err; | 985 | int idx, err; |
| 952 | int dev = devptr->id; | 986 | int dev = devptr->id; |
| 953 | 987 | ||
| @@ -957,6 +991,15 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr) | |||
| 957 | return err; | 991 | return err; |
| 958 | dummy = card->private_data; | 992 | dummy = card->private_data; |
| 959 | dummy->card = card; | 993 | dummy->card = card; |
| 994 | for (mdl = dummy_models; *mdl && model[dev]; mdl++) { | ||
| 995 | if (strcmp(model[dev], (*mdl)->name) == 0) { | ||
| 996 | printk(KERN_INFO | ||
| 997 | "snd-dummy: Using model '%s' for card %i\n", | ||
| 998 | (*mdl)->name, card->number); | ||
| 999 | m = dummy->model = *mdl; | ||
| 1000 | break; | ||
| 1001 | } | ||
| 1002 | } | ||
| 960 | for (idx = 0; idx < MAX_PCM_DEVICES && idx < pcm_devs[dev]; idx++) { | 1003 | for (idx = 0; idx < MAX_PCM_DEVICES && idx < pcm_devs[dev]; idx++) { |
| 961 | if (pcm_substreams[dev] < 1) | 1004 | if (pcm_substreams[dev] < 1) |
| 962 | pcm_substreams[dev] = 1; | 1005 | pcm_substreams[dev] = 1; |
| @@ -966,6 +1009,33 @@ static int __devinit snd_dummy_probe(struct platform_device *devptr) | |||
| 966 | if (err < 0) | 1009 | if (err < 0) |
| 967 | goto __nodev; | 1010 | goto __nodev; |
| 968 | } | 1011 | } |
| 1012 | |||
| 1013 | dummy->pcm_hw = dummy_pcm_hardware; | ||
| 1014 | if (m) { | ||
| 1015 | if (m->formats) | ||
| 1016 | dummy->pcm_hw.formats = m->formats; | ||
| 1017 | if (m->buffer_bytes_max) | ||
| 1018 | dummy->pcm_hw.buffer_bytes_max = m->buffer_bytes_max; | ||
| 1019 | if (m->period_bytes_min) | ||
| 1020 | dummy->pcm_hw.period_bytes_min = m->period_bytes_min; | ||
| 1021 | if (m->period_bytes_max) | ||
| 1022 | dummy->pcm_hw.period_bytes_max = m->period_bytes_max; | ||
| 1023 | if (m->periods_min) | ||
| 1024 | dummy->pcm_hw.periods_min = m->periods_min; | ||
| 1025 | if (m->periods_max) | ||
| 1026 | dummy->pcm_hw.periods_max = m->periods_max; | ||
| 1027 | if (m->rates) | ||
| 1028 | dummy->pcm_hw.rates = m->rates; | ||
| 1029 | if (m->rate_min) | ||
| 1030 | dummy->pcm_hw.rate_min = m->rate_min; | ||
| 1031 | if (m->rate_max) | ||
| 1032 | dummy->pcm_hw.rate_max = m->rate_max; | ||
| 1033 | if (m->channels_min) | ||
| 1034 | dummy->pcm_hw.channels_min = m->channels_min; | ||
| 1035 | if (m->channels_max) | ||
| 1036 | dummy->pcm_hw.channels_max = m->channels_max; | ||
| 1037 | } | ||
| 1038 | |||
| 969 | err = snd_card_dummy_new_mixer(dummy); | 1039 | err = snd_card_dummy_new_mixer(dummy); |
| 970 | if (err < 0) | 1040 | if (err < 0) |
| 971 | goto __nodev; | 1041 | goto __nodev; |
diff --git a/sound/drivers/vx/vx_pcm.c b/sound/drivers/vx/vx_pcm.c index 6644d0034fba..35a2f71a6af5 100644 --- a/sound/drivers/vx/vx_pcm.c +++ b/sound/drivers/vx/vx_pcm.c | |||
| @@ -46,7 +46,6 @@ | |||
| 46 | */ | 46 | */ |
| 47 | 47 | ||
| 48 | #include <linux/slab.h> | 48 | #include <linux/slab.h> |
| 49 | #include <linux/vmalloc.h> | ||
| 50 | #include <linux/delay.h> | 49 | #include <linux/delay.h> |
| 51 | #include <sound/core.h> | 50 | #include <sound/core.h> |
| 52 | #include <sound/asoundef.h> | 51 | #include <sound/asoundef.h> |
| @@ -56,55 +55,6 @@ | |||
| 56 | 55 | ||
| 57 | 56 | ||
| 58 | /* | 57 | /* |
| 59 | * we use a vmalloc'ed (sg-)buffer | ||
| 60 | */ | ||
| 61 | |||
| 62 | /* get the physical page pointer on the given offset */ | ||
| 63 | static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, | ||
| 64 | unsigned long offset) | ||
| 65 | { | ||
| 66 | void *pageptr = subs->runtime->dma_area + offset; | ||
| 67 | return vmalloc_to_page(pageptr); | ||
| 68 | } | ||
| 69 | |||
| 70 | /* | ||
| 71 | * allocate a buffer via vmalloc_32(). | ||
| 72 | * called from hw_params | ||
| 73 | * NOTE: this may be called not only once per pcm open! | ||
| 74 | */ | ||
| 75 | static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t size) | ||
| 76 | { | ||
| 77 | struct snd_pcm_runtime *runtime = subs->runtime; | ||
| 78 | if (runtime->dma_area) { | ||
| 79 | /* already allocated */ | ||
| 80 | if (runtime->dma_bytes >= size) | ||
| 81 | return 0; /* already enough large */ | ||
| 82 | vfree(runtime->dma_area); | ||
| 83 | } | ||
| 84 | runtime->dma_area = vmalloc_32(size); | ||
| 85 | if (! runtime->dma_area) | ||
| 86 | return -ENOMEM; | ||
| 87 | memset(runtime->dma_area, 0, size); | ||
| 88 | runtime->dma_bytes = size; | ||
| 89 | return 1; /* changed */ | ||
| 90 | } | ||
| 91 | |||
| 92 | /* | ||
| 93 | * free the buffer. | ||
| 94 | * called from hw_free callback | ||
| 95 | * NOTE: this may be called not only once per pcm open! | ||
| 96 | */ | ||
| 97 | static int snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs) | ||
| 98 | { | ||
| 99 | struct snd_pcm_runtime *runtime = subs->runtime; | ||
| 100 | |||
| 101 | vfree(runtime->dma_area); | ||
| 102 | runtime->dma_area = NULL; | ||
| 103 | return 0; | ||
| 104 | } | ||
| 105 | |||
| 106 | |||
| 107 | /* | ||
| 108 | * read three pending pcm bytes via inb() | 58 | * read three pending pcm bytes via inb() |
| 109 | */ | 59 | */ |
| 110 | static void vx_pcm_read_per_bytes(struct vx_core *chip, struct snd_pcm_runtime *runtime, | 60 | static void vx_pcm_read_per_bytes(struct vx_core *chip, struct snd_pcm_runtime *runtime, |
| @@ -865,7 +815,8 @@ static snd_pcm_uframes_t vx_pcm_playback_pointer(struct snd_pcm_substream *subs) | |||
| 865 | static int vx_pcm_hw_params(struct snd_pcm_substream *subs, | 815 | static int vx_pcm_hw_params(struct snd_pcm_substream *subs, |
| 866 | struct snd_pcm_hw_params *hw_params) | 816 | struct snd_pcm_hw_params *hw_params) |
| 867 | { | 817 | { |
| 868 | return snd_pcm_alloc_vmalloc_buffer(subs, params_buffer_bytes(hw_params)); | 818 | return snd_pcm_lib_alloc_vmalloc_32_buffer |
| 819 | (subs, params_buffer_bytes(hw_params)); | ||
| 869 | } | 820 | } |
| 870 | 821 | ||
| 871 | /* | 822 | /* |
| @@ -873,7 +824,7 @@ static int vx_pcm_hw_params(struct snd_pcm_substream *subs, | |||
| 873 | */ | 824 | */ |
| 874 | static int vx_pcm_hw_free(struct snd_pcm_substream *subs) | 825 | static int vx_pcm_hw_free(struct snd_pcm_substream *subs) |
| 875 | { | 826 | { |
| 876 | return snd_pcm_free_vmalloc_buffer(subs); | 827 | return snd_pcm_lib_free_vmalloc_buffer(subs); |
| 877 | } | 828 | } |
| 878 | 829 | ||
| 879 | /* | 830 | /* |
| @@ -953,7 +904,8 @@ static struct snd_pcm_ops vx_pcm_playback_ops = { | |||
| 953 | .prepare = vx_pcm_prepare, | 904 | .prepare = vx_pcm_prepare, |
| 954 | .trigger = vx_pcm_trigger, | 905 | .trigger = vx_pcm_trigger, |
| 955 | .pointer = vx_pcm_playback_pointer, | 906 | .pointer = vx_pcm_playback_pointer, |
| 956 | .page = snd_pcm_get_vmalloc_page, | 907 | .page = snd_pcm_lib_get_vmalloc_page, |
| 908 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
| 957 | }; | 909 | }; |
| 958 | 910 | ||
| 959 | 911 | ||
| @@ -1173,7 +1125,8 @@ static struct snd_pcm_ops vx_pcm_capture_ops = { | |||
| 1173 | .prepare = vx_pcm_prepare, | 1125 | .prepare = vx_pcm_prepare, |
| 1174 | .trigger = vx_pcm_trigger, | 1126 | .trigger = vx_pcm_trigger, |
| 1175 | .pointer = vx_pcm_capture_pointer, | 1127 | .pointer = vx_pcm_capture_pointer, |
| 1176 | .page = snd_pcm_get_vmalloc_page, | 1128 | .page = snd_pcm_lib_get_vmalloc_page, |
| 1129 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
| 1177 | }; | 1130 | }; |
| 1178 | 1131 | ||
| 1179 | 1132 | ||
diff --git a/sound/isa/Kconfig b/sound/isa/Kconfig index 02fe81ca88fd..755a0a5f0e3f 100644 --- a/sound/isa/Kconfig +++ b/sound/isa/Kconfig | |||
| @@ -63,15 +63,16 @@ config SND_AD1848 | |||
| 63 | will be called snd-ad1848. | 63 | will be called snd-ad1848. |
| 64 | 64 | ||
| 65 | config SND_ALS100 | 65 | config SND_ALS100 |
| 66 | tristate "Avance Logic ALS100/ALS120" | 66 | tristate "Diamond Tech. DT-019x and Avance Logic ALSxxx" |
| 67 | depends on PNP | 67 | depends on PNP |
| 68 | select ISAPNP | 68 | select ISAPNP |
| 69 | select SND_OPL3_LIB | 69 | select SND_OPL3_LIB |
| 70 | select SND_MPU401_UART | 70 | select SND_MPU401_UART |
| 71 | select SND_SB16_DSP | 71 | select SND_SB16_DSP |
| 72 | help | 72 | help |
| 73 | Say Y here to include support for soundcards based on Avance | 73 | Say Y here to include support for soundcards based on the |
| 74 | Logic ALS100, ALS110, ALS120 and ALS200 chips. | 74 | Diamond Technologies DT-019X or Avance Logic chips: ALS007, |
| 75 | ALS100, ALS110, ALS120 and ALS200 chips. | ||
| 75 | 76 | ||
| 76 | To compile this driver as a module, choose M here: the module | 77 | To compile this driver as a module, choose M here: the module |
| 77 | will be called snd-als100. | 78 | will be called snd-als100. |
| @@ -127,20 +128,6 @@ config SND_CS4236 | |||
| 127 | To compile this driver as a module, choose M here: the module | 128 | To compile this driver as a module, choose M here: the module |
| 128 | will be called snd-cs4236. | 129 | will be called snd-cs4236. |
| 129 | 130 | ||
| 130 | config SND_DT019X | ||
| 131 | tristate "Diamond Technologies DT-019X, Avance Logic ALS-007" | ||
| 132 | depends on PNP | ||
| 133 | select ISAPNP | ||
| 134 | select SND_OPL3_LIB | ||
| 135 | select SND_MPU401_UART | ||
| 136 | select SND_SB16_DSP | ||
| 137 | help | ||
| 138 | Say Y here to include support for soundcards based on the | ||
| 139 | Diamond Technologies DT-019X or Avance Logic ALS-007 chips. | ||
| 140 | |||
| 141 | To compile this driver as a module, choose M here: the module | ||
| 142 | will be called snd-dt019x. | ||
| 143 | |||
| 144 | config SND_ES968 | 131 | config SND_ES968 |
| 145 | tristate "Generic ESS ES968 driver" | 132 | tristate "Generic ESS ES968 driver" |
| 146 | depends on PNP | 133 | depends on PNP |
| @@ -252,6 +239,22 @@ config SND_INTERWAVE_STB | |||
| 252 | To compile this driver as a module, choose M here: the module | 239 | To compile this driver as a module, choose M here: the module |
| 253 | will be called snd-interwave-stb. | 240 | will be called snd-interwave-stb. |
| 254 | 241 | ||
| 242 | config SND_JAZZ16 | ||
| 243 | tristate "Media Vision Jazz16 card and compatibles" | ||
| 244 | select SND_OPL3_LIB | ||
| 245 | select SND_MPU401_UART | ||
| 246 | select SND_SB8_DSP | ||
| 247 | help | ||
| 248 | Say Y here to include support for soundcards based on the | ||
| 249 | Media Vision Jazz16 chipset: digital chip MVD1216 (Jazz16), | ||
| 250 | codec MVA416 (CS4216) and mixer MVA514 (ICS2514). | ||
| 251 | Media Vision's Jazz16 cards were sold under names Pro Sonic 16, | ||
| 252 | Premium 3-D and Pro 3-D. There were also OEMs cards with the | ||
| 253 | Jazz16 chipset. | ||
| 254 | |||
| 255 | To compile this driver as a module, choose M here: the module | ||
| 256 | will be called snd-jazz16. | ||
| 257 | |||
| 255 | config SND_OPL3SA2 | 258 | config SND_OPL3SA2 |
| 256 | tristate "Yamaha OPL3-SA2/SA3" | 259 | tristate "Yamaha OPL3-SA2/SA3" |
| 257 | select SND_OPL3_LIB | 260 | select SND_OPL3_LIB |
diff --git a/sound/isa/Makefile b/sound/isa/Makefile index b906b9a1a81e..c73d30c4f462 100644 --- a/sound/isa/Makefile +++ b/sound/isa/Makefile | |||
| @@ -7,7 +7,6 @@ snd-adlib-objs := adlib.o | |||
| 7 | snd-als100-objs := als100.o | 7 | snd-als100-objs := als100.o |
| 8 | snd-azt2320-objs := azt2320.o | 8 | snd-azt2320-objs := azt2320.o |
| 9 | snd-cmi8330-objs := cmi8330.o | 9 | snd-cmi8330-objs := cmi8330.o |
| 10 | snd-dt019x-objs := dt019x.o | ||
| 11 | snd-es18xx-objs := es18xx.o | 10 | snd-es18xx-objs := es18xx.o |
| 12 | snd-opl3sa2-objs := opl3sa2.o | 11 | snd-opl3sa2-objs := opl3sa2.o |
| 13 | snd-sc6000-objs := sc6000.o | 12 | snd-sc6000-objs := sc6000.o |
| @@ -19,7 +18,6 @@ obj-$(CONFIG_SND_ADLIB) += snd-adlib.o | |||
| 19 | obj-$(CONFIG_SND_ALS100) += snd-als100.o | 18 | obj-$(CONFIG_SND_ALS100) += snd-als100.o |
| 20 | obj-$(CONFIG_SND_AZT2320) += snd-azt2320.o | 19 | obj-$(CONFIG_SND_AZT2320) += snd-azt2320.o |
| 21 | obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o | 20 | obj-$(CONFIG_SND_CMI8330) += snd-cmi8330.o |
| 22 | obj-$(CONFIG_SND_DT019X) += snd-dt019x.o | ||
| 23 | obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o | 21 | obj-$(CONFIG_SND_ES18XX) += snd-es18xx.o |
| 24 | obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o | 22 | obj-$(CONFIG_SND_OPL3SA2) += snd-opl3sa2.o |
| 25 | obj-$(CONFIG_SND_SC6000) += snd-sc6000.o | 23 | obj-$(CONFIG_SND_SC6000) += snd-sc6000.o |
diff --git a/sound/isa/als100.c b/sound/isa/als100.c index 5fd52e4d7079..20becc89f6f6 100644 --- a/sound/isa/als100.c +++ b/sound/isa/als100.c | |||
| @@ -2,9 +2,13 @@ | |||
| 2 | /* | 2 | /* |
| 3 | card-als100.c - driver for Avance Logic ALS100 based soundcards. | 3 | card-als100.c - driver for Avance Logic ALS100 based soundcards. |
| 4 | Copyright (C) 1999-2000 by Massimo Piccioni <dafastidio@libero.it> | 4 | Copyright (C) 1999-2000 by Massimo Piccioni <dafastidio@libero.it> |
| 5 | Copyright (C) 1999-2002 by Massimo Piccioni <dafastidio@libero.it> | ||
| 5 | 6 | ||
| 6 | Thanks to Pierfrancesco 'qM2' Passerini. | 7 | Thanks to Pierfrancesco 'qM2' Passerini. |
| 7 | 8 | ||
| 9 | Generalised for soundcards based on DT-0196 and ALS-007 chips | ||
| 10 | by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>: June 2002. | ||
| 11 | |||
| 8 | This program is free software; you can redistribute it and/or modify | 12 | This program is free software; you can redistribute it and/or modify |
| 9 | it under the terms of the GNU General Public License as published by | 13 | it under the terms of the GNU General Public License as published by |
| 10 | the Free Software Foundation; either version 2 of the License, or | 14 | the Free Software Foundation; either version 2 of the License, or |
| @@ -33,10 +37,10 @@ | |||
| 33 | 37 | ||
| 34 | #define PFX "als100: " | 38 | #define PFX "als100: " |
| 35 | 39 | ||
| 36 | MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>"); | 40 | MODULE_DESCRIPTION("Avance Logic ALS007/ALS1X0"); |
| 37 | MODULE_DESCRIPTION("Avance Logic ALS1X0"); | 41 | MODULE_SUPPORTED_DEVICE("{{Diamond Technologies DT-019X}," |
| 38 | MODULE_LICENSE("GPL"); | 42 | "{Avance Logic ALS-007}}" |
| 39 | MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS100 - PRO16PNP}," | 43 | "{{Avance Logic,ALS100 - PRO16PNP}," |
| 40 | "{Avance Logic,ALS110}," | 44 | "{Avance Logic,ALS110}," |
| 41 | "{Avance Logic,ALS120}," | 45 | "{Avance Logic,ALS120}," |
| 42 | "{Avance Logic,ALS200}," | 46 | "{Avance Logic,ALS200}," |
| @@ -45,9 +49,12 @@ MODULE_SUPPORTED_DEVICE("{{Avance Logic,ALS100 - PRO16PNP}," | |||
| 45 | "{Avance Logic,ALS120}," | 49 | "{Avance Logic,ALS120}," |
| 46 | "{RTL,RTL3000}}"); | 50 | "{RTL,RTL3000}}"); |
| 47 | 51 | ||
| 52 | MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>"); | ||
| 53 | MODULE_LICENSE("GPL"); | ||
| 54 | |||
| 48 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | 55 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ |
| 49 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | 56 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ |
| 50 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */ | 57 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ |
| 51 | static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ | 58 | static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ |
| 52 | static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ | 59 | static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ |
| 53 | static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ | 60 | static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ |
| @@ -57,14 +64,15 @@ static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */ | |||
| 57 | static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */ | 64 | static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */ |
| 58 | 65 | ||
| 59 | module_param_array(index, int, NULL, 0444); | 66 | module_param_array(index, int, NULL, 0444); |
| 60 | MODULE_PARM_DESC(index, "Index value for als100 based soundcard."); | 67 | MODULE_PARM_DESC(index, "Index value for Avance Logic based soundcard."); |
| 61 | module_param_array(id, charp, NULL, 0444); | 68 | module_param_array(id, charp, NULL, 0444); |
| 62 | MODULE_PARM_DESC(id, "ID string for als100 based soundcard."); | 69 | MODULE_PARM_DESC(id, "ID string for Avance Logic based soundcard."); |
| 63 | module_param_array(enable, bool, NULL, 0444); | 70 | module_param_array(enable, bool, NULL, 0444); |
| 64 | MODULE_PARM_DESC(enable, "Enable als100 based soundcard."); | 71 | MODULE_PARM_DESC(enable, "Enable Avance Logic based soundcard."); |
| 72 | |||
| 73 | MODULE_ALIAS("snd-dt019x"); | ||
| 65 | 74 | ||
| 66 | struct snd_card_als100 { | 75 | struct snd_card_als100 { |
| 67 | int dev_no; | ||
| 68 | struct pnp_dev *dev; | 76 | struct pnp_dev *dev; |
| 69 | struct pnp_dev *devmpu; | 77 | struct pnp_dev *devmpu; |
| 70 | struct pnp_dev *devopl; | 78 | struct pnp_dev *devopl; |
| @@ -72,25 +80,43 @@ struct snd_card_als100 { | |||
| 72 | }; | 80 | }; |
| 73 | 81 | ||
| 74 | static struct pnp_card_device_id snd_als100_pnpids[] = { | 82 | static struct pnp_card_device_id snd_als100_pnpids[] = { |
| 83 | /* DT197A30 */ | ||
| 84 | { .id = "RWB1688", | ||
| 85 | .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } }, | ||
| 86 | .driver_data = SB_HW_DT019X }, | ||
| 87 | /* DT0196 / ALS-007 */ | ||
| 88 | { .id = "ALS0007", | ||
| 89 | .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } }, | ||
| 90 | .driver_data = SB_HW_DT019X }, | ||
| 75 | /* ALS100 - PRO16PNP */ | 91 | /* ALS100 - PRO16PNP */ |
| 76 | { .id = "ALS0001", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } } }, | 92 | { .id = "ALS0001", |
| 93 | .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } }, | ||
| 94 | .driver_data = SB_HW_ALS100 }, | ||
| 77 | /* ALS110 - MF1000 - Digimate 3D Sound */ | 95 | /* ALS110 - MF1000 - Digimate 3D Sound */ |
| 78 | { .id = "ALS0110", .devs = { { "@@@1001" }, { "@X@1001" }, { "@H@1001" } } }, | 96 | { .id = "ALS0110", |
| 97 | .devs = { { "@@@1001" }, { "@X@1001" }, { "@H@1001" } }, | ||
| 98 | .driver_data = SB_HW_ALS100 }, | ||
| 79 | /* ALS120 */ | 99 | /* ALS120 */ |
| 80 | { .id = "ALS0120", .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } } }, | 100 | { .id = "ALS0120", |
| 101 | .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } }, | ||
| 102 | .driver_data = SB_HW_ALS100 }, | ||
| 81 | /* ALS200 */ | 103 | /* ALS200 */ |
| 82 | { .id = "ALS0200", .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0001" } } }, | 104 | { .id = "ALS0200", |
| 105 | .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0001" } }, | ||
| 106 | .driver_data = SB_HW_ALS100 }, | ||
| 83 | /* ALS200 OEM */ | 107 | /* ALS200 OEM */ |
| 84 | { .id = "ALS0200", .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0020" } } }, | 108 | { .id = "ALS0200", |
| 109 | .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0020" } }, | ||
| 110 | .driver_data = SB_HW_ALS100 }, | ||
| 85 | /* RTL3000 */ | 111 | /* RTL3000 */ |
| 86 | { .id = "RTL3000", .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } } }, | 112 | { .id = "RTL3000", |
| 87 | { .id = "", } /* end */ | 113 | .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } }, |
| 114 | .driver_data = SB_HW_ALS100 }, | ||
| 115 | { .id = "" } /* end */ | ||
| 88 | }; | 116 | }; |
| 89 | 117 | ||
| 90 | MODULE_DEVICE_TABLE(pnp_card, snd_als100_pnpids); | 118 | MODULE_DEVICE_TABLE(pnp_card, snd_als100_pnpids); |
| 91 | 119 | ||
| 92 | #define DRIVER_NAME "snd-card-als100" | ||
| 93 | |||
| 94 | static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard, | 120 | static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard, |
| 95 | struct pnp_card_link *card, | 121 | struct pnp_card_link *card, |
| 96 | const struct pnp_card_device_id *id) | 122 | const struct pnp_card_device_id *id) |
| @@ -113,8 +139,12 @@ static int __devinit snd_card_als100_pnp(int dev, struct snd_card_als100 *acard, | |||
| 113 | return err; | 139 | return err; |
| 114 | } | 140 | } |
| 115 | port[dev] = pnp_port_start(pdev, 0); | 141 | port[dev] = pnp_port_start(pdev, 0); |
| 116 | dma8[dev] = pnp_dma(pdev, 1); | 142 | if (id->driver_data == SB_HW_DT019X) |
| 117 | dma16[dev] = pnp_dma(pdev, 0); | 143 | dma8[dev] = pnp_dma(pdev, 0); |
| 144 | else { | ||
| 145 | dma8[dev] = pnp_dma(pdev, 1); | ||
| 146 | dma16[dev] = pnp_dma(pdev, 0); | ||
| 147 | } | ||
| 118 | irq[dev] = pnp_irq(pdev, 0); | 148 | irq[dev] = pnp_irq(pdev, 0); |
| 119 | 149 | ||
| 120 | pdev = acard->devmpu; | 150 | pdev = acard->devmpu; |
| @@ -175,22 +205,33 @@ static int __devinit snd_card_als100_probe(int dev, | |||
| 175 | } | 205 | } |
| 176 | snd_card_set_dev(card, &pcard->card->dev); | 206 | snd_card_set_dev(card, &pcard->card->dev); |
| 177 | 207 | ||
| 178 | if ((error = snd_sbdsp_create(card, port[dev], | 208 | if (pid->driver_data == SB_HW_DT019X) |
| 179 | irq[dev], | 209 | dma16[dev] = -1; |
| 180 | snd_sb16dsp_interrupt, | 210 | |
| 181 | dma8[dev], | 211 | error = snd_sbdsp_create(card, port[dev], irq[dev], |
| 182 | dma16[dev], | 212 | snd_sb16dsp_interrupt, |
| 183 | SB_HW_ALS100, &chip)) < 0) { | 213 | dma8[dev], dma16[dev], |
| 214 | pid->driver_data, | ||
| 215 | &chip); | ||
| 216 | if (error < 0) { | ||
| 184 | snd_card_free(card); | 217 | snd_card_free(card); |
| 185 | return error; | 218 | return error; |
| 186 | } | 219 | } |
| 187 | acard->chip = chip; | 220 | acard->chip = chip; |
| 188 | 221 | ||
| 189 | strcpy(card->driver, "ALS100"); | 222 | if (pid->driver_data == SB_HW_DT019X) { |
| 190 | strcpy(card->shortname, "Avance Logic ALS100"); | 223 | strcpy(card->driver, "DT-019X"); |
| 191 | sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d", | 224 | strcpy(card->shortname, "Diamond Tech. DT-019X"); |
| 192 | card->shortname, chip->name, chip->port, | 225 | sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d", |
| 193 | irq[dev], dma8[dev], dma16[dev]); | 226 | card->shortname, chip->name, chip->port, |
| 227 | irq[dev], dma8[dev]); | ||
| 228 | } else { | ||
| 229 | strcpy(card->driver, "ALS100"); | ||
| 230 | strcpy(card->shortname, "Avance Logic ALS100"); | ||
| 231 | sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d", | ||
| 232 | card->shortname, chip->name, chip->port, | ||
| 233 | irq[dev], dma8[dev], dma16[dev]); | ||
| 234 | } | ||
| 194 | 235 | ||
| 195 | if ((error = snd_sb16dsp_pcm(chip, 0, NULL)) < 0) { | 236 | if ((error = snd_sb16dsp_pcm(chip, 0, NULL)) < 0) { |
| 196 | snd_card_free(card); | 237 | snd_card_free(card); |
| @@ -203,9 +244,19 @@ static int __devinit snd_card_als100_probe(int dev, | |||
| 203 | } | 244 | } |
| 204 | 245 | ||
| 205 | if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { | 246 | if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { |
| 206 | if (snd_mpu401_uart_new(card, 0, MPU401_HW_ALS100, | 247 | int mpu_type = MPU401_HW_ALS100; |
| 248 | |||
| 249 | if (mpu_irq[dev] == SNDRV_AUTO_IRQ) | ||
| 250 | mpu_irq[dev] = -1; | ||
| 251 | |||
| 252 | if (pid->driver_data == SB_HW_DT019X) | ||
| 253 | mpu_type = MPU401_HW_MPU401; | ||
| 254 | |||
| 255 | if (snd_mpu401_uart_new(card, 0, | ||
| 256 | mpu_type, | ||
| 207 | mpu_port[dev], 0, | 257 | mpu_port[dev], 0, |
| 208 | mpu_irq[dev], IRQF_DISABLED, | 258 | mpu_irq[dev], |
| 259 | mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0, | ||
| 209 | NULL) < 0) | 260 | NULL) < 0) |
| 210 | snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]); | 261 | snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]); |
| 211 | } | 262 | } |
| @@ -291,7 +342,7 @@ static int snd_als100_pnp_resume(struct pnp_card_link *pcard) | |||
| 291 | 342 | ||
| 292 | static struct pnp_card_driver als100_pnpc_driver = { | 343 | static struct pnp_card_driver als100_pnpc_driver = { |
| 293 | .flags = PNP_DRIVER_RES_DISABLE, | 344 | .flags = PNP_DRIVER_RES_DISABLE, |
| 294 | .name = "als100", | 345 | .name = "als100", |
| 295 | .id_table = snd_als100_pnpids, | 346 | .id_table = snd_als100_pnpids, |
| 296 | .probe = snd_als100_pnp_detect, | 347 | .probe = snd_als100_pnp_detect, |
| 297 | .remove = __devexit_p(snd_als100_pnp_remove), | 348 | .remove = __devexit_p(snd_als100_pnp_remove), |
| @@ -312,7 +363,7 @@ static int __init alsa_card_als100_init(void) | |||
| 312 | if (!als100_devices) { | 363 | if (!als100_devices) { |
| 313 | pnp_unregister_card_driver(&als100_pnpc_driver); | 364 | pnp_unregister_card_driver(&als100_pnpc_driver); |
| 314 | #ifdef MODULE | 365 | #ifdef MODULE |
| 315 | snd_printk(KERN_ERR "no ALS100 based soundcards found\n"); | 366 | snd_printk(KERN_ERR "no Avance Logic based soundcards found\n"); |
| 316 | #endif | 367 | #endif |
| 317 | return -ENODEV; | 368 | return -ENODEV; |
| 318 | } | 369 | } |
diff --git a/sound/isa/dt019x.c b/sound/isa/dt019x.c deleted file mode 100644 index 80f5b1af9be8..000000000000 --- a/sound/isa/dt019x.c +++ /dev/null | |||
| @@ -1,321 +0,0 @@ | |||
| 1 | |||
| 2 | /* | ||
| 3 | dt019x.c - driver for Diamond Technologies DT-0197H based soundcards. | ||
| 4 | Copyright (C) 1999, 2002 by Massimo Piccioni <dafastidio@libero.it> | ||
| 5 | |||
| 6 | Generalised for soundcards based on DT-0196 and ALS-007 chips | ||
| 7 | by Jonathan Woithe <jwoithe@physics.adelaide.edu.au>: June 2002. | ||
| 8 | |||
| 9 | This program is free software; you can redistribute it and/or modify | ||
| 10 | it under the terms of the GNU General Public License as published by | ||
| 11 | the Free Software Foundation; either version 2 of the License, or | ||
| 12 | (at your option) any later version. | ||
| 13 | |||
| 14 | This program is distributed in the hope that it will be useful, | ||
| 15 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 17 | GNU General Public License for more details. | ||
| 18 | |||
| 19 | You should have received a copy of the GNU General Public License | ||
| 20 | along with this program; if not, write to the Free Software | ||
| 21 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include <linux/init.h> | ||
| 25 | #include <linux/wait.h> | ||
| 26 | #include <linux/pnp.h> | ||
| 27 | #include <linux/moduleparam.h> | ||
| 28 | #include <sound/core.h> | ||
| 29 | #include <sound/initval.h> | ||
| 30 | #include <sound/mpu401.h> | ||
| 31 | #include <sound/opl3.h> | ||
| 32 | #include <sound/sb.h> | ||
| 33 | |||
| 34 | #define PFX "dt019x: " | ||
| 35 | |||
| 36 | MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>"); | ||
| 37 | MODULE_DESCRIPTION("Diamond Technologies DT-019X / Avance Logic ALS-007"); | ||
| 38 | MODULE_LICENSE("GPL"); | ||
| 39 | MODULE_SUPPORTED_DEVICE("{{Diamond Technologies DT-019X}," | ||
| 40 | "{Avance Logic ALS-007}}"); | ||
| 41 | |||
| 42 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | ||
| 43 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | ||
| 44 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ | ||
| 45 | static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ | ||
| 46 | static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ | ||
| 47 | static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */ | ||
| 48 | static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* PnP setup */ | ||
| 49 | static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; /* PnP setup */ | ||
| 50 | static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; /* PnP setup */ | ||
| 51 | |||
| 52 | module_param_array(index, int, NULL, 0444); | ||
| 53 | MODULE_PARM_DESC(index, "Index value for DT-019X based soundcard."); | ||
| 54 | module_param_array(id, charp, NULL, 0444); | ||
| 55 | MODULE_PARM_DESC(id, "ID string for DT-019X based soundcard."); | ||
| 56 | module_param_array(enable, bool, NULL, 0444); | ||
| 57 | MODULE_PARM_DESC(enable, "Enable DT-019X based soundcard."); | ||
| 58 | |||
| 59 | struct snd_card_dt019x { | ||
| 60 | struct pnp_dev *dev; | ||
| 61 | struct pnp_dev *devmpu; | ||
| 62 | struct pnp_dev *devopl; | ||
| 63 | struct snd_sb *chip; | ||
| 64 | }; | ||
| 65 | |||
| 66 | static struct pnp_card_device_id snd_dt019x_pnpids[] = { | ||
| 67 | /* DT197A30 */ | ||
| 68 | { .id = "RWB1688", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" }, } }, | ||
| 69 | /* DT0196 / ALS-007 */ | ||
| 70 | { .id = "ALS0007", .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" }, } }, | ||
| 71 | { .id = "", } | ||
| 72 | }; | ||
| 73 | |||
| 74 | MODULE_DEVICE_TABLE(pnp_card, snd_dt019x_pnpids); | ||
| 75 | |||
| 76 | |||
| 77 | #define DRIVER_NAME "snd-card-dt019x" | ||
| 78 | |||
| 79 | |||
| 80 | static int __devinit snd_card_dt019x_pnp(int dev, struct snd_card_dt019x *acard, | ||
| 81 | struct pnp_card_link *card, | ||
| 82 | const struct pnp_card_device_id *pid) | ||
| 83 | { | ||
| 84 | struct pnp_dev *pdev; | ||
| 85 | int err; | ||
| 86 | |||
| 87 | acard->dev = pnp_request_card_device(card, pid->devs[0].id, NULL); | ||
| 88 | if (acard->dev == NULL) | ||
| 89 | return -ENODEV; | ||
| 90 | |||
| 91 | acard->devmpu = pnp_request_card_device(card, pid->devs[1].id, NULL); | ||
| 92 | acard->devopl = pnp_request_card_device(card, pid->devs[2].id, NULL); | ||
| 93 | |||
| 94 | pdev = acard->dev; | ||
| 95 | |||
| 96 | err = pnp_activate_dev(pdev); | ||
| 97 | if (err < 0) { | ||
| 98 | snd_printk(KERN_ERR PFX "DT-019X AUDIO pnp configure failure\n"); | ||
| 99 | return err; | ||
| 100 | } | ||
| 101 | |||
| 102 | port[dev] = pnp_port_start(pdev, 0); | ||
| 103 | dma8[dev] = pnp_dma(pdev, 0); | ||
| 104 | irq[dev] = pnp_irq(pdev, 0); | ||
| 105 | snd_printdd("dt019x: found audio interface: port=0x%lx, irq=0x%x, dma=0x%x\n", | ||
| 106 | port[dev],irq[dev],dma8[dev]); | ||
| 107 | |||
| 108 | pdev = acard->devmpu; | ||
| 109 | if (pdev != NULL) { | ||
| 110 | err = pnp_activate_dev(pdev); | ||
| 111 | if (err < 0) { | ||
| 112 | pnp_release_card_device(pdev); | ||
| 113 | snd_printk(KERN_ERR PFX "DT-019X MPU401 pnp configure failure, skipping\n"); | ||
| 114 | goto __mpu_error; | ||
| 115 | } | ||
| 116 | mpu_port[dev] = pnp_port_start(pdev, 0); | ||
| 117 | mpu_irq[dev] = pnp_irq(pdev, 0); | ||
| 118 | snd_printdd("dt019x: found MPU-401: port=0x%lx, irq=0x%x\n", | ||
| 119 | mpu_port[dev],mpu_irq[dev]); | ||
| 120 | } else { | ||
| 121 | __mpu_error: | ||
| 122 | acard->devmpu = NULL; | ||
| 123 | mpu_port[dev] = -1; | ||
| 124 | } | ||
| 125 | |||
| 126 | pdev = acard->devopl; | ||
| 127 | if (pdev != NULL) { | ||
| 128 | err = pnp_activate_dev(pdev); | ||
| 129 | if (err < 0) { | ||
| 130 | pnp_release_card_device(pdev); | ||
| 131 | snd_printk(KERN_ERR PFX "DT-019X OPL3 pnp configure failure, skipping\n"); | ||
| 132 | goto __fm_error; | ||
| 133 | } | ||
| 134 | fm_port[dev] = pnp_port_start(pdev, 0); | ||
| 135 | snd_printdd("dt019x: found OPL3 synth: port=0x%lx\n",fm_port[dev]); | ||
| 136 | } else { | ||
| 137 | __fm_error: | ||
| 138 | acard->devopl = NULL; | ||
| 139 | fm_port[dev] = -1; | ||
| 140 | } | ||
| 141 | |||
| 142 | return 0; | ||
| 143 | } | ||
| 144 | |||
| 145 | static int __devinit snd_card_dt019x_probe(int dev, struct pnp_card_link *pcard, const struct pnp_card_device_id *pid) | ||
| 146 | { | ||
| 147 | int error; | ||
| 148 | struct snd_sb *chip; | ||
| 149 | struct snd_card *card; | ||
| 150 | struct snd_card_dt019x *acard; | ||
| 151 | struct snd_opl3 *opl3; | ||
| 152 | |||
| 153 | error = snd_card_create(index[dev], id[dev], THIS_MODULE, | ||
| 154 | sizeof(struct snd_card_dt019x), &card); | ||
| 155 | if (error < 0) | ||
| 156 | return error; | ||
| 157 | acard = card->private_data; | ||
| 158 | |||
| 159 | snd_card_set_dev(card, &pcard->card->dev); | ||
| 160 | if ((error = snd_card_dt019x_pnp(dev, acard, pcard, pid))) { | ||
| 161 | snd_card_free(card); | ||
| 162 | return error; | ||
| 163 | } | ||
| 164 | |||
| 165 | if ((error = snd_sbdsp_create(card, port[dev], | ||
| 166 | irq[dev], | ||
| 167 | snd_sb16dsp_interrupt, | ||
| 168 | dma8[dev], | ||
| 169 | -1, | ||
| 170 | SB_HW_DT019X, | ||
| 171 | &chip)) < 0) { | ||
| 172 | snd_card_free(card); | ||
| 173 | return error; | ||
| 174 | } | ||
| 175 | acard->chip = chip; | ||
| 176 | |||
| 177 | strcpy(card->driver, "DT-019X"); | ||
| 178 | strcpy(card->shortname, "Diamond Tech. DT-019X"); | ||
| 179 | sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d", | ||
| 180 | card->shortname, chip->name, chip->port, | ||
| 181 | irq[dev], dma8[dev]); | ||
| 182 | |||
| 183 | if ((error = snd_sb16dsp_pcm(chip, 0, NULL)) < 0) { | ||
| 184 | snd_card_free(card); | ||
| 185 | return error; | ||
| 186 | } | ||
| 187 | if ((error = snd_sbmixer_new(chip)) < 0) { | ||
| 188 | snd_card_free(card); | ||
| 189 | return error; | ||
| 190 | } | ||
| 191 | |||
| 192 | if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { | ||
| 193 | if (mpu_irq[dev] == SNDRV_AUTO_IRQ) | ||
| 194 | mpu_irq[dev] = -1; | ||
| 195 | if (snd_mpu401_uart_new(card, 0, | ||
| 196 | /* MPU401_HW_SB,*/ | ||
| 197 | MPU401_HW_MPU401, | ||
| 198 | mpu_port[dev], 0, | ||
| 199 | mpu_irq[dev], | ||
| 200 | mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0, | ||
| 201 | NULL) < 0) | ||
| 202 | snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx ?\n", mpu_port[dev]); | ||
| 203 | } | ||
| 204 | |||
| 205 | if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) { | ||
| 206 | if (snd_opl3_create(card, | ||
| 207 | fm_port[dev], | ||
| 208 | fm_port[dev] + 2, | ||
| 209 | OPL3_HW_AUTO, 0, &opl3) < 0) { | ||
| 210 | snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx ?\n", | ||
| 211 | fm_port[dev], fm_port[dev] + 2); | ||
| 212 | } else { | ||
| 213 | if ((error = snd_opl3_timer_new(opl3, 0, 1)) < 0) { | ||
| 214 | snd_card_free(card); | ||
| 215 | return error; | ||
| 216 | } | ||
| 217 | if ((error = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) { | ||
| 218 | snd_card_free(card); | ||
| 219 | return error; | ||
| 220 | } | ||
| 221 | } | ||
| 222 | } | ||
| 223 | |||
| 224 | if ((error = snd_card_register(card)) < 0) { | ||
| 225 | snd_card_free(card); | ||
| 226 | return error; | ||
| 227 | } | ||
| 228 | pnp_set_card_drvdata(pcard, card); | ||
| 229 | return 0; | ||
| 230 | } | ||
| 231 | |||
| 232 | static unsigned int __devinitdata dt019x_devices; | ||
| 233 | |||
| 234 | static int __devinit snd_dt019x_pnp_probe(struct pnp_card_link *card, | ||
| 235 | const struct pnp_card_device_id *pid) | ||
| 236 | { | ||
| 237 | static int dev; | ||
| 238 | int res; | ||
| 239 | |||
| 240 | for ( ; dev < SNDRV_CARDS; dev++) { | ||
| 241 | if (!enable[dev]) | ||
| 242 | continue; | ||
| 243 | res = snd_card_dt019x_probe(dev, card, pid); | ||
| 244 | if (res < 0) | ||
| 245 | return res; | ||
| 246 | dev++; | ||
| 247 | dt019x_devices++; | ||
| 248 | return 0; | ||
| 249 | } | ||
| 250 | return -ENODEV; | ||
| 251 | } | ||
| 252 | |||
| 253 | static void __devexit snd_dt019x_pnp_remove(struct pnp_card_link * pcard) | ||
| 254 | { | ||
| 255 | snd_card_free(pnp_get_card_drvdata(pcard)); | ||
| 256 | pnp_set_card_drvdata(pcard, NULL); | ||
| 257 | } | ||
| 258 | |||
| 259 | #ifdef CONFIG_PM | ||
| 260 | static int snd_dt019x_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state) | ||
| 261 | { | ||
| 262 | struct snd_card *card = pnp_get_card_drvdata(pcard); | ||
| 263 | struct snd_card_dt019x *acard = card->private_data; | ||
| 264 | struct snd_sb *chip = acard->chip; | ||
| 265 | |||
| 266 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | ||
| 267 | snd_pcm_suspend_all(chip->pcm); | ||
| 268 | snd_sbmixer_suspend(chip); | ||
| 269 | return 0; | ||
| 270 | } | ||
| 271 | |||
| 272 | static int snd_dt019x_pnp_resume(struct pnp_card_link *pcard) | ||
| 273 | { | ||
| 274 | struct snd_card *card = pnp_get_card_drvdata(pcard); | ||
| 275 | struct snd_card_dt019x *acard = card->private_data; | ||
| 276 | struct snd_sb *chip = acard->chip; | ||
| 277 | |||
| 278 | snd_sbdsp_reset(chip); | ||
| 279 | snd_sbmixer_resume(chip); | ||
| 280 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | ||
| 281 | return 0; | ||
| 282 | } | ||
| 283 | #endif | ||
| 284 | |||
| 285 | static struct pnp_card_driver dt019x_pnpc_driver = { | ||
| 286 | .flags = PNP_DRIVER_RES_DISABLE, | ||
| 287 | .name = "dt019x", | ||
| 288 | .id_table = snd_dt019x_pnpids, | ||
| 289 | .probe = snd_dt019x_pnp_probe, | ||
| 290 | .remove = __devexit_p(snd_dt019x_pnp_remove), | ||
| 291 | #ifdef CONFIG_PM | ||
| 292 | .suspend = snd_dt019x_pnp_suspend, | ||
| 293 | .resume = snd_dt019x_pnp_resume, | ||
| 294 | #endif | ||
| 295 | }; | ||
| 296 | |||
| 297 | static int __init alsa_card_dt019x_init(void) | ||
| 298 | { | ||
| 299 | int err; | ||
| 300 | |||
| 301 | err = pnp_register_card_driver(&dt019x_pnpc_driver); | ||
| 302 | if (err) | ||
| 303 | return err; | ||
| 304 | |||
| 305 | if (!dt019x_devices) { | ||
| 306 | pnp_unregister_card_driver(&dt019x_pnpc_driver); | ||
| 307 | #ifdef MODULE | ||
| 308 | snd_printk(KERN_ERR "no DT-019X / ALS-007 based soundcards found\n"); | ||
| 309 | #endif | ||
| 310 | return -ENODEV; | ||
| 311 | } | ||
| 312 | return 0; | ||
| 313 | } | ||
| 314 | |||
| 315 | static void __exit alsa_card_dt019x_exit(void) | ||
| 316 | { | ||
| 317 | pnp_unregister_card_driver(&dt019x_pnpc_driver); | ||
| 318 | } | ||
| 319 | |||
| 320 | module_init(alsa_card_dt019x_init) | ||
| 321 | module_exit(alsa_card_dt019x_exit) | ||
diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c index c8a8da0d4036..a4af53b5c1cf 100644 --- a/sound/isa/opti9xx/opti92x-ad1848.c +++ b/sound/isa/opti9xx/opti92x-ad1848.c | |||
| @@ -33,6 +33,7 @@ | |||
| 33 | #include <asm/io.h> | 33 | #include <asm/io.h> |
| 34 | #include <asm/dma.h> | 34 | #include <asm/dma.h> |
| 35 | #include <sound/core.h> | 35 | #include <sound/core.h> |
| 36 | #include <sound/tlv.h> | ||
| 36 | #include <sound/wss.h> | 37 | #include <sound/wss.h> |
| 37 | #include <sound/mpu401.h> | 38 | #include <sound/mpu401.h> |
| 38 | #include <sound/opl3.h> | 39 | #include <sound/opl3.h> |
| @@ -546,6 +547,93 @@ __skip_mpu: | |||
| 546 | 547 | ||
| 547 | #ifdef OPTi93X | 548 | #ifdef OPTi93X |
| 548 | 549 | ||
| 550 | static const DECLARE_TLV_DB_SCALE(db_scale_5bit_3db_step, -9300, 300, 0); | ||
| 551 | static const DECLARE_TLV_DB_SCALE(db_scale_5bit, -4650, 150, 0); | ||
| 552 | static const DECLARE_TLV_DB_SCALE(db_scale_4bit_12db_max, -3300, 300, 0); | ||
| 553 | |||
| 554 | static struct snd_kcontrol_new snd_opti93x_controls[] = { | ||
| 555 | WSS_DOUBLE("Master Playback Switch", 0, | ||
| 556 | OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1), | ||
| 557 | WSS_DOUBLE_TLV("Master Playback Volume", 0, | ||
| 558 | OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1, | ||
| 559 | db_scale_5bit_3db_step), | ||
| 560 | WSS_DOUBLE_TLV("PCM Playback Volume", 0, | ||
| 561 | CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1, | ||
| 562 | db_scale_5bit), | ||
| 563 | WSS_DOUBLE_TLV("FM Playback Volume", 0, | ||
| 564 | CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1, | ||
| 565 | db_scale_4bit_12db_max), | ||
| 566 | WSS_DOUBLE("Line Playback Switch", 0, | ||
| 567 | CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), | ||
| 568 | WSS_DOUBLE_TLV("Line Playback Volume", 0, | ||
| 569 | CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1, | ||
| 570 | db_scale_4bit_12db_max), | ||
| 571 | WSS_DOUBLE("Mic Playback Switch", 0, | ||
| 572 | OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1), | ||
| 573 | WSS_DOUBLE_TLV("Mic Playback Volume", 0, | ||
| 574 | OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1, | ||
| 575 | db_scale_4bit_12db_max), | ||
| 576 | WSS_DOUBLE_TLV("CD Playback Volume", 0, | ||
| 577 | CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1, | ||
| 578 | db_scale_4bit_12db_max), | ||
| 579 | WSS_DOUBLE("Aux Playback Switch", 0, | ||
| 580 | OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1), | ||
| 581 | WSS_DOUBLE_TLV("Aux Playback Volume", 0, | ||
| 582 | OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1, | ||
| 583 | db_scale_4bit_12db_max), | ||
| 584 | }; | ||
| 585 | |||
| 586 | static int __devinit snd_opti93x_mixer(struct snd_wss *chip) | ||
| 587 | { | ||
| 588 | struct snd_card *card; | ||
| 589 | unsigned int idx; | ||
| 590 | struct snd_ctl_elem_id id1, id2; | ||
| 591 | int err; | ||
| 592 | |||
| 593 | if (snd_BUG_ON(!chip || !chip->pcm)) | ||
| 594 | return -EINVAL; | ||
| 595 | |||
| 596 | card = chip->card; | ||
| 597 | |||
| 598 | strcpy(card->mixername, chip->pcm->name); | ||
| 599 | |||
| 600 | memset(&id1, 0, sizeof(id1)); | ||
| 601 | memset(&id2, 0, sizeof(id2)); | ||
| 602 | id1.iface = id2.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | ||
| 603 | /* reassign AUX0 switch to CD */ | ||
| 604 | strcpy(id1.name, "Aux Playback Switch"); | ||
| 605 | strcpy(id2.name, "CD Playback Switch"); | ||
| 606 | err = snd_ctl_rename_id(card, &id1, &id2); | ||
| 607 | if (err < 0) { | ||
| 608 | snd_printk(KERN_ERR "Cannot rename opti93x control\n"); | ||
| 609 | return err; | ||
| 610 | } | ||
| 611 | /* reassign AUX1 switch to FM */ | ||
| 612 | strcpy(id1.name, "Aux Playback Switch"); id1.index = 1; | ||
| 613 | strcpy(id2.name, "FM Playback Switch"); | ||
| 614 | err = snd_ctl_rename_id(card, &id1, &id2); | ||
| 615 | if (err < 0) { | ||
| 616 | snd_printk(KERN_ERR "Cannot rename opti93x control\n"); | ||
| 617 | return err; | ||
| 618 | } | ||
| 619 | /* remove AUX1 volume */ | ||
| 620 | strcpy(id1.name, "Aux Playback Volume"); id1.index = 1; | ||
| 621 | snd_ctl_remove_id(card, &id1); | ||
| 622 | |||
| 623 | /* Replace WSS volume controls with OPTi93x volume controls */ | ||
| 624 | id1.index = 0; | ||
| 625 | for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) { | ||
| 626 | strcpy(id1.name, snd_opti93x_controls[idx].name); | ||
| 627 | snd_ctl_remove_id(card, &id1); | ||
| 628 | |||
| 629 | err = snd_ctl_add(card, | ||
| 630 | snd_ctl_new1(&snd_opti93x_controls[idx], chip)); | ||
| 631 | if (err < 0) | ||
| 632 | return err; | ||
| 633 | } | ||
| 634 | return 0; | ||
| 635 | } | ||
| 636 | |||
| 549 | static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id) | 637 | static irqreturn_t snd_opti93x_interrupt(int irq, void *dev_id) |
| 550 | { | 638 | { |
| 551 | struct snd_opti9xx *chip = dev_id; | 639 | struct snd_opti9xx *chip = dev_id; |
| @@ -754,6 +842,11 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card) | |||
| 754 | error = snd_wss_mixer(codec); | 842 | error = snd_wss_mixer(codec); |
| 755 | if (error < 0) | 843 | if (error < 0) |
| 756 | return error; | 844 | return error; |
| 845 | #ifdef OPTi93X | ||
| 846 | error = snd_opti93x_mixer(codec); | ||
| 847 | if (error < 0) | ||
| 848 | return error; | ||
| 849 | #endif | ||
| 757 | #ifdef CS4231 | 850 | #ifdef CS4231 |
| 758 | error = snd_wss_timer(codec, 0, &timer); | 851 | error = snd_wss_timer(codec, 0, &timer); |
| 759 | if (error < 0) | 852 | if (error < 0) |
diff --git a/sound/isa/sb/Makefile b/sound/isa/sb/Makefile index faeffceb01b7..af3669681788 100644 --- a/sound/isa/sb/Makefile +++ b/sound/isa/sb/Makefile | |||
| @@ -12,6 +12,7 @@ snd-sb16-objs := sb16.o | |||
| 12 | snd-sbawe-objs := sbawe.o emu8000.o | 12 | snd-sbawe-objs := sbawe.o emu8000.o |
| 13 | snd-emu8000-synth-objs := emu8000_synth.o emu8000_callback.o emu8000_patch.o emu8000_pcm.o | 13 | snd-emu8000-synth-objs := emu8000_synth.o emu8000_callback.o emu8000_patch.o emu8000_pcm.o |
| 14 | snd-es968-objs := es968.o | 14 | snd-es968-objs := es968.o |
| 15 | snd-jazz16-objs := jazz16.o | ||
| 15 | 16 | ||
| 16 | # Toplevel Module Dependency | 17 | # Toplevel Module Dependency |
| 17 | obj-$(CONFIG_SND_SB_COMMON) += snd-sb-common.o | 18 | obj-$(CONFIG_SND_SB_COMMON) += snd-sb-common.o |
| @@ -21,6 +22,7 @@ obj-$(CONFIG_SND_SB8) += snd-sb8.o | |||
| 21 | obj-$(CONFIG_SND_SB16) += snd-sb16.o | 22 | obj-$(CONFIG_SND_SB16) += snd-sb16.o |
| 22 | obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o | 23 | obj-$(CONFIG_SND_SBAWE) += snd-sbawe.o |
| 23 | obj-$(CONFIG_SND_ES968) += snd-es968.o | 24 | obj-$(CONFIG_SND_ES968) += snd-es968.o |
| 25 | obj-$(CONFIG_SND_JAZZ16) += snd-jazz16.o | ||
| 24 | ifeq ($(CONFIG_SND_SB16_CSP),y) | 26 | ifeq ($(CONFIG_SND_SB16_CSP),y) |
| 25 | obj-$(CONFIG_SND_SB16) += snd-sb16-csp.o | 27 | obj-$(CONFIG_SND_SB16) += snd-sb16-csp.o |
| 26 | obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o | 28 | obj-$(CONFIG_SND_SBAWE) += snd-sb16-csp.o |
diff --git a/sound/isa/sb/jazz16.c b/sound/isa/sb/jazz16.c new file mode 100644 index 000000000000..8d21a3feda3a --- /dev/null +++ b/sound/isa/sb/jazz16.c | |||
| @@ -0,0 +1,404 @@ | |||
| 1 | |||
| 2 | /* | ||
| 3 | * jazz16.c - driver for Media Vision Jazz16 based soundcards. | ||
| 4 | * Copyright (C) 2009 Krzysztof Helt <krzysztof.h1@wp.pl> | ||
| 5 | * Based on patches posted by Rask Ingemann Lambertsen and Rene Herman. | ||
| 6 | * Based on OSS Sound Blaster driver. | ||
| 7 | * | ||
| 8 | * This file is subject to the terms and conditions of the GNU General Public | ||
| 9 | * License. See the file COPYING in the main directory of this archive for | ||
| 10 | * more details. | ||
| 11 | * | ||
| 12 | */ | ||
| 13 | |||
| 14 | #include <linux/init.h> | ||
| 15 | #include <linux/module.h> | ||
| 16 | #include <linux/io.h> | ||
| 17 | #include <asm/dma.h> | ||
| 18 | #include <linux/isa.h> | ||
| 19 | #include <sound/core.h> | ||
| 20 | #include <sound/mpu401.h> | ||
| 21 | #include <sound/opl3.h> | ||
| 22 | #include <sound/sb.h> | ||
| 23 | #define SNDRV_LEGACY_FIND_FREE_IRQ | ||
| 24 | #define SNDRV_LEGACY_FIND_FREE_DMA | ||
| 25 | #include <sound/initval.h> | ||
| 26 | |||
| 27 | #define PFX "jazz16: " | ||
| 28 | |||
| 29 | MODULE_DESCRIPTION("Media Vision Jazz16"); | ||
| 30 | MODULE_SUPPORTED_DEVICE("{{Media Vision ??? }," | ||
| 31 | "{RTL,RTL3000}}"); | ||
| 32 | |||
| 33 | MODULE_AUTHOR("Krzysztof Helt <krzysztof.h1@wp.pl>"); | ||
| 34 | MODULE_LICENSE("GPL"); | ||
| 35 | |||
| 36 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | ||
| 37 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | ||
| 38 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */ | ||
| 39 | static unsigned long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | ||
| 40 | static unsigned long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | ||
| 41 | static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; | ||
| 42 | static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ; | ||
| 43 | static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; | ||
| 44 | static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA; | ||
| 45 | |||
| 46 | module_param_array(index, int, NULL, 0444); | ||
| 47 | MODULE_PARM_DESC(index, "Index value for Media Vision Jazz16 based soundcard."); | ||
| 48 | module_param_array(id, charp, NULL, 0444); | ||
| 49 | MODULE_PARM_DESC(id, "ID string for Media Vision Jazz16 based soundcard."); | ||
| 50 | module_param_array(enable, bool, NULL, 0444); | ||
| 51 | MODULE_PARM_DESC(enable, "Enable Media Vision Jazz16 based soundcard."); | ||
| 52 | module_param_array(port, long, NULL, 0444); | ||
| 53 | MODULE_PARM_DESC(port, "Port # for jazz16 driver."); | ||
| 54 | module_param_array(mpu_port, long, NULL, 0444); | ||
| 55 | MODULE_PARM_DESC(mpu_port, "MPU-401 port # for jazz16 driver."); | ||
| 56 | module_param_array(irq, int, NULL, 0444); | ||
| 57 | MODULE_PARM_DESC(irq, "IRQ # for jazz16 driver."); | ||
| 58 | module_param_array(mpu_irq, int, NULL, 0444); | ||
| 59 | MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for jazz16 driver."); | ||
| 60 | module_param_array(dma8, int, NULL, 0444); | ||
| 61 | MODULE_PARM_DESC(dma8, "DMA8 # for jazz16 driver."); | ||
| 62 | module_param_array(dma16, int, NULL, 0444); | ||
| 63 | MODULE_PARM_DESC(dma16, "DMA16 # for jazz16 driver."); | ||
| 64 | |||
| 65 | #define SB_JAZZ16_WAKEUP 0xaf | ||
| 66 | #define SB_JAZZ16_SET_PORTS 0x50 | ||
| 67 | #define SB_DSP_GET_JAZZ_BRD_REV 0xfa | ||
| 68 | #define SB_JAZZ16_SET_DMAINTR 0xfb | ||
| 69 | #define SB_DSP_GET_JAZZ_MODEL 0xfe | ||
| 70 | |||
| 71 | struct snd_card_jazz16 { | ||
| 72 | struct snd_sb *chip; | ||
| 73 | }; | ||
| 74 | |||
| 75 | static irqreturn_t jazz16_interrupt(int irq, void *chip) | ||
| 76 | { | ||
| 77 | return snd_sb8dsp_interrupt(chip); | ||
| 78 | } | ||
| 79 | |||
| 80 | static int __devinit jazz16_configure_ports(unsigned long port, | ||
| 81 | unsigned long mpu_port, int idx) | ||
| 82 | { | ||
| 83 | unsigned char val; | ||
| 84 | |||
| 85 | if (!request_region(0x201, 1, "jazz16 config")) { | ||
| 86 | snd_printk(KERN_ERR "config port region is already in use.\n"); | ||
| 87 | return -EBUSY; | ||
| 88 | } | ||
| 89 | outb(SB_JAZZ16_WAKEUP - idx, 0x201); | ||
| 90 | udelay(100); | ||
| 91 | outb(SB_JAZZ16_SET_PORTS + idx, 0x201); | ||
| 92 | udelay(100); | ||
| 93 | val = port & 0x70; | ||
| 94 | val |= (mpu_port & 0x30) >> 4; | ||
| 95 | outb(val, 0x201); | ||
| 96 | |||
| 97 | release_region(0x201, 1); | ||
| 98 | return 0; | ||
| 99 | } | ||
| 100 | |||
| 101 | static int __devinit jazz16_detect_board(unsigned long port, | ||
| 102 | unsigned long mpu_port) | ||
| 103 | { | ||
| 104 | int err; | ||
| 105 | int val; | ||
| 106 | struct snd_sb chip; | ||
| 107 | |||
| 108 | if (!request_region(port, 0x10, "jazz16")) { | ||
| 109 | snd_printk(KERN_ERR "I/O port region is already in use.\n"); | ||
| 110 | return -EBUSY; | ||
| 111 | } | ||
| 112 | /* just to call snd_sbdsp_command/reset/get_byte() */ | ||
| 113 | chip.port = port; | ||
| 114 | |||
| 115 | err = snd_sbdsp_reset(&chip); | ||
| 116 | if (err < 0) | ||
| 117 | for (val = 0; val < 4; val++) { | ||
| 118 | err = jazz16_configure_ports(port, mpu_port, val); | ||
| 119 | if (err < 0) | ||
| 120 | break; | ||
| 121 | |||
| 122 | err = snd_sbdsp_reset(&chip); | ||
| 123 | if (!err) | ||
| 124 | break; | ||
| 125 | } | ||
| 126 | if (err < 0) { | ||
| 127 | err = -ENODEV; | ||
| 128 | goto err_unmap; | ||
| 129 | } | ||
| 130 | if (!snd_sbdsp_command(&chip, SB_DSP_GET_JAZZ_BRD_REV)) { | ||
| 131 | err = -EBUSY; | ||
| 132 | goto err_unmap; | ||
| 133 | } | ||
| 134 | val = snd_sbdsp_get_byte(&chip); | ||
| 135 | if (val >= 0x30) | ||
| 136 | snd_sbdsp_get_byte(&chip); | ||
| 137 | |||
| 138 | if ((val & 0xf0) != 0x10) { | ||
| 139 | err = -ENODEV; | ||
| 140 | goto err_unmap; | ||
| 141 | } | ||
| 142 | if (!snd_sbdsp_command(&chip, SB_DSP_GET_JAZZ_MODEL)) { | ||
| 143 | err = -EBUSY; | ||
| 144 | goto err_unmap; | ||
| 145 | } | ||
| 146 | snd_sbdsp_get_byte(&chip); | ||
| 147 | err = snd_sbdsp_get_byte(&chip); | ||
| 148 | snd_printd("Media Vision Jazz16 board detected: rev 0x%x, model 0x%x\n", | ||
| 149 | val, err); | ||
| 150 | |||
| 151 | err = 0; | ||
| 152 | |||
| 153 | err_unmap: | ||
| 154 | release_region(port, 0x10); | ||
| 155 | return err; | ||
| 156 | } | ||
| 157 | |||
| 158 | static int __devinit jazz16_configure_board(struct snd_sb *chip, int mpu_irq) | ||
| 159 | { | ||
| 160 | static unsigned char jazz_irq_bits[] = { 0, 0, 2, 3, 0, 1, 0, 4, | ||
| 161 | 0, 2, 5, 0, 0, 0, 0, 6 }; | ||
| 162 | static unsigned char jazz_dma_bits[] = { 0, 1, 0, 2, 0, 3, 0, 4 }; | ||
| 163 | |||
| 164 | if (jazz_dma_bits[chip->dma8] == 0 || | ||
| 165 | jazz_dma_bits[chip->dma16] == 0 || | ||
| 166 | jazz_irq_bits[chip->irq] == 0) | ||
| 167 | return -EINVAL; | ||
| 168 | |||
| 169 | if (!snd_sbdsp_command(chip, SB_JAZZ16_SET_DMAINTR)) | ||
| 170 | return -EBUSY; | ||
| 171 | |||
| 172 | if (!snd_sbdsp_command(chip, | ||
| 173 | jazz_dma_bits[chip->dma8] | | ||
| 174 | (jazz_dma_bits[chip->dma16] << 4))) | ||
| 175 | return -EBUSY; | ||
| 176 | |||
| 177 | if (!snd_sbdsp_command(chip, | ||
| 178 | jazz_irq_bits[chip->irq] | | ||
| 179 | (jazz_irq_bits[mpu_irq] << 4))) | ||
| 180 | return -EBUSY; | ||
| 181 | |||
| 182 | return 0; | ||
| 183 | } | ||
| 184 | |||
| 185 | static int __devinit snd_jazz16_match(struct device *devptr, unsigned int dev) | ||
| 186 | { | ||
| 187 | if (!enable[dev]) | ||
| 188 | return 0; | ||
| 189 | if (port[dev] == SNDRV_AUTO_PORT) { | ||
| 190 | snd_printk(KERN_ERR "please specify port\n"); | ||
| 191 | return 0; | ||
| 192 | } else if (port[dev] == 0x200 || (port[dev] & ~0x270)) { | ||
| 193 | snd_printk(KERN_ERR "incorrect port specified\n"); | ||
| 194 | return 0; | ||
| 195 | } | ||
| 196 | if (dma8[dev] != SNDRV_AUTO_DMA && | ||
| 197 | dma8[dev] != 1 && dma8[dev] != 3) { | ||
| 198 | snd_printk(KERN_ERR "dma8 must be 1 or 3\n"); | ||
| 199 | return 0; | ||
| 200 | } | ||
| 201 | if (dma16[dev] != SNDRV_AUTO_DMA && | ||
| 202 | dma16[dev] != 5 && dma16[dev] != 7) { | ||
| 203 | snd_printk(KERN_ERR "dma16 must be 5 or 7\n"); | ||
| 204 | return 0; | ||
| 205 | } | ||
| 206 | if (mpu_port[dev] != SNDRV_AUTO_PORT && | ||
| 207 | (mpu_port[dev] & ~0x030) != 0x300) { | ||
| 208 | snd_printk(KERN_ERR "incorrect mpu_port specified\n"); | ||
| 209 | return 0; | ||
| 210 | } | ||
| 211 | if (mpu_irq[dev] != SNDRV_AUTO_DMA && | ||
| 212 | mpu_irq[dev] != 2 && mpu_irq[dev] != 3 && | ||
| 213 | mpu_irq[dev] != 5 && mpu_irq[dev] != 7) { | ||
| 214 | snd_printk(KERN_ERR "mpu_irq must be 2, 3, 5 or 7\n"); | ||
| 215 | return 0; | ||
| 216 | } | ||
| 217 | return 1; | ||
| 218 | } | ||
| 219 | |||
| 220 | static int __devinit snd_jazz16_probe(struct device *devptr, unsigned int dev) | ||
| 221 | { | ||
| 222 | struct snd_card *card; | ||
| 223 | struct snd_card_jazz16 *jazz16; | ||
| 224 | struct snd_sb *chip; | ||
| 225 | struct snd_opl3 *opl3; | ||
| 226 | static int possible_irqs[] = {2, 3, 5, 7, 9, 10, 15, -1}; | ||
| 227 | static int possible_dmas8[] = {1, 3, -1}; | ||
| 228 | static int possible_dmas16[] = {5, 7, -1}; | ||
| 229 | int err, xirq, xdma8, xdma16, xmpu_port, xmpu_irq; | ||
| 230 | |||
| 231 | err = snd_card_create(index[dev], id[dev], THIS_MODULE, | ||
| 232 | sizeof(struct snd_card_jazz16), &card); | ||
| 233 | if (err < 0) | ||
| 234 | return err; | ||
| 235 | |||
| 236 | jazz16 = card->private_data; | ||
| 237 | |||
| 238 | xirq = irq[dev]; | ||
| 239 | if (xirq == SNDRV_AUTO_IRQ) { | ||
| 240 | xirq = snd_legacy_find_free_irq(possible_irqs); | ||
| 241 | if (xirq < 0) { | ||
| 242 | snd_printk(KERN_ERR "unable to find a free IRQ\n"); | ||
| 243 | err = -EBUSY; | ||
| 244 | goto err_free; | ||
| 245 | } | ||
| 246 | } | ||
| 247 | xdma8 = dma8[dev]; | ||
| 248 | if (xdma8 == SNDRV_AUTO_DMA) { | ||
| 249 | xdma8 = snd_legacy_find_free_dma(possible_dmas8); | ||
| 250 | if (xdma8 < 0) { | ||
| 251 | snd_printk(KERN_ERR "unable to find a free DMA8\n"); | ||
| 252 | err = -EBUSY; | ||
| 253 | goto err_free; | ||
| 254 | } | ||
| 255 | } | ||
| 256 | xdma16 = dma16[dev]; | ||
| 257 | if (xdma16 == SNDRV_AUTO_DMA) { | ||
| 258 | xdma16 = snd_legacy_find_free_dma(possible_dmas16); | ||
| 259 | if (xdma16 < 0) { | ||
| 260 | snd_printk(KERN_ERR "unable to find a free DMA16\n"); | ||
| 261 | err = -EBUSY; | ||
| 262 | goto err_free; | ||
| 263 | } | ||
| 264 | } | ||
| 265 | |||
| 266 | xmpu_port = mpu_port[dev]; | ||
| 267 | if (xmpu_port == SNDRV_AUTO_PORT) | ||
| 268 | xmpu_port = 0; | ||
| 269 | err = jazz16_detect_board(port[dev], xmpu_port); | ||
| 270 | if (err < 0) { | ||
| 271 | printk(KERN_ERR "Media Vision Jazz16 board not detected\n"); | ||
| 272 | goto err_free; | ||
| 273 | } | ||
| 274 | err = snd_sbdsp_create(card, port[dev], irq[dev], | ||
| 275 | jazz16_interrupt, | ||
| 276 | dma8[dev], dma16[dev], | ||
| 277 | SB_HW_JAZZ16, | ||
| 278 | &chip); | ||
| 279 | if (err < 0) | ||
| 280 | goto err_free; | ||
| 281 | |||
| 282 | xmpu_irq = mpu_irq[dev]; | ||
| 283 | if (xmpu_irq == SNDRV_AUTO_IRQ || mpu_port[dev] == SNDRV_AUTO_PORT) | ||
| 284 | xmpu_irq = 0; | ||
| 285 | err = jazz16_configure_board(chip, xmpu_irq); | ||
| 286 | if (err < 0) { | ||
| 287 | printk(KERN_ERR "Media Vision Jazz16 configuration failed\n"); | ||
| 288 | goto err_free; | ||
| 289 | } | ||
| 290 | |||
| 291 | jazz16->chip = chip; | ||
| 292 | |||
| 293 | strcpy(card->driver, "jazz16"); | ||
| 294 | strcpy(card->shortname, "Media Vision Jazz16"); | ||
| 295 | sprintf(card->longname, | ||
| 296 | "Media Vision Jazz16 at 0x%lx, irq %d, dma8 %d, dma16 %d", | ||
| 297 | port[dev], xirq, xdma8, xdma16); | ||
| 298 | |||
| 299 | err = snd_sb8dsp_pcm(chip, 0, NULL); | ||
| 300 | if (err < 0) | ||
| 301 | goto err_free; | ||
| 302 | err = snd_sbmixer_new(chip); | ||
| 303 | if (err < 0) | ||
| 304 | goto err_free; | ||
| 305 | |||
| 306 | err = snd_opl3_create(card, chip->port, chip->port + 2, | ||
| 307 | OPL3_HW_AUTO, 1, &opl3); | ||
| 308 | if (err < 0) | ||
| 309 | snd_printk(KERN_WARNING "no OPL device at 0x%lx-0x%lx\n", | ||
| 310 | chip->port, chip->port + 2); | ||
| 311 | else { | ||
| 312 | err = snd_opl3_hwdep_new(opl3, 0, 1, NULL); | ||
| 313 | if (err < 0) | ||
| 314 | goto err_free; | ||
| 315 | } | ||
| 316 | if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) { | ||
| 317 | if (mpu_irq[dev] == SNDRV_AUTO_IRQ) | ||
| 318 | mpu_irq[dev] = -1; | ||
| 319 | |||
| 320 | if (snd_mpu401_uart_new(card, 0, | ||
| 321 | MPU401_HW_MPU401, | ||
| 322 | mpu_port[dev], 0, | ||
| 323 | mpu_irq[dev], | ||
| 324 | mpu_irq[dev] >= 0 ? IRQF_DISABLED : 0, | ||
| 325 | NULL) < 0) | ||
| 326 | snd_printk(KERN_ERR "no MPU-401 device at 0x%lx\n", | ||
| 327 | mpu_port[dev]); | ||
| 328 | } | ||
| 329 | |||
| 330 | snd_card_set_dev(card, devptr); | ||
| 331 | |||
| 332 | err = snd_card_register(card); | ||
| 333 | if (err < 0) | ||
| 334 | goto err_free; | ||
| 335 | |||
| 336 | dev_set_drvdata(devptr, card); | ||
| 337 | return 0; | ||
| 338 | |||
| 339 | err_free: | ||
| 340 | snd_card_free(card); | ||
| 341 | return err; | ||
| 342 | } | ||
| 343 | |||
| 344 | static int __devexit snd_jazz16_remove(struct device *devptr, unsigned int dev) | ||
| 345 | { | ||
| 346 | struct snd_card *card = dev_get_drvdata(devptr); | ||
| 347 | |||
| 348 | dev_set_drvdata(devptr, NULL); | ||
| 349 | snd_card_free(card); | ||
| 350 | return 0; | ||
| 351 | } | ||
| 352 | |||
| 353 | #ifdef CONFIG_PM | ||
| 354 | static int snd_jazz16_suspend(struct device *pdev, unsigned int n, | ||
| 355 | pm_message_t state) | ||
| 356 | { | ||
| 357 | struct snd_card *card = dev_get_drvdata(pdev); | ||
| 358 | struct snd_card_jazz16 *acard = card->private_data; | ||
| 359 | struct snd_sb *chip = acard->chip; | ||
| 360 | |||
| 361 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | ||
| 362 | snd_pcm_suspend_all(chip->pcm); | ||
| 363 | snd_sbmixer_suspend(chip); | ||
| 364 | return 0; | ||
| 365 | } | ||
| 366 | |||
| 367 | static int snd_jazz16_resume(struct device *pdev, unsigned int n) | ||
| 368 | { | ||
| 369 | struct snd_card *card = dev_get_drvdata(pdev); | ||
| 370 | struct snd_card_jazz16 *acard = card->private_data; | ||
| 371 | struct snd_sb *chip = acard->chip; | ||
| 372 | |||
| 373 | snd_sbdsp_reset(chip); | ||
| 374 | snd_sbmixer_resume(chip); | ||
| 375 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | ||
| 376 | return 0; | ||
| 377 | } | ||
| 378 | #endif | ||
| 379 | |||
| 380 | static struct isa_driver snd_jazz16_driver = { | ||
| 381 | .match = snd_jazz16_match, | ||
| 382 | .probe = snd_jazz16_probe, | ||
| 383 | .remove = __devexit_p(snd_jazz16_remove), | ||
| 384 | #ifdef CONFIG_PM | ||
| 385 | .suspend = snd_jazz16_suspend, | ||
| 386 | .resume = snd_jazz16_resume, | ||
| 387 | #endif | ||
| 388 | .driver = { | ||
| 389 | .name = "jazz16" | ||
| 390 | }, | ||
| 391 | }; | ||
| 392 | |||
| 393 | static int __init alsa_card_jazz16_init(void) | ||
| 394 | { | ||
| 395 | return isa_register_driver(&snd_jazz16_driver, SNDRV_CARDS); | ||
| 396 | } | ||
| 397 | |||
| 398 | static void __exit alsa_card_jazz16_exit(void) | ||
| 399 | { | ||
| 400 | isa_unregister_driver(&snd_jazz16_driver); | ||
| 401 | } | ||
| 402 | |||
| 403 | module_init(alsa_card_jazz16_init) | ||
| 404 | module_exit(alsa_card_jazz16_exit) | ||
diff --git a/sound/isa/sb/sb8_main.c b/sound/isa/sb/sb8_main.c index 658d55769c9c..7d84c9f34dc9 100644 --- a/sound/isa/sb/sb8_main.c +++ b/sound/isa/sb/sb8_main.c | |||
| @@ -106,9 +106,21 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream) | |||
| 106 | struct snd_sb *chip = snd_pcm_substream_chip(substream); | 106 | struct snd_sb *chip = snd_pcm_substream_chip(substream); |
| 107 | struct snd_pcm_runtime *runtime = substream->runtime; | 107 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 108 | unsigned int mixreg, rate, size, count; | 108 | unsigned int mixreg, rate, size, count; |
| 109 | unsigned char format; | ||
| 110 | unsigned char stereo = runtime->channels > 1; | ||
| 111 | int dma; | ||
| 109 | 112 | ||
| 110 | rate = runtime->rate; | 113 | rate = runtime->rate; |
| 111 | switch (chip->hardware) { | 114 | switch (chip->hardware) { |
| 115 | case SB_HW_JAZZ16: | ||
| 116 | if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) { | ||
| 117 | if (chip->mode & SB_MODE_CAPTURE_16) | ||
| 118 | return -EBUSY; | ||
| 119 | else | ||
| 120 | chip->mode |= SB_MODE_PLAYBACK_16; | ||
| 121 | } | ||
| 122 | chip->playback_format = SB_DSP_LO_OUTPUT_AUTO; | ||
| 123 | break; | ||
| 112 | case SB_HW_PRO: | 124 | case SB_HW_PRO: |
| 113 | if (runtime->channels > 1) { | 125 | if (runtime->channels > 1) { |
| 114 | if (snd_BUG_ON(rate != SB8_RATE(11025) && | 126 | if (snd_BUG_ON(rate != SB8_RATE(11025) && |
| @@ -133,11 +145,21 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream) | |||
| 133 | default: | 145 | default: |
| 134 | return -EINVAL; | 146 | return -EINVAL; |
| 135 | } | 147 | } |
| 148 | if (chip->mode & SB_MODE_PLAYBACK_16) { | ||
| 149 | format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT; | ||
| 150 | dma = chip->dma16; | ||
| 151 | } else { | ||
| 152 | format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT; | ||
| 153 | chip->mode |= SB_MODE_PLAYBACK_8; | ||
| 154 | dma = chip->dma8; | ||
| 155 | } | ||
| 136 | size = chip->p_dma_size = snd_pcm_lib_buffer_bytes(substream); | 156 | size = chip->p_dma_size = snd_pcm_lib_buffer_bytes(substream); |
| 137 | count = chip->p_period_size = snd_pcm_lib_period_bytes(substream); | 157 | count = chip->p_period_size = snd_pcm_lib_period_bytes(substream); |
| 138 | spin_lock_irqsave(&chip->reg_lock, flags); | 158 | spin_lock_irqsave(&chip->reg_lock, flags); |
| 139 | snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON); | 159 | snd_sbdsp_command(chip, SB_DSP_SPEAKER_ON); |
| 140 | if (runtime->channels > 1) { | 160 | if (chip->hardware == SB_HW_JAZZ16) |
| 161 | snd_sbdsp_command(chip, format); | ||
| 162 | else if (stereo) { | ||
| 141 | /* set playback stereo mode */ | 163 | /* set playback stereo mode */ |
| 142 | spin_lock(&chip->mixer_lock); | 164 | spin_lock(&chip->mixer_lock); |
| 143 | mixreg = snd_sbmixer_read(chip, SB_DSP_STEREO_SW); | 165 | mixreg = snd_sbmixer_read(chip, SB_DSP_STEREO_SW); |
| @@ -147,15 +169,14 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream) | |||
| 147 | /* Soundblaster hardware programming reference guide, 3-23 */ | 169 | /* Soundblaster hardware programming reference guide, 3-23 */ |
| 148 | snd_sbdsp_command(chip, SB_DSP_DMA8_EXIT); | 170 | snd_sbdsp_command(chip, SB_DSP_DMA8_EXIT); |
| 149 | runtime->dma_area[0] = 0x80; | 171 | runtime->dma_area[0] = 0x80; |
| 150 | snd_dma_program(chip->dma8, runtime->dma_addr, 1, DMA_MODE_WRITE); | 172 | snd_dma_program(dma, runtime->dma_addr, 1, DMA_MODE_WRITE); |
| 151 | /* force interrupt */ | 173 | /* force interrupt */ |
| 152 | chip->mode = SB_MODE_HALT; | ||
| 153 | snd_sbdsp_command(chip, SB_DSP_OUTPUT); | 174 | snd_sbdsp_command(chip, SB_DSP_OUTPUT); |
| 154 | snd_sbdsp_command(chip, 0); | 175 | snd_sbdsp_command(chip, 0); |
| 155 | snd_sbdsp_command(chip, 0); | 176 | snd_sbdsp_command(chip, 0); |
| 156 | } | 177 | } |
| 157 | snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE); | 178 | snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE); |
| 158 | if (runtime->channels > 1) { | 179 | if (stereo) { |
| 159 | snd_sbdsp_command(chip, 256 - runtime->rate_den / 2); | 180 | snd_sbdsp_command(chip, 256 - runtime->rate_den / 2); |
| 160 | spin_lock(&chip->mixer_lock); | 181 | spin_lock(&chip->mixer_lock); |
| 161 | /* save output filter status and turn it off */ | 182 | /* save output filter status and turn it off */ |
| @@ -168,13 +189,15 @@ static int snd_sb8_playback_prepare(struct snd_pcm_substream *substream) | |||
| 168 | snd_sbdsp_command(chip, 256 - runtime->rate_den); | 189 | snd_sbdsp_command(chip, 256 - runtime->rate_den); |
| 169 | } | 190 | } |
| 170 | if (chip->playback_format != SB_DSP_OUTPUT) { | 191 | if (chip->playback_format != SB_DSP_OUTPUT) { |
| 192 | if (chip->mode & SB_MODE_PLAYBACK_16) | ||
| 193 | count /= 2; | ||
| 171 | count--; | 194 | count--; |
| 172 | snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE); | 195 | snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE); |
| 173 | snd_sbdsp_command(chip, count & 0xff); | 196 | snd_sbdsp_command(chip, count & 0xff); |
| 174 | snd_sbdsp_command(chip, count >> 8); | 197 | snd_sbdsp_command(chip, count >> 8); |
| 175 | } | 198 | } |
| 176 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 199 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
| 177 | snd_dma_program(chip->dma8, runtime->dma_addr, | 200 | snd_dma_program(dma, runtime->dma_addr, |
| 178 | size, DMA_MODE_WRITE | DMA_AUTOINIT); | 201 | size, DMA_MODE_WRITE | DMA_AUTOINIT); |
| 179 | return 0; | 202 | return 0; |
| 180 | } | 203 | } |
| @@ -212,7 +235,6 @@ static int snd_sb8_playback_trigger(struct snd_pcm_substream *substream, | |||
| 212 | snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); | 235 | snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); |
| 213 | } | 236 | } |
| 214 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 237 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
| 215 | chip->mode = (cmd == SNDRV_PCM_TRIGGER_START) ? SB_MODE_PLAYBACK_8 : SB_MODE_HALT; | ||
| 216 | return 0; | 238 | return 0; |
| 217 | } | 239 | } |
| 218 | 240 | ||
| @@ -234,9 +256,21 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream) | |||
| 234 | struct snd_sb *chip = snd_pcm_substream_chip(substream); | 256 | struct snd_sb *chip = snd_pcm_substream_chip(substream); |
| 235 | struct snd_pcm_runtime *runtime = substream->runtime; | 257 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 236 | unsigned int mixreg, rate, size, count; | 258 | unsigned int mixreg, rate, size, count; |
| 259 | unsigned char format; | ||
| 260 | unsigned char stereo = runtime->channels > 1; | ||
| 261 | int dma; | ||
| 237 | 262 | ||
| 238 | rate = runtime->rate; | 263 | rate = runtime->rate; |
| 239 | switch (chip->hardware) { | 264 | switch (chip->hardware) { |
| 265 | case SB_HW_JAZZ16: | ||
| 266 | if (runtime->format == SNDRV_PCM_FORMAT_S16_LE) { | ||
| 267 | if (chip->mode & SB_MODE_PLAYBACK_16) | ||
| 268 | return -EBUSY; | ||
| 269 | else | ||
| 270 | chip->mode |= SB_MODE_CAPTURE_16; | ||
| 271 | } | ||
| 272 | chip->capture_format = SB_DSP_LO_INPUT_AUTO; | ||
| 273 | break; | ||
| 240 | case SB_HW_PRO: | 274 | case SB_HW_PRO: |
| 241 | if (runtime->channels > 1) { | 275 | if (runtime->channels > 1) { |
| 242 | if (snd_BUG_ON(rate != SB8_RATE(11025) && | 276 | if (snd_BUG_ON(rate != SB8_RATE(11025) && |
| @@ -262,14 +296,24 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream) | |||
| 262 | default: | 296 | default: |
| 263 | return -EINVAL; | 297 | return -EINVAL; |
| 264 | } | 298 | } |
| 299 | if (chip->mode & SB_MODE_CAPTURE_16) { | ||
| 300 | format = stereo ? SB_DSP_STEREO_16BIT : SB_DSP_MONO_16BIT; | ||
| 301 | dma = chip->dma16; | ||
| 302 | } else { | ||
| 303 | format = stereo ? SB_DSP_STEREO_8BIT : SB_DSP_MONO_8BIT; | ||
| 304 | chip->mode |= SB_MODE_CAPTURE_8; | ||
| 305 | dma = chip->dma8; | ||
| 306 | } | ||
| 265 | size = chip->c_dma_size = snd_pcm_lib_buffer_bytes(substream); | 307 | size = chip->c_dma_size = snd_pcm_lib_buffer_bytes(substream); |
| 266 | count = chip->c_period_size = snd_pcm_lib_period_bytes(substream); | 308 | count = chip->c_period_size = snd_pcm_lib_period_bytes(substream); |
| 267 | spin_lock_irqsave(&chip->reg_lock, flags); | 309 | spin_lock_irqsave(&chip->reg_lock, flags); |
| 268 | snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); | 310 | snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); |
| 269 | if (runtime->channels > 1) | 311 | if (chip->hardware == SB_HW_JAZZ16) |
| 312 | snd_sbdsp_command(chip, format); | ||
| 313 | else if (stereo) | ||
| 270 | snd_sbdsp_command(chip, SB_DSP_STEREO_8BIT); | 314 | snd_sbdsp_command(chip, SB_DSP_STEREO_8BIT); |
| 271 | snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE); | 315 | snd_sbdsp_command(chip, SB_DSP_SAMPLE_RATE); |
| 272 | if (runtime->channels > 1) { | 316 | if (stereo) { |
| 273 | snd_sbdsp_command(chip, 256 - runtime->rate_den / 2); | 317 | snd_sbdsp_command(chip, 256 - runtime->rate_den / 2); |
| 274 | spin_lock(&chip->mixer_lock); | 318 | spin_lock(&chip->mixer_lock); |
| 275 | /* save input filter status and turn it off */ | 319 | /* save input filter status and turn it off */ |
| @@ -282,13 +326,15 @@ static int snd_sb8_capture_prepare(struct snd_pcm_substream *substream) | |||
| 282 | snd_sbdsp_command(chip, 256 - runtime->rate_den); | 326 | snd_sbdsp_command(chip, 256 - runtime->rate_den); |
| 283 | } | 327 | } |
| 284 | if (chip->capture_format != SB_DSP_INPUT) { | 328 | if (chip->capture_format != SB_DSP_INPUT) { |
| 329 | if (chip->mode & SB_MODE_PLAYBACK_16) | ||
| 330 | count /= 2; | ||
| 285 | count--; | 331 | count--; |
| 286 | snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE); | 332 | snd_sbdsp_command(chip, SB_DSP_BLOCK_SIZE); |
| 287 | snd_sbdsp_command(chip, count & 0xff); | 333 | snd_sbdsp_command(chip, count & 0xff); |
| 288 | snd_sbdsp_command(chip, count >> 8); | 334 | snd_sbdsp_command(chip, count >> 8); |
| 289 | } | 335 | } |
| 290 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 336 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
| 291 | snd_dma_program(chip->dma8, runtime->dma_addr, | 337 | snd_dma_program(dma, runtime->dma_addr, |
| 292 | size, DMA_MODE_READ | DMA_AUTOINIT); | 338 | size, DMA_MODE_READ | DMA_AUTOINIT); |
| 293 | return 0; | 339 | return 0; |
| 294 | } | 340 | } |
| @@ -328,7 +374,6 @@ static int snd_sb8_capture_trigger(struct snd_pcm_substream *substream, | |||
| 328 | snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); | 374 | snd_sbdsp_command(chip, SB_DSP_SPEAKER_OFF); |
| 329 | } | 375 | } |
| 330 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 376 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
| 331 | chip->mode = (cmd == SNDRV_PCM_TRIGGER_START) ? SB_MODE_CAPTURE_8 : SB_MODE_HALT; | ||
| 332 | return 0; | 377 | return 0; |
| 333 | } | 378 | } |
| 334 | 379 | ||
| @@ -339,13 +384,21 @@ irqreturn_t snd_sb8dsp_interrupt(struct snd_sb *chip) | |||
| 339 | 384 | ||
| 340 | snd_sb_ack_8bit(chip); | 385 | snd_sb_ack_8bit(chip); |
| 341 | switch (chip->mode) { | 386 | switch (chip->mode) { |
| 342 | case SB_MODE_PLAYBACK_8: /* ok.. playback is active */ | 387 | case SB_MODE_PLAYBACK_16: /* ok.. playback is active */ |
| 388 | if (chip->hardware != SB_HW_JAZZ16) | ||
| 389 | break; | ||
| 390 | /* fallthru */ | ||
| 391 | case SB_MODE_PLAYBACK_8: | ||
| 343 | substream = chip->playback_substream; | 392 | substream = chip->playback_substream; |
| 344 | runtime = substream->runtime; | 393 | runtime = substream->runtime; |
| 345 | if (chip->playback_format == SB_DSP_OUTPUT) | 394 | if (chip->playback_format == SB_DSP_OUTPUT) |
| 346 | snd_sb8_playback_trigger(substream, SNDRV_PCM_TRIGGER_START); | 395 | snd_sb8_playback_trigger(substream, SNDRV_PCM_TRIGGER_START); |
| 347 | snd_pcm_period_elapsed(substream); | 396 | snd_pcm_period_elapsed(substream); |
| 348 | break; | 397 | break; |
| 398 | case SB_MODE_CAPTURE_16: | ||
| 399 | if (chip->hardware != SB_HW_JAZZ16) | ||
| 400 | break; | ||
| 401 | /* fallthru */ | ||
| 349 | case SB_MODE_CAPTURE_8: | 402 | case SB_MODE_CAPTURE_8: |
| 350 | substream = chip->capture_substream; | 403 | substream = chip->capture_substream; |
| 351 | runtime = substream->runtime; | 404 | runtime = substream->runtime; |
| @@ -361,10 +414,15 @@ static snd_pcm_uframes_t snd_sb8_playback_pointer(struct snd_pcm_substream *subs | |||
| 361 | { | 414 | { |
| 362 | struct snd_sb *chip = snd_pcm_substream_chip(substream); | 415 | struct snd_sb *chip = snd_pcm_substream_chip(substream); |
| 363 | size_t ptr; | 416 | size_t ptr; |
| 417 | int dma; | ||
| 364 | 418 | ||
| 365 | if (chip->mode != SB_MODE_PLAYBACK_8) | 419 | if (chip->mode & SB_MODE_PLAYBACK_8) |
| 420 | dma = chip->dma8; | ||
| 421 | else if (chip->mode & SB_MODE_PLAYBACK_16) | ||
| 422 | dma = chip->dma16; | ||
| 423 | else | ||
| 366 | return 0; | 424 | return 0; |
| 367 | ptr = snd_dma_pointer(chip->dma8, chip->p_dma_size); | 425 | ptr = snd_dma_pointer(dma, chip->p_dma_size); |
| 368 | return bytes_to_frames(substream->runtime, ptr); | 426 | return bytes_to_frames(substream->runtime, ptr); |
| 369 | } | 427 | } |
| 370 | 428 | ||
| @@ -372,10 +430,15 @@ static snd_pcm_uframes_t snd_sb8_capture_pointer(struct snd_pcm_substream *subst | |||
| 372 | { | 430 | { |
| 373 | struct snd_sb *chip = snd_pcm_substream_chip(substream); | 431 | struct snd_sb *chip = snd_pcm_substream_chip(substream); |
| 374 | size_t ptr; | 432 | size_t ptr; |
| 433 | int dma; | ||
| 375 | 434 | ||
| 376 | if (chip->mode != SB_MODE_CAPTURE_8) | 435 | if (chip->mode & SB_MODE_CAPTURE_8) |
| 436 | dma = chip->dma8; | ||
| 437 | else if (chip->mode & SB_MODE_CAPTURE_16) | ||
| 438 | dma = chip->dma16; | ||
| 439 | else | ||
| 377 | return 0; | 440 | return 0; |
| 378 | ptr = snd_dma_pointer(chip->dma8, chip->c_dma_size); | 441 | ptr = snd_dma_pointer(dma, chip->c_dma_size); |
| 379 | return bytes_to_frames(substream->runtime, ptr); | 442 | return bytes_to_frames(substream->runtime, ptr); |
| 380 | } | 443 | } |
| 381 | 444 | ||
| @@ -446,6 +509,14 @@ static int snd_sb8_open(struct snd_pcm_substream *substream) | |||
| 446 | runtime->hw = snd_sb8_capture; | 509 | runtime->hw = snd_sb8_capture; |
| 447 | } | 510 | } |
| 448 | switch (chip->hardware) { | 511 | switch (chip->hardware) { |
| 512 | case SB_HW_JAZZ16: | ||
| 513 | if (chip->dma16 == 5 || chip->dma16 == 7) | ||
| 514 | runtime->hw.formats |= SNDRV_PCM_FMTBIT_S16_LE; | ||
| 515 | runtime->hw.rates |= SNDRV_PCM_RATE_8000_48000; | ||
| 516 | runtime->hw.rate_min = 4000; | ||
| 517 | runtime->hw.rate_max = 50000; | ||
| 518 | runtime->hw.channels_max = 2; | ||
| 519 | break; | ||
| 449 | case SB_HW_PRO: | 520 | case SB_HW_PRO: |
| 450 | runtime->hw.rate_max = 44100; | 521 | runtime->hw.rate_max = 44100; |
| 451 | runtime->hw.channels_max = 2; | 522 | runtime->hw.channels_max = 2; |
| @@ -468,6 +539,14 @@ static int snd_sb8_open(struct snd_pcm_substream *substream) | |||
| 468 | } | 539 | } |
| 469 | snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | 540 | snd_pcm_hw_constraint_ratnums(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, |
| 470 | &hw_constraints_clock); | 541 | &hw_constraints_clock); |
| 542 | if (chip->dma8 > 3 || chip->dma16 >= 0) { | ||
| 543 | snd_pcm_hw_constraint_step(runtime, 0, | ||
| 544 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 2); | ||
| 545 | snd_pcm_hw_constraint_step(runtime, 0, | ||
| 546 | SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 2); | ||
| 547 | runtime->hw.buffer_bytes_max = 128 * 1024 * 1024; | ||
| 548 | runtime->hw.period_bytes_max = 128 * 1024 * 1024; | ||
| 549 | } | ||
| 471 | return 0; | 550 | return 0; |
| 472 | } | 551 | } |
| 473 | 552 | ||
| @@ -480,6 +559,10 @@ static int snd_sb8_close(struct snd_pcm_substream *substream) | |||
| 480 | chip->capture_substream = NULL; | 559 | chip->capture_substream = NULL; |
| 481 | spin_lock_irqsave(&chip->open_lock, flags); | 560 | spin_lock_irqsave(&chip->open_lock, flags); |
| 482 | chip->open &= ~SB_OPEN_PCM; | 561 | chip->open &= ~SB_OPEN_PCM; |
| 562 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
| 563 | chip->mode &= ~SB_MODE_PLAYBACK; | ||
| 564 | else | ||
| 565 | chip->mode &= ~SB_MODE_CAPTURE; | ||
| 483 | spin_unlock_irqrestore(&chip->open_lock, flags); | 566 | spin_unlock_irqrestore(&chip->open_lock, flags); |
| 484 | return 0; | 567 | return 0; |
| 485 | } | 568 | } |
| @@ -515,6 +598,7 @@ int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm) | |||
| 515 | struct snd_card *card = chip->card; | 598 | struct snd_card *card = chip->card; |
| 516 | struct snd_pcm *pcm; | 599 | struct snd_pcm *pcm; |
| 517 | int err; | 600 | int err; |
| 601 | size_t max_prealloc = 64 * 1024; | ||
| 518 | 602 | ||
| 519 | if (rpcm) | 603 | if (rpcm) |
| 520 | *rpcm = NULL; | 604 | *rpcm = NULL; |
| @@ -527,9 +611,11 @@ int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm) | |||
| 527 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb8_playback_ops); | 611 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_sb8_playback_ops); |
| 528 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb8_capture_ops); | 612 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_sb8_capture_ops); |
| 529 | 613 | ||
| 614 | if (chip->dma8 > 3 || chip->dma16 >= 0) | ||
| 615 | max_prealloc = 128 * 1024; | ||
| 530 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | 616 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, |
| 531 | snd_dma_isa_data(), | 617 | snd_dma_isa_data(), |
| 532 | 64*1024, 64*1024); | 618 | 64*1024, max_prealloc); |
| 533 | 619 | ||
| 534 | if (rpcm) | 620 | if (rpcm) |
| 535 | *rpcm = pcm; | 621 | *rpcm = pcm; |
diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c index 27a651502251..eae6c1c0eff9 100644 --- a/sound/isa/sb/sb_common.c +++ b/sound/isa/sb/sb_common.c | |||
| @@ -170,6 +170,9 @@ static int snd_sbdsp_probe(struct snd_sb * chip) | |||
| 170 | case SB_HW_CS5530: | 170 | case SB_HW_CS5530: |
| 171 | str = "16 (CS5530)"; | 171 | str = "16 (CS5530)"; |
| 172 | break; | 172 | break; |
| 173 | case SB_HW_JAZZ16: | ||
| 174 | str = "Pro (Jazz16)"; | ||
| 175 | break; | ||
| 173 | default: | 176 | default: |
| 174 | return -ENODEV; | 177 | return -ENODEV; |
| 175 | } | 178 | } |
diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c index 318ff0c823e7..6496822c1808 100644 --- a/sound/isa/sb/sb_mixer.c +++ b/sound/isa/sb/sb_mixer.c | |||
| @@ -528,20 +528,11 @@ int snd_sbmixer_add_ctl(struct snd_sb *chip, const char *name, int index, int ty | |||
| 528 | * SB 2.0 specific mixer elements | 528 | * SB 2.0 specific mixer elements |
| 529 | */ | 529 | */ |
| 530 | 530 | ||
| 531 | static struct sbmix_elem snd_sb20_ctl_master_play_vol = | 531 | static struct sbmix_elem snd_sb20_controls[] = { |
| 532 | SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7); | 532 | SB_SINGLE("Master Playback Volume", SB_DSP20_MASTER_DEV, 1, 7), |
| 533 | static struct sbmix_elem snd_sb20_ctl_pcm_play_vol = | 533 | SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3), |
| 534 | SB_SINGLE("PCM Playback Volume", SB_DSP20_PCM_DEV, 1, 3); | 534 | SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7), |
| 535 | static struct sbmix_elem snd_sb20_ctl_synth_play_vol = | 535 | SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7) |
| 536 | SB_SINGLE("Synth Playback Volume", SB_DSP20_FM_DEV, 1, 7); | ||
| 537 | static struct sbmix_elem snd_sb20_ctl_cd_play_vol = | ||
| 538 | SB_SINGLE("CD Playback Volume", SB_DSP20_CD_DEV, 1, 7); | ||
| 539 | |||
| 540 | static struct sbmix_elem *snd_sb20_controls[] = { | ||
| 541 | &snd_sb20_ctl_master_play_vol, | ||
| 542 | &snd_sb20_ctl_pcm_play_vol, | ||
| 543 | &snd_sb20_ctl_synth_play_vol, | ||
| 544 | &snd_sb20_ctl_cd_play_vol | ||
| 545 | }; | 536 | }; |
| 546 | 537 | ||
| 547 | static unsigned char snd_sb20_init_values[][2] = { | 538 | static unsigned char snd_sb20_init_values[][2] = { |
| @@ -552,41 +543,24 @@ static unsigned char snd_sb20_init_values[][2] = { | |||
| 552 | /* | 543 | /* |
| 553 | * SB Pro specific mixer elements | 544 | * SB Pro specific mixer elements |
| 554 | */ | 545 | */ |
| 555 | static struct sbmix_elem snd_sbpro_ctl_master_play_vol = | 546 | static struct sbmix_elem snd_sbpro_controls[] = { |
| 556 | SB_DOUBLE("Master Playback Volume", SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7); | 547 | SB_DOUBLE("Master Playback Volume", |
| 557 | static struct sbmix_elem snd_sbpro_ctl_pcm_play_vol = | 548 | SB_DSP_MASTER_DEV, SB_DSP_MASTER_DEV, 5, 1, 7), |
| 558 | SB_DOUBLE("PCM Playback Volume", SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7); | 549 | SB_DOUBLE("PCM Playback Volume", |
| 559 | static struct sbmix_elem snd_sbpro_ctl_pcm_play_filter = | 550 | SB_DSP_PCM_DEV, SB_DSP_PCM_DEV, 5, 1, 7), |
| 560 | SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1); | 551 | SB_SINGLE("PCM Playback Filter", SB_DSP_PLAYBACK_FILT, 5, 1), |
| 561 | static struct sbmix_elem snd_sbpro_ctl_synth_play_vol = | 552 | SB_DOUBLE("Synth Playback Volume", |
| 562 | SB_DOUBLE("Synth Playback Volume", SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7); | 553 | SB_DSP_FM_DEV, SB_DSP_FM_DEV, 5, 1, 7), |
| 563 | static struct sbmix_elem snd_sbpro_ctl_cd_play_vol = | 554 | SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7), |
| 564 | SB_DOUBLE("CD Playback Volume", SB_DSP_CD_DEV, SB_DSP_CD_DEV, 5, 1, 7); | 555 | SB_DOUBLE("Line Playback Volume", |
| 565 | static struct sbmix_elem snd_sbpro_ctl_line_play_vol = | 556 | SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7), |
| 566 | SB_DOUBLE("Line Playback Volume", SB_DSP_LINE_DEV, SB_DSP_LINE_DEV, 5, 1, 7); | 557 | SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3), |
| 567 | static struct sbmix_elem snd_sbpro_ctl_mic_play_vol = | ||
| 568 | SB_SINGLE("Mic Playback Volume", SB_DSP_MIC_DEV, 1, 3); | ||
| 569 | static struct sbmix_elem snd_sbpro_ctl_capture_source = | ||
| 570 | { | 558 | { |
| 571 | .name = "Capture Source", | 559 | .name = "Capture Source", |
| 572 | .type = SB_MIX_CAPTURE_PRO | 560 | .type = SB_MIX_CAPTURE_PRO |
| 573 | }; | 561 | }, |
| 574 | static struct sbmix_elem snd_sbpro_ctl_capture_filter = | 562 | SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1), |
| 575 | SB_SINGLE("Capture Filter", SB_DSP_CAPTURE_FILT, 5, 1); | 563 | SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1) |
| 576 | static struct sbmix_elem snd_sbpro_ctl_capture_low_filter = | ||
| 577 | SB_SINGLE("Capture Low-Pass Filter", SB_DSP_CAPTURE_FILT, 3, 1); | ||
| 578 | |||
| 579 | static struct sbmix_elem *snd_sbpro_controls[] = { | ||
| 580 | &snd_sbpro_ctl_master_play_vol, | ||
| 581 | &snd_sbpro_ctl_pcm_play_vol, | ||
| 582 | &snd_sbpro_ctl_pcm_play_filter, | ||
| 583 | &snd_sbpro_ctl_synth_play_vol, | ||
| 584 | &snd_sbpro_ctl_cd_play_vol, | ||
| 585 | &snd_sbpro_ctl_line_play_vol, | ||
| 586 | &snd_sbpro_ctl_mic_play_vol, | ||
| 587 | &snd_sbpro_ctl_capture_source, | ||
| 588 | &snd_sbpro_ctl_capture_filter, | ||
| 589 | &snd_sbpro_ctl_capture_low_filter | ||
| 590 | }; | 564 | }; |
| 591 | 565 | ||
| 592 | static unsigned char snd_sbpro_init_values[][2] = { | 566 | static unsigned char snd_sbpro_init_values[][2] = { |
| @@ -598,68 +572,42 @@ static unsigned char snd_sbpro_init_values[][2] = { | |||
| 598 | /* | 572 | /* |
| 599 | * SB16 specific mixer elements | 573 | * SB16 specific mixer elements |
| 600 | */ | 574 | */ |
| 601 | static struct sbmix_elem snd_sb16_ctl_master_play_vol = | 575 | static struct sbmix_elem snd_sb16_controls[] = { |
| 602 | SB_DOUBLE("Master Playback Volume", SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31); | 576 | SB_DOUBLE("Master Playback Volume", |
| 603 | static struct sbmix_elem snd_sb16_ctl_3d_enhance_switch = | 577 | SB_DSP4_MASTER_DEV, (SB_DSP4_MASTER_DEV + 1), 3, 3, 31), |
| 604 | SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1); | 578 | SB_DOUBLE("PCM Playback Volume", |
| 605 | static struct sbmix_elem snd_sb16_ctl_tone_bass = | 579 | SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31), |
| 606 | SB_DOUBLE("Tone Control - Bass", SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15); | 580 | SB16_INPUT_SW("Synth Capture Route", |
| 607 | static struct sbmix_elem snd_sb16_ctl_tone_treble = | 581 | SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5), |
| 608 | SB_DOUBLE("Tone Control - Treble", SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15); | 582 | SB_DOUBLE("Synth Playback Volume", |
| 609 | static struct sbmix_elem snd_sb16_ctl_pcm_play_vol = | 583 | SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31), |
| 610 | SB_DOUBLE("PCM Playback Volume", SB_DSP4_PCM_DEV, (SB_DSP4_PCM_DEV + 1), 3, 3, 31); | 584 | SB16_INPUT_SW("CD Capture Route", |
| 611 | static struct sbmix_elem snd_sb16_ctl_synth_capture_route = | 585 | SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1), |
| 612 | SB16_INPUT_SW("Synth Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 6, 5); | 586 | SB_DOUBLE("CD Playback Switch", |
| 613 | static struct sbmix_elem snd_sb16_ctl_synth_play_vol = | 587 | SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1), |
| 614 | SB_DOUBLE("Synth Playback Volume", SB_DSP4_SYNTH_DEV, (SB_DSP4_SYNTH_DEV + 1), 3, 3, 31); | 588 | SB_DOUBLE("CD Playback Volume", |
| 615 | static struct sbmix_elem snd_sb16_ctl_cd_capture_route = | 589 | SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31), |
| 616 | SB16_INPUT_SW("CD Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 2, 1); | 590 | SB16_INPUT_SW("Mic Capture Route", |
| 617 | static struct sbmix_elem snd_sb16_ctl_cd_play_switch = | 591 | SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0), |
| 618 | SB_DOUBLE("CD Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1); | 592 | SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1), |
| 619 | static struct sbmix_elem snd_sb16_ctl_cd_play_vol = | 593 | SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31), |
| 620 | SB_DOUBLE("CD Playback Volume", SB_DSP4_CD_DEV, (SB_DSP4_CD_DEV + 1), 3, 3, 31); | 594 | SB_SINGLE("Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3), |
| 621 | static struct sbmix_elem snd_sb16_ctl_line_capture_route = | 595 | SB_DOUBLE("Capture Volume", |
| 622 | SB16_INPUT_SW("Line Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3); | 596 | SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3), |
| 623 | static struct sbmix_elem snd_sb16_ctl_line_play_switch = | 597 | SB_DOUBLE("Playback Volume", |
| 624 | SB_DOUBLE("Line Playback Switch", SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1); | 598 | SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3), |
| 625 | static struct sbmix_elem snd_sb16_ctl_line_play_vol = | 599 | SB16_INPUT_SW("Line Capture Route", |
| 626 | SB_DOUBLE("Line Playback Volume", SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31); | 600 | SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 4, 3), |
| 627 | static struct sbmix_elem snd_sb16_ctl_mic_capture_route = | 601 | SB_DOUBLE("Line Playback Switch", |
| 628 | SB16_INPUT_SW("Mic Capture Route", SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT, 0, 0); | 602 | SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1), |
| 629 | static struct sbmix_elem snd_sb16_ctl_mic_play_switch = | 603 | SB_DOUBLE("Line Playback Volume", |
| 630 | SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1); | 604 | SB_DSP4_LINE_DEV, (SB_DSP4_LINE_DEV + 1), 3, 3, 31), |
| 631 | static struct sbmix_elem snd_sb16_ctl_mic_play_vol = | 605 | SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1), |
| 632 | SB_SINGLE("Mic Playback Volume", SB_DSP4_MIC_DEV, 3, 31); | 606 | SB_SINGLE("3D Enhancement Switch", SB_DSP4_3DSE, 0, 1), |
| 633 | static struct sbmix_elem snd_sb16_ctl_pc_speaker_vol = | 607 | SB_DOUBLE("Tone Control - Bass", |
| 634 | SB_SINGLE("Beep Volume", SB_DSP4_SPEAKER_DEV, 6, 3); | 608 | SB_DSP4_BASS_DEV, (SB_DSP4_BASS_DEV + 1), 4, 4, 15), |
| 635 | static struct sbmix_elem snd_sb16_ctl_capture_vol = | 609 | SB_DOUBLE("Tone Control - Treble", |
| 636 | SB_DOUBLE("Capture Volume", SB_DSP4_IGAIN_DEV, (SB_DSP4_IGAIN_DEV + 1), 6, 6, 3); | 610 | SB_DSP4_TREBLE_DEV, (SB_DSP4_TREBLE_DEV + 1), 4, 4, 15) |
| 637 | static struct sbmix_elem snd_sb16_ctl_play_vol = | ||
| 638 | SB_DOUBLE("Playback Volume", SB_DSP4_OGAIN_DEV, (SB_DSP4_OGAIN_DEV + 1), 6, 6, 3); | ||
| 639 | static struct sbmix_elem snd_sb16_ctl_auto_mic_gain = | ||
| 640 | SB_SINGLE("Mic Auto Gain", SB_DSP4_MIC_AGC, 0, 1); | ||
| 641 | |||
| 642 | static struct sbmix_elem *snd_sb16_controls[] = { | ||
| 643 | &snd_sb16_ctl_master_play_vol, | ||
| 644 | &snd_sb16_ctl_3d_enhance_switch, | ||
| 645 | &snd_sb16_ctl_tone_bass, | ||
| 646 | &snd_sb16_ctl_tone_treble, | ||
| 647 | &snd_sb16_ctl_pcm_play_vol, | ||
| 648 | &snd_sb16_ctl_synth_capture_route, | ||
| 649 | &snd_sb16_ctl_synth_play_vol, | ||
| 650 | &snd_sb16_ctl_cd_capture_route, | ||
| 651 | &snd_sb16_ctl_cd_play_switch, | ||
| 652 | &snd_sb16_ctl_cd_play_vol, | ||
| 653 | &snd_sb16_ctl_line_capture_route, | ||
| 654 | &snd_sb16_ctl_line_play_switch, | ||
| 655 | &snd_sb16_ctl_line_play_vol, | ||
| 656 | &snd_sb16_ctl_mic_capture_route, | ||
| 657 | &snd_sb16_ctl_mic_play_switch, | ||
| 658 | &snd_sb16_ctl_mic_play_vol, | ||
| 659 | &snd_sb16_ctl_pc_speaker_vol, | ||
| 660 | &snd_sb16_ctl_capture_vol, | ||
| 661 | &snd_sb16_ctl_play_vol, | ||
| 662 | &snd_sb16_ctl_auto_mic_gain | ||
| 663 | }; | 611 | }; |
| 664 | 612 | ||
| 665 | static unsigned char snd_sb16_init_values[][2] = { | 613 | static unsigned char snd_sb16_init_values[][2] = { |
| @@ -678,46 +626,34 @@ static unsigned char snd_sb16_init_values[][2] = { | |||
| 678 | /* | 626 | /* |
| 679 | * DT019x specific mixer elements | 627 | * DT019x specific mixer elements |
| 680 | */ | 628 | */ |
| 681 | static struct sbmix_elem snd_dt019x_ctl_master_play_vol = | 629 | static struct sbmix_elem snd_dt019x_controls[] = { |
| 682 | SB_DOUBLE("Master Playback Volume", SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4,0, 15); | 630 | /* ALS4000 below has some parts which we might be lacking, |
| 683 | static struct sbmix_elem snd_dt019x_ctl_pcm_play_vol = | 631 | * e.g. snd_als4000_ctl_mono_playback_switch - check it! */ |
| 684 | SB_DOUBLE("PCM Playback Volume", SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4,0, 15); | 632 | SB_DOUBLE("Master Playback Volume", |
| 685 | static struct sbmix_elem snd_dt019x_ctl_synth_play_vol = | 633 | SB_DT019X_MASTER_DEV, SB_DT019X_MASTER_DEV, 4, 0, 15), |
| 686 | SB_DOUBLE("Synth Playback Volume", SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4,0, 15); | 634 | SB_DOUBLE("PCM Playback Switch", |
| 687 | static struct sbmix_elem snd_dt019x_ctl_cd_play_vol = | 635 | SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1), |
| 688 | SB_DOUBLE("CD Playback Volume", SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4,0, 15); | 636 | SB_DOUBLE("PCM Playback Volume", |
| 689 | static struct sbmix_elem snd_dt019x_ctl_mic_play_vol = | 637 | SB_DT019X_PCM_DEV, SB_DT019X_PCM_DEV, 4, 0, 15), |
| 690 | SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7); | 638 | SB_DOUBLE("Synth Playback Switch", |
| 691 | static struct sbmix_elem snd_dt019x_ctl_pc_speaker_vol = | 639 | SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1), |
| 692 | SB_SINGLE("Beep Volume", SB_DT019X_SPKR_DEV, 0, 7); | 640 | SB_DOUBLE("Synth Playback Volume", |
| 693 | static struct sbmix_elem snd_dt019x_ctl_line_play_vol = | 641 | SB_DT019X_SYNTH_DEV, SB_DT019X_SYNTH_DEV, 4, 0, 15), |
| 694 | SB_DOUBLE("Line Playback Volume", SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4,0, 15); | 642 | SB_DOUBLE("CD Playback Switch", |
| 695 | static struct sbmix_elem snd_dt019x_ctl_pcm_play_switch = | 643 | SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 2, 1, 1), |
| 696 | SB_DOUBLE("PCM Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2,1, 1); | 644 | SB_DOUBLE("CD Playback Volume", |
| 697 | static struct sbmix_elem snd_dt019x_ctl_synth_play_switch = | 645 | SB_DT019X_CD_DEV, SB_DT019X_CD_DEV, 4, 0, 15), |
| 698 | SB_DOUBLE("Synth Playback Switch", SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4,3, 1); | 646 | SB_SINGLE("Mic Playback Switch", SB_DSP4_OUTPUT_SW, 0, 1), |
| 699 | static struct sbmix_elem snd_dt019x_ctl_capture_source = | 647 | SB_SINGLE("Mic Playback Volume", SB_DT019X_MIC_DEV, 4, 7), |
| 648 | SB_SINGLE("Beep Volume", SB_DT019X_SPKR_DEV, 0, 7), | ||
| 649 | SB_DOUBLE("Line Playback Switch", | ||
| 650 | SB_DSP4_OUTPUT_SW, SB_DSP4_OUTPUT_SW, 4, 3, 1), | ||
| 651 | SB_DOUBLE("Line Playback Volume", | ||
| 652 | SB_DT019X_LINE_DEV, SB_DT019X_LINE_DEV, 4, 0, 15), | ||
| 700 | { | 653 | { |
| 701 | .name = "Capture Source", | 654 | .name = "Capture Source", |
| 702 | .type = SB_MIX_CAPTURE_DT019X | 655 | .type = SB_MIX_CAPTURE_DT019X |
| 703 | }; | 656 | } |
| 704 | |||
| 705 | static struct sbmix_elem *snd_dt019x_controls[] = { | ||
| 706 | /* ALS4000 below has some parts which we might be lacking, | ||
| 707 | * e.g. snd_als4000_ctl_mono_playback_switch - check it! */ | ||
| 708 | &snd_dt019x_ctl_master_play_vol, | ||
| 709 | &snd_dt019x_ctl_pcm_play_vol, | ||
| 710 | &snd_dt019x_ctl_synth_play_vol, | ||
| 711 | &snd_dt019x_ctl_cd_play_vol, | ||
| 712 | &snd_dt019x_ctl_mic_play_vol, | ||
| 713 | &snd_dt019x_ctl_pc_speaker_vol, | ||
| 714 | &snd_dt019x_ctl_line_play_vol, | ||
| 715 | &snd_sb16_ctl_mic_play_switch, | ||
| 716 | &snd_sb16_ctl_cd_play_switch, | ||
| 717 | &snd_sb16_ctl_line_play_switch, | ||
| 718 | &snd_dt019x_ctl_pcm_play_switch, | ||
| 719 | &snd_dt019x_ctl_synth_play_switch, | ||
| 720 | &snd_dt019x_ctl_capture_source | ||
| 721 | }; | 657 | }; |
| 722 | 658 | ||
| 723 | static unsigned char snd_dt019x_init_values[][2] = { | 659 | static unsigned char snd_dt019x_init_values[][2] = { |
| @@ -735,82 +671,37 @@ static unsigned char snd_dt019x_init_values[][2] = { | |||
| 735 | /* | 671 | /* |
| 736 | * ALS4000 specific mixer elements | 672 | * ALS4000 specific mixer elements |
| 737 | */ | 673 | */ |
| 738 | static struct sbmix_elem snd_als4000_ctl_master_mono_playback_switch = | 674 | static struct sbmix_elem snd_als4000_controls[] = { |
| 739 | SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1); | 675 | SB_DOUBLE("PCM Playback Switch", |
| 740 | static struct sbmix_elem snd_als4k_ctl_master_mono_capture_route = { | 676 | SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 2, 1, 1), |
| 677 | SB_DOUBLE("Synth Playback Switch", | ||
| 678 | SB_DT019X_OUTPUT_SW2, SB_DT019X_OUTPUT_SW2, 4, 3, 1), | ||
| 679 | SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03), | ||
| 680 | SB_SINGLE("Master Mono Playback Switch", SB_ALS4000_MONO_IO_CTRL, 5, 1), | ||
| 681 | { | ||
| 741 | .name = "Master Mono Capture Route", | 682 | .name = "Master Mono Capture Route", |
| 742 | .type = SB_MIX_MONO_CAPTURE_ALS4K | 683 | .type = SB_MIX_MONO_CAPTURE_ALS4K |
| 743 | }; | 684 | }, |
| 744 | static struct sbmix_elem snd_als4000_ctl_mono_playback_switch = | 685 | SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1), |
| 745 | SB_SINGLE("Mono Playback Switch", SB_DT019X_OUTPUT_SW2, 0, 1); | 686 | SB_SINGLE("Analog Loopback Switch", SB_ALS4000_MIC_IN_GAIN, 7, 0x01), |
| 746 | static struct sbmix_elem snd_als4000_ctl_mic_20db_boost = | 687 | SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX, 6, 0x01), |
| 747 | SB_SINGLE("Mic Boost (+20dB)", SB_ALS4000_MIC_IN_GAIN, 0, 0x03); | ||
| 748 | static struct sbmix_elem snd_als4000_ctl_mixer_analog_loopback = | ||
| 749 | SB_SINGLE("Analog Loopback Switch", SB_ALS4000_MIC_IN_GAIN, 7, 0x01); | ||
| 750 | static struct sbmix_elem snd_als4000_ctl_mixer_digital_loopback = | ||
| 751 | SB_SINGLE("Digital Loopback Switch", | 688 | SB_SINGLE("Digital Loopback Switch", |
| 752 | SB_ALS4000_CR3_CONFIGURATION, 7, 0x01); | 689 | SB_ALS4000_CR3_CONFIGURATION, 7, 0x01), |
| 753 | /* FIXME: functionality of 3D controls might be swapped, I didn't find | 690 | /* FIXME: functionality of 3D controls might be swapped, I didn't find |
| 754 | * a description of how to identify what is supposed to be what */ | 691 | * a description of how to identify what is supposed to be what */ |
| 755 | static struct sbmix_elem snd_als4000_3d_control_switch = | 692 | SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX, 0, 0x07), |
| 756 | SB_SINGLE("3D Control - Switch", SB_ALS4000_3D_SND_FX, 6, 0x01); | ||
| 757 | static struct sbmix_elem snd_als4000_3d_control_ratio = | ||
| 758 | SB_SINGLE("3D Control - Level", SB_ALS4000_3D_SND_FX, 0, 0x07); | ||
| 759 | static struct sbmix_elem snd_als4000_3d_control_freq = | ||
| 760 | /* FIXME: maybe there's actually some standard 3D ctrl name for it?? */ | 693 | /* FIXME: maybe there's actually some standard 3D ctrl name for it?? */ |
| 761 | SB_SINGLE("3D Control - Freq", SB_ALS4000_3D_SND_FX, 4, 0x03); | 694 | SB_SINGLE("3D Control - Freq", SB_ALS4000_3D_SND_FX, 4, 0x03), |
| 762 | static struct sbmix_elem snd_als4000_3d_control_delay = | ||
| 763 | /* FIXME: ALS4000a.pdf mentions BBD (Bucket Brigade Device) time delay, | 695 | /* FIXME: ALS4000a.pdf mentions BBD (Bucket Brigade Device) time delay, |
| 764 | * but what ALSA 3D attribute is that actually? "Center", "Depth", | 696 | * but what ALSA 3D attribute is that actually? "Center", "Depth", |
| 765 | * "Wide" or "Space" or even "Level"? Assuming "Wide" for now... */ | 697 | * "Wide" or "Space" or even "Level"? Assuming "Wide" for now... */ |
| 766 | SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f); | 698 | SB_SINGLE("3D Control - Wide", SB_ALS4000_3D_TIME_DELAY, 0, 0x0f), |
| 767 | static struct sbmix_elem snd_als4000_3d_control_poweroff_switch = | 699 | SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01), |
| 768 | SB_SINGLE("3D PowerOff Switch", SB_ALS4000_3D_TIME_DELAY, 4, 0x01); | ||
| 769 | static struct sbmix_elem snd_als4000_ctl_3db_freq_control_switch = | ||
| 770 | SB_SINGLE("Master Playback 8kHz / 20kHz LPF Switch", | 700 | SB_SINGLE("Master Playback 8kHz / 20kHz LPF Switch", |
| 771 | SB_ALS4000_FMDAC, 5, 0x01); | 701 | SB_ALS4000_FMDAC, 5, 0x01), |
| 772 | #ifdef NOT_AVAILABLE | 702 | #ifdef NOT_AVAILABLE |
| 773 | static struct sbmix_elem snd_als4000_ctl_fmdac = | 703 | SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01), |
| 774 | SB_SINGLE("FMDAC Switch (Option ?)", SB_ALS4000_FMDAC, 0, 0x01); | 704 | SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f), |
| 775 | static struct sbmix_elem snd_als4000_ctl_qsound = | ||
| 776 | SB_SINGLE("QSound Mode", SB_ALS4000_QSOUND, 1, 0x1f); | ||
| 777 | #endif | ||
| 778 | |||
| 779 | static struct sbmix_elem *snd_als4000_controls[] = { | ||
| 780 | /* ALS4000a.PDF regs page */ | ||
| 781 | &snd_sb16_ctl_master_play_vol, /* MX30/31 12 */ | ||
| 782 | &snd_dt019x_ctl_pcm_play_switch, /* MX4C 16 */ | ||
| 783 | &snd_sb16_ctl_pcm_play_vol, /* MX32/33 12 */ | ||
| 784 | &snd_sb16_ctl_synth_capture_route, /* MX3D/3E 14 */ | ||
| 785 | &snd_dt019x_ctl_synth_play_switch, /* MX4C 16 */ | ||
| 786 | &snd_sb16_ctl_synth_play_vol, /* MX34/35 12/13 */ | ||
| 787 | &snd_sb16_ctl_cd_capture_route, /* MX3D/3E 14 */ | ||
| 788 | &snd_sb16_ctl_cd_play_switch, /* MX3C 14 */ | ||
| 789 | &snd_sb16_ctl_cd_play_vol, /* MX36/37 13 */ | ||
| 790 | &snd_sb16_ctl_line_capture_route, /* MX3D/3E 14 */ | ||
| 791 | &snd_sb16_ctl_line_play_switch, /* MX3C 14 */ | ||
| 792 | &snd_sb16_ctl_line_play_vol, /* MX38/39 13 */ | ||
| 793 | &snd_sb16_ctl_mic_capture_route, /* MX3D/3E 14 */ | ||
| 794 | &snd_als4000_ctl_mic_20db_boost, /* MX4D 16 */ | ||
| 795 | &snd_sb16_ctl_mic_play_switch, /* MX3C 14 */ | ||
| 796 | &snd_sb16_ctl_mic_play_vol, /* MX3A 13 */ | ||
| 797 | &snd_sb16_ctl_pc_speaker_vol, /* MX3B 14 */ | ||
| 798 | &snd_sb16_ctl_capture_vol, /* MX3F/40 15 */ | ||
| 799 | &snd_sb16_ctl_play_vol, /* MX41/42 15 */ | ||
| 800 | &snd_als4000_ctl_master_mono_playback_switch, /* MX4C 16 */ | ||
| 801 | &snd_als4k_ctl_master_mono_capture_route, /* MX4B 16 */ | ||
| 802 | &snd_als4000_ctl_mono_playback_switch, /* MX4C 16 */ | ||
| 803 | &snd_als4000_ctl_mixer_analog_loopback, /* MX4D 16 */ | ||
| 804 | &snd_als4000_ctl_mixer_digital_loopback, /* CR3 21 */ | ||
| 805 | &snd_als4000_3d_control_switch, /* MX50 17 */ | ||
| 806 | &snd_als4000_3d_control_ratio, /* MX50 17 */ | ||
| 807 | &snd_als4000_3d_control_freq, /* MX50 17 */ | ||
| 808 | &snd_als4000_3d_control_delay, /* MX51 18 */ | ||
| 809 | &snd_als4000_3d_control_poweroff_switch, /* MX51 18 */ | ||
| 810 | &snd_als4000_ctl_3db_freq_control_switch, /* MX4F 17 */ | ||
| 811 | #ifdef NOT_AVAILABLE | ||
| 812 | &snd_als4000_ctl_fmdac, | ||
| 813 | &snd_als4000_ctl_qsound, | ||
| 814 | #endif | 705 | #endif |
| 815 | }; | 706 | }; |
| 816 | 707 | ||
| @@ -829,11 +720,10 @@ static unsigned char snd_als4000_init_values[][2] = { | |||
| 829 | { SB_ALS4000_MIC_IN_GAIN, 0 }, | 720 | { SB_ALS4000_MIC_IN_GAIN, 0 }, |
| 830 | }; | 721 | }; |
| 831 | 722 | ||
| 832 | |||
| 833 | /* | 723 | /* |
| 834 | */ | 724 | */ |
| 835 | static int snd_sbmixer_init(struct snd_sb *chip, | 725 | static int snd_sbmixer_init(struct snd_sb *chip, |
| 836 | struct sbmix_elem **controls, | 726 | struct sbmix_elem *controls, |
| 837 | int controls_count, | 727 | int controls_count, |
| 838 | unsigned char map[][2], | 728 | unsigned char map[][2], |
| 839 | int map_count, | 729 | int map_count, |
| @@ -856,7 +746,8 @@ static int snd_sbmixer_init(struct snd_sb *chip, | |||
| 856 | } | 746 | } |
| 857 | 747 | ||
| 858 | for (idx = 0; idx < controls_count; idx++) { | 748 | for (idx = 0; idx < controls_count; idx++) { |
| 859 | if ((err = snd_sbmixer_add_ctl_elem(chip, controls[idx])) < 0) | 749 | err = snd_sbmixer_add_ctl_elem(chip, &controls[idx]); |
| 750 | if (err < 0) | ||
| 860 | return err; | 751 | return err; |
| 861 | } | 752 | } |
| 862 | snd_component_add(card, name); | 753 | snd_component_add(card, name); |
| @@ -888,6 +779,7 @@ int snd_sbmixer_new(struct snd_sb *chip) | |||
| 888 | return err; | 779 | return err; |
| 889 | break; | 780 | break; |
| 890 | case SB_HW_PRO: | 781 | case SB_HW_PRO: |
| 782 | case SB_HW_JAZZ16: | ||
| 891 | if ((err = snd_sbmixer_init(chip, | 783 | if ((err = snd_sbmixer_init(chip, |
| 892 | snd_sbpro_controls, | 784 | snd_sbpro_controls, |
| 893 | ARRAY_SIZE(snd_sbpro_controls), | 785 | ARRAY_SIZE(snd_sbpro_controls), |
| @@ -908,6 +800,15 @@ int snd_sbmixer_new(struct snd_sb *chip) | |||
| 908 | return err; | 800 | return err; |
| 909 | break; | 801 | break; |
| 910 | case SB_HW_ALS4000: | 802 | case SB_HW_ALS4000: |
| 803 | /* use only the first 16 controls from SB16 */ | ||
| 804 | err = snd_sbmixer_init(chip, | ||
| 805 | snd_sb16_controls, | ||
| 806 | 16, | ||
| 807 | snd_sb16_init_values, | ||
| 808 | ARRAY_SIZE(snd_sb16_init_values), | ||
| 809 | "ALS4000"); | ||
| 810 | if (err < 0) | ||
| 811 | return err; | ||
| 911 | if ((err = snd_sbmixer_init(chip, | 812 | if ((err = snd_sbmixer_init(chip, |
| 912 | snd_als4000_controls, | 813 | snd_als4000_controls, |
| 913 | ARRAY_SIZE(snd_als4000_controls), | 814 | ARRAY_SIZE(snd_als4000_controls), |
| @@ -1029,6 +930,7 @@ void snd_sbmixer_suspend(struct snd_sb *chip) | |||
| 1029 | save_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs)); | 930 | save_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs)); |
| 1030 | break; | 931 | break; |
| 1031 | case SB_HW_PRO: | 932 | case SB_HW_PRO: |
| 933 | case SB_HW_JAZZ16: | ||
| 1032 | save_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs)); | 934 | save_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs)); |
| 1033 | break; | 935 | break; |
| 1034 | case SB_HW_16: | 936 | case SB_HW_16: |
| @@ -1055,6 +957,7 @@ void snd_sbmixer_resume(struct snd_sb *chip) | |||
| 1055 | restore_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs)); | 957 | restore_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs)); |
| 1056 | break; | 958 | break; |
| 1057 | case SB_HW_PRO: | 959 | case SB_HW_PRO: |
| 960 | case SB_HW_JAZZ16: | ||
| 1058 | restore_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs)); | 961 | restore_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs)); |
| 1059 | break; | 962 | break; |
| 1060 | case SB_HW_16: | 963 | case SB_HW_16: |
diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c index 5b9d6c18bc45..9191b32d9130 100644 --- a/sound/isa/wss/wss_lib.c +++ b/sound/isa/wss/wss_lib.c | |||
| @@ -2014,6 +2014,7 @@ static int snd_wss_info_mux(struct snd_kcontrol *kcontrol, | |||
| 2014 | case WSS_HW_INTERWAVE: | 2014 | case WSS_HW_INTERWAVE: |
| 2015 | ptexts = gusmax_texts; | 2015 | ptexts = gusmax_texts; |
| 2016 | break; | 2016 | break; |
| 2017 | case WSS_HW_OPTI93X: | ||
| 2017 | case WSS_HW_OPL3SA2: | 2018 | case WSS_HW_OPL3SA2: |
| 2018 | ptexts = opl3sa_texts; | 2019 | ptexts = opl3sa_texts; |
| 2019 | break; | 2020 | break; |
| @@ -2246,54 +2247,12 @@ WSS_SINGLE("Beep Bypass Playback Switch", 0, | |||
| 2246 | CS4231_MONO_CTRL, 5, 1, 0), | 2247 | CS4231_MONO_CTRL, 5, 1, 0), |
| 2247 | }; | 2248 | }; |
| 2248 | 2249 | ||
| 2249 | static struct snd_kcontrol_new snd_opti93x_controls[] = { | ||
| 2250 | WSS_DOUBLE("Master Playback Switch", 0, | ||
| 2251 | OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 7, 7, 1, 1), | ||
| 2252 | WSS_DOUBLE_TLV("Master Playback Volume", 0, | ||
| 2253 | OPTi93X_OUT_LEFT, OPTi93X_OUT_RIGHT, 1, 1, 31, 1, | ||
| 2254 | db_scale_6bit), | ||
| 2255 | WSS_DOUBLE("PCM Playback Switch", 0, | ||
| 2256 | CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), | ||
| 2257 | WSS_DOUBLE("PCM Playback Volume", 0, | ||
| 2258 | CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 31, 1), | ||
| 2259 | WSS_DOUBLE("FM Playback Switch", 0, | ||
| 2260 | CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1), | ||
| 2261 | WSS_DOUBLE("FM Playback Volume", 0, | ||
| 2262 | CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 1, 1, 15, 1), | ||
| 2263 | WSS_DOUBLE("Line Playback Switch", 0, | ||
| 2264 | CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 7, 7, 1, 1), | ||
| 2265 | WSS_DOUBLE("Line Playback Volume", 0, | ||
| 2266 | CS4231_LEFT_LINE_IN, CS4231_RIGHT_LINE_IN, 0, 0, 15, 1), | ||
| 2267 | WSS_DOUBLE("Mic Playback Switch", 0, | ||
| 2268 | OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 7, 7, 1, 1), | ||
| 2269 | WSS_DOUBLE("Mic Playback Volume", 0, | ||
| 2270 | OPTi93X_MIC_LEFT_INPUT, OPTi93X_MIC_RIGHT_INPUT, 1, 1, 15, 1), | ||
| 2271 | WSS_DOUBLE("Mic Boost", 0, | ||
| 2272 | CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 5, 5, 1, 0), | ||
| 2273 | WSS_DOUBLE("CD Playback Switch", 0, | ||
| 2274 | CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1), | ||
| 2275 | WSS_DOUBLE("CD Playback Volume", 0, | ||
| 2276 | CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 1, 1, 15, 1), | ||
| 2277 | WSS_DOUBLE("Aux Playback Switch", 0, | ||
| 2278 | OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 7, 7, 1, 1), | ||
| 2279 | WSS_DOUBLE("Aux Playback Volume", 0, | ||
| 2280 | OPTi931_AUX_LEFT_INPUT, OPTi931_AUX_RIGHT_INPUT, 1, 1, 15, 1), | ||
| 2281 | WSS_DOUBLE("Capture Volume", 0, | ||
| 2282 | CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT, 0, 0, 15, 0), | ||
| 2283 | { | ||
| 2284 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 2285 | .name = "Capture Source", | ||
| 2286 | .info = snd_wss_info_mux, | ||
| 2287 | .get = snd_wss_get_mux, | ||
| 2288 | .put = snd_wss_put_mux, | ||
| 2289 | } | ||
| 2290 | }; | ||
| 2291 | |||
| 2292 | int snd_wss_mixer(struct snd_wss *chip) | 2250 | int snd_wss_mixer(struct snd_wss *chip) |
| 2293 | { | 2251 | { |
| 2294 | struct snd_card *card; | 2252 | struct snd_card *card; |
| 2295 | unsigned int idx; | 2253 | unsigned int idx; |
| 2296 | int err; | 2254 | int err; |
| 2255 | int count = ARRAY_SIZE(snd_wss_controls); | ||
| 2297 | 2256 | ||
| 2298 | if (snd_BUG_ON(!chip || !chip->pcm)) | 2257 | if (snd_BUG_ON(!chip || !chip->pcm)) |
| 2299 | return -EINVAL; | 2258 | return -EINVAL; |
| @@ -2302,28 +2261,19 @@ int snd_wss_mixer(struct snd_wss *chip) | |||
| 2302 | 2261 | ||
| 2303 | strcpy(card->mixername, chip->pcm->name); | 2262 | strcpy(card->mixername, chip->pcm->name); |
| 2304 | 2263 | ||
| 2305 | if (chip->hardware == WSS_HW_OPTI93X) | 2264 | /* Use only the first 11 entries on AD1848 */ |
| 2306 | for (idx = 0; idx < ARRAY_SIZE(snd_opti93x_controls); idx++) { | 2265 | if (chip->hardware & WSS_HW_AD1848_MASK) |
| 2307 | err = snd_ctl_add(card, | 2266 | count = 11; |
| 2308 | snd_ctl_new1(&snd_opti93x_controls[idx], | 2267 | /* There is no loopback on OPTI93X */ |
| 2309 | chip)); | 2268 | else if (chip->hardware == WSS_HW_OPTI93X) |
| 2310 | if (err < 0) | 2269 | count = 9; |
| 2311 | return err; | 2270 | |
| 2312 | } | 2271 | for (idx = 0; idx < count; idx++) { |
| 2313 | else { | 2272 | err = snd_ctl_add(card, |
| 2314 | int count = ARRAY_SIZE(snd_wss_controls); | 2273 | snd_ctl_new1(&snd_wss_controls[idx], |
| 2315 | 2274 | chip)); | |
| 2316 | /* Use only the first 11 entries on AD1848 */ | 2275 | if (err < 0) |
| 2317 | if (chip->hardware & WSS_HW_AD1848_MASK) | 2276 | return err; |
| 2318 | count = 11; | ||
| 2319 | |||
| 2320 | for (idx = 0; idx < count; idx++) { | ||
| 2321 | err = snd_ctl_add(card, | ||
| 2322 | snd_ctl_new1(&snd_wss_controls[idx], | ||
| 2323 | chip)); | ||
| 2324 | if (err < 0) | ||
| 2325 | return err; | ||
| 2326 | } | ||
| 2327 | } | 2277 | } |
| 2328 | return 0; | 2278 | return 0; |
| 2329 | } | 2279 | } |
diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c index f1d9d16b5486..6aff217379d9 100644 --- a/sound/mips/sgio2audio.c +++ b/sound/mips/sgio2audio.c | |||
| @@ -26,7 +26,6 @@ | |||
| 26 | #include <linux/delay.h> | 26 | #include <linux/delay.h> |
| 27 | #include <linux/spinlock.h> | 27 | #include <linux/spinlock.h> |
| 28 | #include <linux/gfp.h> | 28 | #include <linux/gfp.h> |
| 29 | #include <linux/vmalloc.h> | ||
| 30 | #include <linux/interrupt.h> | 29 | #include <linux/interrupt.h> |
| 31 | #include <linux/dma-mapping.h> | 30 | #include <linux/dma-mapping.h> |
| 32 | #include <linux/platform_device.h> | 31 | #include <linux/platform_device.h> |
| @@ -603,25 +602,14 @@ static int snd_sgio2audio_pcm_close(struct snd_pcm_substream *substream) | |||
| 603 | static int snd_sgio2audio_pcm_hw_params(struct snd_pcm_substream *substream, | 602 | static int snd_sgio2audio_pcm_hw_params(struct snd_pcm_substream *substream, |
| 604 | struct snd_pcm_hw_params *hw_params) | 603 | struct snd_pcm_hw_params *hw_params) |
| 605 | { | 604 | { |
| 606 | struct snd_pcm_runtime *runtime = substream->runtime; | 605 | return snd_pcm_lib_alloc_vmalloc_buffer(substream, |
| 607 | int size = params_buffer_bytes(hw_params); | 606 | params_buffer_bytes(hw_params)); |
| 608 | |||
| 609 | /* alloc virtual 'dma' area */ | ||
| 610 | if (runtime->dma_area) | ||
| 611 | vfree(runtime->dma_area); | ||
| 612 | runtime->dma_area = vmalloc_user(size); | ||
| 613 | if (runtime->dma_area == NULL) | ||
| 614 | return -ENOMEM; | ||
| 615 | runtime->dma_bytes = size; | ||
| 616 | return 0; | ||
| 617 | } | 607 | } |
| 618 | 608 | ||
| 619 | /* hw_free callback */ | 609 | /* hw_free callback */ |
| 620 | static int snd_sgio2audio_pcm_hw_free(struct snd_pcm_substream *substream) | 610 | static int snd_sgio2audio_pcm_hw_free(struct snd_pcm_substream *substream) |
| 621 | { | 611 | { |
| 622 | vfree(substream->runtime->dma_area); | 612 | return snd_pcm_lib_free_vmalloc_buffer(substream); |
| 623 | substream->runtime->dma_area = NULL; | ||
| 624 | return 0; | ||
| 625 | } | 613 | } |
| 626 | 614 | ||
| 627 | /* prepare callback */ | 615 | /* prepare callback */ |
| @@ -692,13 +680,6 @@ snd_sgio2audio_pcm_pointer(struct snd_pcm_substream *substream) | |||
| 692 | chip->channel[chan->idx].pos); | 680 | chip->channel[chan->idx].pos); |
| 693 | } | 681 | } |
| 694 | 682 | ||
| 695 | /* get the physical page pointer on the given offset */ | ||
| 696 | static struct page *snd_sgio2audio_page(struct snd_pcm_substream *substream, | ||
| 697 | unsigned long offset) | ||
| 698 | { | ||
| 699 | return vmalloc_to_page(substream->runtime->dma_area + offset); | ||
| 700 | } | ||
| 701 | |||
| 702 | /* operators */ | 683 | /* operators */ |
| 703 | static struct snd_pcm_ops snd_sgio2audio_playback1_ops = { | 684 | static struct snd_pcm_ops snd_sgio2audio_playback1_ops = { |
| 704 | .open = snd_sgio2audio_playback1_open, | 685 | .open = snd_sgio2audio_playback1_open, |
| @@ -709,7 +690,8 @@ static struct snd_pcm_ops snd_sgio2audio_playback1_ops = { | |||
| 709 | .prepare = snd_sgio2audio_pcm_prepare, | 690 | .prepare = snd_sgio2audio_pcm_prepare, |
| 710 | .trigger = snd_sgio2audio_pcm_trigger, | 691 | .trigger = snd_sgio2audio_pcm_trigger, |
| 711 | .pointer = snd_sgio2audio_pcm_pointer, | 692 | .pointer = snd_sgio2audio_pcm_pointer, |
| 712 | .page = snd_sgio2audio_page, | 693 | .page = snd_pcm_lib_get_vmalloc_page, |
| 694 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
| 713 | }; | 695 | }; |
| 714 | 696 | ||
| 715 | static struct snd_pcm_ops snd_sgio2audio_playback2_ops = { | 697 | static struct snd_pcm_ops snd_sgio2audio_playback2_ops = { |
| @@ -721,7 +703,8 @@ static struct snd_pcm_ops snd_sgio2audio_playback2_ops = { | |||
| 721 | .prepare = snd_sgio2audio_pcm_prepare, | 703 | .prepare = snd_sgio2audio_pcm_prepare, |
| 722 | .trigger = snd_sgio2audio_pcm_trigger, | 704 | .trigger = snd_sgio2audio_pcm_trigger, |
| 723 | .pointer = snd_sgio2audio_pcm_pointer, | 705 | .pointer = snd_sgio2audio_pcm_pointer, |
| 724 | .page = snd_sgio2audio_page, | 706 | .page = snd_pcm_lib_get_vmalloc_page, |
| 707 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
| 725 | }; | 708 | }; |
| 726 | 709 | ||
| 727 | static struct snd_pcm_ops snd_sgio2audio_capture_ops = { | 710 | static struct snd_pcm_ops snd_sgio2audio_capture_ops = { |
| @@ -733,7 +716,8 @@ static struct snd_pcm_ops snd_sgio2audio_capture_ops = { | |||
| 733 | .prepare = snd_sgio2audio_pcm_prepare, | 716 | .prepare = snd_sgio2audio_pcm_prepare, |
| 734 | .trigger = snd_sgio2audio_pcm_trigger, | 717 | .trigger = snd_sgio2audio_pcm_trigger, |
| 735 | .pointer = snd_sgio2audio_pcm_pointer, | 718 | .pointer = snd_sgio2audio_pcm_pointer, |
| 736 | .page = snd_sgio2audio_page, | 719 | .page = snd_pcm_lib_get_vmalloc_page, |
| 720 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
| 737 | }; | 721 | }; |
| 738 | 722 | ||
| 739 | /* | 723 | /* |
diff --git a/sound/oss/kahlua.c b/sound/oss/kahlua.c index 89466b056be7..24d152ccf80d 100644 --- a/sound/oss/kahlua.c +++ b/sound/oss/kahlua.c | |||
| @@ -198,7 +198,7 @@ MODULE_LICENSE("GPL"); | |||
| 198 | * 5530 only. The 5510/5520 decode is different. | 198 | * 5530 only. The 5510/5520 decode is different. |
| 199 | */ | 199 | */ |
| 200 | 200 | ||
| 201 | static struct pci_device_id id_tbl[] = { | 201 | static DEFINE_PCI_DEVICE_TABLE(id_tbl) = { |
| 202 | { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO), 0 }, | 202 | { PCI_VDEVICE(CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO), 0 }, |
| 203 | { } | 203 | { } |
| 204 | }; | 204 | }; |
diff --git a/sound/oss/soundcard.c b/sound/oss/soundcard.c index c62530943888..fde7c12fe5da 100644 --- a/sound/oss/soundcard.c +++ b/sound/oss/soundcard.c | |||
| @@ -328,11 +328,11 @@ static int sound_mixer_ioctl(int mixdev, unsigned int cmd, void __user *arg) | |||
| 328 | return mixer_devs[mixdev]->ioctl(mixdev, cmd, arg); | 328 | return mixer_devs[mixdev]->ioctl(mixdev, cmd, arg); |
| 329 | } | 329 | } |
| 330 | 330 | ||
| 331 | static int sound_ioctl(struct inode *inode, struct file *file, | 331 | static long sound_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
| 332 | unsigned int cmd, unsigned long arg) | ||
| 333 | { | 332 | { |
| 334 | int len = 0, dtype; | 333 | int len = 0, dtype; |
| 335 | int dev = iminor(inode); | 334 | int dev = iminor(file->f_dentry->d_inode); |
| 335 | long ret = -EINVAL; | ||
| 336 | void __user *p = (void __user *)arg; | 336 | void __user *p = (void __user *)arg; |
| 337 | 337 | ||
| 338 | if (_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0) { | 338 | if (_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0) { |
| @@ -353,6 +353,7 @@ static int sound_ioctl(struct inode *inode, struct file *file, | |||
| 353 | if (cmd == OSS_GETVERSION) | 353 | if (cmd == OSS_GETVERSION) |
| 354 | return __put_user(SOUND_VERSION, (int __user *)p); | 354 | return __put_user(SOUND_VERSION, (int __user *)p); |
| 355 | 355 | ||
| 356 | lock_kernel(); | ||
| 356 | if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 && /* Mixer ioctl */ | 357 | if (_IOC_TYPE(cmd) == 'M' && num_mixers > 0 && /* Mixer ioctl */ |
| 357 | (dev & 0x0f) != SND_DEV_CTL) { | 358 | (dev & 0x0f) != SND_DEV_CTL) { |
| 358 | dtype = dev & 0x0f; | 359 | dtype = dev & 0x0f; |
| @@ -360,24 +361,31 @@ static int sound_ioctl(struct inode *inode, struct file *file, | |||
| 360 | case SND_DEV_DSP: | 361 | case SND_DEV_DSP: |
| 361 | case SND_DEV_DSP16: | 362 | case SND_DEV_DSP16: |
| 362 | case SND_DEV_AUDIO: | 363 | case SND_DEV_AUDIO: |
| 363 | return sound_mixer_ioctl(audio_devs[dev >> 4]->mixer_dev, | 364 | ret = sound_mixer_ioctl(audio_devs[dev >> 4]->mixer_dev, |
| 364 | cmd, p); | 365 | cmd, p); |
| 365 | 366 | break; | |
| 366 | default: | 367 | default: |
| 367 | return sound_mixer_ioctl(dev >> 4, cmd, p); | 368 | ret = sound_mixer_ioctl(dev >> 4, cmd, p); |
| 369 | break; | ||
| 368 | } | 370 | } |
| 371 | unlock_kernel(); | ||
| 372 | return ret; | ||
| 369 | } | 373 | } |
| 374 | |||
| 370 | switch (dev & 0x0f) { | 375 | switch (dev & 0x0f) { |
| 371 | case SND_DEV_CTL: | 376 | case SND_DEV_CTL: |
| 372 | if (cmd == SOUND_MIXER_GETLEVELS) | 377 | if (cmd == SOUND_MIXER_GETLEVELS) |
| 373 | return get_mixer_levels(p); | 378 | ret = get_mixer_levels(p); |
| 374 | if (cmd == SOUND_MIXER_SETLEVELS) | 379 | else if (cmd == SOUND_MIXER_SETLEVELS) |
| 375 | return set_mixer_levels(p); | 380 | ret = set_mixer_levels(p); |
| 376 | return sound_mixer_ioctl(dev >> 4, cmd, p); | 381 | else |
| 382 | ret = sound_mixer_ioctl(dev >> 4, cmd, p); | ||
| 383 | break; | ||
| 377 | 384 | ||
| 378 | case SND_DEV_SEQ: | 385 | case SND_DEV_SEQ: |
| 379 | case SND_DEV_SEQ2: | 386 | case SND_DEV_SEQ2: |
| 380 | return sequencer_ioctl(dev, file, cmd, p); | 387 | ret = sequencer_ioctl(dev, file, cmd, p); |
| 388 | break; | ||
| 381 | 389 | ||
| 382 | case SND_DEV_DSP: | 390 | case SND_DEV_DSP: |
| 383 | case SND_DEV_DSP16: | 391 | case SND_DEV_DSP16: |
| @@ -390,7 +398,8 @@ static int sound_ioctl(struct inode *inode, struct file *file, | |||
| 390 | break; | 398 | break; |
| 391 | 399 | ||
| 392 | } | 400 | } |
| 393 | return -EINVAL; | 401 | unlock_kernel(); |
| 402 | return ret; | ||
| 394 | } | 403 | } |
| 395 | 404 | ||
| 396 | static unsigned int sound_poll(struct file *file, poll_table * wait) | 405 | static unsigned int sound_poll(struct file *file, poll_table * wait) |
| @@ -490,7 +499,7 @@ const struct file_operations oss_sound_fops = { | |||
| 490 | .read = sound_read, | 499 | .read = sound_read, |
| 491 | .write = sound_write, | 500 | .write = sound_write, |
| 492 | .poll = sound_poll, | 501 | .poll = sound_poll, |
| 493 | .ioctl = sound_ioctl, | 502 | .unlocked_ioctl = sound_ioctl, |
| 494 | .mmap = sound_mmap, | 503 | .mmap = sound_mmap, |
| 495 | .open = sound_open, | 504 | .open = sound_open, |
| 496 | .release = sound_release, | 505 | .release = sound_release, |
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 351654cf7b09..1298c68d6bf0 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig | |||
| @@ -789,6 +789,7 @@ config SND_VIRTUOSO | |||
| 789 | Say Y here to include support for sound cards based on the | 789 | Say Y here to include support for sound cards based on the |
| 790 | Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, | 790 | Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, |
| 791 | Essence ST (Deluxe), and Essence STX. | 791 | Essence ST (Deluxe), and Essence STX. |
| 792 | Support for the DS is experimental. | ||
| 792 | Support for the HDAV1.3 (Deluxe) is very experimental. | 793 | Support for the HDAV1.3 (Deluxe) is very experimental. |
| 793 | 794 | ||
| 794 | To compile this driver as a module, choose M here: the module | 795 | To compile this driver as a module, choose M here: the module |
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index d9266bae2849..1caf5e3c1f6a 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c | |||
| @@ -544,25 +544,10 @@ static int patch_wolfson04(struct snd_ac97 * ac97) | |||
| 544 | return 0; | 544 | return 0; |
| 545 | } | 545 | } |
| 546 | 546 | ||
| 547 | static int patch_wolfson_wm9705_specific(struct snd_ac97 * ac97) | ||
| 548 | { | ||
| 549 | int err, i; | ||
| 550 | for (i = 0; i < ARRAY_SIZE(wm97xx_snd_ac97_controls); i++) { | ||
| 551 | if ((err = snd_ctl_add(ac97->bus->card, snd_ac97_cnew(&wm97xx_snd_ac97_controls[i], ac97))) < 0) | ||
| 552 | return err; | ||
| 553 | } | ||
| 554 | snd_ac97_write_cache(ac97, 0x72, 0x0808); | ||
| 555 | return 0; | ||
| 556 | } | ||
| 557 | |||
| 558 | static struct snd_ac97_build_ops patch_wolfson_wm9705_ops = { | ||
| 559 | .build_specific = patch_wolfson_wm9705_specific, | ||
| 560 | }; | ||
| 561 | |||
| 562 | static int patch_wolfson05(struct snd_ac97 * ac97) | 547 | static int patch_wolfson05(struct snd_ac97 * ac97) |
| 563 | { | 548 | { |
| 564 | /* WM9705, WM9710 */ | 549 | /* WM9705, WM9710 */ |
| 565 | ac97->build_ops = &patch_wolfson_wm9705_ops; | 550 | ac97->build_ops = &patch_wolfson_wm9703_ops; |
| 566 | #ifdef CONFIG_TOUCHSCREEN_WM9705 | 551 | #ifdef CONFIG_TOUCHSCREEN_WM9705 |
| 567 | /* WM9705 touchscreen uses AUX and VIDEO for touch */ | 552 | /* WM9705 touchscreen uses AUX and VIDEO for touch */ |
| 568 | ac97->flags |= AC97_HAS_NO_VIDEO | AC97_HAS_NO_AUX; | 553 | ac97->flags |= AC97_HAS_NO_VIDEO | AC97_HAS_NO_AUX; |
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c index 8f5098f92c37..4382d0fa6b9a 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c | |||
| @@ -1048,7 +1048,7 @@ snd_ad1889_remove(struct pci_dev *pci) | |||
| 1048 | pci_set_drvdata(pci, NULL); | 1048 | pci_set_drvdata(pci, NULL); |
| 1049 | } | 1049 | } |
| 1050 | 1050 | ||
| 1051 | static struct pci_device_id snd_ad1889_ids[] = { | 1051 | static DEFINE_PCI_DEVICE_TABLE(snd_ad1889_ids) = { |
| 1052 | { PCI_DEVICE(PCI_VENDOR_ID_ANALOG_DEVICES, PCI_DEVICE_ID_AD1889JS) }, | 1052 | { PCI_DEVICE(PCI_VENDOR_ID_ANALOG_DEVICES, PCI_DEVICE_ID_AD1889JS) }, |
| 1053 | { 0, }, | 1053 | { 0, }, |
| 1054 | }; | 1054 | }; |
diff --git a/sound/pci/ali5451/ali5451.c b/sound/pci/ali5451/ali5451.c index aaf4da68969c..5c6e322a48f0 100644 --- a/sound/pci/ali5451/ali5451.c +++ b/sound/pci/ali5451/ali5451.c | |||
| @@ -275,7 +275,7 @@ struct snd_ali { | |||
| 275 | #endif | 275 | #endif |
| 276 | }; | 276 | }; |
| 277 | 277 | ||
| 278 | static struct pci_device_id snd_ali_ids[] = { | 278 | static DEFINE_PCI_DEVICE_TABLE(snd_ali_ids) = { |
| 279 | {PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5451), 0, 0, 0}, | 279 | {PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5451), 0, 0, 0}, |
| 280 | {0, } | 280 | {0, } |
| 281 | }; | 281 | }; |
diff --git a/sound/pci/als300.c b/sound/pci/als300.c index 3aa35af7ca91..d7653cb7ac60 100644 --- a/sound/pci/als300.c +++ b/sound/pci/als300.c | |||
| @@ -145,7 +145,7 @@ struct snd_als300_substream_data { | |||
| 145 | int block_counter_register; | 145 | int block_counter_register; |
| 146 | }; | 146 | }; |
| 147 | 147 | ||
| 148 | static struct pci_device_id snd_als300_ids[] = { | 148 | static DEFINE_PCI_DEVICE_TABLE(snd_als300_ids) = { |
| 149 | { 0x4005, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALS300 }, | 149 | { 0x4005, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALS300 }, |
| 150 | { 0x4005, 0x0308, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALS300_PLUS }, | 150 | { 0x4005, 0x0308, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALS300_PLUS }, |
| 151 | { 0, } | 151 | { 0, } |
diff --git a/sound/pci/als4000.c b/sound/pci/als4000.c index 3dbacde1a5af..d75cf7b06426 100644 --- a/sound/pci/als4000.c +++ b/sound/pci/als4000.c | |||
| @@ -117,7 +117,7 @@ struct snd_card_als4000 { | |||
| 117 | #endif | 117 | #endif |
| 118 | }; | 118 | }; |
| 119 | 119 | ||
| 120 | static struct pci_device_id snd_als4000_ids[] = { | 120 | static DEFINE_PCI_DEVICE_TABLE(snd_als4000_ids) = { |
| 121 | { 0x4005, 0x4000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* ALS4000 */ | 121 | { 0x4005, 0x4000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* ALS4000 */ |
| 122 | { 0, } | 122 | { 0, } |
| 123 | }; | 123 | }; |
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c index 42b4fbbd8e2b..49d572a7b235 100644 --- a/sound/pci/atiixp.c +++ b/sound/pci/atiixp.c | |||
| @@ -286,7 +286,7 @@ struct atiixp { | |||
| 286 | 286 | ||
| 287 | /* | 287 | /* |
| 288 | */ | 288 | */ |
| 289 | static struct pci_device_id snd_atiixp_ids[] = { | 289 | static DEFINE_PCI_DEVICE_TABLE(snd_atiixp_ids) = { |
| 290 | { PCI_VDEVICE(ATI, 0x4341), 0 }, /* SB200 */ | 290 | { PCI_VDEVICE(ATI, 0x4341), 0 }, /* SB200 */ |
| 291 | { PCI_VDEVICE(ATI, 0x4361), 0 }, /* SB300 */ | 291 | { PCI_VDEVICE(ATI, 0x4361), 0 }, /* SB300 */ |
| 292 | { PCI_VDEVICE(ATI, 0x4370), 0 }, /* SB400 */ | 292 | { PCI_VDEVICE(ATI, 0x4370), 0 }, /* SB400 */ |
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c index e7e147bf8eb2..91d7036b6411 100644 --- a/sound/pci/atiixp_modem.c +++ b/sound/pci/atiixp_modem.c | |||
| @@ -261,7 +261,7 @@ struct atiixp_modem { | |||
| 261 | 261 | ||
| 262 | /* | 262 | /* |
| 263 | */ | 263 | */ |
| 264 | static struct pci_device_id snd_atiixp_ids[] = { | 264 | static DEFINE_PCI_DEVICE_TABLE(snd_atiixp_ids) = { |
| 265 | { PCI_VDEVICE(ATI, 0x434d), 0 }, /* SB200 */ | 265 | { PCI_VDEVICE(ATI, 0x434d), 0 }, /* SB200 */ |
| 266 | { PCI_VDEVICE(ATI, 0x4378), 0 }, /* SB400 */ | 266 | { PCI_VDEVICE(ATI, 0x4378), 0 }, /* SB400 */ |
| 267 | { 0, } | 267 | { 0, } |
diff --git a/sound/pci/au88x0/au8810.c b/sound/pci/au88x0/au8810.c index c0e8c6b295cb..aa51cc7771dd 100644 --- a/sound/pci/au88x0/au8810.c +++ b/sound/pci/au88x0/au8810.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | #include "au8810.h" | 1 | #include "au8810.h" |
| 2 | #include "au88x0.h" | 2 | #include "au88x0.h" |
| 3 | static struct pci_device_id snd_vortex_ids[] = { | 3 | static DEFINE_PCI_DEVICE_TABLE(snd_vortex_ids) = { |
| 4 | {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_ADVANTAGE), 1,}, | 4 | {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_ADVANTAGE), 1,}, |
| 5 | {0,} | 5 | {0,} |
| 6 | }; | 6 | }; |
diff --git a/sound/pci/au88x0/au8820.c b/sound/pci/au88x0/au8820.c index a6527330df58..2f321e7306cd 100644 --- a/sound/pci/au88x0/au8820.c +++ b/sound/pci/au88x0/au8820.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | #include "au8820.h" | 1 | #include "au8820.h" |
| 2 | #include "au88x0.h" | 2 | #include "au88x0.h" |
| 3 | static struct pci_device_id snd_vortex_ids[] = { | 3 | static DEFINE_PCI_DEVICE_TABLE(snd_vortex_ids) = { |
| 4 | {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_1), 0,}, | 4 | {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_1), 0,}, |
| 5 | {0,} | 5 | {0,} |
| 6 | }; | 6 | }; |
diff --git a/sound/pci/au88x0/au8830.c b/sound/pci/au88x0/au8830.c index 6c702ad4352a..279b78f06d22 100644 --- a/sound/pci/au88x0/au8830.c +++ b/sound/pci/au88x0/au8830.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | #include "au8830.h" | 1 | #include "au8830.h" |
| 2 | #include "au88x0.h" | 2 | #include "au88x0.h" |
| 3 | static struct pci_device_id snd_vortex_ids[] = { | 3 | static DEFINE_PCI_DEVICE_TABLE(snd_vortex_ids) = { |
| 4 | {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_2), 0,}, | 4 | {PCI_VDEVICE(AUREAL, PCI_DEVICE_ID_AUREAL_VORTEX_2), 0,}, |
| 5 | {0,} | 5 | {0,} |
| 6 | }; | 6 | }; |
diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c index 4d34bb0d99d3..67921f93a41e 100644 --- a/sound/pci/aw2/aw2-alsa.c +++ b/sound/pci/aw2/aw2-alsa.c | |||
| @@ -164,7 +164,7 @@ MODULE_PARM_DESC(id, "ID string for the Audiowerk2 soundcard."); | |||
| 164 | module_param_array(enable, bool, NULL, 0444); | 164 | module_param_array(enable, bool, NULL, 0444); |
| 165 | MODULE_PARM_DESC(enable, "Enable Audiowerk2 soundcard."); | 165 | MODULE_PARM_DESC(enable, "Enable Audiowerk2 soundcard."); |
| 166 | 166 | ||
| 167 | static struct pci_device_id snd_aw2_ids[] = { | 167 | static DEFINE_PCI_DEVICE_TABLE(snd_aw2_ids) = { |
| 168 | {PCI_VENDOR_ID_SAA7146, PCI_DEVICE_ID_SAA7146, 0, 0, | 168 | {PCI_VENDOR_ID_SAA7146, PCI_DEVICE_ID_SAA7146, 0, 0, |
| 169 | 0, 0, 0}, | 169 | 0, 0, 0}, |
| 170 | {0} | 170 | {0} |
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index 69867ace7860..4679ed83a43b 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c | |||
| @@ -350,7 +350,7 @@ struct snd_azf3328 { | |||
| 350 | #endif | 350 | #endif |
| 351 | }; | 351 | }; |
| 352 | 352 | ||
| 353 | static const struct pci_device_id snd_azf3328_ids[] = { | 353 | static DEFINE_PCI_DEVICE_TABLE(snd_azf3328_ids) = { |
| 354 | { 0x122D, 0x50DC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* PCI168/3328 */ | 354 | { 0x122D, 0x50DC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* PCI168/3328 */ |
| 355 | { 0x122D, 0x80DA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* 3328 */ | 355 | { 0x122D, 0x80DA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* 3328 */ |
| 356 | { 0, } | 356 | { 0, } |
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index 4e2b925a94cc..37e1b5df5ab8 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c | |||
| @@ -795,7 +795,7 @@ fail: | |||
| 795 | .driver_data = SND_BT87X_BOARD_ ## id } | 795 | .driver_data = SND_BT87X_BOARD_ ## id } |
| 796 | /* driver_data is the card id for that device */ | 796 | /* driver_data is the card id for that device */ |
| 797 | 797 | ||
| 798 | static struct pci_device_id snd_bt87x_ids[] = { | 798 | static DEFINE_PCI_DEVICE_TABLE(snd_bt87x_ids) = { |
| 799 | /* Hauppauge WinTV series */ | 799 | /* Hauppauge WinTV series */ |
| 800 | BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0x13eb, GENERIC), | 800 | BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x0070, 0x13eb, GENERIC), |
| 801 | /* Hauppauge WinTV series */ | 801 | /* Hauppauge WinTV series */ |
| @@ -964,7 +964,7 @@ static void __devexit snd_bt87x_remove(struct pci_dev *pci) | |||
| 964 | 964 | ||
| 965 | /* default entries for all Bt87x cards - it's not exported */ | 965 | /* default entries for all Bt87x cards - it's not exported */ |
| 966 | /* driver_data is set to 0 to call detection */ | 966 | /* driver_data is set to 0 to call detection */ |
| 967 | static struct pci_device_id snd_bt87x_default_ids[] __devinitdata = { | 967 | static DEFINE_PCI_DEVICE_TABLE(snd_bt87x_default_ids) = { |
| 968 | BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, PCI_ANY_ID, PCI_ANY_ID, UNKNOWN), | 968 | BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, PCI_ANY_ID, PCI_ANY_ID, UNKNOWN), |
| 969 | BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, PCI_ANY_ID, PCI_ANY_ID, UNKNOWN), | 969 | BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_879, PCI_ANY_ID, PCI_ANY_ID, UNKNOWN), |
| 970 | { } | 970 | { } |
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 15e4138bce17..0a3d3d6e77b4 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c | |||
| @@ -1875,7 +1875,7 @@ static int snd_ca0106_resume(struct pci_dev *pci) | |||
| 1875 | #endif | 1875 | #endif |
| 1876 | 1876 | ||
| 1877 | // PCI IDs | 1877 | // PCI IDs |
| 1878 | static struct pci_device_id snd_ca0106_ids[] = { | 1878 | static DEFINE_PCI_DEVICE_TABLE(snd_ca0106_ids) = { |
| 1879 | { PCI_VDEVICE(CREATIVE, 0x0007), 0 }, /* Audigy LS or Live 24bit */ | 1879 | { PCI_VDEVICE(CREATIVE, 0x0007), 0 }, /* Audigy LS or Live 24bit */ |
| 1880 | { 0, } | 1880 | { 0, } |
| 1881 | }; | 1881 | }; |
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index a312bae08f52..1ded64e05643 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c | |||
| @@ -2796,7 +2796,7 @@ static inline void snd_cmipci_proc_init(struct cmipci *cm) {} | |||
| 2796 | #endif | 2796 | #endif |
| 2797 | 2797 | ||
| 2798 | 2798 | ||
| 2799 | static struct pci_device_id snd_cmipci_ids[] = { | 2799 | static DEFINE_PCI_DEVICE_TABLE(snd_cmipci_ids) = { |
| 2800 | {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A), 0}, | 2800 | {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338A), 0}, |
| 2801 | {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B), 0}, | 2801 | {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8338B), 0}, |
| 2802 | {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738), 0}, | 2802 | {PCI_VDEVICE(CMEDIA, PCI_DEVICE_ID_CMEDIA_CM8738), 0}, |
| @@ -3018,7 +3018,7 @@ static int __devinit snd_cmipci_create(struct snd_card *card, struct pci_dev *pc | |||
| 3018 | int integrated_midi = 0; | 3018 | int integrated_midi = 0; |
| 3019 | char modelstr[16]; | 3019 | char modelstr[16]; |
| 3020 | int pcm_index, pcm_spdif_index; | 3020 | int pcm_index, pcm_spdif_index; |
| 3021 | static struct pci_device_id intel_82437vx[] = { | 3021 | static DEFINE_PCI_DEVICE_TABLE(intel_82437vx) = { |
| 3022 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX) }, | 3022 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82437VX) }, |
| 3023 | { }, | 3023 | { }, |
| 3024 | }; | 3024 | }; |
diff --git a/sound/pci/cs4281.c b/sound/pci/cs4281.c index e2e0359bb056..9edc65059e3e 100644 --- a/sound/pci/cs4281.c +++ b/sound/pci/cs4281.c | |||
| @@ -494,7 +494,7 @@ struct cs4281 { | |||
| 494 | 494 | ||
| 495 | static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id); | 495 | static irqreturn_t snd_cs4281_interrupt(int irq, void *dev_id); |
| 496 | 496 | ||
| 497 | static struct pci_device_id snd_cs4281_ids[] = { | 497 | static DEFINE_PCI_DEVICE_TABLE(snd_cs4281_ids) = { |
| 498 | { PCI_VDEVICE(CIRRUS, 0x6005), 0, }, /* CS4281 */ | 498 | { PCI_VDEVICE(CIRRUS, 0x6005), 0, }, /* CS4281 */ |
| 499 | { 0, } | 499 | { 0, } |
| 500 | }; | 500 | }; |
diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c index 033aec430117..767fa7f06cd0 100644 --- a/sound/pci/cs46xx/cs46xx.c +++ b/sound/pci/cs46xx/cs46xx.c | |||
| @@ -64,7 +64,7 @@ MODULE_PARM_DESC(thinkpad, "Force to enable Thinkpad's CLKRUN control."); | |||
| 64 | module_param_array(mmap_valid, bool, NULL, 0444); | 64 | module_param_array(mmap_valid, bool, NULL, 0444); |
| 65 | MODULE_PARM_DESC(mmap_valid, "Support OSS mmap."); | 65 | MODULE_PARM_DESC(mmap_valid, "Support OSS mmap."); |
| 66 | 66 | ||
| 67 | static struct pci_device_id snd_cs46xx_ids[] = { | 67 | static DEFINE_PCI_DEVICE_TABLE(snd_cs46xx_ids) = { |
| 68 | { PCI_VDEVICE(CIRRUS, 0x6001), 0, }, /* CS4280 */ | 68 | { PCI_VDEVICE(CIRRUS, 0x6001), 0, }, /* CS4280 */ |
| 69 | { PCI_VDEVICE(CIRRUS, 0x6003), 0, }, /* CS4612 */ | 69 | { PCI_VDEVICE(CIRRUS, 0x6003), 0, }, /* CS4612 */ |
| 70 | { PCI_VDEVICE(CIRRUS, 0x6004), 0, }, /* CS4615 */ | 70 | { PCI_VDEVICE(CIRRUS, 0x6004), 0, }, /* CS4615 */ |
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 1be96ead4244..3f99a5e8528c 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c | |||
| @@ -2238,11 +2238,11 @@ static void snd_cs46xx_codec_reset (struct snd_ac97 * ac97) | |||
| 2238 | 2238 | ||
| 2239 | /* set the desired CODEC mode */ | 2239 | /* set the desired CODEC mode */ |
| 2240 | if (ac97->num == CS46XX_PRIMARY_CODEC_INDEX) { | 2240 | if (ac97->num == CS46XX_PRIMARY_CODEC_INDEX) { |
| 2241 | snd_printdd("cs46xx: CODOEC1 mode %04x\n",0x0); | 2241 | snd_printdd("cs46xx: CODEC1 mode %04x\n", 0x0); |
| 2242 | snd_cs46xx_ac97_write(ac97,AC97_CSR_ACMODE,0x0); | 2242 | snd_cs46xx_ac97_write(ac97, AC97_CSR_ACMODE, 0x0); |
| 2243 | } else if (ac97->num == CS46XX_SECONDARY_CODEC_INDEX) { | 2243 | } else if (ac97->num == CS46XX_SECONDARY_CODEC_INDEX) { |
| 2244 | snd_printdd("cs46xx: CODOEC2 mode %04x\n",0x3); | 2244 | snd_printdd("cs46xx: CODEC2 mode %04x\n", 0x3); |
| 2245 | snd_cs46xx_ac97_write(ac97,AC97_CSR_ACMODE,0x3); | 2245 | snd_cs46xx_ac97_write(ac97, AC97_CSR_ACMODE, 0x3); |
| 2246 | } else { | 2246 | } else { |
| 2247 | snd_BUG(); /* should never happen ... */ | 2247 | snd_BUG(); /* should never happen ... */ |
| 2248 | } | 2248 | } |
| @@ -2266,7 +2266,7 @@ static void snd_cs46xx_codec_reset (struct snd_ac97 * ac97) | |||
| 2266 | return; | 2266 | return; |
| 2267 | 2267 | ||
| 2268 | /* test if we can write to the record gain volume register */ | 2268 | /* test if we can write to the record gain volume register */ |
| 2269 | snd_ac97_write_cache(ac97, AC97_REC_GAIN, 0x8a05); | 2269 | snd_ac97_write(ac97, AC97_REC_GAIN, 0x8a05); |
| 2270 | if ((err = snd_ac97_read(ac97, AC97_REC_GAIN)) == 0x8a05) | 2270 | if ((err = snd_ac97_read(ac97, AC97_REC_GAIN)) == 0x8a05) |
| 2271 | return; | 2271 | return; |
| 2272 | 2272 | ||
| @@ -3597,7 +3597,7 @@ static struct cs_card_type __devinitdata cards[] = { | |||
| 3597 | #ifdef CONFIG_PM | 3597 | #ifdef CONFIG_PM |
| 3598 | static unsigned int saved_regs[] = { | 3598 | static unsigned int saved_regs[] = { |
| 3599 | BA0_ACOSV, | 3599 | BA0_ACOSV, |
| 3600 | BA0_ASER_FADDR, | 3600 | /*BA0_ASER_FADDR,*/ |
| 3601 | BA0_ASER_MASTER, | 3601 | BA0_ASER_MASTER, |
| 3602 | BA1_PVOL, | 3602 | BA1_PVOL, |
| 3603 | BA1_CVOL, | 3603 | BA1_CVOL, |
| @@ -3644,6 +3644,7 @@ int snd_cs46xx_resume(struct pci_dev *pci) | |||
| 3644 | #ifdef CONFIG_SND_CS46XX_NEW_DSP | 3644 | #ifdef CONFIG_SND_CS46XX_NEW_DSP |
| 3645 | int i; | 3645 | int i; |
| 3646 | #endif | 3646 | #endif |
| 3647 | unsigned int tmp; | ||
| 3647 | 3648 | ||
| 3648 | pci_set_power_state(pci, PCI_D0); | 3649 | pci_set_power_state(pci, PCI_D0); |
| 3649 | pci_restore_state(pci); | 3650 | pci_restore_state(pci); |
| @@ -3685,6 +3686,15 @@ int snd_cs46xx_resume(struct pci_dev *pci) | |||
| 3685 | snd_ac97_resume(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]); | 3686 | snd_ac97_resume(chip->ac97[CS46XX_PRIMARY_CODEC_INDEX]); |
| 3686 | snd_ac97_resume(chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]); | 3687 | snd_ac97_resume(chip->ac97[CS46XX_SECONDARY_CODEC_INDEX]); |
| 3687 | 3688 | ||
| 3689 | /* | ||
| 3690 | * Stop capture DMA. | ||
| 3691 | */ | ||
| 3692 | tmp = snd_cs46xx_peek(chip, BA1_CCTL); | ||
| 3693 | chip->capt.ctl = tmp & 0x0000ffff; | ||
| 3694 | snd_cs46xx_poke(chip, BA1_CCTL, tmp & 0xffff0000); | ||
| 3695 | |||
| 3696 | mdelay(5); | ||
| 3697 | |||
| 3688 | /* reset playback/capture */ | 3698 | /* reset playback/capture */ |
| 3689 | snd_cs46xx_set_play_sample_rate(chip, 8000); | 3699 | snd_cs46xx_set_play_sample_rate(chip, 8000); |
| 3690 | snd_cs46xx_set_capture_sample_rate(chip, 8000); | 3700 | snd_cs46xx_set_capture_sample_rate(chip, 8000); |
diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c index f4f0c8f5dad7..3e5ca8fb519f 100644 --- a/sound/pci/cs46xx/dsp_spos.c +++ b/sound/pci/cs46xx/dsp_spos.c | |||
| @@ -298,6 +298,9 @@ void cs46xx_dsp_spos_destroy (struct snd_cs46xx * chip) | |||
| 298 | if (ins->scbs[i].deleted) continue; | 298 | if (ins->scbs[i].deleted) continue; |
| 299 | 299 | ||
| 300 | cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) ); | 300 | cs46xx_dsp_proc_free_scb_desc ( (ins->scbs + i) ); |
| 301 | #ifdef CONFIG_PM | ||
| 302 | kfree(ins->scbs[i].data); | ||
| 303 | #endif | ||
| 301 | } | 304 | } |
| 302 | 305 | ||
| 303 | kfree(ins->code.data); | 306 | kfree(ins->code.data); |
| @@ -974,13 +977,11 @@ static struct dsp_scb_descriptor * _map_scb (struct snd_cs46xx *chip, char * nam | |||
| 974 | 977 | ||
| 975 | index = find_free_scb_index (ins); | 978 | index = find_free_scb_index (ins); |
| 976 | 979 | ||
| 980 | memset(&ins->scbs[index], 0, sizeof(ins->scbs[index])); | ||
| 977 | strcpy(ins->scbs[index].scb_name, name); | 981 | strcpy(ins->scbs[index].scb_name, name); |
| 978 | ins->scbs[index].address = dest; | 982 | ins->scbs[index].address = dest; |
| 979 | ins->scbs[index].index = index; | 983 | ins->scbs[index].index = index; |
| 980 | ins->scbs[index].proc_info = NULL; | ||
| 981 | ins->scbs[index].ref_count = 1; | 984 | ins->scbs[index].ref_count = 1; |
| 982 | ins->scbs[index].deleted = 0; | ||
| 983 | spin_lock_init(&ins->scbs[index].lock); | ||
| 984 | 985 | ||
| 985 | desc = (ins->scbs + index); | 986 | desc = (ins->scbs + index); |
| 986 | ins->scbs[index].scb_symbol = add_symbol (chip, name, dest, SYMBOL_PARAMETER); | 987 | ins->scbs[index].scb_symbol = add_symbol (chip, name, dest, SYMBOL_PARAMETER); |
| @@ -1022,17 +1023,29 @@ _map_task_tree (struct snd_cs46xx *chip, char * name, u32 dest, u32 size) | |||
| 1022 | return desc; | 1023 | return desc; |
| 1023 | } | 1024 | } |
| 1024 | 1025 | ||
| 1026 | #define SCB_BYTES (0x10 * 4) | ||
| 1027 | |||
| 1025 | struct dsp_scb_descriptor * | 1028 | struct dsp_scb_descriptor * |
| 1026 | cs46xx_dsp_create_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 dest) | 1029 | cs46xx_dsp_create_scb (struct snd_cs46xx *chip, char * name, u32 * scb_data, u32 dest) |
| 1027 | { | 1030 | { |
| 1028 | struct dsp_scb_descriptor * desc; | 1031 | struct dsp_scb_descriptor * desc; |
| 1029 | 1032 | ||
| 1033 | #ifdef CONFIG_PM | ||
| 1034 | /* copy the data for resume */ | ||
| 1035 | scb_data = kmemdup(scb_data, SCB_BYTES, GFP_KERNEL); | ||
| 1036 | if (!scb_data) | ||
| 1037 | return NULL; | ||
| 1038 | #endif | ||
| 1039 | |||
| 1030 | desc = _map_scb (chip,name,dest); | 1040 | desc = _map_scb (chip,name,dest); |
| 1031 | if (desc) { | 1041 | if (desc) { |
| 1032 | desc->data = scb_data; | 1042 | desc->data = scb_data; |
| 1033 | _dsp_create_scb(chip,scb_data,dest); | 1043 | _dsp_create_scb(chip,scb_data,dest); |
| 1034 | } else { | 1044 | } else { |
| 1035 | snd_printk(KERN_ERR "dsp_spos: failed to map SCB\n"); | 1045 | snd_printk(KERN_ERR "dsp_spos: failed to map SCB\n"); |
| 1046 | #ifdef CONFIG_PM | ||
| 1047 | kfree(scb_data); | ||
| 1048 | #endif | ||
| 1036 | } | 1049 | } |
| 1037 | 1050 | ||
| 1038 | return desc; | 1051 | return desc; |
| @@ -1988,7 +2001,28 @@ int cs46xx_dsp_resume(struct snd_cs46xx * chip) | |||
| 1988 | continue; | 2001 | continue; |
| 1989 | _dsp_create_scb(chip, s->data, s->address); | 2002 | _dsp_create_scb(chip, s->data, s->address); |
| 1990 | } | 2003 | } |
| 1991 | 2004 | for (i = 0; i < ins->nscb; i++) { | |
| 2005 | struct dsp_scb_descriptor *s = &ins->scbs[i]; | ||
| 2006 | if (s->deleted) | ||
| 2007 | continue; | ||
| 2008 | if (s->updated) | ||
| 2009 | cs46xx_dsp_spos_update_scb(chip, s); | ||
| 2010 | if (s->volume_set) | ||
| 2011 | cs46xx_dsp_scb_set_volume(chip, s, | ||
| 2012 | s->volume[0], s->volume[1]); | ||
| 2013 | } | ||
| 2014 | if (ins->spdif_status_out & DSP_SPDIF_STATUS_HW_ENABLED) { | ||
| 2015 | cs46xx_dsp_enable_spdif_hw(chip); | ||
| 2016 | snd_cs46xx_poke(chip, (ins->ref_snoop_scb->address + 2) << 2, | ||
| 2017 | (OUTPUT_SNOOP_BUFFER + 0x10) << 0x10); | ||
| 2018 | if (ins->spdif_status_out & DSP_SPDIF_STATUS_PLAYBACK_OPEN) | ||
| 2019 | cs46xx_poke_via_dsp(chip, SP_SPDOUT_CSUV, | ||
| 2020 | ins->spdif_csuv_stream); | ||
| 2021 | } | ||
| 2022 | if (chip->dsp_spos_instance->spdif_status_in) { | ||
| 2023 | cs46xx_poke_via_dsp(chip, SP_ASER_COUNTDOWN, 0x80000005); | ||
| 2024 | cs46xx_poke_via_dsp(chip, SP_SPDIN_CONTROL, 0x800003ff); | ||
| 2025 | } | ||
| 1992 | return 0; | 2026 | return 0; |
| 1993 | } | 2027 | } |
| 1994 | #endif | 2028 | #endif |
diff --git a/sound/pci/cs46xx/dsp_spos.h b/sound/pci/cs46xx/dsp_spos.h index f9e169d33c03..ca47a8114c7f 100644 --- a/sound/pci/cs46xx/dsp_spos.h +++ b/sound/pci/cs46xx/dsp_spos.h | |||
| @@ -212,6 +212,7 @@ static inline void cs46xx_dsp_spos_update_scb (struct snd_cs46xx * chip, | |||
| 212 | (scb->address + SCBsubListPtr) << 2, | 212 | (scb->address + SCBsubListPtr) << 2, |
| 213 | (scb->sub_list_ptr->address << 0x10) | | 213 | (scb->sub_list_ptr->address << 0x10) | |
| 214 | (scb->next_scb_ptr->address)); | 214 | (scb->next_scb_ptr->address)); |
| 215 | scb->updated = 1; | ||
| 215 | } | 216 | } |
| 216 | 217 | ||
| 217 | static inline void cs46xx_dsp_scb_set_volume (struct snd_cs46xx * chip, | 218 | static inline void cs46xx_dsp_scb_set_volume (struct snd_cs46xx * chip, |
| @@ -222,6 +223,9 @@ static inline void cs46xx_dsp_scb_set_volume (struct snd_cs46xx * chip, | |||
| 222 | 223 | ||
| 223 | snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl) << 2, val); | 224 | snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl) << 2, val); |
| 224 | snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl + 1) << 2, val); | 225 | snd_cs46xx_poke(chip, (scb->address + SCBVolumeCtrl + 1) << 2, val); |
| 226 | scb->volume_set = 1; | ||
| 227 | scb->volume[0] = left; | ||
| 228 | scb->volume[1] = right; | ||
| 225 | } | 229 | } |
| 226 | #endif /* __DSP_SPOS_H__ */ | 230 | #endif /* __DSP_SPOS_H__ */ |
| 227 | #endif /* CONFIG_SND_CS46XX_NEW_DSP */ | 231 | #endif /* CONFIG_SND_CS46XX_NEW_DSP */ |
diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c index dd7c41b037b4..00b148a10239 100644 --- a/sound/pci/cs46xx/dsp_spos_scb_lib.c +++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c | |||
| @@ -115,7 +115,6 @@ static void cs46xx_dsp_proc_scb_info_read (struct snd_info_entry *entry, | |||
| 115 | static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb) | 115 | static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * scb) |
| 116 | { | 116 | { |
| 117 | struct dsp_spos_instance * ins = chip->dsp_spos_instance; | 117 | struct dsp_spos_instance * ins = chip->dsp_spos_instance; |
| 118 | unsigned long flags; | ||
| 119 | 118 | ||
| 120 | if ( scb->parent_scb_ptr ) { | 119 | if ( scb->parent_scb_ptr ) { |
| 121 | /* unlink parent SCB */ | 120 | /* unlink parent SCB */ |
| @@ -153,8 +152,6 @@ static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor | |||
| 153 | scb->next_scb_ptr = ins->the_null_scb; | 152 | scb->next_scb_ptr = ins->the_null_scb; |
| 154 | } | 153 | } |
| 155 | 154 | ||
| 156 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
| 157 | |||
| 158 | /* update parent first entry in DSP RAM */ | 155 | /* update parent first entry in DSP RAM */ |
| 159 | cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr); | 156 | cs46xx_dsp_spos_update_scb(chip,scb->parent_scb_ptr); |
| 160 | 157 | ||
| @@ -162,7 +159,6 @@ static void _dsp_unlink_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor | |||
| 162 | cs46xx_dsp_spos_update_scb(chip,scb); | 159 | cs46xx_dsp_spos_update_scb(chip,scb); |
| 163 | 160 | ||
| 164 | scb->parent_scb_ptr = NULL; | 161 | scb->parent_scb_ptr = NULL; |
| 165 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
| 166 | } | 162 | } |
| 167 | } | 163 | } |
| 168 | 164 | ||
| @@ -197,9 +193,9 @@ void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * | |||
| 197 | goto _end; | 193 | goto _end; |
| 198 | #endif | 194 | #endif |
| 199 | 195 | ||
| 200 | spin_lock_irqsave(&scb->lock, flags); | 196 | spin_lock_irqsave(&chip->reg_lock, flags); |
| 201 | _dsp_unlink_scb (chip,scb); | 197 | _dsp_unlink_scb (chip,scb); |
| 202 | spin_unlock_irqrestore(&scb->lock, flags); | 198 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
| 203 | 199 | ||
| 204 | cs46xx_dsp_proc_free_scb_desc(scb); | 200 | cs46xx_dsp_proc_free_scb_desc(scb); |
| 205 | if (snd_BUG_ON(!scb->scb_symbol)) | 201 | if (snd_BUG_ON(!scb->scb_symbol)) |
| @@ -207,6 +203,10 @@ void cs46xx_dsp_remove_scb (struct snd_cs46xx *chip, struct dsp_scb_descriptor * | |||
| 207 | remove_symbol (chip,scb->scb_symbol); | 203 | remove_symbol (chip,scb->scb_symbol); |
| 208 | 204 | ||
| 209 | ins->scbs[scb->index].deleted = 1; | 205 | ins->scbs[scb->index].deleted = 1; |
| 206 | #ifdef CONFIG_PM | ||
| 207 | kfree(ins->scbs[scb->index].data); | ||
| 208 | ins->scbs[scb->index].data = NULL; | ||
| 209 | #endif | ||
| 210 | 210 | ||
| 211 | if (scb->index < ins->scb_highest_frag_index) | 211 | if (scb->index < ins->scb_highest_frag_index) |
| 212 | ins->scb_highest_frag_index = scb->index; | 212 | ins->scb_highest_frag_index = scb->index; |
| @@ -1508,20 +1508,17 @@ int cs46xx_dsp_pcm_unlink (struct snd_cs46xx * chip, | |||
| 1508 | chip->dsp_spos_instance->npcm_channels <= 0)) | 1508 | chip->dsp_spos_instance->npcm_channels <= 0)) |
| 1509 | return -EIO; | 1509 | return -EIO; |
| 1510 | 1510 | ||
| 1511 | spin_lock(&pcm_channel->src_scb->lock); | 1511 | spin_lock_irqsave(&chip->reg_lock, flags); |
| 1512 | |||
| 1513 | if (pcm_channel->unlinked) { | 1512 | if (pcm_channel->unlinked) { |
| 1514 | spin_unlock(&pcm_channel->src_scb->lock); | 1513 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
| 1515 | return -EIO; | 1514 | return -EIO; |
| 1516 | } | 1515 | } |
| 1517 | 1516 | ||
| 1518 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
| 1519 | pcm_channel->unlinked = 1; | 1517 | pcm_channel->unlinked = 1; |
| 1520 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
| 1521 | 1518 | ||
| 1522 | _dsp_unlink_scb (chip,pcm_channel->pcm_reader_scb); | 1519 | _dsp_unlink_scb (chip,pcm_channel->pcm_reader_scb); |
| 1520 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
| 1523 | 1521 | ||
| 1524 | spin_unlock(&pcm_channel->src_scb->lock); | ||
| 1525 | return 0; | 1522 | return 0; |
| 1526 | } | 1523 | } |
| 1527 | 1524 | ||
| @@ -1533,10 +1530,10 @@ int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip, | |||
| 1533 | struct dsp_scb_descriptor * src_scb = pcm_channel->src_scb; | 1530 | struct dsp_scb_descriptor * src_scb = pcm_channel->src_scb; |
| 1534 | unsigned long flags; | 1531 | unsigned long flags; |
| 1535 | 1532 | ||
| 1536 | spin_lock(&pcm_channel->src_scb->lock); | 1533 | spin_lock_irqsave(&chip->reg_lock, flags); |
| 1537 | 1534 | ||
| 1538 | if (pcm_channel->unlinked == 0) { | 1535 | if (pcm_channel->unlinked == 0) { |
| 1539 | spin_unlock(&pcm_channel->src_scb->lock); | 1536 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
| 1540 | return -EIO; | 1537 | return -EIO; |
| 1541 | } | 1538 | } |
| 1542 | 1539 | ||
| @@ -1552,8 +1549,6 @@ int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip, | |||
| 1552 | snd_BUG_ON(pcm_channel->pcm_reader_scb->parent_scb_ptr); | 1549 | snd_BUG_ON(pcm_channel->pcm_reader_scb->parent_scb_ptr); |
| 1553 | pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb; | 1550 | pcm_channel->pcm_reader_scb->parent_scb_ptr = parent_scb; |
| 1554 | 1551 | ||
| 1555 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
| 1556 | |||
| 1557 | /* update SCB entry in DSP RAM */ | 1552 | /* update SCB entry in DSP RAM */ |
| 1558 | cs46xx_dsp_spos_update_scb(chip,pcm_channel->pcm_reader_scb); | 1553 | cs46xx_dsp_spos_update_scb(chip,pcm_channel->pcm_reader_scb); |
| 1559 | 1554 | ||
| @@ -1562,8 +1557,6 @@ int cs46xx_dsp_pcm_link (struct snd_cs46xx * chip, | |||
| 1562 | 1557 | ||
| 1563 | pcm_channel->unlinked = 0; | 1558 | pcm_channel->unlinked = 0; |
| 1564 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 1559 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
| 1565 | |||
| 1566 | spin_unlock(&pcm_channel->src_scb->lock); | ||
| 1567 | return 0; | 1560 | return 0; |
| 1568 | } | 1561 | } |
| 1569 | 1562 | ||
| @@ -1596,13 +1589,17 @@ cs46xx_add_record_source (struct snd_cs46xx *chip, struct dsp_scb_descriptor * s | |||
| 1596 | 1589 | ||
| 1597 | int cs46xx_src_unlink(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src) | 1590 | int cs46xx_src_unlink(struct snd_cs46xx *chip, struct dsp_scb_descriptor * src) |
| 1598 | { | 1591 | { |
| 1592 | unsigned long flags; | ||
| 1593 | |||
| 1599 | if (snd_BUG_ON(!src->parent_scb_ptr)) | 1594 | if (snd_BUG_ON(!src->parent_scb_ptr)) |
| 1600 | return -EINVAL; | 1595 | return -EINVAL; |
| 1601 | 1596 | ||
| 1602 | /* mute SCB */ | 1597 | /* mute SCB */ |
| 1603 | cs46xx_dsp_scb_set_volume (chip,src,0,0); | 1598 | cs46xx_dsp_scb_set_volume (chip,src,0,0); |
| 1604 | 1599 | ||
| 1600 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
| 1605 | _dsp_unlink_scb (chip,src); | 1601 | _dsp_unlink_scb (chip,src); |
| 1602 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
| 1606 | 1603 | ||
| 1607 | return 0; | 1604 | return 0; |
| 1608 | } | 1605 | } |
diff --git a/sound/pci/cs5530.c b/sound/pci/cs5530.c index dc464321d0f3..207479a641cf 100644 --- a/sound/pci/cs5530.c +++ b/sound/pci/cs5530.c | |||
| @@ -58,7 +58,7 @@ struct snd_cs5530 { | |||
| 58 | unsigned long pci_base; | 58 | unsigned long pci_base; |
| 59 | }; | 59 | }; |
| 60 | 60 | ||
| 61 | static struct pci_device_id snd_cs5530_ids[] = { | 61 | static DEFINE_PCI_DEVICE_TABLE(snd_cs5530_ids) = { |
| 62 | {PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO, PCI_ANY_ID, | 62 | {PCI_VENDOR_ID_CYRIX, PCI_DEVICE_ID_CYRIX_5530_AUDIO, PCI_ANY_ID, |
| 63 | PCI_ANY_ID, 0, 0}, | 63 | PCI_ANY_ID, 0, 0}, |
| 64 | {0,} | 64 | {0,} |
diff --git a/sound/pci/cs5535audio/cs5535audio.c b/sound/pci/cs5535audio/cs5535audio.c index 91e7faf69bbb..afb803708416 100644 --- a/sound/pci/cs5535audio/cs5535audio.c +++ b/sound/pci/cs5535audio/cs5535audio.c | |||
| @@ -66,7 +66,7 @@ MODULE_PARM_DESC(id, "ID string for " DRIVER_NAME); | |||
| 66 | module_param_array(enable, bool, NULL, 0444); | 66 | module_param_array(enable, bool, NULL, 0444); |
| 67 | MODULE_PARM_DESC(enable, "Enable " DRIVER_NAME); | 67 | MODULE_PARM_DESC(enable, "Enable " DRIVER_NAME); |
| 68 | 68 | ||
| 69 | static struct pci_device_id snd_cs5535audio_ids[] = { | 69 | static DEFINE_PCI_DEVICE_TABLE(snd_cs5535audio_ids) = { |
| 70 | { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_AUDIO) }, | 70 | { PCI_DEVICE(PCI_VENDOR_ID_NS, PCI_DEVICE_ID_NS_CS5535_AUDIO) }, |
| 71 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_AUDIO) }, | 71 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_AUDIO) }, |
| 72 | {} | 72 | {} |
diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index 459c1f62783b..480cb1e905b6 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c | |||
| @@ -1214,10 +1214,11 @@ static int atc_dev_free(struct snd_device *dev) | |||
| 1214 | return ct_atc_destroy(atc); | 1214 | return ct_atc_destroy(atc); |
| 1215 | } | 1215 | } |
| 1216 | 1216 | ||
| 1217 | static int __devinit atc_identify_card(struct ct_atc *atc) | 1217 | static int __devinit atc_identify_card(struct ct_atc *atc, unsigned int ssid) |
| 1218 | { | 1218 | { |
| 1219 | const struct snd_pci_quirk *p; | 1219 | const struct snd_pci_quirk *p; |
| 1220 | const struct snd_pci_quirk *list; | 1220 | const struct snd_pci_quirk *list; |
| 1221 | u16 vendor_id, device_id; | ||
| 1221 | 1222 | ||
| 1222 | switch (atc->chip_type) { | 1223 | switch (atc->chip_type) { |
| 1223 | case ATC20K1: | 1224 | case ATC20K1: |
| @@ -1231,13 +1232,19 @@ static int __devinit atc_identify_card(struct ct_atc *atc) | |||
| 1231 | default: | 1232 | default: |
| 1232 | return -ENOENT; | 1233 | return -ENOENT; |
| 1233 | } | 1234 | } |
| 1234 | p = snd_pci_quirk_lookup(atc->pci, list); | 1235 | if (ssid) { |
| 1236 | vendor_id = ssid >> 16; | ||
| 1237 | device_id = ssid & 0xffff; | ||
| 1238 | } else { | ||
| 1239 | vendor_id = atc->pci->subsystem_vendor; | ||
| 1240 | device_id = atc->pci->subsystem_device; | ||
| 1241 | } | ||
| 1242 | p = snd_pci_quirk_lookup_id(vendor_id, device_id, list); | ||
| 1235 | if (p) { | 1243 | if (p) { |
| 1236 | if (p->value < 0) { | 1244 | if (p->value < 0) { |
| 1237 | printk(KERN_ERR "ctxfi: " | 1245 | printk(KERN_ERR "ctxfi: " |
| 1238 | "Device %04x:%04x is black-listed\n", | 1246 | "Device %04x:%04x is black-listed\n", |
| 1239 | atc->pci->subsystem_vendor, | 1247 | vendor_id, device_id); |
| 1240 | atc->pci->subsystem_device); | ||
| 1241 | return -ENOENT; | 1248 | return -ENOENT; |
| 1242 | } | 1249 | } |
| 1243 | atc->model = p->value; | 1250 | atc->model = p->value; |
| @@ -1250,8 +1257,7 @@ static int __devinit atc_identify_card(struct ct_atc *atc) | |||
| 1250 | atc->model_name = ct_subsys_name[atc->model]; | 1257 | atc->model_name = ct_subsys_name[atc->model]; |
| 1251 | snd_printd("ctxfi: chip %s model %s (%04x:%04x) is found\n", | 1258 | snd_printd("ctxfi: chip %s model %s (%04x:%04x) is found\n", |
| 1252 | atc->chip_name, atc->model_name, | 1259 | atc->chip_name, atc->model_name, |
| 1253 | atc->pci->subsystem_vendor, | 1260 | vendor_id, device_id); |
| 1254 | atc->pci->subsystem_device); | ||
| 1255 | return 0; | 1261 | return 0; |
| 1256 | } | 1262 | } |
| 1257 | 1263 | ||
| @@ -1625,7 +1631,8 @@ static struct ct_atc atc_preset __devinitdata = { | |||
| 1625 | 1631 | ||
| 1626 | int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, | 1632 | int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, |
| 1627 | unsigned int rsr, unsigned int msr, | 1633 | unsigned int rsr, unsigned int msr, |
| 1628 | int chip_type, struct ct_atc **ratc) | 1634 | int chip_type, unsigned int ssid, |
| 1635 | struct ct_atc **ratc) | ||
| 1629 | { | 1636 | { |
| 1630 | struct ct_atc *atc; | 1637 | struct ct_atc *atc; |
| 1631 | static struct snd_device_ops ops = { | 1638 | static struct snd_device_ops ops = { |
| @@ -1651,7 +1658,7 @@ int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, | |||
| 1651 | mutex_init(&atc->atc_mutex); | 1658 | mutex_init(&atc->atc_mutex); |
| 1652 | 1659 | ||
| 1653 | /* Find card model */ | 1660 | /* Find card model */ |
| 1654 | err = atc_identify_card(atc); | 1661 | err = atc_identify_card(atc, ssid); |
| 1655 | if (err < 0) { | 1662 | if (err < 0) { |
| 1656 | printk(KERN_ERR "ctatc: Card not recognised\n"); | 1663 | printk(KERN_ERR "ctatc: Card not recognised\n"); |
| 1657 | goto error1; | 1664 | goto error1; |
diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h index 9fd8a5708943..7167c0185d52 100644 --- a/sound/pci/ctxfi/ctatc.h +++ b/sound/pci/ctxfi/ctatc.h | |||
| @@ -148,7 +148,7 @@ struct ct_atc { | |||
| 148 | 148 | ||
| 149 | int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, | 149 | int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, |
| 150 | unsigned int rsr, unsigned int msr, int chip_type, | 150 | unsigned int rsr, unsigned int msr, int chip_type, |
| 151 | struct ct_atc **ratc); | 151 | unsigned int subsysid, struct ct_atc **ratc); |
| 152 | int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc); | 152 | int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc); |
| 153 | 153 | ||
| 154 | #endif /* CTATC_H */ | 154 | #endif /* CTATC_H */ |
diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c index 76541748e7bc..f42e7e1a1074 100644 --- a/sound/pci/ctxfi/xfi.c +++ b/sound/pci/ctxfi/xfi.c | |||
| @@ -32,6 +32,7 @@ module_param(multiple, uint, S_IRUGO); | |||
| 32 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | 32 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; |
| 33 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | 33 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; |
| 34 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | 34 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; |
| 35 | static unsigned int subsystem[SNDRV_CARDS]; | ||
| 35 | 36 | ||
| 36 | module_param_array(index, int, NULL, 0444); | 37 | module_param_array(index, int, NULL, 0444); |
| 37 | MODULE_PARM_DESC(index, "Index value for Creative X-Fi driver"); | 38 | MODULE_PARM_DESC(index, "Index value for Creative X-Fi driver"); |
| @@ -39,8 +40,10 @@ module_param_array(id, charp, NULL, 0444); | |||
| 39 | MODULE_PARM_DESC(id, "ID string for Creative X-Fi driver"); | 40 | MODULE_PARM_DESC(id, "ID string for Creative X-Fi driver"); |
| 40 | module_param_array(enable, bool, NULL, 0444); | 41 | module_param_array(enable, bool, NULL, 0444); |
| 41 | MODULE_PARM_DESC(enable, "Enable Creative X-Fi driver"); | 42 | MODULE_PARM_DESC(enable, "Enable Creative X-Fi driver"); |
| 43 | module_param_array(subsystem, int, NULL, 0444); | ||
| 44 | MODULE_PARM_DESC(subsystem, "Override subsystem ID for Creative X-Fi driver"); | ||
| 42 | 45 | ||
| 43 | static struct pci_device_id ct_pci_dev_ids[] = { | 46 | static DEFINE_PCI_DEVICE_TABLE(ct_pci_dev_ids) = { |
| 44 | /* only X-Fi is supported, so... */ | 47 | /* only X-Fi is supported, so... */ |
| 45 | { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_20K1), | 48 | { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_20K1), |
| 46 | .driver_data = ATC20K1, | 49 | .driver_data = ATC20K1, |
| @@ -85,7 +88,7 @@ ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) | |||
| 85 | multiple = 2; | 88 | multiple = 2; |
| 86 | } | 89 | } |
| 87 | err = ct_atc_create(card, pci, reference_rate, multiple, | 90 | err = ct_atc_create(card, pci, reference_rate, multiple, |
| 88 | pci_id->driver_data, &atc); | 91 | pci_id->driver_data, subsystem[dev], &atc); |
| 89 | if (err < 0) | 92 | if (err < 0) |
| 90 | goto error; | 93 | goto error; |
| 91 | 94 | ||
diff --git a/sound/pci/echoaudio/darla20.c b/sound/pci/echoaudio/darla20.c index 8c6db3aa3c1a..a65bafe0800f 100644 --- a/sound/pci/echoaudio/darla20.c +++ b/sound/pci/echoaudio/darla20.c | |||
| @@ -63,7 +63,7 @@ static const struct firmware card_fw[] = { | |||
| 63 | {0, "darla20_dsp.fw"} | 63 | {0, "darla20_dsp.fw"} |
| 64 | }; | 64 | }; |
| 65 | 65 | ||
| 66 | static struct pci_device_id snd_echo_ids[] = { | 66 | static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { |
| 67 | {0x1057, 0x1801, 0xECC0, 0x0010, 0, 0, 0}, /* DSP 56301 Darla20 rev.0 */ | 67 | {0x1057, 0x1801, 0xECC0, 0x0010, 0, 0, 0}, /* DSP 56301 Darla20 rev.0 */ |
| 68 | {0,} | 68 | {0,} |
| 69 | }; | 69 | }; |
diff --git a/sound/pci/echoaudio/darla20_dsp.c b/sound/pci/echoaudio/darla20_dsp.c index 29043301ebb8..20c7cbc89bb3 100644 --- a/sound/pci/echoaudio/darla20_dsp.c +++ b/sound/pci/echoaudio/darla20_dsp.c | |||
| @@ -45,7 +45,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 45 | chip->device_id = device_id; | 45 | chip->device_id = device_id; |
| 46 | chip->subdevice_id = subdevice_id; | 46 | chip->subdevice_id = subdevice_id; |
| 47 | chip->bad_board = TRUE; | 47 | chip->bad_board = TRUE; |
| 48 | chip->dsp_code_to_load = &card_fw[FW_DARLA20_DSP]; | 48 | chip->dsp_code_to_load = FW_DARLA20_DSP; |
| 49 | chip->spdif_status = GD_SPDIF_STATUS_UNDEF; | 49 | chip->spdif_status = GD_SPDIF_STATUS_UNDEF; |
| 50 | chip->clock_state = GD_CLOCK_UNDEF; | 50 | chip->clock_state = GD_CLOCK_UNDEF; |
| 51 | /* Since this card has no ASIC, mark it as loaded so everything | 51 | /* Since this card has no ASIC, mark it as loaded so everything |
| @@ -57,15 +57,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 57 | return err; | 57 | return err; |
| 58 | chip->bad_board = FALSE; | 58 | chip->bad_board = FALSE; |
| 59 | 59 | ||
| 60 | if ((err = init_line_levels(chip)) < 0) | ||
| 61 | return err; | ||
| 62 | |||
| 63 | DE_INIT(("init_hw done\n")); | 60 | DE_INIT(("init_hw done\n")); |
| 64 | return err; | 61 | return err; |
| 65 | } | 62 | } |
| 66 | 63 | ||
| 67 | 64 | ||
| 68 | 65 | ||
| 66 | static int set_mixer_defaults(struct echoaudio *chip) | ||
| 67 | { | ||
| 68 | return init_line_levels(chip); | ||
| 69 | } | ||
| 70 | |||
| 71 | |||
| 72 | |||
| 69 | /* The Darla20 has no external clock sources */ | 73 | /* The Darla20 has no external clock sources */ |
| 70 | static u32 detect_input_clocks(const struct echoaudio *chip) | 74 | static u32 detect_input_clocks(const struct echoaudio *chip) |
| 71 | { | 75 | { |
diff --git a/sound/pci/echoaudio/darla24.c b/sound/pci/echoaudio/darla24.c index 04cbf3eaf05a..0a6c50bcd758 100644 --- a/sound/pci/echoaudio/darla24.c +++ b/sound/pci/echoaudio/darla24.c | |||
| @@ -67,7 +67,7 @@ static const struct firmware card_fw[] = { | |||
| 67 | {0, "darla24_dsp.fw"} | 67 | {0, "darla24_dsp.fw"} |
| 68 | }; | 68 | }; |
| 69 | 69 | ||
| 70 | static struct pci_device_id snd_echo_ids[] = { | 70 | static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { |
| 71 | {0x1057, 0x1801, 0xECC0, 0x0040, 0, 0, 0}, /* DSP 56301 Darla24 rev.0 */ | 71 | {0x1057, 0x1801, 0xECC0, 0x0040, 0, 0, 0}, /* DSP 56301 Darla24 rev.0 */ |
| 72 | {0x1057, 0x1801, 0xECC0, 0x0041, 0, 0, 0}, /* DSP 56301 Darla24 rev.1 */ | 72 | {0x1057, 0x1801, 0xECC0, 0x0041, 0, 0, 0}, /* DSP 56301 Darla24 rev.1 */ |
| 73 | {0,} | 73 | {0,} |
diff --git a/sound/pci/echoaudio/darla24_dsp.c b/sound/pci/echoaudio/darla24_dsp.c index 60228731841f..6da6663e9176 100644 --- a/sound/pci/echoaudio/darla24_dsp.c +++ b/sound/pci/echoaudio/darla24_dsp.c | |||
| @@ -45,7 +45,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 45 | chip->device_id = device_id; | 45 | chip->device_id = device_id; |
| 46 | chip->subdevice_id = subdevice_id; | 46 | chip->subdevice_id = subdevice_id; |
| 47 | chip->bad_board = TRUE; | 47 | chip->bad_board = TRUE; |
| 48 | chip->dsp_code_to_load = &card_fw[FW_DARLA24_DSP]; | 48 | chip->dsp_code_to_load = FW_DARLA24_DSP; |
| 49 | /* Since this card has no ASIC, mark it as loaded so everything | 49 | /* Since this card has no ASIC, mark it as loaded so everything |
| 50 | works OK */ | 50 | works OK */ |
| 51 | chip->asic_loaded = TRUE; | 51 | chip->asic_loaded = TRUE; |
| @@ -56,15 +56,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 56 | return err; | 56 | return err; |
| 57 | chip->bad_board = FALSE; | 57 | chip->bad_board = FALSE; |
| 58 | 58 | ||
| 59 | if ((err = init_line_levels(chip)) < 0) | ||
| 60 | return err; | ||
| 61 | |||
| 62 | DE_INIT(("init_hw done\n")); | 59 | DE_INIT(("init_hw done\n")); |
| 63 | return err; | 60 | return err; |
| 64 | } | 61 | } |
| 65 | 62 | ||
| 66 | 63 | ||
| 67 | 64 | ||
| 65 | static int set_mixer_defaults(struct echoaudio *chip) | ||
| 66 | { | ||
| 67 | return init_line_levels(chip); | ||
| 68 | } | ||
| 69 | |||
| 70 | |||
| 71 | |||
| 68 | static u32 detect_input_clocks(const struct echoaudio *chip) | 72 | static u32 detect_input_clocks(const struct echoaudio *chip) |
| 69 | { | 73 | { |
| 70 | u32 clocks_from_dsp, clock_bits; | 74 | u32 clocks_from_dsp, clock_bits; |
diff --git a/sound/pci/echoaudio/echo3g.c b/sound/pci/echoaudio/echo3g.c index 4022e43a0053..f5142796989b 100644 --- a/sound/pci/echoaudio/echo3g.c +++ b/sound/pci/echoaudio/echo3g.c | |||
| @@ -81,7 +81,7 @@ static const struct firmware card_fw[] = { | |||
| 81 | {0, "3g_asic.fw"} | 81 | {0, "3g_asic.fw"} |
| 82 | }; | 82 | }; |
| 83 | 83 | ||
| 84 | static struct pci_device_id snd_echo_ids[] = { | 84 | static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { |
| 85 | {0x1057, 0x3410, 0xECC0, 0x0100, 0, 0, 0}, /* Echo 3G */ | 85 | {0x1057, 0x3410, 0xECC0, 0x0100, 0, 0, 0}, /* Echo 3G */ |
| 86 | {0,} | 86 | {0,} |
| 87 | }; | 87 | }; |
diff --git a/sound/pci/echoaudio/echo3g_dsp.c b/sound/pci/echoaudio/echo3g_dsp.c index 57967e580571..3cdc2ee2d1dd 100644 --- a/sound/pci/echoaudio/echo3g_dsp.c +++ b/sound/pci/echoaudio/echo3g_dsp.c | |||
| @@ -61,7 +61,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 61 | chip->subdevice_id = subdevice_id; | 61 | chip->subdevice_id = subdevice_id; |
| 62 | chip->bad_board = TRUE; | 62 | chip->bad_board = TRUE; |
| 63 | chip->has_midi = TRUE; | 63 | chip->has_midi = TRUE; |
| 64 | chip->dsp_code_to_load = &card_fw[FW_ECHO3G_DSP]; | 64 | chip->dsp_code_to_load = FW_ECHO3G_DSP; |
| 65 | 65 | ||
| 66 | /* Load the DSP code and the ASIC on the PCI card and get | 66 | /* Load the DSP code and the ASIC on the PCI card and get |
| 67 | what type of external box is attached */ | 67 | what type of external box is attached */ |
| @@ -97,20 +97,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 97 | chip->digital_modes = ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA | | 97 | chip->digital_modes = ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA | |
| 98 | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL | | 98 | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL | |
| 99 | ECHOCAPS_HAS_DIGITAL_MODE_ADAT; | 99 | ECHOCAPS_HAS_DIGITAL_MODE_ADAT; |
| 100 | chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; | ||
| 101 | chip->professional_spdif = FALSE; | ||
| 102 | chip->non_audio_spdif = FALSE; | ||
| 103 | chip->bad_board = FALSE; | ||
| 104 | |||
| 105 | if ((err = init_line_levels(chip)) < 0) | ||
| 106 | return err; | ||
| 107 | err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA); | ||
| 108 | if (err < 0) | ||
| 109 | return err; | ||
| 110 | err = set_phantom_power(chip, 0); | ||
| 111 | if (err < 0) | ||
| 112 | return err; | ||
| 113 | err = set_professional_spdif(chip, TRUE); | ||
| 114 | 100 | ||
| 115 | DE_INIT(("init_hw done\n")); | 101 | DE_INIT(("init_hw done\n")); |
| 116 | return err; | 102 | return err; |
| @@ -118,6 +104,18 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 118 | 104 | ||
| 119 | 105 | ||
| 120 | 106 | ||
| 107 | static int set_mixer_defaults(struct echoaudio *chip) | ||
| 108 | { | ||
| 109 | chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; | ||
| 110 | chip->professional_spdif = FALSE; | ||
| 111 | chip->non_audio_spdif = FALSE; | ||
| 112 | chip->bad_board = FALSE; | ||
| 113 | chip->phantom_power = FALSE; | ||
| 114 | return init_line_levels(chip); | ||
| 115 | } | ||
| 116 | |||
| 117 | |||
| 118 | |||
| 121 | static int set_phantom_power(struct echoaudio *chip, char on) | 119 | static int set_phantom_power(struct echoaudio *chip, char on) |
| 122 | { | 120 | { |
| 123 | u32 control_reg = le32_to_cpu(chip->comm_page->control_register); | 121 | u32 control_reg = le32_to_cpu(chip->comm_page->control_register); |
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 641d7f07392c..8dab82d7d19d 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c | |||
| @@ -36,22 +36,61 @@ MODULE_PARM_DESC(enable, "Enable " ECHOCARD_NAME " soundcard."); | |||
| 36 | static unsigned int channels_list[10] = {1, 2, 4, 6, 8, 10, 12, 14, 16, 999999}; | 36 | static unsigned int channels_list[10] = {1, 2, 4, 6, 8, 10, 12, 14, 16, 999999}; |
| 37 | static const DECLARE_TLV_DB_SCALE(db_scale_output_gain, -12800, 100, 1); | 37 | static const DECLARE_TLV_DB_SCALE(db_scale_output_gain, -12800, 100, 1); |
| 38 | 38 | ||
| 39 | |||
| 40 | |||
| 39 | static int get_firmware(const struct firmware **fw_entry, | 41 | static int get_firmware(const struct firmware **fw_entry, |
| 40 | const struct firmware *frm, struct echoaudio *chip) | 42 | struct echoaudio *chip, const short fw_index) |
| 41 | { | 43 | { |
| 42 | int err; | 44 | int err; |
| 43 | char name[30]; | 45 | char name[30]; |
| 44 | DE_ACT(("firmware requested: %s\n", frm->data)); | 46 | |
| 45 | snprintf(name, sizeof(name), "ea/%s", frm->data); | 47 | #ifdef CONFIG_PM |
| 46 | if ((err = request_firmware(fw_entry, name, pci_device(chip))) < 0) | 48 | if (chip->fw_cache[fw_index]) { |
| 49 | DE_ACT(("firmware requested: %s is cached\n", card_fw[fw_index].data)); | ||
| 50 | *fw_entry = chip->fw_cache[fw_index]; | ||
| 51 | return 0; | ||
| 52 | } | ||
| 53 | #endif | ||
| 54 | |||
| 55 | DE_ACT(("firmware requested: %s\n", card_fw[fw_index].data)); | ||
| 56 | snprintf(name, sizeof(name), "ea/%s", card_fw[fw_index].data); | ||
| 57 | err = request_firmware(fw_entry, name, pci_device(chip)); | ||
| 58 | if (err < 0) | ||
| 47 | snd_printk(KERN_ERR "get_firmware(): Firmware not available (%d)\n", err); | 59 | snd_printk(KERN_ERR "get_firmware(): Firmware not available (%d)\n", err); |
| 60 | #ifdef CONFIG_PM | ||
| 61 | else | ||
| 62 | chip->fw_cache[fw_index] = *fw_entry; | ||
| 63 | #endif | ||
| 48 | return err; | 64 | return err; |
| 49 | } | 65 | } |
| 50 | 66 | ||
| 67 | |||
| 68 | |||
| 51 | static void free_firmware(const struct firmware *fw_entry) | 69 | static void free_firmware(const struct firmware *fw_entry) |
| 52 | { | 70 | { |
| 71 | #ifdef CONFIG_PM | ||
| 72 | DE_ACT(("firmware not released (kept in cache)\n")); | ||
| 73 | #else | ||
| 53 | release_firmware(fw_entry); | 74 | release_firmware(fw_entry); |
| 54 | DE_ACT(("firmware released\n")); | 75 | DE_ACT(("firmware released\n")); |
| 76 | #endif | ||
| 77 | } | ||
| 78 | |||
| 79 | |||
| 80 | |||
| 81 | static void free_firmware_cache(struct echoaudio *chip) | ||
| 82 | { | ||
| 83 | #ifdef CONFIG_PM | ||
| 84 | int i; | ||
| 85 | |||
| 86 | for (i = 0; i < 8 ; i++) | ||
| 87 | if (chip->fw_cache[i]) { | ||
| 88 | release_firmware(chip->fw_cache[i]); | ||
| 89 | DE_ACT(("release_firmware(%d)\n", i)); | ||
| 90 | } | ||
| 91 | |||
| 92 | DE_ACT(("firmware_cache released\n")); | ||
| 93 | #endif | ||
| 55 | } | 94 | } |
| 56 | 95 | ||
| 57 | 96 | ||
| @@ -714,6 +753,8 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 714 | 753 | ||
| 715 | spin_lock(&chip->lock); | 754 | spin_lock(&chip->lock); |
| 716 | switch (cmd) { | 755 | switch (cmd) { |
| 756 | case SNDRV_PCM_TRIGGER_RESUME: | ||
| 757 | DE_ACT(("pcm_trigger resume\n")); | ||
| 717 | case SNDRV_PCM_TRIGGER_START: | 758 | case SNDRV_PCM_TRIGGER_START: |
| 718 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 759 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: |
| 719 | DE_ACT(("pcm_trigger start\n")); | 760 | DE_ACT(("pcm_trigger start\n")); |
| @@ -737,6 +778,8 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 737 | err = start_transport(chip, channelmask, | 778 | err = start_transport(chip, channelmask, |
| 738 | chip->pipe_cyclic_mask); | 779 | chip->pipe_cyclic_mask); |
| 739 | break; | 780 | break; |
| 781 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
| 782 | DE_ACT(("pcm_trigger suspend\n")); | ||
| 740 | case SNDRV_PCM_TRIGGER_STOP: | 783 | case SNDRV_PCM_TRIGGER_STOP: |
| 741 | DE_ACT(("pcm_trigger stop\n")); | 784 | DE_ACT(("pcm_trigger stop\n")); |
| 742 | for (i = 0; i < DSP_MAXPIPES; i++) { | 785 | for (i = 0; i < DSP_MAXPIPES; i++) { |
| @@ -1876,6 +1919,7 @@ static int snd_echo_free(struct echoaudio *chip) | |||
| 1876 | pci_disable_device(chip->pci); | 1919 | pci_disable_device(chip->pci); |
| 1877 | 1920 | ||
| 1878 | /* release chip data */ | 1921 | /* release chip data */ |
| 1922 | free_firmware_cache(chip); | ||
| 1879 | kfree(chip); | 1923 | kfree(chip); |
| 1880 | DE_INIT(("Chip freed.\n")); | 1924 | DE_INIT(("Chip freed.\n")); |
| 1881 | return 0; | 1925 | return 0; |
| @@ -1913,18 +1957,27 @@ static __devinit int snd_echo_create(struct snd_card *card, | |||
| 1913 | return err; | 1957 | return err; |
| 1914 | pci_set_master(pci); | 1958 | pci_set_master(pci); |
| 1915 | 1959 | ||
| 1916 | /* allocate a chip-specific data */ | 1960 | /* Allocate chip if needed */ |
| 1917 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | 1961 | if (!*rchip) { |
| 1918 | if (!chip) { | 1962 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); |
| 1919 | pci_disable_device(pci); | 1963 | if (!chip) { |
| 1920 | return -ENOMEM; | 1964 | pci_disable_device(pci); |
| 1965 | return -ENOMEM; | ||
| 1966 | } | ||
| 1967 | DE_INIT(("chip=%p\n", chip)); | ||
| 1968 | spin_lock_init(&chip->lock); | ||
| 1969 | chip->card = card; | ||
| 1970 | chip->pci = pci; | ||
| 1971 | chip->irq = -1; | ||
| 1972 | atomic_set(&chip->opencount, 0); | ||
| 1973 | mutex_init(&chip->mode_mutex); | ||
| 1974 | chip->can_set_rate = 1; | ||
| 1975 | } else { | ||
| 1976 | /* If this was called from the resume function, chip is | ||
| 1977 | * already allocated and it contains current card settings. | ||
| 1978 | */ | ||
| 1979 | chip = *rchip; | ||
| 1921 | } | 1980 | } |
| 1922 | DE_INIT(("chip=%p\n", chip)); | ||
| 1923 | |||
| 1924 | spin_lock_init(&chip->lock); | ||
| 1925 | chip->card = card; | ||
| 1926 | chip->pci = pci; | ||
| 1927 | chip->irq = -1; | ||
| 1928 | 1981 | ||
| 1929 | /* PCI resource allocation */ | 1982 | /* PCI resource allocation */ |
| 1930 | chip->dsp_registers_phys = pci_resource_start(pci, 0); | 1983 | chip->dsp_registers_phys = pci_resource_start(pci, 0); |
| @@ -1964,7 +2017,9 @@ static __devinit int snd_echo_create(struct snd_card *card, | |||
| 1964 | chip->comm_page = (struct comm_page *)chip->commpage_dma_buf.area; | 2017 | chip->comm_page = (struct comm_page *)chip->commpage_dma_buf.area; |
| 1965 | 2018 | ||
| 1966 | err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device); | 2019 | err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device); |
| 1967 | if (err) { | 2020 | if (err >= 0) |
| 2021 | err = set_mixer_defaults(chip); | ||
| 2022 | if (err < 0) { | ||
| 1968 | DE_INIT(("init_hw err=%d\n", err)); | 2023 | DE_INIT(("init_hw err=%d\n", err)); |
| 1969 | snd_echo_free(chip); | 2024 | snd_echo_free(chip); |
| 1970 | return err; | 2025 | return err; |
| @@ -1975,9 +2030,6 @@ static __devinit int snd_echo_create(struct snd_card *card, | |||
| 1975 | snd_echo_free(chip); | 2030 | snd_echo_free(chip); |
| 1976 | return err; | 2031 | return err; |
| 1977 | } | 2032 | } |
| 1978 | atomic_set(&chip->opencount, 0); | ||
| 1979 | mutex_init(&chip->mode_mutex); | ||
| 1980 | chip->can_set_rate = 1; | ||
| 1981 | *rchip = chip; | 2033 | *rchip = chip; |
| 1982 | /* Init done ! */ | 2034 | /* Init done ! */ |
| 1983 | return 0; | 2035 | return 0; |
| @@ -2010,6 +2062,7 @@ static int __devinit snd_echo_probe(struct pci_dev *pci, | |||
| 2010 | 2062 | ||
| 2011 | snd_card_set_dev(card, &pci->dev); | 2063 | snd_card_set_dev(card, &pci->dev); |
| 2012 | 2064 | ||
| 2065 | chip = NULL; /* Tells snd_echo_create to allocate chip */ | ||
| 2013 | if ((err = snd_echo_create(card, pci, &chip)) < 0) { | 2066 | if ((err = snd_echo_create(card, pci, &chip)) < 0) { |
| 2014 | snd_card_free(card); | 2067 | snd_card_free(card); |
| 2015 | return err; | 2068 | return err; |
| @@ -2149,6 +2202,112 @@ ctl_error: | |||
| 2149 | 2202 | ||
| 2150 | 2203 | ||
| 2151 | 2204 | ||
| 2205 | #if defined(CONFIG_PM) | ||
| 2206 | |||
| 2207 | static int snd_echo_suspend(struct pci_dev *pci, pm_message_t state) | ||
| 2208 | { | ||
| 2209 | struct echoaudio *chip = pci_get_drvdata(pci); | ||
| 2210 | |||
| 2211 | DE_INIT(("suspend start\n")); | ||
| 2212 | snd_pcm_suspend_all(chip->analog_pcm); | ||
| 2213 | snd_pcm_suspend_all(chip->digital_pcm); | ||
| 2214 | |||
| 2215 | #ifdef ECHOCARD_HAS_MIDI | ||
| 2216 | /* This call can sleep */ | ||
| 2217 | if (chip->midi_out) | ||
| 2218 | snd_echo_midi_output_trigger(chip->midi_out, 0); | ||
| 2219 | #endif | ||
| 2220 | spin_lock_irq(&chip->lock); | ||
| 2221 | if (wait_handshake(chip)) { | ||
| 2222 | spin_unlock_irq(&chip->lock); | ||
| 2223 | return -EIO; | ||
| 2224 | } | ||
| 2225 | clear_handshake(chip); | ||
| 2226 | if (send_vector(chip, DSP_VC_GO_COMATOSE) < 0) { | ||
| 2227 | spin_unlock_irq(&chip->lock); | ||
| 2228 | return -EIO; | ||
| 2229 | } | ||
| 2230 | spin_unlock_irq(&chip->lock); | ||
| 2231 | |||
| 2232 | chip->dsp_code = NULL; | ||
| 2233 | free_irq(chip->irq, chip); | ||
| 2234 | chip->irq = -1; | ||
| 2235 | pci_save_state(pci); | ||
| 2236 | pci_disable_device(pci); | ||
| 2237 | |||
| 2238 | DE_INIT(("suspend done\n")); | ||
| 2239 | return 0; | ||
| 2240 | } | ||
| 2241 | |||
| 2242 | |||
| 2243 | |||
| 2244 | static int snd_echo_resume(struct pci_dev *pci) | ||
| 2245 | { | ||
| 2246 | struct echoaudio *chip = pci_get_drvdata(pci); | ||
| 2247 | struct comm_page *commpage, *commpage_bak; | ||
| 2248 | u32 pipe_alloc_mask; | ||
| 2249 | int err; | ||
| 2250 | |||
| 2251 | DE_INIT(("resume start\n")); | ||
| 2252 | pci_restore_state(pci); | ||
| 2253 | commpage_bak = kmalloc(sizeof(struct echoaudio), GFP_KERNEL); | ||
| 2254 | commpage = chip->comm_page; | ||
| 2255 | memcpy(commpage_bak, commpage, sizeof(struct comm_page)); | ||
| 2256 | |||
| 2257 | err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device); | ||
| 2258 | if (err < 0) { | ||
| 2259 | kfree(commpage_bak); | ||
| 2260 | DE_INIT(("resume init_hw err=%d\n", err)); | ||
| 2261 | snd_echo_free(chip); | ||
| 2262 | return err; | ||
| 2263 | } | ||
| 2264 | DE_INIT(("resume init OK\n")); | ||
| 2265 | |||
| 2266 | /* Temporarily set chip->pipe_alloc_mask=0 otherwise | ||
| 2267 | * restore_dsp_settings() fails. | ||
| 2268 | */ | ||
| 2269 | pipe_alloc_mask = chip->pipe_alloc_mask; | ||
| 2270 | chip->pipe_alloc_mask = 0; | ||
| 2271 | err = restore_dsp_rettings(chip); | ||
| 2272 | chip->pipe_alloc_mask = pipe_alloc_mask; | ||
| 2273 | if (err < 0) { | ||
| 2274 | kfree(commpage_bak); | ||
| 2275 | return err; | ||
| 2276 | } | ||
| 2277 | DE_INIT(("resume restore OK\n")); | ||
| 2278 | |||
| 2279 | memcpy(&commpage->audio_format, &commpage_bak->audio_format, | ||
| 2280 | sizeof(commpage->audio_format)); | ||
| 2281 | memcpy(&commpage->sglist_addr, &commpage_bak->sglist_addr, | ||
| 2282 | sizeof(commpage->sglist_addr)); | ||
| 2283 | memcpy(&commpage->midi_output, &commpage_bak->midi_output, | ||
| 2284 | sizeof(commpage->midi_output)); | ||
| 2285 | kfree(commpage_bak); | ||
| 2286 | |||
| 2287 | if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED, | ||
| 2288 | ECHOCARD_NAME, chip)) { | ||
| 2289 | snd_echo_free(chip); | ||
| 2290 | snd_printk(KERN_ERR "cannot grab irq\n"); | ||
| 2291 | return -EBUSY; | ||
| 2292 | } | ||
| 2293 | chip->irq = pci->irq; | ||
| 2294 | DE_INIT(("resume irq=%d\n", chip->irq)); | ||
| 2295 | |||
| 2296 | #ifdef ECHOCARD_HAS_MIDI | ||
| 2297 | if (chip->midi_input_enabled) | ||
| 2298 | enable_midi_input(chip, TRUE); | ||
| 2299 | if (chip->midi_out) | ||
| 2300 | snd_echo_midi_output_trigger(chip->midi_out, 1); | ||
| 2301 | #endif | ||
| 2302 | |||
| 2303 | DE_INIT(("resume done\n")); | ||
| 2304 | return 0; | ||
| 2305 | } | ||
| 2306 | |||
| 2307 | #endif /* CONFIG_PM */ | ||
| 2308 | |||
| 2309 | |||
| 2310 | |||
| 2152 | static void __devexit snd_echo_remove(struct pci_dev *pci) | 2311 | static void __devexit snd_echo_remove(struct pci_dev *pci) |
| 2153 | { | 2312 | { |
| 2154 | struct echoaudio *chip; | 2313 | struct echoaudio *chip; |
| @@ -2171,6 +2330,10 @@ static struct pci_driver driver = { | |||
| 2171 | .id_table = snd_echo_ids, | 2330 | .id_table = snd_echo_ids, |
| 2172 | .probe = snd_echo_probe, | 2331 | .probe = snd_echo_probe, |
| 2173 | .remove = __devexit_p(snd_echo_remove), | 2332 | .remove = __devexit_p(snd_echo_remove), |
| 2333 | #ifdef CONFIG_PM | ||
| 2334 | .suspend = snd_echo_suspend, | ||
| 2335 | .resume = snd_echo_resume, | ||
| 2336 | #endif /* CONFIG_PM */ | ||
| 2174 | }; | 2337 | }; |
| 2175 | 2338 | ||
| 2176 | 2339 | ||
diff --git a/sound/pci/echoaudio/echoaudio.h b/sound/pci/echoaudio/echoaudio.h index f9490ae36c2e..1df974dcb5f4 100644 --- a/sound/pci/echoaudio/echoaudio.h +++ b/sound/pci/echoaudio/echoaudio.h | |||
| @@ -442,13 +442,16 @@ struct echoaudio { | |||
| 442 | u16 device_id, subdevice_id; | 442 | u16 device_id, subdevice_id; |
| 443 | u16 *dsp_code; /* Current DSP code loaded, | 443 | u16 *dsp_code; /* Current DSP code loaded, |
| 444 | * NULL if nothing loaded */ | 444 | * NULL if nothing loaded */ |
| 445 | const struct firmware *dsp_code_to_load;/* DSP code to load */ | 445 | short dsp_code_to_load; /* DSP code to load */ |
| 446 | const struct firmware *asic_code; /* Current ASIC code */ | 446 | short asic_code; /* Current ASIC code */ |
| 447 | u32 comm_page_phys; /* Physical address of the | 447 | u32 comm_page_phys; /* Physical address of the |
| 448 | * memory seen by DSP */ | 448 | * memory seen by DSP */ |
| 449 | volatile u32 __iomem *dsp_registers; /* DSP's register base */ | 449 | volatile u32 __iomem *dsp_registers; /* DSP's register base */ |
| 450 | u32 active_mask; /* Chs. active mask or | 450 | u32 active_mask; /* Chs. active mask or |
| 451 | * punks out */ | 451 | * punks out */ |
| 452 | #ifdef CONFIG_PM | ||
| 453 | const struct firmware *fw_cache[8]; /* Cached firmwares */ | ||
| 454 | #endif | ||
| 452 | 455 | ||
| 453 | #ifdef ECHOCARD_HAS_MIDI | 456 | #ifdef ECHOCARD_HAS_MIDI |
| 454 | u16 mtc_state; /* State for MIDI input parsing state machine */ | 457 | u16 mtc_state; /* State for MIDI input parsing state machine */ |
| @@ -464,11 +467,13 @@ static int load_firmware(struct echoaudio *chip); | |||
| 464 | static int wait_handshake(struct echoaudio *chip); | 467 | static int wait_handshake(struct echoaudio *chip); |
| 465 | static int send_vector(struct echoaudio *chip, u32 command); | 468 | static int send_vector(struct echoaudio *chip, u32 command); |
| 466 | static int get_firmware(const struct firmware **fw_entry, | 469 | static int get_firmware(const struct firmware **fw_entry, |
| 467 | const struct firmware *frm, struct echoaudio *chip); | 470 | struct echoaudio *chip, const short fw_index); |
| 468 | static void free_firmware(const struct firmware *fw_entry); | 471 | static void free_firmware(const struct firmware *fw_entry); |
| 469 | 472 | ||
| 470 | #ifdef ECHOCARD_HAS_MIDI | 473 | #ifdef ECHOCARD_HAS_MIDI |
| 471 | static int enable_midi_input(struct echoaudio *chip, char enable); | 474 | static int enable_midi_input(struct echoaudio *chip, char enable); |
| 475 | static void snd_echo_midi_output_trigger( | ||
| 476 | struct snd_rawmidi_substream *substream, int up); | ||
| 472 | static int midi_service_irq(struct echoaudio *chip); | 477 | static int midi_service_irq(struct echoaudio *chip); |
| 473 | static int __devinit snd_echo_midi_create(struct snd_card *card, | 478 | static int __devinit snd_echo_midi_create(struct snd_card *card, |
| 474 | struct echoaudio *chip); | 479 | struct echoaudio *chip); |
diff --git a/sound/pci/echoaudio/echoaudio_3g.c b/sound/pci/echoaudio/echoaudio_3g.c index e32a74897921..658db44ef746 100644 --- a/sound/pci/echoaudio/echoaudio_3g.c +++ b/sound/pci/echoaudio/echoaudio_3g.c | |||
| @@ -227,12 +227,11 @@ static int load_asic(struct echoaudio *chip) | |||
| 227 | /* Give the DSP a few milliseconds to settle down */ | 227 | /* Give the DSP a few milliseconds to settle down */ |
| 228 | mdelay(2); | 228 | mdelay(2); |
| 229 | 229 | ||
| 230 | err = load_asic_generic(chip, DSP_FNC_LOAD_3G_ASIC, | 230 | err = load_asic_generic(chip, DSP_FNC_LOAD_3G_ASIC, FW_3G_ASIC); |
| 231 | &card_fw[FW_3G_ASIC]); | ||
| 232 | if (err < 0) | 231 | if (err < 0) |
| 233 | return err; | 232 | return err; |
| 234 | 233 | ||
| 235 | chip->asic_code = &card_fw[FW_3G_ASIC]; | 234 | chip->asic_code = FW_3G_ASIC; |
| 236 | 235 | ||
| 237 | /* Now give the new ASIC some time to set up */ | 236 | /* Now give the new ASIC some time to set up */ |
| 238 | msleep(1000); | 237 | msleep(1000); |
diff --git a/sound/pci/echoaudio/echoaudio_dsp.c b/sound/pci/echoaudio/echoaudio_dsp.c index 4df51ef5e095..64417a733220 100644 --- a/sound/pci/echoaudio/echoaudio_dsp.c +++ b/sound/pci/echoaudio/echoaudio_dsp.c | |||
| @@ -175,15 +175,15 @@ static inline int check_asic_status(struct echoaudio *chip) | |||
| 175 | #ifdef ECHOCARD_HAS_ASIC | 175 | #ifdef ECHOCARD_HAS_ASIC |
| 176 | 176 | ||
| 177 | /* Load ASIC code - done after the DSP is loaded */ | 177 | /* Load ASIC code - done after the DSP is loaded */ |
| 178 | static int load_asic_generic(struct echoaudio *chip, u32 cmd, | 178 | static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic) |
| 179 | const struct firmware *asic) | ||
| 180 | { | 179 | { |
| 181 | const struct firmware *fw; | 180 | const struct firmware *fw; |
| 182 | int err; | 181 | int err; |
| 183 | u32 i, size; | 182 | u32 i, size; |
| 184 | u8 *code; | 183 | u8 *code; |
| 185 | 184 | ||
| 186 | if ((err = get_firmware(&fw, asic, chip)) < 0) { | 185 | err = get_firmware(&fw, chip, asic); |
| 186 | if (err < 0) { | ||
| 187 | snd_printk(KERN_WARNING "Firmware not found !\n"); | 187 | snd_printk(KERN_WARNING "Firmware not found !\n"); |
| 188 | return err; | 188 | return err; |
| 189 | } | 189 | } |
| @@ -245,7 +245,8 @@ static int install_resident_loader(struct echoaudio *chip) | |||
| 245 | return 0; | 245 | return 0; |
| 246 | } | 246 | } |
| 247 | 247 | ||
| 248 | if ((i = get_firmware(&fw, &card_fw[FW_361_LOADER], chip)) < 0) { | 248 | i = get_firmware(&fw, chip, FW_361_LOADER); |
| 249 | if (i < 0) { | ||
| 249 | snd_printk(KERN_WARNING "Firmware not found !\n"); | 250 | snd_printk(KERN_WARNING "Firmware not found !\n"); |
| 250 | return i; | 251 | return i; |
| 251 | } | 252 | } |
| @@ -485,7 +486,8 @@ static int load_firmware(struct echoaudio *chip) | |||
| 485 | chip->dsp_code = NULL; | 486 | chip->dsp_code = NULL; |
| 486 | } | 487 | } |
| 487 | 488 | ||
| 488 | if ((err = get_firmware(&fw, chip->dsp_code_to_load, chip)) < 0) | 489 | err = get_firmware(&fw, chip, chip->dsp_code_to_load); |
| 490 | if (err < 0) | ||
| 489 | return err; | 491 | return err; |
| 490 | err = load_dsp(chip, (u16 *)fw->data); | 492 | err = load_dsp(chip, (u16 *)fw->data); |
| 491 | free_firmware(fw); | 493 | free_firmware(fw); |
| @@ -495,9 +497,6 @@ static int load_firmware(struct echoaudio *chip) | |||
| 495 | if ((box_type = load_asic(chip)) < 0) | 497 | if ((box_type = load_asic(chip)) < 0) |
| 496 | return box_type; /* error */ | 498 | return box_type; /* error */ |
| 497 | 499 | ||
| 498 | if ((err = restore_dsp_rettings(chip)) < 0) | ||
| 499 | return err; | ||
| 500 | |||
| 501 | return box_type; | 500 | return box_type; |
| 502 | } | 501 | } |
| 503 | 502 | ||
| @@ -657,51 +656,106 @@ static void get_audio_meters(struct echoaudio *chip, long *meters) | |||
| 657 | 656 | ||
| 658 | static int restore_dsp_rettings(struct echoaudio *chip) | 657 | static int restore_dsp_rettings(struct echoaudio *chip) |
| 659 | { | 658 | { |
| 660 | int err; | 659 | int i, o, err; |
| 661 | DE_INIT(("restore_dsp_settings\n")); | 660 | DE_INIT(("restore_dsp_settings\n")); |
| 662 | 661 | ||
| 663 | if ((err = check_asic_status(chip)) < 0) | 662 | if ((err = check_asic_status(chip)) < 0) |
| 664 | return err; | 663 | return err; |
| 665 | 664 | ||
| 666 | /* @ Gina20/Darla20 only. Should be harmless for other cards. */ | 665 | /* Gina20/Darla20 only. Should be harmless for other cards. */ |
| 667 | chip->comm_page->gd_clock_state = GD_CLOCK_UNDEF; | 666 | chip->comm_page->gd_clock_state = GD_CLOCK_UNDEF; |
| 668 | chip->comm_page->gd_spdif_status = GD_SPDIF_STATUS_UNDEF; | 667 | chip->comm_page->gd_spdif_status = GD_SPDIF_STATUS_UNDEF; |
| 669 | chip->comm_page->handshake = 0xffffffff; | 668 | chip->comm_page->handshake = 0xffffffff; |
| 670 | 669 | ||
| 671 | if ((err = set_sample_rate(chip, chip->sample_rate)) < 0) | 670 | /* Restore output busses */ |
| 671 | for (i = 0; i < num_busses_out(chip); i++) { | ||
| 672 | err = set_output_gain(chip, i, chip->output_gain[i]); | ||
| 673 | if (err < 0) | ||
| 674 | return err; | ||
| 675 | } | ||
| 676 | |||
| 677 | #ifdef ECHOCARD_HAS_VMIXER | ||
| 678 | for (i = 0; i < num_pipes_out(chip); i++) | ||
| 679 | for (o = 0; o < num_busses_out(chip); o++) { | ||
| 680 | err = set_vmixer_gain(chip, o, i, | ||
| 681 | chip->vmixer_gain[o][i]); | ||
| 682 | if (err < 0) | ||
| 683 | return err; | ||
| 684 | } | ||
| 685 | if (update_vmixer_level(chip) < 0) | ||
| 686 | return -EIO; | ||
| 687 | #endif /* ECHOCARD_HAS_VMIXER */ | ||
| 688 | |||
| 689 | #ifdef ECHOCARD_HAS_MONITOR | ||
| 690 | for (o = 0; o < num_busses_out(chip); o++) | ||
| 691 | for (i = 0; i < num_busses_in(chip); i++) { | ||
| 692 | err = set_monitor_gain(chip, o, i, | ||
| 693 | chip->monitor_gain[o][i]); | ||
| 694 | if (err < 0) | ||
| 695 | return err; | ||
| 696 | } | ||
| 697 | #endif /* ECHOCARD_HAS_MONITOR */ | ||
| 698 | |||
| 699 | #ifdef ECHOCARD_HAS_INPUT_GAIN | ||
| 700 | for (i = 0; i < num_busses_in(chip); i++) { | ||
| 701 | err = set_input_gain(chip, i, chip->input_gain[i]); | ||
| 702 | if (err < 0) | ||
| 703 | return err; | ||
| 704 | } | ||
| 705 | #endif /* ECHOCARD_HAS_INPUT_GAIN */ | ||
| 706 | |||
| 707 | err = update_output_line_level(chip); | ||
| 708 | if (err < 0) | ||
| 672 | return err; | 709 | return err; |
| 673 | 710 | ||
| 674 | if (chip->meters_enabled) | 711 | err = update_input_line_level(chip); |
| 675 | if (send_vector(chip, DSP_VC_METERS_ON) < 0) | 712 | if (err < 0) |
| 676 | return -EIO; | 713 | return err; |
| 677 | 714 | ||
| 678 | #ifdef ECHOCARD_HAS_EXTERNAL_CLOCK | 715 | err = set_sample_rate(chip, chip->sample_rate); |
| 679 | if (set_input_clock(chip, chip->input_clock) < 0) | 716 | if (err < 0) |
| 717 | return err; | ||
| 718 | |||
| 719 | if (chip->meters_enabled) { | ||
| 720 | err = send_vector(chip, DSP_VC_METERS_ON); | ||
| 721 | if (err < 0) | ||
| 722 | return err; | ||
| 723 | } | ||
| 724 | |||
| 725 | #ifdef ECHOCARD_HAS_DIGITAL_MODE_SWITCH | ||
| 726 | if (set_digital_mode(chip, chip->digital_mode) < 0) | ||
| 680 | return -EIO; | 727 | return -EIO; |
| 681 | #endif | 728 | #endif |
| 682 | 729 | ||
| 683 | #ifdef ECHOCARD_HAS_OUTPUT_CLOCK_SWITCH | 730 | #ifdef ECHOCARD_HAS_DIGITAL_IO |
| 684 | if (set_output_clock(chip, chip->output_clock) < 0) | 731 | if (set_professional_spdif(chip, chip->professional_spdif) < 0) |
| 685 | return -EIO; | 732 | return -EIO; |
| 686 | #endif | 733 | #endif |
| 687 | 734 | ||
| 688 | if (update_output_line_level(chip) < 0) | 735 | #ifdef ECHOCARD_HAS_PHANTOM_POWER |
| 736 | if (set_phantom_power(chip, chip->phantom_power) < 0) | ||
| 689 | return -EIO; | 737 | return -EIO; |
| 738 | #endif | ||
| 690 | 739 | ||
| 691 | if (update_input_line_level(chip) < 0) | 740 | #ifdef ECHOCARD_HAS_EXTERNAL_CLOCK |
| 741 | /* set_input_clock() also restores automute setting */ | ||
| 742 | if (set_input_clock(chip, chip->input_clock) < 0) | ||
| 692 | return -EIO; | 743 | return -EIO; |
| 744 | #endif | ||
| 693 | 745 | ||
| 694 | #ifdef ECHOCARD_HAS_VMIXER | 746 | #ifdef ECHOCARD_HAS_OUTPUT_CLOCK_SWITCH |
| 695 | if (update_vmixer_level(chip) < 0) | 747 | if (set_output_clock(chip, chip->output_clock) < 0) |
| 696 | return -EIO; | 748 | return -EIO; |
| 697 | #endif | 749 | #endif |
| 698 | 750 | ||
| 699 | if (wait_handshake(chip) < 0) | 751 | if (wait_handshake(chip) < 0) |
| 700 | return -EIO; | 752 | return -EIO; |
| 701 | clear_handshake(chip); | 753 | clear_handshake(chip); |
| 754 | if (send_vector(chip, DSP_VC_UPDATE_FLAGS) < 0) | ||
| 755 | return -EIO; | ||
| 702 | 756 | ||
| 703 | DE_INIT(("restore_dsp_rettings done\n")); | 757 | DE_INIT(("restore_dsp_rettings done\n")); |
| 704 | return send_vector(chip, DSP_VC_UPDATE_FLAGS); | 758 | return 0; |
| 705 | } | 759 | } |
| 706 | 760 | ||
| 707 | 761 | ||
| @@ -918,9 +972,6 @@ static int init_dsp_comm_page(struct echoaudio *chip) | |||
| 918 | chip->card_name = ECHOCARD_NAME; | 972 | chip->card_name = ECHOCARD_NAME; |
| 919 | chip->bad_board = TRUE; /* Set TRUE until DSP loaded */ | 973 | chip->bad_board = TRUE; /* Set TRUE until DSP loaded */ |
| 920 | chip->dsp_code = NULL; /* Current DSP code not loaded */ | 974 | chip->dsp_code = NULL; /* Current DSP code not loaded */ |
| 921 | chip->digital_mode = DIGITAL_MODE_NONE; | ||
| 922 | chip->input_clock = ECHO_CLOCK_INTERNAL; | ||
| 923 | chip->output_clock = ECHO_CLOCK_WORD; | ||
| 924 | chip->asic_loaded = FALSE; | 975 | chip->asic_loaded = FALSE; |
| 925 | memset(chip->comm_page, 0, sizeof(struct comm_page)); | 976 | memset(chip->comm_page, 0, sizeof(struct comm_page)); |
| 926 | 977 | ||
| @@ -931,7 +982,6 @@ static int init_dsp_comm_page(struct echoaudio *chip) | |||
| 931 | chip->comm_page->midi_out_free_count = | 982 | chip->comm_page->midi_out_free_count = |
| 932 | cpu_to_le32(DSP_MIDI_OUT_FIFO_SIZE); | 983 | cpu_to_le32(DSP_MIDI_OUT_FIFO_SIZE); |
| 933 | chip->comm_page->sample_rate = cpu_to_le32(44100); | 984 | chip->comm_page->sample_rate = cpu_to_le32(44100); |
| 934 | chip->sample_rate = 44100; | ||
| 935 | 985 | ||
| 936 | /* Set line levels so we don't blast any inputs on startup */ | 986 | /* Set line levels so we don't blast any inputs on startup */ |
| 937 | memset(chip->comm_page->monitors, ECHOGAIN_MUTED, MONITOR_ARRAY_SIZE); | 987 | memset(chip->comm_page->monitors, ECHOGAIN_MUTED, MONITOR_ARRAY_SIZE); |
| @@ -942,50 +992,21 @@ static int init_dsp_comm_page(struct echoaudio *chip) | |||
| 942 | 992 | ||
| 943 | 993 | ||
| 944 | 994 | ||
| 945 | /* This function initializes the several volume controls for busses and pipes. | 995 | /* This function initializes the chip structure with default values, ie. all |
| 946 | This MUST be called after the DSP is up and running ! */ | 996 | * muted and internal clock source. Then it copies the settings to the DSP. |
| 997 | * This MUST be called after the DSP is up and running ! | ||
| 998 | */ | ||
| 947 | static int init_line_levels(struct echoaudio *chip) | 999 | static int init_line_levels(struct echoaudio *chip) |
| 948 | { | 1000 | { |
| 949 | int st, i, o; | ||
| 950 | |||
| 951 | DE_INIT(("init_line_levels\n")); | 1001 | DE_INIT(("init_line_levels\n")); |
| 952 | 1002 | memset(chip->output_gain, ECHOGAIN_MUTED, sizeof(chip->output_gain)); | |
| 953 | /* Mute output busses */ | 1003 | memset(chip->input_gain, ECHOGAIN_MUTED, sizeof(chip->input_gain)); |
| 954 | for (i = 0; i < num_busses_out(chip); i++) | 1004 | memset(chip->monitor_gain, ECHOGAIN_MUTED, sizeof(chip->monitor_gain)); |
| 955 | if ((st = set_output_gain(chip, i, ECHOGAIN_MUTED))) | 1005 | memset(chip->vmixer_gain, ECHOGAIN_MUTED, sizeof(chip->vmixer_gain)); |
| 956 | return st; | 1006 | chip->input_clock = ECHO_CLOCK_INTERNAL; |
| 957 | if ((st = update_output_line_level(chip))) | 1007 | chip->output_clock = ECHO_CLOCK_WORD; |
| 958 | return st; | 1008 | chip->sample_rate = 44100; |
| 959 | 1009 | return restore_dsp_rettings(chip); | |
| 960 | #ifdef ECHOCARD_HAS_VMIXER | ||
| 961 | /* Mute the Vmixer */ | ||
| 962 | for (i = 0; i < num_pipes_out(chip); i++) | ||
| 963 | for (o = 0; o < num_busses_out(chip); o++) | ||
| 964 | if ((st = set_vmixer_gain(chip, o, i, ECHOGAIN_MUTED))) | ||
| 965 | return st; | ||
| 966 | if ((st = update_vmixer_level(chip))) | ||
| 967 | return st; | ||
| 968 | #endif /* ECHOCARD_HAS_VMIXER */ | ||
| 969 | |||
| 970 | #ifdef ECHOCARD_HAS_MONITOR | ||
| 971 | /* Mute the monitor mixer */ | ||
| 972 | for (o = 0; o < num_busses_out(chip); o++) | ||
| 973 | for (i = 0; i < num_busses_in(chip); i++) | ||
| 974 | if ((st = set_monitor_gain(chip, o, i, ECHOGAIN_MUTED))) | ||
| 975 | return st; | ||
| 976 | if ((st = update_output_line_level(chip))) | ||
| 977 | return st; | ||
| 978 | #endif /* ECHOCARD_HAS_MONITOR */ | ||
| 979 | |||
| 980 | #ifdef ECHOCARD_HAS_INPUT_GAIN | ||
| 981 | for (i = 0; i < num_busses_in(chip); i++) | ||
| 982 | if ((st = set_input_gain(chip, i, ECHOGAIN_MUTED))) | ||
| 983 | return st; | ||
| 984 | if ((st = update_input_line_level(chip))) | ||
| 985 | return st; | ||
| 986 | #endif /* ECHOCARD_HAS_INPUT_GAIN */ | ||
| 987 | |||
| 988 | return 0; | ||
| 989 | } | 1010 | } |
| 990 | 1011 | ||
| 991 | 1012 | ||
diff --git a/sound/pci/echoaudio/gina20.c b/sound/pci/echoaudio/gina20.c index c0e64b8f52a4..2364f8a1bc21 100644 --- a/sound/pci/echoaudio/gina20.c +++ b/sound/pci/echoaudio/gina20.c | |||
| @@ -67,7 +67,7 @@ static const struct firmware card_fw[] = { | |||
| 67 | {0, "gina20_dsp.fw"} | 67 | {0, "gina20_dsp.fw"} |
| 68 | }; | 68 | }; |
| 69 | 69 | ||
| 70 | static struct pci_device_id snd_echo_ids[] = { | 70 | static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { |
| 71 | {0x1057, 0x1801, 0xECC0, 0x0020, 0, 0, 0}, /* DSP 56301 Gina20 rev.0 */ | 71 | {0x1057, 0x1801, 0xECC0, 0x0020, 0, 0, 0}, /* DSP 56301 Gina20 rev.0 */ |
| 72 | {0,} | 72 | {0,} |
| 73 | }; | 73 | }; |
diff --git a/sound/pci/echoaudio/gina20_dsp.c b/sound/pci/echoaudio/gina20_dsp.c index 3f1e7475faea..d1615a0579d1 100644 --- a/sound/pci/echoaudio/gina20_dsp.c +++ b/sound/pci/echoaudio/gina20_dsp.c | |||
| @@ -49,7 +49,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 49 | chip->device_id = device_id; | 49 | chip->device_id = device_id; |
| 50 | chip->subdevice_id = subdevice_id; | 50 | chip->subdevice_id = subdevice_id; |
| 51 | chip->bad_board = TRUE; | 51 | chip->bad_board = TRUE; |
| 52 | chip->dsp_code_to_load = &card_fw[FW_GINA20_DSP]; | 52 | chip->dsp_code_to_load = FW_GINA20_DSP; |
| 53 | chip->spdif_status = GD_SPDIF_STATUS_UNDEF; | 53 | chip->spdif_status = GD_SPDIF_STATUS_UNDEF; |
| 54 | chip->clock_state = GD_CLOCK_UNDEF; | 54 | chip->clock_state = GD_CLOCK_UNDEF; |
| 55 | /* Since this card has no ASIC, mark it as loaded so everything | 55 | /* Since this card has no ASIC, mark it as loaded so everything |
| @@ -62,17 +62,20 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 62 | return err; | 62 | return err; |
| 63 | chip->bad_board = FALSE; | 63 | chip->bad_board = FALSE; |
| 64 | 64 | ||
| 65 | if ((err = init_line_levels(chip)) < 0) | ||
| 66 | return err; | ||
| 67 | |||
| 68 | err = set_professional_spdif(chip, TRUE); | ||
| 69 | |||
| 70 | DE_INIT(("init_hw done\n")); | 65 | DE_INIT(("init_hw done\n")); |
| 71 | return err; | 66 | return err; |
| 72 | } | 67 | } |
| 73 | 68 | ||
| 74 | 69 | ||
| 75 | 70 | ||
| 71 | static int set_mixer_defaults(struct echoaudio *chip) | ||
| 72 | { | ||
| 73 | chip->professional_spdif = FALSE; | ||
| 74 | return init_line_levels(chip); | ||
| 75 | } | ||
| 76 | |||
| 77 | |||
| 78 | |||
| 76 | static u32 detect_input_clocks(const struct echoaudio *chip) | 79 | static u32 detect_input_clocks(const struct echoaudio *chip) |
| 77 | { | 80 | { |
| 78 | u32 clocks_from_dsp, clock_bits; | 81 | u32 clocks_from_dsp, clock_bits; |
diff --git a/sound/pci/echoaudio/gina24.c b/sound/pci/echoaudio/gina24.c index c36a78dd0b5e..616b55825a19 100644 --- a/sound/pci/echoaudio/gina24.c +++ b/sound/pci/echoaudio/gina24.c | |||
| @@ -85,7 +85,7 @@ static const struct firmware card_fw[] = { | |||
| 85 | {0, "gina24_361_asic.fw"} | 85 | {0, "gina24_361_asic.fw"} |
| 86 | }; | 86 | }; |
| 87 | 87 | ||
| 88 | static struct pci_device_id snd_echo_ids[] = { | 88 | static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { |
| 89 | {0x1057, 0x1801, 0xECC0, 0x0050, 0, 0, 0}, /* DSP 56301 Gina24 rev.0 */ | 89 | {0x1057, 0x1801, 0xECC0, 0x0050, 0, 0, 0}, /* DSP 56301 Gina24 rev.0 */ |
| 90 | {0x1057, 0x1801, 0xECC0, 0x0051, 0, 0, 0}, /* DSP 56301 Gina24 rev.1 */ | 90 | {0x1057, 0x1801, 0xECC0, 0x0051, 0, 0, 0}, /* DSP 56301 Gina24 rev.1 */ |
| 91 | {0x1057, 0x3410, 0xECC0, 0x0050, 0, 0, 0}, /* DSP 56361 Gina24 rev.0 */ | 91 | {0x1057, 0x3410, 0xECC0, 0x0050, 0, 0, 0}, /* DSP 56361 Gina24 rev.0 */ |
diff --git a/sound/pci/echoaudio/gina24_dsp.c b/sound/pci/echoaudio/gina24_dsp.c index 2fef37a2a5b9..98f7cfa81b5f 100644 --- a/sound/pci/echoaudio/gina24_dsp.c +++ b/sound/pci/echoaudio/gina24_dsp.c | |||
| @@ -33,8 +33,7 @@ static int write_control_reg(struct echoaudio *chip, u32 value, char force); | |||
| 33 | static int set_input_clock(struct echoaudio *chip, u16 clock); | 33 | static int set_input_clock(struct echoaudio *chip, u16 clock); |
| 34 | static int set_professional_spdif(struct echoaudio *chip, char prof); | 34 | static int set_professional_spdif(struct echoaudio *chip, char prof); |
| 35 | static int set_digital_mode(struct echoaudio *chip, u8 mode); | 35 | static int set_digital_mode(struct echoaudio *chip, u8 mode); |
| 36 | static int load_asic_generic(struct echoaudio *chip, u32 cmd, | 36 | static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic); |
| 37 | const struct firmware *asic); | ||
| 38 | static int check_asic_status(struct echoaudio *chip); | 37 | static int check_asic_status(struct echoaudio *chip); |
| 39 | 38 | ||
| 40 | 39 | ||
| @@ -58,19 +57,16 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 58 | ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF | | 57 | ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF | |
| 59 | ECHO_CLOCK_BIT_ESYNC | ECHO_CLOCK_BIT_ESYNC96 | | 58 | ECHO_CLOCK_BIT_ESYNC | ECHO_CLOCK_BIT_ESYNC96 | |
| 60 | ECHO_CLOCK_BIT_ADAT; | 59 | ECHO_CLOCK_BIT_ADAT; |
| 61 | chip->professional_spdif = FALSE; | ||
| 62 | chip->digital_in_automute = TRUE; | ||
| 63 | chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; | ||
| 64 | 60 | ||
| 65 | /* Gina24 comes in both '301 and '361 flavors */ | 61 | /* Gina24 comes in both '301 and '361 flavors */ |
| 66 | if (chip->device_id == DEVICE_ID_56361) { | 62 | if (chip->device_id == DEVICE_ID_56361) { |
| 67 | chip->dsp_code_to_load = &card_fw[FW_GINA24_361_DSP]; | 63 | chip->dsp_code_to_load = FW_GINA24_361_DSP; |
| 68 | chip->digital_modes = | 64 | chip->digital_modes = |
| 69 | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA | | 65 | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA | |
| 70 | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL | | 66 | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL | |
| 71 | ECHOCAPS_HAS_DIGITAL_MODE_ADAT; | 67 | ECHOCAPS_HAS_DIGITAL_MODE_ADAT; |
| 72 | } else { | 68 | } else { |
| 73 | chip->dsp_code_to_load = &card_fw[FW_GINA24_301_DSP]; | 69 | chip->dsp_code_to_load = FW_GINA24_301_DSP; |
| 74 | chip->digital_modes = | 70 | chip->digital_modes = |
| 75 | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA | | 71 | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA | |
| 76 | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL | | 72 | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL | |
| @@ -82,19 +78,22 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 82 | return err; | 78 | return err; |
| 83 | chip->bad_board = FALSE; | 79 | chip->bad_board = FALSE; |
| 84 | 80 | ||
| 85 | if ((err = init_line_levels(chip)) < 0) | ||
| 86 | return err; | ||
| 87 | err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA); | ||
| 88 | if (err < 0) | ||
| 89 | return err; | ||
| 90 | err = set_professional_spdif(chip, TRUE); | ||
| 91 | |||
| 92 | DE_INIT(("init_hw done\n")); | 81 | DE_INIT(("init_hw done\n")); |
| 93 | return err; | 82 | return err; |
| 94 | } | 83 | } |
| 95 | 84 | ||
| 96 | 85 | ||
| 97 | 86 | ||
| 87 | static int set_mixer_defaults(struct echoaudio *chip) | ||
| 88 | { | ||
| 89 | chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; | ||
| 90 | chip->professional_spdif = FALSE; | ||
| 91 | chip->digital_in_automute = TRUE; | ||
| 92 | return init_line_levels(chip); | ||
| 93 | } | ||
| 94 | |||
| 95 | |||
| 96 | |||
| 98 | static u32 detect_input_clocks(const struct echoaudio *chip) | 97 | static u32 detect_input_clocks(const struct echoaudio *chip) |
| 99 | { | 98 | { |
| 100 | u32 clocks_from_dsp, clock_bits; | 99 | u32 clocks_from_dsp, clock_bits; |
| @@ -125,7 +124,7 @@ static int load_asic(struct echoaudio *chip) | |||
| 125 | { | 124 | { |
| 126 | u32 control_reg; | 125 | u32 control_reg; |
| 127 | int err; | 126 | int err; |
| 128 | const struct firmware *fw; | 127 | short asic; |
| 129 | 128 | ||
| 130 | if (chip->asic_loaded) | 129 | if (chip->asic_loaded) |
| 131 | return 1; | 130 | return 1; |
| @@ -135,14 +134,15 @@ static int load_asic(struct echoaudio *chip) | |||
| 135 | 134 | ||
| 136 | /* Pick the correct ASIC for '301 or '361 Gina24 */ | 135 | /* Pick the correct ASIC for '301 or '361 Gina24 */ |
| 137 | if (chip->device_id == DEVICE_ID_56361) | 136 | if (chip->device_id == DEVICE_ID_56361) |
| 138 | fw = &card_fw[FW_GINA24_361_ASIC]; | 137 | asic = FW_GINA24_361_ASIC; |
| 139 | else | 138 | else |
| 140 | fw = &card_fw[FW_GINA24_301_ASIC]; | 139 | asic = FW_GINA24_301_ASIC; |
| 141 | 140 | ||
| 142 | if ((err = load_asic_generic(chip, DSP_FNC_LOAD_GINA24_ASIC, fw)) < 0) | 141 | err = load_asic_generic(chip, DSP_FNC_LOAD_GINA24_ASIC, asic); |
| 142 | if (err < 0) | ||
| 143 | return err; | 143 | return err; |
| 144 | 144 | ||
| 145 | chip->asic_code = fw; | 145 | chip->asic_code = asic; |
| 146 | 146 | ||
| 147 | /* Now give the new ASIC a little time to set up */ | 147 | /* Now give the new ASIC a little time to set up */ |
| 148 | mdelay(10); | 148 | mdelay(10); |
diff --git a/sound/pci/echoaudio/indigo.c b/sound/pci/echoaudio/indigo.c index 0a58a7c1fd7c..776175c0bdad 100644 --- a/sound/pci/echoaudio/indigo.c +++ b/sound/pci/echoaudio/indigo.c | |||
| @@ -68,7 +68,7 @@ static const struct firmware card_fw[] = { | |||
| 68 | {0, "indigo_dsp.fw"} | 68 | {0, "indigo_dsp.fw"} |
| 69 | }; | 69 | }; |
| 70 | 70 | ||
| 71 | static struct pci_device_id snd_echo_ids[] = { | 71 | static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { |
| 72 | {0x1057, 0x3410, 0xECC0, 0x0090, 0, 0, 0}, /* Indigo */ | 72 | {0x1057, 0x3410, 0xECC0, 0x0090, 0, 0, 0}, /* Indigo */ |
| 73 | {0,} | 73 | {0,} |
| 74 | }; | 74 | }; |
diff --git a/sound/pci/echoaudio/indigo_dsp.c b/sound/pci/echoaudio/indigo_dsp.c index 0b2cd9c86277..5e85f14fe5a8 100644 --- a/sound/pci/echoaudio/indigo_dsp.c +++ b/sound/pci/echoaudio/indigo_dsp.c | |||
| @@ -50,7 +50,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 50 | chip->device_id = device_id; | 50 | chip->device_id = device_id; |
| 51 | chip->subdevice_id = subdevice_id; | 51 | chip->subdevice_id = subdevice_id; |
| 52 | chip->bad_board = TRUE; | 52 | chip->bad_board = TRUE; |
| 53 | chip->dsp_code_to_load = &card_fw[FW_INDIGO_DSP]; | 53 | chip->dsp_code_to_load = FW_INDIGO_DSP; |
| 54 | /* Since this card has no ASIC, mark it as loaded so everything | 54 | /* Since this card has no ASIC, mark it as loaded so everything |
| 55 | works OK */ | 55 | works OK */ |
| 56 | chip->asic_loaded = TRUE; | 56 | chip->asic_loaded = TRUE; |
| @@ -60,15 +60,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 60 | return err; | 60 | return err; |
| 61 | chip->bad_board = FALSE; | 61 | chip->bad_board = FALSE; |
| 62 | 62 | ||
| 63 | if ((err = init_line_levels(chip)) < 0) | ||
| 64 | return err; | ||
| 65 | |||
| 66 | DE_INIT(("init_hw done\n")); | 63 | DE_INIT(("init_hw done\n")); |
| 67 | return err; | 64 | return err; |
| 68 | } | 65 | } |
| 69 | 66 | ||
| 70 | 67 | ||
| 71 | 68 | ||
| 69 | static int set_mixer_defaults(struct echoaudio *chip) | ||
| 70 | { | ||
| 71 | return init_line_levels(chip); | ||
| 72 | } | ||
| 73 | |||
| 74 | |||
| 75 | |||
| 72 | static u32 detect_input_clocks(const struct echoaudio *chip) | 76 | static u32 detect_input_clocks(const struct echoaudio *chip) |
| 73 | { | 77 | { |
| 74 | return ECHO_CLOCK_BIT_INTERNAL; | 78 | return ECHO_CLOCK_BIT_INTERNAL; |
diff --git a/sound/pci/echoaudio/indigo_express_dsp.c b/sound/pci/echoaudio/indigo_express_dsp.c index 9ab625e15652..2e4ab3e34a74 100644 --- a/sound/pci/echoaudio/indigo_express_dsp.c +++ b/sound/pci/echoaudio/indigo_express_dsp.c | |||
| @@ -61,6 +61,7 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) | |||
| 61 | 61 | ||
| 62 | control_reg |= clock; | 62 | control_reg |= clock; |
| 63 | if (control_reg != old_control_reg) { | 63 | if (control_reg != old_control_reg) { |
| 64 | DE_ACT(("set_sample_rate: %d clock %d\n", rate, clock)); | ||
| 64 | chip->comm_page->control_register = cpu_to_le32(control_reg); | 65 | chip->comm_page->control_register = cpu_to_le32(control_reg); |
| 65 | chip->sample_rate = rate; | 66 | chip->sample_rate = rate; |
| 66 | clear_handshake(chip); | 67 | clear_handshake(chip); |
diff --git a/sound/pci/echoaudio/indigodj.c b/sound/pci/echoaudio/indigodj.c index 2db24d29332b..8816b0bd2ba6 100644 --- a/sound/pci/echoaudio/indigodj.c +++ b/sound/pci/echoaudio/indigodj.c | |||
| @@ -68,7 +68,7 @@ static const struct firmware card_fw[] = { | |||
| 68 | {0, "indigo_dj_dsp.fw"} | 68 | {0, "indigo_dj_dsp.fw"} |
| 69 | }; | 69 | }; |
| 70 | 70 | ||
| 71 | static struct pci_device_id snd_echo_ids[] = { | 71 | static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { |
| 72 | {0x1057, 0x3410, 0xECC0, 0x00B0, 0, 0, 0}, /* Indigo DJ*/ | 72 | {0x1057, 0x3410, 0xECC0, 0x00B0, 0, 0, 0}, /* Indigo DJ*/ |
| 73 | {0,} | 73 | {0,} |
| 74 | }; | 74 | }; |
diff --git a/sound/pci/echoaudio/indigodj_dsp.c b/sound/pci/echoaudio/indigodj_dsp.c index 08392916691e..68f3c8ccc1bf 100644 --- a/sound/pci/echoaudio/indigodj_dsp.c +++ b/sound/pci/echoaudio/indigodj_dsp.c | |||
| @@ -50,7 +50,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 50 | chip->device_id = device_id; | 50 | chip->device_id = device_id; |
| 51 | chip->subdevice_id = subdevice_id; | 51 | chip->subdevice_id = subdevice_id; |
| 52 | chip->bad_board = TRUE; | 52 | chip->bad_board = TRUE; |
| 53 | chip->dsp_code_to_load = &card_fw[FW_INDIGO_DJ_DSP]; | 53 | chip->dsp_code_to_load = FW_INDIGO_DJ_DSP; |
| 54 | /* Since this card has no ASIC, mark it as loaded so everything | 54 | /* Since this card has no ASIC, mark it as loaded so everything |
| 55 | works OK */ | 55 | works OK */ |
| 56 | chip->asic_loaded = TRUE; | 56 | chip->asic_loaded = TRUE; |
| @@ -60,15 +60,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 60 | return err; | 60 | return err; |
| 61 | chip->bad_board = FALSE; | 61 | chip->bad_board = FALSE; |
| 62 | 62 | ||
| 63 | if ((err = init_line_levels(chip)) < 0) | ||
| 64 | return err; | ||
| 65 | |||
| 66 | DE_INIT(("init_hw done\n")); | 63 | DE_INIT(("init_hw done\n")); |
| 67 | return err; | 64 | return err; |
| 68 | } | 65 | } |
| 69 | 66 | ||
| 70 | 67 | ||
| 71 | 68 | ||
| 69 | static int set_mixer_defaults(struct echoaudio *chip) | ||
| 70 | { | ||
| 71 | return init_line_levels(chip); | ||
| 72 | } | ||
| 73 | |||
| 74 | |||
| 75 | |||
| 72 | static u32 detect_input_clocks(const struct echoaudio *chip) | 76 | static u32 detect_input_clocks(const struct echoaudio *chip) |
| 73 | { | 77 | { |
| 74 | return ECHO_CLOCK_BIT_INTERNAL; | 78 | return ECHO_CLOCK_BIT_INTERNAL; |
diff --git a/sound/pci/echoaudio/indigodjx.c b/sound/pci/echoaudio/indigodjx.c index 2e44316530a2..b1e3652f2f48 100644 --- a/sound/pci/echoaudio/indigodjx.c +++ b/sound/pci/echoaudio/indigodjx.c | |||
| @@ -68,7 +68,7 @@ static const struct firmware card_fw[] = { | |||
| 68 | {0, "indigo_djx_dsp.fw"} | 68 | {0, "indigo_djx_dsp.fw"} |
| 69 | }; | 69 | }; |
| 70 | 70 | ||
| 71 | static struct pci_device_id snd_echo_ids[] = { | 71 | static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { |
| 72 | {0x1057, 0x3410, 0xECC0, 0x00E0, 0, 0, 0}, /* Indigo DJx*/ | 72 | {0x1057, 0x3410, 0xECC0, 0x00E0, 0, 0, 0}, /* Indigo DJx*/ |
| 73 | {0,} | 73 | {0,} |
| 74 | }; | 74 | }; |
diff --git a/sound/pci/echoaudio/indigodjx_dsp.c b/sound/pci/echoaudio/indigodjx_dsp.c index f591fc2ed960..bb9632c752a9 100644 --- a/sound/pci/echoaudio/indigodjx_dsp.c +++ b/sound/pci/echoaudio/indigodjx_dsp.c | |||
| @@ -48,7 +48,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 48 | chip->device_id = device_id; | 48 | chip->device_id = device_id; |
| 49 | chip->subdevice_id = subdevice_id; | 49 | chip->subdevice_id = subdevice_id; |
| 50 | chip->bad_board = TRUE; | 50 | chip->bad_board = TRUE; |
| 51 | chip->dsp_code_to_load = &card_fw[FW_INDIGO_DJX_DSP]; | 51 | chip->dsp_code_to_load = FW_INDIGO_DJX_DSP; |
| 52 | /* Since this card has no ASIC, mark it as loaded so everything | 52 | /* Since this card has no ASIC, mark it as loaded so everything |
| 53 | works OK */ | 53 | works OK */ |
| 54 | chip->asic_loaded = TRUE; | 54 | chip->asic_loaded = TRUE; |
| @@ -59,10 +59,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 59 | return err; | 59 | return err; |
| 60 | chip->bad_board = FALSE; | 60 | chip->bad_board = FALSE; |
| 61 | 61 | ||
| 62 | err = init_line_levels(chip); | ||
| 63 | if (err < 0) | ||
| 64 | return err; | ||
| 65 | |||
| 66 | DE_INIT(("init_hw done\n")); | 62 | DE_INIT(("init_hw done\n")); |
| 67 | return err; | 63 | return err; |
| 68 | } | 64 | } |
| 65 | |||
| 66 | |||
| 67 | |||
| 68 | static int set_mixer_defaults(struct echoaudio *chip) | ||
| 69 | { | ||
| 70 | return init_line_levels(chip); | ||
| 71 | } | ||
diff --git a/sound/pci/echoaudio/indigoio.c b/sound/pci/echoaudio/indigoio.c index a60c0a0a89b7..1035125336d6 100644 --- a/sound/pci/echoaudio/indigoio.c +++ b/sound/pci/echoaudio/indigoio.c | |||
| @@ -69,7 +69,7 @@ static const struct firmware card_fw[] = { | |||
| 69 | {0, "indigo_io_dsp.fw"} | 69 | {0, "indigo_io_dsp.fw"} |
| 70 | }; | 70 | }; |
| 71 | 71 | ||
| 72 | static struct pci_device_id snd_echo_ids[] = { | 72 | static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { |
| 73 | {0x1057, 0x3410, 0xECC0, 0x00A0, 0, 0, 0}, /* Indigo IO*/ | 73 | {0x1057, 0x3410, 0xECC0, 0x00A0, 0, 0, 0}, /* Indigo IO*/ |
| 74 | {0,} | 74 | {0,} |
| 75 | }; | 75 | }; |
diff --git a/sound/pci/echoaudio/indigoio_dsp.c b/sound/pci/echoaudio/indigoio_dsp.c index 0604c8a85223..beb9a5b69892 100644 --- a/sound/pci/echoaudio/indigoio_dsp.c +++ b/sound/pci/echoaudio/indigoio_dsp.c | |||
| @@ -50,7 +50,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 50 | chip->device_id = device_id; | 50 | chip->device_id = device_id; |
| 51 | chip->subdevice_id = subdevice_id; | 51 | chip->subdevice_id = subdevice_id; |
| 52 | chip->bad_board = TRUE; | 52 | chip->bad_board = TRUE; |
| 53 | chip->dsp_code_to_load = &card_fw[FW_INDIGO_IO_DSP]; | 53 | chip->dsp_code_to_load = FW_INDIGO_IO_DSP; |
| 54 | /* Since this card has no ASIC, mark it as loaded so everything | 54 | /* Since this card has no ASIC, mark it as loaded so everything |
| 55 | works OK */ | 55 | works OK */ |
| 56 | chip->asic_loaded = TRUE; | 56 | chip->asic_loaded = TRUE; |
| @@ -60,15 +60,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 60 | return err; | 60 | return err; |
| 61 | chip->bad_board = FALSE; | 61 | chip->bad_board = FALSE; |
| 62 | 62 | ||
| 63 | if ((err = init_line_levels(chip)) < 0) | ||
| 64 | return err; | ||
| 65 | |||
| 66 | DE_INIT(("init_hw done\n")); | 63 | DE_INIT(("init_hw done\n")); |
| 67 | return err; | 64 | return err; |
| 68 | } | 65 | } |
| 69 | 66 | ||
| 70 | 67 | ||
| 71 | 68 | ||
| 69 | static int set_mixer_defaults(struct echoaudio *chip) | ||
| 70 | { | ||
| 71 | return init_line_levels(chip); | ||
| 72 | } | ||
| 73 | |||
| 74 | |||
| 75 | |||
| 72 | static u32 detect_input_clocks(const struct echoaudio *chip) | 76 | static u32 detect_input_clocks(const struct echoaudio *chip) |
| 73 | { | 77 | { |
| 74 | return ECHO_CLOCK_BIT_INTERNAL; | 78 | return ECHO_CLOCK_BIT_INTERNAL; |
diff --git a/sound/pci/echoaudio/indigoiox.c b/sound/pci/echoaudio/indigoiox.c index eb3819f9654a..60b7cb2753cf 100644 --- a/sound/pci/echoaudio/indigoiox.c +++ b/sound/pci/echoaudio/indigoiox.c | |||
| @@ -69,7 +69,7 @@ static const struct firmware card_fw[] = { | |||
| 69 | {0, "indigo_iox_dsp.fw"} | 69 | {0, "indigo_iox_dsp.fw"} |
| 70 | }; | 70 | }; |
| 71 | 71 | ||
| 72 | static struct pci_device_id snd_echo_ids[] = { | 72 | static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { |
| 73 | {0x1057, 0x3410, 0xECC0, 0x00D0, 0, 0, 0}, /* Indigo IOx */ | 73 | {0x1057, 0x3410, 0xECC0, 0x00D0, 0, 0, 0}, /* Indigo IOx */ |
| 74 | {0,} | 74 | {0,} |
| 75 | }; | 75 | }; |
diff --git a/sound/pci/echoaudio/indigoiox_dsp.c b/sound/pci/echoaudio/indigoiox_dsp.c index f357521c79e6..394c6e76bcbc 100644 --- a/sound/pci/echoaudio/indigoiox_dsp.c +++ b/sound/pci/echoaudio/indigoiox_dsp.c | |||
| @@ -48,7 +48,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 48 | chip->device_id = device_id; | 48 | chip->device_id = device_id; |
| 49 | chip->subdevice_id = subdevice_id; | 49 | chip->subdevice_id = subdevice_id; |
| 50 | chip->bad_board = TRUE; | 50 | chip->bad_board = TRUE; |
| 51 | chip->dsp_code_to_load = &card_fw[FW_INDIGO_IOX_DSP]; | 51 | chip->dsp_code_to_load = FW_INDIGO_IOX_DSP; |
| 52 | /* Since this card has no ASIC, mark it as loaded so everything | 52 | /* Since this card has no ASIC, mark it as loaded so everything |
| 53 | works OK */ | 53 | works OK */ |
| 54 | chip->asic_loaded = TRUE; | 54 | chip->asic_loaded = TRUE; |
| @@ -59,10 +59,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 59 | return err; | 59 | return err; |
| 60 | chip->bad_board = FALSE; | 60 | chip->bad_board = FALSE; |
| 61 | 61 | ||
| 62 | err = init_line_levels(chip); | ||
| 63 | if (err < 0) | ||
| 64 | return err; | ||
| 65 | |||
| 66 | DE_INIT(("init_hw done\n")); | 62 | DE_INIT(("init_hw done\n")); |
| 67 | return err; | 63 | return err; |
| 68 | } | 64 | } |
| 65 | |||
| 66 | |||
| 67 | |||
| 68 | static int set_mixer_defaults(struct echoaudio *chip) | ||
| 69 | { | ||
| 70 | return init_line_levels(chip); | ||
| 71 | } | ||
diff --git a/sound/pci/echoaudio/layla20.c b/sound/pci/echoaudio/layla20.c index 506194688995..8c3f5c5b5301 100644 --- a/sound/pci/echoaudio/layla20.c +++ b/sound/pci/echoaudio/layla20.c | |||
| @@ -76,7 +76,7 @@ static const struct firmware card_fw[] = { | |||
| 76 | {0, "layla20_asic.fw"} | 76 | {0, "layla20_asic.fw"} |
| 77 | }; | 77 | }; |
| 78 | 78 | ||
| 79 | static struct pci_device_id snd_echo_ids[] = { | 79 | static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { |
| 80 | {0x1057, 0x1801, 0xECC0, 0x0030, 0, 0, 0}, /* DSP 56301 Layla20 rev.0 */ | 80 | {0x1057, 0x1801, 0xECC0, 0x0030, 0, 0, 0}, /* DSP 56301 Layla20 rev.0 */ |
| 81 | {0x1057, 0x1801, 0xECC0, 0x0031, 0, 0, 0}, /* DSP 56301 Layla20 rev.1 */ | 81 | {0x1057, 0x1801, 0xECC0, 0x0031, 0, 0, 0}, /* DSP 56301 Layla20 rev.1 */ |
| 82 | {0,} | 82 | {0,} |
diff --git a/sound/pci/echoaudio/layla20_dsp.c b/sound/pci/echoaudio/layla20_dsp.c index 83750e9fd7b4..53ce94605044 100644 --- a/sound/pci/echoaudio/layla20_dsp.c +++ b/sound/pci/echoaudio/layla20_dsp.c | |||
| @@ -31,8 +31,7 @@ | |||
| 31 | 31 | ||
| 32 | static int read_dsp(struct echoaudio *chip, u32 *data); | 32 | static int read_dsp(struct echoaudio *chip, u32 *data); |
| 33 | static int set_professional_spdif(struct echoaudio *chip, char prof); | 33 | static int set_professional_spdif(struct echoaudio *chip, char prof); |
| 34 | static int load_asic_generic(struct echoaudio *chip, u32 cmd, | 34 | static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic); |
| 35 | const struct firmware *asic); | ||
| 36 | static int check_asic_status(struct echoaudio *chip); | 35 | static int check_asic_status(struct echoaudio *chip); |
| 37 | static int update_flags(struct echoaudio *chip); | 36 | static int update_flags(struct echoaudio *chip); |
| 38 | 37 | ||
| @@ -54,7 +53,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 54 | chip->subdevice_id = subdevice_id; | 53 | chip->subdevice_id = subdevice_id; |
| 55 | chip->bad_board = TRUE; | 54 | chip->bad_board = TRUE; |
| 56 | chip->has_midi = TRUE; | 55 | chip->has_midi = TRUE; |
| 57 | chip->dsp_code_to_load = &card_fw[FW_LAYLA20_DSP]; | 56 | chip->dsp_code_to_load = FW_LAYLA20_DSP; |
| 58 | chip->input_clock_types = | 57 | chip->input_clock_types = |
| 59 | ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF | | 58 | ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF | |
| 60 | ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_SUPER; | 59 | ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_SUPER; |
| @@ -65,17 +64,20 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 65 | return err; | 64 | return err; |
| 66 | chip->bad_board = FALSE; | 65 | chip->bad_board = FALSE; |
| 67 | 66 | ||
| 68 | if ((err = init_line_levels(chip)) < 0) | ||
| 69 | return err; | ||
| 70 | |||
| 71 | err = set_professional_spdif(chip, TRUE); | ||
| 72 | |||
| 73 | DE_INIT(("init_hw done\n")); | 67 | DE_INIT(("init_hw done\n")); |
| 74 | return err; | 68 | return err; |
| 75 | } | 69 | } |
| 76 | 70 | ||
| 77 | 71 | ||
| 78 | 72 | ||
| 73 | static int set_mixer_defaults(struct echoaudio *chip) | ||
| 74 | { | ||
| 75 | chip->professional_spdif = FALSE; | ||
| 76 | return init_line_levels(chip); | ||
| 77 | } | ||
| 78 | |||
| 79 | |||
| 80 | |||
| 79 | static u32 detect_input_clocks(const struct echoaudio *chip) | 81 | static u32 detect_input_clocks(const struct echoaudio *chip) |
| 80 | { | 82 | { |
| 81 | u32 clocks_from_dsp, clock_bits; | 83 | u32 clocks_from_dsp, clock_bits; |
| @@ -144,7 +146,7 @@ static int load_asic(struct echoaudio *chip) | |||
| 144 | return 0; | 146 | return 0; |
| 145 | 147 | ||
| 146 | err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA_ASIC, | 148 | err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA_ASIC, |
| 147 | &card_fw[FW_LAYLA20_ASIC]); | 149 | FW_LAYLA20_ASIC); |
| 148 | if (err < 0) | 150 | if (err < 0) |
| 149 | return err; | 151 | return err; |
| 150 | 152 | ||
diff --git a/sound/pci/echoaudio/layla24.c b/sound/pci/echoaudio/layla24.c index e09e3ea7781e..ed1cc0abc2b8 100644 --- a/sound/pci/echoaudio/layla24.c +++ b/sound/pci/echoaudio/layla24.c | |||
| @@ -87,7 +87,7 @@ static const struct firmware card_fw[] = { | |||
| 87 | {0, "layla24_2S_asic.fw"} | 87 | {0, "layla24_2S_asic.fw"} |
| 88 | }; | 88 | }; |
| 89 | 89 | ||
| 90 | static struct pci_device_id snd_echo_ids[] = { | 90 | static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { |
| 91 | {0x1057, 0x3410, 0xECC0, 0x0060, 0, 0, 0}, /* DSP 56361 Layla24 rev.0 */ | 91 | {0x1057, 0x3410, 0xECC0, 0x0060, 0, 0, 0}, /* DSP 56361 Layla24 rev.0 */ |
| 92 | {0,} | 92 | {0,} |
| 93 | }; | 93 | }; |
diff --git a/sound/pci/echoaudio/layla24_dsp.c b/sound/pci/echoaudio/layla24_dsp.c index d61b5cbcccad..8c041647f285 100644 --- a/sound/pci/echoaudio/layla24_dsp.c +++ b/sound/pci/echoaudio/layla24_dsp.c | |||
| @@ -32,8 +32,7 @@ static int write_control_reg(struct echoaudio *chip, u32 value, char force); | |||
| 32 | static int set_input_clock(struct echoaudio *chip, u16 clock); | 32 | static int set_input_clock(struct echoaudio *chip, u16 clock); |
| 33 | static int set_professional_spdif(struct echoaudio *chip, char prof); | 33 | static int set_professional_spdif(struct echoaudio *chip, char prof); |
| 34 | static int set_digital_mode(struct echoaudio *chip, u8 mode); | 34 | static int set_digital_mode(struct echoaudio *chip, u8 mode); |
| 35 | static int load_asic_generic(struct echoaudio *chip, u32 cmd, | 35 | static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic); |
| 36 | const struct firmware *asic); | ||
| 37 | static int check_asic_status(struct echoaudio *chip); | 36 | static int check_asic_status(struct echoaudio *chip); |
| 38 | 37 | ||
| 39 | 38 | ||
| @@ -54,7 +53,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 54 | chip->subdevice_id = subdevice_id; | 53 | chip->subdevice_id = subdevice_id; |
| 55 | chip->bad_board = TRUE; | 54 | chip->bad_board = TRUE; |
| 56 | chip->has_midi = TRUE; | 55 | chip->has_midi = TRUE; |
| 57 | chip->dsp_code_to_load = &card_fw[FW_LAYLA24_DSP]; | 56 | chip->dsp_code_to_load = FW_LAYLA24_DSP; |
| 58 | chip->input_clock_types = | 57 | chip->input_clock_types = |
| 59 | ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF | | 58 | ECHO_CLOCK_BIT_INTERNAL | ECHO_CLOCK_BIT_SPDIF | |
| 60 | ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_ADAT; | 59 | ECHO_CLOCK_BIT_WORD | ECHO_CLOCK_BIT_ADAT; |
| @@ -62,9 +61,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 62 | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA | | 61 | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_RCA | |
| 63 | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL | | 62 | ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL | |
| 64 | ECHOCAPS_HAS_DIGITAL_MODE_ADAT; | 63 | ECHOCAPS_HAS_DIGITAL_MODE_ADAT; |
| 65 | chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; | ||
| 66 | chip->professional_spdif = FALSE; | ||
| 67 | chip->digital_in_automute = TRUE; | ||
| 68 | 64 | ||
| 69 | if ((err = load_firmware(chip)) < 0) | 65 | if ((err = load_firmware(chip)) < 0) |
| 70 | return err; | 66 | return err; |
| @@ -73,17 +69,22 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 73 | if ((err = init_line_levels(chip)) < 0) | 69 | if ((err = init_line_levels(chip)) < 0) |
| 74 | return err; | 70 | return err; |
| 75 | 71 | ||
| 76 | err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA); | ||
| 77 | if (err < 0) | ||
| 78 | return err; | ||
| 79 | err = set_professional_spdif(chip, TRUE); | ||
| 80 | |||
| 81 | DE_INIT(("init_hw done\n")); | 72 | DE_INIT(("init_hw done\n")); |
| 82 | return err; | 73 | return err; |
| 83 | } | 74 | } |
| 84 | 75 | ||
| 85 | 76 | ||
| 86 | 77 | ||
| 78 | static int set_mixer_defaults(struct echoaudio *chip) | ||
| 79 | { | ||
| 80 | chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; | ||
| 81 | chip->professional_spdif = FALSE; | ||
| 82 | chip->digital_in_automute = TRUE; | ||
| 83 | return init_line_levels(chip); | ||
| 84 | } | ||
| 85 | |||
| 86 | |||
| 87 | |||
| 87 | static u32 detect_input_clocks(const struct echoaudio *chip) | 88 | static u32 detect_input_clocks(const struct echoaudio *chip) |
| 88 | { | 89 | { |
| 89 | u32 clocks_from_dsp, clock_bits; | 90 | u32 clocks_from_dsp, clock_bits; |
| @@ -123,18 +124,18 @@ static int load_asic(struct echoaudio *chip) | |||
| 123 | 124 | ||
| 124 | /* Load the ASIC for the PCI card */ | 125 | /* Load the ASIC for the PCI card */ |
| 125 | err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA24_PCI_CARD_ASIC, | 126 | err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA24_PCI_CARD_ASIC, |
| 126 | &card_fw[FW_LAYLA24_1_ASIC]); | 127 | FW_LAYLA24_1_ASIC); |
| 127 | if (err < 0) | 128 | if (err < 0) |
| 128 | return err; | 129 | return err; |
| 129 | 130 | ||
| 130 | chip->asic_code = &card_fw[FW_LAYLA24_2S_ASIC]; | 131 | chip->asic_code = FW_LAYLA24_2S_ASIC; |
| 131 | 132 | ||
| 132 | /* Now give the new ASIC a little time to set up */ | 133 | /* Now give the new ASIC a little time to set up */ |
| 133 | mdelay(10); | 134 | mdelay(10); |
| 134 | 135 | ||
| 135 | /* Do the external one */ | 136 | /* Do the external one */ |
| 136 | err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA24_EXTERNAL_ASIC, | 137 | err = load_asic_generic(chip, DSP_FNC_LOAD_LAYLA24_EXTERNAL_ASIC, |
| 137 | &card_fw[FW_LAYLA24_2S_ASIC]); | 138 | FW_LAYLA24_2S_ASIC); |
| 138 | if (err < 0) | 139 | if (err < 0) |
| 139 | return FALSE; | 140 | return FALSE; |
| 140 | 141 | ||
| @@ -299,7 +300,7 @@ static int set_input_clock(struct echoaudio *chip, u16 clock) | |||
| 299 | /* Depending on what digital mode you want, Layla24 needs different ASICs | 300 | /* Depending on what digital mode you want, Layla24 needs different ASICs |
| 300 | loaded. This function checks the ASIC needed for the new mode and sees | 301 | loaded. This function checks the ASIC needed for the new mode and sees |
| 301 | if it matches the one already loaded. */ | 302 | if it matches the one already loaded. */ |
| 302 | static int switch_asic(struct echoaudio *chip, const struct firmware *asic) | 303 | static int switch_asic(struct echoaudio *chip, short asic) |
| 303 | { | 304 | { |
| 304 | s8 *monitors; | 305 | s8 *monitors; |
| 305 | 306 | ||
| @@ -335,7 +336,7 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode) | |||
| 335 | { | 336 | { |
| 336 | u32 control_reg; | 337 | u32 control_reg; |
| 337 | int err, incompatible_clock; | 338 | int err, incompatible_clock; |
| 338 | const struct firmware *asic; | 339 | short asic; |
| 339 | 340 | ||
| 340 | /* Set clock to "internal" if it's not compatible with the new mode */ | 341 | /* Set clock to "internal" if it's not compatible with the new mode */ |
| 341 | incompatible_clock = FALSE; | 342 | incompatible_clock = FALSE; |
| @@ -344,12 +345,12 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode) | |||
| 344 | case DIGITAL_MODE_SPDIF_RCA: | 345 | case DIGITAL_MODE_SPDIF_RCA: |
| 345 | if (chip->input_clock == ECHO_CLOCK_ADAT) | 346 | if (chip->input_clock == ECHO_CLOCK_ADAT) |
| 346 | incompatible_clock = TRUE; | 347 | incompatible_clock = TRUE; |
| 347 | asic = &card_fw[FW_LAYLA24_2S_ASIC]; | 348 | asic = FW_LAYLA24_2S_ASIC; |
| 348 | break; | 349 | break; |
| 349 | case DIGITAL_MODE_ADAT: | 350 | case DIGITAL_MODE_ADAT: |
| 350 | if (chip->input_clock == ECHO_CLOCK_SPDIF) | 351 | if (chip->input_clock == ECHO_CLOCK_SPDIF) |
| 351 | incompatible_clock = TRUE; | 352 | incompatible_clock = TRUE; |
| 352 | asic = &card_fw[FW_LAYLA24_2A_ASIC]; | 353 | asic = FW_LAYLA24_2A_ASIC; |
| 353 | break; | 354 | break; |
| 354 | default: | 355 | default: |
| 355 | DE_ACT(("Digital mode not supported: %d\n", mode)); | 356 | DE_ACT(("Digital mode not supported: %d\n", mode)); |
diff --git a/sound/pci/echoaudio/mia.c b/sound/pci/echoaudio/mia.c index f05c8c097aa8..cc2bbfc65327 100644 --- a/sound/pci/echoaudio/mia.c +++ b/sound/pci/echoaudio/mia.c | |||
| @@ -77,7 +77,7 @@ static const struct firmware card_fw[] = { | |||
| 77 | {0, "mia_dsp.fw"} | 77 | {0, "mia_dsp.fw"} |
| 78 | }; | 78 | }; |
| 79 | 79 | ||
| 80 | static struct pci_device_id snd_echo_ids[] = { | 80 | static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { |
| 81 | {0x1057, 0x3410, 0xECC0, 0x0080, 0, 0, 0}, /* DSP 56361 Mia rev.0 */ | 81 | {0x1057, 0x3410, 0xECC0, 0x0080, 0, 0, 0}, /* DSP 56361 Mia rev.0 */ |
| 82 | {0x1057, 0x3410, 0xECC0, 0x0081, 0, 0, 0}, /* DSP 56361 Mia rev.1 */ | 82 | {0x1057, 0x3410, 0xECC0, 0x0081, 0, 0, 0}, /* DSP 56361 Mia rev.1 */ |
| 83 | {0,} | 83 | {0,} |
diff --git a/sound/pci/echoaudio/mia_dsp.c b/sound/pci/echoaudio/mia_dsp.c index 551405114cbc..6ebfa6e7ab9e 100644 --- a/sound/pci/echoaudio/mia_dsp.c +++ b/sound/pci/echoaudio/mia_dsp.c | |||
| @@ -53,7 +53,7 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 53 | chip->device_id = device_id; | 53 | chip->device_id = device_id; |
| 54 | chip->subdevice_id = subdevice_id; | 54 | chip->subdevice_id = subdevice_id; |
| 55 | chip->bad_board = TRUE; | 55 | chip->bad_board = TRUE; |
| 56 | chip->dsp_code_to_load = &card_fw[FW_MIA_DSP]; | 56 | chip->dsp_code_to_load = FW_MIA_DSP; |
| 57 | /* Since this card has no ASIC, mark it as loaded so everything | 57 | /* Since this card has no ASIC, mark it as loaded so everything |
| 58 | works OK */ | 58 | works OK */ |
| 59 | chip->asic_loaded = TRUE; | 59 | chip->asic_loaded = TRUE; |
| @@ -66,15 +66,19 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 66 | return err; | 66 | return err; |
| 67 | chip->bad_board = FALSE; | 67 | chip->bad_board = FALSE; |
| 68 | 68 | ||
| 69 | if ((err = init_line_levels(chip))) | ||
| 70 | return err; | ||
| 71 | |||
| 72 | DE_INIT(("init_hw done\n")); | 69 | DE_INIT(("init_hw done\n")); |
| 73 | return err; | 70 | return err; |
| 74 | } | 71 | } |
| 75 | 72 | ||
| 76 | 73 | ||
| 77 | 74 | ||
| 75 | static int set_mixer_defaults(struct echoaudio *chip) | ||
| 76 | { | ||
| 77 | return init_line_levels(chip); | ||
| 78 | } | ||
| 79 | |||
| 80 | |||
| 81 | |||
| 78 | static u32 detect_input_clocks(const struct echoaudio *chip) | 82 | static u32 detect_input_clocks(const struct echoaudio *chip) |
| 79 | { | 83 | { |
| 80 | u32 clocks_from_dsp, clock_bits; | 84 | u32 clocks_from_dsp, clock_bits; |
diff --git a/sound/pci/echoaudio/mona.c b/sound/pci/echoaudio/mona.c index b05bad944901..3e7e01824b40 100644 --- a/sound/pci/echoaudio/mona.c +++ b/sound/pci/echoaudio/mona.c | |||
| @@ -92,7 +92,7 @@ static const struct firmware card_fw[] = { | |||
| 92 | {0, "mona_2_asic.fw"} | 92 | {0, "mona_2_asic.fw"} |
| 93 | }; | 93 | }; |
| 94 | 94 | ||
| 95 | static struct pci_device_id snd_echo_ids[] = { | 95 | static DEFINE_PCI_DEVICE_TABLE(snd_echo_ids) = { |
| 96 | {0x1057, 0x1801, 0xECC0, 0x0070, 0, 0, 0}, /* DSP 56301 Mona rev.0 */ | 96 | {0x1057, 0x1801, 0xECC0, 0x0070, 0, 0, 0}, /* DSP 56301 Mona rev.0 */ |
| 97 | {0x1057, 0x1801, 0xECC0, 0x0071, 0, 0, 0}, /* DSP 56301 Mona rev.1 */ | 97 | {0x1057, 0x1801, 0xECC0, 0x0071, 0, 0, 0}, /* DSP 56301 Mona rev.1 */ |
| 98 | {0x1057, 0x1801, 0xECC0, 0x0072, 0, 0, 0}, /* DSP 56301 Mona rev.2 */ | 98 | {0x1057, 0x1801, 0xECC0, 0x0072, 0, 0, 0}, /* DSP 56301 Mona rev.2 */ |
diff --git a/sound/pci/echoaudio/mona_dsp.c b/sound/pci/echoaudio/mona_dsp.c index eaa619bd2a03..6e6a7eb555b8 100644 --- a/sound/pci/echoaudio/mona_dsp.c +++ b/sound/pci/echoaudio/mona_dsp.c | |||
| @@ -33,8 +33,7 @@ static int write_control_reg(struct echoaudio *chip, u32 value, char force); | |||
| 33 | static int set_input_clock(struct echoaudio *chip, u16 clock); | 33 | static int set_input_clock(struct echoaudio *chip, u16 clock); |
| 34 | static int set_professional_spdif(struct echoaudio *chip, char prof); | 34 | static int set_professional_spdif(struct echoaudio *chip, char prof); |
| 35 | static int set_digital_mode(struct echoaudio *chip, u8 mode); | 35 | static int set_digital_mode(struct echoaudio *chip, u8 mode); |
| 36 | static int load_asic_generic(struct echoaudio *chip, u32 cmd, | 36 | static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic); |
| 37 | const struct firmware *asic); | ||
| 38 | static int check_asic_status(struct echoaudio *chip); | 37 | static int check_asic_status(struct echoaudio *chip); |
| 39 | 38 | ||
| 40 | 39 | ||
| @@ -64,32 +63,30 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id) | |||
| 64 | 63 | ||
| 65 | /* Mona comes in both '301 and '361 flavors */ | 64 | /* Mona comes in both '301 and '361 flavors */ |
| 66 | if (chip->device_id == DEVICE_ID_56361) | 65 | if (chip->device_id == DEVICE_ID_56361) |
| 67 | chip->dsp_code_to_load = &card_fw[FW_MONA_361_DSP]; | 66 | chip->dsp_code_to_load = FW_MONA_361_DSP; |
| 68 | else | 67 | else |
| 69 | chip->dsp_code_to_load = &card_fw[FW_MONA_301_DSP]; | 68 | chip->dsp_code_to_load = FW_MONA_301_DSP; |
| 70 | |||
| 71 | chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; | ||
| 72 | chip->professional_spdif = FALSE; | ||
| 73 | chip->digital_in_automute = TRUE; | ||
| 74 | 69 | ||
| 75 | if ((err = load_firmware(chip)) < 0) | 70 | if ((err = load_firmware(chip)) < 0) |
| 76 | return err; | 71 | return err; |
| 77 | chip->bad_board = FALSE; | 72 | chip->bad_board = FALSE; |
| 78 | 73 | ||
| 79 | if ((err = init_line_levels(chip)) < 0) | ||
| 80 | return err; | ||
| 81 | |||
| 82 | err = set_digital_mode(chip, DIGITAL_MODE_SPDIF_RCA); | ||
| 83 | if (err < 0) | ||
| 84 | return err; | ||
| 85 | err = set_professional_spdif(chip, TRUE); | ||
| 86 | |||
| 87 | DE_INIT(("init_hw done\n")); | 74 | DE_INIT(("init_hw done\n")); |
| 88 | return err; | 75 | return err; |
| 89 | } | 76 | } |
| 90 | 77 | ||
| 91 | 78 | ||
| 92 | 79 | ||
| 80 | static int set_mixer_defaults(struct echoaudio *chip) | ||
| 81 | { | ||
| 82 | chip->digital_mode = DIGITAL_MODE_SPDIF_RCA; | ||
| 83 | chip->professional_spdif = FALSE; | ||
| 84 | chip->digital_in_automute = TRUE; | ||
| 85 | return init_line_levels(chip); | ||
| 86 | } | ||
| 87 | |||
| 88 | |||
| 89 | |||
| 93 | static u32 detect_input_clocks(const struct echoaudio *chip) | 90 | static u32 detect_input_clocks(const struct echoaudio *chip) |
| 94 | { | 91 | { |
| 95 | u32 clocks_from_dsp, clock_bits; | 92 | u32 clocks_from_dsp, clock_bits; |
| @@ -120,7 +117,7 @@ static int load_asic(struct echoaudio *chip) | |||
| 120 | { | 117 | { |
| 121 | u32 control_reg; | 118 | u32 control_reg; |
| 122 | int err; | 119 | int err; |
| 123 | const struct firmware *asic; | 120 | short asic; |
| 124 | 121 | ||
| 125 | if (chip->asic_loaded) | 122 | if (chip->asic_loaded) |
| 126 | return 0; | 123 | return 0; |
| @@ -128,9 +125,9 @@ static int load_asic(struct echoaudio *chip) | |||
| 128 | mdelay(10); | 125 | mdelay(10); |
| 129 | 126 | ||
| 130 | if (chip->device_id == DEVICE_ID_56361) | 127 | if (chip->device_id == DEVICE_ID_56361) |
| 131 | asic = &card_fw[FW_MONA_361_1_ASIC48]; | 128 | asic = FW_MONA_361_1_ASIC48; |
| 132 | else | 129 | else |
| 133 | asic = &card_fw[FW_MONA_301_1_ASIC48]; | 130 | asic = FW_MONA_301_1_ASIC48; |
| 134 | 131 | ||
| 135 | err = load_asic_generic(chip, DSP_FNC_LOAD_MONA_PCI_CARD_ASIC, asic); | 132 | err = load_asic_generic(chip, DSP_FNC_LOAD_MONA_PCI_CARD_ASIC, asic); |
| 136 | if (err < 0) | 133 | if (err < 0) |
| @@ -141,7 +138,7 @@ static int load_asic(struct echoaudio *chip) | |||
| 141 | 138 | ||
| 142 | /* Do the external one */ | 139 | /* Do the external one */ |
| 143 | err = load_asic_generic(chip, DSP_FNC_LOAD_MONA_EXTERNAL_ASIC, | 140 | err = load_asic_generic(chip, DSP_FNC_LOAD_MONA_EXTERNAL_ASIC, |
| 144 | &card_fw[FW_MONA_2_ASIC]); | 141 | FW_MONA_2_ASIC); |
| 145 | if (err < 0) | 142 | if (err < 0) |
| 146 | return err; | 143 | return err; |
| 147 | 144 | ||
| @@ -165,22 +162,22 @@ loaded. This function checks the ASIC needed for the new mode and sees | |||
| 165 | if it matches the one already loaded. */ | 162 | if it matches the one already loaded. */ |
| 166 | static int switch_asic(struct echoaudio *chip, char double_speed) | 163 | static int switch_asic(struct echoaudio *chip, char double_speed) |
| 167 | { | 164 | { |
| 168 | const struct firmware *asic; | ||
| 169 | int err; | 165 | int err; |
| 166 | short asic; | ||
| 170 | 167 | ||
| 171 | /* Check the clock detect bits to see if this is | 168 | /* Check the clock detect bits to see if this is |
| 172 | a single-speed clock or a double-speed clock; load | 169 | a single-speed clock or a double-speed clock; load |
| 173 | a new ASIC if necessary. */ | 170 | a new ASIC if necessary. */ |
| 174 | if (chip->device_id == DEVICE_ID_56361) { | 171 | if (chip->device_id == DEVICE_ID_56361) { |
| 175 | if (double_speed) | 172 | if (double_speed) |
| 176 | asic = &card_fw[FW_MONA_361_1_ASIC96]; | 173 | asic = FW_MONA_361_1_ASIC96; |
| 177 | else | 174 | else |
| 178 | asic = &card_fw[FW_MONA_361_1_ASIC48]; | 175 | asic = FW_MONA_361_1_ASIC48; |
| 179 | } else { | 176 | } else { |
| 180 | if (double_speed) | 177 | if (double_speed) |
| 181 | asic = &card_fw[FW_MONA_301_1_ASIC96]; | 178 | asic = FW_MONA_301_1_ASIC96; |
| 182 | else | 179 | else |
| 183 | asic = &card_fw[FW_MONA_301_1_ASIC48]; | 180 | asic = FW_MONA_301_1_ASIC48; |
| 184 | } | 181 | } |
| 185 | 182 | ||
| 186 | if (asic != chip->asic_code) { | 183 | if (asic != chip->asic_code) { |
| @@ -200,7 +197,7 @@ static int switch_asic(struct echoaudio *chip, char double_speed) | |||
| 200 | static int set_sample_rate(struct echoaudio *chip, u32 rate) | 197 | static int set_sample_rate(struct echoaudio *chip, u32 rate) |
| 201 | { | 198 | { |
| 202 | u32 control_reg, clock; | 199 | u32 control_reg, clock; |
| 203 | const struct firmware *asic; | 200 | short asic; |
| 204 | char force_write; | 201 | char force_write; |
| 205 | 202 | ||
| 206 | /* Only set the clock for internal mode. */ | 203 | /* Only set the clock for internal mode. */ |
| @@ -218,14 +215,14 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate) | |||
| 218 | if (chip->digital_mode == DIGITAL_MODE_ADAT) | 215 | if (chip->digital_mode == DIGITAL_MODE_ADAT) |
| 219 | return -EINVAL; | 216 | return -EINVAL; |
| 220 | if (chip->device_id == DEVICE_ID_56361) | 217 | if (chip->device_id == DEVICE_ID_56361) |
| 221 | asic = &card_fw[FW_MONA_361_1_ASIC96]; | 218 | asic = FW_MONA_361_1_ASIC96; |
| 222 | else | 219 | else |
| 223 | asic = &card_fw[FW_MONA_301_1_ASIC96]; | 220 | asic = FW_MONA_301_1_ASIC96; |
| 224 | } else { | 221 | } else { |
| 225 | if (chip->device_id == DEVICE_ID_56361) | 222 | if (chip->device_id == DEVICE_ID_56361) |
| 226 | asic = &card_fw[FW_MONA_361_1_ASIC48]; | 223 | asic = FW_MONA_361_1_ASIC48; |
| 227 | else | 224 | else |
| 228 | asic = &card_fw[FW_MONA_301_1_ASIC48]; | 225 | asic = FW_MONA_301_1_ASIC48; |
| 229 | } | 226 | } |
| 230 | 227 | ||
| 231 | force_write = 0; | 228 | force_write = 0; |
| @@ -410,8 +407,8 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode) | |||
| 410 | case DIGITAL_MODE_ADAT: | 407 | case DIGITAL_MODE_ADAT: |
| 411 | /* If the current ASIC is the 96KHz ASIC, switch the ASIC | 408 | /* If the current ASIC is the 96KHz ASIC, switch the ASIC |
| 412 | and set to 48 KHz */ | 409 | and set to 48 KHz */ |
| 413 | if (chip->asic_code == &card_fw[FW_MONA_361_1_ASIC96] || | 410 | if (chip->asic_code == FW_MONA_361_1_ASIC96 || |
| 414 | chip->asic_code == &card_fw[FW_MONA_301_1_ASIC96]) { | 411 | chip->asic_code == FW_MONA_301_1_ASIC96) { |
| 415 | set_sample_rate(chip, 48000); | 412 | set_sample_rate(chip, 48000); |
| 416 | } | 413 | } |
| 417 | control_reg |= GML_ADAT_MODE; | 414 | control_reg |= GML_ADAT_MODE; |
diff --git a/sound/pci/emu10k1/emu10k1.c b/sound/pci/emu10k1/emu10k1.c index 168af67d938e..4203782d7cb7 100644 --- a/sound/pci/emu10k1/emu10k1.c +++ b/sound/pci/emu10k1/emu10k1.c | |||
| @@ -76,7 +76,7 @@ MODULE_PARM_DESC(subsystem, "Force card subsystem model."); | |||
| 76 | /* | 76 | /* |
| 77 | * Class 0401: 1102:0008 (rev 00) Subsystem: 1102:1001 -> Audigy2 Value Model:SB0400 | 77 | * Class 0401: 1102:0008 (rev 00) Subsystem: 1102:1001 -> Audigy2 Value Model:SB0400 |
| 78 | */ | 78 | */ |
| 79 | static struct pci_device_id snd_emu10k1_ids[] = { | 79 | static DEFINE_PCI_DEVICE_TABLE(snd_emu10k1_ids) = { |
| 80 | { PCI_VDEVICE(CREATIVE, 0x0002), 0 }, /* EMU10K1 */ | 80 | { PCI_VDEVICE(CREATIVE, 0x0002), 0 }, /* EMU10K1 */ |
| 81 | { PCI_VDEVICE(CREATIVE, 0x0004), 1 }, /* Audigy */ | 81 | { PCI_VDEVICE(CREATIVE, 0x0004), 1 }, /* Audigy */ |
| 82 | { PCI_VDEVICE(CREATIVE, 0x0008), 1 }, /* Audigy 2 Value SB0400 */ | 82 | { PCI_VDEVICE(CREATIVE, 0x0008), 1 }, /* Audigy 2 Value SB0400 */ |
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 1d369ff73805..df47f738098d 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c | |||
| @@ -1605,7 +1605,7 @@ static void __devexit snd_emu10k1x_remove(struct pci_dev *pci) | |||
| 1605 | } | 1605 | } |
| 1606 | 1606 | ||
| 1607 | // PCI IDs | 1607 | // PCI IDs |
| 1608 | static struct pci_device_id snd_emu10k1x_ids[] = { | 1608 | static DEFINE_PCI_DEVICE_TABLE(snd_emu10k1x_ids) = { |
| 1609 | { PCI_VDEVICE(CREATIVE, 0x0006), 0 }, /* Dell OEM version (EMU10K1) */ | 1609 | { PCI_VDEVICE(CREATIVE, 0x0006), 0 }, /* Dell OEM version (EMU10K1) */ |
| 1610 | { 0, } | 1610 | { 0, } |
| 1611 | }; | 1611 | }; |
diff --git a/sound/pci/ens1370.c b/sound/pci/ens1370.c index 2b82c5c723e1..c7fba5379813 100644 --- a/sound/pci/ens1370.c +++ b/sound/pci/ens1370.c | |||
| @@ -443,7 +443,7 @@ struct ensoniq { | |||
| 443 | 443 | ||
| 444 | static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id); | 444 | static irqreturn_t snd_audiopci_interrupt(int irq, void *dev_id); |
| 445 | 445 | ||
| 446 | static struct pci_device_id snd_audiopci_ids[] = { | 446 | static DEFINE_PCI_DEVICE_TABLE(snd_audiopci_ids) = { |
| 447 | #ifdef CHIP1370 | 447 | #ifdef CHIP1370 |
| 448 | { PCI_VDEVICE(ENSONIQ, 0x5000), 0, }, /* ES1370 */ | 448 | { PCI_VDEVICE(ENSONIQ, 0x5000), 0, }, /* ES1370 */ |
| 449 | #endif | 449 | #endif |
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c index fb83e1ffa5cb..553b75217259 100644 --- a/sound/pci/es1938.c +++ b/sound/pci/es1938.c | |||
| @@ -243,7 +243,7 @@ struct es1938 { | |||
| 243 | 243 | ||
| 244 | static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id); | 244 | static irqreturn_t snd_es1938_interrupt(int irq, void *dev_id); |
| 245 | 245 | ||
| 246 | static struct pci_device_id snd_es1938_ids[] = { | 246 | static DEFINE_PCI_DEVICE_TABLE(snd_es1938_ids) = { |
| 247 | { PCI_VDEVICE(ESS, 0x1969), 0, }, /* Solo-1 */ | 247 | { PCI_VDEVICE(ESS, 0x1969), 0, }, /* Solo-1 */ |
| 248 | { 0, } | 248 | { 0, } |
| 249 | }; | 249 | }; |
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c index a11f453a6b6d..ecaea9fb48ec 100644 --- a/sound/pci/es1968.c +++ b/sound/pci/es1968.c | |||
| @@ -551,7 +551,7 @@ struct es1968 { | |||
| 551 | 551 | ||
| 552 | static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id); | 552 | static irqreturn_t snd_es1968_interrupt(int irq, void *dev_id); |
| 553 | 553 | ||
| 554 | static struct pci_device_id snd_es1968_ids[] = { | 554 | static DEFINE_PCI_DEVICE_TABLE(snd_es1968_ids) = { |
| 555 | /* Maestro 1 */ | 555 | /* Maestro 1 */ |
| 556 | { 0x1285, 0x0100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, TYPE_MAESTRO }, | 556 | { 0x1285, 0x0100, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, TYPE_MAESTRO }, |
| 557 | /* Maestro 2 */ | 557 | /* Maestro 2 */ |
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c index 83508b3964fb..e1baad74ea4b 100644 --- a/sound/pci/fm801.c +++ b/sound/pci/fm801.c | |||
| @@ -205,7 +205,7 @@ struct fm801 { | |||
| 205 | #endif | 205 | #endif |
| 206 | }; | 206 | }; |
| 207 | 207 | ||
| 208 | static struct pci_device_id snd_fm801_ids[] = { | 208 | static DEFINE_PCI_DEVICE_TABLE(snd_fm801_ids) = { |
| 209 | { 0x1319, 0x0801, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* FM801 */ | 209 | { 0x1319, 0x0801, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* FM801 */ |
| 210 | { 0x5213, 0x0510, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* Gallant Odyssey Sound 4 */ | 210 | { 0x5213, 0x0510, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0, }, /* Gallant Odyssey Sound 4 */ |
| 211 | { 0, } | 211 | { 0, } |
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index f98b47cd6cfb..26ceace88c96 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
| @@ -824,6 +824,9 @@ int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list, | |||
| 824 | struct hda_pincfg *pin; | 824 | struct hda_pincfg *pin; |
| 825 | unsigned int oldcfg; | 825 | unsigned int oldcfg; |
| 826 | 826 | ||
| 827 | if (get_wcaps_type(get_wcaps(codec, nid)) != AC_WID_PIN) | ||
| 828 | return -EINVAL; | ||
| 829 | |||
| 827 | oldcfg = snd_hda_codec_get_pincfg(codec, nid); | 830 | oldcfg = snd_hda_codec_get_pincfg(codec, nid); |
| 828 | pin = look_up_pincfg(codec, list, nid); | 831 | pin = look_up_pincfg(codec, list, nid); |
| 829 | if (!pin) { | 832 | if (!pin) { |
| @@ -899,6 +902,25 @@ static void restore_pincfgs(struct hda_codec *codec) | |||
| 899 | } | 902 | } |
| 900 | } | 903 | } |
| 901 | 904 | ||
| 905 | /** | ||
| 906 | * snd_hda_shutup_pins - Shut up all pins | ||
| 907 | * @codec: the HDA codec | ||
| 908 | * | ||
| 909 | * Clear all pin controls to shup up before suspend for avoiding click noise. | ||
| 910 | * The controls aren't cached so that they can be resumed properly. | ||
| 911 | */ | ||
| 912 | void snd_hda_shutup_pins(struct hda_codec *codec) | ||
| 913 | { | ||
| 914 | int i; | ||
| 915 | for (i = 0; i < codec->init_pins.used; i++) { | ||
| 916 | struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); | ||
| 917 | /* use read here for syncing after issuing each verb */ | ||
| 918 | snd_hda_codec_read(codec, pin->nid, 0, | ||
| 919 | AC_VERB_SET_PIN_WIDGET_CONTROL, 0); | ||
| 920 | } | ||
| 921 | } | ||
| 922 | EXPORT_SYMBOL_HDA(snd_hda_shutup_pins); | ||
| 923 | |||
| 902 | static void init_hda_cache(struct hda_cache_rec *cache, | 924 | static void init_hda_cache(struct hda_cache_rec *cache, |
| 903 | unsigned int record_size); | 925 | unsigned int record_size); |
| 904 | static void free_hda_cache(struct hda_cache_rec *cache); | 926 | static void free_hda_cache(struct hda_cache_rec *cache); |
| @@ -931,6 +953,7 @@ static void snd_hda_codec_free(struct hda_codec *codec) | |||
| 931 | #endif | 953 | #endif |
| 932 | list_del(&codec->list); | 954 | list_del(&codec->list); |
| 933 | snd_array_free(&codec->mixers); | 955 | snd_array_free(&codec->mixers); |
| 956 | snd_array_free(&codec->nids); | ||
| 934 | codec->bus->caddr_tbl[codec->addr] = NULL; | 957 | codec->bus->caddr_tbl[codec->addr] = NULL; |
| 935 | if (codec->patch_ops.free) | 958 | if (codec->patch_ops.free) |
| 936 | codec->patch_ops.free(codec); | 959 | codec->patch_ops.free(codec); |
| @@ -985,7 +1008,8 @@ int /*__devinit*/ snd_hda_codec_new(struct hda_bus *bus, unsigned int codec_addr | |||
| 985 | mutex_init(&codec->control_mutex); | 1008 | mutex_init(&codec->control_mutex); |
| 986 | init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); | 1009 | init_hda_cache(&codec->amp_cache, sizeof(struct hda_amp_info)); |
| 987 | init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); | 1010 | init_hda_cache(&codec->cmd_cache, sizeof(struct hda_cache_head)); |
| 988 | snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 60); | 1011 | snd_array_init(&codec->mixers, sizeof(struct hda_nid_item), 32); |
| 1012 | snd_array_init(&codec->nids, sizeof(struct hda_nid_item), 32); | ||
| 989 | snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16); | 1013 | snd_array_init(&codec->init_pins, sizeof(struct hda_pincfg), 16); |
| 990 | snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16); | 1014 | snd_array_init(&codec->driver_pins, sizeof(struct hda_pincfg), 16); |
| 991 | if (codec->bus->modelname) { | 1015 | if (codec->bus->modelname) { |
| @@ -1708,7 +1732,7 @@ struct snd_kcontrol *snd_hda_find_mixer_ctl(struct hda_codec *codec, | |||
| 1708 | EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl); | 1732 | EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl); |
| 1709 | 1733 | ||
| 1710 | /** | 1734 | /** |
| 1711 | * snd_hda_ctl-add - Add a control element and assign to the codec | 1735 | * snd_hda_ctl_add - Add a control element and assign to the codec |
| 1712 | * @codec: HD-audio codec | 1736 | * @codec: HD-audio codec |
| 1713 | * @nid: corresponding NID (optional) | 1737 | * @nid: corresponding NID (optional) |
| 1714 | * @kctl: the control element to assign | 1738 | * @kctl: the control element to assign |
| @@ -1723,19 +1747,25 @@ EXPORT_SYMBOL_HDA(snd_hda_find_mixer_ctl); | |||
| 1723 | * | 1747 | * |
| 1724 | * snd_hda_ctl_add() checks the control subdev id field whether | 1748 | * snd_hda_ctl_add() checks the control subdev id field whether |
| 1725 | * #HDA_SUBDEV_NID_FLAG bit is set. If set (and @nid is zero), the lower | 1749 | * #HDA_SUBDEV_NID_FLAG bit is set. If set (and @nid is zero), the lower |
| 1726 | * bits value is taken as the NID to assign. | 1750 | * bits value is taken as the NID to assign. The #HDA_NID_ITEM_AMP bit |
| 1751 | * specifies if kctl->private_value is a HDA amplifier value. | ||
| 1727 | */ | 1752 | */ |
| 1728 | int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, | 1753 | int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, |
| 1729 | struct snd_kcontrol *kctl) | 1754 | struct snd_kcontrol *kctl) |
| 1730 | { | 1755 | { |
| 1731 | int err; | 1756 | int err; |
| 1757 | unsigned short flags = 0; | ||
| 1732 | struct hda_nid_item *item; | 1758 | struct hda_nid_item *item; |
| 1733 | 1759 | ||
| 1734 | if (kctl->id.subdevice & HDA_SUBDEV_NID_FLAG) { | 1760 | if (kctl->id.subdevice & HDA_SUBDEV_AMP_FLAG) { |
| 1761 | flags |= HDA_NID_ITEM_AMP; | ||
| 1735 | if (nid == 0) | 1762 | if (nid == 0) |
| 1736 | nid = kctl->id.subdevice & 0xffff; | 1763 | nid = get_amp_nid_(kctl->private_value); |
| 1737 | kctl->id.subdevice = 0; | ||
| 1738 | } | 1764 | } |
| 1765 | if ((kctl->id.subdevice & HDA_SUBDEV_NID_FLAG) != 0 && nid == 0) | ||
| 1766 | nid = kctl->id.subdevice & 0xffff; | ||
| 1767 | if (kctl->id.subdevice & (HDA_SUBDEV_NID_FLAG|HDA_SUBDEV_AMP_FLAG)) | ||
| 1768 | kctl->id.subdevice = 0; | ||
| 1739 | err = snd_ctl_add(codec->bus->card, kctl); | 1769 | err = snd_ctl_add(codec->bus->card, kctl); |
| 1740 | if (err < 0) | 1770 | if (err < 0) |
| 1741 | return err; | 1771 | return err; |
| @@ -1744,11 +1774,41 @@ int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, | |||
| 1744 | return -ENOMEM; | 1774 | return -ENOMEM; |
| 1745 | item->kctl = kctl; | 1775 | item->kctl = kctl; |
| 1746 | item->nid = nid; | 1776 | item->nid = nid; |
| 1777 | item->flags = flags; | ||
| 1747 | return 0; | 1778 | return 0; |
| 1748 | } | 1779 | } |
| 1749 | EXPORT_SYMBOL_HDA(snd_hda_ctl_add); | 1780 | EXPORT_SYMBOL_HDA(snd_hda_ctl_add); |
| 1750 | 1781 | ||
| 1751 | /** | 1782 | /** |
| 1783 | * snd_hda_add_nid - Assign a NID to a control element | ||
| 1784 | * @codec: HD-audio codec | ||
| 1785 | * @nid: corresponding NID (optional) | ||
| 1786 | * @kctl: the control element to assign | ||
| 1787 | * @index: index to kctl | ||
| 1788 | * | ||
| 1789 | * Add the given control element to an array inside the codec instance. | ||
| 1790 | * This function is used when #snd_hda_ctl_add cannot be used for 1:1 | ||
| 1791 | * NID:KCTL mapping - for example "Capture Source" selector. | ||
| 1792 | */ | ||
| 1793 | int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl, | ||
| 1794 | unsigned int index, hda_nid_t nid) | ||
| 1795 | { | ||
| 1796 | struct hda_nid_item *item; | ||
| 1797 | |||
| 1798 | if (nid > 0) { | ||
| 1799 | item = snd_array_new(&codec->nids); | ||
| 1800 | if (!item) | ||
| 1801 | return -ENOMEM; | ||
| 1802 | item->kctl = kctl; | ||
| 1803 | item->index = index; | ||
| 1804 | item->nid = nid; | ||
| 1805 | return 0; | ||
| 1806 | } | ||
| 1807 | return -EINVAL; | ||
| 1808 | } | ||
| 1809 | EXPORT_SYMBOL_HDA(snd_hda_add_nid); | ||
| 1810 | |||
| 1811 | /** | ||
| 1752 | * snd_hda_ctls_clear - Clear all controls assigned to the given codec | 1812 | * snd_hda_ctls_clear - Clear all controls assigned to the given codec |
| 1753 | * @codec: HD-audio codec | 1813 | * @codec: HD-audio codec |
| 1754 | */ | 1814 | */ |
| @@ -1759,6 +1819,7 @@ void snd_hda_ctls_clear(struct hda_codec *codec) | |||
| 1759 | for (i = 0; i < codec->mixers.used; i++) | 1819 | for (i = 0; i < codec->mixers.used; i++) |
| 1760 | snd_ctl_remove(codec->bus->card, items[i].kctl); | 1820 | snd_ctl_remove(codec->bus->card, items[i].kctl); |
| 1761 | snd_array_free(&codec->mixers); | 1821 | snd_array_free(&codec->mixers); |
| 1822 | snd_array_free(&codec->nids); | ||
| 1762 | } | 1823 | } |
| 1763 | 1824 | ||
| 1764 | /* pseudo device locking | 1825 | /* pseudo device locking |
| @@ -3478,6 +3539,8 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, struct snd_kcontrol_new *knew) | |||
| 3478 | 3539 | ||
| 3479 | for (; knew->name; knew++) { | 3540 | for (; knew->name; knew++) { |
| 3480 | struct snd_kcontrol *kctl; | 3541 | struct snd_kcontrol *kctl; |
| 3542 | if (knew->iface == -1) /* skip this codec private value */ | ||
| 3543 | continue; | ||
| 3481 | kctl = snd_ctl_new1(knew, codec); | 3544 | kctl = snd_ctl_new1(knew, codec); |
| 3482 | if (!kctl) | 3545 | if (!kctl) |
| 3483 | return -ENOMEM; | 3546 | return -ENOMEM; |
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 0a770a28e71f..0c8f05cc56be 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h | |||
| @@ -789,6 +789,7 @@ struct hda_codec { | |||
| 789 | u32 *wcaps; | 789 | u32 *wcaps; |
| 790 | 790 | ||
| 791 | struct snd_array mixers; /* list of assigned mixer elements */ | 791 | struct snd_array mixers; /* list of assigned mixer elements */ |
| 792 | struct snd_array nids; /* list of mapped mixer elements */ | ||
| 792 | 793 | ||
| 793 | struct hda_cache_rec amp_cache; /* cache for amp access */ | 794 | struct hda_cache_rec amp_cache; /* cache for amp access */ |
| 794 | struct hda_cache_rec cmd_cache; /* cache for other commands */ | 795 | struct hda_cache_rec cmd_cache; /* cache for other commands */ |
| @@ -898,6 +899,7 @@ int snd_hda_codec_set_pincfg(struct hda_codec *codec, hda_nid_t nid, | |||
| 898 | unsigned int cfg); | 899 | unsigned int cfg); |
| 899 | int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list, | 900 | int snd_hda_add_pincfg(struct hda_codec *codec, struct snd_array *list, |
| 900 | hda_nid_t nid, unsigned int cfg); /* for hwdep */ | 901 | hda_nid_t nid, unsigned int cfg); /* for hwdep */ |
| 902 | void snd_hda_shutup_pins(struct hda_codec *codec); | ||
| 901 | 903 | ||
| 902 | /* | 904 | /* |
| 903 | * Mixer | 905 | * Mixer |
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 092c6a7c2ff3..5ea21285ee1f 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c | |||
| @@ -861,7 +861,8 @@ static int build_input_controls(struct hda_codec *codec) | |||
| 861 | } | 861 | } |
| 862 | 862 | ||
| 863 | /* create input MUX if multiple sources are available */ | 863 | /* create input MUX if multiple sources are available */ |
| 864 | err = snd_hda_ctl_add(codec, 0, snd_ctl_new1(&cap_sel, codec)); | 864 | err = snd_hda_ctl_add(codec, spec->adc_node->nid, |
| 865 | snd_ctl_new1(&cap_sel, codec)); | ||
| 865 | if (err < 0) | 866 | if (err < 0) |
| 866 | return err; | 867 | return err; |
| 867 | 868 | ||
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 40ccb419b6e9..b36919c0d363 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c | |||
| @@ -293,8 +293,11 @@ static ssize_t type##_store(struct device *dev, \ | |||
| 293 | { \ | 293 | { \ |
| 294 | struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ | 294 | struct snd_hwdep *hwdep = dev_get_drvdata(dev); \ |
| 295 | struct hda_codec *codec = hwdep->private_data; \ | 295 | struct hda_codec *codec = hwdep->private_data; \ |
| 296 | char *after; \ | 296 | unsigned long val; \ |
| 297 | codec->type = simple_strtoul(buf, &after, 0); \ | 297 | int err = strict_strtoul(buf, 0, &val); \ |
| 298 | if (err < 0) \ | ||
| 299 | return err; \ | ||
| 300 | codec->type = val; \ | ||
| 298 | return count; \ | 301 | return count; \ |
| 299 | } | 302 | } |
| 300 | 303 | ||
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index ff6da6f386d1..9925055608b1 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
| @@ -2683,7 +2683,7 @@ static void __devexit azx_remove(struct pci_dev *pci) | |||
| 2683 | } | 2683 | } |
| 2684 | 2684 | ||
| 2685 | /* PCI IDs */ | 2685 | /* PCI IDs */ |
| 2686 | static struct pci_device_id azx_ids[] = { | 2686 | static DEFINE_PCI_DEVICE_TABLE(azx_ids) = { |
| 2687 | /* ICH 6..10 */ | 2687 | /* ICH 6..10 */ |
| 2688 | { PCI_DEVICE(0x8086, 0x2668), .driver_data = AZX_DRIVER_ICH }, | 2688 | { PCI_DEVICE(0x8086, 0x2668), .driver_data = AZX_DRIVER_ICH }, |
| 2689 | { PCI_DEVICE(0x8086, 0x27d8), .driver_data = AZX_DRIVER_ICH }, | 2689 | { PCI_DEVICE(0x8086, 0x27d8), .driver_data = AZX_DRIVER_ICH }, |
| @@ -2723,32 +2723,10 @@ static struct pci_device_id azx_ids[] = { | |||
| 2723 | /* ULI M5461 */ | 2723 | /* ULI M5461 */ |
| 2724 | { PCI_DEVICE(0x10b9, 0x5461), .driver_data = AZX_DRIVER_ULI }, | 2724 | { PCI_DEVICE(0x10b9, 0x5461), .driver_data = AZX_DRIVER_ULI }, |
| 2725 | /* NVIDIA MCP */ | 2725 | /* NVIDIA MCP */ |
| 2726 | { PCI_DEVICE(0x10de, 0x026c), .driver_data = AZX_DRIVER_NVIDIA }, | 2726 | { PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID), |
| 2727 | { PCI_DEVICE(0x10de, 0x0371), .driver_data = AZX_DRIVER_NVIDIA }, | 2727 | .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, |
| 2728 | { PCI_DEVICE(0x10de, 0x03e4), .driver_data = AZX_DRIVER_NVIDIA }, | 2728 | .class_mask = 0xffffff, |
| 2729 | { PCI_DEVICE(0x10de, 0x03f0), .driver_data = AZX_DRIVER_NVIDIA }, | 2729 | .driver_data = AZX_DRIVER_NVIDIA }, |
| 2730 | { PCI_DEVICE(0x10de, 0x044a), .driver_data = AZX_DRIVER_NVIDIA }, | ||
| 2731 | { PCI_DEVICE(0x10de, 0x044b), .driver_data = AZX_DRIVER_NVIDIA }, | ||
| 2732 | { PCI_DEVICE(0x10de, 0x055c), .driver_data = AZX_DRIVER_NVIDIA }, | ||
| 2733 | { PCI_DEVICE(0x10de, 0x055d), .driver_data = AZX_DRIVER_NVIDIA }, | ||
| 2734 | { PCI_DEVICE(0x10de, 0x0590), .driver_data = AZX_DRIVER_NVIDIA }, | ||
| 2735 | { PCI_DEVICE(0x10de, 0x0774), .driver_data = AZX_DRIVER_NVIDIA }, | ||
| 2736 | { PCI_DEVICE(0x10de, 0x0775), .driver_data = AZX_DRIVER_NVIDIA }, | ||
| 2737 | { PCI_DEVICE(0x10de, 0x0776), .driver_data = AZX_DRIVER_NVIDIA }, | ||
| 2738 | { PCI_DEVICE(0x10de, 0x0777), .driver_data = AZX_DRIVER_NVIDIA }, | ||
| 2739 | { PCI_DEVICE(0x10de, 0x07fc), .driver_data = AZX_DRIVER_NVIDIA }, | ||
| 2740 | { PCI_DEVICE(0x10de, 0x07fd), .driver_data = AZX_DRIVER_NVIDIA }, | ||
| 2741 | { PCI_DEVICE(0x10de, 0x0ac0), .driver_data = AZX_DRIVER_NVIDIA }, | ||
| 2742 | { PCI_DEVICE(0x10de, 0x0ac1), .driver_data = AZX_DRIVER_NVIDIA }, | ||
| 2743 | { PCI_DEVICE(0x10de, 0x0ac2), .driver_data = AZX_DRIVER_NVIDIA }, | ||
| 2744 | { PCI_DEVICE(0x10de, 0x0ac3), .driver_data = AZX_DRIVER_NVIDIA }, | ||
| 2745 | { PCI_DEVICE(0x10de, 0x0be2), .driver_data = AZX_DRIVER_NVIDIA }, | ||
| 2746 | { PCI_DEVICE(0x10de, 0x0be3), .driver_data = AZX_DRIVER_NVIDIA }, | ||
| 2747 | { PCI_DEVICE(0x10de, 0x0be4), .driver_data = AZX_DRIVER_NVIDIA }, | ||
| 2748 | { PCI_DEVICE(0x10de, 0x0d94), .driver_data = AZX_DRIVER_NVIDIA }, | ||
| 2749 | { PCI_DEVICE(0x10de, 0x0d95), .driver_data = AZX_DRIVER_NVIDIA }, | ||
| 2750 | { PCI_DEVICE(0x10de, 0x0d96), .driver_data = AZX_DRIVER_NVIDIA }, | ||
| 2751 | { PCI_DEVICE(0x10de, 0x0d97), .driver_data = AZX_DRIVER_NVIDIA }, | ||
| 2752 | /* Teradici */ | 2730 | /* Teradici */ |
| 2753 | { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA }, | 2731 | { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA }, |
| 2754 | /* Creative X-Fi (CA0110-IBG) */ | 2732 | /* Creative X-Fi (CA0110-IBG) */ |
diff --git a/sound/pci/hda/hda_local.h b/sound/pci/hda/hda_local.h index 5778ae882b83..7cee364976ff 100644 --- a/sound/pci/hda/hda_local.h +++ b/sound/pci/hda/hda_local.h | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | * in snd_hda_ctl_add(), so that this value won't appear in the outside. | 31 | * in snd_hda_ctl_add(), so that this value won't appear in the outside. |
| 32 | */ | 32 | */ |
| 33 | #define HDA_SUBDEV_NID_FLAG (1U << 31) | 33 | #define HDA_SUBDEV_NID_FLAG (1U << 31) |
| 34 | #define HDA_SUBDEV_AMP_FLAG (1U << 30) | ||
| 34 | 35 | ||
| 35 | /* | 36 | /* |
| 36 | * for mixer controls | 37 | * for mixer controls |
| @@ -42,7 +43,7 @@ | |||
| 42 | /* mono volume with index (index=0,1,...) (channel=1,2) */ | 43 | /* mono volume with index (index=0,1,...) (channel=1,2) */ |
| 43 | #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ | 44 | #define HDA_CODEC_VOLUME_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ |
| 44 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ | 45 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ |
| 45 | .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \ | 46 | .subdevice = HDA_SUBDEV_AMP_FLAG, \ |
| 46 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | 47 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ |
| 47 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | 48 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ |
| 48 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \ | 49 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \ |
| @@ -63,7 +64,7 @@ | |||
| 63 | /* mono mute switch with index (index=0,1,...) (channel=1,2) */ | 64 | /* mono mute switch with index (index=0,1,...) (channel=1,2) */ |
| 64 | #define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ | 65 | #define HDA_CODEC_MUTE_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ |
| 65 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ | 66 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ |
| 66 | .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \ | 67 | .subdevice = HDA_SUBDEV_AMP_FLAG, \ |
| 67 | .info = snd_hda_mixer_amp_switch_info, \ | 68 | .info = snd_hda_mixer_amp_switch_info, \ |
| 68 | .get = snd_hda_mixer_amp_switch_get, \ | 69 | .get = snd_hda_mixer_amp_switch_get, \ |
| 69 | .put = snd_hda_mixer_amp_switch_put, \ | 70 | .put = snd_hda_mixer_amp_switch_put, \ |
| @@ -81,7 +82,7 @@ | |||
| 81 | /* special beep mono mute switch with index (index=0,1,...) (channel=1,2) */ | 82 | /* special beep mono mute switch with index (index=0,1,...) (channel=1,2) */ |
| 82 | #define HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ | 83 | #define HDA_CODEC_MUTE_BEEP_MONO_IDX(xname, xcidx, nid, channel, xindex, direction) \ |
| 83 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ | 84 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xcidx, \ |
| 84 | .subdevice = HDA_SUBDEV_NID_FLAG | (nid), \ | 85 | .subdevice = HDA_SUBDEV_AMP_FLAG, \ |
| 85 | .info = snd_hda_mixer_amp_switch_info, \ | 86 | .info = snd_hda_mixer_amp_switch_info, \ |
| 86 | .get = snd_hda_mixer_amp_switch_get, \ | 87 | .get = snd_hda_mixer_amp_switch_get, \ |
| 87 | .put = snd_hda_mixer_amp_switch_put_beep, \ | 88 | .put = snd_hda_mixer_amp_switch_put_beep, \ |
| @@ -464,13 +465,20 @@ u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid); | |||
| 464 | u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid); | 465 | u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid); |
| 465 | int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid); | 466 | int snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid); |
| 466 | 467 | ||
| 468 | /* flags for hda_nid_item */ | ||
| 469 | #define HDA_NID_ITEM_AMP (1<<0) | ||
| 470 | |||
| 467 | struct hda_nid_item { | 471 | struct hda_nid_item { |
| 468 | struct snd_kcontrol *kctl; | 472 | struct snd_kcontrol *kctl; |
| 473 | unsigned int index; | ||
| 469 | hda_nid_t nid; | 474 | hda_nid_t nid; |
| 475 | unsigned short flags; | ||
| 470 | }; | 476 | }; |
| 471 | 477 | ||
| 472 | int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, | 478 | int snd_hda_ctl_add(struct hda_codec *codec, hda_nid_t nid, |
| 473 | struct snd_kcontrol *kctl); | 479 | struct snd_kcontrol *kctl); |
| 480 | int snd_hda_add_nid(struct hda_codec *codec, struct snd_kcontrol *kctl, | ||
| 481 | unsigned int index, hda_nid_t nid); | ||
| 474 | void snd_hda_ctls_clear(struct hda_codec *codec); | 482 | void snd_hda_ctls_clear(struct hda_codec *codec); |
| 475 | 483 | ||
| 476 | /* | 484 | /* |
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index c9afc04adac8..f97d35de66c4 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c | |||
| @@ -61,18 +61,29 @@ static const char *get_wid_type_name(unsigned int wid_value) | |||
| 61 | return "UNKNOWN Widget"; | 61 | return "UNKNOWN Widget"; |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | static void print_nid_mixers(struct snd_info_buffer *buffer, | 64 | static void print_nid_array(struct snd_info_buffer *buffer, |
| 65 | struct hda_codec *codec, hda_nid_t nid) | 65 | struct hda_codec *codec, hda_nid_t nid, |
| 66 | struct snd_array *array) | ||
| 66 | { | 67 | { |
| 67 | int i; | 68 | int i; |
| 68 | struct hda_nid_item *items = codec->mixers.list; | 69 | struct hda_nid_item *items = array->list, *item; |
| 69 | struct snd_kcontrol *kctl; | 70 | struct snd_kcontrol *kctl; |
| 70 | for (i = 0; i < codec->mixers.used; i++) { | 71 | for (i = 0; i < array->used; i++) { |
| 71 | if (items[i].nid == nid) { | 72 | item = &items[i]; |
| 72 | kctl = items[i].kctl; | 73 | if (item->nid == nid) { |
| 74 | kctl = item->kctl; | ||
| 73 | snd_iprintf(buffer, | 75 | snd_iprintf(buffer, |
| 74 | " Control: name=\"%s\", index=%i, device=%i\n", | 76 | " Control: name=\"%s\", index=%i, device=%i\n", |
| 75 | kctl->id.name, kctl->id.index, kctl->id.device); | 77 | kctl->id.name, kctl->id.index + item->index, |
| 78 | kctl->id.device); | ||
| 79 | if (item->flags & HDA_NID_ITEM_AMP) | ||
| 80 | snd_iprintf(buffer, | ||
| 81 | " ControlAmp: chs=%lu, dir=%s, " | ||
| 82 | "idx=%lu, ofs=%lu\n", | ||
| 83 | get_amp_channels(kctl), | ||
| 84 | get_amp_direction(kctl) ? "Out" : "In", | ||
| 85 | get_amp_index(kctl), | ||
| 86 | get_amp_offset(kctl)); | ||
| 76 | } | 87 | } |
| 77 | } | 88 | } |
| 78 | } | 89 | } |
| @@ -528,7 +539,8 @@ static void print_gpio(struct snd_info_buffer *buffer, | |||
| 528 | (data & (1<<i)) ? 1 : 0, | 539 | (data & (1<<i)) ? 1 : 0, |
| 529 | (unsol & (1<<i)) ? 1 : 0); | 540 | (unsol & (1<<i)) ? 1 : 0); |
| 530 | /* FIXME: add GPO and GPI pin information */ | 541 | /* FIXME: add GPO and GPI pin information */ |
| 531 | print_nid_mixers(buffer, codec, nid); | 542 | print_nid_array(buffer, codec, nid, &codec->mixers); |
| 543 | print_nid_array(buffer, codec, nid, &codec->nids); | ||
| 532 | } | 544 | } |
| 533 | 545 | ||
| 534 | static void print_codec_info(struct snd_info_entry *entry, | 546 | static void print_codec_info(struct snd_info_entry *entry, |
| @@ -608,7 +620,8 @@ static void print_codec_info(struct snd_info_entry *entry, | |||
| 608 | snd_iprintf(buffer, " CP"); | 620 | snd_iprintf(buffer, " CP"); |
| 609 | snd_iprintf(buffer, "\n"); | 621 | snd_iprintf(buffer, "\n"); |
| 610 | 622 | ||
| 611 | print_nid_mixers(buffer, codec, nid); | 623 | print_nid_array(buffer, codec, nid, &codec->mixers); |
| 624 | print_nid_array(buffer, codec, nid, &codec->nids); | ||
| 612 | print_nid_pcms(buffer, codec, nid); | 625 | print_nid_pcms(buffer, codec, nid); |
| 613 | 626 | ||
| 614 | /* volume knob is a special widget that always have connection | 627 | /* volume knob is a special widget that always have connection |
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c index 69a941c7b158..214301d568fa 100644 --- a/sound/pci/hda/patch_analog.c +++ b/sound/pci/hda/patch_analog.c | |||
| @@ -174,6 +174,7 @@ static struct snd_kcontrol_new ad_beep_mixer[] = { | |||
| 174 | static int ad198x_build_controls(struct hda_codec *codec) | 174 | static int ad198x_build_controls(struct hda_codec *codec) |
| 175 | { | 175 | { |
| 176 | struct ad198x_spec *spec = codec->spec; | 176 | struct ad198x_spec *spec = codec->spec; |
| 177 | struct snd_kcontrol *kctl; | ||
| 177 | unsigned int i; | 178 | unsigned int i; |
| 178 | int err; | 179 | int err; |
| 179 | 180 | ||
| @@ -208,9 +209,7 @@ static int ad198x_build_controls(struct hda_codec *codec) | |||
| 208 | if (!kctl) | 209 | if (!kctl) |
| 209 | return -ENOMEM; | 210 | return -ENOMEM; |
| 210 | kctl->private_value = spec->beep_amp; | 211 | kctl->private_value = spec->beep_amp; |
| 211 | err = snd_hda_ctl_add(codec, | 212 | err = snd_hda_ctl_add(codec, 0, kctl); |
| 212 | get_amp_nid_(spec->beep_amp), | ||
| 213 | kctl); | ||
| 214 | if (err < 0) | 213 | if (err < 0) |
| 215 | return err; | 214 | return err; |
| 216 | } | 215 | } |
| @@ -239,6 +238,27 @@ static int ad198x_build_controls(struct hda_codec *codec) | |||
| 239 | } | 238 | } |
| 240 | 239 | ||
| 241 | ad198x_free_kctls(codec); /* no longer needed */ | 240 | ad198x_free_kctls(codec); /* no longer needed */ |
| 241 | |||
| 242 | /* assign Capture Source enums to NID */ | ||
| 243 | kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); | ||
| 244 | if (!kctl) | ||
| 245 | kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); | ||
| 246 | for (i = 0; kctl && i < kctl->count; i++) { | ||
| 247 | err = snd_hda_add_nid(codec, kctl, i, spec->capsrc_nids[i]); | ||
| 248 | if (err < 0) | ||
| 249 | return err; | ||
| 250 | } | ||
| 251 | |||
| 252 | /* assign IEC958 enums to NID */ | ||
| 253 | kctl = snd_hda_find_mixer_ctl(codec, | ||
| 254 | SNDRV_CTL_NAME_IEC958("",PLAYBACK,NONE) "Source"); | ||
| 255 | if (kctl) { | ||
| 256 | err = snd_hda_add_nid(codec, kctl, 0, | ||
| 257 | spec->multiout.dig_out_nid); | ||
| 258 | if (err < 0) | ||
| 259 | return err; | ||
| 260 | } | ||
| 261 | |||
| 242 | return 0; | 262 | return 0; |
| 243 | } | 263 | } |
| 244 | 264 | ||
| @@ -421,6 +441,11 @@ static int ad198x_build_pcms(struct hda_codec *codec) | |||
| 421 | return 0; | 441 | return 0; |
| 422 | } | 442 | } |
| 423 | 443 | ||
| 444 | static inline void ad198x_shutup(struct hda_codec *codec) | ||
| 445 | { | ||
| 446 | snd_hda_shutup_pins(codec); | ||
| 447 | } | ||
| 448 | |||
| 424 | static void ad198x_free_kctls(struct hda_codec *codec) | 449 | static void ad198x_free_kctls(struct hda_codec *codec) |
| 425 | { | 450 | { |
| 426 | struct ad198x_spec *spec = codec->spec; | 451 | struct ad198x_spec *spec = codec->spec; |
| @@ -434,6 +459,46 @@ static void ad198x_free_kctls(struct hda_codec *codec) | |||
| 434 | snd_array_free(&spec->kctls); | 459 | snd_array_free(&spec->kctls); |
| 435 | } | 460 | } |
| 436 | 461 | ||
| 462 | static void ad198x_power_eapd_write(struct hda_codec *codec, hda_nid_t front, | ||
| 463 | hda_nid_t hp) | ||
| 464 | { | ||
| 465 | struct ad198x_spec *spec = codec->spec; | ||
| 466 | snd_hda_codec_write(codec, front, 0, AC_VERB_SET_EAPD_BTLENABLE, | ||
| 467 | !spec->inv_eapd ? 0x00 : 0x02); | ||
| 468 | snd_hda_codec_write(codec, hp, 0, AC_VERB_SET_EAPD_BTLENABLE, | ||
| 469 | !spec->inv_eapd ? 0x00 : 0x02); | ||
| 470 | } | ||
| 471 | |||
| 472 | static void ad198x_power_eapd(struct hda_codec *codec) | ||
| 473 | { | ||
| 474 | /* We currently only handle front, HP */ | ||
| 475 | switch (codec->vendor_id) { | ||
| 476 | case 0x11d41882: | ||
| 477 | case 0x11d4882a: | ||
| 478 | case 0x11d41884: | ||
| 479 | case 0x11d41984: | ||
| 480 | case 0x11d41883: | ||
| 481 | case 0x11d4184a: | ||
| 482 | case 0x11d4194a: | ||
| 483 | case 0x11d4194b: | ||
| 484 | ad198x_power_eapd_write(codec, 0x12, 0x11); | ||
| 485 | break; | ||
| 486 | case 0x11d41981: | ||
| 487 | case 0x11d41983: | ||
| 488 | ad198x_power_eapd_write(codec, 0x05, 0x06); | ||
| 489 | break; | ||
| 490 | case 0x11d41986: | ||
| 491 | ad198x_power_eapd_write(codec, 0x1b, 0x1a); | ||
| 492 | break; | ||
| 493 | case 0x11d41988: | ||
| 494 | case 0x11d4198b: | ||
| 495 | case 0x11d4989a: | ||
| 496 | case 0x11d4989b: | ||
| 497 | ad198x_power_eapd_write(codec, 0x29, 0x22); | ||
| 498 | break; | ||
| 499 | } | ||
| 500 | } | ||
| 501 | |||
| 437 | static void ad198x_free(struct hda_codec *codec) | 502 | static void ad198x_free(struct hda_codec *codec) |
| 438 | { | 503 | { |
| 439 | struct ad198x_spec *spec = codec->spec; | 504 | struct ad198x_spec *spec = codec->spec; |
| @@ -441,11 +506,29 @@ static void ad198x_free(struct hda_codec *codec) | |||
| 441 | if (!spec) | 506 | if (!spec) |
| 442 | return; | 507 | return; |
| 443 | 508 | ||
| 509 | ad198x_shutup(codec); | ||
| 444 | ad198x_free_kctls(codec); | 510 | ad198x_free_kctls(codec); |
| 445 | kfree(spec); | 511 | kfree(spec); |
| 446 | snd_hda_detach_beep_device(codec); | 512 | snd_hda_detach_beep_device(codec); |
| 447 | } | 513 | } |
| 448 | 514 | ||
| 515 | #ifdef SND_HDA_NEEDS_RESUME | ||
| 516 | static int ad198x_suspend(struct hda_codec *codec, pm_message_t state) | ||
| 517 | { | ||
| 518 | ad198x_shutup(codec); | ||
| 519 | ad198x_power_eapd(codec); | ||
| 520 | return 0; | ||
| 521 | } | ||
| 522 | |||
| 523 | static int ad198x_resume(struct hda_codec *codec) | ||
| 524 | { | ||
| 525 | ad198x_init(codec); | ||
| 526 | snd_hda_codec_resume_amp(codec); | ||
| 527 | snd_hda_codec_resume_cache(codec); | ||
| 528 | return 0; | ||
| 529 | } | ||
| 530 | #endif | ||
| 531 | |||
| 449 | static struct hda_codec_ops ad198x_patch_ops = { | 532 | static struct hda_codec_ops ad198x_patch_ops = { |
| 450 | .build_controls = ad198x_build_controls, | 533 | .build_controls = ad198x_build_controls, |
| 451 | .build_pcms = ad198x_build_pcms, | 534 | .build_pcms = ad198x_build_pcms, |
| @@ -454,6 +537,11 @@ static struct hda_codec_ops ad198x_patch_ops = { | |||
| 454 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 537 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
| 455 | .check_power_status = ad198x_check_power_status, | 538 | .check_power_status = ad198x_check_power_status, |
| 456 | #endif | 539 | #endif |
| 540 | #ifdef SND_HDA_NEEDS_RESUME | ||
| 541 | .suspend = ad198x_suspend, | ||
| 542 | .resume = ad198x_resume, | ||
| 543 | #endif | ||
| 544 | .reboot_notify = ad198x_shutup, | ||
| 457 | }; | 545 | }; |
| 458 | 546 | ||
| 459 | 547 | ||
| @@ -701,6 +789,7 @@ static struct snd_kcontrol_new ad1986a_laptop_eapd_mixers[] = { | |||
| 701 | { | 789 | { |
| 702 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 790 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 703 | .name = "External Amplifier", | 791 | .name = "External Amplifier", |
| 792 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b, | ||
| 704 | .info = ad198x_eapd_info, | 793 | .info = ad198x_eapd_info, |
| 705 | .get = ad198x_eapd_get, | 794 | .get = ad198x_eapd_get, |
| 706 | .put = ad198x_eapd_put, | 795 | .put = ad198x_eapd_put, |
| @@ -808,6 +897,7 @@ static struct snd_kcontrol_new ad1986a_automute_master_mixers[] = { | |||
| 808 | { | 897 | { |
| 809 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 898 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 810 | .name = "Master Playback Switch", | 899 | .name = "Master Playback Switch", |
| 900 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
| 811 | .info = snd_hda_mixer_amp_switch_info, | 901 | .info = snd_hda_mixer_amp_switch_info, |
| 812 | .get = snd_hda_mixer_amp_switch_get, | 902 | .get = snd_hda_mixer_amp_switch_get, |
| 813 | .put = ad1986a_hp_master_sw_put, | 903 | .put = ad1986a_hp_master_sw_put, |
| @@ -1612,6 +1702,7 @@ static struct snd_kcontrol_new ad1981_hp_mixers[] = { | |||
| 1612 | HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol), | 1702 | HDA_BIND_VOL("Master Playback Volume", &ad1981_hp_bind_master_vol), |
| 1613 | { | 1703 | { |
| 1614 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1704 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1705 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x05, | ||
| 1615 | .name = "Master Playback Switch", | 1706 | .name = "Master Playback Switch", |
| 1616 | .info = ad198x_eapd_info, | 1707 | .info = ad198x_eapd_info, |
| 1617 | .get = ad198x_eapd_get, | 1708 | .get = ad198x_eapd_get, |
| @@ -2136,6 +2227,7 @@ static struct snd_kcontrol_new ad1988_laptop_mixers[] = { | |||
| 2136 | { | 2227 | { |
| 2137 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2228 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 2138 | .name = "External Amplifier", | 2229 | .name = "External Amplifier", |
| 2230 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x12, | ||
| 2139 | .info = ad198x_eapd_info, | 2231 | .info = ad198x_eapd_info, |
| 2140 | .get = ad198x_eapd_get, | 2232 | .get = ad198x_eapd_get, |
| 2141 | .put = ad198x_eapd_put, | 2233 | .put = ad198x_eapd_put, |
| @@ -2257,6 +2349,7 @@ static struct snd_kcontrol_new ad1988_spdif_out_mixers[] = { | |||
| 2257 | { | 2349 | { |
| 2258 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2350 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 2259 | .name = "IEC958 Playback Source", | 2351 | .name = "IEC958 Playback Source", |
| 2352 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x1b, | ||
| 2260 | .info = ad1988_spdif_playback_source_info, | 2353 | .info = ad1988_spdif_playback_source_info, |
| 2261 | .get = ad1988_spdif_playback_source_get, | 2354 | .get = ad1988_spdif_playback_source_get, |
| 2262 | .put = ad1988_spdif_playback_source_put, | 2355 | .put = ad1988_spdif_playback_source_put, |
| @@ -2372,6 +2465,12 @@ static struct hda_verb ad1988_spdif_init_verbs[] = { | |||
| 2372 | { } | 2465 | { } |
| 2373 | }; | 2466 | }; |
| 2374 | 2467 | ||
| 2468 | static struct hda_verb ad1988_spdif_in_init_verbs[] = { | ||
| 2469 | /* unmute SPDIF input pin */ | ||
| 2470 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0)}, | ||
| 2471 | { } | ||
| 2472 | }; | ||
| 2473 | |||
| 2375 | /* AD1989 has no ADC -> SPDIF route */ | 2474 | /* AD1989 has no ADC -> SPDIF route */ |
| 2376 | static struct hda_verb ad1989_spdif_init_verbs[] = { | 2475 | static struct hda_verb ad1989_spdif_init_verbs[] = { |
| 2377 | /* SPDIF-1 out pin */ | 2476 | /* SPDIF-1 out pin */ |
| @@ -2589,7 +2688,7 @@ static int add_control(struct ad198x_spec *spec, int type, const char *name, | |||
| 2589 | if (! knew->name) | 2688 | if (! knew->name) |
| 2590 | return -ENOMEM; | 2689 | return -ENOMEM; |
| 2591 | if (get_amp_nid_(val)) | 2690 | if (get_amp_nid_(val)) |
| 2592 | knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val); | 2691 | knew->subdevice = HDA_SUBDEV_AMP_FLAG; |
| 2593 | knew->private_value = val; | 2692 | knew->private_value = val; |
| 2594 | return 0; | 2693 | return 0; |
| 2595 | } | 2694 | } |
| @@ -3107,8 +3206,11 @@ static int patch_ad1988(struct hda_codec *codec) | |||
| 3107 | ad1988_spdif_init_verbs; | 3206 | ad1988_spdif_init_verbs; |
| 3108 | } | 3207 | } |
| 3109 | } | 3208 | } |
| 3110 | if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a) | 3209 | if (spec->dig_in_nid && codec->vendor_id < 0x11d4989a) { |
| 3111 | spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers; | 3210 | spec->mixers[spec->num_mixers++] = ad1988_spdif_in_mixers; |
| 3211 | spec->init_verbs[spec->num_init_verbs++] = | ||
| 3212 | ad1988_spdif_in_init_verbs; | ||
| 3213 | } | ||
| 3112 | 3214 | ||
| 3113 | codec->patch_ops = ad198x_patch_ops; | 3215 | codec->patch_ops = ad198x_patch_ops; |
| 3114 | switch (board_config) { | 3216 | switch (board_config) { |
| @@ -3747,6 +3849,7 @@ static struct snd_kcontrol_new ad1884a_laptop_mixers[] = { | |||
| 3747 | { | 3849 | { |
| 3748 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 3850 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 3749 | .name = "Master Playback Switch", | 3851 | .name = "Master Playback Switch", |
| 3852 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
| 3750 | .info = snd_hda_mixer_amp_switch_info, | 3853 | .info = snd_hda_mixer_amp_switch_info, |
| 3751 | .get = snd_hda_mixer_amp_switch_get, | 3854 | .get = snd_hda_mixer_amp_switch_get, |
| 3752 | .put = ad1884a_mobile_master_sw_put, | 3855 | .put = ad1884a_mobile_master_sw_put, |
| @@ -3775,6 +3878,7 @@ static struct snd_kcontrol_new ad1884a_mobile_mixers[] = { | |||
| 3775 | { | 3878 | { |
| 3776 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 3879 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 3777 | .name = "Master Playback Switch", | 3880 | .name = "Master Playback Switch", |
| 3881 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
| 3778 | .info = snd_hda_mixer_amp_switch_info, | 3882 | .info = snd_hda_mixer_amp_switch_info, |
| 3779 | .get = snd_hda_mixer_amp_switch_get, | 3883 | .get = snd_hda_mixer_amp_switch_get, |
| 3780 | .put = ad1884a_mobile_master_sw_put, | 3884 | .put = ad1884a_mobile_master_sw_put, |
| @@ -4116,6 +4220,7 @@ static struct snd_kcontrol_new ad1984a_touchsmart_mixers[] = { | |||
| 4116 | /* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ | 4220 | /* HDA_CODEC_MUTE("Master Playback Switch", 0x21, 0x0, HDA_OUTPUT),*/ |
| 4117 | { | 4221 | { |
| 4118 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 4222 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 4223 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
| 4119 | .name = "Master Playback Switch", | 4224 | .name = "Master Playback Switch", |
| 4120 | .info = snd_hda_mixer_amp_switch_info, | 4225 | .info = snd_hda_mixer_amp_switch_info, |
| 4121 | .get = snd_hda_mixer_amp_switch_get, | 4226 | .get = snd_hda_mixer_amp_switch_get, |
diff --git a/sound/pci/hda/patch_cirrus.c b/sound/pci/hda/patch_cirrus.c index fe0423c39598..7de782a5b8f4 100644 --- a/sound/pci/hda/patch_cirrus.c +++ b/sound/pci/hda/patch_cirrus.c | |||
| @@ -501,7 +501,8 @@ static int add_mute(struct hda_codec *codec, const char *name, int index, | |||
| 501 | knew.private_value = pval; | 501 | knew.private_value = pval; |
| 502 | snprintf(tmp, sizeof(tmp), "%s %s Switch", name, dir_sfx[dir]); | 502 | snprintf(tmp, sizeof(tmp), "%s %s Switch", name, dir_sfx[dir]); |
| 503 | *kctlp = snd_ctl_new1(&knew, codec); | 503 | *kctlp = snd_ctl_new1(&knew, codec); |
| 504 | return snd_hda_ctl_add(codec, get_amp_nid_(pval), *kctlp); | 504 | (*kctlp)->id.subdevice = HDA_SUBDEV_AMP_FLAG; |
| 505 | return snd_hda_ctl_add(codec, 0, *kctlp); | ||
| 505 | } | 506 | } |
| 506 | 507 | ||
| 507 | static int add_volume(struct hda_codec *codec, const char *name, | 508 | static int add_volume(struct hda_codec *codec, const char *name, |
| @@ -514,7 +515,8 @@ static int add_volume(struct hda_codec *codec, const char *name, | |||
| 514 | knew.private_value = pval; | 515 | knew.private_value = pval; |
| 515 | snprintf(tmp, sizeof(tmp), "%s %s Volume", name, dir_sfx[dir]); | 516 | snprintf(tmp, sizeof(tmp), "%s %s Volume", name, dir_sfx[dir]); |
| 516 | *kctlp = snd_ctl_new1(&knew, codec); | 517 | *kctlp = snd_ctl_new1(&knew, codec); |
| 517 | return snd_hda_ctl_add(codec, get_amp_nid_(pval), *kctlp); | 518 | (*kctlp)->id.subdevice = HDA_SUBDEV_AMP_FLAG; |
| 519 | return snd_hda_ctl_add(codec, 0, *kctlp); | ||
| 518 | } | 520 | } |
| 519 | 521 | ||
| 520 | static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac) | 522 | static void fix_volume_caps(struct hda_codec *codec, hda_nid_t dac) |
| @@ -751,6 +753,7 @@ static int build_input(struct hda_codec *codec) | |||
| 751 | spec->capture_bind[1] = make_bind_capture(codec, &snd_hda_bind_vol); | 753 | spec->capture_bind[1] = make_bind_capture(codec, &snd_hda_bind_vol); |
| 752 | for (i = 0; i < 2; i++) { | 754 | for (i = 0; i < 2; i++) { |
| 753 | struct snd_kcontrol *kctl; | 755 | struct snd_kcontrol *kctl; |
| 756 | int n; | ||
| 754 | if (!spec->capture_bind[i]) | 757 | if (!spec->capture_bind[i]) |
| 755 | return -ENOMEM; | 758 | return -ENOMEM; |
| 756 | kctl = snd_ctl_new1(&cs_capture_ctls[i], codec); | 759 | kctl = snd_ctl_new1(&cs_capture_ctls[i], codec); |
| @@ -760,6 +763,13 @@ static int build_input(struct hda_codec *codec) | |||
| 760 | err = snd_hda_ctl_add(codec, 0, kctl); | 763 | err = snd_hda_ctl_add(codec, 0, kctl); |
| 761 | if (err < 0) | 764 | if (err < 0) |
| 762 | return err; | 765 | return err; |
| 766 | for (n = 0; n < AUTO_PIN_LAST; n++) { | ||
| 767 | if (!spec->adc_nid[n]) | ||
| 768 | continue; | ||
| 769 | err = snd_hda_add_nid(codec, kctl, 0, spec->adc_nid[i]); | ||
| 770 | if (err < 0) | ||
| 771 | return err; | ||
| 772 | } | ||
| 763 | } | 773 | } |
| 764 | 774 | ||
| 765 | if (spec->num_inputs > 1 && !spec->mic_detect) { | 775 | if (spec->num_inputs > 1 && !spec->mic_detect) { |
diff --git a/sound/pci/hda/patch_cmedia.c b/sound/pci/hda/patch_cmedia.c index a45c1169762b..ff60908f4554 100644 --- a/sound/pci/hda/patch_cmedia.c +++ b/sound/pci/hda/patch_cmedia.c | |||
| @@ -315,7 +315,8 @@ static struct hda_verb cmi9880_allout_init[] = { | |||
| 315 | static int cmi9880_build_controls(struct hda_codec *codec) | 315 | static int cmi9880_build_controls(struct hda_codec *codec) |
| 316 | { | 316 | { |
| 317 | struct cmi_spec *spec = codec->spec; | 317 | struct cmi_spec *spec = codec->spec; |
| 318 | int err; | 318 | struct snd_kcontrol *kctl; |
| 319 | int i, err; | ||
| 319 | 320 | ||
| 320 | err = snd_hda_add_new_ctls(codec, cmi9880_basic_mixer); | 321 | err = snd_hda_add_new_ctls(codec, cmi9880_basic_mixer); |
| 321 | if (err < 0) | 322 | if (err < 0) |
| @@ -340,6 +341,14 @@ static int cmi9880_build_controls(struct hda_codec *codec) | |||
| 340 | if (err < 0) | 341 | if (err < 0) |
| 341 | return err; | 342 | return err; |
| 342 | } | 343 | } |
| 344 | |||
| 345 | /* assign Capture Source enums to NID */ | ||
| 346 | kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); | ||
| 347 | for (i = 0; kctl && i < kctl->count; i++) { | ||
| 348 | err = snd_hda_add_nid(codec, kctl, i, spec->adc_nids[i]); | ||
| 349 | if (err < 0) | ||
| 350 | return err; | ||
| 351 | } | ||
| 343 | return 0; | 352 | return 0; |
| 344 | } | 353 | } |
| 345 | 354 | ||
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index c578c28f368e..685015a53292 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
| @@ -111,8 +111,22 @@ struct conexant_spec { | |||
| 111 | 111 | ||
| 112 | unsigned int dell_automute; | 112 | unsigned int dell_automute; |
| 113 | unsigned int port_d_mode; | 113 | unsigned int port_d_mode; |
| 114 | unsigned char ext_mic_bias; | ||
| 115 | unsigned int dell_vostro; | 114 | unsigned int dell_vostro; |
| 115 | |||
| 116 | unsigned int ext_mic_present; | ||
| 117 | unsigned int recording; | ||
| 118 | void (*capture_prepare)(struct hda_codec *codec); | ||
| 119 | void (*capture_cleanup)(struct hda_codec *codec); | ||
| 120 | |||
| 121 | /* OLPC XO-1.5 supports DC input mode (e.g. for use with analog sensors) | ||
| 122 | * through the microphone jack. | ||
| 123 | * When the user enables this through a mixer switch, both internal and | ||
| 124 | * external microphones are disabled. Gain is fixed at 0dB. In this mode, | ||
| 125 | * we also allow the bias to be configured through a separate mixer | ||
| 126 | * control. */ | ||
| 127 | unsigned int dc_enable; | ||
| 128 | unsigned int dc_input_bias; /* offset into cxt5066_olpc_dc_bias */ | ||
| 129 | unsigned int mic_boost; /* offset into cxt5066_analog_mic_boost */ | ||
| 116 | }; | 130 | }; |
| 117 | 131 | ||
| 118 | static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, | 132 | static int conexant_playback_pcm_open(struct hda_pcm_stream *hinfo, |
| @@ -185,6 +199,8 @@ static int conexant_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | |||
| 185 | struct snd_pcm_substream *substream) | 199 | struct snd_pcm_substream *substream) |
| 186 | { | 200 | { |
| 187 | struct conexant_spec *spec = codec->spec; | 201 | struct conexant_spec *spec = codec->spec; |
| 202 | if (spec->capture_prepare) | ||
| 203 | spec->capture_prepare(codec); | ||
| 188 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], | 204 | snd_hda_codec_setup_stream(codec, spec->adc_nids[substream->number], |
| 189 | stream_tag, 0, format); | 205 | stream_tag, 0, format); |
| 190 | return 0; | 206 | return 0; |
| @@ -196,6 +212,8 @@ static int conexant_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | |||
| 196 | { | 212 | { |
| 197 | struct conexant_spec *spec = codec->spec; | 213 | struct conexant_spec *spec = codec->spec; |
| 198 | snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); | 214 | snd_hda_codec_cleanup_stream(codec, spec->adc_nids[substream->number]); |
| 215 | if (spec->capture_cleanup) | ||
| 216 | spec->capture_cleanup(codec); | ||
| 199 | return 0; | 217 | return 0; |
| 200 | } | 218 | } |
| 201 | 219 | ||
| @@ -1723,6 +1741,22 @@ static struct snd_kcontrol_new cxt5051_hp_dv6736_mixers[] = { | |||
| 1723 | {} | 1741 | {} |
| 1724 | }; | 1742 | }; |
| 1725 | 1743 | ||
| 1744 | static struct snd_kcontrol_new cxt5051_f700_mixers[] = { | ||
| 1745 | HDA_CODEC_VOLUME("Mic Volume", 0x14, 0x01, HDA_INPUT), | ||
| 1746 | HDA_CODEC_MUTE("Mic Switch", 0x14, 0x01, HDA_INPUT), | ||
| 1747 | HDA_CODEC_VOLUME("Master Playback Volume", 0x10, 0x00, HDA_OUTPUT), | ||
| 1748 | { | ||
| 1749 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 1750 | .name = "Master Playback Switch", | ||
| 1751 | .info = cxt_eapd_info, | ||
| 1752 | .get = cxt_eapd_get, | ||
| 1753 | .put = cxt5051_hp_master_sw_put, | ||
| 1754 | .private_value = 0x1a, | ||
| 1755 | }, | ||
| 1756 | |||
| 1757 | {} | ||
| 1758 | }; | ||
| 1759 | |||
| 1726 | static struct hda_verb cxt5051_init_verbs[] = { | 1760 | static struct hda_verb cxt5051_init_verbs[] = { |
| 1727 | /* Line in, Mic */ | 1761 | /* Line in, Mic */ |
| 1728 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, | 1762 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(0) | 0x03}, |
| @@ -1813,6 +1847,32 @@ static struct hda_verb cxt5051_lenovo_x200_init_verbs[] = { | |||
| 1813 | { } /* end */ | 1847 | { } /* end */ |
| 1814 | }; | 1848 | }; |
| 1815 | 1849 | ||
| 1850 | static struct hda_verb cxt5051_f700_init_verbs[] = { | ||
| 1851 | /* Line in, Mic */ | ||
| 1852 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x03}, | ||
| 1853 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
| 1854 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, | ||
| 1855 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x0}, | ||
| 1856 | /* SPK */ | ||
| 1857 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
| 1858 | {0x1a, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
| 1859 | /* HP, Amp */ | ||
| 1860 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
| 1861 | {0x16, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
| 1862 | /* DAC1 */ | ||
| 1863 | {0x10, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
| 1864 | /* Record selector: Int mic */ | ||
| 1865 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1) | 0x44}, | ||
| 1866 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x1}, | ||
| 1867 | /* SPDIF route: PCM */ | ||
| 1868 | {0x1c, AC_VERB_SET_CONNECT_SEL, 0x0}, | ||
| 1869 | /* EAPD */ | ||
| 1870 | {0x1a, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | ||
| 1871 | {0x16, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CONEXANT_HP_EVENT}, | ||
| 1872 | {0x17, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN|CXT5051_PORTB_EVENT}, | ||
| 1873 | { } /* end */ | ||
| 1874 | }; | ||
| 1875 | |||
| 1816 | /* initialize jack-sensing, too */ | 1876 | /* initialize jack-sensing, too */ |
| 1817 | static int cxt5051_init(struct hda_codec *codec) | 1877 | static int cxt5051_init(struct hda_codec *codec) |
| 1818 | { | 1878 | { |
| @@ -1832,6 +1892,7 @@ enum { | |||
| 1832 | CXT5051_HP, /* no docking */ | 1892 | CXT5051_HP, /* no docking */ |
| 1833 | CXT5051_HP_DV6736, /* HP without mic switch */ | 1893 | CXT5051_HP_DV6736, /* HP without mic switch */ |
| 1834 | CXT5051_LENOVO_X200, /* Lenovo X200 laptop */ | 1894 | CXT5051_LENOVO_X200, /* Lenovo X200 laptop */ |
| 1895 | CXT5051_F700, /* HP Compaq Presario F700 */ | ||
| 1835 | CXT5051_MODELS | 1896 | CXT5051_MODELS |
| 1836 | }; | 1897 | }; |
| 1837 | 1898 | ||
| @@ -1840,6 +1901,7 @@ static const char *cxt5051_models[CXT5051_MODELS] = { | |||
| 1840 | [CXT5051_HP] = "hp", | 1901 | [CXT5051_HP] = "hp", |
| 1841 | [CXT5051_HP_DV6736] = "hp-dv6736", | 1902 | [CXT5051_HP_DV6736] = "hp-dv6736", |
| 1842 | [CXT5051_LENOVO_X200] = "lenovo-x200", | 1903 | [CXT5051_LENOVO_X200] = "lenovo-x200", |
| 1904 | [CXT5051_F700] = "hp 700" | ||
| 1843 | }; | 1905 | }; |
| 1844 | 1906 | ||
| 1845 | static struct snd_pci_quirk cxt5051_cfg_tbl[] = { | 1907 | static struct snd_pci_quirk cxt5051_cfg_tbl[] = { |
| @@ -1849,6 +1911,7 @@ static struct snd_pci_quirk cxt5051_cfg_tbl[] = { | |||
| 1849 | CXT5051_LAPTOP), | 1911 | CXT5051_LAPTOP), |
| 1850 | SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), | 1912 | SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), |
| 1851 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200), | 1913 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo X200", CXT5051_LENOVO_X200), |
| 1914 | SND_PCI_QUIRK(0x103c, 0x30ea, "Compaq Presario F700", CXT5051_F700), | ||
| 1852 | {} | 1915 | {} |
| 1853 | }; | 1916 | }; |
| 1854 | 1917 | ||
| @@ -1899,6 +1962,11 @@ static int patch_cxt5051(struct hda_codec *codec) | |||
| 1899 | case CXT5051_LENOVO_X200: | 1962 | case CXT5051_LENOVO_X200: |
| 1900 | spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs; | 1963 | spec->init_verbs[0] = cxt5051_lenovo_x200_init_verbs; |
| 1901 | break; | 1964 | break; |
| 1965 | case CXT5051_F700: | ||
| 1966 | spec->init_verbs[0] = cxt5051_f700_init_verbs; | ||
| 1967 | spec->mixers[0] = cxt5051_f700_mixers; | ||
| 1968 | spec->no_auto_mic = 1; | ||
| 1969 | break; | ||
| 1902 | } | 1970 | } |
| 1903 | 1971 | ||
| 1904 | return 0; | 1972 | return 0; |
| @@ -1966,53 +2034,97 @@ static int cxt5066_hp_master_sw_put(struct snd_kcontrol *kcontrol, | |||
| 1966 | return 1; | 2034 | return 1; |
| 1967 | } | 2035 | } |
| 1968 | 2036 | ||
| 1969 | /* toggle input of built-in and mic jack appropriately */ | 2037 | static const struct hda_input_mux cxt5066_olpc_dc_bias = { |
| 1970 | static void cxt5066_automic(struct hda_codec *codec) | 2038 | .num_items = 3, |
| 2039 | .items = { | ||
| 2040 | { "Off", PIN_IN }, | ||
| 2041 | { "50%", PIN_VREF50 }, | ||
| 2042 | { "80%", PIN_VREF80 }, | ||
| 2043 | }, | ||
| 2044 | }; | ||
| 2045 | |||
| 2046 | static int cxt5066_set_olpc_dc_bias(struct hda_codec *codec) | ||
| 1971 | { | 2047 | { |
| 1972 | struct conexant_spec *spec = codec->spec; | 2048 | struct conexant_spec *spec = codec->spec; |
| 1973 | struct hda_verb ext_mic_present[] = { | 2049 | /* Even though port F is the DC input, the bias is controlled on port B. |
| 1974 | /* enable external mic, port B */ | 2050 | * we also leave that port as an active input (but unselected) in DC mode |
| 1975 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_bias}, | 2051 | * just in case that is necessary to make the bias setting take effect. */ |
| 2052 | return snd_hda_codec_write_cache(codec, 0x1a, 0, | ||
| 2053 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
| 2054 | cxt5066_olpc_dc_bias.items[spec->dc_input_bias].index); | ||
| 2055 | } | ||
| 1976 | 2056 | ||
| 1977 | /* switch to external mic input */ | 2057 | /* OLPC defers mic widget control until when capture is started because the |
| 1978 | {0x17, AC_VERB_SET_CONNECT_SEL, 0}, | 2058 | * microphone LED comes on as soon as these settings are put in place. if we |
| 2059 | * did this before recording, it would give the false indication that recording | ||
| 2060 | * is happening when it is not. */ | ||
| 2061 | static void cxt5066_olpc_select_mic(struct hda_codec *codec) | ||
| 2062 | { | ||
| 2063 | struct conexant_spec *spec = codec->spec; | ||
| 2064 | if (!spec->recording) | ||
| 2065 | return; | ||
| 1979 | 2066 | ||
| 1980 | /* disable internal mic, port C */ | 2067 | if (spec->dc_enable) { |
| 1981 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2068 | /* in DC mode we ignore presence detection and just use the jack |
| 1982 | {} | 2069 | * through our special DC port */ |
| 1983 | }; | 2070 | const struct hda_verb enable_dc_mode[] = { |
| 1984 | static struct hda_verb ext_mic_absent[] = { | 2071 | /* disble internal mic, port C */ |
| 1985 | /* enable internal mic, port C */ | 2072 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
| 1986 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 2073 | |
| 2074 | /* enable DC capture, port F */ | ||
| 2075 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
| 2076 | {}, | ||
| 2077 | }; | ||
| 2078 | |||
| 2079 | snd_hda_sequence_write(codec, enable_dc_mode); | ||
| 2080 | /* port B input disabled (and bias set) through the following call */ | ||
| 2081 | cxt5066_set_olpc_dc_bias(codec); | ||
| 2082 | return; | ||
| 2083 | } | ||
| 1987 | 2084 | ||
| 1988 | /* switch to internal mic input */ | 2085 | /* disable DC (port F) */ |
| 1989 | {0x17, AC_VERB_SET_CONNECT_SEL, 1}, | 2086 | snd_hda_codec_write(codec, 0x1e, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, 0); |
| 1990 | 2087 | ||
| 1991 | /* disable external mic, port B */ | 2088 | /* external mic, port B */ |
| 1992 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2089 | snd_hda_codec_write(codec, 0x1a, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, |
| 1993 | {} | 2090 | spec->ext_mic_present ? CXT5066_OLPC_EXT_MIC_BIAS : 0); |
| 1994 | }; | 2091 | |
| 2092 | /* internal mic, port C */ | ||
| 2093 | snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
| 2094 | spec->ext_mic_present ? 0 : PIN_VREF80); | ||
| 2095 | } | ||
| 2096 | |||
| 2097 | /* toggle input of built-in and mic jack appropriately */ | ||
| 2098 | static void cxt5066_olpc_automic(struct hda_codec *codec) | ||
| 2099 | { | ||
| 2100 | struct conexant_spec *spec = codec->spec; | ||
| 1995 | unsigned int present; | 2101 | unsigned int present; |
| 1996 | 2102 | ||
| 1997 | present = snd_hda_jack_detect(codec, 0x1a); | 2103 | if (spec->dc_enable) /* don't do presence detection in DC mode */ |
| 1998 | if (present) { | 2104 | return; |
| 2105 | |||
| 2106 | present = snd_hda_codec_read(codec, 0x1a, 0, | ||
| 2107 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
| 2108 | if (present) | ||
| 1999 | snd_printdd("CXT5066: external microphone detected\n"); | 2109 | snd_printdd("CXT5066: external microphone detected\n"); |
| 2000 | snd_hda_sequence_write(codec, ext_mic_present); | 2110 | else |
| 2001 | } else { | ||
| 2002 | snd_printdd("CXT5066: external microphone absent\n"); | 2111 | snd_printdd("CXT5066: external microphone absent\n"); |
| 2003 | snd_hda_sequence_write(codec, ext_mic_absent); | 2112 | |
| 2004 | } | 2113 | snd_hda_codec_write(codec, 0x17, 0, AC_VERB_SET_CONNECT_SEL, |
| 2114 | present ? 0 : 1); | ||
| 2115 | spec->ext_mic_present = !!present; | ||
| 2116 | |||
| 2117 | cxt5066_olpc_select_mic(codec); | ||
| 2005 | } | 2118 | } |
| 2006 | 2119 | ||
| 2007 | /* toggle input of built-in digital mic and mic jack appropriately */ | 2120 | /* toggle input of built-in digital mic and mic jack appropriately */ |
| 2008 | static void cxt5066_vostro_automic(struct hda_codec *codec) | 2121 | static void cxt5066_vostro_automic(struct hda_codec *codec) |
| 2009 | { | 2122 | { |
| 2010 | struct conexant_spec *spec = codec->spec; | ||
| 2011 | unsigned int present; | 2123 | unsigned int present; |
| 2012 | 2124 | ||
| 2013 | struct hda_verb ext_mic_present[] = { | 2125 | struct hda_verb ext_mic_present[] = { |
| 2014 | /* enable external mic, port B */ | 2126 | /* enable external mic, port B */ |
| 2015 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, spec->ext_mic_bias}, | 2127 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
| 2016 | 2128 | ||
| 2017 | /* switch to external mic input */ | 2129 | /* switch to external mic input */ |
| 2018 | {0x17, AC_VERB_SET_CONNECT_SEL, 0}, | 2130 | {0x17, AC_VERB_SET_CONNECT_SEL, 0}, |
| @@ -2063,15 +2175,18 @@ static void cxt5066_hp_automute(struct hda_codec *codec) | |||
| 2063 | } | 2175 | } |
| 2064 | 2176 | ||
| 2065 | /* unsolicited event for jack sensing */ | 2177 | /* unsolicited event for jack sensing */ |
| 2066 | static void cxt5066_unsol_event(struct hda_codec *codec, unsigned int res) | 2178 | static void cxt5066_olpc_unsol_event(struct hda_codec *codec, unsigned int res) |
| 2067 | { | 2179 | { |
| 2180 | struct conexant_spec *spec = codec->spec; | ||
| 2068 | snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26); | 2181 | snd_printdd("CXT5066: unsol event %x (%x)\n", res, res >> 26); |
| 2069 | switch (res >> 26) { | 2182 | switch (res >> 26) { |
| 2070 | case CONEXANT_HP_EVENT: | 2183 | case CONEXANT_HP_EVENT: |
| 2071 | cxt5066_hp_automute(codec); | 2184 | cxt5066_hp_automute(codec); |
| 2072 | break; | 2185 | break; |
| 2073 | case CONEXANT_MIC_EVENT: | 2186 | case CONEXANT_MIC_EVENT: |
| 2074 | cxt5066_automic(codec); | 2187 | /* ignore mic events in DC mode; we're always using the jack */ |
| 2188 | if (!spec->dc_enable) | ||
| 2189 | cxt5066_olpc_automic(codec); | ||
| 2075 | break; | 2190 | break; |
| 2076 | } | 2191 | } |
| 2077 | } | 2192 | } |
| @@ -2101,6 +2216,15 @@ static const struct hda_input_mux cxt5066_analog_mic_boost = { | |||
| 2101 | }, | 2216 | }, |
| 2102 | }; | 2217 | }; |
| 2103 | 2218 | ||
| 2219 | static int cxt5066_set_mic_boost(struct hda_codec *codec) | ||
| 2220 | { | ||
| 2221 | struct conexant_spec *spec = codec->spec; | ||
| 2222 | return snd_hda_codec_write_cache(codec, 0x17, 0, | ||
| 2223 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
| 2224 | AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | AC_AMP_SET_OUTPUT | | ||
| 2225 | cxt5066_analog_mic_boost.items[spec->mic_boost].index); | ||
| 2226 | } | ||
| 2227 | |||
| 2104 | static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol, | 2228 | static int cxt5066_mic_boost_mux_enum_info(struct snd_kcontrol *kcontrol, |
| 2105 | struct snd_ctl_elem_info *uinfo) | 2229 | struct snd_ctl_elem_info *uinfo) |
| 2106 | { | 2230 | { |
| @@ -2111,15 +2235,8 @@ static int cxt5066_mic_boost_mux_enum_get(struct snd_kcontrol *kcontrol, | |||
| 2111 | struct snd_ctl_elem_value *ucontrol) | 2235 | struct snd_ctl_elem_value *ucontrol) |
| 2112 | { | 2236 | { |
| 2113 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 2237 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
| 2114 | int val; | 2238 | struct conexant_spec *spec = codec->spec; |
| 2115 | hda_nid_t nid = kcontrol->private_value & 0xff; | 2239 | ucontrol->value.enumerated.item[0] = spec->mic_boost; |
| 2116 | int inout = (kcontrol->private_value & 0x100) ? | ||
| 2117 | AC_AMP_GET_INPUT : AC_AMP_GET_OUTPUT; | ||
| 2118 | |||
| 2119 | val = snd_hda_codec_read(codec, nid, 0, | ||
| 2120 | AC_VERB_GET_AMP_GAIN_MUTE, inout); | ||
| 2121 | |||
| 2122 | ucontrol->value.enumerated.item[0] = val & AC_AMP_GAIN; | ||
| 2123 | return 0; | 2240 | return 0; |
| 2124 | } | 2241 | } |
| 2125 | 2242 | ||
| @@ -2127,26 +2244,132 @@ static int cxt5066_mic_boost_mux_enum_put(struct snd_kcontrol *kcontrol, | |||
| 2127 | struct snd_ctl_elem_value *ucontrol) | 2244 | struct snd_ctl_elem_value *ucontrol) |
| 2128 | { | 2245 | { |
| 2129 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 2246 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
| 2247 | struct conexant_spec *spec = codec->spec; | ||
| 2130 | const struct hda_input_mux *imux = &cxt5066_analog_mic_boost; | 2248 | const struct hda_input_mux *imux = &cxt5066_analog_mic_boost; |
| 2131 | unsigned int idx; | 2249 | unsigned int idx; |
| 2132 | hda_nid_t nid = kcontrol->private_value & 0xff; | 2250 | idx = ucontrol->value.enumerated.item[0]; |
| 2133 | int inout = (kcontrol->private_value & 0x100) ? | 2251 | if (idx >= imux->num_items) |
| 2134 | AC_AMP_SET_INPUT : AC_AMP_SET_OUTPUT; | 2252 | idx = imux->num_items - 1; |
| 2253 | |||
| 2254 | spec->mic_boost = idx; | ||
| 2255 | if (!spec->dc_enable) | ||
| 2256 | cxt5066_set_mic_boost(codec); | ||
| 2257 | return 1; | ||
| 2258 | } | ||
| 2259 | |||
| 2260 | static void cxt5066_enable_dc(struct hda_codec *codec) | ||
| 2261 | { | ||
| 2262 | const struct hda_verb enable_dc_mode[] = { | ||
| 2263 | /* disable gain */ | ||
| 2264 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
| 2265 | |||
| 2266 | /* switch to DC input */ | ||
| 2267 | {0x17, AC_VERB_SET_CONNECT_SEL, 3}, | ||
| 2268 | {} | ||
| 2269 | }; | ||
| 2270 | |||
| 2271 | /* configure as input source */ | ||
| 2272 | snd_hda_sequence_write(codec, enable_dc_mode); | ||
| 2273 | cxt5066_olpc_select_mic(codec); /* also sets configured bias */ | ||
| 2274 | } | ||
| 2275 | |||
| 2276 | static void cxt5066_disable_dc(struct hda_codec *codec) | ||
| 2277 | { | ||
| 2278 | /* reconfigure input source */ | ||
| 2279 | cxt5066_set_mic_boost(codec); | ||
| 2280 | /* automic also selects the right mic if we're recording */ | ||
| 2281 | cxt5066_olpc_automic(codec); | ||
| 2282 | } | ||
| 2283 | |||
| 2284 | static int cxt5066_olpc_dc_get(struct snd_kcontrol *kcontrol, | ||
| 2285 | struct snd_ctl_elem_value *ucontrol) | ||
| 2286 | { | ||
| 2287 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
| 2288 | struct conexant_spec *spec = codec->spec; | ||
| 2289 | ucontrol->value.integer.value[0] = spec->dc_enable; | ||
| 2290 | return 0; | ||
| 2291 | } | ||
| 2292 | |||
| 2293 | static int cxt5066_olpc_dc_put(struct snd_kcontrol *kcontrol, | ||
| 2294 | struct snd_ctl_elem_value *ucontrol) | ||
| 2295 | { | ||
| 2296 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
| 2297 | struct conexant_spec *spec = codec->spec; | ||
| 2298 | int dc_enable = !!ucontrol->value.integer.value[0]; | ||
| 2135 | 2299 | ||
| 2136 | if (!imux->num_items) | 2300 | if (dc_enable == spec->dc_enable) |
| 2137 | return 0; | 2301 | return 0; |
| 2302 | |||
| 2303 | spec->dc_enable = dc_enable; | ||
| 2304 | if (dc_enable) | ||
| 2305 | cxt5066_enable_dc(codec); | ||
| 2306 | else | ||
| 2307 | cxt5066_disable_dc(codec); | ||
| 2308 | |||
| 2309 | return 1; | ||
| 2310 | } | ||
| 2311 | |||
| 2312 | static int cxt5066_olpc_dc_bias_enum_info(struct snd_kcontrol *kcontrol, | ||
| 2313 | struct snd_ctl_elem_info *uinfo) | ||
| 2314 | { | ||
| 2315 | return snd_hda_input_mux_info(&cxt5066_olpc_dc_bias, uinfo); | ||
| 2316 | } | ||
| 2317 | |||
| 2318 | static int cxt5066_olpc_dc_bias_enum_get(struct snd_kcontrol *kcontrol, | ||
| 2319 | struct snd_ctl_elem_value *ucontrol) | ||
| 2320 | { | ||
| 2321 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
| 2322 | struct conexant_spec *spec = codec->spec; | ||
| 2323 | ucontrol->value.enumerated.item[0] = spec->dc_input_bias; | ||
| 2324 | return 0; | ||
| 2325 | } | ||
| 2326 | |||
| 2327 | static int cxt5066_olpc_dc_bias_enum_put(struct snd_kcontrol *kcontrol, | ||
| 2328 | struct snd_ctl_elem_value *ucontrol) | ||
| 2329 | { | ||
| 2330 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
| 2331 | struct conexant_spec *spec = codec->spec; | ||
| 2332 | const struct hda_input_mux *imux = &cxt5066_analog_mic_boost; | ||
| 2333 | unsigned int idx; | ||
| 2334 | |||
| 2138 | idx = ucontrol->value.enumerated.item[0]; | 2335 | idx = ucontrol->value.enumerated.item[0]; |
| 2139 | if (idx >= imux->num_items) | 2336 | if (idx >= imux->num_items) |
| 2140 | idx = imux->num_items - 1; | 2337 | idx = imux->num_items - 1; |
| 2141 | 2338 | ||
| 2142 | snd_hda_codec_write_cache(codec, nid, 0, | 2339 | spec->dc_input_bias = idx; |
| 2143 | AC_VERB_SET_AMP_GAIN_MUTE, | 2340 | if (spec->dc_enable) |
| 2144 | AC_AMP_SET_RIGHT | AC_AMP_SET_LEFT | inout | | 2341 | cxt5066_set_olpc_dc_bias(codec); |
| 2145 | imux->items[idx].index); | ||
| 2146 | |||
| 2147 | return 1; | 2342 | return 1; |
| 2148 | } | 2343 | } |
| 2149 | 2344 | ||
| 2345 | static void cxt5066_olpc_capture_prepare(struct hda_codec *codec) | ||
| 2346 | { | ||
| 2347 | struct conexant_spec *spec = codec->spec; | ||
| 2348 | /* mark as recording and configure the microphone widget so that the | ||
| 2349 | * recording LED comes on. */ | ||
| 2350 | spec->recording = 1; | ||
| 2351 | cxt5066_olpc_select_mic(codec); | ||
| 2352 | } | ||
| 2353 | |||
| 2354 | static void cxt5066_olpc_capture_cleanup(struct hda_codec *codec) | ||
| 2355 | { | ||
| 2356 | struct conexant_spec *spec = codec->spec; | ||
| 2357 | const struct hda_verb disable_mics[] = { | ||
| 2358 | /* disable external mic, port B */ | ||
| 2359 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
| 2360 | |||
| 2361 | /* disble internal mic, port C */ | ||
| 2362 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
| 2363 | |||
| 2364 | /* disable DC capture, port F */ | ||
| 2365 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | ||
| 2366 | {}, | ||
| 2367 | }; | ||
| 2368 | |||
| 2369 | snd_hda_sequence_write(codec, disable_mics); | ||
| 2370 | spec->recording = 0; | ||
| 2371 | } | ||
| 2372 | |||
| 2150 | static struct hda_input_mux cxt5066_capture_source = { | 2373 | static struct hda_input_mux cxt5066_capture_source = { |
| 2151 | .num_items = 4, | 2374 | .num_items = 4, |
| 2152 | .items = { | 2375 | .items = { |
| @@ -2187,6 +2410,7 @@ static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = { | |||
| 2187 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | 2410 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | |
| 2188 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | | 2411 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | |
| 2189 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, | 2412 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, |
| 2413 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
| 2190 | .info = snd_hda_mixer_amp_volume_info, | 2414 | .info = snd_hda_mixer_amp_volume_info, |
| 2191 | .get = snd_hda_mixer_amp_volume_get, | 2415 | .get = snd_hda_mixer_amp_volume_get, |
| 2192 | .put = snd_hda_mixer_amp_volume_put, | 2416 | .put = snd_hda_mixer_amp_volume_put, |
| @@ -2198,6 +2422,24 @@ static struct snd_kcontrol_new cxt5066_mixer_master_olpc[] = { | |||
| 2198 | {} | 2422 | {} |
| 2199 | }; | 2423 | }; |
| 2200 | 2424 | ||
| 2425 | static struct snd_kcontrol_new cxt5066_mixer_olpc_dc[] = { | ||
| 2426 | { | ||
| 2427 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 2428 | .name = "DC Mode Enable Switch", | ||
| 2429 | .info = snd_ctl_boolean_mono_info, | ||
| 2430 | .get = cxt5066_olpc_dc_get, | ||
| 2431 | .put = cxt5066_olpc_dc_put, | ||
| 2432 | }, | ||
| 2433 | { | ||
| 2434 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 2435 | .name = "DC Input Bias Enum", | ||
| 2436 | .info = cxt5066_olpc_dc_bias_enum_info, | ||
| 2437 | .get = cxt5066_olpc_dc_bias_enum_get, | ||
| 2438 | .put = cxt5066_olpc_dc_bias_enum_put, | ||
| 2439 | }, | ||
| 2440 | {} | ||
| 2441 | }; | ||
| 2442 | |||
| 2201 | static struct snd_kcontrol_new cxt5066_mixers[] = { | 2443 | static struct snd_kcontrol_new cxt5066_mixers[] = { |
| 2202 | { | 2444 | { |
| 2203 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2445 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| @@ -2210,11 +2452,10 @@ static struct snd_kcontrol_new cxt5066_mixers[] = { | |||
| 2210 | 2452 | ||
| 2211 | { | 2453 | { |
| 2212 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2454 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 2213 | .name = "Ext Mic Boost Capture Enum", | 2455 | .name = "Analog Mic Boost Capture Enum", |
| 2214 | .info = cxt5066_mic_boost_mux_enum_info, | 2456 | .info = cxt5066_mic_boost_mux_enum_info, |
| 2215 | .get = cxt5066_mic_boost_mux_enum_get, | 2457 | .get = cxt5066_mic_boost_mux_enum_get, |
| 2216 | .put = cxt5066_mic_boost_mux_enum_put, | 2458 | .put = cxt5066_mic_boost_mux_enum_put, |
| 2217 | .private_value = 0x17, | ||
| 2218 | }, | 2459 | }, |
| 2219 | 2460 | ||
| 2220 | HDA_BIND_VOL("Capture Volume", &cxt5066_bind_capture_vol_others), | 2461 | HDA_BIND_VOL("Capture Volume", &cxt5066_bind_capture_vol_others), |
| @@ -2296,10 +2537,10 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = { | |||
| 2296 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ | 2537 | {0x19, AC_VERB_SET_CONNECT_SEL, 0x00}, /* DAC1 */ |
| 2297 | 2538 | ||
| 2298 | /* Port B: external microphone */ | 2539 | /* Port B: external microphone */ |
| 2299 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, CXT5066_OLPC_EXT_MIC_BIAS}, | 2540 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
| 2300 | 2541 | ||
| 2301 | /* Port C: internal microphone */ | 2542 | /* Port C: internal microphone */ |
| 2302 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 2543 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
| 2303 | 2544 | ||
| 2304 | /* Port D: unused */ | 2545 | /* Port D: unused */ |
| 2305 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2546 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
| @@ -2308,7 +2549,7 @@ static struct hda_verb cxt5066_init_verbs_olpc[] = { | |||
| 2308 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2549 | {0x1d, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
| 2309 | {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ | 2550 | {0x1d, AC_VERB_SET_EAPD_BTLENABLE, 0x2}, /* default on */ |
| 2310 | 2551 | ||
| 2311 | /* Port F: unused */ | 2552 | /* Port F: external DC input through microphone port */ |
| 2312 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, | 2553 | {0x1e, AC_VERB_SET_PIN_WIDGET_CONTROL, 0}, |
| 2313 | 2554 | ||
| 2314 | /* Port G: internal speakers */ | 2555 | /* Port G: internal speakers */ |
| @@ -2428,8 +2669,22 @@ static int cxt5066_init(struct hda_codec *codec) | |||
| 2428 | cxt5066_hp_automute(codec); | 2669 | cxt5066_hp_automute(codec); |
| 2429 | if (spec->dell_vostro) | 2670 | if (spec->dell_vostro) |
| 2430 | cxt5066_vostro_automic(codec); | 2671 | cxt5066_vostro_automic(codec); |
| 2431 | else | 2672 | } |
| 2432 | cxt5066_automic(codec); | 2673 | cxt5066_set_mic_boost(codec); |
| 2674 | return 0; | ||
| 2675 | } | ||
| 2676 | |||
| 2677 | static int cxt5066_olpc_init(struct hda_codec *codec) | ||
| 2678 | { | ||
| 2679 | struct conexant_spec *spec = codec->spec; | ||
| 2680 | snd_printdd("CXT5066: init\n"); | ||
| 2681 | conexant_init(codec); | ||
| 2682 | cxt5066_hp_automute(codec); | ||
| 2683 | if (!spec->dc_enable) { | ||
| 2684 | cxt5066_set_mic_boost(codec); | ||
| 2685 | cxt5066_olpc_automic(codec); | ||
| 2686 | } else { | ||
| 2687 | cxt5066_enable_dc(codec); | ||
| 2433 | } | 2688 | } |
| 2434 | return 0; | 2689 | return 0; |
| 2435 | } | 2690 | } |
| @@ -2470,7 +2725,7 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
| 2470 | codec->spec = spec; | 2725 | codec->spec = spec; |
| 2471 | 2726 | ||
| 2472 | codec->patch_ops = conexant_patch_ops; | 2727 | codec->patch_ops = conexant_patch_ops; |
| 2473 | codec->patch_ops.init = cxt5066_init; | 2728 | codec->patch_ops.init = conexant_init; |
| 2474 | 2729 | ||
| 2475 | spec->dell_automute = 0; | 2730 | spec->dell_automute = 0; |
| 2476 | spec->multiout.max_channels = 2; | 2731 | spec->multiout.max_channels = 2; |
| @@ -2483,7 +2738,6 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
| 2483 | spec->input_mux = &cxt5066_capture_source; | 2738 | spec->input_mux = &cxt5066_capture_source; |
| 2484 | 2739 | ||
| 2485 | spec->port_d_mode = PIN_HP; | 2740 | spec->port_d_mode = PIN_HP; |
| 2486 | spec->ext_mic_bias = PIN_VREF80; | ||
| 2487 | 2741 | ||
| 2488 | spec->num_init_verbs = 1; | 2742 | spec->num_init_verbs = 1; |
| 2489 | spec->init_verbs[0] = cxt5066_init_verbs; | 2743 | spec->init_verbs[0] = cxt5066_init_verbs; |
| @@ -2510,20 +2764,28 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
| 2510 | spec->dell_automute = 1; | 2764 | spec->dell_automute = 1; |
| 2511 | break; | 2765 | break; |
| 2512 | case CXT5066_OLPC_XO_1_5: | 2766 | case CXT5066_OLPC_XO_1_5: |
| 2513 | codec->patch_ops.unsol_event = cxt5066_unsol_event; | 2767 | codec->patch_ops.init = cxt5066_olpc_init; |
| 2768 | codec->patch_ops.unsol_event = cxt5066_olpc_unsol_event; | ||
| 2514 | spec->init_verbs[0] = cxt5066_init_verbs_olpc; | 2769 | spec->init_verbs[0] = cxt5066_init_verbs_olpc; |
| 2515 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; | 2770 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; |
| 2771 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_olpc_dc; | ||
| 2516 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; | 2772 | spec->mixers[spec->num_mixers++] = cxt5066_mixers; |
| 2517 | spec->port_d_mode = 0; | 2773 | spec->port_d_mode = 0; |
| 2518 | spec->ext_mic_bias = CXT5066_OLPC_EXT_MIC_BIAS; | 2774 | spec->mic_boost = 3; /* default 30dB gain */ |
| 2519 | 2775 | ||
| 2520 | /* no S/PDIF out */ | 2776 | /* no S/PDIF out */ |
| 2521 | spec->multiout.dig_out_nid = 0; | 2777 | spec->multiout.dig_out_nid = 0; |
| 2522 | 2778 | ||
| 2523 | /* input source automatically selected */ | 2779 | /* input source automatically selected */ |
| 2524 | spec->input_mux = NULL; | 2780 | spec->input_mux = NULL; |
| 2781 | |||
| 2782 | /* our capture hooks which allow us to turn on the microphone LED | ||
| 2783 | * at the right time */ | ||
| 2784 | spec->capture_prepare = cxt5066_olpc_capture_prepare; | ||
| 2785 | spec->capture_cleanup = cxt5066_olpc_capture_cleanup; | ||
| 2525 | break; | 2786 | break; |
| 2526 | case CXT5066_DELL_VOSTO: | 2787 | case CXT5066_DELL_VOSTO: |
| 2788 | codec->patch_ops.init = cxt5066_init; | ||
| 2527 | codec->patch_ops.unsol_event = cxt5066_vostro_event; | 2789 | codec->patch_ops.unsol_event = cxt5066_vostro_event; |
| 2528 | spec->init_verbs[0] = cxt5066_init_verbs_vostro; | 2790 | spec->init_verbs[0] = cxt5066_init_verbs_vostro; |
| 2529 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; | 2791 | spec->mixers[spec->num_mixers++] = cxt5066_mixer_master_olpc; |
| @@ -2531,6 +2793,7 @@ static int patch_cxt5066(struct hda_codec *codec) | |||
| 2531 | spec->mixers[spec->num_mixers++] = cxt5066_vostro_mixers; | 2793 | spec->mixers[spec->num_mixers++] = cxt5066_vostro_mixers; |
| 2532 | spec->port_d_mode = 0; | 2794 | spec->port_d_mode = 0; |
| 2533 | spec->dell_vostro = 1; | 2795 | spec->dell_vostro = 1; |
| 2796 | spec->mic_boost = 3; /* default 30dB gain */ | ||
| 2534 | snd_hda_attach_beep_device(codec, 0x13); | 2797 | snd_hda_attach_beep_device(codec, 0x13); |
| 2535 | 2798 | ||
| 2536 | /* no S/PDIF out */ | 2799 | /* no S/PDIF out */ |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index da34095c707f..f628c33d80b3 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
| @@ -338,7 +338,7 @@ struct alc_spec { | |||
| 338 | void (*init_hook)(struct hda_codec *codec); | 338 | void (*init_hook)(struct hda_codec *codec); |
| 339 | void (*unsol_event)(struct hda_codec *codec, unsigned int res); | 339 | void (*unsol_event)(struct hda_codec *codec, unsigned int res); |
| 340 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 340 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
| 341 | void (*power_hook)(struct hda_codec *codec, int power); | 341 | void (*power_hook)(struct hda_codec *codec); |
| 342 | #endif | 342 | #endif |
| 343 | 343 | ||
| 344 | /* for pin sensing */ | 344 | /* for pin sensing */ |
| @@ -391,7 +391,7 @@ struct alc_config_preset { | |||
| 391 | void (*init_hook)(struct hda_codec *); | 391 | void (*init_hook)(struct hda_codec *); |
| 392 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 392 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
| 393 | struct hda_amp_list *loopbacks; | 393 | struct hda_amp_list *loopbacks; |
| 394 | void (*power_hook)(struct hda_codec *codec, int power); | 394 | void (*power_hook)(struct hda_codec *codec); |
| 395 | #endif | 395 | #endif |
| 396 | }; | 396 | }; |
| 397 | 397 | ||
| @@ -633,6 +633,7 @@ static int alc_pin_mode_put(struct snd_kcontrol *kcontrol, | |||
| 633 | 633 | ||
| 634 | #define ALC_PIN_MODE(xname, nid, dir) \ | 634 | #define ALC_PIN_MODE(xname, nid, dir) \ |
| 635 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ | 635 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ |
| 636 | .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ | ||
| 636 | .info = alc_pin_mode_info, \ | 637 | .info = alc_pin_mode_info, \ |
| 637 | .get = alc_pin_mode_get, \ | 638 | .get = alc_pin_mode_get, \ |
| 638 | .put = alc_pin_mode_put, \ | 639 | .put = alc_pin_mode_put, \ |
| @@ -684,6 +685,7 @@ static int alc_gpio_data_put(struct snd_kcontrol *kcontrol, | |||
| 684 | } | 685 | } |
| 685 | #define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \ | 686 | #define ALC_GPIO_DATA_SWITCH(xname, nid, mask) \ |
| 686 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ | 687 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ |
| 688 | .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ | ||
| 687 | .info = alc_gpio_data_info, \ | 689 | .info = alc_gpio_data_info, \ |
| 688 | .get = alc_gpio_data_get, \ | 690 | .get = alc_gpio_data_get, \ |
| 689 | .put = alc_gpio_data_put, \ | 691 | .put = alc_gpio_data_put, \ |
| @@ -738,6 +740,7 @@ static int alc_spdif_ctrl_put(struct snd_kcontrol *kcontrol, | |||
| 738 | } | 740 | } |
| 739 | #define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \ | 741 | #define ALC_SPDIF_CTRL_SWITCH(xname, nid, mask) \ |
| 740 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ | 742 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ |
| 743 | .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ | ||
| 741 | .info = alc_spdif_ctrl_info, \ | 744 | .info = alc_spdif_ctrl_info, \ |
| 742 | .get = alc_spdif_ctrl_get, \ | 745 | .get = alc_spdif_ctrl_get, \ |
| 743 | .put = alc_spdif_ctrl_put, \ | 746 | .put = alc_spdif_ctrl_put, \ |
| @@ -791,6 +794,7 @@ static int alc_eapd_ctrl_put(struct snd_kcontrol *kcontrol, | |||
| 791 | 794 | ||
| 792 | #define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \ | 795 | #define ALC_EAPD_CTRL_SWITCH(xname, nid, mask) \ |
| 793 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ | 796 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = 0, \ |
| 797 | .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ | ||
| 794 | .info = alc_eapd_ctrl_info, \ | 798 | .info = alc_eapd_ctrl_info, \ |
| 795 | .get = alc_eapd_ctrl_get, \ | 799 | .get = alc_eapd_ctrl_get, \ |
| 796 | .put = alc_eapd_ctrl_put, \ | 800 | .put = alc_eapd_ctrl_put, \ |
| @@ -1840,14 +1844,6 @@ static void alc889_acer_aspire_8930g_setup(struct hda_codec *codec) | |||
| 1840 | spec->autocfg.speaker_pins[2] = 0x1b; | 1844 | spec->autocfg.speaker_pins[2] = 0x1b; |
| 1841 | } | 1845 | } |
| 1842 | 1846 | ||
| 1843 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
| 1844 | static void alc889_power_eapd(struct hda_codec *codec, int power) | ||
| 1845 | { | ||
| 1846 | set_eapd(codec, 0x14, power); | ||
| 1847 | set_eapd(codec, 0x15, power); | ||
| 1848 | } | ||
| 1849 | #endif | ||
| 1850 | |||
| 1851 | /* | 1847 | /* |
| 1852 | * ALC880 3-stack model | 1848 | * ALC880 3-stack model |
| 1853 | * | 1849 | * |
| @@ -2450,6 +2446,15 @@ static const char *alc_slave_sws[] = { | |||
| 2450 | * build control elements | 2446 | * build control elements |
| 2451 | */ | 2447 | */ |
| 2452 | 2448 | ||
| 2449 | #define NID_MAPPING (-1) | ||
| 2450 | |||
| 2451 | #define SUBDEV_SPEAKER_ (0 << 6) | ||
| 2452 | #define SUBDEV_HP_ (1 << 6) | ||
| 2453 | #define SUBDEV_LINE_ (2 << 6) | ||
| 2454 | #define SUBDEV_SPEAKER(x) (SUBDEV_SPEAKER_ | ((x) & 0x3f)) | ||
| 2455 | #define SUBDEV_HP(x) (SUBDEV_HP_ | ((x) & 0x3f)) | ||
| 2456 | #define SUBDEV_LINE(x) (SUBDEV_LINE_ | ((x) & 0x3f)) | ||
| 2457 | |||
| 2453 | static void alc_free_kctls(struct hda_codec *codec); | 2458 | static void alc_free_kctls(struct hda_codec *codec); |
| 2454 | 2459 | ||
| 2455 | #ifdef CONFIG_SND_HDA_INPUT_BEEP | 2460 | #ifdef CONFIG_SND_HDA_INPUT_BEEP |
| @@ -2464,8 +2469,11 @@ static struct snd_kcontrol_new alc_beep_mixer[] = { | |||
| 2464 | static int alc_build_controls(struct hda_codec *codec) | 2469 | static int alc_build_controls(struct hda_codec *codec) |
| 2465 | { | 2470 | { |
| 2466 | struct alc_spec *spec = codec->spec; | 2471 | struct alc_spec *spec = codec->spec; |
| 2467 | int err; | 2472 | struct snd_kcontrol *kctl; |
| 2468 | int i; | 2473 | struct snd_kcontrol_new *knew; |
| 2474 | int i, j, err; | ||
| 2475 | unsigned int u; | ||
| 2476 | hda_nid_t nid; | ||
| 2469 | 2477 | ||
| 2470 | for (i = 0; i < spec->num_mixers; i++) { | 2478 | for (i = 0; i < spec->num_mixers; i++) { |
| 2471 | err = snd_hda_add_new_ctls(codec, spec->mixers[i]); | 2479 | err = snd_hda_add_new_ctls(codec, spec->mixers[i]); |
| @@ -2506,8 +2514,7 @@ static int alc_build_controls(struct hda_codec *codec) | |||
| 2506 | if (!kctl) | 2514 | if (!kctl) |
| 2507 | return -ENOMEM; | 2515 | return -ENOMEM; |
| 2508 | kctl->private_value = spec->beep_amp; | 2516 | kctl->private_value = spec->beep_amp; |
| 2509 | err = snd_hda_ctl_add(codec, | 2517 | err = snd_hda_ctl_add(codec, 0, kctl); |
| 2510 | get_amp_nid_(spec->beep_amp), kctl); | ||
| 2511 | if (err < 0) | 2518 | if (err < 0) |
| 2512 | return err; | 2519 | return err; |
| 2513 | } | 2520 | } |
| @@ -2534,6 +2541,75 @@ static int alc_build_controls(struct hda_codec *codec) | |||
| 2534 | } | 2541 | } |
| 2535 | 2542 | ||
| 2536 | alc_free_kctls(codec); /* no longer needed */ | 2543 | alc_free_kctls(codec); /* no longer needed */ |
| 2544 | |||
| 2545 | /* assign Capture Source enums to NID */ | ||
| 2546 | kctl = snd_hda_find_mixer_ctl(codec, "Capture Source"); | ||
| 2547 | if (!kctl) | ||
| 2548 | kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); | ||
| 2549 | for (i = 0; kctl && i < kctl->count; i++) { | ||
| 2550 | hda_nid_t *nids = spec->capsrc_nids; | ||
| 2551 | if (!nids) | ||
| 2552 | nids = spec->adc_nids; | ||
| 2553 | err = snd_hda_add_nid(codec, kctl, i, nids[i]); | ||
| 2554 | if (err < 0) | ||
| 2555 | return err; | ||
| 2556 | } | ||
| 2557 | if (spec->cap_mixer) { | ||
| 2558 | const char *kname = kctl ? kctl->id.name : NULL; | ||
| 2559 | for (knew = spec->cap_mixer; knew->name; knew++) { | ||
| 2560 | if (kname && strcmp(knew->name, kname) == 0) | ||
| 2561 | continue; | ||
| 2562 | kctl = snd_hda_find_mixer_ctl(codec, knew->name); | ||
| 2563 | for (i = 0; kctl && i < kctl->count; i++) { | ||
| 2564 | err = snd_hda_add_nid(codec, kctl, i, | ||
| 2565 | spec->adc_nids[i]); | ||
| 2566 | if (err < 0) | ||
| 2567 | return err; | ||
| 2568 | } | ||
| 2569 | } | ||
| 2570 | } | ||
| 2571 | |||
| 2572 | /* other nid->control mapping */ | ||
| 2573 | for (i = 0; i < spec->num_mixers; i++) { | ||
| 2574 | for (knew = spec->mixers[i]; knew->name; knew++) { | ||
| 2575 | if (knew->iface != NID_MAPPING) | ||
| 2576 | continue; | ||
| 2577 | kctl = snd_hda_find_mixer_ctl(codec, knew->name); | ||
| 2578 | if (kctl == NULL) | ||
| 2579 | continue; | ||
| 2580 | u = knew->subdevice; | ||
| 2581 | for (j = 0; j < 4; j++, u >>= 8) { | ||
| 2582 | nid = u & 0x3f; | ||
| 2583 | if (nid == 0) | ||
| 2584 | continue; | ||
| 2585 | switch (u & 0xc0) { | ||
| 2586 | case SUBDEV_SPEAKER_: | ||
| 2587 | nid = spec->autocfg.speaker_pins[nid]; | ||
| 2588 | break; | ||
| 2589 | case SUBDEV_LINE_: | ||
| 2590 | nid = spec->autocfg.line_out_pins[nid]; | ||
| 2591 | break; | ||
| 2592 | case SUBDEV_HP_: | ||
| 2593 | nid = spec->autocfg.hp_pins[nid]; | ||
| 2594 | break; | ||
| 2595 | default: | ||
| 2596 | continue; | ||
| 2597 | } | ||
| 2598 | err = snd_hda_add_nid(codec, kctl, 0, nid); | ||
| 2599 | if (err < 0) | ||
| 2600 | return err; | ||
| 2601 | } | ||
| 2602 | u = knew->private_value; | ||
| 2603 | for (j = 0; j < 4; j++, u >>= 8) { | ||
| 2604 | nid = u & 0xff; | ||
| 2605 | if (nid == 0) | ||
| 2606 | continue; | ||
| 2607 | err = snd_hda_add_nid(codec, kctl, 0, nid); | ||
| 2608 | if (err < 0) | ||
| 2609 | return err; | ||
| 2610 | } | ||
| 2611 | } | ||
| 2612 | } | ||
| 2537 | return 0; | 2613 | return 0; |
| 2538 | } | 2614 | } |
| 2539 | 2615 | ||
| @@ -3616,6 +3692,11 @@ static int alc_build_pcms(struct hda_codec *codec) | |||
| 3616 | return 0; | 3692 | return 0; |
| 3617 | } | 3693 | } |
| 3618 | 3694 | ||
| 3695 | static inline void alc_shutup(struct hda_codec *codec) | ||
| 3696 | { | ||
| 3697 | snd_hda_shutup_pins(codec); | ||
| 3698 | } | ||
| 3699 | |||
| 3619 | static void alc_free_kctls(struct hda_codec *codec) | 3700 | static void alc_free_kctls(struct hda_codec *codec) |
| 3620 | { | 3701 | { |
| 3621 | struct alc_spec *spec = codec->spec; | 3702 | struct alc_spec *spec = codec->spec; |
| @@ -3636,17 +3717,47 @@ static void alc_free(struct hda_codec *codec) | |||
| 3636 | if (!spec) | 3717 | if (!spec) |
| 3637 | return; | 3718 | return; |
| 3638 | 3719 | ||
| 3720 | alc_shutup(codec); | ||
| 3639 | alc_free_kctls(codec); | 3721 | alc_free_kctls(codec); |
| 3640 | kfree(spec); | 3722 | kfree(spec); |
| 3641 | snd_hda_detach_beep_device(codec); | 3723 | snd_hda_detach_beep_device(codec); |
| 3642 | } | 3724 | } |
| 3643 | 3725 | ||
| 3644 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 3726 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
| 3727 | static void alc_power_eapd(struct hda_codec *codec) | ||
| 3728 | { | ||
| 3729 | /* We currently only handle front, HP */ | ||
| 3730 | switch (codec->vendor_id) { | ||
| 3731 | case 0x10ec0260: | ||
| 3732 | snd_hda_codec_write(codec, 0x0f, 0, | ||
| 3733 | AC_VERB_SET_EAPD_BTLENABLE, 0x00); | ||
| 3734 | snd_hda_codec_write(codec, 0x10, 0, | ||
| 3735 | AC_VERB_SET_EAPD_BTLENABLE, 0x00); | ||
| 3736 | break; | ||
| 3737 | case 0x10ec0262: | ||
| 3738 | case 0x10ec0267: | ||
| 3739 | case 0x10ec0268: | ||
| 3740 | case 0x10ec0269: | ||
| 3741 | case 0x10ec0272: | ||
| 3742 | case 0x10ec0660: | ||
| 3743 | case 0x10ec0662: | ||
| 3744 | case 0x10ec0663: | ||
| 3745 | case 0x10ec0862: | ||
| 3746 | case 0x10ec0889: | ||
| 3747 | snd_hda_codec_write(codec, 0x14, 0, | ||
| 3748 | AC_VERB_SET_EAPD_BTLENABLE, 0x00); | ||
| 3749 | snd_hda_codec_write(codec, 0x15, 0, | ||
| 3750 | AC_VERB_SET_EAPD_BTLENABLE, 0x00); | ||
| 3751 | break; | ||
| 3752 | } | ||
| 3753 | } | ||
| 3754 | |||
| 3645 | static int alc_suspend(struct hda_codec *codec, pm_message_t state) | 3755 | static int alc_suspend(struct hda_codec *codec, pm_message_t state) |
| 3646 | { | 3756 | { |
| 3647 | struct alc_spec *spec = codec->spec; | 3757 | struct alc_spec *spec = codec->spec; |
| 3758 | alc_shutup(codec); | ||
| 3648 | if (spec && spec->power_hook) | 3759 | if (spec && spec->power_hook) |
| 3649 | spec->power_hook(codec, 0); | 3760 | spec->power_hook(codec); |
| 3650 | return 0; | 3761 | return 0; |
| 3651 | } | 3762 | } |
| 3652 | #endif | 3763 | #endif |
| @@ -3654,16 +3765,9 @@ static int alc_suspend(struct hda_codec *codec, pm_message_t state) | |||
| 3654 | #ifdef SND_HDA_NEEDS_RESUME | 3765 | #ifdef SND_HDA_NEEDS_RESUME |
| 3655 | static int alc_resume(struct hda_codec *codec) | 3766 | static int alc_resume(struct hda_codec *codec) |
| 3656 | { | 3767 | { |
| 3657 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
| 3658 | struct alc_spec *spec = codec->spec; | ||
| 3659 | #endif | ||
| 3660 | codec->patch_ops.init(codec); | 3768 | codec->patch_ops.init(codec); |
| 3661 | snd_hda_codec_resume_amp(codec); | 3769 | snd_hda_codec_resume_amp(codec); |
| 3662 | snd_hda_codec_resume_cache(codec); | 3770 | snd_hda_codec_resume_cache(codec); |
| 3663 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
| 3664 | if (spec && spec->power_hook) | ||
| 3665 | spec->power_hook(codec, 1); | ||
| 3666 | #endif | ||
| 3667 | return 0; | 3771 | return 0; |
| 3668 | } | 3772 | } |
| 3669 | #endif | 3773 | #endif |
| @@ -3683,6 +3787,7 @@ static struct hda_codec_ops alc_patch_ops = { | |||
| 3683 | .suspend = alc_suspend, | 3787 | .suspend = alc_suspend, |
| 3684 | .check_power_status = alc_check_power_status, | 3788 | .check_power_status = alc_check_power_status, |
| 3685 | #endif | 3789 | #endif |
| 3790 | .reboot_notify = alc_shutup, | ||
| 3686 | }; | 3791 | }; |
| 3687 | 3792 | ||
| 3688 | 3793 | ||
| @@ -3839,6 +3944,7 @@ static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol, | |||
| 3839 | #define PIN_CTL_TEST(xname,nid) { \ | 3944 | #define PIN_CTL_TEST(xname,nid) { \ |
| 3840 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | 3945 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
| 3841 | .name = xname, \ | 3946 | .name = xname, \ |
| 3947 | .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ | ||
| 3842 | .info = alc_test_pin_ctl_info, \ | 3948 | .info = alc_test_pin_ctl_info, \ |
| 3843 | .get = alc_test_pin_ctl_get, \ | 3949 | .get = alc_test_pin_ctl_get, \ |
| 3844 | .put = alc_test_pin_ctl_put, \ | 3950 | .put = alc_test_pin_ctl_put, \ |
| @@ -3848,6 +3954,7 @@ static int alc_test_pin_src_put(struct snd_kcontrol *kcontrol, | |||
| 3848 | #define PIN_SRC_TEST(xname,nid) { \ | 3954 | #define PIN_SRC_TEST(xname,nid) { \ |
| 3849 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | 3955 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
| 3850 | .name = xname, \ | 3956 | .name = xname, \ |
| 3957 | .subdevice = HDA_SUBDEV_NID_FLAG | nid, \ | ||
| 3851 | .info = alc_test_pin_src_info, \ | 3958 | .info = alc_test_pin_src_info, \ |
| 3852 | .get = alc_test_pin_src_get, \ | 3959 | .get = alc_test_pin_src_get, \ |
| 3853 | .put = alc_test_pin_src_put, \ | 3960 | .put = alc_test_pin_src_put, \ |
| @@ -4387,7 +4494,7 @@ static int add_control(struct alc_spec *spec, int type, const char *name, | |||
| 4387 | if (!knew->name) | 4494 | if (!knew->name) |
| 4388 | return -ENOMEM; | 4495 | return -ENOMEM; |
| 4389 | if (get_amp_nid_(val)) | 4496 | if (get_amp_nid_(val)) |
| 4390 | knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val); | 4497 | knew->subdevice = HDA_SUBDEV_AMP_FLAG; |
| 4391 | knew->private_value = val; | 4498 | knew->private_value = val; |
| 4392 | return 0; | 4499 | return 0; |
| 4393 | } | 4500 | } |
| @@ -5182,6 +5289,7 @@ static struct snd_kcontrol_new alc260_hp_output_mixer[] = { | |||
| 5182 | { | 5289 | { |
| 5183 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 5290 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 5184 | .name = "Master Playback Switch", | 5291 | .name = "Master Playback Switch", |
| 5292 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x11, | ||
| 5185 | .info = snd_ctl_boolean_mono_info, | 5293 | .info = snd_ctl_boolean_mono_info, |
| 5186 | .get = alc260_hp_master_sw_get, | 5294 | .get = alc260_hp_master_sw_get, |
| 5187 | .put = alc260_hp_master_sw_put, | 5295 | .put = alc260_hp_master_sw_put, |
| @@ -5220,6 +5328,7 @@ static struct snd_kcontrol_new alc260_hp_3013_mixer[] = { | |||
| 5220 | { | 5328 | { |
| 5221 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 5329 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 5222 | .name = "Master Playback Switch", | 5330 | .name = "Master Playback Switch", |
| 5331 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x11, | ||
| 5223 | .info = snd_ctl_boolean_mono_info, | 5332 | .info = snd_ctl_boolean_mono_info, |
| 5224 | .get = alc260_hp_master_sw_get, | 5333 | .get = alc260_hp_master_sw_get, |
| 5225 | .put = alc260_hp_master_sw_put, | 5334 | .put = alc260_hp_master_sw_put, |
| @@ -9528,7 +9637,7 @@ static struct alc_config_preset alc882_presets[] = { | |||
| 9528 | .setup = alc889_acer_aspire_8930g_setup, | 9637 | .setup = alc889_acer_aspire_8930g_setup, |
| 9529 | .init_hook = alc_automute_amp, | 9638 | .init_hook = alc_automute_amp, |
| 9530 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 9639 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
| 9531 | .power_hook = alc889_power_eapd, | 9640 | .power_hook = alc_power_eapd, |
| 9532 | #endif | 9641 | #endif |
| 9533 | }, | 9642 | }, |
| 9534 | [ALC888_ACER_ASPIRE_7730G] = { | 9643 | [ALC888_ACER_ASPIRE_7730G] = { |
| @@ -10324,8 +10433,14 @@ static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol, | |||
| 10324 | .info = snd_ctl_boolean_mono_info, \ | 10433 | .info = snd_ctl_boolean_mono_info, \ |
| 10325 | .get = alc262_hp_master_sw_get, \ | 10434 | .get = alc262_hp_master_sw_get, \ |
| 10326 | .put = alc262_hp_master_sw_put, \ | 10435 | .put = alc262_hp_master_sw_put, \ |
| 10436 | }, \ | ||
| 10437 | { \ | ||
| 10438 | .iface = NID_MAPPING, \ | ||
| 10439 | .name = "Master Playback Switch", \ | ||
| 10440 | .private_value = 0x15 | (0x16 << 8) | (0x1b << 16), \ | ||
| 10327 | } | 10441 | } |
| 10328 | 10442 | ||
| 10443 | |||
| 10329 | static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { | 10444 | static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { |
| 10330 | ALC262_HP_MASTER_SWITCH, | 10445 | ALC262_HP_MASTER_SWITCH, |
| 10331 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 10446 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
| @@ -10483,6 +10598,12 @@ static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol, | |||
| 10483 | .info = snd_ctl_boolean_mono_info, \ | 10598 | .info = snd_ctl_boolean_mono_info, \ |
| 10484 | .get = alc262_hippo_master_sw_get, \ | 10599 | .get = alc262_hippo_master_sw_get, \ |
| 10485 | .put = alc262_hippo_master_sw_put, \ | 10600 | .put = alc262_hippo_master_sw_put, \ |
| 10601 | }, \ | ||
| 10602 | { \ | ||
| 10603 | .iface = NID_MAPPING, \ | ||
| 10604 | .name = "Master Playback Switch", \ | ||
| 10605 | .subdevice = SUBDEV_HP(0) | (SUBDEV_LINE(0) << 8) | \ | ||
| 10606 | (SUBDEV_SPEAKER(0) << 16), \ | ||
| 10486 | } | 10607 | } |
| 10487 | 10608 | ||
| 10488 | static struct snd_kcontrol_new alc262_hippo_mixer[] = { | 10609 | static struct snd_kcontrol_new alc262_hippo_mixer[] = { |
| @@ -10963,11 +11084,17 @@ static struct snd_kcontrol_new alc262_fujitsu_mixer[] = { | |||
| 10963 | { | 11084 | { |
| 10964 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 11085 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 10965 | .name = "Master Playback Switch", | 11086 | .name = "Master Playback Switch", |
| 11087 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
| 10966 | .info = snd_hda_mixer_amp_switch_info, | 11088 | .info = snd_hda_mixer_amp_switch_info, |
| 10967 | .get = snd_hda_mixer_amp_switch_get, | 11089 | .get = snd_hda_mixer_amp_switch_get, |
| 10968 | .put = alc262_fujitsu_master_sw_put, | 11090 | .put = alc262_fujitsu_master_sw_put, |
| 10969 | .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), | 11091 | .private_value = HDA_COMPOSE_AMP_VAL(0x14, 3, 0, HDA_OUTPUT), |
| 10970 | }, | 11092 | }, |
| 11093 | { | ||
| 11094 | .iface = NID_MAPPING, | ||
| 11095 | .name = "Master Playback Switch", | ||
| 11096 | .private_value = 0x1b, | ||
| 11097 | }, | ||
| 10971 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | 11098 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), |
| 10972 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | 11099 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), |
| 10973 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | 11100 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), |
| @@ -10998,6 +11125,7 @@ static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = { | |||
| 10998 | { | 11125 | { |
| 10999 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 11126 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 11000 | .name = "Master Playback Switch", | 11127 | .name = "Master Playback Switch", |
| 11128 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
| 11001 | .info = snd_hda_mixer_amp_switch_info, | 11129 | .info = snd_hda_mixer_amp_switch_info, |
| 11002 | .get = snd_hda_mixer_amp_switch_get, | 11130 | .get = snd_hda_mixer_amp_switch_get, |
| 11003 | .put = alc262_lenovo_3000_master_sw_put, | 11131 | .put = alc262_lenovo_3000_master_sw_put, |
| @@ -11152,6 +11280,11 @@ static struct snd_kcontrol_new alc262_ultra_capture_mixer[] = { | |||
| 11152 | .get = alc_mux_enum_get, | 11280 | .get = alc_mux_enum_get, |
| 11153 | .put = alc262_ultra_mux_enum_put, | 11281 | .put = alc262_ultra_mux_enum_put, |
| 11154 | }, | 11282 | }, |
| 11283 | { | ||
| 11284 | .iface = NID_MAPPING, | ||
| 11285 | .name = "Capture Source", | ||
| 11286 | .private_value = 0x15, | ||
| 11287 | }, | ||
| 11155 | { } /* end */ | 11288 | { } /* end */ |
| 11156 | }; | 11289 | }; |
| 11157 | 11290 | ||
| @@ -12170,6 +12303,7 @@ static struct snd_kcontrol_new alc268_acer_aspire_one_mixer[] = { | |||
| 12170 | { | 12303 | { |
| 12171 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 12304 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 12172 | .name = "Master Playback Switch", | 12305 | .name = "Master Playback Switch", |
| 12306 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
| 12173 | .info = snd_hda_mixer_amp_switch_info, | 12307 | .info = snd_hda_mixer_amp_switch_info, |
| 12174 | .get = snd_hda_mixer_amp_switch_get, | 12308 | .get = snd_hda_mixer_amp_switch_get, |
| 12175 | .put = alc268_acer_master_sw_put, | 12309 | .put = alc268_acer_master_sw_put, |
| @@ -12185,6 +12319,7 @@ static struct snd_kcontrol_new alc268_acer_mixer[] = { | |||
| 12185 | { | 12319 | { |
| 12186 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 12320 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 12187 | .name = "Master Playback Switch", | 12321 | .name = "Master Playback Switch", |
| 12322 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
| 12188 | .info = snd_hda_mixer_amp_switch_info, | 12323 | .info = snd_hda_mixer_amp_switch_info, |
| 12189 | .get = snd_hda_mixer_amp_switch_get, | 12324 | .get = snd_hda_mixer_amp_switch_get, |
| 12190 | .put = alc268_acer_master_sw_put, | 12325 | .put = alc268_acer_master_sw_put, |
| @@ -12202,6 +12337,7 @@ static struct snd_kcontrol_new alc268_acer_dmic_mixer[] = { | |||
| 12202 | { | 12337 | { |
| 12203 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 12338 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 12204 | .name = "Master Playback Switch", | 12339 | .name = "Master Playback Switch", |
| 12340 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
| 12205 | .info = snd_hda_mixer_amp_switch_info, | 12341 | .info = snd_hda_mixer_amp_switch_info, |
| 12206 | .get = snd_hda_mixer_amp_switch_get, | 12342 | .get = snd_hda_mixer_amp_switch_get, |
| 12207 | .put = alc268_acer_master_sw_put, | 12343 | .put = alc268_acer_master_sw_put, |
| @@ -13155,6 +13291,7 @@ static struct snd_kcontrol_new alc269_quanta_fl1_mixer[] = { | |||
| 13155 | { | 13291 | { |
| 13156 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 13292 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 13157 | .name = "Master Playback Switch", | 13293 | .name = "Master Playback Switch", |
| 13294 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
| 13158 | .info = snd_hda_mixer_amp_switch_info, | 13295 | .info = snd_hda_mixer_amp_switch_info, |
| 13159 | .get = snd_hda_mixer_amp_switch_get, | 13296 | .get = snd_hda_mixer_amp_switch_get, |
| 13160 | .put = alc268_acer_master_sw_put, | 13297 | .put = alc268_acer_master_sw_put, |
| @@ -13175,6 +13312,7 @@ static struct snd_kcontrol_new alc269_lifebook_mixer[] = { | |||
| 13175 | { | 13312 | { |
| 13176 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 13313 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 13177 | .name = "Master Playback Switch", | 13314 | .name = "Master Playback Switch", |
| 13315 | .subdevice = HDA_SUBDEV_AMP_FLAG, | ||
| 13178 | .info = snd_hda_mixer_amp_switch_info, | 13316 | .info = snd_hda_mixer_amp_switch_info, |
| 13179 | .get = snd_hda_mixer_amp_switch_get, | 13317 | .get = snd_hda_mixer_amp_switch_get, |
| 13180 | .put = alc268_acer_master_sw_put, | 13318 | .put = alc268_acer_master_sw_put, |
| @@ -14939,9 +15077,13 @@ static int patch_alc861(struct hda_codec *codec) | |||
| 14939 | spec->vmaster_nid = 0x03; | 15077 | spec->vmaster_nid = 0x03; |
| 14940 | 15078 | ||
| 14941 | codec->patch_ops = alc_patch_ops; | 15079 | codec->patch_ops = alc_patch_ops; |
| 14942 | if (board_config == ALC861_AUTO) | 15080 | if (board_config == ALC861_AUTO) { |
| 14943 | spec->init_hook = alc861_auto_init; | 15081 | spec->init_hook = alc861_auto_init; |
| 14944 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 15082 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
| 15083 | spec->power_hook = alc_power_eapd; | ||
| 15084 | #endif | ||
| 15085 | } | ||
| 15086 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
| 14945 | if (!spec->loopback.amplist) | 15087 | if (!spec->loopback.amplist) |
| 14946 | spec->loopback.amplist = alc861_loopbacks; | 15088 | spec->loopback.amplist = alc861_loopbacks; |
| 14947 | #endif | 15089 | #endif |
diff --git a/sound/pci/hda/patch_si3054.c b/sound/pci/hda/patch_si3054.c index 43b436c5d01b..f419ee8d75f0 100644 --- a/sound/pci/hda/patch_si3054.c +++ b/sound/pci/hda/patch_si3054.c | |||
| @@ -122,6 +122,7 @@ static int si3054_switch_put(struct snd_kcontrol *kcontrol, | |||
| 122 | #define SI3054_KCONTROL(kname,reg,mask) { \ | 122 | #define SI3054_KCONTROL(kname,reg,mask) { \ |
| 123 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | 123 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
| 124 | .name = kname, \ | 124 | .name = kname, \ |
| 125 | .subdevice = HDA_SUBDEV_NID_FLAG | reg, \ | ||
| 125 | .info = si3054_switch_info, \ | 126 | .info = si3054_switch_info, \ |
| 126 | .get = si3054_switch_get, \ | 127 | .get = si3054_switch_get, \ |
| 127 | .put = si3054_switch_put, \ | 128 | .put = si3054_switch_put, \ |
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 799ba2570902..dbffb5b5c69d 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
| @@ -2688,7 +2688,7 @@ static struct snd_kcontrol_new * | |||
| 2688 | stac_control_new(struct sigmatel_spec *spec, | 2688 | stac_control_new(struct sigmatel_spec *spec, |
| 2689 | struct snd_kcontrol_new *ktemp, | 2689 | struct snd_kcontrol_new *ktemp, |
| 2690 | const char *name, | 2690 | const char *name, |
| 2691 | hda_nid_t nid) | 2691 | unsigned int subdev) |
| 2692 | { | 2692 | { |
| 2693 | struct snd_kcontrol_new *knew; | 2693 | struct snd_kcontrol_new *knew; |
| 2694 | 2694 | ||
| @@ -2704,8 +2704,7 @@ stac_control_new(struct sigmatel_spec *spec, | |||
| 2704 | spec->kctls.alloced--; | 2704 | spec->kctls.alloced--; |
| 2705 | return NULL; | 2705 | return NULL; |
| 2706 | } | 2706 | } |
| 2707 | if (nid) | 2707 | knew->subdevice = subdev; |
| 2708 | knew->subdevice = HDA_SUBDEV_NID_FLAG | nid; | ||
| 2709 | return knew; | 2708 | return knew; |
| 2710 | } | 2709 | } |
| 2711 | 2710 | ||
| @@ -2715,7 +2714,7 @@ static int stac92xx_add_control_temp(struct sigmatel_spec *spec, | |||
| 2715 | unsigned long val) | 2714 | unsigned long val) |
| 2716 | { | 2715 | { |
| 2717 | struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name, | 2716 | struct snd_kcontrol_new *knew = stac_control_new(spec, ktemp, name, |
| 2718 | get_amp_nid_(val)); | 2717 | HDA_SUBDEV_AMP_FLAG); |
| 2719 | if (!knew) | 2718 | if (!knew) |
| 2720 | return -ENOMEM; | 2719 | return -ENOMEM; |
| 2721 | knew->index = idx; | 2720 | knew->index = idx; |
| @@ -4160,34 +4159,52 @@ static void stac92xx_power_down(struct hda_codec *codec) | |||
| 4160 | static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid, | 4159 | static void stac_toggle_power_map(struct hda_codec *codec, hda_nid_t nid, |
| 4161 | int enable); | 4160 | int enable); |
| 4162 | 4161 | ||
| 4162 | static inline int get_int_hint(struct hda_codec *codec, const char *key, | ||
| 4163 | int *valp) | ||
| 4164 | { | ||
| 4165 | const char *p; | ||
| 4166 | p = snd_hda_get_hint(codec, key); | ||
| 4167 | if (p) { | ||
| 4168 | unsigned long val; | ||
| 4169 | if (!strict_strtoul(p, 0, &val)) { | ||
| 4170 | *valp = val; | ||
| 4171 | return 1; | ||
| 4172 | } | ||
| 4173 | } | ||
| 4174 | return 0; | ||
| 4175 | } | ||
| 4176 | |||
| 4163 | /* override some hints from the hwdep entry */ | 4177 | /* override some hints from the hwdep entry */ |
| 4164 | static void stac_store_hints(struct hda_codec *codec) | 4178 | static void stac_store_hints(struct hda_codec *codec) |
| 4165 | { | 4179 | { |
| 4166 | struct sigmatel_spec *spec = codec->spec; | 4180 | struct sigmatel_spec *spec = codec->spec; |
| 4167 | const char *p; | ||
| 4168 | int val; | 4181 | int val; |
| 4169 | 4182 | ||
| 4170 | val = snd_hda_get_bool_hint(codec, "hp_detect"); | 4183 | val = snd_hda_get_bool_hint(codec, "hp_detect"); |
| 4171 | if (val >= 0) | 4184 | if (val >= 0) |
| 4172 | spec->hp_detect = val; | 4185 | spec->hp_detect = val; |
| 4173 | p = snd_hda_get_hint(codec, "gpio_mask"); | 4186 | if (get_int_hint(codec, "gpio_mask", &spec->gpio_mask)) { |
| 4174 | if (p) { | ||
| 4175 | spec->gpio_mask = simple_strtoul(p, NULL, 0); | ||
| 4176 | spec->eapd_mask = spec->gpio_dir = spec->gpio_data = | 4187 | spec->eapd_mask = spec->gpio_dir = spec->gpio_data = |
| 4177 | spec->gpio_mask; | 4188 | spec->gpio_mask; |
| 4178 | } | 4189 | } |
| 4179 | p = snd_hda_get_hint(codec, "gpio_dir"); | 4190 | if (get_int_hint(codec, "gpio_dir", &spec->gpio_dir)) |
| 4180 | if (p) | 4191 | spec->gpio_mask &= spec->gpio_mask; |
| 4181 | spec->gpio_dir = simple_strtoul(p, NULL, 0) & spec->gpio_mask; | 4192 | if (get_int_hint(codec, "gpio_data", &spec->gpio_data)) |
| 4182 | p = snd_hda_get_hint(codec, "gpio_data"); | 4193 | spec->gpio_dir &= spec->gpio_mask; |
| 4183 | if (p) | 4194 | if (get_int_hint(codec, "eapd_mask", &spec->eapd_mask)) |
| 4184 | spec->gpio_data = simple_strtoul(p, NULL, 0) & spec->gpio_mask; | 4195 | spec->eapd_mask &= spec->gpio_mask; |
| 4185 | p = snd_hda_get_hint(codec, "eapd_mask"); | 4196 | if (get_int_hint(codec, "gpio_mute", &spec->gpio_mute)) |
| 4186 | if (p) | 4197 | spec->gpio_mute &= spec->gpio_mask; |
| 4187 | spec->eapd_mask = simple_strtoul(p, NULL, 0) & spec->gpio_mask; | ||
| 4188 | val = snd_hda_get_bool_hint(codec, "eapd_switch"); | 4198 | val = snd_hda_get_bool_hint(codec, "eapd_switch"); |
| 4189 | if (val >= 0) | 4199 | if (val >= 0) |
| 4190 | spec->eapd_switch = val; | 4200 | spec->eapd_switch = val; |
| 4201 | get_int_hint(codec, "gpio_led_polarity", &spec->gpio_led_polarity); | ||
| 4202 | if (get_int_hint(codec, "gpio_led", &spec->gpio_led)) { | ||
| 4203 | spec->gpio_mask |= spec->gpio_led; | ||
| 4204 | spec->gpio_dir |= spec->gpio_led; | ||
| 4205 | if (spec->gpio_led_polarity) | ||
| 4206 | spec->gpio_data |= spec->gpio_led; | ||
| 4207 | } | ||
| 4191 | } | 4208 | } |
| 4192 | 4209 | ||
| 4193 | static int stac92xx_init(struct hda_codec *codec) | 4210 | static int stac92xx_init(struct hda_codec *codec) |
| @@ -4372,18 +4389,8 @@ static void stac92xx_free_kctls(struct hda_codec *codec) | |||
| 4372 | static void stac92xx_shutup(struct hda_codec *codec) | 4389 | static void stac92xx_shutup(struct hda_codec *codec) |
| 4373 | { | 4390 | { |
| 4374 | struct sigmatel_spec *spec = codec->spec; | 4391 | struct sigmatel_spec *spec = codec->spec; |
| 4375 | int i; | ||
| 4376 | hda_nid_t nid; | ||
| 4377 | 4392 | ||
| 4378 | /* reset each pin before powering down DAC/ADC to avoid click noise */ | 4393 | snd_hda_shutup_pins(codec); |
| 4379 | nid = codec->start_nid; | ||
| 4380 | for (i = 0; i < codec->num_nodes; i++, nid++) { | ||
| 4381 | unsigned int wcaps = get_wcaps(codec, nid); | ||
| 4382 | unsigned int wid_type = get_wcaps_type(wcaps); | ||
| 4383 | if (wid_type == AC_WID_PIN) | ||
| 4384 | snd_hda_codec_read(codec, nid, 0, | ||
| 4385 | AC_VERB_SET_PIN_WIDGET_CONTROL, 0); | ||
| 4386 | } | ||
| 4387 | 4394 | ||
| 4388 | if (spec->eapd_mask) | 4395 | if (spec->eapd_mask) |
| 4389 | stac_gpio_set(codec, spec->gpio_mask, | 4396 | stac_gpio_set(codec, spec->gpio_mask, |
| @@ -5431,6 +5438,54 @@ static int stac92hd71bxx_connected_smuxes(struct hda_codec *codec, | |||
| 5431 | return 0; | 5438 | return 0; |
| 5432 | } | 5439 | } |
| 5433 | 5440 | ||
| 5441 | /* HP dv7 bass switch - GPIO5 */ | ||
| 5442 | #define stac_hp_bass_gpio_info snd_ctl_boolean_mono_info | ||
| 5443 | static int stac_hp_bass_gpio_get(struct snd_kcontrol *kcontrol, | ||
| 5444 | struct snd_ctl_elem_value *ucontrol) | ||
| 5445 | { | ||
| 5446 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
| 5447 | struct sigmatel_spec *spec = codec->spec; | ||
| 5448 | ucontrol->value.integer.value[0] = !!(spec->gpio_data & 0x20); | ||
| 5449 | return 0; | ||
| 5450 | } | ||
| 5451 | |||
| 5452 | static int stac_hp_bass_gpio_put(struct snd_kcontrol *kcontrol, | ||
| 5453 | struct snd_ctl_elem_value *ucontrol) | ||
| 5454 | { | ||
| 5455 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
| 5456 | struct sigmatel_spec *spec = codec->spec; | ||
| 5457 | unsigned int gpio_data; | ||
| 5458 | |||
| 5459 | gpio_data = (spec->gpio_data & ~0x20) | | ||
| 5460 | (ucontrol->value.integer.value[0] ? 0x20 : 0); | ||
| 5461 | if (gpio_data == spec->gpio_data) | ||
| 5462 | return 0; | ||
| 5463 | spec->gpio_data = gpio_data; | ||
| 5464 | stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data); | ||
| 5465 | return 1; | ||
| 5466 | } | ||
| 5467 | |||
| 5468 | static struct snd_kcontrol_new stac_hp_bass_sw_ctrl = { | ||
| 5469 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 5470 | .info = stac_hp_bass_gpio_info, | ||
| 5471 | .get = stac_hp_bass_gpio_get, | ||
| 5472 | .put = stac_hp_bass_gpio_put, | ||
| 5473 | }; | ||
| 5474 | |||
| 5475 | static int stac_add_hp_bass_switch(struct hda_codec *codec) | ||
| 5476 | { | ||
| 5477 | struct sigmatel_spec *spec = codec->spec; | ||
| 5478 | |||
| 5479 | if (!stac_control_new(spec, &stac_hp_bass_sw_ctrl, | ||
| 5480 | "Bass Speaker Playback Switch", 0)) | ||
| 5481 | return -ENOMEM; | ||
| 5482 | |||
| 5483 | spec->gpio_mask |= 0x20; | ||
| 5484 | spec->gpio_dir |= 0x20; | ||
| 5485 | spec->gpio_data |= 0x20; | ||
| 5486 | return 0; | ||
| 5487 | } | ||
| 5488 | |||
| 5434 | static int patch_stac92hd71bxx(struct hda_codec *codec) | 5489 | static int patch_stac92hd71bxx(struct hda_codec *codec) |
| 5435 | { | 5490 | { |
| 5436 | struct sigmatel_spec *spec; | 5491 | struct sigmatel_spec *spec; |
| @@ -5674,6 +5729,15 @@ again: | |||
| 5674 | return err; | 5729 | return err; |
| 5675 | } | 5730 | } |
| 5676 | 5731 | ||
| 5732 | /* enable bass on HP dv7 */ | ||
| 5733 | if (spec->board_config == STAC_HP_DV5) { | ||
| 5734 | unsigned int cap; | ||
| 5735 | cap = snd_hda_param_read(codec, 0x1, AC_PAR_GPIO_CAP); | ||
| 5736 | cap &= AC_GPIO_IO_COUNT; | ||
| 5737 | if (cap >= 6) | ||
| 5738 | stac_add_hp_bass_switch(codec); | ||
| 5739 | } | ||
| 5740 | |||
| 5677 | codec->proc_widget_hook = stac92hd7x_proc_hook; | 5741 | codec->proc_widget_hook = stac92hd7x_proc_hook; |
| 5678 | 5742 | ||
| 5679 | return 0; | 5743 | return 0; |
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index b70e26ad263f..9ddc37300f6b 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c | |||
| @@ -54,6 +54,8 @@ | |||
| 54 | #include "hda_codec.h" | 54 | #include "hda_codec.h" |
| 55 | #include "hda_local.h" | 55 | #include "hda_local.h" |
| 56 | 56 | ||
| 57 | #define NID_MAPPING (-1) | ||
| 58 | |||
| 57 | /* amp values */ | 59 | /* amp values */ |
| 58 | #define AMP_VAL_IDX_SHIFT 19 | 60 | #define AMP_VAL_IDX_SHIFT 19 |
| 59 | #define AMP_VAL_IDX_MASK (0x0f<<19) | 61 | #define AMP_VAL_IDX_MASK (0x0f<<19) |
| @@ -157,6 +159,19 @@ struct via_spec { | |||
| 157 | #endif | 159 | #endif |
| 158 | }; | 160 | }; |
| 159 | 161 | ||
| 162 | static struct via_spec * via_new_spec(struct hda_codec *codec) | ||
| 163 | { | ||
| 164 | struct via_spec *spec; | ||
| 165 | |||
| 166 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
| 167 | if (spec == NULL) | ||
| 168 | return NULL; | ||
| 169 | |||
| 170 | codec->spec = spec; | ||
| 171 | spec->codec = codec; | ||
| 172 | return spec; | ||
| 173 | } | ||
| 174 | |||
| 160 | static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) | 175 | static enum VIA_HDA_CODEC get_codec_type(struct hda_codec *codec) |
| 161 | { | 176 | { |
| 162 | u32 vendor_id = codec->vendor_id; | 177 | u32 vendor_id = codec->vendor_id; |
| @@ -443,11 +458,27 @@ static int via_add_control(struct via_spec *spec, int type, const char *name, | |||
| 443 | if (!knew->name) | 458 | if (!knew->name) |
| 444 | return -ENOMEM; | 459 | return -ENOMEM; |
| 445 | if (get_amp_nid_(val)) | 460 | if (get_amp_nid_(val)) |
| 446 | knew->subdevice = HDA_SUBDEV_NID_FLAG | get_amp_nid_(val); | 461 | knew->subdevice = HDA_SUBDEV_AMP_FLAG; |
| 447 | knew->private_value = val; | 462 | knew->private_value = val; |
| 448 | return 0; | 463 | return 0; |
| 449 | } | 464 | } |
| 450 | 465 | ||
| 466 | static struct snd_kcontrol_new *via_clone_control(struct via_spec *spec, | ||
| 467 | struct snd_kcontrol_new *tmpl) | ||
| 468 | { | ||
| 469 | struct snd_kcontrol_new *knew; | ||
| 470 | |||
| 471 | snd_array_init(&spec->kctls, sizeof(*knew), 32); | ||
| 472 | knew = snd_array_new(&spec->kctls); | ||
| 473 | if (!knew) | ||
| 474 | return NULL; | ||
| 475 | *knew = *tmpl; | ||
| 476 | knew->name = kstrdup(tmpl->name, GFP_KERNEL); | ||
| 477 | if (!knew->name) | ||
| 478 | return NULL; | ||
| 479 | return 0; | ||
| 480 | } | ||
| 481 | |||
| 451 | static void via_free_kctls(struct hda_codec *codec) | 482 | static void via_free_kctls(struct hda_codec *codec) |
| 452 | { | 483 | { |
| 453 | struct via_spec *spec = codec->spec; | 484 | struct via_spec *spec = codec->spec; |
| @@ -1088,24 +1119,9 @@ static int via_independent_hp_get(struct snd_kcontrol *kcontrol, | |||
| 1088 | struct snd_ctl_elem_value *ucontrol) | 1119 | struct snd_ctl_elem_value *ucontrol) |
| 1089 | { | 1120 | { |
| 1090 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 1121 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
| 1091 | struct via_spec *spec = codec->spec; | 1122 | hda_nid_t nid = kcontrol->private_value; |
| 1092 | hda_nid_t nid; | ||
| 1093 | unsigned int pinsel; | 1123 | unsigned int pinsel; |
| 1094 | 1124 | ||
| 1095 | switch (spec->codec_type) { | ||
| 1096 | case VT1718S: | ||
| 1097 | nid = 0x34; | ||
| 1098 | break; | ||
| 1099 | case VT2002P: | ||
| 1100 | nid = 0x35; | ||
| 1101 | break; | ||
| 1102 | case VT1812: | ||
| 1103 | nid = 0x3d; | ||
| 1104 | break; | ||
| 1105 | default: | ||
| 1106 | nid = spec->autocfg.hp_pins[0]; | ||
| 1107 | break; | ||
| 1108 | } | ||
| 1109 | /* use !! to translate conn sel 2 for VT1718S */ | 1125 | /* use !! to translate conn sel 2 for VT1718S */ |
| 1110 | pinsel = !!snd_hda_codec_read(codec, nid, 0, | 1126 | pinsel = !!snd_hda_codec_read(codec, nid, 0, |
| 1111 | AC_VERB_GET_CONNECT_SEL, | 1127 | AC_VERB_GET_CONNECT_SEL, |
| @@ -1127,29 +1143,24 @@ static void activate_ctl(struct hda_codec *codec, const char *name, int active) | |||
| 1127 | } | 1143 | } |
| 1128 | } | 1144 | } |
| 1129 | 1145 | ||
| 1146 | static hda_nid_t side_mute_channel(struct via_spec *spec) | ||
| 1147 | { | ||
| 1148 | switch (spec->codec_type) { | ||
| 1149 | case VT1708: return 0x1b; | ||
| 1150 | case VT1709_10CH: return 0x29; | ||
| 1151 | case VT1708B_8CH: /* fall thru */ | ||
| 1152 | case VT1708S: return 0x27; | ||
| 1153 | default: return 0; | ||
| 1154 | } | ||
| 1155 | } | ||
| 1156 | |||
| 1130 | static int update_side_mute_status(struct hda_codec *codec) | 1157 | static int update_side_mute_status(struct hda_codec *codec) |
| 1131 | { | 1158 | { |
| 1132 | /* mute side channel */ | 1159 | /* mute side channel */ |
| 1133 | struct via_spec *spec = codec->spec; | 1160 | struct via_spec *spec = codec->spec; |
| 1134 | unsigned int parm = spec->hp_independent_mode | 1161 | unsigned int parm = spec->hp_independent_mode |
| 1135 | ? AMP_OUT_MUTE : AMP_OUT_UNMUTE; | 1162 | ? AMP_OUT_MUTE : AMP_OUT_UNMUTE; |
| 1136 | hda_nid_t sw3; | 1163 | hda_nid_t sw3 = side_mute_channel(spec); |
| 1137 | |||
| 1138 | switch (spec->codec_type) { | ||
| 1139 | case VT1708: | ||
| 1140 | sw3 = 0x1b; | ||
| 1141 | break; | ||
| 1142 | case VT1709_10CH: | ||
| 1143 | sw3 = 0x29; | ||
| 1144 | break; | ||
| 1145 | case VT1708B_8CH: | ||
| 1146 | case VT1708S: | ||
| 1147 | sw3 = 0x27; | ||
| 1148 | break; | ||
| 1149 | default: | ||
| 1150 | sw3 = 0; | ||
| 1151 | break; | ||
| 1152 | } | ||
| 1153 | 1164 | ||
| 1154 | if (sw3) | 1165 | if (sw3) |
| 1155 | snd_hda_codec_write(codec, sw3, 0, AC_VERB_SET_AMP_GAIN_MUTE, | 1166 | snd_hda_codec_write(codec, sw3, 0, AC_VERB_SET_AMP_GAIN_MUTE, |
| @@ -1162,28 +1173,11 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, | |||
| 1162 | { | 1173 | { |
| 1163 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 1174 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
| 1164 | struct via_spec *spec = codec->spec; | 1175 | struct via_spec *spec = codec->spec; |
| 1165 | hda_nid_t nid = spec->autocfg.hp_pins[0]; | 1176 | hda_nid_t nid = kcontrol->private_value; |
| 1166 | unsigned int pinsel = ucontrol->value.enumerated.item[0]; | 1177 | unsigned int pinsel = ucontrol->value.enumerated.item[0]; |
| 1167 | /* Get Independent Mode index of headphone pin widget */ | 1178 | /* Get Independent Mode index of headphone pin widget */ |
| 1168 | spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel | 1179 | spec->hp_independent_mode = spec->hp_independent_mode_index == pinsel |
| 1169 | ? 1 : 0; | 1180 | ? 1 : 0; |
| 1170 | |||
| 1171 | switch (spec->codec_type) { | ||
| 1172 | case VT1718S: | ||
| 1173 | nid = 0x34; | ||
| 1174 | pinsel = pinsel ? 2 : 0; /* indep HP use AOW4 (index 2) */ | ||
| 1175 | spec->multiout.num_dacs = 4; | ||
| 1176 | break; | ||
| 1177 | case VT2002P: | ||
| 1178 | nid = 0x35; | ||
| 1179 | break; | ||
| 1180 | case VT1812: | ||
| 1181 | nid = 0x3d; | ||
| 1182 | break; | ||
| 1183 | default: | ||
| 1184 | nid = spec->autocfg.hp_pins[0]; | ||
| 1185 | break; | ||
| 1186 | } | ||
| 1187 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, pinsel); | 1181 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_CONNECT_SEL, pinsel); |
| 1188 | 1182 | ||
| 1189 | if (spec->multiout.hp_nid && spec->multiout.hp_nid | 1183 | if (spec->multiout.hp_nid && spec->multiout.hp_nid |
| @@ -1207,18 +1201,55 @@ static int via_independent_hp_put(struct snd_kcontrol *kcontrol, | |||
| 1207 | return 0; | 1201 | return 0; |
| 1208 | } | 1202 | } |
| 1209 | 1203 | ||
| 1210 | static struct snd_kcontrol_new via_hp_mixer[] = { | 1204 | static struct snd_kcontrol_new via_hp_mixer[2] = { |
| 1211 | { | 1205 | { |
| 1212 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1206 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1213 | .name = "Independent HP", | 1207 | .name = "Independent HP", |
| 1214 | .count = 1, | ||
| 1215 | .info = via_independent_hp_info, | 1208 | .info = via_independent_hp_info, |
| 1216 | .get = via_independent_hp_get, | 1209 | .get = via_independent_hp_get, |
| 1217 | .put = via_independent_hp_put, | 1210 | .put = via_independent_hp_put, |
| 1218 | }, | 1211 | }, |
| 1219 | { } /* end */ | 1212 | { |
| 1213 | .iface = NID_MAPPING, | ||
| 1214 | .name = "Independent HP", | ||
| 1215 | }, | ||
| 1220 | }; | 1216 | }; |
| 1221 | 1217 | ||
| 1218 | static int via_hp_build(struct via_spec *spec) | ||
| 1219 | { | ||
| 1220 | struct snd_kcontrol_new *knew; | ||
| 1221 | hda_nid_t nid; | ||
| 1222 | |||
| 1223 | knew = via_clone_control(spec, &via_hp_mixer[0]); | ||
| 1224 | if (knew == NULL) | ||
| 1225 | return -ENOMEM; | ||
| 1226 | |||
| 1227 | switch (spec->codec_type) { | ||
| 1228 | case VT1718S: | ||
| 1229 | nid = 0x34; | ||
| 1230 | break; | ||
| 1231 | case VT2002P: | ||
| 1232 | nid = 0x35; | ||
| 1233 | break; | ||
| 1234 | case VT1812: | ||
| 1235 | nid = 0x3d; | ||
| 1236 | break; | ||
| 1237 | default: | ||
| 1238 | nid = spec->autocfg.hp_pins[0]; | ||
| 1239 | break; | ||
| 1240 | } | ||
| 1241 | |||
| 1242 | knew->subdevice = HDA_SUBDEV_NID_FLAG | nid; | ||
| 1243 | knew->private_value = nid; | ||
| 1244 | |||
| 1245 | knew = via_clone_control(spec, &via_hp_mixer[1]); | ||
| 1246 | if (knew == NULL) | ||
| 1247 | return -ENOMEM; | ||
| 1248 | knew->subdevice = side_mute_channel(spec); | ||
| 1249 | |||
| 1250 | return 0; | ||
| 1251 | } | ||
| 1252 | |||
| 1222 | static void notify_aa_path_ctls(struct hda_codec *codec) | 1253 | static void notify_aa_path_ctls(struct hda_codec *codec) |
| 1223 | { | 1254 | { |
| 1224 | int i; | 1255 | int i; |
| @@ -1376,7 +1407,7 @@ static int via_smart51_put(struct snd_kcontrol *kcontrol, | |||
| 1376 | return 1; | 1407 | return 1; |
| 1377 | } | 1408 | } |
| 1378 | 1409 | ||
| 1379 | static struct snd_kcontrol_new via_smart51_mixer[] = { | 1410 | static struct snd_kcontrol_new via_smart51_mixer[2] = { |
| 1380 | { | 1411 | { |
| 1381 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1412 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 1382 | .name = "Smart 5.1", | 1413 | .name = "Smart 5.1", |
| @@ -1385,9 +1416,36 @@ static struct snd_kcontrol_new via_smart51_mixer[] = { | |||
| 1385 | .get = via_smart51_get, | 1416 | .get = via_smart51_get, |
| 1386 | .put = via_smart51_put, | 1417 | .put = via_smart51_put, |
| 1387 | }, | 1418 | }, |
| 1388 | {} /* end */ | 1419 | { |
| 1420 | .iface = NID_MAPPING, | ||
| 1421 | .name = "Smart 5.1", | ||
| 1422 | } | ||
| 1389 | }; | 1423 | }; |
| 1390 | 1424 | ||
| 1425 | static int via_smart51_build(struct via_spec *spec) | ||
| 1426 | { | ||
| 1427 | struct snd_kcontrol_new *knew; | ||
| 1428 | int index[] = { AUTO_PIN_MIC, AUTO_PIN_FRONT_MIC, AUTO_PIN_LINE }; | ||
| 1429 | hda_nid_t nid; | ||
| 1430 | int i; | ||
| 1431 | |||
| 1432 | knew = via_clone_control(spec, &via_smart51_mixer[0]); | ||
| 1433 | if (knew == NULL) | ||
| 1434 | return -ENOMEM; | ||
| 1435 | |||
| 1436 | for (i = 0; i < ARRAY_SIZE(index); i++) { | ||
| 1437 | nid = spec->autocfg.input_pins[index[i]]; | ||
| 1438 | if (nid) { | ||
| 1439 | knew = via_clone_control(spec, &via_smart51_mixer[1]); | ||
| 1440 | if (knew == NULL) | ||
| 1441 | return -ENOMEM; | ||
| 1442 | knew->subdevice = nid; | ||
| 1443 | } | ||
| 1444 | } | ||
| 1445 | |||
| 1446 | return 0; | ||
| 1447 | } | ||
| 1448 | |||
| 1391 | /* capture mixer elements */ | 1449 | /* capture mixer elements */ |
| 1392 | static struct snd_kcontrol_new vt1708_capture_mixer[] = { | 1450 | static struct snd_kcontrol_new vt1708_capture_mixer[] = { |
| 1393 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT), | 1451 | HDA_CODEC_VOLUME("Capture Volume", 0x15, 0x0, HDA_INPUT), |
| @@ -1819,8 +1877,9 @@ static struct hda_pcm_stream vt1708_pcm_digital_capture = { | |||
| 1819 | static int via_build_controls(struct hda_codec *codec) | 1877 | static int via_build_controls(struct hda_codec *codec) |
| 1820 | { | 1878 | { |
| 1821 | struct via_spec *spec = codec->spec; | 1879 | struct via_spec *spec = codec->spec; |
| 1822 | int err; | 1880 | struct snd_kcontrol *kctl; |
| 1823 | int i; | 1881 | struct snd_kcontrol_new *knew; |
| 1882 | int err, i; | ||
| 1824 | 1883 | ||
| 1825 | for (i = 0; i < spec->num_mixers; i++) { | 1884 | for (i = 0; i < spec->num_mixers; i++) { |
| 1826 | err = snd_hda_add_new_ctls(codec, spec->mixers[i]); | 1885 | err = snd_hda_add_new_ctls(codec, spec->mixers[i]); |
| @@ -1845,6 +1904,27 @@ static int via_build_controls(struct hda_codec *codec) | |||
| 1845 | return err; | 1904 | return err; |
| 1846 | } | 1905 | } |
| 1847 | 1906 | ||
| 1907 | /* assign Capture Source enums to NID */ | ||
| 1908 | kctl = snd_hda_find_mixer_ctl(codec, "Input Source"); | ||
| 1909 | for (i = 0; kctl && i < kctl->count; i++) { | ||
| 1910 | err = snd_hda_add_nid(codec, kctl, i, spec->mux_nids[i]); | ||
| 1911 | if (err < 0) | ||
| 1912 | return err; | ||
| 1913 | } | ||
| 1914 | |||
| 1915 | /* other nid->control mapping */ | ||
| 1916 | for (i = 0; i < spec->num_mixers; i++) { | ||
| 1917 | for (knew = spec->mixers[i]; knew->name; knew++) { | ||
| 1918 | if (knew->iface != NID_MAPPING) | ||
| 1919 | continue; | ||
| 1920 | kctl = snd_hda_find_mixer_ctl(codec, knew->name); | ||
| 1921 | if (kctl == NULL) | ||
| 1922 | continue; | ||
| 1923 | err = snd_hda_add_nid(codec, kctl, 0, | ||
| 1924 | knew->subdevice); | ||
| 1925 | } | ||
| 1926 | } | ||
| 1927 | |||
| 1848 | /* init power states */ | 1928 | /* init power states */ |
| 1849 | set_jack_power_state(codec); | 1929 | set_jack_power_state(codec); |
| 1850 | analog_low_current_mode(codec, 1); | 1930 | analog_low_current_mode(codec, 1); |
| @@ -2481,9 +2561,9 @@ static int vt1708_parse_auto_config(struct hda_codec *codec) | |||
| 2481 | spec->input_mux = &spec->private_imux[0]; | 2561 | spec->input_mux = &spec->private_imux[0]; |
| 2482 | 2562 | ||
| 2483 | if (spec->hp_mux) | 2563 | if (spec->hp_mux) |
| 2484 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 2564 | via_hp_build(spec); |
| 2485 | 2565 | ||
| 2486 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | 2566 | via_smart51_build(spec); |
| 2487 | return 1; | 2567 | return 1; |
| 2488 | } | 2568 | } |
| 2489 | 2569 | ||
| @@ -2554,12 +2634,10 @@ static int patch_vt1708(struct hda_codec *codec) | |||
| 2554 | int err; | 2634 | int err; |
| 2555 | 2635 | ||
| 2556 | /* create a codec specific record */ | 2636 | /* create a codec specific record */ |
| 2557 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 2637 | spec = via_new_spec(codec); |
| 2558 | if (spec == NULL) | 2638 | if (spec == NULL) |
| 2559 | return -ENOMEM; | 2639 | return -ENOMEM; |
| 2560 | 2640 | ||
| 2561 | codec->spec = spec; | ||
| 2562 | |||
| 2563 | /* automatic parse from the BIOS config */ | 2641 | /* automatic parse from the BIOS config */ |
| 2564 | err = vt1708_parse_auto_config(codec); | 2642 | err = vt1708_parse_auto_config(codec); |
| 2565 | if (err < 0) { | 2643 | if (err < 0) { |
| @@ -2597,7 +2675,6 @@ static int patch_vt1708(struct hda_codec *codec) | |||
| 2597 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 2675 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
| 2598 | spec->loopback.amplist = vt1708_loopbacks; | 2676 | spec->loopback.amplist = vt1708_loopbacks; |
| 2599 | #endif | 2677 | #endif |
| 2600 | spec->codec = codec; | ||
| 2601 | INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state); | 2678 | INIT_DELAYED_WORK(&spec->vt1708_hp_work, vt1708_update_hp_jack_state); |
| 2602 | return 0; | 2679 | return 0; |
| 2603 | } | 2680 | } |
| @@ -3010,9 +3087,9 @@ static int vt1709_parse_auto_config(struct hda_codec *codec) | |||
| 3010 | spec->input_mux = &spec->private_imux[0]; | 3087 | spec->input_mux = &spec->private_imux[0]; |
| 3011 | 3088 | ||
| 3012 | if (spec->hp_mux) | 3089 | if (spec->hp_mux) |
| 3013 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 3090 | via_hp_build(spec); |
| 3014 | 3091 | ||
| 3015 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | 3092 | via_smart51_build(spec); |
| 3016 | return 1; | 3093 | return 1; |
| 3017 | } | 3094 | } |
| 3018 | 3095 | ||
| @@ -3032,12 +3109,10 @@ static int patch_vt1709_10ch(struct hda_codec *codec) | |||
| 3032 | int err; | 3109 | int err; |
| 3033 | 3110 | ||
| 3034 | /* create a codec specific record */ | 3111 | /* create a codec specific record */ |
| 3035 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 3112 | spec = via_new_spec(codec); |
| 3036 | if (spec == NULL) | 3113 | if (spec == NULL) |
| 3037 | return -ENOMEM; | 3114 | return -ENOMEM; |
| 3038 | 3115 | ||
| 3039 | codec->spec = spec; | ||
| 3040 | |||
| 3041 | err = vt1709_parse_auto_config(codec); | 3116 | err = vt1709_parse_auto_config(codec); |
| 3042 | if (err < 0) { | 3117 | if (err < 0) { |
| 3043 | via_free(codec); | 3118 | via_free(codec); |
| @@ -3126,12 +3201,10 @@ static int patch_vt1709_6ch(struct hda_codec *codec) | |||
| 3126 | int err; | 3201 | int err; |
| 3127 | 3202 | ||
| 3128 | /* create a codec specific record */ | 3203 | /* create a codec specific record */ |
| 3129 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 3204 | spec = via_new_spec(codec); |
| 3130 | if (spec == NULL) | 3205 | if (spec == NULL) |
| 3131 | return -ENOMEM; | 3206 | return -ENOMEM; |
| 3132 | 3207 | ||
| 3133 | codec->spec = spec; | ||
| 3134 | |||
| 3135 | err = vt1709_parse_auto_config(codec); | 3208 | err = vt1709_parse_auto_config(codec); |
| 3136 | if (err < 0) { | 3209 | if (err < 0) { |
| 3137 | via_free(codec); | 3210 | via_free(codec); |
| @@ -3581,9 +3654,9 @@ static int vt1708B_parse_auto_config(struct hda_codec *codec) | |||
| 3581 | spec->input_mux = &spec->private_imux[0]; | 3654 | spec->input_mux = &spec->private_imux[0]; |
| 3582 | 3655 | ||
| 3583 | if (spec->hp_mux) | 3656 | if (spec->hp_mux) |
| 3584 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 3657 | via_hp_build(spec); |
| 3585 | 3658 | ||
| 3586 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | 3659 | via_smart51_build(spec); |
| 3587 | return 1; | 3660 | return 1; |
| 3588 | } | 3661 | } |
| 3589 | 3662 | ||
| @@ -3605,12 +3678,10 @@ static int patch_vt1708B_8ch(struct hda_codec *codec) | |||
| 3605 | if (get_codec_type(codec) == VT1708BCE) | 3678 | if (get_codec_type(codec) == VT1708BCE) |
| 3606 | return patch_vt1708S(codec); | 3679 | return patch_vt1708S(codec); |
| 3607 | /* create a codec specific record */ | 3680 | /* create a codec specific record */ |
| 3608 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 3681 | spec = via_new_spec(codec); |
| 3609 | if (spec == NULL) | 3682 | if (spec == NULL) |
| 3610 | return -ENOMEM; | 3683 | return -ENOMEM; |
| 3611 | 3684 | ||
| 3612 | codec->spec = spec; | ||
| 3613 | |||
| 3614 | /* automatic parse from the BIOS config */ | 3685 | /* automatic parse from the BIOS config */ |
| 3615 | err = vt1708B_parse_auto_config(codec); | 3686 | err = vt1708B_parse_auto_config(codec); |
| 3616 | if (err < 0) { | 3687 | if (err < 0) { |
| @@ -3657,12 +3728,10 @@ static int patch_vt1708B_4ch(struct hda_codec *codec) | |||
| 3657 | int err; | 3728 | int err; |
| 3658 | 3729 | ||
| 3659 | /* create a codec specific record */ | 3730 | /* create a codec specific record */ |
| 3660 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 3731 | spec = via_new_spec(codec); |
| 3661 | if (spec == NULL) | 3732 | if (spec == NULL) |
| 3662 | return -ENOMEM; | 3733 | return -ENOMEM; |
| 3663 | 3734 | ||
| 3664 | codec->spec = spec; | ||
| 3665 | |||
| 3666 | /* automatic parse from the BIOS config */ | 3735 | /* automatic parse from the BIOS config */ |
| 3667 | err = vt1708B_parse_auto_config(codec); | 3736 | err = vt1708B_parse_auto_config(codec); |
| 3668 | if (err < 0) { | 3737 | if (err < 0) { |
| @@ -4071,9 +4140,9 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec) | |||
| 4071 | spec->input_mux = &spec->private_imux[0]; | 4140 | spec->input_mux = &spec->private_imux[0]; |
| 4072 | 4141 | ||
| 4073 | if (spec->hp_mux) | 4142 | if (spec->hp_mux) |
| 4074 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 4143 | via_hp_build(spec); |
| 4075 | 4144 | ||
| 4076 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | 4145 | via_smart51_build(spec); |
| 4077 | return 1; | 4146 | return 1; |
| 4078 | } | 4147 | } |
| 4079 | 4148 | ||
| @@ -4103,12 +4172,10 @@ static int patch_vt1708S(struct hda_codec *codec) | |||
| 4103 | int err; | 4172 | int err; |
| 4104 | 4173 | ||
| 4105 | /* create a codec specific record */ | 4174 | /* create a codec specific record */ |
| 4106 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 4175 | spec = via_new_spec(codec); |
| 4107 | if (spec == NULL) | 4176 | if (spec == NULL) |
| 4108 | return -ENOMEM; | 4177 | return -ENOMEM; |
| 4109 | 4178 | ||
| 4110 | codec->spec = spec; | ||
| 4111 | |||
| 4112 | /* automatic parse from the BIOS config */ | 4179 | /* automatic parse from the BIOS config */ |
| 4113 | err = vt1708S_parse_auto_config(codec); | 4180 | err = vt1708S_parse_auto_config(codec); |
| 4114 | if (err < 0) { | 4181 | if (err < 0) { |
| @@ -4443,7 +4510,7 @@ static int vt1702_parse_auto_config(struct hda_codec *codec) | |||
| 4443 | spec->input_mux = &spec->private_imux[0]; | 4510 | spec->input_mux = &spec->private_imux[0]; |
| 4444 | 4511 | ||
| 4445 | if (spec->hp_mux) | 4512 | if (spec->hp_mux) |
| 4446 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 4513 | via_hp_build(spec); |
| 4447 | 4514 | ||
| 4448 | return 1; | 4515 | return 1; |
| 4449 | } | 4516 | } |
| @@ -4464,12 +4531,10 @@ static int patch_vt1702(struct hda_codec *codec) | |||
| 4464 | int err; | 4531 | int err; |
| 4465 | 4532 | ||
| 4466 | /* create a codec specific record */ | 4533 | /* create a codec specific record */ |
| 4467 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 4534 | spec = via_new_spec(codec); |
| 4468 | if (spec == NULL) | 4535 | if (spec == NULL) |
| 4469 | return -ENOMEM; | 4536 | return -ENOMEM; |
| 4470 | 4537 | ||
| 4471 | codec->spec = spec; | ||
| 4472 | |||
| 4473 | /* automatic parse from the BIOS config */ | 4538 | /* automatic parse from the BIOS config */ |
| 4474 | err = vt1702_parse_auto_config(codec); | 4539 | err = vt1702_parse_auto_config(codec); |
| 4475 | if (err < 0) { | 4540 | if (err < 0) { |
| @@ -4865,9 +4930,9 @@ static int vt1718S_parse_auto_config(struct hda_codec *codec) | |||
| 4865 | spec->input_mux = &spec->private_imux[0]; | 4930 | spec->input_mux = &spec->private_imux[0]; |
| 4866 | 4931 | ||
| 4867 | if (spec->hp_mux) | 4932 | if (spec->hp_mux) |
| 4868 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 4933 | via_hp_build(spec); |
| 4869 | 4934 | ||
| 4870 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | 4935 | via_smart51_build(spec); |
| 4871 | 4936 | ||
| 4872 | return 1; | 4937 | return 1; |
| 4873 | } | 4938 | } |
| @@ -4888,12 +4953,10 @@ static int patch_vt1718S(struct hda_codec *codec) | |||
| 4888 | int err; | 4953 | int err; |
| 4889 | 4954 | ||
| 4890 | /* create a codec specific record */ | 4955 | /* create a codec specific record */ |
| 4891 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 4956 | spec = via_new_spec(codec); |
| 4892 | if (spec == NULL) | 4957 | if (spec == NULL) |
| 4893 | return -ENOMEM; | 4958 | return -ENOMEM; |
| 4894 | 4959 | ||
| 4895 | codec->spec = spec; | ||
| 4896 | |||
| 4897 | /* automatic parse from the BIOS config */ | 4960 | /* automatic parse from the BIOS config */ |
| 4898 | err = vt1718S_parse_auto_config(codec); | 4961 | err = vt1718S_parse_auto_config(codec); |
| 4899 | if (err < 0) { | 4962 | if (err < 0) { |
| @@ -5014,6 +5077,7 @@ static struct snd_kcontrol_new vt1716s_dmic_mixer[] = { | |||
| 5014 | { | 5077 | { |
| 5015 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 5078 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
| 5016 | .name = "Digital Mic Capture Switch", | 5079 | .name = "Digital Mic Capture Switch", |
| 5080 | .subdevice = HDA_SUBDEV_NID_FLAG | 0x26, | ||
| 5017 | .count = 1, | 5081 | .count = 1, |
| 5018 | .info = vt1716s_dmic_info, | 5082 | .info = vt1716s_dmic_info, |
| 5019 | .get = vt1716s_dmic_get, | 5083 | .get = vt1716s_dmic_get, |
| @@ -5361,9 +5425,9 @@ static int vt1716S_parse_auto_config(struct hda_codec *codec) | |||
| 5361 | spec->input_mux = &spec->private_imux[0]; | 5425 | spec->input_mux = &spec->private_imux[0]; |
| 5362 | 5426 | ||
| 5363 | if (spec->hp_mux) | 5427 | if (spec->hp_mux) |
| 5364 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 5428 | via_hp_build(spec); |
| 5365 | 5429 | ||
| 5366 | spec->mixers[spec->num_mixers++] = via_smart51_mixer; | 5430 | via_smart51_build(spec); |
| 5367 | 5431 | ||
| 5368 | return 1; | 5432 | return 1; |
| 5369 | } | 5433 | } |
| @@ -5384,12 +5448,10 @@ static int patch_vt1716S(struct hda_codec *codec) | |||
| 5384 | int err; | 5448 | int err; |
| 5385 | 5449 | ||
| 5386 | /* create a codec specific record */ | 5450 | /* create a codec specific record */ |
| 5387 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 5451 | spec = via_new_spec(codec); |
| 5388 | if (spec == NULL) | 5452 | if (spec == NULL) |
| 5389 | return -ENOMEM; | 5453 | return -ENOMEM; |
| 5390 | 5454 | ||
| 5391 | codec->spec = spec; | ||
| 5392 | |||
| 5393 | /* automatic parse from the BIOS config */ | 5455 | /* automatic parse from the BIOS config */ |
| 5394 | err = vt1716S_parse_auto_config(codec); | 5456 | err = vt1716S_parse_auto_config(codec); |
| 5395 | if (err < 0) { | 5457 | if (err < 0) { |
| @@ -5719,7 +5781,7 @@ static int vt2002P_parse_auto_config(struct hda_codec *codec) | |||
| 5719 | spec->input_mux = &spec->private_imux[0]; | 5781 | spec->input_mux = &spec->private_imux[0]; |
| 5720 | 5782 | ||
| 5721 | if (spec->hp_mux) | 5783 | if (spec->hp_mux) |
| 5722 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 5784 | via_hp_build(spec); |
| 5723 | 5785 | ||
| 5724 | return 1; | 5786 | return 1; |
| 5725 | } | 5787 | } |
| @@ -5741,12 +5803,10 @@ static int patch_vt2002P(struct hda_codec *codec) | |||
| 5741 | int err; | 5803 | int err; |
| 5742 | 5804 | ||
| 5743 | /* create a codec specific record */ | 5805 | /* create a codec specific record */ |
| 5744 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 5806 | spec = via_new_spec(codec); |
| 5745 | if (spec == NULL) | 5807 | if (spec == NULL) |
| 5746 | return -ENOMEM; | 5808 | return -ENOMEM; |
| 5747 | 5809 | ||
| 5748 | codec->spec = spec; | ||
| 5749 | |||
| 5750 | /* automatic parse from the BIOS config */ | 5810 | /* automatic parse from the BIOS config */ |
| 5751 | err = vt2002P_parse_auto_config(codec); | 5811 | err = vt2002P_parse_auto_config(codec); |
| 5752 | if (err < 0) { | 5812 | if (err < 0) { |
| @@ -6070,7 +6130,7 @@ static int vt1812_parse_auto_config(struct hda_codec *codec) | |||
| 6070 | spec->input_mux = &spec->private_imux[0]; | 6130 | spec->input_mux = &spec->private_imux[0]; |
| 6071 | 6131 | ||
| 6072 | if (spec->hp_mux) | 6132 | if (spec->hp_mux) |
| 6073 | spec->mixers[spec->num_mixers++] = via_hp_mixer; | 6133 | via_hp_build(spec); |
| 6074 | 6134 | ||
| 6075 | return 1; | 6135 | return 1; |
| 6076 | } | 6136 | } |
| @@ -6092,12 +6152,10 @@ static int patch_vt1812(struct hda_codec *codec) | |||
| 6092 | int err; | 6152 | int err; |
| 6093 | 6153 | ||
| 6094 | /* create a codec specific record */ | 6154 | /* create a codec specific record */ |
| 6095 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | 6155 | spec = via_new_spec(codec); |
| 6096 | if (spec == NULL) | 6156 | if (spec == NULL) |
| 6097 | return -ENOMEM; | 6157 | return -ENOMEM; |
| 6098 | 6158 | ||
| 6099 | codec->spec = spec; | ||
| 6100 | |||
| 6101 | /* automatic parse from the BIOS config */ | 6159 | /* automatic parse from the BIOS config */ |
| 6102 | err = vt1812_parse_auto_config(codec); | 6160 | err = vt1812_parse_auto_config(codec); |
| 6103 | if (err < 0) { | 6161 | if (err < 0) { |
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c index c7cff6f8168a..4fc6d8bc637e 100644 --- a/sound/pci/ice1712/ice1712.c +++ b/sound/pci/ice1712/ice1712.c | |||
| @@ -106,7 +106,7 @@ module_param_array(dxr_enable, int, NULL, 0444); | |||
| 106 | MODULE_PARM_DESC(dxr_enable, "Enable DXR support for Terratec DMX6FIRE."); | 106 | MODULE_PARM_DESC(dxr_enable, "Enable DXR support for Terratec DMX6FIRE."); |
| 107 | 107 | ||
| 108 | 108 | ||
| 109 | static const struct pci_device_id snd_ice1712_ids[] = { | 109 | static DEFINE_PCI_DEVICE_TABLE(snd_ice1712_ids) = { |
| 110 | { PCI_VDEVICE(ICE, PCI_DEVICE_ID_ICE_1712), 0 }, /* ICE1712 */ | 110 | { PCI_VDEVICE(ICE, PCI_DEVICE_ID_ICE_1712), 0 }, /* ICE1712 */ |
| 111 | { 0, } | 111 | { 0, } |
| 112 | }; | 112 | }; |
| @@ -1180,6 +1180,10 @@ static int snd_ice1712_playback_pro_open(struct snd_pcm_substream *substream) | |||
| 1180 | snd_pcm_set_sync(substream); | 1180 | snd_pcm_set_sync(substream); |
| 1181 | snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); | 1181 | snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); |
| 1182 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); | 1182 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); |
| 1183 | if (is_pro_rate_locked(ice)) { | ||
| 1184 | runtime->hw.rate_min = PRO_RATE_DEFAULT; | ||
| 1185 | runtime->hw.rate_max = PRO_RATE_DEFAULT; | ||
| 1186 | } | ||
| 1183 | 1187 | ||
| 1184 | if (ice->spdif.ops.open) | 1188 | if (ice->spdif.ops.open) |
| 1185 | ice->spdif.ops.open(ice, substream); | 1189 | ice->spdif.ops.open(ice, substream); |
| @@ -1197,6 +1201,11 @@ static int snd_ice1712_capture_pro_open(struct snd_pcm_substream *substream) | |||
| 1197 | snd_pcm_set_sync(substream); | 1201 | snd_pcm_set_sync(substream); |
| 1198 | snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); | 1202 | snd_pcm_hw_constraint_msbits(runtime, 0, 32, 24); |
| 1199 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); | 1203 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, &hw_constraints_rates); |
| 1204 | if (is_pro_rate_locked(ice)) { | ||
| 1205 | runtime->hw.rate_min = PRO_RATE_DEFAULT; | ||
| 1206 | runtime->hw.rate_max = PRO_RATE_DEFAULT; | ||
| 1207 | } | ||
| 1208 | |||
| 1200 | return 0; | 1209 | return 0; |
| 1201 | } | 1210 | } |
| 1202 | 1211 | ||
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index ae29073eea93..c1498fa5545f 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c | |||
| @@ -94,7 +94,7 @@ MODULE_PARM_DESC(model, "Use the given board model."); | |||
| 94 | 94 | ||
| 95 | 95 | ||
| 96 | /* Both VT1720 and VT1724 have the same PCI IDs */ | 96 | /* Both VT1720 and VT1724 have the same PCI IDs */ |
| 97 | static const struct pci_device_id snd_vt1724_ids[] = { | 97 | static DEFINE_PCI_DEVICE_TABLE(snd_vt1724_ids) = { |
| 98 | { PCI_VDEVICE(ICE, PCI_DEVICE_ID_VT1724), 0 }, | 98 | { PCI_VDEVICE(ICE, PCI_DEVICE_ID_VT1724), 0 }, |
| 99 | { 0, } | 99 | { 0, } |
| 100 | }; | 100 | }; |
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index b990143636f1..6433e65c9507 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c | |||
| @@ -420,7 +420,7 @@ struct intel8x0 { | |||
| 420 | u32 int_sta_mask; /* interrupt status mask */ | 420 | u32 int_sta_mask; /* interrupt status mask */ |
| 421 | }; | 421 | }; |
| 422 | 422 | ||
| 423 | static struct pci_device_id snd_intel8x0_ids[] = { | 423 | static DEFINE_PCI_DEVICE_TABLE(snd_intel8x0_ids) = { |
| 424 | { PCI_VDEVICE(INTEL, 0x2415), DEVICE_INTEL }, /* 82801AA */ | 424 | { PCI_VDEVICE(INTEL, 0x2415), DEVICE_INTEL }, /* 82801AA */ |
| 425 | { PCI_VDEVICE(INTEL, 0x2425), DEVICE_INTEL }, /* 82901AB */ | 425 | { PCI_VDEVICE(INTEL, 0x2425), DEVICE_INTEL }, /* 82901AB */ |
| 426 | { PCI_VDEVICE(INTEL, 0x2445), DEVICE_INTEL }, /* 82801BA */ | 426 | { PCI_VDEVICE(INTEL, 0x2445), DEVICE_INTEL }, /* 82801BA */ |
diff --git a/sound/pci/intel8x0m.c b/sound/pci/intel8x0m.c index 9e7d12e7673f..13cec1e5ced9 100644 --- a/sound/pci/intel8x0m.c +++ b/sound/pci/intel8x0m.c | |||
| @@ -219,7 +219,7 @@ struct intel8x0m { | |||
| 219 | unsigned int pcm_pos_shift; | 219 | unsigned int pcm_pos_shift; |
| 220 | }; | 220 | }; |
| 221 | 221 | ||
| 222 | static struct pci_device_id snd_intel8x0m_ids[] = { | 222 | static DEFINE_PCI_DEVICE_TABLE(snd_intel8x0m_ids) = { |
| 223 | { PCI_VDEVICE(INTEL, 0x2416), DEVICE_INTEL }, /* 82801AA */ | 223 | { PCI_VDEVICE(INTEL, 0x2416), DEVICE_INTEL }, /* 82801AA */ |
| 224 | { PCI_VDEVICE(INTEL, 0x2426), DEVICE_INTEL }, /* 82901AB */ | 224 | { PCI_VDEVICE(INTEL, 0x2426), DEVICE_INTEL }, /* 82901AB */ |
| 225 | { PCI_VDEVICE(INTEL, 0x2446), DEVICE_INTEL }, /* 82801BA */ | 225 | { PCI_VDEVICE(INTEL, 0x2446), DEVICE_INTEL }, /* 82801BA */ |
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c index 7cc38a11e997..6d795700be79 100644 --- a/sound/pci/korg1212/korg1212.c +++ b/sound/pci/korg1212/korg1212.c | |||
| @@ -418,7 +418,7 @@ module_param_array(enable, bool, NULL, 0444); | |||
| 418 | MODULE_PARM_DESC(enable, "Enable Korg 1212 soundcard."); | 418 | MODULE_PARM_DESC(enable, "Enable Korg 1212 soundcard."); |
| 419 | MODULE_AUTHOR("Haroldo Gamal <gamal@alternex.com.br>"); | 419 | MODULE_AUTHOR("Haroldo Gamal <gamal@alternex.com.br>"); |
| 420 | 420 | ||
| 421 | static struct pci_device_id snd_korg1212_ids[] = { | 421 | static DEFINE_PCI_DEVICE_TABLE(snd_korg1212_ids) = { |
| 422 | { | 422 | { |
| 423 | .vendor = 0x10b5, | 423 | .vendor = 0x10b5, |
| 424 | .device = 0x906d, | 424 | .device = 0x906d, |
diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c index 11b8c6514b3d..0cca56038cd9 100644 --- a/sound/pci/lx6464es/lx6464es.c +++ b/sound/pci/lx6464es/lx6464es.c | |||
| @@ -55,7 +55,7 @@ static const char card_name[] = "LX6464ES"; | |||
| 55 | 55 | ||
| 56 | #define PCI_DEVICE_ID_PLX_LX6464ES PCI_DEVICE_ID_PLX_9056 | 56 | #define PCI_DEVICE_ID_PLX_LX6464ES PCI_DEVICE_ID_PLX_9056 |
| 57 | 57 | ||
| 58 | static struct pci_device_id snd_lx6464es_ids[] = { | 58 | static DEFINE_PCI_DEVICE_TABLE(snd_lx6464es_ids) = { |
| 59 | { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES), | 59 | { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES), |
| 60 | .subvendor = PCI_VENDOR_ID_DIGIGRAM, | 60 | .subvendor = PCI_VENDOR_ID_DIGIGRAM, |
| 61 | .subdevice = PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_SERIAL_SUBSYSTEM | 61 | .subdevice = PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_SERIAL_SUBSYSTEM |
diff --git a/sound/pci/maestro3.c b/sound/pci/maestro3.c index 75283fbb4b3f..b64e78139d63 100644 --- a/sound/pci/maestro3.c +++ b/sound/pci/maestro3.c | |||
| @@ -861,7 +861,7 @@ struct snd_m3 { | |||
| 861 | /* | 861 | /* |
| 862 | * pci ids | 862 | * pci ids |
| 863 | */ | 863 | */ |
| 864 | static struct pci_device_id snd_m3_ids[] = { | 864 | static DEFINE_PCI_DEVICE_TABLE(snd_m3_ids) = { |
| 865 | {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO_1, PCI_ANY_ID, PCI_ANY_ID, | 865 | {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO_1, PCI_ANY_ID, PCI_ANY_ID, |
| 866 | PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, | 866 | PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, |
| 867 | {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO, PCI_ANY_ID, PCI_ANY_ID, | 867 | {PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ALLEGRO, PCI_ANY_ID, PCI_ANY_ID, |
diff --git a/sound/pci/mixart/mixart.c b/sound/pci/mixart/mixart.c index a83d1968a845..7e8e7da592a9 100644 --- a/sound/pci/mixart/mixart.c +++ b/sound/pci/mixart/mixart.c | |||
| @@ -60,7 +60,7 @@ MODULE_PARM_DESC(enable, "Enable Digigram " CARD_NAME " soundcard."); | |||
| 60 | /* | 60 | /* |
| 61 | */ | 61 | */ |
| 62 | 62 | ||
| 63 | static struct pci_device_id snd_mixart_ids[] = { | 63 | static DEFINE_PCI_DEVICE_TABLE(snd_mixart_ids) = { |
| 64 | { PCI_VDEVICE(MOTOROLA, 0x0003), 0, }, /* MC8240 */ | 64 | { PCI_VDEVICE(MOTOROLA, 0x0003), 0, }, /* MC8240 */ |
| 65 | { 0, } | 65 | { 0, } |
| 66 | }; | 66 | }; |
diff --git a/sound/pci/nm256/nm256.c b/sound/pci/nm256/nm256.c index 97a0731331a1..5a60492ac7b3 100644 --- a/sound/pci/nm256/nm256.c +++ b/sound/pci/nm256/nm256.c | |||
| @@ -262,7 +262,7 @@ struct nm256 { | |||
| 262 | /* | 262 | /* |
| 263 | * PCI ids | 263 | * PCI ids |
| 264 | */ | 264 | */ |
| 265 | static struct pci_device_id snd_nm256_ids[] = { | 265 | static DEFINE_PCI_DEVICE_TABLE(snd_nm256_ids) = { |
| 266 | {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO), 0}, | 266 | {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256AV_AUDIO), 0}, |
| 267 | {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO), 0}, | 267 | {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256ZX_AUDIO), 0}, |
| 268 | {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO), 0}, | 268 | {PCI_VDEVICE(NEOMAGIC, PCI_DEVICE_ID_NEOMAGIC_NM256XL_PLUS_AUDIO), 0}, |
diff --git a/sound/pci/oxygen/Makefile b/sound/pci/oxygen/Makefile index 389941cf6100..acd8f15f7bff 100644 --- a/sound/pci/oxygen/Makefile +++ b/sound/pci/oxygen/Makefile | |||
| @@ -2,7 +2,7 @@ snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o | |||
| 2 | snd-hifier-objs := hifier.o | 2 | snd-hifier-objs := hifier.o |
| 3 | snd-oxygen-objs := oxygen.o | 3 | snd-oxygen-objs := oxygen.o |
| 4 | snd-virtuoso-objs := virtuoso.o xonar_lib.o \ | 4 | snd-virtuoso-objs := virtuoso.o xonar_lib.o \ |
| 5 | xonar_pcm179x.o xonar_cs43xx.o xonar_hdmi.o | 5 | xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o |
| 6 | 6 | ||
| 7 | obj-$(CONFIG_SND_OXYGEN_LIB) += snd-oxygen-lib.o | 7 | obj-$(CONFIG_SND_OXYGEN_LIB) += snd-oxygen-lib.o |
| 8 | obj-$(CONFIG_SND_HIFIER) += snd-hifier.o | 8 | obj-$(CONFIG_SND_HIFIER) += snd-hifier.o |
diff --git a/sound/pci/oxygen/hifier.c b/sound/pci/oxygen/hifier.c index e3c229b63311..5a87d683691f 100644 --- a/sound/pci/oxygen/hifier.c +++ b/sound/pci/oxygen/hifier.c | |||
| @@ -48,7 +48,7 @@ MODULE_PARM_DESC(id, "ID string"); | |||
| 48 | module_param_array(enable, bool, NULL, 0444); | 48 | module_param_array(enable, bool, NULL, 0444); |
| 49 | MODULE_PARM_DESC(enable, "enable card"); | 49 | MODULE_PARM_DESC(enable, "enable card"); |
| 50 | 50 | ||
| 51 | static struct pci_device_id hifier_ids[] __devinitdata = { | 51 | static DEFINE_PCI_DEVICE_TABLE(hifier_ids) = { |
| 52 | { OXYGEN_PCI_SUBID(0x14c3, 0x1710) }, | 52 | { OXYGEN_PCI_SUBID(0x14c3, 0x1710) }, |
| 53 | { OXYGEN_PCI_SUBID(0x14c3, 0x1711) }, | 53 | { OXYGEN_PCI_SUBID(0x14c3, 0x1711) }, |
| 54 | { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, | 54 | { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, |
diff --git a/sound/pci/oxygen/oxygen.c b/sound/pci/oxygen/oxygen.c index acbedebcffd9..289cb4dacfc7 100644 --- a/sound/pci/oxygen/oxygen.c +++ b/sound/pci/oxygen/oxygen.c | |||
| @@ -72,7 +72,7 @@ enum { | |||
| 72 | MODEL_CLARO_HALO, /* HT-Omega Claro halo */ | 72 | MODEL_CLARO_HALO, /* HT-Omega Claro halo */ |
| 73 | }; | 73 | }; |
| 74 | 74 | ||
| 75 | static struct pci_device_id oxygen_ids[] __devinitdata = { | 75 | static DEFINE_PCI_DEVICE_TABLE(oxygen_ids) = { |
| 76 | { OXYGEN_PCI_SUBID(0x10b0, 0x0216), .driver_data = MODEL_CMEDIA_REF }, | 76 | { OXYGEN_PCI_SUBID(0x10b0, 0x0216), .driver_data = MODEL_CMEDIA_REF }, |
| 77 | { OXYGEN_PCI_SUBID(0x10b0, 0x0218), .driver_data = MODEL_CMEDIA_REF }, | 77 | { OXYGEN_PCI_SUBID(0x10b0, 0x0218), .driver_data = MODEL_CMEDIA_REF }, |
| 78 | { OXYGEN_PCI_SUBID(0x10b0, 0x0219), .driver_data = MODEL_CMEDIA_REF }, | 78 | { OXYGEN_PCI_SUBID(0x10b0, 0x0219), .driver_data = MODEL_CMEDIA_REF }, |
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index 6accaf9580b2..f03a2f2cffee 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c | |||
| @@ -40,7 +40,7 @@ MODULE_PARM_DESC(id, "ID string"); | |||
| 40 | module_param_array(enable, bool, NULL, 0444); | 40 | module_param_array(enable, bool, NULL, 0444); |
| 41 | MODULE_PARM_DESC(enable, "enable card"); | 41 | MODULE_PARM_DESC(enable, "enable card"); |
| 42 | 42 | ||
| 43 | static struct pci_device_id xonar_ids[] __devinitdata = { | 43 | static DEFINE_PCI_DEVICE_TABLE(xonar_ids) = { |
| 44 | { OXYGEN_PCI_SUBID(0x1043, 0x8269) }, | 44 | { OXYGEN_PCI_SUBID(0x1043, 0x8269) }, |
| 45 | { OXYGEN_PCI_SUBID(0x1043, 0x8275) }, | 45 | { OXYGEN_PCI_SUBID(0x1043, 0x8275) }, |
| 46 | { OXYGEN_PCI_SUBID(0x1043, 0x82b7) }, | 46 | { OXYGEN_PCI_SUBID(0x1043, 0x82b7) }, |
| @@ -49,6 +49,7 @@ static struct pci_device_id xonar_ids[] __devinitdata = { | |||
| 49 | { OXYGEN_PCI_SUBID(0x1043, 0x834f) }, | 49 | { OXYGEN_PCI_SUBID(0x1043, 0x834f) }, |
| 50 | { OXYGEN_PCI_SUBID(0x1043, 0x835c) }, | 50 | { OXYGEN_PCI_SUBID(0x1043, 0x835c) }, |
| 51 | { OXYGEN_PCI_SUBID(0x1043, 0x835d) }, | 51 | { OXYGEN_PCI_SUBID(0x1043, 0x835d) }, |
| 52 | { OXYGEN_PCI_SUBID(0x1043, 0x838e) }, | ||
| 52 | { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, | 53 | { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, |
| 53 | { } | 54 | { } |
| 54 | }; | 55 | }; |
| @@ -61,6 +62,8 @@ static int __devinit get_xonar_model(struct oxygen *chip, | |||
| 61 | return 0; | 62 | return 0; |
| 62 | if (get_xonar_cs43xx_model(chip, id) >= 0) | 63 | if (get_xonar_cs43xx_model(chip, id) >= 0) |
| 63 | return 0; | 64 | return 0; |
| 65 | if (get_xonar_wm87x6_model(chip, id) >= 0) | ||
| 66 | return 0; | ||
| 64 | return -EINVAL; | 67 | return -EINVAL; |
| 65 | } | 68 | } |
| 66 | 69 | ||
diff --git a/sound/pci/oxygen/wm8766.h b/sound/pci/oxygen/wm8766.h new file mode 100644 index 000000000000..e0e849a7eaeb --- /dev/null +++ b/sound/pci/oxygen/wm8766.h | |||
| @@ -0,0 +1,73 @@ | |||
| 1 | #ifndef WM8766_H_INCLUDED | ||
| 2 | #define WM8766_H_INCLUDED | ||
| 3 | |||
| 4 | #define WM8766_LDA1 0x00 | ||
| 5 | #define WM8766_RDA1 0x01 | ||
| 6 | #define WM8766_DAC_CTRL 0x02 | ||
| 7 | #define WM8766_INT_CTRL 0x03 | ||
| 8 | #define WM8766_LDA2 0x04 | ||
| 9 | #define WM8766_RDA2 0x05 | ||
| 10 | #define WM8766_LDA3 0x06 | ||
| 11 | #define WM8766_RDA3 0x07 | ||
| 12 | #define WM8766_MASTDA 0x08 | ||
| 13 | #define WM8766_DAC_CTRL2 0x09 | ||
| 14 | #define WM8766_DAC_CTRL3 0x0a | ||
| 15 | #define WM8766_MUTE1 0x0c | ||
| 16 | #define WM8766_MUTE2 0x0f | ||
| 17 | #define WM8766_RESET 0x1f | ||
| 18 | |||
| 19 | /* LDAx/RDAx/MASTDA */ | ||
| 20 | #define WM8766_ATT_MASK 0x0ff | ||
| 21 | #define WM8766_UPDATE 0x100 | ||
| 22 | /* DAC_CTRL */ | ||
| 23 | #define WM8766_MUTEALL 0x001 | ||
| 24 | #define WM8766_DEEMPALL 0x002 | ||
| 25 | #define WM8766_PWDN 0x004 | ||
| 26 | #define WM8766_ATC 0x008 | ||
| 27 | #define WM8766_IZD 0x010 | ||
| 28 | #define WM8766_PL_LEFT_MASK 0x060 | ||
| 29 | #define WM8766_PL_LEFT_MUTE 0x000 | ||
| 30 | #define WM8766_PL_LEFT_LEFT 0x020 | ||
| 31 | #define WM8766_PL_LEFT_RIGHT 0x040 | ||
| 32 | #define WM8766_PL_LEFT_LRMIX 0x060 | ||
| 33 | #define WM8766_PL_RIGHT_MASK 0x180 | ||
| 34 | #define WM8766_PL_RIGHT_MUTE 0x000 | ||
| 35 | #define WM8766_PL_RIGHT_LEFT 0x080 | ||
| 36 | #define WM8766_PL_RIGHT_RIGHT 0x100 | ||
| 37 | #define WM8766_PL_RIGHT_LRMIX 0x180 | ||
| 38 | /* INT_CTRL */ | ||
| 39 | #define WM8766_FMT_MASK 0x003 | ||
| 40 | #define WM8766_FMT_RJUST 0x000 | ||
| 41 | #define WM8766_FMT_LJUST 0x001 | ||
| 42 | #define WM8766_FMT_I2S 0x002 | ||
| 43 | #define WM8766_FMT_DSP 0x003 | ||
| 44 | #define WM8766_LRP 0x004 | ||
| 45 | #define WM8766_BCP 0x008 | ||
| 46 | #define WM8766_IWL_MASK 0x030 | ||
| 47 | #define WM8766_IWL_16 0x000 | ||
| 48 | #define WM8766_IWL_20 0x010 | ||
| 49 | #define WM8766_IWL_24 0x020 | ||
| 50 | #define WM8766_IWL_32 0x030 | ||
| 51 | #define WM8766_PHASE_MASK 0x1c0 | ||
| 52 | /* DAC_CTRL2 */ | ||
| 53 | #define WM8766_ZCD 0x001 | ||
| 54 | #define WM8766_DZFM_MASK 0x006 | ||
| 55 | #define WM8766_DMUTE_MASK 0x038 | ||
| 56 | #define WM8766_DEEMP_MASK 0x1c0 | ||
| 57 | /* DAC_CTRL3 */ | ||
| 58 | #define WM8766_DACPD_MASK 0x00e | ||
| 59 | #define WM8766_PWRDNALL 0x010 | ||
| 60 | #define WM8766_MS 0x020 | ||
| 61 | #define WM8766_RATE_MASK 0x1c0 | ||
| 62 | #define WM8766_RATE_128 0x000 | ||
| 63 | #define WM8766_RATE_192 0x040 | ||
| 64 | #define WM8766_RATE_256 0x080 | ||
| 65 | #define WM8766_RATE_384 0x0c0 | ||
| 66 | #define WM8766_RATE_512 0x100 | ||
| 67 | #define WM8766_RATE_768 0x140 | ||
| 68 | /* MUTE1 */ | ||
| 69 | #define WM8766_MPD1 0x040 | ||
| 70 | /* MUTE2 */ | ||
| 71 | #define WM8766_MPD2 0x020 | ||
| 72 | |||
| 73 | #endif | ||
diff --git a/sound/pci/oxygen/wm8776.h b/sound/pci/oxygen/wm8776.h new file mode 100644 index 000000000000..1a96f5615727 --- /dev/null +++ b/sound/pci/oxygen/wm8776.h | |||
| @@ -0,0 +1,177 @@ | |||
| 1 | #ifndef WM8776_H_INCLUDED | ||
| 2 | #define WM8776_H_INCLUDED | ||
| 3 | |||
| 4 | /* | ||
| 5 | * the following register names are from: | ||
| 6 | * wm8776.h -- WM8776 ASoC driver | ||
| 7 | * | ||
| 8 | * Copyright 2009 Wolfson Microelectronics plc | ||
| 9 | * | ||
| 10 | * Author: Mark Brown <broonie@opensource.wolfsonmicro.com> | ||
| 11 | * | ||
| 12 | * This program is free software; you can redistribute it and/or modify | ||
| 13 | * it under the terms of the GNU General Public License version 2 as | ||
| 14 | * published by the Free Software Foundation. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #define WM8776_HPLVOL 0x00 | ||
| 18 | #define WM8776_HPRVOL 0x01 | ||
| 19 | #define WM8776_HPMASTER 0x02 | ||
| 20 | #define WM8776_DACLVOL 0x03 | ||
| 21 | #define WM8776_DACRVOL 0x04 | ||
| 22 | #define WM8776_DACMASTER 0x05 | ||
| 23 | #define WM8776_PHASESWAP 0x06 | ||
| 24 | #define WM8776_DACCTRL1 0x07 | ||
| 25 | #define WM8776_DACMUTE 0x08 | ||
| 26 | #define WM8776_DACCTRL2 0x09 | ||
| 27 | #define WM8776_DACIFCTRL 0x0a | ||
| 28 | #define WM8776_ADCIFCTRL 0x0b | ||
| 29 | #define WM8776_MSTRCTRL 0x0c | ||
| 30 | #define WM8776_PWRDOWN 0x0d | ||
| 31 | #define WM8776_ADCLVOL 0x0e | ||
| 32 | #define WM8776_ADCRVOL 0x0f | ||
| 33 | #define WM8776_ALCCTRL1 0x10 | ||
| 34 | #define WM8776_ALCCTRL2 0x11 | ||
| 35 | #define WM8776_ALCCTRL3 0x12 | ||
| 36 | #define WM8776_NOISEGATE 0x13 | ||
| 37 | #define WM8776_LIMITER 0x14 | ||
| 38 | #define WM8776_ADCMUX 0x15 | ||
| 39 | #define WM8776_OUTMUX 0x16 | ||
| 40 | #define WM8776_RESET 0x17 | ||
| 41 | |||
| 42 | |||
| 43 | /* HPLVOL/HPRVOL/HPMASTER */ | ||
| 44 | #define WM8776_HPATT_MASK 0x07f | ||
| 45 | #define WM8776_HPZCEN 0x080 | ||
| 46 | #define WM8776_UPDATE 0x100 | ||
| 47 | |||
| 48 | /* DACLVOL/DACRVOL/DACMASTER */ | ||
| 49 | #define WM8776_DATT_MASK 0x0ff | ||
| 50 | /*#define WM8776_UPDATE 0x100*/ | ||
| 51 | |||
| 52 | /* PHASESWAP */ | ||
| 53 | #define WM8776_PH_MASK 0x003 | ||
| 54 | |||
| 55 | /* DACCTRL1 */ | ||
| 56 | #define WM8776_DZCEN 0x001 | ||
| 57 | #define WM8776_ATC 0x002 | ||
| 58 | #define WM8776_IZD 0x004 | ||
| 59 | #define WM8776_TOD 0x008 | ||
| 60 | #define WM8776_PL_LEFT_MASK 0x030 | ||
| 61 | #define WM8776_PL_LEFT_MUTE 0x000 | ||
| 62 | #define WM8776_PL_LEFT_LEFT 0x010 | ||
| 63 | #define WM8776_PL_LEFT_RIGHT 0x020 | ||
| 64 | #define WM8776_PL_LEFT_LRMIX 0x030 | ||
| 65 | #define WM8776_PL_RIGHT_MASK 0x0c0 | ||
| 66 | #define WM8776_PL_RIGHT_MUTE 0x000 | ||
| 67 | #define WM8776_PL_RIGHT_LEFT 0x040 | ||
| 68 | #define WM8776_PL_RIGHT_RIGHT 0x080 | ||
| 69 | #define WM8776_PL_RIGHT_LRMIX 0x0c0 | ||
| 70 | |||
| 71 | /* DACMUTE */ | ||
| 72 | #define WM8776_DMUTE 0x001 | ||
| 73 | |||
| 74 | /* DACCTRL2 */ | ||
| 75 | #define WM8776_DEEMPH 0x001 | ||
| 76 | #define WM8776_DZFM_MASK 0x006 | ||
| 77 | #define WM8776_DZFM_NONE 0x000 | ||
| 78 | #define WM8776_DZFM_LR 0x002 | ||
| 79 | #define WM8776_DZFM_BOTH 0x004 | ||
| 80 | #define WM8776_DZFM_EITHER 0x006 | ||
| 81 | |||
| 82 | /* DACIFCTRL */ | ||
| 83 | #define WM8776_DACFMT_MASK 0x003 | ||
| 84 | #define WM8776_DACFMT_RJUST 0x000 | ||
| 85 | #define WM8776_DACFMT_LJUST 0x001 | ||
| 86 | #define WM8776_DACFMT_I2S 0x002 | ||
| 87 | #define WM8776_DACFMT_DSP 0x003 | ||
| 88 | #define WM8776_DACLRP 0x004 | ||
| 89 | #define WM8776_DACBCP 0x008 | ||
| 90 | #define WM8776_DACWL_MASK 0x030 | ||
| 91 | #define WM8776_DACWL_16 0x000 | ||
| 92 | #define WM8776_DACWL_20 0x010 | ||
| 93 | #define WM8776_DACWL_24 0x020 | ||
| 94 | #define WM8776_DACWL_32 0x030 | ||
| 95 | |||
| 96 | /* ADCIFCTRL */ | ||
| 97 | #define WM8776_ADCFMT_MASK 0x003 | ||
| 98 | #define WM8776_ADCFMT_RJUST 0x000 | ||
| 99 | #define WM8776_ADCFMT_LJUST 0x001 | ||
| 100 | #define WM8776_ADCFMT_I2S 0x002 | ||
| 101 | #define WM8776_ADCFMT_DSP 0x003 | ||
| 102 | #define WM8776_ADCLRP 0x004 | ||
| 103 | #define WM8776_ADCBCP 0x008 | ||
| 104 | #define WM8776_ADCWL_MASK 0x030 | ||
| 105 | #define WM8776_ADCWL_16 0x000 | ||
| 106 | #define WM8776_ADCWL_20 0x010 | ||
| 107 | #define WM8776_ADCWL_24 0x020 | ||
| 108 | #define WM8776_ADCWL_32 0x030 | ||
| 109 | #define WM8776_ADCMCLK 0x040 | ||
| 110 | #define WM8776_ADCHPD 0x100 | ||
| 111 | |||
| 112 | /* MSTRCTRL */ | ||
| 113 | #define WM8776_ADCRATE_MASK 0x007 | ||
| 114 | #define WM8776_ADCRATE_256 0x002 | ||
| 115 | #define WM8776_ADCRATE_384 0x003 | ||
| 116 | #define WM8776_ADCRATE_512 0x004 | ||
| 117 | #define WM8776_ADCRATE_768 0x005 | ||
| 118 | #define WM8776_ADCOSR 0x008 | ||
| 119 | #define WM8776_DACRATE_MASK 0x070 | ||
| 120 | #define WM8776_DACRATE_128 0x000 | ||
| 121 | #define WM8776_DACRATE_192 0x010 | ||
| 122 | #define WM8776_DACRATE_256 0x020 | ||
| 123 | #define WM8776_DACRATE_384 0x030 | ||
| 124 | #define WM8776_DACRATE_512 0x040 | ||
| 125 | #define WM8776_DACRATE_768 0x050 | ||
| 126 | #define WM8776_DACMS 0x080 | ||
| 127 | #define WM8776_ADCMS 0x100 | ||
| 128 | |||
| 129 | /* PWRDOWN */ | ||
| 130 | #define WM8776_PDWN 0x001 | ||
| 131 | #define WM8776_ADCPD 0x002 | ||
| 132 | #define WM8776_DACPD 0x004 | ||
| 133 | #define WM8776_HPPD 0x008 | ||
| 134 | #define WM8776_AINPD 0x040 | ||
| 135 | |||
| 136 | /* ADCLVOL/ADCRVOL */ | ||
| 137 | #define WM8776_AGMASK 0x0ff | ||
| 138 | #define WM8776_ZCA 0x100 | ||
| 139 | |||
| 140 | /* ALCCTRL1 */ | ||
| 141 | #define WM8776_LCT_MASK 0x00f | ||
| 142 | #define WM8776_MAXGAIN_MASK 0x070 | ||
| 143 | #define WM8776_LCSEL_MASK 0x180 | ||
| 144 | #define WM8776_LCSEL_LIMITER 0x000 | ||
| 145 | #define WM8776_LCSEL_ALC_RIGHT 0x080 | ||
| 146 | #define WM8776_LCSEL_ALC_LEFT 0x100 | ||
| 147 | #define WM8776_LCSEL_ALC_STEREO 0x180 | ||
| 148 | |||
| 149 | /* ALCCTRL2 */ | ||
| 150 | #define WM8776_HLD_MASK 0x00f | ||
| 151 | #define WM8776_ALCZC 0x080 | ||
| 152 | #define WM8776_LCEN 0x100 | ||
| 153 | |||
| 154 | /* ALCCTRL3 */ | ||
| 155 | #define WM8776_ATK_MASK 0x00f | ||
| 156 | #define WM8776_DCY_MASK 0x0f0 | ||
| 157 | |||
| 158 | /* NOISEGATE */ | ||
| 159 | #define WM8776_NGAT 0x001 | ||
| 160 | #define WM8776_NGTH_MASK 0x01c | ||
| 161 | |||
| 162 | /* LIMITER */ | ||
| 163 | #define WM8776_MAXATTEN_MASK 0x00f | ||
| 164 | #define WM8776_TRANWIN_MASK 0x070 | ||
| 165 | |||
| 166 | /* ADCMUX */ | ||
| 167 | #define WM8776_AMX_MASK 0x01f | ||
| 168 | #define WM8776_MUTERA 0x040 | ||
| 169 | #define WM8776_MUTELA 0x080 | ||
| 170 | #define WM8776_LRBOTH 0x100 | ||
| 171 | |||
| 172 | /* OUTMUX */ | ||
| 173 | #define WM8776_MX_DAC 0x001 | ||
| 174 | #define WM8776_MX_AUX 0x002 | ||
| 175 | #define WM8776_MX_BYPASS 0x004 | ||
| 176 | |||
| 177 | #endif | ||
diff --git a/sound/pci/oxygen/xonar.h b/sound/pci/oxygen/xonar.h index 89b3ed814d64..b35343b0a9a5 100644 --- a/sound/pci/oxygen/xonar.h +++ b/sound/pci/oxygen/xonar.h | |||
| @@ -35,6 +35,8 @@ int get_xonar_pcm179x_model(struct oxygen *chip, | |||
| 35 | const struct pci_device_id *id); | 35 | const struct pci_device_id *id); |
| 36 | int get_xonar_cs43xx_model(struct oxygen *chip, | 36 | int get_xonar_cs43xx_model(struct oxygen *chip, |
| 37 | const struct pci_device_id *id); | 37 | const struct pci_device_id *id); |
| 38 | int get_xonar_wm87x6_model(struct oxygen *chip, | ||
| 39 | const struct pci_device_id *id); | ||
| 38 | 40 | ||
| 39 | /* HDMI helper functions */ | 41 | /* HDMI helper functions */ |
| 40 | 42 | ||
diff --git a/sound/pci/oxygen/xonar_wm87x6.c b/sound/pci/oxygen/xonar_wm87x6.c new file mode 100644 index 000000000000..7754db166d9e --- /dev/null +++ b/sound/pci/oxygen/xonar_wm87x6.c | |||
| @@ -0,0 +1,1021 @@ | |||
| 1 | /* | ||
| 2 | * card driver for models with WM8776/WM8766 DACs (Xonar DS) | ||
| 3 | * | ||
| 4 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
| 5 | * | ||
| 6 | * | ||
| 7 | * This driver is free software; you can redistribute it and/or modify | ||
| 8 | * it under the terms of the GNU General Public License, version 2. | ||
| 9 | * | ||
| 10 | * This driver is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this driver; if not, see <http://www.gnu.org/licenses/>. | ||
| 17 | */ | ||
| 18 | |||
| 19 | /* | ||
| 20 | * Xonar DS | ||
| 21 | * -------- | ||
| 22 | * | ||
| 23 | * CMI8788: | ||
| 24 | * | ||
| 25 | * SPI 0 -> WM8766 (surround, center/LFE, back) | ||
| 26 | * SPI 1 -> WM8776 (front, input) | ||
| 27 | * | ||
| 28 | * GPIO 4 <- headphone detect | ||
| 29 | * GPIO 6 -> route input jack to input 1/2 (1/0) | ||
| 30 | * GPIO 7 -> enable output to speakers | ||
| 31 | * GPIO 8 -> enable output to speakers | ||
| 32 | */ | ||
| 33 | |||
| 34 | #include <linux/pci.h> | ||
| 35 | #include <linux/delay.h> | ||
| 36 | #include <sound/control.h> | ||
| 37 | #include <sound/core.h> | ||
| 38 | #include <sound/pcm.h> | ||
| 39 | #include <sound/pcm_params.h> | ||
| 40 | #include <sound/tlv.h> | ||
| 41 | #include "xonar.h" | ||
| 42 | #include "wm8776.h" | ||
| 43 | #include "wm8766.h" | ||
| 44 | |||
| 45 | #define GPIO_DS_HP_DETECT 0x0010 | ||
| 46 | #define GPIO_DS_INPUT_ROUTE 0x0040 | ||
| 47 | #define GPIO_DS_OUTPUT_ENABLE 0x0180 | ||
| 48 | |||
| 49 | #define LC_CONTROL_LIMITER 0x40000000 | ||
| 50 | #define LC_CONTROL_ALC 0x20000000 | ||
| 51 | |||
| 52 | struct xonar_wm87x6 { | ||
| 53 | struct xonar_generic generic; | ||
| 54 | u16 wm8776_regs[0x17]; | ||
| 55 | u16 wm8766_regs[0x10]; | ||
| 56 | struct snd_kcontrol *lc_controls[13]; | ||
| 57 | }; | ||
| 58 | |||
| 59 | static void wm8776_write(struct oxygen *chip, | ||
| 60 | unsigned int reg, unsigned int value) | ||
| 61 | { | ||
| 62 | struct xonar_wm87x6 *data = chip->model_data; | ||
| 63 | |||
| 64 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | | ||
| 65 | OXYGEN_SPI_DATA_LENGTH_2 | | ||
| 66 | OXYGEN_SPI_CLOCK_160 | | ||
| 67 | (1 << OXYGEN_SPI_CODEC_SHIFT) | | ||
| 68 | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, | ||
| 69 | (reg << 9) | value); | ||
| 70 | if (reg < ARRAY_SIZE(data->wm8776_regs)) { | ||
| 71 | if (reg >= WM8776_HPLVOL || reg <= WM8776_DACMASTER) | ||
| 72 | value &= ~WM8776_UPDATE; | ||
| 73 | data->wm8776_regs[reg] = value; | ||
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 77 | static void wm8776_write_cached(struct oxygen *chip, | ||
| 78 | unsigned int reg, unsigned int value) | ||
| 79 | { | ||
| 80 | struct xonar_wm87x6 *data = chip->model_data; | ||
| 81 | |||
| 82 | if (reg >= ARRAY_SIZE(data->wm8776_regs) || | ||
| 83 | value != data->wm8776_regs[reg]) | ||
| 84 | wm8776_write(chip, reg, value); | ||
| 85 | } | ||
| 86 | |||
| 87 | static void wm8766_write(struct oxygen *chip, | ||
| 88 | unsigned int reg, unsigned int value) | ||
| 89 | { | ||
| 90 | struct xonar_wm87x6 *data = chip->model_data; | ||
| 91 | |||
| 92 | oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER | | ||
| 93 | OXYGEN_SPI_DATA_LENGTH_2 | | ||
| 94 | OXYGEN_SPI_CLOCK_160 | | ||
| 95 | (0 << OXYGEN_SPI_CODEC_SHIFT) | | ||
| 96 | OXYGEN_SPI_CEN_LATCH_CLOCK_LO, | ||
| 97 | (reg << 9) | value); | ||
| 98 | if (reg < ARRAY_SIZE(data->wm8766_regs)) | ||
| 99 | data->wm8766_regs[reg] = value; | ||
| 100 | } | ||
| 101 | |||
| 102 | static void wm8766_write_cached(struct oxygen *chip, | ||
| 103 | unsigned int reg, unsigned int value) | ||
| 104 | { | ||
| 105 | struct xonar_wm87x6 *data = chip->model_data; | ||
| 106 | |||
| 107 | if (reg >= ARRAY_SIZE(data->wm8766_regs) || | ||
| 108 | value != data->wm8766_regs[reg]) { | ||
| 109 | if ((reg >= WM8766_LDA1 && reg <= WM8766_RDA1) || | ||
| 110 | (reg >= WM8766_LDA2 && reg <= WM8766_MASTDA)) | ||
| 111 | value &= ~WM8766_UPDATE; | ||
| 112 | wm8766_write(chip, reg, value); | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | static void wm8776_registers_init(struct oxygen *chip) | ||
| 117 | { | ||
| 118 | struct xonar_wm87x6 *data = chip->model_data; | ||
| 119 | |||
| 120 | wm8776_write(chip, WM8776_RESET, 0); | ||
| 121 | wm8776_write(chip, WM8776_DACCTRL1, WM8776_DZCEN | | ||
| 122 | WM8776_PL_LEFT_LEFT | WM8776_PL_RIGHT_RIGHT); | ||
| 123 | wm8776_write(chip, WM8776_DACMUTE, chip->dac_mute ? WM8776_DMUTE : 0); | ||
| 124 | wm8776_write(chip, WM8776_DACIFCTRL, | ||
| 125 | WM8776_DACFMT_LJUST | WM8776_DACWL_24); | ||
| 126 | wm8776_write(chip, WM8776_ADCIFCTRL, | ||
| 127 | data->wm8776_regs[WM8776_ADCIFCTRL]); | ||
| 128 | wm8776_write(chip, WM8776_MSTRCTRL, data->wm8776_regs[WM8776_MSTRCTRL]); | ||
| 129 | wm8776_write(chip, WM8776_PWRDOWN, data->wm8776_regs[WM8776_PWRDOWN]); | ||
| 130 | wm8776_write(chip, WM8776_HPLVOL, data->wm8776_regs[WM8776_HPLVOL]); | ||
| 131 | wm8776_write(chip, WM8776_HPRVOL, data->wm8776_regs[WM8776_HPRVOL] | | ||
| 132 | WM8776_UPDATE); | ||
| 133 | wm8776_write(chip, WM8776_ADCLVOL, data->wm8776_regs[WM8776_ADCLVOL]); | ||
| 134 | wm8776_write(chip, WM8776_ADCRVOL, data->wm8776_regs[WM8776_ADCRVOL]); | ||
| 135 | wm8776_write(chip, WM8776_ADCMUX, data->wm8776_regs[WM8776_ADCMUX]); | ||
| 136 | wm8776_write(chip, WM8776_DACLVOL, chip->dac_volume[0]); | ||
| 137 | wm8776_write(chip, WM8776_DACRVOL, chip->dac_volume[1] | WM8776_UPDATE); | ||
| 138 | } | ||
| 139 | |||
| 140 | static void wm8766_registers_init(struct oxygen *chip) | ||
| 141 | { | ||
| 142 | wm8766_write(chip, WM8766_RESET, 0); | ||
| 143 | wm8766_write(chip, WM8766_INT_CTRL, WM8766_FMT_LJUST | WM8766_IWL_24); | ||
| 144 | wm8766_write(chip, WM8766_DAC_CTRL2, | ||
| 145 | WM8766_ZCD | (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); | ||
| 146 | wm8766_write(chip, WM8766_LDA1, chip->dac_volume[2]); | ||
| 147 | wm8766_write(chip, WM8766_RDA1, chip->dac_volume[3]); | ||
| 148 | wm8766_write(chip, WM8766_LDA2, chip->dac_volume[4]); | ||
| 149 | wm8766_write(chip, WM8766_RDA2, chip->dac_volume[5]); | ||
| 150 | wm8766_write(chip, WM8766_LDA3, chip->dac_volume[6]); | ||
| 151 | wm8766_write(chip, WM8766_RDA3, chip->dac_volume[7] | WM8766_UPDATE); | ||
| 152 | } | ||
| 153 | |||
| 154 | static void wm8776_init(struct oxygen *chip) | ||
| 155 | { | ||
| 156 | struct xonar_wm87x6 *data = chip->model_data; | ||
| 157 | |||
| 158 | data->wm8776_regs[WM8776_HPLVOL] = (0x79 - 60) | WM8776_HPZCEN; | ||
| 159 | data->wm8776_regs[WM8776_HPRVOL] = (0x79 - 60) | WM8776_HPZCEN; | ||
| 160 | data->wm8776_regs[WM8776_ADCIFCTRL] = | ||
| 161 | WM8776_ADCFMT_LJUST | WM8776_ADCWL_24 | WM8776_ADCMCLK; | ||
| 162 | data->wm8776_regs[WM8776_MSTRCTRL] = | ||
| 163 | WM8776_ADCRATE_256 | WM8776_DACRATE_256; | ||
| 164 | data->wm8776_regs[WM8776_PWRDOWN] = WM8776_HPPD; | ||
| 165 | data->wm8776_regs[WM8776_ADCLVOL] = 0xa5 | WM8776_ZCA; | ||
| 166 | data->wm8776_regs[WM8776_ADCRVOL] = 0xa5 | WM8776_ZCA; | ||
| 167 | data->wm8776_regs[WM8776_ADCMUX] = 0x001; | ||
| 168 | wm8776_registers_init(chip); | ||
| 169 | } | ||
| 170 | |||
| 171 | static void xonar_ds_init(struct oxygen *chip) | ||
| 172 | { | ||
| 173 | struct xonar_wm87x6 *data = chip->model_data; | ||
| 174 | |||
| 175 | data->generic.anti_pop_delay = 300; | ||
| 176 | data->generic.output_enable_bit = GPIO_DS_OUTPUT_ENABLE; | ||
| 177 | |||
| 178 | wm8776_init(chip); | ||
| 179 | wm8766_registers_init(chip); | ||
| 180 | |||
| 181 | oxygen_write16_masked(chip, OXYGEN_GPIO_CONTROL, GPIO_DS_INPUT_ROUTE, | ||
| 182 | GPIO_DS_HP_DETECT | GPIO_DS_INPUT_ROUTE); | ||
| 183 | oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_DS_INPUT_ROUTE); | ||
| 184 | oxygen_set_bits16(chip, OXYGEN_GPIO_INTERRUPT_MASK, GPIO_DS_HP_DETECT); | ||
| 185 | chip->interrupt_mask |= OXYGEN_INT_GPIO; | ||
| 186 | |||
| 187 | xonar_enable_output(chip); | ||
| 188 | |||
| 189 | snd_component_add(chip->card, "WM8776"); | ||
| 190 | snd_component_add(chip->card, "WM8766"); | ||
| 191 | } | ||
| 192 | |||
| 193 | static void xonar_ds_cleanup(struct oxygen *chip) | ||
| 194 | { | ||
| 195 | xonar_disable_output(chip); | ||
| 196 | } | ||
| 197 | |||
| 198 | static void xonar_ds_suspend(struct oxygen *chip) | ||
| 199 | { | ||
| 200 | xonar_ds_cleanup(chip); | ||
| 201 | } | ||
| 202 | |||
| 203 | static void xonar_ds_resume(struct oxygen *chip) | ||
| 204 | { | ||
| 205 | wm8776_registers_init(chip); | ||
| 206 | wm8766_registers_init(chip); | ||
| 207 | xonar_enable_output(chip); | ||
| 208 | } | ||
| 209 | |||
| 210 | static void wm8776_adc_hardware_filter(unsigned int channel, | ||
| 211 | struct snd_pcm_hardware *hardware) | ||
| 212 | { | ||
| 213 | if (channel == PCM_A) { | ||
| 214 | hardware->rates = SNDRV_PCM_RATE_32000 | | ||
| 215 | SNDRV_PCM_RATE_44100 | | ||
| 216 | SNDRV_PCM_RATE_48000 | | ||
| 217 | SNDRV_PCM_RATE_64000 | | ||
| 218 | SNDRV_PCM_RATE_88200 | | ||
| 219 | SNDRV_PCM_RATE_96000; | ||
| 220 | hardware->rate_max = 96000; | ||
| 221 | } | ||
| 222 | } | ||
| 223 | |||
| 224 | static void set_wm87x6_dac_params(struct oxygen *chip, | ||
| 225 | struct snd_pcm_hw_params *params) | ||
| 226 | { | ||
| 227 | } | ||
| 228 | |||
| 229 | static void set_wm8776_adc_params(struct oxygen *chip, | ||
| 230 | struct snd_pcm_hw_params *params) | ||
| 231 | { | ||
| 232 | u16 reg; | ||
| 233 | |||
| 234 | reg = WM8776_ADCRATE_256 | WM8776_DACRATE_256; | ||
| 235 | if (params_rate(params) > 48000) | ||
| 236 | reg |= WM8776_ADCOSR; | ||
| 237 | wm8776_write_cached(chip, WM8776_MSTRCTRL, reg); | ||
| 238 | } | ||
| 239 | |||
| 240 | static void update_wm8776_volume(struct oxygen *chip) | ||
| 241 | { | ||
| 242 | struct xonar_wm87x6 *data = chip->model_data; | ||
| 243 | u8 to_change; | ||
| 244 | |||
| 245 | if (chip->dac_volume[0] == chip->dac_volume[1]) { | ||
| 246 | if (chip->dac_volume[0] != data->wm8776_regs[WM8776_DACLVOL] || | ||
| 247 | chip->dac_volume[1] != data->wm8776_regs[WM8776_DACRVOL]) { | ||
| 248 | wm8776_write(chip, WM8776_DACMASTER, | ||
| 249 | chip->dac_volume[0] | WM8776_UPDATE); | ||
| 250 | data->wm8776_regs[WM8776_DACLVOL] = chip->dac_volume[0]; | ||
| 251 | data->wm8776_regs[WM8776_DACRVOL] = chip->dac_volume[0]; | ||
| 252 | } | ||
| 253 | } else { | ||
| 254 | to_change = (chip->dac_volume[0] != | ||
| 255 | data->wm8776_regs[WM8776_DACLVOL]) << 0; | ||
| 256 | to_change |= (chip->dac_volume[1] != | ||
| 257 | data->wm8776_regs[WM8776_DACLVOL]) << 1; | ||
| 258 | if (to_change & 1) | ||
| 259 | wm8776_write(chip, WM8776_DACLVOL, chip->dac_volume[0] | | ||
| 260 | ((to_change & 2) ? 0 : WM8776_UPDATE)); | ||
| 261 | if (to_change & 2) | ||
| 262 | wm8776_write(chip, WM8776_DACRVOL, | ||
| 263 | chip->dac_volume[1] | WM8776_UPDATE); | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | static void update_wm87x6_volume(struct oxygen *chip) | ||
| 268 | { | ||
| 269 | static const u8 wm8766_regs[6] = { | ||
| 270 | WM8766_LDA1, WM8766_RDA1, | ||
| 271 | WM8766_LDA2, WM8766_RDA2, | ||
| 272 | WM8766_LDA3, WM8766_RDA3, | ||
| 273 | }; | ||
| 274 | struct xonar_wm87x6 *data = chip->model_data; | ||
| 275 | unsigned int i; | ||
| 276 | u8 to_change; | ||
| 277 | |||
| 278 | update_wm8776_volume(chip); | ||
| 279 | if (chip->dac_volume[2] == chip->dac_volume[3] && | ||
| 280 | chip->dac_volume[2] == chip->dac_volume[4] && | ||
| 281 | chip->dac_volume[2] == chip->dac_volume[5] && | ||
| 282 | chip->dac_volume[2] == chip->dac_volume[6] && | ||
| 283 | chip->dac_volume[2] == chip->dac_volume[7]) { | ||
| 284 | to_change = 0; | ||
| 285 | for (i = 0; i < 6; ++i) | ||
| 286 | if (chip->dac_volume[2] != | ||
| 287 | data->wm8766_regs[wm8766_regs[i]]) | ||
| 288 | to_change = 1; | ||
| 289 | if (to_change) { | ||
| 290 | wm8766_write(chip, WM8766_MASTDA, | ||
| 291 | chip->dac_volume[2] | WM8766_UPDATE); | ||
| 292 | for (i = 0; i < 6; ++i) | ||
| 293 | data->wm8766_regs[wm8766_regs[i]] = | ||
| 294 | chip->dac_volume[2]; | ||
| 295 | } | ||
| 296 | } else { | ||
| 297 | to_change = 0; | ||
| 298 | for (i = 0; i < 6; ++i) | ||
| 299 | to_change |= (chip->dac_volume[2 + i] != | ||
| 300 | data->wm8766_regs[wm8766_regs[i]]) << i; | ||
| 301 | for (i = 0; i < 6; ++i) | ||
| 302 | if (to_change & (1 << i)) | ||
| 303 | wm8766_write(chip, wm8766_regs[i], | ||
| 304 | chip->dac_volume[2 + i] | | ||
| 305 | ((to_change & (0x3e << i)) | ||
| 306 | ? 0 : WM8766_UPDATE)); | ||
| 307 | } | ||
| 308 | } | ||
| 309 | |||
| 310 | static void update_wm8776_mute(struct oxygen *chip) | ||
| 311 | { | ||
| 312 | wm8776_write_cached(chip, WM8776_DACMUTE, | ||
| 313 | chip->dac_mute ? WM8776_DMUTE : 0); | ||
| 314 | } | ||
| 315 | |||
| 316 | static void update_wm87x6_mute(struct oxygen *chip) | ||
| 317 | { | ||
| 318 | update_wm8776_mute(chip); | ||
| 319 | wm8766_write_cached(chip, WM8766_DAC_CTRL2, WM8766_ZCD | | ||
| 320 | (chip->dac_mute ? WM8766_DMUTE_MASK : 0)); | ||
| 321 | } | ||
| 322 | |||
| 323 | static void xonar_ds_gpio_changed(struct oxygen *chip) | ||
| 324 | { | ||
| 325 | u16 bits; | ||
| 326 | |||
| 327 | bits = oxygen_read16(chip, OXYGEN_GPIO_DATA); | ||
| 328 | snd_printk(KERN_INFO "HP detect: %d\n", !!(bits & GPIO_DS_HP_DETECT)); | ||
| 329 | } | ||
| 330 | |||
| 331 | static int wm8776_bit_switch_get(struct snd_kcontrol *ctl, | ||
| 332 | struct snd_ctl_elem_value *value) | ||
| 333 | { | ||
| 334 | struct oxygen *chip = ctl->private_data; | ||
| 335 | struct xonar_wm87x6 *data = chip->model_data; | ||
| 336 | u16 bit = ctl->private_value & 0xffff; | ||
| 337 | unsigned int reg_index = (ctl->private_value >> 16) & 0xff; | ||
| 338 | bool invert = (ctl->private_value >> 24) & 1; | ||
| 339 | |||
| 340 | value->value.integer.value[0] = | ||
| 341 | ((data->wm8776_regs[reg_index] & bit) != 0) ^ invert; | ||
| 342 | return 0; | ||
| 343 | } | ||
| 344 | |||
| 345 | static int wm8776_bit_switch_put(struct snd_kcontrol *ctl, | ||
| 346 | struct snd_ctl_elem_value *value) | ||
| 347 | { | ||
| 348 | struct oxygen *chip = ctl->private_data; | ||
| 349 | struct xonar_wm87x6 *data = chip->model_data; | ||
| 350 | u16 bit = ctl->private_value & 0xffff; | ||
| 351 | u16 reg_value; | ||
| 352 | unsigned int reg_index = (ctl->private_value >> 16) & 0xff; | ||
| 353 | bool invert = (ctl->private_value >> 24) & 1; | ||
| 354 | int changed; | ||
| 355 | |||
| 356 | mutex_lock(&chip->mutex); | ||
| 357 | reg_value = data->wm8776_regs[reg_index] & ~bit; | ||
| 358 | if (value->value.integer.value[0] ^ invert) | ||
| 359 | reg_value |= bit; | ||
| 360 | changed = reg_value != data->wm8776_regs[reg_index]; | ||
| 361 | if (changed) | ||
| 362 | wm8776_write(chip, reg_index, reg_value); | ||
| 363 | mutex_unlock(&chip->mutex); | ||
| 364 | return changed; | ||
| 365 | } | ||
| 366 | |||
| 367 | static int wm8776_field_enum_info(struct snd_kcontrol *ctl, | ||
| 368 | struct snd_ctl_elem_info *info) | ||
| 369 | { | ||
| 370 | static const char *const hld[16] = { | ||
| 371 | "0 ms", "2.67 ms", "5.33 ms", "10.6 ms", | ||
| 372 | "21.3 ms", "42.7 ms", "85.3 ms", "171 ms", | ||
| 373 | "341 ms", "683 ms", "1.37 s", "2.73 s", | ||
| 374 | "5.46 s", "10.9 s", "21.8 s", "43.7 s", | ||
| 375 | }; | ||
| 376 | static const char *const atk_lim[11] = { | ||
| 377 | "0.25 ms", "0.5 ms", "1 ms", "2 ms", | ||
| 378 | "4 ms", "8 ms", "16 ms", "32 ms", | ||
| 379 | "64 ms", "128 ms", "256 ms", | ||
| 380 | }; | ||
| 381 | static const char *const atk_alc[11] = { | ||
| 382 | "8.40 ms", "16.8 ms", "33.6 ms", "67.2 ms", | ||
| 383 | "134 ms", "269 ms", "538 ms", "1.08 s", | ||
| 384 | "2.15 s", "4.3 s", "8.6 s", | ||
| 385 | }; | ||
| 386 | static const char *const dcy_lim[11] = { | ||
| 387 | "1.2 ms", "2.4 ms", "4.8 ms", "9.6 ms", | ||
| 388 | "19.2 ms", "38.4 ms", "76.8 ms", "154 ms", | ||
| 389 | "307 ms", "614 ms", "1.23 s", | ||
| 390 | }; | ||
| 391 | static const char *const dcy_alc[11] = { | ||
| 392 | "33.5 ms", "67.0 ms", "134 ms", "268 ms", | ||
| 393 | "536 ms", "1.07 s", "2.14 s", "4.29 s", | ||
| 394 | "8.58 s", "17.2 s", "34.3 s", | ||
| 395 | }; | ||
| 396 | static const char *const tranwin[8] = { | ||
| 397 | "0 us", "62.5 us", "125 us", "250 us", | ||
| 398 | "500 us", "1 ms", "2 ms", "4 ms", | ||
| 399 | }; | ||
| 400 | u8 max; | ||
| 401 | const char *const *names; | ||
| 402 | |||
| 403 | max = (ctl->private_value >> 12) & 0xf; | ||
| 404 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
| 405 | info->count = 1; | ||
| 406 | info->value.enumerated.items = max + 1; | ||
| 407 | if (info->value.enumerated.item > max) | ||
| 408 | info->value.enumerated.item = max; | ||
| 409 | switch ((ctl->private_value >> 24) & 0x1f) { | ||
| 410 | case WM8776_ALCCTRL2: | ||
| 411 | names = hld; | ||
| 412 | break; | ||
| 413 | case WM8776_ALCCTRL3: | ||
| 414 | if (((ctl->private_value >> 20) & 0xf) == 0) { | ||
| 415 | if (ctl->private_value & LC_CONTROL_LIMITER) | ||
| 416 | names = atk_lim; | ||
| 417 | else | ||
| 418 | names = atk_alc; | ||
| 419 | } else { | ||
| 420 | if (ctl->private_value & LC_CONTROL_LIMITER) | ||
| 421 | names = dcy_lim; | ||
| 422 | else | ||
| 423 | names = dcy_alc; | ||
| 424 | } | ||
| 425 | break; | ||
| 426 | case WM8776_LIMITER: | ||
| 427 | names = tranwin; | ||
| 428 | break; | ||
| 429 | default: | ||
| 430 | return -ENXIO; | ||
| 431 | } | ||
| 432 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
| 433 | return 0; | ||
| 434 | } | ||
| 435 | |||
| 436 | static int wm8776_field_volume_info(struct snd_kcontrol *ctl, | ||
| 437 | struct snd_ctl_elem_info *info) | ||
| 438 | { | ||
| 439 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
| 440 | info->count = 1; | ||
| 441 | info->value.integer.min = (ctl->private_value >> 8) & 0xf; | ||
| 442 | info->value.integer.max = (ctl->private_value >> 12) & 0xf; | ||
| 443 | return 0; | ||
| 444 | } | ||
| 445 | |||
| 446 | static void wm8776_field_set_from_ctl(struct snd_kcontrol *ctl) | ||
| 447 | { | ||
| 448 | struct oxygen *chip = ctl->private_data; | ||
| 449 | struct xonar_wm87x6 *data = chip->model_data; | ||
| 450 | unsigned int value, reg_index, mode; | ||
| 451 | u8 min, max, shift; | ||
| 452 | u16 mask, reg_value; | ||
| 453 | bool invert; | ||
| 454 | |||
| 455 | if ((data->wm8776_regs[WM8776_ALCCTRL1] & WM8776_LCSEL_MASK) == | ||
| 456 | WM8776_LCSEL_LIMITER) | ||
| 457 | mode = LC_CONTROL_LIMITER; | ||
| 458 | else | ||
| 459 | mode = LC_CONTROL_ALC; | ||
| 460 | if (!(ctl->private_value & mode)) | ||
| 461 | return; | ||
| 462 | |||
| 463 | value = ctl->private_value & 0xf; | ||
| 464 | min = (ctl->private_value >> 8) & 0xf; | ||
| 465 | max = (ctl->private_value >> 12) & 0xf; | ||
| 466 | mask = (ctl->private_value >> 16) & 0xf; | ||
| 467 | shift = (ctl->private_value >> 20) & 0xf; | ||
| 468 | reg_index = (ctl->private_value >> 24) & 0x1f; | ||
| 469 | invert = (ctl->private_value >> 29) & 0x1; | ||
| 470 | |||
| 471 | if (invert) | ||
| 472 | value = max - (value - min); | ||
| 473 | reg_value = data->wm8776_regs[reg_index]; | ||
| 474 | reg_value &= ~(mask << shift); | ||
| 475 | reg_value |= value << shift; | ||
| 476 | wm8776_write_cached(chip, reg_index, reg_value); | ||
| 477 | } | ||
| 478 | |||
| 479 | static int wm8776_field_set(struct snd_kcontrol *ctl, unsigned int value) | ||
| 480 | { | ||
| 481 | struct oxygen *chip = ctl->private_data; | ||
| 482 | u8 min, max; | ||
| 483 | int changed; | ||
| 484 | |||
| 485 | min = (ctl->private_value >> 8) & 0xf; | ||
| 486 | max = (ctl->private_value >> 12) & 0xf; | ||
| 487 | if (value < min || value > max) | ||
| 488 | return -EINVAL; | ||
| 489 | mutex_lock(&chip->mutex); | ||
| 490 | changed = value != (ctl->private_value & 0xf); | ||
| 491 | if (changed) { | ||
| 492 | ctl->private_value = (ctl->private_value & ~0xf) | value; | ||
| 493 | wm8776_field_set_from_ctl(ctl); | ||
| 494 | } | ||
| 495 | mutex_unlock(&chip->mutex); | ||
| 496 | return changed; | ||
| 497 | } | ||
| 498 | |||
| 499 | static int wm8776_field_enum_get(struct snd_kcontrol *ctl, | ||
| 500 | struct snd_ctl_elem_value *value) | ||
| 501 | { | ||
| 502 | value->value.enumerated.item[0] = ctl->private_value & 0xf; | ||
| 503 | return 0; | ||
| 504 | } | ||
| 505 | |||
| 506 | static int wm8776_field_volume_get(struct snd_kcontrol *ctl, | ||
| 507 | struct snd_ctl_elem_value *value) | ||
| 508 | { | ||
| 509 | value->value.integer.value[0] = ctl->private_value & 0xf; | ||
| 510 | return 0; | ||
| 511 | } | ||
| 512 | |||
| 513 | static int wm8776_field_enum_put(struct snd_kcontrol *ctl, | ||
| 514 | struct snd_ctl_elem_value *value) | ||
| 515 | { | ||
| 516 | return wm8776_field_set(ctl, value->value.enumerated.item[0]); | ||
| 517 | } | ||
| 518 | |||
| 519 | static int wm8776_field_volume_put(struct snd_kcontrol *ctl, | ||
| 520 | struct snd_ctl_elem_value *value) | ||
| 521 | { | ||
| 522 | return wm8776_field_set(ctl, value->value.integer.value[0]); | ||
| 523 | } | ||
| 524 | |||
| 525 | static int wm8776_hp_vol_info(struct snd_kcontrol *ctl, | ||
| 526 | struct snd_ctl_elem_info *info) | ||
| 527 | { | ||
| 528 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
| 529 | info->count = 2; | ||
| 530 | info->value.integer.min = 0x79 - 60; | ||
| 531 | info->value.integer.max = 0x7f; | ||
| 532 | return 0; | ||
| 533 | } | ||
| 534 | |||
| 535 | static int wm8776_hp_vol_get(struct snd_kcontrol *ctl, | ||
| 536 | struct snd_ctl_elem_value *value) | ||
| 537 | { | ||
| 538 | struct oxygen *chip = ctl->private_data; | ||
| 539 | struct xonar_wm87x6 *data = chip->model_data; | ||
| 540 | |||
| 541 | mutex_lock(&chip->mutex); | ||
| 542 | value->value.integer.value[0] = | ||
| 543 | data->wm8776_regs[WM8776_HPLVOL] & WM8776_HPATT_MASK; | ||
| 544 | value->value.integer.value[1] = | ||
| 545 | data->wm8776_regs[WM8776_HPRVOL] & WM8776_HPATT_MASK; | ||
| 546 | mutex_unlock(&chip->mutex); | ||
| 547 | return 0; | ||
| 548 | } | ||
| 549 | |||
| 550 | static int wm8776_hp_vol_put(struct snd_kcontrol *ctl, | ||
| 551 | struct snd_ctl_elem_value *value) | ||
| 552 | { | ||
| 553 | struct oxygen *chip = ctl->private_data; | ||
| 554 | struct xonar_wm87x6 *data = chip->model_data; | ||
| 555 | u8 to_update; | ||
| 556 | |||
| 557 | mutex_lock(&chip->mutex); | ||
| 558 | to_update = (value->value.integer.value[0] != | ||
| 559 | (data->wm8776_regs[WM8776_HPLVOL] & WM8776_HPATT_MASK)) | ||
| 560 | << 0; | ||
| 561 | to_update |= (value->value.integer.value[1] != | ||
| 562 | (data->wm8776_regs[WM8776_HPRVOL] & WM8776_HPATT_MASK)) | ||
| 563 | << 1; | ||
| 564 | if (value->value.integer.value[0] == value->value.integer.value[1]) { | ||
| 565 | if (to_update) { | ||
| 566 | wm8776_write(chip, WM8776_HPMASTER, | ||
| 567 | value->value.integer.value[0] | | ||
| 568 | WM8776_HPZCEN | WM8776_UPDATE); | ||
| 569 | data->wm8776_regs[WM8776_HPLVOL] = | ||
| 570 | value->value.integer.value[0] | WM8776_HPZCEN; | ||
| 571 | data->wm8776_regs[WM8776_HPRVOL] = | ||
| 572 | value->value.integer.value[0] | WM8776_HPZCEN; | ||
| 573 | } | ||
| 574 | } else { | ||
| 575 | if (to_update & 1) | ||
| 576 | wm8776_write(chip, WM8776_HPLVOL, | ||
| 577 | value->value.integer.value[0] | | ||
| 578 | WM8776_HPZCEN | | ||
| 579 | ((to_update & 2) ? 0 : WM8776_UPDATE)); | ||
| 580 | if (to_update & 2) | ||
| 581 | wm8776_write(chip, WM8776_HPRVOL, | ||
| 582 | value->value.integer.value[1] | | ||
| 583 | WM8776_HPZCEN | WM8776_UPDATE); | ||
| 584 | } | ||
| 585 | mutex_unlock(&chip->mutex); | ||
| 586 | return to_update != 0; | ||
| 587 | } | ||
| 588 | |||
| 589 | static int wm8776_input_mux_get(struct snd_kcontrol *ctl, | ||
| 590 | struct snd_ctl_elem_value *value) | ||
| 591 | { | ||
| 592 | struct oxygen *chip = ctl->private_data; | ||
| 593 | struct xonar_wm87x6 *data = chip->model_data; | ||
| 594 | unsigned int mux_bit = ctl->private_value; | ||
| 595 | |||
| 596 | value->value.integer.value[0] = | ||
| 597 | !!(data->wm8776_regs[WM8776_ADCMUX] & mux_bit); | ||
| 598 | return 0; | ||
| 599 | } | ||
| 600 | |||
| 601 | static int wm8776_input_mux_put(struct snd_kcontrol *ctl, | ||
| 602 | struct snd_ctl_elem_value *value) | ||
| 603 | { | ||
| 604 | struct oxygen *chip = ctl->private_data; | ||
| 605 | struct xonar_wm87x6 *data = chip->model_data; | ||
| 606 | unsigned int mux_bit = ctl->private_value; | ||
| 607 | u16 reg; | ||
| 608 | int changed; | ||
| 609 | |||
| 610 | mutex_lock(&chip->mutex); | ||
| 611 | reg = data->wm8776_regs[WM8776_ADCMUX]; | ||
| 612 | if (value->value.integer.value[0]) { | ||
| 613 | reg &= ~0x003; | ||
| 614 | reg |= mux_bit; | ||
| 615 | } else | ||
| 616 | reg &= ~mux_bit; | ||
| 617 | changed = reg != data->wm8776_regs[WM8776_ADCMUX]; | ||
| 618 | if (changed) { | ||
| 619 | oxygen_write16_masked(chip, OXYGEN_GPIO_DATA, | ||
| 620 | reg & 1 ? GPIO_DS_INPUT_ROUTE : 0, | ||
| 621 | GPIO_DS_INPUT_ROUTE); | ||
| 622 | wm8776_write(chip, WM8776_ADCMUX, reg); | ||
| 623 | } | ||
| 624 | mutex_unlock(&chip->mutex); | ||
| 625 | return changed; | ||
| 626 | } | ||
| 627 | |||
| 628 | static int wm8776_input_vol_info(struct snd_kcontrol *ctl, | ||
| 629 | struct snd_ctl_elem_info *info) | ||
| 630 | { | ||
| 631 | info->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
| 632 | info->count = 2; | ||
| 633 | info->value.integer.min = 0xa5; | ||
| 634 | info->value.integer.max = 0xff; | ||
| 635 | return 0; | ||
| 636 | } | ||
| 637 | |||
| 638 | static int wm8776_input_vol_get(struct snd_kcontrol *ctl, | ||
| 639 | struct snd_ctl_elem_value *value) | ||
| 640 | { | ||
| 641 | struct oxygen *chip = ctl->private_data; | ||
| 642 | struct xonar_wm87x6 *data = chip->model_data; | ||
| 643 | |||
| 644 | mutex_lock(&chip->mutex); | ||
| 645 | value->value.integer.value[0] = | ||
| 646 | data->wm8776_regs[WM8776_ADCLVOL] & WM8776_AGMASK; | ||
| 647 | value->value.integer.value[1] = | ||
| 648 | data->wm8776_regs[WM8776_ADCRVOL] & WM8776_AGMASK; | ||
| 649 | mutex_unlock(&chip->mutex); | ||
| 650 | return 0; | ||
| 651 | } | ||
| 652 | |||
| 653 | static int wm8776_input_vol_put(struct snd_kcontrol *ctl, | ||
| 654 | struct snd_ctl_elem_value *value) | ||
| 655 | { | ||
| 656 | struct oxygen *chip = ctl->private_data; | ||
| 657 | struct xonar_wm87x6 *data = chip->model_data; | ||
| 658 | int changed = 0; | ||
| 659 | |||
| 660 | mutex_lock(&chip->mutex); | ||
| 661 | changed = (value->value.integer.value[0] != | ||
| 662 | (data->wm8776_regs[WM8776_ADCLVOL] & WM8776_AGMASK)) || | ||
| 663 | (value->value.integer.value[1] != | ||
| 664 | (data->wm8776_regs[WM8776_ADCRVOL] & WM8776_AGMASK)); | ||
| 665 | wm8776_write_cached(chip, WM8776_ADCLVOL, | ||
| 666 | value->value.integer.value[0] | WM8776_ZCA); | ||
| 667 | wm8776_write_cached(chip, WM8776_ADCRVOL, | ||
| 668 | value->value.integer.value[1] | WM8776_ZCA); | ||
| 669 | mutex_unlock(&chip->mutex); | ||
| 670 | return changed; | ||
| 671 | } | ||
| 672 | |||
| 673 | static int wm8776_level_control_info(struct snd_kcontrol *ctl, | ||
| 674 | struct snd_ctl_elem_info *info) | ||
| 675 | { | ||
| 676 | static const char *const names[3] = { | ||
| 677 | "None", "Peak Limiter", "Automatic Level Control" | ||
| 678 | }; | ||
| 679 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
| 680 | info->count = 1; | ||
| 681 | info->value.enumerated.items = 3; | ||
| 682 | if (info->value.enumerated.item >= 3) | ||
| 683 | info->value.enumerated.item = 2; | ||
| 684 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
| 685 | return 0; | ||
| 686 | } | ||
| 687 | |||
| 688 | static int wm8776_level_control_get(struct snd_kcontrol *ctl, | ||
| 689 | struct snd_ctl_elem_value *value) | ||
| 690 | { | ||
| 691 | struct oxygen *chip = ctl->private_data; | ||
| 692 | struct xonar_wm87x6 *data = chip->model_data; | ||
| 693 | |||
| 694 | if (!(data->wm8776_regs[WM8776_ALCCTRL2] & WM8776_LCEN)) | ||
| 695 | value->value.enumerated.item[0] = 0; | ||
| 696 | else if ((data->wm8776_regs[WM8776_ALCCTRL1] & WM8776_LCSEL_MASK) == | ||
| 697 | WM8776_LCSEL_LIMITER) | ||
| 698 | value->value.enumerated.item[0] = 1; | ||
| 699 | else | ||
| 700 | value->value.enumerated.item[0] = 2; | ||
| 701 | return 0; | ||
| 702 | } | ||
| 703 | |||
| 704 | static void activate_control(struct oxygen *chip, | ||
| 705 | struct snd_kcontrol *ctl, unsigned int mode) | ||
| 706 | { | ||
| 707 | unsigned int access; | ||
| 708 | |||
| 709 | if (ctl->private_value & mode) | ||
| 710 | access = 0; | ||
| 711 | else | ||
| 712 | access = SNDRV_CTL_ELEM_ACCESS_INACTIVE; | ||
| 713 | if ((ctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_INACTIVE) != access) { | ||
| 714 | ctl->vd[0].access ^= SNDRV_CTL_ELEM_ACCESS_INACTIVE; | ||
| 715 | snd_ctl_notify(chip->card, SNDRV_CTL_EVENT_MASK_INFO, &ctl->id); | ||
| 716 | } | ||
| 717 | } | ||
| 718 | |||
| 719 | static int wm8776_level_control_put(struct snd_kcontrol *ctl, | ||
| 720 | struct snd_ctl_elem_value *value) | ||
| 721 | { | ||
| 722 | struct oxygen *chip = ctl->private_data; | ||
| 723 | struct xonar_wm87x6 *data = chip->model_data; | ||
| 724 | unsigned int mode = 0, i; | ||
| 725 | u16 ctrl1, ctrl2; | ||
| 726 | int changed; | ||
| 727 | |||
| 728 | if (value->value.enumerated.item[0] >= 3) | ||
| 729 | return -EINVAL; | ||
| 730 | mutex_lock(&chip->mutex); | ||
| 731 | changed = value->value.enumerated.item[0] != ctl->private_value; | ||
| 732 | if (changed) { | ||
| 733 | ctl->private_value = value->value.enumerated.item[0]; | ||
| 734 | ctrl1 = data->wm8776_regs[WM8776_ALCCTRL1]; | ||
| 735 | ctrl2 = data->wm8776_regs[WM8776_ALCCTRL2]; | ||
| 736 | switch (value->value.enumerated.item[0]) { | ||
| 737 | default: | ||
| 738 | wm8776_write_cached(chip, WM8776_ALCCTRL2, | ||
| 739 | ctrl2 & ~WM8776_LCEN); | ||
| 740 | break; | ||
| 741 | case 1: | ||
| 742 | wm8776_write_cached(chip, WM8776_ALCCTRL1, | ||
| 743 | (ctrl1 & ~WM8776_LCSEL_MASK) | | ||
| 744 | WM8776_LCSEL_LIMITER); | ||
| 745 | wm8776_write_cached(chip, WM8776_ALCCTRL2, | ||
| 746 | ctrl2 | WM8776_LCEN); | ||
| 747 | mode = LC_CONTROL_LIMITER; | ||
| 748 | break; | ||
| 749 | case 2: | ||
| 750 | wm8776_write_cached(chip, WM8776_ALCCTRL1, | ||
| 751 | (ctrl1 & ~WM8776_LCSEL_MASK) | | ||
| 752 | WM8776_LCSEL_ALC_STEREO); | ||
| 753 | wm8776_write_cached(chip, WM8776_ALCCTRL2, | ||
| 754 | ctrl2 | WM8776_LCEN); | ||
| 755 | mode = LC_CONTROL_ALC; | ||
| 756 | break; | ||
| 757 | } | ||
| 758 | for (i = 0; i < ARRAY_SIZE(data->lc_controls); ++i) | ||
| 759 | activate_control(chip, data->lc_controls[i], mode); | ||
| 760 | } | ||
| 761 | mutex_unlock(&chip->mutex); | ||
| 762 | return changed; | ||
| 763 | } | ||
| 764 | |||
| 765 | static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info) | ||
| 766 | { | ||
| 767 | static const char *const names[2] = { | ||
| 768 | "None", "High-pass Filter" | ||
| 769 | }; | ||
| 770 | |||
| 771 | info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
| 772 | info->count = 1; | ||
| 773 | info->value.enumerated.items = 2; | ||
| 774 | if (info->value.enumerated.item >= 2) | ||
| 775 | info->value.enumerated.item = 1; | ||
| 776 | strcpy(info->value.enumerated.name, names[info->value.enumerated.item]); | ||
| 777 | return 0; | ||
| 778 | } | ||
| 779 | |||
| 780 | static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) | ||
| 781 | { | ||
| 782 | struct oxygen *chip = ctl->private_data; | ||
| 783 | struct xonar_wm87x6 *data = chip->model_data; | ||
| 784 | |||
| 785 | value->value.enumerated.item[0] = | ||
| 786 | !(data->wm8776_regs[WM8776_ADCIFCTRL] & WM8776_ADCHPD); | ||
| 787 | return 0; | ||
| 788 | } | ||
| 789 | |||
| 790 | static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value) | ||
| 791 | { | ||
| 792 | struct oxygen *chip = ctl->private_data; | ||
| 793 | struct xonar_wm87x6 *data = chip->model_data; | ||
| 794 | unsigned int reg; | ||
| 795 | int changed; | ||
| 796 | |||
| 797 | mutex_lock(&chip->mutex); | ||
| 798 | reg = data->wm8776_regs[WM8776_ADCIFCTRL] & ~WM8776_ADCHPD; | ||
| 799 | if (!value->value.enumerated.item[0]) | ||
| 800 | reg |= WM8776_ADCHPD; | ||
| 801 | changed = reg != data->wm8776_regs[WM8776_ADCIFCTRL]; | ||
| 802 | if (changed) | ||
| 803 | wm8776_write(chip, WM8776_ADCIFCTRL, reg); | ||
| 804 | mutex_unlock(&chip->mutex); | ||
| 805 | return changed; | ||
| 806 | } | ||
| 807 | |||
| 808 | #define WM8776_BIT_SWITCH(xname, reg, bit, invert, flags) { \ | ||
| 809 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
| 810 | .name = xname, \ | ||
| 811 | .info = snd_ctl_boolean_mono_info, \ | ||
| 812 | .get = wm8776_bit_switch_get, \ | ||
| 813 | .put = wm8776_bit_switch_put, \ | ||
| 814 | .private_value = ((reg) << 16) | (bit) | ((invert) << 24) | (flags), \ | ||
| 815 | } | ||
| 816 | #define _WM8776_FIELD_CTL(xname, reg, shift, initval, min, max, mask, flags) \ | ||
| 817 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
| 818 | .name = xname, \ | ||
| 819 | .private_value = (initval) | ((min) << 8) | ((max) << 12) | \ | ||
| 820 | ((mask) << 16) | ((shift) << 20) | ((reg) << 24) | (flags) | ||
| 821 | #define WM8776_FIELD_CTL_ENUM(xname, reg, shift, init, min, max, mask, flags) {\ | ||
| 822 | _WM8776_FIELD_CTL(xname " Capture Enum", \ | ||
| 823 | reg, shift, init, min, max, mask, flags), \ | ||
| 824 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | ||
| 825 | SNDRV_CTL_ELEM_ACCESS_INACTIVE, \ | ||
| 826 | .info = wm8776_field_enum_info, \ | ||
| 827 | .get = wm8776_field_enum_get, \ | ||
| 828 | .put = wm8776_field_enum_put, \ | ||
| 829 | } | ||
| 830 | #define WM8776_FIELD_CTL_VOLUME(a, b, c, d, e, f, g, h, tlv_p) { \ | ||
| 831 | _WM8776_FIELD_CTL(a " Capture Volume", b, c, d, e, f, g, h), \ | ||
| 832 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | ||
| 833 | SNDRV_CTL_ELEM_ACCESS_INACTIVE | \ | ||
| 834 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
| 835 | .info = wm8776_field_volume_info, \ | ||
| 836 | .get = wm8776_field_volume_get, \ | ||
| 837 | .put = wm8776_field_volume_put, \ | ||
| 838 | .tlv = { .p = tlv_p }, \ | ||
| 839 | } | ||
| 840 | |||
| 841 | static const DECLARE_TLV_DB_SCALE(wm87x6_dac_db_scale, -6000, 50, 0); | ||
| 842 | static const DECLARE_TLV_DB_SCALE(wm8776_adc_db_scale, -2100, 50, 0); | ||
| 843 | static const DECLARE_TLV_DB_SCALE(wm8776_hp_db_scale, -6000, 100, 0); | ||
| 844 | static const DECLARE_TLV_DB_SCALE(wm8776_lct_db_scale, -1600, 100, 0); | ||
| 845 | static const DECLARE_TLV_DB_SCALE(wm8776_maxgain_db_scale, 0, 400, 0); | ||
| 846 | static const DECLARE_TLV_DB_SCALE(wm8776_ngth_db_scale, -7800, 600, 0); | ||
| 847 | static const DECLARE_TLV_DB_SCALE(wm8776_maxatten_lim_db_scale, -1200, 100, 0); | ||
| 848 | static const DECLARE_TLV_DB_SCALE(wm8776_maxatten_alc_db_scale, -2100, 400, 0); | ||
| 849 | |||
| 850 | static const struct snd_kcontrol_new ds_controls[] = { | ||
| 851 | { | ||
| 852 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 853 | .name = "Headphone Playback Volume", | ||
| 854 | .info = wm8776_hp_vol_info, | ||
| 855 | .get = wm8776_hp_vol_get, | ||
| 856 | .put = wm8776_hp_vol_put, | ||
| 857 | .tlv = { .p = wm8776_hp_db_scale }, | ||
| 858 | }, | ||
| 859 | WM8776_BIT_SWITCH("Headphone Playback Switch", | ||
| 860 | WM8776_PWRDOWN, WM8776_HPPD, 1, 0), | ||
| 861 | { | ||
| 862 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 863 | .name = "Input Capture Volume", | ||
| 864 | .info = wm8776_input_vol_info, | ||
| 865 | .get = wm8776_input_vol_get, | ||
| 866 | .put = wm8776_input_vol_put, | ||
| 867 | .tlv = { .p = wm8776_adc_db_scale }, | ||
| 868 | }, | ||
| 869 | { | ||
| 870 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 871 | .name = "Line Capture Switch", | ||
| 872 | .info = snd_ctl_boolean_mono_info, | ||
| 873 | .get = wm8776_input_mux_get, | ||
| 874 | .put = wm8776_input_mux_put, | ||
| 875 | .private_value = 1 << 0, | ||
| 876 | }, | ||
| 877 | { | ||
| 878 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 879 | .name = "Mic Capture Switch", | ||
| 880 | .info = snd_ctl_boolean_mono_info, | ||
| 881 | .get = wm8776_input_mux_get, | ||
| 882 | .put = wm8776_input_mux_put, | ||
| 883 | .private_value = 1 << 1, | ||
| 884 | }, | ||
| 885 | WM8776_BIT_SWITCH("Aux", WM8776_ADCMUX, 1 << 2, 0, 0), | ||
| 886 | { | ||
| 887 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 888 | .name = "ADC Filter Capture Enum", | ||
| 889 | .info = hpf_info, | ||
| 890 | .get = hpf_get, | ||
| 891 | .put = hpf_put, | ||
| 892 | }, | ||
| 893 | { | ||
| 894 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
| 895 | .name = "Level Control Capture Enum", | ||
| 896 | .info = wm8776_level_control_info, | ||
| 897 | .get = wm8776_level_control_get, | ||
| 898 | .put = wm8776_level_control_put, | ||
| 899 | .private_value = 0, | ||
| 900 | }, | ||
| 901 | }; | ||
| 902 | static const struct snd_kcontrol_new lc_controls[] = { | ||
| 903 | WM8776_FIELD_CTL_VOLUME("Limiter Threshold", | ||
| 904 | WM8776_ALCCTRL1, 0, 11, 0, 15, 0xf, | ||
| 905 | LC_CONTROL_LIMITER, wm8776_lct_db_scale), | ||
| 906 | WM8776_FIELD_CTL_ENUM("Limiter Attack Time", | ||
| 907 | WM8776_ALCCTRL3, 0, 2, 0, 10, 0xf, | ||
| 908 | LC_CONTROL_LIMITER), | ||
| 909 | WM8776_FIELD_CTL_ENUM("Limiter Decay Time", | ||
| 910 | WM8776_ALCCTRL3, 4, 3, 0, 10, 0xf, | ||
| 911 | LC_CONTROL_LIMITER), | ||
| 912 | WM8776_FIELD_CTL_ENUM("Limiter Transient Window", | ||
| 913 | WM8776_LIMITER, 4, 2, 0, 7, 0x7, | ||
| 914 | LC_CONTROL_LIMITER), | ||
| 915 | WM8776_FIELD_CTL_VOLUME("Limiter Maximum Attenuation", | ||
| 916 | WM8776_LIMITER, 0, 6, 3, 12, 0xf, | ||
| 917 | LC_CONTROL_LIMITER, | ||
| 918 | wm8776_maxatten_lim_db_scale), | ||
| 919 | WM8776_FIELD_CTL_VOLUME("ALC Target Level", | ||
| 920 | WM8776_ALCCTRL1, 0, 11, 0, 15, 0xf, | ||
| 921 | LC_CONTROL_ALC, wm8776_lct_db_scale), | ||
| 922 | WM8776_FIELD_CTL_ENUM("ALC Attack Time", | ||
| 923 | WM8776_ALCCTRL3, 0, 2, 0, 10, 0xf, | ||
| 924 | LC_CONTROL_ALC), | ||
| 925 | WM8776_FIELD_CTL_ENUM("ALC Decay Time", | ||
| 926 | WM8776_ALCCTRL3, 4, 3, 0, 10, 0xf, | ||
| 927 | LC_CONTROL_ALC), | ||
| 928 | WM8776_FIELD_CTL_VOLUME("ALC Maximum Gain", | ||
| 929 | WM8776_ALCCTRL1, 4, 7, 1, 7, 0x7, | ||
| 930 | LC_CONTROL_ALC, wm8776_maxgain_db_scale), | ||
| 931 | WM8776_FIELD_CTL_VOLUME("ALC Maximum Attenuation", | ||
| 932 | WM8776_LIMITER, 0, 10, 10, 15, 0xf, | ||
| 933 | LC_CONTROL_ALC, wm8776_maxatten_alc_db_scale), | ||
| 934 | WM8776_FIELD_CTL_ENUM("ALC Hold Time", | ||
| 935 | WM8776_ALCCTRL2, 0, 0, 0, 15, 0xf, | ||
| 936 | LC_CONTROL_ALC), | ||
| 937 | WM8776_BIT_SWITCH("Noise Gate Capture Switch", | ||
| 938 | WM8776_NOISEGATE, WM8776_NGAT, 0, | ||
| 939 | LC_CONTROL_ALC), | ||
| 940 | WM8776_FIELD_CTL_VOLUME("Noise Gate Threshold", | ||
| 941 | WM8776_NOISEGATE, 2, 0, 0, 7, 0x7, | ||
| 942 | LC_CONTROL_ALC, wm8776_ngth_db_scale), | ||
| 943 | }; | ||
| 944 | |||
| 945 | static int xonar_ds_control_filter(struct snd_kcontrol_new *template) | ||
| 946 | { | ||
| 947 | if (!strncmp(template->name, "CD Capture ", 11)) | ||
| 948 | return 1; /* no CD input */ | ||
| 949 | return 0; | ||
| 950 | } | ||
| 951 | |||
| 952 | static int xonar_ds_mixer_init(struct oxygen *chip) | ||
| 953 | { | ||
| 954 | struct xonar_wm87x6 *data = chip->model_data; | ||
| 955 | unsigned int i; | ||
| 956 | struct snd_kcontrol *ctl; | ||
| 957 | int err; | ||
| 958 | |||
| 959 | for (i = 0; i < ARRAY_SIZE(ds_controls); ++i) { | ||
| 960 | ctl = snd_ctl_new1(&ds_controls[i], chip); | ||
| 961 | if (!ctl) | ||
| 962 | return -ENOMEM; | ||
| 963 | err = snd_ctl_add(chip->card, ctl); | ||
| 964 | if (err < 0) | ||
| 965 | return err; | ||
| 966 | } | ||
| 967 | BUILD_BUG_ON(ARRAY_SIZE(lc_controls) != ARRAY_SIZE(data->lc_controls)); | ||
| 968 | for (i = 0; i < ARRAY_SIZE(lc_controls); ++i) { | ||
| 969 | ctl = snd_ctl_new1(&lc_controls[i], chip); | ||
| 970 | if (!ctl) | ||
| 971 | return -ENOMEM; | ||
| 972 | err = snd_ctl_add(chip->card, ctl); | ||
| 973 | if (err < 0) | ||
| 974 | return err; | ||
| 975 | data->lc_controls[i] = ctl; | ||
| 976 | } | ||
| 977 | return 0; | ||
| 978 | } | ||
| 979 | |||
| 980 | static const struct oxygen_model model_xonar_ds = { | ||
| 981 | .shortname = "Xonar DS", | ||
| 982 | .longname = "Asus Virtuoso 200", | ||
| 983 | .chip = "AV200", | ||
| 984 | .init = xonar_ds_init, | ||
| 985 | .control_filter = xonar_ds_control_filter, | ||
| 986 | .mixer_init = xonar_ds_mixer_init, | ||
| 987 | .cleanup = xonar_ds_cleanup, | ||
| 988 | .suspend = xonar_ds_suspend, | ||
| 989 | .resume = xonar_ds_resume, | ||
| 990 | .pcm_hardware_filter = wm8776_adc_hardware_filter, | ||
| 991 | .get_i2s_mclk = oxygen_default_i2s_mclk, | ||
| 992 | .set_dac_params = set_wm87x6_dac_params, | ||
| 993 | .set_adc_params = set_wm8776_adc_params, | ||
| 994 | .update_dac_volume = update_wm87x6_volume, | ||
| 995 | .update_dac_mute = update_wm87x6_mute, | ||
| 996 | .gpio_changed = xonar_ds_gpio_changed, | ||
| 997 | .dac_tlv = wm87x6_dac_db_scale, | ||
| 998 | .model_data_size = sizeof(struct xonar_wm87x6), | ||
| 999 | .device_config = PLAYBACK_0_TO_I2S | | ||
| 1000 | PLAYBACK_1_TO_SPDIF | | ||
| 1001 | CAPTURE_0_FROM_I2S_1, | ||
| 1002 | .dac_channels = 8, | ||
| 1003 | .dac_volume_min = 255 - 2*60, | ||
| 1004 | .dac_volume_max = 255, | ||
| 1005 | .function_flags = OXYGEN_FUNCTION_SPI, | ||
| 1006 | .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
| 1007 | .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST, | ||
| 1008 | }; | ||
| 1009 | |||
| 1010 | int __devinit get_xonar_wm87x6_model(struct oxygen *chip, | ||
| 1011 | const struct pci_device_id *id) | ||
| 1012 | { | ||
| 1013 | switch (id->subdevice) { | ||
| 1014 | case 0x838e: | ||
| 1015 | chip->model = model_xonar_ds; | ||
| 1016 | break; | ||
| 1017 | default: | ||
| 1018 | return -EINVAL; | ||
| 1019 | } | ||
| 1020 | return 0; | ||
| 1021 | } | ||
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index 833e9c7b27c7..95cfde27d25c 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c | |||
| @@ -94,7 +94,7 @@ enum { | |||
| 94 | PCI_ID_LAST | 94 | PCI_ID_LAST |
| 95 | }; | 95 | }; |
| 96 | 96 | ||
| 97 | static struct pci_device_id pcxhr_ids[] = { | 97 | static DEFINE_PCI_DEVICE_TABLE(pcxhr_ids) = { |
| 98 | { 0x10b5, 0x9656, 0x1369, 0xb001, 0, 0, PCI_ID_VX882HR, }, | 98 | { 0x10b5, 0x9656, 0x1369, 0xb001, 0, 0, PCI_ID_VX882HR, }, |
| 99 | { 0x10b5, 0x9656, 0x1369, 0xb101, 0, 0, PCI_ID_PCX882HR, }, | 99 | { 0x10b5, 0x9656, 0x1369, 0xb101, 0, 0, PCI_ID_PCX882HR, }, |
| 100 | { 0x10b5, 0x9656, 0x1369, 0xb201, 0, 0, PCI_ID_VX881HR, }, | 100 | { 0x10b5, 0x9656, 0x1369, 0xb201, 0, 0, PCI_ID_VX881HR, }, |
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index e66ef2b69b5d..960a227eb653 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c | |||
| @@ -506,7 +506,7 @@ static int riptide_reset(struct cmdif *cif, struct snd_riptide *chip); | |||
| 506 | /* | 506 | /* |
| 507 | */ | 507 | */ |
| 508 | 508 | ||
| 509 | static struct pci_device_id snd_riptide_ids[] = { | 509 | static DEFINE_PCI_DEVICE_TABLE(snd_riptide_ids) = { |
| 510 | { PCI_DEVICE(0x127a, 0x4310) }, | 510 | { PCI_DEVICE(0x127a, 0x4310) }, |
| 511 | { PCI_DEVICE(0x127a, 0x4320) }, | 511 | { PCI_DEVICE(0x127a, 0x4320) }, |
| 512 | { PCI_DEVICE(0x127a, 0x4330) }, | 512 | { PCI_DEVICE(0x127a, 0x4330) }, |
| @@ -515,7 +515,7 @@ static struct pci_device_id snd_riptide_ids[] = { | |||
| 515 | }; | 515 | }; |
| 516 | 516 | ||
| 517 | #ifdef SUPPORT_JOYSTICK | 517 | #ifdef SUPPORT_JOYSTICK |
| 518 | static struct pci_device_id snd_riptide_joystick_ids[] __devinitdata = { | 518 | static DEFINE_PCI_DEVICE_TABLE(snd_riptide_joystick_ids) = { |
| 519 | { PCI_DEVICE(0x127a, 0x4312) }, | 519 | { PCI_DEVICE(0x127a, 0x4312) }, |
| 520 | { PCI_DEVICE(0x127a, 0x4322) }, | 520 | { PCI_DEVICE(0x127a, 0x4322) }, |
| 521 | { PCI_DEVICE(0x127a, 0x4332) }, | 521 | { PCI_DEVICE(0x127a, 0x4332) }, |
diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c index f977dba7cbd0..d5e1c6eb7b7b 100644 --- a/sound/pci/rme32.c +++ b/sound/pci/rme32.c | |||
| @@ -226,7 +226,7 @@ struct rme32 { | |||
| 226 | struct snd_kcontrol *spdif_ctl; | 226 | struct snd_kcontrol *spdif_ctl; |
| 227 | }; | 227 | }; |
| 228 | 228 | ||
| 229 | static struct pci_device_id snd_rme32_ids[] = { | 229 | static DEFINE_PCI_DEVICE_TABLE(snd_rme32_ids) = { |
| 230 | {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32), 0,}, | 230 | {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32), 0,}, |
| 231 | {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_8), 0,}, | 231 | {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_8), 0,}, |
| 232 | {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_PRO), 0,}, | 232 | {PCI_VDEVICE(XILINX_RME, PCI_DEVICE_ID_RME_DIGI32_PRO), 0,}, |
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c index 2ba5c0fd55db..9d5252bc870c 100644 --- a/sound/pci/rme96.c +++ b/sound/pci/rme96.c | |||
| @@ -231,7 +231,7 @@ struct rme96 { | |||
| 231 | struct snd_kcontrol *spdif_ctl; | 231 | struct snd_kcontrol *spdif_ctl; |
| 232 | }; | 232 | }; |
| 233 | 233 | ||
| 234 | static struct pci_device_id snd_rme96_ids[] = { | 234 | static DEFINE_PCI_DEVICE_TABLE(snd_rme96_ids) = { |
| 235 | { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96), 0, }, | 235 | { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96), 0, }, |
| 236 | { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8), 0, }, | 236 | { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8), 0, }, |
| 237 | { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8_PRO), 0, }, | 237 | { PCI_VDEVICE(XILINX, PCI_DEVICE_ID_RME_DIGI96_8_PRO), 0, }, |
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 7bb827c7d806..52c6eb57cc3f 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c | |||
| @@ -585,7 +585,7 @@ static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_d | |||
| 585 | } | 585 | } |
| 586 | 586 | ||
| 587 | 587 | ||
| 588 | static struct pci_device_id snd_hdsp_ids[] = { | 588 | static DEFINE_PCI_DEVICE_TABLE(snd_hdsp_ids) = { |
| 589 | { | 589 | { |
| 590 | .vendor = PCI_VENDOR_ID_XILINX, | 590 | .vendor = PCI_VENDOR_ID_XILINX, |
| 591 | .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP, | 591 | .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP, |
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index a1b10d1a384d..3d72c1effeef 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c | |||
| @@ -512,7 +512,7 @@ static char channel_map_madi_ss[HDSPM_MAX_CHANNELS] = { | |||
| 512 | }; | 512 | }; |
| 513 | 513 | ||
| 514 | 514 | ||
| 515 | static struct pci_device_id snd_hdspm_ids[] __devinitdata = { | 515 | static DEFINE_PCI_DEVICE_TABLE(snd_hdspm_ids) = { |
| 516 | { | 516 | { |
| 517 | .vendor = PCI_VENDOR_ID_XILINX, | 517 | .vendor = PCI_VENDOR_ID_XILINX, |
| 518 | .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI, | 518 | .device = PCI_DEVICE_ID_XILINX_HAMMERFALL_DSP_MADI, |
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c index bc539abb2105..44a3e2d8c556 100644 --- a/sound/pci/rme9652/rme9652.c +++ b/sound/pci/rme9652/rme9652.c | |||
| @@ -314,7 +314,7 @@ static void snd_hammerfall_free_buffer(struct snd_dma_buffer *dmab, struct pci_d | |||
| 314 | } | 314 | } |
| 315 | 315 | ||
| 316 | 316 | ||
| 317 | static struct pci_device_id snd_rme9652_ids[] = { | 317 | static DEFINE_PCI_DEVICE_TABLE(snd_rme9652_ids) = { |
| 318 | { | 318 | { |
| 319 | .vendor = 0x10ee, | 319 | .vendor = 0x10ee, |
| 320 | .device = 0x3fc4, | 320 | .device = 0x3fc4, |
diff --git a/sound/pci/sis7019.c b/sound/pci/sis7019.c index 1a5ff0611072..7e3e8fbc90fe 100644 --- a/sound/pci/sis7019.c +++ b/sound/pci/sis7019.c | |||
| @@ -48,7 +48,7 @@ MODULE_PARM_DESC(id, "ID string for SiS7019 Audio Accelerator."); | |||
| 48 | module_param(enable, bool, 0444); | 48 | module_param(enable, bool, 0444); |
| 49 | MODULE_PARM_DESC(enable, "Enable SiS7019 Audio Accelerator."); | 49 | MODULE_PARM_DESC(enable, "Enable SiS7019 Audio Accelerator."); |
| 50 | 50 | ||
| 51 | static struct pci_device_id snd_sis7019_ids[] = { | 51 | static DEFINE_PCI_DEVICE_TABLE(snd_sis7019_ids) = { |
| 52 | { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x7019) }, | 52 | { PCI_DEVICE(PCI_VENDOR_ID_SI, 0x7019) }, |
| 53 | { 0, } | 53 | { 0, } |
| 54 | }; | 54 | }; |
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c index 1f6406c4534d..337b9facadfd 100644 --- a/sound/pci/sonicvibes.c +++ b/sound/pci/sonicvibes.c | |||
| @@ -242,7 +242,7 @@ struct sonicvibes { | |||
| 242 | #endif | 242 | #endif |
| 243 | }; | 243 | }; |
| 244 | 244 | ||
| 245 | static struct pci_device_id snd_sonic_ids[] = { | 245 | static DEFINE_PCI_DEVICE_TABLE(snd_sonic_ids) = { |
| 246 | { PCI_VDEVICE(S3, 0xca00), 0, }, | 246 | { PCI_VDEVICE(S3, 0xca00), 0, }, |
| 247 | { 0, } | 247 | { 0, } |
| 248 | }; | 248 | }; |
diff --git a/sound/pci/trident/trident.c b/sound/pci/trident/trident.c index 21cef97d478d..6d0581841d7a 100644 --- a/sound/pci/trident/trident.c +++ b/sound/pci/trident/trident.c | |||
| @@ -62,7 +62,7 @@ MODULE_PARM_DESC(pcm_channels, "Number of hardware channels assigned for PCM."); | |||
| 62 | module_param_array(wavetable_size, int, NULL, 0444); | 62 | module_param_array(wavetable_size, int, NULL, 0444); |
| 63 | MODULE_PARM_DESC(wavetable_size, "Maximum memory size in kB for wavetable synth."); | 63 | MODULE_PARM_DESC(wavetable_size, "Maximum memory size in kB for wavetable synth."); |
| 64 | 64 | ||
| 65 | static struct pci_device_id snd_trident_ids[] = { | 65 | static DEFINE_PCI_DEVICE_TABLE(snd_trident_ids) = { |
| 66 | {PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX), | 66 | {PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_DX), |
| 67 | PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, | 67 | PCI_CLASS_MULTIMEDIA_AUDIO << 8, 0xffff00, 0}, |
| 68 | {PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX), | 68 | {PCI_DEVICE(PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_4DWAVE_NX), |
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 03d6aea19749..7e494b6a1d0e 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c | |||
| @@ -401,7 +401,7 @@ struct via82xx { | |||
| 401 | #endif | 401 | #endif |
| 402 | }; | 402 | }; |
| 403 | 403 | ||
| 404 | static struct pci_device_id snd_via82xx_ids[] = { | 404 | static DEFINE_PCI_DEVICE_TABLE(snd_via82xx_ids) = { |
| 405 | /* 0x1106, 0x3058 */ | 405 | /* 0x1106, 0x3058 */ |
| 406 | { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C686_5), TYPE_CARD_VIA686, }, /* 686A */ | 406 | { PCI_VDEVICE(VIA, PCI_DEVICE_ID_VIA_82C686_5), TYPE_CARD_VIA686, }, /* 686A */ |
| 407 | /* 0x1106, 0x3059 */ | 407 | /* 0x1106, 0x3059 */ |
diff --git a/sound/pci/via82xx_modem.c b/sound/pci/via82xx_modem.c index 47eb61561dfc..f7e8bbbe3953 100644 --- a/sound/pci/via82xx_modem.c +++ b/sound/pci/via82xx_modem.c | |||
| @@ -260,7 +260,7 @@ struct via82xx_modem { | |||
| 260 | struct snd_info_entry *proc_entry; | 260 | struct snd_info_entry *proc_entry; |
| 261 | }; | 261 | }; |
| 262 | 262 | ||
| 263 | static struct pci_device_id snd_via82xx_modem_ids[] = { | 263 | static DEFINE_PCI_DEVICE_TABLE(snd_via82xx_modem_ids) = { |
| 264 | { PCI_VDEVICE(VIA, 0x3068), TYPE_CARD_VIA82XX_MODEM, }, | 264 | { PCI_VDEVICE(VIA, 0x3068), TYPE_CARD_VIA82XX_MODEM, }, |
| 265 | { 0, } | 265 | { 0, } |
| 266 | }; | 266 | }; |
diff --git a/sound/pci/vx222/vx222.c b/sound/pci/vx222/vx222.c index fc9136c3e0d7..99a9a814be0b 100644 --- a/sound/pci/vx222/vx222.c +++ b/sound/pci/vx222/vx222.c | |||
| @@ -60,7 +60,7 @@ enum { | |||
| 60 | VX_PCI_VX222_NEW | 60 | VX_PCI_VX222_NEW |
| 61 | }; | 61 | }; |
| 62 | 62 | ||
| 63 | static struct pci_device_id snd_vx222_ids[] = { | 63 | static DEFINE_PCI_DEVICE_TABLE(snd_vx222_ids) = { |
| 64 | { 0x10b5, 0x9050, 0x1369, PCI_ANY_ID, 0, 0, VX_PCI_VX222_OLD, }, /* PLX */ | 64 | { 0x10b5, 0x9050, 0x1369, PCI_ANY_ID, 0, 0, VX_PCI_VX222_OLD, }, /* PLX */ |
| 65 | { 0x10b5, 0x9030, 0x1369, PCI_ANY_ID, 0, 0, VX_PCI_VX222_NEW, }, /* PLX */ | 65 | { 0x10b5, 0x9030, 0x1369, PCI_ANY_ID, 0, 0, VX_PCI_VX222_NEW, }, /* PLX */ |
| 66 | { 0, } | 66 | { 0, } |
diff --git a/sound/pci/ymfpci/ymfpci.c b/sound/pci/ymfpci/ymfpci.c index e6b18b90d451..80c682113381 100644 --- a/sound/pci/ymfpci/ymfpci.c +++ b/sound/pci/ymfpci/ymfpci.c | |||
| @@ -66,7 +66,7 @@ MODULE_PARM_DESC(joystick_port, "Joystick port address"); | |||
| 66 | module_param_array(rear_switch, bool, NULL, 0444); | 66 | module_param_array(rear_switch, bool, NULL, 0444); |
| 67 | MODULE_PARM_DESC(rear_switch, "Enable shared rear/line-in switch"); | 67 | MODULE_PARM_DESC(rear_switch, "Enable shared rear/line-in switch"); |
| 68 | 68 | ||
| 69 | static struct pci_device_id snd_ymfpci_ids[] = { | 69 | static DEFINE_PCI_DEVICE_TABLE(snd_ymfpci_ids) = { |
| 70 | { PCI_VDEVICE(YAMAHA, 0x0004), 0, }, /* YMF724 */ | 70 | { PCI_VDEVICE(YAMAHA, 0x0004), 0, }, /* YMF724 */ |
| 71 | { PCI_VDEVICE(YAMAHA, 0x000d), 0, }, /* YMF724F */ | 71 | { PCI_VDEVICE(YAMAHA, 0x000d), 0, }, /* YMF724F */ |
| 72 | { PCI_VDEVICE(YAMAHA, 0x000a), 0, }, /* YMF740 */ | 72 | { PCI_VDEVICE(YAMAHA, 0x000a), 0, }, /* YMF740 */ |
diff --git a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c index 5cfa608823f7..0d668f471620 100644 --- a/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c +++ b/sound/pcmcia/pdaudiocf/pdaudiocf_pcm.c | |||
| @@ -21,7 +21,6 @@ | |||
| 21 | */ | 21 | */ |
| 22 | 22 | ||
| 23 | #include <linux/slab.h> | 23 | #include <linux/slab.h> |
| 24 | #include <linux/vmalloc.h> | ||
| 25 | #include <linux/delay.h> | 24 | #include <linux/delay.h> |
| 26 | #include <sound/core.h> | 25 | #include <sound/core.h> |
| 27 | #include <sound/asoundef.h> | 26 | #include <sound/asoundef.h> |
| @@ -29,49 +28,6 @@ | |||
| 29 | 28 | ||
| 30 | 29 | ||
| 31 | /* | 30 | /* |
| 32 | * we use a vmalloc'ed (sg-)buffer | ||
| 33 | */ | ||
| 34 | |||
| 35 | /* get the physical page pointer on the given offset */ | ||
| 36 | static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, unsigned long offset) | ||
| 37 | { | ||
| 38 | void *pageptr = subs->runtime->dma_area + offset; | ||
| 39 | return vmalloc_to_page(pageptr); | ||
| 40 | } | ||
| 41 | |||
| 42 | /* | ||
| 43 | * hw_params callback | ||
| 44 | * NOTE: this may be called not only once per pcm open! | ||
| 45 | */ | ||
| 46 | static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t size) | ||
| 47 | { | ||
| 48 | struct snd_pcm_runtime *runtime = subs->runtime; | ||
| 49 | if (runtime->dma_area) { | ||
| 50 | if (runtime->dma_bytes >= size) | ||
| 51 | return 0; /* already enough large */ | ||
| 52 | vfree(runtime->dma_area); | ||
| 53 | } | ||
| 54 | runtime->dma_area = vmalloc_32_user(size); | ||
| 55 | if (! runtime->dma_area) | ||
| 56 | return -ENOMEM; | ||
| 57 | runtime->dma_bytes = size; | ||
| 58 | return 0; | ||
| 59 | } | ||
| 60 | |||
| 61 | /* | ||
| 62 | * hw_free callback | ||
| 63 | * NOTE: this may be called not only once per pcm open! | ||
| 64 | */ | ||
| 65 | static int snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs) | ||
| 66 | { | ||
| 67 | struct snd_pcm_runtime *runtime = subs->runtime; | ||
| 68 | |||
| 69 | vfree(runtime->dma_area); | ||
| 70 | runtime->dma_area = NULL; | ||
| 71 | return 0; | ||
| 72 | } | ||
| 73 | |||
| 74 | /* | ||
| 75 | * clear the SRAM contents | 31 | * clear the SRAM contents |
| 76 | */ | 32 | */ |
| 77 | static int pdacf_pcm_clear_sram(struct snd_pdacf *chip) | 33 | static int pdacf_pcm_clear_sram(struct snd_pdacf *chip) |
| @@ -147,7 +103,8 @@ static int pdacf_pcm_trigger(struct snd_pcm_substream *subs, int cmd) | |||
| 147 | static int pdacf_pcm_hw_params(struct snd_pcm_substream *subs, | 103 | static int pdacf_pcm_hw_params(struct snd_pcm_substream *subs, |
| 148 | struct snd_pcm_hw_params *hw_params) | 104 | struct snd_pcm_hw_params *hw_params) |
| 149 | { | 105 | { |
| 150 | return snd_pcm_alloc_vmalloc_buffer(subs, params_buffer_bytes(hw_params)); | 106 | return snd_pcm_lib_alloc_vmalloc_32_buffer |
| 107 | (subs, params_buffer_bytes(hw_params)); | ||
| 151 | } | 108 | } |
| 152 | 109 | ||
| 153 | /* | 110 | /* |
| @@ -155,7 +112,7 @@ static int pdacf_pcm_hw_params(struct snd_pcm_substream *subs, | |||
| 155 | */ | 112 | */ |
| 156 | static int pdacf_pcm_hw_free(struct snd_pcm_substream *subs) | 113 | static int pdacf_pcm_hw_free(struct snd_pcm_substream *subs) |
| 157 | { | 114 | { |
| 158 | return snd_pcm_free_vmalloc_buffer(subs); | 115 | return snd_pcm_lib_free_vmalloc_buffer(subs); |
| 159 | } | 116 | } |
| 160 | 117 | ||
| 161 | /* | 118 | /* |
| @@ -319,7 +276,8 @@ static struct snd_pcm_ops pdacf_pcm_capture_ops = { | |||
| 319 | .prepare = pdacf_pcm_prepare, | 276 | .prepare = pdacf_pcm_prepare, |
| 320 | .trigger = pdacf_pcm_trigger, | 277 | .trigger = pdacf_pcm_trigger, |
| 321 | .pointer = pdacf_pcm_capture_pointer, | 278 | .pointer = pdacf_pcm_capture_pointer, |
| 322 | .page = snd_pcm_get_vmalloc_page, | 279 | .page = snd_pcm_lib_get_vmalloc_page, |
| 280 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
| 323 | }; | 281 | }; |
| 324 | 282 | ||
| 325 | 283 | ||
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig index 73525c048e7f..8c2925814ce4 100644 --- a/sound/usb/Kconfig +++ b/sound/usb/Kconfig | |||
| @@ -21,6 +21,18 @@ config SND_USB_AUDIO | |||
| 21 | To compile this driver as a module, choose M here: the module | 21 | To compile this driver as a module, choose M here: the module |
| 22 | will be called snd-usb-audio. | 22 | will be called snd-usb-audio. |
| 23 | 23 | ||
| 24 | config SND_USB_UA101 | ||
| 25 | tristate "Edirol UA-101 driver (EXPERIMENTAL)" | ||
| 26 | depends on EXPERIMENTAL | ||
| 27 | select SND_PCM | ||
| 28 | select SND_RAWMIDI | ||
| 29 | help | ||
| 30 | Say Y here to include support for the Edirol UA-101 audio/MIDI | ||
| 31 | interface. | ||
| 32 | |||
| 33 | To compile this driver as a module, choose M here: the module | ||
| 34 | will be called snd-ua101. | ||
| 35 | |||
| 24 | config SND_USB_USX2Y | 36 | config SND_USB_USX2Y |
| 25 | tristate "Tascam US-122, US-224 and US-428 USB driver" | 37 | tristate "Tascam US-122, US-224 and US-428 USB driver" |
| 26 | depends on X86 || PPC || ALPHA | 38 | depends on X86 || PPC || ALPHA |
diff --git a/sound/usb/Makefile b/sound/usb/Makefile index abb288bfe35d..5bf64aef9558 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile | |||
| @@ -4,9 +4,11 @@ | |||
| 4 | 4 | ||
| 5 | snd-usb-audio-objs := usbaudio.o usbmixer.o | 5 | snd-usb-audio-objs := usbaudio.o usbmixer.o |
| 6 | snd-usb-lib-objs := usbmidi.o | 6 | snd-usb-lib-objs := usbmidi.o |
| 7 | snd-ua101-objs := ua101.o | ||
| 7 | 8 | ||
| 8 | # Toplevel Module Dependency | 9 | # Toplevel Module Dependency |
| 9 | obj-$(CONFIG_SND_USB_AUDIO) += snd-usb-audio.o snd-usb-lib.o | 10 | obj-$(CONFIG_SND_USB_AUDIO) += snd-usb-audio.o snd-usb-lib.o |
| 11 | obj-$(CONFIG_SND_USB_UA101) += snd-ua101.o snd-usb-lib.o | ||
| 10 | obj-$(CONFIG_SND_USB_USX2Y) += snd-usb-lib.o | 12 | obj-$(CONFIG_SND_USB_USX2Y) += snd-usb-lib.o |
| 11 | obj-$(CONFIG_SND_USB_US122L) += snd-usb-lib.o | 13 | obj-$(CONFIG_SND_USB_US122L) += snd-usb-lib.o |
| 12 | 14 | ||
diff --git a/sound/usb/ua101.c b/sound/usb/ua101.c new file mode 100644 index 000000000000..4f4ccdf70dd0 --- /dev/null +++ b/sound/usb/ua101.c | |||
| @@ -0,0 +1,1421 @@ | |||
| 1 | /* | ||
| 2 | * Edirol UA-101 driver | ||
| 3 | * Copyright (c) Clemens Ladisch <clemens@ladisch.de> | ||
| 4 | * | ||
| 5 | * This driver is free software: you can redistribute it and/or modify | ||
| 6 | * it under the terms of the GNU General Public License, version 2. | ||
| 7 | * | ||
| 8 | * This driver is distributed in the hope that it will be useful, | ||
| 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 11 | * GNU General Public License for more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this driver. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | #include <linux/init.h> | ||
| 18 | #include <linux/module.h> | ||
| 19 | #include <linux/slab.h> | ||
| 20 | #include <linux/usb.h> | ||
| 21 | #include <linux/usb/audio.h> | ||
| 22 | #include <sound/core.h> | ||
| 23 | #include <sound/initval.h> | ||
| 24 | #include <sound/pcm.h> | ||
| 25 | #include <sound/pcm_params.h> | ||
| 26 | #include "usbaudio.h" | ||
| 27 | |||
| 28 | MODULE_DESCRIPTION("Edirol UA-101 driver"); | ||
| 29 | MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); | ||
| 30 | MODULE_LICENSE("GPL v2"); | ||
| 31 | MODULE_SUPPORTED_DEVICE("{{Edirol,UA-101}}"); | ||
| 32 | |||
| 33 | /* I use my UA-1A for testing because I don't have a UA-101 ... */ | ||
| 34 | #define UA1A_HACK | ||
| 35 | |||
| 36 | /* | ||
| 37 | * Should not be lower than the minimum scheduling delay of the host | ||
| 38 | * controller. Some Intel controllers need more than one frame; as long as | ||
| 39 | * that driver doesn't tell us about this, use 1.5 frames just to be sure. | ||
| 40 | */ | ||
| 41 | #define MIN_QUEUE_LENGTH 12 | ||
| 42 | /* Somewhat random. */ | ||
| 43 | #define MAX_QUEUE_LENGTH 30 | ||
| 44 | /* | ||
| 45 | * This magic value optimizes memory usage efficiency for the UA-101's packet | ||
| 46 | * sizes at all sample rates, taking into account the stupid cache pool sizes | ||
| 47 | * that usb_buffer_alloc() uses. | ||
| 48 | */ | ||
| 49 | #define DEFAULT_QUEUE_LENGTH 21 | ||
| 50 | |||
| 51 | #define MAX_PACKET_SIZE 672 /* hardware specific */ | ||
| 52 | #define MAX_MEMORY_BUFFERS DIV_ROUND_UP(MAX_QUEUE_LENGTH, \ | ||
| 53 | PAGE_SIZE / MAX_PACKET_SIZE) | ||
| 54 | |||
| 55 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | ||
| 56 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | ||
| 57 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | ||
| 58 | static unsigned int queue_length = 21; | ||
| 59 | |||
| 60 | module_param_array(index, int, NULL, 0444); | ||
| 61 | MODULE_PARM_DESC(index, "card index"); | ||
| 62 | module_param_array(id, charp, NULL, 0444); | ||
| 63 | MODULE_PARM_DESC(id, "ID string"); | ||
| 64 | module_param_array(enable, bool, NULL, 0444); | ||
| 65 | MODULE_PARM_DESC(enable, "enable card"); | ||
| 66 | module_param(queue_length, uint, 0644); | ||
| 67 | MODULE_PARM_DESC(queue_length, "USB queue length in microframes, " | ||
| 68 | __stringify(MIN_QUEUE_LENGTH)"-"__stringify(MAX_QUEUE_LENGTH)); | ||
| 69 | |||
| 70 | enum { | ||
| 71 | INTF_PLAYBACK, | ||
| 72 | INTF_CAPTURE, | ||
| 73 | INTF_MIDI, | ||
| 74 | |||
| 75 | INTF_COUNT | ||
| 76 | }; | ||
| 77 | |||
| 78 | /* bits in struct ua101::states */ | ||
| 79 | enum { | ||
| 80 | USB_CAPTURE_RUNNING, | ||
| 81 | USB_PLAYBACK_RUNNING, | ||
| 82 | ALSA_CAPTURE_OPEN, | ||
| 83 | ALSA_PLAYBACK_OPEN, | ||
| 84 | ALSA_CAPTURE_RUNNING, | ||
| 85 | ALSA_PLAYBACK_RUNNING, | ||
| 86 | CAPTURE_URB_COMPLETED, | ||
| 87 | PLAYBACK_URB_COMPLETED, | ||
| 88 | DISCONNECTED, | ||
| 89 | }; | ||
| 90 | |||
| 91 | struct ua101 { | ||
| 92 | struct usb_device *dev; | ||
| 93 | struct snd_card *card; | ||
| 94 | struct usb_interface *intf[INTF_COUNT]; | ||
| 95 | int card_index; | ||
| 96 | struct snd_pcm *pcm; | ||
| 97 | struct list_head midi_list; | ||
| 98 | u64 format_bit; | ||
| 99 | unsigned int rate; | ||
| 100 | unsigned int packets_per_second; | ||
| 101 | spinlock_t lock; | ||
| 102 | struct mutex mutex; | ||
| 103 | unsigned long states; | ||
| 104 | |||
| 105 | /* FIFO to synchronize playback rate to capture rate */ | ||
| 106 | unsigned int rate_feedback_start; | ||
| 107 | unsigned int rate_feedback_count; | ||
| 108 | u8 rate_feedback[MAX_QUEUE_LENGTH]; | ||
| 109 | |||
| 110 | struct list_head ready_playback_urbs; | ||
| 111 | struct tasklet_struct playback_tasklet; | ||
| 112 | wait_queue_head_t alsa_capture_wait; | ||
| 113 | wait_queue_head_t rate_feedback_wait; | ||
| 114 | wait_queue_head_t alsa_playback_wait; | ||
| 115 | struct ua101_stream { | ||
| 116 | struct snd_pcm_substream *substream; | ||
| 117 | unsigned int usb_pipe; | ||
| 118 | unsigned int channels; | ||
| 119 | unsigned int frame_bytes; | ||
| 120 | unsigned int max_packet_bytes; | ||
| 121 | unsigned int period_pos; | ||
| 122 | unsigned int buffer_pos; | ||
| 123 | unsigned int queue_length; | ||
| 124 | struct ua101_urb { | ||
| 125 | struct urb urb; | ||
| 126 | struct usb_iso_packet_descriptor iso_frame_desc[1]; | ||
| 127 | struct list_head ready_list; | ||
| 128 | } *urbs[MAX_QUEUE_LENGTH]; | ||
| 129 | struct { | ||
| 130 | unsigned int size; | ||
| 131 | void *addr; | ||
| 132 | dma_addr_t dma; | ||
| 133 | } buffers[MAX_MEMORY_BUFFERS]; | ||
| 134 | } capture, playback; | ||
| 135 | |||
| 136 | unsigned int fps[10]; | ||
| 137 | unsigned int frame_counter; | ||
| 138 | }; | ||
| 139 | |||
| 140 | static DEFINE_MUTEX(devices_mutex); | ||
| 141 | static unsigned int devices_used; | ||
| 142 | static struct usb_driver ua101_driver; | ||
| 143 | |||
| 144 | static void abort_alsa_playback(struct ua101 *ua); | ||
| 145 | static void abort_alsa_capture(struct ua101 *ua); | ||
| 146 | |||
| 147 | static const char *usb_error_string(int err) | ||
| 148 | { | ||
| 149 | switch (err) { | ||
| 150 | case -ENODEV: | ||
| 151 | return "no device"; | ||
| 152 | case -ENOENT: | ||
| 153 | return "endpoint not enabled"; | ||
| 154 | case -EPIPE: | ||
| 155 | return "endpoint stalled"; | ||
| 156 | case -ENOSPC: | ||
| 157 | return "not enough bandwidth"; | ||
| 158 | case -ESHUTDOWN: | ||
| 159 | return "device disabled"; | ||
| 160 | case -EHOSTUNREACH: | ||
| 161 | return "device suspended"; | ||
| 162 | case -EINVAL: | ||
| 163 | case -EAGAIN: | ||
| 164 | case -EFBIG: | ||
| 165 | case -EMSGSIZE: | ||
| 166 | return "internal error"; | ||
| 167 | default: | ||
| 168 | return "unknown error"; | ||
| 169 | } | ||
| 170 | } | ||
| 171 | |||
| 172 | static void abort_usb_capture(struct ua101 *ua) | ||
| 173 | { | ||
| 174 | if (test_and_clear_bit(USB_CAPTURE_RUNNING, &ua->states)) { | ||
| 175 | wake_up(&ua->alsa_capture_wait); | ||
| 176 | wake_up(&ua->rate_feedback_wait); | ||
| 177 | } | ||
| 178 | } | ||
| 179 | |||
| 180 | static void abort_usb_playback(struct ua101 *ua) | ||
| 181 | { | ||
| 182 | if (test_and_clear_bit(USB_PLAYBACK_RUNNING, &ua->states)) | ||
| 183 | wake_up(&ua->alsa_playback_wait); | ||
| 184 | } | ||
| 185 | |||
| 186 | static void playback_urb_complete(struct urb *usb_urb) | ||
| 187 | { | ||
| 188 | struct ua101_urb *urb = (struct ua101_urb *)usb_urb; | ||
| 189 | struct ua101 *ua = urb->urb.context; | ||
| 190 | unsigned long flags; | ||
| 191 | |||
| 192 | if (unlikely(urb->urb.status == -ENOENT || /* unlinked */ | ||
| 193 | urb->urb.status == -ENODEV || /* device removed */ | ||
| 194 | urb->urb.status == -ECONNRESET || /* unlinked */ | ||
| 195 | urb->urb.status == -ESHUTDOWN)) { /* device disabled */ | ||
| 196 | abort_usb_playback(ua); | ||
| 197 | abort_alsa_playback(ua); | ||
| 198 | return; | ||
| 199 | } | ||
| 200 | |||
| 201 | if (test_bit(USB_PLAYBACK_RUNNING, &ua->states)) { | ||
| 202 | /* append URB to FIFO */ | ||
| 203 | spin_lock_irqsave(&ua->lock, flags); | ||
| 204 | list_add_tail(&urb->ready_list, &ua->ready_playback_urbs); | ||
| 205 | if (ua->rate_feedback_count > 0) | ||
| 206 | tasklet_schedule(&ua->playback_tasklet); | ||
| 207 | ua->playback.substream->runtime->delay -= | ||
| 208 | urb->urb.iso_frame_desc[0].length / | ||
| 209 | ua->playback.frame_bytes; | ||
| 210 | spin_unlock_irqrestore(&ua->lock, flags); | ||
| 211 | } | ||
| 212 | } | ||
| 213 | |||
| 214 | static void first_playback_urb_complete(struct urb *urb) | ||
| 215 | { | ||
| 216 | struct ua101 *ua = urb->context; | ||
| 217 | |||
| 218 | urb->complete = playback_urb_complete; | ||
| 219 | playback_urb_complete(urb); | ||
| 220 | |||
| 221 | set_bit(PLAYBACK_URB_COMPLETED, &ua->states); | ||
| 222 | wake_up(&ua->alsa_playback_wait); | ||
| 223 | } | ||
| 224 | |||
| 225 | /* copy data from the ALSA ring buffer into the URB buffer */ | ||
| 226 | static bool copy_playback_data(struct ua101_stream *stream, struct urb *urb, | ||
| 227 | unsigned int frames) | ||
| 228 | { | ||
| 229 | struct snd_pcm_runtime *runtime; | ||
| 230 | unsigned int frame_bytes, frames1; | ||
| 231 | const u8 *source; | ||
| 232 | |||
| 233 | runtime = stream->substream->runtime; | ||
| 234 | frame_bytes = stream->frame_bytes; | ||
| 235 | source = runtime->dma_area + stream->buffer_pos * frame_bytes; | ||
| 236 | if (stream->buffer_pos + frames <= runtime->buffer_size) { | ||
| 237 | memcpy(urb->transfer_buffer, source, frames * frame_bytes); | ||
| 238 | } else { | ||
| 239 | /* wrap around at end of ring buffer */ | ||
| 240 | frames1 = runtime->buffer_size - stream->buffer_pos; | ||
| 241 | memcpy(urb->transfer_buffer, source, frames1 * frame_bytes); | ||
| 242 | memcpy(urb->transfer_buffer + frames1 * frame_bytes, | ||
| 243 | runtime->dma_area, (frames - frames1) * frame_bytes); | ||
| 244 | } | ||
| 245 | |||
| 246 | stream->buffer_pos += frames; | ||
| 247 | if (stream->buffer_pos >= runtime->buffer_size) | ||
| 248 | stream->buffer_pos -= runtime->buffer_size; | ||
| 249 | stream->period_pos += frames; | ||
| 250 | if (stream->period_pos >= runtime->period_size) { | ||
| 251 | stream->period_pos -= runtime->period_size; | ||
| 252 | return true; | ||
| 253 | } | ||
| 254 | return false; | ||
| 255 | } | ||
| 256 | |||
| 257 | static inline void add_with_wraparound(struct ua101 *ua, | ||
| 258 | unsigned int *value, unsigned int add) | ||
| 259 | { | ||
| 260 | *value += add; | ||
| 261 | if (*value >= ua->playback.queue_length) | ||
| 262 | *value -= ua->playback.queue_length; | ||
| 263 | } | ||
| 264 | |||
| 265 | static void playback_tasklet(unsigned long data) | ||
| 266 | { | ||
| 267 | struct ua101 *ua = (void *)data; | ||
| 268 | unsigned long flags; | ||
| 269 | unsigned int frames; | ||
| 270 | struct ua101_urb *urb; | ||
| 271 | bool do_period_elapsed = false; | ||
| 272 | int err; | ||
| 273 | |||
| 274 | if (unlikely(!test_bit(USB_PLAYBACK_RUNNING, &ua->states))) | ||
| 275 | return; | ||
| 276 | |||
| 277 | /* | ||
| 278 | * Synchronizing the playback rate to the capture rate is done by using | ||
| 279 | * the same sequence of packet sizes for both streams. | ||
| 280 | * Submitting a playback URB therefore requires both a ready URB and | ||
| 281 | * the size of the corresponding capture packet, i.e., both playback | ||
| 282 | * and capture URBs must have been completed. Since the USB core does | ||
| 283 | * not guarantee that playback and capture complete callbacks are | ||
| 284 | * called alternately, we use two FIFOs for packet sizes and read URBs; | ||
| 285 | * submitting playback URBs is possible as long as both FIFOs are | ||
| 286 | * nonempty. | ||
| 287 | */ | ||
| 288 | spin_lock_irqsave(&ua->lock, flags); | ||
| 289 | while (ua->rate_feedback_count > 0 && | ||
| 290 | !list_empty(&ua->ready_playback_urbs)) { | ||
| 291 | /* take packet size out of FIFO */ | ||
| 292 | frames = ua->rate_feedback[ua->rate_feedback_start]; | ||
| 293 | add_with_wraparound(ua, &ua->rate_feedback_start, 1); | ||
| 294 | ua->rate_feedback_count--; | ||
| 295 | |||
| 296 | /* take URB out of FIFO */ | ||
| 297 | urb = list_first_entry(&ua->ready_playback_urbs, | ||
| 298 | struct ua101_urb, ready_list); | ||
| 299 | list_del(&urb->ready_list); | ||
| 300 | |||
| 301 | /* fill packet with data or silence */ | ||
| 302 | urb->urb.iso_frame_desc[0].length = | ||
| 303 | frames * ua->playback.frame_bytes; | ||
| 304 | if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states)) | ||
| 305 | do_period_elapsed |= copy_playback_data(&ua->playback, | ||
| 306 | &urb->urb, | ||
| 307 | frames); | ||
| 308 | else | ||
| 309 | memset(urb->urb.transfer_buffer, 0, | ||
| 310 | urb->urb.iso_frame_desc[0].length); | ||
| 311 | |||
| 312 | /* and off you go ... */ | ||
| 313 | err = usb_submit_urb(&urb->urb, GFP_ATOMIC); | ||
| 314 | if (unlikely(err < 0)) { | ||
| 315 | spin_unlock_irqrestore(&ua->lock, flags); | ||
| 316 | abort_usb_playback(ua); | ||
| 317 | abort_alsa_playback(ua); | ||
| 318 | dev_err(&ua->dev->dev, "USB request error %d: %s\n", | ||
| 319 | err, usb_error_string(err)); | ||
| 320 | return; | ||
| 321 | } | ||
| 322 | ua->playback.substream->runtime->delay += frames; | ||
| 323 | } | ||
| 324 | spin_unlock_irqrestore(&ua->lock, flags); | ||
| 325 | if (do_period_elapsed) | ||
| 326 | snd_pcm_period_elapsed(ua->playback.substream); | ||
| 327 | } | ||
| 328 | |||
| 329 | /* copy data from the URB buffer into the ALSA ring buffer */ | ||
| 330 | static bool copy_capture_data(struct ua101_stream *stream, struct urb *urb, | ||
| 331 | unsigned int frames) | ||
| 332 | { | ||
| 333 | struct snd_pcm_runtime *runtime; | ||
| 334 | unsigned int frame_bytes, frames1; | ||
| 335 | u8 *dest; | ||
| 336 | |||
| 337 | runtime = stream->substream->runtime; | ||
| 338 | frame_bytes = stream->frame_bytes; | ||
| 339 | dest = runtime->dma_area + stream->buffer_pos * frame_bytes; | ||
| 340 | if (stream->buffer_pos + frames <= runtime->buffer_size) { | ||
| 341 | memcpy(dest, urb->transfer_buffer, frames * frame_bytes); | ||
| 342 | } else { | ||
| 343 | /* wrap around at end of ring buffer */ | ||
| 344 | frames1 = runtime->buffer_size - stream->buffer_pos; | ||
| 345 | memcpy(dest, urb->transfer_buffer, frames1 * frame_bytes); | ||
| 346 | memcpy(runtime->dma_area, | ||
| 347 | urb->transfer_buffer + frames1 * frame_bytes, | ||
| 348 | (frames - frames1) * frame_bytes); | ||
| 349 | } | ||
| 350 | |||
| 351 | stream->buffer_pos += frames; | ||
| 352 | if (stream->buffer_pos >= runtime->buffer_size) | ||
| 353 | stream->buffer_pos -= runtime->buffer_size; | ||
| 354 | stream->period_pos += frames; | ||
| 355 | if (stream->period_pos >= runtime->period_size) { | ||
| 356 | stream->period_pos -= runtime->period_size; | ||
| 357 | return true; | ||
| 358 | } | ||
| 359 | return false; | ||
| 360 | } | ||
| 361 | |||
| 362 | static void capture_urb_complete(struct urb *urb) | ||
| 363 | { | ||
| 364 | struct ua101 *ua = urb->context; | ||
| 365 | struct ua101_stream *stream = &ua->capture; | ||
| 366 | unsigned long flags; | ||
| 367 | unsigned int frames, write_ptr; | ||
| 368 | bool do_period_elapsed; | ||
| 369 | int err; | ||
| 370 | |||
| 371 | if (unlikely(urb->status == -ENOENT || /* unlinked */ | ||
| 372 | urb->status == -ENODEV || /* device removed */ | ||
| 373 | urb->status == -ECONNRESET || /* unlinked */ | ||
| 374 | urb->status == -ESHUTDOWN)) /* device disabled */ | ||
| 375 | goto stream_stopped; | ||
| 376 | |||
| 377 | if (urb->status >= 0 && urb->iso_frame_desc[0].status >= 0) | ||
| 378 | frames = urb->iso_frame_desc[0].actual_length / | ||
| 379 | stream->frame_bytes; | ||
| 380 | else | ||
| 381 | frames = 0; | ||
| 382 | |||
| 383 | spin_lock_irqsave(&ua->lock, flags); | ||
| 384 | |||
| 385 | if (frames > 0 && test_bit(ALSA_CAPTURE_RUNNING, &ua->states)) | ||
| 386 | do_period_elapsed = copy_capture_data(stream, urb, frames); | ||
| 387 | else | ||
| 388 | do_period_elapsed = false; | ||
| 389 | |||
| 390 | if (test_bit(USB_CAPTURE_RUNNING, &ua->states)) { | ||
| 391 | err = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 392 | if (unlikely(err < 0)) { | ||
| 393 | spin_unlock_irqrestore(&ua->lock, flags); | ||
| 394 | dev_err(&ua->dev->dev, "USB request error %d: %s\n", | ||
| 395 | err, usb_error_string(err)); | ||
| 396 | goto stream_stopped; | ||
| 397 | } | ||
| 398 | |||
| 399 | /* append packet size to FIFO */ | ||
| 400 | write_ptr = ua->rate_feedback_start; | ||
| 401 | add_with_wraparound(ua, &write_ptr, ua->rate_feedback_count); | ||
| 402 | ua->rate_feedback[write_ptr] = frames; | ||
| 403 | if (ua->rate_feedback_count < ua->playback.queue_length) { | ||
| 404 | ua->rate_feedback_count++; | ||
| 405 | if (ua->rate_feedback_count == | ||
| 406 | ua->playback.queue_length) | ||
| 407 | wake_up(&ua->rate_feedback_wait); | ||
| 408 | } else { | ||
| 409 | /* | ||
| 410 | * Ring buffer overflow; this happens when the playback | ||
| 411 | * stream is not running. Throw away the oldest entry, | ||
| 412 | * so that the playback stream, when it starts, sees | ||
| 413 | * the most recent packet sizes. | ||
| 414 | */ | ||
| 415 | add_with_wraparound(ua, &ua->rate_feedback_start, 1); | ||
| 416 | } | ||
| 417 | if (test_bit(USB_PLAYBACK_RUNNING, &ua->states) && | ||
| 418 | !list_empty(&ua->ready_playback_urbs)) | ||
| 419 | tasklet_schedule(&ua->playback_tasklet); | ||
| 420 | } | ||
| 421 | |||
| 422 | spin_unlock_irqrestore(&ua->lock, flags); | ||
| 423 | |||
| 424 | if (do_period_elapsed) | ||
| 425 | snd_pcm_period_elapsed(stream->substream); | ||
| 426 | |||
| 427 | /* for debugging: measure the sample rate relative to the USB clock */ | ||
| 428 | ua->fps[ua->frame_counter++ / ua->packets_per_second] += frames; | ||
| 429 | if (ua->frame_counter >= ARRAY_SIZE(ua->fps) * ua->packets_per_second) { | ||
| 430 | printk(KERN_DEBUG "capture rate:"); | ||
| 431 | for (frames = 0; frames < ARRAY_SIZE(ua->fps); ++frames) | ||
| 432 | printk(KERN_CONT " %u", ua->fps[frames]); | ||
| 433 | printk(KERN_CONT "\n"); | ||
| 434 | memset(ua->fps, 0, sizeof(ua->fps)); | ||
| 435 | ua->frame_counter = 0; | ||
| 436 | } | ||
| 437 | return; | ||
| 438 | |||
| 439 | stream_stopped: | ||
| 440 | abort_usb_playback(ua); | ||
| 441 | abort_usb_capture(ua); | ||
| 442 | abort_alsa_playback(ua); | ||
| 443 | abort_alsa_capture(ua); | ||
| 444 | } | ||
| 445 | |||
| 446 | static void first_capture_urb_complete(struct urb *urb) | ||
| 447 | { | ||
| 448 | struct ua101 *ua = urb->context; | ||
| 449 | |||
| 450 | urb->complete = capture_urb_complete; | ||
| 451 | capture_urb_complete(urb); | ||
| 452 | |||
| 453 | set_bit(CAPTURE_URB_COMPLETED, &ua->states); | ||
| 454 | wake_up(&ua->alsa_capture_wait); | ||
| 455 | } | ||
| 456 | |||
| 457 | static int submit_stream_urbs(struct ua101 *ua, struct ua101_stream *stream) | ||
| 458 | { | ||
| 459 | unsigned int i; | ||
| 460 | |||
| 461 | for (i = 0; i < stream->queue_length; ++i) { | ||
| 462 | int err = usb_submit_urb(&stream->urbs[i]->urb, GFP_KERNEL); | ||
| 463 | if (err < 0) { | ||
| 464 | dev_err(&ua->dev->dev, "USB request error %d: %s\n", | ||
| 465 | err, usb_error_string(err)); | ||
| 466 | return err; | ||
| 467 | } | ||
| 468 | } | ||
| 469 | return 0; | ||
| 470 | } | ||
| 471 | |||
| 472 | static void kill_stream_urbs(struct ua101_stream *stream) | ||
| 473 | { | ||
| 474 | unsigned int i; | ||
| 475 | |||
| 476 | for (i = 0; i < stream->queue_length; ++i) | ||
| 477 | usb_kill_urb(&stream->urbs[i]->urb); | ||
| 478 | } | ||
| 479 | |||
| 480 | static int enable_iso_interface(struct ua101 *ua, unsigned int intf_index) | ||
| 481 | { | ||
| 482 | struct usb_host_interface *alts; | ||
| 483 | |||
| 484 | alts = ua->intf[intf_index]->cur_altsetting; | ||
| 485 | if (alts->desc.bAlternateSetting != 1) { | ||
| 486 | int err = usb_set_interface(ua->dev, | ||
| 487 | alts->desc.bInterfaceNumber, 1); | ||
| 488 | if (err < 0) { | ||
| 489 | dev_err(&ua->dev->dev, | ||
| 490 | "cannot initialize interface; error %d: %s\n", | ||
| 491 | err, usb_error_string(err)); | ||
| 492 | return err; | ||
| 493 | } | ||
| 494 | } | ||
| 495 | return 0; | ||
| 496 | } | ||
| 497 | |||
| 498 | static void disable_iso_interface(struct ua101 *ua, unsigned int intf_index) | ||
| 499 | { | ||
| 500 | struct usb_host_interface *alts; | ||
| 501 | |||
| 502 | alts = ua->intf[intf_index]->cur_altsetting; | ||
| 503 | if (alts->desc.bAlternateSetting != 0) { | ||
| 504 | int err = usb_set_interface(ua->dev, | ||
| 505 | alts->desc.bInterfaceNumber, 0); | ||
| 506 | if (err < 0 && !test_bit(DISCONNECTED, &ua->states)) | ||
| 507 | dev_warn(&ua->dev->dev, | ||
| 508 | "interface reset failed; error %d: %s\n", | ||
| 509 | err, usb_error_string(err)); | ||
| 510 | } | ||
| 511 | } | ||
| 512 | |||
| 513 | static void stop_usb_capture(struct ua101 *ua) | ||
| 514 | { | ||
| 515 | clear_bit(USB_CAPTURE_RUNNING, &ua->states); | ||
| 516 | |||
| 517 | kill_stream_urbs(&ua->capture); | ||
| 518 | |||
| 519 | disable_iso_interface(ua, INTF_CAPTURE); | ||
| 520 | } | ||
| 521 | |||
| 522 | static int start_usb_capture(struct ua101 *ua) | ||
| 523 | { | ||
| 524 | int err; | ||
| 525 | |||
| 526 | if (test_bit(DISCONNECTED, &ua->states)) | ||
| 527 | return -ENODEV; | ||
| 528 | |||
| 529 | if (test_bit(USB_CAPTURE_RUNNING, &ua->states)) | ||
| 530 | return 0; | ||
| 531 | |||
| 532 | kill_stream_urbs(&ua->capture); | ||
| 533 | |||
| 534 | err = enable_iso_interface(ua, INTF_CAPTURE); | ||
| 535 | if (err < 0) | ||
| 536 | return err; | ||
| 537 | |||
| 538 | clear_bit(CAPTURE_URB_COMPLETED, &ua->states); | ||
| 539 | ua->capture.urbs[0]->urb.complete = first_capture_urb_complete; | ||
| 540 | ua->rate_feedback_start = 0; | ||
| 541 | ua->rate_feedback_count = 0; | ||
| 542 | |||
| 543 | set_bit(USB_CAPTURE_RUNNING, &ua->states); | ||
| 544 | err = submit_stream_urbs(ua, &ua->capture); | ||
| 545 | if (err < 0) | ||
| 546 | stop_usb_capture(ua); | ||
| 547 | return err; | ||
| 548 | } | ||
| 549 | |||
| 550 | static void stop_usb_playback(struct ua101 *ua) | ||
| 551 | { | ||
| 552 | clear_bit(USB_PLAYBACK_RUNNING, &ua->states); | ||
| 553 | |||
| 554 | kill_stream_urbs(&ua->playback); | ||
| 555 | |||
| 556 | tasklet_kill(&ua->playback_tasklet); | ||
| 557 | |||
| 558 | disable_iso_interface(ua, INTF_PLAYBACK); | ||
| 559 | } | ||
| 560 | |||
| 561 | static int start_usb_playback(struct ua101 *ua) | ||
| 562 | { | ||
| 563 | unsigned int i, frames; | ||
| 564 | struct urb *urb; | ||
| 565 | int err = 0; | ||
| 566 | |||
| 567 | if (test_bit(DISCONNECTED, &ua->states)) | ||
| 568 | return -ENODEV; | ||
| 569 | |||
| 570 | if (test_bit(USB_PLAYBACK_RUNNING, &ua->states)) | ||
| 571 | return 0; | ||
| 572 | |||
| 573 | kill_stream_urbs(&ua->playback); | ||
| 574 | tasklet_kill(&ua->playback_tasklet); | ||
| 575 | |||
| 576 | err = enable_iso_interface(ua, INTF_PLAYBACK); | ||
| 577 | if (err < 0) | ||
| 578 | return err; | ||
| 579 | |||
| 580 | clear_bit(PLAYBACK_URB_COMPLETED, &ua->states); | ||
| 581 | ua->playback.urbs[0]->urb.complete = | ||
| 582 | first_playback_urb_complete; | ||
| 583 | spin_lock_irq(&ua->lock); | ||
| 584 | INIT_LIST_HEAD(&ua->ready_playback_urbs); | ||
| 585 | spin_unlock_irq(&ua->lock); | ||
| 586 | |||
| 587 | /* | ||
| 588 | * We submit the initial URBs all at once, so we have to wait for the | ||
| 589 | * packet size FIFO to be full. | ||
| 590 | */ | ||
| 591 | wait_event(ua->rate_feedback_wait, | ||
| 592 | ua->rate_feedback_count >= ua->playback.queue_length || | ||
| 593 | !test_bit(USB_CAPTURE_RUNNING, &ua->states) || | ||
| 594 | test_bit(DISCONNECTED, &ua->states)); | ||
| 595 | if (test_bit(DISCONNECTED, &ua->states)) { | ||
| 596 | stop_usb_playback(ua); | ||
| 597 | return -ENODEV; | ||
| 598 | } | ||
| 599 | if (!test_bit(USB_CAPTURE_RUNNING, &ua->states)) { | ||
| 600 | stop_usb_playback(ua); | ||
| 601 | return -EIO; | ||
| 602 | } | ||
| 603 | |||
| 604 | for (i = 0; i < ua->playback.queue_length; ++i) { | ||
| 605 | /* all initial URBs contain silence */ | ||
| 606 | spin_lock_irq(&ua->lock); | ||
| 607 | frames = ua->rate_feedback[ua->rate_feedback_start]; | ||
| 608 | add_with_wraparound(ua, &ua->rate_feedback_start, 1); | ||
| 609 | ua->rate_feedback_count--; | ||
| 610 | spin_unlock_irq(&ua->lock); | ||
| 611 | urb = &ua->playback.urbs[i]->urb; | ||
| 612 | urb->iso_frame_desc[0].length = | ||
| 613 | frames * ua->playback.frame_bytes; | ||
| 614 | memset(urb->transfer_buffer, 0, | ||
| 615 | urb->iso_frame_desc[0].length); | ||
| 616 | } | ||
| 617 | |||
| 618 | set_bit(USB_PLAYBACK_RUNNING, &ua->states); | ||
| 619 | err = submit_stream_urbs(ua, &ua->playback); | ||
| 620 | if (err < 0) | ||
| 621 | stop_usb_playback(ua); | ||
| 622 | return err; | ||
| 623 | } | ||
| 624 | |||
| 625 | static void abort_alsa_capture(struct ua101 *ua) | ||
| 626 | { | ||
| 627 | if (test_bit(ALSA_CAPTURE_RUNNING, &ua->states)) | ||
| 628 | snd_pcm_stop(ua->capture.substream, SNDRV_PCM_STATE_XRUN); | ||
| 629 | } | ||
| 630 | |||
| 631 | static void abort_alsa_playback(struct ua101 *ua) | ||
| 632 | { | ||
| 633 | if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states)) | ||
| 634 | snd_pcm_stop(ua->playback.substream, SNDRV_PCM_STATE_XRUN); | ||
| 635 | } | ||
| 636 | |||
| 637 | static int set_stream_hw(struct ua101 *ua, struct snd_pcm_substream *substream, | ||
| 638 | unsigned int channels) | ||
| 639 | { | ||
| 640 | int err; | ||
| 641 | |||
| 642 | substream->runtime->hw.info = | ||
| 643 | SNDRV_PCM_INFO_MMAP | | ||
| 644 | SNDRV_PCM_INFO_MMAP_VALID | | ||
| 645 | SNDRV_PCM_INFO_BATCH | | ||
| 646 | SNDRV_PCM_INFO_INTERLEAVED | | ||
| 647 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
| 648 | SNDRV_PCM_INFO_FIFO_IN_FRAMES; | ||
| 649 | substream->runtime->hw.formats = ua->format_bit; | ||
| 650 | substream->runtime->hw.rates = snd_pcm_rate_to_rate_bit(ua->rate); | ||
| 651 | substream->runtime->hw.rate_min = ua->rate; | ||
| 652 | substream->runtime->hw.rate_max = ua->rate; | ||
| 653 | substream->runtime->hw.channels_min = channels; | ||
| 654 | substream->runtime->hw.channels_max = channels; | ||
| 655 | substream->runtime->hw.buffer_bytes_max = 45000 * 1024; | ||
| 656 | substream->runtime->hw.period_bytes_min = 1; | ||
| 657 | substream->runtime->hw.period_bytes_max = UINT_MAX; | ||
| 658 | substream->runtime->hw.periods_min = 2; | ||
| 659 | substream->runtime->hw.periods_max = UINT_MAX; | ||
| 660 | err = snd_pcm_hw_constraint_minmax(substream->runtime, | ||
| 661 | SNDRV_PCM_HW_PARAM_PERIOD_TIME, | ||
| 662 | 1500000 / ua->packets_per_second, | ||
| 663 | 8192000); | ||
| 664 | if (err < 0) | ||
| 665 | return err; | ||
| 666 | err = snd_pcm_hw_constraint_msbits(substream->runtime, 0, 32, 24); | ||
| 667 | return err; | ||
| 668 | } | ||
| 669 | |||
| 670 | static int capture_pcm_open(struct snd_pcm_substream *substream) | ||
| 671 | { | ||
| 672 | struct ua101 *ua = substream->private_data; | ||
| 673 | int err; | ||
| 674 | |||
| 675 | ua->capture.substream = substream; | ||
| 676 | err = set_stream_hw(ua, substream, ua->capture.channels); | ||
| 677 | if (err < 0) | ||
| 678 | return err; | ||
| 679 | substream->runtime->hw.fifo_size = | ||
| 680 | DIV_ROUND_CLOSEST(ua->rate, ua->packets_per_second); | ||
| 681 | substream->runtime->delay = substream->runtime->hw.fifo_size; | ||
| 682 | |||
| 683 | mutex_lock(&ua->mutex); | ||
| 684 | err = start_usb_capture(ua); | ||
| 685 | if (err >= 0) | ||
| 686 | set_bit(ALSA_CAPTURE_OPEN, &ua->states); | ||
| 687 | mutex_unlock(&ua->mutex); | ||
| 688 | return err; | ||
| 689 | } | ||
| 690 | |||
| 691 | static int playback_pcm_open(struct snd_pcm_substream *substream) | ||
| 692 | { | ||
| 693 | struct ua101 *ua = substream->private_data; | ||
| 694 | int err; | ||
| 695 | |||
| 696 | ua->playback.substream = substream; | ||
| 697 | err = set_stream_hw(ua, substream, ua->playback.channels); | ||
| 698 | if (err < 0) | ||
| 699 | return err; | ||
| 700 | substream->runtime->hw.fifo_size = | ||
| 701 | DIV_ROUND_CLOSEST(ua->rate * ua->playback.queue_length, | ||
| 702 | ua->packets_per_second); | ||
| 703 | |||
| 704 | mutex_lock(&ua->mutex); | ||
| 705 | err = start_usb_capture(ua); | ||
| 706 | if (err < 0) | ||
| 707 | goto error; | ||
| 708 | err = start_usb_playback(ua); | ||
| 709 | if (err < 0) { | ||
| 710 | if (!test_bit(ALSA_CAPTURE_OPEN, &ua->states)) | ||
| 711 | stop_usb_capture(ua); | ||
| 712 | goto error; | ||
| 713 | } | ||
| 714 | set_bit(ALSA_PLAYBACK_OPEN, &ua->states); | ||
| 715 | error: | ||
| 716 | mutex_unlock(&ua->mutex); | ||
| 717 | return err; | ||
| 718 | } | ||
| 719 | |||
| 720 | static int capture_pcm_close(struct snd_pcm_substream *substream) | ||
| 721 | { | ||
| 722 | struct ua101 *ua = substream->private_data; | ||
| 723 | |||
| 724 | mutex_lock(&ua->mutex); | ||
| 725 | clear_bit(ALSA_CAPTURE_OPEN, &ua->states); | ||
| 726 | if (!test_bit(ALSA_PLAYBACK_OPEN, &ua->states)) | ||
| 727 | stop_usb_capture(ua); | ||
| 728 | mutex_unlock(&ua->mutex); | ||
| 729 | return 0; | ||
| 730 | } | ||
| 731 | |||
| 732 | static int playback_pcm_close(struct snd_pcm_substream *substream) | ||
| 733 | { | ||
| 734 | struct ua101 *ua = substream->private_data; | ||
| 735 | |||
| 736 | mutex_lock(&ua->mutex); | ||
| 737 | stop_usb_playback(ua); | ||
| 738 | clear_bit(ALSA_PLAYBACK_OPEN, &ua->states); | ||
| 739 | if (!test_bit(ALSA_CAPTURE_OPEN, &ua->states)) | ||
| 740 | stop_usb_capture(ua); | ||
| 741 | mutex_unlock(&ua->mutex); | ||
| 742 | return 0; | ||
| 743 | } | ||
| 744 | |||
| 745 | static int capture_pcm_hw_params(struct snd_pcm_substream *substream, | ||
| 746 | struct snd_pcm_hw_params *hw_params) | ||
| 747 | { | ||
| 748 | struct ua101 *ua = substream->private_data; | ||
| 749 | int err; | ||
| 750 | |||
| 751 | mutex_lock(&ua->mutex); | ||
| 752 | err = start_usb_capture(ua); | ||
| 753 | mutex_unlock(&ua->mutex); | ||
| 754 | if (err < 0) | ||
| 755 | return err; | ||
| 756 | |||
| 757 | return snd_pcm_lib_alloc_vmalloc_buffer(substream, | ||
| 758 | params_buffer_bytes(hw_params)); | ||
| 759 | } | ||
| 760 | |||
| 761 | static int playback_pcm_hw_params(struct snd_pcm_substream *substream, | ||
| 762 | struct snd_pcm_hw_params *hw_params) | ||
| 763 | { | ||
| 764 | struct ua101 *ua = substream->private_data; | ||
| 765 | int err; | ||
| 766 | |||
| 767 | mutex_lock(&ua->mutex); | ||
| 768 | err = start_usb_capture(ua); | ||
| 769 | if (err >= 0) | ||
| 770 | err = start_usb_playback(ua); | ||
| 771 | mutex_unlock(&ua->mutex); | ||
| 772 | if (err < 0) | ||
| 773 | return err; | ||
| 774 | |||
| 775 | return snd_pcm_lib_alloc_vmalloc_buffer(substream, | ||
| 776 | params_buffer_bytes(hw_params)); | ||
| 777 | } | ||
| 778 | |||
| 779 | static int ua101_pcm_hw_free(struct snd_pcm_substream *substream) | ||
| 780 | { | ||
| 781 | return snd_pcm_lib_free_vmalloc_buffer(substream); | ||
| 782 | } | ||
| 783 | |||
| 784 | static int capture_pcm_prepare(struct snd_pcm_substream *substream) | ||
| 785 | { | ||
| 786 | struct ua101 *ua = substream->private_data; | ||
| 787 | int err; | ||
| 788 | |||
| 789 | mutex_lock(&ua->mutex); | ||
| 790 | err = start_usb_capture(ua); | ||
| 791 | mutex_unlock(&ua->mutex); | ||
| 792 | if (err < 0) | ||
| 793 | return err; | ||
| 794 | |||
| 795 | /* | ||
| 796 | * The EHCI driver schedules the first packet of an iso stream at 10 ms | ||
| 797 | * in the future, i.e., no data is actually captured for that long. | ||
| 798 | * Take the wait here so that the stream is known to be actually | ||
| 799 | * running when the start trigger has been called. | ||
| 800 | */ | ||
| 801 | wait_event(ua->alsa_capture_wait, | ||
| 802 | test_bit(CAPTURE_URB_COMPLETED, &ua->states) || | ||
| 803 | !test_bit(USB_CAPTURE_RUNNING, &ua->states)); | ||
| 804 | if (test_bit(DISCONNECTED, &ua->states)) | ||
| 805 | return -ENODEV; | ||
| 806 | if (!test_bit(USB_CAPTURE_RUNNING, &ua->states)) | ||
| 807 | return -EIO; | ||
| 808 | |||
| 809 | ua->capture.period_pos = 0; | ||
| 810 | ua->capture.buffer_pos = 0; | ||
| 811 | return 0; | ||
| 812 | } | ||
| 813 | |||
| 814 | static int playback_pcm_prepare(struct snd_pcm_substream *substream) | ||
| 815 | { | ||
| 816 | struct ua101 *ua = substream->private_data; | ||
| 817 | int err; | ||
| 818 | |||
| 819 | mutex_lock(&ua->mutex); | ||
| 820 | err = start_usb_capture(ua); | ||
| 821 | if (err >= 0) | ||
| 822 | err = start_usb_playback(ua); | ||
| 823 | mutex_unlock(&ua->mutex); | ||
| 824 | if (err < 0) | ||
| 825 | return err; | ||
| 826 | |||
| 827 | /* see the comment in capture_pcm_prepare() */ | ||
| 828 | wait_event(ua->alsa_playback_wait, | ||
| 829 | test_bit(PLAYBACK_URB_COMPLETED, &ua->states) || | ||
| 830 | !test_bit(USB_PLAYBACK_RUNNING, &ua->states)); | ||
| 831 | if (test_bit(DISCONNECTED, &ua->states)) | ||
| 832 | return -ENODEV; | ||
| 833 | if (!test_bit(USB_PLAYBACK_RUNNING, &ua->states)) | ||
| 834 | return -EIO; | ||
| 835 | |||
| 836 | substream->runtime->delay = 0; | ||
| 837 | ua->playback.period_pos = 0; | ||
| 838 | ua->playback.buffer_pos = 0; | ||
| 839 | return 0; | ||
| 840 | } | ||
| 841 | |||
| 842 | static int capture_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
| 843 | { | ||
| 844 | struct ua101 *ua = substream->private_data; | ||
| 845 | |||
| 846 | switch (cmd) { | ||
| 847 | case SNDRV_PCM_TRIGGER_START: | ||
| 848 | if (!test_bit(USB_CAPTURE_RUNNING, &ua->states)) | ||
| 849 | return -EIO; | ||
| 850 | set_bit(ALSA_CAPTURE_RUNNING, &ua->states); | ||
| 851 | return 0; | ||
| 852 | case SNDRV_PCM_TRIGGER_STOP: | ||
| 853 | clear_bit(ALSA_CAPTURE_RUNNING, &ua->states); | ||
| 854 | return 0; | ||
| 855 | default: | ||
| 856 | return -EINVAL; | ||
| 857 | } | ||
| 858 | } | ||
| 859 | |||
| 860 | static int playback_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
| 861 | { | ||
| 862 | struct ua101 *ua = substream->private_data; | ||
| 863 | |||
| 864 | switch (cmd) { | ||
| 865 | case SNDRV_PCM_TRIGGER_START: | ||
| 866 | if (!test_bit(USB_PLAYBACK_RUNNING, &ua->states)) | ||
| 867 | return -EIO; | ||
| 868 | set_bit(ALSA_PLAYBACK_RUNNING, &ua->states); | ||
| 869 | return 0; | ||
| 870 | case SNDRV_PCM_TRIGGER_STOP: | ||
| 871 | clear_bit(ALSA_PLAYBACK_RUNNING, &ua->states); | ||
| 872 | return 0; | ||
| 873 | default: | ||
| 874 | return -EINVAL; | ||
| 875 | } | ||
| 876 | } | ||
| 877 | |||
| 878 | static inline snd_pcm_uframes_t ua101_pcm_pointer(struct ua101 *ua, | ||
| 879 | struct ua101_stream *stream) | ||
| 880 | { | ||
| 881 | unsigned long flags; | ||
| 882 | unsigned int pos; | ||
| 883 | |||
| 884 | spin_lock_irqsave(&ua->lock, flags); | ||
| 885 | pos = stream->buffer_pos; | ||
| 886 | spin_unlock_irqrestore(&ua->lock, flags); | ||
| 887 | return pos; | ||
| 888 | } | ||
| 889 | |||
| 890 | static snd_pcm_uframes_t capture_pcm_pointer(struct snd_pcm_substream *subs) | ||
| 891 | { | ||
| 892 | struct ua101 *ua = subs->private_data; | ||
| 893 | |||
| 894 | return ua101_pcm_pointer(ua, &ua->capture); | ||
| 895 | } | ||
| 896 | |||
| 897 | static snd_pcm_uframes_t playback_pcm_pointer(struct snd_pcm_substream *subs) | ||
| 898 | { | ||
| 899 | struct ua101 *ua = subs->private_data; | ||
| 900 | |||
| 901 | return ua101_pcm_pointer(ua, &ua->playback); | ||
| 902 | } | ||
| 903 | |||
| 904 | static struct snd_pcm_ops capture_pcm_ops = { | ||
| 905 | .open = capture_pcm_open, | ||
| 906 | .close = capture_pcm_close, | ||
| 907 | .ioctl = snd_pcm_lib_ioctl, | ||
| 908 | .hw_params = capture_pcm_hw_params, | ||
| 909 | .hw_free = ua101_pcm_hw_free, | ||
| 910 | .prepare = capture_pcm_prepare, | ||
| 911 | .trigger = capture_pcm_trigger, | ||
| 912 | .pointer = capture_pcm_pointer, | ||
| 913 | .page = snd_pcm_lib_get_vmalloc_page, | ||
| 914 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
| 915 | }; | ||
| 916 | |||
| 917 | static struct snd_pcm_ops playback_pcm_ops = { | ||
| 918 | .open = playback_pcm_open, | ||
| 919 | .close = playback_pcm_close, | ||
| 920 | .ioctl = snd_pcm_lib_ioctl, | ||
| 921 | .hw_params = playback_pcm_hw_params, | ||
| 922 | .hw_free = ua101_pcm_hw_free, | ||
| 923 | .prepare = playback_pcm_prepare, | ||
| 924 | .trigger = playback_pcm_trigger, | ||
| 925 | .pointer = playback_pcm_pointer, | ||
| 926 | .page = snd_pcm_lib_get_vmalloc_page, | ||
| 927 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
| 928 | }; | ||
| 929 | |||
| 930 | static const struct uac_format_type_i_discrete_descriptor * | ||
| 931 | find_format_descriptor(struct usb_interface *interface) | ||
| 932 | { | ||
| 933 | struct usb_host_interface *alt; | ||
| 934 | u8 *extra; | ||
| 935 | int extralen; | ||
| 936 | |||
| 937 | if (interface->num_altsetting != 2) { | ||
| 938 | dev_err(&interface->dev, "invalid num_altsetting\n"); | ||
| 939 | return NULL; | ||
| 940 | } | ||
| 941 | |||
| 942 | alt = &interface->altsetting[0]; | ||
| 943 | if (alt->desc.bNumEndpoints != 0) { | ||
| 944 | dev_err(&interface->dev, "invalid bNumEndpoints\n"); | ||
| 945 | return NULL; | ||
| 946 | } | ||
| 947 | |||
| 948 | alt = &interface->altsetting[1]; | ||
| 949 | if (alt->desc.bNumEndpoints != 1) { | ||
| 950 | dev_err(&interface->dev, "invalid bNumEndpoints\n"); | ||
| 951 | return NULL; | ||
| 952 | } | ||
| 953 | |||
| 954 | extra = alt->extra; | ||
| 955 | extralen = alt->extralen; | ||
| 956 | while (extralen >= sizeof(struct usb_descriptor_header)) { | ||
| 957 | struct uac_format_type_i_discrete_descriptor *desc; | ||
| 958 | |||
| 959 | desc = (struct uac_format_type_i_discrete_descriptor *)extra; | ||
| 960 | if (desc->bLength > extralen) { | ||
| 961 | dev_err(&interface->dev, "descriptor overflow\n"); | ||
| 962 | return NULL; | ||
| 963 | } | ||
| 964 | if (desc->bLength == UAC_FORMAT_TYPE_I_DISCRETE_DESC_SIZE(1) && | ||
| 965 | desc->bDescriptorType == USB_DT_CS_INTERFACE && | ||
| 966 | desc->bDescriptorSubtype == UAC_FORMAT_TYPE) { | ||
| 967 | if (desc->bFormatType != UAC_FORMAT_TYPE_I_PCM || | ||
| 968 | desc->bSamFreqType != 1) { | ||
| 969 | dev_err(&interface->dev, | ||
| 970 | "invalid format type\n"); | ||
| 971 | return NULL; | ||
| 972 | } | ||
| 973 | return desc; | ||
| 974 | } | ||
| 975 | extralen -= desc->bLength; | ||
| 976 | extra += desc->bLength; | ||
| 977 | } | ||
| 978 | dev_err(&interface->dev, "sample format descriptor not found\n"); | ||
| 979 | return NULL; | ||
| 980 | } | ||
| 981 | |||
| 982 | static int detect_usb_format(struct ua101 *ua) | ||
| 983 | { | ||
| 984 | const struct uac_format_type_i_discrete_descriptor *fmt_capture; | ||
| 985 | const struct uac_format_type_i_discrete_descriptor *fmt_playback; | ||
| 986 | const struct usb_endpoint_descriptor *epd; | ||
| 987 | unsigned int rate2; | ||
| 988 | |||
| 989 | fmt_capture = find_format_descriptor(ua->intf[INTF_CAPTURE]); | ||
| 990 | fmt_playback = find_format_descriptor(ua->intf[INTF_PLAYBACK]); | ||
| 991 | if (!fmt_capture || !fmt_playback) | ||
| 992 | return -ENXIO; | ||
| 993 | |||
| 994 | switch (fmt_capture->bSubframeSize) { | ||
| 995 | case 3: | ||
| 996 | ua->format_bit = SNDRV_PCM_FMTBIT_S24_3LE; | ||
| 997 | break; | ||
| 998 | case 4: | ||
| 999 | ua->format_bit = SNDRV_PCM_FMTBIT_S32_LE; | ||
| 1000 | break; | ||
| 1001 | default: | ||
| 1002 | dev_err(&ua->dev->dev, "sample width is not 24 or 32 bits\n"); | ||
| 1003 | return -ENXIO; | ||
| 1004 | } | ||
| 1005 | if (fmt_capture->bSubframeSize != fmt_playback->bSubframeSize) { | ||
| 1006 | dev_err(&ua->dev->dev, | ||
| 1007 | "playback/capture sample widths do not match\n"); | ||
| 1008 | return -ENXIO; | ||
| 1009 | } | ||
| 1010 | |||
| 1011 | if (fmt_capture->bBitResolution != 24 || | ||
| 1012 | fmt_playback->bBitResolution != 24) { | ||
| 1013 | dev_err(&ua->dev->dev, "sample width is not 24 bits\n"); | ||
| 1014 | return -ENXIO; | ||
| 1015 | } | ||
| 1016 | |||
| 1017 | ua->rate = combine_triple(fmt_capture->tSamFreq[0]); | ||
| 1018 | rate2 = combine_triple(fmt_playback->tSamFreq[0]); | ||
| 1019 | if (ua->rate != rate2) { | ||
| 1020 | dev_err(&ua->dev->dev, | ||
| 1021 | "playback/capture rates do not match: %u/%u\n", | ||
| 1022 | rate2, ua->rate); | ||
| 1023 | return -ENXIO; | ||
| 1024 | } | ||
| 1025 | |||
| 1026 | switch (ua->dev->speed) { | ||
| 1027 | case USB_SPEED_FULL: | ||
| 1028 | ua->packets_per_second = 1000; | ||
| 1029 | break; | ||
| 1030 | case USB_SPEED_HIGH: | ||
| 1031 | ua->packets_per_second = 8000; | ||
| 1032 | break; | ||
| 1033 | default: | ||
| 1034 | dev_err(&ua->dev->dev, "unknown device speed\n"); | ||
| 1035 | return -ENXIO; | ||
| 1036 | } | ||
| 1037 | |||
| 1038 | ua->capture.channels = fmt_capture->bNrChannels; | ||
| 1039 | ua->playback.channels = fmt_playback->bNrChannels; | ||
| 1040 | ua->capture.frame_bytes = | ||
| 1041 | fmt_capture->bSubframeSize * ua->capture.channels; | ||
| 1042 | ua->playback.frame_bytes = | ||
| 1043 | fmt_playback->bSubframeSize * ua->playback.channels; | ||
| 1044 | |||
| 1045 | epd = &ua->intf[INTF_CAPTURE]->altsetting[1].endpoint[0].desc; | ||
| 1046 | if (!usb_endpoint_is_isoc_in(epd)) { | ||
| 1047 | dev_err(&ua->dev->dev, "invalid capture endpoint\n"); | ||
| 1048 | return -ENXIO; | ||
| 1049 | } | ||
| 1050 | ua->capture.usb_pipe = usb_rcvisocpipe(ua->dev, usb_endpoint_num(epd)); | ||
| 1051 | ua->capture.max_packet_bytes = le16_to_cpu(epd->wMaxPacketSize); | ||
| 1052 | |||
| 1053 | epd = &ua->intf[INTF_PLAYBACK]->altsetting[1].endpoint[0].desc; | ||
| 1054 | if (!usb_endpoint_is_isoc_out(epd)) { | ||
| 1055 | dev_err(&ua->dev->dev, "invalid playback endpoint\n"); | ||
| 1056 | return -ENXIO; | ||
| 1057 | } | ||
| 1058 | ua->playback.usb_pipe = usb_sndisocpipe(ua->dev, usb_endpoint_num(epd)); | ||
| 1059 | ua->playback.max_packet_bytes = le16_to_cpu(epd->wMaxPacketSize); | ||
| 1060 | return 0; | ||
| 1061 | } | ||
| 1062 | |||
| 1063 | static int alloc_stream_buffers(struct ua101 *ua, struct ua101_stream *stream) | ||
| 1064 | { | ||
| 1065 | unsigned int remaining_packets, packets, packets_per_page, i; | ||
| 1066 | size_t size; | ||
| 1067 | |||
| 1068 | stream->queue_length = queue_length; | ||
| 1069 | stream->queue_length = max(stream->queue_length, | ||
| 1070 | (unsigned int)MIN_QUEUE_LENGTH); | ||
| 1071 | stream->queue_length = min(stream->queue_length, | ||
| 1072 | (unsigned int)MAX_QUEUE_LENGTH); | ||
| 1073 | |||
| 1074 | /* | ||
| 1075 | * The cache pool sizes used by usb_buffer_alloc() (128, 512, 2048) are | ||
| 1076 | * quite bad when used with the packet sizes of this device (e.g. 280, | ||
| 1077 | * 520, 624). Therefore, we allocate and subdivide entire pages, using | ||
| 1078 | * a smaller buffer only for the last chunk. | ||
| 1079 | */ | ||
| 1080 | remaining_packets = stream->queue_length; | ||
| 1081 | packets_per_page = PAGE_SIZE / stream->max_packet_bytes; | ||
| 1082 | for (i = 0; i < ARRAY_SIZE(stream->buffers); ++i) { | ||
| 1083 | packets = min(remaining_packets, packets_per_page); | ||
| 1084 | size = packets * stream->max_packet_bytes; | ||
| 1085 | stream->buffers[i].addr = | ||
| 1086 | usb_buffer_alloc(ua->dev, size, GFP_KERNEL, | ||
| 1087 | &stream->buffers[i].dma); | ||
| 1088 | if (!stream->buffers[i].addr) | ||
| 1089 | return -ENOMEM; | ||
| 1090 | stream->buffers[i].size = size; | ||
| 1091 | remaining_packets -= packets; | ||
| 1092 | if (!remaining_packets) | ||
| 1093 | break; | ||
| 1094 | } | ||
| 1095 | if (remaining_packets) { | ||
| 1096 | dev_err(&ua->dev->dev, "too many packets\n"); | ||
| 1097 | return -ENXIO; | ||
| 1098 | } | ||
| 1099 | return 0; | ||
| 1100 | } | ||
| 1101 | |||
| 1102 | static void free_stream_buffers(struct ua101 *ua, struct ua101_stream *stream) | ||
| 1103 | { | ||
| 1104 | unsigned int i; | ||
| 1105 | |||
| 1106 | for (i = 0; i < ARRAY_SIZE(stream->buffers); ++i) | ||
| 1107 | usb_buffer_free(ua->dev, | ||
| 1108 | stream->buffers[i].size, | ||
| 1109 | stream->buffers[i].addr, | ||
| 1110 | stream->buffers[i].dma); | ||
| 1111 | } | ||
| 1112 | |||
| 1113 | static int alloc_stream_urbs(struct ua101 *ua, struct ua101_stream *stream, | ||
| 1114 | void (*urb_complete)(struct urb *)) | ||
| 1115 | { | ||
| 1116 | unsigned max_packet_size = stream->max_packet_bytes; | ||
| 1117 | struct ua101_urb *urb; | ||
| 1118 | unsigned int b, u = 0; | ||
| 1119 | |||
| 1120 | for (b = 0; b < ARRAY_SIZE(stream->buffers); ++b) { | ||
| 1121 | unsigned int size = stream->buffers[b].size; | ||
| 1122 | u8 *addr = stream->buffers[b].addr; | ||
| 1123 | dma_addr_t dma = stream->buffers[b].dma; | ||
| 1124 | |||
| 1125 | while (size >= max_packet_size) { | ||
| 1126 | if (u >= stream->queue_length) | ||
| 1127 | goto bufsize_error; | ||
| 1128 | urb = kmalloc(sizeof(*urb), GFP_KERNEL); | ||
| 1129 | if (!urb) | ||
| 1130 | return -ENOMEM; | ||
| 1131 | usb_init_urb(&urb->urb); | ||
| 1132 | urb->urb.dev = ua->dev; | ||
| 1133 | urb->urb.pipe = stream->usb_pipe; | ||
| 1134 | urb->urb.transfer_flags = URB_ISO_ASAP | | ||
| 1135 | URB_NO_TRANSFER_DMA_MAP; | ||
| 1136 | urb->urb.transfer_buffer = addr; | ||
| 1137 | urb->urb.transfer_dma = dma; | ||
| 1138 | urb->urb.transfer_buffer_length = max_packet_size; | ||
| 1139 | urb->urb.number_of_packets = 1; | ||
| 1140 | urb->urb.interval = 1; | ||
| 1141 | urb->urb.context = ua; | ||
| 1142 | urb->urb.complete = urb_complete; | ||
| 1143 | urb->urb.iso_frame_desc[0].offset = 0; | ||
| 1144 | urb->urb.iso_frame_desc[0].length = max_packet_size; | ||
| 1145 | stream->urbs[u++] = urb; | ||
| 1146 | size -= max_packet_size; | ||
| 1147 | addr += max_packet_size; | ||
| 1148 | dma += max_packet_size; | ||
| 1149 | } | ||
| 1150 | } | ||
| 1151 | if (u == stream->queue_length) | ||
| 1152 | return 0; | ||
| 1153 | bufsize_error: | ||
| 1154 | dev_err(&ua->dev->dev, "internal buffer size error\n"); | ||
| 1155 | return -ENXIO; | ||
| 1156 | } | ||
| 1157 | |||
| 1158 | static void free_stream_urbs(struct ua101_stream *stream) | ||
| 1159 | { | ||
| 1160 | unsigned int i; | ||
| 1161 | |||
| 1162 | for (i = 0; i < stream->queue_length; ++i) | ||
| 1163 | kfree(stream->urbs[i]); | ||
| 1164 | } | ||
| 1165 | |||
| 1166 | static void free_usb_related_resources(struct ua101 *ua, | ||
| 1167 | struct usb_interface *interface) | ||
| 1168 | { | ||
| 1169 | unsigned int i; | ||
| 1170 | |||
| 1171 | free_stream_urbs(&ua->capture); | ||
| 1172 | free_stream_urbs(&ua->playback); | ||
| 1173 | free_stream_buffers(ua, &ua->capture); | ||
| 1174 | free_stream_buffers(ua, &ua->playback); | ||
| 1175 | |||
| 1176 | for (i = 0; i < ARRAY_SIZE(ua->intf); ++i) | ||
| 1177 | if (ua->intf[i]) { | ||
| 1178 | usb_set_intfdata(ua->intf[i], NULL); | ||
| 1179 | if (ua->intf[i] != interface) | ||
| 1180 | usb_driver_release_interface(&ua101_driver, | ||
| 1181 | ua->intf[i]); | ||
| 1182 | } | ||
| 1183 | } | ||
| 1184 | |||
| 1185 | static void ua101_card_free(struct snd_card *card) | ||
| 1186 | { | ||
| 1187 | struct ua101 *ua = card->private_data; | ||
| 1188 | |||
| 1189 | mutex_destroy(&ua->mutex); | ||
| 1190 | } | ||
| 1191 | |||
| 1192 | static int ua101_probe(struct usb_interface *interface, | ||
| 1193 | const struct usb_device_id *usb_id) | ||
| 1194 | { | ||
| 1195 | static const struct snd_usb_midi_endpoint_info midi_ep = { | ||
| 1196 | .out_cables = 0x0001, | ||
| 1197 | .in_cables = 0x0001 | ||
| 1198 | }; | ||
| 1199 | static const struct snd_usb_audio_quirk midi_quirk = { | ||
| 1200 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | ||
| 1201 | .data = &midi_ep | ||
| 1202 | }; | ||
| 1203 | struct snd_card *card; | ||
| 1204 | struct ua101 *ua; | ||
| 1205 | unsigned int card_index, i; | ||
| 1206 | char usb_path[32]; | ||
| 1207 | int err; | ||
| 1208 | |||
| 1209 | if (interface->altsetting->desc.bInterfaceNumber != 0) | ||
| 1210 | return -ENODEV; | ||
| 1211 | |||
| 1212 | mutex_lock(&devices_mutex); | ||
| 1213 | |||
| 1214 | for (card_index = 0; card_index < SNDRV_CARDS; ++card_index) | ||
| 1215 | if (enable[card_index] && !(devices_used & (1 << card_index))) | ||
| 1216 | break; | ||
| 1217 | if (card_index >= SNDRV_CARDS) { | ||
| 1218 | mutex_unlock(&devices_mutex); | ||
| 1219 | return -ENOENT; | ||
| 1220 | } | ||
| 1221 | err = snd_card_create(index[card_index], id[card_index], THIS_MODULE, | ||
| 1222 | sizeof(*ua), &card); | ||
| 1223 | if (err < 0) { | ||
| 1224 | mutex_unlock(&devices_mutex); | ||
| 1225 | return err; | ||
| 1226 | } | ||
| 1227 | card->private_free = ua101_card_free; | ||
| 1228 | ua = card->private_data; | ||
| 1229 | ua->dev = interface_to_usbdev(interface); | ||
| 1230 | ua->card = card; | ||
| 1231 | ua->card_index = card_index; | ||
| 1232 | INIT_LIST_HEAD(&ua->midi_list); | ||
| 1233 | spin_lock_init(&ua->lock); | ||
| 1234 | mutex_init(&ua->mutex); | ||
| 1235 | INIT_LIST_HEAD(&ua->ready_playback_urbs); | ||
| 1236 | tasklet_init(&ua->playback_tasklet, | ||
| 1237 | playback_tasklet, (unsigned long)ua); | ||
| 1238 | init_waitqueue_head(&ua->alsa_capture_wait); | ||
| 1239 | init_waitqueue_head(&ua->rate_feedback_wait); | ||
| 1240 | init_waitqueue_head(&ua->alsa_playback_wait); | ||
| 1241 | |||
| 1242 | #ifdef UA1A_HACK | ||
| 1243 | if (ua->dev->descriptor.idProduct == cpu_to_le16(0x0018)) { | ||
| 1244 | ua->intf[2] = interface; | ||
| 1245 | ua->intf[0] = usb_ifnum_to_if(ua->dev, 1); | ||
| 1246 | ua->intf[1] = usb_ifnum_to_if(ua->dev, 2); | ||
| 1247 | usb_driver_claim_interface(&ua101_driver, ua->intf[0], ua); | ||
| 1248 | usb_driver_claim_interface(&ua101_driver, ua->intf[1], ua); | ||
| 1249 | } else { | ||
| 1250 | #endif | ||
| 1251 | ua->intf[0] = interface; | ||
| 1252 | for (i = 1; i < ARRAY_SIZE(ua->intf); ++i) { | ||
| 1253 | ua->intf[i] = usb_ifnum_to_if(ua->dev, i); | ||
| 1254 | if (!ua->intf[i]) { | ||
| 1255 | dev_err(&ua->dev->dev, "interface %u not found\n", i); | ||
| 1256 | err = -ENXIO; | ||
| 1257 | goto probe_error; | ||
| 1258 | } | ||
| 1259 | err = usb_driver_claim_interface(&ua101_driver, | ||
| 1260 | ua->intf[i], ua); | ||
| 1261 | if (err < 0) { | ||
| 1262 | ua->intf[i] = NULL; | ||
| 1263 | err = -EBUSY; | ||
| 1264 | goto probe_error; | ||
| 1265 | } | ||
| 1266 | } | ||
| 1267 | #ifdef UA1A_HACK | ||
| 1268 | } | ||
| 1269 | #endif | ||
| 1270 | |||
| 1271 | snd_card_set_dev(card, &interface->dev); | ||
| 1272 | |||
| 1273 | #ifdef UA1A_HACK | ||
| 1274 | if (ua->dev->descriptor.idProduct == cpu_to_le16(0x0018)) { | ||
| 1275 | ua->format_bit = SNDRV_PCM_FMTBIT_S16_LE; | ||
| 1276 | ua->rate = 44100; | ||
| 1277 | ua->packets_per_second = 1000; | ||
| 1278 | ua->capture.channels = 2; | ||
| 1279 | ua->playback.channels = 2; | ||
| 1280 | ua->capture.frame_bytes = 4; | ||
| 1281 | ua->playback.frame_bytes = 4; | ||
| 1282 | ua->capture.usb_pipe = usb_rcvisocpipe(ua->dev, 2); | ||
| 1283 | ua->playback.usb_pipe = usb_sndisocpipe(ua->dev, 1); | ||
| 1284 | ua->capture.max_packet_bytes = 192; | ||
| 1285 | ua->playback.max_packet_bytes = 192; | ||
| 1286 | } else { | ||
| 1287 | #endif | ||
| 1288 | err = detect_usb_format(ua); | ||
| 1289 | if (err < 0) | ||
| 1290 | goto probe_error; | ||
| 1291 | #ifdef UA1A_HACK | ||
| 1292 | } | ||
| 1293 | #endif | ||
| 1294 | |||
| 1295 | strcpy(card->driver, "UA-101"); | ||
| 1296 | strcpy(card->shortname, "UA-101"); | ||
| 1297 | usb_make_path(ua->dev, usb_path, sizeof(usb_path)); | ||
| 1298 | snprintf(ua->card->longname, sizeof(ua->card->longname), | ||
| 1299 | "EDIROL UA-101 (serial %s), %u Hz at %s, %s speed", | ||
| 1300 | ua->dev->serial ? ua->dev->serial : "?", ua->rate, usb_path, | ||
| 1301 | ua->dev->speed == USB_SPEED_HIGH ? "high" : "full"); | ||
| 1302 | |||
| 1303 | err = alloc_stream_buffers(ua, &ua->capture); | ||
| 1304 | if (err < 0) | ||
| 1305 | goto probe_error; | ||
| 1306 | err = alloc_stream_buffers(ua, &ua->playback); | ||
| 1307 | if (err < 0) | ||
| 1308 | goto probe_error; | ||
| 1309 | |||
| 1310 | err = alloc_stream_urbs(ua, &ua->capture, capture_urb_complete); | ||
| 1311 | if (err < 0) | ||
| 1312 | goto probe_error; | ||
| 1313 | err = alloc_stream_urbs(ua, &ua->playback, playback_urb_complete); | ||
| 1314 | if (err < 0) | ||
| 1315 | goto probe_error; | ||
| 1316 | |||
| 1317 | err = snd_pcm_new(card, "UA-101", 0, 1, 1, &ua->pcm); | ||
| 1318 | if (err < 0) | ||
| 1319 | goto probe_error; | ||
| 1320 | ua->pcm->private_data = ua; | ||
| 1321 | strcpy(ua->pcm->name, "UA-101"); | ||
| 1322 | snd_pcm_set_ops(ua->pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_pcm_ops); | ||
| 1323 | snd_pcm_set_ops(ua->pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_pcm_ops); | ||
| 1324 | |||
| 1325 | #ifdef UA1A_HACK | ||
| 1326 | if (ua->dev->descriptor.idProduct != cpu_to_le16(0x0018)) { | ||
| 1327 | #endif | ||
| 1328 | err = snd_usbmidi_create(card, ua->intf[INTF_MIDI], | ||
| 1329 | &ua->midi_list, &midi_quirk); | ||
| 1330 | if (err < 0) | ||
| 1331 | goto probe_error; | ||
| 1332 | #ifdef UA1A_HACK | ||
| 1333 | } | ||
| 1334 | #endif | ||
| 1335 | |||
| 1336 | err = snd_card_register(card); | ||
| 1337 | if (err < 0) | ||
| 1338 | goto probe_error; | ||
| 1339 | |||
| 1340 | usb_set_intfdata(interface, ua); | ||
| 1341 | devices_used |= 1 << card_index; | ||
| 1342 | |||
| 1343 | mutex_unlock(&devices_mutex); | ||
| 1344 | return 0; | ||
| 1345 | |||
| 1346 | probe_error: | ||
| 1347 | free_usb_related_resources(ua, interface); | ||
| 1348 | snd_card_free(card); | ||
| 1349 | mutex_unlock(&devices_mutex); | ||
| 1350 | return err; | ||
| 1351 | } | ||
| 1352 | |||
| 1353 | static void ua101_disconnect(struct usb_interface *interface) | ||
| 1354 | { | ||
| 1355 | struct ua101 *ua = usb_get_intfdata(interface); | ||
| 1356 | struct list_head *midi; | ||
| 1357 | |||
| 1358 | if (!ua) | ||
| 1359 | return; | ||
| 1360 | |||
| 1361 | mutex_lock(&devices_mutex); | ||
| 1362 | |||
| 1363 | set_bit(DISCONNECTED, &ua->states); | ||
| 1364 | wake_up(&ua->rate_feedback_wait); | ||
| 1365 | |||
| 1366 | /* make sure that userspace cannot create new requests */ | ||
| 1367 | snd_card_disconnect(ua->card); | ||
| 1368 | |||
| 1369 | /* make sure that there are no pending USB requests */ | ||
| 1370 | __list_for_each(midi, &ua->midi_list) | ||
| 1371 | snd_usbmidi_disconnect(midi); | ||
| 1372 | abort_alsa_playback(ua); | ||
| 1373 | abort_alsa_capture(ua); | ||
| 1374 | mutex_lock(&ua->mutex); | ||
| 1375 | stop_usb_playback(ua); | ||
| 1376 | stop_usb_capture(ua); | ||
| 1377 | mutex_unlock(&ua->mutex); | ||
| 1378 | |||
| 1379 | free_usb_related_resources(ua, interface); | ||
| 1380 | |||
| 1381 | devices_used &= ~(1 << ua->card_index); | ||
| 1382 | |||
| 1383 | snd_card_free_when_closed(ua->card); | ||
| 1384 | |||
| 1385 | mutex_unlock(&devices_mutex); | ||
| 1386 | } | ||
| 1387 | |||
| 1388 | static struct usb_device_id ua101_ids[] = { | ||
| 1389 | #ifdef UA1A_HACK | ||
| 1390 | { USB_DEVICE(0x0582, 0x0018) }, | ||
| 1391 | #endif | ||
| 1392 | { USB_DEVICE(0x0582, 0x007d) }, | ||
| 1393 | { USB_DEVICE(0x0582, 0x008d) }, | ||
| 1394 | { } | ||
| 1395 | }; | ||
| 1396 | MODULE_DEVICE_TABLE(usb, ua101_ids); | ||
| 1397 | |||
| 1398 | static struct usb_driver ua101_driver = { | ||
| 1399 | .name = "snd-ua101", | ||
| 1400 | .id_table = ua101_ids, | ||
| 1401 | .probe = ua101_probe, | ||
| 1402 | .disconnect = ua101_disconnect, | ||
| 1403 | #if 0 | ||
| 1404 | .suspend = ua101_suspend, | ||
| 1405 | .resume = ua101_resume, | ||
| 1406 | #endif | ||
| 1407 | }; | ||
| 1408 | |||
| 1409 | static int __init alsa_card_ua101_init(void) | ||
| 1410 | { | ||
| 1411 | return usb_register(&ua101_driver); | ||
| 1412 | } | ||
| 1413 | |||
| 1414 | static void __exit alsa_card_ua101_exit(void) | ||
| 1415 | { | ||
| 1416 | usb_deregister(&ua101_driver); | ||
| 1417 | mutex_destroy(&devices_mutex); | ||
| 1418 | } | ||
| 1419 | |||
| 1420 | module_init(alsa_card_ua101_init); | ||
| 1421 | module_exit(alsa_card_ua101_exit); | ||
diff --git a/sound/usb/usbaudio.c b/sound/usb/usbaudio.c index 9edef4684978..c539f7fe292f 100644 --- a/sound/usb/usbaudio.c +++ b/sound/usb/usbaudio.c | |||
| @@ -44,9 +44,11 @@ | |||
| 44 | #include <linux/slab.h> | 44 | #include <linux/slab.h> |
| 45 | #include <linux/string.h> | 45 | #include <linux/string.h> |
| 46 | #include <linux/usb.h> | 46 | #include <linux/usb.h> |
| 47 | #include <linux/vmalloc.h> | ||
| 48 | #include <linux/moduleparam.h> | 47 | #include <linux/moduleparam.h> |
| 49 | #include <linux/mutex.h> | 48 | #include <linux/mutex.h> |
| 49 | #include <linux/usb/audio.h> | ||
| 50 | #include <linux/usb/ch9.h> | ||
| 51 | |||
| 50 | #include <sound/core.h> | 52 | #include <sound/core.h> |
| 51 | #include <sound/info.h> | 53 | #include <sound/info.h> |
| 52 | #include <sound/pcm.h> | 54 | #include <sound/pcm.h> |
| @@ -170,11 +172,12 @@ struct snd_usb_substream { | |||
| 170 | unsigned int curpacksize; /* current packet size in bytes (for capture) */ | 172 | unsigned int curpacksize; /* current packet size in bytes (for capture) */ |
| 171 | unsigned int curframesize; /* current packet size in frames (for capture) */ | 173 | unsigned int curframesize; /* current packet size in frames (for capture) */ |
| 172 | unsigned int fill_max: 1; /* fill max packet size always */ | 174 | unsigned int fill_max: 1; /* fill max packet size always */ |
| 175 | unsigned int txfr_quirk:1; /* allow sub-frame alignment */ | ||
| 173 | unsigned int fmt_type; /* USB audio format type (1-3) */ | 176 | unsigned int fmt_type; /* USB audio format type (1-3) */ |
| 174 | 177 | ||
| 175 | unsigned int running: 1; /* running status */ | 178 | unsigned int running: 1; /* running status */ |
| 176 | 179 | ||
| 177 | unsigned int hwptr_done; /* processed frame position in the buffer */ | 180 | unsigned int hwptr_done; /* processed byte position in the buffer */ |
| 178 | unsigned int transfer_done; /* processed frames since last period update */ | 181 | unsigned int transfer_done; /* processed frames since last period update */ |
| 179 | unsigned long active_mask; /* bitmask of active urbs */ | 182 | unsigned long active_mask; /* bitmask of active urbs */ |
| 180 | unsigned long unlink_mask; /* bitmask of unlinked urbs */ | 183 | unsigned long unlink_mask; /* bitmask of unlinked urbs */ |
| @@ -343,7 +346,7 @@ static int retire_capture_urb(struct snd_usb_substream *subs, | |||
| 343 | unsigned long flags; | 346 | unsigned long flags; |
| 344 | unsigned char *cp; | 347 | unsigned char *cp; |
| 345 | int i; | 348 | int i; |
| 346 | unsigned int stride, len, oldptr; | 349 | unsigned int stride, frames, bytes, oldptr; |
| 347 | int period_elapsed = 0; | 350 | int period_elapsed = 0; |
| 348 | 351 | ||
| 349 | stride = runtime->frame_bits >> 3; | 352 | stride = runtime->frame_bits >> 3; |
| @@ -354,29 +357,39 @@ static int retire_capture_urb(struct snd_usb_substream *subs, | |||
| 354 | snd_printd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status); | 357 | snd_printd(KERN_ERR "frame %d active: %d\n", i, urb->iso_frame_desc[i].status); |
| 355 | // continue; | 358 | // continue; |
| 356 | } | 359 | } |
| 357 | len = urb->iso_frame_desc[i].actual_length / stride; | 360 | bytes = urb->iso_frame_desc[i].actual_length; |
| 358 | if (! len) | 361 | frames = bytes / stride; |
| 359 | continue; | 362 | if (!subs->txfr_quirk) |
| 363 | bytes = frames * stride; | ||
| 364 | if (bytes % (runtime->sample_bits >> 3) != 0) { | ||
| 365 | #ifdef CONFIG_SND_DEBUG_VERBOSE | ||
| 366 | int oldbytes = bytes; | ||
| 367 | #endif | ||
| 368 | bytes = frames * stride; | ||
| 369 | snd_printdd(KERN_ERR "Corrected urb data len. %d->%d\n", | ||
| 370 | oldbytes, bytes); | ||
| 371 | } | ||
| 360 | /* update the current pointer */ | 372 | /* update the current pointer */ |
| 361 | spin_lock_irqsave(&subs->lock, flags); | 373 | spin_lock_irqsave(&subs->lock, flags); |
| 362 | oldptr = subs->hwptr_done; | 374 | oldptr = subs->hwptr_done; |
| 363 | subs->hwptr_done += len; | 375 | subs->hwptr_done += bytes; |
| 364 | if (subs->hwptr_done >= runtime->buffer_size) | 376 | if (subs->hwptr_done >= runtime->buffer_size * stride) |
| 365 | subs->hwptr_done -= runtime->buffer_size; | 377 | subs->hwptr_done -= runtime->buffer_size * stride; |
| 366 | subs->transfer_done += len; | 378 | frames = (bytes + (oldptr % stride)) / stride; |
| 379 | subs->transfer_done += frames; | ||
| 367 | if (subs->transfer_done >= runtime->period_size) { | 380 | if (subs->transfer_done >= runtime->period_size) { |
| 368 | subs->transfer_done -= runtime->period_size; | 381 | subs->transfer_done -= runtime->period_size; |
| 369 | period_elapsed = 1; | 382 | period_elapsed = 1; |
| 370 | } | 383 | } |
| 371 | spin_unlock_irqrestore(&subs->lock, flags); | 384 | spin_unlock_irqrestore(&subs->lock, flags); |
| 372 | /* copy a data chunk */ | 385 | /* copy a data chunk */ |
| 373 | if (oldptr + len > runtime->buffer_size) { | 386 | if (oldptr + bytes > runtime->buffer_size * stride) { |
| 374 | unsigned int cnt = runtime->buffer_size - oldptr; | 387 | unsigned int bytes1 = |
| 375 | unsigned int blen = cnt * stride; | 388 | runtime->buffer_size * stride - oldptr; |
| 376 | memcpy(runtime->dma_area + oldptr * stride, cp, blen); | 389 | memcpy(runtime->dma_area + oldptr, cp, bytes1); |
| 377 | memcpy(runtime->dma_area, cp + blen, len * stride - blen); | 390 | memcpy(runtime->dma_area, cp + bytes1, bytes - bytes1); |
| 378 | } else { | 391 | } else { |
| 379 | memcpy(runtime->dma_area + oldptr * stride, cp, len * stride); | 392 | memcpy(runtime->dma_area + oldptr, cp, bytes); |
| 380 | } | 393 | } |
| 381 | } | 394 | } |
| 382 | if (period_elapsed) | 395 | if (period_elapsed) |
| @@ -563,34 +576,34 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, | |||
| 563 | struct snd_pcm_runtime *runtime, | 576 | struct snd_pcm_runtime *runtime, |
| 564 | struct urb *urb) | 577 | struct urb *urb) |
| 565 | { | 578 | { |
| 566 | int i, stride, offs; | 579 | int i, stride; |
| 567 | unsigned int counts; | 580 | unsigned int counts, frames, bytes; |
| 568 | unsigned long flags; | 581 | unsigned long flags; |
| 569 | int period_elapsed = 0; | 582 | int period_elapsed = 0; |
| 570 | struct snd_urb_ctx *ctx = urb->context; | 583 | struct snd_urb_ctx *ctx = urb->context; |
| 571 | 584 | ||
| 572 | stride = runtime->frame_bits >> 3; | 585 | stride = runtime->frame_bits >> 3; |
| 573 | 586 | ||
| 574 | offs = 0; | 587 | frames = 0; |
| 575 | urb->dev = ctx->subs->dev; /* we need to set this at each time */ | 588 | urb->dev = ctx->subs->dev; /* we need to set this at each time */ |
| 576 | urb->number_of_packets = 0; | 589 | urb->number_of_packets = 0; |
| 577 | spin_lock_irqsave(&subs->lock, flags); | 590 | spin_lock_irqsave(&subs->lock, flags); |
| 578 | for (i = 0; i < ctx->packets; i++) { | 591 | for (i = 0; i < ctx->packets; i++) { |
| 579 | counts = snd_usb_audio_next_packet_size(subs); | 592 | counts = snd_usb_audio_next_packet_size(subs); |
| 580 | /* set up descriptor */ | 593 | /* set up descriptor */ |
| 581 | urb->iso_frame_desc[i].offset = offs * stride; | 594 | urb->iso_frame_desc[i].offset = frames * stride; |
| 582 | urb->iso_frame_desc[i].length = counts * stride; | 595 | urb->iso_frame_desc[i].length = counts * stride; |
| 583 | offs += counts; | 596 | frames += counts; |
| 584 | urb->number_of_packets++; | 597 | urb->number_of_packets++; |
| 585 | subs->transfer_done += counts; | 598 | subs->transfer_done += counts; |
| 586 | if (subs->transfer_done >= runtime->period_size) { | 599 | if (subs->transfer_done >= runtime->period_size) { |
| 587 | subs->transfer_done -= runtime->period_size; | 600 | subs->transfer_done -= runtime->period_size; |
| 588 | period_elapsed = 1; | 601 | period_elapsed = 1; |
| 589 | if (subs->fmt_type == USB_FORMAT_TYPE_II) { | 602 | if (subs->fmt_type == UAC_FORMAT_TYPE_II) { |
| 590 | if (subs->transfer_done > 0) { | 603 | if (subs->transfer_done > 0) { |
| 591 | /* FIXME: fill-max mode is not | 604 | /* FIXME: fill-max mode is not |
| 592 | * supported yet */ | 605 | * supported yet */ |
| 593 | offs -= subs->transfer_done; | 606 | frames -= subs->transfer_done; |
| 594 | counts -= subs->transfer_done; | 607 | counts -= subs->transfer_done; |
| 595 | urb->iso_frame_desc[i].length = | 608 | urb->iso_frame_desc[i].length = |
| 596 | counts * stride; | 609 | counts * stride; |
| @@ -600,7 +613,7 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, | |||
| 600 | if (i < ctx->packets) { | 613 | if (i < ctx->packets) { |
| 601 | /* add a transfer delimiter */ | 614 | /* add a transfer delimiter */ |
| 602 | urb->iso_frame_desc[i].offset = | 615 | urb->iso_frame_desc[i].offset = |
| 603 | offs * stride; | 616 | frames * stride; |
| 604 | urb->iso_frame_desc[i].length = 0; | 617 | urb->iso_frame_desc[i].length = 0; |
| 605 | urb->number_of_packets++; | 618 | urb->number_of_packets++; |
| 606 | } | 619 | } |
| @@ -610,26 +623,25 @@ static int prepare_playback_urb(struct snd_usb_substream *subs, | |||
| 610 | if (period_elapsed) /* finish at the period boundary */ | 623 | if (period_elapsed) /* finish at the period boundary */ |
| 611 | break; | 624 | break; |
| 612 | } | 625 | } |
| 613 | if (subs->hwptr_done + offs > runtime->buffer_size) { | 626 | bytes = frames * stride; |
| 627 | if (subs->hwptr_done + bytes > runtime->buffer_size * stride) { | ||
| 614 | /* err, the transferred area goes over buffer boundary. */ | 628 | /* err, the transferred area goes over buffer boundary. */ |
| 615 | unsigned int len = runtime->buffer_size - subs->hwptr_done; | 629 | unsigned int bytes1 = |
| 630 | runtime->buffer_size * stride - subs->hwptr_done; | ||
| 616 | memcpy(urb->transfer_buffer, | 631 | memcpy(urb->transfer_buffer, |
| 617 | runtime->dma_area + subs->hwptr_done * stride, | 632 | runtime->dma_area + subs->hwptr_done, bytes1); |
| 618 | len * stride); | 633 | memcpy(urb->transfer_buffer + bytes1, |
| 619 | memcpy(urb->transfer_buffer + len * stride, | 634 | runtime->dma_area, bytes - bytes1); |
| 620 | runtime->dma_area, | ||
| 621 | (offs - len) * stride); | ||
| 622 | } else { | 635 | } else { |
| 623 | memcpy(urb->transfer_buffer, | 636 | memcpy(urb->transfer_buffer, |
| 624 | runtime->dma_area + subs->hwptr_done * stride, | 637 | runtime->dma_area + subs->hwptr_done, bytes); |
| 625 | offs * stride); | ||
| 626 | } | 638 | } |
| 627 | subs->hwptr_done += offs; | 639 | subs->hwptr_done += bytes; |
| 628 | if (subs->hwptr_done >= runtime->buffer_size) | 640 | if (subs->hwptr_done >= runtime->buffer_size * stride) |
| 629 | subs->hwptr_done -= runtime->buffer_size; | 641 | subs->hwptr_done -= runtime->buffer_size * stride; |
| 630 | runtime->delay += offs; | 642 | runtime->delay += frames; |
| 631 | spin_unlock_irqrestore(&subs->lock, flags); | 643 | spin_unlock_irqrestore(&subs->lock, flags); |
| 632 | urb->transfer_buffer_length = offs * stride; | 644 | urb->transfer_buffer_length = bytes; |
| 633 | if (period_elapsed) | 645 | if (period_elapsed) |
| 634 | snd_pcm_period_elapsed(subs->pcm_substream); | 646 | snd_pcm_period_elapsed(subs->pcm_substream); |
| 635 | return 0; | 647 | return 0; |
| @@ -735,41 +747,6 @@ static void snd_complete_sync_urb(struct urb *urb) | |||
| 735 | } | 747 | } |
| 736 | 748 | ||
| 737 | 749 | ||
| 738 | /* get the physical page pointer at the given offset */ | ||
| 739 | static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs, | ||
| 740 | unsigned long offset) | ||
| 741 | { | ||
| 742 | void *pageptr = subs->runtime->dma_area + offset; | ||
| 743 | return vmalloc_to_page(pageptr); | ||
| 744 | } | ||
| 745 | |||
| 746 | /* allocate virtual buffer; may be called more than once */ | ||
| 747 | static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs, size_t size) | ||
| 748 | { | ||
| 749 | struct snd_pcm_runtime *runtime = subs->runtime; | ||
| 750 | if (runtime->dma_area) { | ||
| 751 | if (runtime->dma_bytes >= size) | ||
| 752 | return 0; /* already large enough */ | ||
| 753 | vfree(runtime->dma_area); | ||
| 754 | } | ||
| 755 | runtime->dma_area = vmalloc_user(size); | ||
| 756 | if (!runtime->dma_area) | ||
| 757 | return -ENOMEM; | ||
| 758 | runtime->dma_bytes = size; | ||
| 759 | return 0; | ||
| 760 | } | ||
| 761 | |||
| 762 | /* free virtual buffer; may be called more than once */ | ||
| 763 | static int snd_pcm_free_vmalloc_buffer(struct snd_pcm_substream *subs) | ||
| 764 | { | ||
| 765 | struct snd_pcm_runtime *runtime = subs->runtime; | ||
| 766 | |||
| 767 | vfree(runtime->dma_area); | ||
| 768 | runtime->dma_area = NULL; | ||
| 769 | return 0; | ||
| 770 | } | ||
| 771 | |||
| 772 | |||
| 773 | /* | 750 | /* |
| 774 | * unlink active urbs. | 751 | * unlink active urbs. |
| 775 | */ | 752 | */ |
| @@ -937,18 +914,18 @@ static int wait_clear_urbs(struct snd_usb_substream *subs) | |||
| 937 | 914 | ||
| 938 | 915 | ||
| 939 | /* | 916 | /* |
| 940 | * return the current pcm pointer. just return the hwptr_done value. | 917 | * return the current pcm pointer. just based on the hwptr_done value. |
| 941 | */ | 918 | */ |
| 942 | static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream) | 919 | static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream) |
| 943 | { | 920 | { |
| 944 | struct snd_usb_substream *subs; | 921 | struct snd_usb_substream *subs; |
| 945 | snd_pcm_uframes_t hwptr_done; | 922 | unsigned int hwptr_done; |
| 946 | 923 | ||
| 947 | subs = (struct snd_usb_substream *)substream->runtime->private_data; | 924 | subs = (struct snd_usb_substream *)substream->runtime->private_data; |
| 948 | spin_lock(&subs->lock); | 925 | spin_lock(&subs->lock); |
| 949 | hwptr_done = subs->hwptr_done; | 926 | hwptr_done = subs->hwptr_done; |
| 950 | spin_unlock(&subs->lock); | 927 | spin_unlock(&subs->lock); |
| 951 | return hwptr_done; | 928 | return hwptr_done / (substream->runtime->frame_bits >> 3); |
| 952 | } | 929 | } |
| 953 | 930 | ||
| 954 | 931 | ||
| @@ -1130,7 +1107,7 @@ static int init_substream_urbs(struct snd_usb_substream *subs, unsigned int peri | |||
| 1130 | u->packets = (i + 1) * total_packs / subs->nurbs | 1107 | u->packets = (i + 1) * total_packs / subs->nurbs |
| 1131 | - i * total_packs / subs->nurbs; | 1108 | - i * total_packs / subs->nurbs; |
| 1132 | u->buffer_size = maxsize * u->packets; | 1109 | u->buffer_size = maxsize * u->packets; |
| 1133 | if (subs->fmt_type == USB_FORMAT_TYPE_II) | 1110 | if (subs->fmt_type == UAC_FORMAT_TYPE_II) |
| 1134 | u->packets++; /* for transfer delimiter */ | 1111 | u->packets++; /* for transfer delimiter */ |
| 1135 | u->urb = usb_alloc_urb(u->packets, GFP_KERNEL); | 1112 | u->urb = usb_alloc_urb(u->packets, GFP_KERNEL); |
| 1136 | if (!u->urb) | 1113 | if (!u->urb) |
| @@ -1206,7 +1183,7 @@ static struct audioformat *find_format(struct snd_usb_substream *subs, unsigned | |||
| 1206 | if (i >= fp->nr_rates) | 1183 | if (i >= fp->nr_rates) |
| 1207 | continue; | 1184 | continue; |
| 1208 | } | 1185 | } |
| 1209 | attr = fp->ep_attr & EP_ATTR_MASK; | 1186 | attr = fp->ep_attr & USB_ENDPOINT_SYNCTYPE; |
| 1210 | if (! found) { | 1187 | if (! found) { |
| 1211 | found = fp; | 1188 | found = fp; |
| 1212 | cur_attr = attr; | 1189 | cur_attr = attr; |
| @@ -1218,14 +1195,14 @@ static struct audioformat *find_format(struct snd_usb_substream *subs, unsigned | |||
| 1218 | * M-audio audiophile USB. | 1195 | * M-audio audiophile USB. |
| 1219 | */ | 1196 | */ |
| 1220 | if (attr != cur_attr) { | 1197 | if (attr != cur_attr) { |
| 1221 | if ((attr == EP_ATTR_ASYNC && | 1198 | if ((attr == USB_ENDPOINT_SYNC_ASYNC && |
| 1222 | subs->direction == SNDRV_PCM_STREAM_PLAYBACK) || | 1199 | subs->direction == SNDRV_PCM_STREAM_PLAYBACK) || |
| 1223 | (attr == EP_ATTR_ADAPTIVE && | 1200 | (attr == USB_ENDPOINT_SYNC_ADAPTIVE && |
| 1224 | subs->direction == SNDRV_PCM_STREAM_CAPTURE)) | 1201 | subs->direction == SNDRV_PCM_STREAM_CAPTURE)) |
| 1225 | continue; | 1202 | continue; |
| 1226 | if ((cur_attr == EP_ATTR_ASYNC && | 1203 | if ((cur_attr == USB_ENDPOINT_SYNC_ASYNC && |
| 1227 | subs->direction == SNDRV_PCM_STREAM_PLAYBACK) || | 1204 | subs->direction == SNDRV_PCM_STREAM_PLAYBACK) || |
| 1228 | (cur_attr == EP_ATTR_ADAPTIVE && | 1205 | (cur_attr == USB_ENDPOINT_SYNC_ADAPTIVE && |
| 1229 | subs->direction == SNDRV_PCM_STREAM_CAPTURE)) { | 1206 | subs->direction == SNDRV_PCM_STREAM_CAPTURE)) { |
| 1230 | found = fp; | 1207 | found = fp; |
| 1231 | cur_attr = attr; | 1208 | cur_attr = attr; |
| @@ -1255,11 +1232,11 @@ static int init_usb_pitch(struct usb_device *dev, int iface, | |||
| 1255 | 1232 | ||
| 1256 | ep = get_endpoint(alts, 0)->bEndpointAddress; | 1233 | ep = get_endpoint(alts, 0)->bEndpointAddress; |
| 1257 | /* if endpoint has pitch control, enable it */ | 1234 | /* if endpoint has pitch control, enable it */ |
| 1258 | if (fmt->attributes & EP_CS_ATTR_PITCH_CONTROL) { | 1235 | if (fmt->attributes & UAC_EP_CS_ATTR_PITCH_CONTROL) { |
| 1259 | data[0] = 1; | 1236 | data[0] = 1; |
| 1260 | if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, | 1237 | if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, |
| 1261 | USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, | 1238 | USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, |
| 1262 | PITCH_CONTROL << 8, ep, data, 1, 1000)) < 0) { | 1239 | UAC_EP_CS_ATTR_PITCH_CONTROL << 8, ep, data, 1, 1000)) < 0) { |
| 1263 | snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH\n", | 1240 | snd_printk(KERN_ERR "%d:%d:%d: cannot set enable PITCH\n", |
| 1264 | dev->devnum, iface, ep); | 1241 | dev->devnum, iface, ep); |
| 1265 | return err; | 1242 | return err; |
| @@ -1278,21 +1255,21 @@ static int init_usb_sample_rate(struct usb_device *dev, int iface, | |||
| 1278 | 1255 | ||
| 1279 | ep = get_endpoint(alts, 0)->bEndpointAddress; | 1256 | ep = get_endpoint(alts, 0)->bEndpointAddress; |
| 1280 | /* if endpoint has sampling rate control, set it */ | 1257 | /* if endpoint has sampling rate control, set it */ |
| 1281 | if (fmt->attributes & EP_CS_ATTR_SAMPLE_RATE) { | 1258 | if (fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE) { |
| 1282 | int crate; | 1259 | int crate; |
| 1283 | data[0] = rate; | 1260 | data[0] = rate; |
| 1284 | data[1] = rate >> 8; | 1261 | data[1] = rate >> 8; |
| 1285 | data[2] = rate >> 16; | 1262 | data[2] = rate >> 16; |
| 1286 | if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, | 1263 | if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, |
| 1287 | USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, | 1264 | USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, |
| 1288 | SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) { | 1265 | UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, data, 3, 1000)) < 0) { |
| 1289 | snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n", | 1266 | snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n", |
| 1290 | dev->devnum, iface, fmt->altsetting, rate, ep); | 1267 | dev->devnum, iface, fmt->altsetting, rate, ep); |
| 1291 | return err; | 1268 | return err; |
| 1292 | } | 1269 | } |
| 1293 | if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), GET_CUR, | 1270 | if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, |
| 1294 | USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN, | 1271 | USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN, |
| 1295 | SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000)) < 0) { | 1272 | UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, data, 3, 1000)) < 0) { |
| 1296 | snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n", | 1273 | snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n", |
| 1297 | dev->devnum, iface, fmt->altsetting, ep); | 1274 | dev->devnum, iface, fmt->altsetting, ep); |
| 1298 | return 0; /* some devices don't support reading */ | 1275 | return 0; /* some devices don't support reading */ |
| @@ -1307,6 +1284,47 @@ static int init_usb_sample_rate(struct usb_device *dev, int iface, | |||
| 1307 | } | 1284 | } |
| 1308 | 1285 | ||
| 1309 | /* | 1286 | /* |
| 1287 | * For E-Mu 0404USB/0202USB/TrackerPre sample rate should be set for device, | ||
| 1288 | * not for interface. | ||
| 1289 | */ | ||
| 1290 | static void set_format_emu_quirk(struct snd_usb_substream *subs, | ||
| 1291 | struct audioformat *fmt) | ||
| 1292 | { | ||
| 1293 | unsigned char emu_samplerate_id = 0; | ||
| 1294 | |||
| 1295 | /* When capture is active | ||
| 1296 | * sample rate shouldn't be changed | ||
| 1297 | * by playback substream | ||
| 1298 | */ | ||
| 1299 | if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK) { | ||
| 1300 | if (subs->stream->substream[SNDRV_PCM_STREAM_CAPTURE].interface != -1) | ||
| 1301 | return; | ||
| 1302 | } | ||
| 1303 | |||
| 1304 | switch (fmt->rate_min) { | ||
| 1305 | case 48000: | ||
| 1306 | emu_samplerate_id = EMU_QUIRK_SR_48000HZ; | ||
| 1307 | break; | ||
| 1308 | case 88200: | ||
| 1309 | emu_samplerate_id = EMU_QUIRK_SR_88200HZ; | ||
| 1310 | break; | ||
| 1311 | case 96000: | ||
| 1312 | emu_samplerate_id = EMU_QUIRK_SR_96000HZ; | ||
| 1313 | break; | ||
| 1314 | case 176400: | ||
| 1315 | emu_samplerate_id = EMU_QUIRK_SR_176400HZ; | ||
| 1316 | break; | ||
| 1317 | case 192000: | ||
| 1318 | emu_samplerate_id = EMU_QUIRK_SR_192000HZ; | ||
| 1319 | break; | ||
| 1320 | default: | ||
| 1321 | emu_samplerate_id = EMU_QUIRK_SR_44100HZ; | ||
| 1322 | break; | ||
| 1323 | } | ||
| 1324 | snd_emuusb_set_samplerate(subs->stream->chip, emu_samplerate_id); | ||
| 1325 | } | ||
| 1326 | |||
| 1327 | /* | ||
| 1310 | * find a matching format and set up the interface | 1328 | * find a matching format and set up the interface |
| 1311 | */ | 1329 | */ |
| 1312 | static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) | 1330 | static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) |
| @@ -1369,9 +1387,9 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) | |||
| 1369 | * descriptors which fool us. if it has only one EP, | 1387 | * descriptors which fool us. if it has only one EP, |
| 1370 | * assume it as adaptive-out or sync-in. | 1388 | * assume it as adaptive-out or sync-in. |
| 1371 | */ | 1389 | */ |
| 1372 | attr = fmt->ep_attr & EP_ATTR_MASK; | 1390 | attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE; |
| 1373 | if (((is_playback && attr == EP_ATTR_ASYNC) || | 1391 | if (((is_playback && attr == USB_ENDPOINT_SYNC_ASYNC) || |
| 1374 | (! is_playback && attr == EP_ATTR_ADAPTIVE)) && | 1392 | (! is_playback && attr == USB_ENDPOINT_SYNC_ADAPTIVE)) && |
| 1375 | altsd->bNumEndpoints >= 2) { | 1393 | altsd->bNumEndpoints >= 2) { |
| 1376 | /* check sync-pipe endpoint */ | 1394 | /* check sync-pipe endpoint */ |
| 1377 | /* ... and check descriptor size before accessing bSynchAddress | 1395 | /* ... and check descriptor size before accessing bSynchAddress |
| @@ -1411,7 +1429,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) | |||
| 1411 | } | 1429 | } |
| 1412 | 1430 | ||
| 1413 | /* always fill max packet size */ | 1431 | /* always fill max packet size */ |
| 1414 | if (fmt->attributes & EP_CS_ATTR_FILL_MAX) | 1432 | if (fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX) |
| 1415 | subs->fill_max = 1; | 1433 | subs->fill_max = 1; |
| 1416 | 1434 | ||
| 1417 | if ((err = init_usb_pitch(dev, subs->interface, alts, fmt)) < 0) | 1435 | if ((err = init_usb_pitch(dev, subs->interface, alts, fmt)) < 0) |
| @@ -1419,6 +1437,14 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) | |||
| 1419 | 1437 | ||
| 1420 | subs->cur_audiofmt = fmt; | 1438 | subs->cur_audiofmt = fmt; |
| 1421 | 1439 | ||
| 1440 | switch (subs->stream->chip->usb_id) { | ||
| 1441 | case USB_ID(0x041e, 0x3f02): /* E-Mu 0202 USB */ | ||
| 1442 | case USB_ID(0x041e, 0x3f04): /* E-Mu 0404 USB */ | ||
| 1443 | case USB_ID(0x041e, 0x3f0a): /* E-Mu Tracker Pre */ | ||
| 1444 | set_format_emu_quirk(subs, fmt); | ||
| 1445 | break; | ||
| 1446 | } | ||
| 1447 | |||
| 1422 | #if 0 | 1448 | #if 0 |
| 1423 | printk(KERN_DEBUG | 1449 | printk(KERN_DEBUG |
| 1424 | "setting done: format = %d, rate = %d..%d, channels = %d\n", | 1450 | "setting done: format = %d, rate = %d..%d, channels = %d\n", |
| @@ -1449,8 +1475,8 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, | |||
| 1449 | unsigned int channels, rate, format; | 1475 | unsigned int channels, rate, format; |
| 1450 | int ret, changed; | 1476 | int ret, changed; |
| 1451 | 1477 | ||
| 1452 | ret = snd_pcm_alloc_vmalloc_buffer(substream, | 1478 | ret = snd_pcm_lib_alloc_vmalloc_buffer(substream, |
| 1453 | params_buffer_bytes(hw_params)); | 1479 | params_buffer_bytes(hw_params)); |
| 1454 | if (ret < 0) | 1480 | if (ret < 0) |
| 1455 | return ret; | 1481 | return ret; |
| 1456 | 1482 | ||
| @@ -1507,7 +1533,7 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) | |||
| 1507 | subs->period_bytes = 0; | 1533 | subs->period_bytes = 0; |
| 1508 | if (!subs->stream->chip->shutdown) | 1534 | if (!subs->stream->chip->shutdown) |
| 1509 | release_substream_urbs(subs, 0); | 1535 | release_substream_urbs(subs, 0); |
| 1510 | return snd_pcm_free_vmalloc_buffer(substream); | 1536 | return snd_pcm_lib_free_vmalloc_buffer(substream); |
| 1511 | } | 1537 | } |
| 1512 | 1538 | ||
| 1513 | /* | 1539 | /* |
| @@ -1861,7 +1887,7 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre | |||
| 1861 | runtime->hw.channels_min = fp->channels; | 1887 | runtime->hw.channels_min = fp->channels; |
| 1862 | if (runtime->hw.channels_max < fp->channels) | 1888 | if (runtime->hw.channels_max < fp->channels) |
| 1863 | runtime->hw.channels_max = fp->channels; | 1889 | runtime->hw.channels_max = fp->channels; |
| 1864 | if (fp->fmt_type == USB_FORMAT_TYPE_II && fp->frame_size > 0) { | 1890 | if (fp->fmt_type == UAC_FORMAT_TYPE_II && fp->frame_size > 0) { |
| 1865 | /* FIXME: there might be more than one audio formats... */ | 1891 | /* FIXME: there might be more than one audio formats... */ |
| 1866 | runtime->hw.period_bytes_min = runtime->hw.period_bytes_max = | 1892 | runtime->hw.period_bytes_min = runtime->hw.period_bytes_max = |
| 1867 | fp->frame_size; | 1893 | fp->frame_size; |
| @@ -1973,7 +1999,8 @@ static struct snd_pcm_ops snd_usb_playback_ops = { | |||
| 1973 | .prepare = snd_usb_pcm_prepare, | 1999 | .prepare = snd_usb_pcm_prepare, |
| 1974 | .trigger = snd_usb_pcm_playback_trigger, | 2000 | .trigger = snd_usb_pcm_playback_trigger, |
| 1975 | .pointer = snd_usb_pcm_pointer, | 2001 | .pointer = snd_usb_pcm_pointer, |
| 1976 | .page = snd_pcm_get_vmalloc_page, | 2002 | .page = snd_pcm_lib_get_vmalloc_page, |
| 2003 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
| 1977 | }; | 2004 | }; |
| 1978 | 2005 | ||
| 1979 | static struct snd_pcm_ops snd_usb_capture_ops = { | 2006 | static struct snd_pcm_ops snd_usb_capture_ops = { |
| @@ -1985,7 +2012,8 @@ static struct snd_pcm_ops snd_usb_capture_ops = { | |||
| 1985 | .prepare = snd_usb_pcm_prepare, | 2012 | .prepare = snd_usb_pcm_prepare, |
| 1986 | .trigger = snd_usb_pcm_capture_trigger, | 2013 | .trigger = snd_usb_pcm_capture_trigger, |
| 1987 | .pointer = snd_usb_pcm_pointer, | 2014 | .pointer = snd_usb_pcm_pointer, |
| 1988 | .page = snd_pcm_get_vmalloc_page, | 2015 | .page = snd_pcm_lib_get_vmalloc_page, |
| 2016 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
| 1989 | }; | 2017 | }; |
| 1990 | 2018 | ||
| 1991 | 2019 | ||
| @@ -2093,7 +2121,7 @@ static struct usb_device_id usb_audio_ids [] = { | |||
| 2093 | #include "usbquirks.h" | 2121 | #include "usbquirks.h" |
| 2094 | { .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS), | 2122 | { .match_flags = (USB_DEVICE_ID_MATCH_INT_CLASS | USB_DEVICE_ID_MATCH_INT_SUBCLASS), |
| 2095 | .bInterfaceClass = USB_CLASS_AUDIO, | 2123 | .bInterfaceClass = USB_CLASS_AUDIO, |
| 2096 | .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL }, | 2124 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL }, |
| 2097 | { } /* Terminating entry */ | 2125 | { } /* Terminating entry */ |
| 2098 | }; | 2126 | }; |
| 2099 | 2127 | ||
| @@ -2132,7 +2160,7 @@ static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct s | |||
| 2132 | snd_iprintf(buffer, " Endpoint: %d %s (%s)\n", | 2160 | snd_iprintf(buffer, " Endpoint: %d %s (%s)\n", |
| 2133 | fp->endpoint & USB_ENDPOINT_NUMBER_MASK, | 2161 | fp->endpoint & USB_ENDPOINT_NUMBER_MASK, |
| 2134 | fp->endpoint & USB_DIR_IN ? "IN" : "OUT", | 2162 | fp->endpoint & USB_DIR_IN ? "IN" : "OUT", |
| 2135 | sync_types[(fp->ep_attr & EP_ATTR_MASK) >> 2]); | 2163 | sync_types[(fp->ep_attr & USB_ENDPOINT_SYNCTYPE) >> 2]); |
| 2136 | if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) { | 2164 | if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) { |
| 2137 | snd_iprintf(buffer, " Rates: %d - %d (continuous)\n", | 2165 | snd_iprintf(buffer, " Rates: %d - %d (continuous)\n", |
| 2138 | fp->rate_min, fp->rate_max); | 2166 | fp->rate_min, fp->rate_max); |
| @@ -2227,6 +2255,7 @@ static void init_substream(struct snd_usb_stream *as, int stream, struct audiofo | |||
| 2227 | subs->stream = as; | 2255 | subs->stream = as; |
| 2228 | subs->direction = stream; | 2256 | subs->direction = stream; |
| 2229 | subs->dev = as->chip->dev; | 2257 | subs->dev = as->chip->dev; |
| 2258 | subs->txfr_quirk = as->chip->txfr_quirk; | ||
| 2230 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) { | 2259 | if (snd_usb_get_speed(subs->dev) == USB_SPEED_FULL) { |
| 2231 | subs->ops = audio_urb_ops[stream]; | 2260 | subs->ops = audio_urb_ops[stream]; |
| 2232 | } else { | 2261 | } else { |
| @@ -2394,29 +2423,68 @@ static int is_big_endian_format(struct snd_usb_audio *chip, struct audioformat * | |||
| 2394 | * @format: the format tag (wFormatTag) | 2423 | * @format: the format tag (wFormatTag) |
| 2395 | * @fmt: the format type descriptor | 2424 | * @fmt: the format type descriptor |
| 2396 | */ | 2425 | */ |
| 2397 | static int parse_audio_format_i_type(struct snd_usb_audio *chip, struct audioformat *fp, | 2426 | static int parse_audio_format_i_type(struct snd_usb_audio *chip, |
| 2398 | int format, unsigned char *fmt) | 2427 | struct audioformat *fp, |
| 2428 | int format, void *_fmt, | ||
| 2429 | int protocol) | ||
| 2399 | { | 2430 | { |
| 2400 | int pcm_format; | 2431 | int pcm_format, i; |
| 2401 | int sample_width, sample_bytes; | 2432 | int sample_width, sample_bytes; |
| 2402 | 2433 | ||
| 2434 | switch (protocol) { | ||
| 2435 | case UAC_VERSION_1: { | ||
| 2436 | struct uac_format_type_i_discrete_descriptor *fmt = _fmt; | ||
| 2437 | sample_width = fmt->bBitResolution; | ||
| 2438 | sample_bytes = fmt->bSubframeSize; | ||
| 2439 | break; | ||
| 2440 | } | ||
| 2441 | |||
| 2442 | case UAC_VERSION_2: { | ||
| 2443 | struct uac_format_type_i_ext_descriptor *fmt = _fmt; | ||
| 2444 | sample_width = fmt->bBitResolution; | ||
| 2445 | sample_bytes = fmt->bSubslotSize; | ||
| 2446 | |||
| 2447 | /* | ||
| 2448 | * FIXME | ||
| 2449 | * USB audio class v2 devices specify a bitmap of possible | ||
| 2450 | * audio formats rather than one fix value. For now, we just | ||
| 2451 | * pick one of them and report that as the only possible | ||
| 2452 | * value for this setting. | ||
| 2453 | * The bit allocation map is in fact compatible to the | ||
| 2454 | * wFormatTag of the v1 AS streaming descriptors, which is why | ||
| 2455 | * we can simply map the matrix. | ||
| 2456 | */ | ||
| 2457 | |||
| 2458 | for (i = 0; i < 5; i++) | ||
| 2459 | if (format & (1UL << i)) { | ||
| 2460 | format = i + 1; | ||
| 2461 | break; | ||
| 2462 | } | ||
| 2463 | |||
| 2464 | break; | ||
| 2465 | } | ||
| 2466 | |||
| 2467 | default: | ||
| 2468 | return -EINVAL; | ||
| 2469 | } | ||
| 2470 | |||
| 2403 | /* FIXME: correct endianess and sign? */ | 2471 | /* FIXME: correct endianess and sign? */ |
| 2404 | pcm_format = -1; | 2472 | pcm_format = -1; |
| 2405 | sample_width = fmt[6]; | 2473 | |
| 2406 | sample_bytes = fmt[5]; | ||
| 2407 | switch (format) { | 2474 | switch (format) { |
| 2408 | case 0: /* some devices don't define this correctly... */ | 2475 | case UAC_FORMAT_TYPE_I_UNDEFINED: /* some devices don't define this correctly... */ |
| 2409 | snd_printdd(KERN_INFO "%d:%u:%d : format type 0 is detected, processed as PCM\n", | 2476 | snd_printdd(KERN_INFO "%d:%u:%d : format type 0 is detected, processed as PCM\n", |
| 2410 | chip->dev->devnum, fp->iface, fp->altsetting); | 2477 | chip->dev->devnum, fp->iface, fp->altsetting); |
| 2411 | /* fall-through */ | 2478 | /* fall-through */ |
| 2412 | case USB_AUDIO_FORMAT_PCM: | 2479 | case UAC_FORMAT_TYPE_I_PCM: |
| 2413 | if (sample_width > sample_bytes * 8) { | 2480 | if (sample_width > sample_bytes * 8) { |
| 2414 | snd_printk(KERN_INFO "%d:%u:%d : sample bitwidth %d in over sample bytes %d\n", | 2481 | snd_printk(KERN_INFO "%d:%u:%d : sample bitwidth %d in over sample bytes %d\n", |
| 2415 | chip->dev->devnum, fp->iface, fp->altsetting, | 2482 | chip->dev->devnum, fp->iface, fp->altsetting, |
| 2416 | sample_width, sample_bytes); | 2483 | sample_width, sample_bytes); |
| 2417 | } | 2484 | } |
| 2418 | /* check the format byte size */ | 2485 | /* check the format byte size */ |
| 2419 | switch (fmt[5]) { | 2486 | printk(" XXXXX SAMPLE BYTES %d\n", sample_bytes); |
| 2487 | switch (sample_bytes) { | ||
| 2420 | case 1: | 2488 | case 1: |
| 2421 | pcm_format = SNDRV_PCM_FORMAT_S8; | 2489 | pcm_format = SNDRV_PCM_FORMAT_S8; |
| 2422 | break; | 2490 | break; |
| @@ -2437,12 +2505,12 @@ static int parse_audio_format_i_type(struct snd_usb_audio *chip, struct audiofor | |||
| 2437 | break; | 2505 | break; |
| 2438 | default: | 2506 | default: |
| 2439 | snd_printk(KERN_INFO "%d:%u:%d : unsupported sample bitwidth %d in %d bytes\n", | 2507 | snd_printk(KERN_INFO "%d:%u:%d : unsupported sample bitwidth %d in %d bytes\n", |
| 2440 | chip->dev->devnum, fp->iface, | 2508 | chip->dev->devnum, fp->iface, fp->altsetting, |
| 2441 | fp->altsetting, sample_width, sample_bytes); | 2509 | sample_width, sample_bytes); |
| 2442 | break; | 2510 | break; |
| 2443 | } | 2511 | } |
| 2444 | break; | 2512 | break; |
| 2445 | case USB_AUDIO_FORMAT_PCM8: | 2513 | case UAC_FORMAT_TYPE_I_PCM8: |
| 2446 | pcm_format = SNDRV_PCM_FORMAT_U8; | 2514 | pcm_format = SNDRV_PCM_FORMAT_U8; |
| 2447 | 2515 | ||
| 2448 | /* Dallas DS4201 workaround: it advertises U8 format, but really | 2516 | /* Dallas DS4201 workaround: it advertises U8 format, but really |
| @@ -2450,13 +2518,13 @@ static int parse_audio_format_i_type(struct snd_usb_audio *chip, struct audiofor | |||
| 2450 | if (chip->usb_id == USB_ID(0x04fa, 0x4201)) | 2518 | if (chip->usb_id == USB_ID(0x04fa, 0x4201)) |
| 2451 | pcm_format = SNDRV_PCM_FORMAT_S8; | 2519 | pcm_format = SNDRV_PCM_FORMAT_S8; |
| 2452 | break; | 2520 | break; |
| 2453 | case USB_AUDIO_FORMAT_IEEE_FLOAT: | 2521 | case UAC_FORMAT_TYPE_I_IEEE_FLOAT: |
| 2454 | pcm_format = SNDRV_PCM_FORMAT_FLOAT_LE; | 2522 | pcm_format = SNDRV_PCM_FORMAT_FLOAT_LE; |
| 2455 | break; | 2523 | break; |
| 2456 | case USB_AUDIO_FORMAT_ALAW: | 2524 | case UAC_FORMAT_TYPE_I_ALAW: |
| 2457 | pcm_format = SNDRV_PCM_FORMAT_A_LAW; | 2525 | pcm_format = SNDRV_PCM_FORMAT_A_LAW; |
| 2458 | break; | 2526 | break; |
| 2459 | case USB_AUDIO_FORMAT_MU_LAW: | 2527 | case UAC_FORMAT_TYPE_I_MULAW: |
| 2460 | pcm_format = SNDRV_PCM_FORMAT_MU_LAW; | 2528 | pcm_format = SNDRV_PCM_FORMAT_MU_LAW; |
| 2461 | break; | 2529 | break; |
| 2462 | default: | 2530 | default: |
| @@ -2470,7 +2538,7 @@ static int parse_audio_format_i_type(struct snd_usb_audio *chip, struct audiofor | |||
| 2470 | 2538 | ||
| 2471 | /* | 2539 | /* |
| 2472 | * parse the format descriptor and stores the possible sample rates | 2540 | * parse the format descriptor and stores the possible sample rates |
| 2473 | * on the audioformat table. | 2541 | * on the audioformat table (audio class v1). |
| 2474 | * | 2542 | * |
| 2475 | * @dev: usb device | 2543 | * @dev: usb device |
| 2476 | * @fp: audioformat record | 2544 | * @fp: audioformat record |
| @@ -2478,13 +2546,13 @@ static int parse_audio_format_i_type(struct snd_usb_audio *chip, struct audiofor | |||
| 2478 | * @offset: the start offset of descriptor pointing the rate type | 2546 | * @offset: the start offset of descriptor pointing the rate type |
| 2479 | * (7 for type I and II, 8 for type II) | 2547 | * (7 for type I and II, 8 for type II) |
| 2480 | */ | 2548 | */ |
| 2481 | static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioformat *fp, | 2549 | static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audioformat *fp, |
| 2482 | unsigned char *fmt, int offset) | 2550 | unsigned char *fmt, int offset) |
| 2483 | { | 2551 | { |
| 2484 | int nr_rates = fmt[offset]; | 2552 | int nr_rates = fmt[offset]; |
| 2485 | 2553 | ||
| 2486 | if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) { | 2554 | if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) { |
| 2487 | snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n", | 2555 | snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n", |
| 2488 | chip->dev->devnum, fp->iface, fp->altsetting); | 2556 | chip->dev->devnum, fp->iface, fp->altsetting); |
| 2489 | return -1; | 2557 | return -1; |
| 2490 | } | 2558 | } |
| @@ -2535,14 +2603,87 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform | |||
| 2535 | } | 2603 | } |
| 2536 | 2604 | ||
| 2537 | /* | 2605 | /* |
| 2606 | * parse the format descriptor and stores the possible sample rates | ||
| 2607 | * on the audioformat table (audio class v2). | ||
| 2608 | */ | ||
| 2609 | static int parse_audio_format_rates_v2(struct snd_usb_audio *chip, | ||
| 2610 | struct audioformat *fp, | ||
| 2611 | struct usb_host_interface *iface) | ||
| 2612 | { | ||
| 2613 | struct usb_device *dev = chip->dev; | ||
| 2614 | unsigned char tmp[2], *data; | ||
| 2615 | int i, nr_rates, data_size, ret = 0; | ||
| 2616 | |||
| 2617 | /* get the number of sample rates first by only fetching 2 bytes */ | ||
| 2618 | ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE, | ||
| 2619 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | ||
| 2620 | 0x0100, chip->clock_id << 8, tmp, sizeof(tmp), 1000); | ||
| 2621 | |||
| 2622 | if (ret < 0) { | ||
| 2623 | snd_printk(KERN_ERR "unable to retrieve number of sample rates\n"); | ||
| 2624 | goto err; | ||
| 2625 | } | ||
| 2626 | |||
| 2627 | nr_rates = (tmp[1] << 8) | tmp[0]; | ||
| 2628 | data_size = 2 + 12 * nr_rates; | ||
| 2629 | data = kzalloc(data_size, GFP_KERNEL); | ||
| 2630 | if (!data) { | ||
| 2631 | ret = -ENOMEM; | ||
| 2632 | goto err; | ||
| 2633 | } | ||
| 2634 | |||
| 2635 | /* now get the full information */ | ||
| 2636 | ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE, | ||
| 2637 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | ||
| 2638 | 0x0100, chip->clock_id << 8, data, data_size, 1000); | ||
| 2639 | |||
| 2640 | if (ret < 0) { | ||
| 2641 | snd_printk(KERN_ERR "unable to retrieve sample rate range\n"); | ||
| 2642 | ret = -EINVAL; | ||
| 2643 | goto err_free; | ||
| 2644 | } | ||
| 2645 | |||
| 2646 | fp->rate_table = kmalloc(sizeof(int) * nr_rates, GFP_KERNEL); | ||
| 2647 | if (!fp->rate_table) { | ||
| 2648 | ret = -ENOMEM; | ||
| 2649 | goto err_free; | ||
| 2650 | } | ||
| 2651 | |||
| 2652 | fp->nr_rates = 0; | ||
| 2653 | fp->rate_min = fp->rate_max = 0; | ||
| 2654 | |||
| 2655 | for (i = 0; i < nr_rates; i++) { | ||
| 2656 | int rate = combine_quad(&data[2 + 12 * i]); | ||
| 2657 | |||
| 2658 | fp->rate_table[fp->nr_rates] = rate; | ||
| 2659 | if (!fp->rate_min || rate < fp->rate_min) | ||
| 2660 | fp->rate_min = rate; | ||
| 2661 | if (!fp->rate_max || rate > fp->rate_max) | ||
| 2662 | fp->rate_max = rate; | ||
| 2663 | fp->rates |= snd_pcm_rate_to_rate_bit(rate); | ||
| 2664 | fp->nr_rates++; | ||
| 2665 | } | ||
| 2666 | |||
| 2667 | err_free: | ||
| 2668 | kfree(data); | ||
| 2669 | err: | ||
| 2670 | return ret; | ||
| 2671 | } | ||
| 2672 | |||
| 2673 | /* | ||
| 2538 | * parse the format type I and III descriptors | 2674 | * parse the format type I and III descriptors |
| 2539 | */ | 2675 | */ |
| 2540 | static int parse_audio_format_i(struct snd_usb_audio *chip, struct audioformat *fp, | 2676 | static int parse_audio_format_i(struct snd_usb_audio *chip, |
| 2541 | int format, unsigned char *fmt) | 2677 | struct audioformat *fp, |
| 2678 | int format, void *_fmt, | ||
| 2679 | struct usb_host_interface *iface) | ||
| 2542 | { | 2680 | { |
| 2543 | int pcm_format; | 2681 | struct usb_interface_descriptor *altsd = get_iface_desc(iface); |
| 2682 | struct uac_format_type_i_discrete_descriptor *fmt = _fmt; | ||
| 2683 | int protocol = altsd->bInterfaceProtocol; | ||
| 2684 | int pcm_format, ret; | ||
| 2544 | 2685 | ||
| 2545 | if (fmt[3] == USB_FORMAT_TYPE_III) { | 2686 | if (fmt->bFormatType == UAC_FORMAT_TYPE_III) { |
| 2546 | /* FIXME: the format type is really IECxxx | 2687 | /* FIXME: the format type is really IECxxx |
| 2547 | * but we give normal PCM format to get the existing | 2688 | * but we give normal PCM format to get the existing |
| 2548 | * apps working... | 2689 | * apps working... |
| @@ -2560,34 +2701,57 @@ static int parse_audio_format_i(struct snd_usb_audio *chip, struct audioformat * | |||
| 2560 | pcm_format = SNDRV_PCM_FORMAT_S16_LE; | 2701 | pcm_format = SNDRV_PCM_FORMAT_S16_LE; |
| 2561 | } | 2702 | } |
| 2562 | } else { | 2703 | } else { |
| 2563 | pcm_format = parse_audio_format_i_type(chip, fp, format, fmt); | 2704 | pcm_format = parse_audio_format_i_type(chip, fp, format, fmt, protocol); |
| 2564 | if (pcm_format < 0) | 2705 | if (pcm_format < 0) |
| 2565 | return -1; | 2706 | return -1; |
| 2566 | } | 2707 | } |
| 2708 | |||
| 2567 | fp->format = pcm_format; | 2709 | fp->format = pcm_format; |
| 2568 | fp->channels = fmt[4]; | 2710 | |
| 2711 | /* gather possible sample rates */ | ||
| 2712 | /* audio class v1 reports possible sample rates as part of the | ||
| 2713 | * proprietary class specific descriptor. | ||
| 2714 | * audio class v2 uses class specific EP0 range requests for that. | ||
| 2715 | */ | ||
| 2716 | switch (protocol) { | ||
| 2717 | case UAC_VERSION_1: | ||
| 2718 | fp->channels = fmt->bNrChannels; | ||
| 2719 | ret = parse_audio_format_rates_v1(chip, fp, _fmt, 7); | ||
| 2720 | break; | ||
| 2721 | case UAC_VERSION_2: | ||
| 2722 | /* fp->channels is already set in this case */ | ||
| 2723 | ret = parse_audio_format_rates_v2(chip, fp, iface); | ||
| 2724 | break; | ||
| 2725 | } | ||
| 2726 | |||
| 2569 | if (fp->channels < 1) { | 2727 | if (fp->channels < 1) { |
| 2570 | snd_printk(KERN_ERR "%d:%u:%d : invalid channels %d\n", | 2728 | snd_printk(KERN_ERR "%d:%u:%d : invalid channels %d\n", |
| 2571 | chip->dev->devnum, fp->iface, fp->altsetting, fp->channels); | 2729 | chip->dev->devnum, fp->iface, fp->altsetting, fp->channels); |
| 2572 | return -1; | 2730 | return -1; |
| 2573 | } | 2731 | } |
| 2574 | return parse_audio_format_rates(chip, fp, fmt, 7); | 2732 | |
| 2733 | return ret; | ||
| 2575 | } | 2734 | } |
| 2576 | 2735 | ||
| 2577 | /* | 2736 | /* |
| 2578 | * prase the format type II descriptor | 2737 | * parse the format type II descriptor |
| 2579 | */ | 2738 | */ |
| 2580 | static int parse_audio_format_ii(struct snd_usb_audio *chip, struct audioformat *fp, | 2739 | static int parse_audio_format_ii(struct snd_usb_audio *chip, |
| 2581 | int format, unsigned char *fmt) | 2740 | struct audioformat *fp, |
| 2741 | int format, void *_fmt, | ||
| 2742 | struct usb_host_interface *iface) | ||
| 2582 | { | 2743 | { |
| 2583 | int brate, framesize; | 2744 | int brate, framesize, ret; |
| 2745 | struct usb_interface_descriptor *altsd = get_iface_desc(iface); | ||
| 2746 | int protocol = altsd->bInterfaceProtocol; | ||
| 2747 | |||
| 2584 | switch (format) { | 2748 | switch (format) { |
| 2585 | case USB_AUDIO_FORMAT_AC3: | 2749 | case UAC_FORMAT_TYPE_II_AC3: |
| 2586 | /* FIXME: there is no AC3 format defined yet */ | 2750 | /* FIXME: there is no AC3 format defined yet */ |
| 2587 | // fp->format = SNDRV_PCM_FORMAT_AC3; | 2751 | // fp->format = SNDRV_PCM_FORMAT_AC3; |
| 2588 | fp->format = SNDRV_PCM_FORMAT_U8; /* temporarily hack to receive byte streams */ | 2752 | fp->format = SNDRV_PCM_FORMAT_U8; /* temporarily hack to receive byte streams */ |
| 2589 | break; | 2753 | break; |
| 2590 | case USB_AUDIO_FORMAT_MPEG: | 2754 | case UAC_FORMAT_TYPE_II_MPEG: |
| 2591 | fp->format = SNDRV_PCM_FORMAT_MPEG; | 2755 | fp->format = SNDRV_PCM_FORMAT_MPEG; |
| 2592 | break; | 2756 | break; |
| 2593 | default: | 2757 | default: |
| @@ -2596,26 +2760,46 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip, struct audioformat | |||
| 2596 | fp->format = SNDRV_PCM_FORMAT_MPEG; | 2760 | fp->format = SNDRV_PCM_FORMAT_MPEG; |
| 2597 | break; | 2761 | break; |
| 2598 | } | 2762 | } |
| 2763 | |||
| 2599 | fp->channels = 1; | 2764 | fp->channels = 1; |
| 2600 | brate = combine_word(&fmt[4]); /* fmt[4,5] : wMaxBitRate (in kbps) */ | 2765 | |
| 2601 | framesize = combine_word(&fmt[6]); /* fmt[6,7]: wSamplesPerFrame */ | 2766 | switch (protocol) { |
| 2602 | snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize); | 2767 | case UAC_VERSION_1: { |
| 2603 | fp->frame_size = framesize; | 2768 | struct uac_format_type_ii_discrete_descriptor *fmt = _fmt; |
| 2604 | return parse_audio_format_rates(chip, fp, fmt, 8); /* fmt[8..] sample rates */ | 2769 | brate = le16_to_cpu(fmt->wMaxBitRate); |
| 2770 | framesize = le16_to_cpu(fmt->wSamplesPerFrame); | ||
| 2771 | snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize); | ||
| 2772 | fp->frame_size = framesize; | ||
| 2773 | ret = parse_audio_format_rates_v1(chip, fp, _fmt, 8); /* fmt[8..] sample rates */ | ||
| 2774 | break; | ||
| 2775 | } | ||
| 2776 | case UAC_VERSION_2: { | ||
| 2777 | struct uac_format_type_ii_ext_descriptor *fmt = _fmt; | ||
| 2778 | brate = le16_to_cpu(fmt->wMaxBitRate); | ||
| 2779 | framesize = le16_to_cpu(fmt->wSamplesPerFrame); | ||
| 2780 | snd_printd(KERN_INFO "found format II with max.bitrate = %d, frame size=%d\n", brate, framesize); | ||
| 2781 | fp->frame_size = framesize; | ||
| 2782 | ret = parse_audio_format_rates_v2(chip, fp, iface); | ||
| 2783 | break; | ||
| 2784 | } | ||
| 2785 | } | ||
| 2786 | |||
| 2787 | return ret; | ||
| 2605 | } | 2788 | } |
| 2606 | 2789 | ||
| 2607 | static int parse_audio_format(struct snd_usb_audio *chip, struct audioformat *fp, | 2790 | static int parse_audio_format(struct snd_usb_audio *chip, struct audioformat *fp, |
| 2608 | int format, unsigned char *fmt, int stream) | 2791 | int format, unsigned char *fmt, int stream, |
| 2792 | struct usb_host_interface *iface) | ||
| 2609 | { | 2793 | { |
| 2610 | int err; | 2794 | int err; |
| 2611 | 2795 | ||
| 2612 | switch (fmt[3]) { | 2796 | switch (fmt[3]) { |
| 2613 | case USB_FORMAT_TYPE_I: | 2797 | case UAC_FORMAT_TYPE_I: |
| 2614 | case USB_FORMAT_TYPE_III: | 2798 | case UAC_FORMAT_TYPE_III: |
| 2615 | err = parse_audio_format_i(chip, fp, format, fmt); | 2799 | err = parse_audio_format_i(chip, fp, format, fmt, iface); |
| 2616 | break; | 2800 | break; |
| 2617 | case USB_FORMAT_TYPE_II: | 2801 | case UAC_FORMAT_TYPE_II: |
| 2618 | err = parse_audio_format_ii(chip, fp, format, fmt); | 2802 | err = parse_audio_format_ii(chip, fp, format, fmt, iface); |
| 2619 | break; | 2803 | break; |
| 2620 | default: | 2804 | default: |
| 2621 | snd_printd(KERN_INFO "%d:%u:%d : format type %d is not supported yet\n", | 2805 | snd_printd(KERN_INFO "%d:%u:%d : format type %d is not supported yet\n", |
| @@ -2633,7 +2817,7 @@ static int parse_audio_format(struct snd_usb_audio *chip, struct audioformat *fp | |||
| 2633 | if (chip->usb_id == USB_ID(0x041e, 0x3000) || | 2817 | if (chip->usb_id == USB_ID(0x041e, 0x3000) || |
| 2634 | chip->usb_id == USB_ID(0x041e, 0x3020) || | 2818 | chip->usb_id == USB_ID(0x041e, 0x3020) || |
| 2635 | chip->usb_id == USB_ID(0x041e, 0x3061)) { | 2819 | chip->usb_id == USB_ID(0x041e, 0x3061)) { |
| 2636 | if (fmt[3] == USB_FORMAT_TYPE_I && | 2820 | if (fmt[3] == UAC_FORMAT_TYPE_I && |
| 2637 | fp->rates != SNDRV_PCM_RATE_48000 && | 2821 | fp->rates != SNDRV_PCM_RATE_48000 && |
| 2638 | fp->rates != SNDRV_PCM_RATE_96000) | 2822 | fp->rates != SNDRV_PCM_RATE_96000) |
| 2639 | return -1; | 2823 | return -1; |
| @@ -2662,10 +2846,10 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
| 2662 | struct usb_host_interface *alts; | 2846 | struct usb_host_interface *alts; |
| 2663 | struct usb_interface_descriptor *altsd; | 2847 | struct usb_interface_descriptor *altsd; |
| 2664 | int i, altno, err, stream; | 2848 | int i, altno, err, stream; |
| 2665 | int format; | 2849 | int format = 0, num_channels = 0; |
| 2666 | struct audioformat *fp = NULL; | 2850 | struct audioformat *fp = NULL; |
| 2667 | unsigned char *fmt, *csep; | 2851 | unsigned char *fmt, *csep; |
| 2668 | int num; | 2852 | int num, protocol; |
| 2669 | 2853 | ||
| 2670 | dev = chip->dev; | 2854 | dev = chip->dev; |
| 2671 | 2855 | ||
| @@ -2684,10 +2868,11 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
| 2684 | for (i = 0; i < num; i++) { | 2868 | for (i = 0; i < num; i++) { |
| 2685 | alts = &iface->altsetting[i]; | 2869 | alts = &iface->altsetting[i]; |
| 2686 | altsd = get_iface_desc(alts); | 2870 | altsd = get_iface_desc(alts); |
| 2871 | protocol = altsd->bInterfaceProtocol; | ||
| 2687 | /* skip invalid one */ | 2872 | /* skip invalid one */ |
| 2688 | if ((altsd->bInterfaceClass != USB_CLASS_AUDIO && | 2873 | if ((altsd->bInterfaceClass != USB_CLASS_AUDIO && |
| 2689 | altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) || | 2874 | altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) || |
| 2690 | (altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIO_STREAMING && | 2875 | (altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING && |
| 2691 | altsd->bInterfaceSubClass != USB_SUBCLASS_VENDOR_SPEC) || | 2876 | altsd->bInterfaceSubClass != USB_SUBCLASS_VENDOR_SPEC) || |
| 2692 | altsd->bNumEndpoints < 1 || | 2877 | altsd->bNumEndpoints < 1 || |
| 2693 | le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == 0) | 2878 | le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == 0) |
| @@ -2708,30 +2893,65 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
| 2708 | continue; | 2893 | continue; |
| 2709 | 2894 | ||
| 2710 | /* get audio formats */ | 2895 | /* get audio formats */ |
| 2711 | fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, AS_GENERAL); | 2896 | switch (protocol) { |
| 2712 | if (!fmt) { | 2897 | case UAC_VERSION_1: { |
| 2713 | snd_printk(KERN_ERR "%d:%u:%d : AS_GENERAL descriptor not found\n", | 2898 | struct uac_as_header_descriptor_v1 *as = |
| 2714 | dev->devnum, iface_no, altno); | 2899 | snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); |
| 2715 | continue; | 2900 | |
| 2901 | if (!as) { | ||
| 2902 | snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n", | ||
| 2903 | dev->devnum, iface_no, altno); | ||
| 2904 | continue; | ||
| 2905 | } | ||
| 2906 | |||
| 2907 | if (as->bLength < sizeof(*as)) { | ||
| 2908 | snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n", | ||
| 2909 | dev->devnum, iface_no, altno); | ||
| 2910 | continue; | ||
| 2911 | } | ||
| 2912 | |||
| 2913 | format = le16_to_cpu(as->wFormatTag); /* remember the format value */ | ||
| 2914 | break; | ||
| 2716 | } | 2915 | } |
| 2717 | 2916 | ||
| 2718 | if (fmt[0] < 7) { | 2917 | case UAC_VERSION_2: { |
| 2719 | snd_printk(KERN_ERR "%d:%u:%d : invalid AS_GENERAL desc\n", | 2918 | struct uac_as_header_descriptor_v2 *as = |
| 2720 | dev->devnum, iface_no, altno); | 2919 | snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); |
| 2721 | continue; | 2920 | |
| 2921 | if (!as) { | ||
| 2922 | snd_printk(KERN_ERR "%d:%u:%d : UAC_AS_GENERAL descriptor not found\n", | ||
| 2923 | dev->devnum, iface_no, altno); | ||
| 2924 | continue; | ||
| 2925 | } | ||
| 2926 | |||
| 2927 | if (as->bLength < sizeof(*as)) { | ||
| 2928 | snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_AS_GENERAL desc\n", | ||
| 2929 | dev->devnum, iface_no, altno); | ||
| 2930 | continue; | ||
| 2931 | } | ||
| 2932 | |||
| 2933 | num_channels = as->bNrChannels; | ||
| 2934 | format = le32_to_cpu(as->bmFormats); | ||
| 2935 | |||
| 2936 | break; | ||
| 2722 | } | 2937 | } |
| 2723 | 2938 | ||
| 2724 | format = (fmt[6] << 8) | fmt[5]; /* remember the format value */ | 2939 | default: |
| 2940 | snd_printk(KERN_ERR "%d:%u:%d : unknown interface protocol %04x\n", | ||
| 2941 | dev->devnum, iface_no, altno, protocol); | ||
| 2942 | continue; | ||
| 2943 | } | ||
| 2725 | 2944 | ||
| 2726 | /* get format type */ | 2945 | /* get format type */ |
| 2727 | fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, FORMAT_TYPE); | 2946 | fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_FORMAT_TYPE); |
| 2728 | if (!fmt) { | 2947 | if (!fmt) { |
| 2729 | snd_printk(KERN_ERR "%d:%u:%d : no FORMAT_TYPE desc\n", | 2948 | snd_printk(KERN_ERR "%d:%u:%d : no UAC_FORMAT_TYPE desc\n", |
| 2730 | dev->devnum, iface_no, altno); | 2949 | dev->devnum, iface_no, altno); |
| 2731 | continue; | 2950 | continue; |
| 2732 | } | 2951 | } |
| 2733 | if (fmt[0] < 8) { | 2952 | if (((protocol == UAC_VERSION_1) && (fmt[0] < 8)) || |
| 2734 | snd_printk(KERN_ERR "%d:%u:%d : invalid FORMAT_TYPE desc\n", | 2953 | ((protocol == UAC_VERSION_2) && (fmt[0] != 6))) { |
| 2954 | snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n", | ||
| 2735 | dev->devnum, iface_no, altno); | 2955 | dev->devnum, iface_no, altno); |
| 2736 | continue; | 2956 | continue; |
| 2737 | } | 2957 | } |
| @@ -2744,6 +2964,7 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
| 2744 | if (fmt[4] == 1 && fmt[5] == 2 && altno == 2 && num == 3 && | 2964 | if (fmt[4] == 1 && fmt[5] == 2 && altno == 2 && num == 3 && |
| 2745 | fp && fp->altsetting == 1 && fp->channels == 1 && | 2965 | fp && fp->altsetting == 1 && fp->channels == 1 && |
| 2746 | fp->format == SNDRV_PCM_FORMAT_S16_LE && | 2966 | fp->format == SNDRV_PCM_FORMAT_S16_LE && |
| 2967 | protocol == UAC_VERSION_1 && | ||
| 2747 | le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == | 2968 | le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == |
| 2748 | fp->maxpacksize * 2) | 2969 | fp->maxpacksize * 2) |
| 2749 | continue; | 2970 | continue; |
| @@ -2752,7 +2973,7 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
| 2752 | /* Creamware Noah has this descriptor after the 2nd endpoint */ | 2973 | /* Creamware Noah has this descriptor after the 2nd endpoint */ |
| 2753 | if (!csep && altsd->bNumEndpoints >= 2) | 2974 | if (!csep && altsd->bNumEndpoints >= 2) |
| 2754 | csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT); | 2975 | csep = snd_usb_find_desc(alts->endpoint[1].extra, alts->endpoint[1].extralen, NULL, USB_DT_CS_ENDPOINT); |
| 2755 | if (!csep || csep[0] < 7 || csep[2] != EP_GENERAL) { | 2976 | if (!csep || csep[0] < 7 || csep[2] != UAC_EP_GENERAL) { |
| 2756 | snd_printk(KERN_WARNING "%d:%u:%d : no or invalid" | 2977 | snd_printk(KERN_WARNING "%d:%u:%d : no or invalid" |
| 2757 | " class specific endpoint descriptor\n", | 2978 | " class specific endpoint descriptor\n", |
| 2758 | dev->devnum, iface_no, altno); | 2979 | dev->devnum, iface_no, altno); |
| @@ -2772,6 +2993,8 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
| 2772 | fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; | 2993 | fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; |
| 2773 | fp->datainterval = parse_datainterval(chip, alts); | 2994 | fp->datainterval = parse_datainterval(chip, alts); |
| 2774 | fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); | 2995 | fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); |
| 2996 | /* num_channels is only set for v2 interfaces */ | ||
| 2997 | fp->channels = num_channels; | ||
| 2775 | if (snd_usb_get_speed(dev) == USB_SPEED_HIGH) | 2998 | if (snd_usb_get_speed(dev) == USB_SPEED_HIGH) |
| 2776 | fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) | 2999 | fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) |
| 2777 | * (fp->maxpacksize & 0x7ff); | 3000 | * (fp->maxpacksize & 0x7ff); |
| @@ -2784,12 +3007,12 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
| 2784 | /* Optoplay sets the sample rate attribute although | 3007 | /* Optoplay sets the sample rate attribute although |
| 2785 | * it seems not supporting it in fact. | 3008 | * it seems not supporting it in fact. |
| 2786 | */ | 3009 | */ |
| 2787 | fp->attributes &= ~EP_CS_ATTR_SAMPLE_RATE; | 3010 | fp->attributes &= ~UAC_EP_CS_ATTR_SAMPLE_RATE; |
| 2788 | break; | 3011 | break; |
| 2789 | case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */ | 3012 | case USB_ID(0x041e, 0x3020): /* Creative SB Audigy 2 NX */ |
| 2790 | case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ | 3013 | case USB_ID(0x0763, 0x2003): /* M-Audio Audiophile USB */ |
| 2791 | /* doesn't set the sample rate attribute, but supports it */ | 3014 | /* doesn't set the sample rate attribute, but supports it */ |
| 2792 | fp->attributes |= EP_CS_ATTR_SAMPLE_RATE; | 3015 | fp->attributes |= UAC_EP_CS_ATTR_SAMPLE_RATE; |
| 2793 | break; | 3016 | break; |
| 2794 | case USB_ID(0x047f, 0x0ca1): /* plantronics headset */ | 3017 | case USB_ID(0x047f, 0x0ca1): /* plantronics headset */ |
| 2795 | case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is | 3018 | case USB_ID(0x077d, 0x07af): /* Griffin iMic (note that there is |
| @@ -2798,16 +3021,16 @@ static int parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
| 2798 | * plantronics headset and Griffin iMic have set adaptive-in | 3021 | * plantronics headset and Griffin iMic have set adaptive-in |
| 2799 | * although it's really not... | 3022 | * although it's really not... |
| 2800 | */ | 3023 | */ |
| 2801 | fp->ep_attr &= ~EP_ATTR_MASK; | 3024 | fp->ep_attr &= ~USB_ENDPOINT_SYNCTYPE; |
| 2802 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) | 3025 | if (stream == SNDRV_PCM_STREAM_PLAYBACK) |
| 2803 | fp->ep_attr |= EP_ATTR_ADAPTIVE; | 3026 | fp->ep_attr |= USB_ENDPOINT_SYNC_ADAPTIVE; |
| 2804 | else | 3027 | else |
| 2805 | fp->ep_attr |= EP_ATTR_SYNC; | 3028 | fp->ep_attr |= USB_ENDPOINT_SYNC_SYNC; |
| 2806 | break; | 3029 | break; |
| 2807 | } | 3030 | } |
| 2808 | 3031 | ||
| 2809 | /* ok, let's parse further... */ | 3032 | /* ok, let's parse further... */ |
| 2810 | if (parse_audio_format(chip, fp, format, fmt, stream) < 0) { | 3033 | if (parse_audio_format(chip, fp, format, fmt, stream, alts) < 0) { |
| 2811 | kfree(fp->rate_table); | 3034 | kfree(fp->rate_table); |
| 2812 | kfree(fp); | 3035 | kfree(fp); |
| 2813 | continue; | 3036 | continue; |
| @@ -2849,6 +3072,65 @@ static void snd_usb_stream_disconnect(struct list_head *head) | |||
| 2849 | } | 3072 | } |
| 2850 | } | 3073 | } |
| 2851 | 3074 | ||
| 3075 | static int snd_usb_create_stream(struct snd_usb_audio *chip, int ctrlif, int interface) | ||
| 3076 | { | ||
| 3077 | struct usb_device *dev = chip->dev; | ||
| 3078 | struct usb_host_interface *alts; | ||
| 3079 | struct usb_interface_descriptor *altsd; | ||
| 3080 | struct usb_interface *iface = usb_ifnum_to_if(dev, interface); | ||
| 3081 | |||
| 3082 | if (!iface) { | ||
| 3083 | snd_printk(KERN_ERR "%d:%u:%d : does not exist\n", | ||
| 3084 | dev->devnum, ctrlif, interface); | ||
| 3085 | return -EINVAL; | ||
| 3086 | } | ||
| 3087 | |||
| 3088 | if (usb_interface_claimed(iface)) { | ||
| 3089 | snd_printdd(KERN_INFO "%d:%d:%d: skipping, already claimed\n", | ||
| 3090 | dev->devnum, ctrlif, interface); | ||
| 3091 | return -EINVAL; | ||
| 3092 | } | ||
| 3093 | |||
| 3094 | alts = &iface->altsetting[0]; | ||
| 3095 | altsd = get_iface_desc(alts); | ||
| 3096 | if ((altsd->bInterfaceClass == USB_CLASS_AUDIO || | ||
| 3097 | altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC) && | ||
| 3098 | altsd->bInterfaceSubClass == USB_SUBCLASS_MIDISTREAMING) { | ||
| 3099 | int err = snd_usbmidi_create(chip->card, iface, | ||
| 3100 | &chip->midi_list, NULL); | ||
| 3101 | if (err < 0) { | ||
| 3102 | snd_printk(KERN_ERR "%d:%u:%d: cannot create sequencer device\n", | ||
| 3103 | dev->devnum, ctrlif, interface); | ||
| 3104 | return -EINVAL; | ||
| 3105 | } | ||
| 3106 | usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L); | ||
| 3107 | |||
| 3108 | return 0; | ||
| 3109 | } | ||
| 3110 | |||
| 3111 | if ((altsd->bInterfaceClass != USB_CLASS_AUDIO && | ||
| 3112 | altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) || | ||
| 3113 | altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING) { | ||
| 3114 | snd_printdd(KERN_ERR "%d:%u:%d: skipping non-supported interface %d\n", | ||
| 3115 | dev->devnum, ctrlif, interface, altsd->bInterfaceClass); | ||
| 3116 | /* skip non-supported classes */ | ||
| 3117 | return -EINVAL; | ||
| 3118 | } | ||
| 3119 | |||
| 3120 | if (snd_usb_get_speed(dev) == USB_SPEED_LOW) { | ||
| 3121 | snd_printk(KERN_ERR "low speed audio streaming not supported\n"); | ||
| 3122 | return -EINVAL; | ||
| 3123 | } | ||
| 3124 | |||
| 3125 | if (! parse_audio_endpoints(chip, interface)) { | ||
| 3126 | usb_set_interface(dev, interface, 0); /* reset the current interface */ | ||
| 3127 | usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L); | ||
| 3128 | return -EINVAL; | ||
| 3129 | } | ||
| 3130 | |||
| 3131 | return 0; | ||
| 3132 | } | ||
| 3133 | |||
| 2852 | /* | 3134 | /* |
| 2853 | * parse audio control descriptor and create pcm/midi streams | 3135 | * parse audio control descriptor and create pcm/midi streams |
| 2854 | */ | 3136 | */ |
| @@ -2856,67 +3138,81 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) | |||
| 2856 | { | 3138 | { |
| 2857 | struct usb_device *dev = chip->dev; | 3139 | struct usb_device *dev = chip->dev; |
| 2858 | struct usb_host_interface *host_iface; | 3140 | struct usb_host_interface *host_iface; |
| 2859 | struct usb_interface *iface; | 3141 | struct usb_interface_descriptor *altsd; |
| 2860 | unsigned char *p1; | 3142 | void *control_header; |
| 2861 | int i, j; | 3143 | int i, protocol; |
| 2862 | 3144 | ||
| 2863 | /* find audiocontrol interface */ | 3145 | /* find audiocontrol interface */ |
| 2864 | host_iface = &usb_ifnum_to_if(dev, ctrlif)->altsetting[0]; | 3146 | host_iface = &usb_ifnum_to_if(dev, ctrlif)->altsetting[0]; |
| 2865 | if (!(p1 = snd_usb_find_csint_desc(host_iface->extra, host_iface->extralen, NULL, HEADER))) { | 3147 | control_header = snd_usb_find_csint_desc(host_iface->extra, |
| 2866 | snd_printk(KERN_ERR "cannot find HEADER\n"); | 3148 | host_iface->extralen, |
| 2867 | return -EINVAL; | 3149 | NULL, UAC_HEADER); |
| 2868 | } | 3150 | altsd = get_iface_desc(host_iface); |
| 2869 | if (! p1[7] || p1[0] < 8 + p1[7]) { | 3151 | protocol = altsd->bInterfaceProtocol; |
| 2870 | snd_printk(KERN_ERR "invalid HEADER\n"); | 3152 | |
| 3153 | if (!control_header) { | ||
| 3154 | snd_printk(KERN_ERR "cannot find UAC_HEADER\n"); | ||
| 2871 | return -EINVAL; | 3155 | return -EINVAL; |
| 2872 | } | 3156 | } |
| 2873 | 3157 | ||
| 2874 | /* | 3158 | switch (protocol) { |
| 2875 | * parse all USB audio streaming interfaces | 3159 | case UAC_VERSION_1: { |
| 2876 | */ | 3160 | struct uac_ac_header_descriptor_v1 *h1 = control_header; |
| 2877 | for (i = 0; i < p1[7]; i++) { | 3161 | |
| 2878 | struct usb_host_interface *alts; | 3162 | if (!h1->bInCollection) { |
| 2879 | struct usb_interface_descriptor *altsd; | 3163 | snd_printk(KERN_INFO "skipping empty audio interface (v1)\n"); |
| 2880 | j = p1[8 + i]; | 3164 | return -EINVAL; |
| 2881 | iface = usb_ifnum_to_if(dev, j); | ||
| 2882 | if (!iface) { | ||
| 2883 | snd_printk(KERN_ERR "%d:%u:%d : does not exist\n", | ||
| 2884 | dev->devnum, ctrlif, j); | ||
| 2885 | continue; | ||
| 2886 | } | ||
| 2887 | if (usb_interface_claimed(iface)) { | ||
| 2888 | snd_printdd(KERN_INFO "%d:%d:%d: skipping, already claimed\n", dev->devnum, ctrlif, j); | ||
| 2889 | continue; | ||
| 2890 | } | 3165 | } |
| 2891 | alts = &iface->altsetting[0]; | 3166 | |
| 2892 | altsd = get_iface_desc(alts); | 3167 | if (h1->bLength < sizeof(*h1) + h1->bInCollection) { |
| 2893 | if ((altsd->bInterfaceClass == USB_CLASS_AUDIO || | 3168 | snd_printk(KERN_ERR "invalid UAC_HEADER (v1)\n"); |
| 2894 | altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC) && | 3169 | return -EINVAL; |
| 2895 | altsd->bInterfaceSubClass == USB_SUBCLASS_MIDI_STREAMING) { | ||
| 2896 | int err = snd_usbmidi_create(chip->card, iface, | ||
| 2897 | &chip->midi_list, NULL); | ||
| 2898 | if (err < 0) { | ||
| 2899 | snd_printk(KERN_ERR "%d:%u:%d: cannot create sequencer device\n", dev->devnum, ctrlif, j); | ||
| 2900 | continue; | ||
| 2901 | } | ||
| 2902 | usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L); | ||
| 2903 | continue; | ||
| 2904 | } | 3170 | } |
| 2905 | if ((altsd->bInterfaceClass != USB_CLASS_AUDIO && | 3171 | |
| 2906 | altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) || | 3172 | for (i = 0; i < h1->bInCollection; i++) |
| 2907 | altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIO_STREAMING) { | 3173 | snd_usb_create_stream(chip, ctrlif, h1->baInterfaceNr[i]); |
| 2908 | snd_printdd(KERN_ERR "%d:%u:%d: skipping non-supported interface %d\n", dev->devnum, ctrlif, j, altsd->bInterfaceClass); | 3174 | |
| 2909 | /* skip non-supported classes */ | 3175 | break; |
| 2910 | continue; | 3176 | } |
| 3177 | |||
| 3178 | case UAC_VERSION_2: { | ||
| 3179 | struct uac_clock_source_descriptor *cs; | ||
| 3180 | struct usb_interface_assoc_descriptor *assoc = | ||
| 3181 | usb_ifnum_to_if(dev, ctrlif)->intf_assoc; | ||
| 3182 | |||
| 3183 | if (!assoc) { | ||
| 3184 | snd_printk(KERN_ERR "Audio class v2 interfaces need an interface association\n"); | ||
| 3185 | return -EINVAL; | ||
| 2911 | } | 3186 | } |
| 2912 | if (snd_usb_get_speed(dev) == USB_SPEED_LOW) { | 3187 | |
| 2913 | snd_printk(KERN_ERR "low speed audio streaming not supported\n"); | 3188 | /* FIXME: for now, we expect there is at least one clock source |
| 2914 | continue; | 3189 | * descriptor and we always take the first one. |
| 3190 | * We should properly support devices with multiple clock sources, | ||
| 3191 | * clock selectors and sample rate conversion units. */ | ||
| 3192 | |||
| 3193 | cs = snd_usb_find_csint_desc(host_iface->extra, host_iface->extralen, | ||
| 3194 | NULL, UAC_CLOCK_SOURCE); | ||
| 3195 | |||
| 3196 | if (!cs) { | ||
| 3197 | snd_printk(KERN_ERR "CLOCK_SOURCE descriptor not found\n"); | ||
| 3198 | return -EINVAL; | ||
| 2915 | } | 3199 | } |
| 2916 | if (! parse_audio_endpoints(chip, j)) { | 3200 | |
| 2917 | usb_set_interface(dev, j, 0); /* reset the current interface */ | 3201 | chip->clock_id = cs->bClockID; |
| 2918 | usb_driver_claim_interface(&usb_audio_driver, iface, (void *)-1L); | 3202 | |
| 3203 | for (i = 0; i < assoc->bInterfaceCount; i++) { | ||
| 3204 | int intf = assoc->bFirstInterface + i; | ||
| 3205 | |||
| 3206 | if (intf != ctrlif) | ||
| 3207 | snd_usb_create_stream(chip, ctrlif, intf); | ||
| 2919 | } | 3208 | } |
| 3209 | |||
| 3210 | break; | ||
| 3211 | } | ||
| 3212 | |||
| 3213 | default: | ||
| 3214 | snd_printk(KERN_ERR "unknown protocol version 0x%02x\n", protocol); | ||
| 3215 | return -EINVAL; | ||
| 2920 | } | 3216 | } |
| 2921 | 3217 | ||
| 2922 | return 0; | 3218 | return 0; |
| @@ -3007,7 +3303,7 @@ static int create_uaxx_quirk(struct snd_usb_audio *chip, | |||
| 3007 | static const struct audioformat ua_format = { | 3303 | static const struct audioformat ua_format = { |
| 3008 | .format = SNDRV_PCM_FORMAT_S24_3LE, | 3304 | .format = SNDRV_PCM_FORMAT_S24_3LE, |
| 3009 | .channels = 2, | 3305 | .channels = 2, |
| 3010 | .fmt_type = USB_FORMAT_TYPE_I, | 3306 | .fmt_type = UAC_FORMAT_TYPE_I, |
| 3011 | .altsetting = 1, | 3307 | .altsetting = 1, |
| 3012 | .altset_idx = 1, | 3308 | .altset_idx = 1, |
| 3013 | .rates = SNDRV_PCM_RATE_CONTINUOUS, | 3309 | .rates = SNDRV_PCM_RATE_CONTINUOUS, |
| @@ -3099,7 +3395,7 @@ static int create_ua1000_quirk(struct snd_usb_audio *chip, | |||
| 3099 | { | 3395 | { |
| 3100 | static const struct audioformat ua1000_format = { | 3396 | static const struct audioformat ua1000_format = { |
| 3101 | .format = SNDRV_PCM_FORMAT_S32_LE, | 3397 | .format = SNDRV_PCM_FORMAT_S32_LE, |
| 3102 | .fmt_type = USB_FORMAT_TYPE_I, | 3398 | .fmt_type = UAC_FORMAT_TYPE_I, |
| 3103 | .altsetting = 1, | 3399 | .altsetting = 1, |
| 3104 | .altset_idx = 1, | 3400 | .altset_idx = 1, |
| 3105 | .attributes = 0, | 3401 | .attributes = 0, |
| @@ -3142,59 +3438,6 @@ static int create_ua1000_quirk(struct snd_usb_audio *chip, | |||
| 3142 | return 0; | 3438 | return 0; |
| 3143 | } | 3439 | } |
| 3144 | 3440 | ||
| 3145 | /* | ||
| 3146 | * Create a stream for an Edirol UA-101 interface. | ||
| 3147 | * Copy, paste and modify from Edirol UA-1000 | ||
| 3148 | */ | ||
| 3149 | static int create_ua101_quirk(struct snd_usb_audio *chip, | ||
| 3150 | struct usb_interface *iface, | ||
| 3151 | const struct snd_usb_audio_quirk *quirk) | ||
| 3152 | { | ||
| 3153 | static const struct audioformat ua101_format = { | ||
| 3154 | .format = SNDRV_PCM_FORMAT_S32_LE, | ||
| 3155 | .fmt_type = USB_FORMAT_TYPE_I, | ||
| 3156 | .altsetting = 1, | ||
| 3157 | .altset_idx = 1, | ||
| 3158 | .attributes = 0, | ||
| 3159 | .rates = SNDRV_PCM_RATE_CONTINUOUS, | ||
| 3160 | }; | ||
| 3161 | struct usb_host_interface *alts; | ||
| 3162 | struct usb_interface_descriptor *altsd; | ||
| 3163 | struct audioformat *fp; | ||
| 3164 | int stream, err; | ||
| 3165 | |||
| 3166 | if (iface->num_altsetting != 2) | ||
| 3167 | return -ENXIO; | ||
| 3168 | alts = &iface->altsetting[1]; | ||
| 3169 | altsd = get_iface_desc(alts); | ||
| 3170 | if (alts->extralen != 18 || alts->extra[1] != USB_DT_CS_INTERFACE || | ||
| 3171 | altsd->bNumEndpoints != 1) | ||
| 3172 | return -ENXIO; | ||
| 3173 | |||
| 3174 | fp = kmemdup(&ua101_format, sizeof(*fp), GFP_KERNEL); | ||
| 3175 | if (!fp) | ||
| 3176 | return -ENOMEM; | ||
| 3177 | |||
| 3178 | fp->channels = alts->extra[11]; | ||
| 3179 | fp->iface = altsd->bInterfaceNumber; | ||
| 3180 | fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; | ||
| 3181 | fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; | ||
| 3182 | fp->datainterval = parse_datainterval(chip, alts); | ||
| 3183 | fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); | ||
| 3184 | fp->rate_max = fp->rate_min = combine_triple(&alts->extra[15]); | ||
| 3185 | |||
| 3186 | stream = (fp->endpoint & USB_DIR_IN) | ||
| 3187 | ? SNDRV_PCM_STREAM_CAPTURE : SNDRV_PCM_STREAM_PLAYBACK; | ||
| 3188 | err = add_audio_endpoint(chip, stream, fp); | ||
| 3189 | if (err < 0) { | ||
| 3190 | kfree(fp); | ||
| 3191 | return err; | ||
| 3192 | } | ||
| 3193 | /* FIXME: playback must be synchronized to capture */ | ||
| 3194 | usb_set_interface(chip->dev, fp->iface, 0); | ||
| 3195 | return 0; | ||
| 3196 | } | ||
| 3197 | |||
| 3198 | static int snd_usb_create_quirk(struct snd_usb_audio *chip, | 3441 | static int snd_usb_create_quirk(struct snd_usb_audio *chip, |
| 3199 | struct usb_interface *iface, | 3442 | struct usb_interface *iface, |
| 3200 | const struct snd_usb_audio_quirk *quirk); | 3443 | const struct snd_usb_audio_quirk *quirk); |
| @@ -3232,6 +3475,18 @@ static int ignore_interface_quirk(struct snd_usb_audio *chip, | |||
| 3232 | return 0; | 3475 | return 0; |
| 3233 | } | 3476 | } |
| 3234 | 3477 | ||
| 3478 | /* | ||
| 3479 | * Allow alignment on audio sub-slot (channel samples) rather than | ||
| 3480 | * on audio slots (audio frames) | ||
| 3481 | */ | ||
| 3482 | static int create_align_transfer_quirk(struct snd_usb_audio *chip, | ||
| 3483 | struct usb_interface *iface, | ||
| 3484 | const struct snd_usb_audio_quirk *quirk) | ||
| 3485 | { | ||
| 3486 | chip->txfr_quirk = 1; | ||
| 3487 | return 1; /* Continue with creating streams and mixer */ | ||
| 3488 | } | ||
| 3489 | |||
| 3235 | 3490 | ||
| 3236 | /* | 3491 | /* |
| 3237 | * boot quirks | 3492 | * boot quirks |
| @@ -3327,6 +3582,32 @@ static int snd_usb_cm6206_boot_quirk(struct usb_device *dev) | |||
| 3327 | } | 3582 | } |
| 3328 | 3583 | ||
| 3329 | /* | 3584 | /* |
| 3585 | * This call will put the synth in "USB send" mode, i.e it will send MIDI | ||
| 3586 | * messages through USB (this is disabled at startup). The synth will | ||
| 3587 | * acknowledge by sending a sysex on endpoint 0x85 and by displaying a USB | ||
| 3588 | * sign on its LCD. Values here are chosen based on sniffing USB traffic | ||
| 3589 | * under Windows. | ||
| 3590 | */ | ||
| 3591 | static int snd_usb_accessmusic_boot_quirk(struct usb_device *dev) | ||
| 3592 | { | ||
| 3593 | int err, actual_length; | ||
| 3594 | |||
| 3595 | /* "midi send" enable */ | ||
| 3596 | static const u8 seq[] = { 0x4e, 0x73, 0x52, 0x01 }; | ||
| 3597 | |||
| 3598 | void *buf = kmemdup(seq, ARRAY_SIZE(seq), GFP_KERNEL); | ||
| 3599 | if (!buf) | ||
| 3600 | return -ENOMEM; | ||
| 3601 | err = usb_interrupt_msg(dev, usb_sndintpipe(dev, 0x05), buf, | ||
| 3602 | ARRAY_SIZE(seq), &actual_length, 1000); | ||
| 3603 | kfree(buf); | ||
| 3604 | if (err < 0) | ||
| 3605 | return err; | ||
| 3606 | |||
| 3607 | return 0; | ||
| 3608 | } | ||
| 3609 | |||
| 3610 | /* | ||
| 3330 | * Setup quirks | 3611 | * Setup quirks |
| 3331 | */ | 3612 | */ |
| 3332 | #define AUDIOPHILE_SET 0x01 /* if set, parse device_setup */ | 3613 | #define AUDIOPHILE_SET 0x01 /* if set, parse device_setup */ |
| @@ -3406,8 +3687,8 @@ static int snd_usb_create_quirk(struct snd_usb_audio *chip, | |||
| 3406 | [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, | 3687 | [QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk, |
| 3407 | [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, | 3688 | [QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk, |
| 3408 | [QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk, | 3689 | [QUIRK_AUDIO_EDIROL_UA1000] = create_ua1000_quirk, |
| 3409 | [QUIRK_AUDIO_EDIROL_UA101] = create_ua101_quirk, | 3690 | [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk, |
| 3410 | [QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk | 3691 | [QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk |
| 3411 | }; | 3692 | }; |
| 3412 | 3693 | ||
| 3413 | if (quirk->type < QUIRK_TYPE_COUNT) { | 3694 | if (quirk->type < QUIRK_TYPE_COUNT) { |
| @@ -3596,7 +3877,6 @@ static void *snd_usb_audio_probe(struct usb_device *dev, | |||
| 3596 | ifnum = get_iface_desc(alts)->bInterfaceNumber; | 3877 | ifnum = get_iface_desc(alts)->bInterfaceNumber; |
| 3597 | id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), | 3878 | id = USB_ID(le16_to_cpu(dev->descriptor.idVendor), |
| 3598 | le16_to_cpu(dev->descriptor.idProduct)); | 3879 | le16_to_cpu(dev->descriptor.idProduct)); |
| 3599 | |||
| 3600 | if (quirk && quirk->ifnum >= 0 && ifnum != quirk->ifnum) | 3880 | if (quirk && quirk->ifnum >= 0 && ifnum != quirk->ifnum) |
| 3601 | goto __err_val; | 3881 | goto __err_val; |
| 3602 | 3882 | ||
| @@ -3624,6 +3904,12 @@ static void *snd_usb_audio_probe(struct usb_device *dev, | |||
| 3624 | goto __err_val; | 3904 | goto __err_val; |
| 3625 | } | 3905 | } |
| 3626 | 3906 | ||
| 3907 | /* Access Music VirusTI Desktop */ | ||
| 3908 | if (id == USB_ID(0x133e, 0x0815)) { | ||
| 3909 | if (snd_usb_accessmusic_boot_quirk(dev) < 0) | ||
| 3910 | goto __err_val; | ||
| 3911 | } | ||
| 3912 | |||
| 3627 | /* | 3913 | /* |
| 3628 | * found a config. now register to ALSA | 3914 | * found a config. now register to ALSA |
| 3629 | */ | 3915 | */ |
| @@ -3661,6 +3947,7 @@ static void *snd_usb_audio_probe(struct usb_device *dev, | |||
| 3661 | } | 3947 | } |
| 3662 | } | 3948 | } |
| 3663 | 3949 | ||
| 3950 | chip->txfr_quirk = 0; | ||
| 3664 | err = 1; /* continue */ | 3951 | err = 1; /* continue */ |
| 3665 | if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) { | 3952 | if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) { |
| 3666 | /* need some special handlings */ | 3953 | /* need some special handlings */ |
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 40ba8115fb81..6b016d4aac6b 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h | |||
| @@ -21,93 +21,6 @@ | |||
| 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| 22 | */ | 22 | */ |
| 23 | 23 | ||
| 24 | |||
| 25 | /* | ||
| 26 | */ | ||
| 27 | |||
| 28 | #define USB_SUBCLASS_AUDIO_CONTROL 0x01 | ||
| 29 | #define USB_SUBCLASS_AUDIO_STREAMING 0x02 | ||
| 30 | #define USB_SUBCLASS_MIDI_STREAMING 0x03 | ||
| 31 | #define USB_SUBCLASS_VENDOR_SPEC 0xff | ||
| 32 | |||
| 33 | #define HEADER 0x01 | ||
| 34 | #define INPUT_TERMINAL 0x02 | ||
| 35 | #define OUTPUT_TERMINAL 0x03 | ||
| 36 | #define MIXER_UNIT 0x04 | ||
| 37 | #define SELECTOR_UNIT 0x05 | ||
| 38 | #define FEATURE_UNIT 0x06 | ||
| 39 | #define PROCESSING_UNIT 0x07 | ||
| 40 | #define EXTENSION_UNIT 0x08 | ||
| 41 | |||
| 42 | #define AS_GENERAL 0x01 | ||
| 43 | #define FORMAT_TYPE 0x02 | ||
| 44 | #define FORMAT_SPECIFIC 0x03 | ||
| 45 | |||
| 46 | #define EP_GENERAL 0x01 | ||
| 47 | |||
| 48 | #define MS_GENERAL 0x01 | ||
| 49 | #define MIDI_IN_JACK 0x02 | ||
| 50 | #define MIDI_OUT_JACK 0x03 | ||
| 51 | |||
| 52 | /* endpoint attributes */ | ||
| 53 | #define EP_ATTR_MASK 0x0c | ||
| 54 | #define EP_ATTR_ASYNC 0x04 | ||
| 55 | #define EP_ATTR_ADAPTIVE 0x08 | ||
| 56 | #define EP_ATTR_SYNC 0x0c | ||
| 57 | |||
| 58 | /* cs endpoint attributes */ | ||
| 59 | #define EP_CS_ATTR_SAMPLE_RATE 0x01 | ||
| 60 | #define EP_CS_ATTR_PITCH_CONTROL 0x02 | ||
| 61 | #define EP_CS_ATTR_FILL_MAX 0x80 | ||
| 62 | |||
| 63 | /* Audio Class specific Request Codes */ | ||
| 64 | |||
| 65 | #define SET_CUR 0x01 | ||
| 66 | #define GET_CUR 0x81 | ||
| 67 | #define SET_MIN 0x02 | ||
| 68 | #define GET_MIN 0x82 | ||
| 69 | #define SET_MAX 0x03 | ||
| 70 | #define GET_MAX 0x83 | ||
| 71 | #define SET_RES 0x04 | ||
| 72 | #define GET_RES 0x84 | ||
| 73 | #define SET_MEM 0x05 | ||
| 74 | #define GET_MEM 0x85 | ||
| 75 | #define GET_STAT 0xff | ||
| 76 | |||
| 77 | /* Terminal Control Selectors */ | ||
| 78 | |||
| 79 | #define COPY_PROTECT_CONTROL 0x01 | ||
| 80 | |||
| 81 | /* Endpoint Control Selectors */ | ||
| 82 | |||
| 83 | #define SAMPLING_FREQ_CONTROL 0x01 | ||
| 84 | #define PITCH_CONTROL 0x02 | ||
| 85 | |||
| 86 | /* Format Types */ | ||
| 87 | #define USB_FORMAT_TYPE_I 0x01 | ||
| 88 | #define USB_FORMAT_TYPE_II 0x02 | ||
| 89 | #define USB_FORMAT_TYPE_III 0x03 | ||
| 90 | |||
| 91 | /* type I */ | ||
| 92 | #define USB_AUDIO_FORMAT_PCM 0x01 | ||
| 93 | #define USB_AUDIO_FORMAT_PCM8 0x02 | ||
| 94 | #define USB_AUDIO_FORMAT_IEEE_FLOAT 0x03 | ||
| 95 | #define USB_AUDIO_FORMAT_ALAW 0x04 | ||
| 96 | #define USB_AUDIO_FORMAT_MU_LAW 0x05 | ||
| 97 | |||
| 98 | /* type II */ | ||
| 99 | #define USB_AUDIO_FORMAT_MPEG 0x1001 | ||
| 100 | #define USB_AUDIO_FORMAT_AC3 0x1002 | ||
| 101 | |||
| 102 | /* type III */ | ||
| 103 | #define USB_AUDIO_FORMAT_IEC1937_AC3 0x2001 | ||
| 104 | #define USB_AUDIO_FORMAT_IEC1937_MPEG1_LAYER1 0x2002 | ||
| 105 | #define USB_AUDIO_FORMAT_IEC1937_MPEG2_NOEXT 0x2003 | ||
| 106 | #define USB_AUDIO_FORMAT_IEC1937_MPEG2_EXT 0x2004 | ||
| 107 | #define USB_AUDIO_FORMAT_IEC1937_MPEG2_LAYER1_LS 0x2005 | ||
| 108 | #define USB_AUDIO_FORMAT_IEC1937_MPEG2_LAYER23_LS 0x2006 | ||
| 109 | |||
| 110 | |||
| 111 | /* maximum number of endpoints per interface */ | 24 | /* maximum number of endpoints per interface */ |
| 112 | #define MIDI_MAX_ENDPOINTS 2 | 25 | #define MIDI_MAX_ENDPOINTS 2 |
| 113 | 26 | ||
| @@ -125,9 +38,13 @@ struct snd_usb_audio { | |||
| 125 | struct snd_card *card; | 38 | struct snd_card *card; |
| 126 | u32 usb_id; | 39 | u32 usb_id; |
| 127 | int shutdown; | 40 | int shutdown; |
| 41 | unsigned int txfr_quirk:1; /* Subframe boundaries on transfers */ | ||
| 128 | int num_interfaces; | 42 | int num_interfaces; |
| 129 | int num_suspended_intf; | 43 | int num_suspended_intf; |
| 130 | 44 | ||
| 45 | /* for audio class v2 */ | ||
| 46 | int clock_id; | ||
| 47 | |||
| 131 | struct list_head pcm_list; /* list of pcm streams */ | 48 | struct list_head pcm_list; /* list of pcm streams */ |
| 132 | int pcm_devs; | 49 | int pcm_devs; |
| 133 | 50 | ||
| @@ -159,8 +76,8 @@ enum quirk_type { | |||
| 159 | QUIRK_AUDIO_STANDARD_INTERFACE, | 76 | QUIRK_AUDIO_STANDARD_INTERFACE, |
| 160 | QUIRK_AUDIO_FIXED_ENDPOINT, | 77 | QUIRK_AUDIO_FIXED_ENDPOINT, |
| 161 | QUIRK_AUDIO_EDIROL_UA1000, | 78 | QUIRK_AUDIO_EDIROL_UA1000, |
| 162 | QUIRK_AUDIO_EDIROL_UA101, | ||
| 163 | QUIRK_AUDIO_EDIROL_UAXX, | 79 | QUIRK_AUDIO_EDIROL_UAXX, |
| 80 | QUIRK_AUDIO_ALIGN_TRANSFER, | ||
| 164 | 81 | ||
| 165 | QUIRK_TYPE_COUNT | 82 | QUIRK_TYPE_COUNT |
| 166 | }; | 83 | }; |
| @@ -209,6 +126,16 @@ struct snd_usb_midi_endpoint_info { | |||
| 209 | /* | 126 | /* |
| 210 | */ | 127 | */ |
| 211 | 128 | ||
| 129 | /*E-mu USB samplerate control quirk*/ | ||
| 130 | enum { | ||
| 131 | EMU_QUIRK_SR_44100HZ = 0, | ||
| 132 | EMU_QUIRK_SR_48000HZ, | ||
| 133 | EMU_QUIRK_SR_88200HZ, | ||
| 134 | EMU_QUIRK_SR_96000HZ, | ||
| 135 | EMU_QUIRK_SR_176400HZ, | ||
| 136 | EMU_QUIRK_SR_192000HZ | ||
| 137 | }; | ||
| 138 | |||
| 212 | #define combine_word(s) ((*(s)) | ((unsigned int)(s)[1] << 8)) | 139 | #define combine_word(s) ((*(s)) | ((unsigned int)(s)[1] << 8)) |
| 213 | #define combine_triple(s) (combine_word(s) | ((unsigned int)(s)[2] << 16)) | 140 | #define combine_triple(s) (combine_word(s) | ((unsigned int)(s)[2] << 16)) |
| 214 | #define combine_quad(s) (combine_triple(s) | ((unsigned int)(s)[3] << 24)) | 141 | #define combine_quad(s) (combine_triple(s) | ((unsigned int)(s)[3] << 24)) |
| @@ -234,6 +161,9 @@ void snd_usbmidi_input_stop(struct list_head* p); | |||
| 234 | void snd_usbmidi_input_start(struct list_head* p); | 161 | void snd_usbmidi_input_start(struct list_head* p); |
| 235 | void snd_usbmidi_disconnect(struct list_head *p); | 162 | void snd_usbmidi_disconnect(struct list_head *p); |
| 236 | 163 | ||
| 164 | void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, | ||
| 165 | unsigned char samplerate_id); | ||
| 166 | |||
| 237 | /* | 167 | /* |
| 238 | * retrieve usb_interface descriptor from the host interface | 168 | * retrieve usb_interface descriptor from the host interface |
| 239 | * (conditional for compatibility with the older API) | 169 | * (conditional for compatibility with the older API) |
diff --git a/sound/usb/usbmidi.c b/sound/usb/usbmidi.c index aae50df06232..2c59afd99611 100644 --- a/sound/usb/usbmidi.c +++ b/sound/usb/usbmidi.c | |||
| @@ -46,6 +46,8 @@ | |||
| 46 | #include <linux/timer.h> | 46 | #include <linux/timer.h> |
| 47 | #include <linux/usb.h> | 47 | #include <linux/usb.h> |
| 48 | #include <linux/wait.h> | 48 | #include <linux/wait.h> |
| 49 | #include <linux/usb/audio.h> | ||
| 50 | |||
| 49 | #include <sound/core.h> | 51 | #include <sound/core.h> |
| 50 | #include <sound/control.h> | 52 | #include <sound/control.h> |
| 51 | #include <sound/rawmidi.h> | 53 | #include <sound/rawmidi.h> |
| @@ -1419,6 +1421,12 @@ static struct port_info { | |||
| 1419 | EXTERNAL_PORT(0x086a, 0x0001, 8, "%s Broadcast"), | 1421 | EXTERNAL_PORT(0x086a, 0x0001, 8, "%s Broadcast"), |
| 1420 | EXTERNAL_PORT(0x086a, 0x0002, 8, "%s Broadcast"), | 1422 | EXTERNAL_PORT(0x086a, 0x0002, 8, "%s Broadcast"), |
| 1421 | EXTERNAL_PORT(0x086a, 0x0003, 4, "%s Broadcast"), | 1423 | EXTERNAL_PORT(0x086a, 0x0003, 4, "%s Broadcast"), |
| 1424 | /* Access Music Virus TI */ | ||
| 1425 | EXTERNAL_PORT(0x133e, 0x0815, 0, "%s MIDI"), | ||
| 1426 | PORT_INFO(0x133e, 0x0815, 1, "%s Synth", 0, | ||
| 1427 | SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | | ||
| 1428 | SNDRV_SEQ_PORT_TYPE_HARDWARE | | ||
| 1429 | SNDRV_SEQ_PORT_TYPE_SYNTHESIZER), | ||
| 1422 | }; | 1430 | }; |
| 1423 | 1431 | ||
| 1424 | static struct port_info *find_port_info(struct snd_usb_midi* umidi, int number) | 1432 | static struct port_info *find_port_info(struct snd_usb_midi* umidi, int number) |
| @@ -1534,7 +1542,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, | |||
| 1534 | if (hostif->extralen >= 7 && | 1542 | if (hostif->extralen >= 7 && |
| 1535 | ms_header->bLength >= 7 && | 1543 | ms_header->bLength >= 7 && |
| 1536 | ms_header->bDescriptorType == USB_DT_CS_INTERFACE && | 1544 | ms_header->bDescriptorType == USB_DT_CS_INTERFACE && |
| 1537 | ms_header->bDescriptorSubtype == HEADER) | 1545 | ms_header->bDescriptorSubtype == UAC_HEADER) |
| 1538 | snd_printdd(KERN_INFO "MIDIStreaming version %02x.%02x\n", | 1546 | snd_printdd(KERN_INFO "MIDIStreaming version %02x.%02x\n", |
| 1539 | ms_header->bcdMSC[1], ms_header->bcdMSC[0]); | 1547 | ms_header->bcdMSC[1], ms_header->bcdMSC[0]); |
| 1540 | else | 1548 | else |
| @@ -1550,7 +1558,7 @@ static int snd_usbmidi_get_ms_info(struct snd_usb_midi* umidi, | |||
| 1550 | if (hostep->extralen < 4 || | 1558 | if (hostep->extralen < 4 || |
| 1551 | ms_ep->bLength < 4 || | 1559 | ms_ep->bLength < 4 || |
| 1552 | ms_ep->bDescriptorType != USB_DT_CS_ENDPOINT || | 1560 | ms_ep->bDescriptorType != USB_DT_CS_ENDPOINT || |
| 1553 | ms_ep->bDescriptorSubtype != MS_GENERAL) | 1561 | ms_ep->bDescriptorSubtype != UAC_MS_GENERAL) |
| 1554 | continue; | 1562 | continue; |
| 1555 | if (usb_endpoint_dir_out(ep)) { | 1563 | if (usb_endpoint_dir_out(ep)) { |
| 1556 | if (endpoints[epidx].out_ep) { | 1564 | if (endpoints[epidx].out_ep) { |
| @@ -1762,9 +1770,9 @@ static int snd_usbmidi_detect_yamaha(struct snd_usb_midi* umidi, | |||
| 1762 | cs_desc < hostif->extra + hostif->extralen && cs_desc[0] >= 2; | 1770 | cs_desc < hostif->extra + hostif->extralen && cs_desc[0] >= 2; |
| 1763 | cs_desc += cs_desc[0]) { | 1771 | cs_desc += cs_desc[0]) { |
| 1764 | if (cs_desc[1] == USB_DT_CS_INTERFACE) { | 1772 | if (cs_desc[1] == USB_DT_CS_INTERFACE) { |
| 1765 | if (cs_desc[2] == MIDI_IN_JACK) | 1773 | if (cs_desc[2] == UAC_MIDI_IN_JACK) |
| 1766 | endpoint->in_cables = (endpoint->in_cables << 1) | 1; | 1774 | endpoint->in_cables = (endpoint->in_cables << 1) | 1; |
| 1767 | else if (cs_desc[2] == MIDI_OUT_JACK) | 1775 | else if (cs_desc[2] == UAC_MIDI_OUT_JACK) |
| 1768 | endpoint->out_cables = (endpoint->out_cables << 1) | 1; | 1776 | endpoint->out_cables = (endpoint->out_cables << 1) | 1; |
| 1769 | } | 1777 | } |
| 1770 | } | 1778 | } |
diff --git a/sound/usb/usbmixer.c b/sound/usb/usbmixer.c index c998220b99c6..8e8f871b74ca 100644 --- a/sound/usb/usbmixer.c +++ b/sound/usb/usbmixer.c | |||
| @@ -32,6 +32,8 @@ | |||
| 32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
| 33 | #include <linux/string.h> | 33 | #include <linux/string.h> |
| 34 | #include <linux/usb.h> | 34 | #include <linux/usb.h> |
| 35 | #include <linux/usb/audio.h> | ||
| 36 | |||
| 35 | #include <sound/core.h> | 37 | #include <sound/core.h> |
| 36 | #include <sound/control.h> | 38 | #include <sound/control.h> |
| 37 | #include <sound/hwdep.h> | 39 | #include <sound/hwdep.h> |
| @@ -69,13 +71,16 @@ static const struct rc_config { | |||
| 69 | { USB_ID(0x041e, 0x3048), 2, 2, 6, 6, 2, 0x6e91 }, /* Toshiba SB0500 */ | 71 | { USB_ID(0x041e, 0x3048), 2, 2, 6, 6, 2, 0x6e91 }, /* Toshiba SB0500 */ |
| 70 | }; | 72 | }; |
| 71 | 73 | ||
| 74 | #define MAX_ID_ELEMS 256 | ||
| 75 | |||
| 72 | struct usb_mixer_interface { | 76 | struct usb_mixer_interface { |
| 73 | struct snd_usb_audio *chip; | 77 | struct snd_usb_audio *chip; |
| 74 | unsigned int ctrlif; | 78 | unsigned int ctrlif; |
| 75 | struct list_head list; | 79 | struct list_head list; |
| 76 | unsigned int ignore_ctl_error; | 80 | unsigned int ignore_ctl_error; |
| 77 | struct urb *urb; | 81 | struct urb *urb; |
| 78 | struct usb_mixer_elem_info **id_elems; /* array[256], indexed by unit id */ | 82 | /* array[MAX_ID_ELEMS], indexed by unit id */ |
| 83 | struct usb_mixer_elem_info **id_elems; | ||
| 79 | 84 | ||
| 80 | /* Sound Blaster remote control stuff */ | 85 | /* Sound Blaster remote control stuff */ |
| 81 | const struct rc_config *rc_cfg; | 86 | const struct rc_config *rc_cfg; |
| @@ -105,7 +110,7 @@ struct mixer_build { | |||
| 105 | struct usb_mixer_interface *mixer; | 110 | struct usb_mixer_interface *mixer; |
| 106 | unsigned char *buffer; | 111 | unsigned char *buffer; |
| 107 | unsigned int buflen; | 112 | unsigned int buflen; |
| 108 | DECLARE_BITMAP(unitbitmap, 256); | 113 | DECLARE_BITMAP(unitbitmap, MAX_ID_ELEMS); |
| 109 | struct usb_audio_term oterm; | 114 | struct usb_audio_term oterm; |
| 110 | const struct usbmix_name_map *map; | 115 | const struct usbmix_name_map *map; |
| 111 | const struct usbmix_selector_map *selector_map; | 116 | const struct usbmix_selector_map *selector_map; |
| @@ -123,6 +128,7 @@ struct usb_mixer_elem_info { | |||
| 123 | int channels; | 128 | int channels; |
| 124 | int val_type; | 129 | int val_type; |
| 125 | int min, max, res; | 130 | int min, max, res; |
| 131 | int dBmin, dBmax; | ||
| 126 | int cached; | 132 | int cached; |
| 127 | int cache_val[MAX_CHANNELS]; | 133 | int cache_val[MAX_CHANNELS]; |
| 128 | u8 initialized; | 134 | u8 initialized; |
| @@ -186,6 +192,21 @@ enum { | |||
| 186 | USB_PROC_DCR_RELEASE = 6, | 192 | USB_PROC_DCR_RELEASE = 6, |
| 187 | }; | 193 | }; |
| 188 | 194 | ||
| 195 | /*E-mu 0202(0404) eXtension Unit(XU) control*/ | ||
| 196 | enum { | ||
| 197 | USB_XU_CLOCK_RATE = 0xe301, | ||
| 198 | USB_XU_CLOCK_SOURCE = 0xe302, | ||
| 199 | USB_XU_DIGITAL_IO_STATUS = 0xe303, | ||
| 200 | USB_XU_DEVICE_OPTIONS = 0xe304, | ||
| 201 | USB_XU_DIRECT_MONITORING = 0xe305, | ||
| 202 | USB_XU_METERING = 0xe306 | ||
| 203 | }; | ||
| 204 | enum { | ||
| 205 | USB_XU_CLOCK_SOURCE_SELECTOR = 0x02, /* clock source*/ | ||
| 206 | USB_XU_CLOCK_RATE_SELECTOR = 0x03, /* clock rate */ | ||
| 207 | USB_XU_DIGITAL_FORMAT_SELECTOR = 0x01, /* the spdif format */ | ||
| 208 | USB_XU_SOFT_LIMIT_SELECTOR = 0x03 /* soft limiter */ | ||
| 209 | }; | ||
| 189 | 210 | ||
| 190 | /* | 211 | /* |
| 191 | * manual mapping of mixer names | 212 | * manual mapping of mixer names |
| @@ -194,42 +215,50 @@ enum { | |||
| 194 | */ | 215 | */ |
| 195 | #include "usbmixer_maps.c" | 216 | #include "usbmixer_maps.c" |
| 196 | 217 | ||
| 197 | /* get the mapped name if the unit matches */ | 218 | static const struct usbmix_name_map * |
| 198 | static int check_mapped_name(struct mixer_build *state, int unitid, int control, char *buf, int buflen) | 219 | find_map(struct mixer_build *state, int unitid, int control) |
| 199 | { | 220 | { |
| 200 | const struct usbmix_name_map *p; | 221 | const struct usbmix_name_map *p = state->map; |
| 201 | 222 | ||
| 202 | if (! state->map) | 223 | if (!p) |
| 203 | return 0; | 224 | return NULL; |
| 204 | 225 | ||
| 205 | for (p = state->map; p->id; p++) { | 226 | for (p = state->map; p->id; p++) { |
| 206 | if (p->id == unitid && p->name && | 227 | if (p->id == unitid && |
| 207 | (! control || ! p->control || control == p->control)) { | 228 | (!control || !p->control || control == p->control)) |
| 208 | buflen--; | 229 | return p; |
| 209 | return strlcpy(buf, p->name, buflen); | ||
| 210 | } | ||
| 211 | } | 230 | } |
| 212 | return 0; | 231 | return NULL; |
| 213 | } | 232 | } |
| 214 | 233 | ||
| 215 | /* check whether the control should be ignored */ | 234 | /* get the mapped name if the unit matches */ |
| 216 | static int check_ignored_ctl(struct mixer_build *state, int unitid, int control) | 235 | static int |
| 236 | check_mapped_name(const struct usbmix_name_map *p, char *buf, int buflen) | ||
| 217 | { | 237 | { |
| 218 | const struct usbmix_name_map *p; | 238 | if (!p || !p->name) |
| 239 | return 0; | ||
| 240 | |||
| 241 | buflen--; | ||
| 242 | return strlcpy(buf, p->name, buflen); | ||
| 243 | } | ||
| 219 | 244 | ||
| 220 | if (! state->map) | 245 | /* check whether the control should be ignored */ |
| 246 | static inline int | ||
| 247 | check_ignored_ctl(const struct usbmix_name_map *p) | ||
| 248 | { | ||
| 249 | if (!p || p->name || p->dB) | ||
| 221 | return 0; | 250 | return 0; |
| 222 | for (p = state->map; p->id; p++) { | 251 | return 1; |
| 223 | if (p->id == unitid && ! p->name && | 252 | } |
| 224 | (! control || ! p->control || control == p->control)) { | 253 | |
| 225 | /* | 254 | /* dB mapping */ |
| 226 | printk(KERN_DEBUG "ignored control %d:%d\n", | 255 | static inline void check_mapped_dB(const struct usbmix_name_map *p, |
| 227 | unitid, control); | 256 | struct usb_mixer_elem_info *cval) |
| 228 | */ | 257 | { |
| 229 | return 1; | 258 | if (p && p->dB) { |
| 230 | } | 259 | cval->dBmin = p->dB->min; |
| 260 | cval->dBmax = p->dB->max; | ||
| 231 | } | 261 | } |
| 232 | return 0; | ||
| 233 | } | 262 | } |
| 234 | 263 | ||
| 235 | /* get the mapped selector source name */ | 264 | /* get the mapped selector source name */ |
| @@ -257,7 +286,7 @@ static void *find_audio_control_unit(struct mixer_build *state, unsigned char un | |||
| 257 | p = NULL; | 286 | p = NULL; |
| 258 | while ((p = snd_usb_find_desc(state->buffer, state->buflen, p, | 287 | while ((p = snd_usb_find_desc(state->buffer, state->buflen, p, |
| 259 | USB_DT_CS_INTERFACE)) != NULL) { | 288 | USB_DT_CS_INTERFACE)) != NULL) { |
| 260 | if (p[0] >= 4 && p[2] >= INPUT_TERMINAL && p[2] <= EXTENSION_UNIT && p[3] == unit) | 289 | if (p[0] >= 4 && p[2] >= UAC_INPUT_TERMINAL && p[2] <= UAC_EXTENSION_UNIT_V1 && p[3] == unit) |
| 261 | return p; | 290 | return p; |
| 262 | } | 291 | } |
| 263 | return NULL; | 292 | return NULL; |
| @@ -378,14 +407,14 @@ static int get_ctl_value(struct usb_mixer_elem_info *cval, int request, int vali | |||
| 378 | 407 | ||
| 379 | static int get_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int *value) | 408 | static int get_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int *value) |
| 380 | { | 409 | { |
| 381 | return get_ctl_value(cval, GET_CUR, validx, value); | 410 | return get_ctl_value(cval, UAC_GET_CUR, validx, value); |
| 382 | } | 411 | } |
| 383 | 412 | ||
| 384 | /* channel = 0: master, 1 = first channel */ | 413 | /* channel = 0: master, 1 = first channel */ |
| 385 | static inline int get_cur_mix_raw(struct usb_mixer_elem_info *cval, | 414 | static inline int get_cur_mix_raw(struct usb_mixer_elem_info *cval, |
| 386 | int channel, int *value) | 415 | int channel, int *value) |
| 387 | { | 416 | { |
| 388 | return get_ctl_value(cval, GET_CUR, (cval->control << 8) | channel, value); | 417 | return get_ctl_value(cval, UAC_GET_CUR, (cval->control << 8) | channel, value); |
| 389 | } | 418 | } |
| 390 | 419 | ||
| 391 | static int get_cur_mix_value(struct usb_mixer_elem_info *cval, | 420 | static int get_cur_mix_value(struct usb_mixer_elem_info *cval, |
| @@ -439,14 +468,14 @@ static int set_ctl_value(struct usb_mixer_elem_info *cval, int request, int vali | |||
| 439 | 468 | ||
| 440 | static int set_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int value) | 469 | static int set_cur_ctl_value(struct usb_mixer_elem_info *cval, int validx, int value) |
| 441 | { | 470 | { |
| 442 | return set_ctl_value(cval, SET_CUR, validx, value); | 471 | return set_ctl_value(cval, UAC_SET_CUR, validx, value); |
| 443 | } | 472 | } |
| 444 | 473 | ||
| 445 | static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, | 474 | static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, |
| 446 | int index, int value) | 475 | int index, int value) |
| 447 | { | 476 | { |
| 448 | int err; | 477 | int err; |
| 449 | err = set_ctl_value(cval, SET_CUR, (cval->control << 8) | channel, | 478 | err = set_ctl_value(cval, UAC_SET_CUR, (cval->control << 8) | channel, |
| 450 | value); | 479 | value); |
| 451 | if (err < 0) | 480 | if (err < 0) |
| 452 | return err; | 481 | return err; |
| @@ -466,20 +495,8 @@ static int mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag, | |||
| 466 | 495 | ||
| 467 | if (size < sizeof(scale)) | 496 | if (size < sizeof(scale)) |
| 468 | return -ENOMEM; | 497 | return -ENOMEM; |
| 469 | /* USB descriptions contain the dB scale in 1/256 dB unit | 498 | scale[2] = cval->dBmin; |
| 470 | * while ALSA TLV contains in 1/100 dB unit | 499 | scale[3] = cval->dBmax; |
| 471 | */ | ||
| 472 | scale[2] = (convert_signed_value(cval, cval->min) * 100) / 256; | ||
| 473 | scale[3] = (convert_signed_value(cval, cval->max) * 100) / 256; | ||
| 474 | if (scale[3] <= scale[2]) { | ||
| 475 | /* something is wrong; assume it's either from/to 0dB */ | ||
| 476 | if (scale[2] < 0) | ||
| 477 | scale[3] = 0; | ||
| 478 | else if (scale[2] > 0) | ||
| 479 | scale[2] = 0; | ||
| 480 | else /* totally crap, return an error */ | ||
| 481 | return -EINVAL; | ||
| 482 | } | ||
| 483 | if (copy_to_user(_tlv, scale, sizeof(scale))) | 500 | if (copy_to_user(_tlv, scale, sizeof(scale))) |
| 484 | return -EFAULT; | 501 | return -EFAULT; |
| 485 | return 0; | 502 | return 0; |
| @@ -588,13 +605,13 @@ static int get_term_name(struct mixer_build *state, struct usb_audio_term *iterm | |||
| 588 | if (term_only) | 605 | if (term_only) |
| 589 | return 0; | 606 | return 0; |
| 590 | switch (iterm->type >> 16) { | 607 | switch (iterm->type >> 16) { |
| 591 | case SELECTOR_UNIT: | 608 | case UAC_SELECTOR_UNIT: |
| 592 | strcpy(name, "Selector"); return 8; | 609 | strcpy(name, "Selector"); return 8; |
| 593 | case PROCESSING_UNIT: | 610 | case UAC_PROCESSING_UNIT_V1: |
| 594 | strcpy(name, "Process Unit"); return 12; | 611 | strcpy(name, "Process Unit"); return 12; |
| 595 | case EXTENSION_UNIT: | 612 | case UAC_EXTENSION_UNIT_V1: |
| 596 | strcpy(name, "Ext Unit"); return 8; | 613 | strcpy(name, "Ext Unit"); return 8; |
| 597 | case MIXER_UNIT: | 614 | case UAC_MIXER_UNIT: |
| 598 | strcpy(name, "Mixer"); return 5; | 615 | strcpy(name, "Mixer"); return 5; |
| 599 | default: | 616 | default: |
| 600 | return sprintf(name, "Unit %d", iterm->id); | 617 | return sprintf(name, "Unit %d", iterm->id); |
| @@ -633,22 +650,22 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_ | |||
| 633 | while ((p1 = find_audio_control_unit(state, id)) != NULL) { | 650 | while ((p1 = find_audio_control_unit(state, id)) != NULL) { |
| 634 | term->id = id; | 651 | term->id = id; |
| 635 | switch (p1[2]) { | 652 | switch (p1[2]) { |
| 636 | case INPUT_TERMINAL: | 653 | case UAC_INPUT_TERMINAL: |
| 637 | term->type = combine_word(p1 + 4); | 654 | term->type = combine_word(p1 + 4); |
| 638 | term->channels = p1[7]; | 655 | term->channels = p1[7]; |
| 639 | term->chconfig = combine_word(p1 + 8); | 656 | term->chconfig = combine_word(p1 + 8); |
| 640 | term->name = p1[11]; | 657 | term->name = p1[11]; |
| 641 | return 0; | 658 | return 0; |
| 642 | case FEATURE_UNIT: | 659 | case UAC_FEATURE_UNIT: |
| 643 | id = p1[4]; | 660 | id = p1[4]; |
| 644 | break; /* continue to parse */ | 661 | break; /* continue to parse */ |
| 645 | case MIXER_UNIT: | 662 | case UAC_MIXER_UNIT: |
| 646 | term->type = p1[2] << 16; /* virtual type */ | 663 | term->type = p1[2] << 16; /* virtual type */ |
| 647 | term->channels = p1[5 + p1[4]]; | 664 | term->channels = p1[5 + p1[4]]; |
| 648 | term->chconfig = combine_word(p1 + 6 + p1[4]); | 665 | term->chconfig = combine_word(p1 + 6 + p1[4]); |
| 649 | term->name = p1[p1[0] - 1]; | 666 | term->name = p1[p1[0] - 1]; |
| 650 | return 0; | 667 | return 0; |
| 651 | case SELECTOR_UNIT: | 668 | case UAC_SELECTOR_UNIT: |
| 652 | /* call recursively to retrieve the channel info */ | 669 | /* call recursively to retrieve the channel info */ |
| 653 | if (check_input_term(state, p1[5], term) < 0) | 670 | if (check_input_term(state, p1[5], term) < 0) |
| 654 | return -ENODEV; | 671 | return -ENODEV; |
| @@ -656,8 +673,8 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_ | |||
| 656 | term->id = id; | 673 | term->id = id; |
| 657 | term->name = p1[9 + p1[0] - 1]; | 674 | term->name = p1[9 + p1[0] - 1]; |
| 658 | return 0; | 675 | return 0; |
| 659 | case PROCESSING_UNIT: | 676 | case UAC_PROCESSING_UNIT_V1: |
| 660 | case EXTENSION_UNIT: | 677 | case UAC_EXTENSION_UNIT_V1: |
| 661 | if (p1[6] == 1) { | 678 | if (p1[6] == 1) { |
| 662 | id = p1[7]; | 679 | id = p1[7]; |
| 663 | break; /* continue to parse */ | 680 | break; /* continue to parse */ |
| @@ -720,6 +737,7 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) | |||
| 720 | cval->min = default_min; | 737 | cval->min = default_min; |
| 721 | cval->max = cval->min + 1; | 738 | cval->max = cval->min + 1; |
| 722 | cval->res = 1; | 739 | cval->res = 1; |
| 740 | cval->dBmin = cval->dBmax = 0; | ||
| 723 | 741 | ||
| 724 | if (cval->val_type == USB_MIXER_BOOLEAN || | 742 | if (cval->val_type == USB_MIXER_BOOLEAN || |
| 725 | cval->val_type == USB_MIXER_INV_BOOLEAN) { | 743 | cval->val_type == USB_MIXER_INV_BOOLEAN) { |
| @@ -734,23 +752,23 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) | |||
| 734 | break; | 752 | break; |
| 735 | } | 753 | } |
| 736 | } | 754 | } |
| 737 | if (get_ctl_value(cval, GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 || | 755 | if (get_ctl_value(cval, UAC_GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 || |
| 738 | get_ctl_value(cval, GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) { | 756 | get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) { |
| 739 | snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n", | 757 | snd_printd(KERN_ERR "%d:%d: cannot get min/max values for control %d (id %d)\n", |
| 740 | cval->id, cval->mixer->ctrlif, cval->control, cval->id); | 758 | cval->id, cval->mixer->ctrlif, cval->control, cval->id); |
| 741 | return -EINVAL; | 759 | return -EINVAL; |
| 742 | } | 760 | } |
| 743 | if (get_ctl_value(cval, GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) { | 761 | if (get_ctl_value(cval, UAC_GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) { |
| 744 | cval->res = 1; | 762 | cval->res = 1; |
| 745 | } else { | 763 | } else { |
| 746 | int last_valid_res = cval->res; | 764 | int last_valid_res = cval->res; |
| 747 | 765 | ||
| 748 | while (cval->res > 1) { | 766 | while (cval->res > 1) { |
| 749 | if (set_ctl_value(cval, SET_RES, (cval->control << 8) | minchn, cval->res / 2) < 0) | 767 | if (set_ctl_value(cval, UAC_SET_RES, (cval->control << 8) | minchn, cval->res / 2) < 0) |
| 750 | break; | 768 | break; |
| 751 | cval->res /= 2; | 769 | cval->res /= 2; |
| 752 | } | 770 | } |
| 753 | if (get_ctl_value(cval, GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) | 771 | if (get_ctl_value(cval, UAC_GET_RES, (cval->control << 8) | minchn, &cval->res) < 0) |
| 754 | cval->res = last_valid_res; | 772 | cval->res = last_valid_res; |
| 755 | } | 773 | } |
| 756 | if (cval->res == 0) | 774 | if (cval->res == 0) |
| @@ -787,6 +805,24 @@ static int get_min_max(struct usb_mixer_elem_info *cval, int default_min) | |||
| 787 | 805 | ||
| 788 | cval->initialized = 1; | 806 | cval->initialized = 1; |
| 789 | } | 807 | } |
| 808 | |||
| 809 | /* USB descriptions contain the dB scale in 1/256 dB unit | ||
| 810 | * while ALSA TLV contains in 1/100 dB unit | ||
| 811 | */ | ||
| 812 | cval->dBmin = (convert_signed_value(cval, cval->min) * 100) / 256; | ||
| 813 | cval->dBmax = (convert_signed_value(cval, cval->max) * 100) / 256; | ||
| 814 | if (cval->dBmin > cval->dBmax) { | ||
| 815 | /* something is wrong; assume it's either from/to 0dB */ | ||
| 816 | if (cval->dBmin < 0) | ||
| 817 | cval->dBmax = 0; | ||
| 818 | else if (cval->dBmin > 0) | ||
| 819 | cval->dBmin = 0; | ||
| 820 | if (cval->dBmin > cval->dBmax) { | ||
| 821 | /* totally crap, return an error */ | ||
| 822 | return -EINVAL; | ||
| 823 | } | ||
| 824 | } | ||
| 825 | |||
| 790 | return 0; | 826 | return 0; |
| 791 | } | 827 | } |
| 792 | 828 | ||
| @@ -912,6 +948,7 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, | |||
| 912 | int nameid = desc[desc[0] - 1]; | 948 | int nameid = desc[desc[0] - 1]; |
| 913 | struct snd_kcontrol *kctl; | 949 | struct snd_kcontrol *kctl; |
| 914 | struct usb_mixer_elem_info *cval; | 950 | struct usb_mixer_elem_info *cval; |
| 951 | const struct usbmix_name_map *map; | ||
| 915 | 952 | ||
| 916 | control++; /* change from zero-based to 1-based value */ | 953 | control++; /* change from zero-based to 1-based value */ |
| 917 | 954 | ||
| @@ -920,7 +957,8 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, | |||
| 920 | return; | 957 | return; |
| 921 | } | 958 | } |
| 922 | 959 | ||
| 923 | if (check_ignored_ctl(state, unitid, control)) | 960 | map = find_map(state, unitid, control); |
| 961 | if (check_ignored_ctl(map)) | ||
| 924 | return; | 962 | return; |
| 925 | 963 | ||
| 926 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); | 964 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); |
| @@ -954,10 +992,11 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, | |||
| 954 | } | 992 | } |
| 955 | kctl->private_free = usb_mixer_elem_free; | 993 | kctl->private_free = usb_mixer_elem_free; |
| 956 | 994 | ||
| 957 | len = check_mapped_name(state, unitid, control, kctl->id.name, sizeof(kctl->id.name)); | 995 | len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); |
| 958 | mapped_name = len != 0; | 996 | mapped_name = len != 0; |
| 959 | if (! len && nameid) | 997 | if (! len && nameid) |
| 960 | len = snd_usb_copy_string_desc(state, nameid, kctl->id.name, sizeof(kctl->id.name)); | 998 | len = snd_usb_copy_string_desc(state, nameid, |
| 999 | kctl->id.name, sizeof(kctl->id.name)); | ||
| 961 | 1000 | ||
| 962 | switch (control) { | 1001 | switch (control) { |
| 963 | case USB_FEATURE_MUTE: | 1002 | case USB_FEATURE_MUTE: |
| @@ -995,6 +1034,7 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, | |||
| 995 | kctl->vd[0].access |= | 1034 | kctl->vd[0].access |= |
| 996 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | | 1035 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | |
| 997 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; | 1036 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; |
| 1037 | check_mapped_dB(map, cval); | ||
| 998 | } | 1038 | } |
| 999 | break; | 1039 | break; |
| 1000 | 1040 | ||
| @@ -1048,29 +1088,30 @@ static void build_feature_ctl(struct mixer_build *state, unsigned char *desc, | |||
| 1048 | * | 1088 | * |
| 1049 | * most of controlls are defined here. | 1089 | * most of controlls are defined here. |
| 1050 | */ | 1090 | */ |
| 1051 | static int parse_audio_feature_unit(struct mixer_build *state, int unitid, unsigned char *ftr) | 1091 | static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void *_ftr) |
| 1052 | { | 1092 | { |
| 1053 | int channels, i, j; | 1093 | int channels, i, j; |
| 1054 | struct usb_audio_term iterm; | 1094 | struct usb_audio_term iterm; |
| 1055 | unsigned int master_bits, first_ch_bits; | 1095 | unsigned int master_bits, first_ch_bits; |
| 1056 | int err, csize; | 1096 | int err, csize; |
| 1097 | struct uac_feature_unit_descriptor *ftr = _ftr; | ||
| 1057 | 1098 | ||
| 1058 | if (ftr[0] < 7 || ! (csize = ftr[5]) || ftr[0] < 7 + csize) { | 1099 | if (ftr->bLength < 7 || ! (csize = ftr->bControlSize) || ftr->bLength < 7 + csize) { |
| 1059 | snd_printk(KERN_ERR "usbaudio: unit %u: invalid FEATURE_UNIT descriptor\n", unitid); | 1100 | snd_printk(KERN_ERR "usbaudio: unit %u: invalid UAC_FEATURE_UNIT descriptor\n", unitid); |
| 1060 | return -EINVAL; | 1101 | return -EINVAL; |
| 1061 | } | 1102 | } |
| 1062 | 1103 | ||
| 1063 | /* parse the source unit */ | 1104 | /* parse the source unit */ |
| 1064 | if ((err = parse_audio_unit(state, ftr[4])) < 0) | 1105 | if ((err = parse_audio_unit(state, ftr->bSourceID)) < 0) |
| 1065 | return err; | 1106 | return err; |
| 1066 | 1107 | ||
| 1067 | /* determine the input source type and name */ | 1108 | /* determine the input source type and name */ |
| 1068 | if (check_input_term(state, ftr[4], &iterm) < 0) | 1109 | if (check_input_term(state, ftr->bSourceID, &iterm) < 0) |
| 1069 | return -EINVAL; | 1110 | return -EINVAL; |
| 1070 | 1111 | ||
| 1071 | channels = (ftr[0] - 7) / csize - 1; | 1112 | channels = (ftr->bLength - 7) / csize - 1; |
| 1072 | 1113 | ||
| 1073 | master_bits = snd_usb_combine_bytes(ftr + 6, csize); | 1114 | master_bits = snd_usb_combine_bytes(ftr->controls, csize); |
| 1074 | /* master configuration quirks */ | 1115 | /* master configuration quirks */ |
| 1075 | switch (state->chip->usb_id) { | 1116 | switch (state->chip->usb_id) { |
| 1076 | case USB_ID(0x08bb, 0x2702): | 1117 | case USB_ID(0x08bb, 0x2702): |
| @@ -1081,21 +1122,21 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, unsig | |||
| 1081 | break; | 1122 | break; |
| 1082 | } | 1123 | } |
| 1083 | if (channels > 0) | 1124 | if (channels > 0) |
| 1084 | first_ch_bits = snd_usb_combine_bytes(ftr + 6 + csize, csize); | 1125 | first_ch_bits = snd_usb_combine_bytes(ftr->controls + csize, csize); |
| 1085 | else | 1126 | else |
| 1086 | first_ch_bits = 0; | 1127 | first_ch_bits = 0; |
| 1087 | /* check all control types */ | 1128 | /* check all control types */ |
| 1088 | for (i = 0; i < 10; i++) { | 1129 | for (i = 0; i < 10; i++) { |
| 1089 | unsigned int ch_bits = 0; | 1130 | unsigned int ch_bits = 0; |
| 1090 | for (j = 0; j < channels; j++) { | 1131 | for (j = 0; j < channels; j++) { |
| 1091 | unsigned int mask = snd_usb_combine_bytes(ftr + 6 + csize * (j+1), csize); | 1132 | unsigned int mask = snd_usb_combine_bytes(ftr->controls + csize * (j+1), csize); |
| 1092 | if (mask & (1 << i)) | 1133 | if (mask & (1 << i)) |
| 1093 | ch_bits |= (1 << j); | 1134 | ch_bits |= (1 << j); |
| 1094 | } | 1135 | } |
| 1095 | if (ch_bits & 1) /* the first channel must be set (for ease of programming) */ | 1136 | if (ch_bits & 1) /* the first channel must be set (for ease of programming) */ |
| 1096 | build_feature_ctl(state, ftr, ch_bits, i, &iterm, unitid); | 1137 | build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid); |
| 1097 | if (master_bits & (1 << i)) | 1138 | if (master_bits & (1 << i)) |
| 1098 | build_feature_ctl(state, ftr, 0, i, &iterm, unitid); | 1139 | build_feature_ctl(state, _ftr, 0, i, &iterm, unitid); |
| 1099 | } | 1140 | } |
| 1100 | 1141 | ||
| 1101 | return 0; | 1142 | return 0; |
| @@ -1122,8 +1163,10 @@ static void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc, | |||
| 1122 | unsigned int num_outs = desc[5 + input_pins]; | 1163 | unsigned int num_outs = desc[5 + input_pins]; |
| 1123 | unsigned int i, len; | 1164 | unsigned int i, len; |
| 1124 | struct snd_kcontrol *kctl; | 1165 | struct snd_kcontrol *kctl; |
| 1166 | const struct usbmix_name_map *map; | ||
| 1125 | 1167 | ||
| 1126 | if (check_ignored_ctl(state, unitid, 0)) | 1168 | map = find_map(state, unitid, 0); |
| 1169 | if (check_ignored_ctl(map)) | ||
| 1127 | return; | 1170 | return; |
| 1128 | 1171 | ||
| 1129 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); | 1172 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); |
| @@ -1152,7 +1195,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state, unsigned char *desc, | |||
| 1152 | } | 1195 | } |
| 1153 | kctl->private_free = usb_mixer_elem_free; | 1196 | kctl->private_free = usb_mixer_elem_free; |
| 1154 | 1197 | ||
| 1155 | len = check_mapped_name(state, unitid, 0, kctl->id.name, sizeof(kctl->id.name)); | 1198 | len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); |
| 1156 | if (! len) | 1199 | if (! len) |
| 1157 | len = get_term_name(state, iterm, kctl->id.name, sizeof(kctl->id.name), 0); | 1200 | len = get_term_name(state, iterm, kctl->id.name, sizeof(kctl->id.name), 0); |
| 1158 | if (! len) | 1201 | if (! len) |
| @@ -1330,7 +1373,32 @@ static struct procunit_info procunits[] = { | |||
| 1330 | { USB_PROC_DCR, "DCR", dcr_proc_info }, | 1373 | { USB_PROC_DCR, "DCR", dcr_proc_info }, |
| 1331 | { 0 }, | 1374 | { 0 }, |
| 1332 | }; | 1375 | }; |
| 1333 | 1376 | /* | |
| 1377 | * predefined data for extension units | ||
| 1378 | */ | ||
| 1379 | static struct procunit_value_info clock_rate_xu_info[] = { | ||
| 1380 | { USB_XU_CLOCK_RATE_SELECTOR, "Selector", USB_MIXER_U8, 0 }, | ||
| 1381 | { 0 } | ||
| 1382 | }; | ||
| 1383 | static struct procunit_value_info clock_source_xu_info[] = { | ||
| 1384 | { USB_XU_CLOCK_SOURCE_SELECTOR, "External", USB_MIXER_BOOLEAN }, | ||
| 1385 | { 0 } | ||
| 1386 | }; | ||
| 1387 | static struct procunit_value_info spdif_format_xu_info[] = { | ||
| 1388 | { USB_XU_DIGITAL_FORMAT_SELECTOR, "SPDIF/AC3", USB_MIXER_BOOLEAN }, | ||
| 1389 | { 0 } | ||
| 1390 | }; | ||
| 1391 | static struct procunit_value_info soft_limit_xu_info[] = { | ||
| 1392 | { USB_XU_SOFT_LIMIT_SELECTOR, " ", USB_MIXER_BOOLEAN }, | ||
| 1393 | { 0 } | ||
| 1394 | }; | ||
| 1395 | static struct procunit_info extunits[] = { | ||
| 1396 | { USB_XU_CLOCK_RATE, "Clock rate", clock_rate_xu_info }, | ||
| 1397 | { USB_XU_CLOCK_SOURCE, "DigitalIn CLK source", clock_source_xu_info }, | ||
| 1398 | { USB_XU_DIGITAL_IO_STATUS, "DigitalOut format:", spdif_format_xu_info }, | ||
| 1399 | { USB_XU_DEVICE_OPTIONS, "AnalogueIn Soft Limit", soft_limit_xu_info }, | ||
| 1400 | { 0 } | ||
| 1401 | }; | ||
| 1334 | /* | 1402 | /* |
| 1335 | * build a processing/extension unit | 1403 | * build a processing/extension unit |
| 1336 | */ | 1404 | */ |
| @@ -1342,6 +1410,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned | |||
| 1342 | int i, err, nameid, type, len; | 1410 | int i, err, nameid, type, len; |
| 1343 | struct procunit_info *info; | 1411 | struct procunit_info *info; |
| 1344 | struct procunit_value_info *valinfo; | 1412 | struct procunit_value_info *valinfo; |
| 1413 | const struct usbmix_name_map *map; | ||
| 1345 | static struct procunit_value_info default_value_info[] = { | 1414 | static struct procunit_value_info default_value_info[] = { |
| 1346 | { 0x01, "Switch", USB_MIXER_BOOLEAN }, | 1415 | { 0x01, "Switch", USB_MIXER_BOOLEAN }, |
| 1347 | { 0 } | 1416 | { 0 } |
| @@ -1371,7 +1440,8 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned | |||
| 1371 | /* FIXME: bitmap might be longer than 8bit */ | 1440 | /* FIXME: bitmap might be longer than 8bit */ |
| 1372 | if (! (dsc[12 + num_ins] & (1 << (valinfo->control - 1)))) | 1441 | if (! (dsc[12 + num_ins] & (1 << (valinfo->control - 1)))) |
| 1373 | continue; | 1442 | continue; |
| 1374 | if (check_ignored_ctl(state, unitid, valinfo->control)) | 1443 | map = find_map(state, unitid, valinfo->control); |
| 1444 | if (check_ignored_ctl(map)) | ||
| 1375 | continue; | 1445 | continue; |
| 1376 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); | 1446 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); |
| 1377 | if (! cval) { | 1447 | if (! cval) { |
| @@ -1391,8 +1461,18 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned | |||
| 1391 | cval->max = dsc[15]; | 1461 | cval->max = dsc[15]; |
| 1392 | cval->res = 1; | 1462 | cval->res = 1; |
| 1393 | cval->initialized = 1; | 1463 | cval->initialized = 1; |
| 1394 | } else | 1464 | } else { |
| 1395 | get_min_max(cval, valinfo->min_value); | 1465 | if (type == USB_XU_CLOCK_RATE) { |
| 1466 | /* E-Mu USB 0404/0202/TrackerPre | ||
| 1467 | * samplerate control quirk | ||
| 1468 | */ | ||
| 1469 | cval->min = 0; | ||
| 1470 | cval->max = 5; | ||
| 1471 | cval->res = 1; | ||
| 1472 | cval->initialized = 1; | ||
| 1473 | } else | ||
| 1474 | get_min_max(cval, valinfo->min_value); | ||
| 1475 | } | ||
| 1396 | 1476 | ||
| 1397 | kctl = snd_ctl_new1(&mixer_procunit_ctl, cval); | 1477 | kctl = snd_ctl_new1(&mixer_procunit_ctl, cval); |
| 1398 | if (! kctl) { | 1478 | if (! kctl) { |
| @@ -1402,8 +1482,9 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, unsigned | |||
| 1402 | } | 1482 | } |
| 1403 | kctl->private_free = usb_mixer_elem_free; | 1483 | kctl->private_free = usb_mixer_elem_free; |
| 1404 | 1484 | ||
| 1405 | if (check_mapped_name(state, unitid, cval->control, kctl->id.name, sizeof(kctl->id.name))) | 1485 | if (check_mapped_name(map, kctl->id.name, |
| 1406 | ; | 1486 | sizeof(kctl->id.name))) |
| 1487 | /* nothing */ ; | ||
| 1407 | else if (info->name) | 1488 | else if (info->name) |
| 1408 | strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name)); | 1489 | strlcpy(kctl->id.name, info->name, sizeof(kctl->id.name)); |
| 1409 | else { | 1490 | else { |
| @@ -1433,7 +1514,7 @@ static int parse_audio_processing_unit(struct mixer_build *state, int unitid, un | |||
| 1433 | 1514 | ||
| 1434 | static int parse_audio_extension_unit(struct mixer_build *state, int unitid, unsigned char *desc) | 1515 | static int parse_audio_extension_unit(struct mixer_build *state, int unitid, unsigned char *desc) |
| 1435 | { | 1516 | { |
| 1436 | return build_audio_procunit(state, unitid, desc, NULL, "Extension Unit"); | 1517 | return build_audio_procunit(state, unitid, desc, extunits, "Extension Unit"); |
| 1437 | } | 1518 | } |
| 1438 | 1519 | ||
| 1439 | 1520 | ||
| @@ -1542,6 +1623,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi | |||
| 1542 | int err; | 1623 | int err; |
| 1543 | struct usb_mixer_elem_info *cval; | 1624 | struct usb_mixer_elem_info *cval; |
| 1544 | struct snd_kcontrol *kctl; | 1625 | struct snd_kcontrol *kctl; |
| 1626 | const struct usbmix_name_map *map; | ||
| 1545 | char **namelist; | 1627 | char **namelist; |
| 1546 | 1628 | ||
| 1547 | if (! num_ins || desc[0] < 5 + num_ins) { | 1629 | if (! num_ins || desc[0] < 5 + num_ins) { |
| @@ -1557,7 +1639,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi | |||
| 1557 | if (num_ins == 1) /* only one ? nonsense! */ | 1639 | if (num_ins == 1) /* only one ? nonsense! */ |
| 1558 | return 0; | 1640 | return 0; |
| 1559 | 1641 | ||
| 1560 | if (check_ignored_ctl(state, unitid, 0)) | 1642 | map = find_map(state, unitid, 0); |
| 1643 | if (check_ignored_ctl(map)) | ||
| 1561 | return 0; | 1644 | return 0; |
| 1562 | 1645 | ||
| 1563 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); | 1646 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); |
| @@ -1612,7 +1695,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, unsi | |||
| 1612 | kctl->private_free = usb_mixer_selector_elem_free; | 1695 | kctl->private_free = usb_mixer_selector_elem_free; |
| 1613 | 1696 | ||
| 1614 | nameid = desc[desc[0] - 1]; | 1697 | nameid = desc[desc[0] - 1]; |
| 1615 | len = check_mapped_name(state, unitid, 0, kctl->id.name, sizeof(kctl->id.name)); | 1698 | len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); |
| 1616 | if (len) | 1699 | if (len) |
| 1617 | ; | 1700 | ; |
| 1618 | else if (nameid) | 1701 | else if (nameid) |
| @@ -1656,17 +1739,17 @@ static int parse_audio_unit(struct mixer_build *state, int unitid) | |||
| 1656 | } | 1739 | } |
| 1657 | 1740 | ||
| 1658 | switch (p1[2]) { | 1741 | switch (p1[2]) { |
| 1659 | case INPUT_TERMINAL: | 1742 | case UAC_INPUT_TERMINAL: |
| 1660 | return 0; /* NOP */ | 1743 | return 0; /* NOP */ |
| 1661 | case MIXER_UNIT: | 1744 | case UAC_MIXER_UNIT: |
| 1662 | return parse_audio_mixer_unit(state, unitid, p1); | 1745 | return parse_audio_mixer_unit(state, unitid, p1); |
| 1663 | case SELECTOR_UNIT: | 1746 | case UAC_SELECTOR_UNIT: |
| 1664 | return parse_audio_selector_unit(state, unitid, p1); | 1747 | return parse_audio_selector_unit(state, unitid, p1); |
| 1665 | case FEATURE_UNIT: | 1748 | case UAC_FEATURE_UNIT: |
| 1666 | return parse_audio_feature_unit(state, unitid, p1); | 1749 | return parse_audio_feature_unit(state, unitid, p1); |
| 1667 | case PROCESSING_UNIT: | 1750 | case UAC_PROCESSING_UNIT_V1: |
| 1668 | return parse_audio_processing_unit(state, unitid, p1); | 1751 | return parse_audio_processing_unit(state, unitid, p1); |
| 1669 | case EXTENSION_UNIT: | 1752 | case UAC_EXTENSION_UNIT_V1: |
| 1670 | return parse_audio_extension_unit(state, unitid, p1); | 1753 | return parse_audio_extension_unit(state, unitid, p1); |
| 1671 | default: | 1754 | default: |
| 1672 | snd_printk(KERN_ERR "usbaudio: unit %u: unexpected type 0x%02x\n", unitid, p1[2]); | 1755 | snd_printk(KERN_ERR "usbaudio: unit %u: unexpected type 0x%02x\n", unitid, p1[2]); |
| @@ -1696,11 +1779,11 @@ static int snd_usb_mixer_dev_free(struct snd_device *device) | |||
| 1696 | /* | 1779 | /* |
| 1697 | * create mixer controls | 1780 | * create mixer controls |
| 1698 | * | 1781 | * |
| 1699 | * walk through all OUTPUT_TERMINAL descriptors to search for mixers | 1782 | * walk through all UAC_OUTPUT_TERMINAL descriptors to search for mixers |
| 1700 | */ | 1783 | */ |
| 1701 | static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) | 1784 | static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) |
| 1702 | { | 1785 | { |
| 1703 | unsigned char *desc; | 1786 | struct uac_output_terminal_descriptor_v1 *desc; |
| 1704 | struct mixer_build state; | 1787 | struct mixer_build state; |
| 1705 | int err; | 1788 | int err; |
| 1706 | const struct usbmix_ctl_map *map; | 1789 | const struct usbmix_ctl_map *map; |
| @@ -1724,14 +1807,14 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) | |||
| 1724 | } | 1807 | } |
| 1725 | 1808 | ||
| 1726 | desc = NULL; | 1809 | desc = NULL; |
| 1727 | while ((desc = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, desc, OUTPUT_TERMINAL)) != NULL) { | 1810 | while ((desc = snd_usb_find_csint_desc(hostif->extra, hostif->extralen, desc, UAC_OUTPUT_TERMINAL)) != NULL) { |
| 1728 | if (desc[0] < 9) | 1811 | if (desc->bLength < 9) |
| 1729 | continue; /* invalid descriptor? */ | 1812 | continue; /* invalid descriptor? */ |
| 1730 | set_bit(desc[3], state.unitbitmap); /* mark terminal ID as visited */ | 1813 | set_bit(desc->bTerminalID, state.unitbitmap); /* mark terminal ID as visited */ |
| 1731 | state.oterm.id = desc[3]; | 1814 | state.oterm.id = desc->bTerminalID; |
| 1732 | state.oterm.type = combine_word(&desc[4]); | 1815 | state.oterm.type = le16_to_cpu(desc->wTerminalType); |
| 1733 | state.oterm.name = desc[8]; | 1816 | state.oterm.name = desc->iTerminal; |
| 1734 | err = parse_audio_unit(&state, desc[7]); | 1817 | err = parse_audio_unit(&state, desc->bSourceID); |
| 1735 | if (err < 0) | 1818 | if (err < 0) |
| 1736 | return err; | 1819 | return err; |
| 1737 | } | 1820 | } |
| @@ -1748,6 +1831,46 @@ static void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, | |||
| 1748 | info->elem_id); | 1831 | info->elem_id); |
| 1749 | } | 1832 | } |
| 1750 | 1833 | ||
| 1834 | static void snd_usb_mixer_dump_cval(struct snd_info_buffer *buffer, | ||
| 1835 | int unitid, | ||
| 1836 | struct usb_mixer_elem_info *cval) | ||
| 1837 | { | ||
| 1838 | static char *val_types[] = {"BOOLEAN", "INV_BOOLEAN", | ||
| 1839 | "S8", "U8", "S16", "U16"}; | ||
| 1840 | snd_iprintf(buffer, " Unit: %i\n", unitid); | ||
| 1841 | if (cval->elem_id) | ||
| 1842 | snd_iprintf(buffer, " Control: name=\"%s\", index=%i\n", | ||
| 1843 | cval->elem_id->name, cval->elem_id->index); | ||
| 1844 | snd_iprintf(buffer, " Info: id=%i, control=%i, cmask=0x%x, " | ||
| 1845 | "channels=%i, type=\"%s\"\n", cval->id, | ||
| 1846 | cval->control, cval->cmask, cval->channels, | ||
| 1847 | val_types[cval->val_type]); | ||
| 1848 | snd_iprintf(buffer, " Volume: min=%i, max=%i, dBmin=%i, dBmax=%i\n", | ||
| 1849 | cval->min, cval->max, cval->dBmin, cval->dBmax); | ||
| 1850 | } | ||
| 1851 | |||
| 1852 | static void snd_usb_mixer_proc_read(struct snd_info_entry *entry, | ||
| 1853 | struct snd_info_buffer *buffer) | ||
| 1854 | { | ||
| 1855 | struct snd_usb_audio *chip = entry->private_data; | ||
| 1856 | struct usb_mixer_interface *mixer; | ||
| 1857 | struct usb_mixer_elem_info *cval; | ||
| 1858 | int unitid; | ||
| 1859 | |||
| 1860 | list_for_each_entry(mixer, &chip->mixer_list, list) { | ||
| 1861 | snd_iprintf(buffer, | ||
| 1862 | "USB Mixer: usb_id=0x%08x, ctrlif=%i, ctlerr=%i\n", | ||
| 1863 | chip->usb_id, mixer->ctrlif, | ||
| 1864 | mixer->ignore_ctl_error); | ||
| 1865 | snd_iprintf(buffer, "Card: %s\n", chip->card->longname); | ||
| 1866 | for (unitid = 0; unitid < MAX_ID_ELEMS; unitid++) { | ||
| 1867 | for (cval = mixer->id_elems[unitid]; cval; | ||
| 1868 | cval = cval->next_id_elem) | ||
| 1869 | snd_usb_mixer_dump_cval(buffer, unitid, cval); | ||
| 1870 | } | ||
| 1871 | } | ||
| 1872 | } | ||
| 1873 | |||
| 1751 | static void snd_usb_mixer_memory_change(struct usb_mixer_interface *mixer, | 1874 | static void snd_usb_mixer_memory_change(struct usb_mixer_interface *mixer, |
| 1752 | int unitid) | 1875 | int unitid) |
| 1753 | { | 1876 | { |
| @@ -1924,7 +2047,7 @@ static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer) | |||
| 1924 | } | 2047 | } |
| 1925 | mixer->rc_setup_packet->bRequestType = | 2048 | mixer->rc_setup_packet->bRequestType = |
| 1926 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; | 2049 | USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE; |
| 1927 | mixer->rc_setup_packet->bRequest = GET_MEM; | 2050 | mixer->rc_setup_packet->bRequest = UAC_GET_MEM; |
| 1928 | mixer->rc_setup_packet->wValue = cpu_to_le16(0); | 2051 | mixer->rc_setup_packet->wValue = cpu_to_le16(0); |
| 1929 | mixer->rc_setup_packet->wIndex = cpu_to_le16(0); | 2052 | mixer->rc_setup_packet->wIndex = cpu_to_le16(0); |
| 1930 | mixer->rc_setup_packet->wLength = cpu_to_le16(len); | 2053 | mixer->rc_setup_packet->wLength = cpu_to_le16(len); |
| @@ -2047,7 +2170,7 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry, | |||
| 2047 | snd_iprintf(buffer, "%s: ", jacks[i].name); | 2170 | snd_iprintf(buffer, "%s: ", jacks[i].name); |
| 2048 | err = snd_usb_ctl_msg(mixer->chip->dev, | 2171 | err = snd_usb_ctl_msg(mixer->chip->dev, |
| 2049 | usb_rcvctrlpipe(mixer->chip->dev, 0), | 2172 | usb_rcvctrlpipe(mixer->chip->dev, 0), |
| 2050 | GET_MEM, USB_DIR_IN | USB_TYPE_CLASS | | 2173 | UAC_GET_MEM, USB_DIR_IN | USB_TYPE_CLASS | |
| 2051 | USB_RECIP_INTERFACE, 0, | 2174 | USB_RECIP_INTERFACE, 0, |
| 2052 | jacks[i].unitid << 8, buf, 3, 100); | 2175 | jacks[i].unitid << 8, buf, 3, 100); |
| 2053 | if (err == 3 && (buf[0] == 3 || buf[0] == 6)) | 2176 | if (err == 3 && (buf[0] == 3 || buf[0] == 6)) |
| @@ -2109,6 +2232,24 @@ static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer) | |||
| 2109 | return 0; | 2232 | return 0; |
| 2110 | } | 2233 | } |
| 2111 | 2234 | ||
| 2235 | void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, | ||
| 2236 | unsigned char samplerate_id) | ||
| 2237 | { | ||
| 2238 | struct usb_mixer_interface *mixer; | ||
| 2239 | struct usb_mixer_elem_info *cval; | ||
| 2240 | int unitid = 12; /* SamleRate ExtensionUnit ID */ | ||
| 2241 | |||
| 2242 | list_for_each_entry(mixer, &chip->mixer_list, list) { | ||
| 2243 | cval = mixer->id_elems[unitid]; | ||
| 2244 | if (cval) { | ||
| 2245 | set_cur_ctl_value(cval, cval->control << 8, | ||
| 2246 | samplerate_id); | ||
| 2247 | snd_usb_mixer_notify_id(mixer, unitid); | ||
| 2248 | } | ||
| 2249 | break; | ||
| 2250 | } | ||
| 2251 | } | ||
| 2252 | |||
| 2112 | int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, | 2253 | int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, |
| 2113 | int ignore_error) | 2254 | int ignore_error) |
| 2114 | { | 2255 | { |
| @@ -2116,7 +2257,9 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, | |||
| 2116 | .dev_free = snd_usb_mixer_dev_free | 2257 | .dev_free = snd_usb_mixer_dev_free |
| 2117 | }; | 2258 | }; |
| 2118 | struct usb_mixer_interface *mixer; | 2259 | struct usb_mixer_interface *mixer; |
| 2119 | int err; | 2260 | struct snd_info_entry *entry; |
| 2261 | struct usb_host_interface *host_iface; | ||
| 2262 | int err, protocol; | ||
| 2120 | 2263 | ||
| 2121 | strcpy(chip->card->mixername, "USB Mixer"); | 2264 | strcpy(chip->card->mixername, "USB Mixer"); |
| 2122 | 2265 | ||
| @@ -2126,12 +2269,23 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, | |||
| 2126 | mixer->chip = chip; | 2269 | mixer->chip = chip; |
| 2127 | mixer->ctrlif = ctrlif; | 2270 | mixer->ctrlif = ctrlif; |
| 2128 | mixer->ignore_ctl_error = ignore_error; | 2271 | mixer->ignore_ctl_error = ignore_error; |
| 2129 | mixer->id_elems = kcalloc(256, sizeof(*mixer->id_elems), GFP_KERNEL); | 2272 | mixer->id_elems = kcalloc(MAX_ID_ELEMS, sizeof(*mixer->id_elems), |
| 2273 | GFP_KERNEL); | ||
| 2130 | if (!mixer->id_elems) { | 2274 | if (!mixer->id_elems) { |
| 2131 | kfree(mixer); | 2275 | kfree(mixer); |
| 2132 | return -ENOMEM; | 2276 | return -ENOMEM; |
| 2133 | } | 2277 | } |
| 2134 | 2278 | ||
| 2279 | host_iface = &usb_ifnum_to_if(chip->dev, ctrlif)->altsetting[0]; | ||
| 2280 | protocol = host_iface->desc.bInterfaceProtocol; | ||
| 2281 | |||
| 2282 | /* FIXME! */ | ||
| 2283 | if (protocol != UAC_VERSION_1) { | ||
| 2284 | snd_printk(KERN_WARNING "mixer interface protocol 0x%02x not yet supported\n", | ||
| 2285 | protocol); | ||
| 2286 | return 0; | ||
| 2287 | } | ||
| 2288 | |||
| 2135 | if ((err = snd_usb_mixer_controls(mixer)) < 0 || | 2289 | if ((err = snd_usb_mixer_controls(mixer)) < 0 || |
| 2136 | (err = snd_usb_mixer_status_create(mixer)) < 0) | 2290 | (err = snd_usb_mixer_status_create(mixer)) < 0) |
| 2137 | goto _error; | 2291 | goto _error; |
| @@ -2142,8 +2296,6 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, | |||
| 2142 | if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020) || | 2296 | if (mixer->chip->usb_id == USB_ID(0x041e, 0x3020) || |
| 2143 | mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || | 2297 | mixer->chip->usb_id == USB_ID(0x041e, 0x3040) || |
| 2144 | mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) { | 2298 | mixer->chip->usb_id == USB_ID(0x041e, 0x3048)) { |
| 2145 | struct snd_info_entry *entry; | ||
| 2146 | |||
| 2147 | if ((err = snd_audigy2nx_controls_create(mixer)) < 0) | 2299 | if ((err = snd_audigy2nx_controls_create(mixer)) < 0) |
| 2148 | goto _error; | 2300 | goto _error; |
| 2149 | if (!snd_card_proc_new(chip->card, "audigy2nx", &entry)) | 2301 | if (!snd_card_proc_new(chip->card, "audigy2nx", &entry)) |
| @@ -2161,6 +2313,11 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, | |||
| 2161 | err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops); | 2313 | err = snd_device_new(chip->card, SNDRV_DEV_LOWLEVEL, mixer, &dev_ops); |
| 2162 | if (err < 0) | 2314 | if (err < 0) |
| 2163 | goto _error; | 2315 | goto _error; |
| 2316 | |||
| 2317 | if (list_empty(&chip->mixer_list) && | ||
| 2318 | !snd_card_proc_new(chip->card, "usbmixer", &entry)) | ||
| 2319 | snd_info_set_text_ops(entry, chip, snd_usb_mixer_proc_read); | ||
| 2320 | |||
| 2164 | list_add(&mixer->list, &chip->mixer_list); | 2321 | list_add(&mixer->list, &chip->mixer_list); |
| 2165 | return 0; | 2322 | return 0; |
| 2166 | 2323 | ||
diff --git a/sound/usb/usbmixer_maps.c b/sound/usb/usbmixer_maps.c index 77c35885e21c..79e903a60862 100644 --- a/sound/usb/usbmixer_maps.c +++ b/sound/usb/usbmixer_maps.c | |||
| @@ -19,11 +19,16 @@ | |||
| 19 | * | 19 | * |
| 20 | */ | 20 | */ |
| 21 | 21 | ||
| 22 | struct usbmix_dB_map { | ||
| 23 | u32 min; | ||
| 24 | u32 max; | ||
| 25 | }; | ||
| 22 | 26 | ||
| 23 | struct usbmix_name_map { | 27 | struct usbmix_name_map { |
| 24 | int id; | 28 | int id; |
| 25 | const char *name; | 29 | const char *name; |
| 26 | int control; | 30 | int control; |
| 31 | struct usbmix_dB_map *dB; | ||
| 27 | }; | 32 | }; |
| 28 | 33 | ||
| 29 | struct usbmix_selector_map { | 34 | struct usbmix_selector_map { |
| @@ -72,7 +77,7 @@ static struct usbmix_name_map extigy_map[] = { | |||
| 72 | { 8, "Line Playback" }, /* FU */ | 77 | { 8, "Line Playback" }, /* FU */ |
| 73 | /* 9: IT mic */ | 78 | /* 9: IT mic */ |
| 74 | { 10, "Mic Playback" }, /* FU */ | 79 | { 10, "Mic Playback" }, /* FU */ |
| 75 | { 11, "Capture Input Source" }, /* SU */ | 80 | { 11, "Capture Source" }, /* SU */ |
| 76 | { 12, "Capture" }, /* FU */ | 81 | { 12, "Capture" }, /* FU */ |
| 77 | /* 13: OT pcm capture */ | 82 | /* 13: OT pcm capture */ |
| 78 | /* 14: MU (w/o controls) */ | 83 | /* 14: MU (w/o controls) */ |
| @@ -102,6 +107,9 @@ static struct usbmix_name_map extigy_map[] = { | |||
| 102 | * e.g. no Master and fake PCM volume | 107 | * e.g. no Master and fake PCM volume |
| 103 | * Pavel Mihaylov <bin@bash.info> | 108 | * Pavel Mihaylov <bin@bash.info> |
| 104 | */ | 109 | */ |
| 110 | static struct usbmix_dB_map mp3plus_dB_1 = {-4781, 0}; /* just guess */ | ||
| 111 | static struct usbmix_dB_map mp3plus_dB_2 = {-1781, 618}; /* just guess */ | ||
| 112 | |||
| 105 | static struct usbmix_name_map mp3plus_map[] = { | 113 | static struct usbmix_name_map mp3plus_map[] = { |
| 106 | /* 1: IT pcm */ | 114 | /* 1: IT pcm */ |
| 107 | /* 2: IT mic */ | 115 | /* 2: IT mic */ |
| @@ -110,16 +118,19 @@ static struct usbmix_name_map mp3plus_map[] = { | |||
| 110 | /* 5: OT digital out */ | 118 | /* 5: OT digital out */ |
| 111 | /* 6: OT speaker */ | 119 | /* 6: OT speaker */ |
| 112 | /* 7: OT pcm capture */ | 120 | /* 7: OT pcm capture */ |
| 113 | { 8, "Capture Input Source" }, /* FU, default PCM Capture Source */ | 121 | { 8, "Capture Source" }, /* FU, default PCM Capture Source */ |
| 114 | /* (Mic, Input 1 = Line input, Input 2 = Optical input) */ | 122 | /* (Mic, Input 1 = Line input, Input 2 = Optical input) */ |
| 115 | { 9, "Master Playback" }, /* FU, default Speaker 1 */ | 123 | { 9, "Master Playback" }, /* FU, default Speaker 1 */ |
| 116 | /* { 10, "Mic Capture", 1 }, */ /* FU, Mic Capture */ | 124 | /* { 10, "Mic Capture", 1 }, */ /* FU, Mic Capture */ |
| 117 | /* { 10, "Mic Capture", 2 }, */ /* FU, Mic Capture */ | 125 | { 10, /* "Mic Capture", */ NULL, 2, .dB = &mp3plus_dB_2 }, |
| 126 | /* FU, Mic Capture */ | ||
| 118 | { 10, "Mic Boost", 7 }, /* FU, default Auto Gain Input */ | 127 | { 10, "Mic Boost", 7 }, /* FU, default Auto Gain Input */ |
| 119 | { 11, "Line Capture" }, /* FU, default PCM Capture */ | 128 | { 11, "Line Capture", .dB = &mp3plus_dB_2 }, |
| 129 | /* FU, default PCM Capture */ | ||
| 120 | { 12, "Digital In Playback" }, /* FU, default PCM 1 */ | 130 | { 12, "Digital In Playback" }, /* FU, default PCM 1 */ |
| 121 | /* { 13, "Mic Playback" }, */ /* FU, default Mic Playback */ | 131 | { 13, /* "Mic Playback", */ .dB = &mp3plus_dB_1 }, |
| 122 | { 14, "Line Playback" }, /* FU, default Speaker */ | 132 | /* FU, default Mic Playback */ |
| 133 | { 14, "Line Playback", .dB = &mp3plus_dB_1 }, /* FU, default Speaker */ | ||
| 123 | /* 15: MU */ | 134 | /* 15: MU */ |
| 124 | { 0 } /* terminator */ | 135 | { 0 } /* terminator */ |
| 125 | }; | 136 | }; |
diff --git a/sound/usb/usbquirks.h b/sound/usb/usbquirks.h index a892bda03df9..f06faf7917b9 100644 --- a/sound/usb/usbquirks.h +++ b/sound/usb/usbquirks.h | |||
| @@ -91,7 +91,7 @@ | |||
| 91 | .idVendor = 0x046d, | 91 | .idVendor = 0x046d, |
| 92 | .idProduct = 0x0850, | 92 | .idProduct = 0x0850, |
| 93 | .bInterfaceClass = USB_CLASS_AUDIO, | 93 | .bInterfaceClass = USB_CLASS_AUDIO, |
| 94 | .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL | 94 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL |
| 95 | }, | 95 | }, |
| 96 | { | 96 | { |
| 97 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | 97 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | |
| @@ -100,7 +100,7 @@ | |||
| 100 | .idVendor = 0x046d, | 100 | .idVendor = 0x046d, |
| 101 | .idProduct = 0x08ae, | 101 | .idProduct = 0x08ae, |
| 102 | .bInterfaceClass = USB_CLASS_AUDIO, | 102 | .bInterfaceClass = USB_CLASS_AUDIO, |
| 103 | .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL | 103 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL |
| 104 | }, | 104 | }, |
| 105 | { | 105 | { |
| 106 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | 106 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | |
| @@ -109,7 +109,7 @@ | |||
| 109 | .idVendor = 0x046d, | 109 | .idVendor = 0x046d, |
| 110 | .idProduct = 0x08c6, | 110 | .idProduct = 0x08c6, |
| 111 | .bInterfaceClass = USB_CLASS_AUDIO, | 111 | .bInterfaceClass = USB_CLASS_AUDIO, |
| 112 | .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL | 112 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL |
| 113 | }, | 113 | }, |
| 114 | { | 114 | { |
| 115 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | 115 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | |
| @@ -118,7 +118,7 @@ | |||
| 118 | .idVendor = 0x046d, | 118 | .idVendor = 0x046d, |
| 119 | .idProduct = 0x08f0, | 119 | .idProduct = 0x08f0, |
| 120 | .bInterfaceClass = USB_CLASS_AUDIO, | 120 | .bInterfaceClass = USB_CLASS_AUDIO, |
| 121 | .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL | 121 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL |
| 122 | }, | 122 | }, |
| 123 | { | 123 | { |
| 124 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | 124 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | |
| @@ -127,7 +127,7 @@ | |||
| 127 | .idVendor = 0x046d, | 127 | .idVendor = 0x046d, |
| 128 | .idProduct = 0x08f5, | 128 | .idProduct = 0x08f5, |
| 129 | .bInterfaceClass = USB_CLASS_AUDIO, | 129 | .bInterfaceClass = USB_CLASS_AUDIO, |
| 130 | .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL | 130 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL |
| 131 | }, | 131 | }, |
| 132 | { | 132 | { |
| 133 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | 133 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | |
| @@ -136,7 +136,7 @@ | |||
| 136 | .idVendor = 0x046d, | 136 | .idVendor = 0x046d, |
| 137 | .idProduct = 0x08f6, | 137 | .idProduct = 0x08f6, |
| 138 | .bInterfaceClass = USB_CLASS_AUDIO, | 138 | .bInterfaceClass = USB_CLASS_AUDIO, |
| 139 | .bInterfaceSubClass = USB_SUBCLASS_AUDIO_CONTROL | 139 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL |
| 140 | }, | 140 | }, |
| 141 | { | 141 | { |
| 142 | USB_DEVICE(0x046d, 0x0990), | 142 | USB_DEVICE(0x046d, 0x0990), |
| @@ -301,7 +301,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
| 301 | .iface = 1, | 301 | .iface = 1, |
| 302 | .altsetting = 1, | 302 | .altsetting = 1, |
| 303 | .altset_idx = 1, | 303 | .altset_idx = 1, |
| 304 | .attributes = EP_CS_ATTR_FILL_MAX, | 304 | .attributes = UAC_EP_CS_ATTR_FILL_MAX, |
| 305 | .endpoint = 0x81, | 305 | .endpoint = 0x81, |
| 306 | .ep_attr = 0x05, | 306 | .ep_attr = 0x05, |
| 307 | .rates = SNDRV_PCM_RATE_CONTINUOUS, | 307 | .rates = SNDRV_PCM_RATE_CONTINUOUS, |
| @@ -1266,37 +1266,6 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
| 1266 | } | 1266 | } |
| 1267 | } | 1267 | } |
| 1268 | }, | 1268 | }, |
| 1269 | /* Roland UA-101 in High-Speed Mode only */ | ||
| 1270 | { | ||
| 1271 | USB_DEVICE(0x0582, 0x007d), | ||
| 1272 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | ||
| 1273 | .vendor_name = "Roland", | ||
| 1274 | .product_name = "UA-101", | ||
| 1275 | .ifnum = QUIRK_ANY_INTERFACE, | ||
| 1276 | .type = QUIRK_COMPOSITE, | ||
| 1277 | .data = (const struct snd_usb_audio_quirk[]) { | ||
| 1278 | { | ||
| 1279 | .ifnum = 0, | ||
| 1280 | .type = QUIRK_AUDIO_EDIROL_UA101 | ||
| 1281 | }, | ||
| 1282 | { | ||
| 1283 | .ifnum = 1, | ||
| 1284 | .type = QUIRK_AUDIO_EDIROL_UA101 | ||
| 1285 | }, | ||
| 1286 | { | ||
| 1287 | .ifnum = 2, | ||
| 1288 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | ||
| 1289 | .data = & (const struct snd_usb_midi_endpoint_info) { | ||
| 1290 | .out_cables = 0x0001, | ||
| 1291 | .in_cables = 0x0001 | ||
| 1292 | } | ||
| 1293 | }, | ||
| 1294 | { | ||
| 1295 | .ifnum = -1 | ||
| 1296 | } | ||
| 1297 | } | ||
| 1298 | } | ||
| 1299 | }, | ||
| 1300 | { | 1269 | { |
| 1301 | /* has ID 0x0081 when not in "Advanced Driver" mode */ | 1270 | /* has ID 0x0081 when not in "Advanced Driver" mode */ |
| 1302 | USB_DEVICE(0x0582, 0x0080), | 1271 | USB_DEVICE(0x0582, 0x0080), |
| @@ -2073,6 +2042,33 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
| 2073 | } | 2042 | } |
| 2074 | }, | 2043 | }, |
| 2075 | 2044 | ||
| 2045 | /* Access Music devices */ | ||
| 2046 | { | ||
| 2047 | /* VirusTI Desktop */ | ||
| 2048 | USB_DEVICE_VENDOR_SPEC(0x133e, 0x0815), | ||
| 2049 | .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { | ||
| 2050 | .ifnum = QUIRK_ANY_INTERFACE, | ||
| 2051 | .type = QUIRK_COMPOSITE, | ||
| 2052 | .data = &(const struct snd_usb_audio_quirk[]) { | ||
| 2053 | { | ||
| 2054 | .ifnum = 3, | ||
| 2055 | .type = QUIRK_MIDI_FIXED_ENDPOINT, | ||
| 2056 | .data = &(const struct snd_usb_midi_endpoint_info) { | ||
| 2057 | .out_cables = 0x0003, | ||
| 2058 | .in_cables = 0x0003 | ||
| 2059 | } | ||
| 2060 | }, | ||
| 2061 | { | ||
| 2062 | .ifnum = 4, | ||
| 2063 | .type = QUIRK_IGNORE_INTERFACE | ||
| 2064 | }, | ||
| 2065 | { | ||
| 2066 | .ifnum = -1 | ||
| 2067 | } | ||
| 2068 | } | ||
| 2069 | } | ||
| 2070 | }, | ||
| 2071 | |||
| 2076 | /* */ | 2072 | /* */ |
| 2077 | { | 2073 | { |
| 2078 | /* aka. Serato Scratch Live DJ Box */ | 2074 | /* aka. Serato Scratch Live DJ Box */ |
| @@ -2105,6 +2101,165 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
| 2105 | } | 2101 | } |
| 2106 | }, | 2102 | }, |
| 2107 | 2103 | ||
| 2104 | /* Hauppauge HVR-950Q and HVR-850 */ | ||
| 2105 | { | ||
| 2106 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x7200), | ||
| 2107 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | ||
| 2108 | USB_DEVICE_ID_MATCH_INT_CLASS | | ||
| 2109 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, | ||
| 2110 | .bInterfaceClass = USB_CLASS_AUDIO, | ||
| 2111 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, | ||
| 2112 | .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { | ||
| 2113 | .vendor_name = "Hauppauge", | ||
| 2114 | .product_name = "HVR-950Q", | ||
| 2115 | .ifnum = QUIRK_ANY_INTERFACE, | ||
| 2116 | .type = QUIRK_AUDIO_ALIGN_TRANSFER, | ||
| 2117 | } | ||
| 2118 | }, | ||
| 2119 | { | ||
| 2120 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x7201), | ||
| 2121 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | ||
| 2122 | USB_DEVICE_ID_MATCH_INT_CLASS | | ||
| 2123 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, | ||
| 2124 | .bInterfaceClass = USB_CLASS_AUDIO, | ||
| 2125 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, | ||
| 2126 | .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { | ||
| 2127 | .vendor_name = "Hauppauge", | ||
| 2128 | .product_name = "HVR-950Q", | ||
| 2129 | .ifnum = QUIRK_ANY_INTERFACE, | ||
| 2130 | .type = QUIRK_AUDIO_ALIGN_TRANSFER, | ||
| 2131 | } | ||
| 2132 | }, | ||
| 2133 | { | ||
| 2134 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x7202), | ||
| 2135 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | ||
| 2136 | USB_DEVICE_ID_MATCH_INT_CLASS | | ||
| 2137 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, | ||
| 2138 | .bInterfaceClass = USB_CLASS_AUDIO, | ||
| 2139 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, | ||
| 2140 | .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { | ||
| 2141 | .vendor_name = "Hauppauge", | ||
| 2142 | .product_name = "HVR-950Q", | ||
| 2143 | .ifnum = QUIRK_ANY_INTERFACE, | ||
| 2144 | .type = QUIRK_AUDIO_ALIGN_TRANSFER, | ||
| 2145 | } | ||
| 2146 | }, | ||
| 2147 | { | ||
| 2148 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x7203), | ||
| 2149 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | ||
| 2150 | USB_DEVICE_ID_MATCH_INT_CLASS | | ||
| 2151 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, | ||
| 2152 | .bInterfaceClass = USB_CLASS_AUDIO, | ||
| 2153 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, | ||
| 2154 | .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { | ||
| 2155 | .vendor_name = "Hauppauge", | ||
| 2156 | .product_name = "HVR-950Q", | ||
| 2157 | .ifnum = QUIRK_ANY_INTERFACE, | ||
| 2158 | .type = QUIRK_AUDIO_ALIGN_TRANSFER, | ||
| 2159 | } | ||
| 2160 | }, | ||
| 2161 | { | ||
| 2162 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x7204), | ||
| 2163 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | ||
| 2164 | USB_DEVICE_ID_MATCH_INT_CLASS | | ||
| 2165 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, | ||
| 2166 | .bInterfaceClass = USB_CLASS_AUDIO, | ||
| 2167 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, | ||
| 2168 | .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { | ||
| 2169 | .vendor_name = "Hauppauge", | ||
| 2170 | .product_name = "HVR-950Q", | ||
| 2171 | .ifnum = QUIRK_ANY_INTERFACE, | ||
| 2172 | .type = QUIRK_AUDIO_ALIGN_TRANSFER, | ||
| 2173 | } | ||
| 2174 | }, | ||
| 2175 | { | ||
| 2176 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x7205), | ||
| 2177 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | ||
| 2178 | USB_DEVICE_ID_MATCH_INT_CLASS | | ||
| 2179 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, | ||
| 2180 | .bInterfaceClass = USB_CLASS_AUDIO, | ||
| 2181 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, | ||
| 2182 | .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { | ||
| 2183 | .vendor_name = "Hauppauge", | ||
| 2184 | .product_name = "HVR-950Q", | ||
| 2185 | .ifnum = QUIRK_ANY_INTERFACE, | ||
| 2186 | .type = QUIRK_AUDIO_ALIGN_TRANSFER, | ||
| 2187 | } | ||
| 2188 | }, | ||
| 2189 | { | ||
| 2190 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x7250), | ||
| 2191 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | ||
| 2192 | USB_DEVICE_ID_MATCH_INT_CLASS | | ||
| 2193 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, | ||
| 2194 | .bInterfaceClass = USB_CLASS_AUDIO, | ||
| 2195 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, | ||
| 2196 | .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { | ||
| 2197 | .vendor_name = "Hauppauge", | ||
| 2198 | .product_name = "HVR-950Q", | ||
| 2199 | .ifnum = QUIRK_ANY_INTERFACE, | ||
| 2200 | .type = QUIRK_AUDIO_ALIGN_TRANSFER, | ||
| 2201 | } | ||
| 2202 | }, | ||
| 2203 | { | ||
| 2204 | USB_DEVICE_VENDOR_SPEC(0x2040, 0x7230), | ||
| 2205 | .match_flags = USB_DEVICE_ID_MATCH_DEVICE | | ||
| 2206 | USB_DEVICE_ID_MATCH_INT_CLASS | | ||
| 2207 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, | ||
| 2208 | .bInterfaceClass = USB_CLASS_AUDIO, | ||
| 2209 | .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, | ||
| 2210 | .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { | ||
| 2211 | .vendor_name = "Hauppauge", | ||
| 2212 | .product_name = "HVR-850", | ||
| 2213 | .ifnum = QUIRK_ANY_INTERFACE, | ||
| 2214 | .type = QUIRK_AUDIO_ALIGN_TRANSFER, | ||
| 2215 | } | ||
| 2216 | }, | ||
| 2217 | |||
| 2218 | /* Digidesign Mbox */ | ||
| 2219 | { | ||
| 2220 | /* Thanks to Clemens Ladisch <clemens@ladisch.de> */ | ||
| 2221 | USB_DEVICE(0x0dba, 0x1000), | ||
| 2222 | .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { | ||
| 2223 | .vendor_name = "Digidesign", | ||
| 2224 | .product_name = "MBox", | ||
| 2225 | .ifnum = QUIRK_ANY_INTERFACE, | ||
| 2226 | .type = QUIRK_COMPOSITE, | ||
| 2227 | .data = (const struct snd_usb_audio_quirk[]){ | ||
| 2228 | { | ||
| 2229 | .ifnum = 0, | ||
| 2230 | .type = QUIRK_IGNORE_INTERFACE, | ||
| 2231 | }, | ||
| 2232 | { | ||
| 2233 | .ifnum = 1, | ||
| 2234 | .type = QUIRK_AUDIO_FIXED_ENDPOINT, | ||
| 2235 | .data = &(const struct audioformat) { | ||
| 2236 | .format = SNDRV_PCM_FORMAT_S24_3BE, | ||
| 2237 | .channels = 2, | ||
| 2238 | .iface = 1, | ||
| 2239 | .altsetting = 1, | ||
| 2240 | .altset_idx = 1, | ||
| 2241 | .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, | ||
| 2242 | .endpoint = 0x02, | ||
| 2243 | .ep_attr = 0x01, | ||
| 2244 | .maxpacksize = 0x130, | ||
| 2245 | .rates = SNDRV_PCM_RATE_44100 | | ||
| 2246 | SNDRV_PCM_RATE_48000, | ||
| 2247 | .rate_min = 44100, | ||
| 2248 | .rate_max = 48000, | ||
| 2249 | .nr_rates = 2, | ||
| 2250 | .rate_table = (unsigned int[]) { | ||
| 2251 | 44100, 48000 | ||
| 2252 | } | ||
| 2253 | } | ||
| 2254 | }, | ||
| 2255 | { | ||
| 2256 | .ifnum = -1 | ||
| 2257 | } | ||
| 2258 | } | ||
| 2259 | |||
| 2260 | } | ||
| 2261 | }, | ||
| 2262 | |||
| 2108 | { | 2263 | { |
| 2109 | /* | 2264 | /* |
| 2110 | * Some USB MIDI devices don't have an audio control interface, | 2265 | * Some USB MIDI devices don't have an audio control interface, |
| @@ -2113,7 +2268,7 @@ YAMAHA_DEVICE(0x7010, "UB99"), | |||
| 2113 | .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS | | 2268 | .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS | |
| 2114 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, | 2269 | USB_DEVICE_ID_MATCH_INT_SUBCLASS, |
| 2115 | .bInterfaceClass = USB_CLASS_AUDIO, | 2270 | .bInterfaceClass = USB_CLASS_AUDIO, |
| 2116 | .bInterfaceSubClass = USB_SUBCLASS_MIDI_STREAMING, | 2271 | .bInterfaceSubClass = USB_SUBCLASS_MIDISTREAMING, |
| 2117 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | 2272 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { |
| 2118 | .ifnum = QUIRK_ANY_INTERFACE, | 2273 | .ifnum = QUIRK_ANY_INTERFACE, |
| 2119 | .type = QUIRK_MIDI_STANDARD_INTERFACE | 2274 | .type = QUIRK_MIDI_STANDARD_INTERFACE |
diff --git a/sound/usb/usx2y/us122l.c b/sound/usb/usx2y/us122l.c index 91bb29666d26..44deb21b1777 100644 --- a/sound/usb/usx2y/us122l.c +++ b/sound/usb/usx2y/us122l.c | |||
| @@ -16,6 +16,8 @@ | |||
| 16 | * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | 16 | * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| 17 | */ | 17 | */ |
| 18 | 18 | ||
| 19 | #include <linux/usb.h> | ||
| 20 | #include <linux/usb/audio.h> | ||
| 19 | #include <sound/core.h> | 21 | #include <sound/core.h> |
| 20 | #include <sound/hwdep.h> | 22 | #include <sound/hwdep.h> |
| 21 | #include <sound/pcm.h> | 23 | #include <sound/pcm.h> |
| @@ -315,9 +317,9 @@ static int us122l_set_sample_rate(struct usb_device *dev, int rate) | |||
| 315 | data[0] = rate; | 317 | data[0] = rate; |
| 316 | data[1] = rate >> 8; | 318 | data[1] = rate >> 8; |
| 317 | data[2] = rate >> 16; | 319 | data[2] = rate >> 16; |
| 318 | err = us122l_ctl_msg(dev, usb_sndctrlpipe(dev, 0), SET_CUR, | 320 | err = us122l_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, |
| 319 | USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, | 321 | USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, |
| 320 | SAMPLING_FREQ_CONTROL << 8, ep, data, 3, 1000); | 322 | UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, data, 3, 1000); |
| 321 | if (err < 0) | 323 | if (err < 0) |
| 322 | snd_printk(KERN_ERR "%d: cannot set freq %d to ep 0x%x\n", | 324 | snd_printk(KERN_ERR "%d: cannot set freq %d to ep 0x%x\n", |
| 323 | dev->devnum, rate, ep); | 325 | dev->devnum, rate, ep); |
