📄 deviceio.c
字号:
/* *---------------------------------------------------------------------- * T-Kernel * * Copyright (C) 2004 by Ken Sakamura. All rights reserved. * T-Kernel is distributed under the T-License. *---------------------------------------------------------------------- * * Version: 1.01.00 * Released by T-Engine Forum(http://www.t-engine.org) at 2004/6/28. * *---------------------------------------------------------------------- *//* * deviceio.c (T-Kernel/SM) * Device Management Function: Input/Output */#include "sysmgr.h"#include <sys/ssid.h>LOCAL OpnCB *OpnCBtbl; /* Open management information table */LOCAL QUEUE FreeOpnCB; /* Unused queue */LOCAL INT MaxOpnDev; /* Maximum number of devices open */#define DD(opncb) ( (opncb) - OpnCBtbl + 1 )#define OPNCB(dd) ( OpnCBtbl + ((dd) - 1) )LOCAL ReqCB *ReqCBtbl; /* Request management information table */LOCAL QUEUE FreeReqCB; /* Unused queue */LOCAL INT MaxReqDev; /* Maximum number of device requests */#define REQID(reqcb) ( (reqcb) - ReqCBtbl + 1 )#define REQCB(reqid) ( ReqCBtbl + ((reqid) - 1) )#define DEVREQ_REQCB(devreq) ((ReqCB*)((B*)(devreq) - offsetof(ReqCB, req)))/* * Get resource management information */LOCAL ResCB* GetResCB( ID ssid, ID tskid ){ ResCB *rescb; rescb = GetResBlk(ssid, tskid); if ( rescb == NULL ) return NULL; LockDM(); /* If the startup function is not called, initialize at this point */ if ( rescb->openq.next == NULL ) { /* Initialization of open device management queue */ QueInit(&rescb->openq); } UnlockDM(); return rescb;}/* * Verify validity of device descriptor */EXPORT ER check_devdesc( ID dd, UINT mode, OpnCB **p_opncb ){ OpnCB *opncb; if ( dd < 1 || dd > MaxOpnDev ) return E_ID; opncb = OPNCB(dd); if ( opncb->resid == 0 ) return E_ID; if ( opncb->resid != tk_get_rid(TSK_SELF) ) return E_OACV; if ( mode != 0 ) { if ( (opncb->omode & mode) == 0 ) return E_OACV; } *p_opncb = opncb; return E_OK;}/* * Verify validity of request ID */LOCAL ReqCB* check_reqid( ID reqid, OpnCB *opncb ){ ReqCB *reqcb; if ( reqid < 1 || reqid > MaxReqDev ) return NULL; reqcb = REQCB(reqid); if ( reqcb->opncb != opncb ) return NULL; return reqcb;}/* * 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(&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;}/* * Free open management block */LOCAL void delOpnCB( OpnCB *opncb, BOOL free ){ QueRemove(&opncb->q); QueRemove(&opncb->resq); if ( free ) { QueInsert(&opncb->q, &FreeOpnCB); } opncb->resid = 0;}/* * Get request management block */LOCAL ReqCB* newReqCB( OpnCB *opncb ){ ReqCB *reqcb; /* Get space in request management block */ reqcb = (ReqCB*)QueRemoveNext(&FreeReqCB); if ( reqcb == NULL ) return NULL; /* No space */ /* Register as requested open device */ QueInsert(&reqcb->q, &opncb->requestq); reqcb->opncb = opncb; return reqcb;}/* * Free request management block */LOCAL void delReqCB( ReqCB *reqcb ){ QueRemove(&reqcb->q); QueInsert(&reqcb->q, &FreeReqCB); reqcb->opncb = NULL;}/* ------------------------------------------------------------------------ *//* * 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;}/* * TRUE if specified device is open. */LOCAL BOOL 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;}/* * Device open */EXPORT ID _tk_opn_dev( UB *devnm, UINT omode ){ ER (*openfn)( ID devid, UINT omode, VP exinf ); VP exinf;#if TA_GP VP gp;#endif UB pdevnm[L_DEVNM + 1]; INT unitno; ResCB *rescb; DevCB *devcb; OpnCB *opncb; ER err; err = ChkSpaceBstrR(devnm, 0); if ( err < E_OK ) goto err_ret1; unitno = phydevnm(pdevnm, devnm); /* Get resource management information */ rescb = GetResCB(DEVICE_SVC, TSK_SELF); if ( rescb == NULL ) { err = E_CTX; goto err_ret1; } LockDM(); /* Search device to open */ devcb = searchDevCB(pdevnm); if ( devcb == NULL || unitno > devcb->ddev.nsub ) { err = E_NOEXS; goto err_ret2; } /* Check open mode */ err = chkopenmode(devcb, unitno, omode); if ( err < E_OK ) goto err_ret2; openfn = (VP)devcb->ddev.openfn; exinf = devcb->ddev.exinf;#if TA_GP gp = devcb->ddev.gp;#endif /* Is device driver call required? */ if ( chkopen(devcb, unitno) && (devcb->ddev.drvatr & TDA_OPENREQ) == 0 ) openfn = NULL; /* Get open management block */ opncb = newOpnCB(devcb, unitno, omode, rescb); if ( opncb == NULL ) { err = E_LIMIT; goto err_ret2; } UnlockDM(); if ( openfn != NULL ) { /* Device driver call */#if TA_GP err = CallDeviceDriver(DEVID(devcb, unitno), omode, exinf, 0, openfn, gp);#else err = (*openfn)(DEVID(devcb, unitno), omode, exinf);#endif if ( err < E_OK ) goto err_ret3; } LockDM(); opncb->resid = tk_get_rid(TSK_SELF); /* Indicate that open processing is completed */ UnlockDM(); return DD(opncb);err_ret3: LockDM(); delOpnCB(opncb, TRUE);err_ret2: UnlockDM();err_ret1: DEBUG_PRINT(("_tk_opn_dev err = %d\n", err)); return err;}/* * Abort all requests */LOCAL void abort_allrequest( OpnCB *opncb ){ ER (*abortfn)( ID tskid, T_DEVREQ *devreq, INT nreq, VP exinf ); INT (*waitfn)( T_DEVREQ *devreq, INT nreq, TMO tmout, VP exinf ); 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 = (VP)devcb->ddev.abortfn; waitfn = (VP)devcb->ddev.waitfn; exinf = devcb->ddev.exinf;#if TA_GP gp = devcb->ddev.gp;#endif opncb->abort_tskid = tk_get_tid(); opncb->abort_cnt = 0; if ( opncb->nwaireq > 0 ) { /* Multiple requests wait */ reqcb = DEVREQ_REQCB(opncb->waireqlst); /* Device driver call */#if TA_GP CallDeviceDriver(reqcb->tskid, opncb->waireqlst, opncb->nwaireq, exinf, abortfn, gp);#else (*abortfn)(reqcb->tskid, opncb->waireqlst, opncb->nwaireq, exinf);#endif 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 */#if TA_GP CallDeviceDriver(reqcb->tskid, &reqcb->req, 1, exinf, abortfn, gp);#else (*abortfn)(reqcb->tskid, &reqcb->req, 1, exinf);#endif opncb->abort_cnt++; } } UnlockDM(); if ( opncb->abort_cnt > 0 ) { /* Wait for completion of abort request processing */ SyncWaitDM(); } 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 */#if TA_GP CallDeviceDriver(&reqcb->req, 1, TMO_FEVR, exinf, waitfn, gp);#else (*waitfn)(&reqcb->req, 1, TMO_FEVR, exinf);#endif LockDM(); /* Unregister completed request */ delReqCB(reqcb); } UnlockDM();}/* * Device close processing */LOCAL ER close_device( OpnCB *opncb, UINT option ){ ER (*closefn)( ID devid, UINT option, VP exinf ); VP exinf;#if TA_GP VP gp;#endif ID devid; DevCB *devcb; INT unitno; ER err, error = E_OK; /* Abort all requests during processing */ abort_allrequest(opncb); LockDM(); devcb = opncb->devcb; unitno = opncb->unitno; closefn = (VP)devcb->ddev.closefn; exinf = devcb->ddev.exinf;#if TA_GP gp = devcb->ddev.gp;#endif devid = DEVID(devcb, unitno); /* Free open management block */ delOpnCB(opncb, FALSE); /* Is device driver call required? */ if ( chkopen(devcb, unitno) ) { option &= ~TD_EJECT; if ( (devcb->ddev.drvatr & TDA_OPENREQ) == 0 ) closefn = NULL; } UnlockDM(); if ( closefn != NULL ) { /* Device driver call */#if TA_GP err = CallDeviceDriver(devid, option, exinf, 0, closefn, gp);#else err = (*closefn)(devid, option, exinf);#endif if ( err < E_OK ) error = err; } LockDM(); /* Return open management block to FreeQue */ QueInsert(&opncb->q, &FreeOpnCB); UnlockDM();#ifdef DEBUG if ( error < E_OK ) DEBUG_PRINT(("close_device err = %d\n", error));#endif return error;}/* * Device close */EXPORT ER _tk_cls_dev( ID dd, UINT option ){ OpnCB *opncb; ER err, error = E_OK; LockDM(); err = check_devdesc(dd, 0, &opncb); if ( err < E_OK ) { error = err; UnlockDM(); goto err_ret; } opncb->resid = 0; /* Indicate that it is during close processing */ UnlockDM(); /* Device close processing */ err = close_device(opncb, option); if ( err < E_OK ) error = err;err_ret:#ifdef DEBUG if ( error < E_OK ) DEBUG_PRINT(("_tk_cls_dev err = %d\n", error));#endif return error;}/* ------------------------------------------------------------------------ *//* * Check break request */LOCAL ER check_break( void ){ T_RTEX rtex; ER err; err = tk_ref_tex(TSK_SELF, &rtex); if ( err < E_OK ) goto err_ret; return ( rtex.pendtex != 0 )? E_ABORT: E_OK;err_ret: DEBUG_PRINT(("check_break err = %d\n", err)); return err;}/* * Request for starting input/output to device */LOCAL ID request( ID dd, INT start, VP buf, INT size, TMO tmout, INT cmd ){ ER (*execfn)( T_DEVREQ *devreq, TMO tmout, VP exinf ); VP exinf;#if TA_GP VP gp;#endif OpnCB *opncb; DevCB *devcb; ReqCB *reqcb; UINT m; ER err; LockDM(); /* Check whether there is a break request */ err = check_break(); if ( err < E_OK ) goto err_ret1; if ( start <= -0x00010000 && start >= -0x7fffffff ) { m = 0; /* Ignore open mode */ } else { m = ( cmd == TDC_READ )? TD_READ: TD_WRITE; } err = check_devdesc(dd, m, &opncb); if ( err < E_OK ) goto err_ret1; devcb = opncb->devcb; execfn = (VP)devcb->ddev.execfn; exinf = devcb->ddev.exinf;#if TA_GP gp = devcb->ddev.gp;#endif /* Get request management block */ reqcb = newReqCB(opncb); if ( reqcb == NULL ) { err = E_LIMIT; goto err_ret1; } /* Set request packet */ reqcb->req.next = NULL; reqcb->req.exinf = NULL; reqcb->req.devid = DEVID(devcb, opncb->unitno); reqcb->req.cmd = cmd; reqcb->req.abort = FALSE; reqcb->req.nolock = ( (opncb->omode & TD_NOLOCK) != 0 )? TRUE: FALSE; reqcb->req.rsv = 0; reqcb->req.start = start; reqcb->req.size = size; reqcb->req.buf = buf; reqcb->req.asize = 0; reqcb->req.error = 0; err = tk_get_tsp(TSK_SELF, &reqcb->req.tskspc); if ( err < E_OK ) goto err_ret2; /* Indicate that it is during processing */ reqcb->tskid = tk_get_tid(); UnlockDM(); /* Device driver call */#if TA_GP err = CallDeviceDriver(&reqcb->req, tmout, exinf, 0, execfn, gp);#else err = (*execfn)(&reqcb->req, tmout, exinf);#endif LockDM(); /* Indicate that it is not during processing */ reqcb->tskid = 0; /* If there is an abort completion wait task, notify abort completion */ if ( opncb->abort_tskid > 0 && --opncb->abort_cnt == 0 ) { SyncSignalDM(opncb->abort_tskid);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -