# Include "dma. h"
/* How to use:
*
* Call the specified DMA channel for the request_dma request. If the return value is 0, the channel is available;
* Use free_dma to release the channel after use.
*/
/* Dma_chan_busy [n]! = 0 indicates that the channel is unavailable
* DMA0 is used to refresh DRAM.
* DMA4 is used as a level connection.
*/
Static volatile unsigned int dma_chan_busy [MAX_DMA_CHANNELS] = {
1, 0, 0, 0, 1, 0, 0, 0
};
/* Replace the data pointed to by * p with newval. According to the xchgl keyword, this value is a 32-bit value.
* Xchgl is an atomic operation that can save cli and sti, and has good stability and performance.
*/
Static _ inline _ unsigned int mutex_atomic_swap (volatile unsigned int * p, unsigned int newval)
{
Unsigned int semval = newval;
/* If one of the operands for the XCHG instructions is a memory ref,
* It makes the swap an uninterruptible RMW cycle.
*
* One operand must be in memory, the other in a register, otherwise
* The swap may not be atomic.
*/
Asm _ volatile _ ("xchgl % 2, % 0/n"
:/* Outputs: semval */"= r" (semval)
:/* Inputs: newval, p */"0" (semval), "m" (* p)
);/* P is a var, containing an address */
Return semval;
}/* Mutex_atomic_swap */
# Define EINVAL 1
# Define EBUSY 2
Int request_dma (unsigned int dmanr)
{
If (dmanr> = MAX_DMA_CHANNELS)
Return-EINVAL;
If (mutex_atomic_swap (& dma_chan_busy [dmanr], 1 )! = 0)
Return-EBUSY;
Else
/* Old flag was 0, now contains 1 to indicate busy */
Return 0;
}/* Request_dma */
# Define printk
Void free_dma (unsigned int dmanr)
{
If (dmanr> = MAX_DMA_CHANNELS ){
Printk ("Trying to free DMA % d/n", dmanr );
Return;
}
If (mutex_atomic_swap (& dma_chan_busy [dmanr], 0) = 0)
Printk ("Trying to free DMA % d/n", dmanr );
}/* Free_dma */