diff options
author | Andreas Mohr <andi@lisas.de> | 2008-05-16 06:18:29 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2008-05-19 07:19:19 -0400 |
commit | 02330fbaaded5b603cba112e4bbf62cdadec159a (patch) | |
tree | 90895cb270106d00bbc30a3f15afe91d07795ee3 /sound/pci/azt3328.h | |
parent | f99a633a151686a599413bef758253dfd04887d1 (diff) |
[ALSA] PCI168 snd-azt3328 Linux driver: another huge update
- figured out 'Digital(ly) Enhanced Game Port' functionality,
implemented support for it (eliminating gameport polling overhead)
- removed optional joystick activation, gameport now enabled unconditionally,
since we now support it via the PCI I/O space, not via conflict-prone
legacy I/O (which I was thus able to DISABLE now)!
- fix playback bug (a muted wave output would get unmuted upon start of
playback, of course this is not what we want, thus remember mute state)
- implement partial power management: when idle, lower clock rate and disable
codec (reduced noise!), and disable gameport circuit when unused
- instantiate OPL3 timer, too
- much better implementation of snd_azf3328_mixer_write_volume_gradually()
- slightly optimized interrupt handling
- lots of cleanup
This time, I also found a way to verify proper OPL3 operation
via MIDI file playback (emulation via synth hardware).
Signed-off-by: Andreas Mohr <andi@lisas.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound/pci/azt3328.h')
-rw-r--r-- | sound/pci/azt3328.h | 197 |
1 files changed, 172 insertions, 25 deletions
diff --git a/sound/pci/azt3328.h b/sound/pci/azt3328.h index 679fa992e2bc..3448fd626f80 100644 --- a/sound/pci/azt3328.h +++ b/sound/pci/azt3328.h | |||
@@ -54,7 +54,10 @@ | |||
54 | #define SOUNDFORMAT_XTAL1 0x00 | 54 | #define SOUNDFORMAT_XTAL1 0x00 |
55 | #define SOUNDFORMAT_XTAL2 0x01 | 55 | #define SOUNDFORMAT_XTAL2 0x01 |
56 | /* all _SUSPECTED_ values are not used by Windows drivers, so we don't | 56 | /* all _SUSPECTED_ values are not used by Windows drivers, so we don't |
57 | * have any hard facts, only rough measurements */ | 57 | * have any hard facts, only rough measurements. |
58 | * All we know is that the crystal used on the board has 24.576MHz, | ||
59 | * like many soundcards (which results in the frequencies below when | ||
60 | * using certain divider values selected by the values below) */ | ||
58 | #define SOUNDFORMAT_FREQ_SUSPECTED_4000 0x0c | SOUNDFORMAT_XTAL1 | 61 | #define SOUNDFORMAT_FREQ_SUSPECTED_4000 0x0c | SOUNDFORMAT_XTAL1 |
59 | #define SOUNDFORMAT_FREQ_SUSPECTED_4800 0x0a | SOUNDFORMAT_XTAL1 | 62 | #define SOUNDFORMAT_FREQ_SUSPECTED_4800 0x0a | SOUNDFORMAT_XTAL1 |
60 | #define SOUNDFORMAT_FREQ_5510 0x0c | SOUNDFORMAT_XTAL2 | 63 | #define SOUNDFORMAT_FREQ_5510 0x0c | SOUNDFORMAT_XTAL2 |
@@ -72,6 +75,26 @@ | |||
72 | #define SOUNDFORMAT_FLAG_16BIT 0x0010 | 75 | #define SOUNDFORMAT_FLAG_16BIT 0x0010 |
73 | #define SOUNDFORMAT_FLAG_2CHANNELS 0x0020 | 76 | #define SOUNDFORMAT_FLAG_2CHANNELS 0x0020 |
74 | 77 | ||
78 | /* define frequency helpers, for maximum value safety */ | ||
79 | enum { | ||
80 | #define AZF_FREQ(rate) AZF_FREQ_##rate = rate | ||
81 | AZF_FREQ(4000), | ||
82 | AZF_FREQ(4800), | ||
83 | AZF_FREQ(5512), | ||
84 | AZF_FREQ(6620), | ||
85 | AZF_FREQ(8000), | ||
86 | AZF_FREQ(9600), | ||
87 | AZF_FREQ(11025), | ||
88 | AZF_FREQ(13240), | ||
89 | AZF_FREQ(16000), | ||
90 | AZF_FREQ(22050), | ||
91 | AZF_FREQ(32000), | ||
92 | AZF_FREQ(44100), | ||
93 | AZF_FREQ(48000), | ||
94 | AZF_FREQ(66200), | ||
95 | #undef AZF_FREQ | ||
96 | } AZF_FREQUENCIES; | ||
97 | |||
75 | /** recording area (see also: playback bit flag definitions) **/ | 98 | /** recording area (see also: playback bit flag definitions) **/ |
76 | #define IDX_IO_REC_FLAGS 0x20 /* ??, PU:0x0000 */ | 99 | #define IDX_IO_REC_FLAGS 0x20 /* ??, PU:0x0000 */ |
77 | #define IDX_IO_REC_IRQTYPE 0x22 /* ??, PU:0x0000 */ | 100 | #define IDX_IO_REC_IRQTYPE 0x22 /* ??, PU:0x0000 */ |
@@ -97,40 +120,164 @@ | |||
97 | 120 | ||
98 | /** DirectX timer, main interrupt area (FIXME: and something else?) **/ | 121 | /** DirectX timer, main interrupt area (FIXME: and something else?) **/ |
99 | #define IDX_IO_TIMER_VALUE 0x60 /* found this timer area by pure luck :-) */ | 122 | #define IDX_IO_TIMER_VALUE 0x60 /* found this timer area by pure luck :-) */ |
100 | #define TIMER_VALUE_MASK 0x000fffffUL /* timer countdown value; triggers IRQ when timer is finished */ | 123 | /* timer countdown value; triggers IRQ when timer is finished */ |
101 | #define TIMER_ENABLE_COUNTDOWN 0x01000000UL /* activate the timer countdown */ | 124 | #define TIMER_VALUE_MASK 0x000fffffUL |
102 | #define TIMER_ENABLE_IRQ 0x02000000UL /* trigger timer IRQ on zero transition */ | 125 | /* activate timer countdown */ |
103 | #define TIMER_ACK_IRQ 0x04000000UL /* being set in IRQ handler in case port 0x00 (hmm, not port 0x64!?!?) had 0x0020 set upon IRQ handler */ | 126 | #define TIMER_COUNTDOWN_ENABLE 0x01000000UL |
127 | /* trigger timer IRQ on zero transition */ | ||
128 | #define TIMER_IRQ_ENABLE 0x02000000UL | ||
129 | /* being set in IRQ handler in case port 0x00 (hmm, not port 0x64!?!?) | ||
130 | * had 0x0020 set upon IRQ handler */ | ||
131 | #define TIMER_IRQ_ACK 0x04000000UL | ||
104 | #define IDX_IO_IRQSTATUS 0x64 | 132 | #define IDX_IO_IRQSTATUS 0x64 |
105 | #define IRQ_PLAYBACK 0x0001 | 133 | /* some IRQ bit in here might also be used to signal a power-management timer |
106 | #define IRQ_RECORDING 0x0002 | 134 | * timeout, to request shutdown of the chip (e.g. AD1815JS has such a thing). |
107 | #define IRQ_MPU401 0x0010 | 135 | * Some OPL3 hardware (e.g. in LM4560) has some special timer hardware which |
108 | #define IRQ_TIMER 0x0020 /* DirectX timer */ | 136 | * can trigger an OPL3 timer IRQ, so maybe there's such a thing as well... */ |
109 | #define IRQ_UNKNOWN1 0x0040 /* probably unused, or possibly I2S port? or gameport IRQ? */ | 137 | |
110 | #define IRQ_UNKNOWN2 0x0080 /* probably unused, or possibly I2S port? or gameport IRQ? */ | 138 | #define IRQ_PLAYBACK 0x0001 |
139 | #define IRQ_RECORDING 0x0002 | ||
140 | #define IRQ_UNKNOWN1 0x0004 /* most probably I2S port */ | ||
141 | #define IRQ_GAMEPORT 0x0008 /* Interrupt of Digital(ly) Enhanced Game Port */ | ||
142 | #define IRQ_MPU401 0x0010 | ||
143 | #define IRQ_TIMER 0x0020 /* DirectX timer */ | ||
144 | #define IRQ_UNKNOWN2 0x0040 /* probably unused, or possibly I2S port? */ | ||
145 | #define IRQ_UNKNOWN3 0x0080 /* probably unused, or possibly I2S port? */ | ||
111 | #define IDX_IO_66H 0x66 /* writing 0xffff returns 0x0000 */ | 146 | #define IDX_IO_66H 0x66 /* writing 0xffff returns 0x0000 */ |
112 | #define IDX_IO_SOME_VALUE 0x68 /* this is set to e.g. 0x3ff or 0x300, and writable; maybe some buffer limit, but I couldn't find out more, PU:0x00ff */ | 147 | /* this is set to e.g. 0x3ff or 0x300, and writable; |
113 | #define IDX_IO_6AH 0x6A /* this WORD can be set to have bits 0x0028 activated (FIXME: correct??); actually inhibits PCM playback!!! maybe power management?? */ | 148 | * maybe some buffer limit, but I couldn't find out more, PU:0x00ff: */ |
114 | #define IO_6A_PAUSE_PLAYBACK 0x0200 /* bit 9; sure, this pauses playback, but what the heck is this really about?? */ | 149 | #define IDX_IO_SOME_VALUE 0x68 |
115 | #define IDX_IO_6CH 0x6C | 150 | #define IO_68_RANDOM_TOGGLE1 0x0100 /* toggles randomly */ |
116 | #define IDX_IO_6EH 0x6E /* writing 0xffff returns 0x83fe */ | 151 | #define IO_68_RANDOM_TOGGLE2 0x0200 /* toggles randomly */ |
117 | /* further I/O indices not saved/restored, so probably not used */ | 152 | /* umm, nope, behaviour of these bits changes depending on what we wrote |
153 | * to 0x6b!! */ | ||
154 | |||
155 | /* this WORD can be set to have bits 0x0028 activated (FIXME: correct??); | ||
156 | * actually inhibits PCM playback!!! maybe power management??: */ | ||
157 | #define IDX_IO_6AH 0x6A | ||
158 | /* bit 5: enabling this will activate permanent counting of bytes 2/3 | ||
159 | * at gameport I/O (0xb402/3) (equal values each) and cause | ||
160 | * gameport legacy I/O at 0x0200 to be _DISABLED_! | ||
161 | * Is this Digital Enhanced Game Port Enable??? Or maybe it's Testmode | ||
162 | * for Enhanced Digital Gameport (see 4D Wave DX card): */ | ||
163 | #define IO_6A_SOMETHING1_GAMEPORT 0x0020 | ||
164 | /* bit 8; sure, this _pauses_ playback (later resumes at same spot!), | ||
165 | * but what the heck is this really about??: */ | ||
166 | #define IO_6A_PAUSE_PLAYBACK_BIT8 0x0100 | ||
167 | /* bit 9; sure, this _pauses_ playback (later resumes at same spot!), | ||
168 | * but what the heck is this really about??: */ | ||
169 | #define IO_6A_PAUSE_PLAYBACK_BIT9 0x0200 | ||
170 | /* BIT8 and BIT9 are _NOT_ able to affect OPL3 MIDI playback, | ||
171 | * thus it suggests influence on PCM only!! | ||
172 | * However OTOH there seems to be no bit anywhere around here | ||
173 | * which is able to disable OPL3... */ | ||
174 | /* bit 10: enabling this actually changes values at legacy gameport | ||
175 | * I/O address (0x200); is this enabling of the Digital Enhanced Game Port??? | ||
176 | * Or maybe this simply switches off the NE558 circuit, since enabling this | ||
177 | * still lets us evaluate button states, but not axis states */ | ||
178 | #define IO_6A_SOMETHING2_GAMEPORT 0x0400 | ||
179 | /* writing 0x0300: causes quite some crackling during | ||
180 | * PC activity such as switching windows (PCI traffic?? | ||
181 | * --> FIFO/timing settings???) */ | ||
182 | /* writing 0x0100 plus/or 0x0200 inhibits playback */ | ||
183 | /* since the Windows .INF file has Flag_Enable_JoyStick and | ||
184 | * Flag_Enable_SB_DOS_Emulation directly together, it stands to reason | ||
185 | * that some other bit in this same register might be responsible | ||
186 | * for SB DOS Emulation activation (note that the file did NOT define | ||
187 | * a switch for OPL3!) */ | ||
188 | #define IDX_IO_6CH 0x6C /* unknown; fully read-writable */ | ||
189 | #define IDX_IO_6EH 0x6E | ||
190 | /* writing 0xffff returns 0x83fe (or 0x03fe only). | ||
191 | * writing 0x83 (and only 0x83!!) to 0x6f will cause 0x6c to switch | ||
192 | * from 0000 to ffff. */ | ||
118 | 193 | ||
194 | /* further I/O indices not saved/restored and not readable after writing, | ||
195 | * so probably not used */ | ||
119 | 196 | ||
120 | /*** I/O 2 area port indices ***/ | 197 | |
198 | /*** Gameport area port indices ***/ | ||
121 | /* (only 0x06 of 0x08 bytes saved/restored by Windows driver) */ | 199 | /* (only 0x06 of 0x08 bytes saved/restored by Windows driver) */ |
122 | #define AZF_IO_SIZE_IO2 0x08 | 200 | #define AZF_IO_SIZE_GAME 0x08 |
123 | #define AZF_IO_SIZE_IO2_PM 0x06 | 201 | #define AZF_IO_SIZE_GAME_PM 0x06 |
202 | |||
203 | enum { | ||
204 | AZF_GAME_LEGACY_IO_PORT = 0x200 | ||
205 | } AZF_GAME_CONFIGS; | ||
206 | |||
207 | #define IDX_GAME_LEGACY_COMPATIBLE 0x00 | ||
208 | /* in some operation mode, writing anything to this port | ||
209 | * triggers an interrupt: | ||
210 | * yup, that's in case IDX_GAME_01H has one of the | ||
211 | * axis measurement bits enabled | ||
212 | * (and of course one needs to have GAME_HWCFG_IRQ_ENABLE, too) */ | ||
213 | |||
214 | #define IDX_GAME_AXES_CONFIG 0x01 | ||
215 | /* NOTE: layout of this register awfully similar (read: "identical??") | ||
216 | * to AD1815JS.pdf (p.29) */ | ||
217 | |||
218 | /* enables axis 1 (X axis) measurement: */ | ||
219 | #define GAME_AXES_ENABLE_1 0x01 | ||
220 | /* enables axis 2 (Y axis) measurement: */ | ||
221 | #define GAME_AXES_ENABLE_2 0x02 | ||
222 | /* enables axis 3 (X axis) measurement: */ | ||
223 | #define GAME_AXES_ENABLE_3 0x04 | ||
224 | /* enables axis 4 (Y axis) measurement: */ | ||
225 | #define GAME_AXES_ENABLE_4 0x08 | ||
226 | /* selects the current axis to read the measured value of | ||
227 | * (at IDX_GAME_AXIS_VALUE): | ||
228 | * 00 = axis 1, 01 = axis 2, 10 = axis 3, 11 = axis 4: */ | ||
229 | #define GAME_AXES_READ_MASK 0x30 | ||
230 | /* enable to have the latch continuously accept ADC values | ||
231 | * (and continuously cause interrupts in case interrupts are enabled); | ||
232 | * AD1815JS.pdf says it's ~16ms interval there: */ | ||
233 | #define GAME_AXES_LATCH_ENABLE 0x40 | ||
234 | /* joystick data (measured axes) ready for reading: */ | ||
235 | #define GAME_AXES_SAMPLING_READY 0x80 | ||
236 | |||
237 | /* NOTE: other card specs (SiS960 and others!) state that the | ||
238 | * game position latches should be frozen when reading and be freed | ||
239 | * (== reset?) after reading!!! | ||
240 | * Freezing most likely means disabling 0x40 (GAME_AXES_LATCH_ENABLE), | ||
241 | * but how to free the value? */ | ||
242 | /* An internet search for "gameport latch ADC" should provide some insight | ||
243 | * into how to program such a gameport system. */ | ||
244 | |||
245 | /* writing 0xf0 to 01H once reset both counters to 0, in some special mode!? | ||
246 | * yup, in case 6AH 0x20 is not enabled | ||
247 | * (and 0x40 is sufficient, 0xf0 is not needed) */ | ||
248 | |||
249 | #define IDX_GAME_AXIS_VALUE 0x02 | ||
250 | /* R: value of currently configured axis (word value!); | ||
251 | * W: trigger axis measurement */ | ||
252 | |||
253 | #define IDX_GAME_HWCONFIG 0x04 | ||
254 | /* note: bits 4 to 7 are never set (== 0) when reading! | ||
255 | * --> reserved bits? */ | ||
256 | /* enables IRQ notification upon axes measurement ready: */ | ||
257 | #define GAME_HWCFG_IRQ_ENABLE 0x01 | ||
258 | /* these bits choose a different frequency for the | ||
259 | * internal ADC counter increment. | ||
260 | * hmm, seems to be a combo of bits: | ||
261 | * 00 --> standard frequency | ||
262 | * 10 --> 1/2 | ||
263 | * 01 --> 1/20 | ||
264 | * 11 --> 1/200: */ | ||
265 | #define GAME_HWCFG_ADC_COUNTER_FREQ_MASK 0x06 | ||
124 | 266 | ||
125 | #define IDX_IO2_LEGACY_ADDR 0x04 | 267 | /* enable gameport legacy I/O address (0x200) |
126 | #define LEGACY_SOMETHING 0x01 /* OPL3?? */ | 268 | * I was unable to locate any configurability for a different address: */ |
127 | #define LEGACY_JOY 0x08 | 269 | #define GAME_HWCFG_LEGACY_ADDRESS_ENABLE 0x08 |
128 | 270 | ||
271 | /*** MPU401 ***/ | ||
129 | #define AZF_IO_SIZE_MPU 0x04 | 272 | #define AZF_IO_SIZE_MPU 0x04 |
130 | #define AZF_IO_SIZE_MPU_PM 0x04 | 273 | #define AZF_IO_SIZE_MPU_PM 0x04 |
131 | 274 | ||
132 | #define AZF_IO_SIZE_SYNTH 0x08 | 275 | /*** OPL3 synth ***/ |
133 | #define AZF_IO_SIZE_SYNTH_PM 0x06 | 276 | #define AZF_IO_SIZE_OPL3 0x08 |
277 | #define AZF_IO_SIZE_OPL3_PM 0x06 | ||
278 | /* hmm, given that a standard OPL3 has 4 registers only, | ||
279 | * there might be some enhanced functionality lurking at the end | ||
280 | * (especially since register 0x04 has a "non-empty" value 0xfe) */ | ||
134 | 281 | ||
135 | /*** mixer I/O area port indices ***/ | 282 | /*** mixer I/O area port indices ***/ |
136 | /* (only 0x22 of 0x40 bytes saved/restored by Windows driver) | 283 | /* (only 0x22 of 0x40 bytes saved/restored by Windows driver) |