diff options
Diffstat (limited to 'drivers/dahdi/xpp')
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) \ |