1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
|
/*
* Purpose: Definitions for the neomagic driver
*/
/*
*
* This file is part of Open Sound System.
*
* Copyright (C) 4Front Technologies 1996-2008.
*
* This this source file is released under GPL v2 license (no other versions).
* See the COPYING file included in the main directory of this source
* distribution for the license terms and conditions.
*
*/
typedef unsigned char U8;
typedef unsigned short U16;
typedef unsigned int U32;
/* The revisions that we currently handle. */
enum neomagicrev
{
REV_NEOMAGICAV, REV_NEOMAGICZX
};
#define MAX_PORTC 2
/* The two memory ports. */
typedef struct neomagic_portc
{
unsigned int physaddr; /* Physical address of the port. */
char *ptr; /* Our mapped-in pointer. */
unsigned int start_offset; /* PTR's offset within the physical port. */
unsigned int end_offset; /* And the offset of the end of the buffer. */
unsigned int samplerate;
unsigned char bits;
unsigned char stereo;
}
neomagic_portc;
typedef struct neomagic_devc
{
/* OS struct for OSS */
oss_device_t *osdev;
/* Our IRQ number. */
int irq;
/* Mutex */
oss_mutex_t mutex;
oss_mutex_t low_mutex;
/* Magic number used to verify that this struct is valid. */
#define NM_MAGIC_SIG 0x55aa00ff
int magsig;
enum neomagicrev rev; /* Revision number */
char *chip_name; /* Chip name. */
ac97_devc ac97devc;
int dev[2]; /* Our audio device numbers. */
int opencnt[2]; /* The # of times each device has been opened. */
/* We use two devices, because we can do simultaneous play and record.
This keeps track of which device is being used for what purpose;
these are the actual device numbers. */
int dev_for_play;
int dev_for_record;
int mixer_dev; /* The mixer device. */
/*
* Can only be opened once for each operation. These aren't set
* until an actual I/O operation is performed; this allows one
* device to be open for read/write without inhibiting I/O to
* the other device.
*/
int is_open_play;
int is_open_record;
int playing; /* Non-zero if we're currently playing a sample. */
int recording; /* Same for recording a sample. */
neomagic_portc portc[MAX_PORTC];
/* The following are offsets within memory port 1. */
unsigned int coeffBuf;
unsigned int allCoeffBuf;
/* Record and playback buffers. */
unsigned int abuf1, abuf2;
char *abuf1virt, *abuf2virt;
/* Offset of the mixer status register in memory port 2. */
unsigned int mixer_status_offset;
/*
* Status mask bit; (*mixer_status_loc & mixer_status_mask) == 0 means
* it's ready.
*/
unsigned short mixer_status_mask;
/* The sizes of the playback and record ring buffers. */
unsigned int playbackBufferSize;
unsigned int recordBufferSize;
/* The devc interrupt service routine. */
int (*introutine) (struct neomagic_devc *);
int mixer_cache[64];
}
neomagic_devc;
/* The BIOS signature. */
#define NM_SIGNATURE 0x4e4d0000
/* Signature mask. */
#define NM_SIG_MASK 0xffff0000
/* Size of the second memory area. */
#define NM_PORT2_SIZE 4096
/* The base offset of the mixer in the second memory area. */
#define NM_MIXER_OFFSET 0x600
/* The maximum size of a coefficient entry. */
#define NM_MAX_COEFFICIENT 0x5000
/* The interrupt register. */
#define NM_INT_REG 0xa04
/* And its bits. */
#define NM_PLAYBACK_INT 0x40
#define NM_RECORD_INT 0x100
#define NM_MISC_INT_1 0x4000
#define NM_MISC_INT_2 0x1
#define NM_ACK_INT(CARD, X) neomagic_writePort16((CARD), 2, NM_INT_REG, (X) << 1)
/* The AV's "mixer ready" status bit and location. */
#define NM_MIXER_STATUS_OFFSET 0xa06
#define NM_MIXER_READY_MASK 0x0800
#define NM_PRESENCE_MASK 0x0050
#define NM_PRESENCE_VALUE 0x0040
/*
* For the ZX. It uses the same interrupt register, but it holds 32
* bits instead of 16.
*/
#define NMZX_PLAYBACK_INT 0x10000
#define NMZX_RECORD_INT 0x80000
#define NMZX_MISC_INT_1 0x8
#define NMZX_MISC_INT_2 0x2
#define NMZX_ACK_INT(CARD, X) neomagic_writePort32((CARD), 2, NM_INT_REG, (X))
/* The ZX's "mixer ready" status bit and location. */
#define NMZX_MIXER_STATUS_OFFSET 0xa08
#define NMZX_MIXER_READY_MASK 0x0800
/* The playback registers start from here. */
#define NM_PLAYBACK_REG_OFFSET 0x0
/* The record registers start from here. */
#define NM_RECORD_REG_OFFSET 0x200
/* The rate register is located 2 bytes from the start of the register area. */
#define NM_RATE_REG_OFFSET 2
/* Mono/stereo flag, number of bits on playback, and rate mask. */
#define NM_RATE_STEREO 1
#define NM_RATE_BITS_16 2
#define NM_RATE_MASK 0xf0
/* Playback enable register. */
#define NM_PLAYBACK_ENABLE_REG (NM_PLAYBACK_REG_OFFSET + 0x1)
#define NM_PLAYBACK_ENABLE_FLAG 1
#define NM_PLAYBACK_ONESHOT 2
#define NM_PLAYBACK_FREERUN 4
/* Mutes the audio output. */
#define NM_AUDIO_MUTE_REG (NM_PLAYBACK_REG_OFFSET + 0x18)
#define NM_AUDIO_MUTE_LEFT 0x8000
#define NM_AUDIO_MUTE_RIGHT 0x0080
/* Recording enable register. */
#define NM_RECORD_ENABLE_REG (NM_RECORD_REG_OFFSET + 0)
#define NM_RECORD_ENABLE_FLAG 1
#define NM_RECORD_FREERUN 2
#define NM_RBUFFER_START (NM_RECORD_REG_OFFSET + 0x4)
#define NM_RBUFFER_END (NM_RECORD_REG_OFFSET + 0x10)
#define NM_RBUFFER_WMARK (NM_RECORD_REG_OFFSET + 0xc)
#define NM_RBUFFER_CURRP (NM_RECORD_REG_OFFSET + 0x8)
#define NM_PBUFFER_START (NM_PLAYBACK_REG_OFFSET + 0x4)
#define NM_PBUFFER_END (NM_PLAYBACK_REG_OFFSET + 0x14)
#define NM_PBUFFER_WMARK (NM_PLAYBACK_REG_OFFSET + 0xc)
#define NM_PBUFFER_CURRP (NM_PLAYBACK_REG_OFFSET + 0x8)
/* A few trivial routines to make it easier to work with the registers
on the chip. */
/* This is a common code portion used to fix up the port offsets. */
#define NM_FIX_PORT \
if (port < 1 || port > 2 || devc == NULL) \
return 0; \
\
if (offset < devc->portc[port - 1].start_offset \
|| offset >= devc->portc[port - 1].end_offset) { \
cmn_err(CE_WARN, "Bad access: port %d, offset 0x%x\n", port, offset); \
return 0; \
} \
offset -= devc->portc[port - 1].start_offset;
#define DEFwritePortX(X, func) \
static inline int neomagic_writePort##X (neomagic_devc *devc,\
int port, int offset, int value)\
{\
U##X *addr;\
\
DDB (cmn_err(CE_CONT, "Writing 0x%x to %d:0x%x\n", value, port, offset));\
\
NM_FIX_PORT;\
\
addr = (U##X *)(devc->portc[port - 1].ptr + offset);\
func (value, addr);\
return 0;\
}
static inline void
nm_writeb (unsigned char value, unsigned char *ptr)
{
*ptr = value;
}
static inline void
nm_writew (unsigned short value, unsigned short *ptr)
{
*ptr = value;
}
static inline void
nm_writel (unsigned int value, unsigned int *ptr)
{
*ptr = value;
}
DEFwritePortX (8, nm_writeb)
DEFwritePortX (16, nm_writew) DEFwritePortX (32, nm_writel)
#define DEFreadPortX(X, func) \
static inline U##X neomagic_readPort##X (neomagic_devc *devc,\
int port, int offset)\
{\
U##X *addr;\
\
NM_FIX_PORT\
\
addr = (U##X *)(devc->portc[port - 1].ptr + offset);\
return func(addr);\
}
static inline unsigned char
nm_readb (unsigned char *ptr)
{
return *ptr;
}
static inline unsigned short
nm_readw (unsigned short *ptr)
{
return *ptr;
}
static inline unsigned int
nm_readl (unsigned int *ptr)
{
return *ptr;
}
DEFreadPortX (8, nm_readb)
DEFreadPortX (16, nm_readw)
DEFreadPortX (32, nm_readl)
static inline int
neomagic_writeBuffer8 (neomagic_devc * devc, unsigned char *src,
int port, int offset, int amt)
{
NM_FIX_PORT;
memcpy (devc->portc[port - 1].ptr + offset, src, amt);
return 0;
}
#if 0
static inline int
neomagic_readBuffer8 (neomagic_devc * devc, unsigned char *dst, int port,
int offset, int amt)
{
NM_FIX_PORT;
memcpy (dst, devc->portc[port - 1].ptr + offset, amt);
return 0;
}
#endif
|