From cc599ab08d6f58a2d5e57db4150e2f9efe1112b8 Mon Sep 17 00:00:00 2001 From: tzafrir Date: Fri, 9 Feb 2007 19:12:55 +0000 Subject: 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 --- xpp/utils/Makefile | 27 ++- xpp/utils/fpga_load.8 | 22 ++- xpp/utils/fpga_load.c | 428 +++++++++++++++++++++++------------------------- xpp/utils/genzaptelconf | 32 +--- xpp/utils/xpp.rules | 8 + xpp/utils/xpp_fxloader | 53 +++--- xpp/utils/zaptel-helper | 401 +++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 678 insertions(+), 293 deletions(-) create mode 100644 xpp/utils/xpp.rules create mode 100644 xpp/utils/zaptel-helper (limited to 'xpp/utils') 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// [options...]\n", progname); + fprintf(stderr, "Usage: %s -D {/proc/bus/usb|/dev/bus/usb}// [options...]\n", progname); fprintf(stderr, "\tOptions:\n"); fprintf(stderr, "\t\t[-b ] # output to \n"); - fprintf(stderr, "\t\t[-d] # Get device version from eeprom\n"); fprintf(stderr, "\t\t[-I ] # Input from \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 # 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 +# 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 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 -- cgit v1.2.3