static int pcsp_start_playing(struct snd_pcsp *chip)
{
	unsigned long ns;

#if PCSP_DEBUG
	printk(KERN_INFO "PCSP: start_playing called\n");
#endif
	if (atomic_read(&chip->timer_active)) {
		printk(KERN_ERR "PCSP: Timer already active\n");
		return -EIO;
	}

	spin_lock(&i8253_lock);
	chip->val61 = inb(0x61) | 0x03;
	outb_p(0x92, 0x43);	/* binary, mode 1, LSB only, ch 2 */
	spin_unlock(&i8253_lock);
	atomic_set(&chip->timer_active, 1);
	chip->thalf = 0;

	ns = pcsp_timer_update(&pcsp_chip.timer);
	if (!ns)
		return -EIO;

	hrtimer_start(&pcsp_chip.timer, ktime_set(0, ns), HRTIMER_MODE_REL);
	return 0;
}
enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
{
	struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer);
	struct snd_pcm_substream *substream;
	int periods_elapsed, pointer_update;
	size_t period_bytes, buffer_bytes;
	unsigned long ns;
	unsigned long flags;

	pointer_update = !chip->thalf;
	ns = pcsp_timer_update(handle);
	if (!ns)
		return HRTIMER_NORESTART;

	/* update the playback position */
	substream = chip->playback_substream;
	if (!substream)
		return HRTIMER_NORESTART;

	period_bytes = snd_pcm_lib_period_bytes(substream);
	buffer_bytes = snd_pcm_lib_buffer_bytes(substream);

	spin_lock_irqsave(&chip->substream_lock, flags);
	chip->playback_ptr += PCSP_INDEX_INC() * chip->fmt_size;
	periods_elapsed = chip->playback_ptr - chip->period_ptr;
	if (periods_elapsed < 0) {
#if PCSP_DEBUG
		printk(KERN_INFO "PCSP: buffer_bytes mod period_bytes != 0 ? "
			"(%zi %zi %zi)\n",
			chip->playback_ptr, period_bytes, buffer_bytes);
#endif
		periods_elapsed += buffer_bytes;
	}
	periods_elapsed /= period_bytes;
	/* wrap the pointer _before_ calling snd_pcm_period_elapsed(),
	 * or ALSA will BUG on us. */
	chip->playback_ptr %= buffer_bytes;

	if (periods_elapsed) {
		chip->period_ptr += periods_elapsed * period_bytes;
		chip->period_ptr %= buffer_bytes;
	}
	spin_unlock_irqrestore(&chip->substream_lock, flags);

	if (periods_elapsed)
		tasklet_schedule(&pcsp_pcm_tasklet);

	hrtimer_forward(handle, hrtimer_get_expires(handle), ns_to_ktime(ns));

	return HRTIMER_RESTART;
}
Beispiel #3
0
enum hrtimer_restart pcsp_do_timer(struct hrtimer *handle)
{
	struct snd_pcsp *chip = container_of(handle, struct snd_pcsp, timer);
	int pointer_update;
	u64 ns;

	if (!atomic_read(&chip->timer_active) || !chip->playback_substream)
		return HRTIMER_NORESTART;

	pointer_update = !chip->thalf;
	ns = pcsp_timer_update(chip);
	if (!ns) {
		printk(KERN_WARNING "PCSP: unexpected stop\n");
		return HRTIMER_NORESTART;
	}

	if (pointer_update)
		pcsp_pointer_update(chip);

	hrtimer_forward(handle, hrtimer_get_expires(handle), ns_to_ktime(ns));

	return HRTIMER_RESTART;
}