/*ARGSUSED*/ static int telmodclose(queue_t *q, int flag, cred_t *credp) { struct telmod_info *tmip = (struct telmod_info *)q->q_ptr; mblk_t *mp; /* * Flush any write-side data downstream. Ignoring flow * control at this point is known to be safe because the * M_HANGUP below poisons the stream such that no modules can * be pushed again. */ while (mp = getq(WR(q))) putnext(WR(q), mp); /* Poison the stream head so that we can't be pushed again. */ (void) putnextctl(q, M_HANGUP); qprocsoff(q); if (tmip->wbufcid) { qunbufcall(q, tmip->wbufcid); tmip->wbufcid = 0; } if (tmip->rbufcid) { qunbufcall(q, tmip->rbufcid); tmip->rbufcid = 0; } if (tmip->wtimoutid) { (void) quntimeout(q, tmip->wtimoutid); tmip->wtimoutid = 0; } if (tmip->rtimoutid) { (void) quntimeout(q, tmip->rtimoutid); tmip->rtimoutid = 0; } if (tmip->unbind_mp != NULL) { freemsg(tmip->unbind_mp); } kmem_free(q->q_ptr, sizeof (struct telmod_info)); q->q_ptr = WR(q)->q_ptr = NULL; return (0); }
/* ARGSUSED */ int dm2s_close(queue_t *rq, int flag, cred_t *cred) { dm2s_t *dm2sp = (dm2s_t *)rq->q_ptr; DPRINTF(DBG_DRV, ("dm2s_close: called\n")); if (dm2sp == NULL) { /* Already closed once */ return (ENODEV); } /* Close the lower layer first */ mutex_enter(&dm2sp->ms_lock); (void) scf_mb_flush(dm2sp->ms_target, dm2sp->ms_key, MB_FLUSH_ALL); dm2s_mbox_fini(dm2sp); mutex_exit(&dm2sp->ms_lock); /* * Now we can assume that no asynchronous callbacks exist. * Poison the stream head so that we can't be pushed again. */ (void) putnextctl(rq, M_HANGUP); qprocsoff(rq); if (dm2sp->ms_rbufcid != 0) { qunbufcall(rq, dm2sp->ms_rbufcid); dm2sp->ms_rbufcid = 0; } if (dm2sp->ms_rq_timeoutid != 0) { DTRACE_PROBE1(dm2s_rqtimeout__cancel, dm2s_t, dm2sp); (void) quntimeout(dm2sp->ms_rq, dm2sp->ms_rq_timeoutid); dm2sp->ms_rq_timeoutid = 0; } if (dm2sp->ms_wq_timeoutid != 0) { DTRACE_PROBE1(dm2s_wqtimeout__cancel, dm2s_t, dm2sp); (void) quntimeout(dm2sp->ms_wq, dm2sp->ms_wq_timeoutid); dm2sp->ms_wq_timeoutid = 0; } /* * Now we can really mark it closed. */ mutex_enter(&dm2sp->ms_lock); dm2sp->ms_rq = dm2sp->ms_wq = NULL; dm2sp->ms_state &= ~DM2S_OPENED; mutex_exit(&dm2sp->ms_lock); rq->q_ptr = WR(rq)->q_ptr = NULL; (void) qassociate(rq, -1); DPRINTF(DBG_DRV, ("dm2s_close: successfully closed\n")); return (0); }
/*ARGSUSED*/ static int telmodopen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *credp) { struct telmod_info *tmip; mblk_t *bp; union T_primitives *tp; int error; if (sflag != MODOPEN) return (EINVAL); if (q->q_ptr != NULL) { /* It's already attached. */ return (0); } /* * Allocate state structure. */ tmip = kmem_zalloc(sizeof (*tmip), KM_SLEEP); /* * Cross-link. */ q->q_ptr = tmip; WR(q)->q_ptr = tmip; noenable(q); tmip->flags |= TEL_STOPPED; qprocson(q); /* * Since TCP operates in the TLI-inspired brain-dead fashion, * the connection will revert to bound state if the connection * is reset by the client. We must send a T_UNBIND_REQ in * that case so the port doesn't get "wedged" (preventing * inetd from being able to restart the listener). Allocate * it here, so that we don't need to worry about allocb() * failures later. */ while ((tmip->unbind_mp = allocb(sizeof (union T_primitives), BPRI_HI)) == NULL) { bufcall_id_t id = qbufcall(q, sizeof (union T_primitives), BPRI_HI, dummy_callback, NULL); if (!qwait_sig(q)) { qunbufcall(q, id); error = EINTR; goto fail; } qunbufcall(q, id); } tmip->unbind_mp->b_wptr = tmip->unbind_mp->b_rptr + sizeof (struct T_unbind_req); tmip->unbind_mp->b_datap->db_type = M_PROTO; tp = (union T_primitives *)tmip->unbind_mp->b_rptr; tp->type = T_UNBIND_REQ; /* * Send a M_PROTO msg of type T_DATA_REQ (this is unique for * read queue since only write queue can get T_DATA_REQ). * Readstream routine in telnet daemon will do a getmsg() till * it receives this proto message */ while ((bp = allocb(sizeof (union T_primitives), BPRI_HI)) == NULL) { bufcall_id_t id = qbufcall(q, sizeof (union T_primitives), BPRI_HI, dummy_callback, NULL); if (!qwait_sig(q)) { qunbufcall(q, id); error = EINTR; goto fail; } qunbufcall(q, id); } bp->b_datap->db_type = M_PROTO; bp->b_wptr = bp->b_rptr + sizeof (union T_primitives); tp = (union T_primitives *)bp->b_rptr; tp->type = T_DATA_REQ; tp->data_req.MORE_flag = 0; putnext(q, bp); return (0); fail: qprocsoff(q); if (tmip->unbind_mp != NULL) { freemsg(tmip->unbind_mp); } kmem_free(tmip, sizeof (struct telmod_info)); q->q_ptr = NULL; WR(q)->q_ptr = NULL; return (error); }
/*ARGSUSED*/ static int mouse8042_close(queue_t *q, int flag, cred_t *cred_p) { struct mouse_state *state; minor_t minor; state = (struct mouse_state *)q->q_ptr; /* * Disable queue processing now, so that another reset cannot get in * after we wait for the current reset (if any) to complete. */ qprocsoff(q); mutex_enter(&state->reset_mutex); while (state->reset_state != MSE_RESET_IDLE) { /* * Waiting for the previous reset to finish is * non-interruptible. Some upper-level clients * cannot deal with EINTR and will not close the * STREAM properly, resulting in failure to reopen it * within the same process. */ cv_wait(&state->reset_cv, &state->reset_mutex); } if (state->reset_tid != 0) { (void) quntimeout(q, state->reset_tid); state->reset_tid = 0; } if (state->reply_mp != NULL) { freemsg(state->reply_mp); state->reply_mp = NULL; } if (state->reset_ack_mp != NULL) { freemsg(state->reset_ack_mp); state->reset_ack_mp = NULL; } mutex_exit(&state->reset_mutex); mutex_enter(&state->ms_mutex); if (state->bc_id != 0) { (void) qunbufcall(q, state->bc_id); state->bc_id = 0; } q->q_ptr = NULL; WR(q)->q_ptr = NULL; state->ms_rqp = NULL; state->ms_wqp = NULL; state->ms_opened = B_FALSE; minor = state->ms_minor; mutex_exit(&state->ms_mutex); if (!MOUSE8042_INTERNAL_OPEN(minor)) { /* * Closing physical PS/2 mouse * * Link it back to virtual mouse, and * mouse8042_open will be called as a result * of the consconfig_link call. Do NOT try * this if the mouse is about to be detached! * * If linking back fails, this specific mouse * will not be available underneath the virtual * mouse, and can only be accessed via physical * open. */ consconfig_link(ddi_driver_major(mouse8042_dip), MOUSE8042_INTERNAL_MINOR(minor)); } return (0); }