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 17 static 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 33 static 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 49 static 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 65 static 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 81 static 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 90 static 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 103 static 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 112 static 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 121 static 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 127 static 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 133 void 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 169 void 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 } 181