gonzui


Format: Advanced Search

mtkernel_3/kernel/tkernel/deviceio.cbare sourcepermlink (0.09 seconds)

Search this content:

    1: /*
    2:  *----------------------------------------------------------------------
    3:  *    micro T-Kernel 3.00.00
    4:  *
    5:  *    Copyright (C) 2006-2019 by Ken Sakamura.
    6:  *    This software is distributed under the T-License 2.1.
    7:  *----------------------------------------------------------------------
    8:  *
    9:  *    Released by TRON Forum(http://www.tron.org) at 2019/12/11.
   10:  *
   11:  *----------------------------------------------------------------------
   12:  */
   13: 
   14: /*
   15:  *      deviceio.c
   16:  *      Device Management Function: Input/Output
   17:  */
   18: 
   19: #include "kernel.h"
   20: #include "sysmgr.h"
   21: #include "device.h"
   22: 
   23: #if USE_DEVICE
   24: 
   25: Noinit(EXPORT OpnCB     knl_OpnCBtbl[MAX_OPNDEV]);  /* Open management information table */
   26: Noinit(EXPORT QUEUE     knl_FreeOpnCB);     /* Unused queue */
   27: 
   28: Noinit(EXPORT ReqCB     knl_ReqCBtbl[MAX_REQDEV]);  /* Request management information table */
   29: Noinit(EXPORT QUEUE     knl_FreeReqCB);     /* Unused queue */
   30: 
   31: Noinit(EXPORT ResCB knl_resource_control_block);
   32: 
   33: 
   34: /*
   35:  * Get resource management information
   36:  */
   37: EXPORT ResCB* knl_GetResCB( void )
   38: {
   39:         LockDM();
   40: 
   41:         /* If the startup function is not called, initialize at this point */
   42:         if ( knl_resource_control_block.openq.next == NULL ) {
   43:                 /* Initialization of open device management queue */
   44:                 QueInit(&(knl_resource_control_block.openq));
   45:         }
   46: 
   47:         UnlockDM();
   48: 
   49:         return &knl_resource_control_block;
   50: }
   51: 
   52: /*
   53:  * Verify validity of device descriptor
   54:  */
   55: EXPORT ER knl_check_devdesc( ID dd, UINT mode, OpnCB **p_opncb )
   56: {
   57:         OpnCB  *opncb;
   58: 
   59:         if ( dd < 1 || dd > MAX_OPNDEV ) {
   60:                 return E_ID;
   61:         }
   62:         opncb = OPNCB(dd);
   63:         if ( opncb->resid == 0 ) {
   64:                 return E_ID;
   65:         }
   66: 
   67:         if ( mode != 0 ) {
   68:                 if ( (opncb->omode & mode) == 0 ) {
   69:                         return E_OACV;
   70:                 }
   71:         }
   72: 
   73:         *p_opncb = opncb;
   74:         return E_OK;
   75: }
   76: 
   77: /*
   78:  * Free open management block
   79:  */
   80: EXPORT void knl_delOpnCB( OpnCB *opncb, BOOL free )
   81: {
   82:         QueRemove(&opncb->q);
   83:         QueRemove(&opncb->resq);
   84: 
   85:         if ( free ) {
   86:                 QueInsert(&opncb->q, &knl_FreeOpnCB);
   87:         }
   88:         opncb->resid = 0;
   89: }
   90: 
   91: /*
   92:  * Free request management block
   93:  */
   94: EXPORT void knl_delReqCB( ReqCB *reqcb )
   95: {
   96:         QueRemove(&reqcb->q);
   97: 
   98:         QueInsert(&reqcb->q, &knl_FreeReqCB);
   99:         reqcb->opncb = NULL;
  100: }
  101: 
  102: /* ------------------------------------------------------------------------ */
  103: 
  104: /*
  105:  * TRUE if specified device is open.
  106:  */
  107: EXPORT BOOL knl_chkopen( DevCB *devcb, INT unitno )
  108: {
  109:         QUEUE  *q;
  110: 
  111:         for ( q = devcb->openq.next; q != &devcb->openq; q = q->next ) {
  112:                 if ( ((OpnCB*)q)->unitno == unitno ) {
  113:                         return TRUE;
  114:                 }
  115:         }
  116:         return FALSE;
  117: }
  118: 
  119: 
  120: LOCAL CONST T_CSEM knl_pk_csem_DM = {
  121:         NULL,
  122:         TA_TFIFO | TA_FIRST,
  123:         0,
  124:         1,
  125: };
  126: 
  127: /*
  128:  * Get open management block
  129:  */
  130: LOCAL OpnCB* newOpnCB( DevCB *devcb, INT unitno, UINT omode, ResCB *rescb )
  131: {
  132:         OpnCB  *opncb;
  133: 
  134:         /* Get space in open management block */
  135:         opncb = (OpnCB*)QueRemoveNext(&knl_FreeOpnCB);
  136:         if ( opncb == NULL ) {
  137:                 return NULL; /* No space */
  138:         }
  139: 
  140:         /* Register as open device */
  141:         QueInsert(&opncb->q, &devcb->openq);
  142:         QueInsert(&opncb->resq, &rescb->openq);
  143: 
  144:         opncb->devcb  = devcb;
  145:         opncb->unitno = unitno;
  146:         opncb->omode  = omode;
  147:         QueInit(&opncb->requestq);
  148:         opncb->waitone = 0;
  149:         opncb->nwaireq = 0;
  150:         opncb->abort_tskid = 0;
  151: 
  152:         opncb->resid  = 0; /* Indicate that open processing is not completed */
  153: 
  154:         return opncb;
  155: }
  156: 
  157: /*
  158:  * Check open mode
  159:  */
  160: LOCAL ER chkopenmode( DevCB *devcb, INT unitno, UINT omode )
  161: {
  162:         QUEUE  *q;
  163:         OpnCB  *opncb;
  164:         INT    read, write, rexcl, wexcl;
  165: 
  166:         if ( (omode & TD_UPDATE) == 0 ) {
  167:                 return E_PAR;
  168:         }
  169: 
  170:         /* Check current open state */
  171:         read = write = rexcl = wexcl = 0;
  172:         for ( q = devcb->openq.next; q != &devcb->openq; q = q->next ) {
  173:                 opncb = (OpnCB*)q;
  174: 
  175:                 if ( unitno == 0 || opncb->unitno == 0 || opncb->unitno == unitno ) {
  176:                         if ( (opncb->omode & TD_READ)  != 0 ) {
  177:                                 read++;
  178:                         }
  179:                         if ( (opncb->omode & TD_WRITE) != 0 ) {
  180:                                 write++;
  181:                         }
  182:                         if ( (opncb->omode & (TD_EXCL|TD_REXCL)) != 0) {
  183:                                 rexcl++;
  184:                         }
  185:                         if ( (opncb->omode & (TD_EXCL|TD_WEXCL)) != 0) {
  186:                                 wexcl++;
  187:                         }
  188:                 }
  189:         }
  190: 
  191:         /* Is it able to open? */
  192:         if ( (omode & (TD_EXCL|TD_REXCL)) != 0 && read  > 0 ) {
  193:                 return E_BUSY;
  194:         }
  195:         if ( (omode & (TD_EXCL|TD_WEXCL)) != 0 && write > 0 ) {
  196:                 return E_BUSY;
  197:         }
  198:         if ( (omode & TD_READ)  != 0 && rexcl > 0 ) {
  199:                 return E_BUSY;
  200:         }
  201:         if ( (omode & TD_WRITE) != 0 && wexcl > 0 ) {
  202:                 return E_BUSY;
  203:         }
  204: 
  205:         return E_OK;
  206: }
  207: 
  208: /*
  209:  * Device open
  210:  */
  211: SYSCALL ID tk_opn_dev( CONST UB *devnm, UINT omode )
  212: {
  213:         OPNFN  openfn;
  214:         void   *exinf;
  215:         UB     pdevnm[L_DEVNM + 1];
  216:         INT    unitno;
  217:         ResCB  *rescb;
  218:         DevCB  *devcb;
  219:         OpnCB  *opncb;
  220:         ER     ercd;
  221:         ID     semid;
  222: 
  223:         unitno = knl_phydevnm(pdevnm, devnm);
  224: 
  225:         /* Get resource management information */
  226:         rescb = knl_GetResCB();
  227:         if ( rescb == NULL ) {
  228:                 ercd = E_CTX;
  229:                 goto err_ret1;
  230:         }
  231: 
  232:         LockDM();
  233: 
  234:         /* Search device to open */
  235:         devcb = knl_searchDevCB(pdevnm);
  236:         if ( devcb == NULL || unitno > devcb->ddev.nsub ) {
  237:                 ercd = E_NOEXS;
  238:                 goto err_ret2;
  239:         }
  240: 
  241:         /* Check open mode */
  242:         ercd = chkopenmode(devcb, unitno, omode);
  243:         if ( ercd < E_OK ) {
  244:                 goto err_ret2;
  245:         }
  246: 
  247:         openfn = (OPNFN)devcb->ddev.openfn;
  248:         exinf = devcb->ddev.exinf;
  249: 
  250:         /* Is device driver call required? */
  251:         if ( knl_chkopen(devcb, unitno) && (devcb->ddev.drvatr & TDA_OPENREQ) == 0 ) {
  252:                 openfn = NULL;
  253:         }
  254: 
  255:         /* Get open management block */
  256:         opncb = newOpnCB(devcb, unitno, omode, rescb);
  257:         if ( opncb == NULL ) {
  258:                 ercd = E_LIMIT;
  259:                 goto err_ret2;
  260:         }
  261: 
  262:         semid = tk_cre_sem(&knl_pk_csem_DM);
  263:         if ( semid < E_OK ) {
  264:                 ercd = E_SYS;
  265:                 goto err_ret2_5;
  266:         }
  267:         opncb->abort_semid = semid;
  268: 
  269:         UnlockDM();
  270: 
  271:         if ( openfn != NULL ) {
  272:                 /* Device driver call */
  273:                 DISABLE_INTERRUPT;
  274:                 knl_ctxtsk->sysmode++;
  275:                 ENABLE_INTERRUPT;
  276:                 ercd = (*openfn)(DEVID(devcb, unitno), omode, exinf);
  277:                 DISABLE_INTERRUPT;
  278:                 knl_ctxtsk->sysmode--;
  279:                 ENABLE_INTERRUPT;
  280: 
  281:                 if ( ercd < E_OK ) {
  282:                         goto err_ret3;
  283:                 }
  284:         }
  285: 
  286:         LockDM();
  287:         opncb->resid = 1; /* Indicate that open processing is completed */
  288:         UnlockDM();
  289: 
  290:         return DD(opncb);
  291: 
  292: err_ret3:
  293:         LockDM();
  294:         tk_del_sem(opncb->abort_semid);
  295: err_ret2_5:
  296:         knl_delOpnCB(opncb, TRUE);
  297: err_ret2:
  298:         UnlockDM();
  299: err_ret1:
  300:         return ercd;
  301: }
  302: 
  303: /*
  304:  * Abort all requests
  305:  */
  306: LOCAL void abort_allrequest( OpnCB *opncb )
  307: {
  308:         ABTFN  abortfn;
  309:         WAIFN  waitfn;
  310:         void   *exinf;
  311:         DevCB  *devcb;
  312:         ReqCB  *reqcb;
  313:         QUEUE  *q;
  314: 
  315:         /* If 'execfn' and 'waitfn' are called, execute abort request. */
  316:         LockDM();
  317: 
  318:         devcb = opncb->devcb;
  319:         abortfn = (ABTFN)devcb->ddev.abortfn;
  320:         waitfn  = (WAIFN)devcb->ddev.waitfn;
  321:         exinf   = devcb->ddev.exinf;
  322: 
  323:         opncb->abort_tskid = tk_get_tid();
  324:         opncb->abort_cnt = 0;
  325: 
  326:         if ( opncb->nwaireq > 0 ) {
  327:                 /* Multiple requests wait */
  328:                 reqcb = DEVREQ_REQCB(opncb->waireqlst);
  329: 
  330:                 /* Device driver call */
  331:                 DISABLE_INTERRUPT;
  332:                 knl_ctxtsk->sysmode++;
  333:                 ENABLE_INTERRUPT;
  334:                 (*abortfn)(reqcb->tskid, opncb->waireqlst, opncb->nwaireq, exinf);
  335:                 DISABLE_INTERRUPT;
  336:                 knl_ctxtsk->sysmode--;
  337:                 ENABLE_INTERRUPT;
  338: 
  339:                 opncb->abort_cnt++;
  340:         } else {
  341:                 /* Start request or single request wait */
  342:                 for ( q = opncb->requestq.next; q != &opncb->requestq; q = q->next ) {
  343:                         reqcb = (ReqCB*)q;
  344:                         if ( reqcb->tskid == 0 ) {
  345:                                 continue;
  346:                         }
  347: 
  348:                         reqcb->req.abort = TRUE;
  349: 
  350:                         /* Device driver call */
  351:                         DISABLE_INTERRUPT;
  352:                         knl_ctxtsk->sysmode++;
  353:                         ENABLE_INTERRUPT;
  354:                         (*abortfn)(reqcb->tskid, &reqcb->req, 1, exinf);
  355:                         DISABLE_INTERRUPT;
  356:                         knl_ctxtsk->sysmode--;
  357:                         ENABLE_INTERRUPT;
  358: 
  359:                         opncb->abort_cnt++;
  360:                 }
  361:         }
  362: 
  363:         UnlockDM();
  364: 
  365:         if ( opncb->abort_cnt > 0 ) {
  366:                 /* Wait for completion of abort request processing */
  367:                 tk_wai_sem(opncb->abort_semid, 1, TMO_FEVR);
  368:         }
  369:         opncb->abort_tskid = 0;
  370: 
  371:         /* Abort remaining requests and wait for completion */
  372:         LockDM();
  373:         while ( !isQueEmpty(&opncb->requestq) ) {
  374:                 reqcb = (ReqCB*)opncb->requestq.next;
  375:                 reqcb->req.abort = TRUE;
  376: 
  377:                 UnlockDM();
  378: 
  379:                 /* Device driver call */
  380:                 DISABLE_INTERRUPT;
  381:                 knl_ctxtsk->sysmode++;
  382:                 ENABLE_INTERRUPT;
  383:                 (*waitfn)(&reqcb->req, 1, TMO_FEVR, exinf);
  384:                 DISABLE_INTERRUPT;
  385:                 knl_ctxtsk->sysmode--;
  386:                 ENABLE_INTERRUPT;
  387: 
  388:                 LockDM();
  389: 
  390:                 /* Unregister completed request */
  391:                 knl_delReqCB(reqcb);
  392:         }
  393:         UnlockDM();
  394: }
  395: 
  396: /*
  397:  * Device close processing
  398:  */
  399: EXPORT ER knl_close_device( OpnCB *opncb, UINT option )
  400: {
  401:         CLSFN  closefn;
  402:         void   *exinf;
  403:         ID     devid;
  404:         DevCB  *devcb;
  405:         INT    unitno;
  406:         ER     ercd = E_OK;
  407: 
  408:         /* Abort all requests during processing */
  409:         abort_allrequest(opncb);
  410: 
  411:         LockDM();
  412: 
  413:         devcb  = opncb->devcb;
  414:         unitno = opncb->unitno;
  415:         closefn = (CLSFN)devcb->ddev.closefn;
  416:         exinf = devcb->ddev.exinf;
  417:         devid = DEVID(devcb, unitno);
  418: 
  419:         /* Delete semaphore for completion check of abortion */
  420:         tk_del_sem(opncb->abort_semid);
  421: 
  422:         /* Free open management block */
  423:         knl_delOpnCB(opncb, FALSE);
  424: 
  425:         /* Is device driver call required? */
  426:         if ( knl_chkopen(devcb, unitno) ) {
  427:                 option &= ~TD_EJECT;
  428:                 if ( (devcb->ddev.drvatr & TDA_OPENREQ) == 0 ) {
  429:                         closefn = NULL;
  430:                 }
  431:         }
  432: 
  433:         UnlockDM();
  434: 
  435:         if ( closefn != NULL ) {
  436:                 /* Device driver call */
  437:                 DISABLE_INTERRUPT;
  438:                 knl_ctxtsk->sysmode++;
  439:                 ENABLE_INTERRUPT;
  440:                 ercd = (*closefn)(devid, option, exinf);
  441:                 DISABLE_INTERRUPT;
  442:                 knl_ctxtsk->sysmode--;
  443:                 ENABLE_INTERRUPT;
  444:         }
  445: 
  446:         LockDM();
  447:         /* Return open management block to FreeQue */
  448:         QueInsert(&opncb->q, &knl_FreeOpnCB);
  449:         UnlockDM();
  450: 
  451:         return ercd;
  452: }
  453: 
  454: /*
  455:  * Device close
  456:  */
  457: SYSCALL ER tk_cls_dev( ID dd, UINT option )
  458: {
  459:         OpnCB  *opncb;
  460:         ER     ercd;
  461: 
  462:         LockDM();
  463: 
  464:         ercd = knl_check_devdesc(dd, 0, &opncb);
  465:         if ( ercd < E_OK ) {
  466:                 UnlockDM();
  467:                 goto err_ret;
  468:         }
  469: 
  470:         opncb->resid = 0; /* Indicate that it is during close processing */
  471: 
  472:         UnlockDM();
  473: 
  474:         /* Device close processing */
  475:         ercd = knl_close_device(opncb, option);
  476: 
  477: err_ret:
  478:         return ercd;
  479: }
  480: 
  481: /* ------------------------------------------------------------------------ */
  482: 
  483: /*
  484:  * Get request management block
  485:  */
  486: LOCAL ReqCB* newReqCB( OpnCB *opncb )
  487: {
  488:         ReqCB  *reqcb;
  489: 
  490:         /* Get space in request management block */
  491:         reqcb = (ReqCB*)QueRemoveNext(&knl_FreeReqCB);
  492:         if ( reqcb == NULL ) {
  493:                 return NULL; /* No space */
  494:         }
  495: 
  496:         /* Register as requested open device */
  497:         QueInsert(&reqcb->q, &opncb->requestq);
  498: 
  499:         reqcb->opncb = opncb;
  500: 
  501:         return reqcb;
  502: }
  503: 
  504: /*
  505:  * Request for starting input/output to device
  506:  */
  507: EXPORT ID knl_request( ID dd, W start, void *buf, W size, TMO tmout, INT cmd )
  508: {
  509:         EXCFN  execfn;
  510:         void   *exinf;
  511:         OpnCB  *opncb;
  512:         DevCB  *devcb;
  513:         ReqCB  *reqcb;
  514:         UINT   m;
  515:         ER     ercd;
  516: 
  517:         LockDM();
  518: 
  519:         if ( start <= -0x00010000 && start >= -0x7fffffff ) {
  520:                 m = 0; /* Ignore open mode */
  521:         } else {
  522:                 m = ( cmd == TDC_READ )? TD_READ: TD_WRITE;
  523:         }
  524:         ercd = knl_check_devdesc(dd, m, &opncb);
  525:         if ( ercd < E_OK ) {
  526:                 goto err_ret1;
  527:         }
  528: 
  529:         devcb = opncb->devcb;
  530:         execfn = (EXCFN)devcb->ddev.execfn;
  531:         exinf = devcb->ddev.exinf;
  532: 
  533:         /* Get request management block */
  534:         reqcb = newReqCB(opncb);
  535:         if ( reqcb == NULL ) {
  536:                 ercd = E_LIMIT;
  537:                 goto err_ret1;
  538:         }
  539: 
  540:         /* Set request packet */
  541:         reqcb->req.next   = NULL;
  542:         reqcb->req.exinf  = NULL;
  543:         reqcb->req.devid  = DEVID(devcb, opncb->unitno);
  544:         reqcb->req.cmd    = cmd;
  545:         reqcb->req.abort  = FALSE;
  546:         reqcb->req.start  = start;
  547:         reqcb->req.size   = size;
  548:         reqcb->req.buf    = buf;
  549:         reqcb->req.asize  = 0;
  550:         reqcb->req.error  = 0;
  551: 
  552:         /* Indicate that it is during processing */
  553:         reqcb->tskid = tk_get_tid();
  554: 
  555:         UnlockDM();
  556: 
  557:         /* Device driver call */
  558:         DISABLE_INTERRUPT;
  559:         knl_ctxtsk->sysmode++;
  560:         ENABLE_INTERRUPT;
  561:         ercd = (*execfn)(&reqcb->req, tmout, exinf);
  562:         DISABLE_INTERRUPT;
  563:         knl_ctxtsk->sysmode--;
  564:         ENABLE_INTERRUPT;
  565: 
  566:         LockDM();
  567: 
  568:         /* Indicate that it is not during processing */
  569:         reqcb->tskid = 0;
  570: 
  571:         /* If there is an abort completion wait task,
  572:            notify abort completion */
  573:         if ( opncb->abort_tskid > 0 && --opncb->abort_cnt == 0 ) {
  574:                 tk_sig_sem(opncb->abort_semid, 1);
  575:         }
  576: 
  577:         if ( ercd < E_OK ) {
  578:                 goto err_ret2;
  579:         }
  580: 
  581:         UnlockDM();
  582: 
  583:         return REQID(reqcb);
  584: 
  585: err_ret2:
  586:         knl_delReqCB(reqcb);
  587: err_ret1:
  588:         UnlockDM();
  589:         return ercd;
  590: }
  591: 
  592: /*
  593:  * Start reading from device
  594:  */
  595: SYSCALL ID tk_rea_dev( ID dd, W start, void *buf, SZ size, TMO tmout )
  596: {
  597:         ER     ercd;
  598: 
  599:         ercd = knl_request(dd, start, buf, size, tmout, TDC_READ);
  600: 
  601:         return ercd;
  602: }
  603: 
  604: /*
  605:  * Synchronous reading from device
  606:  */
  607: SYSCALL ER tk_srea_dev( ID dd, W start, void *buf, SZ size, SZ *asize )
  608: {
  609:         ER     ercd, ioercd;
  610: 
  611:         ercd = tk_rea_dev(dd, start, buf, size, TMO_FEVR);
  612:         if ( ercd < E_OK ) {
  613:                 goto err_ret;
  614:         }
  615: 
  616:         ercd = tk_wai_dev(dd, ercd, asize, &ioercd, TMO_FEVR);
  617:         if ( ercd < E_OK ) {
  618:                 goto err_ret;
  619:         }
  620: 
  621:         return ioercd;
  622: 
  623: err_ret:
  624:         return ercd;
  625: }
  626: 
  627: /*
  628:  * Start writing to device
  629:  */
  630: SYSCALL ID tk_wri_dev( ID dd, W start, CONST void *buf, SZ size, TMO tmout )
  631: {
  632:         ER     ercd;
  633: 
  634:         ercd = knl_request(dd, start, (void *)buf, size, tmout, TDC_WRITE);
  635: 
  636:         return ercd;
  637: }
  638: 
  639: /*
  640:  * Synchronous writing to device
  641:  */
  642: SYSCALL ER tk_swri_dev( ID dd, W start, CONST void *buf, SZ size, SZ *asize )
  643: {
  644:         ER     ercd, ioercd;
  645: 
  646:         ercd = tk_wri_dev(dd, start, buf, size, TMO_FEVR);
  647:         if ( ercd < E_OK ) {
  648:                 goto err_ret;
  649:         }
  650: 
  651:         ercd = tk_wai_dev(dd, ercd, asize, &ioercd, TMO_FEVR);
  652:         if ( ercd < E_OK ) {
  653:                 goto err_ret;
  654:         }
  655: 
  656:         return ioercd;
  657: 
  658: err_ret:
  659:         return ercd;
  660: }
  661: 
  662: /*
  663:  * Verify validity of request ID
  664:  */
  665: LOCAL ReqCB* knl_check_reqid( ID reqid, OpnCB *opncb )
  666: {
  667:         ReqCB  *reqcb;
  668: 
  669:         if ( reqid < 1 || reqid > MAX_REQDEV ) {
  670:                 return NULL;
  671:         }
  672:         reqcb = REQCB(reqid);
  673:         if ( reqcb->opncb != opncb ) {
  674:                 return NULL;
  675:         }
  676: 
  677:         return reqcb;
  678: }
  679: 
  680: /*
  681:  * Request completion wait
  682:  */
  683: SYSCALL ID tk_wai_dev( ID dd, ID reqid, SZ *asize, ER *ioer, TMO tmout )
  684: {
  685:         WAIFN  waitfn;
  686:         void   *exinf;
  687:         OpnCB  *opncb;
  688:         DevCB  *devcb;
  689:         ReqCB  *reqcb;
  690:         T_DEVREQ *devreq;
  691:         INT    reqno, nreq;
  692:         ID     tskid;
  693:         ER     ercd;
  694: 
  695:         tskid = tk_get_tid();
  696: 
  697:         LockDM();
  698: 
  699:         ercd = knl_check_devdesc(dd, 0, &opncb);
  700:         if ( ercd < E_OK ) {
  701:                 goto err_ret2;
  702:         }
  703: 
  704:         devcb = opncb->devcb;
  705:         waitfn = (WAIFN)devcb->ddev.waitfn;
  706:         exinf = devcb->ddev.exinf;
  707: 
  708:         if ( reqid == 0 ) {
  709:                 /* When waiting for completion of any of requests for 'dd' */
  710:                 if ( opncb->nwaireq > 0 || opncb->waitone > 0 ) {
  711:                         ercd = E_OBJ;
  712:                         goto err_ret2;
  713:                 }
  714:                 if ( isQueEmpty(&opncb->requestq) ) {
  715:                         ercd = E_NOEXS;
  716:                         goto err_ret2;
  717:                 }
  718: 
  719:                 /* Create wait request list */
  720:                 reqcb = (ReqCB*)opncb->requestq.next;
  721:                 for ( nreq = 1;; nreq++ ) {
  722:                         reqcb->tskid = tskid;
  723:                         devreq = &reqcb->req;
  724:                         reqcb = (ReqCB*)reqcb->q.next;
  725:                         if ( reqcb == (ReqCB*)&opncb->requestq ) {
  726:                                 break;
  727:                         }
  728:                         devreq->next = &reqcb->req;
  729:                 }
  730:                 devreq->next = NULL;
  731:                 devreq = &((ReqCB*)opncb->requestq.next)->req;
  732: 
  733:                 opncb->waireqlst = devreq;
  734:                 opncb->nwaireq = nreq;
  735:         } else {
  736:                 /* Wait for completion of abort request processing */
  737:                 reqcb = knl_check_reqid(reqid, opncb);
  738:                 if ( reqcb == NULL ) {
  739:                         ercd = E_ID;
  740:                         goto err_ret2;
  741:                 }
  742:                 if ( opncb->nwaireq > 0 || reqcb->tskid > 0 ) {
  743:                         ercd = E_OBJ;
  744:                         goto err_ret2;
  745:                 }
  746: 
  747:                 /* Create waiting request list */
  748:                 reqcb->tskid = tskid;
  749:                 devreq = &reqcb->req;
  750:                 devreq->next = NULL;
  751:                 nreq = 1;
  752: 
  753:                 opncb->waitone++;
  754:         }
  755: 
  756:         UnlockDM();
  757: 
  758:         /* Device driver call */
  759:         DISABLE_INTERRUPT;
  760:         knl_ctxtsk->sysmode++;
  761:         ENABLE_INTERRUPT;
  762:         reqno = (*waitfn)(devreq, nreq, tmout, exinf);
  763:         DISABLE_INTERRUPT;
  764:         knl_ctxtsk->sysmode--;
  765:         ENABLE_INTERRUPT;
  766: 
  767:         if ( reqno <  E_OK ) {
  768:                 ercd = reqno;
  769:         }
  770:         if ( reqno >= nreq ) {
  771:                 ercd = E_SYS;
  772:         }
  773: 
  774:         LockDM();
  775: 
  776:         /* Free wait processing */
  777:         if ( reqid == 0 ) {
  778:                 opncb->nwaireq = 0;
  779:         } else {
  780:                 opncb->waitone--;
  781:         }
  782: 
  783:         /* If there is an abort completion wait task,
  784:            notify abort completion */
  785:         if ( opncb->abort_tskid > 0 && --opncb->abort_cnt == 0 ) {
  786:                 tk_sig_sem(opncb->abort_semid, 1);
  787:         }
  788: 
  789:         /* Get processing result */
  790:         while ( devreq != NULL ) {
  791:                 reqcb = DEVREQ_REQCB(devreq);
  792:                 if ( reqno-- == 0 ) {
  793:                         reqid = REQID(reqcb);
  794:                         *asize = devreq->asize;
  795:                         *ioer  = devreq->error;
  796:                 }
  797:                 reqcb->tskid = 0;
  798:                 devreq = devreq->next;
  799:         }
  800: 
  801:         if ( ercd < E_OK ) {
  802:                 goto err_ret2;
  803:         }
  804: 
  805:         /* Unregister completed request */
  806:         knl_delReqCB(REQCB(reqid));
  807: 
  808:         UnlockDM();
  809: 
  810:         return reqid;
  811: 
  812: err_ret2:
  813:         UnlockDM();
  814:         return ercd;
  815: }
  816: 
  817: /* ------------------------------------------------------------------------ */
  818: 
  819: /* Suspend disable request count */
  820: EXPORT INT      knl_DisSusCnt = 0;
  821: 
  822: /*
  823:  * Send driver request event to each device
  824:  */
  825: LOCAL ER sendevt_alldevice( INT evttyp, BOOL disk )
  826: {
  827:         EVTFN  eventfn;
  828:         QUEUE  *q;
  829:         DevCB  *devcb;
  830:         BOOL   d;
  831:         ER     ercd = E_OK;
  832: 
  833:         for ( q = knl_UsedDevCB.next; q != &knl_UsedDevCB; q = q->next ) {
  834:                 devcb = (DevCB*)q;
  835: 
  836:                 d = ( (devcb->ddev.devatr & TD_DEVTYPE) == TDK_DISK )?
  837:                                                         TRUE: FALSE;
  838:                 if ( disk != d ) {
  839:                         continue;
  840:                 }
  841: 
  842:                 /* Device driver call */
  843:                 eventfn = (EVTFN)devcb->ddev.eventfn;
  844:                 DISABLE_INTERRUPT;
  845:                 knl_ctxtsk->sysmode++;
  846:                 ENABLE_INTERRUPT;
  847:                 ercd = (*eventfn)(evttyp, NULL, devcb->ddev.exinf);
  848:                 DISABLE_INTERRUPT;
  849:                 knl_ctxtsk->sysmode--;
  850:                 ENABLE_INTERRUPT;
  851:         }
  852: 
  853:         return ercd;
  854: }
  855: 
  856: /*
  857:  * Suspend
  858:  */
  859: LOCAL ER do_suspend( void )
  860: {
  861:         ER     ercd;
  862: 
  863:         /* Stop accepting device registration/unregistration */
  864:         LockREG();
  865: 
  866:         /* Suspend processing of device except for disks */
  867:         ercd = sendevt_alldevice(TDV_SUSPEND, FALSE);
  868: 
  869:         /* Suspend processing of disk device */
  870:         ercd = sendevt_alldevice(TDV_SUSPEND, TRUE);
  871: 
  872:         /* Stop accepting new requests */
  873:         LockDM();
  874: 
  875:         /*
  876:          * Insert code to transit to suspend state here
  877:          */
  878: 
  879:         /*
  880:          * Insert code executed on returning from suspend state
  881:          */
  882: 
  883: 
  884:         /* Resume accepting requests */
  885:         UnlockDM();
  886: 
  887:         /* Resume processing of disk device */
  888:         ercd = sendevt_alldevice(TDV_RESUME, TRUE);
  889: 
  890:         /* Resume processing of device except for disks */
  891:         ercd = sendevt_alldevice(TDV_RESUME, FALSE);
  892: 
  893:         /* Resume accepting device registration/unregistration */
  894:         UnlockREG();
  895: 
  896:         return ercd;
  897: }
  898: 
  899: /*
  900:  * Suspend processing
  901:  */
  902: SYSCALL INT tk_sus_dev( UINT mode )
  903: {
  904:         ResCB  *rescb;
  905:         BOOL   suspend = FALSE;
  906:         ER     ercd;
  907: 
  908:         /* Get resource management information */
  909:         rescb = knl_GetResCB();
  910:         if ( rescb == NULL ) {
  911:                 ercd = E_CTX;
  912:                 goto err_ret1;
  913:         }
  914: 
  915:         LockDM();
  916: 
  917:         switch ( mode & 0xf ) {
  918:           case TD_SUSPEND:     /* Suspend */
  919:                 if ( knl_DisSusCnt > 0 && (mode & TD_FORCE) == 0 ) {
  920:                         ercd = E_BUSY;
  921:                         goto err_ret2;
  922:                 }
  923:                 suspend = TRUE;
  924:                 break;
  925: 
  926:           case TD_DISSUS:      /* Disable suspend */
  927:                 if ( knl_DisSusCnt >= MAX_DISSUS ) {
  928:                         ercd = E_QOVR;
  929:                         goto err_ret2;
  930:                 }
  931:                 knl_DisSusCnt++;
  932:                 rescb->dissus++;
  933:                 break;
  934:           case TD_ENASUS:      /* Enable suspend */
  935:                 if ( rescb->dissus > 0 ) {
  936:                         rescb->dissus--;
  937:                         knl_DisSusCnt--;
  938:                 }
  939:                 break;
  940: 
  941:           case TD_CHECK:       /* Get suspend disable request count */
  942:                 break;
  943: 
  944:           default:
  945:                 ercd = E_PAR;
  946:                 goto err_ret2;
  947:         }
  948: 
  949:         UnlockDM();
  950: 
  951:         if ( suspend ) {
  952:                 /* Suspend */
  953:                 ercd = do_suspend();
  954:                 if ( ercd < E_OK ) {
  955:                         goto err_ret1;
  956:                 }
  957:         }
  958: 
  959:         return knl_DisSusCnt;
  960: 
  961: err_ret2:
  962:         UnlockDM();
  963: err_ret1:
  964:         return ercd;
  965: }
  966: 
  967: /* ------------------------------------------------------------------------ */
  968: 
  969: /*
  970:  * Device management startup function
  971:  */
  972: EXPORT void knl_devmgr_startup( void )
  973: {
  974:         LockDM();
  975: 
  976:         /* Initialization of open device management queue */
  977:         QueInit(&(knl_resource_control_block.openq));
  978:         knl_resource_control_block.dissus = 0;
  979:         
  980:         UnlockDM();
  981: 
  982:         return;
  983: }
  984: 
  985: /*
  986:  * Device management cleanup function
  987:  */
  988: EXPORT void knl_devmgr_cleanup( void )
  989: {
  990:         OpnCB  *opncb;
  991: 
  992:         /* Do nothing if it is not used even once */
  993:         if ( knl_resource_control_block.openq.next == NULL ) {
  994:                 return;
  995:         }
  996: 
  997:         LockDM();
  998: 
  999:         /* Free suspend disable request */
 1000:         knl_DisSusCnt -= knl_resource_control_block.dissus;
 1001:         knl_resource_control_block.dissus = 0;
 1002: 
 1003:         /* Close all open devices */
 1004:         while ( !isQueEmpty(&(knl_resource_control_block.openq)) ) {
 1005:                 opncb = RESQ_OPNCB(knl_resource_control_block.openq.next);
 1006: 
 1007:                 /* Indicate that it is during close processing */
 1008:                 opncb->resid = 0;
 1009: 
 1010:                 UnlockDM();
 1011: 
 1012:                 /* Device close processing */
 1013:                 knl_close_device(opncb, 0);
 1014: 
 1015:                 LockDM();
 1016:         }
 1017:         UnlockDM();
 1018: 
 1019:         return;
 1020: }
 1021: 
 1022: /*
 1023:  * Initialization sequence of device input/output-related
 1024:  */
 1025: EXPORT ER knl_initDevIO( void )
 1026: {
 1027:         INT    i;
 1028: 
 1029:         QueInit(&knl_FreeOpnCB);
 1030:         for ( i = 0; i < MAX_OPNDEV; ++i ) {
 1031:                 knl_OpnCBtbl[i].resid = 0;
 1032:                 QueInsert(&knl_OpnCBtbl[i].q, &knl_FreeOpnCB);
 1033:         }
 1034: 
 1035:         QueInit(&knl_FreeReqCB);
 1036:         for ( i = 0; i < MAX_REQDEV; ++i ) {
 1037:                 knl_ReqCBtbl[i].opncb = NULL;
 1038:                 QueInsert(&knl_ReqCBtbl[i].q, &knl_FreeReqCB);
 1039:         }
 1040: 
 1041:         return E_OK;
 1042: }
 1043: 
 1044: /*
 1045:  * Finalization sequence of device input/output-related
 1046:  */
 1047: EXPORT ER knl_finishDevIO( void )
 1048: {
 1049:         return E_OK;
 1050: }
 1051: 
 1052: #endif /* USE_DEVICE */