Path: blob/master/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
26427 views
// SPDX-License-Identifier: GPL-2.0-or-later1/*2* Driver for Sound Core PDAudioCF soundcard3*4* Copyright (c) 2003 by Jaroslav Kysela <[email protected]>5*/67#include <sound/core.h>8#include "pdaudiocf.h"9#include <sound/initval.h>10#include <asm/irq_regs.h>1112/*13*14*/15irqreturn_t pdacf_interrupt(int irq, void *dev)16{17struct snd_pdacf *chip = dev;18unsigned short stat;19bool wake_thread = false;2021if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|22PDAUDIOCF_STAT_IS_CONFIGURED|23PDAUDIOCF_STAT_IS_SUSPENDED)) != PDAUDIOCF_STAT_IS_CONFIGURED)24return IRQ_HANDLED; /* IRQ_NONE here? */2526stat = inw(chip->port + PDAUDIOCF_REG_ISR);27if (stat & (PDAUDIOCF_IRQLVL|PDAUDIOCF_IRQOVR)) {28if (stat & PDAUDIOCF_IRQOVR) /* should never happen */29dev_err(chip->card->dev, "PDAUDIOCF SRAM buffer overrun detected!\n");30if (chip->pcm_substream)31wake_thread = true;32if (!(stat & PDAUDIOCF_IRQAKM))33stat |= PDAUDIOCF_IRQAKM; /* check rate */34}35if (get_irq_regs() != NULL)36snd_ak4117_check_rate_and_errors(chip->ak4117, 0);37return wake_thread ? IRQ_WAKE_THREAD : IRQ_HANDLED;38}3940static inline void pdacf_transfer_mono16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)41{42while (size-- > 0) {43*dst++ = inw(rdp_port) ^ xor;44inw(rdp_port);45}46}4748static inline void pdacf_transfer_mono32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)49{50register u16 val1, val2;5152while (size-- > 0) {53val1 = inw(rdp_port);54val2 = inw(rdp_port);55inw(rdp_port);56*dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;57}58}5960static inline void pdacf_transfer_stereo16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)61{62while (size-- > 0) {63*dst++ = inw(rdp_port) ^ xor;64*dst++ = inw(rdp_port) ^ xor;65}66}6768static inline void pdacf_transfer_stereo32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)69{70register u16 val1, val2, val3;7172while (size-- > 0) {73val1 = inw(rdp_port);74val2 = inw(rdp_port);75val3 = inw(rdp_port);76*dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;77*dst++ = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;78}79}8081static inline void pdacf_transfer_mono16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)82{83while (size-- > 0) {84*dst++ = swab16(inw(rdp_port) ^ xor);85inw(rdp_port);86}87}8889static inline void pdacf_transfer_mono32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)90{91register u16 val1, val2;9293while (size-- > 0) {94val1 = inw(rdp_port);95val2 = inw(rdp_port);96inw(rdp_port);97*dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor);98}99}100101static inline void pdacf_transfer_stereo16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)102{103while (size-- > 0) {104*dst++ = swab16(inw(rdp_port) ^ xor);105*dst++ = swab16(inw(rdp_port) ^ xor);106}107}108109static inline void pdacf_transfer_stereo32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)110{111register u16 val1, val2, val3;112113while (size-- > 0) {114val1 = inw(rdp_port);115val2 = inw(rdp_port);116val3 = inw(rdp_port);117*dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor);118*dst++ = swab32((((u32)val3 << 16) | (val2 & 0xff00)) ^ xor);119}120}121122static inline void pdacf_transfer_mono24le(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port)123{124register u16 val1, val2;125register u32 xval1;126127while (size-- > 0) {128val1 = inw(rdp_port);129val2 = inw(rdp_port);130inw(rdp_port);131xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor;132*dst++ = (u8)(xval1 >> 8);133*dst++ = (u8)(xval1 >> 16);134*dst++ = (u8)(xval1 >> 24);135}136}137138static inline void pdacf_transfer_mono24be(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port)139{140register u16 val1, val2;141register u32 xval1;142143while (size-- > 0) {144val1 = inw(rdp_port);145val2 = inw(rdp_port);146inw(rdp_port);147xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor;148*dst++ = (u8)(xval1 >> 24);149*dst++ = (u8)(xval1 >> 16);150*dst++ = (u8)(xval1 >> 8);151}152}153154static inline void pdacf_transfer_stereo24le(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port)155{156register u16 val1, val2, val3;157register u32 xval1, xval2;158159while (size-- > 0) {160val1 = inw(rdp_port);161val2 = inw(rdp_port);162val3 = inw(rdp_port);163xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;164xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;165*dst++ = (u8)(xval1 >> 8);166*dst++ = (u8)(xval1 >> 16);167*dst++ = (u8)(xval1 >> 24);168*dst++ = (u8)(xval2 >> 8);169*dst++ = (u8)(xval2 >> 16);170*dst++ = (u8)(xval2 >> 24);171}172}173174static inline void pdacf_transfer_stereo24be(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port)175{176register u16 val1, val2, val3;177register u32 xval1, xval2;178179while (size-- > 0) {180val1 = inw(rdp_port);181val2 = inw(rdp_port);182val3 = inw(rdp_port);183xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;184xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;185*dst++ = (u8)(xval1 >> 24);186*dst++ = (u8)(xval1 >> 16);187*dst++ = (u8)(xval1 >> 8);188*dst++ = (u8)(xval2 >> 24);189*dst++ = (u8)(xval2 >> 16);190*dst++ = (u8)(xval2 >> 8);191}192}193194static void pdacf_transfer(struct snd_pdacf *chip, unsigned int size, unsigned int off)195{196unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;197unsigned int xor = chip->pcm_xor;198199if (chip->pcm_sample == 3) {200if (chip->pcm_little) {201if (chip->pcm_channels == 1) {202pdacf_transfer_mono24le((char *)chip->pcm_area + (off * 3), xor, size, rdp_port);203} else {204pdacf_transfer_stereo24le((char *)chip->pcm_area + (off * 6), xor, size, rdp_port);205}206} else {207if (chip->pcm_channels == 1) {208pdacf_transfer_mono24be((char *)chip->pcm_area + (off * 3), xor, size, rdp_port);209} else {210pdacf_transfer_stereo24be((char *)chip->pcm_area + (off * 6), xor, size, rdp_port);211}212}213return;214}215if (chip->pcm_swab == 0) {216if (chip->pcm_channels == 1) {217if (chip->pcm_frame == 2) {218pdacf_transfer_mono16((u16 *)chip->pcm_area + off, xor, size, rdp_port);219} else {220pdacf_transfer_mono32((u32 *)chip->pcm_area + off, xor, size, rdp_port);221}222} else {223if (chip->pcm_frame == 2) {224pdacf_transfer_stereo16((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port);225} else {226pdacf_transfer_stereo32((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port);227}228}229} else {230if (chip->pcm_channels == 1) {231if (chip->pcm_frame == 2) {232pdacf_transfer_mono16sw((u16 *)chip->pcm_area + off, xor, size, rdp_port);233} else {234pdacf_transfer_mono32sw((u32 *)chip->pcm_area + off, xor, size, rdp_port);235}236} else {237if (chip->pcm_frame == 2) {238pdacf_transfer_stereo16sw((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port);239} else {240pdacf_transfer_stereo32sw((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port);241}242}243}244}245246irqreturn_t pdacf_threaded_irq(int irq, void *dev)247{248struct snd_pdacf *chip = dev;249int size, off, cont, rdp, wdp;250251if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|PDAUDIOCF_STAT_IS_CONFIGURED)) != PDAUDIOCF_STAT_IS_CONFIGURED)252return IRQ_HANDLED;253254if (chip->pcm_substream == NULL || chip->pcm_substream->runtime == NULL || !snd_pcm_running(chip->pcm_substream))255return IRQ_HANDLED;256257rdp = inw(chip->port + PDAUDIOCF_REG_RDP);258wdp = inw(chip->port + PDAUDIOCF_REG_WDP);259size = wdp - rdp;260if (size < 0)261size += 0x10000;262if (size == 0)263size = 0x10000;264size /= chip->pcm_frame;265if (size > 64)266size -= 32;267268#if 0269chip->pcm_hwptr += size;270chip->pcm_hwptr %= chip->pcm_size;271chip->pcm_tdone += size;272if (chip->pcm_frame == 2) {273unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;274while (size-- > 0) {275inw(rdp_port);276inw(rdp_port);277}278} else {279unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;280while (size-- > 0) {281inw(rdp_port);282inw(rdp_port);283inw(rdp_port);284}285}286#else287off = chip->pcm_hwptr + chip->pcm_tdone;288off %= chip->pcm_size;289chip->pcm_tdone += size;290while (size > 0) {291cont = chip->pcm_size - off;292if (cont > size)293cont = size;294pdacf_transfer(chip, cont, off);295off += cont;296off %= chip->pcm_size;297size -= cont;298}299#endif300mutex_lock(&chip->reg_lock);301while (chip->pcm_tdone >= chip->pcm_period) {302chip->pcm_hwptr += chip->pcm_period;303chip->pcm_hwptr %= chip->pcm_size;304chip->pcm_tdone -= chip->pcm_period;305mutex_unlock(&chip->reg_lock);306snd_pcm_period_elapsed(chip->pcm_substream);307mutex_lock(&chip->reg_lock);308}309mutex_unlock(&chip->reg_lock);310return IRQ_HANDLED;311}312313314