diff options
-rw-r--r-- | sound/isa/wss/wss_lib.c | 133 |
1 files changed, 69 insertions, 64 deletions
diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c index 866e8686dbe7..011da7a2315d 100644 --- a/sound/isa/wss/wss_lib.c +++ b/sound/isa/wss/wss_lib.c | |||
@@ -1147,79 +1147,84 @@ static snd_pcm_uframes_t snd_wss_capture_pointer(struct snd_pcm_substream *subst | |||
1147 | 1147 | ||
1148 | static int snd_ad1848_probe(struct snd_wss *chip) | 1148 | static int snd_ad1848_probe(struct snd_wss *chip) |
1149 | { | 1149 | { |
1150 | unsigned long timeout = jiffies + msecs_to_jiffies(1000); | ||
1150 | unsigned long flags; | 1151 | unsigned long flags; |
1151 | int i, id, rev, ad1847; | 1152 | unsigned char r; |
1153 | unsigned short hardware = 0; | ||
1154 | int err = 0; | ||
1155 | int i; | ||
1152 | 1156 | ||
1153 | id = 0; | 1157 | while (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) { |
1154 | ad1847 = 0; | 1158 | if (time_after(jiffies, timeout)) |
1155 | for (i = 0; i < 1000; i++) { | 1159 | return -ENODEV; |
1156 | mb(); | 1160 | cond_resched(); |
1157 | if (inb(chip->port + CS4231P(REGSEL)) & CS4231_INIT) | ||
1158 | msleep(1); | ||
1159 | else { | ||
1160 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
1161 | snd_wss_out(chip, CS4231_MISC_INFO, 0x00); | ||
1162 | snd_wss_out(chip, CS4231_LEFT_INPUT, 0xaa); | ||
1163 | snd_wss_out(chip, CS4231_RIGHT_INPUT, 0x45); | ||
1164 | rev = snd_wss_in(chip, CS4231_RIGHT_INPUT); | ||
1165 | if (rev == 0x65) { | ||
1166 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
1167 | id = 1; | ||
1168 | ad1847 = 1; | ||
1169 | break; | ||
1170 | } | ||
1171 | if (rev == 0x45) { | ||
1172 | rev = snd_wss_in(chip, CS4231_LEFT_INPUT); | ||
1173 | if (rev == 0xaa || rev == 0x8a) { | ||
1174 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
1175 | id = 1; | ||
1176 | break; | ||
1177 | } | ||
1178 | } | ||
1179 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
1180 | } | ||
1181 | } | 1161 | } |
1182 | if (id != 1) | ||
1183 | return -ENODEV; /* no valid device found */ | ||
1184 | id = 0; | ||
1185 | if (chip->hardware == WSS_HW_DETECT) | ||
1186 | id = ad1847 ? WSS_HW_AD1847 : WSS_HW_AD1848; | ||
1187 | |||
1188 | spin_lock_irqsave(&chip->reg_lock, flags); | 1162 | spin_lock_irqsave(&chip->reg_lock, flags); |
1189 | inb(chip->port + CS4231P(STATUS)); /* clear any pendings IRQ */ | 1163 | |
1190 | outb(0, chip->port + CS4231P(STATUS)); | 1164 | /* set CS423x MODE 1 */ |
1191 | mb(); | 1165 | snd_wss_out(chip, CS4231_MISC_INFO, 0); |
1192 | if (id == WSS_HW_AD1848) { | 1166 | |
1193 | /* check if there are more than 16 registers */ | 1167 | snd_wss_out(chip, CS4231_RIGHT_INPUT, 0x45); /* 0x55 & ~0x10 */ |
1194 | rev = snd_wss_in(chip, CS4231_MISC_INFO); | 1168 | r = snd_wss_in(chip, CS4231_RIGHT_INPUT); |
1195 | snd_wss_out(chip, CS4231_MISC_INFO, 0x40); | 1169 | if (r != 0x45) { |
1196 | for (i = 0; i < 16; ++i) { | 1170 | /* RMGE always high on AD1847 */ |
1197 | if (snd_wss_in(chip, i) != snd_wss_in(chip, i + 16)) { | 1171 | if ((r & ~CS4231_ENABLE_MIC_GAIN) != 0x45) { |
1198 | id = WSS_HW_CMI8330; | 1172 | err = -ENODEV; |
1199 | break; | 1173 | goto out; |
1200 | } | 1174 | } |
1175 | hardware = WSS_HW_AD1847; | ||
1176 | } else { | ||
1177 | snd_wss_out(chip, CS4231_LEFT_INPUT, 0xaa); | ||
1178 | r = snd_wss_in(chip, CS4231_LEFT_INPUT); | ||
1179 | /* L/RMGE always low on AT2320 */ | ||
1180 | if ((r | CS4231_ENABLE_MIC_GAIN) != 0xaa) { | ||
1181 | err = -ENODEV; | ||
1182 | goto out; | ||
1201 | } | 1183 | } |
1202 | snd_wss_out(chip, CS4231_MISC_INFO, 0x00); | ||
1203 | if (id != WSS_HW_CMI8330 && (rev & 0x80)) | ||
1204 | id = WSS_HW_CS4248; | ||
1205 | if (id == WSS_HW_CMI8330 && (rev & 0x0f) != 0x0a) | ||
1206 | id = 0; | ||
1207 | } | 1184 | } |
1208 | if (id == WSS_HW_CMI8330) { | 1185 | |
1209 | /* verify it is not CS4231 by changing the version register */ | 1186 | /* clear pending IRQ */ |
1210 | /* on CMI8330 it is volume control register and can be set 0 */ | 1187 | wss_inb(chip, CS4231P(STATUS)); |
1211 | snd_wss_out(chip, CS4231_MISC_INFO, CS4231_MODE2); | 1188 | wss_outb(chip, CS4231P(STATUS), 0); |
1212 | snd_wss_dout(chip, CS4231_VERSION, 0x00); | 1189 | mb(); |
1213 | rev = snd_wss_in(chip, CS4231_VERSION) & 0xe7; | 1190 | |
1214 | if (rev) | 1191 | if ((chip->hardware & WSS_HW_TYPE_MASK) != WSS_HW_DETECT) |
1215 | id = 0; | 1192 | goto out; |
1216 | snd_wss_out(chip, CS4231_MISC_INFO, 0); | 1193 | |
1194 | if (hardware) { | ||
1195 | chip->hardware = hardware; | ||
1196 | goto out; | ||
1217 | } | 1197 | } |
1218 | if (id) | ||
1219 | chip->hardware = id; | ||
1220 | 1198 | ||
1199 | r = snd_wss_in(chip, CS4231_MISC_INFO); | ||
1200 | |||
1201 | /* set CS423x MODE 2 */ | ||
1202 | snd_wss_out(chip, CS4231_MISC_INFO, CS4231_MODE2); | ||
1203 | for (i = 0; i < 16; i++) { | ||
1204 | if (snd_wss_in(chip, i) != snd_wss_in(chip, 16 + i)) { | ||
1205 | /* we have more than 16 registers: check ID */ | ||
1206 | if ((r & 0xf) != 0xa) | ||
1207 | goto out_mode; | ||
1208 | /* | ||
1209 | * on CMI8330, CS4231_VERSION is volume control and | ||
1210 | * can be set to 0 | ||
1211 | */ | ||
1212 | snd_wss_dout(chip, CS4231_VERSION, 0); | ||
1213 | r = snd_wss_in(chip, CS4231_VERSION) & 0xe7; | ||
1214 | if (!r) | ||
1215 | chip->hardware = WSS_HW_CMI8330; | ||
1216 | goto out_mode; | ||
1217 | } | ||
1218 | } | ||
1219 | if (r & 0x80) | ||
1220 | chip->hardware = WSS_HW_CS4248; | ||
1221 | else | ||
1222 | chip->hardware = WSS_HW_AD1848; | ||
1223 | out_mode: | ||
1224 | snd_wss_out(chip, CS4231_MISC_INFO, 0); | ||
1225 | out: | ||
1221 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 1226 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
1222 | return 0; /* all things are ok.. */ | 1227 | return err; |
1223 | } | 1228 | } |
1224 | 1229 | ||
1225 | static int snd_wss_probe(struct snd_wss *chip) | 1230 | static int snd_wss_probe(struct snd_wss *chip) |