summaryrefslogtreecommitdiffstats
path: root/sound/oss/nm256.h
blob: 76233176532889cc935850fa58394a066aa45080 (plain)
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
#ifndef _NM256_H_
#define _NM256_H_

#include <linux/spinlock.h>
#include <linux/interrupt.h>

#include "ac97.h"

/* The revisions that we currently handle.  */
enum nm256rev {
    REV_NM256AV, REV_NM256ZX
};

/* Per-card structure. */
struct nm256_info 
{
    /* Magic number used to verify that this struct is valid. */
#define NM_MAGIC_SIG 0x55aa00ff
    int magsig;

    /* Revision number */
    enum nm256rev rev;

    struct ac97_hwint mdev;

    /* Our audio device numbers. */
    int dev[2];

    /* The # of times each device has been opened. (Should only be 
       0 or 1). */
    int opencnt[2];

    /* 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;

	spinlock_t lock;
	
    /* The mixer device. */
    int mixer_oss_dev;

    /* 
     * 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;

    /* Non-zero if we're currently playing a sample. */
    int playing;
    /* Ditto for recording a sample. */
    int recording;

    /* The two memory ports.  */
    struct nm256_ports {
	/* Physical address of the port. */
	u32 physaddr;
	/* Our mapped-in pointer. */
	char __iomem *ptr;
	/* PTR's offset within the physical port.  */
	u32 start_offset;
	/* And the offset of the end of the buffer.  */
	u32 end_offset;
    } port[2];

    /* The following are offsets within memory port 1. */
    u32 coeffBuf;
    u32 allCoeffBuf;

    /* Record and playback buffers. */
    u32 abuf1, abuf2;

    /* Offset of the AC97 mixer in memory port 2. */
    u32 mixer;

    /* Offset of the mixer status register in memory port 2.  */
    u32 mixer_status_offset;

    /* Non-zero if we have written initial values to the mixer. */
    u8 mixer_values_init;

    /* 
     * Status mask bit; (*mixer_status_loc & mixer_status_mask) == 0 means
     * it's ready.  
     */
    u16 mixer_status_mask;

    /* The sizes of the playback and record ring buffers. */
    u32 playbackBufferSize;
    u32 recordBufferSize;

    /* Are the coefficient values in the memory cache current? */
    u8 coeffsCurrent;

    /* For writes, the amount we last wrote. */
    u32 requested_amt;
    /* The start of the block currently playing. */
    u32 curPlayPos;

    /* The amount of data we were requested to record. */
    u32 requestedRecAmt;
    /* The offset of the currently-recording block. */
    u32 curRecPos;
    /* The destination buffer. */
    char *recBuf;

    /* Our IRQ number. */
    int irq;

    /* A flag indicating how many times we've grabbed the IRQ. */
    int has_irq;

    /* The card interrupt service routine. */
    irqreturn_t (*introutine) (int, void *, struct pt_regs *);

    /* Current audio config, cached. */
    struct sinfo {
	u32 samplerate;
	u8 bits;
	u8 stereo;
    } sinfo[2]; /* goes with each device */

    /* The cards are stored in a chain;  this is the next card. */
    struct nm256_info *next_card;
};

/* Debug flag--bigger numbers mean more output. */
extern int nm256_debug;

/* 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) nm256_writePort16((CARD), 2, NM_INT_REG, (X) << 1)

/* The AV's "mixer ready" status bit and location. */
#define NM_MIXER_STATUS_OFFSET 0xa04
#define NM_MIXER_READY_MASK 0x0800
#define NM_MIXER_PRESENCE 0xa06
#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 NM2_PLAYBACK_INT 0x10000
#define NM2_RECORD_INT 0x80000
#define NM2_MISC_INT_1 0x8
#define NM2_MISC_INT_2 0x2
#define NM2_ACK_INT(CARD, X) nm256_writePort32((CARD), 2, NM_INT_REG, (X))

/* The ZX's "mixer ready" status bit and location. */
#define NM2_MIXER_STATUS_OFFSET 0xa06
#define NM2_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 || card == NULL) \
      return -1; \
\
    if (offset < card->port[port - 1].start_offset \
	|| offset >= card->port[port - 1].end_offset) { \
	printk (KERN_ERR "Bad access: port %d, offset 0x%x\n", port, offset); \
	return -1; \
    } \
    offset -= card->port[port - 1].start_offset;

#define DEFwritePortX(X, func) \
static inline int nm256_writePort##X (struct nm256_info *card,\
				      int port, int offset, int value)\
{\
    u##X __iomem *addr;\
\
    if (nm256_debug > 1)\
        printk (KERN_DEBUG "Writing 0x%x to %d:0x%x\n", value, port, offset);\
\
    NM_FIX_PORT;\
\
    addr = (u##X __iomem *)(card->port[port - 1].ptr + offset);\
    func (value, addr);\
    return 0;\
}

DEFwritePortX (8, writeb)
DEFwritePortX (16, writew)
DEFwritePortX (32, writel)

#define DEFreadPortX(X, func) \
static inline u##X nm256_readPort##X (struct nm256_info *card,\
					int port, int offset)\
{\
    u##X __iomem *addr;\
\
    NM_FIX_PORT\
\
    addr = (u##X __iomem *)(card->port[port - 1].ptr + offset);\
    return func(addr);\
}

DEFreadPortX (8, readb)
DEFreadPortX (16, readw)
DEFreadPortX (32, readl)

static inline int
nm256_writeBuffer8 (struct nm256_info *card, u8 *src, int port, int offset,
		      int amt)
{
    NM_FIX_PORT;
    memcpy_toio (card->port[port - 1].ptr + offset, src, amt);
    return 0;
}

static inline int
nm256_readBuffer8 (struct nm256_info *card, u8 *dst, int port, int offset,
		     int amt)
{
    NM_FIX_PORT;
    memcpy_fromio (dst, card->port[port - 1].ptr + offset, amt);
    return 0;
}

/* Returns a non-zero value if we should use the coefficient cache. */
static int nm256_cachedCoefficients (struct nm256_info *card);

#endif

/*
 * Local variables:
 * c-basic-offset: 4
 * End:
 */
OpenPOWER on IntegriCloud