Index: firmware/target/arm/pcm-pp.c =================================================================== --- firmware/target/arm/pcm-pp.c (revision 20211) +++ firmware/target/arm/pcm-pp.c (working copy) @@ -391,32 +391,31 @@ static void play_stop_pcm(void) { #ifdef CPU_PP502x - size_t status = DMA0_STATUS; + size_t status; size_t size; + unsigned long dmacmd; + /* Prevent interrupt during polling */ + pcm_play_lock(); + /* Stop transfer */ - DMA0_CMD &= ~(DMA_CMD_START | DMA_CMD_INTR); + dmacmd = DMA0_CMD; + DMA0_CMD = dmacmd & ~(DMA_CMD_START | DMA_CMD_INTR); /* Wait for not busy + clear int */ - while (DMA0_STATUS & (DMA_STATUS_BUSY | DMA_STATUS_INTR)); + do { + status = DMA0_STATUS; + } while (status & (DMA_STATUS_BUSY | DMA_STATUS_INTR)); - size = (status & 0xfffc) + 4; + pcm_play_unlock(); - if (status & DMA_STATUS_BUSY) - { - /* Transfer was interrupted - leave what's left */ - dma_play_data.addr += dma_play_data.size - size; - dma_play_data.size = size; - } - else if (status & DMA_STATUS_INTR) - { - /* Tranfer was finished - DMA0_STATUS will have been reloaded - * automatically with size in DMA0_CMD. */ - dma_play_data.addr += size; - dma_play_data.size -= size; - if (dma_play_data.size <= 0) - dma_play_data.addr = 0; /* Entire buffer has completed */ - } + /* Update values based on how much was transferred */ + size = (dmacmd & DMA_CMD_SIZE) - (status & DMA_STATUS_SIZE_REMAIN); + dma_play_data.addr += size; + dma_play_data.size -= size; + + if (dma_play_data.size <= 0) + dma_play_data.addr = 0; /* Entire buffer has completed */ #else /* Disable TX interrupt */ IIS_IRQTX_REG &= ~IIS_IRQTX;