/* * Device close processing */ LOCAL ER close_device( OpnCB *opncb, UINT option ) { ID devid; DevCB *devcb; INT unitno; WaitQ waiq; ER ercd = E_OK; /* Abort all requests during processing */ abort_allrequest(opncb); LockDM(); devcb = opncb->devcb; unitno = opncb->unitno; devid = DEVID(devcb, unitno); /* Multiple tasks can initiate open/close processing, so ensure processing only by one task at a time. */ if ( enterSyncWait(&devcb->syncq, &waiq) ) { /* Wait for synchronization for concurrent open/close */ UnlockDM(); SyncWaitDM(); LockDM(); } /* Is device driver call required? */ if ( chkopen(devcb, unitno, opncb) ) { if ( (devcb->ddev.drvatr & TDA_OPENREQ) == 0 ) { goto no_drvcall; } option &= ~TD_EJECT; /* EJECT is effective at last close */ } /* Device driver call */ UnlockDM(); ercd = call_closefn(devcb, DEVID(devcb, unitno), option); LockDM(); no_drvcall: /* Free open management block */ delOpnCB(opncb); /* Wake up task waiting for synchronization for concurrent open/close */ leaveSyncWait(&devcb->syncq, &waiq); UnlockDM(); ERCD_PRINT(("close_device ercd = %d\n", ercd)); return ercd; }
/* * Opens a tty device. */ PRIVATE int tty_open(unsigned minor) { /* Assign controlling terminal. */ if ((IS_LEADER(curr_proc)) && (curr_proc->tty == NULL_DEV)) { /* tty already assigned. */ if (tty.pgrp != NULL) return (-EBUSY); curr_proc->tty = DEVID(TTY_MAJOR, minor, CHRDEV); tty.pgrp = curr_proc; } return (0); }
int main(void) { DEVID(usb_device_id); DEVID_FIELD(usb_device_id, match_flags); DEVID_FIELD(usb_device_id, idVendor); DEVID_FIELD(usb_device_id, idProduct); DEVID_FIELD(usb_device_id, bcdDevice_lo); DEVID_FIELD(usb_device_id, bcdDevice_hi); DEVID_FIELD(usb_device_id, bDeviceClass); DEVID_FIELD(usb_device_id, bDeviceSubClass); DEVID_FIELD(usb_device_id, bDeviceProtocol); DEVID_FIELD(usb_device_id, bInterfaceClass); DEVID_FIELD(usb_device_id, bInterfaceSubClass); DEVID_FIELD(usb_device_id, bInterfaceProtocol); DEVID_FIELD(usb_device_id, bInterfaceNumber); DEVID(hid_device_id); DEVID_FIELD(hid_device_id, bus); DEVID_FIELD(hid_device_id, group); DEVID_FIELD(hid_device_id, vendor); DEVID_FIELD(hid_device_id, product); DEVID(ieee1394_device_id); DEVID_FIELD(ieee1394_device_id, match_flags); DEVID_FIELD(ieee1394_device_id, vendor_id); DEVID_FIELD(ieee1394_device_id, model_id); DEVID_FIELD(ieee1394_device_id, specifier_id); DEVID_FIELD(ieee1394_device_id, version); DEVID(pci_device_id); DEVID_FIELD(pci_device_id, vendor); DEVID_FIELD(pci_device_id, device); DEVID_FIELD(pci_device_id, subvendor); DEVID_FIELD(pci_device_id, subdevice); DEVID_FIELD(pci_device_id, class); DEVID_FIELD(pci_device_id, class_mask); DEVID(ccw_device_id); DEVID_FIELD(ccw_device_id, match_flags); DEVID_FIELD(ccw_device_id, cu_type); DEVID_FIELD(ccw_device_id, cu_model); DEVID_FIELD(ccw_device_id, dev_type); DEVID_FIELD(ccw_device_id, dev_model); DEVID(ap_device_id); DEVID_FIELD(ap_device_id, dev_type); DEVID(css_device_id); DEVID_FIELD(css_device_id, type); DEVID(serio_device_id); DEVID_FIELD(serio_device_id, type); DEVID_FIELD(serio_device_id, proto); DEVID_FIELD(serio_device_id, id); DEVID_FIELD(serio_device_id, extra); DEVID(acpi_device_id); DEVID_FIELD(acpi_device_id, id); DEVID_FIELD(acpi_device_id, cls); DEVID_FIELD(acpi_device_id, cls_msk); DEVID(pnp_device_id); DEVID_FIELD(pnp_device_id, id); DEVID(pnp_card_device_id); DEVID_FIELD(pnp_card_device_id, devs); DEVID(pcmcia_device_id); DEVID_FIELD(pcmcia_device_id, match_flags); DEVID_FIELD(pcmcia_device_id, manf_id); DEVID_FIELD(pcmcia_device_id, card_id); DEVID_FIELD(pcmcia_device_id, func_id); DEVID_FIELD(pcmcia_device_id, function); DEVID_FIELD(pcmcia_device_id, device_no); DEVID_FIELD(pcmcia_device_id, prod_id_hash); DEVID(of_device_id); DEVID_FIELD(of_device_id, name); DEVID_FIELD(of_device_id, type); DEVID_FIELD(of_device_id, compatible); DEVID(vio_device_id); DEVID_FIELD(vio_device_id, type); DEVID_FIELD(vio_device_id, compat); DEVID(input_device_id); DEVID_FIELD(input_device_id, flags); DEVID_FIELD(input_device_id, bustype); DEVID_FIELD(input_device_id, vendor); DEVID_FIELD(input_device_id, product); DEVID_FIELD(input_device_id, version); DEVID_FIELD(input_device_id, evbit); DEVID_FIELD(input_device_id, keybit); DEVID_FIELD(input_device_id, relbit); DEVID_FIELD(input_device_id, absbit); DEVID_FIELD(input_device_id, mscbit); DEVID_FIELD(input_device_id, ledbit); DEVID_FIELD(input_device_id, sndbit); DEVID_FIELD(input_device_id, ffbit); DEVID_FIELD(input_device_id, swbit); DEVID(eisa_device_id); DEVID_FIELD(eisa_device_id, sig); DEVID(parisc_device_id); DEVID_FIELD(parisc_device_id, hw_type); DEVID_FIELD(parisc_device_id, hversion); DEVID_FIELD(parisc_device_id, hversion_rev); DEVID_FIELD(parisc_device_id, sversion); DEVID(sdio_device_id); DEVID_FIELD(sdio_device_id, class); DEVID_FIELD(sdio_device_id, vendor); DEVID_FIELD(sdio_device_id, device); DEVID(ssb_device_id); DEVID_FIELD(ssb_device_id, vendor); DEVID_FIELD(ssb_device_id, coreid); DEVID_FIELD(ssb_device_id, revision); DEVID(bcma_device_id); DEVID_FIELD(bcma_device_id, manuf); DEVID_FIELD(bcma_device_id, id); DEVID_FIELD(bcma_device_id, rev); DEVID_FIELD(bcma_device_id, class); DEVID(virtio_device_id); DEVID_FIELD(virtio_device_id, device); DEVID_FIELD(virtio_device_id, vendor); DEVID(hv_vmbus_device_id); DEVID_FIELD(hv_vmbus_device_id, guid); DEVID(i2c_device_id); DEVID_FIELD(i2c_device_id, name); DEVID(spi_device_id); DEVID_FIELD(spi_device_id, name); DEVID(dmi_system_id); DEVID_FIELD(dmi_system_id, matches); DEVID(platform_device_id); DEVID_FIELD(platform_device_id, name); DEVID(mdio_device_id); DEVID_FIELD(mdio_device_id, phy_id); DEVID_FIELD(mdio_device_id, phy_id_mask); DEVID(zorro_device_id); DEVID_FIELD(zorro_device_id, id); DEVID(isapnp_device_id); DEVID_FIELD(isapnp_device_id, vendor); DEVID_FIELD(isapnp_device_id, function); DEVID(ipack_device_id); DEVID_FIELD(ipack_device_id, format); DEVID_FIELD(ipack_device_id, vendor); DEVID_FIELD(ipack_device_id, device); DEVID(amba_id); DEVID_FIELD(amba_id, id); DEVID_FIELD(amba_id, mask); DEVID(mips_cdmm_device_id); DEVID_FIELD(mips_cdmm_device_id, type); DEVID(x86_cpu_id); DEVID_FIELD(x86_cpu_id, feature); DEVID_FIELD(x86_cpu_id, family); DEVID_FIELD(x86_cpu_id, model); DEVID_FIELD(x86_cpu_id, vendor); DEVID(cpu_feature); DEVID_FIELD(cpu_feature, feature); DEVID(mei_cl_device_id); DEVID_FIELD(mei_cl_device_id, name); DEVID_FIELD(mei_cl_device_id, uuid); DEVID_FIELD(mei_cl_device_id, version); DEVID(rio_device_id); DEVID_FIELD(rio_device_id, did); DEVID_FIELD(rio_device_id, vid); DEVID_FIELD(rio_device_id, asm_did); DEVID_FIELD(rio_device_id, asm_vid); DEVID(ulpi_device_id); DEVID_FIELD(ulpi_device_id, vendor); DEVID_FIELD(ulpi_device_id, product); DEVID(hda_device_id); DEVID_FIELD(hda_device_id, vendor_id); DEVID_FIELD(hda_device_id, rev_id); DEVID_FIELD(hda_device_id, api_version); DEVID(fsl_mc_device_id); DEVID_FIELD(fsl_mc_device_id, vendor); DEVID_FIELD(fsl_mc_device_id, obj_type); return 0; }
/* * This checks for, and validates, the presence of the 460GX chipset, and sets * cbn_460gx to a positive value accordingly. This function returns TRUE if * the chipset scan is to be stopped, or FALSE if the scan is to move on to the * next chipset. */ Bool xf86PreScan460GX(void) { pciBusInfo_t *pBusInfo; PCITAG tag; CARD32 tmp; int i, devno; /* Bus zero should already be set up */ if (!(pBusInfo = pciBusInfo[0])) { cbn_460gx = -1; return FALSE; } /* First look for a 460GX's primary host bridge */ tag = PCI_MAKE_TAG(0, 0x10, 0); if (pciReadLong(tag, PCI_ID_REG) != DEVID(INTEL, 460GX_SAC)) { cbn_460gx = -1; return FALSE; } /* Get CBN (Chipset bus number) */ if (!(cbn_460gx = (unsigned int)pciReadByte(tag, CBN))) { /* Sanity check failed */ cbn_460gx = -1; return TRUE; } if (pciNumBuses <= cbn_460gx) pciNumBuses = cbn_460gx + 1; /* Set up bus CBN */ if (!pciBusInfo[cbn_460gx]) { pciBusInfo[cbn_460gx] = xnfalloc(sizeof(pciBusInfo_t)); *pciBusInfo[cbn_460gx] = *pBusInfo; } tag = PCI_MAKE_TAG(cbn_460gx, 0, 0); if (pciReadLong(tag, PCI_ID_REG) != DEVID(INTEL, 460GX_SAC)) { /* Sanity check failed */ cbn_460gx = -1; return TRUE; } /* * Find out which CBN devices the firmware thinks are present. Of these, * we are only interested in devices 0x10 through 0x17. */ cbdevs_460gx = pciReadLong(tag, DEVNPRES); for (i = 0, devno = 0x10; devno <= 0x17; i++, devno++) { tag = PCI_MAKE_TAG(cbn_460gx, devno, 0); if (pciReadLong(tag, PCI_ID_REG) != DEVID(INTEL, 460GX_SAC)) { /* Sanity check failed */ cbn_460gx = -1; return TRUE; } if (devno == 0x10) iord_460gx = pciReadWord(tag, IORD); busno_460gx[i] = (unsigned int)pciReadByte(tag, BUSNO); subno_460gx[i] = (unsigned int)pciReadByte(tag, SUBNO); pcis_460gx[i] = pciReadByte(tag, PCIS); ior_460gx[i] = pciReadByte(tag, IOR); has_err_460gx[i] = err_460gx[i] = 0; /* Insurance */ tag = PCI_MAKE_TAG(cbn_460gx, devno, 1); tmp = pciReadLong(tag, PCI_ID_REG); switch (tmp) { case DEVID(INTEL, 460GX_PXB): case DEVID(INTEL, 460GX_WXB): if (cbdevs_460gx & (1 << devno)) { /* Sanity check failed */ cbn_460gx = -1; return TRUE; } /* * XXX I don't have WXB docs, but PCI register dumps indicate that * the registers we are interested in are consistent with those of * the PXB. */ err_460gx[i] = pciReadByte(tag, ERRCMD); has_err_460gx[i] = 1; break; case DEVID(INTEL, 460GX_GXB_1): if (cbdevs_460gx & (1 << devno)) { /* Sanity check failed */ cbn_460gx = -1; return TRUE; } /* * XXX GXB isn't documented to have an ERRCMD register, nor any * other means of failing master aborts. For now, assume master * aborts are always allowed to complete normally. */ break; default: if (((CARD16)(tmp + 1U) <= (CARD16)1U) && (cbdevs_460gx & (1U << devno))) break; /* Sanity check failed */ cbn_460gx = -1; return TRUE; } } /* Allow master aborts to complete normally */ for (i = 0, devno = 0x10; devno <= 0x17; i++, devno++) { if (!(err_460gx[i] & 0x01)) continue; pciWriteByte(PCI_MAKE_TAG(cbn_460gx, devno, 1), ERRCMD, err_460gx[i] & ~0x01); } /* * The 460GX spec says that any access to busses higher than CBN will be * master-aborted. It seems possible however that this is not the case in * all 460GX implementations. For now, limit the bus scan to CBN, unless * we have already found a higher bus number. */ for (i = 0; subno_460gx[i] < cbn_460gx; ) { if (++i < 8) continue; pciMaxBusNum = cbn_460gx + 1; break; } return TRUE; }
* GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Nanvix. If not, see <http://www.gnu.org/licenses/>. */ #include <nanvix/const.h> #include <nanvix/dev.h> #include <nanvix/klib.h> #include <sys/types.h> #include <stdarg.h> /** * @brief Kernel's output device. */ PUBLIC dev_t kout = DEVID(NULL_MAJOR, 0, CHRDEV); /** * @brief Changes kernel's output device. * * @param dev New output device. */ PUBLIC void chkout(dev_t dev) { ssize_t n; /* Number of bytes to be flushed. */ char buffer[KBUFFER_SIZE]; /* Temporary buffer. */ kout = dev; /* Flush the content of kernel log. */ n = klog_read(0, buffer, KLOG_SIZE);
/* * Request for starting input/output to device */ EXPORT ID knl_request( ID dd, W start, VP buf, W size, TMO tmout, INT cmd ) { EXCFN execfn; VP exinf; #if TA_GP VP gp; #endif OpnCB *opncb; DevCB *devcb; ReqCB *reqcb; UINT m; ER ercd; LockDM(); if ( start <= -0x00010000 && start >= -0x7fffffff ) { m = 0; /* Ignore open mode */ } else { m = ( cmd == TDC_READ )? TD_READ: TD_WRITE; } ercd = knl_check_devdesc(dd, m, &opncb); if ( ercd < E_OK ) { goto err_ret1; } devcb = opncb->devcb; execfn = (EXCFN)devcb->ddev.execfn; exinf = devcb->ddev.exinf; #if TA_GP gp = devcb->ddev.gp; #endif /* Get request management block */ reqcb = newReqCB(opncb); if ( reqcb == NULL ) { ercd = E_LIMIT; goto err_ret1; } /* Set request packet */ reqcb->req.next = NULL; reqcb->req.exinf = NULL; reqcb->req.devid = DEVID(devcb, opncb->unitno); reqcb->req.cmd = cmd; reqcb->req.abort = FALSE; reqcb->req.start = start; reqcb->req.size = size; reqcb->req.buf = buf; reqcb->req.asize = 0; reqcb->req.error = 0; /* Indicate that it is during processing */ reqcb->tskid = tk_get_tid_impl(); UnlockDM(); /* Device driver call */ DISABLE_INTERRUPT; knl_ctxtsk->sysmode++; ENABLE_INTERRUPT; #if TA_GP ercd = CallDeviceDriver(&reqcb->req, tmout, exinf, 0, (FP)execfn, gp); #else ercd = (*execfn)(&reqcb->req, tmout, exinf); #endif DISABLE_INTERRUPT; knl_ctxtsk->sysmode--; ENABLE_INTERRUPT; LockDM(); /* Indicate that it is not during processing */ reqcb->tskid = 0; /* If there is an abort completion wait task, notify abort completion */ if ( opncb->abort_tskid > 0 && --opncb->abort_cnt == 0 ) { tk_sig_sem_impl(opncb->abort_semid, 1); } if ( ercd < E_OK ) { goto err_ret2; } UnlockDM(); return REQID(reqcb); err_ret2: knl_delReqCB(reqcb); err_ret1: UnlockDM(); DEBUG_PRINT(("knl_request ercd = %d\n", ercd)); return ercd; }
/* * Device close processing */ EXPORT ER knl_close_device( OpnCB *opncb, UINT option ) { CLSFN closefn; VP exinf; #if TA_GP VP gp; #endif ID devid; DevCB *devcb; INT unitno; ER ercd = E_OK; /* Abort all requests during processing */ abort_allrequest(opncb); LockDM(); devcb = opncb->devcb; unitno = opncb->unitno; closefn = (CLSFN)devcb->ddev.closefn; exinf = devcb->ddev.exinf; #if TA_GP gp = devcb->ddev.gp; #endif devid = DEVID(devcb, unitno); /* Delete semaphore for completion check of abortion */ tk_del_sem_impl(opncb->abort_semid); /* Free open management block */ knl_delOpnCB(opncb, FALSE); /* Is device driver call required? */ if ( knl_chkopen(devcb, unitno) ) { option &= ~TD_EJECT; if ( (devcb->ddev.drvatr & TDA_OPENREQ) == 0 ) { closefn = NULL; } } UnlockDM(); if ( closefn != NULL ) { /* Device driver call */ DISABLE_INTERRUPT; knl_ctxtsk->sysmode++; ENABLE_INTERRUPT; #if TA_GP ercd = CallDeviceDriver(devid, option, exinf, 0, (FP)closefn, gp); #else ercd = (*closefn)(devid, option, exinf); #endif DISABLE_INTERRUPT; knl_ctxtsk->sysmode--; ENABLE_INTERRUPT; } LockDM(); /* Return open management block to FreeQue */ QueInsert(&opncb->q, &knl_FreeOpnCB); UnlockDM(); #ifdef DEBUG if ( ercd < E_OK ) { DEBUG_PRINT(("knl_close_device ercd = %d\n", ercd)); } #endif return ercd; }
/* * Device open */ SYSCALL ID tk_opn_dev_impl( UB *devnm, UINT omode ) { OPNFN openfn; VP exinf; #if TA_GP VP gp; #endif UB pdevnm[L_DEVNM + 1]; INT unitno; ResCB *rescb; DevCB *devcb; OpnCB *opncb; ER ercd; ID semid; unitno = knl_phydevnm(pdevnm, devnm); /* Get resource management information */ rescb = knl_GetResCB(); if ( rescb == NULL ) { ercd = E_CTX; goto err_ret1; } LockDM(); /* Search device to open */ devcb = knl_searchDevCB(pdevnm); if ( devcb == NULL || unitno > devcb->ddev.nsub ) { ercd = E_NOEXS; goto err_ret2; } /* Check open mode */ ercd = chkopenmode(devcb, unitno, omode); if ( ercd < E_OK ) { goto err_ret2; } openfn = (OPNFN)devcb->ddev.openfn; exinf = devcb->ddev.exinf; #if TA_GP gp = devcb->ddev.gp; #endif /* Is device driver call required? */ if ( knl_chkopen(devcb, unitno) && (devcb->ddev.drvatr & TDA_OPENREQ) == 0 ) { openfn = NULL; } /* Get open management block */ opncb = newOpnCB(devcb, unitno, omode, rescb); if ( opncb == NULL ) { ercd = E_LIMIT; goto err_ret2; } semid = tk_cre_sem_impl(&knl_pk_csem_DM); if ( semid < E_OK ) { ercd = E_SYS; goto err_ret2_5; } opncb->abort_semid = semid; UnlockDM(); if ( openfn != NULL ) { /* Device driver call */ DISABLE_INTERRUPT; knl_ctxtsk->sysmode++; ENABLE_INTERRUPT; #if TA_GP ercd = CallDeviceDriver(DEVID(devcb, unitno), omode, exinf, 0, (FP)openfn, gp); #else ercd = (*openfn)(DEVID(devcb, unitno), omode, exinf); #endif DISABLE_INTERRUPT; knl_ctxtsk->sysmode--; ENABLE_INTERRUPT; if ( ercd < E_OK ) { goto err_ret3; } } LockDM(); opncb->resid = 1; /* Indicate that open processing is completed */ UnlockDM(); return DD(opncb); err_ret3: LockDM(); err_ret2_5: knl_delOpnCB(opncb, TRUE); err_ret2: UnlockDM(); err_ret1: DEBUG_PRINT(("tk_opn_dev_impl ercd = %d\n", ercd)); return ercd; }
/* * Request for starting input/output to device */ LOCAL ID request( ID dd, D start, void *buf, INT size, TMO_U tmout, INT cmd, enum ReqType syncreq ) { ATR drvatr; OpnCB *opncb; DevCB *devcb; ReqCB *reqcb; UINT m; ER ercd; LockDM(); /* Check whether there is a break request */ ercd = check_break(); if ( ercd < E_OK ) { goto err_ret1; } m = ( cmd == TDC_READ )? TD_READ: TD_WRITE; ercd = check_devdesc(dd, m, &opncb); if ( ercd < E_OK ) { goto err_ret1; } if ( syncreq == SyncReq ) { /* synchronous I/O is prohibited while there are pending I/O requests for completion */ if ( opncb->nwaireq > 0 ) { ercd = E_OBJ; goto err_ret1; } opncb->syncreq++; } devcb = opncb->devcb; drvatr = devcb->ddev.drvatr; /* check the range of parameter value */ if ( (drvatr & TDA_DEV_D) == 0 ) { if ( start > 0x7fffffff || start < (-0x7fffffff-1) ) { ercd = E_PAR; goto err_ret2; } } /* Get request management block */ reqcb = newReqCB(opncb); if ( reqcb == NULL ) { ercd = E_LIMIT; goto err_ret2; } /* Set request packet */ MEMSET(&reqcb->req, 0, sizeof(DEVREQ)); reqcb->req.c.devid = DEVID(devcb, opncb->unitno); reqcb->req.c.cmd = cmd; if ( (opncb->omode & TD_NOLOCK) != 0 ) { reqcb->req.c.nolock = TRUE; } if ( (drvatr & TDA_DEV_D) == 0 ) { reqcb->req.s.start = start; reqcb->req.s.size = size; reqcb->req.s.buf = buf; } else { reqcb->req.l.start_d = start; reqcb->req.l.size = size; reqcb->req.l.buf = buf; } ercd = tk_get_tsp(TSK_SELF, &reqcb->req.c.tskspc); if ( ercd < E_OK ) { goto err_ret3; } /* Indicate that it is during processing */ reqcb->tskid = tk_get_tid(); /* Device driver call */ UnlockDM(); ercd = call_execfn(devcb, &reqcb->req, tmout); LockDM(); LockDAbort(); /* Indicate that it is not during processing */ reqcb->tskid = 0; /* If there is an abort completion wait task, notify abort completion */ if ( opncb->abort_tskid > 0 && --opncb->abort_cnt == 0 ) { SyncSignalDM(opncb->abort_tskid); } UnlockDAbort(); if ( ercd < E_OK ) { goto err_ret3; } UnlockDM(); return REQID(reqcb); err_ret3: delReqCB(reqcb); err_ret2: if ( syncreq == SyncReq ) { opncb->syncreq--; } err_ret1: UnlockDM(); DEBUG_PRINT(("request ercd = %d\n", ercd)); return ercd; }
/* * Device open */ EXPORT ID _tk_opn_dev( CONST UB *devnm, UINT omode ) { UB pdevnm[L_DEVNM + 1]; INT unitno; ResCB *rescb; DevCB *devcb; OpnCB *opncb; WaitQ waiq; ER ercd; ercd = ChkSpaceBstrR(devnm, 0); if ( ercd < E_OK ) { goto err_ret1; } unitno = phydevnm(pdevnm, devnm); /* Get resource management information */ rescb = GetResCB(DEVICE_SVC, TSK_SELF); if ( rescb == NULL ) { ercd = E_CTX; goto err_ret1; } LockDM(); /* Search device to open */ devcb = searchDevCB(pdevnm); if ( devcb == NULL || unitno > devcb->ddev.nsub ) { ercd = E_NOEXS; goto err_ret2; } /* Check open mode */ ercd = chkopenmode(devcb, unitno, omode); if ( ercd < E_OK ) { goto err_ret2; } /* Get open management block */ opncb = newOpnCB(devcb, unitno, omode, rescb); if ( opncb == NULL ) { ercd = E_LIMIT; goto err_ret2; } /* Multiple tasks can initiate open/close processing, so ensure processing only by one task at a time. */ if ( enterSyncWait(&devcb->syncq, &waiq) ) { /* Wait for synchronization for concurrent open/close */ UnlockDM(); SyncWaitDM(); LockDM(); } /* Is device driver call required? */ if ( ! ( chkopen(devcb, unitno, opncb) && (devcb->ddev.drvatr & TDA_OPENREQ) == 0 ) ) { /* Device driver call */ UnlockDM(); ercd = call_openfn(devcb, DEVID(devcb, unitno), omode); LockDM(); if ( ercd < E_OK ) { goto err_ret3; } } opncb->resid = tk_get_rid(TSK_SELF); /* Indicate that open processing is completed */ /* Wake up task waiting for synchronization for concurrent open/close */ leaveSyncWait(&devcb->syncq, &waiq); UnlockDM(); return DD(opncb); err_ret3: delOpnCB(opncb); leaveSyncWait(&devcb->syncq, &waiq); err_ret2: UnlockDM(); err_ret1: DEBUG_PRINT(("_tk_opn_dev ercd = %d\n", ercd)); return ercd; }