Sun Microsystems, Inc.
spacerspacer
spacer www.sun.com docs.sun.com |
spacer
black dot
 
 
8.  STREAMS Kernel-Level Mechanisms General ioctl Processing Transparent ioctl Examples M_COPYIN Example  Previous   Contents   Next 
   
 

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);
 
 
 
  Previous   Contents   Next