[IA64] MCA recovery: pfn_valid() needs a pfn
[powerpc.git] / sound / pci / ac97 / ac97_codec.c
index 6983eea..9bde76c 100644 (file)
@@ -112,6 +112,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
 { 0x414c4723, 0xffffffff, "ALC650F",           NULL,   NULL }, /* already patched */
 { 0x414c4720, 0xfffffff0, "ALC650",            patch_alc650,   NULL },
 { 0x414c4760, 0xfffffff0, "ALC655",            patch_alc655,   NULL },
+{ 0x414c4781, 0xffffffff, "ALC658D",           NULL,   NULL }, /* already patched */
 { 0x414c4780, 0xfffffff0, "ALC658",            patch_alc655,   NULL },
 { 0x414c4790, 0xfffffff0, "ALC850",            patch_alc850,   NULL },
 { 0x414c4730, 0xffffffff, "ALC101",            NULL,           NULL },
@@ -157,6 +158,7 @@ static const ac97_codec_id_t snd_ac97_codec_ids[] = {
 { 0x54524123, 0xffffffff, "TR28602",           NULL,           NULL }, // only guess --jk [TR28023 = eMicro EM28023 (new CT1297)]
 { 0x54584e20, 0xffffffff, "TLC320AD9xC",       NULL,           NULL },
 { 0x56494161, 0xffffffff, "VIA1612A",          NULL,           NULL }, // modified ICE1232 with S/PDIF
+{ 0x56494170, 0xffffffff, "VIA1617A",          patch_vt1617a,  NULL }, // modified VT1616 with S/PDIF
 { 0x57454301, 0xffffffff, "W83971D",           NULL,           NULL },
 { 0x574d4c00, 0xffffffff, "WM9701A",           NULL,           NULL },
 { 0x574d4C03, 0xffffffff, "WM9703,WM9707,WM9708,WM9717", patch_wolfson03, NULL},
@@ -218,12 +220,6 @@ const char *snd_ac97_stereo_enhancements[] =
   /*  31 */ "Reserved 31"
 };
 
-/*
- * Shared AC97 controllers (ICH, ATIIXP...)
- */
-static DECLARE_MUTEX(shared_codec_mutex);
-static ac97_t *shared_codec[AC97_SHARED_TYPES][4];
-
 
 /*
  *  I/O routines
@@ -994,14 +990,8 @@ static int snd_ac97_free(ac97_t *ac97)
 {
        if (ac97) {
                snd_ac97_proc_done(ac97);
-               if (ac97->bus) {
+               if (ac97->bus)
                        ac97->bus->codec[ac97->num] = NULL;
-                       if (ac97->bus->shared_type) {
-                               down(&shared_codec_mutex);
-                               shared_codec[ac97->bus->shared_type-1][ac97->num] = NULL;
-                               up(&shared_codec_mutex);
-                       }
-               }
                if (ac97->private_free)
                        ac97->private_free(ac97);
                kfree(ac97);
@@ -1137,7 +1127,6 @@ snd_kcontrol_t *snd_ac97_cnew(const snd_kcontrol_new_t *_template, ac97_t * ac97
 {
        snd_kcontrol_new_t template;
        memcpy(&template, _template, sizeof(template));
-       snd_runtime_check(!template.index, return NULL);
        template.index = ac97->num;
        return snd_ctl_new1(&template, ac97);
 }
@@ -1307,16 +1296,18 @@ static int snd_ac97_mixer_build(ac97_t * ac97)
        }
        
        /* build master tone controls */
