summaryrefslogtreecommitdiff
path: root/xhfc/xhfc_st_state.c
diff options
context:
space:
mode:
authorNoe Rubinstein <nrubinstein@proformatique.com>2010-11-04 18:57:02 +0100
committerNoe Rubinstein <nrubinstein@proformatique.com>2010-11-04 19:08:01 +0100
commitdbb36f23299b01dc54d5145aa51a971ced62842b (patch)
treebeb0ac2f7f819aae3e1a03f5a860a549abd3f1fc /xhfc/xhfc_st_state.c
parent1512ecac55bd47d0af37953baa27cfdc3c99aa3f (diff)
start rewriting software part of ST state machine
Diffstat (limited to 'xhfc/xhfc_st_state.c')
-rw-r--r--xhfc/xhfc_st_state.c148
1 files changed, 148 insertions, 0 deletions
diff --git a/xhfc/xhfc_st_state.c b/xhfc/xhfc_st_state.c
new file mode 100644
index 0000000..f52425d
--- /dev/null
+++ b/xhfc/xhfc_st_state.c
@@ -0,0 +1,148 @@
+#include <linux/delay.h>
+#include <linux/timer.h>
+
+#include "xhfc.h"
+#include "xhfc_leb.h"
+
+/* Software-implemented timers for the S/T state machine, in milliseconds */
+#define T1_MS 100 /* NT activation timer.
+ 100..1000ms according to Cologne/ETSI TBR4 (??)
+ 100ms in Cologne's mISDN driver. */
+#define T3_MS 30000 /* TE activation timer.
+ according to I.430 "the value depends on the
+ subscriber loop transmission technique. The worst
+ case value is 30s." */
+
+enum te_state { F0, F1, F2, F3, F4, F5, F6, F7, F8 };
+enum nt_state { G0, G1, G2, G3 };
+
+void activate_request(struct xhfc_span* s);
+void deactivate_request(struct xhfc_span* s);
+void handle_state_change(struct xhfc_span* s);
+
+static void expiry_T1(struct xhfc_span* s);
+static void expiry_T3(struct xhfc_span* s);
+
+static void handle_state_change_nt(struct xhfc_span* s);
+static void handle_state_change_te(struct xhfc_span* s);
+static void activate_request_nt(struct xhfc_span* s);
+static void activate_request_te(struct xhfc_span* s);
+
+static void print_current_state(struct xhfc_span* s);
+
+void handle_state_change(struct xhfc_span* s)
+{
+ struct xhfc* x = s->xhfc;
+
+ s->prev_state = s->state;
+
+ write_xhfc(x, R_SU_SEL, s->port);
+ s->state = read_xhfc(x, A_SU_RD_STA);
+
+ if(debug & DEBUG_ST_STATE) //XXX only place where this is used
+ print_state(s);
+
+ if(s->prev_state = s->state) {
+ printk(KERN_WARNING DRIVER_NAME ": a state change has been "
+ "reported on port %d but it looks like the "
+ "state has not changed?", s->port + 1);
+ return;
+ }
+
+ if(s->nt)
+ handle_state_change_nt(s);
+ else
+ handle_state_change_te(s);
+}
+
+static void handle_state_change_nt(struct xhfc_span* s)
+{
+ switch (s->state) {
+ case G0:
+ case G1:
+ case G4:
+ s->span.alarms = DAHDI_ALARM_RED;
+ break;
+ case G2:
+ s->span.alarms = DAHDI_ALARM_YELLOW;
+ if(s->prev_state != G3)
+ /* Start T1 */ ;
+ break;
+ case G3:
+ s->span.alarms = DAHDI_ALARM_NONE;
+ /* Stop T1 */
+ break;
+ }
+}
+
+static void handle_state_change_te(struct xhfc_span* s)
+{
+ switch(s->state) {
+ case F0:
+ case F1:
+ case F2:
+ case F3:
+ case F8:
+ s->span.alarms = DAHDI_ALARM_RED;
+ break;
+ case F4:
+ /* XXX If in F3 and receiving INFO0, the state machine
+ * should change to F4 and start T3. Is the jump to F4
+ * done by the XHFC in hard, (in which case the timer
+ * T3 will be started by the software when detecting a
+ * change of state towards F4) or should it be driven
+ * by the soft (in which case upon detection of the
+ * reception of INFO0 in F3 state, the state would be
+ * set to F4 and T3 started)?
+ *
+ * Andrew did the latter, and I can't seem to get if
+ * and how mISDN handles this.
+ *
+ * Here, the former hypothesis (state change driven by
+ * hard) is assumed.
+ */
+
+ /* Start T3 */
+
+ /* Fall through */
+ case F5:
+ case F6:
+ s->span.alarms = DAHDI_ALARM_YELLOW;
+ break;
+ case F7:
+ s->span.alarms = DAHDI_ALARM_NONE;
+ /* Stop T3 */
+ break;
+
+}
+
+static char *state_descriptions[2][16] = {
+ { /* TE */
+ /* F0 */ "reset",
+ /* F1 */ "inactive",
+ /* F2 */ "sensing",
+ /* F3 */ "deactivate",
+ /* F4 */ "awaiting signal",
+ /* F5 */ "identifying input",
+ /* F6 */ "synchronized",
+ /* F7 */ "activated",
+ /* F8 */ "lost framing",
+ "?", "?", "?", "?", "?", "?", "?" },
+ { /* NT */
+ /* G0 */ "reset",
+ /* G1 */ "deactivated",
+ /* G2 */ "pending activation",
+ /* G3 */ "active",
+ /* G4 */ "pending deactivation",
+ "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", "?" }};
+
+static void print_state(struct xhfc_span* s)
+{
+ printk(KERN_DEBUG DRIVER_NAME "port %d: %s state %c%d (%s)\n",
+ s->port + 1,
+ (s->nt ? "NT" : "TE"),
+ (s->nt ? 'G' : 'F'),
+ s->state,
+ state_description[s->nt][s->state]);
+}
+