line.c 18.9 KB
Newer Older
1
/*
J
Jeff Dike 已提交
2
 * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
L
Linus Torvalds 已提交
3 4 5
 * Licensed under the GPL
 */

J
Jeff Dike 已提交
6
#include "linux/irqreturn.h"
L
Linus Torvalds 已提交
7
#include "linux/kd.h"
8
#include "linux/sched.h"
9
#include "linux/slab.h"
10
#include "chan.h"
J
Jeff Dike 已提交
11
#include "irq_kern.h"
L
Linus Torvalds 已提交
12
#include "irq_user.h"
J
Jeff Dike 已提交
13
#include "kern_util.h"
L
Linus Torvalds 已提交
14 15 16 17
#include "os.h"

#define LINE_BUFSIZE 4096

A
Al Viro 已提交
18
static irqreturn_t line_interrupt(int irq, void *data)
L
Linus Torvalds 已提交
19
{
20 21
	struct chan *chan = data;
	struct line *line = chan->line;
J
Jiri Slaby 已提交
22
	struct tty_struct *tty = tty_port_tty_get(&line->port);
L
Linus Torvalds 已提交
23 24

	if (line)
J
Jiri Slaby 已提交
25 26
		chan_interrupt(line, tty, irq);
	tty_kref_put(tty);
L
Linus Torvalds 已提交
27 28 29
	return IRQ_HANDLED;
}

J
Jeff Dike 已提交
30 31
/*
 * Returns the free space inside the ring buffer of this line.
32
 *
S
Simon Arlott 已提交
33
 * Should be called while holding line->lock (this does not modify data).
34 35
 */
static int write_room(struct line *line)
L
Linus Torvalds 已提交
36 37 38
{
	int n;

39 40 41 42 43
	if (line->buffer == NULL)
		return LINE_BUFSIZE - 1;

	/* This is for the case where the buffer is wrapped! */
	n = line->head - line->tail;
L
Linus Torvalds 已提交
44 45

	if (n <= 0)
J
Jeff Dike 已提交
46
		n += LINE_BUFSIZE; /* The other case */
47 48 49 50 51 52 53 54 55 56 57 58 59 60
	return n - 1;
}

int line_write_room(struct tty_struct *tty)
{
	struct line *line = tty->driver_data;
	unsigned long flags;
	int room;

	spin_lock_irqsave(&line->lock, flags);
	room = write_room(line);
	spin_unlock_irqrestore(&line->lock, flags);

	return room;
L
Linus Torvalds 已提交
61 62
}

63 64 65 66 67 68 69
int line_chars_in_buffer(struct tty_struct *tty)
{
	struct line *line = tty->driver_data;
	unsigned long flags;
	int ret;

	spin_lock_irqsave(&line->lock, flags);
J
Jeff Dike 已提交
70
	/* write_room subtracts 1 for the needed NULL, so we readd it.*/
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
	ret = LINE_BUFSIZE - (write_room(line) + 1);
	spin_unlock_irqrestore(&line->lock, flags);

	return ret;
}

/*
 * This copies the content of buf into the circular buffer associated with
 * this line.
 * The return value is the number of characters actually copied, i.e. the ones
 * for which there was space: this function is not supposed to ever flush out
 * the circular buffer.
 *
 * Must be called while holding line->lock!
 */
L
Linus Torvalds 已提交
86 87 88 89
static int buffer_data(struct line *line, const char *buf, int len)
{
	int end, room;

J
Jeff Dike 已提交
90
	if (line->buffer == NULL) {
L
Linus Torvalds 已提交
91 92
		line->buffer = kmalloc(LINE_BUFSIZE, GFP_ATOMIC);
		if (line->buffer == NULL) {
J
Jeff Dike 已提交
93 94 95
			printk(KERN_ERR "buffer_data - atomic allocation "
			       "failed\n");
			return 0;
L
Linus Torvalds 已提交
96 97 98 99 100 101 102 103 104
		}
		line->head = line->buffer;
		line->tail = line->buffer;
	}

	room = write_room(line);
	len = (len > room) ? room : len;

	end = line->buffer + LINE_BUFSIZE - line->tail;
105

J
Jeff Dike 已提交
106
	if (len < end) {
L
Linus Torvalds 已提交
107 108
		memcpy(line->tail, buf, len);
		line->tail += len;
J
Jeff Dike 已提交
109 110
	}
	else {
111
		/* The circular buffer is wrapping */
L
Linus Torvalds 已提交
112 113 114 115 116 117
		memcpy(line->tail, buf, end);
		buf += end;
		memcpy(line->buffer, buf, len - end);
		line->tail = line->buffer + len - end;
	}

118
	return len;
L
Linus Torvalds 已提交
119 120
}

