line.c 19.3 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 8
#include "linux/kd.h"
#include "chan_kern.h"
J
Jeff Dike 已提交
9
#include "irq_kern.h"
L
Linus Torvalds 已提交
10 11 12 13 14
#include "irq_user.h"
#include "os.h"

#define LINE_BUFSIZE 4096

A
Al Viro 已提交
15
static irqreturn_t line_interrupt(int irq, void *data)
L
Linus Torvalds 已提交
16
{
17 18 19
	struct chan *chan = data;
	struct line *line = chan->line;
	struct tty_struct *tty = line->tty;
L
Linus Torvalds 已提交
20 21 22 23 24 25

	if (line)
		chan_interrupt(&line->chan_list, &line->task, tty, irq);
	return IRQ_HANDLED;
}

A
Andrew Morton 已提交
26
static void line_timer_cb(struct work_struct *work)
L
Linus Torvalds 已提交
27
{
A
Andrew Morton 已提交
28
	struct line *line = container_of(work, struct line, task.work);
L
Linus Torvalds 已提交
29

J
Jeff Dike 已提交
30
	if (!line->throttled)
31 32
		chan_interrupt(&line->chan_list, &line->task, line->tty,
			       line->driver->read_irq);
L
Linus Torvalds 已提交
33 34
}

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

44 45 46 47 48
	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 已提交
49 50

	if (n <= 0)
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
		n = LINE_BUFSIZE + n; /* The other case */
	return n - 1;
}

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

	if (tty->stopped)
		return 0;

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

	/*XXX: Warning to remove */
	if (0 == room)
		printk(KERN_DEBUG "%s: %s: no room left in buffer\n",
		       __FUNCTION__,tty->name);
	return room;
L
Linus Torvalds 已提交
73 74
}

75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
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);

	/*write_room subtracts 1 for the needed NULL, so we readd it.*/
	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 已提交
99 100 101 102
static int buffer_data(struct line *line, const char *buf, int len)
{
	int end, room;

J
Jeff Dike 已提交
103
	if (line->buffer == NULL) {
L
Linus Torvalds 已提交
104 105
		line->buffer = kmalloc(LINE_BUFSIZE, GFP_ATOMIC);
		if (line->buffer == NULL) {
J
Jeff Dike 已提交
106 107 108
			printk(KERN_ERR "buffer_data - atomic allocation "
			       "failed\n");
			return 0;
L
Linus Torvalds 已提交
109 110 111 112 113 114 115 116 117
		}
		line->head = line->buffer;
		line->tail = line->buffer;
	}

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

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

J
Jeff Dike 已提交
119
	if (len < end) {
L
Linus Torvalds 已提交
120 121
		memcpy(line->tail, buf, len);
		line->tail += len;
J
Jeff Dike 已提交
122 123
	}
	else {
124
		/* The circular buffer is wrapping */
L
Linus Torvalds 已提交
125 126 127 128 129 130
		memcpy(line->tail, buf, end);
		buf += end;
		memcpy(line->buffer, buf, len - end);
		line->tail = line->buffer + len - end;
	}

131
	return len;
L
Linus Torvalds 已提交
132 133
}

134 135 136 137 138 139 140 141 142
/*
 * 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 已提交
143 144 145 146 147
static int flush_buffer(struct line *line)
{
	int n, count;

	if ((line->buffer == NULL) || (line->head == line->tail))
148
		return 1;
L
Linus Torvalds 已提交
149 150

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

L
Linus Torvalds 已提交
154 155 156
		n = write_chan(&line->chan_list, line->head, count,
			       line->driver->write_irq);
		if (n < 0)
157 158
			return n;
		if (n == count) {
J
Jeff Dike 已提交
159 160 161 162
			/*
			 * We have flushed from ->head to buffer end, now we
			 * must flush only from the beginning to ->tail.
			 */
L
Linus Torvalds 已提交
163
			line->head = line->buffer;
164
		} else {
L
Linus Torvalds 已提交
165
			line->head += n;
166
			return 0;
L
Linus Torvalds 已提交
167 168 169 170
		}
	}

	count = line->tail - line->head;
J
Jeff Dike 已提交
171
	n = write_chan(&line->chan_list, line->head, count,
L
Linus Torvalds 已提交
172
		       line->driver->write_irq);
173

J
Jeff Dike 已提交
174
	if (n < 0)
175
		return n;
L
Linus Torvalds 已提交
176 177

	line->head += n;
178 179 180 181 182 183 184 185 186 187
	return line->head == line->tail;
}

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

	/*XXX: copied from line_write, verify if it is correct!*/
J
Jeff Dike 已提交
188
	if (tty->stopped)
189 190 191 192 193 194 195
		return;

	spin_lock_irqsave(&line->lock, flags);
	err = flush_buffer(line);
	spin_unlock_irqrestore(&line->lock, flags);
}

J
Jeff Dike 已提交
196 197 198 199
/*
 * We map both ->flush_chars and ->put_char (which go in pair) onto
 * ->flush_buffer and ->write. Hope it's not that bad.
 */
200 201 202 203 204 205 206 207
void line_flush_chars(struct tty_struct *tty)
{
	line_flush_buffer(tty);
}

void line_put_char(struct tty_struct *tty, unsigned char ch)
{
	line_write(tty, &ch, sizeof(ch));
L
Linus Torvalds 已提交
208 209 210 211 212 213
}

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 已提交
214
	int n, ret = 0;
L
Linus Torvalds 已提交
215

J
Jeff Dike 已提交
216
	if (tty->stopped)
217
		return 0;
L
Linus Torvalds 已提交
218

219
	spin_lock_irqsave(&line->lock, flags);
J
Jeff Dike 已提交
220
	if (line->head != line->tail)
L
Linus Torvalds 已提交
221
		ret = buffer_data(line, buf, len);
J
Jeff Dike 已提交
222
	else {
J
Jeff Dike 已提交
223
		n = write_chan(&line->chan_list, buf, len,
L
Linus Torvalds 已提交
224
			       line->driver->write_irq);
225
		if (n < 0) {
L
Linus Torvalds 已提交
226 227 228 229 230 231
			ret = n;
			goto out_up;
		}

		len -= n;
		ret += n;
232
		if (len > 0)
L
Linus Torvalds 已提交
233 234
			ret += buffer_data(line, buf + n, len);
	}
235 236 237
out_up:
	spin_unlock_irqrestore(&line->lock, flags);
	return ret;
L
Linus Torvalds 已提交
238 239
}

A
Alan Cox 已提交
240
void line_set_termios(struct tty_struct *tty, struct ktermios * old)
L
Linus Torvalds 已提交
241 242 243 244
{
	/* nothing */
}

J
Jeff Dike 已提交
245
static const struct {
L
Linus Torvalds 已提交
246 247 248 249 250 251
	int  cmd;
	char *level;
	char *name;
} tty_ioctls[] = {
	/* don't print these, they flood the log ... */
	{ TCGETS,      NULL,       "TCGETS"      },
J
Jeff Dike 已提交
252 253 254 255
	{ TCSETS,      NULL,       "TCSETS"      },
	{ TCSETSW,     NULL,       "TCSETSW"     },
	{ TCFLSH,      NULL,       "TCFLSH"      },
	{ TCSBRK,      NULL,       "TCSBRK"      },
L
Linus Torvalds 已提交
256 257

	/* general tty stuff */
J
Jeff Dike 已提交
258 259 260 261 262
	{ TCSETSF,     KERN_DEBUG, "TCSETSF"     },
	{ TCGETA,      KERN_DEBUG, "TCGETA"      },
	{ TIOCMGET,    KERN_DEBUG, "TIOCMGET"    },
	{ TCSBRKP,     KERN_DEBUG, "TCSBRKP"     },
	{ TIOCMSET,    KERN_DEBUG, "TIOCMSET"    },
L
Linus Torvalds 已提交
263 264 265 266 267 268 269 270 271 272 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 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318

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

int line_ioctl(struct tty_struct *tty, struct file * file,
	       unsigned int cmd, unsigned long arg)
{
	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
	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 已提交
319
		if (i == ARRAY_SIZE(tty_ioctls)) {
L
Linus Torvalds 已提交
320 321 322 323 324 325
			printk(KERN_ERR "%s: %s: unknown ioctl: 0x%x\n",
			       __FUNCTION__, tty->name, cmd);
		}
		ret = -ENOIOCTLCMD;
		break;
	}
326
	return ret;
L
Linus Torvalds 已提交
327 328
}

