initial commit of the linux driver
for the dosch and amand dect pcmcia card. Currently only the type II card is supported. git-svn-id: https://dedected.org/svn/trunk@3 8d8ab74c-27aa-4a3d-9bde-523a2bc1f624
This commit is contained in:
parent
d652a68cd9
commit
56ecf4776a
|
@ -0,0 +1,339 @@
|
|||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The licenses for most software are designed to take away your
|
||||
freedom to share and change it. By contrast, the GNU General Public
|
||||
License is intended to guarantee your freedom to share and change free
|
||||
software--to make sure the software is free for all its users. This
|
||||
General Public License applies to most of the Free Software
|
||||
Foundation's software and to any other program whose authors commit to
|
||||
using it. (Some other Free Software Foundation software is covered by
|
||||
the GNU Lesser General Public License instead.) You can apply it to
|
||||
your programs, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
this service if you wish), that you receive source code or can get it
|
||||
if you want it, that you can change the software or use pieces of it
|
||||
in new free programs; and that you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid
|
||||
anyone to deny you these rights or to ask you to surrender the rights.
|
||||
These restrictions translate to certain responsibilities for you if you
|
||||
distribute copies of the software, or if you modify it.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must give the recipients all the rights that
|
||||
you have. You must make sure that they, too, receive or can get the
|
||||
source code. And you must show them these terms so they know their
|
||||
rights.
|
||||
|
||||
We protect your rights with two steps: (1) copyright the software, and
|
||||
(2) offer you this license which gives you legal permission to copy,
|
||||
distribute and/or modify the software.
|
||||
|
||||
Also, for each author's protection and ours, we want to make certain
|
||||
that everyone understands that there is no warranty for this free
|
||||
software. If the software is modified by someone else and passed on, we
|
||||
want its recipients to know that what they have is not the original, so
|
||||
that any problems introduced by others will not reflect on the original
|
||||
authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software
|
||||
patents. We wish to avoid the danger that redistributors of a free
|
||||
program will individually obtain patent licenses, in effect making the
|
||||
program proprietary. To prevent this, we have made it clear that any
|
||||
patent must be licensed for everyone's free use or not licensed at all.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License applies to any program or other work which contains
|
||||
a notice placed by the copyright holder saying it may be distributed
|
||||
under the terms of this General Public License. The "Program", below,
|
||||
refers to any such program or work, and a "work based on the Program"
|
||||
means either the Program or any derivative work under copyright law:
|
||||
that is to say, a work containing the Program or a portion of it,
|
||||
either verbatim or with modifications and/or translated into another
|
||||
language. (Hereinafter, translation is included without limitation in
|
||||
the term "modification".) Each licensee is addressed as "you".
|
||||
|
||||
Activities other than copying, distribution and modification are not
|
||||
covered by this License; they are outside its scope. The act of
|
||||
running the Program is not restricted, and the output from the Program
|
||||
is covered only if its contents constitute a work based on the
|
||||
Program (independent of having been made by running the Program).
|
||||
Whether that is true depends on what the Program does.
|
||||
|
||||
1. You may copy and distribute verbatim copies of the Program's
|
||||
source code as you receive it, in any medium, provided that you
|
||||
conspicuously and appropriately publish on each copy an appropriate
|
||||
copyright notice and disclaimer of warranty; keep intact all the
|
||||
notices that refer to this License and to the absence of any warranty;
|
||||
and give any other recipients of the Program a copy of this License
|
||||
along with the Program.
|
||||
|
||||
You may charge a fee for the physical act of transferring a copy, and
|
||||
you may at your option offer warranty protection in exchange for a fee.
|
||||
|
||||
2. You may modify your copy or copies of the Program or any portion
|
||||
of it, thus forming a work based on the Program, and copy and
|
||||
distribute such modifications or work under the terms of Section 1
|
||||
above, provided that you also meet all of these conditions:
|
||||
|
||||
a) You must cause the modified files to carry prominent notices
|
||||
stating that you changed the files and the date of any change.
|
||||
|
||||
b) You must cause any work that you distribute or publish, that in
|
||||
whole or in part contains or is derived from the Program or any
|
||||
part thereof, to be licensed as a whole at no charge to all third
|
||||
parties under the terms of this License.
|
||||
|
||||
c) If the modified program normally reads commands interactively
|
||||
when run, you must cause it, when started running for such
|
||||
interactive use in the most ordinary way, to print or display an
|
||||
announcement including an appropriate copyright notice and a
|
||||
notice that there is no warranty (or else, saying that you provide
|
||||
a warranty) and that users may redistribute the program under
|
||||
these conditions, and telling the user how to view a copy of this
|
||||
License. (Exception: if the Program itself is interactive but
|
||||
does not normally print such an announcement, your work based on
|
||||
the Program is not required to print an announcement.)
|
||||
|
||||
These requirements apply to the modified work as a whole. If
|
||||
identifiable sections of that work are not derived from the Program,
|
||||
and can be reasonably considered independent and separate works in
|
||||
themselves, then this License, and its terms, do not apply to those
|
||||
sections when you distribute them as separate works. But when you
|
||||
distribute the same sections as part of a whole which is a work based
|
||||
on the Program, the distribution of the whole must be on the terms of
|
||||
this License, whose permissions for other licensees extend to the
|
||||
entire whole, and thus to each and every part regardless of who wrote it.
|
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest
|
||||
your rights to work written entirely by you; rather, the intent is to
|
||||
exercise the right to control the distribution of derivative or
|
||||
collective works based on the Program.
|
||||
|
||||
In addition, mere aggregation of another work not based on the Program
|
||||
with the Program (or with a work based on the Program) on a volume of
|
||||
a storage or distribution medium does not bring the other work under
|
||||
the scope of this License.
|
||||
|
||||
3. You may copy and distribute the Program (or a work based on it,
|
||||
under Section 2) in object code or executable form under the terms of
|
||||
Sections 1 and 2 above provided that you also do one of the following:
|
||||
|
||||
a) Accompany it with the complete corresponding machine-readable
|
||||
source code, which must be distributed under the terms of Sections
|
||||
1 and 2 above on a medium customarily used for software interchange; or,
|
||||
|
||||
b) Accompany it with a written offer, valid for at least three
|
||||
years, to give any third party, for a charge no more than your
|
||||
cost of physically performing source distribution, a complete
|
||||
machine-readable copy of the corresponding source code, to be
|
||||
distributed under the terms of Sections 1 and 2 above on a medium
|
||||
customarily used for software interchange; or,
|
||||
|
||||
c) Accompany it with the information you received as to the offer
|
||||
to distribute corresponding source code. (This alternative is
|
||||
allowed only for noncommercial distribution and only if you
|
||||
received the program in object code or executable form with such
|
||||
an offer, in accord with Subsection b above.)
|
||||
|
||||
The source code for a work means the preferred form of the work for
|
||||
making modifications to it. For an executable work, complete source
|
||||
code means all the source code for all modules it contains, plus any
|
||||
associated interface definition files, plus the scripts used to
|
||||
control compilation and installation of the executable. However, as a
|
||||
special exception, the source code distributed need not include
|
||||
anything that is normally distributed (in either source or binary
|
||||
form) with the major components (compiler, kernel, and so on) of the
|
||||
operating system on which the executable runs, unless that component
|
||||
itself accompanies the executable.
|
||||
|
||||
If distribution of executable or object code is made by offering
|
||||
access to copy from a designated place, then offering equivalent
|
||||
access to copy the source code from the same place counts as
|
||||
distribution of the source code, even though third parties are not
|
||||
compelled to copy the source along with the object code.
|
||||
|
||||
4. You may not copy, modify, sublicense, or distribute the Program
|
||||
except as expressly provided under this License. Any attempt
|
||||
otherwise to copy, modify, sublicense or distribute the Program is
|
||||
void, and will automatically terminate your rights under this License.
|
||||
However, parties who have received copies, or rights, from you under
|
||||
this License will not have their licenses terminated so long as such
|
||||
parties remain in full compliance.
|
||||
|
||||
5. You are not required to accept this License, since you have not
|
||||
signed it. However, nothing else grants you permission to modify or
|
||||
distribute the Program or its derivative works. These actions are
|
||||
prohibited by law if you do not accept this License. Therefore, by
|
||||
modifying or distributing the Program (or any work based on the
|
||||
Program), you indicate your acceptance of this License to do so, and
|
||||
all its terms and conditions for copying, distributing or modifying
|
||||
the Program or works based on it.
|
||||
|
||||
6. Each time you redistribute the Program (or any work based on the
|
||||
Program), the recipient automatically receives a license from the
|
||||
original licensor to copy, distribute or modify the Program subject to
|
||||
these terms and conditions. You may not impose any further
|
||||
restrictions on the recipients' exercise of the rights granted herein.
|
||||
You are not responsible for enforcing compliance by third parties to
|
||||
this License.
|
||||
|
||||
7. If, as a consequence of a court judgment or allegation of patent
|
||||
infringement or for any other reason (not limited to patent issues),
|
||||
conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot
|
||||
distribute so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you
|
||||
may not distribute the Program at all. For example, if a patent
|
||||
license would not permit royalty-free redistribution of the Program by
|
||||
all those who receive copies directly or indirectly through you, then
|
||||
the only way you could satisfy both it and this License would be to
|
||||
refrain entirely from distribution of the Program.
|
||||
|
||||
If any portion of this section is held invalid or unenforceable under
|
||||
any particular circumstance, the balance of the section is intended to
|
||||
apply and the section as a whole is intended to apply in other
|
||||
circumstances.
|
||||
|
||||
It is not the purpose of this section to induce you to infringe any
|
||||
patents or other property right claims or to contest validity of any
|
||||
such claims; this section has the sole purpose of protecting the
|
||||
integrity of the free software distribution system, which is
|
||||
implemented by public license practices. Many people have made
|
||||
generous contributions to the wide range of software distributed
|
||||
through that system in reliance on consistent application of that
|
||||
system; it is up to the author/donor to decide if he or she is willing
|
||||
to distribute software through any other system and a licensee cannot
|
||||
impose that choice.
|
||||
|
||||
This section is intended to make thoroughly clear what is believed to
|
||||
be a consequence of the rest of this License.
|
||||
|
||||
8. If the distribution and/or use of the Program is restricted in
|
||||
certain countries either by patents or by copyrighted interfaces, the
|
||||
original copyright holder who places the Program under this License
|
||||
may add an explicit geographical distribution limitation excluding
|
||||
those countries, so that distribution is permitted only in or among
|
||||
countries not thus excluded. In such case, this License incorporates
|
||||
the limitation as if written in the body of this License.
|
||||
|
||||
9. The Free Software Foundation may publish revised and/or new versions
|
||||
of the General Public License from time to time. Such new versions will
|
||||
be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the Program
|
||||
specifies a version number of this License which applies to it and "any
|
||||
later version", you have the option of following the terms and conditions
|
||||
either of that version or of any later version published by the Free
|
||||
Software Foundation. If the Program does not specify a version number of
|
||||
this License, you may choose any version ever published by the Free Software
|
||||
Foundation.
|
||||
|
||||
10. If you wish to incorporate parts of the Program into other free
|
||||
programs whose distribution conditions are different, write to the author
|
||||
to ask for permission. For software which is copyrighted by the Free
|
||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
||||
make exceptions for this. Our decision will be guided by the two goals
|
||||
of preserving the free status of all derivatives of our free software and
|
||||
of promoting the sharing and reuse of software generally.
|
||||
|
||||
NO WARRANTY
|
||||
|
||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
||||
REPAIR OR CORRECTION.
|
||||
|
||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
convey the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
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.,
|
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program is interactive, make it output a short notice like this
|
||||
when it starts in an interactive mode:
|
||||
|
||||
Gnomovision version 69, Copyright (C) year name of author
|
||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, the commands you use may
|
||||
be called something other than `show w' and `show c'; they could even be
|
||||
mouse-clicks or menu items--whatever suits your program.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or your
|
||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
||||
necessary. Here is a sample; alter the names:
|
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
||||
|
||||
<signature of Ty Coon>, 1 April 1989
|
||||
Ty Coon, President of Vice
|
||||
|
||||
This General Public License does not permit incorporating your program into
|
||||
proprietary programs. If your program is a subroutine library, you may
|
||||
consider it more useful to permit linking proprietary applications with the
|
||||
library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License.
|
|
@ -0,0 +1,46 @@
|
|||
NODE:=/dev/coa
|
||||
|
||||
PCMCIA_SLOT:=1
|
||||
|
||||
-include pcmcia_slot.make
|
||||
|
||||
ifneq ($(KERNELRELEASE),)
|
||||
obj-m := com_on_air_cs.o
|
||||
com_on_air_cs-objs := com_on_air.o sc14421.o sc14421_sniffer.o sc14421_firmware.o dect.o
|
||||
else
|
||||
KDIR ?= /lib/modules/`uname -r`/build/
|
||||
PWD := $(shell pwd)
|
||||
|
||||
default:
|
||||
$(MAKE) -C $(KDIR) M=$(PWD) modules
|
||||
|
||||
endif
|
||||
|
||||
load: node
|
||||
insmod ./com_on_air_cs.ko && \
|
||||
pccardctl insert $(PCMCIA_SLOT)
|
||||
|
||||
unload:
|
||||
pccardctl eject $(PCMCIA_SLOT) && \
|
||||
rmmod com_on_air_cs
|
||||
|
||||
reload:
|
||||
pccardctl eject $(PCMCIA_SLOT) && \
|
||||
rmmod com_on_air_cs && \
|
||||
insmod ./com_on_air_cs.ko && \
|
||||
pccardctl insert $(PCMCIA_SLOT)
|
||||
|
||||
node: $(NODE)
|
||||
$(NODE):
|
||||
mknod $@ --mode 660 c 3564 0 ### 3564 == 0xDEC
|
||||
# chgrp dect $(NODE)
|
||||
|
||||
read: node coa_read
|
||||
tools/coa_read
|
||||
|
||||
watch: node coa_read
|
||||
watch -n 0.2 ./tools/coa_read
|
||||
|
||||
clean:
|
||||
rm -rf com_on_air_cs.ko com_on_air_cs.mod.c .com_on_air* .sc14421* .tmp* Module.symvers modules.order *.o
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
|
||||
|
||||
!!! for scientific and research purposes only !!!
|
||||
|
||||
|
||||
what
|
||||
~~~~
|
||||
com_on_air_cs is a very basic driver for the Dosch & Amand com-on-air PCMCIA
|
||||
DECT cards.
|
||||
In the tools/ subdir you find userspace tools using the driver
|
||||
|
||||
license
|
||||
~~~~~~~
|
||||
GNU GENERAL PUBLIC LICENSE Version 2
|
||||
see LICENSE
|
||||
|
||||
authors
|
||||
~~~~~~~
|
||||
Matthias Wenzel <dect at mazzoo dot de>
|
||||
Andreas Schuler <krater at badterrorist dot com>
|
||||
|
||||
install
|
||||
~~~~~~~
|
||||
make && make -C tools # compiles the driver and userspace tools
|
||||
make node # create the /dev/coa character device
|
||||
|
||||
running
|
||||
~~~~~~~
|
||||
the most featurecomplete tool for now is dect_cli. it can dump pcap
|
||||
formatted captures. just run it and type help.
|
||||
|
||||
coa_syncsniff dumps pcap files on a given channel and RFPI
|
||||
|
||||
pcap2cchan dumps C-channel information from pcap files
|
||||
|
||||
pcapstein dumps all B-Fields found in a pcap file
|
||||
|
|
@ -0,0 +1,823 @@
|
|||
/*
|
||||
* com_on_air_cs - basic driver for the Dosch and Amand "com on air" cards
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* authors:
|
||||
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
|
||||
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/crc32.h>
|
||||
#include <linux/kfifo.h>
|
||||
#include <linux/poll.h>
|
||||
|
||||
#include <pcmcia/cs_types.h>
|
||||
#include <pcmcia/cs.h>
|
||||
#include <pcmcia/cistpl.h>
|
||||
#include <pcmcia/ciscode.h>
|
||||
#include <pcmcia/ds.h>
|
||||
#include <pcmcia/cisreg.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
|
||||
#include "com_on_air.h"
|
||||
#include "com_on_air_user.h" /* ioctls ... */
|
||||
#include "sc14421.h"
|
||||
#include "sc14421_sniffer.h"
|
||||
|
||||
|
||||
MODULE_AUTHOR("Matthias Wenzel comonair<a>mazzoo.de;"
|
||||
"Andreas Schuler dect<a>badterrorist.com");
|
||||
MODULE_DESCRIPTION("Dosch&Amand COM-ON-AIR PCMCIA driver");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
#define COA_DEVICE_NAME "com_on_air_cs"
|
||||
#define COA_FIFO_SIZE 65536
|
||||
|
||||
struct coa_info *dev;
|
||||
|
||||
|
||||
|
||||
static int coa_open(struct inode *inode, struct file *filp)
|
||||
{
|
||||
if (dev->open)
|
||||
return -EBUSY;
|
||||
dev->open = 1;
|
||||
|
||||
return nonseekable_open(inode, filp);
|
||||
}
|
||||
|
||||
/* we use some "hidden" ioctls */
|
||||
#define COA_IOCTL_TEST0 0xF000
|
||||
#define COA_IOCTL_TEST1 0xF001
|
||||
#define COA_IOCTL_TEST2 0xF002
|
||||
#define COA_IOCTL_TEST3 0xF003
|
||||
#define COA_IOCTL_TEST4 0xF004
|
||||
#define COA_IOCTL_TEST5 0xF005
|
||||
#define COA_IOCTL_TEST6 0xF006
|
||||
#define COA_IOCTL_TEST7 0xF007
|
||||
|
||||
int coa_ioctl(
|
||||
struct inode *inode,
|
||||
struct file *filp,
|
||||
unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
|
||||
unsigned long __user * argp = (unsigned long __user *) arg;
|
||||
|
||||
if (!dev->p_dev->dev_node)
|
||||
return -EIO;
|
||||
|
||||
switch (cmd)
|
||||
{
|
||||
case COA_IOCTL_MODE:
|
||||
{
|
||||
uint16_t mode;
|
||||
if (copy_from_user(&mode, argp, sizeof(mode)))
|
||||
{
|
||||
printk(COA_DEVICE_NAME
|
||||
": invalid argument in ioctl()\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
switch (mode & COA_MODEMASK)
|
||||
{
|
||||
case COA_MODE_IDLE:
|
||||
printk("com_on_air_cs: stopping DIP\n");
|
||||
SC14421_stop_dip(dev->sc14421_base);
|
||||
dev->operation_mode = mode;
|
||||
|
||||
kfifo_reset(dev->rx_fifo);
|
||||
kfifo_reset(dev->tx_fifo);
|
||||
|
||||
break;
|
||||
case COA_MODE_FP:
|
||||
printk("FIXME: implement COA_MODE_FP ;)\n");
|
||||
break;
|
||||
case COA_MODE_PP:
|
||||
printk("FIXME: implement COA_MODE_PP ;)\n");
|
||||
break;
|
||||
case COA_MODE_SNIFF:
|
||||
|
||||
kfifo_reset(dev->rx_fifo);
|
||||
kfifo_reset(dev->tx_fifo);
|
||||
|
||||
/* activiate sniffer */
|
||||
|
||||
if (!dev->sniffer_config)
|
||||
dev->sniffer_config =
|
||||
kzalloc(sizeof(*dev->sniffer_config),
|
||||
GFP_KERNEL);
|
||||
if (!(dev->sniffer_config))
|
||||
return -ENOMEM;
|
||||
|
||||
dev->sniffer_config->snifftype = mode & COA_SUBMODEMASK;
|
||||
dev->sniffer_config->channel = 0;
|
||||
dev->operation_mode = mode;
|
||||
|
||||
sniffer_init(dev);
|
||||
printk(COA_DEVICE_NAME": sniffer initialized\n");
|
||||
break;
|
||||
case COA_MODE_JAM:
|
||||
printk("FIXME: implement COA_MODE_JAM\n");
|
||||
break;
|
||||
default:
|
||||
printk("coa: invalid ioctl() value "
|
||||
"for COA_IOCTL_MODE\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case COA_IOCTL_RADIO:
|
||||
printk("FIXME: implement COA_IOCTL_RADIO\n");
|
||||
break;
|
||||
case COA_IOCTL_RX:
|
||||
printk("FIXME: implement COA_IOCTL_RX\n");
|
||||
break;
|
||||
case COA_IOCTL_TX:
|
||||
printk("FIXME: implement COA_IOCTL_TX\n");
|
||||
break;
|
||||
case COA_IOCTL_CHAN:
|
||||
{
|
||||
uint32_t channel;
|
||||
if (copy_from_user(&channel, argp, sizeof(channel)))
|
||||
{
|
||||
printk(COA_DEVICE_NAME": invalid argument "
|
||||
"in ioctl()\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (channel > 10)
|
||||
return -EINVAL;
|
||||
|
||||
switch (dev->operation_mode & COA_MODEMASK)
|
||||
{
|
||||
case COA_MODE_IDLE:
|
||||
break;
|
||||
case COA_MODE_FP:
|
||||
/* FIXME: implement COA_MODE_FP ;) */
|
||||
break;
|
||||
case COA_MODE_PP:
|
||||
/* FIXME: implement COA_MODE_PP ;) */
|
||||
break;
|
||||
case COA_MODE_SNIFF:
|
||||
dev->sniffer_config->channel = channel;
|
||||
break;
|
||||
case COA_MODE_JAM:
|
||||
printk("FIXME: implement COA_MODE_JAM\n");
|
||||
break;
|
||||
default:
|
||||
printk("coa: invalid ioctl() value "
|
||||
"for COA_IOCTL_MODE\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
sniffer_init(dev);
|
||||
break;
|
||||
}
|
||||
case COA_IOCTL_SLOT:
|
||||
printk("FIXME: implement COA_IOCTL_SLOT\n");
|
||||
break;
|
||||
case COA_IOCTL_RSSI:
|
||||
printk("FIXME: implement COA_IOCTL_RSSI\n");
|
||||
break;
|
||||
case COA_IOCTL_FIRMWARE:
|
||||
printk("FIXME: implement COA_IOCTL_FIRMWARE\n");
|
||||
break;
|
||||
case COA_IOCTL_SETRFPI:
|
||||
{
|
||||
uint8_t RFPI[5];
|
||||
if (copy_from_user(&RFPI, argp, sizeof(RFPI)))
|
||||
{
|
||||
printk(COA_DEVICE_NAME": invalid argument in ioctl()\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
switch (dev->operation_mode & COA_MODEMASK)
|
||||
{
|
||||
case COA_MODE_IDLE:
|
||||
break;
|
||||
case COA_MODE_FP:
|
||||
/* FIXME: implement COA_MODE_FP ;) */
|
||||
break;
|
||||
case COA_MODE_PP:
|
||||
/* FIXME: implement COA_MODE_PP ;) */
|
||||
break;
|
||||
case COA_MODE_SNIFF:
|
||||
memcpy(dev->sniffer_config->RFPI, RFPI, sizeof(dev->sniffer_config->RFPI));
|
||||
break;
|
||||
case COA_MODE_JAM:
|
||||
printk("FIXME: implement COA_MODE_JAM\n");
|
||||
break;
|
||||
default:
|
||||
printk("coa: invalid ioctl() value for COA_IOCTL_MODE\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case COA_IOCTL_TEST7:
|
||||
case COA_IOCTL_TEST6:
|
||||
case COA_IOCTL_TEST5:
|
||||
case COA_IOCTL_TEST4:
|
||||
case COA_IOCTL_TEST3:
|
||||
case COA_IOCTL_TEST2:
|
||||
{
|
||||
printk("\n\ncom_on_air_cs: saw %d interrupts since loading\n\n\n",
|
||||
dev->irq_count);
|
||||
break;
|
||||
}
|
||||
case COA_IOCTL_TEST1:
|
||||
{
|
||||
static char teststring[] = "awake. "
|
||||
"shake dreams from your head my pretty child, "
|
||||
"my swet one. choose the day "
|
||||
"and choose the sign of your day. "
|
||||
"the day's divinity.\n";
|
||||
static char * ps = teststring;
|
||||
int ret;
|
||||
ret = kfifo_put(dev->rx_fifo, ps, 1);
|
||||
if (ret <= 0)
|
||||
printk("com_on_air_cs: rx fifo full? "
|
||||
"kfifo_put() = %d\n", ret);
|
||||
ps++;
|
||||
if (!*ps)
|
||||
ps = teststring;
|
||||
break;
|
||||
}
|
||||
case COA_IOCTL_TEST0:
|
||||
{
|
||||
unsigned char bank;
|
||||
int a, b, i;
|
||||
printk("dumping complete DIP-RAM\n");
|
||||
disable_irq(dev->irq);
|
||||
for (i = 0; i < 8; i++)
|
||||
{
|
||||
bank = (4 * i);
|
||||
SC14421_switch_to_bank(dev->sc14421_base, bank);
|
||||
|
||||
printk("Setting Banking-Register to %.2x\n\n", bank);
|
||||
for (a = 0; a < 16; a++)
|
||||
{
|
||||
unsigned short *sc14421_base = dev->sc14421_base;
|
||||
for (b = 0; b < 16; b++)
|
||||
printk("%.2x ",
|
||||
(unsigned char)
|
||||
SC14421_READ( a*16 + b) );
|
||||
#if 0
|
||||
if (SC14421_READ(511) & 0x0f)
|
||||
printk("%.2x ",
|
||||
(unsigned char)
|
||||
(SC14421_READ(511)));
|
||||
printk("\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
enable_irq(dev->irq);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
printk("coa: invalid ioctl()\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int coa_poll(struct file *file, poll_table * wait)
|
||||
{
|
||||
unsigned int mask = 0;
|
||||
|
||||
if (!dev->p_dev->dev_node)
|
||||
return -EIO;
|
||||
|
||||
if (kfifo_len(dev->rx_fifo))
|
||||
mask |= POLLIN | POLLRDNORM;
|
||||
if (COA_FIFO_SIZE - kfifo_len(dev->tx_fifo))
|
||||
mask |= POLLOUT | POLLWRNORM;
|
||||
return mask;
|
||||
}
|
||||
|
||||
static ssize_t coa_read(
|
||||
struct file *filp,
|
||||
char __user *buf,
|
||||
size_t count_want,
|
||||
loff_t *ppos)
|
||||
{
|
||||
size_t to_copy;
|
||||
size_t not_copied;
|
||||
unsigned char *data;
|
||||
|
||||
if (!dev->p_dev->dev_node)
|
||||
return -EIO;
|
||||
|
||||
to_copy = min(kfifo_len(dev->rx_fifo), count_want);
|
||||
data = kmalloc(to_copy, GFP_KERNEL);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
to_copy = kfifo_get(dev->rx_fifo, data, to_copy);
|
||||
if (to_copy < 0) {
|
||||
kfree(data);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
not_copied = copy_to_user(buf, data, to_copy);
|
||||
kfree(data);
|
||||
|
||||
return to_copy - not_copied;
|
||||
}
|
||||
|
||||
|
||||
static int coa_close(struct inode *inode, struct file *filp)
|
||||
{
|
||||
if (!dev->p_dev->dev_node)
|
||||
return -EIO;
|
||||
SC14421_stop_dip(dev->sc14421_base);
|
||||
|
||||
dev->open = 0;
|
||||
|
||||
kfifo_reset(dev->rx_fifo);
|
||||
kfifo_reset(dev->tx_fifo);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct file_operations coa_fops =
|
||||
{
|
||||
.owner = THIS_MODULE,
|
||||
.open = coa_open,
|
||||
.ioctl = coa_ioctl,
|
||||
.poll = coa_poll,
|
||||
.read = coa_read,
|
||||
.release = coa_close,
|
||||
};
|
||||
|
||||
/**********************************************************************/
|
||||
|
||||
static int com_on_air_suspend (struct pcmcia_device *link)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static int com_on_air_resume (struct pcmcia_device *link)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t
|
||||
com_on_air_irq_handler(int irq, void *dev_id)
|
||||
{
|
||||
struct coa_info * dev = dev_id;
|
||||
jiffies_to_timespec(jiffies, &dev->irq_timestamp);
|
||||
dev->irq_count++;
|
||||
|
||||
switch(dev->operation_mode & COA_MODEMASK)
|
||||
{
|
||||
case COA_MODE_FP:
|
||||
/*station_irq_handler(dev); */
|
||||
break;
|
||||
case COA_MODE_PP:
|
||||
/*phone_irq_handler(dev); */
|
||||
break;
|
||||
case COA_MODE_SNIFF:
|
||||
sniffer_irq_handler(dev);
|
||||
break;
|
||||
default:
|
||||
if (dev->sc14421_base)
|
||||
SC14421_clear_interrupt(dev->sc14421_base);
|
||||
}
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static int com_on_air_probe (struct pcmcia_device *link)
|
||||
{
|
||||
win_req_t req;
|
||||
int ret;
|
||||
|
||||
dev->p_dev = link;
|
||||
link->priv = dev;
|
||||
|
||||
link->dev_node = kzalloc(sizeof(*link->dev_node), GFP_KERNEL);
|
||||
if (!link->dev_node)
|
||||
return -ENOMEM;
|
||||
|
||||
link->devname = kzalloc(strlen(COA_DEVICE_NAME), GFP_KERNEL);
|
||||
if (!link->devname)
|
||||
{
|
||||
ret = -ENOMEM;
|
||||
goto probe_out_5;
|
||||
}
|
||||
|
||||
sprintf(link->devname, COA_DEVICE_NAME);
|
||||
sprintf(link->dev_node->dev_name, COA_DEVICE_NAME);
|
||||
|
||||
printk("com_on_air_cs: >>>>>>>>>>>>>>>>>>>>>>>>\n");
|
||||
printk("com_on_air_cs: card in slot %s\n", link->devname);
|
||||
|
||||
if (link->prod_id[0])
|
||||
printk("com_on_air_cs: prod_id[0] %s\n",
|
||||
link->prod_id[0]);
|
||||
if (link->prod_id[1])
|
||||
printk("com_on_air_cs: prod_id[1] %s\n",
|
||||
link->prod_id[1]);
|
||||
if (link->prod_id[2])
|
||||
printk("com_on_air_cs: prod_id[2] %s\n",
|
||||
link->prod_id[2]);
|
||||
if (link->prod_id[3])
|
||||
printk("com_on_air_cs: prod_id[3] %s\n",
|
||||
link->prod_id[3]);
|
||||
|
||||
link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
|
||||
link->io.NumPorts1 = 16;
|
||||
link->io.Attributes2 = 0;
|
||||
|
||||
link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
|
||||
link->irq.IRQInfo1 = IRQ_LEVEL_ID;
|
||||
link->irq.Handler = com_on_air_irq_handler;
|
||||
link->irq.Instance = dev;
|
||||
|
||||
link->conf.Attributes = CONF_ENABLE_IRQ;
|
||||
link->conf.IntType = INT_MEMORY_AND_IO;
|
||||
link->conf.ConfigIndex = 1;
|
||||
link->conf.Present = PRESENT_OPTION;
|
||||
link->conf.ConfigBase = 0x1020;
|
||||
|
||||
|
||||
req.Attributes = WIN_DATA_WIDTH_16 | WIN_ENABLE;
|
||||
req.Base = 0;
|
||||
req.Size = 0x1000;
|
||||
req.AccessSpeed = 0;
|
||||
|
||||
ret = pcmcia_request_window(&link, &req, &link->win);
|
||||
if (ret != CS_SUCCESS)
|
||||
{
|
||||
printk("couldn't pcmcia_request_window() = 0x%x\n", ret);
|
||||
goto probe_out_4;
|
||||
}
|
||||
|
||||
dev->links[0] = link;
|
||||
dev->memsize[0] = req.Size;
|
||||
dev->membase[0] = ioremap_nocache(req.Base, req.Size);
|
||||
|
||||
if (!dev->membase[0])
|
||||
{
|
||||
printk("com_on_air_cs: ERROR: couldn't ioremap()\n");
|
||||
ret = -EIO;
|
||||
goto probe_out_3;
|
||||
}
|
||||
printk("com_on_air_cs: ioremap()'d baseaddr %p\n", dev->membase[0]);
|
||||
|
||||
link->conf.Present = PRESENT_OPTION;
|
||||
link->socket->functions = 0;
|
||||
|
||||
dev->irq_count = 0;
|
||||
|
||||
ret = pcmcia_request_irq(link, &link->irq);
|
||||
if (ret != CS_SUCCESS)
|
||||
{
|
||||
printk("\ncom_on_air_cs: unable to allocate IRQ %d, ret=%x\n",
|
||||
link->irq.AssignedIRQ, ret);
|
||||
dev->irq = -1;
|
||||
goto probe_out_2;
|
||||
} else {
|
||||
printk("com_on_air_cs: registered IRQ %d\n",
|
||||
link->irq.AssignedIRQ);
|
||||
dev->irq = link->irq.AssignedIRQ;
|
||||
}
|
||||
|
||||
ret = pcmcia_request_configuration(link, &link->conf);
|
||||
if (ret != CS_SUCCESS)
|
||||
{
|
||||
printk("could not pcmcia_request_configuration()\n");
|
||||
goto probe_out_1;
|
||||
}
|
||||
|
||||
ret = pcmcia_get_configuration_info(link, &(dev->config));
|
||||
if (ret == CS_SUCCESS)
|
||||
{
|
||||
printk("com_on_air_cs: %svalid client.\n",
|
||||
(dev->config.Attributes & CONF_VALID_CLIENT) ? "":"in");
|
||||
printk("com_on_air_cs: type 0x%x\n",
|
||||
link->socket->state);
|
||||
printk("com_on_air_cs: function 0x%x\n",
|
||||
dev->config.Function);
|
||||
printk("com_on_air_cs: Attributes %d\n",
|
||||
dev->config.Attributes);
|
||||
printk("com_on_air_cs: Vcc %d\n",
|
||||
dev->config.Vcc);
|
||||
printk("com_on_air_cs: Vpp1 %d\n",
|
||||
dev->config.Vpp1);
|
||||
printk("com_on_air_cs: Vpp2 %d\n",
|
||||
dev->config.Vpp2);
|
||||
printk("com_on_air_cs: IntType %d\n",
|
||||
dev->config.IntType);
|
||||
printk("com_on_air_cs: ConfigBase 0x%x\n",
|
||||
dev->config.ConfigBase);
|
||||
printk("com_on_air_cs: Status %u, "
|
||||
"Pin %u, "
|
||||
"Copy %u, "
|
||||
"Option %u, "
|
||||
"ExtStatus %u\n",
|
||||
dev->config.Status,
|
||||
dev->config.Pin,
|
||||
dev->config.Copy,
|
||||
dev->config.Option,
|
||||
dev->config.ExtStatus);
|
||||
printk("com_on_air_cs: Present %d\n",
|
||||
dev->config.Present);
|
||||
printk("com_on_air_cs: CardValues 0x%x\n",
|
||||
dev->config.CardValues);
|
||||
printk("com_on_air_cs: AssignedIRQ 0x%x\n",
|
||||
dev->config.AssignedIRQ);
|
||||
printk("com_on_air_cs: IRQAttributes 0x%x\n",
|
||||
dev->config.IRQAttributes);
|
||||
printk("com_on_air_cs: BasePort1 0x%x\n",
|
||||
dev->config.BasePort1);
|
||||
printk("com_on_air_cs: NumPorts1 0x%x\n",
|
||||
dev->config.NumPorts1);
|
||||
printk("com_on_air_cs: Attributes1 0x%x\n",
|
||||
dev->config.Attributes1);
|
||||
printk("com_on_air_cs: BasePort2 0x%x\n",
|
||||
dev->config.BasePort2);
|
||||
printk("com_on_air_cs: NumPorts2 0x%x\n",
|
||||
dev->config.NumPorts2);
|
||||
printk("com_on_air_cs: Attributes2 0x%x\n",
|
||||
dev->config.Attributes2);
|
||||
printk("com_on_air_cs: IOAddrLines 0x%x\n",
|
||||
dev->config.IOAddrLines);
|
||||
printk("com_on_air_cs: has%s function_config\n",
|
||||
(link->function_config) ? "":" no");
|
||||
} else {
|
||||
printk("com_on_air_cs: pcmcia_get_configuration_info() "
|
||||
"failed\n");
|
||||
goto probe_out_0;
|
||||
}
|
||||
|
||||
set_device_configbase(dev->config.ConfigBase);
|
||||
|
||||
dev->sc14421_base = ((unsigned short*)(dev->membase[0]));
|
||||
|
||||
ret = get_card_id();
|
||||
printk("com_on_air_cs: get_card_id() = %d\n", ret);
|
||||
switch (ret)
|
||||
{
|
||||
case 0:
|
||||
dev->radio_type = COA_RADIO_TYPE_II;
|
||||
break;
|
||||
case 1:
|
||||
case 2:
|
||||
dev->radio_type = COA_RADIO_TYPE_III;
|
||||
break;
|
||||
default:
|
||||
printk("com_on_air_cs: ERROR; unknown radio type, "
|
||||
"please update driver\n");
|
||||
}
|
||||
dev->card_id = ret;
|
||||
|
||||
printk("com_on_air_cs: -----------------------\n");
|
||||
|
||||
return 0;
|
||||
|
||||
probe_out_0:
|
||||
pcmcia_disable_device(link);
|
||||
probe_out_1:
|
||||
free_irq(dev->irq, dev);
|
||||
probe_out_2:
|
||||
iounmap(dev->membase[0]);
|
||||
probe_out_3:
|
||||
pcmcia_release_window(link->win);
|
||||
probe_out_4:
|
||||
kfree(link->devname);
|
||||
probe_out_5:
|
||||
kfree(link->dev_node);
|
||||
link->dev_node = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void com_on_air_remove(struct pcmcia_device *link)
|
||||
{
|
||||
|
||||
int j;
|
||||
|
||||
printk("com_on_air_cs: COM-ON-AIR card ejected\n");
|
||||
printk("com_on_air_cs: <<<<<<<<<<<<<<<<<<<<<<<\n");
|
||||
|
||||
if (dev->irq >= 0)
|
||||
{
|
||||
printk("com_on_air_cs: freeing interrupt %d\n",
|
||||
dev->irq);
|
||||
free_irq(dev->irq, dev);
|
||||
}
|
||||
|
||||
for (j=0; j<2; j++)
|
||||
{
|
||||
if (dev->membase[j])
|
||||
{
|
||||
printk("com_on_air_cs: iounmap()ing membase[%d]\n", j);
|
||||
iounmap(dev->membase[j]);
|
||||
}
|
||||
if (dev->links[j])
|
||||
if (dev->links[j]->win)
|
||||
{
|
||||
printk("com_on_air_cs: releasing window %d\n",
|
||||
j);
|
||||
pcmcia_release_window(dev->links[j]->win);
|
||||
}
|
||||
}
|
||||
|
||||
printk("com_on_air_cs: pcmcia_disable_device()\n");
|
||||
pcmcia_disable_device(link);
|
||||
if (link->dev_node)
|
||||
{
|
||||
printk("com_on_air_cs: freeing dev_node\n");
|
||||
kfree(link->dev_node);
|
||||
link->dev_node = 0;
|
||||
}
|
||||
if (link->devname)
|
||||
{
|
||||
printk("com_on_air_cs: freeing devname\n");
|
||||
kfree(link->devname);
|
||||
link->devname = 0;
|
||||
}
|
||||
if (dev->sniffer_config)
|
||||
{
|
||||
printk("com_on_air_cs: freeing sniffer_config\n");
|
||||
kfree(dev->sniffer_config);
|
||||
dev->sniffer_config = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static struct pcmcia_device_id com_on_air_ids[] =
|
||||
{
|
||||
/*
|
||||
* the crc32 hashes below are generated by the tool in
|
||||
* Documentation/pcmcia/devicetable.txt
|
||||
*/
|
||||
PCMCIA_DEVICE_PROD_ID12 ("DECTDataDevice", "PCMCIA F22",
|
||||
0x11fe69e9, 0x253670b2),
|
||||
PCMCIA_DEVICE_PROD_ID12 ("DECTDataDevice", "PCMCIA",
|
||||
0x11fe69e9, 0x281f1c5d),
|
||||
#if 1
|
||||
PCMCIA_DEVICE_PROD_ID1234("DOSCH-AMAND", "MMAP PCMCIA",
|
||||
"MXM500", "V1.00",
|
||||
0x4bc552e7, 0x0df519bb,
|
||||
0x09e43c7c, 0x3488c81a),
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
There are more devices out there, I only own the above three.
|
||||
an excerpt from win32 dna.inf:
|
||||
|
||||
%String1%=pcmcia.install,PCMCIA\DOSCH-AMAND-MMAP_PCMCIA-C7D7
|
||||
%String1%=pcmcia.install,PCMCIA\Dosch-Amand-DECT_MultiMedia-BD0D
|
||||
%String1%=pcmcia.install,PCMCIA\DOSCH_&_AMAND-DECT_MULTIMEDIA-1A9F
|
||||
%String1%=pcmcia.install,PCMCIA\DECTDataDevice-F13-6433
|
||||
%String1%=pcmcia.install,PCMCIA\DECTDataDevice-PCMCIA-0EF8
|
||||
%String4%=pci.install,PCI\VEN_11E3&DEV_0001&SUBSYS_000111E3&REV_00
|
||||
%String4%=pci.install,PCI\VEN_11E3&DEV_0001&SUBSYS_00011786&REV_32
|
||||
%String4%=pci.install,PCI\VEN_1786&DEV_0001&SUBSYS_000111E3&REV_00
|
||||
%String5%=freekey2.install,PCMCIA\DECTDataDevice-PCMCIA-FEF2
|
||||
%String6%=freekey2.install,PCMCIA\DECTDataDevice-PCMCIA_F22-4BD3
|
||||
%String6%=freekey2.install,PCMCIA\DECTDataDevice-PCMCIA_F22-BBD9
|
||||
|
||||
#endif
|
||||
PCMCIA_DEVICE_NULL
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(pcmcia, com_on_air_ids);
|
||||
|
||||
/* returns an index into com_on_air_ids[] */
|
||||
int get_card_id(void)
|
||||
{
|
||||
u32 hash[4] = { 0, 0, 0, 0};
|
||||
int i;
|
||||
int found = 0;
|
||||
int ret = -1;
|
||||
for (i=0; i<4; i++)
|
||||
{
|
||||
if (dev->p_dev->prod_id[i])
|
||||
hash[i] = crc32(0,
|
||||
dev->p_dev->prod_id[i],
|
||||
strlen(dev->p_dev->prod_id[i]));
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while(com_on_air_ids[i].match_flags) /* != PCMCIA_DEVICE_NULL */
|
||||
{
|
||||
if ( (hash[0] == com_on_air_ids[i].prod_id_hash[0]) &&
|
||||
(hash[1] == com_on_air_ids[i].prod_id_hash[1]) &&
|
||||
(hash[2] == com_on_air_ids[i].prod_id_hash[2]) &&
|
||||
(hash[3] == com_on_air_ids[i].prod_id_hash[3]) )
|
||||
{
|
||||
found = 1;
|
||||
ret = i;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (!found)
|
||||
printk("com_on_air_cs: ERROR: get_card_id() "
|
||||
"didn't find card, please update driver\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct pcmcia_driver coa_driver =
|
||||
{
|
||||
.owner = THIS_MODULE,
|
||||
.drv =
|
||||
{
|
||||
.name = COA_DEVICE_NAME,
|
||||
},
|
||||
.probe = com_on_air_probe,
|
||||
.remove = com_on_air_remove,
|
||||
|
||||
.suspend = com_on_air_suspend,
|
||||
.resume = com_on_air_resume,
|
||||
|
||||
.id_table = com_on_air_ids,
|
||||
};
|
||||
|
||||
static int __init init_com_on_air_cs(void)
|
||||
{
|
||||
int ret = 0;
|
||||
printk(">>> loading " COA_DEVICE_NAME "\n");
|
||||
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = pcmcia_register_driver(&coa_driver);
|
||||
if (ret != CS_SUCCESS)
|
||||
{
|
||||
printk("couldn't pcmcia_register_driver()\n");
|
||||
goto init_out_3;
|
||||
}
|
||||
|
||||
ret = register_chrdev(0xDEC, COA_DEVICE_NAME, &coa_fops);
|
||||
if (ret < 0)
|
||||
{
|
||||
printk("couldn't register_chrdev()\n");
|
||||
goto init_out_2;
|
||||
}
|
||||
|
||||
spin_lock_init(&dev->rx_fifo_lock);
|
||||
dev->rx_fifo = kfifo_alloc(COA_FIFO_SIZE, GFP_KERNEL,
|
||||
&dev->rx_fifo_lock);
|
||||
if (IS_ERR(dev->rx_fifo))
|
||||
{
|
||||
printk("couldn't kfifo_alloc(dev->rx_fifo)\n");
|
||||
goto init_out_1;
|
||||
}
|
||||
|
||||
spin_lock_init(&dev->tx_fifo_lock);
|
||||
dev->tx_fifo = kfifo_alloc(COA_FIFO_SIZE, GFP_KERNEL,
|
||||
&dev->tx_fifo_lock);
|
||||
if (IS_ERR(dev->tx_fifo))
|
||||
{
|
||||
printk("couldn't kfifo_alloc(dev->tx_fifo)\n");
|
||||
goto init_out_0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
init_out_0:
|
||||
kfifo_free(dev->rx_fifo);
|
||||
init_out_1:
|
||||
unregister_chrdev(0xDEC, COA_DEVICE_NAME);
|
||||
init_out_2:
|
||||
pcmcia_unregister_driver(&coa_driver);
|
||||
init_out_3:
|
||||
kfree(dev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __exit exit_com_on_air_cs(void)
|
||||
{
|
||||
printk("<<< unloading " COA_DEVICE_NAME "\n");
|
||||
|
||||
if (!dev) return;
|
||||
|
||||
unregister_chrdev(0xDEC, COA_DEVICE_NAME);
|
||||
|
||||
pcmcia_unregister_driver(&coa_driver);
|
||||
|
||||
kfifo_free(dev->rx_fifo);
|
||||
kfifo_free(dev->tx_fifo);
|
||||
|
||||
kfree(dev);
|
||||
}
|
||||
|
||||
module_init(init_com_on_air_cs);
|
||||
module_exit(exit_com_on_air_cs);
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* com_on_air_cs - basic driver for the Dosch and Amand "com on air" cards
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* authors:
|
||||
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
|
||||
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef COM_ON_AIR_H
|
||||
#define COM_ON_AIR_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <pcmcia/cs_types.h>
|
||||
#include <pcmcia/cs.h>
|
||||
|
||||
|
||||
struct coa_info
|
||||
{
|
||||
struct pcmcia_device *p_dev;
|
||||
config_info_t config;
|
||||
int open;
|
||||
|
||||
int irq;
|
||||
int irq_count;
|
||||
struct timespec irq_timestamp;
|
||||
|
||||
struct pcmcia_device *links[2];
|
||||
|
||||
caddr_t membase[2];
|
||||
u_int memsize[2];
|
||||
|
||||
|
||||
/* hardware configs */
|
||||
unsigned short *sc14421_base;
|
||||
unsigned int card_id; /* index into com_on_air_ids[] */
|
||||
unsigned int radio_type;
|
||||
|
||||
unsigned int operation_mode;
|
||||
|
||||
/* struct fp_cfg *fp_config; */
|
||||
/* struct pp_cfg *pp_config; */
|
||||
struct sniffer_cfg *sniffer_config;
|
||||
|
||||
struct kfifo *rx_fifo;
|
||||
spinlock_t rx_fifo_lock;
|
||||
struct kfifo *tx_fifo;
|
||||
spinlock_t tx_fifo_lock;
|
||||
};
|
||||
|
||||
|
||||
int get_card_id(void);
|
||||
|
||||
/* radio types */
|
||||
#define COA_RADIO_TYPE_II 0
|
||||
#define COA_RADIO_TYPE_III 1
|
||||
#define COA_RADIO_FREEPAD 2
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* com_on_air_cs - basic driver for the Dosch and Amand "com on air" cards
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* authors:
|
||||
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
|
||||
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef COM_ON_AIR_USER_H
|
||||
#define COM_ON_AIR_USER_H
|
||||
|
||||
/* operation modes */
|
||||
#define COA_MODEMASK 0xFF00
|
||||
#define COA_SUBMODEMASK 0x00FF
|
||||
|
||||
#define COA_MODE_IDLE 0x0000
|
||||
#define COA_MODE_FP 0x0100
|
||||
#define COA_MODE_PP 0x0200
|
||||
#define COA_MODE_SNIFF 0x0300
|
||||
#define COA_MODE_JAM 0x0400
|
||||
|
||||
|
||||
#define COA_SUBMODE_SNIFF_SCANFP 0x0001
|
||||
#define COA_SUBMODE_SNIFF_SCANPP 0x0002
|
||||
#define COA_SUBMODE_SNIFF_SYNC 0x0003
|
||||
|
||||
|
||||
/* ioctl */
|
||||
|
||||
#define COA_IOCTL_MODE 0xD000
|
||||
#define COA_IOCTL_RADIO 0xD001
|
||||
#define COA_IOCTL_RX 0xD002
|
||||
#define COA_IOCTL_TX 0xD003
|
||||
#define COA_IOCTL_CHAN 0xD004
|
||||
#define COA_IOCTL_SLOT 0xD005
|
||||
#define COA_IOCTL_RSSI 0xD006
|
||||
#define COA_IOCTL_FIRMWARE 0xD007 /* request_firmware() */
|
||||
#define COA_IOCTL_SETRFPI 0xD008
|
||||
|
||||
#endif
|
|
@ -0,0 +1,318 @@
|
|||
/*
|
||||
* com_on_air_cs - basic driver for the Dosch and Amand "com on air" cards
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* authors:
|
||||
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
|
||||
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "dect.h"
|
||||
|
||||
#define DECT_A_TA 0xe0
|
||||
#define DECT_A_Q1 0x10
|
||||
#define DECT_A_BA 0x0e
|
||||
#define DECT_A_Q2 0x01
|
||||
|
||||
#define DECT_Q_TYPE 0x80
|
||||
#define DECT_N_TYPE 0x60
|
||||
#define DECT_P_TYPE 0xe0
|
||||
|
||||
#define DECT_Q_HEAD 0xf0
|
||||
|
||||
#define DECT_Q_HEAD_SSINFO 0x00 /* Static System info */
|
||||
#define DECT_Q_HEAD_EXTRF1 0x20 /* Extended RF Carriers Part 1 */
|
||||
#define DECT_Q_HEAD_FPC 0x30 /* Fixed Part Capabilities */
|
||||
#define DECT_Q_HEAD_MULTIFN 0x60 /* Multi Frame Number */
|
||||
|
||||
#define DECT_Q_SSINFO_SLOT 0x0f
|
||||
|
||||
|
||||
#define DECT_P_EXTFLAG 0x80
|
||||
#define DECT_P_HEAD 0x70
|
||||
|
||||
#define DECT_P_HEAD_ZEROLP 0x00 /* Zero Length Page */
|
||||
#define DECT_P_HEAD_SHORTLP 0x10 /* Short Length Page */
|
||||
#define DECT_P_HEAD_FULLLP 0x20 /* Full Length Page */
|
||||
#define DECT_P_HEAD_MACRES 0x30 /* MAC Resume Page */
|
||||
#define DECT_P_HEAD_NOTLAST36 0x40 /* Not the Last 36 Bits of Long Page */
|
||||
#define DECT_P_HEAD_FIRST36 0x50 /* First 36 Bit of Long Page */
|
||||
#define DECT_P_HEAD_LAST26 0x60 /* Last 36 Bit of Long Page */
|
||||
#define DECT_P_HEAD_ALLOFLP 0x70 /* All of Long Page (first and last) */
|
||||
|
||||
#define DECT_P_INFOTYPE 0xf0
|
||||
|
||||
#define DECT_P_IT_FILLBITS 0x00 /* Fill Bits */
|
||||
#define DECT_P_IT_BFCIRCUIT 0x10 /* Blind Full Slot Information for \
|
||||
Circuit Mode Service */
|
||||
#define DECT_P_IT_OTHERBEAR 0x20 /* Other Bearer */
|
||||
#define DECT_P_IT_RECOTHERBEAR 0x30 /* Recommended Other Bearer */
|
||||
#define DECT_P_IT_GOODRFPBEAR 0x40 /* Good RFP Bearer */
|
||||
#define DECT_P_IT_DUMMYCLPOS 0x50 /* Dummy or C/L Bearer Position */
|
||||
#define DECT_P_IT_EXTMODULTYPE 0x60 /* Extended Modulation Type */
|
||||
#define DECT_P_IT_ESCAPE 0x70 /* Escape */
|
||||
#define DECT_P_IT_DUMMYCLBEARM 0x80 /* Dummy or C/L Bearer Marker */
|
||||
#define DECT_P_IT_REPLACEINFO 0x90 /* Bearer Handover/Replacement \
|
||||
Information */
|
||||
|
||||
#define DECT_P_IT_BEARERPOS_SN 0x0f /* Slot Number */
|
||||
#define DECT_P_IT_BEARERPOS_SP 0xc0 /* Start Position */
|
||||
#define DECT_P_IT_BEARERPOS_CN 0x3f /* Channel */
|
||||
|
||||
int dect_is_RFPI_Packet(unsigned char *packet)
|
||||
{
|
||||
if ((packet[5] & DECT_A_TA) == DECT_N_TYPE)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dect_compare_RFPI(unsigned char *packet, unsigned char* RFPI)
|
||||
{
|
||||
if ((packet[5] & DECT_A_TA) == DECT_N_TYPE)
|
||||
{
|
||||
if (!memcmp(&packet[6], RFPI, 5))
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dect_get_slot(unsigned char *packet)
|
||||
{
|
||||
int slot = -1;
|
||||
|
||||
if ((packet[5] & DECT_A_TA) == DECT_Q_TYPE)
|
||||
{
|
||||
if ((packet[6] & DECT_Q_HEAD) == DECT_Q_HEAD_SSINFO)
|
||||
{
|
||||
slot = packet[6] & DECT_Q_SSINFO_SLOT;
|
||||
}
|
||||
}
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
int dect_is_multiframe_number(unsigned char *packet)
|
||||
{
|
||||
if ((packet[5] & DECT_A_TA) == DECT_Q_TYPE)
|
||||
{
|
||||
/*printk("bl"); */
|
||||
if ((packet[6] & DECT_Q_HEAD) == DECT_Q_HEAD_MULTIFN)
|
||||
{
|
||||
/*printk("aa\n"); */
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dect_is_fp_packet(unsigned char *packet)
|
||||
{
|
||||
if ( (packet[3] == 0xe9) && (packet[4] == 0x8a) )
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dect_is_pp_packet(unsigned char *packet)
|
||||
{
|
||||
if ( (packet[3] == 0x16) && (packet[4] == 0x75) )
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int dect_update_slottable(struct dect_slot_info *slottable, int slot, unsigned char *packet)
|
||||
{
|
||||
if (slottable[slot].type == DECT_SLOTTYPE_SCAN)
|
||||
{
|
||||
printk("received packet on scanslot %u on carrier %u\n", slot, slottable[slot].channel);
|
||||
slottable[slot].type = DECT_SLOTTYPE_CARRIER;
|
||||
if (slottable[slot].channel == 0)
|
||||
slottable[slot].channel = 9;
|
||||
else
|
||||
slottable[slot].channel--;
|
||||
slottable[slot].errcnt = 0;
|
||||
slottable[slot].update = 1;
|
||||
|
||||
if (slot > 12)
|
||||
{
|
||||
slottable[slot-12].type = DECT_SLOTTYPE_CARRIER;
|
||||
if (slottable[slot-12].channel == 0)
|
||||
slottable[slot-12].channel = 9;
|
||||
else
|
||||
slottable[slot-12].channel--;
|
||||
slottable[slot-12].errcnt = 0;
|
||||
slottable[slot].update = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
slottable[slot+12].type = DECT_SLOTTYPE_CARRIER;
|
||||
if (slottable[slot+12].channel == 0)
|
||||
slottable[slot+12].channel = 9;
|
||||
else
|
||||
slottable[slot+12].channel--;
|
||||
slottable[slot+12].errcnt = 0;
|
||||
slottable[slot].update = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (dect_is_fp_packet(packet))
|
||||
{
|
||||
|
||||
switch(packet[5] & DECT_A_TA)
|
||||
{
|
||||
case DECT_P_TYPE:
|
||||
if ( ( (packet[6] & DECT_P_HEAD) ==
|
||||
DECT_P_HEAD_ZEROLP) ||
|
||||
( (packet[6] & DECT_P_HEAD) ==
|
||||
DECT_P_HEAD_SHORTLP) )
|
||||
{
|
||||
switch((packet[9] & DECT_P_INFOTYPE))
|
||||
{
|
||||
case DECT_P_IT_OTHERBEAR:
|
||||
{
|
||||
int newslot = (packet[9] & DECT_P_IT_BEARERPOS_SN) % 12;
|
||||
slottable[newslot].active = 1;
|
||||
slottable[newslot].channel = packet[10] & DECT_P_IT_BEARERPOS_CN;
|
||||
slottable[newslot].type = DECT_SLOTTYPE_CARRIER;
|
||||
slottable[newslot].errcnt = 0;
|
||||
slottable[newslot].update = 1;
|
||||
|
||||
slottable[newslot+12].active = 1;
|
||||
slottable[newslot+12].channel = packet[10] & DECT_P_IT_BEARERPOS_CN;
|
||||
slottable[newslot+12].type = DECT_SLOTTYPE_CARRIER;
|
||||
slottable[newslot+12].errcnt = 0;
|
||||
slottable[newslot+12].update = 1;
|
||||
|
||||
/*printk("\n\nstation switching to slot %u channel %u\n\n",newslot, packet[10] & DECT_P_IT_BEARERPOS_CN); */
|
||||
return 1;
|
||||
}
|
||||
|
||||
case DECT_P_IT_BFCIRCUIT: /* set scanning slots */
|
||||
{
|
||||
int i, x, ret = 0;
|
||||
unsigned int slots = (((unsigned int)(packet[9] & ~DECT_P_INFOTYPE)) << 8) | packet[10];
|
||||
|
||||
for (i=0; i<12; i++)
|
||||
{
|
||||
x = (slots & 0x800 ? 1:0);
|
||||
slots <<= 1;
|
||||
|
||||
if (x && (!slottable[i].active))
|
||||
{
|
||||
printk("scanning on slot %u\n", i);
|
||||
slottable[i].active = 1;
|
||||
slottable[i].channel = 0; /* channel unknown at this position */
|
||||
slottable[i].type = DECT_SLOTTYPE_SCAN;
|
||||
slottable[i].errcnt = 0;
|
||||
slottable[i].update = 1;
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
if (x && (!slottable[i+12].active))
|
||||
{
|
||||
printk("scanning on slot %u\n", i + 12);
|
||||
slottable[i+12].active = 1;
|
||||
slottable[i+12].channel = 0; /* channel unknown at this position */
|
||||
slottable[i+12].type = DECT_SLOTTYPE_SCAN;
|
||||
slottable[i+12].errcnt = 0;
|
||||
slottable[i+12].update = 1;
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
case DECT_Q_TYPE:
|
||||
if ((packet[6] & DECT_Q_HEAD) == DECT_Q_HEAD_SSINFO)
|
||||
{
|
||||
uint8_t pscan = packet[10];
|
||||
int i, ret = 0;
|
||||
|
||||
for (i=0; i<24; i++)
|
||||
{
|
||||
if (slottable[i].active)
|
||||
{
|
||||
if (slottable[i].type == DECT_SLOTTYPE_SCAN)
|
||||
{
|
||||
/* if (pscan == 0)
|
||||
pscan = 9;
|
||||
else
|
||||
pscan--;
|
||||
*/
|
||||
slottable[i].channel = pscan;
|
||||
slottable[i].update = 1;
|
||||
ret = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dect_receive_error(struct dect_slot_info *slottable, int slot)
|
||||
{
|
||||
slottable[slot].errcnt++;
|
||||
|
||||
if (slottable[slot].type != DECT_SLOTTYPE_SCAN)
|
||||
{
|
||||
if (slottable[slot].errcnt > 32)
|
||||
{
|
||||
slottable[slot].active = 0;
|
||||
slottable[slot].update = 1;
|
||||
|
||||
printk("slot %u on channel %u died\n", slot, slottable[slot].channel);
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dect_update_scanchannels(struct dect_slot_info *slottable)
|
||||
{
|
||||
int i, ret = 0;
|
||||
|
||||
for (i=0; i<24; i++) /* Increment primary scan channel */
|
||||
{
|
||||
if (slottable[i].active)
|
||||
{
|
||||
if (slottable[i].type == DECT_SLOTTYPE_SCAN)
|
||||
{
|
||||
slottable[i].channel++;
|
||||
if (slottable[i].channel > 9)
|
||||
slottable[i].channel = 0;
|
||||
|
||||
slottable[i].update = 1;
|
||||
|
||||
ret = 1;
|
||||
|
||||
/*printk("slot %u will now scan on carrier %u\n", i, slottable[i].channel); */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* com_on_air_cs - basic driver for the Dosch and Amand "com on air" cards
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* authors:
|
||||
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
|
||||
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DECT_H
|
||||
#define DECT_H
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <linux/kernel.h>
|
||||
|
||||
#define DECT_SLOTTYPE_CARRIER 0
|
||||
#define DECT_SLOTTYPE_SCAN 1
|
||||
|
||||
struct dect_slot_info
|
||||
{
|
||||
uint8_t active;
|
||||
uint8_t channel;
|
||||
uint8_t type;
|
||||
uint8_t errcnt;
|
||||
uint8_t update;
|
||||
};
|
||||
|
||||
|
||||
int dect_is_RFPI_Packet(unsigned char *packet);
|
||||
int dect_compare_RFPI(unsigned char *packet, unsigned char* RFPI);
|
||||
int dect_get_slot(unsigned char *packet);
|
||||
int dect_is_multiframe_number(unsigned char *packet);
|
||||
int dect_is_fp_packet(unsigned char *packet);
|
||||
int dect_is_pp_packet(unsigned char *packet);
|
||||
int dect_update_slottable(struct dect_slot_info *slottable, int slot, unsigned char *packet);
|
||||
int dect_receive_error(struct dect_slot_info *slottable, int slot);
|
||||
int dect_update_scanchannels(struct dect_slot_info *slottable);
|
||||
#endif
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* com_on_air_cs - basic driver for the Dosch and Amand "com on air" cards
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* authors:
|
||||
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
|
||||
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DIP_OPCODE_H
|
||||
#define DIP_OPCODE_H
|
||||
|
||||
|
||||
#define BR 0x01
|
||||
#define JMP 0x02
|
||||
#define JMP1 0x03
|
||||
#define RTN 0x04
|
||||
#define BK_A1 0x05
|
||||
#define WNTM1 0x06
|
||||
#define WNTP1 0x07
|
||||
#define WNT 0x08
|
||||
#define WT 0x09
|
||||
#define RFDIS 0x0a
|
||||
#define RFEN 0x0b
|
||||
#define LD_PTR 0x0c
|
||||
#define SLOTZERO 0x0d
|
||||
#define BK_A 0x0e
|
||||
#define BK_C 0x0f
|
||||
|
||||
|
||||
#define B_RST 0x20
|
||||
#define B_ST2 0x21
|
||||
#define B_XT 0x24
|
||||
#define B_BT2 0x25
|
||||
#define B_BTFU 0x25
|
||||
#define B_XOFF 0x26
|
||||
#define B_ON 0x27
|
||||
#define B_XON 0x27
|
||||
#define UNLCK 0x28
|
||||
#define B_SR 0x29
|
||||
#define B_XR 0x2b
|
||||
#define EN_SL_ADJ 0x2c
|
||||
#define B_BR2 0x2d
|
||||
#define B_BRFU 0x2d
|
||||
#define B_RINV 0x2e
|
||||
#define B_RON 0x2f
|
||||
|
||||
|
||||
#define B_ST 0x31
|
||||
#define B_TX 0x31
|
||||
#define B_AT 0x32
|
||||
#define B_RC 0x33
|
||||
#define B_BT 0x34
|
||||
#define B_BTFP 0x35
|
||||
#define B_BTP 0x35
|
||||
#define B_AT2 0x37
|
||||
#define B_WRS 0x39
|
||||
#define B_AR 0x3a
|
||||
#define B_BR 0x3c
|
||||
#define B_BRP 0x3d
|
||||
#define B_BRFP 0x3d
|
||||
#define B_AR2 0x3f
|
||||
|
||||
|
||||
#define D_RST 0x40
|
||||
#define D_ON 0x42
|
||||
#define D_OFF 0x43
|
||||
#define D_PREP 0x44
|
||||
#define WSC 0x48
|
||||
|
||||
|
||||
#define D_LDK 0x50
|
||||
#define D_LDS 0x57
|
||||
#define D_WRS 0x5f
|
||||
|
||||
|
||||
#define U_PSC 0x60
|
||||
#define U_INT0 0x61
|
||||
#define RCK_INT 0x62
|
||||
#define RCK_EXT 0x63
|
||||
#define B_WB_OFF 0x64
|
||||
#define B_WB_ON 0x65
|
||||
#define CLK1 0x66
|
||||
#define CLK3 0x67
|
||||
#define U_CK8 0x68
|
||||
#define U_CK4 0x69
|
||||
#define U_CK2 0x6a
|
||||
#define U_INT1 0x6b
|
||||
#define U_CK1 0x6c
|
||||
#define U_INT2 0x6d
|
||||
#define U_INT3 0x6f
|
||||
|
||||
|
||||
#define A_RCV0 0x80
|
||||
#define A_RCV36 0x82
|
||||
#define A_RCV30 0x83
|
||||
#define A_RCV24 0x84
|
||||
#define A_RCV18 0x85
|
||||
#define A_RCV12 0x86
|
||||
#define A_RCV6 0x87
|
||||
#define A_RCV33 0x8a
|
||||
#define A_RCV27 0x8b
|
||||
#define A_RCV21 0x8c
|
||||
#define A_RCV15 0x8d
|
||||
#define A_RCV9 0x8e
|
||||
#define A_RCV3 0x8f
|
||||
|
||||
|
||||
#define MEN3N 0xa2
|
||||
#define MEN3 0xa3
|
||||
#define MEN1N 0xa4
|
||||
#define MEN1 0xa5
|
||||
#define MEN2N 0xa6
|
||||
#define MEN2 0xa7
|
||||
#define M_RD 0xa8
|
||||
#define M_RST 0xa9
|
||||
|
||||
|
||||
#define M_WRS 0xb8
|
||||
#define M_WR 0xb9
|
||||
|
||||
|
||||
#define A_RST 0xc0
|
||||
#define A_MUTE 0xc1
|
||||
#define A_STOFF 0xc2
|
||||
#define A_ALAW 0xc3
|
||||
#define A_DT 0xc4
|
||||
#define A_NORM 0xc5
|
||||
#define A_LDR 0xc6
|
||||
#define A_LDW 0xc7
|
||||
#define A_LIN 0xc8
|
||||
#define A_MTOFF 0xc9
|
||||
#define A_MUTE1 0xca
|
||||
#define A_MTOFF1 0xcb
|
||||
#define A_STON 0xcc
|
||||
#define A_DT1 0xcd
|
||||
#define A_LDR1 0xce
|
||||
#define A_LDW1 0xcf
|
||||
|
||||
|
||||
#define A_STRN 0xe0
|
||||
#define P_LD 0xe8
|
||||
#define P_EN 0xe9
|
||||
#define P_SC 0xea
|
||||
#define A_RST1 0xeb
|
||||
#define P_LDL 0xec
|
||||
#define P_LDH 0xed
|
||||
#define C_ON 0xee
|
||||
#define C_OFF 0xef
|
||||
|
||||
|
||||
#define C_LD 0xfa
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1 @@
|
|||
extern unsigned char _fw[509];
|
|
@ -0,0 +1,37 @@
|
|||
CFLAGS=-Wall -O2
|
||||
|
||||
FW=sc14421_firmware
|
||||
|
||||
FW1=sc14421_II_sniff_scan
|
||||
FW2=sc14421_II_sniff_sync
|
||||
|
||||
ALL_FW=$(FW1) $(FW2)
|
||||
|
||||
BIN2C=./bin2c
|
||||
|
||||
all: ../$(FW).h ../$(FW).c
|
||||
|
||||
../$(FW).h: $(FW1).h $(FW2).h
|
||||
cat sc14421_header.h $^ sc14421_footer.h > $@
|
||||
|
||||
../$(FW).c: $(FW1).c $(FW2).c
|
||||
cat $^ > $@
|
||||
|
||||
$(FW1).c $(FW2).c: $(FW1).bin $(FW2).bin $(BIN2C)
|
||||
$(BIN2C) $(@:.c=.bin) $(@:.c=)_fw > $@
|
||||
|
||||
%.bin: %.p
|
||||
p2bin $^ $@ -r 0-507
|
||||
|
||||
%.p: %.asm
|
||||
asl $^
|
||||
|
||||
$(FW1).h $(FW2).h:
|
||||
echo "extern unsigned char $(@:.h=)_fw[509];" > $@
|
||||
|
||||
clean:
|
||||
rm -f ../$(FW).h ../$(FW).c $(BIN2C)
|
||||
rm -f $(foreach f,$(ALL_FW),$f.c)
|
||||
rm -f $(foreach f,$(ALL_FW),$f.h)
|
||||
rm -f $(foreach f,$(ALL_FW),$f.bin)
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#define HEADER_FMT \
|
||||
"\n\n" \
|
||||
"/* automatically generated file\n" \
|
||||
" * DO NOT EDIT\n" \
|
||||
" * edit firmware/filename.asm instead */\n" \
|
||||
"\n" \
|
||||
"unsigned char %s[] = {\n"
|
||||
|
||||
#define FOOTER "};\n"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if(argc<3)
|
||||
{
|
||||
printf("usage: bin2c bin-file varname > c-file\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int f = open(argv[1], O_RDONLY);
|
||||
if(f<0)
|
||||
{
|
||||
printf("cant open(\"%s\"): %s\n", argv[1], strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf(HEADER_FMT, argv[2]);
|
||||
|
||||
uint32_t wordcount = 0;
|
||||
uint16_t w;
|
||||
while (2 == read(f, &w, 2))
|
||||
{
|
||||
if (!wordcount)
|
||||
printf("\t");
|
||||
else
|
||||
if (!(wordcount % 4))
|
||||
printf(",\n\t");
|
||||
else
|
||||
printf(", ");
|
||||
printf("0x%.2x, 0x%.2x", (w&0xff00)>>8, w&0xff);
|
||||
wordcount++;
|
||||
}
|
||||
printf(FOOTER);
|
||||
close(f);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,110 @@
|
|||
CPU SC14421
|
||||
|
||||
ORG 0
|
||||
BR Start
|
||||
|
||||
|
||||
PB_LED EQU 0x80
|
||||
PB_RX_ON EQU 0x40
|
||||
PB_TX_ON EQU 0x10
|
||||
PB_RADIOPOWER EQU 0x04
|
||||
PB_DCTHRESHOLD EQU 0x02
|
||||
PB_RSSI EQU 0x01
|
||||
|
||||
;-------------------------------------------------------------
|
||||
|
||||
Start: B_RST
|
||||
BK_C 0x00
|
||||
C_LD 0x10
|
||||
WT 10
|
||||
B_RC 0x00
|
||||
WT 8
|
||||
B_RST
|
||||
C_ON
|
||||
WT 10
|
||||
P_EN
|
||||
P_LD PB_RADIOPOWER
|
||||
RCK_INT
|
||||
RFEN
|
||||
;-------------------------------------------------------------
|
||||
|
||||
BK_C 0x20
|
||||
JMP RFInit
|
||||
TryAgain: JMP label_B1
|
||||
WT 250
|
||||
P_SC 0x20
|
||||
P_LDH PB_RX_ON|PB_DCTHRESHOLD
|
||||
UNLCK
|
||||
WT 64
|
||||
B_XOFF
|
||||
B_SR
|
||||
WNT 20
|
||||
JMP1 SFieldFound
|
||||
BR TryAgain
|
||||
;-------------------------------------------------------------
|
||||
|
||||
SFieldFound: WNT 23
|
||||
P_SC 0x00
|
||||
JMP ReceiveSlot
|
||||
U_INT0
|
||||
BR TryAgain
|
||||
;-------------------------------------------------------------
|
||||
|
||||
ReceiveSlot: JMP label_B1
|
||||
JMP RecvPP
|
||||
WT 1
|
||||
B_BRFU 0x0e
|
||||
WT 255
|
||||
WT 73
|
||||
P_LDH PB_RSSI
|
||||
P_LDL PB_RX_ON
|
||||
B_WRS 0x00
|
||||
WT 6
|
||||
B_RST
|
||||
P_LDL PB_RX_ON|PB_TX_ON
|
||||
WT 5
|
||||
RTN
|
||||
;-------------------------------------------------------------
|
||||
|
||||
RecvPP: P_LDH PB_RX_ON
|
||||
P_LDL PB_RSSI
|
||||
WT 34
|
||||
WNT 1
|
||||
B_XON
|
||||
P_LDH PB_DCTHRESHOLD
|
||||
WT 5
|
||||
B_SR
|
||||
EN_SL_ADJ
|
||||
WT 12
|
||||
P_LDL PB_DCTHRESHOLD
|
||||
WT 33
|
||||
B_AR2 0x06
|
||||
WT 61
|
||||
RTN
|
||||
;-------------------------------------------------------------
|
||||
|
||||
RFInit: RFEN
|
||||
MEN1N
|
||||
WT 2
|
||||
M_WR 0x4A
|
||||
WT 25
|
||||
M_RST
|
||||
MEN1
|
||||
MEN1N
|
||||
M_WR 0x4D
|
||||
WT 10
|
||||
M_RST
|
||||
MEN1
|
||||
RTN
|
||||
;-------------------------------------------------------------
|
||||
|
||||
label_B1: B_RST
|
||||
B_RC 0x58
|
||||
WT 8
|
||||
MEN2
|
||||
WT 182
|
||||
MEN2N
|
||||
WT 16
|
||||
RTN
|
||||
;-------------------------------------------------------------
|
||||
|
|
@ -0,0 +1,298 @@
|
|||
CPU SC14421
|
||||
|
||||
ORG 0
|
||||
BR Start
|
||||
|
||||
|
||||
PB_LED EQU 0x80
|
||||
PB_RX_ON EQU 0x40
|
||||
PB_TX_ON EQU 0x10
|
||||
PB_RADIOPOWER EQU 0x04
|
||||
PB_DCTHRESHOLD EQU 0x02
|
||||
PB_RSSI EQU 0x01
|
||||
|
||||
;-------------------------------------------------------------
|
||||
|
||||
Start: BR InitDIP
|
||||
;-------------------------------------------------------------
|
||||
|
||||
SlotTable: SLOTZERO
|
||||
JP0: BK_C 0x20
|
||||
PP0: WNT 2
|
||||
JP2: BK_C 0x30
|
||||
PP2: WNT 2
|
||||
JP4: BK_C 0x40
|
||||
PP4: WNT 2
|
||||
JP6: BK_C 0x50
|
||||
PP6: WNT 2
|
||||
JP8: BK_C 0x60
|
||||
PP8: WNT 2
|
||||
JP10: BK_C 0x70
|
||||
PP10: WNT 2
|
||||
U_INT0
|
||||
JP12: BK_C 0x80
|
||||
PP12: WNT 2
|
||||
JP14: BK_C 0x90
|
||||
PP14: WNT 2
|
||||
JP16: BK_C 0xA0
|
||||
PP16: WNT 2
|
||||
JP18: BK_C 0xB0
|
||||
PP18: WNT 2
|
||||
JP20: BK_C 0xC0
|
||||
PP20: WNT 2
|
||||
JP22: BK_C 0xD0
|
||||
PP22: WNT 2
|
||||
U_INT3
|
||||
P_LDL 0x80
|
||||
BR SlotTable
|
||||
;-------------------------------------------------------------
|
||||
|
||||
label_28: JMP RFInit
|
||||
JMP label_B1
|
||||
BR label_2D
|
||||
;-------------------------------------------------------------
|
||||
|
||||
JMP RFInit
|
||||
JMP label_B3
|
||||
label_2D: JMP RecvPP
|
||||
WT 1
|
||||
B_BRFU 0x0E
|
||||
JMP label_6B
|
||||
BR label_51
|
||||
;-------------------------------------------------------------
|
||||
|
||||
JMP RFInit
|
||||
JMP label_B1
|
||||
BR label_37
|
||||
;-------------------------------------------------------------
|
||||
|
||||
JMP RFInit
|
||||
JMP label_B3
|
||||
label_37: JMP RecvPP
|
||||
BR label_92
|
||||
;-------------------------------------------------------------
|
||||
|
||||
JMP RFInit
|
||||
JMP label_B1
|
||||
BR label_3E
|
||||
;-------------------------------------------------------------
|
||||
|
||||
JMP RFInit
|
||||
JMP label_B3
|
||||
label_3E: JMP label_70
|
||||
WT 1
|
||||
B_BTFU 0x0E
|
||||
JMP label_7C
|
||||
BR label_54
|
||||
;-------------------------------------------------------------
|
||||
|
||||
JMP RFInit
|
||||
JMP label_B3
|
||||
JMP label_70
|
||||
WT 1
|
||||
B_BT 0x0E
|
||||
JMP label_7F
|
||||
BR label_53
|
||||
;-------------------------------------------------------------
|
||||
|
||||
JMP RFInit
|
||||
JMP label_B1
|
||||
BR label_4F
|
||||
;-------------------------------------------------------------
|
||||
|
||||
JMP RFInit
|
||||
JMP label_B3
|
||||
label_4F: JMP label_70
|
||||
BR label_9B
|
||||
;-------------------------------------------------------------
|
||||
|
||||
label_51: B_WRS 0x00
|
||||
WT 6
|
||||
label_53: B_RST
|
||||
label_54: P_LDL 0x50
|
||||
WT 5
|
||||
WNT 1
|
||||
label_57: RTN
|
||||
;-------------------------------------------------------------
|
||||
|
||||
label_58: B_RST
|
||||
P_LDL 0x50
|
||||
BR label_57
|
||||
;-------------------------------------------------------------
|
||||
|
||||
RecvPP: P_LDH 0x40
|
||||
P_LDL PB_RSSI
|
||||
WT 25
|
||||
WNT 1
|
||||
WT 9
|
||||
B_XON
|
||||
P_LDH 0x02
|
||||
WT 5
|
||||
B_SR
|
||||
EN_SL_ADJ
|
||||
WT 12
|
||||
P_LDL 0x02
|
||||
WT 33
|
||||
B_AR2 0x06
|
||||
WT 61
|
||||
RTN
|
||||
;-------------------------------------------------------------
|
||||
|
||||
label_6B: WT 249
|
||||
WT 79
|
||||
label_6D: P_LDH PB_RSSI
|
||||
P_LDL 0x40
|
||||
RTN
|
||||
;-------------------------------------------------------------
|
||||
|
||||
label_70: P_LDH 0x00
|
||||
WT 40
|
||||
B_RST
|
||||
B_RC 0x50
|
||||
WNT 1
|
||||
B_ST 0x00
|
||||
WT 1
|
||||
P_LDH 0x10
|
||||
WT 37
|
||||
B_AT2 0x06
|
||||
WT 61
|
||||
RTN
|
||||
;-------------------------------------------------------------
|
||||
|
||||
label_7C: WT 249
|
||||
WT 84
|
||||
B_RST
|
||||
label_7F: P_LDL 0x10
|
||||
WT 8
|
||||
P_LDL 0x00
|
||||
RTN
|
||||
;-------------------------------------------------------------
|
||||
|
||||
label_83: B_XON
|
||||
WT 15
|
||||
B_XOFF
|
||||
WT 61
|
||||
RTN
|
||||
;-------------------------------------------------------------
|
||||
|
||||
label_88: WT 61
|
||||
JMP label_83
|
||||
JMP label_83
|
||||
JMP label_83
|
||||
JMP label_83
|
||||
JMP label_83
|
||||
WT 1
|
||||
B_XON
|
||||
WT 11
|
||||
RTN
|
||||
;-------------------------------------------------------------
|
||||
|
||||
label_92: B_BR 0x0E
|
||||
JMP label_88
|
||||
WT 3
|
||||
B_XR
|
||||
WT 6
|
||||
JMP label_6D
|
||||
B_WRS 0x00
|
||||
WT 6
|
||||
BR label_58
|
||||
;-------------------------------------------------------------
|
||||
|
||||
label_9B: B_BT 0x0E
|
||||
WT 3
|
||||
JMP label_88
|
||||
B_XT
|
||||
WT 13
|
||||
B_RST
|
||||
JMP label_7F
|
||||
BR label_58
|
||||
;-------------------------------------------------------------
|
||||
|
||||
RFInit: RFEN
|
||||
MEN1N
|
||||
WT 1
|
||||
WT 1
|
||||
M_WR 0x4A
|
||||
WT 25
|
||||
M_RST
|
||||
MEN1
|
||||
MEN1N
|
||||
M_WR 0x4D
|
||||
WT 10
|
||||
M_RST
|
||||
MEN1
|
||||
RTN
|
||||
;-------------------------------------------------------------
|
||||
|
||||
label_B1: P_LDL 0x20
|
||||
BR label_B5
|
||||
;-------------------------------------------------------------
|
||||
|
||||
label_B3: P_LDH 0x20
|
||||
BR label_B5
|
||||
;-------------------------------------------------------------
|
||||
|
||||
label_B5: B_RST
|
||||
B_RC 0x58
|
||||
WT 8
|
||||
MEN2
|
||||
WT 118
|
||||
WT 64
|
||||
MEN2N
|
||||
P_LDH 0x00
|
||||
WT 16
|
||||
RTN
|
||||
;-------------------------------------------------------------
|
||||
|
||||
PPSync: BK_C 0x20
|
||||
label_C0: JMP RFInit
|
||||
JMP label_B1
|
||||
WT 250
|
||||
P_SC 0x20
|
||||
P_LDH PB_RX_ON|PB_DCTHRESHOLD
|
||||
UNLCK
|
||||
WT 64
|
||||
B_XOFF
|
||||
B_SR
|
||||
WNT 20
|
||||
JMP1 SFieldFound
|
||||
B_RST
|
||||
U_INT1
|
||||
WNT 23
|
||||
BR label_C0
|
||||
;-------------------------------------------------------------
|
||||
|
||||
SFieldFound: WNT 23
|
||||
P_SC 0x00
|
||||
label_D1: JMP label_28
|
||||
U_INT0
|
||||
WNT 22
|
||||
label_D4: BR label_C0
|
||||
;-------------------------------------------------------------
|
||||
|
||||
InitDIP: B_RST
|
||||
BK_C 0x00
|
||||
C_LD 0x10
|
||||
WT 10
|
||||
B_RC 0x00
|
||||
WT 8
|
||||
B_RST
|
||||
BK_A 0x00
|
||||
A_LDR 0x8C
|
||||
A_LDW 0xB4
|
||||
BK_A1 0x00
|
||||
A_LDR1 0x0C
|
||||
A_LDW1 0x34
|
||||
C_ON
|
||||
A_NORM
|
||||
WT 10
|
||||
P_EN
|
||||
P_LD 0x04
|
||||
RCK_INT
|
||||
RFEN
|
||||
BR PPSync
|
||||
;-------------------------------------------------------------
|
||||
|
||||
SHARED PP0,PP2,PP4,PP6,PP8,PP10,PP12,PP14,PP16,PP18,PP20,PP22
|
||||
SHARED JP0,JP2,JP4,JP6,JP8,JP10,JP12,JP14,JP16,JP18,JP20,JP22
|
||||
SHARED label_D1,label_D4,label_28
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
#endif
|
|
@ -0,0 +1,3 @@
|
|||
#ifndef SC14421_FIRMWARE_H
|
||||
#define SC14421_FIRMWARE_H
|
||||
|
|
@ -0,0 +1,146 @@
|
|||
/*
|
||||
* com_on_air_cs - basic driver for the Dosch and Amand "com on air" cards
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* authors:
|
||||
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
|
||||
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <asm/io.h>
|
||||
|
||||
#include "sc14421.h"
|
||||
#include "dip_opcodes.h"
|
||||
|
||||
static u_int deviceConfigBase = 0;
|
||||
|
||||
void set_device_configbase(u_int configBase)
|
||||
{
|
||||
deviceConfigBase = configBase;
|
||||
}
|
||||
|
||||
void wait_4_IO_cycles()
|
||||
{
|
||||
if (!deviceConfigBase) {
|
||||
printk("error: config base not set!\n");
|
||||
return;
|
||||
}
|
||||
inb_p(deviceConfigBase);
|
||||
inb_p(deviceConfigBase);
|
||||
inb_p(deviceConfigBase);
|
||||
inb_p(deviceConfigBase);
|
||||
}
|
||||
|
||||
void to_dip(uint16_t *dst, unsigned char *src, int length)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<length; i++)
|
||||
#if defined(__LITTLE_ENDIAN)
|
||||
*(dst++) = *(src++);
|
||||
#elif defined(__BIG_ENDIAN)
|
||||
*(dst++) =s wab16(*(src++));
|
||||
#else
|
||||
#error "endianness not defined"
|
||||
#endif
|
||||
}
|
||||
|
||||
void from_dip(unsigned char *dst, volatile uint16_t *src, int length)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<length; i++)
|
||||
#if defined(__LITTLE_ENDIAN)
|
||||
*(dst++) = *(src++);
|
||||
#elif defined(__BIG_ENDIAN)
|
||||
*(dst++) = swab16(*(src++));
|
||||
#else
|
||||
#error "endianness not defined"
|
||||
#endif
|
||||
}
|
||||
|
||||
void SC14421_switch_to_bank(volatile uint16_t *sc14421_base, unsigned char bank)
|
||||
{
|
||||
SC14421_WRITE(511, bank);
|
||||
wait_4_IO_cycles();
|
||||
}
|
||||
|
||||
void SC14421_stop_dip(volatile uint16_t *sc14421_base)
|
||||
{
|
||||
SC14421_switch_to_bank(sc14421_base, SC14421_DIPSTOPPED);
|
||||
}
|
||||
|
||||
void SC14421_write_cmd(volatile uint16_t *sc14421_base, int label, unsigned char opcode, unsigned char operand)
|
||||
{
|
||||
SC14421_WRITE(label*2 + 0, opcode);
|
||||
SC14421_WRITE(label*2 + 1, operand);
|
||||
}
|
||||
|
||||
unsigned char SC14421_clear_interrupt(volatile uint16_t *sc14421_base)
|
||||
{
|
||||
unsigned char int1, int2, cnt = 0;
|
||||
|
||||
int1 = SC14421_READ(511);
|
||||
|
||||
if (int1 == 0xff)
|
||||
return 0;
|
||||
|
||||
int2 = int1 & 0x0f;
|
||||
|
||||
while (int1)
|
||||
{
|
||||
cnt++;
|
||||
if (!cnt)
|
||||
return 0;
|
||||
|
||||
int1 = SC14421_READ(511) & 0x0f;
|
||||
int2 |= int1;
|
||||
}
|
||||
|
||||
return (int2 & 0x0f);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int SC14421_check_RAM(volatile uint16_t *sc14421_base)
|
||||
{
|
||||
unsigned char bank;
|
||||
int ErrCnt;
|
||||
int i;
|
||||
unsigned char x;
|
||||
|
||||
ErrCnt = 0;
|
||||
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
bank = (4*i) | 0x80;
|
||||
SC14421_switch_to_bank(sc14421_base, bank);
|
||||
|
||||
for (x=0; x<254; x++)
|
||||
SC14421_WRITE(x, (x+i) & 0xff);
|
||||
}
|
||||
|
||||
for (i=0; i<8; i++)
|
||||
{
|
||||
bank = (4*i)|0x80;
|
||||
SC14421_switch_to_bank(sc14421_base, bank);
|
||||
|
||||
for (x=0; x<254; x++)
|
||||
{
|
||||
if ( (SC14421_READ(x) & 0xff) != ((x+i) & 0xff) )
|
||||
{
|
||||
printk("error bank:%.2x %.2x - %.2x != %.2x \n", bank, x, SC14421_READ(x), (unsigned char)((x+i) & 0xff));
|
||||
ErrCnt++;
|
||||
}
|
||||
|
||||
SC14421_WRITE(x, 0);
|
||||
}
|
||||
}
|
||||
|
||||
return ErrCnt;
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* com_on_air_cs - basic driver for the Dosch and Amand "com on air" cards
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* authors:
|
||||
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
|
||||
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SC14421_H
|
||||
#define SC14421_H
|
||||
|
||||
#include <linux/byteorder/swab.h>
|
||||
|
||||
#define SC14421_DIPSTOPPED 0x80
|
||||
#define SC14421_RAMBANK0 0x00
|
||||
#define SC14421_RAMBANK1 0x04
|
||||
#define SC14421_RAMBANK2 0x08
|
||||
#define SC14421_RAMBANK3 0x0c
|
||||
#define SC14421_RAMBANK4 0x10
|
||||
#define SC14421_RAMBANK5 0x14
|
||||
#define SC14421_RAMBANK6 0x18
|
||||
#define SC14421_RAMBANK7 0x1c
|
||||
#define SC14421_CODEBANK 0x20
|
||||
|
||||
#if defined(__LITTLE_ENDIAN)
|
||||
# define SC14421_READ(offset) sc14421_base[(offset)]
|
||||
# define SC14421_WRITE(offset, value) { sc14421_base[(offset)] = (value); }
|
||||
#elif defined(__BIG_ENDIAN)
|
||||
# define SC14421_READ(offset) swab16(sc14421_base[(offset)])
|
||||
# define SC14421_WRITE(offset, value) { sc14421_base[(offset)] = swab16(value); }
|
||||
#else
|
||||
# error "could not determine endianness"
|
||||
#endif
|
||||
|
||||
void set_device_configbase(u_int);
|
||||
void wait_4_IO_cycles(void);
|
||||
void to_dip(unsigned short *dst, unsigned char *src, int length);
|
||||
void from_dip(unsigned char *dst, volatile uint16_t *src, int length);
|
||||
void SC14421_switch_to_bank(volatile uint16_t *sc14421_base, unsigned char bank);
|
||||
void SC14421_stop_dip(volatile uint16_t *sc14421_base);
|
||||
void SC14421_write_cmd(volatile uint16_t *sc14421_base, int label, unsigned char opcode, unsigned char operand);
|
||||
unsigned char SC14421_clear_interrupt(volatile uint16_t *sc14421_base);
|
||||
int SC14421_check_RAM(volatile uint16_t *sc14421_base);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,142 @@
|
|||
|
||||
|
||||
/* automatically generated file
|
||||
* DO NOT EDIT
|
||||
* edit firmware/filename.asm instead */
|
||||
|
||||
unsigned char sc14421_II_sniff_scan_fw[] = {
|
||||
0x01, 0x01, 0x20, 0x00, 0x0f, 0x00, 0xfa, 0x10,
|
||||
0x09, 0x0a, 0x33, 0x00, 0x09, 0x08, 0x20, 0x00,
|
||||
0xee, 0x00, 0x09, 0x0a, 0xe9, 0x00, 0xe8, 0x04,
|
||||
0x62, 0x00, 0x0b, 0x00, 0x0f, 0x20, 0x02, 0x3d,
|
||||
0x02, 0x4a, 0x09, 0xfa, 0xea, 0x20, 0xed, 0x42,
|
||||
0x28, 0x00, 0x09, 0x40, 0x26, 0x00, 0x29, 0x00,
|
||||
0x08, 0x14, 0x03, 0x1b, 0x01, 0x10, 0x08, 0x17,
|
||||
0xea, 0x00, 0x02, 0x20, 0x61, 0x00, 0x01, 0x10,
|
||||
0x02, 0x4a, 0x02, 0x2e, 0x09, 0x01, 0x2d, 0x0e,
|
||||
0x09, 0xff, 0x09, 0x49, 0xed, 0x01, 0xec, 0x40,
|
||||
0x39, 0x00, 0x09, 0x06, 0x20, 0x00, 0xec, 0x50,
|
||||
0x09, 0x05, 0x04, 0x00, 0xed, 0x40, 0xec, 0x01,
|
||||
0x09, 0x22, 0x08, 0x01, 0x27, 0x00, 0xed, 0x02,
|
||||
0x09, 0x05, 0x29, 0x00, 0x2c, 0x00, 0x09, 0x0c,
|
||||
0xec, 0x02, 0x09, 0x21, 0x3f, 0x06, 0x09, 0x3d,
|
||||
0x04, 0x00, 0x0b, 0x00, 0xa4, 0x00, 0x09, 0x02,
|
||||
0xb9, 0x4a, 0x09, 0x19, 0xa9, 0x00, 0xa5, 0x00,
|
||||
0xa4, 0x00, 0xb9, 0x4d, 0x09, 0x0a, 0xa9, 0x00,
|
||||
0xa5, 0x00, 0x04, 0x00, 0x20, 0x00, 0x33, 0x58,
|
||||
0x09, 0x08, 0xa7, 0x00, 0x09, 0xb6, 0xa6, 0x00,
|
||||
0x09, 0x10, 0x04, 0x00, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff};
|
||||
|
||||
|
||||
/* automatically generated file
|
||||
* DO NOT EDIT
|
||||
* edit firmware/filename.asm instead */
|
||||
|
||||
unsigned char sc14421_II_sniff_sync_fw[] = {
|
||||
0x01, 0x01, 0x01, 0xcc, 0x0d, 0x00, 0x0f, 0x20,
|
||||
0x08, 0x02, 0x0f, 0x30, 0x08, 0x02, 0x0f, 0x40,
|
||||
0x08, 0x02, 0x0f, 0x50, 0x08, 0x02, 0x0f, 0x60,
|
||||
0x08, 0x02, 0x0f, 0x70, 0x08, 0x02, 0x61, 0x00,
|
||||
0x0f, 0x80, 0x08, 0x02, 0x0f, 0x90, 0x08, 0x02,
|
||||
0x0f, 0xa0, 0x08, 0x02, 0x0f, 0xb0, 0x08, 0x02,
|
||||
0x0f, 0xc0, 0x08, 0x02, 0x0f, 0xd0, 0x08, 0x02,
|
||||
0x6f, 0x00, 0xec, 0x80, 0x01, 0x02, 0x02, 0x9a,
|
||||
0x02, 0xa8, 0x01, 0x24, 0x02, 0x9a, 0x02, 0xaa,
|
||||
0x02, 0x52, 0x09, 0x01, 0x2d, 0x0e, 0x02, 0x62,
|
||||
0x01, 0x48, 0x02, 0x9a, 0x02, 0xa8, 0x01, 0x2e,
|
||||
0x02, 0x9a, 0x02, 0xaa, 0x02, 0x52, 0x01, 0x89,
|
||||
0x02, 0x9a, 0x02, 0xa8, 0x01, 0x35, 0x02, 0x9a,
|
||||
0x02, 0xaa, 0x02, 0x67, 0x09, 0x01, 0x25, 0x0e,
|
||||
0x02, 0x73, 0x01, 0x4b, 0x02, 0x9a, 0x02, 0xaa,
|
||||
0x02, 0x67, 0x09, 0x01, 0x34, 0x0e, 0x02, 0x76,
|
||||
0x01, 0x4a, 0x02, 0x9a, 0x02, 0xa8, 0x01, 0x46,
|
||||
0x02, 0x9a, 0x02, 0xaa, 0x02, 0x67, 0x01, 0x92,
|
||||
0x39, 0x00, 0x09, 0x06, 0x20, 0x00, 0xec, 0x50,
|
||||
0x09, 0x05, 0x08, 0x01, 0x04, 0x00, 0x20, 0x00,
|
||||
0xec, 0x50, 0x01, 0x4e, 0xed, 0x40, 0xec, 0x01,
|
||||
0x09, 0x19, 0x08, 0x01, 0x09, 0x09, 0x27, 0x00,
|
||||
0xed, 0x02, 0x09, 0x05, 0x29, 0x00, 0x2c, 0x00,
|
||||
0x09, 0x0c, 0xec, 0x02, 0x09, 0x21, 0x3f, 0x06,
|
||||
0x09, 0x3d, 0x04, 0x00, 0x09, 0xf9, 0x09, 0x4f,
|
||||
0xed, 0x01, 0xec, 0x40, 0x04, 0x00, 0xed, 0x00,
|
||||
0x09, 0x28, 0x20, 0x00, 0x33, 0x50, 0x08, 0x01,
|
||||
0x31, 0x00, 0x09, 0x01, 0xed, 0x10, 0x09, 0x25,
|
||||
0x37, 0x06, 0x09, 0x3d, 0x04, 0x00, 0x09, 0xf9,
|
||||
0x09, 0x54, 0x20, 0x00, 0xec, 0x10, 0x09, 0x08,
|
||||
0xec, 0x00, 0x04, 0x00, 0x27, 0x00, 0x09, 0x0f,
|
||||
0x26, 0x00, 0x09, 0x3d, 0x04, 0x00, 0x09, 0x3d,
|
||||
0x02, 0x7a, 0x02, 0x7a, 0x02, 0x7a, 0x02, 0x7a,
|
||||
0x02, 0x7a, 0x09, 0x01, 0x27, 0x00, 0x09, 0x0b,
|
||||
0x04, 0x00, 0x3c, 0x0e, 0x02, 0x7f, 0x09, 0x03,
|
||||
0x2b, 0x00, 0x09, 0x06, 0x02, 0x64, 0x39, 0x00,
|
||||
0x09, 0x06, 0x01, 0x4f, 0x34, 0x0e, 0x09, 0x03,
|
||||
0x02, 0x7f, 0x24, 0x00, 0x09, 0x0d, 0x20, 0x00,
|
||||
0x02, 0x76, 0x01, 0x4f, 0x0b, 0x00, 0xa4, 0x00,
|
||||
0x09, 0x01, 0x09, 0x01, 0xb9, 0x4a, 0x09, 0x19,
|
||||
0xa9, 0x00, 0xa5, 0x00, 0xa4, 0x00, 0xb9, 0x4d,
|
||||
0x09, 0x0a, 0xa9, 0x00, 0xa5, 0x00, 0x04, 0x00,
|
||||
0xec, 0x20, 0x01, 0xac, 0xed, 0x20, 0x01, 0xac,
|
||||
0x20, 0x00, 0x33, 0x58, 0x09, 0x08, 0xa7, 0x00,
|
||||
0x09, 0x76, 0x09, 0x40, 0xa6, 0x00, 0xed, 0x00,
|
||||
0x09, 0x10, 0x04, 0x00, 0x0f, 0x20, 0x02, 0x9a,
|
||||
0x02, 0xa8, 0x09, 0xfa, 0xea, 0x20, 0xed, 0x42,
|
||||
0x28, 0x00, 0x09, 0x40, 0x26, 0x00, 0x29, 0x00,
|
||||
0x08, 0x14, 0x03, 0xc6, 0x20, 0x00, 0x6b, 0x00,
|
||||
0x08, 0x17, 0x01, 0xb7, 0x08, 0x17, 0xea, 0x00,
|
||||
0x02, 0x1f, 0x61, 0x00, 0x08, 0x16, 0x01, 0xb7,
|
||||
0x20, 0x00, 0x0f, 0x00, 0xfa, 0x10, 0x09, 0x0a,
|
||||
0x33, 0x00, 0x09, 0x08, 0x20, 0x00, 0x0e, 0x00,
|
||||
0xc6, 0x8c, 0xc7, 0xb4, 0x05, 0x00, 0xce, 0x0c,
|
||||
0xcf, 0x34, 0xee, 0x00, 0xc5, 0x00, 0x09, 0x0a,
|
||||
0xe9, 0x00, 0xe8, 0x04, 0x62, 0x00, 0x0b, 0x00,
|
||||
0x01, 0xb6, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff};
|
|
@ -0,0 +1,7 @@
|
|||
#ifndef SC14421_FIRMWARE_H
|
||||
#define SC14421_FIRMWARE_H
|
||||
|
||||
extern unsigned char sc14421_II_sniff_scan_fw[509];
|
||||
extern unsigned char sc14421_II_sniff_sync_fw[509];
|
||||
|
||||
#endif
|
|
@ -0,0 +1,828 @@
|
|||
/*
|
||||
* com_on_air_cs - basic driver for the Dosch and Amand "com on air" cards
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* authors:
|
||||
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
|
||||
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kfifo.h>
|
||||
|
||||
#include "sc14421.h"
|
||||
#include "dip_opcodes.h"
|
||||
#include "com_on_air.h"
|
||||
#include "sc14421_sniffer.h"
|
||||
#include "sc14421_firmware.h"
|
||||
#include "dect.h"
|
||||
|
||||
|
||||
/* dip config register control */
|
||||
unsigned char scan_init1[] = {0x27,0x00,0xff,0x00,0x5f,0x04,0x00};
|
||||
unsigned char scan_init2[] = {0xc2,0x05,0x00,0x03,0x00,0x00};
|
||||
|
||||
/* hf register type II card */
|
||||
unsigned char scan_II_init3[] = {0x54,0x80,0x09/* patch */,0xa0,0x00,0x00};
|
||||
/* hf register type III card */
|
||||
unsigned char scan_III_init3[] = {0x54,0x80,0x09/* patch */,0xa0,0x00,0x00};
|
||||
|
||||
/* hf register */
|
||||
unsigned char scan_init4[] = {0x15,0xa0,0xff,0x00/* &0x3f */,0x5f,0x04,0x00};
|
||||
|
||||
/* dip control */
|
||||
unsigned char scan_init5[] = {0x27,0x00,0xff,0x00,0x5f,0x05,0x00};
|
||||
|
||||
/* dip control */
|
||||
unsigned char sync_init1[] = {0x27,0x00,0xff,0x00,0x5f,0x04,0x00};
|
||||
unsigned char sync_init2[] = {0xc2,0x05,0x00,0x03,0x00,0x00};
|
||||
|
||||
/* hf register type II card */
|
||||
unsigned char sync_II_init3[] = {0x54,0x80,0x09/* patch */,0xa0,0x00,0x00};
|
||||
/* hf register type III card */
|
||||
unsigned char sync_III_init3[] = {0x54,0x80,0x09/* patch */,0xa0,0x00,0x00};
|
||||
/* hf register */
|
||||
unsigned char sync_init4[] = {0x15,0xa0,0xff,0x00/* &0x3f */,0x5f,0x04,0x00};
|
||||
/* dip control */
|
||||
unsigned char sync_init5[] = {0x27,0x00,0xff,0x00,0x5f,0x05,0x00};
|
||||
|
||||
|
||||
unsigned char fppacket[53] = {0xAA,0xAA,0xAA,0xE9,0x8A};
|
||||
unsigned char pppacket[53] = {0x55,0x55,0x55,0x16,0x75};
|
||||
|
||||
|
||||
/* FIXME:auto-generate all this stuff */
|
||||
#define PP0 0x4
|
||||
#define PP2 0x6
|
||||
#define PP4 0x8
|
||||
#define PP6 0xA
|
||||
#define PP8 0xC
|
||||
#define PP10 0xE
|
||||
#define PP12 0x11
|
||||
#define PP14 0x13
|
||||
#define PP16 0x15
|
||||
#define PP18 0x17
|
||||
#define PP20 0x19
|
||||
#define PP22 0x1B
|
||||
#define JP0 0x3
|
||||
#define JP2 0x5
|
||||
#define JP4 0x7
|
||||
#define JP6 0x9
|
||||
#define JP8 0xB
|
||||
#define JP10 0xD
|
||||
#define JP12 0x10
|
||||
#define JP14 0x12
|
||||
#define JP16 0x14
|
||||
#define JP18 0x16
|
||||
#define JP20 0x18
|
||||
#define JP22 0x1A
|
||||
#define sync_label_D1 0xC8
|
||||
#define sync_label_D4 0xCB
|
||||
#define sync_label_28 0x1F
|
||||
|
||||
|
||||
int sync_jumptable[] = {
|
||||
JP0, 0,
|
||||
JP2, 0,
|
||||
JP4, 0,
|
||||
JP6, 0,
|
||||
JP8, 0,
|
||||
JP10, 0,
|
||||
JP12, 0,
|
||||
JP14, 0,
|
||||
JP16, 0,
|
||||
JP18, 0,
|
||||
JP20, 0,
|
||||
JP22, 0
|
||||
};
|
||||
int sync_patchtable[] = {
|
||||
PP0, 0,
|
||||
PP2, 0,
|
||||
PP4, 0,
|
||||
PP6, 0,
|
||||
PP8, 0,
|
||||
PP10, 0,
|
||||
PP12, 0,
|
||||
PP14, 0,
|
||||
PP16, 0,
|
||||
PP18, 0,
|
||||
PP20, 0,
|
||||
PP22, 0
|
||||
};
|
||||
/* FIXME:end */
|
||||
|
||||
int sync_banktable[] = {
|
||||
SC14421_RAMBANK1,
|
||||
SC14421_RAMBANK1,
|
||||
SC14421_RAMBANK1,
|
||||
SC14421_RAMBANK1,
|
||||
SC14421_RAMBANK2,
|
||||
SC14421_RAMBANK2,
|
||||
SC14421_RAMBANK2,
|
||||
SC14421_RAMBANK2,
|
||||
SC14421_RAMBANK3,
|
||||
SC14421_RAMBANK3,
|
||||
SC14421_RAMBANK3,
|
||||
SC14421_RAMBANK3,
|
||||
SC14421_RAMBANK4,
|
||||
SC14421_RAMBANK4,
|
||||
SC14421_RAMBANK4,
|
||||
SC14421_RAMBANK4,
|
||||
SC14421_RAMBANK5,
|
||||
SC14421_RAMBANK5,
|
||||
SC14421_RAMBANK5,
|
||||
SC14421_RAMBANK5,
|
||||
SC14421_RAMBANK6,
|
||||
SC14421_RAMBANK6,
|
||||
SC14421_RAMBANK6,
|
||||
SC14421_RAMBANK6
|
||||
};
|
||||
|
||||
|
||||
void sniffer_init(struct coa_info *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
SC14421_switch_to_bank(
|
||||
dev->sc14421_base,
|
||||
SC14421_DIPSTOPPED | SC14421_CODEBANK
|
||||
);
|
||||
|
||||
ret = SC14421_check_RAM(dev->sc14421_base);
|
||||
if (ret)
|
||||
printk("Found %u memory r/w errors \n\n", ret);
|
||||
|
||||
switch(dev->sniffer_config->snifftype)
|
||||
{
|
||||
case SNIFF_SCANFP:
|
||||
case SNIFF_SCANPP:
|
||||
sniffer_init_sniff_scan(dev);
|
||||
break;
|
||||
case SNIFF_SYNC:
|
||||
sniffer_init_sniff_sync(dev);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void sniffer_init_sniff_scan(struct coa_info *dev)
|
||||
{
|
||||
uint16_t *sc14421_base = dev->sc14421_base;
|
||||
|
||||
/* printk("loading sniff_scan firmware\n"); */
|
||||
|
||||
SC14421_switch_to_bank(
|
||||
sc14421_base,
|
||||
SC14421_DIPSTOPPED | SC14421_CODEBANK
|
||||
);
|
||||
to_dip(
|
||||
sc14421_base,
|
||||
sc14421_II_sniff_scan_fw,
|
||||
ARRAY_SIZE(sc14421_II_sniff_scan_fw));
|
||||
|
||||
SC14421_clear_interrupt(sc14421_base);
|
||||
|
||||
/* set channel */
|
||||
switch(dev->radio_type)
|
||||
{
|
||||
case COA_RADIO_TYPE_II:
|
||||
scan_II_init3[0] =
|
||||
(scan_II_init3[0] & 0xC1) |
|
||||
((10 - dev->sniffer_config->channel) << 1);
|
||||
break;
|
||||
default:
|
||||
printk("ERROR: this radio type is currently not "
|
||||
"supported. please update the driver\n");
|
||||
}
|
||||
|
||||
if (dev->sniffer_config->snifftype == SNIFF_SCANPP)
|
||||
{
|
||||
scan_init1[0] &= 0xFE;
|
||||
scan_init5[0] &= 0xFE;
|
||||
}
|
||||
else
|
||||
{
|
||||
scan_init1[0] |= 0x01;
|
||||
scan_init5[0] |= 0x01;
|
||||
}
|
||||
|
||||
SC14421_switch_to_bank(
|
||||
sc14421_base,
|
||||
SC14421_DIPSTOPPED | SC14421_RAMBANK0
|
||||
);
|
||||
to_dip(
|
||||
sc14421_base + 0x00,
|
||||
scan_init1,
|
||||
ARRAY_SIZE(scan_init1));
|
||||
to_dip(
|
||||
sc14421_base + 0x10,
|
||||
scan_init2,
|
||||
ARRAY_SIZE(scan_init2)
|
||||
);
|
||||
SC14421_switch_to_bank(
|
||||
sc14421_base,
|
||||
SC14421_DIPSTOPPED | SC14421_RAMBANK1
|
||||
);
|
||||
to_dip(
|
||||
sc14421_base + 0x4A,
|
||||
scan_II_init3,
|
||||
ARRAY_SIZE(scan_II_init3)
|
||||
);
|
||||
to_dip(
|
||||
sc14421_base + 0x58,
|
||||
scan_init5,
|
||||
ARRAY_SIZE(scan_init5)
|
||||
);
|
||||
to_dip(
|
||||
sc14421_base + 0x50,
|
||||
scan_init4,
|
||||
ARRAY_SIZE(scan_init4));
|
||||
|
||||
/* printk("starting dip\n"); */
|
||||
SC14421_switch_to_bank(sc14421_base, SC14421_RAMBANK0);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void sniffer_init_sniff_sync(struct coa_info *dev)
|
||||
{
|
||||
uint16_t *sc14421_base = dev->sc14421_base;
|
||||
|
||||
printk("loading sniff_sync firmware\n");
|
||||
|
||||
SC14421_switch_to_bank(
|
||||
sc14421_base,
|
||||
SC14421_DIPSTOPPED | SC14421_CODEBANK
|
||||
);
|
||||
to_dip(
|
||||
sc14421_base,
|
||||
sc14421_II_sniff_sync_fw,
|
||||
ARRAY_SIZE(sc14421_II_sniff_sync_fw));
|
||||
|
||||
printk("clear interrupt\n");
|
||||
SC14421_clear_interrupt(sc14421_base);
|
||||
|
||||
SC14421_switch_to_bank(
|
||||
sc14421_base,
|
||||
SC14421_DIPSTOPPED | SC14421_RAMBANK0
|
||||
);
|
||||
to_dip(
|
||||
sc14421_base + 0x00,
|
||||
sync_init1,
|
||||
ARRAY_SIZE(sync_init1)
|
||||
);
|
||||
to_dip(
|
||||
sc14421_base + 0x10,
|
||||
sync_init2,
|
||||
ARRAY_SIZE(sync_init2));
|
||||
|
||||
/* set channel */
|
||||
switch(dev->radio_type)
|
||||
{
|
||||
case COA_RADIO_TYPE_II:
|
||||
sync_II_init3[0] =
|
||||
(scan_II_init3[0] & 0xC1) |
|
||||
( (10 - dev->sniffer_config->channel) << 1);
|
||||
break;
|
||||
default:
|
||||
printk("ERROR: this radio type is currently not "
|
||||
"supported. please update the driver\n");
|
||||
;
|
||||
}
|
||||
|
||||
sync_init5[0] |= 0x01;
|
||||
|
||||
|
||||
SC14421_switch_to_bank(
|
||||
sc14421_base,
|
||||
SC14421_DIPSTOPPED | SC14421_RAMBANK1
|
||||
);
|
||||
to_dip(
|
||||
sc14421_base + 0x4A,
|
||||
sync_II_init3,
|
||||
ARRAY_SIZE(sync_II_init3)
|
||||
);
|
||||
to_dip(
|
||||
sc14421_base + 0x58,
|
||||
sync_init5,
|
||||
ARRAY_SIZE(sync_init5)
|
||||
);
|
||||
to_dip(
|
||||
sc14421_base + 0x50,
|
||||
sync_init4,
|
||||
ARRAY_SIZE(sync_init4)
|
||||
);
|
||||
|
||||
dev->sniffer_config->status = 0;
|
||||
sniffer_clear_slottable(dev->sniffer_config->slottable);
|
||||
|
||||
|
||||
printk("starting dip\n");
|
||||
SC14421_switch_to_bank(sc14421_base, SC14421_RAMBANK0);
|
||||
|
||||
}
|
||||
|
||||
void sniffer_irq_handler(struct coa_info *dev)
|
||||
{
|
||||
int irq;
|
||||
|
||||
if (dev->sc14421_base)
|
||||
{
|
||||
irq = SC14421_clear_interrupt(dev->sc14421_base);
|
||||
|
||||
switch(dev->sniffer_config->snifftype)
|
||||
{
|
||||
case SNIFF_SCANFP:
|
||||
case SNIFF_SCANPP:
|
||||
sniffer_sniff_scan_irq(dev, irq);
|
||||
break;
|
||||
case SNIFF_SYNC:
|
||||
sniffer_sniff_sync_irq(dev, irq);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void sniffer_sniff_scan_irq(struct coa_info *dev, int irq)
|
||||
{
|
||||
volatile uint16_t *sc14421_base = dev->sc14421_base;
|
||||
|
||||
if (dev->open)
|
||||
{
|
||||
SC14421_switch_to_bank(sc14421_base, SC14421_RAMBANK1);
|
||||
|
||||
if ( (SC14421_READ(1) & 0xc0) == 0xc0) /* Checksum ok */
|
||||
{
|
||||
uint8_t rssi = SC14421_READ(0);
|
||||
from_dip(
|
||||
fppacket + 5,
|
||||
sc14421_base + 6,
|
||||
6);
|
||||
|
||||
SC14421_WRITE(1, 0); /* Clear Checksum-Flag */
|
||||
|
||||
if (dect_is_RFPI_Packet(fppacket))
|
||||
{
|
||||
int ret;
|
||||
uint8_t station[7];
|
||||
|
||||
station[0] = dev->sniffer_config->channel;
|
||||
station[1] = rssi;
|
||||
memcpy(&station[2], &fppacket[6], 5); /* RFPI */
|
||||
|
||||
ret = kfifo_put(dev->rx_fifo, station, 7);
|
||||
if (ret <= 0)
|
||||
{
|
||||
printk("com_on_air_cs: rx fifo full? "
|
||||
"kfifo_put() = %d\n", ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sniffer_sniff_sync_irq(struct coa_info *dev, int irq)
|
||||
{
|
||||
volatile uint16_t *sc14421_base = dev->sc14421_base;
|
||||
struct sniffer_cfg *config = dev->sniffer_config;
|
||||
|
||||
int r;
|
||||
SC14421_switch_to_bank(sc14421_base, SC14421_RAMBANK1);
|
||||
|
||||
|
||||
if (!(config->status & SNIFF_STATUS_FOUNDSTATION))
|
||||
{
|
||||
if (irq & 0x01)
|
||||
{
|
||||
#if 0
|
||||
printk("N:");
|
||||
for (r=0; r<16; r++)
|
||||
printk("%.2x ", SC14421_READ(r));
|
||||
|
||||
printk("\n");
|
||||
#endif
|
||||
if ( (SC14421_READ(1) & 0xc0) == 0xc0) /* Checksum ok */
|
||||
{
|
||||
SC14421_WRITE(1, 0); /* clear checksum flag */
|
||||
|
||||
from_dip(
|
||||
fppacket + 5,
|
||||
sc14421_base + 6,
|
||||
6);
|
||||
|
||||
if (dect_compare_RFPI(fppacket, config->RFPI))
|
||||
{
|
||||
printk("found station for sync\n");
|
||||
config->status |=
|
||||
SNIFF_STATUS_FOUNDSTATION;
|
||||
|
||||
SC14421_switch_to_bank(
|
||||
sc14421_base,
|
||||
SC14421_CODEBANK
|
||||
);
|
||||
SC14421_write_cmd(
|
||||
sc14421_base,
|
||||
sync_label_D4,
|
||||
BR,
|
||||
sync_label_D1
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!(config->status & SNIFF_STATUS_INSYNC))
|
||||
{
|
||||
if (irq & 0x01)
|
||||
{
|
||||
int slot;
|
||||
int i;
|
||||
|
||||
#if 0
|
||||
printk("S:");
|
||||
for (i=0; i<16; i++)
|
||||
printk("%.2x ", SC14421_READ(i));
|
||||
printk("\n");
|
||||
#endif
|
||||
if ( (SC14421_READ(1) & 0xc0) == 0xc0) /* Checksum ok */
|
||||
{
|
||||
SC14421_WRITE(1, 0); /* clear checksum flag */
|
||||
from_dip(
|
||||
fppacket + 5,
|
||||
sc14421_base + 6,
|
||||
48);
|
||||
|
||||
slot = dect_get_slot(fppacket);
|
||||
if (slot != -1)
|
||||
{
|
||||
/* printk("station in slot %u\n", slot); */
|
||||
config->status |= SNIFF_STATUS_INSYNC;
|
||||
slot %= 12;
|
||||
if (slot%2)
|
||||
printk("slot not possible "
|
||||
"with this firmware\n");
|
||||
|
||||
config->slottable[slot].active = 1;
|
||||
config->slottable[slot].channel =
|
||||
config->channel;
|
||||
config->slottable[slot].type =
|
||||
DECT_SLOTTYPE_CARRIER;
|
||||
config->slottable[slot].errcnt = 0;
|
||||
|
||||
sniffer_sync_patchloop(
|
||||
dev,
|
||||
config->slottable,
|
||||
SNIFF_SLOTPATCH_FP
|
||||
);
|
||||
sniffer_sync_patchloop(
|
||||
dev,
|
||||
config->slottable,
|
||||
SNIFF_SLOTPATCH_PP
|
||||
);
|
||||
|
||||
SC14421_switch_to_bank(
|
||||
sc14421_base,
|
||||
SC14421_CODEBANK
|
||||
);
|
||||
printk("set jump to %u\n",
|
||||
sync_jumptable[slot]);
|
||||
SC14421_write_cmd(
|
||||
sc14421_base,
|
||||
sync_label_D4,
|
||||
BR,
|
||||
sync_jumptable[slot]
|
||||
);
|
||||
|
||||
printk("we are in sync :)\n");
|
||||
|
||||
|
||||
struct sniffed_packet packet;
|
||||
|
||||
packet.rssi = SC14421_READ(0x00);
|
||||
packet.channel = config->channel;
|
||||
packet.slot = slot;
|
||||
memcpy(packet.data, fppacket, 53);
|
||||
|
||||
int ret;
|
||||
packet.timestamp =
|
||||
dev->irq_timestamp;
|
||||
ret = kfifo_put(
|
||||
dev->rx_fifo,
|
||||
(unsigned char*) &packet,
|
||||
sizeof(struct sniffed_packet));
|
||||
if (ret <= 0)
|
||||
printk("com_on_air_cs: rx fifo "
|
||||
"full? kfifo_put() "
|
||||
"= %d\n", ret);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int i, a;
|
||||
if ( (irq & 0x09) == 0x09)
|
||||
printk("interrupt too slow , lost packets!\n");
|
||||
|
||||
if (irq & 0x01)
|
||||
{
|
||||
|
||||
for (a=0; a<12; a++)
|
||||
{
|
||||
if (config->slottable[a].active)
|
||||
{
|
||||
int memofs;
|
||||
|
||||
SC14421_switch_to_bank(
|
||||
sc14421_base,
|
||||
sync_banktable[a]);
|
||||
|
||||
if ( (a/2) % 2)
|
||||
memofs = 0x80;
|
||||
else
|
||||
memofs = 0x00;
|
||||
|
||||
if ( (SC14421_READ(1+memofs) & 0xc0) ==
|
||||
0xc0) /* Checksum ok */
|
||||
{
|
||||
struct sniffed_packet packet;
|
||||
/* fixing indention / coding style is useless beyond here
|
||||
* need to talk to krater about where to cut in functions
|
||||
* - mazzoo */
|
||||
packet.rssi =
|
||||
SC14421_READ(memofs);
|
||||
packet.channel =
|
||||
config->slottable[a].channel;
|
||||
packet.slot = a;
|
||||
memcpy(
|
||||
packet.data,
|
||||
fppacket,
|
||||
5);
|
||||
from_dip(
|
||||
&packet.data[5],
|
||||
sc14421_base+memofs+6,
|
||||
48);
|
||||
|
||||
if (config->slottable[a].type ==
|
||||
DECT_SLOTTYPE_SCAN)
|
||||
/* we received data on a scan-slot , channel is incemented before , but we want hear the old channel */
|
||||
{
|
||||
packet.channel--;
|
||||
printk("slot in scanmode\n");
|
||||
}
|
||||
|
||||
if (dect_is_multiframe_number(packet.data)) /* if there was a multiframe number , then this packet was in frame 8 (0) */
|
||||
{
|
||||
/* printk("found multiframe number\n"); */
|
||||
config->framenumber = 1;
|
||||
}
|
||||
|
||||
/* if (dev->open) */
|
||||
{
|
||||
int ret;
|
||||
packet.timestamp = dev->irq_timestamp;
|
||||
ret = kfifo_put(dev->rx_fifo, (unsigned char*) &packet, sizeof(struct sniffed_packet));
|
||||
if (ret <= 0)
|
||||
{
|
||||
printk("com_on_air_cs: rx fifo full? kfifo_put() = %d\n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if 0
|
||||
printk("F:");
|
||||
for (i=0; i<16; i++)
|
||||
printk("%.2x ", SC14421_READ(i+memofs));
|
||||
|
||||
printk(" : %.2x : %x\n", irq, a);
|
||||
#endif
|
||||
SC14421_WRITE(1+memofs, 0); /* clear checksum flag */
|
||||
|
||||
|
||||
if (dect_update_slottable(config->slottable, a, packet.data))
|
||||
{
|
||||
config->updateppslots = 1;
|
||||
config->updatefpslots = 1;
|
||||
/* printk("new slot , must update slots\n"); */
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dect_receive_error(config->slottable, a))
|
||||
{
|
||||
config->updateppslots = 1;
|
||||
config->updatefpslots = 1;
|
||||
printk("died slot , must update slots\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( (!(irq & 0x08)) && (config->updatefpslots) )
|
||||
{
|
||||
/* printk("patching fp slots\n"); */
|
||||
sniffer_sync_patchloop(dev, config->slottable, SNIFF_SLOTPATCH_FP);
|
||||
config->updatefpslots = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (irq & 0x08)
|
||||
{
|
||||
|
||||
for (a=12; a<24; a++)
|
||||
{
|
||||
if (config->slottable[a].active)
|
||||
{
|
||||
int memofs;
|
||||
|
||||
SC14421_switch_to_bank(sc14421_base, sync_banktable[a]);
|
||||
|
||||
if ( (a/2) % 2)
|
||||
memofs = 0x80;
|
||||
else
|
||||
memofs = 0x00;
|
||||
|
||||
if ( (SC14421_READ(1+memofs) & 0xc0) == 0xc0) /* Checksum ok */
|
||||
{
|
||||
struct sniffed_packet packet;
|
||||
|
||||
packet.rssi = SC14421_READ(memofs);
|
||||
packet.channel = config->slottable[a].channel;
|
||||
packet.slot = a;
|
||||
memcpy(packet.data, pppacket, 5);
|
||||
from_dip(&packet.data[5], sc14421_base+memofs+6, 48);
|
||||
if (config->slottable[a].type == DECT_SLOTTYPE_SCAN)
|
||||
{
|
||||
packet.channel--;
|
||||
printk("slot in scanmode\n");
|
||||
}
|
||||
|
||||
/* if (dev->open) */
|
||||
{
|
||||
int ret;
|
||||
packet.timestamp = dev->irq_timestamp;
|
||||
ret = kfifo_put(dev->rx_fifo, (unsigned char*) &packet, sizeof(struct sniffed_packet));
|
||||
if (ret <= 0)
|
||||
{
|
||||
printk("com_on_air_cs: rx fifo full? kfifo_put() = %d\n", ret);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if 0
|
||||
printk("F:");
|
||||
for (i=0; i<16; i++)
|
||||
printk("%.2x ", SC14421_READ(i+memofs));
|
||||
|
||||
printk(" : %.2x : %x\n", irq, a);
|
||||
#endif
|
||||
|
||||
SC14421_WRITE(1+memofs, 0); /* clear checksum flag */
|
||||
|
||||
|
||||
if (dect_update_slottable(config->slottable, a, packet.data))
|
||||
{
|
||||
config->updateppslots = 1;
|
||||
config->updatefpslots = 1;
|
||||
/* printk("new slot , must update slots\n"); */
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (dect_receive_error(config->slottable, a))
|
||||
{
|
||||
config->updateppslots = 1;
|
||||
config->updatefpslots = 1;
|
||||
/* printk("died slot , must update slots\n"); */
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( (!(irq & 0x01)) && (config->updateppslots) )
|
||||
{
|
||||
/* printk("patching pp slots\n"); */
|
||||
sniffer_sync_patchloop(dev, config->slottable, SNIFF_SLOTPATCH_PP);
|
||||
config->updateppslots = 0;
|
||||
}
|
||||
|
||||
if (dect_update_scanchannels(config->slottable))
|
||||
{
|
||||
config->updateppslots = 1;
|
||||
config->updatefpslots = 1;
|
||||
/* printk("new slot , must update slots\n"); */
|
||||
}
|
||||
|
||||
if (config->framenumber >= 7)
|
||||
config->framenumber = 0;
|
||||
else
|
||||
config->framenumber++;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void sniffer_sync_patchloop(struct coa_info *dev, struct dect_slot_info *slottable, int type)
|
||||
{
|
||||
int slot, offset = 0;
|
||||
volatile uint16_t *sc14421_base = dev->sc14421_base;
|
||||
struct sniffer_cfg *config = dev->sniffer_config;
|
||||
|
||||
|
||||
if (type == SNIFF_SLOTPATCH_PP)
|
||||
offset = 12;
|
||||
|
||||
for (slot = offset; slot < (offset+12); slot++)
|
||||
{
|
||||
if (slottable[slot].update)
|
||||
{
|
||||
slottable[slot].update = 0;
|
||||
|
||||
if (slottable[slot].active && (slot%2))
|
||||
{
|
||||
static int fixme_count = 23;
|
||||
if (fixme_count)
|
||||
{
|
||||
fixme_count--;
|
||||
printk("can't use slot %u with this firmware !\n", slot);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (slottable[slot].active)
|
||||
{
|
||||
int memofs;
|
||||
|
||||
/* set channel */
|
||||
switch(dev->radio_type)
|
||||
{
|
||||
case COA_RADIO_TYPE_II:
|
||||
sync_II_init3[0] = (sync_II_init3[0] & 0xC1) | ((10-slottable[slot].channel) << 1);
|
||||
break;
|
||||
default:
|
||||
printk("ERROR: this radio type is currently not supported. please update the driver\n");
|
||||
}
|
||||
|
||||
if (slot > 11)
|
||||
sync_init5[0] &= 0xFE;
|
||||
else
|
||||
sync_init5[0] |= 0x01;
|
||||
|
||||
if ( (slot/2) % 2)
|
||||
memofs = 0x80;
|
||||
else
|
||||
memofs = 0x00;
|
||||
|
||||
sync_init5[6] = config->framenumber%8;
|
||||
|
||||
SC14421_switch_to_bank(sc14421_base, sync_banktable[slot]);
|
||||
|
||||
to_dip(sc14421_base + 0x4A + memofs, sync_II_init3, ARRAY_SIZE(sync_II_init3));
|
||||
to_dip(sc14421_base + 0x58 + memofs, sync_init5, ARRAY_SIZE(sync_init5));
|
||||
to_dip(sc14421_base + 0x50 + memofs, sync_init4, ARRAY_SIZE(sync_init4));
|
||||
|
||||
|
||||
/* printk("patching slot %u at addr %u\n", slot, sync_patchtable[slot]); */
|
||||
SC14421_switch_to_bank(sc14421_base, SC14421_CODEBANK);
|
||||
SC14421_write_cmd(sc14421_base, sync_patchtable[slot], JMP, sync_label_28);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
SC14421_switch_to_bank(sc14421_base, SC14421_CODEBANK);
|
||||
SC14421_write_cmd(sc14421_base, sync_patchtable[slot], WNT, 2);
|
||||
/* printk("patching addr %u for wait\n", sync_patchtable[slot]); */
|
||||
}
|
||||
}
|
||||
else if (slottable[slot].active && (slottable[slot].type == DECT_SLOTTYPE_CARRIER))
|
||||
{
|
||||
SC14421_switch_to_bank(sc14421_base, sync_banktable[slot]);
|
||||
SC14421_WRITE(0x5e, config->framenumber%8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void sniffer_clear_slottable(struct dect_slot_info *slottable)
|
||||
{
|
||||
int i;
|
||||
for (i=0; i<24; i++)
|
||||
{
|
||||
slottable[i].active = 0;
|
||||
slottable[i].update = 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,75 @@
|
|||
/*
|
||||
* com_on_air_cs - basic driver for the Dosch and Amand "com on air" cards
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* authors:
|
||||
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
|
||||
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef SC14421_SNIFF_H
|
||||
#define SC14421_SNIFF_H
|
||||
|
||||
#include "com_on_air_user.h"
|
||||
|
||||
#define SNIFF_SCANFP COA_SUBMODE_SNIFF_SCANFP
|
||||
#define SNIFF_SCANPP COA_SUBMODE_SNIFF_SCANPP
|
||||
#define SNIFF_SYNC COA_SUBMODE_SNIFF_SYNC
|
||||
|
||||
#define SNIFF_STATUS_FOUNDSTATION 0x80
|
||||
#define SNIFF_STATUS_INSYNC 0x40
|
||||
|
||||
#define SNIFF_SLOTPATCH_FP 0
|
||||
#define SNIFF_SLOTPATCH_PP 1
|
||||
|
||||
#include "dect.h"
|
||||
#include "com_on_air.h"
|
||||
|
||||
struct sniffer_cfg
|
||||
{
|
||||
int snifftype;
|
||||
int channel;
|
||||
unsigned char RFPI[5];
|
||||
unsigned char status;
|
||||
struct dect_slot_info slottable[24];
|
||||
int framenumber;
|
||||
int updatefpslots;
|
||||
int updateppslots;
|
||||
};
|
||||
|
||||
struct sniffed_rfpi
|
||||
{
|
||||
unsigned char rssi;
|
||||
unsigned char channel;
|
||||
unsigned char RFPI[5];
|
||||
};
|
||||
|
||||
#define SLOT_OUT_OF_SYNC 0x20
|
||||
#define SLOT_IN_SYNC 0x21
|
||||
|
||||
struct sniffed_packet
|
||||
{
|
||||
unsigned char rssi;
|
||||
unsigned char channel;
|
||||
unsigned char slot;
|
||||
struct timespec timestamp;
|
||||
unsigned char data[53];
|
||||
};
|
||||
|
||||
|
||||
void sniffer_init(struct coa_info *dev);
|
||||
void sniffer_init_sniff_all(struct coa_info *dev);
|
||||
void sniffer_init_sniff_scan(struct coa_info *dev);
|
||||
void sniffer_init_sniff_sync(struct coa_info *dev);
|
||||
void sniffer_irq_handler(struct coa_info *dev);
|
||||
void sniffer_sniff_all_irq(struct coa_info *dev,int irq);
|
||||
void sniffer_sniff_scan_irq(struct coa_info *dev,int irq);
|
||||
void sniffer_sniff_sync_irq(struct coa_info *dev,int irq);
|
||||
void sniffer_sync_patchloop(struct coa_info *dev,struct dect_slot_info *slottable,int type);
|
||||
void sniffer_clear_slottable(struct dect_slot_info *slottable);
|
||||
#endif
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
CFLAGS=-Wall -O2 -I..
|
||||
PROGS=coa_syncsniff pcap2cchan
|
||||
PCAP_PROGS=pcapstein dect_cli
|
||||
all:$(PROGS) $(PCAP_PROGS)
|
||||
|
||||
$(PCAP_PROGS): $(foreach p,$(PCAP_PROGS), $p.c)
|
||||
$(CC) $(CFLAGS) -lpcap $@.c -o $@
|
||||
clean:
|
||||
rm -f $(PROGS) $(PCAP_PROGS)
|
|
@ -0,0 +1,199 @@
|
|||
/*
|
||||
* coa_syncsniff dumps pcap files on a given channel and RFPI
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* authors:
|
||||
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
|
||||
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <netinet/ether.h>
|
||||
|
||||
#include "com_on_air_user.h"
|
||||
|
||||
|
||||
struct sniffed_packet
|
||||
{
|
||||
unsigned char rssi;
|
||||
unsigned char channel;
|
||||
unsigned char slot;
|
||||
struct timespec timestamp;
|
||||
unsigned char data[53];
|
||||
};
|
||||
|
||||
struct pcap_global_header
|
||||
{
|
||||
uint32_t magic_number; /* magic number */
|
||||
uint16_t version_major; /* major version number */
|
||||
uint16_t version_minor; /* minor version number */
|
||||
int thiszone; /* GMT to local correction */
|
||||
uint32_t sigfigs; /* accuracy of timestamps */
|
||||
uint32_t snaplen; /* max length of captured packets, in octets */
|
||||
uint32_t network; /* data link type */
|
||||
};
|
||||
|
||||
|
||||
struct pcap_record_header
|
||||
{
|
||||
uint32_t ts_sec; /* timestamp seconds */
|
||||
uint32_t ts_usec; /* timestamp microseconds */
|
||||
uint32_t incl_len; /* number of octets of packet saved in file */
|
||||
uint32_t orig_len; /* actual length of packet */
|
||||
};
|
||||
|
||||
void write_global_header(FILE *pcap);
|
||||
void write_record(FILE *pcap,uint32_t sec,uint32_t usec,uint32_t len,unsigned char *record);
|
||||
|
||||
#define DEV "/dev/coa"
|
||||
|
||||
/* we use some "hidden" ioctls */
|
||||
#define COA_IOCTL_TEST0 0xF000
|
||||
#define COA_IOCTL_TEST1 0xF001
|
||||
#define COA_IOCTL_TEST2 0xF002
|
||||
#define COA_IOCTL_TEST3 0xF003
|
||||
#define COA_IOCTL_TEST4 0xF004
|
||||
#define COA_IOCTL_TEST5 0xF005
|
||||
#define COA_IOCTL_TEST6 0xF006
|
||||
#define COA_IOCTL_TEST7 0xF007
|
||||
|
||||
|
||||
#define COA_IOCTL_DUMP_DIP_RAM COA_IOCTL_TEST0
|
||||
#define COA_IOCTL_FIFO_TEST COA_IOCTL_TEST1
|
||||
#define COA_IOCTL_COUNT_IRQ COA_IOCTL_TEST2
|
||||
|
||||
/* default RFPI */
|
||||
uint8_t RFPI[5]={0x00,0x00,0x00,0x00,0x00};
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int d;
|
||||
int ret = 0;
|
||||
|
||||
FILE *pcap;
|
||||
if(argc<2)
|
||||
{
|
||||
printf( "Usage:coa_syncsniff channel pcap-file [RFPI]\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
d=open(DEV, O_RDONLY);
|
||||
if (d<0)
|
||||
{
|
||||
printf("couldn't open(\"%s\"): %s\n", DEV, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pcap=fopen(argv[2],"wb");
|
||||
if(!pcap)
|
||||
{
|
||||
printf("Cant open pcap file for write...\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* optionally accept RFPI as 3rd argument on commandline */
|
||||
if(argc>2)
|
||||
{
|
||||
sscanf(argv[3], "%hhx %hhx %hhx %hhx %hhx", &RFPI[0], &RFPI[1], &RFPI[2], &RFPI[3], &RFPI[4]);
|
||||
printf("RFPI: %02x %02x %02x %02x %02x\n", RFPI[0], RFPI[1], RFPI[2], RFPI[3], RFPI[4]);
|
||||
}
|
||||
|
||||
|
||||
//set sync sniff mode
|
||||
uint16_t val;
|
||||
val = COA_MODE_SNIFF|COA_SUBMODE_SNIFF_SYNC;
|
||||
if(ioctl(d,COA_IOCTL_MODE, &val)){printf("couldn't ioctl()\n");exit(1);}
|
||||
|
||||
//set rfpi to sync with
|
||||
if(ioctl(d,COA_IOCTL_SETRFPI, RFPI)){printf("couldn't ioctl()\n");exit(1);}
|
||||
|
||||
//set channel
|
||||
uint32_t chn=atoi(argv[1]);
|
||||
printf("set channel %u\n",chn);
|
||||
if(ioctl(d,COA_IOCTL_CHAN,&chn)){printf("couldn't set channel\n");exit(1);}
|
||||
|
||||
|
||||
write_global_header(pcap);
|
||||
|
||||
//sniff-loop
|
||||
while (0xDEC + 't')
|
||||
{
|
||||
struct sniffed_packet buf;
|
||||
while (sizeof(struct sniffed_packet) == (ret = read(d, &buf, (sizeof(struct sniffed_packet)))))
|
||||
{
|
||||
unsigned char packet[100];
|
||||
packet[12]=0x23;
|
||||
packet[13]=0x23;
|
||||
packet[14]=0x00; //decttype (receive)
|
||||
packet[15]=buf.channel; //channel
|
||||
packet[16]=0;
|
||||
packet[17]=buf.slot; //slot
|
||||
packet[18]=0;
|
||||
packet[19]=buf.rssi;
|
||||
memcpy(packet+20,buf.data,53);
|
||||
|
||||
write_record(
|
||||
pcap,
|
||||
buf.timestamp.tv_sec,
|
||||
buf.timestamp.tv_nsec/1000,
|
||||
73,
|
||||
packet);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void write_global_header(FILE *pcap)
|
||||
{
|
||||
struct pcap_global_header header;
|
||||
|
||||
header.magic_number=0xa1b2c3d4;
|
||||
header.version_major=2;
|
||||
header.version_minor=4;
|
||||
header.thiszone=0;//GMT
|
||||
header.sigfigs=0;
|
||||
header.snaplen=1024;
|
||||
header.network=1;
|
||||
|
||||
fwrite(&header,1,sizeof(struct pcap_global_header),pcap);
|
||||
}
|
||||
|
||||
void write_record(FILE *pcap,uint32_t sec,uint32_t usec,uint32_t len,unsigned char *record)
|
||||
{
|
||||
struct pcap_record_header header;
|
||||
header.ts_sec=sec;
|
||||
header.ts_usec=usec;
|
||||
header.incl_len=len;
|
||||
header.orig_len=len;
|
||||
|
||||
fwrite(&header,1,sizeof(struct pcap_record_header),pcap);
|
||||
fwrite(record,1,len,pcap);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
* DECT C channel definitions
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* authors:
|
||||
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
|
||||
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DECT_CCHAN_H
|
||||
#define DECT_CCHAN_H
|
||||
|
||||
|
||||
struct strtype
|
||||
{
|
||||
char type;
|
||||
char name[100];
|
||||
};
|
||||
|
||||
struct strtype msgtype[16]=
|
||||
{
|
||||
{0,"0000 LCE (Link Control Entity) messages"},
|
||||
{1,""},
|
||||
{2,""},
|
||||
{3,"0011 CC (Call Control) messages"},
|
||||
{4,"0100 CISS (Call Independent Supplementary Services) messages"},
|
||||
{5,"0101 MM (Mobility Management) messages"},
|
||||
{6,"0110 CLMS (ConnectionLess Message Service) messages"},
|
||||
{7,"0111 COMS (Connection Oriented Message Service) messages"}
|
||||
};
|
||||
|
||||
struct strtype cctype[256]=
|
||||
{
|
||||
{0x01,"{CC-ALERTING}"},
|
||||
{0x02,"{CC-CALL-PROC}"},
|
||||
{0x05,"{CC-SETUP}"},
|
||||
{0x07,"{CC-CONNECT}"},
|
||||
{0x0d,"{CC-SETUP-ACK}"},
|
||||
{0x0f,"{CC-CONNECT-ACK}"},
|
||||
{0x20,"{CC-SERVICE-CHANGE}"},
|
||||
{0x21,"{CC-SERVICE-ACCEPT}"},
|
||||
{0x23,"{CC-SERVICE-REJECT}"},
|
||||
{0x4d,"{CC-RELEASE}"},
|
||||
{0x5a,"{CC-RELEASE-COM}"},
|
||||
{0x60,"{IWU-INFO}"},
|
||||
{0x6e,"{CC-NOTIFY}"},
|
||||
{0x7b,"{CC-INFO}"}
|
||||
};
|
||||
|
||||
struct strtype mmtype[256]=
|
||||
{
|
||||
{0x40,"{AUTHENTICATION-REQUEST}"},
|
||||
{0x41,"{AUTHENTICATION-REPLY}"},
|
||||
{0x42,"{KEY-ALLOCATE}"},
|
||||
{0x43,"{AUTHENTICATION-REJECT}"},
|
||||
{0x44,"{ACCESS-RIGHTS-REQUEST}"},
|
||||
{0x45,"{ACCESS-RIGHTS-ACCEPT}"},
|
||||
{0x47,"{ACCESS-RIGHTS-REJECT}"},
|
||||
{0x48,"{ACCESS-RIGHTS-TERMINATE-REQUEST}"},
|
||||
{0x49,"{ACCESS-RIGHTS-TERMINATE-ACCEPT}"},
|
||||
{0x4b,"{ACCESS-RIGHTS-TERMINATE-REJECT}"},
|
||||
{0x4c,"{CIPHER-REQUEST}"},
|
||||
{0x4e,"{CIPHER-SUGGEST}"},
|
||||
{0x4f,"{CIPHER-REJECT}"},
|
||||
{0x50,"{MM-INFO-REQUEST}"},
|
||||
{0x51,"{MM-INFO-ACCEPT}"},
|
||||
{0x52,"{MM-INFO-SUGGEST}"},
|
||||
{0x53,"{MM-INFO-REJECT}"},
|
||||
{0x54,"{LOCATE-REQUEST}"},
|
||||
{0x55,"{LOCATE-ACCEPT}"},
|
||||
{0x56,"{DETACH}"},
|
||||
{0x57,"{LOCATE-REJECT}"},
|
||||
{0x58,"{IDENTITY-REQUEST}"},
|
||||
{0x5a,"{IDENTITY-REPLY}"},
|
||||
{0x5b,"{MM-IWU}"},
|
||||
{0x5c,"{TEMPORARY-IDENTITY-ASSIGN}"},
|
||||
{0x5d,"{TEMPORARY-IDENTITY-ASSIGN-ACK}"},
|
||||
{0x5f,"{TEMPORARY-IDENTITY-ASSIGN-REJ}"},
|
||||
{0x6e,"{MM-NOTIFY}"}
|
||||
};
|
||||
|
||||
struct strtype sstype[256]=
|
||||
{
|
||||
{0x24,"{HOLD}"},
|
||||
{0x28,"{HOLD-ACK}"},
|
||||
{0x30,"{HOLD-REJECT}"},
|
||||
{0x31,"{RETRIEVE}"},
|
||||
{0x33,"{RETRIEVE-ACK}"},
|
||||
{0x37,"{RETRIEVE-REJECT}"},
|
||||
{0x5a,"{CISS-RELEASE-COM}"},
|
||||
{0x62,"{FACILITY}"},
|
||||
{0x64,"{CISS-REGISTER}"},
|
||||
};
|
||||
|
||||
|
||||
struct cfrag
|
||||
{
|
||||
int valid;
|
||||
int slot;
|
||||
char cttype;
|
||||
unsigned char data[5];
|
||||
};
|
||||
|
||||
struct cpacket
|
||||
{
|
||||
int valid;
|
||||
unsigned char addr;
|
||||
unsigned char ctrl;
|
||||
unsigned char length;
|
||||
unsigned char data[80];
|
||||
unsigned short checksum;
|
||||
};
|
||||
|
||||
struct cdevice
|
||||
{
|
||||
char type;
|
||||
int found;
|
||||
char cnt;
|
||||
int cdata;
|
||||
struct cpacket packet;
|
||||
};
|
||||
|
||||
char lenlookup[64]={
|
||||
5,10,10,10,10,10,15,15,
|
||||
15,15,15,20,20,20,20,20,
|
||||
25,25,25,25,25,30,30,30,
|
||||
30,30,35,35,35,35,35,40,
|
||||
40,40,40,40,45,45,45,45,
|
||||
45,50,50,50,50,50,55,55,
|
||||
55,55,55,60,60,60,60,60,
|
||||
65,65,65,65,65,70,70,70
|
||||
};
|
||||
|
||||
char pklookup[64]={
|
||||
1,2,2,2,2,2,3,3,
|
||||
3,3,3,4,4,4,4,4,
|
||||
5,5,5,5,5,6,6,6,
|
||||
6,6,7,7,7,7,7,8,
|
||||
8,8,8,8,9,9,9,9,
|
||||
9,10,10,10,10,10,11,11,
|
||||
11,11,11,12,12,12,12,12,
|
||||
13,13,13,13,13,14,14,14
|
||||
};
|
||||
|
||||
|
||||
struct cfrag getcfrag(unsigned char *dect,int slot);
|
||||
struct cpacket getcpacket(struct cfrag frag,struct cdevice *device);
|
||||
|
||||
void printcpacket(struct cpacket packet,char *prefix);
|
||||
char *getstring(struct strtype *str,int id,int max);
|
||||
|
||||
|
||||
|
||||
#endif
|
|
@ -0,0 +1,671 @@
|
|||
/*
|
||||
* dect_cli async and sync interface to DECT, can dump pcap files
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* authors:
|
||||
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
|
||||
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
#include <pcap.h>
|
||||
|
||||
|
||||
#include "com_on_air_user.h"
|
||||
#include "dect_cli.h"
|
||||
|
||||
//#define DUMP_IRQ_COUNT_ONCE_PER_SEC
|
||||
|
||||
struct cli_info cli;
|
||||
|
||||
|
||||
#define RXBUF 8192
|
||||
char buf[RXBUF];
|
||||
|
||||
|
||||
/* pcap errors */
|
||||
char errbuf[PCAP_ERRBUF_SIZE];
|
||||
|
||||
void print_help(void)
|
||||
{
|
||||
LOG("\n");
|
||||
LOG(" help - this help\n");
|
||||
LOG(" fpscan - async scan for basestations, dump RFPIs\n");
|
||||
LOG(" callscan - async scan for active calls, dump RFPIs\n");
|
||||
LOG(" autorec - sync on any calls in callscan, autodump in pcap, currently %s\n", cli.autorec ? "ON":"OFF");
|
||||
LOG(" ppscan <rfpi> - sync scan for active calls\n");
|
||||
LOG(" chan <ch> - set current channel [0-9], currently %d\n", cli.channel);
|
||||
// LOG(" slot <sl> - set current slot [0-23], currently %d\n", cli.slot);
|
||||
// LOG(" jam - jam current channel\n");
|
||||
LOG(" dump - dump stations and calls we have seen\n");
|
||||
LOG(" hop - toggle channel hopping, currently %s\n", cli.hop ? "ON":"OFF");
|
||||
LOG(" verb - toggle verbosity, currently %s\n", cli.verbose ? "ON":"OFF");
|
||||
LOG(" stop - stop it - whatever we were doing\n");
|
||||
LOG(" quit - well :)\n");
|
||||
LOG("\n");
|
||||
}
|
||||
|
||||
void set_channel(uint32_t channel)
|
||||
{
|
||||
if (cli.verbose)
|
||||
LOG("### switching to channel %d\n", channel);
|
||||
if (ioctl(cli.fd, COA_IOCTL_CHAN, &channel)){
|
||||
LOG("!!! couldn't ioctl()\n");
|
||||
exit(1);
|
||||
}
|
||||
cli.last_hop = time(NULL);
|
||||
}
|
||||
|
||||
void set_slot(uint32_t slot)
|
||||
{
|
||||
LOG("!!! not yet implemented :(\n");
|
||||
}
|
||||
|
||||
void do_ppscan(uint8_t * RFPI)
|
||||
{
|
||||
LOG("### trying to sync on %.2x %.2x %.2x %.2x %.2x\n",
|
||||
RFPI[0],
|
||||
RFPI[1],
|
||||
RFPI[2],
|
||||
RFPI[3],
|
||||
RFPI[4]
|
||||
);
|
||||
|
||||
/* set sync sniff mode */
|
||||
uint16_t val;
|
||||
val = COA_MODE_SNIFF | COA_SUBMODE_SNIFF_SYNC;
|
||||
if (ioctl(cli.fd, COA_IOCTL_MODE, &val)){
|
||||
LOG("!!! couldn't ioctl()\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* set rfpi to sync with */
|
||||
if(ioctl(cli.fd, COA_IOCTL_SETRFPI, RFPI)){
|
||||
LOG("!!! couldn't ioctl()\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
set_channel(cli.channel);
|
||||
|
||||
memcpy(cli.RFPI, RFPI, 5);
|
||||
cli.mode = MODE_PPSCAN;
|
||||
|
||||
cli.autorec_last_bfield = time(NULL);
|
||||
}
|
||||
|
||||
void add_station(struct dect_station * station)
|
||||
{
|
||||
int i;
|
||||
LOG("### found new %s", station->type == TYPE_FP ? "station":"call on");
|
||||
for (i=0; i<5; i++)
|
||||
LOG(" %.2x", station->RFPI[i]);
|
||||
LOG(" on channel %d RSSI %d\n", station->channel, station->RSSI);
|
||||
|
||||
struct dect_station * p = cli.station_list;
|
||||
if (p)
|
||||
{ /* append to existing list */
|
||||
while (p->next)
|
||||
p = p->next;
|
||||
p->next = malloc(sizeof(*p));
|
||||
p = p->next;
|
||||
}else /* create 1st element in list */
|
||||
{
|
||||
cli.station_list = malloc(sizeof(*cli.station_list));
|
||||
p = cli.station_list;
|
||||
}
|
||||
if (!p)
|
||||
{
|
||||
LOG("!!! out of memory\n");
|
||||
exit(1);
|
||||
}
|
||||
memset(p, 0, sizeof(*p));
|
||||
|
||||
memcpy(p->RFPI, station->RFPI, 5);
|
||||
p->channel = station->channel;
|
||||
p->RSSI = station->RSSI;
|
||||
p->type = station->type;
|
||||
p->first_seen = time(NULL);
|
||||
p->last_seen = p->first_seen;
|
||||
p->count_seen = 1;
|
||||
if (cli.autorec)
|
||||
do_ppscan(station->RFPI);
|
||||
}
|
||||
|
||||
void try_add_station(struct dect_station * station)
|
||||
{
|
||||
struct dect_station * p = cli.station_list;
|
||||
int found = 0;
|
||||
while (p)
|
||||
{
|
||||
if (!memcmp(p->RFPI, station->RFPI, 5))
|
||||
{
|
||||
if (p->type == station->type)
|
||||
{
|
||||
if ( (p->channel != station->channel) &&
|
||||
(cli.verbose) )
|
||||
{
|
||||
int i;
|
||||
LOG("### station");
|
||||
for (i=0; i<5; i++)
|
||||
LOG(" %.2x", station->RFPI[i]);
|
||||
LOG(" switched from channel %d to channel %d\n",
|
||||
p->channel,
|
||||
station->channel);
|
||||
}
|
||||
found = 1;
|
||||
p->channel = station->channel;
|
||||
p->count_seen++;
|
||||
p->last_seen = time(NULL);
|
||||
p->RSSI += station->RSSI; /* we avg on dump */
|
||||
}
|
||||
}
|
||||
p = p->next;
|
||||
}
|
||||
if (!found)
|
||||
add_station(station);
|
||||
}
|
||||
|
||||
|
||||
void do_fpscan(void)
|
||||
{
|
||||
LOG("### starting fpscan\n");
|
||||
uint16_t val;
|
||||
val = COA_MODE_SNIFF | COA_SUBMODE_SNIFF_SCANFP;
|
||||
if (ioctl(cli.fd, COA_IOCTL_MODE, &val)){
|
||||
LOG("!!! couldn't ioctl()\n");
|
||||
exit(1);
|
||||
}
|
||||
/* set start channel */
|
||||
set_channel(cli.channel);
|
||||
cli.mode = MODE_FPSCAN;
|
||||
cli.autorec = 0;
|
||||
}
|
||||
|
||||
void do_callscan(void)
|
||||
{
|
||||
LOG("### starting callscan\n");
|
||||
uint16_t val;
|
||||
val = COA_MODE_SNIFF | COA_SUBMODE_SNIFF_SCANPP;
|
||||
if (ioctl(cli.fd, COA_IOCTL_MODE, &val)){
|
||||
LOG("!!! couldn't ioctl()\n");
|
||||
exit(1);
|
||||
}
|
||||
/* set start channel */
|
||||
set_channel(cli.channel);
|
||||
cli.mode = MODE_CALLSCAN;
|
||||
}
|
||||
|
||||
void do_ppscan_str(char * str_rfpi)
|
||||
{
|
||||
uint8_t RFPI[5];
|
||||
char * end;
|
||||
int i;
|
||||
for (i=0; i<5; i++)
|
||||
{
|
||||
RFPI[i] = strtoul(str_rfpi, &end, 16);
|
||||
if ((errno == ERANGE )
|
||||
|| (errno != 0 && RFPI[i] == 0))
|
||||
{
|
||||
LOG("!!! please enter a valid RFPI (e.g. 00 01 02 03 04)\n");
|
||||
return;
|
||||
}
|
||||
if (end == str_rfpi)
|
||||
{
|
||||
LOG("!!! please enter a valid RFPI (e.g. 00 01 02 03 04)\n");
|
||||
return;
|
||||
}
|
||||
str_rfpi = end;
|
||||
}
|
||||
do_ppscan(RFPI);
|
||||
}
|
||||
|
||||
void do_chan(char * str_chan)
|
||||
{
|
||||
uint32_t channel;
|
||||
char * end;
|
||||
channel = strtoul(str_chan, &end, 0);
|
||||
if ((errno == ERANGE && (channel == LONG_MAX || channel == LONG_MIN))
|
||||
|| (errno != 0 && channel == 0))
|
||||
{
|
||||
LOG("!!! please enter a valid channel number [0-9]\n");
|
||||
return;
|
||||
}
|
||||
if (end == str_chan)
|
||||
{
|
||||
LOG("!!! please enter a valid channel number [0-9]\n");
|
||||
return;
|
||||
}
|
||||
if (channel > 9)
|
||||
{
|
||||
LOG("!!! please enter a valid channel number [0-9]\n");
|
||||
return;
|
||||
}
|
||||
cli.channel = channel;
|
||||
set_channel(cli.channel);
|
||||
}
|
||||
|
||||
void do_slot(char * str_chan)
|
||||
{
|
||||
uint32_t slot;
|
||||
char * end;
|
||||
slot = strtoul(str_chan, &end, 0);
|
||||
if ((errno == ERANGE && (slot == LONG_MAX || slot == LONG_MIN))
|
||||
|| (errno != 0 && slot == 0))
|
||||
{
|
||||
LOG("!!! please enter a valid slot number [0-23]\n");
|
||||
return;
|
||||
}
|
||||
if (end == str_chan)
|
||||
{
|
||||
LOG("!!! please enter a valid slot number [0-23]\n");
|
||||
return;
|
||||
}
|
||||
if (slot > 23)
|
||||
{
|
||||
LOG("!!! please enter a valid slot number [0-23]\n");
|
||||
return;
|
||||
}
|
||||
cli.slot = slot;
|
||||
set_slot(cli.slot);
|
||||
}
|
||||
|
||||
void do_jam(void)
|
||||
{
|
||||
LOG("!!! not yet implemented :(\n");
|
||||
}
|
||||
|
||||
void do_dump(void)
|
||||
{
|
||||
int i;
|
||||
struct dect_station * p = cli.station_list;
|
||||
if (!p)
|
||||
{
|
||||
LOG("### nothing found so far\n");
|
||||
return;
|
||||
}
|
||||
|
||||
LOG("### stations\n");
|
||||
do
|
||||
{
|
||||
if (p->type == TYPE_FP)
|
||||
{
|
||||
LOG(" ");
|
||||
for (i=0; i<5; i++)
|
||||
LOG(" %.2x", p->RFPI[i]);
|
||||
LOG(" ch %1.1d ", p->channel);
|
||||
LOG(" RSSI %5.2f ", (double)p->RSSI / p->count_seen);
|
||||
LOG(" count %4.u ", p->count_seen);
|
||||
LOG(" first %u ", p->first_seen);
|
||||
LOG(" last %u ", p->last_seen);
|
||||
LOG("\n");
|
||||
}
|
||||
} while ((p = p->next));
|
||||
|
||||
p = cli.station_list;
|
||||
LOG("### calls\n");
|
||||
do
|
||||
{
|
||||
if (p->type == TYPE_PP)
|
||||
{
|
||||
LOG(" ");
|
||||
for (i=0; i<5; i++)
|
||||
LOG(" %.2x", p->RFPI[i]);
|
||||
LOG(" ch %1.1d ", p->channel);
|
||||
LOG(" RSSI %5.2f ", (double)p->RSSI / p->count_seen);
|
||||
LOG(" count %4.u ", p->count_seen);
|
||||
LOG(" first %u ", p->first_seen);
|
||||
LOG(" last %u ", p->last_seen);
|
||||
LOG("\n");
|
||||
}
|
||||
} while ((p = p->next));
|
||||
}
|
||||
|
||||
void do_hop(void)
|
||||
{
|
||||
cli.hop = cli.hop ? 0:1;
|
||||
LOG("### channel hopping turned %s\n", cli.hop ? "ON":"OFF");
|
||||
}
|
||||
|
||||
void do_verb(void)
|
||||
{
|
||||
cli.verbose = cli.verbose ? 0:1;
|
||||
LOG("### verbosity turned %s\n", cli.verbose ? "ON":"OFF");
|
||||
}
|
||||
|
||||
void do_autorec(void)
|
||||
{
|
||||
cli.autorec = cli.autorec ? 0:1;
|
||||
LOG("### autorec turned %s\n", cli.autorec ? "ON":"OFF");
|
||||
}
|
||||
|
||||
void do_stop(void)
|
||||
{
|
||||
if (!(cli.mode & MODE_STOP))
|
||||
{
|
||||
LOG("### stopping DIP\n");
|
||||
uint16_t val;
|
||||
val = COA_MODE_IDLE;
|
||||
if (ioctl(cli.fd, COA_IOCTL_MODE, &val)){
|
||||
LOG("couldn't ioctl()\n");
|
||||
exit(1);
|
||||
}
|
||||
cli.mode = MODE_STOP;
|
||||
cli.autorec = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void process_cli_data()
|
||||
{
|
||||
int ret;
|
||||
ret = read(cli.in, buf, RXBUF);
|
||||
buf[ret]=0;
|
||||
if(buf[ret-1] == '\n')
|
||||
buf[ret-1] = 0;
|
||||
int done = 0;
|
||||
if ( !strncasecmp((char *)buf, "help", 4) )
|
||||
{ print_help(); done = 1; }
|
||||
if ( !strncasecmp((char *)buf, "fpscan", 6) )
|
||||
{ do_fpscan(); done = 1; }
|
||||
if ( !strncasecmp((char *)buf, "callscan", 8) )
|
||||
{ do_callscan(); done = 1; }
|
||||
if ( !strncasecmp((char *)buf, "autorec", 7) )
|
||||
{ do_autorec(); done = 1; }
|
||||
if ( !strncasecmp((char *)buf, "ppscan", 6) )
|
||||
{ do_ppscan_str(&buf[6]); done = 1; }
|
||||
if ( !strncasecmp((char *)buf, "chan", 4) )
|
||||
{ do_chan(&buf[4]); done = 1; }
|
||||
if ( !strncasecmp((char *)buf, "slot", 4) )
|
||||
{ do_slot(&buf[4]); done = 1; }
|
||||
if ( !strncasecmp((char *)buf, "jam", 3) )
|
||||
{ do_jam(); done = 1; }
|
||||
if ( !strncasecmp((char *)buf, "dump", 4) )
|
||||
{ do_dump(); done = 1; }
|
||||
if ( !strncasecmp((char *)buf, "hop", 3) )
|
||||
{ do_hop(); done = 1; }
|
||||
if ( !strncasecmp((char *)buf, "verb", 4) )
|
||||
{ do_verb(); done = 1; }
|
||||
if ( !strncasecmp((char *)buf, "stop", 4) )
|
||||
{ do_stop(); done = 1; }
|
||||
if ( !strncasecmp((char *)buf, "quit", 4) )
|
||||
{ do_stop(); exit(0); }
|
||||
|
||||
if(!done)
|
||||
LOG("!!! no such command %s\n", buf);
|
||||
|
||||
}
|
||||
|
||||
void init_pcap(struct sniffed_packet * packet)
|
||||
{
|
||||
char fname[100];
|
||||
sprintf(fname, "dump_%.2x_%.2x_%.2x_%.2x_%.2x.pcap",
|
||||
cli.RFPI[0],
|
||||
cli.RFPI[1],
|
||||
cli.RFPI[2],
|
||||
cli.RFPI[3],
|
||||
cli.RFPI[4]);
|
||||
LOG("### dumping to %s\n", fname);
|
||||
cli.pcap = pcap_open_dead(DLT_EN10MB, 73);
|
||||
if (!cli.pcap)
|
||||
{
|
||||
LOG("!!! couldn't pcap_open_dead(\"%s\")\n", fname);
|
||||
}
|
||||
cli.pcap_d = pcap_dump_open(cli.pcap, fname);
|
||||
if (!cli.pcap_d)
|
||||
{
|
||||
LOG("!!! couldn't pcap_dump_open(\"%s\")\n", fname);
|
||||
}
|
||||
}
|
||||
|
||||
int has_b_field()
|
||||
{
|
||||
if ((cli.packet.data[0x19] & 0x0e) != 0x0e)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void process_dect_data()
|
||||
{
|
||||
int ret;
|
||||
switch (cli.mode)
|
||||
{
|
||||
case MODE_FPSCAN:
|
||||
while (7 == (ret = read(cli.fd, buf, 7))){
|
||||
memcpy(cli.station.RFPI, &buf[2], 5);
|
||||
cli.station.channel = buf[0];
|
||||
cli.station.RSSI = buf[1];
|
||||
cli.station.type = TYPE_FP;
|
||||
try_add_station(&cli.station);
|
||||
}
|
||||
break;
|
||||
case MODE_CALLSCAN:
|
||||
while (7 == (ret = read(cli.fd, buf, 7))){
|
||||
memcpy(cli.station.RFPI, &buf[2], 5);
|
||||
cli.station.channel = buf[0];
|
||||
cli.station.RSSI = buf[1];
|
||||
cli.station.type = TYPE_PP;
|
||||
try_add_station(&cli.station);
|
||||
}
|
||||
break;
|
||||
case MODE_PPSCAN:
|
||||
while ( sizeof(cli.packet) ==
|
||||
read(cli.fd, &cli.packet, sizeof(cli.packet)))
|
||||
{
|
||||
if (!cli.pcap)
|
||||
{
|
||||
LOG("### got sync\n");
|
||||
init_pcap(&cli.packet);
|
||||
/* this is not actually a B-Field,
|
||||
* but we expect some to come soon
|
||||
* and the val needs to be non-0 */
|
||||
cli.autorec_last_bfield = time(NULL);
|
||||
}
|
||||
if (has_b_field())
|
||||
cli.autorec_last_bfield = time(NULL);
|
||||
|
||||
struct pcap_pkthdr pcap_hdr;
|
||||
pcap_hdr.caplen = 73;
|
||||
pcap_hdr.len = 73;
|
||||
ret = gettimeofday(&pcap_hdr.ts, NULL);
|
||||
if (ret)
|
||||
{
|
||||
LOG("!!! couldn't gettimeofday(): %s\n",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
uint8_t pcap_packet[100];
|
||||
memset(pcap_packet, 0, 100);
|
||||
pcap_packet[12] = 0x23;
|
||||
pcap_packet[13] = 0x23;
|
||||
pcap_packet[14] = 0x00; /* decttype (receive) */
|
||||
pcap_packet[15] = cli.packet.channel;
|
||||
pcap_packet[16] = 0;
|
||||
pcap_packet[17] = cli.packet.slot;
|
||||
pcap_packet[18] = 0;
|
||||
pcap_packet[19] = cli.packet.rssi;
|
||||
memcpy(&pcap_packet[20], cli.packet.data, 53);
|
||||
|
||||
pcap_dump(cli.pcap_d, &pcap_hdr, pcap_packet);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void init_dect()
|
||||
{
|
||||
cli.fd = open(DEV, O_RDWR | O_NONBLOCK);
|
||||
if (cli.fd < 0)
|
||||
{
|
||||
LOG("!!! couldn't open(\"%s\"): %s\n",
|
||||
DEV,
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
cli.pcap = NULL;
|
||||
}
|
||||
|
||||
void init_cli()
|
||||
{
|
||||
cli.channel = 0;
|
||||
cli.slot = 0;
|
||||
cli.hop = 1;
|
||||
cli.hop_ch_time = 1; /* in sec */
|
||||
|
||||
cli.mode = MODE_STOP;
|
||||
|
||||
cli.in = fileno(stdin);
|
||||
|
||||
cli.verbose = 0;
|
||||
|
||||
cli.station_list = NULL;
|
||||
|
||||
cli.autorec = 0;
|
||||
cli.autorec_timeout = 10;
|
||||
cli.autorec_last_bfield = 0;
|
||||
}
|
||||
|
||||
void init(void)
|
||||
{
|
||||
init_dect();
|
||||
init_cli();
|
||||
}
|
||||
|
||||
int max_int(int a, int b)
|
||||
{
|
||||
if (a>b)
|
||||
return a;
|
||||
else
|
||||
return b;
|
||||
}
|
||||
|
||||
void mainloop(void)
|
||||
{
|
||||
fd_set rfd;
|
||||
fd_set wfd;
|
||||
fd_set efd;
|
||||
|
||||
int nfds = max_int(cli.in, cli.fd);
|
||||
nfds++;
|
||||
|
||||
struct timeval tv;
|
||||
|
||||
int ret;
|
||||
|
||||
#ifdef DUMP_IRQ_COUNT_ONCE_PER_SEC
|
||||
#define COA_IOCTL_COUNT_IRQ 0xF002
|
||||
uint32_t lasttime = time(NULL);
|
||||
#endif
|
||||
|
||||
|
||||
while (0xDEC + 'T')
|
||||
{
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
|
||||
FD_ZERO(&rfd);
|
||||
FD_ZERO(&wfd);
|
||||
FD_ZERO(&efd);
|
||||
|
||||
FD_SET(cli.in, &rfd);
|
||||
FD_SET(cli.fd, &rfd);
|
||||
|
||||
FD_SET(cli.in, &efd);
|
||||
FD_SET(cli.fd, &efd);
|
||||
|
||||
ret = select(nfds, &rfd, &wfd, &efd, &tv);
|
||||
if (ret < 0)
|
||||
{
|
||||
LOG("!!! select()\n");
|
||||
exit(1);
|
||||
}
|
||||
if (FD_ISSET(cli.in, &efd))
|
||||
{
|
||||
LOG("!!! select() on in: %s\n",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
if (FD_ISSET(cli.fd, &efd))
|
||||
{
|
||||
LOG("!!! select() on fd: %s\n",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (FD_ISSET(cli.in, &rfd))
|
||||
process_cli_data();
|
||||
if (FD_ISSET(cli.fd, &rfd))
|
||||
process_dect_data();
|
||||
|
||||
#ifdef DUMP_IRQ_COUNT_ONCE_PER_SEC
|
||||
if (!(cli.mode & MODE_STOP))
|
||||
if (time(NULL) >= lasttime + 1)
|
||||
{
|
||||
if (ioctl(cli.fd, COA_IOCTL_COUNT_IRQ, NULL))
|
||||
{
|
||||
printf("couldn't ioctl()\n");
|
||||
exit(1);
|
||||
}
|
||||
lasttime = time(NULL);
|
||||
}
|
||||
#endif
|
||||
|
||||
if( (cli.hop) &&
|
||||
( (cli.mode & MODE_FPSCAN) ||
|
||||
(cli.mode & MODE_CALLSCAN) ||
|
||||
(cli.mode & MODE_JAM ) ))
|
||||
{
|
||||
if ( time(NULL) > cli.last_hop + cli.hop_ch_time )
|
||||
{
|
||||
cli.channel++;
|
||||
cli.channel %= 10;
|
||||
set_channel(cli.channel);
|
||||
}
|
||||
}
|
||||
|
||||
if (cli.autorec)
|
||||
{
|
||||
if ( (time (NULL) - cli.autorec_last_bfield
|
||||
> cli.autorec_timeout)
|
||||
&&
|
||||
(cli.mode != MODE_CALLSCAN)
|
||||
)
|
||||
{
|
||||
do_stop();
|
||||
do_callscan();
|
||||
if (cli.pcap)
|
||||
{
|
||||
pcap_dump_close(cli.pcap_d);
|
||||
pcap_close(cli.pcap);
|
||||
cli.pcap_d = NULL;
|
||||
cli.pcap = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
init();
|
||||
/* make stdout unbuffered */
|
||||
setvbuf(stdout,(char*)NULL,_IONBF,0);
|
||||
printf("DECT command line interface\n");
|
||||
printf("type \"help\" if you're lost\n");
|
||||
mainloop();
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* dect_cli async and sync interface to DECT, can dump pcap files
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* authors:
|
||||
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
|
||||
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DECT_CLI_H
|
||||
#define DECT_CLI_H
|
||||
|
||||
#define DEV "/dev/coa"
|
||||
|
||||
// too verbose #define LOG(fmt, args...) printf("%s(): " fmt, __FUNCTION__, ##args)
|
||||
#define LOG(fmt, args...) printf(fmt, ##args)
|
||||
|
||||
|
||||
#define TYPE_FP 23
|
||||
#define TYPE_PP 42
|
||||
|
||||
struct dect_station
|
||||
{
|
||||
struct dect_station * next;
|
||||
uint8_t RFPI[5];
|
||||
uint32_t RSSI;
|
||||
uint8_t channel;
|
||||
uint8_t type;
|
||||
uint32_t first_seen;
|
||||
uint32_t last_seen;
|
||||
uint32_t count_seen;
|
||||
};
|
||||
|
||||
struct sniffed_packet
|
||||
{
|
||||
unsigned char rssi;
|
||||
unsigned char channel;
|
||||
unsigned char slot;
|
||||
struct timespec timestamp;
|
||||
unsigned char data[53];
|
||||
};
|
||||
|
||||
|
||||
#define MODE_STOP 0x00000001
|
||||
#define MODE_FPSCAN 0x00000002
|
||||
#define MODE_PPSCAN 0x00000004
|
||||
#define MODE_CALLSCAN 0x00000008
|
||||
#define MODE_JAM 0x00000010
|
||||
|
||||
|
||||
struct cli_info
|
||||
{
|
||||
uint8_t RFPI[5];
|
||||
uint32_t channel;
|
||||
uint32_t slot;
|
||||
int hop;
|
||||
int hop_ch_time; /* in sec */
|
||||
uint32_t last_hop;
|
||||
|
||||
uint32_t mode;
|
||||
|
||||
int in; /* stdin */
|
||||
int fd; /* filehandle to the DECT-trx */
|
||||
|
||||
int verbose;
|
||||
int autorec;
|
||||
int autorec_timeout;
|
||||
int autorec_last_bfield;
|
||||
|
||||
/* fpscan (async) list of stations */
|
||||
struct dect_station station;
|
||||
struct dect_station * station_list;
|
||||
|
||||
/* ppscan (sync) */
|
||||
struct sniffed_packet packet;
|
||||
pcap_t * pcap;
|
||||
pcap_dumper_t * pcap_d;
|
||||
};
|
||||
|
||||
|
||||
#endif /* DECT_CLI_H */
|
|
@ -0,0 +1,6 @@
|
|||
CPPFLAGS=-Wall -O2 -I../.. -lcurses -lpthread
|
||||
dectshark: dectshark.o gui.o foundinfo.o
|
||||
g++ $(CPPFLAGS) dectshark.cpp gui.cpp foundinfo.cpp -o dectshark
|
||||
|
||||
clean:
|
||||
rm *.o dectshark
|
|
@ -0,0 +1,122 @@
|
|||
#include <ncurses.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
|
||||
#include "com_on_air_user.h"
|
||||
|
||||
|
||||
#include "foundinfo.h"
|
||||
#include "gui.h"
|
||||
|
||||
#define DEV "/dev/coa"
|
||||
|
||||
void *pcap_threadmain(void *threadid);
|
||||
void *show_threadmain(void *threadid);
|
||||
|
||||
|
||||
found_dects founds;
|
||||
print_gui gui;
|
||||
|
||||
pthread_t pcap_thread;
|
||||
pthread_t show_thread;
|
||||
|
||||
|
||||
|
||||
void set_channel(int dev,int channel);
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ch;
|
||||
|
||||
pthread_create(&pcap_thread, NULL, pcap_threadmain, (void *)0);
|
||||
// pthread_create(&show_thread, NULL, show_threadmain, (void *)0);
|
||||
|
||||
// while(1);
|
||||
|
||||
gui.work();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void *pcap_threadmain(void *threadid)
|
||||
{
|
||||
int tid;
|
||||
int chn=0,channeltime=0;
|
||||
int dev;
|
||||
|
||||
dev = open(DEV, O_RDONLY);
|
||||
if (dev<0){
|
||||
printf("couldn't open(\"%s\"): %s\n", DEV, strerror(errno));
|
||||
}
|
||||
|
||||
uint16_t val;
|
||||
val = COA_MODE_SNIFF|COA_SUBMODE_SNIFF_SCANPP;
|
||||
if (ioctl(dev, COA_IOCTL_MODE, &val)){
|
||||
printf("couldn't set sniff mode\n");
|
||||
}
|
||||
|
||||
|
||||
while(0xDEC + 't') // ;)
|
||||
{
|
||||
dect_found found;
|
||||
|
||||
unsigned char buf[7];
|
||||
while (7 == (read(dev, buf, 7)))
|
||||
{
|
||||
memcpy(found.RFPI,buf+2,5);
|
||||
found.channel=buf[0];
|
||||
found.type=DECT_FOUND_FP;
|
||||
founds.AddDect(found);
|
||||
}
|
||||
|
||||
usleep(100000);
|
||||
channeltime++;
|
||||
|
||||
if(channeltime == 5)
|
||||
{
|
||||
chn++;
|
||||
chn %= 10;
|
||||
set_channel(dev,chn);
|
||||
channeltime = 0;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
void set_channel(int dev,int channel)
|
||||
{
|
||||
if (ioctl(dev, COA_IOCTL_CHAN, &channel)){
|
||||
printf("couldn't set channel\n");
|
||||
}
|
||||
|
||||
gui.setchannel(channel);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void *show_threadmain(void *threadid)
|
||||
{
|
||||
gui.work();
|
||||
pthread_exit(NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,97 @@
|
|||
#include "foundinfo.h"
|
||||
|
||||
found_dects::found_dects()
|
||||
{
|
||||
pthread_mutex_init(&mutex,NULL);
|
||||
|
||||
listlen=0;
|
||||
list=(dect_listentry*)malloc(0);
|
||||
}
|
||||
|
||||
found_dects::~found_dects()
|
||||
{
|
||||
listlen=0;
|
||||
free(list);
|
||||
|
||||
pthread_mutex_destroy(&mutex);
|
||||
}
|
||||
|
||||
|
||||
void found_dects::AddDect(dect_found found)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
pthread_mutex_lock(&mutex);
|
||||
|
||||
for(i=0;i<listlen;i++)
|
||||
{
|
||||
if(list[i].channel==found.channel)
|
||||
{
|
||||
if(!memcmp(list[i].RFPI,found.RFPI,5))
|
||||
{
|
||||
if(found.type==DECT_FOUND_FP)
|
||||
list[i].fppackets++;
|
||||
else
|
||||
list[i].pppackets++;
|
||||
|
||||
pthread_mutex_unlock(&mutex);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
listlen++;
|
||||
list=(dect_listentry*)realloc(list,listlen*sizeof(dect_listentry));
|
||||
|
||||
memcpy(list[listlen-1].RFPI,found.RFPI,5);
|
||||
list[listlen-1].channel=found.channel;
|
||||
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
void found_dects::ClearList()
|
||||
{
|
||||
pthread_mutex_lock(&mutex);
|
||||
|
||||
list=(dect_listentry*)realloc(list,0);
|
||||
listlen=0;
|
||||
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
dect_listentry found_dects::GetListEntry(unsigned int entry)
|
||||
{
|
||||
pthread_mutex_lock(&mutex);
|
||||
|
||||
if(entry<listlen)
|
||||
{
|
||||
dect_listentry temp=list[entry];
|
||||
temp.valid=true;
|
||||
|
||||
pthread_mutex_unlock(&mutex);
|
||||
return temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
dect_listentry temp;
|
||||
temp.valid=false;
|
||||
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
|
||||
int found_dects::GetListLength()
|
||||
{
|
||||
int tlen;
|
||||
|
||||
pthread_mutex_lock(&mutex);
|
||||
tlen=listlen;
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
return tlen;
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
#include <pthread.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
|
||||
#if !defined(FOUNDINFO_H)
|
||||
#define FOUNDINFO_H
|
||||
|
||||
|
||||
#define DECT_FOUND_FP 0
|
||||
#define DECT_FOUND_PP 1
|
||||
#define DECT_FOUND_LISTENTRY 2
|
||||
#define DECT_FOUND_INVALID 0xFFFF
|
||||
|
||||
struct dect_found
|
||||
{
|
||||
unsigned int type;
|
||||
unsigned char RFPI[5];
|
||||
char channel;
|
||||
};
|
||||
|
||||
|
||||
struct dect_listentry
|
||||
{
|
||||
unsigned char RFPI[5];
|
||||
char channel;
|
||||
unsigned int fppackets;
|
||||
unsigned int pppackets;
|
||||
bool valid;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class found_dects
|
||||
{
|
||||
public:
|
||||
found_dects();
|
||||
~found_dects();
|
||||
|
||||
void AddDect(dect_found found);
|
||||
void ClearList();
|
||||
dect_listentry GetListEntry(unsigned int entry);
|
||||
int GetListLength();
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
int listlen;
|
||||
dect_listentry *list;
|
||||
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,247 @@
|
|||
#include "gui.h"
|
||||
|
||||
print_gui::print_gui()
|
||||
{
|
||||
selected=startpos=displaypos=0;
|
||||
}
|
||||
|
||||
print_gui::~print_gui()
|
||||
{
|
||||
endwin();
|
||||
}
|
||||
|
||||
|
||||
void print_gui::up()
|
||||
{
|
||||
pthread_mutex_lock(&mutex);
|
||||
|
||||
if(founds.GetListLength()<=(SH-7))
|
||||
{
|
||||
if(displaypos>0)
|
||||
{
|
||||
displaypos--;
|
||||
selected--;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(displaypos>0)
|
||||
{
|
||||
displaypos--;
|
||||
selected--;
|
||||
}
|
||||
else if(startpos>0)
|
||||
{
|
||||
selected--;
|
||||
startpos--;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
void print_gui::down()
|
||||
{
|
||||
pthread_mutex_lock(&mutex);
|
||||
|
||||
if(founds.GetListLength()<=(SH-7))
|
||||
{
|
||||
if(displaypos<(founds.GetListLength()-1))
|
||||
{
|
||||
displaypos++;
|
||||
selected++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(displaypos<(SH-8))
|
||||
{
|
||||
displaypos++;
|
||||
selected++;
|
||||
}
|
||||
else if(startpos<=(founds.GetListLength()-1-(SH-7)))
|
||||
{
|
||||
selected++;
|
||||
startpos++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
int print_gui::getselected()
|
||||
{
|
||||
pthread_mutex_lock(&mutex);
|
||||
return selected;
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void print_gui::work()
|
||||
{
|
||||
InitCurses();
|
||||
|
||||
while(1)
|
||||
{
|
||||
|
||||
if(kbhit_wait(300000))
|
||||
{
|
||||
int ch=wgetch(mainwin);
|
||||
|
||||
switch(ch)
|
||||
{
|
||||
case KEY_LEFT:
|
||||
break;
|
||||
case KEY_RIGHT:
|
||||
break;
|
||||
case KEY_UP:
|
||||
up();
|
||||
break;
|
||||
case KEY_DOWN:
|
||||
down();
|
||||
break;
|
||||
case 'l':
|
||||
//SetLockMode();
|
||||
break;
|
||||
case 'o':
|
||||
//SetOverviewMode();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&mutex);
|
||||
|
||||
PrintFounds(startpos,SH-7,selected);
|
||||
PrintStatus(startpos,founds.GetListLength(),channel);
|
||||
|
||||
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void print_gui::InitCurses()
|
||||
{
|
||||
initscr();
|
||||
|
||||
|
||||
start_color();
|
||||
init_pair(1,COLOR_GREEN,COLOR_BLACK);
|
||||
init_pair(2,COLOR_YELLOW,COLOR_BLACK);
|
||||
init_pair(3,COLOR_WHITE,COLOR_BLACK);
|
||||
init_pair(4,COLOR_RED,COLOR_BLACK);
|
||||
init_pair(5,COLOR_YELLOW,COLOR_GREEN);
|
||||
|
||||
mainwin = newwin(SH-4,SW-20,0,0);
|
||||
statuswin = newwin(SH,20,0,SW-20);
|
||||
msgwin = newwin(4,SW-20,SH-4,0);
|
||||
|
||||
// cbreak();
|
||||
noecho();
|
||||
keypad(mainwin,TRUE);
|
||||
|
||||
wbkgdset(mainwin,(COLOR_PAIR(1)|A_BOLD));
|
||||
wbkgdset(statuswin,(COLOR_PAIR(1)|A_BOLD));
|
||||
wbkgdset(msgwin,(COLOR_PAIR(1)|A_BOLD));
|
||||
|
||||
|
||||
box(mainwin,0,0);
|
||||
wattron(mainwin,COLOR_PAIR(3));
|
||||
mvwprintw(mainwin,1,1,"RFPI");
|
||||
mvwprintw(mainwin,1,13,"Ch");
|
||||
mvwprintw(mainwin,1,31,"FP-Pkt");
|
||||
mvwprintw(mainwin,1,51,"PP-Pkt");
|
||||
wnoutrefresh(mainwin);
|
||||
|
||||
box(statuswin,0,0);
|
||||
wattron(statuswin,COLOR_PAIR(2));
|
||||
mvwprintw(statuswin,1,1,"Station Packets:");
|
||||
mvwprintw(statuswin,4,1,"Phone Packets:");
|
||||
mvwprintw(statuswin,SH-3,1,"Channel:");
|
||||
wnoutrefresh(statuswin);
|
||||
|
||||
box(msgwin,0,0);
|
||||
wnoutrefresh(msgwin);
|
||||
|
||||
doupdate();
|
||||
|
||||
}
|
||||
|
||||
void print_gui::RefreshScreen()
|
||||
{
|
||||
wnoutrefresh(mainwin);
|
||||
wnoutrefresh(statuswin);
|
||||
wnoutrefresh(msgwin);
|
||||
|
||||
doupdate();
|
||||
}
|
||||
|
||||
|
||||
void print_gui::PrintFounds(int start,int num,int selected)
|
||||
{
|
||||
int i,y;
|
||||
|
||||
y=2;
|
||||
for(i=start;i<(start+num);i++)
|
||||
{
|
||||
if(i==selected)
|
||||
wattron(mainwin,COLOR_PAIR(5));
|
||||
else
|
||||
wattron(mainwin,COLOR_PAIR(2));
|
||||
|
||||
dect_listentry entry=founds.GetListEntry(i);
|
||||
|
||||
if(entry.valid)
|
||||
{
|
||||
mvwprintw(mainwin,y,1,"%.2x%.2x%.2x%.2x%.2x ",entry.RFPI[0],entry.RFPI[1],entry.RFPI[2],entry.RFPI[3],entry.RFPI[4]);
|
||||
mvwprintw(mainwin,y,13,"%.2i %12u %12u",entry.channel,entry.fppackets,entry.pppackets);
|
||||
y++;
|
||||
}
|
||||
}
|
||||
|
||||
wrefresh(mainwin);
|
||||
}
|
||||
|
||||
|
||||
void print_gui::PrintStatus(unsigned int PP,unsigned int FP,int channel)
|
||||
{
|
||||
wattron(statuswin,COLOR_PAIR(3));
|
||||
mvwprintw(statuswin,2,1,"%17u",FP);
|
||||
mvwprintw(statuswin,5,1,"%17u",PP);
|
||||
|
||||
mvwprintw(statuswin,SH-2,16,"%2u",channel);
|
||||
wrefresh(statuswin);
|
||||
}
|
||||
|
||||
void print_gui::setchannel(int chn)
|
||||
{
|
||||
pthread_mutex_lock(&mutex);
|
||||
channel=chn;
|
||||
pthread_mutex_unlock(&mutex);
|
||||
}
|
||||
|
||||
|
||||
int print_gui::kbhit_wait(int time)
|
||||
{
|
||||
struct timeval tv;
|
||||
fd_set read_fd;
|
||||
|
||||
tv.tv_sec=0;
|
||||
tv.tv_usec=time;
|
||||
|
||||
FD_ZERO(&read_fd);
|
||||
FD_SET(0,&read_fd);
|
||||
|
||||
if(select(1,&read_fd,NULL,NULL,&tv)==-1)
|
||||
return 0;
|
||||
|
||||
if(FD_ISSET(0,&read_fd))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
#include <ncurses.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/select.h>
|
||||
|
||||
#include "foundinfo.h"
|
||||
|
||||
#if !defined(GUI_H)
|
||||
#define GUI_H
|
||||
|
||||
#define SW 80
|
||||
#define SH 25
|
||||
|
||||
extern found_dects founds;
|
||||
|
||||
class print_gui
|
||||
{
|
||||
public:
|
||||
print_gui();
|
||||
~print_gui();
|
||||
|
||||
void work();
|
||||
|
||||
void up();
|
||||
void down();
|
||||
|
||||
int getselected();
|
||||
|
||||
|
||||
void setchannel(int channel);
|
||||
protected:
|
||||
void InitCurses();
|
||||
void RefreshScreen();
|
||||
void PrintFounds(int start,int num,int selected);
|
||||
void PrintStatus(unsigned int PP,unsigned int FP,int channel);
|
||||
int kbhit_wait(int time);
|
||||
|
||||
pthread_mutex_t mutex;
|
||||
|
||||
int selected,startpos,displaypos;
|
||||
|
||||
WINDOW *mainwin;
|
||||
WINDOW *statuswin;
|
||||
WINDOW *msgwin;
|
||||
|
||||
int channel;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,246 @@
|
|||
/*
|
||||
* pcap2cchan dumps C-channel information from pcap files
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* authors:
|
||||
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
|
||||
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dect_c_channel.h"
|
||||
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
struct cfrag frag;
|
||||
struct cpacket cpacket;
|
||||
|
||||
struct cdevice phone,station;
|
||||
phone.type=station.type=0;
|
||||
phone.cdata=station.cdata=0;
|
||||
phone.found=station.found=0;
|
||||
phone.cnt=station.cnt=0;
|
||||
|
||||
unsigned char packet[135];
|
||||
unsigned int length;
|
||||
|
||||
FILE *pcap=fopen(argv[1],"rb");
|
||||
|
||||
fseek(pcap,0x18,SEEK_SET);
|
||||
|
||||
while(!feof(pcap))
|
||||
{
|
||||
fseek(pcap,12,SEEK_CUR);
|
||||
fread(&length,4,1,pcap);
|
||||
|
||||
if(length>135)
|
||||
{
|
||||
printf("error , packet size too big\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
fread(packet,length,1,pcap);
|
||||
frag=getcfrag(packet+23,packet[17]);
|
||||
|
||||
if(frag.valid)
|
||||
{
|
||||
if(packet[23]==0x16)
|
||||
{
|
||||
cpacket=getcpacket(frag,&phone);
|
||||
|
||||
//printf("Frag : %u -> %u:%.2x %.2x %.2x %.2x %.2x\n",frag.slot,frag.cttype,frag.data[0],frag.data[1],frag.data[2],frag.data[3],frag.data[4]);
|
||||
|
||||
if(cpacket.valid)
|
||||
{
|
||||
printcpacket(cpacket,"phone ");
|
||||
}
|
||||
}
|
||||
else if(packet[23]==0xe9)
|
||||
{
|
||||
cpacket=getcpacket(frag,&station);
|
||||
|
||||
//printf("Frag : %u -> %u:%.2x %.2x %.2x %.2x %.2x\n",frag.slot,frag.cttype,frag.data[0],frag.data[1],frag.data[2],frag.data[3],frag.data[4]);
|
||||
|
||||
|
||||
if(cpacket.valid)
|
||||
printcpacket(cpacket,"station");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fclose(pcap);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct cfrag getcfrag(unsigned char *dect,int slot)
|
||||
{
|
||||
struct cfrag frag;
|
||||
|
||||
if((dect[2]&0xc0)==0) //Ct tail (?)
|
||||
{
|
||||
frag.valid=1;
|
||||
|
||||
frag.cttype=(dect[2]&0x20)>>5;
|
||||
frag.slot=slot;
|
||||
memcpy(frag.data,dect+3,5);
|
||||
|
||||
}
|
||||
else
|
||||
frag.valid=0;
|
||||
|
||||
return frag;
|
||||
}
|
||||
|
||||
|
||||
char *getstring(struct strtype *str,int id,int max)
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<max;i++)
|
||||
{
|
||||
if(str[i].type==id)
|
||||
return str[i].name;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct cpacket getcpacket(struct cfrag frag,struct cdevice *device)
|
||||
{
|
||||
device->packet.valid=0;
|
||||
|
||||
if((frag.cttype!=device->type)&&(!device->found))
|
||||
{
|
||||
device->packet.addr=frag.data[0];
|
||||
device->packet.ctrl=frag.data[1];
|
||||
device->packet.length=frag.data[2];
|
||||
|
||||
if((device->packet.length>>2)>0)
|
||||
{
|
||||
device->packet.data[0]=frag.data[3];
|
||||
device->packet.data[1]=frag.data[4];
|
||||
device->cdata+=2;
|
||||
device->cnt=1;
|
||||
device->found=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
device->packet.checksum=(((unsigned short)(frag.data[3]))<<8)|(frag.data[4]);
|
||||
device->packet.valid=1;
|
||||
device->cdata=0;
|
||||
device->cnt=0;
|
||||
device->found=0;
|
||||
}
|
||||
|
||||
device->type=!device->type;
|
||||
|
||||
}
|
||||
else if(frag.cttype!=device->type)
|
||||
{
|
||||
memcpy(device->packet.data+device->cdata,frag.data,5);
|
||||
device->cdata+=5;
|
||||
device->cnt++;
|
||||
device->type=!device->type;
|
||||
|
||||
if(device->cnt>=pklookup[device->packet.length>>2])
|
||||
{
|
||||
device->packet.checksum=(((unsigned short)(frag.data[3]))<<8)|(frag.data[4]);
|
||||
device->packet.valid=1;
|
||||
device->cdata=0;
|
||||
device->cnt=0;
|
||||
device->found=0;
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
//printf("packet loss (?)\n");
|
||||
device->type=!device->type;
|
||||
|
||||
if(device->found)
|
||||
{
|
||||
memset(device->packet.data+device->cdata,0xff,5);
|
||||
device->cdata+=5;
|
||||
device->cnt++;
|
||||
|
||||
if(device->cnt>=pklookup[device->packet.length>>2])
|
||||
{
|
||||
device->cdata=0;
|
||||
device->packet.valid=1;
|
||||
device->found=0;
|
||||
|
||||
printcpacket(device->packet,"failed ");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
getcpacket(frag,device);
|
||||
|
||||
}
|
||||
|
||||
|
||||
return device->packet;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void printcpacket(struct cpacket packet,char *prefix)
|
||||
{
|
||||
int x;
|
||||
|
||||
printf("\n%s: addr:%.2x ctrl:%.2x len:%.2x crc:%.4x",prefix,packet.addr,packet.ctrl,packet.length,packet.checksum);
|
||||
|
||||
if(packet.length>>2)
|
||||
{
|
||||
printf(" -> ");
|
||||
|
||||
char id=packet.data[1];
|
||||
switch(packet.data[0]&0x0f)
|
||||
{
|
||||
case 0:
|
||||
printf("%s :%s",msgtype[packet.data[0]&0x0f].name,NULL);
|
||||
break;
|
||||
case 3:
|
||||
printf("%s :%s",msgtype[packet.data[0]&0x0f].name,getstring(cctype,id,256));
|
||||
break;
|
||||
case 4:
|
||||
printf("%s :%s",msgtype[packet.data[0]&0x0f].name,getstring(sstype,id,256));
|
||||
break;
|
||||
case 5:
|
||||
printf("%s :%s",msgtype[packet.data[0]&0x0f].name,getstring(mmtype,id,256));
|
||||
break;
|
||||
case 6:
|
||||
printf("%s :%s",msgtype[packet.data[0]&0x0f].name,NULL);
|
||||
break;
|
||||
case 7:
|
||||
printf("%s :%s",msgtype[packet.data[0]&0x0f].name,NULL);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("reserved ");
|
||||
break;
|
||||
}
|
||||
|
||||
printf(" ");
|
||||
|
||||
for(x=0;x<(packet.length>>2);x++)
|
||||
printf(" %.2x",packet.data[x]);
|
||||
}
|
||||
|
||||
// printf("\n\n\n");
|
||||
}
|
|
@ -0,0 +1,177 @@
|
|||
/*
|
||||
* pcapstein dumps all B-Fields found in a pcap file
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* authors:
|
||||
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
|
||||
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <pcap.h>
|
||||
|
||||
#include "pcapstein.h"
|
||||
|
||||
struct file_info fi;
|
||||
|
||||
void usage(void)
|
||||
{
|
||||
fprintf(stderr, "usage: pcapstein <dect-pcap-file>\n");
|
||||
fprintf(stderr, " creates <dect-pcap-file>_pp.ima\n");
|
||||
fprintf(stderr, " and <dect-pcap-file>_fp.ima\n");
|
||||
fprintf(stderr, " for further g.721 audio processing\n");
|
||||
fprintf(stderr, " e.g. decode and sox\n");
|
||||
}
|
||||
|
||||
void init(char * fname)
|
||||
{
|
||||
fi.p = pcap_open_offline(fname, errbuf);
|
||||
if (!fi.p)
|
||||
{
|
||||
fprintf(stderr, "couln't open(\"%s\"): %s\n",
|
||||
fname,
|
||||
strerror(errno));
|
||||
fprintf(stderr, "pcap error: %s\n",
|
||||
errbuf);
|
||||
exit(1);
|
||||
}
|
||||
fprintf(stderr, "%s\n",
|
||||
pcap_lib_version());
|
||||
fprintf(stderr, "pcap file version %d.%d\n",
|
||||
pcap_major_version(fi.p),
|
||||
pcap_minor_version(fi.p)
|
||||
);
|
||||
|
||||
/* output file handles */
|
||||
char * imafname = malloc(strlen(fname)+23);
|
||||
if (!imafname)
|
||||
{
|
||||
fprintf(stderr, "out of memory: %s\n",
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* PP output file */
|
||||
sprintf(imafname, "%s_pp.ima", fname);
|
||||
fi.fpp = open(imafname, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
|
||||
if (!fi.fpp)
|
||||
{
|
||||
fprintf(stderr, "couldn't open(\"%s\"): %s\n",
|
||||
imafname,
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* FP output file */
|
||||
sprintf(imafname, "%s_fp.ima", fname);
|
||||
fi.ffp = open(imafname, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR);
|
||||
if (!fi.ffp)
|
||||
{
|
||||
fprintf(stderr, "couldn't open(\"%s\"): %s\n",
|
||||
imafname,
|
||||
strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
|
||||
free (imafname);
|
||||
}
|
||||
|
||||
void process_b_field(const struct pcap_pkthdr *h, const u_char *pkt)
|
||||
{
|
||||
if ( (pkt[0x17] == 0x16) && (pkt[0x18] == 0x75) )
|
||||
write(fi.fpp, &pkt[0x21], 40);
|
||||
else
|
||||
write(fi.ffp, &pkt[0x21], 40);
|
||||
}
|
||||
|
||||
void process_pcap_packet(
|
||||
u_char *user, const struct pcap_pkthdr *h,
|
||||
const u_char *pkt)
|
||||
{
|
||||
#if 0
|
||||
int i;
|
||||
printf("packet for %s [%u/%u] @%d.%d\n",
|
||||
user,
|
||||
h->len,
|
||||
h->caplen,
|
||||
h->ts.tv_sec,
|
||||
h->ts.tv_usec
|
||||
);
|
||||
#endif
|
||||
|
||||
if (pkt[ETH_TYPE_0_OFF] != ETH_TYPE_0)
|
||||
return;
|
||||
if (pkt[ETH_TYPE_1_OFF] != ETH_TYPE_1)
|
||||
return;
|
||||
#if 0
|
||||
for (i=0; i<sizeof(dect_pkt_hdr); i++)
|
||||
printf("%.2x ", pkt[i]);
|
||||
printf("\n");
|
||||
#endif
|
||||
|
||||
if ((pkt[PKT_OFF_H] & DECT_H_BA_MASK) == DECT_H_BA_NO_B_FIELD)
|
||||
return;
|
||||
|
||||
if ((pkt[PKT_OFF_H] & DECT_H_BA_MASK) == DECT_H_BA_HALF_SLOT)
|
||||
{
|
||||
fprintf(stderr, "unsopported half slot\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if ((pkt[PKT_OFF_H] & DECT_H_BA_MASK) == DECT_H_BA_DOUBLE_SLOT)
|
||||
{
|
||||
fprintf(stderr, "unsopported double slot\n");
|
||||
return;
|
||||
}
|
||||
process_b_field(h, pkt);
|
||||
#if 0
|
||||
for (i=0; i<23; i++)
|
||||
printf("%.2x ", pkt[i]);
|
||||
printf("\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void play()
|
||||
{
|
||||
int ret;
|
||||
ret = pcap_loop(
|
||||
fi.p,
|
||||
-1, /* forever */
|
||||
process_pcap_packet,
|
||||
"beckstein");
|
||||
fprintf(stderr, "pcap_loop() = %d\n", ret);
|
||||
if (*errbuf)
|
||||
fprintf(stderr, "pcap error: %s\n", errbuf);
|
||||
}
|
||||
|
||||
void shutdown()
|
||||
{
|
||||
pcap_close(fi.p);
|
||||
close(fi.fpp);
|
||||
close(fi.ffp);
|
||||
}
|
||||
|
||||
int main(int argc, char ** argv)
|
||||
{
|
||||
if (argc != 2)
|
||||
{
|
||||
usage();
|
||||
exit(1);
|
||||
}
|
||||
init(argv[1]);
|
||||
play();
|
||||
shutdown();
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* pcapstein dumps all B-Fields found in a pcap file
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* authors:
|
||||
* (C) 2008 Andreas Schuler <krater at badterrorist dot com>
|
||||
* (C) 2008 Matthias Wenzel <dect at mazzoo dot de>
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PCAPSTEIN_H
|
||||
#define PCAPSTEIN_H
|
||||
|
||||
struct file_info
|
||||
{
|
||||
pcap_t * p;
|
||||
struct pcap_pkthdr rec; /* walks through all packets */
|
||||
|
||||
int fpp; /* filehandle to PP .ima file */
|
||||
int ffp; /* filehandle to FP .ima file */
|
||||
};
|
||||
|
||||
char errbuf[PCAP_ERRBUF_SIZE];
|
||||
|
||||
#define ETH_TYPE_0_OFF 0x0c
|
||||
#define ETH_TYPE_1_OFF 0x0d
|
||||
#define ETH_TYPE_0 0x23
|
||||
#define ETH_TYPE_1 0x23
|
||||
|
||||
#define PKT_OFF_H 0x19
|
||||
#define PKT_OFF_TAIL 0x1a
|
||||
#define PKT_OFF_R_CRC 0x1f
|
||||
#define PKT_OFF_B_FIELD 0x21
|
||||
|
||||
#define DECT_H_BA_MASK 0x0e
|
||||
#define DECT_H_BA_NO_B_FIELD 0x0e
|
||||
#define DECT_H_BA_HALF_SLOT 0x08
|
||||
#define DECT_H_BA_DOUBLE_SLOT 0x04
|
||||
|
||||
|
||||
#endif /* PCAPSTEIN_H */
|
Loading…
Reference in New Issue