www.pudn.com > soundmodem.rar > smdma.h


/*****************************************************************************/ 
 
/* 
 *	smdma.h  --  soundcard radio modem driver dma buffer routines. 
 * 
 *	Copyright (C) 1996  Thomas Sailer (sailer@ife.ee.ethz.ch) 
 * 
 *	This program is free software; you can redistribute it and/or modify 
 *	it under the terms of the GNU General Public License as published by 
 *	the Free Software Foundation; either version 2 of the License, or 
 *	(at your option) any later version. 
 * 
 *	This program is distributed in the hope that it will be useful, 
 *	but WITHOUT ANY WARRANTY; without even the implied warranty of 
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 *	GNU General Public License for more details. 
 * 
 *	You should have received a copy of the GNU General Public License 
 *	along with this program; if not, write to the Free Software 
 *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 
 * 
 *  Please note that the GPL allows you to use the driver, NOT the radio. 
 *  In order to use the radio, you need a license from the communications 
 *  authority of your country. 
 * 
 */ 
 
#ifndef _SMDMA_H 
#define _SMDMA_H 
 
/* ---------------------------------------------------------------------- */ 
 
#include "sm.h" 
 
/* ---------------------------------------------------------------------- */ 
 
#define DMA_MODE_AUTOINIT      0x10 
#define NUM_FRAGMENTS          4 
 
/* 
 * NOTE: make sure that hdlcdrv_hdlcbuffer contains enough space 
 * for the modulator to fill the whole DMA buffer without underrun 
 * at the highest possible baud rate, otherwise the TX state machine will 
 * not work correctly. That is (9k6 FSK): HDLCDRV_HDLCBUFFER > 6*NUM_FRAGMENTS 
 */  
 
/* --------------------------------------------------------------------- */ 
/* 
 * ===================== DMA buffer management =========================== 
 */ 
 
/* 
 * returns the number of samples per fragment 
 */ 
extern __inline__ unsigned int dma_setup(struct sm_state *sm, int send, unsigned int dmanr) 
{ 
	if (send) { 
		disable_dma(dmanr); 
		clear_dma_ff(dmanr); 
		set_dma_mode(dmanr, DMA_MODE_WRITE | DMA_MODE_AUTOINIT); 
		set_dma_addr(dmanr, virt_to_bus(sm->dma.obuf)); 
		set_dma_count(dmanr, sm->dma.ofragsz * NUM_FRAGMENTS); 
		enable_dma(dmanr); 
		if (sm->dma.o16bit) 
			return sm->dma.ofragsz/2; 
		return sm->dma.ofragsz; 
	} else { 
		disable_dma(dmanr); 
		clear_dma_ff(dmanr); 
		set_dma_mode(dmanr, DMA_MODE_READ | DMA_MODE_AUTOINIT); 
		set_dma_addr(dmanr, virt_to_bus(sm->dma.ibuf)); 
		set_dma_count(dmanr, sm->dma.ifragsz * NUM_FRAGMENTS); 
		enable_dma(dmanr); 
		if (sm->dma.i16bit) 
			return sm->dma.ifragsz/2; 
		return sm->dma.ifragsz; 
	} 
} 
 
/* --------------------------------------------------------------------- */ 
 
extern __inline__ unsigned int dma_ptr(struct sm_state *sm, int send, unsigned int dmanr, 
				       unsigned int *curfrag) 
{ 
	unsigned int dmaptr, sz, frg, offs; 
	 
	dmaptr = get_dma_residue(dmanr); 
	if (send) { 
		sz = sm->dma.ofragsz * NUM_FRAGMENTS; 
		if (dmaptr == 0 || dmaptr > sz) 
			dmaptr = sz; 
		dmaptr--; 
		frg = dmaptr / sm->dma.ofragsz; 
		offs = (dmaptr % sm->dma.ofragsz) + 1; 
		*curfrag = NUM_FRAGMENTS - 1 - frg; 
#ifdef SM_DEBUG 
		if (!sm->debug_vals.dma_residue || offs < sm->debug_vals.dma_residue) 
			sm->debug_vals.dma_residue = offs; 
#endif /* SM_DEBUG */ 
		if (sm->dma.o16bit) 
			return offs/2; 
		return offs; 
	} else { 
		sz = sm->dma.ifragsz * NUM_FRAGMENTS; 
		if (dmaptr == 0 || dmaptr > sz) 
			dmaptr = sz; 
		dmaptr--; 
		frg = dmaptr / sm->dma.ifragsz; 
		offs = (dmaptr % sm->dma.ifragsz) + 1; 
		*curfrag = NUM_FRAGMENTS - 1 - frg; 
#ifdef SM_DEBUG 
		if (!sm->debug_vals.dma_residue || offs < sm->debug_vals.dma_residue) 
			sm->debug_vals.dma_residue = offs; 
#endif /* SM_DEBUG */ 
		if (sm->dma.i16bit) 
			return offs/2; 
		return offs; 
	} 
} 
 
