mirror of
https://github.com/torvalds/linux.git
synced 2024-11-26 06:02:05 +00:00
[SPARC]: Make SBUS dma code similar to EBUS
From: Georg Chini <georg.chini@triaton-webhosting.com> Introduce some sbus_dma routines similar to the ebus_dma stuff to make the code look nearly the same for both cases. Thanks to Christopher for testing. Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
ee1858d312
commit
5a820fa7e1
@ -61,6 +61,14 @@ MODULE_DESCRIPTION("Sun CS4231");
|
|||||||
MODULE_LICENSE("GPL");
|
MODULE_LICENSE("GPL");
|
||||||
MODULE_SUPPORTED_DEVICE("{{Sun,CS4231}}");
|
MODULE_SUPPORTED_DEVICE("{{Sun,CS4231}}");
|
||||||
|
|
||||||
|
#ifdef SBUS_SUPPORT
|
||||||
|
struct sbus_dma_info {
|
||||||
|
spinlock_t lock;
|
||||||
|
int dir;
|
||||||
|
void __iomem *regs;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
typedef struct snd_cs4231 {
|
typedef struct snd_cs4231 {
|
||||||
spinlock_t lock;
|
spinlock_t lock;
|
||||||
void __iomem *port;
|
void __iomem *port;
|
||||||
@ -69,6 +77,11 @@ typedef struct snd_cs4231 {
|
|||||||
struct ebus_dma_info eb2p;
|
struct ebus_dma_info eb2p;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef SBUS_SUPPORT
|
||||||
|
struct sbus_dma_info sb2c;
|
||||||
|
struct sbus_dma_info sb2p;
|
||||||
|
#endif
|
||||||
|
|
||||||
u32 flags;
|
u32 flags;
|
||||||
#define CS4231_FLAG_EBUS 0x00000001
|
#define CS4231_FLAG_EBUS 0x00000001
|
||||||
#define CS4231_FLAG_PLAYBACK 0x00000002
|
#define CS4231_FLAG_PLAYBACK 0x00000002
|
||||||
@ -251,6 +264,15 @@ static cs4231_t *cs4231_list;
|
|||||||
#define APCPNVA 0x38UL /* APC Play DMA Next Address */
|
#define APCPNVA 0x38UL /* APC Play DMA Next Address */
|
||||||
#define APCPNC 0x3cUL /* APC Play Next Count */
|
#define APCPNC 0x3cUL /* APC Play Next Count */
|
||||||
|
|
||||||
|
/* Defines for SBUS DMA-routines */
|
||||||
|
|
||||||
|
#define APCVA 0x0UL /* APC DMA Address */
|
||||||
|
#define APCC 0x4UL /* APC Count */
|
||||||
|
#define APCNVA 0x8UL /* APC DMA Next Address */
|
||||||
|
#define APCNC 0xcUL /* APC Next Count */
|
||||||
|
#define APC_PLAY 0x30UL /* Play registers start at 0x30 */
|
||||||
|
#define APC_RECORD 0x20UL /* Record registers start at 0x20 */
|
||||||
|
|
||||||
/* APCCSR bits */
|
/* APCCSR bits */
|
||||||
|
|
||||||
#define APC_INT_PENDING 0x800000 /* Interrupt Pending */
|
#define APC_INT_PENDING 0x800000 /* Interrupt Pending */
|
||||||
@ -471,6 +493,103 @@ static unsigned char snd_cs4231_in(cs4231_t *chip, unsigned char reg)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SBUS DMA routines
|
||||||
|
*/
|
||||||
|
#ifdef SBUS_SUPPORT
|
||||||
|
|
||||||
|
int sbus_dma_request(struct sbus_dma_info *base, dma_addr_t bus_addr, size_t len)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
u32 test, csr;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
if (len >= (1 << 24))
|
||||||
|
return -EINVAL;
|
||||||
|
spin_lock_irqsave(&base->lock, flags);
|
||||||
|
csr = sbus_readl(base->regs + APCCSR);
|
||||||
|
err = -EINVAL;
|
||||||
|
test = APC_CDMA_READY;
|
||||||
|
if ( base->dir == APC_PLAY )
|
||||||
|
test = APC_PDMA_READY;
|
||||||
|
if (!(csr & test))
|
||||||
|
goto out;
|
||||||
|
err = -EBUSY;
|
||||||
|
csr = sbus_readl(base->regs + APCCSR);
|
||||||
|
test = APC_XINT_CNVA;
|
||||||
|
if ( base->dir == APC_PLAY )
|
||||||
|
test = APC_XINT_PNVA;
|
||||||
|
if (!(csr & test))
|
||||||
|
goto out;
|
||||||
|
err = 0;
|
||||||
|
sbus_writel(bus_addr, base->regs + base->dir + APCNVA);
|
||||||
|
sbus_writel(len, base->regs + base->dir + APCNC);
|
||||||
|
out:
|
||||||
|
spin_unlock_irqrestore(&base->lock, flags);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sbus_dma_prepare(struct sbus_dma_info *base)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
u32 csr, test;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&base->lock, flags);
|
||||||
|
csr = sbus_readl(base->regs + APCCSR);
|
||||||
|
test = APC_GENL_INT | APC_PLAY_INT | APC_XINT_ENA |
|
||||||
|
APC_XINT_PLAY | APC_XINT_PEMP | APC_XINT_GENL |
|
||||||
|
APC_XINT_PENA;
|
||||||
|
if ( base->dir == APC_RECORD )
|
||||||
|
test = APC_GENL_INT | APC_CAPT_INT | APC_XINT_ENA |
|
||||||
|
APC_XINT_CAPT | APC_XINT_CEMP | APC_XINT_GENL;
|
||||||
|
csr |= test;
|
||||||
|
sbus_writel(csr, base->regs + APCCSR);
|
||||||
|
spin_unlock_irqrestore(&base->lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sbus_dma_enable(struct sbus_dma_info *base, int on)
|
||||||
|
{
|
||||||
|
unsigned long flags;
|
||||||
|
u32 csr, shift;
|
||||||
|
|
||||||
|
spin_lock_irqsave(&base->lock, flags);
|
||||||
|
if (!on) {
|
||||||
|
if (base->dir == APC_PLAY) {
|
||||||
|
sbus_writel(0, base->regs + base->dir + APCNVA);
|
||||||
|
sbus_writel(1, base->regs + base->dir + APCC);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sbus_writel(0, base->regs + base->dir + APCNC);
|
||||||
|
sbus_writel(0, base->regs + base->dir + APCVA);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
udelay(500);
|
||||||
|
csr = sbus_readl(base->regs + APCCSR);
|
||||||
|
shift = 0;
|
||||||
|
if ( base->dir == APC_PLAY )
|
||||||
|
shift = 1;
|
||||||
|
if (on)
|
||||||
|
csr &= ~(APC_CPAUSE << shift);
|
||||||
|
else
|
||||||
|
csr |= (APC_CPAUSE << shift);
|
||||||
|
sbus_writel(csr, base->regs + APCCSR);
|
||||||
|
if (on)
|
||||||
|
csr |= (APC_CDMA_READY << shift);
|
||||||
|
else
|
||||||
|
csr &= ~(APC_CDMA_READY << shift);
|
||||||
|
sbus_writel(csr, base->regs + APCCSR);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&base->lock, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int sbus_dma_addr(struct sbus_dma_info *base)
|
||||||
|
{
|
||||||
|
return sbus_readl(base->regs + base->dir + APCVA);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CS4231 detection / MCE routines
|
* CS4231 detection / MCE routines
|
||||||
*/
|
*/
|
||||||
@ -589,29 +708,21 @@ static void snd_cs4231_ebus_advance_dma(struct ebus_dma_info *p, snd_pcm_substre
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef SBUS_SUPPORT
|
#ifdef SBUS_SUPPORT
|
||||||
static void snd_cs4231_sbus_advance_dma(snd_pcm_substream_t *substream, unsigned int *periods_sent)
|
static void snd_cs4231_sbus_advance_dma(struct sbus_dma_info *p, snd_pcm_substream_t *substream, unsigned int *periods_sent)
|
||||||
{
|
{
|
||||||
cs4231_t *chip = snd_pcm_substream_chip(substream);
|
|
||||||
snd_pcm_runtime_t *runtime = substream->runtime;
|
snd_pcm_runtime_t *runtime = substream->runtime;
|
||||||
|
|
||||||
unsigned int period_size = snd_pcm_lib_period_bytes(substream);
|
while (1) {
|
||||||
unsigned int offset = period_size * (*periods_sent % runtime->periods);
|
unsigned int period_size = snd_pcm_lib_period_bytes(substream);
|
||||||
|
unsigned int offset = period_size * (*periods_sent);
|
||||||
|
|
||||||
if (runtime->period_size > 0xffff + 1)
|
if (period_size > 0xffff + 1)
|
||||||
BUG();
|
BUG();
|
||||||
|
|
||||||
switch (substream->stream) {
|
if (sbus_dma_request(p, runtime->dma_addr + offset, period_size))
|
||||||
case SNDRV_PCM_STREAM_PLAYBACK:
|
return;
|
||||||
sbus_writel(runtime->dma_addr + offset, chip->port + APCPNVA);
|
(*periods_sent) = (*periods_sent + 1) % runtime->periods;
|
||||||
sbus_writel(period_size, chip->port + APCPNC);
|
}
|
||||||
break;
|
|
||||||
case SNDRV_PCM_STREAM_CAPTURE:
|
|
||||||
sbus_writel(runtime->dma_addr + offset, chip->port + APCCNVA);
|
|
||||||
sbus_writel(period_size, chip->port + APCCNC);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
(*periods_sent) = (*periods_sent + 1) % runtime->periods;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -646,59 +757,27 @@ static void cs4231_dma_trigger(snd_pcm_substream_t *substream, unsigned int what
|
|||||||
} else {
|
} else {
|
||||||
#endif
|
#endif
|
||||||
#ifdef SBUS_SUPPORT
|
#ifdef SBUS_SUPPORT
|
||||||
u32 csr = sbus_readl(chip->port + APCCSR);
|
if (what & CS4231_PLAYBACK_ENABLE) {
|
||||||
/* I don't know why, but on sbus the period counter must
|
|
||||||
* only start counting after the first period is sent.
|
|
||||||
* Therefore this dummy thing.
|
|
||||||
*/
|
|
||||||
unsigned int dummy = 0;
|
|
||||||
|
|
||||||
switch (what) {
|
|
||||||
case CS4231_PLAYBACK_ENABLE:
|
|
||||||
if (on) {
|
if (on) {
|
||||||
csr &= ~APC_XINT_PLAY;
|
sbus_dma_prepare(&chip->sb2p);
|
||||||
sbus_writel(csr, chip->port + APCCSR);
|
sbus_dma_enable(&chip->sb2p, 1);
|
||||||
|
snd_cs4231_sbus_advance_dma(&chip->sb2p,
|
||||||
csr &= ~APC_PPAUSE;
|
chip->playback_substream,
|
||||||
sbus_writel(csr, chip->port + APCCSR);
|
&chip->p_periods_sent);
|
||||||
|
|
||||||
snd_cs4231_sbus_advance_dma(substream, &dummy);
|
|
||||||
|
|
||||||
csr |= APC_GENL_INT | APC_PLAY_INT | APC_XINT_ENA |
|
|
||||||
APC_XINT_PLAY | APC_XINT_EMPT | APC_XINT_GENL |
|
|
||||||
APC_XINT_PENA | APC_PDMA_READY;
|
|
||||||
sbus_writel(csr, chip->port + APCCSR);
|
|
||||||
} else {
|
} else {
|
||||||
csr |= APC_PPAUSE;
|
sbus_dma_enable(&chip->sb2p, 0);
|
||||||
sbus_writel(csr, chip->port + APCCSR);
|
|
||||||
|
|
||||||
csr &= ~APC_PDMA_READY;
|
|
||||||
sbus_writel(csr, chip->port + APCCSR);
|
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
case CS4231_RECORD_ENABLE:
|
if (what & CS4231_RECORD_ENABLE) {
|
||||||
if (on) {
|
if (on) {
|
||||||
csr &= ~APC_XINT_CAPT;
|
sbus_dma_prepare(&chip->sb2c);
|
||||||
sbus_writel(csr, chip->port + APCCSR);
|
sbus_dma_enable(&chip->sb2c, 1);
|
||||||
|
snd_cs4231_sbus_advance_dma(&chip->sb2c,
|
||||||
csr &= ~APC_CPAUSE;
|
chip->capture_substream,
|
||||||
sbus_writel(csr, chip->port + APCCSR);
|
&chip->c_periods_sent);
|
||||||
|
|
||||||
snd_cs4231_sbus_advance_dma(substream, &dummy);
|
|
||||||
|
|
||||||
csr |= APC_GENL_INT | APC_CAPT_INT | APC_XINT_ENA |
|
|
||||||
APC_XINT_CAPT | APC_XINT_CEMP | APC_XINT_GENL |
|
|
||||||
APC_CDMA_READY;
|
|
||||||
|
|
||||||
sbus_writel(csr, chip->port + APCCSR);
|
|
||||||
} else {
|
} else {
|
||||||
csr |= APC_CPAUSE;
|
sbus_dma_enable(&chip->sb2c, 0);
|
||||||
sbus_writel(csr, chip->port + APCCSR);
|
|
||||||
|
|
||||||
csr &= ~APC_CDMA_READY;
|
|
||||||
sbus_writel(csr, chip->port + APCCSR);
|
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef EBUS_SUPPORT
|
#ifdef EBUS_SUPPORT
|
||||||
@ -1136,10 +1215,7 @@ static int snd_cs4231_playback_prepare(snd_pcm_substream_t *substream)
|
|||||||
if (runtime->period_size > 0xffff + 1)
|
if (runtime->period_size > 0xffff + 1)
|
||||||
BUG();
|
BUG();
|
||||||
|
|
||||||
snd_cs4231_out(chip, CS4231_PLY_LWR_CNT, (runtime->period_size - 1) & 0x00ff);
|
|
||||||
snd_cs4231_out(chip, CS4231_PLY_UPR_CNT, (runtime->period_size - 1) >> 8 & 0x00ff);
|
|
||||||
chip->p_periods_sent = 0;
|
chip->p_periods_sent = 0;
|
||||||
|
|
||||||
spin_unlock_irqrestore(&chip->lock, flags);
|
spin_unlock_irqrestore(&chip->lock, flags);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1171,16 +1247,14 @@ static int snd_cs4231_capture_hw_free(snd_pcm_substream_t *substream)
|
|||||||
static int snd_cs4231_capture_prepare(snd_pcm_substream_t *substream)
|
static int snd_cs4231_capture_prepare(snd_pcm_substream_t *substream)
|
||||||
{
|
{
|
||||||
cs4231_t *chip = snd_pcm_substream_chip(substream);
|
cs4231_t *chip = snd_pcm_substream_chip(substream);
|
||||||
snd_pcm_runtime_t *runtime = substream->runtime;
|
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
spin_lock_irqsave(&chip->lock, flags);
|
spin_lock_irqsave(&chip->lock, flags);
|
||||||
chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE |
|
chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE |
|
||||||
CS4231_RECORD_PIO);
|
CS4231_RECORD_PIO);
|
||||||
|
|
||||||
snd_cs4231_out(chip, CS4231_REC_LWR_CNT, (runtime->period_size - 1) & 0x00ff);
|
|
||||||
snd_cs4231_out(chip, CS4231_REC_LWR_CNT, (runtime->period_size - 1) >> 8 & 0x00ff);
|
|
||||||
|
|
||||||
|
chip->c_periods_sent = 0;
|
||||||
spin_unlock_irqrestore(&chip->lock, flags);
|
spin_unlock_irqrestore(&chip->lock, flags);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@ -1199,15 +1273,41 @@ static void snd_cs4231_overrange(cs4231_t *chip)
|
|||||||
chip->capture_substream->runtime->overrange++;
|
chip->capture_substream->runtime->overrange++;
|
||||||
}
|
}
|
||||||
|
|
||||||
static irqreturn_t snd_cs4231_generic_interrupt(cs4231_t *chip)
|
#ifdef SBUS_SUPPORT
|
||||||
|
static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
unsigned char status;
|
unsigned char status;
|
||||||
|
u32 csr;
|
||||||
|
cs4231_t *chip = dev_id;
|
||||||
|
|
||||||
/*This is IRQ is not raised by the cs4231*/
|
/*This is IRQ is not raised by the cs4231*/
|
||||||
if (!(__cs4231_readb(chip, CS4231P(chip, STATUS)) & CS4231_GLOBALIRQ))
|
if (!(__cs4231_readb(chip, CS4231P(chip, STATUS)) & CS4231_GLOBALIRQ))
|
||||||
return IRQ_NONE;
|
return IRQ_NONE;
|
||||||
|
|
||||||
|
/* ACK the APC interrupt. */
|
||||||
|
csr = sbus_readl(chip->port + APCCSR);
|
||||||
|
|
||||||
|
sbus_writel(csr, chip->port + APCCSR);
|
||||||
|
|
||||||
|
if ((chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE) &&
|
||||||
|
(csr & APC_PLAY_INT) &&
|
||||||
|
(csr & APC_XINT_PNVA) &&
|
||||||
|
!(csr & APC_XINT_EMPT)) {
|
||||||
|
snd_pcm_period_elapsed(chip->playback_substream);
|
||||||
|
snd_cs4231_sbus_advance_dma(&chip->sb2p, chip->playback_substream,
|
||||||
|
&chip->p_periods_sent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) &&
|
||||||
|
(csr & APC_CAPT_INT) &&
|
||||||
|
(csr & APC_XINT_CNVA) &&
|
||||||
|
!(csr & APC_XINT_EMPT)) {
|
||||||
|
snd_pcm_period_elapsed(chip->capture_substream);
|
||||||
|
snd_cs4231_sbus_advance_dma(&chip->sb2c,chip->capture_substream,
|
||||||
|
&chip->c_periods_sent);
|
||||||
|
}
|
||||||
|
|
||||||
status = snd_cs4231_in(chip, CS4231_IRQ_STATUS);
|
status = snd_cs4231_in(chip, CS4231_IRQ_STATUS);
|
||||||
|
|
||||||
if (status & CS4231_TIMER_IRQ) {
|
if (status & CS4231_TIMER_IRQ) {
|
||||||
@ -1225,36 +1325,6 @@ static irqreturn_t snd_cs4231_generic_interrupt(cs4231_t *chip)
|
|||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef SBUS_SUPPORT
|
|
||||||
static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id, struct pt_regs *regs)
|
|
||||||
{
|
|
||||||
cs4231_t *chip = dev_id;
|
|
||||||
|
|
||||||
/* ACK the APC interrupt. */
|
|
||||||
u32 csr = sbus_readl(chip->port + APCCSR);
|
|
||||||
|
|
||||||
sbus_writel(csr, chip->port + APCCSR);
|
|
||||||
|
|
||||||
if ((chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE) &&
|
|
||||||
(csr & APC_PLAY_INT) &&
|
|
||||||
(csr & APC_XINT_PNVA) &&
|
|
||||||
!(csr & APC_XINT_EMPT)) {
|
|
||||||
snd_cs4231_sbus_advance_dma(chip->playback_substream,
|
|
||||||
&chip->p_periods_sent);
|
|
||||||
snd_pcm_period_elapsed(chip->playback_substream);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) &&
|
|
||||||
(csr & APC_CAPT_INT) &&
|
|
||||||
(csr & APC_XINT_CNVA)) {
|
|
||||||
snd_cs4231_sbus_advance_dma(chip->capture_substream,
|
|
||||||
&chip->c_periods_sent);
|
|
||||||
snd_pcm_period_elapsed(chip->capture_substream);
|
|
||||||
}
|
|
||||||
|
|
||||||
return snd_cs4231_generic_interrupt(chip);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef EBUS_SUPPORT
|
#ifdef EBUS_SUPPORT
|
||||||
@ -1284,24 +1354,29 @@ static void snd_cs4231_ebus_capture_callback(struct ebus_dma_info *p, int event,
|
|||||||
static snd_pcm_uframes_t snd_cs4231_playback_pointer(snd_pcm_substream_t *substream)
|
static snd_pcm_uframes_t snd_cs4231_playback_pointer(snd_pcm_substream_t *substream)
|
||||||
{
|
{
|
||||||
cs4231_t *chip = snd_pcm_substream_chip(substream);
|
cs4231_t *chip = snd_pcm_substream_chip(substream);
|
||||||
size_t ptr, residue, period_bytes;
|
size_t ptr;
|
||||||
|
#ifdef EBUS_SUPPORT
|
||||||
|
size_t residue, period_bytes;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE))
|
if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE))
|
||||||
return 0;
|
return 0;
|
||||||
|
#ifdef EBUS_SUPPORT
|
||||||
period_bytes = snd_pcm_lib_period_bytes(substream);
|
period_bytes = snd_pcm_lib_period_bytes(substream);
|
||||||
ptr = period_bytes * chip->p_periods_sent;
|
ptr = period_bytes * chip->p_periods_sent;
|
||||||
#ifdef EBUS_SUPPORT
|
|
||||||
if (chip->flags & CS4231_FLAG_EBUS) {
|
if (chip->flags & CS4231_FLAG_EBUS) {
|
||||||
residue = ebus_dma_residue(&chip->eb2p);
|
residue = ebus_dma_residue(&chip->eb2p);
|
||||||
|
ptr += period_bytes - residue;
|
||||||
} else {
|
} else {
|
||||||
#endif
|
#endif
|
||||||
#ifdef SBUS_SUPPORT
|
#ifdef SBUS_SUPPORT
|
||||||
residue = sbus_readl(chip->port + APCPC);
|
ptr = sbus_dma_addr(&chip->sb2p);
|
||||||
|
if (ptr != 0)
|
||||||
|
ptr -= substream->runtime->dma_addr;
|
||||||
#endif
|
#endif
|
||||||
#ifdef EBUS_SUPPORT
|
#ifdef EBUS_SUPPORT
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
ptr += period_bytes - residue;
|
|
||||||
|
|
||||||
return bytes_to_frames(substream->runtime, ptr);
|
return bytes_to_frames(substream->runtime, ptr);
|
||||||
}
|
}
|
||||||
@ -1309,24 +1384,29 @@ static snd_pcm_uframes_t snd_cs4231_playback_pointer(snd_pcm_substream_t *substr
|
|||||||
static snd_pcm_uframes_t snd_cs4231_capture_pointer(snd_pcm_substream_t * substream)
|
static snd_pcm_uframes_t snd_cs4231_capture_pointer(snd_pcm_substream_t * substream)
|
||||||
{
|
{
|
||||||
cs4231_t *chip = snd_pcm_substream_chip(substream);
|
cs4231_t *chip = snd_pcm_substream_chip(substream);
|
||||||
size_t ptr, residue, period_bytes;
|
size_t ptr;
|
||||||
|
#ifdef EBUS_SUPPORT
|
||||||
|
size_t residue, period_bytes;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE))
|
if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE))
|
||||||
return 0;
|
return 0;
|
||||||
|
#ifdef EBUS_SUPPORT
|
||||||
period_bytes = snd_pcm_lib_period_bytes(substream);
|
period_bytes = snd_pcm_lib_period_bytes(substream);
|
||||||
ptr = period_bytes * chip->c_periods_sent;
|
ptr = period_bytes * chip->c_periods_sent;
|
||||||
#ifdef EBUS_SUPPORT
|
|
||||||
if (chip->flags & CS4231_FLAG_EBUS) {
|
if (chip->flags & CS4231_FLAG_EBUS) {
|
||||||
residue = ebus_dma_residue(&chip->eb2c);
|
residue = ebus_dma_residue(&chip->eb2c);
|
||||||
|
ptr += period_bytes - residue;
|
||||||
} else {
|
} else {
|
||||||
#endif
|
#endif
|
||||||
#ifdef SBUS_SUPPORT
|
#ifdef SBUS_SUPPORT
|
||||||
residue = sbus_readl(chip->port + APCCC);
|
ptr = sbus_dma_addr(&chip->sb2c);
|
||||||
|
if (ptr != 0)
|
||||||
|
ptr -= substream->runtime->dma_addr;
|
||||||
#endif
|
#endif
|
||||||
#ifdef EBUS_SUPPORT
|
#ifdef EBUS_SUPPORT
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
ptr += period_bytes - residue;
|
|
||||||
return bytes_to_frames(substream->runtime, ptr);
|
return bytes_to_frames(substream->runtime, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1983,6 +2063,8 @@ static int __init snd_cs4231_sbus_create(snd_card_t *card,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
spin_lock_init(&chip->lock);
|
spin_lock_init(&chip->lock);
|
||||||
|
spin_lock_init(&chip->sb2c.lock);
|
||||||
|
spin_lock_init(&chip->sb2p.lock);
|
||||||
init_MUTEX(&chip->mce_mutex);
|
init_MUTEX(&chip->mce_mutex);
|
||||||
init_MUTEX(&chip->open_mutex);
|
init_MUTEX(&chip->open_mutex);
|
||||||
chip->card = card;
|
chip->card = card;
|
||||||
@ -1998,6 +2080,11 @@ static int __init snd_cs4231_sbus_create(snd_card_t *card,
|
|||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chip->sb2c.regs = chip->port;
|
||||||
|
chip->sb2p.regs = chip->port;
|
||||||
|
chip->sb2c.dir = APC_RECORD;
|
||||||
|
chip->sb2p.dir = APC_PLAY;
|
||||||
|
|
||||||
if (request_irq(sdev->irqs[0], snd_cs4231_sbus_interrupt,
|
if (request_irq(sdev->irqs[0], snd_cs4231_sbus_interrupt,
|
||||||
SA_SHIRQ, "cs4231", chip)) {
|
SA_SHIRQ, "cs4231", chip)) {
|
||||||
snd_printdd("cs4231-%d: Unable to grab SBUS IRQ %s\n",
|
snd_printdd("cs4231-%d: Unable to grab SBUS IRQ %s\n",
|
||||||
|
Loading…
Reference in New Issue
Block a user