xpp: style - Run Lindent

* Here it is:
  KERNEL_STYLE="-npro -kr -i8 -ts8 -sob -l80 -ss -ncs -cp1"
  TYPEDEFS='
	-T gfp_t
	-T __user
	-T u_char
	-T __u8
	-T byte
	-T bool
	-T charp
	-T xusb_t
	-T xbus_t
	-T xpd_t
	-T xproto_table_t
	-T xproto_entry_t
	-T xframe_t
	-T xpacket_t
	-T reg_cmd_t
	'

  indent $TYPEDEFS $KERNEL_STYLE \
	--ignore-newlines	\
	--indent-label0	\
	--no-space-after-function-call-names	\
	"$@"

Signed-off-by: Oron Peled <oron.peled@xorcom.com>
Acked-By: Tzafrir Cohen <tzafrir.cohen@xorcom.com>

git-svn-id: http://svn.asterisk.org/svn/dahdi/linux/trunk@10428 a0bf4364-ded3-4de4-8d8a-66a801d63aff
This commit is contained in:
Oron Peled 2012-01-11 15:22:46 +00:00 committed by Tzafrir Cohen
parent 97ad9f8d03
commit a2a695c742
33 changed files with 4987 additions and 4471 deletions

View File

@ -40,8 +40,10 @@ static const char rcsid[] = "$Id$";
#endif #endif
static DEF_PARM(int, debug, 0, 0644, "Print DBG statements"); /* must be before dahdi_debug.h */ static DEF_PARM(int, debug, 0, 0644, "Print DBG statements"); /* must be before dahdi_debug.h */
static DEF_PARM(uint, poll_interval, 500, 0644, "Poll channel state interval in milliseconds (0 - disable)"); static DEF_PARM(uint, poll_interval, 500, 0644,
static DEF_PARM_BOOL(nt_keepalive, 1, 0644, "Force BRI_NT to keep trying connection"); "Poll channel state interval in milliseconds (0 - disable)");
static DEF_PARM_BOOL(nt_keepalive, 1, 0644,
"Force BRI_NT to keep trying connection");
enum xhfc_states { enum xhfc_states {
ST_RESET = 0, /* G/F0 */ ST_RESET = 0, /* G/F0 */
@ -149,7 +151,8 @@ static int write_state_register(xpd_t *xpd, __u8 value);
static bool bri_packet_is_valid(xpacket_t *pack); static bool bri_packet_is_valid(xpacket_t *pack);
static void bri_packet_dump(const char *msg, xpacket_t *pack); static void bri_packet_dump(const char *msg, xpacket_t *pack);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
static int proc_bri_info_read(char *page, char **start, off_t off, int count, int *eof, void *data); static int proc_bri_info_read(char *page, char **start, off_t off, int count,
int *eof, void *data);
#endif #endif
static int bri_spanconfig(struct file *file, struct dahdi_span *span, static int bri_spanconfig(struct file *file, struct dahdi_span *span,
struct dahdi_lineconfig *lc); struct dahdi_lineconfig *lc);
@ -180,7 +183,6 @@ enum bri_led_names {
#define NUM_LEDS 2 #define NUM_LEDS 2
#define LED_TICKS 100 #define LED_TICKS 100
struct bri_leds { struct bri_leds {
__u8 state:2; __u8 state:2;
__u8 led_sel:1; /* 0 - GREEN, 1 - RED */ __u8 led_sel:1; /* 0 - GREEN, 1 - RED */
@ -224,12 +226,11 @@ struct BRI_priv_data {
static xproto_table_t PROTO_TABLE(BRI); static xproto_table_t PROTO_TABLE(BRI);
DEF_RPACKET_DATA(BRI, SET_LED, /* Set one of the LED's */ DEF_RPACKET_DATA(BRI, SET_LED, /* Set one of the LED's */
struct bri_leds bri_leds; struct bri_leds bri_leds;);
);
static /* 0x33 */ DECLARE_CMD(BRI, SET_LED, enum bri_led_names which_led, enum led_state to_led_state); static /* 0x33 */ DECLARE_CMD(BRI, SET_LED, enum bri_led_names which_led,
enum led_state to_led_state);
#define DO_LED(xpd, which, tostate) \ #define DO_LED(xpd, which, tostate) \
CALL_PROTO(BRI, SET_LED, (xpd)->xbus, (xpd), (which), (tostate)) CALL_PROTO(BRI, SET_LED, (xpd)->xbus, (xpd), (which), (tostate))
@ -243,9 +244,10 @@ static void dump_hex_buf(xpd_t *xpd, char *msg, __u8 *buf, size_t len)
debug_buf[0] = '\0'; debug_buf[0] = '\0';
for (i = 0; i < len && n < DEBUG_BUF_SIZE; i++) for (i = 0; i < len && n < DEBUG_BUF_SIZE; i++)
n += snprintf(&debug_buf[n], DEBUG_BUF_SIZE - n, "%02X ", buf[i]); n += snprintf(&debug_buf[n], DEBUG_BUF_SIZE - n, "%02X ",
XPD_NOTICE(xpd, "%s[0..%zd]: %s%s\n", msg, len-1, debug_buf, buf[i]);
(n >= DEBUG_BUF_SIZE)?"...":""); XPD_NOTICE(xpd, "%s[0..%zd]: %s%s\n", msg, len - 1, debug_buf,
(n >= DEBUG_BUF_SIZE) ? "..." : "");
} }
static void dump_dchan_packet(xpd_t *xpd, bool transmit, __u8 *buf, int len) static void dump_dchan_packet(xpd_t *xpd, bool transmit, __u8 *buf, int len)
@ -275,14 +277,16 @@ static void dump_dchan_packet(xpd_t *xpd, bool transmit, __u8 *buf, int len)
else else
XPD_NOTICE(xpd, "Unknown frame type 0x%X\n", buf[0]); XPD_NOTICE(xpd, "Unknown frame type 0x%X\n", buf[0]);
snprintf(msgbuf, MAX_PROC_WRITE, "D-Chan %s = (%c) ", direction, ftype); snprintf(msgbuf, MAX_PROC_WRITE, "D-Chan %s = (%c) ", direction,
ftype);
} else { } else {
snprintf(msgbuf, MAX_PROC_WRITE, "D-Chan %s = ", direction); snprintf(msgbuf, MAX_PROC_WRITE, "D-Chan %s = ", direction);
} }
dump_hex_buf(xpd, msgbuf, buf, len); dump_hex_buf(xpd, msgbuf, buf, len);
} }
static void set_bri_timer(xpd_t *xpd, const char *name, int *bri_timer, int value) static void set_bri_timer(xpd_t *xpd, const char *name, int *bri_timer,
int value)
{ {
if (value == HFC_TIMER_OFF) if (value == HFC_TIMER_OFF)
XPD_DBG(SIGNAL, xpd, "Timer %s DISABLE\n", name); XPD_DBG(SIGNAL, xpd, "Timer %s DISABLE\n", name);
@ -305,7 +309,8 @@ static void dchan_state(xpd_t *xpd, bool up)
priv->dchan_alive = 1; priv->dchan_alive = 1;
} else { } else {
XPD_DBG(SIGNAL, xpd, "STATE CHANGE: D-Channel STOPPED\n"); XPD_DBG(SIGNAL, xpd, "STATE CHANGE: D-Channel STOPPED\n");
priv->dchan_rx_counter = priv->dchan_tx_counter = priv->dchan_rx_drops = 0; priv->dchan_rx_counter = priv->dchan_tx_counter =
priv->dchan_rx_drops = 0;
priv->dchan_alive = 0; priv->dchan_alive = 0;
priv->dchan_alive_ticks = 0; priv->dchan_alive_ticks = 0;
} }
@ -321,7 +326,7 @@ static void layer1_state(xpd_t *xpd, bool up)
if (priv->layer1_up == up) if (priv->layer1_up == up)
return; return;
priv->layer1_up = up; priv->layer1_up = up;
XPD_DBG(SIGNAL, xpd, "STATE CHANGE: Layer1 %s\n", (up)?"UP":"DOWN"); XPD_DBG(SIGNAL, xpd, "STATE CHANGE: Layer1 %s\n", (up) ? "UP" : "DOWN");
if (!up) if (!up)
dchan_state(xpd, 0); dchan_state(xpd, 0);
} }
@ -335,7 +340,7 @@ static void te_activation(xpd_t *xpd, bool on)
priv = xpd->priv; priv = xpd->priv;
BUG_ON(!priv); BUG_ON(!priv);
curr_state = priv->state_register.bits.v_su_sta; curr_state = priv->state_register.bits.v_su_sta;
XPD_DBG(SIGNAL, xpd, "%s\n", (on)?"ON":"OFF"); XPD_DBG(SIGNAL, xpd, "%s\n", (on) ? "ON" : "OFF");
if (on) { if (on) {
if (curr_state == ST_TE_DEACTIVATED) { if (curr_state == ST_TE_DEACTIVATED) {
XPD_DBG(SIGNAL, xpd, "HFC_L1_ACTIVATE_TE\n"); XPD_DBG(SIGNAL, xpd, "HFC_L1_ACTIVATE_TE\n");
@ -378,7 +383,7 @@ static void nt_activation(xpd_t *xpd, bool on)
priv = xpd->priv; priv = xpd->priv;
BUG_ON(!priv); BUG_ON(!priv);
curr_state = priv->state_register.bits.v_su_sta; curr_state = priv->state_register.bits.v_su_sta;
XPD_DBG(SIGNAL, xpd, "%s\n", (on)?"ON":"OFF"); XPD_DBG(SIGNAL, xpd, "%s\n", (on) ? "ON" : "OFF");
if (on) { if (on) {
switch (curr_state) { switch (curr_state) {
case ST_RESET: /* F/G 0 */ case ST_RESET: /* F/G 0 */
@ -417,11 +422,11 @@ static void nt_activation(xpd_t *xpd, bool on)
} }
} }
/* /*
* D-Chan receive * D-Chan receive
*/ */
static int bri_check_stat(xpd_t *xpd, struct dahdi_chan *dchan, __u8 *buf, int len) static int bri_check_stat(xpd_t *xpd, struct dahdi_chan *dchan, __u8 *buf,
int len)
{ {
struct BRI_priv_data *priv; struct BRI_priv_data *priv;
__u8 status; __u8 status;
@ -433,7 +438,7 @@ static int bri_check_stat(xpd_t *xpd, struct dahdi_chan *dchan, __u8 *buf, int l
dahdi_hdlc_abort(dchan, DAHDI_EVENT_ABORT); dahdi_hdlc_abort(dchan, DAHDI_EVENT_ABORT);
return -EPROTO; return -EPROTO;
} }
status = buf[len-1]; status = buf[len - 1];
if (status) { if (status) {
int event = DAHDI_EVENT_ABORT; int event = DAHDI_EVENT_ABORT;
@ -522,7 +527,8 @@ static int send_dchan_frame(xpd_t *xpd, xframe_t *xframe, bool is_eof)
priv = xpd->priv; priv = xpd->priv;
if (!test_bit(HFC_L1_ACTIVATED, &priv->l1_flags) if (!test_bit(HFC_L1_ACTIVATED, &priv->l1_flags)
&& !test_bit(HFC_L1_ACTIVATING, &priv->l1_flags)) { && !test_bit(HFC_L1_ACTIVATING, &priv->l1_flags)) {
XPD_DBG(SIGNAL, xpd, "Want to transmit: Kick D-Channel transmiter\n"); XPD_DBG(SIGNAL, xpd,
"Want to transmit: Kick D-Channel transmiter\n");
if (!IS_NT(xpd)) if (!IS_NT(xpd))
te_activation(xpd, 1); te_activation(xpd, 1);
else else
@ -545,8 +551,8 @@ static int send_dchan_frame(xpd_t *xpd, xframe_t *xframe, bool is_eof)
/* /*
* Fill a single multibyte REGISTER_REQUEST * Fill a single multibyte REGISTER_REQUEST
*/ */
static void fill_multibyte(xpd_t *xpd, xpacket_t *pack, bool eoframe, static void fill_multibyte(xpd_t *xpd, xpacket_t *pack, bool eoframe, char *buf,
char *buf, int len) int len)
{ {
reg_cmd_t *reg_cmd; reg_cmd_t *reg_cmd;
char *p; char *p;
@ -587,8 +593,8 @@ static int tx_dchan(xpd_t *xpd)
BUG_ON(!priv); BUG_ON(!priv);
if (atomic_read(&priv->hdlc_pending) == 0) if (atomic_read(&priv->hdlc_pending) == 0)
return 0; return 0;
if (!SPAN_REGISTERED(xpd) || if (!SPAN_REGISTERED(xpd)
!(PHONEDEV(xpd).span.flags & DAHDI_FLAG_RUNNING)) || !(PHONEDEV(xpd).span.flags & DAHDI_FLAG_RUNNING))
return 0; return 0;
/* Allocate frame */ /* Allocate frame */
xframe = ALLOC_SEND_XFRAME(xpd->xbus); xframe = ALLOC_SEND_XFRAME(xpd->xbus);
@ -609,8 +615,7 @@ static int tx_dchan(xpd_t *xpd)
/* /*
* A split. Send what we currently have. * A split. Send what we currently have.
*/ */
XPD_NOTICE(xpd, XPD_NOTICE(xpd, "%s: xframe is full (%d packets)\n",
"%s: xframe is full (%d packets)\n",
__func__, packet_count); __func__, packet_count);
break; break;
} }
@ -661,9 +666,12 @@ static int bri_proc_create(xbus_t *xbus, xpd_t *xpd)
XPD_DBG(PROC, xpd, "\n"); XPD_DBG(PROC, xpd, "\n");
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
XPD_DBG(PROC, xpd, "Creating '%s'\n", PROC_BRI_INFO_FNAME); XPD_DBG(PROC, xpd, "Creating '%s'\n", PROC_BRI_INFO_FNAME);
priv->bri_info = create_proc_read_entry(PROC_BRI_INFO_FNAME, 0444, xpd->proc_xpd_dir, proc_bri_info_read, xpd); priv->bri_info =
create_proc_read_entry(PROC_BRI_INFO_FNAME, 0444, xpd->proc_xpd_dir,
proc_bri_info_read, xpd);
if (!priv->bri_info) { if (!priv->bri_info) {
XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_BRI_INFO_FNAME); XPD_ERR(xpd, "Failed to create proc file '%s'\n",
PROC_BRI_INFO_FNAME);
bri_proc_remove(xbus, xpd); bri_proc_remove(xbus, xpd);
return -EINVAL; return -EINVAL;
} }
@ -672,8 +680,9 @@ static int bri_proc_create(xbus_t *xbus, xpd_t *xpd)
return 0; return 0;
} }
static xpd_t *BRI_card_new(xbus_t *xbus, int unit, int subunit, const xproto_table_t *proto_table, static xpd_t *BRI_card_new(xbus_t *xbus, int unit, int subunit,
__u8 subtype, int subunits, int subunit_ports, bool to_phone) const xproto_table_t *proto_table, __u8 subtype,
int subunits, int subunit_ports, bool to_phone)
{ {
xpd_t *xpd = NULL; xpd_t *xpd = NULL;
int channels = min(3, CHANNELS_PERXPD); int channels = min(3, CHANNELS_PERXPD);
@ -683,7 +692,9 @@ static xpd_t *BRI_card_new(xbus_t *xbus, int unit, int subunit, const xproto_tab
return NULL; return NULL;
} }
XBUS_DBG(GENERAL, xbus, "\n"); XBUS_DBG(GENERAL, xbus, "\n");
xpd = xpd_alloc(xbus, unit, subunit, subtype, subunits, 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) if (!xpd)
return NULL; return NULL;
PHONEDEV(xpd).direction = (to_phone) ? TO_PHONE : TO_PSTN; PHONEDEV(xpd).direction = (to_phone) ? TO_PHONE : TO_PSTN;
@ -752,7 +763,7 @@ static int BRI_card_dahdi_preregistration(xpd_t *xpd, bool on)
xbus = xpd->xbus; xbus = xpd->xbus;
priv = xpd->priv; priv = xpd->priv;
BUG_ON(!xbus); BUG_ON(!xbus);
XPD_DBG(GENERAL, xpd, "%s\n", (on)?"on":"off"); XPD_DBG(GENERAL, xpd, "%s\n", (on) ? "on" : "off");
if (!on) { if (!on) {
/* Nothing to do yet */ /* Nothing to do yet */
return 0; return 0;
@ -766,8 +777,8 @@ static int BRI_card_dahdi_preregistration(xpd_t *xpd, bool on)
XPD_DBG(GENERAL, xpd, "setting BRI channel %d\n", i); XPD_DBG(GENERAL, xpd, "setting BRI channel %d\n", i);
snprintf(cur_chan->name, MAX_CHANNAME, "XPP_%s/%02d/%1d%1d/%d", snprintf(cur_chan->name, MAX_CHANNAME, "XPP_%s/%02d/%1d%1d/%d",
xpd->type_name, xbus->num, xpd->type_name, xbus->num, xpd->addr.unit,
xpd->addr.unit, xpd->addr.subunit, i); xpd->addr.subunit, i);
cur_chan->chanpos = i + 1; cur_chan->chanpos = i + 1;
cur_chan->pvt = xpd; cur_chan->pvt = xpd;
if (i == 2) { /* D-CHAN */ if (i == 2) { /* D-CHAN */
@ -791,8 +802,8 @@ static int BRI_card_dahdi_postregistration(xpd_t *xpd, bool on)
BUG_ON(!xpd); BUG_ON(!xpd);
xbus = xpd->xbus; xbus = xpd->xbus;
BUG_ON(!xbus); BUG_ON(!xbus);
XPD_DBG(GENERAL, xpd, "%s\n", (on)?"on":"off"); XPD_DBG(GENERAL, xpd, "%s\n", (on) ? "on" : "off");
return(0); return (0);
} }
static int BRI_card_hooksig(xpd_t *xpd, int pos, enum dahdi_txsig txsig) static int BRI_card_hooksig(xpd_t *xpd, int pos, enum dahdi_txsig txsig)
@ -879,16 +890,20 @@ static void handle_bri_timers(xpd_t *xpd)
if (IS_NT(xpd)) { if (IS_NT(xpd)) {
if (priv->t1 > HFC_TIMER_OFF) { if (priv->t1 > HFC_TIMER_OFF) {
if (--priv->t1 == 0) { if (--priv->t1 == 0) {
set_bri_timer(xpd, "T1", &priv->t1, HFC_TIMER_OFF); set_bri_timer(xpd, "T1", &priv->t1,
HFC_TIMER_OFF);
if (!nt_keepalive) { if (!nt_keepalive) {
if (priv->state_register.bits.v_su_sta == ST_NT_ACTIVATING) { /* G2 */ if (priv->state_register.bits.v_su_sta == ST_NT_ACTIVATING) { /* G2 */
XPD_DBG(SIGNAL, xpd, "T1 Expired. Deactivate NT\n"); XPD_DBG(SIGNAL, xpd,
clear_bit(HFC_L1_ACTIVATING, &priv->l1_flags); "T1 Expired. Deactivate NT\n");
clear_bit(HFC_L1_ACTIVATING,
&priv->l1_flags);
nt_activation(xpd, 0); /* Deactivate NT */ nt_activation(xpd, 0); /* Deactivate NT */
} else } else
XPD_DBG(SIGNAL, xpd, XPD_DBG(SIGNAL, xpd,
"T1 Expired. (state %d, ignored)\n", "T1 Expired. (state %d, ignored)\n",
priv->state_register.bits.v_su_sta); priv->state_register.
bits.v_su_sta);
} }
} }
} }
@ -896,8 +911,10 @@ static void handle_bri_timers(xpd_t *xpd)
if (priv->t3 > HFC_TIMER_OFF) { if (priv->t3 > HFC_TIMER_OFF) {
/* timer expired ? */ /* timer expired ? */
if (--priv->t3 == 0) { if (--priv->t3 == 0) {
XPD_DBG(SIGNAL, xpd, "T3 expired. Deactivate TE\n"); XPD_DBG(SIGNAL, xpd,
set_bri_timer(xpd, "T3", &priv->t3, HFC_TIMER_OFF); "T3 expired. Deactivate TE\n");
set_bri_timer(xpd, "T3", &priv->t3,
HFC_TIMER_OFF);
clear_bit(HFC_L1_ACTIVATING, &priv->l1_flags); clear_bit(HFC_L1_ACTIVATING, &priv->l1_flags);
te_activation(xpd, 0); /* Deactivate TE */ te_activation(xpd, 0); /* Deactivate TE */
} }
@ -920,8 +937,7 @@ static int BRI_card_tick(xbus_t *xbus, xpd_t *xpd)
if (poll_interval != 0 && (priv->tick_counter % poll_interval) == 0) { if (poll_interval != 0 && (priv->tick_counter % poll_interval) == 0) {
// XPD_DBG(GENERAL, xpd, "%d\n", priv->tick_counter); // XPD_DBG(GENERAL, xpd, "%d\n", priv->tick_counter);
priv->poll_counter++; priv->poll_counter++;
xpp_register_request(xbus, xpd, xpp_register_request(xbus, xpd, BRI_PORT(xpd), /* portno */
BRI_PORT(xpd), /* portno */
0, /* writing */ 0, /* writing */
A_SU_RD_STA, /* regnum */ A_SU_RD_STA, /* regnum */
0, /* do_subreg */ 0, /* do_subreg */
@ -932,9 +948,9 @@ static int BRI_card_tick(xbus_t *xbus, xpd_t *xpd)
0 /* should_reply */ 0 /* should_reply */
); );
if (IS_NT(xpd) && nt_keepalive && if (IS_NT(xpd) && nt_keepalive
!test_bit(HFC_L1_ACTIVATED, &priv->l1_flags) && && !test_bit(HFC_L1_ACTIVATED, &priv->l1_flags)
!test_bit(HFC_L1_ACTIVATING, &priv->l1_flags)) { && !test_bit(HFC_L1_ACTIVATING, &priv->l1_flags)) {
XPD_DBG(SIGNAL, xpd, "Kick NT D-Channel\n"); XPD_DBG(SIGNAL, xpd, "Kick NT D-Channel\n");
nt_activation(xpd, 1); nt_activation(xpd, 1);
} }
@ -943,7 +959,9 @@ static int BRI_card_tick(xbus_t *xbus, xpd_t *xpd)
priv->dchan_notx_ticks++; priv->dchan_notx_ticks++;
priv->dchan_norx_ticks++; priv->dchan_norx_ticks++;
priv->dchan_alive_ticks++; priv->dchan_alive_ticks++;
if (priv->dchan_alive && (priv->dchan_notx_ticks > DCHAN_LOST || priv->dchan_norx_ticks > DCHAN_LOST)) { if (priv->dchan_alive
&& (priv->dchan_notx_ticks > DCHAN_LOST
|| priv->dchan_norx_ticks > DCHAN_LOST)) {
/* /*
* No tx_dchan() or rx_dchan() for many ticks * No tx_dchan() or rx_dchan() for many ticks
* This D-Channel is probabelly dead. * This D-Channel is probabelly dead.
@ -956,7 +974,8 @@ static int BRI_card_tick(xbus_t *xbus, xpd_t *xpd)
/* Detect Layer1 disconnect */ /* Detect Layer1 disconnect */
if (priv->reg30_good && priv->reg30_ticks > poll_interval * REG30_LOST) { if (priv->reg30_good && priv->reg30_ticks > poll_interval * REG30_LOST) {
/* No reply for 1/2 a second */ /* No reply for 1/2 a second */
XPD_ERR(xpd, "Lost state tracking for %d ticks\n", priv->reg30_ticks); XPD_ERR(xpd, "Lost state tracking for %d ticks\n",
priv->reg30_ticks);
priv->reg30_good = 0; priv->reg30_good = 0;
layer1_state(xpd, 0); layer1_state(xpd, 0);
} }
@ -968,7 +987,8 @@ static int BRI_card_tick(xbus_t *xbus, xpd_t *xpd)
return 0; return 0;
} }
static int BRI_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg) static int BRI_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd,
unsigned long arg)
{ {
BUG_ON(!xpd); BUG_ON(!xpd);
if (!XBUS_IS(xpd->xbus, READY)) if (!XBUS_IS(xpd->xbus, READY))
@ -1043,14 +1063,10 @@ static int bri_spanconfig(struct file *file, struct dahdi_span *span,
/* E1's can enable CRC checking */ /* E1's can enable CRC checking */
if (lc->lineconfig & DAHDI_CONFIG_CRC4) if (lc->lineconfig & DAHDI_CONFIG_CRC4)
crcstr = "CRC4"; crcstr = "CRC4";
XPD_DBG(GENERAL, xpd, "[%s]: span=%d (%s) lbo=%d lineconfig=%s/%s/%s (0x%X) sync=%d\n", XPD_DBG(GENERAL, xpd,
IS_NT(xpd)?"NT":"TE", "[%s]: span=%d (%s) lbo=%d lineconfig=%s/%s/%s (0x%X) sync=%d\n",
lc->span, IS_NT(xpd) ? "NT" : "TE", lc->span, lc->name, lc->lbo,
lc->name, framingstr, codingstr, crcstr, lc->lineconfig, lc->sync);
lc->lbo,
framingstr, codingstr, crcstr,
lc->lineconfig,
lc->sync);
PHONEDEV(xpd).timing_priority = lc->sync; PHONEDEV(xpd).timing_priority = lc->sync;
elect_syncer("BRI-spanconfig"); elect_syncer("BRI-spanconfig");
/* /*
@ -1068,7 +1084,8 @@ static int bri_spanconfig(struct file *file, struct dahdi_span *span,
static int bri_chanconfig(struct file *file, struct dahdi_chan *chan, static int bri_chanconfig(struct file *file, struct dahdi_chan *chan,
int sigtype) int sigtype)
{ {
DBG(GENERAL, "channel %d (%s) -> %s\n", chan->channo, chan->name, sig2str(sigtype)); DBG(GENERAL, "channel %d (%s) -> %s\n", chan->channo, chan->name,
sig2str(sigtype));
// FIXME: sanity checks: // FIXME: sanity checks:
// - should be supported (within the sigcap) // - should be supported (within the sigcap)
// - should not replace fxs <->fxo ??? (covered by previous?) // - should not replace fxs <->fxo ??? (covered by previous?)
@ -1089,7 +1106,8 @@ static int bri_startup(struct file *file, struct dahdi_span *span)
priv = xpd->priv; priv = xpd->priv;
BUG_ON(!priv); BUG_ON(!priv);
if (!XBUS_IS(xpd->xbus, READY)) { if (!XBUS_IS(xpd->xbus, READY)) {
XPD_DBG(GENERAL, xpd, "Startup called by dahdi. No Hardware. Ignored\n"); XPD_DBG(GENERAL, xpd,
"Startup called by dahdi. No Hardware. Ignored\n");
return -ENODEV; return -ENODEV;
} }
XPD_DBG(GENERAL, xpd, "STARTUP\n"); XPD_DBG(GENERAL, xpd, "STARTUP\n");
@ -1122,7 +1140,8 @@ static int bri_shutdown(struct dahdi_span *span)
priv = xpd->priv; priv = xpd->priv;
BUG_ON(!priv); BUG_ON(!priv);
if (!XBUS_IS(xpd->xbus, READY)) { if (!XBUS_IS(xpd->xbus, READY)) {
XPD_DBG(GENERAL, xpd, "Shutdown called by dahdi. No Hardware. Ignored\n"); XPD_DBG(GENERAL, xpd,
"Shutdown called by dahdi. No Hardware. Ignored\n");
return -ENODEV; return -ENODEV;
} }
XPD_DBG(GENERAL, xpd, "SHUTDOWN\n"); XPD_DBG(GENERAL, xpd, "SHUTDOWN\n");
@ -1131,8 +1150,7 @@ static int bri_shutdown(struct dahdi_span *span)
return 0; return 0;
} }
static void BRI_card_pcm_recompute(xpd_t *xpd, static void BRI_card_pcm_recompute(xpd_t *xpd, xpp_line_t dont_care)
xpp_line_t dont_care)
{ {
int i; int i;
int line_count; int line_count;
@ -1144,7 +1162,8 @@ static void BRI_card_pcm_recompute(xpd_t *xpd,
BUG_ON(!xpd); BUG_ON(!xpd);
main_xpd = xpd_byaddr(xpd->xbus, xpd->addr.unit, 0); main_xpd = xpd_byaddr(xpd->xbus, xpd->addr.unit, 0);
if (!main_xpd) { if (!main_xpd) {
XPD_DBG(DEVICES, xpd, "Unit 0 is already gone. Ignore request\n"); XPD_DBG(DEVICES, xpd,
"Unit 0 is already gone. Ignore request\n");
return; return;
} }
/* /*
@ -1159,7 +1178,9 @@ static void BRI_card_pcm_recompute(xpd_t *xpd,
if (sub_xpd) { if (sub_xpd) {
xpp_line_t lines = xpp_line_t lines =
PHONEDEV(sub_xpd).offhook_state & ~(PHONEDEV(sub_xpd).digital_signalling); PHONEDEV(sub_xpd).
offhook_state & ~(PHONEDEV(sub_xpd).
digital_signalling);
if (lines) { if (lines) {
pcm_mask |= PCM_SHIFT(lines, i); pcm_mask |= PCM_SHIFT(lines, i);
@ -1183,8 +1204,8 @@ static void BRI_card_pcm_recompute(xpd_t *xpd,
* The main unit account for all subunits (pcm_len and wanted_pcm_mask). * The main unit account for all subunits (pcm_len and wanted_pcm_mask).
*/ */
pcm_len = (line_count) pcm_len = (line_count)
? RPACKET_HEADERSIZE + sizeof(xpp_line_t) + line_count * DAHDI_CHUNKSIZE ? RPACKET_HEADERSIZE + sizeof(xpp_line_t) +
: 0L; line_count * DAHDI_CHUNKSIZE : 0L;
update_wanted_pcm_mask(main_xpd, pcm_mask, pcm_len); update_wanted_pcm_mask(main_xpd, pcm_mask, pcm_len);
spin_unlock_irqrestore(&PHONEDEV(main_xpd).lock_recompute_pcm, flags); spin_unlock_irqrestore(&PHONEDEV(main_xpd).lock_recompute_pcm, flags);
} }
@ -1198,7 +1219,6 @@ static void BRI_card_pcm_fromspan(xpd_t *xpd, xpacket_t *pack)
xpp_line_t pcm_mask = 0; xpp_line_t pcm_mask = 0;
xpp_line_t wanted_lines; xpp_line_t wanted_lines;
BUG_ON(!xpd); BUG_ON(!xpd);
BUG_ON(!pack); BUG_ON(!pack);
pcm = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, pcm); pcm = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, pcm);
@ -1219,12 +1239,16 @@ static void BRI_card_pcm_fromspan(xpd_t *xpd, xpacket_t *pack)
int channo = chan->channo; int channo = chan->channo;
if (pcmtx >= 0 && pcmtx_chan == channo) if (pcmtx >= 0 && pcmtx_chan == channo)
memset((u_char *)pcm, pcmtx, DAHDI_CHUNKSIZE); memset((u_char *)pcm, pcmtx,
DAHDI_CHUNKSIZE);
else else
#endif #endif
memcpy((u_char *)pcm, chan->writechunk, DAHDI_CHUNKSIZE); memcpy((u_char *)pcm,
chan->writechunk,
DAHDI_CHUNKSIZE);
} else } else
memset((u_char *)pcm, 0x7F, DAHDI_CHUNKSIZE); memset((u_char *)pcm, 0x7F,
DAHDI_CHUNKSIZE);
pcm += DAHDI_CHUNKSIZE; pcm += DAHDI_CHUNKSIZE;
} }
} }
@ -1252,13 +1276,15 @@ static void BRI_card_pcm_tospan(xpd_t *xpd, xpacket_t *pack)
return; return;
pcm = RPACKET_FIELD(pack, GLOBAL, PCM_READ, pcm); pcm = RPACKET_FIELD(pack, GLOBAL, PCM_READ, pcm);
pcm_mask = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines); pcm_mask = RPACKET_FIELD(pack, GLOBAL, PCM_WRITE, lines);
for (subunit = 0; subunit < MAX_SUBUNIT; subunit++, pcm_mask >>= SUBUNIT_PCM_SHIFT) { for (subunit = 0; subunit < MAX_SUBUNIT;
subunit++, pcm_mask >>= SUBUNIT_PCM_SHIFT) {
xpd_t *tmp_xpd; xpd_t *tmp_xpd;
if (!pcm_mask) if (!pcm_mask)
break; /* optimize */ break; /* optimize */
tmp_xpd = xpd_byaddr(xpd->xbus, xpd->addr.unit, subunit); tmp_xpd = xpd_byaddr(xpd->xbus, xpd->addr.unit, subunit);
if (!tmp_xpd || !tmp_xpd->card_present || !SPAN_REGISTERED(tmp_xpd)) if (!tmp_xpd || !tmp_xpd->card_present
|| !SPAN_REGISTERED(tmp_xpd))
continue; continue;
spin_lock_irqsave(&tmp_xpd->lock, flags); spin_lock_irqsave(&tmp_xpd->lock, flags);
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {
@ -1319,7 +1345,8 @@ static int BRI_echocancel_setmask(xpd_t *xpd, xpp_line_t ec_mask)
/*---------------- BRI: HOST COMMANDS -------------------------------------*/ /*---------------- BRI: HOST COMMANDS -------------------------------------*/
static /* 0x33 */ HOSTCMD(BRI, SET_LED, enum bri_led_names which_led, enum led_state to_led_state) static /* 0x33 */ HOSTCMD(BRI, SET_LED, enum bri_led_names which_led,
enum led_state to_led_state)
{ {
int ret = 0; int ret = 0;
xframe_t *xframe; xframe_t *xframe;
@ -1330,8 +1357,7 @@ static /* 0x33 */ HOSTCMD(BRI, SET_LED, enum bri_led_names which_led, enum led_s
BUG_ON(!xbus); BUG_ON(!xbus);
priv = xpd->priv; priv = xpd->priv;
BUG_ON(!priv); BUG_ON(!priv);
XPD_DBG(LEDS, xpd, "%s -> %d\n", XPD_DBG(LEDS, xpd, "%s -> %d\n", (which_led) ? "RED" : "GREEN",
(which_led)?"RED":"GREEN",
to_led_state); to_led_state);
XFRAME_NEW_CMD(xframe, pack, xbus, BRI, SET_LED, xpd->xbus_idx); XFRAME_NEW_CMD(xframe, pack, xbus, BRI, SET_LED, xpd->xbus_idx);
bri_leds = &RPACKET_FIELD(pack, BRI, SET_LED, bri_leds); bri_leds = &RPACKET_FIELD(pack, BRI, SET_LED, bri_leds);
@ -1348,8 +1374,7 @@ static int write_state_register(xpd_t *xpd, __u8 value)
int ret; int ret;
XPD_DBG(REGS, xpd, "value = 0x%02X\n", value); XPD_DBG(REGS, xpd, "value = 0x%02X\n", value);
ret = xpp_register_request(xpd->xbus, xpd, ret = xpp_register_request(xpd->xbus, xpd, BRI_PORT(xpd), /* portno */
BRI_PORT(xpd), /* portno */
1, /* writing */ 1, /* writing */
A_SU_WR_STA, /* regnum */ A_SU_WR_STA, /* regnum */
0, /* do_subreg */ 0, /* do_subreg */
@ -1384,11 +1409,8 @@ static void su_new_state(xpd_t *xpd, __u8 reg_x30)
if (priv->state_register.bits.v_su_sta == new_state.bits.v_su_sta) if (priv->state_register.bits.v_su_sta == new_state.bits.v_su_sta)
return; /* same same */ return; /* same same */
XPD_DBG(SIGNAL, xpd, "%02X ---> %02X (info0=%d) (%s%i)\n", XPD_DBG(SIGNAL, xpd, "%02X ---> %02X (info0=%d) (%s%i)\n",
priv->state_register.reg, priv->state_register.reg, reg_x30, new_state.bits.v_su_info0,
reg_x30, IS_NT(xpd) ? "G" : "F", new_state.bits.v_su_sta);
new_state.bits.v_su_info0,
IS_NT(xpd)?"G":"F",
new_state.bits.v_su_sta);
if (!IS_NT(xpd)) { if (!IS_NT(xpd)) {
switch (new_state.bits.v_su_sta) { switch (new_state.bits.v_su_sta) {
case ST_TE_DEACTIVATED: /* F3 */ case ST_TE_DEACTIVATED: /* F3 */
@ -1421,7 +1443,8 @@ static void su_new_state(xpd_t *xpd, __u8 reg_x30)
layer1_state(xpd, 0); layer1_state(xpd, 0);
break; break;
default: default:
XPD_NOTICE(xpd, "Bad TE state: %d\n", new_state.bits.v_su_sta); XPD_NOTICE(xpd, "Bad TE state: %d\n",
new_state.bits.v_su_sta);
break; break;
} }
@ -1453,7 +1476,8 @@ static void su_new_state(xpd_t *xpd, __u8 reg_x30)
layer1_state(xpd, 0); layer1_state(xpd, 0);
break; break;
default: default:
XPD_NOTICE(xpd, "Bad NT state: %d\n", new_state.bits.v_su_sta); XPD_NOTICE(xpd, "Bad NT state: %d\n",
new_state.bits.v_su_sta);
break; break;
} }
} }
@ -1477,7 +1501,7 @@ static int BRI_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info)
static int rate_limit; static int rate_limit;
if ((rate_limit++ % 1003) < 5) if ((rate_limit++ % 1003) < 5)
notify_bad_xpd(__func__, xbus, addr , orig_xpd->xpdname); notify_bad_xpd(__func__, xbus, addr, orig_xpd->xpdname);
return -EPROTO; return -EPROTO;
} }
spin_lock_irqsave(&xpd->lock, flags); spin_lock_irqsave(&xpd->lock, flags);
@ -1485,11 +1509,13 @@ static int BRI_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info)
BUG_ON(!priv); BUG_ON(!priv);
if (REG_FIELD(info, do_subreg)) { if (REG_FIELD(info, do_subreg)) {
XPD_DBG(REGS, xpd, "RI %02X %02X %02X\n", XPD_DBG(REGS, xpd, "RI %02X %02X %02X\n",
REG_FIELD(info, regnum), REG_FIELD(info, subreg), REG_FIELD(info, data_low)); REG_FIELD(info, regnum), REG_FIELD(info, subreg),
REG_FIELD(info, data_low));
} else { } else {
if (REG_FIELD(info, regnum) != A_SU_RD_STA) if (REG_FIELD(info, regnum) != A_SU_RD_STA)
XPD_DBG(REGS, xpd, "RD %02X %02X\n", XPD_DBG(REGS, xpd, "RD %02X %02X\n",
REG_FIELD(info, regnum), REG_FIELD(info, data_low)); REG_FIELD(info, regnum), REG_FIELD(info,
data_low));
else else
XPD_DBG(REGS, xpd, "Got SU_RD_STA=%02X\n", XPD_DBG(REGS, xpd, "Got SU_RD_STA=%02X\n",
REG_FIELD(info, data_low)); REG_FIELD(info, data_low));
@ -1501,7 +1527,8 @@ static int BRI_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info)
if (ret < 0) { if (ret < 0) {
priv->dchan_rx_drops++; priv->dchan_rx_drops++;
if (atomic_read(&PHONEDEV(xpd).open_counter) > 0) if (atomic_read(&PHONEDEV(xpd).open_counter) > 0)
XPD_NOTICE(xpd, "Multibyte Drop: errno=%d\n", ret); XPD_NOTICE(xpd, "Multibyte Drop: errno=%d\n",
ret);
} }
goto end; goto end;
} }
@ -1510,10 +1537,11 @@ static int BRI_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info)
} }
/* Update /proc info only if reply relate to the last slic read request */ /* Update /proc info only if reply relate to the last slic read request */
if ( if (REG_FIELD(&xpd->requested_reply, regnum) == REG_FIELD(info, regnum)
REG_FIELD(&xpd->requested_reply, regnum) == REG_FIELD(info, regnum) && && REG_FIELD(&xpd->requested_reply, do_subreg) == REG_FIELD(info,
REG_FIELD(&xpd->requested_reply, do_subreg) == REG_FIELD(info, do_subreg) && do_subreg)
REG_FIELD(&xpd->requested_reply, subreg) == REG_FIELD(info, subreg)) { && REG_FIELD(&xpd->requested_reply, subreg) == REG_FIELD(info,
subreg)) {
xpd->last_reply = *info; xpd->last_reply = *info;
} }
@ -1528,10 +1556,10 @@ static int BRI_card_state(xpd_t *xpd, bool on)
BUG_ON(!xpd); BUG_ON(!xpd);
priv = xpd->priv; priv = xpd->priv;
XPD_DBG(GENERAL, xpd, "%s\n", (on)?"ON":"OFF"); XPD_DBG(GENERAL, xpd, "%s\n", (on) ? "ON" : "OFF");
if (on) { if (on) {
if (!test_bit(HFC_L1_ACTIVATED, &priv->l1_flags)) { if (!test_bit(HFC_L1_ACTIVATED, &priv->l1_flags)) {
if ( ! IS_NT(xpd)) if (!IS_NT(xpd))
te_activation(xpd, 1); te_activation(xpd, 1);
else else
nt_activation(xpd, 1); nt_activation(xpd, 1);
@ -1566,18 +1594,12 @@ static const struct phoneops bri_phoneops = {
}; };
static xproto_table_t PROTO_TABLE(BRI) = { static xproto_table_t PROTO_TABLE(BRI) = {
.owner = THIS_MODULE, .owner = THIS_MODULE,.entries = {
.entries = {
/* Table Card Opcode */ /* Table Card Opcode */
}, },.name = "BRI", /* protocol name */
.name = "BRI", /* protocol name */ .ports_per_subunit = 1,.type = XPD_TYPE_BRI,.xops =
.ports_per_subunit = 1, &bri_xops,.phoneops = &bri_phoneops,.packet_is_valid =
.type = XPD_TYPE_BRI, bri_packet_is_valid,.packet_dump = bri_packet_dump,};
.xops = &bri_xops,
.phoneops = &bri_phoneops,
.packet_is_valid = bri_packet_is_valid,
.packet_dump = bri_packet_dump,
};
static bool bri_packet_is_valid(xpacket_t *pack) static bool bri_packet_is_valid(xpacket_t *pack)
{ {
@ -1591,10 +1613,12 @@ static void bri_packet_dump(const char *msg, xpacket_t *pack)
{ {
DBG(GENERAL, "%s\n", msg); DBG(GENERAL, "%s\n", msg);
} }
/*------------------------- REGISTER Handling --------------------------*/ /*------------------------- REGISTER Handling --------------------------*/
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
static int proc_bri_info_read(char *page, char **start, off_t off, int count, int *eof, void *data) static int proc_bri_info_read(char *page, char **start, off_t off, int count,
int *eof, void *data)
{ {
int len = 0; int len = 0;
unsigned long flags; unsigned long flags;
@ -1609,11 +1633,16 @@ static int proc_bri_info_read(char *page, char **start, off_t off, int count, in
BUG_ON(!priv); BUG_ON(!priv);
len += sprintf(page + len, "%05d Layer 1: ", priv->poll_counter); len += sprintf(page + len, "%05d Layer 1: ", priv->poll_counter);
if (priv->reg30_good) { if (priv->reg30_good) {
len += sprintf(page + len, "%-5s ", (priv->layer1_up) ? "UP" : "DOWN"); len +=
len += sprintf(page + len, "%c%d %-15s -- fr_sync=%d t2_exp=%d info0=%d g2_g3=%d\n", sprintf(page + len, "%-5s ",
IS_NT(xpd)?'G':'F', (priv->layer1_up) ? "UP" : "DOWN");
len +=
sprintf(page + len,
"%c%d %-15s -- fr_sync=%d t2_exp=%d info0=%d g2_g3=%d\n",
IS_NT(xpd) ? 'G' : 'F',
priv->state_register.bits.v_su_sta, priv->state_register.bits.v_su_sta,
xhfc_state_name(IS_NT(xpd), priv->state_register.bits.v_su_sta), xhfc_state_name(IS_NT(xpd),
priv->state_register.bits.v_su_sta),
priv->state_register.bits.v_su_fr_sync, priv->state_register.bits.v_su_fr_sync,
priv->state_register.bits.v_su_t2_exp, priv->state_register.bits.v_su_t2_exp,
priv->state_register.bits.v_su_info0, priv->state_register.bits.v_su_info0,
@ -1626,24 +1655,37 @@ static int proc_bri_info_read(char *page, char **start, off_t off, int count, in
len += sprintf(page + len, "T3 Timer: %d\n", priv->t3); len += sprintf(page + len, "T3 Timer: %d\n", priv->t3);
} }
len += sprintf(page + len, "Tick Counter: %d\n", priv->tick_counter); len += sprintf(page + len, "Tick Counter: %d\n", priv->tick_counter);
len += sprintf(page + len, "Last Poll Reply: %d ticks ago\n", priv->reg30_ticks); len +=
sprintf(page + len, "Last Poll Reply: %d ticks ago\n",
priv->reg30_ticks);
len += sprintf(page + len, "reg30_good=%d\n", priv->reg30_good); len += sprintf(page + len, "reg30_good=%d\n", priv->reg30_good);
len += sprintf(page + len, "D-Channel: TX=[%5d] RX=[%5d] BAD=[%5d] ", len +=
priv->dchan_tx_counter, priv->dchan_rx_counter, priv->dchan_rx_drops); sprintf(page + len, "D-Channel: TX=[%5d] RX=[%5d] BAD=[%5d] ",
priv->dchan_tx_counter, priv->dchan_rx_counter,
priv->dchan_rx_drops);
if (priv->dchan_alive) { if (priv->dchan_alive) {
len += sprintf(page + len, "(alive %d K-ticks)\n", len +=
priv->dchan_alive_ticks/1000); sprintf(page + len, "(alive %d K-ticks)\n",
priv->dchan_alive_ticks / 1000);
} else { } else {
len += sprintf(page + len, "(dead)\n"); len += sprintf(page + len, "(dead)\n");
} }
len += sprintf(page + len, "dchan_notx_ticks: %d\n", priv->dchan_notx_ticks); len +=
len += sprintf(page + len, "dchan_norx_ticks: %d\n", priv->dchan_norx_ticks); sprintf(page + len, "dchan_notx_ticks: %d\n",
len += sprintf(page + len, "LED: %-10s = %d\n", "GREEN", priv->ledstate[GREEN_LED]); priv->dchan_notx_ticks);
len += sprintf(page + len, "LED: %-10s = %d\n", "RED", priv->ledstate[RED_LED]); len +=
sprintf(page + len, "dchan_norx_ticks: %d\n",
priv->dchan_norx_ticks);
len +=
sprintf(page + len, "LED: %-10s = %d\n", "GREEN",
priv->ledstate[GREEN_LED]);
len +=
sprintf(page + len, "LED: %-10s = %d\n", "RED",
priv->ledstate[RED_LED]);
len += sprintf(page + len, "\nDCHAN:\n"); len += sprintf(page + len, "\nDCHAN:\n");
len += sprintf(page + len, "\n"); len += sprintf(page + len, "\n");
spin_unlock_irqrestore(&xpd->lock, flags); spin_unlock_irqrestore(&xpd->lock, flags);
if (len <= off+count) if (len <= off + count)
*eof = 1; *eof = 1;
*start = page + off; *start = page + off;
len -= off; len -= off;
@ -1662,8 +1704,8 @@ static int bri_xpd_probe(struct device *dev)
xpd = dev_to_xpd(dev); xpd = dev_to_xpd(dev);
/* Is it our device? */ /* Is it our device? */
if (xpd->type != XPD_TYPE_BRI) { if (xpd->type != XPD_TYPE_BRI) {
XPD_ERR(xpd, "drop suggestion for %s (%d)\n", XPD_ERR(xpd, "drop suggestion for %s (%d)\n", dev_name(dev),
dev_name(dev), xpd->type); xpd->type);
return -EINVAL; return -EINVAL;
} }
XPD_DBG(DEVICES, xpd, "SYSFS\n"); XPD_DBG(DEVICES, xpd, "SYSFS\n");
@ -1687,8 +1729,7 @@ static struct xpd_driver bri_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
#endif #endif
.probe = bri_xpd_probe, .probe = bri_xpd_probe,
.remove = bri_xpd_remove .remove = bri_xpd_remove}
}
}; };
static int __init card_bri_startup(void) static int __init card_bri_startup(void)

View File

@ -42,14 +42,9 @@ static DEF_PARM(int, debug, 0, 0644, "Print DBG statements");
static bool echo_packet_is_valid(xpacket_t *pack); static bool echo_packet_is_valid(xpacket_t *pack);
static void echo_packet_dump(const char *msg, xpacket_t *pack); static void echo_packet_dump(const char *msg, xpacket_t *pack);
DEF_RPACKET_DATA(ECHO, SET, DEF_RPACKET_DATA(ECHO, SET, __u8 timeslots[ECHO_TIMESLOTS];);
__u8 timeslots[ECHO_TIMESLOTS];
);
DEF_RPACKET_DATA(ECHO, SET_REPLY, DEF_RPACKET_DATA(ECHO, SET_REPLY, __u8 status; __u8 reserved;);
__u8 status;
__u8 reserved;
);
struct ECHO_priv_data { struct ECHO_priv_data {
}; };
@ -70,7 +65,8 @@ static xpd_t *ECHO_card_new(xbus_t *xbus, int unit, int subunit,
return NULL; return NULL;
} }
XBUS_DBG(GENERAL, xbus, "\n"); XBUS_DBG(GENERAL, xbus, "\n");
xpd = xpd_alloc(xbus, unit, subunit, subtype, subunits, xpd =
xpd_alloc(xbus, unit, subunit, subtype, subunits,
sizeof(struct ECHO_priv_data), proto_table, channels); sizeof(struct ECHO_priv_data), proto_table, channels);
if (!xpd) if (!xpd)
return NULL; return NULL;
@ -122,19 +118,16 @@ static int ECHO_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info)
static int rate_limit; static int rate_limit;
if ((rate_limit++ % 1003) < 5) if ((rate_limit++ % 1003) < 5)
notify_bad_xpd(__func__, xbus, addr, notify_bad_xpd(__func__, xbus, addr, orig_xpd->xpdname);
orig_xpd->xpdname);
return -EPROTO; return -EPROTO;
} }
spin_lock_irqsave(&xpd->lock, flags); spin_lock_irqsave(&xpd->lock, flags);
/* Update /proc info only if reply related to last reg read request */ /* Update /proc info only if reply related to last reg read request */
if ( if (REG_FIELD(&xpd->requested_reply, regnum) == REG_FIELD(info, regnum)
REG_FIELD(&xpd->requested_reply, regnum) == && REG_FIELD(&xpd->requested_reply, do_subreg) == REG_FIELD(info,
REG_FIELD(info, regnum) && do_subreg)
REG_FIELD(&xpd->requested_reply, do_subreg) == && REG_FIELD(&xpd->requested_reply, subreg) == REG_FIELD(info,
REG_FIELD(info, do_subreg) && subreg)) {
REG_FIELD(&xpd->requested_reply, subreg) ==
REG_FIELD(info, subreg)) {
xpd->last_reply = *info; xpd->last_reply = *info;
} }
spin_unlock_irqrestore(&xpd->lock, flags); spin_unlock_irqrestore(&xpd->lock, flags);
@ -236,11 +229,10 @@ static void ECHO_ec_dump(xbus_t *xbus)
"EC-DUMP[%03d]: " "EC-DUMP[%03d]: "
"0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X " "0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X "
"0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\n", "0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X 0x%02X\n",
i, i, ts[i + 0], ts[i + 1], ts[i + 2], ts[i + 3],
ts[i+0], ts[i+1], ts[i+2], ts[i+3], ts[i+4], ts[i+5], ts[i + 4], ts[i + 5], ts[i + 6], ts[i + 7], ts[i + 8],
ts[i+6], ts[i+7], ts[i + 9], ts[i + 10], ts[i + 11], ts[i + 12],
ts[i+8], ts[i+9], ts[i+10], ts[i+11], ts[i+12], ts[i + 13], ts[i + 14], ts[i + 15]
ts[i+13], ts[i+14], ts[i+15]
); );
} }
} }
@ -279,19 +271,12 @@ static const struct echoops echoops = {
}; };
static xproto_table_t PROTO_TABLE(ECHO) = { static xproto_table_t PROTO_TABLE(ECHO) = {
.owner = THIS_MODULE, .owner = THIS_MODULE,.entries = {
.entries = {
/* Table Card Opcode */ /* Table Card Opcode */
XENTRY(ECHO, ECHO, SET_REPLY), XENTRY(ECHO, ECHO, SET_REPLY),},.name = "ECHO",.ports_per_subunit =
}, 1,.type = XPD_TYPE_ECHO,.xops = &echo_xops,.echoops =
.name = "ECHO", &echoops,.packet_is_valid =
.ports_per_subunit = 1, echo_packet_is_valid,.packet_dump = echo_packet_dump,};
.type = XPD_TYPE_ECHO,
.xops = &echo_xops,
.echoops = &echoops,
.packet_is_valid = echo_packet_is_valid,
.packet_dump = echo_packet_dump,
};
static bool echo_packet_is_valid(xpacket_t *pack) static bool echo_packet_is_valid(xpacket_t *pack)
{ {
@ -315,8 +300,8 @@ static int echo_xpd_probe(struct device *dev)
ec_xpd = dev_to_xpd(dev); ec_xpd = dev_to_xpd(dev);
/* Is it our device? */ /* Is it our device? */
if (ec_xpd->type != XPD_TYPE_ECHO) { if (ec_xpd->type != XPD_TYPE_ECHO) {
XPD_ERR(ec_xpd, "drop suggestion for %s (%d)\n", XPD_ERR(ec_xpd, "drop suggestion for %s (%d)\n", dev_name(dev),
dev_name(dev), ec_xpd->type); ec_xpd->type);
return -EINVAL; return -EINVAL;
} }
XPD_DBG(DEVICES, ec_xpd, "SYSFS\n"); XPD_DBG(DEVICES, ec_xpd, "SYSFS\n");
@ -340,8 +325,7 @@ static struct xpd_driver echo_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
#endif #endif
.probe = echo_xpd_probe, .probe = echo_xpd_probe,
.remove = echo_xpd_remove .remove = echo_xpd_remove}
}
}; };
static int __init card_echo_startup(void) static int __init card_echo_startup(void)

View File

@ -34,16 +34,24 @@
static const char rcsid[] = "$Id$"; static const char rcsid[] = "$Id$";
static DEF_PARM(int, debug, 0, 0644, "Print DBG statements"); static DEF_PARM(int, debug, 0, 0644, "Print DBG statements");
static DEF_PARM(uint, poll_battery_interval, 500, 0644, "Poll battery interval in milliseconds (0 - disable)"); static DEF_PARM(uint, poll_battery_interval, 500, 0644,
"Poll battery interval in milliseconds (0 - disable)");
#ifdef WITH_METERING #ifdef WITH_METERING
static DEF_PARM(uint, poll_metering_interval, 500, 0644, "Poll metering interval in milliseconds (0 - disable)"); static DEF_PARM(uint, poll_metering_interval, 500, 0644,
"Poll metering interval in milliseconds (0 - disable)");
#endif #endif
static DEF_PARM(int, ring_debounce, 50, 0644, "Number of ticks to debounce a false RING indication"); static DEF_PARM(int, ring_debounce, 50, 0644,
static DEF_PARM(int, caller_id_style, 0, 0444, "Caller-Id detection style: 0 - [BELL], 1 - [ETSI_FSK], 2 - [ETSI_DTMF]"); "Number of ticks to debounce a false RING indication");
static DEF_PARM(int, power_denial_safezone, 650, 0644, "msec after offhook to ignore power-denial ( (0 - disable power-denial)"); static DEF_PARM(int, caller_id_style, 0, 0444,
static DEF_PARM(int, power_denial_minlen, 80, 0644, "Minimal detected power-denial length (msec) (0 - disable power-denial)"); "Caller-Id detection style: 0 - [BELL], 1 - [ETSI_FSK], 2 - [ETSI_DTMF]");
static DEF_PARM(uint, battery_threshold, 3, 0644, "Minimum voltage that shows there is battery"); static DEF_PARM(int, power_denial_safezone, 650, 0644,
static DEF_PARM(uint, battery_debounce, 1000, 0644, "Minimum interval (msec) for detection of battery off"); "msec after offhook to ignore power-denial ( (0 - disable power-denial)");
static DEF_PARM(int, power_denial_minlen, 80, 0644,
"Minimal detected power-denial length (msec) (0 - disable power-denial)");
static DEF_PARM(uint, battery_threshold, 3, 0644,
"Minimum voltage that shows there is battery");
static DEF_PARM(uint, battery_debounce, 1000, 0644,
"Minimum interval (msec) for detection of battery off");
enum cid_style { enum cid_style {
CID_STYLE_BELL = 0, /* E.g: US (Bellcore) */ CID_STYLE_BELL = 0, /* E.g: US (Bellcore) */
@ -86,9 +94,11 @@ enum fxo_leds {
static bool fxo_packet_is_valid(xpacket_t *pack); static bool fxo_packet_is_valid(xpacket_t *pack);
static void fxo_packet_dump(const char *msg, xpacket_t *pack); static void fxo_packet_dump(const char *msg, xpacket_t *pack);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
static int proc_fxo_info_read(char *page, char **start, off_t off, int count, int *eof, void *data); static int proc_fxo_info_read(char *page, char **start, off_t off, int count,
int *eof, void *data);
#ifdef WITH_METERING #ifdef WITH_METERING
static int proc_xpd_metering_read(char *page, char **start, off_t off, int count, int *eof, void *data); static int proc_xpd_metering_read(char *page, char **start, off_t off,
int count, int *eof, void *data);
#endif #endif
#endif #endif
static void dahdi_report_battery(xpd_t *xpd, lineno_t chan); static void dahdi_report_battery(xpd_t *xpd, lineno_t chan);
@ -170,9 +180,12 @@ struct FXO_priv_data {
static const char *power2str(enum power_state pw) static const char *power2str(enum power_state pw)
{ {
switch (pw) { switch (pw) {
case POWER_UNKNOWN: return "UNKNOWN"; case POWER_UNKNOWN:
case POWER_OFF: return "OFF"; return "UNKNOWN";
case POWER_ON: return "ON"; case POWER_OFF:
return "OFF";
case POWER_ON:
return "ON";
} }
return NULL; return NULL;
} }
@ -183,8 +196,7 @@ static void power_change(xpd_t *xpd, int portno, enum power_state pw)
priv = xpd->priv; priv = xpd->priv;
LINE_DBG(SIGNAL, xpd, portno, "power: %s -> %s\n", LINE_DBG(SIGNAL, xpd, portno, "power: %s -> %s\n",
power2str(priv->power[portno]), power2str(priv->power[portno]), power2str(pw));
power2str(pw));
priv->power[portno] = pw; priv->power[portno] = pw;
} }
@ -213,7 +225,8 @@ static int do_led(xpd_t *xpd, lineno_t chan, __u8 which, bool on)
xbus = xpd->xbus; xbus = xpd->xbus;
priv = xpd->priv; priv = xpd->priv;
which = which % NUM_LEDS; which = which % NUM_LEDS;
if (IS_SET(PHONEDEV(xpd).digital_outputs, chan) || IS_SET(PHONEDEV(xpd).digital_inputs, chan)) if (IS_SET(PHONEDEV(xpd).digital_outputs, chan)
|| IS_SET(PHONEDEV(xpd).digital_inputs, chan))
goto out; goto out;
if (chan == PORT_BROADCAST) { if (chan == PORT_BROADCAST) {
priv->ledstate[which] = (on) ? ~0 : 0; priv->ledstate[which] = (on) ? ~0 : 0;
@ -228,7 +241,8 @@ static int do_led(xpd_t *xpd, lineno_t chan, __u8 which, bool on)
value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_register_mask[which]); value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_register_mask[which]);
value |= (on) ? BIT(0) : 0; value |= (on) ? BIT(0) : 0;
value |= (on) ? BIT(1) : 0; value |= (on) ? BIT(1) : 0;
LINE_DBG(LEDS, xpd, chan, "LED: which=%d -- %s\n", which, (on) ? "on" : "off"); LINE_DBG(LEDS, xpd, chan, "LED: which=%d -- %s\n", which,
(on) ? "on" : "off");
ret = DAA_DIRECT_REQUEST(xbus, xpd, chan, DAA_WRITE, 0x20, value); ret = DAA_DIRECT_REQUEST(xbus, xpd, chan, DAA_WRITE, 0x20, value);
out: out:
return ret; return ret;
@ -249,7 +263,8 @@ static void handle_fxo_leds(xpd_t *xpd)
timer_count = xpd->timer_count; timer_count = xpd->timer_count;
for (color = 0; color < ARRAY_SIZE(colors); color++) { for (color = 0; color < ARRAY_SIZE(colors); color++) {
for_each_line(xpd, i) { for_each_line(xpd, i) {
if (IS_SET(PHONEDEV(xpd).digital_outputs, i) || IS_SET(PHONEDEV(xpd).digital_inputs, i)) if (IS_SET(PHONEDEV(xpd).digital_outputs, i)
|| IS_SET(PHONEDEV(xpd).digital_inputs, i))
continue; continue;
if ((xpd->blink_mode & BIT(i)) || IS_BLINKING(priv, i, color)) { // Blinking if ((xpd->blink_mode & BIT(i)) || IS_BLINKING(priv, i, color)) { // Blinking
int mod_value = LED_COUNTER(priv, i, color); int mod_value = LED_COUNTER(priv, i, color);
@ -258,16 +273,21 @@ static void handle_fxo_leds(xpd_t *xpd)
mod_value = DEFAULT_LED_PERIOD; /* safety value */ mod_value = DEFAULT_LED_PERIOD; /* safety value */
// led state is toggled // led state is toggled
if ((timer_count % mod_value) == 0) { if ((timer_count % mod_value) == 0) {
LINE_DBG(LEDS, xpd, i, "ledstate=%s\n", (IS_SET(priv->ledstate[color], i))?"ON":"OFF"); LINE_DBG(LEDS, xpd, i, "ledstate=%s\n",
(IS_SET
(priv->ledstate[color],
i)) ? "ON" : "OFF");
if (!IS_SET(priv->ledstate[color], i)) { if (!IS_SET(priv->ledstate[color], i)) {
do_led(xpd, i, color, 1); do_led(xpd, i, color, 1);
} else { } else {
do_led(xpd, i, color, 0); do_led(xpd, i, color, 0);
} }
} }
} else if (IS_SET(priv->ledcontrol[color], i) && !IS_SET(priv->ledstate[color], i)) { } else if (IS_SET(priv->ledcontrol[color], i)
&& !IS_SET(priv->ledstate[color], i)) {
do_led(xpd, i, color, 1); do_led(xpd, i, color, 1);
} else if (!IS_SET(priv->ledcontrol[color], i) && IS_SET(priv->ledstate[color], i)) { } else if (!IS_SET(priv->ledcontrol[color], i)
&& IS_SET(priv->ledstate[color], i)) {
do_led(xpd, i, color, 0); do_led(xpd, i, color, 0);
} }
} }
@ -332,7 +352,8 @@ static int do_sethook(xpd_t *xpd, int pos, bool to_offhook)
priv = xpd->priv; priv = xpd->priv;
BUG_ON(!priv); BUG_ON(!priv);
if (priv->battery[pos] != BATTERY_ON && to_offhook) { if (priv->battery[pos] != BATTERY_ON && to_offhook) {
LINE_NOTICE(xpd, pos, "Cannot take offhook while battery is off!\n"); LINE_NOTICE(xpd, pos,
"Cannot take offhook while battery is off!\n");
return -EINVAL; return -EINVAL;
} }
spin_lock_irqsave(&xpd->lock, flags); spin_lock_irqsave(&xpd->lock, flags);
@ -340,12 +361,15 @@ static int do_sethook(xpd_t *xpd, int pos, bool to_offhook)
value = REG_DAA_CONTROL1_ONHM; /* Bit 3 is for CID */ value = REG_DAA_CONTROL1_ONHM; /* Bit 3 is for CID */
if (to_offhook) if (to_offhook)
value |= REG_DAA_CONTROL1_OH; value |= REG_DAA_CONTROL1_OH;
LINE_DBG(SIGNAL, xpd, pos, "SETHOOK: value=0x%02X %s\n", value, (to_offhook)?"OFFHOOK":"ONHOOK"); LINE_DBG(SIGNAL, xpd, pos, "SETHOOK: value=0x%02X %s\n", value,
(to_offhook) ? "OFFHOOK" : "ONHOOK");
if (to_offhook) if (to_offhook)
MARK_ON(priv, pos, LED_GREEN); MARK_ON(priv, pos, LED_GREEN);
else else
MARK_OFF(priv, pos, LED_GREEN); MARK_OFF(priv, pos, LED_GREEN);
ret = DAA_DIRECT_REQUEST(xbus, xpd, pos, DAA_WRITE, REG_DAA_CONTROL1, value); ret =
DAA_DIRECT_REQUEST(xbus, xpd, pos, DAA_WRITE, REG_DAA_CONTROL1,
value);
mark_offhook(xpd, pos, to_offhook); mark_offhook(xpd, pos, to_offhook);
if (caller_id_style != CID_STYLE_ETSI_DTMF) if (caller_id_style != CID_STYLE_ETSI_DTMF)
oht_pcm(xpd, pos, 0); oht_pcm(xpd, pos, 0);
@ -400,19 +424,24 @@ static int fxo_proc_create(xbus_t *xbus, xpd_t *xpd)
priv = xpd->priv; priv = xpd->priv;
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
XPD_DBG(PROC, xpd, "Creating FXO_INFO file\n"); XPD_DBG(PROC, xpd, "Creating FXO_INFO file\n");
priv->fxo_info = create_proc_read_entry(PROC_FXO_INFO_FNAME, 0444, xpd->proc_xpd_dir, proc_fxo_info_read, xpd); priv->fxo_info =
create_proc_read_entry(PROC_FXO_INFO_FNAME, 0444, xpd->proc_xpd_dir,
proc_fxo_info_read, xpd);
if (!priv->fxo_info) { if (!priv->fxo_info) {
XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_FXO_INFO_FNAME); XPD_ERR(xpd, "Failed to create proc file '%s'\n",
PROC_FXO_INFO_FNAME);
fxo_proc_remove(xbus, xpd); fxo_proc_remove(xbus, xpd);
return -EINVAL; return -EINVAL;
} }
SET_PROC_DIRENTRY_OWNER(priv->fxo_info); SET_PROC_DIRENTRY_OWNER(priv->fxo_info);
#ifdef WITH_METERING #ifdef WITH_METERING
XPD_DBG(PROC, xpd, "Creating Metering tone file\n"); XPD_DBG(PROC, xpd, "Creating Metering tone file\n");
priv->meteringfile = create_proc_read_entry(PROC_METERING_FNAME, 0444, xpd->proc_xpd_dir, priv->meteringfile =
create_proc_read_entry(PROC_METERING_FNAME, 0444, xpd->proc_xpd_dir,
proc_xpd_metering_read, xpd); proc_xpd_metering_read, xpd);
if (!priv->meteringfile) { if (!priv->meteringfile) {
XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_METERING_FNAME); XPD_ERR(xpd, "Failed to create proc file '%s'\n",
PROC_METERING_FNAME);
fxo_proc_remove(xbus, xpd); fxo_proc_remove(xbus, xpd);
return -EINVAL; return -EINVAL;
} }
@ -422,8 +451,9 @@ static int fxo_proc_create(xbus_t *xbus, xpd_t *xpd)
return 0; return 0;
} }
static xpd_t *FXO_card_new(xbus_t *xbus, int unit, int subunit, const xproto_table_t *proto_table, static xpd_t *FXO_card_new(xbus_t *xbus, int unit, int subunit,
__u8 subtype, int subunits, int subunit_ports, bool to_phone) const xproto_table_t *proto_table, __u8 subtype,
int subunits, int subunit_ports, bool to_phone)
{ {
xpd_t *xpd = NULL; xpd_t *xpd = NULL;
int channels; int channels;
@ -438,7 +468,9 @@ static xpd_t *FXO_card_new(xbus_t *xbus, int unit, int subunit, const xproto_tab
channels = min(2, subunit_ports); channels = min(2, subunit_ports);
else else
channels = min(8, subunit_ports); channels = min(8, subunit_ports);
xpd = xpd_alloc(xbus, unit, subunit, subtype, subunits, 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) if (!xpd)
return NULL; return NULL;
PHONEDEV(xpd).direction = TO_PSTN; PHONEDEV(xpd).direction = TO_PSTN;
@ -505,7 +537,7 @@ static int FXO_card_dahdi_preregistration(xpd_t *xpd, bool on)
priv = xpd->priv; priv = xpd->priv;
BUG_ON(!priv); BUG_ON(!priv);
timer_count = xpd->timer_count; timer_count = xpd->timer_count;
XPD_DBG(GENERAL, xpd, "%s\n", (on)?"ON":"OFF"); XPD_DBG(GENERAL, xpd, "%s\n", (on) ? "ON" : "OFF");
PHONEDEV(xpd).span.spantype = "FXO"; PHONEDEV(xpd).span.spantype = "FXO";
for_each_line(xpd, i) { for_each_line(xpd, i) {
struct dahdi_chan *cur_chan = XPD_CHAN(xpd, i); struct dahdi_chan *cur_chan = XPD_CHAN(xpd, i);
@ -539,7 +571,7 @@ static int FXO_card_dahdi_postregistration(xpd_t *xpd, bool on)
BUG_ON(!xbus); BUG_ON(!xbus);
priv = xpd->priv; priv = xpd->priv;
BUG_ON(!priv); BUG_ON(!priv);
XPD_DBG(GENERAL, xpd, "%s\n", (on)?"ON":"OFF"); XPD_DBG(GENERAL, xpd, "%s\n", (on) ? "ON" : "OFF");
for_each_line(xpd, i) { for_each_line(xpd, i) {
dahdi_report_battery(xpd, i); dahdi_report_battery(xpd, i);
MARK_OFF(priv, i, LED_GREEN); MARK_OFF(priv, i, LED_GREEN);
@ -589,11 +621,13 @@ static void dahdi_report_battery(xpd_t *xpd, lineno_t chan)
break; break;
case BATTERY_OFF: case BATTERY_OFF:
LINE_DBG(SIGNAL, xpd, chan, "Send DAHDI_ALARM_RED\n"); LINE_DBG(SIGNAL, xpd, chan, "Send DAHDI_ALARM_RED\n");
dahdi_alarm_channel(XPD_CHAN(xpd, chan), DAHDI_ALARM_RED); dahdi_alarm_channel(XPD_CHAN(xpd, chan),
DAHDI_ALARM_RED);
break; break;
case BATTERY_ON: case BATTERY_ON:
LINE_DBG(SIGNAL, xpd, chan, "Send DAHDI_ALARM_NONE\n"); LINE_DBG(SIGNAL, xpd, chan, "Send DAHDI_ALARM_NONE\n");
dahdi_alarm_channel(XPD_CHAN(xpd, chan), DAHDI_ALARM_NONE); dahdi_alarm_channel(XPD_CHAN(xpd, chan),
DAHDI_ALARM_NONE);
break; break;
} }
} }
@ -621,7 +655,8 @@ static void poll_metering(xbus_t *xbus, xpd_t *xpd)
for_each_line(xpd, i) { for_each_line(xpd, i) {
if (IS_OFFHOOK(xpd, i)) if (IS_OFFHOOK(xpd, i))
DAA_DIRECT_REQUEST(xbus, xpd, i, DAA_READ, DAA_REG_METERING, 0); DAA_DIRECT_REQUEST(xbus, xpd, i, DAA_READ,
DAA_REG_METERING, 0);
} }
} }
#endif #endif
@ -663,7 +698,8 @@ static void handle_fxo_power_denial(xpd_t *xpd)
/* /*
* Poll current, previous answers are meaningless * Poll current, previous answers are meaningless
*/ */
DAA_DIRECT_REQUEST(xpd->xbus, xpd, i, DAA_READ, DAA_REG_CURRENT, 0); DAA_DIRECT_REQUEST(xpd->xbus, xpd, i, DAA_READ,
DAA_REG_CURRENT, 0);
} }
continue; continue;
} }
@ -675,8 +711,10 @@ static void handle_fxo_power_denial(xpd_t *xpd)
* detected it yet). This would cause false power denials. * detected it yet). This would cause false power denials.
* So we just flag it and schedule more ticks to wait. * So we just flag it and schedule more ticks to wait.
*/ */
LINE_DBG(SIGNAL, xpd, i, "Possible Power Denial Hangup\n"); LINE_DBG(SIGNAL, xpd, i,
priv->power_denial_delay[i] = POWER_DENIAL_DELAY; "Possible Power Denial Hangup\n");
priv->power_denial_delay[i] =
POWER_DENIAL_DELAY;
} }
continue; continue;
} }
@ -688,7 +726,8 @@ static void handle_fxo_power_denial(xpd_t *xpd)
*/ */
priv->power_denial_delay[i]--; priv->power_denial_delay[i]--;
if (priv->power_denial_delay[i] <= 0) { if (priv->power_denial_delay[i] <= 0) {
LINE_DBG(SIGNAL, xpd, i, "Power Denial Hangup\n"); LINE_DBG(SIGNAL, xpd, i,
"Power Denial Hangup\n");
priv->power_denial_delay[i] = 0; priv->power_denial_delay[i] = 0;
/* /*
* Let Asterisk decide what to do * Let Asterisk decide what to do
@ -726,7 +765,8 @@ static void check_etsi_dtmf(xpd_t *xpd)
/* reset flags if it's been a while */ /* reset flags if it's been a while */
priv->cidtimer[portno] = timer_count; priv->cidtimer[portno] = timer_count;
BIT_CLR(priv->cidfound, portno); BIT_CLR(priv->cidfound, portno);
LINE_DBG(SIGNAL, xpd, portno, "Reset CID flag\n"); LINE_DBG(SIGNAL, xpd, portno,
"Reset CID flag\n");
} }
continue; continue;
} }
@ -740,8 +780,10 @@ static void check_etsi_dtmf(xpd_t *xpd)
if (sample > 16000 || sample < -16000) { if (sample > 16000 || sample < -16000) {
priv->cidtimer[portno] = timer_count; priv->cidtimer[portno] = timer_count;
BIT_SET(priv->cidfound, portno); BIT_SET(priv->cidfound, portno);
LINE_DBG(SIGNAL, xpd, portno, "Found DTMF CLIP (%d)\n", i); LINE_DBG(SIGNAL, xpd, portno,
dahdi_qevent_lock(chan, DAHDI_EVENT_POLARITY); "Found DTMF CLIP (%d)\n", i);
dahdi_qevent_lock(chan,
DAHDI_EVENT_POLARITY);
break; break;
} }
} }
@ -756,10 +798,12 @@ static int FXO_card_tick(xbus_t *xbus, xpd_t *xpd)
BUG_ON(!xpd); BUG_ON(!xpd);
priv = xpd->priv; priv = xpd->priv;
BUG_ON(!priv); BUG_ON(!priv);
if (poll_battery_interval != 0 && (priv->poll_counter % poll_battery_interval) == 0) if (poll_battery_interval != 0
&& (priv->poll_counter % poll_battery_interval) == 0)
poll_battery(xbus, xpd); poll_battery(xbus, xpd);
#ifdef WITH_METERING #ifdef WITH_METERING
if (poll_metering_interval != 0 && (priv->poll_counter % poll_metering_interval) == 0) if (poll_metering_interval != 0
&& (priv->poll_counter % poll_metering_interval) == 0)
poll_metering(xbus, xpd); poll_metering(xbus, xpd);
#endif #endif
handle_fxo_leds(xpd); handle_fxo_leds(xpd);
@ -777,9 +821,11 @@ static int FXO_card_tick(xbus_t *xbus, xpd_t *xpd)
* We define the array size explicitly to track possible inconsistencies * We define the array size explicitly to track possible inconsistencies
* if the struct is modified. * if the struct is modified.
*/ */
static const char echotune_regs[sizeof(struct wctdm_echo_coefs)] = {30, 45, 46, 47, 48, 49, 50, 51, 52}; static const char echotune_regs[sizeof(struct wctdm_echo_coefs)] =
{ 30, 45, 46, 47, 48, 49, 50, 51, 52 };
static int FXO_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg) static int FXO_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd,
unsigned long arg)
{ {
int i, ret; int i, ret;
unsigned char echotune_data[ARRAY_SIZE(echotune_regs)]; unsigned char echotune_data[ARRAY_SIZE(echotune_regs)];
@ -791,14 +837,20 @@ static int FXO_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
case WCTDM_SET_ECHOTUNE: case WCTDM_SET_ECHOTUNE:
XPD_DBG(GENERAL, xpd, "-- Setting echo registers: \n"); XPD_DBG(GENERAL, xpd, "-- Setting echo registers: \n");
/* first off: check if this span is fxs. If not: -EINVALID */ /* first off: check if this span is fxs. If not: -EINVALID */
if (copy_from_user(&echotune_data, (void __user *)arg, sizeof(echotune_data))) if (copy_from_user
(&echotune_data, (void __user *)arg, sizeof(echotune_data)))
return -EFAULT; return -EFAULT;
for (i = 0; i < ARRAY_SIZE(echotune_regs); i++) { for (i = 0; i < ARRAY_SIZE(echotune_regs); i++) {
XPD_DBG(REGS, xpd, "Reg=0x%02X, data=0x%02X\n", echotune_regs[i], echotune_data[i]); XPD_DBG(REGS, xpd, "Reg=0x%02X, data=0x%02X\n",
ret = DAA_DIRECT_REQUEST(xpd->xbus, xpd, pos, DAA_WRITE, echotune_regs[i], echotune_data[i]); echotune_regs[i], echotune_data[i]);
ret =
DAA_DIRECT_REQUEST(xpd->xbus, xpd, pos, DAA_WRITE,
echotune_regs[i],
echotune_data[i]);
if (ret < 0) { if (ret < 0) {
LINE_NOTICE(xpd, pos, "Couldn't write %0x02X to register %0x02X\n", LINE_NOTICE(xpd, pos,
"Couldn't write %0x02X to register %0x02X\n",
echotune_data[i], echotune_regs[i]); echotune_data[i], echotune_regs[i]);
return ret; return ret;
} }
@ -828,8 +880,10 @@ static int FXO_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
HANDLER_DEF(FXO, SIG_CHANGED) HANDLER_DEF(FXO, SIG_CHANGED)
{ {
xpp_line_t sig_status = RPACKET_FIELD(pack, FXO, SIG_CHANGED, sig_status); xpp_line_t sig_status =
xpp_line_t sig_toggles = RPACKET_FIELD(pack, FXO, SIG_CHANGED, sig_toggles); RPACKET_FIELD(pack, FXO, SIG_CHANGED, sig_status);
xpp_line_t sig_toggles =
RPACKET_FIELD(pack, FXO, SIG_CHANGED, sig_toggles);
unsigned long flags; unsigned long flags;
int i; int i;
struct FXO_priv_data *priv; struct FXO_priv_data *priv;
@ -840,7 +894,8 @@ HANDLER_DEF(FXO, SIG_CHANGED)
} }
priv = xpd->priv; priv = xpd->priv;
BUG_ON(!priv); BUG_ON(!priv);
XPD_DBG(SIGNAL, xpd, "(PSTN) sig_toggles=0x%04X sig_status=0x%04X\n", sig_toggles, sig_status); XPD_DBG(SIGNAL, xpd, "(PSTN) sig_toggles=0x%04X sig_status=0x%04X\n",
sig_toggles, sig_status);
spin_lock_irqsave(&xpd->lock, flags); spin_lock_irqsave(&xpd->lock, flags);
for_each_line(xpd, i) { for_each_line(xpd, i) {
int debounce; int debounce;
@ -851,18 +906,23 @@ HANDLER_DEF(FXO, SIG_CHANGED)
* With poll_battery_interval==0 we cannot have BATTERY_OFF * With poll_battery_interval==0 we cannot have BATTERY_OFF
* so we won't get here * so we won't get here
*/ */
LINE_NOTICE(xpd, i, "SIG_CHANGED while battery is off. Ignored.\n"); LINE_NOTICE(xpd, i,
"SIG_CHANGED while battery is off. Ignored.\n");
continue; continue;
} }
/* First report false ring alarms */ /* First report false ring alarms */
debounce = atomic_read(&priv->ring_debounce[i]); debounce = atomic_read(&priv->ring_debounce[i]);
if (debounce) if (debounce)
LINE_NOTICE(xpd, i, "debounced false ring (only %d ticks)\n", debounce); LINE_NOTICE(xpd, i,
"debounced false ring (only %d ticks)\n",
debounce);
/* /*
* Now set a new ring alarm. * Now set a new ring alarm.
* It will be checked in handle_fxo_ring() * It will be checked in handle_fxo_ring()
*/ */
debounce = (IS_SET(sig_status, i)) ? ring_debounce : -ring_debounce; debounce =
(IS_SET(sig_status, i)) ? ring_debounce :
-ring_debounce;
atomic_set(&priv->ring_debounce[i], debounce); atomic_set(&priv->ring_debounce[i], debounce);
} }
} }
@ -889,10 +949,12 @@ static void update_battery_voltage(xpd_t *xpd, __u8 data_low, xportno_t portno)
if (priv->battery[portno] != BATTERY_OFF) { if (priv->battery[portno] != BATTERY_OFF) {
int milliseconds; int milliseconds;
milliseconds = priv->nobattery_debounce[portno]++ * milliseconds =
priv->nobattery_debounce[portno]++ *
poll_battery_interval; poll_battery_interval;
if (milliseconds > battery_debounce) { if (milliseconds > battery_debounce) {
LINE_DBG(SIGNAL, xpd, portno, "BATTERY OFF voltage=%d\n", volts); LINE_DBG(SIGNAL, xpd, portno,
"BATTERY OFF voltage=%d\n", volts);
priv->battery[portno] = BATTERY_OFF; priv->battery[portno] = BATTERY_OFF;
dahdi_report_battery(xpd, portno); dahdi_report_battery(xpd, portno);
/* What's the polarity ? */ /* What's the polarity ? */
@ -910,7 +972,8 @@ static void update_battery_voltage(xpd_t *xpd, __u8 data_low, xportno_t portno)
} else { } else {
priv->nobattery_debounce[portno] = 0; priv->nobattery_debounce[portno] = 0;
if (priv->battery[portno] != BATTERY_ON) { if (priv->battery[portno] != BATTERY_ON) {
LINE_DBG(SIGNAL, xpd, portno, "BATTERY ON voltage=%d\n", volts); LINE_DBG(SIGNAL, xpd, portno, "BATTERY ON voltage=%d\n",
volts);
priv->battery[portno] = BATTERY_ON; priv->battery[portno] = BATTERY_ON;
dahdi_report_battery(xpd, portno); dahdi_report_battery(xpd, portno);
} }
@ -972,8 +1035,10 @@ static void update_battery_voltage(xpd_t *xpd, __u8 data_low, xportno_t portno)
oht_pcm(xpd, portno, 1); /* will be cleared on ring/offhook */ oht_pcm(xpd, portno, 1); /* will be cleared on ring/offhook */
if (SPAN_REGISTERED(xpd)) { if (SPAN_REGISTERED(xpd)) {
LINE_DBG(SIGNAL, xpd, portno, LINE_DBG(SIGNAL, xpd, portno,
"Send DAHDI_EVENT_POLARITY: %s\n", polname); "Send DAHDI_EVENT_POLARITY: %s\n",
dahdi_qevent_lock(XPD_CHAN(xpd, portno), DAHDI_EVENT_POLARITY); polname);
dahdi_qevent_lock(XPD_CHAN(xpd, portno),
DAHDI_EVENT_POLARITY);
} }
} }
priv->polarity[portno] = pol; priv->polarity[portno] = pol;
@ -1038,8 +1103,8 @@ static void update_metering_state(xpd_t *xpd, __u8 data_low, lineno_t portno)
BUG_ON(!priv); BUG_ON(!priv);
old_metering_tone = IS_SET(priv->metering_tone_state, portno); old_metering_tone = IS_SET(priv->metering_tone_state, portno);
LINE_DBG(SIGNAL, xpd, portno, "METERING: %s [dL=0x%X] (%d)\n", LINE_DBG(SIGNAL, xpd, portno, "METERING: %s [dL=0x%X] (%d)\n",
(metering_tone) ? "ON" : "OFF", (metering_tone) ? "ON" : "OFF", data_low,
data_low, priv->metering_count[portno]); priv->metering_count[portno]);
if (metering_tone && !old_metering_tone) { if (metering_tone && !old_metering_tone) {
/* Rising edge */ /* Rising edge */
priv->metering_count[portno]++; priv->metering_count[portno]++;
@ -1049,7 +1114,8 @@ static void update_metering_state(xpd_t *xpd, __u8 data_low, lineno_t portno)
if (metering_tone) { if (metering_tone) {
/* Clear the BTD bit */ /* Clear the BTD bit */
data_low &= ~BTD_BIT; data_low &= ~BTD_BIT;
DAA_DIRECT_REQUEST(xpd->xbus, xpd, portno, DAA_WRITE, DAA_REG_METERING, data_low); DAA_DIRECT_REQUEST(xpd->xbus, xpd, portno, DAA_WRITE,
DAA_REG_METERING, data_low);
} }
} }
#endif #endif
@ -1076,15 +1142,14 @@ static int FXO_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info)
#endif #endif
} }
LINE_DBG(REGS, xpd, portno, "%c reg_num=0x%X, dataL=0x%X dataH=0x%X\n", LINE_DBG(REGS, xpd, portno, "%c reg_num=0x%X, dataL=0x%X dataH=0x%X\n",
((info->bytes == 3)?'I':'D'), ((info->bytes == 3) ? 'I' : 'D'), REG_FIELD(info, regnum),
REG_FIELD(info, regnum), REG_FIELD(info, data_low), REG_FIELD(info, data_high));
REG_FIELD(info, data_low),
REG_FIELD(info, data_high));
/* Update /proc info only if reply relate to the last slic read request */ /* Update /proc info only if reply relate to the last slic read request */
if ( if (REG_FIELD(&xpd->requested_reply, regnum) == REG_FIELD(info, regnum)
REG_FIELD(&xpd->requested_reply, regnum) == REG_FIELD(info, regnum) && && REG_FIELD(&xpd->requested_reply, do_subreg) == REG_FIELD(info,
REG_FIELD(&xpd->requested_reply, do_subreg) == REG_FIELD(info, do_subreg) && do_subreg)
REG_FIELD(&xpd->requested_reply, subreg) == REG_FIELD(info, subreg)) { && REG_FIELD(&xpd->requested_reply, subreg) == REG_FIELD(info,
subreg)) {
xpd->last_reply = *info; xpd->last_reply = *info;
} }
return 0; return 0;
@ -1126,19 +1191,12 @@ static const struct phoneops fxo_phoneops = {
}; };
static xproto_table_t PROTO_TABLE(FXO) = { static xproto_table_t PROTO_TABLE(FXO) = {
.owner = THIS_MODULE, .owner = THIS_MODULE,.entries = {
.entries = {
/* Prototable Card Opcode */ /* Prototable Card Opcode */
XENTRY( FXO, FXO, SIG_CHANGED ), XENTRY(FXO, FXO, SIG_CHANGED),},.name = "FXO", /* protocol name */
}, .ports_per_subunit = 8,.type = XPD_TYPE_FXO,.xops =
.name = "FXO", /* protocol name */ &fxo_xops,.phoneops = &fxo_phoneops,.packet_is_valid =
.ports_per_subunit = 8, fxo_packet_is_valid,.packet_dump = fxo_packet_dump,};
.type = XPD_TYPE_FXO,
.xops = &fxo_xops,
.phoneops = &fxo_phoneops,
.packet_is_valid = fxo_packet_is_valid,
.packet_dump = fxo_packet_dump,
};
static bool fxo_packet_is_valid(xpacket_t *pack) static bool fxo_packet_is_valid(xpacket_t *pack)
{ {
@ -1157,7 +1215,8 @@ static void fxo_packet_dump(const char *msg, xpacket_t *pack)
/*------------------------- DAA Handling --------------------------*/ /*------------------------- DAA Handling --------------------------*/
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
static int proc_fxo_info_read(char *page, char **start, off_t off, int count, int *eof, void *data) static int proc_fxo_info_read(char *page, char **start, off_t off, int count,
int *eof, void *data)
{ {
int len = 0; int len = 0;
unsigned long flags; unsigned long flags;
@ -1172,21 +1231,26 @@ static int proc_fxo_info_read(char *page, char **start, off_t off, int count, in
BUG_ON(!priv); BUG_ON(!priv);
len += sprintf(page + len, "\t%-17s: ", "Channel"); len += sprintf(page + len, "\t%-17s: ", "Channel");
for_each_line(xpd, i) { for_each_line(xpd, i) {
if (!IS_SET(PHONEDEV(xpd).digital_outputs, i) && !IS_SET(PHONEDEV(xpd).digital_inputs, i)) if (!IS_SET(PHONEDEV(xpd).digital_outputs, i)
&& !IS_SET(PHONEDEV(xpd).digital_inputs, i))
len += sprintf(page + len, "%4d ", i % 10); len += sprintf(page + len, "%4d ", i % 10);
} }
len += sprintf(page + len, "\nLeds:"); len += sprintf(page + len, "\nLeds:");
len += sprintf(page + len, "\n\t%-17s: ", "state"); len += sprintf(page + len, "\n\t%-17s: ", "state");
for_each_line(xpd, i) { for_each_line(xpd, i) {
if (!IS_SET(PHONEDEV(xpd).digital_outputs, i) && !IS_SET(PHONEDEV(xpd).digital_inputs, i)) if (!IS_SET(PHONEDEV(xpd).digital_outputs, i)
len += sprintf(page + len, " %d%d ", && !IS_SET(PHONEDEV(xpd).digital_inputs, i))
len +=
sprintf(page + len, " %d%d ",
IS_SET(priv->ledstate[LED_GREEN], i), IS_SET(priv->ledstate[LED_GREEN], i),
IS_SET(priv->ledstate[LED_RED], i)); IS_SET(priv->ledstate[LED_RED], i));
} }
len += sprintf(page + len, "\n\t%-17s: ", "blinking"); len += sprintf(page + len, "\n\t%-17s: ", "blinking");
for_each_line(xpd, i) { for_each_line(xpd, i) {
if (!IS_SET(PHONEDEV(xpd).digital_outputs, i) && !IS_SET(PHONEDEV(xpd).digital_inputs, i)) if (!IS_SET(PHONEDEV(xpd).digital_outputs, i)
len += sprintf(page + len, " %d%d ", && !IS_SET(PHONEDEV(xpd).digital_inputs, i))
len +=
sprintf(page + len, " %d%d ",
IS_BLINKING(priv, i, LED_GREEN), IS_BLINKING(priv, i, LED_GREEN),
IS_BLINKING(priv, i, LED_RED)); IS_BLINKING(priv, i, LED_RED));
} }
@ -1248,7 +1312,8 @@ static int proc_fxo_info_read(char *page, char **start, off_t off, int count, in
} }
len += sprintf(page + len, "\n\t%-17s: ", "safezone"); len += sprintf(page + len, "\n\t%-17s: ", "safezone");
for_each_line(xpd, i) { for_each_line(xpd, i) {
len += sprintf(page + len, "%4d ", priv->power_denial_safezone[i]); len +=
sprintf(page + len, "%4d ", priv->power_denial_safezone[i]);
} }
len += sprintf(page + len, "\n\t%-17s: ", "delay"); len += sprintf(page + len, "\n\t%-17s: ", "delay");
for_each_line(xpd, i) { for_each_line(xpd, i) {
@ -1263,7 +1328,7 @@ static int proc_fxo_info_read(char *page, char **start, off_t off, int count, in
#endif #endif
len += sprintf(page + len, "\n"); len += sprintf(page + len, "\n");
spin_unlock_irqrestore(&xpd->lock, flags); spin_unlock_irqrestore(&xpd->lock, flags);
if (len <= off+count) if (len <= off + count)
*eof = 1; *eof = 1;
*start = page + off; *start = page + off;
len -= off; len -= off;
@ -1276,7 +1341,8 @@ static int proc_fxo_info_read(char *page, char **start, off_t off, int count, in
#endif #endif
#ifdef WITH_METERING #ifdef WITH_METERING
static int proc_xpd_metering_read(char *page, char **start, off_t off, int count, int *eof, void *data) static int proc_xpd_metering_read(char *page, char **start, off_t off,
int count, int *eof, void *data)
{ {
int len = 0; int len = 0;
unsigned long flags; unsigned long flags;
@ -1291,11 +1357,11 @@ static int proc_xpd_metering_read(char *page, char **start, off_t off, int count
spin_lock_irqsave(&xpd->lock, flags); spin_lock_irqsave(&xpd->lock, flags);
len += sprintf(page + len, "# Chan\tMeter (since last read)\n"); len += sprintf(page + len, "# Chan\tMeter (since last read)\n");
for_each_line(xpd, i) { for_each_line(xpd, i) {
len += sprintf(page + len, "%d\t%d\n", len +=
i, priv->metering_count[i]); sprintf(page + len, "%d\t%d\n", i, priv->metering_count[i]);
} }
spin_unlock_irqrestore(&xpd->lock, flags); spin_unlock_irqrestore(&xpd->lock, flags);
if (len <= off+count) if (len <= off + count)
*eof = 1; *eof = 1;
*start = page + off; *start = page + off;
len -= off; len -= off;
@ -1343,7 +1409,6 @@ static DEVICE_ATTR_READER(fxo_battery_show, dev, buf)
static DEVICE_ATTR(fxo_battery, S_IRUGO, fxo_battery_show, NULL); static DEVICE_ATTR(fxo_battery, S_IRUGO, fxo_battery_show, NULL);
static int fxo_xpd_probe(struct device *dev) static int fxo_xpd_probe(struct device *dev)
{ {
xpd_t *xpd; xpd_t *xpd;
@ -1352,14 +1417,15 @@ static int fxo_xpd_probe(struct device *dev)
xpd = dev_to_xpd(dev); xpd = dev_to_xpd(dev);
/* Is it our device? */ /* Is it our device? */
if (xpd->type != XPD_TYPE_FXO) { if (xpd->type != XPD_TYPE_FXO) {
XPD_ERR(xpd, "drop suggestion for %s (%d)\n", XPD_ERR(xpd, "drop suggestion for %s (%d)\n", dev_name(dev),
dev_name(dev), xpd->type); xpd->type);
return -EINVAL; return -EINVAL;
} }
XPD_DBG(DEVICES, xpd, "SYSFS\n"); XPD_DBG(DEVICES, xpd, "SYSFS\n");
ret = device_create_file(dev, &dev_attr_fxo_battery); ret = device_create_file(dev, &dev_attr_fxo_battery);
if (ret) { if (ret) {
XPD_ERR(xpd, "%s: device_create_file(fxo_battery) failed: %d\n", __func__, ret); XPD_ERR(xpd, "%s: device_create_file(fxo_battery) failed: %d\n",
__func__, ret);
goto fail_fxo_battery; goto fail_fxo_battery;
} }
return 0; return 0;
@ -1385,8 +1451,7 @@ static struct xpd_driver fxo_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
#endif #endif
.probe = fxo_xpd_probe, .probe = fxo_xpd_probe,
.remove = fxo_xpd_remove .remove = fxo_xpd_remove}
}
}; };
static int __init card_fxo_startup(void) static int __init card_fxo_startup(void)
@ -1394,7 +1459,8 @@ static int __init card_fxo_startup(void)
int ret; int ret;
if (ring_debounce <= 0) { if (ring_debounce <= 0) {
ERR("ring_debounce=%d. Must be positive number of ticks\n", ring_debounce); ERR("ring_debounce=%d. Must be positive number of ticks\n",
ring_debounce);
return -EINVAL; return -EINVAL;
} }
if ((ret = xpd_driver_register(&fxo_driver.driver)) < 0) if ((ret = xpd_driver_register(&fxo_driver.driver)) < 0)

View File

@ -26,15 +26,12 @@
enum fxo_opcodes { enum fxo_opcodes {
XPROTO_NAME(FXO, SIG_CHANGED) = 0x06, XPROTO_NAME(FXO, SIG_CHANGED) = 0x06,
/**/ /**/ XPROTO_NAME(FXO, DAA_WRITE) = 0x0F, /* Write to DAA */
XPROTO_NAME(FXO, DAA_WRITE) = 0x0F, /* Write to DAA */
XPROTO_NAME(FXO, CHAN_CID) = 0x0F, /* Write to DAA */ XPROTO_NAME(FXO, CHAN_CID) = 0x0F, /* Write to DAA */
XPROTO_NAME(FXO, LED) = 0x0F, /* Write to DAA */ XPROTO_NAME(FXO, LED) = 0x0F, /* Write to DAA */
}; };
DEF_RPACKET_DATA(FXO, SIG_CHANGED, xpp_line_t sig_status; /* channels: lsb=1, msb=8 */
DEF_RPACKET_DATA(FXO, SIG_CHANGED,
xpp_line_t sig_status; /* channels: lsb=1, msb=8 */
xpp_line_t sig_toggles; /* channels: lsb=1, msb=8 */ xpp_line_t sig_toggles; /* channels: lsb=1, msb=8 */
); );

View File

@ -40,7 +40,8 @@ static DEF_PARM_BOOL(dtmf_detection, 1, 0644, "Do DTMF detection in hardware");
static DEF_PARM(uint, poll_digital_inputs, 1000, 0644, "Poll Digital Inputs"); static DEF_PARM(uint, poll_digital_inputs, 1000, 0644, "Poll Digital Inputs");
#endif #endif
static DEF_PARM_BOOL(vmwi_ioctl, 1, 0644, "Asterisk support VMWI notification via ioctl"); static DEF_PARM_BOOL(vmwi_ioctl, 1, 0644,
"Asterisk support VMWI notification via ioctl");
static DEF_PARM_BOOL(ring_trapez, 0, 0664, "Use trapezoid ring type"); static DEF_PARM_BOOL(ring_trapez, 0, 0664, "Use trapezoid ring type");
/* Signaling is opposite (fxo signalling for fxs card) */ /* Signaling is opposite (fxo signalling for fxs card) */
@ -108,9 +109,11 @@ enum fxs_state {
static bool fxs_packet_is_valid(xpacket_t *pack); static bool fxs_packet_is_valid(xpacket_t *pack);
static void fxs_packet_dump(const char *msg, xpacket_t *pack); static void fxs_packet_dump(const char *msg, xpacket_t *pack);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
static int proc_fxs_info_read(char *page, char **start, off_t off, int count, int *eof, void *data); static int proc_fxs_info_read(char *page, char **start, off_t off, int count,
int *eof, void *data);
#ifdef WITH_METERING #ifdef WITH_METERING
static int proc_xpd_metering_write(struct file *file, const char __user *buffer, unsigned long count, void *data); static int proc_xpd_metering_write(struct file *file, const char __user *buffer,
unsigned long count, void *data);
#endif #endif
#endif #endif
static void start_stop_vm_led(xbus_t *xbus, xpd_t *xpd, lineno_t pos); static void start_stop_vm_led(xbus_t *xbus, xpd_t *xpd, lineno_t pos);
@ -157,7 +160,8 @@ struct FXS_priv_data {
#define LED_BLINK_RING (1000/8) /* in ticks */ #define LED_BLINK_RING (1000/8) /* in ticks */
/*---------------- FXS: Static functions ----------------------------------*/ /*---------------- FXS: Static functions ----------------------------------*/
static int linefeed_control(xbus_t *xbus, xpd_t *xpd, lineno_t chan, enum fxs_state value) static int linefeed_control(xbus_t *xbus, xpd_t *xpd, lineno_t chan,
enum fxs_state value)
{ {
struct FXS_priv_data *priv; struct FXS_priv_data *priv;
@ -174,7 +178,8 @@ static int do_chan_power(xbus_t *xbus, xpd_t *xpd, lineno_t chan, bool on)
BUG_ON(!xbus); BUG_ON(!xbus);
BUG_ON(!xpd); BUG_ON(!xpd);
LINE_DBG(SIGNAL, xpd, chan, "%s\n", (on) ? "up" : "down"); LINE_DBG(SIGNAL, xpd, chan, "%s\n", (on) ? "up" : "down");
return SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, REG_BATTERY, value); return SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, REG_BATTERY,
value);
} }
static void vmwi_search(xpd_t *xpd, lineno_t pos, bool on) static void vmwi_search(xpd_t *xpd, lineno_t pos, bool on)
@ -236,7 +241,8 @@ static int do_led(xpd_t *xpd, lineno_t chan, __u8 which, bool on)
xbus = xpd->xbus; xbus = xpd->xbus;
priv = xpd->priv; priv = xpd->priv;
which = which % NUM_LEDS; which = which % NUM_LEDS;
if (IS_SET(PHONEDEV(xpd).digital_outputs, chan) || IS_SET(PHONEDEV(xpd).digital_inputs, chan)) if (IS_SET(PHONEDEV(xpd).digital_outputs, chan)
|| IS_SET(PHONEDEV(xpd).digital_inputs, chan))
goto out; goto out;
if (chan == PORT_BROADCAST) { if (chan == PORT_BROADCAST) {
priv->ledstate[which] = (on) ? ~0 : 0; priv->ledstate[which] = (on) ? ~0 : 0;
@ -247,13 +253,15 @@ static int do_led(xpd_t *xpd, lineno_t chan, __u8 which, bool on)
BIT_CLR(priv->ledstate[which], chan); BIT_CLR(priv->ledstate[which], chan);
} }
} }
LINE_DBG(LEDS, xpd, chan, "LED: which=%d -- %s\n", which, (on) ? "on" : "off"); LINE_DBG(LEDS, xpd, chan, "LED: which=%d -- %s\n", which,
(on) ? "on" : "off");
value = BIT(2) | BIT(3); value = BIT(2) | BIT(3);
value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_register_mask[which]); value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_register_mask[which]);
if (on) if (on)
value |= led_register_vals[which]; value |= led_register_vals[which];
ret = SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, ret =
REG_DIGITAL_IOCTRL, value); SLIC_DIRECT_REQUEST(xbus, xpd, chan, SLIC_WRITE, REG_DIGITAL_IOCTRL,
value);
out: out:
return ret; return ret;
} }
@ -271,7 +279,9 @@ static void handle_fxs_leds(xpd_t *xpd)
timer_count = xpd->timer_count; timer_count = xpd->timer_count;
for (color = 0; color < ARRAY_SIZE(colors); color++) { for (color = 0; color < ARRAY_SIZE(colors); color++) {
for_each_line(xpd, i) { for_each_line(xpd, i) {
if (IS_SET(PHONEDEV(xpd).digital_outputs | PHONEDEV(xpd).digital_inputs, i)) if (IS_SET
(PHONEDEV(xpd).digital_outputs | PHONEDEV(xpd).
digital_inputs, i))
continue; continue;
if ((xpd->blink_mode & BIT(i)) || IS_BLINKING(priv, i, color)) { // Blinking if ((xpd->blink_mode & BIT(i)) || IS_BLINKING(priv, i, color)) { // Blinking
int mod_value = LED_COUNTER(priv, i, color); int mod_value = LED_COUNTER(priv, i, color);
@ -280,16 +290,25 @@ static void handle_fxs_leds(xpd_t *xpd)
mod_value = DEFAULT_LED_PERIOD; /* safety value */ mod_value = DEFAULT_LED_PERIOD; /* safety value */
// led state is toggled // led state is toggled
if ((timer_count % mod_value) == 0) { if ((timer_count % mod_value) == 0) {
LINE_DBG(LEDS, xpd, i, "ledstate=%s\n", (IS_SET(priv->ledstate[color], i))?"ON":"OFF"); LINE_DBG(LEDS, xpd, i, "ledstate=%s\n",
(IS_SET
(priv->ledstate[color],
i)) ? "ON" : "OFF");
if (!IS_SET(priv->ledstate[color], i)) { if (!IS_SET(priv->ledstate[color], i)) {
do_led(xpd, i, color, 1); do_led(xpd, i, color, 1);
} else { } else {
do_led(xpd, i, color, 0); do_led(xpd, i, color, 0);
} }
} }
} else if (IS_SET(priv->ledcontrol[color] & ~priv->ledstate[color], i)) { } else
if (IS_SET
(priv->ledcontrol[color] & ~priv->
ledstate[color], i)) {
do_led(xpd, i, color, 1); do_led(xpd, i, color, 1);
} else if (IS_SET(~priv->ledcontrol[color] & priv->ledstate[color], i)) { } else
if (IS_SET
(~priv->ledcontrol[color] & priv->
ledstate[color], i)) {
do_led(xpd, i, color, 0); do_led(xpd, i, color, 0);
} }
@ -316,8 +335,10 @@ static int metering_gen(xpd_t *xpd, lineno_t chan, bool on)
{ {
__u8 value = (on) ? 0x94 : 0x00; __u8 value = (on) ? 0x94 : 0x00;
LINE_DBG(SIGNAL, xpd, chan, "METERING Generate: %s\n", (on)?"ON":"OFF"); LINE_DBG(SIGNAL, xpd, chan, "METERING Generate: %s\n",
return SLIC_DIRECT_REQUEST(xpd->xbus, xpd, chan, SLIC_WRITE, 0x23, value); (on) ? "ON" : "OFF");
return SLIC_DIRECT_REQUEST(xpd->xbus, xpd, chan, SLIC_WRITE, 0x23,
value);
} }
#endif #endif
@ -355,18 +376,23 @@ static int fxs_proc_create(xbus_t *xbus, xpd_t *xpd)
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
XPD_DBG(PROC, xpd, "Creating FXS_INFO file\n"); XPD_DBG(PROC, xpd, "Creating FXS_INFO file\n");
priv->fxs_info = create_proc_read_entry(PROC_FXS_INFO_FNAME, 0444, xpd->proc_xpd_dir, proc_fxs_info_read, xpd); priv->fxs_info =
create_proc_read_entry(PROC_FXS_INFO_FNAME, 0444, xpd->proc_xpd_dir,
proc_fxs_info_read, xpd);
if (!priv->fxs_info) { if (!priv->fxs_info) {
XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_FXS_INFO_FNAME); XPD_ERR(xpd, "Failed to create proc file '%s'\n",
PROC_FXS_INFO_FNAME);
fxs_proc_remove(xbus, xpd); fxs_proc_remove(xbus, xpd);
return -EINVAL; return -EINVAL;
} }
SET_PROC_DIRENTRY_OWNER(priv->fxs_info); SET_PROC_DIRENTRY_OWNER(priv->fxs_info);
#ifdef WITH_METERING #ifdef WITH_METERING
XPD_DBG(PROC, xpd, "Creating Metering tone file\n"); XPD_DBG(PROC, xpd, "Creating Metering tone file\n");
priv->meteringfile = create_proc_entry(PROC_METERING_FNAME, 0200, xpd->proc_xpd_dir); priv->meteringfile =
create_proc_entry(PROC_METERING_FNAME, 0200, xpd->proc_xpd_dir);
if (!priv->meteringfile) { if (!priv->meteringfile) {
XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_METERING_FNAME); XPD_ERR(xpd, "Failed to create proc file '%s'\n",
PROC_METERING_FNAME);
fxs_proc_remove(xbus, xpd); fxs_proc_remove(xbus, xpd);
return -EINVAL; return -EINVAL;
} }
@ -379,8 +405,9 @@ static int fxs_proc_create(xbus_t *xbus, xpd_t *xpd)
return 0; return 0;
} }
static xpd_t *FXS_card_new(xbus_t *xbus, int unit, int subunit, const xproto_table_t *proto_table, static xpd_t *FXS_card_new(xbus_t *xbus, int unit, int subunit,
__u8 subtype, int subunits, int subunit_ports, bool to_phone) const xproto_table_t *proto_table, __u8 subtype,
int subunits, int subunit_ports, bool to_phone)
{ {
xpd_t *xpd = NULL; xpd_t *xpd = NULL;
int channels; int channels;
@ -407,7 +434,9 @@ static xpd_t *FXS_card_new(xbus_t *xbus, int unit, int subunit, const xproto_tab
d_inputs = LINES_DIGI_INP; d_inputs = LINES_DIGI_INP;
d_outputs = LINES_DIGI_OUT; d_outputs = LINES_DIGI_OUT;
} }
xpd = xpd_alloc(xbus, unit, subunit, subtype, subunits, 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) if (!xpd)
return NULL; return NULL;
/* Initialize digital inputs/outputs */ /* Initialize digital inputs/outputs */
@ -476,9 +505,12 @@ static int FXS_card_init(xbus_t *xbus, xpd_t *xpd)
* So we do this after the LEDs * So we do this after the LEDs
*/ */
for_each_line(xpd, i) { for_each_line(xpd, i) {
if (IS_SET(PHONEDEV(xpd).digital_outputs | PHONEDEV(xpd).digital_inputs, i)) if (IS_SET
(PHONEDEV(xpd).digital_outputs | PHONEDEV(xpd).
digital_inputs, i))
continue; continue;
SLIC_DIRECT_REQUEST(xbus, xpd, i, SLIC_READ, REG_LOOPCLOSURE, 0); SLIC_DIRECT_REQUEST(xbus, xpd, i, SLIC_READ, REG_LOOPCLOSURE,
0);
} }
return 0; return 0;
err: err:
@ -506,21 +538,24 @@ static int FXS_card_dahdi_preregistration(xpd_t *xpd, bool on)
BUG_ON(!xbus); BUG_ON(!xbus);
priv = xpd->priv; priv = xpd->priv;
BUG_ON(!priv); BUG_ON(!priv);
XPD_DBG(GENERAL, xpd, "%s\n", (on)?"on":"off"); XPD_DBG(GENERAL, xpd, "%s\n", (on) ? "on" : "off");
PHONEDEV(xpd).span.spantype = "FXS"; PHONEDEV(xpd).span.spantype = "FXS";
for_each_line(xpd, i) { for_each_line(xpd, i) {
struct dahdi_chan *cur_chan = XPD_CHAN(xpd, i); struct dahdi_chan *cur_chan = XPD_CHAN(xpd, i);
XPD_DBG(GENERAL, xpd, "setting FXS channel %d\n", i); XPD_DBG(GENERAL, xpd, "setting FXS channel %d\n", i);
if (IS_SET(PHONEDEV(xpd).digital_outputs, i)) { if (IS_SET(PHONEDEV(xpd).digital_outputs, i)) {
snprintf(cur_chan->name, MAX_CHANNAME, "XPP_OUT/%02d/%1d%1d/%d", snprintf(cur_chan->name, MAX_CHANNAME,
xbus->num, xpd->addr.unit, xpd->addr.subunit, i); "XPP_OUT/%02d/%1d%1d/%d", xbus->num,
xpd->addr.unit, xpd->addr.subunit, i);
} else if (IS_SET(PHONEDEV(xpd).digital_inputs, i)) { } else if (IS_SET(PHONEDEV(xpd).digital_inputs, i)) {
snprintf(cur_chan->name, MAX_CHANNAME, "XPP_IN/%02d/%1d%1d/%d", snprintf(cur_chan->name, MAX_CHANNAME,
xbus->num, xpd->addr.unit, xpd->addr.subunit, i); "XPP_IN/%02d/%1d%1d/%d", xbus->num,
xpd->addr.unit, xpd->addr.subunit, i);
} else { } else {
snprintf(cur_chan->name, MAX_CHANNAME, "XPP_FXS/%02d/%1d%1d/%d", snprintf(cur_chan->name, MAX_CHANNAME,
xbus->num, xpd->addr.unit, xpd->addr.subunit, i); "XPP_FXS/%02d/%1d%1d/%d", xbus->num,
xpd->addr.unit, xpd->addr.subunit, i);
} }
cur_chan->chanpos = i + 1; cur_chan->chanpos = i + 1;
cur_chan->pvt = xpd; cur_chan->pvt = xpd;
@ -549,7 +584,7 @@ static int FXS_card_dahdi_postregistration(xpd_t *xpd, bool on)
BUG_ON(!xbus); BUG_ON(!xbus);
priv = xpd->priv; priv = xpd->priv;
BUG_ON(!priv); BUG_ON(!priv);
XPD_DBG(GENERAL, xpd, "%s\n", (on)?"on":"off"); XPD_DBG(GENERAL, xpd, "%s\n", (on) ? "on" : "off");
for_each_line(xpd, i) { for_each_line(xpd, i) {
MARK_OFF(priv, i, LED_GREEN); MARK_OFF(priv, i, LED_GREEN);
msleep(2); msleep(2);
@ -590,54 +625,83 @@ static int set_vm_led_mode(xbus_t *xbus, xpd_t *xpd, int pos,
/* A write to register 0x40 will now turn on/off the VM led */ /* A write to register 0x40 will now turn on/off the VM led */
LINE_DBG(SIGNAL, xpd, pos, "NEON\n"); LINE_DBG(SIGNAL, xpd, pos, "NEON\n");
BIT_SET(priv->neon_blinking, pos); BIT_SET(priv->neon_blinking, pos);
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x16, 0xE8, 0x03); ret +=
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x15, 0xEF, 0x7B); SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x16,
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x14, 0x9F, 0x00); 0xE8, 0x03);
ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x22, 0x19); ret +=
ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x30, 0xE0); SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x15,
ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x31, 0x01); 0xEF, 0x7B);
ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x32, 0xF0); ret +=
ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x33, 0x05); SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x14,
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x1D, 0x00, 0x46); 0x9F, 0x00);
ret +=
SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x22, 0x19);
ret +=
SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x30, 0xE0);
ret +=
SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x31, 0x01);
ret +=
SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x32, 0xF0);
ret +=
SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x33, 0x05);
ret +=
SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x1D,
0x00, 0x46);
} else if (ring_trapez) { } else if (ring_trapez) {
LINE_DBG(SIGNAL, xpd, pos, "RINGER: Trapez ring\n"); LINE_DBG(SIGNAL, xpd, pos, "RINGER: Trapez ring\n");
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, ret +=
SLIC_WRITE, 0x16, 0xC8, 0x00); SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x16,
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, 0xC8, 0x00);
SLIC_WRITE, 0x15, 0xAB, 0x5E); ret +=
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x15,
SLIC_WRITE, 0x14, 0x8C, 0x01); 0xAB, 0x5E);
ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, ret +=
SLIC_WRITE, 0x22, 0x01); SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x14,
ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, 0x8C, 0x01);
SLIC_WRITE, 0x4A, 0x34); ret +=
ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x22, 0x01);
SLIC_WRITE, 0x30, 0x00); ret +=
ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x4A, 0x34);
SLIC_WRITE, 0x31, 0x00); ret +=
ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x30, 0x00);
SLIC_WRITE, 0x32, 0x00); ret +=
ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x31, 0x00);
SLIC_WRITE, 0x33, 0x00); ret +=
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x32, 0x00);
SLIC_WRITE, 0x1D, 0x00, 0x36); ret +=
SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x33, 0x00);
ret +=
SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x1D,
0x00, 0x36);
} else { } else {
/* A write to register 0x40 will now turn on/off the ringer */ /* A write to register 0x40 will now turn on/off the ringer */
LINE_DBG(SIGNAL, xpd, pos, "RINGER\n"); LINE_DBG(SIGNAL, xpd, pos, "RINGER\n");
BIT_CLR(priv->neon_blinking, pos); BIT_CLR(priv->neon_blinking, pos);
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x16, 0x00, 0x00); ret +=
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x15, 0x77, 0x01); SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x16,
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x14, 0xFD, 0x7E); 0x00, 0x00);
ret +=
SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x15,
0x77, 0x01);
ret +=
SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x14,
0xFD, 0x7E);
ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x22, 0x00); ret +=
ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x30, 0x00); SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x22, 0x00);
ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x31, 0x00); ret +=
ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x32, 0x00); SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x30, 0x00);
ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x33, 0x00); ret +=
ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x31, 0x00);
0x4A, 0x34);/* High Vbat~ -82V[Dc] */ ret +=
ret += SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x1D, 0x00, 0x36); SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x32, 0x00);
ret +=
SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x33, 0x00);
ret += SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x4A, 0x34); /* High Vbat~ -82V[Dc] */
ret +=
SLIC_INDIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x1D,
0x00, 0x36);
} }
return (ret ? -EPROTO : 0); return (ret ? -EPROTO : 0);
} }
@ -648,15 +712,17 @@ static void start_stop_vm_led(xbus_t *xbus, xpd_t *xpd, lineno_t pos)
unsigned int msgs; unsigned int msgs;
BUG_ON(!xpd); BUG_ON(!xpd);
if (IS_SET(PHONEDEV(xpd).digital_outputs | PHONEDEV(xpd).digital_inputs, pos)) if (IS_SET
(PHONEDEV(xpd).digital_outputs | PHONEDEV(xpd).digital_inputs, pos))
return; return;
priv = xpd->priv; priv = xpd->priv;
msgs = PHONEDEV(xpd).msg_waiting[pos]; msgs = PHONEDEV(xpd).msg_waiting[pos];
LINE_DBG(SIGNAL, xpd, pos, "%s\n", (msgs) ? "ON" : "OFF"); LINE_DBG(SIGNAL, xpd, pos, "%s\n", (msgs) ? "ON" : "OFF");
set_vm_led_mode(xbus, xpd, pos, msgs); set_vm_led_mode(xbus, xpd, pos, msgs);
do_chan_power(xbus, xpd, pos, msgs > 0); do_chan_power(xbus, xpd, pos, msgs > 0);
linefeed_control(xbus, xpd, pos, (msgs > 0) ? linefeed_control(xbus, xpd, pos,
FXS_LINE_RING : priv->idletxhookstate[pos]); (msgs >
0) ? FXS_LINE_RING : priv->idletxhookstate[pos]);
} }
static int relay_out(xpd_t *xpd, int pos, bool on) static int relay_out(xpd_t *xpd, int pos, bool on)
@ -668,10 +734,12 @@ static int relay_out(xpd_t *xpd, int pos, bool on)
BUG_ON(!xpd); BUG_ON(!xpd);
/* map logical position to output port number (0/1) */ /* map logical position to output port number (0/1) */
which -= (xpd->subtype == 2) ? 6 : 8; which -= (xpd->subtype == 2) ? 6 : 8;
LINE_DBG(SIGNAL, xpd, pos, "which=%d -- %s\n", which, (on) ? "on" : "off"); LINE_DBG(SIGNAL, xpd, pos, "which=%d -- %s\n", which,
(on) ? "on" : "off");
which = which % ARRAY_SIZE(relay_channels); which = which % ARRAY_SIZE(relay_channels);
value = BIT(2) | BIT(3); value = BIT(2) | BIT(3);
value |= ((BIT(5) | BIT(6) | BIT(7)) & ~led_register_mask[OUTPUT_RELAY]); value |=
((BIT(5) | BIT(6) | BIT(7)) & ~led_register_mask[OUTPUT_RELAY]);
if (on) if (on)
value |= led_register_vals[OUTPUT_RELAY]; value |= led_register_vals[OUTPUT_RELAY];
return SLIC_DIRECT_REQUEST(xpd->xbus, xpd, relay_channels[which], return SLIC_DIRECT_REQUEST(xpd->xbus, xpd, relay_channels[which],
@ -688,7 +756,7 @@ static int send_ring(xpd_t *xpd, lineno_t chan, bool on)
BUG_ON(!xpd); BUG_ON(!xpd);
xbus = xpd->xbus; xbus = xpd->xbus;
BUG_ON(!xbus); BUG_ON(!xbus);
LINE_DBG(SIGNAL, xpd, chan, "%s\n", (on)?"on":"off"); LINE_DBG(SIGNAL, xpd, chan, "%s\n", (on) ? "on" : "off");
priv = xpd->priv; priv = xpd->priv;
set_vm_led_mode(xbus, xpd, chan, 0); set_vm_led_mode(xbus, xpd, chan, 0);
do_chan_power(xbus, xpd, chan, on); // Power up (for ring) do_chan_power(xbus, xpd, chan, on); // Power up (for ring)
@ -714,7 +782,8 @@ static int FXS_card_hooksig(xpd_t *xpd, int pos, enum dahdi_txsig txsig)
priv = xpd->priv; priv = xpd->priv;
BUG_ON(PHONEDEV(xpd).direction != TO_PHONE); BUG_ON(PHONEDEV(xpd).direction != TO_PHONE);
if (IS_SET(PHONEDEV(xpd).digital_inputs, pos)) { if (IS_SET(PHONEDEV(xpd).digital_inputs, pos)) {
LINE_DBG(SIGNAL, xpd, pos, "Ignoring signal sent to digital input line\n"); LINE_DBG(SIGNAL, xpd, pos,
"Ignoring signal sent to digital input line\n");
return 0; return 0;
} }
if (SPAN_REGISTERED(xpd)) if (SPAN_REGISTERED(xpd))
@ -730,7 +799,8 @@ static int FXS_card_hooksig(xpd_t *xpd, int pos, enum dahdi_txsig txsig)
__do_mute_dtmf(xpd, pos, 0); __do_mute_dtmf(xpd, pos, 0);
spin_unlock_irqrestore(&xpd->lock, flags); spin_unlock_irqrestore(&xpd->lock, flags);
if (IS_SET(PHONEDEV(xpd).digital_outputs, pos)) { if (IS_SET(PHONEDEV(xpd).digital_outputs, pos)) {
LINE_DBG(SIGNAL, xpd, pos, "%s -> digital output OFF\n", txsig2str(txsig)); LINE_DBG(SIGNAL, xpd, pos, "%s -> digital output OFF\n",
txsig2str(txsig));
ret = relay_out(xpd, pos, 0); ret = relay_out(xpd, pos, 0);
return ret; return ret;
} }
@ -739,7 +809,8 @@ static int FXS_card_hooksig(xpd_t *xpd, int pos, enum dahdi_txsig txsig)
* Restore state after KEWL hangup. * Restore state after KEWL hangup.
*/ */
LINE_DBG(SIGNAL, xpd, pos, "KEWL STOP\n"); LINE_DBG(SIGNAL, xpd, pos, "KEWL STOP\n");
linefeed_control(xpd->xbus, xpd, pos, FXS_LINE_POL_ACTIVE); linefeed_control(xpd->xbus, xpd, pos,
FXS_LINE_POL_ACTIVE);
if (IS_OFFHOOK(xpd, pos)) if (IS_OFFHOOK(xpd, pos))
MARK_ON(priv, pos, LED_GREEN); MARK_ON(priv, pos, LED_GREEN);
} }
@ -763,7 +834,9 @@ static int FXS_card_hooksig(xpd_t *xpd, int pos, enum dahdi_txsig txsig)
break; break;
case DAHDI_TXSIG_OFFHOOK: case DAHDI_TXSIG_OFFHOOK:
if (IS_SET(PHONEDEV(xpd).digital_outputs, pos)) { if (IS_SET(PHONEDEV(xpd).digital_outputs, pos)) {
LINE_NOTICE(xpd, pos, "%s -> Is digital output. Ignored\n", txsig2str(txsig)); LINE_NOTICE(xpd, pos,
"%s -> Is digital output. Ignored\n",
txsig2str(txsig));
return -EINVAL; return -EINVAL;
} }
txhook = priv->lasttxhook[pos]; txhook = priv->lasttxhook[pos];
@ -789,7 +862,8 @@ static int FXS_card_hooksig(xpd_t *xpd, int pos, enum dahdi_txsig txsig)
oht_pcm(xpd, pos, 0); oht_pcm(xpd, pos, 0);
vmwi_search(xpd, pos, 0); vmwi_search(xpd, pos, 0);
if (IS_SET(PHONEDEV(xpd).digital_outputs, pos)) { if (IS_SET(PHONEDEV(xpd).digital_outputs, pos)) {
LINE_DBG(SIGNAL, xpd, pos, "%s -> digital output ON\n", txsig2str(txsig)); LINE_DBG(SIGNAL, xpd, pos, "%s -> digital output ON\n",
txsig2str(txsig));
ret = relay_out(xpd, pos, 1); ret = relay_out(xpd, pos, 1);
return ret; return ret;
} }
@ -797,15 +871,17 @@ static int FXS_card_hooksig(xpd_t *xpd, int pos, enum dahdi_txsig txsig)
break; break;
case DAHDI_TXSIG_KEWL: case DAHDI_TXSIG_KEWL:
if (IS_SET(PHONEDEV(xpd).digital_outputs, pos)) { if (IS_SET(PHONEDEV(xpd).digital_outputs, pos)) {
LINE_DBG(SIGNAL, xpd, pos, "%s -> Is digital output. Ignored\n", txsig2str(txsig)); LINE_DBG(SIGNAL, xpd, pos,
"%s -> Is digital output. Ignored\n",
txsig2str(txsig));
return -EINVAL; return -EINVAL;
} }
linefeed_control(xpd->xbus, xpd, pos, FXS_LINE_OPEN); linefeed_control(xpd->xbus, xpd, pos, FXS_LINE_OPEN);
MARK_OFF(priv, pos, LED_GREEN); MARK_OFF(priv, pos, LED_GREEN);
break; break;
default: default:
XPD_NOTICE(xpd, "%s: Can't set tx state to %s (%d)\n", XPD_NOTICE(xpd, "%s: Can't set tx state to %s (%d)\n", __func__,
__func__, txsig2str(txsig), txsig); txsig2str(txsig), txsig);
ret = -EINVAL; ret = -EINVAL;
} }
return ret; return ret;
@ -815,21 +891,20 @@ static int set_vmwi(xpd_t *xpd, int pos, unsigned long arg)
{ {
struct FXS_priv_data *priv; struct FXS_priv_data *priv;
struct dahdi_vmwi_info vmwisetting; struct dahdi_vmwi_info vmwisetting;
const int vmwi_flags = DAHDI_VMWI_LREV | DAHDI_VMWI_HVDC const int vmwi_flags =
| DAHDI_VMWI_HVAC; DAHDI_VMWI_LREV | DAHDI_VMWI_HVDC | DAHDI_VMWI_HVAC;
priv = xpd->priv; priv = xpd->priv;
BUG_ON(!priv); BUG_ON(!priv);
if (copy_from_user(&vmwisetting, (__user void *)arg, if (copy_from_user
sizeof(vmwisetting))) (&vmwisetting, (__user void *)arg, sizeof(vmwisetting)))
return -EFAULT; return -EFAULT;
if ((vmwisetting.vmwi_type & ~vmwi_flags) != 0) { if ((vmwisetting.vmwi_type & ~vmwi_flags) != 0) {
LINE_NOTICE(xpd, pos, "Bad DAHDI_VMWI_CONFIG: 0x%X\n", LINE_NOTICE(xpd, pos, "Bad DAHDI_VMWI_CONFIG: 0x%X\n",
vmwisetting.vmwi_type); vmwisetting.vmwi_type);
return -EINVAL; return -EINVAL;
} }
LINE_DBG(SIGNAL, xpd, pos, LINE_DBG(SIGNAL, xpd, pos, "DAHDI_VMWI_CONFIG: 0x%X\n",
"DAHDI_VMWI_CONFIG: 0x%X\n",
vmwisetting.vmwi_type); vmwisetting.vmwi_type);
if (VMWI_TYPE(priv, pos, LREV)) { if (VMWI_TYPE(priv, pos, LREV)) {
LINE_NOTICE(xpd, pos, LINE_NOTICE(xpd, pos,
@ -856,7 +931,8 @@ static int set_vmwi(xpd_t *xpd, int pos, unsigned long arg)
* Private ioctl() * Private ioctl()
* We don't need it now, since we detect vmwi via FSK patterns * We don't need it now, since we detect vmwi via FSK patterns
*/ */
static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg) static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd,
unsigned long arg)
{ {
struct FXS_priv_data *priv; struct FXS_priv_data *priv;
xbus_t *xbus; xbus_t *xbus;
@ -871,8 +947,8 @@ static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
if (!XBUS_IS(xbus, READY)) if (!XBUS_IS(xbus, READY))
return -ENODEV; return -ENODEV;
if (pos < 0 || pos >= PHONEDEV(xpd).channels) { if (pos < 0 || pos >= PHONEDEV(xpd).channels) {
XPD_NOTICE(xpd, "Bad channel number %d in %s(), cmd=%u\n", XPD_NOTICE(xpd, "Bad channel number %d in %s(), cmd=%u\n", pos,
pos, __func__, cmd); __func__, cmd);
return -EINVAL; return -EINVAL;
} }
@ -880,17 +956,23 @@ static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
case DAHDI_ONHOOKTRANSFER: case DAHDI_ONHOOKTRANSFER:
if (get_user(val, (int __user *)arg)) if (get_user(val, (int __user *)arg))
return -EFAULT; return -EFAULT;
LINE_DBG(SIGNAL, xpd, pos, "DAHDI_ONHOOKTRANSFER (%d millis)\n", val); LINE_DBG(SIGNAL, xpd, pos, "DAHDI_ONHOOKTRANSFER (%d millis)\n",
if (IS_SET(PHONEDEV(xpd).digital_inputs | PHONEDEV(xpd).digital_outputs, pos)) val);
if (IS_SET
(PHONEDEV(xpd).digital_inputs | PHONEDEV(xpd).
digital_outputs, pos))
return 0; /* Nothing to do */ return 0; /* Nothing to do */
oht_pcm(xpd, pos, 1); /* Get ready of VMWI FSK tones */ oht_pcm(xpd, pos, 1); /* Get ready of VMWI FSK tones */
if (priv->lasttxhook[pos] == FXS_LINE_POL_ACTIVE || if (priv->lasttxhook[pos] == FXS_LINE_POL_ACTIVE
IS_SET(priv->neon_blinking, pos)) { || IS_SET(priv->neon_blinking, pos)) {
priv->ohttimer[pos] = val; priv->ohttimer[pos] = val;
priv->idletxhookstate[pos] = FXS_LINE_POL_OHTRANS; priv->idletxhookstate[pos] = FXS_LINE_POL_OHTRANS;
vmwi_search(xpd, pos, 1); vmwi_search(xpd, pos, 1);
CALL_PHONE_METHOD(card_pcm_recompute, xpd, priv->search_fsk_pattern); CALL_PHONE_METHOD(card_pcm_recompute, xpd,
LINE_DBG(SIGNAL, xpd, pos, "Start OHT_TIMER. wanted_pcm_mask=0x%X\n", PHONEDEV(xpd).wanted_pcm_mask); priv->search_fsk_pattern);
LINE_DBG(SIGNAL, xpd, pos,
"Start OHT_TIMER. wanted_pcm_mask=0x%X\n",
PHONEDEV(xpd).wanted_pcm_mask);
} }
if (VMWI_NEON(priv, pos) && !IS_OFFHOOK(xpd, pos)) if (VMWI_NEON(priv, pos) && !IS_OFFHOOK(xpd, pos))
start_stop_vm_led(xbus, xpd, pos); start_stop_vm_led(xbus, xpd, pos);
@ -898,7 +980,8 @@ static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
case DAHDI_TONEDETECT: case DAHDI_TONEDETECT:
if (get_user(val, (int __user *)arg)) if (get_user(val, (int __user *)arg))
return -EFAULT; return -EFAULT;
LINE_DBG(SIGNAL, xpd, pos, "DAHDI_TONEDETECT: %s %s (dtmf_detection=%s)\n", LINE_DBG(SIGNAL, xpd, pos,
"DAHDI_TONEDETECT: %s %s (dtmf_detection=%s)\n",
(val & DAHDI_TONEDETECT_ON) ? "ON" : "OFF", (val & DAHDI_TONEDETECT_ON) ? "ON" : "OFF",
(val & DAHDI_TONEDETECT_MUTE) ? "MUTE" : "NO-MUTE", (val & DAHDI_TONEDETECT_MUTE) ? "MUTE" : "NO-MUTE",
(dtmf_detection ? "YES" : "NO")); (dtmf_detection ? "YES" : "NO"));
@ -906,7 +989,8 @@ static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
spin_lock_irqsave(&xpd->lock, flags); spin_lock_irqsave(&xpd->lock, flags);
if (IS_SET(priv->want_dtmf_events, pos)) { if (IS_SET(priv->want_dtmf_events, pos)) {
/* Detection mode changed: Disable DTMF interrupts */ /* Detection mode changed: Disable DTMF interrupts */
SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x17, 0); SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE,
0x17, 0);
} }
BIT_CLR(priv->want_dtmf_events, pos); BIT_CLR(priv->want_dtmf_events, pos);
BIT_CLR(priv->want_dtmf_mute, pos); BIT_CLR(priv->want_dtmf_mute, pos);
@ -925,7 +1009,8 @@ static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
/* Detection mode changed: Enable DTMF interrupts */ /* Detection mode changed: Enable DTMF interrupts */
LINE_DBG(SIGNAL, xpd, pos, LINE_DBG(SIGNAL, xpd, pos,
"DAHDI_TONEDETECT: Enable Hardware DTMF\n"); "DAHDI_TONEDETECT: Enable Hardware DTMF\n");
SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x17, 1); SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE,
0x17, 1);
} }
BIT_SET(priv->want_dtmf_events, pos); BIT_SET(priv->want_dtmf_events, pos);
} else { } else {
@ -933,7 +1018,8 @@ static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
/* Detection mode changed: Disable DTMF interrupts */ /* Detection mode changed: Disable DTMF interrupts */
LINE_DBG(SIGNAL, xpd, pos, LINE_DBG(SIGNAL, xpd, pos,
"DAHDI_TONEDETECT: Disable Hardware DTMF\n"); "DAHDI_TONEDETECT: Disable Hardware DTMF\n");
SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE, 0x17, 0); SLIC_DIRECT_REQUEST(xbus, xpd, pos, SLIC_WRITE,
0x17, 0);
} }
BIT_CLR(priv->want_dtmf_events, pos); BIT_CLR(priv->want_dtmf_events, pos);
} }
@ -963,13 +1049,15 @@ static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
* asterisk in wrong state (e.g: while ringing). * asterisk in wrong state (e.g: while ringing).
* In these cases, silently ignore it. * In these cases, silently ignore it.
*/ */
if (priv->lasttxhook[pos] == FXS_LINE_RING || priv->lasttxhook[pos] == FXS_LINE_OPEN) { if (priv->lasttxhook[pos] == FXS_LINE_RING
|| priv->lasttxhook[pos] == FXS_LINE_OPEN) {
LINE_DBG(SIGNAL, xpd, pos, LINE_DBG(SIGNAL, xpd, pos,
"DAHDI_SETPOLARITY: %s Cannot change when lasttxhook=0x%X\n", "DAHDI_SETPOLARITY: %s Cannot change when lasttxhook=0x%X\n",
(val)?"ON":"OFF", priv->lasttxhook[pos]); (val) ? "ON" : "OFF", priv->lasttxhook[pos]);
return -EINVAL; return -EINVAL;
} }
LINE_DBG(SIGNAL, xpd, pos, "DAHDI_SETPOLARITY: %s\n", (val)?"ON":"OFF"); LINE_DBG(SIGNAL, xpd, pos, "DAHDI_SETPOLARITY: %s\n",
(val) ? "ON" : "OFF");
if ((val && !reversepolarity) || (!val && reversepolarity)) if ((val && !reversepolarity) || (!val && reversepolarity))
priv->lasttxhook[pos] |= FXS_LINE_RING; priv->lasttxhook[pos] |= FXS_LINE_RING;
else else
@ -992,7 +1080,9 @@ static int FXS_card_ioctl(xpd_t *xpd, int pos, unsigned int cmd, unsigned long a
return 0; return 0;
} }
/* Digital inputs/outputs don't have VM leds */ /* Digital inputs/outputs don't have VM leds */
if (IS_SET(PHONEDEV(xpd).digital_inputs | PHONEDEV(xpd).digital_outputs, pos)) if (IS_SET
(PHONEDEV(xpd).digital_inputs | PHONEDEV(xpd).
digital_outputs, pos))
return 0; return 0;
PHONEDEV(xpd).msg_waiting[pos] = val; PHONEDEV(xpd).msg_waiting[pos] = val;
LINE_DBG(SIGNAL, xpd, pos, "DAHDI_VMWI: %s\n", LINE_DBG(SIGNAL, xpd, pos, "DAHDI_VMWI: %s\n",
@ -1068,8 +1158,8 @@ static void handle_linefeed(xpd_t *xpd)
priv = xpd->priv; priv = xpd->priv;
BUG_ON(!priv); BUG_ON(!priv);
for_each_line(xpd, i) { for_each_line(xpd, i) {
if (priv->lasttxhook[i] == FXS_LINE_RING && if (priv->lasttxhook[i] == FXS_LINE_RING
!IS_SET(priv->neon_blinking, i)) { && !IS_SET(priv->neon_blinking, i)) {
/* RINGing, prepare for OHT */ /* RINGing, prepare for OHT */
priv->ohttimer[i] = OHT_TIMER; priv->ohttimer[i] = OHT_TIMER;
priv->idletxhookstate[i] = FXS_LINE_POL_OHTRANS; priv->idletxhookstate[i] = FXS_LINE_POL_OHTRANS;
@ -1077,13 +1167,18 @@ static void handle_linefeed(xpd_t *xpd)
if (priv->ohttimer[i]) { if (priv->ohttimer[i]) {
priv->ohttimer[i]--; priv->ohttimer[i]--;
if (!priv->ohttimer[i]) { if (!priv->ohttimer[i]) {
LINE_DBG(SIGNAL, xpd, i, "ohttimer expired\n"); LINE_DBG(SIGNAL, xpd, i,
priv->idletxhookstate[i] = FXS_LINE_POL_ACTIVE; "ohttimer expired\n");
priv->idletxhookstate[i] =
FXS_LINE_POL_ACTIVE;
oht_pcm(xpd, i, 0); oht_pcm(xpd, i, 0);
vmwi_search(xpd, i, 0); vmwi_search(xpd, i, 0);
if (priv->lasttxhook[i] == FXS_LINE_POL_OHTRANS) { if (priv->lasttxhook[i] ==
FXS_LINE_POL_OHTRANS) {
/* Apply the change if appropriate */ /* Apply the change if appropriate */
linefeed_control(xpd->xbus, xpd, i, FXS_LINE_POL_ACTIVE); linefeed_control(xpd->xbus, xpd,
i,
FXS_LINE_POL_ACTIVE);
} }
} }
} }
@ -1112,9 +1207,12 @@ static void detect_vmwi(xpd_t *xpd)
{ {
struct FXS_priv_data *priv; struct FXS_priv_data *priv;
xbus_t *xbus; xbus_t *xbus;
static const __u8 FSK_COMMON_PATTERN[] = { 0xA8, 0x49, 0x22, 0x3B, 0x9F, 0xFF, 0x1F, 0xBB }; static const __u8 FSK_COMMON_PATTERN[] =
static const __u8 FSK_ON_PATTERN[] = { 0xA2, 0x2C, 0x1F, 0x2C, 0xBB, 0xA1, 0xA5, 0xFF }; { 0xA8, 0x49, 0x22, 0x3B, 0x9F, 0xFF, 0x1F, 0xBB };
static const __u8 FSK_OFF_PATTERN[] = { 0xA2, 0x2C, 0x28, 0xA5, 0xB1, 0x21, 0x49, 0x9F }; static const __u8 FSK_ON_PATTERN[] =
{ 0xA2, 0x2C, 0x1F, 0x2C, 0xBB, 0xA1, 0xA5, 0xFF };
static const __u8 FSK_OFF_PATTERN[] =
{ 0xA2, 0x2C, 0x28, 0xA5, 0xB1, 0x21, 0x49, 0x9F };
int i; int i;
xpp_line_t ignore_mask; xpp_line_t ignore_mask;
@ -1123,11 +1221,10 @@ static void detect_vmwi(xpd_t *xpd)
priv = xpd->priv; priv = xpd->priv;
BUG_ON(!priv); BUG_ON(!priv);
ignore_mask = ignore_mask =
PHONEDEV(xpd).offhook_state | PHONEDEV(xpd).offhook_state | ~(PHONEDEV(xpd).
~(PHONEDEV(xpd).oht_pcm_pass) | oht_pcm_pass) | ~(priv->
~(priv->search_fsk_pattern) | search_fsk_pattern)
PHONEDEV(xpd).digital_inputs | | PHONEDEV(xpd).digital_inputs | PHONEDEV(xpd).digital_outputs;
PHONEDEV(xpd).digital_outputs;
for_each_line(xpd, i) { for_each_line(xpd, i) {
struct dahdi_chan *chan = XPD_CHAN(xpd, i); struct dahdi_chan *chan = XPD_CHAN(xpd, i);
__u8 *writechunk = chan->writechunk; __u8 *writechunk = chan->writechunk;
@ -1147,17 +1244,26 @@ static void detect_vmwi(xpd_t *xpd)
printk("\n"); printk("\n");
} }
#endif #endif
if (unlikely(mem_equal(writechunk, FSK_COMMON_PATTERN, DAHDI_CHUNKSIZE))) { if (unlikely
LINE_DBG(SIGNAL, xpd, i, "Found common FSK pattern. Start looking for ON/OFF patterns.\n"); (mem_equal
(writechunk, FSK_COMMON_PATTERN, DAHDI_CHUNKSIZE))) {
LINE_DBG(SIGNAL, xpd, i,
"Found common FSK pattern. Start looking for ON/OFF patterns.\n");
BIT_SET(priv->found_fsk_pattern, i); BIT_SET(priv->found_fsk_pattern, i);
} else if (unlikely(IS_SET(priv->found_fsk_pattern, i))) { } else if (unlikely(IS_SET(priv->found_fsk_pattern, i))) {
BIT_CLR(priv->found_fsk_pattern, i); BIT_CLR(priv->found_fsk_pattern, i);
oht_pcm(xpd, i, 0); oht_pcm(xpd, i, 0);
if (unlikely(mem_equal(writechunk, FSK_ON_PATTERN, DAHDI_CHUNKSIZE))) { if (unlikely
(mem_equal
(writechunk, FSK_ON_PATTERN, DAHDI_CHUNKSIZE))) {
LINE_DBG(SIGNAL, xpd, i, "MSG WAITING ON\n"); LINE_DBG(SIGNAL, xpd, i, "MSG WAITING ON\n");
PHONEDEV(xpd).msg_waiting[i] = 1; PHONEDEV(xpd).msg_waiting[i] = 1;
start_stop_vm_led(xbus, xpd, i); start_stop_vm_led(xbus, xpd, i);
} else if (unlikely(mem_equal(writechunk, FSK_OFF_PATTERN, DAHDI_CHUNKSIZE))) { } else
if (unlikely
(mem_equal
(writechunk, FSK_OFF_PATTERN,
DAHDI_CHUNKSIZE))) {
LINE_DBG(SIGNAL, xpd, i, "MSG WAITING OFF\n"); LINE_DBG(SIGNAL, xpd, i, "MSG WAITING OFF\n");
PHONEDEV(xpd).msg_waiting[i] = 0; PHONEDEV(xpd).msg_waiting[i] = 0;
start_stop_vm_led(xbus, xpd, i); start_stop_vm_led(xbus, xpd, i);
@ -1203,7 +1309,10 @@ static int FXS_card_tick(xbus_t *xbus, xpd_t *xpd)
for_each_line(xpd, i) { for_each_line(xpd, i) {
if (!IS_SET(priv->update_offhook_state, i)) if (!IS_SET(priv->update_offhook_state, i))
continue; continue;
rxsig = IS_OFFHOOK(xpd, i) ? DAHDI_RXSIG_OFFHOOK : DAHDI_RXSIG_ONHOOK; rxsig =
IS_OFFHOOK(xpd,
i) ? DAHDI_RXSIG_OFFHOOK :
DAHDI_RXSIG_ONHOOK;
notify_rxsig(xpd, i, rxsig); /* Notify after open() */ notify_rxsig(xpd, i, rxsig); /* Notify after open() */
BIT_CLR(priv->update_offhook_state, i); BIT_CLR(priv->update_offhook_state, i);
} }
@ -1222,7 +1331,8 @@ static int FXS_card_tick(xbus_t *xbus, xpd_t *xpd)
/* /*
* Should be called with spinlocked XPD * Should be called with spinlocked XPD
*/ */
static void process_hookstate(xpd_t *xpd, xpp_line_t offhook, xpp_line_t change_mask) static void process_hookstate(xpd_t *xpd, xpp_line_t offhook,
xpp_line_t change_mask)
{ {
xbus_t *xbus; xbus_t *xbus;
struct FXS_priv_data *priv; struct FXS_priv_data *priv;
@ -1232,9 +1342,11 @@ static void process_hookstate(xpd_t *xpd, xpp_line_t offhook, xpp_line_t change_
BUG_ON(PHONEDEV(xpd).direction != TO_PHONE); BUG_ON(PHONEDEV(xpd).direction != TO_PHONE);
xbus = xpd->xbus; xbus = xpd->xbus;
priv = xpd->priv; priv = xpd->priv;
XPD_DBG(SIGNAL, xpd, "offhook=0x%X change_mask=0x%X\n", offhook, change_mask); XPD_DBG(SIGNAL, xpd, "offhook=0x%X change_mask=0x%X\n", offhook,
change_mask);
for_each_line(xpd, i) { for_each_line(xpd, i) {
if (IS_SET(PHONEDEV(xpd).digital_outputs, i) || IS_SET(PHONEDEV(xpd).digital_inputs, i)) if (IS_SET(PHONEDEV(xpd).digital_outputs, i)
|| IS_SET(PHONEDEV(xpd).digital_inputs, i))
continue; continue;
if (IS_SET(change_mask, i)) { if (IS_SET(change_mask, i)) {
PHONEDEV(xpd).ringing[i] = 0; /* No more ringing... */ PHONEDEV(xpd).ringing[i] = 0; /* No more ringing... */
@ -1246,7 +1358,8 @@ static void process_hookstate(xpd_t *xpd, xpp_line_t offhook, xpp_line_t change_
* Reset our previous DTMF memories... * Reset our previous DTMF memories...
*/ */
BIT_CLR(priv->prev_key_down, i); BIT_CLR(priv->prev_key_down, i);
priv->prev_key_time[i].tv_sec = priv->prev_key_time[i].tv_usec = 0L; priv->prev_key_time[i].tv_sec =
priv->prev_key_time[i].tv_usec = 0L;
if (IS_SET(offhook, i)) { if (IS_SET(offhook, i)) {
LINE_DBG(SIGNAL, xpd, i, "OFFHOOK\n"); LINE_DBG(SIGNAL, xpd, i, "OFFHOOK\n");
MARK_ON(priv, i, LED_GREEN); MARK_ON(priv, i, LED_GREEN);
@ -1267,16 +1380,18 @@ static void process_hookstate(xpd_t *xpd, xpp_line_t offhook, xpp_line_t change_
HANDLER_DEF(FXS, SIG_CHANGED) HANDLER_DEF(FXS, SIG_CHANGED)
{ {
xpp_line_t sig_status = RPACKET_FIELD(pack, FXS, SIG_CHANGED, sig_status); xpp_line_t sig_status =
xpp_line_t sig_toggles = RPACKET_FIELD(pack, FXS, SIG_CHANGED, sig_toggles); RPACKET_FIELD(pack, FXS, SIG_CHANGED, sig_status);
xpp_line_t sig_toggles =
RPACKET_FIELD(pack, FXS, SIG_CHANGED, sig_toggles);
unsigned long flags; unsigned long flags;
BUG_ON(!xpd); BUG_ON(!xpd);
BUG_ON(PHONEDEV(xpd).direction != TO_PHONE); BUG_ON(PHONEDEV(xpd).direction != TO_PHONE);
XPD_DBG(SIGNAL, xpd, "(PHONE) sig_toggles=0x%04X sig_status=0x%04X\n", sig_toggles, sig_status); XPD_DBG(SIGNAL, xpd, "(PHONE) sig_toggles=0x%04X sig_status=0x%04X\n",
sig_toggles, sig_status);
#if 0 #if 0
Is this needed? Is this needed ? for_each_line(xpd, i) {
for_each_line(xpd, i) {
if (IS_SET(sig_toggles, i)) if (IS_SET(sig_toggles, i))
do_chan_power(xpd->xbus, xpd, BIT(i), 0); // Power down (prevent overheating!!!) do_chan_power(xpd->xbus, xpd, BIT(i), 0); // Power down (prevent overheating!!!)
} }
@ -1296,8 +1411,7 @@ static void process_digital_inputs(xpd_t *xpd, const reg_cmd_t *info)
/* Sanity check */ /* Sanity check */
if (!PHONEDEV(xpd).digital_inputs) { if (!PHONEDEV(xpd).digital_inputs) {
XPD_NOTICE(xpd, XPD_NOTICE(xpd, "%s called without digital inputs. Ignored\n",
"%s called without digital inputs. Ignored\n",
__func__); __func__);
return; return;
} }
@ -1363,10 +1477,8 @@ static void process_dtmf(xpd_t *xpd, uint portnum, __u8 val)
priv->prev_key_time[portnum] = now; priv->prev_key_time[portnum] = now;
LINE_DBG(SIGNAL, xpd, portnum, LINE_DBG(SIGNAL, xpd, portnum,
"[%lu.%06lu] DTMF digit %-4s '%c' (val=%d, want_mute=%s want_event=%s, delta=%d msec)\n", "[%lu.%06lu] DTMF digit %-4s '%c' (val=%d, want_mute=%s want_event=%s, delta=%d msec)\n",
now.tv_sec, now.tv_usec, now.tv_sec, now.tv_usec, (key_down) ? "DOWN" : "UP", digit,
(key_down)?"DOWN":"UP", digit, val, val, (want_mute) ? "yes" : "no", (want_event) ? "yes" : "no",
(want_mute) ? "yes" : "no",
(want_event) ? "yes" : "no",
msec); msec);
/* /*
* FIXME: we currently don't use the want_dtmf_mute until * FIXME: we currently don't use the want_dtmf_mute until
@ -1378,7 +1490,8 @@ static void process_dtmf(xpd_t *xpd, uint portnum, __u8 val)
else else
__do_mute_dtmf(xpd, portnum, 0); __do_mute_dtmf(xpd, portnum, 0);
if (want_event) { if (want_event) {
int event = (key_down) ? DAHDI_EVENT_DTMFDOWN : DAHDI_EVENT_DTMFUP; int event =
(key_down) ? DAHDI_EVENT_DTMFDOWN : DAHDI_EVENT_DTMFUP;
dahdi_qevent_lock(XPD_CHAN(xpd, portnum), event | digit); dahdi_qevent_lock(XPD_CHAN(xpd, portnum), event | digit);
} }
@ -1397,8 +1510,8 @@ static int FXS_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info)
indirect = (REG_FIELD(info, regnum) == 0x1E); indirect = (REG_FIELD(info, regnum) == 0x1E);
regnum = (indirect) ? REG_FIELD(info, subreg) : REG_FIELD(info, regnum); regnum = (indirect) ? REG_FIELD(info, subreg) : REG_FIELD(info, regnum);
XPD_DBG(REGS, xpd, "%s reg_num=0x%X, dataL=0x%X dataH=0x%X\n", XPD_DBG(REGS, xpd, "%s reg_num=0x%X, dataL=0x%X dataH=0x%X\n",
(indirect)?"I":"D", (indirect) ? "I" : "D", regnum, REG_FIELD(info, data_low),
regnum, REG_FIELD(info, data_low), REG_FIELD(info, data_high)); REG_FIELD(info, data_high));
if (!indirect && regnum == REG_DTMF_DECODE) { if (!indirect && regnum == REG_DTMF_DECODE) {
__u8 val = REG_FIELD(info, data_low); __u8 val = REG_FIELD(info, data_low);
@ -1430,16 +1543,19 @@ static int FXS_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info)
} }
} else { } else {
#if 0 #if 0
XPD_NOTICE(xpd, "Spurious register reply(ignored): %s reg_num=0x%X, dataL=0x%X dataH=0x%X\n", XPD_NOTICE(xpd,
(indirect)?"I":"D", "Spurious register reply(ignored): %s reg_num=0x%X, dataL=0x%X dataH=0x%X\n",
regnum, REG_FIELD(info, data_low), REG_FIELD(info, data_high)); (indirect) ? "I" : "D", regnum, REG_FIELD(info,
data_low),
REG_FIELD(info, data_high));
#endif #endif
} }
/* Update /proc info only if reply relate to the last slic read request */ /* Update /proc info only if reply relate to the last slic read request */
if ( if (REG_FIELD(&xpd->requested_reply, regnum) == REG_FIELD(info, regnum)
REG_FIELD(&xpd->requested_reply, regnum) == REG_FIELD(info, regnum) && && REG_FIELD(&xpd->requested_reply, do_subreg) == REG_FIELD(info,
REG_FIELD(&xpd->requested_reply, do_subreg) == REG_FIELD(info, do_subreg) && do_subreg)
REG_FIELD(&xpd->requested_reply, subreg) == REG_FIELD(info, subreg)) { && REG_FIELD(&xpd->requested_reply, subreg) == REG_FIELD(info,
subreg)) {
xpd->last_reply = *info; xpd->last_reply = *info;
} }
spin_unlock_irqrestore(&xpd->lock, flags); spin_unlock_irqrestore(&xpd->lock, flags);
@ -1449,7 +1565,7 @@ static int FXS_card_register_reply(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *info)
static int FXS_card_state(xpd_t *xpd, bool on) static int FXS_card_state(xpd_t *xpd, bool on)
{ {
BUG_ON(!xpd); BUG_ON(!xpd);
XPD_DBG(GENERAL, xpd, "%s\n", (on)?"on":"off"); XPD_DBG(GENERAL, xpd, "%s\n", (on) ? "on" : "off");
return 0; return 0;
} }
@ -1478,19 +1594,12 @@ static const struct phoneops fxs_phoneops = {
}; };
static xproto_table_t PROTO_TABLE(FXS) = { static xproto_table_t PROTO_TABLE(FXS) = {
.owner = THIS_MODULE, .owner = THIS_MODULE,.entries = {
.entries = {
/* Prototable Card Opcode */ /* Prototable Card Opcode */
XENTRY( FXS, FXS, SIG_CHANGED ), XENTRY(FXS, FXS, SIG_CHANGED),},.name = "FXS", /* protocol name */
}, .ports_per_subunit = 8,.type = XPD_TYPE_FXS,.xops =
.name = "FXS", /* protocol name */ &fxs_xops,.phoneops = &fxs_phoneops,.packet_is_valid =
.ports_per_subunit = 8, fxs_packet_is_valid,.packet_dump = fxs_packet_dump,};
.type = XPD_TYPE_FXS,
.xops = &fxs_xops,
.phoneops = &fxs_phoneops,
.packet_is_valid = fxs_packet_is_valid,
.packet_dump = fxs_packet_dump,
};
static bool fxs_packet_is_valid(xpacket_t *pack) static bool fxs_packet_is_valid(xpacket_t *pack)
{ {
@ -1509,7 +1618,8 @@ static void fxs_packet_dump(const char *msg, xpacket_t *pack)
/*------------------------- SLIC Handling --------------------------*/ /*------------------------- SLIC Handling --------------------------*/
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
static int proc_fxs_info_read(char *page, char **start, off_t off, int count, int *eof, void *data) static int proc_fxs_info_read(char *page, char **start, off_t off, int count,
int *eof, void *data)
{ {
int len = 0; int len = 0;
unsigned long flags; unsigned long flags;
@ -1523,14 +1633,10 @@ static int proc_fxs_info_read(char *page, char **start, off_t off, int count, in
spin_lock_irqsave(&xpd->lock, flags); spin_lock_irqsave(&xpd->lock, flags);
priv = xpd->priv; priv = xpd->priv;
BUG_ON(!priv); BUG_ON(!priv);
len += sprintf(page + len, "%-8s %-10s %-10s %-10s %-10s %-10s\n", len +=
"Channel", sprintf(page + len, "%-8s %-10s %-10s %-10s %-10s %-10s\n",
"idletxhookstate", "Channel", "idletxhookstate", "lasttxhook", "ohttimer",
"lasttxhook", "neon_blinking", "search_fsk_pattern");
"ohttimer",
"neon_blinking",
"search_fsk_pattern"
);
for_each_line(xpd, i) { for_each_line(xpd, i) {
char pref; char pref;
@ -1540,12 +1646,10 @@ static int proc_fxs_info_read(char *page, char **start, off_t off, int count, in
pref = 'I'; pref = 'I';
else else
pref = ' '; pref = ' ';
len += sprintf(page + len, "%c%7d %10d %10d %10d %10d %10d\n", len +=
pref, sprintf(page + len, "%c%7d %10d %10d %10d %10d %10d\n",
i, pref, i, priv->idletxhookstate[i],
priv->idletxhookstate[i], priv->lasttxhook[i], priv->ohttimer[i],
priv->lasttxhook[i],
priv->ohttimer[i],
IS_SET(priv->neon_blinking, i), IS_SET(priv->neon_blinking, i),
IS_SET(priv->search_fsk_pattern, i) IS_SET(priv->search_fsk_pattern, i)
); );
@ -1555,23 +1659,32 @@ static int proc_fxs_info_read(char *page, char **start, off_t off, int count, in
len += sprintf(page + len, "LED #%d", led); len += sprintf(page + len, "LED #%d", led);
len += sprintf(page + len, "\n\t%-17s: ", "ledstate"); len += sprintf(page + len, "\n\t%-17s: ", "ledstate");
for_each_line(xpd, i) { for_each_line(xpd, i) {
if (!IS_SET(PHONEDEV(xpd).digital_outputs, i) && !IS_SET(PHONEDEV(xpd).digital_inputs, i)) if (!IS_SET(PHONEDEV(xpd).digital_outputs, i)
len += sprintf(page + len, "%d ", IS_SET(priv->ledstate[led], i)); && !IS_SET(PHONEDEV(xpd).digital_inputs, i))
len +=
sprintf(page + len, "%d ",
IS_SET(priv->ledstate[led], i));
} }
len += sprintf(page + len, "\n\t%-17s: ", "ledcontrol"); len += sprintf(page + len, "\n\t%-17s: ", "ledcontrol");
for_each_line(xpd, i) { for_each_line(xpd, i) {
if (!IS_SET(PHONEDEV(xpd).digital_outputs, i) && !IS_SET(PHONEDEV(xpd).digital_inputs, i)) if (!IS_SET(PHONEDEV(xpd).digital_outputs, i)
len += sprintf(page + len, "%d ", IS_SET(priv->ledcontrol[led], i)); && !IS_SET(PHONEDEV(xpd).digital_inputs, i))
len +=
sprintf(page + len, "%d ",
IS_SET(priv->ledcontrol[led], i));
} }
len += sprintf(page + len, "\n\t%-17s: ", "led_counter"); len += sprintf(page + len, "\n\t%-17s: ", "led_counter");
for_each_line(xpd, i) { for_each_line(xpd, i) {
if (!IS_SET(PHONEDEV(xpd).digital_outputs, i) && !IS_SET(PHONEDEV(xpd).digital_inputs, i)) if (!IS_SET(PHONEDEV(xpd).digital_outputs, i)
len += sprintf(page + len, "%d ", LED_COUNTER(priv,i,led)); && !IS_SET(PHONEDEV(xpd).digital_inputs, i))
len +=
sprintf(page + len, "%d ",
LED_COUNTER(priv, i, led));
} }
len += sprintf(page + len, "\n"); len += sprintf(page + len, "\n");
} }
spin_unlock_irqrestore(&xpd->lock, flags); spin_unlock_irqrestore(&xpd->lock, flags);
if (len <= off+count) if (len <= off + count)
*eof = 1; *eof = 1;
*start = page + off; *start = page + off;
len -= off; len -= off;
@ -1584,7 +1697,8 @@ static int proc_fxs_info_read(char *page, char **start, off_t off, int count, in
#endif #endif
#ifdef WITH_METERING #ifdef WITH_METERING
static int proc_xpd_metering_write(struct file *file, const char __user *buffer, unsigned long count, void *data) static int proc_xpd_metering_write(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{ {
xpd_t *xpd = data; xpd_t *xpd = data;
char buf[MAX_PROC_WRITE]; char buf[MAX_PROC_WRITE];
@ -1603,7 +1717,8 @@ static int proc_xpd_metering_write(struct file *file, const char __user *buffer,
buf[count] = '\0'; buf[count] = '\0';
ret = sscanf(buf, "%d", &num); ret = sscanf(buf, "%d", &num);
if (ret != 1) { if (ret != 1) {
XPD_ERR(xpd, "Metering value should be number. Got '%s'\n", buf); XPD_ERR(xpd, "Metering value should be number. Got '%s'\n",
buf);
return -EINVAL; return -EINVAL;
} }
chan = num; chan = num;
@ -1626,8 +1741,8 @@ static int fxs_xpd_probe(struct device *dev)
xpd = dev_to_xpd(dev); xpd = dev_to_xpd(dev);
/* Is it our device? */ /* Is it our device? */
if (xpd->type != XPD_TYPE_FXS) { if (xpd->type != XPD_TYPE_FXS) {
XPD_ERR(xpd, "drop suggestion for %s (%d)\n", XPD_ERR(xpd, "drop suggestion for %s (%d)\n", dev_name(dev),
dev_name(dev), xpd->type); xpd->type);
return -EINVAL; return -EINVAL;
} }
XPD_DBG(DEVICES, xpd, "SYSFS\n"); XPD_DBG(DEVICES, xpd, "SYSFS\n");
@ -1651,8 +1766,7 @@ static struct xpd_driver fxs_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
#endif #endif
.probe = fxs_xpd_probe, .probe = fxs_xpd_probe,
.remove = fxs_xpd_remove .remove = fxs_xpd_remove}
}
}; };
static int __init card_fxs_startup(void) static int __init card_fxs_startup(void)

View File

@ -26,15 +26,12 @@
enum fxs_opcodes { enum fxs_opcodes {
XPROTO_NAME(FXS, SIG_CHANGED) = 0x06, XPROTO_NAME(FXS, SIG_CHANGED) = 0x06,
/**/ /**/ XPROTO_NAME(FXS, CHAN_POWER) = 0x0F, /* Write to SLIC */
XPROTO_NAME(FXS, CHAN_POWER) = 0x0F, /* Write to SLIC */
XPROTO_NAME(FXS, CHAN_CID) = 0x0F, /* Write to SLIC */ XPROTO_NAME(FXS, CHAN_CID) = 0x0F, /* Write to SLIC */
XPROTO_NAME(FXS, LED) = 0x0F, /* Write to SLIC */ XPROTO_NAME(FXS, LED) = 0x0F, /* Write to SLIC */
}; };
DEF_RPACKET_DATA(FXS, SIG_CHANGED, xpp_line_t sig_status; /* channels: lsb=1, msb=8 */
DEF_RPACKET_DATA(FXS, SIG_CHANGED,
xpp_line_t sig_status; /* channels: lsb=1, msb=8 */
xpp_line_t sig_toggles; /* channels: lsb=1, msb=8 */ xpp_line_t sig_toggles; /* channels: lsb=1, msb=8 */
); );

View File

@ -32,7 +32,8 @@
static const char rcsid[] = "$Id$"; static const char rcsid[] = "$Id$";
DEF_PARM(charp,initdir, "/usr/share/dahdi", 0644, "The directory of card initialization scripts"); DEF_PARM(charp, initdir, "/usr/share/dahdi", 0644,
"The directory of card initialization scripts");
#define CHIP_REGISTERS "chipregs" #define CHIP_REGISTERS "chipregs"
@ -40,8 +41,8 @@ extern int debug;
/*---------------- GLOBAL PROC handling -----------------------------------*/ /*---------------- GLOBAL PROC handling -----------------------------------*/
static int send_magic_request(xbus_t *xbus, static int send_magic_request(xbus_t *xbus, unsigned unit, xportno_t portno,
unsigned unit, xportno_t portno, bool eoftx) bool eoftx)
{ {
xframe_t *xframe; xframe_t *xframe;
xpacket_t *pack; xpacket_t *pack;
@ -65,8 +66,8 @@ static int send_magic_request(xbus_t *xbus,
dump_xframe(__func__, xbus, xframe, debug); dump_xframe(__func__, xbus, xframe, debug);
ret = send_cmd_frame(xbus, xframe); ret = send_cmd_frame(xbus, xframe);
if (ret < 0) if (ret < 0)
PORT_ERR(xbus, unit, portno, PORT_ERR(xbus, unit, portno, "%s: failed sending xframe\n",
"%s: failed sending xframe\n", __func__); __func__);
return ret; return ret;
} }
@ -141,7 +142,8 @@ static int execute_chip_command(xpd_t *xpd, const int argc, char *argv[])
addr_mode = argv[argno][1]; addr_mode = argv[argno][1];
switch (addr_mode) { switch (addr_mode) {
case 'I': case 'I':
XPD_NOTICE(xpd, "'I' is deprecated in register commands. Use 'S' instead.\n"); XPD_NOTICE(xpd,
"'I' is deprecated in register commands. Use 'S' instead.\n");
/* fall through */ /* fall through */
case 'S': case 'S':
do_subreg = 1; do_subreg = 1;
@ -157,7 +159,8 @@ static int execute_chip_command(xpd_t *xpd, const int argc, char *argv[])
case 'm': case 'm':
if (op != 'W') { if (op != 'W') {
XPD_ERR(xpd, XPD_ERR(xpd,
"Can use Multibyte (%c) only with op 'W'\n", addr_mode); "Can use Multibyte (%c) only with op 'W'\n",
addr_mode);
goto out; goto out;
} }
num_args--; /* No data low */ num_args--; /* No data low */
@ -185,7 +188,8 @@ static int execute_chip_command(xpd_t *xpd, const int argc, char *argv[])
addr_mode, argc - argno); addr_mode, argc - argno);
goto out; goto out;
} }
ret = send_magic_request(xpd->xbus, xpd->addr.unit, portno, ret =
send_magic_request(xpd->xbus, xpd->addr.unit, portno,
addr_mode == 'm'); addr_mode == 'm');
goto out; goto out;
} }
@ -209,7 +213,8 @@ static int execute_chip_command(xpd_t *xpd, const int argc, char *argv[])
} }
subreg = parse_hexbyte(argv[argno]); subreg = parse_hexbyte(argv[argno]);
if (subreg < 0) { if (subreg < 0) {
XPD_ERR(xpd, "Illegal subregister number '%s'\n", argv[argno]); XPD_ERR(xpd, "Illegal subregister number '%s'\n",
argv[argno]);
goto out; goto out;
} }
//XPD_DBG(REGS, xpd, "Subreg is %X\n", subreg); //XPD_DBG(REGS, xpd, "Subreg is %X\n", subreg);
@ -223,7 +228,8 @@ static int execute_chip_command(xpd_t *xpd, const int argc, char *argv[])
} }
data_low = parse_hexbyte(argv[argno]); data_low = parse_hexbyte(argv[argno]);
if (data_low < 0) { if (data_low < 0) {
XPD_ERR(xpd, "Illegal data_low number '%s'\n", argv[argno]); XPD_ERR(xpd, "Illegal data_low number '%s'\n",
argv[argno]);
goto out; goto out;
} }
//XPD_DBG(REGS, xpd, "Data Low is %X\n", data_low); //XPD_DBG(REGS, xpd, "Data Low is %X\n", data_low);
@ -238,7 +244,8 @@ static int execute_chip_command(xpd_t *xpd, const int argc, char *argv[])
} }
data_high = parse_hexbyte(argv[argno]); data_high = parse_hexbyte(argv[argno]);
if (data_high < 0) { if (data_high < 0) {
XPD_ERR(xpd, "Illegal data_high number '%s'\n", argv[argno]); XPD_ERR(xpd, "Illegal data_high number '%s'\n",
argv[argno]);
goto out; goto out;
} }
//XPD_DBG(REGS, xpd, "Data High is %X\n", data_high); //XPD_DBG(REGS, xpd, "Data High is %X\n", data_high);
@ -246,26 +253,22 @@ static int execute_chip_command(xpd_t *xpd, const int argc, char *argv[])
} else } else
data_high = 0; data_high = 0;
if (argno < argc) { if (argno < argc) {
XPD_ERR(xpd, XPD_ERR(xpd, "Command contains an extra %d argument\n",
"Command contains an extra %d argument\n",
argc - argno); argc - argno);
goto out; goto out;
} }
#if 0 #if 0
XPD_DBG(REGS, xpd, XPD_DBG(REGS, xpd, "portno=%d writing=%d regnum=%d do_subreg=%d subreg=%d dataL=%d do_datah=%d dataH=%d\n", portno, /* portno */
"portno=%d writing=%d regnum=%d do_subreg=%d subreg=%d dataL=%d do_datah=%d dataH=%d\n",
portno, /* portno */
writing, /* writing */ writing, /* writing */
regnum, regnum, do_subreg, /* use subreg */
do_subreg, /* use subreg */
subreg, /* subreg */ subreg, /* subreg */
data_low, data_low, do_datah, /* use data_high */
do_datah, /* use data_high*/
data_high); data_high);
#endif #endif
ret = xpp_register_request(xpd->xbus, xpd, portno, ret =
writing, regnum, do_subreg, subreg, xpp_register_request(xpd->xbus, xpd, portno, writing, regnum,
data_low, do_datah, data_high, 1); do_subreg, subreg, data_low, do_datah,
data_high, 1);
out: out:
return ret; return ret;
} }
@ -298,7 +301,7 @@ int parse_chip_command(xpd_t *xpd, char *cmdline)
for (p = buf; *p && (*p == ' ' || *p == '\t'); p++) /* Trim leading whitespace */ for (p = buf; *p && (*p == ' ' || *p == '\t'); p++) /* Trim leading whitespace */
; ;
str = p; str = p;
for (i = 0; (p = strsep(&str, " \t")) != NULL && i < MAX_ARGS; ) { for (i = 0; (p = strsep(&str, " \t")) != NULL && i < MAX_ARGS;) {
if (*p != '\0') { if (*p != '\0') {
argv[i] = p; argv[i] = p;
// XPD_DBG(REGS, xpd, "ARG %d = '%s'\n", i, p); // XPD_DBG(REGS, xpd, "ARG %d = '%s'\n", i, p);
@ -308,7 +311,8 @@ int parse_chip_command(xpd_t *xpd, char *cmdline)
argv[i] = NULL; argv[i] = NULL;
argc = i; argc = i;
if (p) { if (p) {
XPD_ERR(xpd, "Too many words (%d) to process. Last was '%s'\n", i, p); XPD_ERR(xpd, "Too many words (%d) to process. Last was '%s'\n",
i, p);
goto out; goto out;
} }
if (argc) if (argc)
@ -349,7 +353,8 @@ static void global_packet_dump(const char *msg, xpacket_t *pack);
int xpp_register_request(xbus_t *xbus, xpd_t *xpd, xportno_t portno, int xpp_register_request(xbus_t *xbus, xpd_t *xpd, xportno_t portno,
bool writing, __u8 regnum, bool do_subreg, __u8 subreg, bool writing, __u8 regnum, bool do_subreg, __u8 subreg,
__u8 data_low, bool do_datah, __u8 data_high, bool should_reply) __u8 data_low, bool do_datah, __u8 data_high,
bool should_reply)
{ {
int ret = 0; int ret = 0;
xframe_t *xframe; xframe_t *xframe;
@ -360,11 +365,11 @@ int xpp_register_request(xbus_t *xbus, xpd_t *xpd, xportno_t portno,
DBG(REGS, "NO XBUS\n"); DBG(REGS, "NO XBUS\n");
return -EINVAL; return -EINVAL;
} }
XFRAME_NEW_CMD(xframe, pack, xbus, GLOBAL, REGISTER_REQUEST, xpd->xbus_idx); XFRAME_NEW_CMD(xframe, pack, xbus, GLOBAL, REGISTER_REQUEST,
xpd->xbus_idx);
LINE_DBG(REGS, xpd, portno, "%c%c %02X %02X %02X %02X\n", LINE_DBG(REGS, xpd, portno, "%c%c %02X %02X %02X %02X\n",
(writing)?'W':'R', (writing) ? 'W' : 'R', (do_subreg) ? 'S' : 'D', regnum, subreg,
(do_subreg)?'S':'D', data_low, data_high);
regnum, subreg, data_low, data_high);
reg_cmd = &RPACKET_FIELD(pack, GLOBAL, REGISTER_REQUEST, reg_cmd); reg_cmd = &RPACKET_FIELD(pack, GLOBAL, REGISTER_REQUEST, reg_cmd);
reg_cmd->bytes = sizeof(*reg_cmd) - 1; // do not count the 'bytes' field reg_cmd->bytes = sizeof(*reg_cmd) - 1; // do not count the 'bytes' field
reg_cmd->is_multibyte = 0; reg_cmd->is_multibyte = 0;
@ -387,7 +392,8 @@ int xpp_register_request(xbus_t *xbus, xpd_t *xpd, xportno_t portno,
if (should_reply) if (should_reply)
xpd->requested_reply = *reg_cmd; xpd->requested_reply = *reg_cmd;
if (debug & DBG_REGS) { if (debug & DBG_REGS) {
dump_reg_cmd("REG_REQ", 1, xbus, xpd->addr.unit, reg_cmd->portnum, reg_cmd); dump_reg_cmd("REG_REQ", 1, xbus, xpd->addr.unit,
reg_cmd->portnum, reg_cmd);
dump_packet("REG_REQ", pack, 1); dump_packet("REG_REQ", pack, 1);
} }
if (!xframe->usec_towait) { /* default processing time of SPI */ if (!xframe->usec_towait) { /* default processing time of SPI */
@ -443,8 +449,8 @@ HANDLER_DEF(GLOBAL, NULL_REPLY)
return 0; return 0;
} }
HANDLER_DEF(GLOBAL, AB_DESCRIPTION) /* 0x08 */ HANDLER_DEF(GLOBAL, AB_DESCRIPTION)
{ { /* 0x08 */
struct xbus_workqueue *worker; struct xbus_workqueue *worker;
__u8 rev; __u8 rev;
struct unit_descriptor *units; struct unit_descriptor *units;
@ -473,8 +479,7 @@ HANDLER_DEF(GLOBAL, AB_DESCRIPTION) /* 0x08 */
goto proto_err; goto proto_err;
} }
if (count_units <= 0) { if (count_units <= 0) {
XBUS_NOTICE(xbus, "Empty astribank? (%d units)\n", XBUS_NOTICE(xbus, "Empty astribank? (%d units)\n", count_units);
count_units);
ret = -EPROTO; ret = -EPROTO;
goto proto_err; goto proto_err;
} }
@ -482,7 +487,8 @@ HANDLER_DEF(GLOBAL, AB_DESCRIPTION) /* 0x08 */
ret = -EPROTO; ret = -EPROTO;
goto proto_err; goto proto_err;
} }
XBUS_INFO(xbus, "DESCRIPTOR: %d cards, protocol revision %d\n", count_units, rev); XBUS_INFO(xbus, "DESCRIPTOR: %d cards, protocol revision %d\n",
count_units, rev);
if (xbus_check_unique(xbus)) if (xbus_check_unique(xbus))
return -EBUSY; return -EBUSY;
xbus->revision = rev; xbus->revision = rev;
@ -497,7 +503,9 @@ HANDLER_DEF(GLOBAL, AB_DESCRIPTION) /* 0x08 */
struct card_desc_struct *card_desc; struct card_desc_struct *card_desc;
unsigned long flags; unsigned long flags;
if ((card_desc = KZALLOC(sizeof(struct card_desc_struct), GFP_ATOMIC)) == NULL) { if ((card_desc =
KZALLOC(sizeof(struct card_desc_struct),
GFP_ATOMIC)) == NULL) {
XBUS_ERR(xbus, "Card description allocation failed.\n"); XBUS_ERR(xbus, "Card description allocation failed.\n");
ret = -ENOMEM; ret = -ENOMEM;
goto out; goto out;
@ -510,16 +518,14 @@ HANDLER_DEF(GLOBAL, AB_DESCRIPTION) /* 0x08 */
card_desc->numchips = this_unit->numchips; card_desc->numchips = this_unit->numchips;
card_desc->ports_per_chip = this_unit->ports_per_chip; card_desc->ports_per_chip = this_unit->ports_per_chip;
card_desc->port_dir = this_unit->port_dir; card_desc->port_dir = this_unit->port_dir;
card_desc->ports = card_desc->numchips * card_desc->ports_per_chip; card_desc->ports =
XBUS_INFO(xbus, " CARD %d type=%d.%d ports=%d (%dx%d), port-dir=0x%02X\n", card_desc->numchips * card_desc->ports_per_chip;
card_desc->xpd_addr.unit, XBUS_INFO(xbus,
card_desc->type, " CARD %d type=%d.%d ports=%d (%dx%d), port-dir=0x%02X\n",
card_desc->subtype, card_desc->xpd_addr.unit, card_desc->type,
card_desc->ports, card_desc->subtype, card_desc->ports,
card_desc->numchips, card_desc->numchips, card_desc->ports_per_chip,
card_desc->ports_per_chip, card_desc->port_dir);
card_desc->port_dir
);
spin_lock_irqsave(&worker->worker_lock, flags); spin_lock_irqsave(&worker->worker_lock, flags);
worker->num_units++; worker->num_units++;
XBUS_COUNTER(xbus, UNITS)++; XBUS_COUNTER(xbus, UNITS)++;
@ -549,11 +555,13 @@ HANDLER_DEF(GLOBAL, REGISTER_REPLY)
return -EPROTO; return -EPROTO;
} }
if (debug & DBG_REGS) { if (debug & DBG_REGS) {
dump_reg_cmd("REG_REPLY", 0, xbus, xpd->addr.unit, reg->portnum, reg); dump_reg_cmd("REG_REPLY", 0, xbus, xpd->addr.unit, reg->portnum,
reg);
dump_packet("REG_REPLY", pack, 1); dump_packet("REG_REPLY", pack, 1);
} }
if (! XMETHOD(card_register_reply, xpd)) { if (!XMETHOD(card_register_reply, xpd)) {
XPD_ERR(xpd, "REGISTER_REPLY: without card_register_reply() method\n"); XPD_ERR(xpd,
"REGISTER_REPLY: without card_register_reply() method\n");
return -EINVAL; return -EINVAL;
} }
return CALL_XMETHOD(card_register_reply, xpd, reg); return CALL_XMETHOD(card_register_reply, xpd, reg);
@ -594,9 +602,11 @@ HANDLER_DEF(GLOBAL, ERROR_CODE)
snprintf(tmp_name, TMP_NAME_LEN, "%s(%1d%1d)", xbus->busname, snprintf(tmp_name, TMP_NAME_LEN, "%s(%1d%1d)", xbus->busname,
XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack)); XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack));
} else { } else {
snprintf(tmp_name, TMP_NAME_LEN, "%s/%s", xbus->busname, xpd->xpdname); snprintf(tmp_name, TMP_NAME_LEN, "%s/%s", xbus->busname,
xpd->xpdname);
} }
NOTICE("%s: FIRMWARE %s: category=%d errorbits=0x%02X (rate_limit=%ld)\n", NOTICE
("%s: FIRMWARE %s: category=%d errorbits=0x%02X (rate_limit=%ld)\n",
tmp_name, cmd->name, category_code, errorbits, rate_limit); tmp_name, cmd->name, category_code, errorbits, rate_limit);
dump_packet("FIRMWARE: ", pack, 1); dump_packet("FIRMWARE: ", pack, 1);
/* /*
@ -605,20 +615,16 @@ HANDLER_DEF(GLOBAL, ERROR_CODE)
return 0; return 0;
} }
xproto_table_t PROTO_TABLE(GLOBAL) = { xproto_table_t PROTO_TABLE(GLOBAL) = {
.entries = { .entries = {
/* Prototable Card Opcode */ /* Prototable Card Opcode */
XENTRY( GLOBAL, GLOBAL, NULL_REPLY ), XENTRY(GLOBAL, GLOBAL, NULL_REPLY), XENTRY(GLOBAL, GLOBAL,
XENTRY( GLOBAL, GLOBAL, AB_DESCRIPTION ), AB_DESCRIPTION),
XENTRY( GLOBAL, GLOBAL, SYNC_REPLY ), XENTRY(GLOBAL, GLOBAL, SYNC_REPLY),
XENTRY( GLOBAL, GLOBAL, ERROR_CODE ), XENTRY(GLOBAL, GLOBAL, ERROR_CODE),
XENTRY( GLOBAL, GLOBAL, REGISTER_REPLY ), XENTRY(GLOBAL, GLOBAL, REGISTER_REPLY),},.name =
}, "GLOBAL",.packet_is_valid =
.name = "GLOBAL", global_packet_is_valid,.packet_dump = global_packet_dump,};
.packet_is_valid = global_packet_is_valid,
.packet_dump = global_packet_dump,
};
static bool global_packet_is_valid(xpacket_t *pack) static bool global_packet_is_valid(xpacket_t *pack)
{ {
@ -687,31 +693,38 @@ int run_initialize_registers(xpd_t *xpd)
xpd_t *su = xpd_byaddr(xbus, xpd->addr.unit, i); xpd_t *su = xpd_byaddr(xbus, xpd->addr.unit, i);
if (!su) { if (!su) {
XPD_ERR(xpd, XPD_ERR(xpd, "Have %d subunits, but not subunit #%d\n",
"Have %d subunits, but not subunit #%d\n",
xpd->subunits, i); xpd->subunits, i);
continue; continue;
} }
direction_mask |= (PHONEDEV(su).direction == TO_PHONE) ? BIT(i) : 0; direction_mask |=
(PHONEDEV(su).direction == TO_PHONE) ? BIT(i) : 0;
} }
snprintf(busstr, MAX_ENV_STR, "XBUS_NAME=%s", xbus->busname); snprintf(busstr, MAX_ENV_STR, "XBUS_NAME=%s", xbus->busname);
snprintf(busnumstr, MAX_ENV_STR, "XBUS_NUMBER=%d", xbus->num); snprintf(busnumstr, MAX_ENV_STR, "XBUS_NUMBER=%d", xbus->num);
snprintf(modelstr, MAX_ENV_STR, "XBUS_MODEL_STRING=%s", xbus->transport.model_string); snprintf(modelstr, MAX_ENV_STR, "XBUS_MODEL_STRING=%s",
xbus->transport.model_string);
snprintf(unitstr, MAX_ENV_STR, "UNIT_NUMBER=%d", xpd->addr.unit); snprintf(unitstr, MAX_ENV_STR, "UNIT_NUMBER=%d", xpd->addr.unit);
snprintf(typestr, MAX_ENV_STR, "UNIT_TYPE=%d", xpd->type); snprintf(typestr, MAX_ENV_STR, "UNIT_TYPE=%d", xpd->type);
snprintf(subunitsstr, MAX_ENV_STR, "UNIT_SUBUNITS=%d", xpd->subunits); snprintf(subunitsstr, MAX_ENV_STR, "UNIT_SUBUNITS=%d", xpd->subunits);
snprintf(directionstr, MAX_ENV_STR, "UNIT_SUBUNITS_DIR=%d", direction_mask); snprintf(directionstr, MAX_ENV_STR, "UNIT_SUBUNITS_DIR=%d",
direction_mask);
snprintf(revstr, MAX_ENV_STR, "XBUS_REVISION=%d", xbus->revision); snprintf(revstr, MAX_ENV_STR, "XBUS_REVISION=%d", xbus->revision);
snprintf(connectorstr, MAX_ENV_STR, "XBUS_CONNECTOR=%s", xbus->connector); snprintf(connectorstr, MAX_ENV_STR, "XBUS_CONNECTOR=%s",
xbus->connector);
snprintf(xbuslabel, MAX_ENV_STR, "XBUS_LABEL=%s", xbus->label); snprintf(xbuslabel, MAX_ENV_STR, "XBUS_LABEL=%s", xbus->label);
if (snprintf(init_card, MAX_PATH_STR, "%s/init_card_%d_%d", if (snprintf
initdir, xpd->type, xbus->revision) > MAX_PATH_STR) { (init_card, MAX_PATH_STR, "%s/init_card_%d_%d", initdir, xpd->type,
XPD_NOTICE(xpd, "Cannot initialize. pathname is longer than %d characters.\n", MAX_PATH_STR); xbus->revision) > MAX_PATH_STR) {
XPD_NOTICE(xpd,
"Cannot initialize. pathname is longer than %d characters.\n",
MAX_PATH_STR);
ret = -E2BIG; ret = -E2BIG;
goto err; goto err;
} }
if (!XBUS_IS(xbus, RECVD_DESC)) { if (!XBUS_IS(xbus, RECVD_DESC)) {
XBUS_ERR(xbus, "Skipped register initialization. In state %s.\n", XBUS_ERR(xbus,
"Skipped register initialization. In state %s.\n",
xbus_statename(XBUS_STATE(xbus))); xbus_statename(XBUS_STATE(xbus)));
ret = -ENODEV; ret = -ENODEV;
goto err; goto err;
@ -725,15 +738,18 @@ int run_initialize_registers(xpd_t *xpd)
if (ret == 0) if (ret == 0)
XPD_DBG(DEVICES, xpd, "'%s' finished OK\n", init_card); XPD_DBG(DEVICES, xpd, "'%s' finished OK\n", init_card);
else if (ret < 0) { else if (ret < 0) {
XPD_ERR(xpd, "Failed running '%s' (errno %d)\n", init_card, ret); XPD_ERR(xpd, "Failed running '%s' (errno %d)\n", init_card,
ret);
} else { } else {
__u8 exitval = ((unsigned)ret >> 8) & 0xFF; __u8 exitval = ((unsigned)ret >> 8) & 0xFF;
__u8 sigval = ret & 0xFF; __u8 sigval = ret & 0xFF;
if (!exitval) { if (!exitval) {
XPD_ERR(xpd, "'%s' killed by signal %d\n", init_card, sigval); XPD_ERR(xpd, "'%s' killed by signal %d\n", init_card,
sigval);
} else { } else {
XPD_ERR(xpd, "'%s' aborted with exitval %d\n", init_card, exitval); XPD_ERR(xpd, "'%s' aborted with exitval %d\n",
init_card, exitval);
} }
ret = -EINVAL; ret = -EINVAL;
} }

View File

@ -30,14 +30,11 @@ enum global_opcodes {
XPROTO_NAME(GLOBAL, AB_DESCRIPTION) = 0x08, XPROTO_NAME(GLOBAL, AB_DESCRIPTION) = 0x08,
XPROTO_NAME(GLOBAL, REGISTER_REQUEST) = 0x0F, XPROTO_NAME(GLOBAL, REGISTER_REQUEST) = 0x0F,
XPROTO_NAME(GLOBAL, REGISTER_REPLY) = 0x10, XPROTO_NAME(GLOBAL, REGISTER_REPLY) = 0x10,
/**/ /**/ XPROTO_NAME(GLOBAL, PCM_WRITE) = 0x11,
XPROTO_NAME(GLOBAL, PCM_WRITE) = 0x11,
XPROTO_NAME(GLOBAL, PCM_READ) = 0x12, XPROTO_NAME(GLOBAL, PCM_READ) = 0x12,
/**/ /**/ XPROTO_NAME(GLOBAL, SYNC_SOURCE) = 0x19,
XPROTO_NAME(GLOBAL, SYNC_SOURCE) = 0x19,
XPROTO_NAME(GLOBAL, SYNC_REPLY) = 0x1A, XPROTO_NAME(GLOBAL, SYNC_REPLY) = 0x1A,
/**/ /**/ XPROTO_NAME(GLOBAL, ERROR_CODE) = 0x22,
XPROTO_NAME(GLOBAL, ERROR_CODE) = 0x22,
XPROTO_NAME(GLOBAL, RESET_SYNC_COUNTERS) = 0x23, XPROTO_NAME(GLOBAL, RESET_SYNC_COUNTERS) = 0x23,
XPROTO_NAME(GLOBAL, NULL_REPLY) = 0xFE, XPROTO_NAME(GLOBAL, NULL_REPLY) = 0xFE,
}; };
@ -56,45 +53,18 @@ struct unit_descriptor {
#define NUM_UNITS 6 #define NUM_UNITS 6
DEF_RPACKET_DATA(GLOBAL, NULL_REPLY); DEF_RPACKET_DATA(GLOBAL, NULL_REPLY);
DEF_RPACKET_DATA(GLOBAL, AB_REQUEST, DEF_RPACKET_DATA(GLOBAL, AB_REQUEST, __u8 rev; __u8 reserved;);
__u8 rev; DEF_RPACKET_DATA(GLOBAL, AB_DESCRIPTION, __u8 rev; __u8 reserved[3];
__u8 reserved; struct unit_descriptor unit_descriptor[NUM_UNITS];);
); DEF_RPACKET_DATA(GLOBAL, REGISTER_REQUEST, reg_cmd_t reg_cmd;);
DEF_RPACKET_DATA(GLOBAL, AB_DESCRIPTION, DEF_RPACKET_DATA(GLOBAL, PCM_WRITE, xpp_line_t lines; __u8 pcm[PCM_CHUNKSIZE];);
__u8 rev; DEF_RPACKET_DATA(GLOBAL, PCM_READ, xpp_line_t lines; __u8 pcm[PCM_CHUNKSIZE];);
__u8 reserved[3]; DEF_RPACKET_DATA(GLOBAL, SYNC_SOURCE, __u8 sync_mode; __u8 drift;);
struct unit_descriptor unit_descriptor[NUM_UNITS]; DEF_RPACKET_DATA(GLOBAL, SYNC_REPLY, __u8 sync_mode; __u8 drift;);
); DEF_RPACKET_DATA(GLOBAL, REGISTER_REPLY, reg_cmd_t regcmd;);
DEF_RPACKET_DATA(GLOBAL, REGISTER_REQUEST, DEF_RPACKET_DATA(GLOBAL, RESET_SYNC_COUNTERS, __u8 mask;);
reg_cmd_t reg_cmd; DEF_RPACKET_DATA(GLOBAL, ERROR_CODE, __u8 category_code; __u8 errorbits;
); __u8 bad_packet[0];);
DEF_RPACKET_DATA(GLOBAL, PCM_WRITE,
xpp_line_t lines;
__u8 pcm[PCM_CHUNKSIZE];
);
DEF_RPACKET_DATA(GLOBAL, PCM_READ,
xpp_line_t lines;
__u8 pcm[PCM_CHUNKSIZE];
);
DEF_RPACKET_DATA(GLOBAL, SYNC_SOURCE,
__u8 sync_mode;
__u8 drift;
);
DEF_RPACKET_DATA(GLOBAL, SYNC_REPLY,
__u8 sync_mode;
__u8 drift;
);
DEF_RPACKET_DATA(GLOBAL, REGISTER_REPLY,
reg_cmd_t regcmd;
);
DEF_RPACKET_DATA(GLOBAL, RESET_SYNC_COUNTERS,
__u8 mask;
);
DEF_RPACKET_DATA(GLOBAL, ERROR_CODE,
__u8 category_code;
__u8 errorbits;
__u8 bad_packet[0];
);
/* 0x07 */ DECLARE_CMD(GLOBAL, AB_REQUEST); /* 0x07 */ DECLARE_CMD(GLOBAL, AB_REQUEST);
/* 0x19 */ DECLARE_CMD(GLOBAL, SYNC_SOURCE, enum sync_mode mode, int drift); /* 0x19 */ DECLARE_CMD(GLOBAL, SYNC_SOURCE, enum sync_mode mode, int drift);
@ -102,7 +72,8 @@ DEF_RPACKET_DATA(GLOBAL, ERROR_CODE,
int xpp_register_request(xbus_t *xbus, xpd_t *xpd, xportno_t portno, int xpp_register_request(xbus_t *xbus, xpd_t *xpd, xportno_t portno,
bool writing, __u8 regnum, bool do_subreg, __u8 subreg, bool writing, __u8 regnum, bool do_subreg, __u8 subreg,
__u8 data_low, bool do_datah, __u8 data_high, bool should_reply); __u8 data_low, bool do_datah, __u8 data_high,
bool should_reply);
int send_multibyte_request(xbus_t *xbus, unsigned unit, xportno_t portno, int send_multibyte_request(xbus_t *xbus, unsigned unit, xportno_t portno,
bool eoftx, __u8 *buf, unsigned len); bool eoftx, __u8 *buf, unsigned len);
extern xproto_table_t PROTO_TABLE(GLOBAL); extern xproto_table_t PROTO_TABLE(GLOBAL);

File diff suppressed because it is too large Load Diff

View File

@ -28,5 +28,4 @@ enum pri_opcodes {
XPROTO_NAME(PRI, SET_LED) = 0x33, XPROTO_NAME(PRI, SET_LED) = 0x33,
}; };
#endif /* CARD_PRI_H */ #endif /* CARD_PRI_H */

View File

@ -22,7 +22,7 @@
#include <linux/version.h> #include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
# warning "This module is tested only with 2.6 kernels" #warning "This module is tested only with 2.6 kernels"
#endif #endif
#include <linux/kernel.h> #include <linux/kernel.h>
@ -39,19 +39,11 @@ static struct {
int value; int value;
char *name; char *name;
} poll_names[] = { } poll_names[] = {
P_(POLLIN), P_(POLLIN), P_(POLLPRI), P_(POLLOUT), P_(POLLERR), P_(POLLHUP),
P_(POLLPRI), P_(POLLNVAL), P_(POLLRDNORM), P_(POLLRDBAND), P_(POLLWRNORM),
P_(POLLOUT), P_(POLLWRBAND), P_(POLLMSG), P_(POLLREMOVE)
P_(POLLERR),
P_(POLLHUP),
P_(POLLNVAL),
P_(POLLRDNORM),
P_(POLLRDBAND),
P_(POLLWRNORM),
P_(POLLWRBAND),
P_(POLLMSG),
P_(POLLREMOVE)
}; };
#undef P_ #undef P_
void dump_poll(int debug, const char *msg, int poll) void dump_poll(int debug, const char *msg, int poll)

View File

@ -95,11 +95,16 @@ void dump_poll(int debug, const char *msg, int poll);
static inline char *rxsig2str(enum dahdi_rxsig sig) static inline char *rxsig2str(enum dahdi_rxsig sig)
{ {
switch (sig) { switch (sig) {
case DAHDI_RXSIG_ONHOOK: return "ONHOOK"; case DAHDI_RXSIG_ONHOOK:
case DAHDI_RXSIG_OFFHOOK: return "OFFHOOK"; return "ONHOOK";
case DAHDI_RXSIG_START: return "START"; case DAHDI_RXSIG_OFFHOOK:
case DAHDI_RXSIG_RING: return "RING"; return "OFFHOOK";
case DAHDI_RXSIG_INITIAL: return "INITIAL"; case DAHDI_RXSIG_START:
return "START";
case DAHDI_RXSIG_RING:
return "RING";
case DAHDI_RXSIG_INITIAL:
return "INITIAL";
} }
return "Unknown rxsig"; return "Unknown rxsig";
} }
@ -107,11 +112,16 @@ static inline char *rxsig2str(enum dahdi_rxsig sig)
static inline char *txsig2str(enum dahdi_txsig sig) static inline char *txsig2str(enum dahdi_txsig sig)
{ {
switch (sig) { switch (sig) {
case DAHDI_TXSIG_ONHOOK: return "TXSIG_ONHOOK"; case DAHDI_TXSIG_ONHOOK:
case DAHDI_TXSIG_OFFHOOK: return "TXSIG_OFFHOOK"; return "TXSIG_ONHOOK";
case DAHDI_TXSIG_START: return "TXSIG_START"; case DAHDI_TXSIG_OFFHOOK:
case DAHDI_TXSIG_KEWL: return "TXSIG_KEWL"; /* Drop battery if possible */ return "TXSIG_OFFHOOK";
case DAHDI_TXSIG_TOTAL: break; case DAHDI_TXSIG_START:
return "TXSIG_START";
case DAHDI_TXSIG_KEWL:
return "TXSIG_KEWL"; /* Drop battery if possible */
case DAHDI_TXSIG_TOTAL:
break;
} }
return "Unknown txsig"; return "Unknown txsig";
} }
@ -119,24 +129,42 @@ static inline char *txsig2str(enum dahdi_txsig sig)
static inline char *event2str(int event) static inline char *event2str(int event)
{ {
switch (event) { switch (event) {
case DAHDI_EVENT_NONE: return "NONE"; case DAHDI_EVENT_NONE:
case DAHDI_EVENT_ONHOOK: return "ONHOOK"; return "NONE";
case DAHDI_EVENT_RINGOFFHOOK: return "RINGOFFHOOK"; case DAHDI_EVENT_ONHOOK:
case DAHDI_EVENT_WINKFLASH: return "WINKFLASH"; return "ONHOOK";
case DAHDI_EVENT_ALARM: return "ALARM"; case DAHDI_EVENT_RINGOFFHOOK:
case DAHDI_EVENT_NOALARM: return "NOALARM"; return "RINGOFFHOOK";
case DAHDI_EVENT_ABORT: return "ABORT"; case DAHDI_EVENT_WINKFLASH:
case DAHDI_EVENT_OVERRUN: return "OVERRUN"; return "WINKFLASH";
case DAHDI_EVENT_BADFCS: return "BADFCS"; case DAHDI_EVENT_ALARM:
case DAHDI_EVENT_DIALCOMPLETE: return "DIALCOMPLETE"; return "ALARM";
case DAHDI_EVENT_RINGERON: return "RINGERON"; case DAHDI_EVENT_NOALARM:
case DAHDI_EVENT_RINGEROFF: return "RINGEROFF"; return "NOALARM";
case DAHDI_EVENT_HOOKCOMPLETE: return "HOOKCOMPLETE"; case DAHDI_EVENT_ABORT:
case DAHDI_EVENT_BITSCHANGED: return "BITSCHANGED"; return "ABORT";
case DAHDI_EVENT_PULSE_START: return "PULSE_START"; case DAHDI_EVENT_OVERRUN:
case DAHDI_EVENT_TIMER_EXPIRED: return "TIMER_EXPIRED"; return "OVERRUN";
case DAHDI_EVENT_TIMER_PING: return "TIMER_PING"; case DAHDI_EVENT_BADFCS:
case DAHDI_EVENT_POLARITY: return "POLARITY"; return "BADFCS";
case DAHDI_EVENT_DIALCOMPLETE:
return "DIALCOMPLETE";
case DAHDI_EVENT_RINGERON:
return "RINGERON";
case DAHDI_EVENT_RINGEROFF:
return "RINGEROFF";
case DAHDI_EVENT_HOOKCOMPLETE:
return "HOOKCOMPLETE";
case DAHDI_EVENT_BITSCHANGED:
return "BITSCHANGED";
case DAHDI_EVENT_PULSE_START:
return "PULSE_START";
case DAHDI_EVENT_TIMER_EXPIRED:
return "TIMER_EXPIRED";
case DAHDI_EVENT_TIMER_PING:
return "TIMER_PING";
case DAHDI_EVENT_POLARITY:
return "POLARITY";
} }
return "Unknown event"; return "Unknown event";
} }
@ -144,13 +172,20 @@ static inline char *event2str(int event)
static inline char *hookstate2str(int hookstate) static inline char *hookstate2str(int hookstate)
{ {
switch (hookstate) { switch (hookstate) {
case DAHDI_ONHOOK: return "DAHDI_ONHOOK"; case DAHDI_ONHOOK:
case DAHDI_START: return "DAHDI_START"; return "DAHDI_ONHOOK";
case DAHDI_OFFHOOK: return "DAHDI_OFFHOOK"; case DAHDI_START:
case DAHDI_WINK: return "DAHDI_WINK"; return "DAHDI_START";
case DAHDI_FLASH: return "DAHDI_FLASH"; case DAHDI_OFFHOOK:
case DAHDI_RING: return "DAHDI_RING"; return "DAHDI_OFFHOOK";
case DAHDI_RINGOFF: return "DAHDI_RINGOFF"; case DAHDI_WINK:
return "DAHDI_WINK";
case DAHDI_FLASH:
return "DAHDI_FLASH";
case DAHDI_RING:
return "DAHDI_RING";
case DAHDI_RINGOFF:
return "DAHDI_RINGOFF";
} }
return "Unknown hookstate"; return "Unknown hookstate";
} }
@ -159,23 +194,40 @@ static inline char *hookstate2str(int hookstate)
static inline char *sig2str(int sig) static inline char *sig2str(int sig)
{ {
switch (sig) { switch (sig) {
case DAHDI_SIG_FXSLS: return "FXSLS"; case DAHDI_SIG_FXSLS:
case DAHDI_SIG_FXSKS: return "FXSKS"; return "FXSLS";
case DAHDI_SIG_FXSGS: return "FXSGS"; case DAHDI_SIG_FXSKS:
case DAHDI_SIG_FXOLS: return "FXOLS"; return "FXSKS";
case DAHDI_SIG_FXOKS: return "FXOKS"; case DAHDI_SIG_FXSGS:
case DAHDI_SIG_FXOGS: return "FXOGS"; return "FXSGS";
case DAHDI_SIG_EM: return "E&M"; case DAHDI_SIG_FXOLS:
case DAHDI_SIG_EM_E1: return "E&M-E1"; return "FXOLS";
case DAHDI_SIG_CLEAR: return "Clear"; case DAHDI_SIG_FXOKS:
case DAHDI_SIG_HDLCRAW: return "HDLCRAW"; return "FXOKS";
case DAHDI_SIG_HDLCFCS: return "HDLCFCS"; case DAHDI_SIG_FXOGS:
case DAHDI_SIG_HDLCNET: return "HDLCNET"; return "FXOGS";
case DAHDI_SIG_SLAVE: return "Slave"; case DAHDI_SIG_EM:
case DAHDI_SIG_CAS: return "CAS"; return "E&M";
case DAHDI_SIG_DACS: return "DACS"; case DAHDI_SIG_EM_E1:
case DAHDI_SIG_DACS_RBS: return "DACS+RBS"; return "E&M-E1";
case DAHDI_SIG_SF: return "SF (ToneOnly)"; case DAHDI_SIG_CLEAR:
return "Clear";
case DAHDI_SIG_HDLCRAW:
return "HDLCRAW";
case DAHDI_SIG_HDLCFCS:
return "HDLCFCS";
case DAHDI_SIG_HDLCNET:
return "HDLCNET";
case DAHDI_SIG_SLAVE:
return "Slave";
case DAHDI_SIG_CAS:
return "CAS";
case DAHDI_SIG_DACS:
return "DACS";
case DAHDI_SIG_DACS_RBS:
return "DACS+RBS";
case DAHDI_SIG_SF:
return "SF (ToneOnly)";
case DAHDI_SIG_NONE: case DAHDI_SIG_NONE:
break; break;
} }
@ -186,13 +238,20 @@ static inline char *alarmbit2str(int alarmbit)
{ {
/* from dahdi/kernel.h */ /* from dahdi/kernel.h */
switch (1 << alarmbit) { switch (1 << alarmbit) {
case DAHDI_ALARM_NONE: return "NONE"; case DAHDI_ALARM_NONE:
case DAHDI_ALARM_RECOVER: return "RECOVER"; return "NONE";
case DAHDI_ALARM_LOOPBACK: return "LOOPBACK"; case DAHDI_ALARM_RECOVER:
case DAHDI_ALARM_YELLOW: return "YELLOW"; return "RECOVER";
case DAHDI_ALARM_RED: return "RED"; case DAHDI_ALARM_LOOPBACK:
case DAHDI_ALARM_BLUE: return "BLUE"; return "LOOPBACK";
case DAHDI_ALARM_NOTOPEN: return "NOTOPEN"; case DAHDI_ALARM_YELLOW:
return "YELLOW";
case DAHDI_ALARM_RED:
return "RED";
case DAHDI_ALARM_BLUE:
return "BLUE";
case DAHDI_ALARM_NOTOPEN:
return "NOTOPEN";
} }
return "UNKNOWN"; return "UNKNOWN";
} }

View File

@ -7,7 +7,9 @@ static int mmap_match(struct device *dev, struct device_driver *driver)
{ {
return !strncmp(dev_name(dev), driver->name, strlen(driver->name)); return !strncmp(dev_name(dev), driver->name, strlen(driver->name));
} }
static int mmap_uevent(struct device *dev, char **envp, int num_envp, char *buffer, int buffer_size)
static int mmap_uevent(struct device *dev, char **envp, int num_envp,
char *buffer, int buffer_size)
{ {
envp[0] = buffer; envp[0] = buffer;
envp[1] = NULL; envp[1] = NULL;
@ -33,8 +35,6 @@ static struct device mmap_bus = {
.release = mmap_bus_release, .release = mmap_bus_release,
}; };
int register_mmap_device(struct mmap_device *dev) int register_mmap_device(struct mmap_device *dev)
{ {
dev->dev.bus = &mmap_bus_type; dev->dev.bus = &mmap_bus_type;
@ -48,6 +48,7 @@ void unregister_mmap_device(struct mmap_device *dev)
{ {
device_unregister(&dev->dev); device_unregister(&dev->dev);
} }
EXPORT_SYMBOL(register_mmap_device); EXPORT_SYMBOL(register_mmap_device);
EXPORT_SYMBOL(unregister_mmap_device); EXPORT_SYMBOL(unregister_mmap_device);
@ -61,6 +62,7 @@ void unregister_mmap_driver(struct mmap_driver *driver)
{ {
driver_unregister(&driver->driver); driver_unregister(&driver->driver);
} }
EXPORT_SYMBOL(register_mmap_driver); EXPORT_SYMBOL(register_mmap_driver);
EXPORT_SYMBOL(unregister_mmap_driver); EXPORT_SYMBOL(unregister_mmap_driver);
@ -84,6 +86,7 @@ void unregister_mmap_bus(void)
device_unregister(&mmap_bus); device_unregister(&mmap_bus);
bus_unregister(&mmap_bus_type); bus_unregister(&mmap_bus_type);
} }
EXPORT_SYMBOL(register_mmap_bus); EXPORT_SYMBOL(register_mmap_bus);
EXPORT_SYMBOL(unregister_mmap_bus); EXPORT_SYMBOL(unregister_mmap_bus);

View File

@ -19,7 +19,9 @@
#include "xframe_queue.h" #include "xframe_queue.h"
/* Check at compile time that sizeof(xframe_t) is a multiple of 4 */ /* Check at compile time that sizeof(xframe_t) is a multiple of 4 */
typedef char sizeof_xframe_t_should_be_divisible_by_4[((sizeof(xframe_t) % 4) == 0) * 2 - 1]; typedef char
sizeof_xframe_t_should_be_divisible_by_4[((sizeof(xframe_t) % 4) ==
0) * 2 - 1];
#define ssync() __builtin_bfin_ssync() #define ssync() __builtin_bfin_ssync()
@ -96,7 +98,8 @@ static void update_counter(struct counter *c, struct timeval *tv1)
c->intr_min = diff; c->intr_min = diff;
if (c->intr_max < diff) if (c->intr_max < diff)
c->intr_max = diff; c->intr_max = diff;
c->intr_avg = (c->intr_avg*c->intr_count + diff) / (c->intr_count+1); c->intr_avg =
(c->intr_avg * c->intr_count + diff) / (c->intr_count + 1);
c->intr_count++; c->intr_count++;
} }
@ -153,18 +156,19 @@ static irqreturn_t xpp_mmap_rx_irq(int irq, void *dev_id)
outw(START_RD_BURST, FPGA_BASE_ADDR + 4); outw(START_RD_BURST, FPGA_BASE_ADDR + 4);
insw((unsigned long)FPGA_BASE_ADDR, buf, rxcnt / 2); insw((unsigned long)FPGA_BASE_ADDR, buf, rxcnt / 2);
#if 0 #if 0
for (count = 0; count < rxcnt; count+=2) { for (count = 0; count < rxcnt; count += 2) {
unsigned short v = inw(FPGA_BASE_ADDR); unsigned short v = inw(FPGA_BASE_ADDR);
buf[count] = v & 0xFF; buf[count] = v & 0xFF;
buf[count+1] = v >> 8; buf[count + 1] = v >> 8;
} }
#endif #endif
if (rxcnt & 1) if (rxcnt & 1)
buf[rxcnt-1] = inw(FPGA_BASE_ADDR); buf[rxcnt - 1] = inw(FPGA_BASE_ADDR);
/* Sanity check: length of first packet in frame should be no more than the frame length */ /* Sanity check: length of first packet in frame should be no more than the frame length */
if (((buf[0] | (buf[1]<<8)) & 0x3FF) > rxcnt) { if (((buf[0] | (buf[1] << 8)) & 0x3FF) > rxcnt) {
if (printk_ratelimit()) { if (printk_ratelimit()) {
ERR("Packet len=%d, frame len=%d\n", (buf[0] | (buf[1]<<8)) & 0x3FF, rxcnt); ERR("Packet len=%d, frame len=%d\n",
(buf[0] | (buf[1] << 8)) & 0x3FF, rxcnt);
print_buffer("16 bytes of packet: ", buf, 16); print_buffer("16 bytes of packet: ", buf, 16);
} }
goto free; goto free;
@ -199,7 +203,7 @@ static void send_buffer(unsigned char *buf, unsigned long len)
print_buffer("Sent: ", buf, len); print_buffer("Sent: ", buf, len);
outsw((unsigned long)FPGA_BASE_ADDR, buf, len / 2); outsw((unsigned long)FPGA_BASE_ADDR, buf, len / 2);
if (len & 1) if (len & 1)
outw((unsigned short)buf[len-1], FPGA_BASE_ADDR); outw((unsigned short)buf[len - 1], FPGA_BASE_ADDR);
outw(END_OF_FRAME, FPGA_BASE_ADDR + 4); outw(END_OF_FRAME, FPGA_BASE_ADDR + 4);
} }
@ -258,7 +262,9 @@ static int xframe_send_common(xbus_t *xbus, xframe_t *xframe, bool pcm)
if (pcm && pcm_in_pool_count >= 1) { if (pcm && pcm_in_pool_count >= 1) {
static int rate_limit; static int rate_limit;
if ((rate_limit++ % 1000) == 0) if ((rate_limit++ % 1000) == 0)
XBUS_ERR(xbus, "Dropped PCM xframe (pcm_in_pool_count=%d).\n", pcm_in_pool_count); XBUS_ERR(xbus,
"Dropped PCM xframe (pcm_in_pool_count=%d).\n",
pcm_in_pool_count);
FREE_SEND_XFRAME(xbus, xframe); FREE_SEND_XFRAME(xbus, xframe);
pcm_dropped++; pcm_dropped++;
} else { } else {
@ -266,7 +272,8 @@ static int xframe_send_common(xbus_t *xbus, xframe_t *xframe, bool pcm)
static int rate_limit; static int rate_limit;
spin_unlock_irqrestore(&tx_ready_lock, flags); spin_unlock_irqrestore(&tx_ready_lock, flags);
if ((rate_limit++ % 1000) == 0) if ((rate_limit++ % 1000) == 0)
XBUS_ERR(xbus, "Dropped xframe. Cannot enqueue.\n"); XBUS_ERR(xbus,
"Dropped xframe. Cannot enqueue.\n");
FREE_SEND_XFRAME(xbus, xframe); FREE_SEND_XFRAME(xbus, xframe);
return -E2BIG; return -E2BIG;
} }
@ -284,10 +291,12 @@ static xframe_t *alloc_xframe(xbus_t *xbus, gfp_t gfp_flags)
if (!xframe) { if (!xframe) {
static int rate_limit; static int rate_limit;
if ((rate_limit++ % 1000) < 5) if ((rate_limit++ % 1000) < 5)
XBUS_ERR(xbus, "frame allocation failed (%d)\n", rate_limit); XBUS_ERR(xbus, "frame allocation failed (%d)\n",
rate_limit);
return NULL; return NULL;
} }
xframe_init(xbus, xframe, ((__u8*)xframe) + sizeof(xframe_t), XFRAME_DATASIZE, xbus); xframe_init(xbus, xframe, ((__u8 *)xframe) + sizeof(xframe_t),
XFRAME_DATASIZE, xbus);
return xframe; return xframe;
} }
@ -318,15 +327,11 @@ static int fill_proc_queue(char *p, struct xframe_queue *q)
{ {
int len; int len;
len = sprintf(p, len =
sprintf(p,
"%-15s: counts %3d, %3d, %3d worst %3d, overflows %3d worst_lag %02ld.%ld ms\n", "%-15s: counts %3d, %3d, %3d worst %3d, overflows %3d worst_lag %02ld.%ld ms\n",
q->name, q->name, q->steady_state_count, q->count, q->max_count,
q->steady_state_count, q->worst_count, q->overflows, q->worst_lag_usec / 1000,
q->count,
q->max_count,
q->worst_count,
q->overflows,
q->worst_lag_usec / 1000,
q->worst_lag_usec % 1000); q->worst_lag_usec % 1000);
xframe_queue_clearstats(q); xframe_queue_clearstats(q);
return len; return len;
@ -334,10 +339,12 @@ static int fill_proc_queue(char *p, struct xframe_queue *q)
static int fill_proc_counter(char *p, struct counter *c) static int fill_proc_counter(char *p, struct counter *c)
{ {
return sprintf(p, "min=%ld\nmax=%ld\navg=%ld\ncount=%ld\n", c->intr_min, c->intr_max, c->intr_avg, c->intr_count); return sprintf(p, "min=%ld\nmax=%ld\navg=%ld\ncount=%ld\n", c->intr_min,
c->intr_max, c->intr_avg, c->intr_count);
} }
static int xpp_mmap_proc_read(char *page, char **start, off_t off, int count, int *eof, void *data) static int xpp_mmap_proc_read(char *page, char **start, off_t off, int count,
int *eof, void *data)
{ {
int len = 0; int len = 0;
len += fill_proc_queue(page + len, &txpool); len += fill_proc_queue(page + len, &txpool);
@ -347,7 +354,7 @@ static int xpp_mmap_proc_read(char *page, char **start, off_t off, int count, in
len += fill_proc_counter(page + len, &rx_counter); len += fill_proc_counter(page + len, &rx_counter);
len += sprintf(page + len, "\ntx_counter:\n"); len += sprintf(page + len, "\ntx_counter:\n");
len += fill_proc_counter(page + len, &tx_counter); len += fill_proc_counter(page + len, &tx_counter);
if (len <= off+count) { if (len <= off + count) {
*eof = 1; *eof = 1;
tx_counter.intr_min = rx_counter.intr_min = INT_MAX; tx_counter.intr_min = rx_counter.intr_min = INT_MAX;
tx_counter.intr_max = rx_counter.intr_max = 0; tx_counter.intr_max = rx_counter.intr_max = 0;
@ -363,14 +370,15 @@ static int xpp_mmap_proc_read(char *page, char **start, off_t off, int count, in
return len; return len;
} }
static int xpp_mmap_proc_write(struct file *file, const char __user *buffer, unsigned long count, void *data) static int xpp_mmap_proc_write(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{ {
int i = 0; int i = 0;
char *txchunk, *p, *endp; char *txchunk, *p, *endp;
if (count >= XFRAME_DATASIZE*3+10) if (count >= XFRAME_DATASIZE * 3 + 10)
return -EINVAL; return -EINVAL;
p = txchunk = kmalloc(count+1, GFP_KERNEL); p = txchunk = kmalloc(count + 1, GFP_KERNEL);
if (copy_from_user(txchunk, buffer, count)) { if (copy_from_user(txchunk, buffer, count)) {
count = -EFAULT; count = -EFAULT;
goto out; goto out;
@ -379,8 +387,10 @@ static int xpp_mmap_proc_write(struct file *file, const char __user *buffer, uns
while (*p) { while (*p) {
unsigned long value; unsigned long value;
while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') p++; while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r')
if (*p == '\0') break; p++;
if (*p == '\0')
break;
value = simple_strtoul(p, &endp, 16); value = simple_strtoul(p, &endp, 16);
if (endp == p || value > 0xFF) { if (endp == p || value > 0xFF) {
INFO("%s: Bad input\n", __func__); INFO("%s: Bad input\n", __func__);
@ -408,13 +418,14 @@ static struct mmap_device astribank_dev = {
.driver = &astribank_driver, .driver = &astribank_driver,
}; };
static int __init xpp_mmap_load_fpga(u8 *data, size_t size) static int __init xpp_mmap_load_fpga(u8 * data, size_t size)
{ {
size_t i; size_t i;
bfin_write_PORTGIO_DIR(bfin_read_PORTGIO_DIR() | DATA | NCONFIG | DCLK); //set data, nconfig and dclk to port out bfin_write_PORTGIO_DIR(bfin_read_PORTGIO_DIR() | DATA | NCONFIG | DCLK); //set data, nconfig and dclk to port out
bfin_write_PORTG_FER(bfin_read_PORTG_FER() & ~(DATA | NCONFIG | DCLK)); bfin_write_PORTG_FER(bfin_read_PORTG_FER() & ~(DATA | NCONFIG | DCLK));
bfin_write_PORTGIO_DIR(bfin_read_PORTGIO_DIR() & ~(CONF_DONE | NSTATUS));//set conf_done and nstatus to port in bfin_write_PORTGIO_DIR(bfin_read_PORTGIO_DIR() & ~(CONF_DONE | NSTATUS)); //set conf_done and nstatus to port in
bfin_write_PORTGIO_INEN(bfin_read_PORTGIO_INEN() & ~(DATA | NCONFIG | DCLK)); bfin_write_PORTGIO_INEN(bfin_read_PORTGIO_INEN() &
~(DATA | NCONFIG | DCLK));
bfin_write_PORTGIO_INEN(bfin_read_PORTGIO_INEN() | CONF_DONE | NSTATUS); bfin_write_PORTGIO_INEN(bfin_read_PORTGIO_INEN() | CONF_DONE | NSTATUS);
bfin_write_PORTGIO_CLEAR(NCONFIG); //reset fpga during configuration holds nCONFIG low bfin_write_PORTGIO_CLEAR(NCONFIG); //reset fpga during configuration holds nCONFIG low
@ -429,16 +440,16 @@ static int __init xpp_mmap_load_fpga(u8 *data, size_t size)
return -EIO; return -EIO;
#endif #endif
bfin_write_PORTGIO_CLEAR(DCLK); bfin_write_PORTGIO_CLEAR(DCLK);
for (i=0; i<size; i++) { // loop EP2OUT buffer data to FPGA for (i = 0; i < size; i++) { // loop EP2OUT buffer data to FPGA
int j; int j;
u8 __u8 = data[i]; u8 __u8 = data[i];
for (j=0; j<8; j++) //send the configuration data through the DATA0 pin one bit at a time. for (j = 0; j < 8; j++) //send the configuration data through the DATA0 pin one bit at a time.
{ {
if (__u8 & 1) if (__u8 &1)
bfin_write_PORTGIO_SET(DATA); bfin_write_PORTGIO_SET(DATA);
else else
bfin_write_PORTGIO_CLEAR(DATA); bfin_write_PORTGIO_CLEAR(DATA);
__u8 >>= 1; __u8 >>=1;
bfin_write_PORTGIO_SET(DCLK); bfin_write_PORTGIO_SET(DCLK);
bfin_write_PORTGIO_CLEAR(DCLK); bfin_write_PORTGIO_CLEAR(DCLK);
} }
@ -456,8 +467,10 @@ static int __init xpp_mmap_load_fpga(u8 *data, size_t size)
* to be used for debugging from now on. * to be used for debugging from now on.
*/ */
bfin_write_PORTGIO_DIR(bfin_read_PORTGIO_DIR() | DEBUG_GPIO1 | DEBUG_GPIO2); //set to port out bfin_write_PORTGIO_DIR(bfin_read_PORTGIO_DIR() | DEBUG_GPIO1 | DEBUG_GPIO2); //set to port out
bfin_write_PORTG_FER(bfin_read_PORTG_FER() & ~(DEBUG_GPIO1 | DEBUG_GPIO2)); bfin_write_PORTG_FER(bfin_read_PORTG_FER() &
bfin_write_PORTGIO_INEN(bfin_read_PORTGIO_INEN() & ~(DEBUG_GPIO1 | DEBUG_GPIO2)); ~(DEBUG_GPIO1 | DEBUG_GPIO2));
bfin_write_PORTGIO_INEN(bfin_read_PORTGIO_INEN() &
~(DEBUG_GPIO1 | DEBUG_GPIO2));
#endif #endif
udelay(40); //tCD2UM - CONF_DONE high to user mode udelay(40); //tCD2UM - CONF_DONE high to user mode
return 0; return 0;
@ -467,8 +480,8 @@ static void __exit xpp_mmap_unload_fpga(void)
{ {
bfin_write_PORTGIO_CLEAR(NCONFIG); //reset fpga during configuration holds nCONFIG low bfin_write_PORTGIO_CLEAR(NCONFIG); //reset fpga during configuration holds nCONFIG low
udelay(40); //Tcfg ~40us delay udelay(40); //Tcfg ~40us delay
bfin_write_PORTGIO_DIR(bfin_read_PORTGIO_DIR() & ~( DATA | NCONFIG | DCLK)); //disable output pin bfin_write_PORTGIO_DIR(bfin_read_PORTGIO_DIR() & ~(DATA | NCONFIG | DCLK)); //disable output pin
bfin_write_PORTGIO_INEN(bfin_read_PORTGIO_INEN() & ~( CONF_DONE | NSTATUS));//disable input buffer bfin_write_PORTGIO_INEN(bfin_read_PORTGIO_INEN() & ~(CONF_DONE | NSTATUS)); //disable input buffer
INFO("FPGA Firmware unloaded\n"); INFO("FPGA Firmware unloaded\n");
} }
@ -476,7 +489,8 @@ static int __init xpp_mmap_load_firmware(void)
{ {
const struct firmware *fw; const struct firmware *fw;
int ret; int ret;
if ((ret = request_firmware(&fw, "astribank.bin", &astribank_dev.dev)) < 0) if ((ret =
request_firmware(&fw, "astribank.bin", &astribank_dev.dev)) < 0)
return ret; return ret;
xpp_mmap_load_fpga(fw->data, fw->size); xpp_mmap_load_fpga(fw->data, fw->size);
release_firmware(fw); release_firmware(fw);
@ -499,23 +513,27 @@ static int __init xpp_mmap_init(void)
goto fail_fw; goto fail_fw;
} }
if ((ret = request_irq(FPGA_RX_IRQ, xpp_mmap_rx_irq, IRQF_TRIGGER_RISING, "xpp_mmap_rx", NULL)) < 0) { if ((ret =
request_irq(FPGA_RX_IRQ, xpp_mmap_rx_irq, IRQF_TRIGGER_RISING,
"xpp_mmap_rx", NULL)) < 0) {
ERR("Unable to attach to RX interrupt %d\n", FPGA_RX_IRQ); ERR("Unable to attach to RX interrupt %d\n", FPGA_RX_IRQ);
goto fail_irq_rx; goto fail_irq_rx;
} }
if ((ret = request_irq(FPGA_TX_IRQ, xpp_mmap_tx_irq, IRQF_TRIGGER_RISING, "xpp_mmap_tx", NULL)) < 0) { if ((ret =
request_irq(FPGA_TX_IRQ, xpp_mmap_tx_irq, IRQF_TRIGGER_RISING,
"xpp_mmap_tx", NULL)) < 0) {
ERR("Unable to attach to TX interrupt %d\n", FPGA_TX_IRQ); ERR("Unable to attach to TX interrupt %d\n", FPGA_TX_IRQ);
goto fail_irq_tx; goto fail_irq_tx;
} }
if (!request_region((resource_size_t)FPGA_BASE_ADDR, 8, "xpp_mmap")) { if (!request_region((resource_size_t) FPGA_BASE_ADDR, 8, "xpp_mmap")) {
ERR("Unable to request memory region at %p\n", FPGA_BASE_ADDR); ERR("Unable to request memory region at %p\n", FPGA_BASE_ADDR);
goto fail_region; goto fail_region;
} }
outw(AS_BF_MODE, FPGA_BASE_ADDR + 4); outw(AS_BF_MODE, FPGA_BASE_ADDR + 4);
xframe_cache = kmem_cache_create("xframe_cache", xframe_cache =
sizeof(xframe_t) + XFRAME_DATASIZE, kmem_cache_create("xframe_cache",
0, 0, sizeof(xframe_t) + XFRAME_DATASIZE, 0, 0,
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23)
NULL, NULL,
#endif #endif
@ -534,7 +552,9 @@ static int __init xpp_mmap_init(void)
strncpy(global_xbus->label, "mmap:0", LABEL_SIZE); strncpy(global_xbus->label, "mmap:0", LABEL_SIZE);
xframe_queue_init(&txpool, 10, 200, "mmap_txpool", global_xbus); xframe_queue_init(&txpool, 10, 200, "mmap_txpool", global_xbus);
if (!(proc_entry = create_proc_entry("xpp_mmap", 0, global_xbus->proc_xbus_dir))) { if (!
(proc_entry =
create_proc_entry("xpp_mmap", 0, global_xbus->proc_xbus_dir))) {
ERR("create_proc_entry() failed\n"); ERR("create_proc_entry() failed\n");
ret = -EINVAL; ret = -EINVAL;
goto fail_proc; goto fail_proc;
@ -552,7 +572,7 @@ fail_proc:
fail_xbus: fail_xbus:
kmem_cache_destroy(xframe_cache); kmem_cache_destroy(xframe_cache);
fail_cache: fail_cache:
release_region((resource_size_t)FPGA_BASE_ADDR, 8); release_region((resource_size_t) FPGA_BASE_ADDR, 8);
fail_region: fail_region:
free_irq(FPGA_TX_IRQ, NULL); free_irq(FPGA_TX_IRQ, NULL);
fail_irq_tx: fail_irq_tx:
@ -579,7 +599,7 @@ static void __exit xpp_mmap_exit(void)
xbus_disconnect(xbus); xbus_disconnect(xbus);
kmem_cache_destroy(xframe_cache); kmem_cache_destroy(xframe_cache);
release_region((resource_size_t)FPGA_BASE_ADDR, 8); release_region((resource_size_t) FPGA_BASE_ADDR, 8);
free_irq(FPGA_RX_IRQ, NULL); free_irq(FPGA_RX_IRQ, NULL);
free_irq(FPGA_TX_IRQ, NULL); free_irq(FPGA_TX_IRQ, NULL);

View File

@ -22,7 +22,7 @@
#include <linux/version.h> #include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
# warning "This module is tested only with 2.6 kernels" #warning "This module is tested only with 2.6 kernels"
#endif #endif
#include <linux/kernel.h> #include <linux/kernel.h>
@ -59,11 +59,13 @@ void flip_parport_bit(unsigned char bitnum)
spin_unlock_irqrestore(&lock, flags); spin_unlock_irqrestore(&lock, flags);
parport_write_data(debug_sync_parport, value); parport_write_data(debug_sync_parport, value);
} }
EXPORT_SYMBOL(flip_parport_bit); EXPORT_SYMBOL(flip_parport_bit);
static void parport_attach(struct parport *port) static void parport_attach(struct parport *port)
{ {
printk(KERN_INFO "%s: Using %s for debugging\n", THIS_MODULE->name, port->name); printk(KERN_INFO "%s: Using %s for debugging\n", THIS_MODULE->name,
port->name);
if (debug_sync_parport) { if (debug_sync_parport) {
printk(KERN_ERR "%s: Using %s, ignore new attachment %s\n", printk(KERN_ERR "%s: Using %s, ignore new attachment %s\n",
THIS_MODULE->name, debug_sync_parport->name, port->name); THIS_MODULE->name, debug_sync_parport->name, port->name);

View File

@ -4,10 +4,11 @@ int main(int argc, char *argv[])
{ {
size_t i; size_t i;
for (i=0; i<(sizeof(fxo_modes)/sizeof(struct fxo_mode)); i++) { for (i = 0; i < (sizeof(fxo_modes) / sizeof(struct fxo_mode)); i++) {
if (fxo_modes[i].name == NULL) break; if (fxo_modes[i].name == NULL)
int reg16=0, reg26=0, reg30=0, reg31=0x20; break;
char ring_osc[BUFSIZ]="", ring_x[BUFSIZ] = ""; int reg16 = 0, reg26 = 0, reg30 = 0, reg31 = 0x20;
char ring_osc[BUFSIZ] = "", ring_x[BUFSIZ] = "";
reg16 |= (fxo_modes[i].ohs << 6); reg16 |= (fxo_modes[i].ohs << 6);
reg16 |= (fxo_modes[i].rz << 1); reg16 |= (fxo_modes[i].rz << 1);
@ -22,11 +23,15 @@ int main(int argc, char *argv[])
reg31 |= (fxo_modes[i].ohs2 << 3); reg31 |= (fxo_modes[i].ohs2 << 3);
if (fxo_modes[i].ring_osc) if (fxo_modes[i].ring_osc)
snprintf(ring_osc, BUFSIZ, "ring_osc=%04X", fxo_modes[i].ring_osc); snprintf(ring_osc, BUFSIZ, "ring_osc=%04X",
fxo_modes[i].ring_osc);
if (fxo_modes[i].ring_x) if (fxo_modes[i].ring_x)
snprintf(ring_x, BUFSIZ, "ring_x=%04X", fxo_modes[i].ring_x); snprintf(ring_x, BUFSIZ, "ring_x=%04X",
printf("%-15s\treg16=%02X\treg26=%02X\treg30=%02X\treg31=%02X\t%s\t%s\n", fxo_modes[i].ring_x);
fxo_modes[i].name, reg16, reg26, reg30, reg31, ring_osc, ring_x); printf
("%-15s\treg16=%02X\treg26=%02X\treg30=%02X\treg31=%02X\t%s\t%s\n",
fxo_modes[i].name, reg16, reg26, reg30, reg31, ring_osc,
ring_x);
} }
return 0; return 0;
} }

View File

@ -22,7 +22,7 @@
#include <linux/version.h> #include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
# warning "This module is tested only with 2.6 kernels" #warning "This module is tested only with 2.6 kernels"
#endif #endif
#include <linux/kernel.h> #include <linux/kernel.h>
@ -52,22 +52,28 @@ static const char rcsid[] = "$Id$";
#ifdef PROTOCOL_DEBUG #ifdef PROTOCOL_DEBUG
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
#define PROC_XBUS_COMMAND "command" #define PROC_XBUS_COMMAND "command"
static int proc_xbus_command_write(struct file *file, const char __user *buffer, unsigned long count, void *data); static int proc_xbus_command_write(struct file *file, const char __user *buffer,
unsigned long count, void *data);
#endif #endif
#endif #endif
/* Command line parameters */ /* Command line parameters */
extern int debug; extern int debug;
static DEF_PARM(uint, command_queue_length, 1500, 0444, "Maximal command queue length"); static DEF_PARM(uint, command_queue_length, 1500, 0444,
static DEF_PARM(uint, poll_timeout, 1000, 0644, "Timeout (in jiffies) waiting for units to reply"); "Maximal command queue length");
static DEF_PARM(uint, poll_timeout, 1000, 0644,
"Timeout (in jiffies) waiting for units to reply");
static DEF_PARM_BOOL(rx_tasklet, 0, 0644, "Use receive tasklets"); static DEF_PARM_BOOL(rx_tasklet, 0, 0644, "Use receive tasklets");
static DEF_PARM_BOOL(dahdi_autoreg, 0, 0644, static DEF_PARM_BOOL(dahdi_autoreg, 0, 0644,
"Register devices automatically (1) or not (0)"); "Register devices automatically (1) or not (0)");
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
static int xbus_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data); static int xbus_read_proc(char *page, char **start, off_t off, int count,
int *eof, void *data);
#endif #endif
static void transport_init(xbus_t *xbus, struct xbus_ops *ops, ushort max_send_size, struct device *transport_device, void *priv); static void transport_init(xbus_t *xbus, struct xbus_ops *ops,
ushort max_send_size,
struct device *transport_device, void *priv);
static void transport_destroy(xbus_t *xbus); static void transport_destroy(xbus_t *xbus);
/* Data structures */ /* Data structures */
@ -105,8 +111,7 @@ int xbus_check_unique(xbus_t *xbus)
if (xbus_old && xbus_old != xbus) { if (xbus_old && xbus_old != xbus) {
XBUS_NOTICE(xbus_old, XBUS_NOTICE(xbus_old,
"Duplicate LABEL='%s'. Leave %s unused. refcount_xbus=%d\n", "Duplicate LABEL='%s'. Leave %s unused. refcount_xbus=%d\n",
xbus_old->label, xbus_old->label, xbus->busname,
xbus->busname,
refcount_xbus(xbus_old)); refcount_xbus(xbus_old));
return -EBUSY; return -EBUSY;
} }
@ -119,14 +124,22 @@ int xbus_check_unique(xbus_t *xbus)
const char *xbus_statename(enum xbus_state st) const char *xbus_statename(enum xbus_state st)
{ {
switch (st) { switch (st) {
case XBUS_STATE_START: return "START"; case XBUS_STATE_START:
case XBUS_STATE_IDLE: return "IDLE"; return "START";
case XBUS_STATE_SENT_REQUEST: return "SENT_REQUEST"; case XBUS_STATE_IDLE:
case XBUS_STATE_RECVD_DESC: return "RECVD_DESC"; return "IDLE";
case XBUS_STATE_READY: return "READY"; case XBUS_STATE_SENT_REQUEST:
case XBUS_STATE_DEACTIVATING: return "DEACTIVATING"; return "SENT_REQUEST";
case XBUS_STATE_DEACTIVATED: return "DEACTIVATED"; case XBUS_STATE_RECVD_DESC:
case XBUS_STATE_FAIL: return "FAIL"; return "RECVD_DESC";
case XBUS_STATE_READY:
return "READY";
case XBUS_STATE_DEACTIVATING:
return "DEACTIVATING";
case XBUS_STATE_DEACTIVATED:
return "DEACTIVATED";
case XBUS_STATE_FAIL:
return "FAIL";
} }
return NULL; return NULL;
} }
@ -191,8 +204,8 @@ xbus_t *get_xbus(const char *msg, uint num)
xbus = xbus_num(num); xbus = xbus_num(num);
if (xbus != NULL) { if (xbus != NULL) {
kref_get(&xbus->kref); kref_get(&xbus->kref);
XBUS_DBG(DEVICES, xbus, "%s: refcount_xbus=%d\n", XBUS_DBG(DEVICES, xbus, "%s: refcount_xbus=%d\n", msg,
msg, refcount_xbus(xbus)); refcount_xbus(xbus));
} }
spin_unlock_irqrestore(&xbuses_lock, flags); spin_unlock_irqrestore(&xbuses_lock, flags);
return xbus; return xbus;
@ -200,8 +213,8 @@ xbus_t *get_xbus(const char *msg, uint num)
void put_xbus(const char *msg, xbus_t *xbus) void put_xbus(const char *msg, xbus_t *xbus)
{ {
XBUS_DBG(DEVICES, xbus, "%s: refcount_xbus=%d\n", XBUS_DBG(DEVICES, xbus, "%s: refcount_xbus=%d\n", msg,
msg, refcount_xbus(xbus)); refcount_xbus(xbus));
kref_put(&xbus->kref, xbus_destroy); kref_put(&xbus->kref, xbus_destroy);
} }
@ -214,7 +227,8 @@ int refcount_xbus(xbus_t *xbus)
/*------------------------- Frame Handling ------------------------*/ /*------------------------- Frame Handling ------------------------*/
void xframe_init(xbus_t *xbus, xframe_t *xframe, void *buf, size_t maxsize, void *priv) void xframe_init(xbus_t *xbus, xframe_t *xframe, void *buf, size_t maxsize,
void *priv)
{ {
memset(xframe, 0, sizeof(*xframe)); memset(xframe, 0, sizeof(*xframe));
INIT_LIST_HEAD(&xframe->frame_list); INIT_LIST_HEAD(&xframe->frame_list);
@ -260,7 +274,8 @@ static void do_hexdump(const char msg[], __u8 *data, uint16_t len)
DBG(ANY, "%s: %3d> %02X\n", msg, i, data[i]); DBG(ANY, "%s: %3d> %02X\n", msg, i, data[i]);
} }
void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe, int debug) void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe,
int debug)
{ {
const uint16_t frm_len = XFRAME_LEN(xframe); const uint16_t frm_len = XFRAME_LEN(xframe);
xpacket_t *pack; xpacket_t *pack;
@ -271,15 +286,16 @@ void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe, i
unsigned long flags; unsigned long flags;
if (xframe->xframe_magic != XFRAME_MAGIC) { if (xframe->xframe_magic != XFRAME_MAGIC) {
XBUS_ERR(xbus, "%s: bad xframe_magic %lX\n", XBUS_ERR(xbus, "%s: bad xframe_magic %lX\n", __func__,
__func__, xframe->xframe_magic); xframe->xframe_magic);
return; return;
} }
spin_lock_irqsave(&serialize_dump_xframe, flags); spin_lock_irqsave(&serialize_dump_xframe, flags);
do { do {
if (pos >= xbus->transport.max_send_size) { if (pos >= xbus->transport.max_send_size) {
if (printk_ratelimit()) { if (printk_ratelimit()) {
XBUS_NOTICE(xbus, "%s: xframe overflow (%d bytes)\n", XBUS_NOTICE(xbus,
"%s: xframe overflow (%d bytes)\n",
msg, frm_len); msg, frm_len);
do_hexdump(msg, xframe->packets, frm_len); do_hexdump(msg, xframe->packets, frm_len);
} }
@ -287,7 +303,8 @@ void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe, i
} }
if (pos > frm_len) { if (pos > frm_len) {
if (printk_ratelimit()) { if (printk_ratelimit()) {
XBUS_NOTICE(xbus, "%s: packet overflow pos=%d frame_len=%d\n", XBUS_NOTICE(xbus,
"%s: packet overflow pos=%d frame_len=%d\n",
msg, pos, frm_len); msg, pos, frm_len);
do_hexdump(msg, xframe->packets, frm_len); do_hexdump(msg, xframe->packets, frm_len);
} }
@ -296,8 +313,10 @@ void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe, i
pack = (xpacket_t *)&xframe->packets[pos]; pack = (xpacket_t *)&xframe->packets[pos];
if (XPACKET_LEN(pack) <= 0) { if (XPACKET_LEN(pack) <= 0) {
if (printk_ratelimit()) { if (printk_ratelimit()) {
XBUS_NOTICE(xbus, "%s: xframe -- bad packet_len=%d pos=%d frame_len=%d\n", XBUS_NOTICE(xbus,
msg, XPACKET_LEN(pack), pos, frm_len); "%s: xframe -- bad packet_len=%d pos=%d frame_len=%d\n",
msg, XPACKET_LEN(pack), pos,
frm_len);
do_hexdump(msg, xframe->packets, frm_len); do_hexdump(msg, xframe->packets, frm_len);
} }
break; break;
@ -305,7 +324,8 @@ void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe, i
nextpos = pos + XPACKET_LEN(pack); nextpos = pos + XPACKET_LEN(pack);
if (nextpos > frm_len) { if (nextpos > frm_len) {
if (printk_ratelimit()) { if (printk_ratelimit()) {
XBUS_NOTICE(xbus, "%s: packet overflow nextpos=%d frame_len=%d\n", XBUS_NOTICE(xbus,
"%s: packet overflow nextpos=%d frame_len=%d\n",
msg, nextpos, frm_len); msg, nextpos, frm_len);
do_hexdump(msg, xframe->packets, frm_len); do_hexdump(msg, xframe->packets, frm_len);
} }
@ -314,8 +334,8 @@ void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe, i
do_print = 0; do_print = 0;
if (debug == DBG_ANY) if (debug == DBG_ANY)
do_print = 1; do_print = 1;
else if (XPACKET_OP(pack) != XPROTO_NAME(GLOBAL, PCM_READ) && else if (XPACKET_OP(pack) != XPROTO_NAME(GLOBAL, PCM_READ)
XPACKET_OP(pack) != XPROTO_NAME(GLOBAL, PCM_WRITE)) && XPACKET_OP(pack) != XPROTO_NAME(GLOBAL, PCM_WRITE))
do_print = 1; do_print = 1;
else if (debug & DBG_PCM) { else if (debug & DBG_PCM) {
static int rate_limit; static int rate_limit;
@ -326,17 +346,15 @@ void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe, i
if (do_print) { if (do_print) {
if (num == 1) { if (num == 1) {
XBUS_DBG(ANY, xbus, "%s: frame_len=%d. %s\n", XBUS_DBG(ANY, xbus, "%s: frame_len=%d. %s\n",
msg, frm_len, msg, frm_len, (XPACKET_IS_PCM(pack))
(XPACKET_IS_PCM(pack)) ? "(IS_PCM)" : "");
? "(IS_PCM)"
: "");
} }
XBUS_DBG(ANY, xbus, " %3d. DATALEN=%d pcm=%d slot=%d OP=0x%02X XPD-%d%d (pos=%d)\n", XBUS_DBG(ANY, xbus,
num, XPACKET_LEN(pack), " %3d. DATALEN=%d pcm=%d slot=%d OP=0x%02X XPD-%d%d (pos=%d)\n",
XPACKET_IS_PCM(pack), XPACKET_PCMSLOT(pack), num, XPACKET_LEN(pack), XPACKET_IS_PCM(pack),
XPACKET_OP(pack), XPACKET_PCMSLOT(pack), XPACKET_OP(pack),
XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack), XPACKET_ADDR_UNIT(pack),
pos); XPACKET_ADDR_SUBUNIT(pack), pos);
dump_packet(" ", pack, debug); dump_packet(" ", pack, debug);
} }
num++; num++;
@ -360,7 +378,8 @@ int send_pcm_frame(xbus_t *xbus, xframe_t *xframe)
BUG_ON(!xframe); BUG_ON(!xframe);
if (!XBUS_IS(xbus, READY)) { if (!XBUS_IS(xbus, READY)) {
XBUS_ERR(xbus, "Dropped a pcm frame -- hardware is not ready.\n"); XBUS_ERR(xbus,
"Dropped a pcm frame -- hardware is not ready.\n");
ret = -ENODEV; ret = -ENODEV;
goto error; goto error;
} }
@ -386,7 +405,8 @@ static int really_send_cmd_frame(xbus_t *xbus, xframe_t *xframe)
BUG_ON(!xframe); BUG_ON(!xframe);
BUG_ON(xframe->xframe_magic != XFRAME_MAGIC); BUG_ON(xframe->xframe_magic != XFRAME_MAGIC);
if (!XBUS_FLAGS(xbus, CONNECTED)) { if (!XBUS_FLAGS(xbus, CONNECTED)) {
XBUS_ERR(xbus, "Dropped command before sending -- hardware deactivated.\n"); XBUS_ERR(xbus,
"Dropped command before sending -- hardware deactivated.\n");
dump_xframe("Dropped", xbus, xframe, DBG_ANY); dump_xframe("Dropped", xbus, xframe, DBG_ANY);
FREE_SEND_XFRAME(xbus, xframe); FREE_SEND_XFRAME(xbus, xframe);
return -ENODEV; return -ENODEV;
@ -451,8 +471,10 @@ static int xbus_command_queue_waitempty(xbus_t *xbus)
int ret; int ret;
XBUS_DBG(DEVICES, xbus, "Waiting for command_queue to empty\n"); XBUS_DBG(DEVICES, xbus, "Waiting for command_queue to empty\n");
ret = wait_event_interruptible(xbus->command_queue_empty, ret =
xframe_queue_count(&xbus->command_queue) == 0); wait_event_interruptible(xbus->command_queue_empty,
xframe_queue_count(&xbus->command_queue) ==
0);
if (ret) { if (ret) {
XBUS_ERR(xbus, "waiting for command_queue interrupted!!!\n"); XBUS_ERR(xbus, "waiting for command_queue interrupted!!!\n");
} }
@ -464,10 +486,10 @@ int send_cmd_frame(xbus_t *xbus, xframe_t *xframe)
static int rate_limit; static int rate_limit;
int ret = 0; int ret = 0;
BUG_ON(xframe->xframe_magic != XFRAME_MAGIC); BUG_ON(xframe->xframe_magic != XFRAME_MAGIC);
if (!XBUS_FLAGS(xbus, CONNECTED)) { if (!XBUS_FLAGS(xbus, CONNECTED)) {
XBUS_ERR(xbus, "Dropped command before queueing -- hardware deactivated.\n"); XBUS_ERR(xbus,
"Dropped command before queueing -- hardware deactivated.\n");
ret = -ENODEV; ret = -ENODEV;
goto err; goto err;
} }
@ -502,7 +524,9 @@ static void xframe_enqueue_recv(xbus_t *xbus, xframe_t *xframe)
static int rate_limit; static int rate_limit;
if ((rate_limit++ % 1003) == 0) if ((rate_limit++ % 1003) == 0)
XBUS_ERR(xbus, "Failed to enqueue for receive_tasklet (%d)\n", rate_limit); XBUS_ERR(xbus,
"Failed to enqueue for receive_tasklet (%d)\n",
rate_limit);
FREE_RECV_XFRAME(xbus, xframe); /* return to receive_pool */ FREE_RECV_XFRAME(xbus, xframe); /* return to receive_pool */
return; return;
} }
@ -569,8 +593,8 @@ int xbus_xpd_bind(xbus_t *xbus, xpd_t *xpd, int unit, int subunit)
if (xbus->xpds[xpd_num] != NULL) { if (xbus->xpds[xpd_num] != NULL) {
xpd_t *other = xbus->xpds[xpd_num]; xpd_t *other = xbus->xpds[xpd_num];
XBUS_ERR(xbus, "xpd_num=%d is occupied by %p (%s)\n", XBUS_ERR(xbus, "xpd_num=%d is occupied by %p (%s)\n", xpd_num,
xpd_num, other, other->xpdname); other, other->xpdname);
BUG(); BUG();
} }
snprintf(xpd->xpdname, XPD_NAMELEN, "XPD-%1d%1d", unit, subunit); snprintf(xpd->xpdname, XPD_NAMELEN, "XPD-%1d%1d", unit, subunit);
@ -599,7 +623,8 @@ int xbus_xpd_unbind(xbus_t *xbus, xpd_t *xpd)
BUG(); BUG();
} }
if (xbus->xpds[xpd_num] == NULL) { if (xbus->xpds[xpd_num] == NULL) {
XBUS_ERR(xbus, "%s: slot xpd_num=%d is empty\n", __func__, xpd_num); XBUS_ERR(xbus, "%s: slot xpd_num=%d is empty\n", __func__,
xpd_num);
BUG(); BUG();
} }
if (xbus->xpds[xpd_num] != xpd) { if (xbus->xpds[xpd_num] != xpd) {
@ -618,13 +643,8 @@ int xbus_xpd_unbind(xbus_t *xbus, xpd_t *xpd)
return 0; return 0;
} }
static int new_card(xbus_t *xbus, static int new_card(xbus_t *xbus, int unit, __u8 type, __u8 subtype,
int unit, __u8 numchips, __u8 ports_per_chip, __u8 ports,
__u8 type,
__u8 subtype,
__u8 numchips,
__u8 ports_per_chip,
__u8 ports,
__u8 port_dir) __u8 port_dir)
{ {
const xproto_table_t *proto_table; const xproto_table_t *proto_table;
@ -654,18 +674,13 @@ static int new_card(xbus_t *xbus,
xbus->echo_state.xpd_idx = XPD_IDX(unit, 0); xbus->echo_state.xpd_idx = XPD_IDX(unit, 0);
} }
remaining_ports = ports; remaining_ports = ports;
subunits = (ports + proto_table->ports_per_subunit - 1) / subunits =
proto_table->ports_per_subunit; (ports + proto_table->ports_per_subunit -
XBUS_DBG(DEVICES, xbus, "CARD %d type=%d.%d ports=%d (%dx%d), %d subunits, port-dir=0x%02X\n", 1) / proto_table->ports_per_subunit;
unit, XBUS_DBG(DEVICES, xbus,
type, "CARD %d type=%d.%d ports=%d (%dx%d), %d subunits, port-dir=0x%02X\n",
subtype, unit, type, subtype, ports, numchips, ports_per_chip, subunits,
ports, port_dir);
numchips,
ports_per_chip,
subunits,
port_dir
);
if (type == XPD_TYPE_PRI || type == XPD_TYPE_BRI) if (type == XPD_TYPE_PRI || type == XPD_TYPE_BRI)
xbus->quirks.has_digital_span = 1; xbus->quirks.has_digital_span = 1;
if (type == XPD_TYPE_FXO) if (type == XPD_TYPE_FXO)
@ -680,31 +695,26 @@ static int new_card(xbus_t *xbus,
if (subunit_ports <= 0) { if (subunit_ports <= 0) {
XBUS_NOTICE(xbus, XBUS_NOTICE(xbus,
"Subunit XPD=%d%d without ports (%d of %d)\n", "Subunit XPD=%d%d without ports (%d of %d)\n",
unit, unit, i, subunit_ports, ports);
i,
subunit_ports,
ports);
ret = -ENODEV; ret = -ENODEV;
goto out; goto out;
} }
if (!XBUS_IS(xbus, RECVD_DESC)) { if (!XBUS_IS(xbus, RECVD_DESC)) {
XBUS_NOTICE(xbus, XBUS_NOTICE(xbus,
"Cannot create XPD=%d%d in state %s\n", "Cannot create XPD=%d%d in state %s\n",
unit, unit, i, xbus_statename(XBUS_STATE(xbus)));
i,
xbus_statename(XBUS_STATE(xbus)));
ret = -ENODEV; ret = -ENODEV;
goto out; goto out;
} }
XBUS_DBG(DEVICES, xbus, "Creating XPD=%d%d type=%d.%d (%d ports)\n", XBUS_DBG(DEVICES, xbus,
unit, "Creating XPD=%d%d type=%d.%d (%d ports)\n", unit, i,
i, type, subtype, subunit_ports);
type, ret =
subtype, subunit_ports); create_xpd(xbus, proto_table, unit, i, type, subtype,
ret = create_xpd(xbus, proto_table, unit, i, type, subtype, subunits, subunit_ports, port_dir); subunits, subunit_ports, port_dir);
if (ret < 0) { if (ret < 0) {
XBUS_ERR(xbus, "Creation of XPD=%d%d failed %d\n", XBUS_ERR(xbus, "Creation of XPD=%d%d failed %d\n", unit,
unit, i, ret); i, ret);
goto out; goto out;
} }
xbus->worker.num_units_initialized++; xbus->worker.num_units_initialized++;
@ -748,7 +758,7 @@ out:
spin_unlock_irqrestore(&xbus->lock, flags); spin_unlock_irqrestore(&xbus->lock, flags);
return ret; return ret;
err: err:
for (--i ; i >= 0; i--) { for (--i; i >= 0; i--) {
xpd = xpd_of(xbus, i); xpd = xpd_of(xbus, i);
if (xpd) if (xpd)
put_xpd(__func__, xpd); put_xpd(__func__, xpd);
@ -845,8 +855,7 @@ static int xbus_initialize(xbus_t *xbus)
int res = 0; int res = 0;
do_gettimeofday(&time_start); do_gettimeofday(&time_start);
XBUS_DBG(DEVICES, xbus, "refcount_xbus=%d\n", XBUS_DBG(DEVICES, xbus, "refcount_xbus=%d\n", refcount_xbus(xbus));
refcount_xbus(xbus));
if (xbus_aquire_xpds(xbus) < 0) /* Until end of initialization */ if (xbus_aquire_xpds(xbus) < 0) /* Until end of initialization */
return -EBUSY; return -EBUSY;
for (unit = 0; unit < MAX_UNIT; unit++) { for (unit = 0; unit < MAX_UNIT; unit++) {
@ -856,12 +865,13 @@ static int xbus_initialize(xbus_t *xbus)
if (!XBUS_IS(xbus, RECVD_DESC)) { if (!XBUS_IS(xbus, RECVD_DESC)) {
XBUS_NOTICE(xbus, XBUS_NOTICE(xbus,
"Cannot initialize UNIT=%d in state %s\n", "Cannot initialize UNIT=%d in state %s\n",
unit, unit, xbus_statename(XBUS_STATE(xbus)));
xbus_statename(XBUS_STATE(xbus)));
goto err; goto err;
} }
if (run_initialize_registers(xpd) < 0) { if (run_initialize_registers(xpd) < 0) {
XBUS_ERR(xbus, "Register Initialization of card #%d failed\n", unit); XBUS_ERR(xbus,
"Register Initialization of card #%d failed\n",
unit);
goto err; goto err;
} }
for (subunit = 0; subunit < MAX_SUBUNIT; subunit++) { for (subunit = 0; subunit < MAX_SUBUNIT; subunit++) {
@ -884,8 +894,9 @@ static int xbus_initialize(xbus_t *xbus)
xbus_echocancel(xbus, 1); xbus_echocancel(xbus, 1);
do_gettimeofday(&time_end); do_gettimeofday(&time_end);
timediff = usec_diff(&time_end, &time_start); timediff = usec_diff(&time_end, &time_start);
timediff /= 1000*100; timediff /= 1000 * 100;
XBUS_INFO(xbus, "Initialized in %ld.%1ld sec\n", timediff/10, timediff%10); XBUS_INFO(xbus, "Initialized in %ld.%1ld sec\n", timediff / 10,
timediff % 10);
out: out:
xbus_release_xpds(xbus); /* Initialization done/failed */ xbus_release_xpds(xbus); /* Initialization done/failed */
return res; return res;
@ -1000,7 +1011,8 @@ void xbus_unregister_dahdi_device(xbus_t *xbus)
} }
if (xbus->ddev) { if (xbus->ddev) {
dahdi_unregister_device(xbus->ddev); dahdi_unregister_device(xbus->ddev);
XBUS_NOTICE(xbus, "%s: finished dahdi_unregister_device()\n", __func__); XBUS_NOTICE(xbus, "%s: finished dahdi_unregister_device()\n",
__func__);
xbus_free_ddev(xbus); xbus_free_ddev(xbus);
} }
for (i = 0; i < MAX_XPDS; i++) { for (i = 0; i < MAX_XPDS; i++) {
@ -1017,7 +1029,8 @@ void xbus_unregister_dahdi_device(xbus_t *xbus)
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
static 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); struct xbus_workqueue *worker =
container_of(work, struct xbus_workqueue, xpds_init_work);
#else #else
void xbus_populate(void *data) void xbus_populate(void *data)
{ {
@ -1034,19 +1047,17 @@ void xbus_populate(void *data)
XBUS_DBG(DEVICES, xbus, "Entering %s\n", __func__); XBUS_DBG(DEVICES, xbus, "Entering %s\n", __func__);
spin_lock_irqsave(&worker->worker_lock, flags); spin_lock_irqsave(&worker->worker_lock, flags);
list_for_each_safe(card, next_card, &worker->card_list) { 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); struct card_desc_struct *card_desc =
list_entry(card, struct card_desc_struct, card_list);
list_del(card); list_del(card);
BUG_ON(card_desc->magic != CARD_DESC_MAGIC); BUG_ON(card_desc->magic != CARD_DESC_MAGIC);
/* Release/Reacquire locks around blocking calls */ /* Release/Reacquire locks around blocking calls */
spin_unlock_irqrestore(&xbus->worker.worker_lock, flags); spin_unlock_irqrestore(&xbus->worker.worker_lock, flags);
ret = new_card(xbus, ret =
card_desc->xpd_addr.unit, new_card(xbus, card_desc->xpd_addr.unit, card_desc->type,
card_desc->type, card_desc->subtype, card_desc->numchips,
card_desc->subtype, card_desc->ports_per_chip, card_desc->ports,
card_desc->numchips,
card_desc->ports_per_chip,
card_desc->ports,
card_desc->port_dir); card_desc->port_dir);
spin_lock_irqsave(&xbus->worker.worker_lock, flags); spin_lock_irqsave(&xbus->worker.worker_lock, flags);
KZFREE(card_desc); KZFREE(card_desc);
@ -1055,12 +1066,14 @@ void xbus_populate(void *data)
} }
spin_unlock_irqrestore(&worker->worker_lock, flags); spin_unlock_irqrestore(&worker->worker_lock, flags);
if (xbus_initialize(xbus) < 0) { if (xbus_initialize(xbus) < 0) {
XBUS_NOTICE(xbus, "Initialization failed. Leave unused. refcount_xbus=%d\n", XBUS_NOTICE(xbus,
"Initialization failed. Leave unused. refcount_xbus=%d\n",
refcount_xbus(xbus)); refcount_xbus(xbus));
goto failed; goto failed;
} }
if (!xbus_setstate(xbus, XBUS_STATE_READY)) { if (!xbus_setstate(xbus, XBUS_STATE_READY)) {
XBUS_NOTICE(xbus, "Illegal transition. Leave unused. refcount_xbus=%d\n", XBUS_NOTICE(xbus,
"Illegal transition. Leave unused. refcount_xbus=%d\n",
refcount_xbus(xbus)); refcount_xbus(xbus));
goto failed; goto failed;
} }
@ -1096,7 +1109,8 @@ int xbus_process_worker(xbus_t *xbus)
} }
worker = &xbus->worker; worker = &xbus->worker;
if (down_trylock(&worker->running_initialization)) { if (down_trylock(&worker->running_initialization)) {
ERR("%s: xbus is disconnected -- skip initialization\n", __func__); ERR("%s: xbus is disconnected -- skip initialization\n",
__func__);
return 0; return 0;
} }
XBUS_DBG(DEVICES, xbus, "\n"); XBUS_DBG(DEVICES, xbus, "\n");
@ -1129,12 +1143,13 @@ static void worker_reset(xbus_t *xbus)
name = (xbus) ? xbus->busname : "detached"; name = (xbus) ? xbus->busname : "detached";
DBG(DEVICES, "%s\n", name); DBG(DEVICES, "%s\n", name);
if (!worker->xpds_init_done) { if (!worker->xpds_init_done) {
NOTICE("%s: worker(%s)->xpds_init_done=%d\n", NOTICE("%s: worker(%s)->xpds_init_done=%d\n", __func__, name,
__func__, name, worker->xpds_init_done); worker->xpds_init_done);
} }
spin_lock_irqsave(&worker->worker_lock, flags); spin_lock_irqsave(&worker->worker_lock, flags);
list_for_each_safe(card, next_card, &worker->card_list) { 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); struct card_desc_struct *card_desc =
list_entry(card, struct card_desc_struct, card_list);
BUG_ON(card_desc->magic != CARD_DESC_MAGIC); BUG_ON(card_desc->magic != CARD_DESC_MAGIC);
list_del(card); list_del(card);
@ -1215,8 +1230,7 @@ bool xbus_setflags(xbus_t *xbus, int flagbit, bool on)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&xbus->transport.state_lock, flags); spin_lock_irqsave(&xbus->transport.state_lock, flags);
XBUS_DBG(DEVICES, xbus, "%s flag %d\n", XBUS_DBG(DEVICES, xbus, "%s flag %d\n", (on) ? "Set" : "Clear",
(on) ? "Set" : "Clear",
flagbit); flagbit);
if (on) if (on)
set_bit(flagbit, &(xbus->transport.transport_flags)); set_bit(flagbit, &(xbus->transport.transport_flags));
@ -1243,13 +1257,11 @@ bool xbus_setstate(xbus_t *xbus, enum xbus_state newstate)
case XBUS_STATE_START: case XBUS_STATE_START:
goto bad_state; goto bad_state;
case XBUS_STATE_IDLE: case XBUS_STATE_IDLE:
if (!XBUS_IS(xbus, START) && if (!XBUS_IS(xbus, START) && !XBUS_IS(xbus, DEACTIVATED))
!XBUS_IS(xbus, DEACTIVATED))
goto bad_state; goto bad_state;
break; break;
case XBUS_STATE_SENT_REQUEST: case XBUS_STATE_SENT_REQUEST:
if (!XBUS_IS(xbus, IDLE) && if (!XBUS_IS(xbus, IDLE) && !XBUS_IS(xbus, SENT_REQUEST))
!XBUS_IS(xbus, SENT_REQUEST))
goto bad_state; goto bad_state;
break; break;
case XBUS_STATE_RECVD_DESC: case XBUS_STATE_RECVD_DESC:
@ -1282,10 +1294,10 @@ bool xbus_setstate(xbus_t *xbus, enum xbus_state newstate)
goto out; goto out;
} }
/* All good */ /* All good */
XBUS_DBG(DEVICES, xbus, "%s -> %s\n", XBUS_DBG(DEVICES, xbus, "%s -> %s\n", xbus_statename(XBUS_STATE(xbus)),
xbus_statename(XBUS_STATE(xbus)),
xbus_statename(newstate)); xbus_statename(newstate));
if (xbus->transport.xbus_state == XBUS_STATE_READY && newstate != XBUS_STATE_READY) if (xbus->transport.xbus_state == XBUS_STATE_READY
&& newstate != XBUS_STATE_READY)
state_flip = -1; /* We became bad */ state_flip = -1; /* We became bad */
xbus->transport.xbus_state = newstate; xbus->transport.xbus_state = newstate;
ret = 1; ret = 1;
@ -1299,8 +1311,7 @@ out:
return ret; return ret;
bad_state: bad_state:
XBUS_NOTICE(xbus, "Bad state transition %s -> %s ignored.\n", XBUS_NOTICE(xbus, "Bad state transition %s -> %s ignored.\n",
xbus_statename(XBUS_STATE(xbus)), xbus_statename(XBUS_STATE(xbus)), xbus_statename(newstate));
xbus_statename(newstate));
goto out; goto out;
} }
@ -1408,7 +1419,6 @@ out:
return xbus; return xbus;
} }
void xbus_free(xbus_t *xbus) void xbus_free(xbus_t *xbus)
{ {
unsigned long flags; unsigned long flags;
@ -1425,14 +1435,18 @@ void xbus_free(xbus_t *xbus)
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
if (xbus->proc_xbus_dir) { if (xbus->proc_xbus_dir) {
if (xbus->proc_xbus_summary) { if (xbus->proc_xbus_summary) {
XBUS_DBG(PROC, xbus, "Removing proc '%s'\n", PROC_XBUS_SUMMARY); XBUS_DBG(PROC, xbus, "Removing proc '%s'\n",
remove_proc_entry(PROC_XBUS_SUMMARY, xbus->proc_xbus_dir); PROC_XBUS_SUMMARY);
remove_proc_entry(PROC_XBUS_SUMMARY,
xbus->proc_xbus_dir);
xbus->proc_xbus_summary = NULL; xbus->proc_xbus_summary = NULL;
} }
#ifdef PROTOCOL_DEBUG #ifdef PROTOCOL_DEBUG
if (xbus->proc_xbus_command) { if (xbus->proc_xbus_command) {
XBUS_DBG(PROC, xbus, "Removing proc '%s'\n", PROC_XBUS_COMMAND); XBUS_DBG(PROC, xbus, "Removing proc '%s'\n",
remove_proc_entry(PROC_XBUS_COMMAND, xbus->proc_xbus_dir); PROC_XBUS_COMMAND);
remove_proc_entry(PROC_XBUS_COMMAND,
xbus->proc_xbus_dir);
xbus->proc_xbus_command = NULL; xbus->proc_xbus_command = NULL;
} }
#endif #endif
@ -1448,7 +1462,8 @@ void xbus_free(xbus_t *xbus)
KZFREE(xbus); KZFREE(xbus);
} }
xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, struct device *transport_device, void *priv) xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size,
struct device *transport_device, void *priv)
{ {
int err; int err;
xbus_t *xbus = NULL; xbus_t *xbus = NULL;
@ -1494,20 +1509,23 @@ xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, struct device *tran
err = -EIO; err = -EIO;
goto nobus; goto nobus;
} }
xbus->proc_xbus_summary = create_proc_read_entry(PROC_XBUS_SUMMARY, xbus->proc_xbus_summary =
0444, xbus->proc_xbus_dir, create_proc_read_entry(PROC_XBUS_SUMMARY, 0444, xbus->proc_xbus_dir,
xbus_read_proc, xbus_read_proc,
(void *)((unsigned long)(xbus->num))); (void *)((unsigned long)(xbus->num)));
if (!xbus->proc_xbus_summary) { if (!xbus->proc_xbus_summary) {
XBUS_ERR(xbus, "Failed to create proc file '%s'\n", PROC_XBUS_SUMMARY); XBUS_ERR(xbus, "Failed to create proc file '%s'\n",
PROC_XBUS_SUMMARY);
err = -EIO; err = -EIO;
goto nobus; goto nobus;
} }
SET_PROC_DIRENTRY_OWNER(xbus->proc_xbus_summary); SET_PROC_DIRENTRY_OWNER(xbus->proc_xbus_summary);
#ifdef PROTOCOL_DEBUG #ifdef PROTOCOL_DEBUG
xbus->proc_xbus_command = create_proc_entry(PROC_XBUS_COMMAND, 0200, xbus->proc_xbus_dir); xbus->proc_xbus_command =
create_proc_entry(PROC_XBUS_COMMAND, 0200, xbus->proc_xbus_dir);
if (!xbus->proc_xbus_command) { if (!xbus->proc_xbus_command) {
XBUS_ERR(xbus, "Failed to create proc file '%s'\n", PROC_XBUS_COMMAND); XBUS_ERR(xbus, "Failed to create proc file '%s'\n",
PROC_XBUS_COMMAND);
err = -EIO; err = -EIO;
goto nobus; goto nobus;
} }
@ -1516,12 +1534,14 @@ xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, struct device *tran
SET_PROC_DIRENTRY_OWNER(xbus->proc_xbus_command); SET_PROC_DIRENTRY_OWNER(xbus->proc_xbus_command);
#endif #endif
#endif #endif
xframe_queue_init(&xbus->command_queue, 10, command_queue_length, "command_queue", xbus); xframe_queue_init(&xbus->command_queue, 10, command_queue_length,
"command_queue", xbus);
xframe_queue_init(&xbus->receive_queue, 10, 50, "receive_queue", xbus); xframe_queue_init(&xbus->receive_queue, 10, 50, "receive_queue", xbus);
xframe_queue_init(&xbus->send_pool, 10, 100, "send_pool", xbus); xframe_queue_init(&xbus->send_pool, 10, 100, "send_pool", xbus);
xframe_queue_init(&xbus->receive_pool, 10, 50, "receive_pool", xbus); xframe_queue_init(&xbus->receive_pool, 10, 50, "receive_pool", xbus);
xframe_queue_init(&xbus->pcm_tospan, 5, 10, "pcm_tospan", xbus); xframe_queue_init(&xbus->pcm_tospan, 5, 10, "pcm_tospan", xbus);
tasklet_init(&xbus->receive_tasklet, receive_tasklet_func, (unsigned long)xbus); tasklet_init(&xbus->receive_tasklet, receive_tasklet_func,
(unsigned long)xbus);
/* /*
* Create worker after /proc/XBUS-?? so the directory exists * Create worker after /proc/XBUS-?? so the directory exists
* before /proc/XBUS-??/waitfor_xpds tries to get created. * before /proc/XBUS-??/waitfor_xpds tries to get created.
@ -1588,11 +1608,11 @@ int waitfor_xpds(xbus_t *xbus, char *buf)
} }
XBUS_DBG(DEVICES, xbus, XBUS_DBG(DEVICES, xbus,
"Waiting for card init of %d XPD's max %d seconds (%p)\n", "Waiting for card init of %d XPD's max %d seconds (%p)\n",
worker->num_units, worker->num_units, INITIALIZATION_TIMEOUT / HZ,
INITIALIZATION_TIMEOUT/HZ,
&worker->wait_for_xpd_initialization); &worker->wait_for_xpd_initialization);
ret = wait_event_interruptible_timeout( ret =
worker->wait_for_xpd_initialization, wait_event_interruptible_timeout(worker->
wait_for_xpd_initialization,
xpds_done(xbus), xpds_done(xbus),
INITIALIZATION_TIMEOUT); INITIALIZATION_TIMEOUT);
if (ret == 0) { if (ret == 0) {
@ -1607,13 +1627,13 @@ int waitfor_xpds(xbus_t *xbus, char *buf)
XBUS_DBG(DEVICES, xbus, XBUS_DBG(DEVICES, xbus,
"Finished initialization of %d XPD's in %d seconds.\n", "Finished initialization of %d XPD's in %d seconds.\n",
worker->num_units_initialized, worker->num_units_initialized,
(INITIALIZATION_TIMEOUT - ret)/HZ); (INITIALIZATION_TIMEOUT - ret) / HZ);
if (XBUS_IS(xbus, FAIL)) { if (XBUS_IS(xbus, FAIL)) {
len += sprintf(buf, "FAILED: %s\n", xbus->busname); len += sprintf(buf, "FAILED: %s\n", xbus->busname);
} else { } else {
spin_lock_irqsave(&xbus->lock, flags); spin_lock_irqsave(&xbus->lock, flags);
len += sprintf(buf, "XPDS_READY: %s: %d/%d\n", len +=
xbus->busname, sprintf(buf, "XPDS_READY: %s: %d/%d\n", xbus->busname,
worker->num_units_initialized, worker->num_units); worker->num_units_initialized, worker->num_units);
spin_unlock_irqrestore(&xbus->lock, flags); spin_unlock_irqrestore(&xbus->lock, flags);
} }
@ -1628,21 +1648,18 @@ static int xbus_fill_proc_queue(char *p, struct xframe_queue *q)
{ {
int len; int len;
len = sprintf(p, len =
sprintf(p,
"%-15s: counts %3d, %3d, %3d worst %3d, overflows %3d worst_lag %02ld.%ld ms\n", "%-15s: counts %3d, %3d, %3d worst %3d, overflows %3d worst_lag %02ld.%ld ms\n",
q->name, q->name, q->steady_state_count, q->count, q->max_count,
q->steady_state_count, q->worst_count, q->overflows, q->worst_lag_usec / 1000,
q->count,
q->max_count,
q->worst_count,
q->overflows,
q->worst_lag_usec / 1000,
q->worst_lag_usec % 1000); q->worst_lag_usec % 1000);
xframe_queue_clearstats(q); xframe_queue_clearstats(q);
return len; return len;
} }
static int xbus_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) static int xbus_read_proc(char *page, char **start, off_t off, int count,
int *eof, void *data)
{ {
xbus_t *xbus; xbus_t *xbus;
unsigned long flags; unsigned long flags;
@ -1654,12 +1671,10 @@ static int xbus_read_proc(char *page, char **start, off_t off, int count, int *e
goto out; goto out;
spin_lock_irqsave(&xbus->lock, flags); spin_lock_irqsave(&xbus->lock, flags);
len += sprintf(page + len, "%s: CONNECTOR=%s LABEL=[%s] STATUS=%s\n", len +=
xbus->busname, sprintf(page + len, "%s: CONNECTOR=%s LABEL=[%s] STATUS=%s\n",
xbus->connector, xbus->busname, xbus->connector, xbus->label,
xbus->label, (XBUS_FLAGS(xbus, CONNECTED)) ? "connected" : "missing");
(XBUS_FLAGS(xbus, CONNECTED)) ? "connected" : "missing"
);
len += xbus_fill_proc_queue(page + len, &xbus->send_pool); len += xbus_fill_proc_queue(page + len, &xbus->send_pool);
len += xbus_fill_proc_queue(page + len, &xbus->receive_pool); len += xbus_fill_proc_queue(page + len, &xbus->receive_pool);
len += xbus_fill_proc_queue(page + len, &xbus->command_queue); len += xbus_fill_proc_queue(page + len, &xbus->command_queue);
@ -1671,38 +1686,47 @@ static int xbus_read_proc(char *page, char **start, off_t off, int count, int *e
len += sprintf(page + len, "%5d ", xbus->cpu_rcv_intr[i]); len += sprintf(page + len, "%5d ", xbus->cpu_rcv_intr[i]);
len += sprintf(page + len, "\ncpu_rcv_tasklet: "); len += sprintf(page + len, "\ncpu_rcv_tasklet: ");
for_each_online_cpu(i) for_each_online_cpu(i)
len += sprintf(page + len, "%5d ", xbus->cpu_rcv_tasklet[i]); len +=
sprintf(page + len, "%5d ", xbus->cpu_rcv_tasklet[i]);
len += sprintf(page + len, "\n"); len += sprintf(page + len, "\n");
} }
len += sprintf(page + len, "self_ticking: %d (last_tick at %ld)\n", len +=
sprintf(page + len, "self_ticking: %d (last_tick at %ld)\n",
xbus->self_ticking, xbus->ticker.last_sample.tv.tv_sec); 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, "command_tick: %d\n",
xbus->command_tick_counter);
len += sprintf(page + len, "usec_nosend: %d\n", xbus->usec_nosend); len += sprintf(page + len, "usec_nosend: %d\n", xbus->usec_nosend);
len += sprintf(page + len, "xbus: pcm_rx_counter = %d, frag = %d\n", len +=
sprintf(page + len, "xbus: pcm_rx_counter = %d, frag = %d\n",
atomic_read(&xbus->pcm_rx_counter), xbus->xbus_frag_count); atomic_read(&xbus->pcm_rx_counter), xbus->xbus_frag_count);
len += sprintf(page + len, "max_rx_process = %2ld.%ld ms\n", len +=
xbus->max_rx_process / 1000, sprintf(page + len, "max_rx_process = %2ld.%ld ms\n",
xbus->max_rx_process % 1000); xbus->max_rx_process / 1000, xbus->max_rx_process % 1000);
xbus->max_rx_process = 0; xbus->max_rx_process = 0;
len += sprintf(page + len, "\nTRANSPORT: max_send_size=%d refcount=%d\n", len +=
sprintf(page + len, "\nTRANSPORT: max_send_size=%d refcount=%d\n",
MAX_SEND_SIZE(xbus), MAX_SEND_SIZE(xbus),
atomic_read(&xbus->transport.transport_refcount) atomic_read(&xbus->transport.transport_refcount)
); );
len += sprintf(page + len, "PCM Metrices:\n"); len += sprintf(page + len, "PCM Metrices:\n");
len += sprintf(page + len, "\tPCM TX: min=%ld max=%ld\n", len +=
sprintf(page + len, "\tPCM TX: min=%ld max=%ld\n",
xbus->min_tx_sync, xbus->max_tx_sync); xbus->min_tx_sync, xbus->max_tx_sync);
len += sprintf(page + len, "\tPCM RX: min=%ld max=%ld\n", len +=
sprintf(page + len, "\tPCM RX: min=%ld max=%ld\n",
xbus->min_rx_sync, xbus->max_rx_sync); xbus->min_rx_sync, xbus->max_rx_sync);
len += sprintf(page + len, "COUNTERS:\n"); len += sprintf(page + len, "COUNTERS:\n");
for (i = 0; i < XBUS_COUNTER_MAX; i++) { for (i = 0; i < XBUS_COUNTER_MAX; i++) {
len += sprintf(page + len, "\t%-15s = %d\n", len +=
xbus_counters[i].name, xbus->counters[i]); sprintf(page + len, "\t%-15s = %d\n", xbus_counters[i].name,
xbus->counters[i]);
} }
len += sprintf(page + len, "<-- len=%d\n", len); len += sprintf(page + len, "<-- len=%d\n", len);
spin_unlock_irqrestore(&xbus->lock, flags); spin_unlock_irqrestore(&xbus->lock, flags);
put_xbus(__func__, xbus); /* from xbus_read_proc() */ put_xbus(__func__, xbus); /* from xbus_read_proc() */
out: out:
if (len <= off+count) if (len <= off + count)
*eof = 1; *eof = 1;
*start = page + off; *start = page + off;
len -= off; len -= off;
@ -1715,7 +1739,8 @@ out:
} }
#ifdef PROTOCOL_DEBUG #ifdef PROTOCOL_DEBUG
static int proc_xbus_command_write(struct file *file, const char __user *buffer, unsigned long count, void *data) static int proc_xbus_command_write(struct file *file, const char __user *buffer,
unsigned long count, void *data)
{ {
char *buf; char *buf;
xbus_t *xbus = data; xbus_t *xbus = data;
@ -1728,7 +1753,8 @@ static int proc_xbus_command_write(struct file *file, const char __user *buffer,
const size_t max_text = max_len * 3 + 10; const size_t max_text = max_len * 3 + 10;
if (count > max_text) { if (count > max_text) {
XBUS_ERR(xbus, "%s: line too long (%ld > %zd)\n", __func__, count, max_len); XBUS_ERR(xbus, "%s: line too long (%ld > %zd)\n", __func__,
count, max_len);
return -EFBIG; return -EFBIG;
} }
/* 3 bytes per hex-digit and space */ /* 3 bytes per hex-digit and space */
@ -1756,7 +1782,8 @@ static int proc_xbus_command_write(struct file *file, const char __user *buffer,
if (!(*p)) if (!(*p))
break; break;
if (!isxdigit(*p)) { if (!isxdigit(*p)) {
XBUS_ERR(xbus, "%s: bad hex value ASCII='0x%X' at position %ld\n", XBUS_ERR(xbus,
"%s: bad hex value ASCII='0x%X' at position %ld\n",
__func__, *p, (long)(p - buf)); __func__, *p, (long)(p - buf));
count = -EINVAL; count = -EINVAL;
goto out; goto out;
@ -1767,13 +1794,15 @@ static int proc_xbus_command_write(struct file *file, const char __user *buffer,
if (isxdigit(*p)) if (isxdigit(*p))
hexdigit[1] = *p++; hexdigit[1] = *p++;
if (sscanf(hexdigit, "%2X", &val) != 1) { if (sscanf(hexdigit, "%2X", &val) != 1) {
XBUS_ERR(xbus, "%s: bad hex value '%s' at position %ld\n", XBUS_ERR(xbus,
"%s: bad hex value '%s' at position %ld\n",
__func__, hexdigit, (long)(p - buf)); __func__, hexdigit, (long)(p - buf));
count = -EINVAL; count = -EINVAL;
goto out; goto out;
} }
*q++ = val; *q++ = val;
XBUS_DBG(GENERAL, xbus, "%3zd> '%s' val=%d\n", q - pack_start, hexdigit, val); XBUS_DBG(GENERAL, xbus, "%3zd> '%s' val=%d\n", q - pack_start,
hexdigit, val);
} }
len = q - pack_start; len = q - pack_start;
xframe = ALLOC_SEND_XFRAME(xbus); xframe = ALLOC_SEND_XFRAME(xbus);
@ -1793,8 +1822,8 @@ out:
} }
#endif #endif
static int read_proc_xbuses(char *page, char **start, off_t off, int count,
static int read_proc_xbuses(char *page, char **start, off_t off, int count, int *eof, void *data) int *eof, void *data)
{ {
int len = 0; int len = 0;
int i; int i;
@ -1803,19 +1832,19 @@ static int read_proc_xbuses(char *page, char **start, off_t off, int count, int
xbus_t *xbus = get_xbus(__func__, i); xbus_t *xbus = get_xbus(__func__, i);
if (xbus) { if (xbus) {
len += sprintf(page + len, "%s: CONNECTOR=%s LABEL=[%s] STATUS=%s\n", len +=
xbus->busname, sprintf(page + len,
xbus->connector, "%s: CONNECTOR=%s LABEL=[%s] STATUS=%s\n",
xbus->label, xbus->busname, xbus->connector, xbus->label,
(XBUS_FLAGS(xbus, CONNECTED)) ? "connected" : "missing" (XBUS_FLAGS(xbus, CONNECTED)) ? "connected"
); : "missing");
put_xbus(__func__, xbus); put_xbus(__func__, xbus);
} }
} }
#if 0 #if 0
len += sprintf(page + len, "<-- len=%d\n", len); len += sprintf(page + len, "<-- len=%d\n", len);
#endif #endif
if (len <= off+count) if (len <= off + count)
*eof = 1; *eof = 1;
*start = page + off; *start = page + off;
len -= off; len -= off;
@ -1828,7 +1857,9 @@ static int read_proc_xbuses(char *page, char **start, off_t off, int count, int
} }
#endif #endif
static void transport_init(xbus_t *xbus, struct xbus_ops *ops, ushort max_send_size, struct device *transport_device, void *priv) static void transport_init(xbus_t *xbus, struct xbus_ops *ops,
ushort max_send_size,
struct device *transport_device, void *priv)
{ {
BUG_ON(!xbus); BUG_ON(!xbus);
BUG_ON(!ops); BUG_ON(!ops);
@ -1855,10 +1886,13 @@ static void transport_destroy(xbus_t *xbus)
BUG_ON(!xbus); BUG_ON(!xbus);
XBUS_DBG(DEVICES, xbus, "Waiting... (transport_refcount=%d)\n", XBUS_DBG(DEVICES, xbus, "Waiting... (transport_refcount=%d)\n",
atomic_read(&xbus->transport.transport_refcount)); atomic_read(&xbus->transport.transport_refcount));
ret = wait_event_interruptible(xbus->transport.transport_unused, ret =
atomic_read(&xbus->transport.transport_refcount) == 0); wait_event_interruptible(xbus->transport.transport_unused,
atomic_read(&xbus->transport.
transport_refcount) == 0);
if (ret) if (ret)
XBUS_ERR(xbus, "Waiting for transport_refcount interrupted!!!\n"); XBUS_ERR(xbus,
"Waiting for transport_refcount interrupted!!!\n");
xbus->transport.ops = NULL; xbus->transport.ops = NULL;
xbus->transport.priv = NULL; xbus->transport.priv = NULL;
} }
@ -1909,7 +1943,9 @@ int __init xbus_core_init(void)
INFO("FEATURE: with PROTOCOL_DEBUG\n"); INFO("FEATURE: with PROTOCOL_DEBUG\n");
#endif #endif
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
proc_xbuses = create_proc_read_entry(PROC_XBUSES, 0444, xpp_proc_toplevel, read_proc_xbuses, NULL); proc_xbuses =
create_proc_read_entry(PROC_XBUSES, 0444, xpp_proc_toplevel,
read_proc_xbuses, NULL);
if (!proc_xbuses) { if (!proc_xbuses) {
ERR("Failed to create proc file %s\n", PROC_XBUSES); ERR("Failed to create proc file %s\n", PROC_XBUSES);
ret = -EFAULT; ret = -EFAULT;
@ -1925,7 +1961,6 @@ err:
return ret; return ret;
} }
void xbus_core_shutdown(void) void xbus_core_shutdown(void)
{ {
xbus_core_cleanup(); xbus_core_cleanup();

View File

@ -39,10 +39,10 @@ struct xbus_workqueue;
#ifdef __KERNEL__ #ifdef __KERNEL__
struct xbus_ops { struct xbus_ops {
int (*xframe_send_pcm)(xbus_t *xbus, xframe_t *xframe); int (*xframe_send_pcm) (xbus_t *xbus, xframe_t *xframe);
int (*xframe_send_cmd)(xbus_t *xbus, xframe_t *xframe); int (*xframe_send_cmd) (xbus_t *xbus, xframe_t *xframe);
xframe_t *(*alloc_xframe)(xbus_t *xbus, gfp_t gfp_flags); xframe_t *(*alloc_xframe) (xbus_t *xbus, gfp_t gfp_flags);
void (*free_xframe)(xbus_t *xbus, xframe_t *xframe); void (*free_xframe) (xbus_t *xbus, xframe_t *xframe);
}; };
/* /*
@ -69,17 +69,9 @@ enum {
static struct xbus_counters { static struct xbus_counters {
char *name; char *name;
} xbus_counters[] = { } xbus_counters[] = {
C_(UNITS), C_(UNITS), C_(TX_XFRAME_PCM), C_(RX_XFRAME_PCM), C_(TX_PACK_PCM),
C_(TX_XFRAME_PCM), C_(RX_PACK_PCM), C_(TX_BYTES), C_(RX_BYTES),
C_(RX_XFRAME_PCM), C_(TX_PCM_FRAG), C_(RX_CMD), C_(TX_CMD),};
C_(TX_PACK_PCM),
C_(RX_PACK_PCM),
C_(TX_BYTES),
C_(RX_BYTES),
C_(TX_PCM_FRAG),
C_(RX_CMD),
C_(TX_CMD),
};
#undef C_ #undef C_
@ -163,10 +155,10 @@ int refcount_xbus(xbus_t *xbus);
#define ECHO_TIMESLOTS 128 #define ECHO_TIMESLOTS 128
struct echoops { struct echoops {
int (*ec_set)(xpd_t *xpd, int pos, bool on); int (*ec_set) (xpd_t *xpd, int pos, bool on);
int (*ec_get)(xpd_t *xpd, int pos); int (*ec_get) (xpd_t *xpd, int pos);
int (*ec_update)(xbus_t *xbus); int (*ec_update) (xbus_t *xbus);
void (*ec_dump)(xbus_t *xbus); void (*ec_dump) (xbus_t *xbus);
}; };
struct xbus_echo_state { struct xbus_echo_state {
@ -294,7 +286,8 @@ struct xframe {
void *priv; void *priv;
}; };
void xframe_init(xbus_t *xbus, xframe_t *xframe, void *buf, size_t maxsize, void *priv); void xframe_init(xbus_t *xbus, xframe_t *xframe, void *buf, size_t maxsize,
void *priv);
#define XFRAME_LEN(frame) atomic_read(&(frame)->frame_len) #define XFRAME_LEN(frame) atomic_read(&(frame)->frame_len)
@ -302,7 +295,8 @@ int xbus_core_init(void); /* Initializer */
void xbus_core_shutdown(void); /* Terminator */ void xbus_core_shutdown(void); /* Terminator */
/* Frame handling */ /* Frame handling */
void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe, int debug); void dump_xframe(const char msg[], const xbus_t *xbus, const xframe_t *xframe,
int debug);
int send_cmd_frame(xbus_t *xbus, xframe_t *xframe); int send_cmd_frame(xbus_t *xbus, xframe_t *xframe);
/* /*
@ -325,7 +319,8 @@ xpd_t *xpd_byaddr(const xbus_t *xbus, uint unit, uint subunit);
int xbus_check_unique(xbus_t *xbus); int xbus_check_unique(xbus_t *xbus);
bool xbus_setstate(xbus_t *xbus, enum xbus_state newstate); bool xbus_setstate(xbus_t *xbus, enum xbus_state newstate);
bool xbus_setflags(xbus_t *xbus, int flagbit, bool on); bool xbus_setflags(xbus_t *xbus, int flagbit, bool on);
xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size, struct device *transport_device, void *priv); xbus_t *xbus_new(struct xbus_ops *ops, ushort max_send_size,
struct device *transport_device, void *priv);
void xbus_free(xbus_t *xbus); void xbus_free(xbus_t *xbus);
int xbus_connect(xbus_t *xbus); int xbus_connect(xbus_t *xbus);
int xbus_activate(xbus_t *xbus); int xbus_activate(xbus_t *xbus);
@ -370,4 +365,3 @@ enum kobject_action {
void astribank_uevent_send(xbus_t *xbus, enum kobject_action act); void astribank_uevent_send(xbus_t *xbus, enum kobject_action act);
#endif /* XBUS_CORE_H */ #endif /* XBUS_CORE_H */

View File

@ -22,7 +22,7 @@
#include <linux/version.h> #include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
# warning "This module is tested only with 2.6 kernels" #warning "This module is tested only with 2.6 kernels"
#endif #endif
#include <linux/kernel.h> #include <linux/kernel.h>
@ -37,15 +37,18 @@ static const char rcsid[] = "$Id$";
extern int debug; extern int debug;
#ifdef OPTIMIZE_CHANMUTE #ifdef OPTIMIZE_CHANMUTE
static DEF_PARM_BOOL(optimize_chanmute, 1, 0644, "Optimize by muting inactive channels"); static DEF_PARM_BOOL(optimize_chanmute, 1, 0644,
"Optimize by muting inactive channels");
#endif #endif
static DEF_PARM(int, disable_pcm, 0, 0644, "Disable all PCM transmissions"); static DEF_PARM(int, disable_pcm, 0, 0644, "Disable all PCM transmissions");
#ifdef DEBUG_PCMTX #ifdef DEBUG_PCMTX
DEF_PARM(int, pcmtx, -1, 0644, "Forced PCM value to transmit (negative to disable)"); DEF_PARM(int, pcmtx, -1, 0644,
"Forced PCM value to transmit (negative to disable)");
DEF_PARM(int, pcmtx_chan, 0, 0644, "channel to force PCM value"); DEF_PARM(int, pcmtx_chan, 0, 0644, "channel to force PCM value");
#endif #endif
static DEF_PARM_BOOL(disable_pll_sync, 0, 0644, "Disable automatic adjustment of AB clocks"); static DEF_PARM_BOOL(disable_pll_sync, 0, 0644,
"Disable automatic adjustment of AB clocks");
static xbus_t *syncer; /* current syncer */ static xbus_t *syncer; /* current syncer */
static atomic_t xpp_tick_counter = ATOMIC_INIT(0); static atomic_t xpp_tick_counter = ATOMIC_INIT(0);
@ -118,8 +121,8 @@ static int xpp_ticker_step(struct xpp_ticker *ticker, const struct timeval *t)
spin_lock_irqsave(&ticker->lock, flags); spin_lock_irqsave(&ticker->lock, flags);
ticker->last_sample.tv = *t; ticker->last_sample.tv = *t;
if ((ticker->count % ticker->cycle) == ticker->cycle - 1) { /* rate adjust */ if ((ticker->count % ticker->cycle) == ticker->cycle - 1) { /* rate adjust */
usec = (long)usec_diff( usec =
&ticker->last_sample.tv, (long)usec_diff(&ticker->last_sample.tv,
&ticker->first_sample.tv); &ticker->first_sample.tv);
ticker->first_sample = ticker->last_sample; ticker->first_sample = ticker->last_sample;
ticker->tick_period = usec / ticker->cycle; ticker->tick_period = usec / ticker->cycle;
@ -194,7 +197,8 @@ static void xpp_drift_step(xbus_t *xbus, const struct timeval *tv)
* Do we need to be synchronized and is there an established reference * Do we need to be synchronized and is there an established reference
* ticker (another Astribank or another DAHDI device) already? * ticker (another Astribank or another DAHDI device) already?
*/ */
if (ref_ticker && ref_ticker != &xbus->ticker && syncer && xbus->sync_mode == SYNC_MODE_PLL) { if (ref_ticker && ref_ticker != &xbus->ticker && syncer
&& xbus->sync_mode == SYNC_MODE_PLL) {
int new_delta_tick = ticker->count - ref_ticker->count; int new_delta_tick = ticker->count - ref_ticker->count;
int lost_ticks = new_delta_tick - di->delta_tick; int lost_ticks = new_delta_tick - di->delta_tick;
long usec_delta; long usec_delta;
@ -216,7 +220,7 @@ static void xpp_drift_step(xbus_t *xbus, const struct timeval *tv)
*/ */
XBUS_DBG(SYNC, xbus, "Lost %d tick%s\n", XBUS_DBG(SYNC, xbus, "Lost %d tick%s\n",
lost_ticks, lost_ticks,
(abs(lost_ticks) > 1) ? "s": ""); (abs(lost_ticks) > 1) ? "s" : "");
} }
if (abs(lost_ticks) > 100) { if (abs(lost_ticks) > 100) {
xbus_drift_clear(xbus); xbus_drift_clear(xbus);
@ -224,22 +228,26 @@ static void xpp_drift_step(xbus_t *xbus, const struct timeval *tv)
} }
} else { } else {
/* Sample a delta */ /* Sample a delta */
usec_delta = (long)usec_diff( usec_delta =
&ticker->last_sample.tv, (long)usec_diff(&ticker->last_sample.tv,
&ref_ticker->last_sample.tv); &ref_ticker->last_sample.tv);
sample_tick(xbus, usec_delta); sample_tick(xbus, usec_delta);
if ((ticker->count % SYNC_CYCLE) > (SYNC_CYCLE - SYNC_CYCLE_SAMPLE)) if ((ticker->count % SYNC_CYCLE) >
(SYNC_CYCLE - SYNC_CYCLE_SAMPLE))
di->delta_sum += usec_delta; di->delta_sum += usec_delta;
if ((ticker->count % SYNC_CYCLE) == 0) { if ((ticker->count % SYNC_CYCLE) == 0) {
/* /*
* Full sampling cycle passed. Let's calculate * Full sampling cycle passed. Let's calculate
*/ */
int offset = di->delta_sum / SYNC_CYCLE_SAMPLE - SYNC_CENTER; int offset =
di->delta_sum / SYNC_CYCLE_SAMPLE -
SYNC_CENTER;
int offset_prev = di->offset_prev; int offset_prev = di->offset_prev;
int speed = xbus->sync_adjustment; int speed = xbus->sync_adjustment;
int fix = 0; int fix = 0;
int best_speed = (di->max_speed + di->min_speed) >> 1; int best_speed =
(di->max_speed + di->min_speed) >> 1;
if (offset > 0 && offset < SYNC_DELTA) { if (offset > 0 && offset < SYNC_DELTA) {
speed = best_speed - 1; speed = best_speed - 1;
@ -268,16 +276,22 @@ static void xpp_drift_step(xbus_t *xbus, const struct timeval *tv)
if (offset < di->offset_min) if (offset < di->offset_min)
di->offset_min = offset; di->offset_min = offset;
XBUS_DBG(SYNC, xbus, "offset: %d, min_speed=%d, max_speed=%d, usec_delta(last)=%ld\n", XBUS_DBG(SYNC, xbus,
offset_prev, di->min_speed, di->max_speed, usec_delta); "offset: %d, min_speed=%d, max_speed=%d, usec_delta(last)=%ld\n",
XBUS_DBG(SYNC, xbus, "ADJ: speed=%d (best_speed=%d) fix=%d\n", offset_prev, di->min_speed,
di->max_speed, usec_delta);
XBUS_DBG(SYNC, xbus,
"ADJ: speed=%d (best_speed=%d) fix=%d\n",
speed, best_speed, fix); speed, best_speed, fix);
xbus->sync_adjustment_offset = speed; xbus->sync_adjustment_offset = speed;
if (xbus != syncer && xbus->sync_adjustment != speed) if (xbus != syncer
&& xbus->sync_adjustment != speed)
send_drift(xbus, speed); send_drift(xbus, speed);
di->sync_inaccuracy = abs(offset) + abs(di->offset_range) / 2; di->sync_inaccuracy =
abs(offset) + abs(di->offset_range) / 2;
if (ticker->count >= SYNC_CYCLE * SYNC_CONVERGE) { if (ticker->count >= SYNC_CYCLE * SYNC_CONVERGE) {
di->offset_range = di->offset_max - di->offset_min; di->offset_range =
di->offset_max - di->offset_min;
di->offset_min = INT_MAX; di->offset_min = INT_MAX;
di->offset_max = -INT_MAX; di->offset_max = -INT_MAX;
if (di->max_speed > best_speed) if (di->max_speed > best_speed)
@ -328,7 +342,7 @@ static void xpp_set_syncer(xbus_t *xbus, bool on)
ref_ticker = NULL; ref_ticker = NULL;
} else } else
XBUS_DBG(SYNC, xbus, "ignore %s (current syncer: %s)\n", XBUS_DBG(SYNC, xbus, "ignore %s (current syncer: %s)\n",
(on)?"ON":"OFF", (on) ? "ON" : "OFF",
(syncer) ? syncer->busname : "NO-SYNC"); (syncer) ? syncer->busname : "NO-SYNC");
} }
@ -346,7 +360,7 @@ static void xbus_command_timer(unsigned long param)
void xbus_set_command_timer(xbus_t *xbus, bool on) void xbus_set_command_timer(xbus_t *xbus, bool on)
{ {
XBUS_DBG(SYNC, xbus, "%s\n", (on)?"ON":"OFF"); XBUS_DBG(SYNC, xbus, "%s\n", (on) ? "ON" : "OFF");
if (on) { if (on) {
if (!timer_pending(&xbus->command_timer)) { if (!timer_pending(&xbus->command_timer)) {
XBUS_DBG(SYNC, xbus, "add_timer\n"); XBUS_DBG(SYNC, xbus, "add_timer\n");
@ -359,7 +373,7 @@ void xbus_set_command_timer(xbus_t *xbus, bool on)
XBUS_DBG(SYNC, xbus, "del_timer\n"); XBUS_DBG(SYNC, xbus, "del_timer\n");
del_timer(&xbus->command_timer); del_timer(&xbus->command_timer);
} }
xbus->self_ticking = ! on; xbus->self_ticking = !on;
} }
/* /*
@ -379,7 +393,8 @@ void got_new_syncer(xbus_t *xbus, enum sync_mode mode, int drift)
goto out; goto out;
} }
XBUS_DBG(SYNC, xbus, "Mode %s (%d), drift=%d (pcm_rx_counter=%d)\n", XBUS_DBG(SYNC, xbus, "Mode %s (%d), drift=%d (pcm_rx_counter=%d)\n",
sync_mode_name(mode), mode, drift, atomic_read(&xbus->pcm_rx_counter)); sync_mode_name(mode), mode, drift,
atomic_read(&xbus->pcm_rx_counter));
switch (mode) { switch (mode) {
case SYNC_MODE_AB: case SYNC_MODE_AB:
xbus->sync_mode = mode; xbus->sync_mode = mode;
@ -456,7 +471,8 @@ static void reset_sync_counters(void)
"Dropped packet. Is shutting down.\n"); "Dropped packet. Is shutting down.\n");
} else { } else {
/* Reset sync LEDs once in a while */ /* Reset sync LEDs once in a while */
CALL_PROTO(GLOBAL, RESET_SYNC_COUNTERS, xbus, NULL); CALL_PROTO(GLOBAL, RESET_SYNC_COUNTERS, xbus,
NULL);
} }
} }
put_xbus(__func__, xbus); put_xbus(__func__, xbus);
@ -474,11 +490,13 @@ static void send_drift(xbus_t *xbus, int drift)
msg = "up"; msg = "up";
else else
msg = "down"; msg = "down";
XBUS_DBG(SYNC, xbus, "%sDRIFT adjust %s (%d) (last update %ld seconds ago)\n", XBUS_DBG(SYNC, xbus,
(disable_pll_sync) ? "Fake " : "", "%sDRIFT adjust %s (%d) (last update %ld seconds ago)\n",
msg, drift, now.tv_sec - xbus->pll_updated_at); (disable_pll_sync) ? "Fake " : "", msg, drift,
now.tv_sec - xbus->pll_updated_at);
if (!disable_pll_sync) if (!disable_pll_sync)
CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, SYNC_MODE_PLL, drift); CALL_PROTO(GLOBAL, SYNC_SOURCE, xbus, NULL, SYNC_MODE_PLL,
drift);
xbus->pll_updated_at = now.tv_sec; xbus->pll_updated_at = now.tv_sec;
} }
@ -512,7 +530,8 @@ void dahdi_sync_tick(struct dahdi_span *span, int is_master)
static int rate_limit; static int rate_limit;
if ((rate_limit++ % 10003) == 0) if ((rate_limit++ % 10003) == 0)
XPD_NOTICE(xpd, "Is a DAHDI sync master: ignore sync from DAHDI\n"); XPD_NOTICE(xpd,
"Is a DAHDI sync master: ignore sync from DAHDI\n");
goto noop; goto noop;
} }
/* Now we know for sure someone else is dahdi sync master */ /* Now we know for sure someone else is dahdi sync master */
@ -556,8 +575,7 @@ static void update_sync_master(xbus_t *new_syncer, bool force_dahdi)
WARN_ON(new_syncer && force_dahdi); /* Ambigous */ WARN_ON(new_syncer && force_dahdi); /* Ambigous */
force_dahdi_sync = force_dahdi; force_dahdi_sync = force_dahdi;
msg = (force_dahdi_sync) ? "DAHDI" : "NO-SYNC"; msg = (force_dahdi_sync) ? "DAHDI" : "NO-SYNC";
DBG(SYNC, "%s => %s\n", DBG(SYNC, "%s => %s\n", (syncer) ? syncer->busname : msg,
(syncer) ? syncer->busname : msg,
(new_syncer) ? new_syncer->busname : msg); (new_syncer) ? new_syncer->busname : msg);
/* /*
* This global locking protects: * This global locking protects:
@ -598,7 +616,8 @@ static void update_sync_master(xbus_t *new_syncer, bool force_dahdi)
xbus_request_sync(xbus, xbus_request_sync(xbus,
xbus->sync_mode_default); xbus->sync_mode_default);
else else
XBUS_DBG(SYNC, xbus, "Not self_ticking yet. Ignore\n"); XBUS_DBG(SYNC, xbus,
"Not self_ticking yet. Ignore\n");
} }
put_xbus(__func__, xbus); put_xbus(__func__, xbus);
} }
@ -628,9 +647,12 @@ void elect_syncer(const char *msg)
xpd_t *xpd = xpd_of(xbus, j); xpd_t *xpd = xpd_of(xbus, j);
int prio; int prio;
if (!xpd || !xpd->card_present || !IS_PHONEDEV(xpd)) if (!xpd || !xpd->card_present
|| !IS_PHONEDEV(xpd))
continue; continue;
prio = CALL_PHONE_METHOD(card_timing_priority, xpd); prio =
CALL_PHONE_METHOD(card_timing_priority,
xpd);
if (prio < 0) { if (prio < 0) {
DBG(SYNC, "%s/%s: skip sync\n", DBG(SYNC, "%s/%s: skip sync\n",
xbus->busname, xpd->xpdname); xbus->busname, xpd->xpdname);
@ -646,7 +668,8 @@ void elect_syncer(const char *msg)
} }
if (best_xpd) { if (best_xpd) {
the_xbus = best_xpd->xbus; the_xbus = best_xpd->xbus;
XPD_DBG(SYNC, best_xpd, "%s: elected with priority %d\n", msg, timing_priority); XPD_DBG(SYNC, best_xpd, "%s: elected with priority %d\n", msg,
timing_priority);
} else if (the_xbus) { } else if (the_xbus) {
XBUS_DBG(SYNC, the_xbus, "%s: elected\n", msg); XBUS_DBG(SYNC, the_xbus, "%s: elected\n", msg);
} else { } else {
@ -705,15 +728,15 @@ void generic_card_pcm_recompute(xpd_t *xpd, xpp_line_t pcm_mask)
line_count = 1; line_count = 1;
} }
pcm_len = (line_count) pcm_len = (line_count)
? RPACKET_HEADERSIZE + sizeof(xpp_line_t) + line_count * DAHDI_CHUNKSIZE ? RPACKET_HEADERSIZE + sizeof(xpp_line_t) +
: 0L; line_count * DAHDI_CHUNKSIZE : 0L;
update_wanted_pcm_mask(xpd, pcm_mask, pcm_len); update_wanted_pcm_mask(xpd, pcm_mask, pcm_len);
spin_unlock_irqrestore(&PHONEDEV(xpd).lock_recompute_pcm, flags); spin_unlock_irqrestore(&PHONEDEV(xpd).lock_recompute_pcm, flags);
} }
void fill_beep(u_char *buf, int num, int duration) void fill_beep(u_char *buf, int num, int duration)
{ {
bool alternate = (duration) ? (jiffies/(duration*1000)) & 0x1 : 0; bool alternate = (duration) ? (jiffies / (duration * 1000)) & 0x1 : 0;
int which; int which;
u_char *snd; u_char *snd;
@ -741,16 +764,19 @@ static void do_ec(xpd_t *xpd)
{ {
int i; int i;
for (i = 0;i < PHONEDEV(xpd).span.channels; i++) { for (i = 0; i < PHONEDEV(xpd).span.channels; i++) {
struct dahdi_chan *chan = XPD_CHAN(xpd, i); struct dahdi_chan *chan = XPD_CHAN(xpd, i);
if (unlikely(IS_SET(PHONEDEV(xpd).digital_signalling, i))) /* Don't echo cancel BRI D-chans */ if (unlikely(IS_SET(PHONEDEV(xpd).digital_signalling, i))) /* Don't echo cancel BRI D-chans */
continue; continue;
if (!IS_SET(PHONEDEV(xpd).wanted_pcm_mask, i)) /* No ec for unwanted PCM */ if (!IS_SET(PHONEDEV(xpd).wanted_pcm_mask, i)) /* No ec for unwanted PCM */
continue; continue;
dahdi_ec_chunk(chan, chan->readchunk, PHONEDEV(xpd).ec_chunk2[i]); dahdi_ec_chunk(chan, chan->readchunk,
memcpy(PHONEDEV(xpd).ec_chunk2[i], PHONEDEV(xpd).ec_chunk1[i], DAHDI_CHUNKSIZE); PHONEDEV(xpd).ec_chunk2[i]);
memcpy(PHONEDEV(xpd).ec_chunk1[i], chan->writechunk, DAHDI_CHUNKSIZE); memcpy(PHONEDEV(xpd).ec_chunk2[i], PHONEDEV(xpd).ec_chunk1[i],
DAHDI_CHUNKSIZE);
memcpy(PHONEDEV(xpd).ec_chunk1[i], chan->writechunk,
DAHDI_CHUNKSIZE);
} }
} }
@ -762,18 +788,18 @@ static void do_ec(xpd_t *xpd)
set the DAHDI_FLAG_RBS in this case. */ set the DAHDI_FLAG_RBS in this case. */
/* Opt: If the span uses A/B bits, set them here */ /* Opt: If the span uses A/B bits, set them here */
int (*rbsbits)(struct dahdi_chan *chan, int bits); int (*rbsbits) (struct dahdi_chan * chan, int bits);
/* Option 2: If you don't know about sig bits, but do have their /* Option 2: If you don't know about sig bits, but do have their
equivalents (i.e. you can disconnect battery, detect off hook, equivalents (i.e. you can disconnect battery, detect off hook,
generate ring, etc directly) then you can just specify a generate ring, etc directly) then you can just specify a
sethook function, and we'll call you with appropriate hook states sethook function, and we'll call you with appropriate hook states
to set. Still set the DAHDI_FLAG_RBS in this case as well */ to set. Still set the DAHDI_FLAG_RBS in this case as well */
int (*hooksig)(struct dahdi_chan *chan, enum dahdi_txsig hookstate); int (*hooksig) (struct dahdi_chan * chan, enum dahdi_txsig hookstate);
/* Option 3: If you can't use sig bits, you can write a function /* Option 3: If you can't use sig bits, you can write a function
which handles the individual hook states */ which handles the individual hook states */
int (*sethook)(struct dahdi_chan *chan, int hookstate); int (*sethook) (struct dahdi_chan * chan, int hookstate);
#endif #endif
static bool pcm_valid(xpd_t *xpd, xpacket_t *pack) static bool pcm_valid(xpd_t *xpd, xpacket_t *pack)
@ -799,7 +825,8 @@ static bool pcm_valid(xpd_t *xpd, xpacket_t *pack)
XPD_COUNTER(xpd, RECV_ERRORS)++; XPD_COUNTER(xpd, RECV_ERRORS)++;
if ((rate_limit++ % 1000) <= 10) { if ((rate_limit++ % 1000) <= 10) {
XPD_ERR(xpd, "BAD PCM REPLY: packet_len=%d (should be %d), count=%d\n", XPD_ERR(xpd,
"BAD PCM REPLY: packet_len=%d (should be %d), count=%d\n",
XPACKET_LEN(pack), good_len, count); XPACKET_LEN(pack), good_len, count);
dump_packet("BAD PCM REPLY", pack, 1); dump_packet("BAD PCM REPLY", pack, 1);
} }
@ -808,8 +835,6 @@ static bool pcm_valid(xpd_t *xpd, xpacket_t *pack)
return 1; return 1;
} }
static inline void pcm_frame_out(xbus_t *xbus, xframe_t *xframe) static inline void pcm_frame_out(xbus_t *xbus, xframe_t *xframe)
{ {
unsigned long flags; unsigned long flags;
@ -824,12 +849,14 @@ static inline void pcm_frame_out(xbus_t *xbus, xframe_t *xframe)
usec = usec_diff(&now, &xbus->last_tx_sync); usec = usec_diff(&now, &xbus->last_tx_sync);
xbus->last_tx_sync = now; xbus->last_tx_sync = now;
/* ignore startup statistics */ /* ignore startup statistics */
if (likely(atomic_read(&xbus->pcm_rx_counter) > BIG_TICK_INTERVAL)) { if (likely
(atomic_read(&xbus->pcm_rx_counter) > BIG_TICK_INTERVAL)) {
if (abs(usec - 1000) > TICK_TOLERANCE) { if (abs(usec - 1000) > TICK_TOLERANCE) {
static int rate_limit; static int rate_limit;
if ((rate_limit++ % 5003) == 0) if ((rate_limit++ % 5003) == 0)
XBUS_DBG(SYNC, xbus, "Bad PCM TX timing(%d): usec=%ld.\n", XBUS_DBG(SYNC, xbus,
"Bad PCM TX timing(%d): usec=%ld.\n",
rate_limit, usec); rate_limit, usec);
} }
if (usec > xbus->max_tx_sync) if (usec > xbus->max_tx_sync)
@ -840,7 +867,7 @@ static inline void pcm_frame_out(xbus_t *xbus, xframe_t *xframe)
} }
spin_unlock_irqrestore(&xbus->lock, flags); spin_unlock_irqrestore(&xbus->lock, flags);
/* OK, really send it */ /* OK, really send it */
if (debug & DBG_PCM ) if (debug & DBG_PCM)
dump_xframe("TX_XFRAME_PCM", xbus, xframe, debug); dump_xframe("TX_XFRAME_PCM", xbus, xframe, debug);
send_pcm_frame(xbus, xframe); send_pcm_frame(xbus, xframe);
XBUS_COUNTER(xbus, TX_XFRAME_PCM)++; XBUS_COUNTER(xbus, TX_XFRAME_PCM)++;
@ -876,10 +903,12 @@ void generic_card_pcm_fromspan(xpd_t *xpd, xpacket_t *pack)
int channo = chan->channo; int channo = chan->channo;
if (pcmtx >= 0 && pcmtx_chan == channo) if (pcmtx >= 0 && pcmtx_chan == channo)
memset((u_char *)pcm, pcmtx, DAHDI_CHUNKSIZE); memset((u_char *)pcm, pcmtx,
DAHDI_CHUNKSIZE);
else else
#endif #endif
memcpy((u_char *)pcm, chan->writechunk, DAHDI_CHUNKSIZE); memcpy((u_char *)pcm, chan->writechunk,
DAHDI_CHUNKSIZE);
} else } else
memset((u_char *)pcm, 0x7F, DAHDI_CHUNKSIZE); memset((u_char *)pcm, 0x7F, DAHDI_CHUNKSIZE);
pcm += DAHDI_CHUNKSIZE; pcm += DAHDI_CHUNKSIZE;
@ -915,7 +944,10 @@ void generic_card_pcm_tospan(xpd_t *xpd, xpacket_t *pack)
/* We have and want real data */ /* We have and want real data */
// memset((u_char *)r, 0x5A, DAHDI_CHUNKSIZE); // DEBUG // memset((u_char *)r, 0x5A, DAHDI_CHUNKSIZE); // DEBUG
memcpy((u_char *)r, pcm, DAHDI_CHUNKSIZE); memcpy((u_char *)r, pcm, DAHDI_CHUNKSIZE);
} else if (IS_SET(PHONEDEV(xpd).wanted_pcm_mask | PHONEDEV(xpd).silence_pcm, i)) { } else
if (IS_SET
(PHONEDEV(xpd).wanted_pcm_mask | PHONEDEV(xpd).
silence_pcm, i)) {
/* Inject SILENCE */ /* Inject SILENCE */
memset((u_char *)r, 0x7F, DAHDI_CHUNKSIZE); memset((u_char *)r, 0x7F, DAHDI_CHUNKSIZE);
if (IS_SET(PHONEDEV(xpd).silence_pcm, i)) { if (IS_SET(PHONEDEV(xpd).silence_pcm, i)) {
@ -923,8 +955,10 @@ void generic_card_pcm_tospan(xpd_t *xpd, xpacket_t *pack)
* This will clear the EC buffers until next tick * This will clear the EC buffers until next tick
* So we don't have noise residues from the past. * So we don't have noise residues from the past.
*/ */
memset(PHONEDEV(xpd).ec_chunk2[i], 0x7F, DAHDI_CHUNKSIZE); memset(PHONEDEV(xpd).ec_chunk2[i], 0x7F,
memset(PHONEDEV(xpd).ec_chunk1[i], 0x7F, DAHDI_CHUNKSIZE); DAHDI_CHUNKSIZE);
memset(PHONEDEV(xpd).ec_chunk1[i], 0x7F,
DAHDI_CHUNKSIZE);
} }
} }
if (got_data) if (got_data)
@ -939,6 +973,7 @@ int generic_echocancel_timeslot(xpd_t *xpd, int pos)
{ {
return xpd->addr.unit * 32 + pos; return xpd->addr.unit * 32 + pos;
} }
EXPORT_SYMBOL(generic_echocancel_timeslot); EXPORT_SYMBOL(generic_echocancel_timeslot);
int generic_echocancel_setmask(xpd_t *xpd, xpp_line_t ec_mask) int generic_echocancel_setmask(xpd_t *xpd, xpp_line_t ec_mask)
@ -959,6 +994,7 @@ int generic_echocancel_setmask(xpd_t *xpd, xpp_line_t ec_mask)
CALL_EC_METHOD(ec_update, xpd->xbus, xpd->xbus); CALL_EC_METHOD(ec_update, xpd->xbus, xpd->xbus);
return 0; return 0;
} }
EXPORT_SYMBOL(generic_echocancel_setmask); EXPORT_SYMBOL(generic_echocancel_setmask);
static int copy_pcm_tospan(xbus_t *xbus, xframe_t *xframe) static int copy_pcm_tospan(xbus_t *xbus, xframe_t *xframe)
@ -988,7 +1024,8 @@ static int copy_pcm_tospan(xbus_t *xbus, xframe_t *xframe)
XBUS_NOTICE(xbus, XBUS_NOTICE(xbus,
"%s: Non-PCM packet within a PCM xframe. (%d)\n", "%s: Non-PCM packet within a PCM xframe. (%d)\n",
__func__, rate_limit); __func__, rate_limit);
dump_xframe("In PCM xframe", xbus, xframe, debug); dump_xframe("In PCM xframe", xbus, xframe,
debug);
} }
goto out; goto out;
} }
@ -1004,13 +1041,18 @@ static int copy_pcm_tospan(xbus_t *xbus, xframe_t *xframe)
} }
goto out; goto out;
} }
xpd = xpd_byaddr(xbus, XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack)); xpd =
xpd_byaddr(xbus, XPACKET_ADDR_UNIT(pack),
XPACKET_ADDR_SUBUNIT(pack));
if (unlikely(!xpd)) { if (unlikely(!xpd)) {
static int rate_limit; static int rate_limit;
if ((rate_limit++ % 1003) == 0) { if ((rate_limit++ % 1003) == 0) {
notify_bad_xpd(__func__, xbus, XPACKET_ADDR(pack), "RECEIVE PCM"); notify_bad_xpd(__func__, xbus,
dump_xframe("Unknown XPD addr", xbus, xframe, debug); XPACKET_ADDR(pack),
"RECEIVE PCM");
dump_xframe("Unknown XPD addr", xbus, xframe,
debug);
} }
goto out; goto out;
} }
@ -1083,23 +1125,28 @@ static void xbus_tick(xbus_t *xbus)
if (xframe && !pack) { /* FULL frame */ if (xframe && !pack) { /* FULL frame */
pcm_frame_out(xbus, xframe); pcm_frame_out(xbus, xframe);
xframe = NULL; xframe = NULL;
XBUS_COUNTER(xbus, TX_PCM_FRAG)++; XBUS_COUNTER(xbus,
TX_PCM_FRAG)++;
} }
if (!xframe) { /* Alloc frame */ if (!xframe) { /* Alloc frame */
xframe = ALLOC_SEND_XFRAME(xbus); xframe =
ALLOC_SEND_XFRAME(xbus);
if (!xframe) { if (!xframe) {
static int rate_limit; static int rate_limit;
if ((rate_limit++ % 3001) == 0) if ((rate_limit++ %
3001) == 0)
XBUS_ERR(xbus, XBUS_ERR(xbus,
"%s: failed to allocate new xframe\n", "%s: failed to allocate new xframe\n",
__func__); __func__);
return; return;
} }
} }
pack = xframe_next_packet(xframe, pcm_len); pack =
xframe_next_packet(xframe, pcm_len);
} while (!pack); } while (!pack);
XPACKET_INIT(pack, GLOBAL, PCM_WRITE, xpd->xbus_idx, 1, 0); XPACKET_INIT(pack, GLOBAL, PCM_WRITE,
xpd->xbus_idx, 1, 0);
XPACKET_LEN(pack) = pcm_len; XPACKET_LEN(pack) = pcm_len;
if (!sent_sync_bit) { if (!sent_sync_bit) {
XPACKET_ADDR_SYNC(pack) = 1; XPACKET_ADDR_SYNC(pack) = 1;
@ -1125,12 +1172,15 @@ static void xbus_tick(xbus_t *xbus)
usec = usec_diff(&now, &xbus->last_rx_sync); usec = usec_diff(&now, &xbus->last_rx_sync);
xbus->last_rx_sync = now; xbus->last_rx_sync = now;
/* ignore startup statistics */ /* ignore startup statistics */
if (likely(atomic_read(&xbus->pcm_rx_counter) > BIG_TICK_INTERVAL)) { if (likely
(atomic_read(&xbus->pcm_rx_counter) >
BIG_TICK_INTERVAL)) {
if (abs(usec - 1000) > TICK_TOLERANCE) { if (abs(usec - 1000) > TICK_TOLERANCE) {
static int rate_limit; static int rate_limit;
if ((rate_limit++ % 5003) == 0) if ((rate_limit++ % 5003) == 0)
XBUS_DBG(SYNC, xbus, "Bad PCM RX timing(%d): usec=%ld.\n", XBUS_DBG(SYNC, xbus,
"Bad PCM RX timing(%d): usec=%ld.\n",
rate_limit, usec); rate_limit, usec);
} }
if (usec > xbus->max_rx_sync) if (usec > xbus->max_rx_sync)
@ -1238,7 +1288,8 @@ int fill_sync_string(char *buf, size_t count)
int len = 0; int len = 0;
if (!syncer) { if (!syncer) {
len += snprintf(buf, count, "%s\n", len +=
snprintf(buf, count, "%s\n",
(force_dahdi_sync) ? "DAHDI" : "NO-SYNC"); (force_dahdi_sync) ? "DAHDI" : "NO-SYNC");
} else } else
len += snprintf(buf, count, "SYNC=%02d\n", syncer->num); len += snprintf(buf, count, "SYNC=%02d\n", syncer->num);
@ -1251,7 +1302,7 @@ int xbus_pcm_init(void *toplevel)
#ifdef OPTIMIZE_CHANMUTE #ifdef OPTIMIZE_CHANMUTE
INFO("FEATURE: with CHANMUTE optimization (%sactivated)\n", INFO("FEATURE: with CHANMUTE optimization (%sactivated)\n",
(optimize_chanmute)?"":"de"); (optimize_chanmute) ? "" : "de");
#endif #endif
#ifdef DAHDI_SYNC_TICK #ifdef DAHDI_SYNC_TICK
INFO("FEATURE: with sync_tick() from DAHDI\n"); INFO("FEATURE: with sync_tick() from DAHDI\n");
@ -1267,7 +1318,6 @@ void xbus_pcm_shutdown(void)
{ {
} }
EXPORT_SYMBOL(xbus_request_sync); EXPORT_SYMBOL(xbus_request_sync);
EXPORT_SYMBOL(got_new_syncer); EXPORT_SYMBOL(got_new_syncer);
EXPORT_SYMBOL(elect_syncer); EXPORT_SYMBOL(elect_syncer);
@ -1283,4 +1333,3 @@ EXPORT_SYMBOL(generic_timing_priority);
EXPORT_SYMBOL(pcmtx); EXPORT_SYMBOL(pcmtx);
EXPORT_SYMBOL(pcmtx_chan); EXPORT_SYMBOL(pcmtx_chan);
#endif #endif

View File

@ -88,7 +88,8 @@ struct xpp_drift {
void xpp_drift_init(xbus_t *xbus); void xpp_drift_init(xbus_t *xbus);
static inline long usec_diff(const struct timeval *tv1, const struct timeval *tv2) static inline long usec_diff(const struct timeval *tv1,
const struct timeval *tv2)
{ {
long diff_sec; long diff_sec;
long diff_usec; long diff_usec;
@ -98,7 +99,6 @@ static inline long usec_diff(const struct timeval *tv1, const struct timeval *tv
return diff_sec * 1000000 + diff_usec; return diff_sec * 1000000 + diff_usec;
} }
int xbus_pcm_init(void *top); int xbus_pcm_init(void *top);
void xbus_pcm_shutdown(void); void xbus_pcm_shutdown(void);
int send_pcm_frame(xbus_t *xbus, xframe_t *xframe); int send_pcm_frame(xbus_t *xbus, xframe_t *xframe);
@ -133,4 +133,3 @@ extern int pcmtx_chan;
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
#endif /* XBUS_PCM_H */ #endif /* XBUS_PCM_H */

View File

@ -22,7 +22,7 @@
#include <linux/version.h> #include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
# warning "This module is tested only with 2.6 kernels" #warning "This module is tested only with 2.6 kernels"
#endif #endif
#include <linux/kernel.h> #include <linux/kernel.h>
@ -52,7 +52,8 @@ static ssize_t sync_show(struct device_driver *driver, char *buf)
return fill_sync_string(buf, PAGE_SIZE); return fill_sync_string(buf, PAGE_SIZE);
} }
static ssize_t sync_store(struct device_driver *driver, const char *buf, size_t count) static ssize_t sync_store(struct device_driver *driver, const char *buf,
size_t count)
{ {
/* DBG(SYNC, "%s\n", buf); */ /* DBG(SYNC, "%s\n", buf); */
return exec_sync_command(buf, count); return exec_sync_command(buf, count);
@ -71,8 +72,7 @@ static DEVICE_ATTR_READER(xbus_state_show, dev, buf)
xbus = dev_to_xbus(dev); xbus = dev_to_xbus(dev);
ret = XBUS_STATE(xbus); ret = XBUS_STATE(xbus);
ret = snprintf(buf, PAGE_SIZE, "%s (%d)\n", ret = snprintf(buf, PAGE_SIZE, "%s (%d)\n", xbus_statename(ret), ret);
xbus_statename(ret), ret);
return ret; return ret;
} }
@ -87,9 +87,9 @@ static DEVICE_ATTR_WRITER(xbus_state_store, dev, buf, count)
else if (XBUS_IS(xbus, IDLE) && strncmp(buf, "start", 5) == 0) else if (XBUS_IS(xbus, IDLE) && strncmp(buf, "start", 5) == 0)
xbus_activate(xbus); xbus_activate(xbus);
else { else {
XBUS_NOTICE(xbus, "%s: Illegal action %s in state %s. Ignored.\n", XBUS_NOTICE(xbus,
__func__, buf, "%s: Illegal action %s in state %s. Ignored.\n",
xbus_statename(XBUS_STATE(xbus))); __func__, buf, xbus_statename(XBUS_STATE(xbus)));
return -EINVAL; return -EINVAL;
} }
return count; return count;
@ -101,7 +101,9 @@ static DEVICE_ATTR_READER(status_show, dev, buf)
int ret; int ret;
xbus = dev_to_xbus(dev); xbus = dev_to_xbus(dev);
ret = snprintf(buf, PAGE_SIZE, "%s\n", (XBUS_FLAGS(xbus, CONNECTED))?"connected":"missing"); ret =
snprintf(buf, PAGE_SIZE, "%s\n",
(XBUS_FLAGS(xbus, CONNECTED)) ? "connected" : "missing");
return ret; return ret;
} }
@ -115,16 +117,19 @@ static DEVICE_ATTR_READER(timing_show, dev, buf)
do_gettimeofday(&now); do_gettimeofday(&now);
xbus = dev_to_xbus(dev); xbus = dev_to_xbus(dev);
driftinfo = &xbus->drift; driftinfo = &xbus->drift;
len += snprintf(buf + len, PAGE_SIZE - len, "%-3s", sync_mode_name(xbus->sync_mode)); len +=
snprintf(buf + len, PAGE_SIZE - len, "%-3s",
sync_mode_name(xbus->sync_mode));
if (xbus->sync_mode == SYNC_MODE_PLL) { if (xbus->sync_mode == SYNC_MODE_PLL) {
len += snprintf(buf + len, PAGE_SIZE - len, len +=
" %5d: lost (%4d,%4d) : ", snprintf(buf + len, PAGE_SIZE - len,
xbus->ticker.cycle, " %5d: lost (%4d,%4d) : ", xbus->ticker.cycle,
driftinfo->lost_ticks, driftinfo->lost_tick_count); driftinfo->lost_ticks, driftinfo->lost_tick_count);
len += snprintf(buf + len, PAGE_SIZE - len, len +=
"DRIFT %3d %ld sec ago", snprintf(buf + len, PAGE_SIZE - len,
xbus->sync_adjustment, "DRIFT %3d %ld sec ago", xbus->sync_adjustment,
(xbus->pll_updated_at == 0) ? 0 : now.tv_sec - xbus->pll_updated_at); (xbus->pll_updated_at ==
0) ? 0 : now.tv_sec - xbus->pll_updated_at);
} }
len += snprintf(buf + len, PAGE_SIZE - len, "\n"); len += snprintf(buf + len, PAGE_SIZE - len, "\n");
return len; return len;
@ -151,7 +156,9 @@ static DEVICE_ATTR_READER(samples_show, dev, buf)
for (i = 0; i < SAMPLE_SIZE; i++) { for (i = 0; i < SAMPLE_SIZE; i++) {
if (len > PAGE_SIZE - 20) if (len > PAGE_SIZE - 20)
break; break;
len += snprintf(buf + len, PAGE_SIZE - len, "%d\n", xbus->sample_ticks[i]); len +=
snprintf(buf + len, PAGE_SIZE - len, "%d\n",
xbus->sample_ticks[i]);
} }
return len; return len;
} }
@ -239,25 +246,38 @@ static DEVICE_ATTR_READER(driftinfo_show, dev, buf)
hours = minutes / 60; hours = minutes / 60;
minutes = minutes % 60; minutes = minutes % 60;
#define SHOW(ptr,item) len += snprintf(buf + len, PAGE_SIZE - len, "%-15s: %8d\n", #item, (ptr)->item) #define SHOW(ptr,item) len += snprintf(buf + len, PAGE_SIZE - len, "%-15s: %8d\n", #item, (ptr)->item)
len += snprintf(buf + len, PAGE_SIZE - len, "%-15s: %8d (was %d:%02d:%02d ago)\n", len +=
"lost_ticks", di->lost_ticks, hours, minutes, seconds); snprintf(buf + len, PAGE_SIZE - len,
"%-15s: %8d (was %d:%02d:%02d ago)\n", "lost_ticks",
di->lost_ticks, hours, minutes, seconds);
speed_range = abs(di->max_speed - di->min_speed); speed_range = abs(di->max_speed - di->min_speed);
uframes_inaccuracy = di->sync_inaccuracy / 125; uframes_inaccuracy = di->sync_inaccuracy / 125;
len += snprintf(buf + len, PAGE_SIZE - len, "%-15s: %8d ", len +=
"instability", speed_range + uframes_inaccuracy); snprintf(buf + len, PAGE_SIZE - len, "%-15s: %8d ", "instability",
speed_range + uframes_inaccuracy);
if (xbus->sync_mode == SYNC_MODE_AB) { if (xbus->sync_mode == SYNC_MODE_AB) {
buf[len++] = '-'; buf[len++] = '-';
} else { } else {
for (i = 0; len < PAGE_SIZE - 1 && i < speed_range + uframes_inaccuracy; i++) for (i = 0;
len < PAGE_SIZE - 1
&& i < speed_range + uframes_inaccuracy; i++)
buf[len++] = '#'; buf[len++] = '#';
} }
buf[len++] = '\n'; buf[len++] = '\n';
len += snprintf(buf + len, PAGE_SIZE - len, "%-15s: %8d (uframes)\n", "inaccuracy", uframes_inaccuracy); len +=
len += snprintf(buf + len, PAGE_SIZE - len, "%-15s: %8d\n", "speed_range", speed_range); snprintf(buf + len, PAGE_SIZE - len, "%-15s: %8d (uframes)\n",
"inaccuracy", uframes_inaccuracy);
len +=
snprintf(buf + len, PAGE_SIZE - len, "%-15s: %8d\n", "speed_range",
speed_range);
SHOW(xbus, sync_adjustment); SHOW(xbus, sync_adjustment);
len += snprintf(buf + len, PAGE_SIZE - len, "%-15s: %8d\n", "offset (usec)", di->offset_prev); len +=
snprintf(buf + len, PAGE_SIZE - len, "%-15s: %8d\n",
"offset (usec)", di->offset_prev);
SHOW(di, offset_range); SHOW(di, offset_range);
len += snprintf(buf + len, PAGE_SIZE - len, "%-15s: %8d\n", "best_speed", (di->max_speed + di->min_speed) / 2); len +=
snprintf(buf + len, PAGE_SIZE - len, "%-15s: %8d\n", "best_speed",
(di->max_speed + di->min_speed) / 2);
SHOW(di, min_speed); SHOW(di, min_speed);
SHOW(di, max_speed); SHOW(di, max_speed);
SHOW(ticker, cycle); SHOW(ticker, cycle);
@ -301,14 +321,14 @@ static struct device_attribute xbus_dev_attrs[] = {
__ATTR_RO(waitfor_xpds), __ATTR_RO(waitfor_xpds),
__ATTR_RO(driftinfo), __ATTR_RO(driftinfo),
__ATTR(cls, S_IWUSR, NULL, cls_store), __ATTR(cls, S_IWUSR, NULL, cls_store),
__ATTR(xbus_state, S_IRUGO | S_IWUSR, xbus_state_show, xbus_state_store), __ATTR(xbus_state, S_IRUGO | S_IWUSR, xbus_state_show,
xbus_state_store),
#ifdef SAMPLE_TICKS #ifdef SAMPLE_TICKS
__ATTR(samples, S_IWUSR | S_IRUGO, samples_show, samples_store), __ATTR(samples, S_IWUSR | S_IRUGO, samples_show, samples_store),
#endif #endif
__ATTR_NULL, __ATTR_NULL,
}; };
static int astribank_match(struct device *dev, struct device_driver *driver) static int astribank_match(struct device *dev, struct device_driver *driver)
{ {
DBG(DEVICES, "SYSFS MATCH: dev->bus_id = %s, driver->name = %s\n", DBG(DEVICES, "SYSFS MATCH: dev->bus_id = %s, driver->name = %s\n",
@ -317,7 +337,8 @@ static int astribank_match(struct device *dev, struct device_driver *driver)
} }
#ifdef OLD_HOTPLUG_SUPPORT #ifdef OLD_HOTPLUG_SUPPORT
static int astribank_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; xbus_t *xbus;
@ -349,7 +370,8 @@ static int astribank_hotplug(struct device *dev, char **envp, int envnum, char *
return err; \ return err; \
} while (0) } while (0)
static int astribank_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; xbus_t *xbus;
int i = 0; int i = 0;
@ -429,7 +451,8 @@ static void astribank_release(struct device *dev)
XBUS_ERR(xbus, "Try to release CONNECTED device.\n"); XBUS_ERR(xbus, "Try to release CONNECTED device.\n");
BUG(); BUG();
} }
if (!XBUS_IS(xbus, IDLE) && !XBUS_IS(xbus, FAIL) && !XBUS_IS(xbus, DEACTIVATED)) { if (!XBUS_IS(xbus, IDLE) && !XBUS_IS(xbus, FAIL)
&& !XBUS_IS(xbus, DEACTIVATED)) {
XBUS_ERR(xbus, "Try to release in state %s\n", XBUS_ERR(xbus, "Try to release in state %s\n",
xbus_statename(XBUS_STATE(xbus))); xbus_statename(XBUS_STATE(xbus)));
BUG(); BUG();
@ -495,7 +518,9 @@ static DEVICE_ATTR_READER(chipregs_show, dev, buf)
return -ENODEV; return -ENODEV;
spin_lock_irqsave(&xpd->lock, flags); spin_lock_irqsave(&xpd->lock, flags);
regs = &xpd->last_reply; regs = &xpd->last_reply;
len += sprintf(buf + len, "# Writing bad data into this file may damage your hardware!\n"); 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, "# Consult firmware docs first\n");
len += sprintf(buf + len, "#\n"); len += sprintf(buf + len, "#\n");
do_datah = REG_FIELD(regs, do_datah) ? 1 : 0; do_datah = REG_FIELD(regs, do_datah) ? 1 : 0;
@ -505,19 +530,22 @@ static DEVICE_ATTR_READER(chipregs_show, dev, buf)
} else } else
datah_str[0] = '\0'; datah_str[0] = '\0';
if (REG_FIELD(regs, do_subreg)) { if (REG_FIELD(regs, do_subreg)) {
len += sprintf(buf + len, "#CH\tOP\tReg.\tSub\tDL%s\n", len +=
sprintf(buf + len, "#CH\tOP\tReg.\tSub\tDL%s\n",
(do_datah) ? "\tDH" : ""); (do_datah) ? "\tDH" : "");
len += sprintf(buf + len, "%2d\tRS\t%02X\t%02X\t%02X%s\n", len +=
regs->portnum, sprintf(buf + len, "%2d\tRS\t%02X\t%02X\t%02X%s\n",
REG_FIELD(regs, regnum), REG_FIELD(regs, subreg), regs->portnum, REG_FIELD(regs, regnum),
REG_FIELD(regs, data_low), datah_str); REG_FIELD(regs, subreg), REG_FIELD(regs, data_low),
datah_str);
} else { } else {
len += sprintf(buf + len, "#CH\tOP\tReg.\tDL%s\n", len +=
sprintf(buf + len, "#CH\tOP\tReg.\tDL%s\n",
(do_datah) ? "\tDH" : ""); (do_datah) ? "\tDH" : "");
len += sprintf(buf + len, "%2d\tRD\t%02X\t%02X%s\n", len +=
regs->portnum, sprintf(buf + len, "%2d\tRD\t%02X\t%02X%s\n", regs->portnum,
REG_FIELD(regs, regnum), REG_FIELD(regs, regnum), REG_FIELD(regs, data_low),
REG_FIELD(regs, data_low), datah_str); datah_str);
} }
spin_unlock_irqrestore(&xpd->lock, flags); spin_unlock_irqrestore(&xpd->lock, flags);
return len; return len;
@ -541,14 +569,17 @@ static DEVICE_ATTR_WRITER(chipregs_store, dev, buf, count)
i = strcspn(p, "\r\n"); i = strcspn(p, "\r\n");
if (i > 0) { if (i > 0) {
if (i >= MAX_PROC_WRITE) { if (i >= MAX_PROC_WRITE) {
XPD_NOTICE(xpd, "Command too long (%d chars)\n", i); XPD_NOTICE(xpd, "Command too long (%d chars)\n",
i);
return -E2BIG; return -E2BIG;
} }
memcpy(tmp, p, i); memcpy(tmp, p, i);
tmp[i] = '\0'; tmp[i] = '\0';
ret = parse_chip_command(xpd, tmp); ret = parse_chip_command(xpd, tmp);
if (ret < 0) { if (ret < 0) {
XPD_NOTICE(xpd, "Failed writing command: '%s'\n", tmp); XPD_NOTICE(xpd,
"Failed writing command: '%s'\n",
tmp);
return ret; return ret;
} }
} }
@ -608,7 +639,9 @@ static DEVICE_ATTR_READER(span_show, dev, buf)
if (!xpd) if (!xpd)
return -ENODEV; return -ENODEV;
spin_lock_irqsave(&xpd->lock, flags); spin_lock_irqsave(&xpd->lock, flags);
len += sprintf(buf, "%d\n", SPAN_REGISTERED(xpd) ? PHONEDEV(xpd).span.spanno : 0); len +=
sprintf(buf, "%d\n",
SPAN_REGISTERED(xpd) ? PHONEDEV(xpd).span.spanno : 0);
spin_unlock_irqrestore(&xpd->lock, flags); spin_unlock_irqrestore(&xpd->lock, flags);
return len; return len;
} }
@ -632,8 +665,7 @@ static DEVICE_ATTR_WRITER(span_store, dev, buf, count)
return -EINVAL; return -EINVAL;
if (!XBUS_IS(xpd->xbus, READY)) if (!XBUS_IS(xpd->xbus, READY))
return -ENODEV; return -ENODEV;
XPD_DBG(DEVICES, xpd, XPD_DBG(DEVICES, xpd, "%s -- deprecated (should use pinned-spans)\n",
"%s -- deprecated (should use pinned-spans)\n",
(dahdi_reg) ? "register" : "unregister"); (dahdi_reg) ? "register" : "unregister");
if (xbus_is_registered(xpd->xbus)) { if (xbus_is_registered(xpd->xbus)) {
if (dahdi_reg) { if (dahdi_reg) {
@ -725,11 +757,13 @@ static int xpd_match(struct device *dev, struct device_driver *driver)
xpd_driver = driver_to_xpd_driver(driver); xpd_driver = driver_to_xpd_driver(driver);
xpd = dev_to_xpd(dev); xpd = dev_to_xpd(dev);
if (xpd_driver->type != xpd->type) { if (xpd_driver->type != xpd->type) {
XPD_DBG(DEVICES, xpd, "SYSFS match fail: xpd->type = %d, xpd_driver->type = %d\n", XPD_DBG(DEVICES, xpd,
"SYSFS match fail: xpd->type = %d, xpd_driver->type = %d\n",
xpd->type, xpd_driver->type); xpd->type, xpd_driver->type);
return 0; return 0;
} }
XPD_DBG(DEVICES, xpd, "SYSFS MATCH: type=%d dev->bus_id = %s, driver->name = %s\n", XPD_DBG(DEVICES, xpd,
"SYSFS MATCH: type=%d dev->bus_id = %s, driver->name = %s\n",
xpd->type, dev_name(dev), driver->name); xpd->type, dev_name(dev), driver->name);
return 1; return 1;
} }
@ -758,8 +792,8 @@ int xpd_driver_register(struct device_driver *driver)
DBG(DEVICES, "%s\n", driver->name); DBG(DEVICES, "%s\n", driver->name);
driver->bus = &xpd_type; driver->bus = &xpd_type;
if ((ret = driver_register(driver)) < 0) { if ((ret = driver_register(driver)) < 0) {
ERR("%s: driver_register(%s) failed. Error number %d", ERR("%s: driver_register(%s) failed. Error number %d", __func__,
__func__, driver->name, ret); driver->name, ret);
} }
return ret; return ret;
} }
@ -905,12 +939,12 @@ int echocancel_xpd(xpd_t *xpd, int on)
ret = device_create_file(&xpd->xpd_dev, &dev_attr_echocancel); ret = device_create_file(&xpd->xpd_dev, &dev_attr_echocancel);
if (ret) if (ret)
XPD_ERR(xpd, XPD_ERR(xpd, "%s: device_create_file(echocancel) failed: %d\n",
"%s: device_create_file(echocancel) failed: %d\n",
__func__, ret); __func__, ret);
return ret; return ret;
} }
EXPORT_SYMBOL(echocancel_xpd); EXPORT_SYMBOL(echocancel_xpd);
/*--------- Sysfs Device handling ----*/ /*--------- Sysfs Device handling ----*/
@ -940,11 +974,12 @@ int xbus_sysfs_transport_create(xbus_t *xbus)
XBUS_ERR(xbus, "%s: Missing transport_device\n", __func__); XBUS_ERR(xbus, "%s: Missing transport_device\n", __func__);
return -ENODEV; return -ENODEV;
} }
ret = sysfs_create_link(&astribank->kobj, &transport_device->kobj, ret =
sysfs_create_link(&astribank->kobj, &transport_device->kobj,
"transport"); "transport");
if (ret < 0) { if (ret < 0) {
XBUS_ERR(xbus, "%s: sysfs_create_link failed: %d\n", XBUS_ERR(xbus, "%s: sysfs_create_link failed: %d\n", __func__,
__func__, ret); ret);
dev_set_drvdata(astribank, NULL); dev_set_drvdata(astribank, NULL);
} }
return ret; return ret;
@ -979,7 +1014,8 @@ int xbus_sysfs_create(xbus_t *xbus)
astribank->release = astribank_release; astribank->release = astribank_release;
ret = device_register(astribank); ret = device_register(astribank);
if (ret) { if (ret) {
XBUS_ERR(xbus, "%s: device_register failed: %d\n", __func__, ret); XBUS_ERR(xbus, "%s: device_register failed: %d\n", __func__,
ret);
dev_set_drvdata(astribank, NULL); dev_set_drvdata(astribank, NULL);
} }
return ret; return ret;
@ -991,18 +1027,18 @@ int __init xpp_driver_init(void)
DBG(DEVICES, "SYSFS\n"); DBG(DEVICES, "SYSFS\n");
if ((ret = bus_register(&toplevel_bus_type)) < 0) { if ((ret = bus_register(&toplevel_bus_type)) < 0) {
ERR("%s: bus_register(%s) failed. Error number %d", ERR("%s: bus_register(%s) failed. Error number %d", __func__,
__func__, toplevel_bus_type.name, ret); toplevel_bus_type.name, ret);
goto failed_toplevel; goto failed_toplevel;
} }
if ((ret = driver_register(&xpp_driver)) < 0) { if ((ret = driver_register(&xpp_driver)) < 0) {
ERR("%s: driver_register(%s) failed. Error number %d", ERR("%s: driver_register(%s) failed. Error number %d", __func__,
__func__, xpp_driver.name, ret); xpp_driver.name, ret);
goto failed_xpp_driver; goto failed_xpp_driver;
} }
if ((ret = bus_register(&xpd_type)) < 0) { if ((ret = bus_register(&xpd_type)) < 0) {
ERR("%s: bus_register(%s) failed. Error number %d", ERR("%s: bus_register(%s) failed. Error number %d", __func__,
__func__, xpd_type.name, ret); xpd_type.name, ret);
goto failed_xpd_bus; goto failed_xpd_bus;
} }
return 0; return 0;

View File

@ -45,7 +45,10 @@ typedef uint32_t __u32;
#define ERR(fmt, ...) printf("ERR: " fmt, ## __VA_ARGS__) #define ERR(fmt, ...) printf("ERR: " fmt, ## __VA_ARGS__)
#define __user #define __user
struct list_head { struct list_head *next; struct list_head *prev; }; struct list_head {
struct list_head *next;
struct list_head *prev;
};
#endif #endif
@ -121,7 +124,7 @@ typedef unsigned char byte;
#define OLD_HOTPLUG_SUPPORT // for older kernels #define OLD_HOTPLUG_SUPPORT // for older kernels
#endif #endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10)
#define OLD_HOTPLUG_SUPPORT_269// for way older kernels #define OLD_HOTPLUG_SUPPORT_269 // for way older kernels
#endif #endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)

View File

@ -7,7 +7,8 @@ extern int debug;
static xframe_t *transport_alloc_xframe(xbus_t *xbus, gfp_t gfp_flags); static xframe_t *transport_alloc_xframe(xbus_t *xbus, gfp_t gfp_flags);
static void transport_free_xframe(xbus_t *xbus, xframe_t *xframe); static void transport_free_xframe(xbus_t *xbus, xframe_t *xframe);
void xframe_queue_init(struct xframe_queue *q, unsigned int steady_state_count, unsigned int max_count, const char *name, void *priv) void xframe_queue_init(struct xframe_queue *q, unsigned int steady_state_count,
unsigned int max_count, const char *name, void *priv)
{ {
memset(q, 0, sizeof(*q)); memset(q, 0, sizeof(*q));
spin_lock_init(&q->lock); spin_lock_init(&q->lock);
@ -34,8 +35,7 @@ static void __xframe_dump_queue(struct xframe_queue *q)
do_gettimeofday(&now); do_gettimeofday(&now);
printk(KERN_DEBUG "%s: dump queue '%s' (first packet in each frame)\n", printk(KERN_DEBUG "%s: dump queue '%s' (first packet in each frame)\n",
THIS_MODULE->name, THIS_MODULE->name, q->name);
q->name);
list_for_each_entry_reverse(xframe, &q->head, frame_list) { list_for_each_entry_reverse(xframe, &q->head, frame_list) {
xpacket_t *pack = (xpacket_t *)&xframe->packets[0]; xpacket_t *pack = (xpacket_t *)&xframe->packets[0];
long usec = usec_diff(&now, &xframe->tv_queued); long usec = usec_diff(&now, &xframe->tv_queued);
@ -57,13 +57,10 @@ static bool __xframe_enqueue(struct xframe_queue *q, xframe_t *xframe)
if (q->count >= q->max_count) { if (q->count >= q->max_count) {
q->overflows++; q->overflows++;
if ((overflow_cnt++ % 1000) < 5) { if ((overflow_cnt++ % 1000) < 5) {
NOTICE("Overflow of %-15s: counts %3d, %3d, %3d worst %3d, overflows %3d worst_lag %02ld.%ld ms\n", NOTICE
q->name, ("Overflow of %-15s: counts %3d, %3d, %3d worst %3d, overflows %3d worst_lag %02ld.%ld ms\n",
q->steady_state_count, q->name, q->steady_state_count, q->count,
q->count, q->max_count, q->worst_count, q->overflows,
q->max_count,
q->worst_count,
q->overflows,
q->worst_lag_usec / 1000, q->worst_lag_usec / 1000,
q->worst_lag_usec % 1000); q->worst_lag_usec % 1000);
__xframe_dump_queue(q); __xframe_dump_queue(q);
@ -105,8 +102,10 @@ static xframe_t *__xframe_dequeue(struct xframe_queue *q)
frm = list_entry(h, xframe_t, frame_list); frm = list_entry(h, xframe_t, frame_list);
do_gettimeofday(&now); do_gettimeofday(&now);
usec_lag = usec_lag =
(now.tv_sec - frm->tv_queued.tv_sec)*1000*1000 + (now.tv_sec - frm->tv_queued.tv_sec) * 1000 * 1000 + (now.tv_usec -
(now.tv_usec - frm->tv_queued.tv_usec); frm->
tv_queued.
tv_usec);
if (q->worst_lag_usec < usec_lag) if (q->worst_lag_usec < usec_lag)
q->worst_lag_usec = usec_lag; q->worst_lag_usec = usec_lag;
out: out:
@ -123,6 +122,7 @@ xframe_t *xframe_dequeue(struct xframe_queue *q)
spin_unlock_irqrestore(&q->lock, flags); spin_unlock_irqrestore(&q->lock, flags);
return frm; return frm;
} }
void xframe_queue_disable(struct xframe_queue *q, bool disabled) void xframe_queue_disable(struct xframe_queue *q, bool disabled)
{ {
q->disabled = disabled; q->disabled = disabled;
@ -139,7 +139,8 @@ void xframe_queue_clear(struct xframe_queue *q)
transport_free_xframe(xbus, xframe); transport_free_xframe(xbus, xframe);
i++; i++;
} }
XBUS_DBG(DEVICES, xbus, "%s: finished queue clear (%d items)\n", q->name, i); XBUS_DBG(DEVICES, xbus, "%s: finished queue clear (%d items)\n",
q->name, i);
} }
uint xframe_queue_count(struct xframe_queue *q) uint xframe_queue_count(struct xframe_queue *q)
@ -214,14 +215,16 @@ static bool xframe_queue_adjust(struct xframe_queue *q)
static int rate_limit; static int rate_limit;
if ((rate_limit++ % 3001) == 0) if ((rate_limit++ % 3001) == 0)
XBUS_ERR(xbus, "%s: failed frame allocation\n", q->name); XBUS_ERR(xbus, "%s: failed frame allocation\n",
q->name);
goto out; goto out;
} }
if (!__xframe_enqueue(q, xframe)) { if (!__xframe_enqueue(q, xframe)) {
static int rate_limit; static int rate_limit;
if ((rate_limit++ % 3001) == 0) if ((rate_limit++ % 3001) == 0)
XBUS_ERR(xbus, "%s: failed enqueueing frame\n", q->name); XBUS_ERR(xbus, "%s: failed enqueueing frame\n",
q->name);
transport_free_xframe(xbus, xframe); transport_free_xframe(xbus, xframe);
goto out; goto out;
} }
@ -233,7 +236,8 @@ static bool xframe_queue_adjust(struct xframe_queue *q)
static int rate_limit; static int rate_limit;
if ((rate_limit++ % 3001) == 0) if ((rate_limit++ % 3001) == 0)
XBUS_ERR(xbus, "%s: failed dequeueing frame\n", q->name); XBUS_ERR(xbus, "%s: failed dequeueing frame\n",
q->name);
goto out; goto out;
} }
transport_free_xframe(xbus, xframe); transport_free_xframe(xbus, xframe);
@ -258,7 +262,8 @@ xframe_t *get_xframe(struct xframe_queue *q)
static int rate_limit; static int rate_limit;
if ((rate_limit++ % 3001) == 0) if ((rate_limit++ % 3001) == 0)
XBUS_ERR(xbus, "%s STILL EMPTY (%d)\n", q->name, rate_limit); XBUS_ERR(xbus, "%s STILL EMPTY (%d)\n", q->name,
rate_limit);
return NULL; return NULL;
} }
BUG_ON(xframe->xframe_magic != XFRAME_MAGIC); BUG_ON(xframe->xframe_magic != XFRAME_MAGIC);
@ -294,7 +299,6 @@ void put_xframe(struct xframe_queue *q, xframe_t *xframe)
xframe_queue_adjust(q); xframe_queue_adjust(q);
} }
EXPORT_SYMBOL(xframe_queue_init); EXPORT_SYMBOL(xframe_queue_init);
EXPORT_SYMBOL(xframe_queue_clearstats); EXPORT_SYMBOL(xframe_queue_clearstats);
EXPORT_SYMBOL(xframe_enqueue); EXPORT_SYMBOL(xframe_enqueue);

View File

@ -22,9 +22,8 @@ struct xframe_queue {
unsigned long worst_lag_usec; /* since xframe creation */ unsigned long worst_lag_usec; /* since xframe creation */
}; };
void xframe_queue_init(struct xframe_queue *q, void xframe_queue_init(struct xframe_queue *q, unsigned int steady_state_count,
unsigned int steady_state_count, unsigned int max_count, unsigned int max_count, const char *name, void *priv);
const char *name, void *priv);
__must_check bool xframe_enqueue(struct xframe_queue *q, xframe_t *xframe); __must_check bool xframe_enqueue(struct xframe_queue *q, xframe_t *xframe);
__must_check xframe_t *xframe_dequeue(struct xframe_queue *q); __must_check xframe_t *xframe_dequeue(struct xframe_queue *q);
void xframe_queue_clearstats(struct xframe_queue *q); void xframe_queue_clearstats(struct xframe_queue *q);

View File

@ -122,10 +122,7 @@ enum {
static struct xpd_counters { static struct xpd_counters {
char *name; char *name;
} xpd_counters[] = { } xpd_counters[] = {
C_(PCM_READ), C_(PCM_READ), C_(PCM_WRITE), C_(RECV_ERRORS),};
C_(PCM_WRITE),
C_(RECV_ERRORS),
};
#undef C_ #undef C_

View File

@ -27,7 +27,7 @@
#include <linux/version.h> #include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
# warning "This module is tested only with 2.6 kernels" #warning "This module is tested only with 2.6 kernels"
#endif #endif
#include <linux/kernel.h> #include <linux/kernel.h>
@ -57,7 +57,8 @@ struct proc_dir_entry *xpp_proc_toplevel = NULL;
#define DELAY_UNTIL_DIALTONE 3000 #define DELAY_UNTIL_DIALTONE 3000
DEF_PARM(int, debug, 0, 0644, "Print DBG statements"); DEF_PARM(int, debug, 0, 0644, "Print DBG statements");
static DEF_PARM_BOOL(prefmaster, 0, 0644, "Do we want to be dahdi preferred sync master"); static DEF_PARM_BOOL(prefmaster, 0, 0644,
"Do we want to be dahdi preferred sync master");
// DEF_ARRAY(int, pcmtx, 4, 0, "Forced PCM values to transmit"); // DEF_ARRAY(int, pcmtx, 4, 0, "Forced PCM values to transmit");
#include "dahdi_debug.h" #include "dahdi_debug.h"
@ -75,6 +76,7 @@ static void phonedev_cleanup(xpd_t *xpd);
* echo "3,5" > /sys/module/xpp/parameters/parport_xbuses * echo "3,5" > /sys/module/xpp/parameters/parport_xbuses
*/ */
static int parport_xbuses[2] = { 0, 1 }; static int parport_xbuses[2] = { 0, 1 };
unsigned int parport_xbuses_num_values; unsigned int parport_xbuses_num_values;
#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 9) #if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 9)
module_param_array(parport_xbuses, int, &parport_xbuses_num_values, 0577); module_param_array(parport_xbuses, int, &parport_xbuses_num_values, 0577);
@ -97,6 +99,7 @@ void xbus_flip_bit(xbus_t *xbus, unsigned int bitnum0, unsigned int bitnum1)
if (num == parport_xbuses[1]) if (num == parport_xbuses[1])
flip_parport_bit(bitnum1); flip_parport_bit(bitnum1);
} }
EXPORT_SYMBOL(xbus_flip_bit); EXPORT_SYMBOL(xbus_flip_bit);
#endif #endif
@ -108,7 +111,8 @@ int total_registered_spans(void)
} }
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data); static int xpd_read_proc(char *page, char **start, off_t off, int count,
int *eof, void *data);
#endif #endif
/*------------------------- XPD Management -------------------------*/ /*------------------------- XPD Management -------------------------*/
@ -134,16 +138,14 @@ int refcount_xpd(xpd_t *xpd)
xpd_t *get_xpd(const char *msg, xpd_t *xpd) xpd_t *get_xpd(const char *msg, xpd_t *xpd)
{ {
XPD_DBG(DEVICES, xpd, "%s: refcount_xpd=%d\n", XPD_DBG(DEVICES, xpd, "%s: refcount_xpd=%d\n", msg, refcount_xpd(xpd));
msg, refcount_xpd(xpd));
kref_get(&xpd->kref); kref_get(&xpd->kref);
return xpd; return xpd;
} }
void put_xpd(const char *msg, xpd_t *xpd) void put_xpd(const char *msg, xpd_t *xpd)
{ {
XPD_DBG(DEVICES, xpd, "%s: refcount_xpd=%d\n", XPD_DBG(DEVICES, xpd, "%s: refcount_xpd=%d\n", msg, refcount_xpd(xpd));
msg, refcount_xpd(xpd));
kref_put(&xpd->kref, xpd_destroy); kref_put(&xpd->kref, xpd_destroy);
} }
@ -152,7 +154,8 @@ static void xpd_proc_remove(xbus_t *xbus, xpd_t *xpd)
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
if (xpd->proc_xpd_dir) { if (xpd->proc_xpd_dir) {
if (xpd->proc_xpd_summary) { if (xpd->proc_xpd_summary) {
XPD_DBG(PROC, xpd, "Removing proc '%s'\n", PROC_XPD_SUMMARY); XPD_DBG(PROC, xpd, "Removing proc '%s'\n",
PROC_XPD_SUMMARY);
remove_proc_entry(PROC_XPD_SUMMARY, xpd->proc_xpd_dir); remove_proc_entry(PROC_XPD_SUMMARY, xpd->proc_xpd_dir);
xpd->proc_xpd_summary = NULL; xpd->proc_xpd_summary = NULL;
} }
@ -173,10 +176,12 @@ static int xpd_proc_create(xbus_t *xbus, xpd_t *xpd)
XPD_ERR(xpd, "Failed to create proc directory\n"); XPD_ERR(xpd, "Failed to create proc directory\n");
goto err; goto err;
} }
xpd->proc_xpd_summary = create_proc_read_entry(PROC_XPD_SUMMARY, 0444, xpd->proc_xpd_dir, xpd->proc_xpd_summary =
create_proc_read_entry(PROC_XPD_SUMMARY, 0444, xpd->proc_xpd_dir,
xpd_read_proc, xpd); xpd_read_proc, xpd);
if (!xpd->proc_xpd_summary) { if (!xpd->proc_xpd_summary) {
XPD_ERR(xpd, "Failed to create proc file '%s'\n", PROC_XPD_SUMMARY); XPD_ERR(xpd, "Failed to create proc file '%s'\n",
PROC_XPD_SUMMARY);
goto err; goto err;
} }
SET_PROC_DIRENTRY_OWNER(xpd->proc_xpd_summary); SET_PROC_DIRENTRY_OWNER(xpd->proc_xpd_summary);
@ -217,14 +222,9 @@ void xpd_free(xpd_t *xpd)
* Synchronous part of XPD detection. * Synchronous part of XPD detection.
* Called from new_card() * Called from new_card()
*/ */
int create_xpd(xbus_t *xbus, const xproto_table_t *proto_table, int create_xpd(xbus_t *xbus, const xproto_table_t *proto_table, int unit,
int unit, int subunit, __u8 type, __u8 subtype, int subunits,
int subunit, int subunit_ports, __u8 port_dir)
__u8 type,
__u8 subtype,
int subunits,
int subunit_ports,
__u8 port_dir)
{ {
xpd_t *xpd = NULL; xpd_t *xpd = NULL;
bool to_phone; bool to_phone;
@ -234,8 +234,7 @@ int create_xpd(xbus_t *xbus, const xproto_table_t *proto_table,
BUG_ON(!xbus); BUG_ON(!xbus);
xpd = xpd_byaddr(xbus, unit, subunit); xpd = xpd_byaddr(xbus, unit, subunit);
if (xpd) { if (xpd) {
XPD_NOTICE(xpd, "XPD at %d%d already exists\n", XPD_NOTICE(xpd, "XPD at %d%d already exists\n", unit, subunit);
unit, subunit);
return 0; return 0;
} }
if (subunit_ports <= 0 || subunit_ports > CHANNELS_PERXPD) { if (subunit_ports <= 0 || subunit_ports > CHANNELS_PERXPD) {
@ -243,10 +242,14 @@ int create_xpd(xbus_t *xbus, const xproto_table_t *proto_table,
subunit_ports, unit, subunit); subunit_ports, unit, subunit);
return 0; return 0;
} }
xpd = proto_table->xops->card_new(xbus, unit, subunit, proto_table, subtype, subunits, subunit_ports, to_phone); xpd =
proto_table->xops->card_new(xbus, unit, subunit, proto_table,
subtype, subunits, subunit_ports,
to_phone);
if (!xpd) { if (!xpd) {
XBUS_NOTICE(xbus, "card_new(%d,%d,%d,%d,%d) failed. Ignored.\n", XBUS_NOTICE(xbus, "card_new(%d,%d,%d,%d,%d) failed. Ignored.\n",
unit, subunit, proto_table->type, subtype, to_phone); unit, subunit, proto_table->type, subtype,
to_phone);
return -EINVAL; return -EINVAL;
} }
return 0; return 0;
@ -263,7 +266,8 @@ int create_xpd(xbus_t *xbus, const xproto_table_t *proto_table,
* @eof TODO: figure out procfs * @eof TODO: figure out procfs
* @data an xbus_t pointer with the bus data. * @data an xbus_t pointer with the bus data.
*/ */
static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) static int xpd_read_proc(char *page, char **start, off_t off, int count,
int *eof, void *data)
{ {
int len = 0; int len = 0;
xpd_t *xpd = data; xpd_t *xpd = data;
@ -272,34 +276,45 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eo
if (!xpd) if (!xpd)
goto out; goto out;
len += sprintf(page + len, "%s (%s, card %s, span %d)\n" len +=
"timing_priority: %d\n" sprintf(page + len,
"timer_count: %d span->mainttimer=%d\n" "%s (%s, card %s, span %d)\n" "timing_priority: %d\n"
, "timer_count: %d span->mainttimer=%d\n", xpd->xpdname,
xpd->xpdname, xpd->type_name, xpd->type_name, (xpd->card_present) ? "present" : "missing",
(xpd->card_present) ? "present" : "missing",
(SPAN_REGISTERED(xpd)) ? PHONEDEV(xpd).span.spanno : 0, (SPAN_REGISTERED(xpd)) ? PHONEDEV(xpd).span.spanno : 0,
PHONEDEV(xpd).timing_priority, PHONEDEV(xpd).timing_priority, xpd->timer_count,
xpd->timer_count, PHONEDEV(xpd).span.mainttimer PHONEDEV(xpd).span.mainttimer);
); len +=
len += sprintf(page + len, "xpd_state: %s (%d)\n", sprintf(page + len, "xpd_state: %s (%d)\n",
xpd_statename(xpd->xpd_state), xpd->xpd_state); xpd_statename(xpd->xpd_state), xpd->xpd_state);
len += sprintf(page + len, "open_counter=%d refcount=%d\n", len +=
atomic_read(&PHONEDEV(xpd).open_counter), refcount_xpd(xpd)); sprintf(page + len, "open_counter=%d refcount=%d\n",
len += sprintf(page + len, "Address: U=%d S=%d\n", xpd->addr.unit, xpd->addr.subunit); atomic_read(&PHONEDEV(xpd).open_counter),
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, "Subunits: %d\n", xpd->subunits);
len += sprintf(page + len, "Type: %d.%d\n\n", xpd->type, xpd->subtype); len += sprintf(page + len, "Type: %d.%d\n\n", xpd->type, xpd->subtype);
len += sprintf(page + len, "pcm_len=%d\n\n", PHONEDEV(xpd).pcm_len); len += sprintf(page + len, "pcm_len=%d\n\n", PHONEDEV(xpd).pcm_len);
len += sprintf(page + len, "wanted_pcm_mask=0x%04X\n\n", PHONEDEV(xpd).wanted_pcm_mask); len +=
len += sprintf(page + len, "mute_dtmf=0x%04X\n\n", PHONEDEV(xpd).mute_dtmf); sprintf(page + len, "wanted_pcm_mask=0x%04X\n\n",
PHONEDEV(xpd).wanted_pcm_mask);
len +=
sprintf(page + len, "mute_dtmf=0x%04X\n\n",
PHONEDEV(xpd).mute_dtmf);
len += sprintf(page + len, "STATES:"); len += sprintf(page + len, "STATES:");
len += sprintf(page + len, "\n\t%-17s: ", "output_relays"); len += sprintf(page + len, "\n\t%-17s: ", "output_relays");
for_each_line(xpd, i) { for_each_line(xpd, i) {
len += sprintf(page + len, "%d ", IS_SET(PHONEDEV(xpd).digital_outputs, i)); len +=
sprintf(page + len, "%d ",
IS_SET(PHONEDEV(xpd).digital_outputs, i));
} }
len += sprintf(page + len, "\n\t%-17s: ", "input_relays"); len += sprintf(page + len, "\n\t%-17s: ", "input_relays");
for_each_line(xpd, i) { for_each_line(xpd, i) {
len += sprintf(page + len, "%d ", IS_SET(PHONEDEV(xpd).digital_inputs, i)); len +=
sprintf(page + len, "%d ",
IS_SET(PHONEDEV(xpd).digital_inputs, i));
} }
len += sprintf(page + len, "\n\t%-17s: ", "offhook"); len += sprintf(page + len, "\n\t%-17s: ", "offhook");
for_each_line(xpd, i) { for_each_line(xpd, i) {
@ -307,7 +322,9 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eo
} }
len += sprintf(page + len, "\n\t%-17s: ", "oht_pcm_pass"); len += sprintf(page + len, "\n\t%-17s: ", "oht_pcm_pass");
for_each_line(xpd, i) { for_each_line(xpd, i) {
len += sprintf(page + len, "%d ", IS_SET(PHONEDEV(xpd).oht_pcm_pass, i)); len +=
sprintf(page + len, "%d ",
IS_SET(PHONEDEV(xpd).oht_pcm_pass, i));
} }
len += sprintf(page + len, "\n\t%-17s: ", "msg_waiting"); len += sprintf(page + len, "\n\t%-17s: ", "msg_waiting");
for_each_line(xpd, i) { for_each_line(xpd, i) {
@ -319,11 +336,14 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eo
} }
len += sprintf(page + len, "\n\t%-17s: ", "no_pcm"); len += sprintf(page + len, "\n\t%-17s: ", "no_pcm");
for_each_line(xpd, i) { for_each_line(xpd, i) {
len += sprintf(page + len, "%d ", IS_SET(PHONEDEV(xpd).no_pcm, i)); len +=
sprintf(page + len, "%d ", IS_SET(PHONEDEV(xpd).no_pcm, i));
} }
#if 1 #if 1
if (SPAN_REGISTERED(xpd)) { if (SPAN_REGISTERED(xpd)) {
len += sprintf(page + len, "\nPCM:\n | [readchunk] | [writechunk] | W D"); len +=
sprintf(page + len,
"\nPCM:\n | [readchunk] | [writechunk] | W D");
for_each_line(xpd, i) { for_each_line(xpd, i) {
struct dahdi_chan *chan = XPD_CHAN(xpd, i); struct dahdi_chan *chan = XPD_CHAN(xpd, i);
__u8 rchunk[DAHDI_CHUNKSIZE]; __u8 rchunk[DAHDI_CHUNKSIZE];
@ -350,10 +370,14 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eo
for (j = 0; j < DAHDI_CHUNKSIZE; j++) { for (j = 0; j < DAHDI_CHUNKSIZE; j++) {
len += sprintf(page + len, "%02X ", wchunk[j]); len += sprintf(page + len, "%02X ", wchunk[j]);
} }
len += sprintf(page + len, " | %c", len +=
(IS_SET(PHONEDEV(xpd).wanted_pcm_mask, i))?'+':' '); sprintf(page + len, " | %c",
len += sprintf(page + len, " %c", (IS_SET(PHONEDEV(xpd).wanted_pcm_mask, i)) ?
(IS_SET(PHONEDEV(xpd).mute_dtmf, i))?'-':' '); '+' : ' ');
len +=
sprintf(page + len, " %c",
(IS_SET(PHONEDEV(xpd).mute_dtmf, i)) ? '-' :
' ');
} }
} }
#endif #endif
@ -362,18 +386,22 @@ static int xpd_read_proc(char *page, char **start, off_t off, int count, int *eo
len += sprintf(page + len, "\nSignalling:\n"); len += sprintf(page + len, "\nSignalling:\n");
for_each_line(xpd, i) { for_each_line(xpd, i) {
struct dahdi_chan *chan = XPD_CHAN(xpd, i); struct dahdi_chan *chan = XPD_CHAN(xpd, i);
len += sprintf(page + len, "\t%2d> sigcap=0x%04X sig=0x%04X\n", i, chan->sigcap, chan->sig); len +=
sprintf(page + len,
"\t%2d> sigcap=0x%04X sig=0x%04X\n", i,
chan->sigcap, chan->sig);
} }
} }
#endif #endif
len += sprintf(page + len, "\nCOUNTERS:\n"); len += sprintf(page + len, "\nCOUNTERS:\n");
for (i = 0; i < XPD_COUNTER_MAX; i++) { for (i = 0; i < XPD_COUNTER_MAX; i++) {
len += sprintf(page + len, "\t\t%-20s = %d\n", len +=
sprintf(page + len, "\t\t%-20s = %d\n",
xpd_counters[i].name, xpd->counters[i]); xpd_counters[i].name, xpd->counters[i]);
} }
len += sprintf(page + len, "<-- len=%d\n", len); len += sprintf(page + len, "<-- len=%d\n", len);
out: out:
if (len <= off+count) if (len <= off + count)
*eof = 1; *eof = 1;
*start = page + off; *start = page + off;
len -= off; len -= off;
@ -390,10 +418,14 @@ out:
const char *xpd_statename(enum xpd_state st) const char *xpd_statename(enum xpd_state st)
{ {
switch (st) { switch (st) {
case XPD_STATE_START: return "START"; case XPD_STATE_START:
case XPD_STATE_INIT_REGS: return "INIT_REGS"; return "START";
case XPD_STATE_READY: return "READY"; case XPD_STATE_INIT_REGS:
case XPD_STATE_NOHW: return "NOHW"; return "INIT_REGS";
case XPD_STATE_READY:
return "READY";
case XPD_STATE_NOHW:
return "NOHW";
} }
return NULL; return NULL;
} }
@ -435,14 +467,12 @@ bool xpd_setstate(xpd_t *xpd, enum xpd_state newstate)
xpd->xpd_state = newstate; xpd->xpd_state = newstate;
return 1; return 1;
badstate: badstate:
XPD_NOTICE(xpd, "%s: cannot transition: %s (%d) -> %s (%d)\n", XPD_NOTICE(xpd, "%s: cannot transition: %s (%d) -> %s (%d)\n", __func__,
__func__,
xpd_statename(xpd->xpd_state), xpd->xpd_state, xpd_statename(xpd->xpd_state), xpd->xpd_state,
xpd_statename(newstate), newstate); xpd_statename(newstate), newstate);
return 0; return 0;
} }
/* /*
* Cleanup/initialize phonedev * Cleanup/initialize phonedev
*/ */
@ -460,7 +490,8 @@ static void phonedev_cleanup(xpd_t *xpd)
} }
} }
__must_check static int phonedev_init(xpd_t *xpd, const xproto_table_t *proto_table, __must_check static int phonedev_init(xpd_t *xpd,
const xproto_table_t *proto_table,
int channels, xpp_line_t no_pcm) int channels, xpp_line_t no_pcm)
{ {
struct phonedev *phonedev = &PHONEDEV(xpd); struct phonedev *phonedev = &PHONEDEV(xpd);
@ -476,12 +507,14 @@ __must_check static int phonedev_init(xpd_t *xpd, const xproto_table_t *proto_ta
atomic_set(&phonedev->dahdi_registered, 0); atomic_set(&phonedev->dahdi_registered, 0);
atomic_set(&phonedev->open_counter, 0); atomic_set(&phonedev->open_counter, 0);
for (x = 0; x < phonedev->channels; x++) { for (x = 0; x < phonedev->channels; x++) {
if (!(phonedev->chans[x] = KZALLOC(sizeof(*(phonedev->chans[x])), GFP_KERNEL))) { if (!
(phonedev->chans[x] =
KZALLOC(sizeof(*(phonedev->chans[x])), GFP_KERNEL))) {
ERR("%s: Unable to allocate channel %d\n", __func__, x); ERR("%s: Unable to allocate channel %d\n", __func__, x);
goto err; goto err;
} }
phonedev->ec[x] = KZALLOC(sizeof(*(phonedev->ec[x])), phonedev->ec[x] =
GFP_KERNEL); KZALLOC(sizeof(*(phonedev->ec[x])), GFP_KERNEL);
if (!phonedev->ec[x]) { if (!phonedev->ec[x]) {
ERR("%s: Unable to allocate ec state %d\n", __func__, ERR("%s: Unable to allocate ec state %d\n", __func__,
x); x);
@ -498,10 +531,9 @@ err:
* xpd_alloc - Allocator for new XPD's * xpd_alloc - Allocator for new XPD's
* *
*/ */
__must_check xpd_t *xpd_alloc(xbus_t *xbus, __must_check xpd_t *xpd_alloc(xbus_t *xbus, int unit, int subunit, int subtype,
int unit, int subunit, int subunits, size_t privsize,
int subtype, int subunits, const xproto_table_t *proto_table, int channels)
size_t privsize, const xproto_table_t *proto_table, int channels)
{ {
xpd_t *xpd = NULL; xpd_t *xpd = NULL;
size_t alloc_size = sizeof(xpd_t) + privsize; size_t alloc_size = sizeof(xpd_t) + privsize;
@ -509,11 +541,11 @@ __must_check xpd_t *xpd_alloc(xbus_t *xbus,
xpp_line_t no_pcm = 0; xpp_line_t no_pcm = 0;
BUG_ON(!proto_table); BUG_ON(!proto_table);
XBUS_DBG(DEVICES, xbus, "type=%d channels=%d (alloc_size=%zd)\n", XBUS_DBG(DEVICES, xbus, "type=%d channels=%d (alloc_size=%zd)\n", type,
type, channels, alloc_size); channels, alloc_size);
if (channels > CHANNELS_PERXPD) { if (channels > CHANNELS_PERXPD) {
XBUS_ERR(xbus, "%s: type=%d: too many channels %d\n", XBUS_ERR(xbus, "%s: type=%d: too many channels %d\n", __func__,
__func__, type, channels); type, channels);
goto err; goto err;
} }
@ -535,8 +567,11 @@ __must_check xpd_t *xpd_alloc(xbus_t *xbus,
/* For USB-1 disable some channels */ /* For USB-1 disable some channels */
if (MAX_SEND_SIZE(xbus) < RPACKET_SIZE(GLOBAL, PCM_WRITE)) { if (MAX_SEND_SIZE(xbus) < RPACKET_SIZE(GLOBAL, PCM_WRITE)) {
no_pcm = 0x7F | PHONEDEV(xpd).digital_outputs | PHONEDEV(xpd).digital_inputs; no_pcm =
XBUS_NOTICE(xbus, "max xframe size = %d, disabling some PCM channels. no_pcm=0x%04X\n", 0x7F | PHONEDEV(xpd).digital_outputs | PHONEDEV(xpd).
digital_inputs;
XBUS_NOTICE(xbus,
"max xframe size = %d, disabling some PCM channels. no_pcm=0x%04X\n",
MAX_SEND_SIZE(xbus), PHONEDEV(xpd).no_pcm); MAX_SEND_SIZE(xbus), PHONEDEV(xpd).no_pcm);
} }
if (phonedev_init(xpd, proto_table, channels, no_pcm) < 0) if (phonedev_init(xpd, proto_table, channels, no_pcm) < 0)
@ -589,7 +624,8 @@ void update_xpd_status(xpd_t *xpd, int alarm_flag)
} }
if (span->alarms == alarm_flag) if (span->alarms == alarm_flag)
return; return;
XPD_DBG(GENERAL, xpd, "Update XPD alarms: %s -> %02X\n", PHONEDEV(xpd).span.name, alarm_flag); XPD_DBG(GENERAL, xpd, "Update XPD alarms: %s -> %02X\n",
PHONEDEV(xpd).span.name, alarm_flag);
span->alarms = alarm_flag; span->alarms = alarm_flag;
dahdi_alarm_notify(span); dahdi_alarm_notify(span);
} }
@ -661,14 +697,14 @@ void hookstate_changed(xpd_t *xpd, int pos, bool to_offhook)
*/ */
BIT_SET(PHONEDEV(xpd).silence_pcm, pos); BIT_SET(PHONEDEV(xpd).silence_pcm, pos);
} }
notify_rxsig(xpd, pos, (to_offhook) ? DAHDI_RXSIG_OFFHOOK : DAHDI_RXSIG_ONHOOK); notify_rxsig(xpd, pos,
(to_offhook) ? DAHDI_RXSIG_OFFHOOK : DAHDI_RXSIG_ONHOOK);
} }
#define XPP_MAX_LEN 512 #define XPP_MAX_LEN 512
/*------------------------- Dahdi Interfaces -----------------------*/ /*------------------------- Dahdi Interfaces -----------------------*/
/* /*
* Called from dahdi with spinlock held on chan. Must not call back * Called from dahdi with spinlock held on chan. Must not call back
* dahdi functions. * dahdi functions.
@ -701,9 +737,8 @@ int xpp_open(struct dahdi_chan *chan)
} }
spin_lock_irqsave(&xbus->lock, flags); spin_lock_irqsave(&xbus->lock, flags);
atomic_inc(&PHONEDEV(xpd).open_counter); atomic_inc(&PHONEDEV(xpd).open_counter);
LINE_DBG(DEVICES, xpd, pos, "%s[%d]: open_counter=%d\n", LINE_DBG(DEVICES, xpd, pos, "%s[%d]: open_counter=%d\n", current->comm,
current->comm, current->pid, current->pid, atomic_read(&PHONEDEV(xpd).open_counter));
atomic_read(&PHONEDEV(xpd).open_counter));
spin_unlock_irqrestore(&xbus->lock, flags); spin_unlock_irqrestore(&xbus->lock, flags);
if (PHONE_METHOD(card_open, xpd)) if (PHONE_METHOD(card_open, xpd))
CALL_PHONE_METHOD(card_open, xpd, pos); CALL_PHONE_METHOD(card_open, xpd, pos);
@ -721,9 +756,8 @@ int xpp_close(struct dahdi_chan *chan)
spin_unlock_irqrestore(&xbus->lock, flags); spin_unlock_irqrestore(&xbus->lock, flags);
if (PHONE_METHOD(card_close, xpd)) if (PHONE_METHOD(card_close, xpd))
CALL_PHONE_METHOD(card_close, xpd, pos); CALL_PHONE_METHOD(card_close, xpd, pos);
LINE_DBG(DEVICES, xpd, pos, "%s[%d]: open_counter=%d\n", LINE_DBG(DEVICES, xpd, pos, "%s[%d]: open_counter=%d\n", current->comm,
current->comm, current->pid, current->pid, atomic_read(&PHONEDEV(xpd).open_counter));
atomic_read(&PHONEDEV(xpd).open_counter));
atomic_dec(&PHONEDEV(xpd).open_counter); /* from xpp_open() */ atomic_dec(&PHONEDEV(xpd).open_counter); /* from xpp_open() */
return 0; return 0;
} }
@ -756,7 +790,8 @@ int xpp_ioctl(struct dahdi_chan *chan, unsigned int cmd, unsigned long arg)
default: default:
/* Some span-specific commands before we give up: */ /* Some span-specific commands before we give up: */
if (PHONE_METHOD(card_ioctl, xpd)) { if (PHONE_METHOD(card_ioctl, xpd)) {
return CALL_PHONE_METHOD(card_ioctl, xpd, pos, cmd, arg); return CALL_PHONE_METHOD(card_ioctl, xpd, pos, cmd,
arg);
} }
report_bad_ioctl(THIS_MODULE->name, xpd, pos, cmd); report_bad_ioctl(THIS_MODULE->name, xpd, pos, cmd);
return -ENOTTY; return -ENOTTY;
@ -783,9 +818,11 @@ int xpp_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig)
} }
xbus = xpd->xbus; xbus = xpd->xbus;
BUG_ON(!xbus); BUG_ON(!xbus);
DBG(SIGNAL, "Setting %s to %s (%d)\n", chan->name, txsig2str(txsig), txsig); DBG(SIGNAL, "Setting %s to %s (%d)\n", chan->name, txsig2str(txsig),
txsig);
return CALL_PHONE_METHOD(card_hooksig, xpd, pos, txsig); return CALL_PHONE_METHOD(card_hooksig, xpd, pos, txsig);
} }
EXPORT_SYMBOL(xpp_hooksig); EXPORT_SYMBOL(xpp_hooksig);
/* Req: Set the requested chunk size. This is the unit in which you must /* Req: Set the requested chunk size. This is the unit in which you must
@ -893,16 +930,13 @@ const char *xpp_echocan_name(const struct dahdi_chan *chan)
* quirks and limitations * quirks and limitations
*/ */
if (xbus->quirks.has_fxo) { if (xbus->quirks.has_fxo) {
if ( if (xbus->quirks.has_digital_span && xpd->type == XPD_TYPE_FXO) {
xbus->quirks.has_digital_span &&
xpd->type == XPD_TYPE_FXO) {
LINE_NOTICE(xpd, pos, LINE_NOTICE(xpd, pos,
"quirk: give up HWEC on FXO: " "quirk: give up HWEC on FXO: "
"AB has digital span\n"); "AB has digital span\n");
return NULL; return NULL;
} else if ( } else if (xbus->sync_mode != SYNC_MODE_AB
xbus->sync_mode != SYNC_MODE_AB && && xpd->type == XPD_TYPE_FXS) {
xpd->type == XPD_TYPE_FXS) {
LINE_NOTICE(xpd, pos, LINE_NOTICE(xpd, pos,
"quirk: give up HWEC on FXS: " "quirk: give up HWEC on FXS: "
"AB has FXO and is sync slave\n"); "AB has FXO and is sync slave\n");
@ -911,10 +945,10 @@ const char *xpp_echocan_name(const struct dahdi_chan *chan)
} }
return "XPP"; return "XPP";
} }
EXPORT_SYMBOL(xpp_echocan_name); EXPORT_SYMBOL(xpp_echocan_name);
int xpp_echocan_create(struct dahdi_chan *chan, int xpp_echocan_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp,
struct dahdi_echocanparams *ecp,
struct dahdi_echocanparam *p, struct dahdi_echocanparam *p,
struct dahdi_echocan_state **ec) struct dahdi_echocan_state **ec)
{ {
@ -942,6 +976,7 @@ int xpp_echocan_create(struct dahdi_chan *chan,
CALL_EC_METHOD(ec_update, xbus, xbus); CALL_EC_METHOD(ec_update, xbus, xbus);
return ret; return ret;
} }
EXPORT_SYMBOL(xpp_echocan_create); EXPORT_SYMBOL(xpp_echocan_create);
void xpp_span_assigned(struct dahdi_span *span) void xpp_span_assigned(struct dahdi_span *span)
@ -955,6 +990,7 @@ void xpp_span_assigned(struct dahdi_span *span)
dahdi_alarm_notify(&phonedev->span); dahdi_alarm_notify(&phonedev->span);
} }
} }
EXPORT_SYMBOL(xpp_span_assigned); EXPORT_SYMBOL(xpp_span_assigned);
static const struct dahdi_span_ops xpp_span_ops = { static const struct dahdi_span_ops xpp_span_ops = {
@ -984,7 +1020,8 @@ void xpd_set_spanname(xpd_t *xpd)
{ {
struct dahdi_span *span = &PHONEDEV(xpd).span; struct dahdi_span *span = &PHONEDEV(xpd).span;
snprintf(span->name, MAX_SPANNAME, "%s/%s", xpd->xbus->busname, xpd->xpdname); snprintf(span->name, MAX_SPANNAME, "%s/%s", xpd->xbus->busname,
xpd->xpdname);
/* /*
* The "Xorcom XPD" is a prefix in one of the regexes we * The "Xorcom XPD" is a prefix in one of the regexes we
* use in our dahdi_genconf to match for PRI cards. * use in our dahdi_genconf to match for PRI cards.
@ -994,6 +1031,7 @@ void xpd_set_spanname(xpd_t *xpd)
snprintf(span->desc, MAX_SPANDESC, "Xorcom XPD [%s].%d: %s", snprintf(span->desc, MAX_SPANDESC, "Xorcom XPD [%s].%d: %s",
xpd->xbus->label, span->offset + 1, xpd->type_name); xpd->xbus->label, span->offset + 1, xpd->type_name);
} }
EXPORT_SYMBOL(xpd_set_spanname); EXPORT_SYMBOL(xpd_set_spanname);
static void xpd_init_span(xpd_t *xpd, unsigned offset, int cn) static void xpd_init_span(xpd_t *xpd, unsigned offset, int cn)
@ -1093,9 +1131,11 @@ void xpd_dahdi_preunregister(xpd_t *xpd)
int j; int j;
dahdi_alarm_notify(&PHONEDEV(xpd).span); dahdi_alarm_notify(&PHONEDEV(xpd).span);
XPD_DBG(DEVICES, xpd, "Queuing DAHDI_EVENT_REMOVED on all channels to ask user to release them\n"); XPD_DBG(DEVICES, xpd,
for (j=0; j<PHONEDEV(xpd).span.channels; j++) { "Queuing DAHDI_EVENT_REMOVED on all channels to ask user to release them\n");
dahdi_qevent_lock(XPD_CHAN(xpd, j), DAHDI_EVENT_REMOVED); for (j = 0; j < PHONEDEV(xpd).span.channels; j++) {
dahdi_qevent_lock(XPD_CHAN(xpd, j),
DAHDI_EVENT_REMOVED);
} }
} }
} }
@ -1128,8 +1168,8 @@ static int __init xpp_dahdi_init(void)
int ret = 0; int ret = 0;
void *top = NULL; void *top = NULL;
INFO("revision %s MAX_XPDS=%d (%d*%d)\n", XPP_VERSION, INFO("revision %s MAX_XPDS=%d (%d*%d)\n", XPP_VERSION, MAX_XPDS,
MAX_XPDS, MAX_UNIT, MAX_SUBUNIT); MAX_UNIT, MAX_SUBUNIT);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
xpp_proc_toplevel = proc_mkdir(PROC_DIR, NULL); xpp_proc_toplevel = proc_mkdir(PROC_DIR, NULL);
if (!xpp_proc_toplevel) { if (!xpp_proc_toplevel) {

View File

@ -30,15 +30,17 @@ int xpd_dahdi_preregister(xpd_t *xpd, unsigned offset);
int xpd_dahdi_postregister(xpd_t *xpd); int xpd_dahdi_postregister(xpd_t *xpd);
void xpd_dahdi_preunregister(xpd_t *xpd); void xpd_dahdi_preunregister(xpd_t *xpd);
void xpd_dahdi_postunregister(xpd_t *xpd); void xpd_dahdi_postunregister(xpd_t *xpd);
int create_xpd(xbus_t *xbus, const xproto_table_t *proto_table, int create_xpd(xbus_t *xbus, const xproto_table_t *proto_table, int unit,
int unit, int subunit, __u8 type, __u8 subtype, int subunits, int subunit_ports, __u8 port_dir); int subunit, __u8 type, __u8 subtype, int subunits,
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); int subunit_ports, __u8 port_dir);
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_free(xpd_t *xpd);
void xpd_remove(xpd_t *xpd); void xpd_remove(xpd_t *xpd);
void update_xpd_status(xpd_t *xpd, int alarm_flag); void update_xpd_status(xpd_t *xpd, int alarm_flag);
const char *xpp_echocan_name(const struct dahdi_chan *chan); const char *xpp_echocan_name(const struct dahdi_chan *chan);
int xpp_echocan_create(struct dahdi_chan *chan, int xpp_echocan_create(struct dahdi_chan *chan, struct dahdi_echocanparams *ecp,
struct dahdi_echocanparams *ecp,
struct dahdi_echocanparam *p, struct dahdi_echocanparam *p,
struct dahdi_echocan_state **ec); struct dahdi_echocan_state **ec);
void hookstate_changed(xpd_t *xpd, int pos, bool good); void hookstate_changed(xpd_t *xpd, int pos, bool good);

View File

@ -47,11 +47,11 @@ static const char rcsid[] = "$Id$";
static DEF_PARM(int, debug, 0, 0644, "Print DBG statements"); /* must be before dahdi_debug.h */ static DEF_PARM(int, debug, 0, 0644, "Print DBG statements"); /* must be before dahdi_debug.h */
static DEF_PARM(int, usb1, 0, 0644, "Allow using USB 1.1 interfaces"); static DEF_PARM(int, usb1, 0, 0644, "Allow using USB 1.1 interfaces");
static DEF_PARM(uint, tx_sluggish, 2000, 0644, "A sluggish transmit (usec)"); static DEF_PARM(uint, tx_sluggish, 2000, 0644, "A sluggish transmit (usec)");
static DEF_PARM(uint, drop_pcm_after, 6, 0644, "Number of consecutive tx_sluggish to drop a PCM frame"); static DEF_PARM(uint, drop_pcm_after, 6, 0644,
"Number of consecutive tx_sluggish to drop a PCM frame");
#include "dahdi_debug.h" #include "dahdi_debug.h"
#define XUSB_PRINTK(level, xusb, fmt, ...) \ #define XUSB_PRINTK(level, xusb, fmt, ...) \
printk(KERN_ ## level "%s-%s: xusb-%d (%s) [%s]: " fmt, #level, \ printk(KERN_ ## level "%s-%s: xusb-%d (%s) [%s]: " fmt, #level, \
THIS_MODULE->name, (xusb)->index, xusb->path, xusb->serial, ## __VA_ARGS__) THIS_MODULE->name, (xusb)->index, xusb->path, xusb->serial, ## __VA_ARGS__)
@ -65,7 +65,7 @@ static DEF_PARM(uint, drop_pcm_after, 6, 0644, "Number of consecutive tx_sluggis
/* FIXME: A flag that was deprecated at some point, and rather useless */ /* FIXME: A flag that was deprecated at some point, and rather useless */
/* anyway. Only used in the code or-ed to other flags */ /* anyway. Only used in the code or-ed to other flags */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 14)
# define URB_ASYNC_UNLINK 0 #define URB_ASYNC_UNLINK 0
#endif #endif
/* Get a minor range for your devices from the usb maintainer */ /* Get a minor range for your devices from the usb maintainer */
#define USB_SKEL_MINOR_BASE 192 #define USB_SKEL_MINOR_BASE 192
@ -75,23 +75,23 @@ static DEF_PARM(uint, drop_pcm_after, 6, 0644, "Number of consecutive tx_sluggis
#endif #endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 0)
# warning "This module is tested only with 2.6 kernels" #warning "This module is tested only with 2.6 kernels"
#endif #endif
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34) #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 34)
# define usb_alloc_coherent(dev, size, mem_flags, dma) \ #define usb_alloc_coherent(dev, size, mem_flags, dma) \
usb_buffer_alloc(dev, size, mem_flags, dma) usb_buffer_alloc(dev, size, mem_flags, dma)
# define usb_free_coherent(dev, size, addr, dma) \ #define usb_free_coherent(dev, size, addr, dma) \
usb_buffer_free(dev, size, addr, dma) usb_buffer_free(dev, size, addr, dma)
#endif #endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12) #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12)
# undef USB_FIELDS_MISSING #undef USB_FIELDS_MISSING
#else #else
# define USB_FIELDS_MISSING #define USB_FIELDS_MISSING
# define USB_MAX_STRING 128 #define USB_MAX_STRING 128
# define USB_GET_STRING(udev, field, buf) \ #define USB_GET_STRING(udev, field, buf) \
do { \ do { \
if ((udev)->descriptor.field) { \ if ((udev)->descriptor.field) { \
char tmp[USB_MAX_STRING]; \ char tmp[USB_MAX_STRING]; \
@ -99,7 +99,7 @@ static DEF_PARM(uint, drop_pcm_after, 6, 0644, "Number of consecutive tx_sluggis
snprintf((buf), USB_MAX_STRING, "%s", tmp); \ snprintf((buf), USB_MAX_STRING, "%s", tmp); \
} \ } \
} while (0); } while (0);
# define USB_GET_IFACE_NAME(udev, iface, buf) \ #define USB_GET_IFACE_NAME(udev, iface, buf) \
do { \ do { \
if ((iface)->desc.iInterface) { \ if ((iface)->desc.iInterface) { \
char tmp[USB_MAX_STRING]; \ char tmp[USB_MAX_STRING]; \
@ -154,12 +154,8 @@ enum {
static struct xusb_counters { static struct xusb_counters {
char *name; char *name;
} xusb_counters[] = { } xusb_counters[] = {
C_(RX_FRAMES), C_(RX_FRAMES), C_(TX_FRAMES), C_(RX_ERRORS), C_(TX_ERRORS),
C_(TX_FRAMES), C_(RCV_ZERO_LEN),};
C_(RX_ERRORS),
C_(TX_ERRORS),
C_(RCV_ZERO_LEN),
};
#undef C_ #undef C_
@ -242,9 +238,9 @@ struct xusb {
}; };
static DEFINE_SPINLOCK(xusb_lock); static DEFINE_SPINLOCK(xusb_lock);
static xusb_t *xusb_array[MAX_BUSES] = {}; static xusb_t *xusb_array[MAX_BUSES] = { };
static unsigned bus_count;
static unsigned bus_count;
/* prevent races between open() and disconnect() */ /* prevent races between open() and disconnect() */
static DEFINE_SEMAPHORE(disconnect_sem); static DEFINE_SEMAPHORE(disconnect_sem);
@ -263,10 +259,12 @@ static DEFINE_SEMAPHORE(disconnect_sem);
static void xpp_send_callback(USB_PASS_CB(urb)); static void xpp_send_callback(USB_PASS_CB(urb));
static void xpp_receive_callback(USB_PASS_CB(urb)); static void xpp_receive_callback(USB_PASS_CB(urb));
static int xusb_probe (struct usb_interface *interface, const struct usb_device_id *id); static int xusb_probe(struct usb_interface *interface,
static void xusb_disconnect (struct usb_interface *interface); const struct usb_device_id *id);
static void xusb_disconnect(struct usb_interface *interface);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
static int xusb_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data); static int xusb_read_proc(char *page, char **start, off_t off, int count,
int *eof, void *data);
#endif #endif
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
@ -288,7 +286,8 @@ static void uframe_recompute(struct uframe *uframe, enum xusb_dir dir)
: usb_sndbulkpipe(udev, epnum); : usb_sndbulkpipe(udev, epnum);
BUG_ON(uframe->uframe_magic != UFRAME_MAGIC); BUG_ON(uframe->uframe_magic != UFRAME_MAGIC);
usb_fill_bulk_urb(urb, udev, pipe, uframe->transfer_buffer, uframe->transfer_buffer_length, urb_cb, uframe); usb_fill_bulk_urb(urb, udev, pipe, uframe->transfer_buffer,
uframe->transfer_buffer_length, urb_cb, uframe);
urb->transfer_flags = (URB_NO_TRANSFER_DMA_MAP | URB_ASYNC_UNLINK); urb->transfer_flags = (URB_NO_TRANSFER_DMA_MAP | URB_ASYNC_UNLINK);
} }
@ -306,21 +305,27 @@ static xframe_t *alloc_xframe(xbus_t *xbus, gfp_t gfp_flags)
if (!xusb->present) { if (!xusb->present) {
if ((rate_limit++ % 1003) == 0) if ((rate_limit++ % 1003) == 0)
XUSB_ERR(xusb, XUSB_ERR(xusb,
"abort allocations during device disconnect (%d)\n", rate_limit); "abort allocations during device disconnect (%d)\n",
rate_limit);
return NULL; return NULL;
} }
size = min(xusb->endpoints[XUSB_SEND].max_size, xusb->endpoints[XUSB_RECV].max_size); size =
min(xusb->endpoints[XUSB_SEND].max_size,
xusb->endpoints[XUSB_RECV].max_size);
uframe = kmem_cache_alloc(xusb_cache, gfp_flags); uframe = kmem_cache_alloc(xusb_cache, gfp_flags);
if (!uframe) { if (!uframe) {
if ((rate_limit++ % 1003) == 0) if ((rate_limit++ % 1003) == 0)
XUSB_ERR(xusb, "frame allocation failed (%d)\n", rate_limit); XUSB_ERR(xusb, "frame allocation failed (%d)\n",
rate_limit);
return NULL; return NULL;
} }
usb_init_urb(&uframe->urb); usb_init_urb(&uframe->urb);
p = usb_alloc_coherent(xusb->udev, size, gfp_flags, &uframe->urb.transfer_dma); p = usb_alloc_coherent(xusb->udev, size, gfp_flags,
&uframe->urb.transfer_dma);
if (!p) { if (!p) {
if ((rate_limit++ % 1003) == 0) if ((rate_limit++ % 1003) == 0)
XUSB_ERR(xusb, "buffer allocation failed (%d)\n", rate_limit); XUSB_ERR(xusb, "buffer allocation failed (%d)\n",
rate_limit);
kmem_cache_free(xusb_cache, uframe); kmem_cache_free(xusb_cache, uframe);
return NULL; return NULL;
} }
@ -328,7 +333,8 @@ static xframe_t *alloc_xframe(xbus_t *xbus, gfp_t gfp_flags)
uframe->transfer_buffer_length = size; uframe->transfer_buffer_length = size;
uframe->transfer_buffer = p; uframe->transfer_buffer = p;
uframe->xusb = xusb; uframe->xusb = xusb;
xframe_init(xbus, &uframe->xframe, uframe->transfer_buffer, uframe->transfer_buffer_length, uframe); xframe_init(xbus, &uframe->xframe, uframe->transfer_buffer,
uframe->transfer_buffer_length, uframe);
return &uframe->xframe; return &uframe->xframe;
} }
@ -340,8 +346,7 @@ static void free_xframe(xbus_t *xbus, xframe_t *xframe)
BUG_ON(xbus->transport.priv != uframe->xusb); BUG_ON(xbus->transport.priv != uframe->xusb);
//XUSB_INFO(uframe->xusb, "frame_free\n"); //XUSB_INFO(uframe->xusb, "frame_free\n");
usb_free_coherent(urb->dev, uframe->transfer_buffer_length, usb_free_coherent(urb->dev, uframe->transfer_buffer_length,
urb->transfer_buffer, urb->transfer_buffer, urb->transfer_dma);
urb->transfer_dma);
memset(uframe, 0, sizeof(*uframe)); memset(uframe, 0, sizeof(*uframe));
kmem_cache_free(xusb_cache, uframe); kmem_cache_free(xusb_cache, uframe);
} }
@ -367,7 +372,8 @@ static int do_send_xframe(xbus_t *xbus, xframe_t *xframe)
if ((rate_limit++ % 1003) == 0) if ((rate_limit++ % 1003) == 0)
XUSB_ERR(xusb, XUSB_ERR(xusb,
"abort do_send_xframe during device disconnect (%d)\n", rate_limit); "abort do_send_xframe during device disconnect (%d)\n",
rate_limit);
ret = -ENODEV; ret = -ENODEV;
goto failure; goto failure;
} }
@ -490,24 +496,20 @@ static const struct xusb_model_info {
struct xusb_endpoint out; struct xusb_endpoint out;
} model_table[] = { } model_table[] = {
[MODEL_FPGA_XPD] = { [MODEL_FPGA_XPD] = {
.iface_num = 0, .iface_num = 0,.in = {
.in = { .ep_addr = 0x86 }, .ep_addr = 0x86},.out = {
.out = { .ep_addr = 0x02 }, .ep_addr = 0x02},.desc = "FPGA_XPD"},};
.desc = "FPGA_XPD"
},
};
/* table of devices that work with this driver */ /* table of devices that work with this driver */
static const struct usb_device_id xusb_table [] = { static const struct usb_device_id xusb_table[] = {
{ USB_DEVICE(0xE4E4, 0x1132), .driver_info=(kernel_ulong_t)&model_table[MODEL_FPGA_XPD] }, // FPGA_FXS {USB_DEVICE(0xE4E4, 0x1132),.driver_info = (kernel_ulong_t) & model_table[MODEL_FPGA_XPD]}, // FPGA_FXS
{ USB_DEVICE(0xE4E4, 0x1142), .driver_info=(kernel_ulong_t)&model_table[MODEL_FPGA_XPD] }, // FPGA_1141 {USB_DEVICE(0xE4E4, 0x1142),.driver_info = (kernel_ulong_t) & model_table[MODEL_FPGA_XPD]}, // FPGA_1141
{ USB_DEVICE(0xE4E4, 0x1152), .driver_info=(kernel_ulong_t)&model_table[MODEL_FPGA_XPD] }, // FPGA_1151 {USB_DEVICE(0xE4E4, 0x1152),.driver_info = (kernel_ulong_t) & model_table[MODEL_FPGA_XPD]}, // FPGA_1151
{ USB_DEVICE(0xE4E4, 0x1162), .driver_info=(kernel_ulong_t)&model_table[MODEL_FPGA_XPD] }, // FPGA_1161 {USB_DEVICE(0xE4E4, 0x1162),.driver_info = (kernel_ulong_t) & model_table[MODEL_FPGA_XPD]}, // FPGA_1161
{ } /* Terminating entry */ {} /* Terminating entry */
}; };
MODULE_DEVICE_TABLE (usb, xusb_table); MODULE_DEVICE_TABLE(usb, xusb_table);
/* usb specific object needed to register this driver with the usb subsystem */ /* usb specific object needed to register this driver with the usb subsystem */
static struct usb_driver xusb_driver = { static struct usb_driver xusb_driver = {
@ -568,17 +570,20 @@ static struct usb_class_driver xusb_class = {
*/ */
static int check_usb1(struct usb_endpoint_descriptor *endpoint) static int check_usb1(struct usb_endpoint_descriptor *endpoint)
{ {
const char *msg = (usb_pipein(endpoint->bEndpointAddress))?"input":"output"; const char *msg =
(usb_pipein(endpoint->bEndpointAddress)) ? "input" : "output";
if (endpoint->wMaxPacketSize >= sizeof(xpacket_t)) if (endpoint->wMaxPacketSize >= sizeof(xpacket_t))
return 1; return 1;
if (usb1) { if (usb1) {
NOTICE("USB1 endpoint detected: USB %s endpoint 0x%X support only wMaxPacketSize=%d.\n", NOTICE
("USB1 endpoint detected: USB %s endpoint 0x%X support only wMaxPacketSize=%d.\n",
msg, endpoint->bEndpointAddress, endpoint->wMaxPacketSize); msg, endpoint->bEndpointAddress, endpoint->wMaxPacketSize);
return 1; return 1;
} }
NOTICE("USB1 endpoint detected. Device disabled. To enable: usb1=1, and read docs. (%s, endpoint %d, size %d).\n", NOTICE
("USB1 endpoint detected. Device disabled. To enable: usb1=1, and read docs. (%s, endpoint %d, size %d).\n",
msg, endpoint->bEndpointAddress, endpoint->wMaxPacketSize); msg, endpoint->bEndpointAddress, endpoint->wMaxPacketSize);
return 0; return 0;
} }
@ -588,7 +593,8 @@ static int check_usb1(struct usb_endpoint_descriptor *endpoint)
* check out the endpoints * check out the endpoints
* FIXME: Should be simplified (above 2.6.10) to use usb_dev->ep_in[0..16] and usb_dev->ep_out[0..16] * FIXME: Should be simplified (above 2.6.10) to use usb_dev->ep_in[0..16] and usb_dev->ep_out[0..16]
*/ */
static int set_endpoints(xusb_t *xusb, struct usb_host_interface *iface_desc, struct xusb_model_info *model_info) static int set_endpoints(xusb_t *xusb, struct usb_host_interface *iface_desc,
struct xusb_model_info *model_info)
{ {
struct usb_endpoint_descriptor *endpoint; struct usb_endpoint_descriptor *endpoint;
struct xusb_endpoint *xusb_ep; struct xusb_endpoint *xusb_ep;
@ -602,7 +608,8 @@ static int set_endpoints(xusb_t *xusb, struct usb_host_interface *iface_desc, st
ep_addr = endpoint->bEndpointAddress; ep_addr = endpoint->bEndpointAddress;
if (!BULK_ENDPOINT(endpoint)) { if (!BULK_ENDPOINT(endpoint)) {
DBG(DEVICES, "endpoint 0x%x is not bulk: mbAttributes=0x%X\n", DBG(DEVICES,
"endpoint 0x%x is not bulk: mbAttributes=0x%X\n",
ep_addr, endpoint->bmAttributes); ep_addr, endpoint->bmAttributes);
continue; continue;
} }
@ -626,11 +633,14 @@ static int set_endpoints(xusb_t *xusb, struct usb_host_interface *iface_desc, st
} }
} }
} }
if (!xusb->endpoints[XUSB_RECV].ep_addr || !xusb->endpoints[XUSB_SEND].ep_addr) { if (!xusb->endpoints[XUSB_RECV].ep_addr
|| !xusb->endpoints[XUSB_SEND].ep_addr) {
XUSB_ERR(xusb, "Couldn't find bulk-in or bulk-out endpoints\n"); XUSB_ERR(xusb, "Couldn't find bulk-in or bulk-out endpoints\n");
return 0; return 0;
} }
DBG(DEVICES, "in=0x%02X out=0x%02X\n", xusb->endpoints[XUSB_RECV].ep_addr, xusb->endpoints[XUSB_SEND].ep_addr); DBG(DEVICES, "in=0x%02X out=0x%02X\n",
xusb->endpoints[XUSB_RECV].ep_addr,
xusb->endpoints[XUSB_SEND].ep_addr);
return 1; return 1;
} }
@ -651,12 +661,15 @@ static int set_endpoints(xusb_t *xusb, struct usb_host_interface *iface_desc, st
* Called by the usb core when a new device is connected that it thinks * Called by the usb core when a new device is connected that it thinks
* this driver might be interested in. * this driver might be interested in.
*/ */
static int xusb_probe(struct usb_interface *interface, const struct usb_device_id *id) static int xusb_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{ {
struct usb_device *udev = interface_to_usbdev(interface); struct usb_device *udev = interface_to_usbdev(interface);
struct usb_host_interface *iface_desc = usb_altnum_to_altsetting(interface, 0); struct usb_host_interface *iface_desc =
usb_altnum_to_altsetting(interface, 0);
xusb_t *xusb = NULL; xusb_t *xusb = NULL;
struct xusb_model_info *model_info = (struct xusb_model_info*)id->driver_info; struct xusb_model_info *model_info =
(struct xusb_model_info *)id->driver_info;
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
struct proc_dir_entry *procsummary = NULL; struct proc_dir_entry *procsummary = NULL;
#endif #endif
@ -713,18 +726,18 @@ static int xusb_probe(struct usb_interface *interface, const struct usb_device_i
USB_GET_STRING(udev, iProduct, xusb->product); USB_GET_STRING(udev, iProduct, xusb->product);
USB_GET_IFACE_NAME(udev, iface_desc, xusb->interface_name); USB_GET_IFACE_NAME(udev, iface_desc, xusb->interface_name);
#endif #endif
INFO("XUSB: %s -- %s -- %s\n", INFO("XUSB: %s -- %s -- %s\n", xusb->manufacturer, xusb->product,
xusb->manufacturer, xusb->product, xusb->interface_name); xusb->interface_name);
/* allow device read, write and ioctl */ /* allow device read, write and ioctl */
xusb->present = 1; xusb->present = 1;
/* we can register the device now, as it is ready */ /* 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); retval = usb_register_dev(interface, &xusb_class);
if (retval) { if (retval) {
/* something prevented us from registering this driver */ /* something prevented us from registering this driver */
ERR ("Not able to get a minor for this device.\n"); ERR("Not able to get a minor for this device.\n");
goto probe_failed; goto probe_failed;
} }
@ -732,16 +745,18 @@ static int xusb_probe(struct usb_interface *interface, const struct usb_device_i
/* let the user know what node this device is now attached to */ /* let the user know what node this device is now attached to */
DBG(DEVICES, "USB XPP device now attached to minor %d\n", xusb->minor); DBG(DEVICES, "USB XPP device now attached to minor %d\n", xusb->minor);
xbus = xbus_new(&xusb_ops, min(xusb->endpoints[XUSB_SEND].max_size, xusb->endpoints[XUSB_RECV].max_size), &udev->dev, xusb); xbus =
xbus_new(&xusb_ops,
min(xusb->endpoints[XUSB_SEND].max_size,
xusb->endpoints[XUSB_RECV].max_size), &udev->dev,
xusb);
if (!xbus) { if (!xbus) {
retval = -ENOMEM; retval = -ENOMEM;
goto probe_failed; goto probe_failed;
} }
snprintf(xbus->transport.model_string, snprintf(xbus->transport.model_string,
ARRAY_SIZE(xbus->transport.model_string), ARRAY_SIZE(xbus->transport.model_string), "usb:%04x/%04x/%x",
"usb:%04x/%04x/%x", udev->descriptor.idVendor, udev->descriptor.idProduct,
udev->descriptor.idVendor,
udev->descriptor.idProduct,
udev->descriptor.bcdDevice); udev->descriptor.bcdDevice);
spin_lock_irqsave(&xusb_lock, flags); spin_lock_irqsave(&xusb_lock, flags);
for (i = 0; i < MAX_BUSES; i++) { for (i = 0; i < MAX_BUSES; i++) {
@ -763,11 +778,14 @@ static int xusb_probe(struct usb_interface *interface, const struct usb_device_i
XUSB_DBG(DEVICES, xusb, "GOT XPP USB BUS: %s\n", xbus->connector); XUSB_DBG(DEVICES, xusb, "GOT XPP USB BUS: %s\n", xbus->connector);
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
DBG(PROC, "Creating proc entry " PROC_USBXPP_SUMMARY " in bus proc dir.\n"); DBG(PROC,
procsummary = create_proc_read_entry(PROC_USBXPP_SUMMARY, 0444, xbus->proc_xbus_dir, "Creating proc entry " PROC_USBXPP_SUMMARY " in bus proc dir.\n");
xusb_read_proc, xusb); procsummary =
create_proc_read_entry(PROC_USBXPP_SUMMARY, 0444,
xbus->proc_xbus_dir, xusb_read_proc, xusb);
if (!procsummary) { if (!procsummary) {
XBUS_ERR(xbus, "Failed to create proc file '%s'\n", PROC_USBXPP_SUMMARY); XBUS_ERR(xbus, "Failed to create proc file '%s'\n",
PROC_USBXPP_SUMMARY);
// FIXME: better error handling // FIXME: better error handling
retval = -EIO; retval = -EIO;
goto probe_failed; goto probe_failed;
@ -795,8 +813,11 @@ probe_failed:
if (xbus) { if (xbus) {
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
if (procsummary) { if (procsummary) {
XBUS_DBG(PROC, xbus, "Remove proc_entry: " PROC_USBXPP_SUMMARY "\n"); XBUS_DBG(PROC, xbus,
remove_proc_entry(PROC_USBXPP_SUMMARY, xbus->proc_xbus_dir); "Remove proc_entry: " PROC_USBXPP_SUMMARY
"\n");
remove_proc_entry(PROC_USBXPP_SUMMARY,
xbus->proc_xbus_dir);
procsummary = NULL; procsummary = NULL;
} }
#endif #endif
@ -819,14 +840,16 @@ probe_failed:
*/ */
static void xusb_disconnect(struct usb_interface *interface) static void xusb_disconnect(struct usb_interface *interface)
{ {
struct usb_host_interface *iface_desc = usb_altnum_to_altsetting(interface, 0); struct usb_host_interface *iface_desc =
usb_altnum_to_altsetting(interface, 0);
xusb_t *xusb; xusb_t *xusb;
xbus_t *xbus; xbus_t *xbus;
int i; int i;
DBG(DEVICES, "CALLED on interface #%d\n", iface_desc->desc.bInterfaceNumber); DBG(DEVICES, "CALLED on interface #%d\n",
iface_desc->desc.bInterfaceNumber);
/* prevent races with open() */ /* prevent races with open() */
down (&disconnect_sem); down(&disconnect_sem);
xusb = usb_get_intfdata(interface); xusb = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL); usb_set_intfdata(interface, NULL);
@ -843,23 +866,24 @@ static void xusb_disconnect(struct usb_interface *interface)
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
if (xbus->proc_xbus_dir) { if (xbus->proc_xbus_dir) {
XBUS_DBG(PROC, xbus, "Remove proc_entry: " PROC_USBXPP_SUMMARY "\n"); XBUS_DBG(PROC, xbus,
"Remove proc_entry: " PROC_USBXPP_SUMMARY "\n");
remove_proc_entry(PROC_USBXPP_SUMMARY, xbus->proc_xbus_dir); remove_proc_entry(PROC_USBXPP_SUMMARY, xbus->proc_xbus_dir);
} }
#endif #endif
xbus_disconnect(xbus); // Blocking until fully deactivated! xbus_disconnect(xbus); // Blocking until fully deactivated!
down (&xusb->sem); down(&xusb->sem);
/* give back our minor */ /* give back our minor */
usb_deregister_dev(interface, &xusb_class); usb_deregister_dev(interface, &xusb_class);
up (&xusb->sem); up(&xusb->sem);
DBG(DEVICES, "Semaphore released\n"); DBG(DEVICES, "Semaphore released\n");
XUSB_INFO(xusb, "now disconnected\n"); XUSB_INFO(xusb, "now disconnected\n");
KZFREE(xusb); KZFREE(xusb);
up (&disconnect_sem); up(&disconnect_sem);
} }
static void xpp_send_callback(USB_PASS_CB(urb)) static void xpp_send_callback(USB_PASS_CB(urb))
@ -874,7 +898,8 @@ static void xpp_send_callback(USB_PASS_CB(urb))
int i; int i;
if (!xbus) { if (!xbus) {
XUSB_ERR(xusb, "Sent URB does not belong to a valid xbus anymore...\n"); XUSB_ERR(xusb,
"Sent URB does not belong to a valid xbus anymore...\n");
return; return;
} }
//flip_parport_bit(6); //flip_parport_bit(6);
@ -904,7 +929,8 @@ static void xpp_send_callback(USB_PASS_CB(urb))
} else } else
xusb->sluggish_debounce = 0; xusb->sluggish_debounce = 0;
/* sync/async unlink faults aren't errors */ /* sync/async unlink faults aren't errors */
if (urb->status && !(urb->status == -ENOENT || urb->status == -ECONNRESET)) { if (urb->status
&& !(urb->status == -ENOENT || urb->status == -ECONNRESET)) {
static int rate_limit; static int rate_limit;
if ((rate_limit++ % 1000) < 10) { if ((rate_limit++ % 1000) < 10) {
XUSB_ERR(xusb, XUSB_ERR(xusb,
@ -933,7 +959,8 @@ static void xpp_receive_callback(USB_PASS_CB(urb))
do_gettimeofday(&now); do_gettimeofday(&now);
atomic_dec(&xusb->pending_reads); atomic_dec(&xusb->pending_reads);
if (!xbus) { if (!xbus) {
XUSB_ERR(xusb, "Received URB does not belong to a valid xbus anymore...\n"); XUSB_ERR(xusb,
"Received URB does not belong to a valid xbus anymore...\n");
return; return;
} }
if (!xusb->present) { if (!xusb->present) {
@ -941,7 +968,8 @@ static void xpp_receive_callback(USB_PASS_CB(urb))
goto err; goto err;
} }
if (urb->status) { if (urb->status) {
DBG(GENERAL, "nonzero read bulk status received: %d\n", urb->status); DBG(GENERAL, "nonzero read bulk status received: %d\n",
urb->status);
XUSB_COUNTER(xusb, RX_ERRORS)++; XUSB_COUNTER(xusb, RX_ERRORS)++;
goto err; goto err;
} }
@ -950,7 +978,8 @@ static void xpp_receive_callback(USB_PASS_CB(urb))
static int rate_limit; static int rate_limit;
if ((rate_limit++ % 5003) == 0) if ((rate_limit++ % 5003) == 0)
XUSB_NOTICE(xusb, "Received a zero length URBs (%d)\n", rate_limit); XUSB_NOTICE(xusb, "Received a zero length URBs (%d)\n",
rate_limit);
XUSB_COUNTER(xusb, RCV_ZERO_LEN)++; XUSB_COUNTER(xusb, RCV_ZERO_LEN)++;
goto err; goto err;
} }
@ -971,7 +1000,6 @@ err:
goto end; goto end;
} }
/*------------------------- Initialization -------------------------*/ /*------------------------- Initialization -------------------------*/
static void xpp_usb_cleanup(void) static void xpp_usb_cleanup(void)
@ -988,8 +1016,8 @@ static int __init xpp_usb_init(void)
//xusb_t *xusb; //xusb_t *xusb;
INFO("revision %s\n", XPP_VERSION); INFO("revision %s\n", XPP_VERSION);
xusb_cache = kmem_cache_create("xusb_cache", xusb_cache =
sizeof(xframe_t) + XFRAME_DATASIZE, kmem_cache_create("xusb_cache", sizeof(xframe_t) + XFRAME_DATASIZE,
#if (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 22)) && defined(CONFIG_SLUB) #if (LINUX_VERSION_CODE == KERNEL_VERSION(2, 6, 22)) && defined(CONFIG_SLUB)
0, SLAB_STORE_USER, 0, SLAB_STORE_USER,
#else #else
@ -1016,7 +1044,6 @@ failure:
return ret; return ret;
} }
static void __exit xpp_usb_shutdown(void) static void __exit xpp_usb_shutdown(void)
{ {
DBG(GENERAL, "\n"); DBG(GENERAL, "\n");
@ -1025,11 +1052,10 @@ static void __exit xpp_usb_shutdown(void)
xpp_usb_cleanup(); xpp_usb_cleanup();
} }
#ifdef CONFIG_PROC_FS #ifdef CONFIG_PROC_FS
static int xusb_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) static int xusb_read_proc(char *page, char **start, off_t off, int count,
int *eof, void *data)
{ {
int len = 0; int len = 0;
unsigned long flags; unsigned long flags;
@ -1037,59 +1063,70 @@ static int xusb_read_proc(char *page, char **start, off_t off, int count, int *e
//unsigned long stamp = jiffies; //unsigned long stamp = jiffies;
xusb_t *xusb = data; xusb_t *xusb = data;
uint usb_tx_delay[NUM_BUCKETS]; uint usb_tx_delay[NUM_BUCKETS];
const int mark_limit = tx_sluggish/USEC_BUCKET; const int mark_limit = tx_sluggish / USEC_BUCKET;
if (!xusb) if (!xusb)
goto out; goto out;
// TODO: probably needs a per-xusb lock: // TODO: probably needs a per-xusb lock:
spin_lock_irqsave(&xusb_lock, flags); spin_lock_irqsave(&xusb_lock, flags);
len += sprintf(page + len, "Device: %03d/%03d\n", len +=
xusb->udev->bus->busnum, sprintf(page + len, "Device: %03d/%03d\n", xusb->udev->bus->busnum,
xusb->udev->devnum xusb->udev->devnum);
); len +=
len += sprintf(page + len, "USB: manufacturer=%s\n", xusb->manufacturer); sprintf(page + len, "USB: manufacturer=%s\n", xusb->manufacturer);
len += sprintf(page + len, "USB: product=%s\n", xusb->product); len += sprintf(page + len, "USB: product=%s\n", xusb->product);
len += sprintf(page + len, "USB: serial=%s\n", xusb->serial); len += sprintf(page + len, "USB: serial=%s\n", xusb->serial);
len += sprintf(page + len, "Minor: %d\nModel Info: %s\n", len +=
xusb->minor, xusb->model_info->desc); sprintf(page + len, "Minor: %d\nModel Info: %s\n", xusb->minor,
len += sprintf(page + len, "Endpoints:\n" xusb->model_info->desc);
"\tIn: 0x%02X - Size: %d)\n" len +=
sprintf(page + len,
"Endpoints:\n" "\tIn: 0x%02X - Size: %d)\n"
"\tOut: 0x%02X - Size: %d)\n", "\tOut: 0x%02X - Size: %d)\n",
xusb->endpoints[XUSB_RECV].ep_addr, xusb->endpoints[XUSB_RECV].ep_addr,
xusb->endpoints[XUSB_RECV].max_size, xusb->endpoints[XUSB_RECV].max_size,
xusb->endpoints[XUSB_SEND].ep_addr, xusb->endpoints[XUSB_SEND].ep_addr,
xusb->endpoints[XUSB_SEND].max_size xusb->endpoints[XUSB_SEND].max_size);
); len +=
len += sprintf(page + len, "\npending_writes=%d\n", atomic_read(&xusb->pending_writes)); sprintf(page + len, "\npending_writes=%d\n",
len += sprintf(page + len, "pending_reads=%d\n", atomic_read(&xusb->pending_reads)); atomic_read(&xusb->pending_writes));
len +=
sprintf(page + len, "pending_reads=%d\n",
atomic_read(&xusb->pending_reads));
len += sprintf(page + len, "max_tx_delay=%d\n", xusb->max_tx_delay); len += sprintf(page + len, "max_tx_delay=%d\n", xusb->max_tx_delay);
xusb->max_tx_delay = 0; xusb->max_tx_delay = 0;
#ifdef DEBUG_PCM_TIMING #ifdef DEBUG_PCM_TIMING
len += sprintf(page + len, "\nstamp_last_pcm_read=%lld accumulate_diff=%lld\n", stamp_last_pcm_read, accumulate_diff); len +=
sprintf(page + len,
"\nstamp_last_pcm_read=%lld accumulate_diff=%lld\n",
stamp_last_pcm_read, accumulate_diff);
#endif #endif
memcpy(usb_tx_delay, xusb->usb_tx_delay, sizeof(usb_tx_delay)); memcpy(usb_tx_delay, xusb->usb_tx_delay, sizeof(usb_tx_delay));
len += sprintf(page + len, "usb_tx_delay[%d,%d,%d]: ", len +=
USEC_BUCKET, BUCKET_START, NUM_BUCKETS); sprintf(page + len, "usb_tx_delay[%d,%d,%d]: ", USEC_BUCKET,
BUCKET_START, NUM_BUCKETS);
for (i = BUCKET_START; i < NUM_BUCKETS; i++) { for (i = BUCKET_START; i < NUM_BUCKETS; i++) {
len += sprintf(page + len, "%6d ", len += sprintf(page + len, "%6d ", usb_tx_delay[i]);
usb_tx_delay[i]);
if (i == mark_limit) if (i == mark_limit)
len += sprintf(page + len, "| "); len += sprintf(page + len, "| ");
} }
len += sprintf(page + len, "\nPCM_TX_DROPS: %5d (sluggish: %d)\n", len +=
sprintf(page + len, "\nPCM_TX_DROPS: %5d (sluggish: %d)\n",
atomic_read(&xusb->pcm_tx_drops), atomic_read(&xusb->pcm_tx_drops),
atomic_read(&xusb->usb_sluggish_count) atomic_read(&xusb->usb_sluggish_count)
); );
len += sprintf(page + len, "\nCOUNTERS:\n"); len += sprintf(page + len, "\nCOUNTERS:\n");
for (i = 0; i < XUSB_COUNTER_MAX; i++) { for (i = 0; i < XUSB_COUNTER_MAX; i++) {
len += sprintf(page + len, "\t%-15s = %d\n", xusb_counters[i].name, xusb->counters[i]); len +=
sprintf(page + len, "\t%-15s = %d\n", xusb_counters[i].name,
xusb->counters[i]);
} }
#if 0 #if 0
len += sprintf(page + len, "<-- len=%d\n", len); len += sprintf(page + len, "<-- len=%d\n", len);
#endif #endif
spin_unlock_irqrestore(&xusb_lock, flags); spin_unlock_irqrestore(&xusb_lock, flags);
out: out:
if (len <= off+count) if (len <= off + count)
*eof = 1; *eof = 1;
*start = page + off; *start = page + off;
len -= off; len -= off;
@ -1103,8 +1140,6 @@ out:
#endif #endif
MODULE_DESCRIPTION("XPP USB Transport Driver"); MODULE_DESCRIPTION("XPP USB Transport Driver");
MODULE_AUTHOR("Oron Peled <oron@actcom.co.il>"); MODULE_AUTHOR("Oron Peled <oron@actcom.co.il>");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");

View File

@ -40,12 +40,14 @@ static const xproto_table_t *xprotocol_tables[XPD_TYPE_NOMODULE];
bool valid_xpd_addr(const struct xpd_addr *addr) bool valid_xpd_addr(const struct xpd_addr *addr)
{ {
return ((addr->subunit & ~BITMASK(SUBUNIT_BITS)) == 0) && ((addr->unit & ~BITMASK(UNIT_BITS)) == 0); return ((addr->subunit & ~BITMASK(SUBUNIT_BITS)) == 0)
&& ((addr->unit & ~BITMASK(UNIT_BITS)) == 0);
} }
/*---------------- General Protocol Management ----------------------------*/ /*---------------- General Protocol Management ----------------------------*/
const xproto_entry_t *xproto_card_entry(const xproto_table_t *table, __u8 opcode) const xproto_entry_t *xproto_card_entry(const xproto_table_t *table,
__u8 opcode)
{ {
const xproto_entry_t *xe; const xproto_entry_t *xe;
@ -85,7 +87,8 @@ const xproto_table_t *xproto_get(xpd_type_t cardtype)
if (!xtable) { /* Try to load the relevant module */ if (!xtable) { /* Try to load the relevant module */
int ret = request_module(XPD_TYPE_PREFIX "%d", cardtype); int ret = request_module(XPD_TYPE_PREFIX "%d", cardtype);
if (ret != 0) { if (ret != 0) {
NOTICE("%s: Failed to load module for type=%d. exit status=%d.\n", NOTICE
("%s: Failed to load module for type=%d. exit status=%d.\n",
__func__, cardtype, ret); __func__, cardtype, ret);
/* Drop through: we may be lucky... */ /* Drop through: we may be lucky... */
} }
@ -94,10 +97,12 @@ const xproto_table_t *xproto_get(xpd_type_t cardtype)
if (xtable) { if (xtable) {
BUG_ON(!xtable->owner); BUG_ON(!xtable->owner);
#ifdef CONFIG_MODULE_UNLOAD #ifdef CONFIG_MODULE_UNLOAD
DBG(GENERAL, "%s refcount was %d\n", xtable->name, module_refcount(xtable->owner)); DBG(GENERAL, "%s refcount was %d\n", xtable->name,
module_refcount(xtable->owner));
#endif #endif
if (!try_module_get(xtable->owner)) { if (!try_module_get(xtable->owner)) {
ERR("%s: try_module_get for %s failed.\n", __func__, xtable->name); ERR("%s: try_module_get for %s failed.\n", __func__,
xtable->name);
return NULL; return NULL;
} }
} }
@ -108,7 +113,8 @@ void xproto_put(const xproto_table_t *xtable)
{ {
BUG_ON(!xtable); BUG_ON(!xtable);
#ifdef CONFIG_MODULE_UNLOAD #ifdef CONFIG_MODULE_UNLOAD
DBG(GENERAL, "%s refcount was %d\n", xtable->name, module_refcount(xtable->owner)); DBG(GENERAL, "%s refcount was %d\n", xtable->name,
module_refcount(xtable->owner));
BUG_ON(module_refcount(xtable->owner) <= 0); BUG_ON(module_refcount(xtable->owner) <= 0);
#endif #endif
module_put(xtable->owner); module_put(xtable->owner);
@ -123,10 +129,11 @@ xproto_handler_t xproto_card_handler(const xproto_table_t *table, __u8 opcode)
return xe->handler; return xe->handler;
} }
void notify_bad_xpd(const char *funcname, xbus_t *xbus, const struct xpd_addr addr, const char *msg) void notify_bad_xpd(const char *funcname, xbus_t *xbus,
const struct xpd_addr addr, const char *msg)
{ {
XBUS_NOTICE(xbus, "%s: non-existing address (%1d%1d): %s\n", XBUS_NOTICE(xbus, "%s: non-existing address (%1d%1d): %s\n", funcname,
funcname, addr.unit, addr.subunit, msg); addr.unit, addr.subunit, msg);
} }
static int packet_process(xbus_t *xbus, xpacket_t *pack) static int packet_process(xbus_t *xbus, xpacket_t *pack)
@ -142,14 +149,17 @@ static int packet_process(xbus_t *xbus, xpacket_t *pack)
if (!valid_xpd_addr(&XPACKET_ADDR(pack))) { if (!valid_xpd_addr(&XPACKET_ADDR(pack))) {
if (printk_ratelimit()) { if (printk_ratelimit()) {
XBUS_NOTICE(xbus, "%s: from %d%d: bad address.\n", XBUS_NOTICE(xbus, "%s: from %d%d: bad address.\n",
__func__, __func__, XPACKET_ADDR_UNIT(pack),
XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack)); XPACKET_ADDR_SUBUNIT(pack));
dump_packet("packet_process -- bad address", pack, debug); dump_packet("packet_process -- bad address", pack,
debug);
} }
goto out; goto out;
} }
op = XPACKET_OP(pack); op = XPACKET_OP(pack);
xpd = xpd_byaddr(xbus, XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack)); xpd =
xpd_byaddr(xbus, XPACKET_ADDR_UNIT(pack),
XPACKET_ADDR_SUBUNIT(pack));
/* XPD may be NULL (e.g: during bus polling */ /* XPD may be NULL (e.g: during bus polling */
xe = xproto_global_entry(op); xe = xproto_global_entry(op);
/*-------- Validations -----------*/ /*-------- Validations -----------*/
@ -158,28 +168,32 @@ static int packet_process(xbus_t *xbus, xpacket_t *pack)
if (!xpd) { if (!xpd) {
if (printk_ratelimit()) { if (printk_ratelimit()) {
XBUS_NOTICE(xbus, "%s: from %d%d opcode=0x%02X: no such global command.\n", XBUS_NOTICE(xbus,
__func__, "%s: from %d%d opcode=0x%02X: no such global command.\n",
XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack), op); __func__, XPACKET_ADDR_UNIT(pack),
dump_packet("packet_process -- no such global command", pack, 1); XPACKET_ADDR_SUBUNIT(pack), op);
dump_packet
("packet_process -- no such global command",
pack, 1);
} }
goto out; goto out;
} }
xtable = xproto_table(xpd->type); xtable = xproto_table(xpd->type);
if (!xtable) { if (!xtable) {
if (printk_ratelimit()) if (printk_ratelimit())
XPD_ERR(xpd, "%s: no protocol table (type=%d)\n", XPD_ERR(xpd,
__func__, "%s: no protocol table (type=%d)\n",
xpd->type); __func__, xpd->type);
goto out; goto out;
} }
xe = xproto_card_entry(xtable, op); xe = xproto_card_entry(xtable, op);
if (!xe) { if (!xe) {
if (printk_ratelimit()) { if (printk_ratelimit()) {
XPD_NOTICE(xpd, "%s: bad command (type=%d,opcode=0x%x)\n", XPD_NOTICE(xpd,
__func__, "%s: bad command (type=%d,opcode=0x%x)\n",
xpd->type, op); __func__, xpd->type, op);
dump_packet("packet_process -- bad command", pack, 1); dump_packet("packet_process -- bad command",
pack, 1);
} }
goto out; goto out;
} }
@ -190,7 +204,8 @@ static int packet_process(xbus_t *xbus, xpacket_t *pack)
if (printk_ratelimit()) { if (printk_ratelimit()) {
ERR("xpp: %s: wrong size %d for opcode=0x%02X\n", ERR("xpp: %s: wrong size %d for opcode=0x%02X\n",
__func__, XPACKET_LEN(pack), op); __func__, XPACKET_LEN(pack), op);
dump_packet("packet_process -- wrong size", pack, debug); dump_packet("packet_process -- wrong size", pack,
debug);
} }
goto out; goto out;
} }
@ -223,8 +238,10 @@ static int xframe_receive_cmd(xbus_t *xbus, xframe_t *xframe)
static int rate_limit; static int rate_limit;
if ((rate_limit++ % 1003) == 0) { if ((rate_limit++ % 1003) == 0) {
XBUS_DBG(GENERAL, xbus, "A PCM packet within a Non-PCM xframe\n"); XBUS_DBG(GENERAL, xbus,
dump_xframe("In Non-PCM xframe", xbus, xframe, debug); "A PCM packet within a Non-PCM xframe\n");
dump_xframe("In Non-PCM xframe", xbus, xframe,
debug);
} }
ret = -EPROTO; ret = -EPROTO;
goto out; goto out;
@ -234,7 +251,8 @@ static int xframe_receive_cmd(xbus_t *xbus, xframe_t *xframe)
static int rate_limit; static int rate_limit;
if ((rate_limit++ % 1003) == 0) { if ((rate_limit++ % 1003) == 0) {
XBUS_NOTICE(xbus, "Invalid packet length %d\n", len); XBUS_NOTICE(xbus, "Invalid packet length %d\n",
len);
dump_xframe("BAD LENGTH", xbus, xframe, debug); dump_xframe("BAD LENGTH", xbus, xframe, debug);
} }
ret = -EPROTO; ret = -EPROTO;
@ -285,8 +303,9 @@ int xframe_receive(xbus_t *xbus, xframe_t *xframe)
} }
/* Calculate total processing time */ /* Calculate total processing time */
do_gettimeofday(&now); do_gettimeofday(&now);
usec = (now.tv_sec - tv_received.tv_sec) * 1000000 + usec =
now.tv_usec - tv_received.tv_usec; (now.tv_sec - tv_received.tv_sec) * 1000000 + now.tv_usec -
tv_received.tv_usec;
if (usec > xbus->max_rx_process) if (usec > xbus->max_rx_process)
xbus->max_rx_process = usec; xbus->max_rx_process = usec;
return ret; return ret;
@ -302,13 +321,9 @@ void dump_packet(const char *msg, const xpacket_t *packet, bool debug)
if (!debug) if (!debug)
return; return;
printk(KERN_DEBUG "%s: XPD=%1X-%1X%c (0x%X) OP=0x%02X LEN=%d", printk(KERN_DEBUG "%s: XPD=%1X-%1X%c (0x%X) OP=0x%02X LEN=%d", msg,
msg, XPACKET_ADDR_UNIT(packet), XPACKET_ADDR_SUBUNIT(packet),
XPACKET_ADDR_UNIT(packet), (XPACKET_ADDR_SYNC(packet)) ? '+' : ' ', *addr, op,
XPACKET_ADDR_SUBUNIT(packet),
(XPACKET_ADDR_SYNC(packet))?'+':' ',
*addr,
op,
XPACKET_LEN(packet)); XPACKET_LEN(packet));
#if VERBOSE_DEBUG #if VERBOSE_DEBUG
{ {
@ -321,11 +336,9 @@ void dump_packet(const char *msg, const xpacket_t *packet, bool debug)
if (i >= sizeof(xpacket_t)) { if (i >= sizeof(xpacket_t)) {
if (limiter < ERR_REPORT_LIMIT) { if (limiter < ERR_REPORT_LIMIT) {
ERR("%s: length overflow i=%d > sizeof(xpacket_t)=%lu\n", ERR("%s: length overflow i=%d > sizeof(xpacket_t)=%lu\n", __func__, i + 1, (long)sizeof(xpacket_t));
__func__, i+1, (long)sizeof(xpacket_t));
} else if (limiter == ERR_REPORT_LIMIT) { } else if (limiter == ERR_REPORT_LIMIT) {
ERR("%s: error packet #%d... squelsh reports.\n", ERR("%s: error packet #%d... squelsh reports.\n", __func__, limiter);
__func__, limiter);
} }
limiter++; limiter++;
break; break;
@ -338,8 +351,8 @@ void dump_packet(const char *msg, const xpacket_t *packet, bool debug)
printk("\n"); printk("\n");
} }
void dump_reg_cmd(const char msg[], bool writing, xbus_t *xbus, void dump_reg_cmd(const char msg[], bool writing, xbus_t *xbus, __u8 unit,
__u8 unit, xportno_t port, const reg_cmd_t *regcmd) xportno_t port, const reg_cmd_t *regcmd)
{ {
char action; char action;
char modifier; char modifier;
@ -348,8 +361,9 @@ void dump_reg_cmd(const char msg[], bool writing, xbus_t *xbus,
char data_buf[MAX_PROC_WRITE]; char data_buf[MAX_PROC_WRITE];
if (regcmd->bytes > sizeof(*regcmd) - 1) { /* The size byte is not included */ if (regcmd->bytes > sizeof(*regcmd) - 1) { /* The size byte is not included */
PORT_NOTICE(xbus, unit, port, "%s: %s: Too long: regcmd->bytes = %d\n", PORT_NOTICE(xbus, unit, port,
__func__, msg, regcmd->bytes); "%s: %s: Too long: regcmd->bytes = %d\n", __func__,
msg, regcmd->bytes);
return; return;
} }
if (regcmd->is_multibyte) { if (regcmd->is_multibyte) {
@ -361,27 +375,27 @@ void dump_reg_cmd(const char msg[], bool writing, xbus_t *xbus,
buf[0] = '\0'; buf[0] = '\0';
for (i = 0; i < len && n < MAX_PROC_WRITE; i++) for (i = 0; i < len && n < MAX_PROC_WRITE; i++)
n += snprintf(&buf[n], MAX_PROC_WRITE - n, "%02X ", p[i]); n += snprintf(&buf[n], MAX_PROC_WRITE - n, "%02X ",
p[i]);
PORT_DBG(REGS, xbus, unit, port, PORT_DBG(REGS, xbus, unit, port,
"UNIT-%d PORT-%d: Multibyte(eoframe=%d) %s[0..%zd]: %s%s\n", "UNIT-%d PORT-%d: Multibyte(eoframe=%d) %s[0..%zd]: %s%s\n",
unit, port, regcmd->eoframe, unit, port, regcmd->eoframe, msg, len - 1, buf,
msg, len-1, buf, (n >= MAX_PROC_WRITE)?"...":""); (n >= MAX_PROC_WRITE) ? "..." : "");
return; return;
} }
if (regcmd->bytes != sizeof(*regcmd) - 1) { /* The size byte is not included */ if (regcmd->bytes != sizeof(*regcmd) - 1) { /* The size byte is not included */
PORT_NOTICE(xbus, unit, port, "%s: %s: Wrong size: regcmd->bytes = %d\n", PORT_NOTICE(xbus, unit, port,
"%s: %s: Wrong size: regcmd->bytes = %d\n",
__func__, msg, regcmd->bytes); __func__, msg, regcmd->bytes);
return; return;
} }
snprintf(port_buf, MAX_PROC_WRITE, "%d%s", snprintf(port_buf, MAX_PROC_WRITE, "%d%s", regcmd->portnum,
regcmd->portnum,
(REG_FIELD(regcmd, all_ports_broadcast)) ? "*" : ""); (REG_FIELD(regcmd, all_ports_broadcast)) ? "*" : "");
action = (REG_FIELD(regcmd, read_request)) ? 'R' : 'W'; action = (REG_FIELD(regcmd, read_request)) ? 'R' : 'W';
modifier = 'D'; modifier = 'D';
if (REG_FIELD(regcmd, do_subreg)) { if (REG_FIELD(regcmd, do_subreg)) {
snprintf(reg_buf, MAX_PROC_WRITE, "%02X %02X", snprintf(reg_buf, MAX_PROC_WRITE, "%02X %02X",
REG_FIELD(regcmd, regnum), REG_FIELD(regcmd, regnum), REG_FIELD(regcmd, subreg));
REG_FIELD(regcmd, subreg));
modifier = 'S'; modifier = 'S';
} else { } else {
snprintf(reg_buf, MAX_PROC_WRITE, "%02X", snprintf(reg_buf, MAX_PROC_WRITE, "%02X",
@ -391,16 +405,15 @@ void dump_reg_cmd(const char msg[], bool writing, xbus_t *xbus,
data_buf[0] = '\0'; data_buf[0] = '\0';
} else if (REG_FIELD(regcmd, do_datah)) { } else if (REG_FIELD(regcmd, do_datah)) {
snprintf(data_buf, MAX_PROC_WRITE, "%02X %02X", snprintf(data_buf, MAX_PROC_WRITE, "%02X %02X",
REG_FIELD(regcmd, data_low), REG_FIELD(regcmd, data_low), REG_FIELD(regcmd,
REG_FIELD(regcmd, data_high)); data_high));
modifier = 'I'; modifier = 'I';
} else { } else {
snprintf(data_buf, MAX_PROC_WRITE, "%02X", snprintf(data_buf, MAX_PROC_WRITE, "%02X",
REG_FIELD(regcmd, data_low)); REG_FIELD(regcmd, data_low));
} }
PORT_DBG(REGS, xbus, unit, port, "%s: %s %c%c %s %s\n", PORT_DBG(REGS, xbus, unit, port, "%s: %s %c%c %s %s\n", msg, port_buf,
msg, port_buf, action, modifier, action, modifier, reg_buf, data_buf);
reg_buf, data_buf);
} }
const char *xproto_name(xpd_type_t xpd_type) const char *xproto_name(xpd_type_t xpd_type)
@ -442,7 +455,8 @@ int xproto_register(const xproto_table_t *proto_table)
} }
DBG(GENERAL, "%s (%d)\n", name, type); DBG(GENERAL, "%s (%d)\n", name, type);
if (xprotocol_tables[type]) if (xprotocol_tables[type])
NOTICE("%s: overriding registration of %s (%d)\n", __func__, name, type); NOTICE("%s: overriding registration of %s (%d)\n", __func__,
name, type);
xops = proto_table->xops; xops = proto_table->xops;
CHECK_XOP(xops, card_new); CHECK_XOP(xops, card_new);
CHECK_XOP(xops, card_init); CHECK_XOP(xops, card_init);
@ -460,7 +474,7 @@ int xproto_register(const xproto_table_t *proto_table)
CHECK_PHONEOP(phoneops, card_dahdi_preregistration); CHECK_PHONEOP(phoneops, card_dahdi_preregistration);
CHECK_PHONEOP(phoneops, card_dahdi_postregistration); CHECK_PHONEOP(phoneops, card_dahdi_postregistration);
/* optional method -- call after testing: */ /* optional method -- call after testing: */
/*CHECK_PHONEOP(phoneops, card_ioctl);*/ /*CHECK_PHONEOP(phoneops, card_ioctl); */
} }
xprotocol_tables[type] = proto_table; xprotocol_tables[type] = proto_table;
@ -481,7 +495,8 @@ void xproto_unregister(const xproto_table_t *proto_table)
return; return;
} }
if (!xprotocol_tables[type]) if (!xprotocol_tables[type])
NOTICE("%s: xproto type %s (%d) is already unregistered\n", __func__, name, type); NOTICE("%s: xproto type %s (%d) is already unregistered\n",
__func__, name, type);
xprotocol_tables[type] = NULL; xprotocol_tables[type] = NULL;
} }

View File

@ -200,15 +200,13 @@ typedef struct reg_cmd {
typedef struct xproto_entry xproto_entry_t; typedef struct xproto_entry xproto_entry_t;
typedef struct xproto_table xproto_table_t; typedef struct xproto_table xproto_table_t;
typedef int (*xproto_handler_t)( typedef int (*xproto_handler_t) (xbus_t *xbus, xpd_t *xpd,
xbus_t *xbus, const xproto_entry_t *cmd, xpacket_t *pack);
xpd_t *xpd,
const xproto_entry_t *cmd,
xpacket_t *pack);
const xproto_table_t *xproto_get(xpd_type_t cardtype); const xproto_table_t *xproto_get(xpd_type_t cardtype);
void xproto_put(const xproto_table_t *xtable); void xproto_put(const xproto_table_t *xtable);
const xproto_entry_t *xproto_card_entry(const xproto_table_t *table, __u8 opcode); const xproto_entry_t *xproto_card_entry(const xproto_table_t *table,
__u8 opcode);
xproto_handler_t xproto_card_handler(const xproto_table_t *table, __u8 opcode); xproto_handler_t xproto_card_handler(const xproto_table_t *table, __u8 opcode);
const xproto_entry_t *xproto_global_entry(__u8 opcode); const xproto_entry_t *xproto_global_entry(__u8 opcode);
@ -231,29 +229,30 @@ xproto_handler_t xproto_global_handler(__u8 opcode);
(PHONE_METHOD(name, (xpd))((xpd), ## __VA_ARGS__ )) (PHONE_METHOD(name, (xpd))((xpd), ## __VA_ARGS__ ))
struct phoneops { struct phoneops {
void (*card_pcm_recompute)(xpd_t *xpd, xpp_line_t pcm_mask); void (*card_pcm_recompute) (xpd_t *xpd, xpp_line_t pcm_mask);
void (*card_pcm_fromspan)(xpd_t *xpd, xpacket_t *pack); void (*card_pcm_fromspan) (xpd_t *xpd, xpacket_t *pack);
void (*card_pcm_tospan)(xpd_t *xpd, xpacket_t *pack); void (*card_pcm_tospan) (xpd_t *xpd, xpacket_t *pack);
int (*echocancel_timeslot)(xpd_t *xpd, int pos); int (*echocancel_timeslot) (xpd_t *xpd, int pos);
int (*echocancel_setmask)(xpd_t *xpd, xpp_line_t ec_mask); int (*echocancel_setmask) (xpd_t *xpd, xpp_line_t ec_mask);
int (*card_timing_priority)(xpd_t *xpd); int (*card_timing_priority) (xpd_t *xpd);
int (*card_dahdi_preregistration)(xpd_t *xpd, bool on); int (*card_dahdi_preregistration) (xpd_t *xpd, bool on);
int (*card_dahdi_postregistration)(xpd_t *xpd, bool on); int (*card_dahdi_postregistration) (xpd_t *xpd, bool on);
int (*card_hooksig)(xpd_t *xpd, int pos, enum dahdi_txsig txsig); int (*card_hooksig) (xpd_t *xpd, int pos, enum dahdi_txsig txsig);
int (*card_ioctl)(xpd_t *xpd, int pos, unsigned int cmd, unsigned long arg); int (*card_ioctl) (xpd_t *xpd, int pos, unsigned int cmd,
int (*card_open)(xpd_t *xpd, lineno_t pos); unsigned long arg);
int (*card_close)(xpd_t *xpd, lineno_t pos); int (*card_open) (xpd_t *xpd, lineno_t pos);
int (*card_state)(xpd_t *xpd, bool on); int (*card_close) (xpd_t *xpd, lineno_t pos);
int (*card_state) (xpd_t *xpd, bool on);
}; };
struct xops { struct xops {
xpd_t *(*card_new)(xbus_t *xbus, int unit, int subunit, xpd_t *(*card_new) (xbus_t *xbus, int unit, int subunit,
const xproto_table_t *proto_table, __u8 subtype, const xproto_table_t *proto_table, __u8 subtype,
int subunits, int subunit_ports, bool to_phone); int subunits, int subunit_ports, bool to_phone);
int (*card_init)(xbus_t *xbus, xpd_t *xpd); int (*card_init) (xbus_t *xbus, xpd_t *xpd);
int (*card_remove)(xbus_t *xbus, xpd_t *xpd); int (*card_remove) (xbus_t *xbus, xpd_t *xpd);
int (*card_tick)(xbus_t *xbus, xpd_t *xpd); int (*card_tick) (xbus_t *xbus, xpd_t *xpd);
int (*card_register_reply)(xbus_t *xbus, xpd_t *xpd, reg_cmd_t *reg); int (*card_register_reply) (xbus_t *xbus, xpd_t *xpd, reg_cmd_t *reg);
}; };
struct xproto_entry { struct xproto_entry {
@ -272,8 +271,8 @@ struct xproto_table {
xpd_type_t type; xpd_type_t type;
__u8 ports_per_subunit; __u8 ports_per_subunit;
const char *name; const char *name;
bool (*packet_is_valid)(xpacket_t *pack); bool (*packet_is_valid) (xpacket_t *pack);
void (*packet_dump)(const char *msg, xpacket_t *pack); void (*packet_dump) (const char *msg, xpacket_t *pack);
}; };
#include "card_global.h" #include "card_global.h"
@ -282,7 +281,6 @@ struct xproto_table {
#include "card_bri.h" #include "card_bri.h"
#include "card_pri.h" #include "card_pri.h"
#define MEMBER(card, op) RPACKET_TYPE(card, op) RPACKET_NAME(card, op) #define MEMBER(card, op) RPACKET_TYPE(card, op) RPACKET_NAME(card, op)
struct xpacket { struct xpacket {
@ -303,9 +301,11 @@ struct xpacket {
} PACKED; } PACKED;
void dump_packet(const char *msg, const xpacket_t *packet, bool debug); void dump_packet(const char *msg, const xpacket_t *packet, bool debug);
void dump_reg_cmd(const char msg[], bool writing, xbus_t *xbus, __u8 unit, xportno_t port, const reg_cmd_t *regcmd); void dump_reg_cmd(const char msg[], bool writing, xbus_t *xbus, __u8 unit,
xportno_t port, const reg_cmd_t *regcmd);
int xframe_receive(xbus_t *xbus, xframe_t *xframe); int xframe_receive(xbus_t *xbus, xframe_t *xframe);
void notify_bad_xpd(const char *funcname, xbus_t *xbus, const struct xpd_addr addr, const char *msg); void notify_bad_xpd(const char *funcname, xbus_t *xbus,
const struct xpd_addr addr, const char *msg);
int xproto_register(const xproto_table_t *proto_table); int xproto_register(const xproto_table_t *proto_table);
void xproto_unregister(const xproto_table_t *proto_table); void xproto_unregister(const xproto_table_t *proto_table);
const xproto_entry_t *xproto_global_entry(__u8 opcode); const xproto_entry_t *xproto_global_entry(__u8 opcode);