include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / sound / pci / ctxfi / ctatc.c
index 7898a37..1bff80c 100644 (file)
@@ -24,6 +24,7 @@
 #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 {
@@ -123,7 +137,7 @@ static int ct_map_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm)
        struct snd_pcm_runtime *runtime;
        struct ct_vm *vm;
 
-       if (NULL == apcm->substream)
+       if (!apcm->substream)
                return 0;
 
        runtime = apcm->substream->runtime;
@@ -131,7 +145,7 @@ static int ct_map_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm)
 
        apcm->vm_block = vm->map(vm, apcm->substream, runtime->dma_bytes);
 
-       if (NULL == apcm->vm_block)
+       if (!apcm->vm_block)
                return -ENOENT;
 
        return 0;
@@ -141,7 +155,7 @@ static void ct_unmap_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm)
 {
        struct ct_vm *vm;
 
-       if (NULL == apcm->vm_block)
+       if (!apcm->vm_block)
                return;
 
        vm = atc->vm;
@@ -153,18 +167,7 @@ static void ct_unmap_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm)
 
 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)
@@ -218,16 +221,16 @@ atc_get_pitch(unsigned int input_rate, unsigned int output_rate)
 
 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 {
@@ -247,15 +250,9 @@ static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
        int n_amixer = apcm->substream->runtime->channels, i = 0;
        int device = apcm->substream->pcm->device;
        unsigned int pitch;
-       unsigned long flags;
-
-       if (NULL != apcm->src) {
-               /* Prepared pcm playback */
-               return 0;
-       }
 
        /* 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;
@@ -276,7 +273,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);
-       if (NULL == apcm->amixers) {
+       if (!apcm->amixers) {
                err = -ENOMEM;
                goto error1;
        }
@@ -299,12 +296,12 @@ 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];
-               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;
        }
 
@@ -327,7 +324,7 @@ atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm)
        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);
@@ -338,7 +335,7 @@ atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm)
                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;
@@ -347,7 +344,7 @@ atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm)
                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;
@@ -356,17 +353,17 @@ atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm)
                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;
@@ -380,6 +377,10 @@ static int atc_pcm_playback_start(struct ct_atc *atc, struct ct_atc_pcm *apcm)
        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);
 
@@ -408,7 +409,7 @@ static int atc_pcm_stop(struct ct_atc *atc, struct ct_atc_pcm *apcm)
        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);
@@ -429,6 +430,8 @@ atc_pcm_playback_position(struct ct_atc *atc, struct ct_atc_pcm *apcm)
        u32 size, max_cisz;
        int position;
 
+       if (!src)
+               return 0;
        position = src->ops->get_ca(src);
 
        size = apcm->vm_block->size;
@@ -505,7 +508,7 @@ atc_pcm_capture_get_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm)
        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. */
@@ -531,18 +534,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);
-               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;
        }
@@ -643,10 +646,7 @@ static int atc_pcm_capture_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
        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);
@@ -766,6 +766,8 @@ atc_pcm_capture_position(struct ct_atc *atc, struct ct_atc_pcm *apcm)
 {
        struct src *src = apcm->src;
 
+       if (!src)
+               return 0;
        return src->ops->get_ca(src) - apcm->vm_block->addr;
 }
 
@@ -782,7 +784,7 @@ static int spdif_passthru_playback_get_resources(struct ct_atc *atc,
        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;
@@ -806,7 +808,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);
-       if (NULL == apcm->amixers) {
+       if (!apcm->amixers) {
                err = -ENOMEM;
                goto error1;
        }
@@ -845,10 +847,9 @@ 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;
-       int err;
+       int err = 0;
        unsigned char iec958_con_fs;
 
        switch (rate) {
@@ -865,7 +866,7 @@ spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm)
                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);
@@ -875,7 +876,7 @@ 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);
-       spin_unlock_irqrestore(&atc->atc_lock, flags);
+       mutex_unlock(&atc->atc_mutex);
 
        return err;
 }
@@ -888,10 +889,8 @@ spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
        struct dao *dao;
        int err;
        int i;
-       unsigned long flags;
 
-       if (NULL != apcm->src)
-               return 0;
+       atc_pcm_release_resources(atc, apcm);
 
        /* Configure SPDIFOO and PLL to passthrough mode;
         * determine pll_rate. */
@@ -910,17 +909,17 @@ spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm)
                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);
 
@@ -1028,7 +1027,7 @@ static int atc_line_front_unmute(struct ct_atc *atc, unsigned char state)
 
 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)
@@ -1038,7 +1037,7 @@ 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)
@@ -1068,7 +1067,6 @@ static int atc_spdif_out_set_status(struct ct_atc *atc, unsigned int status)
 
 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;
        int err;
@@ -1076,7 +1074,7 @@ static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state)
        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;
