diff options
author | Georg Chini <georg.chini@triaton-webhosting.com> | 2005-11-07 17:08:25 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2005-11-07 17:08:25 -0500 |
commit | 5a820fa7e1a34f12fec4e6766e5c335ae9427028 (patch) | |
tree | f2cf3a0747fd71cc817a6bfe565d73b60370a6b2 /sound | |
parent | ee1858d3122dedd2e82a61b6ab56b229aefd9447 (diff) |
[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>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/sparc/cs4231.c | 311 |
1 files changed, 199 insertions, 112 deletions
diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c index f4361c518e46..110d64d4848d 100644 --- a/sound/sparc/cs4231.c +++ b/sound/sparc/cs4231.c | |||
@@ -61,6 +61,14 @@ MODULE_DESCRIPTION("Sun CS4231"); | |||
61 | MODULE_LICENSE("GPL"); | 61 | MODULE_LICENSE("GPL"); |
62 | MODULE_SUPPORTED_DEVICE("{{Sun,CS4231}}"); | 62 | MODULE_SUPPORTED_DEVICE("{{Sun,CS4231}}"); |
63 | 63 | ||
64 | #ifdef SBUS_SUPPORT | ||
65 | struct sbus_dma_info { | ||
66 | spinlock_t lock; | ||
67 | int dir; | ||
68 | void __iomem *regs; | ||
69 | }; | ||
70 | #endif | ||
71 | |||
64 | typedef struct snd_cs4231 { | 72 | typedef struct snd_cs4231 { |
65 | spinlock_t lock; | 73 | spinlock_t lock; |
66 | void __iomem *port; | 74 | void __iomem *port; |
@@ -69,6 +77,11 @@ typedef struct snd_cs4231 { | |||
69 | struct ebus_dma_info eb2p; | 77 | struct ebus_dma_info eb2p; |
70 | #endif | 78 | #endif |
71 | 79 | ||
80 | #ifdef SBUS_SUPPORT | ||
81 | struct sbus_dma_info sb2c; | ||
82 | struct sbus_dma_info sb2p; | ||
83 | #endif | ||
84 | |||
72 | u32 flags; | 85 | u32 flags; |
73 | #define CS4231_FLAG_EBUS 0x00000001 | 86 | #define CS4231_FLAG_EBUS 0x00000001 |
74 | #define CS4231_FLAG_PLAYBACK 0x00000002 | 87 | #define CS4231_FLAG_PLAYBACK 0x00000002 |
@@ -251,6 +264,15 @@ static cs4231_t *cs4231_list; | |||
251 | #define APCPNVA 0x38UL /* APC Play DMA Next Address */ | 264 | #define APCPNVA 0x38UL /* APC Play DMA Next Address */ |
252 | #define APCPNC 0x3cUL /* APC Play Next Count */ | 265 | #define APCPNC 0x3cUL /* APC Play Next Count */ |
253 | 266 | ||
267 | /* Defines for SBUS DMA-routines */ | ||
268 | |||
269 | #define APCVA 0x0UL /* APC DMA Address */ | ||
270 | #define APCC 0x4UL /* APC Count */ | ||
271 | #define APCNVA 0x8UL /* APC DMA Next Address */ | ||
272 | #define APCNC 0xcUL /* APC Next Count */ | ||
273 | #define APC_PLAY 0x30UL /* Play registers start at 0x30 */ | ||
274 | #define APC_RECORD 0x20UL /* Record registers start at 0x20 */ | ||
275 | |||
254 | /* APCCSR bits */ | 276 | /* APCCSR bits */ |
255 | 277 | ||
256 | #define APC_INT_PENDING 0x800000 /* Interrupt Pending */ | 278 | #define APC_INT_PENDING 0x800000 /* Interrupt Pending */ |
@@ -472,6 +494,103 @@ static unsigned char snd_cs4231_in(cs4231_t *chip, unsigned char reg) | |||
472 | } | 494 | } |
473 | 495 | ||
474 | /* | 496 | /* |
497 | * SBUS DMA routines | ||
498 | */ | ||
499 | #ifdef SBUS_SUPPORT | ||
500 | |||
501 | int sbus_dma_request(struct sbus_dma_info *base, dma_addr_t bus_addr, size_t len) | ||
502 | { | ||
503 | unsigned long flags; | ||
504 | u32 test, csr; | ||
505 | int err; | ||
506 | |||
507 | if (len >= (1 << 24)) | ||
508 | return -EINVAL; | ||
509 | spin_lock_irqsave(&base->lock, flags); | ||
510 | csr = sbus_readl(base->regs + APCCSR); | ||
511 | err = -EINVAL; | ||
512 | test = APC_CDMA_READY; | ||
513 | if ( base->dir == APC_PLAY ) | ||
514 | test = APC_PDMA_READY; | ||
515 | if (!(csr & test)) | ||
516 | goto out; | ||
517 | err = -EBUSY; | ||
518 | csr = sbus_readl(base->regs + APCCSR); | ||
519 | test = APC_XINT_CNVA; | ||
520 | if ( base->dir == APC_PLAY ) | ||
521 | test = APC_XINT_PNVA; | ||
522 | if (!(csr & test)) | ||
523 | goto out; | ||
524 | err = 0; | ||
525 | sbus_writel(bus_addr, base->regs + base->dir + APCNVA); | ||
526 | sbus_writel(len, base->regs + base->dir + APCNC); | ||
527 | out: | ||
528 | spin_unlock_irqrestore(&base->lock, flags); | ||
529 | return err; | ||
530 | } | ||
531 | |||
532 | void sbus_dma_prepare(struct sbus_dma_info *base) | ||
533 | { | ||
534 | unsigned long flags; | ||
535 | u32 csr, test; | ||
536 | |||
537 | spin_lock_irqsave(&base->lock, flags); | ||
538 | csr = sbus_readl(base->regs + APCCSR); | ||
539 | test = APC_GENL_INT | APC_PLAY_INT | APC_XINT_ENA | | ||
540 | APC_XINT_PLAY | APC_XINT_PEMP | APC_XINT_GENL | | ||
541 | APC_XINT_PENA; | ||
542 | if ( base->dir == APC_RECORD ) | ||
543 | test = APC_GENL_INT | APC_CAPT_INT | APC_XINT_ENA | | ||
544 | APC_XINT_CAPT | APC_XINT_CEMP | APC_XINT_GENL; | ||
545 | csr |= test; | ||
546 | sbus_writel(csr, base->regs + APCCSR); | ||
547 | spin_unlock_irqrestore(&base->lock, flags); | ||
548 | } | ||
549 | |||
550 | void sbus_dma_enable(struct sbus_dma_info *base, int on) | ||
551 | { | ||
552 | unsigned long flags; | ||
553 | u32 csr, shift; | ||
554 | |||
555 | spin_lock_irqsave(&base->lock, flags); | ||
556 | if (!on) { | ||
557 | if (base->dir == APC_PLAY) { | ||
558 | sbus_writel(0, base->regs + base->dir + APCNVA); | ||
559 | sbus_writel(1, base->regs + base->dir + APCC); | ||
560 | } | ||
561 | else | ||
562 | { | ||
563 | sbus_writel(0, base->regs + base->dir + APCNC); | ||
564 | sbus_writel(0, base->regs + base->dir + APCVA); | ||
565 | } | ||
566 | } | ||
567 | udelay(500); | ||
568 | csr = sbus_readl(base->regs + APCCSR); | ||
569 | shift = 0; | ||
570 | if ( base->dir == APC_PLAY ) | ||
571 | shift = 1; | ||
572 | if (on) | ||
573 | csr &= ~(APC_CPAUSE << shift); | ||
574 | else | ||
575 | csr |= (APC_CPAUSE << shift); | ||
576 | sbus_writel(csr, base->regs + APCCSR); | ||
577 | if (on) | ||
578 | csr |= (APC_CDMA_READY << shift); | ||
579 | else | ||
580 | csr &= ~(APC_CDMA_READY << shift); | ||
581 | sbus_writel(csr, base->regs + APCCSR); | ||
582 | |||
583 | spin_unlock_irqrestore(&base->lock, flags); | ||
584 | } | ||
585 | |||
586 | unsigned int sbus_dma_addr(struct sbus_dma_info *base) | ||
587 | { | ||
588 | return sbus_readl(base->regs + base->dir + APCVA); | ||
589 | } | ||
590 | |||
591 | #endif | ||
592 | |||
593 | /* | ||
475 | * CS4231 detection / MCE routines | 594 | * CS4231 detection / MCE routines |
476 | */ | 595 | */ |
477 | 596 | ||
@@ -589,29 +708,21 @@ static void snd_cs4231_ebus_advance_dma(struct ebus_dma_info *p, snd_pcm_substre | |||
589 | #endif | 708 | #endif |
590 | 709 | ||
591 | #ifdef SBUS_SUPPORT | 710 | #ifdef SBUS_SUPPORT |
592 | static void snd_cs4231_sbus_advance_dma(snd_pcm_substream_t *substream, unsigned int *periods_sent) | 711 | static void snd_cs4231_sbus_advance_dma(struct sbus_dma_info *p, snd_pcm_substream_t *substream, unsigned int *periods_sent) |
593 | { | 712 | { |
594 | cs4231_t *chip = snd_pcm_substream_chip(substream); | ||
595 | snd_pcm_runtime_t *runtime = substream->runtime; | 713 | snd_pcm_runtime_t *runtime = substream->runtime; |
596 | 714 | ||
597 | unsigned int period_size = snd_pcm_lib_period_bytes(substream); | 715 | while (1) { |
598 | unsigned int offset = period_size * (*periods_sent % runtime->periods); | 716 | unsigned int period_size = snd_pcm_lib_period_bytes(substream); |
599 | 717 | unsigned int offset = period_size * (*periods_sent); | |
600 | if (runtime->period_size > 0xffff + 1) | ||
601 | BUG(); | ||
602 | |||
603 | switch (substream->stream) { | ||
604 | case SNDRV_PCM_STREAM_PLAYBACK: | ||
605 | sbus_writel(runtime->dma_addr + offset, chip->port + APCPNVA); | ||
606 | sbus_writel(period_size, chip->port + APCPNC); | ||
607 | break; | ||
608 | case SNDRV_PCM_STREAM_CAPTURE: | ||
609 | sbus_writel(runtime->dma_addr + offset, chip->port + APCCNVA); | ||
610 | sbus_writel(period_size, chip->port + APCCNC); | ||
611 | break; | ||
612 | } | ||
613 | 718 | ||
614 | (*periods_sent) = (*periods_sent + 1) % runtime->periods; | 719 | if (period_size > 0xffff + 1) |
720 | BUG(); | ||
721 | |||
722 | if (sbus_dma_request(p, runtime->dma_addr + offset, period_size)) | ||
723 | return; | ||
724 | (*periods_sent) = (*periods_sent + 1) % runtime->periods; | ||
725 | } | ||
615 | } | 726 | } |
616 | #endif | 727 | #endif |
617 | 728 | ||
@@ -646,59 +757,27 @@ static void cs4231_dma_trigger(snd_pcm_substream_t *substream, unsigned int what | |||
646 | } else { | 757 | } else { |
647 | #endif | 758 | #endif |
648 | #ifdef SBUS_SUPPORT | 759 | #ifdef SBUS_SUPPORT |
649 | u32 csr = sbus_readl(chip->port + APCCSR); | 760 | if (what & CS4231_PLAYBACK_ENABLE) { |
650 | /* I don't know why, but on sbus the period counter must | ||
651 | * only start counting after the first period is sent. | ||
652 | * Therefore this dummy thing. | ||
653 | */ | ||
654 | unsigned int dummy = 0; | ||
655 | |||
656 | switch (what) { | ||
657 | case CS4231_PLAYBACK_ENABLE: | ||
658 | if (on) { | 761 | if (on) { |
659 | csr &= ~APC_XINT_PLAY; | 762 | sbus_dma_prepare(&chip->sb2p); |
660 | sbus_writel(csr, chip->port + APCCSR); | 763 | sbus_dma_enable(&chip->sb2p, 1); |
661 | 764 | snd_cs4231_sbus_advance_dma(&chip->sb2p, | |
662 | csr &= ~APC_PPAUSE; | 765 | chip->playback_substream, |
663 | sbus_writel(csr, chip->port + APCCSR); | 766 | &chip->p_periods_sent); |
664 | |||
665 | snd_cs4231_sbus_advance_dma(substream, &dummy); | ||
666 | |||
667 | csr |= APC_GENL_INT | APC_PLAY_INT | APC_XINT_ENA | | ||
668 | APC_XINT_PLAY | APC_XINT_EMPT | APC_XINT_GENL | | ||
669 | APC_XINT_PENA | APC_PDMA_READY; | ||
670 | sbus_writel(csr, chip->port + APCCSR); | ||
671 | } else { | 767 | } else { |
672 | csr |= APC_PPAUSE; | 768 | sbus_dma_enable(&chip->sb2p, 0); |
673 | sbus_writel(csr, chip->port + APCCSR); | ||
674 | |||
675 | csr &= ~APC_PDMA_READY; | ||
676 | sbus_writel(csr, chip->port + APCCSR); | ||
677 | } | 769 | } |
678 | break; | 770 | } |
679 | case CS4231_RECORD_ENABLE: | 771 | if (what & CS4231_RECORD_ENABLE) { |
680 | if (on) { | 772 | if (on) { |
681 | csr &= ~APC_XINT_CAPT; | 773 | sbus_dma_prepare(&chip->sb2c); |
682 | sbus_writel(csr, chip->port + APCCSR); | 774 | sbus_dma_enable(&chip->sb2c, 1); |
683 | 775 | snd_cs4231_sbus_advance_dma(&chip->sb2c, | |
684 | csr &= ~APC_CPAUSE; | 776 | chip->capture_substream, |
685 | sbus_writel(csr, chip->port + APCCSR); | 777 | &chip->c_periods_sent); |
686 | |||
687 | snd_cs4231_sbus_advance_dma(substream, &dummy); | ||
688 | |||
689 | csr |= APC_GENL_INT | APC_CAPT_INT | APC_XINT_ENA | | ||
690 | APC_XINT_CAPT | APC_XINT_CEMP | APC_XINT_GENL | | ||
691 | APC_CDMA_READY; | ||
692 | |||
693 | sbus_writel(csr, chip->port + APCCSR); | ||
694 | } else { | 778 | } else { |
695 | csr |= APC_CPAUSE; | 779 | sbus_dma_enable(&chip->sb2c, 0); |
696 | sbus_writel(csr, chip->port + APCCSR); | ||
697 | |||
698 | csr &= ~APC_CDMA_READY; | ||
699 | sbus_writel(csr, chip->port + APCCSR); | ||
700 | } | 780 | } |
701 | break; | ||
702 | } | 781 | } |
703 | #endif | 782 | #endif |
704 | #ifdef EBUS_SUPPORT | 783 | #ifdef EBUS_SUPPORT |
@@ -1136,10 +1215,7 @@ static int snd_cs4231_playback_prepare(snd_pcm_substream_t *substream) | |||
1136 | if (runtime->period_size > 0xffff + 1) | 1215 | if (runtime->period_size > 0xffff + 1) |
1137 | BUG(); | 1216 | BUG(); |
1138 | 1217 | ||
1139 | snd_cs4231_out(chip, CS4231_PLY_LWR_CNT, (runtime->period_size - 1) & 0x00ff); | ||
1140 | snd_cs4231_out(chip, CS4231_PLY_UPR_CNT, (runtime->period_size - 1) >> 8 & 0x00ff); | ||
1141 | chip->p_periods_sent = 0; | 1218 | chip->p_periods_sent = 0; |
1142 | |||
1143 | spin_unlock_irqrestore(&chip->lock, flags); | 1219 | spin_unlock_irqrestore(&chip->lock, flags); |
1144 | 1220 | ||
1145 | return 0; | 1221 | return 0; |
@@ -1171,16 +1247,14 @@ static int snd_cs4231_capture_hw_free(snd_pcm_substream_t *substream) | |||
1171 | static int snd_cs4231_capture_prepare(snd_pcm_substream_t *substream) | 1247 | static int snd_cs4231_capture_prepare(snd_pcm_substream_t *substream) |
1172 | { | 1248 | { |
1173 | cs4231_t *chip = snd_pcm_substream_chip(substream); | 1249 | cs4231_t *chip = snd_pcm_substream_chip(substream); |
1174 | snd_pcm_runtime_t *runtime = substream->runtime; | ||
1175 | unsigned long flags; | 1250 | unsigned long flags; |
1176 | 1251 | ||
1177 | spin_lock_irqsave(&chip->lock, flags); | 1252 | spin_lock_irqsave(&chip->lock, flags); |
1178 | chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE | | 1253 | chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE | |
1179 | CS4231_RECORD_PIO); | 1254 | CS4231_RECORD_PIO); |
1180 | 1255 | ||
1181 | snd_cs4231_out(chip, CS4231_REC_LWR_CNT, (runtime->period_size - 1) & 0x00ff); | ||
1182 | snd_cs4231_out(chip, CS4231_REC_LWR_CNT, (runtime->period_size - 1) >> 8 & 0x00ff); | ||
1183 | 1256 | ||
1257 | chip->c_periods_sent = 0; | ||
1184 | spin_unlock_irqrestore(&chip->lock, flags); | 1258 | spin_unlock_irqrestore(&chip->lock, flags); |
1185 | 1259 | ||
1186 | return 0; | 1260 | return 0; |
@@ -1199,40 +1273,20 @@ static void snd_cs4231_overrange(cs4231_t *chip) | |||
1199 | chip->capture_substream->runtime->overrange++; | 1273 | chip->capture_substream->runtime->overrange++; |
1200 | } | 1274 | } |
1201 | 1275 | ||
1202 | static irqreturn_t snd_cs4231_generic_interrupt(cs4231_t *chip) | 1276 | #ifdef SBUS_SUPPORT |
1277 | static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
1203 | { | 1278 | { |
1204 | unsigned long flags; | 1279 | unsigned long flags; |
1205 | unsigned char status; | 1280 | unsigned char status; |
1281 | u32 csr; | ||
1282 | cs4231_t *chip = dev_id; | ||
1206 | 1283 | ||
1207 | /*This is IRQ is not raised by the cs4231*/ | 1284 | /*This is IRQ is not raised by the cs4231*/ |
1208 | if (!(__cs4231_readb(chip, CS4231P(chip, STATUS)) & CS4231_GLOBALIRQ)) | 1285 | if (!(__cs4231_readb(chip, CS4231P(chip, STATUS)) & CS4231_GLOBALIRQ)) |
1209 | return IRQ_NONE; | 1286 | return IRQ_NONE; |
1210 | 1287 | ||
1211 | status = snd_cs4231_in(chip, CS4231_IRQ_STATUS); | ||
1212 | |||
1213 | if (status & CS4231_TIMER_IRQ) { | ||
1214 | if (chip->timer) | ||
1215 | snd_timer_interrupt(chip->timer, chip->timer->sticks); | ||
1216 | } | ||
1217 | |||
1218 | if (status & CS4231_RECORD_IRQ) | ||
1219 | snd_cs4231_overrange(chip); | ||
1220 | |||
1221 | /* ACK the CS4231 interrupt. */ | ||
1222 | spin_lock_irqsave(&chip->lock, flags); | ||
1223 | snd_cs4231_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0); | ||
1224 | spin_unlock_irqrestore(&chip->lock, flags); | ||
1225 | |||
1226 | return 0; | ||
1227 | } | ||
1228 | |||
1229 | #ifdef SBUS_SUPPORT | ||
1230 | static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id, struct pt_regs *regs) | ||
1231 | { | ||
1232 | cs4231_t *chip = dev_id; | ||
1233 | |||
1234 | /* ACK the APC interrupt. */ | 1288 | /* ACK the APC interrupt. */ |
1235 | u32 csr = sbus_readl(chip->port + APCCSR); | 1289 | csr = sbus_readl(chip->port + APCCSR); |
1236 | 1290 | ||
1237 | sbus_writel(csr, chip->port + APCCSR); | 1291 | sbus_writel(csr, chip->port + APCCSR); |
1238 | 1292 | ||
@@ -1240,20 +1294,36 @@ static irqreturn_t snd_cs4231_sbus_interrupt(int irq, void *dev_id, struct pt_re | |||
1240 | (csr & APC_PLAY_INT) && | 1294 | (csr & APC_PLAY_INT) && |
1241 | (csr & APC_XINT_PNVA) && | 1295 | (csr & APC_XINT_PNVA) && |
1242 | !(csr & APC_XINT_EMPT)) { | 1296 | !(csr & APC_XINT_EMPT)) { |
1243 | snd_cs4231_sbus_advance_dma(chip->playback_substream, | ||
1244 | &chip->p_periods_sent); | ||
1245 | snd_pcm_period_elapsed(chip->playback_substream); | 1297 | snd_pcm_period_elapsed(chip->playback_substream); |
1298 | snd_cs4231_sbus_advance_dma(&chip->sb2p, chip->playback_substream, | ||
1299 | &chip->p_periods_sent); | ||
1246 | } | 1300 | } |
1247 | 1301 | ||
1248 | if ((chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) && | 1302 | if ((chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE) && |
1249 | (csr & APC_CAPT_INT) && | 1303 | (csr & APC_CAPT_INT) && |
1250 | (csr & APC_XINT_CNVA)) { | 1304 | (csr & APC_XINT_CNVA) && |
1251 | snd_cs4231_sbus_advance_dma(chip->capture_substream, | 1305 | !(csr & APC_XINT_EMPT)) { |
1252 | &chip->c_periods_sent); | ||
1253 | snd_pcm_period_elapsed(chip->capture_substream); | 1306 | snd_pcm_period_elapsed(chip->capture_substream); |
1307 | snd_cs4231_sbus_advance_dma(&chip->sb2c,chip->capture_substream, | ||
1308 | &chip->c_periods_sent); | ||
1254 | } | 1309 | } |
1310 | |||
1311 | status = snd_cs4231_in(chip, CS4231_IRQ_STATUS); | ||
1312 | |||
1313 | if (status & CS4231_TIMER_IRQ) { | ||
1314 | if (chip->timer) | ||
1315 | snd_timer_interrupt(chip->timer, chip->timer->sticks); | ||
1316 | } | ||
1317 | |||
1318 | if (status & CS4231_RECORD_IRQ) | ||
1319 | snd_cs4231_overrange(chip); | ||
1255 | 1320 | ||
1256 | return snd_cs4231_generic_interrupt(chip); | 1321 | /* ACK the CS4231 interrupt. */ |
1322 | spin_lock_irqsave(&chip->lock, flags); | ||
1323 | snd_cs4231_outm(chip, CS4231_IRQ_STATUS, ~CS4231_ALL_IRQS | ~status, 0); | ||
1324 | spin_unlock_irqrestore(&chip->lock, flags); | ||
1325 | |||
1326 | return 0; | ||
1257 | } | 1327 | } |
1258 | #endif | 1328 | #endif |
1259 | 1329 | ||
@@ -1284,24 +1354,29 @@ static void snd_cs4231_ebus_capture_callback(struct ebus_dma_info *p, int event, | |||
1284 | static snd_pcm_uframes_t snd_cs4231_playback_pointer(snd_pcm_substream_t *substream) | 1354 | static snd_pcm_uframes_t snd_cs4231_playback_pointer(snd_pcm_substream_t *substream) |
1285 | { | 1355 | { |
1286 | cs4231_t *chip = snd_pcm_substream_chip(substream); | 1356 | cs4231_t *chip = snd_pcm_substream_chip(substream); |
1287 | size_t ptr, residue, period_bytes; | 1357 | size_t ptr; |
1288 | 1358 | #ifdef EBUS_SUPPORT | |
1359 | size_t residue, period_bytes; | ||
1360 | #endif | ||
1361 | |||
1289 | if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) | 1362 | if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_PLAYBACK_ENABLE)) |
1290 | return 0; | 1363 | return 0; |
1364 | #ifdef EBUS_SUPPORT | ||
1291 | period_bytes = snd_pcm_lib_period_bytes(substream); | 1365 | period_bytes = snd_pcm_lib_period_bytes(substream); |
1292 | ptr = period_bytes * chip->p_periods_sent; | 1366 | ptr = period_bytes * chip->p_periods_sent; |
1293 | #ifdef EBUS_SUPPORT | ||
1294 | if (chip->flags & CS4231_FLAG_EBUS) { | 1367 | if (chip->flags & CS4231_FLAG_EBUS) { |
1295 | residue = ebus_dma_residue(&chip->eb2p); | 1368 | residue = ebus_dma_residue(&chip->eb2p); |
1369 | ptr += period_bytes - residue; | ||
1296 | } else { | 1370 | } else { |
1297 | #endif | 1371 | #endif |
1298 | #ifdef SBUS_SUPPORT | 1372 | #ifdef SBUS_SUPPORT |
1299 | residue = sbus_readl(chip->port + APCPC); | 1373 | ptr = sbus_dma_addr(&chip->sb2p); |
1374 | if (ptr != 0) | ||
1375 | ptr -= substream->runtime->dma_addr; | ||
1300 | #endif | 1376 | #endif |
1301 | #ifdef EBUS_SUPPORT | 1377 | #ifdef EBUS_SUPPORT |
1302 | } | 1378 | } |
1303 | #endif | 1379 | #endif |
1304 | ptr += period_bytes - residue; | ||
1305 | 1380 | ||
1306 | return bytes_to_frames(substream->runtime, ptr); | 1381 | return bytes_to_frames(substream->runtime, ptr); |
1307 | } | 1382 | } |
@@ -1309,24 +1384,29 @@ static snd_pcm_uframes_t snd_cs4231_playback_pointer(snd_pcm_substream_t *substr | |||
1309 | static snd_pcm_uframes_t snd_cs4231_capture_pointer(snd_pcm_substream_t * substream) | 1384 | static snd_pcm_uframes_t snd_cs4231_capture_pointer(snd_pcm_substream_t * substream) |
1310 | { | 1385 | { |
1311 | cs4231_t *chip = snd_pcm_substream_chip(substream); | 1386 | cs4231_t *chip = snd_pcm_substream_chip(substream); |
1312 | size_t ptr, residue, period_bytes; | 1387 | size_t ptr; |
1388 | #ifdef EBUS_SUPPORT | ||
1389 | size_t residue, period_bytes; | ||
1390 | #endif | ||
1313 | 1391 | ||
1314 | if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE)) | 1392 | if (!(chip->image[CS4231_IFACE_CTRL] & CS4231_RECORD_ENABLE)) |
1315 | return 0; | 1393 | return 0; |
1394 | #ifdef EBUS_SUPPORT | ||
1316 | period_bytes = snd_pcm_lib_period_bytes(substream); | 1395 | period_bytes = snd_pcm_lib_period_bytes(substream); |
1317 | ptr = period_bytes * chip->c_periods_sent; | 1396 | ptr = period_bytes * chip->c_periods_sent; |
1318 | #ifdef EBUS_SUPPORT | ||
1319 | if (chip->flags & CS4231_FLAG_EBUS) { | 1397 | if (chip->flags & CS4231_FLAG_EBUS) { |
1320 | residue = ebus_dma_residue(&chip->eb2c); | 1398 | residue = ebus_dma_residue(&chip->eb2c); |
1399 | ptr += period_bytes - residue; | ||
1321 | } else { | 1400 | } else { |
1322 | #endif | 1401 | #endif |
1323 | #ifdef SBUS_SUPPORT | 1402 | #ifdef SBUS_SUPPORT |
1324 | residue = sbus_readl(chip->port + APCCC); | 1403 | ptr = sbus_dma_addr(&chip->sb2c); |
1404 | if (ptr != 0) | ||
1405 | ptr -= substream->runtime->dma_addr; | ||
1325 | #endif | 1406 | #endif |
1326 | #ifdef EBUS_SUPPORT | 1407 | #ifdef EBUS_SUPPORT |
1327 | } | 1408 | } |
1328 | #endif | 1409 | #endif |
1329 | ptr += period_bytes - residue; | ||
1330 | return bytes_to_frames(substream->runtime, ptr); | 1410 | return bytes_to_frames(substream->runtime, ptr); |
1331 | } | 1411 | } |
1332 | 1412 | ||
@@ -1983,6 +2063,8 @@ static int __init snd_cs4231_sbus_create(snd_card_t *card, | |||
1983 | return -ENOMEM; | 2063 | return -ENOMEM; |
1984 | 2064 | ||
1985 | spin_lock_init(&chip->lock); | 2065 | spin_lock_init(&chip->lock); |
2066 | spin_lock_init(&chip->sb2c.lock); | ||
2067 | spin_lock_init(&chip->sb2p.lock); | ||
1986 | init_MUTEX(&chip->mce_mutex); | 2068 | init_MUTEX(&chip->mce_mutex); |
1987 | init_MUTEX(&chip->open_mutex); | 2069 | init_MUTEX(&chip->open_mutex); |
1988 | chip->card = card; | 2070 | chip->card = card; |
@@ -1998,6 +2080,11 @@ static int __init snd_cs4231_sbus_create(snd_card_t *card, | |||
1998 | return -EIO; | 2080 | return -EIO; |
1999 | } | 2081 | } |
2000 | 2082 | ||
2083 | chip->sb2c.regs = chip->port; | ||
2084 | chip->sb2p.regs = chip->port; | ||
2085 | chip->sb2c.dir = APC_RECORD; | ||
2086 | chip->sb2p.dir = APC_PLAY; | ||
2087 | |||
2001 | if (request_irq(sdev->irqs[0], snd_cs4231_sbus_interrupt, | 2088 | if (request_irq(sdev->irqs[0], snd_cs4231_sbus_interrupt, |
2002 | SA_SHIRQ, "cs4231", chip)) { | 2089 | SA_SHIRQ, "cs4231", chip)) { |
2003 | snd_printdd("cs4231-%d: Unable to grab SBUS IRQ %s\n", | 2090 | snd_printdd("cs4231-%d: Unable to grab SBUS IRQ %s\n", |