| |
| /* |
| * |
| Copyright (c) Eicon Networks, 2002. |
| * |
| This source file is supplied for the use with |
| Eicon Networks range of DIVA Server Adapters. |
| * |
| Eicon File Revision : 2.1 |
| * |
| This program is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| * |
| This program is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY OF ANY KIND WHATSOEVER INCLUDING ANY |
| implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
| See the GNU General Public License for more details. |
| * |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| * |
| */ |
| #include "platform.h" |
| #include "di_defs.h" |
| #include "pc.h" |
| #include "pr_pc.h" |
| #include "divasync.h" |
| #define MIPS_SCOM |
| #include "pkmaint.h" /* pc_main.h, packed in os-dependent fashion */ |
| #include "di.h" |
| #include "mi_pc.h" |
| #include "io.h" |
| extern ADAPTER * adapter[MAX_ADAPTER]; |
| extern PISDN_ADAPTER IoAdapters[MAX_ADAPTER]; |
| void request (PISDN_ADAPTER, ENTITY *); |
| static void pcm_req (PISDN_ADAPTER, ENTITY *); |
| /* -------------------------------------------------------------------------- |
| local functions |
| -------------------------------------------------------------------------- */ |
| #define ReqFunc(N) \ |
| static void Request##N(ENTITY *e) \ |
| { if ( IoAdapters[N] ) (* IoAdapters[N]->DIRequest)(IoAdapters[N], e) ; } |
| ReqFunc(0) |
| ReqFunc(1) |
| ReqFunc(2) |
| ReqFunc(3) |
| ReqFunc(4) |
| ReqFunc(5) |
| ReqFunc(6) |
| ReqFunc(7) |
| ReqFunc(8) |
| ReqFunc(9) |
| ReqFunc(10) |
| ReqFunc(11) |
| ReqFunc(12) |
| ReqFunc(13) |
| ReqFunc(14) |
| ReqFunc(15) |
| IDI_CALL Requests[MAX_ADAPTER] = |
| { &Request0, &Request1, &Request2, &Request3, |
| &Request4, &Request5, &Request6, &Request7, |
| &Request8, &Request9, &Request10, &Request11, |
| &Request12, &Request13, &Request14, &Request15 |
| }; |
| /*****************************************************************************/ |
| /* |
| This array should indicate all new services, that this version of XDI |
| is able to provide to his clients |
| */ |
| static byte extended_xdi_features[DIVA_XDI_EXTENDED_FEATURES_MAX_SZ+1] = { |
| (DIVA_XDI_EXTENDED_FEATURES_VALID | |
| DIVA_XDI_EXTENDED_FEATURE_SDRAM_BAR | |
| DIVA_XDI_EXTENDED_FEATURE_CAPI_PRMS | |
| #if defined(DIVA_IDI_RX_DMA) |
| DIVA_XDI_EXTENDED_FEATURE_CMA | |
| DIVA_XDI_EXTENDED_FEATURE_RX_DMA | |
| DIVA_XDI_EXTENDED_FEATURE_MANAGEMENT_DMA | |
| #endif |
| DIVA_XDI_EXTENDED_FEATURE_NO_CANCEL_RC), |
| 0 |
| }; |
| /*****************************************************************************/ |
| void |
| dump_xlog_buffer (PISDN_ADAPTER IoAdapter, Xdesc *xlogDesc) |
| { |
| dword logLen ; |
| word *Xlog = xlogDesc->buf ; |
| word logCnt = xlogDesc->cnt ; |
| word logOut = xlogDesc->out / sizeof(*Xlog) ; |
| DBG_FTL(("%s: ************* XLOG recovery (%d) *************", |
| &IoAdapter->Name[0], (int)logCnt)) |
| DBG_FTL(("Microcode: %s", &IoAdapter->ProtocolIdString[0])) |
| for ( ; logCnt > 0 ; --logCnt ) |
| { |
| if ( !GET_WORD(&Xlog[logOut]) ) |
| { |
| if ( --logCnt == 0 ) |
| break ; |
| logOut = 0 ; |
| } |
| if ( GET_WORD(&Xlog[logOut]) <= (logOut * sizeof(*Xlog)) ) |
| { |
| if ( logCnt > 2 ) |
| { |
| DBG_FTL(("Possibly corrupted XLOG: %d entries left", |
| (int)logCnt)) |
| } |
| break ; |
| } |
| logLen = (dword)(GET_WORD(&Xlog[logOut]) - (logOut * sizeof(*Xlog))) ; |
| DBG_FTL_MXLOG(( (char *)&Xlog[logOut + 1], (dword)(logLen - 2) )) |
| logOut = (GET_WORD(&Xlog[logOut]) + 1) / sizeof(*Xlog) ; |
| } |
| DBG_FTL(("%s: ***************** end of XLOG *****************", |
| &IoAdapter->Name[0])) |
| } |
| /*****************************************************************************/ |
| #if defined(XDI_USE_XLOG) |
| static char *(ExceptionCauseTable[]) = |
| { |
| "Interrupt", |
| "TLB mod /IBOUND", |
| "TLB load /DBOUND", |
| "TLB store", |
| "Address error load", |
| "Address error store", |
| "Instruction load bus error", |
| "Data load/store bus error", |
| "Syscall", |
| "Breakpoint", |
| "Reverd instruction", |
| "Coprocessor unusable", |
| "Overflow", |
| "TRAP", |
| "VCEI", |
| "Floating Point Exception", |
| "CP2", |
| "Reserved 17", |
| "Reserved 18", |
| "Reserved 19", |
| "Reserved 20", |
| "Reserved 21", |
| "Reserved 22", |
| "WATCH", |
| "Reserved 24", |
| "Reserved 25", |
| "Reserved 26", |
| "Reserved 27", |
| "Reserved 28", |
| "Reserved 29", |
| "Reserved 30", |
| "VCED" |
| } ; |
| #endif |
| void |
| dump_trap_frame (PISDN_ADAPTER IoAdapter, byte __iomem *exceptionFrame) |
| { |
| MP_XCPTC __iomem *xcept = (MP_XCPTC __iomem *)exceptionFrame ; |
| dword __iomem *regs; |
| regs = &xcept->regs[0] ; |
| DBG_FTL(("%s: ***************** CPU TRAPPED *****************", |
| &IoAdapter->Name[0])) |
| DBG_FTL(("Microcode: %s", &IoAdapter->ProtocolIdString[0])) |
| DBG_FTL(("Cause: %s", |
| ExceptionCauseTable[(READ_DWORD(&xcept->cr) & 0x0000007c) >> 2])) |
| DBG_FTL(("sr 0x%08x cr 0x%08x epc 0x%08x vaddr 0x%08x", |
| READ_DWORD(&xcept->sr), READ_DWORD(&xcept->cr), |
| READ_DWORD(&xcept->epc), READ_DWORD(&xcept->vaddr))) |
| DBG_FTL(("zero 0x%08x at 0x%08x v0 0x%08x v1 0x%08x", |
| READ_DWORD(®s[ 0]), READ_DWORD(®s[ 1]), |
| READ_DWORD(®s[ 2]), READ_DWORD(®s[ 3]))) |
| DBG_FTL(("a0 0x%08x a1 0x%08x a2 0x%08x a3 0x%08x", |
| READ_DWORD(®s[ 4]), READ_DWORD(®s[ 5]), |
| READ_DWORD(®s[ 6]), READ_DWORD(®s[ 7]))) |
| DBG_FTL(("t0 0x%08x t1 0x%08x t2 0x%08x t3 0x%08x", |
| READ_DWORD(®s[ 8]), READ_DWORD(®s[ 9]), |
| READ_DWORD(®s[10]), READ_DWORD(®s[11]))) |
| DBG_FTL(("t4 0x%08x t5 0x%08x t6 0x%08x t7 0x%08x", |
| READ_DWORD(®s[12]), READ_DWORD(®s[13]), |
| READ_DWORD(®s[14]), READ_DWORD(®s[15]))) |
| DBG_FTL(("s0 0x%08x s1 0x%08x s2 0x%08x s3 0x%08x", |
| READ_DWORD(®s[16]), READ_DWORD(®s[17]), |
| READ_DWORD(®s[18]), READ_DWORD(®s[19]))) |
| DBG_FTL(("s4 0x%08x s5 0x%08x s6 0x%08x s7 0x%08x", |
| READ_DWORD(®s[20]), READ_DWORD(®s[21]), |
| READ_DWORD(®s[22]), READ_DWORD(®s[23]))) |
| DBG_FTL(("t8 0x%08x t9 0x%08x k0 0x%08x k1 0x%08x", |
| READ_DWORD(®s[24]), READ_DWORD(®s[25]), |
| READ_DWORD(®s[26]), READ_DWORD(®s[27]))) |
| DBG_FTL(("gp 0x%08x sp 0x%08x s8 0x%08x ra 0x%08x", |
| READ_DWORD(®s[28]), READ_DWORD(®s[29]), |
| READ_DWORD(®s[30]), READ_DWORD(®s[31]))) |
| DBG_FTL(("md 0x%08x|%08x resvd 0x%08x class 0x%08x", |
| READ_DWORD(&xcept->mdhi), READ_DWORD(&xcept->mdlo), |
| READ_DWORD(&xcept->reseverd), READ_DWORD(&xcept->xclass))) |
| } |
| /* -------------------------------------------------------------------------- |
| Real XDI Request function |
| -------------------------------------------------------------------------- */ |
| void request(PISDN_ADAPTER IoAdapter, ENTITY * e) |
| { |
| byte i; |
| diva_os_spin_lock_magic_t irql; |
| /* |
| * if the Req field in the entity structure is 0, |
| * we treat this request as a special function call |
| */ |
| if ( !e->Req ) |
| { |
| IDI_SYNC_REQ *syncReq = (IDI_SYNC_REQ *)e ; |
| switch (e->Rc) |
| { |
| #if defined(DIVA_IDI_RX_DMA) |
| case IDI_SYNC_REQ_DMA_DESCRIPTOR_OPERATION: { |
| diva_xdi_dma_descriptor_operation_t* pI = \ |
| &syncReq->xdi_dma_descriptor_operation.info; |
| if (!IoAdapter->dma_map) { |
| pI->operation = -1; |
| pI->descriptor_number = -1; |
| return; |
| } |
| diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, &irql, "dma_op"); |
| if (pI->operation == IDI_SYNC_REQ_DMA_DESCRIPTOR_ALLOC) { |
| pI->descriptor_number = diva_alloc_dma_map_entry (\ |
| (struct _diva_dma_map_entry*)IoAdapter->dma_map); |
| if (pI->descriptor_number >= 0) { |
| dword dma_magic; |
| void* local_addr; |
| diva_get_dma_map_entry (\ |
| (struct _diva_dma_map_entry*)IoAdapter->dma_map, |
| pI->descriptor_number, |
| &local_addr, &dma_magic); |
| pI->descriptor_address = local_addr; |
| pI->descriptor_magic = dma_magic; |
| pI->operation = 0; |
| } else { |
| pI->operation = -1; |
| } |
| } else if ((pI->operation == IDI_SYNC_REQ_DMA_DESCRIPTOR_FREE) && |
| (pI->descriptor_number >= 0)) { |
| diva_free_dma_map_entry((struct _diva_dma_map_entry*)IoAdapter->dma_map, |
| pI->descriptor_number); |
| pI->descriptor_number = -1; |
| pI->operation = 0; |
| } else { |
| pI->descriptor_number = -1; |
| pI->operation = -1; |
| } |
| diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "dma_op"); |
| } return; |
| #endif |
| case IDI_SYNC_REQ_XDI_GET_LOGICAL_ADAPTER_NUMBER: { |
| diva_xdi_get_logical_adapter_number_s_t *pI = \ |
| &syncReq->xdi_logical_adapter_number.info; |
| pI->logical_adapter_number = IoAdapter->ANum; |
| pI->controller = IoAdapter->ControllerNumber; |
| pI->total_controllers = IoAdapter->Properties.Adapters; |
| } return; |
| case IDI_SYNC_REQ_XDI_GET_CAPI_PARAMS: { |
| diva_xdi_get_capi_parameters_t prms, *pI = &syncReq->xdi_capi_prms.info; |
| memset (&prms, 0x00, sizeof(prms)); |
| prms.structure_length = min_t(size_t, sizeof(prms), pI->structure_length); |
| memset (pI, 0x00, pI->structure_length); |
| prms.flag_dynamic_l1_down = (IoAdapter->capi_cfg.cfg_1 & \ |
| DIVA_XDI_CAPI_CFG_1_DYNAMIC_L1_ON) ? 1 : 0; |
| prms.group_optimization_enabled = (IoAdapter->capi_cfg.cfg_1 & \ |
| DIVA_XDI_CAPI_CFG_1_GROUP_POPTIMIZATION_ON) ? 1 : 0; |
| memcpy (pI, &prms, prms.structure_length); |
| } return; |
| case IDI_SYNC_REQ_XDI_GET_ADAPTER_SDRAM_BAR: |
| syncReq->xdi_sdram_bar.info.bar = IoAdapter->sdram_bar; |
| return; |
| case IDI_SYNC_REQ_XDI_GET_EXTENDED_FEATURES: { |
| dword i; |
| diva_xdi_get_extended_xdi_features_t* pI =\ |
| &syncReq->xdi_extended_features.info; |
| pI->buffer_length_in_bytes &= ~0x80000000; |
| if (pI->buffer_length_in_bytes && pI->features) { |
| memset (pI->features, 0x00, pI->buffer_length_in_bytes); |
| } |
| for (i = 0; ((pI->features) && (i < pI->buffer_length_in_bytes) && |
| (i < DIVA_XDI_EXTENDED_FEATURES_MAX_SZ)); i++) { |
| pI->features[i] = extended_xdi_features[i]; |
| } |
| if ((pI->buffer_length_in_bytes < DIVA_XDI_EXTENDED_FEATURES_MAX_SZ) || |
| (!pI->features)) { |
| pI->buffer_length_in_bytes =\ |
| (0x80000000 | DIVA_XDI_EXTENDED_FEATURES_MAX_SZ); |
| } |
| } return; |
| case IDI_SYNC_REQ_XDI_GET_STREAM: |
| if (IoAdapter) { |
| diva_xdi_provide_istream_info (&IoAdapter->a, |
| &syncReq->xdi_stream_info.info); |
| } else { |
| syncReq->xdi_stream_info.info.provided_service = 0; |
| } |
| return; |
| case IDI_SYNC_REQ_GET_NAME: |
| if ( IoAdapter ) |
| { |
| strcpy (&syncReq->GetName.name[0], IoAdapter->Name) ; |
| DBG_TRC(("xdi: Adapter %d / Name '%s'", |
| IoAdapter->ANum, IoAdapter->Name)) |
| return ; |
| } |
| syncReq->GetName.name[0] = '\0' ; |
| break ; |
| case IDI_SYNC_REQ_GET_SERIAL: |
| if ( IoAdapter ) |
| { |
| syncReq->GetSerial.serial = IoAdapter->serialNo ; |
| DBG_TRC(("xdi: Adapter %d / SerialNo %ld", |
| IoAdapter->ANum, IoAdapter->serialNo)) |
| return ; |
| } |
| syncReq->GetSerial.serial = 0 ; |
| break ; |
| case IDI_SYNC_REQ_GET_CARDTYPE: |
| if ( IoAdapter ) |
| { |
| syncReq->GetCardType.cardtype = IoAdapter->cardType ; |
| DBG_TRC(("xdi: Adapter %d / CardType %ld", |
| IoAdapter->ANum, IoAdapter->cardType)) |
| return ; |
| } |
| syncReq->GetCardType.cardtype = 0 ; |
| break ; |
| case IDI_SYNC_REQ_GET_XLOG: |
| if ( IoAdapter ) |
| { |
| pcm_req (IoAdapter, e) ; |
| return ; |
| } |
| e->Ind = 0 ; |
| break ; |
| case IDI_SYNC_REQ_GET_DBG_XLOG: |
| if ( IoAdapter ) |
| { |
| pcm_req (IoAdapter, e) ; |
| return ; |
| } |
| e->Ind = 0 ; |
| break ; |
| case IDI_SYNC_REQ_GET_FEATURES: |
| if ( IoAdapter ) |
| { |
| syncReq->GetFeatures.features = |
| (unsigned short)IoAdapter->features ; |
| return ; |
| } |
| syncReq->GetFeatures.features = 0 ; |
| break ; |
| case IDI_SYNC_REQ_PORTDRV_HOOK: |
| if ( IoAdapter ) |
| { |
| DBG_TRC(("Xdi:IDI_SYNC_REQ_PORTDRV_HOOK - ignored")) |
| return ; |
| } |
| break; |
| } |
| if ( IoAdapter ) |
| { |
| return ; |
| } |
| } |
| DBG_TRC(("xdi: Id 0x%x / Req 0x%x / Rc 0x%x", e->Id, e->Req, e->Rc)) |
| if ( !IoAdapter ) |
| { |
| DBG_FTL(("xdi: uninitialized Adapter used - ignore request")) |
| return ; |
| } |
| diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req"); |
| /* |
| * assign an entity |
| */ |
| if ( !(e->Id &0x1f) ) |
| { |
| if ( IoAdapter->e_count >= IoAdapter->e_max ) |
| { |
| DBG_FTL(("xdi: all Ids in use (max=%d) --> Req ignored", |
| IoAdapter->e_max)) |
| diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req"); |
| return ; |
| } |
| /* |
| * find a new free id |
| */ |
| for ( i = 1 ; IoAdapter->e_tbl[i].e ; ++i ) ; |
| IoAdapter->e_tbl[i].e = e ; |
| IoAdapter->e_count++ ; |
| e->No = (byte)i ; |
| e->More = 0 ; |
| e->RCurrent = 0xff ; |
| } |
| else |
| { |
| i = e->No ; |
| } |
| /* |
| * if the entity is still busy, ignore the request call |
| */ |
| if ( e->More & XBUSY ) |
| { |
| DBG_FTL(("xdi: Id 0x%x busy --> Req 0x%x ignored", e->Id, e->Req)) |
| if ( !IoAdapter->trapped && IoAdapter->trapFnc ) |
| { |
| IoAdapter->trapFnc (IoAdapter) ; |
| /* |
| Firs trap, also notify user if supported |
| */ |
| if (IoAdapter->trapped && IoAdapter->os_trap_nfy_Fnc) { |
| (*(IoAdapter->os_trap_nfy_Fnc))(IoAdapter, IoAdapter->ANum); |
| } |
| } |
| diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req"); |
| return ; |
| } |
| /* |
| * initialize transmit status variables |
| */ |
| e->More |= XBUSY ; |
| e->More &= ~XMOREF ; |
| e->XCurrent = 0 ; |
| e->XOffset = 0 ; |
| /* |
| * queue this entity in the adapter request queue |
| */ |
| IoAdapter->e_tbl[i].next = 0 ; |
| if ( IoAdapter->head ) |
| { |
| IoAdapter->e_tbl[IoAdapter->tail].next = i ; |
| IoAdapter->tail = i ; |
| } |
| else |
| { |
| IoAdapter->head = i ; |
| IoAdapter->tail = i ; |
| } |
| /* |
| * queue the DPC to process the request |
| */ |
| diva_os_schedule_soft_isr (&IoAdapter->req_soft_isr); |
| diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req"); |
| } |
| /* --------------------------------------------------------------------- |
| Main DPC routine |
| --------------------------------------------------------------------- */ |
| void DIDpcRoutine (struct _diva_os_soft_isr* psoft_isr, void* Context) { |
| PISDN_ADAPTER IoAdapter = (PISDN_ADAPTER)Context ; |
| ADAPTER* a = &IoAdapter->a ; |
| diva_os_atomic_t* pin_dpc = &IoAdapter->in_dpc; |
| if (diva_os_atomic_increment (pin_dpc) == 1) { |
| do { |
| if ( IoAdapter->tst_irq (a) ) |
| { |
| if ( !IoAdapter->Unavailable ) |
| IoAdapter->dpc (a) ; |
| IoAdapter->clr_irq (a) ; |
| } |
| IoAdapter->out (a) ; |
| } while (diva_os_atomic_decrement (pin_dpc) > 0); |
| /* ---------------------------------------------------------------- |
| Look for XLOG request (cards with indirect addressing) |
| ---------------------------------------------------------------- */ |
| if (IoAdapter->pcm_pending) { |
| struct pc_maint *pcm; |
| diva_os_spin_lock_magic_t OldIrql ; |
| diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, |
| &OldIrql, |
| "data_dpc"); |
| pcm = (struct pc_maint *)IoAdapter->pcm_data; |
| switch (IoAdapter->pcm_pending) { |
| case 1: /* ask card for XLOG */ |
| a->ram_out (a, &IoAdapter->pcm->rc, 0) ; |
| a->ram_out (a, &IoAdapter->pcm->req, pcm->req) ; |
| IoAdapter->pcm_pending = 2; |
| break; |
| case 2: /* Try to get XLOG from the card */ |
| if ((int)(a->ram_in (a, &IoAdapter->pcm->rc))) { |
| a->ram_in_buffer (a, IoAdapter->pcm, pcm, sizeof(*pcm)) ; |
| IoAdapter->pcm_pending = 3; |
| } |
| break; |
| case 3: /* let XDI recovery XLOG */ |
| break; |
| } |
| diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, |
| &OldIrql, |
| "data_dpc"); |
| } |
| /* ---------------------------------------------------------------- */ |
| } |
| } |
| /* -------------------------------------------------------------------------- |
| XLOG interface |
| -------------------------------------------------------------------------- */ |
| static void |
| pcm_req (PISDN_ADAPTER IoAdapter, ENTITY *e) |
| { |
| diva_os_spin_lock_magic_t OldIrql ; |
| int i, rc ; |
| ADAPTER *a = &IoAdapter->a ; |
| struct pc_maint *pcm = (struct pc_maint *)&e->Ind ; |
| /* |
| * special handling of I/O based card interface |
| * the memory access isn't an atomic operation ! |
| */ |
| if ( IoAdapter->Properties.Card == CARD_MAE ) |
| { |
| diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, |
| &OldIrql, |
| "data_pcm_1"); |
| IoAdapter->pcm_data = (void *)pcm; |
| IoAdapter->pcm_pending = 1; |
| diva_os_schedule_soft_isr (&IoAdapter->req_soft_isr); |
| diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, |
| &OldIrql, |
| "data_pcm_1"); |
| for ( rc = 0, i = (IoAdapter->trapped ? 3000 : 250) ; !rc && (i > 0) ; --i ) |
| { |
| diva_os_sleep (1) ; |
| if (IoAdapter->pcm_pending == 3) { |
| diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, |
| &OldIrql, |
| "data_pcm_3"); |
| IoAdapter->pcm_pending = 0; |
| IoAdapter->pcm_data = NULL ; |
| diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, |
| &OldIrql, |
| "data_pcm_3"); |
| return ; |
| } |
| diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, |
| &OldIrql, |
| "data_pcm_2"); |
| diva_os_schedule_soft_isr (&IoAdapter->req_soft_isr); |
| diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, |
| &OldIrql, |
| "data_pcm_2"); |
| } |
| diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, |
| &OldIrql, |
| "data_pcm_4"); |
| IoAdapter->pcm_pending = 0; |
| IoAdapter->pcm_data = NULL ; |
| diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, |
| &OldIrql, |
| "data_pcm_4"); |
| goto Trapped ; |
| } |
| /* |
| * memory based shared ram is accessible from different |
| * processors without disturbing concurrent processes. |
| */ |
| a->ram_out (a, &IoAdapter->pcm->rc, 0) ; |
| a->ram_out (a, &IoAdapter->pcm->req, pcm->req) ; |
| for ( i = (IoAdapter->trapped ? 3000 : 250) ; --i > 0 ; ) |
| { |
| diva_os_sleep (1) ; |
| rc = (int)(a->ram_in (a, &IoAdapter->pcm->rc)) ; |
| if ( rc ) |
| { |
| a->ram_in_buffer (a, IoAdapter->pcm, pcm, sizeof(*pcm)) ; |
| return ; |
| } |
| } |
| Trapped: |
| if ( IoAdapter->trapFnc ) |
| { |
| int trapped = IoAdapter->trapped; |
| IoAdapter->trapFnc (IoAdapter) ; |
| /* |
| Firs trap, also notify user if supported |
| */ |
| if (!trapped && IoAdapter->trapped && IoAdapter->os_trap_nfy_Fnc) { |
| (*(IoAdapter->os_trap_nfy_Fnc))(IoAdapter, IoAdapter->ANum); |
| } |
| } |
| } |
| /*------------------------------------------------------------------*/ |
| /* ram access functions for memory mapped cards */ |
| /*------------------------------------------------------------------*/ |
| byte mem_in (ADAPTER *a, void *addr) |
| { |
| byte val; |
| volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io); |
| val = READ_BYTE(Base + (unsigned long)addr); |
| DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base); |
| return (val); |
| } |
| word mem_inw (ADAPTER *a, void *addr) |
| { |
| word val; |
| volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io); |
| val = READ_WORD((Base + (unsigned long)addr)); |
| DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base); |
| return (val); |
| } |
| void mem_in_dw (ADAPTER *a, void *addr, dword* data, int dwords) |
| { |
| volatile byte __iomem * Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io); |
| while (dwords--) { |
| *data++ = READ_DWORD((Base + (unsigned long)addr)); |
| addr+=4; |
| } |
| DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base); |
| } |
| void mem_in_buffer (ADAPTER *a, void *addr, void *buffer, word length) |
| { |
| volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io); |
| memcpy_fromio(buffer, (Base + (unsigned long)addr), length); |
| DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base); |
| } |
| void mem_look_ahead (ADAPTER *a, PBUFFER *RBuffer, ENTITY *e) |
| { |
| PISDN_ADAPTER IoAdapter = (PISDN_ADAPTER)a->io ; |
| IoAdapter->RBuffer.length = mem_inw (a, &RBuffer->length) ; |
| mem_in_buffer (a, RBuffer->P, IoAdapter->RBuffer.P, |
| IoAdapter->RBuffer.length) ; |
| e->RBuffer = (DBUFFER *)&IoAdapter->RBuffer ; |
| } |
| void mem_out (ADAPTER *a, void *addr, byte data) |
| { |
| volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io); |
| WRITE_BYTE(Base + (unsigned long)addr, data); |
| DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base); |
| } |
| void mem_outw (ADAPTER *a, void *addr, word data) |
| { |
| volatile byte __iomem * Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io); |
| WRITE_WORD((Base + (unsigned long)addr), data); |
| DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base); |
| } |
| void mem_out_dw (ADAPTER *a, void *addr, const dword* data, int dwords) |
| { |
| volatile byte __iomem * Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io); |
| while (dwords--) { |
| WRITE_DWORD((Base + (unsigned long)addr), *data); |
| addr+=4; |
| data++; |
| } |
| DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base); |
| } |
| void mem_out_buffer (ADAPTER *a, void *addr, void *buffer, word length) |
| { |
| volatile byte __iomem * Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io); |
| memcpy_toio((Base + (unsigned long)addr), buffer, length) ; |
| DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base); |
| } |
| void mem_inc (ADAPTER *a, void *addr) |
| { |
| volatile byte __iomem *Base = DIVA_OS_MEM_ATTACH_RAM((PISDN_ADAPTER)a->io); |
| byte x = READ_BYTE(Base + (unsigned long)addr); |
| WRITE_BYTE(Base + (unsigned long)addr, x + 1); |
| DIVA_OS_MEM_DETACH_RAM((PISDN_ADAPTER)a->io, Base); |
| } |
| /*------------------------------------------------------------------*/ |
| /* ram access functions for io-mapped cards */ |
| /*------------------------------------------------------------------*/ |
| byte io_in(ADAPTER * a, void * adr) |
| { |
| byte val; |
| byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io); |
| outppw(Port + 4, (word)(unsigned long)adr); |
| val = inpp(Port); |
| DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port); |
| return(val); |
| } |
| word io_inw(ADAPTER * a, void * adr) |
| { |
| word val; |
| byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io); |
| outppw(Port + 4, (word)(unsigned long)adr); |
| val = inppw(Port); |
| DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port); |
| return(val); |
| } |
| void io_in_buffer(ADAPTER * a, void * adr, void * buffer, word len) |
| { |
| byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io); |
| byte* P = (byte*)buffer; |
| if ((long)adr & 1) { |
| outppw(Port+4, (word)(unsigned long)adr); |
| *P = inpp(Port); |
| P++; |
| adr = ((byte *) adr) + 1; |
| len--; |
| if (!len) { |
| DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port); |
| return; |
| } |
| } |
| outppw(Port+4, (word)(unsigned long)adr); |
| inppw_buffer (Port, P, len+1); |
| DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port); |
| } |
| void io_look_ahead(ADAPTER * a, PBUFFER * RBuffer, ENTITY * e) |
| { |
| byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io); |
| outppw(Port+4, (word)(unsigned long)RBuffer); |
| ((PISDN_ADAPTER)a->io)->RBuffer.length = inppw(Port); |
| inppw_buffer (Port, ((PISDN_ADAPTER)a->io)->RBuffer.P, ((PISDN_ADAPTER)a->io)->RBuffer.length + 1); |
| e->RBuffer = (DBUFFER *) &(((PISDN_ADAPTER)a->io)->RBuffer); |
| DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port); |
| } |
| void io_out(ADAPTER * a, void * adr, byte data) |
| { |
| byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io); |
| outppw(Port+4, (word)(unsigned long)adr); |
| outpp(Port, data); |
| DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port); |
| } |
| void io_outw(ADAPTER * a, void * adr, word data) |
| { |
| byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io); |
| outppw(Port+4, (word)(unsigned long)adr); |
| outppw(Port, data); |
| DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port); |
| } |
| void io_out_buffer(ADAPTER * a, void * adr, void * buffer, word len) |
| { |
| byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io); |
| byte* P = (byte*)buffer; |
| if ((long)adr & 1) { |
| outppw(Port+4, (word)(unsigned long)adr); |
| outpp(Port, *P); |
| P++; |
| adr = ((byte *) adr) + 1; |
| len--; |
| if (!len) { |
| DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port); |
| return; |
| } |
| } |
| outppw(Port+4, (word)(unsigned long)adr); |
| outppw_buffer (Port, P, len+1); |
| DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port); |
| } |
| void io_inc(ADAPTER * a, void * adr) |
| { |
| byte x; |
| byte __iomem *Port = DIVA_OS_MEM_ATTACH_PORT((PISDN_ADAPTER)a->io); |
| outppw(Port+4, (word)(unsigned long)adr); |
| x = inpp(Port); |
| outppw(Port+4, (word)(unsigned long)adr); |
| outpp(Port, x+1); |
| DIVA_OS_MEM_DETACH_PORT((PISDN_ADAPTER)a->io, Port); |
| } |
| /*------------------------------------------------------------------*/ |
| /* OS specific functions related to queuing of entities */ |
| /*------------------------------------------------------------------*/ |
| void free_entity(ADAPTER * a, byte e_no) |
| { |
| PISDN_ADAPTER IoAdapter; |
| diva_os_spin_lock_magic_t irql; |
| IoAdapter = (PISDN_ADAPTER) a->io; |
| diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_free"); |
| IoAdapter->e_tbl[e_no].e = NULL; |
| IoAdapter->e_count--; |
| diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_free"); |
| } |
| void assign_queue(ADAPTER * a, byte e_no, word ref) |
| { |
| PISDN_ADAPTER IoAdapter; |
| diva_os_spin_lock_magic_t irql; |
| IoAdapter = (PISDN_ADAPTER) a->io; |
| diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_assign"); |
| IoAdapter->e_tbl[e_no].assign_ref = ref; |
| IoAdapter->e_tbl[e_no].next = (byte)IoAdapter->assign; |
| IoAdapter->assign = e_no; |
| diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_assign"); |
| } |
| byte get_assign(ADAPTER * a, word ref) |
| { |
| PISDN_ADAPTER IoAdapter; |
| diva_os_spin_lock_magic_t irql; |
| byte e_no; |
| IoAdapter = (PISDN_ADAPTER) a->io; |
| diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, |
| &irql, |
| "data_assign_get"); |
| for(e_no = (byte)IoAdapter->assign; |
| e_no && IoAdapter->e_tbl[e_no].assign_ref!=ref; |
| e_no = IoAdapter->e_tbl[e_no].next); |
| diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, |
| &irql, |
| "data_assign_get"); |
| return e_no; |
| } |
| void req_queue(ADAPTER * a, byte e_no) |
| { |
| PISDN_ADAPTER IoAdapter; |
| diva_os_spin_lock_magic_t irql; |
| IoAdapter = (PISDN_ADAPTER) a->io; |
| diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req_q"); |
| IoAdapter->e_tbl[e_no].next = 0; |
| if(IoAdapter->head) { |
| IoAdapter->e_tbl[IoAdapter->tail].next = e_no; |
| IoAdapter->tail = e_no; |
| } |
| else { |
| IoAdapter->head = e_no; |
| IoAdapter->tail = e_no; |
| } |
| diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req_q"); |
| } |
| byte look_req(ADAPTER * a) |
| { |
| PISDN_ADAPTER IoAdapter; |
| IoAdapter = (PISDN_ADAPTER) a->io; |
| return ((byte)IoAdapter->head) ; |
| } |
| void next_req(ADAPTER * a) |
| { |
| PISDN_ADAPTER IoAdapter; |
| diva_os_spin_lock_magic_t irql; |
| IoAdapter = (PISDN_ADAPTER) a->io; |
| diva_os_enter_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req_next"); |
| IoAdapter->head = IoAdapter->e_tbl[IoAdapter->head].next; |
| if(!IoAdapter->head) IoAdapter->tail = 0; |
| diva_os_leave_spin_lock (&IoAdapter->data_spin_lock, &irql, "data_req_next"); |
| } |
| /*------------------------------------------------------------------*/ |
| /* memory map functions */ |
| /*------------------------------------------------------------------*/ |
| ENTITY * entity_ptr(ADAPTER * a, byte e_no) |
| { |
| PISDN_ADAPTER IoAdapter; |
| IoAdapter = (PISDN_ADAPTER) a->io; |
| return (IoAdapter->e_tbl[e_no].e); |
| } |
| void * PTR_X(ADAPTER * a, ENTITY * e) |
| { |
| return ((void *) e->X); |
| } |
| void * PTR_R(ADAPTER * a, ENTITY * e) |
| { |
| return ((void *) e->R); |
| } |
| void * PTR_P(ADAPTER * a, ENTITY * e, void * P) |
| { |
| return P; |
| } |
| void CALLBACK(ADAPTER * a, ENTITY * e) |
| { |
| if ( e && e->callback ) |
| e->callback (e) ; |
| } |