brintos

brintos / linux-shallow public Read only

0
0
Text · 8.3 KiB · af40a2c Raw
313 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Driver for Sound Core PDAudioCF soundcard4 *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 0270	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#else288	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#endif301	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