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