📄 deviceio.c
字号:
/* *---------------------------------------------------------------------- * T-Kernel * * Copyright (C) 2004-2006 by Ken Sakamura. All rights reserved. * T-Kernel is distributed under the T-License. *---------------------------------------------------------------------- * * Version: 1.02.02 * Released by T-Engine Forum(http://www.t-engine.org) at 2006/8/9. * *---------------------------------------------------------------------- *//* * deviceio.c (T-Kernel/SM) * Device Management Function: Input/Output */#include "sysmgr.h"#include <sys/rominfo.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 ){ 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; 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; } openfn = (OPNFN)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 ) { ercd = E_LIMIT; goto err_ret2; } UnlockDM(); if ( openfn != NULL ) { /* Device driver call */#if TA_GP ercd = CallDeviceDriver(DEVID(devcb, unitno), omode, exinf, 0, (FP)openfn, gp);#else ercd = (*openfn)(DEVID(devcb, unitno), omode, exinf);#endif if ( ercd < 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 ercd = %d\n", ercd)); return ercd;}/* * 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(); 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, (FP)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, (FP)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, (FP)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 ){ 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); /* 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 ercd = CallDeviceDriver(devid, option, exinf, 0, (FP)closefn, gp);#else ercd = (*closefn)(devid, option, exinf);#endif } LockDM(); /* Return open management block to FreeQue */ QueInsert(&opncb->q, &FreeOpnCB); UnlockDM();#ifdef DEBUG if ( ercd < E_OK ) { DEBUG_PRINT(("close_device ercd = %d\n", ercd)); }#endif return ercd;}/* * Device close */EXPORT ER _tk_cls_dev( ID dd, UINT option ){ OpnCB *opncb; ER ercd; LockDM(); ercd = 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 = close_device(opncb, option);err_ret:#ifdef DEBUG if ( ercd < E_OK ) { DEBUG_PRINT(("_tk_cls_dev ercd = %d\n", ercd)); }#endif return ercd;}/* ------------------------------------------------------------------------ *//* * Check break request */LOCAL ER check_break( void ){ T_RTEX rtex; ER ercd; ercd = tk_ref_tex(TSK_SELF, &rtex); if ( ercd < E_OK ) { goto err_ret; } return ( rtex.pendtex != 0 )? E_ABORT: E_OK;err_ret: DEBUG_PRINT(("check_break ercd = %d\n", ercd)); return ercd;}/* * Request for starting input/output to device */LOCAL ID request( ID dd, INT start, VP buf, INT 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(); /* Check whether there is a break request */ ercd = check_break(); if ( ercd < E_OK ) { goto err_ret1; } if ( start <= -0x00010000 && start >= -0x7fffffff ) { m = 0; /* Ignore open mode */ } else { m = ( cmd == TDC_READ )? TD_READ: TD_WRITE; } ercd = check_devdesc(dd, m, &opncb); if ( ercd < E_OK ) { goto err_ret1; } devcb = opncb->devcb; execfn = (EXCFN)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 ) { ercd = 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; ercd = tk_get_tsp(TSK_SELF, &reqcb->req.tskspc); if ( ercd < E_OK ) { goto err_ret2; } /* Indicate that it is during processing */ reqcb->tskid = tk_get_tid(); UnlockDM(); /* Device driver call */#if TA_GP ercd = CallDeviceDriver(&reqcb->req, tmout, exinf, 0, (FP)execfn, gp);#else ercd = (*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); } if ( ercd < E_OK ) { goto err_ret2; } UnlockDM(); return REQID(reqcb);err_ret2: delReqCB(reqcb);err_ret1: UnlockDM(); DEBUG_PRINT(("request ercd = %d\n", ercd)); return ercd;}/* * Start reading from device */EXPORT ID _tk_rea_dev( ID dd, INT start, VP buf, INT size, TMO tmout ){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -