Path: blob/master/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
10817 views
/*1* Driver for Sound Core PDAudioCF soundcard2*3* Copyright (c) 2003 by Jaroslav Kysela <[email protected]>4*5* This program is free software; you can redistribute it and/or modify6* it under the terms of the GNU General Public License as published by7* the Free Software Foundation; either version 2 of the License, or8* (at your option) any later version.9*10* This program is distributed in the hope that it will be useful,11* but WITHOUT ANY WARRANTY; without even the implied warranty of12* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the13* GNU General Public License for more details.14*15* You should have received a copy of the GNU General Public License16* along with this program; if not, write to the Free Software17* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA18*/1920#include <sound/core.h>21#include "pdaudiocf.h"22#include <sound/initval.h>23#include <asm/irq_regs.h>2425/*26*27*/28irqreturn_t pdacf_interrupt(int irq, void *dev)29{30struct snd_pdacf *chip = dev;31unsigned short stat;3233if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|34PDAUDIOCF_STAT_IS_CONFIGURED|35PDAUDIOCF_STAT_IS_SUSPENDED)) != PDAUDIOCF_STAT_IS_CONFIGURED)36return IRQ_HANDLED; /* IRQ_NONE here? */3738stat = inw(chip->port + PDAUDIOCF_REG_ISR);39if (stat & (PDAUDIOCF_IRQLVL|PDAUDIOCF_IRQOVR)) {40if (stat & PDAUDIOCF_IRQOVR) /* should never happen */41snd_printk(KERN_ERR "PDAUDIOCF SRAM buffer overrun detected!\n");42if (chip->pcm_substream)43tasklet_schedule(&chip->tq);44if (!(stat & PDAUDIOCF_IRQAKM))45stat |= PDAUDIOCF_IRQAKM; /* check rate */46}47if (get_irq_regs() != NULL)48snd_ak4117_check_rate_and_errors(chip->ak4117, 0);49return IRQ_HANDLED;50}5152static inline void pdacf_transfer_mono16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)53{54while (size-- > 0) {55*dst++ = inw(rdp_port) ^ xor;56inw(rdp_port);57}58}5960static inline void pdacf_transfer_mono32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)61{62register u16 val1, val2;6364while (size-- > 0) {65val1 = inw(rdp_port);66val2 = inw(rdp_port);67inw(rdp_port);68*dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;69}70}7172static inline void pdacf_transfer_stereo16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)73{74while (size-- > 0) {75*dst++ = inw(rdp_port) ^ xor;76*dst++ = inw(rdp_port) ^ xor;77}78}7980static inline void pdacf_transfer_stereo32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)81{82register u16 val1, val2, val3;8384while (size-- > 0) {85val1 = inw(rdp_port);86val2 = inw(rdp_port);87val3 = inw(rdp_port);88*dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;89*dst++ = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;90}91}9293static inline void pdacf_transfer_mono16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)94{95while (size-- > 0) {96*dst++ = swab16(inw(rdp_port) ^ xor);97inw(rdp_port);98}99}100101static inline void pdacf_transfer_mono32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)102{103register u16 val1, val2;104105while (size-- > 0) {106val1 = inw(rdp_port);107val2 = inw(rdp_port);108inw(rdp_port);109*dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor);110}111}112113static inline void pdacf_transfer_stereo16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)114{115while (size-- > 0) {116*dst++ = swab16(inw(rdp_port) ^ xor);117*dst++ = swab16(inw(rdp_port) ^ xor);118}119}120121static inline void pdacf_transfer_stereo32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)122{123register u16 val1, val2, val3;124125while (size-- > 0) {126val1 = inw(rdp_port);127val2 = inw(rdp_port);128val3 = inw(rdp_port);129*dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor);130*dst++ = swab32((((u32)val3 << 16) | (val2 & 0xff00)) ^ xor);131}132}133134static inline void pdacf_transfer_mono24le(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port)135{136register u16 val1, val2;137register u32 xval1;138139while (size-- > 0) {140val1 = inw(rdp_port);141val2 = inw(rdp_port);142inw(rdp_port);143xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor;144*dst++ = (u8)(xval1 >> 8);145*dst++ = (u8)(xval1 >> 16);146*dst++ = (u8)(xval1 >> 24);147}148}149150static inline void pdacf_transfer_mono24be(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port)151{152register u16 val1, val2;153register u32 xval1;154155while (size-- > 0) {156val1 = inw(rdp_port);157val2 = inw(rdp_port);158inw(rdp_port);159xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor;160*dst++ = (u8)(xval1 >> 24);161*dst++ = (u8)(xval1 >> 16);162*dst++ = (u8)(xval1 >> 8);163}164}165166static inline void pdacf_transfer_stereo24le(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port)167{168register u16 val1, val2, val3;169register u32 xval1, xval2;170171while (size-- > 0) {172val1 = inw(rdp_port);173val2 = inw(rdp_port);174val3 = inw(rdp_port);175xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;176xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;177*dst++ = (u8)(xval1 >> 8);178*dst++ = (u8)(xval1 >> 16);179*dst++ = (u8)(xval1 >> 24);180*dst++ = (u8)(xval2 >> 8);181*dst++ = (u8)(xval2 >> 16);182*dst++ = (u8)(xval2 >> 24);183}184}185186static inline void pdacf_transfer_stereo24be(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port)187{188register u16 val1, val2, val3;189register u32 xval1, xval2;190191while (size-- > 0) {192val1 = inw(rdp_port);193val2 = inw(rdp_port);194val3 = inw(rdp_port);195xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;196xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;197*dst++ = (u8)(xval1 >> 24);198*dst++ = (u8)(xval1 >> 16);199*dst++ = (u8)(xval1 >> 8);200*dst++ = (u8)(xval2 >> 24);201*dst++ = (u8)(xval2 >> 16);202*dst++ = (u8)(xval2 >> 8);203}204}205206static void pdacf_transfer(struct snd_pdacf *chip, unsigned int size, unsigned int off)207{208unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;209unsigned int xor = chip->pcm_xor;210211if (chip->pcm_sample == 3) {212if (chip->pcm_little) {213if (chip->pcm_channels == 1) {214pdacf_transfer_mono24le((char *)chip->pcm_area + (off * 3), xor, size, rdp_port);215} else {216pdacf_transfer_stereo24le((char *)chip->pcm_area + (off * 6), xor, size, rdp_port);217}218} else {219if (chip->pcm_channels == 1) {220pdacf_transfer_mono24be((char *)chip->pcm_area + (off * 3), xor, size, rdp_port);221} else {222pdacf_transfer_stereo24be((char *)chip->pcm_area + (off * 6), xor, size, rdp_port);223}224}225return;226}227if (chip->pcm_swab == 0) {228if (chip->pcm_channels == 1) {229if (chip->pcm_frame == 2) {230pdacf_transfer_mono16((u16 *)chip->pcm_area + off, xor, size, rdp_port);231} else {232pdacf_transfer_mono32((u32 *)chip->pcm_area + off, xor, size, rdp_port);233}234} else {235if (chip->pcm_frame == 2) {236pdacf_transfer_stereo16((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port);237} else {238pdacf_transfer_stereo32((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port);239}240}241} else {242if (chip->pcm_channels == 1) {243if (chip->pcm_frame == 2) {244pdacf_transfer_mono16sw((u16 *)chip->pcm_area + off, xor, size, rdp_port);245} else {246pdacf_transfer_mono32sw((u32 *)chip->pcm_area + off, xor, size, rdp_port);247}248} else {249if (chip->pcm_frame == 2) {250pdacf_transfer_stereo16sw((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port);251} else {252pdacf_transfer_stereo32sw((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port);253}254}255}256}257258void pdacf_tasklet(unsigned long private_data)259{260struct snd_pdacf *chip = (struct snd_pdacf *) private_data;261int size, off, cont, rdp, wdp;262263if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|PDAUDIOCF_STAT_IS_CONFIGURED)) != PDAUDIOCF_STAT_IS_CONFIGURED)264return;265266if (chip->pcm_substream == NULL || chip->pcm_substream->runtime == NULL || !snd_pcm_running(chip->pcm_substream))267return;268269rdp = inw(chip->port + PDAUDIOCF_REG_RDP);270wdp = inw(chip->port + PDAUDIOCF_REG_WDP);271/* printk(KERN_DEBUG "TASKLET: rdp = %x, wdp = %x\n", rdp, wdp); */272size = wdp - rdp;273if (size < 0)274size += 0x10000;275if (size == 0)276size = 0x10000;277size /= chip->pcm_frame;278if (size > 64)279size -= 32;280281#if 0282chip->pcm_hwptr += size;283chip->pcm_hwptr %= chip->pcm_size;284chip->pcm_tdone += size;285if (chip->pcm_frame == 2) {286unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;287while (size-- > 0) {288inw(rdp_port);289inw(rdp_port);290}291} else {292unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;293while (size-- > 0) {294inw(rdp_port);295inw(rdp_port);296inw(rdp_port);297}298}299#else300off = chip->pcm_hwptr + chip->pcm_tdone;301off %= chip->pcm_size;302chip->pcm_tdone += size;303while (size > 0) {304cont = chip->pcm_size - off;305if (cont > size)306cont = size;307pdacf_transfer(chip, cont, off);308off += cont;309off %= chip->pcm_size;310size -= cont;311}312#endif313spin_lock(&chip->reg_lock);314while (chip->pcm_tdone >= chip->pcm_period) {315chip->pcm_hwptr += chip->pcm_period;316chip->pcm_hwptr %= chip->pcm_size;317chip->pcm_tdone -= chip->pcm_period;318spin_unlock(&chip->reg_lock);319snd_pcm_period_elapsed(chip->pcm_substream);320spin_lock(&chip->reg_lock);321}322spin_unlock(&chip->reg_lock);323/* printk(KERN_DEBUG "TASKLET: end\n"); */324}325326327