File Index
Files and directories
Sign in
FILE

gus_io.c

File preview with syntax highlighting.

linux-6.19.14/sound/isa/gus/gus_io.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
  4 *  I/O routines for GF1/InterWave synthesizer chips
  5 */
  6
  7#include <linux/delay.h>
  8#include <linux/time.h>
  9#include <sound/core.h>
 10#include <sound/gus.h>
 11
 12void snd_gf1_delay(struct snd_gus_card * gus)
 13{
 14	int i;
 15
 16	for (i = 0; i < 6; i++) {
 17		mb();
 18		inb(GUSP(gus, DRAM));
 19	}
 20}
 21
 22/*
 23 *  =======================================================================
 24 */
 25
 26/*
 27 *  ok.. stop of control registers (wave & ramp) need some special things..
 28 *       big UltraClick (tm) elimination...
 29 */
 30
 31static inline void __snd_gf1_ctrl_stop(struct snd_gus_card * gus, unsigned char reg)
 32{
 33	unsigned char value;
 34
 35	outb(reg | 0x80, gus->gf1.reg_regsel);
 36	mb();
 37	value = inb(gus->gf1.reg_data8);
 38	mb();
 39	outb(reg, gus->gf1.reg_regsel);
 40	mb();
 41	outb((value | 0x03) & ~(0x80 | 0x20), gus->gf1.reg_data8);
 42	mb();
 43}
 44
 45static inline void __snd_gf1_write8(struct snd_gus_card * gus,
 46				    unsigned char reg,
 47				    unsigned char data)
 48{
 49	outb(reg, gus->gf1.reg_regsel);
 50	mb();
 51	outb(data, gus->gf1.reg_data8);
 52	mb();
 53}
 54
 55static inline unsigned char __snd_gf1_look8(struct snd_gus_card * gus,
 56					    unsigned char reg)
 57{
 58	outb(reg, gus->gf1.reg_regsel);
 59	mb();
 60	return inb(gus->gf1.reg_data8);
 61}
 62
 63static inline void __snd_gf1_write16(struct snd_gus_card * gus,
 64				     unsigned char reg, unsigned int data)
 65{
 66	outb(reg, gus->gf1.reg_regsel);
 67	mb();
 68	outw((unsigned short) data, gus->gf1.reg_data16);
 69	mb();
 70}
 71
 72static inline unsigned short __snd_gf1_look16(struct snd_gus_card * gus,
 73					      unsigned char reg)
 74{
 75	outb(reg, gus->gf1.reg_regsel);
 76	mb();
 77	return inw(gus->gf1.reg_data16);
 78}
 79
 80static inline void __snd_gf1_adlib_write(struct snd_gus_card * gus,
 81					 unsigned char reg, unsigned char data)
 82{
 83	outb(reg, gus->gf1.reg_timerctrl);
 84	inb(gus->gf1.reg_timerctrl);
 85	inb(gus->gf1.reg_timerctrl);
 86	outb(data, gus->gf1.reg_timerdata);
 87	inb(gus->gf1.reg_timerctrl);
 88	inb(gus->gf1.reg_timerctrl);
 89}
 90
 91static inline void __snd_gf1_write_addr(struct snd_gus_card * gus, unsigned char reg,
 92                                        unsigned int addr, int w_16bit)
 93{
 94	if (gus->gf1.enh_mode) {
 95		if (w_16bit)
 96			addr = ((addr >> 1) & ~0x0000000f) | (addr & 0x0000000f);
 97		__snd_gf1_write8(gus, SNDRV_GF1_VB_UPPER_ADDRESS, (unsigned char) ((addr >> 26) & 0x03));
 98	} else if (w_16bit)
 99		addr = (addr & 0x00c0000f) | ((addr & 0x003ffff0) >> 1);
100	__snd_gf1_write16(gus, reg, (unsigned short) (addr >> 11));
101	__snd_gf1_write16(gus, reg + 1, (unsigned short) (addr << 5));
102}
103
104static inline unsigned int __snd_gf1_read_addr(struct snd_gus_card * gus,
105					       unsigned char reg, short w_16bit)
106{
107	unsigned int res;
108
109	res = ((unsigned int) __snd_gf1_look16(gus, reg | 0x80) << 11) & 0xfff800;
110	res |= ((unsigned int) __snd_gf1_look16(gus, (reg + 1) | 0x80) >> 5) & 0x0007ff;
111	if (gus->gf1.enh_mode) {
112		res |= (unsigned int) __snd_gf1_look8(gus, SNDRV_GF1_VB_UPPER_ADDRESS | 0x80) << 26;
113		if (w_16bit)
114			res = ((res << 1) & 0xffffffe0) | (res & 0x0000000f);
115	} else if (w_16bit)
116		res = ((res & 0x001ffff0) << 1) | (res & 0x00c0000f);
117	return res;
118}
119
120
121/*
122 *  =======================================================================
123 */
124
125void snd_gf1_ctrl_stop(struct snd_gus_card * gus, unsigned char reg)
126{
127	__snd_gf1_ctrl_stop(gus, reg);
128}
129
130void snd_gf1_write8(struct snd_gus_card * gus,
131		    unsigned char reg,
132		    unsigned char data)
133{
134	__snd_gf1_write8(gus, reg, data);
135}
136
137unsigned char snd_gf1_look8(struct snd_gus_card * gus, unsigned char reg)
138{
139	return __snd_gf1_look8(gus, reg);
140}
141
142void snd_gf1_write16(struct snd_gus_card * gus,
143		     unsigned char reg,
144		     unsigned int data)
145{
146	__snd_gf1_write16(gus, reg, data);
147}
148
149unsigned short snd_gf1_look16(struct snd_gus_card * gus, unsigned char reg)
150{
151	return __snd_gf1_look16(gus, reg);
152}
153
154void snd_gf1_adlib_write(struct snd_gus_card * gus,
155                         unsigned char reg,
156                         unsigned char data)
157{
158	__snd_gf1_adlib_write(gus, reg, data);
159}
160
161void snd_gf1_write_addr(struct snd_gus_card * gus, unsigned char reg,
162                        unsigned int addr, short w_16bit)
163{
164	__snd_gf1_write_addr(gus, reg, addr, w_16bit);
165}
166
167unsigned int snd_gf1_read_addr(struct snd_gus_card * gus,
168                               unsigned char reg,
169                               short w_16bit)
170{
171	return __snd_gf1_read_addr(gus, reg, w_16bit);
172}
173
174/*
175
176 */
177
178void snd_gf1_i_ctrl_stop(struct snd_gus_card * gus, unsigned char reg)
179{
180	guard(spinlock_irqsave)(&gus->reg_lock);
181	__snd_gf1_ctrl_stop(gus, reg);
182}
183
184void snd_gf1_i_write8(struct snd_gus_card * gus,
185		      unsigned char reg,
186                      unsigned char data)
187{
188	guard(spinlock_irqsave)(&gus->reg_lock);
189	__snd_gf1_write8(gus, reg, data);
190}
191
192unsigned char snd_gf1_i_look8(struct snd_gus_card * gus, unsigned char reg)
193{
194	guard(spinlock_irqsave)(&gus->reg_lock);
195	return __snd_gf1_look8(gus, reg);
196}
197
198void snd_gf1_i_write16(struct snd_gus_card * gus,
199		       unsigned char reg,
200		       unsigned int data)
201{
202	guard(spinlock_irqsave)(&gus->reg_lock);
203	__snd_gf1_write16(gus, reg, data);
204}
205
206unsigned short snd_gf1_i_look16(struct snd_gus_card * gus, unsigned char reg)
207{
208	guard(spinlock_irqsave)(&gus->reg_lock);
209	return __snd_gf1_look16(gus, reg);
210}
211
212void snd_gf1_dram_addr(struct snd_gus_card * gus, unsigned int addr)
213{
214	outb(0x43, gus->gf1.reg_regsel);
215	mb();
216	outw((unsigned short) addr, gus->gf1.reg_data16);
217	mb();
218	outb(0x44, gus->gf1.reg_regsel);
219	mb();
220	outb((unsigned char) (addr >> 16), gus->gf1.reg_data8);
221	mb();
222}
223
224void snd_gf1_poke(struct snd_gus_card * gus, unsigned int addr, unsigned char data)
225{
226	guard(spinlock_irqsave)(&gus->reg_lock);
227	outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel);
228	mb();
229	outw((unsigned short) addr, gus->gf1.reg_data16);
230	mb();
231	outb(SNDRV_GF1_GB_DRAM_IO_HIGH, gus->gf1.reg_regsel);
232	mb();
233	outb((unsigned char) (addr >> 16), gus->gf1.reg_data8);
234	mb();
235	outb(data, gus->gf1.reg_dram);
236}
237
238unsigned char snd_gf1_peek(struct snd_gus_card * gus, unsigned int addr)
239{
240	guard(spinlock_irqsave)(&gus->reg_lock);
241	outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel);
242	mb();
243	outw((unsigned short) addr, gus->gf1.reg_data16);
244	mb();
245	outb(SNDRV_GF1_GB_DRAM_IO_HIGH, gus->gf1.reg_regsel);
246	mb();
247	outb((unsigned char) (addr >> 16), gus->gf1.reg_data8);
248	mb();
249	return inb(gus->gf1.reg_dram);
250}
251
252#if 0
253
254void snd_gf1_pokew(struct snd_gus_card * gus, unsigned int addr, unsigned short data)
255{
256	if (!gus->interwave)
257		dev_dbg(gus->card->dev, "%s - GF1!!!\n", __func__);
258	guard(spinlock_irqsave)(&gus->reg_lock);
259	outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel);
260	mb();
261	outw((unsigned short) addr, gus->gf1.reg_data16);
262	mb();
263	outb(SNDRV_GF1_GB_DRAM_IO_HIGH, gus->gf1.reg_regsel);
264	mb();
265	outb((unsigned char) (addr >> 16), gus->gf1.reg_data8);
266	mb();
267	outb(SNDRV_GF1_GW_DRAM_IO16, gus->gf1.reg_regsel);
268	mb();
269	outw(data, gus->gf1.reg_data16);
270}
271
272unsigned short snd_gf1_peekw(struct snd_gus_card * gus, unsigned int addr)
273{
274	if (!gus->interwave)
275		dev_dbg(gus->card->dev, "%s - GF1!!!\n", __func__);
276	guard(spinlock_irqsave)(&gus->reg_lock);
277	outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel);
278	mb();
279	outw((unsigned short) addr, gus->gf1.reg_data16);
280	mb();
281	outb(SNDRV_GF1_GB_DRAM_IO_HIGH, gus->gf1.reg_regsel);
282	mb();
283	outb((unsigned char) (addr >> 16), gus->gf1.reg_data8);
284	mb();
285	outb(SNDRV_GF1_GW_DRAM_IO16, gus->gf1.reg_regsel);
286	mb();
287	return inw(gus->gf1.reg_data16);
288}
289
290void snd_gf1_dram_setmem(struct snd_gus_card * gus, unsigned int addr,
291			 unsigned short value, unsigned int count)
292{
293	unsigned long port;
294
295	if (!gus->interwave)
296		dev_dbg(gus->card->dev, "%s - GF1!!!\n", __func__);
297	addr &= ~1;
298	count >>= 1;
299	port = GUSP(gus, GF1DATALOW);
300	guard(spinlock_irqsave)(&gus->reg_lock);
301	outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel);
302	mb();
303	outw((unsigned short) addr, gus->gf1.reg_data16);
304	mb();
305	outb(SNDRV_GF1_GB_DRAM_IO_HIGH, gus->gf1.reg_regsel);
306	mb();
307	outb((unsigned char) (addr >> 16), gus->gf1.reg_data8);
308	mb();
309	outb(SNDRV_GF1_GW_DRAM_IO16, gus->gf1.reg_regsel);
310	while (count--)
311		outw(value, port);
312}
313
314#endif  /*  0  */
315
316void snd_gf1_select_active_voices(struct snd_gus_card * gus)
317{
318	unsigned short voices;
319
320	static const unsigned short voices_tbl[32 - 14 + 1] =
321	{
322	    44100, 41160, 38587, 36317, 34300, 32494, 30870, 29400, 28063, 26843,
323	    25725, 24696, 23746, 22866, 22050, 21289, 20580, 19916, 19293
324	};
325
326	voices = gus->gf1.active_voices;
327	if (voices > 32)
328		voices = 32;
329	if (voices < 14)
330		voices = 14;
331	if (gus->gf1.enh_mode)
332		voices = 32;
333	gus->gf1.active_voices = voices;
334	gus->gf1.playback_freq =
335	    gus->gf1.enh_mode ? 44100 : voices_tbl[voices - 14];
336	if (!gus->gf1.enh_mode) {
337		snd_gf1_i_write8(gus, SNDRV_GF1_GB_ACTIVE_VOICES, 0xc0 | (voices - 1));
338		udelay(100);
339	}
340}
~/ Read-only file preview.