diff options
Diffstat (limited to 'sound/pci/ctxfi/ctatc.c')
| -rw-r--r-- | sound/pci/ctxfi/ctatc.c | 187 |
1 files changed, 111 insertions, 76 deletions
diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c index 908658a00377..227d8c8490e1 100644 --- a/sound/pci/ctxfi/ctatc.c +++ b/sound/pci/ctxfi/ctatc.c @@ -1,10 +1,7 @@ -/** +// SPDX-License-Identifier: GPL-2.0-only +/* * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. * - * This source file is released under GPL v2 license (no other versions). - * See the COPYING file included in the main directory of this source - * distribution for the license terms and conditions. - * * @File ctatc.c * * @Brief @@ -28,6 +25,9 @@ #include <sound/control.h> #include <sound/asoundef.h> +#define NUM_ATC_SRCS 6 +#define NUM_ATC_PCM (2 * 4) + #define MONO_SUM_SCALE 0x19a8 /* 2^(-0.5) in 14-bit floating format */ #define MAX_MULTI_CHN 8 @@ -38,7 +38,8 @@ | (0x10 << 16) \ | ((IEC958_AES3_CON_FS_48000) << 24)) -static struct snd_pci_quirk subsys_20k1_list[] = { +static const struct snd_pci_quirk subsys_20k1_list[] = { + SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0021, "SB046x", CTSB046X), SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0022, "SB055x", CTSB055X), SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x002f, "SB055x", CTSB055X), SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0029, "SB073x", CTSB073X), @@ -48,7 +49,7 @@ static struct snd_pci_quirk subsys_20k1_list[] = { { } /* terminator */ }; -static struct snd_pci_quirk subsys_20k2_list[] = { +static const struct snd_pci_quirk subsys_20k2_list[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB0760, "SB0760", CTSB0760), SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB1270, @@ -62,11 +63,13 @@ static struct snd_pci_quirk subsys_20k2_list[] = { SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000, PCI_SUBDEVICE_ID_CREATIVE_HENDRIX, "HENDRIX", CTHENDRIX), + SND_PCI_QUIRK(0x160b, 0x0101, "OK0010", CTOK0010), { } /* terminator */ }; static const char *ct_subsys_name[NUM_CTCARDS] = { /* 20k1 models */ + [CTSB046X] = "SB046x", [CTSB055X] = "SB055x", [CTSB073X] = "SB073x", [CTUAA] = "UAA", @@ -76,6 +79,7 @@ static const char *ct_subsys_name[NUM_CTCARDS] = { [CTHENDRIX] = "Hendrix", [CTSB0880] = "SB0880", [CTSB1270] = "SB1270", + [CTOK0010] = "OK0010", [CT20K2_UNKNOWN] = "Unknown", }; @@ -106,23 +110,20 @@ static struct { .public_name = "Mixer"} }; -typedef int (*create_t)(struct hw *, void **); -typedef int (*destroy_t)(void *); - static struct { int (*create)(struct hw *hw, void **rmgr); int (*destroy)(void *mgr); } rsc_mgr_funcs[NUM_RSCTYP] = { - [SRC] = { .create = (create_t)src_mgr_create, - .destroy = (destroy_t)src_mgr_destroy }, - [SRCIMP] = { .create = (create_t)srcimp_mgr_create, - .destroy = (destroy_t)srcimp_mgr_destroy }, - [AMIXER] = { .create = (create_t)amixer_mgr_create, - .destroy = (destroy_t)amixer_mgr_destroy }, - [SUM] = { .create = (create_t)sum_mgr_create, - .destroy = (destroy_t)sum_mgr_destroy }, - [DAIO] = { .create = (create_t)daio_mgr_create, - .destroy = (destroy_t)daio_mgr_destroy } + [SRC] = { .create = src_mgr_create, + .destroy = src_mgr_destroy }, + [SRCIMP] = { .create = srcimp_mgr_create, + .destroy = srcimp_mgr_destroy }, + [AMIXER] = { .create = amixer_mgr_create, + .destroy = amixer_mgr_destroy }, + [SUM] = { .create = sum_mgr_create, + .destroy = sum_mgr_destroy }, + [DAIO] = { .create = daio_mgr_create, + .destroy = daio_mgr_destroy } }; static int @@ -275,7 +276,7 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) /* Get AMIXER resource */ n_amixer = (n_amixer < 2) ? 2 : n_amixer; - apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL); + apcm->amixers = kcalloc(n_amixer, sizeof(void *), GFP_KERNEL); if (!apcm->amixers) { err = -ENOMEM; goto error1; @@ -299,10 +300,10 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) src = apcm->src; for (i = 0; i < n_amixer; i++) { amixer = apcm->amixers[i]; - mutex_lock(&atc->atc_mutex); - amixer->ops->setup(amixer, &src->rsc, - INIT_VOL, atc->pcm[i+device*2]); - mutex_unlock(&atc->atc_mutex); + scoped_guard(mutex, &atc->atc_mutex) { + amixer->ops->setup(amixer, &src->rsc, + INIT_VOL, atc->pcm[i+device*2]); + } src = src->ops->next_interleave(src); if (!src) src = apcm->src; @@ -543,18 +544,18 @@ atc_pcm_capture_get_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm) } if (n_srcc) { - apcm->srccs = kzalloc(sizeof(void *)*n_srcc, GFP_KERNEL); + apcm->srccs = kcalloc(n_srcc, sizeof(void *), GFP_KERNEL); if (!apcm->srccs) return -ENOMEM; } if (n_amixer) { - apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL); + apcm->amixers = kcalloc(n_amixer, sizeof(void *), GFP_KERNEL); if (!apcm->amixers) { err = -ENOMEM; goto error1; } } - apcm->srcimps = kzalloc(sizeof(void *)*n_srcimp, GFP_KERNEL); + apcm->srcimps = kcalloc(n_srcimp, sizeof(void *), GFP_KERNEL); if (!apcm->srcimps) { err = -ENOMEM; goto error1; @@ -819,7 +820,7 @@ static int spdif_passthru_playback_get_resources(struct ct_atc *atc, /* Get AMIXER resource */ n_amixer = (n_amixer < 2) ? 2 : n_amixer; - apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL); + apcm->amixers = kcalloc(n_amixer, sizeof(void *), GFP_KERNEL); if (!apcm->amixers) { err = -ENOMEM; goto error1; @@ -878,7 +879,7 @@ spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm) return -ENOENT; } - mutex_lock(&atc->atc_mutex); + guard(mutex)(&atc->atc_mutex); dao->ops->get_spos(dao, &status); if (((status >> 24) & IEC958_AES3_CON_FS) != iec958_con_fs) { status &= ~(IEC958_AES3_CON_FS << 24); @@ -888,7 +889,6 @@ spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm) } if ((rate != atc->pll_rate) && (32000 != rate)) err = atc_pll_init(atc, rate); - mutex_unlock(&atc->atc_mutex); return err; } @@ -925,13 +925,13 @@ spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) src = apcm->src; } /* Connect to SPDIFOO */ - mutex_lock(&atc->atc_mutex); - dao = container_of(atc->daios[SPDIFOO], struct dao, daio); - amixer = apcm->amixers[0]; - dao->ops->set_left_input(dao, &amixer->rsc); - amixer = apcm->amixers[1]; - dao->ops->set_right_input(dao, &amixer->rsc); - mutex_unlock(&atc->atc_mutex); + scoped_guard(mutex, &atc->atc_mutex) { + dao = container_of(atc->daios[SPDIFOO], struct dao, daio); + amixer = apcm->amixers[0]; + dao->ops->set_left_input(dao, &amixer->rsc); + amixer = apcm->amixers[1]; + dao->ops->set_right_input(dao, &amixer->rsc); + } ct_timer_prepare(apcm->timer); @@ -989,6 +989,24 @@ static struct capabilities atc_capabilities(struct ct_atc *atc) return hw->capabilities(hw); } +static void atc_dedicated_rca_select(struct ct_atc *atc) +{ + struct dao *dao; + struct ct_mixer *mixer = atc->mixer; + struct rsc *rscs[2] = {NULL}; + + dao = container_of(atc->daios[atc->rca_state ? RCA : LINEO1], + struct dao, daio); + dao->ops->clear_left_input(dao); + dao->ops->clear_right_input(dao); + + mixer->get_output_ports(mixer, MIX_WAVE_FRONT, &rscs[0], &rscs[1]); + dao = container_of(atc->daios[atc->rca_state ? LINEO1 : RCA], + struct dao, daio); + dao->ops->set_left_input(dao, rscs[0]); + dao->ops->set_right_input(dao, rscs[1]); +} + static int atc_output_switch_get(struct ct_atc *atc) { struct hw *hw = atc->hw; @@ -1090,6 +1108,11 @@ static int atc_mic_unmute(struct ct_atc *atc, unsigned char state) return atc_daio_unmute(atc, state, MIC); } +static int atc_rca_unmute(struct ct_atc *atc, unsigned char state) +{ + return atc_daio_unmute(atc, state, RCA); +} + static int atc_spdif_out_unmute(struct ct_atc *atc, unsigned char state) { return atc_daio_unmute(atc, state, SPDIFOO); @@ -1119,7 +1142,7 @@ static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state) struct rsc *rscs[2] = {NULL}; unsigned int spos = 0; - mutex_lock(&atc->atc_mutex); + guard(mutex)(&atc->atc_mutex); dao = container_of(atc->daios[SPDIFOO], struct dao, daio); da_dsc.msr = state ? 1 : atc->msr; da_dsc.passthru = state ? 1 : 0; @@ -1137,7 +1160,6 @@ static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state) } dao->ops->set_spos(dao, spos); dao->ops->commit_write(dao); - mutex_unlock(&atc->atc_mutex); return err; } @@ -1167,9 +1189,11 @@ static int atc_release_resources(struct ct_atc *atc) if (atc->daios) { daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO]; - for (i = 0; i < atc->n_daio; i++) { + for (i = 0; i < NUM_DAIOTYP; i++) { daio = atc->daios[i]; - if (daio->type < LINEIM) { + if (!daio) + continue; + if (daio->output) { dao = container_of(daio, struct dao, daio); dao->ops->clear_left_input(dao); dao->ops->clear_right_input(dao); @@ -1182,8 +1206,9 @@ static int atc_release_resources(struct ct_atc *atc) if (atc->pcm) { sum_mgr = atc->rsc_mgrs[SUM]; - for (i = 0; i < atc->n_pcm; i++) - sum_mgr->put_sum(sum_mgr, atc->pcm[i]); + for (i = 0; i < NUM_ATC_PCM; i++) + if (atc->pcm[i]) + sum_mgr->put_sum(sum_mgr, atc->pcm[i]); kfree(atc->pcm); atc->pcm = NULL; @@ -1191,8 +1216,9 @@ static int atc_release_resources(struct ct_atc *atc) if (atc->srcs) { src_mgr = atc->rsc_mgrs[SRC]; - for (i = 0; i < atc->n_src; i++) - src_mgr->put_src(src_mgr, atc->srcs[i]); + for (i = 0; i < NUM_ATC_SRCS; i++) + if (atc->srcs[i]) + src_mgr->put_src(src_mgr, atc->srcs[i]); kfree(atc->srcs); atc->srcs = NULL; @@ -1200,7 +1226,9 @@ static int atc_release_resources(struct ct_atc *atc) if (atc->srcimps) { srcimp_mgr = atc->rsc_mgrs[SRCIMP]; - for (i = 0; i < atc->n_srcimp; i++) { + for (i = 0; i < NUM_ATC_SRCS; i++) { + if (!atc->srcimps[i]) + continue; srcimp = atc->srcimps[i]; srcimp->ops->unmap(srcimp); srcimp_mgr->put_srcimp(srcimp_mgr, atc->srcimps[i]); @@ -1285,7 +1313,7 @@ static int atc_identify_card(struct ct_atc *atc, unsigned int ssid) if (p) { if (p->value < 0) { dev_err(atc->card->dev, - "Device %04x:%04x is black-listed\n", + "Device %04x:%04x is on the denylist\n", vendor_id, device_id); return -ENOENT; } @@ -1300,6 +1328,7 @@ static int atc_identify_card(struct ct_atc *atc, unsigned int ssid) dev_info(atc->card->dev, "chip %s model %s (%04x:%04x) is found\n", atc->chip_name, atc->model_name, vendor_id, device_id); + atc->rca_state = 0; return 0; } @@ -1373,32 +1402,35 @@ static int atc_get_resources(struct ct_atc *atc) struct srcimp_mgr *srcimp_mgr; struct sum_desc sum_dsc = {0}; struct sum_mgr *sum_mgr; - int err, i, num_srcs, num_daios; + struct capabilities cap; + int err, i; - num_daios = ((atc->model == CTSB1270) ? 8 : 7); - num_srcs = ((atc->model == CTSB1270) ? 6 : 4); + cap = atc->capabilities(atc); - atc->daios = kzalloc(sizeof(void *)*num_daios, GFP_KERNEL); + atc->daios = kcalloc(NUM_DAIOTYP, sizeof(void *), GFP_KERNEL); if (!atc->daios) return -ENOMEM; - atc->srcs = kzalloc(sizeof(void *)*num_srcs, GFP_KERNEL); + atc->srcs = kcalloc(NUM_ATC_SRCS, sizeof(void *), GFP_KERNEL); if (!atc->srcs) return -ENOMEM; - atc->srcimps = kzalloc(sizeof(void *)*num_srcs, GFP_KERNEL); + atc->srcimps = kcalloc(NUM_ATC_SRCS, sizeof(void *), GFP_KERNEL); if (!atc->srcimps) return -ENOMEM; - atc->pcm = kzalloc(sizeof(void *)*(2*4), GFP_KERNEL); + atc->pcm = kcalloc(NUM_ATC_PCM, sizeof(void *), GFP_KERNEL); if (!atc->pcm) return -ENOMEM; daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO]; da_desc.msr = atc->msr; - for (i = 0, atc->n_daio = 0; i < num_daios; i++) { + for (i = 0; i < NUM_DAIOTYP; i++) { + if (((i == MIC) && !cap.dedicated_mic) || ((i == RCA) && !cap.dedicated_rca)) + continue; da_desc.type = (atc->model != CTSB073X) ? i : ((i == SPDIFIO) ? SPDIFI1 : i); + da_desc.output = (i < LINEIM) || (i == RCA); err = daio_mgr->get_daio(daio_mgr, &da_desc, (struct daio **)&atc->daios[i]); if (err) { @@ -1407,42 +1439,39 @@ static int atc_get_resources(struct ct_atc *atc) i); return err; } - atc->n_daio++; } src_mgr = atc->rsc_mgrs[SRC]; src_dsc.multi = 1; src_dsc.msr = atc->msr; src_dsc.mode = ARCRW; - for (i = 0, atc->n_src = 0; i < num_srcs; i++) { + for (i = 0; i < NUM_ATC_SRCS; i++) { + if (((i > 3) && !cap.dedicated_mic)) + continue; err = src_mgr->get_src(src_mgr, &src_dsc, (struct src **)&atc->srcs[i]); if (err) return err; - - atc->n_src++; } srcimp_mgr = atc->rsc_mgrs[SRCIMP]; srcimp_dsc.msr = 8; - for (i = 0, atc->n_srcimp = 0; i < num_srcs; i++) { + for (i = 0; i < NUM_ATC_SRCS; i++) { + if (((i > 3) && !cap.dedicated_mic)) + continue; err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc, (struct srcimp **)&atc->srcimps[i]); if (err) return err; - - atc->n_srcimp++; } sum_mgr = atc->rsc_mgrs[SUM]; sum_dsc.msr = atc->msr; - for (i = 0, atc->n_pcm = 0; i < (2*4); i++) { + for (i = 0; i < NUM_ATC_PCM; i++) { err = sum_mgr->get_sum(sum_mgr, &sum_dsc, (struct sum **)&atc->pcm[i]); if (err) return err; - - atc->n_pcm++; } return 0; @@ -1495,9 +1524,11 @@ static void atc_connect_resources(struct ct_atc *atc) struct sum *sum; struct ct_mixer *mixer; struct rsc *rscs[2] = {NULL}; + struct capabilities cap; int i, j; mixer = atc->mixer; + cap = atc->capabilities(atc); for (i = MIX_WAVE_FRONT, j = LINEO1; i <= MIX_SPDIF_OUT; i++, j++) { mixer->get_output_ports(mixer, i, &rscs[0], &rscs[1]); @@ -1506,6 +1537,11 @@ static void atc_connect_resources(struct ct_atc *atc) dao->ops->set_right_input(dao, rscs[1]); } + if (cap.dedicated_rca) { + /* SE-300PCIE has a dedicated DAC for the RCA. */ + atc_dedicated_rca_select(atc); + } + dai = container_of(atc->daios[LINEIM], struct dai, daio); atc_connect_dai(atc->rsc_mgrs[SRC], dai, (struct src **)&atc->srcs[2], @@ -1515,8 +1551,9 @@ static void atc_connect_resources(struct ct_atc *atc) src = atc->srcs[3]; mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc); - if (atc->model == CTSB1270) { + if (cap.dedicated_mic) { /* Titanium HD has a dedicated ADC for the Mic. */ + /* SE-300PCIE has a 4-channel ADC. */ dai = container_of(atc->daios[MIC], struct dai, daio); atc_connect_dai(atc->rsc_mgrs[SRC], dai, (struct src **)&atc->srcs[4], @@ -1548,18 +1585,10 @@ static void atc_connect_resources(struct ct_atc *atc) #ifdef CONFIG_PM_SLEEP static int atc_suspend(struct ct_atc *atc) { - int i; struct hw *hw = atc->hw; snd_power_change_state(atc->card, SNDRV_CTL_POWER_D3hot); - for (i = FRONT; i < NUM_PCMS; i++) { - if (!atc->pcms[i]) - continue; - - snd_pcm_suspend_all(atc->pcms[i]); - } - atc_release_resources(atc); hw->suspend(hw); @@ -1646,12 +1675,14 @@ static const struct ct_atc atc_preset = { .line_rear_unmute = atc_line_rear_unmute, .line_in_unmute = atc_line_in_unmute, .mic_unmute = atc_mic_unmute, + .rca_unmute = atc_rca_unmute, .spdif_out_unmute = atc_spdif_out_unmute, .spdif_in_unmute = atc_spdif_in_unmute, .spdif_out_get_status = atc_spdif_out_get_status, .spdif_out_set_status = atc_spdif_out_set_status, .spdif_out_passthru = atc_spdif_out_passthru, .capabilities = atc_capabilities, + .dedicated_rca_select = atc_dedicated_rca_select, .output_switch_get = atc_output_switch_get, .output_switch_put = atc_output_switch_put, .mic_source_switch_get = atc_mic_source_switch_get, @@ -1666,6 +1697,10 @@ static const struct ct_atc atc_preset = { * ct_atc_create - create and initialize a hardware manager * @card: corresponding alsa card object * @pci: corresponding kernel pci device object + * @rsr: reference sampling rate + * @msr: master sampling rate + * @chip_type: CHIPTYP enum values + * @ssid: vendor ID (upper 16 bits) and device ID (lower 16 bits) * @ratc: return created object address in it * * Creates and initializes a hardware manager. @@ -1680,7 +1715,7 @@ int ct_atc_create(struct snd_card *card, struct pci_dev *pci, struct ct_atc **ratc) { struct ct_atc *atc; - static struct snd_device_ops ops = { + static const struct snd_device_ops ops = { .dev_free = atc_dev_free, }; int err; |
