diff options
author | Krzysztof Helt <krzysztof.h1@wp.pl> | 2006-08-21 13:30:57 -0400 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2006-09-23 04:42:33 -0400 |
commit | 1be54c824be9b5e163cd83dabdf0ad3ac81c72a8 (patch) | |
tree | 1a559701342e767a6add56a9e7960f26c1baba4c /sound/sparc | |
parent | 294a30dc8cf13c492913f2ed3a6540bdf6e84e39 (diff) |
[ALSA] sparc dbri: ring buffered version
It is a complete rework of low level layer to work on ring
buffers for comands and data descriptors. This removes annoying
noise due to delay in data buffer switching.
Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound/sparc')
-rw-r--r-- | sound/sparc/dbri.c | 385 |
1 files changed, 192 insertions, 193 deletions
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index 5696f792e3d1..3fb2ede80eaf 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c | |||
@@ -2,6 +2,8 @@ | |||
2 | * Driver for DBRI sound chip found on Sparcs. | 2 | * Driver for DBRI sound chip found on Sparcs. |
3 | * Copyright (C) 2004, 2005 Martin Habets (mhabets@users.sourceforge.net) | 3 | * Copyright (C) 2004, 2005 Martin Habets (mhabets@users.sourceforge.net) |
4 | * | 4 | * |
5 | * Converted to ring buffered version by Krzysztof Helt (krzysztof.h1@wp.pl) | ||
6 | * | ||
5 | * Based entirely upon drivers/sbus/audio/dbri.c which is: | 7 | * Based entirely upon drivers/sbus/audio/dbri.c which is: |
6 | * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de) | 8 | * Copyright (C) 1997 Rudolf Koenig (rfkoenig@immd4.informatik.uni-erlangen.de) |
7 | * Copyright (C) 1998, 1999 Brent Baccala (baccala@freesoft.org) | 9 | * Copyright (C) 1998, 1999 Brent Baccala (baccala@freesoft.org) |
@@ -260,7 +262,7 @@ struct dbri_mem { | |||
260 | * the CPU and the DBRI | 262 | * the CPU and the DBRI |
261 | */ | 263 | */ |
262 | struct dbri_dma { | 264 | struct dbri_dma { |
263 | volatile s32 cmd[DBRI_NO_CMDS]; /* Place for commands */ | 265 | s32 cmd[DBRI_NO_CMDS]; /* Place for commands */ |
264 | volatile s32 intr[DBRI_INT_BLK]; /* Interrupt field */ | 266 | volatile s32 intr[DBRI_INT_BLK]; /* Interrupt field */ |
265 | struct dbri_mem desc[DBRI_NO_DESCS]; /* Xmit/receive descriptors */ | 267 | struct dbri_mem desc[DBRI_NO_DESCS]; /* Xmit/receive descriptors */ |
266 | }; | 268 | }; |
@@ -284,7 +286,6 @@ struct dbri_pipe { | |||
284 | struct dbri_streaminfo { | 286 | struct dbri_streaminfo { |
285 | struct snd_pcm_substream *substream; | 287 | struct snd_pcm_substream *substream; |
286 | u32 dvma_buffer; /* Device view of Alsa DMA buffer */ | 288 | u32 dvma_buffer; /* Device view of Alsa DMA buffer */ |
287 | int left; /* # of bytes left in DMA buffer */ | ||
288 | int size; /* Size of DMA buffer */ | 289 | int size; /* Size of DMA buffer */ |
289 | size_t offset; /* offset in user buffer */ | 290 | size_t offset; /* offset in user buffer */ |
290 | int pipe; /* Data pipe used */ | 291 | int pipe; /* Data pipe used */ |
@@ -305,11 +306,11 @@ struct snd_dbri { | |||
305 | 306 | ||
306 | void __iomem *regs; /* dbri HW regs */ | 307 | void __iomem *regs; /* dbri HW regs */ |
307 | int dbri_irqp; /* intr queue pointer */ | 308 | int dbri_irqp; /* intr queue pointer */ |
308 | int wait_send; /* sequence of command buffers send */ | ||
309 | int wait_ackd; /* sequence of command buffers acknowledged */ | ||
310 | 309 | ||
311 | struct dbri_pipe pipes[DBRI_NO_PIPES]; /* DBRI's 32 data pipes */ | 310 | struct dbri_pipe pipes[DBRI_NO_PIPES]; /* DBRI's 32 data pipes */ |
312 | int next_desc[DBRI_NO_DESCS]; /* Index of next desc, or -1 */ | 311 | int next_desc[DBRI_NO_DESCS]; /* Index of next desc, or -1 */ |
312 | spinlock_t cmdlock; /* Protects cmd queue accesses */ | ||
313 | s32 *cmdptr; /* Pointer to the last queued cmd */ | ||
313 | 314 | ||
314 | int chi_bpf; | 315 | int chi_bpf; |
315 | 316 | ||
@@ -544,7 +545,7 @@ struct snd_dbri { | |||
544 | #define DBRI_TD_TBC (1<<0) /* Transmit buffer Complete */ | 545 | #define DBRI_TD_TBC (1<<0) /* Transmit buffer Complete */ |
545 | #define DBRI_TD_STATUS(v) ((v)&0xff) /* Transmit status */ | 546 | #define DBRI_TD_STATUS(v) ((v)&0xff) /* Transmit status */ |
546 | /* Maximum buffer size per TD: almost 8Kb */ | 547 | /* Maximum buffer size per TD: almost 8Kb */ |
547 | #define DBRI_TD_MAXCNT ((1 << 13) - 1) | 548 | #define DBRI_TD_MAXCNT ((1 << 13) - 4) |
548 | 549 | ||
549 | /* Receive descriptor defines */ | 550 | /* Receive descriptor defines */ |
550 | #define DBRI_RD_F (1<<31) /* End of Frame */ | 551 | #define DBRI_RD_F (1<<31) /* End of Frame */ |
@@ -608,79 +609,110 @@ The list is terminated with a WAIT command, which generates a | |||
608 | CPU interrupt to signal completion. | 609 | CPU interrupt to signal completion. |
609 | 610 | ||
610 | Since the DBRI can run in parallel with the CPU, several means of | 611 | Since the DBRI can run in parallel with the CPU, several means of |
611 | synchronization present themselves. The method implemented here is close | 612 | synchronization present themselves. The method implemented here is only |
612 | to the original scheme (Rudolf's), and uses 2 counters (wait_send and | 613 | to use the dbri_cmdwait() to wait for execution of batch of sent commands. |
613 | wait_ackd) to synchronize the command buffer between the CPU and the DBRI. | ||
614 | 614 | ||
615 | A more sophisticated scheme might involve a circular command buffer | 615 | A circular command buffer is used here. A new command is being added |
616 | or an array of command buffers. A routine could fill one with | 616 | while other can be executed. The scheme works by adding two WAIT commands |
617 | commands and link it onto a list. When a interrupt signaled | 617 | after each sent batch of commands. When the next batch is prepared it is |
618 | completion of the current command buffer, look on the list for | 618 | added after the WAIT commands then the WAITs are replaced with single JUMP |
619 | the next one. | 619 | command to the new batch. The the DBRI is forced to reread the last WAIT |
620 | command (replaced by the JUMP by then). If the DBRI is still executing | ||
621 | previous commands the request to reread the WAIT command is ignored. | ||
620 | 622 | ||
621 | Every time a routine wants to write commands to the DBRI, it must | 623 | Every time a routine wants to write commands to the DBRI, it must |
622 | first call dbri_cmdlock() and get an initial pointer into dbri->dma->cmd | 624 | first call dbri_cmdlock() and get pointer to a free space in |
623 | in return. dbri_cmdlock() will block if the previous commands have not | 625 | dbri->dma->cmd buffer. After this, the commands can be written to |
624 | been completed yet. After this the commands can be written to the buffer, | 626 | the buffer, and dbri_cmdsend() is called with the final pointer value |
625 | and dbri_cmdsend() is called with the final pointer value to send them | 627 | to send them to the DBRI. |
626 | to the DBRI. | ||
627 | 628 | ||
628 | */ | 629 | */ |
629 | 630 | ||
630 | static void dbri_process_interrupt_buffer(struct snd_dbri * dbri); | 631 | static void dbri_process_interrupt_buffer(struct snd_dbri * dbri); |
631 | 632 | ||
632 | enum dbri_lock { NoGetLock, GetLock }; | ||
633 | #define MAXLOOPS 10 | 633 | #define MAXLOOPS 10 |
634 | 634 | /* | |
635 | static volatile s32 *dbri_cmdlock(struct snd_dbri * dbri, enum dbri_lock get) | 635 | * Wait for the current command string to execute |
636 | */ | ||
637 | static void dbri_cmdwait(struct snd_dbri *dbri) | ||
636 | { | 638 | { |
637 | int maxloops = MAXLOOPS; | 639 | int maxloops = MAXLOOPS; |
638 | 640 | ||
639 | #ifndef SMP | ||
640 | if ((get == GetLock) && spin_is_locked(&dbri->lock)) { | ||
641 | printk(KERN_ERR "DBRI: cmdlock called while in spinlock."); | ||
642 | } | ||
643 | #endif | ||
644 | |||
645 | /* Delay if previous commands are still being processed */ | 641 | /* Delay if previous commands are still being processed */ |
646 | while ((--maxloops) > 0 && (dbri->wait_send != dbri->wait_ackd)) { | 642 | while ((--maxloops) > 0 && (sbus_readl(dbri->regs + REG0) & D_P)) |
647 | msleep_interruptible(1); | 643 | msleep_interruptible(1); |
648 | } | 644 | |
649 | if (maxloops == 0) { | 645 | if (maxloops == 0) { |
650 | printk(KERN_ERR "DBRI: Chip never completed command buffer %d\n", | 646 | printk(KERN_ERR "DBRI: Chip never completed command buffer\n"); |
651 | dbri->wait_send); | ||
652 | } else { | 647 | } else { |
653 | dprintk(D_CMD, "Chip completed command buffer (%d)\n", | 648 | dprintk(D_CMD, "Chip completed command buffer (%d)\n", |
654 | MAXLOOPS - maxloops - 1); | 649 | MAXLOOPS - maxloops - 1); |
655 | } | 650 | } |
651 | } | ||
652 | /* | ||
653 | * Lock the command queue and returns pointer to a space for len cmd words | ||
654 | * It locks the cmdlock spinlock. | ||
655 | */ | ||
656 | static s32 *dbri_cmdlock(struct snd_dbri * dbri, int len) | ||
657 | { | ||
658 | /* Space for 2 WAIT cmds (replaced later by 1 JUMP cmd) */ | ||
659 | len += 2; | ||
660 | spin_lock(&dbri->cmdlock); | ||
661 | if (dbri->cmdptr - dbri->dma->cmd + len < DBRI_NO_CMDS - 2) | ||
662 | return dbri->cmdptr + 2; | ||
663 | else if (len < sbus_readl(dbri->regs + REG8) - dbri->dma_dvma) | ||
664 | return dbri->dma->cmd; | ||
665 | else | ||
666 | printk(KERN_ERR "DBRI: no space for commands."); | ||
656 | 667 | ||
657 | /*if (get == GetLock) spin_lock(&dbri->lock); */ | 668 | return 0; |
658 | return &dbri->dma->cmd[0]; | ||
659 | } | 669 | } |
660 | 670 | ||
661 | static void dbri_cmdsend(struct snd_dbri * dbri, volatile s32 * cmd) | 671 | /* |
672 | * Send prepared cmd string. It works by writting a JMP cmd into | ||
673 | * the last WAIT cmd and force DBRI to reread the cmd. | ||
674 | * The JMP cmd points to the new cmd string. | ||
675 | * It also releases the cmdlock spinlock. | ||
676 | */ | ||
677 | static void dbri_cmdsend(struct snd_dbri * dbri, s32 * cmd,int len) | ||
662 | { | 678 | { |
663 | volatile s32 *ptr; | 679 | s32 *ptr; |
680 | s32 tmp, addr; | ||
681 | static int wait_id = 0; | ||
664 | 682 | ||
665 | for (ptr = &dbri->dma->cmd[0]; ptr < cmd; ptr++) { | 683 | wait_id++; |
666 | dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr); | 684 | wait_id &= 0xffff; /* restrict it to a 16 bit counter. */ |
667 | } | 685 | *(cmd) = DBRI_CMD(D_WAIT, 1, wait_id); |
686 | *(cmd+1) = DBRI_CMD(D_WAIT, 1, wait_id); | ||
668 | 687 | ||
669 | if ((cmd - &dbri->dma->cmd[0]) >= DBRI_NO_CMDS - 1) { | 688 | /* Replace the last command with JUMP */ |
670 | printk(KERN_ERR "DBRI: Command buffer overflow! (bug in driver)\n"); | 689 | addr = dbri->dma_dvma + (cmd - len - dbri->dma->cmd) * sizeof(s32); |
671 | /* Ignore the last part. */ | 690 | *(dbri->cmdptr+1) = addr; |
672 | cmd = &dbri->dma->cmd[DBRI_NO_CMDS - 3]; | 691 | *(dbri->cmdptr) = DBRI_CMD(D_JUMP, 0, 0); |
673 | } | ||
674 | 692 | ||
675 | dbri->wait_send++; | 693 | #ifdef DBRI_DEBUG |
676 | dbri->wait_send &= 0xffff; /* restrict it to a 16 bit counter. */ | 694 | if (cmd > dbri->cmdptr ) |
677 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); | 695 | for (ptr = dbri->cmdptr; ptr < cmd+2; ptr++) { |
678 | *(cmd++) = DBRI_CMD(D_WAIT, 1, dbri->wait_send); | 696 | dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr); |
697 | } | ||
698 | else { | ||
699 | ptr = dbri->cmdptr; | ||
700 | dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr); | ||
701 | ptr = dbri->cmdptr+1; | ||
702 | dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr); | ||
703 | for (ptr = dbri->dma->cmd; ptr < cmd+2; ptr++) { | ||
704 | dprintk(D_CMD, "cmd: %lx:%08x\n", (unsigned long)ptr, *ptr); | ||
705 | } | ||
706 | } | ||
707 | #endif | ||
679 | 708 | ||
680 | /* Set command pointer and signal it is valid. */ | 709 | /* Reread the last command */ |
681 | sbus_writel(dbri->dma_dvma, dbri->regs + REG8); | 710 | tmp = sbus_readl(dbri->regs + REG0); |
711 | tmp |= D_P; | ||
712 | sbus_writel(tmp, dbri->regs + REG0); | ||
682 | 713 | ||
683 | /*spin_unlock(&dbri->lock); */ | 714 | dbri->cmdptr = cmd; |
715 | spin_unlock(&dbri->cmdlock); | ||
684 | } | 716 | } |
685 | 717 | ||
686 | /* Lock must be held when calling this */ | 718 | /* Lock must be held when calling this */ |
@@ -709,7 +741,7 @@ static void dbri_reset(struct snd_dbri * dbri) | |||
709 | /* Lock must not be held before calling this */ | 741 | /* Lock must not be held before calling this */ |
710 | static void dbri_initialize(struct snd_dbri * dbri) | 742 | static void dbri_initialize(struct snd_dbri * dbri) |
711 | { | 743 | { |
712 | volatile s32 *cmd; | 744 | s32 *cmd; |
713 | u32 dma_addr; | 745 | u32 dma_addr; |
714 | unsigned long flags; | 746 | unsigned long flags; |
715 | int n; | 747 | int n; |
@@ -718,14 +750,11 @@ static void dbri_initialize(struct snd_dbri * dbri) | |||
718 | 750 | ||
719 | dbri_reset(dbri); | 751 | dbri_reset(dbri); |
720 | 752 | ||
721 | cmd = dbri_cmdlock(dbri, NoGetLock); | ||
722 | dprintk(D_GEN, "init: cmd: %p, int: %p\n", | ||
723 | &dbri->dma->cmd[0], &dbri->dma->intr[0]); | ||
724 | |||
725 | /* Initialize pipes */ | 753 | /* Initialize pipes */ |
726 | for (n = 0; n < DBRI_NO_PIPES; n++) | 754 | for (n = 0; n < DBRI_NO_PIPES; n++) |
727 | dbri->pipes[n].desc = dbri->pipes[n].first_desc = -1; | 755 | dbri->pipes[n].desc = dbri->pipes[n].first_desc = -1; |
728 | 756 | ||
757 | spin_lock_init(&dbri->cmdlock); | ||
729 | /* | 758 | /* |
730 | * Initialize the interrupt ringbuffer. | 759 | * Initialize the interrupt ringbuffer. |
731 | */ | 760 | */ |
@@ -735,10 +764,19 @@ static void dbri_initialize(struct snd_dbri * dbri) | |||
735 | /* | 764 | /* |
736 | * Set up the interrupt queue | 765 | * Set up the interrupt queue |
737 | */ | 766 | */ |
767 | spin_lock(&dbri->cmdlock); | ||
768 | cmd = dbri->cmdptr = dbri->dma->cmd; | ||
738 | *(cmd++) = DBRI_CMD(D_IIQ, 0, 0); | 769 | *(cmd++) = DBRI_CMD(D_IIQ, 0, 0); |
739 | *(cmd++) = dma_addr; | 770 | *(cmd++) = dma_addr; |
771 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); | ||
772 | dbri->cmdptr = cmd; | ||
773 | *(cmd++) = DBRI_CMD(D_WAIT, 1, 0); | ||
774 | *(cmd++) = DBRI_CMD(D_WAIT, 1, 0); | ||
775 | dma_addr = dbri->dma_dvma + dbri_dma_off(cmd, 0); | ||
776 | sbus_writel(dma_addr, dbri->regs + REG8); | ||
777 | spin_unlock(&dbri->cmdlock); | ||
778 | dbri_cmdwait(dbri); | ||
740 | 779 | ||
741 | dbri_cmdsend(dbri, cmd); | ||
742 | spin_unlock_irqrestore(&dbri->lock, flags); | 780 | spin_unlock_irqrestore(&dbri->lock, flags); |
743 | } | 781 | } |
744 | 782 | ||
@@ -770,7 +808,7 @@ static void reset_pipe(struct snd_dbri * dbri, int pipe) | |||
770 | { | 808 | { |
771 | int sdp; | 809 | int sdp; |
772 | int desc; | 810 | int desc; |
773 | volatile int *cmd; | 811 | s32 *cmd; |
774 | 812 | ||
775 | if (pipe < 0 || pipe > DBRI_MAX_PIPE) { | 813 | if (pipe < 0 || pipe > DBRI_MAX_PIPE) { |
776 | printk(KERN_ERR "DBRI: reset_pipe called with illegal pipe number\n"); | 814 | printk(KERN_ERR "DBRI: reset_pipe called with illegal pipe number\n"); |
@@ -783,16 +821,18 @@ static void reset_pipe(struct snd_dbri * dbri, int pipe) | |||
783 | return; | 821 | return; |
784 | } | 822 | } |
785 | 823 | ||
786 | cmd = dbri_cmdlock(dbri, NoGetLock); | 824 | cmd = dbri_cmdlock(dbri, 3); |
787 | *(cmd++) = DBRI_CMD(D_SDP, 0, sdp | D_SDP_C | D_SDP_P); | 825 | *(cmd++) = DBRI_CMD(D_SDP, 0, sdp | D_SDP_C | D_SDP_P); |
788 | *(cmd++) = 0; | 826 | *(cmd++) = 0; |
789 | dbri_cmdsend(dbri, cmd); | 827 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); |
828 | dbri_cmdsend(dbri, cmd, 3); | ||
790 | 829 | ||
791 | desc = dbri->pipes[pipe].first_desc; | 830 | desc = dbri->pipes[pipe].first_desc; |
792 | while (desc != -1) { | 831 | if ( desc >= 0) |
793 | dbri->dma->desc[desc].nda = dbri->dma->desc[desc].ba = 0; | 832 | do { |
794 | desc = dbri->next_desc[desc]; | 833 | dbri->dma->desc[desc].nda = dbri->dma->desc[desc].ba = 0; |
795 | } | 834 | desc = dbri->next_desc[desc]; |
835 | } while (desc != -1 && desc != dbri->pipes[pipe].first_desc); | ||
796 | 836 | ||
797 | dbri->pipes[pipe].desc = -1; | 837 | dbri->pipes[pipe].desc = -1; |
798 | dbri->pipes[pipe].first_desc = -1; | 838 | dbri->pipes[pipe].first_desc = -1; |
@@ -828,7 +868,7 @@ static void link_time_slot(struct snd_dbri * dbri, int pipe, | |||
828 | int prevpipe, int nextpipe, | 868 | int prevpipe, int nextpipe, |
829 | int length, int cycle) | 869 | int length, int cycle) |
830 | { | 870 | { |
831 | volatile s32 *cmd; | 871 | s32 *cmd; |
832 | int val; | 872 | int val; |
833 | 873 | ||
834 | if (pipe < 0 || pipe > DBRI_MAX_PIPE | 874 | if (pipe < 0 || pipe > DBRI_MAX_PIPE |
@@ -847,11 +887,10 @@ static void link_time_slot(struct snd_dbri * dbri, int pipe, | |||
847 | } | 887 | } |
848 | 888 | ||
849 | dbri->pipes[prevpipe].nextpipe = pipe; | 889 | dbri->pipes[prevpipe].nextpipe = pipe; |
850 | |||
851 | dbri->pipes[pipe].nextpipe = nextpipe; | 890 | dbri->pipes[pipe].nextpipe = nextpipe; |
852 | dbri->pipes[pipe].length = length; | 891 | dbri->pipes[pipe].length = length; |
853 | 892 | ||
854 | cmd = dbri_cmdlock(dbri, NoGetLock); | 893 | cmd = dbri_cmdlock(dbri, 4); |
855 | 894 | ||
856 | if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) { | 895 | if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) { |
857 | /* Deal with CHI special case: | 896 | /* Deal with CHI special case: |
@@ -874,25 +913,27 @@ static void link_time_slot(struct snd_dbri * dbri, int pipe, | |||
874 | D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe); | 913 | D_TS_LEN(length) | D_TS_CYCLE(cycle) | D_TS_NEXT(nextpipe); |
875 | *(cmd++) = 0; | 914 | *(cmd++) = 0; |
876 | } | 915 | } |
916 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); | ||
877 | 917 | ||
878 | dbri_cmdsend(dbri, cmd); | 918 | dbri_cmdsend(dbri, cmd, 4); |
879 | } | 919 | } |
880 | 920 | ||
881 | static void unlink_time_slot(struct snd_dbri * dbri, int pipe, | 921 | static void unlink_time_slot(struct snd_dbri * dbri, int pipe, |
882 | enum in_or_out direction, int prevpipe, | 922 | enum in_or_out direction, int prevpipe, |
883 | int nextpipe) | 923 | int nextpipe) |
884 | { | 924 | { |
885 | volatile s32 *cmd; | 925 | s32 *cmd; |
886 | int val; | 926 | int val; |
887 | 927 | ||
888 | if (pipe < 0 || pipe > DBRI_MAX_PIPE | 928 | if (pipe < 0 || pipe > DBRI_MAX_PIPE |
889 | || prevpipe < 0 || prevpipe > DBRI_MAX_PIPE) { | 929 | || prevpipe < 0 || prevpipe > DBRI_MAX_PIPE |
930 | || nextpipe < 0 || nextpipe > DBRI_MAX_PIPE) { | ||
890 | printk(KERN_ERR | 931 | printk(KERN_ERR |
891 | "DBRI: unlink_time_slot called with illegal pipe number\n"); | 932 | "DBRI: unlink_time_slot called with illegal pipe number\n"); |
892 | return; | 933 | return; |
893 | } | 934 | } |
894 | 935 | ||
895 | cmd = dbri_cmdlock(dbri, NoGetLock); | 936 | cmd = dbri_cmdlock(dbri, 4); |
896 | 937 | ||
897 | if (direction == PIPEinput) { | 938 | if (direction == PIPEinput) { |
898 | val = D_DTS_VI | D_DTS_DEL | D_DTS_PRVIN(prevpipe) | pipe; | 939 | val = D_DTS_VI | D_DTS_DEL | D_DTS_PRVIN(prevpipe) | pipe; |
@@ -905,8 +946,9 @@ static void unlink_time_slot(struct snd_dbri * dbri, int pipe, | |||
905 | *(cmd++) = 0; | 946 | *(cmd++) = 0; |
906 | *(cmd++) = D_TS_NEXT(nextpipe); | 947 | *(cmd++) = D_TS_NEXT(nextpipe); |
907 | } | 948 | } |
949 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); | ||
908 | 950 | ||
909 | dbri_cmdsend(dbri, cmd); | 951 | dbri_cmdsend(dbri, cmd, 4); |
910 | } | 952 | } |
911 | 953 | ||
912 | /* xmit_fixed() / recv_fixed() | 954 | /* xmit_fixed() / recv_fixed() |
@@ -925,7 +967,7 @@ static void unlink_time_slot(struct snd_dbri * dbri, int pipe, | |||
925 | */ | 967 | */ |
926 | static void xmit_fixed(struct snd_dbri * dbri, int pipe, unsigned int data) | 968 | static void xmit_fixed(struct snd_dbri * dbri, int pipe, unsigned int data) |
927 | { | 969 | { |
928 | volatile s32 *cmd; | 970 | s32 *cmd; |
929 | 971 | ||
930 | if (pipe < 16 || pipe > DBRI_MAX_PIPE) { | 972 | if (pipe < 16 || pipe > DBRI_MAX_PIPE) { |
931 | printk(KERN_ERR "DBRI: xmit_fixed: Illegal pipe number\n"); | 973 | printk(KERN_ERR "DBRI: xmit_fixed: Illegal pipe number\n"); |
@@ -952,12 +994,14 @@ static void xmit_fixed(struct snd_dbri * dbri, int pipe, unsigned int data) | |||
952 | if (dbri->pipes[pipe].sdp & D_SDP_MSB) | 994 | if (dbri->pipes[pipe].sdp & D_SDP_MSB) |
953 | data = reverse_bytes(data, dbri->pipes[pipe].length); | 995 | data = reverse_bytes(data, dbri->pipes[pipe].length); |
954 | 996 | ||
955 | cmd = dbri_cmdlock(dbri, GetLock); | 997 | cmd = dbri_cmdlock(dbri, 3); |
956 | 998 | ||
957 | *(cmd++) = DBRI_CMD(D_SSP, 0, pipe); | 999 | *(cmd++) = DBRI_CMD(D_SSP, 0, pipe); |
958 | *(cmd++) = data; | 1000 | *(cmd++) = data; |
1001 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); | ||
959 | 1002 | ||
960 | dbri_cmdsend(dbri, cmd); | 1003 | dbri_cmdsend(dbri, cmd, 3); |
1004 | dbri_cmdwait(dbri); | ||
961 | } | 1005 | } |
962 | 1006 | ||
963 | static void recv_fixed(struct snd_dbri * dbri, int pipe, volatile __u32 * ptr) | 1007 | static void recv_fixed(struct snd_dbri * dbri, int pipe, volatile __u32 * ptr) |
@@ -991,6 +1035,8 @@ static void recv_fixed(struct snd_dbri * dbri, int pipe, volatile __u32 * ptr) | |||
991 | * and work by building chains of descriptors which identify the | 1035 | * and work by building chains of descriptors which identify the |
992 | * data buffers. Buffers too large for a single descriptor will | 1036 | * data buffers. Buffers too large for a single descriptor will |
993 | * be spread across multiple descriptors. | 1037 | * be spread across multiple descriptors. |
1038 | * | ||
1039 | * All descriptors create a ring buffer. | ||
994 | */ | 1040 | */ |
995 | static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period) | 1041 | static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period) |
996 | { | 1042 | { |
@@ -1051,14 +1097,13 @@ static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period | |||
1051 | return -1; | 1097 | return -1; |
1052 | } | 1098 | } |
1053 | 1099 | ||
1054 | if (len > DBRI_TD_MAXCNT) { | 1100 | if (len > DBRI_TD_MAXCNT) |
1055 | mylen = DBRI_TD_MAXCNT; /* 8KB - 1 */ | 1101 | mylen = DBRI_TD_MAXCNT; /* 8KB - 4 */ |
1056 | } else { | 1102 | else |
1057 | mylen = len; | 1103 | mylen = len; |
1058 | } | 1104 | |
1059 | if (mylen > period) { | 1105 | if (mylen > period) |
1060 | mylen = period; | 1106 | mylen = period; |
1061 | } | ||
1062 | 1107 | ||
1063 | dbri->next_desc[desc] = -1; | 1108 | dbri->next_desc[desc] = -1; |
1064 | dbri->dma->desc[desc].ba = dvma_buffer; | 1109 | dbri->dma->desc[desc].ba = dvma_buffer; |
@@ -1067,17 +1112,17 @@ static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period | |||
1067 | if (streamno == DBRI_PLAY) { | 1112 | if (streamno == DBRI_PLAY) { |
1068 | dbri->dma->desc[desc].word1 = DBRI_TD_CNT(mylen); | 1113 | dbri->dma->desc[desc].word1 = DBRI_TD_CNT(mylen); |
1069 | dbri->dma->desc[desc].word4 = 0; | 1114 | dbri->dma->desc[desc].word4 = 0; |
1070 | if (first_desc != -1) | 1115 | dbri->dma->desc[desc].word1 |= |
1071 | dbri->dma->desc[desc].word1 |= DBRI_TD_M; | 1116 | DBRI_TD_F | DBRI_TD_B; |
1072 | } else { | 1117 | } else { |
1073 | dbri->dma->desc[desc].word1 = 0; | 1118 | dbri->dma->desc[desc].word1 = 0; |
1074 | dbri->dma->desc[desc].word4 = | 1119 | dbri->dma->desc[desc].word4 = |
1075 | DBRI_RD_B | DBRI_RD_BCNT(mylen); | 1120 | DBRI_RD_B | DBRI_RD_BCNT(mylen); |
1076 | } | 1121 | } |
1077 | 1122 | ||
1078 | if (first_desc == -1) { | 1123 | if (first_desc == -1) |
1079 | first_desc = desc; | 1124 | first_desc = desc; |
1080 | } else { | 1125 | else { |
1081 | dbri->next_desc[last_desc] = desc; | 1126 | dbri->next_desc[last_desc] = desc; |
1082 | dbri->dma->desc[last_desc].nda = | 1127 | dbri->dma->desc[last_desc].nda = |
1083 | dbri->dma_dvma + dbri_dma_off(desc, desc); | 1128 | dbri->dma_dvma + dbri_dma_off(desc, desc); |
@@ -1093,21 +1138,28 @@ static int setup_descs(struct snd_dbri * dbri, int streamno, unsigned int period | |||
1093 | return -1; | 1138 | return -1; |
1094 | } | 1139 | } |
1095 | 1140 | ||
1096 | dbri->dma->desc[last_desc].word1 &= ~DBRI_TD_M; | ||
1097 | if (streamno == DBRI_PLAY) { | 1141 | if (streamno == DBRI_PLAY) { |
1098 | dbri->dma->desc[last_desc].word1 |= | 1142 | dbri->dma->desc[last_desc].word1 |= |
1099 | DBRI_TD_I | DBRI_TD_F | DBRI_TD_B; | 1143 | DBRI_TD_F | DBRI_TD_B; |
1144 | dbri->dma->desc[last_desc].nda = | ||
1145 | dbri->dma_dvma + dbri_dma_off(desc, first_desc); | ||
1146 | dbri->next_desc[last_desc] = first_desc; | ||
1100 | } | 1147 | } |
1101 | dbri->pipes[info->pipe].first_desc = first_desc; | 1148 | dbri->pipes[info->pipe].first_desc = first_desc; |
1102 | dbri->pipes[info->pipe].desc = first_desc; | 1149 | dbri->pipes[info->pipe].desc = first_desc; |
1103 | 1150 | ||
1104 | for (desc = first_desc; desc != -1; desc = dbri->next_desc[desc]) { | 1151 | #ifdef DBRI_DEBUG |
1152 | for (desc = first_desc; desc != -1; ) { | ||
1105 | dprintk(D_DESC, "DESC %d: %08x %08x %08x %08x\n", | 1153 | dprintk(D_DESC, "DESC %d: %08x %08x %08x %08x\n", |
1106 | desc, | 1154 | desc, |
1107 | dbri->dma->desc[desc].word1, | 1155 | dbri->dma->desc[desc].word1, |
1108 | dbri->dma->desc[desc].ba, | 1156 | dbri->dma->desc[desc].ba, |
1109 | dbri->dma->desc[desc].nda, dbri->dma->desc[desc].word4); | 1157 | dbri->dma->desc[desc].nda, dbri->dma->desc[desc].word4); |
1158 | desc = dbri->next_desc[desc]; | ||
1159 | if ( desc == first_desc ) | ||
1160 | break; | ||
1110 | } | 1161 | } |
1162 | #endif | ||
1111 | return 0; | 1163 | return 0; |
1112 | } | 1164 | } |
1113 | 1165 | ||
@@ -1127,43 +1179,24 @@ enum master_or_slave { CHImaster, CHIslave }; | |||
1127 | static void reset_chi(struct snd_dbri * dbri, enum master_or_slave master_or_slave, | 1179 | static void reset_chi(struct snd_dbri * dbri, enum master_or_slave master_or_slave, |
1128 | int bits_per_frame) | 1180 | int bits_per_frame) |
1129 | { | 1181 | { |
1130 | volatile s32 *cmd; | 1182 | s32 *cmd; |
1131 | int val; | 1183 | int val; |
1132 | static int chi_initialized = 0; /* FIXME: mutex? */ | ||
1133 | |||
1134 | if (!chi_initialized) { | ||
1135 | 1184 | ||
1136 | cmd = dbri_cmdlock(dbri, GetLock); | 1185 | /* Set CHI Anchor: Pipe 16 */ |
1137 | 1186 | ||
1138 | /* Set CHI Anchor: Pipe 16 */ | 1187 | cmd = dbri_cmdlock(dbri, 4); |
1139 | 1188 | val = D_DTS_VO | D_DTS_VI | D_DTS_INS | |
1140 | val = D_DTS_VO | D_DTS_VI | D_DTS_INS | 1189 | | D_DTS_PRVIN(16) | D_PIPE(16) | D_DTS_PRVOUT(16); |
1141 | | D_DTS_PRVIN(16) | D_PIPE(16) | D_DTS_PRVOUT(16); | 1190 | *(cmd++) = DBRI_CMD(D_DTS, 0, val); |
1142 | *(cmd++) = DBRI_CMD(D_DTS, 0, val); | 1191 | *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16); |
1143 | *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16); | 1192 | *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16); |
1144 | *(cmd++) = D_TS_ANCHOR | D_TS_NEXT(16); | 1193 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); |
1194 | dbri_cmdsend(dbri, cmd, 4); | ||
1145 | 1195 | ||
1146 | dbri->pipes[16].sdp = 1; | 1196 | dbri->pipes[16].sdp = 1; |
1147 | dbri->pipes[16].nextpipe = 16; | 1197 | dbri->pipes[16].nextpipe = 16; |
1148 | 1198 | ||
1149 | #if 0 | 1199 | cmd = dbri_cmdlock(dbri, 4); |
1150 | chi_initialized++; | ||
1151 | #endif | ||
1152 | } else { | ||
1153 | int pipe; | ||
1154 | |||
1155 | for (pipe = 0; pipe < DBRI_NO_PIPES; pipe++ ) | ||
1156 | if ( pipe != 16 ) { | ||
1157 | if (dbri->pipes[pipe].sdp & D_SDP_TO_SER) | ||
1158 | unlink_time_slot(dbri, pipe, PIPEoutput, | ||
1159 | 16, dbri->pipes[pipe].nextpipe); | ||
1160 | else | ||
1161 | unlink_time_slot(dbri, pipe, PIPEinput, | ||
1162 | 16, dbri->pipes[pipe].nextpipe); | ||
1163 | } | ||
1164 | |||
1165 | cmd = dbri_cmdlock(dbri, GetLock); | ||
1166 | } | ||
1167 | 1200 | ||
1168 | if (master_or_slave == CHIslave) { | 1201 | if (master_or_slave == CHIslave) { |
1169 | /* Setup DBRI for CHI Slave - receive clock, frame sync (FS) | 1202 | /* Setup DBRI for CHI Slave - receive clock, frame sync (FS) |
@@ -1202,8 +1235,9 @@ static void reset_chi(struct snd_dbri * dbri, enum master_or_slave master_or_sla | |||
1202 | 1235 | ||
1203 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); | 1236 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); |
1204 | *(cmd++) = DBRI_CMD(D_CDM, 0, D_CDM_XCE | D_CDM_XEN | D_CDM_REN); | 1237 | *(cmd++) = DBRI_CMD(D_CDM, 0, D_CDM_XCE | D_CDM_XEN | D_CDM_REN); |
1238 | *(cmd++) = DBRI_CMD(D_PAUSE, 0, 0); | ||
1205 | 1239 | ||
1206 | dbri_cmdsend(dbri, cmd); | 1240 | dbri_cmdsend(dbri, cmd, 4); |
1207 | } | 1241 | } |
1208 | 1242 | ||
1209 | /* | 1243 | /* |
@@ -1240,6 +1274,8 @@ static void cs4215_setup_pipes(struct snd_dbri * dbri) | |||
1240 | setup_pipe(dbri, 17, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB); | 1274 | setup_pipe(dbri, 17, D_SDP_FIXED | D_SDP_TO_SER | D_SDP_MSB); |
1241 | setup_pipe(dbri, 18, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB); | 1275 | setup_pipe(dbri, 18, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB); |
1242 | setup_pipe(dbri, 19, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB); | 1276 | setup_pipe(dbri, 19, D_SDP_FIXED | D_SDP_FROM_SER | D_SDP_MSB); |
1277 | |||
1278 | dbri_cmdwait(dbri); | ||
1243 | } | 1279 | } |
1244 | 1280 | ||
1245 | static int cs4215_init_data(struct cs4215 *mm) | 1281 | static int cs4215_init_data(struct cs4215 *mm) |
@@ -1271,7 +1307,7 @@ static int cs4215_init_data(struct cs4215 *mm) | |||
1271 | mm->status = 0; | 1307 | mm->status = 0; |
1272 | mm->version = 0xff; | 1308 | mm->version = 0xff; |
1273 | mm->precision = 8; /* For ULAW */ | 1309 | mm->precision = 8; /* For ULAW */ |
1274 | mm->channels = 2; | 1310 | mm->channels = 1; |
1275 | 1311 | ||
1276 | return 0; | 1312 | return 0; |
1277 | } | 1313 | } |
@@ -1554,7 +1590,6 @@ static int cs4215_init(struct snd_dbri * dbri) | |||
1554 | } | 1590 | } |
1555 | 1591 | ||
1556 | cs4215_setup_pipes(dbri); | 1592 | cs4215_setup_pipes(dbri); |
1557 | |||
1558 | cs4215_init_data(&dbri->mm); | 1593 | cs4215_init_data(&dbri->mm); |
1559 | 1594 | ||
1560 | /* Enable capture of the status & version timeslots. */ | 1595 | /* Enable capture of the status & version timeslots. */ |
@@ -1583,9 +1618,7 @@ buffer and calls dbri_process_one_interrupt() for each interrupt word. | |||
1583 | Complicated interrupts are handled by dedicated functions (which | 1618 | Complicated interrupts are handled by dedicated functions (which |
1584 | appear first in this file). Any pending interrupts can be serviced by | 1619 | appear first in this file). Any pending interrupts can be serviced by |
1585 | calling dbri_process_interrupt_buffer(), which works even if the CPU's | 1620 | calling dbri_process_interrupt_buffer(), which works even if the CPU's |
1586 | interrupts are disabled. This function is used by dbri_cmdlock() | 1621 | interrupts are disabled. |
1587 | to make sure we're synced up with the chip before each command sequence, | ||
1588 | even if we're running cli'ed. | ||
1589 | 1622 | ||
1590 | */ | 1623 | */ |
1591 | 1624 | ||
@@ -1594,11 +1627,10 @@ even if we're running cli'ed. | |||
1594 | * Transmit the current TD's for recording/playing, if needed. | 1627 | * Transmit the current TD's for recording/playing, if needed. |
1595 | * For playback, ALSA has filled the DMA memory with new data (we hope). | 1628 | * For playback, ALSA has filled the DMA memory with new data (we hope). |
1596 | */ | 1629 | */ |
1597 | static void xmit_descs(unsigned long data) | 1630 | static void xmit_descs(struct snd_dbri *dbri) |
1598 | { | 1631 | { |
1599 | struct snd_dbri *dbri = (struct snd_dbri *) data; | ||
1600 | struct dbri_streaminfo *info; | 1632 | struct dbri_streaminfo *info; |
1601 | volatile s32 *cmd; | 1633 | s32 *cmd; |
1602 | unsigned long flags; | 1634 | unsigned long flags; |
1603 | int first_td; | 1635 | int first_td; |
1604 | 1636 | ||
@@ -1609,7 +1641,7 @@ static void xmit_descs(unsigned long data) | |||
1609 | info = &dbri->stream_info[DBRI_REC]; | 1641 | info = &dbri->stream_info[DBRI_REC]; |
1610 | spin_lock_irqsave(&dbri->lock, flags); | 1642 | spin_lock_irqsave(&dbri->lock, flags); |
1611 | 1643 | ||
1612 | if ((info->left >= info->size) && (info->pipe >= 0)) { | 1644 | if (info->pipe >= 0) { |
1613 | first_td = dbri->pipes[info->pipe].first_desc; | 1645 | first_td = dbri->pipes[info->pipe].first_desc; |
1614 | 1646 | ||
1615 | dprintk(D_DESC, "xmit_descs rec @ TD %d\n", first_td); | 1647 | dprintk(D_DESC, "xmit_descs rec @ TD %d\n", first_td); |
@@ -1619,16 +1651,15 @@ static void xmit_descs(unsigned long data) | |||
1619 | goto play; | 1651 | goto play; |
1620 | } | 1652 | } |
1621 | 1653 | ||
1622 | cmd = dbri_cmdlock(dbri, NoGetLock); | 1654 | cmd = dbri_cmdlock(dbri, 2); |
1623 | *(cmd++) = DBRI_CMD(D_SDP, 0, | 1655 | *(cmd++) = DBRI_CMD(D_SDP, 0, |
1624 | dbri->pipes[info->pipe].sdp | 1656 | dbri->pipes[info->pipe].sdp |
1625 | | D_SDP_P | D_SDP_EVERY | D_SDP_C); | 1657 | | D_SDP_P | D_SDP_EVERY | D_SDP_C); |
1626 | *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, first_td); | 1658 | *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, first_td); |
1627 | dbri_cmdsend(dbri, cmd); | 1659 | dbri_cmdsend(dbri, cmd, 2); |
1628 | 1660 | ||
1629 | /* Reset our admin of the pipe & bytes read. */ | 1661 | /* Reset our admin of the pipe & bytes read. */ |
1630 | dbri->pipes[info->pipe].desc = first_td; | 1662 | dbri->pipes[info->pipe].desc = first_td; |
1631 | info->left = 0; | ||
1632 | } | 1663 | } |
1633 | 1664 | ||
1634 | play: | 1665 | play: |
@@ -1638,33 +1669,27 @@ play: | |||
1638 | info = &dbri->stream_info[DBRI_PLAY]; | 1669 | info = &dbri->stream_info[DBRI_PLAY]; |
1639 | spin_lock_irqsave(&dbri->lock, flags); | 1670 | spin_lock_irqsave(&dbri->lock, flags); |
1640 | 1671 | ||
1641 | if ((info->left <= 0) && (info->pipe >= 0)) { | 1672 | if (info->pipe >= 0) { |
1642 | first_td = dbri->pipes[info->pipe].first_desc; | 1673 | first_td = dbri->pipes[info->pipe].first_desc; |
1643 | 1674 | ||
1644 | dprintk(D_DESC, "xmit_descs play @ TD %d\n", first_td); | 1675 | dprintk(D_DESC, "xmit_descs play @ TD %d\n", first_td); |
1645 | 1676 | ||
1646 | /* Stream could be closed by the time we run. */ | 1677 | /* Stream could be closed by the time we run. */ |
1647 | if (first_td < 0) { | 1678 | if (first_td >= 0) { |
1648 | spin_unlock_irqrestore(&dbri->lock, flags); | 1679 | cmd = dbri_cmdlock(dbri, 2); |
1649 | return; | 1680 | *(cmd++) = DBRI_CMD(D_SDP, 0, |
1650 | } | 1681 | dbri->pipes[info->pipe].sdp |
1651 | 1682 | | D_SDP_P | D_SDP_EVERY | D_SDP_C); | |
1652 | cmd = dbri_cmdlock(dbri, NoGetLock); | 1683 | *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, first_td); |
1653 | *(cmd++) = DBRI_CMD(D_SDP, 0, | 1684 | dbri_cmdsend(dbri, cmd, 2); |
1654 | dbri->pipes[info->pipe].sdp | ||
1655 | | D_SDP_P | D_SDP_EVERY | D_SDP_C); | ||
1656 | *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, first_td); | ||
1657 | dbri_cmdsend(dbri, cmd); | ||
1658 | 1685 | ||
1659 | /* Reset our admin of the pipe & bytes written. */ | 1686 | /* Reset our admin of the pipe & bytes written. */ |
1660 | dbri->pipes[info->pipe].desc = first_td; | 1687 | dbri->pipes[info->pipe].desc = first_td; |
1661 | info->left = info->size; | 1688 | } |
1662 | } | 1689 | } |
1663 | spin_unlock_irqrestore(&dbri->lock, flags); | 1690 | spin_unlock_irqrestore(&dbri->lock, flags); |
1664 | } | 1691 | } |
1665 | 1692 | ||
1666 | static DECLARE_TASKLET(xmit_descs_task, xmit_descs, 0); | ||
1667 | |||
1668 | /* transmission_complete_intr() | 1693 | /* transmission_complete_intr() |
1669 | * | 1694 | * |
1670 | * Called by main interrupt handler when DBRI signals transmission complete | 1695 | * Called by main interrupt handler when DBRI signals transmission complete |
@@ -1684,7 +1709,6 @@ static void transmission_complete_intr(struct snd_dbri * dbri, int pipe) | |||
1684 | struct dbri_streaminfo *info; | 1709 | struct dbri_streaminfo *info; |
1685 | int td; | 1710 | int td; |
1686 | int status; | 1711 | int status; |
1687 | int len; | ||
1688 | 1712 | ||
1689 | info = &dbri->stream_info[DBRI_PLAY]; | 1713 | info = &dbri->stream_info[DBRI_PLAY]; |
1690 | 1714 | ||
@@ -1703,20 +1727,7 @@ static void transmission_complete_intr(struct snd_dbri * dbri, int pipe) | |||
1703 | dprintk(D_INT, "TD %d, status 0x%02x\n", td, status); | 1727 | dprintk(D_INT, "TD %d, status 0x%02x\n", td, status); |
1704 | 1728 | ||
1705 | dbri->dma->desc[td].word4 = 0; /* Reset it for next time. */ | 1729 | dbri->dma->desc[td].word4 = 0; /* Reset it for next time. */ |
1706 | len = DBRI_RD_CNT(dbri->dma->desc[td].word1); | 1730 | info->offset += DBRI_RD_CNT(dbri->dma->desc[td].word1); |
1707 | info->offset += len; | ||
1708 | info->left -= len; | ||
1709 | |||
1710 | /* On the last TD, transmit them all again. */ | ||
1711 | if (dbri->next_desc[td] == -1) { | ||
1712 | if (info->left > 0) { | ||
1713 | printk(KERN_WARNING | ||
1714 | "%d bytes left after last transfer.\n", | ||
1715 | info->left); | ||
1716 | info->left = 0; | ||
1717 | } | ||
1718 | tasklet_schedule(&xmit_descs_task); | ||
1719 | } | ||
1720 | 1731 | ||
1721 | td = dbri->next_desc[td]; | 1732 | td = dbri->next_desc[td]; |
1722 | dbri->pipes[pipe].desc = td; | 1733 | dbri->pipes[pipe].desc = td; |
@@ -1749,7 +1760,6 @@ static void reception_complete_intr(struct snd_dbri * dbri, int pipe) | |||
1749 | 1760 | ||
1750 | info = &dbri->stream_info[DBRI_REC]; | 1761 | info = &dbri->stream_info[DBRI_REC]; |
1751 | info->offset += DBRI_RD_CNT(status); | 1762 | info->offset += DBRI_RD_CNT(status); |
1752 | info->left += DBRI_RD_CNT(status); | ||
1753 | 1763 | ||
1754 | /* FIXME: Check status */ | 1764 | /* FIXME: Check status */ |
1755 | 1765 | ||
@@ -1757,6 +1767,7 @@ static void reception_complete_intr(struct snd_dbri * dbri, int pipe) | |||
1757 | rd, DBRI_RD_STATUS(status), DBRI_RD_CNT(status)); | 1767 | rd, DBRI_RD_STATUS(status), DBRI_RD_CNT(status)); |
1758 | 1768 | ||
1759 | /* On the last TD, transmit them all again. */ | 1769 | /* On the last TD, transmit them all again. */ |
1770 | #if 0 | ||
1760 | if (dbri->next_desc[rd] == -1) { | 1771 | if (dbri->next_desc[rd] == -1) { |
1761 | if (info->left > info->size) { | 1772 | if (info->left > info->size) { |
1762 | printk(KERN_WARNING | 1773 | printk(KERN_WARNING |
@@ -1765,6 +1776,7 @@ static void reception_complete_intr(struct snd_dbri * dbri, int pipe) | |||
1765 | } | 1776 | } |
1766 | tasklet_schedule(&xmit_descs_task); | 1777 | tasklet_schedule(&xmit_descs_task); |
1767 | } | 1778 | } |
1779 | #endif | ||
1768 | 1780 | ||
1769 | /* Notify ALSA */ | 1781 | /* Notify ALSA */ |
1770 | if (spin_is_locked(&dbri->lock)) { | 1782 | if (spin_is_locked(&dbri->lock)) { |
@@ -1793,16 +1805,11 @@ static void dbri_process_one_interrupt(struct snd_dbri * dbri, int x) | |||
1793 | channel, code, rval); | 1805 | channel, code, rval); |
1794 | } | 1806 | } |
1795 | 1807 | ||
1796 | if (channel == D_INTR_CMD && command == D_WAIT) { | ||
1797 | dbri->wait_ackd = val; | ||
1798 | if (dbri->wait_send != val) { | ||
1799 | printk(KERN_ERR "Processing wait command %d when %d was send.\n", | ||
1800 | val, dbri->wait_send); | ||
1801 | } | ||
1802 | return; | ||
1803 | } | ||
1804 | |||
1805 | switch (code) { | 1808 | switch (code) { |
1809 | case D_INTR_CMDI: | ||
1810 | if (command != D_WAIT) | ||
1811 | printk(KERN_ERR "DBRI: Command read interrupt\n"); | ||
1812 | break; | ||
1806 | case D_INTR_BRDY: | 1813 | case D_INTR_BRDY: |
1807 | reception_complete_intr(dbri, channel); | 1814 | reception_complete_intr(dbri, channel); |
1808 | break; | 1815 | break; |
@@ -1815,8 +1822,10 @@ static void dbri_process_one_interrupt(struct snd_dbri * dbri, int x) | |||
1815 | * resend SDP command with clear pipe bit (C) set | 1822 | * resend SDP command with clear pipe bit (C) set |
1816 | */ | 1823 | */ |
1817 | { | 1824 | { |
1818 | volatile s32 *cmd; | 1825 | /* FIXME: do something useful in case of underrun */ |
1819 | 1826 | printk(KERN_ERR "DBRI: Underrun error\n"); | |
1827 | #if 0 | ||
1828 | s32 *cmd; | ||
1820 | int pipe = channel; | 1829 | int pipe = channel; |
1821 | int td = dbri->pipes[pipe].desc; | 1830 | int td = dbri->pipes[pipe].desc; |
1822 | 1831 | ||
@@ -1827,6 +1836,7 @@ static void dbri_process_one_interrupt(struct snd_dbri * dbri, int x) | |||
1827 | | D_SDP_P | D_SDP_C | D_SDP_2SAME); | 1836 | | D_SDP_P | D_SDP_C | D_SDP_2SAME); |
1828 | *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, td); | 1837 | *(cmd++) = dbri->dma_dvma + dbri_dma_off(desc, td); |
1829 | dbri_cmdsend(dbri, cmd); | 1838 | dbri_cmdsend(dbri, cmd); |
1839 | #endif | ||
1830 | } | 1840 | } |
1831 | break; | 1841 | break; |
1832 | case D_INTR_FXDT: | 1842 | case D_INTR_FXDT: |
@@ -1847,9 +1857,7 @@ static void dbri_process_one_interrupt(struct snd_dbri * dbri, int x) | |||
1847 | /* dbri_process_interrupt_buffer advances through the DBRI's interrupt | 1857 | /* dbri_process_interrupt_buffer advances through the DBRI's interrupt |
1848 | * buffer until it finds a zero word (indicating nothing more to do | 1858 | * buffer until it finds a zero word (indicating nothing more to do |
1849 | * right now). Non-zero words require processing and are handed off | 1859 | * right now). Non-zero words require processing and are handed off |
1850 | * to dbri_process_one_interrupt AFTER advancing the pointer. This | 1860 | * to dbri_process_one_interrupt AFTER advancing the pointer. |
1851 | * order is important since we might recurse back into this function | ||
1852 | * and need to make sure the pointer has been advanced first. | ||
1853 | */ | 1861 | */ |
1854 | static void dbri_process_interrupt_buffer(struct snd_dbri * dbri) | 1862 | static void dbri_process_interrupt_buffer(struct snd_dbri * dbri) |
1855 | { | 1863 | { |
@@ -1919,8 +1927,6 @@ static irqreturn_t snd_dbri_interrupt(int irq, void *dev_id, | |||
1919 | 1927 | ||
1920 | dbri_process_interrupt_buffer(dbri); | 1928 | dbri_process_interrupt_buffer(dbri); |
1921 | 1929 | ||
1922 | /* FIXME: Write 0 into regs to ACK interrupt */ | ||
1923 | |||
1924 | spin_unlock(&dbri->lock); | 1930 | spin_unlock(&dbri->lock); |
1925 | 1931 | ||
1926 | return IRQ_HANDLED; | 1932 | return IRQ_HANDLED; |
@@ -1962,7 +1968,6 @@ static int snd_dbri_open(struct snd_pcm_substream *substream) | |||
1962 | 1968 | ||
1963 | spin_lock_irqsave(&dbri->lock, flags); | 1969 | spin_lock_irqsave(&dbri->lock, flags); |
1964 | info->substream = substream; | 1970 | info->substream = substream; |
1965 | info->left = 0; | ||
1966 | info->offset = 0; | 1971 | info->offset = 0; |
1967 | info->dvma_buffer = 0; | 1972 | info->dvma_buffer = 0; |
1968 | info->pipe = -1; | 1973 | info->pipe = -1; |
@@ -1980,7 +1985,6 @@ static int snd_dbri_close(struct snd_pcm_substream *substream) | |||
1980 | 1985 | ||
1981 | dprintk(D_USR, "close audio output.\n"); | 1986 | dprintk(D_USR, "close audio output.\n"); |
1982 | info->substream = NULL; | 1987 | info->substream = NULL; |
1983 | info->left = 0; | ||
1984 | info->offset = 0; | 1988 | info->offset = 0; |
1985 | 1989 | ||
1986 | return 0; | 1990 | return 0; |
@@ -2062,10 +2066,8 @@ static int snd_dbri_prepare(struct snd_pcm_substream *substream) | |||
2062 | info->size = snd_pcm_lib_buffer_bytes(substream); | 2066 | info->size = snd_pcm_lib_buffer_bytes(substream); |
2063 | if (DBRI_STREAMNO(substream) == DBRI_PLAY) | 2067 | if (DBRI_STREAMNO(substream) == DBRI_PLAY) |
2064 | info->pipe = 4; /* Send pipe */ | 2068 | info->pipe = 4; /* Send pipe */ |
2065 | else { | 2069 | else |
2066 | info->pipe = 6; /* Receive pipe */ | 2070 | info->pipe = 6; /* Receive pipe */ |
2067 | info->left = info->size; /* To trigger submittal */ | ||
2068 | } | ||
2069 | 2071 | ||
2070 | spin_lock_irq(&dbri->lock); | 2072 | spin_lock_irq(&dbri->lock); |
2071 | 2073 | ||
@@ -2093,14 +2095,11 @@ static int snd_dbri_trigger(struct snd_pcm_substream *substream, int cmd) | |||
2093 | case SNDRV_PCM_TRIGGER_START: | 2095 | case SNDRV_PCM_TRIGGER_START: |
2094 | dprintk(D_USR, "start audio, period is %d bytes\n", | 2096 | dprintk(D_USR, "start audio, period is %d bytes\n", |
2095 | (int)snd_pcm_lib_period_bytes(substream)); | 2097 | (int)snd_pcm_lib_period_bytes(substream)); |
2096 | /* Enable & schedule the tasklet that re-submits the TDs. */ | 2098 | /* Re-submit the TDs. */ |
2097 | xmit_descs_task.data = (unsigned long)dbri; | 2099 | xmit_descs(dbri); |
2098 | tasklet_schedule(&xmit_descs_task); | ||
2099 | break; | 2100 | break; |
2100 | case SNDRV_PCM_TRIGGER_STOP: | 2101 | case SNDRV_PCM_TRIGGER_STOP: |
2101 | dprintk(D_USR, "stop audio.\n"); | 2102 | dprintk(D_USR, "stop audio.\n"); |
2102 | /* Make the tasklet bail out immediately. */ | ||
2103 | xmit_descs_task.data = 0; | ||
2104 | reset_pipe(dbri, info->pipe); | 2103 | reset_pipe(dbri, info->pipe); |
2105 | break; | 2104 | break; |
2106 | default: | 2105 | default: |
@@ -2118,8 +2117,8 @@ static snd_pcm_uframes_t snd_dbri_pointer(struct snd_pcm_substream *substream) | |||
2118 | 2117 | ||
2119 | ret = bytes_to_frames(substream->runtime, info->offset) | 2118 | ret = bytes_to_frames(substream->runtime, info->offset) |
2120 | % substream->runtime->buffer_size; | 2119 | % substream->runtime->buffer_size; |
2121 | dprintk(D_USR, "I/O pointer: %ld frames, %d bytes left.\n", | 2120 | dprintk(D_USR, "I/O pointer: %ld frames of %ld.\n", |
2122 | ret, info->left); | 2121 | ret, substream->runtime->buffer_size); |
2123 | return ret; | 2122 | return ret; |
2124 | } | 2123 | } |
2125 | 2124 | ||