Blame view

arch/um/drivers/line.c 19.1 KB
165dc5911   Jeff Dike   [PATCH] uml: Simp...
1
  /*
2f8a2dc2c   Jeff Dike   uml: console tidying
2
   * Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
   * Licensed under the GPL
   */
2f8a2dc2c   Jeff Dike   uml: console tidying
5
  #include "linux/irqreturn.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
  #include "linux/kd.h"
d43c36dc6   Alexey Dobriyan   headers: remove s...
7
  #include "linux/sched.h"
7f3c1fa4c   Jan Kiszka   uml: Fix build br...
8
  #include "linux/slab.h"
510c72a3c   Al Viro   um: take chan_*.h...
9
  #include "chan.h"
2f8a2dc2c   Jeff Dike   uml: console tidying
10
  #include "irq_kern.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
  #include "irq_user.h"
edea13858   Jeff Dike   uml: tidy kern_ut...
12
  #include "kern_util.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
  #include "os.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
14
15
  
  #define LINE_BUFSIZE 4096
7bea96fd2   Al Viro   [PATCH] uml pt_re...
16
  static irqreturn_t line_interrupt(int irq, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
  {
165dc5911   Jeff Dike   [PATCH] uml: Simp...
18
19
  	struct chan *chan = data;
  	struct line *line = chan->line;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
21
  
  	if (line)
03315b591   Alexander Beregalov   uml: line.c: avoi...
22
  		chan_interrupt(&line->chan_list, &line->task, line->tty, irq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
23
24
  	return IRQ_HANDLED;
  }
a2ce77409   Andrew Morton   [PATCH] uml: work...
25
  static void line_timer_cb(struct work_struct *work)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
  {
a2ce77409   Andrew Morton   [PATCH] uml: work...
27
  	struct line *line = container_of(work, struct line, task.work);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28

2f8a2dc2c   Jeff Dike   uml: console tidying
29
  	if (!line->throttled)
e4dcee809   Jeff Dike   [PATCH] uml: Add ...
30
31
  		chan_interrupt(&line->chan_list, &line->task, line->tty,
  			       line->driver->read_irq);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
  }
2f8a2dc2c   Jeff Dike   uml: console tidying
33
34
  /*
   * Returns the free space inside the ring buffer of this line.
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
35
   *
b60745b96   Simon Arlott   spelling fixes: a...
36
   * Should be called while holding line->lock (this does not modify data).
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
37
38
   */
  static int write_room(struct line *line)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
  {
  	int n;
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
41
42
43
44
45
  	if (line->buffer == NULL)
  		return LINE_BUFSIZE - 1;
  
  	/* This is for the case where the buffer is wrapped! */
  	n = line->head - line->tail;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
  	if (n <= 0)
acb2cf34c   Jeff Dike   uml: console driv...
48
  		n += LINE_BUFSIZE; /* The other case */
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
49
50
51
52
53
54
55
56
  	return n - 1;
  }
  
  int line_write_room(struct tty_struct *tty)
  {
  	struct line *line = tty->driver_data;
  	unsigned long flags;
  	int room;
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
57
58
59
  	spin_lock_irqsave(&line->lock, flags);
  	room = write_room(line);
  	spin_unlock_irqrestore(&line->lock, flags);
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
60
  	return room;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
  }
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
62
63
64
65
66
67
68
  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);
acb2cf34c   Jeff Dike   uml: console driv...
69
  	/* write_room subtracts 1 for the needed NULL, so we readd it.*/
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
  	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!
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
86
87
  static int buffer_data(struct line *line, const char *buf, int len)
  {
  	int end, room;
2f8a2dc2c   Jeff Dike   uml: console tidying
88
  	if (line->buffer == NULL) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
89
90
  		line->buffer = kmalloc(LINE_BUFSIZE, GFP_ATOMIC);
  		if (line->buffer == NULL) {
2f8a2dc2c   Jeff Dike   uml: console tidying
91
92
93
94
  			printk(KERN_ERR "buffer_data - atomic allocation "
  			       "failed
  ");
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
95
96
97
98
99
100
101
102
103
  		}
  		line->head = line->buffer;
  		line->tail = line->buffer;
  	}
  
  	room = write_room(line);
  	len = (len > room) ? room : len;
  
  	end = line->buffer + LINE_BUFSIZE - line->tail;
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
104

2f8a2dc2c   Jeff Dike   uml: console tidying
105
  	if (len < end) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
107
  		memcpy(line->tail, buf, len);
  		line->tail += len;
d50084a29   Jeff Dike   [PATCH] uml: Form...
108
109
  	}
  	else {
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
110
  		/* The circular buffer is wrapping */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
111
112
113
114
115
  		memcpy(line->tail, buf, end);
  		buf += end;
  		memcpy(line->buffer, buf, len - end);
  		line->tail = line->buffer + len - end;
  	}
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
116
  	return len;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
  }
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
118
119
120
121
122
123
124
125
126
  /*
   * 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!*/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
