FILE
gus_timer.c
File preview with syntax highlighting.
linux-6.19.14/sound/isa/gus/gus_timer.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.