summaryrefslogtreecommitdiff
path: root/kernel/xpp/card_pri.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/xpp/card_pri.c')
-rw-r--r--kernel/xpp/card_pri.c536
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");