329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344
void line_throttle(struct tty_struct *tty)
{
	struct line *line = tty->driver_data;

	deactivate_chan(&line->chan_list, line->driver->read_irq);
	line->throttled = 1;
}

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

	line->throttled = 0;
	chan_interrupt(&line->chan_list, &line->task, tty,
		       line->driver->read_irq);

J
Jeff Dike 已提交
345 346
	/*
	 * Maybe there is enough stuff pending that calling the interrupt
347 348 349
	 * throttles us again.  In this case, line->throttled will be 1
	 * again and we shouldn't turn the interrupt back on.
	 */
J
Jeff Dike 已提交
350
	if (!line->throttled)
351 352 353
		reactivate_chan(&line->chan_list, line->driver->read_irq);
}

A
Al Viro 已提交
354
static irqreturn_t line_write_interrupt(int irq, void *data)
L
Linus Torvalds 已提交
355
{
356 357 358
	struct chan *chan = data;
	struct line *line = chan->line;
	struct tty_struct *tty = line->tty;
L
Linus Torvalds 已提交
359 360
	int err;

J
Jeff Dike 已提交
361 362 363 364
	/*
	 * Interrupts are disabled here because we registered the interrupt with
	 * IRQF_DISABLED (see line_setup_irq).
	 */
365

366
	spin_lock(&line->lock);
L
Linus Torvalds 已提交
367
	err = flush_buffer(line);
368 369
	if (err == 0) {
		return IRQ_NONE;
J
Jeff Dike 已提交
370
	} else if (err < 0) {
L
Linus Torvalds 已提交
371 372 373
		line->head = line->buffer;
		line->tail = line->buffer;
	}
374
	spin_unlock(&line->lock);
L
Linus Torvalds 已提交
375

J
Jeff Dike 已提交
376
	if (tty == NULL)
377
		return IRQ_NONE;
L
Linus Torvalds 已提交
378

379
	if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) &&
L
Linus Torvalds 已提交
380 381
	   (tty->ldisc.write_wakeup != NULL))
		(tty->ldisc.write_wakeup)(tty);
382

J
Jeff Dike 已提交
383 384
	/*
	 * BLOCKING mode
L
Linus Torvalds 已提交
385 386 387 388 389
	 * In blocking mode, everything sleeps on tty->write_wait.
	 * Sleeping in the console driver would break non-blocking
	 * writes.
	 */

390
	if (waitqueue_active(&tty->write_wait))
L
Linus Torvalds 已提交
391
		wake_up_interruptible(&tty->write_wait);
392
	return IRQ_HANDLED;
L
Linus Torvalds 已提交
393 394
}

