Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
f9c418f6
Commit
f9c418f6
authored
Nov 25, 2002
by
Alan Cox
Committed by
Linus Torvalds
Nov 25, 2002
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[PATCH] kill soundmodem
It was dead before 2.4 (replaced by better userspace versions)
parent
a994c542
Changes
15
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
0 additions
and
6703 deletions
+0
-6703
drivers/net/hamradio/Kconfig
drivers/net/hamradio/Kconfig
+0
-114
drivers/net/hamradio/soundmodem/Makefile
drivers/net/hamradio/soundmodem/Makefile
+0
-42
drivers/net/hamradio/soundmodem/gentbl.c
drivers/net/hamradio/soundmodem/gentbl.c
+0
-689
drivers/net/hamradio/soundmodem/sm.c
drivers/net/hamradio/soundmodem/sm.c
+0
-759
drivers/net/hamradio/soundmodem/sm.h
drivers/net/hamradio/soundmodem/sm.h
+0
-383
drivers/net/hamradio/soundmodem/sm_afsk1200.c
drivers/net/hamradio/soundmodem/sm_afsk1200.c
+0
-272
drivers/net/hamradio/soundmodem/sm_afsk2400_7.c
drivers/net/hamradio/soundmodem/sm_afsk2400_7.c
+0
-296
drivers/net/hamradio/soundmodem/sm_afsk2400_8.c
drivers/net/hamradio/soundmodem/sm_afsk2400_8.c
+0
-296
drivers/net/hamradio/soundmodem/sm_afsk2666.c
drivers/net/hamradio/soundmodem/sm_afsk2666.c
+0
-356
drivers/net/hamradio/soundmodem/sm_fsk9600.c
drivers/net/hamradio/soundmodem/sm_fsk9600.c
+0
-391
drivers/net/hamradio/soundmodem/sm_hapn4800.c
drivers/net/hamradio/soundmodem/sm_hapn4800.c
+0
-560
drivers/net/hamradio/soundmodem/sm_psk4800.c
drivers/net/hamradio/soundmodem/sm_psk4800.c
+0
-418
drivers/net/hamradio/soundmodem/sm_sbc.c
drivers/net/hamradio/soundmodem/sm_sbc.c
+0
-942
drivers/net/hamradio/soundmodem/sm_wss.c
drivers/net/hamradio/soundmodem/sm_wss.c
+0
-968
drivers/net/hamradio/soundmodem/smdma.h
drivers/net/hamradio/soundmodem/smdma.h
+0
-217
No files found.
drivers/net/hamradio/Kconfig
View file @
f9c418f6
...
...
@@ -185,120 +185,6 @@ config BAYCOM_EPP
say M here and read <file:Documentation/modules.txt>. This is
recommended. The module will be called baycom_par.o.
config SOUNDMODEM
tristate "Soundcard modem driver"
depends on PARPORT && AX25
---help---
This experimental driver allows a standard Sound Blaster or
WindowsSoundSystem compatible sound card to be used as a packet
radio modem (NOT as a telephone modem!), to send digital traffic
over amateur radio.
To configure the driver, use the sethdlc, smdiag and smmixer
utilities available in the standard ax25 utilities package. For
information on how to key the transmitter, see
<http://www.ife.ee.ethz.ch/~sailer/pcf/ptt_circ/ptt.html> and
<file:Documentation/networking/soundmodem.txt>.
If you want to compile this driver as a module ( = code which can be
inserted in and removed from the running kernel whenever you want),
say M here and read <file:Documentation/modules.txt>. This is
recommended. The module will be called soundmodem.o.
config SOUNDMODEM_SBC
bool "soundmodem support for Soundblaster and compatible cards"
depends on SOUNDMODEM
help
This option enables the soundmodem driver to use Sound Blaster and
compatible cards. If you have a dual mode card (i.e. a WSS cards
with a Sound Blaster emulation) you should say N here and Y to
"Sound card modem support for WSS and Crystal cards", below, because
this usually results in better performance. This option also
supports SB16/32/64 in full-duplex mode.
config SOUNDMODEM_WSS
bool "soundmodem support for WSS and Crystal cards"
depends on SOUNDMODEM
help
This option enables the soundmodem driver to use WindowsSoundSystem
compatible cards. These cards feature a codec chip from either
Analog Devices (such as AD1848, AD1845, AD1812) or Crystal
Semiconductors (such as CS4248, CS423x). This option also supports
the WSS full-duplex operation which currently works with Crystal
CS423x chips. If you don't need full-duplex operation, do not enable
it to save performance.
config SOUNDMODEM_AFSK1200
bool "soundmodem support for 1200 baud AFSK modulation"
depends on SOUNDMODEM
help
This option enables the soundmodem driver 1200 baud AFSK modem,
compatible to popular modems using TCM3105 or AM7911. The
demodulator requires about 12% of the CPU power of a Pentium 75 CPU
per channel.
config SOUNDMODEM_AFSK2400_7
bool "soundmodem support for 2400 baud AFSK modulation (7.3728MHz crystal)"
depends on SOUNDMODEM
help
This option enables the soundmodem driver 2400 baud AFSK modem,
compatible to TCM3105 modems (over-)clocked with a 7.3728MHz
crystal. Note that the availability of this driver does _not_ imply
that I recommend building such links. It is only here since users
especially in eastern Europe have asked me to do so. In fact this
modulation scheme has many disadvantages, mainly its incompatibility
with many transceiver designs and the fact that the TCM3105 (if
used) is operated widely outside its specifications.
config SOUNDMODEM_AFSK2400_8
bool "soundmodem support for 2400 baud AFSK modulation (8MHz crystal)"
depends on SOUNDMODEM
help
This option enables the soundmodem driver 2400 baud AFSK modem,
compatible to TCM3105 modems (over-)clocked with an 8MHz crystal.
Note that the availability of this driver does _not_ imply that I
recommend building such links. It is only here since users
especially in eastern Europe have asked me to do so. In fact this
modulation scheme has many disadvantages, mainly its incompatibility
with many transceiver designs and the fact that the TCM3105 (if
used) is operated widely outside its specifications.
config SOUNDMODEM_AFSK2666
bool "soundmodem support for 2666 baud AFSK modulation"
depends on SOUNDMODEM
help
This option enables the soundmodem driver 2666 baud AFSK modem.
This modem is experimental, and not compatible to anything
else I know of.
config SOUNDMODEM_HAPN4800
bool "soundmodem support for 4800 baud HAPN-1 modulation"
depends on SOUNDMODEM
help
This option enables the soundmodem driver 4800 baud HAPN-1
compatible modem. This modulation seems to be widely used 'down
under' and in the Netherlands. Here, nobody uses it, so I could not
test if it works. It is compatible to itself, however :-)
config SOUNDMODEM_PSK4800
bool "soundmodem support for 4800 baud PSK modulation"
depends on SOUNDMODEM
help
This option enables the soundmodem driver 4800 baud 8PSK modem.
This modem is experimental, and not compatible to anything
else I know of.
config SOUNDMODEM_FSK9600
bool "soundmodem support for 9600 baud FSK G3RUH modulation"
depends on SOUNDMODEM
help
This option enables the soundmodem driver 9600 baud FSK modem,
compatible to the G3RUH standard. The demodulator requires about 4%
of the CPU power of a Pentium 75 CPU per channel. You can say Y to
both 1200 baud AFSK and 9600 baud FSK if you want (but obviously you
can only use one protocol at a time, depending on what the other end
can understand).
config YAM
tristate "YAM driver for AX.25"
depends on AX25
...
...
drivers/net/hamradio/soundmodem/Makefile
deleted
100644 → 0
View file @
a994c542
#
# Makefile for the soundmodem device driver.
#
obj-$(CONFIG_SOUNDMODEM)
+=
soundmodem.o
soundmodem-y
:=
sm.o
soundmodem-$(CONFIG_SOUNDMODEM_SBC)
+=
sm_sbc.o
soundmodem-$(CONFIG_SOUNDMODEM_WSS)
+=
sm_wss.o
soundmodem-$(CONFIG_SOUNDMODEM_AFSK1200)
+=
sm_afsk1200.o
soundmodem-$(CONFIG_SOUNDMODEM_AFSK2400_7)
+=
sm_afsk2400_7.o
soundmodem-$(CONFIG_SOUNDMODEM_AFSK2400_8)
+=
sm_afsk2400_8.o
soundmodem-$(CONFIG_SOUNDMODEM_AFSK2666)
+=
sm_afsk2666.o
soundmodem-$(CONFIG_SOUNDMODEM_HAPN4800)
+=
sm_hapn4800.o
soundmodem-$(CONFIG_SOUNDMODEM_PSK4800)
+=
sm_psk4800.o
soundmodem-$(CONFIG_SOUNDMODEM_FSK9600)
+=
sm_fsk9600.o
soundmodem-objs
:=
$
(
soundmodem-y
)
host-progs
:=
gentbl
HOST_LOADLIBES
:=
-lm
# Files generated that shall be removed upon make clean
clean-files
:=
sm_tbl_afsk1200.h sm_tbl_afsk2400_7.h
\
sm_tbl_afsk2400_8.h sm_tbl_afsk2666.h
\
sm_tbl_psk4800.h sm_tbl_hapn4800.h
\
sm_tbl_fsk9600.h
include
$(TOPDIR)/Rules.make
# Dependencies on generates files need to be listed explicitly
$(obj)/sm_afsk1200.o
:
$(obj)/sm_tbl_afsk1200.h
$(obj)/sm_afsk2400_7.o
:
$(obj)/sm_tbl_afsk2400_7.h
$(obj)/sm_afsk2400_8.o
:
$(obj)/sm_tbl_afsk2400_8.h
$(obj)/sm_afsk2666.o
:
$(obj)/sm_tbl_afsk2666.h
$(obj)/sm_psk4800.o
:
$(obj)/sm_tbl_psk4800.h
$(obj)/sm_hapn4800.o
:
$(obj)/sm_tbl_hapn4800.h
$(obj)/sm_fsk9600.o
:
$(obj)/sm_tbl_fsk9600.h
$(obj)/sm_tbl_%
:
$(obj)/gentbl
cd
$(obj)
&&
./gentbl
drivers/net/hamradio/soundmodem/gentbl.c
deleted
100644 → 0
View file @
a994c542
/*****************************************************************************/
/*
* gentbl.c -- soundcard radio modem driver table generator.
*
* 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.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
/* -------------------------------------------------------------------- */
static
void
gentbl_offscostab
(
FILE
*
f
,
unsigned
int
nbits
)
{
int
i
;
fprintf
(
f
,
"
\n
/*
\n
* small cosine table in U8 format
\n
*/
\n
"
"#define OFFSCOSTABBITS %u
\n
"
"#define OFFSCOSTABSIZE (1<<OFFSCOSTABBITS)
\n\n
"
,
nbits
);
fprintf
(
f
,
"static unsigned char offscostab[OFFSCOSTABSIZE] = {
\n\t
"
);
for
(
i
=
0
;
i
<
(
1
<<
nbits
);
i
++
)
{
fprintf
(
f
,
"%4u"
,
(
int
)
(
128
+
127
.
0
*
cos
(
i
*
2
.
0
*
M_PI
/
(
1
<<
nbits
))));
if
(
i
<
(
1
<<
nbits
)
-
1
)
fprintf
(
f
,
"%s"
,
(
i
&
7
)
==
7
?
",
\n\t
"
:
","
);
}
fprintf
(
f
,
"
\n
};
\n\n
"
"#define OFFSCOS(x) offscostab[((x)>>%d)&0x%x]
\n\n
"
,
16
-
nbits
,
(
1
<<
nbits
)
-
1
);
}
/* -------------------------------------------------------------------- */
static
void
gentbl_costab
(
FILE
*
f
,
unsigned
int
nbits
)
{
int
i
;
fprintf
(
f
,
"
\n
/*
\n
* more accurate cosine table
\n
*/
\n\n
"
"static const short costab[%d] = {"
,
(
1
<<
nbits
));
for
(
i
=
0
;
i
<
(
1
<<
nbits
);
i
++
)
{
if
(
!
(
i
&
7
))
fprintf
(
f
,
"
\n\t
"
);
fprintf
(
f
,
"%6d"
,
(
int
)(
32767
.
0
*
cos
(
i
*
2
.
0
*
M_PI
/
(
1
<<
nbits
))));
if
(
i
!=
((
1
<<
nbits
)
-
1
))
fprintf
(
f
,
", "
);
}
fprintf
(
f
,
"
\n
};
\n\n
#define COS(x) costab[((x)>>%d)&0x%x]
\n
"
"#define SIN(x) COS((x)+0xc000)
\n\n
"
,
16
-
nbits
,
(
1
<<
nbits
)
-
1
);
}
/* -------------------------------------------------------------------- */
#define AFSK12_SAMPLE_RATE 9600
#define AFSK12_TX_FREQ_LO 1200
#define AFSK12_TX_FREQ_HI 2200
#define AFSK12_CORRLEN 8
static
void
gentbl_afsk1200
(
FILE
*
f
)
{
int
i
,
v
,
sum
;
#define ARGLO(x) 2.0*M_PI*(double)x*(double)AFSK12_TX_FREQ_LO/(double)AFSK12_SAMPLE_RATE
#define ARGHI(x) 2.0*M_PI*(double)x*(double)AFSK12_TX_FREQ_HI/(double)AFSK12_SAMPLE_RATE
fprintf
(
f
,
"
\n
/*
\n
* afsk1200 specific tables
\n
*/
\n
"
"#define AFSK12_SAMPLE_RATE %u
\n
"
"#define AFSK12_TX_FREQ_LO %u
\n
"
"#define AFSK12_TX_FREQ_HI %u
\n
"
"#define AFSK12_CORRLEN %u
\n\n
"
,
AFSK12_SAMPLE_RATE
,
AFSK12_TX_FREQ_LO
,
AFSK12_TX_FREQ_HI
,
AFSK12_CORRLEN
);
fprintf
(
f
,
"static const int afsk12_tx_lo_i[] = {
\n\t
"
);
for
(
sum
=
i
=
0
;
i
<
AFSK12_CORRLEN
;
i
++
)
{
sum
+=
(
v
=
127
.
0
*
cos
(
ARGLO
(
i
)));
fprintf
(
f
,
" %4i%c"
,
v
,
(
i
<
AFSK12_CORRLEN
-
1
)
?
','
:
' '
);
}
fprintf
(
f
,
"
\n
};
\n
#define SUM_AFSK12_TX_LO_I %d
\n\n
"
"static const int afsk12_tx_lo_q[] = {
\n\t
"
,
sum
);
for
(
sum
=
i
=
0
;
i
<
AFSK12_CORRLEN
;
i
++
)
{
sum
+=
(
v
=
127
.
0
*
sin
(
ARGLO
(
i
)));
fprintf
(
f
,
" %4i%c"
,
v
,
(
i
<
AFSK12_CORRLEN
-
1
)
?
','
:
' '
);
}
fprintf
(
f
,
"
\n
};
\n
#define SUM_AFSK12_TX_LO_Q %d
\n\n
"
"static const int afsk12_tx_hi_i[] = {
\n\t
"
,
sum
);
for
(
sum
=
i
=
0
;
i
<
AFSK12_CORRLEN
;
i
++
)
{
sum
+=
(
v
=
127
.
0
*
cos
(
ARGHI
(
i
)));
fprintf
(
f
,
" %4i%c"
,
v
,
(
i
<
AFSK12_CORRLEN
-
1
)
?
','
:
' '
);
}
fprintf
(
f
,
"
\n
};
\n
#define SUM_AFSK12_TX_HI_I %d
\n\n
"
"static const int afsk12_tx_hi_q[] = {
\n\t
"
,
sum
);
for
(
sum
=
i
=
0
;
i
<
AFSK12_CORRLEN
;
i
++
)
{
sum
+=
(
v
=
127
.
0
*
sin
(
ARGHI
(
i
)));
fprintf
(
f
,
" %4i%c"
,
v
,
(
i
<
AFSK12_CORRLEN
-
1
)
?
','
:
' '
);
}
fprintf
(
f
,
"
\n
};
\n
#define SUM_AFSK12_TX_HI_Q %d
\n\n
"
,
sum
);
#undef ARGLO
#undef ARGHI
}
/* -------------------------------------------------------------------- */
static
const
float
fsk96_tx_coeff_4
[
32
]
=
{
-
0
.
001152
,
0
.
000554
,
0
.
0026
98
,
0
.
002753
,
-
0
.
002033
,
-
0
.
00
8861
,
-
0
.
00
8002
,
0
.
006607
,
0
.
023727
,
0
.
01
8905
,
-
0
.
01
8056
,
-
0
.
057
957
,
-
0
.
04436
8
,
0
.
0556
83
,
0
.
207667
,
0
.
322048
,
0
.
322048
,
0
.
207667
,
0
.
0556
83
,
-
0
.
04436
8
,
-
0
.
057
957
,
-
0
.
01
8056
,
0
.
01
8905
,
0
.
023727
,
0
.
006607
,
-
0
.
00
8002
,
-
0
.
00
8861
,
-
0
.
002033
,
0
.
002753
,
0
.
0026
98
,
0
.
000554
,
-
0
.
001152
};
static
const
float
fsk96_tx_coeff_5
[
40
]
=
{
-
0
.
00100
9
,
-
0
.
00004
8
,
0
.
001376
,
0
.
002547
,
0
.
002061
,
-
0
.
001103
,
-
0
.
0057
95
,
-
0
.
00
8170
,
-
0
.
004017
,
0
.
006
924
,
0
.
01
8225
,
0
.
01
9238
,
0
.
002
925
,
-
0
.
025777
,
-
0
.
04
8064
,
-
0
.
03
9683
,
0
.
013760
,
0
.
104144
,
0
.
200355
,
0
.
262346
,
0
.
262346
,
0
.
200355
,
0
.
104144
,
0
.
013760
,
-
0
.
03
9683
,
-
0
.
04
8064
,
-
0
.
025777
,
0
.
002
925
,
0
.
01
9238
,
0
.
01
8225
,
0
.
006
924
,
-
0
.
004017
,
-
0
.
00
8170
,
-
0
.
0057
95
,
-
0
.
001103
,
0
.
002061
,
0
.
002547
,
0
.
001376
,
-
0
.
00004
8
,
-
0
.
00100
9
};
#define HAMMING(x) (0.54-0.46*cos(2*M_PI*(x)));
static
inline
float
hamming
(
float
x
)
{
return
0
.
54
-
0
.
46
*
cos
(
2
*
M_PI
*
x
);
}
static
inline
float
sinc
(
float
x
)
{
if
(
x
==
0
)
return
1
;
x
*=
M_PI
;
return
sin
(
x
)
/
x
;
}
static
void
gentbl_fsk9600
(
FILE
*
f
)
{
int
i
,
j
,
k
,
l
,
m
;
float
s
;
float
c
[
44
];
float
min
,
max
;
fprintf
(
f
,
"
\n
/*
\n
* fsk9600 specific tables
\n
*/
\n
"
);
min
=
max
=
0
;
memset
(
c
,
0
,
sizeof
(
c
));
#if 0
memcpy(c+2, fsk96_tx_coeff_4, sizeof(fsk96_tx_coeff_4));
#else
for
(
i
=
0
;
i
<
29
;
i
++
)
c
[
3
+
i
]
=
sinc
(
1
.
2
*
((
i
-
14
.
0
)
/
4
.
0
))
*
hamming
(
i
/
28
.
0
)
/
3
.
5
;
#endif
fprintf
(
f
,
"static unsigned char fsk96_txfilt_4[] = {
\n\t
"
);
for
(
i
=
0
;
i
<
4
;
i
++
)
{
for
(
j
=
0
;
j
<
256
;
j
++
)
{
for
(
k
=
1
,
s
=
0
,
l
=
i
;
k
<
256
;
k
<<=
1
)
{
if
(
j
&
k
)
{
for
(
m
=
0
;
m
<
4
;
m
++
,
l
++
)
s
+=
c
[
l
];
}
else
{
for
(
m
=
0
;
m
<
4
;
m
++
,
l
++
)
s
-=
c
[
l
];
}
}
s
*=
0
.
75
;
if
(
s
>
max
)
max
=
s
;
if
(
s
<
min
)
min
=
s
;
fprintf
(
f
,
"%4d"
,
(
int
)(
128
+
127
*
s
));
if
(
i
<
3
||
j
<
255
)
fprintf
(
f
,
",%s"
,
(
j
&
7
)
==
7
?
"
\n\t
"
:
""
);
}
}
#ifdef VERBOSE
fprintf
(
stderr
,
"fsk9600: txfilt4: min = %f; max = %f
\n
"
,
min
,
max
);
#endif
fprintf
(
f
,
"
\n
};
\n\n
"
);
min
=
max
=
0
;
memset
(
c
,
0
,
sizeof
(
c
));
#if 0
memcpy(c+2, fsk96_tx_coeff_5, sizeof(fsk96_tx_coeff_5));
#else
for
(
i
=
0
;
i
<
36
;
i
++
)
c
[
4
+
i
]
=
sinc
(
1
.
2
*
((
i
-
17
.
5
)
/
5
.
0
))
*
hamming
(
i
/
35
.
0
)
/
4
.
5
;
#endif
fprintf
(
f
,
"static unsigned char fsk96_txfilt_5[] = {
\n\t
"
);
for
(
i
=
0
;
i
<
5
;
i
++
)
{
for
(
j
=
0
;
j
<
256
;
j
++
)
{
for
(
k
=
1
,
s
=
0
,
l
=
i
;
k
<
256
;
k
<<=
1
)
{
if
(
j
&
k
)
{
for
(
m
=
0
;
m
<
5
;
m
++
,
l
++
)
s
+=
c
[
l
];
}
else
{
for
(
m
=
0
;
m
<
5
;
m
++
,
l
++
)
s
-=
c
[
l
];
}
}
s
*=
0
.
75
;
if
(
s
>
max
)
max
=
s
;
if
(
s
<
min
)
min
=
s
;
fprintf
(
f
,
"%4d"
,
(
int
)(
128
+
127
*
s
));
if
(
i
<
4
||
j
<
255
)
fprintf
(
f
,
",%s"
,
(
j
&
7
)
==
7
?
"
\n\t
"
:
""
);
}
}
#ifdef VERBOSE
fprintf
(
stderr
,
"fsk9600: txfilt5: min = %f; max = %f
\n
"
,
min
,
max
);
#endif
fprintf
(
f
,
"
\n
};
\n\n
"
);
}
/* -------------------------------------------------------------------- */
#define AFSK26_SAMPLERATE 16000
#define AFSK26_NUMCAR 2
#define AFSK26_FIRSTCAR 2000
#define AFSK26_MSK_LEN 6
#define AFSK26_RXOVER 2
#define AFSK26_DEMCORRLEN (2*AFSK26_MSK_LEN)
#define AFSK26_WINDOW(x) ((1-cos(2.0*M_PI*(x)))/2.0)
#define AFSK26_AMPL(x) (((x)?1.0:0.7))
#undef AFSK26_AMPL
#define AFSK26_AMPL(x) 1
static
void
gentbl_afsk2666
(
FILE
*
f
)
{
int
i
,
j
,
k
,
l
,
o
,
v
,
sumi
,
sumq
;
float
window
[
AFSK26_DEMCORRLEN
*
AFSK26_RXOVER
];
int
cfreq
[
AFSK26_NUMCAR
];
fprintf
(
f
,
"
\n
/*
\n
* afsk2666 specific tables
\n
*/
\n
"
"#define AFSK26_DEMCORRLEN %d
\n
"
"#define AFSK26_SAMPLERATE %d
\n\n
"
,
AFSK26_DEMCORRLEN
,
AFSK26_SAMPLERATE
);
fprintf
(
f
,
"static const unsigned int afsk26_carfreq[%d] = { "
,
AFSK26_NUMCAR
);
for
(
i
=
0
;
i
<
AFSK26_NUMCAR
;
i
++
)
{
cfreq
[
i
]
=
0x10000
*
AFSK26_FIRSTCAR
/
AFSK26_SAMPLERATE
+
0x10000
*
i
/
AFSK26_MSK_LEN
/
2
;
fprintf
(
f
,
"0x%x"
,
cfreq
[
i
]);
if
(
i
<
AFSK26_NUMCAR
-
1
)
fprintf
(
f
,
", "
);
}
fprintf
(
f
,
" };
\n\n
"
);
for
(
i
=
0
;
i
<
AFSK26_DEMCORRLEN
*
AFSK26_RXOVER
;
i
++
)
window
[
i
]
=
AFSK26_WINDOW
(((
float
)
i
)
/
(
AFSK26_DEMCORRLEN
*
AFSK26_RXOVER
))
*
127
.
0
;
fprintf
(
f
,
"
\n
static const struct {
\n\t
"
"int i[%d];
\n\t
int q[%d];
\n
} afsk26_dem_tables[%d][%d] = {
\n
"
,
AFSK26_DEMCORRLEN
,
AFSK26_DEMCORRLEN
,
AFSK26_RXOVER
,
AFSK26_NUMCAR
);
for
(
o
=
AFSK26_RXOVER
-
1
;
o
>=
0
;
o
--
)
{
fprintf
(
f
,
"
\t
{
\n
"
);
for
(
i
=
0
;
i
<
AFSK26_NUMCAR
;
i
++
)
{
j
=
cfreq
[
i
];
fprintf
(
f
,
"
\t\t
{{ "
);
for
(
l
=
AFSK26_DEMCORRLEN
-
1
,
k
=
(
j
*
o
)
/
AFSK26_RXOVER
,
sumi
=
0
;
l
>=
0
;
l
--
,
k
=
(
k
+
j
)
&
0xffffu
)
{
sumi
+=
(
v
=
AFSK26_AMPL
(
i
)
*
window
[
l
*
AFSK26_RXOVER
+
o
]
*
cos
(
M_PI
*
k
/
32768
.
0
));
fprintf
(
f
,
"%6d%s"
,
v
,
l
?
", "
:
" }, { "
);
}
for
(
l
=
AFSK26_DEMCORRLEN
-
1
,
k
=
(
j
*
o
)
/
AFSK26_RXOVER
,
sumq
=
0
;
l
>=
0
;
l
--
,
k
=
(
k
+
j
)
&
0xffffu
)
{
sumq
+=
(
v
=
AFSK26_AMPL
(
i
)
*
window
[
l
*
AFSK26_RXOVER
+
o
]
*
sin
(
M_PI
*
k
/
32768
.
0
));
fprintf
(
f
,
"%6d%s"
,
v
,
l
?
", "
:
" }}"
);
}
if
(
i
<
1
)
fprintf
(
f
,
","
);
fprintf
(
f
,
"
\n
#define AFSK26_DEM_SUM_I_%d_%d %d
\n
"
"#define AFSK26_DEM_SUM_Q_%d_%d %d
\n
"
,
AFSK26_RXOVER
-
1
-
o
,
i
,
sumi
,
AFSK26_RXOVER
-
1
-
o
,
i
,
sumq
);
}
fprintf
(
f
,
"
\t
}%s
\n
"
,
o
?
","
:
""
);
}
fprintf
(
f
,
"};
\n\n
"
);
}
/* -------------------------------------------------------------------- */
#define ATAN_TABLEN 1024
static
void
gentbl_atantab
(
FILE
*
f
)
{
int
i
;
short
x
;
fprintf
(
f
,
"
\n
/*
\n
"
" * arctan table (indexed by i/q; should really be indexed by i/(i+q)
\n
"
" */
\n
""#define ATAN_TABLEN %d
\n\n
"
"static const unsigned short atan_tab[ATAN_TABLEN+2] = {"
,
ATAN_TABLEN
);
for
(
i
=
0
;
i
<=
ATAN_TABLEN
;
i
++
)
{
if
(
!
(
i
&
7
))
fprintf
(
f
,
"
\n\t
"
);
x
=
atan
(
i
/
(
float
)
ATAN_TABLEN
)
/
M_PI
*
0x8000
;
fprintf
(
f
,
"%6d, "
,
x
);
}
fprintf
(
f
,
"%6d
\n
};
\n\n
"
,
x
);
}
/* -------------------------------------------------------------------- */
#define PSK48_TXF_OVERSAMPLING 5
#define PSK48_TXF_NUMSAMPLES 16
#define PSK48_RXF_LEN 64
static
const
float
psk48_tx_coeff
[
80
]
=
{
-
0
.
00037
9
,
-
0
.
000640
,
-
0
.
000000
,
0
.
000772
,
0
.
000543
,
-
0
.
00062
9
,
-
0
.
0011
87
,
-
0
.
000000
,
0
.
001634
,
0
.
0011
83
,
-
0
.
0013
82
,
-
0
.
002603
,
-
0
.
000000
,
0
.
0034
81
,
0
.
002472
,
-
0
.
002
828
,
-
0
.
005215
,
-
0
.
000000
,
0
.
006705
,
0
.
00467
8
,
-
0
.
00526
9
,
-
0
.
00
9584
,
-
0
.
000000
,
0
.
012065
,
0
.
00
8360
,
-
0
.
00
9375
,
-
0
.
01702
8
,
-
0
.
000000
,
0
.
021603
,
0
.
015123
,
-
0
.
01722
9
,
-
0
.
032012
,
-
0
.
000000
,
0
.
043774
,
0
.
032544
,
-
0
.
040365
,
-
0
.
084963
,
-
0
.
000000
,
0
.
201161
,
0
.
374060
,
0
.
374060
,
0
.
201161
,
-
0
.
000000
,
-
0
.
084963
,
-
0
.
040365
,
0
.
032544
,
0
.
043774
,
-
0
.
000000
,
-
0
.
032012
,
-
0
.
01722
9
,
0
.
015123
,
0
.
021603
,
-
0
.
000000
,
-
0
.
01702
8
,
-
0
.
00
9375
,
0
.
00
8360
,
0
.
012065
,
-
0
.
000000
,
-
0
.
00
9584
,
-
0
.
00526
9
,
0
.
00467
8
,
0
.
006705
,
-
0
.
000000
,
-
0
.
005215
,
-
0
.
002
828
,
0
.
002472
,
0
.
0034
81
,
-
0
.
000000
,
-
0
.
002603
,
-
0
.
0013
82
,
0
.
0011
83
,
0
.
001634
,
-
0
.
000000
,
-
0
.
0011
87
,
-
0
.
00062
9
,
0
.
000543
,
0
.
000772
,
-
0
.
000000
,
-
0
.
000640
,
-
0
.
00037
9
};
static
const
float
psk48_rx_coeff
[
PSK48_RXF_LEN
]
=
{
-
0
.
00021
9
,
0
.
000360
,
0
.
000
873
,
0
.
0010
80
,
0
.
000747
,
-
0
.
0001
92
,
-
0
.
001466
,
-
0
.
002436
,
-
0
.
00232
8
,
-
0
.
0006
99
,
0
.
002101
,
0
.
004
809
,
0
.
0056
96
,
0
.
0034
92
,
-
0
.
001633
,
-
0
.
007660
,
-
0
.
011316
,
-
0
.
00
9627
,
-
0
.
0017
80
,
0
.
00
9712
,
0
.
01
9426
,
0
.
0211
99
,
0
.
011342
,
-
0
.
00
8583
,
-
0
.
030
955
,
-
0
.
0440
93
,
-
0
.
036634
,
-
0
.
002651
,
0
.
054742
,
0
.
123101
,
0
.
184198
,
0
.
220219
,
0
.
220219
,
0
.
184198
,
0
.
123101
,
0
.
054742
,
-
0
.
002651
,
-
0
.
036634
,
-
0
.
0440
93
,
-
0
.
030
955
,
-
0
.
00
8583
,
0
.
011342
,
0
.
0211
99
,
0
.
01
9426
,
0
.
00
9712
,
-
0
.
0017
80
,
-
0
.
00
9627
,
-
0
.
011316
,
-
0
.
007660
,
-
0
.
001633
,
0
.
0034
92
,
0
.
0056
96
,
0
.
004
809
,
0
.
002101
,
-
0
.
0006
99
,
-
0
.
00232
8
,
-
0
.
002436
,
-
0
.
001466
,
-
0
.
0001
92
,
0
.
000747
,
0
.
0010
80
,
0
.
000
873
,
0
.
000360
,
-
0
.
00021
9
};
static
void
gentbl_psk4800
(
FILE
*
f
)
{
int
i
,
j
,
k
;
short
x
;
fprintf
(
f
,
"
\n
/*
\n
* psk4800 specific tables
\n
*/
\n
"
"#define PSK48_TXF_OVERSAMPLING %d
\n
"
"#define PSK48_TXF_NUMSAMPLES %d
\n\n
"
"#define PSK48_SAMPLERATE 8000
\n
"
"#define PSK48_CAR_FREQ 2000
\n
"
"#define PSK48_PSK_LEN 5
\n
"
"#define PSK48_RXF_LEN %u
\n
"
"#define PSK48_PHASEINC (0x10000*PSK48_CAR_FREQ/PSK48_SAMPLERATE)
\n
"
"#define PSK48_SPHASEINC (0x10000/(2*PSK48_PSK_LEN))
\n\n
"
"static const short psk48_tx_table[PSK48_TXF_OVERSAMPLING*"
"PSK48_TXF_NUMSAMPLES*8*2] = {"
,
PSK48_TXF_OVERSAMPLING
,
PSK48_TXF_NUMSAMPLES
,
PSK48_RXF_LEN
);
for
(
i
=
0
;
i
<
PSK48_TXF_OVERSAMPLING
;
i
++
)
{
for
(
j
=
0
;
j
<
PSK48_TXF_NUMSAMPLES
;
j
++
)
{
fprintf
(
f
,
"
\n\t
"
);
for
(
k
=
0
;
k
<
8
;
k
++
)
{
x
=
32767
.
0
*
cos
(
k
*
M_PI
/
4
.
0
)
*
psk48_tx_coeff
[
j
*
PSK48_TXF_OVERSAMPLING
+
i
];
fprintf
(
f
,
"%6d, "
,
x
);
}
fprintf
(
f
,
"
\n\t
"
);
for
(
k
=
0
;
k
<
8
;
k
++
)
{
x
=
32767
.
0
*
sin
(
k
*
M_PI
/
4
.
0
)
*
psk48_tx_coeff
[
j
*
PSK48_TXF_OVERSAMPLING
+
i
];
fprintf
(
f
,
"%6d"
,
x
);
if
(
k
!=
7
||
j
!=
PSK48_TXF_NUMSAMPLES
-
1
||
i
!=
PSK48_TXF_OVERSAMPLING
-
1
)
fprintf
(
f
,
", "
);
}
}
}
fprintf
(
f
,
"
\n
};
\n\n
"
);
fprintf
(
f
,
"static const short psk48_rx_coeff[PSK48_RXF_LEN] = {
\n\t
"
);
for
(
i
=
0
;
i
<
PSK48_RXF_LEN
;
i
++
)
{
fprintf
(
f
,
"%6d"
,
(
int
)(
psk48_rx_coeff
[
i
]
*
32767
.
0
));
if
(
i
<
PSK48_RXF_LEN
-
1
)
fprintf
(
f
,
",%s"
,
(
i
&
7
)
==
7
?
"
\n\t
"
:
""
);
}
fprintf
(
f
,
"
\n
};
\n\n
"
);
}
/* -------------------------------------------------------------------- */
static
void
gentbl_hapn4800
(
FILE
*
f
)
{
int
i
,
j
,
k
,
l
;
float
s
;
float
c
[
44
];
float
min
,
max
;
fprintf
(
f
,
"
\n
/*
\n
* hapn4800 specific tables
\n
*/
\n\n
"
);
/*
* firstly generate tables for the FM transmitter modulator
*/
min
=
max
=
0
;
memset
(
c
,
0
,
sizeof
(
c
));
for
(
i
=
0
;
i
<
24
;
i
++
)
c
[
8
+
i
]
=
sinc
(
1
.
5
*
((
i
-
11
.
5
)
/
8
.
0
))
*
hamming
(
i
/
23
.
0
)
/
2
.
4
;
for
(
i
=
0
;
i
<
24
;
i
++
)
c
[
i
]
-=
c
[
i
+
8
];
fprintf
(
f
,
"static unsigned char hapn48_txfilt_8[] = {
\n\t
"
);
for
(
i
=
0
;
i
<
8
;
i
++
)
{
for
(
j
=
0
;
j
<
16
;
j
++
)
{
for
(
k
=
1
,
s
=
0
,
l
=
i
;
k
<
16
;
k
<<=
1
,
l
+=
8
)
{
if
(
j
&
k
)
s
+=
c
[
l
];
else
s
-=
c
[
l
];
}
if
(
s
>
max
)
max
=
s
;
if
(
s
<
min
)
min
=
s
;
fprintf
(
f
,
"%4d"
,
(
int
)(
128
+
127
*
s
));
if
(
i
<
7
||
j
<
15
)
fprintf
(
f
,
",%s"
,
(
j
&
7
)
==
7
?
"
\n\t
"
:
""
);
}
}
#ifdef VERBOSE
fprintf
(
stderr
,
"hapn4800: txfilt8: min = %f; max = %f
\n
"
,
min
,
max
);
#endif
fprintf
(
f
,
"
\n
};
\n\n
"
);
min
=
max
=
0
;
memset
(
c
,
0
,
sizeof
(
c
));
for
(
i
=
0
;
i
<
30
;
i
++
)
c
[
10
+
i
]
=
sinc
(
1
.
5
*
((
i
-
14
.
5
)
/
10
.
0
))
*
hamming
(
i
/
29
.
0
)
/
2
.
4
;
for
(
i
=
0
;
i
<
30
;
i
++
)
c
[
i
]
-=
c
[
i
+
10
];
fprintf
(
f
,
"static unsigned char hapn48_txfilt_10[] = {
\n\t
"
);
for
(
i
=
0
;
i
<
10
;
i
++
)
{
for
(
j
=
0
;
j
<
16
;
j
++
)
{
for
(
k
=
1
,
s
=
0
,
l
=
i
;
k
<
16
;
k
<<=
1
,
l
+=
10
)
{
if
(
j
&
k
)
s
+=
c
[
l
];
else
s
-=
c
[
l
];
}
if
(
s
>
max
)
max
=
s
;
if
(
s
<
min
)
min
=
s
;
fprintf
(
f
,
"%4d"
,
(
int
)(
128
+
127
*
s
));
if
(
i
<
9
||
j
<
15
)
fprintf
(
f
,
",%s"
,
(
j
&
7
)
==
7
?
"
\n\t
"
:
""
);
}
}
#ifdef VERBOSE
fprintf
(
stderr
,
"hapn4800: txfilt10: min = %f; max = %f
\n
"
,
min
,
max
);
#endif
fprintf
(
f
,
"
\n
};
\n\n
"
);
/*
* secondly generate tables for the PM transmitter modulator
*/
min
=
max
=
0
;
memset
(
c
,
0
,
sizeof
(
c
));
for
(
i
=
0
;
i
<
25
;
i
++
)
c
[
i
]
=
sinc
(
1
.
4
*
((
i
-
12
.
0
)
/
8
.
0
))
*
hamming
(
i
/
24
.
0
)
/
6
.
3
;
for
(
i
=
0
;
i
<
25
;
i
++
)
for
(
j
=
1
;
j
<
8
;
j
++
)
c
[
i
]
+=
c
[
i
+
j
];
fprintf
(
f
,
"static unsigned char hapn48_txfilt_pm8[] = {
\n\t
"
);
for
(
i
=
0
;
i
<
8
;
i
++
)
{
for
(
j
=
0
;
j
<
16
;
j
++
)
{
for
(
k
=
1
,
s
=
0
,
l
=
i
;
k
<
16
;
k
<<=
1
,
l
+=
8
)
{
if
(
j
&
k
)
s
+=
c
[
l
];
else
s
-=
c
[
l
];
}
if
(
s
>
max
)
max
=
s
;
if
(
s
<
min
)
min
=
s
;
fprintf
(
f
,
"%4d"
,
(
int
)(
128
+
127
*
s
));
if
(
i
<
7
||
j
<
15
)
fprintf
(
f
,
",%s"
,
(
j
&
7
)
==
7
?
"
\n\t
"
:
""
);
}
}
#ifdef VERBOSE
fprintf
(
stderr
,
"hapn4800: txfiltpm8: min = %f; max = %f
\n
"
,
min
,
max
);
#endif
fprintf
(
f
,
"
\n
};
\n\n
"
);
min
=
max
=
0
;
memset
(
c
,
0
,
sizeof
(
c
));
for
(
i
=
0
;
i
<
31
;
i
++
)
c
[
10
+
i
]
=
sinc
(
1
.
4
*
((
i
-
15
.
0
)
/
10
.
0
))
*
hamming
(
i
/
30
.
0
)
/
7
.
9
;
for
(
i
=
0
;
i
<
31
;
i
++
)
for
(
j
=
1
;
j
<
10
;
j
++
)
c
[
i
]
+=
c
[
i
+
j
];
fprintf
(
f
,
"static unsigned char hapn48_txfilt_pm10[] = {
\n\t
"
);
for
(
i
=
0
;
i
<
10
;
i
++
)
{
for
(
j
=
0
;
j
<
16
;
j
++
)
{
for
(
k
=
1
,
s
=
0
,
l
=
i
;
k
<
16
;
k
<<=
1
,
l
+=
10
)
{
if
(
j
&
k
)
s
+=
c
[
l
];
else
s
-=
c
[
l
];
}
if
(
s
>
max
)
max
=
s
;
if
(
s
<
min
)
min
=
s
;
fprintf
(
f
,
"%4d"
,
(
int
)(
128
+
127
*
s
));
if
(
i
<
9
||
j
<
15
)
fprintf
(
f
,
",%s"
,
(
j
&
7
)
==
7
?
"
\n\t
"
:
""
);
}
}
#ifdef VERBOSE
fprintf
(
stderr
,
"hapn4800: txfiltpm10: min = %f; max = %f
\n
"
,
min
,
max
);
#endif
fprintf
(
f
,
"
\n
};
\n\n
"
);
}
/* -------------------------------------------------------------------- */
#define AFSK24_SAMPLERATE 16000
#define AFSK24_CORRLEN 14
static
void
gentbl_afsk2400
(
FILE
*
f
,
float
tcm3105clk
)
{
int
i
,
sum
,
v
;
fprintf
(
f
,
"
\n
/*
\n
* afsk2400 specific tables (tcm3105 clk %7fHz)
\n
*/
\n
"
"#define AFSK24_TX_FREQ_LO %d
\n
"
"#define AFSK24_TX_FREQ_HI %d
\n
"
"#define AFSK24_BITPLL_INC %d
\n
"
"#define AFSK24_SAMPLERATE %d
\n\n
"
,
tcm3105clk
,
(
int
)(
tcm3105clk
/
3694
.
0
),
(
int
)(
tcm3105clk
/
2015
.
0
),
0x10000
*
2400
/
AFSK24_SAMPLERATE
,
AFSK24_SAMPLERATE
);
#define ARGLO(x) 2.0*M_PI*(double)x*(tcm3105clk/3694.0)/(double)AFSK24_SAMPLERATE
#define ARGHI(x) 2.0*M_PI*(double)x*(tcm3105clk/2015.0)/(double)AFSK24_SAMPLERATE
#define WINDOW(x) hamming((float)(x)/(AFSK24_CORRLEN-1.0))
fprintf
(
f
,
"static const int afsk24_tx_lo_i[] = {
\n\t
"
);
for
(
sum
=
i
=
0
;
i
<
AFSK24_CORRLEN
;
i
++
)
{
sum
+=
(
v
=
127
.
0
*
cos
(
ARGLO
(
i
))
*
WINDOW
(
i
));
fprintf
(
f
,
" %4i%c"
,
v
,
(
i
<
AFSK24_CORRLEN
-
1
)
?
','
:
' '
);
}
fprintf
(
f
,
"
\n
};
\n
#define SUM_AFSK24_TX_LO_I %d
\n\n
"
"static const int afsk24_tx_lo_q[] = {
\n\t
"
,
sum
);
for
(
sum
=
i
=
0
;
i
<
AFSK24_CORRLEN
;
i
++
)
{
sum
+=
(
v
=
127
.
0
*
sin
(
ARGLO
(
i
))
*
WINDOW
(
i
));
fprintf
(
f
,
" %4i%c"
,
v
,
(
i
<
AFSK24_CORRLEN
-
1
)
?
','
:
' '
);
}
fprintf
(
f
,
"
\n
};
\n
#define SUM_AFSK24_TX_LO_Q %d
\n\n
"
"static const int afsk24_tx_hi_i[] = {
\n\t
"
,
sum
);
for
(
sum
=
i
=
0
;
i
<
AFSK24_CORRLEN
;
i
++
)
{
sum
+=
(
v
=
127
.
0
*
cos
(
ARGHI
(
i
))
*
WINDOW
(
i
));
fprintf
(
f
,
" %4i%c"
,
v
,
(
i
<
AFSK24_CORRLEN
-
1
)
?
','
:
' '
);
}
fprintf
(
f
,
"
\n
};
\n
#define SUM_AFSK24_TX_HI_I %d
\n\n
"
"static const int afsk24_tx_hi_q[] = {
\n\t
"
,
sum
);
for
(
sum
=
i
=
0
;
i
<
AFSK24_CORRLEN
;
i
++
)
{
sum
+=
(
v
=
127
.
0
*
sin
(
ARGHI
(
i
))
*
WINDOW
(
i
));
fprintf
(
f
,
" %4i%c"
,
v
,
(
i
<
AFSK24_CORRLEN
-
1
)
?
','
:
' '
);
}
fprintf
(
f
,
"
\n
};
\n
#define SUM_AFSK24_TX_HI_Q %d
\n\n
"
,
sum
);
#undef ARGLO
#undef ARGHI
#undef WINDOW
}
/* -------------------------------------------------------------------- */
static
char
*
progname
;
static
void
gentbl_banner
(
FILE
*
f
)
{
fprintf
(
f
,
"/*
\n
* THIS FILE IS GENERATED AUTOMATICALLY BY %s, "
"DO NOT EDIT!
\n
*/
\n\n
"
,
progname
);
}
/* -------------------------------------------------------------------- */
int
main
(
int
argc
,
char
*
argv
[])
{
FILE
*
f
;
progname
=
argv
[
0
];
if
(
!
(
f
=
fopen
(
"sm_tbl_afsk1200.h"
,
"w"
)))
exit
(
1
);
gentbl_banner
(
f
);
gentbl_offscostab
(
f
,
6
);
gentbl_costab
(
f
,
6
);
gentbl_afsk1200
(
f
);
fclose
(
f
);
if
(
!
(
f
=
fopen
(
"sm_tbl_afsk2666.h"
,
"w"
)))
exit
(
1
);
gentbl_banner
(
f
);
gentbl_offscostab
(
f
,
6
);
gentbl_costab
(
f
,
6
);
gentbl_afsk2666
(
f
);
fclose
(
f
);
if
(
!
(
f
=
fopen
(
"sm_tbl_psk4800.h"
,
"w"
)))
exit
(
1
);
gentbl_banner
(
f
);
gentbl_psk4800
(
f
);
gentbl_costab
(
f
,
8
);
gentbl_atantab
(
f
);
fclose
(
f
);
if
(
!
(
f
=
fopen
(
"sm_tbl_hapn4800.h"
,
"w"
)))
exit
(
1
);
gentbl_banner
(
f
);
gentbl_hapn4800
(
f
);
fclose
(
f
);
if
(
!
(
f
=
fopen
(
"sm_tbl_fsk9600.h"
,
"w"
)))
exit
(
1
);
gentbl_banner
(
f
);
gentbl_fsk9600
(
f
);
fclose
(
f
);
if
(
!
(
f
=
fopen
(
"sm_tbl_afsk2400_8.h"
,
"w"
)))
exit
(
1
);
gentbl_banner
(
f
);
gentbl_offscostab
(
f
,
6
);
gentbl_costab
(
f
,
6
);
gentbl_afsk2400
(
f
,
8000000
);
fclose
(
f
);
if
(
!
(
f
=
fopen
(
"sm_tbl_afsk2400_7.h"
,
"w"
)))
exit
(
1
);
gentbl_banner
(
f
);
gentbl_offscostab
(
f
,
6
);
gentbl_costab
(
f
,
6
);
gentbl_afsk2400
(
f
,
7372800
);
fclose
(
f
);
exit
(
0
);
}
/* -------------------------------------------------------------------- */
drivers/net/hamradio/soundmodem/sm.c
deleted
100644 → 0
View file @
a994c542
/*****************************************************************************/
/*
* sm.c -- soundcard radio modem driver.
*
* Copyright (C) 1996-2000 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.
*
*
* Command line options (insmod command line)
*
* mode mode string; eg. "wss:afsk1200"
* iobase base address of the soundcard; common values are 0x220 for sbc,
* 0x530 for wss
* irq interrupt number; common values are 7 or 5 for sbc, 11 for wss
* dma dma number; common values are 0 or 1
*
*
* History:
* 0.1 21.09.1996 Started
* 18.10.1996 Changed to new user space access routines (copy_{to,from}_user)
* 0.4 21.01.1997 Separately compileable soundcard/modem modules
* 0.5 03.03.1997 fixed LPT probing (check_lpt result was interpreted the wrong way round)
* 0.6 16.04.1997 init code/data tagged
* 0.7 30.07.1997 fixed halfduplex interrupt handlers/hotfix for CS423X
* 0.8 14.04.1998 cleanups
* 0.9 03.08.1999 adapt to Linus' new __setup/__initcall
* use parport lowlevel drivers instead of directly writing to a parallel port
* removed some pre-2.2 kernel compatibility cruft
* 0.10 10.08.1999 Check if parport can do SPP and is safe to access during interrupt contexts
* 0.11 12.02.2000 adapted to softnet driver interface
* 0.12 03.07.2000 fix interface name handling
*/
/*****************************************************************************/
#include <linux/config.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/parport.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include "sm.h"
/* --------------------------------------------------------------------- */
/*static*/
const
char
sm_drvname
[]
=
"soundmodem"
;
static
const
char
sm_drvinfo
[]
=
KERN_INFO
"soundmodem: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA
\n
"
KERN_INFO
"soundmodem: version 0.12 compiled "
__TIME__
" "
__DATE__
"
\n
"
;
/* --------------------------------------------------------------------- */
/*static*/
const
struct
modem_tx_info
*
sm_modem_tx_table
[]
=
{
#ifdef CONFIG_SOUNDMODEM_AFSK1200
&
sm_afsk1200_tx
,
#endif
/* CONFIG_SOUNDMODEM_AFSK1200 */
#ifdef CONFIG_SOUNDMODEM_AFSK2400_7
&
sm_afsk2400_7_tx
,
#endif
/* CONFIG_SOUNDMODEM_AFSK2400_7 */
#ifdef CONFIG_SOUNDMODEM_AFSK2400_8
&
sm_afsk2400_8_tx
,
#endif
/* CONFIG_SOUNDMODEM_AFSK2400_8 */
#ifdef CONFIG_SOUNDMODEM_AFSK2666
&
sm_afsk2666_tx
,
#endif
/* CONFIG_SOUNDMODEM_AFSK2666 */
#ifdef CONFIG_SOUNDMODEM_PSK4800
&
sm_psk4800_tx
,
#endif
/* CONFIG_SOUNDMODEM_PSK4800 */
#ifdef CONFIG_SOUNDMODEM_HAPN4800
&
sm_hapn4800_8_tx
,
&
sm_hapn4800_10_tx
,
&
sm_hapn4800_pm8_tx
,
&
sm_hapn4800_pm10_tx
,
#endif
/* CONFIG_SOUNDMODEM_HAPN4800 */
#ifdef CONFIG_SOUNDMODEM_FSK9600
&
sm_fsk9600_4_tx
,
&
sm_fsk9600_5_tx
,
#endif
/* CONFIG_SOUNDMODEM_FSK9600 */
NULL
};
/*static*/
const
struct
modem_rx_info
*
sm_modem_rx_table
[]
=
{
#ifdef CONFIG_SOUNDMODEM_AFSK1200
&
sm_afsk1200_rx
,
#endif
/* CONFIG_SOUNDMODEM_AFSK1200 */
#ifdef CONFIG_SOUNDMODEM_AFSK2400_7
&
sm_afsk2400_7_rx
,
#endif
/* CONFIG_SOUNDMODEM_AFSK2400_7 */
#ifdef CONFIG_SOUNDMODEM_AFSK2400_8
&
sm_afsk2400_8_rx
,
#endif
/* CONFIG_SOUNDMODEM_AFSK2400_8 */
#ifdef CONFIG_SOUNDMODEM_AFSK2666
&
sm_afsk2666_rx
,
#endif
/* CONFIG_SOUNDMODEM_AFSK2666 */
#ifdef CONFIG_SOUNDMODEM_PSK4800
&
sm_psk4800_rx
,
#endif
/* CONFIG_SOUNDMODEM_PSK4800 */
#ifdef CONFIG_SOUNDMODEM_HAPN4800
&
sm_hapn4800_8_rx
,
&
sm_hapn4800_10_rx
,
&
sm_hapn4800_pm8_rx
,
&
sm_hapn4800_pm10_rx
,
#endif
/* CONFIG_SOUNDMODEM_HAPN4800 */
#ifdef CONFIG_SOUNDMODEM_FSK9600
&
sm_fsk9600_4_rx
,
&
sm_fsk9600_5_rx
,
#endif
/* CONFIG_SOUNDMODEM_FSK9600 */
NULL
};
static
const
struct
hardware_info
*
sm_hardware_table
[]
=
{
#ifdef CONFIG_SOUNDMODEM_SBC
&
sm_hw_sbc
,
&
sm_hw_sbcfdx
,
#endif
/* CONFIG_SOUNDMODEM_SBC */
#ifdef CONFIG_SOUNDMODEM_WSS
&
sm_hw_wss
,
&
sm_hw_wssfdx
,
#endif
/* CONFIG_SOUNDMODEM_WSS */
NULL
};
/* --------------------------------------------------------------------- */
#define NR_PORTS 4
static
struct
net_device
sm_device
[
NR_PORTS
];
/* --------------------------------------------------------------------- */
#define UART_RBR(iobase) (iobase+0)
#define UART_THR(iobase) (iobase+0)
#define UART_IER(iobase) (iobase+1)
#define UART_IIR(iobase) (iobase+2)
#define UART_FCR(iobase) (iobase+2)
#define UART_LCR(iobase) (iobase+3)
#define UART_MCR(iobase) (iobase+4)
#define UART_LSR(iobase) (iobase+5)
#define UART_MSR(iobase) (iobase+6)
#define UART_SCR(iobase) (iobase+7)
#define UART_DLL(iobase) (iobase+0)
#define UART_DLM(iobase) (iobase+1)
#define SER_EXTENT 8
#define MIDI_DATA(iobase) (iobase)
#define MIDI_STATUS(iobase) (iobase+1)
#define MIDI_READ_FULL 0x80
/* attention: negative logic!! */
#define MIDI_WRITE_EMPTY 0x40
/* attention: negative logic!! */
#define MIDI_EXTENT 2
/* ---------------------------------------------------------------------- */
#define PARAM_TXDELAY 1
#define PARAM_PERSIST 2
#define PARAM_SLOTTIME 3
#define PARAM_TXTAIL 4
#define PARAM_FULLDUP 5
#define PARAM_HARDWARE 6
#define PARAM_RETURN 255
#define SP_SER 1
#define SP_PAR 2
#define SP_MIDI 4
/*
* ===================== port checking routines ========================
*/
enum
uart
{
c_uart_unknown
,
c_uart_8250
,
c_uart_16450
,
c_uart_16550
,
c_uart_16550A
};
static
const
char
*
uart_str
[]
=
{
"unknown"
,
"8250"
,
"16450"
,
"16550"
,
"16550A"
};
static
enum
uart
check_uart
(
unsigned
int
iobase
)
{
unsigned
char
b1
,
b2
,
b3
;
enum
uart
u
;
enum
uart
uart_tab
[]
=
{
c_uart_16450
,
c_uart_unknown
,
c_uart_16550
,
c_uart_16550A
};
if
(
iobase
<=
0
||
iobase
>
0x1000
-
SER_EXTENT
)
return
c_uart_unknown
;
if
(
check_region
(
iobase
,
SER_EXTENT
))
return
c_uart_unknown
;
b1
=
inb
(
UART_MCR
(
iobase
));
outb
(
b1
|
0x10
,
UART_MCR
(
iobase
));
/* loopback mode */
b2
=
inb
(
UART_MSR
(
iobase
));
outb
(
0x1a
,
UART_MCR
(
iobase
));
b3
=
inb
(
UART_MSR
(
iobase
))
&
0xf0
;
outb
(
b1
,
UART_MCR
(
iobase
));
/* restore old values */
outb
(
b2
,
UART_MSR
(
iobase
));
if
(
b3
!=
0x90
)
return
c_uart_unknown
;
inb
(
UART_RBR
(
iobase
));
inb
(
UART_RBR
(
iobase
));
outb
(
0x01
,
UART_FCR
(
iobase
));
/* enable FIFOs */
u
=
uart_tab
[(
inb
(
UART_IIR
(
iobase
))
>>
6
)
&
3
];
if
(
u
==
c_uart_16450
)
{
outb
(
0x5a
,
UART_SCR
(
iobase
));
b1
=
inb
(
UART_SCR
(
iobase
));
outb
(
0xa5
,
UART_SCR
(
iobase
));
b2
=
inb
(
UART_SCR
(
iobase
));
if
((
b1
!=
0x5a
)
||
(
b2
!=
0xa5
))
u
=
c_uart_8250
;
}
return
u
;
}
/* --------------------------------------------------------------------- */
static
int
check_midi
(
unsigned
int
iobase
)
{
unsigned
long
timeout
;
unsigned
long
flags
;
unsigned
char
b
;
if
(
iobase
<=
0
||
iobase
>
0x1000
-
MIDI_EXTENT
)
return
0
;
if
(
check_region
(
iobase
,
MIDI_EXTENT
))
return
0
;
timeout
=
jiffies
+
(
HZ
/
100
);
while
(
inb
(
MIDI_STATUS
(
iobase
))
&
MIDI_WRITE_EMPTY
)
if
((
signed
)(
jiffies
-
timeout
)
>
0
)
return
0
;
save_flags
(
flags
);
cli
();
outb
(
0xff
,
MIDI_DATA
(
iobase
));
b
=
inb
(
MIDI_STATUS
(
iobase
));
restore_flags
(
flags
);
if
(
!
(
b
&
MIDI_WRITE_EMPTY
))
return
0
;
while
(
inb
(
MIDI_STATUS
(
iobase
))
&
MIDI_WRITE_EMPTY
)
if
((
signed
)(
jiffies
-
timeout
)
>
0
)
return
0
;
return
1
;
}
/* --------------------------------------------------------------------- */
void
sm_output_status
(
struct
sm_state
*
sm
)
{
int
invert_dcd
=
0
;
int
invert_ptt
=
0
;
int
ptt
=
/*hdlcdrv_ptt(&sm->hdrv)*/
(
sm
->
dma
.
ptt_cnt
>
0
)
^
invert_ptt
;
int
dcd
=
(
!!
sm
->
hdrv
.
hdlcrx
.
dcd
)
^
invert_dcd
;
if
(
sm
->
hdrv
.
ptt_out
.
flags
&
SP_SER
)
{
outb
(
dcd
|
(
ptt
<<
1
),
UART_MCR
(
sm
->
hdrv
.
ptt_out
.
seriobase
));
outb
(
0x40
&
(
-
ptt
),
UART_LCR
(
sm
->
hdrv
.
ptt_out
.
seriobase
));
}
if
(
sm
->
hdrv
.
ptt_out
.
flags
&
SP_PAR
&&
sm
->
pardev
&&
sm
->
pardev
->
port
)
parport_write_data
(
sm
->
pardev
->
port
,
ptt
|
(
dcd
<<
1
));
if
(
sm
->
hdrv
.
ptt_out
.
flags
&
SP_MIDI
&&
hdlcdrv_ptt
(
&
sm
->
hdrv
))
outb
(
0
,
MIDI_DATA
(
sm
->
hdrv
.
ptt_out
.
midiiobase
));
}
/* --------------------------------------------------------------------- */
static
void
sm_output_open
(
struct
sm_state
*
sm
,
const
char
*
ifname
)
{
enum
uart
u
=
c_uart_unknown
;
struct
parport
*
pp
=
NULL
;
sm
->
hdrv
.
ptt_out
.
flags
=
0
;
if
(
sm
->
hdrv
.
ptt_out
.
seriobase
>
0
&&
sm
->
hdrv
.
ptt_out
.
seriobase
<=
0x1000
-
SER_EXTENT
&&
((
u
=
check_uart
(
sm
->
hdrv
.
ptt_out
.
seriobase
)))
!=
c_uart_unknown
)
{
sm
->
hdrv
.
ptt_out
.
flags
|=
SP_SER
;
request_region
(
sm
->
hdrv
.
ptt_out
.
seriobase
,
SER_EXTENT
,
"sm ser ptt"
);
outb
(
0
,
UART_IER
(
sm
->
hdrv
.
ptt_out
.
seriobase
));
/* 5 bits, 1 stop, no parity, no break, Div latch access */
outb
(
0x80
,
UART_LCR
(
sm
->
hdrv
.
ptt_out
.
seriobase
));
outb
(
0
,
UART_DLM
(
sm
->
hdrv
.
ptt_out
.
seriobase
));
outb
(
1
,
UART_DLL
(
sm
->
hdrv
.
ptt_out
.
seriobase
));
/* as fast as possible */
/* LCR and MCR set by output_status */
}
sm
->
pardev
=
NULL
;
if
(
sm
->
hdrv
.
ptt_out
.
pariobase
>
0
)
{
pp
=
parport_enumerate
();
while
(
pp
&&
pp
->
base
!=
sm
->
hdrv
.
ptt_out
.
pariobase
)
pp
=
pp
->
next
;
if
(
!
pp
)
printk
(
KERN_WARNING
"%s: parport at address 0x%x not found
\n
"
,
sm_drvname
,
sm
->
hdrv
.
ptt_out
.
pariobase
);
else
if
((
~
pp
->
modes
)
&
(
PARPORT_MODE_PCSPP
|
PARPORT_MODE_SAFEININT
))
printk
(
KERN_WARNING
"%s: parport at address 0x%x cannot be used
\n
"
,
sm_drvname
,
sm
->
hdrv
.
ptt_out
.
pariobase
);
else
{
sm
->
pardev
=
parport_register_device
(
pp
,
ifname
,
NULL
,
NULL
,
NULL
,
PARPORT_DEV_EXCL
,
NULL
);
if
(
!
sm
->
pardev
)
{
pp
=
NULL
;
printk
(
KERN_WARNING
"%s: cannot register parport device (address 0x%x)
\n
"
,
sm_drvname
,
sm
->
hdrv
.
ptt_out
.
pariobase
);
}
else
{
if
(
parport_claim
(
sm
->
pardev
))
{
parport_unregister_device
(
sm
->
pardev
);
sm
->
pardev
=
NULL
;
printk
(
KERN_WARNING
"%s: cannot claim parport at address 0x%x
\n
"
,
sm_drvname
,
sm
->
hdrv
.
ptt_out
.
pariobase
);
}
else
sm
->
hdrv
.
ptt_out
.
flags
|=
SP_PAR
;
}
}
}
if
(
sm
->
hdrv
.
ptt_out
.
midiiobase
>
0
&&
sm
->
hdrv
.
ptt_out
.
midiiobase
<=
0x1000
-
MIDI_EXTENT
&&
check_midi
(
sm
->
hdrv
.
ptt_out
.
midiiobase
))
{
sm
->
hdrv
.
ptt_out
.
flags
|=
SP_MIDI
;
request_region
(
sm
->
hdrv
.
ptt_out
.
midiiobase
,
MIDI_EXTENT
,
"sm midi ptt"
);
}
sm_output_status
(
sm
);
printk
(
KERN_INFO
"%s: ptt output:"
,
sm_drvname
);
if
(
sm
->
hdrv
.
ptt_out
.
flags
&
SP_SER
)
printk
(
" serial interface at 0x%x, uart %s"
,
sm
->
hdrv
.
ptt_out
.
seriobase
,
uart_str
[
u
]);
if
(
sm
->
hdrv
.
ptt_out
.
flags
&
SP_PAR
)
printk
(
" parallel interface at 0x%x"
,
sm
->
hdrv
.
ptt_out
.
pariobase
);
if
(
sm
->
hdrv
.
ptt_out
.
flags
&
SP_MIDI
)
printk
(
" mpu401 (midi) interface at 0x%x"
,
sm
->
hdrv
.
ptt_out
.
midiiobase
);
if
(
!
sm
->
hdrv
.
ptt_out
.
flags
)
printk
(
" none"
);
printk
(
"
\n
"
);
}
/* --------------------------------------------------------------------- */
static
void
sm_output_close
(
struct
sm_state
*
sm
)
{
/* release regions used for PTT output */
sm
->
hdrv
.
hdlctx
.
ptt
=
sm
->
hdrv
.
hdlctx
.
calibrate
=
0
;
sm_output_status
(
sm
);
if
(
sm
->
hdrv
.
ptt_out
.
flags
&
SP_SER
)
release_region
(
sm
->
hdrv
.
ptt_out
.
seriobase
,
SER_EXTENT
);
if
(
sm
->
hdrv
.
ptt_out
.
flags
&
SP_PAR
&&
sm
->
pardev
)
{
parport_release
(
sm
->
pardev
);
parport_unregister_device
(
sm
->
pardev
);
}
if
(
sm
->
hdrv
.
ptt_out
.
flags
&
SP_MIDI
)
release_region
(
sm
->
hdrv
.
ptt_out
.
midiiobase
,
MIDI_EXTENT
);
sm
->
hdrv
.
ptt_out
.
flags
=
0
;
}
/* --------------------------------------------------------------------- */
static
int
sm_open
(
struct
net_device
*
dev
);
static
int
sm_close
(
struct
net_device
*
dev
);
static
int
sm_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
ifr
,
struct
hdlcdrv_ioctl
*
hi
,
int
cmd
);
/* --------------------------------------------------------------------- */
static
const
struct
hdlcdrv_ops
sm_ops
=
{
sm_drvname
,
sm_drvinfo
,
sm_open
,
sm_close
,
sm_ioctl
};
/* --------------------------------------------------------------------- */
static
int
sm_open
(
struct
net_device
*
dev
)
{
struct
sm_state
*
sm
;
int
err
;
if
(
!
dev
||
!
dev
->
priv
||
((
struct
sm_state
*
)
dev
->
priv
)
->
hdrv
.
magic
!=
HDLCDRV_MAGIC
)
{
printk
(
KERN_ERR
"sm_open: invalid device struct
\n
"
);
return
-
EINVAL
;
}
sm
=
(
struct
sm_state
*
)
dev
->
priv
;
if
(
!
sm
->
mode_tx
||
!
sm
->
mode_rx
||
!
sm
->
hwdrv
||
!
sm
->
hwdrv
->
open
)
return
-
ENODEV
;
sm
->
hdrv
.
par
.
bitrate
=
sm
->
mode_rx
->
bitrate
;
err
=
sm
->
hwdrv
->
open
(
dev
,
sm
);
if
(
err
)
return
err
;
sm_output_open
(
sm
,
dev
->
name
);
MOD_INC_USE_COUNT
;
printk
(
KERN_INFO
"%s: %s mode %s.%s at iobase 0x%lx irq %u dma %u dma2 %u
\n
"
,
sm_drvname
,
sm
->
hwdrv
->
hw_name
,
sm
->
mode_tx
->
name
,
sm
->
mode_rx
->
name
,
dev
->
base_addr
,
dev
->
irq
,
dev
->
dma
,
sm
->
hdrv
.
ptt_out
.
dma2
);
return
0
;
}
/* --------------------------------------------------------------------- */
static
int
sm_close
(
struct
net_device
*
dev
)
{
struct
sm_state
*
sm
;
int
err
=
-
ENODEV
;
if
(
!
dev
||
!
dev
->
priv
||
((
struct
sm_state
*
)
dev
->
priv
)
->
hdrv
.
magic
!=
HDLCDRV_MAGIC
)
{
printk
(
KERN_ERR
"sm_close: invalid device struct
\n
"
);
return
-
EINVAL
;
}
sm
=
(
struct
sm_state
*
)
dev
->
priv
;
if
(
sm
->
hwdrv
&&
sm
->
hwdrv
->
close
)
err
=
sm
->
hwdrv
&&
sm
->
hwdrv
->
close
(
dev
,
sm
);
sm_output_close
(
sm
);
MOD_DEC_USE_COUNT
;
printk
(
KERN_INFO
"%s: close %s at iobase 0x%lx irq %u dma %u
\n
"
,
sm_drvname
,
sm
->
hwdrv
->
hw_name
,
dev
->
base_addr
,
dev
->
irq
,
dev
->
dma
);
return
err
;
}
/* --------------------------------------------------------------------- */
static
int
sethw
(
struct
net_device
*
dev
,
struct
sm_state
*
sm
,
char
*
mode
)
{
char
*
cp
=
strchr
(
mode
,
':'
);
const
struct
hardware_info
**
hwp
=
sm_hardware_table
;
if
(
!
cp
)
cp
=
mode
;
else
{
*
cp
++
=
'\0'
;
while
(
hwp
&&
(
*
hwp
)
&&
(
*
hwp
)
->
hw_name
&&
strcmp
((
*
hwp
)
->
hw_name
,
mode
))
hwp
++
;
if
(
!
hwp
||
!*
hwp
||
!
(
*
hwp
)
->
hw_name
)
return
-
EINVAL
;
if
((
*
hwp
)
->
loc_storage
>
sizeof
(
sm
->
hw
))
{
printk
(
KERN_ERR
"%s: insufficient storage for hw driver %s (%d)
\n
"
,
sm_drvname
,
(
*
hwp
)
->
hw_name
,
(
*
hwp
)
->
loc_storage
);
return
-
EINVAL
;
}
sm
->
hwdrv
=
*
hwp
;
}
if
(
!*
cp
)
return
0
;
if
(
sm
->
hwdrv
&&
sm
->
hwdrv
->
sethw
)
return
sm
->
hwdrv
->
sethw
(
dev
,
sm
,
cp
);
return
-
EINVAL
;
}
/* --------------------------------------------------------------------- */
static
int
sm_ioctl
(
struct
net_device
*
dev
,
struct
ifreq
*
ifr
,
struct
hdlcdrv_ioctl
*
hi
,
int
cmd
)
{
struct
sm_state
*
sm
;
struct
sm_ioctl
bi
;
unsigned
long
flags
;
unsigned
int
newdiagmode
;
unsigned
int
newdiagflags
;
char
*
cp
;
const
struct
modem_tx_info
**
mtp
=
sm_modem_tx_table
;
const
struct
modem_rx_info
**
mrp
=
sm_modem_rx_table
;
const
struct
hardware_info
**
hwp
=
sm_hardware_table
;
if
(
!
dev
||
!
dev
->
priv
||
((
struct
sm_state
*
)
dev
->
priv
)
->
hdrv
.
magic
!=
HDLCDRV_MAGIC
)
{
printk
(
KERN_ERR
"sm_ioctl: invalid device struct
\n
"
);
return
-
EINVAL
;
}
sm
=
(
struct
sm_state
*
)
dev
->
priv
;
if
(
cmd
!=
SIOCDEVPRIVATE
)
{
if
(
!
sm
->
hwdrv
||
!
sm
->
hwdrv
->
ioctl
)
return
sm
->
hwdrv
->
ioctl
(
dev
,
sm
,
ifr
,
hi
,
cmd
);
return
-
ENOIOCTLCMD
;
}
switch
(
hi
->
cmd
)
{
default:
if
(
sm
->
hwdrv
&&
sm
->
hwdrv
->
ioctl
)
return
sm
->
hwdrv
->
ioctl
(
dev
,
sm
,
ifr
,
hi
,
cmd
);
return
-
ENOIOCTLCMD
;
case
HDLCDRVCTL_GETMODE
:
cp
=
hi
->
data
.
modename
;
if
(
sm
->
hwdrv
&&
sm
->
hwdrv
->
hw_name
)
cp
+=
sprintf
(
cp
,
"%s:"
,
sm
->
hwdrv
->
hw_name
);
else
cp
+=
sprintf
(
cp
,
"<unspec>:"
);
if
(
sm
->
mode_tx
&&
sm
->
mode_tx
->
name
)
cp
+=
sprintf
(
cp
,
"%s"
,
sm
->
mode_tx
->
name
);
else
cp
+=
sprintf
(
cp
,
"<unspec>"
);
if
(
!
sm
->
mode_rx
||
!
sm
->
mode_rx
||
strcmp
(
sm
->
mode_rx
->
name
,
sm
->
mode_tx
->
name
))
{
if
(
sm
->
mode_rx
&&
sm
->
mode_rx
->
name
)
cp
+=
sprintf
(
cp
,
",%s"
,
sm
->
mode_rx
->
name
);
else
cp
+=
sprintf
(
cp
,
",<unspec>"
);
}
if
(
copy_to_user
(
ifr
->
ifr_data
,
hi
,
sizeof
(
*
hi
)))
return
-
EFAULT
;
return
0
;
case
HDLCDRVCTL_SETMODE
:
if
(
netif_running
(
dev
)
||
!
capable
(
CAP_NET_ADMIN
))
return
-
EACCES
;
hi
->
data
.
modename
[
sizeof
(
hi
->
data
.
modename
)
-
1
]
=
'\0'
;
return
sethw
(
dev
,
sm
,
hi
->
data
.
modename
);
case
HDLCDRVCTL_MODELIST
:
cp
=
hi
->
data
.
modename
;
while
(
*
hwp
)
{
if
((
*
hwp
)
->
hw_name
)
cp
+=
sprintf
(
cp
,
"%s:,"
,
(
*
hwp
)
->
hw_name
);
hwp
++
;
}
while
(
*
mtp
)
{
if
((
*
mtp
)
->
name
)
cp
+=
sprintf
(
cp
,
">%s,"
,
(
*
mtp
)
->
name
);
mtp
++
;
}
while
(
*
mrp
)
{
if
((
*
mrp
)
->
name
)
cp
+=
sprintf
(
cp
,
"<%s,"
,
(
*
mrp
)
->
name
);
mrp
++
;
}
cp
[
-
1
]
=
'\0'
;
if
(
copy_to_user
(
ifr
->
ifr_data
,
hi
,
sizeof
(
*
hi
)))
return
-
EFAULT
;
return
0
;
#ifdef SM_DEBUG
case
SMCTL_GETDEBUG
:
if
(
copy_from_user
(
&
bi
,
ifr
->
ifr_data
,
sizeof
(
bi
)))
return
-
EFAULT
;
bi
.
data
.
dbg
.
int_rate
=
sm
->
debug_vals
.
last_intcnt
;
bi
.
data
.
dbg
.
mod_cycles
=
sm
->
debug_vals
.
mod_cyc
;
bi
.
data
.
dbg
.
demod_cycles
=
sm
->
debug_vals
.
demod_cyc
;
bi
.
data
.
dbg
.
dma_residue
=
sm
->
debug_vals
.
dma_residue
;
sm
->
debug_vals
.
mod_cyc
=
sm
->
debug_vals
.
demod_cyc
=
sm
->
debug_vals
.
dma_residue
=
0
;
if
(
copy_to_user
(
ifr
->
ifr_data
,
&
bi
,
sizeof
(
bi
)))
return
-
EFAULT
;
return
0
;
#endif
/* SM_DEBUG */
case
SMCTL_DIAGNOSE
:
if
(
copy_from_user
(
&
bi
,
ifr
->
ifr_data
,
sizeof
(
bi
)))
return
-
EFAULT
;
newdiagmode
=
bi
.
data
.
diag
.
mode
;
newdiagflags
=
bi
.
data
.
diag
.
flags
;
if
(
newdiagmode
>
SM_DIAGMODE_CONSTELLATION
)
return
-
EINVAL
;
bi
.
data
.
diag
.
mode
=
sm
->
diag
.
mode
;
bi
.
data
.
diag
.
flags
=
sm
->
diag
.
flags
;
bi
.
data
.
diag
.
samplesperbit
=
sm
->
mode_rx
->
sperbit
;
if
(
sm
->
diag
.
mode
!=
newdiagmode
)
{
save_flags
(
flags
);
cli
();
sm
->
diag
.
ptr
=
-
1
;
sm
->
diag
.
flags
=
newdiagflags
&
~
SM_DIAGFLAG_VALID
;
sm
->
diag
.
mode
=
newdiagmode
;
restore_flags
(
flags
);
if
(
copy_to_user
(
ifr
->
ifr_data
,
&
bi
,
sizeof
(
bi
)))
return
-
EFAULT
;
return
0
;
}
if
(
sm
->
diag
.
ptr
<
0
||
sm
->
diag
.
mode
==
SM_DIAGMODE_OFF
)
{
if
(
copy_to_user
(
ifr
->
ifr_data
,
&
bi
,
sizeof
(
bi
)))
return
-
EFAULT
;
return
0
;
}
if
(
bi
.
data
.
diag
.
datalen
>
DIAGDATALEN
)
bi
.
data
.
diag
.
datalen
=
DIAGDATALEN
;
if
(
sm
->
diag
.
ptr
<
bi
.
data
.
diag
.
datalen
)
{
if
(
copy_to_user
(
ifr
->
ifr_data
,
&
bi
,
sizeof
(
bi
)))
return
-
EFAULT
;
return
0
;
}
if
(
copy_to_user
(
bi
.
data
.
diag
.
data
,
sm
->
diag
.
data
,
bi
.
data
.
diag
.
datalen
*
sizeof
(
short
)))
return
-
EFAULT
;
bi
.
data
.
diag
.
flags
|=
SM_DIAGFLAG_VALID
;
save_flags
(
flags
);
cli
();
sm
->
diag
.
ptr
=
-
1
;
sm
->
diag
.
flags
=
newdiagflags
&
~
SM_DIAGFLAG_VALID
;
sm
->
diag
.
mode
=
newdiagmode
;
restore_flags
(
flags
);
if
(
copy_to_user
(
ifr
->
ifr_data
,
&
bi
,
sizeof
(
bi
)))
return
-
EFAULT
;
return
0
;
}
}
/* --------------------------------------------------------------------- */
/*
* command line settable parameters
*/
static
char
*
mode
[
NR_PORTS
]
=
{
[
0
...
NR_PORTS
-
1
]
=
NULL
};
static
int
iobase
[
NR_PORTS
]
=
{
[
0
...
NR_PORTS
-
1
]
=
-
1
};
static
int
irq
[
NR_PORTS
]
=
{
[
0
...
NR_PORTS
-
1
]
=
-
1
};
static
int
dma
[
NR_PORTS
]
=
{
[
0
...
NR_PORTS
-
1
]
=
-
1
};
static
int
dma2
[
NR_PORTS
]
=
{
[
0
...
NR_PORTS
-
1
]
=
-
1
};
static
int
serio
[
NR_PORTS
]
=
{
[
0
...
NR_PORTS
-
1
]
=
0
};
static
int
pario
[
NR_PORTS
]
=
{
[
0
...
NR_PORTS
-
1
]
=
0
};
static
int
midiio
[
NR_PORTS
]
=
{
[
0
...
NR_PORTS
-
1
]
=
0
};
MODULE_PARM
(
mode
,
"1-"
__MODULE_STRING
(
NR_PORTS
)
"s"
);
MODULE_PARM_DESC
(
mode
,
"soundmodem operating mode; eg. sbc:afsk1200 or wss:fsk9600"
);
MODULE_PARM
(
iobase
,
"1-"
__MODULE_STRING
(
NR_PORTS
)
"i"
);
MODULE_PARM_DESC
(
iobase
,
"soundmodem base address"
);
MODULE_PARM
(
irq
,
"1-"
__MODULE_STRING
(
NR_PORTS
)
"i"
);
MODULE_PARM_DESC
(
irq
,
"soundmodem interrupt"
);
MODULE_PARM
(
dma
,
"1-"
__MODULE_STRING
(
NR_PORTS
)
"i"
);
MODULE_PARM_DESC
(
dma
,
"soundmodem dma channel"
);
MODULE_PARM
(
dma2
,
"1-"
__MODULE_STRING
(
NR_PORTS
)
"i"
);
MODULE_PARM_DESC
(
dma2
,
"soundmodem 2nd dma channel; full duplex only"
);
MODULE_PARM
(
serio
,
"1-"
__MODULE_STRING
(
NR_PORTS
)
"i"
);
MODULE_PARM_DESC
(
serio
,
"soundmodem PTT output on serial port"
);
MODULE_PARM
(
pario
,
"1-"
__MODULE_STRING
(
NR_PORTS
)
"i"
);
MODULE_PARM_DESC
(
pario
,
"soundmodem PTT output on parallel port"
);
MODULE_PARM
(
midiio
,
"1-"
__MODULE_STRING
(
NR_PORTS
)
"i"
);
MODULE_PARM_DESC
(
midiio
,
"soundmodem PTT output on midi port"
);
MODULE_AUTHOR
(
"Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"
);
MODULE_DESCRIPTION
(
"Soundcard amateur radio modem driver"
);
/* --------------------------------------------------------------------- */
static
int
__init
init_soundmodem
(
void
)
{
int
i
,
j
,
found
=
0
;
char
set_hw
=
1
;
struct
sm_state
*
sm
;
printk
(
sm_drvinfo
);
/*
* register net devices
*/
for
(
i
=
0
;
i
<
NR_PORTS
;
i
++
)
{
struct
net_device
*
dev
=
sm_device
+
i
;
char
ifname
[
IFNAMSIZ
];
sprintf
(
ifname
,
"sm%d"
,
i
);
if
(
!
mode
[
i
])
set_hw
=
0
;
else
{
if
(
!
strncmp
(
mode
[
i
],
"sbc"
,
3
))
{
if
(
iobase
[
i
]
==
-
1
)
iobase
[
i
]
=
0x220
;
if
(
irq
[
i
]
==
-
1
)
irq
[
i
]
=
5
;
if
(
dma
[
i
]
==
-
1
)
dma
[
i
]
=
1
;
}
else
{
if
(
iobase
[
i
]
==
-
1
)
iobase
[
i
]
=
0x530
;
if
(
irq
[
i
]
==
-
1
)
irq
[
i
]
=
11
;
if
(
dma
[
i
]
==
-
1
)
dma
[
i
]
=
1
;
}
}
if
(
!
set_hw
)
iobase
[
i
]
=
irq
[
i
]
=
0
;
j
=
hdlcdrv_register_hdlcdrv
(
dev
,
&
sm_ops
,
sizeof
(
struct
sm_state
),
ifname
,
iobase
[
i
],
irq
[
i
],
dma
[
i
]);
if
(
!
j
)
{
sm
=
(
struct
sm_state
*
)
dev
->
priv
;
sm
->
hdrv
.
ptt_out
.
dma2
=
dma2
[
i
];
sm
->
hdrv
.
ptt_out
.
seriobase
=
serio
[
i
];
sm
->
hdrv
.
ptt_out
.
pariobase
=
pario
[
i
];
sm
->
hdrv
.
ptt_out
.
midiiobase
=
midiio
[
i
];
if
(
set_hw
&&
sethw
(
dev
,
sm
,
mode
[
i
]))
set_hw
=
0
;
found
++
;
}
else
{
printk
(
KERN_WARNING
"%s: cannot register net device
\n
"
,
sm_drvname
);
}
}
if
(
!
found
)
return
-
ENXIO
;
return
0
;
}
static
void
__exit
cleanup_soundmodem
(
void
)
{
int
i
;
printk
(
KERN_INFO
"sm: cleanup_module called
\n
"
);
for
(
i
=
0
;
i
<
NR_PORTS
;
i
++
)
{
struct
net_device
*
dev
=
sm_device
+
i
;
struct
sm_state
*
sm
=
(
struct
sm_state
*
)
dev
->
priv
;
if
(
sm
)
{
if
(
sm
->
hdrv
.
magic
!=
HDLCDRV_MAGIC
)
printk
(
KERN_ERR
"sm: invalid magic in "
"cleanup_module
\n
"
);
else
hdlcdrv_unregister_hdlcdrv
(
dev
);
}
}
}
module_init
(
init_soundmodem
);
module_exit
(
cleanup_soundmodem
);
/* --------------------------------------------------------------------- */
#ifndef MODULE
/*
* format: soundmodem=io,irq,dma[,dma2[,serio[,pario]]],mode
* mode: hw:modem
* hw: sbc, wss, wssfdx
* modem: afsk1200, fsk9600
*/
static
int
__init
sm_setup
(
char
*
str
)
{
static
unsigned
nr_dev
;
int
ints
[
8
];
if
(
nr_dev
>=
NR_PORTS
)
return
0
;
str
=
get_options
(
str
,
8
,
ints
);
mode
[
nr_dev
]
=
str
;
if
(
ints
[
0
]
>=
1
)
iobase
[
nr_dev
]
=
ints
[
1
];
if
(
ints
[
0
]
>=
2
)
irq
[
nr_dev
]
=
ints
[
2
];
if
(
ints
[
0
]
>=
3
)
dma
[
nr_dev
]
=
ints
[
3
];
if
(
ints
[
0
]
>=
4
)
dma2
[
nr_dev
]
=
ints
[
4
];
if
(
ints
[
0
]
>=
5
)
serio
[
nr_dev
]
=
ints
[
5
];
if
(
ints
[
0
]
>=
6
)
pario
[
nr_dev
]
=
ints
[
6
];
if
(
ints
[
0
]
>=
7
)
midiio
[
nr_dev
]
=
ints
[
7
];
nr_dev
++
;
return
1
;
}
__setup
(
"soundmodem="
,
sm_setup
);
#endif
/* MODULE */
/* --------------------------------------------------------------------- */
drivers/net/hamradio/soundmodem/sm.h
deleted
100644 → 0
View file @
a994c542
/*****************************************************************************/
/*
* sm.h -- soundcard radio modem driver internal header.
*
* Copyright (C) 1996-1999 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 _SM_H
#define _SM_H
/* ---------------------------------------------------------------------- */
#include <linux/hdlcdrv.h>
#include <linux/soundmodem.h>
#include <asm/processor.h>
#include <linux/bitops.h>
#include <linux/parport.h>
#define SM_DEBUG
/* ---------------------------------------------------------------------- */
/*
* Information that need to be kept for each board.
*/
struct
sm_state
{
struct
hdlcdrv_state
hdrv
;
const
struct
modem_tx_info
*
mode_tx
;
const
struct
modem_rx_info
*
mode_rx
;
const
struct
hardware_info
*
hwdrv
;
struct
pardevice
*
pardev
;
/*
* Hardware (soundcard) access routines state
*/
struct
{
void
*
ibuf
;
unsigned
int
ifragsz
;
unsigned
int
ifragptr
;
unsigned
int
i16bit
;
void
*
obuf
;
unsigned
int
ofragsz
;
unsigned
int
ofragptr
;
unsigned
int
o16bit
;
int
ptt_cnt
;
}
dma
;
union
{
long
hw
[
32
/
sizeof
(
long
)];
}
hw
;
/*
* state of the modem code
*/
union
{
long
m
[
48
/
sizeof
(
long
)];
}
m
;
union
{
long
d
[
256
/
sizeof
(
long
)];
}
d
;
#define DIAGDATALEN 64
struct
diag_data
{
unsigned
int
mode
;
unsigned
int
flags
;
volatile
int
ptr
;
short
data
[
DIAGDATALEN
];
}
diag
;
#ifdef SM_DEBUG
struct
debug_vals
{
unsigned
long
last_jiffies
;
unsigned
cur_intcnt
;
unsigned
last_intcnt
;
unsigned
mod_cyc
;
unsigned
demod_cyc
;
unsigned
dma_residue
;
}
debug_vals
;
#endif
/* SM_DEBUG */
};
/* ---------------------------------------------------------------------- */
/*
* Mode definition structure
*/
struct
modem_tx_info
{
const
char
*
name
;
unsigned
int
loc_storage
;
int
srate
;
int
bitrate
;
void
(
*
modulator_u8
)(
struct
sm_state
*
,
unsigned
char
*
,
unsigned
int
);
void
(
*
modulator_s16
)(
struct
sm_state
*
,
short
*
,
unsigned
int
);
void
(
*
init
)(
struct
sm_state
*
);
};
struct
modem_rx_info
{
const
char
*
name
;
unsigned
int
loc_storage
;
int
srate
;
int
bitrate
;
unsigned
int
overlap
;
unsigned
int
sperbit
;
void
(
*
demodulator_u8
)(
struct
sm_state
*
,
const
unsigned
char
*
,
unsigned
int
);
void
(
*
demodulator_s16
)(
struct
sm_state
*
,
const
short
*
,
unsigned
int
);
void
(
*
init
)(
struct
sm_state
*
);
};
/* ---------------------------------------------------------------------- */
/*
* Soundcard driver definition structure
*/
struct
hardware_info
{
char
*
hw_name
;
/* used for request_{region,irq,dma} */
unsigned
int
loc_storage
;
/*
* mode specific open/close
*/
int
(
*
open
)(
struct
net_device
*
,
struct
sm_state
*
);
int
(
*
close
)(
struct
net_device
*
,
struct
sm_state
*
);
int
(
*
ioctl
)(
struct
net_device
*
,
struct
sm_state
*
,
struct
ifreq
*
,
struct
hdlcdrv_ioctl
*
,
int
);
int
(
*
sethw
)(
struct
net_device
*
,
struct
sm_state
*
,
char
*
);
};
/* --------------------------------------------------------------------- */
extern
const
char
sm_drvname
[];
extern
const
char
sm_drvinfo
[];
/* --------------------------------------------------------------------- */
/*
* ===================== diagnostics stuff ===============================
*/
static
inline
void
diag_trigger
(
struct
sm_state
*
sm
)
{
if
(
sm
->
diag
.
ptr
<
0
)
if
(
!
(
sm
->
diag
.
flags
&
SM_DIAGFLAG_DCDGATE
)
||
sm
->
hdrv
.
hdlcrx
.
dcd
)
sm
->
diag
.
ptr
=
0
;
}
/* --------------------------------------------------------------------- */
#define SHRT_MAX ((short)(((unsigned short)(~0U))>>1))
#define SHRT_MIN (-SHRT_MAX-1)
static
inline
void
diag_add
(
struct
sm_state
*
sm
,
int
valinp
,
int
valdemod
)
{
int
val
;
if
((
sm
->
diag
.
mode
!=
SM_DIAGMODE_INPUT
&&
sm
->
diag
.
mode
!=
SM_DIAGMODE_DEMOD
)
||
sm
->
diag
.
ptr
>=
DIAGDATALEN
||
sm
->
diag
.
ptr
<
0
)
return
;
val
=
(
sm
->
diag
.
mode
==
SM_DIAGMODE_DEMOD
)
?
valdemod
:
valinp
;
/* clip */
if
(
val
>
SHRT_MAX
)
val
=
SHRT_MAX
;
if
(
val
<
SHRT_MIN
)
val
=
SHRT_MIN
;
sm
->
diag
.
data
[
sm
->
diag
.
ptr
++
]
=
val
;
}
/* --------------------------------------------------------------------- */
static
inline
void
diag_add_one
(
struct
sm_state
*
sm
,
int
val
)
{
if
((
sm
->
diag
.
mode
!=
SM_DIAGMODE_INPUT
&&
sm
->
diag
.
mode
!=
SM_DIAGMODE_DEMOD
)
||
sm
->
diag
.
ptr
>=
DIAGDATALEN
||
sm
->
diag
.
ptr
<
0
)
return
;
/* clip */
if
(
val
>
SHRT_MAX
)
val
=
SHRT_MAX
;
if
(
val
<
SHRT_MIN
)
val
=
SHRT_MIN
;
sm
->
diag
.
data
[
sm
->
diag
.
ptr
++
]
=
val
;
}
/* --------------------------------------------------------------------- */
static
inline
void
diag_add_constellation
(
struct
sm_state
*
sm
,
int
vali
,
int
valq
)
{
if
((
sm
->
diag
.
mode
!=
SM_DIAGMODE_CONSTELLATION
)
||
sm
->
diag
.
ptr
>=
DIAGDATALEN
-
1
||
sm
->
diag
.
ptr
<
0
)
return
;
/* clip */
if
(
vali
>
SHRT_MAX
)
vali
=
SHRT_MAX
;
if
(
vali
<
SHRT_MIN
)
vali
=
SHRT_MIN
;
if
(
valq
>
SHRT_MAX
)
valq
=
SHRT_MAX
;
if
(
valq
<
SHRT_MIN
)
valq
=
SHRT_MIN
;
sm
->
diag
.
data
[
sm
->
diag
.
ptr
++
]
=
vali
;
sm
->
diag
.
data
[
sm
->
diag
.
ptr
++
]
=
valq
;
}
/* --------------------------------------------------------------------- */
/*
* ===================== utility functions ===============================
*/
#if 0
static inline unsigned int hweight32(unsigned int w)
__attribute__ ((unused));
static inline unsigned int hweight16(unsigned short w)
__attribute__ ((unused));
static inline unsigned int hweight8(unsigned char w)
__attribute__ ((unused));
static inline unsigned int hweight32(unsigned int w)
{
unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
}
static inline unsigned int hweight16(unsigned short w)
{
unsigned short res = (w & 0x5555) + ((w >> 1) & 0x5555);
res = (res & 0x3333) + ((res >> 2) & 0x3333);
res = (res & 0x0F0F) + ((res >> 4) & 0x0F0F);
return (res & 0x00FF) + ((res >> 8) & 0x00FF);
}
static inline unsigned int hweight8(unsigned char w)
{
unsigned short res = (w & 0x55) + ((w >> 1) & 0x55);
res = (res & 0x33) + ((res >> 2) & 0x33);
return (res & 0x0F) + ((res >> 4) & 0x0F);
}
#endif
static
inline
unsigned
int
gcd
(
unsigned
int
x
,
unsigned
int
y
)
__attribute__
((
unused
));
static
inline
unsigned
int
lcm
(
unsigned
int
x
,
unsigned
int
y
)
__attribute__
((
unused
));
static
inline
unsigned
int
gcd
(
unsigned
int
x
,
unsigned
int
y
)
{
for
(;;)
{
if
(
!
x
)
return
y
;
if
(
!
y
)
return
x
;
if
(
x
>
y
)
x
%=
y
;
else
y
%=
x
;
}
}
static
inline
unsigned
int
lcm
(
unsigned
int
x
,
unsigned
int
y
)
{
return
x
*
y
/
gcd
(
x
,
y
);
}
/* --------------------------------------------------------------------- */
/*
* ===================== profiling =======================================
*/
#ifdef __i386__
#include <asm/msr.h>
/*
* only do 32bit cycle counter arithmetic; we hope we won't overflow.
* in fact, overflowing modems would require over 2THz CPU clock speeds :-)
*/
#define time_exec(var,cmd) \
({ \
if (cpu_has_tsc) { \
unsigned int cnt1, cnt2; \
rdtscl(cnt1); \
cmd; \
rdtscl(cnt2); \
var = cnt2-cnt1; \
} else { \
cmd; \
} \
})
#else
/* __i386__ */
#define time_exec(var,cmd) cmd
#endif
/* __i386__ */
/* --------------------------------------------------------------------- */
extern
const
struct
modem_tx_info
sm_afsk1200_tx
;
extern
const
struct
modem_tx_info
sm_afsk2400_7_tx
;
extern
const
struct
modem_tx_info
sm_afsk2400_8_tx
;
extern
const
struct
modem_tx_info
sm_afsk2666_tx
;
extern
const
struct
modem_tx_info
sm_psk4800_tx
;
extern
const
struct
modem_tx_info
sm_hapn4800_8_tx
;
extern
const
struct
modem_tx_info
sm_hapn4800_10_tx
;
extern
const
struct
modem_tx_info
sm_hapn4800_pm8_tx
;
extern
const
struct
modem_tx_info
sm_hapn4800_pm10_tx
;
extern
const
struct
modem_tx_info
sm_fsk9600_4_tx
;
extern
const
struct
modem_tx_info
sm_fsk9600_5_tx
;
extern
const
struct
modem_rx_info
sm_afsk1200_rx
;
extern
const
struct
modem_rx_info
sm_afsk2400_7_rx
;
extern
const
struct
modem_rx_info
sm_afsk2400_8_rx
;
extern
const
struct
modem_rx_info
sm_afsk2666_rx
;
extern
const
struct
modem_rx_info
sm_psk4800_rx
;
extern
const
struct
modem_rx_info
sm_hapn4800_8_rx
;
extern
const
struct
modem_rx_info
sm_hapn4800_10_rx
;
extern
const
struct
modem_rx_info
sm_hapn4800_pm8_rx
;
extern
const
struct
modem_rx_info
sm_hapn4800_pm10_rx
;
extern
const
struct
modem_rx_info
sm_fsk9600_4_rx
;
extern
const
struct
modem_rx_info
sm_fsk9600_5_rx
;
extern
const
struct
hardware_info
sm_hw_sbc
;
extern
const
struct
hardware_info
sm_hw_sbcfdx
;
extern
const
struct
hardware_info
sm_hw_wss
;
extern
const
struct
hardware_info
sm_hw_wssfdx
;
extern
const
struct
modem_tx_info
*
sm_modem_tx_table
[];
extern
const
struct
modem_rx_info
*
sm_modem_rx_table
[];
extern
const
struct
hardware_info
*
sm_hardware_table
[];
/* --------------------------------------------------------------------- */
void
sm_output_status
(
struct
sm_state
*
sm
);
/*void sm_output_open(struct sm_state *sm);*/
/*void sm_output_close(struct sm_state *sm);*/
/* --------------------------------------------------------------------- */
extern
void
inline
sm_int_freq
(
struct
sm_state
*
sm
)
{
#ifdef SM_DEBUG
unsigned
long
cur_jiffies
=
jiffies
;
/*
* measure the interrupt frequency
*/
sm
->
debug_vals
.
cur_intcnt
++
;
if
((
cur_jiffies
-
sm
->
debug_vals
.
last_jiffies
)
>=
HZ
)
{
sm
->
debug_vals
.
last_jiffies
=
cur_jiffies
;
sm
->
debug_vals
.
last_intcnt
=
sm
->
debug_vals
.
cur_intcnt
;
sm
->
debug_vals
.
cur_intcnt
=
0
;
}
#endif
/* SM_DEBUG */
}
/* --------------------------------------------------------------------- */
#endif
/* _SM_H */
drivers/net/hamradio/soundmodem/sm_afsk1200.c
deleted
100644 → 0
View file @
a994c542
/*****************************************************************************/
/*
* sm_afsk1200.c -- soundcard radio modem driver, 1200 baud AFSK modem
*
* 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.
*
*/
#include "sm.h"
#include "sm_tbl_afsk1200.h"
/* --------------------------------------------------------------------- */
struct
demod_state_afsk12
{
unsigned
int
shreg
;
unsigned
int
bit_pll
;
unsigned
char
last_sample
;
unsigned
int
dcd_shreg
;
int
dcd_sum0
,
dcd_sum1
,
dcd_sum2
;
unsigned
int
dcd_time
;
unsigned
char
last_rxbit
;
};
struct
mod_state_afsk12
{
unsigned
int
shreg
;
unsigned
char
tx_bit
;
unsigned
int
bit_pll
;
unsigned
int
dds_inc
;
unsigned
int
txphase
;
};
/* --------------------------------------------------------------------- */
static
const
int
dds_inc
[
2
]
=
{
AFSK12_TX_FREQ_LO
*
0x10000
/
AFSK12_SAMPLE_RATE
,
AFSK12_TX_FREQ_HI
*
0x10000
/
AFSK12_SAMPLE_RATE
};
static
void
modulator_1200_u8
(
struct
sm_state
*
sm
,
unsigned
char
*
buf
,
unsigned
int
buflen
)
{
struct
mod_state_afsk12
*
st
=
(
struct
mod_state_afsk12
*
)(
&
sm
->
m
);
for
(;
buflen
>
0
;
buflen
--
)
{
if
(
!
((
st
->
txphase
++
)
&
7
))
{
if
(
st
->
shreg
<=
1
)
st
->
shreg
=
hdlcdrv_getbits
(
&
sm
->
hdrv
)
|
0x10000
;
st
->
tx_bit
=
(
st
->
tx_bit
^
(
!
(
st
->
shreg
&
1
)))
&
1
;
st
->
shreg
>>=
1
;
}
st
->
dds_inc
=
dds_inc
[
st
->
tx_bit
&
1
];
*
buf
++
=
OFFSCOS
(
st
->
bit_pll
);
st
->
bit_pll
+=
st
->
dds_inc
;
}
}
/* --------------------------------------------------------------------- */
static
void
modulator_1200_s16
(
struct
sm_state
*
sm
,
short
*
buf
,
unsigned
int
buflen
)
{
struct
mod_state_afsk12
*
st
=
(
struct
mod_state_afsk12
*
)(
&
sm
->
m
);
for
(;
buflen
>
0
;
buflen
--
)
{
if
(
!
((
st
->
txphase
++
)
&
7
))
{
if
(
st
->
shreg
<=
1
)
st
->
shreg
=
hdlcdrv_getbits
(
&
sm
->
hdrv
)
|
0x10000
;
st
->
tx_bit
=
(
st
->
tx_bit
^
(
!
(
st
->
shreg
&
1
)))
&
1
;
st
->
shreg
>>=
1
;
}
st
->
dds_inc
=
dds_inc
[
st
->
tx_bit
&
1
];
*
buf
++
=
COS
(
st
->
bit_pll
);
st
->
bit_pll
+=
st
->
dds_inc
;
}
}
/* --------------------------------------------------------------------- */
static
__inline__
int
convolution8_u8
(
const
unsigned
char
*
st
,
const
int
*
coeff
,
int
csum
)
{
int
sum
=
-
0x80
*
csum
;
sum
+=
(
st
[
0
]
*
coeff
[
0
]);
sum
+=
(
st
[
-
1
]
*
coeff
[
1
]);
sum
+=
(
st
[
-
2
]
*
coeff
[
2
]);
sum
+=
(
st
[
-
3
]
*
coeff
[
3
]);
sum
+=
(
st
[
-
4
]
*
coeff
[
4
]);
sum
+=
(
st
[
-
5
]
*
coeff
[
5
]);
sum
+=
(
st
[
-
6
]
*
coeff
[
6
]);
sum
+=
(
st
[
-
7
]
*
coeff
[
7
]);
sum
>>=
7
;
return
sum
*
sum
;
}
static
__inline__
int
convolution8_s16
(
const
short
*
st
,
const
int
*
coeff
,
int
csum
)
{
int
sum
=
0
;
sum
+=
(
st
[
0
]
*
coeff
[
0
]);
sum
+=
(
st
[
-
1
]
*
coeff
[
1
]);
sum
+=
(
st
[
-
2
]
*
coeff
[
2
]);
sum
+=
(
st
[
-
3
]
*
coeff
[
3
]);
sum
+=
(
st
[
-
4
]
*
coeff
[
4
]);
sum
+=
(
st
[
-
5
]
*
coeff
[
5
]);
sum
+=
(
st
[
-
6
]
*
coeff
[
6
]);
sum
+=
(
st
[
-
7
]
*
coeff
[
7
]);
sum
>>=
15
;
return
sum
*
sum
;
}
static
__inline__
int
do_filter_1200_u8
(
const
unsigned
char
*
buf
)
{
int
sum
=
convolution8_u8
(
buf
,
afsk12_tx_lo_i
,
SUM_AFSK12_TX_LO_I
);
sum
+=
convolution8_u8
(
buf
,
afsk12_tx_lo_q
,
SUM_AFSK12_TX_LO_Q
);
sum
-=
convolution8_u8
(
buf
,
afsk12_tx_hi_i
,
SUM_AFSK12_TX_HI_I
);
sum
-=
convolution8_u8
(
buf
,
afsk12_tx_hi_q
,
SUM_AFSK12_TX_HI_Q
);
return
sum
;
}
static
__inline__
int
do_filter_1200_s16
(
const
short
*
buf
)
{
int
sum
=
convolution8_s16
(
buf
,
afsk12_tx_lo_i
,
SUM_AFSK12_TX_LO_I
);
sum
+=
convolution8_s16
(
buf
,
afsk12_tx_lo_q
,
SUM_AFSK12_TX_LO_Q
);
sum
-=
convolution8_s16
(
buf
,
afsk12_tx_hi_i
,
SUM_AFSK12_TX_HI_I
);
sum
-=
convolution8_s16
(
buf
,
afsk12_tx_hi_q
,
SUM_AFSK12_TX_HI_Q
);
return
sum
;
}
/* --------------------------------------------------------------------- */
static
const
int
pll_corr
[
2
]
=
{
-
0x1000
,
0x1000
};
static
void
demodulator_1200_u8
(
struct
sm_state
*
sm
,
const
unsigned
char
*
buf
,
unsigned
int
buflen
)
{
struct
demod_state_afsk12
*
st
=
(
struct
demod_state_afsk12
*
)(
&
sm
->
d
);
int
j
;
int
sum
;
unsigned
char
newsample
;
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
sum
=
do_filter_1200_u8
(
buf
);
st
->
dcd_shreg
<<=
1
;
st
->
bit_pll
+=
0x2000
;
newsample
=
(
sum
>
0
);
if
(
st
->
last_sample
^
newsample
)
{
st
->
last_sample
=
newsample
;
st
->
dcd_shreg
|=
1
;
st
->
bit_pll
+=
pll_corr
[
st
->
bit_pll
<
0x9000
];
j
=
4
*
hweight8
(
st
->
dcd_shreg
&
0x38
)
-
hweight16
(
st
->
dcd_shreg
&
0x7c0
);
st
->
dcd_sum0
+=
j
;
}
hdlcdrv_channelbit
(
&
sm
->
hdrv
,
st
->
last_sample
);
if
((
--
st
->
dcd_time
)
<=
0
)
{
hdlcdrv_setdcd
(
&
sm
->
hdrv
,
(
st
->
dcd_sum0
+
st
->
dcd_sum1
+
st
->
dcd_sum2
)
<
0
);
st
->
dcd_sum2
=
st
->
dcd_sum1
;
st
->
dcd_sum1
=
st
->
dcd_sum0
;
st
->
dcd_sum0
=
2
;
/* slight bias */
st
->
dcd_time
=
120
;
}
if
(
st
->
bit_pll
>=
0x10000
)
{
st
->
bit_pll
&=
0xffff
;
st
->
shreg
>>=
1
;
st
->
shreg
|=
(
!
(
st
->
last_rxbit
^
st
->
last_sample
))
<<
16
;
st
->
last_rxbit
=
st
->
last_sample
;
diag_trigger
(
sm
);
if
(
st
->
shreg
&
1
)
{
hdlcdrv_putbits
(
&
sm
->
hdrv
,
st
->
shreg
>>
1
);
st
->
shreg
=
0x10000
;
}
}
diag_add
(
sm
,
(((
int
)
*
buf
)
-
0x80
)
<<
8
,
sum
);
}
}
/* --------------------------------------------------------------------- */
static
void
demodulator_1200_s16
(
struct
sm_state
*
sm
,
const
short
*
buf
,
unsigned
int
buflen
)
{
struct
demod_state_afsk12
*
st
=
(
struct
demod_state_afsk12
*
)(
&
sm
->
d
);
int
j
;
int
sum
;
unsigned
char
newsample
;
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
sum
=
do_filter_1200_s16
(
buf
);
st
->
dcd_shreg
<<=
1
;
st
->
bit_pll
+=
0x2000
;
newsample
=
(
sum
>
0
);
if
(
st
->
last_sample
^
newsample
)
{
st
->
last_sample
=
newsample
;
st
->
dcd_shreg
|=
1
;
st
->
bit_pll
+=
pll_corr
[
st
->
bit_pll
<
0x9000
];
j
=
4
*
hweight8
(
st
->
dcd_shreg
&
0x38
)
-
hweight16
(
st
->
dcd_shreg
&
0x7c0
);
st
->
dcd_sum0
+=
j
;
}
hdlcdrv_channelbit
(
&
sm
->
hdrv
,
st
->
last_sample
);
if
((
--
st
->
dcd_time
)
<=
0
)
{
hdlcdrv_setdcd
(
&
sm
->
hdrv
,
(
st
->
dcd_sum0
+
st
->
dcd_sum1
+
st
->
dcd_sum2
)
<
0
);
st
->
dcd_sum2
=
st
->
dcd_sum1
;
st
->
dcd_sum1
=
st
->
dcd_sum0
;
st
->
dcd_sum0
=
2
;
/* slight bias */
st
->
dcd_time
=
120
;
}
if
(
st
->
bit_pll
>=
0x10000
)
{
st
->
bit_pll
&=
0xffff
;
st
->
shreg
>>=
1
;
st
->
shreg
|=
(
!
(
st
->
last_rxbit
^
st
->
last_sample
))
<<
16
;
st
->
last_rxbit
=
st
->
last_sample
;
diag_trigger
(
sm
);
if
(
st
->
shreg
&
1
)
{
hdlcdrv_putbits
(
&
sm
->
hdrv
,
st
->
shreg
>>
1
);
st
->
shreg
=
0x10000
;
}
}
diag_add
(
sm
,
*
buf
,
sum
);
}
}
/* --------------------------------------------------------------------- */
static
void
demod_init_1200
(
struct
sm_state
*
sm
)
{
struct
demod_state_afsk12
*
st
=
(
struct
demod_state_afsk12
*
)(
&
sm
->
d
);
st
->
dcd_time
=
120
;
st
->
dcd_sum0
=
2
;
}
/* --------------------------------------------------------------------- */
const
struct
modem_tx_info
sm_afsk1200_tx
=
{
"afsk1200"
,
sizeof
(
struct
mod_state_afsk12
),
AFSK12_SAMPLE_RATE
,
1200
,
modulator_1200_u8
,
modulator_1200_s16
,
NULL
};
const
struct
modem_rx_info
sm_afsk1200_rx
=
{
"afsk1200"
,
sizeof
(
struct
demod_state_afsk12
),
AFSK12_SAMPLE_RATE
,
1200
,
8
,
AFSK12_SAMPLE_RATE
/
1200
,
demodulator_1200_u8
,
demodulator_1200_s16
,
demod_init_1200
};
/* --------------------------------------------------------------------- */
drivers/net/hamradio/soundmodem/sm_afsk2400_7.c
deleted
100644 → 0
View file @
a994c542
/*****************************************************************************/
/*
* sm_afsk2400_7.c -- soundcard radio modem driver, 2400 baud AFSK modem
*
* 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.
*
*/
/*
* This driver is intended to be compatible with TCM3105 modems
* overclocked to 7.3728MHz. The mark and space frequencies therefore
* lie at 3658 and 1996 Hz.
* Note that I do _not_ recommend the building of such links, I provide
* this only for the users who live in the coverage area of such
* a "legacy" link.
*/
#include "sm.h"
#include "sm_tbl_afsk2400_7.h"
/* --------------------------------------------------------------------- */
struct
demod_state_afsk24
{
unsigned
int
shreg
;
unsigned
int
bit_pll
;
unsigned
char
last_sample
;
unsigned
int
dcd_shreg
;
int
dcd_sum0
,
dcd_sum1
,
dcd_sum2
;
unsigned
int
dcd_time
;
unsigned
char
last_rxbit
;
};
struct
mod_state_afsk24
{
unsigned
int
shreg
;
unsigned
char
tx_bit
;
unsigned
int
bit_pll
;
unsigned
int
tx_seq
;
unsigned
int
phinc
;
};
/* --------------------------------------------------------------------- */
static
const
int
dds_inc
[
2
]
=
{
AFSK24_TX_FREQ_LO
*
0x10000
/
AFSK24_SAMPLERATE
,
AFSK24_TX_FREQ_HI
*
0x10000
/
AFSK24_SAMPLERATE
};
static
void
modulator_2400_u8
(
struct
sm_state
*
sm
,
unsigned
char
*
buf
,
unsigned
int
buflen
)
{
struct
mod_state_afsk24
*
st
=
(
struct
mod_state_afsk24
*
)(
&
sm
->
m
);
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
if
(
st
->
tx_seq
<
0x5555
)
{
if
(
st
->
shreg
<=
1
)
st
->
shreg
=
hdlcdrv_getbits
(
&
sm
->
hdrv
)
|
0x10000
;
st
->
tx_bit
=
(
st
->
tx_bit
^
(
!
(
st
->
shreg
&
1
)))
&
1
;
st
->
shreg
>>=
1
;
st
->
phinc
=
dds_inc
[
st
->
tx_bit
&
1
];
}
st
->
tx_seq
+=
0x5555
;
st
->
tx_seq
&=
0xffff
;
*
buf
=
OFFSCOS
(
st
->
bit_pll
);
st
->
bit_pll
+=
st
->
phinc
;
}
}
/* --------------------------------------------------------------------- */
static
void
modulator_2400_s16
(
struct
sm_state
*
sm
,
short
*
buf
,
unsigned
int
buflen
)
{
struct
mod_state_afsk24
*
st
=
(
struct
mod_state_afsk24
*
)(
&
sm
->
m
);
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
if
(
st
->
tx_seq
<
0x5555
)
{
if
(
st
->
shreg
<=
1
)
st
->
shreg
=
hdlcdrv_getbits
(
&
sm
->
hdrv
)
|
0x10000
;
st
->
tx_bit
=
(
st
->
tx_bit
^
(
!
(
st
->
shreg
&
1
)))
&
1
;
st
->
shreg
>>=
1
;
st
->
phinc
=
dds_inc
[
st
->
tx_bit
&
1
];
}
st
->
tx_seq
+=
0x5555
;
st
->
tx_seq
&=
0xffff
;
*
buf
=
COS
(
st
->
bit_pll
);
st
->
bit_pll
+=
st
->
phinc
;
}
}
/* --------------------------------------------------------------------- */
static
__inline__
int
convolution14_u8
(
const
unsigned
char
*
st
,
const
int
*
coeff
,
int
csum
)
{
int
sum
=
-
0x80
*
csum
;
sum
+=
(
st
[
0
]
*
coeff
[
0
]);
sum
+=
(
st
[
-
1
]
*
coeff
[
1
]);
sum
+=
(
st
[
-
2
]
*
coeff
[
2
]);
sum
+=
(
st
[
-
3
]
*
coeff
[
3
]);
sum
+=
(
st
[
-
4
]
*
coeff
[
4
]);
sum
+=
(
st
[
-
5
]
*
coeff
[
5
]);
sum
+=
(
st
[
-
6
]
*
coeff
[
6
]);
sum
+=
(
st
[
-
7
]
*
coeff
[
7
]);
sum
+=
(
st
[
-
8
]
*
coeff
[
8
]);
sum
+=
(
st
[
-
9
]
*
coeff
[
9
]);
sum
+=
(
st
[
-
10
]
*
coeff
[
10
]);
sum
+=
(
st
[
-
11
]
*
coeff
[
11
]);
sum
+=
(
st
[
-
12
]
*
coeff
[
12
]);
sum
+=
(
st
[
-
13
]
*
coeff
[
13
]);
sum
>>=
7
;
return
sum
*
sum
;
}
static
__inline__
int
convolution14_s16
(
const
short
*
st
,
const
int
*
coeff
,
int
csum
)
{
int
sum
=
0
;
sum
+=
(
st
[
0
]
*
coeff
[
0
]);
sum
+=
(
st
[
-
1
]
*
coeff
[
1
]);
sum
+=
(
st
[
-
2
]
*
coeff
[
2
]);
sum
+=
(
st
[
-
3
]
*
coeff
[
3
]);
sum
+=
(
st
[
-
4
]
*
coeff
[
4
]);
sum
+=
(
st
[
-
5
]
*
coeff
[
5
]);
sum
+=
(
st
[
-
6
]
*
coeff
[
6
]);
sum
+=
(
st
[
-
7
]
*
coeff
[
7
]);
sum
+=
(
st
[
-
8
]
*
coeff
[
8
]);
sum
+=
(
st
[
-
9
]
*
coeff
[
9
]);
sum
+=
(
st
[
-
10
]
*
coeff
[
10
]);
sum
+=
(
st
[
-
11
]
*
coeff
[
11
]);
sum
+=
(
st
[
-
12
]
*
coeff
[
12
]);
sum
+=
(
st
[
-
13
]
*
coeff
[
13
]);
sum
>>=
15
;
return
sum
*
sum
;
}
static
__inline__
int
do_filter_2400_u8
(
const
unsigned
char
*
buf
)
{
int
sum
=
convolution14_u8
(
buf
,
afsk24_tx_lo_i
,
SUM_AFSK24_TX_LO_I
);
sum
+=
convolution14_u8
(
buf
,
afsk24_tx_lo_q
,
SUM_AFSK24_TX_LO_Q
);
sum
-=
convolution14_u8
(
buf
,
afsk24_tx_hi_i
,
SUM_AFSK24_TX_HI_I
);
sum
-=
convolution14_u8
(
buf
,
afsk24_tx_hi_q
,
SUM_AFSK24_TX_HI_Q
);
return
sum
;
}
static
__inline__
int
do_filter_2400_s16
(
const
short
*
buf
)
{
int
sum
=
convolution14_s16
(
buf
,
afsk24_tx_lo_i
,
SUM_AFSK24_TX_LO_I
);
sum
+=
convolution14_s16
(
buf
,
afsk24_tx_lo_q
,
SUM_AFSK24_TX_LO_Q
);
sum
-=
convolution14_s16
(
buf
,
afsk24_tx_hi_i
,
SUM_AFSK24_TX_HI_I
);
sum
-=
convolution14_s16
(
buf
,
afsk24_tx_hi_q
,
SUM_AFSK24_TX_HI_Q
);
return
sum
;
}
/* --------------------------------------------------------------------- */
static
void
demodulator_2400_u8
(
struct
sm_state
*
sm
,
const
unsigned
char
*
buf
,
unsigned
int
buflen
)
{
struct
demod_state_afsk24
*
st
=
(
struct
demod_state_afsk24
*
)(
&
sm
->
d
);
int
j
;
int
sum
;
unsigned
char
newsample
;
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
sum
=
do_filter_2400_u8
(
buf
);
st
->
dcd_shreg
<<=
1
;
st
->
bit_pll
+=
AFSK24_BITPLL_INC
;
newsample
=
(
sum
>
0
);
if
(
st
->
last_sample
^
newsample
)
{
st
->
last_sample
=
newsample
;
st
->
dcd_shreg
|=
1
;
if
(
st
->
bit_pll
<
(
0x8000
+
AFSK24_BITPLL_INC
/
2
))
st
->
bit_pll
+=
AFSK24_BITPLL_INC
/
2
;
else
st
->
bit_pll
-=
AFSK24_BITPLL_INC
/
2
;
j
=
/* 2 * */
hweight8
(
st
->
dcd_shreg
&
0x1c
)
-
hweight16
(
st
->
dcd_shreg
&
0x1e0
);
st
->
dcd_sum0
+=
j
;
}
hdlcdrv_channelbit
(
&
sm
->
hdrv
,
st
->
last_sample
);
if
((
--
st
->
dcd_time
)
<=
0
)
{
hdlcdrv_setdcd
(
&
sm
->
hdrv
,
(
st
->
dcd_sum0
+
st
->
dcd_sum1
+
st
->
dcd_sum2
)
<
0
);
st
->
dcd_sum2
=
st
->
dcd_sum1
;
st
->
dcd_sum1
=
st
->
dcd_sum0
;
st
->
dcd_sum0
=
2
;
/* slight bias */
st
->
dcd_time
=
120
;
}
if
(
st
->
bit_pll
>=
0x10000
)
{
st
->
bit_pll
&=
0xffff
;
st
->
shreg
>>=
1
;
st
->
shreg
|=
(
!
(
st
->
last_rxbit
^
st
->
last_sample
))
<<
16
;
st
->
last_rxbit
=
st
->
last_sample
;
diag_trigger
(
sm
);
if
(
st
->
shreg
&
1
)
{
hdlcdrv_putbits
(
&
sm
->
hdrv
,
st
->
shreg
>>
1
);
st
->
shreg
=
0x10000
;
}
}
diag_add
(
sm
,
(((
int
)
*
buf
)
-
0x80
)
<<
8
,
sum
);
}
}
/* --------------------------------------------------------------------- */
static
void
demodulator_2400_s16
(
struct
sm_state
*
sm
,
const
short
*
buf
,
unsigned
int
buflen
)
{
struct
demod_state_afsk24
*
st
=
(
struct
demod_state_afsk24
*
)(
&
sm
->
d
);
int
j
;
int
sum
;
unsigned
char
newsample
;
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
sum
=
do_filter_2400_s16
(
buf
);
st
->
dcd_shreg
<<=
1
;
st
->
bit_pll
+=
AFSK24_BITPLL_INC
;
newsample
=
(
sum
>
0
);
if
(
st
->
last_sample
^
newsample
)
{
st
->
last_sample
=
newsample
;
st
->
dcd_shreg
|=
1
;
if
(
st
->
bit_pll
<
(
0x8000
+
AFSK24_BITPLL_INC
/
2
))
st
->
bit_pll
+=
AFSK24_BITPLL_INC
/
2
;
else
st
->
bit_pll
-=
AFSK24_BITPLL_INC
/
2
;
j
=
/* 2 * */
hweight8
(
st
->
dcd_shreg
&
0x1c
)
-
hweight16
(
st
->
dcd_shreg
&
0x1e0
);
st
->
dcd_sum0
+=
j
;
}
hdlcdrv_channelbit
(
&
sm
->
hdrv
,
st
->
last_sample
);
if
((
--
st
->
dcd_time
)
<=
0
)
{
hdlcdrv_setdcd
(
&
sm
->
hdrv
,
(
st
->
dcd_sum0
+
st
->
dcd_sum1
+
st
->
dcd_sum2
)
<
0
);
st
->
dcd_sum2
=
st
->
dcd_sum1
;
st
->
dcd_sum1
=
st
->
dcd_sum0
;
st
->
dcd_sum0
=
2
;
/* slight bias */
st
->
dcd_time
=
120
;
}
if
(
st
->
bit_pll
>=
0x10000
)
{
st
->
bit_pll
&=
0xffff
;
st
->
shreg
>>=
1
;
st
->
shreg
|=
(
!
(
st
->
last_rxbit
^
st
->
last_sample
))
<<
16
;
st
->
last_rxbit
=
st
->
last_sample
;
diag_trigger
(
sm
);
if
(
st
->
shreg
&
1
)
{
hdlcdrv_putbits
(
&
sm
->
hdrv
,
st
->
shreg
>>
1
);
st
->
shreg
=
0x10000
;
}
}
diag_add
(
sm
,
*
buf
,
sum
);
}
}
/* --------------------------------------------------------------------- */
static
void
demod_init_2400
(
struct
sm_state
*
sm
)
{
struct
demod_state_afsk24
*
st
=
(
struct
demod_state_afsk24
*
)(
&
sm
->
d
);
st
->
dcd_time
=
120
;
st
->
dcd_sum0
=
2
;
}
/* --------------------------------------------------------------------- */
const
struct
modem_tx_info
sm_afsk2400_7_tx
=
{
"afsk2400_7"
,
sizeof
(
struct
mod_state_afsk24
),
AFSK24_SAMPLERATE
,
2400
,
modulator_2400_u8
,
modulator_2400_s16
,
NULL
};
const
struct
modem_rx_info
sm_afsk2400_7_rx
=
{
"afsk2400_7"
,
sizeof
(
struct
demod_state_afsk24
),
AFSK24_SAMPLERATE
,
2400
,
14
,
AFSK24_SAMPLERATE
/
2400
,
demodulator_2400_u8
,
demodulator_2400_s16
,
demod_init_2400
};
/* --------------------------------------------------------------------- */
drivers/net/hamradio/soundmodem/sm_afsk2400_8.c
deleted
100644 → 0
View file @
a994c542
/*****************************************************************************/
/*
* sm_afsk2400_8.c -- soundcard radio modem driver, 2400 baud AFSK modem
*
* 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.
*
*/
/*
* This driver is intended to be compatible with TCM3105 modems
* overclocked to 8MHz. The mark and space frequencies therefore
* lie at 3970 and 2165 Hz.
* Note that I do _not_ recommend the building of such links, I provide
* this only for the users who live in the coverage area of such
* a "legacy" link.
*/
#include "sm.h"
#include "sm_tbl_afsk2400_8.h"
/* --------------------------------------------------------------------- */
struct
demod_state_afsk24
{
unsigned
int
shreg
;
unsigned
int
bit_pll
;
unsigned
char
last_sample
;
unsigned
int
dcd_shreg
;
int
dcd_sum0
,
dcd_sum1
,
dcd_sum2
;
unsigned
int
dcd_time
;
unsigned
char
last_rxbit
;
};
struct
mod_state_afsk24
{
unsigned
int
shreg
;
unsigned
char
tx_bit
;
unsigned
int
bit_pll
;
unsigned
int
tx_seq
;
unsigned
int
phinc
;
};
/* --------------------------------------------------------------------- */
static
const
int
dds_inc
[
2
]
=
{
AFSK24_TX_FREQ_LO
*
0x10000
/
AFSK24_SAMPLERATE
,
AFSK24_TX_FREQ_HI
*
0x10000
/
AFSK24_SAMPLERATE
};
static
void
modulator_2400_u8
(
struct
sm_state
*
sm
,
unsigned
char
*
buf
,
unsigned
int
buflen
)
{
struct
mod_state_afsk24
*
st
=
(
struct
mod_state_afsk24
*
)(
&
sm
->
m
);
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
if
(
st
->
tx_seq
<
0x5555
)
{
if
(
st
->
shreg
<=
1
)
st
->
shreg
=
hdlcdrv_getbits
(
&
sm
->
hdrv
)
|
0x10000
;
st
->
tx_bit
=
(
st
->
tx_bit
^
(
!
(
st
->
shreg
&
1
)))
&
1
;
st
->
shreg
>>=
1
;
st
->
phinc
=
dds_inc
[
st
->
tx_bit
&
1
];
}
st
->
tx_seq
+=
0x5555
;
st
->
tx_seq
&=
0xffff
;
*
buf
=
OFFSCOS
(
st
->
bit_pll
);
st
->
bit_pll
+=
st
->
phinc
;
}
}
/* --------------------------------------------------------------------- */
static
void
modulator_2400_s16
(
struct
sm_state
*
sm
,
short
*
buf
,
unsigned
int
buflen
)
{
struct
mod_state_afsk24
*
st
=
(
struct
mod_state_afsk24
*
)(
&
sm
->
m
);
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
if
(
st
->
tx_seq
<
0x5555
)
{
if
(
st
->
shreg
<=
1
)
st
->
shreg
=
hdlcdrv_getbits
(
&
sm
->
hdrv
)
|
0x10000
;
st
->
tx_bit
=
(
st
->
tx_bit
^
(
!
(
st
->
shreg
&
1
)))
&
1
;
st
->
shreg
>>=
1
;
st
->
phinc
=
dds_inc
[
st
->
tx_bit
&
1
];
}
st
->
tx_seq
+=
0x5555
;
st
->
tx_seq
&=
0xffff
;
*
buf
=
COS
(
st
->
bit_pll
);
st
->
bit_pll
+=
st
->
phinc
;
}
}
/* --------------------------------------------------------------------- */
static
__inline__
int
convolution14_u8
(
const
unsigned
char
*
st
,
const
int
*
coeff
,
int
csum
)
{
int
sum
=
-
0x80
*
csum
;
sum
+=
(
st
[
0
]
*
coeff
[
0
]);
sum
+=
(
st
[
-
1
]
*
coeff
[
1
]);
sum
+=
(
st
[
-
2
]
*
coeff
[
2
]);
sum
+=
(
st
[
-
3
]
*
coeff
[
3
]);
sum
+=
(
st
[
-
4
]
*
coeff
[
4
]);
sum
+=
(
st
[
-
5
]
*
coeff
[
5
]);
sum
+=
(
st
[
-
6
]
*
coeff
[
6
]);
sum
+=
(
st
[
-
7
]
*
coeff
[
7
]);
sum
+=
(
st
[
-
8
]
*
coeff
[
8
]);
sum
+=
(
st
[
-
9
]
*
coeff
[
9
]);
sum
+=
(
st
[
-
10
]
*
coeff
[
10
]);
sum
+=
(
st
[
-
11
]
*
coeff
[
11
]);
sum
+=
(
st
[
-
12
]
*
coeff
[
12
]);
sum
+=
(
st
[
-
13
]
*
coeff
[
13
]);
sum
>>=
7
;
return
sum
*
sum
;
}
static
__inline__
int
convolution14_s16
(
const
short
*
st
,
const
int
*
coeff
,
int
csum
)
{
int
sum
=
0
;
sum
+=
(
st
[
0
]
*
coeff
[
0
]);
sum
+=
(
st
[
-
1
]
*
coeff
[
1
]);
sum
+=
(
st
[
-
2
]
*
coeff
[
2
]);
sum
+=
(
st
[
-
3
]
*
coeff
[
3
]);
sum
+=
(
st
[
-
4
]
*
coeff
[
4
]);
sum
+=
(
st
[
-
5
]
*
coeff
[
5
]);
sum
+=
(
st
[
-
6
]
*
coeff
[
6
]);
sum
+=
(
st
[
-
7
]
*
coeff
[
7
]);
sum
+=
(
st
[
-
8
]
*
coeff
[
8
]);
sum
+=
(
st
[
-
9
]
*
coeff
[
9
]);
sum
+=
(
st
[
-
10
]
*
coeff
[
10
]);
sum
+=
(
st
[
-
11
]
*
coeff
[
11
]);
sum
+=
(
st
[
-
12
]
*
coeff
[
12
]);
sum
+=
(
st
[
-
13
]
*
coeff
[
13
]);
sum
>>=
15
;
return
sum
*
sum
;
}
static
__inline__
int
do_filter_2400_u8
(
const
unsigned
char
*
buf
)
{
int
sum
=
convolution14_u8
(
buf
,
afsk24_tx_lo_i
,
SUM_AFSK24_TX_LO_I
);
sum
+=
convolution14_u8
(
buf
,
afsk24_tx_lo_q
,
SUM_AFSK24_TX_LO_Q
);
sum
-=
convolution14_u8
(
buf
,
afsk24_tx_hi_i
,
SUM_AFSK24_TX_HI_I
);
sum
-=
convolution14_u8
(
buf
,
afsk24_tx_hi_q
,
SUM_AFSK24_TX_HI_Q
);
return
sum
;
}
static
__inline__
int
do_filter_2400_s16
(
const
short
*
buf
)
{
int
sum
=
convolution14_s16
(
buf
,
afsk24_tx_lo_i
,
SUM_AFSK24_TX_LO_I
);
sum
+=
convolution14_s16
(
buf
,
afsk24_tx_lo_q
,
SUM_AFSK24_TX_LO_Q
);
sum
-=
convolution14_s16
(
buf
,
afsk24_tx_hi_i
,
SUM_AFSK24_TX_HI_I
);
sum
-=
convolution14_s16
(
buf
,
afsk24_tx_hi_q
,
SUM_AFSK24_TX_HI_Q
);
return
sum
;
}
/* --------------------------------------------------------------------- */
static
void
demodulator_2400_u8
(
struct
sm_state
*
sm
,
const
unsigned
char
*
buf
,
unsigned
int
buflen
)
{
struct
demod_state_afsk24
*
st
=
(
struct
demod_state_afsk24
*
)(
&
sm
->
d
);
int
j
;
int
sum
;
unsigned
char
newsample
;
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
sum
=
do_filter_2400_u8
(
buf
);
st
->
dcd_shreg
<<=
1
;
st
->
bit_pll
+=
AFSK24_BITPLL_INC
;
newsample
=
(
sum
>
0
);
if
(
st
->
last_sample
^
newsample
)
{
st
->
last_sample
=
newsample
;
st
->
dcd_shreg
|=
1
;
if
(
st
->
bit_pll
<
(
0x8000
+
AFSK24_BITPLL_INC
/
2
))
st
->
bit_pll
+=
AFSK24_BITPLL_INC
/
2
;
else
st
->
bit_pll
-=
AFSK24_BITPLL_INC
/
2
;
j
=
/* 2 * */
hweight8
(
st
->
dcd_shreg
&
0x1c
)
-
hweight16
(
st
->
dcd_shreg
&
0x1e0
);
st
->
dcd_sum0
+=
j
;
}
hdlcdrv_channelbit
(
&
sm
->
hdrv
,
st
->
last_sample
);
if
((
--
st
->
dcd_time
)
<=
0
)
{
hdlcdrv_setdcd
(
&
sm
->
hdrv
,
(
st
->
dcd_sum0
+
st
->
dcd_sum1
+
st
->
dcd_sum2
)
<
0
);
st
->
dcd_sum2
=
st
->
dcd_sum1
;
st
->
dcd_sum1
=
st
->
dcd_sum0
;
st
->
dcd_sum0
=
2
;
/* slight bias */
st
->
dcd_time
=
120
;
}
if
(
st
->
bit_pll
>=
0x10000
)
{
st
->
bit_pll
&=
0xffff
;
st
->
shreg
>>=
1
;
st
->
shreg
|=
(
!
(
st
->
last_rxbit
^
st
->
last_sample
))
<<
16
;
st
->
last_rxbit
=
st
->
last_sample
;
diag_trigger
(
sm
);
if
(
st
->
shreg
&
1
)
{
hdlcdrv_putbits
(
&
sm
->
hdrv
,
st
->
shreg
>>
1
);
st
->
shreg
=
0x10000
;
}
}
diag_add
(
sm
,
(((
int
)
*
buf
)
-
0x80
)
<<
8
,
sum
);
}
}
/* --------------------------------------------------------------------- */
static
void
demodulator_2400_s16
(
struct
sm_state
*
sm
,
const
short
*
buf
,
unsigned
int
buflen
)
{
struct
demod_state_afsk24
*
st
=
(
struct
demod_state_afsk24
*
)(
&
sm
->
d
);
int
j
;
int
sum
;
unsigned
char
newsample
;
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
sum
=
do_filter_2400_s16
(
buf
);
st
->
dcd_shreg
<<=
1
;
st
->
bit_pll
+=
AFSK24_BITPLL_INC
;
newsample
=
(
sum
>
0
);
if
(
st
->
last_sample
^
newsample
)
{
st
->
last_sample
=
newsample
;
st
->
dcd_shreg
|=
1
;
if
(
st
->
bit_pll
<
(
0x8000
+
AFSK24_BITPLL_INC
/
2
))
st
->
bit_pll
+=
AFSK24_BITPLL_INC
/
2
;
else
st
->
bit_pll
-=
AFSK24_BITPLL_INC
/
2
;
j
=
/* 2 * */
hweight8
(
st
->
dcd_shreg
&
0x1c
)
-
hweight16
(
st
->
dcd_shreg
&
0x1e0
);
st
->
dcd_sum0
+=
j
;
}
hdlcdrv_channelbit
(
&
sm
->
hdrv
,
st
->
last_sample
);
if
((
--
st
->
dcd_time
)
<=
0
)
{
hdlcdrv_setdcd
(
&
sm
->
hdrv
,
(
st
->
dcd_sum0
+
st
->
dcd_sum1
+
st
->
dcd_sum2
)
<
0
);
st
->
dcd_sum2
=
st
->
dcd_sum1
;
st
->
dcd_sum1
=
st
->
dcd_sum0
;
st
->
dcd_sum0
=
2
;
/* slight bias */
st
->
dcd_time
=
120
;
}
if
(
st
->
bit_pll
>=
0x10000
)
{
st
->
bit_pll
&=
0xffff
;
st
->
shreg
>>=
1
;
st
->
shreg
|=
(
!
(
st
->
last_rxbit
^
st
->
last_sample
))
<<
16
;
st
->
last_rxbit
=
st
->
last_sample
;
diag_trigger
(
sm
);
if
(
st
->
shreg
&
1
)
{
hdlcdrv_putbits
(
&
sm
->
hdrv
,
st
->
shreg
>>
1
);
st
->
shreg
=
0x10000
;
}
}
diag_add
(
sm
,
*
buf
,
sum
);
}
}
/* --------------------------------------------------------------------- */
static
void
demod_init_2400
(
struct
sm_state
*
sm
)
{
struct
demod_state_afsk24
*
st
=
(
struct
demod_state_afsk24
*
)(
&
sm
->
d
);
st
->
dcd_time
=
120
;
st
->
dcd_sum0
=
2
;
}
/* --------------------------------------------------------------------- */
const
struct
modem_tx_info
sm_afsk2400_8_tx
=
{
"afsk2400_8"
,
sizeof
(
struct
mod_state_afsk24
),
AFSK24_SAMPLERATE
,
2400
,
modulator_2400_u8
,
modulator_2400_s16
,
NULL
};
const
struct
modem_rx_info
sm_afsk2400_8_rx
=
{
"afsk2400_8"
,
sizeof
(
struct
demod_state_afsk24
),
AFSK24_SAMPLERATE
,
2400
,
14
,
AFSK24_SAMPLERATE
/
2400
,
demodulator_2400_u8
,
demodulator_2400_s16
,
demod_init_2400
};
/* --------------------------------------------------------------------- */
drivers/net/hamradio/soundmodem/sm_afsk2666.c
deleted
100644 → 0
View file @
a994c542
/*****************************************************************************/
/*
* sm_afsk2666.c -- soundcard radio modem driver, 2666 baud AFSK modem
*
* Copyright (C) 1997 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.
*
*/
#include "sm.h"
#include "sm_tbl_afsk2666.h"
/* --------------------------------------------------------------------- */
struct
demod_state_afsk26
{
unsigned
int
shreg
;
unsigned
long
descram
;
int
dem_sum
[
8
];
int
dem_sum_mean
;
int
dem_cnt
;
unsigned
int
bit_pll
;
unsigned
char
last_sample
;
unsigned
int
dcd_shreg
;
int
dcd_sum0
,
dcd_sum1
,
dcd_sum2
;
unsigned
int
dcd_time
;
};
struct
mod_state_afsk26
{
unsigned
int
shreg
;
unsigned
long
scram
;
unsigned
int
bit_pll
;
unsigned
int
phinc
;
unsigned
int
tx_seq
;
};
/* --------------------------------------------------------------------- */
#define DESCRAM_TAP1 0x20000
#define DESCRAM_TAP2 0x01000
#define DESCRAM_TAP3 0x00001
#define DESCRAM_TAPSH1 17
#define DESCRAM_TAPSH2 12
#define DESCRAM_TAPSH3 0
#define SCRAM_TAP1 0x20000
/* X^17 */
#define SCRAM_TAPN 0x00021
/* X^0+X^5 */
/* --------------------------------------------------------------------- */
static
void
modulator_2666_u8
(
struct
sm_state
*
sm
,
unsigned
char
*
buf
,
unsigned
int
buflen
)
{
struct
mod_state_afsk26
*
st
=
(
struct
mod_state_afsk26
*
)(
&
sm
->
m
);
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
if
(
!
st
->
tx_seq
++
)
{
if
(
st
->
shreg
<=
1
)
st
->
shreg
=
hdlcdrv_getbits
(
&
sm
->
hdrv
)
|
0x10000
;
st
->
scram
=
((
st
->
scram
<<
1
)
|
(
st
->
scram
&
1
));
st
->
scram
^=
(
!
(
st
->
shreg
&
1
));
st
->
shreg
>>=
1
;
if
(
st
->
scram
&
(
SCRAM_TAP1
<<
1
))
st
->
scram
^=
SCRAM_TAPN
<<
1
;
st
->
phinc
=
afsk26_carfreq
[
!
(
st
->
scram
&
(
SCRAM_TAP1
<<
2
))];
}
if
(
st
->
tx_seq
>=
6
)
st
->
tx_seq
=
0
;
*
buf
=
OFFSCOS
(
st
->
bit_pll
);
st
->
bit_pll
+=
st
->
phinc
;
}
}
/* --------------------------------------------------------------------- */
static
void
modulator_2666_s16
(
struct
sm_state
*
sm
,
short
*
buf
,
unsigned
int
buflen
)
{
struct
mod_state_afsk26
*
st
=
(
struct
mod_state_afsk26
*
)(
&
sm
->
m
);
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
if
(
!
st
->
tx_seq
++
)
{
if
(
st
->
shreg
<=
1
)
st
->
shreg
=
hdlcdrv_getbits
(
&
sm
->
hdrv
)
|
0x10000
;
st
->
scram
=
((
st
->
scram
<<
1
)
|
(
st
->
scram
&
1
));
st
->
scram
^=
(
!
(
st
->
shreg
&
1
));
st
->
shreg
>>=
1
;
if
(
st
->
scram
&
(
SCRAM_TAP1
<<
1
))
st
->
scram
^=
SCRAM_TAPN
<<
1
;
st
->
phinc
=
afsk26_carfreq
[
!
(
st
->
scram
&
(
SCRAM_TAP1
<<
2
))];
}
if
(
st
->
tx_seq
>=
6
)
st
->
tx_seq
=
0
;
*
buf
=
COS
(
st
->
bit_pll
);
st
->
bit_pll
+=
st
->
phinc
;
}
}
/* --------------------------------------------------------------------- */
static
__inline__
int
convolution12_u8
(
const
unsigned
char
*
st
,
const
int
*
coeff
,
int
csum
)
{
int
sum
=
-
0x80
*
csum
;
sum
+=
(
st
[
0
]
*
coeff
[
0
]);
sum
+=
(
st
[
-
1
]
*
coeff
[
1
]);
sum
+=
(
st
[
-
2
]
*
coeff
[
2
]);
sum
+=
(
st
[
-
3
]
*
coeff
[
3
]);
sum
+=
(
st
[
-
4
]
*
coeff
[
4
]);
sum
+=
(
st
[
-
5
]
*
coeff
[
5
]);
sum
+=
(
st
[
-
6
]
*
coeff
[
6
]);
sum
+=
(
st
[
-
7
]
*
coeff
[
7
]);
sum
+=
(
st
[
-
8
]
*
coeff
[
8
]);
sum
+=
(
st
[
-
9
]
*
coeff
[
9
]);
sum
+=
(
st
[
-
10
]
*
coeff
[
10
]);
sum
+=
(
st
[
-
11
]
*
coeff
[
11
]);
return
sum
;
}
static
__inline__
int
convolution12_s16
(
const
short
*
st
,
const
int
*
coeff
,
int
csum
)
{
int
sum
=
0
;
sum
+=
(
st
[
0
]
*
coeff
[
0
]);
sum
+=
(
st
[
-
1
]
*
coeff
[
1
]);
sum
+=
(
st
[
-
2
]
*
coeff
[
2
]);
sum
+=
(
st
[
-
3
]
*
coeff
[
3
]);
sum
+=
(
st
[
-
4
]
*
coeff
[
4
]);
sum
+=
(
st
[
-
5
]
*
coeff
[
5
]);
sum
+=
(
st
[
-
6
]
*
coeff
[
6
]);
sum
+=
(
st
[
-
7
]
*
coeff
[
7
]);
sum
+=
(
st
[
-
8
]
*
coeff
[
8
]);
sum
+=
(
st
[
-
9
]
*
coeff
[
9
]);
sum
+=
(
st
[
-
10
]
*
coeff
[
10
]);
sum
+=
(
st
[
-
11
]
*
coeff
[
11
]);
sum
>>=
8
;
return
sum
;
}
/* ---------------------------------------------------------------------- */
#if 0
static int binexp(unsigned int i)
{
int ret = 31;
if (!i)
return 0;
if (i < 0x10000LU) {
i <<= 16;
ret -= 16;
}
if (i < 0x1000000LU) {
i <<= 8;
ret -= 8;
}
if (i < 0x10000000LU) {
i <<= 4;
ret -= 4;
}
if (i < 0x40000000LU) {
i <<= 2;
ret -= 2;
}
if (i < 0x80000000LU)
ret -= 1;
return ret;
}
static const sqrt_tab[16] = {
00000, 16384, 23170, 28378, 32768, 36636, 40132, 43348,
46341, 49152, 51811, 54340, 56756, 59073, 61303, 63455
};
static unsigned int int_sqrt_approx(unsigned int i)
{
unsigned int j;
if (i < 16)
return sqrt_tab[i] >> 14;
j = binexp(i) >> 1;
i >>= (j * 2 - 2);
return (sqrt_tab[i & 0xf] << j) >> 15;
}
#endif
/* --------------------------------------------------------------------- */
extern
unsigned
int
est_pwr
(
int
i
,
int
q
)
{
unsigned
int
ui
=
abs
(
i
);
unsigned
int
uq
=
abs
(
q
);
if
(
uq
>
ui
)
{
unsigned
int
tmp
;
tmp
=
ui
;
ui
=
uq
;
uq
=
tmp
;
}
if
(
uq
>
(
ui
>>
1
))
return
7
*
(
ui
>>
3
)
+
9
*
(
uq
>>
4
);
else
return
ui
+
(
uq
>>
2
);
}
/* --------------------------------------------------------------------- */
static
void
demod_one_sample
(
struct
sm_state
*
sm
,
struct
demod_state_afsk26
*
st
,
int
curval
,
int
loi
,
int
loq
,
int
hii
,
int
hiq
)
{
static
const
int
pll_corr
[
2
]
=
{
-
0xa00
,
0xa00
};
unsigned
char
curbit
;
unsigned
int
descx
;
int
val
;
/*
* estimate power
*/
val
=
est_pwr
(
hii
,
hiq
)
-
est_pwr
(
loi
,
loq
);
/*
* estimate center value
*/
st
->
dem_sum
[
0
]
+=
val
>>
8
;
if
((
++
st
->
dem_cnt
)
>=
256
)
{
st
->
dem_cnt
=
0
;
st
->
dem_sum_mean
=
(
st
->
dem_sum
[
0
]
+
st
->
dem_sum
[
1
]
+
st
->
dem_sum
[
2
]
+
st
->
dem_sum
[
3
]
+
st
->
dem_sum
[
4
]
+
st
->
dem_sum
[
5
]
+
st
->
dem_sum
[
6
]
+
st
->
dem_sum
[
7
])
>>
3
;
memmove
(
st
->
dem_sum
+
1
,
st
->
dem_sum
,
sizeof
(
st
->
dem_sum
)
-
sizeof
(
st
->
dem_sum
[
0
]));
st
->
dem_sum
[
0
]
=
0
;
}
/*
* decision and bit clock regen
*/
val
-=
st
->
dem_sum_mean
;
diag_add
(
sm
,
curval
,
val
);
st
->
dcd_shreg
<<=
1
;
st
->
bit_pll
+=
0x1555
;
curbit
=
(
val
>
0
);
if
(
st
->
last_sample
^
curbit
)
{
st
->
dcd_shreg
|=
1
;
st
->
bit_pll
+=
pll_corr
[
st
->
bit_pll
<
(
0x8000
+
0x1555
)];
st
->
dcd_sum0
+=
4
*
hweight8
(
st
->
dcd_shreg
&
0x1e
)
-
hweight16
(
st
->
dcd_shreg
&
0xfe00
);
}
st
->
last_sample
=
curbit
;
hdlcdrv_channelbit
(
&
sm
->
hdrv
,
curbit
);
if
((
--
st
->
dcd_time
)
<=
0
)
{
hdlcdrv_setdcd
(
&
sm
->
hdrv
,
(
st
->
dcd_sum0
+
st
->
dcd_sum1
+
st
->
dcd_sum2
)
<
0
);
st
->
dcd_sum2
=
st
->
dcd_sum1
;
st
->
dcd_sum1
=
st
->
dcd_sum0
;
st
->
dcd_sum0
=
2
;
/* slight bias */
st
->
dcd_time
=
400
;
}
if
(
st
->
bit_pll
>=
0x10000
)
{
st
->
bit_pll
&=
0xffffu
;
st
->
descram
=
(
st
->
descram
<<
1
)
|
curbit
;
descx
=
st
->
descram
^
(
st
->
descram
>>
1
);
descx
^=
((
descx
>>
DESCRAM_TAPSH1
)
^
(
descx
>>
DESCRAM_TAPSH2
));
st
->
shreg
>>=
1
;
st
->
shreg
|=
(
!
(
descx
&
1
))
<<
16
;
if
(
st
->
shreg
&
1
)
{
hdlcdrv_putbits
(
&
sm
->
hdrv
,
st
->
shreg
>>
1
);
st
->
shreg
=
0x10000
;
}
diag_trigger
(
sm
);
}
}
/* --------------------------------------------------------------------- */
static
void
demodulator_2666_u8
(
struct
sm_state
*
sm
,
const
unsigned
char
*
buf
,
unsigned
int
buflen
)
{
struct
demod_state_afsk26
*
st
=
(
struct
demod_state_afsk26
*
)(
&
sm
->
d
);
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
demod_one_sample
(
sm
,
st
,
(
*
buf
-
0x80
)
<<
8
,
convolution12_u8
(
buf
,
afsk26_dem_tables
[
0
][
0
].
i
,
AFSK26_DEM_SUM_I_0_0
),
convolution12_u8
(
buf
,
afsk26_dem_tables
[
0
][
0
].
q
,
AFSK26_DEM_SUM_Q_0_0
),
convolution12_u8
(
buf
,
afsk26_dem_tables
[
0
][
1
].
i
,
AFSK26_DEM_SUM_I_0_1
),
convolution12_u8
(
buf
,
afsk26_dem_tables
[
0
][
1
].
q
,
AFSK26_DEM_SUM_Q_0_1
));
demod_one_sample
(
sm
,
st
,
(
*
buf
-
0x80
)
<<
8
,
convolution12_u8
(
buf
,
afsk26_dem_tables
[
1
][
0
].
i
,
AFSK26_DEM_SUM_I_1_0
),
convolution12_u8
(
buf
,
afsk26_dem_tables
[
1
][
0
].
q
,
AFSK26_DEM_SUM_Q_1_0
),
convolution12_u8
(
buf
,
afsk26_dem_tables
[
1
][
1
].
i
,
AFSK26_DEM_SUM_I_1_1
),
convolution12_u8
(
buf
,
afsk26_dem_tables
[
1
][
1
].
q
,
AFSK26_DEM_SUM_Q_1_1
));
}
}
/* --------------------------------------------------------------------- */
static
void
demodulator_2666_s16
(
struct
sm_state
*
sm
,
const
short
*
buf
,
unsigned
int
buflen
)
{
struct
demod_state_afsk26
*
st
=
(
struct
demod_state_afsk26
*
)(
&
sm
->
d
);
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
demod_one_sample
(
sm
,
st
,
*
buf
,
convolution12_s16
(
buf
,
afsk26_dem_tables
[
0
][
0
].
i
,
AFSK26_DEM_SUM_I_0_0
),
convolution12_s16
(
buf
,
afsk26_dem_tables
[
0
][
0
].
q
,
AFSK26_DEM_SUM_Q_0_0
),
convolution12_s16
(
buf
,
afsk26_dem_tables
[
0
][
1
].
i
,
AFSK26_DEM_SUM_I_0_1
),
convolution12_s16
(
buf
,
afsk26_dem_tables
[
0
][
1
].
q
,
AFSK26_DEM_SUM_Q_0_1
));
demod_one_sample
(
sm
,
st
,
*
buf
,
convolution12_s16
(
buf
,
afsk26_dem_tables
[
1
][
0
].
i
,
AFSK26_DEM_SUM_I_1_0
),
convolution12_s16
(
buf
,
afsk26_dem_tables
[
1
][
0
].
q
,
AFSK26_DEM_SUM_Q_1_0
),
convolution12_s16
(
buf
,
afsk26_dem_tables
[
1
][
1
].
i
,
AFSK26_DEM_SUM_I_1_1
),
convolution12_s16
(
buf
,
afsk26_dem_tables
[
1
][
1
].
q
,
AFSK26_DEM_SUM_Q_1_1
));
}
}
/* --------------------------------------------------------------------- */
static
void
demod_init_2666
(
struct
sm_state
*
sm
)
{
struct
demod_state_afsk26
*
st
=
(
struct
demod_state_afsk26
*
)(
&
sm
->
d
);
st
->
dcd_time
=
400
;
st
->
dcd_sum0
=
2
;
}
/* --------------------------------------------------------------------- */
const
struct
modem_tx_info
sm_afsk2666_tx
=
{
"afsk2666"
,
sizeof
(
struct
mod_state_afsk26
),
AFSK26_SAMPLERATE
,
2666
,
modulator_2666_u8
,
modulator_2666_s16
,
NULL
};
const
struct
modem_rx_info
sm_afsk2666_rx
=
{
"afsk2666"
,
sizeof
(
struct
demod_state_afsk26
),
AFSK26_SAMPLERATE
,
2666
,
12
,
6
,
demodulator_2666_u8
,
demodulator_2666_s16
,
demod_init_2666
};
/* --------------------------------------------------------------------- */
drivers/net/hamradio/soundmodem/sm_fsk9600.c
deleted
100644 → 0
View file @
a994c542
/*****************************************************************************/
/*
* sm_fsk9600.c -- soundcard radio modem driver,
* 9600 baud G3RUH compatible FSK modem
*
* 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.
*
*/
#include "sm.h"
#include "sm_tbl_fsk9600.h"
/* --------------------------------------------------------------------- */
struct
demod_state_fsk96
{
unsigned
int
shreg
;
unsigned
long
descram
;
unsigned
int
bit_pll
;
unsigned
char
last_sample
;
unsigned
int
dcd_shreg
;
int
dcd_sum0
,
dcd_sum1
,
dcd_sum2
;
unsigned
int
dcd_time
;
};
struct
mod_state_fsk96
{
unsigned
int
shreg
;
unsigned
long
scram
;
unsigned
char
tx_bit
;
unsigned
char
*
txtbl
;
unsigned
int
txphase
;
};
/* --------------------------------------------------------------------- */
#define DESCRAM_TAP1 0x20000
#define DESCRAM_TAP2 0x01000
#define DESCRAM_TAP3 0x00001
#define DESCRAM_TAPSH1 17
#define DESCRAM_TAPSH2 12
#define DESCRAM_TAPSH3 0
#define SCRAM_TAP1 0x20000
/* X^17 */
#define SCRAM_TAPN 0x00021
/* X^0+X^5 */
/* --------------------------------------------------------------------- */
static
void
modulator_9600_4_u8
(
struct
sm_state
*
sm
,
unsigned
char
*
buf
,
unsigned
int
buflen
)
{
struct
mod_state_fsk96
*
st
=
(
struct
mod_state_fsk96
*
)(
&
sm
->
m
);
for
(;
buflen
>
0
;
buflen
--
)
{
if
(
!
st
->
txphase
++
)
{
if
(
st
->
shreg
<=
1
)
st
->
shreg
=
hdlcdrv_getbits
(
&
sm
->
hdrv
)
|
0x10000
;
st
->
scram
=
(
st
->
scram
<<
1
)
|
(
st
->
scram
&
1
);
st
->
scram
^=
!
(
st
->
shreg
&
1
);
st
->
shreg
>>=
1
;
if
(
st
->
scram
&
(
SCRAM_TAP1
<<
1
))
st
->
scram
^=
SCRAM_TAPN
<<
1
;
st
->
tx_bit
=
(
st
->
tx_bit
<<
1
)
|
(
!!
(
st
->
scram
&
(
SCRAM_TAP1
<<
2
)));
st
->
txtbl
=
fsk96_txfilt_4
+
(
st
->
tx_bit
&
0xff
);
}
if
(
st
->
txphase
>=
4
)
st
->
txphase
=
0
;
*
buf
++
=
*
st
->
txtbl
;
st
->
txtbl
+=
0x100
;
}
}
/* --------------------------------------------------------------------- */
static
void
modulator_9600_4_s16
(
struct
sm_state
*
sm
,
short
*
buf
,
unsigned
int
buflen
)
{
struct
mod_state_fsk96
*
st
=
(
struct
mod_state_fsk96
*
)(
&
sm
->
m
);
for
(;
buflen
>
0
;
buflen
--
)
{
if
(
!
st
->
txphase
++
)
{
if
(
st
->
shreg
<=
1
)
st
->
shreg
=
hdlcdrv_getbits
(
&
sm
->
hdrv
)
|
0x10000
;
st
->
scram
=
(
st
->
scram
<<
1
)
|
(
st
->
scram
&
1
);
st
->
scram
^=
!
(
st
->
shreg
&
1
);
st
->
shreg
>>=
1
;
if
(
st
->
scram
&
(
SCRAM_TAP1
<<
1
))
st
->
scram
^=
SCRAM_TAPN
<<
1
;
st
->
tx_bit
=
(
st
->
tx_bit
<<
1
)
|
(
!!
(
st
->
scram
&
(
SCRAM_TAP1
<<
2
)));
st
->
txtbl
=
fsk96_txfilt_4
+
(
st
->
tx_bit
&
0xff
);
}
if
(
st
->
txphase
>=
4
)
st
->
txphase
=
0
;
*
buf
++
=
((
*
st
->
txtbl
)
-
0x80
)
<<
8
;
st
->
txtbl
+=
0x100
;
}
}
/* --------------------------------------------------------------------- */
static
void
demodulator_9600_4_u8
(
struct
sm_state
*
sm
,
const
unsigned
char
*
buf
,
unsigned
int
buflen
)
{
struct
demod_state_fsk96
*
st
=
(
struct
demod_state_fsk96
*
)(
&
sm
->
d
);
static
const
int
pll_corr
[
2
]
=
{
-
0x1000
,
0x1000
};
unsigned
char
curbit
;
unsigned
int
descx
;
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
st
->
dcd_shreg
<<=
1
;
st
->
bit_pll
+=
0x4000
;
curbit
=
(
*
buf
>=
0x80
);
if
(
st
->
last_sample
^
curbit
)
{
st
->
dcd_shreg
|=
1
;
st
->
bit_pll
+=
pll_corr
[
st
->
bit_pll
<
0xa000
];
st
->
dcd_sum0
+=
8
*
hweight8
(
st
->
dcd_shreg
&
0x0c
)
-
!!
(
st
->
dcd_shreg
&
0x10
);
}
st
->
last_sample
=
curbit
;
hdlcdrv_channelbit
(
&
sm
->
hdrv
,
st
->
last_sample
);
if
((
--
st
->
dcd_time
)
<=
0
)
{
hdlcdrv_setdcd
(
&
sm
->
hdrv
,
(
st
->
dcd_sum0
+
st
->
dcd_sum1
+
st
->
dcd_sum2
)
<
0
);
st
->
dcd_sum2
=
st
->
dcd_sum1
;
st
->
dcd_sum1
=
st
->
dcd_sum0
;
st
->
dcd_sum0
=
2
;
/* slight bias */
st
->
dcd_time
=
240
;
}
if
(
st
->
bit_pll
>=
0x10000
)
{
st
->
bit_pll
&=
0xffff
;
st
->
descram
=
(
st
->
descram
<<
1
)
|
curbit
;
descx
=
st
->
descram
^
(
st
->
descram
>>
1
);
descx
^=
((
descx
>>
DESCRAM_TAPSH1
)
^
(
descx
>>
DESCRAM_TAPSH2
));
st
->
shreg
>>=
1
;
st
->
shreg
|=
(
!
(
descx
&
1
))
<<
16
;
if
(
st
->
shreg
&
1
)
{
hdlcdrv_putbits
(
&
sm
->
hdrv
,
st
->
shreg
>>
1
);
st
->
shreg
=
0x10000
;
}
diag_trigger
(
sm
);
}
diag_add_one
(
sm
,
((
short
)(
*
buf
-
0x80
))
<<
8
);
}
}
/* --------------------------------------------------------------------- */
static
void
demodulator_9600_4_s16
(
struct
sm_state
*
sm
,
const
short
*
buf
,
unsigned
int
buflen
)
{
struct
demod_state_fsk96
*
st
=
(
struct
demod_state_fsk96
*
)(
&
sm
->
d
);
static
const
int
pll_corr
[
2
]
=
{
-
0x1000
,
0x1000
};
unsigned
char
curbit
;
unsigned
int
descx
;
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
st
->
dcd_shreg
<<=
1
;
st
->
bit_pll
+=
0x4000
;
curbit
=
(
*
buf
>=
0
);
if
(
st
->
last_sample
^
curbit
)
{
st
->
dcd_shreg
|=
1
;
st
->
bit_pll
+=
pll_corr
[
st
->
bit_pll
<
0xa000
];
st
->
dcd_sum0
+=
8
*
hweight8
(
st
->
dcd_shreg
&
0x0c
)
-
!!
(
st
->
dcd_shreg
&
0x10
);
}
st
->
last_sample
=
curbit
;
hdlcdrv_channelbit
(
&
sm
->
hdrv
,
st
->
last_sample
);
if
((
--
st
->
dcd_time
)
<=
0
)
{
hdlcdrv_setdcd
(
&
sm
->
hdrv
,
(
st
->
dcd_sum0
+
st
->
dcd_sum1
+
st
->
dcd_sum2
)
<
0
);
st
->
dcd_sum2
=
st
->
dcd_sum1
;
st
->
dcd_sum1
=
st
->
dcd_sum0
;
st
->
dcd_sum0
=
2
;
/* slight bias */
st
->
dcd_time
=
240
;
}
if
(
st
->
bit_pll
>=
0x10000
)
{
st
->
bit_pll
&=
0xffff
;
st
->
descram
=
(
st
->
descram
<<
1
)
|
curbit
;
descx
=
st
->
descram
^
(
st
->
descram
>>
1
);
descx
^=
((
descx
>>
DESCRAM_TAPSH1
)
^
(
descx
>>
DESCRAM_TAPSH2
));
st
->
shreg
>>=
1
;
st
->
shreg
|=
(
!
(
descx
&
1
))
<<
16
;
if
(
st
->
shreg
&
1
)
{
hdlcdrv_putbits
(
&
sm
->
hdrv
,
st
->
shreg
>>
1
);
st
->
shreg
=
0x10000
;
}
diag_trigger
(
sm
);
}
diag_add_one
(
sm
,
*
buf
);
}
}
/* --------------------------------------------------------------------- */
static
void
modulator_9600_5_u8
(
struct
sm_state
*
sm
,
unsigned
char
*
buf
,
unsigned
int
buflen
)
{
struct
mod_state_fsk96
*
st
=
(
struct
mod_state_fsk96
*
)(
&
sm
->
m
);
for
(;
buflen
>
0
;
buflen
--
)
{
if
(
!
st
->
txphase
++
)
{
if
(
st
->
shreg
<=
1
)
st
->
shreg
=
hdlcdrv_getbits
(
&
sm
->
hdrv
)
|
0x10000
;
st
->
scram
=
(
st
->
scram
<<
1
)
|
(
st
->
scram
&
1
);
st
->
scram
^=
!
(
st
->
shreg
&
1
);
st
->
shreg
>>=
1
;
if
(
st
->
scram
&
(
SCRAM_TAP1
<<
1
))
st
->
scram
^=
SCRAM_TAPN
<<
1
;
st
->
tx_bit
=
(
st
->
tx_bit
<<
1
)
|
(
!!
(
st
->
scram
&
(
SCRAM_TAP1
<<
2
)));
st
->
txtbl
=
fsk96_txfilt_5
+
(
st
->
tx_bit
&
0xff
);
}
if
(
st
->
txphase
>=
5
)
st
->
txphase
=
0
;
*
buf
++
=
*
st
->
txtbl
;
st
->
txtbl
+=
0x100
;
}
}
/* --------------------------------------------------------------------- */
static
void
modulator_9600_5_s16
(
struct
sm_state
*
sm
,
short
*
buf
,
unsigned
int
buflen
)
{
struct
mod_state_fsk96
*
st
=
(
struct
mod_state_fsk96
*
)(
&
sm
->
m
);
for
(;
buflen
>
0
;
buflen
--
)
{
if
(
!
st
->
txphase
++
)
{
if
(
st
->
shreg
<=
1
)
st
->
shreg
=
hdlcdrv_getbits
(
&
sm
->
hdrv
)
|
0x10000
;
st
->
scram
=
(
st
->
scram
<<
1
)
|
(
st
->
scram
&
1
);
st
->
scram
^=
!
(
st
->
shreg
&
1
);
st
->
shreg
>>=
1
;
if
(
st
->
scram
&
(
SCRAM_TAP1
<<
1
))
st
->
scram
^=
SCRAM_TAPN
<<
1
;
st
->
tx_bit
=
(
st
->
tx_bit
<<
1
)
|
(
!!
(
st
->
scram
&
(
SCRAM_TAP1
<<
2
)));
st
->
txtbl
=
fsk96_txfilt_5
+
(
st
->
tx_bit
&
0xff
);
}
if
(
st
->
txphase
>=
5
)
st
->
txphase
=
0
;
*
buf
++
=
((
*
st
->
txtbl
)
-
0x80
)
<<
8
;
st
->
txtbl
+=
0x100
;
}
}
/* --------------------------------------------------------------------- */
static
void
demodulator_9600_5_u8
(
struct
sm_state
*
sm
,
const
unsigned
char
*
buf
,
unsigned
int
buflen
)
{
struct
demod_state_fsk96
*
st
=
(
struct
demod_state_fsk96
*
)(
&
sm
->
d
);
static
const
int
pll_corr
[
2
]
=
{
-
0x1000
,
0x1000
};
unsigned
char
curbit
;
unsigned
int
descx
;
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
st
->
dcd_shreg
<<=
1
;
st
->
bit_pll
+=
0x3333
;
curbit
=
(
*
buf
>=
0x80
);
if
(
st
->
last_sample
^
curbit
)
{
st
->
dcd_shreg
|=
1
;
st
->
bit_pll
+=
pll_corr
[
st
->
bit_pll
<
0x9999
];
st
->
dcd_sum0
+=
16
*
hweight8
(
st
->
dcd_shreg
&
0x0c
)
-
hweight8
(
st
->
dcd_shreg
&
0x70
);
}
st
->
last_sample
=
curbit
;
hdlcdrv_channelbit
(
&
sm
->
hdrv
,
st
->
last_sample
);
if
((
--
st
->
dcd_time
)
<=
0
)
{
hdlcdrv_setdcd
(
&
sm
->
hdrv
,
(
st
->
dcd_sum0
+
st
->
dcd_sum1
+
st
->
dcd_sum2
)
<
0
);
st
->
dcd_sum2
=
st
->
dcd_sum1
;
st
->
dcd_sum1
=
st
->
dcd_sum0
;
st
->
dcd_sum0
=
2
;
/* slight bias */
st
->
dcd_time
=
240
;
}
if
(
st
->
bit_pll
>=
0x10000
)
{
st
->
bit_pll
&=
0xffff
;
st
->
descram
=
(
st
->
descram
<<
1
)
|
curbit
;
descx
=
st
->
descram
^
(
st
->
descram
>>
1
);
descx
^=
((
descx
>>
DESCRAM_TAPSH1
)
^
(
descx
>>
DESCRAM_TAPSH2
));
st
->
shreg
>>=
1
;
st
->
shreg
|=
(
!
(
descx
&
1
))
<<
16
;
if
(
st
->
shreg
&
1
)
{
hdlcdrv_putbits
(
&
sm
->
hdrv
,
st
->
shreg
>>
1
);
st
->
shreg
=
0x10000
;
}
diag_trigger
(
sm
);
}
diag_add_one
(
sm
,
((
short
)(
*
buf
-
0x80
))
<<
8
);
}
}
/* --------------------------------------------------------------------- */
static
void
demodulator_9600_5_s16
(
struct
sm_state
*
sm
,
const
short
*
buf
,
unsigned
int
buflen
)
{
struct
demod_state_fsk96
*
st
=
(
struct
demod_state_fsk96
*
)(
&
sm
->
d
);
static
const
int
pll_corr
[
2
]
=
{
-
0x1000
,
0x1000
};
unsigned
char
curbit
;
unsigned
int
descx
;
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
st
->
dcd_shreg
<<=
1
;
st
->
bit_pll
+=
0x3333
;
curbit
=
(
*
buf
>=
0
);
if
(
st
->
last_sample
^
curbit
)
{
st
->
dcd_shreg
|=
1
;
st
->
bit_pll
+=
pll_corr
[
st
->
bit_pll
<
0x9999
];
st
->
dcd_sum0
+=
16
*
hweight8
(
st
->
dcd_shreg
&
0x0c
)
-
hweight8
(
st
->
dcd_shreg
&
0x70
);
}
st
->
last_sample
=
curbit
;
hdlcdrv_channelbit
(
&
sm
->
hdrv
,
st
->
last_sample
);
if
((
--
st
->
dcd_time
)
<=
0
)
{
hdlcdrv_setdcd
(
&
sm
->
hdrv
,
(
st
->
dcd_sum0
+
st
->
dcd_sum1
+
st
->
dcd_sum2
)
<
0
);
st
->
dcd_sum2
=
st
->
dcd_sum1
;
st
->
dcd_sum1
=
st
->
dcd_sum0
;
st
->
dcd_sum0
=
2
;
/* slight bias */
st
->
dcd_time
=
240
;
}
if
(
st
->
bit_pll
>=
0x10000
)
{
st
->
bit_pll
&=
0xffff
;
st
->
descram
=
(
st
->
descram
<<
1
)
|
curbit
;
descx
=
st
->
descram
^
(
st
->
descram
>>
1
);
descx
^=
((
descx
>>
DESCRAM_TAPSH1
)
^
(
descx
>>
DESCRAM_TAPSH2
));
st
->
shreg
>>=
1
;
st
->
shreg
|=
(
!
(
descx
&
1
))
<<
16
;
if
(
st
->
shreg
&
1
)
{
hdlcdrv_putbits
(
&
sm
->
hdrv
,
st
->
shreg
>>
1
);
st
->
shreg
=
0x10000
;
}
diag_trigger
(
sm
);
}
diag_add_one
(
sm
,
*
buf
);
}
}
/* --------------------------------------------------------------------- */
static
void
demod_init_9600
(
struct
sm_state
*
sm
)
{
struct
demod_state_fsk96
*
st
=
(
struct
demod_state_fsk96
*
)(
&
sm
->
d
);
st
->
dcd_time
=
240
;
st
->
dcd_sum0
=
2
;
}
/* --------------------------------------------------------------------- */
const
struct
modem_tx_info
sm_fsk9600_4_tx
=
{
"fsk9600"
,
sizeof
(
struct
mod_state_fsk96
),
38400
,
9600
,
modulator_9600_4_u8
,
modulator_9600_4_s16
,
NULL
};
const
struct
modem_rx_info
sm_fsk9600_4_rx
=
{
"fsk9600"
,
sizeof
(
struct
demod_state_fsk96
),
38400
,
9600
,
1
,
4
,
demodulator_9600_4_u8
,
demodulator_9600_4_s16
,
demod_init_9600
};
/* --------------------------------------------------------------------- */
const
struct
modem_tx_info
sm_fsk9600_5_tx
=
{
"fsk9600"
,
sizeof
(
struct
mod_state_fsk96
),
48000
,
9600
,
modulator_9600_5_u8
,
modulator_9600_5_s16
,
NULL
};
const
struct
modem_rx_info
sm_fsk9600_5_rx
=
{
"fsk9600"
,
sizeof
(
struct
demod_state_fsk96
),
48000
,
9600
,
1
,
5
,
demodulator_9600_5_u8
,
demodulator_9600_5_s16
,
demod_init_9600
};
/* --------------------------------------------------------------------- */
drivers/net/hamradio/soundmodem/sm_hapn4800.c
deleted
100644 → 0
View file @
a994c542
/*****************************************************************************/
/*
* sm_hapn4800.c -- soundcard radio modem driver, 4800 baud HAPN modem
*
* 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.
*
*
* This module implements a (hopefully) HAPN (Hamilton Area Packet
* Network) compatible 4800 baud modem.
* The HAPN modem uses kind of "duobinary signalling" (not really,
* duobinary signalling gives ... 0 0 -1 0 1 0 0 ... at the sampling
* instants, whereas HAPN signalling gives ... 0 0 -1 1 0 0 ..., see
* Proakis, Digital Communications).
* The code is untested. It is compatible with itself (i.e. it can decode
* the packets it sent), but I could not test if it is compatible with
* any "real" HAPN modem, since noone uses it in my region of the world.
* Feedback therefore welcome.
*/
#include "sm.h"
#include "sm_tbl_hapn4800.h"
/* --------------------------------------------------------------------- */
struct
demod_state_hapn48
{
unsigned
int
shreg
;
unsigned
int
bit_pll
;
unsigned
char
last_bit
;
unsigned
char
last_bit2
;
unsigned
int
dcd_shreg
;
int
dcd_sum0
,
dcd_sum1
,
dcd_sum2
;
unsigned
int
dcd_time
;
int
lvlhi
,
lvllo
;
};
struct
mod_state_hapn48
{
unsigned
int
shreg
;
unsigned
char
tx_bit
;
unsigned
int
tx_seq
;
const
unsigned
char
*
tbl
;
};
/* --------------------------------------------------------------------- */
static
void
modulator_hapn4800_10_u8
(
struct
sm_state
*
sm
,
unsigned
char
*
buf
,
unsigned
int
buflen
)
{
struct
mod_state_hapn48
*
st
=
(
struct
mod_state_hapn48
*
)(
&
sm
->
m
);
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
if
(
!
st
->
tx_seq
++
)
{
if
(
st
->
shreg
<=
1
)
st
->
shreg
=
hdlcdrv_getbits
(
&
sm
->
hdrv
)
|
0x10000
;
st
->
tx_bit
=
((
st
->
tx_bit
<<
1
)
|
(
st
->
tx_bit
&
1
));
st
->
tx_bit
^=
(
!
(
st
->
shreg
&
1
));
st
->
shreg
>>=
1
;
st
->
tbl
=
hapn48_txfilt_10
+
(
st
->
tx_bit
&
0xf
);
}
if
(
st
->
tx_seq
>=
10
)
st
->
tx_seq
=
0
;
*
buf
=
*
st
->
tbl
;
st
->
tbl
+=
0x10
;
}
}
/* --------------------------------------------------------------------- */
static
void
modulator_hapn4800_10_s16
(
struct
sm_state
*
sm
,
short
*
buf
,
unsigned
int
buflen
)
{
struct
mod_state_hapn48
*
st
=
(
struct
mod_state_hapn48
*
)(
&
sm
->
m
);
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
if
(
!
st
->
tx_seq
++
)
{
if
(
st
->
shreg
<=
1
)
st
->
shreg
=
hdlcdrv_getbits
(
&
sm
->
hdrv
)
|
0x10000
;
st
->
tx_bit
=
((
st
->
tx_bit
<<
1
)
|
(
st
->
tx_bit
&
1
));
st
->
tx_bit
^=
(
!
(
st
->
shreg
&
1
));
st
->
shreg
>>=
1
;
st
->
tbl
=
hapn48_txfilt_10
+
(
st
->
tx_bit
&
0xf
);
}
if
(
st
->
tx_seq
>=
10
)
st
->
tx_seq
=
0
;
*
buf
=
((
*
st
->
tbl
)
-
0x80
)
<<
8
;
st
->
tbl
+=
0x10
;
}
}
/* --------------------------------------------------------------------- */
static
void
modulator_hapn4800_8_u8
(
struct
sm_state
*
sm
,
unsigned
char
*
buf
,
unsigned
int
buflen
)
{
struct
mod_state_hapn48
*
st
=
(
struct
mod_state_hapn48
*
)(
&
sm
->
m
);
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
if
(
!
st
->
tx_seq
++
)
{
if
(
st
->
shreg
<=
1
)
st
->
shreg
=
hdlcdrv_getbits
(
&
sm
->
hdrv
)
|
0x10000
;
st
->
tx_bit
=
(
st
->
tx_bit
<<
1
)
|
(
st
->
tx_bit
&
1
);
st
->
tx_bit
^=
!
(
st
->
shreg
&
1
);
st
->
shreg
>>=
1
;
st
->
tbl
=
hapn48_txfilt_8
+
(
st
->
tx_bit
&
0xf
);
}
if
(
st
->
tx_seq
>=
8
)
st
->
tx_seq
=
0
;
*
buf
=
*
st
->
tbl
;
st
->
tbl
+=
0x10
;
}
}
/* --------------------------------------------------------------------- */
static
void
modulator_hapn4800_8_s16
(
struct
sm_state
*
sm
,
short
*
buf
,
unsigned
int
buflen
)
{
struct
mod_state_hapn48
*
st
=
(
struct
mod_state_hapn48
*
)(
&
sm
->
m
);
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
if
(
!
st
->
tx_seq
++
)
{
if
(
st
->
shreg
<=
1
)
st
->
shreg
=
hdlcdrv_getbits
(
&
sm
->
hdrv
)
|
0x10000
;
st
->
tx_bit
=
(
st
->
tx_bit
<<
1
)
|
(
st
->
tx_bit
&
1
);
st
->
tx_bit
^=
!
(
st
->
shreg
&
1
);
st
->
shreg
>>=
1
;
st
->
tbl
=
hapn48_txfilt_8
+
(
st
->
tx_bit
&
0xf
);
}
if
(
st
->
tx_seq
>=
8
)
st
->
tx_seq
=
0
;
*
buf
=
((
*
st
->
tbl
)
-
0x80
)
<<
8
;
st
->
tbl
+=
0x10
;
}
}
/* --------------------------------------------------------------------- */
static
void
modulator_hapn4800_pm10_u8
(
struct
sm_state
*
sm
,
unsigned
char
*
buf
,
unsigned
int
buflen
)
{
struct
mod_state_hapn48
*
st
=
(
struct
mod_state_hapn48
*
)(
&
sm
->
m
);
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
if
(
!
st
->
tx_seq
++
)
{
if
(
st
->
shreg
<=
1
)
st
->
shreg
=
hdlcdrv_getbits
(
&
sm
->
hdrv
)
|
0x10000
;
st
->
tx_bit
=
((
st
->
tx_bit
<<
1
)
|
(
st
->
tx_bit
&
1
));
st
->
tx_bit
^=
(
!
(
st
->
shreg
&
1
));
st
->
shreg
>>=
1
;
st
->
tbl
=
hapn48_txfilt_pm10
+
(
st
->
tx_bit
&
0xf
);
}
if
(
st
->
tx_seq
>=
10
)
st
->
tx_seq
=
0
;
*
buf
=
*
st
->
tbl
;
st
->
tbl
+=
0x10
;
}
}
/* --------------------------------------------------------------------- */
static
void
modulator_hapn4800_pm10_s16
(
struct
sm_state
*
sm
,
short
*
buf
,
unsigned
int
buflen
)
{
struct
mod_state_hapn48
*
st
=
(
struct
mod_state_hapn48
*
)(
&
sm
->
m
);
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
if
(
!
st
->
tx_seq
++
)
{
if
(
st
->
shreg
<=
1
)
st
->
shreg
=
hdlcdrv_getbits
(
&
sm
->
hdrv
)
|
0x10000
;
st
->
tx_bit
=
((
st
->
tx_bit
<<
1
)
|
(
st
->
tx_bit
&
1
));
st
->
tx_bit
^=
(
!
(
st
->
shreg
&
1
));
st
->
shreg
>>=
1
;
st
->
tbl
=
hapn48_txfilt_pm10
+
(
st
->
tx_bit
&
0xf
);
}
if
(
st
->
tx_seq
>=
10
)
st
->
tx_seq
=
0
;
*
buf
=
((
*
st
->
tbl
)
-
0x80
)
<<
8
;
st
->
tbl
+=
0x10
;
}
}
/* --------------------------------------------------------------------- */
static
void
modulator_hapn4800_pm8_u8
(
struct
sm_state
*
sm
,
unsigned
char
*
buf
,
unsigned
int
buflen
)
{
struct
mod_state_hapn48
*
st
=
(
struct
mod_state_hapn48
*
)(
&
sm
->
m
);
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
if
(
!
st
->
tx_seq
++
)
{
if
(
st
->
shreg
<=
1
)
st
->
shreg
=
hdlcdrv_getbits
(
&
sm
->
hdrv
)
|
0x10000
;
st
->
tx_bit
=
(
st
->
tx_bit
<<
1
)
|
(
st
->
tx_bit
&
1
);
st
->
tx_bit
^=
!
(
st
->
shreg
&
1
);
st
->
shreg
>>=
1
;
st
->
tbl
=
hapn48_txfilt_pm8
+
(
st
->
tx_bit
&
0xf
);
}
if
(
st
->
tx_seq
>=
8
)
st
->
tx_seq
=
0
;
*
buf
=
*
st
->
tbl
;
st
->
tbl
+=
0x10
;
}
}
/* --------------------------------------------------------------------- */
static
void
modulator_hapn4800_pm8_s16
(
struct
sm_state
*
sm
,
short
*
buf
,
unsigned
int
buflen
)
{
struct
mod_state_hapn48
*
st
=
(
struct
mod_state_hapn48
*
)(
&
sm
->
m
);
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
if
(
!
st
->
tx_seq
++
)
{
if
(
st
->
shreg
<=
1
)
st
->
shreg
=
hdlcdrv_getbits
(
&
sm
->
hdrv
)
|
0x10000
;
st
->
tx_bit
=
(
st
->
tx_bit
<<
1
)
|
(
st
->
tx_bit
&
1
);
st
->
tx_bit
^=
!
(
st
->
shreg
&
1
);
st
->
shreg
>>=
1
;
st
->
tbl
=
hapn48_txfilt_pm8
+
(
st
->
tx_bit
&
0xf
);
}
if
(
st
->
tx_seq
>=
8
)
st
->
tx_seq
=
0
;
*
buf
=
((
*
st
->
tbl
)
-
0x80
)
<<
8
;
st
->
tbl
+=
0x10
;
}
}
/* --------------------------------------------------------------------- */
static
void
demodulator_hapn4800_10_u8
(
struct
sm_state
*
sm
,
const
unsigned
char
*
buf
,
unsigned
int
buflen
)
{
struct
demod_state_hapn48
*
st
=
(
struct
demod_state_hapn48
*
)(
&
sm
->
d
);
static
const
int
pll_corr
[
2
]
=
{
-
0x800
,
0x800
};
int
curst
,
cursync
;
int
inv
;
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
inv
=
((
int
)(
buf
[
-
2
])
-
0x80
)
<<
8
;
st
->
lvlhi
=
(
st
->
lvlhi
*
65309
)
>>
16
;
/* decay */
st
->
lvllo
=
(
st
->
lvllo
*
65309
)
>>
16
;
/* decay */
if
(
inv
>
st
->
lvlhi
)
st
->
lvlhi
=
inv
;
if
(
inv
<
st
->
lvllo
)
st
->
lvllo
=
inv
;
if
(
buflen
&
1
)
st
->
dcd_shreg
<<=
1
;
st
->
bit_pll
+=
0x199a
;
curst
=
cursync
=
0
;
if
(
inv
>
st
->
lvlhi
>>
1
)
{
curst
=
1
;
cursync
=
(
buf
[
-
2
]
>
buf
[
-
1
]
&&
buf
[
-
2
]
>
buf
[
-
3
]
&&
buf
[
-
2
]
>
buf
[
-
0
]
&&
buf
[
-
2
]
>
buf
[
-
4
]);
}
else
if
(
inv
<
st
->
lvllo
>>
1
)
{
curst
=
-
1
;
cursync
=
(
buf
[
-
2
]
<
buf
[
-
1
]
&&
buf
[
-
2
]
<
buf
[
-
3
]
&&
buf
[
-
2
]
<
buf
[
-
0
]
&&
buf
[
-
2
]
<
buf
[
-
4
]);
}
if
(
cursync
)
{
st
->
dcd_shreg
|=
cursync
;
st
->
bit_pll
+=
pll_corr
[((
st
->
bit_pll
-
0x8000u
)
&
0xffffu
)
<
0x8ccdu
];
st
->
dcd_sum0
+=
16
*
hweight32
(
st
->
dcd_shreg
&
0x18c6318c
)
-
hweight32
(
st
->
dcd_shreg
&
0xe739ce70
);
}
hdlcdrv_channelbit
(
&
sm
->
hdrv
,
cursync
);
if
((
--
st
->
dcd_time
)
<=
0
)
{
hdlcdrv_setdcd
(
&
sm
->
hdrv
,
(
st
->
dcd_sum0
+
st
->
dcd_sum1
+
st
->
dcd_sum2
)
<
0
);
st
->
dcd_sum2
=
st
->
dcd_sum1
;
st
->
dcd_sum1
=
st
->
dcd_sum0
;
st
->
dcd_sum0
=
2
;
/* slight bias */
st
->
dcd_time
=
240
;
}
if
(
st
->
bit_pll
>=
0x10000
)
{
st
->
bit_pll
&=
0xffff
;
st
->
last_bit2
=
st
->
last_bit
;
if
(
curst
<
0
)
st
->
last_bit
=
0
;
else
if
(
curst
>
0
)
st
->
last_bit
=
1
;
st
->
shreg
>>=
1
;
st
->
shreg
|=
((
st
->
last_bit
^
st
->
last_bit2
^
1
)
&
1
)
<<
16
;
if
(
st
->
shreg
&
1
)
{
hdlcdrv_putbits
(
&
sm
->
hdrv
,
st
->
shreg
>>
1
);
st
->
shreg
=
0x10000
;
}
diag_trigger
(
sm
);
}
diag_add_one
(
sm
,
inv
);
}
}
/* --------------------------------------------------------------------- */
static
void
demodulator_hapn4800_10_s16
(
struct
sm_state
*
sm
,
const
short
*
buf
,
unsigned
int
buflen
)
{
struct
demod_state_hapn48
*
st
=
(
struct
demod_state_hapn48
*
)(
&
sm
->
d
);
static
const
int
pll_corr
[
2
]
=
{
-
0x800
,
0x800
};
int
curst
,
cursync
;
int
inv
;
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
inv
=
buf
[
-
2
];
st
->
lvlhi
=
(
st
->
lvlhi
*
65309
)
>>
16
;
/* decay */
st
->
lvllo
=
(
st
->
lvllo
*
65309
)
>>
16
;
/* decay */
if
(
inv
>
st
->
lvlhi
)
st
->
lvlhi
=
inv
;
if
(
inv
<
st
->
lvllo
)
st
->
lvllo
=
inv
;
if
(
buflen
&
1
)
st
->
dcd_shreg
<<=
1
;
st
->
bit_pll
+=
0x199a
;
curst
=
cursync
=
0
;
if
(
inv
>
st
->
lvlhi
>>
1
)
{
curst
=
1
;
cursync
=
(
buf
[
-
2
]
>
buf
[
-
1
]
&&
buf
[
-
2
]
>
buf
[
-
3
]
&&
buf
[
-
2
]
>
buf
[
-
0
]
&&
buf
[
-
2
]
>
buf
[
-
4
]);
}
else
if
(
inv
<
st
->
lvllo
>>
1
)
{
curst
=
-
1
;
cursync
=
(
buf
[
-
2
]
<
buf
[
-
1
]
&&
buf
[
-
2
]
<
buf
[
-
3
]
&&
buf
[
-
2
]
<
buf
[
-
0
]
&&
buf
[
-
2
]
<
buf
[
-
4
]);
}
if
(
cursync
)
{
st
->
dcd_shreg
|=
cursync
;
st
->
bit_pll
+=
pll_corr
[((
st
->
bit_pll
-
0x8000u
)
&
0xffffu
)
<
0x8ccdu
];
st
->
dcd_sum0
+=
16
*
hweight32
(
st
->
dcd_shreg
&
0x18c6318c
)
-
hweight32
(
st
->
dcd_shreg
&
0xe739ce70
);
}
hdlcdrv_channelbit
(
&
sm
->
hdrv
,
cursync
);
if
((
--
st
->
dcd_time
)
<=
0
)
{
hdlcdrv_setdcd
(
&
sm
->
hdrv
,
(
st
->
dcd_sum0
+
st
->
dcd_sum1
+
st
->
dcd_sum2
)
<
0
);
st
->
dcd_sum2
=
st
->
dcd_sum1
;
st
->
dcd_sum1
=
st
->
dcd_sum0
;
st
->
dcd_sum0
=
2
;
/* slight bias */
st
->
dcd_time
=
240
;
}
if
(
st
->
bit_pll
>=
0x10000
)
{
st
->
bit_pll
&=
0xffff
;
st
->
last_bit2
=
st
->
last_bit
;
if
(
curst
<
0
)
st
->
last_bit
=
0
;
else
if
(
curst
>
0
)
st
->
last_bit
=
1
;
st
->
shreg
>>=
1
;
st
->
shreg
|=
((
st
->
last_bit
^
st
->
last_bit2
^
1
)
&
1
)
<<
16
;
if
(
st
->
shreg
&
1
)
{
hdlcdrv_putbits
(
&
sm
->
hdrv
,
st
->
shreg
>>
1
);
st
->
shreg
=
0x10000
;
}
diag_trigger
(
sm
);
}
diag_add_one
(
sm
,
inv
);
}
}
/* --------------------------------------------------------------------- */
static
void
demodulator_hapn4800_8_u8
(
struct
sm_state
*
sm
,
const
unsigned
char
*
buf
,
unsigned
int
buflen
)
{
struct
demod_state_hapn48
*
st
=
(
struct
demod_state_hapn48
*
)(
&
sm
->
d
);
static
const
int
pll_corr
[
2
]
=
{
-
0x800
,
0x800
};
int
curst
,
cursync
;
int
inv
;
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
inv
=
((
int
)(
buf
[
-
2
])
-
0x80
)
<<
8
;
st
->
lvlhi
=
(
st
->
lvlhi
*
65309
)
>>
16
;
/* decay */
st
->
lvllo
=
(
st
->
lvllo
*
65309
)
>>
16
;
/* decay */
if
(
inv
>
st
->
lvlhi
)
st
->
lvlhi
=
inv
;
if
(
inv
<
st
->
lvllo
)
st
->
lvllo
=
inv
;
if
(
buflen
&
1
)
st
->
dcd_shreg
<<=
1
;
st
->
bit_pll
+=
0x2000
;
curst
=
cursync
=
0
;
if
(
inv
>
st
->
lvlhi
>>
1
)
{
curst
=
1
;
cursync
=
(
buf
[
-
2
]
>
buf
[
-
1
]
&&
buf
[
-
2
]
>
buf
[
-
3
]
&&
buf
[
-
2
]
>
buf
[
-
0
]
&&
buf
[
-
2
]
>
buf
[
-
4
]);
}
else
if
(
inv
<
st
->
lvllo
>>
1
)
{
curst
=
-
1
;
cursync
=
(
buf
[
-
2
]
<
buf
[
-
1
]
&&
buf
[
-
2
]
<
buf
[
-
3
]
&&
buf
[
-
2
]
<
buf
[
-
0
]
&&
buf
[
-
2
]
<
buf
[
-
4
]);
}
if
(
cursync
)
{
st
->
dcd_shreg
|=
cursync
;
st
->
bit_pll
+=
pll_corr
[((
st
->
bit_pll
-
0x8000u
)
&
0xffffu
)
<
0x9000u
];
st
->
dcd_sum0
+=
16
*
hweight32
(
st
->
dcd_shreg
&
0x44444444
)
-
hweight32
(
st
->
dcd_shreg
&
0xbbbbbbbb
);
}
hdlcdrv_channelbit
(
&
sm
->
hdrv
,
cursync
);
if
((
--
st
->
dcd_time
)
<=
0
)
{
hdlcdrv_setdcd
(
&
sm
->
hdrv
,
(
st
->
dcd_sum0
+
st
->
dcd_sum1
+
st
->
dcd_sum2
)
<
0
);
st
->
dcd_sum2
=
st
->
dcd_sum1
;
st
->
dcd_sum1
=
st
->
dcd_sum0
;
st
->
dcd_sum0
=
2
;
/* slight bias */
st
->
dcd_time
=
240
;
}
if
(
st
->
bit_pll
>=
0x10000
)
{
st
->
bit_pll
&=
0xffff
;
st
->
last_bit2
=
st
->
last_bit
;
if
(
curst
<
0
)
st
->
last_bit
=
0
;
else
if
(
curst
>
0
)
st
->
last_bit
=
1
;
st
->
shreg
>>=
1
;
st
->
shreg
|=
((
st
->
last_bit
^
st
->
last_bit2
^
1
)
&
1
)
<<
16
;
if
(
st
->
shreg
&
1
)
{
hdlcdrv_putbits
(
&
sm
->
hdrv
,
st
->
shreg
>>
1
);
st
->
shreg
=
0x10000
;
}
diag_trigger
(
sm
);
}
diag_add_one
(
sm
,
inv
);
}
}
/* --------------------------------------------------------------------- */
static
void
demodulator_hapn4800_8_s16
(
struct
sm_state
*
sm
,
const
short
*
buf
,
unsigned
int
buflen
)
{
struct
demod_state_hapn48
*
st
=
(
struct
demod_state_hapn48
*
)(
&
sm
->
d
);
static
const
int
pll_corr
[
2
]
=
{
-
0x800
,
0x800
};
int
curst
,
cursync
;
int
inv
;
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
inv
=
buf
[
-
2
];
st
->
lvlhi
=
(
st
->
lvlhi
*
65309
)
>>
16
;
/* decay */
st
->
lvllo
=
(
st
->
lvllo
*
65309
)
>>
16
;
/* decay */
if
(
inv
>
st
->
lvlhi
)
st
->
lvlhi
=
inv
;
if
(
inv
<
st
->
lvllo
)
st
->
lvllo
=
inv
;
if
(
buflen
&
1
)
st
->
dcd_shreg
<<=
1
;
st
->
bit_pll
+=
0x2000
;
curst
=
cursync
=
0
;
if
(
inv
>
st
->
lvlhi
>>
1
)
{
curst
=
1
;
cursync
=
(
buf
[
-
2
]
>
buf
[
-
1
]
&&
buf
[
-
2
]
>
buf
[
-
3
]
&&
buf
[
-
2
]
>
buf
[
-
0
]
&&
buf
[
-
2
]
>
buf
[
-
4
]);
}
else
if
(
inv
<
st
->
lvllo
>>
1
)
{
curst
=
-
1
;
cursync
=
(
buf
[
-
2
]
<
buf
[
-
1
]
&&
buf
[
-
2
]
<
buf
[
-
3
]
&&
buf
[
-
2
]
<
buf
[
-
0
]
&&
buf
[
-
2
]
<
buf
[
-
4
]);
}
if
(
cursync
)
{
st
->
dcd_shreg
|=
cursync
;
st
->
bit_pll
+=
pll_corr
[((
st
->
bit_pll
-
0x8000u
)
&
0xffffu
)
<
0x9000u
];
st
->
dcd_sum0
+=
16
*
hweight32
(
st
->
dcd_shreg
&
0x44444444
)
-
hweight32
(
st
->
dcd_shreg
&
0xbbbbbbbb
);
}
hdlcdrv_channelbit
(
&
sm
->
hdrv
,
cursync
);
if
((
--
st
->
dcd_time
)
<=
0
)
{
hdlcdrv_setdcd
(
&
sm
->
hdrv
,
(
st
->
dcd_sum0
+
st
->
dcd_sum1
+
st
->
dcd_sum2
)
<
0
);
st
->
dcd_sum2
=
st
->
dcd_sum1
;
st
->
dcd_sum1
=
st
->
dcd_sum0
;
st
->
dcd_sum0
=
2
;
/* slight bias */
st
->
dcd_time
=
240
;
}
if
(
st
->
bit_pll
>=
0x10000
)
{
st
->
bit_pll
&=
0xffff
;
st
->
last_bit2
=
st
->
last_bit
;
if
(
curst
<
0
)
st
->
last_bit
=
0
;
else
if
(
curst
>
0
)
st
->
last_bit
=
1
;
st
->
shreg
>>=
1
;
st
->
shreg
|=
((
st
->
last_bit
^
st
->
last_bit2
^
1
)
&
1
)
<<
16
;
if
(
st
->
shreg
&
1
)
{
hdlcdrv_putbits
(
&
sm
->
hdrv
,
st
->
shreg
>>
1
);
st
->
shreg
=
0x10000
;
}
diag_trigger
(
sm
);
}
diag_add_one
(
sm
,
inv
);
}
}
/* --------------------------------------------------------------------- */
static
void
demod_init_hapn4800
(
struct
sm_state
*
sm
)
{
struct
demod_state_hapn48
*
st
=
(
struct
demod_state_hapn48
*
)(
&
sm
->
d
);
st
->
dcd_time
=
120
;
st
->
dcd_sum0
=
2
;
}
/* --------------------------------------------------------------------- */
const
struct
modem_tx_info
sm_hapn4800_8_tx
=
{
"hapn4800"
,
sizeof
(
struct
mod_state_hapn48
),
38400
,
4800
,
modulator_hapn4800_8_u8
,
modulator_hapn4800_8_s16
,
NULL
};
const
struct
modem_rx_info
sm_hapn4800_8_rx
=
{
"hapn4800"
,
sizeof
(
struct
demod_state_hapn48
),
38400
,
4800
,
5
,
8
,
demodulator_hapn4800_8_u8
,
demodulator_hapn4800_8_s16
,
demod_init_hapn4800
};
/* --------------------------------------------------------------------- */
const
struct
modem_tx_info
sm_hapn4800_10_tx
=
{
"hapn4800"
,
sizeof
(
struct
mod_state_hapn48
),
48000
,
4800
,
modulator_hapn4800_10_u8
,
modulator_hapn4800_10_s16
,
NULL
};
const
struct
modem_rx_info
sm_hapn4800_10_rx
=
{
"hapn4800"
,
sizeof
(
struct
demod_state_hapn48
),
48000
,
4800
,
5
,
10
,
demodulator_hapn4800_10_u8
,
demodulator_hapn4800_10_s16
,
demod_init_hapn4800
};
/* --------------------------------------------------------------------- */
const
struct
modem_tx_info
sm_hapn4800_pm8_tx
=
{
"hapn4800pm"
,
sizeof
(
struct
mod_state_hapn48
),
38400
,
4800
,
modulator_hapn4800_pm8_u8
,
modulator_hapn4800_pm8_s16
,
NULL
};
const
struct
modem_rx_info
sm_hapn4800_pm8_rx
=
{
"hapn4800pm"
,
sizeof
(
struct
demod_state_hapn48
),
38400
,
4800
,
5
,
8
,
demodulator_hapn4800_8_u8
,
demodulator_hapn4800_8_s16
,
demod_init_hapn4800
};
/* --------------------------------------------------------------------- */
const
struct
modem_tx_info
sm_hapn4800_pm10_tx
=
{
"hapn4800pm"
,
sizeof
(
struct
mod_state_hapn48
),
48000
,
4800
,
modulator_hapn4800_pm10_u8
,
modulator_hapn4800_pm10_s16
,
NULL
};
const
struct
modem_rx_info
sm_hapn4800_pm10_rx
=
{
"hapn4800pm"
,
sizeof
(
struct
demod_state_hapn48
),
48000
,
4800
,
5
,
10
,
demodulator_hapn4800_10_u8
,
demodulator_hapn4800_10_s16
,
demod_init_hapn4800
};
/* --------------------------------------------------------------------- */
drivers/net/hamradio/soundmodem/sm_psk4800.c
deleted
100644 → 0
View file @
a994c542
/*****************************************************************************/
/*
* sm_psk4800.c -- soundcard radio modem driver, 4800 baud 8PSK modem
*
* Copyright (C) 1997 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.
*
*/
#include "sm.h"
#include "sm_tbl_psk4800.h"
/* --------------------------------------------------------------------- */
#define DESCRAM_TAP1 0x20000
#define DESCRAM_TAP2 0x01000
#define DESCRAM_TAP3 0x00001
#define DESCRAM_TAPSH1 17
#define DESCRAM_TAPSH2 12
#define DESCRAM_TAPSH3 0
#define SCRAM_TAP1 0x20000
/* X^17 */
#define SCRAM_TAPN 0x00021
/* X^0+X^5 */
#define SCRAM_SHIFT 17
/* --------------------------------------------------------------------- */
struct
demod_state_psk48
{
/*
* input mixer and lowpass
*/
short
infi
[
PSK48_RXF_LEN
/
2
],
infq
[
PSK48_RXF_LEN
/
2
];
unsigned
int
downmixer
;
int
ovrphase
;
short
magi
,
magq
;
/*
* sampling instant recovery
*/
int
pwrhist
[
5
];
unsigned
int
s_phase
;
int
cur_sync
;
/*
* phase recovery
*/
short
cur_phase_dev
;
short
last_ph_err
;
unsigned
short
pskph
;
unsigned
int
phase
;
unsigned
short
last_pskph
;
unsigned
char
cur_raw
,
last_raw
,
rawbits
;
/*
* decoding
*/
unsigned
int
shreg
;
unsigned
long
descram
;
unsigned
int
bit_pll
;
unsigned
char
last_sample
;
unsigned
int
dcd_shreg
;
int
dcd_sum0
,
dcd_sum1
,
dcd_sum2
;
unsigned
int
dcd_time
;
};
struct
mod_state_psk48
{
unsigned
char
txbits
[
PSK48_TXF_NUMSAMPLES
];
unsigned
short
txphase
;
unsigned
int
shreg
;
unsigned
long
scram
;
const
short
*
tbl
;
unsigned
int
txseq
;
};
/* --------------------------------------------------------------------- */
static
void
modulator_4800_u8
(
struct
sm_state
*
sm
,
unsigned
char
*
buf
,
unsigned
int
buflen
)
{
struct
mod_state_psk48
*
st
=
(
struct
mod_state_psk48
*
)(
&
sm
->
m
);
int
i
,
j
;
int
si
,
sq
;
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
if
(
!
st
->
txseq
++
)
{
memmove
(
st
->
txbits
+
1
,
st
->
txbits
,
sizeof
(
st
->
txbits
)
-
sizeof
(
st
->
txbits
[
0
]));
for
(
i
=
0
;
i
<
3
;
i
++
)
{
if
(
st
->
shreg
<=
1
)
st
->
shreg
=
hdlcdrv_getbits
(
&
sm
->
hdrv
)
|
0x10000
;
st
->
scram
=
(
st
->
scram
<<
1
)
|
(
st
->
shreg
&
1
);
st
->
shreg
>>=
1
;
if
(
st
->
scram
&
SCRAM_TAP1
)
st
->
scram
^=
SCRAM_TAPN
;
}
j
=
(
st
->
scram
>>
(
SCRAM_SHIFT
+
3
))
&
7
;
st
->
txbits
[
0
]
-=
(
j
^
(
j
>>
1
));
st
->
txbits
[
0
]
&=
7
;
st
->
tbl
=
psk48_tx_table
;
}
if
(
st
->
txseq
>=
PSK48_TXF_OVERSAMPLING
)
st
->
txseq
=
0
;
for
(
j
=
si
=
sq
=
0
;
j
<
PSK48_TXF_NUMSAMPLES
;
j
++
,
st
->
tbl
+=
16
)
{
si
+=
st
->
tbl
[
st
->
txbits
[
j
]];
sq
+=
st
->
tbl
[
st
->
txbits
[
j
]
+
8
];
}
*
buf
=
((
si
*
COS
(
st
->
txphase
)
+
sq
*
SIN
(
st
->
txphase
))
>>
23
)
+
0x80
;
st
->
txphase
=
(
st
->
txphase
+
PSK48_PHASEINC
)
&
0xffffu
;
}
}
/* --------------------------------------------------------------------- */
static
void
modulator_4800_s16
(
struct
sm_state
*
sm
,
short
*
buf
,
unsigned
int
buflen
)
{
struct
mod_state_psk48
*
st
=
(
struct
mod_state_psk48
*
)(
&
sm
->
m
);
int
i
,
j
;
int
si
,
sq
;
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
if
(
!
st
->
txseq
++
)
{
memmove
(
st
->
txbits
+
1
,
st
->
txbits
,
sizeof
(
st
->
txbits
)
-
sizeof
(
st
->
txbits
[
0
]));
for
(
i
=
0
;
i
<
3
;
i
++
)
{
if
(
st
->
shreg
<=
1
)
st
->
shreg
=
hdlcdrv_getbits
(
&
sm
->
hdrv
)
|
0x10000
;
st
->
scram
=
(
st
->
scram
<<
1
)
|
(
st
->
shreg
&
1
);
st
->
shreg
>>=
1
;
if
(
st
->
scram
&
SCRAM_TAP1
)
st
->
scram
^=
SCRAM_TAPN
;
}
j
=
(
st
->
scram
>>
(
SCRAM_SHIFT
+
3
))
&
7
;
st
->
txbits
[
0
]
-=
(
j
^
(
j
>>
1
));
st
->
txbits
[
0
]
&=
7
;
st
->
tbl
=
psk48_tx_table
;
}
if
(
st
->
txseq
>=
PSK48_TXF_OVERSAMPLING
)
st
->
txseq
=
0
;
for
(
j
=
si
=
sq
=
0
;
j
<
PSK48_TXF_NUMSAMPLES
;
j
++
,
st
->
tbl
+=
16
)
{
si
+=
st
->
tbl
[
st
->
txbits
[
j
]];
sq
+=
st
->
tbl
[
st
->
txbits
[
j
]
+
8
];
}
*
buf
=
(
si
*
COS
(
st
->
txphase
)
+
sq
*
SIN
(
st
->
txphase
))
>>
15
;
st
->
txphase
=
(
st
->
txphase
+
PSK48_PHASEINC
)
&
0xffffu
;
}
}
/* --------------------------------------------------------------------- */
static
__inline__
unsigned
short
tbl_atan
(
short
q
,
short
i
)
{
short
tmp
;
unsigned
short
argoffs
=
0
;
if
(
i
==
0
&&
q
==
0
)
return
0
;
switch
(((
q
<
0
)
<<
1
)
|
(
i
<
0
))
{
case
0
:
break
;
case
1
:
tmp
=
q
;
q
=
-
i
;
i
=
tmp
;
argoffs
=
0x4000
;
break
;
case
3
:
q
=
-
q
;
i
=
-
i
;
argoffs
=
0x8000
;
break
;
case
2
:
tmp
=
-
q
;
q
=
i
;
i
=
tmp
;
argoffs
=
0xc000
;
break
;
}
if
(
q
>
i
)
{
tmp
=
i
/
q
*
ATAN_TABLEN
;
return
(
argoffs
+
0x4000
-
atan_tab
[((
i
<<
15
)
/
q
*
ATAN_TABLEN
>>
15
)])
&
0xffffu
;
}
return
(
argoffs
+
atan_tab
[((
q
<<
15
)
/
i
*
ATAN_TABLEN
)
>>
15
])
&
0xffffu
;
}
#define ATAN(q,i) tbl_atan(q, i)
/* --------------------------------------------------------------------- */
static
void
demod_psk48_baseband
(
struct
sm_state
*
sm
,
struct
demod_state_psk48
*
st
,
short
vali
,
short
valq
)
{
int
i
,
j
;
st
->
magi
=
vali
;
st
->
magq
=
valq
;
memmove
(
st
->
pwrhist
+
1
,
st
->
pwrhist
,
sizeof
(
st
->
pwrhist
)
-
sizeof
(
st
->
pwrhist
[
0
]));
st
->
pwrhist
[
0
]
=
st
->
magi
*
st
->
magi
+
st
->
magq
*
st
->
magq
;
st
->
cur_sync
=
((
st
->
pwrhist
[
4
]
>>
2
)
>
st
->
pwrhist
[
2
]
&&
(
st
->
pwrhist
[
0
]
>>
2
)
>
st
->
pwrhist
[
2
]
&&
st
->
pwrhist
[
3
]
>
st
->
pwrhist
[
2
]
&&
st
->
pwrhist
[
1
]
>
st
->
pwrhist
[
2
]);
st
->
s_phase
&=
0xffff
;
st
->
s_phase
+=
PSK48_SPHASEINC
;
st
->
dcd_shreg
<<=
1
;
if
(
st
->
cur_sync
)
{
if
(
st
->
s_phase
>=
(
0x8000
+
5
*
PSK48_SPHASEINC
/
2
))
st
->
s_phase
-=
PSK48_SPHASEINC
/
6
;
else
st
->
s_phase
+=
PSK48_SPHASEINC
/
6
;
st
->
dcd_sum0
=
4
*
hweight8
(
st
->
dcd_shreg
&
0xf8
)
-
hweight16
(
st
->
dcd_shreg
&
0x1f00
);
}
if
((
--
st
->
dcd_time
)
<=
0
)
{
hdlcdrv_setdcd
(
&
sm
->
hdrv
,
(
st
->
dcd_sum0
+
st
->
dcd_sum1
+
st
->
dcd_sum2
)
<
0
);
st
->
dcd_sum2
=
st
->
dcd_sum1
;
st
->
dcd_sum1
=
st
->
dcd_sum0
;
st
->
dcd_sum0
=
2
;
/* slight bias */
st
->
dcd_time
=
240
;
}
if
(
st
->
s_phase
<
0x10000
)
return
;
/*
* sample one constellation
*/
st
->
last_pskph
=
st
->
pskph
;
st
->
pskph
=
(
ATAN
(
st
->
magq
,
st
->
magi
)
-
st
->
phase
)
&
0xffffu
;
st
->
last_ph_err
=
(
st
->
pskph
&
0x1fffu
)
-
0x1000
;
st
->
phase
+=
st
->
last_ph_err
/
16
;
st
->
last_raw
=
st
->
cur_raw
;
st
->
cur_raw
=
((
st
->
pskph
>>
13
)
&
7
);
i
=
(
st
->
cur_raw
-
st
->
last_raw
)
&
7
;
st
->
rawbits
=
i
^
(
i
>>
1
)
^
(
i
>>
2
);
st
->
descram
=
(
st
->
descram
<<
3
)
|
(
st
->
rawbits
);
hdlcdrv_channelbit
(
&
sm
->
hdrv
,
st
->
descram
&
4
);
hdlcdrv_channelbit
(
&
sm
->
hdrv
,
st
->
descram
&
2
);
hdlcdrv_channelbit
(
&
sm
->
hdrv
,
st
->
descram
&
1
);
i
=
(((
st
->
descram
>>
DESCRAM_TAPSH1
)
&
7
)
^
((
st
->
descram
>>
DESCRAM_TAPSH2
)
&
7
)
^
((
st
->
descram
>>
DESCRAM_TAPSH3
)
&
7
));
for
(
j
=
4
;
j
;
j
>>=
1
)
{
st
->
shreg
>>=
1
;
st
->
shreg
|=
(
!!
(
i
&
j
))
<<
16
;
if
(
st
->
shreg
&
1
)
{
hdlcdrv_putbits
(
&
sm
->
hdrv
,
st
->
shreg
>>
1
);
st
->
shreg
=
0x10000
;
}
}
#if 0
st->dcd_shreg <<= 1;
st->bit_pll += 0x4000;
curbit = (*buf >= 0x80);
if (st->last_sample ^ curbit) {
st->dcd_shreg |= 1;
st->bit_pll += pll_corr
[st->bit_pll < 0xa000];
st->dcd_sum0 += 8 *
hweight8(st->dcd_shreg & 0x0c) -
!!(st->dcd_shreg & 0x10);
}
st->last_sample = curbit;
hdlcdrv_channelbit(&sm->hdrv, st->last_sample);
if ((--st->dcd_time) <= 0) {
hdlcdrv_setdcd(&sm->hdrv, (st->dcd_sum0 +
st->dcd_sum1 +
st->dcd_sum2) < 0);
st->dcd_sum2 = st->dcd_sum1;
st->dcd_sum1 = st->dcd_sum0;
st->dcd_sum0 = 2; /* slight bias */
st->dcd_time = 240;
}
if (st->bit_pll >= 0x10000) {
st->bit_pll &= 0xffffu;
st->descram = (st->descram << 1) | curbit;
descx = st->descram ^ (st->descram >> 1);
descx ^= ((descx >> DESCRAM_TAPSH1) ^
(descx >> DESCRAM_TAPSH2));
st->shreg >>= 1;
st->shreg |= (!(descx & 1)) << 16;
if (st->shreg & 1) {
hdlcdrv_putbits(&sm->hdrv, st->shreg >> 1);
st->shreg = 0x10000;
}
diag_trigger(sm);
}
diag_add_one(sm, ((short)(*buf - 0x80)) << 8);
#endif
diag_trigger
(
sm
);
diag_add_constellation
(
sm
,
(
vali
*
COS
(
st
->
phase
)
+
valq
*
SIN
(
st
->
phase
))
>>
13
,
(
valq
*
COS
(
st
->
phase
)
-
vali
*
SIN
(
st
->
phase
))
>>
13
);
}
/* --------------------------------------------------------------------- */
static
void
demodulator_4800_u8
(
struct
sm_state
*
sm
,
const
unsigned
char
*
buf
,
unsigned
int
buflen
)
{
struct
demod_state_psk48
*
st
=
(
struct
demod_state_psk48
*
)(
&
sm
->
d
);
int
i
,
si
,
sq
;
const
short
*
coeff
;
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
memmove
(
st
->
infi
+
1
,
st
->
infi
,
sizeof
(
st
->
infi
)
-
sizeof
(
st
->
infi
[
0
]));
memmove
(
st
->
infq
+
1
,
st
->
infq
,
sizeof
(
st
->
infq
)
-
sizeof
(
st
->
infq
[
0
]));
si
=
*
buf
;
si
&=
0xff
;
si
-=
128
;
diag_add_one
(
sm
,
si
<<
8
);
st
->
infi
[
0
]
=
(
si
*
COS
(
st
->
downmixer
))
>>
7
;
st
->
infq
[
0
]
=
(
si
*
SIN
(
st
->
downmixer
))
>>
7
;
st
->
downmixer
=
(
st
->
downmixer
-
PSK48_PHASEINC
)
&
0xffffu
;
for
(
i
=
si
=
sq
=
0
,
coeff
=
psk48_rx_coeff
;
i
<
(
PSK48_RXF_LEN
/
2
);
i
++
,
coeff
+=
2
)
{
si
+=
st
->
infi
[
i
]
*
(
*
coeff
);
sq
+=
st
->
infq
[
i
]
*
(
*
coeff
);
}
demod_psk48_baseband
(
sm
,
st
,
si
>>
15
,
sq
>>
15
);
for
(
i
=
si
=
sq
=
0
,
coeff
=
psk48_rx_coeff
+
1
;
i
<
(
PSK48_RXF_LEN
/
2
);
i
++
,
coeff
+=
2
)
{
si
+=
st
->
infi
[
i
]
*
(
*
coeff
);
sq
+=
st
->
infq
[
i
]
*
(
*
coeff
);
}
demod_psk48_baseband
(
sm
,
st
,
si
>>
15
,
sq
>>
15
);
}
}
/* --------------------------------------------------------------------- */
static
void
demodulator_4800_s16
(
struct
sm_state
*
sm
,
const
short
*
buf
,
unsigned
int
buflen
)
{
struct
demod_state_psk48
*
st
=
(
struct
demod_state_psk48
*
)(
&
sm
->
d
);
int
i
,
si
,
sq
;
const
short
*
coeff
;
for
(;
buflen
>
0
;
buflen
--
,
buf
++
)
{
memmove
(
st
->
infi
+
1
,
st
->
infi
,
sizeof
(
st
->
infi
)
-
sizeof
(
st
->
infi
[
0
]));
memmove
(
st
->
infq
+
1
,
st
->
infq
,
sizeof
(
st
->
infq
)
-
sizeof
(
st
->
infq
[
0
]));
si
=
*
buf
;
diag_add_one
(
sm
,
si
);
st
->
infi
[
0
]
=
(
si
*
COS
(
st
->
downmixer
))
>>
15
;
st
->
infq
[
0
]
=
(
si
*
SIN
(
st
->
downmixer
))
>>
15
;
st
->
downmixer
=
(
st
->
downmixer
-
PSK48_PHASEINC
)
&
0xffffu
;
for
(
i
=
si
=
sq
=
0
,
coeff
=
psk48_rx_coeff
;
i
<
(
PSK48_RXF_LEN
/
2
);
i
++
,
coeff
+=
2
)
{
si
+=
st
->
infi
[
i
]
*
(
*
coeff
);
sq
+=
st
->
infq
[
i
]
*
(
*
coeff
);
}
demod_psk48_baseband
(
sm
,
st
,
si
>>
15
,
sq
>>
15
);
for
(
i
=
si
=
sq
=
0
,
coeff
=
psk48_rx_coeff
+
1
;
i
<
(
PSK48_RXF_LEN
/
2
);
i
++
,
coeff
+=
2
)
{
si
+=
st
->
infi
[
i
]
*
(
*
coeff
);
sq
+=
st
->
infq
[
i
]
*
(
*
coeff
);
}
demod_psk48_baseband
(
sm
,
st
,
si
>>
15
,
sq
>>
15
);
}
}
/* --------------------------------------------------------------------- */
static
void
mod_init_4800
(
struct
sm_state
*
sm
)
{
struct
mod_state_psk48
*
st
=
(
struct
mod_state_psk48
*
)(
&
sm
->
m
);
st
->
scram
=
1
;
}
/* --------------------------------------------------------------------- */
static
void
demod_init_4800
(
struct
sm_state
*
sm
)
{
struct
demod_state_psk48
*
st
=
(
struct
demod_state_psk48
*
)(
&
sm
->
d
);
st
->
dcd_time
=
120
;
st
->
dcd_sum0
=
2
;
}
/* --------------------------------------------------------------------- */
const
struct
modem_tx_info
sm_psk4800_tx
=
{
"psk4800"
,
sizeof
(
struct
mod_state_psk48
),
PSK48_SAMPLERATE
,
4800
,
modulator_4800_u8
,
modulator_4800_s16
,
mod_init_4800
};
const
struct
modem_rx_info
sm_psk4800_rx
=
{
"psk4800"
,
sizeof
(
struct
demod_state_psk48
),
PSK48_SAMPLERATE
,
4800
,
1
,
PSK48_TXF_OVERSAMPLING
,
demodulator_4800_u8
,
demodulator_4800_s16
,
demod_init_4800
};
/* --------------------------------------------------------------------- */
drivers/net/hamradio/soundmodem/sm_sbc.c
deleted
100644 → 0
View file @
a994c542
/*
* sm_sbc.c -- soundcard radio modem driver soundblaster hardware driver
*
* 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.
*
*/
#include <linux/ptrace.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/soundmodem.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <asm/dma.h>
#include "sm.h"
#include "smdma.h"
/* --------------------------------------------------------------------- */
/*
* currently this module is supposed to support both module styles, i.e.
* the old one present up to about 2.1.9, and the new one functioning
* starting with 2.1.21. The reason is I have a kit allowing to compile
* this module also under 2.0.x which was requested by several people.
* This will go in 2.2
*/
#include <linux/version.h>
#if LINUX_VERSION_CODE >= 0x20100
#include <asm/uaccess.h>
#else
#include <asm/segment.h>
#include <linux/mm.h>
#undef put_user
#undef get_user
#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
static
inline
int
copy_from_user
(
void
*
to
,
const
void
*
from
,
unsigned
long
n
)
{
int
i
=
verify_area
(
VERIFY_READ
,
from
,
n
);
if
(
i
)
return
i
;
memcpy_fromfs
(
to
,
from
,
n
);
return
0
;
}
static
inline
int
copy_to_user
(
void
*
to
,
const
void
*
from
,
unsigned
long
n
)
{
int
i
=
verify_area
(
VERIFY_WRITE
,
to
,
n
);
if
(
i
)
return
i
;
memcpy_tofs
(
to
,
from
,
n
);
return
0
;
}
#endif
/* --------------------------------------------------------------------- */
struct
sc_state_sbc
{
unsigned
char
revhi
,
revlo
;
unsigned
char
fmt
[
2
];
unsigned
int
sr
[
2
];
};
#define SCSTATE ((struct sc_state_sbc *)(&sm->hw))
/* --------------------------------------------------------------------- */
/*
* the sbc converter's registers
*/
#define DSP_RESET(iobase) (iobase+0x6)
#define DSP_READ_DATA(iobase) (iobase+0xa)
#define DSP_WRITE_DATA(iobase) (iobase+0xc)
#define DSP_WRITE_STATUS(iobase) (iobase+0xc)
#define DSP_DATA_AVAIL(iobase) (iobase+0xe)
#define DSP_MIXER_ADDR(iobase) (iobase+0x4)
#define DSP_MIXER_DATA(iobase) (iobase+0x5)
#define DSP_INTACK_16BIT(iobase) (iobase+0xf)
#define SBC_EXTENT 16
/* --------------------------------------------------------------------- */
/*
* SBC commands
*/
#define SBC_OUTPUT 0x14
#define SBC_INPUT 0x24
#define SBC_BLOCKSIZE 0x48
#define SBC_HI_OUTPUT 0x91
#define SBC_HI_INPUT 0x99
#define SBC_LO_OUTPUT_AUTOINIT 0x1c
#define SBC_LO_INPUT_AUTOINIT 0x2c
#define SBC_HI_OUTPUT_AUTOINIT 0x90
#define SBC_HI_INPUT_AUTOINIT 0x98
#define SBC_IMMED_INT 0xf2
#define SBC_GET_REVISION 0xe1
#define ESS_GET_REVISION 0xe7
#define SBC_SPEAKER_ON 0xd1
#define SBC_SPEAKER_OFF 0xd3
#define SBC_DMA_ON 0xd0
#define SBC_DMA_OFF 0xd4
#define SBC_SAMPLE_RATE 0x40
#define SBC_SAMPLE_RATE_OUT 0x41
#define SBC_SAMPLE_RATE_IN 0x42
#define SBC_MONO_8BIT 0xa0
#define SBC_MONO_16BIT 0xa4
#define SBC_STEREO_8BIT 0xa8
#define SBC_STEREO_16BIT 0xac
#define SBC4_OUT8_AI 0xc6
#define SBC4_IN8_AI 0xce
#define SBC4_MODE_UNS_MONO 0x00
#define SBC4_MODE_SIGN_MONO 0x10
#define SBC4_OUT16_AI 0xb6
#define SBC4_IN16_AI 0xbe
/* --------------------------------------------------------------------- */
static
int
inline
reset_dsp
(
struct
net_device
*
dev
)
{
int
i
;
outb
(
1
,
DSP_RESET
(
dev
->
base_addr
));
udelay
(
300
);
outb
(
0
,
DSP_RESET
(
dev
->
base_addr
));
for
(
i
=
0
;
i
<
0xffff
;
i
++
)
if
(
inb
(
DSP_DATA_AVAIL
(
dev
->
base_addr
))
&
0x80
)
if
(
inb
(
DSP_READ_DATA
(
dev
->
base_addr
))
==
0xaa
)
return
1
;
return
0
;
}
/* --------------------------------------------------------------------- */
static
void
inline
write_dsp
(
struct
net_device
*
dev
,
unsigned
char
data
)
{
int
i
;
for
(
i
=
0
;
i
<
0xffff
;
i
++
)
if
(
!
(
inb
(
DSP_WRITE_STATUS
(
dev
->
base_addr
))
&
0x80
))
{
outb
(
data
,
DSP_WRITE_DATA
(
dev
->
base_addr
));
return
;
}
}
/* --------------------------------------------------------------------- */
static
int
inline
read_dsp
(
struct
net_device
*
dev
,
unsigned
char
*
data
)
{
int
i
;
if
(
!
data
)
return
0
;
for
(
i
=
0
;
i
<
0xffff
;
i
++
)
if
(
inb
(
DSP_DATA_AVAIL
(
dev
->
base_addr
))
&
0x80
)
{
*
data
=
inb
(
DSP_READ_DATA
(
dev
->
base_addr
));
return
1
;
}
return
0
;
}
/* --------------------------------------------------------------------- */
static
int
config_resources
(
struct
net_device
*
dev
,
struct
sm_state
*
sm
,
int
fdx
)
{
unsigned
char
irqreg
=
0
,
dmareg
=
0
,
realirq
,
realdma
;
unsigned
long
flags
;
switch
(
dev
->
irq
)
{
case
2
:
case
9
:
irqreg
|=
0x01
;
break
;
case
5
:
irqreg
|=
0x02
;
break
;
case
7
:
irqreg
|=
0x04
;
break
;
case
10
:
irqreg
|=
0x08
;
break
;
default:
return
-
ENODEV
;
}
switch
(
dev
->
dma
)
{
case
0
:
dmareg
|=
0x01
;
break
;
case
1
:
dmareg
|=
0x02
;
break
;
case
3
:
dmareg
|=
0x08
;
break
;
default:
return
-
ENODEV
;
}
if
(
fdx
)
{
switch
(
sm
->
hdrv
.
ptt_out
.
dma2
)
{
case
5
:
dmareg
|=
0x20
;
break
;
case
6
:
dmareg
|=
0x40
;
break
;
case
7
:
dmareg
|=
0x80
;
break
;
default:
return
-
ENODEV
;
}
}
save_flags
(
flags
);
cli
();
outb
(
0x80
,
DSP_MIXER_ADDR
(
dev
->
base_addr
));
outb
(
irqreg
,
DSP_MIXER_DATA
(
dev
->
base_addr
));
realirq
=
inb
(
DSP_MIXER_DATA
(
dev
->
base_addr
));
outb
(
0x81
,
DSP_MIXER_ADDR
(
dev
->
base_addr
));
outb
(
dmareg
,
DSP_MIXER_DATA
(
dev
->
base_addr
));
realdma
=
inb
(
DSP_MIXER_DATA
(
dev
->
base_addr
));
restore_flags
(
flags
);
if
((
~
realirq
)
&
irqreg
||
(
~
realdma
)
&
dmareg
)
{
printk
(
KERN_ERR
"%s: sbc resource registers cannot be set; PnP device "
"and IRQ/DMA specified wrongly?
\n
"
,
sm_drvname
);
return
-
EINVAL
;
}
return
0
;
}
/* --------------------------------------------------------------------- */
static
void
inline
sbc_int_ack_8bit
(
struct
net_device
*
dev
)
{
inb
(
DSP_DATA_AVAIL
(
dev
->
base_addr
));
}
/* --------------------------------------------------------------------- */
static
void
inline
sbc_int_ack_16bit
(
struct
net_device
*
dev
)
{
inb
(
DSP_INTACK_16BIT
(
dev
->
base_addr
));
}
/* --------------------------------------------------------------------- */
static
void
setup_dma_dsp
(
struct
net_device
*
dev
,
struct
sm_state
*
sm
,
int
send
)
{
unsigned
long
flags
;
static
const
unsigned
char
sbcmode
[
2
][
2
]
=
{
{
SBC_LO_INPUT_AUTOINIT
,
SBC_LO_OUTPUT_AUTOINIT
},
{
SBC_HI_INPUT_AUTOINIT
,
SBC_HI_OUTPUT_AUTOINIT
}
};
static
const
unsigned
char
sbc4mode
[
2
]
=
{
SBC4_IN8_AI
,
SBC4_OUT8_AI
};
static
const
unsigned
char
sbcskr
[
2
]
=
{
SBC_SPEAKER_OFF
,
SBC_SPEAKER_ON
};
unsigned
int
nsamps
;
send
=
!!
send
;
if
(
!
reset_dsp
(
dev
))
{
printk
(
KERN_ERR
"%s: sbc: cannot reset sb dsp
\n
"
,
sm_drvname
);
return
;
}
save_flags
(
flags
);
cli
();
sbc_int_ack_8bit
(
dev
);
write_dsp
(
dev
,
SBC_SAMPLE_RATE
);
/* set sampling rate */
write_dsp
(
dev
,
SCSTATE
->
fmt
[
send
]);
write_dsp
(
dev
,
sbcskr
[
send
]);
nsamps
=
dma_setup
(
sm
,
send
,
dev
->
dma
)
-
1
;
sbc_int_ack_8bit
(
dev
);
if
(
SCSTATE
->
revhi
>=
4
)
{
write_dsp
(
dev
,
sbc4mode
[
send
]);
write_dsp
(
dev
,
SBC4_MODE_UNS_MONO
);
write_dsp
(
dev
,
nsamps
&
0xff
);
write_dsp
(
dev
,
nsamps
>>
8
);
}
else
{
write_dsp
(
dev
,
SBC_BLOCKSIZE
);
write_dsp
(
dev
,
nsamps
&
0xff
);
write_dsp
(
dev
,
nsamps
>>
8
);
write_dsp
(
dev
,
sbcmode
[
SCSTATE
->
fmt
[
send
]
>=
180
][
send
]);
/* hispeed mode if sample rate > 13kHz */
}
restore_flags
(
flags
);
}
/* --------------------------------------------------------------------- */
static
void
sbc_interrupt
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
{
struct
net_device
*
dev
=
(
struct
net_device
*
)
dev_id
;
struct
sm_state
*
sm
=
(
struct
sm_state
*
)
dev
->
priv
;
unsigned
int
curfrag
;
if
(
!
dev
||
!
sm
||
sm
->
hdrv
.
magic
!=
HDLCDRV_MAGIC
)
return
;
cli
();
sbc_int_ack_8bit
(
dev
);
disable_dma
(
dev
->
dma
);
clear_dma_ff
(
dev
->
dma
);
dma_ptr
(
sm
,
sm
->
dma
.
ptt_cnt
>
0
,
dev
->
dma
,
&
curfrag
);
enable_dma
(
dev
->
dma
);
sm_int_freq
(
sm
);
sti
();
if
(
sm
->
dma
.
ptt_cnt
<=
0
)
{
dma_receive
(
sm
,
curfrag
);
hdlcdrv_arbitrate
(
dev
,
&
sm
->
hdrv
);
if
(
hdlcdrv_ptt
(
&
sm
->
hdrv
))
{
/* starting to transmit */
disable_dma
(
dev
->
dma
);
hdlcdrv_transmitter
(
dev
,
&
sm
->
hdrv
);
/* prefill HDLC buffer */
dma_start_transmit
(
sm
);
setup_dma_dsp
(
dev
,
sm
,
1
);
dma_transmit
(
sm
);
}
}
else
if
(
dma_end_transmit
(
sm
,
curfrag
))
{
/* stopping transmission */
disable_dma
(
dev
->
dma
);
sti
();
dma_init_receive
(
sm
);
setup_dma_dsp
(
dev
,
sm
,
0
);
}
else
dma_transmit
(
sm
);
sm_output_status
(
sm
);
hdlcdrv_transmitter
(
dev
,
&
sm
->
hdrv
);
hdlcdrv_receiver
(
dev
,
&
sm
->
hdrv
);
}
/* --------------------------------------------------------------------- */
static
int
sbc_open
(
struct
net_device
*
dev
,
struct
sm_state
*
sm
)
{
int
err
;
unsigned
int
dmasz
,
u
;
if
(
sizeof
(
sm
->
m
)
<
sizeof
(
struct
sc_state_sbc
))
{
printk
(
KERN_ERR
"sm sbc: sbc state too big: %d > %d
\n
"
,
sizeof
(
struct
sc_state_sbc
),
sizeof
(
sm
->
m
));
return
-
ENODEV
;
}
if
(
!
dev
||
!
sm
)
return
-
ENXIO
;
if
(
dev
->
base_addr
<=
0
||
dev
->
base_addr
>
0x1000
-
SBC_EXTENT
||
dev
->
irq
<
2
||
dev
->
irq
>
15
||
dev
->
dma
>
3
)
return
-
ENXIO
;
if
(
check_region
(
dev
->
base_addr
,
SBC_EXTENT
))
return
-
EACCES
;
/*
* check if a card is available
*/
if
(
!
reset_dsp
(
dev
))
{
printk
(
KERN_ERR
"%s: sbc: no card at io address 0x%lx
\n
"
,
sm_drvname
,
dev
->
base_addr
);
return
-
ENODEV
;
}
write_dsp
(
dev
,
SBC_GET_REVISION
);
if
(
!
read_dsp
(
dev
,
&
SCSTATE
->
revhi
)
||
!
read_dsp
(
dev
,
&
SCSTATE
->
revlo
))
return
-
ENODEV
;
printk
(
KERN_INFO
"%s: SoundBlaster DSP revision %d.%d
\n
"
,
sm_drvname
,
SCSTATE
->
revhi
,
SCSTATE
->
revlo
);
if
(
SCSTATE
->
revhi
<
2
)
{
printk
(
KERN_ERR
"%s: your card is an antiquity, at least DSP "
"rev 2.00 required
\n
"
,
sm_drvname
);
return
-
ENODEV
;
}
if
(
SCSTATE
->
revhi
<
3
&&
(
SCSTATE
->
fmt
[
0
]
>=
180
||
SCSTATE
->
fmt
[
1
]
>=
180
))
{
printk
(
KERN_ERR
"%s: sbc io 0x%lx: DSP rev %d.%02d too "
"old, at least 3.00 required
\n
"
,
sm_drvname
,
dev
->
base_addr
,
SCSTATE
->
revhi
,
SCSTATE
->
revlo
);
return
-
ENODEV
;
}
if
(
SCSTATE
->
revhi
>=
4
&&
(
err
=
config_resources
(
dev
,
sm
,
0
)))
{
printk
(
KERN_ERR
"%s: invalid IRQ and/or DMA specified
\n
"
,
sm_drvname
);
return
err
;
}
/*
* initialize some variables
*/
dma_init_receive
(
sm
);
dmasz
=
(
NUM_FRAGMENTS
+
1
)
*
sm
->
dma
.
ifragsz
;
u
=
NUM_FRAGMENTS
*
sm
->
dma
.
ofragsz
;
if
(
u
>
dmasz
)
dmasz
=
u
;
if
(
!
(
sm
->
dma
.
ibuf
=
sm
->
dma
.
obuf
=
kmalloc
(
dmasz
,
GFP_KERNEL
|
GFP_DMA
)))
return
-
ENOMEM
;
dma_init_transmit
(
sm
);
dma_init_receive
(
sm
);
memset
(
&
sm
->
m
,
0
,
sizeof
(
sm
->
m
));
memset
(
&
sm
->
d
,
0
,
sizeof
(
sm
->
d
));
if
(
sm
->
mode_tx
->
init
)
sm
->
mode_tx
->
init
(
sm
);
if
(
sm
->
mode_rx
->
init
)
sm
->
mode_rx
->
init
(
sm
);
if
(
request_dma
(
dev
->
dma
,
sm
->
hwdrv
->
hw_name
))
{
kfree
(
sm
->
dma
.
obuf
);
return
-
EBUSY
;
}
if
(
request_irq
(
dev
->
irq
,
sbc_interrupt
,
SA_INTERRUPT
,
sm
->
hwdrv
->
hw_name
,
dev
))
{
free_dma
(
dev
->
dma
);
kfree
(
sm
->
dma
.
obuf
);
return
-
EBUSY
;
}
request_region
(
dev
->
base_addr
,
SBC_EXTENT
,
sm
->
hwdrv
->
hw_name
);
setup_dma_dsp
(
dev
,
sm
,
0
);
return
0
;
}
/* --------------------------------------------------------------------- */
static
int
sbc_close
(
struct
net_device
*
dev
,
struct
sm_state
*
sm
)
{
if
(
!
dev
||
!
sm
)
return
-
EINVAL
;
/*
* disable interrupts
*/
disable_dma
(
dev
->
dma
);
reset_dsp
(
dev
);
free_irq
(
dev
->
irq
,
dev
);
free_dma
(
dev
->
dma
);
release_region
(
dev
->
base_addr
,
SBC_EXTENT
);
kfree
(
sm
->
dma
.
obuf
);
return
0
;
}
/* --------------------------------------------------------------------- */
static
int
sbc_sethw
(
struct
net_device
*
dev
,
struct
sm_state
*
sm
,
char
*
mode
)
{
char
*
cp
=
strchr
(
mode
,
'.'
);
const
struct
modem_tx_info
**
mtp
=
sm_modem_tx_table
;
const
struct
modem_rx_info
**
mrp
;
if
(
!
strcmp
(
mode
,
"off"
))
{
sm
->
mode_tx
=
NULL
;
sm
->
mode_rx
=
NULL
;
return
0
;
}
if
(
cp
)
*
cp
++
=
'\0'
;
else
cp
=
mode
;
for
(;
*
mtp
;
mtp
++
)
{
if
((
*
mtp
)
->
loc_storage
>
sizeof
(
sm
->
m
))
{
printk
(
KERN_ERR
"%s: insufficient storage for modulator %s (%d)
\n
"
,
sm_drvname
,
(
*
mtp
)
->
name
,
(
*
mtp
)
->
loc_storage
);
continue
;
}
if
(
!
(
*
mtp
)
->
name
||
strcmp
((
*
mtp
)
->
name
,
mode
))
continue
;
if
((
*
mtp
)
->
srate
<
5000
||
(
*
mtp
)
->
srate
>
44100
)
continue
;
if
(
!
(
*
mtp
)
->
modulator_u8
)
continue
;
for
(
mrp
=
sm_modem_rx_table
;
*
mrp
;
mrp
++
)
{
if
((
*
mrp
)
->
loc_storage
>
sizeof
(
sm
->
d
))
{
printk
(
KERN_ERR
"%s: insufficient storage for demodulator %s (%d)
\n
"
,
sm_drvname
,
(
*
mrp
)
->
name
,
(
*
mrp
)
->
loc_storage
);
continue
;
}
if
(
!
(
*
mrp
)
->
demodulator_u8
)
continue
;
if
((
*
mrp
)
->
name
&&
!
strcmp
((
*
mrp
)
->
name
,
cp
)
&&
(
*
mrp
)
->
srate
>=
5000
&&
(
*
mrp
)
->
srate
<=
44100
)
{
sm
->
mode_tx
=
*
mtp
;
sm
->
mode_rx
=
*
mrp
;
SCSTATE
->
fmt
[
0
]
=
256
-
((
1000000L
+
sm
->
mode_rx
->
srate
/
2
)
/
sm
->
mode_rx
->
srate
);
SCSTATE
->
fmt
[
1
]
=
256
-
((
1000000L
+
sm
->
mode_tx
->
srate
/
2
)
/
sm
->
mode_tx
->
srate
);
sm
->
dma
.
ifragsz
=
(
sm
->
mode_rx
->
srate
+
50
)
/
100
;
sm
->
dma
.
ofragsz
=
(
sm
->
mode_tx
->
srate
+
50
)
/
100
;
if
(
sm
->
dma
.
ifragsz
<
sm
->
mode_rx
->
overlap
)
sm
->
dma
.
ifragsz
=
sm
->
mode_rx
->
overlap
;
sm
->
dma
.
i16bit
=
sm
->
dma
.
o16bit
=
0
;
return
0
;
}
}
}
return
-
EINVAL
;
}
/* --------------------------------------------------------------------- */
static
int
sbc_ioctl
(
struct
net_device
*
dev
,
struct
sm_state
*
sm
,
struct
ifreq
*
ifr
,
struct
hdlcdrv_ioctl
*
hi
,
int
cmd
)
{
struct
sm_ioctl
bi
;
unsigned
long
flags
;
int
i
;
if
(
cmd
!=
SIOCDEVPRIVATE
)
return
-
ENOIOCTLCMD
;
if
(
hi
->
cmd
==
HDLCDRVCTL_MODEMPARMASK
)
return
HDLCDRV_PARMASK_IOBASE
|
HDLCDRV_PARMASK_IRQ
|
HDLCDRV_PARMASK_DMA
|
HDLCDRV_PARMASK_SERIOBASE
|
HDLCDRV_PARMASK_PARIOBASE
|
HDLCDRV_PARMASK_MIDIIOBASE
;
if
(
copy_from_user
(
&
bi
,
ifr
->
ifr_data
,
sizeof
(
bi
)))
return
-
EFAULT
;
switch
(
bi
.
cmd
)
{
default:
return
-
ENOIOCTLCMD
;
case
SMCTL_GETMIXER
:
i
=
0
;
bi
.
data
.
mix
.
sample_rate
=
sm
->
mode_rx
->
srate
;
bi
.
data
.
mix
.
bit_rate
=
sm
->
hdrv
.
par
.
bitrate
;
bi
.
data
.
mix
.
mixer_type
=
SM_MIXER_INVALID
;
switch
(
SCSTATE
->
revhi
)
{
case
2
:
bi
.
data
.
mix
.
mixer_type
=
SM_MIXER_CT1335
;
break
;
case
3
:
bi
.
data
.
mix
.
mixer_type
=
SM_MIXER_CT1345
;
break
;
case
4
:
bi
.
data
.
mix
.
mixer_type
=
SM_MIXER_CT1745
;
break
;
}
if
(
bi
.
data
.
mix
.
mixer_type
!=
SM_MIXER_INVALID
&&
bi
.
data
.
mix
.
reg
<
0x80
)
{
save_flags
(
flags
);
cli
();
outb
(
bi
.
data
.
mix
.
reg
,
DSP_MIXER_ADDR
(
dev
->
base_addr
));
bi
.
data
.
mix
.
data
=
inb
(
DSP_MIXER_DATA
(
dev
->
base_addr
));
restore_flags
(
flags
);
i
=
1
;
}
if
(
copy_to_user
(
ifr
->
ifr_data
,
&
bi
,
sizeof
(
bi
)))
return
-
EFAULT
;
return
i
;
case
SMCTL_SETMIXER
:
if
(
!
capable
(
CAP_SYS_RAWIO
))
return
-
EACCES
;
switch
(
SCSTATE
->
revhi
)
{
case
2
:
if
(
bi
.
data
.
mix
.
mixer_type
!=
SM_MIXER_CT1335
)
return
-
EINVAL
;
break
;
case
3
:
if
(
bi
.
data
.
mix
.
mixer_type
!=
SM_MIXER_CT1345
)
return
-
EINVAL
;
break
;
case
4
:
if
(
bi
.
data
.
mix
.
mixer_type
!=
SM_MIXER_CT1745
)
return
-
EINVAL
;
break
;
default:
return
-
ENODEV
;
}
if
(
bi
.
data
.
mix
.
reg
>=
0x80
)
return
-
EACCES
;
save_flags
(
flags
);
cli
();
outb
(
bi
.
data
.
mix
.
reg
,
DSP_MIXER_ADDR
(
dev
->
base_addr
));
outb
(
bi
.
data
.
mix
.
data
,
DSP_MIXER_DATA
(
dev
->
base_addr
));
restore_flags
(
flags
);
return
0
;
}
if
(
copy_to_user
(
ifr
->
ifr_data
,
&
bi
,
sizeof
(
bi
)))
return
-
EFAULT
;
return
0
;
}
/* --------------------------------------------------------------------- */
const
struct
hardware_info
sm_hw_sbc
=
{
"sbc"
,
sizeof
(
struct
sc_state_sbc
),
sbc_open
,
sbc_close
,
sbc_ioctl
,
sbc_sethw
};
/* --------------------------------------------------------------------- */
static
void
setup_dma_fdx_dsp
(
struct
net_device
*
dev
,
struct
sm_state
*
sm
)
{
unsigned
long
flags
;
unsigned
int
isamps
,
osamps
;
if
(
!
reset_dsp
(
dev
))
{
printk
(
KERN_ERR
"%s: sbc: cannot reset sb dsp
\n
"
,
sm_drvname
);
return
;
}
save_flags
(
flags
);
cli
();
sbc_int_ack_8bit
(
dev
);
sbc_int_ack_16bit
(
dev
);
/* should eventually change to set rates individually by SBC_SAMPLE_RATE_{IN/OUT} */
write_dsp
(
dev
,
SBC_SAMPLE_RATE_IN
);
write_dsp
(
dev
,
SCSTATE
->
sr
[
0
]
>>
8
);
write_dsp
(
dev
,
SCSTATE
->
sr
[
0
]
&
0xff
);
write_dsp
(
dev
,
SBC_SAMPLE_RATE_OUT
);
write_dsp
(
dev
,
SCSTATE
->
sr
[
1
]
>>
8
);
write_dsp
(
dev
,
SCSTATE
->
sr
[
1
]
&
0xff
);
write_dsp
(
dev
,
SBC_SPEAKER_ON
);
if
(
sm
->
dma
.
o16bit
)
{
/*
* DMA channel 1 (8bit) does input (capture),
* DMA channel 2 (16bit) does output (playback)
*/
isamps
=
dma_setup
(
sm
,
0
,
dev
->
dma
)
-
1
;
osamps
=
dma_setup
(
sm
,
1
,
sm
->
hdrv
.
ptt_out
.
dma2
)
-
1
;
sbc_int_ack_8bit
(
dev
);
sbc_int_ack_16bit
(
dev
);
write_dsp
(
dev
,
SBC4_IN8_AI
);
write_dsp
(
dev
,
SBC4_MODE_UNS_MONO
);
write_dsp
(
dev
,
isamps
&
0xff
);
write_dsp
(
dev
,
isamps
>>
8
);
write_dsp
(
dev
,
SBC4_OUT16_AI
);
write_dsp
(
dev
,
SBC4_MODE_SIGN_MONO
);
write_dsp
(
dev
,
osamps
&
0xff
);
write_dsp
(
dev
,
osamps
>>
8
);
}
else
{
/*
* DMA channel 1 (8bit) does output (playback),
* DMA channel 2 (16bit) does input (capture)
*/
isamps
=
dma_setup
(
sm
,
0
,
sm
->
hdrv
.
ptt_out
.
dma2
)
-
1
;
osamps
=
dma_setup
(
sm
,
1
,
dev
->
dma
)
-
1
;
sbc_int_ack_8bit
(
dev
);
sbc_int_ack_16bit
(
dev
);
write_dsp
(
dev
,
SBC4_OUT8_AI
);
write_dsp
(
dev
,
SBC4_MODE_UNS_MONO
);
write_dsp
(
dev
,
osamps
&
0xff
);
write_dsp
(
dev
,
osamps
>>
8
);
write_dsp
(
dev
,
SBC4_IN16_AI
);
write_dsp
(
dev
,
SBC4_MODE_SIGN_MONO
);
write_dsp
(
dev
,
isamps
&
0xff
);
write_dsp
(
dev
,
isamps
>>
8
);
}
dma_init_receive
(
sm
);
dma_init_transmit
(
sm
);
restore_flags
(
flags
);
}
/* --------------------------------------------------------------------- */
static
void
sbcfdx_interrupt
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
{
struct
net_device
*
dev
=
(
struct
net_device
*
)
dev_id
;
struct
sm_state
*
sm
=
(
struct
sm_state
*
)
dev
->
priv
;
unsigned
char
intsrc
,
pbint
=
0
,
captint
=
0
;
unsigned
int
ocfrag
,
icfrag
;
unsigned
long
flags
;
if
(
!
dev
||
!
sm
||
sm
->
hdrv
.
magic
!=
HDLCDRV_MAGIC
)
return
;
save_flags
(
flags
);
cli
();
outb
(
0x82
,
DSP_MIXER_ADDR
(
dev
->
base_addr
));
intsrc
=
inb
(
DSP_MIXER_DATA
(
dev
->
base_addr
));
if
(
intsrc
&
0x01
)
{
sbc_int_ack_8bit
(
dev
);
if
(
sm
->
dma
.
o16bit
)
{
captint
=
1
;
disable_dma
(
dev
->
dma
);
clear_dma_ff
(
dev
->
dma
);
dma_ptr
(
sm
,
0
,
dev
->
dma
,
&
icfrag
);
enable_dma
(
dev
->
dma
);
}
else
{
pbint
=
1
;
disable_dma
(
dev
->
dma
);
clear_dma_ff
(
dev
->
dma
);
dma_ptr
(
sm
,
1
,
dev
->
dma
,
&
ocfrag
);
enable_dma
(
dev
->
dma
);
}
}
if
(
intsrc
&
0x02
)
{
sbc_int_ack_16bit
(
dev
);
if
(
sm
->
dma
.
o16bit
)
{
pbint
=
1
;
disable_dma
(
sm
->
hdrv
.
ptt_out
.
dma2
);
clear_dma_ff
(
sm
->
hdrv
.
ptt_out
.
dma2
);
dma_ptr
(
sm
,
1
,
sm
->
hdrv
.
ptt_out
.
dma2
,
&
ocfrag
);
enable_dma
(
sm
->
hdrv
.
ptt_out
.
dma2
);
}
else
{
captint
=
1
;
disable_dma
(
sm
->
hdrv
.
ptt_out
.
dma2
);
clear_dma_ff
(
sm
->
hdrv
.
ptt_out
.
dma2
);
dma_ptr
(
sm
,
0
,
sm
->
hdrv
.
ptt_out
.
dma2
,
&
icfrag
);
enable_dma
(
sm
->
hdrv
.
ptt_out
.
dma2
);
}
}
restore_flags
(
flags
);
sm_int_freq
(
sm
);
sti
();
if
(
pbint
)
{
if
(
dma_end_transmit
(
sm
,
ocfrag
))
dma_clear_transmit
(
sm
);
dma_transmit
(
sm
);
}
if
(
captint
)
{
dma_receive
(
sm
,
icfrag
);
hdlcdrv_arbitrate
(
dev
,
&
sm
->
hdrv
);
}
sm_output_status
(
sm
);
hdlcdrv_transmitter
(
dev
,
&
sm
->
hdrv
);
hdlcdrv_receiver
(
dev
,
&
sm
->
hdrv
);
}
/* --------------------------------------------------------------------- */
static
int
sbcfdx_open
(
struct
net_device
*
dev
,
struct
sm_state
*
sm
)
{
int
err
;
if
(
sizeof
(
sm
->
m
)
<
sizeof
(
struct
sc_state_sbc
))
{
printk
(
KERN_ERR
"sm sbc: sbc state too big: %d > %d
\n
"
,
sizeof
(
struct
sc_state_sbc
),
sizeof
(
sm
->
m
));
return
-
ENODEV
;
}
if
(
!
dev
||
!
sm
)
return
-
ENXIO
;
if
(
dev
->
base_addr
<=
0
||
dev
->
base_addr
>
0x1000
-
SBC_EXTENT
||
dev
->
irq
<
2
||
dev
->
irq
>
15
||
dev
->
dma
>
3
)
return
-
ENXIO
;
if
(
check_region
(
dev
->
base_addr
,
SBC_EXTENT
))
return
-
EACCES
;
/*
* check if a card is available
*/
if
(
!
reset_dsp
(
dev
))
{
printk
(
KERN_ERR
"%s: sbc: no card at io address 0x%lx
\n
"
,
sm_drvname
,
dev
->
base_addr
);
return
-
ENODEV
;
}
write_dsp
(
dev
,
SBC_GET_REVISION
);
if
(
!
read_dsp
(
dev
,
&
SCSTATE
->
revhi
)
||
!
read_dsp
(
dev
,
&
SCSTATE
->
revlo
))
return
-
ENODEV
;
printk
(
KERN_INFO
"%s: SoundBlaster DSP revision %d.%d
\n
"
,
sm_drvname
,
SCSTATE
->
revhi
,
SCSTATE
->
revlo
);
if
(
SCSTATE
->
revhi
<
4
)
{
printk
(
KERN_ERR
"%s: at least DSP rev 4.00 required
\n
"
,
sm_drvname
);
return
-
ENODEV
;
}
if
((
err
=
config_resources
(
dev
,
sm
,
1
)))
{
printk
(
KERN_ERR
"%s: invalid IRQ and/or DMA specified
\n
"
,
sm_drvname
);
return
err
;
}
/*
* initialize some variables
*/
if
(
!
(
sm
->
dma
.
ibuf
=
kmalloc
(
sm
->
dma
.
ifragsz
*
(
NUM_FRAGMENTS
+
1
),
GFP_KERNEL
|
GFP_DMA
)))
return
-
ENOMEM
;
if
(
!
(
sm
->
dma
.
obuf
=
kmalloc
(
sm
->
dma
.
ofragsz
*
NUM_FRAGMENTS
,
GFP_KERNEL
|
GFP_DMA
)))
{
kfree
(
sm
->
dma
.
ibuf
);
return
-
ENOMEM
;
}
dma_init_transmit
(
sm
);
dma_init_receive
(
sm
);
memset
(
&
sm
->
m
,
0
,
sizeof
(
sm
->
m
));
memset
(
&
sm
->
d
,
0
,
sizeof
(
sm
->
d
));
if
(
sm
->
mode_tx
->
init
)
sm
->
mode_tx
->
init
(
sm
);
if
(
sm
->
mode_rx
->
init
)
sm
->
mode_rx
->
init
(
sm
);
if
(
request_dma
(
dev
->
dma
,
sm
->
hwdrv
->
hw_name
))
{
kfree
(
sm
->
dma
.
ibuf
);
kfree
(
sm
->
dma
.
obuf
);
return
-
EBUSY
;
}
if
(
request_dma
(
sm
->
hdrv
.
ptt_out
.
dma2
,
sm
->
hwdrv
->
hw_name
))
{
kfree
(
sm
->
dma
.
ibuf
);
kfree
(
sm
->
dma
.
obuf
);
free_dma
(
dev
->
dma
);
return
-
EBUSY
;
}
if
(
request_irq
(
dev
->
irq
,
sbcfdx_interrupt
,
SA_INTERRUPT
,
sm
->
hwdrv
->
hw_name
,
dev
))
{
kfree
(
sm
->
dma
.
ibuf
);
kfree
(
sm
->
dma
.
obuf
);
free_dma
(
dev
->
dma
);
free_dma
(
sm
->
hdrv
.
ptt_out
.
dma2
);
return
-
EBUSY
;
}
request_region
(
dev
->
base_addr
,
SBC_EXTENT
,
sm
->
hwdrv
->
hw_name
);
setup_dma_fdx_dsp
(
dev
,
sm
);
return
0
;
}
/* --------------------------------------------------------------------- */
static
int
sbcfdx_close
(
struct
net_device
*
dev
,
struct
sm_state
*
sm
)
{
if
(
!
dev
||
!
sm
)
return
-
EINVAL
;
/*
* disable interrupts
*/
disable_dma
(
dev
->
dma
);
disable_dma
(
sm
->
hdrv
.
ptt_out
.
dma2
);
reset_dsp
(
dev
);
free_irq
(
dev
->
irq
,
dev
);
free_dma
(
dev
->
dma
);
free_dma
(
sm
->
hdrv
.
ptt_out
.
dma2
);
release_region
(
dev
->
base_addr
,
SBC_EXTENT
);
kfree
(
sm
->
dma
.
ibuf
);
kfree
(
sm
->
dma
.
obuf
);
return
0
;
}
/* --------------------------------------------------------------------- */
static
int
sbcfdx_sethw
(
struct
net_device
*
dev
,
struct
sm_state
*
sm
,
char
*
mode
)
{
char
*
cp
=
strchr
(
mode
,
'.'
);
const
struct
modem_tx_info
**
mtp
=
sm_modem_tx_table
;
const
struct
modem_rx_info
**
mrp
;
if
(
!
strcmp
(
mode
,
"off"
))
{
sm
->
mode_tx
=
NULL
;
sm
->
mode_rx
=
NULL
;
return
0
;
}
if
(
cp
)
*
cp
++
=
'\0'
;
else
cp
=
mode
;
for
(;
*
mtp
;
mtp
++
)
{
if
((
*
mtp
)
->
loc_storage
>
sizeof
(
sm
->
m
))
{
printk
(
KERN_ERR
"%s: insufficient storage for modulator %s (%d)
\n
"
,
sm_drvname
,
(
*
mtp
)
->
name
,
(
*
mtp
)
->
loc_storage
);
continue
;
}
if
(
!
(
*
mtp
)
->
name
||
strcmp
((
*
mtp
)
->
name
,
mode
))
continue
;
if
((
*
mtp
)
->
srate
<
5000
||
(
*
mtp
)
->
srate
>
44100
)
continue
;
for
(
mrp
=
sm_modem_rx_table
;
*
mrp
;
mrp
++
)
{
if
((
*
mrp
)
->
loc_storage
>
sizeof
(
sm
->
d
))
{
printk
(
KERN_ERR
"%s: insufficient storage for demodulator %s (%d)
\n
"
,
sm_drvname
,
(
*
mrp
)
->
name
,
(
*
mrp
)
->
loc_storage
);
continue
;
}
if
((
*
mrp
)
->
name
&&
!
strcmp
((
*
mrp
)
->
name
,
cp
)
&&
(
*
mtp
)
->
srate
>=
5000
&&
(
*
mtp
)
->
srate
<=
44100
&&
(
*
mrp
)
->
srate
==
(
*
mtp
)
->
srate
)
{
sm
->
mode_tx
=
*
mtp
;
sm
->
mode_rx
=
*
mrp
;
SCSTATE
->
sr
[
0
]
=
sm
->
mode_rx
->
srate
;
SCSTATE
->
sr
[
1
]
=
sm
->
mode_tx
->
srate
;
sm
->
dma
.
ifragsz
=
(
sm
->
mode_rx
->
srate
+
50
)
/
100
;
sm
->
dma
.
ofragsz
=
(
sm
->
mode_tx
->
srate
+
50
)
/
100
;
if
(
sm
->
dma
.
ifragsz
<
sm
->
mode_rx
->
overlap
)
sm
->
dma
.
ifragsz
=
sm
->
mode_rx
->
overlap
;
if
(
sm
->
mode_rx
->
demodulator_s16
&&
sm
->
mode_tx
->
modulator_u8
)
{
sm
->
dma
.
i16bit
=
1
;
sm
->
dma
.
o16bit
=
0
;
sm
->
dma
.
ifragsz
<<=
1
;
}
else
if
(
sm
->
mode_rx
->
demodulator_u8
&&
sm
->
mode_tx
->
modulator_s16
)
{
sm
->
dma
.
i16bit
=
0
;
sm
->
dma
.
o16bit
=
1
;
sm
->
dma
.
ofragsz
<<=
1
;
}
else
{
printk
(
KERN_INFO
"%s: mode %s or %s unusable
\n
"
,
sm_drvname
,
sm
->
mode_rx
->
name
,
sm
->
mode_tx
->
name
);
sm
->
mode_tx
=
NULL
;
sm
->
mode_rx
=
NULL
;
return
-
EINVAL
;
}
return
0
;
}
}
}
return
-
EINVAL
;
}
/* --------------------------------------------------------------------- */
static
int
sbcfdx_ioctl
(
struct
net_device
*
dev
,
struct
sm_state
*
sm
,
struct
ifreq
*
ifr
,
struct
hdlcdrv_ioctl
*
hi
,
int
cmd
)
{
if
(
cmd
!=
SIOCDEVPRIVATE
)
return
-
ENOIOCTLCMD
;
if
(
hi
->
cmd
==
HDLCDRVCTL_MODEMPARMASK
)
return
HDLCDRV_PARMASK_IOBASE
|
HDLCDRV_PARMASK_IRQ
|
HDLCDRV_PARMASK_DMA
|
HDLCDRV_PARMASK_DMA2
|
HDLCDRV_PARMASK_SERIOBASE
|
HDLCDRV_PARMASK_PARIOBASE
|
HDLCDRV_PARMASK_MIDIIOBASE
;
return
sbc_ioctl
(
dev
,
sm
,
ifr
,
hi
,
cmd
);
}
/* --------------------------------------------------------------------- */
const
struct
hardware_info
sm_hw_sbcfdx
=
{
"sbcfdx"
,
sizeof
(
struct
sc_state_sbc
),
sbcfdx_open
,
sbcfdx_close
,
sbcfdx_ioctl
,
sbcfdx_sethw
};
/* --------------------------------------------------------------------- */
drivers/net/hamradio/soundmodem/sm_wss.c
deleted
100644 → 0
View file @
a994c542
/*****************************************************************************/
/*
* sm_wss.c -- soundcard radio modem driver, WSS (half duplex) driver
*
* 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.
*
*/
#include <linux/ptrace.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/soundmodem.h>
#include <asm/io.h>
#include <asm/dma.h>
#include "sm.h"
#include "smdma.h"
/* --------------------------------------------------------------------- */
/*
* currently this module is supposed to support both module styles, i.e.
* the old one present up to about 2.1.9, and the new one functioning
* starting with 2.1.21. The reason is I have a kit allowing to compile
* this module also under 2.0.x which was requested by several people.
* This will go in 2.2
*/
#include <linux/version.h>
#if LINUX_VERSION_CODE >= 0x20100
#include <asm/uaccess.h>
#else
#include <asm/segment.h>
#include <linux/mm.h>
#undef put_user
#undef get_user
#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
static
inline
int
copy_from_user
(
void
*
to
,
const
void
*
from
,
unsigned
long
n
)
{
int
i
=
verify_area
(
VERIFY_READ
,
from
,
n
);
if
(
i
)
return
i
;
memcpy_fromfs
(
to
,
from
,
n
);
return
0
;
}
static
inline
int
copy_to_user
(
void
*
to
,
const
void
*
from
,
unsigned
long
n
)
{
int
i
=
verify_area
(
VERIFY_WRITE
,
to
,
n
);
if
(
i
)
return
i
;
memcpy_tofs
(
to
,
from
,
n
);
return
0
;
}
#endif
/* --------------------------------------------------------------------- */
struct
sc_state_wss
{
unsigned
char
revwss
,
revid
,
revv
,
revcid
;
unsigned
char
fmt
[
2
];
unsigned
char
crystal
;
};
#define SCSTATE ((struct sc_state_wss *)(&sm->hw))
/* --------------------------------------------------------------------- */
#define WSS_CONFIG(iobase) (iobase+0)
#define WSS_STATUS(iobase) (iobase+3)
#define WSS_CODEC_IA(iobase) (iobase+4)
#define WSS_CODEC_ID(iobase) (iobase+5)
#define WSS_CODEC_STATUS(iobase) (iobase+6)
#define WSS_CODEC_DATA(iobase) (iobase+7)
#define WSS_EXTENT 8
#define CS423X_HOTFIX
/* --------------------------------------------------------------------- */
static
void
write_codec
(
struct
net_device
*
dev
,
unsigned
char
idx
,
unsigned
char
data
)
{
int
timeout
=
900000
;
/* wait until codec ready */
while
(
timeout
>
0
&&
inb
(
WSS_CODEC_IA
(
dev
->
base_addr
))
&
0x80
)
timeout
--
;
outb
(
idx
,
WSS_CODEC_IA
(
dev
->
base_addr
));
outb
(
data
,
WSS_CODEC_ID
(
dev
->
base_addr
));
}
/* --------------------------------------------------------------------- */
static
unsigned
char
read_codec
(
struct
net_device
*
dev
,
unsigned
char
idx
)
{
int
timeout
=
900000
;
/* wait until codec ready */
while
(
timeout
>
0
&&
inb
(
WSS_CODEC_IA
(
dev
->
base_addr
))
&
0x80
)
timeout
--
;
outb
(
idx
&
0x1f
,
WSS_CODEC_IA
(
dev
->
base_addr
));
return
inb
(
WSS_CODEC_ID
(
dev
->
base_addr
));
}
/* --------------------------------------------------------------------- */
extern
void
inline
wss_ack_int
(
struct
net_device
*
dev
)
{
outb
(
0
,
WSS_CODEC_STATUS
(
dev
->
base_addr
));
}
/* --------------------------------------------------------------------- */
static
int
wss_srate_tab
[
16
]
=
{
8000
,
5510
,
16000
,
11025
,
27420
,
18900
,
32000
,
22050
,
-
1
,
37800
,
-
1
,
44100
,
48000
,
33075
,
9600
,
6620
};
static
int
wss_srate_index
(
int
srate
)
{
int
i
;
for
(
i
=
0
;
i
<
(
sizeof
(
wss_srate_tab
)
/
sizeof
(
wss_srate_tab
[
0
]));
i
++
)
if
(
srate
==
wss_srate_tab
[
i
]
&&
wss_srate_tab
[
i
]
>
0
)
return
i
;
return
-
1
;
}
/* --------------------------------------------------------------------- */
static
int
wss_set_codec_fmt
(
struct
net_device
*
dev
,
struct
sm_state
*
sm
,
unsigned
char
fmt
,
unsigned
char
fmt2
,
char
fdx
,
char
fullcalib
)
{
unsigned
long
time
;
unsigned
long
flags
;
save_flags
(
flags
);
cli
();
/* Clock and data format register */
write_codec
(
dev
,
0x48
,
fmt
);
if
(
SCSTATE
->
crystal
)
{
write_codec
(
dev
,
0x5c
,
fmt2
&
0xf0
);
/* MCE and interface config reg */
write_codec
(
dev
,
0x49
,
(
fdx
?
0
:
0x4
)
|
(
fullcalib
?
0x18
:
0
));
}
else
/* MCE and interface config reg */
write_codec
(
dev
,
0x49
,
fdx
?
0x8
:
0xc
);
outb
(
0xb
,
WSS_CODEC_IA
(
dev
->
base_addr
));
/* leave MCE */
if
(
SCSTATE
->
crystal
&&
!
fullcalib
)
{
restore_flags
(
flags
);
return
0
;
}
/*
* wait for ACI start
*/
time
=
1000
;
while
(
!
(
read_codec
(
dev
,
0x0b
)
&
0x20
))
if
(
!
(
--
time
))
{
printk
(
KERN_WARNING
"%s: ad1848 auto calibration timed out (1)
\n
"
,
sm_drvname
);
restore_flags
(
flags
);
return
-
1
;
}
/*
* wait for ACI end
*/
sti
();
time
=
jiffies
+
HZ
/
4
;
while
((
read_codec
(
dev
,
0x0b
)
&
0x20
)
&&
((
signed
)(
jiffies
-
time
)
<
0
));
restore_flags
(
flags
);
if
((
signed
)(
jiffies
-
time
)
>=
0
)
{
printk
(
KERN_WARNING
"%s: ad1848 auto calibration timed out (2)
\n
"
,
sm_drvname
);
return
-
1
;
}
return
0
;
}
/* --------------------------------------------------------------------- */
static
int
wss_init_codec
(
struct
net_device
*
dev
,
struct
sm_state
*
sm
,
char
fdx
,
unsigned
char
src_l
,
unsigned
char
src_r
,
int
igain_l
,
int
igain_r
,
int
ogain_l
,
int
ogain_r
)
{
unsigned
char
tmp
,
reg0
,
reg1
,
reg6
,
reg7
;
static
const
signed
char
irqtab
[
16
]
=
{
-
1
,
-
1
,
0x10
,
-
1
,
-
1
,
-
1
,
-
1
,
0x08
,
-
1
,
0x10
,
0x18
,
0x20
,
-
1
,
-
1
,
-
1
,
-
1
};
static
const
signed
char
dmatab
[
4
]
=
{
1
,
2
,
-
1
,
3
};
tmp
=
inb
(
WSS_STATUS
(
dev
->
base_addr
));
if
((
tmp
&
0x3f
)
!=
0x04
&&
(
tmp
&
0x3f
)
!=
0x00
&&
(
tmp
&
0x3f
)
!=
0x0f
)
{
printk
(
KERN_WARNING
"sm: WSS card id register not found, "
"address 0x%lx, ID register 0x%02x
\n
"
,
dev
->
base_addr
,
(
int
)
tmp
);
/* return -1; */
SCSTATE
->
revwss
=
0
;
}
else
{
if
((
tmp
&
0x80
)
&&
((
dev
->
dma
==
0
)
||
((
dev
->
irq
>=
8
)
&&
(
dev
->
irq
!=
9
))))
{
printk
(
KERN_ERR
"%s: WSS: DMA0 and/or IRQ8..IRQ15 "
"(except IRQ9) cannot be used on an 8bit "
"card
\n
"
,
sm_drvname
);
return
-
1
;
}
if
(
dev
->
irq
>
15
||
irqtab
[
dev
->
irq
]
==
-
1
)
{
printk
(
KERN_ERR
"%s: WSS: invalid interrupt %d
\n
"
,
sm_drvname
,
(
int
)
dev
->
irq
);
return
-
1
;
}
if
(
dev
->
dma
>
3
||
dmatab
[
dev
->
dma
]
==
-
1
)
{
printk
(
KERN_ERR
"%s: WSS: invalid dma channel %d
\n
"
,
sm_drvname
,
(
int
)
dev
->
dma
);
return
-
1
;
}
tmp
=
irqtab
[
dev
->
irq
]
|
dmatab
[
dev
->
dma
];
/* irq probe */
outb
((
tmp
&
0x38
)
|
0x40
,
WSS_CONFIG
(
dev
->
base_addr
));
if
(
!
(
inb
(
WSS_STATUS
(
dev
->
base_addr
))
&
0x40
))
{
outb
(
0
,
WSS_CONFIG
(
dev
->
base_addr
));
printk
(
KERN_ERR
"%s: WSS: IRQ%d is not free!
\n
"
,
sm_drvname
,
dev
->
irq
);
}
outb
(
tmp
,
WSS_CONFIG
(
dev
->
base_addr
));
SCSTATE
->
revwss
=
inb
(
WSS_STATUS
(
dev
->
base_addr
))
&
0x3f
;
}
/*
* initialize the codec
*/
if
(
igain_l
<
0
)
igain_l
=
0
;
if
(
igain_r
<
0
)
igain_r
=
0
;
if
(
ogain_l
>
0
)
ogain_l
=
0
;
if
(
ogain_r
>
0
)
ogain_r
=
0
;
reg0
=
(
src_l
<<
6
)
&
0xc0
;
reg1
=
(
src_r
<<
6
)
&
0xc0
;
if
(
reg0
==
0x80
&&
igain_l
>=
20
)
{
reg0
|=
0x20
;
igain_l
-=
20
;
}
if
(
reg1
==
0x80
&&
igain_r
>=
20
)
{
reg1
|=
0x20
;
igain_r
-=
20
;
}
if
(
igain_l
>
23
)
igain_l
=
23
;
if
(
igain_r
>
23
)
igain_r
=
23
;
reg0
|=
igain_l
*
2
/
3
;
reg1
|=
igain_r
*
2
/
3
;
reg6
=
(
ogain_l
<
-
95
)
?
0x80
:
(
ogain_l
*
(
-
2
)
/
3
);
reg7
=
(
ogain_r
<
-
95
)
?
0x80
:
(
ogain_r
*
(
-
2
)
/
3
);
write_codec
(
dev
,
9
,
0
);
write_codec
(
dev
,
0
,
0x45
);
if
(
read_codec
(
dev
,
0
)
!=
0x45
)
goto
codec_err
;
write_codec
(
dev
,
0
,
0xaa
);
if
(
read_codec
(
dev
,
0
)
!=
0xaa
)
goto
codec_err
;
write_codec
(
dev
,
12
,
0x40
);
/* enable MODE2 */
write_codec
(
dev
,
16
,
0
);
write_codec
(
dev
,
0
,
0x45
);
SCSTATE
->
crystal
=
(
read_codec
(
dev
,
16
)
!=
0x45
);
write_codec
(
dev
,
0
,
0xaa
);
SCSTATE
->
crystal
&=
(
read_codec
(
dev
,
16
)
!=
0xaa
);
if
(
SCSTATE
->
crystal
)
{
SCSTATE
->
revcid
=
read_codec
(
dev
,
0x19
);
SCSTATE
->
revv
=
(
SCSTATE
->
revcid
>>
5
)
&
7
;
SCSTATE
->
revcid
&=
7
;
write_codec
(
dev
,
0x10
,
0x80
);
/* maximum output level */
write_codec
(
dev
,
0x11
,
0x02
);
/* xtal enable and no HPF */
write_codec
(
dev
,
0x12
,
0x80
);
/* left line input control */
write_codec
(
dev
,
0x13
,
0x80
);
/* right line input control */
write_codec
(
dev
,
0x16
,
0
);
/* disable alternative freq sel */
write_codec
(
dev
,
0x1a
,
0xe0
);
/* mono IO disable */
write_codec
(
dev
,
0x1b
,
0x00
);
/* left out no att */
write_codec
(
dev
,
0x1d
,
0x00
);
/* right out no att */
}
if
(
wss_set_codec_fmt
(
dev
,
sm
,
SCSTATE
->
fmt
[
0
],
SCSTATE
->
fmt
[
0
],
fdx
,
1
))
goto
codec_err
;
write_codec
(
dev
,
0
,
reg0
);
/* left input control */
write_codec
(
dev
,
1
,
reg1
);
/* right input control */
write_codec
(
dev
,
2
,
0x80
);
/* left aux#1 input control */
write_codec
(
dev
,
3
,
0x80
);
/* right aux#1 input control */
write_codec
(
dev
,
4
,
0x80
);
/* left aux#2 input control */
write_codec
(
dev
,
5
,
0x80
);
/* right aux#2 input control */
write_codec
(
dev
,
6
,
reg6
);
/* left dac control */
write_codec
(
dev
,
7
,
reg7
);
/* right dac control */
write_codec
(
dev
,
0xa
,
0x2
);
/* pin control register */
write_codec
(
dev
,
0xd
,
0x0
);
/* digital mix control */
SCSTATE
->
revid
=
read_codec
(
dev
,
0xc
)
&
0xf
;
/*
* print revisions
*/
if
(
SCSTATE
->
crystal
)
printk
(
KERN_INFO
"%s: Crystal CODEC ID %d, Chip revision %d, "
" Chip ID %d
\n
"
,
sm_drvname
,
(
int
)
SCSTATE
->
revid
,
(
int
)
SCSTATE
->
revv
,
(
int
)
SCSTATE
->
revcid
);
else
printk
(
KERN_INFO
"%s: WSS revision %d, CODEC revision %d
\n
"
,
sm_drvname
,
(
int
)
SCSTATE
->
revwss
,
(
int
)
SCSTATE
->
revid
);
return
0
;
codec_err:
outb
(
0
,
WSS_CONFIG
(
dev
->
base_addr
));
printk
(
KERN_ERR
"%s: no WSS soundcard found at address 0x%lx
\n
"
,
sm_drvname
,
dev
->
base_addr
);
return
-
1
;
}
/* --------------------------------------------------------------------- */
static
void
setup_dma_wss
(
struct
net_device
*
dev
,
struct
sm_state
*
sm
,
int
send
)
{
unsigned
long
flags
;
static
const
unsigned
char
codecmode
[
2
]
=
{
0x0e
,
0x0d
};
unsigned
char
oldcodecmode
;
long
abrt
;
unsigned
char
fmt
;
unsigned
int
numsamps
;
send
=
!!
send
;
fmt
=
SCSTATE
->
fmt
[
send
];
save_flags
(
flags
);
cli
();
/*
* perform the final DMA sequence to disable the codec request
*/
oldcodecmode
=
read_codec
(
dev
,
9
);
write_codec
(
dev
,
9
,
0xc
);
/* disable codec */
wss_ack_int
(
dev
);
if
(
read_codec
(
dev
,
11
)
&
0x10
)
{
dma_setup
(
sm
,
oldcodecmode
&
1
,
dev
->
dma
);
abrt
=
0
;
while
((
read_codec
(
dev
,
11
)
&
0x10
)
||
((
++
abrt
)
>=
0x10000
));
}
#ifdef CS423X_HOTFIX
if
(
read_codec
(
dev
,
0x8
)
!=
fmt
||
SCSTATE
->
crystal
)
wss_set_codec_fmt
(
dev
,
sm
,
fmt
,
fmt
,
0
,
0
);
#else
/* CS423X_HOTFIX */
if
(
read_codec
(
dev
,
0x8
)
!=
fmt
)
wss_set_codec_fmt
(
dev
,
sm
,
fmt
,
fmt
,
0
,
0
);
#endif
/* CS423X_HOTFIX */
numsamps
=
dma_setup
(
sm
,
send
,
dev
->
dma
)
-
1
;
write_codec
(
dev
,
15
,
numsamps
&
0xff
);
write_codec
(
dev
,
14
,
numsamps
>>
8
);
write_codec
(
dev
,
9
,
codecmode
[
send
]);
restore_flags
(
flags
);
}
/* --------------------------------------------------------------------- */
static
void
wss_interrupt
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
{
struct
net_device
*
dev
=
(
struct
net_device
*
)
dev_id
;
struct
sm_state
*
sm
=
(
struct
sm_state
*
)
dev
->
priv
;
unsigned
int
curfrag
;
unsigned
int
nums
;
if
(
!
dev
||
!
sm
||
!
sm
->
mode_rx
||
!
sm
->
mode_tx
||
sm
->
hdrv
.
magic
!=
HDLCDRV_MAGIC
)
return
;
cli
();
wss_ack_int
(
dev
);
disable_dma
(
dev
->
dma
);
clear_dma_ff
(
dev
->
dma
);
nums
=
dma_ptr
(
sm
,
sm
->
dma
.
ptt_cnt
>
0
,
dev
->
dma
,
&
curfrag
)
-
1
;
write_codec
(
dev
,
15
,
nums
&
0xff
);
write_codec
(
dev
,
14
,
nums
>>
8
);
enable_dma
(
dev
->
dma
);
sm_int_freq
(
sm
);
sti
();
if
(
sm
->
dma
.
ptt_cnt
<=
0
)
{
dma_receive
(
sm
,
curfrag
);
hdlcdrv_arbitrate
(
dev
,
&
sm
->
hdrv
);
if
(
hdlcdrv_ptt
(
&
sm
->
hdrv
))
{
/* starting to transmit */
disable_dma
(
dev
->
dma
);
hdlcdrv_transmitter
(
dev
,
&
sm
->
hdrv
);
/* prefill HDLC buffer */
dma_start_transmit
(
sm
);
setup_dma_wss
(
dev
,
sm
,
1
);
dma_transmit
(
sm
);
}
}
else
if
(
dma_end_transmit
(
sm
,
curfrag
))
{
/* stopping transmission */
disable_dma
(
dev
->
dma
);
dma_init_receive
(
sm
);
setup_dma_wss
(
dev
,
sm
,
0
);
}
else
dma_transmit
(
sm
);
sm_output_status
(
sm
);
hdlcdrv_transmitter
(
dev
,
&
sm
->
hdrv
);
hdlcdrv_receiver
(
dev
,
&
sm
->
hdrv
);
}
/* --------------------------------------------------------------------- */
static
int
wss_open
(
struct
net_device
*
dev
,
struct
sm_state
*
sm
)
{
unsigned
int
dmasz
,
u
;
if
(
sizeof
(
sm
->
m
)
<
sizeof
(
struct
sc_state_wss
))
{
printk
(
KERN_ERR
"sm wss: wss state too big: %d > %d
\n
"
,
sizeof
(
struct
sc_state_wss
),
sizeof
(
sm
->
m
));
return
-
ENODEV
;
}
if
(
!
dev
||
!
sm
||
!
sm
->
mode_rx
||
!
sm
->
mode_tx
)
return
-
ENXIO
;
if
(
dev
->
base_addr
<=
0
||
dev
->
base_addr
>
0x1000
-
WSS_EXTENT
||
dev
->
irq
<
2
||
dev
->
irq
>
15
||
dev
->
dma
>
3
)
return
-
ENXIO
;
if
(
check_region
(
dev
->
base_addr
,
WSS_EXTENT
))
return
-
EACCES
;
/*
* check if a card is available
*/
if
(
wss_init_codec
(
dev
,
sm
,
0
,
1
,
1
,
0
,
0
,
-
45
,
-
45
))
return
-
ENODEV
;
/*
* initialize some variables
*/
dma_init_receive
(
sm
);
dmasz
=
(
NUM_FRAGMENTS
+
1
)
*
sm
->
dma
.
ifragsz
;
u
=
NUM_FRAGMENTS
*
sm
->
dma
.
ofragsz
;
if
(
u
>
dmasz
)
dmasz
=
u
;
if
(
!
(
sm
->
dma
.
ibuf
=
sm
->
dma
.
obuf
=
kmalloc
(
dmasz
,
GFP_KERNEL
|
GFP_DMA
)))
return
-
ENOMEM
;
dma_init_transmit
(
sm
);
dma_init_receive
(
sm
);
memset
(
&
sm
->
m
,
0
,
sizeof
(
sm
->
m
));
memset
(
&
sm
->
d
,
0
,
sizeof
(
sm
->
d
));
if
(
sm
->
mode_tx
->
init
)
sm
->
mode_tx
->
init
(
sm
);
if
(
sm
->
mode_rx
->
init
)
sm
->
mode_rx
->
init
(
sm
);
if
(
request_dma
(
dev
->
dma
,
sm
->
hwdrv
->
hw_name
))
{
kfree
(
sm
->
dma
.
obuf
);
return
-
EBUSY
;
}
if
(
request_irq
(
dev
->
irq
,
wss_interrupt
,
SA_INTERRUPT
,
sm
->
hwdrv
->
hw_name
,
dev
))
{
free_dma
(
dev
->
dma
);
kfree
(
sm
->
dma
.
obuf
);
return
-
EBUSY
;
}
request_region
(
dev
->
base_addr
,
WSS_EXTENT
,
sm
->
hwdrv
->
hw_name
);
setup_dma_wss
(
dev
,
sm
,
0
);
return
0
;
}
/* --------------------------------------------------------------------- */
static
int
wss_close
(
struct
net_device
*
dev
,
struct
sm_state
*
sm
)
{
if
(
!
dev
||
!
sm
)
return
-
EINVAL
;
/*
* disable interrupts
*/
disable_dma
(
dev
->
dma
);
write_codec
(
dev
,
9
,
0xc
);
/* disable codec */
free_irq
(
dev
->
irq
,
dev
);
free_dma
(
dev
->
dma
);
release_region
(
dev
->
base_addr
,
WSS_EXTENT
);
kfree
(
sm
->
dma
.
obuf
);
return
0
;
}
/* --------------------------------------------------------------------- */
static
int
wss_sethw
(
struct
net_device
*
dev
,
struct
sm_state
*
sm
,
char
*
mode
)
{
char
*
cp
=
strchr
(
mode
,
'.'
);
const
struct
modem_tx_info
**
mtp
=
sm_modem_tx_table
;
const
struct
modem_rx_info
**
mrp
;
int
i
,
j
;
if
(
!
strcmp
(
mode
,
"off"
))
{
sm
->
mode_tx
=
NULL
;
sm
->
mode_rx
=
NULL
;
return
0
;
}
if
(
cp
)
*
cp
++
=
'\0'
;
else
cp
=
mode
;
for
(;
*
mtp
;
mtp
++
)
{
if
((
*
mtp
)
->
loc_storage
>
sizeof
(
sm
->
m
))
{
printk
(
KERN_ERR
"%s: insufficient storage for modulator %s (%d)
\n
"
,
sm_drvname
,
(
*
mtp
)
->
name
,
(
*
mtp
)
->
loc_storage
);
continue
;
}
if
(
!
(
*
mtp
)
->
name
||
strcmp
((
*
mtp
)
->
name
,
mode
))
continue
;
if
((
i
=
wss_srate_index
((
*
mtp
)
->
srate
))
<
0
)
continue
;
for
(
mrp
=
sm_modem_rx_table
;
*
mrp
;
mrp
++
)
{
if
((
*
mrp
)
->
loc_storage
>
sizeof
(
sm
->
d
))
{
printk
(
KERN_ERR
"%s: insufficient storage for demodulator %s (%d)
\n
"
,
sm_drvname
,
(
*
mrp
)
->
name
,
(
*
mrp
)
->
loc_storage
);
continue
;
}
if
((
*
mrp
)
->
name
&&
!
strcmp
((
*
mrp
)
->
name
,
cp
)
&&
((
j
=
wss_srate_index
((
*
mrp
)
->
srate
))
>=
0
))
{
sm
->
mode_tx
=
*
mtp
;
sm
->
mode_rx
=
*
mrp
;
SCSTATE
->
fmt
[
0
]
=
j
;
SCSTATE
->
fmt
[
1
]
=
i
;
sm
->
dma
.
ifragsz
=
(
sm
->
mode_rx
->
srate
+
50
)
/
100
;
sm
->
dma
.
ofragsz
=
(
sm
->
mode_tx
->
srate
+
50
)
/
100
;
if
(
sm
->
dma
.
ifragsz
<
sm
->
mode_rx
->
overlap
)
sm
->
dma
.
ifragsz
=
sm
->
mode_rx
->
overlap
;
/* prefer same data format if possible to minimize switching times */
sm
->
dma
.
i16bit
=
sm
->
dma
.
o16bit
=
2
;
if
(
sm
->
mode_rx
->
srate
==
sm
->
mode_tx
->
srate
)
{
if
(
sm
->
mode_rx
->
demodulator_s16
&&
sm
->
mode_tx
->
modulator_s16
)
sm
->
dma
.
i16bit
=
sm
->
dma
.
o16bit
=
1
;
else
if
(
sm
->
mode_rx
->
demodulator_u8
&&
sm
->
mode_tx
->
modulator_u8
)
sm
->
dma
.
i16bit
=
sm
->
dma
.
o16bit
=
0
;
}
if
(
sm
->
dma
.
i16bit
==
2
)
{
if
(
sm
->
mode_rx
->
demodulator_s16
)
sm
->
dma
.
i16bit
=
1
;
else
if
(
sm
->
mode_rx
->
demodulator_u8
)
sm
->
dma
.
i16bit
=
0
;
}
if
(
sm
->
dma
.
o16bit
==
2
)
{
if
(
sm
->
mode_tx
->
modulator_s16
)
sm
->
dma
.
o16bit
=
1
;
else
if
(
sm
->
mode_tx
->
modulator_u8
)
sm
->
dma
.
o16bit
=
0
;
}
if
(
sm
->
dma
.
i16bit
==
2
||
sm
->
dma
.
o16bit
==
2
)
{
printk
(
KERN_INFO
"%s: mode %s or %s unusable
\n
"
,
sm_drvname
,
sm
->
mode_rx
->
name
,
sm
->
mode_tx
->
name
);
sm
->
mode_tx
=
NULL
;
sm
->
mode_rx
=
NULL
;
return
-
EINVAL
;
}
#ifdef __BIG_ENDIAN
/* big endian 16bit only works on crystal cards... */
if
(
sm
->
dma
.
i16bit
)
{
SCSTATE
->
fmt
[
0
]
|=
0xc0
;
sm
->
dma
.
ifragsz
<<=
1
;
}
if
(
sm
->
dma
.
o16bit
)
{
SCSTATE
->
fmt
[
1
]
|=
0xc0
;
sm
->
dma
.
ofragsz
<<=
1
;
}
#else
/* __BIG_ENDIAN */
if
(
sm
->
dma
.
i16bit
)
{
SCSTATE
->
fmt
[
0
]
|=
0x40
;
sm
->
dma
.
ifragsz
<<=
1
;
}
if
(
sm
->
dma
.
o16bit
)
{
SCSTATE
->
fmt
[
1
]
|=
0x40
;
sm
->
dma
.
ofragsz
<<=
1
;
}
#endif
/* __BIG_ENDIAN */
return
0
;
}
}
}
return
-
EINVAL
;
}
/* --------------------------------------------------------------------- */
static
int
wss_ioctl
(
struct
net_device
*
dev
,
struct
sm_state
*
sm
,
struct
ifreq
*
ifr
,
struct
hdlcdrv_ioctl
*
hi
,
int
cmd
)
{
struct
sm_ioctl
bi
;
int
i
;
if
(
cmd
!=
SIOCDEVPRIVATE
)
return
-
ENOIOCTLCMD
;
if
(
hi
->
cmd
==
HDLCDRVCTL_MODEMPARMASK
)
return
HDLCDRV_PARMASK_IOBASE
|
HDLCDRV_PARMASK_IRQ
|
HDLCDRV_PARMASK_DMA
|
HDLCDRV_PARMASK_SERIOBASE
|
HDLCDRV_PARMASK_PARIOBASE
|
HDLCDRV_PARMASK_MIDIIOBASE
;
if
(
copy_from_user
(
&
bi
,
ifr
->
ifr_data
,
sizeof
(
bi
)))
return
-
EFAULT
;
switch
(
bi
.
cmd
)
{
default:
return
-
ENOIOCTLCMD
;
case
SMCTL_GETMIXER
:
i
=
0
;
bi
.
data
.
mix
.
sample_rate
=
sm
->
mode_rx
->
srate
;
bi
.
data
.
mix
.
bit_rate
=
sm
->
hdrv
.
par
.
bitrate
;
bi
.
data
.
mix
.
mixer_type
=
SCSTATE
->
crystal
?
SM_MIXER_CRYSTAL
:
SM_MIXER_AD1848
;
if
(((
SCSTATE
->
crystal
?
0x2c0c20fflu
:
0x20fflu
)
>>
bi
.
data
.
mix
.
reg
)
&
1
)
{
bi
.
data
.
mix
.
data
=
read_codec
(
dev
,
bi
.
data
.
mix
.
reg
);
i
=
1
;
}
if
(
copy_to_user
(
ifr
->
ifr_data
,
&
bi
,
sizeof
(
bi
)))
return
-
EFAULT
;
return
i
;
case
SMCTL_SETMIXER
:
if
(
!
capable
(
CAP_SYS_RAWIO
))
return
-
EACCES
;
if
((
bi
.
data
.
mix
.
mixer_type
!=
SM_MIXER_CRYSTAL
||
!
SCSTATE
->
crystal
)
&&
(
bi
.
data
.
mix
.
mixer_type
!=
SM_MIXER_AD1848
||
bi
.
data
.
mix
.
reg
>=
0x10
))
return
-
EINVAL
;
if
(
!
((
0x2c0c20fflu
>>
bi
.
data
.
mix
.
reg
)
&
1
))
return
-
EACCES
;
write_codec
(
dev
,
bi
.
data
.
mix
.
reg
,
bi
.
data
.
mix
.
data
);
return
0
;
}
if
(
copy_to_user
(
ifr
->
ifr_data
,
&
bi
,
sizeof
(
bi
)))
return
-
EFAULT
;
return
0
;
}
/* --------------------------------------------------------------------- */
const
struct
hardware_info
sm_hw_wss
=
{
"wss"
,
sizeof
(
struct
sc_state_wss
),
wss_open
,
wss_close
,
wss_ioctl
,
wss_sethw
};
/* --------------------------------------------------------------------- */
static
void
setup_fdx_dma_wss
(
struct
net_device
*
dev
,
struct
sm_state
*
sm
)
{
unsigned
long
flags
;
unsigned
char
oldcodecmode
,
codecdma
;
long
abrt
;
unsigned
int
osamps
,
isamps
;
save_flags
(
flags
);
cli
();
/*
* perform the final DMA sequence to disable the codec request
*/
oldcodecmode
=
read_codec
(
dev
,
9
);
write_codec
(
dev
,
9
,
0
);
/* disable codec DMA */
wss_ack_int
(
dev
);
if
((
codecdma
=
read_codec
(
dev
,
11
))
&
0x10
)
{
dma_setup
(
sm
,
1
,
dev
->
dma
);
dma_setup
(
sm
,
0
,
sm
->
hdrv
.
ptt_out
.
dma2
);
abrt
=
0
;
while
(((
codecdma
=
read_codec
(
dev
,
11
))
&
0x10
)
||
((
++
abrt
)
>=
0x10000
));
}
wss_set_codec_fmt
(
dev
,
sm
,
SCSTATE
->
fmt
[
1
],
SCSTATE
->
fmt
[
0
],
1
,
1
);
osamps
=
dma_setup
(
sm
,
1
,
dev
->
dma
)
-
1
;
isamps
=
dma_setup
(
sm
,
0
,
sm
->
hdrv
.
ptt_out
.
dma2
)
-
1
;
write_codec
(
dev
,
15
,
osamps
&
0xff
);
write_codec
(
dev
,
14
,
osamps
>>
8
);
if
(
SCSTATE
->
crystal
)
{
write_codec
(
dev
,
31
,
isamps
&
0xff
);
write_codec
(
dev
,
30
,
isamps
>>
8
);
}
write_codec
(
dev
,
9
,
3
);
restore_flags
(
flags
);
}
/* --------------------------------------------------------------------- */
static
void
wssfdx_interrupt
(
int
irq
,
void
*
dev_id
,
struct
pt_regs
*
regs
)
{
struct
net_device
*
dev
=
(
struct
net_device
*
)
dev_id
;
struct
sm_state
*
sm
=
(
struct
sm_state
*
)
dev
->
priv
;
unsigned
long
flags
;
unsigned
char
cry_int_src
;
unsigned
icfrag
,
ocfrag
,
isamps
,
osamps
;
if
(
!
dev
||
!
sm
||
!
sm
->
mode_rx
||
!
sm
->
mode_tx
||
sm
->
hdrv
.
magic
!=
HDLCDRV_MAGIC
)
return
;
save_flags
(
flags
);
cli
();
if
(
SCSTATE
->
crystal
)
{
/* Crystal has an essentially different interrupt handler! */
cry_int_src
=
read_codec
(
dev
,
0x18
);
wss_ack_int
(
dev
);
if
(
cry_int_src
&
0x10
)
{
/* playback interrupt */
disable_dma
(
dev
->
dma
);
clear_dma_ff
(
dev
->
dma
);
osamps
=
dma_ptr
(
sm
,
1
,
dev
->
dma
,
&
ocfrag
)
-
1
;
write_codec
(
dev
,
15
,
osamps
&
0xff
);
write_codec
(
dev
,
14
,
osamps
>>
8
);
enable_dma
(
dev
->
dma
);
}
if
(
cry_int_src
&
0x20
)
{
/* capture interrupt */
disable_dma
(
sm
->
hdrv
.
ptt_out
.
dma2
);
clear_dma_ff
(
sm
->
hdrv
.
ptt_out
.
dma2
);
isamps
=
dma_ptr
(
sm
,
0
,
sm
->
hdrv
.
ptt_out
.
dma2
,
&
icfrag
)
-
1
;
write_codec
(
dev
,
31
,
isamps
&
0xff
);
write_codec
(
dev
,
30
,
isamps
>>
8
);
enable_dma
(
sm
->
hdrv
.
ptt_out
.
dma2
);
}
restore_flags
(
flags
);
sm_int_freq
(
sm
);
sti
();
if
(
cry_int_src
&
0x10
)
{
if
(
dma_end_transmit
(
sm
,
ocfrag
))
dma_clear_transmit
(
sm
);
dma_transmit
(
sm
);
}
if
(
cry_int_src
&
0x20
)
{
dma_receive
(
sm
,
icfrag
);
hdlcdrv_arbitrate
(
dev
,
&
sm
->
hdrv
);
}
sm_output_status
(
sm
);
hdlcdrv_transmitter
(
dev
,
&
sm
->
hdrv
);
hdlcdrv_receiver
(
dev
,
&
sm
->
hdrv
);
return
;
}
wss_ack_int
(
dev
);
disable_dma
(
dev
->
dma
);
disable_dma
(
sm
->
hdrv
.
ptt_out
.
dma2
);
clear_dma_ff
(
dev
->
dma
);
clear_dma_ff
(
sm
->
hdrv
.
ptt_out
.
dma2
);
osamps
=
dma_ptr
(
sm
,
1
,
dev
->
dma
,
&
ocfrag
)
-
1
;
isamps
=
dma_ptr
(
sm
,
0
,
sm
->
hdrv
.
ptt_out
.
dma2
,
&
icfrag
)
-
1
;
write_codec
(
dev
,
15
,
osamps
&
0xff
);
write_codec
(
dev
,
14
,
osamps
>>
8
);
if
(
SCSTATE
->
crystal
)
{
write_codec
(
dev
,
31
,
isamps
&
0xff
);
write_codec
(
dev
,
30
,
isamps
>>
8
);
}
enable_dma
(
dev
->
dma
);
enable_dma
(
sm
->
hdrv
.
ptt_out
.
dma2
);
restore_flags
(
flags
);
sm_int_freq
(
sm
);
sti
();
if
(
dma_end_transmit
(
sm
,
ocfrag
))
dma_clear_transmit
(
sm
);
dma_transmit
(
sm
);
dma_receive
(
sm
,
icfrag
);
hdlcdrv_arbitrate
(
dev
,
&
sm
->
hdrv
);
sm_output_status
(
sm
);
hdlcdrv_transmitter
(
dev
,
&
sm
->
hdrv
);
hdlcdrv_receiver
(
dev
,
&
sm
->
hdrv
);
}
/* --------------------------------------------------------------------- */
static
int
wssfdx_open
(
struct
net_device
*
dev
,
struct
sm_state
*
sm
)
{
if
(
!
dev
||
!
sm
||
!
sm
->
mode_rx
||
!
sm
->
mode_tx
)
return
-
ENXIO
;
if
(
dev
->
base_addr
<=
0
||
dev
->
base_addr
>
0x1000
-
WSS_EXTENT
||
dev
->
irq
<
2
||
dev
->
irq
>
15
||
dev
->
dma
>
3
)
return
-
ENXIO
;
if
(
check_region
(
dev
->
base_addr
,
WSS_EXTENT
))
return
-
EACCES
;
/*
* check if a card is available
*/
if
(
wss_init_codec
(
dev
,
sm
,
1
,
1
,
1
,
0
,
0
,
-
45
,
-
45
))
return
-
ENODEV
;
/*
* initialize some variables
*/
if
(
!
(
sm
->
dma
.
ibuf
=
kmalloc
(
sm
->
dma
.
ifragsz
*
(
NUM_FRAGMENTS
+
1
),
GFP_KERNEL
|
GFP_DMA
)))
return
-
ENOMEM
;
if
(
!
(
sm
->
dma
.
obuf
=
kmalloc
(
sm
->
dma
.
ofragsz
*
NUM_FRAGMENTS
,
GFP_KERNEL
|
GFP_DMA
)))
{
kfree
(
sm
->
dma
.
ibuf
);
return
-
ENOMEM
;
}
dma_init_transmit
(
sm
);
dma_init_receive
(
sm
);
memset
(
&
sm
->
m
,
0
,
sizeof
(
sm
->
m
));
memset
(
&
sm
->
d
,
0
,
sizeof
(
sm
->
d
));
if
(
sm
->
mode_tx
->
init
)
sm
->
mode_tx
->
init
(
sm
);
if
(
sm
->
mode_rx
->
init
)
sm
->
mode_rx
->
init
(
sm
);
if
(
request_dma
(
dev
->
dma
,
sm
->
hwdrv
->
hw_name
))
{
kfree
(
sm
->
dma
.
ibuf
);
kfree
(
sm
->
dma
.
obuf
);
return
-
EBUSY
;
}
if
(
request_dma
(
sm
->
hdrv
.
ptt_out
.
dma2
,
sm
->
hwdrv
->
hw_name
))
{
kfree
(
sm
->
dma
.
ibuf
);
kfree
(
sm
->
dma
.
obuf
);
free_dma
(
dev
->
dma
);
return
-
EBUSY
;
}
if
(
request_irq
(
dev
->
irq
,
wssfdx_interrupt
,
SA_INTERRUPT
,
sm
->
hwdrv
->
hw_name
,
dev
))
{
kfree
(
sm
->
dma
.
ibuf
);
kfree
(
sm
->
dma
.
obuf
);
free_dma
(
dev
->
dma
);
free_dma
(
sm
->
hdrv
.
ptt_out
.
dma2
);
return
-
EBUSY
;
}
request_region
(
dev
->
base_addr
,
WSS_EXTENT
,
sm
->
hwdrv
->
hw_name
);
setup_fdx_dma_wss
(
dev
,
sm
);
return
0
;
}
/* --------------------------------------------------------------------- */
static
int
wssfdx_close
(
struct
net_device
*
dev
,
struct
sm_state
*
sm
)
{
if
(
!
dev
||
!
sm
)
return
-
EINVAL
;
/*
* disable interrupts
*/
disable_dma
(
dev
->
dma
);
disable_dma
(
sm
->
hdrv
.
ptt_out
.
dma2
);
write_codec
(
dev
,
9
,
0xc
);
/* disable codec */
free_irq
(
dev
->
irq
,
dev
);
free_dma
(
dev
->
dma
);
free_dma
(
sm
->
hdrv
.
ptt_out
.
dma2
);
release_region
(
dev
->
base_addr
,
WSS_EXTENT
);
kfree
(
sm
->
dma
.
ibuf
);
kfree
(
sm
->
dma
.
obuf
);
return
0
;
}
/* --------------------------------------------------------------------- */
static
int
wssfdx_sethw
(
struct
net_device
*
dev
,
struct
sm_state
*
sm
,
char
*
mode
)
{
char
*
cp
=
strchr
(
mode
,
'.'
);
const
struct
modem_tx_info
**
mtp
=
sm_modem_tx_table
;
const
struct
modem_rx_info
**
mrp
;
int
i
;
if
(
!
strcmp
(
mode
,
"off"
))
{
sm
->
mode_tx
=
NULL
;
sm
->
mode_rx
=
NULL
;
return
0
;
}
if
(
cp
)
*
cp
++
=
'\0'
;
else
cp
=
mode
;
for
(;
*
mtp
;
mtp
++
)
{
if
((
*
mtp
)
->
loc_storage
>
sizeof
(
sm
->
m
))
{
printk
(
KERN_ERR
"%s: insufficient storage for modulator %s (%d)
\n
"
,
sm_drvname
,
(
*
mtp
)
->
name
,
(
*
mtp
)
->
loc_storage
);
continue
;
}
if
(
!
(
*
mtp
)
->
name
||
strcmp
((
*
mtp
)
->
name
,
mode
))
continue
;
if
((
i
=
wss_srate_index
((
*
mtp
)
->
srate
))
<
0
)
continue
;
for
(
mrp
=
sm_modem_rx_table
;
*
mrp
;
mrp
++
)
{
if
((
*
mrp
)
->
loc_storage
>
sizeof
(
sm
->
d
))
{
printk
(
KERN_ERR
"%s: insufficient storage for demodulator %s (%d)
\n
"
,
sm_drvname
,
(
*
mrp
)
->
name
,
(
*
mrp
)
->
loc_storage
);
continue
;
}
if
((
*
mrp
)
->
name
&&
!
strcmp
((
*
mrp
)
->
name
,
cp
)
&&
(
*
mtp
)
->
srate
==
(
*
mrp
)
->
srate
)
{
sm
->
mode_tx
=
*
mtp
;
sm
->
mode_rx
=
*
mrp
;
SCSTATE
->
fmt
[
0
]
=
SCSTATE
->
fmt
[
1
]
=
i
;
sm
->
dma
.
ifragsz
=
sm
->
dma
.
ofragsz
=
(
sm
->
mode_rx
->
srate
+
50
)
/
100
;
if
(
sm
->
dma
.
ifragsz
<
sm
->
mode_rx
->
overlap
)
sm
->
dma
.
ifragsz
=
sm
->
mode_rx
->
overlap
;
sm
->
dma
.
i16bit
=
sm
->
dma
.
o16bit
=
2
;
if
(
sm
->
mode_rx
->
demodulator_s16
)
{
sm
->
dma
.
i16bit
=
1
;
sm
->
dma
.
ifragsz
<<=
1
;
#ifdef __BIG_ENDIAN
/* big endian 16bit only works on crystal cards... */
SCSTATE
->
fmt
[
0
]
|=
0xc0
;
#else
/* __BIG_ENDIAN */
SCSTATE
->
fmt
[
0
]
|=
0x40
;
#endif
/* __BIG_ENDIAN */
}
else
if
(
sm
->
mode_rx
->
demodulator_u8
)
sm
->
dma
.
i16bit
=
0
;
if
(
sm
->
mode_tx
->
modulator_s16
)
{
sm
->
dma
.
o16bit
=
1
;
sm
->
dma
.
ofragsz
<<=
1
;
#ifdef __BIG_ENDIAN
/* big endian 16bit only works on crystal cards... */
SCSTATE
->
fmt
[
1
]
|=
0xc0
;
#else
/* __BIG_ENDIAN */
SCSTATE
->
fmt
[
1
]
|=
0x40
;
#endif
/* __BIG_ENDIAN */
}
else
if
(
sm
->
mode_tx
->
modulator_u8
)
sm
->
dma
.
o16bit
=
0
;
if
(
sm
->
dma
.
i16bit
==
2
||
sm
->
dma
.
o16bit
==
2
)
{
printk
(
KERN_INFO
"%s: mode %s or %s unusable
\n
"
,
sm_drvname
,
sm
->
mode_rx
->
name
,
sm
->
mode_tx
->
name
);
sm
->
mode_tx
=
NULL
;
sm
->
mode_rx
=
NULL
;
return
-
EINVAL
;
}
return
0
;
}
}
}
return
-
EINVAL
;
}
/* --------------------------------------------------------------------- */
static
int
wssfdx_ioctl
(
struct
net_device
*
dev
,
struct
sm_state
*
sm
,
struct
ifreq
*
ifr
,
struct
hdlcdrv_ioctl
*
hi
,
int
cmd
)
{
if
(
cmd
!=
SIOCDEVPRIVATE
)
return
-
ENOIOCTLCMD
;
if
(
hi
->
cmd
==
HDLCDRVCTL_MODEMPARMASK
)
return
HDLCDRV_PARMASK_IOBASE
|
HDLCDRV_PARMASK_IRQ
|
HDLCDRV_PARMASK_DMA
|
HDLCDRV_PARMASK_DMA2
|
HDLCDRV_PARMASK_SERIOBASE
|
HDLCDRV_PARMASK_PARIOBASE
|
HDLCDRV_PARMASK_MIDIIOBASE
;
return
wss_ioctl
(
dev
,
sm
,
ifr
,
hi
,
cmd
);
}
/* --------------------------------------------------------------------- */
const
struct
hardware_info
sm_hw_wssfdx
=
{
"wssfdx"
,
sizeof
(
struct
sc_state_wss
),
wssfdx_open
,
wssfdx_close
,
wssfdx_ioctl
,
wssfdx_sethw
};
/* --------------------------------------------------------------------- */
#undef SCSTATE
drivers/net/hamradio/soundmodem/smdma.h
deleted
100644 → 0
View file @
a994c542
/*****************************************************************************/
/*
* 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
*/
static
__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
;
}
}
/* --------------------------------------------------------------------- */
static
__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
;
}
}
/* --------------------------------------------------------------------- */
static
__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
;
}
static
__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
++
;
}
}
static
__inline__
void
dma_init_transmit
(
struct
sm_state
*
sm
)
{
sm
->
dma
.
ofragptr
=
0
;
sm
->
dma
.
ptt_cnt
=
0
;
}
static
__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
;
}
static
__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
);
}
/* --------------------------------------------------------------------- */
static
__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
;
}
}
static
__inline__
void
dma_init_receive
(
struct
sm_state
*
sm
)
{
sm
->
dma
.
ifragptr
=
0
;
}
/* --------------------------------------------------------------------- */
#endif
/* _SMDMA_H */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment