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 Stream 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);