395
int line_setup_irq(int fd, int input, int output, struct line *line, void *data)
L
Linus Torvalds 已提交
396
{
J
Jeff Dike 已提交
397
	const struct line_driver *driver = line->driver;
398
	int err = 0, flags = IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM;
L
Linus Torvalds 已提交
399

400 401
	if (input)
		err = um_request_irq(driver->read_irq, fd, IRQ_READ,
J
Jeff Dike 已提交
402
				       line_interrupt, flags,
403
				       driver->read_irq_name, data);
404 405 406 407
	if (err)
		return err;
	if (output)
		err = um_request_irq(driver->write_irq, fd, IRQ_WRITE,
J
Jeff Dike 已提交
408
					line_write_interrupt, flags,
409
					driver->write_irq_name, data);
L
Linus Torvalds 已提交
410
	line->have_irq = 1;
411
	return err;
L
Linus Torvalds 已提交
412 413
}

J
Jeff Dike 已提交
414 415
/*
 * Normally, a driver like this can rely mostly on the tty layer
J
Jeff Dike 已提交
416 417 418 419
 * 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.
 *
420 421 422 423 424
 * 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 已提交
425
 *
426 427 428
 * tty->count serves to decide whether the device should be enabled or
 * disabled on the host.  If it's equal to 1, then we are doing the
 * first open or last close.  Otherwise, open and close just return.
J
Jeff Dike 已提交
429 430
 */

431
int line_open(struct line *lines, struct tty_struct *tty)
L
Linus Torvalds 已提交
432
{
J
Jeff Dike 已提交
433
	struct line *line = &lines[tty->index];
434
	int err = -ENODEV;
L
Linus Torvalds 已提交
435

J
Jeff Dike 已提交
436
	spin_lock(&line->count_lock);
J
Jeff Dike 已提交
437
	if (!line->valid)
J
Jeff Dike 已提交
438
		goto out_unlock;
L
Linus Torvalds 已提交
439

J
Jeff Dike 已提交
440
	err = 0;
J
Jeff Dike 已提交
441
	if (tty->count > 1)
J
Jeff Dike 已提交
442 443 444
		goto out_unlock;

	spin_unlock(&line->count_lock);
445

446 447 448
	tty->driver_data = line;
	line->tty = tty;

449 450 451 452
	err = enable_chan(line);
	if (err)
		return err;

J
Jeff Dike 已提交
453
	INIT_DELAYED_WORK(&line->task, line_timer_cb);
454

J
Jeff Dike 已提交
455
	if (!line->sigio) {
J
Jeff Dike 已提交
456 457
		chan_enable_winch(&line->chan_list, tty);
		line->sigio = 1;
L
Linus Torvalds 已提交
458 459
	}

J
Jeff Dike 已提交
460 461 462 463 464 465 466
	chan_window_size(&line->chan_list, &tty->winsize.ws_row,
			 &tty->winsize.ws_col);

	return err;

out_unlock:
	spin_unlock(&line->count_lock);
467
	return err;
L
Linus Torvalds 已提交
468 469
}

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

L
Linus Torvalds 已提交
472 473 474 475
void line_close(struct tty_struct *tty, struct file * filp)
{
	struct line *line = tty->driver_data;

J
Jeff Dike 已提交
476 477
	/*
	 * If line_open fails (and tty->driver_data is never set),
J
Jeff Dike 已提交
478 479
	 * tty_open will call line_close.  So just return in this case.
	 */
J
Jeff Dike 已提交
480
	if (line == NULL)
J
Jeff Dike 已提交
481
		return;
482 483 484 485

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

J
Jeff Dike 已提交
486
	spin_lock(&line->count_lock);
J
Jeff Dike 已提交
487
	if (!line->valid)
J
Jeff Dike 已提交
488
		goto out_unlock;
J
Jeff Dike 已提交
489

J
Jeff Dike 已提交
490
	if (tty->count > 1)
J
Jeff Dike 已提交
491 492 493 494 495 496 497
		goto out_unlock;

	spin_unlock(&line->count_lock);

	line->tty = NULL;
	tty->driver_data = NULL;

J
Jeff Dike 已提交
498
	if (line->sigio) {
J
Jeff Dike 已提交
499 500
		unregister_winch(tty);
		line->sigio = 0;
J
Jeff Dike 已提交
501
	}
J
Jeff Dike 已提交
502

J
Jeff Dike 已提交
503 504 505 506
	return;

out_unlock:
	spin_unlock(&line->count_lock);
L
Linus Torvalds 已提交
507 508 509 510 511 512 513
}

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

	for(i = 0; i < nlines; i++)
