gus_timer.c (4650B)
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 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 - 320us 51 */ 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}