예제 #1
0
static int s3c2410_dma_started(struct s3c2410_dma_chan *chan)
{
    unsigned long flags;

    local_irq_save(flags);

    dbg_showchan(chan);

    /* if we've only loaded one buffer onto the channel, then chec
     * to see if we have another, and if so, try and load it so when
     * the first buffer is finished, the new one will be loaded onto
     * the channel */

    if (chan->next != NULL) {
        if (chan->load_state == S3C2410_DMALOAD_1LOADED) {

            if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
                pr_debug("%s: buff not yet loaded, no more todo\n",
                         __func__);
            } else {
                chan->load_state = S3C2410_DMALOAD_1RUNNING;
                s3c2410_dma_loadbuffer(chan, chan->next);
            }

        } else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) {
            s3c2410_dma_loadbuffer(chan, chan->next);
        }
    }


    local_irq_restore(flags);

    return 0;

}
예제 #2
0
static inline void
s3c2410_dma_lastxfer(s3c2410_dma_chan_t *chan)
{
	pr_debug("dma%d: s3c2410_dma_lastxfer: load_state %d\n",
		 chan->number, chan->load_state);

	switch (chan->load_state) {
	case S3C2410_DMALOAD_NONE:
		break;

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

	default:
		pr_debug("dma%d: lastxfer: unhandled load_state %d with no next",
			 chan->number, chan->load_state);
		return;

	}

	/* hopefully this'll shut the damned thing up after the transfer... */
	dma_wrreg(chan, S3C2410_DMA_DCON, chan->dcon | S3C2410_DCON_NORELOAD);
}
예제 #3
0
static inline void
s3c2410_dma_lastxfer(struct s3c2410_dma_chan *chan)
{

	switch (chan->load_state) {
	case S3C2410_DMALOAD_NONE:
		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;
		}
		break;

	case S3C2410_DMALOAD_1LOADED_1RUNNING:
		/* I belive in this case we do not have anything to do
		 * until the next buffer comes along, and we turn off the
		 * reload */
		return;

	default:
		pr_debug("dma%d: lastxfer: unhandled load_state %d with no next\n",
			 chan->number, chan->load_state);
		return;

	}

	/* hopefully this'll shut the damned thing up after the transfer... */
	dma_wrreg(chan, S3C2410_DMA_DCON, chan->dcon | S3C2410_DCON_NORELOAD);
}
예제 #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;
}
예제 #5
0
int s3c2410_dma_enqueue(unsigned int channel, void *id,
                        dma_addr_t data, int size)
{
    struct s3c2410_dma_chan *chan = lookup_dma_channel(channel);
    struct s3c2410_dma_buf *buf;
    unsigned long flags;

    if (chan == NULL)
        return -EINVAL;

    pr_debug("%s: id=%p, data=%08x, size=%d\n",
             __func__, id, (unsigned int)data, size);

    buf = kmem_cache_alloc(dma_kmem, GFP_ATOMIC);
    if (buf == NULL) {
        pr_debug("%s: out of memory (%ld alloc)\n",
                 __func__, (long)sizeof(*buf));
        return -ENOMEM;
    }

    //pr_debug("%s: new buffer %p\n", __func__, buf);
    //dbg_showchan(chan);

    buf->next  = NULL;
    buf->data  = buf->ptr = data;
    buf->size  = size;
    buf->id    = id;
    buf->magic = BUF_MAGIC;

    local_irq_save(flags);

    if (chan->curr == NULL) {
        /* we've got nothing loaded... */
        pr_debug("%s: buffer %p queued onto empty channel\n",
                 __func__, buf);

        chan->curr = buf;
        chan->end  = buf;
        chan->next = NULL;
    } else {
        pr_debug("dma%d: %s: buffer %p queued onto non-empty channel\n",
                 chan->number, __func__, buf);

        if (chan->end == NULL)
            pr_debug("dma%d: %s: %p not empty, and chan->end==NULL?\n",
                     chan->number, __func__, chan);

        chan->end->next = buf;
        chan->end = buf;
    }

    /* if necessary, update the next buffer field */
    if (chan->next == NULL)
        chan->next = buf;

    /* check to see if we can load a buffer */
    if (chan->state == S3C2410_DMA_RUNNING) {
        if (chan->load_state == S3C2410_DMALOAD_1LOADED && 1) {
            if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
                printk(KERN_ERR "dma%d: loadbuffer:"
                       "timeout loading buffer\n",
                       chan->number);
                dbg_showchan(chan);
                local_irq_restore(flags);
                return -EINVAL;
            }
        }

        while (s3c2410_dma_canload(chan) && chan->next != NULL) {
            s3c2410_dma_loadbuffer(chan, chan->next);
        }
    } else if (chan->state == S3C2410_DMA_IDLE) {
        if (chan->flags & S3C2410_DMAF_AUTOSTART) {
            s3c2410_dma_ctrl(chan->number | DMACH_LOW_LEVEL,
                             S3C2410_DMAOP_START);
        }
    }

    local_irq_restore(flags);
    return 0;
}
예제 #6
0
static int s3c2410_dma_start(struct s3c2410_dma_chan *chan)
{
    unsigned long tmp;
    unsigned long flags;

    pr_debug("s3c2410_start_dma: channel=%d\n", chan->number);

    local_irq_save(flags);

    if (chan->state == S3C2410_DMA_RUNNING) {
        pr_debug("s3c2410_start_dma: already running (%d)\n", chan->state);
        local_irq_restore(flags);
        return 0;
    }

    chan->state = S3C2410_DMA_RUNNING;

    /* check wether there is anything to load, and if not, see
     * if we can find anything to load
     */

    if (chan->load_state == S3C2410_DMALOAD_NONE) {
        if (chan->next == NULL) {
            printk(KERN_ERR "dma%d: channel has nothing loaded\n",
                   chan->number);
            chan->state = S3C2410_DMA_IDLE;
            local_irq_restore(flags);
            return -EINVAL;
        }

        s3c2410_dma_loadbuffer(chan, chan->next);
    }

    dbg_showchan(chan);

    /* enable the channel */

    if (!chan->irq_enabled) {
        enable_irq(chan->irq);
        chan->irq_enabled = 1;
    }

    /* start the channel going */

    tmp = dma_rdreg(chan, S3C2410_DMA_DMASKTRIG);
    tmp &= ~S3C2410_DMASKTRIG_STOP;
    tmp |= S3C2410_DMASKTRIG_ON;
    dma_wrreg(chan, S3C2410_DMA_DMASKTRIG, tmp);

    pr_debug("dma%d: %08lx to DMASKTRIG\n", chan->number, tmp);

#if 0
    /* the dma buffer loads should take care of clearing the AUTO
     * reloading feature */
    tmp = dma_rdreg(chan, S3C2410_DMA_DCON);
    tmp &= ~S3C2410_DCON_NORELOAD;
    dma_wrreg(chan, S3C2410_DMA_DCON, tmp);
#endif

    s3c2410_dma_call_op(chan, S3C2410_DMAOP_START);

    dbg_showchan(chan);

    /* if we've only loaded one buffer onto the channel, then chec
     * to see if we have another, and if so, try and load it so when
     * the first buffer is finished, the new one will be loaded onto
     * the channel */

    if (chan->next != NULL) {
        if (chan->load_state == S3C2410_DMALOAD_1LOADED) {

            if (s3c2410_dma_waitforload(chan, __LINE__) == 0) {
                pr_debug("%s: buff not yet loaded, no more todo\n",
                         __func__);
            } else {
                chan->load_state = S3C2410_DMALOAD_1RUNNING;
                s3c2410_dma_loadbuffer(chan, chan->next);
            }

        } else if (chan->load_state == S3C2410_DMALOAD_1RUNNING) {
            s3c2410_dma_loadbuffer(chan, chan->next);
        }
    }


    local_irq_restore(flags);

    return 0;
}