514
		close_chan(&lines[i].chan_list, 0);
L
Linus Torvalds 已提交
515 516
}

517 518
static int setup_one_line(struct line *lines, int n, char *init, int init_prio,
			  char **error_out)
J
Jeff Dike 已提交
519 520
{
	struct line *line = &lines[n];
521
	int err = -EINVAL;
J
Jeff Dike 已提交
522 523 524

	spin_lock(&line->count_lock);

J
Jeff Dike 已提交
525
	if (line->tty != NULL) {
526
		*error_out = "Device is already open";
J
Jeff Dike 已提交
527 528 529
		goto out;
	}

J
Jeff Dike 已提交
530
	if (line->init_pri <= init_prio) {
J
Jeff Dike 已提交
531 532 533 534 535 536 537 538
		line->init_pri = init_prio;
		if (!strcmp(init, "none"))
			line->valid = 0;
		else {
			line->init_str = init;
			line->valid = 1;
		}
	}
539
	err = 0;
J
Jeff Dike 已提交
540 541
out:
	spin_unlock(&line->count_lock);
542
	return err;
J
Jeff Dike 已提交
543 544
}

J
Jeff Dike 已提交
545 546
/*
 * Common setup code for both startup command line and mconsole initialization.
M
Matt LaPlante 已提交
547
 * @lines contains the array (of size @num) to modify;
548
 * @init is the setup string;
549
 * @error_out is an error string in the case of failure;
550
 */
551

552 553
int line_setup(struct line *lines, unsigned int num, char *init,
	       char **error_out)
L
Linus Torvalds 已提交
554
{
555
	int i, n, err;
L
Linus Torvalds 已提交
556 557
	char *end;

J
Jeff Dike 已提交
558 559 560 561 562
	if (*init == '=') {
		/*
		 * We said con=/ssl= instead of con#=, so we are configuring all
		 * consoles at once.
		 */
563
		n = -1;
J
Jeff Dike 已提交
564 565
	}
	else {
L
Linus Torvalds 已提交
566
		n = simple_strtoul(init, &end, 0);
J
Jeff Dike 已提交
567
		if (*end != '=') {
568 569
			*error_out = "Couldn't parse device number";
			return -EINVAL;
L
Linus Torvalds 已提交
570 571 572 573
		}
		init = end;
	}
	init++;
574 575

	if (n >= (signed int) num) {
576 577 578
		*error_out = "Device number out of range";
		return -EINVAL;
	}
J
Jeff Dike 已提交
579
	else if (n >= 0) {
580
		err = setup_one_line(lines, n, init, INIT_ONE, error_out);
J
Jeff Dike 已提交
581
		if (err)
582
			return err;
J
Jeff Dike 已提交
583 584
	}
	else {
J
Jeff Dike 已提交
585
		for(i = 0; i < num; i++) {
586 587
			err = setup_one_line(lines, i, init, INIT_ALL,
					     error_out);
J
Jeff Dike 已提交
588
			if (err)
589 590
				return err;
		}
L
Linus Torvalds 已提交
591
	}
592
	return n == -1 ? num : n;
L
Linus Torvalds 已提交
593 594
}

595
int line_config(struct line *lines, unsigned int num, char *str,
596
		const struct chan_opts *opts, char **error_out)