121 122 123 124 125 126 127 128 129
/*
 * Flushes the ring buffer to the output channels. That is, write_chan is
 * called, passing it line->head as buffer, and an appropriate count.
 *
 * On exit, returns 1 when the buffer is empty,
 * 0 when the buffer is not empty on exit,
 * and -errno when an error occurred.
 *
 * Must be called while holding line->lock!*/
L
Linus Torvalds 已提交
130 131 132 133 134
static int flush_buffer(struct line *line)
{
	int n, count;

	if ((line->buffer == NULL) || (line->head == line->tail))
135
		return 1;
L
Linus Torvalds 已提交
136 137

	if (line->tail < line->head) {
138
		/* line->buffer + LINE_BUFSIZE is the end of the buffer! */
L
Linus Torvalds 已提交
139
		count = line->buffer + LINE_BUFSIZE - line->head;
140

141
		n = write_chan(line->chan_out, line->head, count,
L
Linus Torvalds 已提交
142 143
			       line->driver->write_irq);
		if (n < 0)
144 145
			return n;
		if (n == count) {
J
Jeff Dike 已提交
146 147 148 149
			/*
			 * We have flushed from ->head to buffer end, now we
			 * must flush only from the beginning to ->tail.
			 */
L
Linus Torvalds 已提交
150
			line->head = line->buffer;
151
		} else {
L
Linus Torvalds 已提交
152
			line->head += n;
153
			return 0;
L
Linus Torvalds 已提交
154 155 156 157
		}
	}

	count = line->tail - line->head;
158
	n = write_chan(line->chan_out, line->head, count,
L
Linus Torvalds 已提交
159
		       line->driver->write_irq);
160

J
Jeff Dike 已提交
161
	if (n < 0)
162
		return n;
L
Linus Torvalds 已提交
163 164

	line->head += n;
165 166 167 168 169 170 171 172 173
	return line->head == line->tail;
}

void line_flush_buffer(struct tty_struct *tty)
{
	struct line *line = tty->driver_data;
	unsigned long flags;

	spin_lock_irqsave(&line->lock, flags);
R
Richard Weinberger 已提交
174
	flush_buffer(line);
175 176 177
	spin_unlock_irqrestore(&line->lock, flags);
}

J
Jeff Dike 已提交
178 179 180 181
/*
 * We map both ->flush_chars and ->put_char (which go in pair) onto
 * ->flush_buffer and ->write. Hope it's not that bad.
 */
182 183 184 185 186
void line_flush_chars(struct tty_struct *tty)
{
	line_flush_buffer(tty);
}

187
int line_put_char(struct tty_struct *tty, unsigned char ch)
188
{
189
	return line_write(tty, &ch, sizeof(ch));
L
Linus Torvalds 已提交
190 191 192 193 194 195
}

int line_write(struct tty_struct *tty, const unsigned char *buf, int len)
{
	struct line *line = tty->driver_data;
	unsigned long flags;
J
Jeff Dike 已提交
196
	int n, ret = 0;
L
Linus Torvalds 已提交
197

198
	spin_lock_irqsave(&line->lock, flags);
J
Jeff Dike 已提交
199
	if (line->head != line->tail)
L
Linus Torvalds 已提交
200
		ret = buffer_data(line, buf, len);
J
Jeff Dike 已提交
201
	else {
202
		n = write_chan(line->chan_out, buf, len,
L
Linus Torvalds 已提交
203
			       line->driver->write_irq);
204
		if (n < 0) {
L
Linus Torvalds 已提交
205 206 207 208 209 210
			ret = n;
			goto out_up;
		}

		len -= n;
		ret += n;
211
		if (len > 0)
L
Linus Torvalds 已提交
212 213
			ret += buffer_data(line, buf + n, len);
	}
214 215 216
out_up:
	spin_unlock_irqrestore(&line->lock, flags);
	return ret;
L
Linus Torvalds 已提交
217 218
}

A
Alan Cox 已提交
219
void line_set_termios(struct tty_struct *tty, struct ktermios * old)
L
Linus Torvalds 已提交
220 221 222 223
{
	/* nothing */
}

