Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/isa/gus/gus_io.c
26425 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Copyright (c) by Jaroslav Kysela <[email protected]>
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
12
void 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
31
static 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
45
static 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
55
static 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
63
static 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
72
static 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
80
static 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
91
static 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
104
static 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
125
void snd_gf1_ctrl_stop(struct snd_gus_card * gus, unsigned char reg)
126
{
127
__snd_gf1_ctrl_stop(gus, reg);
128
}
129
130
void 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
137
unsigned char snd_gf1_look8(struct snd_gus_card * gus, unsigned char reg)
138
{
139
return __snd_gf1_look8(gus, reg);
140
}
141
142
void 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
149
unsigned short snd_gf1_look16(struct snd_gus_card * gus, unsigned char reg)
150
{
151
return __snd_gf1_look16(gus, reg);
152
}
153
154
void 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
161
void 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
167
unsigned 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
178
void snd_gf1_i_ctrl_stop(struct snd_gus_card * gus, unsigned char reg)
179
{
180
unsigned long flags;
181
182
spin_lock_irqsave(&gus->reg_lock, flags);
183
__snd_gf1_ctrl_stop(gus, reg);
184
spin_unlock_irqrestore(&gus->reg_lock, flags);
185
}
186
187
void snd_gf1_i_write8(struct snd_gus_card * gus,
188
unsigned char reg,
189
unsigned char data)
190
{
191
unsigned long flags;
192
193
spin_lock_irqsave(&gus->reg_lock, flags);
194
__snd_gf1_write8(gus, reg, data);
195
spin_unlock_irqrestore(&gus->reg_lock, flags);
196
}
197
198
unsigned char snd_gf1_i_look8(struct snd_gus_card * gus, unsigned char reg)
199
{
200
unsigned long flags;
201
unsigned char res;
202
203
spin_lock_irqsave(&gus->reg_lock, flags);
204
res = __snd_gf1_look8(gus, reg);
205
spin_unlock_irqrestore(&gus->reg_lock, flags);
206
return res;
207
}
208
209
void snd_gf1_i_write16(struct snd_gus_card * gus,
210
unsigned char reg,
211
unsigned int data)
212
{
213
unsigned long flags;
214
215
spin_lock_irqsave(&gus->reg_lock, flags);
216
__snd_gf1_write16(gus, reg, data);
217
spin_unlock_irqrestore(&gus->reg_lock, flags);
218
}
219
220
unsigned short snd_gf1_i_look16(struct snd_gus_card * gus, unsigned char reg)
221
{
222
unsigned long flags;
223
unsigned short res;
224
225
spin_lock_irqsave(&gus->reg_lock, flags);
226
res = __snd_gf1_look16(gus, reg);
227
spin_unlock_irqrestore(&gus->reg_lock, flags);
228
return res;
229
}
230
231
void snd_gf1_dram_addr(struct snd_gus_card * gus, unsigned int addr)
232
{
233
outb(0x43, gus->gf1.reg_regsel);
234
mb();
235
outw((unsigned short) addr, gus->gf1.reg_data16);
236
mb();
237
outb(0x44, gus->gf1.reg_regsel);
238
mb();
239
outb((unsigned char) (addr >> 16), gus->gf1.reg_data8);
240
mb();
241
}
242
243
void snd_gf1_poke(struct snd_gus_card * gus, unsigned int addr, unsigned char data)
244
{
245
unsigned long flags;
246
247
spin_lock_irqsave(&gus->reg_lock, flags);
248
outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel);
249
mb();
250
outw((unsigned short) addr, gus->gf1.reg_data16);
251
mb();
252
outb(SNDRV_GF1_GB_DRAM_IO_HIGH, gus->gf1.reg_regsel);
253
mb();
254
outb((unsigned char) (addr >> 16), gus->gf1.reg_data8);
255
mb();
256
outb(data, gus->gf1.reg_dram);
257
spin_unlock_irqrestore(&gus->reg_lock, flags);
258
}
259
260
unsigned char snd_gf1_peek(struct snd_gus_card * gus, unsigned int addr)
261
{
262
unsigned long flags;
263
unsigned char res;
264
265
spin_lock_irqsave(&gus->reg_lock, flags);
266
outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel);
267
mb();
268
outw((unsigned short) addr, gus->gf1.reg_data16);
269
mb();
270
outb(SNDRV_GF1_GB_DRAM_IO_HIGH, gus->gf1.reg_regsel);
271
mb();
272
outb((unsigned char) (addr >> 16), gus->gf1.reg_data8);
273
mb();
274
res = inb(gus->gf1.reg_dram);
275
spin_unlock_irqrestore(&gus->reg_lock, flags);
276
return res;
277
}
278
279
#if 0
280
281
void snd_gf1_pokew(struct snd_gus_card * gus, unsigned int addr, unsigned short data)
282
{
283
unsigned long flags;
284
285
if (!gus->interwave)
286
dev_dbg(gus->card->dev, "%s - GF1!!!\n", __func__);
287
spin_lock_irqsave(&gus->reg_lock, flags);
288
outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel);
289
mb();
290
outw((unsigned short) addr, gus->gf1.reg_data16);
291
mb();
292
outb(SNDRV_GF1_GB_DRAM_IO_HIGH, gus->gf1.reg_regsel);
293
mb();
294
outb((unsigned char) (addr >> 16), gus->gf1.reg_data8);
295
mb();
296
outb(SNDRV_GF1_GW_DRAM_IO16, gus->gf1.reg_regsel);
297
mb();
298
outw(data, gus->gf1.reg_data16);
299
spin_unlock_irqrestore(&gus->reg_lock, flags);
300
}
301
302
unsigned short snd_gf1_peekw(struct snd_gus_card * gus, unsigned int addr)
303
{
304
unsigned long flags;
305
unsigned short res;
306
307
if (!gus->interwave)
308
dev_dbg(gus->card->dev, "%s - GF1!!!\n", __func__);
309
spin_lock_irqsave(&gus->reg_lock, flags);
310
outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel);
311
mb();
312
outw((unsigned short) addr, gus->gf1.reg_data16);
313
mb();
314
outb(SNDRV_GF1_GB_DRAM_IO_HIGH, gus->gf1.reg_regsel);
315
mb();
316
outb((unsigned char) (addr >> 16), gus->gf1.reg_data8);
317
mb();
318
outb(SNDRV_GF1_GW_DRAM_IO16, gus->gf1.reg_regsel);
319
mb();
320
res = inw(gus->gf1.reg_data16);
321
spin_unlock_irqrestore(&gus->reg_lock, flags);
322
return res;
323
}
324
325
void snd_gf1_dram_setmem(struct snd_gus_card * gus, unsigned int addr,
326
unsigned short value, unsigned int count)
327
{
328
unsigned long port;
329
unsigned long flags;
330
331
if (!gus->interwave)
332
dev_dbg(gus->card->dev, "%s - GF1!!!\n", __func__);
333
addr &= ~1;
334
count >>= 1;
335
port = GUSP(gus, GF1DATALOW);
336
spin_lock_irqsave(&gus->reg_lock, flags);
337
outb(SNDRV_GF1_GW_DRAM_IO_LOW, gus->gf1.reg_regsel);
338
mb();
339
outw((unsigned short) addr, gus->gf1.reg_data16);
340
mb();
341
outb(SNDRV_GF1_GB_DRAM_IO_HIGH, gus->gf1.reg_regsel);
342
mb();
343
outb((unsigned char) (addr >> 16), gus->gf1.reg_data8);
344
mb();
345
outb(SNDRV_GF1_GW_DRAM_IO16, gus->gf1.reg_regsel);
346
while (count--)
347
outw(value, port);
348
spin_unlock_irqrestore(&gus->reg_lock, flags);
349
}
350
351
#endif /* 0 */
352
353
void snd_gf1_select_active_voices(struct snd_gus_card * gus)
354
{
355
unsigned short voices;
356
357
static const unsigned short voices_tbl[32 - 14 + 1] =
358
{
359
44100, 41160, 38587, 36317, 34300, 32494, 30870, 29400, 28063, 26843,
360
25725, 24696, 23746, 22866, 22050, 21289, 20580, 19916, 19293
361
};
362
363
voices = gus->gf1.active_voices;
364
if (voices > 32)
365
voices = 32;
366
if (voices < 14)
367
voices = 14;
368
if (gus->gf1.enh_mode)
369
voices = 32;
370
gus->gf1.active_voices = voices;
371
gus->gf1.playback_freq =
372
gus->gf1.enh_mode ? 44100 : voices_tbl[voices - 14];
373
if (!gus->gf1.enh_mode) {
374
snd_gf1_i_write8(gus, SNDRV_GF1_GB_ACTIVE_VOICES, 0xc0 | (voices - 1));
375
udelay(100);
376
}
377
}
378
379