📄 deviceio.c
字号:
/* *---------------------------------------------------------------------- * micro T-Kernel * * Copyright (C) 2006-2007 by Ken Sakamura. All rights reserved. * micro T-Kernel is distributed under the micro T-License. *---------------------------------------------------------------------- * * Version: 1.00.00 * Released by T-Engine Forum(http://www.t-engine.org) at 2007/03/26. * *---------------------------------------------------------------------- *//* * deviceio.c * Device Management Function: Input/Output *//** [BEGIN Common Definitions] */#include "kernel.h"#include "sysmgr.h"#include "device.h"/** [END Common Definitions] */#if CFN_MAX_REGDEV#ifdef USE_FUNC_OPNCBTBLNoinit(EXPORT OpnCB knl_OpnCBtbl[CFN_MAX_OPNDEV]); /* Open management information table */Noinit(EXPORT QUEUE knl_FreeOpnCB); /* Unused queue */#endif /* USE_FUNC_OPNCBTBL */#ifdef USE_FUNC_REQCBTBLNoinit(EXPORT ReqCB knl_ReqCBtbl[CFN_MAX_REQDEV]); /* Request management information table */Noinit(EXPORT QUEUE knl_FreeReqCB); /* Unused queue */#endif /* USE_FUNC_REQCBTBL */#ifdef USE_FUNC_RESOURCE_CONTROL_BLOCKNoinit(EXPORT ResCB knl_resource_control_block);#endif /* USE_FUNC_RESOURCE_CONTROL_BLOCK */#ifdef USE_FUNC_GETRESCB/* * Get resource management information */EXPORT ResCB* knl_GetResCB( void ){ LockDM(); /* If the startup function is not called, initialize at this point */ if ( knl_resource_control_block.openq.next == NULL ) { /* Initialization of open device management queue */ QueInit(&(knl_resource_control_block.openq)); } UnlockDM(); return &knl_resource_control_block;}#endif /* USE_FUNC_GETRESCB */#ifdef USE_FUNC_CHECK_DEVDESC/* * Verify validity of device descriptor */EXPORT ER knl_check_devdesc( ID dd, UINT mode, OpnCB **p_opncb ){ OpnCB *opncb; if ( dd < 1 || dd > CFN_MAX_OPNDEV ) { return E_ID; } opncb = OPNCB(dd); if ( opncb->resid == 0 ) { return E_ID; } if ( mode != 0 ) { if ( (opncb->omode & mode) == 0 ) { return E_OACV; } } *p_opncb = opncb; return E_OK;}#endif /* USE_FUNC_CHECK_DEVDESC */#ifdef USE_FUNC_DELOPNCB/* * Free open management block */EXPORT void knl_delOpnCB( OpnCB *opncb, BOOL free ){ QueRemove(&opncb->q); QueRemove(&opncb->resq); if ( free ) { QueInsert(&opncb->q, &knl_FreeOpnCB); } opncb->resid = 0;}#endif /* USE_FUNC_DELOPNCB */#ifdef USE_FUNC_DELREQCB/* * Free request management block */EXPORT void knl_delReqCB( ReqCB *reqcb ){ QueRemove(&reqcb->q); QueInsert(&reqcb->q, &knl_FreeReqCB); reqcb->opncb = NULL;}#endif /* USE_FUNC_DELREQCB *//* ------------------------------------------------------------------------ */#ifdef USE_FUNC_CHKOPEN/* * TRUE if specified device is open. */EXPORT BOOL knl_chkopen( DevCB *devcb, INT unitno ){ QUEUE *q; for ( q = devcb->openq.next; q != &devcb->openq; q = q->next ) { if ( ((OpnCB*)q)->unitno == unitno ) { return TRUE; } } return FALSE;}#endif /* USE_FUNC_CHKOPEN */#ifdef USE_FUNC_TK_OPN_DEVLOCAL T_CSEM knl_pk_csem_DM = { NULL, TA_TFIFO | TA_FIRST, 0, 1,};/* * Get open management block */LOCAL OpnCB* newOpnCB( DevCB *devcb, INT unitno, UINT omode, ResCB *rescb ){ OpnCB *opncb; /* Get space in open management block */ opncb = (OpnCB*)QueRemoveNext(&knl_FreeOpnCB); if ( opncb == NULL ) { return NULL; /* No space */ } /* Register as open device */ QueInsert(&opncb->q, &devcb->openq); QueInsert(&opncb->resq, &rescb->openq); opncb->devcb = devcb; opncb->unitno = unitno; opncb->omode = omode; QueInit(&opncb->requestq); opncb->waitone = 0; opncb->nwaireq = 0; opncb->abort_tskid = 0; opncb->resid = 0; /* Indicate that open processing is not completed */ return opncb;}/* * Check open mode */LOCAL ER chkopenmode( DevCB *devcb, INT unitno, UINT omode ){ QUEUE *q; OpnCB *opncb; INT read, write, rexcl, wexcl; if ( (omode & TD_UPDATE) == 0 ) { return E_PAR; } /* Check current open state */ read = write = rexcl = wexcl = 0; for ( q = devcb->openq.next; q != &devcb->openq; q = q->next ) { opncb = (OpnCB*)q; if ( unitno == 0 || opncb->unitno == 0 || opncb->unitno == unitno ) { if ( (opncb->omode & TD_READ) != 0 ) { read++; } if ( (opncb->omode & TD_WRITE) != 0 ) { write++; } if ( (opncb->omode & (TD_EXCL|TD_REXCL)) != 0) { rexcl++; } if ( (opncb->omode & (TD_EXCL|TD_WEXCL)) != 0) { wexcl++; } } } /* Is it able to open? */ if ( (omode & (TD_EXCL|TD_REXCL)) != 0 && read > 0 ) { return E_BUSY; } if ( (omode & (TD_EXCL|TD_WEXCL)) != 0 && write > 0 ) { return E_BUSY; } if ( (omode & TD_READ) != 0 && rexcl > 0 ) { return E_BUSY; } if ( (omode & TD_WRITE) != 0 && wexcl > 0 ) { return E_BUSY; } return E_OK;}/* * 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;}#endif /* USE_FUNC_TK_OPN_DEV */#ifdef USE_FUNC_CLOSE_DEVICE/* * Abort all requests */LOCAL void abort_allrequest( OpnCB *opncb ){ ABTFN abortfn; WAIFN waitfn; VP exinf;#if TA_GP VP gp;#endif DevCB *devcb; ReqCB *reqcb; QUEUE *q; /* If 'execfn' and 'waitfn' are called, execute abort request. */ LockDM(); devcb = opncb->devcb; abortfn = (ABTFN)devcb->ddev.abortfn; waitfn = (WAIFN)devcb->ddev.waitfn; exinf = devcb->ddev.exinf;#if TA_GP gp = devcb->ddev.gp;#endif opncb->abort_tskid = tk_get_tid_impl(); opncb->abort_cnt = 0; if ( opncb->nwaireq > 0 ) { /* Multiple requests wait */ reqcb = DEVREQ_REQCB(opncb->waireqlst); /* Device driver call */ DISABLE_INTERRUPT; knl_ctxtsk->sysmode++; ENABLE_INTERRUPT;#if TA_GP CallDeviceDriver(reqcb->tskid, opncb->waireqlst, opncb->nwaireq, exinf, (FP)abortfn, gp);#else (*abortfn)(reqcb->tskid, opncb->waireqlst, opncb->nwaireq, exinf);#endif DISABLE_INTERRUPT; knl_ctxtsk->sysmode--; ENABLE_INTERRUPT; opncb->abort_cnt++; } else { /* Start request or single request wait */ for ( q = opncb->requestq.next; q != &opncb->requestq; q = q->next ) { reqcb = (ReqCB*)q; if ( reqcb->tskid == 0 ) { continue; } reqcb->req.abort = TRUE; /* Device driver call */ DISABLE_INTERRUPT; knl_ctxtsk->sysmode++; ENABLE_INTERRUPT;#if TA_GP CallDeviceDriver(reqcb->tskid, &reqcb->req, 1, exinf, (FP)abortfn, gp);#else (*abortfn)(reqcb->tskid, &reqcb->req, 1, exinf);#endif DISABLE_INTERRUPT; knl_ctxtsk->sysmode--; ENABLE_INTERRUPT; opncb->abort_cnt++; } } UnlockDM(); if ( opncb->abort_cnt > 0 ) { /* Wait for completion of abort request processing */ tk_wai_sem_impl(opncb->abort_semid, 1, TMO_FEVR); } opncb->abort_tskid = 0; /* Abort remaining requests and wait for completion */ LockDM(); while ( !isQueEmpty(&opncb->requestq) ) { reqcb = (ReqCB*)opncb->requestq.next; reqcb->req.abort = TRUE; UnlockDM(); /* Device driver call */ DISABLE_INTERRUPT; knl_ctxtsk->sysmode++; ENABLE_INTERRUPT;#if TA_GP CallDeviceDriver(&reqcb->req, 1, TMO_FEVR, exinf, (FP)waitfn, gp);#else (*waitfn)(&reqcb->req, 1, TMO_FEVR, exinf);#endif DISABLE_INTERRUPT; knl_ctxtsk->sysmode--; ENABLE_INTERRUPT; LockDM(); /* Unregister completed request */ knl_delReqCB(reqcb); } UnlockDM();}/* * Device close processing */EXPORT ER knl_close_device( OpnCB *opncb, UINT option ){ CLSFN closefn; VP exinf;#if TA_GP VP gp;#endif ID devid; DevCB *devcb; INT unitno; ER ercd = E_OK; /* Abort all requests during processing */ abort_allrequest(opncb); LockDM(); devcb = opncb->devcb; unitno = opncb->unitno; closefn = (CLSFN)devcb->ddev.closefn; exinf = devcb->ddev.exinf;#if TA_GP gp = devcb->ddev.gp;#endif devid = DEVID(devcb, unitno); /* Delete semaphore for completion check of abortion */ tk_del_sem_impl(opncb->abort_semid); /* Free open management block */ knl_delOpnCB(opncb, FALSE); /* Is device driver call required? */ if ( knl_chkopen(devcb, unitno) ) { option &= ~TD_EJECT; if ( (devcb->ddev.drvatr & TDA_OPENREQ) == 0 ) { closefn = NULL; } } UnlockDM(); if ( closefn != NULL ) { /* Device driver call */ DISABLE_INTERRUPT; knl_ctxtsk->sysmode++; ENABLE_INTERRUPT;#if TA_GP ercd = CallDeviceDriver(devid, option, exinf, 0, (FP)closefn, gp);#else ercd = (*closefn)(devid, option, exinf);#endif DISABLE_INTERRUPT; knl_ctxtsk->sysmode--; ENABLE_INTERRUPT; } LockDM(); /* Return open management block to FreeQue */ QueInsert(&opncb->q, &knl_FreeOpnCB); UnlockDM();#ifdef DEBUG if ( ercd < E_OK ) { DEBUG_PRINT(("knl_close_device ercd = %d\n", ercd)); }#endif return ercd;}#endif /* USE_FUNC_CLOSE_DEVICE */#ifdef USE_FUNC_TK_CLS_DEV/* * Device close */SYSCALL ER tk_cls_dev_impl( ID dd, UINT option ){ OpnCB *opncb; ER ercd; LockDM(); ercd = knl_check_devdesc(dd, 0, &opncb); if ( ercd < E_OK ) { UnlockDM(); goto err_ret; } opncb->resid = 0; /* Indicate that it is during close processing */ UnlockDM(); /* Device close processing */ ercd = knl_close_device(opncb, option);err_ret:#ifdef DEBUG if ( ercd < E_OK ) { DEBUG_PRINT(("tk_cls_dev_impl ercd = %d\n", ercd)); }#endif return ercd;}#endif /* USE_FUNC_TK_CLS_DEV *//* ------------------------------------------------------------------------ */#ifdef USE_FUNC_REQUEST/* * Get request management block */LOCAL ReqCB* newReqCB( OpnCB *opncb ){ ReqCB *reqcb; /* Get space in request management block */ reqcb = (ReqCB*)QueRemoveNext(&knl_FreeReqCB); if ( reqcb == NULL ) { return NULL; /* No space */ } /* Register as requested open device */ QueInsert(&reqcb->q, &opncb->requestq); reqcb->opncb = opncb; return reqcb;}/* * Request for starting input/output to device */EXPORT ID knl_request( ID dd, W start, VP buf, W size, TMO tmout, INT cmd ){ EXCFN execfn; VP exinf;#if TA_GP VP gp;#endif OpnCB *opncb; DevCB *devcb; ReqCB *reqcb; UINT m; ER ercd; LockDM(); if ( start <= -0x00010000 && start >= -0x7fffffff ) { m = 0; /* Ignore open mode */ } else { m = ( cmd == TDC_READ )? TD_READ: TD_WRITE; } ercd = knl_check_devdesc(dd, m, &opncb); if ( ercd < E_OK ) { goto err_ret1; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -