diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /arch/um/drivers/line.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'arch/um/drivers/line.c')
-rw-r--r-- | arch/um/drivers/line.c | 681 |
1 files changed, 681 insertions, 0 deletions
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c new file mode 100644 index 000000000000..6924f273ced9 --- /dev/null +++ b/arch/um/drivers/line.c | |||
@@ -0,0 +1,681 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) | ||
3 | * Licensed under the GPL | ||
4 | */ | ||
5 | |||
6 | #include "linux/sched.h" | ||
7 | #include "linux/slab.h" | ||
8 | #include "linux/list.h" | ||
9 | #include "linux/kd.h" | ||
10 | #include "linux/interrupt.h" | ||
11 | #include "linux/devfs_fs_kernel.h" | ||
12 | #include "asm/uaccess.h" | ||
13 | #include "chan_kern.h" | ||
14 | #include "irq_user.h" | ||
15 | #include "line.h" | ||
16 | #include "kern.h" | ||
17 | #include "user_util.h" | ||
18 | #include "kern_util.h" | ||
19 | #include "os.h" | ||
20 | #include "irq_kern.h" | ||
21 | |||
22 | #define LINE_BUFSIZE 4096 | ||
23 | |||
24 | static irqreturn_t line_interrupt(int irq, void *data, struct pt_regs *unused) | ||
25 | { | ||
26 | struct tty_struct *tty = data; | ||
27 | struct line *line = tty->driver_data; | ||
28 | |||
29 | if (line) | ||
30 | chan_interrupt(&line->chan_list, &line->task, tty, irq); | ||
31 | return IRQ_HANDLED; | ||
32 | } | ||
33 | |||
34 | static void line_timer_cb(void *arg) | ||
35 | { | ||
36 | struct tty_struct *tty = arg; | ||
37 | struct line *line = tty->driver_data; | ||
38 | |||
39 | line_interrupt(line->driver->read_irq, arg, NULL); | ||
40 | } | ||
41 | |||
42 | static int write_room(struct line *dev) | ||
43 | { | ||
44 | int n; | ||
45 | |||
46 | if (dev->buffer == NULL) | ||
47 | return (LINE_BUFSIZE - 1); | ||
48 | |||
49 | n = dev->head - dev->tail; | ||
50 | if (n <= 0) | ||
51 | n = LINE_BUFSIZE + n; | ||
52 | return (n - 1); | ||
53 | } | ||
54 | |||
55 | static int buffer_data(struct line *line, const char *buf, int len) | ||
56 | { | ||
57 | int end, room; | ||
58 | |||
59 | if(line->buffer == NULL){ | ||
60 | line->buffer = kmalloc(LINE_BUFSIZE, GFP_ATOMIC); | ||
61 | if (line->buffer == NULL) { | ||
62 | printk("buffer_data - atomic allocation failed\n"); | ||
63 | return(0); | ||
64 | } | ||
65 | line->head = line->buffer; | ||
66 | line->tail = line->buffer; | ||
67 | } | ||
68 | |||
69 | room = write_room(line); | ||
70 | len = (len > room) ? room : len; | ||
71 | |||
72 | end = line->buffer + LINE_BUFSIZE - line->tail; | ||
73 | if(len < end){ | ||
74 | memcpy(line->tail, buf, len); | ||
75 | line->tail += len; | ||
76 | } | ||
77 | else { | ||
78 | memcpy(line->tail, buf, end); | ||
79 | buf += end; | ||
80 | memcpy(line->buffer, buf, len - end); | ||
81 | line->tail = line->buffer + len - end; | ||
82 | } | ||
83 | |||
84 | return(len); | ||
85 | } | ||
86 | |||
87 | static int flush_buffer(struct line *line) | ||
88 | { | ||
89 | int n, count; | ||
90 | |||
91 | if ((line->buffer == NULL) || (line->head == line->tail)) | ||
92 | return(1); | ||
93 | |||
94 | if (line->tail < line->head) { | ||
95 | count = line->buffer + LINE_BUFSIZE - line->head; | ||
96 | n = write_chan(&line->chan_list, line->head, count, | ||
97 | line->driver->write_irq); | ||
98 | if (n < 0) | ||
99 | return(n); | ||
100 | if (n == count) | ||
101 | line->head = line->buffer; | ||
102 | else { | ||
103 | line->head += n; | ||
104 | return(0); | ||
105 | } | ||
106 | } | ||
107 | |||
108 | count = line->tail - line->head; | ||
109 | n = write_chan(&line->chan_list, line->head, count, | ||
110 | line->driver->write_irq); | ||
111 | if(n < 0) return(n); | ||
112 | |||
113 | line->head += n; | ||
114 | return(line->head == line->tail); | ||
115 | } | ||
116 | |||
117 | int line_write(struct tty_struct *tty, const unsigned char *buf, int len) | ||
118 | { | ||
119 | struct line *line = tty->driver_data; | ||
120 | unsigned long flags; | ||
121 | int n, err, ret = 0; | ||
122 | |||
123 | if(tty->stopped) return 0; | ||
124 | |||
125 | down(&line->sem); | ||
126 | if(line->head != line->tail){ | ||
127 | local_irq_save(flags); | ||
128 | ret = buffer_data(line, buf, len); | ||
129 | err = flush_buffer(line); | ||
130 | local_irq_restore(flags); | ||
131 | if(err <= 0 && (err != -EAGAIN || !ret)) | ||
132 | ret = err; | ||
133 | } | ||
134 | else { | ||
135 | n = write_chan(&line->chan_list, buf, len, | ||
136 | line->driver->write_irq); | ||
137 | if(n < 0){ | ||
138 | ret = n; | ||
139 | goto out_up; | ||
140 | } | ||
141 | |||
142 | len -= n; | ||
143 | ret += n; | ||
144 | if(len > 0) | ||
145 | ret += buffer_data(line, buf + n, len); | ||
146 | } | ||
147 | out_up: | ||
148 | up(&line->sem); | ||
149 | return(ret); | ||
150 | } | ||
151 | |||
152 | void line_put_char(struct tty_struct *tty, unsigned char ch) | ||
153 | { | ||
154 | line_write(tty, &ch, sizeof(ch)); | ||
155 | } | ||
156 | |||
157 | void line_set_termios(struct tty_struct *tty, struct termios * old) | ||
158 | { | ||
159 | /* nothing */ | ||
160 | } | ||
161 | |||
162 | int line_chars_in_buffer(struct tty_struct *tty) | ||
163 | { | ||
164 | return 0; | ||
165 | } | ||
166 | |||
167 | static struct { | ||
168 | int cmd; | ||
169 | char *level; | ||
170 | char *name; | ||
171 | } tty_ioctls[] = { | ||
172 | /* don't print these, they flood the log ... */ | ||
173 | { TCGETS, NULL, "TCGETS" }, | ||
174 | { TCSETS, NULL, "TCSETS" }, | ||
175 | { TCSETSW, NULL, "TCSETSW" }, | ||
176 | { TCFLSH, NULL, "TCFLSH" }, | ||
177 | { TCSBRK, NULL, "TCSBRK" }, | ||
178 | |||
179 | /* general tty stuff */ | ||
180 | { TCSETSF, KERN_DEBUG, "TCSETSF" }, | ||
181 | { TCGETA, KERN_DEBUG, "TCGETA" }, | ||
182 | { TIOCMGET, KERN_DEBUG, "TIOCMGET" }, | ||
183 | { TCSBRKP, KERN_DEBUG, "TCSBRKP" }, | ||
184 | { TIOCMSET, KERN_DEBUG, "TIOCMSET" }, | ||
185 | |||
186 | /* linux-specific ones */ | ||
187 | { TIOCLINUX, KERN_INFO, "TIOCLINUX" }, | ||
188 | { KDGKBMODE, KERN_INFO, "KDGKBMODE" }, | ||
189 | { KDGKBTYPE, KERN_INFO, "KDGKBTYPE" }, | ||
190 | { KDSIGACCEPT, KERN_INFO, "KDSIGACCEPT" }, | ||
191 | }; | ||
192 | |||
193 | int line_ioctl(struct tty_struct *tty, struct file * file, | ||
194 | unsigned int cmd, unsigned long arg) | ||
195 | { | ||
196 | int ret; | ||
197 | int i; | ||
198 | |||
199 | ret = 0; | ||
200 | switch(cmd) { | ||
201 | #ifdef TIOCGETP | ||
202 | case TIOCGETP: | ||
203 | case TIOCSETP: | ||
204 | case TIOCSETN: | ||
205 | #endif | ||
206 | #ifdef TIOCGETC | ||
207 | case TIOCGETC: | ||
208 | case TIOCSETC: | ||
209 | #endif | ||
210 | #ifdef TIOCGLTC | ||
211 | case TIOCGLTC: | ||
212 | case TIOCSLTC: | ||
213 | #endif | ||
214 | case TCGETS: | ||
215 | case TCSETSF: | ||
216 | case TCSETSW: | ||
217 | case TCSETS: | ||
218 | case TCGETA: | ||
219 | case TCSETAF: | ||
220 | case TCSETAW: | ||
221 | case TCSETA: | ||
222 | case TCXONC: | ||
223 | case TCFLSH: | ||
224 | case TIOCOUTQ: | ||
225 | case TIOCINQ: | ||
226 | case TIOCGLCKTRMIOS: | ||
227 | case TIOCSLCKTRMIOS: | ||
228 | case TIOCPKT: | ||
229 | case TIOCGSOFTCAR: | ||
230 | case TIOCSSOFTCAR: | ||
231 | return -ENOIOCTLCMD; | ||
232 | #if 0 | ||
233 | case TCwhatever: | ||
234 | /* do something */ | ||
235 | break; | ||
236 | #endif | ||
237 | default: | ||
238 | for (i = 0; i < ARRAY_SIZE(tty_ioctls); i++) | ||
239 | if (cmd == tty_ioctls[i].cmd) | ||
240 | break; | ||
241 | if (i < ARRAY_SIZE(tty_ioctls)) { | ||
242 | if (NULL != tty_ioctls[i].level) | ||
243 | printk("%s%s: %s: ioctl %s called\n", | ||
244 | tty_ioctls[i].level, __FUNCTION__, | ||
245 | tty->name, tty_ioctls[i].name); | ||
246 | } else { | ||
247 | printk(KERN_ERR "%s: %s: unknown ioctl: 0x%x\n", | ||
248 | __FUNCTION__, tty->name, cmd); | ||
249 | } | ||
250 | ret = -ENOIOCTLCMD; | ||
251 | break; | ||
252 | } | ||
253 | return(ret); | ||
254 | } | ||
255 | |||
256 | static irqreturn_t line_write_interrupt(int irq, void *data, | ||
257 | struct pt_regs *unused) | ||
258 | { | ||
259 | struct tty_struct *tty = data; | ||
260 | struct line *line = tty->driver_data; | ||
261 | int err; | ||
262 | |||
263 | err = flush_buffer(line); | ||
264 | if(err == 0) | ||
265 | return(IRQ_NONE); | ||
266 | else if(err < 0){ | ||
267 | line->head = line->buffer; | ||
268 | line->tail = line->buffer; | ||
269 | } | ||
270 | |||
271 | if(tty == NULL) | ||
272 | return(IRQ_NONE); | ||
273 | |||
274 | if(test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && | ||
275 | (tty->ldisc.write_wakeup != NULL)) | ||
276 | (tty->ldisc.write_wakeup)(tty); | ||
277 | |||
278 | /* BLOCKING mode | ||
279 | * In blocking mode, everything sleeps on tty->write_wait. | ||
280 | * Sleeping in the console driver would break non-blocking | ||
281 | * writes. | ||
282 | */ | ||
283 | |||
284 | if(waitqueue_active(&tty->write_wait)) | ||
285 | wake_up_interruptible(&tty->write_wait); | ||
286 | return(IRQ_HANDLED); | ||
287 | } | ||
288 | |||
289 | int line_setup_irq(int fd, int input, int output, struct tty_struct *tty) | ||
290 | { | ||
291 | struct line *line = tty->driver_data; | ||
292 | struct line_driver *driver = line->driver; | ||
293 | int err = 0, flags = SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM; | ||
294 | |||
295 | if(input) err = um_request_irq(driver->read_irq, fd, IRQ_READ, | ||
296 | line_interrupt, flags, | ||
297 | driver->read_irq_name, tty); | ||
298 | if(err) return(err); | ||
299 | if(output) err = um_request_irq(driver->write_irq, fd, IRQ_WRITE, | ||
300 | line_write_interrupt, flags, | ||
301 | driver->write_irq_name, tty); | ||
302 | line->have_irq = 1; | ||
303 | return(err); | ||
304 | } | ||
305 | |||
306 | void line_disable(struct tty_struct *tty, int current_irq) | ||
307 | { | ||
308 | struct line *line = tty->driver_data; | ||
309 | |||
310 | if(!line->have_irq) | ||
311 | return; | ||
312 | |||
313 | if(line->driver->read_irq == current_irq) | ||
314 | free_irq_later(line->driver->read_irq, tty); | ||
315 | else { | ||
316 | free_irq_by_irq_and_dev(line->driver->read_irq, tty); | ||
317 | free_irq(line->driver->read_irq, tty); | ||
318 | } | ||
319 | |||
320 | if(line->driver->write_irq == current_irq) | ||
321 | free_irq_later(line->driver->write_irq, tty); | ||
322 | else { | ||
323 | free_irq_by_irq_and_dev(line->driver->write_irq, tty); | ||
324 | free_irq(line->driver->write_irq, tty); | ||
325 | } | ||
326 | |||
327 | line->have_irq = 0; | ||
328 | } | ||
329 | |||
330 | int line_open(struct line *lines, struct tty_struct *tty, | ||
331 | struct chan_opts *opts) | ||
332 | { | ||
333 | struct line *line; | ||
334 | int err = 0; | ||
335 | |||
336 | line = &lines[tty->index]; | ||
337 | tty->driver_data = line; | ||
338 | |||
339 | down(&line->sem); | ||
340 | if (tty->count == 1) { | ||
341 | if (!line->valid) { | ||
342 | err = -ENODEV; | ||
343 | goto out; | ||
344 | } | ||
345 | if (list_empty(&line->chan_list)) { | ||
346 | err = parse_chan_pair(line->init_str, &line->chan_list, | ||
347 | line->init_pri, tty->index, opts); | ||
348 | if(err) goto out; | ||
349 | err = open_chan(&line->chan_list); | ||
350 | if(err) goto out; | ||
351 | } | ||
352 | enable_chan(&line->chan_list, tty); | ||
353 | INIT_WORK(&line->task, line_timer_cb, tty); | ||
354 | } | ||
355 | |||
356 | if(!line->sigio){ | ||
357 | chan_enable_winch(&line->chan_list, tty); | ||
358 | line->sigio = 1; | ||
359 | } | ||
360 | chan_window_size(&line->chan_list, &tty->winsize.ws_row, | ||
361 | &tty->winsize.ws_col); | ||
362 | line->count++; | ||
363 | |||
364 | out: | ||
365 | up(&line->sem); | ||
366 | return(err); | ||
367 | } | ||
368 | |||
369 | void line_close(struct tty_struct *tty, struct file * filp) | ||
370 | { | ||
371 | struct line *line = tty->driver_data; | ||
372 | |||
373 | down(&line->sem); | ||
374 | line->count--; | ||
375 | if (tty->count == 1) { | ||
376 | line_disable(tty, -1); | ||
377 | tty->driver_data = NULL; | ||
378 | } | ||
379 | up(&line->sem); | ||
380 | } | ||
381 | |||
382 | void close_lines(struct line *lines, int nlines) | ||
383 | { | ||
384 | int i; | ||
385 | |||
386 | for(i = 0; i < nlines; i++) | ||
387 | close_chan(&lines[i].chan_list); | ||
388 | } | ||
389 | |||
390 | int line_setup(struct line *lines, int num, char *init, int all_allowed) | ||
391 | { | ||
392 | int i, n; | ||
393 | char *end; | ||
394 | |||
395 | if(*init == '=') n = -1; | ||
396 | else { | ||
397 | n = simple_strtoul(init, &end, 0); | ||
398 | if(*end != '='){ | ||
399 | printk(KERN_ERR "line_setup failed to parse \"%s\"\n", | ||
400 | init); | ||
401 | return(0); | ||
402 | } | ||
403 | init = end; | ||
404 | } | ||
405 | init++; | ||
406 | if((n >= 0) && (n >= num)){ | ||
407 | printk("line_setup - %d out of range ((0 ... %d) allowed)\n", | ||
408 | n, num - 1); | ||
409 | return(0); | ||
410 | } | ||
411 | else if (n >= 0){ | ||
412 | if (lines[n].count > 0) { | ||
413 | printk("line_setup - device %d is open\n", n); | ||
414 | return(0); | ||
415 | } | ||
416 | if (lines[n].init_pri <= INIT_ONE){ | ||
417 | lines[n].init_pri = INIT_ONE; | ||
418 | if (!strcmp(init, "none")) | ||
419 | lines[n].valid = 0; | ||
420 | else { | ||
421 | lines[n].init_str = init; | ||
422 | lines[n].valid = 1; | ||
423 | } | ||
424 | } | ||
425 | } | ||
426 | else if(!all_allowed){ | ||
427 | printk("line_setup - can't configure all devices from " | ||
428 | "mconsole\n"); | ||
429 | return(0); | ||
430 | } | ||
431 | else { | ||
432 | for(i = 0; i < num; i++){ | ||
433 | if(lines[i].init_pri <= INIT_ALL){ | ||
434 | lines[i].init_pri = INIT_ALL; | ||
435 | if(!strcmp(init, "none")) lines[i].valid = 0; | ||
436 | else { | ||
437 | lines[i].init_str = init; | ||
438 | lines[i].valid = 1; | ||
439 | } | ||
440 | } | ||
441 | } | ||
442 | } | ||
443 | return(1); | ||
444 | } | ||
445 | |||
446 | int line_config(struct line *lines, int num, char *str) | ||
447 | { | ||
448 | char *new = uml_strdup(str); | ||
449 | |||
450 | if(new == NULL){ | ||
451 | printk("line_config - uml_strdup failed\n"); | ||
452 | return(-ENOMEM); | ||
453 | } | ||
454 | return(!line_setup(lines, num, new, 0)); | ||
455 | } | ||
456 | |||
457 | int line_get_config(char *name, struct line *lines, int num, char *str, | ||
458 | int size, char **error_out) | ||
459 | { | ||
460 | struct line *line; | ||
461 | char *end; | ||
462 | int dev, n = 0; | ||
463 | |||
464 | dev = simple_strtoul(name, &end, 0); | ||
465 | if((*end != '\0') || (end == name)){ | ||
466 | *error_out = "line_get_config failed to parse device number"; | ||
467 | return(0); | ||
468 | } | ||
469 | |||
470 | if((dev < 0) || (dev >= num)){ | ||
471 | *error_out = "device number of of range"; | ||
472 | return(0); | ||
473 | } | ||
474 | |||
475 | line = &lines[dev]; | ||
476 | |||
477 | down(&line->sem); | ||
478 | if(!line->valid) | ||
479 | CONFIG_CHUNK(str, size, n, "none", 1); | ||
480 | else if(line->count == 0) | ||
481 | CONFIG_CHUNK(str, size, n, line->init_str, 1); | ||
482 | else n = chan_config_string(&line->chan_list, str, size, error_out); | ||
483 | up(&line->sem); | ||
484 | |||
485 | return(n); | ||
486 | } | ||
487 | |||
488 | int line_remove(struct line *lines, int num, char *str) | ||
489 | { | ||
490 | char config[sizeof("conxxxx=none\0")]; | ||
491 | |||
492 | sprintf(config, "%s=none", str); | ||
493 | return(!line_setup(lines, num, config, 0)); | ||
494 | } | ||
495 | |||
496 | int line_write_room(struct tty_struct *tty) | ||
497 | { | ||
498 | struct line *dev = tty->driver_data; | ||
499 | int room; | ||
500 | |||
501 | if (tty->stopped) | ||
502 | return 0; | ||
503 | room = write_room(dev); | ||
504 | if (0 == room) | ||
505 | printk(KERN_DEBUG "%s: %s: no room left in buffer\n", | ||
506 | __FUNCTION__,tty->name); | ||
507 | return room; | ||
508 | } | ||
509 | |||
510 | struct tty_driver *line_register_devfs(struct lines *set, | ||
511 | struct line_driver *line_driver, | ||
512 | struct tty_operations *ops, struct line *lines, | ||
513 | int nlines) | ||
514 | { | ||
515 | int i; | ||
516 | struct tty_driver *driver = alloc_tty_driver(nlines); | ||
517 | |||
518 | if (!driver) | ||
519 | return NULL; | ||
520 | |||
521 | driver->driver_name = line_driver->name; | ||
522 | driver->name = line_driver->device_name; | ||
523 | driver->devfs_name = line_driver->devfs_name; | ||
524 | driver->major = line_driver->major; | ||
525 | driver->minor_start = line_driver->minor_start; | ||
526 | driver->type = line_driver->type; | ||
527 | driver->subtype = line_driver->subtype; | ||
528 | driver->flags = TTY_DRIVER_REAL_RAW; | ||
529 | driver->init_termios = tty_std_termios; | ||
530 | tty_set_operations(driver, ops); | ||
531 | |||
532 | if (tty_register_driver(driver)) { | ||
533 | printk("%s: can't register %s driver\n", | ||
534 | __FUNCTION__,line_driver->name); | ||
535 | put_tty_driver(driver); | ||
536 | return NULL; | ||
537 | } | ||
538 | |||
539 | for(i = 0; i < nlines; i++){ | ||
540 | if(!lines[i].valid) | ||
541 | tty_unregister_device(driver, i); | ||
542 | } | ||
543 | |||
544 | mconsole_register_dev(&line_driver->mc); | ||
545 | return driver; | ||
546 | } | ||
547 | |||
548 | void lines_init(struct line *lines, int nlines) | ||
549 | { | ||
550 | struct line *line; | ||
551 | int i; | ||
552 | |||
553 | for(i = 0; i < nlines; i++){ | ||
554 | line = &lines[i]; | ||
555 | INIT_LIST_HEAD(&line->chan_list); | ||
556 | sema_init(&line->sem, 1); | ||
557 | if(line->init_str != NULL){ | ||
558 | line->init_str = uml_strdup(line->init_str); | ||
559 | if(line->init_str == NULL) | ||
560 | printk("lines_init - uml_strdup returned " | ||
561 | "NULL\n"); | ||
562 | } | ||
563 | } | ||
564 | } | ||
565 | |||
566 | struct winch { | ||
567 | struct list_head list; | ||
568 | int fd; | ||
569 | int tty_fd; | ||
570 | int pid; | ||
571 | struct tty_struct *tty; | ||
572 | }; | ||
573 | |||
574 | irqreturn_t winch_interrupt(int irq, void *data, struct pt_regs *unused) | ||
575 | { | ||
576 | struct winch *winch = data; | ||
577 | struct tty_struct *tty; | ||
578 | struct line *line; | ||
579 | int err; | ||
580 | char c; | ||
581 | |||
582 | if(winch->fd != -1){ | ||
583 | err = generic_read(winch->fd, &c, NULL); | ||
584 | if(err < 0){ | ||
585 | if(err != -EAGAIN){ | ||
586 | printk("winch_interrupt : read failed, " | ||
587 | "errno = %d\n", -err); | ||
588 | printk("fd %d is losing SIGWINCH support\n", | ||
589 | winch->tty_fd); | ||
590 | return(IRQ_HANDLED); | ||
591 | } | ||
592 | goto out; | ||
593 | } | ||
594 | } | ||
595 | tty = winch->tty; | ||
596 | if (tty != NULL) { | ||
597 | line = tty->driver_data; | ||
598 | chan_window_size(&line->chan_list, | ||
599 | &tty->winsize.ws_row, | ||
600 | &tty->winsize.ws_col); | ||
601 | kill_pg(tty->pgrp, SIGWINCH, 1); | ||
602 | } | ||
603 | out: | ||
604 | if(winch->fd != -1) | ||
605 | reactivate_fd(winch->fd, WINCH_IRQ); | ||
606 | return(IRQ_HANDLED); | ||
607 | } | ||
608 | |||
609 | DECLARE_MUTEX(winch_handler_sem); | ||
610 | LIST_HEAD(winch_handlers); | ||
611 | |||
612 | void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty) | ||
613 | { | ||
614 | struct winch *winch; | ||
615 | |||
616 | down(&winch_handler_sem); | ||
617 | winch = kmalloc(sizeof(*winch), GFP_KERNEL); | ||
618 | if (winch == NULL) { | ||
619 | printk("register_winch_irq - kmalloc failed\n"); | ||
620 | goto out; | ||
621 | } | ||
622 | *winch = ((struct winch) { .list = LIST_HEAD_INIT(winch->list), | ||
623 | .fd = fd, | ||
624 | .tty_fd = tty_fd, | ||
625 | .pid = pid, | ||
626 | .tty = tty }); | ||
627 | list_add(&winch->list, &winch_handlers); | ||
628 | if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt, | ||
629 | SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, | ||
630 | "winch", winch) < 0) | ||
631 | printk("register_winch_irq - failed to register IRQ\n"); | ||
632 | out: | ||
633 | up(&winch_handler_sem); | ||
634 | } | ||
635 | |||
636 | static void winch_cleanup(void) | ||
637 | { | ||
638 | struct list_head *ele; | ||
639 | struct winch *winch; | ||
640 | |||
641 | list_for_each(ele, &winch_handlers){ | ||
642 | winch = list_entry(ele, struct winch, list); | ||
643 | if(winch->fd != -1){ | ||
644 | deactivate_fd(winch->fd, WINCH_IRQ); | ||
645 | os_close_file(winch->fd); | ||
646 | } | ||
647 | if(winch->pid != -1) | ||
648 | os_kill_process(winch->pid, 1); | ||
649 | } | ||
650 | } | ||
651 | __uml_exitcall(winch_cleanup); | ||
652 | |||
653 | char *add_xterm_umid(char *base) | ||
654 | { | ||
655 | char *umid, *title; | ||
656 | int len; | ||
657 | |||
658 | umid = get_umid(1); | ||
659 | if(umid == NULL) return(base); | ||
660 | |||
661 | len = strlen(base) + strlen(" ()") + strlen(umid) + 1; | ||
662 | title = kmalloc(len, GFP_KERNEL); | ||
663 | if(title == NULL){ | ||
664 | printk("Failed to allocate buffer for xterm title\n"); | ||
665 | return(base); | ||
666 | } | ||
667 | |||
668 | snprintf(title, len, "%s (%s)", base, umid); | ||
669 | return(title); | ||
670 | } | ||
671 | |||
672 | /* | ||
673 | * Overrides for Emacs so that we follow Linus's tabbing style. | ||
674 | * Emacs will notice this stuff at the end of the file and automatically | ||
675 | * adjust the settings for this buffer only. This must remain at the end | ||
676 | * of the file. | ||
677 | * --------------------------------------------------------------------------- | ||
678 | * Local variables: | ||
679 | * c-file-style: "linux" | ||
680 | * End: | ||
681 | */ | ||