diff options
author | Andreas Mohr <andi@lisas.de> | 2010-12-27 15:17:26 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2011-01-02 05:11:24 -0500 |
commit | da237f35a8a503fb8893fb3b9d0622a991bcebef (patch) | |
tree | 36c9ad6accec05028e9e7ab0ef62cccede0aaa6b | |
parent | 345855951a7d36eed815fd129c49b7ee2b7a6864 (diff) |
ALSA: azt3328: use proper private_data hookup for codec identification
- much improved implementation due to clean codec hierarchy
- preparation for potential per-codec spinlock change
NOTE: additionally removes a chip->pcm[codec_type] NULL ptr check
(due to it requiring access to external chip struct),
however I believe this to be ok since this condition should not occur
and most drivers don't check against that either.
Signed-off-by: Andreas Mohr <andi@lisas.de>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r-- | sound/pci/azt3328.c | 234 |
1 files changed, 90 insertions, 144 deletions
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c index b1fad46a7b02..76ff5fdb4838 100644 --- a/sound/pci/azt3328.c +++ b/sound/pci/azt3328.c | |||
@@ -292,14 +292,6 @@ static int seqtimer_scaling = 128; | |||
292 | module_param(seqtimer_scaling, int, 0444); | 292 | module_param(seqtimer_scaling, int, 0444); |
293 | MODULE_PARM_DESC(seqtimer_scaling, "Set 1024000Hz sequencer timer scale factor (lockup danger!). Default 128."); | 293 | MODULE_PARM_DESC(seqtimer_scaling, "Set 1024000Hz sequencer timer scale factor (lockup danger!). Default 128."); |
294 | 294 | ||
295 | struct snd_azf3328_codec_data { | ||
296 | unsigned long io_base; | ||
297 | unsigned int dma_base; /* helper to avoid an indirection in hotpath */ | ||
298 | struct snd_pcm_substream *substream; | ||
299 | bool running; | ||
300 | const char *name; | ||
301 | }; | ||
302 | |||
303 | enum snd_azf3328_codec_type { | 295 | enum snd_azf3328_codec_type { |
304 | /* warning: fixed indices (also used for bitmask checks!) */ | 296 | /* warning: fixed indices (also used for bitmask checks!) */ |
305 | AZF_CODEC_PLAYBACK = 0, | 297 | AZF_CODEC_PLAYBACK = 0, |
@@ -307,6 +299,16 @@ enum snd_azf3328_codec_type { | |||
307 | AZF_CODEC_I2S_OUT = 2, | 299 | AZF_CODEC_I2S_OUT = 2, |
308 | }; | 300 | }; |
309 | 301 | ||
302 | struct snd_azf3328_codec_data { | ||
303 | unsigned long io_base; /* keep first! (avoid offset calc) */ | ||
304 | unsigned int dma_base; /* helper to avoid an indirection in hotpath */ | ||
305 | spinlock_t *lock; /* TODO: convert to our own per-codec lock member */ | ||
306 | struct snd_pcm_substream *substream; | ||
307 | bool running; | ||
308 | enum snd_azf3328_codec_type type; | ||
309 | const char *name; | ||
310 | }; | ||
311 | |||
310 | struct snd_azf3328 { | 312 | struct snd_azf3328 { |
311 | /* often-used fields towards beginning, then grouped */ | 313 | /* often-used fields towards beginning, then grouped */ |
312 | 314 | ||
@@ -949,15 +951,13 @@ snd_azf3328_hw_free(struct snd_pcm_substream *substream) | |||
949 | } | 951 | } |
950 | 952 | ||
951 | static void | 953 | static void |
952 | snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, | 954 | snd_azf3328_codec_setfmt(struct snd_azf3328_codec_data *codec, |
953 | enum snd_azf3328_codec_type codec_type, | ||
954 | enum azf_freq_t bitrate, | 955 | enum azf_freq_t bitrate, |
955 | unsigned int format_width, | 956 | unsigned int format_width, |
956 | unsigned int channels | 957 | unsigned int channels |
957 | ) | 958 | ) |
958 | { | 959 | { |
959 | unsigned long flags; | 960 | unsigned long flags; |
960 | const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; | ||
961 | u16 val = 0xff00; | 961 | u16 val = 0xff00; |
962 | u8 freq = 0; | 962 | u8 freq = 0; |
963 | 963 | ||
@@ -1007,7 +1007,7 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, | |||
1007 | if (format_width == 16) | 1007 | if (format_width == 16) |
1008 | val |= SOUNDFORMAT_FLAG_16BIT; | 1008 | val |= SOUNDFORMAT_FLAG_16BIT; |
1009 | 1009 | ||
1010 | spin_lock_irqsave(&chip->reg_lock, flags); | 1010 | spin_lock_irqsave(codec->lock, flags); |
1011 | 1011 | ||
1012 | /* set bitrate/format */ | 1012 | /* set bitrate/format */ |
1013 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_SOUNDFORMAT, val); | 1013 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_SOUNDFORMAT, val); |
@@ -1020,7 +1020,7 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, | |||
1020 | * FIXME: does this have some side effects for full-duplex | 1020 | * FIXME: does this have some side effects for full-duplex |
1021 | * or other dramatic side effects? */ | 1021 | * or other dramatic side effects? */ |
1022 | /* do it for non-capture codecs only */ | 1022 | /* do it for non-capture codecs only */ |
1023 | if (codec_type == AZF_CODEC_PLAYBACK) | 1023 | if (codec->type != AZF_CODEC_CAPTURE) |
1024 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, | 1024 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, |
1025 | snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS) | | 1025 | snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS) | |
1026 | DMA_RUN_SOMETHING1 | | 1026 | DMA_RUN_SOMETHING1 | |
@@ -1030,20 +1030,19 @@ snd_azf3328_codec_setfmt(struct snd_azf3328 *chip, | |||
1030 | DMA_SOMETHING_ELSE | 1030 | DMA_SOMETHING_ELSE |
1031 | ); | 1031 | ); |
1032 | 1032 | ||
1033 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 1033 | spin_unlock_irqrestore(codec->lock, flags); |
1034 | snd_azf3328_dbgcallleave(); | 1034 | snd_azf3328_dbgcallleave(); |
1035 | } | 1035 | } |
1036 | 1036 | ||
1037 | static inline void | 1037 | static inline void |
1038 | snd_azf3328_codec_setfmt_lowpower(struct snd_azf3328 *chip, | 1038 | snd_azf3328_codec_setfmt_lowpower(struct snd_azf3328_codec_data *codec |
1039 | enum snd_azf3328_codec_type codec_type | ||
1040 | ) | 1039 | ) |
1041 | { | 1040 | { |
1042 | /* choose lowest frequency for low power consumption. | 1041 | /* choose lowest frequency for low power consumption. |
1043 | * While this will cause louder noise due to rather coarse frequency, | 1042 | * While this will cause louder noise due to rather coarse frequency, |
1044 | * it should never matter since output should always | 1043 | * it should never matter since output should always |
1045 | * get disabled properly when idle anyway. */ | 1044 | * get disabled properly when idle anyway. */ |
1046 | snd_azf3328_codec_setfmt(chip, codec_type, AZF_FREQ_4000, 8, 1); | 1045 | snd_azf3328_codec_setfmt(codec, AZF_FREQ_4000, 8, 1); |
1047 | } | 1046 | } |
1048 | 1047 | ||
1049 | static void | 1048 | static void |
@@ -1117,23 +1116,18 @@ snd_azf3328_ctrl_codec_activity(struct snd_azf3328 *chip, | |||
1117 | /* ...and adjust clock, too | 1116 | /* ...and adjust clock, too |
1118 | * (reduce noise and power consumption) */ | 1117 | * (reduce noise and power consumption) */ |
1119 | if (!enable) | 1118 | if (!enable) |
1120 | snd_azf3328_codec_setfmt_lowpower( | 1119 | snd_azf3328_codec_setfmt_lowpower(codec); |
1121 | chip, | ||
1122 | codec_type | ||
1123 | ); | ||
1124 | codec->running = enable; | 1120 | codec->running = enable; |
1125 | } | 1121 | } |
1126 | } | 1122 | } |
1127 | 1123 | ||
1128 | static void | 1124 | static void |
1129 | snd_azf3328_codec_setdmaa(struct snd_azf3328 *chip, | 1125 | snd_azf3328_codec_setdmaa(struct snd_azf3328_codec_data *codec, |
1130 | enum snd_azf3328_codec_type codec_type, | ||
1131 | unsigned long addr, | 1126 | unsigned long addr, |
1132 | unsigned int count, | 1127 | unsigned int count, |
1133 | unsigned int size | 1128 | unsigned int size |
1134 | ) | 1129 | ) |
1135 | { | 1130 | { |
1136 | const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; | ||
1137 | snd_azf3328_dbgcallenter(); | 1131 | snd_azf3328_dbgcallenter(); |
1138 | if (!codec->running) { | 1132 | if (!codec->running) { |
1139 | /* AZF3328 uses a two buffer pointer DMA transfer approach */ | 1133 | /* AZF3328 uses a two buffer pointer DMA transfer approach */ |
@@ -1152,22 +1146,22 @@ snd_azf3328_codec_setdmaa(struct snd_azf3328 *chip, | |||
1152 | 1146 | ||
1153 | /* build combined I/O buffer length word */ | 1147 | /* build combined I/O buffer length word */ |
1154 | lengths = (count_areas << 16) | (count_areas); | 1148 | lengths = (count_areas << 16) | (count_areas); |
1155 | spin_lock_irqsave(&chip->reg_lock, flags); | 1149 | spin_lock_irqsave(codec->lock, flags); |
1156 | snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_START_1, addr); | 1150 | snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_START_1, addr); |
1157 | snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_START_2, | 1151 | snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_START_2, |
1158 | addr_area2); | 1152 | addr_area2); |
1159 | snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_LENGTHS, | 1153 | snd_azf3328_codec_outl(codec, IDX_IO_CODEC_DMA_LENGTHS, |
1160 | lengths); | 1154 | lengths); |
1161 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 1155 | spin_unlock_irqrestore(codec->lock, flags); |
1162 | } | 1156 | } |
1163 | snd_azf3328_dbgcallleave(); | 1157 | snd_azf3328_dbgcallleave(); |
1164 | } | 1158 | } |
1165 | 1159 | ||
1166 | static int | 1160 | static int |
1167 | snd_azf3328_codec_prepare(struct snd_pcm_substream *substream) | 1161 | snd_azf3328_pcm_prepare(struct snd_pcm_substream *substream) |
1168 | { | 1162 | { |
1169 | struct snd_pcm_runtime *runtime = substream->runtime; | 1163 | struct snd_pcm_runtime *runtime = substream->runtime; |
1170 | struct snd_azf3328_codec *codec = runtime->private_data; | 1164 | struct snd_azf3328_codec_data *codec = runtime->private_data; |
1171 | #if 0 | 1165 | #if 0 |
1172 | unsigned int size = snd_pcm_lib_buffer_bytes(substream); | 1166 | unsigned int size = snd_pcm_lib_buffer_bytes(substream); |
1173 | unsigned int count = snd_pcm_lib_period_bytes(substream); | 1167 | unsigned int count = snd_pcm_lib_period_bytes(substream); |
@@ -1178,11 +1172,11 @@ snd_azf3328_codec_prepare(struct snd_pcm_substream *substream) | |||
1178 | codec->dma_base = runtime->dma_addr; | 1172 | codec->dma_base = runtime->dma_addr; |
1179 | 1173 | ||
1180 | #if 0 | 1174 | #if 0 |
1181 | snd_azf3328_codec_setfmt(chip, AZF_CODEC_..., | 1175 | snd_azf3328_codec_setfmt(codec, |
1182 | runtime->rate, | 1176 | runtime->rate, |
1183 | snd_pcm_format_width(runtime->format), | 1177 | snd_pcm_format_width(runtime->format), |
1184 | runtime->channels); | 1178 | runtime->channels); |
1185 | snd_azf3328_codec_setdmaa(chip, AZF_CODEC_..., | 1179 | snd_azf3328_codec_setdmaa(codec, |
1186 | runtime->dma_addr, count, size); | 1180 | runtime->dma_addr, count, size); |
1187 | #endif | 1181 | #endif |
1188 | snd_azf3328_dbgcallleave(); | 1182 | snd_azf3328_dbgcallleave(); |
@@ -1190,24 +1184,23 @@ snd_azf3328_codec_prepare(struct snd_pcm_substream *substream) | |||
1190 | } | 1184 | } |
1191 | 1185 | ||
1192 | static int | 1186 | static int |
1193 | snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, | 1187 | snd_azf3328_pcm_trigger(struct snd_pcm_substream *substream, int cmd) |
1194 | struct snd_pcm_substream *substream, int cmd) | ||
1195 | { | 1188 | { |
1196 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1189 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); |
1197 | const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; | ||
1198 | struct snd_pcm_runtime *runtime = substream->runtime; | 1190 | struct snd_pcm_runtime *runtime = substream->runtime; |
1191 | struct snd_azf3328_codec_data *codec = runtime->private_data; | ||
1199 | int result = 0; | 1192 | int result = 0; |
1200 | u16 flags1; | 1193 | u16 flags1; |
1201 | bool previously_muted = 0; | 1194 | bool previously_muted = 0; |
1202 | bool is_playback_codec = (AZF_CODEC_PLAYBACK == codec_type); | 1195 | bool is_main_mixer_playback_codec = (AZF_CODEC_PLAYBACK == codec->type); |
1203 | 1196 | ||
1204 | snd_azf3328_dbgcalls("snd_azf3328_codec_trigger cmd %d\n", cmd); | 1197 | snd_azf3328_dbgcalls("snd_azf3328_pcm_trigger cmd %d\n", cmd); |
1205 | 1198 | ||
1206 | switch (cmd) { | 1199 | switch (cmd) { |
1207 | case SNDRV_PCM_TRIGGER_START: | 1200 | case SNDRV_PCM_TRIGGER_START: |
1208 | snd_azf3328_dbgcodec("START %s\n", codec->name); | 1201 | snd_azf3328_dbgcodec("START %s\n", codec->name); |
1209 | 1202 | ||
1210 | if (is_playback_codec) { | 1203 | if (is_main_mixer_playback_codec) { |
1211 | /* mute WaveOut (avoid clicking during setup) */ | 1204 | /* mute WaveOut (avoid clicking during setup) */ |
1212 | previously_muted = | 1205 | previously_muted = |
1213 | snd_azf3328_mixer_set_mute( | 1206 | snd_azf3328_mixer_set_mute( |
@@ -1215,12 +1208,12 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, | |||
1215 | ); | 1208 | ); |
1216 | } | 1209 | } |
1217 | 1210 | ||
1218 | snd_azf3328_codec_setfmt(chip, codec_type, | 1211 | snd_azf3328_codec_setfmt(codec, |
1219 | runtime->rate, | 1212 | runtime->rate, |
1220 | snd_pcm_format_width(runtime->format), | 1213 | snd_pcm_format_width(runtime->format), |
1221 | runtime->channels); | 1214 | runtime->channels); |
1222 | 1215 | ||
1223 | spin_lock(&chip->reg_lock); | 1216 | spin_lock(codec->lock); |
1224 | /* first, remember current value: */ | 1217 | /* first, remember current value: */ |
1225 | flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS); | 1218 | flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS); |
1226 | 1219 | ||
@@ -1230,14 +1223,14 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, | |||
1230 | 1223 | ||
1231 | /* FIXME: clear interrupts or what??? */ | 1224 | /* FIXME: clear interrupts or what??? */ |
1232 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_IRQTYPE, 0xffff); | 1225 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_IRQTYPE, 0xffff); |
1233 | spin_unlock(&chip->reg_lock); | 1226 | spin_unlock(codec->lock); |
1234 | 1227 | ||
1235 | snd_azf3328_codec_setdmaa(chip, codec_type, runtime->dma_addr, | 1228 | snd_azf3328_codec_setdmaa(codec, runtime->dma_addr, |
1236 | snd_pcm_lib_period_bytes(substream), | 1229 | snd_pcm_lib_period_bytes(substream), |
1237 | snd_pcm_lib_buffer_bytes(substream) | 1230 | snd_pcm_lib_buffer_bytes(substream) |
1238 | ); | 1231 | ); |
1239 | 1232 | ||
1240 | spin_lock(&chip->reg_lock); | 1233 | spin_lock(codec->lock); |
1241 | #ifdef WIN9X | 1234 | #ifdef WIN9X |
1242 | /* FIXME: enable playback/recording??? */ | 1235 | /* FIXME: enable playback/recording??? */ |
1243 | flags1 |= DMA_RUN_SOMETHING1 | DMA_RUN_SOMETHING2; | 1236 | flags1 |= DMA_RUN_SOMETHING1 | DMA_RUN_SOMETHING2; |
@@ -1261,10 +1254,10 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, | |||
1261 | DMA_EPILOGUE_SOMETHING | | 1254 | DMA_EPILOGUE_SOMETHING | |
1262 | DMA_SOMETHING_ELSE); | 1255 | DMA_SOMETHING_ELSE); |
1263 | #endif | 1256 | #endif |
1264 | spin_unlock(&chip->reg_lock); | 1257 | spin_unlock(codec->lock); |
1265 | snd_azf3328_ctrl_codec_activity(chip, codec_type, 1); | 1258 | snd_azf3328_ctrl_codec_activity(chip, codec->type, 1); |
1266 | 1259 | ||
1267 | if (is_playback_codec) { | 1260 | if (is_main_mixer_playback_codec) { |
1268 | /* now unmute WaveOut */ | 1261 | /* now unmute WaveOut */ |
1269 | if (!previously_muted) | 1262 | if (!previously_muted) |
1270 | snd_azf3328_mixer_set_mute( | 1263 | snd_azf3328_mixer_set_mute( |
@@ -1277,19 +1270,19 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, | |||
1277 | case SNDRV_PCM_TRIGGER_RESUME: | 1270 | case SNDRV_PCM_TRIGGER_RESUME: |
1278 | snd_azf3328_dbgcodec("RESUME %s\n", codec->name); | 1271 | snd_azf3328_dbgcodec("RESUME %s\n", codec->name); |
1279 | /* resume codec if we were active */ | 1272 | /* resume codec if we were active */ |
1280 | spin_lock(&chip->reg_lock); | 1273 | spin_lock(codec->lock); |
1281 | if (codec->running) | 1274 | if (codec->running) |
1282 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, | 1275 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, |
1283 | snd_azf3328_codec_inw( | 1276 | snd_azf3328_codec_inw( |
1284 | codec, IDX_IO_CODEC_DMA_FLAGS | 1277 | codec, IDX_IO_CODEC_DMA_FLAGS |
1285 | ) | DMA_RESUME | 1278 | ) | DMA_RESUME |
1286 | ); | 1279 | ); |
1287 | spin_unlock(&chip->reg_lock); | 1280 | spin_unlock(codec->lock); |
1288 | break; | 1281 | break; |
1289 | case SNDRV_PCM_TRIGGER_STOP: | 1282 | case SNDRV_PCM_TRIGGER_STOP: |
1290 | snd_azf3328_dbgcodec("STOP %s\n", codec->name); | 1283 | snd_azf3328_dbgcodec("STOP %s\n", codec->name); |
1291 | 1284 | ||
1292 | if (is_playback_codec) { | 1285 | if (is_main_mixer_playback_codec) { |
1293 | /* mute WaveOut (avoid clicking during setup) */ | 1286 | /* mute WaveOut (avoid clicking during setup) */ |
1294 | previously_muted = | 1287 | previously_muted = |
1295 | snd_azf3328_mixer_set_mute( | 1288 | snd_azf3328_mixer_set_mute( |
@@ -1297,7 +1290,7 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, | |||
1297 | ); | 1290 | ); |
1298 | } | 1291 | } |
1299 | 1292 | ||
1300 | spin_lock(&chip->reg_lock); | 1293 | spin_lock(codec->lock); |
1301 | /* first, remember current value: */ | 1294 | /* first, remember current value: */ |
1302 | flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS); | 1295 | flags1 = snd_azf3328_codec_inw(codec, IDX_IO_CODEC_DMA_FLAGS); |
1303 | 1296 | ||
@@ -1312,10 +1305,10 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, | |||
1312 | 1305 | ||
1313 | flags1 &= ~DMA_RUN_SOMETHING1; | 1306 | flags1 &= ~DMA_RUN_SOMETHING1; |
1314 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); | 1307 | snd_azf3328_codec_outw(codec, IDX_IO_CODEC_DMA_FLAGS, flags1); |
1315 | spin_unlock(&chip->reg_lock); | 1308 | spin_unlock(codec->lock); |
1316 | snd_azf3328_ctrl_codec_activity(chip, codec_type, 0); | 1309 | snd_azf3328_ctrl_codec_activity(chip, codec->type, 0); |
1317 | 1310 | ||
1318 | if (is_playback_codec) { | 1311 | if (is_main_mixer_playback_codec) { |
1319 | /* now unmute WaveOut */ | 1312 | /* now unmute WaveOut */ |
1320 | if (!previously_muted) | 1313 | if (!previously_muted) |
1321 | snd_azf3328_mixer_set_mute( | 1314 | snd_azf3328_mixer_set_mute( |
@@ -1349,31 +1342,12 @@ snd_azf3328_codec_trigger(enum snd_azf3328_codec_type codec_type, | |||
1349 | return result; | 1342 | return result; |
1350 | } | 1343 | } |
1351 | 1344 | ||
1352 | static int | ||
1353 | snd_azf3328_codec_playback_trigger(struct snd_pcm_substream *substream, int cmd) | ||
1354 | { | ||
1355 | return snd_azf3328_codec_trigger(AZF_CODEC_PLAYBACK, substream, cmd); | ||
1356 | } | ||
1357 | |||
1358 | static int | ||
1359 | snd_azf3328_codec_capture_trigger(struct snd_pcm_substream *substream, int cmd) | ||
1360 | { | ||
1361 | return snd_azf3328_codec_trigger(AZF_CODEC_CAPTURE, substream, cmd); | ||
1362 | } | ||
1363 | |||
1364 | static int | ||
1365 | snd_azf3328_codec_i2s_out_trigger(struct snd_pcm_substream *substream, int cmd) | ||
1366 | { | ||
1367 | return snd_azf3328_codec_trigger(AZF_CODEC_I2S_OUT, substream, cmd); | ||
1368 | } | ||
1369 | |||
1370 | static snd_pcm_uframes_t | 1345 | static snd_pcm_uframes_t |
1371 | snd_azf3328_codec_pointer(struct snd_pcm_substream *substream, | 1346 | snd_azf3328_pcm_pointer(struct snd_pcm_substream *substream |
1372 | enum snd_azf3328_codec_type codec_type | ||
1373 | ) | 1347 | ) |
1374 | { | 1348 | { |
1375 | const struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1349 | const struct snd_azf3328_codec_data *codec = |
1376 | const struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; | 1350 | substream->runtime->private_data; |
1377 | unsigned long result; | 1351 | unsigned long result; |
1378 | snd_pcm_uframes_t frmres; | 1352 | snd_pcm_uframes_t frmres; |
1379 | 1353 | ||
@@ -1391,24 +1365,6 @@ snd_azf3328_codec_pointer(struct snd_pcm_substream *substream, | |||
1391 | return frmres; | 1365 | return frmres; |
1392 | } | 1366 | } |
1393 | 1367 | ||
1394 | static snd_pcm_uframes_t | ||
1395 | snd_azf3328_codec_playback_pointer(struct snd_pcm_substream *substream) | ||
1396 | { | ||
1397 | return snd_azf3328_codec_pointer(substream, AZF_CODEC_PLAYBACK); | ||
1398 | } | ||
1399 | |||
1400 | static snd_pcm_uframes_t | ||
1401 | snd_azf3328_codec_capture_pointer(struct snd_pcm_substream *substream) | ||
1402 | { | ||
1403 | return snd_azf3328_codec_pointer(substream, AZF_CODEC_CAPTURE); | ||
1404 | } | ||
1405 | |||
1406 | static snd_pcm_uframes_t | ||
1407 | snd_azf3328_codec_i2s_out_pointer(struct snd_pcm_substream *substream) | ||
1408 | { | ||
1409 | return snd_azf3328_codec_pointer(substream, AZF_CODEC_I2S_OUT); | ||
1410 | } | ||
1411 | |||
1412 | /******************************************************************/ | 1368 | /******************************************************************/ |
1413 | 1369 | ||
1414 | #ifdef SUPPORT_GAMEPORT | 1370 | #ifdef SUPPORT_GAMEPORT |
@@ -1642,29 +1598,29 @@ snd_azf3328_irq_log_unknown_type(u8 which) | |||
1642 | } | 1598 | } |
1643 | 1599 | ||
1644 | static inline void | 1600 | static inline void |
1645 | snd_azf3328_codec_interrupt(struct snd_azf3328 *chip, u8 status) | 1601 | snd_azf3328_pcm_interrupt(const struct snd_azf3328_codec_data *first_codec, |
1602 | u8 status | ||
1603 | ) | ||
1646 | { | 1604 | { |
1647 | u8 which; | 1605 | u8 which; |
1648 | enum snd_azf3328_codec_type codec_type; | 1606 | enum snd_azf3328_codec_type codec_type; |
1649 | const struct snd_azf3328_codec_data *codec; | 1607 | const struct snd_azf3328_codec_data *codec = first_codec; |
1650 | 1608 | ||
1651 | for (codec_type = AZF_CODEC_PLAYBACK; | 1609 | for (codec_type = AZF_CODEC_PLAYBACK; |
1652 | codec_type <= AZF_CODEC_I2S_OUT; | 1610 | codec_type <= AZF_CODEC_I2S_OUT; |
1653 | ++codec_type) { | 1611 | ++codec_type, ++codec) { |
1654 | 1612 | ||
1655 | /* skip codec if there's no interrupt for it */ | 1613 | /* skip codec if there's no interrupt for it */ |
1656 | if (!(status & (1 << codec_type))) | 1614 | if (!(status & (1 << codec_type))) |
1657 | continue; | 1615 | continue; |
1658 | 1616 | ||
1659 | codec = &chip->codecs[codec_type]; | 1617 | spin_lock(codec->lock); |
1660 | |||
1661 | spin_lock(&chip->reg_lock); | ||
1662 | which = snd_azf3328_codec_inb(codec, IDX_IO_CODEC_IRQTYPE); | 1618 | which = snd_azf3328_codec_inb(codec, IDX_IO_CODEC_IRQTYPE); |
1663 | /* ack all IRQ types immediately */ | 1619 | /* ack all IRQ types immediately */ |
1664 | snd_azf3328_codec_outb(codec, IDX_IO_CODEC_IRQTYPE, which); | 1620 | snd_azf3328_codec_outb(codec, IDX_IO_CODEC_IRQTYPE, which); |
1665 | spin_unlock(&chip->reg_lock); | 1621 | spin_unlock(codec->lock); |
1666 | 1622 | ||
1667 | if ((chip->pcm[codec_type]) && (codec->substream)) { | 1623 | if (codec->substream) { |
1668 | snd_pcm_period_elapsed(codec->substream); | 1624 | snd_pcm_period_elapsed(codec->substream); |
1669 | snd_azf3328_dbgcodec("%s period done (#%x), @ %x\n", | 1625 | snd_azf3328_dbgcodec("%s period done (#%x), @ %x\n", |
1670 | codec->name, | 1626 | codec->name, |
@@ -1719,7 +1675,7 @@ snd_azf3328_interrupt(int irq, void *dev_id) | |||
1719 | } | 1675 | } |
1720 | 1676 | ||
1721 | if (status & (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_I2S_OUT)) | 1677 | if (status & (IRQ_PLAYBACK|IRQ_RECORDING|IRQ_I2S_OUT)) |
1722 | snd_azf3328_codec_interrupt(chip, status); | 1678 | snd_azf3328_pcm_interrupt(chip->codecs, status); |
1723 | 1679 | ||
1724 | if (status & IRQ_GAMEPORT) | 1680 | if (status & IRQ_GAMEPORT) |
1725 | snd_azf3328_gameport_interrupt(chip); | 1681 | snd_azf3328_gameport_interrupt(chip); |
@@ -1807,101 +1763,85 @@ snd_azf3328_pcm_open(struct snd_pcm_substream *substream, | |||
1807 | { | 1763 | { |
1808 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1764 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); |
1809 | struct snd_pcm_runtime *runtime = substream->runtime; | 1765 | struct snd_pcm_runtime *runtime = substream->runtime; |
1766 | struct snd_azf3328_codec_data *codec = &chip->codecs[codec_type]; | ||
1810 | 1767 | ||
1811 | snd_azf3328_dbgcallenter(); | 1768 | snd_azf3328_dbgcallenter(); |
1812 | chip->codecs[codec_type].substream = substream; | 1769 | codec->substream = substream; |
1813 | 1770 | ||
1814 | /* same parameters for all our codecs - at least we think so... */ | 1771 | /* same parameters for all our codecs - at least we think so... */ |
1815 | runtime->hw = snd_azf3328_hardware; | 1772 | runtime->hw = snd_azf3328_hardware; |
1816 | 1773 | ||
1817 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | 1774 | snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, |
1818 | &snd_azf3328_hw_constraints_rates); | 1775 | &snd_azf3328_hw_constraints_rates); |
1776 | runtime->private_data = codec; | ||
1819 | snd_azf3328_dbgcallleave(); | 1777 | snd_azf3328_dbgcallleave(); |
1820 | return 0; | 1778 | return 0; |
1821 | } | 1779 | } |
1822 | 1780 | ||
1823 | static int | 1781 | static int |
1824 | snd_azf3328_playback_open(struct snd_pcm_substream *substream) | 1782 | snd_azf3328_pcm_playback_open(struct snd_pcm_substream *substream) |
1825 | { | 1783 | { |
1826 | return snd_azf3328_pcm_open(substream, AZF_CODEC_PLAYBACK); | 1784 | return snd_azf3328_pcm_open(substream, AZF_CODEC_PLAYBACK); |
1827 | } | 1785 | } |
1828 | 1786 | ||
1829 | static int | 1787 | static int |
1830 | snd_azf3328_capture_open(struct snd_pcm_substream *substream) | 1788 | snd_azf3328_pcm_capture_open(struct snd_pcm_substream *substream) |
1831 | { | 1789 | { |
1832 | return snd_azf3328_pcm_open(substream, AZF_CODEC_CAPTURE); | 1790 | return snd_azf3328_pcm_open(substream, AZF_CODEC_CAPTURE); |
1833 | } | 1791 | } |
1834 | 1792 | ||
1835 | static int | 1793 | static int |
1836 | snd_azf3328_i2s_out_open(struct snd_pcm_substream *substream) | 1794 | snd_azf3328_pcm_i2s_out_open(struct snd_pcm_substream *substream) |
1837 | { | 1795 | { |
1838 | return snd_azf3328_pcm_open(substream, AZF_CODEC_I2S_OUT); | 1796 | return snd_azf3328_pcm_open(substream, AZF_CODEC_I2S_OUT); |
1839 | } | 1797 | } |
1840 | 1798 | ||
1841 | static int | 1799 | static int |
1842 | snd_azf3328_pcm_close(struct snd_pcm_substream *substream, | 1800 | snd_azf3328_pcm_close(struct snd_pcm_substream *substream |
1843 | enum snd_azf3328_codec_type codec_type | ||
1844 | ) | 1801 | ) |
1845 | { | 1802 | { |
1846 | struct snd_azf3328 *chip = snd_pcm_substream_chip(substream); | 1803 | struct snd_azf3328_codec_data *codec = |
1804 | substream->runtime->private_data; | ||
1847 | 1805 | ||
1848 | snd_azf3328_dbgcallenter(); | 1806 | snd_azf3328_dbgcallenter(); |
1849 | chip->codecs[codec_type].substream = NULL; | 1807 | codec->substream = NULL; |
1850 | snd_azf3328_dbgcallleave(); | 1808 | snd_azf3328_dbgcallleave(); |
1851 | return 0; | 1809 | return 0; |
1852 | } | 1810 | } |
1853 | 1811 | ||
1854 | static int | ||
1855 | snd_azf3328_playback_close(struct snd_pcm_substream *substream) | ||
1856 | { | ||
1857 | return snd_azf3328_pcm_close(substream, AZF_CODEC_PLAYBACK); | ||
1858 | } | ||
1859 | |||
1860 | static int | ||
1861 | snd_azf3328_capture_close(struct snd_pcm_substream *substream) | ||
1862 | { | ||
1863 | return snd_azf3328_pcm_close(substream, AZF_CODEC_CAPTURE); | ||
1864 | } | ||
1865 | |||
1866 | static int | ||
1867 | snd_azf3328_i2s_out_close(struct snd_pcm_substream *substream) | ||
1868 | { | ||
1869 | return snd_azf3328_pcm_close(substream, AZF_CODEC_I2S_OUT); | ||
1870 | } | ||
1871 | |||
1872 | /******************************************************************/ | 1812 | /******************************************************************/ |
1873 | 1813 | ||
1874 | static struct snd_pcm_ops snd_azf3328_playback_ops = { | 1814 | static struct snd_pcm_ops snd_azf3328_playback_ops = { |
1875 | .open = snd_azf3328_playback_open, | 1815 | .open = snd_azf3328_pcm_playback_open, |
1876 | .close = snd_azf3328_playback_close, | 1816 | .close = snd_azf3328_pcm_close, |
1877 | .ioctl = snd_pcm_lib_ioctl, | 1817 | .ioctl = snd_pcm_lib_ioctl, |
1878 | .hw_params = snd_azf3328_hw_params, | 1818 | .hw_params = snd_azf3328_hw_params, |
1879 | .hw_free = snd_azf3328_hw_free, | 1819 | .hw_free = snd_azf3328_hw_free, |
1880 | .prepare = snd_azf3328_codec_prepare, | 1820 | .prepare = snd_azf3328_pcm_prepare, |
1881 | .trigger = snd_azf3328_codec_playback_trigger, | 1821 | .trigger = snd_azf3328_pcm_trigger, |
1882 | .pointer = snd_azf3328_codec_playback_pointer | 1822 | .pointer = snd_azf3328_pcm_pointer |
1883 | }; | 1823 | }; |
1884 | 1824 | ||
1885 | static struct snd_pcm_ops snd_azf3328_capture_ops = { | 1825 | static struct snd_pcm_ops snd_azf3328_capture_ops = { |
1886 | .open = snd_azf3328_capture_open, | 1826 | .open = snd_azf3328_pcm_capture_open, |
1887 | .close = snd_azf3328_capture_close, | 1827 | .close = snd_azf3328_pcm_close, |
1888 | .ioctl = snd_pcm_lib_ioctl, | 1828 | .ioctl = snd_pcm_lib_ioctl, |
1889 | .hw_params = snd_azf3328_hw_params, | 1829 | .hw_params = snd_azf3328_hw_params, |
1890 | .hw_free = snd_azf3328_hw_free, | 1830 | .hw_free = snd_azf3328_hw_free, |
1891 | .prepare = snd_azf3328_codec_prepare, | 1831 | .prepare = snd_azf3328_pcm_prepare, |
1892 | .trigger = snd_azf3328_codec_capture_trigger, | 1832 | .trigger = snd_azf3328_pcm_trigger, |
1893 | .pointer = snd_azf3328_codec_capture_pointer | 1833 | .pointer = snd_azf3328_pcm_pointer |
1894 | }; | 1834 | }; |
1895 | 1835 | ||
1896 | static struct snd_pcm_ops snd_azf3328_i2s_out_ops = { | 1836 | static struct snd_pcm_ops snd_azf3328_i2s_out_ops = { |
1897 | .open = snd_azf3328_i2s_out_open, | 1837 | .open = snd_azf3328_pcm_i2s_out_open, |
1898 | .close = snd_azf3328_i2s_out_close, | 1838 | .close = snd_azf3328_pcm_close, |
1899 | .ioctl = snd_pcm_lib_ioctl, | 1839 | .ioctl = snd_pcm_lib_ioctl, |
1900 | .hw_params = snd_azf3328_hw_params, | 1840 | .hw_params = snd_azf3328_hw_params, |
1901 | .hw_free = snd_azf3328_hw_free, | 1841 | .hw_free = snd_azf3328_hw_free, |
1902 | .prepare = snd_azf3328_codec_prepare, | 1842 | .prepare = snd_azf3328_pcm_prepare, |
1903 | .trigger = snd_azf3328_codec_i2s_out_trigger, | 1843 | .trigger = snd_azf3328_pcm_trigger, |
1904 | .pointer = snd_azf3328_codec_i2s_out_pointer | 1844 | .pointer = snd_azf3328_pcm_pointer |
1905 | }; | 1845 | }; |
1906 | 1846 | ||
1907 | static int __devinit | 1847 | static int __devinit |
@@ -2198,7 +2138,7 @@ snd_azf3328_create(struct snd_card *card, | |||
2198 | }; | 2138 | }; |
2199 | u8 dma_init; | 2139 | u8 dma_init; |
2200 | enum snd_azf3328_codec_type codec_type; | 2140 | enum snd_azf3328_codec_type codec_type; |
2201 | struct snd_azf3328_codec *codec_setup; | 2141 | struct snd_azf3328_codec_data *codec_setup; |
2202 | 2142 | ||
2203 | *rchip = NULL; | 2143 | *rchip = NULL; |
2204 | 2144 | ||
@@ -2238,14 +2178,20 @@ snd_azf3328_create(struct snd_card *card, | |||
2238 | 2178 | ||
2239 | codec_setup = &chip->codecs[AZF_CODEC_PLAYBACK]; | 2179 | codec_setup = &chip->codecs[AZF_CODEC_PLAYBACK]; |
2240 | codec_setup->io_base = chip->ctrl_io + AZF_IO_OFFS_CODEC_PLAYBACK; | 2180 | codec_setup->io_base = chip->ctrl_io + AZF_IO_OFFS_CODEC_PLAYBACK; |
2181 | codec_setup->lock = &chip->reg_lock; | ||
2182 | codec_setup->type = AZF_CODEC_PLAYBACK; | ||
2241 | codec_setup->name = "PLAYBACK"; | 2183 | codec_setup->name = "PLAYBACK"; |
2242 | 2184 | ||
2243 | codec_setup = &chip->codecs[AZF_CODEC_CAPTURE]; | 2185 | codec_setup = &chip->codecs[AZF_CODEC_CAPTURE]; |
2244 | codec_setup->io_base = chip->ctrl_io + AZF_IO_OFFS_CODEC_CAPTURE; | 2186 | codec_setup->io_base = chip->ctrl_io + AZF_IO_OFFS_CODEC_CAPTURE; |
2187 | codec_setup->lock = &chip->reg_lock; | ||
2188 | codec_setup->type = AZF_CODEC_CAPTURE; | ||
2245 | codec_setup->name = "CAPTURE"; | 2189 | codec_setup->name = "CAPTURE"; |
2246 | 2190 | ||
2247 | codec_setup = &chip->codecs[AZF_CODEC_I2S_OUT]; | 2191 | codec_setup = &chip->codecs[AZF_CODEC_I2S_OUT]; |
2248 | codec_setup->io_base = chip->ctrl_io + AZF_IO_OFFS_CODEC_I2S_OUT; | 2192 | codec_setup->io_base = chip->ctrl_io + AZF_IO_OFFS_CODEC_I2S_OUT; |
2193 | codec_setup->lock = &chip->reg_lock; | ||
2194 | codec_setup->type = AZF_CODEC_I2S_OUT; | ||
2249 | codec_setup->name = "I2S_OUT"; | 2195 | codec_setup->name = "I2S_OUT"; |
2250 | 2196 | ||
2251 | if (request_irq(pci->irq, snd_azf3328_interrupt, | 2197 | if (request_irq(pci->irq, snd_azf3328_interrupt, |
@@ -2283,10 +2229,10 @@ snd_azf3328_create(struct snd_card *card, | |||
2283 | codec->running = 1; | 2229 | codec->running = 1; |
2284 | snd_azf3328_ctrl_codec_activity(chip, codec_type, 0); | 2230 | snd_azf3328_ctrl_codec_activity(chip, codec_type, 0); |
2285 | 2231 | ||
2286 | spin_lock_irq(&chip->reg_lock); | 2232 | spin_lock_irq(codec->lock); |
2287 | snd_azf3328_codec_outb(codec, IDX_IO_CODEC_DMA_FLAGS, | 2233 | snd_azf3328_codec_outb(codec, IDX_IO_CODEC_DMA_FLAGS, |
2288 | dma_init); | 2234 | dma_init); |
2289 | spin_unlock_irq(&chip->reg_lock); | 2235 | spin_unlock_irq(codec->lock); |
2290 | } | 2236 | } |
2291 | 2237 | ||
2292 | snd_card_set_dev(card, &pci->dev); | 2238 | snd_card_set_dev(card, &pci->dev); |