kernel: Use NULL for pointers.
[dragonfly.git] / sys / kern / tty_pty.c
1 /*
2  * (MPSAFE)
3  *
4  * Copyright (c) 1982, 1986, 1989, 1993
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *      This product includes software developed by the University of
18  *      California, Berkeley and its contributors.
19  * 4. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  *      @(#)tty_pty.c   8.4 (Berkeley) 2/20/95
36  * $FreeBSD: src/sys/kern/tty_pty.c,v 1.74.2.4 2002/02/20 19:58:13 dillon Exp $
37  */
38
39 /*
40  * MPSAFE NOTE: 
41  * Most functions here could use a separate lock to deal with concurrent
42  * access to the 'pt's.
43  *
44  * Right now the tty_token must be held for all this.
45  */
46
47 /*
48  * Pseudo-teletype Driver
49  * (Actually two drivers, requiring two dev_ops structures)
50  */
51
52 #include "opt_compat.h"
53
54 #include <sys/param.h>
55 #include <sys/systm.h>
56 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
57 #include <sys/ioctl_compat.h>
58 #endif
59 #include <sys/proc.h>
60 #include <sys/priv.h>
61 #include <sys/tty.h>
62 #include <sys/conf.h>
63 #include <sys/fcntl.h>
64 #include <sys/kernel.h>
65 #include <sys/vnode.h>
66 #include <sys/signalvar.h>
67 #include <sys/malloc.h>
68 #include <sys/device.h>
69 #include <sys/thread2.h>
70 #include <sys/devfs.h>
71 #include <sys/stat.h>
72 #include <sys/sysctl.h>
73
74 #define UNIX98_PTYS     1
75
76 MALLOC_DEFINE(M_PTY, "ptys", "pty data structures");
77
78 static void ptsstart (struct tty *tp);
79 static void ptsstop (struct tty *tp, int rw);
80 static void ptsunhold (struct tty *tp);
81 static void ptcwakeup (struct tty *tp, int flag);
82 static void ptyinit (int n);
83 static int  filt_ptcread (struct knote *kn, long hint);
84 static void filt_ptcrdetach (struct knote *kn);
85 static int  filt_ptcwrite (struct knote *kn, long hint);
86 static void filt_ptcwdetach (struct knote *kn);
87
88 static  d_open_t        ptsopen;
89 static  d_close_t       ptsclose;
90 static  d_read_t        ptsread;
91 static  d_write_t       ptswrite;
92 static  d_ioctl_t       ptyioctl;
93 static  d_open_t        ptcopen;
94 static  d_close_t       ptcclose;
95 static  d_read_t        ptcread;
96 static  d_write_t       ptcwrite;
97 static  d_kqfilter_t    ptckqfilter;
98
99 #ifdef UNIX98_PTYS
100 DEVFS_DECLARE_CLONE_BITMAP(pty);
101
102 static  d_clone_t       ptyclone;
103
104 static int      pty_debug_level = 0;
105
106 static struct dev_ops pts98_ops = {
107         { "pts98", 0, D_TTY | D_MPSAFE },
108         .d_open =       ptsopen,
109         .d_close =      ptsclose,
110         .d_read =       ptsread,
111         .d_write =      ptswrite,
112         .d_ioctl =      ptyioctl,
113         .d_kqfilter =   ttykqfilter,
114         .d_revoke =     ttyrevoke
115 };
116
117 static struct dev_ops ptc98_ops = {
118         { "ptc98", 0, D_TTY | D_MASTER | D_MPSAFE },
119         .d_open =       ptcopen,
120         .d_close =      ptcclose,
121         .d_read =       ptcread,
122         .d_write =      ptcwrite,
123         .d_ioctl =      ptyioctl,
124         .d_kqfilter =   ptckqfilter,
125         .d_revoke =     ttyrevoke
126 };
127 #endif
128
129 static struct dev_ops pts_ops = {
130         { "pts", 0, D_TTY | D_MPSAFE },
131         .d_open =       ptsopen,
132         .d_close =      ptsclose,
133         .d_read =       ptsread,
134         .d_write =      ptswrite,
135         .d_ioctl =      ptyioctl,
136         .d_kqfilter =   ttykqfilter,
137         .d_revoke =     ttyrevoke
138 };
139
140 #define CDEV_MAJOR_C    6
141 static struct dev_ops ptc_ops = {
142         { "ptc", 0, D_TTY | D_MASTER | D_MPSAFE },
143         .d_open =       ptcopen,
144         .d_close =      ptcclose,
145         .d_read =       ptcread,
146         .d_write =      ptcwrite,
147         .d_ioctl =      ptyioctl,
148         .d_kqfilter =   ptckqfilter,
149         .d_revoke =     ttyrevoke
150 };
151
152 #define BUFSIZ 100              /* Chunk size iomoved to/from user */
153
154 struct  pt_ioctl {
155         int     pt_flags;
156         int     pt_refs;        /* Structural references interlock S/MOPEN */
157         int     pt_uminor;
158         struct  kqinfo pt_kqr, pt_kqw;
159         u_char  pt_send;
160         u_char  pt_ucntl;
161         struct tty pt_tty;
162         cdev_t  devs, devc;
163         struct  prison *pt_prison;
164 };
165
166 /*
167  * pt_flags ptc state
168  */
169 #define PF_PKT          0x0008          /* packet mode */
170 #define PF_STOPPED      0x0010          /* user told stopped */
171 #define PF_REMOTE       0x0020          /* remote and flow controlled input */
172 #define PF_NOSTOP       0x0040
173 #define PF_UCNTL        0x0080          /* user control mode */
174
175 #define PF_PTCSTATEMASK 0x00FF
176
177 /*
178  * pt_flags open state.  Note that PF_SCLOSED is used to activate
179  * read EOF on the ptc so it is only set after the slave has been
180  * opened and then closed, and cleared again if the slave is opened
181  * again.
182  */
183 #define PF_UNIX98       0x0100
184 #define PF_SOPEN        0x0200
185 #define PF_MOPEN        0x0400
186 #define PF_SCLOSED      0x0800
187 #define PF_TERMINATED   0x8000
188
189 /*
190  * This function creates and initializes a pts/ptc pair
191  *
192  * pts == /dev/tty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
193  * ptc == /dev/pty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
194  *
195  * XXX: define and add mapping of upper minor bits to allow more 
196  *      than 256 ptys.
197  */
198 static void
199 ptyinit(int n)
200 {
201         cdev_t devs, devc;
202         char *names = "pqrsPQRS";
203         struct pt_ioctl *pt;
204
205         /* For now we only map the lower 8 bits of the minor */
206         if (n & ~0xff)
207                 return;
208
209         pt = kmalloc(sizeof(*pt), M_PTY, M_WAITOK | M_ZERO);
210         pt->devs = devs = make_dev(&pts_ops, n,
211             0, 0, 0666, "tty%c%r", names[n / 32], n % 32);
212         pt->devc = devc = make_dev(&ptc_ops, n,
213             0, 0, 0666, "pty%c%r", names[n / 32], n % 32);
214
215         pt->pt_tty.t_dev = devs;
216         pt->pt_uminor = n;
217         devs->si_drv1 = devc->si_drv1 = pt;
218         devs->si_tty = devc->si_tty = &pt->pt_tty;
219         devs->si_flags |= SI_OVERRIDE;  /* uid, gid, perms from dev */
220         devc->si_flags |= SI_OVERRIDE;  /* uid, gid, perms from dev */
221         ttyregister(&pt->pt_tty);
222 }
223
224 #ifdef UNIX98_PTYS
225 static int
226 ptyclone(struct dev_clone_args *ap)
227 {
228         int unit;
229         struct pt_ioctl *pt;
230
231         /*
232          * Limit the number of unix98 pty (slave) devices to 1000, as
233          * the utmp(5) format only allows for 8 bytes for the tty,
234          * "pts/XXX".
235          * If this limit is reached, we don't clone and return error
236          * to devfs.
237          */
238         unit = devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(pty), 1000);
239
240         if (unit < 0) {
241                 ap->a_dev = NULL;
242                 return 1;
243         }
244
245         pt = kmalloc(sizeof(*pt), M_PTY, M_WAITOK | M_ZERO);
246
247         pt->devc = make_only_dev(&ptc98_ops, unit,
248                                  ap->a_cred->cr_ruid,
249                                  0, 0600, "ptm/%d", unit);
250         pt->devs = make_dev(&pts98_ops, unit,
251                             ap->a_cred->cr_ruid,
252                             GID_TTY, 0620, "pts/%d", unit);
253         ap->a_dev = pt->devc;
254
255         pt->devs->si_flags |= SI_OVERRIDE;      /* uid, gid, perms from dev */
256         pt->devc->si_flags |= SI_OVERRIDE;      /* uid, gid, perms from dev */
257
258         pt->pt_tty.t_dev = pt->devs;
259         pt->pt_flags |= PF_UNIX98;
260         pt->pt_uminor = unit;
261         pt->devs->si_drv1 = pt->devc->si_drv1 = pt;
262         pt->devs->si_tty = pt->devc->si_tty = &pt->pt_tty;
263
264         ttyregister(&pt->pt_tty);
265
266         return 0;
267 }
268 #endif
269
270 /*
271  * pti_hold() prevents the pti from being destroyed due to a termination
272  * while a pt*open() is blocked.
273  *
274  * This function returns non-zero if we cannot hold due to a termination
275  * interlock.
276  *
277  * NOTE: Must be called with tty_token held
278  */
279 static int
280 pti_hold(struct pt_ioctl *pti)
281 {
282         if (pti->pt_flags & PF_TERMINATED)
283                 return(ENXIO);
284         ++pti->pt_refs;
285         return(0);
286 }
287
288 /*
289  * pti_done() releases the reference and checks to see if both sides have
290  * been closed on a unix98 pty, allowing us to destroy the device and
291  * release resources.
292  *
293  * We do not release resources on non-unix98 ptys.  Those are left
294  * statically allocated.
295  */
296 static void
297 pti_done(struct pt_ioctl *pti)
298 {
299         lwkt_gettoken(&tty_token);
300         if (--pti->pt_refs == 0) {
301 #ifdef UNIX98_PTYS
302                 cdev_t dev;
303                 int uminor_no;
304
305                 /*
306                  * Only unix09 ptys are freed up
307                  */
308                 if ((pti->pt_flags & PF_UNIX98) == 0) {
309                         lwkt_reltoken(&tty_token);
310                         return;
311                 }
312
313                 /*
314                  * Interlock open attempts against termination by setting
315                  * PF_TERMINATED.  This allows us to block while cleaning
316                  * out the device infrastructure.
317                  *
318                  * Do not terminate the tty if it still has a session
319                  * association (t_refs).
320                  */
321                 if ((pti->pt_flags & (PF_SOPEN|PF_MOPEN)) == 0 &&
322                     pti->pt_tty.t_refs == 0) {
323                         pti->pt_flags |= PF_TERMINATED;
324                         uminor_no = pti->pt_uminor;
325
326                         if ((dev = pti->devs) != NULL) {
327                                 dev->si_drv1 = NULL;
328                                 pti->devs = NULL;
329                                 destroy_dev(dev);
330                         }
331                         if ((dev = pti->devc) != NULL) {
332                                 dev->si_drv1 = NULL;
333                                 pti->devc = NULL;
334                                 destroy_dev(dev);
335                         }
336                         ttyunregister(&pti->pt_tty);
337                         devfs_clone_bitmap_put(&DEVFS_CLONE_BITMAP(pty),
338                                                uminor_no);
339                         kfree(pti, M_PTY);
340                 }
341 #endif
342         }
343         lwkt_reltoken(&tty_token);
344 }
345
346 /*ARGSUSED*/
347 static  int
348 ptsopen(struct dev_open_args *ap)
349 {
350         cdev_t dev = ap->a_head.a_dev;
351         struct tty *tp;
352         int error;
353         struct pt_ioctl *pti;
354
355         /*
356          * The pti will already be assigned by the clone code or
357          * pre-created if a non-unix 98 pty.  If si_drv1 is NULL
358          * we are somehow racing a unix98 termination.
359          */
360         if (dev->si_drv1 == NULL)
361                 return(ENXIO);
362         pti = dev->si_drv1;
363
364         lwkt_gettoken(&tty_token);
365         if (pti_hold(pti)) {
366                 lwkt_reltoken(&tty_token);
367                 return(ENXIO);
368         }
369
370         tp = dev->si_tty;
371
372         /*
373          * Reinit most of the tty state if it isn't open.  Handle
374          * exclusive access.
375          */
376         if ((tp->t_state & TS_ISOPEN) == 0) {
377                 ttychars(tp);           /* Set up default chars */
378                 tp->t_iflag = TTYDEF_IFLAG;
379                 tp->t_oflag = TTYDEF_OFLAG;
380                 tp->t_lflag = TTYDEF_LFLAG;
381                 tp->t_cflag = TTYDEF_CFLAG;
382                 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
383         } else if ((tp->t_state & TS_XCLUDE) &&
384                    priv_check_cred(ap->a_cred, PRIV_ROOT, 0)) {
385                 pti_done(pti);
386                 lwkt_reltoken(&tty_token);
387                 return (EBUSY);
388         } else if (pti->pt_prison != ap->a_cred->cr_prison) {
389                 pti_done(pti);
390                 lwkt_reltoken(&tty_token);
391                 return (EBUSY);
392         }
393
394         /*
395          * If the ptc is already present this will connect us up.  It
396          * is unclear if this is actually needed.
397          *
398          * If neither side is open be sure to clear any left over
399          * ZOMBIE state before continuing.
400          */
401         if (tp->t_oproc)
402                 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
403         else if ((pti->pt_flags & PF_SOPEN) == 0)
404                 tp->t_state &= ~TS_ZOMBIE;
405
406         /*
407          * Wait for the carrier (ptc side)
408          */
409         while ((tp->t_state & TS_CARR_ON) == 0) {
410                 if (ap->a_oflags & FNONBLOCK)
411                         break;
412                 error = ttysleep(tp, TSA_CARR_ON(tp), PCATCH, "ptsopn", 0);
413                 if (error) {
414                         pti_done(pti);
415                         lwkt_reltoken(&tty_token);
416                         return (error);
417                 }
418         }
419
420         /*
421          * Mark the tty open and mark the slave side as being open.
422          */
423         error = (*linesw[tp->t_line].l_open)(dev, tp);
424
425         if (error == 0) {
426                 pti->pt_flags |= PF_SOPEN;
427                 pti->pt_flags &= ~PF_SCLOSED;
428                 ptcwakeup(tp, FREAD|FWRITE);
429         }
430         pti_done(pti);
431
432         lwkt_reltoken(&tty_token);
433         return (error);
434 }
435
436 static  int
437 ptsclose(struct dev_close_args *ap)
438 {
439         cdev_t dev = ap->a_head.a_dev;
440         struct tty *tp;
441         struct pt_ioctl *pti = dev->si_drv1;
442         int err;
443
444         lwkt_gettoken(&tty_token);
445         if (pti_hold(pti))
446                 panic("ptsclose on terminated pti");
447
448         /*
449          * Disconnect the slave side
450          */
451         tp = dev->si_tty;
452         err = (*linesw[tp->t_line].l_close)(tp, ap->a_fflag);
453         ptsstop(tp, FREAD|FWRITE);
454         ttyclose(tp);                   /* clears t_state */
455
456         /*
457          * Mark the pts side closed and signal the ptc.  Do not mark the
458          * tty a zombie... that is, allow the tty to be re-opened as long
459          * as the ptc is still open.  The ptc will read() EOFs until the
460          * pts side is reopened or the ptc is closed.
461          *
462          * xterm() depends on this behavior as it will revoke() the pts
463          * and then reopen it after the (unnecessary old code) chmod.
464          */
465         pti->pt_flags &= ~PF_SOPEN;
466         pti->pt_flags |= PF_SCLOSED;
467         if (tp->t_oproc)
468                 ptcwakeup(tp, FREAD);
469         pti_done(pti);
470         lwkt_reltoken(&tty_token);
471         return (err);
472 }
473
474 static  int
475 ptsread(struct dev_read_args *ap)
476 {
477         cdev_t dev = ap->a_head.a_dev;
478         struct proc *p = curproc;
479         struct tty *tp = dev->si_tty;
480         struct pt_ioctl *pti = dev->si_drv1;
481         struct lwp *lp;
482
483         int error = 0;
484
485         lp = curthread->td_lwp;
486
487         lwkt_gettoken(&tty_token);
488 again:
489         if (pti->pt_flags & PF_REMOTE) {
490                 while (isbackground(p, tp)) {
491                         if (SIGISMEMBER(p->p_sigignore, SIGTTIN) ||
492                             SIGISMEMBER(lp->lwp_sigmask, SIGTTIN) ||
493                             p->p_pgrp->pg_jobc == 0 ||
494                             (p->p_flags & P_PPWAIT)) {
495                                 lwkt_reltoken(&tty_token);
496                                 return (EIO);
497                         }
498                         pgsignal(p->p_pgrp, SIGTTIN, 1);
499                         error = ttysleep(tp, &lbolt, PCATCH, "ptsbg", 0);
500                         if (error) {
501                                 lwkt_reltoken(&tty_token);
502                                 return (error);
503                         }
504                 }
505                 if (tp->t_canq.c_cc == 0) {
506                         if (ap->a_ioflag & IO_NDELAY) {
507                                 lwkt_reltoken(&tty_token);
508                                 return (EWOULDBLOCK);
509                         }
510                         error = ttysleep(tp, TSA_PTS_READ(tp), PCATCH,
511                                          "ptsin", 0);
512                         if (error) {
513                                 lwkt_reltoken(&tty_token);
514                                 return (error);
515                         }
516                         goto again;
517                 }
518                 while (tp->t_canq.c_cc > 1 && ap->a_uio->uio_resid > 0)
519                         if (ureadc(clist_getc(&tp->t_canq), ap->a_uio) < 0) {
520                                 error = EFAULT;
521                                 break;
522                         }
523                 if (tp->t_canq.c_cc == 1)
524                         clist_getc(&tp->t_canq);
525                 if (tp->t_canq.c_cc) {
526                         lwkt_reltoken(&tty_token);
527                         return (error);
528                 }
529         } else
530                 if (tp->t_oproc)
531                         error = (*linesw[tp->t_line].l_read)(tp, ap->a_uio, ap->a_ioflag);
532         ptcwakeup(tp, FWRITE);
533         lwkt_reltoken(&tty_token);
534         return (error);
535 }
536
537 /*
538  * Write to pseudo-tty.
539  * Wakeups of controlling tty will happen
540  * indirectly, when tty driver calls ptsstart.
541  */
542 static  int
543 ptswrite(struct dev_write_args *ap)
544 {
545         cdev_t dev = ap->a_head.a_dev;
546         struct tty *tp;
547         int ret;
548
549         lwkt_gettoken(&tty_token);
550         tp = dev->si_tty;
551         if (tp->t_oproc == 0) {
552                 lwkt_reltoken(&tty_token);
553                 return (EIO);
554         }
555         ret = ((*linesw[tp->t_line].l_write)(tp, ap->a_uio, ap->a_ioflag));
556         lwkt_reltoken(&tty_token);
557         return ret;
558 }
559
560 /*
561  * Start output on pseudo-tty.
562  * Wake up process selecting or sleeping for input from controlling tty.
563  */
564 static void
565 ptsstart(struct tty *tp)
566 {
567         lwkt_gettoken(&tty_token);
568         struct pt_ioctl *pti = tp->t_dev->si_drv1;
569
570         if (tp->t_state & TS_TTSTOP) {
571                 lwkt_reltoken(&tty_token);
572                 return;
573         }
574         if (pti) {
575                 if (pti->pt_flags & PF_STOPPED) {
576                         pti->pt_flags &= ~PF_STOPPED;
577                         pti->pt_send = TIOCPKT_START;
578                 }
579         }
580         ptcwakeup(tp, FREAD);
581         lwkt_reltoken(&tty_token);
582 }
583
584 /*
585  * NOTE: Must be called with tty_token held
586  */
587 static void
588 ptcwakeup(struct tty *tp, int flag)
589 {
590         ASSERT_LWKT_TOKEN_HELD(&tty_token);
591
592         if (flag & FREAD) {
593                 wakeup(TSA_PTC_READ(tp));
594                 KNOTE(&tp->t_rkq.ki_note, 0);
595         }
596         if (flag & FWRITE) {
597                 wakeup(TSA_PTC_WRITE(tp));
598                 KNOTE(&tp->t_wkq.ki_note, 0);
599         }
600 }
601
602 static  int
603 ptcopen(struct dev_open_args *ap)
604 {
605         cdev_t dev = ap->a_head.a_dev;
606         struct tty *tp;
607         struct pt_ioctl *pti;
608
609         /*
610          * The pti will already be assigned by the clone code or
611          * pre-created if a non-unix 98 pty.  If si_drv1 is NULL
612          * we are somehow racing a unix98 termination.
613          */
614         if (dev->si_drv1 == NULL)
615                 return(ENXIO);
616
617         lwkt_gettoken(&tty_token);
618         pti = dev->si_drv1;
619         if (pti_hold(pti)) {
620                 lwkt_reltoken(&tty_token);
621                 return(ENXIO);
622         }
623         if (pti->pt_prison && pti->pt_prison != ap->a_cred->cr_prison) {
624                 pti_done(pti);
625                 lwkt_reltoken(&tty_token);
626                 return(EBUSY);
627         }
628         tp = dev->si_tty;
629         if (tp->t_oproc) {
630                 pti_done(pti);
631                 lwkt_reltoken(&tty_token);
632                 return (EIO);
633         }
634
635         /*
636          * If the slave side is not yet open clear any left over zombie
637          * state before doing our modem control.
638          */
639         if ((pti->pt_flags & PF_SOPEN) == 0)
640                 tp->t_state &= ~TS_ZOMBIE;
641
642         tp->t_oproc = ptsstart;
643         tp->t_stop = ptsstop;
644         tp->t_unhold = ptsunhold;
645
646         /*
647          * Carrier on!
648          */
649         (void)(*linesw[tp->t_line].l_modem)(tp, 1);
650
651         tp->t_lflag &= ~EXTPROC;
652         pti->pt_prison = ap->a_cred->cr_prison;
653         pti->pt_flags &= ~PF_PTCSTATEMASK;
654         pti->pt_send = 0;
655         pti->pt_ucntl = 0;
656
657         pti->devs->si_uid = ap->a_cred->cr_uid;
658         pti->devs->si_gid = 0;
659         pti->devs->si_perms = 0600;
660         pti->devc->si_uid = ap->a_cred->cr_uid;
661         pti->devc->si_gid = 0;
662         pti->devc->si_perms = 0600;
663
664         /*
665          * Mark master side open.  This does not cause any events
666          * on the slave side.
667          */
668         pti->pt_flags |= PF_MOPEN;
669         pti_done(pti);
670
671         lwkt_reltoken(&tty_token);
672         return (0);
673 }
674
675 static  int
676 ptcclose(struct dev_close_args *ap)
677 {
678         cdev_t dev = ap->a_head.a_dev;
679         struct tty *tp;
680         struct pt_ioctl *pti = dev->si_drv1;
681
682         lwkt_gettoken(&tty_token);
683         if (pti_hold(pti))
684                 panic("ptcclose on terminated pti");
685
686         tp = dev->si_tty;
687         (void)(*linesw[tp->t_line].l_modem)(tp, 0);
688
689         /*
690          * Mark the master side closed.  If the slave is still open
691          * mark the tty ZOMBIE, preventing any new action until both
692          * sides have closed.
693          *
694          * NOTE: The ttyflush() will wake up the slave once we've
695          *       set appropriate flags.  The ZOMBIE flag will be
696          *       cleared when the slave side is closed.
697          */
698         pti->pt_flags &= ~PF_MOPEN;
699         if (pti->pt_flags & PF_SOPEN)
700                 tp->t_state |= TS_ZOMBIE;
701
702         /*
703          * Turn off the carrier and disconnect.  This will notify the slave
704          * side.
705          */
706         if (tp->t_state & TS_ISOPEN) {
707                 tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED);
708                 ttyflush(tp, FREAD | FWRITE);
709         }
710         tp->t_oproc = NULL;             /* mark closed */
711
712         pti->pt_prison = NULL;
713         pti->devs->si_uid = 0;
714         pti->devs->si_gid = 0;
715         pti->devs->si_perms = 0666;
716         pti->devc->si_uid = 0;
717         pti->devc->si_gid = 0;
718         pti->devc->si_perms = 0666;
719
720         pti_done(pti);
721
722         lwkt_reltoken(&tty_token);
723         return (0);
724 }
725
726 static  int
727 ptcread(struct dev_read_args *ap)
728 {
729         cdev_t dev = ap->a_head.a_dev;
730         struct tty *tp = dev->si_tty;
731         struct pt_ioctl *pti = dev->si_drv1;
732         char buf[BUFSIZ];
733         int error = 0, cc;
734
735         lwkt_gettoken(&tty_token);
736         /*
737          * We want to block until the slave
738          * is open, and there's something to read;
739          * but if we lost the slave or we're NBIO,
740          * then return the appropriate error instead.
741          */
742         for (;;) {
743                 if (tp->t_state&TS_ISOPEN) {
744                         if ((pti->pt_flags & PF_PKT) && pti->pt_send) {
745                                 error = ureadc((int)pti->pt_send, ap->a_uio);
746                                 if (error) {
747                                         lwkt_reltoken(&tty_token);
748                                         return (error);
749                                 }
750                                 if (pti->pt_send & TIOCPKT_IOCTL) {
751                                         cc = (int)szmin(ap->a_uio->uio_resid,
752                                                         sizeof(tp->t_termios));
753                                         uiomove((caddr_t)&tp->t_termios, cc,
754                                                 ap->a_uio);
755                                 }
756                                 pti->pt_send = 0;
757                                 lwkt_reltoken(&tty_token);
758                                 return (0);
759                         }
760                         if ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl) {
761                                 error = ureadc((int)pti->pt_ucntl, ap->a_uio);
762                                 if (error) {
763                                         lwkt_reltoken(&tty_token);
764                                         return (error);
765                                 }
766                                 pti->pt_ucntl = 0;
767                                 lwkt_reltoken(&tty_token);
768                                 return (0);
769                         }
770                         if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
771                                 break;
772                 }
773                 if ((tp->t_state & TS_CONNECTED) == 0) {
774                         lwkt_reltoken(&tty_token);
775                         return (0);     /* EOF */
776                 }
777                 if (ap->a_ioflag & IO_NDELAY) {
778                         lwkt_reltoken(&tty_token);
779                         return (EWOULDBLOCK);
780                 }
781                 error = tsleep(TSA_PTC_READ(tp), PCATCH, "ptcin", 0);
782                 if (error) {
783                         lwkt_reltoken(&tty_token);
784                         return (error);
785                 }
786         }
787         if (pti->pt_flags & (PF_PKT|PF_UCNTL))
788                 error = ureadc(0, ap->a_uio);
789         while (ap->a_uio->uio_resid > 0 && error == 0) {
790                 cc = q_to_b(&tp->t_outq, buf,
791                             (int)szmin(ap->a_uio->uio_resid, BUFSIZ));
792                 if (cc <= 0)
793                         break;
794                 error = uiomove(buf, (size_t)cc, ap->a_uio);
795         }
796         ttwwakeup(tp);
797         lwkt_reltoken(&tty_token);
798         return (error);
799 }
800
801 static  void
802 ptsstop(struct tty *tp, int flush)
803 {
804         struct pt_ioctl *pti = tp->t_dev->si_drv1;
805         int flag;
806
807         lwkt_gettoken(&tty_token);
808         /* note: FLUSHREAD and FLUSHWRITE already ok */
809         if (pti) {
810                 if (flush == 0) {
811                         flush = TIOCPKT_STOP;
812                         pti->pt_flags |= PF_STOPPED;
813                 } else {
814                         pti->pt_flags &= ~PF_STOPPED;
815                 }
816                 pti->pt_send |= flush;
817                 /* change of perspective */
818         }
819         flag = 0;
820         if (flush & FREAD)
821                 flag |= FWRITE;
822         if (flush & FWRITE)
823                 flag |= FREAD;
824         ptcwakeup(tp, flag);
825
826         lwkt_reltoken(&tty_token);
827 }
828
829 /*
830  * ttyunhold() calls us instead of just decrementing tp->t_refs.  This
831  * is needed because a session can hold onto a pts (half closed state)
832  * even if there are no live file descriptors.  Without the callback
833  * we can't clean up.
834  */
835 static  void
836 ptsunhold(struct tty *tp)
837 {
838         struct pt_ioctl *pti = tp->t_dev->si_drv1;
839
840         lwkt_gettoken(&tty_token);
841         pti_hold(pti);
842         --tp->t_refs;
843         pti_done(pti);
844         lwkt_reltoken(&tty_token);
845 }
846
847 /*
848  * kqueue ops for pseudo-terminals.
849  */
850 static struct filterops ptcread_filtops =
851         { FILTEROP_ISFD|FILTEROP_MPSAFE, NULL, filt_ptcrdetach, filt_ptcread };
852 static struct filterops ptcwrite_filtops =
853         { FILTEROP_ISFD|FILTEROP_MPSAFE, NULL, filt_ptcwdetach, filt_ptcwrite };
854
855 static  int
856 ptckqfilter(struct dev_kqfilter_args *ap)
857 {
858         cdev_t dev = ap->a_head.a_dev;
859         struct knote *kn = ap->a_kn;
860         struct tty *tp = dev->si_tty;
861         struct klist *klist;
862
863         lwkt_gettoken(&tty_token);
864         ap->a_result = 0;
865         switch (kn->kn_filter) {
866         case EVFILT_READ:
867                 klist = &tp->t_rkq.ki_note;
868                 kn->kn_fop = &ptcread_filtops;
869                 break;
870         case EVFILT_WRITE:
871                 klist = &tp->t_wkq.ki_note;
872                 kn->kn_fop = &ptcwrite_filtops;
873                 break;
874         default:
875                 ap->a_result = EOPNOTSUPP;
876                 lwkt_reltoken(&tty_token);
877                 return (0);
878         }
879
880         kn->kn_hook = (caddr_t)dev;
881         knote_insert(klist, kn);
882         lwkt_reltoken(&tty_token);
883         return (0);
884 }
885
886 static int
887 filt_ptcread (struct knote *kn, long hint)
888 {
889         struct tty *tp = ((cdev_t)kn->kn_hook)->si_tty;
890         struct pt_ioctl *pti = ((cdev_t)kn->kn_hook)->si_drv1;
891
892         lwkt_gettoken(&tty_token);
893         if ((tp->t_state & TS_ZOMBIE) || (pti->pt_flags & PF_SCLOSED)) {
894                 kn->kn_flags |= (EV_EOF | EV_NODATA);
895                 lwkt_reltoken(&tty_token);
896                 return (1);
897         }
898
899         if ((tp->t_state & TS_ISOPEN) &&
900             ((tp->t_outq.c_cc && (tp->t_state & TS_TTSTOP) == 0) ||
901              ((pti->pt_flags & PF_PKT) && pti->pt_send) ||
902              ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl))) {
903                 kn->kn_data = tp->t_outq.c_cc;
904                 lwkt_reltoken(&tty_token);
905                 return(1);
906         } else {
907                 lwkt_reltoken(&tty_token);
908                 return(0);
909         }
910 }
911
912 static int
913 filt_ptcwrite (struct knote *kn, long hint)
914 {
915         struct tty *tp = ((cdev_t)kn->kn_hook)->si_tty;
916         struct pt_ioctl *pti = ((cdev_t)kn->kn_hook)->si_drv1;
917
918         lwkt_gettoken(&tty_token);
919         if (tp->t_state & TS_ZOMBIE) {
920                 kn->kn_flags |= (EV_EOF | EV_NODATA);
921                 lwkt_reltoken(&tty_token);
922                 return (1);
923         }
924
925         if (tp->t_state & TS_ISOPEN &&
926             ((pti->pt_flags & PF_REMOTE) ?
927              (tp->t_canq.c_cc == 0) :
928              ((tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG - 2) ||
929               (tp->t_canq.c_cc == 0 && (tp->t_lflag & ICANON))))) {
930                 kn->kn_data = tp->t_canq.c_cc + tp->t_rawq.c_cc;
931                 lwkt_reltoken(&tty_token);
932                 return(1);
933         } else {
934                 lwkt_reltoken(&tty_token);
935                 return(0);
936         }
937         /* NOTREACHED */
938 }
939
940 static void
941 filt_ptcrdetach (struct knote *kn)
942 {
943         struct tty *tp = ((cdev_t)kn->kn_hook)->si_tty;
944
945         knote_remove(&tp->t_rkq.ki_note, kn);
946 }
947
948 static void
949 filt_ptcwdetach (struct knote *kn)
950 {
951         struct tty *tp = ((cdev_t)kn->kn_hook)->si_tty;
952
953         knote_remove(&tp->t_wkq.ki_note, kn);
954 }
955
956 /*
957  * I/O ops
958  */
959 static  int
960 ptcwrite(struct dev_write_args *ap)
961 {
962         cdev_t dev = ap->a_head.a_dev;
963         struct tty *tp = dev->si_tty;
964         u_char *cp = NULL;
965         int cc = 0;
966         u_char locbuf[BUFSIZ];
967         int cnt = 0;
968         struct pt_ioctl *pti = dev->si_drv1;
969         int error = 0;
970
971         lwkt_gettoken(&tty_token);
972 again:
973         if ((tp->t_state&TS_ISOPEN) == 0)
974                 goto block;
975         if (pti->pt_flags & PF_REMOTE) {
976                 if (tp->t_canq.c_cc)
977                         goto block;
978                 while ((ap->a_uio->uio_resid > 0 || cc > 0) &&
979                        tp->t_canq.c_cc < TTYHOG - 1) {
980                         if (cc == 0) {
981                                 cc = (int)szmin(ap->a_uio->uio_resid, BUFSIZ);
982                                 cc = imin(cc, TTYHOG - 1 - tp->t_canq.c_cc);
983                                 cp = locbuf;
984                                 error = uiomove(cp, (size_t)cc, ap->a_uio);
985                                 if (error) {
986                                         lwkt_reltoken(&tty_token);
987                                         return (error);
988                                 }
989                                 /* check again for safety */
990                                 if ((tp->t_state & TS_ISOPEN) == 0) {
991                                         /* adjust as usual */
992                                         ap->a_uio->uio_resid += cc;
993                                         lwkt_reltoken(&tty_token);
994                                         return (EIO);
995                                 }
996                         }
997                         if (cc > 0) {
998                                 cc = b_to_q((char *)cp, cc, &tp->t_canq);
999                                 /*
1000                                  * XXX we don't guarantee that the canq size
1001                                  * is >= TTYHOG, so the above b_to_q() may
1002                                  * leave some bytes uncopied.  However, space
1003                                  * is guaranteed for the null terminator if
1004                                  * we don't fail here since (TTYHOG - 1) is
1005                                  * not a multiple of CBSIZE.
1006                                  */
1007                                 if (cc > 0)
1008                                         break;
1009                         }
1010                 }
1011                 /* adjust for data copied in but not written */
1012                 ap->a_uio->uio_resid += cc;
1013                 clist_putc(0, &tp->t_canq);
1014                 ttwakeup(tp);
1015                 wakeup(TSA_PTS_READ(tp));
1016                 lwkt_reltoken(&tty_token);
1017                 return (0);
1018         }
1019         while (ap->a_uio->uio_resid > 0 || cc > 0) {
1020                 if (cc == 0) {
1021                         cc = (int)szmin(ap->a_uio->uio_resid, BUFSIZ);
1022                         cp = locbuf;
1023                         error = uiomove(cp, (size_t)cc, ap->a_uio);
1024                         if (error) {
1025                                 lwkt_reltoken(&tty_token);
1026                                 return (error);
1027                         }
1028                         /* check again for safety */
1029                         if ((tp->t_state & TS_ISOPEN) == 0) {
1030                                 /* adjust for data copied in but not written */
1031                                 ap->a_uio->uio_resid += cc;
1032                                 lwkt_reltoken(&tty_token);
1033                                 return (EIO);
1034                         }
1035                 }
1036                 while (cc > 0) {
1037                         if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
1038                            (tp->t_canq.c_cc > 0 || !(tp->t_lflag&ICANON))) {
1039                                 wakeup(TSA_HUP_OR_INPUT(tp));
1040                                 goto block;
1041                         }
1042                         (*linesw[tp->t_line].l_rint)(*cp++, tp);
1043                         cnt++;
1044                         cc--;
1045                 }
1046                 cc = 0;
1047         }
1048         lwkt_reltoken(&tty_token);
1049         return (0);
1050 block:
1051         /*
1052          * Come here to wait for slave to open, for space
1053          * in outq, or space in rawq, or an empty canq.
1054          */
1055         if ((tp->t_state & TS_CONNECTED) == 0) {
1056                 /* adjust for data copied in but not written */
1057                 ap->a_uio->uio_resid += cc;
1058                 lwkt_reltoken(&tty_token);
1059                 return (EIO);
1060         }
1061         if (ap->a_ioflag & IO_NDELAY) {
1062                 /* adjust for data copied in but not written */
1063                 ap->a_uio->uio_resid += cc;
1064                 if (cnt == 0) {
1065                         lwkt_reltoken(&tty_token);
1066                         return (EWOULDBLOCK);
1067                 }
1068                 lwkt_reltoken(&tty_token);
1069                 return (0);
1070         }
1071         error = tsleep(TSA_PTC_WRITE(tp), PCATCH, "ptcout", 0);
1072         if (error) {
1073                 /* adjust for data copied in but not written */
1074                 ap->a_uio->uio_resid += cc;
1075                 lwkt_reltoken(&tty_token);
1076                 return (error);
1077         }
1078         goto again;
1079 }
1080
1081 /*ARGSUSED*/
1082 static  int
1083 ptyioctl(struct dev_ioctl_args *ap)
1084 {
1085         cdev_t dev = ap->a_head.a_dev;
1086         struct tty *tp = dev->si_tty;
1087         struct pt_ioctl *pti = dev->si_drv1;
1088         u_char *cc = tp->t_cc;
1089         int stop, error;
1090
1091         lwkt_gettoken(&tty_token);
1092         if (dev_dflags(dev) & D_MASTER) {
1093                 switch (ap->a_cmd) {
1094
1095                 case TIOCGPGRP:
1096                         /*
1097                          * We avoid calling ttioctl on the controller since,
1098                          * in that case, tp must be the controlling terminal.
1099                          */
1100                         *(int *)ap->a_data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
1101                         lwkt_reltoken(&tty_token);
1102                         return (0);
1103
1104                 case TIOCPKT:
1105                         if (*(int *)ap->a_data) {
1106                                 if (pti->pt_flags & PF_UCNTL) {
1107                                         lwkt_reltoken(&tty_token);
1108                                         return (EINVAL);
1109                                 }
1110                                 pti->pt_flags |= PF_PKT;
1111                         } else {
1112                                 pti->pt_flags &= ~PF_PKT;
1113                         }
1114                         lwkt_reltoken(&tty_token);
1115                         return (0);
1116
1117                 case TIOCUCNTL:
1118                         if (*(int *)ap->a_data) {
1119                                 if (pti->pt_flags & PF_PKT) {
1120                                         lwkt_reltoken(&tty_token);
1121                                         return (EINVAL);
1122                                 }
1123                                 pti->pt_flags |= PF_UCNTL;
1124                         } else {
1125                                 pti->pt_flags &= ~PF_UCNTL;
1126                         }
1127                         lwkt_reltoken(&tty_token);
1128                         return (0);
1129
1130                 case TIOCREMOTE:
1131                         if (*(int *)ap->a_data)
1132                                 pti->pt_flags |= PF_REMOTE;
1133                         else
1134                                 pti->pt_flags &= ~PF_REMOTE;
1135                         ttyflush(tp, FREAD|FWRITE);
1136                         lwkt_reltoken(&tty_token);
1137                         return (0);
1138
1139 #ifdef UNIX98_PTYS
1140                 case TIOCISPTMASTER:
1141                         if ((pti->pt_flags & PF_UNIX98) &&
1142                             (pti->devc == dev)) {
1143                                 lwkt_reltoken(&tty_token);
1144                                 return (0);
1145                         } else {
1146                                 lwkt_reltoken(&tty_token);
1147                                 return (EINVAL);
1148                         }
1149                 }
1150 #endif
1151
1152                 /*
1153                  * The rest of the ioctls shouldn't be called until 
1154                  * the slave is open.
1155                  */
1156                 if ((tp->t_state & TS_ISOPEN) == 0) {
1157                         lwkt_reltoken(&tty_token);
1158                         return (EAGAIN);
1159                 }
1160
1161                 switch (ap->a_cmd) {
1162 #ifdef COMPAT_43
1163                 case TIOCSETP:
1164                 case TIOCSETN:
1165 #endif
1166                 case TIOCSETD:
1167                 case TIOCSETA:
1168                 case TIOCSETAW:
1169                 case TIOCSETAF:
1170                         /*
1171                          * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
1172                          * ttywflush(tp) will hang if there are characters in
1173                          * the outq.
1174                          */
1175                         ndflush(&tp->t_outq, tp->t_outq.c_cc);
1176                         break;
1177
1178                 case TIOCSIG:
1179                         if (*(unsigned int *)ap->a_data >= NSIG ||
1180                             *(unsigned int *)ap->a_data == 0) {
1181                                 lwkt_reltoken(&tty_token);
1182                                 return(EINVAL);
1183                         }
1184                         if ((tp->t_lflag&NOFLSH) == 0)
1185                                 ttyflush(tp, FREAD|FWRITE);
1186                         pgsignal(tp->t_pgrp, *(unsigned int *)ap->a_data, 1);
1187                         if ((*(unsigned int *)ap->a_data == SIGINFO) &&
1188                             ((tp->t_lflag&NOKERNINFO) == 0))
1189                                 ttyinfo(tp);
1190                         lwkt_reltoken(&tty_token);
1191                         return(0);
1192                 }
1193         }
1194         if (ap->a_cmd == TIOCEXT) {
1195                 /*
1196                  * When the EXTPROC bit is being toggled, we need
1197                  * to send an TIOCPKT_IOCTL if the packet driver
1198                  * is turned on.
1199                  */
1200                 if (*(int *)ap->a_data) {
1201                         if (pti->pt_flags & PF_PKT) {
1202                                 pti->pt_send |= TIOCPKT_IOCTL;
1203                                 ptcwakeup(tp, FREAD);
1204                         }
1205                         tp->t_lflag |= EXTPROC;
1206                 } else {
1207                         if ((tp->t_lflag & EXTPROC) &&
1208                             (pti->pt_flags & PF_PKT)) {
1209                                 pti->pt_send |= TIOCPKT_IOCTL;
1210                                 ptcwakeup(tp, FREAD);
1211                         }
1212                         tp->t_lflag &= ~EXTPROC;
1213                 }
1214                 lwkt_reltoken(&tty_token);
1215                 return(0);
1216         }
1217         error = (*linesw[tp->t_line].l_ioctl)(tp, ap->a_cmd, ap->a_data,
1218                                               ap->a_fflag, ap->a_cred);
1219         if (error == ENOIOCTL)
1220                  error = ttioctl(tp, ap->a_cmd, ap->a_data, ap->a_fflag);
1221         if (error == ENOIOCTL) {
1222                 if (pti->pt_flags & PF_UCNTL &&
1223                     (ap->a_cmd & ~0xff) == UIOCCMD(0)) {
1224                         if (ap->a_cmd & 0xff) {
1225                                 pti->pt_ucntl = (u_char)ap->a_cmd;
1226                                 ptcwakeup(tp, FREAD);
1227                         }
1228                         lwkt_reltoken(&tty_token);
1229                         return (0);
1230                 }
1231                 error = ENOTTY;
1232         }
1233         /*
1234          * If external processing and packet mode send ioctl packet.
1235          */
1236         if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) {
1237                 switch(ap->a_cmd) {
1238                 case TIOCSETA:
1239                 case TIOCSETAW:
1240                 case TIOCSETAF:
1241 #ifdef COMPAT_43
1242                 case TIOCSETP:
1243                 case TIOCSETN:
1244 #endif
1245 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1246                 case TIOCSETC:
1247                 case TIOCSLTC:
1248                 case TIOCLBIS:
1249                 case TIOCLBIC:
1250                 case TIOCLSET:
1251 #endif
1252                         pti->pt_send |= TIOCPKT_IOCTL;
1253                         ptcwakeup(tp, FREAD);
1254                 default:
1255                         break;
1256                 }
1257         }
1258         stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
1259                 && CCEQ(cc[VSTART], CTRL('q'));
1260         if (pti->pt_flags & PF_NOSTOP) {
1261                 if (stop) {
1262                         pti->pt_send &= ~TIOCPKT_NOSTOP;
1263                         pti->pt_send |= TIOCPKT_DOSTOP;
1264                         pti->pt_flags &= ~PF_NOSTOP;
1265                         ptcwakeup(tp, FREAD);
1266                 }
1267         } else {
1268                 if (!stop) {
1269                         pti->pt_send &= ~TIOCPKT_DOSTOP;
1270                         pti->pt_send |= TIOCPKT_NOSTOP;
1271                         pti->pt_flags |= PF_NOSTOP;
1272                         ptcwakeup(tp, FREAD);
1273                 }
1274         }
1275         lwkt_reltoken(&tty_token);
1276         return (error);
1277 }
1278
1279
1280 static void ptc_drvinit (void *unused);
1281
1282 #ifdef UNIX98_PTYS
1283 SYSCTL_INT(_kern, OID_AUTO, pty_debug, CTLFLAG_RW, &pty_debug_level,
1284                 0, "Change pty debug level");
1285 #endif
1286
1287 static void
1288 ptc_drvinit(void *unused)
1289 {
1290         int i;
1291
1292 #ifdef UNIX98_PTYS
1293         /*
1294          * Unix98 pty stuff.
1295          * Create the clonable base device.
1296          */
1297         make_autoclone_dev(&ptc_ops, &DEVFS_CLONE_BITMAP(pty), ptyclone,
1298             0, 0, 0666, "ptmx");
1299 #endif
1300
1301         for (i = 0; i < 256; i++) {
1302                 ptyinit(i);
1303         }
1304 }
1305
1306 SYSINIT(ptcdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR_C,ptc_drvinit,NULL)