|
@@ -355,6 +355,9 @@ struct ichdev {
|
|
unsigned int fragsize1;
|
|
unsigned int fragsize1;
|
|
unsigned int position;
|
|
unsigned int position;
|
|
unsigned int pos_shift;
|
|
unsigned int pos_shift;
|
|
|
|
+ unsigned int last_pos;
|
|
|
|
+ unsigned long last_pos_jiffies;
|
|
|
|
+ unsigned int jiffy_to_bytes;
|
|
int frags;
|
|
int frags;
|
|
int lvi;
|
|
int lvi;
|
|
int lvi_frag;
|
|
int lvi_frag;
|
|
@@ -838,7 +841,10 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd
|
|
ichdev->suspended = 0;
|
|
ichdev->suspended = 0;
|
|
/* fallthru */
|
|
/* fallthru */
|
|
case SNDRV_PCM_TRIGGER_START:
|
|
case SNDRV_PCM_TRIGGER_START:
|
|
|
|
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
|
val = ICH_IOCE | ICH_STARTBM;
|
|
val = ICH_IOCE | ICH_STARTBM;
|
|
|
|
+ ichdev->last_pos = ichdev->position;
|
|
|
|
+ ichdev->last_pos_jiffies = jiffies;
|
|
break;
|
|
break;
|
|
case SNDRV_PCM_TRIGGER_SUSPEND:
|
|
case SNDRV_PCM_TRIGGER_SUSPEND:
|
|
ichdev->suspended = 1;
|
|
ichdev->suspended = 1;
|
|
@@ -849,9 +855,6 @@ static int snd_intel8x0_pcm_trigger(struct snd_pcm_substream *substream, int cmd
|
|
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
|
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
|
val = ICH_IOCE;
|
|
val = ICH_IOCE;
|
|
break;
|
|
break;
|
|
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
|
|
|
- val = ICH_IOCE | ICH_STARTBM;
|
|
|
|
- break;
|
|
|
|
default:
|
|
default:
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
}
|
|
}
|
|
@@ -1045,6 +1048,7 @@ static int snd_intel8x0_pcm_prepare(struct snd_pcm_substream *substream)
|
|
ichdev->pos_shift = (runtime->sample_bits > 16) ? 2 : 1;
|
|
ichdev->pos_shift = (runtime->sample_bits > 16) ? 2 : 1;
|
|
}
|
|
}
|
|
snd_intel8x0_setup_periods(chip, ichdev);
|
|
snd_intel8x0_setup_periods(chip, ichdev);
|
|
|
|
+ ichdev->jiffy_to_bytes = (runtime->rate * 4 * ichdev->pos_shift) / HZ;
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -1053,7 +1057,7 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *subs
|
|
struct intel8x0 *chip = snd_pcm_substream_chip(substream);
|
|
struct intel8x0 *chip = snd_pcm_substream_chip(substream);
|
|
struct ichdev *ichdev = get_ichdev(substream);
|
|
struct ichdev *ichdev = get_ichdev(substream);
|
|
size_t ptr1, ptr;
|
|
size_t ptr1, ptr;
|
|
- int civ, timeout = 100;
|
|
|
|
|
|
+ int civ, timeout = 10;
|
|
unsigned int position;
|
|
unsigned int position;
|
|
|
|
|
|
spin_lock(&chip->reg_lock);
|
|
spin_lock(&chip->reg_lock);
|
|
@@ -1069,9 +1073,19 @@ static snd_pcm_uframes_t snd_intel8x0_pcm_pointer(struct snd_pcm_substream *subs
|
|
ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb))
|
|
ptr1 == igetword(chip, ichdev->reg_offset + ichdev->roff_picb))
|
|
break;
|
|
break;
|
|
} while (timeout--);
|
|
} while (timeout--);
|
|
- ptr1 <<= ichdev->pos_shift;
|
|
|
|
- ptr = ichdev->fragsize1 - ptr1;
|
|
|
|
- ptr += position;
|
|
|
|
|
|
+ if (ptr1 != 0) {
|
|
|
|
+ ptr1 <<= ichdev->pos_shift;
|
|
|
|
+ ptr = ichdev->fragsize1 - ptr1;
|
|
|
|
+ ptr += position;
|
|
|
|
+ ichdev->last_pos = ptr;
|
|
|
|
+ ichdev->last_pos_jiffies = jiffies;
|
|
|
|
+ } else {
|
|
|
|
+ ptr1 = jiffies - ichdev->last_pos_jiffies;
|
|
|
|
+ if (ptr1)
|
|
|
|
+ ptr1 -= 1;
|
|
|
|
+ ptr = ichdev->last_pos + ptr1 * ichdev->jiffy_to_bytes;
|
|
|
|
+ ptr %= ichdev->size;
|
|
|
|
+ }
|
|
spin_unlock(&chip->reg_lock);
|
|
spin_unlock(&chip->reg_lock);
|
|
if (ptr >= ichdev->size)
|
|
if (ptr >= ichdev->size)
|
|
return 0;
|
|
return 0;
|
|
@@ -2661,12 +2675,14 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip)
|
|
struct snd_pcm_substream *subs;
|
|
struct snd_pcm_substream *subs;
|
|
struct ichdev *ichdev;
|
|
struct ichdev *ichdev;
|
|
unsigned long port;
|
|
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)
|
|
if (chip->ac97_bus->clock != 48000)
|
|
return; /* specified in module option */
|
|
return; /* specified in module option */
|
|
|
|
|
|
|
|
+ __again:
|
|
subs = chip->pcm[0]->streams[0].substream;
|
|
subs = chip->pcm[0]->streams[0].substream;
|
|
if (! subs || subs->dma_buffer.bytes < INTEL8X0_TESTBUF_SIZE) {
|
|
if (! subs || subs->dma_buffer.bytes < INTEL8X0_TESTBUF_SIZE) {
|
|
snd_printk(KERN_WARNING "no playback buffer allocated - aborting measure ac97 clock\n");
|
|
snd_printk(KERN_WARNING "no playback buffer allocated - aborting measure ac97 clock\n");
|
|
@@ -2674,7 +2690,7 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip)
|
|
}
|
|
}
|
|
ichdev = &chip->ichd[ICHD_PCMOUT];
|
|
ichdev = &chip->ichd[ICHD_PCMOUT];
|
|
ichdev->physbuf = subs->dma_buffer.addr;
|
|
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 */
|
|
ichdev->substream = NULL; /* don't process interrupts */
|
|
|
|
|
|
/* set rate */
|
|
/* set rate */
|
|
@@ -2693,16 +2709,31 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip)
|
|
iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE);
|
|
iputbyte(chip, port + ICH_REG_OFF_CR, ICH_IOCE);
|
|
iputdword(chip, ICHREG(ALI_DMACR), 1 << ichdev->ali_slot);
|
|
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);
|
|
spin_unlock_irq(&chip->reg_lock);
|
|
msleep(50);
|
|
msleep(50);
|
|
spin_lock_irq(&chip->reg_lock);
|
|
spin_lock_irq(&chip->reg_lock);
|
|
/* check the position */
|
|
/* 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;
|
|
chip->in_measurement = 0;
|
|
- do_gettimeofday(&stop_time);
|
|
|
|
|
|
+ do_posix_clock_monotonic_gettime(&stop_time);
|
|
/* stop */
|
|
/* stop */
|
|
if (chip->device_type == DEVICE_ALI) {
|
|
if (chip->device_type == DEVICE_ALI) {
|
|
iputdword(chip, ICHREG(ALI_DMACR), 1 << (ichdev->ali_slot + 16));
|
|
iputdword(chip, ICHREG(ALI_DMACR), 1 << (ichdev->ali_slot + 16));
|
|
@@ -2717,19 +2748,37 @@ static void __devinit intel8x0_measure_ac97_clock(struct intel8x0 *chip)
|
|
iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS);
|
|
iputbyte(chip, port + ICH_REG_OFF_CR, ICH_RESETREGS);
|
|
spin_unlock_irq(&chip->reg_lock);
|
|
spin_unlock_irq(&chip->reg_lock);
|
|
|
|
|
|
|
|
+ if (pos == 0) {
|
|
|
|
+ snd_printk(KERN_ERR "intel8x0: measure - unreliable DMA position..\n");
|
|
|
|
+ __retry:
|
|
|
|
+ if (attempt < 2) {
|
|
|
|
+ attempt++;
|
|
|
|
+ goto __again;
|
|
|
|
+ }
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ pos /= 4;
|
|
t = stop_time.tv_sec - start_time.tv_sec;
|
|
t = stop_time.tv_sec - start_time.tv_sec;
|
|
t *= 1000000;
|
|
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) {
|
|
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;
|
|
pos = (pos / t) * 1000 + ((pos % t) * 1000) / t;
|
|
- if (pos < 40000 || pos >= 60000)
|
|
|
|
|
|
+ if (pos < 40000 || pos >= 60000) {
|
|
/* abnormal value. hw problem? */
|
|
/* abnormal value. hw problem? */
|
|
printk(KERN_INFO "intel8x0: measured clock %ld rejected\n", pos);
|
|
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)
|
|
else if (pos < 47500 || pos > 48500)
|
|
/* not 48000Hz, tuning the clock.. */
|
|
/* not 48000Hz, tuning the clock.. */
|
|
chip->ac97_bus->clock = (chip->ac97_bus->clock * 48000) / pos;
|
|
chip->ac97_bus->clock = (chip->ac97_bus->clock * 48000) / pos;
|