File: /usr/src/linux/drivers/net/hamradio/soundmodem/smdma.h

1     /*****************************************************************************/
2     
3     /*
4      *	smdma.h  --  soundcard radio modem driver dma buffer routines.
5      *
6      *	Copyright (C) 1996  Thomas Sailer (sailer@ife.ee.ethz.ch)
7      *
8      *	This program is free software; you can redistribute it and/or modify
9      *	it under the terms of the GNU General Public License as published by
10      *	the Free Software Foundation; either version 2 of the License, or
11      *	(at your option) any later version.
12      *
13      *	This program is distributed in the hope that it will be useful,
14      *	but WITHOUT ANY WARRANTY; without even the implied warranty of
15      *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16      *	GNU General Public License for more details.
17      *
18      *	You should have received a copy of the GNU General Public License
19      *	along with this program; if not, write to the Free Software
20      *	Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21      *
22      *  Please note that the GPL allows you to use the driver, NOT the radio.
23      *  In order to use the radio, you need a license from the communications
24      *  authority of your country.
25      *
26      */
27     
28     #ifndef _SMDMA_H
29     #define _SMDMA_H
30     
31     /* ---------------------------------------------------------------------- */
32     
33     #include "sm.h"
34     
35     /* ---------------------------------------------------------------------- */
36     
37     #define DMA_MODE_AUTOINIT      0x10
38     #define NUM_FRAGMENTS          4
39     
40     /*
41      * NOTE: make sure that hdlcdrv_hdlcbuffer contains enough space
42      * for the modulator to fill the whole DMA buffer without underrun
43      * at the highest possible baud rate, otherwise the TX state machine will
44      * not work correctly. That is (9k6 FSK): HDLCDRV_HDLCBUFFER > 6*NUM_FRAGMENTS
45      */ 
46     
47     /* --------------------------------------------------------------------- */
48     /*
49      * ===================== DMA buffer management ===========================
50      */
51     
52     /*
53      * returns the number of samples per fragment
54      */
55     extern __inline__ unsigned int dma_setup(struct sm_state *sm, int send, unsigned int dmanr)
56     {
57     	if (send) {
58     		disable_dma(dmanr);
59     		clear_dma_ff(dmanr);
60     		set_dma_mode(dmanr, DMA_MODE_WRITE | DMA_MODE_AUTOINIT);
61     		set_dma_addr(dmanr, virt_to_bus(sm->dma.obuf));
62     		set_dma_count(dmanr, sm->dma.ofragsz * NUM_FRAGMENTS);
63     		enable_dma(dmanr);
64     		if (sm->dma.o16bit)
65     			return sm->dma.ofragsz/2;
66     		return sm->dma.ofragsz;
67     	} else {
68     		disable_dma(dmanr);
69     		clear_dma_ff(dmanr);
70     		set_dma_mode(dmanr, DMA_MODE_READ | DMA_MODE_AUTOINIT);
71     		set_dma_addr(dmanr, virt_to_bus(sm->dma.ibuf));
72     		set_dma_count(dmanr, sm->dma.ifragsz * NUM_FRAGMENTS);
73     		enable_dma(dmanr);
74     		if (sm->dma.i16bit)
75     			return sm->dma.ifragsz/2;
76     		return sm->dma.ifragsz;
77     	}
78     }
79     
80     /* --------------------------------------------------------------------- */
81     
82     extern __inline__ unsigned int dma_ptr(struct sm_state *sm, int send, unsigned int dmanr,
83     				       unsigned int *curfrag)
84     {
85     	unsigned int dmaptr, sz, frg, offs;
86     	
87     	dmaptr = get_dma_residue(dmanr);
88     	if (send) {
89     		sz = sm->dma.ofragsz * NUM_FRAGMENTS;
90     		if (dmaptr == 0 || dmaptr > sz)
91     			dmaptr = sz;
92     		dmaptr--;
93     		frg = dmaptr / sm->dma.ofragsz;
94     		offs = (dmaptr % sm->dma.ofragsz) + 1;
95     		*curfrag = NUM_FRAGMENTS - 1 - frg;
96     #ifdef SM_DEBUG
97     		if (!sm->debug_vals.dma_residue || offs < sm->debug_vals.dma_residue)
98     			sm->debug_vals.dma_residue = offs;
99     #endif /* SM_DEBUG */
100     		if (sm->dma.o16bit)
101     			return offs/2;
102     		return offs;
103     	} else {
104     		sz = sm->dma.ifragsz * NUM_FRAGMENTS;
105     		if (dmaptr == 0 || dmaptr > sz)
106     			dmaptr = sz;
107     		dmaptr--;
108     		frg = dmaptr / sm->dma.ifragsz;
109     		offs = (dmaptr % sm->dma.ifragsz) + 1;
110     		*curfrag = NUM_FRAGMENTS - 1 - frg;
111     #ifdef SM_DEBUG
112     		if (!sm->debug_vals.dma_residue || offs < sm->debug_vals.dma_residue)
113     			sm->debug_vals.dma_residue = offs;
114     #endif /* SM_DEBUG */
115     		if (sm->dma.i16bit)
116     			return offs/2;
117     		return offs;
118     	}
119     }
120     
121     /* --------------------------------------------------------------------- */
122     
123     extern __inline__ int dma_end_transmit(struct sm_state *sm, unsigned int curfrag)
124     {
125     	unsigned int diff = (NUM_FRAGMENTS + curfrag - sm->dma.ofragptr) % NUM_FRAGMENTS;
126     
127     	sm->dma.ofragptr = curfrag;
128     	if (sm->dma.ptt_cnt <= 0) {
129     		sm->dma.ptt_cnt = 0;
130     		return 0;
131     	}
132     	sm->dma.ptt_cnt -= diff;
133     	if (sm->dma.ptt_cnt <= 0) {
134     		sm->dma.ptt_cnt = 0;
135     		return -1;
136     	}
137     	return 0;
138     }
139     
140     extern __inline__ void dma_transmit(struct sm_state *sm)
141     {
142     	void *p;
143     
144     	while (sm->dma.ptt_cnt < NUM_FRAGMENTS && hdlcdrv_ptt(&sm->hdrv)) {
145     		p = (unsigned char *)sm->dma.obuf + sm->dma.ofragsz *
146     			((sm->dma.ofragptr + sm->dma.ptt_cnt) % NUM_FRAGMENTS);
147     		if (sm->dma.o16bit) {
148     			time_exec(sm->debug_vals.mod_cyc, 
149     				  sm->mode_tx->modulator_s16(sm, p, sm->dma.ofragsz/2));
150     		} else {
151     			time_exec(sm->debug_vals.mod_cyc, 
152     				  sm->mode_tx->modulator_u8(sm, p, sm->dma.ofragsz));
153     		}
154     		sm->dma.ptt_cnt++;
155     	}
156     }
157     
158     extern __inline__ void dma_init_transmit(struct sm_state *sm)
159     {
160     	sm->dma.ofragptr = 0;
161     	sm->dma.ptt_cnt = 0;
162     }
163     
164     extern __inline__ void dma_start_transmit(struct sm_state *sm)
165     {
166     	sm->dma.ofragptr = 0;
167     	if (sm->dma.o16bit) {
168     		time_exec(sm->debug_vals.mod_cyc, 
169     			  sm->mode_tx->modulator_s16(sm, sm->dma.obuf, sm->dma.ofragsz/2));
170     	} else {
171     		time_exec(sm->debug_vals.mod_cyc, 
172     			  sm->mode_tx->modulator_u8(sm, sm->dma.obuf, sm->dma.ofragsz));
173     	}
174     	sm->dma.ptt_cnt = 1;
175     }
176     
177     extern __inline__ void dma_clear_transmit(struct sm_state *sm)
178     {
179     	sm->dma.ptt_cnt = 0;
180     	memset(sm->dma.obuf, (sm->dma.o16bit) ? 0 : 0x80, sm->dma.ofragsz * NUM_FRAGMENTS);
181     }
182     
183     /* --------------------------------------------------------------------- */
184     
185     extern __inline__ void dma_receive(struct sm_state *sm, unsigned int curfrag)
186     {
187     	void *p;
188     
189     	while (sm->dma.ifragptr != curfrag) {
190     		if (sm->dma.ifragptr)
191     			p = (unsigned char *)sm->dma.ibuf + 
192     				sm->dma.ifragsz * sm->dma.ifragptr;
193     		else {
194     			p = (unsigned char *)sm->dma.ibuf + NUM_FRAGMENTS * sm->dma.ifragsz;
195     			memcpy(p, sm->dma.ibuf, sm->dma.ifragsz);
196     		}
197     		if (sm->dma.o16bit) {
198     			time_exec(sm->debug_vals.demod_cyc, 
199     				  sm->mode_rx->demodulator_s16(sm, p, sm->dma.ifragsz/2));
200     		} else {
201     			time_exec(sm->debug_vals.demod_cyc, 
202     				  sm->mode_rx->demodulator_u8(sm, p, sm->dma.ifragsz));
203     		}
204     		sm->dma.ifragptr = (sm->dma.ifragptr + 1) % NUM_FRAGMENTS;
205     	}
206     }
207     
208     extern __inline__ void dma_init_receive(struct sm_state *sm)
209     {
210     	sm->dma.ifragptr = 0;
211     }
212     
213     /* --------------------------------------------------------------------- */
214     #endif /* _SMDMA_H */
215     
216     
217     
218