Merge branch 'master' of git://git.alsa-project.org/alsa-kernel into for-linus
* 'master' of git://git.alsa-project.org/alsa-kernel: [ALSA] intel8x0: add one retry to the ac97_clock measurement routine [ALSA] intel8x0: fix wrong conditions in ac97_clock measure routine [ALSA] intel8x0: do not use zero value from PICB register [ALSA] intel8x0: an attempt to make ac97_clock measurement more reliable [ALSA] pcm-midlevel: Add more strict buffer position checks based on jiffies [ALSA] hda_intel: fix unexpected ring buffer positions
This commit is contained in:
Коммит
45c27fc8c8
|
@ -268,7 +268,8 @@ struct snd_pcm_runtime {
|
|||
int overrange;
|
||||
snd_pcm_uframes_t avail_max;
|
||||
snd_pcm_uframes_t hw_ptr_base; /* Position at buffer restart */
|
||||
snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time*/
|
||||
snd_pcm_uframes_t hw_ptr_interrupt; /* Position at interrupt time */
|
||||
unsigned long hw_ptr_jiffies; /* Time when hw_ptr is updated */
|
||||
|
||||
/* -- HW params -- */
|
||||
snd_pcm_access_t access; /* access mode */
|
||||
|
|
|
@ -209,9 +209,11 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
|
|||
{
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
snd_pcm_uframes_t pos;
|
||||
snd_pcm_uframes_t new_hw_ptr, hw_ptr_interrupt, hw_base;
|
||||
snd_pcm_sframes_t delta;
|
||||
snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_ptr_interrupt, hw_base;
|
||||
snd_pcm_sframes_t hdelta, delta;
|
||||
unsigned long jdelta;
|
||||
|
||||
old_hw_ptr = runtime->status->hw_ptr;
|
||||
pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
|
||||
if (pos == SNDRV_PCM_POS_XRUN) {
|
||||
xrun(substream);
|
||||
|
@ -247,7 +249,30 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
|
|||
new_hw_ptr = hw_base + pos;
|
||||
}
|
||||
}
|
||||
if (delta > runtime->period_size) {
|
||||
hdelta = new_hw_ptr - old_hw_ptr;
|
||||
jdelta = jiffies - runtime->hw_ptr_jiffies;
|
||||
if (((hdelta * HZ) / runtime->rate) > jdelta + HZ/100) {
|
||||
delta = jdelta /
|
||||
(((runtime->period_size * HZ) / runtime->rate)
|
||||
+ HZ/100);
|
||||
hw_ptr_error(substream,
|
||||
"hw_ptr skipping! [Q] "
|
||||
"(pos=%ld, delta=%ld, period=%ld, "
|
||||
"jdelta=%lu/%lu/%lu)\n",
|
||||
(long)pos, (long)hdelta,
|
||||
(long)runtime->period_size, jdelta,
|
||||
((hdelta * HZ) / runtime->rate), delta);
|
||||
hw_ptr_interrupt = runtime->hw_ptr_interrupt +
|
||||
runtime->period_size * delta;
|
||||
if (hw_ptr_interrupt >= runtime->boundary)
|
||||
hw_ptr_interrupt -= runtime->boundary;
|
||||
/* rebase to interrupt position */
|
||||
hw_base = new_hw_ptr = hw_ptr_interrupt;
|
||||
/* align hw_base to buffer_size */
|
||||
hw_base -= hw_base % runtime->buffer_size;
|
||||
delta = 0;
|
||||
}
|
||||
if (delta > runtime->period_size + runtime->period_size / 2) {
|
||||
hw_ptr_error(substream,
|
||||
"Lost interrupts? "
|
||||
"(stream=%i, delta=%ld, intr_ptr=%ld)\n",
|
||||
|
@ -263,6 +288,7 @@ static int snd_pcm_update_hw_ptr_interrupt(struct snd_pcm_substream *substream)
|
|||
|
||||
runtime->hw_ptr_base = hw_base;
|
||||
runtime->status->hw_ptr = new_hw_ptr;
|
||||
runtime->hw_ptr_jiffies = jiffies;
|
||||
runtime->hw_ptr_interrupt = hw_ptr_interrupt;
|
||||
|
||||
return snd_pcm_update_hw_ptr_post(substream, runtime);
|
||||
|
@ -275,6 +301,7 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
|
|||
snd_pcm_uframes_t pos;
|
||||
snd_pcm_uframes_t old_hw_ptr, new_hw_ptr, hw_base;
|
||||
snd_pcm_sframes_t delta;
|
||||
unsigned long jdelta;
|
||||
|
||||
old_hw_ptr = runtime->status->hw_ptr;
|
||||
pos = snd_pcm_update_hw_ptr_pos(substream, runtime);
|
||||
|
@ -286,14 +313,15 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
|
|||
new_hw_ptr = hw_base + pos;
|
||||
|
||||
delta = new_hw_ptr - old_hw_ptr;
|
||||
jdelta = jiffies - runtime->hw_ptr_jiffies;
|
||||
if (delta < 0) {
|
||||
delta += runtime->buffer_size;
|
||||
if (delta < 0) {
|
||||
hw_ptr_error(substream,
|
||||
"Unexpected hw_pointer value [2] "
|
||||
"(stream=%i, pos=%ld, old_ptr=%ld)\n",
|
||||
"(stream=%i, pos=%ld, old_ptr=%ld, jdelta=%li)\n",
|
||||
substream->stream, (long)pos,
|
||||
(long)old_hw_ptr);
|
||||
(long)old_hw_ptr, jdelta);
|
||||
return 0;
|
||||
}
|
||||
hw_base += runtime->buffer_size;
|
||||
|
@ -301,12 +329,13 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
|
|||
hw_base = 0;
|
||||
new_hw_ptr = hw_base + pos;
|
||||
}
|
||||
if (delta > runtime->period_size && runtime->periods > 1) {
|
||||
if (((delta * HZ) / runtime->rate) > jdelta + HZ/100) {
|
||||
hw_ptr_error(substream,
|
||||
"hw_ptr skipping! "
|
||||
"(pos=%ld, delta=%ld, period=%ld)\n",
|
||||
"(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu)\n",
|
||||
(long)pos, (long)delta,
|
||||
(long)runtime->period_size);
|
||||
(long)runtime->period_size, jdelta,
|
||||
((delta * HZ) / runtime->rate));
|
||||
return 0;
|
||||
}
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK &&
|
||||
|
@ -315,6 +344,7 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
|
|||
|
||||
runtime->hw_ptr_base = hw_base;
|
||||
runtime->status->hw_ptr = new_hw_ptr;
|
||||
runtime->hw_ptr_jiffies = jiffies;
|
||||
|
||||
return snd_pcm_update_hw_ptr_post(substream, runtime);
|
||||
}
|
||||
|
@ -1441,6 +1471,7 @@ static int snd_pcm_lib_ioctl_reset(struct snd_pcm_substream *substream,
|
|||
runtime->status->hw_ptr %= runtime->buffer_size;
|
||||
else
|
||||
runtime->status->hw_ptr = 0;
|
||||
runtime->hw_ptr_jiffies = jiffies;
|
||||
snd_pcm_stream_unlock_irqrestore(substream, flags);
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -312,6 +312,9 @@ struct azx_dev {
|
|||
unsigned int period_bytes; /* size of the period in bytes */
|
||||
unsigned int frags; /* number for period in the play buffer */
|
||||
unsigned int fifo_size; /* FIFO size */
|
||||
unsigned int start_flag: 1; /* stream full start flag */
|
||||
unsigned long start_jiffies; /* start + minimum jiffies */
|
||||
unsigned long min_jiffies; /* minimum jiffies before position is valid */
|
||||
|
||||
void __iomem *sd_addr; /* stream descriptor pointer */
|
||||
|
||||
|
@ -330,7 +333,6 @@ struct azx_dev {
|
|||
unsigned int opened :1;
|
||||
unsigned int running :1;
|
||||
unsigned int irq_pending :1;
|
||||
unsigned int irq_ignore :1;
|
||||
/*
|
||||
* For VIA:
|
||||
* A flag to ensure DMA position is 0
|
||||
|
@ -975,7 +977,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
|
|||
struct azx *chip = dev_id;
|
||||
struct azx_dev *azx_dev;
|
||||
u32 status;
|
||||
int i;
|
||||
int i, ok;
|
||||
|
||||
spin_lock(&chip->reg_lock);
|
||||
|
||||
|
@ -991,18 +993,14 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
|
|||
azx_sd_writeb(azx_dev, SD_STS, SD_INT_MASK);
|
||||
if (!azx_dev->substream || !azx_dev->running)
|
||||
continue;
|
||||
/* ignore the first dummy IRQ (due to pos_adj) */
|
||||
if (azx_dev->irq_ignore) {
|
||||
azx_dev->irq_ignore = 0;
|
||||
continue;
|
||||
}
|
||||
/* check whether this IRQ is really acceptable */
|
||||
if (azx_position_ok(chip, azx_dev)) {
|
||||
ok = azx_position_ok(chip, azx_dev);
|
||||
if (ok == 1) {
|
||||
azx_dev->irq_pending = 0;
|
||||
spin_unlock(&chip->reg_lock);
|
||||
snd_pcm_period_elapsed(azx_dev->substream);
|
||||
spin_lock(&chip->reg_lock);
|
||||
} else if (chip->bus && chip->bus->workq) {
|
||||
} else if (ok == 0 && chip->bus && chip->bus->workq) {
|
||||
/* bogus IRQ, process it later */
|
||||
azx_dev->irq_pending = 1;
|
||||
queue_work(chip->bus->workq,
|
||||
|
@ -1088,7 +1086,6 @@ static int azx_setup_periods(struct azx *chip,
|
|||
bdl = (u32 *)azx_dev->bdl.area;
|
||||
ofs = 0;
|
||||
azx_dev->frags = 0;
|
||||
azx_dev->irq_ignore = 0;
|
||||
pos_adj = bdl_pos_adj[chip->dev_index];
|
||||
if (pos_adj > 0) {
|
||||
struct snd_pcm_runtime *runtime = substream->runtime;
|
||||
|
@ -1109,7 +1106,6 @@ static int azx_setup_periods(struct azx *chip,
|
|||
&bdl, ofs, pos_adj, 1);
|
||||
if (ofs < 0)
|
||||
goto error;
|
||||
azx_dev->irq_ignore = 1;
|
||||
}
|
||||
} else
|
||||
pos_adj = 0;
|
||||
|
@ -1155,6 +1151,9 @@ static void azx_stream_reset(struct azx *chip, struct azx_dev *azx_dev)
|
|||
while (((val = azx_sd_readb(azx_dev, SD_CTL)) & SD_CTL_STREAM_RESET) &&
|
||||
--timeout)
|
||||
;
|
||||
|
||||
/* reset first position - may not be synced with hw at this time */
|
||||
*azx_dev->posbuf = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1409,7 +1408,6 @@ static int azx_pcm_open(struct snd_pcm_substream *substream)
|
|||
snd_pcm_set_sync(substream);
|
||||
mutex_unlock(&chip->open_mutex);
|
||||
|
||||
azx_stream_reset(chip, azx_dev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1474,6 +1472,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
|
|||
unsigned int bufsize, period_bytes, format_val;
|
||||
int err;
|
||||
|
||||
azx_stream_reset(chip, azx_dev);
|
||||
format_val = snd_hda_calc_stream_format(runtime->rate,
|
||||
runtime->channels,
|
||||
runtime->format,
|
||||
|
@ -1502,6 +1501,8 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream)
|
|||
return err;
|
||||
}
|
||||
|
||||
azx_dev->min_jiffies = (runtime->period_size * HZ) /
|
||||
(runtime->rate * 2);
|
||||
azx_setup_controller(chip, azx_dev);
|
||||
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
|
||||
azx_dev->fifo_size = azx_sd_readw(azx_dev, SD_FIFOSIZE) + 1;
|
||||
|
@ -1518,13 +1519,14 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
struct azx *chip = apcm->chip;
|
||||
struct azx_dev *azx_dev;
|
||||
struct snd_pcm_substream *s;
|
||||
int start, nsync = 0, sbits = 0;
|
||||
int rstart = 0, start, nsync = 0, sbits = 0;
|
||||
int nwait, timeout;
|
||||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
rstart = 1;
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
start = 1;
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
|
||||
|
@ -1554,6 +1556,10 @@ static int azx_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
if (s->pcm->card != substream->pcm->card)
|
||||
continue;
|
||||
azx_dev = get_azx_dev(s);
|
||||
if (rstart) {
|
||||
azx_dev->start_flag = 1;
|
||||
azx_dev->start_jiffies = jiffies + azx_dev->min_jiffies;
|
||||
}
|
||||
if (start)
|
||||
azx_stream_start(chip, azx_dev);
|
||||
else
|
||||
|
@ -1703,6 +1709,11 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev)
|
|||
{
|
||||
unsigned int pos;
|
||||
|
||||
if (azx_dev->start_flag &&
|
||||
time_before_eq(jiffies, azx_dev->start_jiffies))
|
||||
return -1; /* bogus (too early) interrupt */
|
||||
azx_dev->start_flag = 0;
|
||||
|
||||
pos = azx_get_position(chip, azx_dev);
|
||||
if (chip->position_fix == POS_FIX_AUTO) {
|
||||
if (!pos) {
|
||||
|
|
|
@ -355,6 +355,9 @@ struct ichdev {
|
|||
unsigned int fragsize1;
|
||||
unsigned int position;
|
||||
unsigned int pos_shift;
|
||||
unsigned int last_pos;
|
||||
unsigned long last_pos_jiffies;
|
||||
unsigned int jiffy_to_bytes;
|
||||
int frags;
|
||||
int lvi;
|
||||
int lvi_frag;
|
||||
|
@ -838,7 +841,10 @@ 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;
|
||||
ichdev->last_pos_jiffies = jiffies;
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
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:
|
||||
val = ICH_IOCE;
|
||||
break;
|
||||
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
|
||||
val = ICH_IOCE | ICH_STARTBM;
|
||||
break;
|
||||
default:
|
||||
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;
|
||||
}
|
||||
snd_intel8x0_setup_periods(chip, ichdev);
|
||||
ichdev->jiffy_to_bytes = (runtime->rate * 4 * ichdev->pos_shift) / HZ;
|
||||
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 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 +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))
|
||||
break;
|
||||
} 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);
|
||||
if (ptr >= ichdev->size)
|
||||
return 0;
|
||||
|
@ -2661,12 +2675,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 +2690,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 +2709,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,19 +2748,37 @@ 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);
|
||||
|
||||
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);
|
||||
if (t == 0) {
|
||||
snd_printk(KERN_ERR "?? calculation error..\n");
|
||||
if (pos == 0) {
|
||||
snd_printk(KERN_ERR "intel8x0: measure - unreliable DMA position..\n");
|
||||
__retry:
|
||||
if (attempt < 2) {
|
||||
attempt++;
|
||||
goto __again;
|
||||
}
|
||||
return;
|
||||
}
|
||||
pos = (pos / 4) * 1000;
|
||||
|
||||
pos /= 4;
|
||||
t = stop_time.tv_sec - start_time.tv_sec;
|
||||
t *= 1000000;
|
||||
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 "intel8x0: ?? calculation error..\n");
|
||||
goto __retry;
|
||||
}
|
||||
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;
|
||||
|
|
Загрузка…
Ссылка в новой задаче