J
Jeff Dike 已提交
224
static const struct {
L
Linus Torvalds 已提交
225 226 227 228 229 230
	int  cmd;
	char *level;
	char *name;
} tty_ioctls[] = {
	/* don't print these, they flood the log ... */
	{ TCGETS,      NULL,       "TCGETS"      },
J
Jeff Dike 已提交
231 232 233 234
	{ TCSETS,      NULL,       "TCSETS"      },
	{ TCSETSW,     NULL,       "TCSETSW"     },
	{ TCFLSH,      NULL,       "TCFLSH"      },
	{ TCSBRK,      NULL,       "TCSBRK"      },
L
Linus Torvalds 已提交
235 236

	/* general tty stuff */
J
Jeff Dike 已提交
237 238 239 240 241
	{ TCSETSF,     KERN_DEBUG, "TCSETSF"     },
	{ TCGETA,      KERN_DEBUG, "TCGETA"      },
	{ TIOCMGET,    KERN_DEBUG, "TIOCMGET"    },
	{ TCSBRKP,     KERN_DEBUG, "TCSBRKP"     },
	{ TIOCMSET,    KERN_DEBUG, "TIOCMSET"    },
L
Linus Torvalds 已提交
242 243 244 245 246 247 248 249

	/* linux-specific ones */
	{ TIOCLINUX,   KERN_INFO,  "TIOCLINUX"   },
	{ KDGKBMODE,   KERN_INFO,  "KDGKBMODE"   },
	{ KDGKBTYPE,   KERN_INFO,  "KDGKBTYPE"   },
	{ KDSIGACCEPT, KERN_INFO,  "KDSIGACCEPT" },
};

250 251
int line_ioctl(struct tty_struct *tty, unsigned int cmd,
				unsigned long arg)
L
Linus Torvalds 已提交
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270
{
	int ret;
	int i;

	ret = 0;
	switch(cmd) {
#ifdef TIOCGETP
	case TIOCGETP:
	case TIOCSETP:
	case TIOCSETN:
#endif
#ifdef TIOCGETC
	case TIOCGETC:
	case TIOCSETC:
#endif
#ifdef TIOCGLTC
	case TIOCGLTC:
	case TIOCSLTC:
#endif
271 272
	/* Note: these are out of date as we now have TCGETS2 etc but this
	   whole lot should probably go away */
L
Linus Torvalds 已提交
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
	case TCGETS:
	case TCSETSF:
	case TCSETSW:
	case TCSETS:
	case TCGETA:
	case TCSETAF:
	case TCSETAW:
	case TCSETA:
	case TCXONC:
	case TCFLSH:
	case TIOCOUTQ:
	case TIOCINQ:
	case TIOCGLCKTRMIOS:
	case TIOCSLCKTRMIOS:
	case TIOCPKT:
	case TIOCGSOFTCAR:
	case TIOCSSOFTCAR:
		return -ENOIOCTLCMD;
#if 0
	case TCwhatever:
		/* do something */
		break;
#endif
	default:
		for (i = 0; i < ARRAY_SIZE(tty_ioctls); i++)
			if (cmd == tty_ioctls[i].cmd)
				break;
J
Jeff Dike 已提交
300
		if (i == ARRAY_SIZE(tty_ioctls)) {
L
Linus Torvalds 已提交
301
			printk(KERN_ERR "%s: %s: unknown ioctl: 0x%x\n",
302
			       __func__, tty->name, cmd);
L
Linus Torvalds 已提交
303 304 305 306
		}
		ret = -ENOIOCTLCMD;
		break;
	}
307
	return ret;
L
Linus Torvalds 已提交
308 309
}

310 311 312 313
void line_throttle(struct tty_struct *tty)
{
	struct line *line = tty->driver_data;

314
	deactivate_chan(line->chan_in, line->driver->read_irq);
315 316 317 318 319 320 321 322
	line->throttled = 1;
}

void line_unthrottle(struct tty_struct *tty)
{
	struct line *line = tty->driver_data;

	line->throttled = 0;
323
	chan_interrupt(line, tty, line->driver->read_irq);
324

J
Jeff Dike 已提交
325 326
	/*
	 * Maybe there is enough stuff pending that calling the interrupt
327 328 329
	 * throttles us again.  In this case, line->throttled will be 1
	 * again and we shouldn't turn the interrupt back on.
	 */
J
Jeff Dike 已提交
330
	if (!line->throttled)
331
		reactivate_chan(line->chan_in, line->driver->read_irq);
332 333
}

