diff options
author | Takashi Iwai <tiwai@suse.de> | 2009-05-04 10:00:16 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2009-05-04 10:00:16 -0400 |
commit | 3a20ac2c52b1317f5a5f0bd9cd3cbe8495ddd026 (patch) | |
tree | 9a912f2609cefb9698b5cce09cd240bd6dbd09fb /sound/pci/intel8x0.c | |
parent | 18cc8d8d9b74c446832336d8f6e1afb145f9431b (diff) | |
parent | 3e5b50165fd0be080044586f43fcdd460ed27610 (diff) |
Merge branch 'fix/pcm-jiffies-check' into fix/asoc
Diffstat (limited to 'sound/pci/intel8x0.c')
-rw-r--r-- | sound/pci/intel8x0.c | 186 |
1 files changed, 138 insertions, 48 deletions
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c index 671ff65db029..173bebf9f51d 100644 --- a/sound/pci/intel8x0.c +++ b/sound/pci/intel8x0.c | |||
@@ -355,6 +355,9 @@ struct ichdev { | |||
355 | unsigned int fragsize1; | 355 | unsigned int fragsize1; |
356 | unsigned int position; | 356 | unsigned int position; |
357 | unsigned int pos_shift; | 357 | unsigned int pos_shift; |
358 | unsigned int last_pos; | ||
359 | unsigned long last_pos_jiffies; | ||
360 | unsigned int jiffy_to_bytes; | ||
358 | int frags; | 361 | int frags; |
359 | int lvi; | 362 | int lvi; |
360 | int lvi_frag; | 363 | int lvi_frag; |
@@ -617,7 +620,7 @@ static int snd_intel8x0_ali_codec_semaphore(struct intel8x0 *chip) | |||
617 | int time = 100; | 620 | int time = 100; |
618 | if (chip->buggy_semaphore) | 621 | if (chip->buggy_semaphore) |
619 | return 0; /* just ignore ... */ | 622 | return 0; /* just ignore ... */ |
620 | while (time-- && (igetdword(chip, ICHREG(ALI_CAS)) & ALI_CAS_SEM_BUSY)) | 623 | while (--time && (igetdword(chip, ICHREG(ALI_CAS)) & ALI_CAS_SEM_BUSY)) |
621 | udelay(1); | 624 | udelay(1); |
622 | if (! time && ! chip->in_ac97_init) | 625 | if (! time && ! chip->in_ac97_init) |
623 | snd_printk(KERN_WARNING "ali_codec_semaphore timeout\n"); | 626 | snd_printk(KERN_WARNING "ali_codec_semaphore timeout\n"); |
@@ -689,7 +692,7 @@ static void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ich | |||
689 | bdbar[idx + 1] = cpu_to_le32(0x80000000 | /* interrupt on completion */ | 692 | bdbar[idx + 1] = cpu_to_le32(0x80000000 | /* interrupt on completion */ |
690 | ichdev->fragsize >> ichdev->pos_shift); | 693 | ichdev->fragsize >> ichdev->pos_shift); |
691 | #if 0 | 694 | #if 0 |
692 | printk("bdbar[%i] = 0x%x [0x%x]\n", | 695 | printk(KERN_DEBUG "bdbar[%i] = 0x%x [0x%x]\n", |
693 | idx + 0, bdbar[idx + 0], bdbar[idx + 1]); | 696 | idx + 0, bdbar[idx + 0], bdbar[idx + 1]); |
694 | #endif | 697 | #endif |
695 | } | 698 | } |
@@ -701,8 +704,10 @@ static void snd_intel8x0_setup_periods(struct intel8x0 *chip, struct ichdev *ich | |||
701 | ichdev->lvi_frag = ICH_REG_LVI_MASK % ichdev->frags; | 704 | ichdev->lvi_frag = ICH_REG_LVI_MASK % ichdev->frags; |
702 | ichdev->position = 0; | 705 | ichdev->position = 0; |
703 | #if 0 | 706 | #if 0 |
704 | printk("lvi_frag = %i, frags = %i, period_size = 0x%x, period_size1 = 0x%x\n", | 707 | printk(KERN_DEBUG "lvi_frag = %i, frags = %i, period_size = 0x%x, " |
705 | ichdev->lvi_frag, ichdev->frags, ichdev->fragsize, ichdev->fragsize1); | 708 | "period_size1 = 0x%x\n", |
709 | ichdev->lvi_frag, ichdev->frags, ichdev->fragsize, | ||
710 | ichdev->fragsize1); | ||
706 | #endif | 711 | #endif |
707 | /* clear interrupts */ | 712 | /* clear interrupts */ |
708 | iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI); | 713 | iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI); |
@@ -768,7 +773,8 @@ static inline void snd_intel8x0_update(struct intel8x0 *chip, struct ichdev *ich | |||
768 | ichdev->lvi_frag %= ichdev->frags; | 773 | ichdev->lvi_frag %= ichdev->frags; |
769 | ichdev->bdbar[ichdev->lvi * 2] = cpu_to_le32(ichdev->physbuf + ichdev->lvi_frag * ichdev->fragsize1); | 774 | ichdev->bdbar[ichdev->lvi * 2] = cpu_to_le32(ichdev->physbuf + ichdev->lvi_frag * ichdev->fragsize1); |
770 | #if 0 | 775 | #if 0 |
771 | printk("new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, all = 0x%x, 0x%x\n", | 776 | printk(KERN_DEBUG "new: bdbar[%i] = 0x%x [0x%x], prefetch = %i, " |
777 | "all = 0x%x, 0x%x\n", | ||
772 | ichdev->lvi * 2, ichdev->bdbar[ichdev->lvi * 2], | 778 | ichdev->lvi * 2, ichdev->bdbar[ichdev->lvi * 2], |
773 | ichdev->bdbar[ichdev->lvi * 2 + 1], inb(ICH_REG_OFF_PIV + port), | 779 | ichdev->bdbar[ichdev->lvi * 2 + 1], inb(ICH_REG_OFF_PIV + port), |
774 | inl(port + 4), inb(port + ICH_REG_OFF_CR)); | 780 | inl(port + 4), inb(port + ICH_REG_OFF_CR)); |
@@ -835,7 +841,10 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd | |||
835 | ichdev->suspended = 0; | 841 | ichdev->suspended = 0; |
836 | /* fallthru */ | 842 | /* fallthru */ |
837 | case SNDRV_PCM_TRIGGER_START: | 843 | case SNDRV_PCM_TRIGGER_START: |
844 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
838 | val = ICH_IOCE | ICH_STARTBM; | 845 | val = ICH_IOCE | ICH_STARTBM; |
846 | ichdev->last_pos = ichdev->position; | ||
847 | ichdev->last_pos_jiffies = jiffies; | ||
839 | break; | 848 | break; |
840 | case SNDRV_PCM_TRIGGER_SUSPEND: | 849 | case SNDRV_PCM_TRIGGER_SUSPEND: |
841 | ichdev->suspended = 1; | 850 | ichdev->suspended = 1; |
@@ -846,9 +855,6 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd | |||
846 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 855 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
847 | val = ICH_IOCE; | 856 | val = ICH_IOCE; |
848 | break; | 857 | break; |
849 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
850 | val = ICH_IOCE | ICH_STARTBM; | ||
851 | break; | ||
852 | default: | 858 | default: |
853 | return -EINVAL; | 859 | return -EINVAL; |
854 | } | 860 | } |
@@ -1042,6 +1048,7 @@ static int snd_intel8x0_pcm_prepare(struct snd_pcm_substream *substream) | |||
1042 | ichdev->pos_shift = (runtime->sample_bits > 16) ? 2 : 1; | 1048 | ichdev->pos_shift = (runtime->sample_bits > 16) ? 2 : 1; |
1043 | } | 1049 | } |
1044 | snd_intel8x0_setup_periods(chip, ichdev); | 1050 | snd_intel8x0_setup_periods(chip, ichdev); |
1051 | ichdev->jiffy_to_bytes = (runtime->rate * 4 * ichdev->pos_shift) / HZ; | ||
1045 | return 0; | 1052 | return 0; |
1046 | } | 1053 | } |
1047 | 1054 | ||
@@ -1050,7 +1057,7 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *subs | |||
1050 | struct intel8x0 *chip = snd_pcm_substream_chip(substream); | 1057 | struct intel8x0 *chip = snd_pcm_substream_chip(substream); |
1051 | struct ichdev *ichdev = get_ichdev(substream); | 1058 | struct ichdev *ichdev = get_ichdev(substream); |
1052 | size_t ptr1, ptr; | 1059 | size_t ptr1, ptr; |
1053 | int civ, timeout = 100; | 1060 | int civ, timeout = 10; |
1054 | unsigned int position; | 1061 | unsigned int position; |
1055 | 1062 | ||
1056 | spin_lock(&chip->reg_lock); | 1063 | spin_lock(&chip->reg_lock); |
@@ -1066,9 +1073,19 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *subs | |||
1066 | ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb)) | 1073 | ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb)) |
1067 | break; | 1074 | break; |
1068 | } while (timeout--); | 1075 | } while (timeout--); |
1069 | ptr1 <<= ichdev->pos_shift; | 1076 | if (ptr1 != 0) { |
1070 | ptr = ichdev->fragsize1 - ptr1; | 1077 | ptr1 <<= ichdev->pos_shift; |
1071 | ptr += position; | 1078 | ptr = ichdev->fragsize1 - ptr1; |
1079 | ptr += position; | ||
1080 | ichdev->last_pos = ptr; | ||
1081 | ichdev->last_pos_jiffies = jiffies; | ||
1082 | } else { | ||
1083 | ptr1 = jiffies - ichdev->last_pos_jiffies; | ||
1084 | if (ptr1) | ||
1085 | ptr1 -= 1; | ||
1086 | ptr = ichdev->last_pos + ptr1 * ichdev->jiffy_to_bytes; | ||
1087 | ptr %= ichdev->size; | ||
1088 | } | ||
1072 | spin_unlock(&chip->reg_lock); | 1089 | spin_unlock(&chip->reg_lock); |
1073 | if (ptr >= ichdev->size) | 1090 | if (ptr >= ichdev->size) |
1074 | return 0; | 1091 | return 0; |
@@ -1837,6 +1854,12 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { | |||
1837 | }, | 1854 | }, |
1838 | { | 1855 | { |
1839 | .subvendor = 0x1028, | 1856 | .subvendor = 0x1028, |
1857 | .subdevice = 0x016a, | ||
1858 | .name = "Dell Inspiron 8600", /* STAC9750/51 */ | ||
1859 | .type = AC97_TUNE_HP_ONLY | ||
1860 | }, | ||
1861 | { | ||
1862 | .subvendor = 0x1028, | ||
1840 | .subdevice = 0x0186, | 1863 | .subdevice = 0x0186, |
1841 | .name = "Dell Latitude D810", /* cf. Malone #41015 */ | 1864 | .name = "Dell Latitude D810", /* cf. Malone #41015 */ |
1842 | .type = AC97_TUNE_HP_MUTE_LED | 1865 | .type = AC97_TUNE_HP_MUTE_LED |
@@ -1879,12 +1902,6 @@ static struct ac97_quirk ac97_quirks[] __devinitdata = { | |||
1879 | }, | 1902 | }, |
1880 | { | 1903 | { |
1881 | .subvendor = 0x103c, | 1904 | .subvendor = 0x103c, |
1882 | .subdevice = 0x0934, | ||
1883 | .name = "HP nx8220", | ||
1884 | .type = AC97_TUNE_MUTE_LED | ||
1885 | }, | ||
1886 | { | ||
1887 | .subvendor = 0x103c, | ||
1888 | .subdevice = 0x129d, | 1905 | .subdevice = 0x129d, |
1889 | .name = "HP xw8000", | 1906 | .name = "HP xw8000", |
1890 | .type = AC97_TUNE_HP_ONLY | 1907 | .type = AC97_TUNE_HP_ONLY |
@@ -2287,23 +2304,23 @@ static void do_ali_reset(struct intel8x0 *chip) | |||
2287 | iputdword(chip, ICHREG(ALI_INTERRUPTSR), 0x00000000); | 2304 | iputdword(chip, ICHREG(ALI_INTERRUPTSR), 0x00000000); |
2288 | } | 2305 | } |
2289 | 2306 | ||
2290 | static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing) | 2307 | #ifdef CONFIG_SND_AC97_POWER_SAVE |
2291 | { | 2308 | static struct snd_pci_quirk ich_chip_reset_mode[] = { |
2292 | unsigned long end_time; | 2309 | SND_PCI_QUIRK(0x1014, 0x051f, "Thinkpad R32", 1), |
2293 | unsigned int cnt, status, nstatus; | 2310 | { } /* end */ |
2294 | 2311 | }; | |
2295 | /* put logic to right state */ | ||
2296 | /* first clear status bits */ | ||
2297 | status = ICH_RCS | ICH_MCINT | ICH_POINT | ICH_PIINT; | ||
2298 | if (chip->device_type == DEVICE_NFORCE) | ||
2299 | status |= ICH_NVSPINT; | ||
2300 | cnt = igetdword(chip, ICHREG(GLOB_STA)); | ||
2301 | iputdword(chip, ICHREG(GLOB_STA), cnt & status); | ||
2302 | 2312 | ||
2313 | static int snd_intel8x0_ich_chip_cold_reset(struct intel8x0 *chip) | ||
2314 | { | ||
2315 | unsigned int cnt; | ||
2303 | /* ACLink on, 2 channels */ | 2316 | /* ACLink on, 2 channels */ |
2317 | |||
2318 | if (snd_pci_quirk_lookup(chip->pci, ich_chip_reset_mode)) | ||
2319 | return -EIO; | ||
2320 | |||
2304 | cnt = igetdword(chip, ICHREG(GLOB_CNT)); | 2321 | cnt = igetdword(chip, ICHREG(GLOB_CNT)); |
2305 | cnt &= ~(ICH_ACLINK | ICH_PCM_246_MASK); | 2322 | cnt &= ~(ICH_ACLINK | ICH_PCM_246_MASK); |
2306 | #ifdef CONFIG_SND_AC97_POWER_SAVE | 2323 | |
2307 | /* do cold reset - the full ac97 powerdown may leave the controller | 2324 | /* do cold reset - the full ac97 powerdown may leave the controller |
2308 | * in a warm state but actually it cannot communicate with the codec. | 2325 | * in a warm state but actually it cannot communicate with the codec. |
2309 | */ | 2326 | */ |
@@ -2312,22 +2329,58 @@ static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing) | |||
2312 | udelay(10); | 2329 | udelay(10); |
2313 | iputdword(chip, ICHREG(GLOB_CNT), cnt | ICH_AC97COLD); | 2330 | iputdword(chip, ICHREG(GLOB_CNT), cnt | ICH_AC97COLD); |
2314 | msleep(1); | 2331 | msleep(1); |
2332 | return 0; | ||
2333 | } | ||
2334 | #define snd_intel8x0_ich_chip_can_cold_reset(chip) \ | ||
2335 | (!snd_pci_quirk_lookup(chip->pci, ich_chip_reset_mode)) | ||
2315 | #else | 2336 | #else |
2337 | #define snd_intel8x0_ich_chip_cold_reset(chip) 0 | ||
2338 | #define snd_intel8x0_ich_chip_can_cold_reset(chip) (0) | ||
2339 | #endif | ||
2340 | |||
2341 | static int snd_intel8x0_ich_chip_reset(struct intel8x0 *chip) | ||
2342 | { | ||
2343 | unsigned long end_time; | ||
2344 | unsigned int cnt; | ||
2345 | /* ACLink on, 2 channels */ | ||
2346 | cnt = igetdword(chip, ICHREG(GLOB_CNT)); | ||
2347 | cnt &= ~(ICH_ACLINK | ICH_PCM_246_MASK); | ||
2316 | /* finish cold or do warm reset */ | 2348 | /* finish cold or do warm reset */ |
2317 | cnt |= (cnt & ICH_AC97COLD) == 0 ? ICH_AC97COLD : ICH_AC97WARM; | 2349 | cnt |= (cnt & ICH_AC97COLD) == 0 ? ICH_AC97COLD : ICH_AC97WARM; |
2318 | iputdword(chip, ICHREG(GLOB_CNT), cnt); | 2350 | iputdword(chip, ICHREG(GLOB_CNT), cnt); |
2319 | end_time = (jiffies + (HZ / 4)) + 1; | 2351 | end_time = (jiffies + (HZ / 4)) + 1; |
2320 | do { | 2352 | do { |
2321 | if ((igetdword(chip, ICHREG(GLOB_CNT)) & ICH_AC97WARM) == 0) | 2353 | if ((igetdword(chip, ICHREG(GLOB_CNT)) & ICH_AC97WARM) == 0) |
2322 | goto __ok; | 2354 | return 0; |
2323 | schedule_timeout_uninterruptible(1); | 2355 | schedule_timeout_uninterruptible(1); |
2324 | } while (time_after_eq(end_time, jiffies)); | 2356 | } while (time_after_eq(end_time, jiffies)); |
2325 | snd_printk(KERN_ERR "AC'97 warm reset still in progress? [0x%x]\n", | 2357 | snd_printk(KERN_ERR "AC'97 warm reset still in progress? [0x%x]\n", |
2326 | igetdword(chip, ICHREG(GLOB_CNT))); | 2358 | igetdword(chip, ICHREG(GLOB_CNT))); |
2327 | return -EIO; | 2359 | return -EIO; |
2360 | } | ||
2361 | |||
2362 | static int snd_intel8x0_ich_chip_init(struct intel8x0 *chip, int probing) | ||
2363 | { | ||
2364 | unsigned long end_time; | ||
2365 | unsigned int status, nstatus; | ||
2366 | unsigned int cnt; | ||
2367 | int err; | ||
2368 | |||
2369 | /* put logic to right state */ | ||
2370 | /* first clear status bits */ | ||
2371 | status = ICH_RCS | ICH_MCINT | ICH_POINT | ICH_PIINT; | ||
2372 | if (chip->device_type == DEVICE_NFORCE) | ||
2373 | status |= ICH_NVSPINT; | ||
2374 | cnt = igetdword(chip, ICHREG(GLOB_STA)); | ||
2375 | iputdword(chip, ICHREG(GLOB_STA), cnt & status); | ||
2376 | |||
2377 | if (snd_intel8x0_ich_chip_can_cold_reset(chip)) | ||
2378 | err = snd_intel8x0_ich_chip_cold_reset(chip); | ||
2379 | else | ||
2380 | err = snd_intel8x0_ich_chip_reset(chip); | ||
2381 | if (err < 0) | ||
2382 | return err; | ||
2328 | 2383 | ||
2329 | __ok: | ||
2330 | #endif | ||
2331 | if (probing) { | 2384 | if (probing) { |
2332 | /* wait for any codec ready status. | 2385 | /* wait for any codec ready status. |
2333 | * Once it becomes ready it should remain ready | 2386 | * Once it becomes ready it should remain ready |
@@ -2622,12 +2675,14 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip) | |||
2622 | struct snd_pcm_substream *subs; | 2675 | struct snd_pcm_substream *subs; |
2623 | struct ichdev *ichdev; | 2676 | struct ichdev *ichdev; |
2624 | unsigned long port; | 2677 | unsigned long port; |
2625 | unsigned long pos, t; | 2678 | unsigned long pos, pos1, t; |
2626 | struct timeval start_time, stop_time; | 2679 | int civ, timeout = 1000, attempt = 1; |
2680 | struct timespec start_time, stop_time; | ||
2627 | 2681 | ||
2628 | if (chip->ac97_bus->clock != 48000) | 2682 | if (chip->ac97_bus->clock != 48000) |
2629 | return; /* specified in module option */ | 2683 | return; /* specified in module option */ |
2630 | 2684 | ||
2685 | __again: | ||
2631 | subs = chip->pcm[0]->streams[0].substream; | 2686 | subs = chip->pcm[0]->streams[0].substream; |
2632 | if (! subs || subs->dma_buffer.bytes < INTEL8X0_TESTBUF_SIZE) { | 2687 | if (! subs || subs->dma_buffer.bytes < INTEL8X0_TESTBUF_SIZE) { |
2633 | snd_printk(KERN_WARNING "no playback buffer allocated - aborting measure ac97 clock\n"); | 2688 | snd_printk(KERN_WARNING "no playback buffer allocated - aborting measure ac97 clock\n"); |
@@ -2635,7 +2690,7 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip) | |||
2635 | } | 2690 | } |
2636 | ichdev = &chip->ichd[ICHD_PCMOUT]; | 2691 | ichdev = &chip->ichd[ICHD_PCMOUT]; |
2637 | ichdev->physbuf = subs->dma_buffer.addr; | 2692 | ichdev->physbuf = subs->dma_buffer.addr; |
2638 | ichdev->size = chip->ichd[ICHD_PCMOUT].fragsize = INTEL8X0_TESTBUF_SIZE; | 2693 | ichdev->size = ichdev->fragsize = INTEL8X0_TESTBUF_SIZE; |
2639 | ichdev->substream = NULL; /* don't process interrupts */ | 2694 | ichdev->substream = NULL; /* don't process interrupts */ |
2640 | 2695 | ||
2641 | /* set rate */ | 2696 | /* set rate */ |
@@ -2654,16 +2709,31 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip) | |||
2654 | iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE); | 2709 | iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE); |
2655 | iputdword(chip, ICHREG(ALI_DMACR), 1 << ichdev->ali_slot); | 2710 | iputdword(chip, ICHREG(ALI_DMACR), 1 << ichdev->ali_slot); |
2656 | } | 2711 | } |
2657 | do_gettimeofday(&start_time); | 2712 | do_posix_clock_monotonic_gettime(&start_time); |
2658 | spin_unlock_irq(&chip->reg_lock); | 2713 | spin_unlock_irq(&chip->reg_lock); |
2659 | msleep(50); | 2714 | msleep(50); |
2660 | spin_lock_irq(&chip->reg_lock); | 2715 | spin_lock_irq(&chip->reg_lock); |
2661 | /* check the position */ | 2716 | /* check the position */ |
2662 | pos = ichdev->fragsize1; | 2717 | do { |
2663 | pos -= igetword(chip, ichdev->reg_offset + ichdev->roff_picb) << ichdev->pos_shift; | 2718 | civ = igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV); |
2664 | pos += ichdev->position; | 2719 | pos1 = igetword(chip, ichdev->reg_offset + ichdev->roff_picb); |
2720 | if (pos1 == 0) { | ||
2721 | udelay(10); | ||
2722 | continue; | ||
2723 | } | ||
2724 | if (civ == igetbyte(chip, ichdev->reg_offset + ICH_REG_OFF_CIV) && | ||
2725 | pos1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb)) | ||
2726 | break; | ||
2727 | } while (timeout--); | ||
2728 | if (pos1 == 0) { /* oops, this value is not reliable */ | ||
2729 | pos = 0; | ||
2730 | } else { | ||
2731 | pos = ichdev->fragsize1; | ||
2732 | pos -= pos1 << ichdev->pos_shift; | ||
2733 | pos += ichdev->position; | ||
2734 | } | ||
2665 | chip->in_measurement = 0; | 2735 | chip->in_measurement = 0; |
2666 | do_gettimeofday(&stop_time); | 2736 | do_posix_clock_monotonic_gettime(&stop_time); |
2667 | /* stop */ | 2737 | /* stop */ |
2668 | if (chip->device_type == DEVICE_ALI) { | 2738 | if (chip->device_type == DEVICE_ALI) { |
2669 | iputdword(chip, ICHREG(ALI_DMACR), 1 << (ichdev->ali_slot + 16)); | 2739 | iputdword(chip, ICHREG(ALI_DMACR), 1 << (ichdev->ali_slot + 16)); |
@@ -2678,22 +2748,42 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip) | |||
2678 | iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS); | 2748 | iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS); |
2679 | spin_unlock_irq(&chip->reg_lock); | 2749 | spin_unlock_irq(&chip->reg_lock); |
2680 | 2750 | ||
2751 | if (pos == 0) { | ||
2752 | snd_printk(KERN_ERR "intel8x0: measure - unreliable DMA position..\n"); | ||
2753 | __retry: | ||
2754 | if (attempt < 3) { | ||
2755 | msleep(300); | ||
2756 | attempt++; | ||
2757 | goto __again; | ||
2758 | } | ||
2759 | goto __end; | ||
2760 | } | ||
2761 | |||
2762 | pos /= 4; | ||
2681 | t = stop_time.tv_sec - start_time.tv_sec; | 2763 | t = stop_time.tv_sec - start_time.tv_sec; |
2682 | t *= 1000000; | 2764 | t *= 1000000; |
2683 | t += stop_time.tv_usec - start_time.tv_usec; | 2765 | t += (stop_time.tv_nsec - start_time.tv_nsec) / 1000; |
2684 | printk(KERN_INFO "%s: measured %lu usecs\n", __func__, t); | 2766 | printk(KERN_INFO "%s: measured %lu usecs (%lu samples)\n", __func__, t, pos); |
2685 | if (t == 0) { | 2767 | if (t == 0) { |
2686 | snd_printk(KERN_ERR "?? calculation error..\n"); | 2768 | snd_printk(KERN_ERR "intel8x0: ?? calculation error..\n"); |
2687 | return; | 2769 | goto __retry; |
2688 | } | 2770 | } |
2689 | pos = (pos / 4) * 1000; | 2771 | pos *= 1000; |
2690 | pos = (pos / t) * 1000 + ((pos % t) * 1000) / t; | 2772 | pos = (pos / t) * 1000 + ((pos % t) * 1000) / t; |
2691 | if (pos < 40000 || pos >= 60000) | 2773 | if (pos < 40000 || pos >= 60000) { |
2692 | /* abnormal value. hw problem? */ | 2774 | /* abnormal value. hw problem? */ |
2693 | printk(KERN_INFO "intel8x0: measured clock %ld rejected\n", pos); | 2775 | printk(KERN_INFO "intel8x0: measured clock %ld rejected\n", pos); |
2776 | goto __retry; | ||
2777 | } else if (pos > 40500 && pos < 41500) | ||
2778 | /* first exception - 41000Hz reference clock */ | ||
2779 | chip->ac97_bus->clock = 41000; | ||
2780 | else if (pos > 43600 && pos < 44600) | ||
2781 | /* second exception - 44100HZ reference clock */ | ||
2782 | chip->ac97_bus->clock = 44100; | ||
2694 | else if (pos < 47500 || pos > 48500) | 2783 | else if (pos < 47500 || pos > 48500) |
2695 | /* not 48000Hz, tuning the clock.. */ | 2784 | /* not 48000Hz, tuning the clock.. */ |
2696 | chip->ac97_bus->clock = (chip->ac97_bus->clock * 48000) / pos; | 2785 | chip->ac97_bus->clock = (chip->ac97_bus->clock * 48000) / pos; |
2786 | __end: | ||
2697 | printk(KERN_INFO "intel8x0: clocking to %d\n", chip->ac97_bus->clock); | 2787 | printk(KERN_INFO "intel8x0: clocking to %d\n", chip->ac97_bus->clock); |
2698 | snd_ac97_update_power(chip->ac97[0], AC97_PCM_FRONT_DAC_RATE, 0); | 2788 | snd_ac97_update_power(chip->ac97[0], AC97_PCM_FRONT_DAC_RATE, 0); |
2699 | } | 2789 | } |