diff options
Diffstat (limited to 'sound/pci/ctxfi/ctatc.c')
-rw-r--r-- | sound/pci/ctxfi/ctatc.c | 206 |
1 files changed, 152 insertions, 54 deletions
diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index b0adc8094009..a49c76647307 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c | |||
@@ -46,8 +46,6 @@ static struct snd_pci_quirk __devinitdata subsys_20k1_list[] = { | |||
46 | SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0031, "SB073x", CTSB073X), | 46 | SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0031, "SB073x", CTSB073X), |
47 | SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000, 0x6000, | 47 | SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000, 0x6000, |
48 | "UAA", CTUAA), | 48 | "UAA", CTUAA), |
49 | SND_PCI_QUIRK_VENDOR(PCI_VENDOR_ID_CREATIVE, | ||
50 | "Unknown", CT20K1_UNKNOWN), | ||
51 | { } /* terminator */ | 49 | { } /* terminator */ |
52 | }; | 50 | }; |
53 | 51 | ||
@@ -67,13 +65,16 @@ static struct snd_pci_quirk __devinitdata subsys_20k2_list[] = { | |||
67 | }; | 65 | }; |
68 | 66 | ||
69 | static const char *ct_subsys_name[NUM_CTCARDS] = { | 67 | static const char *ct_subsys_name[NUM_CTCARDS] = { |
68 | /* 20k1 models */ | ||
70 | [CTSB055X] = "SB055x", | 69 | [CTSB055X] = "SB055x", |
71 | [CTSB073X] = "SB073x", | 70 | [CTSB073X] = "SB073x", |
72 | [CTSB0760] = "SB076x", | ||
73 | [CTUAA] = "UAA", | 71 | [CTUAA] = "UAA", |
74 | [CT20K1_UNKNOWN] = "Unknown", | 72 | [CT20K1_UNKNOWN] = "Unknown", |
73 | /* 20k2 models */ | ||
74 | [CTSB0760] = "SB076x", | ||
75 | [CTHENDRIX] = "Hendrix", | 75 | [CTHENDRIX] = "Hendrix", |
76 | [CTSB0880] = "SB0880", | 76 | [CTSB0880] = "SB0880", |
77 | [CT20K2_UNKNOWN] = "Unknown", | ||
77 | }; | 78 | }; |
78 | 79 | ||
79 | static struct { | 80 | static struct { |
@@ -260,13 +261,8 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) | |||
260 | int device = apcm->substream->pcm->device; | 261 | int device = apcm->substream->pcm->device; |
261 | unsigned int pitch; | 262 | unsigned int pitch; |
262 | 263 | ||
263 | if (NULL != apcm->src) { | ||
264 | /* Prepared pcm playback */ | ||
265 | return 0; | ||
266 | } | ||
267 | |||
268 | /* first release old resources */ | 264 | /* first release old resources */ |
269 | atc->pcm_release_resources(atc, apcm); | 265 | atc_pcm_release_resources(atc, apcm); |
270 | 266 | ||
271 | /* Get SRC resource */ | 267 | /* Get SRC resource */ |
272 | desc.multi = apcm->substream->runtime->channels; | 268 | desc.multi = apcm->substream->runtime->channels; |
@@ -660,10 +656,7 @@ static int atc_pcm_capture_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) | |||
660 | unsigned int pitch; | 656 | unsigned int pitch; |
661 | int mix_base = 0, imp_base = 0; | 657 | int mix_base = 0, imp_base = 0; |
662 | 658 | ||
663 | if (NULL != apcm->src) { | 659 | atc_pcm_release_resources(atc, apcm); |
664 | /* Prepared pcm capture */ | ||
665 | return 0; | ||
666 | } | ||
667 | 660 | ||
668 | /* Get needed resources. */ | 661 | /* Get needed resources. */ |
669 | err = atc_pcm_capture_get_resources(atc, apcm); | 662 | err = atc_pcm_capture_get_resources(atc, apcm); |
@@ -866,7 +859,7 @@ spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm) | |||
866 | struct dao *dao = container_of(atc->daios[SPDIFOO], struct dao, daio); | 859 | struct dao *dao = container_of(atc->daios[SPDIFOO], struct dao, daio); |
867 | unsigned int rate = apcm->substream->runtime->rate; | 860 | unsigned int rate = apcm->substream->runtime->rate; |
868 | unsigned int status; | 861 | unsigned int status; |
869 | int err; | 862 | int err = 0; |
870 | unsigned char iec958_con_fs; | 863 | unsigned char iec958_con_fs; |
871 | 864 | ||
872 | switch (rate) { | 865 | switch (rate) { |
@@ -907,8 +900,7 @@ spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) | |||
907 | int err; | 900 | int err; |
908 | int i; | 901 | int i; |
909 | 902 | ||
910 | if (NULL != apcm->src) | 903 | atc_pcm_release_resources(atc, apcm); |
911 | return 0; | ||
912 | 904 | ||
913 | /* Configure SPDIFOO and PLL to passthrough mode; | 905 | /* Configure SPDIFOO and PLL to passthrough mode; |
914 | * determine pll_rate. */ | 906 | * determine pll_rate. */ |
@@ -1115,32 +1107,20 @@ static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state) | |||
1115 | return err; | 1107 | return err; |
1116 | } | 1108 | } |
1117 | 1109 | ||
1118 | static int ct_atc_destroy(struct ct_atc *atc) | 1110 | static int atc_release_resources(struct ct_atc *atc) |
1119 | { | 1111 | { |
1120 | struct daio_mgr *daio_mgr; | 1112 | int i; |
1121 | struct dao *dao; | 1113 | struct daio_mgr *daio_mgr = NULL; |
1122 | struct dai *dai; | 1114 | struct dao *dao = NULL; |
1123 | struct daio *daio; | 1115 | struct dai *dai = NULL; |
1124 | struct sum_mgr *sum_mgr; | 1116 | struct daio *daio = NULL; |
1125 | struct src_mgr *src_mgr; | 1117 | struct sum_mgr *sum_mgr = NULL; |
1126 | struct srcimp_mgr *srcimp_mgr; | 1118 | struct src_mgr *src_mgr = NULL; |
1127 | struct srcimp *srcimp; | 1119 | struct srcimp_mgr *srcimp_mgr = NULL; |
1128 | struct ct_mixer *mixer; | 1120 | struct srcimp *srcimp = NULL; |
1129 | int i = 0; | 1121 | struct ct_mixer *mixer = NULL; |
1130 | 1122 | ||
1131 | if (NULL == atc) | 1123 | /* disconnect internal mixer objects */ |
1132 | return 0; | ||
1133 | |||
1134 | if (atc->timer) { | ||
1135 | ct_timer_free(atc->timer); | ||
1136 | atc->timer = NULL; | ||
1137 | } | ||
1138 | |||
1139 | /* Stop hardware and disable all interrupts */ | ||
1140 | if (NULL != atc->hw) | ||
1141 | ((struct hw *)atc->hw)->card_stop(atc->hw); | ||
1142 | |||
1143 | /* Destroy internal mixer objects */ | ||
1144 | if (NULL != atc->mixer) { | 1124 | if (NULL != atc->mixer) { |
1145 | mixer = atc->mixer; | 1125 | mixer = atc->mixer; |
1146 | mixer->set_input_left(mixer, MIX_LINE_IN, NULL); | 1126 | mixer->set_input_left(mixer, MIX_LINE_IN, NULL); |
@@ -1149,7 +1129,6 @@ static int ct_atc_destroy(struct ct_atc *atc) | |||
1149 | mixer->set_input_right(mixer, MIX_MIC_IN, NULL); | 1129 | mixer->set_input_right(mixer, MIX_MIC_IN, NULL); |
1150 | mixer->set_input_left(mixer, MIX_SPDIF_IN, NULL); | 1130 | mixer->set_input_left(mixer, MIX_SPDIF_IN, NULL); |
1151 | mixer->set_input_right(mixer, MIX_SPDIF_IN, NULL); | 1131 | mixer->set_input_right(mixer, MIX_SPDIF_IN, NULL); |
1152 | ct_mixer_destroy(atc->mixer); | ||
1153 | } | 1132 | } |
1154 | 1133 | ||
1155 | if (NULL != atc->daios) { | 1134 | if (NULL != atc->daios) { |
@@ -1167,6 +1146,7 @@ static int ct_atc_destroy(struct ct_atc *atc) | |||
1167 | daio_mgr->put_daio(daio_mgr, daio); | 1146 | daio_mgr->put_daio(daio_mgr, daio); |
1168 | } | 1147 | } |
1169 | kfree(atc->daios); | 1148 | kfree(atc->daios); |
1149 | atc->daios = NULL; | ||
1170 | } | 1150 | } |
1171 | 1151 | ||
1172 | if (NULL != atc->pcm) { | 1152 | if (NULL != atc->pcm) { |
@@ -1175,6 +1155,7 @@ static int ct_atc_destroy(struct ct_atc *atc) | |||
1175 | sum_mgr->put_sum(sum_mgr, atc->pcm[i]); | 1155 | sum_mgr->put_sum(sum_mgr, atc->pcm[i]); |
1176 | 1156 | ||
1177 | kfree(atc->pcm); | 1157 | kfree(atc->pcm); |
1158 | atc->pcm = NULL; | ||
1178 | } | 1159 | } |
1179 | 1160 | ||
1180 | if (NULL != atc->srcs) { | 1161 | if (NULL != atc->srcs) { |
@@ -1183,6 +1164,7 @@ static int ct_atc_destroy(struct ct_atc *atc) | |||
1183 | src_mgr->put_src(src_mgr, atc->srcs[i]); | 1164 | src_mgr->put_src(src_mgr, atc->srcs[i]); |
1184 | 1165 | ||
1185 | kfree(atc->srcs); | 1166 | kfree(atc->srcs); |
1167 | atc->srcs = NULL; | ||
1186 | } | 1168 | } |
1187 | 1169 | ||
1188 | if (NULL != atc->srcimps) { | 1170 | if (NULL != atc->srcimps) { |
@@ -1193,8 +1175,30 @@ static int ct_atc_destroy(struct ct_atc *atc) | |||
1193 | srcimp_mgr->put_srcimp(srcimp_mgr, atc->srcimps[i]); | 1175 | srcimp_mgr->put_srcimp(srcimp_mgr, atc->srcimps[i]); |
1194 | } | 1176 | } |
1195 | kfree(atc->srcimps); | 1177 | kfree(atc->srcimps); |
1178 | atc->srcimps = NULL; | ||
1179 | } | ||
1180 | |||
1181 | return 0; | ||
1182 | } | ||
1183 | |||
1184 | static int ct_atc_destroy(struct ct_atc *atc) | ||
1185 | { | ||
1186 | int i = 0; | ||
1187 | |||
1188 | if (NULL == atc) | ||
1189 | return 0; | ||
1190 | |||
1191 | if (atc->timer) { | ||
1192 | ct_timer_free(atc->timer); | ||
1193 | atc->timer = NULL; | ||
1196 | } | 1194 | } |
1197 | 1195 | ||
1196 | atc_release_resources(atc); | ||
1197 | |||
1198 | /* Destroy internal mixer objects */ | ||
1199 | if (NULL != atc->mixer) | ||
1200 | ct_mixer_destroy(atc->mixer); | ||
1201 | |||
1198 | for (i = 0; i < NUM_RSCTYP; i++) { | 1202 | for (i = 0; i < NUM_RSCTYP; i++) { |
1199 | if ((NULL != rsc_mgr_funcs[i].destroy) && | 1203 | if ((NULL != rsc_mgr_funcs[i].destroy) && |
1200 | (NULL != atc->rsc_mgrs[i])) | 1204 | (NULL != atc->rsc_mgrs[i])) |
@@ -1240,9 +1244,21 @@ static int __devinit atc_identify_card(struct ct_atc *atc) | |||
1240 | return -ENOENT; | 1244 | return -ENOENT; |
1241 | } | 1245 | } |
1242 | p = snd_pci_quirk_lookup(atc->pci, list); | 1246 | p = snd_pci_quirk_lookup(atc->pci, list); |
1243 | if (!p) | 1247 | if (p) { |
1244 | return -ENOENT; | 1248 | if (p->value < 0) { |
1245 | atc->model = p->value; | 1249 | printk(KERN_ERR "ctxfi: " |
1250 | "Device %04x:%04x is black-listed\n", | ||
1251 | atc->pci->subsystem_vendor, | ||
1252 | atc->pci->subsystem_device); | ||
1253 | return -ENOENT; | ||
1254 | } | ||
1255 | atc->model = p->value; | ||
1256 | } else { | ||
1257 | if (atc->chip_type == ATC20K1) | ||
1258 | atc->model = CT20K1_UNKNOWN; | ||
1259 | else | ||
1260 | atc->model = CT20K2_UNKNOWN; | ||
1261 | } | ||
1246 | atc->model_name = ct_subsys_name[atc->model]; | 1262 | atc->model_name = ct_subsys_name[atc->model]; |
1247 | snd_printd("ctxfi: chip %s model %s (%04x:%04x) is found\n", | 1263 | snd_printd("ctxfi: chip %s model %s (%04x:%04x) is found\n", |
1248 | atc->chip_name, atc->model_name, | 1264 | atc->chip_name, atc->model_name, |
@@ -1310,7 +1326,7 @@ static int __devinit atc_create_hw_devs(struct ct_atc *atc) | |||
1310 | return 0; | 1326 | return 0; |
1311 | } | 1327 | } |
1312 | 1328 | ||
1313 | static int __devinit atc_get_resources(struct ct_atc *atc) | 1329 | static int atc_get_resources(struct ct_atc *atc) |
1314 | { | 1330 | { |
1315 | struct daio_desc da_desc = {0}; | 1331 | struct daio_desc da_desc = {0}; |
1316 | struct daio_mgr *daio_mgr; | 1332 | struct daio_mgr *daio_mgr; |
@@ -1407,16 +1423,10 @@ static int __devinit atc_get_resources(struct ct_atc *atc) | |||
1407 | atc->n_pcm++; | 1423 | atc->n_pcm++; |
1408 | } | 1424 | } |
1409 | 1425 | ||
1410 | err = ct_mixer_create(atc, (struct ct_mixer **)&atc->mixer); | ||
1411 | if (err) { | ||
1412 | printk(KERN_ERR "ctxfi: Failed to create mixer obj!!!\n"); | ||
1413 | return err; | ||
1414 | } | ||
1415 | |||
1416 | return 0; | 1426 | return 0; |
1417 | } | 1427 | } |
1418 | 1428 | ||
1419 | static void __devinit | 1429 | static void |
1420 | atc_connect_dai(struct src_mgr *src_mgr, struct dai *dai, | 1430 | atc_connect_dai(struct src_mgr *src_mgr, struct dai *dai, |
1421 | struct src **srcs, struct srcimp **srcimps) | 1431 | struct src **srcs, struct srcimp **srcimps) |
1422 | { | 1432 | { |
@@ -1455,7 +1465,7 @@ atc_connect_dai(struct src_mgr *src_mgr, struct dai *dai, | |||
1455 | src_mgr->commit_write(src_mgr); /* Synchronously enable SRCs */ | 1465 | src_mgr->commit_write(src_mgr); /* Synchronously enable SRCs */ |
1456 | } | 1466 | } |
1457 | 1467 | ||
1458 | static void __devinit atc_connect_resources(struct ct_atc *atc) | 1468 | static void atc_connect_resources(struct ct_atc *atc) |
1459 | { | 1469 | { |
1460 | struct dai *dai; | 1470 | struct dai *dai; |
1461 | struct dao *dao; | 1471 | struct dao *dao; |
@@ -1501,6 +1511,84 @@ static void __devinit atc_connect_resources(struct ct_atc *atc) | |||
1501 | } | 1511 | } |
1502 | } | 1512 | } |
1503 | 1513 | ||
1514 | #ifdef CONFIG_PM | ||
1515 | static int atc_suspend(struct ct_atc *atc, pm_message_t state) | ||
1516 | { | ||
1517 | int i; | ||
1518 | struct hw *hw = atc->hw; | ||
1519 | |||
1520 | snd_power_change_state(atc->card, SNDRV_CTL_POWER_D3hot); | ||
1521 | |||
1522 | for (i = FRONT; i < NUM_PCMS; i++) { | ||
1523 | if (!atc->pcms[i]) | ||
1524 | continue; | ||
1525 | |||
1526 | snd_pcm_suspend_all(atc->pcms[i]); | ||
1527 | } | ||
1528 | |||
1529 | atc_release_resources(atc); | ||
1530 | |||
1531 | hw->suspend(hw, state); | ||
1532 | |||
1533 | return 0; | ||
1534 | } | ||
1535 | |||
1536 | static int atc_hw_resume(struct ct_atc *atc) | ||
1537 | { | ||
1538 | struct hw *hw = atc->hw; | ||
1539 | struct card_conf info = {0}; | ||
1540 | |||
1541 | /* Re-initialize card hardware. */ | ||
1542 | info.rsr = atc->rsr; | ||
1543 | info.msr = atc->msr; | ||
1544 | info.vm_pgt_phys = atc_get_ptp_phys(atc, 0); | ||
1545 | return hw->resume(hw, &info); | ||
1546 | } | ||
1547 | |||
1548 | static int atc_resources_resume(struct ct_atc *atc) | ||
1549 | { | ||
1550 | struct ct_mixer *mixer; | ||
1551 | int err = 0; | ||
1552 | |||
1553 | /* Get resources */ | ||
1554 | err = atc_get_resources(atc); | ||
1555 | if (err < 0) { | ||
1556 | atc_release_resources(atc); | ||
1557 | return err; | ||
1558 | } | ||
1559 | |||
1560 | /* Build topology */ | ||
1561 | atc_connect_resources(atc); | ||
1562 | |||
1563 | mixer = atc->mixer; | ||
1564 | mixer->resume(mixer); | ||
1565 | |||
1566 | return 0; | ||
1567 | } | ||
1568 | |||
1569 | static int atc_resume(struct ct_atc *atc) | ||
1570 | { | ||
1571 | int err = 0; | ||
1572 | |||
1573 | /* Do hardware resume. */ | ||
1574 | err = atc_hw_resume(atc); | ||
1575 | if (err < 0) { | ||
1576 | printk(KERN_ERR "ctxfi: pci_enable_device failed, " | ||
1577 | "disabling device\n"); | ||
1578 | snd_card_disconnect(atc->card); | ||
1579 | return err; | ||
1580 | } | ||
1581 | |||
1582 | err = atc_resources_resume(atc); | ||
1583 | if (err < 0) | ||
1584 | return err; | ||
1585 | |||
1586 | snd_power_change_state(atc->card, SNDRV_CTL_POWER_D0); | ||
1587 | |||
1588 | return 0; | ||
1589 | } | ||
1590 | #endif | ||
1591 | |||
1504 | static struct ct_atc atc_preset __devinitdata = { | 1592 | static struct ct_atc atc_preset __devinitdata = { |
1505 | .map_audio_buffer = ct_map_audio_buffer, | 1593 | .map_audio_buffer = ct_map_audio_buffer, |
1506 | .unmap_audio_buffer = ct_unmap_audio_buffer, | 1594 | .unmap_audio_buffer = ct_unmap_audio_buffer, |
@@ -1529,6 +1617,10 @@ static struct ct_atc atc_preset __devinitdata = { | |||
1529 | .spdif_out_set_status = atc_spdif_out_set_status, | 1617 | .spdif_out_set_status = atc_spdif_out_set_status, |
1530 | .spdif_out_passthru = atc_spdif_out_passthru, | 1618 | .spdif_out_passthru = atc_spdif_out_passthru, |
1531 | .have_digit_io_switch = atc_have_digit_io_switch, | 1619 | .have_digit_io_switch = atc_have_digit_io_switch, |
1620 | #ifdef CONFIG_PM | ||
1621 | .suspend = atc_suspend, | ||
1622 | .resume = atc_resume, | ||
1623 | #endif | ||
1532 | }; | 1624 | }; |
1533 | 1625 | ||
1534 | /** | 1626 | /** |
@@ -1587,6 +1679,12 @@ int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, | |||
1587 | if (err < 0) | 1679 | if (err < 0) |
1588 | goto error1; | 1680 | goto error1; |
1589 | 1681 | ||
1682 | err = ct_mixer_create(atc, (struct ct_mixer **)&atc->mixer); | ||
1683 | if (err) { | ||
1684 | printk(KERN_ERR "ctxfi: Failed to create mixer obj!!!\n"); | ||
1685 | goto error1; | ||
1686 | } | ||
1687 | |||
1590 | /* Get resources */ | 1688 | /* Get resources */ |
1591 | err = atc_get_resources(atc); | 1689 | err = atc_get_resources(atc); |
1592 | if (err < 0) | 1690 | if (err < 0) |