@@ -1094,38 +1092,26 @@ static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state)
        }
        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)
 {
-       struct daio_mgr *daio_mgr;
-       struct dao *dao;
-       struct dai *dai;
-       struct daio *daio;
-       struct sum_mgr *sum_mgr;
-       struct src_mgr *src_mgr;
-       struct srcimp_mgr *srcimp_mgr;
-       struct srcimp *srcimp;
-       struct ct_mixer *mixer;
-       int i = 0;
-
-       if (NULL == atc)
-               return 0;
-
-       if (atc->timer) {
-               ct_timer_free(atc->timer);
-               atc->timer = NULL;
-       }
-
-       /* 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) {
+       int i;
+       struct daio_mgr *daio_mgr = NULL;
+       struct dao *dao = NULL;
+       struct dai *dai = NULL;
+       struct daio *daio = NULL;
+       struct sum_mgr *sum_mgr = NULL;
+       struct src_mgr *src_mgr = NULL;
+       struct srcimp_mgr *srcimp_mgr = NULL;
+       struct srcimp *srcimp = NULL;
+       struct ct_mixer *mixer = NULL;
+
+       /* 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);
@@ -1133,10 +1119,9 @@ static int ct_atc_destroy(struct ct_atc *atc)
                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];
@@ -1151,25 +1136,28 @@ static int ct_atc_destroy(struct ct_atc *atc)
                        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];
@@ -1177,20 +1165,41 @@ static int ct_atc_destroy(struct ct_atc *atc)
                        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;
        }
@@ -1206,67 +1215,62 @@ static int atc_dev_free(struct snd_device *dev)
        return ct_atc_destroy(atc);
 }
 
-static int __devinit 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;
 }
 
 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,
@@ -1287,7 +1291,7 @@ static int __devinit atc_create_hw_devs(struct ct_atc *atc)
        struct card_conf info = {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;
@@ -1303,7 +1307,7 @@ static int __devinit atc_create_hw_devs(struct ct_atc *atc)
                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]);
@@ -1317,7 +1321,7 @@ static int __devinit atc_create_hw_devs(struct ct_atc *atc)
        return 0;
 }
 
-static int __devinit atc_get_resources(struct ct_atc *atc)
+static int atc_get_resources(struct ct_atc *atc)
 {
        struct daio_desc da_desc = {0};
        struct daio_mgr *daio_mgr;
@@ -1328,22 +1332,21 @@ static int __devinit atc_get_resources(struct ct_atc *atc)
        struct sum_desc sum_dsc = {0};
        struct sum_mgr *sum_mgr;
        int err, i;
-       unsigned short subsys_id;
 
        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];
@@ -1359,13 +1362,10 @@ static int __devinit atc_get_resources(struct ct_atc *atc)
                }
                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) {
@@ -1418,16 +1418,10 @@ static int __devinit atc_get_resources(struct ct_atc *atc)
                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;
 }
 
-static void __devinit
+static void
 atc_connect_dai(struct src_mgr *src_mgr, struct dai *dai,
                struct src **srcs, struct srcimp **srcimps)
 {
@@ -1466,7 +1460,7 @@ atc_connect_dai(struct src_mgr *src_mgr, struct dai *dai,
        src_mgr->commit_write(src_mgr); /* Synchronously enable SRCs */
 }
 
-static void __devinit atc_connect_resources(struct ct_atc *atc)
+static void atc_connect_resources(struct ct_atc *atc)
 {
        struct dai *dai;
        struct dao *dao;
@@ -1512,6 +1506,84 @@ static void __devinit atc_connect_resources(struct ct_atc *atc)
        }
 }
 
+#ifdef CONFIG_PM
+static int atc_suspend(struct ct_atc *atc, pm_message_t state)
+{
+       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,
@@ -1540,6 +1612,10 @@ static struct ct_atc atc_preset __devinitdata = {
        .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
 };
 
 /**
@@ -1555,7 +1631,9 @@ static struct ct_atc atc_preset __devinitdata = {
  */
 
 int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci,
-                 unsigned int rsr, unsigned int msr, struct ct_atc **ratc)
+                           unsigned int rsr, unsigned int msr,
+                           int chip_type, unsigned int ssid,
+                           struct ct_atc **ratc)
 {
        struct ct_atc *atc;
        static struct snd_device_ops ops = {
@@ -1566,7 +1644,7 @@ int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci,
        *ratc = NULL;
 
        atc = kzalloc(sizeof(*atc), GFP_KERNEL);
-       if (NULL == atc)
+       if (!atc)
                return -ENOMEM;
 
        /* Set operations */
@@ -1576,18 +1654,19 @@ int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci,
        atc->pci = pci;
        atc->rsr = rsr;
        atc->msr = msr;
+       atc->chip_type = chip_type;
 
-       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;
 
@@ -1596,6 +1675,12 @@ int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci,
        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)