A
Al Viro 已提交
334
static irqreturn_t line_write_interrupt(int irq, void *data)
L
Linus Torvalds 已提交
335
{
336 337
	struct chan *chan = data;
	struct line *line = chan->line;
J
Jiri Slaby 已提交
338
	struct tty_struct *tty;
L
Linus Torvalds 已提交
339 340
	int err;

J
Jeff Dike 已提交
341
	/*
Y
Yong Zhang 已提交
342 343
	 * Interrupts are disabled here because genirq keep irqs disabled when
	 * calling the action handler.
J
Jeff Dike 已提交
344
	 */
345

346
	spin_lock(&line->lock);
L
Linus Torvalds 已提交
347
	err = flush_buffer(line);
348
	if (err == 0) {
A
Al Viro 已提交
349
		spin_unlock(&line->lock);
350
		return IRQ_NONE;
J
Jeff Dike 已提交
351
	} else if (err < 0) {
L
Linus Torvalds 已提交
352 353 354
		line->head = line->buffer;
		line->tail = line->buffer;
	}
355
	spin_unlock(&line->lock);
L
Linus Torvalds 已提交
356

J
Jiri Slaby 已提交
357
	tty = tty_port_tty_get(&line->port);
J
Jeff Dike 已提交
358
	if (tty == NULL)
359
		return IRQ_NONE;
L
Linus Torvalds 已提交
360

W
WANG Cong 已提交
361
	tty_wakeup(tty);
J
Jiri Slaby 已提交
362 363
	tty_kref_put(tty);

364
	return IRQ_HANDLED;
L
Linus Torvalds 已提交
365 366
}

367
int line_setup_irq(int fd, int input, int output, struct line *line, void *data)
L
Linus Torvalds 已提交
368
{
J
Jeff Dike 已提交
369
	const struct line_driver *driver = line->driver;
Y
Yong Zhang 已提交
370
	int err = 0, flags = IRQF_SHARED | IRQF_SAMPLE_RANDOM;
L
Linus Torvalds 已提交
371

372 373
	if (input)
		err = um_request_irq(driver->read_irq, fd, IRQ_READ,
J
Jeff Dike 已提交
374
				       line_interrupt, flags,
375
				       driver->read_irq_name, data);
376 377 378 379
	if (err)
		return err;
	if (output)
		err = um_request_irq(driver->write_irq, fd, IRQ_WRITE,
J
Jeff Dike 已提交
380
					line_write_interrupt, flags,
381
					driver->write_irq_name, data);
382
	return err;
L
Linus Torvalds 已提交
383 384
}

J
Jeff Dike 已提交
385 386
/*
 * Normally, a driver like this can rely mostly on the tty layer
J
Jeff Dike 已提交
387 388 389 390
 * locking, particularly when it comes to the driver structure.
 * However, in this case, mconsole requests can come in "from the
 * side", and race with opens and closes.
 *
391 392 393 394 395
 * mconsole config requests will want to be sure the device isn't in
 * use, and get_config, open, and close will want a stable
 * configuration.  The checking and modification of the configuration
 * is done under a spinlock.  Checking whether the device is in use is
 * line->tty->count > 1, also under the spinlock.
J
Jeff Dike 已提交
396
 *
A
Al Viro 已提交
397 398
 * line->count serves to decide whether the device should be enabled or
 * disabled on the host.  If it's equal to 0, then we are doing the
399
 * first open or last close.  Otherwise, open and close just return.
J
Jeff Dike 已提交
400 401
 */

402
int line_open(struct line *lines, struct tty_struct *tty)
L
Linus Torvalds 已提交
403
{
J
Jeff Dike 已提交
404
	struct line *line = &lines[tty->index];
405
	int err = -ENODEV;
L
Linus Torvalds 已提交
406

407
	mutex_lock(&line->count_lock);
J
Jeff Dike 已提交
408
	if (!line->valid)
J
Jeff Dike 已提交
409
		goto out_unlock;
L
Linus Torvalds 已提交
410

J
Jeff Dike 已提交
411
	err = 0;
J
Jiri Slaby 已提交
412
	if (line->port.count++)
J
Jeff Dike 已提交
413 414
		goto out_unlock;

A
Al Viro 已提交
415
	BUG_ON(tty->driver_data);
416
	tty->driver_data = line;
J
Jiri Slaby 已提交
417
	tty_port_tty_set(&line->port, tty);
418

419
	err = enable_chan(line);
A
Al Viro 已提交
420
	if (err) /* line_close() will be called by our caller */
421
		goto out_unlock;
422

J
Jeff Dike 已提交
423
	if (!line->sigio) {
424
		chan_enable_winch(line->chan_out, tty);
J
Jeff Dike 已提交
425
		line->sigio = 1;
L
Linus Torvalds 已提交
426 427
	}

428
	chan_window_size(line, &tty->winsize.ws_row,
J
Jeff Dike 已提交
429 430
			 &tty->winsize.ws_col);
out_unlock:
431
	mutex_unlock(&line->count_lock);
432
	return err;
L
Linus Torvalds 已提交
433 434
}

J
Jeff Dike 已提交
435 436
static void unregister_winch(struct tty_struct *tty);

