#include "ctsrc.h"
#include "ctamixer.h"
#include "ctdaio.h"
+#include "cttimer.h"
#include <linux/delay.h>
+#include <linux/slab.h>
#include <sound/pcm.h>
#include <sound/control.h>
#include <sound/asoundef.h>
| (0x10 << 16) \
| ((IEC958_AES3_CON_FS_48000) << 24))
-static const struct ct_atc_chip_sub_details atc_sub_details[NUM_CTCARDS] = {
- [CTSB0760] = {.subsys = PCI_SUBDEVICE_ID_CREATIVE_SB0760,
- .nm_model = "SB076x"},
- [CTHENDRIX] = {.subsys = PCI_SUBDEVICE_ID_CREATIVE_HENDRIX,
- .nm_model = "Hendrix"},
- [CTSB08801] = {.subsys = PCI_SUBDEVICE_ID_CREATIVE_SB08801,
- .nm_model = "SB0880"},
- [CTSB08802] = {.subsys = PCI_SUBDEVICE_ID_CREATIVE_SB08802,
- .nm_model = "SB0880"},
- [CTSB08803] = {.subsys = PCI_SUBDEVICE_ID_CREATIVE_SB08803,
- .nm_model = "SB0880"}
+static struct snd_pci_quirk __devinitdata subsys_20k1_list[] = {
+ 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),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0031, "SB073x", CTSB073X),
+ SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000, 0x6000,
+ "UAA", CTUAA),
+ { } /* terminator */
};
-static struct ct_atc_chip_details atc_chip_details[] = {
- {.vendor = PCI_VENDOR_ID_CREATIVE,
- .device = PCI_DEVICE_ID_CREATIVE_20K1,
- .sub_details = NULL,
- .nm_card = "X-Fi 20k1"},
- {.vendor = PCI_VENDOR_ID_CREATIVE,
- .device = PCI_DEVICE_ID_CREATIVE_20K2,
- .sub_details = atc_sub_details,
- .nm_card = "X-Fi 20k2"},
- {} /* terminator */
+static struct snd_pci_quirk __devinitdata 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_SB08801,
+ "SB0880", CTSB0880),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08802,
+ "SB0880", CTSB0880),
+ SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08803,
+ "SB0880", CTSB0880),
+ SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000,
+ PCI_SUBDEVICE_ID_CREATIVE_HENDRIX, "HENDRIX",
+ CTHENDRIX),
+ { } /* terminator */
+};
+
+static const char *ct_subsys_name[NUM_CTCARDS] = {
+ /* 20k1 models */
+ [CTSB055X] = "SB055x",
+ [CTSB073X] = "SB073x",
+ [CTUAA] = "UAA",
+ [CT20K1_UNKNOWN] = "Unknown",
+ /* 20k2 models */
+ [CTSB0760] = "SB076x",
+ [CTHENDRIX] = "Hendrix",
+ [CTSB0880] = "SB0880",
+ [CT20K2_UNKNOWN] = "Unknown",
};
static struct {
[FRONT] = { .create = ct_alsa_pcm_create,
.destroy = NULL,
.public_name = "Front/WaveIn"},
- [REAR] = { .create = ct_alsa_pcm_create,
+ [SURROUND] = { .create = ct_alsa_pcm_create,
.destroy = NULL,
- .public_name = "Rear"},
+ .public_name = "Surround"},
[CLFE] = { .create = ct_alsa_pcm_create,
.destroy = NULL,
.public_name = "Center/LFE"},
- [SURROUND] = { .create = ct_alsa_pcm_create,
+ [SIDE] = { .create = ct_alsa_pcm_create,
.destroy = NULL,
- .public_name = "Surround"},
+ .public_name = "Side"},
[IEC958] = { .create = ct_alsa_pcm_create,
.destroy = NULL,
.public_name = "IEC958 Non-audio"},
struct snd_pcm_runtime *runtime;
struct ct_vm *vm;
- if (NULL == apcm->substream)
+ if (!apcm->substream)
return 0;
runtime = apcm->substream->runtime;
vm = atc->vm;
- apcm->vm_block = vm->map(vm, runtime->dma_area, runtime->dma_bytes);
+ apcm->vm_block = vm->map(vm, apcm->substream, runtime->dma_bytes);
- if (NULL == apcm->vm_block)
+ if (!apcm->vm_block)
return -ENOENT;
return 0;
{
struct ct_vm *vm;
- if (NULL == apcm->vm_block)
+ if (!apcm->vm_block)
return;
vm = atc->vm;
static unsigned long atc_get_ptp_phys(struct ct_atc *atc, int index)
{
- struct ct_vm *vm;
- void *kvirt_addr;
- unsigned long phys_addr;
-
- vm = atc->vm;
- kvirt_addr = vm->get_ptp_virt(vm, index);
- if (kvirt_addr == NULL)
- phys_addr = (~0UL);
- else
- phys_addr = virt_to_phys(kvirt_addr);
-
- return phys_addr;
+ return atc->vm->get_ptp_phys(atc->vm, index);
}
static unsigned int convert_format(snd_pcm_format_t snd_format)
{
switch (snd_format) {
case SNDRV_PCM_FORMAT_U8:
- case SNDRV_PCM_FORMAT_S8:
return SRC_SF_U8;
case SNDRV_PCM_FORMAT_S16_LE:
- case SNDRV_PCM_FORMAT_U16_LE:
return SRC_SF_S16;
case SNDRV_PCM_FORMAT_S24_3LE:
return SRC_SF_S24;
- case SNDRV_PCM_FORMAT_S24_LE:
case SNDRV_PCM_FORMAT_S32_LE:
return SRC_SF_S32;
+ case SNDRV_PCM_FORMAT_FLOAT_LE:
+ return SRC_SF_F32;
default:
printk(KERN_ERR "ctxfi: not recognized snd format is %d \n",
snd_format);
static unsigned int
atc_get_pitch(unsigned int input_rate, unsigned int output_rate)
{
- unsigned int pitch = 0;
- int b = 0;
+ unsigned int pitch;
+ int b;
/* get pitch and convert to fixed-point 8.24 format. */
pitch = (input_rate / output_rate) << 24;
static int select_rom(unsigned int pitch)
{
- if ((pitch > 0x00428f5c) && (pitch < 0x01b851ec)) {
+ if (pitch > 0x00428f5c && pitch < 0x01b851ec) {
/* 0.26 <= pitch <= 1.72 */
return 1;
- } else if ((0x01d66666 == pitch) || (0x01d66667 == pitch)) {
+ } else if (pitch == 0x01d66666 || pitch == 0x01d66667) {
/* pitch == 1.8375 */
return 2;
- } else if (0x02000000 == pitch) {
+ } else if (pitch == 0x02000000) {
/* pitch == 2 */
return 3;
- } else if ((pitch >= 0x0) && (pitch <= 0x08000000)) {
+ } else if (pitch <= 0x08000000) {
/* 0 <= pitch <= 8 */
return 0;
} else {
struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER];
struct src_desc desc = {0};
struct amixer_desc mix_dsc = {0};
- struct src *src = NULL;
- struct amixer *amixer = NULL;
- int err = 0;
+ struct src *src;
+ struct amixer *amixer;
+ int err;
int n_amixer = apcm->substream->runtime->channels, i = 0;
int device = apcm->substream->pcm->device;
- unsigned int pitch = 0;
- unsigned long flags;
-
- if (NULL != apcm->src) {
- /* Prepared pcm playback */
- return 0;
- }
+ unsigned int pitch;
/* first release old resources */
- atc->pcm_release_resources(atc, apcm);
+ atc_pcm_release_resources(atc, apcm);
/* Get SRC resource */
desc.multi = apcm->substream->runtime->channels;
/* Get AMIXER resource */
n_amixer = (n_amixer < 2) ? 2 : n_amixer;
apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL);
- if (NULL == apcm->amixers) {
+ if (!apcm->amixers) {
err = -ENOMEM;
goto error1;
}
src = apcm->src;
for (i = 0; i < n_amixer; i++) {
amixer = apcm->amixers[i];
- spin_lock_irqsave(&atc->atc_lock, flags);
+ mutex_lock(&atc->atc_mutex);
amixer->ops->setup(amixer, &src->rsc,
INIT_VOL, atc->pcm[i+device*2]);
- spin_unlock_irqrestore(&atc->atc_lock, flags);
+ mutex_unlock(&atc->atc_mutex);
src = src->ops->next_interleave(src);
- if (NULL == src)
+ if (!src)
src = apcm->src;
}
+ ct_timer_prepare(apcm->timer);
+
return 0;
error1:
struct srcimp_mgr *srcimp_mgr = atc->rsc_mgrs[SRCIMP];
struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER];
struct sum_mgr *sum_mgr = atc->rsc_mgrs[SUM];
- struct srcimp *srcimp = NULL;
- int i = 0;
+ struct srcimp *srcimp;
+ int i;
- if (NULL != apcm->srcimps) {
+ if (apcm->srcimps) {
for (i = 0; i < apcm->n_srcimp; i++) {
srcimp = apcm->srcimps[i];
srcimp->ops->unmap(srcimp);
apcm->srcimps = NULL;
}
- if (NULL != apcm->srccs) {
+ if (apcm->srccs) {
for (i = 0; i < apcm->n_srcc; i++) {
src_mgr->put_src(src_mgr, apcm->srccs[i]);
apcm->srccs[i] = NULL;
apcm->srccs = NULL;
}
- if (NULL != apcm->amixers) {
+ if (apcm->amixers) {
for (i = 0; i < apcm->n_amixer; i++) {
amixer_mgr->put_amixer(amixer_mgr, apcm->amixers[i]);
apcm->amixers[i] = NULL;
apcm->amixers = NULL;
}
- if (NULL != apcm->mono) {
+ if (apcm->mono) {
sum_mgr->put_sum(sum_mgr, apcm->mono);
apcm->mono = NULL;
}
- if (NULL != apcm->src) {
+ if (apcm->src) {
src_mgr->put_src(src_mgr, apcm->src);
apcm->src = NULL;
}
- if (NULL != apcm->vm_block) {
+ if (apcm->vm_block) {
/* Undo device virtual mem map */
ct_unmap_audio_buffer(atc, apcm);
apcm->vm_block = NULL;
static int atc_pcm_playback_start(struct ct_atc *atc, struct ct_atc_pcm *apcm)
{
- unsigned int max_cisz = 0;
+ unsigned int max_cisz;
struct src *src = apcm->src;
+ if (apcm->started)
+ return 0;
+ apcm->started = 1;
+
max_cisz = src->multi * src->rsc.msr;
max_cisz = 0x80 * (max_cisz < 8 ? max_cisz : 8);
src->ops->set_state(src, SRC_STATE_INIT);
src->ops->commit_write(src);
+ ct_timer_start(apcm->timer);
return 0;
}
static int atc_pcm_stop(struct ct_atc *atc, struct ct_atc_pcm *apcm)
{
- struct src *src = NULL;
- int i = 0;
+ struct src *src;
+ int i;
+
+ ct_timer_stop(apcm->timer);
src = apcm->src;
src->ops->set_bm(src, 0);
src->ops->set_state(src, SRC_STATE_OFF);
src->ops->commit_write(src);
- if (NULL != apcm->srccs) {
+ if (apcm->srccs) {
for (i = 0; i < apcm->n_srcc; i++) {
src = apcm->srccs[i];
src->ops->set_bm(src, 0);
atc_pcm_playback_position(struct ct_atc *atc, struct ct_atc_pcm *apcm)
{
struct src *src = apcm->src;
- u32 size = 0, max_cisz = 0;
- int position = 0;
+ u32 size, max_cisz;
+ int position;
+ if (!src)
+ return 0;
position = src->ops->get_ca(src);
size = apcm->vm_block->size;
static void setup_src_node_conf(struct ct_atc *atc, struct ct_atc_pcm *apcm,
struct src_node_conf_t *conf, int *n_srcc)
{
- unsigned int pitch = 0;
+ unsigned int pitch;
/* get pitch and convert to fixed-point 8.24 format. */
pitch = atc_get_pitch((atc->rsr * atc->msr),
struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER];
struct sum_mgr *sum_mgr = atc->rsc_mgrs[SUM];
struct src_desc src_dsc = {0};
- struct src *src = NULL;
+ struct src *src;
struct srcimp_desc srcimp_dsc = {0};
- struct srcimp *srcimp = NULL;
+ struct srcimp *srcimp;
struct amixer_desc mix_dsc = {0};
struct sum_desc sum_dsc = {0};
- unsigned int pitch = 0;
- int multi = 0, err = 0, i = 0;
- int n_srcimp = 0, n_amixer = 0, n_srcc = 0, n_sum = 0;
+ unsigned int pitch;
+ int multi, err, i;
+ int n_srcimp, n_amixer, n_srcc, n_sum;
struct src_node_conf_t src_node_conf[2] = {{0} };
/* first release old resources */
- atc->pcm_release_resources(atc, apcm);
+ atc_pcm_release_resources(atc, apcm);
/* The numbers of converting SRCs and SRCIMPs should be determined
* by pitch value. */
setup_src_node_conf(atc, apcm, src_node_conf, &n_srcc);
n_sum = (1 == multi) ? 1 : 0;
- n_amixer += n_sum * 2 + n_srcc;
- n_srcimp += n_srcc;
+ n_amixer = n_sum * 2 + n_srcc;
+ n_srcimp = n_srcc;
if ((multi > 1) && (0x8000000 >= pitch)) {
/* Need extra AMIXERs and SRCIMPs for special treatment
* of interleaved recording of conjugate channels */
if (n_srcc) {
apcm->srccs = kzalloc(sizeof(void *)*n_srcc, GFP_KERNEL);
- if (NULL == apcm->srccs)
+ if (!apcm->srccs)
return -ENOMEM;
}
if (n_amixer) {
apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL);
- if (NULL == apcm->amixers) {
+ if (!apcm->amixers) {
err = -ENOMEM;
goto error1;
}
}
apcm->srcimps = kzalloc(sizeof(void *)*n_srcimp, GFP_KERNEL);
- if (NULL == apcm->srcimps) {
+ if (!apcm->srcimps) {
err = -ENOMEM;
goto error1;
}
static int atc_pcm_capture_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
{
- struct src *src = NULL;
- struct amixer *amixer = NULL;
- struct srcimp *srcimp = NULL;
+ struct src *src;
+ struct amixer *amixer;
+ struct srcimp *srcimp;
struct ct_mixer *mixer = atc->mixer;
- struct sum *mono = NULL;
+ struct sum *mono;
struct rsc *out_ports[8] = {NULL};
- int err = 0, i = 0, j = 0, n_sum = 0, multi = 0;
- unsigned int pitch = 0;
+ int err, i, j, n_sum, multi;
+ unsigned int pitch;
int mix_base = 0, imp_base = 0;
- if (NULL != apcm->src) {
- /* Prepared pcm capture */
- return 0;
- }
+ atc_pcm_release_resources(atc, apcm);
/* Get needed resources. */
err = atc_pcm_capture_get_resources(atc, apcm);
}
}
+ ct_timer_prepare(apcm->timer);
+
return 0;
}
static int atc_pcm_capture_start(struct ct_atc *atc, struct ct_atc_pcm *apcm)
{
- struct src *src = NULL;
+ struct src *src;
struct src_mgr *src_mgr = atc->rsc_mgrs[SRC];
- int i = 0, multi = 0;
+ int i, multi;
if (apcm->started)
return 0;
/* Enable relevant SRCs synchronously */
src_mgr->commit_write(src_mgr);
+ ct_timer_start(apcm->timer);
return 0;
}
{
struct src *src = apcm->src;
+ if (!src)
+ return 0;
return src->ops->get_ca(src) - apcm->vm_block->addr;
}
struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER];
struct src_desc desc = {0};
struct amixer_desc mix_dsc = {0};
- struct src *src = NULL;
- int err = 0;
- int n_amixer = apcm->substream->runtime->channels, i = 0;
- unsigned int pitch = 0, rsr = atc->pll_rate;
+ struct src *src;
+ int err;
+ int n_amixer = apcm->substream->runtime->channels, i;
+ unsigned int pitch, rsr = atc->pll_rate;
/* first release old resources */
- atc->pcm_release_resources(atc, apcm);
+ atc_pcm_release_resources(atc, apcm);
/* Get SRC resource */
desc.multi = apcm->substream->runtime->channels;
/* Get AMIXER resource */
n_amixer = (n_amixer < 2) ? 2 : n_amixer;
apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL);
- if (NULL == apcm->amixers) {
+ if (!apcm->amixers) {
err = -ENOMEM;
goto error1;
}
return err;
}
+static int atc_pll_init(struct ct_atc *atc, int rate)
+{
+ struct hw *hw = atc->hw;
+ int err;
+ err = hw->pll_init(hw, rate);
+ atc->pll_rate = err ? 0 : rate;
+ return err;
+}
+
static int
spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm)
{
struct dao *dao = container_of(atc->daios[SPDIFOO], struct dao, daio);
- unsigned long flags;
unsigned int rate = apcm->substream->runtime->rate;
- unsigned int status = 0;
+ unsigned int status;
int err = 0;
- unsigned char iec958_con_fs = 0;
+ unsigned char iec958_con_fs;
switch (rate) {
case 48000:
return -ENOENT;
}
- spin_lock_irqsave(&atc->atc_lock, flags);
+ mutex_lock(&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);
dao->ops->set_spos(dao, status);
dao->ops->commit_write(dao);
}
- if ((rate != atc->pll_rate) && (32000 != rate)) {
- err = ((struct hw *)atc->hw)->pll_init(atc->hw, rate);
- atc->pll_rate = err ? 0 : rate;
- }
- spin_unlock_irqrestore(&atc->atc_lock, flags);
+ if ((rate != atc->pll_rate) && (32000 != rate))
+ err = atc_pll_init(atc, rate);
+ mutex_unlock(&atc->atc_mutex);
return err;
}
static int
spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
{
- struct src *src = NULL;
- struct amixer *amixer = NULL;
- struct dao *dao = NULL;
- int err = 0;
- int i = 0;
- unsigned long flags;
+ struct src *src;
+ struct amixer *amixer;
+ struct dao *dao;
+ int err;
+ int i;
- if (NULL != apcm->src)
- return 0;
+ atc_pcm_release_resources(atc, apcm);
/* Configure SPDIFOO and PLL to passthrough mode;
* determine pll_rate. */
amixer = apcm->amixers[i];
amixer->ops->setup(amixer, &src->rsc, INIT_VOL, NULL);
src = src->ops->next_interleave(src);
- if (NULL == src)
+ if (!src)
src = apcm->src;
}
/* Connect to SPDIFOO */
- spin_lock_irqsave(&atc->atc_lock, flags);
+ 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);
- spin_unlock_irqrestore(&atc->atc_lock, flags);
+ mutex_unlock(&atc->atc_mutex);
+
+ ct_timer_prepare(apcm->timer);
return 0;
}
{
struct hw *hw = atc->hw;
struct ct_mixer *mixer = atc->mixer;
- struct src *src = NULL;
+ struct src *src;
if (hw->is_adc_source_selected(hw, ADC_LINEIN))
return 0;
{
struct hw *hw = atc->hw;
struct ct_mixer *mixer = atc->mixer;
- struct src *src = NULL;
+ struct src *src;
if (hw->is_adc_source_selected(hw, ADC_MICIN))
return 0;
static int atc_line_surround_unmute(struct ct_atc *atc, unsigned char state)
{
- return atc_daio_unmute(atc, state, LINEO4);
+ return atc_daio_unmute(atc, state, LINEO2);
}
static int atc_line_clfe_unmute(struct ct_atc *atc, unsigned char state)
static int atc_line_rear_unmute(struct ct_atc *atc, unsigned char state)
{
- return atc_daio_unmute(atc, state, LINEO2);
+ return atc_daio_unmute(atc, state, LINEO4);
}
static int atc_line_in_unmute(struct ct_atc *atc, unsigned char state)
static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state)
{
- unsigned long flags;
struct dao_desc da_dsc = {0};
- struct dao *dao = NULL;
- int err = 0;
+ struct dao *dao;
+ int err;
struct ct_mixer *mixer = atc->mixer;
struct rsc *rscs[2] = {NULL};
unsigned int spos = 0;
- spin_lock_irqsave(&atc->atc_lock, flags);
+ mutex_lock(&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;
dao->ops->set_left_input(dao, rscs[0]);
dao->ops->set_right_input(dao, rscs[1]);
/* Restore PLL to atc->rsr if needed. */
- if (atc->pll_rate != atc->rsr) {
- err = ((struct hw *)atc->hw)->pll_init(atc->hw,
- atc->rsr);
- atc->pll_rate = err ? 0 : atc->rsr;
- }
+ if (atc->pll_rate != atc->rsr)
+ err = atc_pll_init(atc, atc->rsr);
}
dao->ops->set_spos(dao, spos);
dao->ops->commit_write(dao);
- spin_unlock_irqrestore(&atc->atc_lock, flags);
+ mutex_unlock(&atc->atc_mutex);
return err;
}
-static int ct_atc_destroy(struct ct_atc *atc)
+static int atc_release_resources(struct ct_atc *atc)
{
+ int i;
struct daio_mgr *daio_mgr = NULL;
struct dao *dao = NULL;
struct dai *dai = NULL;
struct srcimp_mgr *srcimp_mgr = NULL;
struct srcimp *srcimp = NULL;
struct ct_mixer *mixer = NULL;
- int i = 0;
-
- if (NULL == atc)
- return 0;
-
- /* Stop hardware and disable all interrupts */
- if (NULL != atc->hw)
- ((struct hw *)atc->hw)->card_stop(atc->hw);
- /* Destroy internal mixer objects */
- if (NULL != atc->mixer) {
+ /* disconnect internal mixer objects */
+ if (atc->mixer) {
mixer = atc->mixer;
mixer->set_input_left(mixer, MIX_LINE_IN, NULL);
mixer->set_input_right(mixer, MIX_LINE_IN, NULL);
mixer->set_input_right(mixer, MIX_MIC_IN, NULL);
mixer->set_input_left(mixer, MIX_SPDIF_IN, NULL);
mixer->set_input_right(mixer, MIX_SPDIF_IN, NULL);
- ct_mixer_destroy(atc->mixer);
}
- if (NULL != atc->daios) {
+ if (atc->daios) {
daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
for (i = 0; i < atc->n_daio; i++) {
daio = atc->daios[i];
daio_mgr->put_daio(daio_mgr, daio);
}
kfree(atc->daios);
+ atc->daios = NULL;
}
- if (NULL != atc->pcm) {
+ 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]);
kfree(atc->pcm);
+ atc->pcm = NULL;
}
- if (NULL != atc->srcs) {
+ 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]);
kfree(atc->srcs);
+ atc->srcs = NULL;
}
- if (NULL != atc->srcimps) {
+ if (atc->srcimps) {
srcimp_mgr = atc->rsc_mgrs[SRCIMP];
for (i = 0; i < atc->n_srcimp; i++) {
srcimp = atc->srcimps[i];
srcimp_mgr->put_srcimp(srcimp_mgr, atc->srcimps[i]);
}
kfree(atc->srcimps);
+ atc->srcimps = NULL;
+ }
+
+ return 0;
+}
+
+static int ct_atc_destroy(struct ct_atc *atc)
+{
+ int i = 0;
+
+ if (!atc)
+ return 0;
+
+ if (atc->timer) {
+ ct_timer_free(atc->timer);
+ atc->timer = NULL;
}
+ atc_release_resources(atc);
+
+ /* Destroy internal mixer objects */
+ if (atc->mixer)
+ ct_mixer_destroy(atc->mixer);
+
for (i = 0; i < NUM_RSCTYP; i++) {
- if ((NULL != rsc_mgr_funcs[i].destroy) &&
- (NULL != atc->rsc_mgrs[i]))
+ if (rsc_mgr_funcs[i].destroy && atc->rsc_mgrs[i])
rsc_mgr_funcs[i].destroy(atc->rsc_mgrs[i]);
}
- if (NULL != atc->hw)
+ if (atc->hw)
destroy_hw_obj((struct hw *)atc->hw);
/* Destroy device virtual memory manager object */
- if (NULL != atc->vm) {
+ if (atc->vm) {
ct_vm_destroy(atc->vm);
atc->vm = NULL;
}
return ct_atc_destroy(atc);
}
-static int atc_identify_card(struct ct_atc *atc)
+static int __devinit atc_identify_card(struct ct_atc *atc, unsigned int ssid)
{
- u16 subsys;
- u8 revision;
- struct pci_dev *pci = atc->pci;
- const struct ct_atc_chip_details *d;
- enum CTCARDS i;
-
- subsys = pci->subsystem_device;
- revision = pci->revision;
- atc->chip_details = NULL;
- atc->model = NUM_CTCARDS;
- for (d = atc_chip_details; d->vendor; d++) {
- if (d->vendor != pci->vendor || d->device != pci->device)
- continue;
-
- if (NULL == d->sub_details) {
- atc->chip_details = d;
- break;
- }
- for (i = 0; i < NUM_CTCARDS; i++) {
- if ((d->sub_details[i].subsys == subsys) ||
- (((subsys & 0x6000) == 0x6000) &&
- ((d->sub_details[i].subsys & 0x6000) == 0x6000))) {
- atc->model = i;
- break;
- }
- }
- if (i >= NUM_CTCARDS)
- continue;
+ const struct snd_pci_quirk *p;
+ const struct snd_pci_quirk *list;
+ u16 vendor_id, device_id;
- atc->chip_details = d;
+ switch (atc->chip_type) {
+ case ATC20K1:
+ atc->chip_name = "20K1";
+ list = subsys_20k1_list;
break;
- /* not take revision into consideration now */
- }
- if (!d->vendor)
+ case ATC20K2:
+ atc->chip_name = "20K2";
+ list = subsys_20k2_list;
+ break;
+ default:
return -ENOENT;
-
+ }
+ if (ssid) {
+ vendor_id = ssid >> 16;
+ device_id = ssid & 0xffff;
+ } else {
+ vendor_id = atc->pci->subsystem_vendor;
+ device_id = atc->pci->subsystem_device;
+ }
+ p = snd_pci_quirk_lookup_id(vendor_id, device_id, list);
+ if (p) {
+ if (p->value < 0) {
+ printk(KERN_ERR "ctxfi: "
+ "Device %04x:%04x is black-listed\n",
+ vendor_id, device_id);
+ return -ENOENT;
+ }
+ atc->model = p->value;
+ } else {
+ if (atc->chip_type == ATC20K1)
+ atc->model = CT20K1_UNKNOWN;
+ else
+ atc->model = CT20K2_UNKNOWN;
+ }
+ atc->model_name = ct_subsys_name[atc->model];
+ snd_printd("ctxfi: chip %s model %s (%04x:%04x) is found\n",
+ atc->chip_name, atc->model_name,
+ vendor_id, device_id);
return 0;
}
-static int ct_create_alsa_devs(struct ct_atc *atc)
+int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc)
{
enum CTALSADEVS i;
- struct hw *hw = atc->hw;
int err;
- switch (hw->get_chip_type(hw)) {
- case ATC20K1:
- alsa_dev_funcs[MIXER].public_name = "20K1";
- break;
- case ATC20K2:
- alsa_dev_funcs[MIXER].public_name = "20K2";
- break;
- default:
- alsa_dev_funcs[MIXER].public_name = "Unknown";
- break;
- }
+ alsa_dev_funcs[MIXER].public_name = atc->chip_name;
for (i = 0; i < NUM_CTALSADEVS; i++) {
- if (NULL == alsa_dev_funcs[i].create)
+ if (!alsa_dev_funcs[i].create)
continue;
err = alsa_dev_funcs[i].create(atc, i,
return 0;
}
-static int atc_create_hw_devs(struct ct_atc *atc)
+static int __devinit atc_create_hw_devs(struct ct_atc *atc)
{
- struct hw *hw = NULL;
+ struct hw *hw;
struct card_conf info = {0};
- int i = 0, err = 0;
+ int i, err;
- err = create_hw_obj(atc->pci, &hw);
+ err = create_hw_obj(atc->pci, atc->chip_type, atc->model, &hw);
if (err) {
printk(KERN_ERR "Failed to create hw obj!!!\n");
return err;
return err;
for (i = 0; i < NUM_RSCTYP; i++) {
- if (NULL == rsc_mgr_funcs[i].create)
+ if (!rsc_mgr_funcs[i].create)
continue;
err = rsc_mgr_funcs[i].create(atc->hw, &atc->rsc_mgrs[i]);
static int atc_get_resources(struct ct_atc *atc)
{
struct daio_desc da_desc = {0};
- struct daio_mgr *daio_mgr = NULL;
+ struct daio_mgr *daio_mgr;
struct src_desc src_dsc = {0};
- struct src_mgr *src_mgr = NULL;
+ struct src_mgr *src_mgr;
struct srcimp_desc srcimp_dsc = {0};
- struct srcimp_mgr *srcimp_mgr = NULL;
+ struct srcimp_mgr *srcimp_mgr;
struct sum_desc sum_dsc = {0};
- struct sum_mgr *sum_mgr = NULL;
- int err = 0, i = 0;
- unsigned short subsys_id;
+ struct sum_mgr *sum_mgr;
+ int err, i;
atc->daios = kzalloc(sizeof(void *)*(DAIONUM), GFP_KERNEL);
- if (NULL == atc->daios)
+ if (!atc->daios)
return -ENOMEM;
atc->srcs = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL);
- if (NULL == atc->srcs)
+ if (!atc->srcs)
return -ENOMEM;
atc->srcimps = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL);
- if (NULL == atc->srcimps)
+ if (!atc->srcimps)
return -ENOMEM;
atc->pcm = kzalloc(sizeof(void *)*(2*4), GFP_KERNEL);
- if (NULL == atc->pcm)
+ if (!atc->pcm)
return -ENOMEM;
daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO];
}
atc->n_daio++;
}
- subsys_id = atc->pci->subsystem_device;
- if ((subsys_id == 0x0029) || (subsys_id == 0x0031)) {
- /* SB073x cards */
+ if (atc->model == CTSB073X)
da_desc.type = SPDIFI1;
- } else {
+ else
da_desc.type = SPDIFIO;
- }
err = daio_mgr->get_daio(daio_mgr, &da_desc,
(struct daio **)&atc->daios[i]);
if (err) {
atc->n_pcm++;
}
- err = ct_mixer_create(atc, (struct ct_mixer **)&atc->mixer);
- if (err) {
- printk(KERN_ERR "ctxfi: Failed to create mixer obj!!!\n");
- return err;
- }
-
return 0;
}
struct src **srcs, struct srcimp **srcimps)
{
struct rsc *rscs[2] = {NULL};
- struct src *src = NULL;
- struct srcimp *srcimp = NULL;
+ struct src *src;
+ struct srcimp *srcimp;
int i = 0;
rscs[0] = &dai->daio.rscl;
static void atc_connect_resources(struct ct_atc *atc)
{
- struct dai *dai = NULL;
- struct dao *dao = NULL;
- struct src *src = NULL;
- struct sum *sum = NULL;
- struct ct_mixer *mixer = NULL;
+ struct dai *dai;
+ struct dao *dao;
+ struct src *src;
+ struct sum *sum;
+ struct ct_mixer *mixer;
struct rsc *rscs[2] = {NULL};
- int i = 0, j = 0;
+ int i, j;
mixer = atc->mixer;
}
}
-static void atc_set_ops(struct ct_atc *atc)
+#ifdef CONFIG_PM
+static int atc_suspend(struct ct_atc *atc, pm_message_t state)
{
- /* Set operations */
- atc->map_audio_buffer = ct_map_audio_buffer;
- atc->unmap_audio_buffer = ct_unmap_audio_buffer;
- atc->pcm_playback_prepare = atc_pcm_playback_prepare;
- atc->pcm_release_resources = atc_pcm_release_resources;
- atc->pcm_playback_start = atc_pcm_playback_start;
- atc->pcm_playback_stop = atc_pcm_stop;
- atc->pcm_playback_position = atc_pcm_playback_position;
- atc->pcm_capture_prepare = atc_pcm_capture_prepare;
- atc->pcm_capture_start = atc_pcm_capture_start;
- atc->pcm_capture_stop = atc_pcm_stop;
- atc->pcm_capture_position = atc_pcm_capture_position;
- atc->spdif_passthru_playback_prepare = spdif_passthru_playback_prepare;
- atc->get_ptp_phys = atc_get_ptp_phys;
- atc->select_line_in = atc_select_line_in;
- atc->select_mic_in = atc_select_mic_in;
- atc->select_digit_io = atc_select_digit_io;
- atc->line_front_unmute = atc_line_front_unmute;
- atc->line_surround_unmute = atc_line_surround_unmute;
- atc->line_clfe_unmute = atc_line_clfe_unmute;
- atc->line_rear_unmute = atc_line_rear_unmute;
- atc->line_in_unmute = atc_line_in_unmute;
- atc->spdif_out_unmute = atc_spdif_out_unmute;
- atc->spdif_in_unmute = atc_spdif_in_unmute;
- atc->spdif_out_get_status = atc_spdif_out_get_status;
- atc->spdif_out_set_status = atc_spdif_out_set_status;
- atc->spdif_out_passthru = atc_spdif_out_passthru;
- atc->have_digit_io_switch = atc_have_digit_io_switch;
+ 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, state);
+
+ return 0;
}
+static int atc_hw_resume(struct ct_atc *atc)
+{
+ struct hw *hw = atc->hw;
+ struct card_conf info = {0};
+
+ /* Re-initialize card hardware. */
+ info.rsr = atc->rsr;
+ info.msr = atc->msr;
+ info.vm_pgt_phys = atc_get_ptp_phys(atc, 0);
+ return hw->resume(hw, &info);
+}
+
+static int atc_resources_resume(struct ct_atc *atc)
+{
+ struct ct_mixer *mixer;
+ int err = 0;
+
+ /* Get resources */
+ err = atc_get_resources(atc);
+ if (err < 0) {
+ atc_release_resources(atc);
+ return err;
+ }
+
+ /* Build topology */
+ atc_connect_resources(atc);
+
+ mixer = atc->mixer;
+ mixer->resume(mixer);
+
+ return 0;
+}
+
+static int atc_resume(struct ct_atc *atc)
+{
+ int err = 0;
+
+ /* Do hardware resume. */
+ err = atc_hw_resume(atc);
+ if (err < 0) {
+ printk(KERN_ERR "ctxfi: pci_enable_device failed, "
+ "disabling device\n");
+ snd_card_disconnect(atc->card);
+ return err;
+ }
+
+ err = atc_resources_resume(atc);
+ if (err < 0)
+ return err;
+
+ snd_power_change_state(atc->card, SNDRV_CTL_POWER_D0);
+
+ return 0;
+}
+#endif
+
+static struct ct_atc atc_preset __devinitdata = {
+ .map_audio_buffer = ct_map_audio_buffer,
+ .unmap_audio_buffer = ct_unmap_audio_buffer,
+ .pcm_playback_prepare = atc_pcm_playback_prepare,
+ .pcm_release_resources = atc_pcm_release_resources,
+ .pcm_playback_start = atc_pcm_playback_start,
+ .pcm_playback_stop = atc_pcm_stop,
+ .pcm_playback_position = atc_pcm_playback_position,
+ .pcm_capture_prepare = atc_pcm_capture_prepare,
+ .pcm_capture_start = atc_pcm_capture_start,
+ .pcm_capture_stop = atc_pcm_stop,
+ .pcm_capture_position = atc_pcm_capture_position,
+ .spdif_passthru_playback_prepare = spdif_passthru_playback_prepare,
+ .get_ptp_phys = atc_get_ptp_phys,
+ .select_line_in = atc_select_line_in,
+ .select_mic_in = atc_select_mic_in,
+ .select_digit_io = atc_select_digit_io,
+ .line_front_unmute = atc_line_front_unmute,
+ .line_surround_unmute = atc_line_surround_unmute,
+ .line_clfe_unmute = atc_line_clfe_unmute,
+ .line_rear_unmute = atc_line_rear_unmute,
+ .line_in_unmute = atc_line_in_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,
+ .have_digit_io_switch = atc_have_digit_io_switch,
+#ifdef CONFIG_PM
+ .suspend = atc_suspend,
+ .resume = atc_resume,
+#endif
+};
+
/**
* ct_atc_create - create and initialize a hardware manager
* @card: corresponding alsa card object
* Returns 0 if suceeds, or negative error code if fails.
*/
-int ct_atc_create(struct snd_card *card, struct pci_dev *pci,
- unsigned int rsr, unsigned int msr, struct ct_atc **ratc)
+int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci,
+ unsigned int rsr, unsigned int msr,
+ int chip_type, unsigned int ssid,
+ struct ct_atc **ratc)
{
- struct ct_atc *atc = NULL;
+ struct ct_atc *atc;
static struct snd_device_ops ops = {
.dev_free = atc_dev_free,
};
- int err = 0;
+ int err;
*ratc = NULL;
atc = kzalloc(sizeof(*atc), GFP_KERNEL);
- if (NULL == atc)
+ if (!atc)
return -ENOMEM;
+ /* Set operations */
+ *atc = atc_preset;
+
atc->card = card;
atc->pci = pci;
atc->rsr = rsr;
atc->msr = msr;
+ atc->chip_type = chip_type;
- /* Set operations */
- atc_set_ops(atc);
-
- spin_lock_init(&atc->atc_lock);
+ mutex_init(&atc->atc_mutex);
/* Find card model */
- err = atc_identify_card(atc);
+ err = atc_identify_card(atc, ssid);
if (err < 0) {
printk(KERN_ERR "ctatc: Card not recognised\n");
goto error1;
}
/* Set up device virtual memory management object */
- err = ct_vm_create(&atc->vm);
+ err = ct_vm_create(&atc->vm, pci);
if (err < 0)
goto error1;
if (err < 0)
goto error1;
+ err = ct_mixer_create(atc, (struct ct_mixer **)&atc->mixer);
+ if (err) {
+ printk(KERN_ERR "ctxfi: Failed to create mixer obj!!!\n");
+ goto error1;
+ }
+
/* Get resources */
err = atc_get_resources(atc);
if (err < 0)
/* Build topology */
atc_connect_resources(atc);
- atc->create_alsa_devs = ct_create_alsa_devs;
+ atc->timer = ct_timer_new(atc);
+ if (!atc->timer)
+ goto error1;
err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, atc, &ops);
if (err < 0)
printk(KERN_ERR "ctxfi: Something wrong!!!\n");
return err;
}
-