#include <sys/types.h>
#include <sys/param.h>
#include <sys/stropts.h>
#include <sys/stream.h>
#include <sys/strsun.h>
#include <sys/conf.h>
#include <sys/stat.h>
#include <sys/errno.h>
#include <sys/modctl.h>
#include <sys/consdev.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
#include <sys/kstat.h>
#include <sys/vuid_wheel.h>
#include <sys/msio.h>
#include <sys/consms.h>
static void consms_plink(queue_t *, mblk_t *);
static int consms_punlink(queue_t *, mblk_t *);
static void
consms_lqs_ack_complete(consms_lq_t *, mblk_t *);
static void consms_add_lq(consms_lq_t *);
static void consms_check_caps(void);
static mblk_t *consms_new_firm_event(ushort_t, int);
static void consms_mux_max_wheel_report(mblk_t *);
static void consms_mux_cache_states(mblk_t *);
static void consms_mux_link_msg(consms_msg_t *);
static consms_msg_t *consms_mux_unlink_msg(uint_t);
static consms_msg_t *consms_mux_find_msg(uint_t);
static void consms_mux_iocdata(consms_msg_t *, mblk_t *);
static void consms_mux_disp_iocdata(consms_response_t *, mblk_t *);
static int consms_mux_disp_ioctl(queue_t *, mblk_t *);
static void consms_mux_copyreq(queue_t *, consms_msg_t *, mblk_t *);
static void consms_mux_ack(consms_msg_t *, mblk_t *);
static void consms_mux_disp_data(mblk_t *);
static int consmsopen(queue_t *, dev_t *, int, int, cred_t *);
static int consmsclose(queue_t *, int, cred_t *);
static int consmsuwput(queue_t *, mblk_t *);
static int consmslrput(queue_t *, mblk_t *);
static int consmslwserv(queue_t *);
static struct module_info consmsm_info = {
0,
"consms",
0,
1024,
2048,
128
};
static struct qinit consmsurinit = {
putq,
(int (*)())NULL,
consmsopen,
consmsclose,
(int (*)())NULL,
&consmsm_info,
NULL
};
static struct qinit consmsuwinit = {
consmsuwput,
(int (*)())NULL,
consmsopen,
consmsclose,
(int (*)())NULL,
&consmsm_info,
NULL
};
static struct qinit consmslrinit = {
consmslrput,
(int (*)())NULL,
(int (*)())NULL,
(int (*)())NULL,
(int (*)())NULL,
&consmsm_info,
NULL
};
static struct qinit consmslwinit = {
putq,
consmslwserv,
(int (*)())NULL,
(int (*)())NULL,
(int (*)())NULL,
&consmsm_info,
NULL
};
static struct streamtab consms_str_info = {
&consmsurinit,
&consmsuwinit,
&consmslrinit,
&consmslwinit,
};
static void consmsioctl(queue_t *q, mblk_t *mp);
static int consms_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
void **result);
static int consms_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
static int consms_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
static int consms_kstat_update(kstat_t *, int);
static queue_t *upperqueue;
static dev_info_t *consms_dip;
static long consms_idle_stamp;
static consms_msg_t *consms_mux_msg;
static kmutex_t consms_msg_lock;
static consms_state_t consms_state;
static kmutex_t consmslock;
static struct {
kstat_named_t idle_sec;
} consms_kstat = {
{ "idle_sec", KSTAT_DATA_LONG, }
};
static struct cb_ops cb_consms_ops = {
nulldev,
nulldev,
nodev,
nodev,
nodev,
nodev,
nodev,
nodev,
nodev,
nodev,
nodev,
nochpoll,
ddi_prop_op,
&consms_str_info,
D_MP | D_MTPERMOD
};
static struct dev_ops consms_ops = {
DEVO_REV,
0,
consms_info,
nulldev,
nulldev,
consms_attach,
consms_detach,
nodev,
&(cb_consms_ops),
(struct bus_ops *)NULL,
NULL,
ddi_quiesce_not_needed,
};
static struct modldrv modldrv = {
&mod_driverops,
"Mouse Driver for Sun 'consms' 5.57",
&consms_ops,
};
static struct modlinkage modlinkage = {
MODREV_1,
(void *)&modldrv,
NULL
};
int
_init(void)
{
int error;
mutex_init(&consmslock, NULL, MUTEX_DRIVER, NULL);
mutex_init(&consms_msg_lock, NULL, MUTEX_DRIVER, NULL);
error = mod_install(&modlinkage);
if (error != 0) {
mutex_destroy(&consmslock);
mutex_destroy(&consms_msg_lock);
}
return (error);
}
int
_fini(void)
{
int error;
error = mod_remove(&modlinkage);
if (error != 0)
return (error);
mutex_destroy(&consmslock);
mutex_destroy(&consms_msg_lock);
return (0);
}
int
_info(struct modinfo *modinfop)
{
return (mod_info(&modlinkage, modinfop));
}
static int
consms_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
{
kstat_t *ksp;
switch (cmd) {
case DDI_ATTACH:
break;
default:
return (DDI_FAILURE);
}
if (ddi_create_minor_node(devi, "mouse", S_IFCHR,
0, DDI_PSEUDO, 0) == DDI_FAILURE) {
ddi_remove_minor_node(devi, NULL);
return (-1);
}
consms_dip = devi;
(void) ddi_prop_update_int(DDI_DEV_T_NONE, devi, DDI_NO_AUTODETACH, 1);
ksp = kstat_create("consms", 0, "activity", "misc", KSTAT_TYPE_NAMED,
sizeof (consms_kstat) / sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL);
if (ksp) {
ksp->ks_data = (void *)&consms_kstat;
ksp->ks_update = consms_kstat_update;
kstat_install(ksp);
consms_idle_stamp = gethrestime_sec();
}
consms_state.consms_lqs = NULL;
consms_state.consms_num_lqs = 0;
consms_state.consms_vuid_format = VUID_FIRM_EVENT;
consms_state.consms_num_buttons = 0;
consms_state.consms_num_wheels = 0;
consms_state.consms_wheel_state_bf |= VUID_WHEEL_STATE_ENABLED;
consms_state.consms_ms_parms.jitter_thresh =
CONSMS_PARMS_DEFAULT_JITTER;
consms_state.consms_ms_parms.speed_limit =
CONSMS_PARMS_DEFAULT_SPEED_LIMIT;
consms_state.consms_ms_parms.speed_law =
CONSMS_PARMS_DEFAULT_SPEED_LAW;
consms_state.consms_ms_sr.height = CONSMS_SR_DEFAULT_HEIGHT;
consms_state.consms_ms_sr.width = CONSMS_SR_DEFAULT_WIDTH;
return (DDI_SUCCESS);
}
static int
consms_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
{
switch (cmd) {
case DDI_DETACH:
default:
return (DDI_FAILURE);
}
}
static int
consms_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
void **result)
{
int error;
switch (infocmd) {
case DDI_INFO_DEVT2DEVINFO:
if (consms_dip == NULL) {
error = DDI_FAILURE;
} else {
*result = (void *) consms_dip;
error = DDI_SUCCESS;
}
break;
case DDI_INFO_DEVT2INSTANCE:
*result = (void *)0;
error = DDI_SUCCESS;
break;
default:
error = DDI_FAILURE;
}
return (error);
}
static int
consmsopen(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp)
{
upperqueue = q;
qprocson(q);
return (0);
}
static int
consmsclose(queue_t *q, int flag, cred_t *crp)
{
qprocsoff(q);
upperqueue = NULL;
return (0);
}
static int
consmsuwput(queue_t *q, mblk_t *mp)
{
struct iocblk *iocbp = (struct iocblk *)mp->b_rptr;
consms_msg_t *msg;
int error = 0;
switch (mp->b_datap->db_type) {
case M_IOCTL:
consmsioctl(q, mp);
break;
case M_FLUSH:
if (*mp->b_rptr & FLUSHW)
flushq(q, FLUSHDATA);
if (*mp->b_rptr & FLUSHR)
flushq(RD(q), FLUSHDATA);
if (consms_state.consms_num_lqs > 0) {
consms_mux_disp_data(mp);
} else {
*mp->b_rptr &= ~FLUSHW;
if (*mp->b_rptr & FLUSHR)
qreply(q, mp);
else
freemsg(mp);
}
break;
case M_DATA:
if (consms_state.consms_num_lqs > 0) {
consms_mux_disp_data(mp);
} else {
freemsg(mp);
}
break;
case M_IOCDATA:
if ((msg = consms_mux_find_msg(iocbp->ioc_id)) != NULL) {
consms_mux_iocdata(msg, mp);
} else {
error = EINVAL;
}
break;
default:
error = EINVAL;
break;
}
if (error) {
mp->b_datap->db_type = M_ERROR;
if (mp->b_cont) {
freemsg(mp->b_cont);
mp->b_cont = NULL;
}
mp->b_rptr = mp->b_datap->db_base;
mp->b_wptr = mp->b_rptr + sizeof (char);
*mp->b_rptr = (char)error;
qreply(q, mp);
}
return (0);
}
static void
consmsioctl(queue_t *q, mblk_t *mp)
{
struct iocblk *iocp;
int error;
mblk_t *datap;
iocp = (struct iocblk *)mp->b_rptr;
switch (iocp->ioc_cmd) {
case I_LINK:
case I_PLINK:
mutex_enter(&consmslock);
consms_plink(q, mp);
mutex_exit(&consmslock);
return;
case I_UNLINK:
case I_PUNLINK:
mutex_enter(&consmslock);
if ((error = consms_punlink(q, mp)) != 0) {
mutex_exit(&consmslock);
miocnak(q, mp, 0, error);
return;
}
mutex_exit(&consmslock);
iocp->ioc_count = 0;
break;
case MSIOBUTTONS:
if ((consms_state.consms_num_lqs <= 0) ||
((datap = allocb(sizeof (int), BPRI_HI)) == NULL)) {
miocnak(q, mp, 0, ENOMEM);
return;
}
*(int *)datap->b_wptr = consms_state.consms_num_buttons;
datap->b_wptr += sizeof (int);
if (mp->b_cont) {
freemsg(mp->b_cont);
}
mp->b_cont = datap;
iocp->ioc_count = sizeof (int);
break;
default:
if (consms_state.consms_num_lqs <= 0) {
miocnak(q, mp, 0, EINVAL);
return;
}
if ((error = consms_mux_disp_ioctl(q, mp)) != 0)
miocnak(q, mp, 0, error);
return;
}
miocack(q, mp, iocp->ioc_count, 0);
}
static int
consmslwserv(queue_t *q)
{
mblk_t *mp;
while (canput(q->q_next) && (mp = getq(q)) != NULL)
putnext(q, mp);
return (0);
}
static int
consmslrput(queue_t *q, mblk_t *mp)
{
struct iocblk *iocbp = (struct iocblk *)mp->b_rptr;
struct copyreq *copyreq = (struct copyreq *)mp->b_rptr;
consms_msg_t *msg;
consms_lq_t *lq = (consms_lq_t *)q->q_ptr;
ASSERT(lq != NULL);
switch (mp->b_datap->db_type) {
case M_FLUSH:
if (*mp->b_rptr & FLUSHW)
flushq(WR(q), FLUSHDATA);
if (*mp->b_rptr & FLUSHR)
flushq(q, FLUSHDATA);
if (upperqueue != NULL)
putnext(upperqueue, mp);
else {
*mp->b_rptr &= ~FLUSHR;
if (*mp->b_rptr & FLUSHW)
qreply(q, mp);
else
freemsg(mp);
}
break;
case M_DATA:
if (upperqueue != NULL)
putnext(upperqueue, mp);
else
freemsg(mp);
consms_idle_stamp = gethrestime_sec();
break;
case M_IOCACK:
case M_IOCNAK:
if (lq->lq_ioc_reply_func != NULL) {
mutex_enter(&consmslock);
lq->lq_ioc_reply_func(lq, mp);
mutex_exit(&consmslock);
freemsg(mp);
break;
}
if ((msg = consms_mux_find_msg(iocbp->ioc_id)) != NULL) {
consms_mux_ack(msg, mp);
} else {
freemsg(mp);
}
consms_idle_stamp = gethrestime_sec();
break;
case M_COPYIN:
case M_COPYOUT:
if ((msg = consms_mux_find_msg(copyreq->cq_id)) != NULL) {
consms_mux_copyreq(q, msg, mp);
} else
freemsg(mp);
consms_idle_stamp = gethrestime_sec();
break;
case M_ERROR:
case M_HANGUP:
default:
freemsg(mp);
break;
}
return (0);
}
static int
consms_kstat_update(kstat_t *ksp, int rw)
{
if (rw == KSTAT_WRITE)
return (EACCES);
consms_kstat.idle_sec.value.l = gethrestime_sec() - consms_idle_stamp;
return (0);
}
static int
consms_punlink(queue_t *q, mblk_t *mp)
{
struct linkblk *linkp;
consms_lq_t *lq;
consms_lq_t *prev_lq;
ASSERT(MUTEX_HELD(&consmslock));
linkp = (struct linkblk *)mp->b_cont->b_rptr;
prev_lq = NULL;
for (lq = consms_state.consms_lqs; lq != NULL; lq = lq->lq_next) {
if (lq->lq_queue == linkp->l_qbot) {
if (prev_lq)
prev_lq->lq_next = lq->lq_next;
else
consms_state.consms_lqs = lq->lq_next;
kmem_free(lq, sizeof (*lq));
consms_state.consms_num_lqs--;
consms_check_caps();
return (0);
}
prev_lq = lq;
}
return (EINVAL);
}
static void
consms_plink(queue_t *q, mblk_t *mp)
{
struct linkblk *linkp;
consms_lq_t *lq;
queue_t *lowq;
ASSERT(MUTEX_HELD(&consmslock));
linkp = (struct linkblk *)mp->b_cont->b_rptr;
lowq = linkp->l_qbot;
lq = kmem_zalloc(sizeof (*lq), KM_SLEEP);
lowq->q_ptr = (void *)lq;
OTHERQ(lowq)->q_ptr = (void *)lq;
lq->lq_queue = lowq;
lq->lq_pending_plink = mp;
lq->lq_pending_queue = q;
lq->lq_num_buttons = 3;
lq->lq_state = LQS_START;
consms_lqs_ack_complete(lq, NULL);
}
static void
consms_lqs_ack_complete(consms_lq_t *lq, mblk_t *mp)
{
mblk_t *req = NULL;
boolean_t skipped = B_FALSE;
wheel_state *ws;
Ms_screen_resolution *sr;
Ms_parms *params;
ASSERT(MUTEX_HELD(&consmslock));
while ((lq->lq_state < LQS_DONE) && (req == NULL)) {
switch (lq->lq_state) {
case LQS_START:
req = mkiocb(MSIOBUTTONS);
if (req && ((req->b_cont = allocb(sizeof (int),
BPRI_MED)) == NULL)) {
freemsg(req);
req = NULL;
}
if (req == NULL)
skipped = B_TRUE;
lq->lq_state++;
break;
case LQS_BUTTON_COUNT_PENDING:
if (!skipped && mp && mp->b_cont &&
(mp->b_datap->db_type == M_IOCACK))
lq->lq_num_buttons =
*(int *)mp->b_cont->b_rptr;
req = mkiocb(VUIDGWHEELCOUNT);
if (req && ((req->b_cont = allocb(sizeof (int),
BPRI_MED)) == NULL)) {
freemsg(req);
req = NULL;
}
if (req == NULL)
skipped = B_TRUE;
lq->lq_state++;
break;
case LQS_WHEEL_COUNT_PENDING:
if (!skipped && mp && mp->b_cont &&
(mp->b_datap->db_type == M_IOCACK))
lq->lq_num_wheels =
*(int *)mp->b_cont->b_rptr;
req = mkiocb(VUIDSFORMAT);
if (req && ((req->b_cont = allocb(sizeof (int),
BPRI_MED)) == NULL)) {
freemsg(req);
req = NULL;
}
if (req) {
*(int *)req->b_cont->b_wptr =
consms_state.consms_vuid_format;
req->b_cont->b_wptr += sizeof (int);
}
lq->lq_state++;
break;
case LQS_SET_VUID_FORMAT_PENDING:
req = mkiocb(VUIDSWHEELSTATE);
if (req && ((req->b_cont = allocb(sizeof (wheel_state),
BPRI_MED)) == NULL)) {
freemsg(req);
req = NULL;
}
if (req) {
ws = (wheel_state *)req->b_cont->b_wptr;
ws->vers = VUID_WHEEL_STATE_VERS;
ws->id = 0;
ws->stateflags =
consms_state.consms_wheel_state_bf & 1;
req->b_cont->b_wptr += sizeof (wheel_state);
}
lq->lq_state++;
break;
case LQS_SET_WHEEL_STATE_PENDING:
req = mkiocb(MSIOSETPARMS);
if (req && ((req->b_cont = allocb(sizeof (Ms_parms),
BPRI_MED)) == NULL)) {
freemsg(req);
req = NULL;
}
if (req) {
params = (Ms_parms *)req->b_cont->b_wptr;
*params = consms_state.consms_ms_parms;
req->b_cont->b_wptr += sizeof (Ms_parms);
}
lq->lq_state++;
break;
case LQS_SET_PARMS_PENDING:
req = mkiocb(MSIOSRESOLUTION);
if (req && ((req->b_cont =
allocb(sizeof (Ms_screen_resolution),
BPRI_MED)) == NULL)) {
freemsg(req);
req = NULL;
}
if (req) {
sr =
(Ms_screen_resolution *)req->b_cont->b_wptr;
*sr = consms_state.consms_ms_sr;
req->b_cont->b_wptr +=
sizeof (Ms_screen_resolution);
}
lq->lq_state++;
break;
case LQS_SET_RESOLUTION_PENDING:
lq->lq_state++;
consms_add_lq(lq);
break;
}
}
if (lq->lq_state < LQS_DONE) {
lq->lq_ioc_reply_func = consms_lqs_ack_complete;
(void) putq(lq->lq_queue, req);
}
}
static void
consms_add_lq(consms_lq_t *lq)
{
struct iocblk *iocp;
ASSERT(MUTEX_HELD(&consmslock));
lq->lq_ioc_reply_func = NULL;
iocp = (struct iocblk *)lq->lq_pending_plink->b_rptr;
iocp->ioc_error = 0;
iocp->ioc_count = 0;
iocp->ioc_rval = 0;
lq->lq_pending_plink->b_datap->db_type = M_IOCACK;
qreply(lq->lq_pending_queue, lq->lq_pending_plink);
lq->lq_pending_plink = NULL;
lq->lq_pending_queue = NULL;
consms_state.consms_num_lqs++;
lq->lq_next = consms_state.consms_lqs;
consms_state.consms_lqs = lq;
consms_check_caps();
}
static void
consms_check_caps(void)
{
consms_lq_t *lq;
int max_buttons = 0;
int max_wheels = 0;
mblk_t *mp;
for (lq = consms_state.consms_lqs; lq != NULL; lq = lq->lq_next) {
max_buttons = CONSMS_MAX(max_buttons, lq->lq_num_buttons);
max_wheels = CONSMS_MAX(max_wheels, lq->lq_num_wheels);
}
if (max_buttons != consms_state.consms_num_buttons) {
consms_state.consms_num_buttons = max_buttons;
if (upperqueue != NULL) {
if ((mp = consms_new_firm_event(
MOUSE_CAP_CHANGE_NUM_BUT,
consms_state.consms_num_buttons)) != NULL) {
putnext(upperqueue, mp);
}
}
}
if (max_wheels != consms_state.consms_num_wheels) {
consms_state.consms_num_wheels = max_wheels;
if (upperqueue != NULL) {
if ((mp = consms_new_firm_event(
MOUSE_CAP_CHANGE_NUM_WHEEL,
consms_state.consms_num_wheels)) != NULL) {
putnext(upperqueue, mp);
}
}
}
}
static mblk_t *
consms_new_firm_event(ushort_t id, int value)
{
Firm_event *fep;
mblk_t *tmp;
if ((tmp = allocb(sizeof (Firm_event), BPRI_HI)) != NULL) {
fep = (Firm_event *)tmp->b_wptr;
fep->id = id;
fep->pair_type = FE_PAIR_NONE;
fep->pair = '\0';
fep->value = value;
tmp->b_wptr += sizeof (Firm_event);
}
return (tmp);
}
static void
consms_mux_link_msg(consms_msg_t *msg)
{
mutex_enter(&consms_msg_lock);
msg->msg_next = consms_mux_msg;
consms_mux_msg = msg;
mutex_exit(&consms_msg_lock);
}
static consms_msg_t *
consms_mux_unlink_msg(uint_t msg_id)
{
consms_msg_t *msg;
consms_msg_t *prev_msg;
mutex_enter(&consms_msg_lock);
prev_msg = NULL;
for (msg = consms_mux_msg; msg != NULL;
prev_msg = msg, msg = msg->msg_next) {
if (msg->msg_id == msg_id)
break;
}
if (msg != NULL) {
if (prev_msg != NULL) {
prev_msg->msg_next = msg->msg_next;
} else {
consms_mux_msg = consms_mux_msg->msg_next;
}
msg->msg_next = NULL;
}
mutex_exit(&consms_msg_lock);
return (msg);
}
static consms_msg_t *
consms_mux_find_msg(uint_t msg_id)
{
consms_msg_t *msg;
mutex_enter(&consms_msg_lock);
for (msg = consms_mux_msg; msg != NULL; msg = msg->msg_next) {
if (msg->msg_id == msg_id)
break;
}
mutex_exit(&consms_msg_lock);
return (msg);
}
static void
consms_mux_ack(consms_msg_t *msg, mblk_t *mp)
{
mblk_t *ack_mp;
msg->msg_num_responses++;
if (mp->b_datap->db_type == M_IOCACK) {
ASSERT(msg->msg_rsp_list == NULL);
if (msg->msg_ack_mp == NULL) {
msg->msg_ack_mp = mp;
mp = NULL;
}
}
if (msg->msg_num_responses == msg->msg_num_requests) {
if ((msg->msg_ack_mp == NULL) &&
(msg->msg_rsp_list == NULL)) {
ack_mp = mp;
mp = NULL;
} else if (msg->msg_rsp_list == NULL) {
ack_mp = msg->msg_ack_mp;
consms_mux_cache_states(msg->msg_request);
consms_mux_max_wheel_report(ack_mp);
} else {
ack_mp = msg->msg_rsp_list->rsp_mp;
consms_mux_max_wheel_report(ack_mp);
}
qreply(msg->msg_queue, ack_mp);
if (msg->msg_rsp_list == NULL) {
if (msg->msg_request)
freemsg(msg->msg_request);
(void) consms_mux_unlink_msg(msg->msg_id);
kmem_free(msg, sizeof (*msg));
}
}
if (mp) {
freemsg(mp);
}
}
static void
consms_mux_copyreq(queue_t *q, consms_msg_t *msg, mblk_t *mp)
{
consms_response_t *rsp;
rsp = (consms_response_t *)kmem_zalloc(sizeof (*rsp), KM_SLEEP);
rsp->rsp_mp = mp;
rsp->rsp_queue = q;
if (msg->msg_rsp_list) {
rsp->rsp_next = msg->msg_rsp_list;
}
msg->msg_rsp_list = rsp;
msg->msg_num_responses++;
if (msg->msg_num_responses == msg->msg_num_requests) {
consms_mux_max_wheel_report(msg->msg_rsp_list->rsp_mp);
qreply(msg->msg_queue, msg->msg_rsp_list->rsp_mp);
}
}
static void
consms_mux_disp_iocdata(consms_response_t *rsp, mblk_t *mp)
{
mblk_t *down_mp = rsp->rsp_mp;
struct copyresp *copyresp = (struct copyresp *)mp->b_rptr;
struct copyresp *newresp = (struct copyresp *)down_mp->b_rptr;
newresp->cp_rval = copyresp->cp_rval;
down_mp->b_datap->db_type = mp->b_datap->db_type;
if (down_mp->b_cont != NULL) {
freemsg(down_mp->b_cont);
down_mp->b_cont = NULL;
}
if (mp->b_cont != NULL) {
down_mp->b_cont = copymsg(mp->b_cont);
}
(void) putq(WR(rsp->rsp_queue), down_mp);
}
static void
consms_mux_iocdata(consms_msg_t *msg, mblk_t *mp)
{
consms_response_t *rsp;
consms_response_t *tmp;
consms_response_t *first;
struct copyresp *copyresp;
int request_nums;
ASSERT(msg->msg_rsp_list != NULL);
copyresp = (struct copyresp *)mp->b_rptr;
if ((copyresp->cp_cmd == VUIDSWHEELSTATE) ||
(copyresp->cp_cmd == MSIOSRESOLUTION)) {
freemsg(msg->msg_request);
msg->msg_request = copymsg(mp);
}
msg->msg_num_requests = msg->msg_num_responses;
msg->msg_num_responses = 0;
request_nums = 1;
first = msg->msg_rsp_list;
rsp = first->rsp_next;
msg->msg_rsp_list = NULL;
for (rsp = first->rsp_next; rsp != NULL; ) {
tmp = rsp;
rsp = rsp->rsp_next;
consms_mux_disp_iocdata(tmp, mp);
kmem_free(tmp, sizeof (*tmp));
request_nums++;
}
msg->msg_num_requests = request_nums;
(void) putq(WR(first->rsp_queue), mp);
kmem_free(first, sizeof (*first));
}
static void
consms_mux_max_wheel_report(mblk_t *mp)
{
struct iocblk *iocp;
int num_wheels;
if (mp == NULL || mp->b_cont == NULL)
return;
iocp = (struct iocblk *)mp->b_rptr;
if ((iocp->ioc_cmd == VUIDGWHEELCOUNT) &&
(mp->b_datap->db_type == M_COPYOUT)) {
num_wheels = *(int *)mp->b_cont->b_rptr;
if (num_wheels < consms_state.consms_num_wheels) {
*(int *)mp->b_cont->b_rptr =
consms_state.consms_num_wheels;
}
}
}
static void
consms_mux_cache_states(mblk_t *mp)
{
struct iocblk *iocp;
Ms_parms *parms;
Ms_screen_resolution *sr;
wheel_state *ws;
if (mp == NULL || mp->b_cont == NULL)
return;
iocp = (struct iocblk *)mp->b_rptr;
switch (iocp->ioc_cmd) {
case VUIDSFORMAT:
consms_state.consms_vuid_format = *(int *)mp->b_cont->b_rptr;
break;
case MSIOSETPARMS:
parms = (Ms_parms *)mp->b_cont->b_rptr;
consms_state.consms_ms_parms = *parms;
break;
case MSIOSRESOLUTION:
sr = (Ms_screen_resolution *)mp->b_cont->b_rptr;
consms_state.consms_ms_sr = *sr;
break;
case VUIDSWHEELSTATE:
ws = (wheel_state *)mp->b_cont->b_rptr;
consms_state.consms_wheel_state_bf =
(ws->stateflags << ws->id) |
(consms_state.consms_wheel_state_bf & ~(1 << ws->id));
break;
}
}
static int
consms_mux_disp_ioctl(queue_t *q, mblk_t *mp)
{
struct iocblk *iocp;
consms_msg_t *msg;
consms_lq_t *lq;
mblk_t *copy_mp;
int error = 0;
iocp = (struct iocblk *)mp->b_rptr;
msg = (consms_msg_t *)kmem_zalloc(sizeof (*msg), KM_SLEEP);
msg->msg_id = iocp->ioc_id;
msg->msg_request = mp;
msg->msg_queue = q;
msg->msg_num_requests = consms_state.consms_num_lqs;
consms_mux_link_msg(msg);
for (lq = consms_state.consms_lqs; lq != NULL; lq = lq->lq_next) {
if ((copy_mp = copymsg(mp)) != NULL) {
(void) putq(lq->lq_queue, copy_mp);
} else {
msg->msg_num_requests--;
}
}
if (msg->msg_num_requests <= 0) {
(void) consms_mux_unlink_msg(msg->msg_id);
kmem_free(msg, sizeof (*msg));
error = ENOMEM;
}
return (error);
}
static void
consms_mux_disp_data(mblk_t *mp)
{
consms_lq_t *lq;
mblk_t *copy_mp;
for (lq = consms_state.consms_lqs; lq != NULL; lq = lq->lq_next) {
if ((copy_mp = copymsg(mp)) != NULL) {
(void) putq(lq->lq_queue, copy_mp);
}
}
freemsg(mp);
}