diff options
Diffstat (limited to 'sound/isa/wss/wss_lib.c')
-rw-r--r-- | sound/isa/wss/wss_lib.c | 150 |
1 files changed, 120 insertions, 30 deletions
diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c index 57d1e8ee6bbb..a5602f515f49 100644 --- a/sound/isa/wss/wss_lib.c +++ b/sound/isa/wss/wss_lib.c | |||
@@ -1073,7 +1073,11 @@ irqreturn_t snd_wss_interrupt(int irq, void *dev_id) | |||
1073 | struct snd_wss *chip = dev_id; | 1073 | struct snd_wss *chip = dev_id; |
1074 | unsigned char status; | 1074 | unsigned char status; |
1075 | 1075 | ||
1076 | status = snd_wss_in(chip, CS4231_IRQ_STATUS); | 1076 | if (chip->hardware & WSS_HW_AD1848_MASK) |
1077 | /* pretend it was the only possible irq for AD1848 */ | ||
1078 | status = CS4231_PLAYBACK_IRQ; | ||
1079 | else | ||
1080 | status = snd_wss_in(chip, CS4231_IRQ_STATUS); | ||
1077 | if (status & CS4231_TIMER_IRQ) { | 1081 | if (status & CS4231_TIMER_IRQ) { |
1078 | if (chip->timer) | 1082 | if (chip->timer) |
1079 | snd_timer_interrupt(chip->timer, chip->timer->sticks); | 1083 | snd_timer_interrupt(chip->timer, chip->timer->sticks); |
@@ -1105,7 +1109,11 @@ irqreturn_t snd_wss_interrupt(int irq, void *dev_id) | |||
1105 | } | 1109 | } |
1106 | 1110 | ||
1107 | spin_lock(&chip->reg_lock); | 1111 | spin_lock(&chip->reg_lock); |
1108 | snd_wss_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0); | 1112 | status = ~CS4231_ALL_IRQS | ~status; |
1113 | if (chip->hardware & WSS_HW_AD1848_MASK) | ||
1114 | wss_outb(chip, CS4231P(STATUS), 0); | ||
1115 | else | ||
1116 | snd_wss_outm(chip, CS4231_IRQ_STATUS, status, 0); | ||
1109 | spin_unlock(&chip->reg_lock); | 1117 | spin_unlock(&chip->reg_lock); |
1110 | return IRQ_HANDLED; | 1118 | return IRQ_HANDLED; |
1111 | } | 1119 | } |
@@ -1137,36 +1145,112 @@ static snd_pcm_uframes_t snd_wss_capture_pointer(struct snd_pcm_substream *subst | |||
1137 | 1145 | ||
1138 | */ | 1146 | */ |
1139 | 1147 | ||
1140 | static int snd_wss_probe(struct snd_wss *chip) | 1148 | static int snd_ad1848_probe(struct snd_wss *chip) |
1141 | { | 1149 | { |
1142 | unsigned long flags; | 1150 | unsigned long flags; |
1143 | int i, id, rev; | 1151 | int i, id, rev, ad1847; |
1144 | unsigned char *ptr; | ||
1145 | unsigned int hw; | ||
1146 | 1152 | ||
1147 | #if 0 | ||
1148 | snd_wss_debug(chip); | ||
1149 | #endif | ||
1150 | id = 0; | 1153 | id = 0; |
1151 | for (i = 0; i < 50; i++) { | 1154 | ad1847 = 0; |
1155 | for (i = 0; i < 1000; i++) { | ||
1152 | mb(); | 1156 | mb(); |
1153 | if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) | 1157 | if (inb(chip->port + CS4231P(REGSEL)) & CS4231_INIT) |
1154 | udelay(2000); | 1158 | msleep(1); |
1155 | else { | 1159 | else { |
1156 | spin_lock_irqsave(&chip->reg_lock, flags); | 1160 | spin_lock_irqsave(&chip->reg_lock, flags); |
1157 | snd_wss_out(chip, CS4231_MISC_INFO, CS4231_MODE2); | 1161 | snd_wss_out(chip, CS4231_MISC_INFO, 0x00); |
1158 | id = snd_wss_in(chip, CS4231_MISC_INFO) & 0x0f; | 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 (snd_wss_in(chip, CS4231_LEFT_INPUT) == 0xaa && | ||
1172 | rev == 0x45) { | ||
1173 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
1174 | id = 1; | ||
1175 | break; | ||
1176 | } | ||
1159 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 1177 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
1160 | if (id == 0x0a) | ||
1161 | break; /* this is valid value */ | ||
1162 | } | 1178 | } |
1163 | } | 1179 | } |
1164 | snd_printdd("wss: port = 0x%lx, id = 0x%x\n", chip->port, id); | 1180 | if (id != 1) |
1165 | if (id != 0x0a) | ||
1166 | return -ENODEV; /* no valid device found */ | 1181 | return -ENODEV; /* no valid device found */ |
1182 | id = 0; | ||
1183 | if (chip->hardware == WSS_HW_DETECT) | ||
1184 | id = ad1847 ? WSS_HW_AD1847 : WSS_HW_AD1848; | ||
1185 | |||
1186 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
1187 | inb(chip->port + CS4231P(STATUS)); /* clear any pendings IRQ */ | ||
1188 | outb(0, chip->port + CS4231P(STATUS)); | ||
1189 | mb(); | ||
1190 | if (id == WSS_HW_AD1848) { | ||
1191 | /* check if there are more than 16 registers */ | ||
1192 | rev = snd_wss_in(chip, CS4231_MISC_INFO); | ||
1193 | snd_wss_out(chip, CS4231_MISC_INFO, 0x40); | ||
1194 | for (i = 0; i < 16; ++i) { | ||
1195 | if (snd_wss_in(chip, i) != snd_wss_in(chip, i + 16)) { | ||
1196 | id = WSS_HW_CMI8330; | ||
1197 | break; | ||
1198 | } | ||
1199 | } | ||
1200 | snd_wss_out(chip, CS4231_MISC_INFO, 0x00); | ||
1201 | if (id != WSS_HW_CMI8330 && (rev & 0x80)) | ||
1202 | id = WSS_HW_CS4248; | ||
1203 | if (id == WSS_HW_CMI8330 && (rev & 0x0f) != 0x0a) | ||
1204 | id = 0; | ||
1205 | } | ||
1206 | if (id == WSS_HW_CMI8330) { | ||
1207 | /* verify it is not CS4231 by changing the version register */ | ||
1208 | /* on CMI8330 it is volume control register and can be set 0 */ | ||
1209 | snd_wss_out(chip, CS4231_MISC_INFO, CS4231_MODE2); | ||
1210 | snd_wss_dout(chip, CS4231_VERSION, 0x00); | ||
1211 | rev = snd_wss_in(chip, CS4231_VERSION) & 0xe7; | ||
1212 | if (rev) | ||
1213 | id = 0; | ||
1214 | snd_wss_out(chip, CS4231_MISC_INFO, 0); | ||
1215 | } | ||
1216 | if (id) | ||
1217 | chip->hardware = id; | ||
1218 | |||
1219 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
1220 | return 0; /* all things are ok.. */ | ||
1221 | } | ||
1222 | |||
1223 | static int snd_wss_probe(struct snd_wss *chip) | ||
1224 | { | ||
1225 | unsigned long flags; | ||
1226 | int i, id, rev, regnum; | ||
1227 | unsigned char *ptr; | ||
1228 | unsigned int hw; | ||
1229 | |||
1230 | id = snd_ad1848_probe(chip); | ||
1231 | if (id < 0) | ||
1232 | return id; | ||
1167 | 1233 | ||
1168 | hw = chip->hardware; | 1234 | hw = chip->hardware; |
1169 | if ((hw & WSS_HW_TYPE_MASK) == WSS_HW_DETECT) { | 1235 | if ((hw & WSS_HW_TYPE_MASK) == WSS_HW_DETECT) { |
1236 | for (i = 0; i < 50; i++) { | ||
1237 | mb(); | ||
1238 | if (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT) | ||
1239 | msleep(2); | ||
1240 | else { | ||
1241 | spin_lock_irqsave(&chip->reg_lock, flags); | ||
1242 | snd_wss_out(chip, CS4231_MISC_INFO, | ||
1243 | CS4231_MODE2); | ||
1244 | id = snd_wss_in(chip, CS4231_MISC_INFO) & 0x0f; | ||
1245 | spin_unlock_irqrestore(&chip->reg_lock, flags); | ||
1246 | if (id == 0x0a) | ||
1247 | break; /* this is valid value */ | ||
1248 | } | ||
1249 | } | ||
1250 | snd_printdd("wss: port = 0x%lx, id = 0x%x\n", chip->port, id); | ||
1251 | if (id != 0x0a) | ||
1252 | return -ENODEV; /* no valid device found */ | ||
1253 | |||
1170 | rev = snd_wss_in(chip, CS4231_VERSION) & 0xe7; | 1254 | rev = snd_wss_in(chip, CS4231_VERSION) & 0xe7; |
1171 | snd_printdd("CS4231: VERSION (I25) = 0x%x\n", rev); | 1255 | snd_printdd("CS4231: VERSION (I25) = 0x%x\n", rev); |
1172 | if (rev == 0x80) { | 1256 | if (rev == 0x80) { |
@@ -1197,7 +1281,8 @@ static int snd_wss_probe(struct snd_wss *chip) | |||
1197 | mb(); | 1281 | mb(); |
1198 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 1282 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
1199 | 1283 | ||
1200 | chip->image[CS4231_MISC_INFO] = CS4231_MODE2; | 1284 | if (!(chip->hardware & WSS_HW_AD1848_MASK)) |
1285 | chip->image[CS4231_MISC_INFO] = CS4231_MODE2; | ||
1201 | switch (chip->hardware) { | 1286 | switch (chip->hardware) { |
1202 | case WSS_HW_INTERWAVE: | 1287 | case WSS_HW_INTERWAVE: |
1203 | chip->image[CS4231_MISC_INFO] = CS4231_IW_MODE3; | 1288 | chip->image[CS4231_MISC_INFO] = CS4231_IW_MODE3; |
@@ -1223,9 +1308,10 @@ static int snd_wss_probe(struct snd_wss *chip) | |||
1223 | chip->hardware == WSS_HW_INTERWAVE ? 0xc2 : 0x01; | 1308 | chip->hardware == WSS_HW_INTERWAVE ? 0xc2 : 0x01; |
1224 | } | 1309 | } |
1225 | ptr = (unsigned char *) &chip->image; | 1310 | ptr = (unsigned char *) &chip->image; |
1311 | regnum = (chip->hardware & WSS_HW_AD1848_MASK) ? 16 : 32; | ||
1226 | snd_wss_mce_down(chip); | 1312 | snd_wss_mce_down(chip); |
1227 | spin_lock_irqsave(&chip->reg_lock, flags); | 1313 | spin_lock_irqsave(&chip->reg_lock, flags); |
1228 | for (i = 0; i < 32; i++) /* ok.. fill all CS4231 registers */ | 1314 | for (i = 0; i < regnum; i++) /* ok.. fill all registers */ |
1229 | snd_wss_out(chip, i, *ptr++); | 1315 | snd_wss_out(chip, i, *ptr++); |
1230 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 1316 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
1231 | snd_wss_mce_up(chip); | 1317 | snd_wss_mce_up(chip); |
@@ -1635,6 +1721,10 @@ static int snd_wss_new(struct snd_card *card, | |||
1635 | else | 1721 | else |
1636 | memcpy(&chip->image, &snd_wss_original_image, | 1722 | memcpy(&chip->image, &snd_wss_original_image, |
1637 | sizeof(snd_wss_original_image)); | 1723 | sizeof(snd_wss_original_image)); |
1724 | if (chip->hardware & WSS_HW_AD1848_MASK) { | ||
1725 | chip->image[CS4231_PIN_CTRL] = 0; | ||
1726 | chip->image[CS4231_TEST_INIT] = 0; | ||
1727 | } | ||
1638 | 1728 | ||
1639 | *rchip = chip; | 1729 | *rchip = chip; |
1640 | return 0; | 1730 | return 0; |
@@ -1662,7 +1752,7 @@ int snd_wss_create(struct snd_card *card, | |||
1662 | chip->dma1 = -1; | 1752 | chip->dma1 = -1; |
1663 | chip->dma2 = -1; | 1753 | chip->dma2 = -1; |
1664 | 1754 | ||
1665 | chip->res_port = request_region(port, 4, "CS4231"); | 1755 | chip->res_port = request_region(port, 4, "WSS"); |
1666 | if (!chip->res_port) { | 1756 | if (!chip->res_port) { |
1667 | snd_printk(KERN_ERR "wss: can't grab port 0x%lx\n", port); | 1757 | snd_printk(KERN_ERR "wss: can't grab port 0x%lx\n", port); |
1668 | snd_wss_free(chip); | 1758 | snd_wss_free(chip); |
@@ -1681,20 +1771,20 @@ int snd_wss_create(struct snd_card *card, | |||
1681 | chip->cport = cport; | 1771 | chip->cport = cport; |
1682 | if (!(hwshare & WSS_HWSHARE_IRQ)) | 1772 | if (!(hwshare & WSS_HWSHARE_IRQ)) |
1683 | if (request_irq(irq, snd_wss_interrupt, IRQF_DISABLED, | 1773 | if (request_irq(irq, snd_wss_interrupt, IRQF_DISABLED, |
1684 | "CS4231", (void *) chip)) { | 1774 | "WSS", (void *) chip)) { |
1685 | snd_printk(KERN_ERR "wss: can't grab IRQ %d\n", irq); | 1775 | snd_printk(KERN_ERR "wss: can't grab IRQ %d\n", irq); |
1686 | snd_wss_free(chip); | 1776 | snd_wss_free(chip); |
1687 | return -EBUSY; | 1777 | return -EBUSY; |
1688 | } | 1778 | } |
1689 | chip->irq = irq; | 1779 | chip->irq = irq; |
1690 | if (!(hwshare & WSS_HWSHARE_DMA1) && request_dma(dma1, "CS4231 - 1")) { | 1780 | if (!(hwshare & WSS_HWSHARE_DMA1) && request_dma(dma1, "WSS - 1")) { |
1691 | snd_printk(KERN_ERR "wss: can't grab DMA1 %d\n", dma1); | 1781 | snd_printk(KERN_ERR "wss: can't grab DMA1 %d\n", dma1); |
1692 | snd_wss_free(chip); | 1782 | snd_wss_free(chip); |
1693 | return -EBUSY; | 1783 | return -EBUSY; |
1694 | } | 1784 | } |
1695 | chip->dma1 = dma1; | 1785 | chip->dma1 = dma1; |
1696 | if (!(hwshare & WSS_HWSHARE_DMA2) && dma1 != dma2 && | 1786 | if (!(hwshare & WSS_HWSHARE_DMA2) && dma1 != dma2 && |
1697 | dma2 >= 0 && request_dma(dma2, "CS4231 - 2")) { | 1787 | dma2 >= 0 && request_dma(dma2, "WSS - 2")) { |
1698 | snd_printk(KERN_ERR "wss: can't grab DMA2 %d\n", dma2); | 1788 | snd_printk(KERN_ERR "wss: can't grab DMA2 %d\n", dma2); |
1699 | snd_wss_free(chip); | 1789 | snd_wss_free(chip); |
1700 | return -EBUSY; | 1790 | return -EBUSY; |
@@ -1705,6 +1795,12 @@ int snd_wss_create(struct snd_card *card, | |||
1705 | } else | 1795 | } else |
1706 | chip->dma2 = dma2; | 1796 | chip->dma2 = dma2; |
1707 | 1797 | ||
1798 | if (hardware == WSS_HW_THINKPAD) { | ||
1799 | chip->thinkpad_flag = 1; | ||
1800 | chip->hardware = WSS_HW_DETECT; /* reset */ | ||
1801 | snd_wss_thinkpad_twiddle(chip, 1); | ||
1802 | } | ||
1803 | |||
1708 | /* global setup */ | 1804 | /* global setup */ |
1709 | if (snd_wss_probe(chip) < 0) { | 1805 | if (snd_wss_probe(chip) < 0) { |
1710 | snd_wss_free(chip); | 1806 | snd_wss_free(chip); |
@@ -1775,12 +1871,6 @@ int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm) | |||
1775 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_wss_playback_ops); | 1871 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_wss_playback_ops); |
1776 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_wss_capture_ops); | 1872 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_wss_capture_ops); |
1777 | 1873 | ||
1778 | /* temporary */ | ||
1779 | if (chip->hardware & WSS_HW_AD1848_MASK) { | ||
1780 | chip->rate_constraint = snd_wss_xrate; | ||
1781 | chip->set_playback_format = snd_wss_playback_format; | ||
1782 | chip->set_capture_format = snd_wss_capture_format; | ||
1783 | } | ||
1784 | /* global setup */ | 1874 | /* global setup */ |
1785 | pcm->private_data = chip; | 1875 | pcm->private_data = chip; |
1786 | pcm->info_flags = 0; | 1876 | pcm->info_flags = 0; |