L
Linus Torvalds 已提交
437 438 439 440
void line_close(struct tty_struct *tty, struct file * filp)
{
	struct line *line = tty->driver_data;

J
Jeff Dike 已提交
441 442
	/*
	 * If line_open fails (and tty->driver_data is never set),
J
Jeff Dike 已提交
443 444
	 * tty_open will call line_close.  So just return in this case.
	 */
J
Jeff Dike 已提交
445
	if (line == NULL)
J
Jeff Dike 已提交
446
		return;
447 448 449 450

	/* We ignore the error anyway! */
	flush_buffer(line);

451
	mutex_lock(&line->count_lock);
A
Al Viro 已提交
452
	BUG_ON(!line->valid);
J
Jeff Dike 已提交
453

J
Jiri Slaby 已提交
454
	if (--line->port.count)
J
Jeff Dike 已提交
455 456
		goto out_unlock;

J
Jiri Slaby 已提交
457
	tty_port_tty_set(&line->port, NULL);
J
Jeff Dike 已提交
458 459
	tty->driver_data = NULL;

J
Jeff Dike 已提交
460
	if (line->sigio) {
J
Jeff Dike 已提交
461 462
		unregister_winch(tty);
		line->sigio = 0;
J
Jeff Dike 已提交
463
	}
J
Jeff Dike 已提交
464

J
Jeff Dike 已提交
465
out_unlock:
466
	mutex_unlock(&line->count_lock);
L
Linus Torvalds 已提交
467 468 469 470 471 472 473
}

void close_lines(struct line *lines, int nlines)
{
	int i;

	for(i = 0; i < nlines; i++)
A
Al Viro 已提交
474
		close_chan(&lines[i]);
L
Linus Torvalds 已提交
475 476
}

A
Al Viro 已提交
477 478
int setup_one_line(struct line *lines, int n, char *init,
		   const struct chan_opts *opts, char **error_out)
J
Jeff Dike 已提交
479 480
{
	struct line *line = &lines[n];
481
	struct tty_driver *driver = line->driver->driver;
482
	int err = -EINVAL;
J
Jeff Dike 已提交
483

484
	mutex_lock(&line->count_lock);
J
Jeff Dike 已提交
485

J
Jiri Slaby 已提交
486
	if (line->port.count) {
487
		*error_out = "Device is already open";
J
Jeff Dike 已提交
488 489 490
		goto out;
	}

491 492 493 494
	if (!strcmp(init, "none")) {
		if (line->valid) {
			line->valid = 0;
			kfree(line->init_str);
495
			tty_unregister_device(driver, n);
496 497 498 499 500 501 502 503 504
			parse_chan_pair(NULL, line, n, opts, error_out);
			err = 0;
		}
	} else {
		char *new = kstrdup(init, GFP_KERNEL);
		if (!new) {
			*error_out = "Failed to allocate memory";
			return -ENOMEM;
		}
A
Al Viro 已提交
505
		if (line->valid) {
506
			tty_unregister_device(driver, n);
A
Al Viro 已提交
507 508
			kfree(line->init_str);
		}
509
		line->init_str = new;
A
Al Viro 已提交
510
		line->valid = 1;
511
		err = parse_chan_pair(new, line, n, opts, error_out);
512 513 514 515 516 517 518 519
		if (!err) {
			struct device *d = tty_register_device(driver, n, NULL);
			if (IS_ERR(d)) {
				*error_out = "Failed to register device";
				err = PTR_ERR(d);
				parse_chan_pair(NULL, line, n, opts, error_out);
			}
		}
520 521 522 523 524
		if (err) {
			line->init_str = NULL;
			line->valid = 0;
			kfree(new);
		}
J
Jeff Dike 已提交
525 526
	}
out:
527
	mutex_unlock(&line->count_lock);
528
	return err;
J
Jeff Dike 已提交
529 530
}

J
Jeff Dike 已提交
531 532
/*
 * Common setup code for both startup command line and mconsole initialization.
M
Matt LaPlante 已提交
533
 * @lines contains the array (of size @num) to modify;
534
 * @init is the setup string;
535
 * @error_out is an error string in the case of failure;
536
 */
537

A
Al Viro 已提交
538 539
int line_setup(char **conf, unsigned int num, char **def,
	       char *init, char *name)
