diff options
Diffstat (limited to 'kernel/xpp/card_pri.c')
-rw-r--r-- | kernel/xpp/card_pri.c | 536 |
1 files changed, 434 insertions, 102 deletions
diff --git a/kernel/xpp/card_pri.c b/kernel/xpp/card_pri.c index 78d2025..a8eef64 100644 --- a/kernel/xpp/card_pri.c +++ b/kernel/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 zt_span *span); static int pri_shutdown(struct zt_span *span); static int pri_rbsbits(struct zt_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, @@ -101,25 +105,16 @@ static int pri_num_channels(enum pri_protocol pri_protocol) return num_channels[pri_protocol]; } -static const char *type_name(enum pri_protocol pri_protocol, bool is_nt) +static const char *type_name(enum pri_protocol pri_protocol) { - static const char *names[2][4] = { - /* TE */ [0] = { - [PRI_PROTO_0] = "Unknown_TE", - [PRI_PROTO_E1] = "E1_TE", - [PRI_PROTO_T1] = "T1_TE", - [PRI_PROTO_J1] = "J1_TE" - }, - /* NT */ [1] = { - [PRI_PROTO_0] = "Unknown_NT", - [PRI_PROTO_E1] = "E1_NT", - [PRI_PROTO_T1] = "T1_NT", - [PRI_PROTO_J1] = "J1_NT" - } - }; - int term = (is_nt) ? 1 : 0; + static const char *names[4] = { + [PRI_PROTO_0] = "PRI-Unknown", + [PRI_PROTO_E1] = "E1", + [PRI_PROTO_T1] = "T1", + [PRI_PROTO_J1] = "J1" + }; - return names[term][pri_protocol]; + return names[pri_protocol]; } static int pri_linecompat(enum pri_protocol pri_protocol) @@ -159,10 +154,10 @@ enum pri_led_state { }; enum pri_led_selectors { - TE_RED_LED = 0, - TE_GREEN_LED = 1, - NT_RED_LED = 2, - NT_GREEN_LED = 3, + BOTTOM_RED_LED = 0, + BOTTOM_GREEN_LED = 1, + TOP_RED_LED = 2, + TOP_GREEN_LED = 3, }; #define NUM_LEDS 4 @@ -294,9 +289,10 @@ struct pri_leds { #define NUM_CAS_RS (REG_RS16_E - REG_RS2_E + 1) struct PRI_priv_data { - bool is_nt; bool clock_source; +#ifdef OLD_PROC struct proc_dir_entry *pri_info; +#endif enum pri_protocol pri_protocol; int deflaw; unsigned int dchan_num; @@ -393,6 +389,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; @@ -407,7 +404,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; @@ -432,6 +431,7 @@ err: pri_proc_remove(xbus, xpd); return -EINVAL; } +#endif static bool valid_pri_modes(const xpd_t *xpd) { @@ -524,7 +524,7 @@ static int set_pri_proto(xpd_t *xpd, enum pri_protocol set_proto) priv->deflaw = deflaw; priv->dchan_num = dchan_num; priv->local_loopback = 0; - xpd->type_name = type_name(priv->pri_protocol, priv->is_nt); + xpd->type_name = type_name(priv->pri_protocol); XPD_DBG(GENERAL, xpd, "%s, channels=%d, dchan_num=%d, deflaw=%d\n", pri_protocol_name(set_proto), xpd->channels, @@ -557,7 +557,7 @@ static void zap_update_syncsrc(xpd_t *xpd) if(!subxpd) continue; priv = subxpd->priv; - if(priv->clock_source) { + if(priv->clock_source && priv->alarms == 0) { if(best_spanno) XPD_ERR(xpd, "Duplicate XPD's with clock_source=1\n"); best_spanno = subxpd->span.spanno; @@ -578,7 +578,7 @@ static void zap_update_syncsrc(xpd_t *xpd) /* * Called from: * - set_master_mode() -- - * As a result of ztcfg or writing to /proc/xpp/XBUS-??/XPD-/??/pri_info + * As a result of ztcfg * - layer1_state() -- * As a result of an alarm. */ @@ -587,10 +587,10 @@ static void set_clocking(xpd_t *xpd) xbus_t *xbus; xpd_t *best_xpd = NULL; int best_subunit = -1; /* invalid */ - int best_subunit_prio = 0; + unsigned int best_subunit_prio = INT_MAX; 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; @@ -602,7 +602,7 @@ static void set_clocking(xpd_t *xpd) priv = subxpd->priv; if(priv->alarms != 0) continue; - if(subxpd->timing_priority > best_subunit_prio) { + if(subxpd->timing_priority > 0 && subxpd->timing_priority < best_subunit_prio) { best_xpd = subxpd; best_subunit = i; best_subunit_prio = subxpd->timing_priority; @@ -635,7 +635,6 @@ static void set_clocking(xpd_t *xpd) } } zap_update_syncsrc(xpd); - put_xbus(xbus); } static void set_reg_lim0(const char *msg, xpd_t *xpd) @@ -665,10 +664,8 @@ static void set_reg_lim0(const char *msg, xpd_t *xpd) * Normally set by the timing parameter in zaptel.conf * If this is called by ztcfg, than it's too late to change * zaptel sync priority (we are already registered) - * There are two workarounds to mitigate this problem: - * 1. So we set *our* sync master at least. - * 2. And we try to call it with a sane default from set_nt() - * which is called before zaptel registration. + * + * Also called from set_localloop() */ static int set_master_mode(const char *msg, xpd_t *xpd) { @@ -682,43 +679,20 @@ static int set_master_mode(const char *msg, xpd_t *xpd) return 0; } -static int set_nt(const char *msg, xpd_t *xpd, bool is_nt) +static int set_localloop(xpd_t *xpd, bool localloop) { struct PRI_priv_data *priv; - const char *tname; BUG_ON(!xpd); priv = xpd->priv; - tname = type_name(priv->pri_protocol, is_nt); - XPD_DBG(SIGNAL, xpd, "%s(%s): %s %s\n", __FUNCTION__, msg, tname, (is_nt) ? "NT" : "TE"); if(SPAN_REGISTERED(xpd)) { - XPD_NOTICE(xpd, "Registered as span %d. Cannot do %s(%s)\n", - xpd->span.spanno, __FUNCTION__, msg); - return -EBUSY; - } - priv->is_nt = is_nt; - xpd->type_name = tname; - xpd->direction = (is_nt) ? TO_PHONE : TO_PSTN; - if(xpd->timing_priority == 0 && !is_nt) /* by default set timing priority from NT/TE */ - xpd->timing_priority = 1; - set_master_mode(msg, xpd); - return 0; -} - -static int set_localloop(const char *msg, xpd_t *xpd, bool localloop) -{ - struct PRI_priv_data *priv; - - BUG_ON(!xpd); - priv = xpd->priv; - XPD_DBG(SIGNAL, xpd, "(%s): %s\n", msg, (localloop)?"YES":"NO"); - if(SPAN_REGISTERED(xpd)) { - XPD_NOTICE(xpd, "Registered as span %d. Cannot do %s(%s)\n", - xpd->span.spanno, __FUNCTION__, msg); + XPD_NOTICE(xpd, "Registered as span %d. Cannot do %s\n", + xpd->span.spanno, __FUNCTION__); return -EBUSY; } priv->local_loopback = localloop; - set_reg_lim0(__FUNCTION__, xpd); + XPD_DBG(SIGNAL, xpd, "%s: %s\n", __FUNCTION__, (localloop) ? "LOCALLOOP" : "NO"); + set_master_mode(__FUNCTION__, xpd); return 0; } @@ -855,7 +829,7 @@ static int pri_lineconfig(xpd_t *xpd, int lineconfig) fmr3 |= REG_FMR3_EXTIW; } XPD_DBG(GENERAL, xpd, "[%s] lineconfig=%s/%s/%s %s (0x%X)\n", - (priv->is_nt)?"NT":"TE", + (priv->clock_source)?"MASTER":"SLAVE", framingstr, codingstr, crcstr, (lineconfig & ZT_CONFIG_NOTOPEN)?"YELLOW":"", lineconfig); @@ -910,7 +884,7 @@ static int pri_spanconfig(struct zt_span *span, struct zt_lineconfig *lc) * We currently ignore it also. */ XPD_DBG(GENERAL, xpd, "[%s] lbo=%d lineconfig=0x%X sync=%d\n", - (priv->is_nt)?"NT":"TE", lc->lbo, lc->lineconfig, lc->sync); + (priv->clock_source)?"MASTER":"SLAVE", lc->lbo, lc->lineconfig, lc->sync); ret = pri_lineconfig(xpd, lc->lineconfig); if(!ret) { span->lineconfig = lc->lineconfig; @@ -942,22 +916,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->pri_protocol = PRI_PROTO_0; /* Default, changes in set_pri_proto() */ priv->deflaw = ZT_LAW_DEFAULT; /* Default, changes in set_pri_proto() */ - xpd->type_name = - type_name(priv->pri_protocol, 0); /* Default, changes in set_nt() */ - if(xpd_common_init(xbus, xpd, unit, subunit, subtype, subunits) < 0) - goto err; - if(pri_proc_create(xbus, xpd) < 0) - goto err; + xpd->type_name = type_name(priv->pri_protocol); +#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) @@ -988,6 +960,11 @@ static int PRI_card_init(xbus_t *xbus, xpd_t *xpd) XPD_NOTICE(xpd, "PRI protocol not set\n"); goto err; } + xpd->type_name = type_name(priv->pri_protocol); + xpd->direction = TO_PSTN; + XPD_DBG(DEVICES, xpd, "%s\n", xpd->type_name); + xpd->timing_priority = 1; /* SLAVE */ + set_master_mode(__FUNCTION__, xpd); for(ret = 0; ret < NUM_LEDS; ret++) { DO_LED(xpd, ret, PRI_LED_ON); msleep(20); @@ -996,7 +973,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; } @@ -1008,7 +987,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; } @@ -1117,7 +1098,7 @@ static void dchan_state(xpd_t *xpd, bool up) /* * LED managment is done by the driver now: - * - Turn constant ON RED/GREEN led to indicate NT/TE port + * - Turn constant ON RED/GREEN led to indicate MASTER/SLAVE port * - Very fast "Double Blink" to indicate Layer1 alive (without D-Channel) * - Constant blink (1/2 sec cycle) to indicate D-Channel alive. */ @@ -1133,12 +1114,12 @@ static void handle_leds(xbus_t *xbus, xpd_t *xpd) BUG_ON(!xpd); priv = xpd->priv; BUG_ON(!priv); - if(priv->is_nt) { - which_led = NT_RED_LED; - other_led = TE_GREEN_LED; + if(xpd->timing_priority == 0) { + which_led = TOP_RED_LED; + other_led = BOTTOM_GREEN_LED; } else { - which_led = TE_GREEN_LED; - other_led = NT_RED_LED; + which_led = BOTTOM_GREEN_LED; + other_led = TOP_RED_LED; } ledstate = priv->ledstate[which_led]; timer_count = xpd->timer_count; @@ -1214,7 +1195,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 ZT_TONEDETECT: @@ -1249,7 +1230,7 @@ static int pri_startup(struct zt_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 zaptel. No Hardware. Ignored\n"); return -ENODEV; } @@ -1270,7 +1251,7 @@ static int pri_shutdown(struct zt_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 zaptel. No Hardware. Ignored\n"); return -ENODEV; } @@ -1671,11 +1652,10 @@ static xproto_table_t PROTO_TABLE(PRI) = { static bool pri_packet_is_valid(xpacket_t *pack) { - const xproto_entry_t *xe_nt = NULL; - const xproto_entry_t *xe_te = NULL; + const xproto_entry_t *xe = NULL; // DBG(GENERAL, "\n"); - xe_nt = xproto_card_entry(&PROTO_TABLE(PRI), XPACKET_OP(pack)); - return xe_nt != NULL || xe_te != NULL; + xe = xproto_card_entry(&PROTO_TABLE(PRI), XPACKET_OP(pack)); + return xe != NULL; } static void pri_packet_dump(const char *msg, xpacket_t *pack) @@ -1683,6 +1663,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; @@ -1690,18 +1671,17 @@ static int proc_pri_info_write(struct file *file, const char __user *buffer, uns char buf[MAX_PROC_WRITE]; char *p; char *tok; - static const char *msg = "PROC"; /* for logs */ int ret = 0; bool got_localloop = 0; bool got_nolocalloop = 0; - bool got_te = 0; - bool got_nt = 0; bool got_e1 = 0; bool got_t1 = 0; bool got_j1 = 0; 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); @@ -1725,10 +1705,6 @@ static int proc_pri_info_write(struct file *file, const char __user *buffer, uns got_localloop = 1; else if(strnicmp(tok, "NOLOCALLOOP", 8) == 0) got_nolocalloop = 1; - else if(strnicmp(tok, "NT", 2) == 0) - got_nt = 1; - else if(strnicmp(tok, "TE", 2) == 0) - got_te = 1; else if(strnicmp(tok, "E1", 2) == 0) got_e1 = 1; else if(strnicmp(tok, "T1", 2) == 0) @@ -1752,13 +1728,9 @@ static int proc_pri_info_write(struct file *file, const char __user *buffer, uns return -EINVAL; } if(got_localloop) - ret = set_localloop(msg, xpd, 1); + ret = set_localloop(xpd, 1); if(got_nolocalloop) - ret = set_localloop(msg, xpd, 0); - if(got_nt) - ret = set_nt(msg, xpd, 1); - if(got_te) - ret = set_nt(msg, xpd, 0); + ret = set_localloop(xpd, 0); return (ret) ? ret : count; } @@ -1774,11 +1746,13 @@ 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); len += sprintf(page + len, "PRI: %s %s%s (deflaw=%d, dchan=%d)\n", - (priv->is_nt) ? "NT" : "TE", + (priv->clock_source) ? "MASTER" : "SLAVE", pri_protocol_name(priv->pri_protocol), (priv->local_loopback) ? " LOCALLOOP" : "", priv->deflaw, priv->dchan_num); @@ -1836,11 +1810,368 @@ 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", +#ifndef OLD_HOTPLUG_SUPPORT + .owner = THIS_MODULE, +#endif + .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; @@ -1850,6 +2181,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"); |