diff options
| -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", |
