File Index
Files and directories
Sign in
FILE

pdaudiocf_irq.c

File preview with syntax highlighting.

linux-6.19.14/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c C
  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 <perex@perex.cz>
  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 */
 16irqreturn_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
 41static 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
 49static 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
 61static 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
 69static 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
 82static 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
 90static 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
102static 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
110static 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
123static 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
139static 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
155static 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
175static 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
195static 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
247irqreturn_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}
~/ Read-only file preview.