diff options
author | Noe Rubinstein <nrubinstein@proformatique.com> | 2010-11-04 18:57:02 +0100 |
---|---|---|
committer | Noe Rubinstein <nrubinstein@proformatique.com> | 2010-11-04 19:08:01 +0100 |
commit | dbb36f23299b01dc54d5145aa51a971ced62842b (patch) | |
tree | beb0ac2f7f819aae3e1a03f5a860a549abd3f1fc /xhfc/xhfc_st_state.c | |
parent | 1512ecac55bd47d0af37953baa27cfdc3c99aa3f (diff) |
start rewriting software part of ST state machine
Diffstat (limited to 'xhfc/xhfc_st_state.c')
-rw-r--r-- | xhfc/xhfc_st_state.c | 148 |
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]); +} + |