linux/sound/pcmcia/pdaudiocf/pdaudiocf_irq.c
<<
>>
Prefs
   1/*
   2 * Driver for Sound Core PDAudioCF soundcard
   3 *
   4 * Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz>
   5 *
   6 *   This program is free software; you can redistribute it and/or modify
   7 *   it under the terms of the GNU General Public License as published by
   8 *   the Free Software Foundation; either version 2 of the License, or
   9 *   (at your option) any later version.
  10 *
  11 *   This program is distributed in the hope that it will be useful,
  12 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14 *   GNU General Public License for more details.
  15 *
  16 *   You should have received a copy of the GNU General Public License
  17 *   along with this program; if not, write to the Free Software
  18 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  19 */
  20
  21#include <sound/core.h>
  22#include "pdaudiocf.h"
  23#include <sound/initval.h>
  24#include <asm/irq_regs.h>
  25
  26/*
  27 *
  28 */
  29irqreturn_t pdacf_interrupt(int irq, void *dev)
  30{
  31        struct snd_pdacf *chip = dev;
  32        unsigned short stat;
  33        bool wake_thread = false;
  34
  35        if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|
  36                                  PDAUDIOCF_STAT_IS_CONFIGURED|
  37                                  PDAUDIOCF_STAT_IS_SUSPENDED)) != PDAUDIOCF_STAT_IS_CONFIGURED)
  38                return IRQ_HANDLED;     /* IRQ_NONE here? */
  39
  40        stat = inw(chip->port + PDAUDIOCF_REG_ISR);
  41        if (stat & (PDAUDIOCF_IRQLVL|PDAUDIOCF_IRQOVR)) {
  42                if (stat & PDAUDIOCF_IRQOVR)    /* should never happen */
  43                        snd_printk(KERN_ERR "PDAUDIOCF SRAM buffer overrun detected!\n");
  44                if (chip->pcm_substream)
  45                        wake_thread = true;
  46                if (!(stat & PDAUDIOCF_IRQAKM))
  47                        stat |= PDAUDIOCF_IRQAKM;       /* check rate */
  48        }
  49        if (get_irq_regs() != NULL)
  50                snd_ak4117_check_rate_and_errors(chip->ak4117, 0);
  51        return wake_thread ? IRQ_WAKE_THREAD : IRQ_HANDLED;
  52}
  53
  54static inline void pdacf_transfer_mono16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
  55{
  56        while (size-- > 0) {
  57                *dst++ = inw(rdp_port) ^ xor;
  58                inw(rdp_port);
  59        }
  60}
  61
  62static inline void pdacf_transfer_mono32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
  63{
  64        register u16 val1, val2;
  65
  66        while (size-- > 0) {
  67                val1 = inw(rdp_port);
  68                val2 = inw(rdp_port);
  69                inw(rdp_port);
  70                *dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
  71        }
  72}
  73
  74static inline void pdacf_transfer_stereo16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
  75{
  76        while (size-- > 0) {
  77                *dst++ = inw(rdp_port) ^ xor;
  78                *dst++ = inw(rdp_port) ^ xor;
  79        }
  80}
  81
  82static inline void pdacf_transfer_stereo32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
  83{
  84        register u16 val1, val2, val3;
  85
  86        while (size-- > 0) {
  87                val1 = inw(rdp_port);
  88                val2 = inw(rdp_port);
  89                val3 = inw(rdp_port);
  90                *dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
  91                *dst++ = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
  92        }
  93}
  94
  95static inline void pdacf_transfer_mono16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
  96{
  97        while (size-- > 0) {
  98                *dst++ = swab16(inw(rdp_port) ^ xor);
  99                inw(rdp_port);
 100        }
 101}
 102
 103static inline void pdacf_transfer_mono32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
 104{
 105        register u16 val1, val2;
 106
 107        while (size-- > 0) {
 108                val1 = inw(rdp_port);
 109                val2 = inw(rdp_port);
 110                inw(rdp_port);
 111                *dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor);
 112        }
 113}
 114
 115static inline void pdacf_transfer_stereo16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
 116{
 117        while (size-- > 0) {
 118                *dst++ = swab16(inw(rdp_port) ^ xor);
 119                *dst++ = swab16(inw(rdp_port) ^ xor);
 120        }
 121}
 122
 123static inline void pdacf_transfer_stereo32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
 124{
 125        register u16 val1, val2, val3;
 126
 127        while (size-- > 0) {
 128                val1 = inw(rdp_port);
 129                val2 = inw(rdp_port);
 130                val3 = inw(rdp_port);
 131                *dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor);
 132                *dst++ = swab32((((u32)val3 << 16) | (val2 & 0xff00)) ^ xor);
 133        }
 134}
 135
 136static inline void pdacf_transfer_mono24le(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
 137{
 138        register u16 val1, val2;
 139        register u32 xval1;
 140
 141        while (size-- > 0) {
 142                val1 = inw(rdp_port);
 143                val2 = inw(rdp_port);
 144                inw(rdp_port);
 145                xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor;
 146                *dst++ = (u8)(xval1 >> 8);
 147                *dst++ = (u8)(xval1 >> 16);
 148                *dst++ = (u8)(xval1 >> 24);
 149        }
 150}
 151
 152static inline void pdacf_transfer_mono24be(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
 153{
 154        register u16 val1, val2;
 155        register u32 xval1;
 156
 157        while (size-- > 0) {
 158                val1 = inw(rdp_port);
 159                val2 = inw(rdp_port);
 160                inw(rdp_port);
 161                xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor;
 162                *dst++ = (u8)(xval1 >> 24);
 163                *dst++ = (u8)(xval1 >> 16);
 164                *dst++ = (u8)(xval1 >> 8);
 165        }
 166}
 167
 168static inline void pdacf_transfer_stereo24le(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
 169{
 170        register u16 val1, val2, val3;
 171        register u32 xval1, xval2;
 172
 173        while (size-- > 0) {
 174                val1 = inw(rdp_port);
 175                val2 = inw(rdp_port);
 176                val3 = inw(rdp_port);
 177                xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
 178                xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
 179                *dst++ = (u8)(xval1 >> 8);
 180                *dst++ = (u8)(xval1 >> 16);
 181                *dst++ = (u8)(xval1 >> 24);
 182                *dst++ = (u8)(xval2 >> 8);
 183                *dst++ = (u8)(xval2 >> 16);
 184                *dst++ = (u8)(xval2 >> 24);
 185        }
 186}
 187
 188static inline void pdacf_transfer_stereo24be(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
 189{
 190        register u16 val1, val2, val3;
 191        register u32 xval1, xval2;
 192
 193        while (size-- > 0) {
 194                val1 = inw(rdp_port);
 195                val2 = inw(rdp_port);
 196                val3 = inw(rdp_port);
 197                xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
 198                xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
 199                *dst++ = (u8)(xval1 >> 24);
 200                *dst++ = (u8)(xval1 >> 16);
 201                *dst++ = (u8)(xval1 >> 8);
 202                *dst++ = (u8)(xval2 >> 24);
 203                *dst++ = (u8)(xval2 >> 16);
 204                *dst++ = (u8)(xval2 >> 8);
 205        }
 206}
 207
 208static void pdacf_transfer(struct snd_pdacf *chip, unsigned int size, unsigned int off)
 209{
 210        unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
 211        unsigned int xor = chip->pcm_xor;
 212
 213        if (chip->pcm_sample == 3) {
 214                if (chip->pcm_little) {
 215                        if (chip->pcm_channels == 1) {
 216                                pdacf_transfer_mono24le((char *)chip->pcm_area + (off * 3), xor, size, rdp_port);
 217                        } else {
 218                                pdacf_transfer_stereo24le((char *)chip->pcm_area + (off * 6), xor, size, rdp_port);
 219                        }
 220                } else {
 221                        if (chip->pcm_channels == 1) {
 222                                pdacf_transfer_mono24be((char *)chip->pcm_area + (off * 3), xor, size, rdp_port);
 223                        } else {
 224                                pdacf_transfer_stereo24be((char *)chip->pcm_area + (off * 6), xor, size, rdp_port);
 225                        }                       
 226                }
 227                return;
 228        }
 229        if (chip->pcm_swab == 0) {
 230                if (chip->pcm_channels == 1) {
 231                        if (chip->pcm_frame == 2) {
 232                                pdacf_transfer_mono16((u16 *)chip->pcm_area + off, xor, size, rdp_port);
 233                        } else {
 234                                pdacf_transfer_mono32((u32 *)chip->pcm_area + off, xor, size, rdp_port);
 235                        }
 236                } else {
 237                        if (chip->pcm_frame == 2) {
 238                                pdacf_transfer_stereo16((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
 239                        } else {
 240                                pdacf_transfer_stereo32((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
 241                        }
 242                }
 243        } else {
 244                if (chip->pcm_channels == 1) {
 245                        if (chip->pcm_frame == 2) {
 246                                pdacf_transfer_mono16sw((u16 *)chip->pcm_area + off, xor, size, rdp_port);
 247                        } else {
 248                                pdacf_transfer_mono32sw((u32 *)chip->pcm_area + off, xor, size, rdp_port);
 249                        }
 250                } else {
 251                        if (chip->pcm_frame == 2) {
 252                                pdacf_transfer_stereo16sw((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
 253                        } else {
 254                                pdacf_transfer_stereo32sw((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
 255                        }
 256                }
 257        }
 258}
 259
 260irqreturn_t pdacf_threaded_irq(int irq, void *dev)
 261{
 262        struct snd_pdacf *chip = dev;
 263        int size, off, cont, rdp, wdp;
 264
 265        if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|PDAUDIOCF_STAT_IS_CONFIGURED)) != PDAUDIOCF_STAT_IS_CONFIGURED)
 266                return IRQ_HANDLED;
 267        
 268        if (chip->pcm_substream == NULL || chip->pcm_substream->runtime == NULL || !snd_pcm_running(chip->pcm_substream))
 269                return IRQ_HANDLED;
 270
 271        rdp = inw(chip->port + PDAUDIOCF_REG_RDP);
 272        wdp = inw(chip->port + PDAUDIOCF_REG_WDP);
 273        /* printk(KERN_DEBUG "TASKLET: rdp = %x, wdp = %x\n", rdp, wdp); */
 274        size = wdp - rdp;
 275        if (size < 0)
 276                size += 0x10000;
 277        if (size == 0)
 278                size = 0x10000;
 279        size /= chip->pcm_frame;
 280        if (size > 64)
 281                size -= 32;
 282
 283#if 0
 284        chip->pcm_hwptr += size;
 285        chip->pcm_hwptr %= chip->pcm_size;
 286        chip->pcm_tdone += size;
 287        if (chip->pcm_frame == 2) {
 288                unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
 289                while (size-- > 0) {
 290                        inw(rdp_port);
 291                        inw(rdp_port);
 292                }
 293        } else {
 294                unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
 295                while (size-- > 0) {
 296                        inw(rdp_port);
 297                        inw(rdp_port);
 298                        inw(rdp_port);
 299                }
 300        }
 301#else
 302        off = chip->pcm_hwptr + chip->pcm_tdone;
 303        off %= chip->pcm_size;
 304        chip->pcm_tdone += size;
 305        while (size > 0) {
 306                cont = chip->pcm_size - off;
 307                if (cont > size)
 308                        cont = size;
 309                pdacf_transfer(chip, cont, off);
 310                off += cont;
 311                off %= chip->pcm_size;
 312                size -= cont;
 313        }
 314#endif
 315        mutex_lock(&chip->reg_lock);
 316        while (chip->pcm_tdone >= chip->pcm_period) {
 317                chip->pcm_hwptr += chip->pcm_period;
 318                chip->pcm_hwptr %= chip->pcm_size;
 319                chip->pcm_tdone -= chip->pcm_period;
 320                mutex_unlock(&chip->reg_lock);
 321                snd_pcm_period_elapsed(chip->pcm_substream);
 322                mutex_lock(&chip->reg_lock);
 323        }
 324        mutex_unlock(&chip->reg_lock);
 325        return IRQ_HANDLED;
 326}
 327