-       if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_TONE)) {
-               for (idx = 0; idx < 2; idx++) {
-                       if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_tone[idx], ac97))) < 0)
-                               return err;
-                       if (ac97->id == AC97_ID_YMF753) {
-                               kctl->private_value &= ~(0xff << 16);
-                               kctl->private_value |= 7 << 16;
+       if (!(ac97->flags & AC97_HAS_NO_TONE)) {
+               if (snd_ac97_try_volume_mix(ac97, AC97_MASTER_TONE)) {
+                       for (idx = 0; idx < 2; idx++) {
+                               if ((err = snd_ctl_add(card, kctl = snd_ac97_cnew(&snd_ac97_controls_tone[idx], ac97))) < 0)
+                                       return err;
+                               if (ac97->id == AC97_ID_YMF753) {
+                                       kctl->private_value &= ~(0xff << 16);
+                                       kctl->private_value |= 7 << 16;
+                               }
                        }
+                       snd_ac97_write_cache(ac97, AC97_MASTER_TONE, 0x0f0f);
                }
-               snd_ac97_write_cache(ac97, AC97_MASTER_TONE, 0x0f0f);
        }
        
        /* build PC Speaker controls */
@@ -1339,11 +1330,13 @@ static int snd_ac97_mixer_build(ac97_t * ac97)
        }
        
        /* build MIC controls */
-       if (snd_ac97_try_volume_mix(ac97, AC97_MIC)) {
-               if ((err = snd_ac97_cmix_new(card, "Mic Playback", AC97_MIC, ac97)) < 0)
-                       return err;
-               if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97))) < 0)
-                       return err;
+       if (!(ac97->flags & AC97_HAS_NO_MIC)) {
+               if (snd_ac97_try_volume_mix(ac97, AC97_MIC)) {
+                       if ((err = snd_ac97_cmix_new(card, "Mic Playback", AC97_MIC, ac97)) < 0)
+                               return err;
+                       if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_mic_boost, ac97))) < 0)
+                               return err;
+               }
        }
 
        /* build Line controls */
@@ -1402,12 +1395,14 @@ static int snd_ac97_mixer_build(ac97_t * ac97)
                }
                snd_ac97_write_cache(ac97, AC97_PCM, init_val);
        } else {
-               if (ac97->flags & AC97_HAS_NO_PCM_VOL)
-                       err = snd_ac97_cmute_new(card, "PCM Playback Switch", AC97_PCM, ac97);
-               else
-                       err = snd_ac97_cmix_new(card, "PCM Playback", AC97_PCM, ac97);
-               if (err < 0)
-                       return err;
+               if (!(ac97->flags & AC97_HAS_NO_STD_PCM)) {
+                       if (ac97->flags & AC97_HAS_NO_PCM_VOL)
+                               err = snd_ac97_cmute_new(card, "PCM Playback Switch", AC97_PCM, ac97);
+                       else
+                               err = snd_ac97_cmix_new(card, "PCM Playback", AC97_PCM, ac97);
+                       if (err < 0)
+                               return err;
+               }
        }
 
        /* build Capture controls */
@@ -1549,7 +1544,7 @@ static int snd_ac97_modem_build(snd_card_t * card, ac97_t * ac97)
 
        /* build modem switches */
        for (idx = 0; idx < ARRAY_SIZE(snd_ac97_controls_modem_switches); idx++)
-               if ((err = snd_ctl_add(card, snd_ac97_cnew(&snd_ac97_controls_modem_switches[idx], ac97))) < 0)
+               if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_ac97_controls_modem_switches[idx], ac97))) < 0)
                        return err;
 
        /* build chip specific controls */
@@ -1750,8 +1745,7 @@ static int ac97_reset_wait(ac97_t *ac97, int timeout, int with_modem)
                        if ((snd_ac97_read(ac97, AC97_REC_GAIN) & 0x7fff) == 0x0a05)
                                return 0;
                }
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(1);
+               schedule_timeout_uninterruptible(1);
        } while (time_after_eq(end_time, jiffies));
        return -ENODEV;
 }
