Exemplo n.º 1
0
static int s3c2410_dma_flush(struct s3c2410_dma_chan *chan)
{
    struct s3c2410_dma_buf *buf, *next;
    unsigned long flags;

    pr_debug("%s: chan %p (%d)\n", __func__, chan, chan->number);

    dbg_showchan(chan);

    local_irq_save(flags);

    if (chan->state != S3C2410_DMA_IDLE) {
        pr_debug("%s: stopping channel...\n", __func__ );
        s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP);
    }

    buf = chan->curr;
    if (buf == NULL)
        buf = chan->next;

    chan->curr = chan->next = chan->end = NULL;

    if (buf != NULL) {
        for ( ; buf != NULL; buf = next) {
            next = buf->next;

            pr_debug("%s: free buffer %p, next %p\n",
                     __func__, buf, buf->next);

            s3c2410_dma_buffdone(chan, buf, S3C2410_RES_ABORT);
            s3c2410_dma_freebuf(buf);
        }
    }

    dbg_showregs(chan);

    s3c2410_dma_waitforstop(chan);

#if 0
    /* should also clear interrupts, according to WinCE BSP */
    {
        unsigned long tmp;

        tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
        tmp |= S3C2410_DCON_NORELOAD;
        dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
    }
#endif

    dbg_showregs(chan);

    local_irq_restore(flags);

    return 0;
}
Exemplo n.º 2
0
static int s3c2410_dma_flush(struct s3c2410_dma_chan *chan)
{
	struct s3c2410_dma_buf *buf, *next;
	unsigned long flags;

	pr_debug("%s: chan %p (%d)\n", __func__, chan, chan->number);

	dbg_showchan(chan);

	local_irq_save(flags);

	if (chan->state != S3C2410_DMA_IDLE) {
		pr_debug("%s: stopping channel...\n", __func__ );
		s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP);
	}

	buf = chan->curr;
	if (buf == NULL)
		buf = chan->next;

	chan->curr = chan->next = chan->end = NULL;

	if (buf != NULL) {
		for ( ; buf != NULL; buf = next) {
			next = buf->next;

			pr_debug("%s: free buffer %p, next %p\n",
			       __func__, buf, buf->next);

			s3c2410_dma_buffdone(chan, buf, S3C2410_RES_ABORT);
			s3c2410_dma_freebuf(buf);
		}
	}

	dbg_showregs(chan);

	s3c2410_dma_waitforstop(chan);


	dbg_showregs(chan);

	local_irq_restore(flags);

	return 0;
}
Exemplo n.º 3
0
static int s3c2410_dma_flush(s3c2410_dma_chan_t *chan)
{
	s3c2410_dma_buf_t *buf, *next;
	unsigned long flags;

	pr_debug("%s:\n", __FUNCTION__);

	local_irq_save(flags);

	if (chan->state != S3C2410_DMA_IDLE) {
		pr_debug("%s: stopping channel...\n", __FUNCTION__ );
		s3c2410_dma_ctrl(chan->number, S3C2410_DMAOP_STOP);
	}

	buf = chan->curr;
	if (buf == NULL)
		buf = chan->next;

	chan->curr = chan->next = chan->end = NULL;

	if (buf != NULL) {
		for ( ; buf != NULL; buf = next) {
			next = buf->next;

			pr_debug("%s: free buffer %p, next %p\n",
			       __FUNCTION__, buf, buf->next);

			s3c2410_dma_buffdone(chan, buf, S3C2410_RES_ABORT);
			s3c2410_dma_freebuf(buf);
		}
	}

	local_irq_restore(flags);

	return 0;
}
Exemplo n.º 4
0
static irqreturn_t
s3c2410_dma_irq(int irq, void *devpw)
{
    struct s3c2410_dma_chan *chan = (struct s3c2410_dma_chan *)devpw;
    struct s3c2410_dma_buf  *buf;

    buf = chan->curr;

    dbg_showchan(chan);

    /* modify the channel state */

    switch (chan->load_state) {
    case S3C2410_DMALOAD_1RUNNING:
        /* TODO - if we are running only one buffer, we probably
         * want to reload here, and then worry about the buffer
         * callback */

        chan->load_state = S3C2410_DMALOAD_NONE;
        break;

    case S3C2410_DMALOAD_1LOADED:
        /* iirc, we should go back to NONE loaded here, we
         * had a buffer, and it was never verified as being
         * loaded.
         */

        chan->load_state = S3C2410_DMALOAD_NONE;
        break;

    case S3C2410_DMALOAD_1LOADED_1RUNNING:
        /* we'll worry about checking to see if another buffer is
         * ready after we've called back the owner. This should
         * ensure we do not wait around too long for the DMA
         * engine to start the next transfer
         */

        chan->load_state = S3C2410_DMALOAD_1LOADED;
        break;

    case S3C2410_DMALOAD_NONE:
        printk(KERN_ERR "dma%d: IRQ with no loaded buffer?\n",
               chan->number);
        break;

    default:
        printk(KERN_ERR "dma%d: IRQ in invalid load_state %d\n",
               chan->number, chan->load_state);
        break;
    }

    if (buf != NULL) {
        /* update the chain to make sure that if we load any more
         * buffers when we call the callback function, things should
         * work properly */

        chan->curr = buf->next;
        buf->next  = NULL;

        if (buf->magic != BUF_MAGIC) {
            printk(KERN_ERR "dma%d: %s: buf %p incorrect magic\n",
                   chan->number, __func__, buf);
            return IRQ_HANDLED;
        }

        s3c2410_dma_buffdone(chan, buf, S3C2410_RES_OK);

        /* free resouces */
        s3c2410_dma_freebuf(buf);
    } else {
    }

    /* only reload if the channel is still running... our buffer done
     * routine may have altered the state by requesting the dma channel
     * to stop or shutdown... */

    /* todo: check that when the channel is shut-down from inside this
     * function, we cope with unsetting reload, etc */

    if (chan->next != NULL && chan->state != S3C2410_DMA_IDLE) {
        unsigned long flags;

        switch (chan->load_state) {
        case S3C2410_DMALOAD_1RUNNING:
            /* don't need to do anything for this state */
            break;

        case S3C2410_DMALOAD_NONE:
            /* can load buffer immediately */
            break;

        case S3C2410_DMALOAD_1LOADED:
            if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
                /* flag error? */
                printk(KERN_ERR "dma%d: timeout waiting for load (%s)\n",
                       chan->number, __func__);
                return IRQ_HANDLED;
            }

            break;

        case S3C2410_DMALOAD_1LOADED_1RUNNING:
            goto no_load;

        default:
            printk(KERN_ERR "dma%d: unknown load_state in irq, %d\n",
                   chan->number, chan->load_state);
            return IRQ_HANDLED;
        }

        local_irq_save(flags);
        s3c2410_dma_loadbuffer(chan, chan->next);
        local_irq_restore(flags);
    } else {
        s3c2410_dma_lastxfer(chan);

        /* see if we can stop this channel.. */
        if (chan->load_state == S3C2410_DMALOAD_NONE) {
            pr_debug("dma%d: end of transfer, stopping channel (%ld)\n",
                     chan->number, jiffies);
            s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL,
                             S3C2410_DMAOP_STOP);
        }
    }

no_load:
    return IRQ_HANDLED;
}