📄 altera_avalon_dma.c
字号:
/******************************************************************************* ** License Agreement ** ** Copyright (c) 2003 Altera Corporation, San Jose, California, USA. ** All rights reserved. ** ** Permission is hereby granted, free of charge, to any person obtaining a ** copy of this software and associated documentation files (the "Software"), ** to deal in the Software without restriction, including without limitation ** the rights to use, copy, modify, merge, publish, distribute, sublicense, ** and/or sell copies of the Software, and to permit persons to whom the ** Software is furnished to do so, subject to the following conditions: ** ** The above copyright notice and this permission notice shall be included in ** all copies or substantial portions of the Software. ** ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER ** DEALINGS IN THE SOFTWARE. ** ** This agreement shall be governed in all respects by the laws of the State ** of California and by the laws of the United States of America. ** *******************************************************************************/#include "altera_avalon_dma.h"#include "sys/alt_irq.h"#include "altera_avalon_dma_regs.h"#include <errno.h>/* * alt_avalon_dma_launch_bidir() is called to launch a new transaction when * both the receive and transmit channels are using incrementing addresses, * i.e. both channels are accesing memory rather than devices. */void alt_avalon_dma_launch_bidir (alt_avalon_dma_priv* priv){ alt_avalon_dma_txslot* tx_slot; alt_avalon_dma_rxslot* rx_slot; if ((priv->tx_start != priv->tx_end) && (priv->rx_start != priv->rx_end)) { priv->active = 1; tx_slot = &priv->tx_buf[priv->tx_start]; rx_slot = &priv->rx_buf[priv->rx_start]; IOWR_ALTERA_AVALON_DMA_RADDRESS (priv->base, (alt_u32) tx_slot->from); IOWR_ALTERA_AVALON_DMA_WADDRESS (priv->base, (alt_u32) rx_slot->data); IOWR_ALTERA_AVALON_DMA_LENGTH (priv->base, (tx_slot->len > rx_slot->len) ? rx_slot->len : tx_slot->len); } else { priv->active = 0; }}/* * alt_avalon_dma_launch_txonly() is called to launch a new transaction when * only the transmit channels is using incrementing addresses, * i.e. the receive channel is accessing a single memory location (which is * probably a device register). */static void alt_avalon_dma_launch_txonly (alt_avalon_dma_priv* priv){ alt_avalon_dma_txslot* tx_slot; if (priv->tx_start != priv->tx_end) { priv->active = 1; tx_slot = &priv->tx_buf[priv->tx_start]; IOWR_ALTERA_AVALON_DMA_RADDRESS (priv->base, (alt_u32) tx_slot->from); IOWR_ALTERA_AVALON_DMA_LENGTH (priv->base, tx_slot->len); } else { priv->active = 0; }}/* * alt_avalon_dma_launch_rxonly() is called to launch a new transaction when * only the receive channel is using incrementing addresses, * i.e. the transmit channel is accessing a single memory location (which is * probably a device register). */static void alt_avalon_dma_launch_rxonly (alt_avalon_dma_priv* priv){ alt_avalon_dma_rxslot* rx_slot; if (priv->rx_start != priv->rx_end) { priv->active = 1; rx_slot = &priv->rx_buf[priv->rx_start]; IOWR_ALTERA_AVALON_DMA_WADDRESS (priv->base, (alt_u32) rx_slot->data); IOWR_ALTERA_AVALON_DMA_LENGTH (priv->base, rx_slot->len); } else { priv->active = 0; }}/* * alt_avalon_dma_ioctl is used to process ioctl request for a given DMA * device instance. See alt_dma_dev.h for the meaning of the supported * ioctl requests. */static int alt_avalon_dma_ioctl (alt_avalon_dma_priv* priv, int req, void* arg){ int status = 0; alt_u32 mode; /* * Ioctl calls should not be made while the device is active (i.e. while there * are DMA transfers outstanding), since this can lead to unpredictable * behaviour. * * The test below attempts to trap this error. It is not foolproof, * since it cannot catch concurrent calls to alt_alavalon_dma_prepare() * or alt_avalon_dma_send(), but it should at least catch the most * common class of problems. */ if ((priv->tx_start != priv->tx_end) || (priv->rx_start != priv->rx_end) || IORD_ALTERA_AVALON_DMA_LENGTH (priv->base)) { return -EIO; } /* Now process the ioctl. */ switch (req) { case ALT_DMA_TX_STREAM_ON: if (!(priv->flags & ALT_AVALON_DMA_RX_STREAM)) { IOWR_ALTERA_AVALON_DMA_RADDRESS (priv->base, (alt_u32) arg); priv->flags |= ALT_AVALON_DMA_TX_STREAM; priv->launch = alt_avalon_dma_launch_rxonly; } else { status = -EIO; } break; case ALT_DMA_TX_STREAM_OFF: priv->flags &= ~ALT_AVALON_DMA_TX_STREAM; priv->launch = alt_avalon_dma_launch_bidir; break; case ALT_DMA_RX_STREAM_ON: if (!(priv->flags & ALT_AVALON_DMA_TX_STREAM)) { IOWR_ALTERA_AVALON_DMA_WADDRESS (priv->base, (alt_u32) arg); priv->flags |= ALT_AVALON_DMA_RX_STREAM; priv->launch = alt_avalon_dma_launch_txonly; } else { status = -EIO; } break; case ALT_DMA_RX_STREAM_OFF: priv->flags &= ~ALT_AVALON_DMA_RX_STREAM; priv->launch = alt_avalon_dma_launch_bidir; break; case ALT_DMA_SET_MODE_8: priv->flags = (priv->flags & ~ALT_AVALON_DMA_MODE_MSK) | ALT_AVALON_DMA_MODE_8; break; case ALT_DMA_SET_MODE_16: priv->flags = (priv->flags & ~ALT_AVALON_DMA_MODE_MSK) | ALT_AVALON_DMA_MODE_16; break; case ALT_DMA_SET_MODE_32: priv->flags = (priv->flags & ~ALT_AVALON_DMA_MODE_MSK) | ALT_AVALON_DMA_MODE_32; break; case ALT_DMA_SET_MODE_64: priv->flags = (priv->flags & ~ALT_AVALON_DMA_MODE_MSK) | ALT_AVALON_DMA_MODE_64; break; case ALT_DMA_SET_MODE_128: priv->flags = (priv->flags & ~ALT_AVALON_DMA_MODE_MSK) | ALT_AVALON_DMA_MODE_128; break; default: status = -ENOTTY; } if (!status) { switch (priv->flags & ALT_AVALON_DMA_MODE_MSK) { case ALT_AVALON_DMA_MODE_8: mode = ALTERA_AVALON_DMA_CONTROL_BYTE_MSK; break; case ALT_AVALON_DMA_MODE_16: mode = ALTERA_AVALON_DMA_CONTROL_HW_MSK; break; case ALT_AVALON_DMA_MODE_32: mode = ALTERA_AVALON_DMA_CONTROL_WORD_MSK; break; case ALT_AVALON_DMA_MODE_64: mode = ALTERA_AVALON_DMA_CONTROL_DWORD_MSK; break; default: mode = ALTERA_AVALON_DMA_CONTROL_QWORD_MSK; } if (priv->flags & ALT_AVALON_DMA_TX_STREAM) { IOWR_ALTERA_AVALON_DMA_CONTROL (priv->base, mode | ALTERA_AVALON_DMA_CONTROL_GO_MSK | ALTERA_AVALON_DMA_CONTROL_I_EN_MSK | ALTERA_AVALON_DMA_CONTROL_REEN_MSK | ALTERA_AVALON_DMA_CONTROL_WEEN_MSK | ALTERA_AVALON_DMA_CONTROL_LEEN_MSK | ALTERA_AVALON_DMA_CONTROL_RCON_MSK); } else if (priv->flags & ALT_AVALON_DMA_RX_STREAM) { IOWR_ALTERA_AVALON_DMA_CONTROL (priv->base, mode | ALTERA_AVALON_DMA_CONTROL_GO_MSK | ALTERA_AVALON_DMA_CONTROL_I_EN_MSK | ALTERA_AVALON_DMA_CONTROL_REEN_MSK | ALTERA_AVALON_DMA_CONTROL_WEEN_MSK | ALTERA_AVALON_DMA_CONTROL_LEEN_MSK | ALTERA_AVALON_DMA_CONTROL_WCON_MSK); } else { IOWR_ALTERA_AVALON_DMA_CONTROL (priv->base, mode | ALTERA_AVALON_DMA_CONTROL_GO_MSK | ALTERA_AVALON_DMA_CONTROL_I_EN_MSK | ALTERA_AVALON_DMA_CONTROL_REEN_MSK | ALTERA_AVALON_DMA_CONTROL_WEEN_MSK | ALTERA_AVALON_DMA_CONTROL_LEEN_MSK); } } return status;}/* * Perform an ioctl request for a transmit channel. */int alt_avalon_dma_tx_ioctl (alt_dma_txchan dma,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -