• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/sound/isa/gus/
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
32static 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
50static 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
68static 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
86static 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
104static 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
113static 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
126static 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
135static 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
144static 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
150static 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
156void 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
192void 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