Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee13...
[pandora-kernel.git] / drivers / char / tty_ioctl.c
1 /*
2  *  linux/drivers/char/tty_ioctl.c
3  *
4  *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
5  *
6  * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
7  * which can be dynamically activated and de-activated by the line
8  * discipline handling modules (like SLIP).
9  */
10
11 #include <linux/types.h>
12 #include <linux/termios.h>
13 #include <linux/errno.h>
14 #include <linux/sched.h>
15 #include <linux/kernel.h>
16 #include <linux/major.h>
17 #include <linux/tty.h>
18 #include <linux/fcntl.h>
19 #include <linux/string.h>
20 #include <linux/mm.h>
21 #include <linux/module.h>
22 #include <linux/bitops.h>
23 #include <linux/mutex.h>
24
25 #include <asm/io.h>
26 #include <asm/uaccess.h>
27 #include <asm/system.h>
28
29 #undef TTY_DEBUG_WAIT_UNTIL_SENT
30
31 #undef  DEBUG
32
33 /*
34  * Internal flag options for termios setting behavior
35  */
36 #define TERMIOS_FLUSH   1
37 #define TERMIOS_WAIT    2
38 #define TERMIOS_TERMIO  4
39
40
41 /**
42  *      tty_wait_until_sent     -       wait for I/O to finish
43  *      @tty: tty we are waiting for
44  *      @timeout: how long we will wait
45  *
46  *      Wait for characters pending in a tty driver to hit the wire, or
47  *      for a timeout to occur (eg due to flow control)
48  *
49  *      Locking: none
50  */
51
52 void tty_wait_until_sent(struct tty_struct * tty, long timeout)
53 {
54         DECLARE_WAITQUEUE(wait, current);
55
56 #ifdef TTY_DEBUG_WAIT_UNTIL_SENT
57         char buf[64];
58         
59         printk(KERN_DEBUG "%s wait until sent...\n", tty_name(tty, buf));
60 #endif
61         if (!tty->driver->chars_in_buffer)
62                 return;
63         add_wait_queue(&tty->write_wait, &wait);
64         if (!timeout)
65                 timeout = MAX_SCHEDULE_TIMEOUT;
66         do {
67 #ifdef TTY_DEBUG_WAIT_UNTIL_SENT
68                 printk(KERN_DEBUG "waiting %s...(%d)\n", tty_name(tty, buf),
69                        tty->driver->chars_in_buffer(tty));
70 #endif
71                 set_current_state(TASK_INTERRUPTIBLE);
72                 if (signal_pending(current))
73                         goto stop_waiting;
74                 if (!tty->driver->chars_in_buffer(tty))
75                         break;
76                 timeout = schedule_timeout(timeout);
77         } while (timeout);
78         if (tty->driver->wait_until_sent)
79                 tty->driver->wait_until_sent(tty, timeout);
80 stop_waiting:
81         set_current_state(TASK_RUNNING);
82         remove_wait_queue(&tty->write_wait, &wait);
83 }
84
85 EXPORT_SYMBOL(tty_wait_until_sent);
86
87 static void unset_locked_termios(struct termios *termios,
88                                  struct termios *old,
89                                  struct termios *locked)
90 {
91         int     i;
92         
93 #define NOSET_MASK(x,y,z) (x = ((x) & ~(z)) | ((y) & (z)))
94
95         if (!locked) {
96                 printk(KERN_WARNING "Warning?!? termios_locked is NULL.\n");
97                 return;
98         }
99
100         NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag);
101         NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag);
102         NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag);
103         NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag);
104         termios->c_line = locked->c_line ? old->c_line : termios->c_line;
105         for (i=0; i < NCCS; i++)
106                 termios->c_cc[i] = locked->c_cc[i] ?
107                         old->c_cc[i] : termios->c_cc[i];
108 }
109
110 /**
111  *      change_termios          -       update termios values
112  *      @tty: tty to update
113  *      @new_termios: desired new value
114  *
115  *      Perform updates to the termios values set on this terminal. There
116  *      is a bit of layering violation here with n_tty in terms of the
117  *      internal knowledge of this function.
118  *
119  *      Locking: termios_sem
120  */
121
122 static void change_termios(struct tty_struct * tty, struct termios * new_termios)
123 {
124         int canon_change;
125         struct termios old_termios = *tty->termios;
126         struct tty_ldisc *ld;
127         
128         /*
129          *      Perform the actual termios internal changes under lock.
130          */
131          
132
133         /* FIXME: we need to decide on some locking/ordering semantics
134            for the set_termios notification eventually */
135         mutex_lock(&tty->termios_mutex);
136
137         *tty->termios = *new_termios;
138         unset_locked_termios(tty->termios, &old_termios, tty->termios_locked);
139         canon_change = (old_termios.c_lflag ^ tty->termios->c_lflag) & ICANON;
140         if (canon_change) {
141                 memset(&tty->read_flags, 0, sizeof tty->read_flags);
142                 tty->canon_head = tty->read_tail;
143                 tty->canon_data = 0;
144                 tty->erasing = 0;
145         }
146         
147         
148         if (canon_change && !L_ICANON(tty) && tty->read_cnt)
149                 /* Get characters left over from canonical mode. */
150                 wake_up_interruptible(&tty->read_wait);
151
152         /* See if packet mode change of state. */
153
154         if (tty->link && tty->link->packet) {
155                 int old_flow = ((old_termios.c_iflag & IXON) &&
156                                 (old_termios.c_cc[VSTOP] == '\023') &&
157                                 (old_termios.c_cc[VSTART] == '\021'));
158                 int new_flow = (I_IXON(tty) &&
159                                 STOP_CHAR(tty) == '\023' &&
160                                 START_CHAR(tty) == '\021');
161                 if (old_flow != new_flow) {
162                         tty->ctrl_status &= ~(TIOCPKT_DOSTOP | TIOCPKT_NOSTOP);
163                         if (new_flow)
164                                 tty->ctrl_status |= TIOCPKT_DOSTOP;
165                         else
166                                 tty->ctrl_status |= TIOCPKT_NOSTOP;
167                         wake_up_interruptible(&tty->link->read_wait);
168                 }
169         }
170            
171         if (tty->driver->set_termios)
172                 (*tty->driver->set_termios)(tty, &old_termios);
173
174         ld = tty_ldisc_ref(tty);
175         if (ld != NULL) {
176                 if (ld->set_termios)
177                         (ld->set_termios)(tty, &old_termios);
178                 tty_ldisc_deref(ld);
179         }
180         mutex_unlock(&tty->termios_mutex);
181 }
182
183 /**
184  *      set_termios             -       set termios values for a tty
185  *      @tty: terminal device
186  *      @arg: user data
187  *      @opt: option information
188  *
189  *      Helper function to prepare termios data and run neccessary other
190  *      functions before using change_termios to do the actual changes.
191  *
192  *      Locking:
193  *              Called functions take ldisc and termios_sem locks
194  */
195
196 static int set_termios(struct tty_struct * tty, void __user *arg, int opt)
197 {
198         struct termios tmp_termios;
199         struct tty_ldisc *ld;
200         int retval = tty_check_change(tty);
201
202         if (retval)
203                 return retval;
204
205         if (opt & TERMIOS_TERMIO) {
206                 memcpy(&tmp_termios, tty->termios, sizeof(struct termios));
207                 if (user_termio_to_kernel_termios(&tmp_termios,
208                                                 (struct termio __user *)arg))
209                         return -EFAULT;
210         } else {
211                 if (user_termios_to_kernel_termios(&tmp_termios,
212                                                 (struct termios __user *)arg))
213                         return -EFAULT;
214         }
215
216         ld = tty_ldisc_ref(tty);
217         
218         if (ld != NULL) {
219                 if ((opt & TERMIOS_FLUSH) && ld->flush_buffer)
220                         ld->flush_buffer(tty);
221                 tty_ldisc_deref(ld);
222         }
223         
224         if (opt & TERMIOS_WAIT) {
225                 tty_wait_until_sent(tty, 0);
226                 if (signal_pending(current))
227                         return -EINTR;
228         }
229
230         change_termios(tty, &tmp_termios);
231         return 0;
232 }
233
234 static int get_termio(struct tty_struct * tty, struct termio __user * termio)
235 {
236         if (kernel_termios_to_user_termio(termio, tty->termios))
237                 return -EFAULT;
238         return 0;
239 }
240
241 static unsigned long inq_canon(struct tty_struct * tty)
242 {
243         int nr, head, tail;
244
245         if (!tty->canon_data || !tty->read_buf)
246                 return 0;
247         head = tty->canon_head;
248         tail = tty->read_tail;
249         nr = (head - tail) & (N_TTY_BUF_SIZE-1);
250         /* Skip EOF-chars.. */
251         while (head != tail) {
252                 if (test_bit(tail, tty->read_flags) &&
253                     tty->read_buf[tail] == __DISABLED_CHAR)
254                         nr--;
255                 tail = (tail+1) & (N_TTY_BUF_SIZE-1);
256         }
257         return nr;
258 }
259
260 #ifdef TIOCGETP
261 /*
262  * These are deprecated, but there is limited support..
263  *
264  * The "sg_flags" translation is a joke..
265  */
266 static int get_sgflags(struct tty_struct * tty)
267 {
268         int flags = 0;
269
270         if (!(tty->termios->c_lflag & ICANON)) {
271                 if (tty->termios->c_lflag & ISIG)
272                         flags |= 0x02;          /* cbreak */
273                 else
274                         flags |= 0x20;          /* raw */
275         }
276         if (tty->termios->c_lflag & ECHO)
277                 flags |= 0x08;                  /* echo */
278         if (tty->termios->c_oflag & OPOST)
279                 if (tty->termios->c_oflag & ONLCR)
280                         flags |= 0x10;          /* crmod */
281         return flags;
282 }
283
284 static int get_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb)
285 {
286         struct sgttyb tmp;
287
288         mutex_lock(&tty->termios_mutex);
289         tmp.sg_ispeed = 0;
290         tmp.sg_ospeed = 0;
291         tmp.sg_erase = tty->termios->c_cc[VERASE];
292         tmp.sg_kill = tty->termios->c_cc[VKILL];
293         tmp.sg_flags = get_sgflags(tty);
294         mutex_unlock(&tty->termios_mutex);
295         
296         return copy_to_user(sgttyb, &tmp, sizeof(tmp)) ? -EFAULT : 0;
297 }
298
299 static void set_sgflags(struct termios * termios, int flags)
300 {
301         termios->c_iflag = ICRNL | IXON;
302         termios->c_oflag = 0;
303         termios->c_lflag = ISIG | ICANON;
304         if (flags & 0x02) {     /* cbreak */
305                 termios->c_iflag = 0;
306                 termios->c_lflag &= ~ICANON;
307         }
308         if (flags & 0x08) {             /* echo */
309                 termios->c_lflag |= ECHO | ECHOE | ECHOK |
310                                     ECHOCTL | ECHOKE | IEXTEN;
311         }
312         if (flags & 0x10) {             /* crmod */
313                 termios->c_oflag |= OPOST | ONLCR;
314         }
315         if (flags & 0x20) {     /* raw */
316                 termios->c_iflag = 0;
317                 termios->c_lflag &= ~(ISIG | ICANON);
318         }
319         if (!(termios->c_lflag & ICANON)) {
320                 termios->c_cc[VMIN] = 1;
321                 termios->c_cc[VTIME] = 0;
322         }
323 }
324
325 /**
326  *      set_sgttyb              -       set legacy terminal values
327  *      @tty: tty structure
328  *      @sgttyb: pointer to old style terminal structure
329  *
330  *      Updates a terminal from the legacy BSD style terminal information
331  *      structure.
332  *
333  *      Locking: termios_sem
334  */
335
336 static int set_sgttyb(struct tty_struct * tty, struct sgttyb __user * sgttyb)
337 {
338         int retval;
339         struct sgttyb tmp;
340         struct termios termios;
341
342         retval = tty_check_change(tty);
343         if (retval)
344                 return retval;
345         
346         if (copy_from_user(&tmp, sgttyb, sizeof(tmp)))
347                 return -EFAULT;
348
349         mutex_lock(&tty->termios_mutex);
350         termios =  *tty->termios;
351         termios.c_cc[VERASE] = tmp.sg_erase;
352         termios.c_cc[VKILL] = tmp.sg_kill;
353         set_sgflags(&termios, tmp.sg_flags);
354         mutex_unlock(&tty->termios_mutex);
355         change_termios(tty, &termios);
356         return 0;
357 }
358 #endif
359
360 #ifdef TIOCGETC
361 static int get_tchars(struct tty_struct * tty, struct tchars __user * tchars)
362 {
363         struct tchars tmp;
364
365         tmp.t_intrc = tty->termios->c_cc[VINTR];
366         tmp.t_quitc = tty->termios->c_cc[VQUIT];
367         tmp.t_startc = tty->termios->c_cc[VSTART];
368         tmp.t_stopc = tty->termios->c_cc[VSTOP];
369         tmp.t_eofc = tty->termios->c_cc[VEOF];
370         tmp.t_brkc = tty->termios->c_cc[VEOL2]; /* what is brkc anyway? */
371         return copy_to_user(tchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
372 }
373
374 static int set_tchars(struct tty_struct * tty, struct tchars __user * tchars)
375 {
376         struct tchars tmp;
377
378         if (copy_from_user(&tmp, tchars, sizeof(tmp)))
379                 return -EFAULT;
380         tty->termios->c_cc[VINTR] = tmp.t_intrc;
381         tty->termios->c_cc[VQUIT] = tmp.t_quitc;
382         tty->termios->c_cc[VSTART] = tmp.t_startc;
383         tty->termios->c_cc[VSTOP] = tmp.t_stopc;
384         tty->termios->c_cc[VEOF] = tmp.t_eofc;
385         tty->termios->c_cc[VEOL2] = tmp.t_brkc; /* what is brkc anyway? */
386         return 0;
387 }
388 #endif
389
390 #ifdef TIOCGLTC
391 static int get_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars)
392 {
393         struct ltchars tmp;
394
395         tmp.t_suspc = tty->termios->c_cc[VSUSP];
396         tmp.t_dsuspc = tty->termios->c_cc[VSUSP];       /* what is dsuspc anyway? */
397         tmp.t_rprntc = tty->termios->c_cc[VREPRINT];
398         tmp.t_flushc = tty->termios->c_cc[VEOL2];       /* what is flushc anyway? */
399         tmp.t_werasc = tty->termios->c_cc[VWERASE];
400         tmp.t_lnextc = tty->termios->c_cc[VLNEXT];
401         return copy_to_user(ltchars, &tmp, sizeof(tmp)) ? -EFAULT : 0;
402 }
403
404 static int set_ltchars(struct tty_struct * tty, struct ltchars __user * ltchars)
405 {
406         struct ltchars tmp;
407
408         if (copy_from_user(&tmp, ltchars, sizeof(tmp)))
409                 return -EFAULT;
410
411         tty->termios->c_cc[VSUSP] = tmp.t_suspc;
412         tty->termios->c_cc[VEOL2] = tmp.t_dsuspc;       /* what is dsuspc anyway? */
413         tty->termios->c_cc[VREPRINT] = tmp.t_rprntc;
414         tty->termios->c_cc[VEOL2] = tmp.t_flushc;       /* what is flushc anyway? */
415         tty->termios->c_cc[VWERASE] = tmp.t_werasc;
416         tty->termios->c_cc[VLNEXT] = tmp.t_lnextc;
417         return 0;
418 }
419 #endif
420
421 /**
422  *      send_prio_char          -       send priority character
423  *
424  *      Send a high priority character to the tty even if stopped
425  *
426  *      Locking: none for xchar method, write ordering for write method.
427  */
428
429 static int send_prio_char(struct tty_struct *tty, char ch)
430 {
431         int     was_stopped = tty->stopped;
432
433         if (tty->driver->send_xchar) {
434                 tty->driver->send_xchar(tty, ch);
435                 return 0;
436         }
437
438         if (mutex_lock_interruptible(&tty->atomic_write_lock))
439                 return -ERESTARTSYS;
440
441         if (was_stopped)
442                 start_tty(tty);
443         tty->driver->write(tty, &ch, 1);
444         if (was_stopped)
445                 stop_tty(tty);
446         mutex_unlock(&tty->atomic_write_lock);
447         return 0;
448 }
449
450 int n_tty_ioctl(struct tty_struct * tty, struct file * file,
451                        unsigned int cmd, unsigned long arg)
452 {
453         struct tty_struct * real_tty;
454         void __user *p = (void __user *)arg;
455         int retval;
456         struct tty_ldisc *ld;
457
458         if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
459             tty->driver->subtype == PTY_TYPE_MASTER)
460                 real_tty = tty->link;
461         else
462                 real_tty = tty;
463
464         switch (cmd) {
465 #ifdef TIOCGETP
466                 case TIOCGETP:
467                         return get_sgttyb(real_tty, (struct sgttyb __user *) arg);
468                 case TIOCSETP:
469                 case TIOCSETN:
470                         return set_sgttyb(real_tty, (struct sgttyb __user *) arg);
471 #endif
472 #ifdef TIOCGETC
473                 case TIOCGETC:
474                         return get_tchars(real_tty, p);
475                 case TIOCSETC:
476                         return set_tchars(real_tty, p);
477 #endif
478 #ifdef TIOCGLTC
479                 case TIOCGLTC:
480                         return get_ltchars(real_tty, p);
481                 case TIOCSLTC:
482                         return set_ltchars(real_tty, p);
483 #endif
484                 case TCGETS:
485                         if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios))
486                                 return -EFAULT;
487                         return 0;
488                 case TCSETSF:
489                         return set_termios(real_tty, p,  TERMIOS_FLUSH | TERMIOS_WAIT);
490                 case TCSETSW:
491                         return set_termios(real_tty, p, TERMIOS_WAIT);
492                 case TCSETS:
493                         return set_termios(real_tty, p, 0);
494                 case TCGETA:
495                         return get_termio(real_tty, p);
496                 case TCSETAF:
497                         return set_termios(real_tty, p, TERMIOS_FLUSH | TERMIOS_WAIT | TERMIOS_TERMIO);
498                 case TCSETAW:
499                         return set_termios(real_tty, p, TERMIOS_WAIT | TERMIOS_TERMIO);
500                 case TCSETA:
501                         return set_termios(real_tty, p, TERMIOS_TERMIO);
502                 case TCXONC:
503                         retval = tty_check_change(tty);
504                         if (retval)
505                                 return retval;
506                         switch (arg) {
507                         case TCOOFF:
508                                 if (!tty->flow_stopped) {
509                                         tty->flow_stopped = 1;
510                                         stop_tty(tty);
511                                 }
512                                 break;
513                         case TCOON:
514                                 if (tty->flow_stopped) {
515                                         tty->flow_stopped = 0;
516                                         start_tty(tty);
517                                 }
518                                 break;
519                         case TCIOFF:
520                                 if (STOP_CHAR(tty) != __DISABLED_CHAR)
521                                         return send_prio_char(tty, STOP_CHAR(tty));
522                                 break;
523                         case TCION:
524                                 if (START_CHAR(tty) != __DISABLED_CHAR)
525                                         return send_prio_char(tty, START_CHAR(tty));
526                                 break;
527                         default:
528                                 return -EINVAL;
529                         }
530                         return 0;
531                 case TCFLSH:
532                         retval = tty_check_change(tty);
533                         if (retval)
534                                 return retval;
535                                 
536                         ld = tty_ldisc_ref(tty);
537                         switch (arg) {
538                         case TCIFLUSH:
539                                 if (ld && ld->flush_buffer)
540                                         ld->flush_buffer(tty);
541                                 break;
542                         case TCIOFLUSH:
543                                 if (ld && ld->flush_buffer)
544                                         ld->flush_buffer(tty);
545                                 /* fall through */
546                         case TCOFLUSH:
547                                 if (tty->driver->flush_buffer)
548                                         tty->driver->flush_buffer(tty);
549                                 break;
550                         default:
551                                 tty_ldisc_deref(ld);
552                                 return -EINVAL;
553                         }
554                         tty_ldisc_deref(ld);
555                         return 0;
556                 case TIOCOUTQ:
557                         return put_user(tty->driver->chars_in_buffer ?
558                                         tty->driver->chars_in_buffer(tty) : 0,
559                                         (int __user *) arg);
560                 case TIOCINQ:
561                         retval = tty->read_cnt;
562                         if (L_ICANON(tty))
563                                 retval = inq_canon(tty);
564                         return put_user(retval, (unsigned int __user *) arg);
565                 case TIOCGLCKTRMIOS:
566                         if (kernel_termios_to_user_termios((struct termios __user *)arg, real_tty->termios_locked))
567                                 return -EFAULT;
568                         return 0;
569
570                 case TIOCSLCKTRMIOS:
571                         if (!capable(CAP_SYS_ADMIN))
572                                 return -EPERM;
573                         if (user_termios_to_kernel_termios(real_tty->termios_locked, (struct termios __user *) arg))
574                                 return -EFAULT;
575                         return 0;
576
577                 case TIOCPKT:
578                 {
579                         int pktmode;
580
581                         if (tty->driver->type != TTY_DRIVER_TYPE_PTY ||
582                             tty->driver->subtype != PTY_TYPE_MASTER)
583                                 return -ENOTTY;
584                         if (get_user(pktmode, (int __user *) arg))
585                                 return -EFAULT;
586                         if (pktmode) {
587                                 if (!tty->packet) {
588                                         tty->packet = 1;
589                                         tty->link->ctrl_status = 0;
590                                 }
591                         } else
592                                 tty->packet = 0;
593                         return 0;
594                 }
595                 case TIOCGSOFTCAR:
596                         return put_user(C_CLOCAL(tty) ? 1 : 0, (int __user *)arg);
597                 case TIOCSSOFTCAR:
598                         if (get_user(arg, (unsigned int __user *) arg))
599                                 return -EFAULT;
600                         mutex_lock(&tty->termios_mutex);
601                         tty->termios->c_cflag =
602                                 ((tty->termios->c_cflag & ~CLOCAL) |
603                                  (arg ? CLOCAL : 0));
604                         mutex_unlock(&tty->termios_mutex);
605                         return 0;
606                 default:
607                         return -ENOIOCTLCMD;
608                 }
609 }
610
611 EXPORT_SYMBOL(n_tty_ioctl);