sound: use DEFINE_PCI_DEVICE_TABLE
[safe/jmp/linux-2.6] / sound / pci / intel8x0.c
index 5764881..6433e65 100644 (file)
@@ -355,6 +355,7 @@ struct ichdev {
         unsigned int fragsize1;
         unsigned int position;
        unsigned int pos_shift;
+       unsigned int last_pos;
         int frags;
         int lvi;
         int lvi_frag;
@@ -419,30 +420,30 @@ struct intel8x0 {
        u32 int_sta_mask;               /* interrupt status mask */
 };
 
-static struct pci_device_id snd_intel8x0_ids[] = {
-       { 0x8086, 0x2415, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 82801AA */
-       { 0x8086, 0x2425, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 82901AB */
-       { 0x8086, 0x2445, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 82801BA */
-       { 0x8086, 0x2485, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* ICH3 */
-       { 0x8086, 0x24c5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ICH4 */
-       { 0x8086, 0x24d5, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ICH5 */
-       { 0x8086, 0x25a6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ESB */
-       { 0x8086, 0x266e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ICH6 */
-       { 0x8086, 0x27de, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ICH7 */
-       { 0x8086, 0x2698, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL_ICH4 }, /* ESB2 */
-       { 0x8086, 0x7195, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* 440MX */
-       { 0x1039, 0x7012, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_SIS },   /* SI7012 */
-       { 0x10de, 0x01b1, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },        /* NFORCE */
-       { 0x10de, 0x003a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },        /* MCP04 */
-       { 0x10de, 0x006a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },        /* NFORCE2 */
-       { 0x10de, 0x0059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },        /* CK804 */
-       { 0x10de, 0x008a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },        /* CK8 */
-       { 0x10de, 0x00da, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },        /* NFORCE3 */
-       { 0x10de, 0x00ea, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },        /* CK8S */
-       { 0x10de, 0x026b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_NFORCE },        /* MCP51 */
-       { 0x1022, 0x746d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* AMD8111 */
-       { 0x1022, 0x7445, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* AMD768 */
-       { 0x10b9, 0x5455, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALI },   /* Ali5455 */
+static DEFINE_PCI_DEVICE_TABLE(snd_intel8x0_ids) = {
+       { PCI_VDEVICE(INTEL, 0x2415), DEVICE_INTEL },   /* 82801AA */
+       { PCI_VDEVICE(INTEL, 0x2425), DEVICE_INTEL },   /* 82901AB */
+       { PCI_VDEVICE(INTEL, 0x2445), DEVICE_INTEL },   /* 82801BA */
+       { PCI_VDEVICE(INTEL, 0x2485), DEVICE_INTEL },   /* ICH3 */
+       { PCI_VDEVICE(INTEL, 0x24c5), DEVICE_INTEL_ICH4 }, /* ICH4 */
+       { PCI_VDEVICE(INTEL, 0x24d5), DEVICE_INTEL_ICH4 }, /* ICH5 */
+       { PCI_VDEVICE(INTEL, 0x25a6), DEVICE_INTEL_ICH4 }, /* ESB */
+       { PCI_VDEVICE(INTEL, 0x266e), DEVICE_INTEL_ICH4 }, /* ICH6 */
+       { PCI_VDEVICE(INTEL, 0x27de), DEVICE_INTEL_ICH4 }, /* ICH7 */
+       { PCI_VDEVICE(INTEL, 0x2698), DEVICE_INTEL_ICH4 }, /* ESB2 */
+       { PCI_VDEVICE(INTEL, 0x7195), DEVICE_INTEL },   /* 440MX */
+       { PCI_VDEVICE(SI, 0x7012), DEVICE_SIS },        /* SI7012 */
+       { PCI_VDEVICE(NVIDIA, 0x01b1), DEVICE_NFORCE }, /* NFORCE */
+       { PCI_VDEVICE(NVIDIA, 0x003a), DEVICE_NFORCE }, /* MCP04 */
+       { PCI_VDEVICE(NVIDIA, 0x006a), DEVICE_NFORCE }, /* NFORCE2 */
+       { PCI_VDEVICE(NVIDIA, 0x0059), DEVICE_NFORCE }, /* CK804 */
+       { PCI_VDEVICE(NVIDIA, 0x008a), DEVICE_NFORCE }, /* CK8 */
+       { PCI_VDEVICE(NVIDIA, 0x00da), DEVICE_NFORCE }, /* NFORCE3 */
+       { PCI_VDEVICE(NVIDIA, 0x00ea), DEVICE_NFORCE }, /* CK8S */
+       { PCI_VDEVICE(NVIDIA, 0x026b), DEVICE_NFORCE }, /* MCP51 */
+       { PCI_VDEVICE(AMD, 0x746d), DEVICE_INTEL },     /* AMD8111 */
+       { PCI_VDEVICE(AMD, 0x7445), DEVICE_INTEL },     /* AMD768 */
+       { PCI_VDEVICE(AL, 0x5455), DEVICE_ALI },   /* Ali5455 */
        { 0, }
 };
 
@@ -838,7 +839,9 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd
                ichdev->suspended = 0;
                /* fallthru */
        case SNDRV_PCM_TRIGGER_START:
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
                val = ICH_IOCE | ICH_STARTBM;
+               ichdev->last_pos = ichdev->position;
                break;
        case SNDRV_PCM_TRIGGER_SUSPEND:
                ichdev->suspended = 1;
@@ -849,9 +852,6 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd
        case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
                val = ICH_IOCE;
                break;
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               val = ICH_IOCE | ICH_STARTBM;
-               break;
        default:
                return -EINVAL;
        }
@@ -1053,7 +1053,7 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *subs
        struct intel8x0 *chip = snd_pcm_substream_chip(substream);
        struct ichdev *ichdev = get_ichdev(substream);
        size_t ptr1, ptr;
-       int civ, timeout = 100;
+       int civ, timeout = 10;
        unsigned int position;
 
        spin_lock(&chip->reg_lock);
@@ -1069,9 +1069,23 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *subs
                    ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb))
                        break;
        } while (timeout--);
-       ptr1 <<= ichdev->pos_shift;
-       ptr = ichdev->fragsize1 - ptr1;
-       ptr += position;
+       ptr = ichdev->last_pos;
+       if (ptr1 != 0) {
+               ptr1 <<= ichdev->pos_shift;
+               ptr = ichdev->fragsize1 - ptr1;
+               ptr += position;
+               if (ptr < ichdev->last_pos) {
+                       unsigned int pos_base, last_base;
+                       pos_base = position / ichdev->fragsize1;
+                       last_base = ichdev->last_pos / ichdev->fragsize1;
+                       /* another sanity check; ptr1 can go back to full
+                        * before the base position is updated
+                        */
+                       if (pos_base == last_base)
+                               ptr = ichdev->last_pos;
+               }
+       }
+       ichdev->last_pos = ptr;
        spin_unlock(&chip->reg_lock);
        if (ptr >= ichdev->size)
                return 0;
@@ -1840,6 +1854,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
        },
        {
                .subvendor = 0x1028,
+               .subdevice = 0x016a,
+               .name = "Dell Inspiron 8600",   /* STAC9750/51 */
+               .type = AC97_TUNE_HP_ONLY
+       },
+       {
+               .subvendor = 0x1028,
                .subdevice = 0x0186,
                .name = "Dell Latitude D810", /* cf. Malone #41015 */
                .type = AC97_TUNE_HP_MUTE_LED
@@ -1882,12 +1902,6 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
        },
        {
                .subvendor = 0x103c,
-               .subdevice = 0x0934,
-               .name = "HP nx8220",
-               .type = AC97_TUNE_MUTE_LED
-       },
-       {
-               .subvendor = 0x103c,
                .subdevice = 0x129d,
                .name = "HP xw8000",
                .type = AC97_TUNE_HP_ONLY
@@ -1936,10 +1950,28 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
        },
        {
                .subvendor = 0x104d,
+               .subdevice = 0x8144,
+               .name = "Sony",
+               .type = AC97_TUNE_INV_EAPD
+       },
+       {
+               .subvendor = 0x104d,
                .subdevice = 0x8197,
                .name = "Sony S1XP",
                .type = AC97_TUNE_INV_EAPD
        },
+       {
+               .subvendor = 0x104d,
+               .subdevice = 0x81c0,
+               .name = "Sony VAIO VGN-T350P", /*AD1981B*/
+               .type = AC97_TUNE_INV_EAPD
+       },
+       {
+               .subvendor = 0x104d,
+               .subdevice = 0x81c5,
+               .name = "Sony VAIO VGN-B1VP", /*AD1981B*/
+               .type = AC97_TUNE_INV_EAPD
+       },
        {
                .subvendor = 0x1043,
                .subdevice = 0x80f3,
@@ -2031,6 +2063,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = {
                .type = AC97_TUNE_HP_ONLY
        },
        {
+               .subvendor = 0x161f,
+               .subdevice = 0x203a,
+               .name = "Gateway 4525GZ",               /* AD1981B */
+               .type = AC97_TUNE_INV_EAPD
+       },
+       {
                .subvendor = 0x1734,
                .subdevice = 0x0088,
                .name = "Fujitsu-Siemens D1522",        /* AD1981 */
@@ -2661,12 +2699,14 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip)
        struct snd_pcm_substream *subs;
        struct ichdev *ichdev;
        unsigned long port;
-       unsigned long pos, t;
-       struct timeval start_time, stop_time;
+       unsigned long pos, pos1, t;
+       int civ, timeout = 1000, attempt = 1;
+       struct timespec start_time, stop_time;
 
        if (chip->ac97_bus->clock != 48000)
                return; /* specified in module option */
 
+      __again:
        subs = chip->pcm[0]->streams[0].substream;
        if (! subs || subs->dma_buffer.bytes < INTEL8X0_TESTBUF_SIZE) {
                snd_printk(KERN_WARNING "no playback buffer allocated - aborting measure ac97 clock\n");
@@ -2674,7 +2714,7 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip)
        }
        ichdev = &chip->ichd[ICHD_PCMOUT];
        ichdev->physbuf = subs->dma_buffer.addr;
-       ichdev->size = chip->ichd[ICHD_PCMOUT].fragsize = INTEL8X0_TESTBUF_SIZE;
+       ichdev->size = ichdev->fragsize = INTEL8X0_TESTBUF_SIZE;
        ichdev->substream = NULL; /* don't process interrupts */
 
        /* set rate */
@@ -2693,16 +2733,31 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip)
                iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE);
                iputdword(chip, ICHREG(ALI_DMACR), 1 << ichdev->ali_slot);
        }
-       do_gettimeofday(&start_time);
+       do_posix_clock_monotonic_gettime(&start_time);
        spin_unlock_irq(&chip->reg_lock);
        msleep(50);
        spin_lock_irq(&chip->reg_lock);
        /* check the position */
-       pos = ichdev->fragsize1;
-       pos -= igetword(chip, ichdev->reg_offset + ichdev->roff_picb) << ichdev->pos_shift;
-       pos += ichdev->position;
+       do {
+               civ = igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV);
+               pos1 = igetword(chip, ichdev->reg_offset + ichdev->roff_picb);
+               if (pos1 == 0) {
+                       udelay(10);
+                       continue;
+               }
+               if (civ == igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV) &&
+                   pos1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb))
+                       break;
+       } while (timeout--);
+       if (pos1 == 0) {        /* oops, this value is not reliable */
+               pos = 0;
+       } else {
+               pos = ichdev->fragsize1;
+               pos -= pos1 << ichdev->pos_shift;
+               pos += ichdev->position;
+       }
        chip->in_measurement = 0;
-       do_gettimeofday(&stop_time);
+       do_posix_clock_monotonic_gettime(&stop_time);
        /* stop */
        if (chip->device_type == DEVICE_ALI) {
                iputdword(chip, ICHREG(ALI_DMACR), 1 << (ichdev->ali_slot + 16));
@@ -2717,22 +2772,42 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip)
        iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS);
        spin_unlock_irq(&chip->reg_lock);
 
+       if (pos == 0) {
+               snd_printk(KERN_ERR "intel8x0: measure - unreliable DMA position..\n");
+             __retry:
+               if (attempt < 3) {
+                       msleep(300);
+                       attempt++;
+                       goto __again;
+               }
+               goto __end;
+       }
+
+       pos /= 4;
        t = stop_time.tv_sec - start_time.tv_sec;
        t *= 1000000;
-       t += stop_time.tv_usec - start_time.tv_usec;
-       printk(KERN_INFO "%s: measured %lu usecs\n", __func__, t);
+       t += (stop_time.tv_nsec - start_time.tv_nsec) / 1000;
+       printk(KERN_INFO "%s: measured %lu usecs (%lu samples)\n", __func__, t, pos);
        if (t == 0) {
-               snd_printk(KERN_ERR "?? calculation error..\n");
-               return;
+               snd_printk(KERN_ERR "intel8x0: ?? calculation error..\n");
+               goto __retry;
        }
-       pos = (pos / 4) * 1000;
+       pos *= 1000;
        pos = (pos / t) * 1000 + ((pos % t) * 1000) / t;
-       if (pos < 40000 || pos >= 60000) 
+       if (pos < 40000 || pos >= 60000) {
                /* abnormal value. hw problem? */
                printk(KERN_INFO "intel8x0: measured clock %ld rejected\n", pos);
+               goto __retry;
+       } else if (pos > 40500 && pos < 41500)
+               /* first exception - 41000Hz reference clock */
+               chip->ac97_bus->clock = 41000;
+       else if (pos > 43600 && pos < 44600)
+               /* second exception - 44100HZ reference clock */
+               chip->ac97_bus->clock = 44100;
        else if (pos < 47500 || pos > 48500)
                /* not 48000Hz, tuning the clock.. */
                chip->ac97_bus->clock = (chip->ac97_bus->clock * 48000) / pos;
+      __end:
        printk(KERN_INFO "intel8x0: clocking to %d\n", chip->ac97_bus->clock);
        snd_ac97_update_power(chip->ac97[0], AC97_PCM_FRONT_DAC_RATE, 0);
 }