Пример #1
0
/*ARGSUSED*/
static int
lx_ptm_close(dev_t dev, int flag, int otyp, cred_t *credp)
{
	ldi_handle_t	lh;
	major_t		maj;
	minor_t		min, lastmin;
	uint_t		index;
	int		err;

	index = DEVT_TO_INDEX(dev);

	/*
	 * we must cleanup all the state associated with this major/minor
	 * terminal pair before actually closing the ptm master device.
	 * this is required because once the close of the ptm device is
	 * complete major/minor terminal pair is immediatly available for
	 * re-use in any zone.
	 */

	/* free up our saved reference for this layered handle */
	lh = lx_ptm_lh_remove(index);

	/* unconfigure autopush for the associated terminal slave device */
	maj = lps.lps_pts_major;
	min = index;
	lastmin = 0;
	do {
		/*
		 * we loop here because we don't want to release this ptm
		 * node if autopush can't be disabled on the associated
		 * slave device because then bad things could happen if
		 * another brand were to get this terminal allocated
		 * to them.
		 *
		 * XXX should we ever give up?
		 */
		err = kstr_autopush(CLR_AUTOPUSH, &maj, &min, &lastmin,
		    0, NULL);
	} while (err != 0);

	err = ldi_close(lh, flag, credp);

	/*
	 * note that we don't have to bother with changing the permissions
	 * on the associated slave device here.  the reason is that no one
	 * can actually open the device untill it's associated master
	 * device is re-opened, which will result in the permissions on
	 * it being reset.
	 */
	return (err);
}
Пример #2
0
/*ARGSUSED1*/
static int
zc_close(queue_t *rqp, int flag, cred_t *credp)
{
	queue_t *wqp;
	mblk_t	*bp;
	zc_state_t *zcs;
	major_t major;
	minor_t minor;

	zcs = (zc_state_t *)rqp->q_ptr;

	if (rqp == zcs->zc_master_rdq) {
		DBG("Closing master side");

		zcs->zc_master_rdq = NULL;
		zcs->zc_state &= ~ZC_STATE_MOPEN;

		/*
		 * qenable slave side write queue so that it can flush
		 * its messages as master's read queue is going away
		 */
		if (zcs->zc_slave_rdq != NULL) {
			qenable(WR(zcs->zc_slave_rdq));
		}

		qprocsoff(rqp);
		WR(rqp)->q_ptr = rqp->q_ptr = NULL;

	} else if (rqp == zcs->zc_slave_rdq) {

		DBG("Closing slave side");
		zcs->zc_state &= ~ZC_STATE_SOPEN;
		zcs->zc_slave_rdq = NULL;

		wqp = WR(rqp);
		while ((bp = getq(wqp)) != NULL) {
			if (zcs->zc_master_rdq != NULL)
				putnext(zcs->zc_master_rdq, bp);
			else if (bp->b_datap->db_type == M_IOCTL)
				miocnak(wqp, bp, 0, 0);
			else
				freemsg(bp);
		}

		/*
		 * Qenable master side write queue so that it can flush its
		 * messages as slaves's read queue is going away.
		 */
		if (zcs->zc_master_rdq != NULL)
			qenable(WR(zcs->zc_master_rdq));

		qprocsoff(rqp);
		WR(rqp)->q_ptr = rqp->q_ptr = NULL;

		/*
		 * Clear the sad configuration so that reopening doesn't fail
		 * to set up sad configuration.
		 */
		major = ddi_driver_major(zcs->zc_devinfo);
		minor = ddi_get_instance(zcs->zc_devinfo) << 1 | ZC_SLAVE_MINOR;
		(void) kstr_autopush(CLR_AUTOPUSH, &major, &minor, NULL, NULL,
		    NULL);
	}

	return (0);
}
Пример #3
0
/*ARGSUSED*/
static int
zc_slave_open(zc_state_t *zcs,
    queue_t	*rqp,	/* pointer to the read side queue */
    dev_t	*devp,	/* pointer to stream tail's dev */
    int		oflag,	/* the user open(2) supplied flags */
    int		sflag,	/* open state flag */
    cred_t	*credp)	/* credentials */
{
	mblk_t *mop;
	struct stroptions *sop;
	major_t major;
	minor_t minor;
	minor_t lastminor;
	uint_t anchorindex;

	/*
	 * The slave side can be opened as many times as needed.
	 */
	if ((zcs->zc_state & ZC_STATE_SOPEN) != 0) {
		ASSERT((rqp != NULL) && (WR(rqp)->q_ptr == zcs));
		return (0);
	}

	/*
	 * Set up sad(7D) so that the necessary STREAMS modules will be in
	 * place.  A wrinkle is that 'ptem' must be anchored
	 * in place (see streamio(7i)) because we always want the console to
	 * have terminal semantics.
	 */
	minor = ddi_get_instance(zcs->zc_devinfo) << 1 | ZC_SLAVE_MINOR;
	major = ddi_driver_major(zcs->zc_devinfo);
	lastminor = 0;
	anchorindex = 1;
	if (kstr_autopush(SET_AUTOPUSH, &major, &minor, &lastminor,
	    &anchorindex, zcons_mods) != 0) {
		DBG("zc_slave_open(): kstr_autopush() failed\n");
		return (EIO);
	}

	if ((mop = allocb(sizeof (struct stroptions), BPRI_MED)) == NULL) {
		DBG("zc_slave_open(): mop allocation failed\n");
		return (ENOMEM);
	}

	zcs->zc_state |= ZC_STATE_SOPEN;

	/*
	 * q_ptr stores driver private data; stash the soft state data on both
	 * read and write sides of the queue.
	 */
	WR(rqp)->q_ptr = rqp->q_ptr = zcs;

	qprocson(rqp);

	/*
	 * Must follow qprocson(), since we aren't ready to process until then.
	 */
	zcs->zc_slave_rdq = rqp;

	/*
	 * set up hi/lo water marks on stream head read queue and add
	 * controlling tty as needed.
	 */
	mop->b_datap->db_type = M_SETOPTS;
	mop->b_wptr += sizeof (struct stroptions);
	sop = (struct stroptions *)(void *)mop->b_rptr;
	sop->so_flags = SO_HIWAT | SO_LOWAT | SO_ISTTY;
	sop->so_hiwat = _TTY_BUFSIZ;
	sop->so_lowat = 256;
	putnext(rqp, mop);

	return (0);
}
Пример #4
0
/*ARGSUSED*/
static int
lx_ptm_open(dev_t *devp, int flag, int otyp, cred_t *credp)
{
	struct strioctl	iocb;
	ptmptsopencb_t	ppocb = { NULL, NULL };
	ldi_handle_t	lh;
	major_t		maj, our_major = getmajor(*devp);
	minor_t		min, lastmin;
	uint_t		index, anchor = 1;
	dev_t		ptm_dev;
	int		err, rval = 0;

	/*
	 * Don't support the FNDELAY flag and FNONBLOCK until we either
	 * find a Linux app that opens /dev/ptmx with the O_NDELAY
	 * or O_NONBLOCK flags explicitly, or until we create test cases
	 * to determine how reads of master terminal devices opened with
	 * these flags behave in different situations on Linux.  Supporting
	 * these flags will involve enhancing our read implementation
	 * and changing the way it deals with EOF notifications.
	 */
	if (flag & (FNDELAY | FNONBLOCK))
		return (ENOTSUP);

	/*
	 * we're layered on top of the ptm driver so open that driver
	 * first.  (note that we're opening /dev/ptmx in the global
	 * zone, not ourselves in the Linux zone.)
	 */
	err = ldi_open_by_name(LP_PTM_PATH, flag, credp, &lh, lps.lps_li);
	if (err != 0)
		return (err);

	/* get the devt returned by the ptmx open */
	err = ldi_get_dev(lh, &ptm_dev);
	if (err != 0) {
		(void) ldi_close(lh, flag, credp);
		return (err);
	}

	/*
	 * we're a cloning driver so here's well change the devt that we
	 * return.  the ptmx is also a cloning driver so we'll just use
	 * it's minor number as our minor number (it already manages it's
	 * minor name space so no reason to duplicate the effort.)
	 */
	index = getminor(ptm_dev);
	*devp = makedevice(our_major, INDEX_TO_MINOR(index));

	/* Get a callback function to query if the pts device is open. */
	iocb.ic_cmd = PTMPTSOPENCB;
	iocb.ic_timout = 0;
	iocb.ic_len = sizeof (ppocb);
	iocb.ic_dp = (char *)&ppocb;

	err = ldi_ioctl(lh, I_STR, (intptr_t)&iocb, FKIOCTL, kcred, &rval);
	if ((err != 0) || (rval != 0)) {
		(void) ldi_close(lh, flag, credp);
		return (EIO); /* XXX return something else here? */
	}
	ASSERT(ppocb.ppocb_func != NULL);

	/*
	 * now setup autopush for the terminal slave device.  this is
	 * necessary so that when a Linux program opens the device we
	 * can push required strmod modules onto the stream.  in Solaris
	 * this is normally done by the application that actually
	 * allocates the terminal.
	 */
	maj = lps.lps_pts_major;
	min = index;
	lastmin = 0;
	err = kstr_autopush(SET_AUTOPUSH, &maj, &min, &lastmin,
	    &anchor, lx_pts_mods);
	if (err != 0) {
		(void) ldi_close(lh, flag, credp);
		return (EIO); /* XXX return something else here? */
	}

	/* save off this layered handle for future accesses */
	lx_ptm_lh_insert(index, lh);
	lx_ptm_lh_set_ppocb(index, &ppocb);
	return (0);
}