@@ -1789,7 +1783,7 @@ int snd_ac97_bus(snd_card_t *card, int num, ac97_bus_ops_t *ops,
 
        snd_assert(card != NULL, return -EINVAL);
        snd_assert(rbus != NULL, return -EINVAL);
-       bus = kcalloc(1, sizeof(*bus), GFP_KERNEL);
+       bus = kzalloc(sizeof(*bus), GFP_KERNEL);
        if (bus == NULL)
                return -ENOMEM;
        bus->card = card;
@@ -1807,6 +1801,38 @@ int snd_ac97_bus(snd_card_t *card, int num, ac97_bus_ops_t *ops,
        return 0;
 }
 
+/* stop no dev release warning */
+static void ac97_device_release(struct device * dev)
+{
+}
+
+/* register ac97 codec to bus */
+static int snd_ac97_dev_register(snd_device_t *device)
+{
+       ac97_t *ac97 = device->device_data;
+       int err;
+
+       ac97->dev.bus = &ac97_bus_type;
+       ac97->dev.parent = ac97->bus->card->dev;
+       ac97->dev.release = ac97_device_release;
+       snprintf(ac97->dev.bus_id, BUS_ID_SIZE, "card%d-%d", ac97->bus->card->number, ac97->num);
+       if ((err = device_register(&ac97->dev)) < 0) {
+               snd_printk(KERN_ERR "Can't register ac97 bus\n");
+               ac97->dev.bus = NULL;
+               return err;
+       }
+       return 0;
+}
+
+/* unregister ac97 codec */
+static int snd_ac97_dev_unregister(snd_device_t *device)
+{
+       ac97_t *ac97 = device->device_data;
+       if (ac97->dev.bus)
+               device_unregister(&ac97->dev);
+       return snd_ac97_free(ac97);
+}
+
 /* build_ops to do nothing */
 static struct snd_ac97_build_ops null_build_ops;
 
@@ -1840,6 +1866,8 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97)
        const ac97_codec_id_t *pid;
        static snd_device_ops_t ops = {
                .dev_free =     snd_ac97_dev_free,
+               .dev_register = snd_ac97_dev_register,
+               .dev_unregister =       snd_ac97_dev_unregister,
        };
 
        snd_assert(rac97 != NULL, return -EINVAL);
@@ -1847,23 +1875,8 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97)
        snd_assert(bus != NULL && template != NULL, return -EINVAL);
        snd_assert(template->num < 4 && bus->codec[template->num] == NULL, return -EINVAL);
 
-       snd_assert(bus->shared_type <= AC97_SHARED_TYPES, return -EINVAL);
-       if (bus->shared_type) {
-               /* already shared? */
-               down(&shared_codec_mutex);
-               ac97 = shared_codec[bus->shared_type-1][template->num];
-               if (ac97) {
-                       if ((ac97_is_audio(ac97) && (template->scaps & AC97_SCAP_SKIP_AUDIO)) ||
-                           (ac97_is_modem(ac97) && (template->scaps & AC97_SCAP_SKIP_MODEM))) {
-                               up(&shared_codec_mutex);
-                               return -EACCES; /* skip this */
-                       }
-               }
-               up(&shared_codec_mutex);
-       }
-
        card = bus->card;
-       ac97 = kcalloc(1, sizeof(*ac97), GFP_KERNEL);
+       ac97 = kzalloc(sizeof(*ac97), GFP_KERNEL);
        if (ac97 == NULL)
                return -ENOMEM;
        ac97->private_data = template->private_data;
@@ -1978,8 +1991,7 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97)
                do {
                        if ((snd_ac97_read(ac97, AC97_POWERDOWN) & 0x0f) == 0x0f)
                                goto __ready_ok;
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       schedule_timeout(1);
+                       schedule_timeout_uninterruptible(1);
                } while (time_after_eq(end_time, jiffies));
                snd_printk(KERN_WARNING "AC'97 %d analog subsections not ready\n", ac97->num);
        }
