File Index
Files and directories
Sign in
FILE

gus_timer.c

File preview with syntax highlighting.

linux-6.19.14/sound/isa/gus/gus_timer.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 *  Routines for Gravis UltraSound soundcards - Timers
  4 *  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 - 80us
 15 */
 16
 17static int snd_gf1_timer1_start(struct snd_timer * timer)
 18{
 19	unsigned char tmp;
 20	unsigned int ticks;
 21	struct snd_gus_card *gus;
 22
 23	gus = snd_timer_chip(timer);
 24	guard(spinlock_irqsave)(&gus->reg_lock);
 25	ticks = timer->sticks;
 26	tmp = (gus->gf1.timer_enabled |= 4);
 27	snd_gf1_write8(gus, SNDRV_GF1_GB_ADLIB_TIMER_1, 256 - ticks);	/* timer 1 count */
 28	snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp);	/* enable timer 1 IRQ */
 29	snd_gf1_adlib_write(gus, 0x04, tmp >> 2);	/* timer 2 start */
 30	return 0;
 31}
 32
 33static int snd_gf1_timer1_stop(struct snd_timer * timer)
 34{
 35	unsigned char tmp;
 36	struct snd_gus_card *gus;
 37
 38	gus = snd_timer_chip(timer);
 39	guard(spinlock_irqsave)(&gus->reg_lock);
 40	tmp = (gus->gf1.timer_enabled &= ~4);
 41	snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp);	/* disable timer #1 */
 42	return 0;
 43}
 44
 45/*
 46 *  Timer 2 - 320us
 47 */
 48
 49static int snd_gf1_timer2_start(struct snd_timer * timer)
 50{
 51	unsigned char tmp;
 52	unsigned int ticks;
 53	struct snd_gus_card *gus;
 54
 55	gus = snd_timer_chip(timer);
 56	guard(spinlock_irqsave)(&gus->reg_lock);
 57	ticks = timer->sticks;
 58	tmp = (gus->gf1.timer_enabled |= 8);
 59	snd_gf1_write8(gus, SNDRV_GF1_GB_ADLIB_TIMER_2, 256 - ticks);	/* timer 2 count */
 60	snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp);	/* enable timer 2 IRQ */
 61	snd_gf1_adlib_write(gus, 0x04, tmp >> 2);	/* timer 2 start */
 62	return 0;
 63}
 64
 65static int snd_gf1_timer2_stop(struct snd_timer * timer)
 66{
 67	unsigned char tmp;
 68	struct snd_gus_card *gus;
 69
 70	gus = snd_timer_chip(timer);
 71	guard(spinlock_irqsave)(&gus->reg_lock);
 72	tmp = (gus->gf1.timer_enabled &= ~8);
 73	snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp);	/* disable timer #1 */
 74	return 0;
 75}
 76
 77/*
 78
 79 */
 80
 81static void snd_gf1_interrupt_timer1(struct snd_gus_card * gus)
 82{
 83	struct snd_timer *timer = gus->gf1.timer1;
 84
 85	if (timer == NULL)
 86		return;
 87	snd_timer_interrupt(timer, timer->sticks);
 88}
 89
 90static void snd_gf1_interrupt_timer2(struct snd_gus_card * gus)
 91{
 92	struct snd_timer *timer = gus->gf1.timer2;
 93
 94	if (timer == NULL)
 95		return;
 96	snd_timer_interrupt(timer, timer->sticks);
 97}
 98
 99/*
100
101 */
102
103static const struct snd_timer_hardware snd_gf1_timer1 =
104{
105	.flags =	SNDRV_TIMER_HW_STOP,
106	.resolution =	80000,
107	.ticks =	256,
108	.start =	snd_gf1_timer1_start,
109	.stop =		snd_gf1_timer1_stop,
110};
111
112static const struct snd_timer_hardware snd_gf1_timer2 =
113{
114	.flags =	SNDRV_TIMER_HW_STOP,
115	.resolution =	320000,
116	.ticks =	256,
117	.start =	snd_gf1_timer2_start,
118	.stop =		snd_gf1_timer2_stop,
119};
120
121static void snd_gf1_timer1_free(struct snd_timer *timer)
122{
123	struct snd_gus_card *gus = timer->private_data;
124	gus->gf1.timer1 = NULL;
125}
126
127static void snd_gf1_timer2_free(struct snd_timer *timer)
128{
129	struct snd_gus_card *gus = timer->private_data;
130	gus->gf1.timer2 = NULL;
131}
132
133void snd_gf1_timers_init(struct snd_gus_card * gus)
134{
135	struct snd_timer *timer;
136	struct snd_timer_id tid;
137
138	if (gus->gf1.timer1 != NULL || gus->gf1.timer2 != NULL)
139		return;
140
141	gus->gf1.interrupt_handler_timer1 = snd_gf1_interrupt_timer1;
142	gus->gf1.interrupt_handler_timer2 = snd_gf1_interrupt_timer2;
143
144	tid.dev_class = SNDRV_TIMER_CLASS_CARD;
145	tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE;
146	tid.card = gus->card->number;
147	tid.device = gus->timer_dev;
148	tid.subdevice = 0;
149
150	if (snd_timer_new(gus->card, "GF1 timer", &tid, &timer) >= 0) {
151		strscpy(timer->name, "GF1 timer #1");
152		timer->private_data = gus;
153		timer->private_free = snd_gf1_timer1_free;
154		timer->hw = snd_gf1_timer1;
155	}
156	gus->gf1.timer1 = timer;
157
158	tid.device++;
159
160	if (snd_timer_new(gus->card, "GF1 timer", &tid, &timer) >= 0) {
161		strscpy(timer->name, "GF1 timer #2");
162		timer->private_data = gus;
163		timer->private_free = snd_gf1_timer2_free;
164		timer->hw = snd_gf1_timer2;
165	}
166	gus->gf1.timer2 = timer;
167}
168
169void snd_gf1_timers_done(struct snd_gus_card * gus)
170{
171	snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_TIMER1 | SNDRV_GF1_HANDLER_TIMER2);
172	if (gus->gf1.timer1) {
173		snd_device_free(gus->card, gus->gf1.timer1);
174		gus->gf1.timer1 = NULL;
175	}
176	if (gus->gf1.timer2) {
177		snd_device_free(gus->card, gus->gf1.timer2);
178		gus->gf1.timer2 = NULL;
179	}
180}
~/ Read-only file preview.