1 /* 2 * Routines for Gravis UltraSound soundcards - Timers 3 * Copyright (c) by Jaroslav Kysela <perex@suse.cz> 4 * 5 * GUS have similar timers as AdLib (OPL2/OPL3 chips). 6 * 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 * 22 */ 23 24 #include <sound/driver.h> 25 #include <linux/time.h> 26 #include <sound/core.h> 27 #include <sound/gus.h> 28 29 /* 30 * Timer 1 - 80us 31 */ 32 33 static int snd_gf1_timer1_start(struct snd_timer * timer) 34 { 35 unsigned long flags; 36 unsigned char tmp; 37 unsigned int ticks; 38 struct snd_gus_card *gus; 39 40 gus = snd_timer_chip(timer); 41 spin_lock_irqsave(&gus->reg_lock, flags); 42 ticks = timer->sticks; 43 tmp = (gus->gf1.timer_enabled |= 4); 44 snd_gf1_write8(gus, SNDRV_GF1_GB_ADLIB_TIMER_1, 256 - ticks); /* timer 1 count */ 45 snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp); /* enable timer 1 IRQ */ 46 snd_gf1_adlib_write(gus, 0x04, tmp >> 2); /* timer 2 start */ 47 spin_unlock_irqrestore(&gus->reg_lock, flags); 48 return 0; 49 } 50 51 static int snd_gf1_timer1_stop(struct snd_timer * timer) 52 { 53 unsigned long flags; 54 unsigned char tmp; 55 struct snd_gus_card *gus; 56 57 gus = snd_timer_chip(timer); 58 spin_lock_irqsave(&gus->reg_lock, flags); 59 tmp = (gus->gf1.timer_enabled &= ~4); 60 snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp); /* disable timer #1 */ 61 spin_unlock_irqrestore(&gus->reg_lock, flags); 62 return 0; 63 } 64 65 /* 66 * Timer 2 - 320us 67 */ 68 69 static int snd_gf1_timer2_start(struct snd_timer * timer) 70 { 71 unsigned long flags; 72 unsigned char tmp; 73 unsigned int ticks; 74 struct snd_gus_card *gus; 75 76 gus = snd_timer_chip(timer); 77 spin_lock_irqsave(&gus->reg_lock, flags); 78 ticks = timer->sticks; 79 tmp = (gus->gf1.timer_enabled |= 8); 80 snd_gf1_write8(gus, SNDRV_GF1_GB_ADLIB_TIMER_2, 256 - ticks); /* timer 2 count */ 81 snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp); /* enable timer 2 IRQ */ 82 snd_gf1_adlib_write(gus, 0x04, tmp >> 2); /* timer 2 start */ 83 spin_unlock_irqrestore(&gus->reg_lock, flags); 84 return 0; 85 } 86 87 static int snd_gf1_timer2_stop(struct snd_timer * timer) 88 { 89 unsigned long flags; 90 unsigned char tmp; 91 struct snd_gus_card *gus; 92 93 gus = snd_timer_chip(timer); 94 spin_lock_irqsave(&gus->reg_lock, flags); 95 tmp = (gus->gf1.timer_enabled &= ~8); 96 snd_gf1_write8(gus, SNDRV_GF1_GB_SOUND_BLASTER_CONTROL, tmp); /* disable timer #1 */ 97 spin_unlock_irqrestore(&gus->reg_lock, flags); 98 return 0; 99 } 100 101 /* 102 103 */ 104 105 static void snd_gf1_interrupt_timer1(struct snd_gus_card * gus) 106 { 107 struct snd_timer *timer = gus->gf1.timer1; 108 109 if (timer == NULL) 110 return; 111 snd_timer_interrupt(timer, timer->sticks); 112 } 113 114 static void snd_gf1_interrupt_timer2(struct snd_gus_card * gus) 115 { 116 struct snd_timer *timer = gus->gf1.timer2; 117 118 if (timer == NULL) 119 return; 120 snd_timer_interrupt(timer, timer->sticks); 121 } 122 123 /* 124 125 */ 126 127 static struct snd_timer_hardware snd_gf1_timer1 = 128 { 129 .flags = SNDRV_TIMER_HW_STOP, 130 .resolution = 80000, 131 .ticks = 256, 132 .start = snd_gf1_timer1_start, 133 .stop = snd_gf1_timer1_stop, 134 }; 135 136 static struct snd_timer_hardware snd_gf1_timer2 = 137 { 138 .flags = SNDRV_TIMER_HW_STOP, 139 .resolution = 320000, 140 .ticks = 256, 141 .start = snd_gf1_timer2_start, 142 .stop = snd_gf1_timer2_stop, 143 }; 144 145 static void snd_gf1_timer1_free(struct snd_timer *timer) 146 { 147 struct snd_gus_card *gus = timer->private_data; 148 gus->gf1.timer1 = NULL; 149 } 150 151 static void snd_gf1_timer2_free(struct snd_timer *timer) 152 { 153 struct snd_gus_card *gus = timer->private_data; 154 gus->gf1.timer2 = NULL; 155 } 156 157 void snd_gf1_timers_init(struct snd_gus_card * gus) 158 { 159 struct snd_timer *timer; 160 struct snd_timer_id tid; 161 162 if (gus->gf1.timer1 != NULL || gus->gf1.timer2 != NULL) 163 return; 164 165 gus->gf1.interrupt_handler_timer1 = snd_gf1_interrupt_timer1; 166 gus->gf1.interrupt_handler_timer2 = snd_gf1_interrupt_timer2; 167 168 tid.dev_class = SNDRV_TIMER_CLASS_CARD; 169 tid.dev_sclass = SNDRV_TIMER_SCLASS_NONE; 170 tid.card = gus->card->number; 171 tid.device = gus->timer_dev; 172 tid.subdevice = 0; 173 174 if (snd_timer_new(gus->card, "GF1 timer", &tid, &timer) >= 0) { 175 strcpy(timer->name, "GF1 timer #1"); 176 timer->private_data = gus; 177 timer->private_free = snd_gf1_timer1_free; 178 timer->hw = snd_gf1_timer1; 179 } 180 gus->gf1.timer1 = timer; 181 182 tid.device++; 183 184 if (snd_timer_new(gus->card, "GF1 timer", &tid, &timer) >= 0) { 185 strcpy(timer->name, "GF1 timer #2"); 186 timer->private_data = gus; 187 timer->private_free = snd_gf1_timer2_free; 188 timer->hw = snd_gf1_timer2; 189 } 190 gus->gf1.timer2 = timer; 191 } 192 193 void snd_gf1_timers_done(struct snd_gus_card * gus) 194 { 195 snd_gf1_set_default_handlers(gus, SNDRV_GF1_HANDLER_TIMER1 | SNDRV_GF1_HANDLER_TIMER2); 196 if (gus->gf1.timer1) { 197 snd_device_free(gus->card, gus->gf1.timer1); 198 gus->gf1.timer1 = NULL; 199 } 200 if (gus->gf1.timer2) { 201 snd_device_free(gus->card, gus->gf1.timer2); 202 gus->gf1.timer2 = NULL; 203 } 204 } 205