M_COPYOUT Example
Note - Please see the copyout section in Writing Device Drivers for information
on the 64-bit data structure macros.
The following code excerpts return option values for the STREAMS device
by placing them in the user's options structure. This is
done by a transparent ioctl(2)
call of the form
struct options optadd;
ioctl(fd, GET_OPTIONS,(caddr_t) &optadd)
|
or by a nontransparent I_STR call
struct strioctl opts_strioctl;
structure options optadd;
opts_strioctl.ic_cmd = GET_OPTIONS;
opts_strioctl.ic_timeout = -1
opts_strioctl.ic_len = sizeof (struct options);
opts_strioctl.ic_dp = (char *)&optadd;
ioctl(fd, I_STR, (caddr_t) &opts_strioctl)
|
In the nontransparent I_STR case, opts_strioctl.ic_dp points to the options structure optadd.
Example 8-7 illustrates support of both the I_STR and transparent forms of ioctl(2). The transparent form requires a single M_COPYOUT message following receipt of the M_IOCTL
to copy out the contents of the structure. xxwput() is
the write-side put procedure of module or driver xx.
Example 8-10 M_COPYOUT
struct options { /* same members as in user space */
int op_one;
int op_two;
short op_three;
long op_four;
};
static int
xxwput (queue_t *q, mblk_t *mp)
{
struct iocblk *iocbp;
struct copyreq *cqp;
struct copyresp *csp;
int transparent = 0;
switch (mp->b_datap->db_type) {
.
.
.
case M_IOCTL:
iocbp = (struct iocblk *)mp->b_rptr;
switch (iocbp->ioc_cmd) {
case GET_OPTIONS:
if (iocbp->ioc_count == TRANSPARENT) {
transparent = 1;
cqp = (struct copyreq *)mp->b_rptr;
cqp->cq_size = sizeof(struct options);
/* Get struct address from
linked M_DATA block */
cqp->cq_addr = (caddr_t)
*(caddr_t *)mp->b_cont->b_rptr;
cqp->cq_flag = 0;
/* No state necessary - we will only ever
* get one M_IOCDATA from the Stream head
* indicating success or failure for
* the copyout */
}
if (mp->b_cont)
freemsg(mp->b_cont);
if ((mp->b_cont =
allocb(sizeof(struct options),
BPRI_MED)) == NULL) {
mp->b_datap->db_type = M_IOCNAK;
iocbp->ioc_error = EAGAIN;
qreply(q, mp);
break;
}
/* hypothetical routine */
xx_get_options(mp->b_cont);
if (transparent) {
mp->b_datap->db_type = M_COPYOUT;
mp->b_wptr = mp->b_rptr + sizeof(struct copyreq);
} else {
mp->b_datap->db_type = M_IOCACK;
iocbp->ioc_count = sizeof(struct options);
}
qreply(q, mp);
break;
default: /* M_IOCTL not for us */
/*if module, pass on;if driver, nak ioctl*/
break;
} /* switch (iocbp->ioc_cmd) */
break;
case M_IOCDATA:
csp = (struct copyresp *)mp->b_rptr;
/* M_IOCDATA not for us */
if (csp->cmd != GET_OPTIONS) {
/*if module/pass on, if driver/free message*/
break;
}
if ( csp->cp_rval ) {
freemsg(mp); /* failure */
return (0);
}
/* Data successfully copied out, ack */
/* reuse M_IOCDATA for ack */
mp->b_datap->db_type = M_IOCACK;
mp->b_wptr = mp->b_rptr + sizeof(struct iocblk);
/* can have been overwritten */
iocbp->ioc_error = 0;
iocbp->ioc_count = 0;
iocbp->ioc_rval = 0;
qreply(q, mp);
break;
.
.
.
} /* switch (mp->b_datap->db_type) */
return (0);
|
xxwput() first checks whether the ioctl(2) command is transparent. If
it is, the message is reused as an M_COPYOUT copy request
message. The pointer to the receiving buffer is in the linked message and
is copied into cq_addr. Because only a single copy out
is being done, no state information needs to be stored in cq_private. The original linked message is freed, in case it isn't big enough
to hold the request.
if (iocbp->ioc_count == TRANSPARENT) {
transparent = 1;
cqp = (struct copyreq *)mp->b_rptr;
cqp->cq_size = sizeof(struct options);
/* Get struct address from linked M_DATA block */
cqp->cq_addr = (caddr_t)
*(caddr_t *)mp->b_cont->b_rptr;
cqp->cq_flag = 0;
/* No state necessary - we will only ever get one
* M_IOCDATA from the Stream head indicating
* success or failure for the copyout */
}
if (mp->b_cont)
freemsg(mp->b_cont);
|