diff options
Diffstat (limited to 'sound/pci/azt3328.c')
| -rw-r--r-- | sound/pci/azt3328.c | 1116 |
1 files changed, 617 insertions, 499 deletions
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index f290bc56178f..8451a0169f32 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * azt3328.c - driver for Aztech AZF3328 based soundcards (e.g. PCI168). | 2 | * azt3328.c - driver for Aztech AZF3328 based soundcards (e.g. PCI168). |
| 3 | * Copyright (C) 2002, 2005 - 2008 by Andreas Mohr <andi AT lisas.de> | 3 | * Copyright (C) 2002, 2005 - 2009 by Andreas Mohr <andi AT lisas.de> |
| 4 | * | 4 | * |
| 5 | * Framework borrowed from Bart Hartgers's als4000.c. | 5 | * Framework borrowed from Bart Hartgers's als4000.c. |
| 6 | * Driver developed on PCI168 AP(W) version (PCI rev. 10, subsystem ID 1801), | 6 | * Driver developed on PCI168 AP(W) version (PCI rev. 10, subsystem ID 1801), |
| @@ -10,6 +10,13 @@ | |||
| 10 | * PCI168 A/AP, sub ID 8000 | 10 | * PCI168 A/AP, sub ID 8000 |
| 11 | * Please give me feedback in case you try my driver with one of these!! | 11 | * Please give me feedback in case you try my driver with one of these!! |
| 12 | * | 12 | * |
| 13 | * Keywords: Windows XP Vista 168nt4-125.zip 168win95-125.zip PCI 168 download | ||
| 14 | * (XP/Vista do not support this card at all but every Linux distribution | ||
| 15 | * has very good support out of the box; | ||
| 16 | * just to make sure that the right people hit this and get to know that, | ||
| 17 | * despite the high level of Internet ignorance - as usual :-P - | ||
| 18 | * about very good support for this card - on Linux!) | ||
| 19 | * | ||
| 13 | * GPL LICENSE | 20 | * GPL LICENSE |
| 14 | * This program is free software; you can redistribute it and/or modify | 21 | * This program is free software; you can redistribute it and/or modify |
| 15 | * it under the terms of the GNU General Public License as published by | 22 | * it under the terms of the GNU General Public License as published by |
| @@ -71,10 +78,11 @@ | |||
| 71 | * - built-in General DirectX timer having a 20 bits counter | 78 | * - built-in General DirectX timer having a 20 bits counter |
| 72 | * with 1us resolution (see below!) | 79 | * with 1us resolution (see below!) |
| 73 | * - I2S serial output port for external DAC | 80 | * - I2S serial output port for external DAC |
| 81 | * [FIXME: 3.3V or 5V level? maximum rate is 66.2kHz right?] | ||
| 74 | * - supports 33MHz PCI spec 2.1, PCI power management 1.0, compliant with ACPI | 82 | * - supports 33MHz PCI spec 2.1, PCI power management 1.0, compliant with ACPI |
| 75 | * - supports hardware volume control | 83 | * - supports hardware volume control |
| 76 | * - single chip low cost solution (128 pin QFP) | 84 | * - single chip low cost solution (128 pin QFP) |
| 77 | * - supports programmable Sub-vendor and Sub-system ID | 85 | * - supports programmable Sub-vendor and Sub-system ID [24C02 SEEPROM chip] |
| 78 | * required for Microsoft's logo compliance (FIXME: where?) | 86 | * required for Microsoft's logo compliance (FIXME: where?) |
| 79 | * At least the Trident 4D Wave DX has one bit somewhere | 87 | * At least the Trident 4D Wave DX has one bit somewhere |
| 80 | * to enable writes to PCI subsystem VID registers, that should be it. | 88 | * to enable writes to PCI subsystem VID registers, that should be it. |
| @@ -82,6 +90,7 @@ | |||
| 82 | * some custom data starting at 0x80. What kind of config settings | 90 | * some custom data starting at 0x80. What kind of config settings |
| 83 | * are located in our extended PCI space anyway?? | 91 | * are located in our extended PCI space anyway?? |
| 84 | * - PCI168 AP(W) card: power amplifier with 4 Watts/channel at 4 Ohms | 92 | * - PCI168 AP(W) card: power amplifier with 4 Watts/channel at 4 Ohms |
| 93 | * [TDA1517P chip] | ||
| 85 | * | 94 | * |
| 86 | * Note that this driver now is actually *better* than the Windows driver, | 95 | * Note that this driver now is actually *better* than the Windows driver, |
| 87 | * since it additionally supports the card's 1MHz DirectX timer - just try | 96 | * since it additionally supports the card's 1MHz DirectX timer - just try |
| @@ -146,10 +155,15 @@ | |||
| 146 | * to read the Digital Enhanced Game Port. Not sure whether it is fixable. | 155 | * to read the Digital Enhanced Game Port. Not sure whether it is fixable. |
| 147 | * | 156 | * |
| 148 | * TODO | 157 | * TODO |
| 158 | * - use PCI_VDEVICE | ||
| 159 | * - verify driver status on x86_64 | ||
| 160 | * - test multi-card driver operation | ||
| 161 | * - (ab)use 1MHz DirectX timer as kernel clocksource | ||
| 149 | * - test MPU401 MIDI playback etc. | 162 | * - test MPU401 MIDI playback etc. |
| 150 | * - add more power micro-management (disable various units of the card | 163 | * - add more power micro-management (disable various units of the card |
| 151 | * as long as they're unused). However this requires more I/O ports which I | 164 | * as long as they're unused, to improve audio quality and save power). |
| 152 | * haven't figured out yet and which thus might not even exist... | 165 | * However this requires more I/O ports which I haven't figured out yet |
| 166 | * and which thus might not even exist... | ||
| 153 | * The standard suspend/resume functionality could probably make use of | 167 | * The standard suspend/resume functionality could probably make use of |
| 154 | * some improvement, too... | 168 | * some improvement, too... |
| 155 | * - figure out what all unknown port bits are responsible for | 169 | * - figure out what all unknown port bits are responsible for |
| @@ -185,25 +199,46 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); | |||
| 185 | #define SUPPORT_GAMEPORT 1 | 199 | #define SUPPORT_GAMEPORT 1 |
| 186 | #endif | 200 | #endif |
| 187 | 201 | ||
| 202 | /* === Debug settings === | ||
| 203 | Further diagnostic functionality than the settings below | ||
| 204 | does not need to be provided, since one can easily write a bash script | ||
| 205 | to dump the card's I/O ports (those listed in lspci -v -v): | ||
| 206 | function dump() | ||
| 207 | { | ||
| 208 | local descr=$1; local addr=$2; local count=$3 | ||
| 209 | |||
| 210 | echo "${descr}: ${count} @ ${addr}:" | ||
| 211 | dd if=/dev/port skip=$[${addr}] count=${count} bs=1 2>/dev/null| hexdump -C | ||
| 212 | } | ||
| 213 | and then use something like | ||
| 214 | "dump joy200 0x200 8", "dump mpu388 0x388 4", "dump joy 0xb400 8", | ||
| 215 | "dump codec00 0xa800 32", "dump mixer 0xb800 64", "dump synth 0xbc00 8", | ||
| 216 | possibly within a "while true; do ... sleep 1; done" loop. | ||
| 217 | Tweaking ports could be done using | ||
| 218 | VALSTRING="`printf "%02x" $value`" | ||
| 219 | printf "\x""$VALSTRING"|dd of=/dev/port seek=$[${addr}] bs=1 2>/dev/null | ||
| 220 | */ | ||
| 221 | |||
| 188 | #define DEBUG_MISC 0 | 222 | #define DEBUG_MISC 0 |
| 189 | #define DEBUG_CALLS 0 | 223 | #define DEBUG_CALLS 0 |
| 190 | #define DEBUG_MIXER 0 | 224 | #define DEBUG_MIXER 0 |
| 191 | #define DEBUG_PLAY_REC 0 | 225 | #define DEBUG_CODEC 0 |
| 192 | #define DEBUG_IO 0 | 226 | #define DEBUG_IO 0 |
| 193 | #define DEBUG_TIMER 0 | 227 | #define DEBUG_TIMER 0 |
| 194 | #define DEBUG_GAME 0 | 228 | #define DEBUG_GAME 0 |
| 229 | #define DEBUG_PM 0 | ||
| 195 | #define MIXER_TESTING 0 | 230 | #define MIXER_TESTING 0 |
| 196 | 231 | ||
| 197 | #if DEBUG_MISC | 232 | #if DEBUG_MISC |
| 198 | #define snd_azf3328_dbgmisc(format, args...) printk(KERN_ERR format, ##args) | 233 | #define snd_azf3328_dbgmisc(format, args...) printk(KERN_DEBUG format, ##args) |
| 199 | #else | 234 | #else |
| 200 | #define snd_azf3328_dbgmisc(format, args...) | 235 | #define snd_azf3328_dbgmisc(format, args...) |
| 201 | #endif | 236 | #endif |
| 202 | 237 | ||
| 203 | #if DEBUG_CALLS | 238 | #if DEBUG_CALLS |
| 204 | #define snd_azf3328_dbgcalls(format, args...) printk(format, ##args) | 239 | #define snd_azf3328_dbgcalls(format, args...) printk(format, ##args) |
| 205 | #define snd_azf3328_dbgcallenter() printk(KERN_ERR "--> %s\n", __func__) | 240 | #define snd_azf3328_dbgcallenter() printk(KERN_DEBUG "--> %s\n", __func__) |
| 206 | #define snd_azf3328_dbgcallleave() printk(KERN_ERR "<-- %s\n", __func__) | 241 | #define snd_azf3328_dbgcallleave() printk(KERN_DEBUG "<-- %s\n", __func__) |
| 207 | #else | 242 | #else |
| 208 | #define snd_azf3328_dbgcalls(format, args...) | 243 | #define snd_azf3328_dbgcalls(format, args...) |
| 209 | #define snd_azf3328_dbgcallenter() | 244 | #define snd_azf3328_dbgcallenter() |
| @@ -216,10 +251,10 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); | |||
| 216 | #define snd_azf3328_dbgmixer(format, args...) | 251 | #define snd_azf3328_dbgmixer(format, args...) |
| 217 | #endif | 252 | #endif |
| 218 | 253 | ||
| 219 | #if DEBUG_PLAY_REC | 254 | #if DEBUG_CODEC |
| 220 | #define snd_azf3328_dbgplay(format, args...) printk(KERN_DEBUG format, ##args) | 255 | #define snd_azf3328_dbgcodec(format, args...) printk(KERN_DEBUG format, ##args) |
| 221 | #else | 256 | #else |
| 222 | #define snd_azf3328_dbgplay(format, args...) | 257 | #define snd_azf3328_dbgcodec(format, args...) |
| 223 | #endif | 258 | #endif |
| 224 | 259 | ||
| 225 | #if DEBUG_MISC | 260 | #if DEBUG_MISC |
| @@ -234,6 +269,12 @@ MODULE_SUPPORTED_DEVICE("{{Aztech,AZF3328}}"); | |||
| 234 | #define snd_azf3328_dbggame(format, args...) | 269 | #define snd_azf3328_dbggame(format, args...) |
| 235 | #endif | 270 | #endif |
| 236 | 271 | ||
| 272 | #if DEBUG_PM | ||
| 273 | #define snd_azf3328_dbgpm(format, args...) printk(KERN_DEBUG format, ##args) | ||
| 274 | #else | ||
| 275 | #define snd_azf3328_dbgpm(format, args...) | ||
| 276 | #endif | ||
| 277 | |||
| 237 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | 278 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ |
| 238 | module_param_array(index, int, NULL, 0444); | 279 | module_param_array(index, int, NULL, 0444); |
| 239 | MODULE_PARM_DESC(index, "Index value for AZF3328 soundcard."); | 280 | MODULE_PARM_DESC(index, "Index value for AZF3328 soundcard."); |
| @@ -250,22 +291,23 @@ static int seqtimer_scaling = 128; | |||
| 250 | module_param(seqtimer_scaling, int, 0444); | 291 | module_param(seqtimer_scaling, int, 0444); |
| 251 | MODULE_PARM_DESC(seqtimer_scaling, "Set 1024000Hz sequencer timer scale factor (lockup danger!). Default 128."); | 292 | MODULE_PARM_DESC(seqtimer_scaling, "Set 1024000Hz sequencer timer scale factor (lockup danger!). Default 128."); |
| 252 | 293 | ||
| 253 | struct snd_azf3328_audio_stream { | 294 | struct snd_azf3328_codec_data { |
| 295 | unsigned long io_base; | ||
| 254 | struct snd_pcm_substream *substream; | 296 | struct snd_pcm_substream *substream; |
| 255 | int enabled; | 297 | bool running; |
| 256 | int running; | 298 | const char *name; |
| 257 | unsigned long portbase; | ||
| 258 | }; | 299 | }; |
| 259 | 300 | ||
| 260 | enum snd_azf3328_stream_index { | 301 | enum snd_azf3328_codec_type { |
| 261 | AZF_PLAYBACK = 0, | 302 | AZF_CODEC_PLAYBACK = 0, |
| 262 | AZF_CAPTURE = 1, | 303 | AZF_CODEC_CAPTURE = 1, |
| 304 | AZF_CODEC_I2S_OUT = 2, | ||
| 263 | }; | 305 | }; |
| 264 | 306 | ||
| 265 | struct snd_azf3328 { | 307 | struct snd_azf3328 { |
| 266 | /* often-used fields towards beginning, then grouped */ | 308 | /* often-used fields towards beginning, then grouped */ |
| 267 | 309 | ||
| 268 | unsigned long codec_io; /* usually 0xb000, size 128 */ | 310 | unsigned long ctrl_io; /* usually 0xb000, size 128 */ |
| 269 | unsigned long game_io; /* usually 0xb400, size 8 */ | 311 | unsigned long game_io; /* usually 0xb400, size 8 */ |
| 270 | unsigned long mpu_io; /* usually 0xb800, size 4 */ | 312 | unsigned long mpu_io; /* usually 0xb800, size 4 */ |
| 271 | unsigned long opl3_io; /* usually 0xbc00, size 8 */ | 313 | unsigned long opl3_io; /* usually 0xbc00, size 8 */ |
| @@ -275,15 +317,17 @@ struct snd_azf3328 { | |||
| 275 | 317 | ||
| 276 | struct snd_timer *timer; | 318 | struct snd_timer *timer; |
| 277 | 319 | ||
| 278 | struct snd_pcm *pcm; | 320 | struct snd_pcm *pcm[3]; |
| 279 | struct snd_azf3328_audio_stream audio_stream[2]; | 321 | |
| 322 | /* playback, recording and I2S out codecs */ | ||
| 323 | struct snd_azf3328_codec_data codecs[3]; | ||
| 280 | 324 | ||
| 281 | struct snd_card *card; | 325 | struct snd_card *card; |
| 282 | struct snd_rawmidi *rmidi; | 326 | struct snd_rawmidi *rmidi; |
| 283 | 327 | ||
| 284 | #ifdef SUPPORT_GAMEPORT | 328 | #ifdef SUPPORT_GAMEPORT |
| 285 | struct gameport *gameport; | 329 | struct gameport *gameport; |
| 286 | int axes[4]; | 330 | u16 axes[4]; |
| 287 | #endif | 331 | #endif |
| 288 | 332 | ||
| 289 | struct pci_dev *pci; | 333 | struct pci_dev *pci; |
| @@ -293,16 +337,16 @@ struct snd_azf3328 { | |||
| 293 | * If we need to add more registers here, then we might try to fold this | 337 | * If we need to add more registers here, then we might try to fold this |
| 294 | * into some transparent combined shadow register handling with | 338 | * into some transparent combined shadow register handling with |
| 295 | * CONFIG_PM register storage below, but that's slightly difficult. */ | 339 | * CONFIG_PM register storage below, but that's slightly difficult. */ |
| 296 | u16 shadow_reg_codec_6AH; | 340 | u16 shadow_reg_ctrl_6AH; |
| 297 | 341 | ||
| 298 | #ifdef CONFIG_PM | 342 | #ifdef CONFIG_PM |
| 299 | /* register value containers for power management | 343 | /* register value containers for power management |
| 300 | * Note: not always full I/O range preserved (just like Win driver!) */ | 344 | * Note: not always full I/O range preserved (similar to Win driver!) */ |
| 301 | u16 saved_regs_codec[AZF_IO_SIZE_CODEC_PM / 2]; | 345 | u32 saved_regs_ctrl[AZF_ALIGN(AZF_IO_SIZE_CTRL_PM) / 4]; |
| 302 | u16 saved_regs_game [AZF_IO_SIZE_GAME_PM / 2]; | 346 | u32 saved_regs_game[AZF_ALIGN(AZF_IO_SIZE_GAME_PM) / 4]; |
| 303 | u16 saved_regs_mpu [AZF_IO_SIZE_MPU_PM / 2]; | 347 | u32 saved_regs_mpu[AZF_ALIGN(AZF_IO_SIZE_MPU_PM) / 4]; |
| 304 | u16 saved_regs_opl3 [AZF_IO_SIZE_OPL3_PM / 2]; | 348 | u32 saved_regs_opl3[AZF_ALIGN(AZF_IO_SIZE_OPL3_PM) / 4]; |
| 305 | u16 saved_regs_mixer[AZF_IO_SIZE_MIXER_PM / 2]; | 349 | u32 saved_regs_mixer[AZF_ALIGN(AZF_IO_SIZE_MIXER_PM) / 4]; |
| 306 | #endif | 350 | #endif |
| 307 | }; | 351 | }; |
| 308 | 352 | ||
| @@ -316,7 +360,7 @@ MODULE_DEVICE_TABLE(pci, snd_azf3328_ids); | |||
| 316 | 360 | ||
| 317 | 361 | ||
| 318 | static int | 362 | static int |
| 319 | snd_azf3328_io_reg_setb(unsigned reg, u8 mask, int do_set) | 363 | snd_azf3328_io_reg_setb(unsigned reg, u8 mask, bool do_set) |
| 320 | { | 364 | { |
| 321 | u8 prev = inb(reg), new; | 365 | u8 prev = inb(reg), new; |
| 322 | 366 | ||
| @@ -331,39 +375,72 @@ snd_azf3328_io_reg_setb(unsigned reg, u8 mask, int do_set) | |||
| 331 | } | 375 | } |
| 332 | 376 | ||
| 333 | static inline void | 377 | static inline void |
| 334 | snd_azf3328_codec_outb(const struct snd_azf3328 *chip, unsigned reg, u8 value) | 378 | snd_azf3328_codec_outb(const struct snd_azf3328_codec_data *codec, |
| 379 | unsigned reg, | ||
| 380 | u8 value | ||
| 381 | ) | ||
| 335 | { | 382 | { |
| 336 | outb(value, chip->codec_io + reg); | 383 | outb(value, codec->io_base + reg); |
| 337 | } | 384 | } |
| 338 | 385 | ||
| 339 | static inline u8 | 386 | static inline u8 |
| 340 | snd_azf3328_codec_inb(const struct snd_azf3328 *chip, unsigned reg) | 387 | snd_azf3328_codec_inb(const struct snd_azf3328_codec_data *codec, unsigned reg) |
| 341 | { | 388 | { |
| 342 | return inb(chip->codec_io + reg); | 389 | return inb(codec->io_base + reg); |
| 343 | } | 390 | } |
| 344 | 391 | ||
| 345 | static inline void | 392 | static inline void |
| 346 | snd_azf3328_codec_outw(const struct snd_azf3328 *chip, unsigned reg, u16 value) | 393 | snd_azf3328_codec_outw(const struct snd_azf3328_codec_data *codec, |
| 394 | unsigned reg, | ||
| 395 | u16 value | ||
| 396 | ) | ||
| 347 | { | 397 | { |
| 348 | outw(value, chip->codec_io + reg); | 398 | outw(value, codec->io_base + reg); |
| 349 | } | 399 | } |
| 350 | 400 | ||
| 351 | static inline u16 | 401 | static inline u16 |
| 352 | snd_azf3328_codec_inw(const struct snd_azf3328 *chip, unsigned reg) | 402 | snd_azf3328_codec_inw(const struct snd_azf3328_codec_data *codec, unsigned reg) |
| 353 | { | 403 | { |
| 354 | return inw(chip->codec_io + reg); | 404 | return inw(codec->io_base + reg); |
| 355 | } | 405 | } |
| 356 | 406 | ||
| 357 | static inline void | 407 | static inline void |
| 358 | snd_azf3328_codec_outl(const struct snd_azf3328 *chip, unsigned reg, u32 value) | 408 | snd_azf3328_codec_outl(const struct snd_azf3328_codec_data *codec, |
| 409 | unsigned reg, | ||
| 410 | u32 value | ||
| 411 | ) | ||
| 359 | { | 412 | { |
| 360 | outl(value, chip->codec_io + reg); | 413 | outl(value, codec->io_base + reg); |
| 361 | } | 414 | } |
| 362 | 415 | ||
| 363 | static inline u32 | 416 | static inline u32 |
| 364 | snd_azf3328_codec_inl(const struct snd_azf3328 *chip, unsigned reg) | 417 | snd_azf3328_codec_inl(const struct snd_azf3328_codec_data *codec, unsigned reg) |
| 418 | { | ||
| 419 | return inl(codec->io_base + reg); | ||
| 420 | } | ||
| 421 | |||
| 422 | static inline void | ||
| 423 | snd_azf3328_ctrl_outb(const struct snd_azf3328 *chip, unsigned reg, u8 value) | ||
| 424 | { | ||
| 425 | outb(value, chip->ctrl_io + reg); | ||
| 426 | } | ||
| 427 | |||
| 428 | static inline u8 | ||
| 429 | snd_azf3328_ctrl_inb(const struct snd_azf3328 *chip, unsigned reg) | ||
| 430 | { | ||
| 431 | return inb(chip->ctrl_io + reg); | ||
| 432 | } | ||
| 433 | |||
| 434 | static inline void | ||
| 435 | snd_azf3328_ctrl_outw(const struct snd_azf3328 *chip, unsigned reg, u16 value) | ||
| 436 | { | ||
| 437 | outw(value, chip->ctrl_io + reg); | ||
| 438 | } | ||
| 439 | |||
| 440 | static inline void | ||
| 441 | snd_azf3328_ctrl_outl(const struct snd_azf3328 *chip, unsigned reg, u32 value) | ||
| 365 | { | 442 | { |
| 366 | return inl(chip->codec_io + reg); | 443 | outl(value, chip->ctrl_io + reg); |
| 367 | } | 444 | } |
| 368 | 445 | ||
| 369 | static inline void | 446 | static inline void |
| @@ -404,13 +481,13 @@ snd_azf3328_mixer_inw(const struct snd_azf3328 *chip, unsigned reg) | |||
| 404 | 481 | ||
| 405 | #define AZF_MUTE_BIT 0x80 | 482 | #define AZF_MUTE_BIT 0x80 |
| 406 | 483 | ||
| 407 | static int | 484 | static bool |
| 408 | snd_azf3328_mixer_set_mute(const struct snd_azf3328 *chip, | 485 | snd_azf3328_mixer_set_mute(const struct snd_azf3328 *chip, |
| 409 | unsigned reg, int do_mute | 486 | unsigned reg, bool do_mute |
| 410 | ) | 487 | ) |
| 411 | { | 488 | { |
| 412 | unsigned long portbase = chip->mixer_io + reg + 1; | 489 | unsigned long portbase = chip->mixer_io + reg + 1; |
| 413 | int updated; | 490 | bool updated; |
| 414 | 491 | ||
| 415 | /* the mute bit is on the *second* (i.e. right) register of a | 492 | /* the mute bit is on the *second* (i.e. right) register of a |
| 416 | * left/right channel setting */ | 493 | * left/right channel setting */ |
| @@ -569,7 +646,7 @@ snd_azf3328_get_mixer(struct snd_kcontrol *kcontrol, | |||
| 569 | { | 646 | { |
| 570 | struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol); | 647 | struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol); |
| 571 | struct azf3328_mixer_reg reg; | 648 | struct azf3328_mixer_reg reg; |
| 572 | unsigned int oreg, val; | 649 | u16 oreg, val; |
| 573 | 650 | ||
| 574 | snd_azf3328_dbgcallenter(); | 651 | snd_azf3328_dbgcallenter(); |
| 575 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); | 652 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); |
| @@ -600,7 +677,7 @@ snd_azf3328_put_mixer(struct snd_kcontrol *kcontrol, | |||
| 600 | { | 677 | { |
| 601 | struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol); | 678 | struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol); |
| 602 | struct azf3328_mixer_reg reg; | 679 | struct azf3328_mixer_reg reg; |
| 603 | unsigned int oreg, nreg, val; | 680 | u16 oreg, nreg, val; |
| 604 | 681 | ||
| 605 | snd_azf3328_dbgcallenter(); | 682 | snd_azf3328_dbgcallenter(); |
| 606 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); | 683 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); |
| @@ -709,7 +786,7 @@ snd_azf3328_put_mixer_enum(struct snd_kcontrol *kcontrol, | |||
| 709 | { | 786 | { |
| 710 | struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol); | 787 | struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol); |
| 711 | struct azf3328_mixer_reg reg; | 788 | struct azf3328_mixer_reg reg; |
| 712 | unsigned int oreg, nreg, val; | 789 | u16 oreg, nreg, val; |
| 713 | 790 | ||
| 714 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); | 791 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); |
| 715 | oreg = snd_azf3328_mixer_inw(chip, reg.reg); | 792 | oreg = snd_azf3328_mixer_inw(chip, reg.reg); |
| @@ -867,14 +944,15 @@ snd_azf3328_hw_free(struct snd_pcm_substream *substream) | |||
| 867 | 944 | ||
| 868 | static void | 945 | static void |
| 869 | snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, | 946 | snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, |
| 870 | unsigned reg, | 947 | enum snd_azf3328_codec_type codec_type, |
| 871 | enum azf_freq_t bitrate, | 948 | enum azf_freq_t bitrate, |
| 872 | unsigned int format_width, | 949 | unsigned int format_width, |
| 873 | unsigned int channels | 950 | unsigned int channels |
| 874 | ) | 951 | ) |
| 875 | { | 952 | { |
| 876 | u16 val = 0xff00; | ||
| 877 | unsigned long flags; | 953 | unsigned long flags; |
| 954 | const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; | ||
| 955 | u16 val = 0xff00; | ||
| 878 | 956 | ||
| 879 | snd_azf3328_dbgcallenter(); | 957 | snd_azf3328_dbgcallenter(); |
| 880 | switch (bitrate) { | 958 | switch (bitrate) { |
| @@ -917,7 +995,7 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, | |||
| 917 | spin_lock_irqsave(&chip->reg_lock, flags); | 995 | spin_lock_irqsave(&chip->reg_lock, flags); |
| 918 | 996 | ||
| 919 | /* set bitrate/format */ | 997 | /* set bitrate/format */ |
| 920 | snd_azf3328_codec_outw(chip, reg, val); | 998 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_SOUNDFORMAT, val); |
| 921 | 999 | ||
| 922 | /* changing the bitrate/format settings switches off the | 1000 | /* changing the bitrate/format settings switches off the |
| 923 | * audio output with an annoying click in case of 8/16bit format change | 1001 | * audio output with an annoying click in case of 8/16bit format change |
| @@ -926,11 +1004,11 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, | |||
| 926 | * (FIXME: yes, it works, but what exactly am I doing here?? :) | 1004 | * (FIXME: yes, it works, but what exactly am I doing here?? :) |
| 927 | * FIXME: does this have some side effects for full-duplex | 1005 | * FIXME: does this have some side effects for full-duplex |
| 928 | * or other dramatic side effects? */ | 1006 | * or other dramatic side effects? */ |
| 929 | if (reg == IDX_IO_PLAY_SOUNDFORMAT) /* only do it for playback */ | 1007 | if (codec_type == AZF_CODEC_PLAYBACK) /* only do it for playback */ |
| 930 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, | 1008 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, |
| 931 | snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) | | 1009 | snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS) | |
| 932 | DMA_PLAY_SOMETHING1 | | 1010 | DMA_RUN_SOMETHING1 | |
| 933 | DMA_PLAY_SOMETHING2 | | 1011 | DMA_RUN_SOMETHING2 | |
| 934 | SOMETHING_ALMOST_ALWAYS_SET | | 1012 | SOMETHING_ALMOST_ALWAYS_SET | |
| 935 | DMA_EPILOGUE_SOMETHING | | 1013 | DMA_EPILOGUE_SOMETHING | |
| 936 | DMA_SOMETHING_ELSE | 1014 | DMA_SOMETHING_ELSE |
| @@ -942,112 +1020,134 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, | |||
| 942 | 1020 | ||
| 943 | static inline void | 1021 | static inline void |
| 944 | snd_azf3328_codec_setfmt_lowpower(struct snd_azf3328 *chip, | 1022 | snd_azf3328_codec_setfmt_lowpower(struct snd_azf3328 *chip, |
| 945 | unsigned reg | 1023 | enum snd_azf3328_codec_type codec_type |
| 946 | ) | 1024 | ) |
| 947 | { | 1025 | { |
| 948 | /* choose lowest frequency for low power consumption. | 1026 | /* choose lowest frequency for low power consumption. |
| 949 | * While this will cause louder noise due to rather coarse frequency, | 1027 | * While this will cause louder noise due to rather coarse frequency, |
| 950 | * it should never matter since output should always | 1028 | * it should never matter since output should always |
| 951 | * get disabled properly when idle anyway. */ | 1029 | * get disabled properly when idle anyway. */ |
| 952 | snd_azf3328_codec_setfmt(chip, reg, AZF_FREQ_4000, 8, 1); | 1030 | snd_azf3328_codec_setfmt(chip, codec_type, AZF_FREQ_4000, 8, 1); |
| 953 | } | 1031 | } |
| 954 | 1032 | ||
| 955 | static void | 1033 | static void |
| 956 | snd_azf3328_codec_reg_6AH_update(struct snd_azf3328 *chip, | 1034 | snd_azf3328_ctrl_reg_6AH_update(struct snd_azf3328 *chip, |
| 957 | unsigned bitmask, | 1035 | unsigned bitmask, |
| 958 | int enable | 1036 | bool enable |
| 959 | ) | 1037 | ) |
| 960 | { | 1038 | { |
| 961 | if (enable) | 1039 | bool do_mask = !enable; |
| 962 | chip->shadow_reg_codec_6AH &= ~bitmask; | 1040 | if (do_mask) |
| 1041 | chip->shadow_reg_ctrl_6AH |= bitmask; | ||
| 963 | else | 1042 | else |
| 964 | chip->shadow_reg_codec_6AH |= bitmask; | 1043 | chip->shadow_reg_ctrl_6AH &= ~bitmask; |
| 965 | snd_azf3328_dbgplay("6AH_update mask 0x%04x enable %d: val 0x%04x\n", | 1044 | snd_azf3328_dbgcodec("6AH_update mask 0x%04x do_mask %d: val 0x%04x\n", |
| 966 | bitmask, enable, chip->shadow_reg_codec_6AH); | 1045 | bitmask, do_mask, chip->shadow_reg_ctrl_6AH); |
| 967 | snd_azf3328_codec_outw(chip, IDX_IO_6AH, chip->shadow_reg_codec_6AH); | 1046 | snd_azf3328_ctrl_outw(chip, IDX_IO_6AH, chip->shadow_reg_ctrl_6AH); |
| 968 | } | 1047 | } |
| 969 | 1048 | ||
| 970 | static inline void | 1049 | static inline void |
| 971 | snd_azf3328_codec_enable(struct snd_azf3328 *chip, int enable) | 1050 | snd_azf3328_ctrl_enable_codecs(struct snd_azf3328 *chip, bool enable) |
| 972 | { | 1051 | { |
| 973 | snd_azf3328_dbgplay("codec_enable %d\n", enable); | 1052 | snd_azf3328_dbgcodec("codec_enable %d\n", enable); |
| 974 | /* no idea what exactly is being done here, but I strongly assume it's | 1053 | /* no idea what exactly is being done here, but I strongly assume it's |
| 975 | * PM related */ | 1054 | * PM related */ |
| 976 | snd_azf3328_codec_reg_6AH_update( | 1055 | snd_azf3328_ctrl_reg_6AH_update( |
| 977 | chip, IO_6A_PAUSE_PLAYBACK_BIT8, enable | 1056 | chip, IO_6A_PAUSE_PLAYBACK_BIT8, enable |
| 978 | ); | 1057 | ); |
| 979 | } | 1058 | } |
| 980 | 1059 | ||
| 981 | static void | 1060 | static void |
| 982 | snd_azf3328_codec_activity(struct snd_azf3328 *chip, | 1061 | snd_azf3328_ctrl_codec_activity(struct snd_azf3328 *chip, |
| 983 | enum snd_azf3328_stream_index stream_type, | 1062 | enum snd_azf3328_codec_type codec_type, |
| 984 | int enable | 1063 | bool enable |
| 985 | ) | 1064 | ) |
| 986 | { | 1065 | { |
| 987 | int need_change = (chip->audio_stream[stream_type].running != enable); | 1066 | struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; |
| 1067 | bool need_change = (codec->running != enable); | ||
| 988 | 1068 | ||
| 989 | snd_azf3328_dbgplay( | 1069 | snd_azf3328_dbgcodec( |
| 990 | "codec_activity: type %d, enable %d, need_change %d\n", | 1070 | "codec_activity: %s codec, enable %d, need_change %d\n", |
| 991 | stream_type, enable, need_change | 1071 | codec->name, enable, need_change |
| 992 | ); | 1072 | ); |
| 993 | if (need_change) { | 1073 | if (need_change) { |
| 994 | enum snd_azf3328_stream_index other = | 1074 | static const struct { |
| 995 | (stream_type == AZF_PLAYBACK) ? | 1075 | enum snd_azf3328_codec_type other1; |
| 996 | AZF_CAPTURE : AZF_PLAYBACK; | 1076 | enum snd_azf3328_codec_type other2; |
| 997 | /* small check to prevent shutting down the other party | 1077 | } peer_codecs[3] = |
| 998 | * in case it's active */ | 1078 | { { AZF_CODEC_CAPTURE, AZF_CODEC_I2S_OUT }, |
| 999 | if ((enable) || !(chip->audio_stream[other].running)) | 1079 | { AZF_CODEC_PLAYBACK, AZF_CODEC_I2S_OUT }, |
| 1000 | snd_azf3328_codec_enable(chip, enable); | 1080 | { AZF_CODEC_PLAYBACK, AZF_CODEC_CAPTURE } }; |
| 1081 | bool call_function; | ||
| 1082 | |||
| 1083 | if (enable) | ||
| 1084 | /* if enable codec, call enable_codecs func | ||
| 1085 | to enable codec supply... */ | ||
| 1086 | call_function = 1; | ||
| 1087 | else { | ||
| 1088 | /* ...otherwise call enable_codecs func | ||
| 1089 | (which globally shuts down operation of codecs) | ||
| 1090 | only in case the other codecs are currently | ||
| 1091 | not active either! */ | ||
| 1092 | call_function = | ||
| 1093 | ((!chip->codecs[peer_codecs[codec_type].other1] | ||
| 1094 | .running) | ||
| 1095 | && (!chip->codecs[peer_codecs[codec_type].other2] | ||
| 1096 | .running)); | ||
| 1097 | } | ||
| 1098 | if (call_function) | ||
| 1099 | snd_azf3328_ctrl_enable_codecs(chip, enable); | ||
| 1001 | 1100 | ||
| 1002 | /* ...and adjust clock, too | 1101 | /* ...and adjust clock, too |
| 1003 | * (reduce noise and power consumption) */ | 1102 | * (reduce noise and power consumption) */ |
| 1004 | if (!enable) | 1103 | if (!enable) |
| 1005 | snd_azf3328_codec_setfmt_lowpower( | 1104 | snd_azf3328_codec_setfmt_lowpower( |
| 1006 | chip, | 1105 | chip, |
| 1007 | chip->audio_stream[stream_type].portbase | 1106 | codec_type |
| 1008 | + IDX_IO_PLAY_SOUNDFORMAT | ||
| 1009 | ); | 1107 | ); |
| 1108 | codec->running = enable; | ||
| 1010 | } | 1109 | } |
| 1011 | chip->audio_stream[stream_type].running = enable; | ||
| 1012 | } | 1110 | } |
| 1013 | 1111 | ||
| 1014 | static void | 1112 | static void |
| 1015 | snd_azf3328_setdmaa(struct snd_azf3328 *chip, | 1113 | snd_azf3328_codec_setdmaa(struct snd_azf3328 *chip, |
| 1016 | long unsigned int addr, | 1114 | enum snd_azf3328_codec_type codec_type, |
| 1017 | unsigned int count, | 1115 | unsigned long addr, |
| 1018 | unsigned int size, | 1116 | unsigned int count, |
| 1019 | enum snd_azf3328_stream_index stream_type | 1117 | unsigned int size |
| 1020 | ) | 1118 | ) |
| 1021 | { | 1119 | { |
| 1120 | const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; | ||
| 1022 | snd_azf3328_dbgcallenter(); | 1121 | snd_azf3328_dbgcallenter(); |
| 1023 | if (!chip->audio_stream[stream_type].running) { | 1122 | if (!codec->running) { |
| 1024 | /* AZF3328 uses a two buffer pointer DMA playback approach */ | 1123 | /* AZF3328 uses a two buffer pointer DMA transfer approach */ |
| 1025 | 1124 | ||
| 1026 | unsigned long flags, portbase, addr_area2; | 1125 | unsigned long flags, addr_area2; |
| 1027 | 1126 | ||
| 1028 | /* width 32bit (prevent overflow): */ | 1127 | /* width 32bit (prevent overflow): */ |
| 1029 | unsigned long count_areas, count_tmp; | 1128 | u32 count_areas, lengths; |
| 1030 | 1129 | ||
| 1031 | portbase = chip->audio_stream[stream_type].portbase; | ||
| 1032 | count_areas = size/2; | 1130 | count_areas = size/2; |
| 1033 | addr_area2 = addr+count_areas; | 1131 | addr_area2 = addr+count_areas; |
| 1034 | count_areas--; /* max. index */ | 1132 | count_areas--; /* max. index */ |
| 1035 | snd_azf3328_dbgplay("set DMA: buf1 %08lx[%lu], buf2 %08lx[%lu]\n", addr, count_areas, addr_area2, count_areas); | 1133 | snd_azf3328_dbgcodec("setdma: buffers %08lx[%u] / %08lx[%u]\n", |
| 1134 | addr, count_areas, addr_area2, count_areas); | ||
| 1036 | 1135 | ||
| 1037 | /* build combined I/O buffer length word */ | 1136 | /* build combined I/O buffer length word */ |
| 1038 | count_tmp = count_areas; | 1137 | lengths = (count_areas << 16) | (count_areas); |
| 1039 | count_areas |= (count_tmp << 16); | ||
| 1040 | spin_lock_irqsave(&chip->reg_lock, flags); | 1138 | spin_lock_irqsave(&chip->reg_lock, flags); |
| 1041 | outl(addr, portbase + IDX_IO_PLAY_DMA_START_1); | 1139 | snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_START_1, addr); |
| 1042 | outl(addr_area2, portbase + IDX_IO_PLAY_DMA_START_2); | 1140 | snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_START_2, |
| 1043 | outl(count_areas, portbase + IDX_IO_PLAY_DMA_LEN_1); | 1141 | addr_area2); |
| 1142 | snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_LENGTHS, | ||
| 1143 | lengths); | ||
| 1044 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 1144 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
| 1045 | } | 1145 | } |
| 1046 | snd_azf3328_dbgcallleave(); | 1146 | snd_azf3328_dbgcallleave(); |
| 1047 | } | 1147 | } |
| 1048 | 1148 | ||
| 1049 | static int | 1149 | static int |
| 1050 | snd_azf3328_playback_prepare(struct snd_pcm_substream *substream) | 1150 | snd_azf3328_codec_prepare(struct snd_pcm_substream *substream) |
| 1051 | { | 1151 | { |
| 1052 | #if 0 | 1152 | #if 0 |
| 1053 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1153 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); |
| @@ -1058,157 +1158,161 @@ snd_azf3328_playback_prepare(struct snd_pcm_substream *substream) | |||
| 1058 | 1158 | ||
| 1059 | snd_azf3328_dbgcallenter(); | 1159 | snd_azf3328_dbgcallenter(); |
| 1060 | #if 0 | 1160 | #if 0 |
| 1061 | snd_azf3328_codec_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, | 1161 | snd_azf3328_codec_setfmt(chip, AZF_CODEC_..., |
| 1062 | runtime->rate, | 1162 | runtime->rate, |
| 1063 | snd_pcm_format_width(runtime->format), | 1163 | snd_pcm_format_width(runtime->format), |
| 1064 | runtime->channels); | 1164 | runtime->channels); |
| 1065 | snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, AZF_PLAYBACK); | 1165 | snd_azf3328_codec_setdmaa(chip, AZF_CODEC_..., |
| 1166 | runtime->dma_addr, count, size); | ||
| 1066 | #endif | 1167 | #endif |
| 1067 | snd_azf3328_dbgcallleave(); | 1168 | snd_azf3328_dbgcallleave(); |
| 1068 | return 0; | 1169 | return 0; |
| 1069 | } | 1170 | } |
| 1070 | 1171 | ||
| 1071 | static int | 1172 | static int |
| 1072 | snd_azf3328_capture_prepare(struct snd_pcm_substream *substream) | 1173 | snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, |
| 1073 | { | 1174 | struct snd_pcm_substream *substream, int cmd) |
| 1074 | #if 0 | ||
| 1075 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | ||
| 1076 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
| 1077 | unsigned int size = snd_pcm_lib_buffer_bytes(substream); | ||
| 1078 | unsigned int count = snd_pcm_lib_period_bytes(substream); | ||
| 1079 | #endif | ||
| 1080 | |||
| 1081 | snd_azf3328_dbgcallenter(); | ||
| 1082 | #if 0 | ||
| 1083 | snd_azf3328_codec_setfmt(chip, IDX_IO_REC_SOUNDFORMAT, | ||
| 1084 | runtime->rate, | ||
| 1085 | snd_pcm_format_width(runtime->format), | ||
| 1086 | runtime->channels); | ||
| 1087 | snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, AZF_CAPTURE); | ||
| 1088 | #endif | ||
| 1089 | snd_azf3328_dbgcallleave(); | ||
| 1090 | return 0; | ||
| 1091 | } | ||
| 1092 | |||
| 1093 | static int | ||
| 1094 | snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) | ||
| 1095 | { | 1175 | { |
| 1096 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1176 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); |
| 1177 | const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; | ||
| 1097 | struct snd_pcm_runtime *runtime = substream->runtime; | 1178 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 1098 | int result = 0; | 1179 | int result = 0; |
| 1099 | unsigned int status1; | 1180 | u16 flags1; |
| 1100 | int previously_muted; | 1181 | bool previously_muted = 0; |
| 1182 | bool is_playback_codec = (AZF_CODEC_PLAYBACK == codec_type); | ||
| 1101 | 1183 | ||
| 1102 | snd_azf3328_dbgcalls("snd_azf3328_playback_trigger cmd %d\n", cmd); | 1184 | snd_azf3328_dbgcalls("snd_azf3328_codec_trigger cmd %d\n", cmd); |
| 1103 | 1185 | ||
| 1104 | switch (cmd) { | 1186 | switch (cmd) { |
| 1105 | case SNDRV_PCM_TRIGGER_START: | 1187 | case SNDRV_PCM_TRIGGER_START: |
| 1106 | snd_azf3328_dbgplay("START PLAYBACK\n"); | 1188 | snd_azf3328_dbgcodec("START %s\n", codec->name); |
| 1107 | 1189 | ||
| 1108 | /* mute WaveOut (avoid clicking during setup) */ | 1190 | if (is_playback_codec) { |
| 1109 | previously_muted = | 1191 | /* mute WaveOut (avoid clicking during setup) */ |
| 1110 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); | 1192 | previously_muted = |
| 1193 | snd_azf3328_mixer_set_mute( | ||
| 1194 | chip, IDX_MIXER_WAVEOUT, 1 | ||
| 1195 | ); | ||
| 1196 | } | ||
| 1111 | 1197 | ||
| 1112 | snd_azf3328_codec_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, | 1198 | snd_azf3328_codec_setfmt(chip, codec_type, |
| 1113 | runtime->rate, | 1199 | runtime->rate, |
| 1114 | snd_pcm_format_width(runtime->format), | 1200 | snd_pcm_format_width(runtime->format), |
| 1115 | runtime->channels); | 1201 | runtime->channels); |
| 1116 | 1202 | ||
| 1117 | spin_lock(&chip->reg_lock); | 1203 | spin_lock(&chip->reg_lock); |
| 1118 | /* first, remember current value: */ | 1204 | /* first, remember current value: */ |
| 1119 | status1 = snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS); | 1205 | flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS); |
| 1120 | 1206 | ||
| 1121 | /* stop playback */ | 1207 | /* stop transfer */ |
| 1122 | status1 &= ~DMA_RESUME; | 1208 | flags1 &= ~DMA_RESUME; |
| 1123 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); | 1209 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); |
| 1124 | 1210 | ||
| 1125 | /* FIXME: clear interrupts or what??? */ | 1211 | /* FIXME: clear interrupts or what??? */ |
| 1126 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_IRQTYPE, 0xffff); | 1212 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_IRQTYPE, 0xffff); |
| 1127 | spin_unlock(&chip->reg_lock); | 1213 | spin_unlock(&chip->reg_lock); |
| 1128 | 1214 | ||
| 1129 | snd_azf3328_setdmaa(chip, runtime->dma_addr, | 1215 | snd_azf3328_codec_setdmaa(chip, codec_type, runtime->dma_addr, |
| 1130 | snd_pcm_lib_period_bytes(substream), | 1216 | snd_pcm_lib_period_bytes(substream), |
| 1131 | snd_pcm_lib_buffer_bytes(substream), | 1217 | snd_pcm_lib_buffer_bytes(substream) |
| 1132 | AZF_PLAYBACK); | 1218 | ); |
| 1133 | 1219 | ||
| 1134 | spin_lock(&chip->reg_lock); | 1220 | spin_lock(&chip->reg_lock); |
| 1135 | #ifdef WIN9X | 1221 | #ifdef WIN9X |
| 1136 | /* FIXME: enable playback/recording??? */ | 1222 | /* FIXME: enable playback/recording??? */ |
| 1137 | status1 |= DMA_PLAY_SOMETHING1 | DMA_PLAY_SOMETHING2; | 1223 | flags1 |= DMA_RUN_SOMETHING1 | DMA_RUN_SOMETHING2; |
| 1138 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); | 1224 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); |
| 1139 | 1225 | ||
| 1140 | /* start playback again */ | 1226 | /* start transfer again */ |
| 1141 | /* FIXME: what is this value (0x0010)??? */ | 1227 | /* FIXME: what is this value (0x0010)??? */ |
| 1142 | status1 |= DMA_RESUME | DMA_EPILOGUE_SOMETHING; | 1228 | flags1 |= DMA_RESUME | DMA_EPILOGUE_SOMETHING; |
| 1143 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); | 1229 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); |
| 1144 | #else /* NT4 */ | 1230 | #else /* NT4 */ |
| 1145 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, | 1231 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, |
| 1146 | 0x0000); | 1232 | 0x0000); |
| 1147 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, | 1233 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, |
| 1148 | DMA_PLAY_SOMETHING1); | 1234 | DMA_RUN_SOMETHING1); |
| 1149 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, | 1235 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, |
| 1150 | DMA_PLAY_SOMETHING1 | | 1236 | DMA_RUN_SOMETHING1 | |
| 1151 | DMA_PLAY_SOMETHING2); | 1237 | DMA_RUN_SOMETHING2); |
| 1152 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, | 1238 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, |
| 1153 | DMA_RESUME | | 1239 | DMA_RESUME | |
| 1154 | SOMETHING_ALMOST_ALWAYS_SET | | 1240 | SOMETHING_ALMOST_ALWAYS_SET | |
| 1155 | DMA_EPILOGUE_SOMETHING | | 1241 | DMA_EPILOGUE_SOMETHING | |
| 1156 | DMA_SOMETHING_ELSE); | 1242 | DMA_SOMETHING_ELSE); |
| 1157 | #endif | 1243 | #endif |
| 1158 | spin_unlock(&chip->reg_lock); | 1244 | spin_unlock(&chip->reg_lock); |
| 1159 | snd_azf3328_codec_activity(chip, AZF_PLAYBACK, 1); | 1245 | snd_azf3328_ctrl_codec_activity(chip, codec_type, 1); |
| 1160 | 1246 | ||
| 1161 | /* now unmute WaveOut */ | 1247 | if (is_playback_codec) { |
| 1162 | if (!previously_muted) | 1248 | /* now unmute WaveOut */ |
| 1163 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0); | 1249 | if (!previously_muted) |
| 1250 | snd_azf3328_mixer_set_mute( | ||
| 1251 | chip, IDX_MIXER_WAVEOUT, 0 | ||
| 1252 | ); | ||
| 1253 | } | ||
| 1164 | 1254 | ||
| 1165 | snd_azf3328_dbgplay("STARTED PLAYBACK\n"); | 1255 | snd_azf3328_dbgcodec("STARTED %s\n", codec->name); |
| 1166 | break; | 1256 | break; |
| 1167 | case SNDRV_PCM_TRIGGER_RESUME: | 1257 | case SNDRV_PCM_TRIGGER_RESUME: |
| 1168 | snd_azf3328_dbgplay("RESUME PLAYBACK\n"); | 1258 | snd_azf3328_dbgcodec("RESUME %s\n", codec->name); |
| 1169 | /* resume playback if we were active */ | 1259 | /* resume codec if we were active */ |
| 1170 | spin_lock(&chip->reg_lock); | 1260 | spin_lock(&chip->reg_lock); |
| 1171 | if (chip->audio_stream[AZF_PLAYBACK].running) | 1261 | if (codec->running) |
| 1172 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, | 1262 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, |
| 1173 | snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) | DMA_RESUME); | 1263 | snd_azf3328_codec_inw( |
| 1264 | codec, IDX_IO_CODEC_DMA_FLAGS | ||
| 1265 | ) | DMA_RESUME | ||
| 1266 | ); | ||
| 1174 | spin_unlock(&chip->reg_lock); | 1267 | spin_unlock(&chip->reg_lock); |
| 1175 | break; | 1268 | break; |
| 1176 | case SNDRV_PCM_TRIGGER_STOP: | 1269 | case SNDRV_PCM_TRIGGER_STOP: |
| 1177 | snd_azf3328_dbgplay("STOP PLAYBACK\n"); | 1270 | snd_azf3328_dbgcodec("STOP %s\n", codec->name); |
| 1178 | 1271 | ||
| 1179 | /* mute WaveOut (avoid clicking during setup) */ | 1272 | if (is_playback_codec) { |
| 1180 | previously_muted = | 1273 | /* mute WaveOut (avoid clicking during setup) */ |
| 1181 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); | 1274 | previously_muted = |
| 1275 | snd_azf3328_mixer_set_mute( | ||
| 1276 | chip, IDX_MIXER_WAVEOUT, 1 | ||
| 1277 | ); | ||
| 1278 | } | ||
| 1182 | 1279 | ||
| 1183 | spin_lock(&chip->reg_lock); | 1280 | spin_lock(&chip->reg_lock); |
| 1184 | /* first, remember current value: */ | 1281 | /* first, remember current value: */ |
| 1185 | status1 = snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS); | 1282 | flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS); |
| 1186 | 1283 | ||
| 1187 | /* stop playback */ | 1284 | /* stop transfer */ |
| 1188 | status1 &= ~DMA_RESUME; | 1285 | flags1 &= ~DMA_RESUME; |
| 1189 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); | 1286 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); |
| 1190 | 1287 | ||
| 1191 | /* hmm, is this really required? we're resetting the same bit | 1288 | /* hmm, is this really required? we're resetting the same bit |
| 1192 | * immediately thereafter... */ | 1289 | * immediately thereafter... */ |
| 1193 | status1 |= DMA_PLAY_SOMETHING1; | 1290 | flags1 |= DMA_RUN_SOMETHING1; |
| 1194 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); | 1291 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); |
| 1195 | 1292 | ||
| 1196 | status1 &= ~DMA_PLAY_SOMETHING1; | 1293 | flags1 &= ~DMA_RUN_SOMETHING1; |
| 1197 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); | 1294 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); |
| 1198 | spin_unlock(&chip->reg_lock); | 1295 | spin_unlock(&chip->reg_lock); |
| 1199 | snd_azf3328_codec_activity(chip, AZF_PLAYBACK, 0); | 1296 | snd_azf3328_ctrl_codec_activity(chip, codec_type, 0); |
| 1200 | 1297 | ||
| 1201 | /* now unmute WaveOut */ | 1298 | if (is_playback_codec) { |
| 1202 | if (!previously_muted) | 1299 | /* now unmute WaveOut */ |
| 1203 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0); | 1300 | if (!previously_muted) |
| 1301 | snd_azf3328_mixer_set_mute( | ||
| 1302 | chip, IDX_MIXER_WAVEOUT, 0 | ||
| 1303 | ); | ||
| 1304 | } | ||
| 1204 | 1305 | ||
| 1205 | snd_azf3328_dbgplay("STOPPED PLAYBACK\n"); | 1306 | snd_azf3328_dbgcodec("STOPPED %s\n", codec->name); |
| 1206 | break; | 1307 | break; |
| 1207 | case SNDRV_PCM_TRIGGER_SUSPEND: | 1308 | case SNDRV_PCM_TRIGGER_SUSPEND: |
| 1208 | snd_azf3328_dbgplay("SUSPEND PLAYBACK\n"); | 1309 | snd_azf3328_dbgcodec("SUSPEND %s\n", codec->name); |
| 1209 | /* make sure playback is stopped */ | 1310 | /* make sure codec is stopped */ |
| 1210 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, | 1311 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, |
| 1211 | snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) & ~DMA_RESUME); | 1312 | snd_azf3328_codec_inw( |
| 1313 | codec, IDX_IO_CODEC_DMA_FLAGS | ||
| 1314 | ) & ~DMA_RESUME | ||
| 1315 | ); | ||
| 1212 | break; | 1316 | break; |
| 1213 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 1317 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
| 1214 | snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n"); | 1318 | snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n"); |
| @@ -1217,7 +1321,7 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 1217 | snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n"); | 1321 | snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n"); |
| 1218 | break; | 1322 | break; |
| 1219 | default: | 1323 | default: |
| 1220 | printk(KERN_ERR "FIXME: unknown trigger mode!\n"); | 1324 | snd_printk(KERN_ERR "FIXME: unknown trigger mode!\n"); |
| 1221 | return -EINVAL; | 1325 | return -EINVAL; |
| 1222 | } | 1326 | } |
| 1223 | 1327 | ||
| @@ -1225,172 +1329,74 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) | |||
| 1225 | return result; | 1329 | return result; |
| 1226 | } | 1330 | } |
| 1227 | 1331 | ||
| 1228 | /* this is just analogous to playback; I'm not quite sure whether recording | ||
| 1229 | * should actually be triggered like that */ | ||
| 1230 | static int | 1332 | static int |
| 1231 | snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd) | 1333 | snd_azf3328_codec_playback_trigger(struct snd_pcm_substream *substream, int cmd) |
| 1232 | { | 1334 | { |
| 1233 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1335 | return snd_azf3328_codec_trigger(AZF_CODEC_PLAYBACK, substream, cmd); |
| 1234 | struct snd_pcm_runtime *runtime = substream->runtime; | 1336 | } |
| 1235 | int result = 0; | ||
| 1236 | unsigned int status1; | ||
| 1237 | |||
| 1238 | snd_azf3328_dbgcalls("snd_azf3328_capture_trigger cmd %d\n", cmd); | ||
| 1239 | |||
| 1240 | switch (cmd) { | ||
| 1241 | case SNDRV_PCM_TRIGGER_START: | ||
| 1242 | |||
| 1243 | snd_azf3328_dbgplay("START CAPTURE\n"); | ||
| 1244 | |||
| 1245 | snd_azf3328_codec_setfmt(chip, IDX_IO_REC_SOUNDFORMAT, | ||
| 1246 | runtime->rate, | ||
| 1247 | snd_pcm_format_width(runtime->format), | ||
| 1248 | runtime->channels); | ||
| 1249 | |||
| 1250 | spin_lock(&chip->reg_lock); | ||
| 1251 | /* first, remember current value: */ | ||
| 1252 | status1 = snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS); | ||
| 1253 | |||
| 1254 | /* stop recording */ | ||
| 1255 | status1 &= ~DMA_RESUME; | ||
| 1256 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); | ||
| 1257 | |||
| 1258 | /* FIXME: clear interrupts or what??? */ | ||
| 1259 | snd_azf3328_codec_outw(chip, IDX_IO_REC_IRQTYPE, 0xffff); | ||
| 1260 | spin_unlock(&chip->reg_lock); | ||
| 1261 | |||
| 1262 | snd_azf3328_setdmaa(chip, runtime->dma_addr, | ||
| 1263 | snd_pcm_lib_period_bytes(substream), | ||
| 1264 | snd_pcm_lib_buffer_bytes(substream), | ||
| 1265 | AZF_CAPTURE); | ||
| 1266 | |||
| 1267 | spin_lock(&chip->reg_lock); | ||
| 1268 | #ifdef WIN9X | ||
| 1269 | /* FIXME: enable playback/recording??? */ | ||
| 1270 | status1 |= DMA_PLAY_SOMETHING1 | DMA_PLAY_SOMETHING2; | ||
| 1271 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); | ||
| 1272 | |||
| 1273 | /* start capture again */ | ||
| 1274 | /* FIXME: what is this value (0x0010)??? */ | ||
| 1275 | status1 |= DMA_RESUME | DMA_EPILOGUE_SOMETHING; | ||
| 1276 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); | ||
| 1277 | #else | ||
| 1278 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, | ||
| 1279 | 0x0000); | ||
| 1280 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, | ||
| 1281 | DMA_PLAY_SOMETHING1); | ||
| 1282 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, | ||
| 1283 | DMA_PLAY_SOMETHING1 | | ||
| 1284 | DMA_PLAY_SOMETHING2); | ||
| 1285 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, | ||
| 1286 | DMA_RESUME | | ||
| 1287 | SOMETHING_ALMOST_ALWAYS_SET | | ||
| 1288 | DMA_EPILOGUE_SOMETHING | | ||
| 1289 | DMA_SOMETHING_ELSE); | ||
| 1290 | #endif | ||
| 1291 | spin_unlock(&chip->reg_lock); | ||
| 1292 | snd_azf3328_codec_activity(chip, AZF_CAPTURE, 1); | ||
| 1293 | |||
| 1294 | snd_azf3328_dbgplay("STARTED CAPTURE\n"); | ||
| 1295 | break; | ||
| 1296 | case SNDRV_PCM_TRIGGER_RESUME: | ||
| 1297 | snd_azf3328_dbgplay("RESUME CAPTURE\n"); | ||
| 1298 | /* resume recording if we were active */ | ||
| 1299 | spin_lock(&chip->reg_lock); | ||
| 1300 | if (chip->audio_stream[AZF_CAPTURE].running) | ||
| 1301 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, | ||
| 1302 | snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS) | DMA_RESUME); | ||
| 1303 | spin_unlock(&chip->reg_lock); | ||
| 1304 | break; | ||
| 1305 | case SNDRV_PCM_TRIGGER_STOP: | ||
| 1306 | snd_azf3328_dbgplay("STOP CAPTURE\n"); | ||
| 1307 | |||
| 1308 | spin_lock(&chip->reg_lock); | ||
| 1309 | /* first, remember current value: */ | ||
| 1310 | status1 = snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS); | ||
| 1311 | |||
| 1312 | /* stop recording */ | ||
| 1313 | status1 &= ~DMA_RESUME; | ||
| 1314 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); | ||
| 1315 | |||
| 1316 | status1 |= DMA_PLAY_SOMETHING1; | ||
| 1317 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); | ||
| 1318 | |||
| 1319 | status1 &= ~DMA_PLAY_SOMETHING1; | ||
| 1320 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, status1); | ||
| 1321 | spin_unlock(&chip->reg_lock); | ||
| 1322 | snd_azf3328_codec_activity(chip, AZF_CAPTURE, 0); | ||
| 1323 | 1337 | ||
| 1324 | snd_azf3328_dbgplay("STOPPED CAPTURE\n"); | 1338 | static int |
| 1325 | break; | 1339 | snd_azf3328_codec_capture_trigger(struct snd_pcm_substream *substream, int cmd) |
| 1326 | case SNDRV_PCM_TRIGGER_SUSPEND: | 1340 | { |
| 1327 | snd_azf3328_dbgplay("SUSPEND CAPTURE\n"); | 1341 | return snd_azf3328_codec_trigger(AZF_CODEC_CAPTURE, substream, cmd); |
| 1328 | /* make sure recording is stopped */ | 1342 | } |
| 1329 | snd_azf3328_codec_outw(chip, IDX_IO_REC_FLAGS, | ||
| 1330 | snd_azf3328_codec_inw(chip, IDX_IO_REC_FLAGS) & ~DMA_RESUME); | ||
| 1331 | break; | ||
| 1332 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
| 1333 | snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n"); | ||
| 1334 | break; | ||
| 1335 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
| 1336 | snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_RELEASE NIY!\n"); | ||
| 1337 | break; | ||
| 1338 | default: | ||
| 1339 | printk(KERN_ERR "FIXME: unknown trigger mode!\n"); | ||
| 1340 | return -EINVAL; | ||
| 1341 | } | ||
| 1342 | 1343 | ||
| 1343 | snd_azf3328_dbgcallleave(); | 1344 | static int |
| 1344 | return result; | 1345 | snd_azf3328_codec_i2s_out_trigger(struct snd_pcm_substream *substream, int cmd) |
| 1346 | { | ||
| 1347 | return snd_azf3328_codec_trigger(AZF_CODEC_I2S_OUT, substream, cmd); | ||
| 1345 | } | 1348 | } |
| 1346 | 1349 | ||
| 1347 | static snd_pcm_uframes_t | 1350 | static snd_pcm_uframes_t |
| 1348 | snd_azf3328_playback_pointer(struct snd_pcm_substream *substream) | 1351 | snd_azf3328_codec_pointer(struct snd_pcm_substream *substream, |
| 1352 | enum snd_azf3328_codec_type codec_type | ||
| 1353 | ) | ||
| 1349 | { | 1354 | { |
| 1350 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1355 | const struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); |
| 1356 | const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; | ||
| 1351 | unsigned long bufptr, result; | 1357 | unsigned long bufptr, result; |
| 1352 | snd_pcm_uframes_t frmres; | 1358 | snd_pcm_uframes_t frmres; |
| 1353 | 1359 | ||
| 1354 | #ifdef QUERY_HARDWARE | 1360 | #ifdef QUERY_HARDWARE |
| 1355 | bufptr = snd_azf3328_codec_inl(chip, IDX_IO_PLAY_DMA_START_1); | 1361 | bufptr = snd_azf3328_codec_inl(codec, IDX_IO_CODEC_DMA_START_1); |
| 1356 | #else | 1362 | #else |
| 1357 | bufptr = substream->runtime->dma_addr; | 1363 | bufptr = substream->runtime->dma_addr; |
| 1358 | #endif | 1364 | #endif |
| 1359 | result = snd_azf3328_codec_inl(chip, IDX_IO_PLAY_DMA_CURRPOS); | 1365 | result = snd_azf3328_codec_inl(codec, IDX_IO_CODEC_DMA_CURRPOS); |
| 1360 | 1366 | ||
| 1361 | /* calculate offset */ | 1367 | /* calculate offset */ |
| 1362 | result -= bufptr; | 1368 | result -= bufptr; |
| 1363 | frmres = bytes_to_frames( substream->runtime, result); | 1369 | frmres = bytes_to_frames( substream->runtime, result); |
| 1364 | snd_azf3328_dbgplay("PLAY @ 0x%8lx, frames %8ld\n", result, frmres); | 1370 | snd_azf3328_dbgcodec("%s @ 0x%8lx, frames %8ld\n", |
| 1371 | codec->name, result, frmres); | ||
| 1365 | return frmres; | 1372 | return frmres; |
| 1366 | } | 1373 | } |
| 1367 | 1374 | ||
| 1368 | static snd_pcm_uframes_t | 1375 | static snd_pcm_uframes_t |
| 1369 | snd_azf3328_capture_pointer(struct snd_pcm_substream *substream) | 1376 | snd_azf3328_codec_playback_pointer(struct snd_pcm_substream *substream) |
| 1370 | { | 1377 | { |
| 1371 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1378 | return snd_azf3328_codec_pointer(substream, AZF_CODEC_PLAYBACK); |
| 1372 | unsigned long bufptr, result; | 1379 | } |
| 1373 | snd_pcm_uframes_t frmres; | ||
| 1374 | 1380 | ||
| 1375 | #ifdef QUERY_HARDWARE | 1381 | static snd_pcm_uframes_t |
| 1376 | bufptr = snd_azf3328_codec_inl(chip, IDX_IO_REC_DMA_START_1); | 1382 | snd_azf3328_codec_capture_pointer(struct snd_pcm_substream *substream) |
| 1377 | #else | 1383 | { |
| 1378 | bufptr = substream->runtime->dma_addr; | 1384 | return snd_azf3328_codec_pointer(substream, AZF_CODEC_CAPTURE); |
| 1379 | #endif | 1385 | } |
| 1380 | result = snd_azf3328_codec_inl(chip, IDX_IO_REC_DMA_CURRPOS); | ||
| 1381 | 1386 | ||
| 1382 | /* calculate offset */ | 1387 | static snd_pcm_uframes_t |
| 1383 | result -= bufptr; | 1388 | snd_azf3328_codec_i2s_out_pointer(struct snd_pcm_substream *substream) |
| 1384 | frmres = bytes_to_frames( substream->runtime, result); | 1389 | { |
| 1385 | snd_azf3328_dbgplay("REC @ 0x%8lx, frames %8ld\n", result, frmres); | 1390 | return snd_azf3328_codec_pointer(substream, AZF_CODEC_I2S_OUT); |
| 1386 | return frmres; | ||
| 1387 | } | 1391 | } |
| 1388 | 1392 | ||
| 1389 | /******************************************************************/ | 1393 | /******************************************************************/ |
| 1390 | 1394 | ||
| 1391 | #ifdef SUPPORT_GAMEPORT | 1395 | #ifdef SUPPORT_GAMEPORT |
| 1392 | static inline void | 1396 | static inline void |
| 1393 | snd_azf3328_gameport_irq_enable(struct snd_azf3328 *chip, int enable) | 1397 | snd_azf3328_gameport_irq_enable(struct snd_azf3328 *chip, |
| 1398 | bool enable | ||
| 1399 | ) | ||
| 1394 | { | 1400 | { |
| 1395 | snd_azf3328_io_reg_setb( | 1401 | snd_azf3328_io_reg_setb( |
| 1396 | chip->game_io+IDX_GAME_HWCONFIG, | 1402 | chip->game_io+IDX_GAME_HWCONFIG, |
| @@ -1400,7 +1406,9 @@ snd_azf3328_gameport_irq_enable(struct snd_azf3328 *chip, int enable) | |||
| 1400 | } | 1406 | } |
| 1401 | 1407 | ||
| 1402 | static inline void | 1408 | static inline void |
| 1403 | snd_azf3328_gameport_legacy_address_enable(struct snd_azf3328 *chip, int enable) | 1409 | snd_azf3328_gameport_legacy_address_enable(struct snd_azf3328 *chip, |
| 1410 | bool enable | ||
| 1411 | ) | ||
| 1404 | { | 1412 | { |
| 1405 | snd_azf3328_io_reg_setb( | 1413 | snd_azf3328_io_reg_setb( |
| 1406 | chip->game_io+IDX_GAME_HWCONFIG, | 1414 | chip->game_io+IDX_GAME_HWCONFIG, |
| @@ -1409,10 +1417,27 @@ snd_azf3328_gameport_legacy_address_enable(struct snd_azf3328 *chip, int enable) | |||
| 1409 | ); | 1417 | ); |
| 1410 | } | 1418 | } |
| 1411 | 1419 | ||
| 1420 | static void | ||
| 1421 | snd_azf3328_gameport_set_counter_frequency(struct snd_azf3328 *chip, | ||
| 1422 | unsigned int freq_cfg | ||
| 1423 | ) | ||
| 1424 | { | ||
| 1425 | snd_azf3328_io_reg_setb( | ||
| 1426 | chip->game_io+IDX_GAME_HWCONFIG, | ||
| 1427 | 0x02, | ||
| 1428 | (freq_cfg & 1) != 0 | ||
| 1429 | ); | ||
| 1430 | snd_azf3328_io_reg_setb( | ||
| 1431 | chip->game_io+IDX_GAME_HWCONFIG, | ||
| 1432 | 0x04, | ||
| 1433 | (freq_cfg & 2) != 0 | ||
| 1434 | ); | ||
| 1435 | } | ||
| 1436 | |||
| 1412 | static inline void | 1437 | static inline void |
| 1413 | snd_azf3328_gameport_axis_circuit_enable(struct snd_azf3328 *chip, int enable) | 1438 | snd_azf3328_gameport_axis_circuit_enable(struct snd_azf3328 *chip, bool enable) |
| 1414 | { | 1439 | { |
| 1415 | snd_azf3328_codec_reg_6AH_update( | 1440 | snd_azf3328_ctrl_reg_6AH_update( |
| 1416 | chip, IO_6A_SOMETHING2_GAMEPORT, enable | 1441 | chip, IO_6A_SOMETHING2_GAMEPORT, enable |
| 1417 | ); | 1442 | ); |
| 1418 | } | 1443 | } |
| @@ -1447,6 +1472,8 @@ snd_azf3328_gameport_open(struct gameport *gameport, int mode) | |||
| 1447 | break; | 1472 | break; |
| 1448 | } | 1473 | } |
| 1449 | 1474 | ||
| 1475 | snd_azf3328_gameport_set_counter_frequency(chip, | ||
| 1476 | GAME_HWCFG_ADC_COUNTER_FREQ_STD); | ||
| 1450 | snd_azf3328_gameport_axis_circuit_enable(chip, (res == 0)); | 1477 | snd_azf3328_gameport_axis_circuit_enable(chip, (res == 0)); |
| 1451 | 1478 | ||
| 1452 | return res; | 1479 | return res; |
| @@ -1458,6 +1485,8 @@ snd_azf3328_gameport_close(struct gameport *gameport) | |||
| 1458 | struct snd_azf3328 *chip = gameport_get_port_data(gameport); | 1485 | struct snd_azf3328 *chip = gameport_get_port_data(gameport); |
| 1459 | 1486 | ||
| 1460 | snd_azf3328_dbggame("gameport_close\n"); | 1487 | snd_azf3328_dbggame("gameport_close\n"); |
| 1488 | snd_azf3328_gameport_set_counter_frequency(chip, | ||
| 1489 | GAME_HWCFG_ADC_COUNTER_FREQ_1_200); | ||
| 1461 | snd_azf3328_gameport_axis_circuit_enable(chip, 0); | 1490 | snd_azf3328_gameport_axis_circuit_enable(chip, 0); |
| 1462 | } | 1491 | } |
| 1463 | 1492 | ||
| @@ -1491,7 +1520,7 @@ snd_azf3328_gameport_cooked_read(struct gameport *gameport, | |||
| 1491 | 1520 | ||
| 1492 | val = snd_azf3328_game_inb(chip, IDX_GAME_AXES_CONFIG); | 1521 | val = snd_azf3328_game_inb(chip, IDX_GAME_AXES_CONFIG); |
| 1493 | if (val & GAME_AXES_SAMPLING_READY) { | 1522 | if (val & GAME_AXES_SAMPLING_READY) { |
| 1494 | for (i = 0; i < 4; ++i) { | 1523 | for (i = 0; i < ARRAY_SIZE(chip->axes); ++i) { |
| 1495 | /* configure the axis to read */ | 1524 | /* configure the axis to read */ |
| 1496 | val = (i << 4) | 0x0f; | 1525 | val = (i << 4) | 0x0f; |
| 1497 | snd_azf3328_game_outb(chip, IDX_GAME_AXES_CONFIG, val); | 1526 | snd_azf3328_game_outb(chip, IDX_GAME_AXES_CONFIG, val); |
| @@ -1514,7 +1543,7 @@ snd_azf3328_gameport_cooked_read(struct gameport *gameport, | |||
| 1514 | snd_azf3328_game_outw(chip, IDX_GAME_AXIS_VALUE, 0xffff); | 1543 | snd_azf3328_game_outw(chip, IDX_GAME_AXIS_VALUE, 0xffff); |
| 1515 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 1544 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
| 1516 | 1545 | ||
| 1517 | for (i = 0; i < 4; i++) { | 1546 | for (i = 0; i < ARRAY_SIZE(chip->axes); i++) { |
| 1518 | axes[i] = chip->axes[i]; | 1547 | axes[i] = chip->axes[i]; |
| 1519 | if (axes[i] == 0xffff) | 1548 | if (axes[i] == 0xffff) |
| 1520 | axes[i] = -1; | 1549 | axes[i] = -1; |
| @@ -1552,6 +1581,8 @@ snd_azf3328_gameport(struct snd_azf3328 *chip, int dev) | |||
| 1552 | /* DISABLE legacy address: we don't need it! */ | 1581 | /* DISABLE legacy address: we don't need it! */ |
| 1553 | snd_azf3328_gameport_legacy_address_enable(chip, 0); | 1582 | snd_azf3328_gameport_legacy_address_enable(chip, 0); |
| 1554 | 1583 | ||
| 1584 | snd_azf3328_gameport_set_counter_frequency(chip, | ||
| 1585 | GAME_HWCFG_ADC_COUNTER_FREQ_1_200); | ||
| 1555 | snd_azf3328_gameport_axis_circuit_enable(chip, 0); | 1586 | snd_azf3328_gameport_axis_circuit_enable(chip, 0); |
| 1556 | 1587 | ||
| 1557 | gameport_register_port(chip->gameport); | 1588 | gameport_register_port(chip->gameport); |
| @@ -1585,40 +1616,77 @@ snd_azf3328_gameport_interrupt(struct snd_azf3328 *chip) | |||
| 1585 | static inline void | 1616 | static inline void |
| 1586 | snd_azf3328_irq_log_unknown_type(u8 which) | 1617 | snd_azf3328_irq_log_unknown_type(u8 which) |
| 1587 | { | 1618 | { |
| 1588 | snd_azf3328_dbgplay( | 1619 | snd_azf3328_dbgcodec( |
| 1589 | "azt3328: unknown IRQ type (%x) occurred, please report!\n", | 1620 | "azt3328: unknown IRQ type (%x) occurred, please report!\n", |
| 1590 | which | 1621 | which |
| 1591 | ); | 1622 | ); |
| 1592 | } | 1623 | } |
| 1593 | 1624 | ||
| 1625 | static inline void | ||
| 1626 | snd_azf3328_codec_interrupt(struct snd_azf3328 *chip, u8 status) | ||
| 1627 | { | ||
| 1628 | u8 which; | ||
| 1629 | enum snd_azf3328_codec_type codec_type; | ||
| 1630 | const struct snd_azf3328_codec_data *codec; | ||
| 1631 | |||
| 1632 | for (codec_type = AZF_CODEC_PLAYBACK; | ||
| 1633 | codec_type <= AZF_CODEC_I2S_OUT; | ||
| 1634 | ++codec_type) { | ||
| 1635 | |||
| 1636 | /* skip codec if there's no interrupt for it */ | ||
| 1637 | if (!(status & (1 << codec_type))) | ||
| 1638 | continue; | ||
| 1639 | |||
| 1640 | codec = &chip->codecs[codec_type]; | ||
| 1641 | |||
| 1642 | spin_lock(&chip->reg_lock); | ||
| 1643 | which = snd_azf3328_codec_inb(codec, IDX_IO_CODEC_IRQTYPE); | ||
| 1644 | /* ack all IRQ types immediately */ | ||
| 1645 | snd_azf3328_codec_outb(codec, IDX_IO_CODEC_IRQTYPE, which); | ||
| 1646 | spin_unlock(&chip->reg_lock); | ||
| 1647 | |||
| 1648 | if ((chip->pcm[codec_type]) && (codec->substream)) { | ||
| 1649 | snd_pcm_period_elapsed(codec->substream); | ||
| 1650 | snd_azf3328_dbgcodec("%s period done (#%x), @ %x\n", | ||
| 1651 | codec->name, | ||
| 1652 | which, | ||
| 1653 | snd_azf3328_codec_inl( | ||
| 1654 | codec, IDX_IO_CODEC_DMA_CURRPOS | ||
| 1655 | ) | ||
| 1656 | ); | ||
| 1657 | } else | ||
| 1658 | printk(KERN_WARNING "azt3328: irq handler problem!\n"); | ||
| 1659 | if (which & IRQ_SOMETHING) | ||
| 1660 | snd_azf3328_irq_log_unknown_type(which); | ||
| 1661 | } | ||
| 1662 | } | ||
| 1663 | |||
| 1594 | static irqreturn_t | 1664 | static irqreturn_t |
| 1595 | snd_azf3328_interrupt(int irq, void *dev_id) | 1665 | snd_azf3328_interrupt(int irq, void *dev_id) |
| 1596 | { | 1666 | { |
| 1597 | struct snd_azf3328 *chip = dev_id; | 1667 | struct snd_azf3328 *chip = dev_id; |
| 1598 | u8 status, which; | 1668 | u8 status; |
| 1599 | #if DEBUG_PLAY_REC | 1669 | #if DEBUG_CODEC |
| 1600 | static unsigned long irq_count; | 1670 | static unsigned long irq_count; |
| 1601 | #endif | 1671 | #endif |
| 1602 | 1672 | ||
| 1603 | status = snd_azf3328_codec_inb(chip, IDX_IO_IRQSTATUS); | 1673 | status = snd_azf3328_ctrl_inb(chip, IDX_IO_IRQSTATUS); |
| 1604 | 1674 | ||
| 1605 | /* fast path out, to ease interrupt sharing */ | 1675 | /* fast path out, to ease interrupt sharing */ |
| 1606 | if (!(status & | 1676 | if (!(status & |
| 1607 | (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_GAMEPORT|IRQ_MPU401|IRQ_TIMER) | 1677 | (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_I2S_OUT |
| 1678 | |IRQ_GAMEPORT|IRQ_MPU401|IRQ_TIMER) | ||
| 1608 | )) | 1679 | )) |
| 1609 | return IRQ_NONE; /* must be interrupt for another device */ | 1680 | return IRQ_NONE; /* must be interrupt for another device */ |
| 1610 | 1681 | ||
| 1611 | snd_azf3328_dbgplay( | 1682 | snd_azf3328_dbgcodec( |
| 1612 | "irq_count %ld! IDX_IO_PLAY_FLAGS %04x, " | 1683 | "irq_count %ld! IDX_IO_IRQSTATUS %04x\n", |
| 1613 | "IDX_IO_PLAY_IRQTYPE %04x, IDX_IO_IRQSTATUS %04x\n", | ||
| 1614 | irq_count++ /* debug-only */, | 1684 | irq_count++ /* debug-only */, |
| 1615 | snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS), | ||
| 1616 | snd_azf3328_codec_inw(chip, IDX_IO_PLAY_IRQTYPE), | ||
| 1617 | status | 1685 | status |
| 1618 | ); | 1686 | ); |
| 1619 | 1687 | ||
| 1620 | if (status & IRQ_TIMER) { | 1688 | if (status & IRQ_TIMER) { |
| 1621 | /* snd_azf3328_dbgplay("timer %ld\n", | 1689 | /* snd_azf3328_dbgcodec("timer %ld\n", |
| 1622 | snd_azf3328_codec_inl(chip, IDX_IO_TIMER_VALUE) | 1690 | snd_azf3328_codec_inl(chip, IDX_IO_TIMER_VALUE) |
| 1623 | & TIMER_VALUE_MASK | 1691 | & TIMER_VALUE_MASK |
| 1624 | ); */ | 1692 | ); */ |
| @@ -1626,71 +1694,36 @@ snd_azf3328_interrupt(int irq, void *dev_id) | |||
| 1626 | snd_timer_interrupt(chip->timer, chip->timer->sticks); | 1694 | snd_timer_interrupt(chip->timer, chip->timer->sticks); |
| 1627 | /* ACK timer */ | 1695 | /* ACK timer */ |
| 1628 | spin_lock(&chip->reg_lock); | 1696 | spin_lock(&chip->reg_lock); |
| 1629 | snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x07); | 1697 | snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x07); |
| 1630 | spin_unlock(&chip->reg_lock); | 1698 | spin_unlock(&chip->reg_lock); |
| 1631 | snd_azf3328_dbgplay("azt3328: timer IRQ\n"); | 1699 | snd_azf3328_dbgcodec("azt3328: timer IRQ\n"); |
| 1632 | } | 1700 | } |
| 1633 | if (status & IRQ_PLAYBACK) { | ||
| 1634 | spin_lock(&chip->reg_lock); | ||
| 1635 | which = snd_azf3328_codec_inb(chip, IDX_IO_PLAY_IRQTYPE); | ||
| 1636 | /* ack all IRQ types immediately */ | ||
| 1637 | snd_azf3328_codec_outb(chip, IDX_IO_PLAY_IRQTYPE, which); | ||
| 1638 | spin_unlock(&chip->reg_lock); | ||
| 1639 | 1701 | ||
| 1640 | if (chip->pcm && chip->audio_stream[AZF_PLAYBACK].substream) { | 1702 | if (status & (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_I2S_OUT)) |
| 1641 | snd_pcm_period_elapsed( | 1703 | snd_azf3328_codec_interrupt(chip, status); |
| 1642 | chip->audio_stream[AZF_PLAYBACK].substream | ||
| 1643 | ); | ||
| 1644 | snd_azf3328_dbgplay("PLAY period done (#%x), @ %x\n", | ||
| 1645 | which, | ||
| 1646 | snd_azf3328_codec_inl( | ||
| 1647 | chip, IDX_IO_PLAY_DMA_CURRPOS | ||
| 1648 | ) | ||
| 1649 | ); | ||
| 1650 | } else | ||
| 1651 | printk(KERN_WARNING "azt3328: irq handler problem!\n"); | ||
| 1652 | if (which & IRQ_PLAY_SOMETHING) | ||
| 1653 | snd_azf3328_irq_log_unknown_type(which); | ||
| 1654 | } | ||
| 1655 | if (status & IRQ_RECORDING) { | ||
| 1656 | spin_lock(&chip->reg_lock); | ||
| 1657 | which = snd_azf3328_codec_inb(chip, IDX_IO_REC_IRQTYPE); | ||
| 1658 | /* ack all IRQ types immediately */ | ||
| 1659 | snd_azf3328_codec_outb(chip, IDX_IO_REC_IRQTYPE, which); | ||
| 1660 | spin_unlock(&chip->reg_lock); | ||
| 1661 | 1704 | ||
| 1662 | if (chip->pcm && chip->audio_stream[AZF_CAPTURE].substream) { | ||
| 1663 | snd_pcm_period_elapsed( | ||
| 1664 | chip->audio_stream[AZF_CAPTURE].substream | ||
| 1665 | ); | ||
| 1666 | snd_azf3328_dbgplay("REC period done (#%x), @ %x\n", | ||
| 1667 | which, | ||
| 1668 | snd_azf3328_codec_inl( | ||
| 1669 | chip, IDX_IO_REC_DMA_CURRPOS | ||
| 1670 | ) | ||
| 1671 | ); | ||
| 1672 | } else | ||
| 1673 | printk(KERN_WARNING "azt3328: irq handler problem!\n"); | ||
| 1674 | if (which & IRQ_REC_SOMETHING) | ||
| 1675 | snd_azf3328_irq_log_unknown_type(which); | ||
| 1676 | } | ||
| 1677 | if (status & IRQ_GAMEPORT) | 1705 | if (status & IRQ_GAMEPORT) |
| 1678 | snd_azf3328_gameport_interrupt(chip); | 1706 | snd_azf3328_gameport_interrupt(chip); |
| 1707 | |||
| 1679 | /* MPU401 has less critical IRQ requirements | 1708 | /* MPU401 has less critical IRQ requirements |
| 1680 | * than timer and playback/recording, right? */ | 1709 | * than timer and playback/recording, right? */ |
| 1681 | if (status & IRQ_MPU401) { | 1710 | if (status & IRQ_MPU401) { |
| 1682 | snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data); | 1711 | snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data); |
| 1683 | 1712 | ||
| 1684 | /* hmm, do we have to ack the IRQ here somehow? | 1713 | /* hmm, do we have to ack the IRQ here somehow? |
| 1685 | * If so, then I don't know how... */ | 1714 | * If so, then I don't know how yet... */ |
| 1686 | snd_azf3328_dbgplay("azt3328: MPU401 IRQ\n"); | 1715 | snd_azf3328_dbgcodec("azt3328: MPU401 IRQ\n"); |
| 1687 | } | 1716 | } |
| 1688 | return IRQ_HANDLED; | 1717 | return IRQ_HANDLED; |
| 1689 | } | 1718 | } |
| 1690 | 1719 | ||
| 1691 | /*****************************************************************/ | 1720 | /*****************************************************************/ |
| 1692 | 1721 | ||
| 1693 | static const struct snd_pcm_hardware snd_azf3328_playback = | 1722 | /* as long as we think we have identical snd_pcm_hardware parameters |
| 1723 | for playback, capture and i2s out, we can use the same physical struct | ||
| 1724 | since the struct is simply being copied into a member. | ||
| 1725 | */ | ||
| 1726 | static const struct snd_pcm_hardware snd_azf3328_hardware = | ||
| 1694 | { | 1727 | { |
| 1695 | /* FIXME!! Correct? */ | 1728 | /* FIXME!! Correct? */ |
| 1696 | .info = SNDRV_PCM_INFO_MMAP | | 1729 | .info = SNDRV_PCM_INFO_MMAP | |
| @@ -1718,31 +1751,6 @@ static const struct snd_pcm_hardware snd_azf3328_playback = | |||
| 1718 | .fifo_size = 0, | 1751 | .fifo_size = 0, |
| 1719 | }; | 1752 | }; |
| 1720 | 1753 | ||
| 1721 | static const struct snd_pcm_hardware snd_azf3328_capture = | ||
| 1722 | { | ||
| 1723 | /* FIXME */ | ||
| 1724 | .info = SNDRV_PCM_INFO_MMAP | | ||
| 1725 | SNDRV_PCM_INFO_INTERLEAVED | | ||
| 1726 | SNDRV_PCM_INFO_MMAP_VALID, | ||
| 1727 | .formats = SNDRV_PCM_FMTBIT_S8 | | ||
| 1728 | SNDRV_PCM_FMTBIT_U8 | | ||
| 1729 | SNDRV_PCM_FMTBIT_S16_LE | | ||
| 1730 | SNDRV_PCM_FMTBIT_U16_LE, | ||
| 1731 | .rates = SNDRV_PCM_RATE_5512 | | ||
| 1732 | SNDRV_PCM_RATE_8000_48000 | | ||
| 1733 | SNDRV_PCM_RATE_KNOT, | ||
| 1734 | .rate_min = AZF_FREQ_4000, | ||
| 1735 | .rate_max = AZF_FREQ_66200, | ||
| 1736 | .channels_min = 1, | ||
| 1737 | .channels_max = 2, | ||
| 1738 | .buffer_bytes_max = 65536, | ||
| 1739 | .period_bytes_min = 64, | ||
| 1740 | .period_bytes_max = 65536, | ||
| 1741 | .periods_min = 1, | ||
| 1742 | .periods_max = 1024, | ||
| 1743 | .fifo_size = 0, | ||
| 1744 | }; | ||
| 1745 | |||
| 1746 | 1754 | ||
| 1747 | static unsigned int snd_azf3328_fixed_rates[] = { | 1755 | static unsigned int snd_azf3328_fixed_rates[] = { |
| 1748 | AZF_FREQ_4000, | 1756 | AZF_FREQ_4000, |
| @@ -1770,14 +1778,19 @@ static struct snd_pcm_hw_constraint_list snd_azf3328_hw_constraints_rates = { | |||
| 1770 | /*****************************************************************/ | 1778 | /*****************************************************************/ |
| 1771 | 1779 | ||
| 1772 | static int | 1780 | static int |
| 1773 | snd_azf3328_playback_open(struct snd_pcm_substream *substream) | 1781 | snd_azf3328_pcm_open(struct snd_pcm_substream *substream, |
| 1782 | enum snd_azf3328_codec_type codec_type | ||
| 1783 | ) | ||
| 1774 | { | 1784 | { |
| 1775 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1785 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); |
| 1776 | struct snd_pcm_runtime *runtime = substream->runtime; | 1786 | struct snd_pcm_runtime *runtime = substream->runtime; |
| 1777 | 1787 | ||
| 1778 | snd_azf3328_dbgcallenter(); | 1788 | snd_azf3328_dbgcallenter(); |
| 1779 | chip->audio_stream[AZF_PLAYBACK].substream = substream; | 1789 | chip->codecs[codec_type].substream = substream; |
| 1780 | runtime->hw = snd_azf3328_playback; | 1790 | |
| 1791 | /* same parameters for all our codecs - at least we think so... */ | ||
| 1792 | runtime->hw = snd_azf3328_hardware; | ||
| 1793 | |||
| 1781 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | 1794 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, |
| 1782 | &snd_azf3328_hw_constraints_rates); | 1795 | &snd_azf3328_hw_constraints_rates); |
| 1783 | snd_azf3328_dbgcallleave(); | 1796 | snd_azf3328_dbgcallleave(); |
| @@ -1785,40 +1798,52 @@ snd_azf3328_playback_open(struct snd_pcm_substream *substream) | |||
| 1785 | } | 1798 | } |
| 1786 | 1799 | ||
| 1787 | static int | 1800 | static int |
| 1801 | snd_azf3328_playback_open(struct snd_pcm_substream *substream) | ||
| 1802 | { | ||
| 1803 | return snd_azf3328_pcm_open(substream, AZF_CODEC_PLAYBACK); | ||
| 1804 | } | ||
| 1805 | |||
| 1806 | static int | ||
| 1788 | snd_azf3328_capture_open(struct snd_pcm_substream *substream) | 1807 | snd_azf3328_capture_open(struct snd_pcm_substream *substream) |
| 1789 | { | 1808 | { |
| 1790 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1809 | return snd_azf3328_pcm_open(substream, AZF_CODEC_CAPTURE); |
| 1791 | struct snd_pcm_runtime *runtime = substream->runtime; | 1810 | } |
| 1792 | 1811 | ||
| 1793 | snd_azf3328_dbgcallenter(); | 1812 | static int |
| 1794 | chip->audio_stream[AZF_CAPTURE].substream = substream; | 1813 | snd_azf3328_i2s_out_open(struct snd_pcm_substream *substream) |
| 1795 | runtime->hw = snd_azf3328_capture; | 1814 | { |
| 1796 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | 1815 | return snd_azf3328_pcm_open(substream, AZF_CODEC_I2S_OUT); |
| 1797 | &snd_azf3328_hw_constraints_rates); | ||
| 1798 | snd_azf3328_dbgcallleave(); | ||
| 1799 | return 0; | ||
| 1800 | } | 1816 | } |
| 1801 | 1817 | ||
| 1802 | static int | 1818 | static int |
| 1803 | snd_azf3328_playback_close(struct snd_pcm_substream *substream) | 1819 | snd_azf3328_pcm_close(struct snd_pcm_substream *substream, |
| 1820 | enum snd_azf3328_codec_type codec_type | ||
| 1821 | ) | ||
| 1804 | { | 1822 | { |
| 1805 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1823 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); |
| 1806 | 1824 | ||
| 1807 | snd_azf3328_dbgcallenter(); | 1825 | snd_azf3328_dbgcallenter(); |
| 1808 | chip->audio_stream[AZF_PLAYBACK].substream = NULL; | 1826 | chip->codecs[codec_type].substream = NULL; |
| 1809 | snd_azf3328_dbgcallleave(); | 1827 | snd_azf3328_dbgcallleave(); |
| 1810 | return 0; | 1828 | return 0; |
| 1811 | } | 1829 | } |
| 1812 | 1830 | ||
| 1813 | static int | 1831 | static int |
| 1832 | snd_azf3328_playback_close(struct snd_pcm_substream *substream) | ||
| 1833 | { | ||
| 1834 | return snd_azf3328_pcm_close(substream, AZF_CODEC_PLAYBACK); | ||
| 1835 | } | ||
| 1836 | |||
| 1837 | static int | ||
| 1814 | snd_azf3328_capture_close(struct snd_pcm_substream *substream) | 1838 | snd_azf3328_capture_close(struct snd_pcm_substream *substream) |
| 1815 | { | 1839 | { |
| 1816 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1840 | return snd_azf3328_pcm_close(substream, AZF_CODEC_CAPTURE); |
| 1841 | } | ||
| 1817 | 1842 | ||
| 1818 | snd_azf3328_dbgcallenter(); | 1843 | static int |
| 1819 | chip->audio_stream[AZF_CAPTURE].substream = NULL; | 1844 | snd_azf3328_i2s_out_close(struct snd_pcm_substream *substream) |
| 1820 | snd_azf3328_dbgcallleave(); | 1845 | { |
| 1821 | return 0; | 1846 | return snd_azf3328_pcm_close(substream, AZF_CODEC_I2S_OUT); |
| 1822 | } | 1847 | } |
| 1823 | 1848 | ||
| 1824 | /******************************************************************/ | 1849 | /******************************************************************/ |
| @@ -1829,9 +1854,9 @@ static struct snd_pcm_ops snd_azf3328_playback_ops = { | |||
| 1829 | .ioctl = snd_pcm_lib_ioctl, | 1854 | .ioctl = snd_pcm_lib_ioctl, |
| 1830 | .hw_params = snd_azf3328_hw_params, | 1855 | .hw_params = snd_azf3328_hw_params, |
| 1831 | .hw_free = snd_azf3328_hw_free, | 1856 | .hw_free = snd_azf3328_hw_free, |
| 1832 | .prepare = snd_azf3328_playback_prepare, | 1857 | .prepare = snd_azf3328_codec_prepare, |
| 1833 | .trigger = snd_azf3328_playback_trigger, | 1858 | .trigger = snd_azf3328_codec_playback_trigger, |
| 1834 | .pointer = snd_azf3328_playback_pointer | 1859 | .pointer = snd_azf3328_codec_playback_pointer |
| 1835 | }; | 1860 | }; |
| 1836 | 1861 | ||
| 1837 | static struct snd_pcm_ops snd_azf3328_capture_ops = { | 1862 | static struct snd_pcm_ops snd_azf3328_capture_ops = { |
| @@ -1840,30 +1865,67 @@ static struct snd_pcm_ops snd_azf3328_capture_ops = { | |||
| 1840 | .ioctl = snd_pcm_lib_ioctl, | 1865 | .ioctl = snd_pcm_lib_ioctl, |
| 1841 | .hw_params = snd_azf3328_hw_params, | 1866 | .hw_params = snd_azf3328_hw_params, |
| 1842 | .hw_free = snd_azf3328_hw_free, | 1867 | .hw_free = snd_azf3328_hw_free, |
| 1843 | .prepare = snd_azf3328_capture_prepare, | 1868 | .prepare = snd_azf3328_codec_prepare, |
| 1844 | .trigger = snd_azf3328_capture_trigger, | 1869 | .trigger = snd_azf3328_codec_capture_trigger, |
| 1845 | .pointer = snd_azf3328_capture_pointer | 1870 | .pointer = snd_azf3328_codec_capture_pointer |
| 1871 | }; | ||
| 1872 | |||
| 1873 | static struct snd_pcm_ops snd_azf3328_i2s_out_ops = { | ||
| 1874 | .open = snd_azf3328_i2s_out_open, | ||
| 1875 | .close = snd_azf3328_i2s_out_close, | ||
| 1876 | .ioctl = snd_pcm_lib_ioctl, | ||
| 1877 | .hw_params = snd_azf3328_hw_params, | ||
| 1878 | .hw_free = snd_azf3328_hw_free, | ||
| 1879 | .prepare = snd_azf3328_codec_prepare, | ||
| 1880 | .trigger = snd_azf3328_codec_i2s_out_trigger, | ||
| 1881 | .pointer = snd_azf3328_codec_i2s_out_pointer | ||
| 1846 | }; | 1882 | }; |
| 1847 | 1883 | ||
| 1848 | static int __devinit | 1884 | static int __devinit |
| 1849 | snd_azf3328_pcm(struct snd_azf3328 *chip, int device) | 1885 | snd_azf3328_pcm(struct snd_azf3328 *chip) |
| 1850 | { | 1886 | { |
| 1887 | enum { AZF_PCMDEV_STD, AZF_PCMDEV_I2S_OUT, NUM_AZF_PCMDEVS }; /* pcm devices */ | ||
| 1888 | |||
| 1851 | struct snd_pcm *pcm; | 1889 | struct snd_pcm *pcm; |
| 1852 | int err; | 1890 | int err; |
| 1853 | 1891 | ||
| 1854 | snd_azf3328_dbgcallenter(); | 1892 | snd_azf3328_dbgcallenter(); |
| 1855 | if ((err = snd_pcm_new(chip->card, "AZF3328 DSP", device, 1, 1, &pcm)) < 0) | 1893 | |
| 1894 | err = snd_pcm_new(chip->card, "AZF3328 DSP", AZF_PCMDEV_STD, | ||
| 1895 | 1, 1, &pcm); | ||
| 1896 | if (err < 0) | ||
| 1856 | return err; | 1897 | return err; |
| 1857 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_azf3328_playback_ops); | 1898 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, |
| 1858 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_azf3328_capture_ops); | 1899 | &snd_azf3328_playback_ops); |
| 1900 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, | ||
| 1901 | &snd_azf3328_capture_ops); | ||
| 1859 | 1902 | ||
| 1860 | pcm->private_data = chip; | 1903 | pcm->private_data = chip; |
| 1861 | pcm->info_flags = 0; | 1904 | pcm->info_flags = 0; |
| 1862 | strcpy(pcm->name, chip->card->shortname); | 1905 | strcpy(pcm->name, chip->card->shortname); |
| 1863 | chip->pcm = pcm; | 1906 | /* same pcm object for playback/capture (see snd_pcm_new() above) */ |
| 1907 | chip->pcm[AZF_CODEC_PLAYBACK] = pcm; | ||
| 1908 | chip->pcm[AZF_CODEC_CAPTURE] = pcm; | ||
| 1864 | 1909 | ||
| 1865 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | 1910 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, |
| 1866 | snd_dma_pci_data(chip->pci), 64*1024, 64*1024); | 1911 | snd_dma_pci_data(chip->pci), |
| 1912 | 64*1024, 64*1024); | ||
| 1913 | |||
| 1914 | err = snd_pcm_new(chip->card, "AZF3328 I2S OUT", AZF_PCMDEV_I2S_OUT, | ||
| 1915 | 1, 0, &pcm); | ||
| 1916 | if (err < 0) | ||
| 1917 | return err; | ||
| 1918 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, | ||
| 1919 | &snd_azf3328_i2s_out_ops); | ||
| 1920 | |||
| 1921 | pcm->private_data = chip; | ||
| 1922 | pcm->info_flags = 0; | ||
| 1923 | strcpy(pcm->name, chip->card->shortname); | ||
| 1924 | chip->pcm[AZF_CODEC_I2S_OUT] = pcm; | ||
| 1925 | |||
| 1926 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | ||
| 1927 | snd_dma_pci_data(chip->pci), | ||
| 1928 | 64*1024, 64*1024); | ||
| 1867 | 1929 | ||
| 1868 | snd_azf3328_dbgcallleave(); | 1930 | snd_azf3328_dbgcallleave(); |
| 1869 | return 0; | 1931 | return 0; |
| @@ -1902,7 +1964,7 @@ snd_azf3328_timer_start(struct snd_timer *timer) | |||
| 1902 | snd_azf3328_dbgtimer("setting timer countdown value %d, add COUNTDOWN|IRQ\n", delay); | 1964 | snd_azf3328_dbgtimer("setting timer countdown value %d, add COUNTDOWN|IRQ\n", delay); |
| 1903 | delay |= TIMER_COUNTDOWN_ENABLE | TIMER_IRQ_ENABLE; | 1965 | delay |= TIMER_COUNTDOWN_ENABLE | TIMER_IRQ_ENABLE; |
| 1904 | spin_lock_irqsave(&chip->reg_lock, flags); | 1966 | spin_lock_irqsave(&chip->reg_lock, flags); |
| 1905 | snd_azf3328_codec_outl(chip, IDX_IO_TIMER_VALUE, delay); | 1967 | snd_azf3328_ctrl_outl(chip, IDX_IO_TIMER_VALUE, delay); |
| 1906 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 1968 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
| 1907 | snd_azf3328_dbgcallleave(); | 1969 | snd_azf3328_dbgcallleave(); |
| 1908 | return 0; | 1970 | return 0; |
| @@ -1919,7 +1981,7 @@ snd_azf3328_timer_stop(struct snd_timer *timer) | |||
| 1919 | spin_lock_irqsave(&chip->reg_lock, flags); | 1981 | spin_lock_irqsave(&chip->reg_lock, flags); |
| 1920 | /* disable timer countdown and interrupt */ | 1982 | /* disable timer countdown and interrupt */ |
| 1921 | /* FIXME: should we write TIMER_IRQ_ACK here? */ | 1983 | /* FIXME: should we write TIMER_IRQ_ACK here? */ |
| 1922 | snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0); | 1984 | snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0); |
| 1923 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 1985 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
| 1924 | snd_azf3328_dbgcallleave(); | 1986 | snd_azf3328_dbgcallleave(); |
| 1925 | return 0; | 1987 | return 0; |
| @@ -2035,7 +2097,7 @@ snd_azf3328_test_bit(unsigned unsigned reg, int bit) | |||
| 2035 | 2097 | ||
| 2036 | outb(val, reg); | 2098 | outb(val, reg); |
| 2037 | 2099 | ||
| 2038 | printk(KERN_ERR "reg %04x bit %d: %02x %02x %02x\n", | 2100 | printk(KERN_DEBUG "reg %04x bit %d: %02x %02x %02x\n", |
| 2039 | reg, bit, val, valoff, valon | 2101 | reg, bit, val, valoff, valon |
| 2040 | ); | 2102 | ); |
| 2041 | } | 2103 | } |
| @@ -2048,9 +2110,9 @@ snd_azf3328_debug_show_ports(const struct snd_azf3328 *chip) | |||
| 2048 | u16 tmp; | 2110 | u16 tmp; |
| 2049 | 2111 | ||
| 2050 | snd_azf3328_dbgmisc( | 2112 | snd_azf3328_dbgmisc( |
| 2051 | "codec_io 0x%lx, game_io 0x%lx, mpu_io 0x%lx, " | 2113 | "ctrl_io 0x%lx, game_io 0x%lx, mpu_io 0x%lx, " |
| 2052 | "opl3_io 0x%lx, mixer_io 0x%lx, irq %d\n", | 2114 | "opl3_io 0x%lx, mixer_io 0x%lx, irq %d\n", |
| 2053 | chip->codec_io, chip->game_io, chip->mpu_io, | 2115 | chip->ctrl_io, chip->game_io, chip->mpu_io, |
| 2054 | chip->opl3_io, chip->mixer_io, chip->irq | 2116 | chip->opl3_io, chip->mixer_io, chip->irq |
| 2055 | ); | 2117 | ); |
| 2056 | 2118 | ||
| @@ -2083,9 +2145,9 @@ snd_azf3328_debug_show_ports(const struct snd_azf3328 *chip) | |||
| 2083 | inb(0x38c + tmp) | 2145 | inb(0x38c + tmp) |
| 2084 | ); | 2146 | ); |
| 2085 | 2147 | ||
| 2086 | for (tmp = 0; tmp < AZF_IO_SIZE_CODEC; tmp += 2) | 2148 | for (tmp = 0; tmp < AZF_IO_SIZE_CTRL; tmp += 2) |
| 2087 | snd_azf3328_dbgmisc("codec 0x%02x: 0x%04x\n", | 2149 | snd_azf3328_dbgmisc("ctrl 0x%02x: 0x%04x\n", |
| 2088 | tmp, snd_azf3328_codec_inw(chip, tmp) | 2150 | tmp, snd_azf3328_ctrl_inw(chip, tmp) |
| 2089 | ); | 2151 | ); |
| 2090 | 2152 | ||
| 2091 | for (tmp = 0; tmp < AZF_IO_SIZE_MIXER; tmp += 2) | 2153 | for (tmp = 0; tmp < AZF_IO_SIZE_MIXER; tmp += 2) |
| @@ -2106,7 +2168,8 @@ snd_azf3328_create(struct snd_card *card, | |||
| 2106 | static struct snd_device_ops ops = { | 2168 | static struct snd_device_ops ops = { |
| 2107 | .dev_free = snd_azf3328_dev_free, | 2169 | .dev_free = snd_azf3328_dev_free, |
| 2108 | }; | 2170 | }; |
| 2109 | u16 tmp; | 2171 | u8 dma_init; |
| 2172 | enum snd_azf3328_codec_type codec_type; | ||
| 2110 | 2173 | ||
| 2111 | *rchip = NULL; | 2174 | *rchip = NULL; |
| 2112 | 2175 | ||
| @@ -2138,14 +2201,21 @@ snd_azf3328_create(struct snd_card *card, | |||
| 2138 | if (err < 0) | 2201 | if (err < 0) |
| 2139 | goto out_err; | 2202 | goto out_err; |
| 2140 | 2203 | ||
| 2141 | chip->codec_io = pci_resource_start(pci, 0); | 2204 | chip->ctrl_io = pci_resource_start(pci, 0); |
| 2142 | chip->game_io = pci_resource_start(pci, 1); | 2205 | chip->game_io = pci_resource_start(pci, 1); |
| 2143 | chip->mpu_io = pci_resource_start(pci, 2); | 2206 | chip->mpu_io = pci_resource_start(pci, 2); |
| 2144 | chip->opl3_io = pci_resource_start(pci, 3); | 2207 | chip->opl3_io = pci_resource_start(pci, 3); |
| 2145 | chip->mixer_io = pci_resource_start(pci, 4); | 2208 | chip->mixer_io = pci_resource_start(pci, 4); |
| 2146 | 2209 | ||
| 2147 | chip->audio_stream[AZF_PLAYBACK].portbase = chip->codec_io + 0x00; | 2210 | chip->codecs[AZF_CODEC_PLAYBACK].io_base = |
| 2148 | chip->audio_stream[AZF_CAPTURE].portbase = chip->codec_io + 0x20; | 2211 | chip->ctrl_io + AZF_IO_OFFS_CODEC_PLAYBACK; |
| 2212 | chip->codecs[AZF_CODEC_PLAYBACK].name = "PLAYBACK"; | ||
| 2213 | chip->codecs[AZF_CODEC_CAPTURE].io_base = | ||
| 2214 | chip->ctrl_io + AZF_IO_OFFS_CODEC_CAPTURE; | ||
| 2215 | chip->codecs[AZF_CODEC_CAPTURE].name = "CAPTURE"; | ||
| 2216 | chip->codecs[AZF_CODEC_I2S_OUT].io_base = | ||
| 2217 | chip->ctrl_io + AZF_IO_OFFS_CODEC_I2S_OUT; | ||
| 2218 | chip->codecs[AZF_CODEC_I2S_OUT].name = "I2S_OUT"; | ||
| 2149 | 2219 | ||
| 2150 | if (request_irq(pci->irq, snd_azf3328_interrupt, | 2220 | if (request_irq(pci->irq, snd_azf3328_interrupt, |
| 2151 | IRQF_SHARED, card->shortname, chip)) { | 2221 | IRQF_SHARED, card->shortname, chip)) { |
| @@ -2168,20 +2238,25 @@ snd_azf3328_create(struct snd_card *card, | |||
| 2168 | if (err < 0) | 2238 | if (err < 0) |
| 2169 | goto out_err; | 2239 | goto out_err; |
| 2170 | 2240 | ||
| 2171 | /* shutdown codecs to save power */ | 2241 | /* standard codec init stuff */ |
| 2172 | /* have snd_azf3328_codec_activity() act properly */ | 2242 | /* default DMA init value */ |
| 2173 | chip->audio_stream[AZF_PLAYBACK].running = 1; | 2243 | dma_init = DMA_RUN_SOMETHING2|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE; |
| 2174 | snd_azf3328_codec_activity(chip, AZF_PLAYBACK, 0); | ||
| 2175 | 2244 | ||
| 2176 | /* standard chip init stuff */ | 2245 | for (codec_type = AZF_CODEC_PLAYBACK; |
| 2177 | /* default IRQ init value */ | 2246 | codec_type <= AZF_CODEC_I2S_OUT; ++codec_type) { |
| 2178 | tmp = DMA_PLAY_SOMETHING2|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE; | 2247 | struct snd_azf3328_codec_data *codec = |
| 2248 | &chip->codecs[codec_type]; | ||
| 2179 | 2249 | ||
| 2180 | spin_lock_irq(&chip->reg_lock); | 2250 | /* shutdown codecs to save power */ |
| 2181 | snd_azf3328_codec_outb(chip, IDX_IO_PLAY_FLAGS, tmp); | 2251 | /* have ...ctrl_codec_activity() act properly */ |
| 2182 | snd_azf3328_codec_outb(chip, IDX_IO_REC_FLAGS, tmp); | 2252 | codec->running = 1; |
| 2183 | snd_azf3328_codec_outb(chip, IDX_IO_SOMETHING_FLAGS, tmp); | 2253 | snd_azf3328_ctrl_codec_activity(chip, codec_type, 0); |
| 2184 | spin_unlock_irq(&chip->reg_lock); | 2254 | |
| 2255 | spin_lock_irq(&chip->reg_lock); | ||
| 2256 | snd_azf3328_codec_outb(codec, IDX_IO_CODEC_DMA_FLAGS, | ||
| 2257 | dma_init); | ||
| 2258 | spin_unlock_irq(&chip->reg_lock); | ||
| 2259 | } | ||
| 2185 | 2260 | ||
| 2186 | snd_card_set_dev(card, &pci->dev); | 2261 | snd_card_set_dev(card, &pci->dev); |
| 2187 | 2262 | ||
| @@ -2229,8 +2304,11 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) | |||
| 2229 | 2304 | ||
| 2230 | card->private_data = chip; | 2305 | card->private_data = chip; |
| 2231 | 2306 | ||
| 2307 | /* chose to use MPU401_HW_AZT2320 ID instead of MPU401_HW_MPU401, | ||
| 2308 | since our hardware ought to be similar, thus use same ID. */ | ||
| 2232 | err = snd_mpu401_uart_new( | 2309 | err = snd_mpu401_uart_new( |
| 2233 | card, 0, MPU401_HW_MPU401, chip->mpu_io, MPU401_INFO_INTEGRATED, | 2310 | card, 0, |
| 2311 | MPU401_HW_AZT2320, chip->mpu_io, MPU401_INFO_INTEGRATED, | ||
| 2234 | pci->irq, 0, &chip->rmidi | 2312 | pci->irq, 0, &chip->rmidi |
| 2235 | ); | 2313 | ); |
| 2236 | if (err < 0) { | 2314 | if (err < 0) { |
| @@ -2244,7 +2322,7 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) | |||
| 2244 | if (err < 0) | 2322 | if (err < 0) |
| 2245 | goto out_err; | 2323 | goto out_err; |
| 2246 | 2324 | ||
| 2247 | err = snd_azf3328_pcm(chip, 0); | 2325 | err = snd_azf3328_pcm(chip); |
| 2248 | if (err < 0) | 2326 | if (err < 0) |
| 2249 | goto out_err; | 2327 | goto out_err; |
| 2250 | 2328 | ||
| @@ -2266,14 +2344,14 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) | |||
| 2266 | opl3->private_data = chip; | 2344 | opl3->private_data = chip; |
| 2267 | 2345 | ||
| 2268 | sprintf(card->longname, "%s at 0x%lx, irq %i", | 2346 | sprintf(card->longname, "%s at 0x%lx, irq %i", |
| 2269 | card->shortname, chip->codec_io, chip->irq); | 2347 | card->shortname, chip->ctrl_io, chip->irq); |
| 2270 | 2348 | ||
| 2271 | err = snd_card_register(card); | 2349 | err = snd_card_register(card); |
| 2272 | if (err < 0) | 2350 | if (err < 0) |
| 2273 | goto out_err; | 2351 | goto out_err; |
| 2274 | 2352 | ||
| 2275 | #ifdef MODULE | 2353 | #ifdef MODULE |
| 2276 | printk( | 2354 | printk(KERN_INFO |
| 2277 | "azt3328: Sound driver for Aztech AZF3328-based soundcards such as PCI168.\n" | 2355 | "azt3328: Sound driver for Aztech AZF3328-based soundcards such as PCI168.\n" |
| 2278 | "azt3328: Hardware was completely undocumented, unfortunately.\n" | 2356 | "azt3328: Hardware was completely undocumented, unfortunately.\n" |
| 2279 | "azt3328: Feel free to contact andi AT lisas.de for bug reports etc.!\n" | 2357 | "azt3328: Feel free to contact andi AT lisas.de for bug reports etc.!\n" |
| @@ -2308,36 +2386,52 @@ snd_azf3328_remove(struct pci_dev *pci) | |||
| 2308 | } | 2386 | } |
| 2309 | 2387 | ||
| 2310 | #ifdef CONFIG_PM | 2388 | #ifdef CONFIG_PM |
| 2389 | static inline void | ||
| 2390 | snd_azf3328_suspend_regs(unsigned long io_addr, unsigned count, u32 *saved_regs) | ||
| 2391 | { | ||
| 2392 | unsigned reg; | ||
| 2393 | |||
| 2394 | for (reg = 0; reg < count; ++reg) { | ||
| 2395 | *saved_regs = inl(io_addr); | ||
| 2396 | snd_azf3328_dbgpm("suspend: io 0x%04lx: 0x%08x\n", | ||
| 2397 | io_addr, *saved_regs); | ||
| 2398 | ++saved_regs; | ||
| 2399 | io_addr += sizeof(*saved_regs); | ||
| 2400 | } | ||
| 2401 | } | ||
| 2402 | |||
| 2311 | static int | 2403 | static int |
| 2312 | snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state) | 2404 | snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state) |
| 2313 | { | 2405 | { |
| 2314 | struct snd_card *card = pci_get_drvdata(pci); | 2406 | struct snd_card *card = pci_get_drvdata(pci); |
| 2315 | struct snd_azf3328 *chip = card->private_data; | 2407 | struct snd_azf3328 *chip = card->private_data; |
| 2316 | unsigned reg; | 2408 | u16 *saved_regs_ctrl_u16; |
| 2317 | 2409 | ||
| 2318 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | 2410 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); |
| 2319 | 2411 | ||
| 2320 | snd_pcm_suspend_all(chip->pcm); | 2412 | snd_pcm_suspend_all(chip->pcm[AZF_CODEC_PLAYBACK]); |
| 2413 | snd_pcm_suspend_all(chip->pcm[AZF_CODEC_I2S_OUT]); | ||
| 2321 | 2414 | ||
| 2322 | for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; ++reg) | 2415 | snd_azf3328_suspend_regs(chip->mixer_io, |
| 2323 | chip->saved_regs_mixer[reg] = inw(chip->mixer_io + reg * 2); | 2416 | ARRAY_SIZE(chip->saved_regs_mixer), chip->saved_regs_mixer); |
| 2324 | 2417 | ||
| 2325 | /* make sure to disable master volume etc. to prevent looping sound */ | 2418 | /* make sure to disable master volume etc. to prevent looping sound */ |
| 2326 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); | 2419 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); |
| 2327 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); | 2420 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); |
| 2328 | 2421 | ||
| 2329 | for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; ++reg) | 2422 | snd_azf3328_suspend_regs(chip->ctrl_io, |
| 2330 | chip->saved_regs_codec[reg] = inw(chip->codec_io + reg * 2); | 2423 | ARRAY_SIZE(chip->saved_regs_ctrl), chip->saved_regs_ctrl); |
| 2331 | 2424 | ||
| 2332 | /* manually store the one currently relevant write-only reg, too */ | 2425 | /* manually store the one currently relevant write-only reg, too */ |
| 2333 | chip->saved_regs_codec[IDX_IO_6AH / 2] = chip->shadow_reg_codec_6AH; | 2426 | saved_regs_ctrl_u16 = (u16 *)chip->saved_regs_ctrl; |
| 2427 | saved_regs_ctrl_u16[IDX_IO_6AH / 2] = chip->shadow_reg_ctrl_6AH; | ||
| 2334 | 2428 | ||
| 2335 | for (reg = 0; reg < AZF_IO_SIZE_GAME_PM / 2; ++reg) | 2429 | snd_azf3328_suspend_regs(chip->game_io, |
| 2336 | chip->saved_regs_game[reg] = inw(chip->game_io + reg * 2); | 2430 | ARRAY_SIZE(chip->saved_regs_game), chip->saved_regs_game); |
| 2337 | for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; ++reg) | 2431 | snd_azf3328_suspend_regs(chip->mpu_io, |
| 2338 | chip->saved_regs_mpu[reg] = inw(chip->mpu_io + reg * 2); | 2432 | ARRAY_SIZE(chip->saved_regs_mpu), chip->saved_regs_mpu); |
| 2339 | for (reg = 0; reg < AZF_IO_SIZE_OPL3_PM / 2; ++reg) | 2433 | snd_azf3328_suspend_regs(chip->opl3_io, |
| 2340 | chip->saved_regs_opl3[reg] = inw(chip->opl3_io + reg * 2); | 2434 | ARRAY_SIZE(chip->saved_regs_opl3), chip->saved_regs_opl3); |
| 2341 | 2435 | ||
| 2342 | pci_disable_device(pci); | 2436 | pci_disable_device(pci); |
| 2343 | pci_save_state(pci); | 2437 | pci_save_state(pci); |
| @@ -2345,12 +2439,28 @@ snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state) | |||
| 2345 | return 0; | 2439 | return 0; |
| 2346 | } | 2440 | } |
| 2347 | 2441 | ||
| 2442 | static inline void | ||
| 2443 | snd_azf3328_resume_regs(const u32 *saved_regs, | ||
| 2444 | unsigned long io_addr, | ||
| 2445 | unsigned count | ||
| 2446 | ) | ||
| 2447 | { | ||
| 2448 | unsigned reg; | ||
| 2449 | |||
| 2450 | for (reg = 0; reg < count; ++reg) { | ||
| 2451 | outl(*saved_regs, io_addr); | ||
| 2452 | snd_azf3328_dbgpm("resume: io 0x%04lx: 0x%08x --> 0x%08x\n", | ||
| 2453 | io_addr, *saved_regs, inl(io_addr)); | ||
| 2454 | ++saved_regs; | ||
| 2455 | io_addr += sizeof(*saved_regs); | ||
| 2456 | } | ||
| 2457 | } | ||
| 2458 | |||
| 2348 | static int | 2459 | static int |
| 2349 | snd_azf3328_resume(struct pci_dev *pci) | 2460 | snd_azf3328_resume(struct pci_dev *pci) |
| 2350 | { | 2461 | { |
| 2351 | struct snd_card *card = pci_get_drvdata(pci); | 2462 | struct snd_card *card = pci_get_drvdata(pci); |
| 2352 | struct snd_azf3328 *chip = card->private_data; | 2463 | const struct snd_azf3328 *chip = card->private_data; |
| 2353 | unsigned reg; | ||
| 2354 | 2464 | ||
| 2355 | pci_set_power_state(pci, PCI_D0); | 2465 | pci_set_power_state(pci, PCI_D0); |
| 2356 | pci_restore_state(pci); | 2466 | pci_restore_state(pci); |
| @@ -2362,16 +2472,24 @@ snd_azf3328_resume(struct pci_dev *pci) | |||
| 2362 | } | 2472 | } |
| 2363 | pci_set_master(pci); | 2473 | pci_set_master(pci); |
| 2364 | 2474 | ||
| 2365 | for (reg = 0; reg < AZF_IO_SIZE_GAME_PM / 2; ++reg) | 2475 | snd_azf3328_resume_regs(chip->saved_regs_game, chip->game_io, |
| 2366 | outw(chip->saved_regs_game[reg], chip->game_io + reg * 2); | 2476 | ARRAY_SIZE(chip->saved_regs_game)); |
| 2367 | for (reg = 0; reg < AZF_IO_SIZE_MPU_PM / 2; ++reg) | 2477 | snd_azf3328_resume_regs(chip->saved_regs_mpu, chip->mpu_io, |
| 2368 | outw(chip->saved_regs_mpu[reg], chip->mpu_io + reg * 2); | 2478 | ARRAY_SIZE(chip->saved_regs_mpu)); |
| 2369 | for (reg = 0; reg < AZF_IO_SIZE_OPL3_PM / 2; ++reg) | 2479 | snd_azf3328_resume_regs(chip->saved_regs_opl3, chip->opl3_io, |
| 2370 | outw(chip->saved_regs_opl3[reg], chip->opl3_io + reg * 2); | 2480 | ARRAY_SIZE(chip->saved_regs_opl3)); |
| 2371 | for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; ++reg) | 2481 | |
| 2372 | outw(chip->saved_regs_mixer[reg], chip->mixer_io + reg * 2); | 2482 | snd_azf3328_resume_regs(chip->saved_regs_mixer, chip->mixer_io, |
| 2373 | for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; ++reg) | 2483 | ARRAY_SIZE(chip->saved_regs_mixer)); |
| 2374 | outw(chip->saved_regs_codec[reg], chip->codec_io + reg * 2); | 2484 | |
| 2485 | /* unfortunately with 32bit transfers, IDX_MIXER_PLAY_MASTER (0x02) | ||
| 2486 | and IDX_MIXER_RESET (offset 0x00) get touched at the same time, | ||
| 2487 | resulting in a mixer reset condition persisting until _after_ | ||
| 2488 | master vol was restored. Thus master vol needs an extra restore. */ | ||
| 2489 | outw(((u16 *)chip->saved_regs_mixer)[1], chip->mixer_io + 2); | ||
| 2490 | |||
| 2491 | snd_azf3328_resume_regs(chip->saved_regs_ctrl, chip->ctrl_io, | ||
| 2492 | ARRAY_SIZE(chip->saved_regs_ctrl)); | ||
| 2375 | 2493 | ||
| 2376 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | 2494 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); |
| 2377 | return 0; | 2495 | return 0; |
