ALSA: ctxfi - Clean up probe routines
authorTakashi Iwai <tiwai@suse.de>
Mon, 8 Jun 2009 16:10:32 +0000 (18:10 +0200)
committerTakashi Iwai <tiwai@suse.de>
Mon, 8 Jun 2009 16:10:32 +0000 (18:10 +0200)
Clean up probe routines and model detection routines so that the driver
won't call and check the PCI subsystem id at each time.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/ctxfi/ctatc.c
sound/pci/ctxfi/ctatc.h
sound/pci/ctxfi/ctdaio.c
sound/pci/ctxfi/cthardware.c
sound/pci/ctxfi/cthardware.h
sound/pci/ctxfi/cthw20k1.c
sound/pci/ctxfi/xfi.c

index 7898a37..002a70e 100644 (file)
                            | (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, 0x6000,
+                          PCI_SUBDEVICE_ID_CREATIVE_HENDRIX, "UAA", CTUAA),
+       SND_PCI_QUIRK_VENDOR(PCI_VENDOR_ID_CREATIVE,
+                            "Unknown", CT20K1_UNKNOWN),
+       { } /* 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, 0x6000,
+                          PCI_SUBDEVICE_ID_CREATIVE_HENDRIX, "UAA", CTHENDRIX),
+       { } /* terminator */
+};
+
+static const char *ct_subsys_name[NUM_CTCARDS] = {
+       [CTSB055X]      = "SB055x",
+       [CTSB073X]      = "SB073x",
+       [CTSB0760]      = "SB076x",
+       [CTUAA]         = "UAA",
+       [CT20K1_UNKNOWN] = "Unknown",
+       [CTHENDRIX]     = "Hendrix",
+       [CTSB0880]      = "SB0880",
 };
 
 static struct {
@@ -1208,62 +1219,39 @@ static int atc_dev_free(struct snd_device *dev)
 
 static int __devinit atc_identify_card(struct ct_atc *atc)
 {
-       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;
+       const struct snd_pci_quirk *p;
+       const struct snd_pci_quirk *list;
 
-               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;
-
-               atc->chip_details = d;
+       switch (atc->chip_type) {
+       case ATC20K1:
+               atc->chip_name = "20K1";
+               list = subsys_20k1_list;
+               break;
+       case ATC20K2:
+               atc->chip_name = "20K2";
+               list = subsys_20k2_list;
                break;
-               /* not take revision into consideration now */
+       default:
+               return -ENOENT;
        }
-       if (!d->vendor)
+       p = snd_pci_quirk_lookup(atc->pci, list);
+       if (!p)
                return -ENOENT;
-
+       atc->model = p->value;
+       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,
+                  atc->pci->subsystem_vendor,
+                  atc->pci->subsystem_device);
        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)
