📄 dma_ep93xx.c
字号:
* last: 1 if this is the last buffer in this stream, 0 otherwise. * ****************************************************************************/intep93xx_dma_add_buffer(int handle, unsigned int source, unsigned int dest, unsigned int size, unsigned int last, unsigned int buf_id){ unsigned int flags; ep93xx_dma_t * dma; int channel; /* * Get the DMA hw channel # from the handle. */ channel = dma_get_channel_from_handle(handle); /* * See if this is a valid handle. */ if (channel < 0) { printk(KERN_ERR "DMA Add Buffer: Invalid dma handle.\n"); return(-EINVAL); } /* * Get a pointer to the dma instance. */ dma = &dma_chan[channel]; /* * Mask interrupts and hold on to the original state. */ local_irq_save(flags); /* * If the buffer queue is full, last_buffer is the same as current_buffer and * we're not tranfering, or last_buffer is pointing to a used buffer, then exit. * TODO: do I need to do any more checks? */ if (dma->total_buffers >= MAX_EP93XX_DMA_BUFFERS) { /* * Restore the state of the irqs */ local_irq_restore(flags); /* * Fail. */ return(-1); } /* * Add this buffer to the queue */ dma->buffer_queue[dma->last_buffer].source = source; dma->buffer_queue[dma->last_buffer].dest = dest; dma->buffer_queue[dma->last_buffer].size = size; dma->buffer_queue[dma->last_buffer].last = last; dma->buffer_queue[dma->last_buffer].buf_id = buf_id; /* * Reset the used field of the buffer structure. */ dma->buffer_queue[dma->last_buffer].used = FALSE; /* * Increment the End Item Pointer. */ dma->last_buffer = (dma->last_buffer + 1) % MAX_EP93XX_DMA_BUFFERS; /* * Increment the new buffers counter and the total buffers counter */ dma->new_buffers++; dma->total_buffers++; /* * restore the interrupt state. */ local_irq_restore(flags); /* * Check if the channel was starved into a stopped state. */ if (dma->pause && dma->xfer_enable) { if (dma->new_buffers >= 1) { DPRINTK("DMA - calling start from add after starve. \n"); /* * The channel was starved into a stopped state, and we've got * 2 new buffers, so start tranferring again. */ ep93xx_dma_start(handle, 1, 0); } } /* * Success. */ return(0);}/***************************************************************************** * * int ep93xx_dma_remove_buffer(int handle, unsigned int * address, * unsigned int * size) * * Description: Remove a buffer entry from the DMA buffer queue. If * buffer was removed successfully, return 0, otherwise * return -1. * * handle: handle for the channel to remove a buffer from. * address: Pointer to an integer which is filled in with the start * address of the removed buffer. * size: Pointer to an integer which is filled in with the size in * bytes of the removed buffer. * ****************************************************************************/intep93xx_dma_remove_buffer(int handle, unsigned int * buf_id){ unsigned int test; unsigned int loop; int return_val = -1; unsigned int flags; ep93xx_dma_t *dma; int channel; /* * Get the DMA hw channel # from the handle. */ channel = dma_get_channel_from_handle(handle); /* * See if this is a valid handle. */ if (channel < 0) { printk(KERN_ERR "DMA Remove Buffer: Invalid dma handle.\n"); return(-EINVAL); } dma = &dma_chan[channel]; /* * Mask interrupts and hold on to the original state. */ local_irq_save(flags); /* * Make sure there are used buffers to be returned. */ if (dma->used_buffers) { test = dma->last_buffer; for (loop = 0; loop < MAX_EP93XX_DMA_BUFFERS; loop++) { if (dma->buffer_queue[test].used && (dma->buffer_queue[test].buf_id != -1)) { /*DPRINTK("buffer %d used \n", test); */ /* * This is a used buffer, fill in the buf_id pointer * with the buf_id for this buffer. */ *buf_id = dma->buffer_queue[test].buf_id; /* * Reset this buffer structure */ dma->buffer_queue[test].buf_id = -1; /* * Decrement the used buffer counter, and the total buffer counter. */ dma->used_buffers--; dma->total_buffers--; /* * Successful removal of a buffer, so set the return * value to 0, then exit this loop. */ return_val = 0; break; } /* * This buffer isn't used, let's see if the next one is. */ test = (test + 1) % MAX_EP93XX_DMA_BUFFERS; } } /* * Restore interrupts. */ local_irq_restore(flags); /* * Success. */ return(return_val);}/***************************************************************************** * * int ep93xx_dma_pause(int handle, unsigned int channels, * unsigned int * handles) * * Description: Disable any ongoing transfer for the given channel, retaining * the state of the current buffer transaction so that upon * resume, the dma will continue where it left off. * * handle: Handle for the channel to be paused. If this is a pause for * for multiple channels, handle is a valid handle for one of * the channels to be paused. * channels: number of channel to pause transfers on. * handles: Pointer to an array of handles, one for each channel which * to be paused. If this pause is intended only for one * channel, this field should be set to NULL. * ****************************************************************************/intep93xx_dma_pause(int handle, unsigned int channels, unsigned int * handles){ unsigned int flags; ep93xx_dma_t * dma; int channel; DPRINTK("ep93xx_dma_pause \n"); /* * Mask interrupts and hold on to the original state. */ local_irq_save(flags); /* * Get the DMA hw channel # from the handle. */ channel = dma_get_channel_from_handle(handle); /* * See if this is a valid handle. */ if (channel < 0) { /* * restore interrupts. */ local_irq_restore(flags); printk(KERN_ERR "DMA Pause: Invalid dma handle.\n"); /* * Fail. */ return(-EINVAL); } DPRINTK("DMA %d: pause \n", channel); /* * Set up a pointer to the dma instance data. */ dma = &dma_chan[channel]; /* * Check if we're already paused. */ if (dma->pause) { /* * We're paused, but are we stopped? */ if (dma->xfer_enable) /* * Put the channel in the stopped state. */ dma->xfer_enable = FALSE; DPRINTK("DMA Pause - already paused."); } else { /* * Put the channel into the stopped state. */ dma->xfer_enable = FALSE; dma->pause = TRUE; } /* * restore interrupts. */ local_irq_restore(flags); /* * Already paused, so exit. */ return(0);}/***************************************************************************** * * void ep93xx_dma_flush(int handle) * * Description: Flushes all queued buffers and transfers in progress * for the given channel. Return the buffer entries * to the calling function. * * handle: handle for the channel for which the flush is intended. * ****************************************************************************/intep93xx_dma_flush(int handle){ unsigned int loop, flags; ep93xx_dma_t * dma; int channel; unsigned int M2P_reg_base; /* * Get the DMA hw channel # from the handle. */ channel = dma_get_channel_from_handle(handle); /* * See if this is a valid handle. */ if (channel < 0) { printk(KERN_ERR "DMA Flush: Invalid dma handle.\n"); return(-EINVAL); } DPRINTK("DMA %d: flush \n", channel); /* * Set up a pointer to the dma instance data for this channel */ dma = &dma_chan[channel]; /* * Mask interrupts and hold on to the original state. */ local_irq_save(flags); for (loop = 0; loop < MAX_EP93XX_DMA_BUFFERS; loop++) dma->buffer_queue[loop].buf_id = -1; /* * Set the Current and Last item to zero. */ dma->current_buffer = 0; dma->last_buffer = 0; /* * Reset the Buffer counters */ dma->used_buffers = 0; dma->new_buffers = 0; dma->total_buffers = 0; /* * reset the Total bytes counter. */ dma->total_bytes = 0; M2P_reg_base = dma_chan[channel].reg_base; /* * restore interrupts. */ local_irq_restore(flags); /* * Success. */ return(0);}/***************************************************************************** * * int ep93xx_dma_queue_full(int handle) * * Description: Query to determine if the DMA queue of buffers for * a given channel is full. * 0 = queue is full * 1 = queue is not full * * handle: handle for the channel to query. * ****************************************************************************/intep93xx_dma_queue_full(int handle){ int list_full = 0; unsigned int flags; int channel; /* * Get the DMA hw channel # from the handle. */ channel = dma_get_channel_from_handle(handle); /* * See if this is a valid handle. */ if (channel < 0) { printk(KERN_ERR "DMA Queue Full: Invalid dma handle.\n"); return(-EINVAL); } DPRINTK("DMA %d: queue full \n", channel); /* * Mask interrupts and hold on to the original state. */ local_irq_save(flags); /* * If the last item is equal to the used item then * the queue is full. */ if (dma_chan[channel].total_buffers < MAX_EP93XX_DMA_BUFFERS) list_full = FALSE; else list_full = TRUE; /* * restore interrupts. */ local_irq_restore(flags); return(list_full);}/***************************************************************************** * * int ep93xx_dma_get_position() * * Description: Takes two integer pointers and fills them with the start * and current address of the buffer currently transferring * on the specified DMA channel. * * handle handle for the channel to query. * *buf_id buffer id for the current buffer transferring on the * dma channel. * *total total bytes transferred on the channel. Only counts * whole buffers transferred. * *current_frac number of bytes transferred so far in the current buffer. ****************************************************************************/intep93xx_dma_get_position(int handle, unsigned int * buf_id, unsigned int * total, unsigned int * current_frac ){ int channel; ep93xx_dma_t * dma; unsigned int buf_id1, total1, current_frac1, buf_id2, total2; unsigned int Status, NextBuffer, StateIsBufNext, M2P_reg_base=0; unsigned int pause1, pause2; /* * Get the DMA hw channel # from the handle. See if this is a * valid handle. */ channel = dma_get_channel_from_handle(handle); if (channel < 0) { printk(KERN_ERR "DMA Get Position: Invalid dma handle.\n"); return(-EINVAL); } dma = &dma_chan[channel]; /* * If DMA moves to a new buffer in the middle of us grabbing the * buffer info, then do it over again. */ do{ buf_id1 = dma->buffer_queue[dm
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -