gonzui


Format: Advanced Search

tkernel_2/lib/libdrvif/src/gdrvif.cbare sourcepermlink (0.05 seconds)

Search this content:

    1: /*
    2:  *----------------------------------------------------------------------
    3:  *    T-Kernel 2.0 Software Package
    4:  *
    5:  *    Copyright 2011 by Ken Sakamura.
    6:  *    This software is distributed under the latest version of T-License 2.x.
    7:  *----------------------------------------------------------------------
    8:  *
    9:  *    Released by T-Engine Forum(http://www.t-engine.org/) at 2011/05/17.
   10:  *    Modified by T-Engine Forum at 2014/09/10.
   11:  *    Modified by TRON Forum(http://www.tron.org/) at 2015/06/01.
   12:  *
   13:  *----------------------------------------------------------------------
   14:  */
   15: 
   16: 
   17: /*
   18:  *      gdrvif.c
   19:  *
   20:  *      General-purpose device driver I/F layer
   21:  */
   22: 
   23: #include <basic.h>
   24: #include <device/gdrvif.h>
   25: #include <tk/tkernel.h>
   26: #include <tk/util.h>
   27: #include <sys/queue.h>
   28: #include <libstr.h>
   29: #include <sys/debug.h>
   30: 
   31: typedef enum {
   32:         NotDone        = 0,   /* Unused or during processing */
   33:         Abort  = 1,     /* During abort */
   34:         Done   = 2       /* Completion*/
   35: } DONE;
   36: 
   37: /*
   38:  * Management queue for device request
   39:  */
   40: typedef struct DeviceRequestQueue {
   41:         QUEUE          q;      /* For connection with queue */
   42:         T_DEVREQ       *req; /* Device request packet */
   43:         INT            memsz;    /* Area size of I/O buffer */
   44:         ID             wtid;      /* Wait-for-completion task ID */
   45:         DONE           done;    /* Completion status */
   46: } DRQ;
   47: 
   48: /*
   49:  * Driver I/F access handle (GDI)
   50:  */
   51: struct GeneralDriverInterface {
   52:         FastMLock      lock;        /* Lock for exclusive access control */
   53:         GDefDev                def;  /* Device registration information */
   54:         ID             devid;     /* Device ID */
   55: 
   56:         DRQ            *drq;     /* Buffer for DRQ */
   57:         QUEUE          freeq;  /* Free queue*/
   58:         QUEUE          acpq;   /* Wait-for-accepting queue*/
   59:         ID             flgid;     /* Event flag for queue insert notification */
   60: 
   61:         INT            limit;    /* Maximum number of queuings per request type */
   62:         INT            preq[2];/* The number of TDC_READ/WRITE requests during the accept-wait and the processing */
   63: 
   64:         INT            acpd[2];/* The number of requests of the accept-wait TDC_READ/WRITE (specific data) */
   65:         INT            acpa[2];/* The number of requests of the accept-wait TDC_READ/WRITE (attribute data) */
   66: };
   67: 
   68: /* Count the number of the accept-wait requests */
   69: #define cntacpq(req, gdi, ope)                                  \
   70:         if ( (req)->cmd == TDC_READ ) {                                \
   71:                 if ( (req)->start < 0 ) (gdi)->acpa[0] ope;   \
   72:                 else                  (gdi)->acpd[0] ope;    \
   73:         } else {                                               \
   74:                 if ( (req)->start < 0 ) (gdi)->acpa[1] ope;   \
   75:                 else                  (gdi)->acpd[1] ope;    \
   76:         }
   77: 
   78: /* True if "q" is a valid DRQ */
   79: #define validDRQ(q, gdi) \
   80:         ( (q) >= (gdi)->drq && (q) < (gdi)->drq + (gdi)->def.maxreqq )
   81: 
   82: /*
   83:  * Event flag pattern for queue insert notification
   84:  *      Use "DEVREQ_ACPPTN(cmd)" for insertion into "acpq"
   85:  */
   86: #define FREEQ_RD        0x40000000     /* Acceptance of "TDC_READ" request is enabled */
   87: #define FREEQ_WR        0x80000000     /* Acceptance of "TDC_WRITE" request is enabled */
   88: 
   89: /*
   90:  * Lock for exclusive access control over an access to management information
   91:  */
   92: #define LockGDI(gdi)    MLock(&(gdi)->lock, 0)
   93: #define UnlockGDI(gdi)  MUnlock(&(gdi)->lock, 0)
   94: 
   95: /*
   96:  * Lock for exclusive access control over a processing function call
   97:  */
   98: #define LockCALL(gdi)   MLock(&(gdi)->lock, 1)
   99: #define UnlockCALL(gdi) MUnlock(&(gdi)->lock, 1)
  100: 
  101: /*
  102:  * Lock for DRQ get (gdi_getDRQ)
  103:  */
  104: #define LockDRQ(gdi, rw, tmo)   MLockTmo(&(gdi)->lock, 2 + (rw), (tmo))
  105: #define UnlockDRQ(gdi, rw)      MUnlock(&(gdi)->lock, 2 + (rw))
  106: 
  107: /*
  108:  * Task event for completion notification
  109:  */
  110: LOCAL INT       GDI_TEV;
  111: 
  112: #define TEVPTN(tev)     ( 1 << ((tev) - 1) )
  113: #define TTWTEV(tev)     ( TTW_EV1 << ((tev) - 1) )
  114: 
  115: /* ------------------------------------------------------------------------ */
  116: /*
  117:  *      Get information from GDI
  118:  *      These functions shall be call-ready even at the independent part,
  119:  *      during disabling the dispatch, and during disabling the interrupts.
  120:  */
  121: 
  122: /*
  123:  * Get physical device ID
  124:  */
  125: EXPORT ID GDI_devid( GDI gdi )
  126: {
  127:         return gdi->devid;
  128: }
  129: 
  130: /*
  131:  * Get the extended information (GDefDev.exinf)
  132:  */
  133: EXPORT void* GDI_exinf( GDI gdi )
  134: {
  135:         return gdi->def.exinf;
  136: }
  137: 
  138: /*
  139:  * Get the registration information
  140:  */
  141: EXPORT const GDefDev* GDI_ddev( GDI gdi )
  142: {
  143:         return &gdi->def;
  144: }
  145: 
  146: /* ------------------------------------------------------------------------ */
  147: /*
  148:  *      Management queue of device request
  149:  */
  150: 
  151: /*
  152:  * Fetch from the free queue
  153:  *      When DRQ is obtained, execute a return in the state of executing "LockGDI()".
  154:  */
  155: LOCAL ER gdi_getDRQ( DRQ **p_drq, T_DEVREQ *req, TMO tmout, GDI gdi )
  156: {
  157:         DRQ    *drq;
  158:         SYSTIM stime, ctime;
  159:         TMO    tmo = tmout;
  160:         INT    rw;
  161:         UINT   ptn, waiptn;
  162:         ER     err;
  163: 
  164:         rw = ( req->cmd == TDC_READ )? 0 : 1;
  165:         waiptn = ( rw == 0 )? FREEQ_RD: FREEQ_WR;
  166: 
  167:         if ( tmout != TMO_FEVR ) {
  168:                 err = tk_get_otm(&stime);
  169:                 if ( err < E_OK ) goto err_ret1;
  170:         }
  171: 
  172:         /* Lock for DRQ : This required in order to ensure that only one task
  173:                 waits the event flag for the same pattern */
  174:         err = LockDRQ(gdi, rw, tmo);
  175:         if ( err < E_OK ) goto err_ret1;
  176: 
  177:         for ( ;; ) {
  178:                 /* Fetch one from the free queue */
  179:                 LockGDI(gdi);
  180:                 if ( gdi->preq[rw] < gdi->limit ) {
  181:                         drq = (DRQ*)QueRemoveNext(&gdi->freeq);
  182:                         if ( drq != NULL ) break; /* Obtained */
  183:                 }
  184:                 UnlockGDI(gdi);
  185: 
  186:                 /* Remaining waiting time */
  187:                 if ( tmout != TMO_FEVR ) {
  188:                         err = tk_get_otm(&ctime);
  189:                         if ( err < E_OK ) goto err_ret2;
  190: 
  191:                         tmo = tmout - (ctime.lo - stime.lo);
  192:                         if ( tmo <= 0 ) { err = E_TMOUT; goto err_ret2; }
  193:                 }
  194:                 /* Wait for DRQ to be returned to the free queue */
  195:                 err = tk_wai_flg(gdi->flgid, waiptn, TWF_ORW | TWF_BITCLR,
  196:                                                         &ptn, tmo);
  197:                 if ( err < E_OK ) {
  198:                         if ( err == E_DISWAI ) err = E_ABORT;
  199:                         goto err_ret2;
  200:                 }
  201:         }
  202: 
  203:         /* UnLock for DRQ */
  204:         UnlockDRQ(gdi, rw);
  205: 
  206:         gdi->preq[rw]++;
  207: 
  208:         /* Set the device request to DRQ */
  209:         drq->req = req;
  210:         if ( req->exinf != NULL ) {
  211:                 /* There is the task that waits for completion (gdi_waitfn) */
  212:                 drq->wtid = *(ID*)req->exinf;
  213:         }
  214:         req->exinf = drq;
  215: 
  216:         *p_drq = drq;
  217:         return E_OK;  /* Return while executing "LockGDI()" */
  218: 
  219: err_ret2:
  220:         UnlockDRQ(gdi, rw);
  221: err_ret1:
  222:         DEBUG_PRINT(("gdi_getDRQ err = %d\n", err));
  223:         return err;
  224: }
  225: 
  226: /*
  227:  * Return to the free queue
  228:  *      Call by executing "LockGDI()"
  229:  */
  230: LOCAL void gdi_relDRQ( DRQ *drq, GDI gdi )
  231: {
  232:         UINT   ptn = isQueEmpty(&gdi->freeq)? (FREEQ_RD|FREEQ_WR): 0;
  233: 
  234:         if ( drq->req->cmd == TDC_READ ) {
  235:                 if ( gdi->preq[0]-- == gdi->limit ) ptn |= FREEQ_RD;
  236:         } else {
  237:                 if ( gdi->preq[1]-- == gdi->limit ) ptn |= FREEQ_WR;
  238:         }
  239: 
  240:         if ( ptn != 0 ) {
  241:                 tk_set_flg(gdi->flgid, ptn);
  242:         }
  243: 
  244:         QueInsert((QUEUE*)drq, &gdi->freeq);
  245: 
  246:         drq->req  = NULL;
  247:         drq->wtid = 0;
  248:         drq->done = NotDone;
  249: }
  250: 
  251: /*
  252:  * An insertion into the queue that waits for accepting a request
  253:  *      Call by executing "LockGDI()"
  254:  */
  255: LOCAL ER gdi_sndreq( DRQ *drq, GDI gdi )
  256: {
  257:         T_DEVREQ       *req = drq->req;
  258:         UINT           setptn;
  259:         ER             err;
  260: 
  261:         if ( req->abort ) { err = E_ABORT; goto err_ret1; }
  262: 
  263:         /* Insert into the queue that waits for accepting */
  264:         setptn = 0;
  265:         if ( req->cmd == TDC_READ ) {
  266:                 if ( req->start < 0 ) {
  267:                         if ( gdi->acpa[0]++ == 0 ) setptn |= DRP_AREAD;
  268:                 } else {
  269:                         if ( gdi->acpd[0]++ == 0 ) setptn |= DRP_DREAD;
  270:                 }
  271:         } else {
  272:                 if ( req->start < 0 ) {
  273:                         if ( gdi->acpa[1]++ == 0 ) setptn |= DRP_AWRITE;
  274:                 } else {
  275:                         if ( gdi->acpd[1]++ == 0 ) setptn |= DRP_DWRITE;
  276:                 }
  277:         }
  278:         QueInsert((QUEUE*)drq, &gdi->acpq);
  279: 
  280:         if ( setptn != 0 ) {
  281:                 /* Notify the insertion into the queue that waits for accepting  */
  282:                 err = tk_set_flg(gdi->flgid, setptn);
  283:                 if ( err < E_OK ) goto err_ret2;
  284:         }
  285: 
  286:         return E_OK;
  287: 
  288: err_ret2:
  289:         cntacpq(req, gdi, --);
  290:         QueRemove((QUEUE*)drq);
  291: err_ret1:
  292:         DEBUG_PRINT(("gdi_sndreq err = %d\n", err));
  293:         return err;
  294: }
  295: 
  296: /*
  297:  * Accept requests
  298:  *      Fetch one request from the request accept queue.
  299:  *      When there is no request in queue, the device driver shall enter into a wait status until request is made.
  300:  *      Specify "acpptn" by ORing the pattern of accepted request type (TDC_READ/TDC_WRITE)
  301:  *      or the value obtained in "DEVREQ_ACPPTN()" in the pattern of user command.
  302:  *      In addition, the request regarding specific data and attribute data can be individually accepted.
  303:  *      (Refer to the following descriptions of the accept-wait-extended function).
  304:  *      As for the acceptance of request, normal request (including the case of individual specification of "TDC_READ", "TDC_WRITE", "specific data", and "attribute data")
  305:  *      is prioritized over the user command.
  306:  *      However, normal request and user command may be simultaneously received.
  307:  *      Specify a time-out time in milli second for "tmout".
  308:  *      "TMO_POL" and "TMO_FEVR" also can be specified.
  309:  *      Return the received request pattern or error to the return value.
  310:  *      Return the pattern of the accepted request in the format specified for "acpptn".
  311:  *      Briefly, when the accept-wait-extended function is used,
  312:  *      the request for the specific data and the request for attribute are individually indicated.
  313:  *      In this case,"DRP_ADSEL" is also set.
  314:  *
  315:  *      In the case of Normal request
  316:  *        Return the pattern, which indicates the type of the accepted request, to the return value.
  317:  *        Return the accepted request to "*devreq"
  318:  *      In the case of User command
  319:  *        Return the pattern, which indicates the accepted user command, to the return value.
  320:  *        When several kinds of user command are accumulated,
  321:  *        the pattern, in which all the user commands specified at "acpptn" are collectively accepted and ORed, shall be returned
  322:  *      
  323:  *        Return NULL to "*devreq"
  324:  *      In the case where normal request and user command are simultaneously accepted.
  325:  *        Return the pattern, which ORed both the accepted normal request and user command
  326:  *        , to the return value.
  327:  *        Return the accepted normal request to "*devreq".
  328:  *      In the case of time-out or error
  329:  *        Return the error code to the return value. "E_TMOUT" is returned in case of time out.
  330:  *        "*devreq" is indeterminate.
  331:  *
  332:  *      "exinf" of the accepted request(T_DEVREQ) shall never be changed.
  333:  *      Checking of "buf" space (ChkSpace) is already executed in driver I/F
  334:  *      Reply to user command (GDI_Reply) is unnecessary.
  335:  *
  336:  *      Generally, the next request is newly received after one request is accepted and processed
  337:  *      and the result is returned.
  338:  *      However, several requests may be received and simultaneously processed.
  339:  *      In the case of processing several requests simultaneously, the several request processing tasks may execute each "GDI_Accept()" to be processed in parallel.
  340:  *      Or one processing task may execute several "GDI_Accept()" to be processed simultaneously.
  341:  *      
  342:  *      It does not matter that the order of accepting request and the order of returning result are not necessarily the same.
  343:  *
  344:  *Accept-wait-extended function  (Specify the accept-wait for specific data and attribute data individually)
  345:  *      DRP_DREAD    Read the specific data
  346:  *      DRP_DWRITE   Write the specific data
  347:  *      DRP_AREAD    Read the attribute data
  348:  *      DRP_AWRITE   Write the attribute data
  349:  *      These shall be specified by ORing these above.
  350:  *
  351:  *      "DRP_DREAD |DRP_AREAD" is equivalent to "DRP_READ".
  352:  *      "DRP_DWRITE|DRP_AWRITE" is equivalent to "DRP_WRITE".
  353:  *
  354:  *      These specific data and attribute data individual specification cannot be simultaneously combined
  355:  *      and used with "DRP_READ" and "DRP_WRITE" .
  356:  */
  357: EXPORT INT GDI_Accept( T_DEVREQ **devreq, INT _acpptn, TMO tmout, GDI gdi )
  358: {
  359:         DRQ            *drq;
  360:         T_DEVREQ       *req;
  361:         QUEUE          *q;
  362:         INT            reqptn, rptn;
  363:         UINT           acpptn, aptn;
  364:         SYSTIM         stime, ctime;
  365:         TMO            tmo;
  366:         ER             err;
  367: 
  368:         if ( (_acpptn & DRP_ADSEL) == 0 ) {
  369:                 /* Normal specification */
  370:                 if ( (_acpptn & ~(DRP_NORMREQ|DRP_USERCMD)) != 0 )
  371:                                         { err = E_PAR; goto err_ret; }
  372:                 acpptn = ((_acpptn & DRP_NORMREQ) << 8) | _acpptn;
  373:         } else {
  374:                 /* Extended specification*/
  375:                 if ( (_acpptn & ~(DRP_REQMASK|DRP_USERCMD)) != 0 )
  376:                                         { err = E_PAR; goto err_ret; }
  377:                 acpptn = _acpptn & ~DRP_ADSEL;
  378:         }
  379: 
  380:         aptn = 0;
  381:         tmo = TMO_FEVR;
  382:         stime.lo = 0;
  383: 
  384:         for ( ;; ) {
  385:                 /* Fetch the request from queue */
  386:                 LockGDI(gdi);
  387:                 drq = NULL;
  388:                 req = NULL; rptn = 0; /* "warning" measures */
  389:                 for ( q = gdi->acpq.next; q != &gdi->acpq; q = q->next ) {
  390:                         req = ((DRQ*)q)->req;
  391:                         rptn = DEVREQ_ACPPTN(req->cmd);
  392:                         if ( req->start < 0 ) rptn <<= 8;
  393:                         if ( (rptn & acpptn) == 0 ) continue;
  394: 
  395:                         drq = (DRQ*)q;
  396:                         cntacpq(req, gdi, --);
  397:                         QueRemove(q);
  398:                         QueInit(q);
  399:                         break;
  400:                 }
  401:                 UnlockGDI(gdi);
  402:                 reqptn = aptn & DRP_USERCMD;
  403:                 if ( drq != NULL ) {
  404:                         if ( req->abort ) {
  405:                                 /* Abort processing */
  406:                                 req->error = E_ABORT;
  407:                                 GDI_Reply(req, gdi);
  408:                                 continue;
  409:                         }
  410: 
  411:                         /* Normal request was accepted */
  412:                         *devreq = req;
  413:                         reqptn |= rptn;
  414: 
  415:                         if ( (aptn &= ~rptn & DRP_REQMASK) != 0 ) {
  416:                                 /* Reset the unnecessarily cleared flag */
  417:                                 tk_set_flg(gdi->flgid, aptn);
  418:                         }
  419:                         break;
  420:                 }
  421:                 if ( reqptn != 0 ) {
  422:                         /* Only the user command is accepted */
  423:                         *devreq = NULL;
  424:                         break;
  425:                 }
  426: 
  427:                 /* Remaining waiting time */
  428:                 if ( tmout != TMO_FEVR ) {
  429:                         err = tk_get_otm(&ctime);
  430:                         if ( err < E_OK ) goto err_ret;
  431:                         if ( tmo < 0 ) {
  432:                                 stime = ctime;
  433:                                 tmo = tmout;
  434:                         } else {
  435:                                 tmo = tmout - (ctime.lo - stime.lo);
  436:                                 if ( tmo < 0 ) tmo = 0;
  437:                         }
  438:                 }
  439: 
  440:                 /* Wait for the request to come */
  441:                 err = tk_wai_flg(gdi->flgid, acpptn, TWF_ORW | TWF_BITCLR,
  442:                                                                 &aptn, tmo);
  443:                 if ( err < E_OK ) goto err_ret;
  444:                 aptn &= acpptn;
  445:         }
  446: 
  447:         if ( (reqptn & DRP_REQMASK) != 0 ) {
  448:                 if ( (_acpptn & DRP_ADSEL) == 0 ) {
  449:                         /* Normal specification */
  450:                         reqptn |= (reqptn & (DRP_NORMREQ << 8)) >> 8;
  451:                         reqptn &= ~(DRP_NORMREQ << 8);
  452:                 } else {
  453:                         /* Extended specification */
  454:                         reqptn |= DRP_ADSEL;
  455:                 }
  456:         }
  457: 
  458:         return reqptn;
  459: 
  460: err_ret:
  461:         DEBUG_PRINT(("GDI_Accept err = %d\n", err));
  462:         return err;
  463: }
  464: 
  465: /*
  466:  * Issue the user command
  467:  *      Issue the user command specified in "cmd".
  468:  *      Only the values ranging from 16 to 23 can be specified for "cmd".
  469:  *      The issued user command is accepted by "GDI_Accept()".
  470:  *      When the user command, which is not accepted by "GDI_Accept()",
  471:  *      is accumulated, the several identical commands shall not be accumulated.
  472:  *      Even if the identical command is issued several times, only the amount
  473:  *      of one time is accumulated.
  474:  *      And the command accumulated by amount of one time of "GDI_Accept()" will disappear.
  475:  *      Meanwhile, "GDI_SendCmd()" only issues the user command,
  476:  *      and returns without waiting to be accepted by "GDI_Accept()".
  477:  *      User command is generally used to release the waiting of "GDI_Accept()"
  478:  *      at any given point in time.
  479:  */
  480: EXPORT ER GDI_SendCmd( INT cmd, GDI gdi )
  481: {
  482:         ER     err;
  483: 
  484:         if ( cmd < 16 || cmd > 23 ) { err = E_PAR; goto err_ret; }
  485: 
  486:         err = tk_set_flg(gdi->flgid, DEVREQ_ACPPTN(cmd));
  487:         if ( err < E_OK ) goto err_ret;
  488: 
  489:         return E_OK;
  490: 
  491: err_ret:
  492:         DEBUG_PRINT(("GDI_SendCmd err = %d\n", err));
  493:         return err;
  494: }
  495: 
  496: /*
  497:  * Reply to request
  498:  *      Return the processing result of the request accepted in "GDI_Accept()".
  499:  *      The task that executed "GDI_Accept()" and the task to execute "GDI_Reply()"
  500:  *      may not be the same.
  501:  */
  502: EXPORT void GDI_Reply( T_DEVREQ *req, GDI gdi )
  503: {
  504:         DRQ    *drq = req->exinf;
  505: 
  506:         LockGDI(gdi);
  507:         drq->done = Done;
  508: 
  509:         if ( drq->wtid > 0 ) {
  510:                 /* Completion shall be notified to the task that waits for completion. */
  511:                 tk_sig_tev(drq->wtid, GDI_TEV);
  512:         }
  513:         UnlockGDI(gdi);
  514: }
  515: 
  516: /* ------------------------------------------------------------------------ */
  517: /*
  518:  *      Processing function
  519:  */
  520: 
  521: /*
  522:  * Open function
  523:  */
  524: LOCAL ER gdi_openfn( ID devid, UINT omode, GDI gdi )
  525: {
  526:         ER     err;
  527: 
  528:         if ( gdi->def.open == NULL ) return E_OK;
  529: 
  530:         LockCALL(gdi);
  531:         err = (*gdi->def.open)(devid, omode, gdi);
  532:         UnlockCALL(gdi);
  533: 
  534:         return err;
  535: }
  536: 
  537: /*
  538:  * Close function
  539:  */
  540: LOCAL ER gdi_closefn( ID devid, UINT option, GDI gdi )
  541: {
  542:         ER     err;
  543: 
  544:         if ( gdi->def.close == NULL ) return E_OK;
  545: 
  546:         LockCALL(gdi);
  547:         err = (*gdi->def.close)(devid, option, gdi);
  548:         UnlockCALL(gdi);
  549: 
  550:         return err;
  551: }
  552: 
  553: /*
  554:  * Processing start function
  555:  */
  556: LOCAL ER gdi_execfn( T_DEVREQ *req, TMO tmout, GDI gdi )
  557: {
  558:         DRQ    *drq;
  559:         INT    memsz;
  560:         ER     err;
  561: 
  562:         /* I/O size */
  563:         if ( req->start < 0 ) {
  564:                 /* Attribute data */
  565:                 memsz = req->size;
  566:         } else {
  567:                 /* Specific data */
  568:                 if ( gdi->def.blksz <= 0 ) { err = E_PAR; goto err_ret1; }
  569:                 memsz = req->size * gdi->def.blksz;
  570:         }
  571:         if ( memsz < 0 ) { err = E_PAR; goto err_ret1; }
  572: 
  573:         if ( memsz > 0 ) {
  574:                 /* Check the "buf" area */
  575:                 if ( req->cmd == TDC_READ ) {
  576:                         err = ChkSpaceRW(req->buf, memsz);
  577:                 } else {
  578:                         err = ChkSpaceR(req->buf, memsz);
  579:                 }
  580:                 if ( err < E_OK ) goto err_ret1;
  581: 
  582:                 if ( (gdi->def.drvatr & TDA_LOCKREQ) != 0 && !req->nolock ) {
  583:                         /* Lock the "buf" area (residentialization) */
  584:                         err = LockSpace(req->buf, memsz);
  585:                         if ( err < E_OK ) goto err_ret1;
  586:                 }
  587:         }
  588: 
  589:         /* Get the "DRQ"*/
  590:         err = gdi_getDRQ(&drq, req, tmout, gdi);
  591:         if ( err < E_OK ) goto err_ret2;
  592:         /* "LockGDI()" is in execution */
  593: 
  594:         drq->memsz = memsz;
  595: 
  596:         /* Insert it into the queue that waits for accepting the request */
  597:         err = gdi_sndreq(drq, gdi);
  598:         if ( err < E_OK ) goto err_ret3;
  599: 
  600:         UnlockGDI(gdi);
  601: 
  602:         return E_OK;
  603: 
  604: err_ret3:
  605:         gdi_relDRQ(drq, gdi);
  606:         UnlockGDI(gdi);
  607: err_ret2:
  608:         if ( (gdi->def.drvatr & TDA_LOCKREQ) != 0 && !req->nolock ) {
  609:                 if ( memsz > 0 ) UnlockSpace(req->buf, memsz);
  610:         }
  611: err_ret1:
  612:         DEBUG_PRINT(("gdi_execfn err = %d\n", err));
  613:         return err;
  614: }
  615: 
  616: /*
  617:  * Abort in the wait-for-completion
  618:  *      Return 1 if request is completed by an abort
  619:  *      Return 0 if wait-for-completion is necessary.
  620:  */
  621: LOCAL INT gdi_waitfn_abort( DRQ *drq, GDI gdi )
  622: {
  623:         T_DEVREQ       *req = drq->req;
  624:         INT            done;
  625: 
  626:         if ( !isQueEmpty(&drq->q) ) {
  627:                 /* Wait for accepting the processing (inside queue) : delete from the queue that waits for accepting */
  628:                 cntacpq(req, gdi, --);
  629:                 QueRemove(&drq->q);
  630:                 QueInit(&drq->q);
  631:                 req->error = E_ABORT;
  632:                 drq->done = Done;
  633:                 done = 1;
  634:         } else {
  635:                 /* During processing : call the abort function */
  636:                 drq->done = Abort;
  637:                 if ( gdi->def.abort != NULL ) {
  638:                         (*gdi->def.abort)(req, gdi);
  639:                 }
  640:                 done = 0;
  641:         }
  642: 
  643:         return done;
  644: }
  645: 
  646: /*
  647:  * Wait-for-completion function
  648:  */
  649: LOCAL INT gdi_waitfn( T_DEVREQ *devreq, INT nreq, TMO tmout, GDI gdi )
  650: {
  651:         T_DEVREQ       *req;
  652:         DRQ            *drq, *complete = NULL;
  653:         ID             mytid;
  654:         INT            i, n, abort = 0;
  655:         INT            memsz;
  656:         void           *buf;
  657:         ER             err;
  658: 
  659:         mytid = tk_get_tid();
  660: 
  661:         LockGDI(gdi);
  662: 
  663:         /* Check if there is an already completed request */
  664:         req = devreq;
  665:         for ( n = 0; n < nreq; ++n ) {
  666:                 drq = req->exinf;
  667:                 if ( drq != NULL && drq->done == Done ) {
  668:                         complete = drq;  /* Completed request */
  669:                         break;
  670:                 }
  671:                 req = req->next;
  672:         }
  673:         if ( complete == NULL ) {
  674:                 /* Mark the request targeting the wait-for-completion */
  675:                 req = devreq;
  676:                 for ( i = 0; i < nreq; ++i ) {
  677:                         drq = req->exinf;
  678:                         if ( drq == NULL ) {
  679:                                 /* Before a request-accept (not queued) */
  680:                                 req->exinf = &mytid;
  681:                         } else {
  682:                                 /* Wait-for-accepting a processing, or during processing */
  683:                                 if ( req->abort && drq->done == NotDone ) {
  684:                                         /* Abort processing */
  685:                                         abort |= gdi_waitfn_abort(drq, gdi);
  686:                                 }
  687:                                 drq->wtid = mytid;
  688:                         }
  689:                         req = req->next;
  690:                 }
  691:         }
  692: 
  693:         UnlockGDI(gdi);
  694: 
  695:         if ( complete == NULL ) {
  696:                 /* Wait-for-completion */
  697:                 if ( abort == 0 ) {
  698:                         err = tk_wai_tev(TEVPTN(GDI_TEV), tmout);
  699:                 } else {
  700:                         err = E_ABORT;
  701:                 }
  702: 
  703:                 /* Search the completed request, and release the completion-wait-mark */
  704:                 req = devreq;
  705:                 LockGDI(gdi);
  706:                 for ( i = 0; i < nreq; ++i ) {
  707:                         drq = req->exinf;
  708:                         if ( validDRQ(drq, gdi) ) {
  709:                                 drq->wtid = 0;
  710:                                 if ( complete == NULL && drq->done == Done ) {
  711:                                         complete = drq;  /* Completed request*/
  712:                                         n = i;
  713:                                 }
  714:                         } else {
  715:                                 req->exinf = NULL;
  716:                         }
  717:                         req = req->next;
  718:                 }
  719:                 UnlockGDI(gdi);
  720: 
  721:                 /* Execute the clear because a task event may remain */
  722:                 tk_wai_tev(TEVPTN(GDI_TEV), TMO_POL);
  723: 
  724:                 if ( complete == NULL ) {
  725:                         if ( err == E_DISWAI ) err = E_ABORT;
  726:                         if ( err >= E_OK ) err = E_SYS; /* It should be impossible */
  727:                         goto err_ret;
  728:                 }
  729:         }
  730: 
  731:         /* "memsz > 0" when "buf" space needs to be unlocked */
  732:         memsz = ( (gdi->def.drvatr & TDA_LOCKREQ) != 0
  733:                         && !complete->req->nolock )? complete->memsz: 0;
  734:         buf = complete->req->buf;
  735: 
  736:         /* Release "DRQ"*/
  737:         LockGDI(gdi);
  738:         gdi_relDRQ(complete, gdi);
  739:         UnlockGDI(gdi);
  740: 
  741:         /* Unlock "buf" space: executing after the release of "DRQ" is required */
  742:         if ( memsz > 0 ) UnlockSpace(buf, memsz);
  743: 
  744:         return n;
  745: 
  746: err_ret:
  747:         DEBUG_PRINT(("gdi_waitfn err = %d\n", err));
  748:         return err;
  749: }
  750: 
  751: /*
  752:  * Abort processing
  753:  *      Call by executing "LockGDI()"
  754:  */
  755: LOCAL ER gdi_abortreq( ID tskid, T_DEVREQ *req, GDI gdi )
  756: {
  757:         DRQ    *drq = req->exinf;
  758:         ER     err;
  759: 
  760:         if ( drq == NULL ) {
  761:                 /* Before the request of acceptance: release "execfn"-wait */
  762:                 tk_dis_wai(tskid, TTW_FLG);
  763:                 return E_OK;
  764:         }
  765: 
  766:         if ( drq->req == NULL ) {
  767:                 /* Processing was already completed */
  768:                 return E_OK;
  769:         }
  770: 
  771:         if ( !isQueEmpty(&drq->q) ) {
  772:                 /* Wait-for-acceptance: delete from the accept-wait-queue */
  773:                 cntacpq(req, gdi, --);
  774:                 QueRemove(&drq->q);
  775:                 QueInit(&drq->q);
  776:                 req->error = E_ABORT;
  777:                 drq->done = Done;
  778:         }
  779: 
  780:         if ( drq->done == Done ) {
  781:                 /* Processed: release the completion-wait */
  782:                 tk_dis_wai(tskid, TTWTEV(GDI_TEV));
  783:                 return E_OK;
  784:         }
  785: 
  786:         /* Request the abort with device driver */
  787:         if ( drq->done != Abort ) {
  788:                 drq->done = Abort;
  789:                 if ( gdi->def.abort != NULL ) {
  790:                         err = (*gdi->def.abort)(req, gdi);
  791:                         if ( err < E_OK ) goto err_ret;
  792:                 }
  793:         }
  794: 
  795:         return E_OK;
  796: 
  797: err_ret:
  798:         DEBUG_PRINT(("gdi_abortreq err = %d\n", err));
  799:         return err;
  800: }
  801: 
  802: /*
  803:  * Abort processing function
  804:  */
  805: LOCAL ER gdi_abortfn( ID tskid, T_DEVREQ *req, INT nreq, GDI gdi )
  806: {
  807:         LockGDI(gdi);
  808:         if ( nreq == 1 ) {
  809:                 /* Wait-for-acceptance or only one wait-for-completion */
  810:                 gdi_abortreq(tskid, req, gdi);
  811:         } else {
  812:                 /* Several completion-waits */
  813:                 tk_dis_wai(tskid, TTWTEV(GDI_TEV));
  814:         }
  815:         UnlockGDI(gdi);
  816: 
  817:         return E_OK;
  818: }
  819: 
  820: /*
  821:  * Event function
  822:  */
  823: LOCAL INT gdi_eventfn( INT evttyp, void *evtinf, GDI gdi )
  824: {
  825:         INT    ret;
  826: 
  827:         if ( gdi->def.event == NULL ) return E_OK;
  828: 
  829:         LockCALL(gdi);
  830:         ret = (*gdi->def.event)(evttyp, evtinf, gdi);
  831:         UnlockCALL(gdi);
  832: 
  833:         return ret;
  834: }
  835: 
  836: /* ------------------------------------------------------------------------ */
  837: /*
  838:  *      Device registration
  839:  */
  840: 
  841: /*
  842:  * Device registration processing
  843:  */
  844: LOCAL ER gdi_defdevice( GDI gdi, T_IDEV *idev )
  845: {
  846:         T_DDEV ddev;
  847:         ER     err;
  848: 
  849:         ddev.exinf   = gdi;
  850:         ddev.drvatr  = gdi->def.drvatr & ~(TDA_LOCKREQ|TDA_LIMITEDREQ);
  851:         ddev.devatr  = gdi->def.devatr;
  852:         ddev.nsub    = gdi->def.nsub;
  853:         ddev.blksz   = gdi->def.blksz;
  854:         ddev.openfn  = (FP)gdi_openfn;
  855:         ddev.closefn = (FP)gdi_closefn;
  856:         ddev.execfn  = (FP)gdi_execfn;
  857:         ddev.waitfn  = (FP)gdi_waitfn;
  858:         ddev.abortfn = (FP)gdi_abortfn;
  859:         ddev.eventfn = (FP)gdi_eventfn;
  860: 
  861:         err = tk_def_dev(gdi->def.devnm, &ddev, idev);
  862:         if ( err < E_OK ) goto err_ret;
  863: 
  864:         gdi->devid = (ID)err;
  865: 
  866:         return E_OK;
  867: 
  868: err_ret:
  869:         DEBUG_PRINT(("gdi_defdevice err = %d\n", err));
  870:         return err;
  871: }
  872: 
  873: /*
  874:  * Device registration
  875:  *      Device shall be registered in accordance with "ddev" registration information.
  876:  *      Device initial information is returned to "idev".
  877:  *      It is not returned when "idev = NULL".
  878:  *      Return the driver I/F access handle to "GDI".
  879:  */
  880: EXPORT ER GDefDevice( const GDefDev *ddev, T_IDEV *idev, GDI *p_gdi )
  881: {
  882:         GDI    gdi;
  883:         DRQ    *drq;
  884:         T_CFLG cflg;
  885:         INT    n;
  886:         ER     err;
  887: 
  888:         if ( ddev->maxreqq < 1 ) { err = E_PAR; goto err_ret1; }
  889: 
  890:         if ( GDI_TEV == 0 ) {
  891:                 /* Get the allocation of task event */
  892:                 n = tk_get_cfn((UB*)"TEV_GDI", &GDI_TEV, 1);
  893:                 if ( n < 1 ) { err = ( n < E_OK )? n: E_SYS; goto err_ret1; }
  894:         }
  895: 
  896:         /* Create "GDI" */
  897:         gdi = Kmalloc(sizeof(*gdi));
  898:         if ( gdi == NULL ) { err = E_NOMEM; goto err_ret1; }
  899: 
  900:         gdi->def = *ddev;
  901:         QueInit(&gdi->freeq);
  902:         QueInit(&gdi->acpq);
  903: 
  904:         gdi->limit = ddev->maxreqq + 1;
  905:         if ( (ddev->drvatr & TDA_LIMITEDREQ) != 0 ) gdi->limit /= 2;
  906:         gdi->preq[0] = gdi->preq[1] = 0;
  907:         gdi->acpd[0] = gdi->acpd[1] = 0;
  908:         gdi->acpa[0] = gdi->acpa[1] = 0;
  909: 
  910:         /* Allocate "DRQ" */
  911:         n = ddev->maxreqq;
  912:         drq = Kcalloc(n, sizeof(DRQ));
  913:         if ( drq == NULL ) { err = E_NOMEM; goto err_ret2; }
  914:         gdi->drq = drq;
  915:         while ( n-- > 0 ) {
  916:                 QueInsert((QUEUE*)drq, &gdi->freeq);
  917:                 drq++;
  918:         }
  919: 
  920:         /* Create the event flag for queue insert notification */
  921:         STRNCPY((B*)&cflg.exinf, (B*)gdi->def.devnm, sizeof(void*));
  922:         cflg.flgatr  = TA_TPRI | TA_WMUL;
  923:         cflg.iflgptn = 0;
  924:         err = tk_cre_flg(&cflg);
  925:         if ( err < E_OK ) goto err_ret3;
  926:         gdi->flgid = (ID)err;
  927: 
  928:         /* Create the lock for exclusive access control */
  929:         err = CreateMLock(&gdi->lock, gdi->def.devnm);
  930:         if ( err < E_OK ) goto err_ret4;
  931: 
  932:         /* Device registration */
  933:         err = gdi_defdevice(gdi, idev);
  934:         if ( err < E_OK ) goto err_ret5;
  935: 
  936:         *p_gdi = gdi;
  937:         return E_OK;
  938: 
  939: err_ret5:
  940:         DeleteMLock(&gdi->lock);
  941: err_ret4:
  942:         tk_del_flg(gdi->flgid);
  943: err_ret3:
  944:         Kfree(gdi->drq);
  945: err_ret2:
  946:         Kfree(gdi);
  947: err_ret1:
  948:         DEBUG_PRINT(("GDefDevice err = %d\n", err));
  949:         return err;
  950: }
  951: 
  952: /*
  953:  * Update
  954:  *      Update the GDI device registration in accordance with "ddev" registration information.
  955:  *      Device name (devnm) and the maximum number of request queuings
  956:  *      (maxreqq) cannot be changed.(must not be changed).
  957:  *      All the requests that are accumulated in the request-accept-queue
  958:  *      and are not accepted yet shall be aborted.
  959:  *      Device ID is not changed when updated.
  960:  *      "GRedefDevice()" cannot be called from the processing function
  961:  *      (open/close/abort/event).
  962:  */
  963: EXPORT ER GRedefDevice( const GDefDev *ddev, GDI gdi )
  964: {
  965:         DRQ    *drq;
  966:         ER     err;
  967: 
  968:         LockGDI(gdi);
  969:         gdi->def = *ddev;
  970:         UnlockGDI(gdi);
  971: 
  972:         /* Update the device registration */
  973:         err = gdi_defdevice(gdi, NULL);
  974:         if ( err < E_OK ) goto err_ret;
  975: 
  976:         /* Abort all the requests accumulated in an accept-wait-queue */
  977:         LockGDI(gdi);
  978:         while ( (drq = (DRQ*)QueRemoveNext(&gdi->acpq)) != NULL ) {
  979:                 QueInit(&drq->q);
  980:                 drq->req->error = E_ABORT;
  981:                 drq->done = Done;
  982:                 if ( drq->wtid > 0 ) {
  983:                         tk_dis_wai(drq->wtid, TTWTEV(GDI_TEV));
  984:                 }
  985:         }
  986:         gdi->acpd[0] = gdi->acpd[1] = 0;
  987:         gdi->acpa[0] = gdi->acpa[1] = 0;
  988:         UnlockGDI(gdi);
  989: 
  990:         return E_OK;
  991: 
  992: err_ret:
  993:         DEBUG_PRINT(("GRedefDevice err = %d\n", err));
  994:         return err;
  995: }
  996: 
  997: /*
  998:  * Deregistration
  999:  *      Deregister "GDI" device
 1000:  */
 1001: EXPORT ER GDelDevice( GDI gdi )
 1002: {
 1003:         ER     err, error = E_OK;
 1004: 
 1005:         /* Deregister device */
 1006:         err = tk_def_dev(gdi->def.devnm, NULL, NULL);
 1007:         if ( err < E_OK ) {
 1008:                 error = err;
 1009:                 if ( err == E_BUSY ) goto err_ret;
 1010:         }
 1011: 
 1012:         /* Delete the lock for exclusive access control */
 1013:         DeleteMLock(&gdi->lock);
 1014: 
 1015:         /* Delete the event flag for queue insert notification */
 1016:         err = tk_del_flg(gdi->flgid);
 1017:         if ( err < E_OK ) error = err;
 1018: 
 1019:         /* Delete "DRQ" */
 1020:         Kfree(gdi->drq);
 1021: 
 1022:         /* Delete "GDI" */
 1023:         Kfree(gdi);
 1024: 
 1025: err_ret:
 1026: #ifdef DEBUG
 1027:         if ( error < E_OK ) DEBUG_PRINT(("GDelDevice err = %d\n", error));
 1028: #endif
 1029:         return error;
 1030: }
 1031: 
 1032: /* ------------------------------------------------------------------------ */