gonzui


Format: Advanced Search

tkernel_2/driver/tef_em1d/lowkbpd/src/hwkbpd.cbare sourcepermlink (0.08 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/07/28.
   11:  *    Modified by TRON Forum(http://www.tron.org/) at 2015/06/01.
   12:  *
   13:  *----------------------------------------------------------------------
   14:  */
   15: 
   16: /*
   17:         hwkbpd.c        lowkbpd machine-depdendent part
   18:  *
   19:  */
   20: #include "kbpd.h"
   21: #include <tk/syslib.h>
   22: #include <device/devconf.h>
   23: #include <device/em1d512_iic.h>
   24: 
   25: /* Get "DEVCONF" entry */
   26: IMPORT  W        GetDevConf(UB *name, W *val);
   27: 
   28: LOCAL   ID        FlgID;                 /* flag for event notification */
   29: 
   30: #define TpFlg   (1 << 0)
   31: #define SwFlg   (1 << 1)
   32: 
   33: // ---------------------------------------------------------------------------
   34: /* tablet parameter (coordinate normalizaton parameter, etc.) */
   35: typedef struct {
   36:         W      x_bias;
   37:         W      x_span;
   38:         W      y_bias;
   39:         W      y_span;
   40:         W      nodsp;
   41:         W      rate_off;
   42:         W      rate_on;
   43: } TABPAR;
   44: 
   45: LOCAL   TABPAR    TabPar = {944, -880, 912, -832, 0, 50, 50};
   46: 
   47: #define ACC_DELTA_X     (8)         /* avoid pen jitter (X) */
   48: #define ACC_DELTA_Y     (8)         /* avoid pen jitter(Y) */
   49: #define INV_DELTA_X     (0)         /* ignore small displacement (X) */
   50: #define INV_DELTA_Y     (0)         /* ignore small displacement (Y) */
   51: 
   52: LOCAL   W px, py, pb, ax, ay;     /* previous TP status */
   53: LOCAL   RawEvt    PrevTpEvt;         /* area to save previous TP event */
   54: LOCAL   UW        PrevTpSts = 0;         /* area to save previous TP status */
   55: LOCAL   W CurrTpSw = 0;           /* area to save the current TP touch status */
   56: LOCAL   W TpActive = 1;           /* TP active or inactive status */
   57: LOCAL   FastLock  HwLock_tp;       /* for exclusive access control purposes */
   58: LOCAL   ID        TpTaskID;              /* TP processing task ID */
   59: 
   60: #define TpVec   IV_GPIO(0)
   61: #define RETRY   4
   62: 
   63: /* read DA9052 register */
   64: LOCAL   W ReadDA9052(W reg)
   65: {
   66:         W      er, i;
   67:         UB     cmd[2];
   68: 
   69:         for (i = RETRY; i > 0; i--) {
   70:                 cmd[0] = (reg << 1) | 1;
   71:                 cmd[1] = ~0;
   72:                 er = em1d512_spixfer(0, cmd, cmd, sizeof(cmd));
   73:                 if (er >= E_OK) return cmd[1];
   74:         }
   75: 
   76:         DP(("ReadDA9052(R%d) [%#x]\n", reg, er));
   77:         return er;
   78: }
   79: 
   80: /* write DA9052 register */
   81: LOCAL   W WriteDA9052(W reg, W dat)
   82: {
   83:         W      er, i;
   84:         UB     cmd[2];
   85: 
   86:         for (i = RETRY; i > 0; i--) {
   87:                 cmd[0] = reg << 1;
   88:                 cmd[1] = dat;
   89:                 er = em1d512_spixfer(0, cmd, cmd, sizeof(cmd));
   90:                 if (er >= E_OK) return E_OK;
   91:         }
   92: 
   93:         DP(("WriteDA9052(R%d, %#x) [%#x]\n", reg, dat, er));
   94:         return er;
   95: }
   96: 
   97: /* touch panel data processing */
   98: LOCAL   void      tpproc(InMsg *msg)
   99: {
  100:         W      x, y, sw, dx, dy;
  101:         RawEvt evt;
  102:         union {
  103:                 PdInStat      stat;
  104:                 UW            uw;
  105:         } u;
  106: 
  107:         sw = msg->hw.dt[0];
  108:         x  = msg->hw.dt[2] | (msg->hw.dt[3] << 8);
  109:         y  = msg->hw.dt[4] | (msg->hw.dt[5] << 8);
  110: 
  111:         if (!sw) {
  112:                 if (!pb) goto fin;
  113:                 x = px;
  114:                 y = py;
  115:         } else {       /* if pen on */
  116:                 if (pb) {
  117:                         /* avoid pointer jitter */
  118:                         dx = x - px;
  119:                         dy = y - py;
  120:                         if (dx < 0 && (dx += INV_DELTA_X) > 0) dx = 0;
  121:                         if (dx > 0 && (dx -= INV_DELTA_X) < 0) dx = 0;
  122:                         if (dy < 0 && (dy += INV_DELTA_Y) > 0) dy = 0;
  123:                         if (dy > 0 && (dy -= INV_DELTA_Y) < 0) dy = 0;
  124:                         ax += dx;
  125:                         ay += dy;
  126:                         if (ax > -ACC_DELTA_X && ax < ACC_DELTA_X &&
  127:                             ay > -ACC_DELTA_Y && ay < ACC_DELTA_Y) goto fin;
  128:                 }
  129:         }
  130:         ax = ay = 0;
  131:         px = x;
  132:         py = y;
  133: 
  134:         /* set event status */
  135:         u.uw = 0;
  136:         evt.p.stat = u.stat;
  137:         evt.p.stat.cmd   = INP_PD;
  138:         evt.p.stat.main  = pb = sw ? 1 : 0;
  139:         evt.p.stat.abs   = 1;  /* absolute movement only, relative motion unsupported */
  140:         evt.p.stat.norel = 1;
  141:         evt.p.stat.nodsp = TabPar.nodsp;
  142: 
  143:         /* normalize X/Y coordinates */
  144:         x = (x - TabPar.x_bias) * PDIN_XMAX / TabPar.x_span;
  145:         y = (y - TabPar.y_bias) * PDIN_YMAX / TabPar.y_span;
  146: 
  147:         evt.p.xpos = (x < 0) ? 0 : ((x > PDIN_XMAX) ? PDIN_XMAX : x);
  148:         evt.p.ypos = (y < 0) ? 0 : ((y > PDIN_YMAX) ? PDIN_YMAX : y);
  149: 
  150:         /* send event */
  151:         kpSendPdEvt(&evt, &PrevTpSts, &PrevTpEvt);
  152: 
  153:  fin:
  154:         return;
  155: }
  156: 
  157: /* enable TP interrupt */
  158: LOCAL   void      tpIntEnable(void)
  159: {
  160:         /* interrupts can be missed using edge-triggermode,
  161:          * so we use level-trigger mode (register handling of DA9052 is done via SPI:
  162:          * pay attention to the delay caused by SPI communication) */
  163:         SetIntMode(TpVec, IM_ENA | IM_LEVEL | IM_LOW);
  164:         EnableInt(TpVec);
  165: 
  166:         return;
  167: }
  168: 
  169: /* disable TP interrupt */
  170: LOCAL   void      tpIntDisable(void)
  171: {
  172:         DisableInt(TpVec);
  173:         SetIntMode(TpVec, IM_DIS);
  174: 
  175:         return;
  176: }
  177: 
  178: /* TP interrupt handler */
  179: LOCAL   void      tp_inthdr(INTVEC vec)
  180: {
  181:         /* wakeup a waiting task */
  182:         tk_set_flg(FlgID, TpFlg);
  183: 
  184:         /* disable interrupt */
  185:         DisableInt(vec);
  186: 
  187:         return;
  188: }
  189: 
  190: /* read TP */
  191: LOCAL   ER        tpread(UW *x, UW *y, UW *sw)
  192: {
  193:         W      sts, xmsb, ymsb, xylsb;
  194: 
  195:         /* obtain status */
  196:         if ((sts = ReadDA9052(6)) < 0 ||
  197:             (xmsb = ReadDA9052(107)) < 0 ||
  198:             (ymsb = ReadDA9052(108)) < 0 ||
  199:             (xylsb = ReadDA9052(109)) < 0) return E_IO;
  200: 
  201:         /* x-axis <- y-measure, y-axis <- x-measure */
  202:         *x = (ymsb << 2) | ((xylsb & 0x0c) >> 2);
  203:         *y = (xmsb << 2) | ((xylsb & 0x03) >> 0);
  204:         *sw = xylsb & 0x40;
  205: 
  206:         /* error if pen down and A/D conversion is not finished */
  207:         return (*sw && !(sts & 0x80)) ? E_BUSY : E_OK;
  208: }
  209: 
  210: /* TP processing */
  211: LOCAL   void      tpscan(void)
  212: {
  213:         ER     er;
  214:         UW     x, y, sw;
  215:         InMsg  msg;
  216: 
  217:         /* read TP status */
  218:         er = tpread(&x, &y, &sw);
  219:         if (er < E_OK) goto fin0;
  220: 
  221:         /* if already in untouch state, do not send untouch message. */
  222:         if(!sw && !CurrTpSw) goto fin0;
  223: 
  224:         /* change touch state */
  225:         CurrTpSw = sw;
  226: 
  227:         msg.hw.id = HWPD;
  228:         msg.hw.dt[0] = sw;
  229:         msg.hw.dt[2] = x & 0xff;
  230:         msg.hw.dt[3] = (x >> 8) & 0xff;
  231:         msg.hw.dt[4] = y & 0xff;
  232:         msg.hw.dt[5] = (y >> 8) & 0xff;
  233:         tk_snd_mbf(InpMbf, &msg, sizeof(msg), TMO_POL);
  234: fin0:
  235:         return;
  236: }
  237: 
  238: /* TP processing task */
  239: LOCAL   void      tp_task(void)
  240: {
  241:         ER     er;
  242:         W      i;
  243:         UINT   flg;
  244:         LOCAL  const UB tpsetup[] = {
  245:                  10, 0xff,    // IRQ_MASK_A (mask all)
  246:                  11, 0xbf,    // IRQ_MASK_B M_PEN_DOWN
  247:                  12, 0xff,    // IRQ_MASK_C (mask all)
  248:                  13, 0xff,    // IRQ_MASK_D (mask all)
  249:                   5, 0xff,    // EVENT_A (clear all)
  250:                   6, 0xff,    // EVENT_B (clear all)
  251:                   7, 0xff,    // EVENT_C (clear all)
  252:                   8, 0xff,    // EVENT_D (clear all)
  253:                  22, 0x09,    // GPIO3:TSIYN,  GPIO2:GPI,Active low
  254:                  23, 0x00,    // GPIO5:TSIXN,  GPIO4:TSIYP
  255:                  24, 0x00,    // GPIO7:TSIREF, GPIO6:TSIXP
  256:                 105, 0xc3,    // TSI_CONT_A 4slot, PEN_DET_EN, AUTO_TSI_EN
  257:                 106, 0x80,    // TSI_CONT_B X+/X-,Y+/Y-,Y+/X-
  258:                  82, 0x40,    // 1ms interval
  259:                   0, 0x00,    // (terminate)
  260:         };
  261: 
  262:         /* DA9052 TSI initialization */
  263:         for (i = 0; tpsetup[i]; i += 2) {
  264:                 er = WriteDA9052(tpsetup[i], tpsetup[i + 1]);
  265:                 if (er < E_OK) goto fin0;
  266:         }
  267: 
  268:         /* enable interrupt */
  269:         tpIntEnable();
  270: 
  271:         while (1) {
  272:                 /* wait for TP interrupt */
  273:                 tk_wai_flg(FlgID, TpFlg, TWF_ANDW | TWF_BITCLR, &flg, TMO_FEVR);
  274: 
  275:                 // interrupt is prohibited inside the TP intterupt handler
  276: 
  277:                 /* polling is done while pen touch state */
  278:                 while (1) {
  279:                         Lock(&HwLock_tp);
  280:                         tpscan();
  281:                         Unlock(&HwLock_tp);
  282: 
  283:                         if (CurrTpSw) {
  284:                                 tk_dly_tsk(TabPar.rate_on);
  285:                                 WriteDA9052(6, 0xc0);
  286:                         } else {
  287:                                 /* if untouch state is entered, generate an interrupt
  288:                                  * even if we clear status flag,
  289:                                  * the interrupt is continuously generated for a while, so
  290:                                  * we wait for a while after clearing the flag */
  291:                                 WriteDA9052(6, 0xc0);
  292:                                 tk_dly_tsk(TabPar.rate_off);
  293:                                 break;
  294:                         }
  295:                 }
  296: 
  297:                 /* re-enabling TP interrupt */
  298:                 EnableInt(TpVec);
  299:         }
  300: 
  301: fin0:
  302:         tpIntDisable();
  303:         tk_exd_tsk();
  304: }
  305: 
  306: /* start processing of TP processing task ID */
  307: LOCAL   ER        tpstart(BOOL start)
  308: {
  309:         ER     er;
  310:         W      n, par[L_DEVCONF_VAL];
  311:         T_DINT dint;
  312:         T_CTSK ctsk;
  313: 
  314:         /* termination */
  315:         if (!start) {
  316:                 er = E_OK;
  317:                 if (!TpActive) goto fin0;
  318:                 else goto fin4;
  319:         }
  320: 
  321:         /* enable or disable tablet */
  322:         n = GetDevConf("TEngUseTablet", par);
  323:         if (n > 0) TpActive = par[0] ? 1 : 0;
  324:         if (!TpActive) goto fin0;
  325: 
  326:         /* set tablet parameters */
  327:         n = GetDevConf("TEngTabletPar", par);
  328:         if (n >= 6 && par[1] != 0 && par[3] != 0) {
  329:                 TabPar.x_bias   = par[0];
  330:                 TabPar.x_span   = par[1];
  331:                 TabPar.y_bias   = par[2];
  332:                 TabPar.y_span   = par[3];
  333:                 TabPar.nodsp    = par[4] ? 1 : 0;
  334:                 TabPar.rate_off = par[5];
  335:                 TabPar.rate_on  = (n >= 7) ? par[6] : par[5];
  336:         }
  337: 
  338:         /* create a lock */
  339:         er = CreateLock(&HwLock_tp, "lkbY");
  340:         if (er < E_OK) goto fin0;
  341: 
  342:         /* set up interrupt handler */
  343:         dint.inthdr = tp_inthdr;
  344:         dint.intatr = TA_HLNG;
  345:         er = tk_def_int(TpVec, &dint);
  346:         if (er < E_OK) goto fin1;
  347: 
  348:         /* define TP processing task */
  349:         SetOBJNAME(ctsk.exinf, "lkbY");
  350:         ctsk.task = tp_task;
  351:         ctsk.itskpri = DEF_PRIORITY;
  352:         ctsk.stksz = TASK_STKSZ;
  353:         ctsk.tskatr = TA_HLNG | TA_RNG0;
  354:         er = tk_cre_tsk(&ctsk);
  355:         if (er < E_OK) goto fin2;
  356:         TpTaskID = er;
  357: 
  358:         /* start TP processing task */
  359:         er = tk_sta_tsk(TpTaskID, 0);
  360:         if (er < E_OK) goto fin3;
  361: 
  362:         er = E_OK;     
  363:         goto fin0;
  364: fin4:
  365:         tpIntDisable();
  366:         tk_ter_tsk(TpTaskID);
  367: fin3:
  368:         tk_del_tsk(TpTaskID);
  369: fin2:
  370:         tk_def_int(TpVec, NULL);
  371: fin1:
  372:         DeleteLock(&HwLock_tp);
  373: fin0:
  374:         return er;
  375: }
  376: 
  377: // ---------------------------------------------------------------------------
  378: LOCAL   UB        PrevSwMsg = 0;         /* area to store previous SW message */
  379: LOCAL   UB        PrevSwSts = 0;         /* area to store previous SW readout */
  380: LOCAL   FastLock  HwLock_sw;       /* for exclusive access control purposes */
  381: LOCAL   ID        SwTaskID;              /* SW processing task ID */
  382: 
  383: LOCAL   const INTVEC      SwVec[] = {IV_GPIO(4), IV_GPIO(6), IV_GPIO(7)};
  384: LOCAL   const UB  KeyCode[] = {
  385: /*      P4/SW4 P5/--- P6/SW3 P7/SW2 P8/SW1 */
  386:         0x6f,  0x00,  0x6d,  0x6e,  0x00,
  387: };
  388: 
  389: #define GIOBase(x)      (0xc0050000 + 0x00000040 * (x))
  390: #define GIO_L           0x00
  391: #define GIO_I(x)        (GIOBase(x) + 0x0010)
  392: 
  393: /* SW data processing */
  394: LOCAL   void      swproc(InMsg *msg)
  395: {
  396:         INT    i, mask, kchg, kcode;
  397: 
  398:         /* send the difference from the previous data */
  399:         kchg = PrevSwMsg ^ msg->hw.dt[0];
  400:         for (i = 0, mask = 1; i < sizeof(KeyCode); i++, mask <<= 1) {
  401:                 if (!(mask & kchg)) continue;
  402: 
  403:                 kcode = KeyCode[i];
  404:                 if (kcode) kpSendKeyEvt((msg->hw.dt[0] & mask) ?
  405:                                         0x01 : 0x00, kcode);
  406:         }
  407: 
  408:         /* save key status */
  409:         PrevSwMsg = msg->hw.dt[0];
  410: 
  411:         return;
  412: }
  413: 
  414: /* enable SW interrupt */
  415: LOCAL   void      swIntEnable(void)
  416: {
  417:         W      i;
  418: 
  419:         for (i = 0; i < sizeof(SwVec) / sizeof(INTVEC); i++) {
  420:                 SetIntMode(SwVec[i], IM_ENA | IM_EDGE | IM_BOTH);
  421:                 ClearInt(SwVec[i]);
  422:                 EnableInt(SwVec[i]);
  423:         }
  424: 
  425:         return;
  426: }
  427: 
  428: /* disable SW interrupt */
  429: LOCAL   void      swIntDisable(void)
  430: {
  431:         W      i;
  432: 
  433:         for (i = 0; i < sizeof(SwVec) / sizeof(INTVEC); i++) {
  434:                 DisableInt(SwVec[i]);
  435:                 SetIntMode(SwVec[i], IM_DIS);
  436:                 ClearInt(SwVec[i]);
  437:         }
  438: 
  439:         return;
  440: }
  441: 
  442: /* SW interrupt handler */
  443: LOCAL   void      sw_inthdr(INTVEC vec)
  444: {
  445:         /* wakeup a waiting task */
  446:         tk_set_flg(FlgID, SwFlg);
  447: 
  448:         /* clear interrupt flag */
  449:         ClearInt(vec);
  450: 
  451:         return;
  452: }
  453: 
  454: /* SW processing */
  455: LOCAL   void      swscan(void)
  456: {
  457:         InMsg  msg;
  458:         UW     sw;
  459: 
  460:         /* read SW status */
  461:         sw = in_w(GIO_I(GIO_L));
  462: 
  463:         /* mask and shift unnecessary bits */
  464:         sw &= 0x000000d0;      // P7,P6,P4
  465:         sw >>= 4;              // bit0: P4
  466: 
  467:         /* if the state is different from the previously read state, send a message */
  468:         if (sw != PrevSwSts) {
  469:                 msg.hw.id = HWKB;
  470:                 msg.hw.dt[0] = sw;
  471:                 tk_snd_mbf(InpMbf, &msg, sizeof(msg), TMO_POL);
  472:                 PrevSwSts = sw;
  473:         }
  474:         return;
  475: }
  476: 
  477: /* SW processing task */
  478: LOCAL   void      sw_task(void)
  479: {
  480:         UINT   flg;
  481: 
  482:         /* enable interrupt */
  483:         swIntEnable();
  484: 
  485:         while (1) {
  486:                 /* wait for SW interrupt */
  487:                 tk_clr_flg(FlgID, ~SwFlg);
  488:                 tk_wai_flg(FlgID, SwFlg, TWF_ANDW, &flg, TMO_FEVR);
  489: 
  490:                 /* wait for a while to suprress chattering */
  491:                 tk_dly_tsk(10);
  492: 
  493:                 /* SW processing */
  494:                 Lock(&HwLock_sw);
  495:                 swscan();
  496:                 Unlock(&HwLock_sw);
  497:         }
  498: 
  499:         /* emergency (usually control does not come here) */
  500:         swIntDisable();
  501:         tk_exd_tsk();
  502: }
  503: 
  504: /* start processing of SW processing task */
  505: LOCAL   ER        swstart(BOOL start)
  506: {
  507:         ER     er;
  508:         W      i;
  509:         T_DINT dint;
  510:         T_CTSK ctsk;
  511: 
  512:         /* termination */
  513:         if (!start) {
  514:                 er = E_OK;
  515:                 goto fin4;
  516:         }
  517: 
  518:         /* create a lock */
  519:         er = CreateLock(&HwLock_sw, "lkbX");
  520:         if (er < E_OK) goto fin0;
  521: 
  522:         /* set up interrupt handler */
  523:         dint.inthdr = sw_inthdr;
  524:         dint.intatr = TA_HLNG;
  525:         for (i = 0; i < sizeof(SwVec) / sizeof(INTVEC); i++) {
  526:                 er = tk_def_int(SwVec[i], &dint);
  527:                 if (er < E_OK) goto fin2;
  528:         }
  529: 
  530:         /* define SW processing task */
  531:         SetOBJNAME(ctsk.exinf, "lkbX");
  532:         ctsk.task = sw_task;
  533:         ctsk.itskpri = DEF_PRIORITY;
  534:         ctsk.stksz = TASK_STKSZ;
  535:         ctsk.tskatr = TA_HLNG | TA_RNG0;
  536:         er = tk_cre_tsk(&ctsk);
  537:         if (er < E_OK) goto fin2;
  538:         SwTaskID = er;
  539: 
  540:         /* start SW processing task */
  541:         er = tk_sta_tsk(SwTaskID, 0);
  542:         if (er < E_OK) goto fin3;
  543: 
  544:         er = E_OK;
  545:         goto fin0;
  546: fin4:
  547:         swIntDisable();
  548:         tk_ter_tsk(SwTaskID);
  549: fin3:
  550:         tk_del_tsk(SwTaskID);
  551: fin2:
  552:         for (i = 0; i < sizeof(SwVec) / sizeof(INTVEC); i++) {
  553:                 tk_def_int(SwVec[i], NULL);
  554:         }
  555: /*fin1:*/
  556:         DeleteLock(&HwLock_sw);
  557: fin0:
  558:         return er;
  559: }
  560: 
  561: // ---------------------------------------------------------------------------
  562: /* process received data */
  563: EXPORT  void     hwProc(InMsg *msg)
  564: {
  565:         switch (msg->hw.id) {
  566:         case   HWKB:     swproc(msg);                        break;
  567:         case   HWPD:     if (TpActive) tpproc(msg);  break;
  568:         default:                                       break;
  569:         }
  570: 
  571:         return;
  572: }
  573: 
  574: /* set input mode */
  575: EXPORT  void     hwImode(W inpmd)
  576: {
  577:         return;                /* no configurable item : do nothing */
  578: }
  579: 
  580: /* device initialization processing(cmd: DC_OPEN/DC_SUSPEND/DC_RESUME) */
  581: EXPORT  ER       hwInit(W cmd)
  582: {
  583:         ER     er;
  584:         T_CFLG cflg;
  585: 
  586:         switch (cmd) {
  587:         default:                       /* not applicable */
  588:                 return E_OK;
  589: 
  590:         case   DC_SUSPEND:               /* suspend */
  591:                 Lock(&HwLock_sw);
  592:                 if (TpActive) Lock(&HwLock_tp);
  593:                 return E_OK;
  594: 
  595:         case   DC_RESUME:                /* resume */
  596:                 if (TpActive) Unlock(&HwLock_tp);
  597:                 Unlock(&HwLock_sw);
  598:                 return E_OK;
  599: 
  600:         case   DC_OPEN:          /* initial reset */
  601:                 break;
  602:         }
  603: 
  604:         /* initailize SPI driver */
  605:         if ( (er = em1d512_iicspi_svc(TRUE)) < E_OK ) goto fin0;
  606: 
  607:         SetOBJNAME(cflg.exinf, "lkbZ");
  608:         cflg.flgatr = TA_TFIFO | TA_WMUL;
  609:         cflg.iflgptn = 0;
  610:         er = tk_cre_flg(&cflg);
  611:         if (er < E_OK) goto fin0;
  612:         FlgID = er;
  613: 
  614:         er = swstart(TRUE);
  615:         if (er < E_OK) goto fin1;
  616: 
  617:         er = tpstart(TRUE);
  618:         if (er < E_OK) goto fin2;
  619: 
  620:         er = E_OK;
  621:         goto fin0;
  622: 
  623: /*fin3:*/
  624:         tpstart(FALSE);
  625: fin2:
  626:         swstart(FALSE);
  627: fin1:
  628:         tk_del_flg(FlgID);
  629: fin0:
  630:         return er;
  631: }