L
Linus Torvalds 已提交
540
{
A
Al Viro 已提交
541
	char *error;
L
Linus Torvalds 已提交
542

J
Jeff Dike 已提交
543 544 545 546 547
	if (*init == '=') {
		/*
		 * We said con=/ssl= instead of con#=, so we are configuring all
		 * consoles at once.
		 */
A
Al Viro 已提交
548 549 550 551 552
		*def = init + 1;
	} else {
		char *end;
		unsigned n = simple_strtoul(init, &end, 0);

J
Jeff Dike 已提交
553
		if (*end != '=') {
A
Al Viro 已提交
554 555
			error = "Couldn't parse device number";
			goto out;
L
Linus Torvalds 已提交
556
		}
A
Al Viro 已提交
557 558 559
		if (n >= num) {
			error = "Device number out of range";
			goto out;
560
		}
A
Al Viro 已提交
561
		conf[n] = end + 1;
L
Linus Torvalds 已提交
562
	}
A
Al Viro 已提交
563 564 565 566 567 568
	return 0;

out:
	printk(KERN_ERR "Failed to set up %s with "
	       "configuration string \"%s\" : %s\n", name, init, error);
	return -EINVAL;
L
Linus Torvalds 已提交
569 570
}

571
int line_config(struct line *lines, unsigned int num, char *str,
572
		const struct chan_opts *opts, char **error_out)
L
Linus Torvalds 已提交
573
{
574
	char *end;
575
	int n;
L
Linus Torvalds 已提交
576

J
Jeff Dike 已提交
577
	if (*str == '=') {
578 579
		*error_out = "Can't configure all devices from mconsole";
		return -EINVAL;
580 581
	}

582 583 584 585 586 587 588 589 590 591
	n = simple_strtoul(str, &end, 0);
	if (*end++ != '=') {
		*error_out = "Couldn't parse device number";
		return -EINVAL;
	}
	if (n >= num) {
		*error_out = "Device number out of range";
		return -EINVAL;
	}

592
	return setup_one_line(lines, n, end, opts, error_out);
L
Linus Torvalds 已提交
593 594
}

595
int line_get_config(char *name, struct line *lines, unsigned int num, char *str,
L
Linus Torvalds 已提交
596 597 598 599 600 601 602
		    int size, char **error_out)
{
	struct line *line;
	char *end;
	int dev, n = 0;

	dev = simple_strtoul(name, &end, 0);
J
Jeff Dike 已提交
603
	if ((*end != '\0') || (end == name)) {
L
Linus Torvalds 已提交
604
		*error_out = "line_get_config failed to parse device number";
605
		return 0;
L
Linus Torvalds 已提交
606 607
	}

J
Jeff Dike 已提交
608
	if ((dev < 0) || (dev >= num)) {
609 610
		*error_out = "device number out of range";
		return 0;
L
Linus Torvalds 已提交
611 612 613 614
	}

	line = &lines[dev];

615
	mutex_lock(&line->count_lock);
J
Jeff Dike 已提交
616
	if (!line->valid)
L
Linus Torvalds 已提交
617
		CONFIG_CHUNK(str, size, n, "none", 1);
J
Jiri Slaby 已提交
618 619 620 621 622 623 624 625 626
	else {
		struct tty_struct *tty = tty_port_tty_get(&line->port);
		if (tty == NULL) {
			CONFIG_CHUNK(str, size, n, line->init_str, 1);
		} else {
			n = chan_config_string(line, str, size, error_out);
			tty_kref_put(tty);
		}
	}
627
	mutex_unlock(&line->count_lock);
L
Linus Torvalds 已提交
628

629
	return n;
L
Linus Torvalds 已提交
630 631
}

J
Jeff Dike 已提交
632 633 634
int line_id(char **str, int *start_out, int *end_out)
{
	char *end;
J
Jeff Dike 已提交
635
	int n;
J
Jeff Dike 已提交
636 637

	n = simple_strtoul(*str, &end, 0);
J
Jeff Dike 已提交
638 639
	if ((*end != '\0') || (end == *str))
		return -1;
J
Jeff Dike 已提交
640

J
Jeff Dike 已提交
641 642 643 644
	*str = end;
	*start_out = n;
	*end_out = n;
	return n;
J
Jeff Dike 已提交
645 646
}

647
int line_remove(struct line *lines, unsigned int num, int n, char **error_out)
L
Linus Torvalds 已提交
648
{
649 650 651 652
	if (n >= num) {
		*error_out = "Device number out of range";
		return -EINVAL;
	}
653
	return setup_one_line(lines, n, "none", NULL, error_out);
L
Linus Torvalds 已提交
654 655
}

656 657 658
int register_lines(struct line_driver *line_driver,
		   const struct tty_operations *ops,
		   struct line *lines, int nlines)