L
Linus Torvalds 已提交
597
{
598
	struct line *line;
J
Jeff Dike 已提交
599
	char *new;
600
	int n;
L
Linus Torvalds 已提交
601

J
Jeff Dike 已提交
602
	if (*str == '=') {
603 604
		*error_out = "Can't configure all devices from mconsole";
		return -EINVAL;
605 606
	}

J
Jeff Dike 已提交
607
	new = kstrdup(str, GFP_KERNEL);
J
Jeff Dike 已提交
608
	if (new == NULL) {
609 610
		*error_out = "Failed to allocate memory";
		return -ENOMEM;
L
Linus Torvalds 已提交
611
	}
612
	n = line_setup(lines, num, new, error_out);
J
Jeff Dike 已提交
613
	if (n < 0)
614
		return n;
615 616

	line = &lines[n];
617
	return parse_chan_pair(line->init_str, line, n, opts, error_out);
L
Linus Torvalds 已提交
618 619
}

620
int line_get_config(char *name, struct line *lines, unsigned int num, char *str,
L
Linus Torvalds 已提交
621 622 623 624 625 626 627
		    int size, char **error_out)
{
	struct line *line;
	char *end;
	int dev, n = 0;

	dev = simple_strtoul(name, &end, 0);
J
Jeff Dike 已提交
628
	if ((*end != '\0') || (end == name)) {
L
Linus Torvalds 已提交
629
		*error_out = "line_get_config failed to parse device number";
630
		return 0;
L
Linus Torvalds 已提交
631 632
	}

J
Jeff Dike 已提交
633
	if ((dev < 0) || (dev >= num)) {
634 635
		*error_out = "device number out of range";
		return 0;
L
Linus Torvalds 已提交
636 637 638 639
	}

	line = &lines[dev];

J
Jeff Dike 已提交
640
	spin_lock(&line->count_lock);
J
Jeff Dike 已提交
641
	if (!line->valid)
L
Linus Torvalds 已提交
642
		CONFIG_CHUNK(str, size, n, "none", 1);
J
Jeff Dike 已提交
643
	else if (line->tty == NULL)
L
Linus Torvalds 已提交
644 645
		CONFIG_CHUNK(str, size, n, line->init_str, 1);
	else n = chan_config_string(&line->chan_list, str, size, error_out);
J
Jeff Dike 已提交
646
	spin_unlock(&line->count_lock);
L
Linus Torvalds 已提交
647

648
	return n;
L
Linus Torvalds 已提交
649 650
}

J
Jeff Dike 已提交
651 652 653
int line_id(char **str, int *start_out, int *end_out)
{
	char *end;
J
Jeff Dike 已提交
654
	int n;
J
Jeff Dike 已提交
655 656

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

J
Jeff Dike 已提交
660 661 662 663
	*str = end;
	*start_out = n;
	*end_out = n;
	return n;
J
Jeff Dike 已提交
664 665
}

666
int line_remove(struct line *lines, unsigned int num, int n, char **error_out)
L
Linus Torvalds 已提交
667
{
668
	int err;
L
Linus Torvalds 已提交
669 670
	char config[sizeof("conxxxx=none\0")];

J
Jeff Dike 已提交
671
	sprintf(config, "%d=none", n);
672
	err = line_setup(lines, num, config, error_out);
J
Jeff Dike 已提交
673
	if (err >= 0)
674 675
		err = 0;
	return err;
L
Linus Torvalds 已提交
676 677
}

678 679 680
struct tty_driver *register_lines(struct line_driver *line_driver,
				  const struct tty_operations *ops,
				  struct line *lines, int nlines)
L
Linus Torvalds 已提交
681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698
{
	int i;
	struct tty_driver *driver = alloc_tty_driver(nlines);

	if (!driver)
		return NULL;

	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;
	driver->flags = TTY_DRIVER_REAL_RAW;
	driver->init_termios = tty_std_termios;
	tty_set_operations(driver, ops);

	if (tty_register_driver(driver)) {
J
Jeff Dike 已提交
699 700
		printk(KERN_ERR "register_lines : can't register %s driver\n",
		       line_driver->name);
L
Linus Torvalds 已提交
701 702 703 704
		put_tty_driver(driver);
		return NULL;
	}

J
Jeff Dike 已提交
705 706
	for(i = 0; i < nlines; i++) {
		if (!lines[i].valid)
L
Linus Torvalds 已提交
707 708 709 710 711 712 713
			tty_unregister_device(driver, i);
	}

	mconsole_register_dev(&line_driver->mc);
	return driver;
}

