root/drivers/char/pty.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pty_close
  2. pty_write
  3. pty_write_room
  4. pty_chars_in_buffer
  5. pty_flush_buffer
  6. pty_open
  7. pty_init

   1 /*
   2  *  linux/kernel/chr_drv/pty.c
   3  *
   4  *  Copyright (C) 1991, 1992  Linus Torvalds
   5  */
   6 
   7 /*
   8  *      pty.c
   9  *
  10  * This module exports the following pty function:
  11  * 
  12  *      int  pty_open(struct tty_struct * tty, struct file * filp);
  13  */
  14 
  15 #include <linux/errno.h>
  16 #include <linux/sched.h>
  17 #include <linux/interrupt.h>
  18 #include <linux/tty.h>
  19 #include <linux/tty_flip.h>
  20 #include <linux/fcntl.h>
  21 #include <linux/string.h>
  22 #include <linux/major.h>
  23 #include <linux/mm.h>
  24 
  25 #include <asm/segment.h>
  26 #include <asm/system.h>
  27 #include <asm/bitops.h>
  28 
  29 struct pty_struct {
  30         int     magic;
  31         struct wait_queue * open_wait;
  32 };
  33 
  34 #define PTY_MAGIC 0x5001
  35 
  36 #define PTY_BUF_SIZE PAGE_SIZE/2
  37 
  38 /*
  39  * tmp_buf is used as a temporary buffer by pty_write.  We need to
  40  * lock it in case the memcpy_fromfs blocks while swapping in a page,
  41  * and some other program tries to do a pty write at the same time.
  42  * Since the lock will only come under contention when the system is
  43  * swapping and available memory is low, it makes sense to share one
  44  * buffer across all the PTY's, since it significantly saves memory if
  45  * large numbers of PTY's are open.
  46  */
  47 static unsigned char *tmp_buf;
  48 static struct semaphore tmp_buf_sem = MUTEX;
  49 
  50 struct tty_driver pty_driver, pty_slave_driver;
  51 static int pty_refcount;
  52 
  53 static struct tty_struct *pty_table[NR_PTYS];
  54 static struct termios *pty_termios[NR_PTYS];
  55 static struct termios *pty_termios_locked[NR_PTYS];
  56 static struct tty_struct *ttyp_table[NR_PTYS];
  57 static struct termios *ttyp_termios[NR_PTYS];
  58 static struct termios *ttyp_termios_locked[NR_PTYS];
  59 static struct pty_struct pty_state[NR_PTYS];
  60 
  61 #define MIN(a,b)        ((a) < (b) ? (a) : (b))
  62 
  63 static void pty_close(struct tty_struct * tty, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
  64 {
  65         if (!tty)
  66                 return;
  67         if (tty->driver.subtype == PTY_TYPE_MASTER) {
  68                 if (tty->count > 1)
  69                         printk("master pty_close: count = %d!!\n", tty->count);
  70         } else {
  71                 if (tty->count > 2)
  72                         return;
  73         }
  74         wake_up_interruptible(&tty->read_wait);
  75         wake_up_interruptible(&tty->write_wait);
  76         if (!tty->link)
  77                 return;
  78         wake_up_interruptible(&tty->link->read_wait);
  79         wake_up_interruptible(&tty->link->write_wait);
  80         if (tty->driver.subtype == PTY_TYPE_MASTER)
  81                 tty_hangup(tty->link);
  82         else {
  83                 start_tty(tty);
  84                 set_bit(TTY_SLAVE_CLOSED, &tty->link->flags);
  85         }
  86 }
  87 
  88 static int pty_write(struct tty_struct * tty, int from_user,
     /* [previous][next][first][last][top][bottom][index][help] */
  89                        unsigned char *buf, int count)
  90 {
  91         struct tty_struct *to = tty->link;
  92         int     c=0, n, r;
  93         char    *temp_buffer;
  94 
  95         if (!to || tty->stopped)
  96                 return 0;
  97         
  98         if (from_user) {
  99                 down(&tmp_buf_sem);
 100                 temp_buffer = tmp_buf +
 101                         ((tty->driver.subtype-1) * PTY_BUF_SIZE);
 102                 while (count > 0) {
 103                         n = MIN(count, PTY_BUF_SIZE);
 104                         memcpy_fromfs(temp_buffer, buf, n);
 105                         r = to->ldisc.receive_room(to);
 106                         if (r <= 0)
 107                                 break;
 108                         n = MIN(n, r);
 109                         to->ldisc.receive_buf(to, temp_buffer, 0, n);
 110                         buf += n;  c+= n;
 111                         count -= n;
 112                 }
 113                 up(&tmp_buf_sem);
 114         } else {
 115                 c = MIN(count, to->ldisc.receive_room(to));
 116                 to->ldisc.receive_buf(to, buf, 0, c);
 117         }
 118         
 119         return c;
 120 }
 121 
 122 static int pty_write_room(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 123 {
 124         struct tty_struct *to = tty->link;
 125 
 126         if (!to || tty->stopped)
 127                 return 0;
 128 
 129         return to->ldisc.receive_room(to);
 130 }
 131 
 132 static int pty_chars_in_buffer(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 133 {
 134         struct tty_struct *to = tty->link;
 135 
 136         if (!to || !to->ldisc.chars_in_buffer)
 137                 return 0;
 138 
 139         return to->ldisc.chars_in_buffer(to);
 140 }
 141 
 142 static void pty_flush_buffer(struct tty_struct *tty)
     /* [previous][next][first][last][top][bottom][index][help] */
 143 {
 144         struct tty_struct *to = tty->link;
 145         
 146         if (!to)
 147                 return;
 148         
 149         if (to->ldisc.flush_buffer)
 150                 to->ldisc.flush_buffer(to);
 151         
 152         if (to->packet) {
 153                 tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
 154                 wake_up_interruptible(&to->read_wait);
 155         }
 156 }
 157 
 158 int pty_open(struct tty_struct *tty, struct file * filp)
     /* [previous][next][first][last][top][bottom][index][help] */
 159 {
 160         int     line;
 161         struct  pty_struct *pty;
 162         
 163         if (!tty || !tty->link)
 164                 return -ENODEV;
 165         line = MINOR(tty->device) - tty->driver.minor_start;
 166         if ((line < 0) || (line >= NR_PTYS))
 167                 return -ENODEV;
 168         pty = pty_state + line;
 169         tty->driver_data = pty;
 170 
 171         if (!tmp_buf) {
 172                 tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL);
 173                 if (!tmp_buf)
 174                         return -ENOMEM;
 175         }
 176 
 177         if (tty->driver.subtype == PTY_TYPE_SLAVE)
 178                 clear_bit(TTY_SLAVE_CLOSED, &tty->link->flags);
 179         wake_up_interruptible(&pty->open_wait);
 180         if (filp->f_flags & O_NDELAY)
 181                 return 0;
 182         while (!tty->link->count && !(current->signal & ~current->blocked))
 183                 interruptible_sleep_on(&pty->open_wait);
 184         if (!tty->link->count)
 185                 return -ERESTARTSYS;
 186         return 0;
 187 }
 188 
 189 long pty_init(long kmem_start)
     /* [previous][next][first][last][top][bottom][index][help] */
 190 {
 191         memset(&pty_state, 0, sizeof(pty_state));
 192         memset(&pty_driver, 0, sizeof(struct tty_driver));
 193         pty_driver.magic = TTY_DRIVER_MAGIC;
 194         pty_driver.name = "pty";
 195         pty_driver.major = TTY_MAJOR;
 196         pty_driver.minor_start = 128;
 197         pty_driver.num = NR_PTYS;
 198         pty_driver.type = TTY_DRIVER_TYPE_PTY;
 199         pty_driver.subtype = PTY_TYPE_MASTER;
 200         pty_driver.init_termios = tty_std_termios;
 201         pty_driver.init_termios.c_iflag = 0;
 202         pty_driver.init_termios.c_oflag = 0;
 203         pty_driver.init_termios.c_cflag = B9600 | CS8 | CREAD;
 204         pty_driver.init_termios.c_lflag = 0;
 205         pty_driver.flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_REAL_RAW;
 206         pty_driver.refcount = &pty_refcount;
 207         pty_driver.table = pty_table;
 208         pty_driver.termios = pty_termios;
 209         pty_driver.termios_locked = pty_termios_locked;
 210         pty_driver.other = &pty_slave_driver;
 211 
 212         pty_driver.open = pty_open;
 213         pty_driver.close = pty_close;
 214         pty_driver.write = pty_write;
 215         pty_driver.write_room = pty_write_room;
 216         pty_driver.flush_buffer = pty_flush_buffer;
 217         pty_driver.chars_in_buffer = pty_chars_in_buffer;
 218 
 219         pty_slave_driver = pty_driver;
 220         pty_slave_driver.name = "ttyp";
 221         pty_slave_driver.subtype = PTY_TYPE_SLAVE;
 222         pty_slave_driver.minor_start = 192;
 223         pty_slave_driver.init_termios = tty_std_termios;
 224         pty_slave_driver.table = ttyp_table;
 225         pty_slave_driver.termios = ttyp_termios;
 226         pty_slave_driver.termios_locked = ttyp_termios_locked;
 227         pty_slave_driver.other = &pty_driver;
 228 
 229         tmp_buf = 0;
 230 
 231         if (tty_register_driver(&pty_driver))
 232                 panic("Couldn't register pty driver");
 233         if (tty_register_driver(&pty_slave_driver))
 234                 panic("Couldn't register pty slave driver");
 235         
 236         return kmem_start;
 237 }

/* [previous][next][first][last][top][bottom][index][help] */