linux/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
<<
>>
Prefs
   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                        snd_printk(KERN_ERR "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        /* printk(KERN_DEBUG "TASKLET: rdp = %x, wdp = %x\n", rdp, wdp); */
 261        size = wdp - rdp;
 262        if (size < 0)
 263                size += 0x10000;
 264        if (size == 0)
 265                size = 0x10000;
 266        size /= chip->pcm_frame;
 267        if (size > 64)
 268                size -= 32;
 269
 270#if 0
 271        chip->pcm_hwptr += size;
 272        chip->pcm_hwptr %= chip->pcm_size;
 273        chip->pcm_tdone += size;
 274        if (chip->pcm_frame == 2) {
 275                unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
 276                while (size-- > 0) {
 277                        inw(rdp_port);
 278                        inw(rdp_port);
 279                }
 280        } else {
 281                unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
 282                while (size-- > 0) {
 283                        inw(rdp_port);
 284                        inw(rdp_port);
 285                        inw(rdp_port);
 286                }
 287        }
 288#else
 289        off = chip->pcm_hwptr + chip->pcm_tdone;
 290        off %= chip->pcm_size;
 291        chip->pcm_tdone += size;
 292        while (size > 0) {
 293                cont = chip->pcm_size - off;
 294                if (cont > size)
 295                        cont = size;
 296                pdacf_transfer(chip, cont, off);
 297                off += cont;
 298                off %= chip->pcm_size;
 299                size -= cont;
 300        }
 301#endif
 302        mutex_lock(&chip->reg_lock);
 303        while (chip->pcm_tdone >= chip->pcm_period) {
 304                chip->pcm_hwptr += chip->pcm_period;
 305                chip->pcm_hwptr %= chip->pcm_size;
 306                chip->pcm_tdone -= chip->pcm_period;
 307                mutex_unlock(&chip->reg_lock);
 308                snd_pcm_period_elapsed(chip->pcm_substream);
 309                mutex_lock(&chip->reg_lock);
 310        }
 311        mutex_unlock(&chip->reg_lock);
 312        return IRQ_HANDLED;
 313}
 314