714 715
static DEFINE_SPINLOCK(winch_handler_lock);
static LIST_HEAD(winch_handlers);
716

717
void lines_init(struct line *lines, int nlines, struct chan_opts *opts)
L
Linus Torvalds 已提交
718 719
{
	struct line *line;
720
	char *error;
L
Linus Torvalds 已提交
721 722
	int i;

J
Jeff Dike 已提交
723
	for(i = 0; i < nlines; i++) {
L
Linus Torvalds 已提交
724 725
		line = &lines[i];
		INIT_LIST_HEAD(&line->chan_list);
726

J
Jeff Dike 已提交
727
		if (line->init_str == NULL)
J
Jeff Dike 已提交
728 729 730
			continue;

		line->init_str = kstrdup(line->init_str, GFP_KERNEL);
J
Jeff Dike 已提交
731 732
		if (line->init_str == NULL)
			printk(KERN_ERR "lines_init - kstrdup returned NULL\n");
733

J
Jeff Dike 已提交
734 735 736
		if (parse_chan_pair(line->init_str, line, i, opts, &error)) {
			printk(KERN_ERR "parse_chan_pair failed for "
			       "device %d : %s\n", i, error);
737 738
			line->valid = 0;
		}
L
Linus Torvalds 已提交
739 740 741 742 743 744 745 746 747
	}
}

struct winch {
	struct list_head list;
	int fd;
	int tty_fd;
	int pid;
	struct tty_struct *tty;
J
Jeff Dike 已提交
748
	unsigned long stack;
L
Linus Torvalds 已提交
749 750
};

J
Jeff Dike 已提交
751 752 753 754 755 756 757 758 759 760 761 762 763 764 765
static void free_winch(struct winch *winch, int free_irq_ok)
{
	list_del(&winch->list);

	if (winch->pid != -1)
		os_kill_process(winch->pid, 1);
	if (winch->fd != -1)
		os_close_file(winch->fd);
	if (winch->stack != 0)
		free_stack(winch->stack, 0);
	if (free_irq_ok)
		free_irq(WINCH_IRQ, winch);
	kfree(winch);
}

A
Al Viro 已提交
766
static irqreturn_t winch_interrupt(int irq, void *data)
L
Linus Torvalds 已提交
767 768 769 770 771 772 773
{
	struct winch *winch = data;
	struct tty_struct *tty;
	struct line *line;
	int err;
	char c;

J
Jeff Dike 已提交
774
	if (winch->fd != -1) {
L
Linus Torvalds 已提交
775
		err = generic_read(winch->fd, &c, NULL);
J
Jeff Dike 已提交
776 777 778 779 780 781
		if (err < 0) {
			if (err != -EAGAIN) {
				printk(KERN_ERR "winch_interrupt : "
				       "read failed, errno = %d\n", -err);
				printk(KERN_ERR "fd %d is losing SIGWINCH "
				       "support\n", winch->tty_fd);
J
Jeff Dike 已提交
782
				free_winch(winch, 0);
783
				return IRQ_HANDLED;
L
Linus Torvalds 已提交
784 785 786 787
			}
			goto out;
		}
	}
J
Jeff Dike 已提交
788
	tty = winch->tty;
L
Linus Torvalds 已提交
789 790
	if (tty != NULL) {
		line = tty->driver_data;
J
Jeff Dike 已提交
791
		chan_window_size(&line->chan_list, &tty->winsize.ws_row,
L
Linus Torvalds 已提交
792
				 &tty->winsize.ws_col);
793
		kill_pgrp(tty->pgrp, SIGWINCH, 1);
L
Linus Torvalds 已提交
794 795
	}
 out:
J
Jeff Dike 已提交
796
	if (winch->fd != -1)
L
Linus Torvalds 已提交
797
		reactivate_fd(winch->fd, WINCH_IRQ);
798
	return IRQ_HANDLED;
L
Linus Torvalds 已提交
799 800
}

