summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTzafrir Cohen <tzafrir.cohen@xorcom.com>2008-10-16 17:40:22 +0000
committerTzafrir Cohen <tzafrir.cohen@xorcom.com>2008-10-16 17:40:22 +0000
commit12058f5c95e9dbfddea2c0dc8d1a9f32b6d431b5 (patch)
tree4a6a549a985c1a04e9b370fca3b2e8922228efad
parentfdaba144813046745154ec3425705a80e2ca5eb6 (diff)
xpp: start migration from procfs to sysfs.
* Sysfs representation for XPDs: /sys/bus/xpds/devices/<bus>:<unit>:<subunit> * Astribanks sysfs directories now include the XPDs as subdirectories: e.g. /sys/bus/astribanks/devices/xbus-00/00:3:0 * procfs control interface deprecated: conditioned by OLD_PROC (defaults to off). Control functionality moved to sysfs: * xbus attributes: cls connector label status timing waitfor_xpds xbus_state * XPDs can have driver-specific attributes. Common attriubtes: blink chipregs span * PRI-specific attributes: pri_clocking pri_dchan pri_cas pri_alarms pri_layer1 pri_localloop pri_protocol * The Astribank attribute "xbus_state" is read/write. Reading it shows the current state of the Astribank. Writing "start" or "stop" allows a software equivalent of connect or disconnect respectively. * When an Astribank is ready it sends an "online" event. Whenever its not ready (e.g. at the time of disconnect) it sends an "offline" event. Use astribank_hook.sample to handle those. git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@5097 a0bf4364-ded3-4de4-8d8a-66a801d63aff
-rw-r--r--drivers/dahdi/xpp/Kbuild5
-rwxr-xr-xdrivers/dahdi/xpp/astribank_hook.sample26
-rw-r--r--drivers/dahdi/xpp/card_bri.c49
-rw-r--r--drivers/dahdi/xpp/card_fxo.c45
-rw-r--r--drivers/dahdi/xpp/card_fxs.c46
-rw-r--r--drivers/dahdi/xpp/card_global.c65
-rw-r--r--drivers/dahdi/xpp/card_global.h3
-rw-r--r--drivers/dahdi/xpp/card_pri.c403
-rwxr-xr-xdrivers/dahdi/xpp/init_card_1_3037
-rwxr-xr-xdrivers/dahdi/xpp/init_card_2_3031
-rwxr-xr-xdrivers/dahdi/xpp/init_card_3_3029
-rwxr-xr-xdrivers/dahdi/xpp/init_card_4_3045
-rw-r--r--drivers/dahdi/xpp/mmapdrv.c12
-rw-r--r--drivers/dahdi/xpp/xbus-core.c743
-rw-r--r--drivers/dahdi/xpp/xbus-core.h72
-rw-r--r--drivers/dahdi/xpp/xbus-pcm.c69
-rw-r--r--drivers/dahdi/xpp/xbus-sysfs.c695
-rw-r--r--drivers/dahdi/xpp/xdefs.h12
-rw-r--r--drivers/dahdi/xpp/xframe_queue.c10
-rw-r--r--drivers/dahdi/xpp/xframe_queue.h3
-rw-r--r--drivers/dahdi/xpp/xpd.h30
-rw-r--r--drivers/dahdi/xpp/xpp.rules6
-rw-r--r--drivers/dahdi/xpp/xpp_dahdi.c249
-rw-r--r--drivers/dahdi/xpp/xpp_dahdi.h7
-rw-r--r--drivers/dahdi/xpp/xpp_usb.c40
-rw-r--r--drivers/dahdi/xpp/xproto.c12
-rw-r--r--drivers/dahdi/xpp/xproto.h2
27 files changed, 1986 insertions, 760 deletions
diff --git a/drivers/dahdi/xpp/Kbuild b/drivers/dahdi/xpp/Kbuild
index 5ee59d2..3b41e18 100644
--- a/drivers/dahdi/xpp/Kbuild
+++ b/drivers/dahdi/xpp/Kbuild
@@ -3,7 +3,7 @@ EXTRA_CFLAGS = $(XPP_LOCAL_CFLAGS) \
-DPOLL_DIGITAL_INPUTS \
-DDEBUG_PCMTX \
-DPROTOCOL_DEBUG \
- -g
+ -g # -DOLD_PROC
#
WITH_BRISTUFF := $(shell grep -c '^[[:space:]]*\#[[:space:]]*define[[:space:]]\+CONFIG_DAHDI_BRI_DCHANS\>' $(src)/../dahdi_config.h)
@@ -80,7 +80,8 @@ $(obj)/init_fxo_modes: $(obj)/print_fxo_modes
$(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)
+ $(Q)$(FXO_VERIFY) || (rm -f $@; exit 1)
+ touch $@
$(obj)/init_card_%_$(XPP_PROTOCOL_VERSION).verified: $(src)/init_card_%_$(XPP_PROTOCOL_VERSION)
@echo ' VERIFY $<'
diff --git a/drivers/dahdi/xpp/astribank_hook.sample b/drivers/dahdi/xpp/astribank_hook.sample
new file mode 100755
index 0000000..7cd0497
--- /dev/null
+++ b/drivers/dahdi/xpp/astribank_hook.sample
@@ -0,0 +1,26 @@
+#! /bin/sh
+
+me=`basename $0`
+LOGGER="logger -i -t '$me'"
+
+set -e
+
+echo "starting($ACTION): '$*'" | $LOGGER
+
+case "$ACTION" in
+add)
+ ;;
+remove)
+ ;;
+online)
+ ;;
+offline)
+ ;;
+*)
+ echo "$0: Unknown ACTION='$ACTION'" | $LOGGER
+ echo "$0: ARGS='$*'" | $LOGGER
+ echo "$0: ENV:" | $LOGGER
+ env | $LOGGER
+ exit 1
+esac
+
diff --git a/drivers/dahdi/xpp/card_bri.c b/drivers/dahdi/xpp/card_bri.c
index 1adbf7c..cf0fdfa 100644
--- a/drivers/dahdi/xpp/card_bri.c
+++ b/drivers/dahdi/xpp/card_bri.c
@@ -616,13 +616,11 @@ static xpd_t *BRI_card_new(xbus_t *xbus, int unit, int subunit, const xproto_tab
int channels = min(3, CHANNELS_PERXPD);
XBUS_DBG(GENERAL, xbus, "\n");
- xpd = xpd_alloc(sizeof(struct BRI_priv_data), proto_table, channels);
+ xpd = xpd_alloc(xbus, unit, subunit, subtype, subunits, sizeof(struct BRI_priv_data), proto_table, channels);
if(!xpd)
return NULL;
xpd->direction = (to_phone) ? TO_PHONE : TO_PSTN;
xpd->type_name = (to_phone) ? "BRI_NT" : "BRI_TE";
- if(xpd_common_init(xbus, xpd, unit, subunit, subtype, subunits) < 0)
- goto err;
if(bri_proc_create(xbus, xpd) < 0)
goto err;
return xpd;
@@ -924,7 +922,7 @@ static int BRI_card_tick(xbus_t *xbus, xpd_t *xpd)
static int BRI_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg)
{
BUG_ON(!xpd);
- if(!TRANSPORT_RUNNING(xpd->xbus))
+ if(!XBUS_IS(xpd->xbus, READY))
return -ENODEV;
switch (cmd) {
case DAHDI_TONEDETECT:
@@ -1021,7 +1019,7 @@ static int bri_startup(struct dahdi_span *span)
BUG_ON(!xpd);
priv = xpd->priv;
BUG_ON(!priv);
- if(!TRANSPORT_RUNNING(xpd->xbus)) {
+ if(!XBUS_IS(xpd->xbus, READY)) {
XPD_DBG(GENERAL, xpd, "Startup called by dahdi. No Hardware. Ignored\n");
return -ENODEV;
}
@@ -1054,7 +1052,7 @@ static int bri_shutdown(struct dahdi_span *span)
BUG_ON(!xpd);
priv = xpd->priv;
BUG_ON(!priv);
- if(!TRANSPORT_RUNNING(xpd->xbus)) {
+ if(!XBUS_IS(xpd->xbus, READY)) {
XPD_DBG(GENERAL, xpd, "Shutdown called by dahdi. No Hardware. Ignored\n");
return -ENODEV;
}
@@ -1479,10 +1477,46 @@ static int proc_bri_info_read(char *page, char **start, off_t off, int count, in
return len;
}
+static int bri_xpd_probe(struct device *dev)
+{
+ xpd_t *xpd;
+
+ xpd = dev_to_xpd(dev);
+ /* Is it our device? */
+ if(xpd->type != XPD_TYPE_BRI) {
+ XPD_ERR(xpd, "drop suggestion for %s (%d)\n",
+ dev->bus_id, xpd->type);
+ return -EINVAL;
+ }
+ XPD_DBG(DEVICES, xpd, "SYSFS\n");
+ return 0;
+}
+
+static int bri_xpd_remove(struct device *dev)
+{
+ xpd_t *xpd;
+
+ xpd = dev_to_xpd(dev);
+ XPD_DBG(DEVICES, xpd, "SYSFS\n");
+ return 0;
+}
+
+static struct xpd_driver bri_driver = {
+ .type = XPD_TYPE_BRI,
+ .driver = {
+ .name = "bri",
+ .owner = THIS_MODULE,
+ .probe = bri_xpd_probe,
+ .remove = bri_xpd_remove
+ }
+};
+
static int __init card_bri_startup(void)
{
- DBG(GENERAL, "\n");
+ int ret;
+ if((ret = xpd_driver_register(&bri_driver.driver)) < 0)
+ return ret;
INFO("revision %s\n", XPP_VERSION);
xproto_register(&PROTO_TABLE(BRI));
return 0;
@@ -1492,6 +1526,7 @@ static void __exit card_bri_cleanup(void)
{
DBG(GENERAL, "\n");
xproto_unregister(&PROTO_TABLE(BRI));
+ xpd_driver_unregister(&bri_driver.driver);
}
MODULE_DESCRIPTION("XPP BRI Card Driver");
diff --git a/drivers/dahdi/xpp/card_fxo.c b/drivers/dahdi/xpp/card_fxo.c
index 59766b1..7bbf9b4 100644
--- a/drivers/dahdi/xpp/card_fxo.c
+++ b/drivers/dahdi/xpp/card_fxo.c
@@ -437,13 +437,11 @@ static xpd_t *FXO_card_new(xbus_t *xbus, int unit, int subunit, const xproto_tab
channels = min(2, CHANNELS_PERXPD);
else
channels = min(8, CHANNELS_PERXPD);
- xpd = xpd_alloc(sizeof(struct FXO_priv_data), proto_table, channels);
+ xpd = xpd_alloc(xbus, unit, subunit, subtype, subunits, sizeof(struct FXO_priv_data), proto_table, channels);
if(!xpd)
return NULL;
xpd->direction = TO_PSTN;
xpd->type_name = "FXO";
- if(xpd_common_init(xbus, xpd, unit, subunit, subtype, subunits) < 0)
- goto err;
if(fxo_proc_create(xbus, xpd) < 0)
goto err;
return xpd;
@@ -790,7 +788,7 @@ static int FXO_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
unsigned char echotune_data[ARRAY_SIZE(echotune_regs)];
BUG_ON(!xpd);
- if(!TRANSPORT_RUNNING(xpd->xbus))
+ if(!XBUS_IS(xpd->xbus, READY))
return -ENODEV;
switch (cmd) {
case WCTDM_SET_ECHOTUNE:
@@ -1315,12 +1313,50 @@ static int proc_xpd_metering_read(char *page, char **start, off_t off, int count
}
#endif
+static int fxo_xpd_probe(struct device *dev)
+{
+ xpd_t *xpd;
+
+ xpd = dev_to_xpd(dev);
+ /* Is it our device? */
+ if(xpd->type != XPD_TYPE_FXO) {
+ XPD_ERR(xpd, "drop suggestion for %s (%d)\n",
+ dev->bus_id, xpd->type);
+ return -EINVAL;
+ }
+ XPD_DBG(DEVICES, xpd, "SYSFS\n");
+ return 0;
+}
+
+static int fxo_xpd_remove(struct device *dev)
+{
+ xpd_t *xpd;
+
+ xpd = dev_to_xpd(dev);
+ XPD_DBG(DEVICES, xpd, "SYSFS\n");
+ return 0;
+}
+
+static struct xpd_driver fxo_driver = {
+ .type = XPD_TYPE_FXO,
+ .driver = {
+ .name = "fxo",
+ .owner = THIS_MODULE,
+ .probe = fxo_xpd_probe,
+ .remove = fxo_xpd_remove
+ }
+};
+
static int __init card_fxo_startup(void)
{
+ int ret;
+
if(ring_debounce <= 0) {
ERR("ring_debounce=%d. Must be positive number of ticks\n", ring_debounce);
return -EINVAL;
}
+ if((ret = xpd_driver_register(&fxo_driver.driver)) < 0)
+ return ret;
INFO("revision %s\n", XPP_VERSION);
#ifdef WITH_METERING
INFO("FEATURE: WITH METERING Detection\n");
@@ -1334,6 +1370,7 @@ static int __init card_fxo_startup(void)
static void __exit card_fxo_cleanup(void)
{
xproto_unregister(&PROTO_TABLE(FXO));
+ xpd_driver_unregister(&fxo_driver.driver);
}
MODULE_DESCRIPTION("XPP FXO Card Driver");
diff --git a/drivers/dahdi/xpp/card_fxs.c b/drivers/dahdi/xpp/card_fxs.c
index cdb184b..67fbd61 100644
--- a/drivers/dahdi/xpp/card_fxs.c
+++ b/drivers/dahdi/xpp/card_fxs.c
@@ -382,7 +382,7 @@ static xpd_t *FXS_card_new(xbus_t *xbus, int unit, int subunit, const xproto_tab
channels = regular_channels;
if(unit == 0)
channels += 6; /* 2 DIGITAL OUTPUTS, 4 DIGITAL INPUTS */
- xpd = xpd_alloc(sizeof(struct FXS_priv_data), proto_table, channels);
+ xpd = xpd_alloc(xbus, unit, subunit, subtype, subunits, sizeof(struct FXS_priv_data), proto_table, channels);
if(!xpd)
return NULL;
if(unit == 0) {
@@ -392,8 +392,6 @@ static xpd_t *FXS_card_new(xbus_t *xbus, int unit, int subunit, const xproto_tab
}
xpd->direction = TO_PHONE;
xpd->type_name = "FXS";
- if(xpd_common_init(xbus, xpd, unit, subunit, subtype, subunits) < 0)
- goto err;
if(fxs_proc_create(xbus, xpd) < 0)
goto err;
priv = xpd->priv;
@@ -765,7 +763,7 @@ static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
BUG_ON(!priv);
xbus = xpd->xbus;
BUG_ON(!xbus);
- if(!TRANSPORT_RUNNING(xbus))
+ if(!XBUS_IS(xbus, READY))
return -ENODEV;
if (pos < 0 || pos >= xpd->channels) {
XPD_NOTICE(xpd, "Bad channel number %d in %s(), cmd=%u\n",
@@ -1466,8 +1464,47 @@ static int proc_xpd_metering_write(struct file *file, const char __user *buffer,
}
#endif
+static int fxs_xpd_probe(struct device *dev)
+{
+ xpd_t *xpd;
+
+ xpd = dev_to_xpd(dev);
+ /* Is it our device? */
+ if(xpd->type != XPD_TYPE_FXS) {
+ XPD_ERR(xpd, "drop suggestion for %s (%d)\n",
+ dev->bus_id, xpd->type);
+ return -EINVAL;
+ }
+ XPD_DBG(DEVICES, xpd, "SYSFS\n");
+ return 0;
+}
+
+static int fxs_xpd_remove(struct device *dev)
+{
+ xpd_t *xpd;
+
+ xpd = dev_to_xpd(dev);
+ XPD_DBG(DEVICES, xpd, "SYSFS\n");
+ return 0;
+}
+
+static struct xpd_driver fxs_driver = {
+ .type = XPD_TYPE_FXS,
+ .driver = {
+ .name = "fxs",
+ .owner = THIS_MODULE,
+ .probe = fxs_xpd_probe,
+ .remove = fxs_xpd_remove
+ }
+};
+
static int __init card_fxs_startup(void)
{
+ int ret;
+
+ if((ret = xpd_driver_register(&fxs_driver.driver)) < 0)
+ return ret;
+
INFO("revision %s\n", XPP_VERSION);
#ifdef POLL_DIGITAL_INPUTS
INFO("FEATURE: with DIGITAL INPUTS support (polled every %d msec)\n",
@@ -1492,6 +1529,7 @@ static int __init card_fxs_startup(void)
static void __exit card_fxs_cleanup(void)
{
xproto_unregister(&PROTO_TABLE(FXS));
+ xpd_driver_unregister(&fxs_driver.driver);
}
MODULE_DESCRIPTION("XPP FXS Card Driver");
diff --git a/drivers/dahdi/xpp/card_global.c b/drivers/dahdi/xpp/card_global.c
index d912257..a8264e4 100644
--- a/drivers/dahdi/xpp/card_global.c
+++ b/drivers/dahdi/xpp/card_global.c
@@ -40,6 +40,7 @@ extern int debug;
/*---------------- GLOBAL PROC handling -----------------------------------*/
+#ifdef OLD_PROC
static int proc_xpd_register_read(char *page, char **start, off_t off, int count, int *eof, void *data)
{
int len = 0;
@@ -51,6 +52,8 @@ static int proc_xpd_register_read(char *page, char **start, off_t off, int count
if(!xpd)
return -ENODEV;
+ XPD_NOTICE(xpd, "%s: DEPRECATED: %s[%d] read from /proc interface instead of /sys\n",
+ __FUNCTION__, current->comm, current->tgid);
spin_lock_irqsave(&xpd->lock, flags);
info = &xpd->last_reply;
len += sprintf(page + len, "# Writing bad data into this file may damage your hardware!\n");
@@ -88,6 +91,7 @@ static int proc_xpd_register_read(char *page, char **start, off_t off, int count
len = 0;
return len;
}
+#endif
static int parse_hexbyte(const char *buf)
{
@@ -289,7 +293,7 @@ out:
return ret;
}
-static int parse_chip_command(xpd_t *xpd, char *cmdline)
+int parse_chip_command(xpd_t *xpd, char *cmdline)
{
xbus_t *xbus;
int ret = -EBADR;
@@ -303,8 +307,9 @@ static int parse_chip_command(xpd_t *xpd, char *cmdline)
BUG_ON(!xpd);
xbus = xpd->xbus;
- if(!XBUS_GET(xbus)) {
- XBUS_DBG(GENERAL, xbus, "Dropped packet. Is shutting down.\n");
+ if(XBUS_IS(xbus, DISCONNECTED)) {
+ XBUS_DBG(GENERAL, xbus, "Dropped packet. In state %s.\n",
+ xbus_statename(XBUS_STATE(xbus)));
return -EBUSY;
}
strlcpy(buf, cmdline, MAX_PROC_WRITE); /* Save a copy */
@@ -335,11 +340,10 @@ static int parse_chip_command(xpd_t *xpd, char *cmdline)
else
ret = 0; /* empty command - no op */
out:
- XBUS_PUT(xbus);
return ret;
}
-
+#ifdef OLD_PROC
static int proc_xpd_register_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
{
xpd_t *xpd = data;
@@ -350,6 +354,8 @@ static int proc_xpd_register_write(struct file *file, const char __user *buffer,
if(!xpd)
return -ENODEV;
+ XPD_NOTICE(xpd, "%s: DEPRECATED: %s[%d] wrote to /proc interface instead of /sys\n",
+ __FUNCTION__, current->comm, current->tgid);
for(i = 0; i < count; /* noop */) {
for(p = buf; p < buf + MAX_PROC_WRITE; p++) { /* read a line */
if(i >= count)
@@ -405,6 +411,7 @@ err:
chip_proc_remove(xbus, xpd);
return -EINVAL;
}
+#endif
/*---------------- GLOBAL Protocol Commands -------------------------------*/
@@ -415,7 +422,7 @@ static void global_packet_dump(const char *msg, xpacket_t *pack);
/* 0x07 */ HOSTCMD(GLOBAL, AB_REQUEST)
{
- int ret = 0;
+ int ret = -ENODEV;
xframe_t *xframe;
xpacket_t *pack;
@@ -427,7 +434,8 @@ static void global_packet_dump(const char *msg, xpacket_t *pack);
RPACKET_FIELD(pack, GLOBAL, AB_REQUEST, rev) = XPP_PROTOCOL_VERSION;
RPACKET_FIELD(pack, GLOBAL, AB_REQUEST, reserved) = 0;
XBUS_DBG(DEVICES, xbus, "Protocol Version %d\n", XPP_PROTOCOL_VERSION);
- ret = send_cmd_frame(xbus, xframe);
+ if(xbus_setstate(xbus, XBUS_STATE_SENT_REQUEST))
+ ret = send_cmd_frame(xbus, xframe);
return ret;
}
@@ -590,6 +598,10 @@ HANDLER_DEF(GLOBAL, AB_DESCRIPTION) /* 0x08 */
ret = -EPROTO;
goto proto_err;
}
+ if(!xbus_setstate(xbus, XBUS_STATE_RECVD_DESC)) {
+ ret = -EPROTO;
+ goto proto_err;
+ }
XBUS_INFO(xbus, "DESCRIPTOR: %d cards, protocol revision %d\n", count_units, rev);
xbus->revision = rev;
if(!worker) {
@@ -631,19 +643,8 @@ HANDLER_DEF(GLOBAL, AB_DESCRIPTION) /* 0x08 */
list_add_tail(&card_desc->card_list, &worker->card_list);
spin_unlock_irqrestore(&worker->worker_lock, flags);
}
- /* Initialize the work. (adapt to kernel API changes). */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
- INIT_WORK(&worker->xpds_init_work, xbus_populate);
-#else
- INIT_WORK(&worker->xpds_init_work, xbus_populate, worker);
-#endif
- xbus = get_xbus(xbus->num); /* released in xbus_populate() */
- BUG_ON(!xbus);
- /* Now send it */
- if(!queue_work(worker->wq, &worker->xpds_init_work)) {
- XBUS_ERR(xbus, "Failed to queue xpd initialization work\n");
+ if(!xbus_process_worker(xbus))
return -ENODEV;
- }
return 0;
proto_err:
dump_packet("AB_DESCRIPTION", pack, DBG_ANY);
@@ -762,12 +763,14 @@ int run_initialize_registers(xpd_t *xpd)
int ret;
xbus_t *xbus;
char busstr[MAX_ENV_STR];
+ char busnumstr[MAX_ENV_STR];
char unitstr[MAX_ENV_STR];
char subunitsstr[MAX_ENV_STR];
char typestr[MAX_ENV_STR];
char directionstr[MAX_ENV_STR];
char revstr[MAX_ENV_STR];
char connectorstr[MAX_ENV_STR];
+ char xbuslabel[MAX_ENV_STR];
char init_card[MAX_PATH_STR];
byte direction_mask;
int i;
@@ -777,12 +780,14 @@ int run_initialize_registers(xpd_t *xpd)
};
char *envp[] = {
busstr,
+ busnumstr,
unitstr,
subunitsstr,
typestr,
directionstr,
revstr,
connectorstr,
+ xbuslabel,
NULL
};
@@ -792,6 +797,10 @@ int run_initialize_registers(xpd_t *xpd)
XPD_NOTICE(xpd, "Missing initdir parameter\n");
return -EINVAL;
}
+ if(!xpd_setstate(xpd, XPD_STATE_INIT_REGS)) {
+ ret = -EINVAL;
+ goto err;
+ }
direction_mask = 0;
for(i = 0; i < xpd->subunits; i++) {
xpd_t *su = xpd_byaddr(xbus, xpd->addr.unit, i);
@@ -805,21 +814,25 @@ int run_initialize_registers(xpd_t *xpd)
direction_mask |= (su->direction == TO_PHONE) ? BIT(i) : 0;
}
snprintf(busstr, MAX_ENV_STR, "XBUS_NAME=%s", xbus->busname);
+ snprintf(busnumstr, MAX_ENV_STR, "XBUS_NUMBER=%d", xbus->num);
snprintf(unitstr, MAX_ENV_STR, "UNIT_NUMBER=%d", xpd->addr.unit);
snprintf(typestr, MAX_ENV_STR, "UNIT_TYPE=%d", xpd->type);
snprintf(subunitsstr, MAX_ENV_STR, "UNIT_SUBUNITS=%d", xpd->subunits);
snprintf(directionstr, MAX_ENV_STR, "UNIT_SUBUNITS_DIR=%d", direction_mask);
snprintf(revstr, MAX_ENV_STR, "XBUS_REVISION=%d", xbus->revision);
- snprintf(connectorstr, MAX_ENV_STR, "XBUS_CONNECTOR=%s", xbus->location);
- snprintf(connectorstr, MAX_ENV_STR, "XBUS_LABEL=%s", xbus->label);
+ snprintf(connectorstr, MAX_ENV_STR, "XBUS_CONNECTOR=%s", xbus->connector);
+ snprintf(xbuslabel, MAX_ENV_STR, "XBUS_LABEL=%s", xbus->label);
if(snprintf(init_card, MAX_PATH_STR, "%s/init_card_%d_%d",
initdir, xpd->type, xbus->revision) > MAX_PATH_STR) {
XPD_NOTICE(xpd, "Cannot initialize. pathname is longer than %d characters.\n", MAX_PATH_STR);
- return -E2BIG;
+ ret = -E2BIG;
+ goto err;
}
- if(!XBUS_GET(xbus)) {
- XBUS_ERR(xbus, "Skipped register initialization. XBUS is going down\n");
- return -ENODEV;
+ if(!XBUS_IS(xbus, RECVD_DESC)) {
+ XBUS_ERR(xbus, "Skipped register initialization. In state %s.\n",
+ xbus_statename(XBUS_STATE(xbus)));
+ ret = -ENODEV;
+ goto err;
}
XPD_DBG(DEVICES, xpd, "running '%s' for type=%d revision=%d\n",
init_card, xpd->type, xbus->revision);
@@ -842,7 +855,7 @@ int run_initialize_registers(xpd_t *xpd)
}
ret = -EINVAL;
}
- XBUS_PUT(xbus);
+err:
return ret;
}
diff --git a/drivers/dahdi/xpp/card_global.h b/drivers/dahdi/xpp/card_global.h
index c71f74d..c6a9a9b 100644
--- a/drivers/dahdi/xpp/card_global.h
+++ b/drivers/dahdi/xpp/card_global.h
@@ -99,8 +99,10 @@ DEF_RPACKET_DATA(GLOBAL, ERROR_CODE,
/* 0x19 */ DECLARE_CMD(GLOBAL, SYNC_SOURCE, enum sync_mode mode, int drift);
/* 0x23 */ DECLARE_CMD(GLOBAL, RESET_SYNC_COUNTERS);
+#ifdef OLD_PROC
void chip_proc_remove(xbus_t *xbus, xpd_t *xpd);
int chip_proc_create(xbus_t *xbus, xpd_t *xpd);
+#endif
int xpp_register_request(xbus_t *xbus, xpd_t *xpd, xportno_t portno,
bool writing, byte regnum, bool do_subreg, byte subreg,
byte data_low, bool do_datah, byte data_high, bool should_reply);
@@ -108,6 +110,7 @@ int send_multibyte_request(xbus_t *xbus, unsigned unit, xportno_t portno,
bool eoftx, byte *buf, unsigned len);
extern xproto_table_t PROTO_TABLE(GLOBAL);
int run_initialize_registers(xpd_t *xpd);
+int parse_chip_command(xpd_t *xpd, char *cmdline);
extern charp initdir;
#endif /* CARD_GLOBAL_H */
diff --git a/drivers/dahdi/xpp/card_pri.c b/drivers/dahdi/xpp/card_pri.c
index 990fc0b..a215b5c 100644
--- a/drivers/dahdi/xpp/card_pri.c
+++ b/drivers/dahdi/xpp/card_pri.c
@@ -62,15 +62,19 @@ static DEF_PARM(uint, poll_interval, 500, 0644, "Poll channel state interval in
static bool pri_packet_is_valid(xpacket_t *pack);
static void pri_packet_dump(const char *msg, xpacket_t *pack);
+#ifdef OLD_PROC
static int proc_pri_info_read(char *page, char **start, off_t off, int count, int *eof, void *data);
static int proc_pri_info_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
+#endif
static int pri_startup(struct dahdi_span *span);
static int pri_shutdown(struct dahdi_span *span);
static int pri_rbsbits(struct dahdi_chan *chan, int bits);
static int pri_lineconfig(xpd_t *xpd, int lineconfig);
#define PROC_REGISTER_FNAME "slics"
+#ifdef OLD_PROC
#define PROC_PRI_INFO_FNAME "pri_info"
+#endif
enum pri_protocol {
PRI_PROTO_0 = 0,
@@ -104,7 +108,7 @@ static int pri_num_channels(enum pri_protocol pri_protocol)
static const char *type_name(enum pri_protocol pri_protocol)
{
static const char *names[4] = {
- [PRI_PROTO_0] = "Unknown",
+ [PRI_PROTO_0] = "PRI-Unknown",
[PRI_PROTO_E1] = "E1",
[PRI_PROTO_T1] = "T1",
[PRI_PROTO_J1] = "J1"
@@ -276,7 +280,9 @@ struct pri_leds {
struct PRI_priv_data {
bool clock_source;
+#ifdef OLD_PROC
struct proc_dir_entry *pri_info;
+#endif
enum pri_protocol pri_protocol;
int deflaw;
unsigned int dchan_num;
@@ -373,6 +379,7 @@ static int pri_write_reg(xpd_t *xpd, int regnum, byte val)
);
}
+#ifdef OLD_PROC
static void pri_proc_remove(xbus_t *xbus, xpd_t *xpd)
{
struct PRI_priv_data *priv;
@@ -387,7 +394,9 @@ static void pri_proc_remove(xbus_t *xbus, xpd_t *xpd)
}
#endif
}
+#endif
+#ifdef OLD_PROC
static int pri_proc_create(xbus_t *xbus, xpd_t *xpd)
{
struct PRI_priv_data *priv;
@@ -412,6 +421,7 @@ err:
pri_proc_remove(xbus, xpd);
return -EINVAL;
}
+#endif
static bool valid_pri_modes(const xpd_t *xpd)
{
@@ -570,7 +580,7 @@ static void set_clocking(xpd_t *xpd)
int best_subunit_prio = 0;
int i;
- xbus = get_xbus(xpd->xbus->num);
+ xbus = xpd->xbus;
/* Find subunit with best timing priority */
for(i = 0; i < MAX_SLAVES; i++) {
struct PRI_priv_data *priv;
@@ -612,7 +622,6 @@ static void set_clocking(xpd_t *xpd)
}
}
dahdi_update_syncsrc(xpd);
- put_xbus(xbus);
}
static void set_reg_lim0(const char *msg, xpd_t *xpd)
@@ -890,21 +899,20 @@ static xpd_t *PRI_card_new(xbus_t *xbus, int unit, int subunit, const xproto_tab
int channels = min(31, CHANNELS_PERXPD); /* worst case */
XBUS_DBG(GENERAL, xbus, "\n");
- xpd = xpd_alloc(sizeof(struct PRI_priv_data), proto_table, channels);
+ xpd = xpd_alloc(xbus, unit, subunit, subtype, subunits, sizeof(struct PRI_priv_data), proto_table, channels);
if(!xpd)
return NULL;
priv = xpd->priv;
priv->pri_protocol = PRI_PROTO_0; /* Default, changes in set_pri_proto() */
priv->deflaw = DAHDI_LAW_DEFAULT; /* Default, changes in set_pri_proto() */
xpd->type_name = type_name(priv->pri_protocol);
- if(xpd_common_init(xbus, xpd, unit, subunit, subtype, subunits) < 0)
- goto err;
- if(pri_proc_create(xbus, xpd) < 0)
- goto err;
+#ifdef OLD_PROC
+ if(pri_proc_create(xbus, xpd) < 0) {
+ xpd_free(xpd);
+ return NULL;
+ }
+#endif
return xpd;
-err:
- xpd_free(xpd);
- return NULL;
}
static int PRI_card_init(xbus_t *xbus, xpd_t *xpd)
@@ -948,7 +956,9 @@ static int PRI_card_init(xbus_t *xbus, xpd_t *xpd)
priv->initialized = 1;
return 0;
err:
+#ifdef OLD_PROC
pri_proc_remove(xbus, xpd);
+#endif
XPD_ERR(xpd, "Failed initializing registers (%d)\n", ret);
return ret;
}
@@ -960,7 +970,9 @@ static int PRI_card_remove(xbus_t *xbus, xpd_t *xpd)
BUG_ON(!xpd);
priv = xpd->priv;
XPD_DBG(GENERAL, xpd, "\n");
+#ifdef OLD_PROC
pri_proc_remove(xbus, xpd);
+#endif
return 0;
}
@@ -1164,7 +1176,7 @@ static int PRI_card_tick(xbus_t *xbus, xpd_t *xpd)
static int PRI_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg)
{
BUG_ON(!xpd);
- if(!TRANSPORT_RUNNING(xpd->xbus))
+ if(!XBUS_IS(xpd->xbus, READY))
return -ENODEV;
switch (cmd) {
case DAHDI_TONEDETECT:
@@ -1199,7 +1211,7 @@ static int pri_startup(struct dahdi_span *span)
BUG_ON(!xpd);
priv = xpd->priv;
BUG_ON(!priv);
- if(!TRANSPORT_RUNNING(xpd->xbus)) {
+ if(!XBUS_IS(xpd->xbus, READY)) {
XPD_DBG(GENERAL, xpd, "Startup called by dahdi. No Hardware. Ignored\n");
return -ENODEV;
}
@@ -1220,7 +1232,7 @@ static int pri_shutdown(struct dahdi_span *span)
BUG_ON(!xpd);
priv = xpd->priv;
BUG_ON(!priv);
- if(!TRANSPORT_RUNNING(xpd->xbus)) {
+ if(!XBUS_IS(xpd->xbus, READY)) {
XPD_DBG(GENERAL, xpd, "Shutdown called by dahdi. No Hardware. Ignored\n");
return -ENODEV;
}
@@ -1631,6 +1643,7 @@ static void pri_packet_dump(const char *msg, xpacket_t *pack)
DBG(GENERAL, "%s\n", msg);
}
/*------------------------- REGISTER Handling --------------------------*/
+#ifdef OLD_PROC
static int proc_pri_info_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
{
xpd_t *xpd = data;
@@ -1647,6 +1660,8 @@ static int proc_pri_info_write(struct file *file, const char __user *buffer, uns
if(!xpd)
return -ENODEV;
+ XPD_NOTICE(xpd, "%s: DEPRECATED: %s[%d] write to /proc interface instead of /sys\n",
+ __FUNCTION__, current->comm, current->tgid);
priv = xpd->priv;
if(count >= MAX_PROC_WRITE) { /* leave room for null */
XPD_ERR(xpd, "write too long (%ld)\n", count);
@@ -1711,6 +1726,8 @@ static int proc_pri_info_read(char *page, char **start, off_t off, int count, in
DBG(PROC, "\n");
if(!xpd)
return -ENODEV;
+ XPD_NOTICE(xpd, "%s: DEPRECATED: %s[%d] read from /proc interface instead of /sys\n",
+ __FUNCTION__, current->comm, current->tgid);
spin_lock_irqsave(&xpd->lock, flags);
priv = xpd->priv;
BUG_ON(!priv);
@@ -1773,11 +1790,366 @@ static int proc_pri_info_read(char *page, char **start, off_t off, int count, in
len = 0;
return len;
}
+#endif
+
+/*------------------------- sysfs stuff --------------------------------*/
+static DEVICE_ATTR_READER(pri_protocol_show, dev, buf)
+{
+ xpd_t *xpd;
+ struct PRI_priv_data *priv;
+ unsigned long flags;
+ int len = 0;
+
+ BUG_ON(!dev);
+ xpd = dev_to_xpd(dev);
+ if(!xpd)
+ return -ENODEV;
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ spin_lock_irqsave(&xpd->lock, flags);
+ len += sprintf(buf, "%s\n", pri_protocol_name(priv->pri_protocol));
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ return len;
+}
+
+static DEVICE_ATTR_WRITER(pri_protocol_store, dev, buf, count)
+{
+ xpd_t *xpd;
+ enum pri_protocol new_protocol = PRI_PROTO_0;
+ int i;
+ int ret;
+
+ BUG_ON(!dev);
+ xpd = dev_to_xpd(dev);
+ XPD_DBG(GENERAL, xpd, "%s\n", buf);
+ if(!xpd)
+ return -ENODEV;
+ if((i = strcspn(buf, " \r\n")) != 2) {
+ XPD_NOTICE(xpd,
+ "Protocol name '%s' has %d characters (should be 2). Ignored.\n",
+ buf, i);
+ return -EINVAL;
+ }
+ if(strnicmp(buf, "E1", 2) == 0)
+ new_protocol = PRI_PROTO_E1;
+ else if(strnicmp(buf, "T1", 2) == 0)
+ new_protocol = PRI_PROTO_T1;
+ else if(strnicmp(buf, "J1", 2) == 0)
+ new_protocol = PRI_PROTO_J1;
+ else {
+ XPD_NOTICE(xpd,
+ "Unknown PRI protocol '%s' (should be E1|T1|J1). Ignored.\n",
+ buf);
+ return -EINVAL;
+ }
+ ret = set_pri_proto(xpd, new_protocol);
+ return (ret < 0) ? ret : count;
+}
+
+static DEVICE_ATTR(pri_protocol, S_IRUGO | S_IWUSR, pri_protocol_show, pri_protocol_store);
+
+static DEVICE_ATTR_READER(pri_localloop_show, dev, buf)
+{
+ xpd_t *xpd;
+ struct PRI_priv_data *priv;
+ unsigned long flags;
+ int len = 0;
+
+ BUG_ON(!dev);
+ xpd = dev_to_xpd(dev);
+ if(!xpd)
+ return -ENODEV;
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ spin_lock_irqsave(&xpd->lock, flags);
+ len += sprintf(buf, "%c\n",
+ (priv->local_loopback) ? 'Y' : 'N');
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ return len;
+}
+
+static DEVICE_ATTR_WRITER(pri_localloop_store, dev, buf, count)
+{
+ xpd_t *xpd;
+ bool ll = 0;
+ int i;
+ int ret;
+
+ BUG_ON(!dev);
+ xpd = dev_to_xpd(dev);
+ XPD_DBG(GENERAL, xpd, "%s\n", buf);
+ if(!xpd)
+ return -ENODEV;
+ if((i = strcspn(buf, " \r\n")) != 1) {
+ XPD_NOTICE(xpd,
+ "Value '%s' has %d characters (should be 1). Ignored.\n",
+ buf, i);
+ return -EINVAL;
+ }
+ if(strchr("1Yy", buf[0]) != NULL)
+ ll = 1;
+ else if(strchr("0Nn", buf[0]) != NULL)
+ ll = 0;
+ else {
+ XPD_NOTICE(xpd,
+ "Unknown value '%s' (should be [1Yy]|[0Nn]). Ignored.\n",
+ buf);
+ return -EINVAL;
+ }
+ ret = set_localloop(xpd, ll);
+ return (ret < 0) ? ret : count;
+}
+
+static DEVICE_ATTR(pri_localloop, S_IRUGO | S_IWUSR, pri_localloop_show, pri_localloop_store);
+
+static DEVICE_ATTR_READER(pri_layer1_show, dev, buf)
+{
+ xpd_t *xpd;
+ struct PRI_priv_data *priv;
+ unsigned long flags;
+ int len = 0;
+
+ BUG_ON(!dev);
+ xpd = dev_to_xpd(dev);
+ if(!xpd)
+ return -ENODEV;
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ spin_lock_irqsave(&xpd->lock, flags);
+ if(priv->poll_noreplies > 1)
+ len += sprintf(buf + len, "Unknown[%d]", priv->poll_noreplies);
+ else
+ len += sprintf(buf + len, "%-10s", ((priv->layer1_up) ? "UP" : "DOWN"));
+ len += sprintf(buf + len, "%d\n", priv->layer1_replies);
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ return len;
+}
+
+static DEVICE_ATTR(pri_layer1, S_IRUGO, pri_layer1_show, NULL);
+
+static DEVICE_ATTR_READER(pri_alarms_show, dev, buf)
+{
+ xpd_t *xpd;
+ struct PRI_priv_data *priv;
+ unsigned long flags;
+ int len = 0;
+ const static struct {
+ byte bits;
+ const char *name;
+ } alarm_types[] = {
+ { REG_FRS0_LOS, "RED" },
+ { REG_FRS0_AIS, "BLUE" },
+ { REG_FRS0_RRA, "YELLOW" },
+ };
+
+ BUG_ON(!dev);
+ xpd = dev_to_xpd(dev);
+ if(!xpd)
+ return -ENODEV;
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ spin_lock_irqsave(&xpd->lock, flags);
+ if(priv->poll_noreplies > 1)
+ len += sprintf(buf + len, "Unknown[%d]", priv->poll_noreplies);
+ else {
+ int i;
+
+ for(i = 0; i < ARRAY_SIZE(alarm_types); i++) {
+ if(priv->reg_frs0 & alarm_types[i].bits)
+ len += sprintf(buf + len, "%s ", alarm_types[i].name);
+ }
+ }
+ len += sprintf(buf + len, "\n");
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ return len;
+}
+
+static DEVICE_ATTR(pri_alarms, S_IRUGO, pri_alarms_show, NULL);
+
+static DEVICE_ATTR_READER(pri_cas_show, dev, buf)
+{
+ xpd_t *xpd;
+ struct PRI_priv_data *priv;
+ unsigned long flags;
+ int len = 0;
+
+ BUG_ON(!dev);
+ xpd = dev_to_xpd(dev);
+ if(!xpd)
+ return -ENODEV;
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ spin_lock_irqsave(&xpd->lock, flags);
+ if(priv->is_cas) {
+ int i;
+
+ len += sprintf(buf + len,
+ "CAS: replies=%d\n", priv->cas_replies);
+ len += sprintf(buf + len, " CAS-TS: ");
+ for(i = 0; i < NUM_CAS_RS; i++) {
+ len += sprintf(buf + len, " %02X", priv->cas_ts_e[i]);
+ }
+ len += sprintf(buf + len, "\n");
+ len += sprintf(buf + len, " CAS-RS: ");
+ for(i = 0; i < NUM_CAS_RS; i++) {
+ len += sprintf(buf + len, " %02X", priv->cas_rs_e[i]);
+ }
+ len += sprintf(buf + len, "\n");
+ }
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ return len;
+}
+
+static DEVICE_ATTR(pri_cas, S_IRUGO, pri_cas_show, NULL);
+
+static DEVICE_ATTR_READER(pri_dchan_show, dev, buf)
+{
+ xpd_t *xpd;
+ struct PRI_priv_data *priv;
+ unsigned long flags;
+ int len = 0;
+
+ BUG_ON(!dev);
+ xpd = dev_to_xpd(dev);
+ if(!xpd)
+ return -ENODEV;
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ spin_lock_irqsave(&xpd->lock, flags);
+ len += sprintf(buf + len, "D-Channel: TX=[%5d] (0x%02X) RX=[%5d] (0x%02X) ",
+ priv->dchan_tx_counter, priv->dchan_tx_sample,
+ priv->dchan_rx_counter, priv->dchan_rx_sample);
+ if(priv->dchan_alive) {
+ len += sprintf(buf + len, "(alive %d K-ticks)\n",
+ priv->dchan_alive_ticks/1000);
+ } else {
+ len += sprintf(buf + len, "(dead)\n");
+ }
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ return len;
+}
+
+static DEVICE_ATTR(pri_dchan, S_IRUGO, pri_dchan_show, NULL);
+
+static DEVICE_ATTR_READER(pri_clocking_show, dev, buf)
+{
+ xpd_t *xpd;
+ struct PRI_priv_data *priv;
+ unsigned long flags;
+ int len = 0;
+
+ BUG_ON(!dev);
+ xpd = dev_to_xpd(dev);
+ if(!xpd)
+ return -ENODEV;
+ priv = xpd->priv;
+ BUG_ON(!priv);
+ spin_lock_irqsave(&xpd->lock, flags);
+ len += sprintf(buf + len, "%s\n", (priv->clock_source) ? "MASTER" : "SLAVE");
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ return len;
+}
+
+static DEVICE_ATTR(pri_clocking, S_IRUGO, pri_clocking_show, NULL);
+
+
+static int pri_xpd_probe(struct device *dev)
+{
+ xpd_t *xpd;
+ int ret = 0;
+
+ xpd = dev_to_xpd(dev);
+ /* Is it our device? */
+ if(xpd->type != XPD_TYPE_PRI) {
+ XPD_ERR(xpd, "drop suggestion for %s (%d)\n",
+ dev->bus_id, xpd->type);
+ return -EINVAL;
+ }
+ XPD_DBG(DEVICES, xpd, "SYSFS\n");
+ ret = device_create_file(dev, &dev_attr_pri_protocol);
+ if(ret) {
+ XPD_ERR(xpd, "%s: device_create_file(pri_protocol) failed: %d\n", __FUNCTION__, ret);
+ goto fail_pri_protocol;
+ }
+ ret = device_create_file(dev, &dev_attr_pri_localloop);
+ if(ret) {
+ XPD_ERR(xpd, "%s: device_create_file(pri_localloop) failed: %d\n", __FUNCTION__, ret);
+ goto fail_pri_localloop;
+ }
+ ret = device_create_file(dev, &dev_attr_pri_layer1);
+ if(ret) {
+ XPD_ERR(xpd, "%s: device_create_file(pri_layer1) failed: %d\n", __FUNCTION__, ret);
+ goto fail_pri_layer1;
+ }
+ ret = device_create_file(dev, &dev_attr_pri_alarms);
+ if(ret) {
+ XPD_ERR(xpd, "%s: device_create_file(pri_alarms) failed: %d\n", __FUNCTION__, ret);
+ goto fail_pri_alarms;
+ }
+ ret = device_create_file(dev, &dev_attr_pri_cas);
+ if(ret) {
+ XPD_ERR(xpd, "%s: device_create_file(pri_cas) failed: %d\n", __FUNCTION__, ret);
+ goto fail_pri_cas;
+ }
+ ret = device_create_file(dev, &dev_attr_pri_dchan);
+ if(ret) {
+ XPD_ERR(xpd, "%s: device_create_file(pri_dchan) failed: %d\n", __FUNCTION__, ret);
+ goto fail_pri_dchan;
+ }
+ ret = device_create_file(dev, &dev_attr_pri_clocking);
+ if(ret) {
+ XPD_ERR(xpd, "%s: device_create_file(pri_clocking) failed: %d\n", __FUNCTION__, ret);
+ goto fail_pri_clocking;
+ }
+ return 0;
+fail_pri_clocking:
+ device_remove_file(dev, &dev_attr_pri_dchan);
+fail_pri_dchan:
+ device_remove_file(dev, &dev_attr_pri_cas);
+fail_pri_cas:
+ device_remove_file(dev, &dev_attr_pri_alarms);
+fail_pri_alarms:
+ device_remove_file(dev, &dev_attr_pri_layer1);
+fail_pri_layer1:
+ device_remove_file(dev, &dev_attr_pri_localloop);
+fail_pri_localloop:
+ device_remove_file(dev, &dev_attr_pri_protocol);
+fail_pri_protocol:
+ return ret;
+}
+
+static int pri_xpd_remove(struct device *dev)
+{
+ xpd_t *xpd;
+
+ xpd = dev_to_xpd(dev);
+ XPD_DBG(DEVICES, xpd, "SYSFS\n");
+ device_remove_file(dev, &dev_attr_pri_clocking);
+ device_remove_file(dev, &dev_attr_pri_dchan);
+ device_remove_file(dev, &dev_attr_pri_cas);
+ device_remove_file(dev, &dev_attr_pri_alarms);
+ device_remove_file(dev, &dev_attr_pri_layer1);
+ device_remove_file(dev, &dev_attr_pri_localloop);
+ device_remove_file(dev, &dev_attr_pri_protocol);
+ return 0;
+}
+
+static struct xpd_driver pri_driver = {
+ .type = XPD_TYPE_PRI,
+ .driver = {
+ .name = "pri",
+ .owner = THIS_MODULE,
+ .probe = pri_xpd_probe,
+ .remove = pri_xpd_remove
+ }
+};
static int __init card_pri_startup(void)
{
- DBG(GENERAL, "\n");
+ int ret;
+ if((ret = xpd_driver_register(&pri_driver.driver)) < 0)
+ return ret;
INFO("revision %s\n", XPP_VERSION);
xproto_register(&PROTO_TABLE(PRI));
return 0;
@@ -1787,6 +2159,7 @@ static void __exit card_pri_cleanup(void)
{
DBG(GENERAL, "\n");
xproto_unregister(&PROTO_TABLE(PRI));
+ xpd_driver_unregister(&pri_driver.driver);
}
MODULE_DESCRIPTION("XPP PRI Card Driver");
diff --git a/drivers/dahdi/xpp/init_card_1_30 b/drivers/dahdi/xpp/init_card_1_30
index e1bbc1f..927b0e7 100755
--- a/drivers/dahdi/xpp/init_card_1_30
+++ b/drivers/dahdi/xpp/init_card_1_30
@@ -1,6 +1,9 @@
#! /usr/bin/perl -w
use strict;
+# Make warnings fatal
+local $SIG{__WARN__} = sub { die @_ };
+
#
# Written by Oron Peled <oron@actcom.co.il>
# Copyright (C) 2006, Xorcom
@@ -48,16 +51,13 @@ 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';
getopts('o:', \%opts);
my %settings;
$settings{debug} = 0;
$settings{fxs_skip_calib} = 0;
-
-my $xpd_name = sprintf("XPD-%1d0", $ENV{UNIT_NUMBER});
-my $chipregs = "$ENV{XPP_BASE}/$ENV{XBUS_NAME}/$xpd_name/chipregs";
+my $chipregs;
sub logit {
print STDERR "$unit_id: @_\n";
@@ -70,11 +70,34 @@ sub debug {
# Arrange for error logging
if (-t STDERR) {
$unit_id = 'Interactive';
- logit "Interactive startup";
+ main::debug "Interactive startup";
} else {
$unit_id = "$ENV{XBUS_NAME}/UNIT-$ENV{UNIT_NUMBER}";
open (STDERR, "| logger -t $program -p kern.info") || die;
- logit "Non Interactive startup";
+ main::debug "Non Interactive startup";
+ foreach my $k (qw(
+ XBUS_NAME
+ XBUS_NUMBER
+ UNIT_NUMBER
+ UNIT_TYPE
+ UNIT_SUBUNITS
+ UNIT_SUBUNITS_DIR
+ XBUS_REVISION
+ XBUS_CONNECTOR
+ XBUS_LABEL)) {
+ unless(defined $ENV{$k}) {
+ logit "Missing ENV{$k}\n";
+ die;
+ }
+ }
+ $chipregs = sprintf "/sys/bus/xpds/devices/%02d:%1d:0/chipregs",
+ $ENV{XBUS_NUMBER}, $ENV{UNIT_NUMBER};
+ if(! -f $chipregs) {
+ my $xpd_name = sprintf("XPD-%1d0", $ENV{UNIT_NUMBER});
+ $chipregs = "/proc/xpp/$ENV{XBUS_NAME}/$xpd_name/chipregs";
+ logit "OLD DRIVER: does not use /sys chipregs. Falling back to /proc"
+ if -f $chipregs;
+ }
}
sub set_output() {
@@ -88,7 +111,7 @@ sub set_output() {
}
open(REG, ">$output") || die "Failed to open '$output': $!\n";
my $oldfh = select REG;
- print "# Setting output\n" if $opts{o};
+ main::logit "# Setting output" if $opts{o};
return $oldfh;
}
diff --git a/drivers/dahdi/xpp/init_card_2_30 b/drivers/dahdi/xpp/init_card_2_30
index 6a62ec8..c5c785d 100755
--- a/drivers/dahdi/xpp/init_card_2_30
+++ b/drivers/dahdi/xpp/init_card_2_30
@@ -1,6 +1,9 @@
#! /usr/bin/perl -w
use strict;
+# Make warnings fatal
+local $SIG{__WARN__} = sub { die @_ };
+
#
# Written by Oron Peled <oron@actcom.co.il>
# Copyright (C) 2006, Xorcom
@@ -48,14 +51,11 @@ 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';
getopts('o:v:', \%opts);
my %settings;
$settings{debug} = 0;
-
-my $xpd_name;
my $chipregs;
sub logit {
@@ -72,10 +72,31 @@ if (-t STDERR) {
main::debug "Interactive startup";
} else {
$unit_id = "$ENV{XBUS_NAME}/UNIT-$ENV{UNIT_NUMBER}";
- $xpd_name = sprintf("XPD-%1d0", $ENV{UNIT_NUMBER});
- $chipregs = "$ENV{XPP_BASE}/$ENV{XBUS_NAME}/$xpd_name/chipregs";
open (STDERR, "| logger -t $program -p kern.info") || die;
main::debug "Non Interactive startup";
+ foreach my $k (qw(
+ XBUS_NAME
+ XBUS_NUMBER
+ UNIT_NUMBER
+ UNIT_TYPE
+ UNIT_SUBUNITS
+ UNIT_SUBUNITS_DIR
+ XBUS_REVISION
+ XBUS_CONNECTOR
+ XBUS_LABEL)) {
+ unless(defined $ENV{$k}) {
+ logit "Missing ENV{$k}\n";
+ die;
+ }
+ }
+ $chipregs = sprintf "/sys/bus/xpds/devices/%02d:%1d:0/chipregs",
+ $ENV{XBUS_NUMBER}, $ENV{UNIT_NUMBER};
+ if(! -f $chipregs) {
+ my $xpd_name = sprintf("XPD-%1d0", $ENV{UNIT_NUMBER});
+ $chipregs = "/proc/xpp/$ENV{XBUS_NAME}/$xpd_name/chipregs";
+ logit "OLD DRIVER: does not use /sys chipregs. Falling back to /proc"
+ if -f $chipregs;
+ }
}
sub set_output() {
diff --git a/drivers/dahdi/xpp/init_card_3_30 b/drivers/dahdi/xpp/init_card_3_30
index 474b44e..c06e885 100755
--- a/drivers/dahdi/xpp/init_card_3_30
+++ b/drivers/dahdi/xpp/init_card_3_30
@@ -1,6 +1,9 @@
#! /usr/bin/perl -w
use strict;
+# Make warnings fatal
+local $SIG{__WARN__} = sub { die @_ };
+
#
# $Id$
#
@@ -61,7 +64,6 @@ 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';
getopts('o:', \%opts);
@@ -77,6 +79,21 @@ if (-t STDERR) {
$unit_id = "$ENV{XBUS_NAME}/UNIT-$ENV{UNIT_NUMBER}";
open (STDERR, "| logger -t $program -p kern.info") || die;
logit "Non Interactive startup";
+ foreach my $k (qw(
+ XBUS_NAME
+ XBUS_NUMBER
+ UNIT_NUMBER
+ UNIT_TYPE
+ UNIT_SUBUNITS
+ UNIT_SUBUNITS_DIR
+ XBUS_REVISION
+ XBUS_CONNECTOR
+ XBUS_LABEL)) {
+ unless(defined $ENV{$k}) {
+ logit "Missing ENV{$k}\n";
+ die;
+ }
+ }
}
sub select_subunit($) {
@@ -87,8 +104,14 @@ sub select_subunit($) {
if($opts{o}) {
$output = $opts{o};
} else {
- my $xpd_name = sprintf("XPD-%1d%1d", $ENV{UNIT_NUMBER}, $subunit);
- $output = "$ENV{XPP_BASE}/$ENV{XBUS_NAME}/$xpd_name/chipregs";
+ $output = sprintf "/sys/bus/xpds/devices/%02d:%1d:%1d/chipregs",
+ $ENV{XBUS_NUMBER}, $ENV{UNIT_NUMBER}, $subunit;
+ if(! -f $output) {
+ my $xpd_name = sprintf("XPD-%1d%1d", $ENV{UNIT_NUMBER}, $subunit);
+ $output = "/proc/xpp/$ENV{XBUS_NAME}/$xpd_name/chipregs";
+ logit "OLD DRIVER: does not use /sys chipregs. Falling back to /proc"
+ if -f $output;
+ }
}
open(REG, ">$output") || die "Failed to open '$output': $!\n";
my $oldfh = select REG;
diff --git a/drivers/dahdi/xpp/init_card_4_30 b/drivers/dahdi/xpp/init_card_4_30
index e79a0dd..6c76b78 100755
--- a/drivers/dahdi/xpp/init_card_4_30
+++ b/drivers/dahdi/xpp/init_card_4_30
@@ -1,6 +1,9 @@
#! /usr/bin/perl -w
use strict;
+# Make warnings fatal
+local $SIG{__WARN__} = sub { die @_ };
+
#
# $Id$
#
@@ -59,7 +62,6 @@ 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';
getopts('o:', \%opts);
@@ -77,6 +79,21 @@ if (-t STDERR) {
$unit_id = "$ENV{XBUS_NAME}/UNIT-$ENV{UNIT_NUMBER}";
open (STDERR, "| logger -t $program -p kern.info") || die;
logit "Non Interactive startup";
+ foreach my $k (qw(
+ XBUS_NAME
+ XBUS_NUMBER
+ UNIT_NUMBER
+ UNIT_TYPE
+ UNIT_SUBUNITS
+ UNIT_SUBUNITS_DIR
+ XBUS_REVISION
+ XBUS_CONNECTOR
+ XBUS_LABEL)) {
+ unless(defined $ENV{$k}) {
+ logit "Missing ENV{$k}\n";
+ die;
+ }
+ }
}
sub select_subunit($) {
@@ -87,8 +104,14 @@ sub select_subunit($) {
if($opts{o}) {
$output = $opts{o};
} else {
- my $xpd_name = sprintf("XPD-%1d%1d", $ENV{UNIT_NUMBER}, $subunit);
- $output = "$ENV{XPP_BASE}/$ENV{XBUS_NAME}/$xpd_name/chipregs";
+ $output = sprintf "/sys/bus/xpds/devices/%02d:%1d:%1d/chipregs",
+ $ENV{XBUS_NUMBER}, $ENV{UNIT_NUMBER}, $subunit;
+ if(! -f $output) {
+ my $xpd_name = sprintf("XPD-%1d%1d", $ENV{UNIT_NUMBER}, $subunit);
+ $output = "/proc/xpp/$ENV{XBUS_NAME}/$xpd_name/chipregs";
+ logit "OLD DRIVER: does not use /sys chipregs. Falling back to /proc"
+ if -f $output;
+ }
}
open(REG, ">$output") || die "Failed to open '$output': $!\n";
my $oldfh = select REG;
@@ -186,15 +209,21 @@ sub get_pri_protocol {
sub write_pri_info {
my $port = shift;
my $subunit = $port->{PORT_NUM};
- my $xpd_name = "XPD-$ENV{UNIT_NUMBER}$subunit";
- my $info = "$ENV{XPP_BASE}/$ENV{XBUS_NAME}/$xpd_name/pri_info";
my $pri_protocol = $port->get_pri_protocol;
+ my $xpd_name = sprintf("XPD-%1d%1d", $ENV{UNIT_NUMBER}, $subunit);
if(defined $pri_protocol) {
main::logit "$xpd_name: pri_protocol $pri_protocol";
- open(INFO, ">$info") || die "Failed to open '$info': $!\n";
- print INFO "$pri_protocol\n" || die "Failed writing '$pri_protocol' to '$info': $!\n";
- close INFO || die "Failed during close of '$info': $!\n";
+ my $file = sprintf "/sys/bus/xpds/devices/%02d:%1d:%1d/pri_protocol",
+ $ENV{XBUS_NUMBER}, $ENV{UNIT_NUMBER}, $subunit;
+ if(! -f $file) {
+ $file = "/proc/xpp/$ENV{XBUS_NAME}/$xpd_name/pri_info";
+ main::logit "OLD DRIVER: does not use /sys chipregs. Falling back to /proc"
+ if -f $file;
+ }
+ open(INFO, ">$file") || die "Failed to open '$file': $!\n";
+ print INFO "$pri_protocol\n" || die "Failed writing '$pri_protocol' to '$file': $!\n";
+ close INFO || die "Failed during close of '$file': $!\n";
} else {
main::logit "$xpd_name: Skip setting pri protocol -- non given";
}
diff --git a/drivers/dahdi/xpp/mmapdrv.c b/drivers/dahdi/xpp/mmapdrv.c
index c3ce708..22b9a2b 100644
--- a/drivers/dahdi/xpp/mmapdrv.c
+++ b/drivers/dahdi/xpp/mmapdrv.c
@@ -113,7 +113,7 @@ static irqreturn_t xpp_mmap_rx_irq(int irq, void *dev_id)
if (unlikely(disconnecting))
return IRQ_HANDLED;
- xbus = get_xbus(global_xbus->num);
+ xbus = xbus_num(global_xbus->num);
BUG_ON(!xbus);
if(!XBUS_GET(xbus)) {
if (printk_ratelimit())
@@ -186,7 +186,6 @@ free:
out:
if (in_use)
XBUS_PUT(xbus);
- put_xbus(xbus);
#ifdef DEBUG_VIA_GPIO
rx_intr_counter++;
#endif
@@ -230,11 +229,10 @@ static irqreturn_t xpp_mmap_tx_irq(int irq, void *dev_id)
spin_unlock_irqrestore(&tx_ready_lock, flags);
xbus = (xbus_t *)xframe->priv;
BUG_ON(!xbus);
- xbus = get_xbus(xbus->num);
+ xbus = xbus_num(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;
}
@@ -532,7 +530,7 @@ static int __init xpp_mmap_init(void)
ret = -ENOMEM;
goto fail_xbus;
}
- strncpy(global_xbus->location, "mmap", XBUS_DESCLEN);
+ strncpy(global_xbus->connector, "mmap", XBUS_DESCLEN);
strncpy(global_xbus->label, "mmap:0", LABEL_SIZE);
xframe_queue_init(&txpool, 10, 200, "mmap_txpool", global_xbus);
@@ -575,10 +573,10 @@ static void __exit xpp_mmap_exit(void)
xbus_t *xbus;
DBG(GENERAL, "\n");
disconnecting = 1;
- xbus = get_xbus(global_xbus->num);
+ xbus = xbus_num(global_xbus->num);
remove_proc_entry("xpp_mmap", xbus->proc_xbus_dir);
xframe_queue_clear(&txpool);
- xbus_disconnect(xbus); /* xbus_disconnect() calls put_xbus() */
+ xbus_disconnect(xbus);
kmem_cache_destroy(xframe_cache);
release_region((resource_size_t)FPGA_BASE_ADDR, 8);
diff --git a/drivers/dahdi/xpp/xbus-core.c b/drivers/dahdi/xpp/xbus-core.c
index 398decd..f868c0e 100644
--- a/drivers/dahdi/xpp/xbus-core.c
+++ b/drivers/dahdi/xpp/xbus-core.c
@@ -50,7 +50,9 @@ static const char rcsid[] = "$Id$";
#define INITIALIZATION_TIMEOUT (90*HZ) /* in jiffies */
#define PROC_XBUSES "xbuses"
#define PROC_XBUS_SUMMARY "summary"
+#ifdef OLD_PROC
#define PROC_XBUS_WAITFOR_XPDS "waitfor_xpds"
+#endif
#ifdef PROTOCOL_DEBUG
#define PROC_XBUS_COMMAND "command"
@@ -63,21 +65,36 @@ static DEF_PARM(uint, poll_timeout, 1000, 0644, "Timeout (in jiffies) waiting fo
static DEF_PARM_BOOL(rx_tasklet, 0, 0644, "Use receive tasklets");
static int xbus_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data);
+#ifdef OLD_PROC
static int xbus_read_waitfor_xpds(char *page, char **start, off_t off, int count, int *eof, void *data);
+#endif
static void transport_init(xbus_t *xbus, struct xbus_ops *ops, ushort max_send_size, void *priv);
static void transport_destroy(xbus_t *xbus);
/* Data structures */
static spinlock_t xbuses_lock = SPIN_LOCK_UNLOCKED;
-static int bus_count = 0;
static struct proc_dir_entry *proc_xbuses = NULL;
static struct xbus_desc {
xbus_t *xbus;
- atomic_t xbus_refcount;
- wait_queue_head_t can_release_xbus;
} xbuses_array[MAX_BUSES];
+const char *xbus_statename(enum xbus_state st)
+{
+ switch(st) {
+ case XBUS_STATE_START: return "START";
+ case XBUS_STATE_IDLE: return "IDLE";
+ case XBUS_STATE_SENT_REQUEST: return "SENT_REQUEST";
+ case XBUS_STATE_RECVD_DESC: return "RECVD_DESC";
+ case XBUS_STATE_READY: return "READY";
+ case XBUS_STATE_DEACTIVATING: return "DEACTIVATING";
+ case XBUS_STATE_DEACTIVATED: return "DEACTIVATED";
+ case XBUS_STATE_DISCONNECTED: return "DISCONNECTED";
+ case XBUS_STATE_FAIL: return "FAIL";
+ }
+ return NULL;
+}
+
static void init_xbus(uint num, xbus_t *xbus)
{
struct xbus_desc *desc;
@@ -85,72 +102,18 @@ static void init_xbus(uint num, xbus_t *xbus)
BUG_ON(num >= ARRAY_SIZE(xbuses_array));
desc = &xbuses_array[num];
desc->xbus = xbus;
- atomic_set(&desc->xbus_refcount, 0);
- init_waitqueue_head(&desc->can_release_xbus);
-}
-
-static int refcount_xbus(uint num)
-{
- BUG_ON(num >= ARRAY_SIZE(xbuses_array));
- return atomic_read(&xbuses_array[num].xbus_refcount);
}
-xbus_t *get_xbus(uint num)
+xbus_t *xbus_num(uint num)
{
struct xbus_desc *desc;
if(num >= ARRAY_SIZE(xbuses_array))
return NULL;
desc = &xbuses_array[num];
- atomic_inc(&desc->xbus_refcount);
- if(!desc->xbus)
- atomic_dec(&desc->xbus_refcount);
return desc->xbus;
}
-void put_xbus(xbus_t *xbus)
-{
- struct xbus_desc *desc;
- int num;
-
- BUG_ON(!xbus);
- num = xbus->num;
- BUG_ON(num >= ARRAY_SIZE(xbuses_array));
- desc = &xbuses_array[num];
- BUG_ON(desc->xbus != xbus);
- if(atomic_dec_and_test(&desc->xbus_refcount)) {
- static int rate_limit;
-
- if((rate_limit++ % 1003) == 0)
- XBUS_DBG(DEVICES, xbus,
- "wake_up(can_release_xbus) (%d)\n", rate_limit);
- wake_up(&desc->can_release_xbus);
- }
-}
-
-static bool __must_check wait_for_xbus_release(uint xbus_num)
-{
- xbus_t *xbus;
- int ret;
-
- xbus = get_xbus(xbus_num);
- if(!xbus) {
- ERR("%s: xbus #%d is already removed. Skip.\n",
- __FUNCTION__, xbus_num);
- return 0;
- }
- put_xbus(xbus);
- DBG(DEVICES, "Waiting... refcount_xbus=%d\n", refcount_xbus(xbus_num));
- ret = wait_event_interruptible(xbuses_array[xbus_num].can_release_xbus,
- refcount_xbus(xbus_num) == 0);
- if(ret) {
- ERR("%s: waiting for xbus #%d interrupted!!!\n",
- __FUNCTION__, xbus_num);
- } else
- DBG(DEVICES, "Waiting for refcount_xbus done.\n");
- return 1;
-}
-
static void initialize_xbuses_array(void)
{
int i;
@@ -171,6 +134,30 @@ static void finalize_xbuses_array(void)
}
}
+xbus_t *get_xbus(const char *msg, xbus_t *xbus)
+{
+ struct device *dev;
+
+ XBUS_DBG(DEVICES, xbus, "%s: refcount_xbus=%d\n",
+ msg, refcount_xbus(xbus));
+ dev = get_device(&xbus->astribank);
+ return dev_to_xbus(dev);
+}
+
+void put_xbus(const char *msg, xbus_t *xbus)
+{
+ XBUS_DBG(DEVICES, xbus, "%s: refcount_xbus=%d\n",
+ msg, refcount_xbus(xbus));
+ put_device(&xbus->astribank);
+}
+
+int refcount_xbus(xbus_t *xbus)
+{
+ struct kref *kref = &xbus->astribank.kobj.kref;
+
+ return atomic_read(&kref->refcount);
+}
+
/*------------------------- Debugfs Handling -----------------------*/
#ifdef XPP_DEBUGFS
@@ -314,7 +301,7 @@ static int debugfs_release(struct inode *inode, struct file *file)
BUG_ON(!d->xbus);
XBUS_DBG(GENERAL, d->xbus, "\n");
d->xbus->debugfs_data = NULL;
- kfree(d);
+ KZFREE(d);
module_put(THIS_MODULE);
return 0;
}
@@ -455,23 +442,6 @@ void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe, i
spin_unlock_irqrestore(&serialize_dump_xframe, flags);
}
-static bool xbus_ready(const xbus_t *xbus, const char msg[])
-{
- if(!xbus) {
- ERR("null xbus: %s\n", msg);
- return 0;
- }
- if (!TRANSPORT_RUNNING(xbus)) {
- XBUS_ERR(xbus, "%s -- hardware is not ready.", msg);
- return 0;
- }
- if(!xbus->transport.ops) {
- XBUS_ERR(xbus, "%s -- hardware is gone.", msg);
- return 0;
- }
- return 1;
-}
-
/**
*
* Frame is freed:
@@ -484,7 +454,8 @@ int send_pcm_frame(xbus_t *xbus, xframe_t *xframe)
int ret = -ENODEV;
BUG_ON(!xframe);
- if(!xbus_ready(xbus, "Dropped a pcm frame")) {
+ if(!XBUS_IS(xbus, READY)) {
+ XBUS_ERR(xbus, "Dropped a pcm frame -- hardware is not ready.\n");
ret = -ENODEV;
goto error;
}
@@ -509,7 +480,9 @@ static int really_send_cmd_frame(xbus_t *xbus, xframe_t *xframe)
BUG_ON(!xbus);
BUG_ON(!xframe);
BUG_ON(xframe->xframe_magic != XFRAME_MAGIC);
- if(!xbus_ready(xbus, "Dropped command before sending")) {
+ if(XBUS_IS(xbus, DISCONNECTED)) {
+ XBUS_ERR(xbus, "Dropped command before sending -- hardware deactivated.\n");
+ dump_xframe("Dropped", xbus, xframe, DBG_ANY);
FREE_SEND_XFRAME(xbus, xframe);
return -ENODEV;
}
@@ -531,15 +504,17 @@ int xbus_command_queue_tick(xbus_t *xbus)
xframe_t *frm;
int ret = 0;
+ xbus->command_tick_counter++;
frm = xframe_dequeue(&xbus->command_queue);
if(frm) {
BUG_ON(frm->xframe_magic != XFRAME_MAGIC);
ret = really_send_cmd_frame(xbus, frm);
- if(ret < 0)
+ if(ret < 0) {
XBUS_ERR(xbus,
"Failed to send from command_queue (ret=%d)\n",
ret);
- XBUS_PUT(xbus);
+ xbus_setstate(xbus, XBUS_STATE_FAIL);
+ }
} else
wake_up(&xbus->command_queue_empty);
return ret;
@@ -550,10 +525,9 @@ static void xbus_command_queue_clean(xbus_t *xbus)
xframe_t *frm;
XBUS_DBG(DEVICES, xbus, "count=%d\n", xbus->command_queue.count);
- xframe_queue_disable(&xbus->command_queue);
+ xframe_queue_disable(&xbus->command_queue, 1);
while((frm = xframe_dequeue(&xbus->command_queue)) != NULL) {
FREE_SEND_XFRAME(xbus, frm);
- XBUS_PUT(xbus);
}
}
@@ -577,23 +551,21 @@ int send_cmd_frame(xbus_t *xbus, xframe_t *xframe)
BUG_ON(xframe->xframe_magic != XFRAME_MAGIC);
- if(!xbus_ready(xbus, "Dropped command before queueing")) {
- ret = -ENODEV;
- goto err;
- }
- if(!XBUS_GET(xbus)) {
- /* shutting down */
+ if(XBUS_IS(xbus, DISCONNECTED)) {
+ XBUS_ERR(xbus, "Dropped command before queueing -- hardware deactivated.\n");
ret = -ENODEV;
goto err;
}
+ if(debug & DBG_COMMANDS)
+ dump_xframe(__FUNCTION__, xbus, xframe, DBG_ANY);
if(!xframe_enqueue(&xbus->command_queue, xframe)) {
if((rate_limit++ % 1003) == 0) {
XBUS_ERR(xbus,
"Dropped command xframe. Cannot enqueue (%d)\n",
rate_limit);
- dump_xframe("send_cmd_frame", xbus, xframe, DBG_ANY);
+ dump_xframe(__FUNCTION__, xbus, xframe, DBG_ANY);
}
- XBUS_PUT(xbus);
+ xbus_setstate(xbus, XBUS_STATE_FAIL);
ret = -E2BIG;
goto err;
}
@@ -644,7 +616,7 @@ void xbus_receive_xframe(xbus_t *xbus, xframe_t *xframe)
if(rx_tasklet) {
xframe_enqueue_recv(xbus, xframe);
} else {
- if (likely(TRANSPORT_RUNNING(xbus)))
+ if(likely(!XBUS_IS(xbus, DISCONNECTED)))
xframe_receive(xbus, xframe);
else
FREE_RECV_XFRAME(xbus, xframe); /* return to receive_pool */
@@ -666,75 +638,72 @@ xpd_t *xpd_byaddr(const xbus_t *xbus, uint unit, uint subunit)
return xbus->xpds[XPD_IDX(unit,subunit)];
}
-int xbus_register_xpd(xbus_t *xbus, xpd_t *xpd)
+int xbus_xpd_bind(xbus_t *xbus, xpd_t *xpd, int unit, int subunit)
{
- unsigned int xpd_num = xpd->xbus_idx;
+ unsigned int xpd_num;
unsigned long flags;
- int ret = 0;
- xbus = get_xbus(xbus->num); /* until unregister */
BUG_ON(!xbus);
- XBUS_DBG(DEVICES, xbus, "XPD #%d (xbus_refcount=%d)\n",
- xpd_num, refcount_xbus(xbus->num));
+ xpd_num = XPD_IDX(unit,subunit);
+ XBUS_DBG(DEVICES, xbus, "XPD #%d\n", xpd_num);
spin_lock_irqsave(&xbus->lock, flags);
if(!VALID_XPD_NUM(xpd_num)) {
XBUS_ERR(xbus, "Bad xpd_num = %d\n", xpd_num);
- ret = -EINVAL;
- goto out;
+ BUG();
}
if(xbus->xpds[xpd_num] != NULL) {
xpd_t *other = xbus->xpds[xpd_num];
XBUS_ERR(xbus, "xpd_num=%d is occupied by %p (%s)\n",
xpd_num, other, other->xpdname);
- ret = -EINVAL;
- goto out;
+ BUG();
}
+ snprintf(xpd->xpdname, XPD_NAMELEN, "XPD-%1d%1d", unit, subunit);
+ MKADDR(&xpd->addr, unit, subunit);
+ xpd->xbus_idx = xpd_num;
xbus->xpds[xpd_num] = xpd;
xpd->xbus = xbus;
- xbus->num_xpds++;
-out:
+ atomic_inc(&xbus->xbus_ref_count);
+ atomic_inc(&xbus->num_xpds);
spin_unlock_irqrestore(&xbus->lock, flags);
- return ret;
+ /* Must be done out of atomic context */
+ if(xpd_device_register(xbus, xpd) < 0) {
+ XPD_ERR(xpd, "%s: xpd_device_register() failed\n", __FUNCTION__);
+ /* FIXME: What to do? */
+ }
+ return 0;
}
-int xbus_unregister_xpd(xbus_t *xbus, xpd_t *xpd)
+int xbus_xpd_unbind(xbus_t *xbus, xpd_t *xpd)
{
unsigned int xpd_num = xpd->xbus_idx;
unsigned long flags;
- int ret = -EINVAL;
- spin_lock_irqsave(&xbus->lock, flags);
- XBUS_DBG(DEVICES, xbus, "XPD #%d (xbus_refcount=%d)\n",
- xpd_num, refcount_xbus(xbus->num));
+ XBUS_DBG(DEVICES, xbus, "XPD #%d\n", xpd_num);
if(!VALID_XPD_NUM(xpd_num)) {
XBUS_ERR(xbus, "%s: Bad xpd_num = %d\n", __FUNCTION__, xpd_num);
- goto out;
+ BUG();
}
if(xbus->xpds[xpd_num] == NULL) {
XBUS_ERR(xbus, "%s: slot xpd_num=%d is empty\n", __FUNCTION__, xpd_num);
- goto out;
+ BUG();
}
if(xbus->xpds[xpd_num] != xpd) {
xpd_t *other = xbus->xpds[xpd_num];
XBUS_ERR(xbus, "%s: slot xpd_num=%d is occupied by %p (%s)\n",
__FUNCTION__, xpd_num, other, other->xpdname);
- goto out;
+ BUG();
}
- xbus->xpds[xpd_num] = NULL;
- xbus->num_xpds--;
+ spin_lock_irqsave(&xbus->lock, flags);
xpd->xbus = NULL;
- put_xbus(xbus); /* we got it in xbus_register_xpd() */
- ret = 0;
-out:
+ xbus->xpds[xpd_num] = NULL;
+ if(atomic_dec_and_test(&xbus->num_xpds))
+ xbus_setstate(xbus, XBUS_STATE_IDLE);
spin_unlock_irqrestore(&xbus->lock, flags);
- return ret;
+ return 0;
}
-/*
- * Called with xbus->worker locked.
- */
static int new_card(xbus_t *xbus,
int unit,
byte type,
@@ -773,7 +742,12 @@ static int new_card(xbus_t *xbus,
BUG_ON(!xops);
xbus->worker->num_units += subunits - 1;
for(i = 0; i < subunits; i++) {
- if(!TRANSPORT_RUNNING(xbus)) {
+ if(!XBUS_IS(xbus, RECVD_DESC)) {
+ XBUS_NOTICE(xbus,
+ "Cannot create XPD=%d%d in state %s\n",
+ unit,
+ i,
+ xbus_statename(XBUS_STATE(xbus)));
ret = -ENODEV;
goto out;
}
@@ -782,13 +756,13 @@ static int new_card(xbus_t *xbus,
i,
type,
subtype);
- if(!XBUS_GET(xbus)) {
- XBUS_ERR(xbus, "Aborting creation. Is shutting down.\n");
+ if(!XBUS_IS(xbus, RECVD_DESC)) {
+ XBUS_ERR(xbus, "Aborting creation -- In bad state %s\n",
+ xbus_statename(XBUS_STATE(xbus)));
ret = -ENODEV;
goto out;
}
ret = create_xpd(xbus, proto_table, unit, i, type, subtype, subunits, port_dir);
- XBUS_PUT(xbus);
if(ret < 0) {
XBUS_ERR(xbus, "Creation of XPD=%d%d failed %d\n",
unit, i, ret);
@@ -801,44 +775,77 @@ out:
return ret;
}
+static void xbus_release_xpds(xbus_t *xbus)
+{
+ int i;
+
+ XBUS_INFO(xbus, "[%s] Release XPDS\n", xbus->label);
+ for(i = 0; i < MAX_XPDS; i++) {
+ xpd_t *xpd = xpd_of(xbus, i);
+
+ if(xpd)
+ put_xpd(__FUNCTION__, xpd); /* taken in xbus_xpd_bind() */
+ }
+}
+
+static int xpd_initialize(xpd_t *xpd)
+{
+ int ret = -ENODEV;
+
+ if(CALL_XMETHOD(card_init, xpd->xbus, xpd) < 0) {
+ XPD_ERR(xpd, "Card Initialization failed\n");
+ goto out;
+ }
+ //CALL_XMETHOD(XPD_STATE, xpd->xbus, xpd, 0); /* Turn off all channels */
+ xpd->card_present = 1;
+ CALL_XMETHOD(XPD_STATE, xpd->xbus, xpd, 1); /* Turn on all channels */
+ if(!xpd_setstate(xpd, XPD_STATE_READY)) {
+ goto out;
+ }
+ XPD_INFO(xpd, "Initialized: %s\n", xpd->type_name);
+ xpd_post_init(xpd);
+ ret = 0;
+out:
+ return ret;
+}
+
static int xbus_initialize(xbus_t *xbus)
{
int unit;
int subunit;
xpd_t *xpd;
+ XBUS_DBG(DEVICES, xbus, "refcount_xbus=%d\n",
+ refcount_xbus(xbus));
for(unit = 0; unit < MAX_UNIT; unit++) {
xpd = xpd_byaddr(xbus, unit, 0);
if(!xpd)
continue;
if(run_initialize_registers(xpd) < 0) {
- XPD_ERR(xpd, "Register Initialization failed\n");
+ XBUS_ERR(xbus, "Register Initialization of card #%d failed\n", unit);
goto err;
}
for(subunit = 0; subunit < MAX_SUBUNIT; subunit++) {
+ int ret;
+
xpd = xpd_byaddr(xbus, unit, subunit);
if(!xpd)
continue;
- if(CALL_XMETHOD(card_init, xpd->xbus, xpd) < 0) {
- XPD_ERR(xpd, "Card Initialization failed\n");
+ xpd = get_xpd(__FUNCTION__, xpd);
+ if(!xpd) {
+ XBUS_ERR(xbus,
+ "Aborting initialization. XPD-%d%d is gone.\n",
+ unit, subunit);
goto err;
}
- //CALL_XMETHOD(XPD_STATE, xpd->xbus, xpd, 0); /* Turn off all channels */
- xpd->card_present = 1;
- CALL_XMETHOD(XPD_STATE, xpd->xbus, xpd, 1); /* Turn on all channels */
- XPD_INFO(xpd, "Initialized: %s\n", xpd->type_name);
- xpd_post_init(xpd);
+ ret = xpd_initialize(xpd);
+ put_xpd(__FUNCTION__, xpd);
+ if(ret < 0)
+ goto err;
}
}
return 0;
err:
- for(unit = 0; unit < MAX_UNIT; unit++) {
- for(subunit = 0; subunit < MAX_SUBUNIT; subunit++) {
- xpd = xpd_byaddr(xbus, unit, subunit);
- if(!xpd)
- xpd_free(xpd);
- }
- }
return -EINVAL;
}
@@ -848,7 +855,7 @@ err:
* initialized.
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
-void xbus_populate(struct work_struct *work)
+static void xbus_populate(struct work_struct *work)
{
struct xbus_workqueue *worker = container_of(work, struct xbus_workqueue, xpds_init_work);
#else
@@ -863,10 +870,7 @@ void xbus_populate(void *data)
int ret = 0;
xbus = worker->xbus;
- if(!XBUS_GET(xbus)) {
- XBUS_NOTICE(xbus, "Shutting down, aboring initialization\n");
- return;
- }
+ XBUS_DBG(DEVICES, xbus, "Entering %s\n", __FUNCTION__);
spin_lock_irqsave(&worker->worker_lock, flags);
list_for_each_safe(card, next_card, &worker->card_list) {
struct card_desc_struct *card_desc = list_entry(card, struct card_desc_struct, card_list);
@@ -889,13 +893,17 @@ void xbus_populate(void *data)
break;
}
spin_unlock_irqrestore(&worker->worker_lock, flags);
- xbus_initialize(xbus);
- worker->xpds_init_done = 1;
- ret = xbus_sysfs_create(xbus);
- if(ret) {
- XBUS_ERR(xbus, "SYSFS creation failed: %d\n", ret);
+ if(xbus_initialize(xbus) < 0) {
+ XBUS_NOTICE(xbus, "Initialization failed. Leave unused. refcount_xbus=%d\n",
+ refcount_xbus(xbus));
+ goto failed;
}
- wake_up(&worker->wait_for_xpd_initialization);
+ if(!xbus_setstate(xbus, XBUS_STATE_READY)) {
+ XBUS_NOTICE(xbus, "Illegal transition. Leave unused. refcount_xbus=%d\n",
+ refcount_xbus(xbus));
+ goto failed;
+ }
+ worker->xpds_init_done = 1;
/*
* Now request Astribank to start self_ticking.
* This is the last initialization command. So
@@ -903,48 +911,108 @@ void xbus_populate(void *data)
*/
xbus_request_sync(xbus, SYNC_MODE_PLL);
elect_syncer("xbus_poll(end)"); /* FIXME: try to do it later */
- put_xbus(xbus); /* taken in AB_DESCRIPTION */
- XBUS_PUT(xbus);
+out:
+ XBUS_DBG(DEVICES, xbus, "Leaving\n");
+ wake_up(&worker->wait_for_xpd_initialization);
+ XBUS_DBG(DEVICES, xbus, "populate release\n");
+ up(&xbus->in_worker);
+ return;
+failed:
+ goto out;
}
-static void worker_destroy(struct xbus_workqueue *worker)
+int xbus_process_worker(xbus_t *xbus)
{
- xbus_t *xbus;
+ struct xbus_workqueue *worker = xbus->worker;
+
+ if(!xbus) {
+ ERR("%s: xbus gone -- skip initialization\n", __FUNCTION__);
+ return 0;
+ }
+ if(down_trylock(&xbus->in_worker)) {
+ ERR("%s: xbus is disconnected -- skip initialization\n", __FUNCTION__);
+ return 0;
+ }
+ XBUS_DBG(DEVICES, xbus, "\n");
+ /* Initialize the work. (adapt to kernel API changes). */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
+ INIT_WORK(&worker->xpds_init_work, xbus_populate);
+#else
+ INIT_WORK(&worker->xpds_init_work, xbus_populate, worker);
+#endif
+ BUG_ON(!xbus);
+ /* Now send it */
+ if(!queue_work(worker->wq, &worker->xpds_init_work)) {
+ XBUS_ERR(xbus, "Failed to queue xpd initialization work\n");
+ up(&xbus->in_worker);
+ return 0;
+ }
+ return 1;
+}
+
+static void worker_reset(struct xbus_workqueue *worker)
+{
+
struct list_head *card;
struct list_head *next_card;
unsigned long flags;
+ xbus_t *xbus = worker->xbus;
+ char *name = (xbus) ? xbus->busname : "detached";
- if(!worker)
- return;
+ BUG_ON(!worker);
+ DBG(DEVICES, "%s\n", name);
+ if(!worker->xpds_init_done) {
+ NOTICE("%s: worker(%s)->xpds_init_done=%d\n",
+ __FUNCTION__, name, worker->xpds_init_done);
+ }
spin_lock_irqsave(&worker->worker_lock, flags);
- xbus = worker->xbus;
list_for_each_safe(card, next_card, &worker->card_list) {
struct card_desc_struct *card_desc = list_entry(card, struct card_desc_struct, card_list);
BUG_ON(card_desc->magic != CARD_DESC_MAGIC);
list_del(card);
- kfree(card_desc);
+ KZFREE(card_desc);
}
+ worker->xpds_init_done = 0;
+ worker->num_units = 0;
+ worker->num_units_initialized = 0;
spin_unlock_irqrestore(&worker->worker_lock, flags);
+ wake_up(&worker->wait_for_xpd_initialization);
+}
+
+static void worker_destroy(struct xbus_workqueue *worker)
+{
+ xbus_t *xbus;
+
+ if(!worker)
+ return;
+ worker_reset(worker);
+ xbus = worker->xbus;
if(xbus) {
+ XBUS_DBG(DEVICES, xbus, "Waiting for worker to finish...\n");
+ down(&xbus->in_worker);
+ XBUS_DBG(DEVICES, xbus, "Waiting for worker to finish -- done\n");
+ if (worker->wq) {
+ XBUS_DBG(DEVICES, xbus, "destroying workqueue...\n");
+ flush_workqueue(worker->wq);
+ destroy_workqueue(worker->wq);
+ worker->wq = NULL;
+ XBUS_DBG(DEVICES, xbus, "destroying workqueue -- done\n");
+ }
#ifdef CONFIG_PROC_FS
+#ifdef OLD_PROC
if(xbus->proc_xbus_dir && worker->proc_xbus_waitfor_xpds) {
XBUS_DBG(PROC, xbus, "Removing proc '%s'\n", PROC_XBUS_WAITFOR_XPDS);
remove_proc_entry(PROC_XBUS_WAITFOR_XPDS, xbus->proc_xbus_dir);
worker->proc_xbus_waitfor_xpds = NULL;
}
#endif
+#endif
XBUS_DBG(DEVICES, xbus, "detach worker\n");
xbus->worker = NULL;
+ KZFREE(worker);
+ put_xbus(__FUNCTION__, xbus); /* got from worker_new() */
}
- if (worker->wq) {
- DBG(DEVICES, "XBUS #%d: destroy workqueue\n", worker->xbus->num);
- flush_workqueue(worker->wq);
- destroy_workqueue(worker->wq);
- worker->wq = NULL;
- }
- put_xbus(xbus); /* Taken in worker_new() */
- KZFREE(worker);
}
/*
@@ -952,29 +1020,27 @@ static void worker_destroy(struct xbus_workqueue *worker)
* May call blocking operations, but only briefly (as we are called
* from xbus_new() which is called from khubd.
*/
-static struct xbus_workqueue *worker_new(int xbus_num)
+static struct xbus_workqueue *worker_new(int xbusno)
{
struct xbus_workqueue *worker;
xbus_t *xbus;
- xbus = get_xbus(xbus_num); /* release in worker_destroy */
+ if((xbus = xbus_num(xbusno)) == NULL)
+ return NULL;
+ get_xbus(__FUNCTION__, xbus); /* return in worker_destroy() */
BUG_ON(xbus->busname[0] == '\0'); /* No name? */
- BUG_ON(xbus->worker != NULL); /* Hmmm... nested workers? */
+ BUG_ON(xbus->worker != NULL); /* Hmmm... nested workers? */
XBUS_DBG(DEVICES, xbus, "\n");
worker = KZALLOC(sizeof(*worker), GFP_KERNEL);
if(!worker)
goto err;
- worker->xbus = xbus;
/* poll related variables */
spin_lock_init(&worker->worker_lock);
INIT_LIST_HEAD(&worker->card_list);
init_waitqueue_head(&worker->wait_for_xpd_initialization);
- worker->wq = create_singlethread_workqueue(xbus->busname);
- if(!worker->wq) {
- XBUS_ERR(xbus, "Failed to create worker workqueue.\n");
- goto err;
- }
+ worker->xbus = xbus;
#ifdef CONFIG_PROC_FS
+#ifdef OLD_PROC
if(xbus->proc_xbus_dir) {
worker->proc_xbus_waitfor_xpds = create_proc_read_entry(
PROC_XBUS_WAITFOR_XPDS, 0444,
@@ -988,18 +1054,118 @@ static struct xbus_workqueue *worker_new(int xbus_num)
worker->proc_xbus_waitfor_xpds->owner = THIS_MODULE;
}
#endif
+#endif
+ worker->wq = create_singlethread_workqueue(xbus->busname);
+ if(!worker->wq) {
+ XBUS_ERR(xbus, "Failed to create worker workqueue.\n");
+ goto err;
+ }
return worker;
err:
worker_destroy(worker);
return NULL;
}
+bool xbus_setstate(xbus_t *xbus, enum xbus_state newstate)
+{
+ unsigned long flags;
+ bool ret = 0;
+ int state_flip = 0;
+
+ spin_lock_irqsave(&xbus->transport.state_lock, flags);
+ if(newstate == XBUS_STATE(xbus)) {
+ XBUS_DBG(DEVICES, xbus, "stay at %s\n",
+ xbus_statename(newstate));
+ goto out;
+ }
+ /* Sanity tests */
+ switch(newstate) {
+ case XBUS_STATE_START:
+ goto bad_state;
+ case XBUS_STATE_IDLE:
+ if(!XBUS_IS(xbus, START) &&
+ !XBUS_IS(xbus, DEACTIVATED))
+ goto bad_state;
+ break;
+ case XBUS_STATE_SENT_REQUEST:
+ if(!XBUS_IS(xbus, IDLE) &&
+ !XBUS_IS(xbus, SENT_REQUEST))
+ goto bad_state;
+ break;
+ case XBUS_STATE_RECVD_DESC:
+ if(!XBUS_IS(xbus, SENT_REQUEST))
+ goto bad_state;
+ break;
+ case XBUS_STATE_READY:
+ if(!XBUS_IS(xbus, RECVD_DESC))
+ goto bad_state;
+ state_flip = 1; /* We are good */
+ break;
+ case XBUS_STATE_DEACTIVATING:
+#if 0
+ if(XBUS_IS(xbus, DEACTIVATED) || XBUS_IS(xbus, DISCONNECTED))
+ goto bad_state;
+#endif
+ break;
+ case XBUS_STATE_DEACTIVATED:
+ if(!XBUS_IS(xbus, DEACTIVATING))
+ goto bad_state;
+ break;
+ case XBUS_STATE_DISCONNECTED:
+ break;
+ case XBUS_STATE_FAIL:
+ if(XBUS_IS(xbus, DEACTIVATING) || XBUS_IS(xbus, DEACTIVATED) || XBUS_IS(xbus, DISCONNECTED))
+ goto bad_state;
+ break;
+ default:
+ XBUS_NOTICE(xbus, "%s: unknown state %d\n", __FUNCTION__, newstate);
+ goto out;
+ }
+ /* All good */
+ XBUS_DBG(DEVICES, xbus, "%s -> %s\n",
+ xbus_statename(XBUS_STATE(xbus)),
+ xbus_statename(newstate));
+ if(xbus->transport.xbus_state == XBUS_STATE_READY && newstate != XBUS_STATE_READY)
+ state_flip = -1; /* We became bad */
+ xbus->transport.xbus_state = newstate;
+ ret = 1;
+out:
+ spin_unlock_irqrestore(&xbus->transport.state_lock, flags);
+ /* Should be sent out of spinlocks */
+ if(state_flip > 0)
+ astribank_uevent_send(xbus, KOBJ_ONLINE);
+ else if(state_flip < 0)
+ astribank_uevent_send(xbus, KOBJ_OFFLINE);
+ return ret;
+bad_state:
+ XBUS_NOTICE(xbus, "Bad state transition %s -> %s ignored.\n",
+ xbus_statename(XBUS_STATE(xbus)),
+ xbus_statename(newstate));
+ goto out;
+}
+
int xbus_activate(xbus_t *xbus)
{
+ XBUS_INFO(xbus, "[%s] Activating\n", xbus->label);
+ xpp_drift_init(xbus);
+ xbus_set_command_timer(xbus, 1);
+ xframe_queue_disable(&xbus->command_queue, 0);
+ xbus_setstate(xbus, XBUS_STATE_IDLE); /* must be done after transport is valid */
+ CALL_PROTO(GLOBAL, AB_REQUEST, xbus, NULL);
+ /*
+ * Make sure Astribank knows not to send us ticks.
+ */
+ xbus_request_sync(xbus, SYNC_MODE_NONE);
+ return 0;
+}
+
+int xbus_connect(xbus_t *xbus)
+{
struct xbus_ops *ops;
struct xbus_workqueue *worker;
BUG_ON(!xbus);
+ XBUS_DBG(DEVICES, xbus, "\n");
ops = transportops_get(xbus);
BUG_ON(!ops);
worker = xbus->worker;
@@ -1009,64 +1175,66 @@ int xbus_activate(xbus_t *xbus)
BUG_ON(!ops->xframe_send_cmd);
BUG_ON(!ops->alloc_xframe);
BUG_ON(!ops->free_xframe);
- xpp_drift_init(xbus);
- /*
- * We start with timer based ticking
- */
- xbus_set_command_timer(xbus, 1);
- xbus->transport.transport_running = 1; /* must be done after transport is valid */
- XBUS_INFO(xbus, "[%s] Activating\n", xbus->label);
- /*
- * Make sure Astribank knows not to send us ticks.
- */
- xbus_request_sync(xbus, SYNC_MODE_NONE);
- CALL_PROTO(GLOBAL, AB_REQUEST, xbus, NULL);
+ xbus_activate(xbus);
return 0;
}
-void xbus_disconnect(xbus_t *xbus)
+void xbus_deactivate(xbus_t *xbus, bool is_disconnected)
{
int i;
BUG_ON(!xbus);
- XBUS_INFO(xbus, "[%s] Disconnecting\n", xbus->label);
- xbus_set_command_timer(xbus, 1);
+ XBUS_INFO(xbus, "[%s] Deactivating\n", xbus->label);
+ if(!xbus_setstate(xbus, XBUS_STATE_DEACTIVATING))
+ return;
xbus_request_sync(xbus, SYNC_MODE_NONE); /* no more ticks */
- xbus_sysfs_remove(xbus); /* Device-Model */
for(i = 0; i < MAX_XPDS; i++) {
xpd_t *xpd = xpd_of(xbus, i);
- if(!xpd)
- continue;
- if(xpd->xbus_idx != i) {
- XBUS_ERR(xbus, "BUG: xpd->xbus_idx=%d != i=%d\n", xpd->xbus_idx, i);
- continue;
+ if(xpd) {
+ xpd_unreg_request(xpd);
}
- xpd_disconnect(xpd);
}
- XBUS_DBG(DEVICES, xbus, "Deactivating\n");
- tasklet_kill(&xbus->receive_tasklet);
- xframe_queue_clear(&xbus->receive_queue);
+ elect_syncer("deactivate");
+ XBUS_DBG(DEVICES, xbus, "[%s] Waiting for queues\n", xbus->label);
xbus_command_queue_clean(xbus);
xbus_command_queue_waitempty(xbus);
- del_timer_sync(&xbus->command_timer);
+ xbus_setstate(xbus, XBUS_STATE_DEACTIVATED);
+ worker_reset(xbus->worker);
+ xbus_release_xpds(xbus);
+ if(!is_disconnected)
+ xbus_setstate(xbus, XBUS_STATE_IDLE);
+}
+
+void xbus_disconnect(xbus_t *xbus)
+{
+ XBUS_INFO(xbus, "[%s] Disconnecting\n", xbus->label);
+ BUG_ON(!xbus);
+ xbus_deactivate(xbus, 1);
+ xbus_command_queue_clean(xbus);
+ xbus_command_queue_waitempty(xbus);
+ tasklet_kill(&xbus->receive_tasklet);
+ xframe_queue_clear(&xbus->receive_queue);
xframe_queue_clear(&xbus->send_pool);
xframe_queue_clear(&xbus->receive_pool);
xframe_queue_clear(&xbus->pcm_tospan);
+ xbus_setstate(xbus, XBUS_STATE_DISCONNECTED);
+ del_timer_sync(&xbus->command_timer);
transportops_put(xbus);
transport_destroy(xbus);
- elect_syncer("disconnect");
- XBUS_DBG(DEVICES, xbus, "Deactivated (refcount_xbus=%d)\n", refcount_xbus(xbus->num));
+ worker_destroy(xbus->worker);
+ XBUS_DBG(DEVICES, xbus, "Deactivated refcount_xbus=%d\n",
+ refcount_xbus(xbus));
if(atomic_dec_and_test(&xbus->xbus_ref_count)) {
- XBUS_DBG(DEVICES, xbus, "Going to remove XBUS\n");
- xbus_remove(xbus);
+ XBUS_DBG(DEVICES, xbus, "%s: Last ref to xbus. Removing\n", __FUNCTION__);
}
+ xbus_sysfs_remove(xbus); /* Device-Model */
}
static xbus_t *xbus_alloc(void)
{
unsigned long flags;
- xbus_t *xbus;
- int i;
+ xbus_t *xbus;
+ int i;
xbus = KZALLOC(sizeof(xbus_t), GFP_KERNEL);
if(!xbus) {
@@ -1079,28 +1247,27 @@ static xbus_t *xbus_alloc(void)
break;
if(i >= MAX_BUSES) {
ERR("%s: No free slot for new bus. i=%d\n", __FUNCTION__, i);
- kfree(xbus);
+ KZFREE(xbus);
xbus = NULL;
goto out;
}
/* Found empty slot */
xbus->num = i;
init_xbus(i, xbus);
- xbus = get_xbus(i);
- bus_count++;
out:
spin_unlock_irqrestore(&xbuses_lock, flags);
return xbus;
}
-static void xbus_free(xbus_t *xbus)
+void xbus_free(xbus_t *xbus)
{
unsigned long flags;
uint num;
if(!xbus)
return;
+ XBUS_DBG(DEVICES, xbus, "Free\n");
spin_lock_irqsave(&xbuses_lock, flags);
num = xbus->num;
BUG_ON(!xbuses_array[num].xbus);
@@ -1136,18 +1303,7 @@ static void xbus_free(xbus_t *xbus)
}
#endif
spin_lock_irqsave(&xbuses_lock, flags);
- /*
- * Return to xbus reference counts:
- * - One from our caller: transport disconnect or xpp_close()
- * - One from xbus_alloc()
- */
- put_xbus(xbus);
- put_xbus(xbus);
- if(!wait_for_xbus_release(xbus->num))
- BUG(); /* Let's see what happens next... */
- bus_count--;
- XBUS_DBG(DEVICES, xbus, "Going to free... refcount_xbus=%d\n", refcount_xbus(num));
- BUG_ON(refcount_xbus(num) != 0);
+ XBUS_DBG(DEVICES, xbus, "Going to free...\n");
init_xbus(num, NULL);
spin_unlock_irqrestore(&xbuses_lock, flags);
KZFREE(xbus);
@@ -1159,23 +1315,31 @@ xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, void *priv)
xbus_t *xbus = NULL;
BUG_ON(!ops);
- XBUS_DBG(GENERAL, xbus, "allocate new xbus\n");
xbus = xbus_alloc();
- if(!xbus)
+ if(!xbus) {
+ ERR("%s: Failed allocating new xbus\n", __FUNCTION__);
+ module_put(THIS_MODULE);
return NULL;
+ }
+ snprintf(xbus->busname, XBUS_NAMELEN, "XBUS-%02d", xbus->num);
+ XBUS_DBG(DEVICES, xbus, "\n");
transport_init(xbus, ops, max_send_size, priv);
spin_lock_init(&xbus->lock);
atomic_set(&xbus->xbus_ref_count, 1); /* a single ref */
- snprintf(xbus->busname, XBUS_NAMELEN, "XBUS-%02d", xbus->num);
init_waitqueue_head(&xbus->command_queue_empty);
init_timer(&xbus->command_timer);
+ init_MUTEX(&xbus->in_worker);
atomic_set(&xbus->pcm_rx_counter, 0);
xbus->min_tx_sync = INT_MAX;
xbus->min_rx_sync = INT_MAX;
- xbus->num_xpds = 0;
+ atomic_set(&xbus->num_xpds, 0);
xbus->sync_mode = SYNC_MODE_NONE;
- init_rwsem(&xbus->in_use);
+ err = xbus_sysfs_create(xbus);
+ if(err) {
+ XBUS_ERR(xbus, "SYSFS creation failed: %d\n", err);
+ goto nobus;
+ }
xbus_reset_counters(xbus);
#ifdef CONFIG_PROC_FS
XBUS_DBG(PROC, xbus, "Creating xbus proc directory\n");
@@ -1240,31 +1404,6 @@ nobus:
return NULL;
}
-void xbus_remove(xbus_t *xbus)
-{
- int i;
-
- BUG_ON(TRANSPORT_RUNNING(xbus));
- down_write(&xbus->in_use);
-
- XBUS_INFO(xbus, "[%s] Removing\n", xbus->label);
- for(i = 0; i < MAX_XPDS; i++) {
- xpd_t *xpd = xpd_of(xbus, i);
-
- if(xpd) {
- if(xpd->xbus_idx != i) {
- XBUS_ERR(xbus, "BUG: xpd->xbus_idx=%d != i=%d\n", xpd->xbus_idx, i);
- continue;
- }
- XBUS_DBG(DEVICES, xbus, " Removing xpd #%d\n", i);
- xpd_remove(xpd);
- }
- xbus->xpds[i] = NULL;
- }
- worker_destroy(xbus->worker);
- xbus_free(xbus);
-}
-
/*------------------------- Proc handling --------------------------*/
void xbus_reset_counters(xbus_t *xbus)
@@ -1305,17 +1444,18 @@ static int xbus_read_proc(char *page, char **start, off_t off, int count, int *e
int len = 0;
int i = (int)((unsigned long)data);
- xbus = get_xbus(i);
+ xbus = xbus_num(i);
if(!xbus)
goto out;
+ xbus = get_xbus(__FUNCTION__, xbus); /* until end of xbus_read_proc */
spin_lock_irqsave(&xbus->lock, flags);
worker = xbus->worker;
len += sprintf(page + len, "%s: CONNECTOR=%s LABEL=[%s] STATUS=%s\n",
xbus->busname,
- xbus->location,
+ xbus->connector,
xbus->label,
- (TRANSPORT_RUNNING(xbus)) ? "connected" : "missing"
+ (!XBUS_IS(xbus, DISCONNECTED)) ? "connected" : "missing"
);
len += sprintf(page + len, "\nxbus_ref_count=%d\n",
atomic_read(&xbus->xbus_ref_count)
@@ -1336,6 +1476,7 @@ static int xbus_read_proc(char *page, char **start, off_t off, int count, int *e
}
len += sprintf(page + len, "self_ticking: %d (last_tick at %ld)\n",
xbus->self_ticking, xbus->ticker.last_sample.tv.tv_sec);
+ len += sprintf(page + len, "command_tick: %d\n", xbus->command_tick_counter);
len += sprintf(page + len, "xbus: pcm_rx_counter = %d, frag = %d\n",
atomic_read(&xbus->pcm_rx_counter), xbus->xbus_frag_count);
len += sprintf(page + len, "max_rx_process = %2ld.%ld ms\n",
@@ -1358,7 +1499,7 @@ static int xbus_read_proc(char *page, char **start, off_t off, int count, int *e
}
len += sprintf(page + len, "<-- len=%d\n", len);
spin_unlock_irqrestore(&xbus->lock, flags);
- put_xbus(xbus);
+ put_xbus(__FUNCTION__, xbus); /* from xbus_read_proc() */
out:
if (len <= off+count)
*eof = 1;
@@ -1372,23 +1513,20 @@ out:
}
-static int xbus_read_waitfor_xpds(char *page, char **start, off_t off, int count, int *eof, void *data)
+int waitfor_xpds(xbus_t *xbus, char *buf)
{
- int len = 0;
- unsigned long flags;
- xbus_t *xbus = data;
struct xbus_workqueue *worker;
+ unsigned long flags;
int ret;
+ int len = 0;
- if(!xbus)
- goto out;
- /* first handle special cases */
- if(!count || off)
- goto out;
/*
- * worker is created before /proc/XBUS-??
+ * FIXME: worker is created before ?????
* So by now it exists and initialized.
*/
+ xbus = get_xbus(__FUNCTION__, xbus); /* until end of waitfor_xpds_show() */
+ if(!xbus)
+ return -ENODEV;
worker = xbus->worker;
BUG_ON(!worker);
XBUS_DBG(DEVICES, xbus,
@@ -1407,25 +1545,49 @@ static int xbus_read_waitfor_xpds(char *page, char **start, off_t off, int count
*/
ret = wait_event_interruptible_timeout(
worker->wait_for_xpd_initialization,
- worker->xpds_init_done,
+ !XBUS_IS(xbus, RECVD_DESC) || worker->xpds_init_done,
INITIALIZATION_TIMEOUT);
if(ret == 0) {
XBUS_ERR(xbus, "Card Initialization Timeout\n");
- return ret;
+ len = -ETIMEDOUT;
+ goto out;
} else if(ret < 0) {
XBUS_ERR(xbus, "Card Initialization Interrupted %d\n", ret);
- return ret;
+ len = ret;
+ goto out;
} else
XBUS_DBG(DEVICES, xbus,
"Finished initialization of %d XPD's in %d seconds.\n",
worker->num_units_initialized,
(INITIALIZATION_TIMEOUT - ret)/HZ);
spin_lock_irqsave(&xbus->lock, flags);
- len += sprintf(page + len, "XPDS_READY: %s: %d/%d\n",
+ len += sprintf(buf, "XPDS_READY: %s: %d/%d\n",
xbus->busname,
worker->num_units_initialized, worker->num_units);
spin_unlock_irqrestore(&xbus->lock, flags);
out:
+ put_xbus(__FUNCTION__, xbus); /* from start of waitfor_xpds_show() */
+ return len;
+}
+
+#ifdef OLD_PROC
+static int xbus_read_waitfor_xpds(char *page, char **start, off_t off, int count, int *eof, void *data)
+{
+ int len = 0;
+ unsigned long flags;
+ xbus_t *xbus = data;
+ struct xbus_workqueue *worker;
+ int ret;
+
+ if(!xbus)
+ goto out;
+ XBUS_NOTICE(xbus, "%s: DEPRECATED: %s[%d] read from /proc interface instead of /sys\n",
+ __FUNCTION__, current->comm, current->tgid);
+ /* first handle special cases */
+ if(!count || off)
+ goto out;
+ len = waitfor_xpds(xbus, page);
+out:
if (len <= off+count)
*eof = 1;
*start = page + off;
@@ -1437,6 +1599,7 @@ out:
return len;
}
+#endif
#ifdef PROTOCOL_DEBUG
static int proc_xbus_command_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
@@ -1526,17 +1689,15 @@ static int read_proc_xbuses(char *page, char **start, off_t off, int count, int
spin_lock_irqsave(&xbuses_lock, flags);
for(i = 0; i < MAX_BUSES; i++) {
- xbus_t *xbus = get_xbus(i);
+ xbus_t *xbus = xbus_num(i);
if(xbus) {
- len += sprintf(page + len, "%s: CONNECTOR=%s LABEL=[%s] STATUS=%s REFCOUNT=%d\n",
+ len += sprintf(page + len, "%s: CONNECTOR=%s LABEL=[%s] STATUS=%s\n",
xbus->busname,
- xbus->location,
+ xbus->connector,
xbus->label,
- (TRANSPORT_RUNNING(xbus)) ? "connected" : "missing",
- refcount_xbus(i) - 1
+ (!XBUS_IS(xbus, DISCONNECTED)) ? "connected" : "missing"
);
- put_xbus(xbus);
}
}
#if 0
@@ -1567,6 +1728,8 @@ static void transport_init(xbus_t *xbus, struct xbus_ops *ops, ushort max_send_s
xbus->transport.ops = ops;
xbus->transport.max_send_size = max_send_size;
xbus->transport.priv = priv;
+ xbus->transport.xbus_state = XBUS_STATE_START;
+ spin_lock_init(&xbus->transport.state_lock);
spin_lock_init(&xbus->transport.lock);
atomic_set(&xbus->transport.transport_refcount, 0);
init_waitqueue_head(&xbus->transport.transport_unused);
@@ -1577,7 +1740,6 @@ static void transport_destroy(xbus_t *xbus)
int ret;
BUG_ON(!xbus);
- xbus->transport.transport_running = 0;
XBUS_DBG(DEVICES, xbus, "Waiting... (transport_refcount=%d)\n",
atomic_read(&xbus->transport.transport_refcount));
ret = wait_event_interruptible(xbus->transport.transport_unused,
@@ -1660,7 +1822,7 @@ int __init xbus_core_init(void)
goto err;
}
#endif
- if((ret = register_xpp_bus()) < 0)
+ if((ret = xpp_driver_init()) < 0)
goto err;
return 0;
err:
@@ -1673,25 +1835,22 @@ void xbus_core_shutdown(void)
{
int i;
- for(i = 0; i < MAX_BUSES; i++) {
- xbus_t *xbus = get_xbus(i);
-
- if(xbus) {
- xbus_remove(xbus);
- }
- }
- BUG_ON(bus_count);
- unregister_xpp_bus();
+ for(i = 0; i < MAX_BUSES; i++)
+ BUG_ON(xbus_num(i));
xbus_core_cleanup();
+ xpp_driver_exit();
}
EXPORT_SYMBOL(xpd_of);
EXPORT_SYMBOL(xpd_byaddr);
-EXPORT_SYMBOL(get_xbus);
-EXPORT_SYMBOL(put_xbus);
+EXPORT_SYMBOL(xbus_num);
+EXPORT_SYMBOL(xbus_setstate);
+EXPORT_SYMBOL(xbus_statename);
EXPORT_SYMBOL(xbus_new);
-EXPORT_SYMBOL(xbus_remove);
+EXPORT_SYMBOL(xbus_free);
+EXPORT_SYMBOL(xbus_connect);
EXPORT_SYMBOL(xbus_activate);
+EXPORT_SYMBOL(xbus_deactivate);
EXPORT_SYMBOL(xbus_disconnect);
EXPORT_SYMBOL(xbus_receive_xframe);
EXPORT_SYMBOL(xbus_reset_counters);
diff --git a/drivers/dahdi/xpp/xbus-core.h b/drivers/dahdi/xpp/xbus-core.h
index 85fac80..c563c88 100644
--- a/drivers/dahdi/xpp/xbus-core.h
+++ b/drivers/dahdi/xpp/xbus-core.h
@@ -86,18 +86,34 @@ static struct xbus_counters {
#define XBUS_COUNTER_MAX ARRAY_SIZE(xbus_counters)
+enum xbus_state {
+ XBUS_STATE_START,
+ XBUS_STATE_IDLE,
+ XBUS_STATE_SENT_REQUEST,
+ XBUS_STATE_RECVD_DESC,
+ XBUS_STATE_READY,
+ XBUS_STATE_DEACTIVATING,
+ XBUS_STATE_DEACTIVATED,
+ XBUS_STATE_DISCONNECTED,
+ XBUS_STATE_FAIL,
+};
+
+const char *xbus_statename(enum xbus_state st);
+
struct xbus_transport {
struct xbus_ops *ops;
void *priv;
ushort max_send_size;
- bool transport_running; /* Hardware is functional */
+ enum xbus_state xbus_state;
+ spinlock_t state_lock;
atomic_t transport_refcount;
wait_queue_head_t transport_unused;
spinlock_t lock;
};
#define MAX_SEND_SIZE(xbus) ((xbus)->transport.max_send_size)
-#define TRANSPORT_RUNNING(xbus) ((xbus)->transport.transport_running)
+#define XBUS_STATE(xbus) ((xbus)->transport.xbus_state)
+#define XBUS_IS(xbus, st) (XBUS_STATE(xbus) == XBUS_STATE_ ## st)
#define TRANSPORT_EXIST(xbus) ((xbus)->transport.ops != NULL)
struct xbus_ops *transportops_get(xbus_t *xbus);
@@ -133,8 +149,10 @@ void put_xframe(struct xframe_queue *q, xframe_t *xframe);
#define FREE_SEND_XFRAME(xbus, xframe) put_xframe(&(xbus)->send_pool, (xframe))
#define FREE_RECV_XFRAME(xbus, xframe) put_xframe(&(xbus)->receive_pool, (xframe))
-xbus_t *get_xbus(uint num);
-void put_xbus(xbus_t *xbus);
+xbus_t *xbus_num(uint num);
+xbus_t *get_xbus(const char *msg, xbus_t *xbus);
+void put_xbus(const char *msg, xbus_t *xbus);
+int refcount_xbus(xbus_t *xbus);
/*
* An xbus is a transport layer for Xorcom Protocol commands
@@ -143,7 +161,7 @@ struct xbus {
char busname[XBUS_NAMELEN]; /* set by xbus_new() */
/* low-level bus drivers set these 2 fields */
- char location[XBUS_DESCLEN];
+ char connector[XBUS_DESCLEN];
char label[LABEL_SIZE];
byte revision; /* Protocol revision */
struct xbus_transport transport;
@@ -151,6 +169,7 @@ struct xbus {
int num;
struct xpd *xpds[MAX_XPDS];
+ int command_tick_counter;
struct xframe_queue command_queue;
wait_queue_head_t command_queue_empty;
@@ -198,6 +217,7 @@ struct xbus {
#endif
struct xbus_workqueue *worker;
+ struct semaphore in_worker;
/*
* Sync adjustment
@@ -206,11 +226,7 @@ struct xbus {
int sync_adjustment_offset;
long pll_updated_at;
- struct rw_semaphore in_use;
-#define XBUS_GET(xbus) down_read_trylock(&(xbus)->in_use)
-#define XBUS_PUT(xbus) up_read(&(xbus)->in_use)
-
- int num_xpds;
+ atomic_t num_xpds;
#ifdef XPP_DEBUGFS
struct dentry *debugfs_dir;
@@ -281,25 +297,29 @@ xpacket_t *xframe_next_packet(xframe_t *xframe, int len);
xpd_t *xpd_of(const xbus_t *xbus, int xpd_num);
xpd_t *xpd_byaddr(const xbus_t *xbus, uint unit, uint subunit);
+bool xbus_setstate(xbus_t *xbus, enum xbus_state newstate);
xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, void *priv);
-void xbus_remove(xbus_t *xbus);
-int xbus_activate(xbus_t *xbus);
-void xbus_disconnect(xbus_t *xbus);
-void xbus_receive_xframe(xbus_t *xbus, xframe_t *xframe);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
-void xbus_populate(struct work_struct *work);
-#else
-void xbus_populate(void *data);
-#endif
-
-int xbus_register_xpd(xbus_t *xbus, xpd_t *xpd);
-int xbus_unregister_xpd(xbus_t *xbus, xpd_t *xpd);
+void xbus_free(xbus_t *xbus);
+int xbus_connect(xbus_t *xbus);
+int xbus_activate(xbus_t *xbus);
+void xbus_deactivate(xbus_t *xbus, bool is_disconnected);
+void xbus_disconnect(xbus_t *xbus);
+void xbus_receive_xframe(xbus_t *xbus, xframe_t *xframe);
+int xbus_process_worker(xbus_t *xbus);
+int waitfor_xpds(xbus_t *xbus, char *buf);
+
+int xbus_xpd_bind(xbus_t *xbus, xpd_t *xpd, int unit, int subunit);
+int xbus_xpd_unbind(xbus_t *xbus, xpd_t *xpd);
/* sysfs */
-int register_xpp_bus(void);
-void unregister_xpp_bus(void);
-int xbus_sysfs_create(xbus_t *xbus);
-void xbus_sysfs_remove(xbus_t *xbus);
+int xpd_device_register(xbus_t *xbus, xpd_t *xpd);
+void xpd_device_unregister(xpd_t *xpd);
+
+int xpp_driver_init(void);
+void xpp_driver_exit(void);
+int xbus_sysfs_create(xbus_t *xbus);
+void xbus_sysfs_remove(xbus_t *xbus);
+void astribank_uevent_send(xbus_t *xbus, enum kobject_action act);
#endif /* XBUS_CORE_H */
diff --git a/drivers/dahdi/xpp/xbus-pcm.c b/drivers/dahdi/xpp/xbus-pcm.c
index 030fbdf..9e6ce8d 100644
--- a/drivers/dahdi/xpp/xbus-pcm.c
+++ b/drivers/dahdi/xpp/xbus-pcm.c
@@ -172,9 +172,11 @@ static void xpp_drift_step(xbus_t *xbus, const struct timeval *tv)
if(lost_ticks) {
driftinfo->lost_ticks++;
driftinfo->lost_tick_count += abs(lost_ticks);
- XBUS_DBG(SYNC, xbus, "Lost %d tick%s\n",
- lost_ticks,
- (abs(lost_ticks) > 1) ? "s": "");
+ if(printk_ratelimit()) {
+ XBUS_DBG(SYNC, xbus, "Lost %d tick%s\n",
+ lost_ticks,
+ (abs(lost_ticks) > 1) ? "s": "");
+ }
ticker->cycle = SYNC_ADJ_QUICK;
if(abs(lost_ticks) > 100)
ticker->count = ref_ticker->count;
@@ -362,6 +364,10 @@ void xbus_request_sync(xbus_t *xbus, enum sync_mode mode)
BUG_ON(!xbus);
XBUS_DBG(SYNC, xbus, "sent request (mode=%d)\n", mode);
CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, mode, 0);
+ if(mode == SYNC_MODE_NONE) {
+ xbus->self_ticking = 0;
+ xbus_set_command_timer(xbus, 1);
+ }
}
static void reset_sync_counters(void)
@@ -370,7 +376,7 @@ static void reset_sync_counters(void)
//DBG(SYNC, "%d\n", atomic_read(&xpp_tick_counter));
for(i = 0; i < MAX_BUSES; i++) {
- xbus_t *xbus = get_xbus(i);
+ xbus_t *xbus = xbus_num(i);
if(!xbus)
continue;
@@ -380,20 +386,15 @@ static void reset_sync_counters(void)
* - Or maybe they didn't answer us in the first place
(e.g: wrong firmware version, etc).
*/
- if (TRANSPORT_RUNNING(xbus) && xbus->self_ticking) {
- if(XBUS_GET(xbus)) {
+ if(xbus->self_ticking) {
+ if(XBUS_IS(xbus, DISCONNECTED)) {
+ XBUS_DBG(GENERAL, xbus,
+ "Dropped packet. Is shutting down.\n");
+ } else {
/* Reset sync LEDs once in a while */
CALL_PROTO(GLOBAL, RESET_SYNC_COUNTERS, xbus, NULL);
- XBUS_PUT(xbus);
- } else {
- static int rate_limit;
-
- if((rate_limit++ % 1003) == 0)
- XBUS_DBG(GENERAL, xbus,
- "Dropped packet. Is shutting down. (%d)\n", rate_limit);
}
}
- put_xbus(xbus);
}
}
@@ -520,16 +521,15 @@ static void update_sync_master(xbus_t *new_syncer)
DBG(SYNC, "stop unwanted syncers\n");
/* Shut all down except the wanted sync master */
for(i = 0; i < MAX_BUSES; i++) {
- xbus_t *xbus = get_xbus(i);
+ xbus_t *xbus = xbus_num(i);
if(!xbus)
continue;
- if(TRANSPORT_RUNNING(xbus) && xbus != new_syncer) {
+ if(!XBUS_IS(xbus, DISCONNECTED) && xbus != new_syncer) {
if(xbus->self_ticking)
xbus_request_sync(xbus, SYNC_MODE_PLL);
else
XBUS_DBG(SYNC, xbus, "Not self_ticking yet. Ignore\n");
}
- put_xbus(xbus);
}
}
@@ -542,12 +542,12 @@ void elect_syncer(const char *msg)
xbus_t *the_xbus = NULL;
for(i = 0; i < MAX_BUSES; i++) {
- xbus_t *xbus = get_xbus(i);
+ xbus_t *xbus = xbus_num(i);
if(!xbus)
continue;
if(!the_xbus)
the_xbus = xbus;
- if (TRANSPORT_RUNNING(xbus)) {
+ if(XBUS_IS(xbus, READY)) {
for(j = 0; j < MAX_XPDS; j++) {
xpd_t *xpd = xpd_of(xbus, j);
@@ -559,7 +559,6 @@ void elect_syncer(const char *msg)
}
}
}
- put_xbus(xbus);
}
if(best_xpd) {
the_xbus = best_xpd->xbus;
@@ -726,7 +725,7 @@ static inline void pcm_frame_out(xbus_t *xbus, xframe_t *xframe)
spin_lock_irqsave(&xbus->lock, flags);
do_gettimeofday(&now);
- if(unlikely(disable_pcm || !TRANSPORT_RUNNING(xbus)))
+ if(unlikely(disable_pcm || !XBUS_IS(xbus, READY)))
goto dropit;
if(XPACKET_ADDR_SYNC((xpacket_t *)xframe->packets)) {
usec = usec_diff(&now, &xbus->last_tx_sync);
@@ -1124,7 +1123,7 @@ static int proc_sync_read(char *page, char **start, off_t off, int count, int *e
static int proc_sync_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
{
char buf[MAX_PROC_WRITE];
- int xbus_num;
+ int xbusno;
int xpd_num;
xbus_t *xbus;
xpd_t *xpd;
@@ -1139,40 +1138,36 @@ static int proc_sync_write(struct file *file, const char __user *buffer, unsigne
DBG(SYNC, "DAHDI\n");
force_dahdi_sync=1;
update_sync_master(NULL);
- } else if(sscanf(buf, "SYNC=%d", &xbus_num) == 1) {
- DBG(SYNC, "SYNC=%d\n", xbus_num);
- if((xbus = get_xbus(xbus_num)) == NULL) {
- ERR("No bus %d exists\n", xbus_num);
+ } else if(sscanf(buf, "SYNC=%d", &xbusno) == 1) {
+ DBG(SYNC, "SYNC=%d\n", xbusno);
+ if((xbus = xbus_num(xbusno)) == NULL) {
+ ERR("No bus %d exists\n", xbusno);
return -ENXIO;
}
update_sync_master(xbus);
- put_xbus(xbus);
- } else if(sscanf(buf, "QUERY=%d", &xbus_num) == 1) {
- DBG(SYNC, "QUERY=%d\n", xbus_num);
- if((xbus = get_xbus(xbus_num)) == NULL) {
- ERR("No bus %d exists\n", xbus_num);
+ } else if(sscanf(buf, "QUERY=%d", &xbusno) == 1) {
+ DBG(SYNC, "QUERY=%d\n", xbusno);
+ if((xbus = xbus_num(xbusno)) == NULL) {
+ ERR("No bus %d exists\n", xbusno);
return -ENXIO;
}
CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, SYNC_MODE_QUERY, 0);
- put_xbus(xbus);
- } else if(sscanf(buf, "%d %d", &xbus_num, &xpd_num) == 2) {
+ } else if(sscanf(buf, "%d %d", &xbusno, &xpd_num) == 2) {
NOTICE("Using deprecated syntax to update %s file\n",
PROC_SYNC);
if(xpd_num != 0) {
ERR("Currently can only set sync for XPD #0\n");
return -EINVAL;
}
- if((xbus = get_xbus(xbus_num)) == NULL) {
- ERR("No bus %d exists\n", xbus_num);
+ if((xbus = xbus_num(xbusno)) == NULL) {
+ ERR("No bus %d exists\n", xbusno);
return -ENXIO;
}
if((xpd = xpd_of(xbus, xpd_num)) == NULL) {
XBUS_ERR(xbus, "No xpd %d exists\n", xpd_num);
- put_xbus(xbus);
return -ENXIO;
}
update_sync_master(xbus);
- put_xbus(xbus);
} else {
ERR("%s: cannot parse '%s'\n", __FUNCTION__, buf);
count = -EINVAL;
diff --git a/drivers/dahdi/xpp/xbus-sysfs.c b/drivers/dahdi/xpp/xbus-sysfs.c
index c00ee64..5bb4f7d 100644
--- a/drivers/dahdi/xpp/xbus-sysfs.c
+++ b/drivers/dahdi/xpp/xbus-sysfs.c
@@ -38,6 +38,7 @@
#include "xpd.h"
#include "xpp_dahdi.h"
#include "xbus-core.h"
+#include "card_global.h"
#ifdef XPP_DEBUGFS
#include "xpp_log.h"
#endif
@@ -48,7 +49,6 @@ static const char rcsid[] = "$Id$";
/* Command line parameters */
extern int debug;
-
/* Kernel versions... */
/*
* Hotplug replaced with uevent in 2.6.16
@@ -57,27 +57,184 @@ extern int debug;
#define OLD_HOPLUG_SUPPORT // for older kernels
#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
-#define DEVICE_ATTR_READER(name,dev,buf) \
- ssize_t name(struct device *dev, struct device_attribute *attr, char *buf)
-#define DEVICE_ATTR_WRITER(name,dev,buf, count) \
- ssize_t name(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
-#else
-#define DEVICE_ATTR_READER(name,dev,buf) \
- ssize_t name(struct device *dev, char *buf)
-#define DEVICE_ATTR_WRITER(name,dev,buf, count) \
- ssize_t name(struct device *dev, const char *buf, size_t count)
+/*--------- Sysfs Bus handling ----*/
+static DEVICE_ATTR_READER(xbus_state_show, dev, buf)
+{
+ xbus_t *xbus;
+ int ret;
+
+ xbus = dev_to_xbus(dev);
+ ret = XBUS_STATE(xbus);
+ ret = snprintf(buf, PAGE_SIZE, "%s (%d)\n",
+ xbus_statename(ret), ret);
+ return ret;
+}
+
+static DEVICE_ATTR_WRITER(xbus_state_store, dev, buf, count)
+{
+ xbus_t *xbus;
+
+ xbus = dev_to_xbus(dev);
+ XBUS_DBG(GENERAL, xbus, "%s\n", buf);
+ if(strncmp(buf, "stop", 4) == 0)
+ xbus_deactivate(xbus, 0);
+ else if(XBUS_IS(xbus, IDLE) && strncmp(buf, "start", 5) == 0)
+ xbus_activate(xbus);
+ else {
+ XBUS_NOTICE(xbus, "%s: Illegal action %s in state %s. Ignored.\n",
+ __FUNCTION__, buf,
+ xbus_statename(XBUS_STATE(xbus)));
+ return -EINVAL;
+ }
+ return count;
+}
+
+static DEVICE_ATTR_READER(status_show, dev, buf)
+{
+ xbus_t *xbus;
+ int ret;
+
+ xbus = dev_to_xbus(dev);
+ ret = snprintf(buf, PAGE_SIZE, "%s\n", (!XBUS_IS(xbus, DISCONNECTED))?"connected":"missing");
+ return ret;
+}
+
+static DEVICE_ATTR_READER(timing_show, dev, buf)
+{
+ xbus_t *xbus;
+ struct xpp_drift *driftinfo;
+ int len = 0;
+ struct timeval now;
+
+ do_gettimeofday(&now);
+ xbus = dev_to_xbus(dev);
+ driftinfo = &xbus->drift;
+ len += snprintf(buf + len, PAGE_SIZE - len, "DRIFT: %-3s", sync_mode_name(xbus->sync_mode));
+ if(xbus->sync_mode == SYNC_MODE_PLL) {
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ " %5d: jitter %4d median %4d calc_drift %3d lost (%4d,%4d) : ",
+ xbus->ticker.cycle,
+ driftinfo->jitter, driftinfo->median,
+ driftinfo->calc_drift,
+ driftinfo->lost_ticks, driftinfo->lost_tick_count);
+ len += snprintf(buf + len, PAGE_SIZE - len,
+ "DRIFT %3d %ld sec ago",
+ xbus->sync_adjustment,
+ (xbus->pll_updated_at == 0) ? 0 : now.tv_sec - xbus->pll_updated_at);
+ }
+ len += snprintf(buf + len, PAGE_SIZE - len, "\n");
+ return len;
+}
+
+#ifdef SAMPLE_TICKS
+/*
+ * tick sampling: Measure offset from reference ticker:
+ * - Recording start when writing to:
+ * /sys/bus/astribanks/devices/xbus-??/samples
+ * - Recording ends when filling SAMPLE_SIZE ticks
+ * - Results are read from the same sysfs file.
+ * - Trying to read/write during recording, returns -EBUSY.
+ */
+static DEVICE_ATTR_READER(samples_show, dev, buf)
+{
+ xbus_t *xbus;
+ int len = 0;
+ int i;
+
+ xbus = dev_to_xbus(dev);
+ if(xbus->sample_running)
+ return -EBUSY;
+ for(i = 0; i < SAMPLE_SIZE; i++) {
+ if(len > PAGE_SIZE - 20)
+ break;
+ len += snprintf(buf + len, PAGE_SIZE - len, "%d\n", xbus->sample_ticks[i]);
+ }
+ return len;
+}
+
+static DEVICE_ATTR_WRITER(samples_store, dev, buf, count)
+{
+ xbus_t *xbus;
+
+ xbus = dev_to_xbus(dev);
+ if(xbus->sample_running)
+ return -EBUSY;
+ memset(xbus->sample_ticks, 0, sizeof(*xbus->sample_ticks));
+ xbus->sample_pos = 0;
+ xbus->sample_running = 1;
+ return count;
+}
#endif
-/*--------- Sysfs Bus handling ----*/
-static int xpp_bus_match(struct device *dev, struct device_driver *driver)
+/*
+ * Clear statistics
+ */
+static DEVICE_ATTR_WRITER(cls_store, dev, buf, count)
+{
+ xbus_t *xbus;
+ struct xpp_drift *driftinfo;
+
+ xbus = dev_to_xbus(dev);
+ driftinfo = &xbus->drift;
+ driftinfo->lost_ticks = 0;
+ driftinfo->lost_tick_count = 0;
+ xbus->min_tx_sync = INT_MAX;
+ xbus->max_tx_sync = 0;
+ xbus->min_rx_sync = INT_MAX;
+ xbus->max_rx_sync = 0;
+#ifdef SAMPLE_TICKS
+ memset(xbus->sample_ticks, 0, sizeof(*xbus->sample_ticks));
+#endif
+ return count;
+}
+
+static DEVICE_ATTR_READER(waitfor_xpds_show, dev, buf)
+{
+ xbus_t *xbus;
+ int len;
+
+ xbus = dev_to_xbus(dev);
+ len = waitfor_xpds(xbus, buf);
+ return len;
+}
+
+#define xbus_attr(field, format_string) \
+static ssize_t \
+field##_show(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+ xbus_t *xbus; \
+ \
+ xbus = dev_to_xbus(dev); \
+ return sprintf (buf, format_string, xbus->field); \
+}
+
+xbus_attr(connector, "%s\n");
+xbus_attr(label, "%s\n");
+
+struct device_attribute xbus_dev_attrs[] = {
+ __ATTR_RO(connector),
+ __ATTR_RO(label),
+ __ATTR_RO(status),
+ __ATTR_RO(timing),
+ __ATTR_RO(waitfor_xpds),
+ __ATTR(cls, S_IWUSR, NULL, cls_store),
+ __ATTR(xbus_state, S_IRUGO | S_IWUSR, xbus_state_show, xbus_state_store),
+#ifdef SAMPLE_TICKS
+ __ATTR(samples, S_IWUSR | S_IRUGO, samples_show, samples_store),
+#endif
+ __ATTR_NULL,
+};
+
+
+static int astribank_match(struct device *dev, struct device_driver *driver)
{
- DBG(GENERAL, "dev->bus_id = %s, driver->name = %s\n", dev->bus_id, driver->name);
+ DBG(DEVICES, "SYSFS MATCH: dev->bus_id = %s, driver->name = %s\n",
+ dev->bus_id, driver->name);
return 1;
}
#ifdef OLD_HOPLUG_SUPPORT
-static int xpp_bus_hotplug(struct device *dev, char **envp, int envnum, char *buff, int bufsize)
+static int astribank_hotplug(struct device *dev, char **envp, int envnum, char *buff, int bufsize)
{
xbus_t *xbus;
@@ -109,7 +266,7 @@ static int xpp_bus_hotplug(struct device *dev, char **envp, int envnum, char *bu
return err; \
} while (0)
-static int xpp_bus_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
+static int astribank_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
{
xbus_t *xbus;
int i = 0;
@@ -119,11 +276,12 @@ static int xpp_bus_uevent(struct device *dev, char **envp, int num_envp, char *b
if(!dev)
return -ENODEV;
xbus = dev_to_xbus(dev);
- DBG(GENERAL, "bus_id=%s xbus=%s\n", dev->bus_id, xbus->busname);
+ DBG(GENERAL, "SYFS bus_id=%s xbus=%s\n", dev->bus_id, xbus->busname);
XBUS_VAR_BLOCK;
envp[i] = NULL;
return 0;
}
+
#else
#define XBUS_ADD_UEVENT_VAR(fmt, val...) \
do { \
@@ -132,7 +290,7 @@ static int xpp_bus_uevent(struct device *dev, char **envp, int num_envp, char *b
return err; \
} while (0)
-static int xpp_bus_uevent(struct device *dev, struct kobj_uevent_env *kenv)
+static int astribank_uevent(struct device *dev, struct kobj_uevent_env *kenv)
{
xbus_t *xbus;
extern char *initdir;
@@ -140,232 +298,354 @@ static int xpp_bus_uevent(struct device *dev, struct kobj_uevent_env *kenv)
if(!dev)
return -ENODEV;
xbus = dev_to_xbus(dev);
- DBG(GENERAL, "bus_id=%s xbus=%s\n", dev->bus_id, xbus->busname);
+ DBG(GENERAL, "SYFS bus_id=%s xbus=%s\n", dev->bus_id, xbus->busname);
XBUS_VAR_BLOCK;
return 0;
}
+
#endif
+void astribank_uevent_send(xbus_t *xbus, enum kobject_action act)
+{
+ struct kobject *kobj;
+
+ kobj = &xbus->astribank.kobj;
+ XBUS_DBG(DEVICES, xbus, "SYFS bus_id=%s action=%d\n",
+ xbus->astribank.bus_id, act);
+ kobject_uevent(kobj, act);
+}
+
#endif /* OLD_HOPLUG_SUPPORT */
-static void xpp_bus_release(struct device *dev)
+static void xpp_release(struct device *dev)
{
- DBG(GENERAL, "\n");
+ DBG(DEVICES, "SYSFS %s\n", dev->bus_id);
}
-static void xpp_dev_release(struct device *dev)
+static void astribank_release(struct device *dev)
{
xbus_t *xbus;
BUG_ON(!dev);
xbus = dev_to_xbus(dev);
- XBUS_DBG(GENERAL, xbus, "\n");
+ if(!XBUS_IS(xbus, DISCONNECTED)) {
+ XBUS_ERR(xbus, "Try to release in state %s\n",
+ xbus_statename(XBUS_STATE(xbus)));
+ BUG();
+ }
+ XBUS_INFO(xbus, "[%s] Astribank Release\n", xbus->label);
+ xbus_free(xbus);
}
-static struct bus_type xpp_bus_type = {
+static struct bus_type toplevel_bus_type = {
.name = "astribanks",
- .match = xpp_bus_match,
+ .match = astribank_match,
#ifdef OLD_HOPLUG_SUPPORT
- .hotplug = xpp_bus_hotplug,
+ .hotplug = astribank_hotplug,
#else
- .uevent = xpp_bus_uevent,
+ .uevent = astribank_uevent,
#endif
+ .dev_attrs = xbus_dev_attrs,
};
-static struct device xpp_bus = {
- .bus_id = "xppbus",
- .release = xpp_bus_release
+static struct device toplevel_device = {
+ .bus_id = "xpp",
+ .release = xpp_release
};
+static int astribank_probe(struct device *dev)
+{
+ xbus_t *xbus;
+
+ xbus = dev_to_xbus(dev);
+ XBUS_DBG(DEVICES, xbus, "SYSFS\n");
+ return 0;
+}
+
+static int astribank_remove(struct device *dev)
+{
+ xbus_t *xbus;
+
+ xbus = dev_to_xbus(dev);
+ XBUS_INFO(xbus, "[%s] Atribank Remove\n", xbus->label);
+ return 0;
+}
+
static struct device_driver xpp_driver = {
.name = "xppdrv",
- .bus = &xpp_bus_type,
+ .bus = &toplevel_bus_type,
+ .probe = astribank_probe,
+ .remove = astribank_remove,
#ifndef OLD_HOPLUG_SUPPORT
.owner = THIS_MODULE
#endif
};
-int register_xpp_bus(void)
+/*--------- Sysfs XPD handling ----*/
+
+static DEVICE_ATTR_READER(chipregs_show, dev, buf)
{
- int ret;
+ xpd_t *xpd;
+ unsigned long flags;
+ reg_cmd_t *regs;
+ bool do_datah;
+ char datah_str[50];
+ int len = 0;
- if((ret = bus_register(&xpp_bus_type)) < 0) {
- ERR("%s: bus_register failed. Error number %d", __FUNCTION__, ret);
- goto failed_bus;
- }
- if((ret = device_register(&xpp_bus)) < 0) {
- ERR("%s: registration of xpp_bus failed. Error number %d",
- __FUNCTION__, ret);
- goto failed_busdevice;
- }
- if((ret = driver_register(&xpp_driver)) < 0) {
- ERR("%s: driver_register failed. Error number %d", __FUNCTION__, ret);
- goto failed_driver;
+ BUG_ON(!dev);
+ xpd = dev_to_xpd(dev);
+ if(!xpd)
+ return -ENODEV;
+ spin_lock_irqsave(&xpd->lock, flags);
+ regs = &xpd->last_reply;
+ len += sprintf(buf + len, "# Writing bad data into this file may damage your hardware!\n");
+ len += sprintf(buf + len, "# Consult firmware docs first\n");
+ len += sprintf(buf + len, "#\n");
+ do_datah = REG_FIELD(regs, do_datah) ? 1 : 0;
+ if(do_datah) {
+ snprintf(datah_str, ARRAY_SIZE(datah_str), "\t%02X",
+ REG_FIELD(regs, data_high));
+ } else
+ datah_str[0] = '\0';
+ if(REG_FIELD(regs, do_subreg)) {
+ len += sprintf(buf + len, "#CH\tOP\tReg.\tSub\tDL%s\n",
+ (do_datah) ? "\tDH" : "");
+ len += sprintf(buf + len, "%2d\tRS\t%02X\t%02X\t%02X%s\n",
+ regs->portnum,
+ REG_FIELD(regs, regnum), REG_FIELD(regs, subreg),
+ REG_FIELD(regs, data_low), datah_str);
+ } else {
+ len += sprintf(buf + len, "#CH\tOP\tReg.\tDL%s\n",
+ (do_datah) ? "\tDH" : "");
+ len += sprintf(buf + len, "%2d\tRD\t%02X\t%02X%s\n",
+ regs->portnum,
+ REG_FIELD(regs, regnum),
+ REG_FIELD(regs, data_low), datah_str);
}
- return 0;
-failed_driver:
- device_unregister(&xpp_bus);
-failed_busdevice:
- bus_unregister(&xpp_bus_type);
-failed_bus:
- return ret;
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ return len;
}
-void unregister_xpp_bus(void)
+static DEVICE_ATTR_WRITER(chipregs_store, dev, buf, count)
{
- driver_unregister(&xpp_driver);
- device_unregister(&xpp_bus);
- bus_unregister(&xpp_bus_type);
+ xpd_t *xpd;
+ const char *p;
+ char tmp[MAX_PROC_WRITE];
+ int i;
+ int ret;
+
+ BUG_ON(!dev);
+ xpd = dev_to_xpd(dev);
+ //XPD_DBG(GENERAL, xpd, "%s\n", buf);
+ if(!xpd)
+ return -ENODEV;
+ p = buf;
+ while((p - buf) < count) {
+ i = strcspn(p, "\r\n");
+ if(i > 0) {
+ if(i >= MAX_PROC_WRITE) {
+ XPD_NOTICE(xpd, "Command too long (%d chars)\n", i);
+ return -E2BIG;
+ }
+ memcpy(tmp, p, i);
+ tmp[i] = '\0';
+ ret = parse_chip_command(xpd, tmp);
+ if(ret < 0) {
+ XPD_NOTICE(xpd, "Failed writing command: '%s'\n", tmp);
+ return ret;
+ }
+ }
+ p += i + 1;
+ }
+ return count;
}
-/*--------- Sysfs Device handling ----*/
-static DEVICE_ATTR_READER(connector_show, dev, buf)
+static DEVICE_ATTR_READER(blink_show, dev, buf)
{
- xbus_t *xbus;
- int ret;
+ xpd_t *xpd;
+ unsigned long flags;
+ int len = 0;
- xbus = dev_to_xbus(dev);
- ret = snprintf(buf, PAGE_SIZE, "%s\n", xbus->location);
- return ret;
+ BUG_ON(!dev);
+ xpd = dev_to_xpd(dev);
+ if(!xpd)
+ return -ENODEV;
+ spin_lock_irqsave(&xpd->lock, flags);
+ len += sprintf(buf, "0x%lX\n", xpd->blink_mode);
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ return len;
}
-static DEVICE_ATTR_READER(label_show, dev, buf)
+static DEVICE_ATTR_WRITER(blink_store, dev, buf, count)
{
- xbus_t *xbus;
- int ret;
+ xpd_t *xpd;
+ char *endp;
+ unsigned long blink;
- xbus = dev_to_xbus(dev);
- ret = snprintf(buf, PAGE_SIZE, "%s\n", xbus->label);
- return ret;
+ BUG_ON(!dev);
+ xpd = dev_to_xpd(dev);
+ //XPD_DBG(GENERAL, xpd, "%s\n", buf);
+ if(!xpd)
+ return -ENODEV;
+ blink = simple_strtoul(buf, &endp, 0);
+ if(*endp != '\0' && *endp != '\n' && *endp != '\r')
+ return -EINVAL;
+ if(blink > 0xFFFF)
+ return -EINVAL;
+ XPD_DBG(GENERAL, xpd, "BLINK channels: 0x%lX\n", blink);
+ xpd->blink_mode = blink;
+ return count;
}
-static DEVICE_ATTR_READER(status_show, dev, buf)
+static DEVICE_ATTR_READER(span_show, dev, buf)
{
- xbus_t *xbus;
- int ret;
+ xpd_t *xpd;
+ unsigned long flags;
+ int len = 0;
- xbus = dev_to_xbus(dev);
- ret = snprintf(buf, PAGE_SIZE, "%s\n", (TRANSPORT_RUNNING(xbus))?"connected":"missing");
- return ret;
+ BUG_ON(!dev);
+ xpd = dev_to_xpd(dev);
+ if(!xpd)
+ return -ENODEV;
+ spin_lock_irqsave(&xpd->lock, flags);
+ len += sprintf(buf, "%d\n", SPAN_REGISTERED(xpd) ? xpd->span.spanno : 0);
+ spin_unlock_irqrestore(&xpd->lock, flags);
+ return len;
}
-static DEVICE_ATTR_READER(timing_show, dev, buf)
+static DEVICE_ATTR_WRITER(span_store, dev, buf, count)
{
- xbus_t *xbus;
- struct xpp_drift *driftinfo;
- int len = 0;
- struct timeval now;
+ xpd_t *xpd;
+ int dahdi_reg;
+ int ret;
- do_gettimeofday(&now);
- xbus = dev_to_xbus(dev);
- driftinfo = &xbus->drift;
- len += snprintf(buf + len, PAGE_SIZE - len, "DRIFT: %-3s", sync_mode_name(xbus->sync_mode));
- if(xbus->sync_mode == SYNC_MODE_PLL) {
- len += snprintf(buf + len, PAGE_SIZE - len,
- " %5d: jitter %4d median %4d calc_drift %3d lost (%4d,%4d) : ",
- xbus->ticker.cycle,
- driftinfo->jitter, driftinfo->median,
- driftinfo->calc_drift,
- driftinfo->lost_ticks, driftinfo->lost_tick_count);
- len += snprintf(buf + len, PAGE_SIZE - len,
- "DRIFT %3d %ld sec ago",
- xbus->sync_adjustment,
- (xbus->pll_updated_at == 0) ? 0 : now.tv_sec - xbus->pll_updated_at);
+ BUG_ON(!dev);
+ xpd = dev_to_xpd(dev);
+ if(!xpd)
+ return -ENODEV;
+ ret = sscanf(buf, "%d", &dahdi_reg);
+ if(ret != 1)
+ return -EINVAL;
+ if(!XBUS_IS(xpd->xbus, READY))
+ return -ENODEV;
+ XPD_DBG(GENERAL, xpd, "%s\n", (dahdi_reg) ? "register" : "unregister");
+ if(dahdi_reg)
+ ret = dahdi_register_xpd(xpd);
+ else
+ ret = dahdi_unregister_xpd(xpd);
+ return (ret < 0) ? ret : count;
+}
+
+static int xpd_match(struct device *dev, struct device_driver *driver)
+{
+ struct xpd_driver *xpd_driver;
+ xpd_t *xpd;
+
+ xpd_driver = driver_to_xpd_driver(driver);
+ xpd = dev_to_xpd(dev);
+ if(xpd_driver->type != xpd->type) {
+ XPD_DBG(DEVICES, xpd, "SYSFS match fail: xpd->type = %d, xpd_driver->type = %d\n",
+ xpd->type, xpd_driver->type);
+ return 0;
}
- len += snprintf(buf + len, PAGE_SIZE - len, "\n");
- return len;
+ XPD_DBG(DEVICES, xpd, "SYSFS MATCH: type=%d dev->bus_id = %s, driver->name = %s\n",
+ xpd->type, dev->bus_id, driver->name);
+ return 1;
}
-#ifdef SAMPLE_TICKS
-/*
- * tick sampling: Measure offset from reference ticker:
- * - Recording start when writing to:
- * /sys/bus/astribanks/devices/xbus-??/samples
- * - Recording ends when filling SAMPLE_SIZE ticks
- * - Results are read from the same sysfs file.
- * - Trying to read/write during recording, returns -EBUSY.
- */
-static DEVICE_ATTR_READER(samples_show, dev, buf)
+struct device_attribute xpd_dev_attrs[] = {
+ __ATTR(chipregs, S_IRUGO | S_IWUSR, chipregs_show, chipregs_store),
+ __ATTR(blink, S_IRUGO | S_IWUSR, blink_show, blink_store),
+ __ATTR(span, S_IRUGO | S_IWUSR, span_show, span_store),
+ __ATTR_NULL,
+};
+
+static struct bus_type xpd_type = {
+ .name = "xpds",
+ .match = xpd_match,
+ .dev_attrs = xpd_dev_attrs,
+};
+
+int xpd_driver_register(struct device_driver *driver)
{
- xbus_t *xbus;
- int len = 0;
- int i;
+ int ret;
- xbus = dev_to_xbus(dev);
- if(xbus->sample_running)
- return -EBUSY;
- for(i = 0; i < SAMPLE_SIZE; i++) {
- if(len > PAGE_SIZE - 20)
- break;
- len += snprintf(buf + len, PAGE_SIZE - len, "%d\n", xbus->sample_ticks[i]);
+ DBG(DEVICES, "%s\n", driver->name);
+ driver->bus = &xpd_type;
+ if((ret = driver_register(driver)) < 0) {
+ ERR("%s: driver_register(%s) failed. Error number %d",
+ __FUNCTION__, driver->name, ret);
}
- return len;
+ return ret;
}
-static DEVICE_ATTR_WRITER(samples_store, dev, buf, count)
+void xpd_driver_unregister(struct device_driver *driver)
{
- xbus_t *xbus;
+ DBG(DEVICES, "%s\n", driver->name);
+ driver_unregister(driver);
+}
- xbus = dev_to_xbus(dev);
- if(xbus->sample_running)
- return -EBUSY;
- memset(xbus->sample_ticks, 0, sizeof(*xbus->sample_ticks));
- xbus->sample_pos = 0;
- xbus->sample_running = 1;
- return count;
+static void xpd_release(struct device *dev)
+{
+ xpd_t *xpd;
+
+ BUG_ON(!dev);
+ xpd = dev_to_xpd(dev);
+ XPD_DBG(DEVICES, xpd, "SYSFS\n");
+ xpd_remove(xpd);
}
-#endif
-/*
- * Clear statistics
- */
-static DEVICE_ATTR_WRITER(cls_store, dev, buf, count)
+int xpd_device_register(xbus_t *xbus, xpd_t *xpd)
{
- xbus_t *xbus;
- struct xpp_drift *driftinfo;
+ struct device *dev = &xpd->xpd_dev;
+ int ret;
+
+ XPD_DBG(DEVICES, xpd, "SYSFS\n");
+ dev->bus = &xpd_type;
+ dev->parent = &xbus->astribank;
+ snprintf(dev->bus_id, BUS_ID_SIZE, "%02d:%1x:%1x",
+ xbus->num, xpd->addr.unit, xpd->addr.subunit);
+ dev->driver_data = xpd;
+ dev->release = xpd_release;
+ ret = device_register(dev);
+ if(ret) {
+ XPD_ERR(xpd, "%s: device_register failed: %d\n", __FUNCTION__, ret);
+ return ret;
+ }
+ get_xpd(__FUNCTION__, xpd);
+ BUG_ON(!xpd);
+ return 0;
+}
- xbus = dev_to_xbus(dev);
- driftinfo = &xbus->drift;
- driftinfo->lost_ticks = 0;
- driftinfo->lost_tick_count = 0;
- xbus->min_tx_sync = INT_MAX;
- xbus->max_tx_sync = 0;
- xbus->min_rx_sync = INT_MAX;
- xbus->max_rx_sync = 0;
-#ifdef SAMPLE_TICKS
- memset(xbus->sample_ticks, 0, sizeof(*xbus->sample_ticks));
-#endif
- return count;
+void xpd_device_unregister(xpd_t *xpd)
+{
+ xbus_t *xbus;
+ struct device *dev;
+
+ xbus = xpd->xbus;
+ BUG_ON(!xbus);
+ XPD_DBG(DEVICES, xpd, "SYSFS\n");
+ dev = &xpd->xpd_dev;
+ if(!dev->driver_data)
+ return;
+ BUG_ON(dev->driver_data != xpd);
+ device_unregister(dev);
+ dev->driver_data = NULL;
}
-static DEVICE_ATTR(connector, S_IRUGO, connector_show, NULL);
-static DEVICE_ATTR(label, S_IRUGO, label_show, NULL);
-static DEVICE_ATTR(status, S_IRUGO, status_show, NULL);
-static DEVICE_ATTR(timing, S_IRUGO, timing_show, NULL);
-static DEVICE_ATTR(cls, S_IWUSR, NULL, cls_store);
-#ifdef SAMPLE_TICKS
-static DEVICE_ATTR(samples, S_IWUSR | S_IRUGO, samples_show, samples_store);
-#endif
+/*--------- Sysfs Device handling ----*/
void xbus_sysfs_remove(xbus_t *xbus)
{
struct device *astribank;
BUG_ON(!xbus);
- XBUS_DBG(GENERAL, xbus, "\n");
+ XBUS_DBG(DEVICES, xbus, "\n");
astribank = &xbus->astribank;
BUG_ON(!astribank);
if(!astribank->driver_data)
return;
BUG_ON(astribank->driver_data != xbus);
-#ifdef SAMPLE_TICKS
- device_remove_file(&xbus->astribank, &dev_attr_samples);
-#endif
- device_remove_file(&xbus->astribank, &dev_attr_cls);
- device_remove_file(&xbus->astribank, &dev_attr_timing);
- device_remove_file(&xbus->astribank, &dev_attr_status);
- device_remove_file(&xbus->astribank, &dev_attr_label);
- device_remove_file(&xbus->astribank, &dev_attr_connector);
device_unregister(&xbus->astribank);
}
@@ -377,51 +657,64 @@ int xbus_sysfs_create(xbus_t *xbus)
BUG_ON(!xbus);
astribank = &xbus->astribank;
BUG_ON(!astribank);
- XBUS_DBG(GENERAL, xbus, "\n");
- device_initialize(astribank);
- astribank->bus = &xpp_bus_type;
- astribank->parent = &xpp_bus;
+ XBUS_DBG(DEVICES, xbus, "\n");
+ astribank->bus = &toplevel_bus_type;
+ astribank->parent = &toplevel_device;
snprintf(astribank->bus_id, BUS_ID_SIZE, "xbus-%02d", xbus->num);
- astribank->driver_data = NULL; /* override below */
- astribank->release = xpp_dev_release;
+ astribank->driver_data = xbus;
+ astribank->release = astribank_release;
ret = device_register(astribank);
if(ret) {
- XBUS_ERR(xbus, "%s: device_add failed: %d\n", __FUNCTION__, ret);
- goto out;
- }
- ret = device_create_file(astribank, &dev_attr_connector);
- if(ret) {
- XBUS_ERR(xbus, "%s: device_create_file failed: %d\n", __FUNCTION__, ret);
- goto out;
- }
- ret = device_create_file(astribank, &dev_attr_label);
- if(ret) {
- XBUS_ERR(xbus, "%s: device_create_file failed: %d\n", __FUNCTION__, ret);
- goto out;
+ XBUS_ERR(xbus, "%s: device_register failed: %d\n", __FUNCTION__, ret);
+ astribank->driver_data = NULL;
}
- ret = device_create_file(astribank, &dev_attr_status);
- if(ret) {
- XBUS_ERR(xbus, "%s: device_create_file failed: %d\n", __FUNCTION__, ret);
- goto out;
+ return ret;
+}
+
+int __init xpp_driver_init(void)
+{
+ int ret;
+
+ DBG(DEVICES, "SYSFS\n");
+ if((ret = bus_register(&toplevel_bus_type)) < 0) {
+ ERR("%s: bus_register(%s) failed. Error number %d",
+ __FUNCTION__, toplevel_bus_type.name, ret);
+ goto failed_bus;
}
- ret = device_create_file(astribank, &dev_attr_timing);
- if(ret) {
- XBUS_ERR(xbus, "%s: device_create_file failed: %d\n", __FUNCTION__, ret);
- goto out;
+ if((ret = device_register(&toplevel_device)) < 0) {
+ ERR("%s: device_register(%s) failed. Error number %d",
+ __FUNCTION__, toplevel_device.bus_id, ret);
+ goto failed_busdevice;
}
- ret = device_create_file(astribank, &dev_attr_cls);
- if(ret) {
- XBUS_ERR(xbus, "%s: device_create_file failed: %d\n", __FUNCTION__, ret);
- goto out;
+ if((ret = driver_register(&xpp_driver)) < 0) {
+ ERR("%s: driver_register(%s) failed. Error number %d",
+ __FUNCTION__, xpp_driver.name, ret);
+ goto failed_xpp_driver;
}
-#ifdef SAMPLE_TICKS
- ret = device_create_file(astribank, &dev_attr_samples);
- if(ret) {
- XBUS_ERR(xbus, "%s: device_create_file failed: %d\n", __FUNCTION__, ret);
- goto out;
+ if((ret = bus_register(&xpd_type)) < 0) {
+ ERR("%s: bus_register(%s) failed. Error number %d",
+ __FUNCTION__, xpd_type.name, ret);
+ goto failed_xpd_bus;
}
-#endif
- astribank->driver_data = xbus; /* Everything is good */
-out:
+ return 0;
+failed_xpd_bus:
+ driver_unregister(&xpp_driver);
+failed_xpp_driver:
+ device_unregister(&toplevel_device);
+failed_busdevice:
+ bus_unregister(&toplevel_bus_type);
+failed_bus:
return ret;
}
+
+void xpp_driver_exit(void)
+{
+ DBG(DEVICES, "SYSFS\n");
+ bus_unregister(&xpd_type);
+ driver_unregister(&xpp_driver);
+ device_unregister(&toplevel_device);
+ bus_unregister(&toplevel_bus_type);
+}
+
+EXPORT_SYMBOL(xpd_driver_register);
+EXPORT_SYMBOL(xpd_driver_unregister);
diff --git a/drivers/dahdi/xpp/xdefs.h b/drivers/dahdi/xpp/xdefs.h
index 41d9e5d..5763679 100644
--- a/drivers/dahdi/xpp/xdefs.h
+++ b/drivers/dahdi/xpp/xdefs.h
@@ -113,6 +113,18 @@ typedef unsigned char byte;
kfree(p); \
} while(0);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,14)
+#define DEVICE_ATTR_READER(name,dev,buf) \
+ ssize_t name(struct device *dev, struct device_attribute *attr, char *buf)
+#define DEVICE_ATTR_WRITER(name,dev,buf, count) \
+ ssize_t name(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+#else
+#define DEVICE_ATTR_READER(name,dev,buf) \
+ ssize_t name(struct device *dev, char *buf)
+#define DEVICE_ATTR_WRITER(name,dev,buf, count) \
+ ssize_t name(struct device *dev, const char *buf, size_t count)
+#endif
+
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
/* Also don't define this for later RHEL >= 5.2 . hex_asc is from the
* same linux-2.6-net-infrastructure-updates-to-mac80211-iwl4965.patch
diff --git a/drivers/dahdi/xpp/xframe_queue.c b/drivers/dahdi/xpp/xframe_queue.c
index 033be8b..915c5af 100644
--- a/drivers/dahdi/xpp/xframe_queue.c
+++ b/drivers/dahdi/xpp/xframe_queue.c
@@ -29,6 +29,10 @@ static bool __xframe_enqueue(struct xframe_queue *q, xframe_t *xframe)
{
int ret = 1;
+ if(unlikely(q->disabled)) {
+ ret = 0;
+ goto out;
+ }
if(q->count >= q->max_count) {
q->overflows++;
NOTICE("Overflow of %-15s: counts %3d, %3d, %3d worst %3d, overflows %3d worst_lag %02ld.%ld ms\n",
@@ -95,9 +99,9 @@ xframe_t *xframe_dequeue(struct xframe_queue *q)
spin_unlock_irqrestore(&q->lock, flags);
return frm;
}
-void xframe_queue_disable(struct xframe_queue *q)
+void xframe_queue_disable(struct xframe_queue *q, bool disabled)
{
- q->max_count = 0;
+ q->disabled = disabled;
}
void xframe_queue_clear(struct xframe_queue *q)
@@ -106,7 +110,7 @@ void xframe_queue_clear(struct xframe_queue *q)
xbus_t *xbus = q->priv;
int i = 0;
- xframe_queue_disable(q);
+ xframe_queue_disable(q, 1);
while((xframe = xframe_dequeue(q)) != NULL) {
transport_free_xframe(xbus, xframe);
i++;
diff --git a/drivers/dahdi/xpp/xframe_queue.h b/drivers/dahdi/xpp/xframe_queue.h
index 5612d65..eba94dd 100644
--- a/drivers/dahdi/xpp/xframe_queue.h
+++ b/drivers/dahdi/xpp/xframe_queue.h
@@ -9,6 +9,7 @@
struct xframe_queue {
struct list_head head;
+ bool disabled;
unsigned int count;
unsigned int max_count;
unsigned int steady_state_count;
@@ -27,7 +28,7 @@ void xframe_queue_init(struct xframe_queue *q,
__must_check bool xframe_enqueue(struct xframe_queue *q, xframe_t *xframe);
__must_check xframe_t *xframe_dequeue(struct xframe_queue *q);
void xframe_queue_clearstats(struct xframe_queue *q);
-void xframe_queue_disable(struct xframe_queue *q);
+void xframe_queue_disable(struct xframe_queue *q, bool disabled);
void xframe_queue_clear(struct xframe_queue *q);
uint xframe_queue_count(struct xframe_queue *q);
diff --git a/drivers/dahdi/xpp/xpd.h b/drivers/dahdi/xpp/xpd.h
index 2e89adb..2e0363a 100644
--- a/drivers/dahdi/xpp/xpd.h
+++ b/drivers/dahdi/xpp/xpd.h
@@ -139,6 +139,16 @@ static struct xpd_counters {
#define XPD_COUNTER_MAX (sizeof(xpd_counters)/sizeof(xpd_counters[0]))
+enum xpd_state {
+ XPD_STATE_START,
+ XPD_STATE_INIT_REGS,
+ XPD_STATE_READY,
+ XPD_STATE_NOHW,
+};
+
+bool xpd_setstate(xpd_t *xpd, enum xpd_state newstate);
+const char *xpd_statename(enum xpd_state st);
+
/*
* An XPD is a single Xorcom Protocol Device
*/
@@ -161,6 +171,10 @@ struct xpd {
xpp_line_t digital_signalling; /* BRI signalling channels */
uint timing_priority; /* from 'span' directives in chan_dahdi.conf */
+ enum xpd_state xpd_state;
+ struct device xpd_dev;
+#define dev_to_xpd(dev) container_of(dev, struct xpd, xpd_dev)
+
/* maintained by card drivers */
uint pcm_len; /* allocation length of PCM packet (dynamic) */
xpp_line_t wanted_pcm_mask;
@@ -173,7 +187,7 @@ struct xpd {
spinlock_t lock;
atomic_t dahdi_registered; /* Am I fully registered with dahdi */
- atomic_t open_counter; /* Number of open channels */
+ atomic_t open_counter; /* open channels */
int flags;
unsigned long blink_mode; /* bitmask of blinking ports */
@@ -182,10 +196,12 @@ struct xpd {
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *proc_xpd_dir;
struct proc_dir_entry *proc_xpd_summary;
+#ifdef OLD_PROC
struct proc_dir_entry *proc_xpd_ztregister;
struct proc_dir_entry *proc_xpd_blink;
struct proc_dir_entry *proc_xpd_chipregs;
#endif
+#endif
int counters[XPD_COUNTER_MAX];
@@ -226,6 +242,18 @@ static inline void *my_kzalloc(size_t size, gfp_t flags)
return p;
}
+struct xpd_driver {
+ xpd_type_t type;
+
+ struct device_driver driver;
+#define driver_to_xpd_driver(driver) container_of(driver, struct xpd_driver, driver)
+};
+
+int xpd_driver_register(struct device_driver *driver);
+void xpd_driver_unregister(struct device_driver *driver);
+xpd_t *get_xpd(const char *msg, xpd_t *xpd);
+void put_xpd(const char *msg, xpd_t *xpd);
+
#endif
#endif /* XPD_H */
diff --git a/drivers/dahdi/xpp/xpp.rules b/drivers/dahdi/xpp/xpp.rules
index 907e08a..874bed2 100644
--- a/drivers/dahdi/xpp/xpp.rules
+++ b/drivers/dahdi/xpp/xpp.rules
@@ -9,6 +9,8 @@ SYSFS{idVendor}=="e4e4", SYSFS{idProduct}=="11[345][01]", \
LABEL="xpp_usb_add_end"
# Hotplug hook for Astribank up/down
+# If you need this functionality, copy the astribank_hook.sample
+# to $XPP_INIT_DIR/astribank_hook
+#
# By default XPP_INIT_DIR="/usr/share/dahdi"
-KERNEL=="xbus*" RUN+="%E{XPP_INIT_DIR}/astribank_hook udev $kernel $sysfs{status} $sysfs{connector}"
-
+#KERNEL=="xbus*" RUN+="%E{XPP_INIT_DIR}/astribank_hook udev $kernel $sysfs{status} $sysfs{connector}"
diff --git a/drivers/dahdi/xpp/xpp_dahdi.c b/drivers/dahdi/xpp/xpp_dahdi.c
index ea4b61b..f778f48 100644
--- a/drivers/dahdi/xpp/xpp_dahdi.c
+++ b/drivers/dahdi/xpp/xpp_dahdi.c
@@ -49,8 +49,10 @@ static const char rcsid[] = "$Id$";
#ifdef CONFIG_PROC_FS
struct proc_dir_entry *xpp_proc_toplevel = NULL;
#define PROC_DIR "xpp"
+#ifdef OLD_PROC
#define PROC_XPD_ZTREGISTER "dahdi_registration"
#define PROC_XPD_BLINK "blink"
+#endif
#define PROC_XPD_SUMMARY "summary"
#endif
@@ -107,26 +109,53 @@ int total_registered_spans(void)
return atomic_read(&num_registered_spans);
}
-static int dahdi_register_xpd(xpd_t *xpd);
-static int dahdi_unregister_xpd(xpd_t *xpd);
static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data);
+#ifdef OLD_PROC
static int proc_xpd_ztregister_read(char *page, char **start, off_t off, int count, int *eof, void *data);
static int proc_xpd_ztregister_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
static int proc_xpd_blink_read(char *page, char **start, off_t off, int count, int *eof, void *data);
static int proc_xpd_blink_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
+#endif
/*------------------------- XPD Management -------------------------*/
+atomic_t *refcount_xpd(xpd_t *xpd)
+{
+ struct kref *kref = &xpd->xpd_dev.kobj.kref;
+
+ return &kref->refcount;
+}
+
+xpd_t *get_xpd(const char *msg, xpd_t *xpd)
+{
+ struct device *dev;
+
+ XPD_DBG(DEVICES, xpd, "%s: refcount_xpd=%d\n",
+ msg, atomic_read(refcount_xpd(xpd)));
+ dev = get_device(&xpd->xpd_dev);
+ return dev_to_xpd(dev);
+}
+
+void put_xpd(const char *msg, xpd_t *xpd)
+{
+ XPD_DBG(DEVICES, xpd, "%s: refcount_xpd=%d\n",
+ msg, atomic_read(refcount_xpd(xpd)));
+ put_device(&xpd->xpd_dev);
+}
+
static void xpd_proc_remove(xbus_t *xbus, xpd_t *xpd)
{
#ifdef CONFIG_PROC_FS
if(xpd->proc_xpd_dir) {
+#ifdef OLD_PROC
chip_proc_remove(xbus, xpd);
+#endif
if(xpd->proc_xpd_summary) {
XPD_DBG(PROC, xpd, "Removing proc '%s'\n", PROC_XPD_SUMMARY);
remove_proc_entry(PROC_XPD_SUMMARY, xpd->proc_xpd_dir);
xpd->proc_xpd_summary = NULL;
}
+#ifdef OLD_PROC
if(xpd->proc_xpd_ztregister) {
XPD_DBG(PROC, xpd, "Removing proc '%s'\n", PROC_XPD_ZTREGISTER);
remove_proc_entry(PROC_XPD_ZTREGISTER, xpd->proc_xpd_dir);
@@ -137,6 +166,7 @@ static void xpd_proc_remove(xbus_t *xbus, xpd_t *xpd)
remove_proc_entry(PROC_XPD_BLINK, xpd->proc_xpd_dir);
xpd->proc_xpd_blink = NULL;
}
+#endif
XPD_DBG(PROC, xpd, "Removing %s/%s proc directory\n",
xbus->busname, xpd->xpdname);
remove_proc_entry(xpd->xpdname, xbus->proc_xbus_dir);
@@ -161,6 +191,7 @@ static int xpd_proc_create(xbus_t *xbus, xpd_t *xpd)
goto err;
}
xpd->proc_xpd_summary->owner = THIS_MODULE;
+#ifdef OLD_PROC
xpd->proc_xpd_ztregister = create_proc_entry(PROC_XPD_ZTREGISTER, 0644, xpd->proc_xpd_dir);
if (!xpd->proc_xpd_ztregister) {
XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_XPD_ZTREGISTER);
@@ -182,6 +213,7 @@ static int xpd_proc_create(xbus_t *xbus, xpd_t *xpd)
if(chip_proc_create(xbus, xpd) < 0)
goto err;
#endif
+#endif
return 0;
err:
xpd_proc_remove(xbus, xpd);
@@ -203,45 +235,19 @@ void xpd_free(xpd_t *xpd)
return;
XPD_DBG(DEVICES, xpd, "\n");
xpd_proc_remove(xbus, xpd);
- xbus_unregister_xpd(xbus, xpd);
+ xbus_xpd_unbind(xbus, xpd);
for (x = 0; x < xpd->channels; x++) {
- if (xpd->chans[x]) {
- kfree(xpd->chans[x]);
- }
+ if (xpd->chans[x])
+ KZFREE(xpd->chans[x]);
}
KZFREE(xpd);
-}
-
-
-__must_check int xpd_common_init(xbus_t *xbus, xpd_t *xpd, int unit, int subunit, int subtype, int subunits)
-{
- int ret;
-
- MKADDR(&xpd->addr, unit, subunit);
- xpd->xbus_idx = XPD_IDX(unit,subunit);
- snprintf(xpd->xpdname, XPD_NAMELEN, "XPD-%1d%1d", unit, subunit);
- xpd->subtype = subtype;
- xpd->subunits = subunits;
- xpd->offhook = 0;
-
- /* For USB-1 disable some channels */
- if(MAX_SEND_SIZE(xbus) < RPACKET_SIZE(GLOBAL, PCM_WRITE)) {
- xpp_line_t no_pcm;
-
- no_pcm = 0x7F | xpd->digital_outputs | xpd->digital_inputs;
- xpd->no_pcm = no_pcm;
- XBUS_NOTICE(xbus, "max xframe size = %d, disabling some PCM channels. no_pcm=0x%04X\n",
- MAX_SEND_SIZE(xbus), xpd->no_pcm);
- }
- if((ret = xpd_proc_create(xbus, xpd)) < 0)
- return ret;
- xbus_register_xpd(xbus, xpd);
- return 0;
+ DBG(DEVICES, "refcount_xbus=%d\n", refcount_xbus(xbus));
+ put_xbus(__FUNCTION__, xbus); /* was taken in xpd_alloc() */
}
/*
* Synchronous part of XPD detection.
- * Called from xbus_poll()
+ * Called from new_card()
*/
int create_xpd(xbus_t *xbus, const xproto_table_t *proto_table,
int unit,
@@ -253,7 +259,6 @@ int create_xpd(xbus_t *xbus, const xproto_table_t *proto_table,
{
xpd_t *xpd = NULL;
bool to_phone;
- int ret = -EINVAL;
BUG_ON(type == XPD_TYPE_NOMODULE);
to_phone = BIT(subunit) & port_dir;
@@ -262,20 +267,15 @@ int create_xpd(xbus_t *xbus, const xproto_table_t *proto_table,
if(xpd) {
XPD_NOTICE(xpd, "XPD at %d%d already exists\n",
unit, subunit);
- goto out;
+ return 0;
}
xpd = proto_table->xops.card_new(xbus, unit, subunit, proto_table, subtype, subunits, to_phone);
if(!xpd) {
XBUS_NOTICE(xbus, "card_new(%d,%d,%d,%d,%d) failed. Ignored.\n",
unit, subunit, proto_table->type, subtype, to_phone);
- goto err;
+ return -EINVAL;
}
-out:
return 0;
-err:
- if(xpd)
- xpd_free(xpd);
- return ret;
}
void xpd_post_init(xpd_t *xpd)
@@ -317,6 +317,10 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eo
xpd->timing_priority,
xpd->timer_count, xpd->span.mainttimer
);
+ len += sprintf(page + len, "xpd_state: %s (%d)\n",
+ xpd_statename(xpd->xpd_state), xpd->xpd_state);
+ len += sprintf(page + len, "open_counter=%d refcount=%d\n",
+ atomic_read(&xpd->open_counter), atomic_read(refcount_xpd(xpd)));
len += sprintf(page + len, "Address: U=%d S=%d\n", xpd->addr.unit, xpd->addr.subunit);
len += sprintf(page + len, "Subunits: %d\n", xpd->subunits);
len += sprintf(page + len, "Type: %d.%d\n\n", xpd->type, xpd->subtype);
@@ -418,11 +422,70 @@ out:
#endif
+const char *xpd_statename(enum xpd_state st)
+{
+ switch(st) {
+ case XPD_STATE_START: return "START";
+ case XPD_STATE_INIT_REGS: return "INIT_REGS";
+ case XPD_STATE_READY: return "READY";
+ case XPD_STATE_NOHW: return "NOHW";
+ }
+ return NULL;
+}
+
+bool xpd_setstate(xpd_t *xpd, enum xpd_state newstate)
+{
+ BUG_ON(!xpd);
+ XPD_DBG(DEVICES, xpd, "%s: %s (%d) -> %s (%d)\n", __FUNCTION__,
+ xpd_statename(xpd->xpd_state), xpd->xpd_state,
+ xpd_statename(newstate), newstate);
+ switch(newstate) {
+ case XPD_STATE_START:
+ goto badstate;
+ case XPD_STATE_INIT_REGS:
+ if(xpd->xpd_state != XPD_STATE_START)
+ goto badstate;
+ if(xpd->addr.subunit != 0) {
+ XPD_NOTICE(xpd,
+ "%s: Moving to %s allowed only for subunit 0\n",
+ __FUNCTION__, xpd_statename(newstate));
+ goto badstate;
+ }
+ break;
+ case XPD_STATE_READY:
+ if(xpd->addr.subunit == 0) {
+ /* Unit 0 script initialize registers of all subunits */
+ if(xpd->xpd_state != XPD_STATE_INIT_REGS)
+ goto badstate;
+ } else {
+ if(xpd->xpd_state != XPD_STATE_START)
+ goto badstate;
+ }
+ break;
+ case XPD_STATE_NOHW:
+ break;
+ default:
+ XPD_ERR(xpd, "%s: Unknown newstate=%d\n", __FUNCTION__, newstate);
+ }
+ xpd->xpd_state = newstate;
+ return 1;
+badstate:
+ XPD_NOTICE(xpd, "%s: cannot transition: %s (%d) -> %s (%d)\n",
+ __FUNCTION__,
+ xpd_statename(xpd->xpd_state), xpd->xpd_state,
+ xpd_statename(newstate), newstate);
+ return 0;
+}
+
+
/*
* xpd_alloc - Allocator for new XPD's
*
*/
-xpd_t *xpd_alloc(size_t privsize, const xproto_table_t *proto_table, int channels)
+__must_check xpd_t *xpd_alloc(xbus_t *xbus,
+ int unit, int subunit,
+ int subtype, int subunits,
+ size_t privsize, const xproto_table_t *proto_table, int channels)
{
xpd_t *xpd = NULL;
size_t alloc_size = sizeof(xpd_t) + privsize;
@@ -430,22 +493,21 @@ xpd_t *xpd_alloc(size_t privsize, const xproto_table_t *proto_table, int channel
unsigned int x;
BUG_ON(!proto_table);
- DBG(DEVICES, "type=%d channels=%d (alloc_size=%zd)\n",
+ XBUS_DBG(DEVICES, xbus, "type=%d channels=%d (alloc_size=%zd)\n",
type, channels, alloc_size);
if(channels > CHANNELS_PERXPD) {
- ERR("%s: type=%d: too many channels %d\n",
+ XBUS_ERR(xbus, "%s: type=%d: too many channels %d\n",
__FUNCTION__, type, channels);
goto err;
}
if((xpd = KZALLOC(alloc_size, GFP_KERNEL)) == NULL) {
- ERR("%s: type=%d: Unable to allocate memory\n",
+ XBUS_ERR(xbus, "%s: type=%d: Unable to allocate memory\n",
__FUNCTION__, type);
goto err;
}
xpd->priv = (byte *)xpd + sizeof(xpd_t);
spin_lock_init(&xpd->lock);
- xpd->xbus_idx = -1;
xpd->channels = channels;
xpd->card_present = 0;
xpd->offhook = 0x0; /* ONHOOK */
@@ -454,21 +516,37 @@ xpd_t *xpd_alloc(size_t privsize, const xproto_table_t *proto_table, int channel
xpd->xops = &proto_table->xops;
xpd->digital_outputs = 0;
xpd->digital_inputs = 0;
+ xpd->xpd_state = XPD_STATE_START;
+ xpd->subtype = subtype;
+ xpd->subunits = subunits;
atomic_set(&xpd->dahdi_registered, 0);
atomic_set(&xpd->open_counter, 0);
+ /* For USB-1 disable some channels */
+ if(MAX_SEND_SIZE(xbus) < RPACKET_SIZE(GLOBAL, PCM_WRITE)) {
+ xpp_line_t no_pcm;
+
+ no_pcm = 0x7F | xpd->digital_outputs | xpd->digital_inputs;
+ xpd->no_pcm = no_pcm;
+ XBUS_NOTICE(xbus, "max xframe size = %d, disabling some PCM channels. no_pcm=0x%04X\n",
+ MAX_SEND_SIZE(xbus), xpd->no_pcm);
+ }
for (x = 0; x < xpd->channels; x++) {
if (!(xpd->chans[x] = kmalloc(sizeof(*xpd->chans[x]), GFP_KERNEL))) {
ERR("%s: Unable to allocate channel %d\n", __FUNCTION__, x);
goto err;
}
}
-
- xproto_get(type); /* will be returned in xpd_free() */
+ xbus_xpd_bind(xbus, xpd, unit, subunit);
+ if(xpd_proc_create(xbus, xpd) < 0)
+ goto err;
+ xbus = get_xbus(__FUNCTION__, xbus); /* returned in xpd_free() */
+ xproto_get(type); /* will be returned in xpd_free() */
return xpd;
err:
if(xpd) {
+ xpd_proc_remove(xbus, xpd);
for (x = 0; x < xpd->channels; x++) {
if (xpd->chans[x]) {
kfree(xpd->chans[x]);
@@ -479,30 +557,33 @@ err:
return NULL;
}
-void xpd_disconnect(xpd_t *xpd)
+void xpd_unreg_request(xpd_t *xpd)
{
unsigned long flags;
BUG_ON(!xpd);
+ XPD_DBG(DEVICES, xpd, "\n");
spin_lock_irqsave(&xpd->lock, flags);
- XPD_DBG(DEVICES, xpd, "(%p)\n", xpd->xproto);
- if(!xpd->card_present) /* Multiple reports */
- goto out;
xpd->card_present = 0;
+ xpd_setstate(xpd, XPD_STATE_NOHW);
if(SPAN_REGISTERED(xpd)) {
int i;
update_xpd_status(xpd, DAHDI_ALARM_NOTOPEN);
/* TODO: Should this be done before releasing the spinlock? */
- XPD_DBG(DEVICES, xpd, "Queuing DAHDI_EVENT_REMOVED on all channels to ask user to release them\n");
- for (i=0; i<xpd->span.channels; i++)
+ XPD_DBG(DEVICES, xpd, "Queuing DAHDI_EVENT_REMOVED on all channels to ask user to close them\n");
+ for (i=0; i<xpd->span.channels; i++) {
dahdi_qevent_lock(xpd->chans[i],DAHDI_EVENT_REMOVED);
+ }
}
-out:
spin_unlock_irqrestore(&xpd->lock, flags);
+ xpd_device_unregister(xpd);
}
+/*
+ * The xpd isn't open by anyone, we can unregister it and free it
+ */
void xpd_remove(xpd_t *xpd)
{
xbus_t *xbus;
@@ -513,6 +594,9 @@ void xpd_remove(xpd_t *xpd)
dahdi_unregister_xpd(xpd);
CALL_XMETHOD(card_remove, xbus, xpd);
xpd_free(xpd);
+ if(atomic_dec_and_test(&xbus->xbus_ref_count)) {
+ XBUS_DBG(DEVICES, xbus, "%s: Last ref to xbus. Removing\n", __FUNCTION__);
+ }
}
void update_xpd_status(xpd_t *xpd, int alarm_flag)
@@ -570,6 +654,7 @@ void update_line_status(xpd_t *xpd, int pos, bool to_offhook)
}
#ifdef CONFIG_PROC_FS
+#ifdef OLD_PROC
static int proc_xpd_ztregister_read(char *page, char **start, off_t off, int count, int *eof, void *data)
{
int len = 0;
@@ -577,8 +662,9 @@ static int proc_xpd_ztregister_read(char *page, char **start, off_t off, int cou
xpd_t *xpd = data;
BUG_ON(!xpd);
+ XPD_NOTICE(xpd, "%s: DEPRECATED: %s[%d] read from /proc interface instead of /sys\n",
+ __FUNCTION__, current->comm, current->tgid);
spin_lock_irqsave(&xpd->lock, flags);
-
len += sprintf(page + len, "%d\n", SPAN_REGISTERED(xpd) ? xpd->span.spanno : 0);
spin_unlock_irqrestore(&xpd->lock, flags);
if (len <= off+count)
@@ -600,6 +686,8 @@ static int proc_xpd_ztregister_write(struct file *file, const char __user *buffe
int ret;
BUG_ON(!xpd);
+ XPD_NOTICE(xpd, "%s: DEPRECATED: %s[%d] wrote to /proc interface instead of /sys\n",
+ __FUNCTION__, current->comm, current->tgid);
if(count >= MAX_PROC_WRITE)
return -EINVAL;
if(copy_from_user(buf, buffer, count))
@@ -608,6 +696,8 @@ static int proc_xpd_ztregister_write(struct file *file, const char __user *buffe
ret = sscanf(buf, "%d", &dahdi_reg);
if(ret != 1)
return -EINVAL;
+ if(!XBUS_IS(xpd->xbus, READY))
+ return -ENODEV;
XPD_DBG(GENERAL, xpd, "%s\n", (dahdi_reg) ? "register" : "unregister");
if(dahdi_reg)
ret = dahdi_register_xpd(xpd);
@@ -623,8 +713,9 @@ static int proc_xpd_blink_read(char *page, char **start, off_t off, int count, i
xpd_t *xpd = data;
BUG_ON(!xpd);
+ XPD_NOTICE(xpd, "%s: DEPRECATED: %s[%d] read from /proc interface instead of /sys\n",
+ __FUNCTION__, current->comm, current->tgid);
spin_lock_irqsave(&xpd->lock, flags);
-
len += sprintf(page + len, "0x%lX\n", xpd->blink_mode);
spin_unlock_irqrestore(&xpd->lock, flags);
if (len <= off+count)
@@ -647,6 +738,8 @@ static int proc_xpd_blink_write(struct file *file, const char __user *buffer, un
BUG_ON(!xpd);
+ XPD_NOTICE(xpd, "%s: DEPRECATED: %s[%d] wrote to /proc interface instead of /sys\n",
+ __FUNCTION__, current->comm, current->tgid);
if(count >= MAX_PROC_WRITE)
return -EINVAL;
if(copy_from_user(buf, buffer, count))
@@ -661,6 +754,7 @@ static int proc_xpd_blink_write(struct file *file, const char __user *buffer, un
xpd->blink_mode = blink;
return count;
}
+#endif
#endif
@@ -692,25 +786,30 @@ int xpp_open(struct dahdi_chan *chan)
return -EINVAL;
}
xpd = chan->pvt;
+ xpd = get_xpd(__FUNCTION__, xpd); /* Returned in xpp_close() */
if (!xpd) {
NOTICE("open called on a chan with no pvt (xpd)\n");
- return -EINVAL;
+ BUG();
}
xbus = xpd->xbus;
if (!xbus) {
NOTICE("open called on a chan with no xbus\n");
- return -EINVAL;
+ BUG();
}
pos = chan->chanpos - 1;
+ if(!xpd->card_present) {
+ LINE_NOTICE(xpd, pos, "Cannot open -- device not ready\n");
+ put_xpd(__FUNCTION__, xpd);
+ return -ENODEV;
+ }
#endif
-
spin_lock_irqsave(&xbus->lock, flags);
- atomic_inc(&xbus->xbus_ref_count);
atomic_inc(&xpd->open_counter);
+ LINE_DBG(DEVICES, xpd, pos, "%s[%d]: open_counter=%d\n",
+ current->comm, current->pid,
+ atomic_read(&xpd->open_counter));
if(IS_SET(xpd->digital_signalling, pos)) /* D-chan offhook */
BIT_SET(xpd->offhook, pos);
- DBG(DEVICES, "chan=%d (xbus_ref_count=%d)\n",
- pos, atomic_read(&xbus->xbus_ref_count));
spin_unlock_irqrestore(&xbus->lock, flags);
if(xpd->xops->card_open)
xpd->xops->card_open(xpd, pos);
@@ -725,16 +824,16 @@ int xpp_close(struct dahdi_chan *chan)
unsigned long flags;
spin_lock_irqsave(&xbus->lock, flags);
- atomic_dec(&xpd->open_counter);
if(IS_SET(xpd->digital_signalling, pos)) /* D-chan onhook */
BIT_CLR(xpd->offhook, pos);
spin_unlock_irqrestore(&xbus->lock, flags);
if(xpd->xops->card_close)
xpd->xops->card_close(xpd, pos);
- XPD_DBG(GENERAL, xpd, "pid=%d: chan=%d (xbus_ref_count=%d)\n",
- current->pid, pos, atomic_read(&xbus->xbus_ref_count));
- if(atomic_dec_and_test(&xbus->xbus_ref_count))
- xbus_remove(xbus);
+ LINE_DBG(DEVICES, xpd, pos, "%s[%d]: open_counter=%d\n",
+ current->comm, current->pid,
+ atomic_read(&xpd->open_counter));
+ atomic_dec(&xpd->open_counter); /* from xpp_open() */
+ put_xpd(__FUNCTION__, xpd); /* from xpp_open() */
return 0;
}
@@ -861,7 +960,7 @@ static int xpp_watchdog(struct dahdi_span *span, int cause)
* - User action through /proc
* - During xpd_remove()
*/
-static int dahdi_unregister_xpd(xpd_t *xpd)
+int dahdi_unregister_xpd(xpd_t *xpd)
{
unsigned long flags;
@@ -874,6 +973,7 @@ static int dahdi_unregister_xpd(xpd_t *xpd)
return -EIDRM;
}
update_xpd_status(xpd, DAHDI_ALARM_NOTOPEN);
+ /* We should now have only a ref from the xbus (from create_xpd()) */
if(atomic_read(&xpd->open_counter)) {
XPD_NOTICE(xpd, "Busy (open_counter=%d). Skipping.\n", atomic_read(&xpd->open_counter));
spin_unlock_irqrestore(&xpd->lock, flags);
@@ -891,7 +991,7 @@ static int dahdi_unregister_xpd(xpd_t *xpd)
return 0;
}
-static int dahdi_register_xpd(xpd_t *xpd)
+int dahdi_register_xpd(xpd_t *xpd)
{
struct dahdi_span *span;
xbus_t *xbus;
@@ -953,7 +1053,7 @@ static int dahdi_register_xpd(xpd_t *xpd)
* - The modern "/sys/bus/astribanks/devices/xbus-??/connector" attribute
* So let's also export it via the newfangled "location" field.
*/
- snprintf(span->location, sizeof(span->location) - 1, "%s", xbus->location);
+ snprintf(span->location, sizeof(span->location) - 1, "%s", xbus->connector);
/*
* Who said a span and irq have 1-1 relationship?
* Also exporting this low-level detail isn't too wise.
@@ -1058,12 +1158,13 @@ static void __exit xpp_dahdi_cleanup(void)
}
EXPORT_SYMBOL(debug);
-EXPORT_SYMBOL(xpd_common_init);
EXPORT_SYMBOL(create_xpd);
EXPORT_SYMBOL(xpd_post_init);
+EXPORT_SYMBOL(get_xpd);
+EXPORT_SYMBOL(put_xpd);
EXPORT_SYMBOL(xpd_alloc);
EXPORT_SYMBOL(xpd_free);
-EXPORT_SYMBOL(xpd_disconnect);
+EXPORT_SYMBOL(xpd_unreg_request);
EXPORT_SYMBOL(update_xpd_status);
EXPORT_SYMBOL(update_line_status);
EXPORT_SYMBOL(xpp_open);
diff --git a/drivers/dahdi/xpp/xpp_dahdi.h b/drivers/dahdi/xpp/xpp_dahdi.h
index 74a12c8..7b5695a 100644
--- a/drivers/dahdi/xpp/xpp_dahdi.h
+++ b/drivers/dahdi/xpp/xpp_dahdi.h
@@ -25,12 +25,13 @@
#include "xpd.h"
#include "xproto.h"
-void xpd_disconnect(xpd_t *xpd);
-int xpd_common_init(xbus_t *xbus, xpd_t *xpd, int unit, int subunit, int subtype, int subunits);
+int dahdi_register_xpd(xpd_t *xpd);
+int dahdi_unregister_xpd(xpd_t *xpd);
+void xpd_unreg_request(xpd_t *xpd);
int create_xpd(xbus_t *xbus, const xproto_table_t *proto_table,
int unit, int subunit, byte type, byte subtype, int subunits, byte port_dir);
void xpd_post_init(xpd_t *xpd);
-xpd_t *xpd_alloc(size_t privsize, const xproto_table_t *proto_table, int channels);
+xpd_t *xpd_alloc(xbus_t *xbus, int unit, int subunit, int subtype, int subunits, size_t privsize, const xproto_table_t *proto_table, int channels);
void xpd_free(xpd_t *xpd);
void xpd_remove(xpd_t *xpd);
void update_xpd_status(xpd_t *xpd, int alarm_flag);
diff --git a/drivers/dahdi/xpp/xpp_usb.c b/drivers/dahdi/xpp/xpp_usb.c
index a64a50c..2346fb4 100644
--- a/drivers/dahdi/xpp/xpp_usb.c
+++ b/drivers/dahdi/xpp/xpp_usb.c
@@ -439,7 +439,7 @@ static int xframe_send_cmd(xbus_t *xbus, xframe_t *xframe)
*/
static bool xusb_listen(xusb_t *xusb)
{
- xbus_t *xbus = get_xbus(xusb->xbus_num);
+ xbus_t *xbus = xbus_num(xusb->xbus_num);
xframe_t *xframe;
struct uframe *uframe;
int ret = 0;
@@ -465,7 +465,6 @@ static bool xusb_listen(xusb_t *xusb)
atomic_inc(&xusb->pending_reads);
ret = 1;
out:
- put_xbus(xbus);
return ret;
}
@@ -710,7 +709,7 @@ static int xusb_probe(struct usb_interface *interface, const struct usb_device_i
xusb->present = 1;
/* we can register the device now, as it is ready */
- usb_set_intfdata (interface, xusb);
+ usb_set_intfdata(interface, xusb);
retval = usb_register_dev (interface, &xusb_class);
if (retval) {
/* something prevented us from registering this driver */
@@ -739,12 +738,12 @@ static int xusb_probe(struct usb_interface *interface, const struct usb_device_i
goto probe_failed;
}
usb_make_path(udev, xusb->path, XBUS_DESCLEN); // May trunacte... ignore
- snprintf(xbus->location, XBUS_DESCLEN, "%s", xusb->path);
+ snprintf(xbus->connector, XBUS_DESCLEN, "%s", xusb->path);
if(xusb->serial && xusb->serial[0])
snprintf(xbus->label, LABEL_SIZE, "usb:%s", xusb->serial);
xusb->index = i;
xusb_array[i] = xusb;
- XUSB_DBG(DEVICES, xusb, "GOT XPP USB BUS: %s\n", xbus->location);
+ XUSB_DBG(DEVICES, xusb, "GOT XPP USB BUS: %s\n", xbus->connector);
#ifdef CONFIG_PROC_FS
DBG(PROC, "Creating proc entry " PROC_USBXPP_SUMMARY " in bus proc dir.\n");
@@ -763,11 +762,11 @@ static int xusb_probe(struct usb_interface *interface, const struct usb_device_i
/* prepare several pending frames for receive side */
for(i = 0; i < 10; i++)
xusb_listen(xusb);
- xbus_activate(xbus);
+ xbus_connect(xbus);
return retval;
probe_failed:
ERR("Failed to initialize xpp usb bus: %d\n", retval);
- usb_set_intfdata (interface, NULL);
+ usb_set_intfdata(interface, NULL);
if(xusb) {
if(xusb->minor) { // passed registration phase
ERR("Calling usb_deregister_dev()\n");
@@ -801,18 +800,20 @@ probe_failed:
*/
static void xusb_disconnect(struct usb_interface *interface)
{
+ struct usb_host_interface *iface_desc = usb_altnum_to_altsetting(interface, 0);
xusb_t *xusb;
xbus_t *xbus;
int minor;
int i;
- DBG(DEVICES, "CALLED\n");
+ DBG(DEVICES, "CALLED on interface #%d\n", iface_desc->desc.bInterfaceNumber);
/* prevent races with open() */
down (&disconnect_sem);
- xusb = usb_get_intfdata (interface);
+ xusb = usb_get_intfdata(interface);
+ usb_set_intfdata(interface, NULL);
xusb->present = 0;
- xbus = get_xbus(xusb->xbus_num);
+ xbus = xbus_num(xusb->xbus_num);
/* find our xusb */
for(i = 0; i < MAX_BUSES; i++) {
@@ -828,17 +829,13 @@ static void xusb_disconnect(struct usb_interface *interface)
remove_proc_entry(PROC_USBXPP_SUMMARY, xbus->proc_xbus_dir);
}
#endif
- /*
- * put_xbus() would be called during xbus_disconnect()
- */
xbus_disconnect(xbus); // Blocking until fully deactivated!
- usb_set_intfdata (interface, NULL);
down (&xusb->sem);
minor = xusb->minor;
/* give back our minor */
- usb_deregister_dev (interface, &xusb_class);
+ usb_deregister_dev(interface, &xusb_class);
up (&xusb->sem);
DBG(DEVICES, "Semaphore released\n");
@@ -853,7 +850,7 @@ static void xpp_send_callback(USB_PASS_CB(urb))
struct uframe *uframe = urb_to_uframe(urb);
xframe_t *xframe = &uframe->xframe;
xusb_t *xusb = uframe->xusb;
- xbus_t *xbus = get_xbus(xusb->xbus_num);
+ xbus_t *xbus = xbus_num(xusb->xbus_num);
struct timeval now;
long usec;
int writes = atomic_read(&xusb->pending_writes);
@@ -904,7 +901,6 @@ static void xpp_send_callback(USB_PASS_CB(urb))
FREE_SEND_XFRAME(xbus, xframe);
if(!xusb->present)
XUSB_ERR(xusb, "A urb from non-connected device?\n");
- put_xbus(xbus);
}
static void xpp_receive_callback(USB_PASS_CB(urb))
@@ -912,7 +908,7 @@ static void xpp_receive_callback(USB_PASS_CB(urb))
struct uframe *uframe = urb_to_uframe(urb);
xframe_t *xframe = &uframe->xframe;
xusb_t *xusb = uframe->xusb;
- xbus_t *xbus = get_xbus(xusb->xbus_num);
+ xbus_t *xbus = xbus_num(xusb->xbus_num);
size_t size;
bool do_resubmit = 1;
bool is_inuse = 0;
@@ -924,11 +920,6 @@ static void xpp_receive_callback(USB_PASS_CB(urb))
XUSB_ERR(xusb, "Received URB does not belong to a valid xbus anymore...\n");
return;
}
- if(!XBUS_GET(xbus)) {
- XUSB_ERR(xusb, "Dropping urb. Is shutting down.\n");
- do_resubmit = 0;
- goto err;
- }
is_inuse = 1;
if(!xusb->present) {
do_resubmit = 0;
@@ -957,11 +948,8 @@ static void xpp_receive_callback(USB_PASS_CB(urb))
/* Send UP */
xbus_receive_xframe(xbus, xframe);
end:
- if(is_inuse)
- XBUS_PUT(xbus);
if(do_resubmit)
xusb_listen(xusb);
- put_xbus(xbus);
return;
err:
FREE_RECV_XFRAME(xbus, xframe);
diff --git a/drivers/dahdi/xpp/xproto.c b/drivers/dahdi/xpp/xproto.c
index 72686e3..53b6fce 100644
--- a/drivers/dahdi/xpp/xproto.c
+++ b/drivers/dahdi/xpp/xproto.c
@@ -262,7 +262,7 @@ int xframe_receive(xbus_t *xbus, xframe_t *xframe)
FREE_RECV_XFRAME(xbus, xframe);
return -EPROTO;
}
- if(!XBUS_GET(xbus)) {
+ if(XBUS_IS(xbus, DISCONNECTED)) {
XBUS_DBG(GENERAL, xbus, "Dropped xframe. Is shutting down.\n");
return -ENODEV;
}
@@ -270,9 +270,12 @@ int xframe_receive(xbus_t *xbus, xframe_t *xframe)
/*
* We want to check that xframes do not mix PCM and other commands
*/
- if(XPACKET_IS_PCM((xpacket_t *)xframe->packets))
- xframe_receive_pcm(xbus, xframe);
- else {
+ if(XPACKET_IS_PCM((xpacket_t *)xframe->packets)) {
+ if(!XBUS_IS(xbus, READY))
+ FREE_RECV_XFRAME(xbus, xframe);
+ else
+ xframe_receive_pcm(xbus, xframe);
+ } else {
XBUS_COUNTER(xbus, RX_CMD)++;
ret = xframe_receive_cmd(xbus, xframe);
}
@@ -282,7 +285,6 @@ int xframe_receive(xbus_t *xbus, xframe_t *xframe)
now.tv_usec - tv_received.tv_usec;
if(usec > xbus->max_rx_process)
xbus->max_rx_process = usec;
- XBUS_PUT(xbus);
return ret;
}
diff --git a/drivers/dahdi/xpp/xproto.h b/drivers/dahdi/xpp/xproto.h
index c58f36d..dbb720e 100644
--- a/drivers/dahdi/xpp/xproto.h
+++ b/drivers/dahdi/xpp/xproto.h
@@ -147,7 +147,7 @@ bool valid_xpd_addr(const struct xpd_addr *addr);
do { \
int pack_len = RPACKET_SIZE(card,op); \
\
- if(!TRANSPORT_RUNNING(xbus)) \
+ if(XBUS_IS(xbus, DISCONNECTED)) \
return -ENODEV; \
frm = ALLOC_SEND_XFRAME(xbus); \
if(!frm) \