@@ -1287,7 +1275,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;
@@ -1328,7 +1316,6 @@ 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)
@@ -1359,13 +1346,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) {
@@ -1555,7 +1539,8 @@ 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, struct ct_atc **ratc)
 {
        struct ct_atc *atc;
        static struct snd_device_ops ops = {
@@ -1576,6 +1561,7 @@ 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);
 
index 04459aa..a033472 100644 (file)
@@ -37,15 +37,6 @@ enum CTALSADEVS {            /* Types of alsa devices */
        NUM_CTALSADEVS          /* This should always be the last */
 };
 
-enum CTCARDS {
-       CTSB0760,
-       CTHENDRIX,
-       CTSB08801,
-       CTSB08802,
-       CTSB08803,
-       NUM_CTCARDS             /* This should always be the last */
-};
-
 struct ct_atc_chip_sub_details {
        u16 subsys;
        const char *nm_model;
@@ -89,8 +80,10 @@ struct ct_atc {
        unsigned int msr; /* master sample rate in rsr */
        unsigned int pll_rate; /* current rate of Phase Lock Loop */
 
-       const struct ct_atc_chip_details *chip_details;
-       enum CTCARDS model;
+       int chip_type;
+       int model;
+       const char *chip_name;
+       const char *model_name;
 
        struct ct_vm *vm; /* device virtual memory manager for this card */
        int (*map_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm);
@@ -147,7 +140,7 @@ struct ct_atc {
 
 
 int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci,
-                           unsigned int rsr, unsigned int msr,
+                           unsigned int rsr, unsigned int msr, int chip_type,
                            struct ct_atc **ratc);
 int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc);
 
index befead4..082e35c 100644 (file)
@@ -116,7 +116,7 @@ static struct rsc_ops daio_in_rsc_ops_20k2 = {
 
 static unsigned int daio_device_index(enum DAIOTYP type, struct hw *hw)
 {
-       switch (hw->get_chip_type(hw)) {
+       switch (hw->chip_type) {
        case ATC20K1:
                switch (type) {
                case SPDIFOO:   return 0;
@@ -343,7 +343,7 @@ static int daio_rsc_init(struct daio *daio,
        int err;
        unsigned int idx_l, idx_r;
 
-       switch (((struct hw *)hw)->get_chip_type(hw)) {
+       switch (((struct hw *)hw)->chip_type) {
        case ATC20K1:
                idx_l = idx_20k1[desc->type].left;
                idx_r = idx_20k1[desc->type].right;
@@ -367,7 +367,7 @@ static int daio_rsc_init(struct daio *daio,
        if (desc->type <= DAIO_OUT_MAX) {
                daio->rscl.ops = daio->rscr.ops = &daio_out_rsc_ops;
        } else {
-               switch (((struct hw *)hw)->get_chip_type(hw)) {
+               switch (((struct hw *)hw)->chip_type) {
                case ATC20K1:
                        daio->rscl.ops = daio->rscr.ops = &daio_in_rsc_ops_20k1;
                        break;
index 5ec6813..8e64f48 100644 (file)
 #include "cthw20k2.h"
 #include <linux/bug.h>
 
-static enum CHIPTYP __devinitdata get_chip_type(struct hw *hw)
-{
-       enum CHIPTYP type;
-
-       switch (hw->pci->device) {
-       case 0x0005:    /* 20k1 device */
-               type = ATC20K1;
-               break;
-       case 0x000B:    /* 20k2 device */
-               type = ATC20K2;
-               break;
-       default:
-               type = ATCNONE;
-               break;
-       }
-
-       return type;
-}
-
-int __devinit create_hw_obj(struct pci_dev *pci, struct hw **rhw)
+int __devinit create_hw_obj(struct pci_dev *pci, enum CHIPTYP chip_type,
+                           enum CTCARDS model, struct hw **rhw)
 {
        int err;
 
-       switch (pci->device) {
-       case 0x0005:    /* 20k1 device */
+       switch (chip_type) {
+       case ATC20K1:
                err = create_20k1_hw_obj(rhw);
                break;
-       case 0x000B:    /* 20k2 device */
+       case ATC20K2:
                err = create_20k2_hw_obj(rhw);
                break;
        default:
@@ -58,7 +40,8 @@ int __devinit create_hw_obj(struct pci_dev *pci, struct hw **rhw)
                return err;
 
        (*rhw)->pci = pci;
-       (*rhw)->get_chip_type = get_chip_type;
+       (*rhw)->chip_type = chip_type;
+       (*rhw)->model = model;
 
        return 0;
 }
index 8f11644..4a8e04f 100644 (file)
@@ -27,6 +27,19 @@ enum CHIPTYP {
        ATCNONE
 };
 
+enum CTCARDS {
+       /* 20k1 models */
+       CTSB055X,
+       CTSB073X,
+       CTUAA,
+       CT20K1_UNKNOWN,
+       /* 20k2 models */
+       CTSB0760,
+       CTHENDRIX,
+       CTSB0880,
+       NUM_CTCARDS             /* This should always be the last */
+};
+
 /* Type of input source for ADC */
 enum ADCSRC{
        ADC_MICIN,
@@ -48,7 +61,6 @@ struct hw {
        int (*card_init)(struct hw *hw, struct card_conf *info);
        int (*card_stop)(struct hw *hw);
        int (*pll_init)(struct hw *hw, unsigned int rsr);
-       enum CHIPTYP (*get_chip_type)(struct hw *hw);
        int (*is_adc_source_selected)(struct hw *hw, enum ADCSRC source);
        int (*select_adc_source)(struct hw *hw, enum ADCSRC source);
        int (*have_digit_io_switch)(struct hw *hw);
@@ -156,9 +168,13 @@ struct hw {
        int irq;
        unsigned long io_base;
        unsigned long mem_base;
+
+       enum CHIPTYP chip_type;
+       enum CTCARDS model;
 };
 
-int create_hw_obj(struct pci_dev *pci, struct hw **rhw);
+int create_hw_obj(struct pci_dev *pci, enum CHIPTYP chip_type,
+                 enum CTCARDS model, struct hw **rhw);
 int destroy_hw_obj(struct hw *hw);
 
 unsigned int get_field(unsigned int data, unsigned int field);
index 38b87b6..5d58650 100644 (file)
@@ -1432,11 +1432,9 @@ static int hw_dac_init(struct hw *hw, const struct dac_conf *info)
 {
        u32 data;
        u16 gpioorg;
-       u16 subsys_id;
        unsigned int ret;
 
-       pci_read_config_word(hw->pci, PCI_SUBSYSTEM_ID, &subsys_id);
-       if ((subsys_id == 0x0022) || (subsys_id == 0x002F)) {
+       if (hw->model == CTSB055X) {
                /* SB055x, unmute outputs */
                gpioorg = (u16)hw_read_20kx(hw, GPIO);
                gpioorg &= 0xffbf;      /* set GPIO6 to low */
@@ -1538,19 +1536,14 @@ static int is_adc_input_selected_hendrix(struct hw *hw, enum ADCSRC type)
 
 static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type)
 {
-       u16 subsys_id;
-
-       pci_read_config_word(hw->pci, PCI_SUBSYSTEM_ID, &subsys_id);
-       if ((subsys_id == 0x0022) || (subsys_id == 0x002F)) {
-               /* SB055x cards */
+       switch (hw->model) {
+       case CTSB055X:
                return is_adc_input_selected_SB055x(hw, type);
-       } else if ((subsys_id == 0x0029) || (subsys_id == 0x0031)) {
-               /* SB073x cards */
+       case CTSB073X:
                return is_adc_input_selected_hendrix(hw, type);
-       } else if ((subsys_id & 0xf000) == 0x6000) {
-               /* Vista compatible cards */
+       case CTHENDRIX:
                return is_adc_input_selected_hendrix(hw, type);
-       } else {
+       default:
                return is_adc_input_selected_SBx(hw, type);
        }
 }
@@ -1692,20 +1685,17 @@ adc_input_select_hendrix(struct hw *hw, enum ADCSRC type, unsigned char boost)
 
 static int hw_adc_input_select(struct hw *hw, enum ADCSRC type)
 {
-       u16 subsys_id;
-
-       pci_read_config_word(hw->pci, PCI_SUBSYSTEM_ID, &subsys_id);
-       if ((subsys_id == 0x0022) || (subsys_id == 0x002F)) {
-               /* SB055x cards */
-               return adc_input_select_SB055x(hw, type, (ADC_MICIN == type));
-       } else if ((subsys_id == 0x0029) || (subsys_id == 0x0031)) {
-               /* SB073x cards */
-               return adc_input_select_hendrix(hw, type, (ADC_MICIN == type));
-       } else if ((subsys_id & 0xf000) == 0x6000) {
-               /* Vista compatible cards */
-               return adc_input_select_hendrix(hw, type, (ADC_MICIN == type));
-       } else {
-               return adc_input_select_SBx(hw, type, (ADC_MICIN == type));
+       int state = type == ADC_MICIN;
+
+       switch (hw->model) {
+       case CTSB055X:
+               return adc_input_select_SB055x(hw, type, state);
+       case CTSB073X:
+               return adc_input_select_hendrix(hw, type, state);
+       case CTHENDRIX:
+               return adc_input_select_hendrix(hw, type, state);
+       default:
+               return adc_input_select_SBx(hw, type, state);
        }
 }
 
@@ -1781,28 +1771,16 @@ static int adc_init_SBx(struct hw *hw, int input, int mic20db)
 
 static int hw_adc_init(struct hw *hw, const struct adc_conf *info)
 {
-       int err;
-       u16 subsys_id;
-
-       pci_read_config_word(hw->pci, PCI_SUBSYSTEM_ID, &subsys_id);
-       if ((subsys_id == 0x0022) || (subsys_id == 0x002F)) {
-               /* Sb055x card */
-               err = adc_init_SB055x(hw, info->input, info->mic20db);
-       } else {
-               err = adc_init_SBx(hw, info->input, info->mic20db);
-       }
-
-       return err;
+       if (hw->model == CTSB055X)
+               return adc_init_SB055x(hw, info->input, info->mic20db);
+       else
+               return adc_init_SBx(hw, info->input, info->mic20db);
 }
 
 static int hw_have_digit_io_switch(struct hw *hw)
 {
-       u16 subsys_id;
-
-       pci_read_config_word(hw->pci, PCI_SUBSYSTEM_ID, &subsys_id);
        /* SB073x and Vista compatible cards have no digit IO switch */
-       return !((subsys_id == 0x0029) || (subsys_id == 0x0031)
-                               || ((subsys_id & 0xf000) == 0x6000));
+       return !(hw->model == CTSB073X || hw->model == CTHENDRIX);
 }
 
 #define CTLBITS(a, b, c, d)    (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
@@ -1918,7 +1896,6 @@ static int hw_card_start(struct hw *hw)
 {
        int err;
        struct pci_dev *pci = hw->pci;
-       u16 subsys_id;
 
        err = pci_enable_device(pci);
        if (err < 0)
@@ -1939,8 +1916,7 @@ static int hw_card_start(struct hw *hw)
                goto error1;
 
        /* Switch to X-Fi mode from UAA mode if neeeded */
-       pci_read_config_word(pci, PCI_SUBSYSTEM_ID, &subsys_id);
-       if ((0x5 == pci->device) && (0x6000 == (subsys_id & 0x6000))) {
+       if (hw->model == CTHENDRIX) {
                err = uaa_to_xfi(pci);
                if (err)
                        goto error2;
@@ -2004,7 +1980,6 @@ static int hw_card_init(struct hw *hw, struct card_conf *info)
 {
        int err;
        unsigned int gctl;
-       u16 subsys_id;
        u32 data;
        struct dac_conf dac_info = {0};
        struct adc_conf adc_info = {0};
@@ -2044,19 +2019,20 @@ static int hw_card_init(struct hw *hw, struct card_conf *info)
        hw_write_20kx(hw, SRCIP, 0);
        mdelay(30);
 
-       pci_read_config_word(hw->pci, PCI_SUBSYSTEM_ID, &subsys_id);
        /* Detect the card ID and configure GPIO accordingly. */
-       if ((subsys_id == 0x0022) || (subsys_id == 0x002F)) {
-               /* SB055x cards */
+       switch (hw->model) {
+       case CTSB055X:
                hw_write_20kx(hw, GPIOCTL, 0x13fe);
-       } else if ((subsys_id == 0x0029) || (subsys_id == 0x0031)) {
-               /* SB073x cards */
+               break;
+       case CTSB073X:
                hw_write_20kx(hw, GPIOCTL, 0x00e6);
-       } else if ((subsys_id & 0xf000) == 0x6000) {
-               /* Vista compatible cards */
+               break;
+       case CTHENDRIX: /* Vista compatible cards */
                hw_write_20kx(hw, GPIOCTL, 0x00c2);
-       } else {
+               break;
+       default:
                hw_write_20kx(hw, GPIOCTL, 0x01e6);
+               break;
        }
 
        trn_info.vm_pgt_phys = info->vm_pgt_phys;
index 279dac6..2d3dd89 100644 (file)
@@ -15,6 +15,7 @@
 #include <sound/core.h>
 #include <sound/initval.h>
 #include "ctatc.h"
+#include "cthardware.h"
 
 MODULE_AUTHOR("Creative Technology Ltd");
 MODULE_DESCRIPTION("X-Fi driver version 1.03");
@@ -41,8 +42,12 @@ MODULE_PARM_DESC(enable, "Enable Creative X-Fi driver");
 
 static struct pci_device_id ct_pci_dev_ids[] = {
        /* only X-Fi is supported, so... */
-       { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_20K1) },
-       { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_20K2) },
+       { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_20K1),
+         .driver_data = ATC20K1,
+       },
+       { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_20K2),
+         .driver_data = ATC20K2,
+       },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, ct_pci_dev_ids);
@@ -79,7 +84,8 @@ ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
                       "1 and 2, Value 2 is assumed.\n");
                multiple = 2;
        }
-       err = ct_atc_create(card, pci, reference_rate, multiple, &atc);
+       err = ct_atc_create(card, pci, reference_rate, multiple,
+                           pci_id->driver_data, &atc);
        if (err < 0)
                goto error;
 
@@ -92,7 +98,8 @@ ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
 
        strcpy(card->driver, "SB-XFi");
        strcpy(card->shortname, "Creative X-Fi");
-       strcpy(card->longname, "Creative ALSA Driver X-Fi");
+       snprintf(card->longname, sizeof(card->longname), "%s %s %s",
+                card->shortname, atc->chip_name, atc->model_name);
 
        err = snd_card_register(card);
        if (err < 0)