/* 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 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); }
/* * dm2s_wsrv - Streams write side service procedure. * * All messages are transmitted in the service procedure * only. This is done to simplify the streams synchronization. */ int dm2s_wsrv(queue_t *wq) { dm2s_t *dm2sp = (dm2s_t *)wq->q_ptr; DPRINTF(DBG_DRV, ("dm2s_wsrv: called\n")); ASSERT(dm2sp != NULL); /* Lets cancel any timeouts waiting to be scheduled. */ 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; } mutex_enter(&dm2sp->ms_lock); dm2s_start(wq, dm2sp); mutex_exit(&dm2sp->ms_lock); DPRINTF(DBG_DRV, ("dm2s_wsrv: return\n")); return (0); }
static uint_t mouse8042_intr(caddr_t arg) { unsigned char mdata; mblk_t *mp; struct mouse_state *state = (struct mouse_state *)arg; int rc; mutex_enter(&state->ms_mutex); rc = DDI_INTR_UNCLAIMED; for (;;) { if (ddi_get8(state->ms_handle, state->ms_addr + I8042_INT_INPUT_AVAIL) == 0) { break; } mdata = ddi_get8(state->ms_handle, state->ms_addr + I8042_INT_INPUT_DATA); rc = DDI_INTR_CLAIMED; /* * If we're not ready for this data, discard it. */ if (!state->ready) continue; mutex_enter(&state->reset_mutex); if (state->reset_state != MSE_RESET_IDLE) { if (mdata == MSEERROR || mdata == MSERESET) { state->reset_state = MSE_RESET_FAILED; } else { state->reset_state = mouse8042_reset_fsm(state->reset_state, mdata); } if (state->reset_state == MSE_RESET_ACK) { /* * We received an ACK from the mouse, so * send it upstream immediately so that * consumers depending on the immediate * ACK don't time out. */ if (state->reset_ack_mp != NULL) { mp = state->reset_ack_mp; state->reset_ack_mp = NULL; if (state->ms_rqp != NULL) { *mp->b_wptr++ = MSE_ACK; putnext(state->ms_rqp, mp); } else freemsg(mp); } if (state->ms_wqp != NULL) { enableok(state->ms_wqp); qenable(state->ms_wqp); } } else if (state->reset_state == MSE_RESET_IDLE || state->reset_state == MSE_RESET_FAILED) { /* * If we transitioned back to the idle reset state (or * the reset failed), disable the timeout, release the * 8042 exclusive-access lock, then send the response * the the upper-level modules. Finally, enable the * queue and schedule queue service procedures so that * upper-level modules can process the response. * Otherwise, if we're still in the middle of the * reset sequence, do not send the data up (since the * response is sent at the end of the sequence, or * on timeout/error). */ mutex_exit(&state->reset_mutex); (void) quntimeout(state->ms_wqp, state->reset_tid); mutex_enter(&state->reset_mutex); (void) ddi_get8(state->ms_handle, state->ms_addr + I8042_UNLOCK); state->reset_tid = 0; if (state->reply_mp != NULL) { mp = state->reply_mp; if (state->reset_state == MSE_RESET_FAILED) { *mp->b_wptr++ = mdata; } else { *mp->b_wptr++ = MSE_AA; *mp->b_wptr++ = MSE_00; } state->reply_mp = NULL; } else { mp = NULL; } state->reset_state = MSE_RESET_IDLE; cv_signal(&state->reset_cv); if (mp != NULL) { if (state->ms_rqp != NULL) putnext(state->ms_rqp, mp); else freemsg(mp); } if (state->ms_wqp != NULL) { enableok(state->ms_wqp); qenable(state->ms_wqp); } } mutex_exit(&state->reset_mutex); mutex_exit(&state->ms_mutex); return (rc); } mutex_exit(&state->reset_mutex); if (state->ms_rqp != NULL && (mp = allocb(1, BPRI_MED))) { *mp->b_wptr++ = mdata; putnext(state->ms_rqp, mp); } } mutex_exit(&state->ms_mutex); return (rc); }
/*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); }