123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326 |
- /*
- * Driver for Sound Core PDAudioCF soundcard
- *
- * Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
- #include <sound/core.h>
- #include "pdaudiocf.h"
- #include <sound/initval.h>
- #include <asm/irq_regs.h>
- /*
- *
- */
- irqreturn_t pdacf_interrupt(int irq, void *dev)
- {
- struct snd_pdacf *chip = dev;
- unsigned short stat;
- if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|
- PDAUDIOCF_STAT_IS_CONFIGURED|
- PDAUDIOCF_STAT_IS_SUSPENDED)) != PDAUDIOCF_STAT_IS_CONFIGURED)
- return IRQ_HANDLED; /* IRQ_NONE here? */
- stat = inw(chip->port + PDAUDIOCF_REG_ISR);
- if (stat & (PDAUDIOCF_IRQLVL|PDAUDIOCF_IRQOVR)) {
- if (stat & PDAUDIOCF_IRQOVR) /* should never happen */
- snd_printk(KERN_ERR "PDAUDIOCF SRAM buffer overrun detected!\n");
- if (chip->pcm_substream)
- tasklet_schedule(&chip->tq);
- if (!(stat & PDAUDIOCF_IRQAKM))
- stat |= PDAUDIOCF_IRQAKM; /* check rate */
- }
- if (get_irq_regs() != NULL)
- snd_ak4117_check_rate_and_errors(chip->ak4117, 0);
- return IRQ_HANDLED;
- }
- static inline void pdacf_transfer_mono16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
- {
- while (size-- > 0) {
- *dst++ = inw(rdp_port) ^ xor;
- inw(rdp_port);
- }
- }
- static inline void pdacf_transfer_mono32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
- {
- register u16 val1, val2;
- while (size-- > 0) {
- val1 = inw(rdp_port);
- val2 = inw(rdp_port);
- inw(rdp_port);
- *dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
- }
- }
- static inline void pdacf_transfer_stereo16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
- {
- while (size-- > 0) {
- *dst++ = inw(rdp_port) ^ xor;
- *dst++ = inw(rdp_port) ^ xor;
- }
- }
- static inline void pdacf_transfer_stereo32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
- {
- register u16 val1, val2, val3;
- while (size-- > 0) {
- val1 = inw(rdp_port);
- val2 = inw(rdp_port);
- val3 = inw(rdp_port);
- *dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
- *dst++ = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
- }
- }
- static inline void pdacf_transfer_mono16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
- {
- while (size-- > 0) {
- *dst++ = swab16(inw(rdp_port) ^ xor);
- inw(rdp_port);
- }
- }
- static inline void pdacf_transfer_mono32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
- {
- register u16 val1, val2;
- while (size-- > 0) {
- val1 = inw(rdp_port);
- val2 = inw(rdp_port);
- inw(rdp_port);
- *dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor);
- }
- }
- static inline void pdacf_transfer_stereo16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
- {
- while (size-- > 0) {
- *dst++ = swab16(inw(rdp_port) ^ xor);
- *dst++ = swab16(inw(rdp_port) ^ xor);
- }
- }
- static inline void pdacf_transfer_stereo32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
- {
- register u16 val1, val2, val3;
- while (size-- > 0) {
- val1 = inw(rdp_port);
- val2 = inw(rdp_port);
- val3 = inw(rdp_port);
- *dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor);
- *dst++ = swab32((((u32)val3 << 16) | (val2 & 0xff00)) ^ xor);
- }
- }
- static inline void pdacf_transfer_mono24le(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
- {
- register u16 val1, val2;
- register u32 xval1;
- while (size-- > 0) {
- val1 = inw(rdp_port);
- val2 = inw(rdp_port);
- inw(rdp_port);
- xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor;
- *dst++ = (u8)(xval1 >> 8);
- *dst++ = (u8)(xval1 >> 16);
- *dst++ = (u8)(xval1 >> 24);
- }
- }
- static inline void pdacf_transfer_mono24be(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
- {
- register u16 val1, val2;
- register u32 xval1;
- while (size-- > 0) {
- val1 = inw(rdp_port);
- val2 = inw(rdp_port);
- inw(rdp_port);
- xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor;
- *dst++ = (u8)(xval1 >> 24);
- *dst++ = (u8)(xval1 >> 16);
- *dst++ = (u8)(xval1 >> 8);
- }
- }
- static inline void pdacf_transfer_stereo24le(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
- {
- register u16 val1, val2, val3;
- register u32 xval1, xval2;
- while (size-- > 0) {
- val1 = inw(rdp_port);
- val2 = inw(rdp_port);
- val3 = inw(rdp_port);
- xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
- xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
- *dst++ = (u8)(xval1 >> 8);
- *dst++ = (u8)(xval1 >> 16);
- *dst++ = (u8)(xval1 >> 24);
- *dst++ = (u8)(xval2 >> 8);
- *dst++ = (u8)(xval2 >> 16);
- *dst++ = (u8)(xval2 >> 24);
- }
- }
- static inline void pdacf_transfer_stereo24be(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
- {
- register u16 val1, val2, val3;
- register u32 xval1, xval2;
- while (size-- > 0) {
- val1 = inw(rdp_port);
- val2 = inw(rdp_port);
- val3 = inw(rdp_port);
- xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
- xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
- *dst++ = (u8)(xval1 >> 24);
- *dst++ = (u8)(xval1 >> 16);
- *dst++ = (u8)(xval1 >> 8);
- *dst++ = (u8)(xval2 >> 24);
- *dst++ = (u8)(xval2 >> 16);
- *dst++ = (u8)(xval2 >> 8);
- }
- }
- static void pdacf_transfer(struct snd_pdacf *chip, unsigned int size, unsigned int off)
- {
- unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
- unsigned int xor = chip->pcm_xor;
- if (chip->pcm_sample == 3) {
- if (chip->pcm_little) {
- if (chip->pcm_channels == 1) {
- pdacf_transfer_mono24le((char *)chip->pcm_area + (off * 3), xor, size, rdp_port);
- } else {
- pdacf_transfer_stereo24le((char *)chip->pcm_area + (off * 6), xor, size, rdp_port);
- }
- } else {
- if (chip->pcm_channels == 1) {
- pdacf_transfer_mono24be((char *)chip->pcm_area + (off * 3), xor, size, rdp_port);
- } else {
- pdacf_transfer_stereo24be((char *)chip->pcm_area + (off * 6), xor, size, rdp_port);
- }
- }
- return;
- }
- if (chip->pcm_swab == 0) {
- if (chip->pcm_channels == 1) {
- if (chip->pcm_frame == 2) {
- pdacf_transfer_mono16((u16 *)chip->pcm_area + off, xor, size, rdp_port);
- } else {
- pdacf_transfer_mono32((u32 *)chip->pcm_area + off, xor, size, rdp_port);
- }
- } else {
- if (chip->pcm_frame == 2) {
- pdacf_transfer_stereo16((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
- } else {
- pdacf_transfer_stereo32((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
- }
- }
- } else {
- if (chip->pcm_channels == 1) {
- if (chip->pcm_frame == 2) {
- pdacf_transfer_mono16sw((u16 *)chip->pcm_area + off, xor, size, rdp_port);
- } else {
- pdacf_transfer_mono32sw((u32 *)chip->pcm_area + off, xor, size, rdp_port);
- }
- } else {
- if (chip->pcm_frame == 2) {
- pdacf_transfer_stereo16sw((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
- } else {
- pdacf_transfer_stereo32sw((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
- }
- }
- }
- }
- void pdacf_tasklet(unsigned long private_data)
- {
- struct snd_pdacf *chip = (struct snd_pdacf *) private_data;
- int size, off, cont, rdp, wdp;
- if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|PDAUDIOCF_STAT_IS_CONFIGURED)) != PDAUDIOCF_STAT_IS_CONFIGURED)
- return;
-
- if (chip->pcm_substream == NULL || chip->pcm_substream->runtime == NULL || !snd_pcm_running(chip->pcm_substream))
- return;
- rdp = inw(chip->port + PDAUDIOCF_REG_RDP);
- wdp = inw(chip->port + PDAUDIOCF_REG_WDP);
- /* printk(KERN_DEBUG "TASKLET: rdp = %x, wdp = %x\n", rdp, wdp); */
- size = wdp - rdp;
- if (size < 0)
- size += 0x10000;
- if (size == 0)
- size = 0x10000;
- size /= chip->pcm_frame;
- if (size > 64)
- size -= 32;
- #if 0
- chip->pcm_hwptr += size;
- chip->pcm_hwptr %= chip->pcm_size;
- chip->pcm_tdone += size;
- if (chip->pcm_frame == 2) {
- unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
- while (size-- > 0) {
- inw(rdp_port);
- inw(rdp_port);
- }
- } else {
- unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
- while (size-- > 0) {
- inw(rdp_port);
- inw(rdp_port);
- inw(rdp_port);
- }
- }
- #else
- off = chip->pcm_hwptr + chip->pcm_tdone;
- off %= chip->pcm_size;
- chip->pcm_tdone += size;
- while (size > 0) {
- cont = chip->pcm_size - off;
- if (cont > size)
- cont = size;
- pdacf_transfer(chip, cont, off);
- off += cont;
- off %= chip->pcm_size;
- size -= cont;
- }
- #endif
- spin_lock(&chip->reg_lock);
- while (chip->pcm_tdone >= chip->pcm_period) {
- chip->pcm_hwptr += chip->pcm_period;
- chip->pcm_hwptr %= chip->pcm_size;
- chip->pcm_tdone -= chip->pcm_period;
- spin_unlock(&chip->reg_lock);
- snd_pcm_period_elapsed(chip->pcm_substream);
- spin_lock(&chip->reg_lock);
- }
- spin_unlock(&chip->reg_lock);
- /* printk(KERN_DEBUG "TASKLET: end\n"); */
- }
|