diff options
author | Andreas Mohr <andi@lisas.de> | 2009-07-05 07:55:46 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-07-06 02:24:47 -0400 |
commit | dfbf9511155d3584b8747c935216077f46eb9a4f (patch) | |
tree | 0591d571c38dd032eff9c2ca41ab1c34e19aa4f8 /sound/pci/azt3328.c | |
parent | 3eff8958308ed875a4e845d59a498288f8bbad77 (diff) |
ALSA: azt3328: large codec cleanup, add I2S port etc.
- fully separate codec I/O port handling, enabling the use of a single
function each for all codecs (playback, capture, I2S out)
- add a new separate pcm for I2S out port (UNTESTED, no I2S DAC
available yet)
- switch gameport to low frequency while idle, to try to reduce noise/power
- improve snd_azf3328_codec_setdmaa() calculation
- minor variable type cleanup (u16, bool etc.)
- add some doc updates (help those lost Windows users, debug help, ...)
Note that due to the large cleanup aspect of the codec I/O change,
I was able to fit everything including all improvements into the
same binary size!! (a measly 10 bytes more or so)
This should now be the almost last patch to this driver
(minus some possible kernel clocksource patch and x86_64 fixes or so).
I just felt like taking a break from the usual stuff and wanted to
get this driver's structure finished, and it's rather clean now...
Tested, working and checkpatch.pl:ed on 2.6.30-rc5,
applies cleanly to 2.6.30 proper.
Signed-off-by: Andreas Mohr <andi@lisas.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
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; |