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
  34        if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|
  35                                  PDAUDIOCF_STAT_IS_CONFIGURED|
  36                                  PDAUDIOCF_STAT_IS_SUSPENDED)) != PDAUDIOCF_STAT_IS_CONFIGURED)
  37                return IRQ_HANDLED;     /* IRQ_NONE here? */
  38
  39        stat = inw(chip->port + PDAUDIOCF_REG_ISR);
  40        if (stat & (PDAUDIOCF_IRQLVL|PDAUDIOCF_IRQOVR)) {
  41                if (stat & PDAUDIOCF_IRQOVR)    /* should never happen */
  42                        snd_printk(KERN_ERR "PDAUDIOCF SRAM buffer overrun detected!\n");
  43                if (chip->pcm_substream)
  44                        tasklet_schedule(&chip->tq);
  45                if (!(stat & PDAUDIOCF_IRQAKM))
  46                        stat |= PDAUDIOCF_IRQAKM;       /* check rate */
  47        }
  48        if (get_irq_regs() != NULL)
  49                snd_ak4117_check_rate_and_errors(chip->ak4117, 0);
  50        return IRQ_HANDLED;
  51}
  52
  53static inline void pdacf_transfer_mono16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
  54{
  55        while (size-- > 0) {
  56                *dst++ = inw(rdp_port) ^ xor;
  57                inw(rdp_port);
  58        }
  59}
  60
  61static inline void pdacf_transfer_mono32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
  62{
  63        register u16 val1, val2;
  64
  65        while (size-- > 0) {
  66                val1 = inw(rdp_port);
  67                val2 = inw(rdp_port);
  68                inw(rdp_port);
  69                *dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
  70        }
  71}
  72
  73static inline void pdacf_transfer_stereo16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
  74{
  75        while (size-- > 0) {
  76                *dst++ = inw(rdp_port) ^ xor;
  77                *dst++ = inw(rdp_port) ^ xor;
  78        }
  79}
  80
  81static inline void pdacf_transfer_stereo32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
  82{
  83        register u16 val1, val2, val3;
  84
  85        while (size-- > 0) {
  86                val1 = inw(rdp_port);
  87                val2 = inw(rdp_port);
  88                val3 = inw(rdp_port);
  89                *dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
  90                *dst++ = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
  91        }
  92}
  93
  94static inline void pdacf_transfer_mono16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
  95{
  96        while (size-- > 0) {
  97                *dst++ = swab16(inw(rdp_port) ^ xor);
  98                inw(rdp_port);
  99        }
 100}
 101
 102static inline void pdacf_transfer_mono32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
 103{
 104        register u16 val1, val2;
 105
 106        while (size-- > 0) {
 107                val1 = inw(rdp_port);
 108                val2 = inw(rdp_port);
 109                inw(rdp_port);
 110                *dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor);
 111        }
 112}
 113
 114static inline void pdacf_transfer_stereo16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
 115{
 116        while (size-- > 0) {
 117                *dst++ = swab16(inw(rdp_port) ^ xor);
 118                *dst++ = swab16(inw(rdp_port) ^ xor);
 119        }
 120}
 121
 122static inline void pdacf_transfer_stereo32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
 123{
 124        register u16 val1, val2, val3;
 125
 126        while (size-- > 0) {
 127                val1 = inw(rdp_port);
 128                val2 = inw(rdp_port);
 129                val3 = inw(rdp_port);
 130                *dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor);
 131                *dst++ = swab32((((u32)val3 << 16) | (val2 & 0xff00)) ^ xor);
 132        }
 133}
 134
 135static inline void pdacf_transfer_mono24le(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
 136{
 137        register u16 val1, val2;
 138        register u32 xval1;
 139
 140        while (size-- > 0) {
 141                val1 = inw(rdp_port);
 142                val2 = inw(rdp_port);
 143                inw(rdp_port);
 144                xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor;
 145                *dst++ = (u8)(xval1 >> 8);
 146                *dst++ = (u8)(xval1 >> 16);
 147                *dst++ = (u8)(xval1 >> 24);
 148        }
 149}
 150
 151static inline void pdacf_transfer_mono24be(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
 152{
 153        register u16 val1, val2;
 154        register u32 xval1;
 155
 156        while (size-- > 0) {
 157                val1 = inw(rdp_port);
 158                val2 = inw(rdp_port);
 159                inw(rdp_port);
 160                xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor;
 161                *dst++ = (u8)(xval1 >> 24);
 162                *dst++ = (u8)(xval1 >> 16);
 163                *dst++ = (u8)(xval1 >> 8);
 164        }
 165}
 166
 167static inline void pdacf_transfer_stereo24le(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
 168{
 169        register u16 val1, val2, val3;
 170        register u32 xval1, xval2;
 171
 172        while (size-- > 0) {
 173                val1 = inw(rdp_port);
 174                val2 = inw(rdp_port);
 175                val3 = inw(rdp_port);
 176                xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
 177                xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
 178                *dst++ = (u8)(xval1 >> 8);
 179                *dst++ = (u8)(xval1 >> 16);
 180                *dst++ = (u8)(xval1 >> 24);
 181                *dst++ = (u8)(xval2 >> 8);
 182                *dst++ = (u8)(xval2 >> 16);
 183                *dst++ = (u8)(xval2 >> 24);
 184        }
 185}
 186
 187static inline void pdacf_transfer_stereo24be(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
 188{
 189        register u16 val1, val2, val3;
 190        register u32 xval1, xval2;
 191
 192        while (size-- > 0) {
 193                val1 = inw(rdp_port);
 194                val2 = inw(rdp_port);
 195                val3 = inw(rdp_port);
 196                xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
 197                xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
 198                *dst++ = (u8)(xval1 >> 24);
 199                *dst++ = (u8)(xval1 >> 16);
 200                *dst++ = (u8)(xval1 >> 8);
 201                *dst++ = (u8)(xval2 >> 24);
 202                *dst++ = (u8)(xval2 >> 16);
 203                *dst++ = (u8)(xval2 >> 8);
 204        }
 205}
 206
 207static void pdacf_transfer(struct snd_pdacf *chip, unsigned int size, unsigned int off)
 208{
 209        unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
 210        unsigned int xor = chip->pcm_xor;
 211
 212        if (chip->pcm_sample == 3) {
 213                if (chip->pcm_little) {
 214                        if (chip->pcm_channels == 1) {
 215                                pdacf_transfer_mono24le((char *)chip->pcm_area + (off * 3), xor, size, rdp_port);
 216                        } else {
 217                                pdacf_transfer_stereo24le((char *)chip->pcm_area + (off * 6), xor, size, rdp_port);
 218                        }
 219                } else {
 220                        if (chip->pcm_channels == 1) {
 221                                pdacf_transfer_mono24be((char *)chip->pcm_area + (off * 3), xor, size, rdp_port);
 222                        } else {
 223                                pdacf_transfer_stereo24be((char *)chip->pcm_area + (off * 6), xor, size, rdp_port);
 224                        }                       
 225                }
 226                return;
 227        }
 228        if (chip->pcm_swab == 0) {
 229                if (chip->pcm_channels == 1) {
 230                        if (chip->pcm_frame == 2) {
 231                                pdacf_transfer_mono16((u16 *)chip->pcm_area + off, xor, size, rdp_port);
 232                        } else {
 233                                pdacf_transfer_mono32((u32 *)chip->pcm_area + off, xor, size, rdp_port);
 234                        }
 235                } else {
 236                        if (chip->pcm_frame == 2) {
 237                                pdacf_transfer_stereo16((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
 238                        } else {
 239                                pdacf_transfer_stereo32((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
 240                        }
 241                }
 242        } else {
 243                if (chip->pcm_channels == 1) {
 244                        if (chip->pcm_frame == 2) {
 245                                pdacf_transfer_mono16sw((u16 *)chip->pcm_area + off, xor, size, rdp_port);
 246                        } else {
 247                                pdacf_transfer_mono32sw((u32 *)chip->pcm_area + off, xor, size, rdp_port);
 248                        }
 249                } else {
 250                        if (chip->pcm_frame == 2) {
 251                                pdacf_transfer_stereo16sw((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
 252                        } else {
 253                                pdacf_transfer_stereo32sw((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
 254                        }
 255                }
 256        }
 257}
 258
 259void pdacf_tasklet(unsigned long private_data)
 260{
 261        struct snd_pdacf *chip = (struct snd_pdacf *) private_data;
 262        int size, off, cont, rdp, wdp;
 263
 264        if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|PDAUDIOCF_STAT_IS_CONFIGURED)) != PDAUDIOCF_STAT_IS_CONFIGURED)
 265                return;
 266        
 267        if (chip->pcm_substream == NULL || chip->pcm_substream->runtime == NULL || !snd_pcm_running(chip->pcm_substream))
 268                return;
 269
 270        rdp = inw(chip->port + PDAUDIOCF_REG_RDP);
 271        wdp = inw(chip->port + PDAUDIOCF_REG_WDP);
 272        /* printk(KERN_DEBUG "TASKLET: rdp = %x, wdp = %x\n", rdp, wdp); */
 273        size = wdp - rdp;
 274        if (size < 0)
 275                size += 0x10000;
 276        if (size == 0)
 277                size = 0x10000;
 278        size /= chip->pcm_frame;
 279        if (size > 64)
 280                size -= 32;
 281
 282#if 0
 283        chip->pcm_hwptr += size;
 284        chip->pcm_hwptr %= chip->pcm_size;
 285        chip->pcm_tdone += size;
 286        if (chip->pcm_frame == 2) {
 287                unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
 288                while (size-- > 0) {
 289                        inw(rdp_port);
 290                        inw(rdp_port);
 291                }
 292        } else {
 293                unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
 294                while (size-- > 0) {
 295                        inw(rdp_port);
 296                        inw(rdp_port);
 297                        inw(rdp_port);
 298                }
 299        }
 300#else
 301        off = chip->pcm_hwptr + chip->pcm_tdone;
 302        off %= chip->pcm_size;
 303        chip->pcm_tdone += size;
 304        while (size > 0) {
 305                cont = chip->pcm_size - off;
 306                if (cont > size)
 307                        cont = size;
 308                pdacf_transfer(chip, cont, off);
 309                off += cont;
 310                off %= chip->pcm_size;
 311                size -= cont;
 312        }
 313#endif
 314        spin_lock(&chip->reg_lock);
 315        while (chip->pcm_tdone >= chip->pcm_period) {
 316                chip->pcm_hwptr += chip->pcm_period;
 317                chip->pcm_hwptr %= chip->pcm_size;
 318                chip->pcm_tdone -= chip->pcm_period;
 319                spin_unlock(&chip->reg_lock);
 320                snd_pcm_period_elapsed(chip->pcm_substream);
 321                spin_lock(&chip->reg_lock);
 322        }
 323        spin_unlock(&chip->reg_lock);
 324        /* printk(KERN_DEBUG "TASKLET: end\n"); */
 325}
 326