// SPDX-License-Identifier: GPL-2.0
/*
* linux / kernel / dma . c : A DMA channel allocator . Inspired by linux / kernel / irq . c .
*
* Written by Hennus Bergman , 1992 .
*
* 1994 / 12 / 26 : Changes by Alex Nash to fix a minor bug in / proc / dma .
* In the previous version the reported device could end up being wrong ,
* if a device requested a DMA channel that was already in use .
* [ It also happened to remove the sizeof ( char * ) = = sizeof ( int )
* assumption introduced because of those / proc / dma patches . - - Hennus ]
*/
#include <linux/export.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/seq_file.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
#include <asm /dma.h>
/* A note on resource allocation:
*
* All drivers needing DMA channels , should allocate and release them
* through the public routines ` request_dma ( ) ' and ` free_dma ( ) ' .
*
* In order to avoid problems , all processes should allocate resources in
* the same sequence and release them in the reverse order .
*
* So , when allocating DMAs and IRQs , first allocate the IRQ , then the DMA .
* When releasing them , first release the DMA , then release the IRQ .
* If you don ' t , you may cause allocation requests to fail unnecessarily .
* This doesn ' t really matter now , but it will once we get real semaphores
* in the kernel .
*/
DEFINE_SPINLOCK(dma_spin_lock);
/*
* If our port doesn ' t define this it has no PC like DMA
*/
#ifdef MAX_DMA_CHANNELS
/* Channel n is busy iff dma_chan_busy[n].lock != 0.
* DMA0 used to be reserved for DRAM refresh , but apparently not any more . . .
* DMA4 is reserved for cascading .
*/
struct dma_chan {
int lock;
const char *device_id;
};
static struct dma_chan dma_chan_busy[MAX_DMA_CHANNELS] = {
[4 ] = { 1 , "cascade" },
};
/**
* request_dma - request and reserve a system DMA channel
* @ dmanr : DMA channel number
* @ device_id : reserving device ID string , used in / proc / dma
*/
int request_dma(unsigned int dmanr, const char * device_id)
{
if (dmanr >= MAX_DMA_CHANNELS)
return -EINVAL;
if (xchg(&dma_chan_busy[dmanr].lock, 1 ) != 0 )
return -EBUSY;
dma_chan_busy[dmanr].device_id = device_id;
/* old flag was 0, now contains 1 to indicate busy */
return 0 ;
} /* request_dma */
/**
* free_dma - free a reserved system DMA channel
* @ dmanr : DMA channel number
*/
void free_dma(unsigned int dmanr)
{
if (dmanr >= MAX_DMA_CHANNELS) {
printk(KERN_WARNING "Trying to free DMA%d\n" , dmanr);
return ;
}
if (xchg(&dma_chan_busy[dmanr].lock, 0 ) == 0 ) {
printk(KERN_WARNING "Trying to free free DMA%d\n" , dmanr);
return ;
}
} /* free_dma */
#else
int request_dma(unsigned int dmanr, const char *device_id)
{
return -EINVAL;
}
void free_dma(unsigned int dmanr)
{
}
#endif
#ifdef CONFIG_PROC_FS
#ifdef MAX_DMA_CHANNELS
static int proc_dma_show(struct seq_file *m, void *v)
{
int i;
for (i = 0 ; i < MAX_DMA_CHANNELS ; i++) {
if (dma_chan_busy[i].lock) {
seq_printf(m, "%2d: %s\n" , i,
dma_chan_busy[i].device_id);
}
}
return 0 ;
}
#else
static int proc_dma_show(struct seq_file *m, void *v)
{
seq_puts(m, "No DMA\n" );
return 0 ;
}
#endif /* MAX_DMA_CHANNELS */
static int __init proc_dma_init(void )
{
proc_create_single("dma" , 0 , NULL, proc_dma_show);
return 0 ;
}
__initcall(proc_dma_init);
#endif
EXPORT_SYMBOL(request_dma);
EXPORT_SYMBOL(free_dma);
EXPORT_SYMBOL(dma_spin_lock);
Messung V0.5 in Prozent C=93 H=92 G=92
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet am 2026-09-29)
¤
*© Formatika GbR, Deutschland