J
Jeff Dike 已提交
801 802
void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty,
			unsigned long stack)
L
Linus Torvalds 已提交
803 804 805 806 807
{
	struct winch *winch;

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

L
Linus Torvalds 已提交
812 813 814 815
	*winch = ((struct winch) { .list  	= LIST_HEAD_INIT(winch->list),
				   .fd  	= fd,
				   .tty_fd 	= tty_fd,
				   .pid  	= pid,
J
Jeff Dike 已提交
816 817 818 819 820 821
				   .tty 	= tty,
				   .stack	= stack });

	if (um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt,
			   IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM,
			   "winch", winch) < 0) {
J
Jeff Dike 已提交
822 823
		printk(KERN_ERR "register_winch_irq - failed to register "
		       "IRQ\n");
J
Jeff Dike 已提交
824 825
		goto out_free;
	}
826 827

	spin_lock(&winch_handler_lock);
L
Linus Torvalds 已提交
828
	list_add(&winch->list, &winch_handlers);
829 830
	spin_unlock(&winch_handler_lock);

J
Jeff Dike 已提交
831
	return;
832

J
Jeff Dike 已提交
833
 out_free:
834
	kfree(winch);
J
Jeff Dike 已提交
835 836 837 838 839
 cleanup:
	os_kill_process(pid, 1);
	os_close_file(fd);
	if (stack != 0)
		free_stack(stack, 0);
840 841
}

J
Jeff Dike 已提交
842 843 844
static void unregister_winch(struct tty_struct *tty)
{
	struct list_head *ele;
845
	struct winch *winch;
J
Jeff Dike 已提交
846

847
	spin_lock(&winch_handler_lock);
848

J
Jeff Dike 已提交
849
	list_for_each(ele, &winch_handlers) {
J
Jeff Dike 已提交
850
		winch = list_entry(ele, struct winch, list);
J
Jeff Dike 已提交
851
		if (winch->tty == tty) {
J
Jeff Dike 已提交
852
			free_winch(winch, 1);
853
			break;
J
Jeff Dike 已提交
854 855
		}
	}
856
	spin_unlock(&winch_handler_lock);
J
Jeff Dike 已提交
857 858
}

L
Linus Torvalds 已提交
859 860
static void winch_cleanup(void)
{
861
	struct list_head *ele, *next;
L
Linus Torvalds 已提交
862 863
	struct winch *winch;

864 865
	spin_lock(&winch_handler_lock);

J
Jeff Dike 已提交
866
	list_for_each_safe(ele, next, &winch_handlers) {
L
Linus Torvalds 已提交
867
		winch = list_entry(ele, struct winch, list);
J
Jeff Dike 已提交
868
		free_winch(winch, 1);
L
Linus Torvalds 已提交
869
	}
870 871

	spin_unlock(&winch_handler_lock);
L
Linus Torvalds 已提交
872 873 874 875 876 877 878 879
}
__uml_exitcall(winch_cleanup);

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

J
Jeff Dike 已提交
880
	umid = get_umid();
J
Jeff Dike 已提交
881
	if (*umid == '\0')
882
		return base;
883

L
Linus Torvalds 已提交
884 885
	len = strlen(base) + strlen(" ()") + strlen(umid) + 1;
	title = kmalloc(len, GFP_KERNEL);
J
Jeff Dike 已提交
886 887
	if (title == NULL) {
		printk(KERN_ERR "Failed to allocate buffer for xterm title\n");
888
		return base;
L
Linus Torvalds 已提交
889 890 891
	}

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