11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Driver for Sound Core PDAudioCF soundcard
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
4c1017a4cdb68ae5368fbc9ee42c77f1f5dca8916Jaroslav Kysela * Copyright (c) 2003 by Jaroslav Kysela <perex@perex.cz>
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   This program is free software; you can redistribute it and/or modify
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   it under the terms of the GNU General Public License as published by
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   the Free Software Foundation; either version 2 of the License, or
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   (at your option) any later version.
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   This program is distributed in the hope that it will be useful,
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   but WITHOUT ANY WARRANTY; without even the implied warranty of
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   GNU General Public License for more details.
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   You should have received a copy of the GNU General Public License
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   along with this program; if not, write to the Free Software
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <sound/core.h>
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "pdaudiocf.h"
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <sound/initval.h>
2497432886617825d412bcedadf5e5b308f931caadAl Viro#include <asm/irq_regs.h>
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
297d12e780e003f93433d49ce78cfedf4b4c52adc5David Howellsirqreturn_t pdacf_interrupt(int irq, void *dev)
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
31db13154843cb2c99a93e9feed575e906f6e0e455Takashi Iwai	struct snd_pdacf *chip = dev;
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned short stat;
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  PDAUDIOCF_STAT_IS_CONFIGURED|
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				  PDAUDIOCF_STAT_IS_SUSPENDED)) != PDAUDIOCF_STAT_IS_CONFIGURED)
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return IRQ_HANDLED;	/* IRQ_NONE here? */
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	stat = inw(chip->port + PDAUDIOCF_REG_ISR);
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (stat & (PDAUDIOCF_IRQLVL|PDAUDIOCF_IRQOVR)) {
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (stat & PDAUDIOCF_IRQOVR)	/* should never happen */
421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			snd_printk(KERN_ERR "PDAUDIOCF SRAM buffer overrun detected!\n");
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (chip->pcm_substream)
441f04128a3db7c0f0e8b5d25323eba70ac342f47fTakashi Iwai			tasklet_schedule(&chip->tq);
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (!(stat & PDAUDIOCF_IRQAKM))
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			stat |= PDAUDIOCF_IRQAKM;	/* check rate */
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
487d12e780e003f93433d49ce78cfedf4b4c52adc5David Howells	if (get_irq_regs() != NULL)
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		snd_ak4117_check_rate_and_errors(chip->ak4117, 0);
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return IRQ_HANDLED;
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void pdacf_transfer_mono16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (size-- > 0) {
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = inw(rdp_port) ^ xor;
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inw(rdp_port);
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void pdacf_transfer_mono32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register u16 val1, val2;
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (size-- > 0) {
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val1 = inw(rdp_port);
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val2 = inw(rdp_port);
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inw(rdp_port);
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void pdacf_transfer_stereo16(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (size-- > 0) {
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = inw(rdp_port) ^ xor;
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = inw(rdp_port) ^ xor;
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void pdacf_transfer_stereo32(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register u16 val1, val2, val3;
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (size-- > 0) {
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val1 = inw(rdp_port);
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val2 = inw(rdp_port);
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val3 = inw(rdp_port);
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void pdacf_transfer_mono16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (size-- > 0) {
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = swab16(inw(rdp_port) ^ xor);
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inw(rdp_port);
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void pdacf_transfer_mono32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register u16 val1, val2;
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (size-- > 0) {
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val1 = inw(rdp_port);
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val2 = inw(rdp_port);
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inw(rdp_port);
1101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor);
1111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void pdacf_transfer_stereo16sw(u16 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (size-- > 0) {
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = swab16(inw(rdp_port) ^ xor);
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = swab16(inw(rdp_port) ^ xor);
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void pdacf_transfer_stereo32sw(u32 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register u16 val1, val2, val3;
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (size-- > 0) {
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val1 = inw(rdp_port);
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val2 = inw(rdp_port);
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val3 = inw(rdp_port);
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = swab32((((val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor);
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = swab32((((u32)val3 << 16) | (val2 & 0xff00)) ^ xor);
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void pdacf_transfer_mono24le(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register u16 val1, val2;
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register u32 xval1;
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (size-- > 0) {
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val1 = inw(rdp_port);
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val2 = inw(rdp_port);
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inw(rdp_port);
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor;
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = (u8)(xval1 >> 8);
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = (u8)(xval1 >> 16);
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = (u8)(xval1 >> 24);
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void pdacf_transfer_mono24be(u8 *dst, u16 xor, unsigned int size, unsigned long rdp_port)
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register u16 val1, val2;
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register u32 xval1;
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (size-- > 0) {
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val1 = inw(rdp_port);
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val2 = inw(rdp_port);
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		inw(rdp_port);
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		xval1 = (((val2 & 0xff) << 8) | (val1 << 16)) ^ xor;
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = (u8)(xval1 >> 24);
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = (u8)(xval1 >> 16);
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = (u8)(xval1 >> 8);
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void pdacf_transfer_stereo24le(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register u16 val1, val2, val3;
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register u32 xval1, xval2;
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (size-- > 0) {
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val1 = inw(rdp_port);
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val2 = inw(rdp_port);
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val3 = inw(rdp_port);
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = (u8)(xval1 >> 8);
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = (u8)(xval1 >> 16);
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = (u8)(xval1 >> 24);
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = (u8)(xval2 >> 8);
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = (u8)(xval2 >> 16);
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = (u8)(xval2 >> 24);
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic inline void pdacf_transfer_stereo24be(u8 *dst, u32 xor, unsigned int size, unsigned long rdp_port)
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register u16 val1, val2, val3;
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	register u32 xval1, xval2;
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (size-- > 0) {
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val1 = inw(rdp_port);
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val2 = inw(rdp_port);
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		val3 = inw(rdp_port);
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		xval1 = ((((u32)val2 & 0xff) << 24) | ((u32)val1 << 8)) ^ xor;
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		xval2 = (((u32)val3 << 16) | (val2 & 0xff00)) ^ xor;
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = (u8)(xval1 >> 24);
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = (u8)(xval1 >> 16);
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = (u8)(xval1 >> 8);
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = (u8)(xval2 >> 24);
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = (u8)(xval2 >> 16);
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		*dst++ = (u8)(xval2 >> 8);
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
207db13154843cb2c99a93e9feed575e906f6e0e455Takashi Iwaistatic void pdacf_transfer(struct snd_pdacf *chip, unsigned int size, unsigned int off)
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	unsigned int xor = chip->pcm_xor;
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (chip->pcm_sample == 3) {
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (chip->pcm_little) {
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (chip->pcm_channels == 1) {
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pdacf_transfer_mono24le((char *)chip->pcm_area + (off * 3), xor, size, rdp_port);
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pdacf_transfer_stereo24le((char *)chip->pcm_area + (off * 6), xor, size, rdp_port);
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (chip->pcm_channels == 1) {
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pdacf_transfer_mono24be((char *)chip->pcm_area + (off * 3), xor, size, rdp_port);
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pdacf_transfer_stereo24be((char *)chip->pcm_area + (off * 6), xor, size, rdp_port);
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (chip->pcm_swab == 0) {
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (chip->pcm_channels == 1) {
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (chip->pcm_frame == 2) {
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pdacf_transfer_mono16((u16 *)chip->pcm_area + off, xor, size, rdp_port);
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pdacf_transfer_mono32((u32 *)chip->pcm_area + off, xor, size, rdp_port);
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (chip->pcm_frame == 2) {
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pdacf_transfer_stereo16((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pdacf_transfer_stereo32((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (chip->pcm_channels == 1) {
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (chip->pcm_frame == 2) {
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pdacf_transfer_mono16sw((u16 *)chip->pcm_area + off, xor, size, rdp_port);
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
2471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pdacf_transfer_mono32sw((u32 *)chip->pcm_area + off, xor, size, rdp_port);
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		} else {
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (chip->pcm_frame == 2) {
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pdacf_transfer_stereo16sw((u16 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				pdacf_transfer_stereo32sw((u32 *)chip->pcm_area + (off * 2), xor, size, rdp_port);
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvoid pdacf_tasklet(unsigned long private_data)
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
261db13154843cb2c99a93e9feed575e906f6e0e455Takashi Iwai	struct snd_pdacf *chip = (struct snd_pdacf *) private_data;
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int size, off, cont, rdp, wdp;
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if ((chip->chip_status & (PDAUDIOCF_STAT_IS_STALE|PDAUDIOCF_STAT_IS_CONFIGURED)) != PDAUDIOCF_STAT_IS_CONFIGURED)
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (chip->pcm_substream == NULL || chip->pcm_substream->runtime == NULL || !snd_pcm_running(chip->pcm_substream))
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return;
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	rdp = inw(chip->port + PDAUDIOCF_REG_RDP);
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	wdp = inw(chip->port + PDAUDIOCF_REG_WDP);
2722ebfb8eeb8f244f9d25937d31a947895cf819e26Takashi Iwai	/* printk(KERN_DEBUG "TASKLET: rdp = %x, wdp = %x\n", rdp, wdp); */
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size = wdp - rdp;
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (size < 0)
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size += 0x10000;
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (size == 0)
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size = 0x10000;
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	size /= chip->pcm_frame;
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (size > 64)
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size -= 32;
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#if 0
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	chip->pcm_hwptr += size;
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	chip->pcm_hwptr %= chip->pcm_size;
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	chip->pcm_tdone += size;
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (chip->pcm_frame == 2) {
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (size-- > 0) {
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			inw(rdp_port);
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			inw(rdp_port);
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		unsigned long rdp_port = chip->port + PDAUDIOCF_REG_MD;
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (size-- > 0) {
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			inw(rdp_port);
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			inw(rdp_port);
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			inw(rdp_port);
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#else
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	off = chip->pcm_hwptr + chip->pcm_tdone;
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	off %= chip->pcm_size;
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	chip->pcm_tdone += size;
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (size > 0) {
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		cont = chip->pcm_size - off;
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (cont > size)
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			cont = size;
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		pdacf_transfer(chip, cont, off);
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		off += cont;
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		off %= chip->pcm_size;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		size -= cont;
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_lock(&chip->reg_lock);
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (chip->pcm_tdone >= chip->pcm_period) {
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		chip->pcm_hwptr += chip->pcm_period;
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		chip->pcm_hwptr %= chip->pcm_size;
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		chip->pcm_tdone -= chip->pcm_period;
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_unlock(&chip->reg_lock);
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		snd_pcm_period_elapsed(chip->pcm_substream);
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		spin_lock(&chip->reg_lock);
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	spin_unlock(&chip->reg_lock);
3242ebfb8eeb8f244f9d25937d31a947895cf819e26Takashi Iwai	/* printk(KERN_DEBUG "TASKLET: end\n"); */
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
326