diff options
Diffstat (limited to 'sound/pci/azt3328.c')
-rw-r--r-- | sound/pci/azt3328.c | 978 |
1 files changed, 524 insertions, 454 deletions
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index f290bc56178f..39dfdaa6a56f 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 Linux support for this card) | ||
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,6 +199,26 @@ 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 |
@@ -250,22 +284,23 @@ static int seqtimer_scaling = 128; | |||
250 | module_param(seqtimer_scaling, int, 0444); | 284 | module_param(seqtimer_scaling, int, 0444); |
251 | MODULE_PARM_DESC(seqtimer_scaling, "Set 1024000Hz sequencer timer scale factor (lockup danger!). Default 128."); | 285 | MODULE_PARM_DESC(seqtimer_scaling, "Set 1024000Hz sequencer timer scale factor (lockup danger!). Default 128."); |
252 | 286 | ||
253 | struct snd_azf3328_audio_stream { | 287 | struct snd_azf3328_codec_data { |
288 | unsigned long io_base; | ||
254 | struct snd_pcm_substream *substream; | 289 | struct snd_pcm_substream *substream; |
255 | int enabled; | 290 | bool running; |
256 | int running; | 291 | const char *name; |
257 | unsigned long portbase; | ||
258 | }; | 292 | }; |
259 | 293 | ||
260 | enum snd_azf3328_stream_index { | 294 | enum snd_azf3328_codec_type { |
261 | AZF_PLAYBACK = 0, | 295 | AZF_CODEC_PLAYBACK = 0, |
262 | AZF_CAPTURE = 1, | 296 | AZF_CODEC_CAPTURE = 1, |
297 | AZF_CODEC_I2S_OUT = 2, | ||
263 | }; | 298 | }; |
264 | 299 | ||
265 | struct snd_azf3328 { | 300 | struct snd_azf3328 { |
266 | /* often-used fields towards beginning, then grouped */ | 301 | /* often-used fields towards beginning, then grouped */ |
267 | 302 | ||
268 | unsigned long codec_io; /* usually 0xb000, size 128 */ | 303 | unsigned long ctrl_io; /* usually 0xb000, size 128 */ |
269 | unsigned long game_io; /* usually 0xb400, size 8 */ | 304 | unsigned long game_io; /* usually 0xb400, size 8 */ |
270 | unsigned long mpu_io; /* usually 0xb800, size 4 */ | 305 | unsigned long mpu_io; /* usually 0xb800, size 4 */ |
271 | unsigned long opl3_io; /* usually 0xbc00, size 8 */ | 306 | unsigned long opl3_io; /* usually 0xbc00, size 8 */ |
@@ -275,15 +310,17 @@ struct snd_azf3328 { | |||
275 | 310 | ||
276 | struct snd_timer *timer; | 311 | struct snd_timer *timer; |
277 | 312 | ||
278 | struct snd_pcm *pcm; | 313 | struct snd_pcm *pcm[3]; |
279 | struct snd_azf3328_audio_stream audio_stream[2]; | 314 | |
315 | /* playback, recording and I2S out codecs */ | ||
316 | struct snd_azf3328_codec_data codecs[3]; | ||
280 | 317 | ||
281 | struct snd_card *card; | 318 | struct snd_card *card; |
282 | struct snd_rawmidi *rmidi; | 319 | struct snd_rawmidi *rmidi; |
283 | 320 | ||
284 | #ifdef SUPPORT_GAMEPORT | 321 | #ifdef SUPPORT_GAMEPORT |
285 | struct gameport *gameport; | 322 | struct gameport *gameport; |
286 | int axes[4]; | 323 | u16 axes[4]; |
287 | #endif | 324 | #endif |
288 | 325 | ||
289 | struct pci_dev *pci; | 326 | struct pci_dev *pci; |
@@ -293,12 +330,12 @@ struct snd_azf3328 { | |||
293 | * If we need to add more registers here, then we might try to fold this | 330 | * If we need to add more registers here, then we might try to fold this |
294 | * into some transparent combined shadow register handling with | 331 | * into some transparent combined shadow register handling with |
295 | * CONFIG_PM register storage below, but that's slightly difficult. */ | 332 | * CONFIG_PM register storage below, but that's slightly difficult. */ |
296 | u16 shadow_reg_codec_6AH; | 333 | u16 shadow_reg_ctrl_6AH; |
297 | 334 | ||
298 | #ifdef CONFIG_PM | 335 | #ifdef CONFIG_PM |
299 | /* register value containers for power management | 336 | /* register value containers for power management |
300 | * Note: not always full I/O range preserved (just like Win driver!) */ | 337 | * Note: not always full I/O range preserved (just like Win driver!) */ |
301 | u16 saved_regs_codec[AZF_IO_SIZE_CODEC_PM / 2]; | 338 | u16 saved_regs_ctrl[AZF_IO_SIZE_CTRL_PM / 2]; |
302 | u16 saved_regs_game [AZF_IO_SIZE_GAME_PM / 2]; | 339 | u16 saved_regs_game [AZF_IO_SIZE_GAME_PM / 2]; |
303 | u16 saved_regs_mpu [AZF_IO_SIZE_MPU_PM / 2]; | 340 | u16 saved_regs_mpu [AZF_IO_SIZE_MPU_PM / 2]; |
304 | u16 saved_regs_opl3 [AZF_IO_SIZE_OPL3_PM / 2]; | 341 | u16 saved_regs_opl3 [AZF_IO_SIZE_OPL3_PM / 2]; |
@@ -316,7 +353,7 @@ MODULE_DEVICE_TABLE(pci, snd_azf3328_ids); | |||
316 | 353 | ||
317 | 354 | ||
318 | static int | 355 | static int |
319 | snd_azf3328_io_reg_setb(unsigned reg, u8 mask, int do_set) | 356 | snd_azf3328_io_reg_setb(unsigned reg, u8 mask, bool do_set) |
320 | { | 357 | { |
321 | u8 prev = inb(reg), new; | 358 | u8 prev = inb(reg), new; |
322 | 359 | ||
@@ -331,39 +368,72 @@ snd_azf3328_io_reg_setb(unsigned reg, u8 mask, int do_set) | |||
331 | } | 368 | } |
332 | 369 | ||
333 | static inline void | 370 | static inline void |
334 | snd_azf3328_codec_outb(const struct snd_azf3328 *chip, unsigned reg, u8 value) | 371 | snd_azf3328_codec_outb(const struct snd_azf3328_codec_data *codec, |
372 | unsigned reg, | ||
373 | u8 value | ||
374 | ) | ||
335 | { | 375 | { |
336 | outb(value, chip->codec_io + reg); | 376 | outb(value, codec->io_base + reg); |
337 | } | 377 | } |
338 | 378 | ||
339 | static inline u8 | 379 | static inline u8 |
340 | snd_azf3328_codec_inb(const struct snd_azf3328 *chip, unsigned reg) | 380 | snd_azf3328_codec_inb(const struct snd_azf3328_codec_data *codec, unsigned reg) |
341 | { | 381 | { |
342 | return inb(chip->codec_io + reg); | 382 | return inb(codec->io_base + reg); |
343 | } | 383 | } |
344 | 384 | ||
345 | static inline void | 385 | static inline void |
346 | snd_azf3328_codec_outw(const struct snd_azf3328 *chip, unsigned reg, u16 value) | 386 | snd_azf3328_codec_outw(const struct snd_azf3328_codec_data *codec, |
387 | unsigned reg, | ||
388 | u16 value | ||
389 | ) | ||
347 | { | 390 | { |
348 | outw(value, chip->codec_io + reg); | 391 | outw(value, codec->io_base + reg); |
349 | } | 392 | } |
350 | 393 | ||
351 | static inline u16 | 394 | static inline u16 |
352 | snd_azf3328_codec_inw(const struct snd_azf3328 *chip, unsigned reg) | 395 | snd_azf3328_codec_inw(const struct snd_azf3328_codec_data *codec, unsigned reg) |
353 | { | 396 | { |
354 | return inw(chip->codec_io + reg); | 397 | return inw(codec->io_base + reg); |
355 | } | 398 | } |
356 | 399 | ||
357 | static inline void | 400 | static inline void |
358 | snd_azf3328_codec_outl(const struct snd_azf3328 *chip, unsigned reg, u32 value) | 401 | snd_azf3328_codec_outl(const struct snd_azf3328_codec_data *codec, |
402 | unsigned reg, | ||
403 | u32 value | ||
404 | ) | ||
359 | { | 405 | { |
360 | outl(value, chip->codec_io + reg); | 406 | outl(value, codec->io_base + reg); |
361 | } | 407 | } |
362 | 408 | ||
363 | static inline u32 | 409 | static inline u32 |
364 | snd_azf3328_codec_inl(const struct snd_azf3328 *chip, unsigned reg) | 410 | snd_azf3328_codec_inl(const struct snd_azf3328_codec_data *codec, unsigned reg) |
411 | { | ||
412 | return inl(codec->io_base + reg); | ||
413 | } | ||
414 | |||
415 | static inline void | ||
416 | snd_azf3328_ctrl_outb(const struct snd_azf3328 *chip, unsigned reg, u8 value) | ||
365 | { | 417 | { |
366 | return inl(chip->codec_io + reg); | 418 | outb(value, chip->ctrl_io + reg); |
419 | } | ||
420 | |||
421 | static inline u8 | ||
422 | snd_azf3328_ctrl_inb(const struct snd_azf3328 *chip, unsigned reg) | ||
423 | { | ||
424 | return inb(chip->ctrl_io + reg); | ||
425 | } | ||
426 | |||
427 | static inline void | ||
428 | snd_azf3328_ctrl_outw(const struct snd_azf3328 *chip, unsigned reg, u16 value) | ||
429 | { | ||
430 | outw(value, chip->ctrl_io + reg); | ||
431 | } | ||
432 | |||
433 | static inline void | ||
434 | snd_azf3328_ctrl_outl(const struct snd_azf3328 *chip, unsigned reg, u32 value) | ||
435 | { | ||
436 | outl(value, chip->ctrl_io + reg); | ||
367 | } | 437 | } |
368 | 438 | ||
369 | static inline void | 439 | static inline void |
@@ -404,13 +474,13 @@ snd_azf3328_mixer_inw(const struct snd_azf3328 *chip, unsigned reg) | |||
404 | 474 | ||
405 | #define AZF_MUTE_BIT 0x80 | 475 | #define AZF_MUTE_BIT 0x80 |
406 | 476 | ||
407 | static int | 477 | static bool |
408 | snd_azf3328_mixer_set_mute(const struct snd_azf3328 *chip, | 478 | snd_azf3328_mixer_set_mute(const struct snd_azf3328 *chip, |
409 | unsigned reg, int do_mute | 479 | unsigned reg, bool do_mute |
410 | ) | 480 | ) |
411 | { | 481 | { |
412 | unsigned long portbase = chip->mixer_io + reg + 1; | 482 | unsigned long portbase = chip->mixer_io + reg + 1; |
413 | int updated; | 483 | bool updated; |
414 | 484 | ||
415 | /* the mute bit is on the *second* (i.e. right) register of a | 485 | /* the mute bit is on the *second* (i.e. right) register of a |
416 | * left/right channel setting */ | 486 | * left/right channel setting */ |
@@ -569,7 +639,7 @@ snd_azf3328_get_mixer(struct snd_kcontrol *kcontrol, | |||
569 | { | 639 | { |
570 | struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol); | 640 | struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol); |
571 | struct azf3328_mixer_reg reg; | 641 | struct azf3328_mixer_reg reg; |
572 | unsigned int oreg, val; | 642 | u16 oreg, val; |
573 | 643 | ||
574 | snd_azf3328_dbgcallenter(); | 644 | snd_azf3328_dbgcallenter(); |
575 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); | 645 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); |
@@ -600,7 +670,7 @@ snd_azf3328_put_mixer(struct snd_kcontrol *kcontrol, | |||
600 | { | 670 | { |
601 | struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol); | 671 | struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol); |
602 | struct azf3328_mixer_reg reg; | 672 | struct azf3328_mixer_reg reg; |
603 | unsigned int oreg, nreg, val; | 673 | u16 oreg, nreg, val; |
604 | 674 | ||
605 | snd_azf3328_dbgcallenter(); | 675 | snd_azf3328_dbgcallenter(); |
606 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); | 676 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); |
@@ -709,7 +779,7 @@ snd_azf3328_put_mixer_enum(struct snd_kcontrol *kcontrol, | |||
709 | { | 779 | { |
710 | struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol); | 780 | struct snd_azf3328 *chip = snd_kcontrol_chip(kcontrol); |
711 | struct azf3328_mixer_reg reg; | 781 | struct azf3328_mixer_reg reg; |
712 | unsigned int oreg, nreg, val; | 782 | u16 oreg, nreg, val; |
713 | 783 | ||
714 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); | 784 | snd_azf3328_mixer_reg_decode(®, kcontrol->private_value); |
715 | oreg = snd_azf3328_mixer_inw(chip, reg.reg); | 785 | oreg = snd_azf3328_mixer_inw(chip, reg.reg); |
@@ -867,14 +937,15 @@ snd_azf3328_hw_free(struct snd_pcm_substream *substream) | |||
867 | 937 | ||
868 | static void | 938 | static void |
869 | snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, | 939 | snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, |
870 | unsigned reg, | 940 | enum snd_azf3328_codec_type codec_type, |
871 | enum azf_freq_t bitrate, | 941 | enum azf_freq_t bitrate, |
872 | unsigned int format_width, | 942 | unsigned int format_width, |
873 | unsigned int channels | 943 | unsigned int channels |
874 | ) | 944 | ) |
875 | { | 945 | { |
876 | u16 val = 0xff00; | ||
877 | unsigned long flags; | 946 | unsigned long flags; |
947 | const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; | ||
948 | u16 val = 0xff00; | ||
878 | 949 | ||
879 | snd_azf3328_dbgcallenter(); | 950 | snd_azf3328_dbgcallenter(); |
880 | switch (bitrate) { | 951 | switch (bitrate) { |
@@ -917,7 +988,7 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, | |||
917 | spin_lock_irqsave(&chip->reg_lock, flags); | 988 | spin_lock_irqsave(&chip->reg_lock, flags); |
918 | 989 | ||
919 | /* set bitrate/format */ | 990 | /* set bitrate/format */ |
920 | snd_azf3328_codec_outw(chip, reg, val); | 991 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_SOUNDFORMAT, val); |
921 | 992 | ||
922 | /* changing the bitrate/format settings switches off the | 993 | /* changing the bitrate/format settings switches off the |
923 | * audio output with an annoying click in case of 8/16bit format change | 994 | * audio output with an annoying click in case of 8/16bit format change |
@@ -926,11 +997,11 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, | |||
926 | * (FIXME: yes, it works, but what exactly am I doing here?? :) | 997 | * (FIXME: yes, it works, but what exactly am I doing here?? :) |
927 | * FIXME: does this have some side effects for full-duplex | 998 | * FIXME: does this have some side effects for full-duplex |
928 | * or other dramatic side effects? */ | 999 | * or other dramatic side effects? */ |
929 | if (reg == IDX_IO_PLAY_SOUNDFORMAT) /* only do it for playback */ | 1000 | if (codec_type == AZF_CODEC_PLAYBACK) /* only do it for playback */ |
930 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, | 1001 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, |
931 | snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) | | 1002 | snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS) | |
932 | DMA_PLAY_SOMETHING1 | | 1003 | DMA_RUN_SOMETHING1 | |
933 | DMA_PLAY_SOMETHING2 | | 1004 | DMA_RUN_SOMETHING2 | |
934 | SOMETHING_ALMOST_ALWAYS_SET | | 1005 | SOMETHING_ALMOST_ALWAYS_SET | |
935 | DMA_EPILOGUE_SOMETHING | | 1006 | DMA_EPILOGUE_SOMETHING | |
936 | DMA_SOMETHING_ELSE | 1007 | DMA_SOMETHING_ELSE |
@@ -942,134 +1013,132 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, | |||
942 | 1013 | ||
943 | static inline void | 1014 | static inline void |
944 | snd_azf3328_codec_setfmt_lowpower(struct snd_azf3328 *chip, | 1015 | snd_azf3328_codec_setfmt_lowpower(struct snd_azf3328 *chip, |
945 | unsigned reg | 1016 | enum snd_azf3328_codec_type codec_type |
946 | ) | 1017 | ) |
947 | { | 1018 | { |
948 | /* choose lowest frequency for low power consumption. | 1019 | /* choose lowest frequency for low power consumption. |
949 | * While this will cause louder noise due to rather coarse frequency, | 1020 | * While this will cause louder noise due to rather coarse frequency, |
950 | * it should never matter since output should always | 1021 | * it should never matter since output should always |
951 | * get disabled properly when idle anyway. */ | 1022 | * get disabled properly when idle anyway. */ |
952 | snd_azf3328_codec_setfmt(chip, reg, AZF_FREQ_4000, 8, 1); | 1023 | snd_azf3328_codec_setfmt(chip, codec_type, AZF_FREQ_4000, 8, 1); |
953 | } | 1024 | } |
954 | 1025 | ||
955 | static void | 1026 | static void |
956 | snd_azf3328_codec_reg_6AH_update(struct snd_azf3328 *chip, | 1027 | snd_azf3328_ctrl_reg_6AH_update(struct snd_azf3328 *chip, |
957 | unsigned bitmask, | 1028 | unsigned bitmask, |
958 | int enable | 1029 | bool enable |
959 | ) | 1030 | ) |
960 | { | 1031 | { |
961 | if (enable) | 1032 | if (enable) |
962 | chip->shadow_reg_codec_6AH &= ~bitmask; | 1033 | chip->shadow_reg_ctrl_6AH &= ~bitmask; |
963 | else | 1034 | else |
964 | chip->shadow_reg_codec_6AH |= bitmask; | 1035 | chip->shadow_reg_ctrl_6AH |= bitmask; |
965 | snd_azf3328_dbgplay("6AH_update mask 0x%04x enable %d: val 0x%04x\n", | 1036 | snd_azf3328_dbgplay("6AH_update mask 0x%04x enable %d: val 0x%04x\n", |
966 | bitmask, enable, chip->shadow_reg_codec_6AH); | 1037 | bitmask, enable, chip->shadow_reg_ctrl_6AH); |
967 | snd_azf3328_codec_outw(chip, IDX_IO_6AH, chip->shadow_reg_codec_6AH); | 1038 | snd_azf3328_ctrl_outw(chip, IDX_IO_6AH, chip->shadow_reg_ctrl_6AH); |
968 | } | 1039 | } |
969 | 1040 | ||
970 | static inline void | 1041 | static inline void |
971 | snd_azf3328_codec_enable(struct snd_azf3328 *chip, int enable) | 1042 | snd_azf3328_ctrl_enable_codecs(struct snd_azf3328 *chip, bool enable) |
972 | { | 1043 | { |
973 | snd_azf3328_dbgplay("codec_enable %d\n", enable); | 1044 | snd_azf3328_dbgplay("codec_enable %d\n", enable); |
974 | /* no idea what exactly is being done here, but I strongly assume it's | 1045 | /* no idea what exactly is being done here, but I strongly assume it's |
975 | * PM related */ | 1046 | * PM related */ |
976 | snd_azf3328_codec_reg_6AH_update( | 1047 | snd_azf3328_ctrl_reg_6AH_update( |
977 | chip, IO_6A_PAUSE_PLAYBACK_BIT8, enable | 1048 | chip, IO_6A_PAUSE_PLAYBACK_BIT8, enable |
978 | ); | 1049 | ); |
979 | } | 1050 | } |
980 | 1051 | ||
981 | static void | 1052 | static void |
982 | snd_azf3328_codec_activity(struct snd_azf3328 *chip, | 1053 | snd_azf3328_ctrl_codec_activity(struct snd_azf3328 *chip, |
983 | enum snd_azf3328_stream_index stream_type, | 1054 | enum snd_azf3328_codec_type codec_type, |
984 | int enable | 1055 | bool enable |
985 | ) | 1056 | ) |
986 | { | 1057 | { |
987 | int need_change = (chip->audio_stream[stream_type].running != enable); | 1058 | struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; |
1059 | bool need_change = (codec->running != enable); | ||
988 | 1060 | ||
989 | snd_azf3328_dbgplay( | 1061 | snd_azf3328_dbgplay( |
990 | "codec_activity: type %d, enable %d, need_change %d\n", | 1062 | "codec_activity: %s codec, enable %d, need_change %d\n", |
991 | stream_type, enable, need_change | 1063 | codec->name, enable, need_change |
992 | ); | 1064 | ); |
993 | if (need_change) { | 1065 | if (need_change) { |
994 | enum snd_azf3328_stream_index other = | 1066 | static const struct { |
995 | (stream_type == AZF_PLAYBACK) ? | 1067 | enum snd_azf3328_codec_type other1; |
996 | AZF_CAPTURE : AZF_PLAYBACK; | 1068 | enum snd_azf3328_codec_type other2; |
997 | /* small check to prevent shutting down the other party | 1069 | } peer_codecs[3] = |
998 | * in case it's active */ | 1070 | { { AZF_CODEC_CAPTURE, AZF_CODEC_I2S_OUT }, |
999 | if ((enable) || !(chip->audio_stream[other].running)) | 1071 | { AZF_CODEC_PLAYBACK, AZF_CODEC_I2S_OUT }, |
1000 | snd_azf3328_codec_enable(chip, enable); | 1072 | { AZF_CODEC_PLAYBACK, AZF_CODEC_CAPTURE } }; |
1073 | bool call_function; | ||
1074 | |||
1075 | if (enable) | ||
1076 | /* if enable codec, call enable_codecs func | ||
1077 | to enable codec supply... */ | ||
1078 | call_function = 1; | ||
1079 | else { | ||
1080 | /* ...otherwise call enable_codecs func | ||
1081 | (which globally shuts down operation of codecs) | ||
1082 | only in case the other codecs are currently | ||
1083 | not active either! */ | ||
1084 | if ((!chip->codecs[peer_codecs[codec_type].other1] | ||
1085 | .running) | ||
1086 | && (!chip->codecs[peer_codecs[codec_type].other2] | ||
1087 | .running)) | ||
1088 | call_function = 1; | ||
1089 | } | ||
1090 | if (call_function) | ||
1091 | snd_azf3328_ctrl_enable_codecs(chip, enable); | ||
1001 | 1092 | ||
1002 | /* ...and adjust clock, too | 1093 | /* ...and adjust clock, too |
1003 | * (reduce noise and power consumption) */ | 1094 | * (reduce noise and power consumption) */ |
1004 | if (!enable) | 1095 | if (!enable) |
1005 | snd_azf3328_codec_setfmt_lowpower( | 1096 | snd_azf3328_codec_setfmt_lowpower( |
1006 | chip, | 1097 | chip, |
1007 | chip->audio_stream[stream_type].portbase | 1098 | codec_type |
1008 | + IDX_IO_PLAY_SOUNDFORMAT | ||
1009 | ); | 1099 | ); |
1010 | } | 1100 | } |
1011 | chip->audio_stream[stream_type].running = enable; | 1101 | codec->running = enable; |
1012 | } | 1102 | } |
1013 | 1103 | ||
1014 | static void | 1104 | static void |
1015 | snd_azf3328_setdmaa(struct snd_azf3328 *chip, | 1105 | snd_azf3328_codec_setdmaa(struct snd_azf3328 *chip, |
1016 | long unsigned int addr, | 1106 | enum snd_azf3328_codec_type codec_type, |
1017 | unsigned int count, | 1107 | unsigned long addr, |
1018 | unsigned int size, | 1108 | unsigned int count, |
1019 | enum snd_azf3328_stream_index stream_type | 1109 | unsigned int size |
1020 | ) | 1110 | ) |
1021 | { | 1111 | { |
1112 | const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; | ||
1022 | snd_azf3328_dbgcallenter(); | 1113 | snd_azf3328_dbgcallenter(); |
1023 | if (!chip->audio_stream[stream_type].running) { | 1114 | if (!codec->running) { |
1024 | /* AZF3328 uses a two buffer pointer DMA playback approach */ | 1115 | /* AZF3328 uses a two buffer pointer DMA transfer approach */ |
1025 | 1116 | ||
1026 | unsigned long flags, portbase, addr_area2; | 1117 | unsigned long flags; |
1027 | 1118 | ||
1028 | /* width 32bit (prevent overflow): */ | 1119 | /* width 32bit (prevent overflow): */ |
1029 | unsigned long count_areas, count_tmp; | 1120 | u32 addr_area2, count_areas, lengths; |
1030 | 1121 | ||
1031 | portbase = chip->audio_stream[stream_type].portbase; | ||
1032 | count_areas = size/2; | 1122 | count_areas = size/2; |
1033 | addr_area2 = addr+count_areas; | 1123 | addr_area2 = addr+count_areas; |
1034 | count_areas--; /* max. index */ | 1124 | count_areas--; /* max. index */ |
1035 | snd_azf3328_dbgplay("set DMA: buf1 %08lx[%lu], buf2 %08lx[%lu]\n", addr, count_areas, addr_area2, count_areas); | 1125 | snd_azf3328_dbgplay("set DMA: buf1 %08lx[%lu], buf2 %08lx[%lu]\n", addr, count_areas, addr_area2, count_areas); |
1036 | 1126 | ||
1037 | /* build combined I/O buffer length word */ | 1127 | /* build combined I/O buffer length word */ |
1038 | count_tmp = count_areas; | 1128 | lengths = (count_areas << 16) | (count_areas); |
1039 | count_areas |= (count_tmp << 16); | ||
1040 | spin_lock_irqsave(&chip->reg_lock, flags); | 1129 | spin_lock_irqsave(&chip->reg_lock, flags); |
1041 | outl(addr, portbase + IDX_IO_PLAY_DMA_START_1); | 1130 | snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_START_1, addr); |
1042 | outl(addr_area2, portbase + IDX_IO_PLAY_DMA_START_2); | 1131 | snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_START_2, |
1043 | outl(count_areas, portbase + IDX_IO_PLAY_DMA_LEN_1); | 1132 | addr_area2); |
1133 | snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_LENGTHS, | ||
1134 | lengths); | ||
1044 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 1135 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
1045 | } | 1136 | } |
1046 | snd_azf3328_dbgcallleave(); | 1137 | snd_azf3328_dbgcallleave(); |
1047 | } | 1138 | } |
1048 | 1139 | ||
1049 | static int | 1140 | static int |
1050 | snd_azf3328_playback_prepare(struct snd_pcm_substream *substream) | 1141 | snd_azf3328_codec_prepare(struct snd_pcm_substream *substream) |
1051 | { | ||
1052 | #if 0 | ||
1053 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | ||
1054 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
1055 | unsigned int size = snd_pcm_lib_buffer_bytes(substream); | ||
1056 | unsigned int count = snd_pcm_lib_period_bytes(substream); | ||
1057 | #endif | ||
1058 | |||
1059 | snd_azf3328_dbgcallenter(); | ||
1060 | #if 0 | ||
1061 | snd_azf3328_codec_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, | ||
1062 | runtime->rate, | ||
1063 | snd_pcm_format_width(runtime->format), | ||
1064 | runtime->channels); | ||
1065 | snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, AZF_PLAYBACK); | ||
1066 | #endif | ||
1067 | snd_azf3328_dbgcallleave(); | ||
1068 | return 0; | ||
1069 | } | ||
1070 | |||
1071 | static int | ||
1072 | snd_azf3328_capture_prepare(struct snd_pcm_substream *substream) | ||
1073 | { | 1142 | { |
1074 | #if 0 | 1143 | #if 0 |
1075 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1144 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); |
@@ -1080,135 +1149,161 @@ snd_azf3328_capture_prepare(struct snd_pcm_substream *substream) | |||
1080 | 1149 | ||
1081 | snd_azf3328_dbgcallenter(); | 1150 | snd_azf3328_dbgcallenter(); |
1082 | #if 0 | 1151 | #if 0 |
1083 | snd_azf3328_codec_setfmt(chip, IDX_IO_REC_SOUNDFORMAT, | 1152 | snd_azf3328_codec_setfmt(chip, AZF_CODEC_..., |
1084 | runtime->rate, | 1153 | runtime->rate, |
1085 | snd_pcm_format_width(runtime->format), | 1154 | snd_pcm_format_width(runtime->format), |
1086 | runtime->channels); | 1155 | runtime->channels); |
1087 | snd_azf3328_setdmaa(chip, runtime->dma_addr, count, size, AZF_CAPTURE); | 1156 | snd_azf3328_codec_setdmaa(chip, AZF_CODEC_..., |
1157 | runtime->dma_addr, count, size); | ||
1088 | #endif | 1158 | #endif |
1089 | snd_azf3328_dbgcallleave(); | 1159 | snd_azf3328_dbgcallleave(); |
1090 | return 0; | 1160 | return 0; |
1091 | } | 1161 | } |
1092 | 1162 | ||
1093 | static int | 1163 | static int |
1094 | snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) | 1164 | snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, |
1165 | struct snd_pcm_substream *substream, int cmd) | ||
1095 | { | 1166 | { |
1096 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1167 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); |
1168 | const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; | ||
1097 | struct snd_pcm_runtime *runtime = substream->runtime; | 1169 | struct snd_pcm_runtime *runtime = substream->runtime; |
1098 | int result = 0; | 1170 | int result = 0; |
1099 | unsigned int status1; | 1171 | u16 flags1; |
1100 | int previously_muted; | 1172 | bool previously_muted = 0; |
1173 | bool is_playback_codec = (AZF_CODEC_PLAYBACK == codec_type); | ||
1101 | 1174 | ||
1102 | snd_azf3328_dbgcalls("snd_azf3328_playback_trigger cmd %d\n", cmd); | 1175 | snd_azf3328_dbgcalls("snd_azf3328_codec_trigger cmd %d\n", cmd); |
1103 | 1176 | ||
1104 | switch (cmd) { | 1177 | switch (cmd) { |
1105 | case SNDRV_PCM_TRIGGER_START: | 1178 | case SNDRV_PCM_TRIGGER_START: |
1106 | snd_azf3328_dbgplay("START PLAYBACK\n"); | 1179 | snd_azf3328_dbgplay("START %s\n", codec->name); |
1107 | 1180 | ||
1108 | /* mute WaveOut (avoid clicking during setup) */ | 1181 | if (is_playback_codec) { |
1109 | previously_muted = | 1182 | /* mute WaveOut (avoid clicking during setup) */ |
1110 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); | 1183 | previously_muted = |
1184 | snd_azf3328_mixer_set_mute( | ||
1185 | chip, IDX_MIXER_WAVEOUT, 1 | ||
1186 | ); | ||
1187 | } | ||
1111 | 1188 | ||
1112 | snd_azf3328_codec_setfmt(chip, IDX_IO_PLAY_SOUNDFORMAT, | 1189 | snd_azf3328_codec_setfmt(chip, codec_type, |
1113 | runtime->rate, | 1190 | runtime->rate, |
1114 | snd_pcm_format_width(runtime->format), | 1191 | snd_pcm_format_width(runtime->format), |
1115 | runtime->channels); | 1192 | runtime->channels); |
1116 | 1193 | ||
1117 | spin_lock(&chip->reg_lock); | 1194 | spin_lock(&chip->reg_lock); |
1118 | /* first, remember current value: */ | 1195 | /* first, remember current value: */ |
1119 | status1 = snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS); | 1196 | flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS); |
1120 | 1197 | ||
1121 | /* stop playback */ | 1198 | /* stop transfer */ |
1122 | status1 &= ~DMA_RESUME; | 1199 | flags1 &= ~DMA_RESUME; |
1123 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); | 1200 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); |
1124 | 1201 | ||
1125 | /* FIXME: clear interrupts or what??? */ | 1202 | /* FIXME: clear interrupts or what??? */ |
1126 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_IRQTYPE, 0xffff); | 1203 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_IRQTYPE, 0xffff); |
1127 | spin_unlock(&chip->reg_lock); | 1204 | spin_unlock(&chip->reg_lock); |
1128 | 1205 | ||
1129 | snd_azf3328_setdmaa(chip, runtime->dma_addr, | 1206 | snd_azf3328_codec_setdmaa(chip, codec_type, runtime->dma_addr, |
1130 | snd_pcm_lib_period_bytes(substream), | 1207 | snd_pcm_lib_period_bytes(substream), |
1131 | snd_pcm_lib_buffer_bytes(substream), | 1208 | snd_pcm_lib_buffer_bytes(substream) |
1132 | AZF_PLAYBACK); | 1209 | ); |
1133 | 1210 | ||
1134 | spin_lock(&chip->reg_lock); | 1211 | spin_lock(&chip->reg_lock); |
1135 | #ifdef WIN9X | 1212 | #ifdef WIN9X |
1136 | /* FIXME: enable playback/recording??? */ | 1213 | /* FIXME: enable playback/recording??? */ |
1137 | status1 |= DMA_PLAY_SOMETHING1 | DMA_PLAY_SOMETHING2; | 1214 | flags1 |= DMA_RUN_SOMETHING1 | DMA_RUN_SOMETHING2; |
1138 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); | 1215 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); |
1139 | 1216 | ||
1140 | /* start playback again */ | 1217 | /* start transfer again */ |
1141 | /* FIXME: what is this value (0x0010)??? */ | 1218 | /* FIXME: what is this value (0x0010)??? */ |
1142 | status1 |= DMA_RESUME | DMA_EPILOGUE_SOMETHING; | 1219 | flags1 |= DMA_RESUME | DMA_EPILOGUE_SOMETHING; |
1143 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); | 1220 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); |
1144 | #else /* NT4 */ | 1221 | #else /* NT4 */ |
1145 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, | 1222 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, |
1146 | 0x0000); | 1223 | 0x0000); |
1147 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, | 1224 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, |
1148 | DMA_PLAY_SOMETHING1); | 1225 | DMA_RUN_SOMETHING1); |
1149 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, | 1226 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, |
1150 | DMA_PLAY_SOMETHING1 | | 1227 | DMA_RUN_SOMETHING1 | |
1151 | DMA_PLAY_SOMETHING2); | 1228 | DMA_RUN_SOMETHING2); |
1152 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, | 1229 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, |
1153 | DMA_RESUME | | 1230 | DMA_RESUME | |
1154 | SOMETHING_ALMOST_ALWAYS_SET | | 1231 | SOMETHING_ALMOST_ALWAYS_SET | |
1155 | DMA_EPILOGUE_SOMETHING | | 1232 | DMA_EPILOGUE_SOMETHING | |
1156 | DMA_SOMETHING_ELSE); | 1233 | DMA_SOMETHING_ELSE); |
1157 | #endif | 1234 | #endif |
1158 | spin_unlock(&chip->reg_lock); | 1235 | spin_unlock(&chip->reg_lock); |
1159 | snd_azf3328_codec_activity(chip, AZF_PLAYBACK, 1); | 1236 | snd_azf3328_ctrl_codec_activity(chip, codec_type, 1); |
1160 | 1237 | ||
1161 | /* now unmute WaveOut */ | 1238 | if (is_playback_codec) { |
1162 | if (!previously_muted) | 1239 | /* now unmute WaveOut */ |
1163 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0); | 1240 | if (!previously_muted) |
1241 | snd_azf3328_mixer_set_mute( | ||
1242 | chip, IDX_MIXER_WAVEOUT, 0 | ||
1243 | ); | ||
1244 | } | ||
1164 | 1245 | ||
1165 | snd_azf3328_dbgplay("STARTED PLAYBACK\n"); | 1246 | snd_azf3328_dbgplay("STARTED %s\n", codec->name); |
1166 | break; | 1247 | break; |
1167 | case SNDRV_PCM_TRIGGER_RESUME: | 1248 | case SNDRV_PCM_TRIGGER_RESUME: |
1168 | snd_azf3328_dbgplay("RESUME PLAYBACK\n"); | 1249 | snd_azf3328_dbgplay("RESUME %s\n", codec->name); |
1169 | /* resume playback if we were active */ | 1250 | /* resume codec if we were active */ |
1170 | spin_lock(&chip->reg_lock); | 1251 | spin_lock(&chip->reg_lock); |
1171 | if (chip->audio_stream[AZF_PLAYBACK].running) | 1252 | if (codec->running) |
1172 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, | 1253 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, |
1173 | snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) | DMA_RESUME); | 1254 | snd_azf3328_codec_inw( |
1255 | codec, IDX_IO_CODEC_DMA_FLAGS | ||
1256 | ) | DMA_RESUME | ||
1257 | ); | ||
1174 | spin_unlock(&chip->reg_lock); | 1258 | spin_unlock(&chip->reg_lock); |
1175 | break; | 1259 | break; |
1176 | case SNDRV_PCM_TRIGGER_STOP: | 1260 | case SNDRV_PCM_TRIGGER_STOP: |
1177 | snd_azf3328_dbgplay("STOP PLAYBACK\n"); | 1261 | snd_azf3328_dbgplay("STOP %s\n", codec->name); |
1178 | 1262 | ||
1179 | /* mute WaveOut (avoid clicking during setup) */ | 1263 | if (is_playback_codec) { |
1180 | previously_muted = | 1264 | /* mute WaveOut (avoid clicking during setup) */ |
1181 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); | 1265 | previously_muted = |
1266 | snd_azf3328_mixer_set_mute( | ||
1267 | chip, IDX_MIXER_WAVEOUT, 1 | ||
1268 | ); | ||
1269 | } | ||
1182 | 1270 | ||
1183 | spin_lock(&chip->reg_lock); | 1271 | spin_lock(&chip->reg_lock); |
1184 | /* first, remember current value: */ | 1272 | /* first, remember current value: */ |
1185 | status1 = snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS); | 1273 | flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS); |
1186 | 1274 | ||
1187 | /* stop playback */ | 1275 | /* stop transfer */ |
1188 | status1 &= ~DMA_RESUME; | 1276 | flags1 &= ~DMA_RESUME; |
1189 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); | 1277 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); |
1190 | 1278 | ||
1191 | /* hmm, is this really required? we're resetting the same bit | 1279 | /* hmm, is this really required? we're resetting the same bit |
1192 | * immediately thereafter... */ | 1280 | * immediately thereafter... */ |
1193 | status1 |= DMA_PLAY_SOMETHING1; | 1281 | flags1 |= DMA_RUN_SOMETHING1; |
1194 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); | 1282 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); |
1195 | 1283 | ||
1196 | status1 &= ~DMA_PLAY_SOMETHING1; | 1284 | flags1 &= ~DMA_RUN_SOMETHING1; |
1197 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, status1); | 1285 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); |
1198 | spin_unlock(&chip->reg_lock); | 1286 | spin_unlock(&chip->reg_lock); |
1199 | snd_azf3328_codec_activity(chip, AZF_PLAYBACK, 0); | 1287 | snd_azf3328_ctrl_codec_activity(chip, codec_type, 0); |
1200 | 1288 | ||
1201 | /* now unmute WaveOut */ | 1289 | if (is_playback_codec) { |
1202 | if (!previously_muted) | 1290 | /* now unmute WaveOut */ |
1203 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 0); | 1291 | if (!previously_muted) |
1292 | snd_azf3328_mixer_set_mute( | ||
1293 | chip, IDX_MIXER_WAVEOUT, 0 | ||
1294 | ); | ||
1295 | } | ||
1204 | 1296 | ||
1205 | snd_azf3328_dbgplay("STOPPED PLAYBACK\n"); | 1297 | snd_azf3328_dbgplay("STOPPED %s\n", codec->name); |
1206 | break; | 1298 | break; |
1207 | case SNDRV_PCM_TRIGGER_SUSPEND: | 1299 | case SNDRV_PCM_TRIGGER_SUSPEND: |
1208 | snd_azf3328_dbgplay("SUSPEND PLAYBACK\n"); | 1300 | snd_azf3328_dbgplay("SUSPEND %s\n", codec->name); |
1209 | /* make sure playback is stopped */ | 1301 | /* make sure codec is stopped */ |
1210 | snd_azf3328_codec_outw(chip, IDX_IO_PLAY_FLAGS, | 1302 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, |
1211 | snd_azf3328_codec_inw(chip, IDX_IO_PLAY_FLAGS) & ~DMA_RESUME); | 1303 | snd_azf3328_codec_inw( |
1304 | codec, IDX_IO_CODEC_DMA_FLAGS | ||
1305 | ) & ~DMA_RESUME | ||
1306 | ); | ||
1212 | break; | 1307 | break; |
1213 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 1308 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
1214 | snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n"); | 1309 | snd_printk(KERN_ERR "FIXME: SNDRV_PCM_TRIGGER_PAUSE_PUSH NIY!\n"); |
@@ -1225,172 +1320,74 @@ snd_azf3328_playback_trigger(struct snd_pcm_substream *substream, int cmd) | |||
1225 | return result; | 1320 | return result; |
1226 | } | 1321 | } |
1227 | 1322 | ||
1228 | /* this is just analogous to playback; I'm not quite sure whether recording | ||
1229 | * should actually be triggered like that */ | ||
1230 | static int | 1323 | static int |
1231 | snd_azf3328_capture_trigger(struct snd_pcm_substream *substream, int cmd) | 1324 | snd_azf3328_codec_playback_trigger(struct snd_pcm_substream *substream, int cmd) |
1232 | { | 1325 | { |
1233 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1326 | return snd_azf3328_codec_trigger(AZF_CODEC_PLAYBACK, substream, cmd); |
1234 | struct snd_pcm_runtime *runtime = substream->runtime; | 1327 | } |
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 | 1328 | ||
1324 | snd_azf3328_dbgplay("STOPPED CAPTURE\n"); | 1329 | static int |
1325 | break; | 1330 | snd_azf3328_codec_capture_trigger(struct snd_pcm_substream *substream, int cmd) |
1326 | case SNDRV_PCM_TRIGGER_SUSPEND: | 1331 | { |
1327 | snd_azf3328_dbgplay("SUSPEND CAPTURE\n"); | 1332 | return snd_azf3328_codec_trigger(AZF_CODEC_CAPTURE, substream, cmd); |
1328 | /* make sure recording is stopped */ | 1333 | } |
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 | 1334 | ||
1343 | snd_azf3328_dbgcallleave(); | 1335 | static int |
1344 | return result; | 1336 | snd_azf3328_codec_i2s_out_trigger(struct snd_pcm_substream *substream, int cmd) |
1337 | { | ||
1338 | return snd_azf3328_codec_trigger(AZF_CODEC_I2S_OUT, substream, cmd); | ||
1345 | } | 1339 | } |
1346 | 1340 | ||
1347 | static snd_pcm_uframes_t | 1341 | static snd_pcm_uframes_t |
1348 | snd_azf3328_playback_pointer(struct snd_pcm_substream *substream) | 1342 | snd_azf3328_codec_pointer(struct snd_pcm_substream *substream, |
1343 | enum snd_azf3328_codec_type codec_type | ||
1344 | ) | ||
1349 | { | 1345 | { |
1350 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1346 | const struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); |
1347 | const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; | ||
1351 | unsigned long bufptr, result; | 1348 | unsigned long bufptr, result; |
1352 | snd_pcm_uframes_t frmres; | 1349 | snd_pcm_uframes_t frmres; |
1353 | 1350 | ||
1354 | #ifdef QUERY_HARDWARE | 1351 | #ifdef QUERY_HARDWARE |
1355 | bufptr = snd_azf3328_codec_inl(chip, IDX_IO_PLAY_DMA_START_1); | 1352 | bufptr = snd_azf3328_codec_inl(codec, IDX_IO_CODEC_DMA_START_1); |
1356 | #else | 1353 | #else |
1357 | bufptr = substream->runtime->dma_addr; | 1354 | bufptr = substream->runtime->dma_addr; |
1358 | #endif | 1355 | #endif |
1359 | result = snd_azf3328_codec_inl(chip, IDX_IO_PLAY_DMA_CURRPOS); | 1356 | result = snd_azf3328_codec_inl(codec, IDX_IO_CODEC_DMA_CURRPOS); |
1360 | 1357 | ||
1361 | /* calculate offset */ | 1358 | /* calculate offset */ |
1362 | result -= bufptr; | 1359 | result -= bufptr; |
1363 | frmres = bytes_to_frames( substream->runtime, result); | 1360 | frmres = bytes_to_frames( substream->runtime, result); |
1364 | snd_azf3328_dbgplay("PLAY @ 0x%8lx, frames %8ld\n", result, frmres); | 1361 | snd_azf3328_dbgplay("%s @ 0x%8lx, frames %8ld\n", |
1362 | codec->name, result, frmres); | ||
1365 | return frmres; | 1363 | return frmres; |
1366 | } | 1364 | } |
1367 | 1365 | ||
1368 | static snd_pcm_uframes_t | 1366 | static snd_pcm_uframes_t |
1369 | snd_azf3328_capture_pointer(struct snd_pcm_substream *substream) | 1367 | snd_azf3328_codec_playback_pointer(struct snd_pcm_substream *substream) |
1370 | { | 1368 | { |
1371 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1369 | return snd_azf3328_codec_pointer(substream, AZF_CODEC_PLAYBACK); |
1372 | unsigned long bufptr, result; | 1370 | } |
1373 | snd_pcm_uframes_t frmres; | ||
1374 | 1371 | ||
1375 | #ifdef QUERY_HARDWARE | 1372 | static snd_pcm_uframes_t |
1376 | bufptr = snd_azf3328_codec_inl(chip, IDX_IO_REC_DMA_START_1); | 1373 | snd_azf3328_codec_capture_pointer(struct snd_pcm_substream *substream) |
1377 | #else | 1374 | { |
1378 | bufptr = substream->runtime->dma_addr; | 1375 | return snd_azf3328_codec_pointer(substream, AZF_CODEC_CAPTURE); |
1379 | #endif | 1376 | } |
1380 | result = snd_azf3328_codec_inl(chip, IDX_IO_REC_DMA_CURRPOS); | ||
1381 | 1377 | ||
1382 | /* calculate offset */ | 1378 | static snd_pcm_uframes_t |
1383 | result -= bufptr; | 1379 | snd_azf3328_codec_i2s_out_pointer(struct snd_pcm_substream *substream) |
1384 | frmres = bytes_to_frames( substream->runtime, result); | 1380 | { |
1385 | snd_azf3328_dbgplay("REC @ 0x%8lx, frames %8ld\n", result, frmres); | 1381 | return snd_azf3328_codec_pointer(substream, AZF_CODEC_I2S_OUT); |
1386 | return frmres; | ||
1387 | } | 1382 | } |
1388 | 1383 | ||
1389 | /******************************************************************/ | 1384 | /******************************************************************/ |
1390 | 1385 | ||
1391 | #ifdef SUPPORT_GAMEPORT | 1386 | #ifdef SUPPORT_GAMEPORT |
1392 | static inline void | 1387 | static inline void |
1393 | snd_azf3328_gameport_irq_enable(struct snd_azf3328 *chip, int enable) | 1388 | snd_azf3328_gameport_irq_enable(struct snd_azf3328 *chip, |
1389 | bool enable | ||
1390 | ) | ||
1394 | { | 1391 | { |
1395 | snd_azf3328_io_reg_setb( | 1392 | snd_azf3328_io_reg_setb( |
1396 | chip->game_io+IDX_GAME_HWCONFIG, | 1393 | chip->game_io+IDX_GAME_HWCONFIG, |
@@ -1400,7 +1397,9 @@ snd_azf3328_gameport_irq_enable(struct snd_azf3328 *chip, int enable) | |||
1400 | } | 1397 | } |
1401 | 1398 | ||
1402 | static inline void | 1399 | static inline void |
1403 | snd_azf3328_gameport_legacy_address_enable(struct snd_azf3328 *chip, int enable) | 1400 | snd_azf3328_gameport_legacy_address_enable(struct snd_azf3328 *chip, |
1401 | bool enable | ||
1402 | ) | ||
1404 | { | 1403 | { |
1405 | snd_azf3328_io_reg_setb( | 1404 | snd_azf3328_io_reg_setb( |
1406 | chip->game_io+IDX_GAME_HWCONFIG, | 1405 | chip->game_io+IDX_GAME_HWCONFIG, |
@@ -1409,10 +1408,27 @@ snd_azf3328_gameport_legacy_address_enable(struct snd_azf3328 *chip, int enable) | |||
1409 | ); | 1408 | ); |
1410 | } | 1409 | } |
1411 | 1410 | ||
1411 | static void | ||
1412 | snd_azf3328_gameport_set_counter_frequency(struct snd_azf3328 *chip, | ||
1413 | unsigned int freq_cfg | ||
1414 | ) | ||
1415 | { | ||
1416 | snd_azf3328_io_reg_setb( | ||
1417 | chip->game_io+IDX_GAME_HWCONFIG, | ||
1418 | 0x02, | ||
1419 | (freq_cfg & 1) != 0 | ||
1420 | ); | ||
1421 | snd_azf3328_io_reg_setb( | ||
1422 | chip->game_io+IDX_GAME_HWCONFIG, | ||
1423 | 0x04, | ||
1424 | (freq_cfg & 2) != 0 | ||
1425 | ); | ||
1426 | } | ||
1427 | |||
1412 | static inline void | 1428 | static inline void |
1413 | snd_azf3328_gameport_axis_circuit_enable(struct snd_azf3328 *chip, int enable) | 1429 | snd_azf3328_gameport_axis_circuit_enable(struct snd_azf3328 *chip, bool enable) |
1414 | { | 1430 | { |
1415 | snd_azf3328_codec_reg_6AH_update( | 1431 | snd_azf3328_ctrl_reg_6AH_update( |
1416 | chip, IO_6A_SOMETHING2_GAMEPORT, enable | 1432 | chip, IO_6A_SOMETHING2_GAMEPORT, enable |
1417 | ); | 1433 | ); |
1418 | } | 1434 | } |
@@ -1447,6 +1463,8 @@ snd_azf3328_gameport_open(struct gameport *gameport, int mode) | |||
1447 | break; | 1463 | break; |
1448 | } | 1464 | } |
1449 | 1465 | ||
1466 | snd_azf3328_gameport_set_counter_frequency(chip, | ||
1467 | GAME_HWCFG_ADC_COUNTER_FREQ_STD); | ||
1450 | snd_azf3328_gameport_axis_circuit_enable(chip, (res == 0)); | 1468 | snd_azf3328_gameport_axis_circuit_enable(chip, (res == 0)); |
1451 | 1469 | ||
1452 | return res; | 1470 | return res; |
@@ -1458,6 +1476,8 @@ snd_azf3328_gameport_close(struct gameport *gameport) | |||
1458 | struct snd_azf3328 *chip = gameport_get_port_data(gameport); | 1476 | struct snd_azf3328 *chip = gameport_get_port_data(gameport); |
1459 | 1477 | ||
1460 | snd_azf3328_dbggame("gameport_close\n"); | 1478 | snd_azf3328_dbggame("gameport_close\n"); |
1479 | snd_azf3328_gameport_set_counter_frequency(chip, | ||
1480 | GAME_HWCFG_ADC_COUNTER_FREQ_1_200); | ||
1461 | snd_azf3328_gameport_axis_circuit_enable(chip, 0); | 1481 | snd_azf3328_gameport_axis_circuit_enable(chip, 0); |
1462 | } | 1482 | } |
1463 | 1483 | ||
@@ -1491,7 +1511,7 @@ snd_azf3328_gameport_cooked_read(struct gameport *gameport, | |||
1491 | 1511 | ||
1492 | val = snd_azf3328_game_inb(chip, IDX_GAME_AXES_CONFIG); | 1512 | val = snd_azf3328_game_inb(chip, IDX_GAME_AXES_CONFIG); |
1493 | if (val & GAME_AXES_SAMPLING_READY) { | 1513 | if (val & GAME_AXES_SAMPLING_READY) { |
1494 | for (i = 0; i < 4; ++i) { | 1514 | for (i = 0; i < ARRAY_SIZE(chip->axes); ++i) { |
1495 | /* configure the axis to read */ | 1515 | /* configure the axis to read */ |
1496 | val = (i << 4) | 0x0f; | 1516 | val = (i << 4) | 0x0f; |
1497 | snd_azf3328_game_outb(chip, IDX_GAME_AXES_CONFIG, val); | 1517 | snd_azf3328_game_outb(chip, IDX_GAME_AXES_CONFIG, val); |
@@ -1514,7 +1534,7 @@ snd_azf3328_gameport_cooked_read(struct gameport *gameport, | |||
1514 | snd_azf3328_game_outw(chip, IDX_GAME_AXIS_VALUE, 0xffff); | 1534 | snd_azf3328_game_outw(chip, IDX_GAME_AXIS_VALUE, 0xffff); |
1515 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 1535 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
1516 | 1536 | ||
1517 | for (i = 0; i < 4; i++) { | 1537 | for (i = 0; i < ARRAY_SIZE(chip->axes); i++) { |
1518 | axes[i] = chip->axes[i]; | 1538 | axes[i] = chip->axes[i]; |
1519 | if (axes[i] == 0xffff) | 1539 | if (axes[i] == 0xffff) |
1520 | axes[i] = -1; | 1540 | axes[i] = -1; |
@@ -1552,6 +1572,8 @@ snd_azf3328_gameport(struct snd_azf3328 *chip, int dev) | |||
1552 | /* DISABLE legacy address: we don't need it! */ | 1572 | /* DISABLE legacy address: we don't need it! */ |
1553 | snd_azf3328_gameport_legacy_address_enable(chip, 0); | 1573 | snd_azf3328_gameport_legacy_address_enable(chip, 0); |
1554 | 1574 | ||
1575 | snd_azf3328_gameport_set_counter_frequency(chip, | ||
1576 | GAME_HWCFG_ADC_COUNTER_FREQ_1_200); | ||
1555 | snd_azf3328_gameport_axis_circuit_enable(chip, 0); | 1577 | snd_azf3328_gameport_axis_circuit_enable(chip, 0); |
1556 | 1578 | ||
1557 | gameport_register_port(chip->gameport); | 1579 | gameport_register_port(chip->gameport); |
@@ -1591,29 +1613,69 @@ snd_azf3328_irq_log_unknown_type(u8 which) | |||
1591 | ); | 1613 | ); |
1592 | } | 1614 | } |
1593 | 1615 | ||
1616 | static inline void | ||
1617 | snd_azf3328_codec_interrupt(struct snd_azf3328 *chip, u8 status) | ||
1618 | { | ||
1619 | u8 which; | ||
1620 | enum snd_azf3328_codec_type codec_type; | ||
1621 | const struct snd_azf3328_codec_data *codec; | ||
1622 | |||
1623 | for (codec_type = AZF_CODEC_PLAYBACK; | ||
1624 | codec_type <= AZF_CODEC_I2S_OUT; | ||
1625 | ++codec_type) { | ||
1626 | |||
1627 | /* skip codec if there's no interrupt for it */ | ||
1628 | if (!(status & (1 << codec_type))) | ||
1629 | continue; | ||
1630 | |||
1631 | codec = &chip->codecs[codec_type]; | ||
1632 | |||
1633 | spin_lock(&chip->reg_lock); | ||
1634 | which = snd_azf3328_codec_inb(codec, IDX_IO_CODEC_IRQTYPE); | ||
1635 | /* ack all IRQ types immediately */ | ||
1636 | snd_azf3328_codec_outb(codec, IDX_IO_CODEC_IRQTYPE, which); | ||
1637 | spin_unlock(&chip->reg_lock); | ||
1638 | |||
1639 | if ((chip->pcm[codec_type]) | ||
1640 | && (chip->codecs[codec_type].substream)) { | ||
1641 | snd_pcm_period_elapsed( | ||
1642 | chip->codecs[codec_type].substream | ||
1643 | ); | ||
1644 | snd_azf3328_dbgplay("%s period done (#%x), @ %x\n", | ||
1645 | codec->name, | ||
1646 | which, | ||
1647 | snd_azf3328_codec_inl( | ||
1648 | codec, IDX_IO_CODEC_DMA_CURRPOS | ||
1649 | ) | ||
1650 | ); | ||
1651 | } else | ||
1652 | printk(KERN_WARNING "azt3328: irq handler problem!\n"); | ||
1653 | if (which & IRQ_SOMETHING) | ||
1654 | snd_azf3328_irq_log_unknown_type(which); | ||
1655 | } | ||
1656 | } | ||
1657 | |||
1594 | static irqreturn_t | 1658 | static irqreturn_t |
1595 | snd_azf3328_interrupt(int irq, void *dev_id) | 1659 | snd_azf3328_interrupt(int irq, void *dev_id) |
1596 | { | 1660 | { |
1597 | struct snd_azf3328 *chip = dev_id; | 1661 | struct snd_azf3328 *chip = dev_id; |
1598 | u8 status, which; | 1662 | u8 status; |
1599 | #if DEBUG_PLAY_REC | 1663 | #if DEBUG_PLAY_REC |
1600 | static unsigned long irq_count; | 1664 | static unsigned long irq_count; |
1601 | #endif | 1665 | #endif |
1602 | 1666 | ||
1603 | status = snd_azf3328_codec_inb(chip, IDX_IO_IRQSTATUS); | 1667 | status = snd_azf3328_ctrl_inb(chip, IDX_IO_IRQSTATUS); |
1604 | 1668 | ||
1605 | /* fast path out, to ease interrupt sharing */ | 1669 | /* fast path out, to ease interrupt sharing */ |
1606 | if (!(status & | 1670 | if (!(status & |
1607 | (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_GAMEPORT|IRQ_MPU401|IRQ_TIMER) | 1671 | (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_I2S_OUT |
1672 | |IRQ_GAMEPORT|IRQ_MPU401|IRQ_TIMER) | ||
1608 | )) | 1673 | )) |
1609 | return IRQ_NONE; /* must be interrupt for another device */ | 1674 | return IRQ_NONE; /* must be interrupt for another device */ |
1610 | 1675 | ||
1611 | snd_azf3328_dbgplay( | 1676 | snd_azf3328_dbgplay( |
1612 | "irq_count %ld! IDX_IO_PLAY_FLAGS %04x, " | 1677 | "irq_count %ld! IDX_IO_IRQSTATUS %04x\n", |
1613 | "IDX_IO_PLAY_IRQTYPE %04x, IDX_IO_IRQSTATUS %04x\n", | ||
1614 | irq_count++ /* debug-only */, | 1678 | 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 | 1679 | status |
1618 | ); | 1680 | ); |
1619 | 1681 | ||
@@ -1626,63 +1688,24 @@ snd_azf3328_interrupt(int irq, void *dev_id) | |||
1626 | snd_timer_interrupt(chip->timer, chip->timer->sticks); | 1688 | snd_timer_interrupt(chip->timer, chip->timer->sticks); |
1627 | /* ACK timer */ | 1689 | /* ACK timer */ |
1628 | spin_lock(&chip->reg_lock); | 1690 | spin_lock(&chip->reg_lock); |
1629 | snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x07); | 1691 | snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0x07); |
1630 | spin_unlock(&chip->reg_lock); | 1692 | spin_unlock(&chip->reg_lock); |
1631 | snd_azf3328_dbgplay("azt3328: timer IRQ\n"); | 1693 | snd_azf3328_dbgplay("azt3328: timer IRQ\n"); |
1632 | } | 1694 | } |
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 | 1695 | ||
1640 | if (chip->pcm && chip->audio_stream[AZF_PLAYBACK].substream) { | 1696 | if (status & (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_I2S_OUT)) |
1641 | snd_pcm_period_elapsed( | 1697 | 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 | 1698 | ||
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) | 1699 | if (status & IRQ_GAMEPORT) |
1678 | snd_azf3328_gameport_interrupt(chip); | 1700 | snd_azf3328_gameport_interrupt(chip); |
1701 | |||
1679 | /* MPU401 has less critical IRQ requirements | 1702 | /* MPU401 has less critical IRQ requirements |
1680 | * than timer and playback/recording, right? */ | 1703 | * than timer and playback/recording, right? */ |
1681 | if (status & IRQ_MPU401) { | 1704 | if (status & IRQ_MPU401) { |
1682 | snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data); | 1705 | snd_mpu401_uart_interrupt(irq, chip->rmidi->private_data); |
1683 | 1706 | ||
1684 | /* hmm, do we have to ack the IRQ here somehow? | 1707 | /* hmm, do we have to ack the IRQ here somehow? |
1685 | * If so, then I don't know how... */ | 1708 | * If so, then I don't know how yet... */ |
1686 | snd_azf3328_dbgplay("azt3328: MPU401 IRQ\n"); | 1709 | snd_azf3328_dbgplay("azt3328: MPU401 IRQ\n"); |
1687 | } | 1710 | } |
1688 | return IRQ_HANDLED; | 1711 | return IRQ_HANDLED; |
@@ -1690,7 +1713,11 @@ snd_azf3328_interrupt(int irq, void *dev_id) | |||
1690 | 1713 | ||
1691 | /*****************************************************************/ | 1714 | /*****************************************************************/ |
1692 | 1715 | ||
1693 | static const struct snd_pcm_hardware snd_azf3328_playback = | 1716 | /* as long as we think we have identical snd_pcm_hardware parameters |
1717 | for playback, capture and i2s out, we can use the same physical struct | ||
1718 | since the struct is simply being copied into a member. | ||
1719 | */ | ||
1720 | static const struct snd_pcm_hardware snd_azf3328_hardware = | ||
1694 | { | 1721 | { |
1695 | /* FIXME!! Correct? */ | 1722 | /* FIXME!! Correct? */ |
1696 | .info = SNDRV_PCM_INFO_MMAP | | 1723 | .info = SNDRV_PCM_INFO_MMAP | |
@@ -1718,31 +1745,6 @@ static const struct snd_pcm_hardware snd_azf3328_playback = | |||
1718 | .fifo_size = 0, | 1745 | .fifo_size = 0, |
1719 | }; | 1746 | }; |
1720 | 1747 | ||
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 | 1748 | ||
1747 | static unsigned int snd_azf3328_fixed_rates[] = { | 1749 | static unsigned int snd_azf3328_fixed_rates[] = { |
1748 | AZF_FREQ_4000, | 1750 | AZF_FREQ_4000, |
@@ -1770,14 +1772,19 @@ static struct snd_pcm_hw_constraint_list snd_azf3328_hw_constraints_rates = { | |||
1770 | /*****************************************************************/ | 1772 | /*****************************************************************/ |
1771 | 1773 | ||
1772 | static int | 1774 | static int |
1773 | snd_azf3328_playback_open(struct snd_pcm_substream *substream) | 1775 | snd_azf3328_pcm_open(struct snd_pcm_substream *substream, |
1776 | enum snd_azf3328_codec_type codec_type | ||
1777 | ) | ||
1774 | { | 1778 | { |
1775 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1779 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); |
1776 | struct snd_pcm_runtime *runtime = substream->runtime; | 1780 | struct snd_pcm_runtime *runtime = substream->runtime; |
1777 | 1781 | ||
1778 | snd_azf3328_dbgcallenter(); | 1782 | snd_azf3328_dbgcallenter(); |
1779 | chip->audio_stream[AZF_PLAYBACK].substream = substream; | 1783 | chip->codecs[codec_type].substream = substream; |
1780 | runtime->hw = snd_azf3328_playback; | 1784 | |
1785 | /* same parameters for all our codecs - at least we think so... */ | ||
1786 | runtime->hw = snd_azf3328_hardware; | ||
1787 | |||
1781 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | 1788 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, |
1782 | &snd_azf3328_hw_constraints_rates); | 1789 | &snd_azf3328_hw_constraints_rates); |
1783 | snd_azf3328_dbgcallleave(); | 1790 | snd_azf3328_dbgcallleave(); |
@@ -1785,40 +1792,52 @@ snd_azf3328_playback_open(struct snd_pcm_substream *substream) | |||
1785 | } | 1792 | } |
1786 | 1793 | ||
1787 | static int | 1794 | static int |
1795 | snd_azf3328_playback_open(struct snd_pcm_substream *substream) | ||
1796 | { | ||
1797 | return snd_azf3328_pcm_open(substream, AZF_CODEC_PLAYBACK); | ||
1798 | } | ||
1799 | |||
1800 | static int | ||
1788 | snd_azf3328_capture_open(struct snd_pcm_substream *substream) | 1801 | snd_azf3328_capture_open(struct snd_pcm_substream *substream) |
1789 | { | 1802 | { |
1790 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1803 | return snd_azf3328_pcm_open(substream, AZF_CODEC_CAPTURE); |
1791 | struct snd_pcm_runtime *runtime = substream->runtime; | 1804 | } |
1792 | 1805 | ||
1793 | snd_azf3328_dbgcallenter(); | 1806 | static int |
1794 | chip->audio_stream[AZF_CAPTURE].substream = substream; | 1807 | snd_azf3328_i2s_out_open(struct snd_pcm_substream *substream) |
1795 | runtime->hw = snd_azf3328_capture; | 1808 | { |
1796 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | 1809 | return snd_azf3328_pcm_open(substream, AZF_CODEC_I2S_OUT); |
1797 | &snd_azf3328_hw_constraints_rates); | ||
1798 | snd_azf3328_dbgcallleave(); | ||
1799 | return 0; | ||
1800 | } | 1810 | } |
1801 | 1811 | ||
1802 | static int | 1812 | static int |
1803 | snd_azf3328_playback_close(struct snd_pcm_substream *substream) | 1813 | snd_azf3328_pcm_close(struct snd_pcm_substream *substream, |
1814 | enum snd_azf3328_codec_type codec_type | ||
1815 | ) | ||
1804 | { | 1816 | { |
1805 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1817 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); |
1806 | 1818 | ||
1807 | snd_azf3328_dbgcallenter(); | 1819 | snd_azf3328_dbgcallenter(); |
1808 | chip->audio_stream[AZF_PLAYBACK].substream = NULL; | 1820 | chip->codecs[codec_type].substream = NULL; |
1809 | snd_azf3328_dbgcallleave(); | 1821 | snd_azf3328_dbgcallleave(); |
1810 | return 0; | 1822 | return 0; |
1811 | } | 1823 | } |
1812 | 1824 | ||
1813 | static int | 1825 | static int |
1826 | snd_azf3328_playback_close(struct snd_pcm_substream *substream) | ||
1827 | { | ||
1828 | return snd_azf3328_pcm_close(substream, AZF_CODEC_PLAYBACK); | ||
1829 | } | ||
1830 | |||
1831 | static int | ||
1814 | snd_azf3328_capture_close(struct snd_pcm_substream *substream) | 1832 | snd_azf3328_capture_close(struct snd_pcm_substream *substream) |
1815 | { | 1833 | { |
1816 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1834 | return snd_azf3328_pcm_close(substream, AZF_CODEC_CAPTURE); |
1835 | } | ||
1817 | 1836 | ||
1818 | snd_azf3328_dbgcallenter(); | 1837 | static int |
1819 | chip->audio_stream[AZF_CAPTURE].substream = NULL; | 1838 | snd_azf3328_i2s_out_close(struct snd_pcm_substream *substream) |
1820 | snd_azf3328_dbgcallleave(); | 1839 | { |
1821 | return 0; | 1840 | return snd_azf3328_pcm_close(substream, AZF_CODEC_I2S_OUT); |
1822 | } | 1841 | } |
1823 | 1842 | ||
1824 | /******************************************************************/ | 1843 | /******************************************************************/ |
@@ -1829,9 +1848,9 @@ static struct snd_pcm_ops snd_azf3328_playback_ops = { | |||
1829 | .ioctl = snd_pcm_lib_ioctl, | 1848 | .ioctl = snd_pcm_lib_ioctl, |
1830 | .hw_params = snd_azf3328_hw_params, | 1849 | .hw_params = snd_azf3328_hw_params, |
1831 | .hw_free = snd_azf3328_hw_free, | 1850 | .hw_free = snd_azf3328_hw_free, |
1832 | .prepare = snd_azf3328_playback_prepare, | 1851 | .prepare = snd_azf3328_codec_prepare, |
1833 | .trigger = snd_azf3328_playback_trigger, | 1852 | .trigger = snd_azf3328_codec_playback_trigger, |
1834 | .pointer = snd_azf3328_playback_pointer | 1853 | .pointer = snd_azf3328_codec_playback_pointer |
1835 | }; | 1854 | }; |
1836 | 1855 | ||
1837 | static struct snd_pcm_ops snd_azf3328_capture_ops = { | 1856 | static struct snd_pcm_ops snd_azf3328_capture_ops = { |
@@ -1840,30 +1859,67 @@ static struct snd_pcm_ops snd_azf3328_capture_ops = { | |||
1840 | .ioctl = snd_pcm_lib_ioctl, | 1859 | .ioctl = snd_pcm_lib_ioctl, |
1841 | .hw_params = snd_azf3328_hw_params, | 1860 | .hw_params = snd_azf3328_hw_params, |
1842 | .hw_free = snd_azf3328_hw_free, | 1861 | .hw_free = snd_azf3328_hw_free, |
1843 | .prepare = snd_azf3328_capture_prepare, | 1862 | .prepare = snd_azf3328_codec_prepare, |
1844 | .trigger = snd_azf3328_capture_trigger, | 1863 | .trigger = snd_azf3328_codec_capture_trigger, |
1845 | .pointer = snd_azf3328_capture_pointer | 1864 | .pointer = snd_azf3328_codec_capture_pointer |
1865 | }; | ||
1866 | |||
1867 | static struct snd_pcm_ops snd_azf3328_i2s_out_ops = { | ||
1868 | .open = snd_azf3328_i2s_out_open, | ||
1869 | .close = snd_azf3328_i2s_out_close, | ||
1870 | .ioctl = snd_pcm_lib_ioctl, | ||
1871 | .hw_params = snd_azf3328_hw_params, | ||
1872 | .hw_free = snd_azf3328_hw_free, | ||
1873 | .prepare = snd_azf3328_codec_prepare, | ||
1874 | .trigger = snd_azf3328_codec_i2s_out_trigger, | ||
1875 | .pointer = snd_azf3328_codec_i2s_out_pointer | ||
1846 | }; | 1876 | }; |
1847 | 1877 | ||
1848 | static int __devinit | 1878 | static int __devinit |
1849 | snd_azf3328_pcm(struct snd_azf3328 *chip, int device) | 1879 | snd_azf3328_pcm(struct snd_azf3328 *chip) |
1850 | { | 1880 | { |
1881 | enum { AZF_PCMDEV_STD, AZF_PCMDEV_I2S_OUT, NUM_AZF_PCMDEVS }; /* pcm devices */ | ||
1882 | |||
1851 | struct snd_pcm *pcm; | 1883 | struct snd_pcm *pcm; |
1852 | int err; | 1884 | int err; |
1853 | 1885 | ||
1854 | snd_azf3328_dbgcallenter(); | 1886 | snd_azf3328_dbgcallenter(); |
1855 | if ((err = snd_pcm_new(chip->card, "AZF3328 DSP", device, 1, 1, &pcm)) < 0) | 1887 | |
1888 | err = snd_pcm_new(chip->card, "AZF3328 DSP", AZF_PCMDEV_STD, | ||
1889 | 1, 1, &pcm); | ||
1890 | if (err < 0) | ||
1856 | return err; | 1891 | return err; |
1857 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_azf3328_playback_ops); | 1892 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, |
1858 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_azf3328_capture_ops); | 1893 | &snd_azf3328_playback_ops); |
1894 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, | ||
1895 | &snd_azf3328_capture_ops); | ||
1859 | 1896 | ||
1860 | pcm->private_data = chip; | 1897 | pcm->private_data = chip; |
1861 | pcm->info_flags = 0; | 1898 | pcm->info_flags = 0; |
1862 | strcpy(pcm->name, chip->card->shortname); | 1899 | strcpy(pcm->name, chip->card->shortname); |
1863 | chip->pcm = pcm; | 1900 | /* same pcm object for playback/capture (see snd_pcm_new() above) */ |
1901 | chip->pcm[AZF_CODEC_PLAYBACK] = pcm; | ||
1902 | chip->pcm[AZF_CODEC_CAPTURE] = pcm; | ||
1864 | 1903 | ||
1865 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | 1904 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, |
1866 | snd_dma_pci_data(chip->pci), 64*1024, 64*1024); | 1905 | snd_dma_pci_data(chip->pci), |
1906 | 64*1024, 64*1024); | ||
1907 | |||
1908 | err = snd_pcm_new(chip->card, "AZF3328 I2S OUT", AZF_PCMDEV_I2S_OUT, | ||
1909 | 1, 0, &pcm); | ||
1910 | if (err < 0) | ||
1911 | return err; | ||
1912 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, | ||
1913 | &snd_azf3328_i2s_out_ops); | ||
1914 | |||
1915 | pcm->private_data = chip; | ||
1916 | pcm->info_flags = 0; | ||
1917 | strcpy(pcm->name, chip->card->shortname); | ||
1918 | chip->pcm[AZF_CODEC_I2S_OUT] = pcm; | ||
1919 | |||
1920 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | ||
1921 | snd_dma_pci_data(chip->pci), | ||
1922 | 64*1024, 64*1024); | ||
1867 | 1923 | ||
1868 | snd_azf3328_dbgcallleave(); | 1924 | snd_azf3328_dbgcallleave(); |
1869 | return 0; | 1925 | return 0; |
@@ -1902,7 +1958,7 @@ snd_azf3328_timer_start(struct snd_timer *timer) | |||
1902 | snd_azf3328_dbgtimer("setting timer countdown value %d, add COUNTDOWN|IRQ\n", delay); | 1958 | snd_azf3328_dbgtimer("setting timer countdown value %d, add COUNTDOWN|IRQ\n", delay); |
1903 | delay |= TIMER_COUNTDOWN_ENABLE | TIMER_IRQ_ENABLE; | 1959 | delay |= TIMER_COUNTDOWN_ENABLE | TIMER_IRQ_ENABLE; |
1904 | spin_lock_irqsave(&chip->reg_lock, flags); | 1960 | spin_lock_irqsave(&chip->reg_lock, flags); |
1905 | snd_azf3328_codec_outl(chip, IDX_IO_TIMER_VALUE, delay); | 1961 | snd_azf3328_ctrl_outl(chip, IDX_IO_TIMER_VALUE, delay); |
1906 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 1962 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
1907 | snd_azf3328_dbgcallleave(); | 1963 | snd_azf3328_dbgcallleave(); |
1908 | return 0; | 1964 | return 0; |
@@ -1919,7 +1975,7 @@ snd_azf3328_timer_stop(struct snd_timer *timer) | |||
1919 | spin_lock_irqsave(&chip->reg_lock, flags); | 1975 | spin_lock_irqsave(&chip->reg_lock, flags); |
1920 | /* disable timer countdown and interrupt */ | 1976 | /* disable timer countdown and interrupt */ |
1921 | /* FIXME: should we write TIMER_IRQ_ACK here? */ | 1977 | /* FIXME: should we write TIMER_IRQ_ACK here? */ |
1922 | snd_azf3328_codec_outb(chip, IDX_IO_TIMER_VALUE + 3, 0); | 1978 | snd_azf3328_ctrl_outb(chip, IDX_IO_TIMER_VALUE + 3, 0); |
1923 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 1979 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
1924 | snd_azf3328_dbgcallleave(); | 1980 | snd_azf3328_dbgcallleave(); |
1925 | return 0; | 1981 | return 0; |
@@ -2048,9 +2104,9 @@ snd_azf3328_debug_show_ports(const struct snd_azf3328 *chip) | |||
2048 | u16 tmp; | 2104 | u16 tmp; |
2049 | 2105 | ||
2050 | snd_azf3328_dbgmisc( | 2106 | snd_azf3328_dbgmisc( |
2051 | "codec_io 0x%lx, game_io 0x%lx, mpu_io 0x%lx, " | 2107 | "ctrl_io 0x%lx, game_io 0x%lx, mpu_io 0x%lx, " |
2052 | "opl3_io 0x%lx, mixer_io 0x%lx, irq %d\n", | 2108 | "opl3_io 0x%lx, mixer_io 0x%lx, irq %d\n", |
2053 | chip->codec_io, chip->game_io, chip->mpu_io, | 2109 | chip->ctrl_io, chip->game_io, chip->mpu_io, |
2054 | chip->opl3_io, chip->mixer_io, chip->irq | 2110 | chip->opl3_io, chip->mixer_io, chip->irq |
2055 | ); | 2111 | ); |
2056 | 2112 | ||
@@ -2083,9 +2139,9 @@ snd_azf3328_debug_show_ports(const struct snd_azf3328 *chip) | |||
2083 | inb(0x38c + tmp) | 2139 | inb(0x38c + tmp) |
2084 | ); | 2140 | ); |
2085 | 2141 | ||
2086 | for (tmp = 0; tmp < AZF_IO_SIZE_CODEC; tmp += 2) | 2142 | for (tmp = 0; tmp < AZF_IO_SIZE_CTRL; tmp += 2) |
2087 | snd_azf3328_dbgmisc("codec 0x%02x: 0x%04x\n", | 2143 | snd_azf3328_dbgmisc("ctrl 0x%02x: 0x%04x\n", |
2088 | tmp, snd_azf3328_codec_inw(chip, tmp) | 2144 | tmp, snd_azf3328_ctrl_inw(chip, tmp) |
2089 | ); | 2145 | ); |
2090 | 2146 | ||
2091 | for (tmp = 0; tmp < AZF_IO_SIZE_MIXER; tmp += 2) | 2147 | for (tmp = 0; tmp < AZF_IO_SIZE_MIXER; tmp += 2) |
@@ -2106,7 +2162,8 @@ snd_azf3328_create(struct snd_card *card, | |||
2106 | static struct snd_device_ops ops = { | 2162 | static struct snd_device_ops ops = { |
2107 | .dev_free = snd_azf3328_dev_free, | 2163 | .dev_free = snd_azf3328_dev_free, |
2108 | }; | 2164 | }; |
2109 | u16 tmp; | 2165 | u8 dma_init; |
2166 | enum snd_azf3328_codec_type codec_type; | ||
2110 | 2167 | ||
2111 | *rchip = NULL; | 2168 | *rchip = NULL; |
2112 | 2169 | ||
@@ -2138,14 +2195,21 @@ snd_azf3328_create(struct snd_card *card, | |||
2138 | if (err < 0) | 2195 | if (err < 0) |
2139 | goto out_err; | 2196 | goto out_err; |
2140 | 2197 | ||
2141 | chip->codec_io = pci_resource_start(pci, 0); | 2198 | chip->ctrl_io = pci_resource_start(pci, 0); |
2142 | chip->game_io = pci_resource_start(pci, 1); | 2199 | chip->game_io = pci_resource_start(pci, 1); |
2143 | chip->mpu_io = pci_resource_start(pci, 2); | 2200 | chip->mpu_io = pci_resource_start(pci, 2); |
2144 | chip->opl3_io = pci_resource_start(pci, 3); | 2201 | chip->opl3_io = pci_resource_start(pci, 3); |
2145 | chip->mixer_io = pci_resource_start(pci, 4); | 2202 | chip->mixer_io = pci_resource_start(pci, 4); |
2146 | 2203 | ||
2147 | chip->audio_stream[AZF_PLAYBACK].portbase = chip->codec_io + 0x00; | 2204 | chip->codecs[AZF_CODEC_PLAYBACK].io_base = |
2148 | chip->audio_stream[AZF_CAPTURE].portbase = chip->codec_io + 0x20; | 2205 | chip->ctrl_io + AZF_IO_OFFS_CODEC_PLAYBACK; |
2206 | chip->codecs[AZF_CODEC_PLAYBACK].name = "PLAYBACK"; | ||
2207 | chip->codecs[AZF_CODEC_CAPTURE].io_base = | ||
2208 | chip->ctrl_io + AZF_IO_OFFS_CODEC_CAPTURE; | ||
2209 | chip->codecs[AZF_CODEC_CAPTURE].name = "CAPTURE"; | ||
2210 | chip->codecs[AZF_CODEC_I2S_OUT].io_base = | ||
2211 | chip->ctrl_io + AZF_IO_OFFS_CODEC_I2S_OUT; | ||
2212 | chip->codecs[AZF_CODEC_I2S_OUT].name = "I2S_OUT"; | ||
2149 | 2213 | ||
2150 | if (request_irq(pci->irq, snd_azf3328_interrupt, | 2214 | if (request_irq(pci->irq, snd_azf3328_interrupt, |
2151 | IRQF_SHARED, card->shortname, chip)) { | 2215 | IRQF_SHARED, card->shortname, chip)) { |
@@ -2168,20 +2232,25 @@ snd_azf3328_create(struct snd_card *card, | |||
2168 | if (err < 0) | 2232 | if (err < 0) |
2169 | goto out_err; | 2233 | goto out_err; |
2170 | 2234 | ||
2171 | /* shutdown codecs to save power */ | 2235 | /* standard codec init stuff */ |
2172 | /* have snd_azf3328_codec_activity() act properly */ | 2236 | /* default DMA init value */ |
2173 | chip->audio_stream[AZF_PLAYBACK].running = 1; | 2237 | dma_init = DMA_RUN_SOMETHING2|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE; |
2174 | snd_azf3328_codec_activity(chip, AZF_PLAYBACK, 0); | 2238 | |
2239 | for (codec_type = AZF_CODEC_PLAYBACK; | ||
2240 | codec_type <= AZF_CODEC_I2S_OUT; ++codec_type) { | ||
2241 | struct snd_azf3328_codec_data *codec = | ||
2242 | &chip->codecs[codec_type]; | ||
2175 | 2243 | ||
2176 | /* standard chip init stuff */ | 2244 | /* shutdown codecs to save power */ |
2177 | /* default IRQ init value */ | 2245 | /* have ...ctrl_codec_activity() act properly */ |
2178 | tmp = DMA_PLAY_SOMETHING2|DMA_EPILOGUE_SOMETHING|DMA_SOMETHING_ELSE; | 2246 | codec->running = 1; |
2247 | snd_azf3328_ctrl_codec_activity(chip, codec_type, 0); | ||
2179 | 2248 | ||
2180 | spin_lock_irq(&chip->reg_lock); | 2249 | spin_lock_irq(&chip->reg_lock); |
2181 | snd_azf3328_codec_outb(chip, IDX_IO_PLAY_FLAGS, tmp); | 2250 | snd_azf3328_codec_outb(codec, IDX_IO_CODEC_DMA_FLAGS, |
2182 | snd_azf3328_codec_outb(chip, IDX_IO_REC_FLAGS, tmp); | 2251 | dma_init); |
2183 | snd_azf3328_codec_outb(chip, IDX_IO_SOMETHING_FLAGS, tmp); | 2252 | spin_unlock_irq(&chip->reg_lock); |
2184 | spin_unlock_irq(&chip->reg_lock); | 2253 | } |
2185 | 2254 | ||
2186 | snd_card_set_dev(card, &pci->dev); | 2255 | snd_card_set_dev(card, &pci->dev); |
2187 | 2256 | ||
@@ -2244,7 +2313,7 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) | |||
2244 | if (err < 0) | 2313 | if (err < 0) |
2245 | goto out_err; | 2314 | goto out_err; |
2246 | 2315 | ||
2247 | err = snd_azf3328_pcm(chip, 0); | 2316 | err = snd_azf3328_pcm(chip); |
2248 | if (err < 0) | 2317 | if (err < 0) |
2249 | goto out_err; | 2318 | goto out_err; |
2250 | 2319 | ||
@@ -2266,7 +2335,7 @@ snd_azf3328_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) | |||
2266 | opl3->private_data = chip; | 2335 | opl3->private_data = chip; |
2267 | 2336 | ||
2268 | sprintf(card->longname, "%s at 0x%lx, irq %i", | 2337 | sprintf(card->longname, "%s at 0x%lx, irq %i", |
2269 | card->shortname, chip->codec_io, chip->irq); | 2338 | card->shortname, chip->ctrl_io, chip->irq); |
2270 | 2339 | ||
2271 | err = snd_card_register(card); | 2340 | err = snd_card_register(card); |
2272 | if (err < 0) | 2341 | if (err < 0) |
@@ -2317,7 +2386,8 @@ snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state) | |||
2317 | 2386 | ||
2318 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); | 2387 | snd_power_change_state(card, SNDRV_CTL_POWER_D3hot); |
2319 | 2388 | ||
2320 | snd_pcm_suspend_all(chip->pcm); | 2389 | snd_pcm_suspend_all(chip->pcm[AZF_CODEC_PLAYBACK]); |
2390 | snd_pcm_suspend_all(chip->pcm[AZF_CODEC_I2S_OUT]); | ||
2321 | 2391 | ||
2322 | for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; ++reg) | 2392 | for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; ++reg) |
2323 | chip->saved_regs_mixer[reg] = inw(chip->mixer_io + reg * 2); | 2393 | chip->saved_regs_mixer[reg] = inw(chip->mixer_io + reg * 2); |
@@ -2326,11 +2396,11 @@ snd_azf3328_suspend(struct pci_dev *pci, pm_message_t state) | |||
2326 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); | 2396 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_PLAY_MASTER, 1); |
2327 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); | 2397 | snd_azf3328_mixer_set_mute(chip, IDX_MIXER_WAVEOUT, 1); |
2328 | 2398 | ||
2329 | for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; ++reg) | 2399 | for (reg = 0; reg < AZF_IO_SIZE_CTRL_PM / 2; ++reg) |
2330 | chip->saved_regs_codec[reg] = inw(chip->codec_io + reg * 2); | 2400 | chip->saved_regs_ctrl[reg] = inw(chip->ctrl_io + reg * 2); |
2331 | 2401 | ||
2332 | /* manually store the one currently relevant write-only reg, too */ | 2402 | /* manually store the one currently relevant write-only reg, too */ |
2333 | chip->saved_regs_codec[IDX_IO_6AH / 2] = chip->shadow_reg_codec_6AH; | 2403 | chip->saved_regs_ctrl[IDX_IO_6AH / 2] = chip->shadow_reg_ctrl_6AH; |
2334 | 2404 | ||
2335 | for (reg = 0; reg < AZF_IO_SIZE_GAME_PM / 2; ++reg) | 2405 | for (reg = 0; reg < AZF_IO_SIZE_GAME_PM / 2; ++reg) |
2336 | chip->saved_regs_game[reg] = inw(chip->game_io + reg * 2); | 2406 | chip->saved_regs_game[reg] = inw(chip->game_io + reg * 2); |
@@ -2349,7 +2419,7 @@ static int | |||
2349 | snd_azf3328_resume(struct pci_dev *pci) | 2419 | snd_azf3328_resume(struct pci_dev *pci) |
2350 | { | 2420 | { |
2351 | struct snd_card *card = pci_get_drvdata(pci); | 2421 | struct snd_card *card = pci_get_drvdata(pci); |
2352 | struct snd_azf3328 *chip = card->private_data; | 2422 | const struct snd_azf3328 *chip = card->private_data; |
2353 | unsigned reg; | 2423 | unsigned reg; |
2354 | 2424 | ||
2355 | pci_set_power_state(pci, PCI_D0); | 2425 | pci_set_power_state(pci, PCI_D0); |
@@ -2370,8 +2440,8 @@ snd_azf3328_resume(struct pci_dev *pci) | |||
2370 | outw(chip->saved_regs_opl3[reg], chip->opl3_io + reg * 2); | 2440 | outw(chip->saved_regs_opl3[reg], chip->opl3_io + reg * 2); |
2371 | for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; ++reg) | 2441 | for (reg = 0; reg < AZF_IO_SIZE_MIXER_PM / 2; ++reg) |
2372 | outw(chip->saved_regs_mixer[reg], chip->mixer_io + reg * 2); | 2442 | outw(chip->saved_regs_mixer[reg], chip->mixer_io + reg * 2); |
2373 | for (reg = 0; reg < AZF_IO_SIZE_CODEC_PM / 2; ++reg) | 2443 | for (reg = 0; reg < AZF_IO_SIZE_CTRL_PM / 2; ++reg) |
2374 | outw(chip->saved_regs_codec[reg], chip->codec_io + reg * 2); | 2444 | outw(chip->saved_regs_ctrl[reg], chip->ctrl_io + reg * 2); |
2375 | 2445 | ||
2376 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); | 2446 | snd_power_change_state(card, SNDRV_CTL_POWER_D0); |
2377 | return 0; | 2447 | return 0; |