mISDN/drivers/isdn/hardware/mISDN/arcofi.c

150 lines
3.4 KiB
C

/* $Id$
*
* arcofi.c Ansteuerung ARCOFI 2165
*
* Author Karsten Keil (keil@isdn4linux.de)
*
* This file is (c) under GNU PUBLIC LICENSE
*
*/
#include "channel.h"
#include "layer1.h"
#include "isac.h"
#include "arcofi.h"
#include "debug.h"
#include "helper.h"
#define ARCOFI_TIMER_VALUE 20
static void
add_arcofi_timer(channel_t *dch) {
isac_chip_t *isac = dch->hw;
if (test_and_set_bit(FLG_ARCOFI_TIMER, &dch->Flags)) {
del_timer(&isac->arcofitimer);
}
init_timer(&isac->arcofitimer);
isac->arcofitimer.expires = jiffies + ((ARCOFI_TIMER_VALUE * HZ)/1000);
add_timer(&isac->arcofitimer);
}
static void
send_arcofi(channel_t *dch) {
u_char val;
isac_chip_t *isac = dch->hw;
add_arcofi_timer(dch);
isac->mon_txp = 0;
isac->mon_txc = isac->arcofi_list->len;
memcpy(isac->mon_tx, isac->arcofi_list->msg, isac->mon_txc);
switch(isac->arcofi_bc) {
case 0: break;
case 1: isac->mon_tx[1] |= 0x40;
break;
default: break;
}
isac->mocr &= 0x0f;
isac->mocr |= 0xa0;
dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
val = dch->read_reg(dch->inst.privat, ISAC_MOSR);
dch->write_reg(dch->inst.privat, ISAC_MOX1, isac->mon_tx[isac->mon_txp++]);
isac->mocr |= 0x10;
dch->write_reg(dch->inst.privat, ISAC_MOCR, isac->mocr);
}
int
arcofi_fsm(channel_t *dch, int event, void *data) {
isac_chip_t *isac = dch->hw;
if (dch->debug & L1_DEB_MONITOR) {
mISDN_debugprint(&dch->inst, "arcofi state %d event %d", isac->arcofi_state, event);
}
if (event == ARCOFI_TIMEOUT) {
isac->arcofi_state = ARCOFI_NOP;
test_and_set_bit(FLG_ARCOFI_ERROR, &dch->Flags);
wake_up(&isac->arcofi_wait);
return(1);
}
switch (isac->arcofi_state) {
case ARCOFI_NOP:
if (event == ARCOFI_START) {
isac->arcofi_list = data;
isac->arcofi_state = ARCOFI_TRANSMIT;
send_arcofi(dch);
}
break;
case ARCOFI_TRANSMIT:
if (event == ARCOFI_TX_END) {
if (isac->arcofi_list->receive) {
add_arcofi_timer(dch);
isac->arcofi_state = ARCOFI_RECEIVE;
} else {
if (isac->arcofi_list->next) {
isac->arcofi_list =
isac->arcofi_list->next;
send_arcofi(dch);
} else {
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &dch->Flags)) {
del_timer(&isac->arcofitimer);
}
isac->arcofi_state = ARCOFI_NOP;
wake_up(&isac->arcofi_wait);
}
}
}
break;
case ARCOFI_RECEIVE:
if (event == ARCOFI_RX_END) {
struct sk_buff *skb = data;
// FIXME handle message
if (skb)
kfree_skb(skb);
else
int_error();
if (isac->arcofi_list->next) {
isac->arcofi_list =
isac->arcofi_list->next;
isac->arcofi_state = ARCOFI_TRANSMIT;
send_arcofi(dch);
} else {
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &dch->Flags)) {
del_timer(&isac->arcofitimer);
}
isac->arcofi_state = ARCOFI_NOP;
wake_up(&isac->arcofi_wait);
}
}
break;
default:
mISDN_debugprint(&dch->inst, "Arcofi unknown state %x", isac->arcofi_state);
return(2);
}
return(0);
}
static void
arcofi_timer(channel_t *dch) {
arcofi_fsm(dch, ARCOFI_TIMEOUT, NULL);
}
void
clear_arcofi(channel_t *dch) {
isac_chip_t *isac = dch->hw;
if (test_and_clear_bit(FLG_ARCOFI_TIMER, &dch->Flags)) {
del_timer(&isac->arcofitimer);
}
}
void
init_arcofi(channel_t *dch) {
isac_chip_t *isac = dch->hw;
isac->arcofitimer.function = (void *) arcofi_timer;
isac->arcofitimer.data = (long) dch;
init_timer(&isac->arcofitimer);
dch->type |= ISAC_TYPE_ARCOFI;
}