Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
26427 views
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
* Driver for Sound Core PDAudioCF soundcard
4
*
5
* Copyright (c) 2003 by Jaroslav Kysela <[email protected]>
6
*/
7
8
#include <sound/core.h>
9
#include "pdaudiocf.h"
10
#include <sound/initval.h>
11
#include <asm/irq_regs.h>
12
13
/*
14
*
15
*/
16
irqreturn_t pdacf_interrupt(int irq, void *dev)
17
{
18
struct snd_pdacf *chip = dev;
19
unsigned short stat;
20
bool wake_thread = false;
21
22
if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|
23
PDAUDIOCF_STAT_IS_CONFIGURED|
24
PDAUDIOCF_STAT_IS_SUSPENDED)) != PDAUDIOCF_STAT_IS_CONFIGURED)
25
return IRQ_HANDLED; /* IRQ_NONE here? */
26
27
stat = inw(chip->port + PDAUDIOCF_REG_ISR);
28
if (stat & (PDAUDIOCF_IRQLVL|PDAUDIOCF_IRQOVR)) {
29
if (stat & PDAUDIOCF_IRQOVR) /* should never happen */
30
dev_err(chip->card->dev, "PDAUDIOCF SRAM buffer overrun detected!\n");
31
if (chip->pcm_substream)
32
wake_thread = true;
33
if (!(stat & PDAUDIOCF_IRQAKM))
34
stat |= PDAUDIOCF_IRQAKM; /* check rate */
35
}
36
if (get_irq_regs() != NULL)
37
snd_ak4117_check_rate_and_errors(chip->ak4117, 0);
38
return wake_thread ? IRQ_WAKE_THREAD : IRQ_HANDLED;
39
}
40
41
static inline void pdacf_transfer_mono16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
42
{
43
while (size-- > 0) {
44
*dst++ = inw(rdp_port) ^ xor;
45
inw(rdp_port);
46
}
47
}
48
49
static inline void pdacf_transfer_mono32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
50
{
51
register u16 val1, val2;
52
53
while (size-- > 0) {
54
val1 = inw(rdp_port);
55
val2 = inw(rdp_port);
56
inw(rdp_port);
57
*dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
58
}
59
}
60
61
static inline void pdacf_transfer_stereo16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
62
{
63
while (size-- > 0) {
64
*dst++ = inw(rdp_port) ^ xor;
65
*dst++ = inw(rdp_port) ^ xor;
66
}
67
}
68
69
static inline void pdacf_transfer_stereo32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
70
{
71
register u16 val1, val2, val3;
72
73
while (size-- > 0) {
74
val1 = inw(rdp_port);
75
val2 = inw(rdp_port);
76
val3 = inw(rdp_port);
77
*dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
78
*dst++ = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
79
}
80
}
81
82
static inline void pdacf_transfer_mono16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
83
{
84
while (size-- > 0) {
85
*dst++ = swab16(inw(rdp_port) ^ xor);
86
inw(rdp_port);
87
}
88
}
89
90
static inline void pdacf_transfer_mono32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
91
{
92
register u16 val1, val2;
93
94
while (size-- > 0) {
95
val1 = inw(rdp_port);
96
val2 = inw(rdp_port);
97
inw(rdp_port);
98
*dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor);
99
}
100
}
101
102
static inline void pdacf_transfer_stereo16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
103
{
104
while (size-- > 0) {
105
*dst++ = swab16(inw(rdp_port) ^ xor);
106
*dst++ = swab16(inw(rdp_port) ^ xor);
107
}
108
}
109
110
static inline void pdacf_transfer_stereo32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
111
{
112
register u16 val1, val2, val3;
113
114
while (size-- > 0) {
115
val1 = inw(rdp_port);
116
val2 = inw(rdp_port);
117
val3 = inw(rdp_port);
118
*dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor);
119
*dst++ = swab32((((u32)val3 << 16) | (val2 & 0xff00)) ^ xor);
120
}
121
}
122
123
static inline void pdacf_transfer_mono24le(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
124
{
125
register u16 val1, val2;
126
register u32 xval1;
127
128
while (size-- > 0) {
129
val1 = inw(rdp_port);
130
val2 = inw(rdp_port);
131
inw(rdp_port);
132
xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor;
133
*dst++ = (u8)(xval1 >> 8);
134
*dst++ = (u8)(xval1 >> 16);
135
*dst++ = (u8)(xval1 >> 24);
136
}
137
}
138
139
static inline void pdacf_transfer_mono24be(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
140
{
141
register u16 val1, val2;
142
register u32 xval1;
143
144
while (size-- > 0) {
145
val1 = inw(rdp_port);
146
val2 = inw(rdp_port);
147
inw(rdp_port);
148
xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor;
149
*dst++ = (u8)(xval1 >> 24);
150
*dst++ = (u8)(xval1 >> 16);
151
*dst++ = (u8)(xval1 >> 8);
152
}
153
}
154
155
static inline void pdacf_transfer_stereo24le(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
156
{
157
register u16 val1, val2, val3;
158
register u32 xval1, xval2;
159
160
while (size-- > 0) {
161
val1 = inw(rdp_port);
162
val2 = inw(rdp_port);
163
val3 = inw(rdp_port);
164
xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
165
xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
166
*dst++ = (u8)(xval1 >> 8);
167
*dst++ = (u8)(xval1 >> 16);
168
*dst++ = (u8)(xval1 >> 24);
169
*dst++ = (u8)(xval2 >> 8);
170
*dst++ = (u8)(xval2 >> 16);
171
*dst++ = (u8)(xval2 >> 24);
172
}
173
}
174
175
static inline void pdacf_transfer_stereo24be(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
176
{
177
register u16 val1, val2, val3;
178
register u32 xval1, xval2;
179
180
while (size-- > 0) {
181
val1 = inw(rdp_port);
182
val2 = inw(rdp_port);
183
val3 = inw(rdp_port);
184
xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
185
xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
186
*dst++ = (u8)(xval1 >> 24);
187
*dst++ = (u8)(xval1 >> 16);
188
*dst++ = (u8)(xval1 >> 8);
189
*dst++ = (u8)(xval2 >> 24);
190
*dst++ = (u8)(xval2 >> 16);
191
*dst++ = (u8)(xval2 >> 8);
192
}
193
}
194
195
static void pdacf_transfer(struct snd_pdacf *chip, unsigned int size, unsigned int off)
196
{
197
unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
198
unsigned int xor = chip->pcm_xor;
199
200
if (chip->pcm_sample == 3) {
201
if (chip->pcm_little) {
202
if (chip->pcm_channels == 1) {
203
pdacf_transfer_mono24le((char *)chip->pcm_area + (off * 3), xor, size, rdp_port);
204
} else {
205
pdacf_transfer_stereo24le((char *)chip->pcm_area + (off * 6), xor, size, rdp_port);
206
}
207
} else {
208
if (chip->pcm_channels == 1) {
209
pdacf_transfer_mono24be((char *)chip->pcm_area + (off * 3), xor, size, rdp_port);
210
} else {
211
pdacf_transfer_stereo24be((char *)chip->pcm_area + (off * 6), xor, size, rdp_port);
212
}
213
}
214
return;
215
}
216
if (chip->pcm_swab == 0) {
217
if (chip->pcm_channels == 1) {
218
if (chip->pcm_frame == 2) {
219
pdacf_transfer_mono16((u16 *)chip->pcm_area + off, xor, size, rdp_port);
220
} else {
221
pdacf_transfer_mono32((u32 *)chip->pcm_area + off, xor, size, rdp_port);
222
}
223
} else {
224
if (chip->pcm_frame == 2) {
225
pdacf_transfer_stereo16((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
226
} else {
227
pdacf_transfer_stereo32((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
228
}
229
}
230
} else {
231
if (chip->pcm_channels == 1) {
232
if (chip->pcm_frame == 2) {
233
pdacf_transfer_mono16sw((u16 *)chip->pcm_area + off, xor, size, rdp_port);
234
} else {
235
pdacf_transfer_mono32sw((u32 *)chip->pcm_area + off, xor, size, rdp_port);
236
}
237
} else {
238
if (chip->pcm_frame == 2) {
239
pdacf_transfer_stereo16sw((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
240
} else {
241
pdacf_transfer_stereo32sw((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
242
}
243
}
244
}
245
}
246
247
irqreturn_t pdacf_threaded_irq(int irq, void *dev)
248
{
249
struct snd_pdacf *chip = dev;
250
int size, off, cont, rdp, wdp;
251
252
if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|PDAUDIOCF_STAT_IS_CONFIGURED)) != PDAUDIOCF_STAT_IS_CONFIGURED)
253
return IRQ_HANDLED;
254
255
if (chip->pcm_substream == NULL || chip->pcm_substream->runtime == NULL || !snd_pcm_running(chip->pcm_substream))
256
return IRQ_HANDLED;
257
258
rdp = inw(chip->port + PDAUDIOCF_REG_RDP);
259
wdp = inw(chip->port + PDAUDIOCF_REG_WDP);
260
size = wdp - rdp;
261
if (size < 0)
262
size += 0x10000;
263
if (size == 0)
264
size = 0x10000;
265
size /= chip->pcm_frame;
266
if (size > 64)
267
size -= 32;
268
269
#if 0
270
chip->pcm_hwptr += size;
271
chip->pcm_hwptr %= chip->pcm_size;
272
chip->pcm_tdone += size;
273
if (chip->pcm_frame == 2) {
274
unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
275
while (size-- > 0) {
276
inw(rdp_port);
277
inw(rdp_port);
278
}
279
} else {
280
unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
281
while (size-- > 0) {
282
inw(rdp_port);
283
inw(rdp_port);
284
inw(rdp_port);
285
}
286
}
287
#else
288
off = chip->pcm_hwptr + chip->pcm_tdone;
289
off %= chip->pcm_size;
290
chip->pcm_tdone += size;
291
while (size > 0) {
292
cont = chip->pcm_size - off;
293
if (cont > size)
294
cont = size;
295
pdacf_transfer(chip, cont, off);
296
off += cont;
297
off %= chip->pcm_size;
298
size -= cont;
299
}
300
#endif
301
mutex_lock(&chip->reg_lock);
302
while (chip->pcm_tdone >= chip->pcm_period) {
303
chip->pcm_hwptr += chip->pcm_period;
304
chip->pcm_hwptr %= chip->pcm_size;
305
chip->pcm_tdone -= chip->pcm_period;
306
mutex_unlock(&chip->reg_lock);
307
snd_pcm_period_elapsed(chip->pcm_substream);
308
mutex_lock(&chip->reg_lock);
309
}
310
mutex_unlock(&chip->reg_lock);
311
return IRQ_HANDLED;
312
}
313
314