L
Linus Torvalds 已提交
659 660
{
	struct tty_driver *driver = alloc_tty_driver(nlines);
661
	int err;
A
Al Viro 已提交
662
	int i;
L
Linus Torvalds 已提交
663 664

	if (!driver)
665
		return -ENOMEM;
L
Linus Torvalds 已提交
666 667 668 669 670 671 672

	driver->driver_name = line_driver->name;
	driver->name = line_driver->device_name;
	driver->major = line_driver->major;
	driver->minor_start = line_driver->minor_start;
	driver->type = line_driver->type;
	driver->subtype = line_driver->subtype;
673
	driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
L
Linus Torvalds 已提交
674
	driver->init_termios = tty_std_termios;
A
Al Viro 已提交
675 676
	
	for (i = 0; i < nlines; i++) {
J
Jiri Slaby 已提交
677
		tty_port_init(&lines[i].port);
A
Al Viro 已提交
678 679 680 681 682
		spin_lock_init(&lines[i].lock);
		mutex_init(&lines[i].count_lock);
		lines[i].driver = line_driver;
		INIT_LIST_HEAD(&lines[i].chan_list);
	}
L
Linus Torvalds 已提交
683 684
	tty_set_operations(driver, ops);

685 686
	err = tty_register_driver(driver);
	if (err) {
J
Jeff Dike 已提交
687 688
		printk(KERN_ERR "register_lines : can't register %s driver\n",
		       line_driver->name);
L
Linus Torvalds 已提交
689
		put_tty_driver(driver);
690
		return err;
L
Linus Torvalds 已提交
691 692
	}

693
	line_driver->driver = driver;
L
Linus Torvalds 已提交
694
	mconsole_register_dev(&line_driver->mc);
695
	return 0;
L
Linus Torvalds 已提交
696 697
}

698 699
static DEFINE_SPINLOCK(winch_handler_lock);
static LIST_HEAD(winch_handlers);
700

L
Linus Torvalds 已提交
701 702 703 704 705 706
struct winch {
	struct list_head list;
	int fd;
	int tty_fd;
	int pid;
	struct tty_struct *tty;
J
Jeff Dike 已提交
707
	unsigned long stack;
A
Al Viro 已提交
708
	struct work_struct work;
L
Linus Torvalds 已提交
709 710
};

A
Al Viro 已提交
711
static void __free_winch(struct work_struct *work)
J
Jeff Dike 已提交
712
{
A
Al Viro 已提交
713
	struct winch *winch = container_of(work, struct winch, work);
R
Richard Weinberger 已提交
714
	um_free_irq(WINCH_IRQ, winch);
J
Jeff Dike 已提交
715 716 717 718 719 720 721 722

	if (winch->pid != -1)
		os_kill_process(winch->pid, 1);
	if (winch->stack != 0)
		free_stack(winch->stack, 0);
	kfree(winch);
}

A
Al Viro 已提交
723 724 725 726 727 728 729 730 731 732
static void free_winch(struct winch *winch)
{
	int fd = winch->fd;
	winch->fd = -1;
	if (fd != -1)
		os_close_file(fd);
	list_del(&winch->list);
	__free_winch(&winch->work);
}

A
Al Viro 已提交
733
static irqreturn_t winch_interrupt(int irq, void *data)
L
Linus Torvalds 已提交
734 735 736 737
{
	struct winch *winch = data;
	struct tty_struct *tty;
	struct line *line;
A
Al Viro 已提交
738
	int fd = winch->fd;
L
Linus Torvalds 已提交
739 740 741
	int err;
	char c;

A
Al Viro 已提交
742 743
	if (fd != -1) {
		err = generic_read(fd, &c, NULL);
J
Jeff Dike 已提交
744 745
		if (err < 0) {
			if (err != -EAGAIN) {
A
Al Viro 已提交
746 747 748
				winch->fd = -1;
				list_del(&winch->list);
				os_close_file(fd);
J
Jeff Dike 已提交
749 750 751 752
				printk(KERN_ERR "winch_interrupt : "
				       "read failed, errno = %d\n", -err);
				printk(KERN_ERR "fd %d is losing SIGWINCH "
				       "support\n", winch->tty_fd);
A
Al Viro 已提交
753 754
				INIT_WORK(&winch->work, __free_winch);
				schedule_work(&winch->work);
755
				return IRQ_HANDLED;
L
Linus Torvalds 已提交
756 757 758 759
			}
			goto out;
		}
	}
J
Jeff Dike 已提交
760
	tty = winch->tty;
L
Linus Torvalds 已提交
761 762
	if (tty != NULL) {
		line = tty->driver_data;
J
Jeff Dike 已提交
763
		if (line != NULL) {
764
			chan_window_size(line, &tty->winsize.ws_row,
J
Jeff Dike 已提交
765 766 767
					 &tty->winsize.ws_col);
			kill_pgrp(tty->pgrp, SIGWINCH, 1);
		}
L
Linus Torvalds 已提交
768 769
	}
 out:
J
Jeff Dike 已提交
770
	if (winch->fd != -1)
L
Linus Torvalds 已提交
771
		reactivate_fd(winch->fd, WINCH_IRQ);
772
	return IRQ_HANDLED;
L
Linus Torvalds 已提交
773 774
}

