brintos

brintos / linux-shallow public Read only

0
0
Text · 4.5 KiB · 047ddbc Raw
189 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  Routines for Gravis UltraSound soundcards - Timers4 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>5 *6 *  GUS have similar timers as AdLib (OPL2/OPL3 chips).7 */8 9#include <linux/time.h>10#include <sound/core.h>11#include <sound/gus.h>12 13/*14 *  Timer 1 - 80us15 */16 17static int snd_gf1_timer1_start(struct snd_timer * timer)18{19	unsigned long flags;20	unsigned char tmp;21	unsigned int ticks;22	struct snd_gus_card *gus;23 24	gus = snd_timer_chip(timer);25	spin_lock_irqsave(&gus->reg_lock, flags);26	ticks = timer->sticks;27	tmp = (gus->gf1.timer_enabled |= 4);28	snd_gf1_write8(gus, SNDRV_GF1_GB_ADLIB_TIMER_1, 256 - ticks);	/* timer 1 count */29	snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp);	/* enable timer 1 IRQ */30	snd_gf1_adlib_write(gus, 0x04, tmp >> 2);	/* timer 2 start */31	spin_unlock_irqrestore(&gus->reg_lock, flags);32	return 0;33}34 35static int snd_gf1_timer1_stop(struct snd_timer * timer)36{37	unsigned long flags;38	unsigned char tmp;39	struct snd_gus_card *gus;40 41	gus = snd_timer_chip(timer);42	spin_lock_irqsave(&gus->reg_lock, flags);43	tmp = (gus->gf1.timer_enabled &= ~4);44	snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp);	/* disable timer #1 */45	spin_unlock_irqrestore(&gus->reg_lock, flags);46	return 0;47}48 49/*50 *  Timer 2 - 320us51 */52 53static int snd_gf1_timer2_start(struct snd_timer * timer)54{55	unsigned long flags;56	unsigned char tmp;57	unsigned int ticks;58	struct snd_gus_card *gus;59 60	gus = snd_timer_chip(timer);61	spin_lock_irqsave(&gus->reg_lock, flags);62	ticks = timer->sticks;63	tmp = (gus->gf1.timer_enabled |= 8);64	snd_gf1_write8(gus, SNDRV_GF1_GB_ADLIB_TIMER_2, 256 - ticks);	/* timer 2 count */65	snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp);	/* enable timer 2 IRQ */66	snd_gf1_adlib_write(gus, 0x04, tmp >> 2);	/* timer 2 start */67	spin_unlock_irqrestore(&gus->reg_lock, flags);68	return 0;69}70 71static int snd_gf1_timer2_stop(struct snd_timer * timer)72{73	unsigned long flags;74	unsigned char tmp;75	struct snd_gus_card *gus;76 77	gus = snd_timer_chip(timer);78	spin_lock_irqsave(&gus->reg_lock, flags);79	tmp = (gus->gf1.timer_enabled &= ~8);80	snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp);	/* disable timer #1 */81	spin_unlock_irqrestore(&gus->reg_lock, flags);82	return 0;83}84 85/*86 87 */88 89static void snd_gf1_interrupt_timer1(struct snd_gus_card * gus)90{91	struct snd_timer *timer = gus->gf1.timer1;92 93	if (timer == NULL)94		return;95	snd_timer_interrupt(timer, timer->sticks);96}97 98static void snd_gf1_interrupt_timer2(struct snd_gus_card * gus)99{100	struct snd_timer *timer = gus->gf1.timer2;101 102	if (timer == NULL)103		return;104	snd_timer_interrupt(timer, timer->sticks);105}106 107/*108 109 */110 111static const struct snd_timer_hardware snd_gf1_timer1 =112{113	.flags =	SNDRV_TIMER_HW_STOP,114	.resolution =	80000,115	.ticks =	256,116	.start =	snd_gf1_timer1_start,117	.stop =		snd_gf1_timer1_stop,118};119 120static const struct snd_timer_hardware snd_gf1_timer2 =121{122	.flags =	SNDRV_TIMER_HW_STOP,123	.resolution =	320000,124	.ticks =	256,125	.start =	snd_gf1_timer2_start,126	.stop =		snd_gf1_timer2_stop,127};128 129static void snd_gf1_timer1_free(struct snd_timer *timer)130{131	struct snd_gus_card *gus = timer->private_data;132	gus->gf1.timer1 = NULL;133}134 135static void snd_gf1_timer2_free(struct snd_timer *timer)136{137	struct snd_gus_card *gus = timer->private_data;138	gus->gf1.timer2 = NULL;139}140 141void snd_gf1_timers_init(struct snd_gus_card * gus)142{143	struct snd_timer *timer;144	struct snd_timer_id tid;145 146	if (gus->gf1.timer1 != NULL || gus->gf1.timer2 != NULL)147		return;148 149	gus->gf1.interrupt_handler_timer1 = snd_gf1_interrupt_timer1;150	gus->gf1.interrupt_handler_timer2 = snd_gf1_interrupt_timer2;151 152	tid.dev_class = SNDRV_TIMER_CLASS_CARD;153	tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;154	tid.card = gus->card->number;155	tid.device = gus->timer_dev;156	tid.subdevice = 0;157 158	if (snd_timer_new(gus->card, "GF1 timer", &tid, &timer) >= 0) {159		strcpy(timer->name, "GF1 timer #1");160		timer->private_data = gus;161		timer->private_free = snd_gf1_timer1_free;162		timer->hw = snd_gf1_timer1;163	}164	gus->gf1.timer1 = timer;165 166	tid.device++;167 168	if (snd_timer_new(gus->card, "GF1 timer", &tid, &timer) >= 0) {169		strcpy(timer->name, "GF1 timer #2");170		timer->private_data = gus;171		timer->private_free = snd_gf1_timer2_free;172		timer->hw = snd_gf1_timer2;173	}174	gus->gf1.timer2 = timer;175}176 177void snd_gf1_timers_done(struct snd_gus_card * gus)178{179	snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_TIMER1 | SNDRV_GF1_HANDLER_TIMER2);180	if (gus->gf1.timer1) {181		snd_device_free(gus->card, gus->gf1.timer1);182		gus->gf1.timer1 = NULL;183	}184	if (gus->gf1.timer2) {185		snd_device_free(gus->card, gus->gf1.timer2);186		gus->gf1.timer2 = NULL;187	}188}189