| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1 | /* | 
|  | 2 | *  ALSA driver for Echoaudio soundcards. | 
|  | 3 | *  Copyright (C) 2003-2004 Giuliano Pochini <pochini@shiny.it> | 
|  | 4 | * | 
|  | 5 | *  This program is free software; you can redistribute it and/or modify | 
|  | 6 | *  it under the terms of the GNU General Public License as published by | 
|  | 7 | *  the Free Software Foundation; version 2 of the License. | 
|  | 8 | * | 
|  | 9 | *  This program is distributed in the hope that it will be useful, | 
|  | 10 | *  but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 11 | *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|  | 12 | *  GNU General Public License for more details. | 
|  | 13 | * | 
|  | 14 | *  You should have received a copy of the GNU General Public License | 
|  | 15 | *  along with this program; if not, write to the Free Software | 
|  | 16 | *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | 
|  | 17 | */ | 
|  | 18 |  | 
|  | 19 | MODULE_AUTHOR("Giuliano Pochini <pochini@shiny.it>"); | 
|  | 20 | MODULE_LICENSE("GPL v2"); | 
|  | 21 | MODULE_DESCRIPTION("Echoaudio " ECHOCARD_NAME " soundcards driver"); | 
|  | 22 | MODULE_SUPPORTED_DEVICE("{{Echoaudio," ECHOCARD_NAME "}}"); | 
|  | 23 | MODULE_DEVICE_TABLE(pci, snd_echo_ids); | 
|  | 24 |  | 
|  | 25 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | 
|  | 26 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | 
|  | 27 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | 
|  | 28 |  | 
|  | 29 | module_param_array(index, int, NULL, 0444); | 
|  | 30 | MODULE_PARM_DESC(index, "Index value for " ECHOCARD_NAME " soundcard."); | 
|  | 31 | module_param_array(id, charp, NULL, 0444); | 
|  | 32 | MODULE_PARM_DESC(id, "ID string for " ECHOCARD_NAME " soundcard."); | 
|  | 33 | module_param_array(enable, bool, NULL, 0444); | 
|  | 34 | MODULE_PARM_DESC(enable, "Enable " ECHOCARD_NAME " soundcard."); | 
|  | 35 |  | 
|  | 36 | static unsigned int channels_list[10] = {1, 2, 4, 6, 8, 10, 12, 14, 16, 999999}; | 
| Takashi Iwai | 0cb29ea | 2007-01-29 15:33:49 +0100 | [diff] [blame] | 37 | static const DECLARE_TLV_DB_SCALE(db_scale_output_gain, -12800, 100, 1); | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 38 |  | 
| Giuliano Pochini | 19b5006 | 2010-02-14 18:15:34 +0100 | [diff] [blame] | 39 |  | 
|  | 40 |  | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 41 | static int get_firmware(const struct firmware **fw_entry, | 
| Giuliano Pochini | 19b5006 | 2010-02-14 18:15:34 +0100 | [diff] [blame] | 42 | struct echoaudio *chip, const short fw_index) | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 43 | { | 
|  | 44 | int err; | 
|  | 45 | char name[30]; | 
| Giuliano Pochini | 19b5006 | 2010-02-14 18:15:34 +0100 | [diff] [blame] | 46 |  | 
| Giuliano Pochini | 4f8ada4 | 2010-02-14 18:15:51 +0100 | [diff] [blame] | 47 | #ifdef CONFIG_PM | 
|  | 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) | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 59 | snd_printk(KERN_ERR "get_firmware(): Firmware not available (%d)\n", err); | 
| Giuliano Pochini | 4f8ada4 | 2010-02-14 18:15:51 +0100 | [diff] [blame] | 60 | #ifdef CONFIG_PM | 
|  | 61 | else | 
|  | 62 | chip->fw_cache[fw_index] = *fw_entry; | 
|  | 63 | #endif | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 64 | return err; | 
|  | 65 | } | 
|  | 66 |  | 
| Giuliano Pochini | 19b5006 | 2010-02-14 18:15:34 +0100 | [diff] [blame] | 67 |  | 
|  | 68 |  | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 69 | static void free_firmware(const struct firmware *fw_entry) | 
|  | 70 | { | 
| Giuliano Pochini | 4f8ada4 | 2010-02-14 18:15:51 +0100 | [diff] [blame] | 71 | #ifdef CONFIG_PM | 
|  | 72 | DE_ACT(("firmware not released (kept in cache)\n")); | 
|  | 73 | #else | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 74 | release_firmware(fw_entry); | 
|  | 75 | DE_ACT(("firmware released\n")); | 
| Giuliano Pochini | 4f8ada4 | 2010-02-14 18:15:51 +0100 | [diff] [blame] | 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 | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 94 | } | 
|  | 95 |  | 
|  | 96 |  | 
|  | 97 |  | 
|  | 98 | /****************************************************************************** | 
|  | 99 | PCM interface | 
|  | 100 | ******************************************************************************/ | 
|  | 101 |  | 
|  | 102 | static void audiopipe_free(struct snd_pcm_runtime *runtime) | 
|  | 103 | { | 
|  | 104 | struct audiopipe *pipe = runtime->private_data; | 
|  | 105 |  | 
|  | 106 | if (pipe->sgpage.area) | 
|  | 107 | snd_dma_free_pages(&pipe->sgpage); | 
|  | 108 | kfree(pipe); | 
|  | 109 | } | 
|  | 110 |  | 
|  | 111 |  | 
|  | 112 |  | 
|  | 113 | static int hw_rule_capture_format_by_channels(struct snd_pcm_hw_params *params, | 
|  | 114 | struct snd_pcm_hw_rule *rule) | 
|  | 115 | { | 
|  | 116 | struct snd_interval *c = hw_param_interval(params, | 
|  | 117 | SNDRV_PCM_HW_PARAM_CHANNELS); | 
|  | 118 | struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); | 
|  | 119 | struct snd_mask fmt; | 
|  | 120 |  | 
|  | 121 | snd_mask_any(&fmt); | 
|  | 122 |  | 
|  | 123 | #ifndef ECHOCARD_HAS_STEREO_BIG_ENDIAN32 | 
|  | 124 | /* >=2 channels cannot be S32_BE */ | 
|  | 125 | if (c->min == 2) { | 
|  | 126 | fmt.bits[0] &= ~SNDRV_PCM_FMTBIT_S32_BE; | 
|  | 127 | return snd_mask_refine(f, &fmt); | 
|  | 128 | } | 
|  | 129 | #endif | 
|  | 130 | /* > 2 channels cannot be U8 and S32_BE */ | 
|  | 131 | if (c->min > 2) { | 
|  | 132 | fmt.bits[0] &= ~(SNDRV_PCM_FMTBIT_U8 | SNDRV_PCM_FMTBIT_S32_BE); | 
|  | 133 | return snd_mask_refine(f, &fmt); | 
|  | 134 | } | 
|  | 135 | /* Mono is ok with any format */ | 
|  | 136 | return 0; | 
|  | 137 | } | 
|  | 138 |  | 
|  | 139 |  | 
|  | 140 |  | 
|  | 141 | static int hw_rule_capture_channels_by_format(struct snd_pcm_hw_params *params, | 
|  | 142 | struct snd_pcm_hw_rule *rule) | 
|  | 143 | { | 
|  | 144 | struct snd_interval *c = hw_param_interval(params, | 
|  | 145 | SNDRV_PCM_HW_PARAM_CHANNELS); | 
|  | 146 | struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); | 
|  | 147 | struct snd_interval ch; | 
|  | 148 |  | 
|  | 149 | snd_interval_any(&ch); | 
|  | 150 |  | 
|  | 151 | /* S32_BE is mono (and stereo) only */ | 
|  | 152 | if (f->bits[0] == SNDRV_PCM_FMTBIT_S32_BE) { | 
|  | 153 | ch.min = 1; | 
|  | 154 | #ifdef ECHOCARD_HAS_STEREO_BIG_ENDIAN32 | 
|  | 155 | ch.max = 2; | 
|  | 156 | #else | 
|  | 157 | ch.max = 1; | 
|  | 158 | #endif | 
|  | 159 | ch.integer = 1; | 
|  | 160 | return snd_interval_refine(c, &ch); | 
|  | 161 | } | 
|  | 162 | /* U8 can be only mono or stereo */ | 
|  | 163 | if (f->bits[0] == SNDRV_PCM_FMTBIT_U8) { | 
|  | 164 | ch.min = 1; | 
|  | 165 | ch.max = 2; | 
|  | 166 | ch.integer = 1; | 
|  | 167 | return snd_interval_refine(c, &ch); | 
|  | 168 | } | 
|  | 169 | /* S16_LE, S24_3LE and S32_LE support any number of channels. */ | 
|  | 170 | return 0; | 
|  | 171 | } | 
|  | 172 |  | 
|  | 173 |  | 
|  | 174 |  | 
|  | 175 | static int hw_rule_playback_format_by_channels(struct snd_pcm_hw_params *params, | 
|  | 176 | struct snd_pcm_hw_rule *rule) | 
|  | 177 | { | 
|  | 178 | struct snd_interval *c = hw_param_interval(params, | 
|  | 179 | SNDRV_PCM_HW_PARAM_CHANNELS); | 
|  | 180 | struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); | 
|  | 181 | struct snd_mask fmt; | 
|  | 182 | u64 fmask; | 
|  | 183 | snd_mask_any(&fmt); | 
|  | 184 |  | 
|  | 185 | fmask = fmt.bits[0] + ((u64)fmt.bits[1] << 32); | 
|  | 186 |  | 
|  | 187 | /* >2 channels must be S16_LE, S24_3LE or S32_LE */ | 
|  | 188 | if (c->min > 2) { | 
|  | 189 | fmask &= SNDRV_PCM_FMTBIT_S16_LE | | 
|  | 190 | SNDRV_PCM_FMTBIT_S24_3LE | | 
|  | 191 | SNDRV_PCM_FMTBIT_S32_LE; | 
|  | 192 | /* 1 channel must be S32_BE or S32_LE */ | 
|  | 193 | } else if (c->max == 1) | 
|  | 194 | fmask &= SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE; | 
|  | 195 | #ifndef ECHOCARD_HAS_STEREO_BIG_ENDIAN32 | 
|  | 196 | /* 2 channels cannot be S32_BE */ | 
|  | 197 | else if (c->min == 2 && c->max == 2) | 
|  | 198 | fmask &= ~SNDRV_PCM_FMTBIT_S32_BE; | 
|  | 199 | #endif | 
|  | 200 | else | 
|  | 201 | return 0; | 
|  | 202 |  | 
|  | 203 | fmt.bits[0] &= (u32)fmask; | 
|  | 204 | fmt.bits[1] &= (u32)(fmask >> 32); | 
|  | 205 | return snd_mask_refine(f, &fmt); | 
|  | 206 | } | 
|  | 207 |  | 
|  | 208 |  | 
|  | 209 |  | 
|  | 210 | static int hw_rule_playback_channels_by_format(struct snd_pcm_hw_params *params, | 
|  | 211 | struct snd_pcm_hw_rule *rule) | 
|  | 212 | { | 
|  | 213 | struct snd_interval *c = hw_param_interval(params, | 
|  | 214 | SNDRV_PCM_HW_PARAM_CHANNELS); | 
|  | 215 | struct snd_mask *f = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); | 
|  | 216 | struct snd_interval ch; | 
|  | 217 | u64 fmask; | 
|  | 218 |  | 
|  | 219 | snd_interval_any(&ch); | 
|  | 220 | ch.integer = 1; | 
|  | 221 | fmask = f->bits[0] + ((u64)f->bits[1] << 32); | 
|  | 222 |  | 
|  | 223 | /* S32_BE is mono (and stereo) only */ | 
|  | 224 | if (fmask == SNDRV_PCM_FMTBIT_S32_BE) { | 
|  | 225 | ch.min = 1; | 
|  | 226 | #ifdef ECHOCARD_HAS_STEREO_BIG_ENDIAN32 | 
|  | 227 | ch.max = 2; | 
|  | 228 | #else | 
|  | 229 | ch.max = 1; | 
|  | 230 | #endif | 
|  | 231 | /* U8 is stereo only */ | 
|  | 232 | } else if (fmask == SNDRV_PCM_FMTBIT_U8) | 
|  | 233 | ch.min = ch.max = 2; | 
|  | 234 | /* S16_LE and S24_3LE must be at least stereo */ | 
|  | 235 | else if (!(fmask & ~(SNDRV_PCM_FMTBIT_S16_LE | | 
|  | 236 | SNDRV_PCM_FMTBIT_S24_3LE))) | 
|  | 237 | ch.min = 2; | 
|  | 238 | else | 
|  | 239 | return 0; | 
|  | 240 |  | 
|  | 241 | return snd_interval_refine(c, &ch); | 
|  | 242 | } | 
|  | 243 |  | 
|  | 244 |  | 
|  | 245 |  | 
|  | 246 | /* Since the sample rate is a global setting, do allow the user to change the | 
|  | 247 | sample rate only if there is only one pcm device open. */ | 
|  | 248 | static int hw_rule_sample_rate(struct snd_pcm_hw_params *params, | 
|  | 249 | struct snd_pcm_hw_rule *rule) | 
|  | 250 | { | 
|  | 251 | struct snd_interval *rate = hw_param_interval(params, | 
|  | 252 | SNDRV_PCM_HW_PARAM_RATE); | 
|  | 253 | struct echoaudio *chip = rule->private; | 
|  | 254 | struct snd_interval fixed; | 
|  | 255 |  | 
|  | 256 | if (!chip->can_set_rate) { | 
|  | 257 | snd_interval_any(&fixed); | 
|  | 258 | fixed.min = fixed.max = chip->sample_rate; | 
|  | 259 | return snd_interval_refine(rate, &fixed); | 
|  | 260 | } | 
|  | 261 | return 0; | 
|  | 262 | } | 
|  | 263 |  | 
|  | 264 |  | 
|  | 265 | static int pcm_open(struct snd_pcm_substream *substream, | 
|  | 266 | signed char max_channels) | 
|  | 267 | { | 
|  | 268 | struct echoaudio *chip; | 
|  | 269 | struct snd_pcm_runtime *runtime; | 
|  | 270 | struct audiopipe *pipe; | 
|  | 271 | int err, i; | 
|  | 272 |  | 
|  | 273 | if (max_channels <= 0) | 
|  | 274 | return -EAGAIN; | 
|  | 275 |  | 
|  | 276 | chip = snd_pcm_substream_chip(substream); | 
|  | 277 | runtime = substream->runtime; | 
|  | 278 |  | 
| Panagiotis Issaris | 59feddb | 2006-07-25 15:28:03 +0200 | [diff] [blame] | 279 | pipe = kzalloc(sizeof(struct audiopipe), GFP_KERNEL); | 
|  | 280 | if (!pipe) | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 281 | return -ENOMEM; | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 282 | pipe->index = -1;		/* Not configured yet */ | 
|  | 283 |  | 
|  | 284 | /* Set up hw capabilities and contraints */ | 
|  | 285 | memcpy(&pipe->hw, &pcm_hardware_skel, sizeof(struct snd_pcm_hardware)); | 
|  | 286 | DE_HWP(("max_channels=%d\n", max_channels)); | 
|  | 287 | pipe->constr.list = channels_list; | 
|  | 288 | pipe->constr.mask = 0; | 
|  | 289 | for (i = 0; channels_list[i] <= max_channels; i++); | 
|  | 290 | pipe->constr.count = i; | 
|  | 291 | if (pipe->hw.channels_max > max_channels) | 
|  | 292 | pipe->hw.channels_max = max_channels; | 
|  | 293 | if (chip->digital_mode == DIGITAL_MODE_ADAT) { | 
|  | 294 | pipe->hw.rate_max = 48000; | 
|  | 295 | pipe->hw.rates &= SNDRV_PCM_RATE_8000_48000; | 
|  | 296 | } | 
|  | 297 |  | 
|  | 298 | runtime->hw = pipe->hw; | 
|  | 299 | runtime->private_data = pipe; | 
|  | 300 | runtime->private_free = audiopipe_free; | 
|  | 301 | snd_pcm_set_sync(substream); | 
|  | 302 |  | 
|  | 303 | /* Only mono and any even number of channels are allowed */ | 
|  | 304 | if ((err = snd_pcm_hw_constraint_list(runtime, 0, | 
|  | 305 | SNDRV_PCM_HW_PARAM_CHANNELS, | 
|  | 306 | &pipe->constr)) < 0) | 
|  | 307 | return err; | 
|  | 308 |  | 
|  | 309 | /* All periods should have the same size */ | 
|  | 310 | if ((err = snd_pcm_hw_constraint_integer(runtime, | 
|  | 311 | SNDRV_PCM_HW_PARAM_PERIODS)) < 0) | 
|  | 312 | return err; | 
|  | 313 |  | 
|  | 314 | /* The hw accesses memory in chunks 32 frames long and they should be | 
|  | 315 | 32-bytes-aligned. It's not a requirement, but it seems that IRQs are | 
|  | 316 | generated with a resolution of 32 frames. Thus we need the following */ | 
|  | 317 | if ((err = snd_pcm_hw_constraint_step(runtime, 0, | 
|  | 318 | SNDRV_PCM_HW_PARAM_PERIOD_SIZE, | 
|  | 319 | 32)) < 0) | 
|  | 320 | return err; | 
|  | 321 | if ((err = snd_pcm_hw_constraint_step(runtime, 0, | 
|  | 322 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE, | 
|  | 323 | 32)) < 0) | 
|  | 324 | return err; | 
|  | 325 |  | 
|  | 326 | if ((err = snd_pcm_hw_rule_add(substream->runtime, 0, | 
|  | 327 | SNDRV_PCM_HW_PARAM_RATE, | 
|  | 328 | hw_rule_sample_rate, chip, | 
|  | 329 | SNDRV_PCM_HW_PARAM_RATE, -1)) < 0) | 
|  | 330 | return err; | 
|  | 331 |  | 
|  | 332 | /* Finally allocate a page for the scatter-gather list */ | 
|  | 333 | if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, | 
|  | 334 | snd_dma_pci_data(chip->pci), | 
|  | 335 | PAGE_SIZE, &pipe->sgpage)) < 0) { | 
|  | 336 | DE_HWP(("s-g list allocation failed\n")); | 
|  | 337 | return err; | 
|  | 338 | } | 
|  | 339 |  | 
|  | 340 | return 0; | 
|  | 341 | } | 
|  | 342 |  | 
|  | 343 |  | 
|  | 344 |  | 
|  | 345 | static int pcm_analog_in_open(struct snd_pcm_substream *substream) | 
|  | 346 | { | 
|  | 347 | struct echoaudio *chip = snd_pcm_substream_chip(substream); | 
|  | 348 | int err; | 
|  | 349 |  | 
|  | 350 | DE_ACT(("pcm_analog_in_open\n")); | 
|  | 351 | if ((err = pcm_open(substream, num_analog_busses_in(chip) - | 
|  | 352 | substream->number)) < 0) | 
|  | 353 | return err; | 
|  | 354 | if ((err = snd_pcm_hw_rule_add(substream->runtime, 0, | 
|  | 355 | SNDRV_PCM_HW_PARAM_CHANNELS, | 
|  | 356 | hw_rule_capture_channels_by_format, NULL, | 
|  | 357 | SNDRV_PCM_HW_PARAM_FORMAT, -1)) < 0) | 
|  | 358 | return err; | 
|  | 359 | if ((err = snd_pcm_hw_rule_add(substream->runtime, 0, | 
|  | 360 | SNDRV_PCM_HW_PARAM_FORMAT, | 
|  | 361 | hw_rule_capture_format_by_channels, NULL, | 
|  | 362 | SNDRV_PCM_HW_PARAM_CHANNELS, -1)) < 0) | 
|  | 363 | return err; | 
|  | 364 | atomic_inc(&chip->opencount); | 
|  | 365 | if (atomic_read(&chip->opencount) > 1 && chip->rate_set) | 
|  | 366 | chip->can_set_rate=0; | 
|  | 367 | DE_HWP(("pcm_analog_in_open  cs=%d  oc=%d  r=%d\n", | 
|  | 368 | chip->can_set_rate, atomic_read(&chip->opencount), | 
|  | 369 | chip->sample_rate)); | 
|  | 370 | return 0; | 
|  | 371 | } | 
|  | 372 |  | 
|  | 373 |  | 
|  | 374 |  | 
|  | 375 | static int pcm_analog_out_open(struct snd_pcm_substream *substream) | 
|  | 376 | { | 
|  | 377 | struct echoaudio *chip = snd_pcm_substream_chip(substream); | 
|  | 378 | int max_channels, err; | 
|  | 379 |  | 
|  | 380 | #ifdef ECHOCARD_HAS_VMIXER | 
|  | 381 | max_channels = num_pipes_out(chip); | 
|  | 382 | #else | 
|  | 383 | max_channels = num_analog_busses_out(chip); | 
|  | 384 | #endif | 
|  | 385 | DE_ACT(("pcm_analog_out_open\n")); | 
|  | 386 | if ((err = pcm_open(substream, max_channels - substream->number)) < 0) | 
|  | 387 | return err; | 
|  | 388 | if ((err = snd_pcm_hw_rule_add(substream->runtime, 0, | 
|  | 389 | SNDRV_PCM_HW_PARAM_CHANNELS, | 
|  | 390 | hw_rule_playback_channels_by_format, | 
|  | 391 | NULL, | 
|  | 392 | SNDRV_PCM_HW_PARAM_FORMAT, -1)) < 0) | 
|  | 393 | return err; | 
|  | 394 | if ((err = snd_pcm_hw_rule_add(substream->runtime, 0, | 
|  | 395 | SNDRV_PCM_HW_PARAM_FORMAT, | 
|  | 396 | hw_rule_playback_format_by_channels, | 
|  | 397 | NULL, | 
|  | 398 | SNDRV_PCM_HW_PARAM_CHANNELS, -1)) < 0) | 
|  | 399 | return err; | 
|  | 400 | atomic_inc(&chip->opencount); | 
|  | 401 | if (atomic_read(&chip->opencount) > 1 && chip->rate_set) | 
|  | 402 | chip->can_set_rate=0; | 
|  | 403 | DE_HWP(("pcm_analog_out_open  cs=%d  oc=%d  r=%d\n", | 
|  | 404 | chip->can_set_rate, atomic_read(&chip->opencount), | 
|  | 405 | chip->sample_rate)); | 
|  | 406 | return 0; | 
|  | 407 | } | 
|  | 408 |  | 
|  | 409 |  | 
|  | 410 |  | 
|  | 411 | #ifdef ECHOCARD_HAS_DIGITAL_IO | 
|  | 412 |  | 
|  | 413 | static int pcm_digital_in_open(struct snd_pcm_substream *substream) | 
|  | 414 | { | 
|  | 415 | struct echoaudio *chip = snd_pcm_substream_chip(substream); | 
|  | 416 | int err, max_channels; | 
|  | 417 |  | 
|  | 418 | DE_ACT(("pcm_digital_in_open\n")); | 
|  | 419 | max_channels = num_digital_busses_in(chip) - substream->number; | 
| Takashi Iwai | befceea | 2007-12-03 17:08:40 +0100 | [diff] [blame] | 420 | mutex_lock(&chip->mode_mutex); | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 421 | if (chip->digital_mode == DIGITAL_MODE_ADAT) | 
|  | 422 | err = pcm_open(substream, max_channels); | 
|  | 423 | else	/* If the card has ADAT, subtract the 6 channels | 
|  | 424 | * that S/PDIF doesn't have | 
|  | 425 | */ | 
|  | 426 | err = pcm_open(substream, max_channels - ECHOCARD_HAS_ADAT); | 
|  | 427 |  | 
|  | 428 | if (err < 0) | 
|  | 429 | goto din_exit; | 
|  | 430 |  | 
|  | 431 | if ((err = snd_pcm_hw_rule_add(substream->runtime, 0, | 
|  | 432 | SNDRV_PCM_HW_PARAM_CHANNELS, | 
|  | 433 | hw_rule_capture_channels_by_format, NULL, | 
|  | 434 | SNDRV_PCM_HW_PARAM_FORMAT, -1)) < 0) | 
|  | 435 | goto din_exit; | 
|  | 436 | if ((err = snd_pcm_hw_rule_add(substream->runtime, 0, | 
|  | 437 | SNDRV_PCM_HW_PARAM_FORMAT, | 
|  | 438 | hw_rule_capture_format_by_channels, NULL, | 
|  | 439 | SNDRV_PCM_HW_PARAM_CHANNELS, -1)) < 0) | 
|  | 440 | goto din_exit; | 
|  | 441 |  | 
|  | 442 | atomic_inc(&chip->opencount); | 
|  | 443 | if (atomic_read(&chip->opencount) > 1 && chip->rate_set) | 
|  | 444 | chip->can_set_rate=0; | 
|  | 445 |  | 
|  | 446 | din_exit: | 
| Takashi Iwai | befceea | 2007-12-03 17:08:40 +0100 | [diff] [blame] | 447 | mutex_unlock(&chip->mode_mutex); | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 448 | return err; | 
|  | 449 | } | 
|  | 450 |  | 
|  | 451 |  | 
|  | 452 |  | 
|  | 453 | #ifndef ECHOCARD_HAS_VMIXER	/* See the note in snd_echo_new_pcm() */ | 
|  | 454 |  | 
|  | 455 | static int pcm_digital_out_open(struct snd_pcm_substream *substream) | 
|  | 456 | { | 
|  | 457 | struct echoaudio *chip = snd_pcm_substream_chip(substream); | 
|  | 458 | int err, max_channels; | 
|  | 459 |  | 
|  | 460 | DE_ACT(("pcm_digital_out_open\n")); | 
|  | 461 | max_channels = num_digital_busses_out(chip) - substream->number; | 
| Takashi Iwai | befceea | 2007-12-03 17:08:40 +0100 | [diff] [blame] | 462 | mutex_lock(&chip->mode_mutex); | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 463 | if (chip->digital_mode == DIGITAL_MODE_ADAT) | 
|  | 464 | err = pcm_open(substream, max_channels); | 
|  | 465 | else	/* If the card has ADAT, subtract the 6 channels | 
|  | 466 | * that S/PDIF doesn't have | 
|  | 467 | */ | 
|  | 468 | err = pcm_open(substream, max_channels - ECHOCARD_HAS_ADAT); | 
|  | 469 |  | 
|  | 470 | if (err < 0) | 
|  | 471 | goto dout_exit; | 
|  | 472 |  | 
|  | 473 | if ((err = snd_pcm_hw_rule_add(substream->runtime, 0, | 
|  | 474 | SNDRV_PCM_HW_PARAM_CHANNELS, | 
|  | 475 | hw_rule_playback_channels_by_format, | 
|  | 476 | NULL, SNDRV_PCM_HW_PARAM_FORMAT, | 
|  | 477 | -1)) < 0) | 
|  | 478 | goto dout_exit; | 
|  | 479 | if ((err = snd_pcm_hw_rule_add(substream->runtime, 0, | 
|  | 480 | SNDRV_PCM_HW_PARAM_FORMAT, | 
|  | 481 | hw_rule_playback_format_by_channels, | 
|  | 482 | NULL, SNDRV_PCM_HW_PARAM_CHANNELS, | 
|  | 483 | -1)) < 0) | 
|  | 484 | goto dout_exit; | 
|  | 485 | atomic_inc(&chip->opencount); | 
|  | 486 | if (atomic_read(&chip->opencount) > 1 && chip->rate_set) | 
|  | 487 | chip->can_set_rate=0; | 
|  | 488 | dout_exit: | 
| Takashi Iwai | befceea | 2007-12-03 17:08:40 +0100 | [diff] [blame] | 489 | mutex_unlock(&chip->mode_mutex); | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 490 | return err; | 
|  | 491 | } | 
|  | 492 |  | 
|  | 493 | #endif /* !ECHOCARD_HAS_VMIXER */ | 
|  | 494 |  | 
|  | 495 | #endif /* ECHOCARD_HAS_DIGITAL_IO */ | 
|  | 496 |  | 
|  | 497 |  | 
|  | 498 |  | 
|  | 499 | static int pcm_close(struct snd_pcm_substream *substream) | 
|  | 500 | { | 
|  | 501 | struct echoaudio *chip = snd_pcm_substream_chip(substream); | 
|  | 502 | int oc; | 
|  | 503 |  | 
|  | 504 | /* Nothing to do here. Audio is already off and pipe will be | 
|  | 505 | * freed by its callback | 
|  | 506 | */ | 
|  | 507 | DE_ACT(("pcm_close\n")); | 
|  | 508 |  | 
|  | 509 | atomic_dec(&chip->opencount); | 
|  | 510 | oc = atomic_read(&chip->opencount); | 
|  | 511 | DE_ACT(("pcm_close  oc=%d  cs=%d  rs=%d\n", oc, | 
|  | 512 | chip->can_set_rate, chip->rate_set)); | 
|  | 513 | if (oc < 2) | 
|  | 514 | chip->can_set_rate = 1; | 
|  | 515 | if (oc == 0) | 
|  | 516 | chip->rate_set = 0; | 
|  | 517 | DE_ACT(("pcm_close2 oc=%d  cs=%d  rs=%d\n", oc, | 
|  | 518 | chip->can_set_rate,chip->rate_set)); | 
|  | 519 |  | 
|  | 520 | return 0; | 
|  | 521 | } | 
|  | 522 |  | 
|  | 523 |  | 
|  | 524 |  | 
|  | 525 | /* Channel allocation and scatter-gather list setup */ | 
|  | 526 | static int init_engine(struct snd_pcm_substream *substream, | 
|  | 527 | struct snd_pcm_hw_params *hw_params, | 
|  | 528 | int pipe_index, int interleave) | 
|  | 529 | { | 
|  | 530 | struct echoaudio *chip; | 
|  | 531 | int err, per, rest, page, edge, offs; | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 532 | struct audiopipe *pipe; | 
|  | 533 |  | 
|  | 534 | chip = snd_pcm_substream_chip(substream); | 
|  | 535 | pipe = (struct audiopipe *) substream->runtime->private_data; | 
|  | 536 |  | 
|  | 537 | /* Sets up che hardware. If it's already initialized, reset and | 
|  | 538 | * redo with the new parameters | 
|  | 539 | */ | 
|  | 540 | spin_lock_irq(&chip->lock); | 
|  | 541 | if (pipe->index >= 0) { | 
|  | 542 | DE_HWP(("hwp_ie free(%d)\n", pipe->index)); | 
|  | 543 | err = free_pipes(chip, pipe); | 
| Takashi Iwai | da3cec3 | 2008-08-08 17:12:14 +0200 | [diff] [blame] | 544 | snd_BUG_ON(err); | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 545 | chip->substream[pipe->index] = NULL; | 
|  | 546 | } | 
|  | 547 |  | 
|  | 548 | err = allocate_pipes(chip, pipe, pipe_index, interleave); | 
|  | 549 | if (err < 0) { | 
|  | 550 | spin_unlock_irq(&chip->lock); | 
|  | 551 | DE_ACT((KERN_NOTICE "allocate_pipes(%d) err=%d\n", | 
|  | 552 | pipe_index, err)); | 
|  | 553 | return err; | 
|  | 554 | } | 
|  | 555 | spin_unlock_irq(&chip->lock); | 
|  | 556 | DE_ACT((KERN_NOTICE "allocate_pipes()=%d\n", pipe_index)); | 
|  | 557 |  | 
|  | 558 | DE_HWP(("pcm_hw_params (bufsize=%dB periods=%d persize=%dB)\n", | 
|  | 559 | params_buffer_bytes(hw_params), params_periods(hw_params), | 
|  | 560 | params_period_bytes(hw_params))); | 
|  | 561 | err = snd_pcm_lib_malloc_pages(substream, | 
|  | 562 | params_buffer_bytes(hw_params)); | 
|  | 563 | if (err < 0) { | 
|  | 564 | snd_printk(KERN_ERR "malloc_pages err=%d\n", err); | 
|  | 565 | spin_lock_irq(&chip->lock); | 
|  | 566 | free_pipes(chip, pipe); | 
|  | 567 | spin_unlock_irq(&chip->lock); | 
|  | 568 | pipe->index = -1; | 
|  | 569 | return err; | 
|  | 570 | } | 
|  | 571 |  | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 572 | sglist_init(chip, pipe); | 
|  | 573 | edge = PAGE_SIZE; | 
|  | 574 | for (offs = page = per = 0; offs < params_buffer_bytes(hw_params); | 
|  | 575 | per++) { | 
|  | 576 | rest = params_period_bytes(hw_params); | 
|  | 577 | if (offs + rest > params_buffer_bytes(hw_params)) | 
|  | 578 | rest = params_buffer_bytes(hw_params) - offs; | 
|  | 579 | while (rest) { | 
| Takashi Iwai | 77a23f2 | 2008-08-21 13:00:13 +0200 | [diff] [blame] | 580 | dma_addr_t addr; | 
|  | 581 | addr = snd_pcm_sgbuf_get_addr(substream, offs); | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 582 | if (rest <= edge - offs) { | 
| Takashi Iwai | 77a23f2 | 2008-08-21 13:00:13 +0200 | [diff] [blame] | 583 | sglist_add_mapping(chip, pipe, addr, rest); | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 584 | sglist_add_irq(chip, pipe); | 
|  | 585 | offs += rest; | 
|  | 586 | rest = 0; | 
|  | 587 | } else { | 
| Takashi Iwai | 77a23f2 | 2008-08-21 13:00:13 +0200 | [diff] [blame] | 588 | sglist_add_mapping(chip, pipe, addr, | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 589 | edge - offs); | 
|  | 590 | rest -= edge - offs; | 
|  | 591 | offs = edge; | 
|  | 592 | } | 
|  | 593 | if (offs == edge) { | 
|  | 594 | edge += PAGE_SIZE; | 
|  | 595 | page++; | 
|  | 596 | } | 
|  | 597 | } | 
|  | 598 | } | 
|  | 599 |  | 
|  | 600 | /* Close the ring buffer */ | 
|  | 601 | sglist_wrap(chip, pipe); | 
|  | 602 |  | 
|  | 603 | /* This stuff is used by the irq handler, so it must be | 
|  | 604 | * initialized before chip->substream | 
|  | 605 | */ | 
|  | 606 | chip->last_period[pipe_index] = 0; | 
|  | 607 | pipe->last_counter = 0; | 
|  | 608 | pipe->position = 0; | 
|  | 609 | smp_wmb(); | 
|  | 610 | chip->substream[pipe_index] = substream; | 
|  | 611 | chip->rate_set = 1; | 
|  | 612 | spin_lock_irq(&chip->lock); | 
|  | 613 | set_sample_rate(chip, hw_params->rate_num / hw_params->rate_den); | 
|  | 614 | spin_unlock_irq(&chip->lock); | 
|  | 615 | DE_HWP(("pcm_hw_params ok\n")); | 
|  | 616 | return 0; | 
|  | 617 | } | 
|  | 618 |  | 
|  | 619 |  | 
|  | 620 |  | 
|  | 621 | static int pcm_analog_in_hw_params(struct snd_pcm_substream *substream, | 
|  | 622 | struct snd_pcm_hw_params *hw_params) | 
|  | 623 | { | 
|  | 624 | struct echoaudio *chip = snd_pcm_substream_chip(substream); | 
|  | 625 |  | 
|  | 626 | return init_engine(substream, hw_params, px_analog_in(chip) + | 
|  | 627 | substream->number, params_channels(hw_params)); | 
|  | 628 | } | 
|  | 629 |  | 
|  | 630 |  | 
|  | 631 |  | 
|  | 632 | static int pcm_analog_out_hw_params(struct snd_pcm_substream *substream, | 
|  | 633 | struct snd_pcm_hw_params *hw_params) | 
|  | 634 | { | 
|  | 635 | return init_engine(substream, hw_params, substream->number, | 
|  | 636 | params_channels(hw_params)); | 
|  | 637 | } | 
|  | 638 |  | 
|  | 639 |  | 
|  | 640 |  | 
|  | 641 | #ifdef ECHOCARD_HAS_DIGITAL_IO | 
|  | 642 |  | 
|  | 643 | static int pcm_digital_in_hw_params(struct snd_pcm_substream *substream, | 
|  | 644 | struct snd_pcm_hw_params *hw_params) | 
|  | 645 | { | 
|  | 646 | struct echoaudio *chip = snd_pcm_substream_chip(substream); | 
|  | 647 |  | 
|  | 648 | return init_engine(substream, hw_params, px_digital_in(chip) + | 
|  | 649 | substream->number, params_channels(hw_params)); | 
|  | 650 | } | 
|  | 651 |  | 
|  | 652 |  | 
|  | 653 |  | 
|  | 654 | #ifndef ECHOCARD_HAS_VMIXER	/* See the note in snd_echo_new_pcm() */ | 
|  | 655 | static int pcm_digital_out_hw_params(struct snd_pcm_substream *substream, | 
|  | 656 | struct snd_pcm_hw_params *hw_params) | 
|  | 657 | { | 
|  | 658 | struct echoaudio *chip = snd_pcm_substream_chip(substream); | 
|  | 659 |  | 
|  | 660 | return init_engine(substream, hw_params, px_digital_out(chip) + | 
|  | 661 | substream->number, params_channels(hw_params)); | 
|  | 662 | } | 
|  | 663 | #endif /* !ECHOCARD_HAS_VMIXER */ | 
|  | 664 |  | 
|  | 665 | #endif /* ECHOCARD_HAS_DIGITAL_IO */ | 
|  | 666 |  | 
|  | 667 |  | 
|  | 668 |  | 
|  | 669 | static int pcm_hw_free(struct snd_pcm_substream *substream) | 
|  | 670 | { | 
|  | 671 | struct echoaudio *chip; | 
|  | 672 | struct audiopipe *pipe; | 
|  | 673 |  | 
|  | 674 | chip = snd_pcm_substream_chip(substream); | 
|  | 675 | pipe = (struct audiopipe *) substream->runtime->private_data; | 
|  | 676 |  | 
|  | 677 | spin_lock_irq(&chip->lock); | 
|  | 678 | if (pipe->index >= 0) { | 
|  | 679 | DE_HWP(("pcm_hw_free(%d)\n", pipe->index)); | 
|  | 680 | free_pipes(chip, pipe); | 
|  | 681 | chip->substream[pipe->index] = NULL; | 
|  | 682 | pipe->index = -1; | 
|  | 683 | } | 
|  | 684 | spin_unlock_irq(&chip->lock); | 
|  | 685 |  | 
|  | 686 | DE_HWP(("pcm_hw_freed\n")); | 
|  | 687 | snd_pcm_lib_free_pages(substream); | 
|  | 688 | return 0; | 
|  | 689 | } | 
|  | 690 |  | 
|  | 691 |  | 
|  | 692 |  | 
|  | 693 | static int pcm_prepare(struct snd_pcm_substream *substream) | 
|  | 694 | { | 
|  | 695 | struct echoaudio *chip = snd_pcm_substream_chip(substream); | 
|  | 696 | struct snd_pcm_runtime *runtime = substream->runtime; | 
|  | 697 | struct audioformat format; | 
|  | 698 | int pipe_index = ((struct audiopipe *)runtime->private_data)->index; | 
|  | 699 |  | 
|  | 700 | DE_HWP(("Prepare rate=%d format=%d channels=%d\n", | 
|  | 701 | runtime->rate, runtime->format, runtime->channels)); | 
|  | 702 | format.interleave = runtime->channels; | 
|  | 703 | format.data_are_bigendian = 0; | 
|  | 704 | format.mono_to_stereo = 0; | 
|  | 705 | switch (runtime->format) { | 
|  | 706 | case SNDRV_PCM_FORMAT_U8: | 
|  | 707 | format.bits_per_sample = 8; | 
|  | 708 | break; | 
|  | 709 | case SNDRV_PCM_FORMAT_S16_LE: | 
|  | 710 | format.bits_per_sample = 16; | 
|  | 711 | break; | 
|  | 712 | case SNDRV_PCM_FORMAT_S24_3LE: | 
|  | 713 | format.bits_per_sample = 24; | 
|  | 714 | break; | 
|  | 715 | case SNDRV_PCM_FORMAT_S32_BE: | 
|  | 716 | format.data_are_bigendian = 1; | 
|  | 717 | case SNDRV_PCM_FORMAT_S32_LE: | 
|  | 718 | format.bits_per_sample = 32; | 
|  | 719 | break; | 
|  | 720 | default: | 
|  | 721 | DE_HWP(("Prepare error: unsupported format %d\n", | 
|  | 722 | runtime->format)); | 
|  | 723 | return -EINVAL; | 
|  | 724 | } | 
|  | 725 |  | 
| Takashi Iwai | da3cec3 | 2008-08-08 17:12:14 +0200 | [diff] [blame] | 726 | if (snd_BUG_ON(pipe_index >= px_num(chip))) | 
|  | 727 | return -EINVAL; | 
|  | 728 | if (snd_BUG_ON(!is_pipe_allocated(chip, pipe_index))) | 
|  | 729 | return -EINVAL; | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 730 | set_audio_format(chip, pipe_index, &format); | 
|  | 731 | return 0; | 
|  | 732 | } | 
|  | 733 |  | 
|  | 734 |  | 
|  | 735 |  | 
|  | 736 | static int pcm_trigger(struct snd_pcm_substream *substream, int cmd) | 
|  | 737 | { | 
|  | 738 | struct echoaudio *chip = snd_pcm_substream_chip(substream); | 
|  | 739 | struct snd_pcm_runtime *runtime = substream->runtime; | 
|  | 740 | struct audiopipe *pipe = runtime->private_data; | 
|  | 741 | int i, err; | 
|  | 742 | u32 channelmask = 0; | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 743 | struct snd_pcm_substream *s; | 
|  | 744 |  | 
| Takashi Iwai | ef991b9 | 2007-02-22 12:52:53 +0100 | [diff] [blame] | 745 | snd_pcm_group_for_each_entry(s, substream) { | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 746 | for (i = 0; i < DSP_MAXPIPES; i++) { | 
|  | 747 | if (s == chip->substream[i]) { | 
|  | 748 | channelmask |= 1 << i; | 
|  | 749 | snd_pcm_trigger_done(s, substream); | 
|  | 750 | } | 
|  | 751 | } | 
|  | 752 | } | 
|  | 753 |  | 
|  | 754 | spin_lock(&chip->lock); | 
|  | 755 | switch (cmd) { | 
| Giuliano Pochini | 47b5d02 | 2010-02-14 18:16:10 +0100 | [diff] [blame] | 756 | case SNDRV_PCM_TRIGGER_RESUME: | 
|  | 757 | DE_ACT(("pcm_trigger resume\n")); | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 758 | case SNDRV_PCM_TRIGGER_START: | 
|  | 759 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | 
|  | 760 | DE_ACT(("pcm_trigger start\n")); | 
|  | 761 | for (i = 0; i < DSP_MAXPIPES; i++) { | 
|  | 762 | if (channelmask & (1 << i)) { | 
|  | 763 | pipe = chip->substream[i]->runtime->private_data; | 
|  | 764 | switch (pipe->state) { | 
|  | 765 | case PIPE_STATE_STOPPED: | 
|  | 766 | chip->last_period[i] = 0; | 
|  | 767 | pipe->last_counter = 0; | 
|  | 768 | pipe->position = 0; | 
|  | 769 | *pipe->dma_counter = 0; | 
|  | 770 | case PIPE_STATE_PAUSED: | 
|  | 771 | pipe->state = PIPE_STATE_STARTED; | 
|  | 772 | break; | 
|  | 773 | case PIPE_STATE_STARTED: | 
|  | 774 | break; | 
|  | 775 | } | 
|  | 776 | } | 
|  | 777 | } | 
|  | 778 | err = start_transport(chip, channelmask, | 
|  | 779 | chip->pipe_cyclic_mask); | 
|  | 780 | break; | 
| Giuliano Pochini | 47b5d02 | 2010-02-14 18:16:10 +0100 | [diff] [blame] | 781 | case SNDRV_PCM_TRIGGER_SUSPEND: | 
|  | 782 | DE_ACT(("pcm_trigger suspend\n")); | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 783 | case SNDRV_PCM_TRIGGER_STOP: | 
|  | 784 | DE_ACT(("pcm_trigger stop\n")); | 
|  | 785 | for (i = 0; i < DSP_MAXPIPES; i++) { | 
|  | 786 | if (channelmask & (1 << i)) { | 
|  | 787 | pipe = chip->substream[i]->runtime->private_data; | 
|  | 788 | pipe->state = PIPE_STATE_STOPPED; | 
|  | 789 | } | 
|  | 790 | } | 
|  | 791 | err = stop_transport(chip, channelmask); | 
|  | 792 | break; | 
|  | 793 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 
|  | 794 | DE_ACT(("pcm_trigger pause\n")); | 
|  | 795 | for (i = 0; i < DSP_MAXPIPES; i++) { | 
|  | 796 | if (channelmask & (1 << i)) { | 
|  | 797 | pipe = chip->substream[i]->runtime->private_data; | 
|  | 798 | pipe->state = PIPE_STATE_PAUSED; | 
|  | 799 | } | 
|  | 800 | } | 
|  | 801 | err = pause_transport(chip, channelmask); | 
|  | 802 | break; | 
|  | 803 | default: | 
|  | 804 | err = -EINVAL; | 
|  | 805 | } | 
|  | 806 | spin_unlock(&chip->lock); | 
|  | 807 | return err; | 
|  | 808 | } | 
|  | 809 |  | 
|  | 810 |  | 
|  | 811 |  | 
|  | 812 | static snd_pcm_uframes_t pcm_pointer(struct snd_pcm_substream *substream) | 
|  | 813 | { | 
|  | 814 | struct snd_pcm_runtime *runtime = substream->runtime; | 
|  | 815 | struct audiopipe *pipe = runtime->private_data; | 
|  | 816 | size_t cnt, bufsize, pos; | 
|  | 817 |  | 
|  | 818 | cnt = le32_to_cpu(*pipe->dma_counter); | 
|  | 819 | pipe->position += cnt - pipe->last_counter; | 
|  | 820 | pipe->last_counter = cnt; | 
|  | 821 | bufsize = substream->runtime->buffer_size; | 
|  | 822 | pos = bytes_to_frames(substream->runtime, pipe->position); | 
|  | 823 |  | 
|  | 824 | while (pos >= bufsize) { | 
|  | 825 | pipe->position -= frames_to_bytes(substream->runtime, bufsize); | 
|  | 826 | pos -= bufsize; | 
|  | 827 | } | 
|  | 828 | return pos; | 
|  | 829 | } | 
|  | 830 |  | 
|  | 831 |  | 
|  | 832 |  | 
|  | 833 | /* pcm *_ops structures */ | 
|  | 834 | static struct snd_pcm_ops analog_playback_ops = { | 
|  | 835 | .open = pcm_analog_out_open, | 
|  | 836 | .close = pcm_close, | 
|  | 837 | .ioctl = snd_pcm_lib_ioctl, | 
|  | 838 | .hw_params = pcm_analog_out_hw_params, | 
|  | 839 | .hw_free = pcm_hw_free, | 
|  | 840 | .prepare = pcm_prepare, | 
|  | 841 | .trigger = pcm_trigger, | 
|  | 842 | .pointer = pcm_pointer, | 
|  | 843 | .page = snd_pcm_sgbuf_ops_page, | 
|  | 844 | }; | 
|  | 845 | static struct snd_pcm_ops analog_capture_ops = { | 
|  | 846 | .open = pcm_analog_in_open, | 
|  | 847 | .close = pcm_close, | 
|  | 848 | .ioctl = snd_pcm_lib_ioctl, | 
|  | 849 | .hw_params = pcm_analog_in_hw_params, | 
|  | 850 | .hw_free = pcm_hw_free, | 
|  | 851 | .prepare = pcm_prepare, | 
|  | 852 | .trigger = pcm_trigger, | 
|  | 853 | .pointer = pcm_pointer, | 
|  | 854 | .page = snd_pcm_sgbuf_ops_page, | 
|  | 855 | }; | 
|  | 856 | #ifdef ECHOCARD_HAS_DIGITAL_IO | 
|  | 857 | #ifndef ECHOCARD_HAS_VMIXER | 
|  | 858 | static struct snd_pcm_ops digital_playback_ops = { | 
|  | 859 | .open = pcm_digital_out_open, | 
|  | 860 | .close = pcm_close, | 
|  | 861 | .ioctl = snd_pcm_lib_ioctl, | 
|  | 862 | .hw_params = pcm_digital_out_hw_params, | 
|  | 863 | .hw_free = pcm_hw_free, | 
|  | 864 | .prepare = pcm_prepare, | 
|  | 865 | .trigger = pcm_trigger, | 
|  | 866 | .pointer = pcm_pointer, | 
|  | 867 | .page = snd_pcm_sgbuf_ops_page, | 
|  | 868 | }; | 
|  | 869 | #endif /* !ECHOCARD_HAS_VMIXER */ | 
|  | 870 | static struct snd_pcm_ops digital_capture_ops = { | 
|  | 871 | .open = pcm_digital_in_open, | 
|  | 872 | .close = pcm_close, | 
|  | 873 | .ioctl = snd_pcm_lib_ioctl, | 
|  | 874 | .hw_params = pcm_digital_in_hw_params, | 
|  | 875 | .hw_free = pcm_hw_free, | 
|  | 876 | .prepare = pcm_prepare, | 
|  | 877 | .trigger = pcm_trigger, | 
|  | 878 | .pointer = pcm_pointer, | 
|  | 879 | .page = snd_pcm_sgbuf_ops_page, | 
|  | 880 | }; | 
|  | 881 | #endif /* ECHOCARD_HAS_DIGITAL_IO */ | 
|  | 882 |  | 
|  | 883 |  | 
|  | 884 |  | 
|  | 885 | /* Preallocate memory only for the first substream because it's the most | 
|  | 886 | * used one | 
|  | 887 | */ | 
|  | 888 | static int snd_echo_preallocate_pages(struct snd_pcm *pcm, struct device *dev) | 
|  | 889 | { | 
|  | 890 | struct snd_pcm_substream *ss; | 
|  | 891 | int stream, err; | 
|  | 892 |  | 
|  | 893 | for (stream = 0; stream < 2; stream++) | 
|  | 894 | for (ss = pcm->streams[stream].substream; ss; ss = ss->next) { | 
|  | 895 | err = snd_pcm_lib_preallocate_pages(ss, SNDRV_DMA_TYPE_DEV_SG, | 
|  | 896 | dev, | 
|  | 897 | ss->number ? 0 : 128<<10, | 
|  | 898 | 256<<10); | 
|  | 899 | if (err < 0) | 
|  | 900 | return err; | 
|  | 901 | } | 
|  | 902 | return 0; | 
|  | 903 | } | 
|  | 904 |  | 
|  | 905 |  | 
|  | 906 |  | 
|  | 907 | /*<--snd_echo_probe() */ | 
|  | 908 | static int __devinit snd_echo_new_pcm(struct echoaudio *chip) | 
|  | 909 | { | 
|  | 910 | struct snd_pcm *pcm; | 
|  | 911 | int err; | 
|  | 912 |  | 
|  | 913 | #ifdef ECHOCARD_HAS_VMIXER | 
|  | 914 | /* This card has a Vmixer, that is there is no direct mapping from PCM | 
|  | 915 | streams to physical outputs. The user can mix the streams as he wishes | 
|  | 916 | via control interface and it's possible to send any stream to any | 
|  | 917 | output, thus it makes no sense to keep analog and digital outputs | 
|  | 918 | separated */ | 
|  | 919 |  | 
|  | 920 | /* PCM#0 Virtual outputs and analog inputs */ | 
|  | 921 | if ((err = snd_pcm_new(chip->card, "PCM", 0, num_pipes_out(chip), | 
|  | 922 | num_analog_busses_in(chip), &pcm)) < 0) | 
|  | 923 | return err; | 
|  | 924 | pcm->private_data = chip; | 
|  | 925 | chip->analog_pcm = pcm; | 
|  | 926 | strcpy(pcm->name, chip->card->shortname); | 
|  | 927 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &analog_playback_ops); | 
|  | 928 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &analog_capture_ops); | 
|  | 929 | if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0) | 
|  | 930 | return err; | 
|  | 931 | DE_INIT(("Analog PCM ok\n")); | 
|  | 932 |  | 
|  | 933 | #ifdef ECHOCARD_HAS_DIGITAL_IO | 
|  | 934 | /* PCM#1 Digital inputs, no outputs */ | 
|  | 935 | if ((err = snd_pcm_new(chip->card, "Digital PCM", 1, 0, | 
|  | 936 | num_digital_busses_in(chip), &pcm)) < 0) | 
|  | 937 | return err; | 
|  | 938 | pcm->private_data = chip; | 
|  | 939 | chip->digital_pcm = pcm; | 
|  | 940 | strcpy(pcm->name, chip->card->shortname); | 
|  | 941 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &digital_capture_ops); | 
|  | 942 | if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0) | 
|  | 943 | return err; | 
|  | 944 | DE_INIT(("Digital PCM ok\n")); | 
|  | 945 | #endif /* ECHOCARD_HAS_DIGITAL_IO */ | 
|  | 946 |  | 
|  | 947 | #else /* ECHOCARD_HAS_VMIXER */ | 
|  | 948 |  | 
|  | 949 | /* The card can manage substreams formed by analog and digital channels | 
|  | 950 | at the same time, but I prefer to keep analog and digital channels | 
|  | 951 | separated, because that mixed thing is confusing and useless. So we | 
|  | 952 | register two PCM devices: */ | 
|  | 953 |  | 
|  | 954 | /* PCM#0 Analog i/o */ | 
|  | 955 | if ((err = snd_pcm_new(chip->card, "Analog PCM", 0, | 
|  | 956 | num_analog_busses_out(chip), | 
|  | 957 | num_analog_busses_in(chip), &pcm)) < 0) | 
|  | 958 | return err; | 
|  | 959 | pcm->private_data = chip; | 
|  | 960 | chip->analog_pcm = pcm; | 
|  | 961 | strcpy(pcm->name, chip->card->shortname); | 
|  | 962 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &analog_playback_ops); | 
|  | 963 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &analog_capture_ops); | 
|  | 964 | if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0) | 
|  | 965 | return err; | 
|  | 966 | DE_INIT(("Analog PCM ok\n")); | 
|  | 967 |  | 
|  | 968 | #ifdef ECHOCARD_HAS_DIGITAL_IO | 
|  | 969 | /* PCM#1 Digital i/o */ | 
|  | 970 | if ((err = snd_pcm_new(chip->card, "Digital PCM", 1, | 
|  | 971 | num_digital_busses_out(chip), | 
|  | 972 | num_digital_busses_in(chip), &pcm)) < 0) | 
|  | 973 | return err; | 
|  | 974 | pcm->private_data = chip; | 
|  | 975 | chip->digital_pcm = pcm; | 
|  | 976 | strcpy(pcm->name, chip->card->shortname); | 
|  | 977 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &digital_playback_ops); | 
|  | 978 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &digital_capture_ops); | 
|  | 979 | if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0) | 
|  | 980 | return err; | 
|  | 981 | DE_INIT(("Digital PCM ok\n")); | 
|  | 982 | #endif /* ECHOCARD_HAS_DIGITAL_IO */ | 
|  | 983 |  | 
|  | 984 | #endif /* ECHOCARD_HAS_VMIXER */ | 
|  | 985 |  | 
|  | 986 | return 0; | 
|  | 987 | } | 
|  | 988 |  | 
|  | 989 |  | 
|  | 990 |  | 
|  | 991 |  | 
|  | 992 | /****************************************************************************** | 
|  | 993 | Control interface | 
|  | 994 | ******************************************************************************/ | 
|  | 995 |  | 
| Giuliano Pochini | 392bf2f | 2009-09-30 08:26:45 +0200 | [diff] [blame] | 996 | #if !defined(ECHOCARD_HAS_VMIXER) || defined(ECHOCARD_HAS_LINE_OUT_GAIN) | 
| Giuliano Pochini | 9f5d790 | 2009-03-15 21:33:34 +0100 | [diff] [blame] | 997 |  | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 998 | /******************* PCM output volume *******************/ | 
|  | 999 | static int snd_echo_output_gain_info(struct snd_kcontrol *kcontrol, | 
|  | 1000 | struct snd_ctl_elem_info *uinfo) | 
|  | 1001 | { | 
|  | 1002 | struct echoaudio *chip; | 
|  | 1003 |  | 
|  | 1004 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1005 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 
|  | 1006 | uinfo->count = num_busses_out(chip); | 
|  | 1007 | uinfo->value.integer.min = ECHOGAIN_MINOUT; | 
|  | 1008 | uinfo->value.integer.max = ECHOGAIN_MAXOUT; | 
|  | 1009 | return 0; | 
|  | 1010 | } | 
|  | 1011 |  | 
|  | 1012 | static int snd_echo_output_gain_get(struct snd_kcontrol *kcontrol, | 
|  | 1013 | struct snd_ctl_elem_value *ucontrol) | 
|  | 1014 | { | 
|  | 1015 | struct echoaudio *chip; | 
|  | 1016 | int c; | 
|  | 1017 |  | 
|  | 1018 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1019 | for (c = 0; c < num_busses_out(chip); c++) | 
|  | 1020 | ucontrol->value.integer.value[c] = chip->output_gain[c]; | 
|  | 1021 | return 0; | 
|  | 1022 | } | 
|  | 1023 |  | 
|  | 1024 | static int snd_echo_output_gain_put(struct snd_kcontrol *kcontrol, | 
|  | 1025 | struct snd_ctl_elem_value *ucontrol) | 
|  | 1026 | { | 
|  | 1027 | struct echoaudio *chip; | 
|  | 1028 | int c, changed, gain; | 
|  | 1029 |  | 
|  | 1030 | changed = 0; | 
|  | 1031 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1032 | spin_lock_irq(&chip->lock); | 
|  | 1033 | for (c = 0; c < num_busses_out(chip); c++) { | 
|  | 1034 | gain = ucontrol->value.integer.value[c]; | 
|  | 1035 | /* Ignore out of range values */ | 
|  | 1036 | if (gain < ECHOGAIN_MINOUT || gain > ECHOGAIN_MAXOUT) | 
|  | 1037 | continue; | 
|  | 1038 | if (chip->output_gain[c] != gain) { | 
|  | 1039 | set_output_gain(chip, c, gain); | 
|  | 1040 | changed = 1; | 
|  | 1041 | } | 
|  | 1042 | } | 
|  | 1043 | if (changed) | 
|  | 1044 | update_output_line_level(chip); | 
|  | 1045 | spin_unlock_irq(&chip->lock); | 
|  | 1046 | return changed; | 
|  | 1047 | } | 
|  | 1048 |  | 
| Giuliano Pochini | 392bf2f | 2009-09-30 08:26:45 +0200 | [diff] [blame] | 1049 | #ifdef ECHOCARD_HAS_LINE_OUT_GAIN | 
|  | 1050 | /* On the Mia this one controls the line-out volume */ | 
|  | 1051 | static struct snd_kcontrol_new snd_echo_line_output_gain __devinitdata = { | 
|  | 1052 | .name = "Line Playback Volume", | 
|  | 1053 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 
|  | 1054 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | 
|  | 1055 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | 
|  | 1056 | .info = snd_echo_output_gain_info, | 
|  | 1057 | .get = snd_echo_output_gain_get, | 
|  | 1058 | .put = snd_echo_output_gain_put, | 
|  | 1059 | .tlv = {.p = db_scale_output_gain}, | 
|  | 1060 | }; | 
|  | 1061 | #else | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1062 | static struct snd_kcontrol_new snd_echo_pcm_output_gain __devinitdata = { | 
|  | 1063 | .name = "PCM Playback Volume", | 
|  | 1064 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 
| Giuliano Pochini | 048b945 | 2006-11-24 13:03:58 +0100 | [diff] [blame] | 1065 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1066 | .info = snd_echo_output_gain_info, | 
|  | 1067 | .get = snd_echo_output_gain_get, | 
|  | 1068 | .put = snd_echo_output_gain_put, | 
| Giuliano Pochini | 048b945 | 2006-11-24 13:03:58 +0100 | [diff] [blame] | 1069 | .tlv = {.p = db_scale_output_gain}, | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1070 | }; | 
|  | 1071 | #endif | 
|  | 1072 |  | 
| Giuliano Pochini | 392bf2f | 2009-09-30 08:26:45 +0200 | [diff] [blame] | 1073 | #endif /* !ECHOCARD_HAS_VMIXER || ECHOCARD_HAS_LINE_OUT_GAIN */ | 
|  | 1074 |  | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1075 |  | 
|  | 1076 |  | 
|  | 1077 | #ifdef ECHOCARD_HAS_INPUT_GAIN | 
|  | 1078 |  | 
|  | 1079 | /******************* Analog input volume *******************/ | 
|  | 1080 | static int snd_echo_input_gain_info(struct snd_kcontrol *kcontrol, | 
|  | 1081 | struct snd_ctl_elem_info *uinfo) | 
|  | 1082 | { | 
|  | 1083 | struct echoaudio *chip; | 
|  | 1084 |  | 
|  | 1085 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1086 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 
|  | 1087 | uinfo->count = num_analog_busses_in(chip); | 
|  | 1088 | uinfo->value.integer.min = ECHOGAIN_MININP; | 
|  | 1089 | uinfo->value.integer.max = ECHOGAIN_MAXINP; | 
|  | 1090 | return 0; | 
|  | 1091 | } | 
|  | 1092 |  | 
|  | 1093 | static int snd_echo_input_gain_get(struct snd_kcontrol *kcontrol, | 
|  | 1094 | struct snd_ctl_elem_value *ucontrol) | 
|  | 1095 | { | 
|  | 1096 | struct echoaudio *chip; | 
|  | 1097 | int c; | 
|  | 1098 |  | 
|  | 1099 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1100 | for (c = 0; c < num_analog_busses_in(chip); c++) | 
|  | 1101 | ucontrol->value.integer.value[c] = chip->input_gain[c]; | 
|  | 1102 | return 0; | 
|  | 1103 | } | 
|  | 1104 |  | 
|  | 1105 | static int snd_echo_input_gain_put(struct snd_kcontrol *kcontrol, | 
|  | 1106 | struct snd_ctl_elem_value *ucontrol) | 
|  | 1107 | { | 
|  | 1108 | struct echoaudio *chip; | 
|  | 1109 | int c, gain, changed; | 
|  | 1110 |  | 
|  | 1111 | changed = 0; | 
|  | 1112 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1113 | spin_lock_irq(&chip->lock); | 
|  | 1114 | for (c = 0; c < num_analog_busses_in(chip); c++) { | 
|  | 1115 | gain = ucontrol->value.integer.value[c]; | 
|  | 1116 | /* Ignore out of range values */ | 
|  | 1117 | if (gain < ECHOGAIN_MININP || gain > ECHOGAIN_MAXINP) | 
|  | 1118 | continue; | 
|  | 1119 | if (chip->input_gain[c] != gain) { | 
|  | 1120 | set_input_gain(chip, c, gain); | 
|  | 1121 | changed = 1; | 
|  | 1122 | } | 
|  | 1123 | } | 
|  | 1124 | if (changed) | 
|  | 1125 | update_input_line_level(chip); | 
|  | 1126 | spin_unlock_irq(&chip->lock); | 
|  | 1127 | return changed; | 
|  | 1128 | } | 
|  | 1129 |  | 
| Takashi Iwai | 0cb29ea | 2007-01-29 15:33:49 +0100 | [diff] [blame] | 1130 | static const DECLARE_TLV_DB_SCALE(db_scale_input_gain, -2500, 50, 0); | 
| Giuliano Pochini | 048b945 | 2006-11-24 13:03:58 +0100 | [diff] [blame] | 1131 |  | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1132 | static struct snd_kcontrol_new snd_echo_line_input_gain __devinitdata = { | 
|  | 1133 | .name = "Line Capture Volume", | 
|  | 1134 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 
| Giuliano Pochini | 048b945 | 2006-11-24 13:03:58 +0100 | [diff] [blame] | 1135 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1136 | .info = snd_echo_input_gain_info, | 
|  | 1137 | .get = snd_echo_input_gain_get, | 
|  | 1138 | .put = snd_echo_input_gain_put, | 
| Giuliano Pochini | 048b945 | 2006-11-24 13:03:58 +0100 | [diff] [blame] | 1139 | .tlv = {.p = db_scale_input_gain}, | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1140 | }; | 
|  | 1141 |  | 
|  | 1142 | #endif /* ECHOCARD_HAS_INPUT_GAIN */ | 
|  | 1143 |  | 
|  | 1144 |  | 
|  | 1145 |  | 
|  | 1146 | #ifdef ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL | 
|  | 1147 |  | 
|  | 1148 | /************ Analog output nominal level (+4dBu / -10dBV) ***************/ | 
|  | 1149 | static int snd_echo_output_nominal_info (struct snd_kcontrol *kcontrol, | 
|  | 1150 | struct snd_ctl_elem_info *uinfo) | 
|  | 1151 | { | 
|  | 1152 | struct echoaudio *chip; | 
|  | 1153 |  | 
|  | 1154 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1155 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | 
|  | 1156 | uinfo->count = num_analog_busses_out(chip); | 
|  | 1157 | uinfo->value.integer.min = 0; | 
|  | 1158 | uinfo->value.integer.max = 1; | 
|  | 1159 | return 0; | 
|  | 1160 | } | 
|  | 1161 |  | 
|  | 1162 | static int snd_echo_output_nominal_get(struct snd_kcontrol *kcontrol, | 
|  | 1163 | struct snd_ctl_elem_value *ucontrol) | 
|  | 1164 | { | 
|  | 1165 | struct echoaudio *chip; | 
|  | 1166 | int c; | 
|  | 1167 |  | 
|  | 1168 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1169 | for (c = 0; c < num_analog_busses_out(chip); c++) | 
|  | 1170 | ucontrol->value.integer.value[c] = chip->nominal_level[c]; | 
|  | 1171 | return 0; | 
|  | 1172 | } | 
|  | 1173 |  | 
|  | 1174 | static int snd_echo_output_nominal_put(struct snd_kcontrol *kcontrol, | 
|  | 1175 | struct snd_ctl_elem_value *ucontrol) | 
|  | 1176 | { | 
|  | 1177 | struct echoaudio *chip; | 
|  | 1178 | int c, changed; | 
|  | 1179 |  | 
|  | 1180 | changed = 0; | 
|  | 1181 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1182 | spin_lock_irq(&chip->lock); | 
|  | 1183 | for (c = 0; c < num_analog_busses_out(chip); c++) { | 
|  | 1184 | if (chip->nominal_level[c] != ucontrol->value.integer.value[c]) { | 
|  | 1185 | set_nominal_level(chip, c, | 
|  | 1186 | ucontrol->value.integer.value[c]); | 
|  | 1187 | changed = 1; | 
|  | 1188 | } | 
|  | 1189 | } | 
|  | 1190 | if (changed) | 
|  | 1191 | update_output_line_level(chip); | 
|  | 1192 | spin_unlock_irq(&chip->lock); | 
|  | 1193 | return changed; | 
|  | 1194 | } | 
|  | 1195 |  | 
|  | 1196 | static struct snd_kcontrol_new snd_echo_output_nominal_level __devinitdata = { | 
|  | 1197 | .name = "Line Playback Switch (-10dBV)", | 
|  | 1198 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 
|  | 1199 | .info = snd_echo_output_nominal_info, | 
|  | 1200 | .get = snd_echo_output_nominal_get, | 
|  | 1201 | .put = snd_echo_output_nominal_put, | 
|  | 1202 | }; | 
|  | 1203 |  | 
|  | 1204 | #endif /* ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL */ | 
|  | 1205 |  | 
|  | 1206 |  | 
|  | 1207 |  | 
|  | 1208 | #ifdef ECHOCARD_HAS_INPUT_NOMINAL_LEVEL | 
|  | 1209 |  | 
|  | 1210 | /*************** Analog input nominal level (+4dBu / -10dBV) ***************/ | 
|  | 1211 | static int snd_echo_input_nominal_info(struct snd_kcontrol *kcontrol, | 
|  | 1212 | struct snd_ctl_elem_info *uinfo) | 
|  | 1213 | { | 
|  | 1214 | struct echoaudio *chip; | 
|  | 1215 |  | 
|  | 1216 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1217 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | 
|  | 1218 | uinfo->count = num_analog_busses_in(chip); | 
|  | 1219 | uinfo->value.integer.min = 0; | 
|  | 1220 | uinfo->value.integer.max = 1; | 
|  | 1221 | return 0; | 
|  | 1222 | } | 
|  | 1223 |  | 
|  | 1224 | static int snd_echo_input_nominal_get(struct snd_kcontrol *kcontrol, | 
|  | 1225 | struct snd_ctl_elem_value *ucontrol) | 
|  | 1226 | { | 
|  | 1227 | struct echoaudio *chip; | 
|  | 1228 | int c; | 
|  | 1229 |  | 
|  | 1230 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1231 | for (c = 0; c < num_analog_busses_in(chip); c++) | 
|  | 1232 | ucontrol->value.integer.value[c] = | 
|  | 1233 | chip->nominal_level[bx_analog_in(chip) + c]; | 
|  | 1234 | return 0; | 
|  | 1235 | } | 
|  | 1236 |  | 
|  | 1237 | static int snd_echo_input_nominal_put(struct snd_kcontrol *kcontrol, | 
|  | 1238 | struct snd_ctl_elem_value *ucontrol) | 
|  | 1239 | { | 
|  | 1240 | struct echoaudio *chip; | 
|  | 1241 | int c, changed; | 
|  | 1242 |  | 
|  | 1243 | changed = 0; | 
|  | 1244 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1245 | spin_lock_irq(&chip->lock); | 
|  | 1246 | for (c = 0; c < num_analog_busses_in(chip); c++) { | 
|  | 1247 | if (chip->nominal_level[bx_analog_in(chip) + c] != | 
|  | 1248 | ucontrol->value.integer.value[c]) { | 
|  | 1249 | set_nominal_level(chip, bx_analog_in(chip) + c, | 
|  | 1250 | ucontrol->value.integer.value[c]); | 
|  | 1251 | changed = 1; | 
|  | 1252 | } | 
|  | 1253 | } | 
|  | 1254 | if (changed) | 
|  | 1255 | update_output_line_level(chip);	/* "Output" is not a mistake | 
|  | 1256 | * here. | 
|  | 1257 | */ | 
|  | 1258 | spin_unlock_irq(&chip->lock); | 
|  | 1259 | return changed; | 
|  | 1260 | } | 
|  | 1261 |  | 
|  | 1262 | static struct snd_kcontrol_new snd_echo_intput_nominal_level __devinitdata = { | 
|  | 1263 | .name = "Line Capture Switch (-10dBV)", | 
|  | 1264 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 
|  | 1265 | .info = snd_echo_input_nominal_info, | 
|  | 1266 | .get = snd_echo_input_nominal_get, | 
|  | 1267 | .put = snd_echo_input_nominal_put, | 
|  | 1268 | }; | 
|  | 1269 |  | 
|  | 1270 | #endif /* ECHOCARD_HAS_INPUT_NOMINAL_LEVEL */ | 
|  | 1271 |  | 
|  | 1272 |  | 
|  | 1273 |  | 
|  | 1274 | #ifdef ECHOCARD_HAS_MONITOR | 
|  | 1275 |  | 
|  | 1276 | /******************* Monitor mixer *******************/ | 
|  | 1277 | static int snd_echo_mixer_info(struct snd_kcontrol *kcontrol, | 
|  | 1278 | struct snd_ctl_elem_info *uinfo) | 
|  | 1279 | { | 
|  | 1280 | struct echoaudio *chip; | 
|  | 1281 |  | 
|  | 1282 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1283 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 
|  | 1284 | uinfo->count = 1; | 
|  | 1285 | uinfo->value.integer.min = ECHOGAIN_MINOUT; | 
|  | 1286 | uinfo->value.integer.max = ECHOGAIN_MAXOUT; | 
|  | 1287 | uinfo->dimen.d[0] = num_busses_out(chip); | 
|  | 1288 | uinfo->dimen.d[1] = num_busses_in(chip); | 
|  | 1289 | return 0; | 
|  | 1290 | } | 
|  | 1291 |  | 
|  | 1292 | static int snd_echo_mixer_get(struct snd_kcontrol *kcontrol, | 
|  | 1293 | struct snd_ctl_elem_value *ucontrol) | 
|  | 1294 | { | 
|  | 1295 | struct echoaudio *chip; | 
|  | 1296 |  | 
|  | 1297 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1298 | ucontrol->value.integer.value[0] = | 
|  | 1299 | chip->monitor_gain[ucontrol->id.index / num_busses_in(chip)] | 
|  | 1300 | [ucontrol->id.index % num_busses_in(chip)]; | 
|  | 1301 | return 0; | 
|  | 1302 | } | 
|  | 1303 |  | 
|  | 1304 | static int snd_echo_mixer_put(struct snd_kcontrol *kcontrol, | 
|  | 1305 | struct snd_ctl_elem_value *ucontrol) | 
|  | 1306 | { | 
|  | 1307 | struct echoaudio *chip; | 
|  | 1308 | int changed,  gain; | 
|  | 1309 | short out, in; | 
|  | 1310 |  | 
|  | 1311 | changed = 0; | 
|  | 1312 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1313 | out = ucontrol->id.index / num_busses_in(chip); | 
|  | 1314 | in = ucontrol->id.index % num_busses_in(chip); | 
|  | 1315 | gain = ucontrol->value.integer.value[0]; | 
|  | 1316 | if (gain < ECHOGAIN_MINOUT || gain > ECHOGAIN_MAXOUT) | 
|  | 1317 | return -EINVAL; | 
|  | 1318 | if (chip->monitor_gain[out][in] != gain) { | 
|  | 1319 | spin_lock_irq(&chip->lock); | 
|  | 1320 | set_monitor_gain(chip, out, in, gain); | 
|  | 1321 | update_output_line_level(chip); | 
|  | 1322 | spin_unlock_irq(&chip->lock); | 
|  | 1323 | changed = 1; | 
|  | 1324 | } | 
|  | 1325 | return changed; | 
|  | 1326 | } | 
|  | 1327 |  | 
|  | 1328 | static struct snd_kcontrol_new snd_echo_monitor_mixer __devinitdata = { | 
|  | 1329 | .name = "Monitor Mixer Volume", | 
|  | 1330 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 
| Giuliano Pochini | 048b945 | 2006-11-24 13:03:58 +0100 | [diff] [blame] | 1331 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1332 | .info = snd_echo_mixer_info, | 
|  | 1333 | .get = snd_echo_mixer_get, | 
|  | 1334 | .put = snd_echo_mixer_put, | 
| Giuliano Pochini | 048b945 | 2006-11-24 13:03:58 +0100 | [diff] [blame] | 1335 | .tlv = {.p = db_scale_output_gain}, | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1336 | }; | 
|  | 1337 |  | 
|  | 1338 | #endif /* ECHOCARD_HAS_MONITOR */ | 
|  | 1339 |  | 
|  | 1340 |  | 
|  | 1341 |  | 
|  | 1342 | #ifdef ECHOCARD_HAS_VMIXER | 
|  | 1343 |  | 
|  | 1344 | /******************* Vmixer *******************/ | 
|  | 1345 | static int snd_echo_vmixer_info(struct snd_kcontrol *kcontrol, | 
|  | 1346 | struct snd_ctl_elem_info *uinfo) | 
|  | 1347 | { | 
|  | 1348 | struct echoaudio *chip; | 
|  | 1349 |  | 
|  | 1350 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1351 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 
|  | 1352 | uinfo->count = 1; | 
|  | 1353 | uinfo->value.integer.min = ECHOGAIN_MINOUT; | 
|  | 1354 | uinfo->value.integer.max = ECHOGAIN_MAXOUT; | 
|  | 1355 | uinfo->dimen.d[0] = num_busses_out(chip); | 
|  | 1356 | uinfo->dimen.d[1] = num_pipes_out(chip); | 
|  | 1357 | return 0; | 
|  | 1358 | } | 
|  | 1359 |  | 
|  | 1360 | static int snd_echo_vmixer_get(struct snd_kcontrol *kcontrol, | 
|  | 1361 | struct snd_ctl_elem_value *ucontrol) | 
|  | 1362 | { | 
|  | 1363 | struct echoaudio *chip; | 
|  | 1364 |  | 
|  | 1365 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1366 | ucontrol->value.integer.value[0] = | 
|  | 1367 | chip->vmixer_gain[ucontrol->id.index / num_pipes_out(chip)] | 
|  | 1368 | [ucontrol->id.index % num_pipes_out(chip)]; | 
|  | 1369 | return 0; | 
|  | 1370 | } | 
|  | 1371 |  | 
|  | 1372 | static int snd_echo_vmixer_put(struct snd_kcontrol *kcontrol, | 
|  | 1373 | struct snd_ctl_elem_value *ucontrol) | 
|  | 1374 | { | 
|  | 1375 | struct echoaudio *chip; | 
|  | 1376 | int gain, changed; | 
|  | 1377 | short vch, out; | 
|  | 1378 |  | 
|  | 1379 | changed = 0; | 
|  | 1380 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1381 | out = ucontrol->id.index / num_pipes_out(chip); | 
|  | 1382 | vch = ucontrol->id.index % num_pipes_out(chip); | 
|  | 1383 | gain = ucontrol->value.integer.value[0]; | 
|  | 1384 | if (gain < ECHOGAIN_MINOUT || gain > ECHOGAIN_MAXOUT) | 
|  | 1385 | return -EINVAL; | 
|  | 1386 | if (chip->vmixer_gain[out][vch] != ucontrol->value.integer.value[0]) { | 
|  | 1387 | spin_lock_irq(&chip->lock); | 
|  | 1388 | set_vmixer_gain(chip, out, vch, ucontrol->value.integer.value[0]); | 
|  | 1389 | update_vmixer_level(chip); | 
|  | 1390 | spin_unlock_irq(&chip->lock); | 
|  | 1391 | changed = 1; | 
|  | 1392 | } | 
|  | 1393 | return changed; | 
|  | 1394 | } | 
|  | 1395 |  | 
|  | 1396 | static struct snd_kcontrol_new snd_echo_vmixer __devinitdata = { | 
|  | 1397 | .name = "VMixer Volume", | 
|  | 1398 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 
| Giuliano Pochini | 048b945 | 2006-11-24 13:03:58 +0100 | [diff] [blame] | 1399 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1400 | .info = snd_echo_vmixer_info, | 
|  | 1401 | .get = snd_echo_vmixer_get, | 
|  | 1402 | .put = snd_echo_vmixer_put, | 
| Giuliano Pochini | 048b945 | 2006-11-24 13:03:58 +0100 | [diff] [blame] | 1403 | .tlv = {.p = db_scale_output_gain}, | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1404 | }; | 
|  | 1405 |  | 
|  | 1406 | #endif /* ECHOCARD_HAS_VMIXER */ | 
|  | 1407 |  | 
|  | 1408 |  | 
|  | 1409 |  | 
|  | 1410 | #ifdef ECHOCARD_HAS_DIGITAL_MODE_SWITCH | 
|  | 1411 |  | 
|  | 1412 | /******************* Digital mode switch *******************/ | 
|  | 1413 | static int snd_echo_digital_mode_info(struct snd_kcontrol *kcontrol, | 
|  | 1414 | struct snd_ctl_elem_info *uinfo) | 
|  | 1415 | { | 
|  | 1416 | static char *names[4] = { | 
|  | 1417 | "S/PDIF Coaxial", "S/PDIF Optical", "ADAT Optical", | 
|  | 1418 | "S/PDIF Cdrom" | 
|  | 1419 | }; | 
|  | 1420 | struct echoaudio *chip; | 
|  | 1421 |  | 
|  | 1422 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1423 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 
|  | 1424 | uinfo->value.enumerated.items = chip->num_digital_modes; | 
|  | 1425 | uinfo->count = 1; | 
|  | 1426 | if (uinfo->value.enumerated.item >= chip->num_digital_modes) | 
|  | 1427 | uinfo->value.enumerated.item = chip->num_digital_modes - 1; | 
|  | 1428 | strcpy(uinfo->value.enumerated.name, names[ | 
|  | 1429 | chip->digital_mode_list[uinfo->value.enumerated.item]]); | 
|  | 1430 | return 0; | 
|  | 1431 | } | 
|  | 1432 |  | 
|  | 1433 | static int snd_echo_digital_mode_get(struct snd_kcontrol *kcontrol, | 
|  | 1434 | struct snd_ctl_elem_value *ucontrol) | 
|  | 1435 | { | 
|  | 1436 | struct echoaudio *chip; | 
|  | 1437 | int i, mode; | 
|  | 1438 |  | 
|  | 1439 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1440 | mode = chip->digital_mode; | 
|  | 1441 | for (i = chip->num_digital_modes - 1; i >= 0; i--) | 
|  | 1442 | if (mode == chip->digital_mode_list[i]) { | 
|  | 1443 | ucontrol->value.enumerated.item[0] = i; | 
|  | 1444 | break; | 
|  | 1445 | } | 
|  | 1446 | return 0; | 
|  | 1447 | } | 
|  | 1448 |  | 
|  | 1449 | static int snd_echo_digital_mode_put(struct snd_kcontrol *kcontrol, | 
|  | 1450 | struct snd_ctl_elem_value *ucontrol) | 
|  | 1451 | { | 
|  | 1452 | struct echoaudio *chip; | 
|  | 1453 | int changed; | 
|  | 1454 | unsigned short emode, dmode; | 
|  | 1455 |  | 
|  | 1456 | changed = 0; | 
|  | 1457 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1458 |  | 
|  | 1459 | emode = ucontrol->value.enumerated.item[0]; | 
|  | 1460 | if (emode >= chip->num_digital_modes) | 
|  | 1461 | return -EINVAL; | 
|  | 1462 | dmode = chip->digital_mode_list[emode]; | 
|  | 1463 |  | 
|  | 1464 | if (dmode != chip->digital_mode) { | 
|  | 1465 | /* mode_mutex is required to make this operation atomic wrt | 
|  | 1466 | pcm_digital_*_open() and set_input_clock() functions. */ | 
| Takashi Iwai | befceea | 2007-12-03 17:08:40 +0100 | [diff] [blame] | 1467 | mutex_lock(&chip->mode_mutex); | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1468 |  | 
|  | 1469 | /* Do not allow the user to change the digital mode when a pcm | 
|  | 1470 | device is open because it also changes the number of channels | 
|  | 1471 | and the allowed sample rates */ | 
|  | 1472 | if (atomic_read(&chip->opencount)) { | 
|  | 1473 | changed = -EAGAIN; | 
|  | 1474 | } else { | 
|  | 1475 | changed = set_digital_mode(chip, dmode); | 
|  | 1476 | /* If we had to change the clock source, report it */ | 
|  | 1477 | if (changed > 0 && chip->clock_src_ctl) { | 
|  | 1478 | snd_ctl_notify(chip->card, | 
|  | 1479 | SNDRV_CTL_EVENT_MASK_VALUE, | 
|  | 1480 | &chip->clock_src_ctl->id); | 
|  | 1481 | DE_ACT(("SDM() =%d\n", changed)); | 
|  | 1482 | } | 
|  | 1483 | if (changed >= 0) | 
|  | 1484 | changed = 1;	/* No errors */ | 
|  | 1485 | } | 
| Takashi Iwai | befceea | 2007-12-03 17:08:40 +0100 | [diff] [blame] | 1486 | mutex_unlock(&chip->mode_mutex); | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1487 | } | 
|  | 1488 | return changed; | 
|  | 1489 | } | 
|  | 1490 |  | 
|  | 1491 | static struct snd_kcontrol_new snd_echo_digital_mode_switch __devinitdata = { | 
|  | 1492 | .name = "Digital mode Switch", | 
|  | 1493 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, | 
|  | 1494 | .info = snd_echo_digital_mode_info, | 
|  | 1495 | .get = snd_echo_digital_mode_get, | 
|  | 1496 | .put = snd_echo_digital_mode_put, | 
|  | 1497 | }; | 
|  | 1498 |  | 
|  | 1499 | #endif /* ECHOCARD_HAS_DIGITAL_MODE_SWITCH */ | 
|  | 1500 |  | 
|  | 1501 |  | 
|  | 1502 |  | 
|  | 1503 | #ifdef ECHOCARD_HAS_DIGITAL_IO | 
|  | 1504 |  | 
|  | 1505 | /******************* S/PDIF mode switch *******************/ | 
|  | 1506 | static int snd_echo_spdif_mode_info(struct snd_kcontrol *kcontrol, | 
|  | 1507 | struct snd_ctl_elem_info *uinfo) | 
|  | 1508 | { | 
|  | 1509 | static char *names[2] = {"Consumer", "Professional"}; | 
|  | 1510 |  | 
|  | 1511 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 
|  | 1512 | uinfo->value.enumerated.items = 2; | 
|  | 1513 | uinfo->count = 1; | 
|  | 1514 | if (uinfo->value.enumerated.item) | 
|  | 1515 | uinfo->value.enumerated.item = 1; | 
|  | 1516 | strcpy(uinfo->value.enumerated.name, | 
|  | 1517 | names[uinfo->value.enumerated.item]); | 
|  | 1518 | return 0; | 
|  | 1519 | } | 
|  | 1520 |  | 
|  | 1521 | static int snd_echo_spdif_mode_get(struct snd_kcontrol *kcontrol, | 
|  | 1522 | struct snd_ctl_elem_value *ucontrol) | 
|  | 1523 | { | 
|  | 1524 | struct echoaudio *chip; | 
|  | 1525 |  | 
|  | 1526 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1527 | ucontrol->value.enumerated.item[0] = !!chip->professional_spdif; | 
|  | 1528 | return 0; | 
|  | 1529 | } | 
|  | 1530 |  | 
|  | 1531 | static int snd_echo_spdif_mode_put(struct snd_kcontrol *kcontrol, | 
|  | 1532 | struct snd_ctl_elem_value *ucontrol) | 
|  | 1533 | { | 
|  | 1534 | struct echoaudio *chip; | 
|  | 1535 | int mode; | 
|  | 1536 |  | 
|  | 1537 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1538 | mode = !!ucontrol->value.enumerated.item[0]; | 
|  | 1539 | if (mode != chip->professional_spdif) { | 
|  | 1540 | spin_lock_irq(&chip->lock); | 
|  | 1541 | set_professional_spdif(chip, mode); | 
|  | 1542 | spin_unlock_irq(&chip->lock); | 
|  | 1543 | return 1; | 
|  | 1544 | } | 
|  | 1545 | return 0; | 
|  | 1546 | } | 
|  | 1547 |  | 
|  | 1548 | static struct snd_kcontrol_new snd_echo_spdif_mode_switch __devinitdata = { | 
|  | 1549 | .name = "S/PDIF mode Switch", | 
|  | 1550 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, | 
|  | 1551 | .info = snd_echo_spdif_mode_info, | 
|  | 1552 | .get = snd_echo_spdif_mode_get, | 
|  | 1553 | .put = snd_echo_spdif_mode_put, | 
|  | 1554 | }; | 
|  | 1555 |  | 
|  | 1556 | #endif /* ECHOCARD_HAS_DIGITAL_IO */ | 
|  | 1557 |  | 
|  | 1558 |  | 
|  | 1559 |  | 
|  | 1560 | #ifdef ECHOCARD_HAS_EXTERNAL_CLOCK | 
|  | 1561 |  | 
|  | 1562 | /******************* Select input clock source *******************/ | 
|  | 1563 | static int snd_echo_clock_source_info(struct snd_kcontrol *kcontrol, | 
|  | 1564 | struct snd_ctl_elem_info *uinfo) | 
|  | 1565 | { | 
|  | 1566 | static char *names[8] = { | 
|  | 1567 | "Internal", "Word", "Super", "S/PDIF", "ADAT", "ESync", | 
|  | 1568 | "ESync96", "MTC" | 
|  | 1569 | }; | 
|  | 1570 | struct echoaudio *chip; | 
|  | 1571 |  | 
|  | 1572 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1573 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | 
|  | 1574 | uinfo->value.enumerated.items = chip->num_clock_sources; | 
|  | 1575 | uinfo->count = 1; | 
|  | 1576 | if (uinfo->value.enumerated.item >= chip->num_clock_sources) | 
|  | 1577 | uinfo->value.enumerated.item = chip->num_clock_sources - 1; | 
|  | 1578 | strcpy(uinfo->value.enumerated.name, names[ | 
|  | 1579 | chip->clock_source_list[uinfo->value.enumerated.item]]); | 
|  | 1580 | return 0; | 
|  | 1581 | } | 
|  | 1582 |  | 
|  | 1583 | static int snd_echo_clock_source_get(struct snd_kcontrol *kcontrol, | 
|  | 1584 | struct snd_ctl_elem_value *ucontrol) | 
|  | 1585 | { | 
|  | 1586 | struct echoaudio *chip; | 
|  | 1587 | int i, clock; | 
|  | 1588 |  | 
|  | 1589 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1590 | clock = chip->input_clock; | 
|  | 1591 |  | 
|  | 1592 | for (i = 0; i < chip->num_clock_sources; i++) | 
|  | 1593 | if (clock == chip->clock_source_list[i]) | 
|  | 1594 | ucontrol->value.enumerated.item[0] = i; | 
|  | 1595 |  | 
|  | 1596 | return 0; | 
|  | 1597 | } | 
|  | 1598 |  | 
|  | 1599 | static int snd_echo_clock_source_put(struct snd_kcontrol *kcontrol, | 
|  | 1600 | struct snd_ctl_elem_value *ucontrol) | 
|  | 1601 | { | 
|  | 1602 | struct echoaudio *chip; | 
|  | 1603 | int changed; | 
|  | 1604 | unsigned int eclock, dclock; | 
|  | 1605 |  | 
|  | 1606 | changed = 0; | 
|  | 1607 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1608 | eclock = ucontrol->value.enumerated.item[0]; | 
|  | 1609 | if (eclock >= chip->input_clock_types) | 
|  | 1610 | return -EINVAL; | 
|  | 1611 | dclock = chip->clock_source_list[eclock]; | 
|  | 1612 | if (chip->input_clock != dclock) { | 
| Takashi Iwai | befceea | 2007-12-03 17:08:40 +0100 | [diff] [blame] | 1613 | mutex_lock(&chip->mode_mutex); | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1614 | spin_lock_irq(&chip->lock); | 
|  | 1615 | if ((changed = set_input_clock(chip, dclock)) == 0) | 
|  | 1616 | changed = 1;	/* no errors */ | 
|  | 1617 | spin_unlock_irq(&chip->lock); | 
| Takashi Iwai | befceea | 2007-12-03 17:08:40 +0100 | [diff] [blame] | 1618 | mutex_unlock(&chip->mode_mutex); | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1619 | } | 
|  | 1620 |  | 
|  | 1621 | if (changed < 0) | 
|  | 1622 | DE_ACT(("seticlk val%d err 0x%x\n", dclock, changed)); | 
|  | 1623 |  | 
|  | 1624 | return changed; | 
|  | 1625 | } | 
|  | 1626 |  | 
|  | 1627 | static struct snd_kcontrol_new snd_echo_clock_source_switch __devinitdata = { | 
|  | 1628 | .name = "Sample Clock Source", | 
|  | 1629 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | 
|  | 1630 | .info = snd_echo_clock_source_info, | 
|  | 1631 | .get = snd_echo_clock_source_get, | 
|  | 1632 | .put = snd_echo_clock_source_put, | 
|  | 1633 | }; | 
|  | 1634 |  | 
|  | 1635 | #endif /* ECHOCARD_HAS_EXTERNAL_CLOCK */ | 
|  | 1636 |  | 
|  | 1637 |  | 
|  | 1638 |  | 
|  | 1639 | #ifdef ECHOCARD_HAS_PHANTOM_POWER | 
|  | 1640 |  | 
|  | 1641 | /******************* Phantom power switch *******************/ | 
| Takashi Iwai | a5ce889 | 2007-07-23 15:42:26 +0200 | [diff] [blame] | 1642 | #define snd_echo_phantom_power_info	snd_ctl_boolean_mono_info | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1643 |  | 
|  | 1644 | static int snd_echo_phantom_power_get(struct snd_kcontrol *kcontrol, | 
|  | 1645 | struct snd_ctl_elem_value *ucontrol) | 
|  | 1646 | { | 
|  | 1647 | struct echoaudio *chip = snd_kcontrol_chip(kcontrol); | 
|  | 1648 |  | 
|  | 1649 | ucontrol->value.integer.value[0] = chip->phantom_power; | 
|  | 1650 | return 0; | 
|  | 1651 | } | 
|  | 1652 |  | 
|  | 1653 | static int snd_echo_phantom_power_put(struct snd_kcontrol *kcontrol, | 
|  | 1654 | struct snd_ctl_elem_value *ucontrol) | 
|  | 1655 | { | 
|  | 1656 | struct echoaudio *chip = snd_kcontrol_chip(kcontrol); | 
|  | 1657 | int power, changed = 0; | 
|  | 1658 |  | 
|  | 1659 | power = !!ucontrol->value.integer.value[0]; | 
|  | 1660 | if (chip->phantom_power != power) { | 
|  | 1661 | spin_lock_irq(&chip->lock); | 
|  | 1662 | changed = set_phantom_power(chip, power); | 
|  | 1663 | spin_unlock_irq(&chip->lock); | 
|  | 1664 | if (changed == 0) | 
|  | 1665 | changed = 1;	/* no errors */ | 
|  | 1666 | } | 
|  | 1667 | return changed; | 
|  | 1668 | } | 
|  | 1669 |  | 
|  | 1670 | static struct snd_kcontrol_new snd_echo_phantom_power_switch __devinitdata = { | 
|  | 1671 | .name = "Phantom power Switch", | 
|  | 1672 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, | 
|  | 1673 | .info = snd_echo_phantom_power_info, | 
|  | 1674 | .get = snd_echo_phantom_power_get, | 
|  | 1675 | .put = snd_echo_phantom_power_put, | 
|  | 1676 | }; | 
|  | 1677 |  | 
|  | 1678 | #endif /* ECHOCARD_HAS_PHANTOM_POWER */ | 
|  | 1679 |  | 
|  | 1680 |  | 
|  | 1681 |  | 
|  | 1682 | #ifdef ECHOCARD_HAS_DIGITAL_IN_AUTOMUTE | 
|  | 1683 |  | 
|  | 1684 | /******************* Digital input automute switch *******************/ | 
| Takashi Iwai | a5ce889 | 2007-07-23 15:42:26 +0200 | [diff] [blame] | 1685 | #define snd_echo_automute_info		snd_ctl_boolean_mono_info | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1686 |  | 
|  | 1687 | static int snd_echo_automute_get(struct snd_kcontrol *kcontrol, | 
|  | 1688 | struct snd_ctl_elem_value *ucontrol) | 
|  | 1689 | { | 
|  | 1690 | struct echoaudio *chip = snd_kcontrol_chip(kcontrol); | 
|  | 1691 |  | 
|  | 1692 | ucontrol->value.integer.value[0] = chip->digital_in_automute; | 
|  | 1693 | return 0; | 
|  | 1694 | } | 
|  | 1695 |  | 
|  | 1696 | static int snd_echo_automute_put(struct snd_kcontrol *kcontrol, | 
|  | 1697 | struct snd_ctl_elem_value *ucontrol) | 
|  | 1698 | { | 
|  | 1699 | struct echoaudio *chip = snd_kcontrol_chip(kcontrol); | 
|  | 1700 | int automute, changed = 0; | 
|  | 1701 |  | 
|  | 1702 | automute = !!ucontrol->value.integer.value[0]; | 
|  | 1703 | if (chip->digital_in_automute != automute) { | 
|  | 1704 | spin_lock_irq(&chip->lock); | 
|  | 1705 | changed = set_input_auto_mute(chip, automute); | 
|  | 1706 | spin_unlock_irq(&chip->lock); | 
|  | 1707 | if (changed == 0) | 
|  | 1708 | changed = 1;	/* no errors */ | 
|  | 1709 | } | 
|  | 1710 | return changed; | 
|  | 1711 | } | 
|  | 1712 |  | 
|  | 1713 | static struct snd_kcontrol_new snd_echo_automute_switch __devinitdata = { | 
|  | 1714 | .name = "Digital Capture Switch (automute)", | 
|  | 1715 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, | 
|  | 1716 | .info = snd_echo_automute_info, | 
|  | 1717 | .get = snd_echo_automute_get, | 
|  | 1718 | .put = snd_echo_automute_put, | 
|  | 1719 | }; | 
|  | 1720 |  | 
|  | 1721 | #endif /* ECHOCARD_HAS_DIGITAL_IN_AUTOMUTE */ | 
|  | 1722 |  | 
|  | 1723 |  | 
|  | 1724 |  | 
|  | 1725 | /******************* VU-meters switch *******************/ | 
| Takashi Iwai | a5ce889 | 2007-07-23 15:42:26 +0200 | [diff] [blame] | 1726 | #define snd_echo_vumeters_switch_info		snd_ctl_boolean_mono_info | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1727 |  | 
|  | 1728 | static int snd_echo_vumeters_switch_put(struct snd_kcontrol *kcontrol, | 
|  | 1729 | struct snd_ctl_elem_value *ucontrol) | 
|  | 1730 | { | 
|  | 1731 | struct echoaudio *chip; | 
|  | 1732 |  | 
|  | 1733 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1734 | spin_lock_irq(&chip->lock); | 
|  | 1735 | set_meters_on(chip, ucontrol->value.integer.value[0]); | 
|  | 1736 | spin_unlock_irq(&chip->lock); | 
|  | 1737 | return 1; | 
|  | 1738 | } | 
|  | 1739 |  | 
|  | 1740 | static struct snd_kcontrol_new snd_echo_vumeters_switch __devinitdata = { | 
|  | 1741 | .name = "VU-meters Switch", | 
|  | 1742 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, | 
|  | 1743 | .access = SNDRV_CTL_ELEM_ACCESS_WRITE, | 
|  | 1744 | .info = snd_echo_vumeters_switch_info, | 
|  | 1745 | .put = snd_echo_vumeters_switch_put, | 
|  | 1746 | }; | 
|  | 1747 |  | 
|  | 1748 |  | 
|  | 1749 |  | 
|  | 1750 | /***** Read VU-meters (input, output, analog and digital together) *****/ | 
|  | 1751 | static int snd_echo_vumeters_info(struct snd_kcontrol *kcontrol, | 
|  | 1752 | struct snd_ctl_elem_info *uinfo) | 
|  | 1753 | { | 
|  | 1754 | struct echoaudio *chip; | 
|  | 1755 |  | 
|  | 1756 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1757 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 
|  | 1758 | uinfo->count = 96; | 
|  | 1759 | uinfo->value.integer.min = ECHOGAIN_MINOUT; | 
|  | 1760 | uinfo->value.integer.max = 0; | 
|  | 1761 | #ifdef ECHOCARD_HAS_VMIXER | 
|  | 1762 | uinfo->dimen.d[0] = 3;	/* Out, In, Virt */ | 
|  | 1763 | #else | 
|  | 1764 | uinfo->dimen.d[0] = 2;	/* Out, In */ | 
|  | 1765 | #endif | 
|  | 1766 | uinfo->dimen.d[1] = 16;	/* 16 channels */ | 
|  | 1767 | uinfo->dimen.d[2] = 2;	/* 0=level, 1=peak */ | 
|  | 1768 | return 0; | 
|  | 1769 | } | 
|  | 1770 |  | 
|  | 1771 | static int snd_echo_vumeters_get(struct snd_kcontrol *kcontrol, | 
|  | 1772 | struct snd_ctl_elem_value *ucontrol) | 
|  | 1773 | { | 
|  | 1774 | struct echoaudio *chip; | 
|  | 1775 |  | 
|  | 1776 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1777 | get_audio_meters(chip, ucontrol->value.integer.value); | 
|  | 1778 | return 0; | 
|  | 1779 | } | 
|  | 1780 |  | 
|  | 1781 | static struct snd_kcontrol_new snd_echo_vumeters __devinitdata = { | 
|  | 1782 | .name = "VU-meters", | 
|  | 1783 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 
| Giuliano Pochini | 048b945 | 2006-11-24 13:03:58 +0100 | [diff] [blame] | 1784 | .access = SNDRV_CTL_ELEM_ACCESS_READ | | 
|  | 1785 | SNDRV_CTL_ELEM_ACCESS_VOLATILE | | 
|  | 1786 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1787 | .info = snd_echo_vumeters_info, | 
|  | 1788 | .get = snd_echo_vumeters_get, | 
| Giuliano Pochini | 048b945 | 2006-11-24 13:03:58 +0100 | [diff] [blame] | 1789 | .tlv = {.p = db_scale_output_gain}, | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1790 | }; | 
|  | 1791 |  | 
|  | 1792 |  | 
|  | 1793 |  | 
|  | 1794 | /*** Channels info - it exports informations about the number of channels ***/ | 
|  | 1795 | static int snd_echo_channels_info_info(struct snd_kcontrol *kcontrol, | 
|  | 1796 | struct snd_ctl_elem_info *uinfo) | 
|  | 1797 | { | 
|  | 1798 | struct echoaudio *chip; | 
|  | 1799 |  | 
|  | 1800 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1801 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | 
|  | 1802 | uinfo->count = 6; | 
|  | 1803 | uinfo->value.integer.min = 0; | 
|  | 1804 | uinfo->value.integer.max = 1 << ECHO_CLOCK_NUMBER; | 
|  | 1805 | return 0; | 
|  | 1806 | } | 
|  | 1807 |  | 
|  | 1808 | static int snd_echo_channels_info_get(struct snd_kcontrol *kcontrol, | 
|  | 1809 | struct snd_ctl_elem_value *ucontrol) | 
|  | 1810 | { | 
|  | 1811 | struct echoaudio *chip; | 
|  | 1812 | int detected, clocks, bit, src; | 
|  | 1813 |  | 
|  | 1814 | chip = snd_kcontrol_chip(kcontrol); | 
|  | 1815 | ucontrol->value.integer.value[0] = num_busses_in(chip); | 
|  | 1816 | ucontrol->value.integer.value[1] = num_analog_busses_in(chip); | 
|  | 1817 | ucontrol->value.integer.value[2] = num_busses_out(chip); | 
|  | 1818 | ucontrol->value.integer.value[3] = num_analog_busses_out(chip); | 
|  | 1819 | ucontrol->value.integer.value[4] = num_pipes_out(chip); | 
|  | 1820 |  | 
|  | 1821 | /* Compute the bitmask of the currently valid input clocks */ | 
|  | 1822 | detected = detect_input_clocks(chip); | 
|  | 1823 | clocks = 0; | 
|  | 1824 | src = chip->num_clock_sources - 1; | 
|  | 1825 | for (bit = ECHO_CLOCK_NUMBER - 1; bit >= 0; bit--) | 
|  | 1826 | if (detected & (1 << bit)) | 
|  | 1827 | for (; src >= 0; src--) | 
|  | 1828 | if (bit == chip->clock_source_list[src]) { | 
|  | 1829 | clocks |= 1 << src; | 
|  | 1830 | break; | 
|  | 1831 | } | 
|  | 1832 | ucontrol->value.integer.value[5] = clocks; | 
|  | 1833 |  | 
|  | 1834 | return 0; | 
|  | 1835 | } | 
|  | 1836 |  | 
|  | 1837 | static struct snd_kcontrol_new snd_echo_channels_info __devinitdata = { | 
|  | 1838 | .name = "Channels info", | 
|  | 1839 | .iface = SNDRV_CTL_ELEM_IFACE_HWDEP, | 
|  | 1840 | .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE, | 
|  | 1841 | .info = snd_echo_channels_info_info, | 
|  | 1842 | .get = snd_echo_channels_info_get, | 
|  | 1843 | }; | 
|  | 1844 |  | 
|  | 1845 |  | 
|  | 1846 |  | 
|  | 1847 |  | 
|  | 1848 | /****************************************************************************** | 
|  | 1849 | IRQ Handler | 
|  | 1850 | ******************************************************************************/ | 
|  | 1851 |  | 
| David Howells | 7d12e78 | 2006-10-05 14:55:46 +0100 | [diff] [blame] | 1852 | static irqreturn_t snd_echo_interrupt(int irq, void *dev_id) | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1853 | { | 
|  | 1854 | struct echoaudio *chip = dev_id; | 
|  | 1855 | struct snd_pcm_substream *substream; | 
|  | 1856 | int period, ss, st; | 
|  | 1857 |  | 
|  | 1858 | spin_lock(&chip->lock); | 
|  | 1859 | st = service_irq(chip); | 
|  | 1860 | if (st < 0) { | 
|  | 1861 | spin_unlock(&chip->lock); | 
|  | 1862 | return IRQ_NONE; | 
|  | 1863 | } | 
|  | 1864 | /* The hardware doesn't tell us which substream caused the irq, | 
|  | 1865 | thus we have to check all running substreams. */ | 
|  | 1866 | for (ss = 0; ss < DSP_MAXPIPES; ss++) { | 
| Giuliano Pochini | b721e68 | 2010-02-17 00:57:44 +0100 | [diff] [blame] | 1867 | substream = chip->substream[ss]; | 
|  | 1868 | if (substream && ((struct audiopipe *)substream->runtime-> | 
|  | 1869 | private_data)->state == PIPE_STATE_STARTED) { | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1870 | period = pcm_pointer(substream) / | 
|  | 1871 | substream->runtime->period_size; | 
|  | 1872 | if (period != chip->last_period[ss]) { | 
|  | 1873 | chip->last_period[ss] = period; | 
|  | 1874 | spin_unlock(&chip->lock); | 
|  | 1875 | snd_pcm_period_elapsed(substream); | 
|  | 1876 | spin_lock(&chip->lock); | 
|  | 1877 | } | 
|  | 1878 | } | 
|  | 1879 | } | 
|  | 1880 | spin_unlock(&chip->lock); | 
|  | 1881 |  | 
|  | 1882 | #ifdef ECHOCARD_HAS_MIDI | 
|  | 1883 | if (st > 0 && chip->midi_in) { | 
|  | 1884 | snd_rawmidi_receive(chip->midi_in, chip->midi_buffer, st); | 
|  | 1885 | DE_MID(("rawmidi_iread=%d\n", st)); | 
|  | 1886 | } | 
|  | 1887 | #endif | 
|  | 1888 | return IRQ_HANDLED; | 
|  | 1889 | } | 
|  | 1890 |  | 
|  | 1891 |  | 
|  | 1892 |  | 
|  | 1893 |  | 
|  | 1894 | /****************************************************************************** | 
|  | 1895 | Module construction / destruction | 
|  | 1896 | ******************************************************************************/ | 
|  | 1897 |  | 
|  | 1898 | static int snd_echo_free(struct echoaudio *chip) | 
|  | 1899 | { | 
|  | 1900 | DE_INIT(("Stop DSP...\n")); | 
| Takashi Iwai | ebf029d | 2008-04-22 17:28:11 +0200 | [diff] [blame] | 1901 | if (chip->comm_page) | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1902 | rest_in_peace(chip); | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1903 | DE_INIT(("Stopped.\n")); | 
|  | 1904 |  | 
|  | 1905 | if (chip->irq >= 0) | 
| Takashi Iwai | 437a5a4 | 2006-11-21 12:14:23 +0100 | [diff] [blame] | 1906 | free_irq(chip->irq, chip); | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1907 |  | 
| Takashi Iwai | ebf029d | 2008-04-22 17:28:11 +0200 | [diff] [blame] | 1908 | if (chip->comm_page) | 
|  | 1909 | snd_dma_free_pages(&chip->commpage_dma_buf); | 
|  | 1910 |  | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1911 | if (chip->dsp_registers) | 
|  | 1912 | iounmap(chip->dsp_registers); | 
|  | 1913 |  | 
| Takashi Iwai | 8caf7aa | 2006-06-28 16:39:36 +0200 | [diff] [blame] | 1914 | if (chip->iores) | 
|  | 1915 | release_and_free_resource(chip->iores); | 
|  | 1916 |  | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1917 | DE_INIT(("MMIO freed.\n")); | 
|  | 1918 |  | 
|  | 1919 | pci_disable_device(chip->pci); | 
|  | 1920 |  | 
|  | 1921 | /* release chip data */ | 
| Giuliano Pochini | 4f8ada4 | 2010-02-14 18:15:51 +0100 | [diff] [blame] | 1922 | free_firmware_cache(chip); | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1923 | kfree(chip); | 
|  | 1924 | DE_INIT(("Chip freed.\n")); | 
|  | 1925 | return 0; | 
|  | 1926 | } | 
|  | 1927 |  | 
|  | 1928 |  | 
|  | 1929 |  | 
|  | 1930 | static int snd_echo_dev_free(struct snd_device *device) | 
|  | 1931 | { | 
|  | 1932 | struct echoaudio *chip = device->device_data; | 
|  | 1933 |  | 
|  | 1934 | DE_INIT(("snd_echo_dev_free()...\n")); | 
|  | 1935 | return snd_echo_free(chip); | 
|  | 1936 | } | 
|  | 1937 |  | 
|  | 1938 |  | 
|  | 1939 |  | 
|  | 1940 | /* <--snd_echo_probe() */ | 
|  | 1941 | static __devinit int snd_echo_create(struct snd_card *card, | 
|  | 1942 | struct pci_dev *pci, | 
|  | 1943 | struct echoaudio **rchip) | 
|  | 1944 | { | 
|  | 1945 | struct echoaudio *chip; | 
|  | 1946 | int err; | 
|  | 1947 | size_t sz; | 
|  | 1948 | static struct snd_device_ops ops = { | 
|  | 1949 | .dev_free = snd_echo_dev_free, | 
|  | 1950 | }; | 
|  | 1951 |  | 
|  | 1952 | *rchip = NULL; | 
|  | 1953 |  | 
|  | 1954 | pci_write_config_byte(pci, PCI_LATENCY_TIMER, 0xC0); | 
|  | 1955 |  | 
|  | 1956 | if ((err = pci_enable_device(pci)) < 0) | 
|  | 1957 | return err; | 
|  | 1958 | pci_set_master(pci); | 
|  | 1959 |  | 
| Giuliano Pochini | 47b5d02 | 2010-02-14 18:16:10 +0100 | [diff] [blame] | 1960 | /* Allocate chip if needed */ | 
|  | 1961 | if (!*rchip) { | 
|  | 1962 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | 
|  | 1963 | if (!chip) { | 
|  | 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; | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1980 | } | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1981 |  | 
|  | 1982 | /* PCI resource allocation */ | 
|  | 1983 | chip->dsp_registers_phys = pci_resource_start(pci, 0); | 
|  | 1984 | sz = pci_resource_len(pci, 0); | 
|  | 1985 | if (sz > PAGE_SIZE) | 
|  | 1986 | sz = PAGE_SIZE;		/* We map only the required part */ | 
|  | 1987 |  | 
|  | 1988 | if ((chip->iores = request_mem_region(chip->dsp_registers_phys, sz, | 
|  | 1989 | ECHOCARD_NAME)) == NULL) { | 
|  | 1990 | snd_echo_free(chip); | 
|  | 1991 | snd_printk(KERN_ERR "cannot get memory region\n"); | 
|  | 1992 | return -EBUSY; | 
|  | 1993 | } | 
|  | 1994 | chip->dsp_registers = (volatile u32 __iomem *) | 
|  | 1995 | ioremap_nocache(chip->dsp_registers_phys, sz); | 
|  | 1996 |  | 
| Takashi Iwai | 437a5a4 | 2006-11-21 12:14:23 +0100 | [diff] [blame] | 1997 | if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED, | 
|  | 1998 | ECHOCARD_NAME, chip)) { | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 1999 | snd_echo_free(chip); | 
|  | 2000 | snd_printk(KERN_ERR "cannot grab irq\n"); | 
|  | 2001 | return -EBUSY; | 
|  | 2002 | } | 
|  | 2003 | chip->irq = pci->irq; | 
|  | 2004 | DE_INIT(("pci=%p irq=%d subdev=%04x Init hardware...\n", | 
|  | 2005 | chip->pci, chip->irq, chip->pci->subsystem_device)); | 
|  | 2006 |  | 
|  | 2007 | /* Create the DSP comm page - this is the area of memory used for most | 
|  | 2008 | of the communication with the DSP, which accesses it via bus mastering */ | 
|  | 2009 | if (snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV, snd_dma_pci_data(chip->pci), | 
|  | 2010 | sizeof(struct comm_page), | 
|  | 2011 | &chip->commpage_dma_buf) < 0) { | 
|  | 2012 | snd_echo_free(chip); | 
|  | 2013 | snd_printk(KERN_ERR "cannot allocate the comm page\n"); | 
|  | 2014 | return -ENOMEM; | 
|  | 2015 | } | 
|  | 2016 | chip->comm_page_phys = chip->commpage_dma_buf.addr; | 
|  | 2017 | chip->comm_page = (struct comm_page *)chip->commpage_dma_buf.area; | 
|  | 2018 |  | 
|  | 2019 | err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device); | 
| Giuliano Pochini | 47b5d02 | 2010-02-14 18:16:10 +0100 | [diff] [blame] | 2020 | if (err >= 0) | 
|  | 2021 | err = set_mixer_defaults(chip); | 
|  | 2022 | if (err < 0) { | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 2023 | DE_INIT(("init_hw err=%d\n", err)); | 
|  | 2024 | snd_echo_free(chip); | 
|  | 2025 | return err; | 
|  | 2026 | } | 
|  | 2027 | DE_INIT(("Card init OK\n")); | 
|  | 2028 |  | 
|  | 2029 | if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { | 
|  | 2030 | snd_echo_free(chip); | 
|  | 2031 | return err; | 
|  | 2032 | } | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 2033 | *rchip = chip; | 
|  | 2034 | /* Init done ! */ | 
|  | 2035 | return 0; | 
|  | 2036 | } | 
|  | 2037 |  | 
|  | 2038 |  | 
|  | 2039 |  | 
|  | 2040 | /* constructor */ | 
|  | 2041 | static int __devinit snd_echo_probe(struct pci_dev *pci, | 
|  | 2042 | const struct pci_device_id *pci_id) | 
|  | 2043 | { | 
|  | 2044 | static int dev; | 
|  | 2045 | struct snd_card *card; | 
|  | 2046 | struct echoaudio *chip; | 
|  | 2047 | char *dsp; | 
|  | 2048 | int i, err; | 
|  | 2049 |  | 
|  | 2050 | if (dev >= SNDRV_CARDS) | 
|  | 2051 | return -ENODEV; | 
|  | 2052 | if (!enable[dev]) { | 
|  | 2053 | dev++; | 
|  | 2054 | return -ENOENT; | 
|  | 2055 | } | 
|  | 2056 |  | 
|  | 2057 | DE_INIT(("Echoaudio driver starting...\n")); | 
|  | 2058 | i = 0; | 
| Takashi Iwai | e58de7b | 2008-12-28 16:44:30 +0100 | [diff] [blame] | 2059 | err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); | 
|  | 2060 | if (err < 0) | 
|  | 2061 | return err; | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 2062 |  | 
| Takashi Iwai | c187c04 | 2007-02-19 15:27:33 +0100 | [diff] [blame] | 2063 | snd_card_set_dev(card, &pci->dev); | 
|  | 2064 |  | 
| Giuliano Pochini | 47b5d02 | 2010-02-14 18:16:10 +0100 | [diff] [blame] | 2065 | chip = NULL;	/* Tells snd_echo_create to allocate chip */ | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 2066 | if ((err = snd_echo_create(card, pci, &chip)) < 0) { | 
|  | 2067 | snd_card_free(card); | 
|  | 2068 | return err; | 
|  | 2069 | } | 
|  | 2070 |  | 
|  | 2071 | strcpy(card->driver, "Echo_" ECHOCARD_NAME); | 
|  | 2072 | strcpy(card->shortname, chip->card_name); | 
|  | 2073 |  | 
|  | 2074 | dsp = "56301"; | 
|  | 2075 | if (pci_id->device == 0x3410) | 
|  | 2076 | dsp = "56361"; | 
|  | 2077 |  | 
|  | 2078 | sprintf(card->longname, "%s rev.%d (DSP%s) at 0x%lx irq %i", | 
|  | 2079 | card->shortname, pci_id->subdevice & 0x000f, dsp, | 
|  | 2080 | chip->dsp_registers_phys, chip->irq); | 
|  | 2081 |  | 
|  | 2082 | if ((err = snd_echo_new_pcm(chip)) < 0) { | 
|  | 2083 | snd_printk(KERN_ERR "new pcm error %d\n", err); | 
|  | 2084 | snd_card_free(card); | 
|  | 2085 | return err; | 
|  | 2086 | } | 
|  | 2087 |  | 
|  | 2088 | #ifdef ECHOCARD_HAS_MIDI | 
|  | 2089 | if (chip->has_midi) {	/* Some Mia's do not have midi */ | 
|  | 2090 | if ((err = snd_echo_midi_create(card, chip)) < 0) { | 
|  | 2091 | snd_printk(KERN_ERR "new midi error %d\n", err); | 
|  | 2092 | snd_card_free(card); | 
|  | 2093 | return err; | 
|  | 2094 | } | 
|  | 2095 | } | 
|  | 2096 | #endif | 
|  | 2097 |  | 
|  | 2098 | #ifdef ECHOCARD_HAS_VMIXER | 
|  | 2099 | snd_echo_vmixer.count = num_pipes_out(chip) * num_busses_out(chip); | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 2100 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vmixer, chip))) < 0) | 
|  | 2101 | goto ctl_error; | 
| Giuliano Pochini | 392bf2f | 2009-09-30 08:26:45 +0200 | [diff] [blame] | 2102 | #ifdef ECHOCARD_HAS_LINE_OUT_GAIN | 
|  | 2103 | err = snd_ctl_add(chip->card, | 
|  | 2104 | snd_ctl_new1(&snd_echo_line_output_gain, chip)); | 
|  | 2105 | if (err < 0) | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 2106 | goto ctl_error; | 
|  | 2107 | #endif | 
| Giuliano Pochini | 392bf2f | 2009-09-30 08:26:45 +0200 | [diff] [blame] | 2108 | #else /* ECHOCARD_HAS_VMIXER */ | 
|  | 2109 | err = snd_ctl_add(chip->card, | 
|  | 2110 | snd_ctl_new1(&snd_echo_pcm_output_gain, chip)); | 
|  | 2111 | if (err < 0) | 
|  | 2112 | goto ctl_error; | 
|  | 2113 | #endif /* ECHOCARD_HAS_VMIXER */ | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 2114 |  | 
|  | 2115 | #ifdef ECHOCARD_HAS_INPUT_GAIN | 
|  | 2116 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_line_input_gain, chip))) < 0) | 
|  | 2117 | goto ctl_error; | 
|  | 2118 | #endif | 
|  | 2119 |  | 
|  | 2120 | #ifdef ECHOCARD_HAS_INPUT_NOMINAL_LEVEL | 
|  | 2121 | if (!chip->hasnt_input_nominal_level) | 
|  | 2122 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_intput_nominal_level, chip))) < 0) | 
|  | 2123 | goto ctl_error; | 
|  | 2124 | #endif | 
|  | 2125 |  | 
|  | 2126 | #ifdef ECHOCARD_HAS_OUTPUT_NOMINAL_LEVEL | 
|  | 2127 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_output_nominal_level, chip))) < 0) | 
|  | 2128 | goto ctl_error; | 
|  | 2129 | #endif | 
|  | 2130 |  | 
|  | 2131 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vumeters_switch, chip))) < 0) | 
|  | 2132 | goto ctl_error; | 
|  | 2133 |  | 
|  | 2134 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_vumeters, chip))) < 0) | 
|  | 2135 | goto ctl_error; | 
|  | 2136 |  | 
|  | 2137 | #ifdef ECHOCARD_HAS_MONITOR | 
|  | 2138 | snd_echo_monitor_mixer.count = num_busses_in(chip) * num_busses_out(chip); | 
|  | 2139 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_monitor_mixer, chip))) < 0) | 
|  | 2140 | goto ctl_error; | 
|  | 2141 | #endif | 
|  | 2142 |  | 
|  | 2143 | #ifdef ECHOCARD_HAS_DIGITAL_IN_AUTOMUTE | 
|  | 2144 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_automute_switch, chip))) < 0) | 
|  | 2145 | goto ctl_error; | 
|  | 2146 | #endif | 
|  | 2147 |  | 
|  | 2148 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_channels_info, chip))) < 0) | 
|  | 2149 | goto ctl_error; | 
|  | 2150 |  | 
|  | 2151 | #ifdef ECHOCARD_HAS_DIGITAL_MODE_SWITCH | 
|  | 2152 | /* Creates a list of available digital modes */ | 
|  | 2153 | chip->num_digital_modes = 0; | 
|  | 2154 | for (i = 0; i < 6; i++) | 
|  | 2155 | if (chip->digital_modes & (1 << i)) | 
|  | 2156 | chip->digital_mode_list[chip->num_digital_modes++] = i; | 
|  | 2157 |  | 
|  | 2158 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_digital_mode_switch, chip))) < 0) | 
|  | 2159 | goto ctl_error; | 
|  | 2160 | #endif /* ECHOCARD_HAS_DIGITAL_MODE_SWITCH */ | 
|  | 2161 |  | 
|  | 2162 | #ifdef ECHOCARD_HAS_EXTERNAL_CLOCK | 
|  | 2163 | /* Creates a list of available clock sources */ | 
|  | 2164 | chip->num_clock_sources = 0; | 
|  | 2165 | for (i = 0; i < 10; i++) | 
|  | 2166 | if (chip->input_clock_types & (1 << i)) | 
|  | 2167 | chip->clock_source_list[chip->num_clock_sources++] = i; | 
|  | 2168 |  | 
|  | 2169 | if (chip->num_clock_sources > 1) { | 
|  | 2170 | chip->clock_src_ctl = snd_ctl_new1(&snd_echo_clock_source_switch, chip); | 
|  | 2171 | if ((err = snd_ctl_add(chip->card, chip->clock_src_ctl)) < 0) | 
|  | 2172 | goto ctl_error; | 
|  | 2173 | } | 
|  | 2174 | #endif /* ECHOCARD_HAS_EXTERNAL_CLOCK */ | 
|  | 2175 |  | 
|  | 2176 | #ifdef ECHOCARD_HAS_DIGITAL_IO | 
|  | 2177 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_spdif_mode_switch, chip))) < 0) | 
|  | 2178 | goto ctl_error; | 
|  | 2179 | #endif | 
|  | 2180 |  | 
|  | 2181 | #ifdef ECHOCARD_HAS_PHANTOM_POWER | 
|  | 2182 | if (chip->has_phantom_power) | 
|  | 2183 | if ((err = snd_ctl_add(chip->card, snd_ctl_new1(&snd_echo_phantom_power_switch, chip))) < 0) | 
|  | 2184 | goto ctl_error; | 
|  | 2185 | #endif | 
|  | 2186 |  | 
| Julia Lawall | a0fd434 | 2010-04-02 14:47:59 +0200 | [diff] [blame] | 2187 | err = snd_card_register(card); | 
|  | 2188 | if (err < 0) | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 2189 | goto ctl_error; | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 2190 | snd_printk(KERN_INFO "Card registered: %s\n", card->longname); | 
|  | 2191 |  | 
|  | 2192 | pci_set_drvdata(pci, chip); | 
|  | 2193 | dev++; | 
|  | 2194 | return 0; | 
|  | 2195 |  | 
|  | 2196 | ctl_error: | 
|  | 2197 | snd_printk(KERN_ERR "new control error %d\n", err); | 
|  | 2198 | snd_card_free(card); | 
|  | 2199 | return err; | 
|  | 2200 | } | 
|  | 2201 |  | 
|  | 2202 |  | 
|  | 2203 |  | 
| Giuliano Pochini | 47b5d02 | 2010-02-14 18:16:10 +0100 | [diff] [blame] | 2204 | #if defined(CONFIG_PM) | 
|  | 2205 |  | 
|  | 2206 | static int snd_echo_suspend(struct pci_dev *pci, pm_message_t state) | 
|  | 2207 | { | 
|  | 2208 | struct echoaudio *chip = pci_get_drvdata(pci); | 
|  | 2209 |  | 
|  | 2210 | DE_INIT(("suspend start\n")); | 
|  | 2211 | snd_pcm_suspend_all(chip->analog_pcm); | 
|  | 2212 | snd_pcm_suspend_all(chip->digital_pcm); | 
|  | 2213 |  | 
|  | 2214 | #ifdef ECHOCARD_HAS_MIDI | 
|  | 2215 | /* This call can sleep */ | 
|  | 2216 | if (chip->midi_out) | 
|  | 2217 | snd_echo_midi_output_trigger(chip->midi_out, 0); | 
|  | 2218 | #endif | 
|  | 2219 | spin_lock_irq(&chip->lock); | 
|  | 2220 | if (wait_handshake(chip)) { | 
|  | 2221 | spin_unlock_irq(&chip->lock); | 
|  | 2222 | return -EIO; | 
|  | 2223 | } | 
|  | 2224 | clear_handshake(chip); | 
|  | 2225 | if (send_vector(chip, DSP_VC_GO_COMATOSE) < 0) { | 
|  | 2226 | spin_unlock_irq(&chip->lock); | 
|  | 2227 | return -EIO; | 
|  | 2228 | } | 
|  | 2229 | spin_unlock_irq(&chip->lock); | 
|  | 2230 |  | 
|  | 2231 | chip->dsp_code = NULL; | 
|  | 2232 | free_irq(chip->irq, chip); | 
|  | 2233 | chip->irq = -1; | 
|  | 2234 | pci_save_state(pci); | 
|  | 2235 | pci_disable_device(pci); | 
|  | 2236 |  | 
|  | 2237 | DE_INIT(("suspend done\n")); | 
|  | 2238 | return 0; | 
|  | 2239 | } | 
|  | 2240 |  | 
|  | 2241 |  | 
|  | 2242 |  | 
|  | 2243 | static int snd_echo_resume(struct pci_dev *pci) | 
|  | 2244 | { | 
|  | 2245 | struct echoaudio *chip = pci_get_drvdata(pci); | 
|  | 2246 | struct comm_page *commpage, *commpage_bak; | 
|  | 2247 | u32 pipe_alloc_mask; | 
|  | 2248 | int err; | 
|  | 2249 |  | 
|  | 2250 | DE_INIT(("resume start\n")); | 
|  | 2251 | pci_restore_state(pci); | 
|  | 2252 | commpage_bak = kmalloc(sizeof(struct echoaudio), GFP_KERNEL); | 
| Kulikov Vasiliy | 0b6d092 | 2010-07-16 20:15:43 +0400 | [diff] [blame] | 2253 | if (commpage_bak == NULL) | 
|  | 2254 | return -ENOMEM; | 
| Giuliano Pochini | 47b5d02 | 2010-02-14 18:16:10 +0100 | [diff] [blame] | 2255 | commpage = chip->comm_page; | 
|  | 2256 | memcpy(commpage_bak, commpage, sizeof(struct comm_page)); | 
|  | 2257 |  | 
|  | 2258 | err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device); | 
|  | 2259 | if (err < 0) { | 
|  | 2260 | kfree(commpage_bak); | 
|  | 2261 | DE_INIT(("resume init_hw err=%d\n", err)); | 
|  | 2262 | snd_echo_free(chip); | 
|  | 2263 | return err; | 
|  | 2264 | } | 
|  | 2265 | DE_INIT(("resume init OK\n")); | 
|  | 2266 |  | 
|  | 2267 | /* Temporarily set chip->pipe_alloc_mask=0 otherwise | 
|  | 2268 | * restore_dsp_settings() fails. | 
|  | 2269 | */ | 
|  | 2270 | pipe_alloc_mask = chip->pipe_alloc_mask; | 
|  | 2271 | chip->pipe_alloc_mask = 0; | 
|  | 2272 | err = restore_dsp_rettings(chip); | 
|  | 2273 | chip->pipe_alloc_mask = pipe_alloc_mask; | 
|  | 2274 | if (err < 0) { | 
|  | 2275 | kfree(commpage_bak); | 
|  | 2276 | return err; | 
|  | 2277 | } | 
|  | 2278 | DE_INIT(("resume restore OK\n")); | 
|  | 2279 |  | 
|  | 2280 | memcpy(&commpage->audio_format, &commpage_bak->audio_format, | 
|  | 2281 | sizeof(commpage->audio_format)); | 
|  | 2282 | memcpy(&commpage->sglist_addr, &commpage_bak->sglist_addr, | 
|  | 2283 | sizeof(commpage->sglist_addr)); | 
|  | 2284 | memcpy(&commpage->midi_output, &commpage_bak->midi_output, | 
|  | 2285 | sizeof(commpage->midi_output)); | 
|  | 2286 | kfree(commpage_bak); | 
|  | 2287 |  | 
|  | 2288 | if (request_irq(pci->irq, snd_echo_interrupt, IRQF_SHARED, | 
|  | 2289 | ECHOCARD_NAME, chip)) { | 
|  | 2290 | snd_echo_free(chip); | 
|  | 2291 | snd_printk(KERN_ERR "cannot grab irq\n"); | 
|  | 2292 | return -EBUSY; | 
|  | 2293 | } | 
|  | 2294 | chip->irq = pci->irq; | 
|  | 2295 | DE_INIT(("resume irq=%d\n", chip->irq)); | 
|  | 2296 |  | 
|  | 2297 | #ifdef ECHOCARD_HAS_MIDI | 
|  | 2298 | if (chip->midi_input_enabled) | 
|  | 2299 | enable_midi_input(chip, TRUE); | 
|  | 2300 | if (chip->midi_out) | 
|  | 2301 | snd_echo_midi_output_trigger(chip->midi_out, 1); | 
|  | 2302 | #endif | 
|  | 2303 |  | 
|  | 2304 | DE_INIT(("resume done\n")); | 
|  | 2305 | return 0; | 
|  | 2306 | } | 
|  | 2307 |  | 
|  | 2308 | #endif /* CONFIG_PM */ | 
|  | 2309 |  | 
|  | 2310 |  | 
|  | 2311 |  | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 2312 | static void __devexit snd_echo_remove(struct pci_dev *pci) | 
|  | 2313 | { | 
|  | 2314 | struct echoaudio *chip; | 
|  | 2315 |  | 
|  | 2316 | chip = pci_get_drvdata(pci); | 
|  | 2317 | if (chip) | 
|  | 2318 | snd_card_free(chip->card); | 
|  | 2319 | pci_set_drvdata(pci, NULL); | 
|  | 2320 | } | 
|  | 2321 |  | 
|  | 2322 |  | 
|  | 2323 |  | 
|  | 2324 | /****************************************************************************** | 
|  | 2325 | Everything starts and ends here | 
|  | 2326 | ******************************************************************************/ | 
|  | 2327 |  | 
|  | 2328 | /* pci_driver definition */ | 
|  | 2329 | static struct pci_driver driver = { | 
|  | 2330 | .name = "Echoaudio " ECHOCARD_NAME, | 
|  | 2331 | .id_table = snd_echo_ids, | 
|  | 2332 | .probe = snd_echo_probe, | 
|  | 2333 | .remove = __devexit_p(snd_echo_remove), | 
| Giuliano Pochini | 47b5d02 | 2010-02-14 18:16:10 +0100 | [diff] [blame] | 2334 | #ifdef CONFIG_PM | 
|  | 2335 | .suspend = snd_echo_suspend, | 
|  | 2336 | .resume = snd_echo_resume, | 
|  | 2337 | #endif /* CONFIG_PM */ | 
| Giuliano Pochini | dd7b254 | 2006-06-28 13:53:41 +0200 | [diff] [blame] | 2338 | }; | 
|  | 2339 |  | 
|  | 2340 |  | 
|  | 2341 |  | 
|  | 2342 | /* initialization of the module */ | 
|  | 2343 | static int __init alsa_card_echo_init(void) | 
|  | 2344 | { | 
|  | 2345 | return pci_register_driver(&driver); | 
|  | 2346 | } | 
|  | 2347 |  | 
|  | 2348 |  | 
|  | 2349 |  | 
|  | 2350 | /* clean up the module */ | 
|  | 2351 | static void __exit alsa_card_echo_exit(void) | 
|  | 2352 | { | 
|  | 2353 | pci_unregister_driver(&driver); | 
|  | 2354 | } | 
|  | 2355 |  | 
|  | 2356 |  | 
|  | 2357 | module_init(alsa_card_echo_init) | 
|  | 2358 | module_exit(alsa_card_echo_exit) |