J
Jeff Dike 已提交
775 776
void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty,
			unsigned long stack)
L
Linus Torvalds 已提交
777 778 779 780 781
{
	struct winch *winch;

	winch = kmalloc(sizeof(*winch), GFP_KERNEL);
	if (winch == NULL) {
J
Jeff Dike 已提交
782
		printk(KERN_ERR "register_winch_irq - kmalloc failed\n");
J
Jeff Dike 已提交
783
		goto cleanup;
L
Linus Torvalds 已提交
784
	}
785

L
Linus Torvalds 已提交
786 787 788 789
	*winch = ((struct winch) { .list  	= LIST_HEAD_INIT(winch->list),
				   .fd  	= fd,
				   .tty_fd 	= tty_fd,
				   .pid  	= pid,
J
Jeff Dike 已提交
790 791 792 793
				   .tty 	= tty,
				   .stack	= stack });

	if (um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt,
Y
Yong Zhang 已提交
794
			   IRQF_SHARED | IRQF_SAMPLE_RANDOM,
J
Jeff Dike 已提交
795
			   "winch", winch) < 0) {
J
Jeff Dike 已提交
796 797
		printk(KERN_ERR "register_winch_irq - failed to register "
		       "IRQ\n");
J
Jeff Dike 已提交
798 799
		goto out_free;
	}
800 801

	spin_lock(&winch_handler_lock);
L
Linus Torvalds 已提交
802
	list_add(&winch->list, &winch_handlers);
803 804
	spin_unlock(&winch_handler_lock);

J
Jeff Dike 已提交
805
	return;
806

J
Jeff Dike 已提交
807
 out_free:
808
	kfree(winch);
J
Jeff Dike 已提交
809 810 811 812 813
 cleanup:
	os_kill_process(pid, 1);
	os_close_file(fd);
	if (stack != 0)
		free_stack(stack, 0);
814 815
}

J
Jeff Dike 已提交
816 817
static void unregister_winch(struct tty_struct *tty)
{
818
	struct list_head *ele, *next;
819
	struct winch *winch;
J
Jeff Dike 已提交
820

821
	spin_lock(&winch_handler_lock);
822

823
	list_for_each_safe(ele, next, &winch_handlers) {
J
Jeff Dike 已提交
824
		winch = list_entry(ele, struct winch, list);
J
Jeff Dike 已提交
825
		if (winch->tty == tty) {
A
Al Viro 已提交
826
			free_winch(winch);
827
			break;
J
Jeff Dike 已提交
828 829
		}
	}
830
	spin_unlock(&winch_handler_lock);
J
Jeff Dike 已提交
831 832
}

L
Linus Torvalds 已提交
833 834
static void winch_cleanup(void)
{
835
	struct list_head *ele, *next;
L
Linus Torvalds 已提交
836 837
	struct winch *winch;

838 839
	spin_lock(&winch_handler_lock);

J
Jeff Dike 已提交
840
	list_for_each_safe(ele, next, &winch_handlers) {
L
Linus Torvalds 已提交
841
		winch = list_entry(ele, struct winch, list);
A
Al Viro 已提交
842
		free_winch(winch);
L
Linus Torvalds 已提交
843
	}
844 845

	spin_unlock(&winch_handler_lock);
L
Linus Torvalds 已提交
846 847 848 849 850 851 852 853
}
__uml_exitcall(winch_cleanup);

char *add_xterm_umid(char *base)
{
	char *umid, *title;
	int len;

J
Jeff Dike 已提交
854
	umid = get_umid();
J
Jeff Dike 已提交
855
	if (*umid == '\0')
856
		return base;
857

L
Linus Torvalds 已提交
858 859
	len = strlen(base) + strlen(" ()") + strlen(umid) + 1;
	title = kmalloc(len, GFP_KERNEL);
J
Jeff Dike 已提交
860 861
	if (title == NULL) {
		printk(KERN_ERR "Failed to allocate buffer for xterm title\n");
862
		return base;
L
Linus Torvalds 已提交
863 864 865
	}

	snprintf(title, len, "%s (%s)", base, umid);
866
	return title;
L
Linus Torvalds 已提交
867
}