/* --------------------------------------------------------------------- */ 
 
extern __inline__ int dma_end_transmit(struct sm_state *sm, unsigned int curfrag) 
{ 
	unsigned int diff = (NUM_FRAGMENTS + curfrag - sm->dma.ofragptr) % NUM_FRAGMENTS; 
 
	sm->dma.ofragptr = curfrag; 
	if (sm->dma.ptt_cnt <= 0) { 
		sm->dma.ptt_cnt = 0; 
		return 0; 
	} 
	sm->dma.ptt_cnt -= diff; 
	if (sm->dma.ptt_cnt <= 0) { 
		sm->dma.ptt_cnt = 0; 
		return -1; 
	} 
	return 0; 
} 
 
extern __inline__ void dma_transmit(struct sm_state *sm) 
{ 
	void *p; 
 
	while (sm->dma.ptt_cnt < NUM_FRAGMENTS && hdlcdrv_ptt(&sm->hdrv)) { 
		p = (unsigned char *)sm->dma.obuf + sm->dma.ofragsz * 
			((sm->dma.ofragptr + sm->dma.ptt_cnt) % NUM_FRAGMENTS); 
		if (sm->dma.o16bit) { 
			time_exec(sm->debug_vals.mod_cyc,  
				  sm->mode_tx->modulator_s16(sm, p, sm->dma.ofragsz/2)); 
		} else { 
			time_exec(sm->debug_vals.mod_cyc,  
				  sm->mode_tx->modulator_u8(sm, p, sm->dma.ofragsz)); 
		} 
		sm->dma.ptt_cnt++; 
	} 
} 
 
extern __inline__ void dma_init_transmit(struct sm_state *sm) 
{ 
	sm->dma.ofragptr = 0; 
	sm->dma.ptt_cnt = 0; 
} 
 
extern __inline__ void dma_start_transmit(struct sm_state *sm) 
{ 
	sm->dma.ofragptr = 0; 
	if (sm->dma.o16bit) { 
		time_exec(sm->debug_vals.mod_cyc,  
			  sm->mode_tx->modulator_s16(sm, sm->dma.obuf, sm->dma.ofragsz/2)); 
	} else { 
		time_exec(sm->debug_vals.mod_cyc,  
			  sm->mode_tx->modulator_u8(sm, sm->dma.obuf, sm->dma.ofragsz)); 
	} 
	sm->dma.ptt_cnt = 1; 
} 
 
extern __inline__ void dma_clear_transmit(struct sm_state *sm) 
{ 
	sm->dma.ptt_cnt = 0; 
	memset(sm->dma.obuf, (sm->dma.o16bit) ? 0 : 0x80, sm->dma.ofragsz * NUM_FRAGMENTS); 
} 
 
/* --------------------------------------------------------------------- */ 
 
extern __inline__ void dma_receive(struct sm_state *sm, unsigned int curfrag) 
{ 
	void *p; 
 
	while (sm->dma.ifragptr != curfrag) { 
		if (sm->dma.ifragptr) 
			p = (unsigned char *)sm->dma.ibuf +  
				sm->dma.ifragsz * sm->dma.ifragptr; 
		else { 
			p = (unsigned char *)sm->dma.ibuf + NUM_FRAGMENTS * sm->dma.ifragsz; 
			memcpy(p, sm->dma.ibuf, sm->dma.ifragsz); 
		} 
		if (sm->dma.o16bit) { 
			time_exec(sm->debug_vals.demod_cyc,  
				  sm->mode_rx->demodulator_s16(sm, p, sm->dma.ifragsz/2)); 
		} else { 
			time_exec(sm->debug_vals.demod_cyc,  
				  sm->mode_rx->demodulator_u8(sm, p, sm->dma.ifragsz)); 
		} 
		sm->dma.ifragptr = (sm->dma.ifragptr + 1) % NUM_FRAGMENTS; 
	} 
} 
 
extern __inline__ void dma_init_receive(struct sm_state *sm) 
{ 
	sm->dma.ifragptr = 0; 
} 
 
/* --------------------------------------------------------------------- */ 
#endif /* _SMDMA_H */