diff options
Diffstat (limited to 'drivers/dahdi/xpp')
-rw-r--r-- | drivers/dahdi/xpp/Kbuild | 60 | ||||
-rw-r--r-- | drivers/dahdi/xpp/Kconfig | 48 | ||||
-rw-r--r-- | drivers/dahdi/xpp/XppConfig.pm | 13 | ||||
-rwxr-xr-x | drivers/dahdi/xpp/init_card_1_30 | 2 | ||||
-rwxr-xr-x | drivers/dahdi/xpp/init_card_2_30 | 27 | ||||
-rwxr-xr-x | drivers/dahdi/xpp/init_card_3_30 | 2 | ||||
-rwxr-xr-x | drivers/dahdi/xpp/init_card_4_30 | 4 | ||||
-rw-r--r-- | drivers/dahdi/xpp/mmapbus.c | 91 | ||||
-rw-r--r-- | drivers/dahdi/xpp/mmapbus.h | 26 | ||||
-rw-r--r-- | drivers/dahdi/xpp/mmapdrv.c | 598 | ||||
-rw-r--r-- | drivers/dahdi/xpp/print_fxo_modes.c | 32 |
11 files changed, 862 insertions, 41 deletions
diff --git a/drivers/dahdi/xpp/Kbuild b/drivers/dahdi/xpp/Kbuild index 3f0774e..6d4db4c 100644 --- a/drivers/dahdi/xpp/Kbuild +++ b/drivers/dahdi/xpp/Kbuild @@ -1,9 +1,3 @@ -ifdef SUBDIRS - ZAP_KERNEL = $(SUBDIRS) -else - ZAP_KERNEL = $(M) -endif - EXTRA_CFLAGS = $(XPP_LOCAL_CFLAGS) \ -DDEBUG \ -DPOLL_DIGITAL_INPUTS \ @@ -13,20 +7,22 @@ EXTRA_CFLAGS = $(XPP_LOCAL_CFLAGS) \ -g # +WITH_BRISTUFF := $(shell grep '^[[:space:]]*\#[[:space:]]*define[[:space:]]\+CONFIG_ZAPATA_BRI_DCHANS\>' $(src)/../dahdi_config.h) + obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_XPP) += xpp.o -obj-$(CONFIG_DAHDI_XPP_USB) += xpp_usb.o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_XPD_FXS) += xpd_fxs.o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_XPD_FXO) += xpd_fxo.o obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_XPD_PRI) += xpd_pri.o - -HAS_BRISTUFF := $(shell grep '^[[:space:]]*\#[[:space:]]*define[[:space:]]\+CONFIG_ZAPATA_BRI_DCHANS\>' $(ZAP_KERNEL)/dahdi_config.h) +ifneq (,$(WITH_BRISTUFF)) +obj-$(DAHDI_BUILD_ALL)$(CONFIG_DAHDI_XPD_BRI) += xpd_bri.o +endif # Build only supported modules ifneq (,$(filter y m,$(CONFIG_USB))) -obj-m += xpp_usb.o +obj-$(DAHDI_BUILD_ALL)$(CONFIG_XPP_USB) += xpp_usb.o endif -ifneq (,$(HAS_BRISTUFF)) -obj-m += xpd_bri.o +ifneq (,$(filter y m,$(CONFIG_BF537))) +obj-$(DAHDI_BUILD_ALL)$(CONFIG_XPP_MMAP) += xpp_mmap.o endif xpp-objs += xbus-core.o xbus-sysfs.o xbus-pcm.o xframe_queue.o xpp_zap.o xproto.o card_global.o zap_debug.o @@ -34,6 +30,7 @@ xpd_fxs-objs += card_fxs.o xpd_fxo-objs += card_fxo.o xpd_bri-objs += card_bri.o xpd_pri-objs += card_pri.o +xpp_mmap-objs += mmapbus.o mmapdrv.o ifeq (y,$(PARPORT_DEBUG)) EXTRA_CFLAGS += -DDEBUG_SYNC_PARPORT @@ -42,7 +39,7 @@ endif # Handle versioning XPP_VERSION_STR ?= $(shell if [ -r $(obj)/.version ]; then echo "\"`cat $(obj)/.version`\""; else echo '"Unknown"'; fi) -clean-files := xpp_version.h +clean-files += xpp_version.h $(obj)/card_fxs.o $(obj)/card_fxo.o $(obj)/card_bri.o $(obj)/card_pri.o $(obj)/xpp_usb.o $(obj)/xpp.o: $(obj)/xpp_version.h @@ -53,5 +50,42 @@ $(obj)/xpp_version.h: FORCE fi $(Q)rm -f $@.tmp +# Validations: +# - Syntactic verification of perl scripts +# - Handle country table validation for init_card_2_* + +XPP_PROTOCOL_VERSION := $(shell grep XPP_PROTOCOL_VERSION $(src)/xproto.h | sed -e 's/^.*XPP_PROTOCOL_VERSION[ \t]*//') + +xpp_verifications = \ + init_card_1_$(XPP_PROTOCOL_VERSION) \ + init_card_2_$(XPP_PROTOCOL_VERSION) \ + init_card_3_$(XPP_PROTOCOL_VERSION) \ + init_card_4_$(XPP_PROTOCOL_VERSION) \ + init_fxo_modes + +xpp_verified = $(foreach file, $(xpp_verifications), $(file).verified) + +FXO_MODES = $(src)/../fxo_modes.h +FXO_VERIFY = $(obj)/init_card_2_$(XPP_PROTOCOL_VERSION) -v $(obj)/init_fxo_modes + +hostprogs-y := print_fxo_modes +always := $(xpp_verified) +print_fxo_modes-objs := print_fxo_modes.o +HOSTCFLAGS_print_fxo_modes.o += -include $(FXO_MODES) + +clean-files += print_fxo_modes init_fxo_modes $(xpp_verified) + +$(obj)/init_fxo_modes: $(obj)/print_fxo_modes + @echo ' GEN $@' + $(Q)$(obj)/print_fxo_modes >$@ || (rm -f $@; exit 1) + +$(obj)/init_fxo_modes.verified: $(obj)/init_card_2_$(XPP_PROTOCOL_VERSION) $(obj)/init_fxo_modes + @echo ' CHECK $(obj)/init_card_2_$(XPP_PROTOCOL_VERSION)' + $(Q)$(FXO_VERIFY) && touch $@ || (rm -f $@; exit 1) + +$(obj)/init_card_%_$(XPP_PROTOCOL_VERSION).verified: $(src)/init_card_%_$(XPP_PROTOCOL_VERSION) + @echo ' VERIFY $<' + $(Q)perl -c $< 2> $@ || (cat $@; rm -f $@; exit 1) + .PHONY: FORCE FORCE: diff --git a/drivers/dahdi/xpp/Kconfig b/drivers/dahdi/xpp/Kconfig index fa1d57c..aebd29c 100644 --- a/drivers/dahdi/xpp/Kconfig +++ b/drivers/dahdi/xpp/Kconfig @@ -4,7 +4,7 @@ menuconfig DAHDI_XPP tristate "Xorcom Astribank Support" - depends on DAHDI && USB + depends on DAHDI default DAHDI ---help--- Infrastructure support for Xorcom Astribank products. @@ -14,16 +14,32 @@ menuconfig DAHDI_XPP If unsure, say Y. -if DAHDI_XPP - config DAHDI_XPP_USB - tristate - depends on DAHDI_XPP + tristate "Astribank USB transport" + depends on DAHDI_XPP && USB + default DAHDI_XPP + ---help--- + To compile this driver as a module, choose M here: the + module will be called xpp_usb. + + If unsure, say Y. + +config DAHDI_XPP_MMAP + tristate "Astribank Blackfin transport" + depends on DAHDI_XPP && BF537 default DAHDI_XPP + ---help--- + To compile this driver as a module, choose M here: the + module will be called xpp_mmap. + + This module can be compiled only on Blackfin architecture + (with uClinux). + + If unsure, say N. config DAHDI_XPD_FXS tristate "FXS port Support" - depends on DAHDI_XPP + depends on DAHDI_XPP && (DAHDI_XPP_USB || DAHDI_XPP_MMAP) default DAHDI_XPP ---help--- To compile this driver as a module, choose M here: the @@ -33,7 +49,7 @@ config DAHDI_XPD_FXS config DAHDI_XPD_FXO tristate "FXO port Support" - depends on DAHDI_XPP + depends on DAHDI_XPP && (DAHDI_XPP_USB || DAHDI_XPP_MMAP) default DAHDI_XPP ---help--- To compile this driver as a module, choose M here: the @@ -41,14 +57,26 @@ config DAHDI_XPD_FXO If unsure, say Y. +config DAHDI_XPD_BRI + tristate "BRI port Support" + depends on DAHDI_XPP && (DAHDI_XPP_USB || DAHDI_XPP_MMAP) + default DAHDI_XPP + ---help--- + To compile this driver as a module, choose M here: the + module will be called xpd_pri. + + Note: this driver will be automatically excluded + from compilation if dahdi driver does not + contain the "bristuff" patch. + + If unsure, say Y. + config DAHDI_XPD_PRI tristate "PRI port Support" - depends on DAHDI_XPP + depends on DAHDI_XPP && (DAHDI_XPP_USB || DAHDI_XPP_MMAP) default DAHDI_XPP ---help--- To compile this driver as a module, choose M here: the module will be called xpd_pri. If unsure, say Y. - -endif # DAHDI_XPP diff --git a/drivers/dahdi/xpp/XppConfig.pm b/drivers/dahdi/xpp/XppConfig.pm index 2ccb6a9..1485a0d 100644 --- a/drivers/dahdi/xpp/XppConfig.pm +++ b/drivers/dahdi/xpp/XppConfig.pm @@ -1,4 +1,4 @@ -package XppConf; +package XppConfig; # # Written by Oron Peled <oron@actcom.co.il> # Copyright (C) 2008, Xorcom @@ -11,8 +11,6 @@ use strict; my $conf_file = "/etc/dahdi/xpp.conf"; -$conf_file = $ENV{XPP_CONFIG} if $ENV{XPP_CONFIG}; - sub subst_var($$) { my $lookup = shift; my $string = shift; @@ -55,7 +53,13 @@ LINE: return %xpp_config; } -my %x = read_config($conf_file); +sub import { + my $pack = shift || die "Import without package?"; + my $init_dir = shift || die "$pack::import -- missing init_dir parameter"; + my $local_conf = "$init_dir/xpp.conf"; + $conf_file = $local_conf if -r $local_conf; + my %x = read_config($conf_file); +} sub show_vars { my $assoc = shift; @@ -79,6 +83,5 @@ sub source_vars { return ($conf_file, %result); } -source_vars(qw(XPP_PRI_SETUP opermode)); 1; diff --git a/drivers/dahdi/xpp/init_card_1_30 b/drivers/dahdi/xpp/init_card_1_30 index a0623d5..b781d7c 100755 --- a/drivers/dahdi/xpp/init_card_1_30 +++ b/drivers/dahdi/xpp/init_card_1_30 @@ -45,7 +45,7 @@ use Getopt::Std; my $program = basename("$0"); my $init_dir = dirname("$0"); BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir", "$init_dir/zconf"); } -use XppConfig; +use XppConfig $init_dir; my $unit_id; my %opts; $ENV{XPP_BASE} = '/proc/xpp'; diff --git a/drivers/dahdi/xpp/init_card_2_30 b/drivers/dahdi/xpp/init_card_2_30 index 6cc6804..aa16280 100755 --- a/drivers/dahdi/xpp/init_card_2_30 +++ b/drivers/dahdi/xpp/init_card_2_30 @@ -45,12 +45,12 @@ use Getopt::Std; my $program = basename("$0"); my $init_dir = dirname("$0"); BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir", "$init_dir/zconf", "$init_dir/utils/zconf"); } -use XppConfig; +use XppConfig $init_dir; my $unit_id; my %opts; $ENV{XPP_BASE} = '/proc/xpp'; -getopts('o:', \%opts); +getopts('o:v:', \%opts); my $debug; @@ -127,9 +127,9 @@ BULGARIA reg16=00 reg26=C2 reg30=03 reg31=20 CANADA reg16=00 reg26=C0 reg30=00 reg31=20 CHILE reg16=00 reg26=C0 reg30=00 reg31=20 CHINA reg16=00 reg26=30 reg30=0F reg31=20 -COLUMBIA reg16=00 reg26=C0 reg30=00 reg31=20 +COLOMBIA reg16=00 reg26=C0 reg30=00 reg31=20 CROATIA reg16=00 reg26=C2 reg30=02 reg31=20 -CYRPUS reg16=00 reg26=C2 reg30=02 reg31=20 +CYPRUS reg16=00 reg26=C2 reg30=02 reg31=20 CZECH reg16=00 reg26=C2 reg30=02 reg31=20 DENMARK reg16=00 reg26=C2 reg30=02 reg31=28 ECUADOR reg16=00 reg26=C0 reg30=00 reg31=20 @@ -263,6 +263,7 @@ sub opermode_to_string($) { sub opermode_verify($) { my $input = shift or die; my %verification_table; + my $mismatches = 0; open(F, $input) or die "$0: Failed opening '$input': $!\n"; while(<F>) { @@ -281,7 +282,8 @@ sub opermode_verify($) { foreach my $location (sort keys %verification_table) { my $mode = $opermode_table{$location}; if(! defined $mode) { - printf STDERR "Missing $location\n"; + printf STDERR "Missing from $0: '$location'\n"; + $mismatches++; next; } my $verify_mode = $verification_table{$location}; @@ -291,16 +293,20 @@ sub opermode_verify($) { print STDERR "DIFF: $location:\n"; printf STDERR "\t%-20s: %s\n", "program", $str1; printf STDERR "\t%-20s: %s\n", "verify", $str2; + $mismatches++; } } # Second test: check for extra data in our program foreach my $location (sort keys %opermode_table) { my $mode = $verification_table{$location}; if(! defined $mode) { - printf STDERR "Extra $location\n"; + printf STDERR "Extra in $0 '$location'\n"; + $mismatches++; next; } } + print STDERR "Total $mismatches mismatches\n" if $mismatches; + return $mismatches; } sub read_defaults() { @@ -331,11 +337,12 @@ package main; FXO::opermode_preprocess; # Must be first -if(@ARGV and $ARGV[0] =~ /^verify(.*)/) { - my $verify_file = $1; - die "Usage: $0 verify=filename\n" unless $verify_file =~ s/^=//; +if($opts{v}) { + my $verify_file = $opts{v}; + die "Usage: $0 [-v verify_filename]\n" unless $verify_file; main::debug "$0: opermode verification (input='$verify_file')"; - FXO::opermode_verify($verify_file); + my $mismatches = FXO::opermode_verify($verify_file); + die "$0: Verification against $verify_file failed\n" if $mismatches != 0; exit 0; } diff --git a/drivers/dahdi/xpp/init_card_3_30 b/drivers/dahdi/xpp/init_card_3_30 index ce8ad01..2f94da9 100755 --- a/drivers/dahdi/xpp/init_card_3_30 +++ b/drivers/dahdi/xpp/init_card_3_30 @@ -57,6 +57,8 @@ use Getopt::Std; my $program = basename("$0"); my $init_dir = dirname("$0"); +BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir", "$init_dir/zconf"); } +use XppConfig $init_dir; my $unit_id; my %opts; $ENV{XPP_BASE} = '/proc/xpp'; diff --git a/drivers/dahdi/xpp/init_card_4_30 b/drivers/dahdi/xpp/init_card_4_30 index c5ff7b8..0d0ae2b 100755 --- a/drivers/dahdi/xpp/init_card_4_30 +++ b/drivers/dahdi/xpp/init_card_4_30 @@ -54,6 +54,8 @@ use Getopt::Std; my $program = basename("$0"); my $init_dir = dirname("$0"); +BEGIN { $init_dir = dirname($0); unshift(@INC, "$init_dir", "$init_dir/zconf"); } +use XppConfig $init_dir; my $unit_id; my %opts; $ENV{XPP_BASE} = '/proc/xpp'; @@ -344,8 +346,6 @@ sub port_setup($) { } package main; -BEGIN { my $dir = dirname($0); unshift(@INC, "$dir", "$dir/zconf"); } -use XppConfig; logit "Starting '$0'"; diff --git a/drivers/dahdi/xpp/mmapbus.c b/drivers/dahdi/xpp/mmapbus.c new file mode 100644 index 0000000..30ca8c5 --- /dev/null +++ b/drivers/dahdi/xpp/mmapbus.c @@ -0,0 +1,91 @@ +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/device.h> +#include "mmapbus.h" + +static int mmap_match(struct device *dev, struct device_driver *driver) +{ + return !strncmp(dev->bus_id, driver->name, strlen(driver->name)); +} +static int mmap_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size) +{ + envp[0] = buffer; + envp[1] = NULL; + return 0; +} + +static void mmap_bus_release(struct device *dev) +{ +} + +static void mmap_dev_release(struct device *dev) +{ +} + +static struct bus_type mmap_bus_type = { + .name = "mmap", + .match = mmap_match, + .uevent = mmap_uevent, +}; + +static struct device mmap_bus = { + .bus_id = "mmap0", + .release = mmap_bus_release, +}; + + + +int register_mmap_device(struct mmap_device *dev) +{ + dev->dev.bus = &mmap_bus_type; + dev->dev.parent = &mmap_bus; + dev->dev.release = mmap_dev_release; + strncpy(dev->dev.bus_id, dev->name, BUS_ID_SIZE); + return device_register(&dev->dev); +} + +void unregister_mmap_device(struct mmap_device *dev) +{ + device_unregister(&dev->dev); +} +EXPORT_SYMBOL(register_mmap_device); +EXPORT_SYMBOL(unregister_mmap_device); + +int register_mmap_driver(struct mmap_driver *driver) +{ + driver->driver.bus = &mmap_bus_type; + return driver_register(&driver->driver); +} + +void unregister_mmap_driver(struct mmap_driver *driver) +{ + driver_unregister(&driver->driver); +} +EXPORT_SYMBOL(register_mmap_driver); +EXPORT_SYMBOL(unregister_mmap_driver); + +int register_mmap_bus(void) +{ + int ret = 0; + if ((ret = bus_register(&mmap_bus_type)) < 0) + goto bus_type_reg; + if ((ret = device_register(&mmap_bus)) < 0) + goto bus_reg; + return ret; + +bus_reg: + bus_unregister(&mmap_bus_type); +bus_type_reg: + return ret; +} + +void unregister_mmap_bus(void) +{ + device_unregister(&mmap_bus); + bus_unregister(&mmap_bus_type); +} +EXPORT_SYMBOL(register_mmap_bus); +EXPORT_SYMBOL(unregister_mmap_bus); + +MODULE_AUTHOR("Alexander Landau <landau.alex@gmail.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/dahdi/xpp/mmapbus.h b/drivers/dahdi/xpp/mmapbus.h new file mode 100644 index 0000000..98fad66 --- /dev/null +++ b/drivers/dahdi/xpp/mmapbus.h @@ -0,0 +1,26 @@ +#ifndef MMAPBUS_H +#define MMAPBUS_H + +#include <linux/device.h> + +struct mmap_device { + char *name; + struct mmap_driver *driver; + struct device dev; +}; +#define to_mmap_device(x) container_of(x, struct mmap_device, dev) + +struct mmap_driver { + struct module *module; + struct device_driver driver; +}; +#define to_mmap_driver(x) container_of(x, struct mmap_driver, driver) + +int register_mmap_bus(void); +void unregister_mmap_bus(void); +int register_mmap_device(struct mmap_device *dev); +void unregister_mmap_device(struct mmap_device *dev); +int register_mmap_driver(struct mmap_driver *driver); +void unregister_mmap_driver(struct mmap_driver *driver); + +#endif diff --git a/drivers/dahdi/xpp/mmapdrv.c b/drivers/dahdi/xpp/mmapdrv.c new file mode 100644 index 0000000..d63ca12 --- /dev/null +++ b/drivers/dahdi/xpp/mmapdrv.c @@ -0,0 +1,598 @@ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/proc_fs.h> +#include <linux/interrupt.h> +#include <linux/firmware.h> +#include <asm/io.h> +#include <asm/irq.h> +#include <asm/blackfin.h> +#include <asm/dma.h> +#include <asm/cacheflush.h> +#include <asm/uaccess.h> +#include <dahdi.h> +#include "mmapbus.h" +#include "xbus-core.h" +#include "zap_debug.h" +#include "xdefs.h" +#include "xproto.h" +#include "xframe_queue.h" + +/* Check at compile time that sizeof(xframe_t) is a multiple of 4 */ +typedef char sizeof_xframe_t_should_be_divisible_by_4[((sizeof(xframe_t) % 4) == 0) * 2 - 1]; + +#define ssync() __builtin_bfin_ssync() + +//#define AB_IN_BUF PF5 +/* firmware pins */ +#define DATA PG8 +#define NCONFIG PG9 +#define CONF_DONE PG10 +#define DCLK PG11 +#define NSTATUS PG12 + +#ifdef DEBUG_VIA_GPIO +/* + * For debugging we can use the following two pins. + * These two pins are not used *after initialization* + */ +#define DEBUG_GPIO1 CONF_DONE +#define DEBUG_GPIO2 NSTATUS + +static int rx_intr_counter; +#endif + +#define FPGA_RX_IRQ IRQ_PF7 +#define FPGA_TX_IRQ IRQ_PF4 +#define FPGA_BASE_ADDR ((volatile char __iomem *)0x203FA800) + +#define END_OF_FRAME 0x0001 +#define GET_LEN 0x0002 +#define START_RD_BURST 0x0008 +#define AS_BF_MODE 0x0010 //stand alone Astribank without USB (Asterisk BlackFin Mode) +#define EC_BF_MODE 0x0020 //all data between Astribank and USB routed thru BF(EchoCanceler BlackFin Mode) +#define NO_BF_MODE 0x0040 //Astribank worke with USB only (no BlackFin Mode) +#define SET_XA_DIR 0x0080 +#define GET_XPD_STS 0x0100 +#define GET_CHECKSUM 0x0200 + +static const char rcsid[] = "$Id$"; + +static DEF_PARM(int, debug, 0, 0644, "Print DBG statements"); +static DEF_PARM(int, notxrx, 0, 0644, "Don't send or receive anything"); + +struct counter { + long intr_min, intr_max; + long intr_avg, intr_count; +}; + +static xbus_t *global_xbus; +static bool tx_ready = 1; +static spinlock_t tx_ready_lock = SPIN_LOCK_UNLOCKED; +static struct xframe_queue txpool; +static unsigned int pcm_in_pool_count; +static bool disconnecting; +static struct kmem_cache *xframe_cache; +static struct counter tx_counter, rx_counter; +static unsigned long pcm_dropped; + +static void print_buffer(const char *msg, const char *buf, int len) +{ + int i; + printk(KERN_ERR "%s", msg); + for (i = 0; i < len; i++) { + printk("%02X ", (unsigned char)buf[i]); + } + printk("\n"); +} + +static void update_counter(struct counter *c, struct timeval *tv1) +{ + struct timeval tv2; + long diff; + do_gettimeofday(&tv2); + diff = usec_diff(&tv2, tv1); + if (c->intr_min > diff) + c->intr_min = diff; + if (c->intr_max < diff) + c->intr_max = diff; + c->intr_avg = (c->intr_avg*c->intr_count + diff) / (c->intr_count+1); + c->intr_count++; +} + +static irqreturn_t xpp_mmap_rx_irq(int irq, void *dev_id) +{ + unsigned short rxcnt; + xbus_t *xbus; + xframe_t *xframe; + byte *buf; + bool in_use = 0; + struct timeval tv1; + + do_gettimeofday(&tv1); + if (unlikely(disconnecting)) + return IRQ_HANDLED; + + xbus = get_xbus(global_xbus->num); + BUG_ON(!xbus); + if(!XBUS_GET(xbus)) { + if (printk_ratelimit()) + XBUS_ERR(xbus, "Dropping packet. Is shutting down.\n"); + goto out; + } + in_use = 1; + + outw(GET_LEN, FPGA_BASE_ADDR + 4); + rxcnt = inw(FPGA_BASE_ADDR); + if (rxcnt < 3) { + if (printk_ratelimit()) + NOTICE("Got %d bytes\n", rxcnt); + goto out; + } + if(rxcnt >= XFRAME_DATASIZE) { + if (printk_ratelimit()) + ERR("Bad rxcnt=%d\n", rxcnt); + goto out; + } + + xframe = ALLOC_RECV_XFRAME(xbus); + if (!xframe) { + if (printk_ratelimit()) + XBUS_ERR(xbus, "Empty receive_pool\n"); + goto out; + } + buf = xframe->packets; + atomic_set(&xframe->frame_len, rxcnt); + do_gettimeofday(&xframe->tv_received); +#ifdef DEBUG_VIA_GPIO + if (rx_intr_counter & 1) + bfin_write_PORTGIO_SET(DEBUG_GPIO1); + else + bfin_write_PORTGIO_CLEAR(DEBUG_GPIO1); +#endif + outw(START_RD_BURST, FPGA_BASE_ADDR + 4); + insw((unsigned long)FPGA_BASE_ADDR, buf, rxcnt / 2); +#if 0 + for (count = 0; count < rxcnt; count+=2) { + unsigned short v = inw(FPGA_BASE_ADDR); + buf[count] = v & 0xFF; + buf[count+1] = v >> 8; + } +#endif + if (rxcnt & 1) + buf[rxcnt-1] = inw(FPGA_BASE_ADDR); + /* Sanity check: length of first packet in frame should be no more than the frame length */ + if (((buf[0] | (buf[1]<<8)) & 0x3FF) > rxcnt) { + if (printk_ratelimit()) { + ERR("Packet len=%d, frame len=%d\n", (buf[0] | (buf[1]<<8)) & 0x3FF, rxcnt); + print_buffer("16 bytes of packet: ", buf, 16); + } + goto free; + } + if (debug && buf[2] != 0x12) + print_buffer("Received: ", buf, rxcnt); + if (!notxrx) { + xbus_receive_xframe(xbus, xframe); +#ifdef DEBUG_VIA_GPIO + if (rx_intr_counter & 1) + bfin_write_PORTGIO_SET(DEBUG_GPIO2); + else + bfin_write_PORTGIO_CLEAR(DEBUG_GPIO2); +#endif + goto out; + } +free: + FREE_RECV_XFRAME(xbus, xframe); +out: + if (in_use) + XBUS_PUT(xbus); + put_xbus(xbus); +#ifdef DEBUG_VIA_GPIO + rx_intr_counter++; +#endif + update_counter(&rx_counter, &tv1); + return IRQ_HANDLED; +} + +static void send_buffer(unsigned char *buf, unsigned long len) +{ + if (debug && len >= 3 && buf[2] != 0x11) + print_buffer("Sent: ", buf, len); + outsw((unsigned long)FPGA_BASE_ADDR, buf, len / 2); + if (len & 1) + outw((unsigned short)buf[len-1], FPGA_BASE_ADDR); + outw(END_OF_FRAME, FPGA_BASE_ADDR + 4); +} + +static irqreturn_t xpp_mmap_tx_irq(int irq, void *dev_id) +{ + unsigned long flags; + xbus_t *xbus; + xframe_t *xframe; + struct timeval tv1; + + do_gettimeofday(&tv1); + if (unlikely(disconnecting)) { + update_counter(&tx_counter, &tv1); + return IRQ_HANDLED; + } + spin_lock_irqsave(&tx_ready_lock, flags); + xframe = xframe_dequeue(&txpool); + if (!xframe) { + tx_ready = 1; + spin_unlock_irqrestore(&tx_ready_lock, flags); + update_counter(&tx_counter, &tv1); + return IRQ_HANDLED; + } + tx_ready = 0; + if (XPACKET_IS_PCM((xpacket_t *)xframe->packets)) + pcm_in_pool_count--; + spin_unlock_irqrestore(&tx_ready_lock, flags); + xbus = (xbus_t *)xframe->priv; + BUG_ON(!xbus); + xbus = get_xbus(xbus->num); + BUG_ON(!xbus); + send_buffer(xframe->packets, XFRAME_LEN(xframe)); + FREE_SEND_XFRAME(xbus, xframe); + put_xbus(xbus); + update_counter(&tx_counter, &tv1); + return IRQ_HANDLED; +} + +static int xframe_send_common(xbus_t *xbus, xframe_t *xframe, bool pcm) +{ + unsigned long flags; + if (unlikely(disconnecting)) { + FREE_SEND_XFRAME(xbus, xframe); + return -ENODEV; + } + if (unlikely(notxrx)) { + FREE_SEND_XFRAME(xbus, xframe); + return 0; + } + spin_lock_irqsave(&tx_ready_lock, flags); + if (tx_ready) { + tx_ready = 0; + send_buffer(xframe->packets, XFRAME_LEN(xframe)); + spin_unlock_irqrestore(&tx_ready_lock, flags); + FREE_SEND_XFRAME(xbus, xframe); + } else { + if (pcm && pcm_in_pool_count >= 1) { + static int rate_limit; + if ((rate_limit++ % 1000) == 0) + XBUS_ERR(xbus, "Dropped PCM xframe (pcm_in_pool_count=%d).\n", pcm_in_pool_count); + FREE_SEND_XFRAME(xbus, xframe); + pcm_dropped++; + } else { + if (!xframe_enqueue(&txpool, xframe)) { + static int rate_limit; + spin_unlock_irqrestore(&tx_ready_lock, flags); + if ((rate_limit++ % 1000) == 0) + XBUS_ERR(xbus, "Dropped xframe. Cannot enqueue.\n"); + FREE_SEND_XFRAME(xbus, xframe); + return -E2BIG; + } + if (pcm) + pcm_in_pool_count++; + } + spin_unlock_irqrestore(&tx_ready_lock, flags); + } + return 0; +} + +static xframe_t *alloc_xframe(xbus_t *xbus, gfp_t gfp_flags) +{ + xframe_t *xframe = kmem_cache_alloc(xframe_cache, gfp_flags); + if (!xframe) { + static int rate_limit; + if ((rate_limit++ % 1000) < 5) + XBUS_ERR(xbus, "frame allocation failed (%d)\n", rate_limit); + return NULL; + } + xframe_init(xbus, xframe, ((byte*)xframe) + sizeof(xframe_t), XFRAME_DATASIZE, xbus); + return xframe; +} + +static void free_xframe(xbus_t *xbus, xframe_t *xframe) +{ + memset(xframe, 0, sizeof(*xframe)); + kmem_cache_free(xframe_cache, xframe); +} + +static int xframe_send_pcm(xbus_t *xbus, xframe_t *xframe) +{ + return xframe_send_common(xbus, xframe, 1); +} + +static int xframe_send_cmd(xbus_t *xbus, xframe_t *xframe) +{ + return xframe_send_common(xbus, xframe, 0); +} + +static struct xbus_ops xmmap_ops = { + .xframe_send_pcm = xframe_send_pcm, + .xframe_send_cmd = xframe_send_cmd, + .alloc_xframe = alloc_xframe, + .free_xframe = free_xframe, +}; + +static int fill_proc_queue(char *p, struct xframe_queue *q) +{ + int len; + + len = sprintf(p, + "%-15s: counts %3d, %3d, %3d worst %3d, overflows %3d worst_lag %02ld.%ld ms\n", + q->name, + q->steady_state_count, + q->count, + q->max_count, + q->worst_count, + q->overflows, + q->worst_lag_usec / 1000, + q->worst_lag_usec % 1000); + xframe_queue_clearstats(q); + return len; +} + +static int fill_proc_counter(char *p, struct counter *c) +{ + return sprintf(p, "min=%ld\nmax=%ld\navg=%ld\ncount=%ld\n", c->intr_min, c->intr_max, c->intr_avg, c->intr_count); +} + +static int xpp_mmap_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + int len = 0; + len += fill_proc_queue(page + len, &txpool); + len += sprintf(page + len, "pcm_in_pool_count=%d\n", pcm_in_pool_count); + len += sprintf(page + len, "pcm_dropped=%lu\n", pcm_dropped); + len += sprintf(page + len, "\nrx_counter:\n"); + len += fill_proc_counter(page + len, &rx_counter); + len += sprintf(page + len, "\ntx_counter:\n"); + len += fill_proc_counter(page + len, &tx_counter); + if (len <= off+count) { + *eof = 1; + tx_counter.intr_min = rx_counter.intr_min = INT_MAX; + tx_counter.intr_max = rx_counter.intr_max = 0; + tx_counter.intr_avg = rx_counter.intr_avg = 0; + tx_counter.intr_count = rx_counter.intr_count = 0; + } + *start = page + off; + len -= off; + if (len > count) + len = count; + if (len < 0) + len = 0; + return len; +} + +static int xpp_mmap_proc_write(struct file *file, const char __user *buffer, unsigned long count, void *data) +{ + int i = 0; + char *txchunk, *p, *endp; + + if (count >= XFRAME_DATASIZE*3+10) + return -EINVAL; + p = txchunk = kmalloc(count+1, GFP_KERNEL); + if (copy_from_user(txchunk, buffer, count)) { + count = -EFAULT; + goto out; + } + txchunk[count] = '\0'; + + while (*p) { + unsigned long value; + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; + if (*p == '\0') break; + value = simple_strtoul(p, &endp, 16); + if (endp == p || value > 0xFF) { + INFO("%s: Bad input\n", __FUNCTION__); + count = -EINVAL; + goto out; + } + p = endp; + txchunk[i++] = (char)value; + } + send_buffer(txchunk, i); +out: + kfree(txchunk); + return count; +} + +static struct mmap_driver astribank_driver = { + .module = THIS_MODULE, + .driver = { + .name = "xpp_mmap", + }, +}; + +static struct mmap_device astribank_dev = { + .name = "astribank0", + .driver = &astribank_driver, +}; + +static int __init xpp_mmap_load_fpga(u8 *data, size_t size) +{ + size_t i; + bfin_write_PORTGIO_DIR(bfin_read_PORTGIO_DIR() | DATA | NCONFIG | DCLK); //set data, nconfig and dclk to port out + bfin_write_PORTG_FER(bfin_read_PORTG_FER() & ~(DATA | NCONFIG | DCLK)); + bfin_write_PORTGIO_DIR(bfin_read_PORTGIO_DIR() & ~(CONF_DONE | NSTATUS));//set conf_done and nstatus to port in + bfin_write_PORTGIO_INEN(bfin_read_PORTGIO_INEN() & ~(DATA | NCONFIG | DCLK)); + bfin_write_PORTGIO_INEN(bfin_read_PORTGIO_INEN() | CONF_DONE | NSTATUS); + + bfin_write_PORTGIO_CLEAR(NCONFIG); //reset fpga during configuration holds nCONFIG low + udelay(40); //Tcfg ~40us delay + bfin_write_PORTGIO_SET(NCONFIG); //transition nCONFIG to high - reset end. + udelay(40); //Tcf2ck ~40us delay + if (!(bfin_read_PORTGIO() & NSTATUS)) + return -EIO; //report reset faill - Tcf2st1 pass + +#if 0 + if (!(bfin_read_PORTGIO() & CONF_DONE)) + return -EIO; +#endif + bfin_write_PORTGIO_CLEAR(DCLK); + for (i=0; i<size; i++) { // loop EP2OUT buffer data to FPGA + int j; + u8 byte = data[i]; + for (j=0; j<8; j++) //send the configuration data through the DATA0 pin one bit at a time. + { + if (byte & 1) + bfin_write_PORTGIO_SET(DATA); + else + bfin_write_PORTGIO_CLEAR(DATA); + byte >>= 1; + bfin_write_PORTGIO_SET(DCLK); + bfin_write_PORTGIO_CLEAR(DCLK); + } + if (!(bfin_read_PORTGIO() & NSTATUS)) + return -EIO; //check the nSTATUS + } + bfin_write_PORTGIO_CLEAR(DATA); + udelay(1); + if (!(bfin_read_PORTGIO() & CONF_DONE)) + return -EIO; +#ifdef DEBUG_VIA_GPIO + /* + * Normal initialization is done. Now we can reuse + * some pins that were used only during initialization + * to be used for debugging from now on. + */ + bfin_write_PORTGIO_DIR(bfin_read_PORTGIO_DIR() | DEBUG_GPIO1 | DEBUG_GPIO2); //set to port out + bfin_write_PORTG_FER(bfin_read_PORTG_FER() & ~(DEBUG_GPIO1 | DEBUG_GPIO2)); + bfin_write_PORTGIO_INEN(bfin_read_PORTGIO_INEN() & ~(DEBUG_GPIO1 | DEBUG_GPIO2)); +#endif + udelay(40); //tCD2UM - CONF_DONE high to user mode + return 0; +} + +static void __exit xpp_mmap_unload_fpga(void) +{ + bfin_write_PORTGIO_CLEAR(NCONFIG); //reset fpga during configuration holds nCONFIG low + udelay(40); //Tcfg ~40us delay + bfin_write_PORTGIO_DIR(bfin_read_PORTGIO_DIR() & ~( DATA | NCONFIG | DCLK)); //disable output pin + bfin_write_PORTGIO_INEN(bfin_read_PORTGIO_INEN() & ~( CONF_DONE | NSTATUS));//disable input buffer + INFO("FPGA Firmware unloaded\n"); +} + +static int __init xpp_mmap_load_firmware(void) +{ + const struct firmware *fw; + int ret; + if ((ret = request_firmware(&fw, "astribank.bin", &astribank_dev.dev)) < 0) + return ret; + xpp_mmap_load_fpga(fw->data, fw->size); + release_firmware(fw); + return ret; +} + +static int __init xpp_mmap_init(void) +{ + int ret; + struct proc_dir_entry *proc_entry; + + if ((ret = register_mmap_bus()) < 0) + goto bus_reg; + if ((ret = register_mmap_driver(&astribank_driver)) < 0) + goto driver_reg; + if ((ret = register_mmap_device(&astribank_dev)) < 0) + goto dev_reg; + if ((ret = xpp_mmap_load_firmware()) < 0) { + ERR("xpp_mmap_load_firmware() failed, errno=%d\n", ret); + goto fail_fw; + } + + if ((ret = request_irq(FPGA_RX_IRQ, xpp_mmap_rx_irq, IRQF_TRIGGER_RISING, "xpp_mmap_rx", NULL)) < 0) { + ERR("Unable to attach to RX interrupt %d\n", FPGA_RX_IRQ); + goto fail_irq_rx; + } + if ((ret = request_irq(FPGA_TX_IRQ, xpp_mmap_tx_irq, IRQF_TRIGGER_RISING, "xpp_mmap_tx", NULL)) < 0) { + ERR("Unable to attach to TX interrupt %d\n", FPGA_TX_IRQ); + goto fail_irq_tx; + } + if (!request_region((resource_size_t)FPGA_BASE_ADDR, 8, "xpp_mmap")) { + ERR("Unable to request memory region at %p\n", FPGA_BASE_ADDR); + goto fail_region; + } + outw(AS_BF_MODE, FPGA_BASE_ADDR + 4); + + xframe_cache = kmem_cache_create("xframe_cache", + sizeof(xframe_t) + XFRAME_DATASIZE, + 0, 0, +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,23) + NULL, +#endif + NULL); + if(!xframe_cache) { + ret = -ENOMEM; + goto fail_cache; + } + /* interface with Zaptel */ + global_xbus = xbus_new(&xmmap_ops, XFRAME_DATASIZE, NULL); + if (!global_xbus) { + ret = -ENOMEM; + goto fail_xbus; + } + strncpy(global_xbus->location, "mmap", XBUS_DESCLEN); + strncpy(global_xbus->label, "mmap:0", LABEL_SIZE); + + xframe_queue_init(&txpool, 10, 200, "mmap_txpool", global_xbus); + if (!(proc_entry = create_proc_entry("xpp_mmap", 0, global_xbus->proc_xbus_dir))) { + ERR("create_proc_entry() failed\n"); + ret = -EINVAL; + goto fail_proc; + } + proc_entry->write_proc = xpp_mmap_proc_write; + proc_entry->read_proc = xpp_mmap_proc_read; + /* Go xbus, go! */ + xbus_connect(global_xbus); + INFO("xpp_mmap module loaded\n"); + + return 0; + +fail_proc: + xbus_disconnect(global_xbus); +fail_xbus: + kmem_cache_destroy(xframe_cache); +fail_cache: + release_region((resource_size_t)FPGA_BASE_ADDR, 8); +fail_region: + free_irq(FPGA_TX_IRQ, NULL); +fail_irq_tx: + free_irq(FPGA_RX_IRQ, NULL); +fail_irq_rx: +fail_fw: + unregister_mmap_device(&astribank_dev); +dev_reg: + unregister_mmap_driver(&astribank_driver); +driver_reg: + unregister_mmap_bus(); +bus_reg: + return ret; +} + +static void __exit xpp_mmap_exit(void) +{ + xbus_t *xbus; + DBG(GENERAL, "\n"); + disconnecting = 1; + xbus = get_xbus(global_xbus->num); + remove_proc_entry("xpp_mmap", xbus->proc_xbus_dir); + xframe_queue_clear(&txpool); + xbus_disconnect(xbus); /* xbus_disconnect() calls put_xbus() */ + kmem_cache_destroy(xframe_cache); + + release_region((resource_size_t)FPGA_BASE_ADDR, 8); + free_irq(FPGA_RX_IRQ, NULL); + free_irq(FPGA_TX_IRQ, NULL); + + unregister_mmap_device(&astribank_dev); + unregister_mmap_driver(&astribank_driver); + unregister_mmap_bus(); + xpp_mmap_unload_fpga(); + INFO("xpp_mmap module unloaded\n"); +} + +module_init(xpp_mmap_init); +module_exit(xpp_mmap_exit); +MODULE_AUTHOR("Alexander Landau <landau.alex@gmail.com>"); +MODULE_LICENSE("GPL"); diff --git a/drivers/dahdi/xpp/print_fxo_modes.c b/drivers/dahdi/xpp/print_fxo_modes.c new file mode 100644 index 0000000..6d7d747 --- /dev/null +++ b/drivers/dahdi/xpp/print_fxo_modes.c @@ -0,0 +1,32 @@ +#include <stdio.h> + +int main(int argc, char *argv[]) +{ + size_t i; + + for (i=0; i<(sizeof(fxo_modes)/sizeof(struct fxo_mode)); i++) { + if (fxo_modes[i].name == NULL) break; + int reg16=0, reg26=0, reg30=0, reg31=0x20; + char ring_osc[BUFSIZ]="", ring_x[BUFSIZ] = ""; + + reg16 |= (fxo_modes[i].ohs << 6); + reg16 |= (fxo_modes[i].rz << 1); + reg16 |= (fxo_modes[i].rt); + + reg26 |= (fxo_modes[i].dcv << 6); + reg26 |= (fxo_modes[i].mini << 4); + reg26 |= (fxo_modes[i].ilim << 1); + + reg30 = (fxo_modes[i].acim); + + reg31 |= (fxo_modes[i].ohs2 << 3); + + if (fxo_modes[i].ring_osc) + snprintf(ring_osc, BUFSIZ, "ring_osc=%04X", fxo_modes[i].ring_osc); + if (fxo_modes[i].ring_x) + snprintf(ring_x, BUFSIZ, "ring_x=%04X", fxo_modes[i].ring_x); + printf("%-15s\treg16=%02X\treg26=%02X\treg30=%02X\treg31=%02X\t%s\t%s\n", + fxo_modes[i].name, reg16, reg26, reg30, reg31, ring_osc, ring_x); + } + return 0; +} |