@@ -2011,8 +2023,7 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97)
                do {
                        if ((snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS) & tmp) == tmp)
                                goto __ready_ok;
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       schedule_timeout(1);
+                       schedule_timeout_uninterruptible(1);
                } while (time_after_eq(end_time, jiffies));
                snd_printk(KERN_WARNING "MC'97 %d converters and GPIO not ready (0x%x)\n", ac97->num, snd_ac97_read(ac97, AC97_EXTENDED_MSTATUS));
        }
@@ -2035,6 +2046,8 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97)
                snd_ac97_update_bits(ac97, AC97_GENERAL_PURPOSE, AC97_GP_DRSS_MASK, AC97_GP_DRSS_78);
                if ((snd_ac97_read(ac97, AC97_GENERAL_PURPOSE) & AC97_GP_DRSS_MASK) == AC97_GP_DRSS_78)
                        ac97->flags |= AC97_DOUBLE_RATE;
+               /* restore to slots 10/11 to avoid the confliction with surrounds */
+               snd_ac97_update_bits(ac97, AC97_GENERAL_PURPOSE, AC97_GP_DRSS_MASK, 0);
        }
        if (ac97->ext_id & AC97_EI_VRA) {       /* VRA support */
                snd_ac97_determine_rates(ac97, AC97_PCM_FRONT_DAC_RATE, 0, &ac97->rates[AC97_RATES_FRONT_DAC]);
@@ -2111,7 +2124,7 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97)
                }
        }
        /* make sure the proper powerdown bits are cleared */
-       if (ac97->scaps) {
+       if (ac97->scaps && ac97_is_audio(ac97)) {
                reg = snd_ac97_read(ac97, AC97_EXTENDED_STATUS);
                if (ac97->scaps & AC97_SCAP_SURROUND_DAC) 
                        reg &= ~AC97_EA_PRJ;
@@ -2125,13 +2138,6 @@ int snd_ac97_mixer(ac97_bus_t *bus, ac97_template_t *template, ac97_t **rac97)
                return err;
        }
        *rac97 = ac97;
-
-       if (bus->shared_type) {
-               down(&shared_codec_mutex);
-               shared_codec[bus->shared_type-1][ac97->num] = ac97;
-               up(&shared_codec_mutex);
-       }
-
        return 0;
 }
 
@@ -2253,8 +2259,7 @@ void snd_ac97_resume(ac97_t *ac97)
                do {
                        if (snd_ac97_read(ac97, AC97_MASTER) == 0x8101)
                                break;
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       schedule_timeout(1);
+                       schedule_timeout_uninterruptible(1);
                } while (time_after_eq(end_time, jiffies));
                /* FIXME: extra delay */
                ac97->bus->ops->write(ac97, AC97_MASTER, 0x8000);
@@ -2266,8 +2271,7 @@ void snd_ac97_resume(ac97_t *ac97)
                        unsigned short val = snd_ac97_read(ac97, AC97_EXTENDED_MID);
                        if (val != 0xffff && (val & 1) != 0)
                                break;
-                       set_current_state(TASK_UNINTERRUPTIBLE);
-                       schedule_timeout(1);
+                       schedule_timeout_uninterruptible(1);
                } while (time_after_eq(end_time, jiffies));
        }
 __reset_ready:
@@ -2539,8 +2543,6 @@ int snd_ac97_tune_hardware(ac97_t *ac97, struct ac97_quirk *quirk, const char *o
 {
        int result;
 
-       snd_assert(quirk, return -EINVAL);
-
        /* quirk overriden? */
        if (override && strcmp(override, "-1") && strcmp(override, "default")) {
                result = apply_quirk_str(ac97, override);
@@ -2549,6 +2551,9 @@ int snd_ac97_tune_hardware(ac97_t *ac97, struct ac97_quirk *quirk, const char *o
                return result;
        }
 
+       if (! quirk)
+               return -EINVAL;
+
        for (; quirk->subvendor; quirk++) {
                if (quirk->subvendor != ac97->subsystem_vendor)
                        continue;