Please see copyout() section in the Writing Device Driversfor information on the 64-bit data structure macros.
Example 8-8 returns option values for this 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 an 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 I_STR case, opts_strioctl.ic_dp points to the options structure, optadd.
Example 8-8 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 copyout the contents of the structure. xxwput is the write-side put procedure of module or driver xx.
This example first checks if the ioctl(2) command is transparent [line 22]. If it is, the message is reused as an M_COPYOUT copy request message [lines 24-32]. The pointer to the receiving buffer is in the linked message and is copied into cq_addr [lines 26-27]. Since 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 [lines 32-33]. As an optimization, the following code checks the size of the message for reuse:
mp->;b_cont->b_datap->db_lim - mp->b_cont->b_datap->db_base >= sizeof (struct options) |
A new linked message is allocated to hold the option request [lines 32-40]. When using the transparent ioctl(2) the M_COPYOUT command data contained in the linked message is passed to the stream head. The stream head will copy the data to the user's address space and issue an M_IOCDATA in response to the M_COPYOUT message, which the module must acknowledge in a M_IOCACK message [lines 59-73]. ioc_error, ioc_count, and ioc_rval are cleared to prevent any stale data from being passed back to the stream head [lines 69-71].
If the message is not transparent (is issued through an I_STR ioctl(2)) the data is sent with the M_IOCACK acknowledgment message and copied into the buffer specified by the strioctl data structure [lines 50-51].
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);