Compare commits
82 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fdca6f36de | ||
|
|
02f6b4e7bd | ||
|
|
701ed41adf | ||
|
|
03b3ce1a10 | ||
|
|
2c4373972b | ||
|
|
2ecf700dd8 | ||
|
|
74e949c33a | ||
|
|
3efa9d8cd1 | ||
|
|
4cd09feb54 | ||
|
|
1f024713ed | ||
|
|
0b499d9566 | ||
|
|
438b2a36b3 | ||
|
|
be94aa11bb | ||
|
|
1add33efe7 | ||
|
|
094e30483d | ||
|
|
e4ea886ee0 | ||
|
|
860eb4ab48 | ||
|
|
47dcc9377c | ||
|
|
f10eb3f547 | ||
|
|
99de304d84 | ||
|
|
c49a56c954 | ||
|
|
e6b16eace1 | ||
|
|
3933ffd350 | ||
|
|
05bf6ac601 | ||
|
|
d536c3e203 | ||
|
|
2e7acd212e | ||
|
|
71c003ba49 | ||
|
|
3707ee713e | ||
|
|
f5d3b35d7b | ||
|
|
6bcc70a421 | ||
|
|
d389f9f743 | ||
|
|
0faac26dde | ||
|
|
d803fad133 | ||
|
|
acfec5dfbb | ||
|
|
5ec9d756aa | ||
|
|
4bfdd8bea5 | ||
|
|
c0d52a04cb | ||
|
|
1cf7d9b08c | ||
|
|
3a0905b1ec | ||
|
|
4a75f58156 | ||
|
|
2b20289cb7 | ||
|
|
dd944f3362 | ||
|
|
d8fe2af23d | ||
|
|
35e9924b3c | ||
|
|
a9c85de700 | ||
|
|
7a822db82c | ||
|
|
007ff90025 | ||
|
|
be25fdb6fa | ||
|
|
06daf6c270 | ||
|
|
1672e07deb | ||
|
|
7b578b83b9 | ||
|
|
1ab5723b85 | ||
|
|
cbad5a7ae1 | ||
|
|
b3c6320374 | ||
|
|
69a716af1a | ||
|
|
eed2e4e00b | ||
|
|
466acea7e0 | ||
|
|
3134b36d7e | ||
|
|
4707e19654 | ||
|
|
e42548f2c5 | ||
|
|
abe35059bc | ||
|
|
348f6ab030 | ||
|
|
26efcf6902 | ||
|
|
a648cef0f6 | ||
|
|
a5a52dbe94 | ||
|
|
43ad3eeb65 | ||
|
|
706dc43483 | ||
|
|
92f1e46b8f | ||
|
|
abb09a012d | ||
|
|
7405dd6038 | ||
|
|
496f817773 | ||
|
|
4a6ecbbdeb | ||
|
|
bd0366287e | ||
|
|
f287c0af7f | ||
|
|
7adc74512e | ||
|
|
b993d25c5a | ||
|
|
41ae90a8a3 | ||
|
|
d4c8eb47ac | ||
|
|
2bd36a3307 | ||
|
|
600dd03e30 | ||
|
|
3d1d87e526 | ||
|
|
745118acb9 |
9
.gitignore
vendored
9
.gitignore
vendored
@@ -5,6 +5,7 @@
|
||||
*.mod
|
||||
*.mod.[oc]
|
||||
*.ko
|
||||
*.ko.unsigned
|
||||
*.cmd
|
||||
*.order
|
||||
*.tar.gz
|
||||
@@ -38,4 +39,12 @@ drivers/dahdi/firmware/dahdi-fw-oct6114-256.bin
|
||||
drivers/dahdi/firmware/dahdi-fw-tc400m.bin
|
||||
drivers/dahdi/firmware/dahdi-fw-te820.bin
|
||||
drivers/dahdi/firmware/dahdi-fw-vpmoct032.bin
|
||||
drivers/dahdi/firmware/dahdi-fw-a4a.bin
|
||||
drivers/dahdi/firmware/dahdi-fw-a4b.bin
|
||||
drivers/dahdi/firmware/dahdi-fw-a8a.bin
|
||||
drivers/dahdi/firmware/dahdi-fw-a8b.bin
|
||||
drivers/dahdi/firmware/dahdi-fw-oct6114-032.bin
|
||||
drivers/dahdi/firmware/dahdi-fw-te133.bin
|
||||
drivers/dahdi/firmware/dahdi-fw-te134.bin
|
||||
drivers/dahdi/firmware/dahdi-fw-te435.bin
|
||||
drivers/dahdi/firmware/make_firmware_object
|
||||
|
||||
28
Makefile
28
Makefile
@@ -47,8 +47,6 @@ ifeq (yes,$(HAS_KSRC))
|
||||
HOTPLUG_FIRMWARE:=$(shell if grep -q '^CONFIG_FW_LOADER=[ym]' $(KCONFIG); then echo "yes"; else echo "no"; fi)
|
||||
endif
|
||||
|
||||
UDEV_DIR:=/etc/udev/rules.d
|
||||
|
||||
MODULE_ALIASES:=wcfxs wctdm8xxp wct2xxp
|
||||
|
||||
INST_HEADERS:=kernel.h user.h fasthdlc.h wctdm_user.h dahdi_config.h
|
||||
@@ -82,12 +80,12 @@ include/dahdi/version.h: FORCE
|
||||
fi
|
||||
@rm -f $@.tmp
|
||||
|
||||
prereq: include/dahdi/version.h firmware-loaders oct612x-lib
|
||||
prereq: include/dahdi/version.h firmware-loaders
|
||||
|
||||
stackcheck: $(CHECKSTACK) modules
|
||||
objdump -d drivers/dahdi/*.ko drivers/dahdi/*/*.ko | $(CHECKSTACK)
|
||||
|
||||
install: all install-modules install-devices install-include install-firmware install-xpp-firm
|
||||
install: all install-modules install-include install-firmware install-xpp-firm
|
||||
@echo "###################################################"
|
||||
@echo "###"
|
||||
@echo "### DAHDI installed successfully."
|
||||
@@ -96,7 +94,7 @@ install: all install-modules install-devices install-include install-firmware in
|
||||
@echo "###"
|
||||
@echo "###################################################"
|
||||
|
||||
uninstall: uninstall-modules uninstall-devices uninstall-include uninstall-firmware
|
||||
uninstall: uninstall-modules uninstall-include uninstall-firmware
|
||||
|
||||
install-modconf:
|
||||
build_tools/genmodconf $(BUILDVER) "$(ROOT_PREFIX)" "$(filter-out dahdi dahdi_dummy xpp dahdi_transcode dahdi_dynamic,$(BUILD_MODULES)) $(MODULE_ALIASES)"
|
||||
@@ -118,13 +116,6 @@ uninstall-firmware:
|
||||
firmware-loaders:
|
||||
$(MAKE) -C drivers/dahdi/firmware firmware-loaders
|
||||
|
||||
oct612x-lib:
|
||||
ifeq (no,$(HAS_KSRC))
|
||||
@echo "You do not appear to have the sources for the $(KVERS) kernel installed."
|
||||
@exit 1
|
||||
endif
|
||||
$(MAKE) -C $(KSRC) M='$(PWD)/drivers/dahdi/oct612x'
|
||||
|
||||
install-include:
|
||||
for hdr in $(INST_HEADERS); do \
|
||||
install -D -m 644 include/dahdi/$$hdr $(DESTDIR)/usr/include/dahdi/$$hdr; \
|
||||
@@ -137,14 +128,6 @@ uninstall-include:
|
||||
done
|
||||
-rmdir $(DESTDIR)/usr/include/dahdi
|
||||
|
||||
install-devices:
|
||||
install -d $(DESTDIR)$(UDEV_DIR)
|
||||
build_tools/genudevrules > $(DESTDIR)$(UDEV_DIR)/dahdi.rules
|
||||
install -m 644 drivers/dahdi/xpp/xpp.rules $(DESTDIR)$(UDEV_DIR)/
|
||||
|
||||
uninstall-devices:
|
||||
rm -f $(DESTDIR)$(UDEV_DIR)/dahdi.rules
|
||||
|
||||
install-modules: modules
|
||||
ifndef DESTDIR
|
||||
@if modinfo zaptel > /dev/null 2>&1; then \
|
||||
@@ -186,6 +169,9 @@ update:
|
||||
echo "Not under version control"; \
|
||||
fi
|
||||
|
||||
dist:
|
||||
@./build_tools/make_dist "dahdi-linux" "$(DAHDIVERSION)"
|
||||
|
||||
clean:
|
||||
ifneq (no,$(HAS_KSRC))
|
||||
$(KMAKE) clean
|
||||
@@ -215,6 +201,6 @@ README.html: README
|
||||
dahdi-api.html: drivers/dahdi/dahdi-base.c
|
||||
build_tools/kernel-doc --kernel $(KSRC) $^ >$@
|
||||
|
||||
.PHONY: distclean dist-clean clean all install devices modules stackcheck install-udev update install-modules install-include uninstall-modules firmware-download install-xpp-firm firmware-loaders
|
||||
.PHONY: distclean dist-clean clean all install devices modules stackcheck install-udev update install-modules install-include uninstall-modules firmware-download install-xpp-firm firmware-loaders dist
|
||||
|
||||
FORCE:
|
||||
|
||||
43
README
43
README
@@ -528,16 +528,26 @@ XPP (Astribank) module parameters
|
||||
==== dahdi_autoreg
|
||||
(xpp)
|
||||
|
||||
Register spans automatically (1) or not (0). Default: 0.
|
||||
Setting it simplifies operations with a single Astribank and no other
|
||||
DAHDI hardware. However if you have such systems, automatic
|
||||
registration can cause the order of spans to be unpredictable.
|
||||
The standard startup scripts use 'dahdi_registration on' instead of this.
|
||||
Deprecated. See dahdi.<<_auto_assign_spans,auto_assign_spans>> above.
|
||||
|
||||
Originally had a somewhat similar (but xpp-specific and more limited)
|
||||
role to auto_assign_spans. For backward compatibility this variable is
|
||||
still kept, but its value is unused. Astribanks will auto-register
|
||||
with dahdi if auto_assign_spans is not set.
|
||||
|
||||
==== tools_rootdir
|
||||
(xpp)
|
||||
|
||||
Defaults to /. Passed (as the variable DAHDI_TOOLS_ROOTDIR) to generated
|
||||
events (which can be used in udev hooks). Also serves as the base of
|
||||
the variable DAHDI_INIT_DIR (by default: $DAHDI_TOOLS_DIR/usr/share/dahdi).
|
||||
|
||||
==== initdir
|
||||
(xpp)
|
||||
|
||||
This is the directory containing the initialization scripts.
|
||||
Deprecated. Setting both initdir and tools_rootdir will generate an error.
|
||||
|
||||
A directory under tools_rootdir containing the initialization scripts.
|
||||
The default is /usr/share/dahdi .
|
||||
Setting this value could be useful if that location is inconvenient for you.
|
||||
|
||||
@@ -887,11 +897,12 @@ to other nodes.
|
||||
|
||||
Class DAHDI
|
||||
^^^^^^^^^^^
|
||||
under /sys/class/dadhi there exists a node for each DAHDI device file
|
||||
under /dev/dahdi. The name is 'dahdi!foo' for the file '/dev/dahdi/foo'
|
||||
(udev translates exclamation marks to slashes). Those nodes are not, for
|
||||
the most part, proper SysFS nodes, and don't include any interesting
|
||||
properties.
|
||||
Under /sys/class/dadhi there exists a node for the non-channel DAHDI
|
||||
device file under /dev/dahdi. The name is 'dahdi!foo' for the file
|
||||
'/dev/dahdi/foo' (udev translates exclamation marks to slashes). Those
|
||||
nodes are not, for the most part, proper SysFS nodes, and don't include
|
||||
any interesting properties. The files in this class `ctl`, `timer`,
|
||||
`channel`, `pseudo` and (if exists) `transcode`.
|
||||
|
||||
|
||||
Devices Bus
|
||||
@@ -916,6 +927,10 @@ A unique hardware-level identifier (e.g. serial number), if available.
|
||||
===== /sys/bus/dahdi_devices/devices/DEVICE/manufacturer
|
||||
The name of the manufacturer. Freeform-string.
|
||||
|
||||
===== /sys/bus/dahdi_devices/devices/DEVICE/registration_time
|
||||
The time at which the device registered with the DAHDI core. Example
|
||||
value: "0005634136.941901429".
|
||||
|
||||
===== /sys/bus/dahdi_devices/devices/DEVICE/spantype
|
||||
A line for each available span: <num>:<type>. This has to be provided
|
||||
here as in the case of manual assignment, userspace may need to know
|
||||
@@ -980,6 +995,12 @@ A very short type string.
|
||||
===== /sys/bus/dahdi_spans/devices/span-N/syncsrc
|
||||
Current sync source.
|
||||
|
||||
==== sys/bus/dahdi_spans/drivers/generic_lowlevel/master_span
|
||||
All spans in the bus are handled by a single driver. The driver has one
|
||||
non-standard attribute: master_span. printing it shows the current DAHDI
|
||||
master span writing a number to it forces setting this span as the master
|
||||
span.
|
||||
|
||||
|
||||
Channels Bus
|
||||
^^^^^^^^^^^^
|
||||
|
||||
123
build_tools/dkms-helper
Executable file
123
build_tools/dkms-helper
Executable file
@@ -0,0 +1,123 @@
|
||||
#!/bin/sh
|
||||
|
||||
set -e
|
||||
|
||||
DKMS=$(which dkms)
|
||||
|
||||
usage() {
|
||||
echo "$(basename $0): Helper functions for DKMS (Dynamic Kernel Module Support)"
|
||||
echo "Usage: $0 [add|remove|generate_conf]"
|
||||
echo "Options:"
|
||||
echo " remove -a : Remove all versions of DAHDI for all kernels."
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo ""
|
||||
echo " build_tools/dkms-helper add"
|
||||
echo " Installs the current version of DAHDI into the DKMS system."
|
||||
echo ""
|
||||
echo " build_tools/dkms-helper remove"
|
||||
echo " Removes the current version of DAHDI from all kernels."
|
||||
echo ""
|
||||
echo " build_tools/dkms-helper generate_conf > dkms.conf"
|
||||
echo " Create a dkms.conf based on the currently compiled kernel"
|
||||
echo " modules. This is also done as part of add and is not"
|
||||
echo " normally needed as a separate step."
|
||||
echo ""
|
||||
echo "NOTE: Because firmware files could be different between different"
|
||||
echo "versions of DAHDI, and the firmware files are installed into the common"
|
||||
echo "/lib/firmware directory, you should remove a given version of DAHDI from all"
|
||||
echo "kernels before installing a new version of DAHDI to avoid potential"
|
||||
echo "conflicts."
|
||||
echo ""
|
||||
}
|
||||
|
||||
generate_configuration() {
|
||||
echo 'PACKAGE_NAME="dahdi-linux"'
|
||||
echo "PACKAGE_VERSION=\"$(build_tools/make_version .)\""
|
||||
echo 'MAKE="make KSRC=/lib/modules/${kernelver}/build"'
|
||||
echo 'CLEAN="make clean"'
|
||||
echo 'AUTOINSTALL="yes"'
|
||||
let "module_number=0" || true
|
||||
for file in $(find ./ -type f -name "*.ko"); do
|
||||
MODULE_LOCATION=$(dirname $file | cut -d\/ -f 2-)
|
||||
echo "BUILT_MODULE_NAME[$module_number]=\"$(basename $file .ko)\""
|
||||
echo "BUILT_MODULE_LOCATION[$module_number]=\"$MODULE_LOCATION\""
|
||||
echo "DEST_MODULE_LOCATION[$module_number]=\"/kernel/dahdi/$(echo $MODULE_LOCATION | cut -d\/ -f 3-)\""
|
||||
let "module_number=${module_number}+1" || true
|
||||
done
|
||||
if [ $module_number -eq 0 ]; then
|
||||
echo "WARNING: You should build the modules before generating a config." >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
add() {
|
||||
GIT=$(which git)
|
||||
VERSION="$(build_tools/make_version .)"
|
||||
if [ $(id -u) != "0" ]; then
|
||||
echo "You must run $0 as root."
|
||||
exit 1
|
||||
fi
|
||||
echo "Building for version ${VERSION}"
|
||||
make > /dev/null
|
||||
echo "Copying to /usr/src/dahdi-linux-${VERSION}"
|
||||
if [ ! -d /usr/src/dahdi-linux-${VERSION} ]; then
|
||||
if [ -d .git ]; then
|
||||
${GIT} checkout-index -a --prefix=/usr/src/dahdi-linux-${VERSION}/
|
||||
else
|
||||
cp -f -r * /usr/src/dahdi-linux-${VERSION}/
|
||||
fi
|
||||
fi
|
||||
make -C /usr/src/dahdi-linux-${VERSION} install-firmware firmware-loaders
|
||||
build_tools/dkms-helper generate_conf > /usr/src/dahdi-linux-${VERSION}/dkms.conf
|
||||
echo $VERSION > /usr/src/dahdi-linux-${VERSION}/.version
|
||||
${DKMS} add -m dahdi-linux -v ${VERSION}
|
||||
${DKMS} build -m dahdi-linux -v ${VERSION}
|
||||
${DKMS} install --force -m dahdi-linux -v ${VERSION}
|
||||
}
|
||||
|
||||
remove() {
|
||||
if [ $(id -u) != "0" ]; then
|
||||
echo "You must run $0 as root."
|
||||
exit 1
|
||||
fi
|
||||
REMOVE_ALL=false
|
||||
shift
|
||||
while getopts "a" opt; do
|
||||
case $opt in
|
||||
a) REMOVE_ALL=true ;;
|
||||
*) echo "Unknown option to remove" ; exit 1;;
|
||||
esac
|
||||
done
|
||||
if [ $REMOVE_ALL == true ]; then
|
||||
# Remove all installed dahdi versions for all kernels.
|
||||
for version in $(${DKMS} status -m dahdi-linux | cut -d, -f 2 | sed -e "s/^\s\+//"); do
|
||||
echo "Removing version ${version}"
|
||||
${DKMS} remove -m dahdi-linux -v ${version} --all
|
||||
rm -f -r /usr/src/dahdi-linux-${version}
|
||||
done
|
||||
else
|
||||
# Just remove the version for the current tree.
|
||||
GIT=$(which git)
|
||||
VERSION="$(build_tools/make_version .)"
|
||||
${DKMS} remove -m dahdi-linux -v ${VERSION} --all
|
||||
if [ -e /usr/src/dahdi-linux-${VERSION}/dkms.conf ]; then
|
||||
rm -f -r /usr/src/dahdi-linux-${VERSION}
|
||||
else
|
||||
echo "/usr/src/dahdi-linux-${VERSION} not a dkms dir?"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Run the command...
|
||||
shift $(($OPTIND-1))
|
||||
COMMAND=$1
|
||||
case $COMMAND in
|
||||
add) add $*; exit $? ;;
|
||||
remove) remove $* ; exit $? ;;
|
||||
generate_conf) generate_configuration; exit $? ;;
|
||||
*) echo "unknown command $0" ; usage; exit 1;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
@@ -1,40 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
ver=`udevinfo -V | cut -f3 -d" "`
|
||||
|
||||
if [ -z "${ver}" ]; then
|
||||
# Not found - try udevadm
|
||||
ver=`udevadm info -V | cut -f3 -d" "`
|
||||
|
||||
if [ -z "${ver}" ]; then
|
||||
# nobody has that old version, anyway.
|
||||
ver=54
|
||||
fi
|
||||
fi
|
||||
|
||||
# udev versions prior to 055 use a single '=' for matching key values
|
||||
# udev versions 055 and later support '==' for that purpose, and versions
|
||||
# beyond 092 will probably make it mandatory
|
||||
#
|
||||
# very old versions of udev required naming rules and permissions rules to be
|
||||
# in separate files, but it's not clear at what version number that changed
|
||||
|
||||
if [ ${ver} -gt 54 ]; then
|
||||
match="=="
|
||||
else
|
||||
match="="
|
||||
fi
|
||||
|
||||
cat <<EOF
|
||||
# udev rules to generate the /dev/dahdi device files (if not yet provided
|
||||
# by your distribution):
|
||||
KERNEL${match}"dahdictl", NAME="dahdi/ctl"
|
||||
KERNEL${match}"dahditranscode", NAME="dahdi/transcode"
|
||||
KERNEL${match}"dahditimer", NAME="dahdi/timer"
|
||||
KERNEL${match}"dahdichannel", NAME="dahdi/channel"
|
||||
KERNEL${match}"dahdipseudo", NAME="dahdi/pseudo"
|
||||
KERNEL${match}"dahdi[0-9]*", NAME="dahdi/%n"
|
||||
|
||||
# DAHDI devices with ownership/permissions for running as non-root
|
||||
SUBSYSTEM${match}"dahdi", OWNER="asterisk", GROUP="asterisk", MODE="0660"
|
||||
EOF
|
||||
@@ -61,7 +61,7 @@ export ASTRIBANK_HEXLOAD
|
||||
|
||||
# make sure Astribank initialization scripts are from our tree.
|
||||
xpp_ARGS="$xpp_ARGS initdir=$FIRMWARE_DIR"
|
||||
#dahdi_ARGS="$dahdi_ARGS initdir=$FIRMWARE_DIR"
|
||||
dahdi_ARGS="$dahdi_ARGS tools_rootdir=$DESTDIR"
|
||||
|
||||
if [ "$DYNAMIC_LOC" = 'yes' ]; then
|
||||
MODULES_LOAD="$MODULES_LOAD dahdi_dynamic dahdi_dynamic_loc"
|
||||
|
||||
26
build_tools/make_dist
Executable file
26
build_tools/make_dist
Executable file
@@ -0,0 +1,26 @@
|
||||
#! /bin/sh
|
||||
|
||||
if [ "$#" -ne 2 ]; then
|
||||
echo >&2 "Usage: $0 <package> <version>"
|
||||
exit 1
|
||||
fi
|
||||
package="$1"
|
||||
version="$2"
|
||||
tarball_prefix="$package-$version"
|
||||
echo "I: Making dist tarball for $tarball_prefix"
|
||||
tarball_name="$tarball_prefix.tar.gz"
|
||||
|
||||
tmp_work_dir=".tmp"
|
||||
tmp_version_dir="$tmp_work_dir/$tarball_prefix"
|
||||
|
||||
if [ "$DESTDIR" != '' ]; then
|
||||
destdir="$DESTDIR/"
|
||||
fi
|
||||
output="$destdir$tarball_name"
|
||||
|
||||
mkdir -p "$tmp_version_dir"
|
||||
git archive --format tar HEAD | tar xf - -C "$tmp_version_dir"
|
||||
echo "$version" > "$tmp_version_dir/.version"
|
||||
tar czf "$output" -C "$tmp_work_dir" "$tarball_prefix"
|
||||
rm -rf "$tmp_work_dir"
|
||||
echo "I: tarball is ready: '$output'"
|
||||
@@ -7,18 +7,35 @@ obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_DYNAMIC_ETHMF) += dahdi_dynamic_ethmf.o
|
||||
obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_TRANSCODE) += dahdi_transcode.o
|
||||
|
||||
ifdef CONFIG_PCI
|
||||
obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_OCT612X) += oct612x/
|
||||
obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCT4XXP) += wct4xxp/
|
||||
obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTC4XXP) += wctc4xxp/
|
||||
obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTDM24XXP) += wctdm24xxp/
|
||||
obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTE12XP) += wcte12xp/
|
||||
obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTE13XP) += wcte13xp.o
|
||||
|
||||
wcte13xp-objs := wcte13xp-base.o oct612x/lib.a
|
||||
CFLAGS_wcte13xp-base.o += -I$(src)/oct612x/include -I$(src)/oct612x/octdeviceapi -I$(src)/oct612x/octdeviceapi/oct6100api
|
||||
wcte13xp-objs := wcte13xp-base.o wcxb_spi.o wcxb.o wcxb_flash.o
|
||||
CFLAGS_wcte13xp-base.o += -I$(src)/oct612x -I$(src)/oct612x/include -I$(src)/oct612x/octdeviceapi -I$(src)/oct612x/octdeviceapi/oct6100api
|
||||
ifeq ($(HOTPLUG_FIRMWARE),yes)
|
||||
CFLAGS_wcte13xp-base.o += -DHOTPLUG_FIRMWARE
|
||||
endif
|
||||
|
||||
obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTE43X) += wcte43x.o
|
||||
|
||||
wcte43x-objs := wcte43x-base.o wcxb_spi.o wcxb.o wcxb_flash.o
|
||||
CFLAGS_wcte43x-base.o += -I$(src)/oct612x -I$(src)/oct612x/include -I$(src)/oct612x/octdeviceapi -I$(src)/oct612x/octdeviceapi/oct6100api
|
||||
ifeq ($(HOTPLUG_FIRMWARE),yes)
|
||||
CFLAGS_wcte43x-base.o += -DHOTPLUG_FIRMWARE
|
||||
endif
|
||||
|
||||
obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCAXX) += wcaxx.o
|
||||
|
||||
wcaxx-objs := wcaxx-base.o wcxb_spi.o wcxb.o wcxb_flash.o
|
||||
CFLAGS_wcaxx-base.o += -I$(src)/oct612x/ -I$(src)/oct612x/include -I$(src)/oct612x/octdeviceapi -I$(src)/oct612x/octdeviceapi/oct6100api
|
||||
ifeq ($(HOTPLUG_FIRMWARE),yes)
|
||||
CFLAGS_wcaxx-base.o += -DHOTPLUG_FIRMWARE
|
||||
endif
|
||||
|
||||
obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCTDM) += wctdm.o
|
||||
obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_VOICEBUS) += voicebus/
|
||||
obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCB4XXP) += wcb4xxp/
|
||||
|
||||
@@ -50,6 +50,7 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/ktime.h>
|
||||
|
||||
#if defined(HAVE_UNLOCKED_IOCTL) && defined(CONFIG_BKL)
|
||||
#include <linux/smp_lock.h>
|
||||
@@ -173,7 +174,7 @@ static sumtype *conf_sums_next;
|
||||
static sumtype *conf_sums;
|
||||
static sumtype *conf_sums_prev;
|
||||
|
||||
static struct dahdi_span *master;
|
||||
static struct dahdi_span *master_span;
|
||||
struct file_operations *dahdi_transcode_fops = NULL;
|
||||
|
||||
|
||||
@@ -611,7 +612,7 @@ void dahdi_unregister_echocan_factory(const struct dahdi_echocan_factory *ec)
|
||||
/* Is this span our syncronization master? */
|
||||
int dahdi_is_sync_master(const struct dahdi_span *span)
|
||||
{
|
||||
return span == master;
|
||||
return span == master_span;
|
||||
}
|
||||
|
||||
static inline void rotate_sums(void)
|
||||
@@ -732,6 +733,8 @@ enum spantypes dahdi_str2spantype(const char *name)
|
||||
return SPANTYPE_DIGITAL_BRI_TE;
|
||||
else if (strcasecmp("BRI_SOFT", name) == 0)
|
||||
return SPANTYPE_DIGITAL_BRI_SOFT;
|
||||
else if (strcasecmp("DYNAMIC", name) == 0)
|
||||
return SPANTYPE_DIGITAL_DYNAMIC;
|
||||
else
|
||||
return SPANTYPE_INVALID;
|
||||
}
|
||||
@@ -749,6 +752,7 @@ const char *dahdi_spantype2str(enum spantypes st)
|
||||
case SPANTYPE_DIGITAL_BRI_NT: return "BRI_NT";
|
||||
case SPANTYPE_DIGITAL_BRI_TE: return "BRI_TE";
|
||||
case SPANTYPE_DIGITAL_BRI_SOFT: return "BRI_SOFT";
|
||||
case SPANTYPE_DIGITAL_DYNAMIC: return "DYNAMIC";
|
||||
default:
|
||||
case SPANTYPE_INVALID: return "INVALID";
|
||||
};
|
||||
@@ -787,6 +791,7 @@ ssize_t lineconfig_str(int lineconfig, char buf[], size_t size)
|
||||
int crc4_bit = 0;
|
||||
int len = 0;
|
||||
int bit;
|
||||
bool written = false;
|
||||
|
||||
for (bit = 4; bit <= 12; bit++) {
|
||||
int mask = (1 << bit);
|
||||
@@ -798,8 +803,10 @@ ssize_t lineconfig_str(int lineconfig, char buf[], size_t size)
|
||||
case DAHDI_CONFIG_AMI:
|
||||
case DAHDI_CONFIG_HDB3:
|
||||
framing_bit = bit;
|
||||
len += snprintf(buf + len, size, "%s/",
|
||||
len += snprintf(buf + len, size, "%s%s",
|
||||
(written) ? "/" : "",
|
||||
dahdi_lineconfig_bit_name(bit));
|
||||
written = true;
|
||||
}
|
||||
}
|
||||
if (!coding_bit) {
|
||||
@@ -808,14 +815,18 @@ ssize_t lineconfig_str(int lineconfig, char buf[], size_t size)
|
||||
case DAHDI_CONFIG_D4:
|
||||
case DAHDI_CONFIG_CCS:
|
||||
coding_bit = bit;
|
||||
len += snprintf(buf + len, size, "%s",
|
||||
len += snprintf(buf + len, size, "%s%s",
|
||||
(written) ? "/" : "",
|
||||
dahdi_lineconfig_bit_name(bit));
|
||||
written = true;
|
||||
}
|
||||
}
|
||||
if (!crc4_bit && mask == DAHDI_CONFIG_CRC4) {
|
||||
crc4_bit = bit;
|
||||
len += snprintf(buf + len, size, "/%s",
|
||||
len += snprintf(buf + len, size, "%s%s",
|
||||
(written) ? "/" : "",
|
||||
dahdi_lineconfig_bit_name(bit));
|
||||
written = true;
|
||||
}
|
||||
}
|
||||
return len;
|
||||
@@ -3833,6 +3844,31 @@ void dahdi_alarm_channel(struct dahdi_chan *chan, int alarms)
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
}
|
||||
|
||||
struct dahdi_span *get_master_span(void)
|
||||
{
|
||||
return master_span;
|
||||
}
|
||||
|
||||
void set_master_span(int spanno)
|
||||
{
|
||||
struct dahdi_span *s;
|
||||
unsigned long flags;
|
||||
struct dahdi_span *old_master;
|
||||
|
||||
spin_lock_irqsave(&chan_lock, flags);
|
||||
old_master = master_span;
|
||||
list_for_each_entry(s, &span_list, spans_node) {
|
||||
if (spanno == s->spanno) {
|
||||
master_span = s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&chan_lock, flags);
|
||||
if ((debug & DEBUG_MAIN) && (old_master != master_span))
|
||||
module_printk(KERN_NOTICE, "Master span is set to %d (%s)\n",
|
||||
master_span->spanno, master_span->name);
|
||||
}
|
||||
|
||||
static void __dahdi_find_master_span(void)
|
||||
{
|
||||
struct dahdi_span *s;
|
||||
@@ -3840,7 +3876,7 @@ static void __dahdi_find_master_span(void)
|
||||
struct dahdi_span *old_master;
|
||||
|
||||
spin_lock_irqsave(&chan_lock, flags);
|
||||
old_master = master;
|
||||
old_master = master_span;
|
||||
list_for_each_entry(s, &span_list, spans_node) {
|
||||
if (s->alarms && old_master)
|
||||
continue;
|
||||
@@ -3850,15 +3886,15 @@ static void __dahdi_find_master_span(void)
|
||||
continue;
|
||||
if (!can_provide_timing(s))
|
||||
continue;
|
||||
if (master == s)
|
||||
if (master_span == s)
|
||||
continue;
|
||||
|
||||
master = s;
|
||||
master_span = s;
|
||||
break;
|
||||
}
|
||||
spin_unlock_irqrestore(&chan_lock, flags);
|
||||
|
||||
if ((debug & DEBUG_MAIN) && (old_master != master))
|
||||
if ((debug & DEBUG_MAIN) && (old_master != master_span))
|
||||
module_printk(KERN_NOTICE, "Master changed to %s\n", s->name);
|
||||
}
|
||||
|
||||
@@ -3899,7 +3935,7 @@ void dahdi_alarm_notify(struct dahdi_span *span)
|
||||
dahdi_alarm_channel(span->chans[x], span->alarms);
|
||||
|
||||
/* If we're going into or out of alarm we should try to find a
|
||||
* new master that may be a better fit. */
|
||||
* new master_span that may be a better fit. */
|
||||
dahdi_find_master_span();
|
||||
|
||||
/* Report more detailed alarms */
|
||||
@@ -5129,7 +5165,7 @@ static int dahdi_ioctl_startup(struct file *file, unsigned long data)
|
||||
}
|
||||
|
||||
/* Now that this span is running, it might be selected as the
|
||||
* master span */
|
||||
* master_span */
|
||||
__dahdi_find_master_span();
|
||||
}
|
||||
put_span(s);
|
||||
@@ -7194,7 +7230,7 @@ EXPORT_SYMBOL(dahdi_init_span);
|
||||
* @spanno: The span number we would like assigned. If 0, the first
|
||||
* available spanno/basechan will be used.
|
||||
* @basechan: The base channel number we would like. Ignored if spanno is 0.
|
||||
* @prefmaster: will the new span be preferred as a master?
|
||||
* @prefmaster: will the new span be preferred as a master_span?
|
||||
*
|
||||
* Assigns a span for usage with DAHDI. All the channel numbers in it will
|
||||
* have their numbering started at basechan.
|
||||
@@ -7213,6 +7249,7 @@ static int _dahdi_assign_span(struct dahdi_span *span, unsigned int spanno,
|
||||
{
|
||||
int res = 0;
|
||||
unsigned int x;
|
||||
unsigned long flags;
|
||||
|
||||
if (!span || !span->ops || !span->ops->owner)
|
||||
return -EFAULT;
|
||||
@@ -7224,6 +7261,16 @@ static int _dahdi_assign_span(struct dahdi_span *span, unsigned int spanno,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* DAHDI_ALARM_NOTOPEN can be set when a span is disabled, i.e. via
|
||||
* sysfs, so when the span is being reassigned we should make sure it's
|
||||
* cleared. This eliminates the need for board drivers to re-report
|
||||
* their alarm states on span reassignment. */
|
||||
|
||||
spin_lock_irqsave(&span->lock, flags);
|
||||
span->alarms &= ~DAHDI_ALARM_NOTOPEN;
|
||||
dahdi_alarm_notify(span);
|
||||
spin_unlock_irqrestore(&span->lock, flags);
|
||||
|
||||
if (span->ops->enable_hw_preechocan ||
|
||||
span->ops->disable_hw_preechocan) {
|
||||
if ((NULL == span->ops->enable_hw_preechocan) ||
|
||||
@@ -7327,7 +7374,8 @@ int dahdi_assign_device_spans(struct dahdi_device *ddev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int auto_assign_spans = 1;
|
||||
int auto_assign_spans = 1;
|
||||
EXPORT_SYMBOL(auto_assign_spans);
|
||||
static const char *UNKNOWN = "";
|
||||
|
||||
/**
|
||||
@@ -7357,6 +7405,7 @@ static int _dahdi_register_device(struct dahdi_device *ddev,
|
||||
__dahdi_init_span(s);
|
||||
}
|
||||
|
||||
ktime_get_ts(&ddev->registration_time);
|
||||
ret = dahdi_sysfs_add_device(ddev, parent);
|
||||
if (ret)
|
||||
return ret;
|
||||
@@ -7472,8 +7521,8 @@ static int _dahdi_unassign_span(struct dahdi_span *span)
|
||||
for (x=0;x<span->channels;x++)
|
||||
dahdi_chan_unreg(span->chans[x]);
|
||||
|
||||
new_master = master; /* FIXME: locking */
|
||||
if (master == span)
|
||||
new_master = master_span; /* FIXME: locking */
|
||||
if (master_span == span)
|
||||
new_master = NULL;
|
||||
|
||||
spin_lock_irqsave(&chan_lock, flags);
|
||||
@@ -7484,13 +7533,13 @@ static int _dahdi_unassign_span(struct dahdi_span *span)
|
||||
break;
|
||||
}
|
||||
spin_unlock_irqrestore(&chan_lock, flags);
|
||||
if (master != new_master) {
|
||||
if (master_span != new_master) {
|
||||
if (debug & DEBUG_MAIN) {
|
||||
module_printk(KERN_NOTICE, "%s: Span ('%s') is new master\n", __FUNCTION__,
|
||||
(new_master)? new_master->name: "no master");
|
||||
}
|
||||
}
|
||||
master = new_master;
|
||||
master_span = new_master;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,8 +32,15 @@
|
||||
#include "dahdi-sysfs.h"
|
||||
|
||||
|
||||
static char *initdir = "/usr/share/dahdi";
|
||||
module_param(initdir, charp, 0644);
|
||||
static char *initdir;
|
||||
module_param(initdir, charp, 0444);
|
||||
MODULE_PARM_DESC(initdir,
|
||||
"deprecated, should use <tools_rootdir>/usr/share/dahdi");
|
||||
|
||||
static char *tools_rootdir;
|
||||
module_param(tools_rootdir, charp, 0444);
|
||||
MODULE_PARM_DESC(tools_rootdir,
|
||||
"root directory of all tools paths (default /)");
|
||||
|
||||
static int span_match(struct device *dev, struct device_driver *driver)
|
||||
{
|
||||
@@ -47,7 +54,9 @@ static inline struct dahdi_span *dev_to_span(struct device *dev)
|
||||
|
||||
#define SPAN_VAR_BLOCK \
|
||||
do { \
|
||||
DAHDI_ADD_UEVENT_VAR("DAHDI_INIT_DIR=%s", initdir); \
|
||||
DAHDI_ADD_UEVENT_VAR("DAHDI_TOOLS_ROOTDIR=%s", tools_rootdir); \
|
||||
DAHDI_ADD_UEVENT_VAR("DAHDI_INIT_DIR=%s/%s", tools_rootdir, \
|
||||
initdir); \
|
||||
DAHDI_ADD_UEVENT_VAR("SPAN_NUM=%d", span->spanno); \
|
||||
DAHDI_ADD_UEVENT_VAR("SPAN_NAME=%s", span->name); \
|
||||
} while (0)
|
||||
@@ -222,16 +231,51 @@ static struct device_attribute span_dev_attrs[] = {
|
||||
__ATTR_NULL,
|
||||
};
|
||||
|
||||
static ssize_t master_span_show(struct device_driver *driver, char *buf)
|
||||
{
|
||||
struct dahdi_span *s = get_master_span();
|
||||
|
||||
return snprintf(buf, PAGE_SIZE, "%d\n", (s) ? s->spanno : 0);
|
||||
}
|
||||
|
||||
static ssize_t master_span_store(struct device_driver *driver, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
int spanno;
|
||||
|
||||
if (sscanf(buf, "%d", &spanno) != 1) {
|
||||
module_printk(KERN_ERR, "non-numeric input '%s'\n", buf);
|
||||
return -EINVAL;
|
||||
}
|
||||
set_master_span(spanno);
|
||||
return count;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
|
||||
static struct driver_attribute dahdi_attrs[] = {
|
||||
__ATTR(master_span, S_IRUGO | S_IWUSR, master_span_show,
|
||||
master_span_store),
|
||||
__ATTR_NULL,
|
||||
};
|
||||
#else
|
||||
static DRIVER_ATTR_RW(master_span);
|
||||
static struct attribute *dahdi_attrs[] = {
|
||||
&driver_attr_master_span.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(dahdi);
|
||||
#endif
|
||||
|
||||
static struct bus_type spans_bus_type = {
|
||||
.name = "dahdi_spans",
|
||||
.match = span_match,
|
||||
.uevent = span_uevent,
|
||||
.dev_attrs = span_dev_attrs,
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
|
||||
.drv_attrs = dahdi_attrs,
|
||||
#else
|
||||
.drv_groups = dahdi_groups,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int span_probe(struct device *dev)
|
||||
@@ -296,6 +340,7 @@ void span_sysfs_remove(struct dahdi_span *span)
|
||||
|
||||
get_device(span_device);
|
||||
span_uevent_send(span, KOBJ_OFFLINE);
|
||||
sysfs_remove_link(&span_device->kobj, "ddev");
|
||||
device_unregister(span->span_device);
|
||||
dev_set_drvdata(span_device, NULL);
|
||||
span_device->parent = NULL;
|
||||
@@ -336,6 +381,15 @@ int span_sysfs_create(struct dahdi_span *span)
|
||||
span->span_device = NULL;
|
||||
goto cleanup;
|
||||
}
|
||||
res = sysfs_create_link(&span_device->kobj, &span_device->parent->kobj,
|
||||
"ddev");
|
||||
if (res) {
|
||||
span_err(span, "%s: sysfs_create_link failed: %d\n", __func__,
|
||||
res);
|
||||
kfree(span->span_device);
|
||||
span->span_device = NULL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
for (x = 0; x < span->channels; x++) {
|
||||
res = chan_sysfs_create(span->chans[x]);
|
||||
@@ -362,6 +416,71 @@ static inline struct dahdi_device *to_ddev(struct device *dev)
|
||||
return container_of(dev, struct dahdi_device, dev);
|
||||
}
|
||||
|
||||
#define DEVICE_VAR_BLOCK \
|
||||
do { \
|
||||
DAHDI_ADD_UEVENT_VAR("DAHDI_TOOLS_ROOTDIR=%s", tools_rootdir); \
|
||||
DAHDI_ADD_UEVENT_VAR("DAHDI_INIT_DIR=%s/%s", tools_rootdir, \
|
||||
initdir); \
|
||||
DAHDI_ADD_UEVENT_VAR("DAHDI_DEVICE_HWID=%s", \
|
||||
ddev->hardware_id); \
|
||||
DAHDI_ADD_UEVENT_VAR("DAHDI_DEVICE_LOCATION=%s", \
|
||||
ddev->location); \
|
||||
} while (0)
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
|
||||
#define DAHDI_ADD_UEVENT_VAR(fmt, val...) \
|
||||
do { \
|
||||
int err = add_uevent_var(envp, num_envp, &i, \
|
||||
buffer, buffer_size, &len, \
|
||||
fmt, val); \
|
||||
if (err) \
|
||||
return err; \
|
||||
} while (0)
|
||||
|
||||
static int device_uevent(struct device *dev, char **envp, int num_envp,
|
||||
char *buffer, int buffer_size)
|
||||
{
|
||||
struct dahdi_device *ddev;
|
||||
int i = 0;
|
||||
int len = 0;
|
||||
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
ddev = to_ddev(dev);
|
||||
if (!ddev)
|
||||
return -ENODEV;
|
||||
|
||||
dahdi_dbg(GENERAL, "SYFS dev_name=%s\n", dev_name(dev));
|
||||
DEVICE_VAR_BLOCK;
|
||||
envp[i] = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
#define DAHDI_ADD_UEVENT_VAR(fmt, val...) \
|
||||
do { \
|
||||
int err = add_uevent_var(kenv, fmt, val); \
|
||||
if (err) \
|
||||
return err; \
|
||||
} while (0)
|
||||
|
||||
static int device_uevent(struct device *dev, struct kobj_uevent_env *kenv)
|
||||
{
|
||||
struct dahdi_device *ddev;
|
||||
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
ddev = to_ddev(dev);
|
||||
if (!ddev)
|
||||
return -ENODEV;
|
||||
dahdi_dbg(GENERAL, "SYFS dev_name=%s\n", dev_name(dev));
|
||||
DEVICE_VAR_BLOCK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static ssize_t
|
||||
dahdi_device_manufacturer_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
@@ -402,6 +521,16 @@ dahdi_device_hardware_id_show(struct device *dev,
|
||||
(ddev->hardware_id) ? ddev->hardware_id : "");
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
dahdi_device_location_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct dahdi_device *ddev = to_ddev(dev);
|
||||
|
||||
return sprintf(buf, "%s\n",
|
||||
(ddev->location) ? ddev->location : "");
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
dahdi_device_auto_assign(struct device *dev, struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
@@ -500,7 +629,8 @@ dahdi_spantype_store(struct device *dev, struct device_attribute *attr,
|
||||
{
|
||||
struct dahdi_device *const ddev = to_ddev(dev);
|
||||
int ret;
|
||||
struct dahdi_span *span;
|
||||
struct dahdi_span *span = NULL;
|
||||
struct dahdi_span *cur;
|
||||
unsigned int local_span_number;
|
||||
char spantype_name[80];
|
||||
enum spantypes spantype;
|
||||
@@ -516,9 +646,18 @@ dahdi_spantype_store(struct device *dev, struct device_attribute *attr,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
list_for_each_entry(span, &ddev->spans, device_node) {
|
||||
if (local_spanno(span) == local_span_number)
|
||||
list_for_each_entry(cur, &ddev->spans, device_node) {
|
||||
if (local_spanno(cur) == local_span_number) {
|
||||
span = cur;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!span || (local_spanno(span) != local_span_number)) {
|
||||
module_printk(KERN_WARNING,
|
||||
"%d is not a valid local span number "
|
||||
"for this device.\n", local_span_number);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (test_bit(DAHDI_FLAGBIT_REGISTERED, &span->flags)) {
|
||||
@@ -527,12 +666,6 @@ dahdi_spantype_store(struct device *dev, struct device_attribute *attr,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (local_spanno(span) != local_span_number) {
|
||||
module_printk(KERN_WARNING,
|
||||
"%d is not a valid local span number "
|
||||
"for this device.\n", local_span_number);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (!span->ops->set_spantype) {
|
||||
module_printk(KERN_WARNING, "Span %s does not support "
|
||||
@@ -544,21 +677,37 @@ dahdi_spantype_store(struct device *dev, struct device_attribute *attr,
|
||||
return (ret < 0) ? ret : count;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
dahdi_registration_time_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct dahdi_device *ddev = to_ddev(dev);
|
||||
int count = 0;
|
||||
|
||||
count += sprintf(buf, "%010ld.%09ld\n",
|
||||
ddev->registration_time.tv_sec,
|
||||
ddev->registration_time.tv_nsec);
|
||||
return count;
|
||||
}
|
||||
|
||||
static struct device_attribute dahdi_device_attrs[] = {
|
||||
__ATTR(manufacturer, S_IRUGO, dahdi_device_manufacturer_show, NULL),
|
||||
__ATTR(type, S_IRUGO, dahdi_device_type_show, NULL),
|
||||
__ATTR(span_count, S_IRUGO, dahdi_device_span_count_show, NULL),
|
||||
__ATTR(hardware_id, S_IRUGO, dahdi_device_hardware_id_show, NULL),
|
||||
__ATTR(location, S_IRUGO, dahdi_device_location_show, NULL),
|
||||
__ATTR(auto_assign, S_IWUSR, NULL, dahdi_device_auto_assign),
|
||||
__ATTR(assign_span, S_IWUSR, NULL, dahdi_device_assign_span),
|
||||
__ATTR(unassign_span, S_IWUSR, NULL, dahdi_device_unassign_span),
|
||||
__ATTR(spantype, S_IWUSR | S_IRUGO, dahdi_spantype_show,
|
||||
dahdi_spantype_store),
|
||||
__ATTR(registration_time, S_IRUGO, dahdi_registration_time_show, NULL),
|
||||
__ATTR_NULL,
|
||||
};
|
||||
|
||||
static struct bus_type dahdi_device_bus = {
|
||||
.name = "dahdi_devices",
|
||||
.uevent = device_uevent,
|
||||
.dev_attrs = dahdi_device_attrs,
|
||||
};
|
||||
|
||||
@@ -639,6 +788,19 @@ int __init dahdi_sysfs_init(const struct file_operations *dahdi_fops)
|
||||
int res = 0;
|
||||
|
||||
dahdi_dbg(DEVICES, "Registering DAHDI device bus\n");
|
||||
|
||||
/* Handle dahdi-tools paths (for udev environment) */
|
||||
if (tools_rootdir && initdir) {
|
||||
dahdi_err("Cannot use tools-rootdir and initdir parameters simultaneously\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (initdir)
|
||||
pr_notice("dahdi: initdir is depracated -- prefer using \"tools_rootdir\" parameter\n");
|
||||
else
|
||||
initdir = "/usr/share/dahdi";
|
||||
if (!tools_rootdir)
|
||||
tools_rootdir = "";
|
||||
|
||||
res = bus_register(&dahdi_device_bus);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
@@ -630,6 +630,10 @@ static int _create_dynamic(struct dahdi_dynamic_span *dds)
|
||||
d->span.deflaw = DAHDI_LAW_MULAW;
|
||||
d->span.flags |= DAHDI_FLAG_RBS;
|
||||
d->span.chans = d->chans;
|
||||
d->span.spantype = SPANTYPE_DIGITAL_DYNAMIC;
|
||||
d->span.linecompat = DAHDI_CONFIG_D4 | DAHDI_CONFIG_ESF |
|
||||
DAHDI_CONFIG_AMI | DAHDI_CONFIG_B8ZS | DAHDI_CONFIG_CCS |
|
||||
DAHDI_CONFIG_HDB3 | DAHDI_CONFIG_CRC4 | DAHDI_CONFIG_NOTOPEN;
|
||||
d->span.ops = &dynamic_ops;
|
||||
for (x = 0; x < d->span.channels; x++) {
|
||||
sprintf(d->chans[x]->name, "DYN/%s/%s/%d",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#
|
||||
# Makefile for firmware downloading/installation
|
||||
#
|
||||
# Copyright (C) 2007-2010, Digium, Inc.
|
||||
# Copyright (C) 2007-2013, Digium, Inc.
|
||||
#
|
||||
# Joshua Colp <jcolp@digium.com>
|
||||
#
|
||||
@@ -31,12 +31,19 @@ VPMADT032_VERSION:=1.25.0
|
||||
HX8_VERSION:=2.06
|
||||
VPMOCT032_VERSION:=1.12.0
|
||||
WCT820_VERSION:=1.76
|
||||
TE133_VERSION:=6f0017
|
||||
TE134_VERSION:=6f0017
|
||||
TE133_VERSION:=780017
|
||||
TE134_VERSION:=780017
|
||||
TE435_VERSION:=e0017
|
||||
A8A_VERSION:=1d0017
|
||||
A8B_VERSION:=1d0017
|
||||
A4A_VERSION:=a0017
|
||||
A4B_VERSION:=b0017
|
||||
|
||||
FIRMWARE_URL:=http://downloads.digium.com/pub/telephony/firmware/releases
|
||||
|
||||
ALL_FIRMWARE=FIRMWARE-OCT6114-032 FIRMWARE-OCT6114-064 FIRMWARE-OCT6114-128 FIRMWARE-OCT6114-256 FIRMWARE-TC400M FIRMWARE-HX8 FIRMWARE-VPMOCT032 FIRMWARE-TE820 FIRMWARE-TE133 FIRMWARE-TE134
|
||||
ALL_FIRMWARE=FIRMWARE-OCT6114-032 FIRMWARE-OCT6114-064 FIRMWARE-OCT6114-128 FIRMWARE-OCT6114-256
|
||||
ALL_FIRMWARE+=FIRMWARE-TC400M FIRMWARE-HX8 FIRMWARE-VPMOCT032 FIRMWARE-TE820 FIRMWARE-TE133 FIRMWARE-TE134
|
||||
ALL_FIRMWARE+=FIRMWARE-A8A FIRMWARE-A8B FIRMWARE-A4A FIRMWARE-A4B FIRMWARE-TE435
|
||||
|
||||
# Firmware files should use the naming convention: dahdi-fw-<base name>-<sub name>-<version> or dahdi-fw-<base name>-<version>
|
||||
# First example: dahdi-fw-oct6114-064-1.05.01
|
||||
@@ -55,6 +62,11 @@ FIRMWARE:=$(FIRMWARE:FIRMWARE-VPMOCT032=dahdi-fw-vpmoct032-$(VPMOCT032_VERSION).
|
||||
FIRMWARE:=$(FIRMWARE:FIRMWARE-TE820=dahdi-fw-te820-$(WCT820_VERSION).tar.gz)
|
||||
FIRMWARE:=$(FIRMWARE:FIRMWARE-TE133=dahdi-fw-te133-$(TE133_VERSION).tar.gz)
|
||||
FIRMWARE:=$(FIRMWARE:FIRMWARE-TE134=dahdi-fw-te134-$(TE134_VERSION).tar.gz)
|
||||
FIRMWARE:=$(FIRMWARE:FIRMWARE-TE435=dahdi-fw-te435-$(TE435_VERSION).tar.gz)
|
||||
FIRMWARE:=$(FIRMWARE:FIRMWARE-A8A=dahdi-fw-a8b-$(A8B_VERSION).tar.gz)
|
||||
FIRMWARE:=$(FIRMWARE:FIRMWARE-A8B=dahdi-fw-a8a-$(A8A_VERSION).tar.gz)
|
||||
FIRMWARE:=$(FIRMWARE:FIRMWARE-A4A=dahdi-fw-a4b-$(A4B_VERSION).tar.gz)
|
||||
FIRMWARE:=$(FIRMWARE:FIRMWARE-A4B=dahdi-fw-a4a-$(A4A_VERSION).tar.gz)
|
||||
|
||||
FWLOADERS:=dahdi-fwload-vpmadt032-$(VPMADT032_VERSION).tar.gz
|
||||
|
||||
@@ -225,6 +237,61 @@ ifeq ($(shell if ( [ -f $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-te134-$(TE
|
||||
else
|
||||
@echo "Firmware dahdi-fw-te134.bin is already installed with required version $(TE134_VERSION)"
|
||||
endif
|
||||
ifeq ($(shell if ( [ -f $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-te435-$(TE435_VERSION) ] ) && ( [ -f $(DESTDIR)/lib/firmware/.dahdi-fw-te435-$(TE435_VERSION) ] ); then echo "no"; else echo "yes"; fi),yes)
|
||||
@echo "Installing dahdi-fw-te435.bin to hotplug firmware directories"
|
||||
@install -m 644 dahdi-fw-te435.bin $(DESTDIR)/usr/lib/hotplug/firmware
|
||||
@rm -rf $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-te435-*
|
||||
@touch $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-te435-$(TE435_VERSION)
|
||||
@install -m 644 dahdi-fw-te435.bin $(DESTDIR)/lib/firmware
|
||||
@rm -rf $(DESTDIR)/lib/firmware/.dahdi-fw-te435-*
|
||||
@touch $(DESTDIR)/lib/firmware/.dahdi-fw-te435-$(TE435_VERSION)
|
||||
else
|
||||
@echo "Firmware dahdi-fw-te435.bin is already installed with required version $(TE435_VERSION)"
|
||||
endif
|
||||
ifeq ($(shell if ( [ -f $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-a8a-$(A8A_VERSION) ] ) && ( [ -f $(DESTDIR)/lib/firmware/.dahdi-fw-a8a-$(A8A_VERSION) ] ); then echo "no"; else echo "yes"; fi),yes)
|
||||
@echo "Installing dahdi-fw-a8a.bin to hotplug firmware directories"
|
||||
@install -m 644 dahdi-fw-a8a.bin $(DESTDIR)/usr/lib/hotplug/firmware
|
||||
@rm -rf $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-a8a-*
|
||||
@touch $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-a8a-$(A8A_VERSION)
|
||||
@install -m 644 dahdi-fw-a8a.bin $(DESTDIR)/lib/firmware
|
||||
@rm -rf $(DESTDIR)/lib/firmware/.dahdi-fw-a8a-*
|
||||
@touch $(DESTDIR)/lib/firmware/.dahdi-fw-a8a-$(A8A_VERSION)
|
||||
else
|
||||
@echo "Firmware dahdi-fw-a8a.bin is already installed with required version $(A8A_VERSION)"
|
||||
endif
|
||||
ifeq ($(shell if ( [ -f $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-a8b-$(A8B_VERSION) ] ) && ( [ -f $(DESTDIR)/lib/firmware/.dahdi-fw-a8b-$(A8B_VERSION) ] ); then echo "no"; else echo "yes"; fi),yes)
|
||||
@echo "Installing dahdi-fw-a8b.bin to hotplug firmware directories"
|
||||
@install -m 644 dahdi-fw-a8b.bin $(DESTDIR)/usr/lib/hotplug/firmware
|
||||
@rm -rf $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-a8b-*
|
||||
@touch $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-a8b-$(A8B_VERSION)
|
||||
@install -m 644 dahdi-fw-a8b.bin $(DESTDIR)/lib/firmware
|
||||
@rm -rf $(DESTDIR)/lib/firmware/.dahdi-fw-a8b-*
|
||||
@touch $(DESTDIR)/lib/firmware/.dahdi-fw-a8b-$(A8B_VERSION)
|
||||
else
|
||||
@echo "Firmware dahdi-fw-a8b.bin is already installed with required version $(A8B_VERSION)"
|
||||
endif
|
||||
ifeq ($(shell if ( [ -f $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-a4a-$(A4A_VERSION) ] ) && ( [ -f $(DESTDIR)/lib/firmware/.dahdi-fw-a4a-$(A4A_VERSION) ] ); then echo "no"; else echo "yes"; fi),yes)
|
||||
@echo "Installing dahdi-fw-a4a.bin to hotplug firmware directories"
|
||||
@install -m 644 dahdi-fw-a4a.bin $(DESTDIR)/usr/lib/hotplug/firmware
|
||||
@rm -rf $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-a4a-*
|
||||
@touch $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-a4a-$(A4A_VERSION)
|
||||
@install -m 644 dahdi-fw-a4a.bin $(DESTDIR)/lib/firmware
|
||||
@rm -rf $(DESTDIR)/lib/firmware/.dahdi-fw-a4a-*
|
||||
@touch $(DESTDIR)/lib/firmware/.dahdi-fw-a4a-$(A4A_VERSION)
|
||||
else
|
||||
@echo "Firmware dahdi-fw-a4a.bin is already installed with required version $(A4A_VERSION)"
|
||||
endif
|
||||
ifeq ($(shell if ( [ -f $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-a4b-$(A4B_VERSION) ] ) && ( [ -f $(DESTDIR)/lib/firmware/.dahdi-fw-a4b-$(A4B_VERSION) ] ); then echo "no"; else echo "yes"; fi),yes)
|
||||
@echo "Installing dahdi-fw-a4b.bin to hotplug firmware directories"
|
||||
@install -m 644 dahdi-fw-a4b.bin $(DESTDIR)/usr/lib/hotplug/firmware
|
||||
@rm -rf $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-a4b-*
|
||||
@touch $(DESTDIR)/usr/lib/hotplug/firmware/.dahdi-fw-a4b-$(A4B_VERSION)
|
||||
@install -m 645 dahdi-fw-a4b.bin $(DESTDIR)/lib/firmware
|
||||
@rm -rf $(DESTDIR)/lib/firmware/.dahdi-fw-a4b-*
|
||||
@touch $(DESTDIR)/lib/firmware/.dahdi-fw-a4b-$(A4B_VERSION)
|
||||
else
|
||||
@echo "Firmware dahdi-fw-a4b.bin is already installed with required version $(A4B_VERSION)"
|
||||
endif
|
||||
|
||||
# Uninstall any installed dahdi firmware images from hotplug firmware directories
|
||||
hotplug-uninstall:
|
||||
|
||||
32
drivers/dahdi/oct612x/Kbuild
Normal file
32
drivers/dahdi/oct612x/Kbuild
Normal file
@@ -0,0 +1,32 @@
|
||||
#
|
||||
# Produces the oct612x library
|
||||
#
|
||||
octapi_files = octdeviceapi/oct6100api/oct6100_api/oct6100_adpcm_chan.o \
|
||||
octdeviceapi/oct6100api/oct6100_api/oct6100_channel.o \
|
||||
octdeviceapi/oct6100api/oct6100_api/oct6100_chip_open.o \
|
||||
octdeviceapi/oct6100api/oct6100_api/oct6100_chip_stats.o \
|
||||
octdeviceapi/oct6100api/oct6100_api/oct6100_conf_bridge.o \
|
||||
octdeviceapi/oct6100api/oct6100_api/oct6100_debug.o \
|
||||
octdeviceapi/oct6100api/oct6100_api/oct6100_events.o \
|
||||
octdeviceapi/oct6100api/oct6100_api/oct6100_interrupts.o \
|
||||
octdeviceapi/oct6100api/oct6100_api/oct6100_memory.o \
|
||||
octdeviceapi/oct6100api/oct6100_api/oct6100_miscellaneous.o \
|
||||
octdeviceapi/oct6100api/oct6100_api/oct6100_mixer.o \
|
||||
octdeviceapi/oct6100api/oct6100_api/oct6100_phasing_tsst.o \
|
||||
octdeviceapi/oct6100api/oct6100_api/oct6100_playout_buf.o \
|
||||
octdeviceapi/oct6100api/oct6100_api/oct6100_remote_debug.o \
|
||||
octdeviceapi/oct6100api/oct6100_api/oct6100_tlv.o \
|
||||
octdeviceapi/oct6100api/oct6100_api/oct6100_tone_detection.o \
|
||||
octdeviceapi/oct6100api/oct6100_api/oct6100_tsi_cnct.o \
|
||||
octdeviceapi/oct6100api/oct6100_api/oct6100_tsst.o \
|
||||
apilib/bt/octapi_bt0.o \
|
||||
apilib/largmath/octapi_largmath.o \
|
||||
apilib/llman/octapi_llman.o \
|
||||
oct612x-user.o
|
||||
|
||||
# TODO: ccflags was added in 2.6.24 in commit f77bf01425b11947eeb3b5b54. This
|
||||
# should be changed to a conditional compilation based on the Kernel Version.
|
||||
# ccflags-y := -I$(src)/.. -Wno-undef -I$(src)/include -I$(src)/octdeviceapi -I$(src)/octdeviceapi/oct6100api
|
||||
EXTRA_CFLAGS = -I$(src)/.. -Wno-undef -I$(src)/include -I$(src)/octdeviceapi -I$(src)/octdeviceapi/oct6100api
|
||||
obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_OCT612X) := oct612x.o
|
||||
oct612x-objs := $(octapi_files)
|
||||
200
drivers/dahdi/oct612x/oct612x-user.c
Normal file
200
drivers/dahdi/oct612x/oct612x-user.c
Normal file
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Octasic OCT6100 Interface
|
||||
*
|
||||
* Copyright (C) 2013 Digium, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2 as published by the
|
||||
* Free Software Foundation. See the LICENSE file included with
|
||||
* this program for more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <dahdi/kernel.h>
|
||||
|
||||
#include "oct612x.h"
|
||||
|
||||
UINT32 Oct6100UserGetTime(tPOCT6100_GET_TIME f_pTime)
|
||||
{
|
||||
/* Why couldn't they just take a timeval like everyone else? */
|
||||
struct timeval tv;
|
||||
unsigned long long total_usecs;
|
||||
unsigned int mask = ~0;
|
||||
|
||||
do_gettimeofday(&tv);
|
||||
total_usecs = (((unsigned long long)(tv.tv_sec)) * 1000000) +
|
||||
(((unsigned long long)(tv.tv_usec)));
|
||||
f_pTime->aulWallTimeUs[0] = (total_usecs & mask);
|
||||
f_pTime->aulWallTimeUs[1] = (total_usecs >> 32);
|
||||
return cOCT6100_ERR_OK;
|
||||
}
|
||||
|
||||
UINT32 Oct6100UserMemSet(PVOID f_pAddress, UINT32 f_ulPattern,
|
||||
UINT32 f_ulLength)
|
||||
{
|
||||
memset(f_pAddress, f_ulPattern, f_ulLength);
|
||||
return cOCT6100_ERR_OK;
|
||||
}
|
||||
|
||||
UINT32 Oct6100UserMemCopy(PVOID f_pDestination, const void *f_pSource,
|
||||
UINT32 f_ulLength)
|
||||
{
|
||||
memcpy(f_pDestination, f_pSource, f_ulLength);
|
||||
return cOCT6100_ERR_OK;
|
||||
}
|
||||
|
||||
UINT32 Oct6100UserCreateSerializeObject(
|
||||
tPOCT6100_CREATE_SERIALIZE_OBJECT f_pCreate)
|
||||
{
|
||||
return cOCT6100_ERR_OK;
|
||||
}
|
||||
|
||||
UINT32 Oct6100UserDestroySerializeObject(
|
||||
tPOCT6100_DESTROY_SERIALIZE_OBJECT f_pDestroy)
|
||||
{
|
||||
#ifdef OCTASIC_DEBUG
|
||||
pr_debug("I should never be called! (destroy serialize object)\n");
|
||||
#endif
|
||||
return cOCT6100_ERR_OK;
|
||||
}
|
||||
|
||||
UINT32 Oct6100UserSeizeSerializeObject(
|
||||
tPOCT6100_SEIZE_SERIALIZE_OBJECT f_pSeize)
|
||||
{
|
||||
/* Not needed */
|
||||
return cOCT6100_ERR_OK;
|
||||
}
|
||||
|
||||
UINT32 Oct6100UserReleaseSerializeObject(
|
||||
tPOCT6100_RELEASE_SERIALIZE_OBJECT f_pRelease)
|
||||
{
|
||||
/* Not needed */
|
||||
return cOCT6100_ERR_OK;
|
||||
}
|
||||
|
||||
UINT32 Oct6100UserDriverWriteApi(tPOCT6100_WRITE_PARAMS f_pWriteParams)
|
||||
{
|
||||
struct oct612x_context *context = f_pWriteParams->pProcessContext;
|
||||
#ifdef OCTASIC_DEBUG
|
||||
if (!context || !context->ops || !context->ops->write) {
|
||||
pr_debug("Invalid call to %s\n", __func__);
|
||||
return cOCT6100_ERR_BASE;
|
||||
}
|
||||
#endif
|
||||
context->ops->write(context, f_pWriteParams->ulWriteAddress,
|
||||
f_pWriteParams->usWriteData);
|
||||
return cOCT6100_ERR_OK;
|
||||
}
|
||||
|
||||
UINT32 Oct6100UserDriverWriteSmearApi(tPOCT6100_WRITE_SMEAR_PARAMS f_pSmearParams)
|
||||
{
|
||||
struct oct612x_context *context = f_pSmearParams->pProcessContext;
|
||||
#ifdef OCTASIC_DEBUG
|
||||
if (!context || !context->ops || !context->ops->write_smear) {
|
||||
pr_debug("Invalid call to %s\n", __func__);
|
||||
return cOCT6100_ERR_BASE;
|
||||
}
|
||||
#endif
|
||||
context->ops->write_smear(context, f_pSmearParams->ulWriteAddress,
|
||||
f_pSmearParams->usWriteData,
|
||||
f_pSmearParams->ulWriteLength);
|
||||
return cOCT6100_ERR_OK;
|
||||
}
|
||||
|
||||
UINT32 Oct6100UserDriverWriteBurstApi(
|
||||
tPOCT6100_WRITE_BURST_PARAMS f_pBurstParams)
|
||||
{
|
||||
struct oct612x_context *context = f_pBurstParams->pProcessContext;
|
||||
#ifdef OCTASIC_DEBUG
|
||||
if (!context || !context->ops || !context->ops->write_burst) {
|
||||
pr_debug("Invalid call to %s\n", __func__);
|
||||
return cOCT6100_ERR_BASE;
|
||||
}
|
||||
#endif
|
||||
context->ops->write_burst(context, f_pBurstParams->ulWriteAddress,
|
||||
f_pBurstParams->pusWriteData,
|
||||
f_pBurstParams->ulWriteLength);
|
||||
return cOCT6100_ERR_OK;
|
||||
}
|
||||
|
||||
UINT32 Oct6100UserDriverReadApi(tPOCT6100_READ_PARAMS f_pReadParams)
|
||||
{
|
||||
struct oct612x_context *context = f_pReadParams->pProcessContext;
|
||||
#ifdef OCTASIC_DEBUG
|
||||
if (!context || !context->ops || !context->ops->read) {
|
||||
pr_debug("Invalid call to %s\n", __func__);
|
||||
return cOCT6100_ERR_BASE;
|
||||
}
|
||||
#endif
|
||||
context->ops->read(context, f_pReadParams->ulReadAddress,
|
||||
f_pReadParams->pusReadData);
|
||||
return cOCT6100_ERR_OK;
|
||||
}
|
||||
|
||||
UINT32 Oct6100UserDriverReadBurstApi(tPOCT6100_READ_BURST_PARAMS f_pBurstParams)
|
||||
{
|
||||
struct oct612x_context *context = f_pBurstParams->pProcessContext;
|
||||
#ifdef OCTASIC_DEBUG
|
||||
if (!context || !context->ops || !context->ops->read_burst) {
|
||||
pr_debug("Invalid call to %s\n", __func__);
|
||||
return cOCT6100_ERR_BASE;
|
||||
}
|
||||
#endif
|
||||
context->ops->read_burst(context, f_pBurstParams->ulReadAddress,
|
||||
f_pBurstParams->pusReadData,
|
||||
f_pBurstParams->ulReadLength);
|
||||
return cOCT6100_ERR_OK;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(Oct6100ChipOpen);
|
||||
EXPORT_SYMBOL(Oct6100ChipClose);
|
||||
EXPORT_SYMBOL(Oct6100ChipCloseDef);
|
||||
EXPORT_SYMBOL(Oct6100GetInstanceSize);
|
||||
EXPORT_SYMBOL(Oct6100GetInstanceSizeDef);
|
||||
EXPORT_SYMBOL(Oct6100ChipOpenDef);
|
||||
EXPORT_SYMBOL(Oct6100ChannelModify);
|
||||
EXPORT_SYMBOL(Oct6100ToneDetectionEnableDef);
|
||||
EXPORT_SYMBOL(Oct6100InterruptServiceRoutine);
|
||||
EXPORT_SYMBOL(Oct6100InterruptServiceRoutineDef);
|
||||
EXPORT_SYMBOL(Oct6100ApiGetCapacityPins);
|
||||
EXPORT_SYMBOL(Oct6100ToneDetectionEnable);
|
||||
EXPORT_SYMBOL(Oct6100EventGetToneDef);
|
||||
EXPORT_SYMBOL(Oct6100EventGetTone);
|
||||
EXPORT_SYMBOL(Oct6100ApiGetCapacityPinsDef);
|
||||
EXPORT_SYMBOL(Oct6100ChannelOpen);
|
||||
EXPORT_SYMBOL(Oct6100ChannelOpenDef);
|
||||
EXPORT_SYMBOL(Oct6100ChannelModifyDef);
|
||||
|
||||
static int __init oct612x_module_init(void)
|
||||
{
|
||||
/* This registration with dahdi.ko will fail since the span is not
|
||||
* defined, but it will make sure that this module is a dependency of
|
||||
* dahdi.ko, so that when it is being unloded, this module will be
|
||||
* unloaded as well. */
|
||||
dahdi_register_device(NULL, NULL);
|
||||
return 0;
|
||||
}
|
||||
module_init(oct612x_module_init);
|
||||
|
||||
static void __exit oct612x_module_cleanup(void)
|
||||
{
|
||||
/* Nothing to do */;
|
||||
}
|
||||
module_exit(oct612x_module_cleanup);
|
||||
|
||||
MODULE_AUTHOR("Digium Incorporated <support@digium.com>");
|
||||
MODULE_DESCRIPTION("Octasic OCT6100 Hardware Echocan Library");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
49
drivers/dahdi/oct612x/oct612x.h
Normal file
49
drivers/dahdi/oct612x/oct612x.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Octasic OCT6100 Interface
|
||||
*
|
||||
* Copyright (C) 2013 Digium, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2 as published by the
|
||||
* Free Software Foundation. See the LICENSE file included with
|
||||
* this program for more details.
|
||||
*/
|
||||
#ifndef __OCT612X_H__
|
||||
#define __OCT612X_H__
|
||||
|
||||
#include <oct6100api/oct6100_api.h>
|
||||
|
||||
struct oct612x_context;
|
||||
|
||||
/**
|
||||
* struct oct612x_ops - Callbacks used by oct612x library to talk to part.
|
||||
*
|
||||
*/
|
||||
struct oct612x_ops {
|
||||
int (*write)(struct oct612x_context *context, u32 address, u16 value);
|
||||
int (*read)(struct oct612x_context *context, u32 address, u16 *value);
|
||||
int (*write_smear)(struct oct612x_context *context, u32 address,
|
||||
u16 value, size_t count);
|
||||
int (*write_burst)(struct oct612x_context *context, u32 address,
|
||||
const u16 *value, size_t count);
|
||||
int (*read_burst)(struct oct612x_context *context, u32 address,
|
||||
u16 *value, size_t count);
|
||||
};
|
||||
|
||||
struct oct612x_context {
|
||||
const struct oct612x_ops *ops;
|
||||
struct device *dev;
|
||||
};
|
||||
|
||||
#endif /* __OCT612X_H__ */
|
||||
4544
drivers/dahdi/wcaxx-base.c
Normal file
4544
drivers/dahdi/wcaxx-base.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,7 +2,7 @@ obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_WCT4XXP) += wct4xxp.o
|
||||
|
||||
FIRM_DIR := ../firmware
|
||||
|
||||
EXTRA_CFLAGS += -I$(src)/.. $(shell $(src)/../oct612x/octasic-helper cflags $(src)/../oct612x) -Wno-undef
|
||||
EXTRA_CFLAGS += -I$(src)/.. -I$(src)/../oct612x/ $(shell $(src)/../oct612x/octasic-helper cflags $(src)/../oct612x) -Wno-undef
|
||||
|
||||
# The OCT612X source files are from a vendor drop and we do not want to edit
|
||||
# them to make this warning go away. Therefore, turn off the
|
||||
@@ -14,7 +14,7 @@ ifeq ($(HOTPLUG_FIRMWARE),yes)
|
||||
EXTRA_CFLAGS+=-DHOTPLUG_FIRMWARE
|
||||
endif
|
||||
|
||||
wct4xxp-objs := base.o vpm450m.o ../oct612x/lib.a
|
||||
wct4xxp-objs := base.o vpm450m.o
|
||||
|
||||
ifneq ($(HOTPLUG_FIRMWARE),yes)
|
||||
wct4xxp-objs += $(FIRM_DIR)/dahdi-fw-oct6114-064.o $(FIRM_DIR)/dahdi-fw-oct6114-128.o $(FIRM_DIR)/dahdi-fw-oct6114-256.o
|
||||
|
||||
@@ -183,7 +183,7 @@ static inline int t4_queue_work(struct workqueue_struct *wq, struct work_struct
|
||||
"CONFIG_NOEXTENDED_RESET."
|
||||
#endif
|
||||
|
||||
static int debug=0;
|
||||
int debug = 0;
|
||||
static int timingcable = 0;
|
||||
static int t1e1override = -1; /* deprecated */
|
||||
static char *default_linemode = "auto";
|
||||
@@ -299,6 +299,7 @@ struct t4_span {
|
||||
unsigned long alarmcheck_time;
|
||||
int spanflags;
|
||||
int syncpos;
|
||||
|
||||
#ifdef SUPPORT_GEN1
|
||||
int e1check; /* E1 check */
|
||||
#endif
|
||||
@@ -345,6 +346,7 @@ struct t4 {
|
||||
int irq; /* IRQ used by device */
|
||||
int order; /* Order */
|
||||
const struct devtype *devtype;
|
||||
unsigned int reset_required:1; /* If reset needed in serial_setup */
|
||||
unsigned int falc31:1; /* are we falc v3.1 (atomic not necessary) */
|
||||
unsigned int t1e1:8; /* T1 / E1 select pins */
|
||||
int ledreg; /* LED Register */
|
||||
@@ -505,7 +507,7 @@ static void t4_check_sigbits(struct t4 *wc, int span);
|
||||
#define FMR5_EIBR (1 << 6) /* Internal Bit Robbing Access */
|
||||
#define DEC_T 0x60 /* Diable Error Counter */
|
||||
#define IERR_T 0x1B /* Single Bit Defect Insertion Register */
|
||||
#define IBV 0 /* Bipolar violation */
|
||||
#define IBV (1 << 0) /* Bipolar violation */
|
||||
#define IPE (1 << 1) /* PRBS defect */
|
||||
#define ICASE (1 << 2) /* CAS defect */
|
||||
#define ICRCE (1 << 3) /* CRC defect */
|
||||
@@ -1119,16 +1121,11 @@ static int t4_echocan_create(struct dahdi_chan *chan,
|
||||
struct t4 *wc = chan->pvt;
|
||||
struct t4_span *tspan = container_of(chan->span, struct t4_span, span);
|
||||
int channel;
|
||||
const struct dahdi_echocan_ops *ops;
|
||||
const struct dahdi_echocan_features *features;
|
||||
const bool alaw = (chan->span->deflaw == 2);
|
||||
|
||||
if (!vpmsupport || !wc->vpm)
|
||||
return -ENODEV;
|
||||
|
||||
ops = &vpm_ec_ops;
|
||||
features = &vpm_ec_features;
|
||||
|
||||
if (ecp->param_count > 0) {
|
||||
dev_warn(&wc->dev->dev, "%s echo canceller does not support "
|
||||
"parameters; failing request\n",
|
||||
@@ -1137,8 +1134,8 @@ static int t4_echocan_create(struct dahdi_chan *chan,
|
||||
}
|
||||
|
||||
*ec = tspan->ec[chan->chanpos - 1];
|
||||
(*ec)->ops = ops;
|
||||
(*ec)->features = *features;
|
||||
(*ec)->ops = &vpm_ec_ops;
|
||||
(*ec)->features = vpm_ec_features;
|
||||
|
||||
channel = has_e1_span(wc) ? chan->chanpos : chan->chanpos + 4;
|
||||
|
||||
@@ -1712,8 +1709,11 @@ _t4_spanconfig(struct file *file, struct dahdi_span *span,
|
||||
|
||||
if (lc->sync < 0)
|
||||
lc->sync = 0;
|
||||
if (lc->sync > wc->numspans)
|
||||
if (lc->sync > wc->numspans) {
|
||||
dev_warn(&wc->dev->dev, "WARNING: Cannot set priority on span %d to %d. Please set to a number between 1 and %d\n",
|
||||
span->spanno, lc->sync, wc->numspans);
|
||||
lc->sync = 0;
|
||||
}
|
||||
|
||||
/* remove this span number from the current sync sources, if there */
|
||||
for(i = 0; i < wc->numspans; i++) {
|
||||
@@ -1890,6 +1890,33 @@ static void setup_chunks(struct t4 *wc, int which)
|
||||
}
|
||||
}
|
||||
|
||||
static int __t4_hardware_init_1(struct t4 *wc, unsigned int cardflags,
|
||||
bool first_time);
|
||||
static int __t4_hardware_init_2(struct t4 *wc, bool first_time);
|
||||
|
||||
static int t4_hardware_stop(struct t4 *wc);
|
||||
|
||||
static void t4_framer_reset(struct t4 *wc)
|
||||
{
|
||||
const bool first_time = false;
|
||||
bool have_vpm = wc->vpm != NULL;
|
||||
if (have_vpm) {
|
||||
release_vpm450m(wc->vpm);
|
||||
wc->vpm = NULL;
|
||||
}
|
||||
t4_hardware_stop(wc);
|
||||
__t4_set_sclk_src(wc, WC_SELF, 0, 0);
|
||||
__t4_hardware_init_1(wc, wc->devtype->flags, first_time);
|
||||
__t4_hardware_init_2(wc, first_time);
|
||||
if (have_vpm) {
|
||||
t4_vpm_init(wc);
|
||||
wc->dmactrl |= (wc->vpm) ? T4_VPM_PRESENT : 0;
|
||||
t4_pci_out(wc, WC_DMACTRL, wc->dmactrl);
|
||||
}
|
||||
setup_chunks(wc, 0);
|
||||
wc->lastindex = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* t4_serial_setup - Setup serial parameters and system interface.
|
||||
* @wc: The card to configure.
|
||||
@@ -1899,6 +1926,7 @@ static void t4_serial_setup(struct t4 *wc)
|
||||
{
|
||||
unsigned long flags;
|
||||
unsigned int unit;
|
||||
bool reset_required = false;
|
||||
|
||||
if (debug) {
|
||||
dev_info(&wc->dev->dev,
|
||||
@@ -1906,6 +1934,14 @@ static void t4_serial_setup(struct t4 *wc)
|
||||
wc->numspans);
|
||||
}
|
||||
|
||||
spin_lock_irqsave(&wc->reglock, flags);
|
||||
reset_required = wc->reset_required > 0;
|
||||
wc->reset_required = 0;
|
||||
spin_unlock_irqrestore(&wc->reglock, flags);
|
||||
|
||||
if (reset_required)
|
||||
t4_framer_reset(wc);
|
||||
|
||||
spin_lock_irqsave(&wc->reglock, flags);
|
||||
/* GPC1: Multiplex mode enabled, FSC is output, active low, RCLK from
|
||||
* channel 0 */
|
||||
@@ -2056,6 +2092,7 @@ static void t4_span_assigned(struct dahdi_span *span)
|
||||
struct t4 *wc = tspan->owner;
|
||||
struct dahdi_span *pos;
|
||||
unsigned int unassigned_spans = 0;
|
||||
unsigned long flags;
|
||||
|
||||
/* We use this to make sure all the spans are assigned before
|
||||
* running the serial setup. */
|
||||
@@ -2064,8 +2101,14 @@ static void t4_span_assigned(struct dahdi_span *span)
|
||||
++unassigned_spans;
|
||||
}
|
||||
|
||||
if (0 == unassigned_spans)
|
||||
if (0 == unassigned_spans) {
|
||||
t4_serial_setup(wc);
|
||||
|
||||
set_bit(T4_CHECK_TIMING, &wc->checkflag);
|
||||
spin_lock_irqsave(&wc->reglock, flags);
|
||||
__t4_set_sclk_src(wc, WC_SELF, 0, 0);
|
||||
spin_unlock_irqrestore(&wc->reglock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
static void free_wc(struct t4 *wc)
|
||||
@@ -2227,6 +2270,7 @@ static int t4_set_linemode(struct dahdi_span *span, enum spantypes linemode)
|
||||
enum linemode mode;
|
||||
const char *old_name;
|
||||
static DEFINE_MUTEX(linemode_lock);
|
||||
unsigned long flags;
|
||||
|
||||
dev_dbg(&wc->dev->dev, "Setting '%s' to '%s'\n", span->name,
|
||||
dahdi_spantype2str(linemode));
|
||||
@@ -2234,6 +2278,10 @@ static int t4_set_linemode(struct dahdi_span *span, enum spantypes linemode)
|
||||
if (span->spantype == linemode)
|
||||
return 0;
|
||||
|
||||
spin_lock_irqsave(&wc->reglock, flags);
|
||||
wc->reset_required = 1;
|
||||
spin_unlock_irqrestore(&wc->reglock, flags);
|
||||
|
||||
/* Do not allow the t1e1 member to be changed by multiple threads. */
|
||||
mutex_lock(&linemode_lock);
|
||||
old_name = dahdi_spantype2str(span->spantype);
|
||||
@@ -2830,6 +2878,10 @@ static void __t4_configure_e1(struct t4 *wc, int unit, int lineconfig)
|
||||
__t4_framer_out(wc, unit, 0x17, 0x04 | imr3extra); /* IMR3: AIS */
|
||||
__t4_framer_out(wc, unit, 0x18, 0x3f); /* IMR4: We care about slips on transmit */
|
||||
|
||||
__t4_framer_out(wc, unit, 0x2f, 0x00);
|
||||
__t4_framer_out(wc, unit, 0x30, 0x00);
|
||||
__t4_framer_out(wc, unit, 0x31, 0x00);
|
||||
|
||||
dev_info(&wc->dev->dev, "TE%dXXP: Span %d configured for %s/%s%s\n",
|
||||
wc->numspans, unit + 1, framing, line, crc4);
|
||||
}
|
||||
@@ -4306,7 +4358,7 @@ static void t4_vpm_init(struct t4 *wc)
|
||||
laws[x] = 1;
|
||||
}
|
||||
|
||||
vpm_capacity = get_vpm450m_capacity(wc);
|
||||
vpm_capacity = get_vpm450m_capacity(&wc->dev->dev);
|
||||
if (vpm_capacity != wc->numspans * 32) {
|
||||
dev_info(&wc->dev->dev, "Disabling VPMOCT%03d. TE%dXXP"\
|
||||
" requires a VPMOCT%03d", vpm_capacity,
|
||||
@@ -4378,7 +4430,8 @@ static void t4_vpm_init(struct t4 *wc)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(wc->vpm = init_vpm450m(wc, laws, wc->numspans, firmware))) {
|
||||
wc->vpm = init_vpm450m(&wc->dev->dev, laws, wc->numspans, firmware);
|
||||
if (!wc->vpm) {
|
||||
dev_notice(&wc->dev->dev, "VPM450: Failed to initialize\n");
|
||||
if (firmware != &embedded_firmware)
|
||||
release_firmware(firmware);
|
||||
@@ -4865,17 +4918,18 @@ cleanup:
|
||||
return res;
|
||||
}
|
||||
|
||||
static int t4_hardware_init_1(struct t4 *wc, unsigned int cardflags)
|
||||
static int
|
||||
__t4_hardware_init_1(struct t4 *wc, unsigned int cardflags, bool first_time)
|
||||
{
|
||||
unsigned int version;
|
||||
int res;
|
||||
|
||||
version = t4_pci_in(wc, WC_VERSION);
|
||||
if (is_octal(wc)) {
|
||||
if (is_octal(wc) && first_time) {
|
||||
dev_info(&wc->dev->dev, "Firmware Version: %01x.%02x\n",
|
||||
(version & 0xf00) >> 8,
|
||||
version & 0xff);
|
||||
} else {
|
||||
} else if (first_time) {
|
||||
dev_info(&wc->dev->dev, "Firmware Version: %08x\n", version);
|
||||
}
|
||||
if (debug) {
|
||||
@@ -4923,30 +4977,33 @@ static int t4_hardware_init_1(struct t4 *wc, unsigned int cardflags)
|
||||
t4_pci_out(wc, WC_INTR, 0x00000000);
|
||||
|
||||
/* Read T1/E1 status */
|
||||
if (!strcasecmp("auto", default_linemode)) {
|
||||
if (-1 == t1e1override) {
|
||||
wc->t1e1 = (((t4_pci_in(wc, WC_LEDS)) & 0x0f00) >> 8);
|
||||
wc->t1e1 &= 0xf;
|
||||
if (is_octal(wc)) {
|
||||
wc->t1e1 |= ((t4_pci_in(wc, WC_LEDS2)) &
|
||||
0x0f00) >> 4;
|
||||
if (first_time) {
|
||||
if (!strcasecmp("auto", default_linemode)) {
|
||||
if (-1 == t1e1override) {
|
||||
wc->t1e1 = (((t4_pci_in(wc, WC_LEDS)) &
|
||||
0x0f00) >> 8);
|
||||
wc->t1e1 &= 0xf;
|
||||
if (is_octal(wc)) {
|
||||
wc->t1e1 |= ((t4_pci_in(wc, WC_LEDS2)) &
|
||||
0x0f00) >> 4;
|
||||
}
|
||||
} else {
|
||||
dev_warn(&wc->dev->dev,
|
||||
"'t1e1override' is deprecated. Please use 'default_linemode'.\n");
|
||||
wc->t1e1 = t1e1override & 0xf;
|
||||
}
|
||||
} else if (!strcasecmp("t1", default_linemode)) {
|
||||
wc->t1e1 = 0;
|
||||
} else if (!strcasecmp("e1", default_linemode)) {
|
||||
wc->t1e1 = 0xff;
|
||||
} else if (!strcasecmp("j1", default_linemode)) {
|
||||
wc->t1e1 = 0;
|
||||
j1mode = 1;
|
||||
} else {
|
||||
dev_warn(&wc->dev->dev, "'t1e1override' is deprecated. "
|
||||
"Please use 'default_linemode'.\n");
|
||||
wc->t1e1 = t1e1override & 0xf;
|
||||
dev_err(&wc->dev->dev, "'%s' is an unknown linemode.\n",
|
||||
default_linemode);
|
||||
wc->t1e1 = 0;
|
||||
}
|
||||
} else if (!strcasecmp("t1", default_linemode)) {
|
||||
wc->t1e1 = 0;
|
||||
} else if (!strcasecmp("e1", default_linemode)) {
|
||||
wc->t1e1 = 0xff;
|
||||
} else if (!strcasecmp("j1", default_linemode)) {
|
||||
wc->t1e1 = 0;
|
||||
j1mode = 1;
|
||||
} else {
|
||||
dev_err(&wc->dev->dev, "'%s' is an unknown linemode.\n",
|
||||
default_linemode);
|
||||
wc->t1e1 = 0;
|
||||
}
|
||||
|
||||
wc->order = ((t4_pci_in(wc, WC_LEDS)) & 0xf0000000) >> 28;
|
||||
@@ -4975,7 +5032,12 @@ static int t4_hardware_init_1(struct t4 *wc, unsigned int cardflags)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int t4_hardware_init_2(struct t4 *wc)
|
||||
static int t4_hardware_init_1(struct t4 *wc, unsigned int cardflags)
|
||||
{
|
||||
return __t4_hardware_init_1(wc, cardflags, true);
|
||||
}
|
||||
|
||||
static int __t4_hardware_init_2(struct t4 *wc, bool first_time)
|
||||
{
|
||||
int x;
|
||||
unsigned int regval;
|
||||
@@ -5007,13 +5069,14 @@ static int t4_hardware_init_2(struct t4 *wc)
|
||||
|
||||
if (!is_octal(wc)) {
|
||||
regval = t4_framer_in(wc, 0, 0x4a);
|
||||
if (regval == 0x05) {
|
||||
if (first_time && regval == 0x05) {
|
||||
dev_info(&wc->dev->dev, "FALC Framer Version: 2.1 or "
|
||||
"earlier\n");
|
||||
} else if (regval == 0x20) {
|
||||
dev_info(&wc->dev->dev, "FALC Framer Version: 3.1\n");
|
||||
if (first_time)
|
||||
dev_info(&wc->dev->dev, "FALC Framer Version: 3.1\n");
|
||||
wc->falc31 = 1;
|
||||
} else {
|
||||
} else if (first_time) {
|
||||
dev_info(&wc->dev->dev, "FALC Framer Version: Unknown "
|
||||
"(VSTR = 0x%02x)\n", regval);
|
||||
}
|
||||
@@ -5033,14 +5096,24 @@ static int t4_hardware_init_2(struct t4 *wc)
|
||||
t4_pci_in(wc, x));
|
||||
}
|
||||
}
|
||||
|
||||
wc->gpio = 0x00000000;
|
||||
t4_pci_out(wc, WC_GPIO, wc->gpio);
|
||||
t4_gpio_setdir(wc, (1 << 17), (1 << 17));
|
||||
t4_gpio_setdir(wc, (0xff), (0xff));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int t4_hardware_init_2(struct t4 *wc)
|
||||
{
|
||||
return __t4_hardware_init_2(wc, true);
|
||||
}
|
||||
|
||||
static int __devinit t4_launch(struct t4 *wc)
|
||||
{
|
||||
int x;
|
||||
int res;
|
||||
unsigned long flags;
|
||||
|
||||
if (test_bit(DAHDI_FLAGBIT_REGISTERED, &wc->tspans[0]->span.flags))
|
||||
return 0;
|
||||
@@ -5072,17 +5145,14 @@ static int __devinit t4_launch(struct t4 *wc)
|
||||
&wc->ddev->spans);
|
||||
}
|
||||
|
||||
tasklet_init(&wc->t4_tlet, t4_isr_bh, (unsigned long)wc);
|
||||
|
||||
res = dahdi_register_device(wc->ddev, &wc->dev->dev);
|
||||
if (res) {
|
||||
dev_err(&wc->dev->dev, "Failed to register with DAHDI.\n");
|
||||
return res;
|
||||
}
|
||||
|
||||
set_bit(T4_CHECK_TIMING, &wc->checkflag);
|
||||
spin_lock_irqsave(&wc->reglock, flags);
|
||||
__t4_set_sclk_src(wc, WC_SELF, 0, 0);
|
||||
spin_unlock_irqrestore(&wc->reglock, flags);
|
||||
tasklet_init(&wc->t4_tlet, t4_isr_bh, (unsigned long)wc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -5296,10 +5366,6 @@ t4_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
dev_info(&wc->dev->dev,
|
||||
"Found a Wildcard: %s\n", wc->devtype->desc);
|
||||
}
|
||||
wc->gpio = 0x00000000;
|
||||
t4_pci_out(wc, WC_GPIO, wc->gpio);
|
||||
t4_gpio_setdir(wc, (1 << 17), (1 << 17));
|
||||
t4_gpio_setdir(wc, (0xff), (0xff));
|
||||
|
||||
#ifdef VPM_SUPPORT
|
||||
if (!wc->vpm) {
|
||||
|
||||
@@ -31,99 +31,62 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "vpm450m.h"
|
||||
#include "oct6100api/oct6100_api.h"
|
||||
#include <oct612x.h>
|
||||
|
||||
/* API for Octasic access */
|
||||
UINT32 Oct6100UserGetTime(tPOCT6100_GET_TIME f_pTime)
|
||||
static int wct4xxp_oct612x_write(struct oct612x_context *context,
|
||||
u32 address, u16 value)
|
||||
{
|
||||
/* Why couldn't they just take a timeval like everyone else? */
|
||||
struct timeval tv;
|
||||
unsigned long long total_usecs;
|
||||
unsigned int mask = ~0;
|
||||
|
||||
do_gettimeofday(&tv);
|
||||
total_usecs = (((unsigned long long)(tv.tv_sec)) * 1000000) +
|
||||
(((unsigned long long)(tv.tv_usec)));
|
||||
f_pTime->aulWallTimeUs[0] = (total_usecs & mask);
|
||||
f_pTime->aulWallTimeUs[1] = (total_usecs >> 32);
|
||||
return cOCT6100_ERR_OK;
|
||||
struct t4 *wc = dev_get_drvdata(context->dev);
|
||||
oct_set_reg(wc, address, value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
UINT32 Oct6100UserMemSet(PVOID f_pAddress, UINT32 f_ulPattern, UINT32 f_ulLength)
|
||||
static int wct4xxp_oct612x_read(struct oct612x_context *context, u32 address,
|
||||
u16 *value)
|
||||
{
|
||||
memset(f_pAddress, f_ulPattern, f_ulLength);
|
||||
return cOCT6100_ERR_OK;
|
||||
struct t4 *wc = dev_get_drvdata(context->dev);
|
||||
*value = (u16)oct_get_reg(wc, address);
|
||||
return 0;
|
||||
}
|
||||
|
||||
UINT32 Oct6100UserMemCopy(PVOID f_pDestination, const void *f_pSource, UINT32 f_ulLength)
|
||||
static int wct4xxp_oct612x_write_smear(struct oct612x_context *context,
|
||||
u32 address, u16 value, size_t count)
|
||||
{
|
||||
memcpy(f_pDestination, f_pSource, f_ulLength);
|
||||
return cOCT6100_ERR_OK;
|
||||
struct t4 *wc = dev_get_drvdata(context->dev);
|
||||
int i;
|
||||
for (i = 0; i < count; ++i)
|
||||
oct_set_reg(wc, address + (i << 1), value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
UINT32 Oct6100UserCreateSerializeObject(tPOCT6100_CREATE_SERIALIZE_OBJECT f_pCreate)
|
||||
static int wct4xxp_oct612x_write_burst(struct oct612x_context *context,
|
||||
u32 address, const u16 *buffer,
|
||||
size_t count)
|
||||
{
|
||||
return cOCT6100_ERR_OK;
|
||||
struct t4 *wc = dev_get_drvdata(context->dev);
|
||||
int i;
|
||||
for (i = 0; i < count; ++i)
|
||||
oct_set_reg(wc, address + (i << 1), buffer[i]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
UINT32 Oct6100UserDestroySerializeObject(tPOCT6100_DESTROY_SERIALIZE_OBJECT f_pDestroy)
|
||||
static int wct4xxp_oct612x_read_burst(struct oct612x_context *context,
|
||||
u32 address, u16 *buffer, size_t count)
|
||||
{
|
||||
#ifdef OCTASIC_DEBUG
|
||||
printk(KERN_DEBUG "I should never be called! (destroy serialize object)\n");
|
||||
#endif
|
||||
return cOCT6100_ERR_OK;
|
||||
struct t4 *wc = dev_get_drvdata(context->dev);
|
||||
int i;
|
||||
for (i = 0; i < count; ++i)
|
||||
buffer[i] = oct_get_reg(wc, address + (i << 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
UINT32 Oct6100UserSeizeSerializeObject(tPOCT6100_SEIZE_SERIALIZE_OBJECT f_pSeize)
|
||||
{
|
||||
/* Not needed */
|
||||
return cOCT6100_ERR_OK;
|
||||
}
|
||||
|
||||
UINT32 Oct6100UserReleaseSerializeObject(tPOCT6100_RELEASE_SERIALIZE_OBJECT f_pRelease)
|
||||
{
|
||||
/* Not needed */
|
||||
return cOCT6100_ERR_OK;
|
||||
}
|
||||
|
||||
UINT32 Oct6100UserDriverWriteApi(tPOCT6100_WRITE_PARAMS f_pWriteParams)
|
||||
{
|
||||
oct_set_reg(f_pWriteParams->pProcessContext, f_pWriteParams->ulWriteAddress, f_pWriteParams->usWriteData);
|
||||
return cOCT6100_ERR_OK;
|
||||
}
|
||||
|
||||
UINT32 Oct6100UserDriverWriteSmearApi(tPOCT6100_WRITE_SMEAR_PARAMS f_pSmearParams)
|
||||
{
|
||||
unsigned int x;
|
||||
for (x=0;x<f_pSmearParams->ulWriteLength;x++) {
|
||||
oct_set_reg(f_pSmearParams->pProcessContext, f_pSmearParams->ulWriteAddress + (x << 1), f_pSmearParams->usWriteData);
|
||||
}
|
||||
return cOCT6100_ERR_OK;
|
||||
}
|
||||
|
||||
UINT32 Oct6100UserDriverWriteBurstApi(tPOCT6100_WRITE_BURST_PARAMS f_pBurstParams)
|
||||
{
|
||||
unsigned int x;
|
||||
for (x=0;x<f_pBurstParams->ulWriteLength;x++) {
|
||||
oct_set_reg(f_pBurstParams->pProcessContext, f_pBurstParams->ulWriteAddress + (x << 1), f_pBurstParams->pusWriteData[x]);
|
||||
}
|
||||
return cOCT6100_ERR_OK;
|
||||
}
|
||||
|
||||
UINT32 Oct6100UserDriverReadApi(tPOCT6100_READ_PARAMS f_pReadParams)
|
||||
{
|
||||
*(f_pReadParams->pusReadData) = oct_get_reg(f_pReadParams->pProcessContext, f_pReadParams->ulReadAddress);
|
||||
return cOCT6100_ERR_OK;
|
||||
}
|
||||
|
||||
UINT32 Oct6100UserDriverReadBurstApi(tPOCT6100_READ_BURST_PARAMS f_pBurstParams)
|
||||
{
|
||||
unsigned int x;
|
||||
for (x=0;x<f_pBurstParams->ulReadLength;x++) {
|
||||
f_pBurstParams->pusReadData[x] = oct_get_reg(f_pBurstParams->pProcessContext, f_pBurstParams->ulReadAddress + (x << 1));
|
||||
}
|
||||
return cOCT6100_ERR_OK;
|
||||
}
|
||||
static const struct oct612x_ops wct4xxp_oct612x_ops = {
|
||||
.write = wct4xxp_oct612x_write,
|
||||
.read = wct4xxp_oct612x_read,
|
||||
.write_smear = wct4xxp_oct612x_write_smear,
|
||||
.write_burst = wct4xxp_oct612x_write_burst,
|
||||
.read_burst = wct4xxp_oct612x_read_burst,
|
||||
};
|
||||
|
||||
#define SOUT_G168_1100GB_ON 0x40000004
|
||||
#define SOUT_DTMF_1 0x40000011
|
||||
@@ -173,6 +136,7 @@ UINT32 Oct6100UserDriverReadBurstApi(tPOCT6100_READ_BURST_PARAMS f_pBurstParams)
|
||||
|
||||
struct vpm450m {
|
||||
tPOCT6100_INSTANCE_API pApiInstance;
|
||||
struct oct612x_context context;
|
||||
UINT32 aulEchoChanHndl[256];
|
||||
int chanflags[256];
|
||||
int ecmode[256];
|
||||
@@ -256,8 +220,10 @@ void vpm450m_set_alaw_companding(struct vpm450m *vpm450m, int channel,
|
||||
pr_notice("Failed to apply echo can changes on channel %d %d %08x!\n",
|
||||
vpm450m->aulEchoChanHndl[channel], channel, ulResult);
|
||||
} else {
|
||||
pr_info("Changed companding on channel %d to %s.\n", channel,
|
||||
(alaw) ? "alaw" : "ulaw");
|
||||
if (debug) {
|
||||
pr_info("Changed companding on channel %d to %s.\n",
|
||||
channel, (alaw) ? "alaw" : "ulaw");
|
||||
}
|
||||
if (alaw)
|
||||
vpm450m->chanflags[channel] |= FLAG_ALAW;
|
||||
else
|
||||
@@ -451,14 +417,18 @@ int vpm450m_getdtmf(struct vpm450m *vpm450m, int *channel, int *tone, int *start
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned int get_vpm450m_capacity(void *wc)
|
||||
unsigned int get_vpm450m_capacity(struct device *device)
|
||||
{
|
||||
struct oct612x_context context;
|
||||
UINT32 ulResult;
|
||||
|
||||
tOCT6100_API_GET_CAPACITY_PINS CapacityPins;
|
||||
|
||||
context.dev = device;
|
||||
context.ops = &wct4xxp_oct612x_ops;
|
||||
|
||||
Oct6100ApiGetCapacityPinsDef(&CapacityPins);
|
||||
CapacityPins.pProcessContext = wc;
|
||||
CapacityPins.pProcessContext = &context;
|
||||
CapacityPins.ulMemoryType = cOCT6100_MEM_TYPE_DDR;
|
||||
CapacityPins.fEnableMemClkOut = TRUE;
|
||||
CapacityPins.ulMemClkFreq = cOCT6100_MCLK_FREQ_133_MHZ;
|
||||
@@ -472,7 +442,8 @@ unsigned int get_vpm450m_capacity(void *wc)
|
||||
return CapacityPins.ulCapacityValue;
|
||||
}
|
||||
|
||||
struct vpm450m *init_vpm450m(void *wc, int *isalaw, int numspans, const struct firmware *firmware)
|
||||
struct vpm450m *init_vpm450m(struct device *device, int *isalaw,
|
||||
int numspans, const struct firmware *firmware)
|
||||
{
|
||||
tOCT6100_CHIP_OPEN *ChipOpen;
|
||||
tOCT6100_GET_INSTANCE_SIZE InstanceSize;
|
||||
@@ -487,6 +458,8 @@ struct vpm450m *init_vpm450m(void *wc, int *isalaw, int numspans, const struct f
|
||||
return NULL;
|
||||
|
||||
memset(vpm450m, 0, sizeof(struct vpm450m));
|
||||
vpm450m->context.dev = device;
|
||||
vpm450m->context.ops = &wct4xxp_oct612x_ops;
|
||||
|
||||
if (!(ChipOpen = kmalloc(sizeof(tOCT6100_CHIP_OPEN), GFP_KERNEL))) {
|
||||
kfree(vpm450m);
|
||||
@@ -515,7 +488,7 @@ struct vpm450m *init_vpm450m(void *wc, int *isalaw, int numspans, const struct f
|
||||
ChipOpen->ulUpclkFreq = cOCT6100_UPCLK_FREQ_33_33_MHZ;
|
||||
Oct6100GetInstanceSizeDef(&InstanceSize);
|
||||
|
||||
ChipOpen->pProcessContext = wc;
|
||||
ChipOpen->pProcessContext = &vpm450m->context;
|
||||
|
||||
ChipOpen->pbyImageFile = firmware->data;
|
||||
ChipOpen->ulImageSize = firmware->size;
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include <linux/firmware.h>
|
||||
|
||||
struct t4;
|
||||
struct vpm450m;
|
||||
|
||||
/* From driver */
|
||||
@@ -32,8 +33,9 @@ unsigned int oct_get_reg(void *data, unsigned int reg);
|
||||
void oct_set_reg(void *data, unsigned int reg, unsigned int val);
|
||||
|
||||
/* From vpm450m */
|
||||
struct vpm450m *init_vpm450m(void *wc, int *isalaw, int numspans, const struct firmware *firmware);
|
||||
unsigned int get_vpm450m_capacity(void *wc);
|
||||
struct vpm450m *init_vpm450m(struct device *device, int *isalaw,
|
||||
int numspans, const struct firmware *firmware);
|
||||
unsigned int get_vpm450m_capacity(struct device *device);
|
||||
void vpm450m_setec(struct vpm450m *instance, int channel, int eclen);
|
||||
void vpm450m_setdtmf(struct vpm450m *instance, int channel, int dtmfdetect, int dtmfmute);
|
||||
int vpm450m_checkirq(struct vpm450m *vpm450m);
|
||||
@@ -42,4 +44,6 @@ void release_vpm450m(struct vpm450m *instance);
|
||||
void vpm450m_set_alaw_companding(struct vpm450m *vpm450m,
|
||||
int channel, bool alaw);
|
||||
|
||||
extern int debug;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -3100,6 +3100,8 @@ wctdm_init_voicedaa(struct wctdm *wc, struct wctdm_module *mod,
|
||||
spin_unlock_irqrestore(&wc->reglock, flags);
|
||||
msleep(20);
|
||||
|
||||
memset(&mod->mod.fxo, 0, sizeof(mod->mod.fxo));
|
||||
|
||||
if (!sane && wctdm_voicedaa_insane(wc, mod))
|
||||
return -2;
|
||||
|
||||
@@ -3244,8 +3246,7 @@ wctdm_init_proslic(struct wctdm *wc, struct wctdm_module *const mod,
|
||||
return -2;
|
||||
|
||||
/* Initialize VMWI settings */
|
||||
memset(&(fxs->vmwisetting), 0, sizeof(fxs->vmwisetting));
|
||||
fxs->vmwi_linereverse = 0;
|
||||
memset(fxs, 0, sizeof(*fxs));
|
||||
|
||||
/* By default, don't send on hook */
|
||||
if (!reversepolarity != !fxs->reversepolarity)
|
||||
@@ -4384,32 +4385,6 @@ wctdm_chanconfig(struct file *file, struct dahdi_chan *chan, int sigtype)
|
||||
return wctdm_wait_for_ready(wc);
|
||||
}
|
||||
|
||||
/*
|
||||
* wctdm24xxp_assigned - Called when span is assigned.
|
||||
* @span: The span that is now assigned.
|
||||
*
|
||||
* This function is called by the core of DAHDI after the span number and
|
||||
* channel numbers have been assigned.
|
||||
*
|
||||
*/
|
||||
static void wctdm24xxp_assigned(struct dahdi_span *span)
|
||||
{
|
||||
struct dahdi_span *s;
|
||||
struct dahdi_device *ddev = span->parent;
|
||||
struct wctdm *wc = NULL;
|
||||
|
||||
list_for_each_entry(s, &ddev->spans, device_node) {
|
||||
wc = (container_of(s, struct wctdm_span, span))->wc;
|
||||
if (!test_bit(DAHDI_FLAGBIT_REGISTERED, &s->flags))
|
||||
return;
|
||||
}
|
||||
|
||||
if (wc) {
|
||||
WARN_ON(0 == wc->not_ready);
|
||||
--wc->not_ready;
|
||||
}
|
||||
}
|
||||
|
||||
static const struct dahdi_span_ops wctdm24xxp_analog_span_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.hooksig = wctdm_hooksig,
|
||||
@@ -4419,7 +4394,6 @@ static const struct dahdi_span_ops wctdm24xxp_analog_span_ops = {
|
||||
.watchdog = wctdm_watchdog,
|
||||
.chanconfig = wctdm_chanconfig,
|
||||
.dacs = wctdm_dacs,
|
||||
.assigned = wctdm24xxp_assigned,
|
||||
#ifdef VPM_SUPPORT
|
||||
.enable_hw_preechocan = wctdm_enable_hw_preechocan,
|
||||
.disable_hw_preechocan = wctdm_disable_hw_preechocan,
|
||||
@@ -4438,7 +4412,6 @@ static const struct dahdi_span_ops wctdm24xxp_digital_span_ops = {
|
||||
.spanconfig = b400m_spanconfig,
|
||||
.chanconfig = b400m_chanconfig,
|
||||
.dacs = wctdm_dacs,
|
||||
.assigned = wctdm24xxp_assigned,
|
||||
#ifdef VPM_SUPPORT
|
||||
.enable_hw_preechocan = wctdm_enable_hw_preechocan,
|
||||
.disable_hw_preechocan = wctdm_disable_hw_preechocan,
|
||||
@@ -5951,6 +5924,9 @@ __wctdm_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
|
||||
return -1;
|
||||
}
|
||||
|
||||
WARN_ON(wc->not_ready <= 0);
|
||||
--wc->not_ready;
|
||||
|
||||
dev_info(&wc->vb.pdev->dev,
|
||||
"Found a %s: %s (%d BRI spans, %d analog %s)\n",
|
||||
(is_hx8(wc)) ? "Hybrid card" : "Wildcard TDM",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
3575
drivers/dahdi/wcte43x-base.c
Normal file
3575
drivers/dahdi/wcte43x-base.c
Normal file
File diff suppressed because it is too large
Load Diff
1009
drivers/dahdi/wcxb.c
Normal file
1009
drivers/dahdi/wcxb.c
Normal file
File diff suppressed because it is too large
Load Diff
192
drivers/dahdi/wcxb.h
Normal file
192
drivers/dahdi/wcxb.h
Normal file
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* wcxb SPI library
|
||||
*
|
||||
* Copyright (C) 2013 Digium, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2 as published by the
|
||||
* Free Software Foundation. See the LICENSE file included with
|
||||
* this program for more details.
|
||||
*/
|
||||
|
||||
#ifndef __WCXB_H__
|
||||
#define __WCXB_H__
|
||||
|
||||
#define WCXB_DEFAULT_LATENCY 3U
|
||||
#define WCXB_DEFAULT_MAXLATENCY 20U
|
||||
#define WCXB_DMA_CHAN_SIZE 128
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24)
|
||||
/* The is_pcie member was backported but I'm not sure in which version. */
|
||||
# ifndef RHEL_RELEASE_VERSION
|
||||
#define WCXB_PCI_DEV_DOES_NOT_HAVE_IS_PCIE
|
||||
# endif
|
||||
#else
|
||||
#endif
|
||||
|
||||
struct wcxb;
|
||||
|
||||
struct wcxb_operations {
|
||||
void (*handle_receive)(struct wcxb *xb, void *frame);
|
||||
void (*handle_transmit)(struct wcxb *xb, void *frame);
|
||||
void (*handle_error)(struct wcxb *xb);
|
||||
void (*handle_interrupt)(struct wcxb *xb, u32 pending);
|
||||
};
|
||||
|
||||
struct wcxb_meta_desc;
|
||||
struct wcxb_hw_desc;
|
||||
|
||||
struct wcxb {
|
||||
struct pci_dev *pdev;
|
||||
spinlock_t lock;
|
||||
const struct wcxb_operations *ops;
|
||||
unsigned int *debug;
|
||||
unsigned int max_latency;
|
||||
unsigned int latency;
|
||||
struct {
|
||||
u32 have_msi:1;
|
||||
u32 latency_locked:1;
|
||||
u32 drive_timing_cable:1;
|
||||
#ifdef WCXB_PCI_DEV_DOES_NOT_HAVE_IS_PCIE
|
||||
u32 is_pcie:1;
|
||||
#endif
|
||||
} flags;
|
||||
void __iomem *membase;
|
||||
struct wcxb_meta_desc *meta_dring;
|
||||
struct wcxb_hw_desc *hw_dring;
|
||||
unsigned int dma_head;
|
||||
unsigned int dma_tail;
|
||||
dma_addr_t hw_dring_phys;
|
||||
struct dma_pool *pool;
|
||||
unsigned long framecount;
|
||||
};
|
||||
|
||||
extern int wcxb_init(struct wcxb *xb, const char *board_name, u32 int_mode);
|
||||
extern void wcxb_release(struct wcxb *xb);
|
||||
extern int wcxb_start(struct wcxb *xb);
|
||||
extern void wcxb_stop(struct wcxb *xb);
|
||||
extern int wcxb_wait_for_stop(struct wcxb *xb, unsigned long timeout_ms);
|
||||
extern bool wcxb_is_stopped(struct wcxb *xb);
|
||||
|
||||
enum wcxb_clock_sources {
|
||||
WCXB_CLOCK_SELF, /* Use the internal oscillator for timing. */
|
||||
WCXB_CLOCK_RECOVER, /* Recover the clock from a framer. */
|
||||
#ifdef RPC_RCLK
|
||||
WCXB_CLOCK_RECOVER_ALT, /* Recover the clock from a framer. */
|
||||
#endif
|
||||
WCXB_CLOCK_SLAVE /* Recover clock from any timing header. */
|
||||
};
|
||||
|
||||
extern enum wcxb_clock_sources wcxb_get_clksrc(struct wcxb *xb);
|
||||
extern void wcxb_set_clksrc(struct wcxb *xb, enum wcxb_clock_sources clksrc);
|
||||
|
||||
static inline void wcxb_enable_timing_header_driver(struct wcxb *xb)
|
||||
{
|
||||
xb->flags.drive_timing_cable = 1;
|
||||
}
|
||||
static inline bool wcxb_is_timing_header_driver_enabled(struct wcxb *xb)
|
||||
{
|
||||
return 1 == xb->flags.drive_timing_cable;
|
||||
}
|
||||
|
||||
static inline void wcxb_disable_timing_header_driver(struct wcxb *xb)
|
||||
{
|
||||
xb->flags.drive_timing_cable = 0;
|
||||
}
|
||||
|
||||
enum wcxb_reset_option {
|
||||
WCXB_RESET_NOW,
|
||||
WCXB_RESET_LATER
|
||||
};
|
||||
|
||||
extern u32 wcxb_get_firmware_version(struct wcxb *xb);
|
||||
extern int wcxb_check_firmware(struct wcxb *xb, const u32 expected_version,
|
||||
const char *firmware_filename,
|
||||
bool force_firmware,
|
||||
enum wcxb_reset_option reset);
|
||||
|
||||
extern void wcxb_stop_dma(struct wcxb *xb);
|
||||
extern void wcxb_disable_interrupts(struct wcxb *xb);
|
||||
|
||||
static inline void wcxb_gpio_set(struct wcxb *xb, u32 bits)
|
||||
{
|
||||
u32 reg;
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&xb->lock, flags);
|
||||
reg = ioread32be(xb->membase);
|
||||
iowrite32be(reg | bits, xb->membase);
|
||||
spin_unlock_irqrestore(&xb->lock, flags);
|
||||
}
|
||||
|
||||
static inline void wcxb_gpio_clear(struct wcxb *xb, u32 bits)
|
||||
{
|
||||
u32 reg;
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&xb->lock, flags);
|
||||
reg = ioread32be(xb->membase);
|
||||
iowrite32be(reg & (~bits), xb->membase);
|
||||
spin_unlock_irqrestore(&xb->lock, flags);
|
||||
}
|
||||
|
||||
static inline void
|
||||
wcxb_set_maxlatency(struct wcxb *xb, unsigned int max_latency)
|
||||
{
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&xb->lock, flags);
|
||||
xb->max_latency = clamp(max_latency,
|
||||
xb->latency,
|
||||
WCXB_DEFAULT_MAXLATENCY);
|
||||
spin_unlock_irqrestore(&xb->lock, flags);
|
||||
}
|
||||
|
||||
static inline void
|
||||
wcxb_set_minlatency(struct wcxb *xb, unsigned int min_latency)
|
||||
{
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&xb->lock, flags);
|
||||
xb->latency = clamp(min_latency, WCXB_DEFAULT_LATENCY,
|
||||
WCXB_DEFAULT_MAXLATENCY);
|
||||
spin_unlock_irqrestore(&xb->lock, flags);
|
||||
}
|
||||
|
||||
static inline void
|
||||
wcxb_lock_latency(struct wcxb *xb)
|
||||
{
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&xb->lock, flags);
|
||||
xb->flags.latency_locked = 1;
|
||||
spin_unlock_irqrestore(&xb->lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
static inline void
|
||||
wcxb_unlock_latency(struct wcxb *xb)
|
||||
{
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&xb->lock, flags);
|
||||
xb->flags.latency_locked = 0;
|
||||
spin_unlock_irqrestore(&xb->lock, flags);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Interface for the echocan block */
|
||||
extern void wcxb_enable_echocan(struct wcxb *xb);
|
||||
extern void wcxb_disable_echocan(struct wcxb *xb);
|
||||
extern void wcxb_reset_echocan(struct wcxb *xb);
|
||||
extern void wcxb_enable_echocan_dram(struct wcxb *xb);
|
||||
extern bool wcxb_is_echocan_present(struct wcxb *xb);
|
||||
extern u16 wcxb_get_echocan_reg(struct wcxb *xb, u32 address);
|
||||
extern void wcxb_set_echocan_reg(struct wcxb *xb, u32 address, u16 val);
|
||||
|
||||
#endif
|
||||
170
drivers/dahdi/wcxb_flash.c
Normal file
170
drivers/dahdi/wcxb_flash.c
Normal file
@@ -0,0 +1,170 @@
|
||||
/*
|
||||
* wcxb SPI library
|
||||
*
|
||||
* Copyright (C) 2013 Digium, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2 as published by the
|
||||
* Free Software Foundation. See the LICENSE file included with
|
||||
* this program for more details.
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include "wcxb_spi.h"
|
||||
#include "wcxb_flash.h"
|
||||
|
||||
#define FLASH_PAGE_PROGRAM 0x02
|
||||
#define FLASH_READ 0x03
|
||||
#define FLASH_READ_STATUS 0x05
|
||||
#define FLASH_WRITE_ENABLE 0x06
|
||||
#define FLASH_SECTOR_ERASE 0xd8
|
||||
|
||||
static int wcxb_flash_read_status_register(struct wcxb_spi_device *spi,
|
||||
u8 *status)
|
||||
{
|
||||
u8 command[] = {
|
||||
FLASH_READ_STATUS,
|
||||
};
|
||||
struct wcxb_spi_transfer t_cmd = {
|
||||
.tx_buf = command,
|
||||
.len = sizeof(command),
|
||||
};
|
||||
struct wcxb_spi_transfer t_serial = {
|
||||
.rx_buf = status,
|
||||
.len = 1,
|
||||
};
|
||||
struct wcxb_spi_message m;
|
||||
wcxb_spi_message_init(&m);
|
||||
wcxb_spi_message_add_tail(&t_cmd, &m);
|
||||
wcxb_spi_message_add_tail(&t_serial, &m);
|
||||
return wcxb_spi_sync(spi, &m);
|
||||
}
|
||||
|
||||
int wcxb_flash_read(struct wcxb_spi_device *spi, unsigned int address,
|
||||
void *data, size_t len)
|
||||
{
|
||||
u8 command[] = {
|
||||
FLASH_READ,
|
||||
(address & 0xff0000) >> 16,
|
||||
(address & 0xff00) >> 8,
|
||||
(address & 0xff)
|
||||
};
|
||||
struct wcxb_spi_transfer t_cmd = {
|
||||
.tx_buf = command,
|
||||
.len = sizeof(command),
|
||||
};
|
||||
struct wcxb_spi_transfer t_serial = {
|
||||
.rx_buf = data,
|
||||
.len = len,
|
||||
};
|
||||
struct wcxb_spi_message m;
|
||||
wcxb_spi_message_init(&m);
|
||||
wcxb_spi_message_add_tail(&t_cmd, &m);
|
||||
wcxb_spi_message_add_tail(&t_serial, &m);
|
||||
return wcxb_spi_sync(spi, &m);
|
||||
}
|
||||
|
||||
static int wcxb_flash_wait_until_not_busy(struct wcxb_spi_device *spi)
|
||||
{
|
||||
int res;
|
||||
u8 status;
|
||||
unsigned long stop = jiffies + 5*HZ;
|
||||
do {
|
||||
res = wcxb_flash_read_status_register(spi, &status);
|
||||
} while (!res && (status & 0x1) && time_before(jiffies, stop));
|
||||
if (!res)
|
||||
return res;
|
||||
if (time_after_eq(jiffies, stop))
|
||||
return -EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int wcxb_flash_write_enable(struct wcxb_spi_device *spi)
|
||||
{
|
||||
u8 command = FLASH_WRITE_ENABLE;
|
||||
return wcxb_spi_write(spi, &command, 1);
|
||||
}
|
||||
|
||||
int wcxb_flash_sector_erase(struct wcxb_spi_device *spi,
|
||||
unsigned int address)
|
||||
{
|
||||
int res;
|
||||
u8 command[] = {FLASH_SECTOR_ERASE, (address >> 16)&0xff, 0x00, 0x00};
|
||||
/* Sector must be on 64KB boundary. */
|
||||
if (address & 0xffff)
|
||||
return -EINVAL;
|
||||
/* Start the erase. */
|
||||
res = wcxb_flash_write_enable(spi);
|
||||
if (res)
|
||||
return res;
|
||||
res = wcxb_spi_write(spi, &command, sizeof(command));
|
||||
if (res)
|
||||
return res;
|
||||
return wcxb_flash_wait_until_not_busy(spi);
|
||||
}
|
||||
|
||||
int wcxb_flash_write(struct wcxb_spi_device *spi, unsigned int address,
|
||||
const void *data, size_t len)
|
||||
{
|
||||
int res;
|
||||
const size_t FLASH_PAGE_SIZE = 256;
|
||||
u8 command[] = {
|
||||
FLASH_PAGE_PROGRAM,
|
||||
(address & 0xff0000) >> 16,
|
||||
(address & 0xff00) >> 8,
|
||||
0x00,
|
||||
};
|
||||
struct wcxb_spi_transfer t_cmd = {
|
||||
.tx_buf = command,
|
||||
.len = sizeof(command),
|
||||
};
|
||||
struct wcxb_spi_transfer t_data = {
|
||||
.tx_buf = data,
|
||||
.len = len,
|
||||
};
|
||||
struct wcxb_spi_message m;
|
||||
|
||||
/* We need to write on page size boundaries */
|
||||
WARN_ON(address & 0xff);
|
||||
|
||||
wcxb_spi_message_init(&m);
|
||||
wcxb_spi_message_add_tail(&t_cmd, &m);
|
||||
wcxb_spi_message_add_tail(&t_data, &m);
|
||||
|
||||
while (len) {
|
||||
res = wcxb_flash_write_enable(spi);
|
||||
if (res)
|
||||
return res;
|
||||
command[1] = (address >> 16) & 0xff;
|
||||
command[2] = (address >> 8) & 0xff;
|
||||
t_data.tx_buf = data;
|
||||
t_data.len = min(len, FLASH_PAGE_SIZE);
|
||||
res = wcxb_spi_sync(spi, &m);
|
||||
WARN_ON(res);
|
||||
if (res)
|
||||
return res;
|
||||
res = wcxb_flash_wait_until_not_busy(spi);
|
||||
WARN_ON(res);
|
||||
if (res)
|
||||
return res;
|
||||
len -= t_data.len;
|
||||
address += t_data.len;
|
||||
data += t_data.len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
34
drivers/dahdi/wcxb_flash.h
Normal file
34
drivers/dahdi/wcxb_flash.h
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* wcxb SPI library
|
||||
*
|
||||
* Copyright (C) 2013 Digium, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2 as published by the
|
||||
* Free Software Foundation. See the LICENSE file included with
|
||||
* this program for more details.
|
||||
*/
|
||||
|
||||
#ifndef __WCXB_FLASH_H__
|
||||
#define __WCXB_FLASH_H__
|
||||
|
||||
extern int wcxb_flash_read(struct wcxb_spi_device *spi, unsigned int address,
|
||||
void *data, size_t len);
|
||||
|
||||
extern int wcxb_flash_sector_erase(struct wcxb_spi_device *spi, unsigned int
|
||||
address);
|
||||
extern int wcxb_flash_write(struct wcxb_spi_device *spi, unsigned int address,
|
||||
const void *data, size_t len);
|
||||
|
||||
#endif
|
||||
386
drivers/dahdi/wcxb_spi.c
Normal file
386
drivers/dahdi/wcxb_spi.c
Normal file
@@ -0,0 +1,386 @@
|
||||
/*
|
||||
* wcxb SPI library
|
||||
*
|
||||
* Copyright (C) 2013 Digium, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2 as published by the
|
||||
* Free Software Foundation. See the LICENSE file included with
|
||||
* this program for more details.
|
||||
*/
|
||||
|
||||
#define DEBUG
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/completion.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
#include <linux/io.h>
|
||||
|
||||
#include <dahdi/kernel.h>
|
||||
|
||||
#include "wcxb_spi.h"
|
||||
|
||||
#define BBIT(n) (1UL << (31UL - (n)))
|
||||
|
||||
#define SPISRR 0x40
|
||||
#define SPISRR_RESET 0x0000000a /* Resets Device */
|
||||
|
||||
#define SPICR 0x60
|
||||
#define SPICR_LSB_FIRST BBIT(22) /* LSB First. 0=MSB first transfer */
|
||||
#define SPICR_MASTER_INHIBIT BBIT(23) /* Master Transaction Inhibit */
|
||||
#define SPICR_SLAVE_SELECT BBIT(24) /* Manual Slave Select Assert Enable */
|
||||
#define SPICR_RX_FIFO_RESET BBIT(25) /* Receive FIFO Reset */
|
||||
#define SPICR_TX_FIFO_RESET BBIT(26) /* Transmit FIFO Reset */
|
||||
#define SPICR_CPHA BBIT(27) /* Clock Phase */
|
||||
#define SPICR_CPOL BBIT(28) /* Clock Polarity 0=Active High */
|
||||
#define SPICR_MASTER BBIT(29) /* Master Enable */
|
||||
#define SPICR_SPE BBIT(30) /* SPI System Enable */
|
||||
#define SPICR_LOOP BBIT(31) /* Local Loopback Mode */
|
||||
|
||||
#define SPICR_START_TRANSFER (SPICR_CPHA | SPICR_CPOL | \
|
||||
SPICR_MASTER | SPICR_SPE)
|
||||
#define SPICR_READY_TRANSFER (SPICR_MASTER_INHIBIT | SPICR_START_TRANSFER)
|
||||
|
||||
#define SPISR 0x64 /* SPI Status Register */
|
||||
#define SPISR_SLAVE_MODE_SEL BBIT(26) /* Slave Mode Select Flag */
|
||||
#define SPISR_MODF BBIT(27) /* Mode-Fault Error Flag */
|
||||
#define SPISR_TX_FULL BBIT(28) /* Transmit FIFO Full */
|
||||
#define SPISR_TX_EMPTY BBIT(29) /* Transmit FIFO Empty */
|
||||
#define SPISR_RX_FULL BBIT(30) /* Receive FIFO Full */
|
||||
#define SPISR_RX_EMPTY BBIT(31) /* Receive FIFO Empty */
|
||||
|
||||
#define SPIDTR 0x68 /* SPI Data Transmit Register */
|
||||
#define SPIDRR 0x6c /* SPI Data Receive Register */
|
||||
|
||||
#define SPISSR 0x70 /* SPI Slave Select Register */
|
||||
|
||||
#undef SUCCESS
|
||||
#define SUCCESS 0
|
||||
|
||||
struct wcxb_spi_master {
|
||||
struct device *parent;
|
||||
struct list_head message_queue;
|
||||
spinlock_t lock;
|
||||
void __iomem *base;
|
||||
struct wcxb_spi_message *cur_msg;
|
||||
struct wcxb_spi_transfer *cur_transfer;
|
||||
u16 bytes_left;
|
||||
u16 bytes_in_fifo;
|
||||
const u8 *cur_tx_byte;
|
||||
u8 *cur_rx_byte;
|
||||
u16 auto_cs:1;
|
||||
};
|
||||
|
||||
static inline void _wcxb_assert_chip_select(struct wcxb_spi_master *master,
|
||||
unsigned int cs)
|
||||
{
|
||||
const int cs_mask = ~(1UL << cs);
|
||||
iowrite32be(cs_mask, master->base + SPISSR);
|
||||
ioread32be(master->base + SPISSR);
|
||||
}
|
||||
|
||||
static inline void _wcxb_clear_chip_select(struct wcxb_spi_master *master)
|
||||
{
|
||||
iowrite32be(~(0), master->base + SPISSR);
|
||||
ioread32(master->base + SPISSR);
|
||||
}
|
||||
|
||||
static inline void wcxb_spi_reset_controller(struct wcxb_spi_master *master)
|
||||
{
|
||||
u32 spicr = SPICR_READY_TRANSFER;
|
||||
spicr |= (master->auto_cs) ? 0 : SPICR_SLAVE_SELECT;
|
||||
iowrite32be(SPISRR_RESET, master->base + SPISRR);
|
||||
iowrite32be(spicr, master->base + SPICR);
|
||||
iowrite32be(0xffffffff, master->base + SPISSR);
|
||||
}
|
||||
|
||||
struct wcxb_spi_master *wcxb_spi_master_create(struct device *parent,
|
||||
void __iomem *membase,
|
||||
bool auto_cs)
|
||||
{
|
||||
struct wcxb_spi_master *master = NULL;
|
||||
master = kzalloc(sizeof(struct wcxb_spi_master), GFP_KERNEL);
|
||||
if (!master)
|
||||
goto error_exit;
|
||||
|
||||
spin_lock_init(&master->lock);
|
||||
INIT_LIST_HEAD(&master->message_queue);
|
||||
master->base = membase;
|
||||
master->parent = parent;
|
||||
|
||||
master->auto_cs = (auto_cs) ? 1 : 0;
|
||||
wcxb_spi_reset_controller(master);
|
||||
return master;
|
||||
|
||||
error_exit:
|
||||
kfree(master);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void wcxb_spi_master_destroy(struct wcxb_spi_master *master)
|
||||
{
|
||||
struct wcxb_spi_message *m;
|
||||
if (!master)
|
||||
return;
|
||||
while (!list_empty(&master->message_queue)) {
|
||||
m = list_first_entry(&master->message_queue,
|
||||
struct wcxb_spi_message, node);
|
||||
list_del(&m->node);
|
||||
if (m->complete)
|
||||
m->complete(m->arg);
|
||||
}
|
||||
kfree(master);
|
||||
return;
|
||||
}
|
||||
|
||||
static inline bool is_txfifo_empty(const struct wcxb_spi_master *master)
|
||||
{
|
||||
return ((ioread32(master->base + SPISR) &
|
||||
cpu_to_be32(SPISR_TX_EMPTY)) > 0);
|
||||
}
|
||||
|
||||
static const u8 DUMMY_TX = 0xff;
|
||||
static u8 DUMMY_RX;
|
||||
|
||||
static void _wcxb_spi_transfer_to_fifo(struct wcxb_spi_master *master)
|
||||
{
|
||||
const unsigned int FIFO_SIZE = 16;
|
||||
u32 spicr;
|
||||
while (master->bytes_left && master->bytes_in_fifo < FIFO_SIZE) {
|
||||
iowrite32be(*master->cur_tx_byte, master->base + SPIDTR);
|
||||
master->bytes_in_fifo++;
|
||||
master->bytes_left--;
|
||||
if (&DUMMY_TX != master->cur_tx_byte)
|
||||
master->cur_tx_byte++;
|
||||
}
|
||||
|
||||
spicr = (master->auto_cs) ? SPICR_START_TRANSFER :
|
||||
SPICR_START_TRANSFER | SPICR_SLAVE_SELECT;
|
||||
iowrite32be(spicr, master->base + SPICR);
|
||||
}
|
||||
|
||||
static void _wcxb_spi_transfer_from_fifo(struct wcxb_spi_master *master)
|
||||
{
|
||||
u32 spicr;
|
||||
while (master->bytes_in_fifo) {
|
||||
*master->cur_rx_byte = ioread32be(master->base + SPIDRR);
|
||||
if (&DUMMY_RX != master->cur_rx_byte)
|
||||
master->cur_rx_byte++;
|
||||
--master->bytes_in_fifo;
|
||||
}
|
||||
|
||||
spicr = SPICR_START_TRANSFER;
|
||||
spicr |= (master->auto_cs) ? 0 : SPICR_SLAVE_SELECT;
|
||||
iowrite32be(spicr | SPICR_MASTER_INHIBIT, master->base + SPICR);
|
||||
}
|
||||
|
||||
static void _wcxb_spi_start_transfer(struct wcxb_spi_master *master,
|
||||
struct wcxb_spi_transfer *t)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (!t || !master || (!t->tx_buf && !t->rx_buf) ||
|
||||
master->cur_transfer) {
|
||||
WARN_ON(1);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
master->cur_transfer = t;
|
||||
master->bytes_left = t->len;
|
||||
master->cur_tx_byte = (t->tx_buf) ?: &DUMMY_TX;
|
||||
master->cur_rx_byte = (t->rx_buf) ?: &DUMMY_RX;
|
||||
|
||||
_wcxb_spi_transfer_to_fifo(master);
|
||||
}
|
||||
|
||||
/**
|
||||
* _wcxb_spi_start_message - Start a new message transferring.
|
||||
*
|
||||
* Must be called with master->lock held.
|
||||
*
|
||||
*/
|
||||
static int _wcxb_spi_start_message(struct wcxb_spi_master *master,
|
||||
struct wcxb_spi_message *message)
|
||||
{
|
||||
struct wcxb_spi_transfer *t;
|
||||
|
||||
if (master->cur_msg) {
|
||||
/* There is already a message in progress. Queue for later. */
|
||||
list_add_tail(&message->node, &master->message_queue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!message->spi) {
|
||||
dev_dbg(master->parent,
|
||||
"Queueing message without SPI device specified?\n");
|
||||
return -EINVAL;
|
||||
};
|
||||
|
||||
master->cur_msg = message;
|
||||
|
||||
_wcxb_assert_chip_select(master, message->spi->chip_select);
|
||||
t = list_first_entry(&message->transfers,
|
||||
struct wcxb_spi_transfer, node);
|
||||
_wcxb_spi_start_transfer(master, t);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* wcxb_spi_complete_message - Complete the current message.
|
||||
*
|
||||
* Called after all transfers in current message have been completed. This will
|
||||
* complete the current message and start the next queued message if there are
|
||||
* any.
|
||||
*
|
||||
* Must be called with the master->lock held.
|
||||
*
|
||||
*/
|
||||
static void _wcxb_spi_complete_cur_msg(struct wcxb_spi_master *master)
|
||||
{
|
||||
struct wcxb_spi_message *message;
|
||||
if (!master->cur_msg)
|
||||
return;
|
||||
message = master->cur_msg;
|
||||
message->status = SUCCESS;
|
||||
_wcxb_clear_chip_select(master);
|
||||
master->cur_msg = NULL;
|
||||
if (!list_empty(&master->message_queue)) {
|
||||
message = list_first_entry(&master->message_queue,
|
||||
struct wcxb_spi_message, node);
|
||||
list_del(&message->node);
|
||||
_wcxb_spi_start_message(master, message);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static inline bool
|
||||
_wcxb_spi_is_last_transfer(const struct wcxb_spi_transfer *t,
|
||||
const struct wcxb_spi_message *message)
|
||||
{
|
||||
return t->node.next == &message->transfers;
|
||||
}
|
||||
|
||||
static inline struct wcxb_spi_transfer *
|
||||
_wcxb_spi_next_transfer(struct wcxb_spi_transfer *t)
|
||||
{
|
||||
return list_entry(t->node.next, struct wcxb_spi_transfer, node);
|
||||
}
|
||||
|
||||
/**
|
||||
* wcxb_spi_handle_interrupt - Drives the transfers forward.
|
||||
*
|
||||
* Doesn't necessarily need to be called in the context of a real interrupt, but
|
||||
* should be called with interrupts disabled on the local CPU.
|
||||
*
|
||||
*/
|
||||
void wcxb_spi_handle_interrupt(struct wcxb_spi_master *master)
|
||||
{
|
||||
struct wcxb_spi_message *msg;
|
||||
struct wcxb_spi_transfer *t;
|
||||
void (*complete)(void *arg) = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
/* Check if we're not in the middle of a transfer, or not finished with
|
||||
* a part of one. */
|
||||
spin_lock_irqsave(&master->lock, flags);
|
||||
|
||||
t = master->cur_transfer;
|
||||
msg = master->cur_msg;
|
||||
|
||||
if (!msg || !is_txfifo_empty(master))
|
||||
goto done;
|
||||
|
||||
#ifdef DEBUG
|
||||
if (!t) {
|
||||
dev_dbg(master->parent,
|
||||
"No current transfer in %s\n", __func__);
|
||||
goto done;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* First read any data out of the receive FIFO into the current
|
||||
* transfer. */
|
||||
_wcxb_spi_transfer_from_fifo(master);
|
||||
if (master->bytes_left) {
|
||||
/* The current transfer isn't finished. */
|
||||
_wcxb_spi_transfer_to_fifo(master);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* The current transfer is finished. Check for another transfer in this
|
||||
* message or complete it and look for another message to start. */
|
||||
master->cur_transfer = NULL;
|
||||
|
||||
if (_wcxb_spi_is_last_transfer(t, msg)) {
|
||||
complete = msg->complete;
|
||||
_wcxb_spi_complete_cur_msg(master);
|
||||
} else {
|
||||
t = _wcxb_spi_next_transfer(t);
|
||||
_wcxb_spi_start_transfer(master, t);
|
||||
}
|
||||
done:
|
||||
spin_unlock_irqrestore(&master->lock, flags);
|
||||
/* Do not call the complete call back under the bus lock. */
|
||||
if (complete)
|
||||
complete(msg->arg);
|
||||
return;
|
||||
}
|
||||
|
||||
int wcxb_spi_async(struct wcxb_spi_device *spi,
|
||||
struct wcxb_spi_message *message)
|
||||
{
|
||||
int res;
|
||||
unsigned long flags;
|
||||
WARN_ON(!spi || !message || !spi->master);
|
||||
|
||||
if (list_empty(&message->transfers)) {
|
||||
/* No transfers in this message? */
|
||||
if (message->complete)
|
||||
message->complete(message->arg);
|
||||
message->status = -EINVAL;
|
||||
return 0;
|
||||
}
|
||||
message->status = -EINPROGRESS;
|
||||
message->spi = spi;
|
||||
spin_lock_irqsave(&spi->master->lock, flags);
|
||||
res = _wcxb_spi_start_message(spi->master, message);
|
||||
spin_unlock_irqrestore(&spi->master->lock, flags);
|
||||
return res;
|
||||
}
|
||||
|
||||
static void wcxb_spi_complete_message(void *arg)
|
||||
{
|
||||
complete((struct completion *)arg);
|
||||
}
|
||||
|
||||
int wcxb_spi_sync(struct wcxb_spi_device *spi, struct wcxb_spi_message *message)
|
||||
{
|
||||
DECLARE_COMPLETION_ONSTACK(done);
|
||||
WARN_ON(!spi || !spi->master);
|
||||
message->complete = wcxb_spi_complete_message;
|
||||
message->arg = &done;
|
||||
wcxb_spi_async(spi, message);
|
||||
|
||||
/* TODO: There has got to be a better way to do this. */
|
||||
while (!try_wait_for_completion(&done)) {
|
||||
wcxb_spi_handle_interrupt(spi->master);
|
||||
cpu_relax();
|
||||
}
|
||||
return message->status;
|
||||
}
|
||||
116
drivers/dahdi/wcxb_spi.h
Normal file
116
drivers/dahdi/wcxb_spi.h
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* wcxb SPI library
|
||||
*
|
||||
* Copyright (C) 2013 Digium, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* See http://www.asterisk.org for more information about
|
||||
* the Asterisk project. Please do not directly contact
|
||||
* any of the maintainers of this project for assistance;
|
||||
* the project provides a web site, mailing lists and IRC
|
||||
* channels for your use.
|
||||
*
|
||||
* This program is free software, distributed under the terms of
|
||||
* the GNU General Public License Version 2 as published by the
|
||||
* Free Software Foundation. See the LICENSE file included with
|
||||
* this program for more details.
|
||||
*/
|
||||
|
||||
#ifndef __WCXB_SPI_H
|
||||
#define __WCXB_SPI_H
|
||||
|
||||
#include <linux/spi/spi.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
struct wcxb_spi_transfer {
|
||||
const void *tx_buf;
|
||||
void *rx_buf;
|
||||
u32 len:16;
|
||||
u16 delay_usecs;
|
||||
struct list_head node;
|
||||
};
|
||||
|
||||
struct wcxb_spi_message {
|
||||
struct list_head transfers;
|
||||
struct list_head node;
|
||||
struct wcxb_spi_device *spi;
|
||||
void (*complete)(void *arg);
|
||||
void *arg;
|
||||
int status;
|
||||
};
|
||||
|
||||
struct wcxb_spi_master;
|
||||
|
||||
struct wcxb_spi_device {
|
||||
struct wcxb_spi_master *master;
|
||||
u16 chip_select;
|
||||
};
|
||||
|
||||
extern struct wcxb_spi_master *wcxb_spi_master_create(struct device *parent,
|
||||
void __iomem *base, bool auto_cs);
|
||||
extern void wcxb_spi_master_destroy(struct wcxb_spi_master *master);
|
||||
extern int wcxb_spi_sync(struct wcxb_spi_device *spi,
|
||||
struct wcxb_spi_message *message);
|
||||
extern int wcxb_spi_async(struct wcxb_spi_device *spi,
|
||||
struct wcxb_spi_message *message);
|
||||
extern void wcxb_spi_handle_interrupt(struct wcxb_spi_master *master);
|
||||
|
||||
static inline struct wcxb_spi_device *
|
||||
wcxb_spi_device_create(struct wcxb_spi_master *master, u16 chip_select)
|
||||
{
|
||||
struct wcxb_spi_device *spi = kzalloc(sizeof(*spi), GFP_KERNEL);
|
||||
if (!spi)
|
||||
return NULL;
|
||||
spi->master = master;
|
||||
spi->chip_select = chip_select;
|
||||
return spi;
|
||||
}
|
||||
|
||||
static inline void wcxb_spi_device_destroy(struct wcxb_spi_device *spi)
|
||||
{
|
||||
kfree(spi);
|
||||
}
|
||||
|
||||
static inline void wcxb_spi_message_init(struct wcxb_spi_message *m)
|
||||
{
|
||||
memset(m, 0, sizeof(*m));
|
||||
INIT_LIST_HEAD(&m->transfers);
|
||||
}
|
||||
|
||||
static inline void wcxb_spi_message_add_tail(struct wcxb_spi_transfer *t,
|
||||
struct wcxb_spi_message *m)
|
||||
{
|
||||
list_add_tail(&t->node, &m->transfers);
|
||||
}
|
||||
|
||||
static inline int
|
||||
wcxb_spi_write(struct wcxb_spi_device *spi, const void *buffer, size_t len)
|
||||
{
|
||||
struct wcxb_spi_transfer t = {
|
||||
.tx_buf = buffer,
|
||||
.len = len,
|
||||
};
|
||||
struct wcxb_spi_message m;
|
||||
wcxb_spi_message_init(&m);
|
||||
wcxb_spi_message_add_tail(&t, &m);
|
||||
return wcxb_spi_sync(spi, &m);
|
||||
}
|
||||
|
||||
static inline int
|
||||
wcxb_spi_read(struct wcxb_spi_device *spi, void *buffer, size_t len)
|
||||
{
|
||||
struct wcxb_spi_transfer t = {
|
||||
.rx_buf = buffer,
|
||||
.len = len,
|
||||
};
|
||||
struct wcxb_spi_message m;
|
||||
wcxb_spi_message_init(&m);
|
||||
wcxb_spi_message_add_tail(&t, &m);
|
||||
return wcxb_spi_sync(spi, &m);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -654,6 +654,95 @@ static void __do_mute_dtmf(xpd_t *xpd, int pos, bool muteit)
|
||||
CALL_PHONE_METHOD(card_pcm_recompute, xpd, priv->search_fsk_pattern);
|
||||
}
|
||||
|
||||
struct ring_reg_param {
|
||||
int is_indirect;
|
||||
int regno;
|
||||
uint8_t h_val;
|
||||
uint8_t l_val;
|
||||
};
|
||||
|
||||
enum ring_types {
|
||||
RING_TYPE_NEON = 0,
|
||||
RING_TYPE_TRAPEZ,
|
||||
RING_TYPE_NORMAL,
|
||||
};
|
||||
|
||||
struct byte_pair {
|
||||
uint8_t h_val;
|
||||
uint8_t l_val;
|
||||
};
|
||||
|
||||
struct ring_reg_params {
|
||||
const int is_indirect;
|
||||
const int regno;
|
||||
struct byte_pair values[1 + RING_TYPE_NORMAL - RING_TYPE_NEON];
|
||||
};
|
||||
|
||||
#define REG_ENTRY(di, reg, vh1, vl1, vh2, vl2, vh3, vl3) \
|
||||
{ (di), (reg), .values = { \
|
||||
[RING_TYPE_NEON] = { .h_val = (vh1), .l_val = (vl1) }, \
|
||||
[RING_TYPE_TRAPEZ] = { .h_val = (vh2), .l_val = (vl2) }, \
|
||||
[RING_TYPE_NORMAL] = { .h_val = (vh3), .l_val = (vl3) }, \
|
||||
}, \
|
||||
}
|
||||
|
||||
static struct ring_reg_params ring_parameters[] = {
|
||||
/* INDIR REG NEON TRAPEZ NORMAL */
|
||||
REG_ENTRY(1, 0x16, 0xE8, 0x03, 0xC8, 0x00, 0x00, 0x00),
|
||||
REG_ENTRY(1, 0x15, 0xEF, 0x7B, 0xAB, 0x5E, 0x77, 0x01),
|
||||
REG_ENTRY(1, 0x14, 0x9F, 0x00, 0x8C, 0x01, 0xFD, 0x7E),
|
||||
|
||||
REG_ENTRY(0, 0x22, 0x00, 0x19, 0x00, 0x01, 0x00, 0x00),
|
||||
|
||||
REG_ENTRY(0, 0x30, 0x00, 0xE0, 0x00, 0x00, 0x00, 0x00),
|
||||
REG_ENTRY(0, 0x31, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00),
|
||||
REG_ENTRY(0, 0x32, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00),
|
||||
REG_ENTRY(0, 0x33, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00),
|
||||
|
||||
REG_ENTRY(1, 0x1D, 0x00, 0x46, 0x00, 0x36, 0x00, 0x36),
|
||||
};
|
||||
|
||||
static int send_ring_parameters(xbus_t *xbus, xpd_t *xpd, int pos,
|
||||
enum ring_types rtype)
|
||||
{
|
||||
const struct ring_reg_params *p;
|
||||
const struct byte_pair *v;
|
||||
int ret = 0;
|
||||
int i;
|
||||
|
||||
if (rtype < RING_TYPE_NEON || rtype > RING_TYPE_NORMAL)
|
||||
return -EINVAL;
|
||||
for (i = 0; i < ARRAY_SIZE(ring_parameters); i++) {
|
||||
p = &ring_parameters[i];
|
||||
v = &(p->values[rtype]);
|
||||
if (p->is_indirect) {
|
||||
LINE_DBG(REGS, xpd, pos,
|
||||
"[%d] 0x%02X: I 0x%02X 0x%02X\n",
|
||||
i, p->regno, v->h_val, v->l_val);
|
||||
ret = SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE,
|
||||
p->regno, v->h_val, v->l_val);
|
||||
if (ret < 0) {
|
||||
LINE_ERR(xpd, pos,
|
||||
"Failed: 0x%02X: I 0x%02X, 0x%02X\n",
|
||||
p->regno, v->h_val, v->l_val);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
LINE_DBG(REGS, xpd, pos, "[%d] 0x%02X: D 0x%02X\n",
|
||||
i, p->regno, v->l_val);
|
||||
ret = SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE,
|
||||
p->regno, v->l_val);
|
||||
if (ret < 0) {
|
||||
LINE_ERR(xpd, pos,
|
||||
"Failed: 0x%02X: D 0x%02X\n",
|
||||
p->regno, v->l_val);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int set_vm_led_mode(xbus_t *xbus, xpd_t *xpd, int pos,
|
||||
unsigned int msg_waiting)
|
||||
{
|
||||
@@ -667,81 +756,15 @@ static int set_vm_led_mode(xbus_t *xbus, xpd_t *xpd, int pos,
|
||||
/* A write to register 0x40 will now turn on/off the VM led */
|
||||
LINE_DBG(SIGNAL, xpd, pos, "NEON\n");
|
||||
BIT_SET(priv->neon_blinking, pos);
|
||||
ret +=
|
||||
SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x16,
|
||||
0xE8, 0x03);
|
||||
ret +=
|
||||
SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x15,
|
||||
0xEF, 0x7B);
|
||||
ret +=
|
||||
SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x14,
|
||||
0x9F, 0x00);
|
||||
ret +=
|
||||
SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x22, 0x19);
|
||||
ret +=
|
||||
SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x30, 0xE0);
|
||||
ret +=
|
||||
SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x31, 0x01);
|
||||
ret +=
|
||||
SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x32, 0xF0);
|
||||
ret +=
|
||||
SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x33, 0x05);
|
||||
ret +=
|
||||
SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x1D,
|
||||
0x00, 0x46);
|
||||
ret = send_ring_parameters(xbus, xpd, pos, RING_TYPE_NEON);
|
||||
} else if (ring_trapez) {
|
||||
LINE_DBG(SIGNAL, xpd, pos, "RINGER: Trapez ring\n");
|
||||
ret +=
|
||||
SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x16,
|
||||
0xC8, 0x00);
|
||||
ret +=
|
||||
SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x15,
|
||||
0xAB, 0x5E);
|
||||
ret +=
|
||||
SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x14,
|
||||
0x8C, 0x01);
|
||||
ret +=
|
||||
SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x22, 0x01);
|
||||
ret +=
|
||||
SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x4A, 0x34);
|
||||
ret +=
|
||||
SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x30, 0x00);
|
||||
ret +=
|
||||
SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x31, 0x00);
|
||||
ret +=
|
||||
SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x32, 0x00);
|
||||
ret +=
|
||||
SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x33, 0x00);
|
||||
ret +=
|
||||
SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x1D,
|
||||
0x00, 0x36);
|
||||
ret = send_ring_parameters(xbus, xpd, pos, RING_TYPE_TRAPEZ);
|
||||
} else {
|
||||
/* A write to register 0x40 will now turn on/off the ringer */
|
||||
LINE_DBG(SIGNAL, xpd, pos, "RINGER\n");
|
||||
BIT_CLR(priv->neon_blinking, pos);
|
||||
|
||||
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE,
|
||||
0x16, 0x00, 0x00);
|
||||
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE,
|
||||
0x15, 0x77, 0x01);
|
||||
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE,
|
||||
0x14, 0xFD, 0x7E);
|
||||
|
||||
ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE,
|
||||
0x22, 0x00);
|
||||
ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE,
|
||||
0x30, 0x00);
|
||||
ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE,
|
||||
0x31, 0x00);
|
||||
ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE,
|
||||
0x32, 0x00);
|
||||
ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE,
|
||||
0x33, 0x00);
|
||||
/* High Vbat~ -82V[Dc] */
|
||||
ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE,
|
||||
0x4A, 0x34);
|
||||
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE,
|
||||
0x1D, 0x00, 0x36);
|
||||
ret = send_ring_parameters(xbus, xpd, pos, RING_TYPE_NORMAL);
|
||||
}
|
||||
return (ret ? -EPROTO : 0);
|
||||
}
|
||||
@@ -1838,9 +1861,134 @@ static const struct file_operations proc_xpd_metering_ops = {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static DEVICE_ATTR_READER(fxs_ring_registers_show, dev, buf)
|
||||
{
|
||||
xpd_t *xpd;
|
||||
struct FXS_priv_data *priv;
|
||||
unsigned long flags;
|
||||
const struct ring_reg_params *p;
|
||||
const struct byte_pair *v;
|
||||
enum ring_types rtype;
|
||||
int len = 0;
|
||||
int i;
|
||||
|
||||
BUG_ON(!dev);
|
||||
xpd = dev_to_xpd(dev);
|
||||
if (!xpd)
|
||||
return -ENODEV;
|
||||
priv = xpd->priv;
|
||||
BUG_ON(!priv);
|
||||
spin_lock_irqsave(&xpd->lock, flags);
|
||||
len += sprintf(buf + len, "# Reg#: D/I\tNEON \tTRAPEZ \tNORMAL \n");
|
||||
for (i = 0; i < ARRAY_SIZE(ring_parameters); i++) {
|
||||
p = &ring_parameters[i];
|
||||
len += sprintf(buf + len, "[%d] 0x%02X: %c",
|
||||
i, p->regno, (p->is_indirect) ? 'I' : 'D');
|
||||
for (rtype = RING_TYPE_NEON; rtype <= RING_TYPE_NORMAL; rtype++) {
|
||||
v = &(p->values[rtype]);
|
||||
if (p->is_indirect)
|
||||
len += sprintf(buf + len, "\t0x%02X 0x%02X",
|
||||
v->h_val, v->l_val);
|
||||
else
|
||||
len += sprintf(buf + len, "\t0x%02X ----",
|
||||
v->l_val);
|
||||
}
|
||||
len += sprintf(buf + len, "\n");
|
||||
}
|
||||
spin_unlock_irqrestore(&xpd->lock, flags);
|
||||
return len;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_WRITER(fxs_ring_registers_store, dev, buf, count)
|
||||
{
|
||||
xpd_t *xpd;
|
||||
struct FXS_priv_data *priv;
|
||||
unsigned long flags;
|
||||
char rtype_name[MAX_PROC_WRITE];
|
||||
enum ring_types rtype;
|
||||
struct ring_reg_params *params;
|
||||
struct byte_pair *v;
|
||||
int regno;
|
||||
int h_val;
|
||||
int l_val;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
BUG_ON(!dev);
|
||||
xpd = dev_to_xpd(dev);
|
||||
if (!xpd)
|
||||
return -ENODEV;
|
||||
priv = xpd->priv;
|
||||
BUG_ON(!priv);
|
||||
ret = sscanf(buf, "%10s %X %X %X\n",
|
||||
rtype_name, ®no, &h_val, &l_val);
|
||||
if (ret < 3 || ret > 4) {
|
||||
XPD_ERR(xpd, "Bad input: '%s'\n", buf);
|
||||
XPD_ERR(xpd, "# Correct input\n");
|
||||
XPD_ERR(xpd, "{NEON|TRAPEZ|NORMAL} <regno> <byte> [<byte>]\n");
|
||||
goto invalid_input;
|
||||
}
|
||||
if (strcasecmp("NEON", rtype_name) == 0)
|
||||
rtype = RING_TYPE_NEON;
|
||||
else if (strcasecmp("TRAPEZ", rtype_name) == 0)
|
||||
rtype = RING_TYPE_TRAPEZ;
|
||||
else if (strcasecmp("NORMAL", rtype_name) == 0)
|
||||
rtype = RING_TYPE_NORMAL;
|
||||
else {
|
||||
XPD_ERR(xpd, "Unknown ring type '%s' (NEON/TRAPEZ/NORMAL)\n",
|
||||
rtype_name);
|
||||
goto invalid_input;
|
||||
}
|
||||
params = NULL;
|
||||
for (i = 0; i < ARRAY_SIZE(ring_parameters); i++) {
|
||||
if (ring_parameters[i].regno == regno) {
|
||||
params = &ring_parameters[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!params) {
|
||||
XPD_ERR(xpd, "Bad register 0x%X\n", regno);
|
||||
goto invalid_input;
|
||||
}
|
||||
if (params->is_indirect) {
|
||||
if (ret != 4) {
|
||||
XPD_ERR(xpd,
|
||||
"Missing low-byte (0x%X is indirect register)\n",
|
||||
regno);
|
||||
goto invalid_input;
|
||||
}
|
||||
XPD_INFO(xpd, "%s Indirect 0x%X <=== 0x%X 0x%X\n",
|
||||
rtype_name, regno, h_val, l_val);
|
||||
} else {
|
||||
if (ret != 3) {
|
||||
XPD_ERR(xpd,
|
||||
"Should give exactly one value (0x%X is direct register)\n",
|
||||
regno);
|
||||
goto invalid_input;
|
||||
}
|
||||
l_val = h_val;
|
||||
h_val = 0;
|
||||
XPD_INFO(xpd, "%s Direct 0x%X <=== 0x%X\n",
|
||||
rtype_name, regno, h_val);
|
||||
}
|
||||
spin_lock_irqsave(&xpd->lock, flags);
|
||||
v = &(params->values[rtype]);
|
||||
v->h_val = h_val;
|
||||
v->l_val = l_val;
|
||||
spin_unlock_irqrestore(&xpd->lock, flags);
|
||||
return count;
|
||||
invalid_input:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(fxs_ring_registers, S_IRUGO | S_IWUSR,
|
||||
fxs_ring_registers_show,
|
||||
fxs_ring_registers_store);
|
||||
|
||||
static int fxs_xpd_probe(struct device *dev)
|
||||
{
|
||||
xpd_t *xpd;
|
||||
int ret;
|
||||
|
||||
xpd = dev_to_xpd(dev);
|
||||
/* Is it our device? */
|
||||
@@ -1850,7 +1998,15 @@ static int fxs_xpd_probe(struct device *dev)
|
||||
return -EINVAL;
|
||||
}
|
||||
XPD_DBG(DEVICES, xpd, "SYSFS\n");
|
||||
ret = device_create_file(dev, &dev_attr_fxs_ring_registers);
|
||||
if (ret) {
|
||||
XPD_ERR(xpd, "%s: device_create_file(fxs_ring_registers) failed: %d\n",
|
||||
__func__, ret);
|
||||
goto fail_fxs_ring_registers;
|
||||
}
|
||||
return 0;
|
||||
fail_fxs_ring_registers:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int fxs_xpd_remove(struct device *dev)
|
||||
@@ -1859,6 +2015,7 @@ static int fxs_xpd_remove(struct device *dev)
|
||||
|
||||
xpd = dev_to_xpd(dev);
|
||||
XPD_DBG(DEVICES, xpd, "SYSFS\n");
|
||||
device_remove_file(dev, &dev_attr_fxs_ring_registers);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -511,6 +511,11 @@ HANDLER_DEF(GLOBAL, AB_DESCRIPTION)
|
||||
ret = -EPROTO;
|
||||
goto proto_err;
|
||||
}
|
||||
if (units[0].addr.unit != 0 || units[0].addr.subunit != 0) {
|
||||
XBUS_NOTICE(xbus, "No first module. Astribank unusable.\n");
|
||||
ret = -EPROTO;
|
||||
goto proto_err;
|
||||
}
|
||||
if (!xbus_setstate(xbus, XBUS_STATE_RECVD_DESC)) {
|
||||
ret = -EPROTO;
|
||||
goto proto_err;
|
||||
@@ -568,6 +573,7 @@ HANDLER_DEF(GLOBAL, AB_DESCRIPTION)
|
||||
}
|
||||
goto out;
|
||||
proto_err:
|
||||
xbus_setstate(xbus, XBUS_STATE_FAIL);
|
||||
dump_packet("AB_DESCRIPTION", pack, DBG_ANY);
|
||||
out:
|
||||
return ret;
|
||||
|
||||
20517
drivers/dahdi/xpp/firmwares/FPGA_1161.202.hex
Normal file
20517
drivers/dahdi/xpp/firmwares/FPGA_1161.202.hex
Normal file
File diff suppressed because it is too large
Load Diff
@@ -3,7 +3,7 @@
|
||||
|
||||
USB_FW = USB_FW.hex USB_FW.201.hex USB_RECOV.hex
|
||||
FPGA_FW = FPGA_FXS.hex FPGA_1141.hex FPGA_1151.hex FPGA_1161.hex \
|
||||
FPGA_1161.201.hex
|
||||
FPGA_1161.201.hex FPGA_1161.202.hex
|
||||
PIC_FW = PIC_TYPE_1.hex PIC_TYPE_2.hex PIC_TYPE_3.hex PIC_TYPE_4.hex
|
||||
OCT_FW = $(wildcard OCT6104E-256D.ima)
|
||||
FIRMWARES = $(USB_FW) $(FPGA_FW) $(PIC_FW) $(OCT_FW)
|
||||
@@ -20,4 +20,7 @@ install:
|
||||
mkdir -p $(TARGET)
|
||||
install $(SCRIPTS) $(TARGET)/
|
||||
install -m 644 ../XppConfig.pm $(FIRMWARES) $(TARGET)/
|
||||
if [ ! -r $(TARGET)/USB_FW.202.hex ]; then \
|
||||
ln -s USB_FW.201.hex $(TARGET)/USB_FW.202.hex;\
|
||||
fi
|
||||
|
||||
|
||||
1
drivers/dahdi/xpp/firmwares/USB_FW.202.hex
Symbolic link
1
drivers/dahdi/xpp/firmwares/USB_FW.202.hex
Symbolic link
@@ -0,0 +1 @@
|
||||
USB_FW.201.hex
|
||||
@@ -59,6 +59,7 @@ my %settings;
|
||||
$settings{debug} = 0;
|
||||
$settings{fxs_skip_calib} = 0;
|
||||
my $chipregs;
|
||||
my $ring_registers;
|
||||
|
||||
sub logit {
|
||||
print STDERR "$unit_id: @_\n";
|
||||
@@ -104,6 +105,10 @@ if (-t STDERR) {
|
||||
logit "OLD DRIVER: does not use /sys chipregs. Falling back to /proc"
|
||||
if -f $chipregs;
|
||||
}
|
||||
$ring_registers = sprintf "/sys/bus/xpds/devices/%02d:%1d:0/fxs_ring_registers",
|
||||
$ENV{XBUS_NUMBER}, $ENV{UNIT_NUMBER};
|
||||
logit "OLD DRIVER: missing '$ring_registers' -- fallback to hard-coded defaults"
|
||||
unless -f $ring_registers;
|
||||
}
|
||||
|
||||
sub set_output() {
|
||||
@@ -147,6 +152,16 @@ sub write_to_slic_file($) {
|
||||
|
||||
}
|
||||
|
||||
sub write_to_ring_register($) {
|
||||
my $write_str = shift;
|
||||
|
||||
open(SLICS,">$ring_registers") or
|
||||
die("Failed writing to ring_registers file $ring_registers");
|
||||
print SLICS $write_str;
|
||||
close(SLICS) or die "Failed writing '$write_str' to '$ring_registers': $!";
|
||||
main::mysleep(0.001);
|
||||
}
|
||||
|
||||
sub read_reg($$$) {
|
||||
my $read_slic = shift;
|
||||
my $read_reg = shift;
|
||||
@@ -298,7 +313,7 @@ sub init_early_direct_regs() {
|
||||
return write_to_slic_file("#
|
||||
* WD 08 00 # Audio Path Loopback Control
|
||||
* WD 6C 01
|
||||
* WD 4A 3F # High Battery Voltage
|
||||
* WD 4A 34 # High Battery Voltage
|
||||
* WD 4B $lbv # Low Battery Voltage
|
||||
* WD 49 $vcm # Common Mode Voltage (VCM)
|
||||
* WD 40 00 # Line Feed Control
|
||||
@@ -442,6 +457,10 @@ sub check_slics() {
|
||||
return @slics;
|
||||
}
|
||||
|
||||
sub overwrite_ring_registers() {
|
||||
write_to_ring_register("NEON 0x33 0x12");
|
||||
}
|
||||
|
||||
package main;
|
||||
|
||||
main::debug "Starting '$0'";
|
||||
@@ -470,6 +489,7 @@ while(<DATA>) {
|
||||
print "$_\n";
|
||||
}
|
||||
close REG;
|
||||
FXS::overwrite_ring_registers();
|
||||
|
||||
main::debug "Ending '$0'";
|
||||
close STDERR;
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#ifdef PROTOCOL_DEBUG
|
||||
@@ -59,8 +60,8 @@ static DEF_PARM(uint, command_queue_length, 1500, 0444,
|
||||
static DEF_PARM(uint, poll_timeout, 1000, 0644,
|
||||
"Timeout (in jiffies) waiting for units to reply");
|
||||
static DEF_PARM_BOOL(rx_tasklet, 0, 0644, "Use receive tasklets");
|
||||
static DEF_PARM_BOOL(dahdi_autoreg, 0, 0644,
|
||||
"Register devices automatically (1) or not (0)");
|
||||
static DEF_PARM_BOOL(dahdi_autoreg, 0, 0444,
|
||||
"Register devices automatically (1) or not (0). UNUSED.");
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
static const struct file_operations xbus_read_proc_ops;
|
||||
@@ -937,6 +938,8 @@ static void xbus_free_ddev(xbus_t *xbus)
|
||||
xbus->ddev = NULL;
|
||||
}
|
||||
|
||||
static DEFINE_MUTEX(dahdi_registration_mutex);
|
||||
|
||||
int xbus_register_dahdi_device(xbus_t *xbus)
|
||||
{
|
||||
int i;
|
||||
@@ -944,6 +947,11 @@ int xbus_register_dahdi_device(xbus_t *xbus)
|
||||
int ret;
|
||||
|
||||
XBUS_DBG(DEVICES, xbus, "Entering %s\n", __func__);
|
||||
ret = mutex_lock_interruptible(&dahdi_registration_mutex);
|
||||
if (ret < 0) {
|
||||
XBUS_ERR(xbus, "dahdi_registration_mutex already taken\n");
|
||||
goto err;
|
||||
}
|
||||
if (xbus_is_registered(xbus)) {
|
||||
XBUS_ERR(xbus, "Already registered to DAHDI\n");
|
||||
WARN_ON(1);
|
||||
@@ -1008,17 +1016,26 @@ int xbus_register_dahdi_device(xbus_t *xbus)
|
||||
xpd_dahdi_postregister(xpd);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
ret = 0;
|
||||
out:
|
||||
mutex_unlock(&dahdi_registration_mutex);
|
||||
return ret;
|
||||
err:
|
||||
xbus_free_ddev(xbus);
|
||||
return ret;
|
||||
goto out;
|
||||
}
|
||||
|
||||
void xbus_unregister_dahdi_device(xbus_t *xbus)
|
||||
{
|
||||
int i;
|
||||
int ret;
|
||||
|
||||
XBUS_NOTICE(xbus, "%s\n", __func__);
|
||||
ret = mutex_lock_interruptible(&dahdi_registration_mutex);
|
||||
if (ret < 0) {
|
||||
XBUS_ERR(xbus, "dahdi_registration_mutex already taken\n");
|
||||
return;
|
||||
}
|
||||
for (i = 0; i < MAX_XPDS; i++) {
|
||||
xpd_t *xpd = xpd_of(xbus, i);
|
||||
xpd_dahdi_preunregister(xpd);
|
||||
@@ -1033,6 +1050,7 @@ void xbus_unregister_dahdi_device(xbus_t *xbus)
|
||||
xpd_t *xpd = xpd_of(xbus, i);
|
||||
xpd_dahdi_postunregister(xpd);
|
||||
}
|
||||
mutex_unlock(&dahdi_registration_mutex);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1100,7 +1118,7 @@ void xbus_populate(void *data)
|
||||
*/
|
||||
xbus_request_sync(xbus, SYNC_MODE_PLL);
|
||||
elect_syncer("xbus_populate(end)"); /* FIXME: try to do it later */
|
||||
if (dahdi_autoreg)
|
||||
if (!auto_assign_spans)
|
||||
xbus_register_dahdi_device(xbus);
|
||||
out:
|
||||
XBUS_DBG(DEVICES, xbus, "Leaving\n");
|
||||
@@ -1959,6 +1977,10 @@ int __init xbus_core_init(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (dahdi_autoreg == 1) {
|
||||
NOTICE("WARNING: The dahdi_autoreg parameter is deprecated " \
|
||||
"-- just set dahdi.auto_assign_spans=0\n");
|
||||
}
|
||||
initialize_xbuses_array();
|
||||
#ifdef PROTOCOL_DEBUG
|
||||
INFO("FEATURE: with PROTOCOL_DEBUG\n");
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/proc_fs.h>
|
||||
#ifdef PROTOCOL_DEBUG
|
||||
#include <linux/ctype.h>
|
||||
@@ -54,10 +55,19 @@ static ssize_t sync_store(struct device_driver *driver, const char *buf,
|
||||
return exec_sync_command(buf, count);
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
|
||||
static struct driver_attribute xpp_attrs[] = {
|
||||
__ATTR(sync, S_IRUGO | S_IWUSR, sync_show, sync_store),
|
||||
__ATTR_NULL,
|
||||
};
|
||||
#else
|
||||
static DRIVER_ATTR_RW(sync);
|
||||
static struct attribute *xpp_attrs[] = {
|
||||
&driver_attr_sync.attr,
|
||||
NULL,
|
||||
};
|
||||
ATTRIBUTE_GROUPS(xpp);
|
||||
#endif
|
||||
|
||||
/*--------- Sysfs Bus handling ----*/
|
||||
static DEVICE_ATTR_READER(xbus_state_show, dev, buf)
|
||||
@@ -409,7 +419,11 @@ static struct bus_type toplevel_bus_type = {
|
||||
.match = astribank_match,
|
||||
.uevent = astribank_uevent,
|
||||
.dev_attrs = xbus_dev_attrs,
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0)
|
||||
.drv_attrs = xpp_attrs,
|
||||
#else
|
||||
.drv_groups = xpp_groups,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int astribank_probe(struct device *dev)
|
||||
@@ -582,6 +596,8 @@ static DEVICE_ATTR_READER(span_show, dev, buf)
|
||||
return len;
|
||||
}
|
||||
|
||||
static DEFINE_MUTEX(span_store_mutex);
|
||||
|
||||
/*
|
||||
* For backward compatibility with old dahdi-tools
|
||||
* Remove after dahdi_registration is upgraded
|
||||
@@ -601,8 +617,13 @@ static DEVICE_ATTR_WRITER(span_store, dev, buf, count)
|
||||
return -EINVAL;
|
||||
if (!XBUS_IS(xpd->xbus, READY))
|
||||
return -ENODEV;
|
||||
XPD_DBG(DEVICES, xpd, "%s -- deprecated (should use pinned-spans)\n",
|
||||
XPD_DBG(DEVICES, xpd, "%s -- deprecated (should use assigned-spans)\n",
|
||||
(dahdi_reg) ? "register" : "unregister");
|
||||
ret = mutex_lock_interruptible(&span_store_mutex);
|
||||
if (ret < 0) {
|
||||
XBUS_ERR(xpd->xbus, "span_store_mutex already taken\n");
|
||||
return ret;
|
||||
}
|
||||
if (xbus_is_registered(xpd->xbus)) {
|
||||
if (dahdi_reg) {
|
||||
XPD_DBG(DEVICES, xpd,
|
||||
@@ -620,6 +641,7 @@ static DEVICE_ATTR_WRITER(span_store, dev, buf, count)
|
||||
xbus_register_dahdi_device(xpd->xbus);
|
||||
}
|
||||
}
|
||||
mutex_unlock(&span_store_mutex);
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
# Load firmware into the Xorcom Astribank device:
|
||||
SUBSYSTEM=="usb", ACTION=="add", \
|
||||
ENV{PRODUCT}=="e4e4/11[3456][013]/*", ENV{DEVTYPE}!="usb_interface", \
|
||||
RUN+="/usr/share/dahdi/xpp_fxloader udev $env{PRODUCT}"
|
||||
|
||||
# Hotplug hook for Astribank up/down
|
||||
# If you need this functionality, copy the astribank_hook.sample
|
||||
# to $XPP_INIT_DIR/astribank_hook
|
||||
#
|
||||
# By default XPP_INIT_DIR="/usr/share/dahdi"
|
||||
KERNEL=="xbus*", RUN+="%E{XPP_INIT_DIR}/astribank_hook udev $kernel $sysfs{status} $sysfs{connector}"
|
||||
@@ -40,11 +40,10 @@
|
||||
/* #define SHORT_FLASH_TIME */
|
||||
|
||||
/*
|
||||
* Uncomment to disable calibration and/or DC/DC converter tests
|
||||
* Uncomment to disable calibration tests
|
||||
* (not generally recommended)
|
||||
*/
|
||||
/* #define NO_CALIBRATION */
|
||||
/* #define NO_DCDC */
|
||||
|
||||
/*
|
||||
* Boost ring voltage (Higher ring voltage, takes more power)
|
||||
|
||||
@@ -811,6 +811,7 @@ enum spantypes {
|
||||
SPANTYPE_DIGITAL_BRI_NT,
|
||||
SPANTYPE_DIGITAL_BRI_TE,
|
||||
SPANTYPE_DIGITAL_BRI_SOFT,
|
||||
SPANTYPE_DIGITAL_DYNAMIC,
|
||||
};
|
||||
const char *dahdi_spantype2str(enum spantypes st);
|
||||
enum spantypes dahdi_str2spantype(const char *name);
|
||||
@@ -909,7 +910,7 @@ struct dahdi_span_ops {
|
||||
/*! Opt: Provide the name of the echo canceller on a channel */
|
||||
const char *(*echocan_name)(const struct dahdi_chan *chan);
|
||||
|
||||
/*! When using "pinned_spans", this function is called back when this
|
||||
/*! When using "assigned spans", this function is called back when this
|
||||
* span has been assigned with the system. */
|
||||
void (*assigned)(struct dahdi_span *span);
|
||||
|
||||
@@ -940,6 +941,7 @@ struct dahdi_device {
|
||||
const char *devicetype;
|
||||
struct device dev;
|
||||
unsigned int irqmisses;
|
||||
struct timespec registration_time;
|
||||
};
|
||||
|
||||
struct dahdi_span {
|
||||
@@ -1003,6 +1005,8 @@ struct dahdi_transcoder_channel {
|
||||
};
|
||||
|
||||
int dahdi_is_sync_master(const struct dahdi_span *span);
|
||||
struct dahdi_span *get_master_span(void);
|
||||
void set_master_span(int spanno);
|
||||
|
||||
static inline int
|
||||
dahdi_tc_is_built(struct dahdi_transcoder_channel *dtc) {
|
||||
@@ -1276,6 +1280,7 @@ static inline void dahdi_ec_span(struct dahdi_span *span)
|
||||
}
|
||||
|
||||
extern struct file_operations *dahdi_transcode_fops;
|
||||
extern int auto_assign_spans;
|
||||
|
||||
/* Don't use these directly -- they're not guaranteed to
|
||||
be there. */
|
||||
@@ -1402,6 +1407,8 @@ static inline short dahdi_txtone_nextsample(struct dahdi_chan *ss)
|
||||
#define DAHDI_FORMAT_AUDIO_MASK ((1 << 16) - 1)
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 10, 0)
|
||||
#ifdef RHEL_RELEASE_VERSION
|
||||
#if RHEL_RELEASE_CODE < RHEL_RELEASE_VERSION(6, 5)
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#include <linux/proc_fs.h>
|
||||
static inline void *PDE_DATA(const struct inode *inode)
|
||||
@@ -1409,8 +1416,37 @@ static inline void *PDE_DATA(const struct inode *inode)
|
||||
return PDE(inode)->data;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#else
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#include <linux/proc_fs.h>
|
||||
static inline void *PDE_DATA(const struct inode *inode)
|
||||
{
|
||||
return PDE(inode)->data;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 31)
|
||||
#define KERN_CONT ""
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
|
||||
|
||||
# ifndef RHEL_RELEASE_VERSION
|
||||
/* I'm not sure which 5.x release this was backported into. */
|
||||
static inline int try_wait_for_completion(struct completion *x)
|
||||
{
|
||||
unsigned long flags;
|
||||
int ret = 1;
|
||||
|
||||
spin_lock_irqsave(&x->wait.lock, flags);
|
||||
if (!x->done)
|
||||
ret = 0;
|
||||
else
|
||||
x->done--;
|
||||
spin_unlock_irqrestore(&x->wait.lock, flags);
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#include <linux/proc_fs.h>
|
||||
@@ -1450,8 +1486,11 @@ void dahdi_pci_disable_link_state(struct pci_dev *pdev, int state);
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22)
|
||||
|
||||
#ifndef __packed
|
||||
#define __packed __attribute__((packed))
|
||||
#define list_first_entry(ptr, type, member) \
|
||||
list_entry((ptr)->next, type, member)
|
||||
|
||||
#ifndef __packed
|
||||
#define __packed __attribute__((packed))
|
||||
#endif
|
||||
|
||||
#include <linux/ctype.h>
|
||||
@@ -1479,6 +1518,7 @@ static inline int strcasecmp(const char *s1, const char *s2)
|
||||
#endif /* 2.6.22 */
|
||||
#endif /* 2.6.25 */
|
||||
#endif /* 2.6.26 */
|
||||
#endif /* 2.6.27 */
|
||||
#endif /* 2.6.31 */
|
||||
#endif /* 3.10.0 */
|
||||
|
||||
@@ -1571,6 +1611,17 @@ struct mutex {
|
||||
printk(KERN_INFO pr_fmt(fmt), ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/* If KBUILD_MODNAME is not defined in a compilation unit, then the dev_dbg
|
||||
* macro will not work properly. */
|
||||
#ifndef KBUILD_MODNAME
|
||||
#undef dev_dbg
|
||||
#ifdef DEBUG
|
||||
#define dev_dbg dev_info
|
||||
#else
|
||||
#define dev_dbg(...) do { } while (0)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* The dbg_* ones use a magical variable 'debug' and the user should be
|
||||
* aware of that.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user