summaryrefslogtreecommitdiff
path: root/xpp/utils
diff options
context:
space:
mode:
authortzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-02-09 19:12:55 +0000
committertzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2007-02-09 19:12:55 +0000
commitcc599ab08d6f58a2d5e57db4150e2f9efe1112b8 (patch)
tree3f6df61996f5a6df4f05cd447c2b120ae8b4669e /xpp/utils
parenteeaa77f409b4e0e158e62cb852e462ccef317f3f (diff)
Merged revisions 2123-2124 via svnmerge from
https://origsvn.digium.com/svn/zaptel/branches/1.4 ........ r2123 | tzafrir | 2007-02-08 02:05:17 +0200 (Thu, 08 Feb 2007) | 27 lines Branch 1.4 is back in sync (currently: xorcom rev. 3332): * Performance improvements for multi-XPD (span) devices. * Astribank BRI driver (in next commit). * Changes under /proc: - XBUS and XPD numbers have two digits. - Every script wildcard should be replaced from XBUS-? to XBUS-[0-9]* - Added /proc/xpp/XBUS-*/XPD-*/blink: echo 1 to start and 0 to stop. * Several countries (South Africa, UAE, anybody else) require a shorter ring delay. Adjust FXO reg 0x17 (23)'s bits 0:2 to 011. * Use tasklets to move most of the interrupt PCM copying out of the interrupt. * Debugfs-based code to dump data to userspace (used to debug BRI D channel). * Pretend every 2.6.9 actually has later RHEL's typedefs. * fpga_load supports /dev/bus/usb . * Fixed physical order sorting in genzaptelconf. * Reverse polarity and power denial detection. * A short led flash at registration time. * Add a real version of the xpp modules to them (independent of the Zaptel version). * Update our line status even when not registered. * Fixed a false SIG_CHANGED when inserting or removing cable to FXO. * Fixed compilation fixes for 2.6.20 (Bug #8982) * A cleaner fix for the bool changes of 2.6.19 . * Automatically detect echo_can_state_t at debug time. * Automaitcally set XPP_DEBUGFS (depending on debugfs) at compile time. * Bug-fixes to zaptel-helper. Moved to xpp/utils . * Xbus protocol version: 2.4 (Zaptel 1.2.12/1.4.0 had 2.3). XPS Init scripts renamed accordingly. ........ r2124 | tzafrir | 2007-02-08 02:30:56 +0200 (Thu, 08 Feb 2007) | 1 line Now 'chans' is used after all. ........ git-svn-id: http://svn.digium.com/svn/zaptel/trunk@2144 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'xpp/utils')
-rw-r--r--xpp/utils/Makefile27
-rw-r--r--xpp/utils/fpga_load.822
-rw-r--r--xpp/utils/fpga_load.c428
-rwxr-xr-xxpp/utils/genzaptelconf32
-rw-r--r--xpp/utils/xpp.rules8
-rw-r--r--xpp/utils/xpp_fxloader53
-rw-r--r--xpp/utils/zaptel-helper401
7 files changed, 678 insertions, 293 deletions
diff --git a/xpp/utils/Makefile b/xpp/utils/Makefile
index c565093..d23b50d 100644
--- a/xpp/utils/Makefile
+++ b/xpp/utils/Makefile
@@ -1,6 +1,8 @@
PEDANTIC = -ansi -pedantic -std=c99
RANLIB = ranlib
+INSTALL = install
+INSTALL_DATA = install -m 644
TOPDIR ?= ../..
@@ -11,7 +13,20 @@ INSTALL_DATA = $(INSTALL) -m 644
BINDIR = $(prefix)/sbin
DATADIR = $(datadir)/zaptel
MANDIR = $(mandir)/man8
+
+# In 1.4 those are provided by autoconf through makeopts
+prefix ?= /usr
+datadir ?= $(prefix)/share
+mandir ?= $(datadir)/man
+INSTALL ?= install
+
+INSTALL_DATA = $(INSTALL) -m 644
+
+BINDIR = $(prefix)/sbin
+DATADIR = $(datadir)/zaptel
+MANDIR = $(mandir)/man8
HOTPLUG_USB_DIR = /etc/hotplug/usb
+UDEV_RULES_DIR = /etc/udev/rules.d
XPD_FIRMWARE = $(wildcard ../firmwares/*.hex)
XPD_INIT_DATA = $(XPD_FIRMWARE) init_fxo_modes
@@ -20,17 +35,17 @@ XPD_INIT = $(wildcard ../init_card_?_*) ../calibrate_slics
# Variables that should be defined above, but need sane defaults:
# FIXME: Are those values really sane?
HOSTCC ?= $(CC)
-PBX_LIBUSB ?= 1
-DRIVER_DIR ?= $(TOPDIR)
+CONFIG_USB ?= y
+ZAPTEL_DIR ?= ../..
-WCTDM=$(DRIVER_DIR)/wctdm.c
+WCTDM=$(ZAPTEL_DIR)/wctdm.c
CFLAGS = -g -Wall $(EXTRA_CFLAGS)
TARGETS = init_fxo_modes print_modes adj_clock
PROG_INSTALL = genzaptelconf adj_clock
MAN_INSTALL = genzaptelconf.8 adj_clock.8
-ifeq ($(PBX_LIBUSB),1)
+ifneq (,$(filter y m,$(CONFIG_USB)))
TARGETS += libhexfile.a fpga_load test_parse
PROG_INSTALL += fpga_load
MAN_INSTALL += fpga_load.8
@@ -49,6 +64,8 @@ install: all
$(INSTALL) -d $(DESTDIR)$(HOTPLUG_USB_DIR)
$(INSTALL_DATA) xpp_fxloader.usermap $(DESTDIR)$(HOTPLUG_USB_DIR)/
$(INSTALL) xpp_fxloader $(DESTDIR)$(HOTPLUG_USB_DIR)/
+ $(INSTALL) -d $(DESTDIR)$(UDEV_RULES_DIR)
+ $(INSTALL_DATA) xpp.rules $(DESTDIR)$(UDEV_RULES_DIR)/
libhexfile.a: hexfile.o
$(AR) cru $@ $^
@@ -57,6 +74,8 @@ libhexfile.a: hexfile.o
fpga_load: fpga_load.o libhexfile.a
$(CC) -L. -o $@ $@.o $(EXTRA_LIBS) -lhexfile -lusb
+fpga_load.o: CFLAGS+=-D_GNU_SOURCE # We use memrchr()
+
hexfile.o: hexfile.c hexfile.h
$(CC) $(CFLAGS) $(PEDANTIC) -c $<
diff --git a/xpp/utils/fpga_load.8 b/xpp/utils/fpga_load.8
index 09dd5aa..640bbfd 100644
--- a/xpp/utils/fpga_load.8
+++ b/xpp/utils/fpga_load.8
@@ -5,10 +5,10 @@ ztcfg \- reads and loads zaptel.conf
.SH SYNOPSIS
.B fpga_load
-[\fB-g\fR|\fB-d\fR] [\fB-v\fR] \fB-D\fR/proc/bus/usb/\fIBUS/DEV\fR
+[\fB-g\fR] [\fB-v\fR] \fB-D \fR{/proc/bus/usb|/dev/bus/usb}/\fIBUS/DEV\fR
.B fpga_load
-[\fB-g\fR] [\fB-v\fR] \fB-D\fR/proc/bus/usb/\fIBUS/DEV\fR \fB-I \fIfirmware.hex\fR [\fB-b \fIdump.bin\fR]
+[\fB-g\fR] [\fB-v\fR] \fB-D \fR{/proc/bus/usb|/dev/bus/usb}/\fIBUS/DEV\fR \fB-I \fIfirmware.hex\fR [\fB-b \fIdump.bin\fR]
.B fpga_load -h
@@ -18,29 +18,27 @@ loads the FPGA firmware to the Xorcom Astribank device.
The syntax resembles that of fxload(8).
.SH OPTIONS
-.B -d
+.B -b
.I dump.bin
.RS
Before writing firmware, bump the processed binary file to
.I dump.bin\fR.
.RE
-.B -d
-.RS
-Print Version number bytes from eeprom (to standard output). Implies -g.
-.RE
-
.B -D
.I DEVICE
.RS
-Required. The device to read from/write to. This is normally
-/proc/bus/usb/\fIbus_num\fR/\fIdevice_num\fR , where \fIbus_num\fR and
-\fIdevice_num\fR are the first two numbers in the output of lsusb(8).
+Required. The device to read from/write to. On modern UDEV-based system
+this is usually /dev/bus/usb/\fIbus_num\fR/\fIdevice_num\fR,
+where \fIbus_num\fR and \fIdevice_num\fR are the first two numbers in the
+output of lsusb(8).
+On older systems that use usbfs, it is usually
+/proc/bus/usb/\fIbus_num\fR/\fIdevice_num\fR.
.RE
.B -g
.RS
-Dump all eeprom data to standard error.
+Dump all eeprom data to standard output.
.RE
.B -I
diff --git a/xpp/utils/fpga_load.c b/xpp/utils/fpga_load.c
index e4d4e91..426e6a6 100644
--- a/xpp/utils/fpga_load.c
+++ b/xpp/utils/fpga_load.c
@@ -72,7 +72,15 @@ enum fpga_load_status {
FW_CONFIG_DONE = 8
};
-int my_usb_device(struct usb_device *dev, usb_dev_handle *handle);
+struct my_usb_device {
+ struct usb_device *dev;
+ usb_dev_handle *handle;
+ char iManufacturer[BUFSIZ];
+ char iProduct[BUFSIZ];
+ char iSerialNumber[BUFSIZ];
+ int is_usb2;
+ struct myeeprom eeprom;
+};
const char *load_status2str(enum fpga_load_status s)
{
@@ -85,33 +93,43 @@ const char *load_status2str(enum fpga_load_status s)
}
}
-int path_of_dev(char buf[], unsigned int buflen, struct usb_device *dev)
-{
- return snprintf(buf, buflen, "/proc/bus/usb/%s/%s", dev->bus->dirname, dev->filename);
-}
-
struct usb_device *dev_of_path(const char *path)
{
struct usb_bus *bus;
struct usb_device *dev;
char dirname[PATH_MAX];
char filename[PATH_MAX];
- const char prefix[] = "/proc/bus/usb/";
- const int prefix_len = strlen(prefix);
const char *p;
int bnum;
int dnum;
int ret;
assert(path != NULL);
- if(strncmp(prefix, path, prefix_len) != 0) {
- ERR("wrong path: '%s'\n", path);
+ if(access(path, F_OK) < 0) {
+ perror(path);
+ return NULL;
+ }
+ /* Find last '/' */
+ if((p = memrchr(path, '/', strlen(path))) == NULL) {
+ ERR("Missing a '/' in %s\n", path);
+ return NULL;
+ }
+ /* Get the device number */
+ ret = sscanf(p + 1, "%d", &dnum);
+ if(ret != 1) {
+ ERR("Path tail is not a device number: '%s'\n", p);
return NULL;
}
- p = path + prefix_len;
- ret = sscanf(p, "%d/%d", &bnum, &dnum);
- if(ret != 2) {
- ERR("wrong path tail: '%s'\n", p);
+ /* Search for a '/' before that */
+ p = memrchr(path, '/', p - path);
+ if(p == NULL)
+ p = path; /* Relative path */
+ else
+ p++; /* skip '/' */
+ /* Get the bus number */
+ ret = sscanf(p, "%d", &bnum);
+ if(ret != 1) {
+ ERR("Path tail is not a bus number: '%s'\n", p);
return NULL;
}
sprintf(dirname, "%03d", bnum);
@@ -149,6 +167,9 @@ int get_usb_string(char *buf, unsigned int len, uint16_t item, usb_dev_handle *h
#define MY_EP_OUT 0x04
#define MY_EP_IN 0x88
+#define FPGA_EP_OUT 0x02
+#define FPGA_EP_IN 0x86
+
#define TIMEOUT 5000
static const int my_endpoints[MY_ENDPOINTS] = {
@@ -158,34 +179,36 @@ static const int my_endpoints[MY_ENDPOINTS] = {
0x88
};
-void usb_cleanup(usb_dev_handle *handle)
+void my_usb_device_cleanup(struct my_usb_device *mydev)
{
- if(usb_release_interface(handle, MY_INTERFACE) != 0) {
+ assert(mydev != NULL);
+ if(!mydev->handle) {
+ return; /* Nothing to do */
+ }
+ if(usb_release_interface(mydev->handle, MY_INTERFACE) != 0) {
ERR("Releasing interface: usb: %s\n", usb_strerror());
}
- if(usb_close(handle) != 0) {
+ if(usb_close(mydev->handle) != 0) {
ERR("Closing device: usb: %s\n", usb_strerror());
}
}
-void print_bcd_ver(const struct myeeprom *eeprom)
+static void show_device_info(const struct my_usb_device *mydev)
{
- /* In this case, print only the version. Also note that this
- * is an output, and sent to stdout
- */
- printf("%d.%03d\n", eeprom->release_major, eeprom->release_minor);
- return;
-}
-
-void dump_eeprom(const struct myeeprom *eeprom)
-{
- const uint8_t *data = eeprom->serial;
-
- INFO("Source: 0x%02X\n", eeprom->source);
- INFO("Vendor: 0x%04X\n", eeprom->vendor);
- INFO("Product: 0x%04X\n", eeprom->product);
- INFO("Release: %d.%03d\n", eeprom->release_major, eeprom->release_minor);
- INFO("Data: 0x[%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X]\n",
+ const struct myeeprom *eeprom;
+ const uint8_t *data = eeprom->serial;
+
+ assert(mydev != NULL);
+ eeprom = &mydev->eeprom;
+ data = eeprom->serial;
+ printf("USB iManufacturer: [%s]\n", mydev->iManufacturer);
+ printf("USB iProduct: [%s]\n", mydev->iProduct);
+ printf("USB iSerialNumber: [%s]\n", mydev->iSerialNumber);
+ printf("EEPROM Source: 0x%02X\n", eeprom->source);
+ printf("EEPROM Vendor: 0x%04X\n", eeprom->vendor);
+ printf("EEPROM Product: 0x%04X\n", eeprom->product);
+ printf("EEPROM Release: %d.%03d\n", eeprom->release_major, eeprom->release_minor);
+ printf("EEPROM Serial: 0x[%02X,%02X,%02X,%02X,%02X,%02X,%02X,%02X]\n",
data[0], data[1], data[2], data[3],
data[4], data[5], data[6], data[7]);
}
@@ -199,46 +222,46 @@ void dump_packet(const char *buf, int len)
}
#ifdef XORCOM_INTERNAL
-int eeprom_set(struct usb_dev_handle *handle, const struct myeeprom *eeprom)
+int eeprom_set(struct my_usb_device *mydev, const struct myeeprom *eeprom)
{
int ret;
int len;
char buf[PACKET_SIZE];
struct fpga_packet_header *phead = (struct fpga_packet_header *)buf;
- if(verbose >= LOG_INFO)
+ if(verbose >= LOG_DEBUG)
INFO("%s Start...\n", __FUNCTION__);
- assert(handle != NULL);
+ assert(mydev != NULL);
phead->header.op = EEPROM_SET;
memcpy(&phead->d.eeprom_set.data, eeprom, EEPROM_SIZE);
len = sizeof(phead->d.eeprom_set) + sizeof(phead->header.op);
- if(verbose >= LOG_INFO) {
+ if(verbose >= LOG_DEBUG) {
INFO("%s write %d bytes\n", __FUNCTION__, len);
dump_packet((char *)phead, len);
}
- ret = usb_bulk_write(handle, MY_EP_OUT, (char *)phead, len, TIMEOUT);
+ ret = usb_bulk_write(mydev->handle, MY_EP_OUT, (char *)phead, len, TIMEOUT);
if(ret < 0) {
- ERR("usb: bulk_write failed (%d)\n", ret);
+ ERR("bulk_write failed: %s\n", usb_strerror());
return ret;
} else if(ret != len) {
- ERR("usb: bulk_write short write (%d)\n", ret);
+ ERR("bulk_write short write: %s\n", usb_strerror());
return -EFAULT;
}
- ret = usb_bulk_read(handle, MY_EP_IN, buf, sizeof(buf), TIMEOUT);
+ ret = usb_bulk_read(mydev->handle, MY_EP_IN, buf, sizeof(buf), TIMEOUT);
if(ret < 0) {
- ERR("usb: bulk_read failed (%d)\n", ret);
+ ERR("bulk_read failed: %s\n", usb_strerror());
return ret;
} else if(ret == 0)
return 0;
phead = (struct fpga_packet_header *)buf;
if(phead->header.op == BAD_COMMAND) {
- ERR("BAD_COMMAND\n");
+ ERR("Firmware rejected EEPROM_SET command\n");
return -EINVAL;
} else if(phead->header.op != EEPROM_SET) {
ERR("Got unexpected reply op=%d\n", phead->header.op);
return -EINVAL;
}
- if(verbose >= LOG_INFO) {
+ if(verbose >= LOG_DEBUG) {
INFO("%s read %d bytes\n", __FUNCTION__, ret);
dump_packet(buf, ret);
}
@@ -246,33 +269,35 @@ int eeprom_set(struct usb_dev_handle *handle, const struct myeeprom *eeprom)
}
#endif
-int eeprom_get(struct usb_dev_handle *handle, struct myeeprom *eeprom)
+int eeprom_get(struct my_usb_device *mydev)
{
int ret;
int len;
char buf[PACKET_SIZE];
struct fpga_packet_header *phead = (struct fpga_packet_header *)buf;
+ struct myeeprom *eeprom;
- assert(handle != NULL);
- if(verbose >= LOG_INFO)
+ assert(mydev != NULL);
+ eeprom = &mydev->eeprom;
+ if(verbose >= LOG_DEBUG)
INFO("%s Start...\n", __FUNCTION__);
phead->header.op = EEPROM_GET;
len = sizeof(phead->header.op); /* warning: sending small packet */
- if(verbose >= LOG_INFO) {
+ if(verbose >= LOG_DEBUG) {
INFO("%s write %d bytes\n", __FUNCTION__, len);
dump_packet(buf, len);
}
- ret = usb_bulk_write(handle, MY_EP_OUT, (char *)phead, len, TIMEOUT);
+ ret = usb_bulk_write(mydev->handle, MY_EP_OUT, (char *)phead, len, TIMEOUT);
if(ret < 0) {
- ERR("usb: bulk_write failed (%d)\n", ret);
+ ERR("bulk_write failed: %s\n", usb_strerror());
return ret;
} else if(ret != len) {
- ERR("usb: bulk_write short write (%d)\n", ret);
+ ERR("bulk_write short write: %s\n", usb_strerror());
return -EFAULT;
}
- ret = usb_bulk_read(handle, MY_EP_IN, buf, sizeof(buf), TIMEOUT);
+ ret = usb_bulk_read(mydev->handle, MY_EP_IN, buf, sizeof(buf), TIMEOUT);
if(ret < 0) {
- ERR("usb: bulk_read failed (%d)\n", ret);
+ ERR("bulk_read failed: %s\n", usb_strerror());
return ret;
} else if(ret == 0)
return 0;
@@ -284,7 +309,7 @@ int eeprom_get(struct usb_dev_handle *handle, struct myeeprom *eeprom)
ERR("Got unexpected reply op=%d\n", phead->header.op);
return -EINVAL;
}
- if(verbose >= LOG_INFO) {
+ if(verbose >= LOG_DEBUG) {
INFO("%s read %d bytes\n", __FUNCTION__, ret);
dump_packet(buf, ret);
}
@@ -292,7 +317,7 @@ int eeprom_get(struct usb_dev_handle *handle, struct myeeprom *eeprom)
return 0;
}
-int send_hexline(struct usb_dev_handle *handle, struct hexline *hexline, int seq)
+int send_hexline(struct my_usb_device *mydev, struct hexline *hexline, int seq)
{
int ret;
int len;
@@ -301,7 +326,7 @@ int send_hexline(struct usb_dev_handle *handle, struct hexline *hexline, int seq
struct fpga_packet_header *phead = (struct fpga_packet_header *)buf;
enum fpga_load_status status;
- assert(handle != NULL);
+ assert(mydev != NULL);
assert(hexline != NULL);
len = hexline->d.content.header.ll; /* don't send checksum */
data = hexline->d.content.tt_data.data;
@@ -314,21 +339,21 @@ int send_hexline(struct usb_dev_handle *handle, struct hexline *hexline, int seq
phead->d.data_packet.reserved = 0x00;
memcpy(phead->d.data_packet.data, data, len);
len += sizeof(hexline->d.content.header);
- if(verbose >= LOG_INFO)
+ if(verbose >= LOG_DEBUG)
INFO("%04d+\r", seq);
- ret = usb_bulk_write(handle, MY_EP_OUT, (char *)phead, len, TIMEOUT);
+ ret = usb_bulk_write(mydev->handle, MY_EP_OUT, (char *)phead, len, TIMEOUT);
if(ret < 0) {
- ERR("usb: bulk_write failed (%d)\n", ret);
+ ERR("bulk_write failed: %s\n", usb_strerror());
return ret;
} else if(ret != len) {
- ERR("usb: bulk_write short write (%d)\n", ret);
+ ERR("bulk_write short write: %s\n", usb_strerror());
return -EFAULT;
}
if (verbose >= LOG_DEBUG)
dump_packet((char*)phead, len);
- ret = usb_bulk_read(handle, MY_EP_IN, buf, sizeof(buf), TIMEOUT);
+ ret = usb_bulk_read(mydev->handle, MY_EP_IN, buf, sizeof(buf), TIMEOUT);
if(ret < 0) {
- ERR("usb: bulk_read failed (%d)\n", ret);
+ ERR("bulk_read failed: %s\n", usb_strerror());
return ret;
} else if(ret == 0)
return 0;
@@ -361,7 +386,7 @@ int send_hexline(struct usb_dev_handle *handle, struct hexline *hexline, int seq
//. returns > 0 - ok, the number of lines sent
//. returns < 0 - error number
-int send_splited_hexline(struct usb_dev_handle *handle, struct hexline *hexline, int seq, uint8_t maxwidth)
+int send_splited_hexline(struct my_usb_device *mydev, struct hexline *hexline, int seq, uint8_t maxwidth)
{
struct hexline *extraline;
int linessent = 0;
@@ -370,6 +395,7 @@ int send_splited_hexline(struct usb_dev_handle *handle, struct hexline *hexline,
unsigned int this_line = 0;
uint8_t bytesleft = 0;
+ assert(mydev != NULL);
if(!hexline) {
ERR("Bad record %d type = %d\n", seq, hexline->d.content.header.tt);
return -EINVAL;
@@ -390,7 +416,7 @@ int send_splited_hexline(struct usb_dev_handle *handle, struct hexline *hexline,
extraline->d.content.header.offset = hexline->d.content.header.offset + extra_offset;
extraline->d.content.header.tt = hexline->d.content.header.tt;
memcpy( extraline->d.content.tt_data.data, hexline->d.content.tt_data.data+extra_offset, this_line);
- status = send_hexline( handle, extraline, seq+linessent );
+ status = send_hexline(mydev, extraline, seq+linessent );
// cleanups
free(extraline);
extra_offset += this_line;
@@ -402,21 +428,44 @@ int send_splited_hexline(struct usb_dev_handle *handle, struct hexline *hexline,
return linessent;
}
-int my_usb_device(struct usb_device *dev, usb_dev_handle *handle)
+int my_usb_device_init(const char devpath[], struct my_usb_device *mydev)
{
struct usb_device_descriptor *dev_desc;
struct usb_config_descriptor *config_desc;
struct usb_interface *interface;
struct usb_interface_descriptor *iface_desc;
struct usb_endpoint_descriptor *endpoint;
- char iManufacturer[BUFSIZ];
- char iProduct[BUFSIZ];
int ret;
int i;
- assert(dev != NULL);
- dev_desc = &dev->descriptor;
- config_desc = dev->config;
+ assert(mydev != NULL);
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+ mydev->dev = dev_of_path(devpath);
+ if(!mydev->dev) {
+ ERR("Bailing out\n");
+ return 0;
+ }
+ mydev->handle = usb_open(mydev->dev);
+ if(!mydev->handle) {
+ ERR("Failed to open usb device '%s/%s': %s\n", mydev->dev->bus->dirname, mydev->dev->filename, usb_strerror());
+ return 0;
+ }
+ if(usb_reset(mydev->handle) != 0) {
+ ERR("Reseting device: usb: %s\n", usb_strerror());
+ return 0;
+ }
+ if(usb_set_configuration(mydev->handle, MY_CONFIG) != 0) {
+ ERR("usb: %s\n", usb_strerror());
+ return 0;
+ }
+ if(usb_claim_interface(mydev->handle, MY_INTERFACE) != 0) {
+ ERR("usb: %s\n", usb_strerror());
+ return 0;
+ }
+ dev_desc = &mydev->dev->descriptor;
+ config_desc = mydev->dev->config;
interface = config_desc->interface;
iface_desc = interface->altsetting;
if(verbose >= LOG_INFO)
@@ -424,127 +473,86 @@ int my_usb_device(struct usb_device *dev, usb_dev_handle *handle)
dev_desc->idVendor, dev_desc->idProduct, dev_desc->bDeviceClass, iface_desc->bNumEndpoints);
if(iface_desc->bInterfaceClass != 0xFF) {
ERR("Wrong Interface class %d\n", iface_desc->bInterfaceClass);
- return -EINVAL;
+ return 0;
}
if(iface_desc->bInterfaceNumber != MY_INTERFACE) {
ERR("Wrong Interface number %d\n", iface_desc->bInterfaceNumber);
- return -EINVAL;
+ return 0;
}
if(iface_desc->bNumEndpoints != MY_ENDPOINTS) {
ERR("Wrong number of endpoints: %d\n", iface_desc->bNumEndpoints);
- return -EINVAL;
+ return 0;
}
endpoint = iface_desc->endpoint;
+ mydev->is_usb2 = (endpoint->wMaxPacketSize == 512);
for(i = 0; i < iface_desc->bNumEndpoints; i++, endpoint++) {
if(endpoint->bEndpointAddress != my_endpoints[i]) {
ERR("Wrong endpoint %d: address = 0x%X\n", i, endpoint->bEndpointAddress);
- return -EINVAL;
+ return 0;
}
if(endpoint->bEndpointAddress == MY_EP_OUT || endpoint->bEndpointAddress == MY_EP_IN) {
if(endpoint->wMaxPacketSize > PACKET_SIZE) {
ERR("Endpoint #%d wMaxPacketSize too large (%d)\n", i, endpoint->wMaxPacketSize);
- return -EINVAL;
+ return 0;
}
}
}
- if(usb_reset(handle) != 0) {
- ERR("Reseting device: usb: %s\n", usb_strerror());
- }
- if(usb_set_configuration(handle, MY_CONFIG) != 0) {
- ERR("usb: %s\n", usb_strerror());
- return -EINVAL;
- }
- if(usb_claim_interface(handle, MY_INTERFACE) != 0) {
- ERR("usb: %s\n", usb_strerror());
- return -EINVAL;
- }
- if(usb_resetep(handle, MY_EP_OUT) != 0) {
- ERR("usb: %s\n", usb_strerror());
- return -EINVAL;
+ if(usb_resetep(mydev->handle, MY_EP_OUT) != 0) {
+ ERR("Failed to reset usb output endpoint: %s\n", usb_strerror());
+ return 0;
}
- if(usb_resetep(handle, MY_EP_IN) != 0) {
- ERR("usb: %s\n", usb_strerror());
- return -EINVAL;
+ if(usb_resetep(mydev->handle, MY_EP_IN) != 0) {
+ ERR("Failed to reset usb input endpoint: %s\n", usb_strerror());
+ return 0;
}
- ret = get_usb_string(iManufacturer, BUFSIZ, dev_desc->iManufacturer, handle);
- ret = get_usb_string(iProduct, BUFSIZ, dev_desc->iProduct, handle);
- if(verbose >= LOG_INFO)
- INFO("iManufacturer=%s iProduct=%s\n", iManufacturer, iProduct);
- return 0;
+ ret = get_usb_string(mydev->iManufacturer, BUFSIZ, dev_desc->iManufacturer, mydev->handle);
+ ret = get_usb_string(mydev->iProduct, BUFSIZ, dev_desc->iProduct, mydev->handle);
+ ret = get_usb_string(mydev->iSerialNumber, BUFSIZ, dev_desc->iSerialNumber, mydev->handle);
+ return 1;
}
-int renumerate_device(struct usb_dev_handle *handle)
+int renumerate_device(struct my_usb_device *mydev)
{
char buf[PACKET_SIZE];
struct fpga_packet_header *phead = (struct fpga_packet_header *)buf;
int ret;
- assert(handle != NULL);
+ assert(mydev != NULL);
if(verbose >= LOG_INFO)
INFO("Renumerating\n");
phead->header.op = RENUMERATE;
- ret = usb_bulk_write(handle, MY_EP_OUT, (char *)phead, 1, TIMEOUT);
+ ret = usb_bulk_write(mydev->handle, MY_EP_OUT, (char *)phead, 1, TIMEOUT);
if(ret < 0) {
- ERR("usb: bulk_write failed (%d)\n", ret);
+ ERR("bulk_write failed: %s\n", usb_strerror());
return ret;
} else if(ret != 1) {
- ERR("usb: bulk_write short write (%d)\n", ret);
+ ERR("bulk_write short write: %s\n", usb_strerror());
return -EFAULT;
}
return 0;
}
-int fpga_load(struct usb_dev_handle *handle, const struct hexdata *hexdata)
+/*
+ * Returns: true on success, false on failure
+ */
+int fpga_load(struct my_usb_device *mydev, const struct hexdata *hexdata)
{
unsigned int i;
+ unsigned int j = 0;
int ret;
int finished = 0;
- assert(handle != NULL);
+ assert(mydev != NULL);
if(verbose >= LOG_INFO)
INFO("Start...\n");
-
- for(i = 0; i < hexdata->maxlines; i++) {
- struct hexline *hexline = hexdata->lines[i];
-
- if(!hexline)
- break;
- if(finished) {
- ERR("Extra data after End Of Data Record (line %d)\n", i);
- return 0;
- }
- if(hexline->d.content.header.tt == TT_EOF) {
- INFO("End of data\n");
- finished = 1;
- continue;
- }
- if((ret = send_hexline(handle, hexline, i)) != 0) {
- perror("Failed sending hexline");
- return 0;
- }
- }
- if(verbose >= LOG_INFO)
- INFO("Finished...\n");
- return 1;
-}
-
-int fpga_load_usb1(struct usb_dev_handle *handle, const struct hexdata *hexdata)
-{
- unsigned int i,j=0;
- int ret;
- int finished = 0;
-
- assert(handle != NULL);
- if(verbose >= LOG_INFO)
- INFO("Start...\n");
-
- // i - is the line number
- // j - is the sequence number, on USB 2, i=j, but on
- // USB 1 send_splited_hexline may increase the sequence
- // number, as it needs
+ /*
+ * i - is the line number
+ * j - is the sequence number, on USB 2, i=j, but on
+ * USB 1 send_splited_hexline may increase the sequence
+ * number, as it needs
+ */
for(i = 0; i < hexdata->maxlines; i++) {
struct hexline *hexline = hexdata->lines[i];
-
if(!hexline)
break;
@@ -553,16 +561,23 @@ int fpga_load_usb1(struct usb_dev_handle *handle, const struct hexdata *hexdata)
return 0;
}
if(hexline->d.content.header.tt == TT_EOF) {
- INFO("End of data\n");
+ if(verbose >= LOG_INFO)
+ INFO("End of data\n");
finished = 1;
continue;
}
-
- if((ret = send_splited_hexline(handle, hexline, j, 60)) < 0) {
- perror("Failed sending hexline (splitting did not help)");
- return 0;
+ if(mydev->is_usb2) {
+ if((ret = send_hexline(mydev, hexline, i)) != 0) {
+ perror("Failed sending hexline");
+ return 0;
+ }
+ } else {
+ if((ret = send_splited_hexline(mydev, hexline, j, 60)) < 0) {
+ perror("Failed sending hexline (splitting did not help)");
+ return 0;
+ }
+ j += ret;
}
- j += ret;
}
if(verbose >= LOG_INFO)
INFO("Finished...\n");
@@ -573,10 +588,9 @@ int fpga_load_usb1(struct usb_dev_handle *handle, const struct hexdata *hexdata)
void usage()
{
- fprintf(stderr, "Usage: %s -D /proc/bus/usb/<bus>/<dev> [options...]\n", progname);
+ fprintf(stderr, "Usage: %s -D {/proc/bus/usb|/dev/bus/usb}/<bus>/<dev> [options...]\n", progname);
fprintf(stderr, "\tOptions:\n");
fprintf(stderr, "\t\t[-b <binfile>] # output to <binfile>\n");
- fprintf(stderr, "\t\t[-d] # Get device version from eeprom\n");
fprintf(stderr, "\t\t[-I <hexfile>] # Input from <hexfile>\n");
fprintf(stderr, "\t\t[-g] # Get eeprom from device\n");
#ifdef XORCOM_INTERNAL
@@ -599,27 +613,14 @@ static void parse_report_func(int level, const char *msg, ...)
va_end(ap);
}
-int hasUSB2( struct usb_device *dev )
-{
- if (dev->config->interface->altsetting->endpoint->wMaxPacketSize != 512)
- return 0;
- else
- return 1;
-}
-
-// usb_interface_descriptor->usb_endpoint_descriptor.wMaxPacketSize
-
int main(int argc, char *argv[])
{
- struct usb_device *dev;
- usb_dev_handle *handle;
+ struct my_usb_device mydev;
const char *devpath = NULL;
const char *binfile = NULL;
const char *hexfile = NULL;
struct hexdata *hexdata = NULL;
- struct myeeprom eeprom_buf;
int opt_read_eeprom = 0;
- int opt_print_bcdver_only = 0;
#ifdef XORCOM_INTERNAL
int opt_write_eeprom = 0;
char *vendor = NULL;
@@ -629,9 +630,9 @@ int main(int argc, char *argv[])
char *release = NULL;
char *serial = NULL;
uint8_t serial_buf[SERIAL_SIZE];
- const char options[] = "b:C:dD:ghI:vV:P:R:S:";
+ const char options[] = "b:C:D:ghI:vV:P:R:S:";
#else
- const char options[] = "b:dD:ghI:v";
+ const char options[] = "b:D:ghI:v";
#endif
int ret = 0;
@@ -652,10 +653,6 @@ int main(int argc, char *argv[])
case 'b':
binfile = optarg;
break;
- case 'd':
- opt_print_bcdver_only = 1;
- opt_read_eeprom = 1;
- break;
case 'g':
opt_read_eeprom = 1;
break;
@@ -730,97 +727,74 @@ int main(int argc, char *argv[])
ERR("Missing device path\n");
usage();
}
- if(verbose)
+#ifdef XORCOM_INTERNAL
+ if(vendor || product || release || serial || source )
+ opt_read_eeprom = opt_write_eeprom = 1;
+#endif
+ if(verbose >= LOG_INFO)
INFO("Startup %s\n", devpath);
- usb_init();
- usb_find_busses();
- usb_find_devices();
- dev = dev_of_path(devpath);
- if(!dev) {
- ERR("Bailing out\n");
- exit(1);
- }
- handle = usb_open(dev);
- if(!handle) {
- ERR("Failed to open usb device '%s/%s': %s\n", dev->bus->dirname, dev->filename, usb_strerror());
- return -ENODEV;
- }
- if(my_usb_device(dev, handle)) {
- ERR("Foreign usb device '%s/%s'\n", dev->bus->dirname, dev->filename);
+ if(!my_usb_device_init(devpath, &mydev)) {
+ ERR("Failed to initialize USB device '%s'\n", devpath);
ret = -ENODEV;
goto dev_err;
}
-
+ ret = eeprom_get(&mydev);
+ if(ret < 0) {
+ ERR("Failed reading eeprom\n");
+ goto dev_err;
+ }
+ if(opt_read_eeprom) {
+ show_device_info(&mydev);
+ }
if(hexdata) {
- int status;
-
- if (hasUSB2(dev))
- status = fpga_load(handle, hexdata);
- else {
+ if (!mydev.is_usb2)
INFO("Warning: working on a low end USB1 backend\n");
- status = fpga_load_usb1(handle, hexdata);
- }
-
- if(!status) {
+ if(!fpga_load(&mydev, hexdata)) {
ERR("FPGA loading failed\n");
ret = -ENODEV;
goto dev_err;
}
- ret = renumerate_device(handle);
+ ret = renumerate_device(&mydev);
if(ret < 0) {
ERR("Renumeration failed: errno=%d\n", ret);
goto dev_err;
}
}
-#ifdef XORCOM_INTERNAL
- if(vendor || product || release || serial || source )
- opt_read_eeprom = opt_write_eeprom = 1;
-#endif
- if(opt_read_eeprom) {
- ret = eeprom_get(handle, &eeprom_buf);
- if(ret < 0) {
- ERR("Failed reading eeprom: %d\n", ret);
- goto dev_err;
- }
- if (opt_print_bcdver_only)
- print_bcd_ver(&eeprom_buf);
- else
- dump_eeprom(&eeprom_buf);
- }
#ifdef XORCOM_INTERNAL
if(opt_write_eeprom) {
// FF: address source is from device. C0: from eeprom
if (is_source_given)
- eeprom_buf.source = strtoul(source, NULL, 0);
+ mydev.eeprom.source = strtoul(source, NULL, 0);
else
- eeprom_buf.source = 0xC0;
+ mydev.eeprom.source = 0xC0;
if(vendor)
- eeprom_buf.vendor = strtoul(vendor, NULL, 0);
+ mydev.eeprom.vendor = strtoul(vendor, NULL, 0);
if(product)
- eeprom_buf.product = strtoul(product, NULL, 0);
+ mydev.eeprom.product = strtoul(product, NULL, 0);
if(release) {
int release_major = 0;
int release_minor = 0;
sscanf(release, "%d.%d", &release_major, &release_minor);
- eeprom_buf.release_major = release_major;
- eeprom_buf.release_minor = release_minor;
+ mydev.eeprom.release_major = release_major;
+ mydev.eeprom.release_minor = release_minor;
}
if(serial) {
- memcpy(eeprom_buf.serial, serial_buf, SERIAL_SIZE);
+ memcpy(&mydev.eeprom.serial, serial_buf, SERIAL_SIZE);
}
- dump_eeprom(&eeprom_buf);
- ret = eeprom_set(handle, &eeprom_buf);
+ ret = eeprom_set(&mydev, &mydev.eeprom);
if(ret < 0) {
- ERR("Failed writing eeprom: %d\n", ret);
+ ERR("Failed writing eeprom: %s\n", strerror(-ret));
goto dev_err;
}
+ printf("------- RESULTS -------\n");
+ show_device_info(&mydev);
}
#endif
- if(verbose)
+ if(verbose >= LOG_INFO)
INFO("Exiting\n");
dev_err:
- usb_cleanup(handle);
+ my_usb_device_cleanup(&mydev);
return ret;
}
diff --git a/xpp/utils/genzaptelconf b/xpp/utils/genzaptelconf
index 03c28be..a5fb0b0 100755
--- a/xpp/utils/genzaptelconf
+++ b/xpp/utils/genzaptelconf
@@ -50,10 +50,6 @@ context_output=astbank-output # useless, but helps marking the channels :-)
#group_manual=yes
group_phones=5 # group for phones
group_lines=0 # group for lines
-# set 'immediate=yes' for Asteribank input channels and 'immediate=no'
-# for others. Note that if an Astribank is not detected, the script
-# will set this to "no", so you can safely leave it as "yes".
-set_immediate=yes
# Set fxs_immediate to 'yes' to make all FXS lines answer immediately.
fxs_immediate=no
@@ -231,15 +227,6 @@ zap_reg_xpp() {
}
-check_for_astribank(){
- if ! grep -q XPP_IN/ /proc/zaptel/* 2>/dev/null
- then
- # we only get here is if we find no Astribank input channels
- # in /proc/zaptel . Hence we can safely disable their special settings:
- set_immediate=no
- fi
-}
-
usage() {
program=`basename $0`
@@ -395,14 +382,11 @@ print_pattern() {
fi
fi
- if [ "$set_immediate" = 'yes' ]
- then
- if [ "$astbank_type" = 'input' ] || \
- ( [ "$fxs_immediate" = 'yes' ] && [ "$sig" = "fxo" ] )
- then
- echo 'immediate=yes' >> $zapata_file
- reset_values="$reset_values immediate"
- fi
+ if [ "$astbank_type" = 'input' ] || \
+ ( [ "$fxs_immediate" = 'yes' ] && [ "$sig" = "fxo" ] )
+ then
+ echo 'immediate=yes' >> $zapata_file
+ reset_values="$reset_values immediate"
fi
echo "channel => $chan" >> $zapata_file
reset_zapata_entry $zapata_file $reset_values
@@ -1028,14 +1012,10 @@ if [ "$mode" = list ]; then
genconf list
else
zap_reg_xpp
- check_for_astribank
wait_for_zapctl
say "Generating '${ZAPCONF_FILE} and ${ZAPATA_FILE}'"
genconf files
- if [ "$set_immediate" = 'yes' ] && [ -x /etc/init.d/zaptel ]
- then /etc/init.d/zaptel start
- else run_ztcfg
- fi
+ run_ztcfg
fi
if [ "$tmp_dir" != '' ]
diff --git a/xpp/utils/xpp.rules b/xpp/utils/xpp.rules
new file mode 100644
index 0000000..8a669b1
--- /dev/null
+++ b/xpp/utils/xpp.rules
@@ -0,0 +1,8 @@
+BUS!="usb", ACTION!="add", GOTO="xpp_usb_add_end"
+
+# Load firmware into the Xorcom Astribank device:
+SYSFS{idVendor}=="e4e4", SYSFS{idProduct}=="11[345][01]", \
+ RUN+="/etc/hotplug/usb/xpp_fxloader udev $sysfs{idVendor}/$sysfs{idProduct}/$sysfs{bcdDevice}"
+
+LABEL="xpp_usb_add_end"
+
diff --git a/xpp/utils/xpp_fxloader b/xpp/utils/xpp_fxloader
index b14f746..918a712 100644
--- a/xpp/utils/xpp_fxloader
+++ b/xpp/utils/xpp_fxloader
@@ -1,8 +1,8 @@
#!/bin/sh
-# xpp_fxload: load XPP firmware
+# xpp_fxloader: load Xorcom Astribank (XPP) firmware
#
-# This script can be run manually or from hotplug.
+# This script can be run manually or from hotplug/udev.
#
# Firmware files should be located in $FIRMWARE_DIR which defaults:
# 1. /usr/share/zaptel
@@ -12,28 +12,21 @@
# Manual Run
# ##########
#
-# path/to/xpp_fxloader xppdetect
+# path/to/xpp_fxloader load
#
# Make sure the firmware files are in $FIRMWARE_DIR
#
+# UDEV Installation
+# #################
#
-# Hotplg Run
-# ##########
+# Copy xpp.rules to /etc/udev/udev.d and xpp_fxloader to /etc/hotplug/usb/ .
#
-# 1. Copy this file and the file xpp_fxloader.usermap to /etc/hotplug/usb/
-# 2. tail -f /var/log/messages...
+# Hotplug Installation
+# ####################
#
-#
-# Suggested udev configuration: I used the following file as
-# /etc/udev/rules.d/z60_zaptel.rules :
+# Copy this file and the file xpp_fxloader.usermap to /etc/hotplug/usb/ .
#
-# BUS!="usb", ACTION!="add", GOTO="zaptel_usb_add_end"
#
-# SYSFS{idVendor}=="e4e4", SYSFS{idProduct}=="11[345][01]", \
-# RUN+="/etc/hotplug/usb/xpp_fxloader udev $sysfs{idVendor}/$sysfs{idProduct}/$sysfs{bcdDevice}"
-#
-# LABEL="zaptel_usb_add_end"
-#
# Written by Tzafrir Cohen <tzafrir.cohen@xorcom.com>
# Copyright (C) 2006, Xorcom
#
@@ -64,16 +57,28 @@ else
LOGGER="logger -i -t '$me'"
fi
-if [ -r "$DEFAULTS" ]; then
- . "$DEFAULTS"
-fi
+USBFS_PREFIX=/proc/bus/usb
+DEVUSB_PREFIX=/dev/bus/usb
+USB_PREFIX=
FIRMWARE_DIR="${FIRMWARE_DIR:-/usr/share/zaptel}"
FIRM_FXS=$FIRMWARE_DIR/FPGA_FXS.hex
REENUM_SLEEP_TIME=3 # only used on manual runs
-FPGA_LOAD="/usr/sbin/fpga_load"
+FPGA_LOAD=${FPGA_LOAD:-/usr/sbin/fpga_load}
+
+if [ -r "$DEFAULTS" ]; then
+ . "$DEFAULTS"
+fi
+
+if [ "$USB_PREFIX" = '' ]; then
+ if [ -d "$DEVUSB_PREFIX" ]; then
+ USB_PREFIX=$DEVUSB_PREFIX
+ elif [ -r "$USBFS_PREFIX/devices" ]; then
+ USB_PREFIX=$USBFS_PREFIX
+ fi
+fi
# With Kernels older that 2.6.10 it seems to be possible
# to trigger a race condition by running fxload or fpga_load
@@ -90,7 +95,7 @@ find_dev() {
v_id=$1
p_id=$2
- lsusb | tr -d : | awk "/ ID $v_id$p_id/{printf \"/proc/bus/usb/%s/%s \",\$2,\$4}"
+ lsusb | tr -d : | awk "/ ID $v_id$p_id/{printf \"$USB_PREFIX/%s/%s \",\$2,\$4}"
}
do_fxload() {
@@ -128,7 +133,7 @@ load_fpga() {
devices=`find_dev $v_id $p_id`
for dev in $devices
do
- card_ver=`$FPGA_LOAD -d -D $dev`
+ card_ver=`$FPGA_LOAD -g -D $dev | sed -n 's/^.*Release: *//'`
firm_ver=`hexfile_version $FIRMWARE_DIR/$fw`
$LOGGER "FPGA Firmware $FIRMWARE_DIR/$fw into $dev"
@@ -151,7 +156,7 @@ load_fpga() {
case "$1" in
udev)
# the following emulate hotplug's environment from udev's environment:
- DEVICE=`echo $DEVNAME | sed -e 's|^/dev/|/proc/|'`
+ DEVICE="$DEVNAME"
PRODUCT="$2"
# skip on to the rest of the script. Don't exit.
;;
@@ -190,7 +195,7 @@ esac
## Hotplug run
##
-if [ "$ACTION" = "add" ] && [ -f "$DEVICE" ]
+if [ "$ACTION" = "add" ] && [ -w "$DEVICE" ]
then
$LOGGER "Trying to find what to do for product $PRODUCT, device $DEVICE"
prod_id=`echo "$PRODUCT" | cut -d/ -f2`
diff --git a/xpp/utils/zaptel-helper b/xpp/utils/zaptel-helper
new file mode 100644
index 0000000..1b2ca45
--- /dev/null
+++ b/xpp/utils/zaptel-helper
@@ -0,0 +1,401 @@
+#!/bin/sh
+
+# zaptel-helper: helper script/functions for Zaptel
+
+# Wrriten by Tzafrir Cohen <tzafrir.cohen@xorcom.com>
+# Copyright (C) 2006-2007, Xorcom
+#
+# All rights reserved.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# Should be possible to run with -e set. This is also recommended.
+
+# Constants:
+# maximal time (in seconds) to wait for /dev/zap/dtl to appear after
+# loading zaptel
+DEVZAP_TIMEOUT=${DEVZAP_TIMEOUT:-20}
+
+# Zaptel modules we'll try when detecting zaptel hardware:
+ALL_MODULES="${ALL_MODULES:-zaphfc qozap ztgsm wctdm wctdm24xxp wcfxo wcfxs pciradio tor2 torisa wct1xxp wct4xxp wcte11xp wanpipe wcusb xpp_usb}"
+
+# Where do we write the list of modules we detected (if at all):
+MODLIST_FILE_DEBIAN=${MODLIST_FILE_DEBIAN:-/etc/modules}
+MODLIST_FILE_REDHAT=${MODLIST_FILE_REDHAT:-/etc/sysconfig/zaptel}
+
+# The location of of the fxotune binary
+FXOTUNE="${FXOTUNE:-/usr/sbin/fxotune}"
+FXOTUNE_CONF="${FXOTUNE_CONF:-/etc/fxotune.conf}"
+
+# this is the context FXO zaptel channels are in.
+# See run_fxotune.
+FXO_CONTEXT=${FXO_CONTEXT:-from-pstn}
+
+ZTCFG="${ZTCFG:-/sbin/ztcfg}"
+
+# TODO: this may not be appropriate for a general-purpose script.
+# However you should not use a direct 'echo' to write output to the user
+#, to make it simple to override.
+say() {
+ echo "$@"
+}
+
+error() {
+ echo >&2 "$@"
+}
+
+die() {
+ error "$@"
+ exit 1
+}
+
+
+#############################################################################
+#####
+##### Init helper functions
+#####
+
+
+# Wait for udev to generate /dev/zap/ctl, if needed:
+wait_for_zapctl() {
+ # if device file already exists, or if zaptel has failed to load:
+ # no point waiting.
+ if [ -c /dev/zap/ctl ] || ! grep -q zaptel /proc/modules ; then
+ return
+ fi
+
+ say "Waiting for /dev/zap/ctl to be generated"
+ devzap_found=0
+ for i in `seq $DEVZAP_TIMEOUT`; do
+ sleep 1
+ if [ -c /dev/zap/ctl ]; then
+ devzap_found=1
+ break
+ fi
+ done
+ if [ "$devzap_found" != 1 ]; then
+ say "Still no /dev/zap/ctl after $devzap_timeout seconds."
+ error "No /dev/zap/ctl: cannot run ztcfg. Aborting."
+ fi
+}
+
+# load the fxotune parameters
+# FIXME: /etc/fxotune.conf is a bad location for that file .
+# /etc/zaptel/fxotune.conf?
+fxotune_load() {
+ if [ -x "$FXOTUNE" ] && [ -r "FXOTUNE_CONF" ]; then
+ $FROTUNE -s
+ fi
+}
+
+# If there is no zaptel timing source, load
+# ztdummy. Other modules should have been loaded by
+# now.
+guarantee_timing_source() {
+ if ! head -c 0 /dev/zap/pseudo 2>/dev/null
+ then modprobe ztdummy || true # will fail if there is no module package
+ fi
+}
+
+kill_zaptel_users() {
+ fuser -k /dev/zap/*
+}
+
+# recursively unload a module and its dependencies, if possible.
+# where's modprobe -r when you need it?
+# inputs: module to unload.
+# returns: the result from
+unload_module() {
+ module="$1"
+ line=`lsmod 2>/dev/null | grep "^$1 "`
+ if [ "$line" = '' ]; then return; fi # module was not loaded
+
+ set -- $line
+ # $1: the original module, $2: size, $3: refcount, $4: deps list
+ mods=`echo $4 | tr , ' '`
+ for mod in $mods; do
+ # run in a subshell, so it won't step over our vars:
+ (unload_module $mod)
+ # TODO: the following is probably the error handling we want:
+ # if [ $? != 0 ]; then return 1; fi
+ done
+ rmmod $module
+}
+
+# sleep a while until the xpp modules fully register
+wait_for_xpp() {
+ if [ -d /proc/xpp ]
+ then
+ # wait for the XPDs to register:
+ # TODO: improve error reporting and produce a messagee here
+ cat /proc/xpp/XBUS-*/waitfor_xpds 2>/dev/null >/dev/null || true
+ fi
+}
+
+zap_reg_xpp() {
+ if [ ! -d /proc/xpp ]; then return; fi
+
+ # Get a list of connected Astribank devices, sorted by the name of
+ # the USB connector. That order is rather arbitrary, but will not
+ # change without changes to the cabling.
+ xbusses=`sort -k 2 /proc/xpp/xbuses | awk -F: '/STATUS=connected/ {print $1}'`
+
+ # get a list of XPDs that were not yet registered as zaptel spans.
+ # this will be the case if you set the parameter zap_autoreg=0 to
+ # the module xpp
+ # Append /dev/null to provide a valid file name in case of an empty pattern.
+ xbusses_pattern=`echo $xbusses| sed -e 's|XBUS-[0-9]*|/proc/xpp/&/XPD-*/zt_registration|g'`' /dev/null'
+ xpds_to_register=`grep -l 0 $xbusses_pattern 2>/dev/null` || true
+ for file in $xpds_to_register; do
+ echo 1 >$file
+ done
+}
+
+# Set the sync source of the Astribank to the right value
+fix_asterisbank_sync() {
+ # do nothing if module not present
+ if [ ! -d /proc/xpp ]; then return; fi
+
+ #if ! grep -q '^HOST' /proc/xpp/sync 2>/dev/null; then return; fi
+
+ case "$XPP_SYNC" in
+ n*|N*) return;;
+ host|HOST) sync_value="HOST";;
+ [0-9]*)sync_value="$XPP_SYNC";;
+ *)
+ # find the number of the first bus, and sync from it:
+ fxo_pat=`awk -F: '/STATUS=connected/{print $1}' /proc/xpp/xbuses | sed -e 's|.*|/proc/xpp/&/*/fxo_info|'`
+ # find the first FXO unit, and set it as the sync master
+ bus=`ls -1 $fxo_pat 2> /dev/null | head -n1 | cut -d- -f2 | cut -d/ -f1`
+
+ # do nothing if there is no bus:
+ case "$bus" in [0-9]*):;; *) return;; esac
+ sync_value="$bus 0"
+ ;;
+ esac
+ # the built-in echo of bash fails to print a proper error on failure
+ if ! /bin/echo "$sync_value" >/proc/xpp/sync
+ then
+ error "Updating XPP sync source failed (used XPP_SYNC='$XPP_SYNC')"
+ fi
+}
+
+run_adj_clock() {
+ if [ "$XPP_RUN_ADJ_CLOCK" = '' ]; then return; fi
+
+ # daemonize adj_clock:
+ (adj_clock </dev/null >/dev/null 2>&1 &)&
+}
+
+init_astribank() {
+ wait_for_xpp
+ zap_reg_xpp
+ fix_asterisbank_sync
+ run_adj_clock
+}
+
+xpp_do_blink() {
+ val="$1"
+ shift
+ for xbus in $*
+ do
+ for xpd in /proc/xpp/XBUS-"$xbus"/XPD-*
+ do
+ echo "$val" > "$xpd/blink"
+ done
+ done
+}
+
+xpp_blink() {
+ xbuses=`grep STATUS=connected /proc/xpp/xbuses | sed -e 's/^XBUS-//' -e 's/:.*$//'`
+ num=`echo $1 | tr -c -d 0-9`
+ case "$num" in
+ [0-9]*)
+ shift
+ xpp_do_blink 1 $xbuses
+ sleep 2
+ xpp_do_blink 0 $xbuses
+ ;;
+ *)
+ shift
+ echo 1>&2 Enumerating $xbuses
+ xpp_do_blink 0 $xbuses
+ for i in $xbuses
+ do
+ echo "BLINKING: $i"
+ xpp_do_blink 1 "$i"
+ sleep 2
+ xpp_do_blink 0 "$i"
+ done
+ ;;
+ esac
+}
+
+# The current Debian start function.
+# The function is not responsible for loading the zaptel modules:
+# they will be loaded beforehand.
+debian_start() {
+ wait_for_xpp
+ zap_reg_xpp
+ fix_asterisbank_sync
+ wait_for_zapctl
+
+ if [ -r /etc/fxotune.conf ] && [ -x $FXOTUNE ]; then
+ $FXOTUNE -s
+ fi
+
+ # configure existing modules:
+ $ZTCFG
+}
+
+
+# run_fxotune: destroy all FXO channels and run fxotune.
+# This allows running fxotune without completly shutting down Asterisk.
+#
+# A simplistic assumption: every zaptel channel in the context from-pstn
+# is a FXO ones.
+# or rather: all tunable FXO channels are in the context from-pstn are
+# not defined by zaptel.
+run_fxotune() {
+ zap_fxo_chans=`asterisk -rx "zap show channels" | awk "/$FXO_CONTEXT/{print \$1}"`
+ xpp_fxo_chans=`cat /proc/zaptel/* | awk '/XPP_FXO/{print $1}'`
+ for chan in $xpp_fxo_chans $zap_fxo_chans; do
+ asterisk -rx "zap destroy channel $chan"
+ done
+ $FXOTUNE -i
+ asterisk -rx "zap restart"
+}
+
+
+# recursively unload a module and its dependencies, if possible.
+# where's modprobe -r when you need it?
+# inputs: module to unload.
+unload_module() {
+ set +e
+ module="$1"
+ line=`lsmod 2>/dev/null | grep "^$module "`
+ if [ "$line" = '' ]; then return; fi # module was not loaded
+
+ set -- $line
+ # $1: the original module, $2: size, $3: refcount, $4: deps list
+ mods=`echo $4 | tr , ' '`
+ # xpd_fxs actually sort of depends on xpp:
+ case "$module" in xpd_*) mods="xpp_usb $mods";; esac
+ for mod in $mods; do
+ # run in a subshell, so it won't step over our vars:
+ (unload_module $mod)
+ done
+ rmmod $module || true
+ set -e
+}
+
+unload() {
+ unload_module zaptel
+}
+
+# sleep a while until the xpp modules fully register
+wait_for_xpp() {
+ if [ -d /proc/xpp ] && \
+ [ "`cat /sys/module/xpp/parameters/zap_autoreg`" = 'Y' ]
+ then
+ # wait for the XPDs to register:
+ # TODO: improve error reporting and produce a messagee here
+ cat /proc/xpp/XBUS-*/waitfor_xpds 2>/dev/null >/dev/null || true
+ fi
+}
+
+#############################################################################
+#####
+##### Hardware detection functions
+#####
+
+load_modules() {
+ say "Test Loading modules:"
+ for i in $ALL_MODULES
+ do
+ lines_before=`count_proc_zap_lines`
+ args="${i}_args"
+ eval "args=\$$args"
+ # a module is worth listing if it:
+ # a. loaded successfully, and
+ # b. added channels lines under /proc/zaptel/*
+ if /sbin/modprobe $i $args 2> /dev/null
+ then
+ check=0
+ case "$i" in
+ xpp_usb) check=`grep 'STATUS=connected' 2>/dev/null /proc/xpp/xbuses | wc -l` ;;
+ # FIXME: zttranscode will always load, and will never
+ # add a span. Maybe try to read from /dev/zap/transcode .
+ zttranscode) : ;;
+ *) if [ $lines_before -lt `count_proc_zap_lines` ]; then check=1; fi ;;
+ esac
+ if [ "$check" != 0 ]
+ then
+ probed_modules="$probed_modules $i"
+ say " ok $i $args"
+ else
+ say " - $i $args"
+ rmmod $i
+ fi
+ else
+ say " - $i $args"
+ fi
+ done
+}
+
+update_module_list_debian() {
+ say "Updating Debian modules list $MODLIST_FILE_DEBIAN."
+ del_args=`for i in $ALL_MODULES ztdummy
+ do
+ echo "$i" | sed s:.\*:-e\ '/^&/d':
+ done`
+ add_args=`for i in $*
+ do
+ echo "$i" | sed s:.\*:-e\ '\$a&':
+ done`
+
+ sed -i.bak $del_args "$MODLIST_FILE_DEBIAN"
+ for i in $*
+ do
+ echo "$i"
+ done >> "$MODLIST_FILE_DEBIAN"
+}
+
+update_module_list_redhat() {
+ say "Updating modules list in zaptel init config $MODLIST_FILE_REDHAT."
+ sed -i.bak -e '/^MODULES=/d' "$MODLIST_FILE_REDHAT"
+ echo "MODULES=\"$*\"" >> "$MODLIST_FILE_REDHAT"
+}
+
+update_module_list() {
+ if [ -f "$MODLIST_FILE_DEBIAN" ]; then
+ update_module_list_debian "$@"
+ elif [ -f "$MODLIST_FILE_REDHAT" ]; then
+ update_module_list_redhat "$@"
+ else
+ die "Can't find a modules list to update. Tried: $MODLIST_FILE_DEBIAN, $MODLIST_FILE_REDHAT. Aborting"
+ fi
+}
+
+
+
+
+
+
+# unless we wanted to use this as a set of functions, run
+# the given function with its parameters:
+if [ "$ZAPHELPER_ONLY_INCLUDE" = '' ]; then
+ "$@"
+fi