diff options
Diffstat (limited to 'sys/dev/ce/ceddk.c')
-rw-r--r-- | sys/dev/ce/ceddk.c | 1522 |
1 files changed, 1522 insertions, 0 deletions
diff --git a/sys/dev/ce/ceddk.c b/sys/dev/ce/ceddk.c new file mode 100644 index 0000000..bc98012 --- /dev/null +++ b/sys/dev/ce/ceddk.c @@ -0,0 +1,1522 @@ +/* + * Middle-level code for Cronyx Tau32-PCI adapters. + * + * Copyright (C) 2004 Cronyx Engineering + * Copyright (C) 2004 Roman Kurakin <rik@FreeBSD.org> + * + * This software is distributed with NO WARRANTIES, not even the implied + * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * Authors grant any other persons or organisations a permission to use, + * modify and redistribute this software in source and binary forms, + * as long as this message is kept with the software, all derivative + * works or modified versions. + * + * $Cronyx: ceddk.c,v 1.2.6.2 2005/11/17 16:04:13 rik Exp $ + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <dev/cx/machdep.h> +#include <dev/ce/ceddk.h> + +#undef CE_DDK_DEBUG_ENABLED +#ifdef CE_DDK_DEBUG_ENABLED +#ifdef __FreeBSD__ +# define CE_DDK_DEBUG(b,c,s) \ + do { \ + if (c) { \ + printf("ce%d-%d: ",(b)->num,(c)->num); \ + } else { \ + printf("ce%d-*: ",(b)->num); \ + } \ + printf s; \ + } while (0) +#else +# define CE_DDK_DEBUG(b,c,s) do {} while (0) +#endif +#else +# define CE_DDK_DEBUG(b,c,s) do {} while (0) +#endif + +#if 0 +#define ENTER() \ + static int enter=0; \ + do { \ + enter++; \ + printf ("%s: >> enter (%16llx) %d\n", __FUNCTION__, rdtsc (), enter); \ + } while (0) + +#define EXIT(val...) \ + do { \ + enter--; \ + printf ("%s: << exit (%16llx) %d line %d\n", __FUNCTION__, rdtsc (), enter, __LINE__); \ + return val; \ + } while (0) +#else +#define ENTER() \ + do {} while (0) + +#define EXIT(val...) \ + do {return val;} while (0) +#endif + +#define CE_ENQUEUE(list,item) \ + do { \ + TAU32_UserRequest **last; \ + last = &(list); \ + while (*last) { \ + last = &(*last)->next; \ + } \ + (*last) = (item); \ + (item)->next = NULL; \ + } while (0) + +#define CE_ENQUEUE_HEAD(list,item) \ + do { \ + (item)->next = list; \ + list = item; \ + } while (0) + +#define CE_DEQUEUE(list,item) \ + do { \ + item = list; \ + if (list) { \ + list = (item)->next; \ + } \ + } while (0) + +#define CE_PREREQUEST(b,c,list,item) \ + do { \ + item = list; \ + if (!item) { \ + CE_DDK_DEBUG (b, c, ("Fatal error, no free structs " \ + "for UserRequest (%s:%d)\n", \ + __FUNCTION__, __LINE__)); \ + } \ + } while (0) + +#define CE_DUMP_QUEUE(list) \ + do { \ + TAU32_UserRequest *item; \ + int i = 0; \ + item = list; \ + while (item) { \ + printf ("item%d: %p\n", i, item); \ + item = item->next; \ + i++; \ + } \ + } while (0) + +#define CE_FIND_ITEM(list,item,flag) \ + do { \ + TAU32_UserRequest *citem; \ + flag = 0; \ + for (citem = list; citem; citem = citem->next) { \ + if (citem == item) { \ + flag = 1; \ + break; \ + } \ + } \ + } while (0) + +#define CE_LAST_ITEM(list,item) \ + do { \ + TAU32_UserRequest **last; \ + last = &(list); \ + while ((*last) && (*last)->next) { \ + last = &(*last)->next; \ + } \ + (item) = (*last); \ + } while (0) + +#define CE_ASSERT(a) \ + do { \ + if (!(a)) { \ + printf ("ASSERT: %d %s\n", __LINE__, #a); \ + __asm __volatile ("int $3"); \ + } \ + } while (0) + +static void _ce_set_ts (ce_chan_t *c, unsigned long ts); +static void _ce_submit_configure_e1 (ce_chan_t *c, char *rname); + +#ifdef CE_DDK_DEBUG_ENABLED +static char *ce_err2str (unsigned long err) +{ + switch (err) { + case TAU32_SUCCESSFUL: + return "Successful"; + case TAU32_ERROR_ALLOCATION: + return "Allocation error, not enough tx/rx descriptors"; + case TAU32_ERROR_BUS: + return "PEB could not access to host memory by PCI bus for load/store information"; + case TAU32_ERROR_FAIL: + return "PEB action request failed"; + case TAU32_ERROR_TIMEOUT: + return "PEB action request timeout"; + case TAU32_ERROR_CANCELLED: + return "request has been canceled"; + case TAU32_ERROR_TX_UNDERFLOW: + return "transmission underflow"; + case TAU32_ERROR_TX_PROTOCOL: + return "TX_PROTOCOL"; + case TAU32_ERROR_RX_OVERFLOW: + return "RX_OVERFLOW"; + case TAU32_ERROR_RX_ABORT: + return "RX_ABORT"; + case TAU32_ERROR_RX_CRC: + return "RX_CRC"; + case TAU32_ERROR_RX_SHORT: + return "RX_SHORT"; + case TAU32_ERROR_RX_SYNC: + return "RX_SYNC"; + case TAU32_ERROR_RX_FRAME: + return "RX_FRAME"; + case TAU32_ERROR_RX_LONG: + return "RX_LONG"; + case TAU32_ERROR_RX_SPLIT: + return "frame has splitted between two requests due rx-gap allocation"; + case TAU32_ERROR_RX_UNFIT: + return "frame can't be fit into request buffer"; + case TAU32_ERROR_TSP: + return "ERROR_TSP"; + case TAU32_ERROR_RSP: + return "ERROR_RSP"; + case TAU32_ERROR_INT_OVER_TX: + return "ERROR INT OVER TX"; + case TAU32_ERROR_INT_OVER_RX: + return "ERROR INT OVER RX"; + case TAU32_ERROR_INT_STORM: + return "irq storm"; + case TAU32_ERROR_INT_E1LOST: + return "ERROR_E1LOST"; + default: + return ("Unknown error"); + } +} +#endif + +void ce_set_dtr (ce_chan_t *c, int on) +{ + c->dtr = on?1:0; +} + +void ce_set_rts (ce_chan_t *c, int on) +{ + c->rts = on?1:0; +} + +static void TAU32_CALLBACK_TYPE ce_on_receive + (TAU32_UserContext *pContext, TAU32_UserRequest *req) +{ + ce_buf_item_t *item = (ce_buf_item_t *)req; + ce_chan_t *c; + ce_board_t *b; + unsigned int error; + int len; + + ENTER (); + if (!req || !req->sys) { + EXIT (); + } + + c = (ce_chan_t *)req->sys; + b = c->board; + + len = req->Io.Rx.Received; + error = req->ErrorCode; + + c->rintr++; + if (error == TAU32_SUCCESSFUL) { + if (req->Io.Rx.FrameEnd) { + c->ipkts++; + } else { + CE_DDK_DEBUG (b, c, ("No FrameEnd\n")); + /* probably do something in some cases*/ + } + c->ibytes += len; + if (c->receive) + c->receive (c, item->buf, len); + } else if (error & TAU32_ERROR_BUS) { + c->overrun++; + if (c->error) + c->error (c, CE_OVERRUN); + } else { + CE_DDK_DEBUG (b, c, ("Another receive error: %x\n", error)); + /* Do some procesing */ + } + + CE_ASSERT (!req->pInternal); + CE_ENQUEUE (c->rx_queue, req); + while (c->rx_queue) { + CE_DEQUEUE (c->rx_queue, req); + CE_ASSERT (req); + item = (ce_buf_item_t *)req; + req->Command = TAU32_Rx_Data; + req->Io.Rx.Channel = c->num; + req->pCallback = ce_on_receive; + req->Io.Rx.BufferLength = BUFSZ+4; + req->Io.Rx.PhysicalDataAddress = item->phys; + if (!TAU32_SubmitRequest (b->ddk.pControllerObject, req)) { + CE_DDK_DEBUG (b, c, ("RX submition failure\n")); + c->rx_pending--; + CE_ENQUEUE_HEAD (c->rx_queue, req); + break; + } + } + EXIT (); +} + +static void TAU32_CALLBACK_TYPE ce_on_transmit + (TAU32_UserContext *pContext, TAU32_UserRequest *req) +{ + int len; + unsigned int error; + ce_chan_t *c; + ENTER (); + + if (!req || !req->sys) { + EXIT (); + } + + c = (ce_chan_t *)req->sys; + + len = req->Io.Tx.Transmitted; + error = req->ErrorCode; + + c->tintr++; + if (error == TAU32_SUCCESSFUL) { + c->obytes += len; + c->opkts++; + } else if (error & TAU32_ERROR_BUS) { + c->underrun++; + if (c->error) + c->error (c, CE_UNDERRUN); + } else { + CE_DDK_DEBUG (c->board, c, ("Another transmit error: %x\n", + error)); + /* Do some procesing */ + } + + CE_ENQUEUE (c->tx_queue, req); + c->tx_pending--; + + if (c->transmit) + c->transmit (c, 0, len); + EXIT (); +} + +int ce_transmit_space (ce_chan_t *c) +{ + return c->tx_pending < (TAU32_IO_QUEUE); +} + +int ce_send_packet (ce_chan_t *c, unsigned char *buf, int len, void *tag) +{ + TAU32_UserRequest *req; + ce_buf_item_t *item; + + ENTER (); + + if (!ce_transmit_space (c)) { + EXIT (-1); + } + + if (len <= 0 || len > BUFSZ) { + EXIT (-2); + } + + CE_DEQUEUE (c->tx_queue, req); + CE_ASSERT (req); + item = (ce_buf_item_t *)req; + + if (buf != item->buf) + memcpy (item->buf, buf, len); + + CE_ASSERT (!req->pInternal); + + req->Command = TAU32_Tx_Data | TAU32_Tx_FrameEnd; + req->Io.Tx.Channel = c->num; + req->pCallback = ce_on_transmit; + req->Io.Tx.DataLength = len; + req->Io.Tx.PhysicalDataAddress = item->phys; + c->tx_pending++; + if (!TAU32_SubmitRequest (c->board->ddk.pControllerObject, req)) { + CE_DDK_DEBUG (c->board, c, ("Can't submit packet for " + "transmission\n")); + CE_ENQUEUE_HEAD (c->tx_queue, req); + c->tx_pending--; + EXIT (-3); + } + EXIT (0); +} + +static void TAU32_CALLBACK_TYPE ce_on_config + (TAU32_UserContext *pContext, TAU32_UserRequest *req) +{ + ce_board_t *b = (ce_board_t *) pContext; + ENTER (); + b->cr.pending--; + if (req->ErrorCode) + CE_DDK_DEBUG (b, (ce_chan_t*)0, ("Config request failure: %lx\n", + req->ErrorCode)); + EXIT (); +} + +static void TAU32_CALLBACK_TYPE ce_on_config_stop + (TAU32_UserContext *pContext, TAU32_UserRequest *req) +{ + int i, first; + TAU32_UserRequest *rreq; + ce_board_t *b = (ce_board_t *) pContext; + ce_chan_t *c = b->chan + req->Io.ChannelNumber; + + ENTER (); + /* Stop all requests */ + CE_ASSERT (0);/* Buggy */ + CE_LAST_ITEM (c->rx_queue, rreq); + /* A little hacky, try to guess which is a first */ + first = rreq ? (c->rx_item - (ce_buf_item_t *)rreq) + 1 : 0; + for (i = 0; i < TAU32_IO_QUEUE; i++) { + int is_pending; + rreq = &c->rx_item[(i + first) % TAU32_IO_QUEUE].req; + CE_FIND_ITEM (c->rx_queue, rreq, is_pending); + if (!is_pending) + continue; + TAU32_CancelRequest (b->ddk.pControllerObject, rreq, 1); + rreq->Command = TAU32_Rx_Data; + rreq->Io.Rx.Channel = c->num; + rreq->Io.Rx.BufferLength = BUFSZ+4; + rreq->Io.Rx.PhysicalDataAddress = ((ce_buf_item_t *)rreq)->phys; + c->rx_pending++; + if (!TAU32_SubmitRequest (b->ddk.pControllerObject, rreq)) { + CE_ASSERT (0);/* Buggy */ + c->rx_pending--; + break; + } + } + + c->tx_pending = 0; +/* c->rx_pending = 0;*/ + EXIT (); +} + +static int ce_cfg_submit (ce_board_t *b) +{ + TAU32_UserRequest *req; + ENTER (); + + CE_DEQUEUE (b->cr.queue, req); + CE_ASSERT (req); + CE_ASSERT (!req->pInternal); + + req->pCallback = ce_on_config; + b->cr.pending++; + + CE_DDK_DEBUG (b, (ce_chan_t *)0, ("config request pending: %d\n", + b->cr.pending)); + + if (!TAU32_SubmitRequest (b->ddk.pControllerObject, req)) { + CE_ENQUEUE_HEAD (b->cr.queue, req); + CE_DDK_DEBUG (b, (ce_chan_t *)0, ("Fail to submit config request\n")); + b->cr.pending--; + EXIT (0); + } + + EXIT (1); +} + +void ce_init_board (ce_board_t *b) +{ + int i; + + b->cr.queue = NULL; + + for (i = 0; i < CONFREQSZ; i++) { + CE_ENQUEUE (b->cr.queue, b->cr.req + i); + } + + b->chan[0].config = TAU32_ais_on_loss; + + /* lloop = off, rloop = off */ + b->chan[0].config |= TAU32_LineNormal; + b->chan[0].lloop = 0; + b->chan[0].rloop = 0; + + /* unfram=off, scrambler=off, use16=off, crc4=off, + higain=off, monitor=off*/ + b->chan[0].config |= (b->ddk.Interfaces == 2 ? TAU32_framed_cas_cross : + TAU32_framed_cas_set); + b->chan[0].unfram = 0; + b->chan[0].scrambler = 0; + b->chan[0].use16 = 0; + b->chan[0].crc4 = 0; + b->chan[0].higain = 0; + b->chan[0].monitor = 0; + + if (b->ddk.Interfaces == 2) { + b->chan[1].config = TAU32_ais_on_loss; + /* lloop = off, rloop = off */ + b->chan[1].config |= TAU32_LineNormal; + /* unfram=off, scrambler=off, use16=off, crc4=off, + higain=off, monitor=off*/ + b->chan[1].config |= TAU32_framed_cas_cross; + b->chan[1].unfram = 0; + b->chan[1].scrambler = 0; + b->chan[1].use16 = 0; + b->chan[1].crc4 = 0; + b->chan[1].higain = 0; + b->chan[1].monitor = 0; + } + + for (i = 0; i < NCHAN; i++) { + /* Chan0 ts=1-15,17-31, Chan1 ts=1-2 */ + b->chan[i].type = i < b->ddk.Interfaces ? T_E1 : T_DATA; + b->chan[i].ts = (i == 0 ? 0xfffefffe : + (i != 1 ? 0 : + (b->ddk.Interfaces == 2 ? 0x6: 0))); + b->chan[i].dir = (b->ddk.Interfaces == 2) ? (i%2) : 0; + b->chan[i].mtu = 1504; + } +#if 0 + /* c->num == 0 */ + req = b->cr.queue; + /* We must have some here */ + CE_ASSERT (req); + req->Command = TAU32_Configure_E1; + req->Io.InterfaceConfig.Interface = TAU32_E1_A; + req->Io.InterfaceConfig.Config = b->chan[0].config; + req->Io.InterfaceConfig.UnframedTsMask = 0; + if (!ce_cfg_submit (b)) { + CE_DDK_DEBUG (b, b->chan + 0, + ("Submit request failure, line %d\n", + __LINE__)); + } + /* c->num == 1 */ + if (b->ddk.Interfaces == 2) { + req = b->cr.queue; + /* We must have some here */ + CE_ASSERT (req); + req->Command = TAU32_Configure_E1; + req->Io.InterfaceConfig.Interface = TAU32_E1_B; + req->Io.InterfaceConfig.Config = b->chan[1].config; + req->Io.InterfaceConfig.UnframedTsMask = 0; + if (!ce_cfg_submit (b)) { + CE_DDK_DEBUG (b, b->chan + 1, + ("Submit request failure, line %d\n", + __LINE__)); + } + } +#endif + /* Set default cross matrix */ + for (i = 0; i < 32; i++) { + /* -X-> Peb */ + b->dxc[i] = TAU32_CROSS_OFF; + /* Link2 -> Link1 */ + b->dxc[i + 32] = i + 64; + /* Link1 -> Link2 */ + b->dxc[i + 64] = i + 32; + } + + /* We have only mux mode for now. Later we will also have cross mode */ + b->mux = 1; +} + +void ce_start_chan (ce_chan_t *c, int tx, int rx, ce_buf_t *cb, + unsigned long phys) +{ + int i; + ce_board_t *b = c->board; + +/* c->config = TAU32_ais_on_loss | TAU32_framed_cas_cross;*/ + + if (cb) { + CE_DDK_DEBUG (b, c, ("ce_buf_t virt:%p phys:%p\n", cb, + (void *)phys)); + c->tx_item = cb->tx_item; + c->rx_item = cb->rx_item; + c->tx_queue = NULL; + c->rx_queue = NULL; + for (i = 0; i < TAU32_IO_QUEUE; i++) { + c->tx_item[i].phys = phys + + ((char *)(c->tx_item[i].buf)-(char *)cb); + c->rx_item[i].phys = phys + + ((char *)(c->rx_item[i].buf)-(char *)cb); + cb->tx_item[i].req.sys = c; + cb->rx_item[i].req.sys = c; + CE_DDK_DEBUG (b, c, ("tx_item[%d].buf virt:%p phys:%p\n", + i, c->tx_item[i].buf, + (void *)c->tx_item[i].phys)); + CE_DDK_DEBUG (b, c, ("rx_item[%d].buf virt:%p phys:%p\n", + i, c->rx_item[i].buf, + (void *)c->rx_item[i].phys)); + CE_ENQUEUE (c->rx_queue, &c->rx_item[i].req); + CE_ENQUEUE (c->tx_queue, &c->tx_item[i].req); + } + c->tx_pending = 0; + c->rx_pending = 0; + } + + /* submit rx */ + while (1) { + ce_buf_item_t *item; + TAU32_UserRequest *req; + + CE_DEQUEUE (c->rx_queue, req); + if (!req) + break; + item = (ce_buf_item_t *) req; + CE_ASSERT (c->rx_pending < TAU32_IO_QUEUE); + req->Command = TAU32_Rx_Data; + req->Io.Rx.Channel = c->num; + req->pCallback = ce_on_receive; + req->Io.Rx.BufferLength = c->mtu + (c->phony ? 0 : 4); + req->Io.Rx.PhysicalDataAddress = item->phys; + c->rx_pending++; + if (!TAU32_SubmitRequest (b->ddk.pControllerObject, req)) { + CE_DDK_DEBUG (b, c, ("Faild to submit rx request\n")); + /*XXXRIK: shouldn't happen, but ... */ + CE_ASSERT (0); + c->rx_pending--; + break; + } + } + + if (tx | rx) { + TAU32_UserRequest *req; + CE_PREREQUEST (b, c, b->cr.queue, req); + if (!req) + return; + req->Command = TAU32_Configure_Commit | + (tx ? TAU32_Tx_Start : 0) | + (rx ? TAU32_Rx_Start : 0); + req->Io.ChannelNumber = c->num; + if (!ce_cfg_submit (b)) { + CE_DDK_DEBUG (b, c, ("Can't start chan\n")); + /* Do some error processing */ + return; + } + } + + /* If we run just after ce_board_init we have prope values. + * Else I hope you didn't set ts to incorrect value. + */ + _ce_set_ts (c, c->ts); + if (c->num < b->ddk.Interfaces) { + /* The same for other modes. We don't check them. + * We hope that config is correctly set. Just as we have + * after ce_board_init. If channel was stoped we hope that + * it's config was not broken just after it and we didn't + * brake it before start. + */ + _ce_submit_configure_e1 (c, "start_init"); + } +} + +void ce_stop_chan (ce_chan_t *c) +{ + ce_board_t *b = c->board; + TAU32_UserRequest *req; + CE_DEQUEUE (b->cr.queue, req); + + /* XXXRIK: This function should be for comleteness, but for now I + * don't use it. So I just start to write and didn't finished it yet. + * It and it is VERY BUGGY!!! Do not use it. If you realy + * need it ask me to fix it or rewrite it by your self. + * Note: most buggy part of it in ce_on_config_stop! + */ + if (!req) { + CE_DDK_DEBUG (b, c, ("Fatal error, no free structs for " + "UserRequest (%s:%d)\n", __FUNCTION__, __LINE__)); + return; + } + req->Command = TAU32_Configure_Commit | + TAU32_Tx_Stop | TAU32_Rx_Stop; + req->Command = 0; + req->Io.ChannelNumber = c->num; + req->pCallback = ce_on_config_stop; + b->cr.pending++; + + if (!TAU32_SubmitRequest (b->ddk.pControllerObject, req)) { + CE_ENQUEUE_HEAD (b->cr.queue, req); + CE_DDK_DEBUG (b, c, ("Can't stop chan\n")); + b->cr.pending--; + } +} + + +void ce_register_transmit (ce_chan_t *c, + void (*func) (ce_chan_t*, void*, int)) +{ + c->transmit = func; +} + +void ce_register_receive (ce_chan_t *c, + void (*func) (ce_chan_t*, unsigned char*, int)) +{ + c->receive = func; +} + +void ce_register_error (ce_chan_t *c, + void (*func) (ce_chan_t*, int)) +{ + c->error = func; +} + +void TAU32_CALLBACK_TYPE ce_error_callback (TAU32_UserContext *pContext, + int Item, unsigned NotifyBits) +{ + ce_board_t *b = (ce_board_t *) pContext; + ENTER (); + if (NotifyBits & (TAU32_ERROR_FAIL | TAU32_ERROR_TIMEOUT + | TAU32_ERROR_INT_OVER_TX | TAU32_ERROR_INT_OVER_RX + | TAU32_ERROR_INT_STORM)) { + /* Fatal: adapter failure, need reset & restart */ + /* RIKXXX: probably I should add CE_FAILURE for ce_error */ + CE_DDK_DEBUG (b, (ce_chan_t *)0, ("Err, disable interrupts: %s\n", + ce_err2str (NotifyBits))); +/* TAU32_DisableInterrupts (b->ddk.pControllerObject);*/ + EXIT (); + } + if (Item >= 0) { + /* channel error */ + ce_chan_t *c = b->chan + Item; + if (NotifyBits & TAU32_ERROR_TX_UNDERFLOW) { + c->underrun++; + if (c->error) + c->error (c, CE_UNDERRUN); + } + if (NotifyBits & TAU32_ERROR_RX_OVERFLOW) { + c->overrun++; + if (c->error) + c->error (c, CE_OVERFLOW); + } + if (NotifyBits & (TAU32_ERROR_RX_FRAME | TAU32_ERROR_RX_ABORT | + TAU32_ERROR_RX_SHORT | TAU32_ERROR_RX_LONG | + TAU32_ERROR_RX_SYNC | TAU32_ERROR_RX_SPLIT | + TAU32_ERROR_RX_UNFIT)) { + c->frame++; + CE_DDK_DEBUG (b, c, ("Frame error: %x\n", NotifyBits)); + if (c->error) + c->error (c, CE_FRAME); + } + if(NotifyBits & TAU32_ERROR_RX_CRC) { + c->crc++; + if (c->error) + c->error (c, CE_CRC); + } + } else { + CE_DDK_DEBUG (b, (ce_chan_t *)0, ("Another error: %x\n", + NotifyBits)); + /* Adapter error, do smth */ + } + EXIT (); +} + +void TAU32_CALLBACK_TYPE ce_status_callback(TAU32_UserContext *pContext, + int Item, unsigned NotifyBits) +{ + ce_board_t *b = (ce_board_t *) pContext; + ENTER (); + if(Item >= 0) { + /* e1 status */ + ce_chan_t *c = b->chan + Item; + c->acc_status |= b->ddk.InterfacesInfo[Item].Status; +/* CE_DDK_DEBUG (b, c, ("Current status: %x\n", c->acc_status));*/ + } else { + CE_DDK_DEBUG (b, (ce_chan_t *)0, ("Another status: %x\n", NotifyBits)); + /* Adapter status, do smth. */ + } + EXIT (); +} + +int ce_get_cd (ce_chan_t *c) +{ + unsigned int e1status = c->board->ddk.InterfacesInfo[c->dir].Status; + + return (c->ts && !(e1status & (TAU32_RCL | TAU32_E1OFF))); +} + +int ce_get_cts (ce_chan_t *c) +{ + return 0; +} + +int ce_get_dsr (ce_chan_t *c) +{ + return 0; +} + +void ce_e1_timer (ce_chan_t *c) +{ + unsigned bpv, fas, crc4, ebit, pcv, oof, css; + unsigned int acc_status; + ce_board_t *b = c->board; + TAU32_E1_State *state; + + if (c->num >= b->ddk.Interfaces) + return; + + state = &b->ddk.InterfacesInfo[c->num]; + acc_status = c->acc_status; + + /* Clear acc_status */ + c->acc_status = b->ddk.InterfacesInfo[c->num].Status; + + /* Count seconds. + * During the first second after the channel startup + * the status registers are not stable yet, + * we will so skip the first second. */ + ++c->cursec; + if (! c->totsec && c->cursec <= 1) + return; + + c->status = 0; + + /* Compute the SNMP-compatible channel status. */ + oof = 0; + + if (acc_status & TAU32_RCL) + c->status |= ESTS_LOS; /* loss of signal */ + if (acc_status & TAU32_RUA1) + c->status |= ESTS_AIS; /* receiving all ones */ + + /* Get error counters. */ + bpv = state->RxViolations; + fas = 0; + crc4 = 0; + ebit = 0; + css = 0; + + if (! c->unfram) { + if (! c->use16 && (acc_status & TAU32_RSA1)) + c->status |= ESTS_AIS16; /* signaling all ones */ + if (! c->use16 && (acc_status & TAU32_RDMA)) + c->status |= ESTS_FARLOMF; /* alarm in timeslot 16 */ + if (acc_status & TAU32_RRA) + c->status |= ESTS_FARLOF; /* far loss of framing */ + + if (acc_status & TAU32_RFAS) { + c->status |= ESTS_LOF; /* loss of framing */ + ++oof; /* out of framing */ + } + if ((! c->use16 && (acc_status & TAU32_RCAS)) || + (c->crc4 && (acc_status & TAU32_RCRC4))) { + c->status |= ESTS_LOMF; /* loss of multiframing */ + ++oof; /* out of framing */ + } + fas = state->FasErrors; + crc4 = state->Crc4Errors; + ebit = state->FarEndBlockErrors; + + /* Controlled slip second -- any slip event. */ + css = state->TransmitSlips + state->ReceiveSlips; + } + + /* Clear state */ + state->RxViolations = 0; + state->FasErrors = 0; + state->Crc4Errors = 0; + state->FarEndBlockErrors = 0; + state->TransmitSlips = 0; + state->ReceiveSlips = 0; + + if (c->status & ESTS_LOS) + c->status = ESTS_LOS; + else if (c->status & ESTS_AIS) + c->status = ESTS_AIS; + else if (c->status & ESTS_LOF) + c->status = ESTS_LOF; + else if (c->status & ESTS_LOMF) + c->status &= ~(ESTS_FARLOMF | ESTS_AIS16); + + if (! c->status) + c->status = ESTS_NOALARM; + + c->currnt.bpv += bpv; + c->currnt.fse += fas; + if (c->crc4) { + c->currnt.crce += crc4; + c->currnt.rcrce += ebit; + } + + /* Path code violation is frame sync error if CRC4 disabled, + * or CRC error if CRC4 enabled. */ + pcv = fas; + if (c->crc4) + pcv += crc4; + + /* Unavaiable second -- receiving all ones, or + * loss of carrier, or loss of signal. */ + if (acc_status & (TAU32_RUA1 | TAU32_RCL)) + /* Unavailable second -- no other counters. */ + ++c->currnt.uas; + else { + /* Line errored second -- any BPV. */ + if (bpv) + ++c->currnt.les; + + /* Errored second -- any PCV, or out of frame sync, + * or any slip events. */ + if (pcv || oof || css) + ++c->currnt.es; + + /* Severely errored framing second -- out of frame sync. */ + if (oof) + ++c->currnt.oofs; + + /* Severely errored seconds -- + * 832 or more PCVs, or 2048 or more BPVs. */ + if (bpv >= 2048 || pcv >= 832) + ++c->currnt.ses; + else { + /* Bursty errored seconds -- + * no SES and more than 1 PCV. */ + if (pcv > 1) + ++c->currnt.bes; + + /* Collect data for computing + * degraded minutes. */ + ++c->degsec; + c->degerr += bpv + pcv; + } + } + + /* Degraded minutes -- having error rate more than 10e-6, + * not counting unavailable and severely errored seconds. */ + if (c->cursec % 60 == 0) { + if (c->degerr > c->degsec * 2048 / 1000) + ++c->currnt.dm; + c->degsec = 0; + c->degerr = 0; + } + + /* Rotate statistics every 15 minutes. */ + if (c->cursec > 15*60) { + int i; + + for (i=47; i>0; --i) + c->interval[i] = c->interval[i-1]; + c->interval[0] = c->currnt; + + /* Accumulate total statistics. */ + c->total.bpv += c->currnt.bpv; + c->total.fse += c->currnt.fse; + c->total.crce += c->currnt.crce; + c->total.rcrce += c->currnt.rcrce; + c->total.uas += c->currnt.uas; + c->total.les += c->currnt.les; + c->total.es += c->currnt.es; + c->total.bes += c->currnt.bes; + c->total.ses += c->currnt.ses; + c->total.oofs += c->currnt.oofs; + c->total.css += c->currnt.css; + c->total.dm += c->currnt.dm; + c->currnt.bpv = 0; + c->currnt.fse = 0; + c->currnt.crce = 0; + c->currnt.rcrce = 0; + c->currnt.uas = 0; + c->currnt.les = 0; + c->currnt.es = 0; + c->currnt.bes = 0; + c->currnt.ses = 0; + c->currnt.oofs = 0; + c->currnt.css = 0; + c->currnt.dm = 0; + + c->totsec += c->cursec; + c->cursec = 0; + } +} + +void ce_set_baud (ce_chan_t *c, unsigned long baud) +{ + TAU32_UserRequest *req; + ce_board_t *b = c->board; + unsigned long cfg = c->config & ~TAU32_framing_mode_mask; + unsigned long ts; + unsigned long kbps = (baud + 32000) / 64000 * 64; + + if (!c->unfram || c->num != 0 || + baud == c->baud || b->cr.pending >= CONFREQSZ) + return; + + if (!kbps || kbps > 1024) { + ts = 0xffffffffUL; + cfg |= TAU32_unframed_2048; + } else if (kbps > 512) { + ts = 0x0000ffffUL; + cfg |= TAU32_unframed_1024; + } else if (kbps > 256) { + ts = 0x000000ffUL; + cfg |= TAU32_unframed_512; + } else if (kbps > 128) { + ts = 0x0000000fUL; + cfg |= TAU32_unframed_256; + } else if (kbps > 64) { + ts = 0x00000003UL; + cfg |= TAU32_unframed_128; + } else { + ts = 0x00000001UL; + cfg |= TAU32_unframed_64; + } + + /* _ce_set_ts () will set proper baud */ + _ce_set_ts (c, ts); + CE_PREREQUEST (b, c, b->cr.queue, req); + if (!req) + return; + req->Command = TAU32_Configure_E1; + req->Io.InterfaceConfig.Interface = TAU32_E1_A; + req->Io.InterfaceConfig.Config = cfg; + req->Io.InterfaceConfig.UnframedTsMask = ts; + if (ce_cfg_submit (b)) { + c->baud = baud; + c->ts = ts; + c->config = cfg; + } +} + +void ce_set_lloop (ce_chan_t *c, unsigned char on) +{ + TAU32_UserRequest *req; + unsigned long cfg = c->config & ~(TAU32_line_mode_mask | TAU32_ais_on_loss); + ce_board_t *b = c->board; + + if (c->num >= b->ddk.Interfaces || b->cr.pending >= CONFREQSZ) + return; + on = on ? 1 : 0; + if (on == c->lloop) + return; + + cfg |= on ? TAU32_LineLoopInt : (TAU32_LineNormal | TAU32_ais_on_loss); + CE_PREREQUEST (b, c, b->cr.queue, req); + if (!req) + return; + req->Command = TAU32_Configure_E1; + req->Io.InterfaceConfig.Interface = c->num ? TAU32_E1_B : TAU32_E1_A; + req->Io.InterfaceConfig.Config = cfg; + req->Io.InterfaceConfig.UnframedTsMask = c->ts; + CE_DDK_DEBUG (b, c, ("Submit lloop\n")); + if (ce_cfg_submit (b)) { + c->lloop = on ? 1 : 0; + c->config = cfg; + } +} + +void ce_set_rloop (ce_chan_t *c, unsigned char on) +{ + TAU32_UserRequest *req; + unsigned long cfg = c->config & ~TAU32_line_mode_mask; + ce_board_t *b = c->board; + + if (c->num >= b->ddk.Interfaces || b->cr.pending >= CONFREQSZ) + return; + on = on ? 1 : 0; + if (on == c->rloop) + return; + + cfg |= on ? TAU32_LineLoopExt : TAU32_LineNormal; + CE_PREREQUEST (b, c, b->cr.queue, req); + if (!req) + return; + req->Command = TAU32_Configure_E1; + req->Io.InterfaceConfig.Interface = c->num ? TAU32_E1_B : TAU32_E1_A; + req->Io.InterfaceConfig.Config = cfg; + req->Io.InterfaceConfig.UnframedTsMask = c->ts; + CE_DDK_DEBUG (b, c, ("Submit rloop\n")); + if (ce_cfg_submit (b)) { + c->rloop = on ? 1 : 0; + c->config = cfg; + } +} + +void ce_set_higain (ce_chan_t *c, unsigned char on) +{ + TAU32_UserRequest *req; + unsigned long cfg = c->config & ~TAU32_higain; + ce_board_t *b = c->board; + + if (c->num >= b->ddk.Interfaces || b->cr.pending >= CONFREQSZ) + return; + on = on ? 1 : 0; + if (on == c->higain) + return; + + cfg |= on ? TAU32_higain : 0; + CE_PREREQUEST (b, c, b->cr.queue, req); + if (!req) + return; + req->Command = TAU32_Configure_E1; + req->Io.InterfaceConfig.Interface = c->num ? TAU32_E1_B : TAU32_E1_A; + req->Io.InterfaceConfig.Config = cfg; + req->Io.InterfaceConfig.UnframedTsMask = c->ts; + CE_DDK_DEBUG (b, c, ("Submit higain\n")); + if (ce_cfg_submit (b)) { + c->higain = on ? 1 : 0; + c->config = cfg; + } +} + +static void _ce_set_ts (ce_chan_t *c, unsigned long ts) +{ + TAU32_UserRequest *req; + ce_board_t *b = c->board; + unsigned long mask = 0, omask = 0; + int nts = 0, ots = 0, pts = 0; + int i, k; + + if (b->cr.pending >= CONFREQSZ) + return; + + /* + * pts - number of busy "peb" ts + * ots - current (old) busy ts + * nts - new busy ts + */ + for (i = 0; i < 32; i++) { + if (c->ts & (1ul << i)) + ots++; + if (ts & (1ul << i)) + nts++; + if (b->dxc[i] != TAU32_CROSS_OFF) + pts++; + } + + CE_DDK_DEBUG (b, c, ("pts: %d ots: %d nts: %d ts: %lx\n", pts, ots, nts, + ts)); + /* 32 - all busy + my old busy == free */ + if (32 - pts + ots - nts < 0) + return; + + /* Ok. We have enougth "peb" ts. Clean old. */ + /* We start from zero, cause this is peb cells */ + for (i = 0; i < 32; i++) { + int tin = b->dxc[i]; + int t = tin % 32; + if (tin < (c->dir?64:32) || tin > (c->dir?95:63)) + continue; + if (c->ts & (1ul << t)) { + b->dxc[tin] = TAU32_CROSS_OFF; + b->dxc[i] = TAU32_CROSS_OFF; + if (b->dxc[t + 32] == TAU32_CROSS_OFF && + b->dxc[t + 64] == TAU32_CROSS_OFF) { + b->dxc[t + 32] = t + 64; + b->dxc[t + 64] = t + 32; + } + omask |= (1ul << t); + } + } + + k = 0; + /* Set */ + for (i = 0; i < 32; i++) { + if ((ts & (1ul << i)) == 0) + continue; + while (b->dxc[k] != TAU32_CROSS_OFF) { + k++; + /* Paranoic */ + if (k >= 32) { + CE_DDK_DEBUG (b, c, ("TS count overflow\n")); + return; + } + } + b->dxc[k] = (c->dir?64:32) + i; + b->dxc[(c->dir?64:32) + i] = k; + if (b->dxc[(c->dir?32:64) + i] == (c->dir?64:32) + i) + b->dxc[(c->dir?32:64) + i] = TAU32_CROSS_OFF; + mask |= (1ul << k); + } + + c->ts = ts; + c->baud = nts*64000; + + CE_PREREQUEST (b, c, b->cr.queue, req); + if (!req) + return; + + req->Command = TAU32_Timeslots_Channel | TAU32_Configure_Commit; + req->Io.ChannelNumber = c->num; + req->Io.ChannelConfig.AssignedTsMask = mask; + + if (c->phony) { + b->pmask &= ~omask; + b->pmask |= mask; + } + + CE_DDK_DEBUG (b, c, ("ts=%lx mask=%lx omask=%lx pmask=%lx\n", c->ts, + mask, omask, b->pmask)); + CE_DDK_DEBUG (b, c, ("Crossmatrix table:\n")); + +#ifdef CE_DDK_DEBUG_ENABLED + for (i = 0; i < 32*3; i++) { + printf ("%3d\t%s", b->dxc[i], (i%8==7)?"\n":""); + printf ("%s",(i%32==31)?"\n":""); + } +#endif + + CE_DDK_DEBUG (b, c, ("Submit tsmask\n")); + if (!ce_cfg_submit (b)) { + CE_DDK_DEBUG (b, c, ("Fail to submit tsmask\n")); + /* Do some error processing */ + return; + } + + CE_DDK_DEBUG (b, c, ("SetCrossMatrix\n")); + if (!TAU32_SetCrossMatrix(b->ddk.pControllerObject, b->dxc, b->pmask)) { + CE_DDK_DEBUG (b, c, ("Faild to SetCrossMatrix\n")); + /* Do some error processing */ + return; + } +} + +void ce_set_ts (ce_chan_t *c, unsigned long ts) +{ + ce_board_t *b = c->board; + ce_chan_t *x; + + if (c->ts == ts || b->chan->unfram) + return; + + ts &= ~(1ul); + + if (!b->chan[c->dir].use16) + ts &= ~(1ul << 16); + + for (x = b->chan; x < b->chan + NCHAN; x++) { + if (x == c || x->dir != c->dir) + continue; + ts &= ~x->ts; + } + + _ce_set_ts (c, ts); +} + +void ce_set_unfram (ce_chan_t *c, unsigned char on) +{ + TAU32_UserRequest *req; + ce_board_t *b = c->board; + unsigned long cfg = c->config & ~TAU32_framing_mode_mask; + unsigned long i; + + if (c->num != 0 || b->cr.pending + 2*32 + 3>= CONFREQSZ) + return; + + on = on ? 1 : 0; + + if (on == c->unfram) + return; + + if (on) { + ce_set_dir (c, 0); + for (i = 1; i < TAU32_CHANNELS; i++) { + ce_set_ts (b->chan + i, 0); + ce_set_phony (b->chan + i, 0); + } + ce_set_use16 (b->chan + 0, 0); + ce_set_use16 (b->chan + 1, 0); + /* Get current value, previous ce_set request may change it */ + cfg = c->config & ~TAU32_framing_mode_mask; + cfg |= TAU32_unframed_2048; + c->unfram = on; + _ce_set_ts (b->chan, ~0ul); + c->config = cfg; + /* XXXRIK: Do extra checks on config queue size*/ + if (b->ddk.Interfaces) { + CE_PREREQUEST (b, c, b->cr.queue, req); + if (!req) + return; + req->Command = TAU32_Configure_E1; + req->Io.InterfaceConfig.Interface = TAU32_E1_B; + req->Io.InterfaceConfig.Config = TAU32_LineOff; + req->Io.InterfaceConfig.UnframedTsMask = 0; + CE_DDK_DEBUG (b, c, ("unfram: B line off\n")); + ce_cfg_submit (b); + } + CE_PREREQUEST (b, c, b->cr.queue, req); + if (!req) + return; + req->Command = TAU32_Configure_E1; + req->Io.InterfaceConfig.Interface = TAU32_E1_A; + req->Io.InterfaceConfig.Config = cfg; + req->Io.InterfaceConfig.UnframedTsMask = c->ts; + CE_DDK_DEBUG (b, c, ("Submit unfram\n")); + ce_cfg_submit (b); + } else { + cfg |= TAU32_framed_cas_cross; + CE_PREREQUEST (b, c, b->cr.queue, req); + if (!req) + return; + req->Command = TAU32_Configure_E1; + req->Io.InterfaceConfig.Interface = TAU32_E1_ALL; + req->Io.InterfaceConfig.Config = cfg; + req->Io.InterfaceConfig.UnframedTsMask = 0; + CE_DDK_DEBUG (b, c, ("Submit framed\n")); + ce_cfg_submit (b); + ce_set_ts (c, 0); + } + c->unfram = on; +} + +void ce_set_phony (ce_chan_t *c, unsigned char on) +{ + TAU32_UserRequest *req; + ce_board_t *b = c->board; + unsigned long mask = 0; + int i; + + if ((c->phony && on) || (c->phony == 0 && on == 0) || + b->cr.pending >= CONFREQSZ) + return; + + CE_PREREQUEST (b, c, b->cr.queue, req); + if (!req) + return; + + req->Command = TAU32_Configure_Channel; + req->Io.InterfaceConfig.Config = on ? TAU32_TMA : + (TAU32_HDLC | TAU32_fr_rx_splitcheck | TAU32_fr_rx_fitcheck); + req->Io.ChannelNumber = c->num; + CE_DDK_DEBUG (b, c, ("Submit phony\n")); + if (!ce_cfg_submit (b)) { + /* Do some error processing */ + return; + } + + for (i = 0; i < 32; i++) { + int t = b->dxc[i] % 32; + if (b->dxc[i] < (c->dir?64:32) || b->dxc[i] > (c->dir?95:63)) + continue; + if (c->ts & (1ul << t)) + mask |= (1ul << t); + } + + CE_DDK_DEBUG (b, c, ("phony mask:%lx\n", mask)); + + if (on) { + b->pmask |= mask; + } else { + b->pmask &= ~mask; + } + + c->phony = on ? 1 : 0; + + CE_DDK_DEBUG (b, c, ("Submit (setcrosmatrix) phony\n")); + if (!TAU32_SetCrossMatrix(b->ddk.pControllerObject, b->dxc, b->pmask)) { + /* Do some error processing */ + return; + } +} + +void ce_set_scrambler (ce_chan_t *c, unsigned char on) +{ + TAU32_UserRequest *req; + unsigned long cfg = c->config & ~TAU32_scrambler; + ce_board_t *b = c->board; + + if (c->num != 0 || c->unfram == 0 || b->cr.pending >= CONFREQSZ) + return; + on = on ? 1 : 0; + if (on == c->scrambler) + return; + + cfg |= on ? TAU32_scrambler : 0; + CE_PREREQUEST (b, c, b->cr.queue, req); + if (!req) + return; + req->Command = TAU32_Configure_E1; + req->Io.InterfaceConfig.Interface = c->num ? TAU32_E1_B : TAU32_E1_A; + req->Io.InterfaceConfig.Config = cfg; + req->Io.InterfaceConfig.UnframedTsMask = c->ts; + CE_DDK_DEBUG (b, c, ("Submit scrambler\n")); + if (ce_cfg_submit (b)) { + c->scrambler = on ? 1 : 0; + c->config = cfg; + } +} + +void ce_set_monitor (ce_chan_t *c, unsigned char on) +{ + TAU32_UserRequest *req; + unsigned long cfg = c->config & ~TAU32_monitor; + ce_board_t *b = c->board; + + if (c->num >= b->ddk.Interfaces || b->cr.pending >= CONFREQSZ) + return; + on = on ? 1 : 0; + if (on == c->monitor) + return; + + cfg |= on ? TAU32_monitor : 0; + CE_PREREQUEST (b, c, b->cr.queue, req); + if (!req) + return; + req->Command = TAU32_Configure_E1; + req->Io.InterfaceConfig.Interface = c->num ? TAU32_E1_B : TAU32_E1_A; + req->Io.InterfaceConfig.Config = cfg; + req->Io.InterfaceConfig.UnframedTsMask = c->ts; + CE_DDK_DEBUG (b, c, ("Submit monitor\n")); + if (ce_cfg_submit (b)) { + c->monitor = on ? 1 : 0; + c->config = cfg; + } +} + +static void _ce_submit_configure_e1 (ce_chan_t *c, char *rname) +{ + TAU32_UserRequest *req; + ce_board_t *b = c->board; + + CE_PREREQUEST (b, c, b->cr.queue, req); + if (!req) + return; + req->Command = TAU32_Configure_E1; + req->Io.InterfaceConfig.Interface = c->num == 0 ? TAU32_E1_A : TAU32_E1_B; + req->Io.InterfaceConfig.Config = c->config; + req->Io.InterfaceConfig.UnframedTsMask = c->ts; + CE_DDK_DEBUG (b, c, ("Submit %s\n", rname ? rname : "")); + if (!ce_cfg_submit (b)) { + CE_DDK_DEBUG (b, c, ("Fail to submit %s\n", rname?rname:"")); + /* Do some error processing */ + return; + } +} + +void ce_set_use16 (ce_chan_t *c, unsigned char on) +{ + ce_board_t *b = c->board; + ce_chan_t *x; + unsigned long cfg[2]; + int use[2]; + + if (c->num >= b->ddk.Interfaces || b->cr.pending + 2 >= CONFREQSZ) + return; + + cfg[0] = b->chan[0].config & ~TAU32_framing_mode_mask; + cfg[1] = b->chan[1].config & ~TAU32_framing_mode_mask; + + on = on ? 1 : 0; + + if (c->use16 == on || b->chan->unfram) + return; + + use[0] = b->chan[0].use16; + use[1] = b->chan[1].use16; + + /* Correct value */ + use[c->num] = on; + + if (b->ddk.Interfaces == 1) { + cfg[0] |= on ? TAU32_framed_cas_set : TAU32_framed_no_cas; + } else { + if (use[0] == 0 && use[1] == 0) { + cfg[0] |= TAU32_framed_cas_cross; + cfg[1] |= TAU32_framed_cas_cross; + } else if (use[0] == 0) { + cfg[0] |= TAU32_framed_cas_set; + cfg[1] |= TAU32_framed_no_cas; + } else if (use[1] == 0) { + cfg[0] |= TAU32_framed_no_cas; + cfg[1] |= TAU32_framed_cas_set; + } else { + cfg[0] |= TAU32_framed_no_cas; + cfg[1] |= TAU32_framed_no_cas; + } + } + + c->use16 = on; + + for (x = b->chan; !on && x < b->chan + NCHAN; x++) { + if (x->dir == c->num && x->ts & (1ul<<16)) { + ce_set_ts (x, x->ts); + break; + } + } + + if (cfg[0] != b->chan[0].config) { + b->chan[0].config = cfg[0]; + _ce_submit_configure_e1 (b->chan + 0, "use16"); + } + + if (cfg[1] != b->chan[1].config) { + b->chan[1].config = cfg[1]; + _ce_submit_configure_e1 (b->chan + 1, "use16"); + } +} + +void ce_set_crc4 (ce_chan_t *c, unsigned char on) +{ + TAU32_UserRequest *req; + unsigned long cfg = c->config & ~TAU32_crc4_mf; + ce_board_t *b = c->board; + + if (c->num >= b->ddk.Interfaces || b->cr.pending >= CONFREQSZ) + return; + on = on ? 1 : 0; + if (on == c->crc4 || b->chan->unfram) + return; + + cfg |= on ? TAU32_crc4_mf : 0; + CE_PREREQUEST (b, c, b->cr.queue, req); + if (!req) + return; + req->Command = TAU32_Configure_E1; + req->Io.InterfaceConfig.Interface = c->num ? TAU32_E1_B : TAU32_E1_A; + req->Io.InterfaceConfig.Config = cfg; + req->Io.InterfaceConfig.UnframedTsMask = c->ts; + CE_DDK_DEBUG (b, c, ("Submit crc4\n")); + if (ce_cfg_submit (b)) { + c->crc4 = on ? 1 : 0; + c->config = cfg; + } +} + +void ce_set_gsyn (ce_chan_t *c, int syn) +{ + ce_board_t *b = c->board; + unsigned int mode; + + if (c->num >= b->ddk.Interfaces) + return; + + if (syn == GSYN_RCV) + syn = c->num ? GSYN_RCV1 : GSYN_RCV0; + + switch (syn) { + default: mode = TAU32_SYNC_INTERNAL; break; + case GSYN_RCV0: mode = TAU32_SYNC_RCV_A; break; + case GSYN_RCV1: mode = TAU32_SYNC_RCV_B; break; + } + + CE_DDK_DEBUG (b, c, ("Set Sync Mode\n")); + if (TAU32_SetSyncMode (b->ddk.pControllerObject, mode)) { + b->chan->gsyn = syn; + if (b->ddk.Interfaces > 1) + (b->chan + 1)->gsyn = syn; + } +} + +int ce_get_cable (ce_chan_t *c) +{ + ce_board_t *b = c->board; + if (c->num >= b->ddk.Interfaces) + return 0; + + return CABLE_TP; +} + +void ce_set_dir (ce_chan_t *c, int dir) +{ + ce_board_t *b = c->board; + unsigned long ts; + if (b->cr.pending + 1>= CONFREQSZ || c->dir == dir) + return; + + ts = c->ts; + ce_set_ts (c, 0); + c->dir = dir; + ce_set_ts (c, ts); +} |