/* * Copyright (C) Eicon Technology Corporation, 2000. * * Eicon File Revision : 1.15 * * This software may be used and distributed according to the terms * of the GNU General Public License, incorporated herein by reference. * */ #include "eicon.h" #include "sys.h" #include "idi.h" #include "constant.h" #include "divas.h" #include "pc.h" #include "pr_pc.h" #include "uxio.h" #define DIVAS_LOAD_CMD 0x02 #define DIVAS_START_CMD 0x03 #define DIVAS_IRQ_RESET 0xC18 #define DIVAS_IRQ_RESET_VAL 0xFE #define TEST_INT_DIVAS 0x11 #define TEST_INT_DIVAS_BRI 0x12 #define TEST_INT_DIVAS_Q 0x13 #define DIVAS_RESET 0x81 #define DIVAS_LED1 0x04 #define DIVAS_LED2 0x08 #define DIVAS_LED3 0x20 #define DIVAS_LED4 0x40 #define DIVAS_SIGNATURE 0x4447 #define MP_PROTOCOL_ADDR 0xA0011000 #define PLX_IOBASE 0 #define DIVAS_IOBASE 1 typedef struct { dword cmd; dword addr; dword len; dword err; dword live; dword reserved[(0x1020>>2)-6]; dword signature; byte data[1]; } diva_server_boot_t; int DivasCardNext; card_t DivasCards[MAX_CARDS]; dia_config_t *DivasConfig(card_t *, dia_config_t *); static DESCRIPTOR DIDD_Table[32]; void DIVA_DIDD_Read( DESCRIPTOR *table, int tablelength ) { memset(table, 0, tablelength); if (tablelength > sizeof(DIDD_Table)) tablelength = sizeof(DIDD_Table); if(tablelength % sizeof(DESCRIPTOR)) { tablelength /= sizeof(DESCRIPTOR); tablelength *= sizeof(DESCRIPTOR); } if (tablelength > 0) memcpy((void *)table, (void *)DIDD_Table, tablelength); return; } void DIVA_DIDD_Write(DESCRIPTOR *table, int tablelength) { if (tablelength > sizeof(DIDD_Table)) tablelength = sizeof(DIDD_Table); memcpy((void *)DIDD_Table, (void *)table, tablelength); return; } static void init_idi_tab(void) { DESCRIPTOR d[32]; memset(d, 0, sizeof(d)); d[0].type = IDI_DIMAINT; /* identify the DIMAINT entry */ d[0].channels = 0; /* zero channels associated with dimaint*/ d[0].features = 0; /* no features associated with dimaint */ d[0].request = (IDI_CALL) DivasPrintf; DIVA_DIDD_Write(d, sizeof(d)); return; } /* * I/O routines for memory mapped cards */ byte mem_in(ADAPTER *a, void *adr) { card_t *card = a->io; unsigned char *b, *m; byte value; m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); m += (unsigned int) adr; value = UxCardMemIn(card->hw, m); UxCardMemDetach(card->hw, b); return value; } word mem_inw(ADAPTER *a, void *adr) { card_t *card = a->io; unsigned char *b, *m; word value; m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); m += (unsigned int) adr; value = UxCardMemInW(card->hw, m); UxCardMemDetach(card->hw, b); return value; } void mem_in_buffer(ADAPTER *a, void *adr, void *P, word length) { card_t *card = a->io; unsigned char *b, *m; m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); m += (unsigned int) adr; UxCardMemInBuffer(card->hw, m, P, length); UxCardMemDetach(card->hw, b); return; } void mem_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e) { card_t *card = a->io; unsigned char *b, *m; m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); m += (dword) &RBuffer->length; card->RBuffer.length = UxCardMemInW(card->hw, m); m = b; m += (dword) &RBuffer->P; UxCardMemInBuffer(card->hw, m, card->RBuffer.P, card->RBuffer.length); e->RBuffer = (DBUFFER *) &card->RBuffer; UxCardMemDetach(card->hw, b); return; } void mem_out(ADAPTER *a, void *adr, byte data) { card_t *card = a->io; unsigned char *b, *m; m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); m += (unsigned int) adr; UxCardMemOut(card->hw, m, data); UxCardMemDetach(card->hw, b); return; } void mem_outw(ADAPTER *a, void *adr, word data) { card_t *card = a->io; unsigned char *b, *m; m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); m += (unsigned int) adr; UxCardMemOutW(card->hw, m, data); UxCardMemDetach(card->hw, b); return; } void mem_out_buffer(ADAPTER *a, void *adr, void *P, word length) { card_t *card = a->io; unsigned char *b, *m; m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); m += (unsigned int) adr; UxCardMemOutBuffer(card->hw, m, P, length); UxCardMemDetach(card->hw, b); return; } void mem_inc(ADAPTER *a, void *adr) { word value; card_t *card = a->io; unsigned char *b, *m; m = b = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); m += (unsigned int) adr; value = UxCardMemInW(card->hw, m); value++; UxCardMemOutW(card->hw, m, value); UxCardMemDetach(card->hw, b); return; } /* * I/O routines for I/O mapped cards */ byte io_in(ADAPTER *a, void *adr) { card_t *card = a->io; byte value; byte *DivasIOBase = NULL; DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); value = UxCardIoIn(card->hw, DivasIOBase, adr); UxCardMemDetach(card->hw, DivasIOBase); return value; } word io_inw(ADAPTER *a, void *adr) { card_t *card = a->io; word value; byte *DivasIOBase = NULL; DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); value = UxCardIoInW(card->hw, DivasIOBase, adr); UxCardMemDetach(card->hw, DivasIOBase); return value; } void io_in_buffer(ADAPTER *a, void *adr, void *P, word length) { card_t *card = a->io; byte *DivasIOBase = NULL; DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); UxCardIoInBuffer(card->hw, DivasIOBase, adr, P,length); UxCardMemDetach(card->hw, DivasIOBase); return; } void io_look_ahead(ADAPTER *a, PBUFFER *RBuffer, ENTITY *e) { card_t *card = a->io; byte *DivasIOBase = NULL; DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); card->RBuffer.length = UxCardIoInW(card->hw, DivasIOBase, (byte *) RBuffer); UxCardIoInBuffer(card->hw, DivasIOBase, &RBuffer->P, card->RBuffer.P, card->RBuffer.length); UxCardMemDetach(card->hw, DivasIOBase); e->RBuffer = (DBUFFER *) &card->RBuffer; return; } void io_out(ADAPTER *a, void *adr, byte data) { card_t *card = a->io; byte *DivasIOBase = NULL; DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); UxCardIoOut(card->hw, DivasIOBase, adr, data); UxCardMemDetach(card->hw, DivasIOBase); return; } void io_outw(ADAPTER *a, void *adr, word data) { card_t *card = a->io; byte *DivasIOBase = NULL; DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); UxCardIoOutW(card->hw, DivasIOBase, adr, data); UxCardMemDetach(card->hw, DivasIOBase); return; } void io_out_buffer(ADAPTER *a, void *adr, void *P, word length) { card_t *card = a->io; byte *DivasIOBase = NULL; DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); UxCardIoOutBuffer(card->hw, DivasIOBase, adr, P, length); UxCardMemDetach(card->hw, DivasIOBase); return; } void io_inc(ADAPTER *a, void *adr) { word value; card_t *card = a->io; byte *DivasIOBase; DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); value = UxCardIoInW(card->hw, DivasIOBase, adr); value++; UxCardIoOutW(card->hw, DivasIOBase, adr, value); UxCardMemDetach(card->hw, DivasIOBase); return; } static void test_int(card_t *card) { byte *shared, *DivasIOBase; switch (card->test_int_pend) { case TEST_INT_DIVAS: DPRINTF(("divas: test interrupt pending")); shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); if (UxCardMemIn(card->hw, &shared[0x3FE])) { UxCardMemOut(card->hw, &(((struct pr_ram *)shared)->RcOutput), 0); UxCardMemDetach(card->hw, shared); (*card->reset_int)(card); shared = UxCardMemAttach(card->hw, DIVAS_SHARED_MEMORY); UxCardMemOut(card->hw, &shared[0x3FE], 0); DPRINTF(("divas: test interrupt cleared")); } UxCardMemDetach(card->hw, shared); card->test_int_pend = 0; break; case TEST_INT_DIVAS_BRI: DPRINTF(("divas: BRI test interrupt pending")); (*card->reset_int)(card); DivasIOBase = UxCardMemAttach(card->hw, DIVAS_IOBASE); UxCardIoOutW(card->hw, DivasIOBase, (void *) 0x3FE, 0); UxCardMemDetach(card->hw, DivasIOBase); DPRINTF(("divas: test interrupt cleared")); card->test_int_pend = 0; break; case TEST_INT_DIVAS_Q: DPRINTF(("divas: 4BRI test interrupt pending")); (*card->reset_int)(card); card->test_int_pend = 0; break; default: DPRINTF(("divas: unknown test interrupt pending")); return; } return; } void card_isr (void *dev_id) { card_t *card = (card_t *) dev_id; ADAPTER *a = &card->a; int ipl; if (card->test_int_pend) { ipl = UxCardLock(card->hw); card->int_pend=0; test_int(card); UxCardUnlock(card->hw,ipl); return; } if(card->card_isr) { (*(card->card_isr))(card); } else { ipl = UxCardLock(card->hw); if ((card->test_int)(a)) { (card->reset_int)(card); } UxCardUnlock(card->hw,ipl); } } int DivasCardNew(dia_card_t *card_info) { card_t *card; static boolean_t first_call = TRUE; boolean_t NeedISRandReset = FALSE; DPRINTF(("divas: new card ")); if (first_call) { first_call = FALSE; init_idi_tab(); } DivasConfigGet(card_info); if (DivasCardNext == DIM(DivasCards)) { KDPRINTF((KERN_WARNING "Divas: no space available for new card")); return -1; } card = &DivasCards[DivasCardNext]; card->state = DIA_UNKNOWN; card->cfg = *card_info; card->a.io = card; if (UxCardHandleGet(&card->hw, card_info)) { KDPRINTF((KERN_WARNING "Divas: cannot get OS specific handle for card")); return -1; } if (card_info->card_type == DIA_CARD_TYPE_DIVA_SERVER_B) { DivasBriPatch(card); card_info->io_base = card->cfg.io_base; } switch (card_info->card_type) { case DIA_CARD_TYPE_DIVA_SERVER: if (DivasPriInit(card, card_info)) { return -1; } NeedISRandReset = TRUE; break; case DIA_CARD_TYPE_DIVA_SERVER_B: if (DivasBriInit(card, card_info)) { return -1; } NeedISRandReset = TRUE; break; case DIA_CARD_TYPE_DIVA_SERVER_Q: if (Divas4BriInit(card, card_info)) { return -1; } if (card_info->name[6] == '0') { NeedISRandReset = TRUE; } else // Need to set paramater for ISR anyway { card->hw->user_isr_arg = card; card->hw->user_isr = card_isr; } break; default: KDPRINTF((KERN_WARNING "Divas: unsupported card type (%d)", card_info->card_type)); return -1; } if (NeedISRandReset) { if (UxIsrInstall(card->hw, card_isr, card)) { KDPRINTF((KERN_WARNING "Divas: Install ISR failed (IRQ %d)", card->cfg.irq)); UxCardHandleFree(card->hw); return -1; } if (card_info->card_type != DIA_CARD_TYPE_DIVA_SERVER_Q) { if ((*card->card_reset)(card)) { KDPRINTF((KERN_WARNING "Divas: Adapter reset failed")); return -1; } card->state = DIA_RESET; } NeedISRandReset = FALSE; } DivasCardNext++; return 0; } void *get_card(int card_id) { int i; for (i=0; i < DivasCardNext; i++) { if (DivasCards[i].cfg.card_id == card_id) { return(&DivasCards[i]); } } DPRINTF(("divas: get_card() : no such card id (%d)", card_id)); return NULL; } int DivasCardConfig(dia_config_t *config) { card_t *card; int status; DPRINTF(("divas: configuring card")); card = get_card(config->card_id); if (!card) { return -1; } config = DivasConfig(card, config); status = (*card->card_config)(card, config); if (!status) { card->state = DIA_CONFIGURED; } return status; } int DivasCardLoad(dia_load_t *load) { card_t *card; int status; card = get_card(load->card_id); if (!card) { return -1; } if (card->state == DIA_RUNNING) { (*card->card_reset)(card); } status = (*card->card_load)(card, load); if (!status) { card->state = DIA_LOADED; } return status; } static int idi_register(card_t *card, byte channels) { DESCRIPTOR d[32]; int length, num_entities; DPRINTF(("divas: registering card with IDI")); num_entities = (channels > 2) ? MAX_PENTITIES : MAX_ENTITIES; card->e_tbl = UxAlloc(sizeof(E_INFO) * num_entities); if (!card->e_tbl) { KDPRINTF((KERN_WARNING "Divas: IDI register failed - no memory available")); return -1; } memset(card->e_tbl, 0, sizeof(E_INFO) * num_entities); card->e_max = num_entities; DIVA_DIDD_Read(d, sizeof(d)); for(length=0; length < DIM(d); length++) if (d[length].type == 0) break; if (length >= DIM(d)) { KDPRINTF((KERN_WARNING "Divas: IDI register failed - table full")); return -1; } switch (card->cfg.card_type) { case DIA_CARD_TYPE_DIVA_SERVER: d[length].type = IDI_ADAPTER_PR; /* d[length].serial = card->serial_no; */ break; case DIA_CARD_TYPE_DIVA_SERVER_B: d[length].type = IDI_ADAPTER_MAESTRA; /* d[length].serial = card->serial_no; */ break; // 4BRI is treated as 4 BRI adapters case DIA_CARD_TYPE_DIVA_SERVER_Q: d[length].type = IDI_ADAPTER_MAESTRA; /* d[length].serial = card->cfg.serial; */ } d[length].features = 0; d[length].features |= DI_FAX3|DI_MODEM|DI_POST|DI_V110|DI_V120; if ( card->hw->features & PROTCAP_MANIF ) { d[length].features |= DI_MANAGE ; } if ( card->hw->features & PROTCAP_V_42 ) { d[length].features |= DI_V_42 ; } if ( card->hw->features & PROTCAP_EXTD_FAX ) { d[length].features |= DI_EXTD_FAX ; } d[length].channels = channels; d[length].request = DivasIdiRequest[card - DivasCards]; length++; DIVA_DIDD_Write(d, sizeof(d)); return 0; } int DivasCardStart(int card_id) { card_t *card; byte channels; int status; DPRINTF(("divas: starting card")); card = get_card(card_id); if (!card) { return -1; } status = (*card->card_start)(card, &channels); if (status) { return status; } /* 4BRI == 4 x BRI so call idi_register 4 times each with 2 channels */ if (card->cfg.card_type == DIA_CARD_TYPE_DIVA_SERVER_Q) { int i; card_t *FourBRISlave; for (i=3; i >= 0; i--) { FourBRISlave = get_card(card_id - i); /* 0, 1, 2, 3 */ if (FourBRISlave) { idi_register(FourBRISlave, 2); FourBRISlave->state = DIA_RUNNING; } } card->serial_no = card->cfg.serial; DPRINTF(("divas: card id %d (4BRI), serial no. 0x%x ready with %d channels", card_id - 3, card->serial_no, (int) channels)); } else { status = idi_register(card, channels); if (!status) { card->state = DIA_RUNNING; DPRINTF(("divas: card id %d, serial no. 0x%x ready with %d channels", card_id, card->serial_no, (int) channels)); } } return status; } int DivasGetMem(mem_block_t *mem_block) { card_t *card; word card_id = mem_block->card_id; card = get_card(card_id); if (!card) { return 0; } return (*card->card_mem_get)(card, mem_block); } /* * Deleyed Procedure Call for handling interrupts from card */ void DivaDoCardDpc(card_t *card) { ADAPTER *a; a = &card->a; if(UxInterlockedIncrement(card->hw, &card->dpc_reentered) > 1) { return; } do{ if((*(card->test_int))(a)) { (*(card->dpc))(a); (*(card->clear_int))(a); } (*(card->out))(a); }while(UxInterlockedDecrement(card->hw, &card->dpc_reentered)); } void DivasDoDpc(void *pData) { card_t *card = DivasCards; int i = DivasCardNext; while(i--) { if (card->state == DIA_RUNNING) DivaDoCardDpc(card); card++; } } void DivasDoRequestDpc(void *pData) { DivasDoDpc(pData); } /* * DivasGetNum * Returns the number of active adapters */ int DivasGetNum(void) { return(DivasCardNext); } /* * DivasGetList * Returns a list of active adapters */ int DivasGetList(dia_card_list_t *card_list) { int i; memset(card_list, 0, sizeof(dia_card_list_t)); for(i = 0; i < DivasCardNext; i++) { card_list->card_type = DivasCards[i].cfg.card_type; card_list->card_slot = DivasCards[i].cfg.slot; card_list->state = DivasCards[i].state; card_list++; } return 0; } /* * control logging for specified card */ void DivasLog(dia_log_t *log) { card_t *card; card = get_card(log->card_id); if (!card) { return; } card->log_types = log->log_types; return; }