129
130
131
  static int flush_buffer(struct line *line)
  {
  	int n, count;
  
  	if ((line->buffer == NULL) || (line->head == line->tail))
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
132
  		return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
134
  
  	if (line->tail < line->head) {
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
135
  		/* line->buffer + LINE_BUFSIZE is the end of the buffer! */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
  		count = line->buffer + LINE_BUFSIZE - line->head;
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
137

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
139
140
  		n = write_chan(&line->chan_list, line->head, count,
  			       line->driver->write_irq);
  		if (n < 0)
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
141
142
  			return n;
  		if (n == count) {
2f8a2dc2c   Jeff Dike   uml: console tidying
143
144
145
146
  			/*
  			 * We have flushed from ->head to buffer end, now we
  			 * must flush only from the beginning to ->tail.
  			 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
  			line->head = line->buffer;
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
148
  		} else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
  			line->head += n;
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
150
  			return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
153
154
  		}
  	}
  
  	count = line->tail - line->head;
d50084a29   Jeff Dike   [PATCH] uml: Form...
155
  	n = write_chan(&line->chan_list, line->head, count,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
  		       line->driver->write_irq);
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
157

2f8a2dc2c   Jeff Dike   uml: console tidying
158
  	if (n < 0)
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
159
  		return n;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
161
  
  	line->head += n;
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
162
163
164
165
166
167
168
  	return line->head == line->tail;
  }
  
  void line_flush_buffer(struct tty_struct *tty)
  {
  	struct line *line = tty->driver_data;
  	unsigned long flags;
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
169

b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
170
  	spin_lock_irqsave(&line->lock, flags);
f1c93e494   Richard Weinberger   um: remove dead code
171
  	flush_buffer(line);
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
172
  	spin_unlock_irqrestore(&line->lock, flags);
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
173
  }
2f8a2dc2c   Jeff Dike   uml: console tidying
174
175
176
177
  /*
   * We map both ->flush_chars and ->put_char (which go in pair) onto
   * ->flush_buffer and ->write. Hope it's not that bad.
   */
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
178
179
180
181
  void line_flush_chars(struct tty_struct *tty)
  {
  	line_flush_buffer(tty);
  }
3168cb98b   WANG Cong   uml: fix inconsis...
182
  int line_put_char(struct tty_struct *tty, unsigned char ch)
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
183
  {
3168cb98b   WANG Cong   uml: fix inconsis...
184
  	return line_write(tty, &ch, sizeof(ch));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
186
187
188
189
190
  }
  
  int line_write(struct tty_struct *tty, const unsigned char *buf, int len)
  {
  	struct line *line = tty->driver_data;
  	unsigned long flags;
c59dbcadd   Jeff Dike   uml: fix console ...
191
  	int n, ret = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
192

b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
193
  	spin_lock_irqsave(&line->lock, flags);
c59dbcadd   Jeff Dike   uml: fix console ...
194
  	if (line->head != line->tail)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
  		ret = buffer_data(line, buf, len);
c59dbcadd   Jeff Dike   uml: fix console ...
196
  	else {
d50084a29   Jeff Dike   [PATCH] uml: Form...
197
  		n = write_chan(&line->chan_list, buf, len,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
  			       line->driver->write_irq);
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
199
  		if (n < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
201
202
203
204
205
  			ret = n;
  			goto out_up;
  		}
  
  		len -= n;
  		ret += n;
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
206
  		if (len > 0)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
208
  			ret += buffer_data(line, buf + n, len);
  	}
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
209
210
211
  out_up:
  	spin_unlock_irqrestore(&line->lock, flags);
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
  }
606d099cd   Alan Cox   [PATCH] tty: swit...
213
  void line_set_termios(struct tty_struct *tty, struct ktermios * old)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
214
215
216
  {
  	/* nothing */
  }
5e7672ec3   Jeff Dike   [PATCH] uml: cons...
217
  static const struct {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
218
219
220
221
222
223
  	int  cmd;
  	char *level;
  	char *name;
  } tty_ioctls[] = {
  	/* don't print these, they flood the log ... */
  	{ TCGETS,      NULL,       "TCGETS"      },
2f8a2dc2c   Jeff Dike   uml: console tidying
224
225
226
227
  	{ TCSETS,      NULL,       "TCSETS"      },
  	{ TCSETSW,     NULL,       "TCSETSW"     },
  	{ TCFLSH,      NULL,       "TCFLSH"      },
  	{ TCSBRK,      NULL,       "TCSBRK"      },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
229
  
  	/* general tty stuff */
2f8a2dc2c   Jeff Dike   uml: console tidying
230
231
232
233
234
  	{ TCSETSF,     KERN_DEBUG, "TCSETSF"     },
  	{ TCGETA,      KERN_DEBUG, "TCGETA"      },
  	{ TIOCMGET,    KERN_DEBUG, "TIOCMGET"    },
  	{ TCSBRKP,     KERN_DEBUG, "TCSBRKP"     },
  	{ TIOCMSET,    KERN_DEBUG, "TIOCMSET"    },
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
236
237
238
239
240
241
  
  	/* linux-specific ones */
  	{ TIOCLINUX,   KERN_INFO,  "TIOCLINUX"   },
  	{ KDGKBMODE,   KERN_INFO,  "KDGKBMODE"   },
  	{ KDGKBTYPE,   KERN_INFO,  "KDGKBTYPE"   },
  	{ KDSIGACCEPT, KERN_INFO,  "KDSIGACCEPT" },
  };
8a06dc4d5   Richard Weinberger   um: remove file p...
242
243
  int line_ioctl(struct tty_struct *tty, unsigned int cmd,
  				unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
  {
  	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
c564b6fda   Alan Cox   uml: small cleanu...
263
264
  	/* Note: these are out of date as we now have TCGETS2 etc but this
  	   whole lot should probably go away */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
  	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;
2f8a2dc2c   Jeff Dike   uml: console tidying
292
  		if (i == ARRAY_SIZE(tty_ioctls)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
293
294
  			printk(KERN_ERR "%s: %s: unknown ioctl: 0x%x
  ",
3595726ac   Harvey Harrison   uml: replace rema...
295
  			       __func__, tty->name, cmd);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
297
298
299
  		}
  		ret = -ENOIOCTLCMD;
  		break;
  	}
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
300
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
301
  }
e4dcee809   Jeff Dike   [PATCH] uml: Add ...
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
  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);
2f8a2dc2c   Jeff Dike   uml: console tidying
317
318
  	/*
  	 * Maybe there is enough stuff pending that calling the interrupt
e4dcee809   Jeff Dike   [PATCH] uml: Add ...
319
320
321
  	 * throttles us again.  In this case, line->throttled will be 1
  	 * again and we shouldn't turn the interrupt back on.
  	 */
2f8a2dc2c   Jeff Dike   uml: console tidying
322
  	if (!line->throttled)
e4dcee809   Jeff Dike   [PATCH] uml: Add ...
323
324
  		reactivate_chan(&line->chan_list, line->driver->read_irq);
  }
7bea96fd2   Al Viro   [PATCH] uml pt_re...
325
  static irqreturn_t line_write_interrupt(int irq, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
326
  {
165dc5911   Jeff Dike   [PATCH] uml: Simp...
327
328
329
  	struct chan *chan = data;
  	struct line *line = chan->line;
  	struct tty_struct *tty = line->tty;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330
  	int err;
2f8a2dc2c   Jeff Dike   uml: console tidying
331
332
333
334
  	/*
  	 * Interrupts are disabled here because we registered the interrupt with
  	 * IRQF_DISABLED (see line_setup_irq).
  	 */
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
335

ec0ac8ad3   Paolo 'Blaisorblade' Giarrusso   [PATCH] um: fix c...
336
  	spin_lock(&line->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
  	err = flush_buffer(line);
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
338
339
  	if (err == 0) {
  		return IRQ_NONE;
2f8a2dc2c   Jeff Dike   uml: console tidying
340
  	} else if (err < 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
341
342
343
  		line->head = line->buffer;
  		line->tail = line->buffer;
  	}
ec0ac8ad3   Paolo 'Blaisorblade' Giarrusso   [PATCH] um: fix c...
344
  	spin_unlock(&line->lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
345

2f8a2dc2c   Jeff Dike   uml: console tidying
346
  	if (tty == NULL)
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
347
  		return IRQ_NONE;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
348

06ac66790   WANG Cong   uml: fix tty-rela...
349
  	tty_wakeup(tty);
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
350
  	return IRQ_HANDLED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
  }
165dc5911   Jeff Dike   [PATCH] uml: Simp...
352
  int line_setup_irq(int fd, int input, int output, struct line *line, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
  {
5e7672ec3   Jeff Dike   [PATCH] uml: cons...
354
  	const struct line_driver *driver = line->driver;
bd6aa6502   Thomas Gleixner   [PATCH] irq-flags...
355
  	int err = 0, flags = IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
356

b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
357
358
  	if (input)
  		err = um_request_irq(driver->read_irq, fd, IRQ_READ,
d50084a29   Jeff Dike   [PATCH] uml: Form...
359
  				       line_interrupt, flags,
165dc5911   Jeff Dike   [PATCH] uml: Simp...
360
  				       driver->read_irq_name, data);
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
361
362
363
364
  	if (err)
  		return err;
  	if (output)
  		err = um_request_irq(driver->write_irq, fd, IRQ_WRITE,
d50084a29   Jeff Dike   [PATCH] uml: Form...
365
  					line_write_interrupt, flags,
165dc5911   Jeff Dike   [PATCH] uml: Simp...
366
  					driver->write_irq_name, data);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
367
  	line->have_irq = 1;
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
368
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
369
  }
2f8a2dc2c   Jeff Dike   uml: console tidying
370
371
  /*
   * Normally, a driver like this can rely mostly on the tty layer
d79a58093   Jeff Dike   [PATCH] uml: cons...
372
373
374
375
   * 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.
   *
c6256c682   Jeff Dike   [PATCH] uml: fix ...
376
377
378
379
380
   * 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.
d79a58093   Jeff Dike   [PATCH] uml: cons...
381
   *
f71f94845   Al Viro   um: fix oopsable ...
382
383
   * 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
c6256c682   Jeff Dike   [PATCH] uml: fix ...
384
   * first open or last close.  Otherwise, open and close just return.
d79a58093   Jeff Dike   [PATCH] uml: cons...
385
   */
1f80171e8   Jeff Dike   [PATCH] uml: move...
386
  int line_open(struct line *lines, struct tty_struct *tty)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
  {
d79a58093   Jeff Dike   [PATCH] uml: cons...
388
  	struct line *line = &lines[tty->index];
165dc5911   Jeff Dike   [PATCH] uml: Simp...
389
  	int err = -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
390

d79a58093   Jeff Dike   [PATCH] uml: cons...
391
  	spin_lock(&line->count_lock);
2f8a2dc2c   Jeff Dike   uml: console tidying
392
  	if (!line->valid)
d79a58093   Jeff Dike   [PATCH] uml: cons...
393
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394

d79a58093   Jeff Dike   [PATCH] uml: cons...
395
  	err = 0;
f71f94845   Al Viro   um: fix oopsable ...
396
  	if (line->count++)
d79a58093   Jeff Dike   [PATCH] uml: cons...
397
  		goto out_unlock;
f71f94845   Al Viro   um: fix oopsable ...
398
  	BUG_ON(tty->driver_data);
165dc5911   Jeff Dike   [PATCH] uml: Simp...
399
400
  	tty->driver_data = line;
  	line->tty = tty;
165dc5911   Jeff Dike   [PATCH] uml: Simp...
401

f71f94845   Al Viro   um: fix oopsable ...
402
  	spin_unlock(&line->count_lock);
d14ad81f8   Jeff Dike   uml: handle error...
403
  	err = enable_chan(line);
f71f94845   Al Viro   um: fix oopsable ...
404
  	if (err) /* line_close() will be called by our caller */
d14ad81f8   Jeff Dike   uml: handle error...
405
  		return err;
d79a58093   Jeff Dike   [PATCH] uml: cons...
406
  	INIT_DELAYED_WORK(&line->task, line_timer_cb);
165dc5911   Jeff Dike   [PATCH] uml: Simp...
407

2f8a2dc2c   Jeff Dike   uml: console tidying
408
  	if (!line->sigio) {
d79a58093   Jeff Dike   [PATCH] uml: cons...
409
410
  		chan_enable_winch(&line->chan_list, tty);
  		line->sigio = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412

d79a58093   Jeff Dike   [PATCH] uml: cons...
413
414
  	chan_window_size(&line->chan_list, &tty->winsize.ws_row,
  			 &tty->winsize.ws_col);
f71f94845   Al Viro   um: fix oopsable ...
415
  	return 0;
d79a58093   Jeff Dike   [PATCH] uml: cons...
416
417
418
  
  out_unlock:
  	spin_unlock(&line->count_lock);
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
419
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
  }
cd2ee4a30   Jeff Dike   [PATCH] uml: Fix ...
421
  static void unregister_winch(struct tty_struct *tty);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
422
423
424
  void line_close(struct tty_struct *tty, struct file * filp)
  {
  	struct line *line = tty->driver_data;
2f8a2dc2c   Jeff Dike   uml: console tidying
425
426
  	/*
  	 * If line_open fails (and tty->driver_data is never set),
d79a58093   Jeff Dike   [PATCH] uml: cons...
427
428
  	 * tty_open will call line_close.  So just return in this case.
  	 */
2f8a2dc2c   Jeff Dike   uml: console tidying
429
  	if (line == NULL)
d79a58093   Jeff Dike   [PATCH] uml: cons...
430
  		return;
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
431
432
433
  
  	/* We ignore the error anyway! */
  	flush_buffer(line);
d79a58093   Jeff Dike   [PATCH] uml: cons...
434
  	spin_lock(&line->count_lock);
f71f94845   Al Viro   um: fix oopsable ...
435
  	BUG_ON(!line->valid);
cd2ee4a30   Jeff Dike   [PATCH] uml: Fix ...
436

f71f94845   Al Viro   um: fix oopsable ...
437
  	if (--line->count)
d79a58093   Jeff Dike   [PATCH] uml: cons...
438
  		goto out_unlock;
d79a58093   Jeff Dike   [PATCH] uml: cons...
439
440
  	line->tty = NULL;
  	tty->driver_data = NULL;
f71f94845   Al Viro   um: fix oopsable ...
441
  	spin_unlock(&line->count_lock);
2f8a2dc2c   Jeff Dike   uml: console tidying
442
  	if (line->sigio) {
d79a58093   Jeff Dike   [PATCH] uml: cons...
443
444
  		unregister_winch(tty);
  		line->sigio = 0;
2f8a2dc2c   Jeff Dike   uml: console tidying
445
  	}
cd2ee4a30   Jeff Dike   [PATCH] uml: Fix ...
446

d79a58093   Jeff Dike   [PATCH] uml: cons...
447
448
449
450
  	return;
  
  out_unlock:
  	spin_unlock(&line->count_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
451
452
453
454
455
456
457
  }
  
  void close_lines(struct line *lines, int nlines)
  {
  	int i;
  
  	for(i = 0; i < nlines; i++)
165dc5911   Jeff Dike   [PATCH] uml: Simp...
458
  		close_chan(&lines[i].chan_list, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
  }
f28169d20   Jeff Dike   [PATCH] uml: retu...
460
461
  static int setup_one_line(struct line *lines, int n, char *init, int init_prio,
  			  char **error_out)
d79a58093   Jeff Dike   [PATCH] uml: cons...
462
463
  {
  	struct line *line = &lines[n];
f28169d20   Jeff Dike   [PATCH] uml: retu...
464
  	int err = -EINVAL;
d79a58093   Jeff Dike   [PATCH] uml: cons...
465
466
  
  	spin_lock(&line->count_lock);
f71f94845   Al Viro   um: fix oopsable ...
467
  	if (line->count) {
f28169d20   Jeff Dike   [PATCH] uml: retu...
468
  		*error_out = "Device is already open";
d79a58093   Jeff Dike   [PATCH] uml: cons...
469
470
  		goto out;
  	}
2f8a2dc2c   Jeff Dike   uml: console tidying
471
  	if (line->init_pri <= init_prio) {
d79a58093   Jeff Dike   [PATCH] uml: cons...
472
473
474
475
476
477
478
479
  		line->init_pri = init_prio;
  		if (!strcmp(init, "none"))
  			line->valid = 0;
  		else {
  			line->init_str = init;
  			line->valid = 1;
  		}
  	}
f28169d20   Jeff Dike   [PATCH] uml: retu...
480
  	err = 0;
d79a58093   Jeff Dike   [PATCH] uml: cons...
481
482
  out:
  	spin_unlock(&line->count_lock);
f28169d20   Jeff Dike   [PATCH] uml: retu...
483
  	return err;
d79a58093   Jeff Dike   [PATCH] uml: cons...
484
  }
2f8a2dc2c   Jeff Dike   uml: console tidying
485
486
  /*
   * Common setup code for both startup command line and mconsole initialization.
4b3f686d4   Matt LaPlante   Attack of "the th...
487
   * @lines contains the array (of size @num) to modify;
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
488
   * @init is the setup string;
f28169d20   Jeff Dike   [PATCH] uml: retu...
489
   * @error_out is an error string in the case of failure;
d571cd18f   Jeff Dike   [PATCH] uml: Move...
490
   */
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
491

f28169d20   Jeff Dike   [PATCH] uml: retu...
492
493
  int line_setup(struct line *lines, unsigned int num, char *init,
  	       char **error_out)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
  {
f28169d20   Jeff Dike   [PATCH] uml: retu...
495
  	int i, n, err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496
  	char *end;
2f8a2dc2c   Jeff Dike   uml: console tidying
497
498
499
500
501
  	if (*init == '=') {
  		/*
  		 * We said con=/ssl= instead of con#=, so we are configuring all
  		 * consoles at once.
  		 */
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
502
  		n = -1;
d50084a29   Jeff Dike   [PATCH] uml: Form...
503
504
  	}
  	else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
  		n = simple_strtoul(init, &end, 0);
2f8a2dc2c   Jeff Dike   uml: console tidying
506
  		if (*end != '=') {
f28169d20   Jeff Dike   [PATCH] uml: retu...
507
508
  			*error_out = "Couldn't parse device number";
  			return -EINVAL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
510
511
512
  		}
  		init = end;
  	}
  	init++;
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
513
514
  
  	if (n >= (signed int) num) {
f28169d20   Jeff Dike   [PATCH] uml: retu...
515
516
517
  		*error_out = "Device number out of range";
  		return -EINVAL;
  	}
2f8a2dc2c   Jeff Dike   uml: console tidying
518
  	else if (n >= 0) {
f28169d20   Jeff Dike   [PATCH] uml: retu...
519
  		err = setup_one_line(lines, n, init, INIT_ONE, error_out);
2f8a2dc2c   Jeff Dike   uml: console tidying
520
  		if (err)
f28169d20   Jeff Dike   [PATCH] uml: retu...
521
  			return err;
d50084a29   Jeff Dike   [PATCH] uml: Form...
522
  	}
d50084a29   Jeff Dike   [PATCH] uml: Form...
523
  	else {
2f8a2dc2c   Jeff Dike   uml: console tidying
524
  		for(i = 0; i < num; i++) {
f28169d20   Jeff Dike   [PATCH] uml: retu...
525
526
  			err = setup_one_line(lines, i, init, INIT_ALL,
  					     error_out);
2f8a2dc2c   Jeff Dike   uml: console tidying
527
  			if (err)
f28169d20   Jeff Dike   [PATCH] uml: retu...
528
529
  				return err;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
530
  	}
418e55d49   Jeff Dike   [PATCH] uml: line...
531
  	return n == -1 ? num : n;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
532
  }
1f80171e8   Jeff Dike   [PATCH] uml: move...
533
  int line_config(struct line *lines, unsigned int num, char *str,
f28169d20   Jeff Dike   [PATCH] uml: retu...
534
  		const struct chan_opts *opts, char **error_out)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
  {
1f80171e8   Jeff Dike   [PATCH] uml: move...
536
  	struct line *line;
970d6e3a3   Jeff Dike   [PATCH] uml: use ...
537
  	char *new;
418e55d49   Jeff Dike   [PATCH] uml: line...
538
  	int n;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539

2f8a2dc2c   Jeff Dike   uml: console tidying
540
  	if (*str == '=') {
f28169d20   Jeff Dike   [PATCH] uml: retu...
541
542
  		*error_out = "Can't configure all devices from mconsole";
  		return -EINVAL;
d571cd18f   Jeff Dike   [PATCH] uml: Move...
543
  	}
970d6e3a3   Jeff Dike   [PATCH] uml: use ...
544
  	new = kstrdup(str, GFP_KERNEL);
2f8a2dc2c   Jeff Dike   uml: console tidying
545
  	if (new == NULL) {
f28169d20   Jeff Dike   [PATCH] uml: retu...
546
547
  		*error_out = "Failed to allocate memory";
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548
  	}
f28169d20   Jeff Dike   [PATCH] uml: retu...
549
  	n = line_setup(lines, num, new, error_out);
2f8a2dc2c   Jeff Dike   uml: console tidying
550
  	if (n < 0)
f28169d20   Jeff Dike   [PATCH] uml: retu...
551
  		return n;
1f80171e8   Jeff Dike   [PATCH] uml: move...
552
553
  
  	line = &lines[n];
f28169d20   Jeff Dike   [PATCH] uml: retu...
554
  	return parse_chan_pair(line->init_str, line, n, opts, error_out);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
  }
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
556
  int line_get_config(char *name, struct line *lines, unsigned int num, char *str,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557
558
559
560
561
562
563
  		    int size, char **error_out)
  {
  	struct line *line;
  	char *end;
  	int dev, n = 0;
  
  	dev = simple_strtoul(name, &end, 0);
2f8a2dc2c   Jeff Dike   uml: console tidying
564
  	if ((*end != '\0') || (end == name)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
565
  		*error_out = "line_get_config failed to parse device number";
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
566
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
567
  	}
2f8a2dc2c   Jeff Dike   uml: console tidying
568
  	if ((dev < 0) || (dev >= num)) {
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
569
570
  		*error_out = "device number out of range";
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
571
572
573
  	}
  
  	line = &lines[dev];
d79a58093   Jeff Dike   [PATCH] uml: cons...
574
  	spin_lock(&line->count_lock);
2f8a2dc2c   Jeff Dike   uml: console tidying
575
  	if (!line->valid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
576
  		CONFIG_CHUNK(str, size, n, "none", 1);
2f8a2dc2c   Jeff Dike   uml: console tidying
577
  	else if (line->tty == NULL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578
579
  		CONFIG_CHUNK(str, size, n, line->init_str, 1);
  	else n = chan_config_string(&line->chan_list, str, size, error_out);
d79a58093   Jeff Dike   [PATCH] uml: cons...
580
  	spin_unlock(&line->count_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
581

b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
582
  	return n;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
583
  }
29d56cfe3   Jeff Dike   [PATCH] uml: hot-...
584
585
586
  int line_id(char **str, int *start_out, int *end_out)
  {
  	char *end;
2f8a2dc2c   Jeff Dike   uml: console tidying
587
  	int n;
29d56cfe3   Jeff Dike   [PATCH] uml: hot-...
588
589
  
  	n = simple_strtoul(*str, &end, 0);
2f8a2dc2c   Jeff Dike   uml: console tidying
590
591
  	if ((*end != '\0') || (end == *str))
  		return -1;
29d56cfe3   Jeff Dike   [PATCH] uml: hot-...
592

2f8a2dc2c   Jeff Dike   uml: console tidying
593
594
595
596
  	*str = end;
  	*start_out = n;
  	*end_out = n;
  	return n;
29d56cfe3   Jeff Dike   [PATCH] uml: hot-...
597
  }
f28169d20   Jeff Dike   [PATCH] uml: retu...
598
  int line_remove(struct line *lines, unsigned int num, int n, char **error_out)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
  {
418e55d49   Jeff Dike   [PATCH] uml: line...
600
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601
  	char config[sizeof("conxxxx=none\0")];
29d56cfe3   Jeff Dike   [PATCH] uml: hot-...
602
  	sprintf(config, "%d=none", n);
f28169d20   Jeff Dike   [PATCH] uml: retu...
603
  	err = line_setup(lines, num, config, error_out);
2f8a2dc2c   Jeff Dike   uml: console tidying
604
  	if (err >= 0)
418e55d49   Jeff Dike   [PATCH] uml: line...
605
606
  		err = 0;
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
607
  }
d5c9ffc6c   Jeff Dike   [PATCH] uml: cons...
608
609
610
  struct tty_driver *register_lines(struct line_driver *line_driver,
  				  const struct tty_operations *ops,
  				  struct line *lines, int nlines)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
611
612
613
614
615
616
617
618
619
  {
  	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;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
620
621
622
623
624
625
626
627
628
  	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)) {
2f8a2dc2c   Jeff Dike   uml: console tidying
629
630
631
  		printk(KERN_ERR "register_lines : can't register %s driver
  ",
  		       line_driver->name);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
632
633
634
  		put_tty_driver(driver);
  		return NULL;
  	}
2f8a2dc2c   Jeff Dike   uml: console tidying
635
636
  	for(i = 0; i < nlines; i++) {
  		if (!lines[i].valid)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
637
638
639
640
641
642
  			tty_unregister_device(driver, i);
  	}
  
  	mconsole_register_dev(&line_driver->mc);
  	return driver;
  }
9010772cd   Jeff Dike   [PATCH] uml: Add ...
643
644
  static DEFINE_SPINLOCK(winch_handler_lock);
  static LIST_HEAD(winch_handlers);
605a69ac8   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: remo...
645

1f80171e8   Jeff Dike   [PATCH] uml: move...
646
  void lines_init(struct line *lines, int nlines, struct chan_opts *opts)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
647
648
  {
  	struct line *line;
f28169d20   Jeff Dike   [PATCH] uml: retu...
649
  	char *error;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
650
  	int i;
2f8a2dc2c   Jeff Dike   uml: console tidying
651
  	for(i = 0; i < nlines; i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
652
653
  		line = &lines[i];
  		INIT_LIST_HEAD(&line->chan_list);
9010772cd   Jeff Dike   [PATCH] uml: Add ...
654

2f8a2dc2c   Jeff Dike   uml: console tidying
655
  		if (line->init_str == NULL)
d50084a29   Jeff Dike   [PATCH] uml: Form...
656
657
658
  			continue;
  
  		line->init_str = kstrdup(line->init_str, GFP_KERNEL);
2f8a2dc2c   Jeff Dike   uml: console tidying
659
660
661
  		if (line->init_str == NULL)
  			printk(KERN_ERR "lines_init - kstrdup returned NULL
  ");
1f80171e8   Jeff Dike   [PATCH] uml: move...
662

2f8a2dc2c   Jeff Dike   uml: console tidying
663
664
665
666
  		if (parse_chan_pair(line->init_str, line, i, opts, &error)) {
  			printk(KERN_ERR "parse_chan_pair failed for "
  			       "device %d : %s
  ", i, error);
1f80171e8   Jeff Dike   [PATCH] uml: move...
667
668
  			line->valid = 0;
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
669
670
671
672
673
674
675
676
677
  	}
  }
  
  struct winch {
  	struct list_head list;
  	int fd;
  	int tty_fd;
  	int pid;
  	struct tty_struct *tty;
42a359e31   Jeff Dike   uml: SIGIO suppor...
678
  	unsigned long stack;
7cf3cf21a   Al Viro   um: fix free_winc...
679
  	struct work_struct work;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680
  };
7cf3cf21a   Al Viro   um: fix free_winc...
681
  static void __free_winch(struct work_struct *work)
42a359e31   Jeff Dike   uml: SIGIO suppor...
682
  {
7cf3cf21a   Al Viro   um: fix free_winc...
683
684
  	struct winch *winch = container_of(work, struct winch, work);
  	free_irq(WINCH_IRQ, winch);
42a359e31   Jeff Dike   uml: SIGIO suppor...
685
686
687
  
  	if (winch->pid != -1)
  		os_kill_process(winch->pid, 1);
42a359e31   Jeff Dike   uml: SIGIO suppor...
688
689
  	if (winch->stack != 0)
  		free_stack(winch->stack, 0);
42a359e31   Jeff Dike   uml: SIGIO suppor...
690
691
  	kfree(winch);
  }
7cf3cf21a   Al Viro   um: fix free_winc...
692
693
694
695
696
697
698
699
700
  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);
  }
7bea96fd2   Al Viro   [PATCH] uml pt_re...
701
  static irqreturn_t winch_interrupt(int irq, void *data)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
703
704
705
  {
  	struct winch *winch = data;
  	struct tty_struct *tty;
  	struct line *line;
7cf3cf21a   Al Viro   um: fix free_winc...
706
  	int fd = winch->fd;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
707
708
  	int err;
  	char c;
7cf3cf21a   Al Viro   um: fix free_winc...
709
710
  	if (fd != -1) {
  		err = generic_read(fd, &c, NULL);
2f8a2dc2c   Jeff Dike   uml: console tidying
711
712
  		if (err < 0) {
  			if (err != -EAGAIN) {
7cf3cf21a   Al Viro   um: fix free_winc...
713
714
715
  				winch->fd = -1;
  				list_del(&winch->list);
  				os_close_file(fd);
2f8a2dc2c   Jeff Dike   uml: console tidying
716
717
718
719
720
721
  				printk(KERN_ERR "winch_interrupt : "
  				       "read failed, errno = %d
  ", -err);
  				printk(KERN_ERR "fd %d is losing SIGWINCH "
  				       "support
  ", winch->tty_fd);
7cf3cf21a   Al Viro   um: fix free_winc...
722
723
  				INIT_WORK(&winch->work, __free_winch);
  				schedule_work(&winch->work);
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
724
  				return IRQ_HANDLED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
725
726
727
728
  			}
  			goto out;
  		}
  	}
42a359e31   Jeff Dike   uml: SIGIO suppor...
729
  	tty = winch->tty;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
731
  	if (tty != NULL) {
  		line = tty->driver_data;
438ee6798   Jeff Dike   uml: DEBUG_SHIRQ ...
732
733
734
735
736
  		if (line != NULL) {
  			chan_window_size(&line->chan_list, &tty->winsize.ws_row,
  					 &tty->winsize.ws_col);
  			kill_pgrp(tty->pgrp, SIGWINCH, 1);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
737
738
  	}
   out:
2f8a2dc2c   Jeff Dike   uml: console tidying
739
  	if (winch->fd != -1)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
  		reactivate_fd(winch->fd, WINCH_IRQ);
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
741
  	return IRQ_HANDLED;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
742
  }
42a359e31   Jeff Dike   uml: SIGIO suppor...
743
744
  void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty,
  			unsigned long stack)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
745
746
  {
  	struct winch *winch;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
747
748
  	winch = kmalloc(sizeof(*winch), GFP_KERNEL);
  	if (winch == NULL) {
2f8a2dc2c   Jeff Dike   uml: console tidying
749
750
  		printk(KERN_ERR "register_winch_irq - kmalloc failed
  ");
42a359e31   Jeff Dike   uml: SIGIO suppor...
751
  		goto cleanup;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
  	}
605a69ac8   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: remo...
753

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
754
755
756
757
  	*winch = ((struct winch) { .list  	= LIST_HEAD_INIT(winch->list),
  				   .fd  	= fd,
  				   .tty_fd 	= tty_fd,
  				   .pid  	= pid,
42a359e31   Jeff Dike   uml: SIGIO suppor...
758
759
760
761
762
763
  				   .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) {
2f8a2dc2c   Jeff Dike   uml: console tidying
764
765
766
  		printk(KERN_ERR "register_winch_irq - failed to register "
  		       "IRQ
  ");
42a359e31   Jeff Dike   uml: SIGIO suppor...
767
768
  		goto out_free;
  	}
605a69ac8   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: remo...
769
770
  
  	spin_lock(&winch_handler_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
771
  	list_add(&winch->list, &winch_handlers);
605a69ac8   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: remo...
772
  	spin_unlock(&winch_handler_lock);
42a359e31   Jeff Dike   uml: SIGIO suppor...
773
  	return;
e464bf2be   Jeff Dike   [PATCH] uml: SIGW...
774

42a359e31   Jeff Dike   uml: SIGIO suppor...
775
   out_free:
e464bf2be   Jeff Dike   [PATCH] uml: SIGW...
776
  	kfree(winch);
42a359e31   Jeff Dike   uml: SIGIO suppor...
777
778
779
780
781
   cleanup:
  	os_kill_process(pid, 1);
  	os_close_file(fd);
  	if (stack != 0)
  		free_stack(stack, 0);
e464bf2be   Jeff Dike   [PATCH] uml: SIGW...
782
  }
cd2ee4a30   Jeff Dike   [PATCH] uml: Fix ...
783
784
  static void unregister_winch(struct tty_struct *tty)
  {
48a0b7404   Will Newton   arch/um/drivers/l...
785
  	struct list_head *ele, *next;
e464bf2be   Jeff Dike   [PATCH] uml: SIGW...
786
  	struct winch *winch;
cd2ee4a30   Jeff Dike   [PATCH] uml: Fix ...
787

605a69ac8   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: remo...
788
  	spin_lock(&winch_handler_lock);
e464bf2be   Jeff Dike   [PATCH] uml: SIGW...
789

48a0b7404   Will Newton   arch/um/drivers/l...
790
  	list_for_each_safe(ele, next, &winch_handlers) {
cd2ee4a30   Jeff Dike   [PATCH] uml: Fix ...
791
  		winch = list_entry(ele, struct winch, list);
2f8a2dc2c   Jeff Dike   uml: console tidying
792
  		if (winch->tty == tty) {
7cf3cf21a   Al Viro   um: fix free_winc...
793
  			free_winch(winch);
e464bf2be   Jeff Dike   [PATCH] uml: SIGW...
794
  			break;
2f8a2dc2c   Jeff Dike   uml: console tidying
795
796
  		}
  	}
605a69ac8   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: remo...
797
  	spin_unlock(&winch_handler_lock);
cd2ee4a30   Jeff Dike   [PATCH] uml: Fix ...
798
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
799
800
  static void winch_cleanup(void)
  {
e464bf2be   Jeff Dike   [PATCH] uml: SIGW...
801
  	struct list_head *ele, *next;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
  	struct winch *winch;
e464bf2be   Jeff Dike   [PATCH] uml: SIGW...
803
  	spin_lock(&winch_handler_lock);
2f8a2dc2c   Jeff Dike   uml: console tidying
804
  	list_for_each_safe(ele, next, &winch_handlers) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
805
  		winch = list_entry(ele, struct winch, list);
7cf3cf21a   Al Viro   um: fix free_winc...
806
  		free_winch(winch);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
  	}
e464bf2be   Jeff Dike   [PATCH] uml: SIGW...
808
809
  
  	spin_unlock(&winch_handler_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
810
811
812
813
814
815
816
  }
  __uml_exitcall(winch_cleanup);
  
  char *add_xterm_umid(char *base)
  {
  	char *umid, *title;
  	int len;
7eebe8a9c   Jeff Dike   [PATCH] uml: umid...
817
  	umid = get_umid();
2f8a2dc2c   Jeff Dike   uml: console tidying
818
  	if (*umid == '\0')
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
819
  		return base;
165dc5911   Jeff Dike   [PATCH] uml: Simp...
820

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
821
822
  	len = strlen(base) + strlen(" ()") + strlen(umid) + 1;
  	title = kmalloc(len, GFP_KERNEL);
2f8a2dc2c   Jeff Dike   uml: console tidying
823
824
825
  	if (title == NULL) {
  		printk(KERN_ERR "Failed to allocate buffer for xterm title
  ");
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
826
  		return base;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
827
828
829
  	}
  
  	snprintf(title, len, "%s (%s)", base, umid);
b97b77cca   Paolo 'Blaisorblade' Giarrusso   [PATCH] uml: redo...
830
  	return title;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
831
  }