This source file includes following definitions.
- change_speed
- flush
- wait_until_sent
- send_break
- do_get_ps_info
- get_termios
- set_termios
- get_termio
- set_termio
- set_window_size
- get_window_size
- tty_ioctl
1
2
3
4
5
6
7 #include <errno.h>
8 #include <termios.h>
9 #include <sys/types.h>
10
11 #include <linux/sched.h>
12 #include <linux/kernel.h>
13 #include <linux/tty.h>
14
15 #include <asm/io.h>
16 #include <asm/segment.h>
17 #include <asm/system.h>
18
19 extern int session_of_pgrp(int pgrp);
20 extern int do_screendump(int arg);
21 extern int kill_pg(int pgrp, int sig, int priv);
22 extern int vt_ioctl(struct tty_struct *tty, int dev, int cmd, int arg);
23
24 static unsigned short quotient[] = {
25 0, 2304, 1536, 1047, 857,
26 768, 576, 384, 192, 96,
27 64, 48, 24, 12, 6, 3
28 };
29
30 static void change_speed(struct tty_struct * tty)
31 {
32 unsigned short port,quot;
33
34 if (!(port = tty->read_q->data))
35 return;
36 quot = quotient[tty->termios.c_cflag & CBAUD];
37 cli();
38 outb_p(0x80,port+3);
39 outb_p(quot & 0xff,port);
40 outb_p(quot >> 8,port+1);
41 outb(0x03,port+3);
42 sti();
43 }
44
45 void flush(struct tty_queue * queue)
46 {
47 if (queue) {
48 cli();
49 queue->head = queue->tail;
50 sti();
51 wake_up(&queue->proc_list);
52 }
53 }
54
55 static void wait_until_sent(struct tty_struct * tty)
56 {
57 while (!(current->signal & ~current->blocked) && !EMPTY(tty->write_q)) {
58 TTY_WRITE_FLUSH(tty);
59 current->counter = 0;
60 cli();
61 if (EMPTY(tty->write_q))
62 break;
63 else
64 interruptible_sleep_on(&tty->write_q->proc_list);
65 sti();
66 }
67 sti();
68 }
69
70 static void send_break(struct tty_struct * tty)
71 {
72 unsigned short port;
73
74 if (!(port = tty->read_q->data))
75 return;
76 port += 3;
77 current->state = TASK_INTERRUPTIBLE;
78 current->timeout = jiffies + 25;
79 outb_p(inb_p(port) | 0x40,port);
80 schedule();
81 outb_p(inb_p(port) & 0xbf,port);
82 }
83
84 static int do_get_ps_info(int arg)
85 {
86 struct tstruct {
87 int flag;
88 int present[NR_TASKS];
89 struct task_struct tasks[NR_TASKS];
90 };
91 struct tstruct *ts = (struct tstruct *)arg;
92 struct task_struct **p;
93 char *c, *d;
94 int i, n = 0;
95
96 verify_area((void *)arg, sizeof(struct tstruct));
97
98 for (p = &FIRST_TASK ; p <= &LAST_TASK ; p++, n++)
99 if (*p)
100 {
101 c = (char *)(*p);
102 d = (char *)(ts->tasks+n);
103 for (i=0 ; i<sizeof(struct task_struct) ; i++)
104 put_fs_byte(*c++, d++);
105 put_fs_long(1, (unsigned long *)(ts->present+n));
106 }
107 else
108 put_fs_long(0, (unsigned long *)(ts->present+n));
109 return(0);
110 }
111
112 static int get_termios(struct tty_struct * tty, struct termios * termios)
113 {
114 int i;
115
116 verify_area(termios, sizeof (*termios));
117 for (i=0 ; i< (sizeof (*termios)) ; i++)
118 put_fs_byte( ((char *)&tty->termios)[i] , i+(char *)termios );
119 return 0;
120 }
121
122 static int set_termios(struct tty_struct * tty, struct termios * termios,
123 int channel)
124 {
125 int i;
126
127
128
129
130 if ((current->tty == channel) &&
131 (tty->pgrp != current->pgrp)) {
132 if (is_orphaned_pgrp(current->pgrp))
133 return -EIO;
134 if (!is_ignored(SIGTTOU))
135 return tty_signal(SIGTTOU, tty);
136 }
137 for (i=0 ; i< (sizeof (*termios)) ; i++)
138 ((char *)&tty->termios)[i]=get_fs_byte(i+(char *)termios);
139 change_speed(tty);
140 return 0;
141 }
142
143 static int get_termio(struct tty_struct * tty, struct termio * termio)
144 {
145 int i;
146 struct termio tmp_termio;
147
148 verify_area(termio, sizeof (*termio));
149 tmp_termio.c_iflag = tty->termios.c_iflag;
150 tmp_termio.c_oflag = tty->termios.c_oflag;
151 tmp_termio.c_cflag = tty->termios.c_cflag;
152 tmp_termio.c_lflag = tty->termios.c_lflag;
153 tmp_termio.c_line = tty->termios.c_line;
154 for(i=0 ; i < NCC ; i++)
155 tmp_termio.c_cc[i] = tty->termios.c_cc[i];
156 for (i=0 ; i< (sizeof (*termio)) ; i++)
157 put_fs_byte( ((char *)&tmp_termio)[i] , i+(char *)termio );
158 return 0;
159 }
160
161
162
163
164 static int set_termio(struct tty_struct * tty, struct termio * termio,
165 int channel)
166 {
167 int i;
168 struct termio tmp_termio;
169
170 if ((current->tty == channel) &&
171 (tty->pgrp > 0) &&
172 (tty->pgrp != current->pgrp)) {
173 if (is_orphaned_pgrp(current->pgrp))
174 return -EIO;
175 if (!is_ignored(SIGTTOU))
176 return tty_signal(SIGTTOU, tty);
177 }
178 for (i=0 ; i< (sizeof (*termio)) ; i++)
179 ((char *)&tmp_termio)[i]=get_fs_byte(i+(char *)termio);
180 *(unsigned short *)&tty->termios.c_iflag = tmp_termio.c_iflag;
181 *(unsigned short *)&tty->termios.c_oflag = tmp_termio.c_oflag;
182 *(unsigned short *)&tty->termios.c_cflag = tmp_termio.c_cflag;
183 *(unsigned short *)&tty->termios.c_lflag = tmp_termio.c_lflag;
184 tty->termios.c_line = tmp_termio.c_line;
185 for(i=0 ; i < NCC ; i++)
186 tty->termios.c_cc[i] = tmp_termio.c_cc[i];
187 change_speed(tty);
188 return 0;
189 }
190
191 static int set_window_size(struct tty_struct * tty, struct winsize * ws)
192 {
193 int i,changed;
194 char c, * tmp;
195
196 if (!ws)
197 return -EINVAL;
198 tmp = (char *) &tty->winsize;
199 changed = 0;
200 for (i = 0; i < sizeof (*ws) ; i++,tmp++) {
201 c = get_fs_byte(i + (char *) ws);
202 if (c == *tmp)
203 continue;
204 changed = 1;
205 *tmp = c;
206 }
207 if (changed)
208 kill_pg(tty->pgrp, SIGWINCH, 1);
209 return 0;
210 }
211
212 static int get_window_size(struct tty_struct * tty, struct winsize * ws)
213 {
214 int i;
215 char * tmp;
216
217 if (!ws)
218 return -EINVAL;
219 verify_area(ws, sizeof (*ws));
220 tmp = (char *) ws;
221 for (i = 0; i < sizeof (struct winsize) ; i++,tmp++)
222 put_fs_byte(((char *) &tty->winsize)[i], tmp);
223 return 0;
224 }
225
226 int tty_ioctl(struct inode * inode, struct file * file,
227 unsigned int cmd, unsigned int arg)
228 {
229 struct tty_struct * tty;
230 struct tty_struct * other_tty;
231 int pgrp;
232 int dev;
233
234 if (MAJOR(inode->i_rdev) == 5) {
235 dev = current->tty;
236 if (dev<0)
237 return -EINVAL;
238 } else
239 dev = MINOR(inode->i_rdev);
240 tty = tty_table + (dev ? ((dev < 64)? dev-1:dev) : fg_console);
241
242 if (IS_A_PTY(dev))
243 other_tty = tty_table + PTY_OTHER(dev);
244 else
245 other_tty = NULL;
246
247 if (!(tty->write_q && tty->read_q && tty->secondary && tty->write))
248 return -EINVAL;
249 switch (cmd) {
250 case TCGETS:
251 return get_termios(tty,(struct termios *) arg);
252 case TCSETSF:
253 flush(tty->read_q);
254 flush(tty->secondary);
255 if (other_tty)
256 flush(other_tty->write_q);
257
258 case TCSETSW:
259 wait_until_sent(tty);
260
261 case TCSETS:
262 return set_termios(tty,(struct termios *) arg, dev);
263 case TCGETA:
264 return get_termio(tty,(struct termio *) arg);
265 case TCSETAF:
266 flush(tty->read_q);
267 flush(tty->secondary);
268 if (other_tty)
269 flush(other_tty->write_q);
270
271 case TCSETAW:
272 wait_until_sent(tty);
273 case TCSETA:
274 return set_termio(tty,(struct termio *) arg, dev);
275 case TCSBRK:
276 wait_until_sent(tty);
277 if (!arg)
278 send_break(tty);
279 return 0;
280 case TCXONC:
281 switch (arg) {
282 case TCOOFF:
283 tty->stopped = 1;
284 TTY_WRITE_FLUSH(tty);
285 return 0;
286 case TCOON:
287 tty->stopped = 0;
288 TTY_WRITE_FLUSH(tty);
289 return 0;
290 case TCIOFF:
291 if (STOP_CHAR(tty))
292 PUTCH(STOP_CHAR(tty),tty->write_q);
293 return 0;
294 case TCION:
295 if (START_CHAR(tty))
296 PUTCH(START_CHAR(tty),tty->write_q);
297 return 0;
298 }
299 return -EINVAL;
300 case TCFLSH:
301 if (arg==0) {
302 flush(tty->read_q);
303 flush(tty->secondary);
304 if (other_tty)
305 flush(other_tty->write_q);
306 } else if (arg==1)
307 flush(tty->write_q);
308 else if (arg==2) {
309 flush(tty->read_q);
310 flush(tty->secondary);
311 flush(tty->write_q);
312 if (other_tty)
313 flush(other_tty->write_q);
314 } else
315 return -EINVAL;
316 return 0;
317 case TIOCEXCL:
318 return -EINVAL;
319 case TIOCNXCL:
320 return -EINVAL;
321 case TIOCSCTTY:
322 return -EINVAL;
323 case TIOCGPGRP:
324 verify_area((void *) arg,4);
325 put_fs_long(tty->pgrp,(unsigned long *) arg);
326 return 0;
327 case TIOCSPGRP:
328 if ((current->tty < 0) ||
329 (current->tty != dev) ||
330 (tty->session != current->session))
331 return -ENOTTY;
332 pgrp=get_fs_long((unsigned long *) arg);
333 if (pgrp < 0)
334 return -EINVAL;
335 if (session_of_pgrp(pgrp) != current->session)
336 return -EPERM;
337 tty->pgrp = pgrp;
338 return 0;
339 case TIOCOUTQ:
340 verify_area((void *) arg,4);
341 put_fs_long(CHARS(tty->write_q),(unsigned long *) arg);
342 return 0;
343 case TIOCINQ:
344 verify_area((void *) arg,4);
345 if (L_CANON(tty) && !tty->secondary->data)
346 put_fs_long(0, (unsigned long *) arg);
347 else
348 put_fs_long(CHARS(tty->secondary),
349 (unsigned long *) arg);
350 return 0;
351 case TIOCSTI:
352 return -EINVAL;
353 case TIOCGWINSZ:
354 return get_window_size(tty,(struct winsize *) arg);
355 case TIOCSWINSZ:
356 if (IS_A_PTY_MASTER(dev))
357 set_window_size(other_tty,(struct winsize *) arg);
358 return set_window_size(tty,(struct winsize *) arg);
359 case TIOCMGET:
360 return -EINVAL;
361 case TIOCMBIS:
362 return -EINVAL;
363 case TIOCMBIC:
364 return -EINVAL;
365 case TIOCMSET:
366 return -EINVAL;
367 case TIOCGSOFTCAR:
368 return -EINVAL;
369 case TIOCSSOFTCAR:
370 return -EINVAL;
371 case TIOCLINUX:
372 switch (get_fs_byte((char *)arg))
373 {
374 case 0:
375 return do_screendump(arg);
376 case 1:
377 return do_get_ps_info(arg);
378 default:
379 return -EINVAL;
380 }
381 case TIOCCONS:
382 if (!IS_A_PTY(dev))
383 return -EINVAL;
384 if (redirect)
385 return -EBUSY;
386 if (!suser())
387 return -EPERM;
388 if (IS_A_PTY_MASTER(dev))
389 redirect = other_tty;
390 else
391 redirect = tty;
392 return 0;
393 default:
394 return vt_ioctl(tty, dev, cmd, arg);
395 }
396 }