/* * Device open */ SYSCALL ID tk_opn_dev_impl( UB *devnm, UINT omode ) { OPNFN openfn; VP exinf; #if TA_GP VP gp; #endif UB pdevnm[L_DEVNM + 1]; INT unitno; ResCB *rescb; DevCB *devcb; OpnCB *opncb; ER ercd; ID semid; unitno = knl_phydevnm(pdevnm, devnm); /* Get resource management information */ rescb = knl_GetResCB(); if ( rescb == NULL ) { ercd = E_CTX; goto err_ret1; } LockDM(); /* Search device to open */ devcb = knl_searchDevCB(pdevnm); if ( devcb == NULL || unitno > devcb->ddev.nsub ) { ercd = E_NOEXS; goto err_ret2; } /* Check open mode */ ercd = chkopenmode(devcb, unitno, omode); if ( ercd < E_OK ) { goto err_ret2; } openfn = (OPNFN)devcb->ddev.openfn; exinf = devcb->ddev.exinf; #if TA_GP gp = devcb->ddev.gp; #endif /* Is device driver call required? */ if ( knl_chkopen(devcb, unitno) && (devcb->ddev.drvatr & TDA_OPENREQ) == 0 ) { openfn = NULL; } /* Get open management block */ opncb = newOpnCB(devcb, unitno, omode, rescb); if ( opncb == NULL ) { ercd = E_LIMIT; goto err_ret2; } semid = tk_cre_sem_impl(&knl_pk_csem_DM); if ( semid < E_OK ) { ercd = E_SYS; goto err_ret2_5; } opncb->abort_semid = semid; UnlockDM(); if ( openfn != NULL ) { /* Device driver call */ DISABLE_INTERRUPT; knl_ctxtsk->sysmode++; ENABLE_INTERRUPT; #if TA_GP ercd = CallDeviceDriver(DEVID(devcb, unitno), omode, exinf, 0, (FP)openfn, gp); #else ercd = (*openfn)(DEVID(devcb, unitno), omode, exinf); #endif DISABLE_INTERRUPT; knl_ctxtsk->sysmode--; ENABLE_INTERRUPT; if ( ercd < E_OK ) { goto err_ret3; } } LockDM(); opncb->resid = 1; /* Indicate that open processing is completed */ UnlockDM(); return DD(opncb); err_ret3: LockDM(); err_ret2_5: knl_delOpnCB(opncb, TRUE); err_ret2: UnlockDM(); err_ret1: DEBUG_PRINT(("tk_opn_dev_impl ercd = %d\n", ercd)); return ercd; }
/* * Device open */ EXPORT ID _tk_opn_dev( CONST UB *devnm, UINT omode ) { UB pdevnm[L_DEVNM + 1]; INT unitno; ResCB *rescb; DevCB *devcb; OpnCB *opncb; WaitQ waiq; ER ercd; ercd = ChkSpaceBstrR(devnm, 0); if ( ercd < E_OK ) { goto err_ret1; } unitno = phydevnm(pdevnm, devnm); /* Get resource management information */ rescb = GetResCB(DEVICE_SVC, TSK_SELF); if ( rescb == NULL ) { ercd = E_CTX; goto err_ret1; } LockDM(); /* Search device to open */ devcb = searchDevCB(pdevnm); if ( devcb == NULL || unitno > devcb->ddev.nsub ) { ercd = E_NOEXS; goto err_ret2; } /* Check open mode */ ercd = chkopenmode(devcb, unitno, omode); if ( ercd < E_OK ) { goto err_ret2; } /* Get open management block */ opncb = newOpnCB(devcb, unitno, omode, rescb); if ( opncb == NULL ) { ercd = E_LIMIT; goto err_ret2; } /* Multiple tasks can initiate open/close processing, so ensure processing only by one task at a time. */ if ( enterSyncWait(&devcb->syncq, &waiq) ) { /* Wait for synchronization for concurrent open/close */ UnlockDM(); SyncWaitDM(); LockDM(); } /* Is device driver call required? */ if ( ! ( chkopen(devcb, unitno, opncb) && (devcb->ddev.drvatr & TDA_OPENREQ) == 0 ) ) { /* Device driver call */ UnlockDM(); ercd = call_openfn(devcb, DEVID(devcb, unitno), omode); LockDM(); if ( ercd < E_OK ) { goto err_ret3; } } opncb->resid = tk_get_rid(TSK_SELF); /* Indicate that open processing is completed */ /* Wake up task waiting for synchronization for concurrent open/close */ leaveSyncWait(&devcb->syncq, &waiq); UnlockDM(); return DD(opncb); err_ret3: delOpnCB(opncb); leaveSyncWait(&devcb->syncq, &waiq); err_ret2: UnlockDM(); err_ret1: DEBUG_PRINT(("_tk_opn_dev ercd = %d\n", ercd)); return ercd; }