1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21/*
22 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23 * Use is subject to license terms.
24 */
25/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
26/*	  All Rights Reserved  	*/
27
28
29
30/*
31 * Pseudo Terminal Slave Driver.
32 *
33 * The pseudo-tty subsystem simulates a terminal connection, where the master
34 * side represents the terminal and the slave represents the user process's
35 * special device end point. The master device is set up as a cloned device
36 * where its major device number is the major for the clone device and its minor
37 * device number is the major for the ptm driver. There are no nodes in the file
38 * system for master devices. The master pseudo driver is opened using the
39 * open(2) system call with /dev/ptmx as the device parameter.  The clone open
40 * finds the next available minor device for the ptm major device.
41 *
42 * A master device is available only if it and its corresponding slave device
43 * are not already open. When the master device is opened, the corresponding
44 * slave device is automatically locked out. Only one open is allowed on a
45 * master device.  Multiple opens are allowed on the slave device.  After both
46 * the master and slave have been opened, the user has two file descriptors
47 * which are the end points of a full duplex connection composed of two streams
48 * which are automatically connected at the master and slave drivers. The user
49 * may then push modules onto either side of the stream pair.
50 *
51 * The master and slave drivers pass all messages to their adjacent queues.
52 * Only the M_FLUSH needs some processing.  Because the read queue of one side
53 * is connected to the write queue of the other, the FLUSHR flag is changed to
54 * the FLUSHW flag and vice versa. When the master device is closed an M_HANGUP
55 * message is sent to the slave device which will render the device
56 * unusable. The process on the slave side gets the EIO when attempting to write
57 * on that stream but it will be able to read any data remaining on the stream
58 * head read queue.  When all the data has been read, read() returns 0
59 * indicating that the stream can no longer be used.  On the last close of the
60 * slave device, a 0-length message is sent to the master device. When the
61 * application on the master side issues a read() or getmsg() and 0 is returned,
62 * the user of the master device decides whether to issue a close() that
63 * dismantles the pseudo-terminal subsystem. If the master device is not closed,
64 * the pseudo-tty subsystem will be available to another user to open the slave
65 * device.
66 *
67 * Synchronization:
68 *
69 *   All global data synchronization between ptm/pts is done via global
70 *   ptms_lock mutex which is initialized at system boot time from
71 *   ptms_initspace (called from space.c).
72 *
73 *   Individual fields of pt_ttys structure (except ptm_rdq, pts_rdq and
74 *   pt_nullmsg) are protected by pt_ttys.pt_lock mutex.
75 *
76 *   PT_ENTER_READ/PT_ENTER_WRITE are reference counter based read-write locks
77 *   which allow reader locks to be reacquired by the same thread (usual
78 *   reader/writer locks can't be used for that purpose since it is illegal for
79 *   a thread to acquire a lock it already holds, even as a reader). The sole
80 *   purpose of these macros is to guarantee that the peer queue will not
81 *   disappear (due to closing peer) while it is used. It is safe to use
82 *   PT_ENTER_READ/PT_EXIT_READ brackets across calls like putq/putnext (since
83 *   they are not real locks but reference counts).
84 *
85 *   PT_ENTER_WRITE/PT_EXIT_WRITE brackets are used ONLY in master/slave
86 *   open/close paths to modify ptm_rdq and pts_rdq fields. These fields should
87 *   be set to appropriate queues *after* qprocson() is called during open (to
88 *   prevent peer from accessing the queue with incomplete plumbing) and set to
89 *   NULL before qprocsoff() is called during close.
90 *
91 *   The pt_nullmsg field is only used in open/close routines and it is also
92 *   protected by PT_ENTER_WRITE/PT_EXIT_WRITE brackets to avoid extra mutex
93 *   holds.
94 *
95 * Lock Ordering:
96 *
97 *   If both ptms_lock and per-pty lock should be held, ptms_lock should always
98 *   be entered first, followed by per-pty lock.
99 *
100 * See ptms.h, ptm.c and ptms_conf.c fore more information.
101 *
102 */
103
104#include <sys/types.h>
105#include <sys/param.h>
106#include <sys/sysmacros.h>
107#include <sys/stream.h>
108#include <sys/stropts.h>
109#include <sys/stat.h>
110#include <sys/errno.h>
111#include <sys/debug.h>
112#include <sys/cmn_err.h>
113#include <sys/ptms.h>
114#include <sys/systm.h>
115#include <sys/modctl.h>
116#include <sys/conf.h>
117#include <sys/ddi.h>
118#include <sys/sunddi.h>
119#include <sys/cred.h>
120#include <sys/zone.h>
121
122#ifdef DEBUG
123int pts_debug = 0;
124#define	DBG(a)	 if (pts_debug) cmn_err(CE_NOTE, a)
125#else
126#define	DBG(a)
127#endif
128
129static int ptsopen(queue_t *, dev_t *, int, int, cred_t *);
130static int ptsclose(queue_t *, int, cred_t *);
131static void ptswput(queue_t *, mblk_t *);
132static void ptsrsrv(queue_t *);
133static void ptswsrv(queue_t *);
134
135/*
136 * Slave Stream Pseudo Terminal Module: stream data structure definitions
137 */
138static struct module_info pts_info = {
139	0xface,
140	"pts",
141	0,
142	512,
143	512,
144	128
145};
146
147static struct qinit ptsrint = {
148	NULL,
149	(int (*)()) ptsrsrv,
150	ptsopen,
151	ptsclose,
152	NULL,
153	&pts_info,
154	NULL
155};
156
157static struct qinit ptswint = {
158	(int (*)()) ptswput,
159	(int (*)()) ptswsrv,
160	NULL,
161	NULL,
162	NULL,
163	&pts_info,
164	NULL
165};
166
167static struct streamtab ptsinfo = {
168	&ptsrint,
169	&ptswint,
170	NULL,
171	NULL
172};
173
174static int pts_devinfo(dev_info_t *, ddi_info_cmd_t, void *, void **);
175static int pts_attach(dev_info_t *, ddi_attach_cmd_t);
176static int pts_detach(dev_info_t *, ddi_detach_cmd_t);
177
178#define	PTS_CONF_FLAG	(D_NEW | D_MP)
179
180/*
181 * this will define (struct cb_ops cb_pts_ops) and (struct dev_ops pts_ops)
182 */
183DDI_DEFINE_STREAM_OPS(pts_ops, nulldev, nulldev,	\
184	pts_attach, pts_detach, nodev,			\
185	pts_devinfo, PTS_CONF_FLAG, &ptsinfo, ddi_quiesce_not_supported);
186
187/*
188 * Module linkage information for the kernel.
189 */
190
191static struct modldrv modldrv = {
192	&mod_driverops, /* Type of module.  This one is a pseudo driver */
193	"Slave Stream Pseudo Terminal driver 'pts'",
194	&pts_ops,	/* driver ops */
195};
196
197static struct modlinkage modlinkage = {
198	MODREV_1,
199	&modldrv,
200	NULL
201};
202
203int
204_init(void)
205{
206	int rc;
207
208	if ((rc = mod_install(&modlinkage)) == 0)
209		ptms_init();
210	return (rc);
211}
212
213
214int
215_fini(void)
216{
217	return (mod_remove(&modlinkage));
218}
219
220int
221_info(struct modinfo *modinfop)
222{
223	return (mod_info(&modlinkage, modinfop));
224}
225
226static int
227pts_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
228{
229	if (cmd != DDI_ATTACH)
230		return (DDI_FAILURE);
231
232	mutex_enter(&ptms_lock);
233	pts_dip = devi;
234	mutex_exit(&ptms_lock);
235
236	return (DDI_SUCCESS);
237}
238
239/*ARGSUSED*/
240static int
241pts_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
242{
243	if (cmd != DDI_DETACH)
244		return (DDI_FAILURE);
245
246	/*
247	 * For now, pts cannot be detached.
248	 */
249	return (DDI_FAILURE);
250}
251
252/*ARGSUSED*/
253static int
254pts_devinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
255    void **result)
256{
257	int error;
258
259	switch (infocmd) {
260	case DDI_INFO_DEVT2DEVINFO:
261		if (pts_dip == NULL) {
262			error = DDI_FAILURE;
263		} else {
264			*result = (void *)pts_dip;
265			error = DDI_SUCCESS;
266		}
267		break;
268	case DDI_INFO_DEVT2INSTANCE:
269		*result = (void *)0;
270		error = DDI_SUCCESS;
271		break;
272	default:
273		error = DDI_FAILURE;
274	}
275	return (error);
276}
277
278/* ARGSUSED */
279/*
280 * Open the slave device. Reject a clone open and do not allow the
281 * driver to be pushed. If the slave/master pair is locked or if
282 * the master is not open, return EACCESS.
283 * Upon success, store the write queue pointer in private data and
284 * set the PTSOPEN bit in the pt_state field.
285 */
286static int
287ptsopen(
288	queue_t *rqp,		/* pointer to the read side queue */
289	dev_t   *devp,		/* pointer to stream tail's dev */
290	int	oflag,		/* the user open(2) supplied flags */
291	int	sflag,		/* open state flag */
292	cred_t  *credp)		/* credentials */
293{
294	struct pt_ttys	*ptsp;
295	mblk_t		*mp;
296	mblk_t		*mop;	/* ptr to a setopts message block */
297	minor_t		dminor = getminor(*devp);
298	struct stroptions *sop;
299
300	DDBG("entering ptsopen(%d)", dminor);
301
302	if (sflag != 0) {
303		return (EINVAL);
304	}
305
306	mutex_enter(&ptms_lock);
307	ptsp = ptms_minor2ptty(dminor);
308
309	if (ptsp == NULL) {
310		mutex_exit(&ptms_lock);
311		return (ENXIO);
312	}
313	mutex_enter(&ptsp->pt_lock);
314
315	/*
316	 * Prevent opens from zones other than the one blessed by ptm.  We
317	 * can't even allow the global zone to open all pts's, as it would
318	 * otherwise inproperly be able to claim pts's already opened by zones.
319	 */
320	if (ptsp->pt_zoneid != getzoneid()) {
321		mutex_exit(&ptsp->pt_lock);
322		mutex_exit(&ptms_lock);
323		return (EPERM);
324	}
325
326	/*
327	 * Allow reopen of this device.
328	 */
329	if (rqp->q_ptr != NULL) {
330		ASSERT(rqp->q_ptr == ptsp);
331		ASSERT(ptsp->pts_rdq == rqp);
332		mutex_exit(&ptsp->pt_lock);
333		mutex_exit(&ptms_lock);
334		return (0);
335	}
336
337	DDBGP("ptsopen: p = %p\n", (uintptr_t)ptsp);
338	DDBG("ptsopen: state = %x\n", ptsp->pt_state);
339
340
341	ASSERT(ptsp->pt_minor == dminor);
342
343	if ((ptsp->pt_state & PTLOCK) || !(ptsp->pt_state & PTMOPEN)) {
344		mutex_exit(&ptsp->pt_lock);
345		mutex_exit(&ptms_lock);
346		return (EAGAIN);
347	}
348
349	/*
350	 * if already, open simply return...
351	 */
352	if (ptsp->pt_state & PTSOPEN) {
353		ASSERT(rqp->q_ptr == ptsp);
354		ASSERT(ptsp->pts_rdq == rqp);
355		mutex_exit(&ptsp->pt_lock);
356		mutex_exit(&ptms_lock);
357		return (0);
358	}
359
360	/*
361	 * Allocate message block for setting stream head options.
362	 */
363	if ((mop = allocb(sizeof (struct stroptions), BPRI_MED)) == NULL) {
364		mutex_exit(&ptsp->pt_lock);
365		mutex_exit(&ptms_lock);
366		return (ENOMEM);
367	}
368
369	/*
370	 * Slave should send zero-length message to a master when it is
371	 * closing. If memory is low at that time, master will not detect slave
372	 * closes, this pty will not be deallocated. So, preallocate this
373	 * zero-length message block early.
374	 */
375	if ((mp = allocb(0, BPRI_MED)) == NULL) {
376		mutex_exit(&ptsp->pt_lock);
377		mutex_exit(&ptms_lock);
378		freemsg(mop);
379		return (ENOMEM);
380	}
381
382	ptsp->pt_state |= PTSOPEN;
383
384	WR(rqp)->q_ptr = rqp->q_ptr = ptsp;
385
386	mutex_exit(&ptsp->pt_lock);
387	mutex_exit(&ptms_lock);
388
389	qprocson(rqp);
390
391	/*
392	 * After qprocson pts driver is fully plumbed into the stream and can
393	 * send/receive messages. Setting pts_rdq will allow master side to send
394	 * messages to the slave. This setting can't occur before qprocson() is
395	 * finished because slave is not ready to process them.
396	 */
397	PT_ENTER_WRITE(ptsp);
398	ptsp->pts_rdq = rqp;
399	ASSERT(ptsp->pt_nullmsg == NULL);
400	ptsp->pt_nullmsg = mp;
401	PT_EXIT_WRITE(ptsp);
402
403	/*
404	 * set up hi/lo water marks on stream head read queue
405	 * and add controlling tty if not set
406	 */
407
408	mop->b_datap->db_type = M_SETOPTS;
409	mop->b_wptr += sizeof (struct stroptions);
410	sop = (struct stroptions *)mop->b_rptr;
411	sop->so_flags = SO_HIWAT | SO_LOWAT | SO_ISTTY;
412	sop->so_hiwat = 512;
413	sop->so_lowat = 256;
414	putnext(rqp, mop);
415
416	return (0);
417}
418
419
420
421/*
422 * Find the address to private data identifying the slave's write
423 * queue. Send a 0-length msg up the slave's read queue to designate
424 * the master is closing. Uattach the master from the slave by nulling
425 * out master's write queue field in private data.
426 */
427/*ARGSUSED1*/
428static int
429ptsclose(queue_t *rqp, int flag, cred_t *credp)
430{
431	struct pt_ttys	*ptsp;
432	queue_t *wqp;
433	mblk_t	*mp;
434	mblk_t	*bp;
435
436	/*
437	 * q_ptr should never be NULL in the close routine and it is checked in
438	 * DEBUG kernel by ASSERT. For non-DEBUG kernel the attempt is made to
439	 * behave gracefully.
440	 */
441	ASSERT(rqp->q_ptr != NULL);
442	if (rqp->q_ptr == NULL) {
443		qprocsoff(rqp);
444		return (0);
445	}
446
447	ptsp = (struct pt_ttys *)rqp->q_ptr;
448
449	/*
450	 * Slave is going to close and doesn't want any new  messages coming
451	 * from the master side, so set pts_rdq to NULL. This should be done
452	 * before call to qprocsoff() since slave can't process additional
453	 * messages from the master after qprocsoff is called.
454	 */
455	PT_ENTER_WRITE(ptsp);
456	mp = ptsp->pt_nullmsg;
457	ptsp->pt_nullmsg = NULL;
458	ptsp->pts_rdq = NULL;
459	PT_EXIT_WRITE(ptsp);
460
461	/*
462	 * Drain the ouput
463	 */
464	wqp = WR(rqp);
465	PT_ENTER_READ(ptsp);
466	while ((bp = getq(wqp)) != NULL) {
467		if (ptsp->ptm_rdq) {
468			putnext(ptsp->ptm_rdq, bp);
469		} else if (bp->b_datap->db_type == M_IOCTL) {
470			bp->b_datap->db_type = M_IOCNAK;
471			freemsg(bp->b_cont);
472			bp->b_cont = NULL;
473			qreply(wqp, bp);
474		} else {
475			freemsg(bp);
476		}
477	}
478	/*
479	 * qenable master side write queue so that it can flush
480	 * its messages as slaves's read queue is going away
481	 */
482	if (ptsp->ptm_rdq) {
483		if (mp)
484			putnext(ptsp->ptm_rdq, mp);
485		else
486			qenable(WR(ptsp->ptm_rdq));
487	} else
488		freemsg(mp);
489	PT_EXIT_READ(ptsp);
490
491	qprocsoff(rqp);
492
493	rqp->q_ptr = NULL;
494	WR(rqp)->q_ptr = NULL;
495
496	ptms_close(ptsp, PTSOPEN | PTSTTY);
497
498	return (0);
499}
500
501
502/*
503 * The wput procedure will only handle flush messages.
504 * All other messages are queued and the write side
505 * service procedure sends them off to the master side.
506 */
507static void
508ptswput(queue_t *qp, mblk_t *mp)
509{
510	struct pt_ttys *ptsp;
511	struct iocblk  *iocp;
512	unsigned char type = mp->b_datap->db_type;
513
514	DBG(("entering ptswput\n"));
515	ASSERT(qp->q_ptr);
516
517	ptsp = (struct pt_ttys *)qp->q_ptr;
518	PT_ENTER_READ(ptsp);
519	if (ptsp->ptm_rdq == NULL) {
520		DBG(("in write put proc but no master\n"));
521		/*
522		 * NAK ioctl as slave side read queue is gone.
523		 * Or else free the message.
524		 */
525		if (mp->b_datap->db_type == M_IOCTL) {
526			mp->b_datap->db_type = M_IOCNAK;
527			freemsg(mp->b_cont);
528			mp->b_cont = NULL;
529			qreply(qp, mp);
530		} else
531			freemsg(mp);
532		PT_EXIT_READ(ptsp);
533		return;
534	}
535
536	if (type >= QPCTL) {
537		switch (type) {
538
539		/*
540		 * if write queue request, flush slave's write
541		 * queue and send FLUSHR to ptm. If read queue
542		 * request, send FLUSHR to ptm.
543		 */
544		case M_FLUSH:
545		DBG(("pts got flush request\n"));
546		if (*mp->b_rptr & FLUSHW) {
547
548			DBG(("got FLUSHW, flush pts write Q\n"));
549			if (*mp->b_rptr & FLUSHBAND)
550				/*
551				 * if it is a FLUSHBAND, do flushband.
552				 */
553				flushband(qp, *(mp->b_rptr + 1), FLUSHDATA);
554			else
555				flushq(qp, FLUSHDATA);
556
557			*mp->b_rptr &= ~FLUSHW;
558			if ((*mp->b_rptr & FLUSHR) == 0) {
559				/*
560				 * FLUSHW only. Change to FLUSHR and putnext
561				 * to ptm, then we are done.
562				 */
563				*mp->b_rptr |= FLUSHR;
564				if (ptsp->ptm_rdq)
565					putnext(ptsp->ptm_rdq, mp);
566				break;
567			} else {
568				mblk_t *nmp;
569
570				/* It is a FLUSHRW. Duplicate the mblk */
571				nmp = copyb(mp);
572				if (nmp) {
573					/*
574					 * Change FLUSHW to FLUSHR before
575					 * putnext to ptm.
576					 */
577					DBG(("putnext nmp(FLUSHR) to ptm\n"));
578					*nmp->b_rptr |= FLUSHR;
579					if (ptsp->ptm_rdq)
580						putnext(ptsp->ptm_rdq, nmp);
581				}
582			}
583		}
584		/*
585		 * Since the packet module will toss any
586		 * M_FLUSHES sent to the master's stream head
587		 * read queue, we simply turn it around here.
588		 */
589		if (*mp->b_rptr & FLUSHR) {
590			ASSERT(RD(qp)->q_first == NULL);
591			DBG(("qreply(qp) turning FLUSHR around\n"));
592			qreply(qp, mp);
593		} else {
594			freemsg(mp);
595		}
596		break;
597
598		case M_READ:
599		/* Caused by ldterm - can not pass to master */
600		freemsg(mp);
601		break;
602
603		default:
604		if (ptsp->ptm_rdq)
605			putnext(ptsp->ptm_rdq, mp);
606		break;
607		}
608		PT_EXIT_READ(ptsp);
609		return;
610	}
611
612	switch (type) {
613
614	case M_IOCTL:
615		/*
616		 * For case PTSSTTY set the flag PTSTTY and ACK
617		 * the ioctl so that the user program can push
618		 * the associated modules to get tty semantics.
619		 * See bugid 4025044
620		 */
621		iocp = (struct iocblk *)mp->b_rptr;
622		switch (iocp->ioc_cmd) {
623		default:
624			break;
625
626		case PTSSTTY:
627			if (ptsp->pt_state & PTSTTY) {
628				mp->b_datap->db_type = M_IOCNAK;
629				iocp->ioc_error = EEXIST;
630			} else {
631				mp->b_datap->db_type = M_IOCACK;
632				mutex_enter(&ptsp->pt_lock);
633				ptsp->pt_state |= PTSTTY;
634				mutex_exit(&ptsp->pt_lock);
635				iocp->ioc_error = 0;
636			}
637			iocp->ioc_count = 0;
638			qreply(qp, mp);
639			PT_EXIT_READ(ptsp);
640			return;
641		}
642
643	default:
644		/*
645		 * send other messages to the master
646		 */
647		DBG(("put msg on slave's write queue\n"));
648		(void) putq(qp, mp);
649		break;
650	}
651
652	PT_EXIT_READ(ptsp);
653	DBG(("return from ptswput()\n"));
654}
655
656
657/*
658 * enable the write side of the master. This triggers the
659 * master to send any messages queued on its write side to
660 * the read side of this slave.
661 */
662static void
663ptsrsrv(queue_t *qp)
664{
665	struct pt_ttys *ptsp;
666
667	DBG(("entering ptsrsrv\n"));
668	ASSERT(qp->q_ptr);
669
670	ptsp = (struct pt_ttys *)qp->q_ptr;
671	PT_ENTER_READ(ptsp);
672	if (ptsp->ptm_rdq == NULL) {
673		DBG(("in read srv proc but no master\n"));
674		PT_EXIT_READ(ptsp);
675		return;
676	}
677	qenable(WR(ptsp->ptm_rdq));
678	PT_EXIT_READ(ptsp);
679	DBG(("leaving ptsrsrv\n"));
680}
681
682/*
683 * If there are messages on this queue that can be sent to
684 * master, send them via putnext(). Else, if queued messages
685 * cannot be sent, leave them on this queue. If priority
686 * messages on this queue, send them to master no matter what.
687 */
688static void
689ptswsrv(queue_t *qp)
690{
691	struct pt_ttys *ptsp;
692	queue_t *ptm_rdq;
693	mblk_t *mp;
694
695	DBG(("entering ptswsrv\n"));
696	ASSERT(qp->q_ptr);
697
698	ptsp = (struct pt_ttys *)qp->q_ptr;
699	PT_ENTER_READ(ptsp);
700	if (ptsp->ptm_rdq == NULL) {
701		DBG(("in write srv proc but no master\n"));
702		/*
703		 * Free messages on the write queue and send
704		 * NAK for any M_IOCTL type messages to wakeup
705		 * the user process waiting for ACK/NAK from
706		 * the ioctl invocation
707		 */
708		while ((mp = getq(qp)) != NULL) {
709			if (mp->b_datap->db_type == M_IOCTL) {
710				mp->b_datap->db_type = M_IOCNAK;
711				freemsg(mp->b_cont);
712				mp->b_cont = NULL;
713				qreply(qp, mp);
714			} else
715				freemsg(mp);
716		}
717		PT_EXIT_READ(ptsp);
718		return;
719	} else {
720		ptm_rdq = ptsp->ptm_rdq;
721	}
722
723	/*
724	 * while there are messages on this write queue...
725	 */
726	while ((mp = getq(qp)) != NULL) {
727		/*
728		 * if don't have control message and cannot put
729		 * msg. on master's read queue, put it back on
730		 * this queue.
731		 */
732		if (mp->b_datap->db_type <= QPCTL &&
733		    !bcanputnext(ptm_rdq, mp->b_band)) {
734			DBG(("put msg. back on Q\n"));
735			(void) putbq(qp, mp);
736			break;
737		}
738		/*
739		 * else send the message up master's stream
740		 */
741		DBG(("send message to master\n"));
742		putnext(ptm_rdq, mp);
743	}
744	DBG(("leaving ptswsrv\n"));
745	PT_EXIT_READ(ptsp);
746}
747