Blame view
arch/um/drivers/line.c
19.1 KB
165dc5911 [PATCH] uml: Simp... |
1 |
/* |
2f8a2dc2c uml: console tidying |
2 |
* Copyright (C) 2001 - 2007 Jeff Dike (jdike@{addtoit,linux.intel}.com) |
1da177e4c Linux-2.6.12-rc2 |
3 4 |
* Licensed under the GPL */ |
2f8a2dc2c uml: console tidying |
5 |
#include "linux/irqreturn.h" |
1da177e4c Linux-2.6.12-rc2 |
6 |
#include "linux/kd.h" |
d43c36dc6 headers: remove s... |
7 |
#include "linux/sched.h" |
7f3c1fa4c uml: Fix build br... |
8 |
#include "linux/slab.h" |
510c72a3c um: take chan_*.h... |
9 |
#include "chan.h" |
2f8a2dc2c uml: console tidying |
10 |
#include "irq_kern.h" |
1da177e4c Linux-2.6.12-rc2 |
11 |
#include "irq_user.h" |
edea13858 uml: tidy kern_ut... |
12 |
#include "kern_util.h" |
1da177e4c Linux-2.6.12-rc2 |
13 |
#include "os.h" |
1da177e4c Linux-2.6.12-rc2 |
14 15 |
#define LINE_BUFSIZE 4096 |
7bea96fd2 [PATCH] uml pt_re... |
16 |
static irqreturn_t line_interrupt(int irq, void *data) |
1da177e4c Linux-2.6.12-rc2 |
17 |
{ |
165dc5911 [PATCH] uml: Simp... |
18 19 |
struct chan *chan = data; struct line *line = chan->line; |
1da177e4c Linux-2.6.12-rc2 |
20 21 |
if (line) |
03315b591 uml: line.c: avoi... |
22 |
chan_interrupt(&line->chan_list, &line->task, line->tty, irq); |
1da177e4c Linux-2.6.12-rc2 |
23 24 |
return IRQ_HANDLED; } |
a2ce77409 [PATCH] uml: work... |
25 |
static void line_timer_cb(struct work_struct *work) |
1da177e4c Linux-2.6.12-rc2 |
26 |
{ |
a2ce77409 [PATCH] uml: work... |
27 |
struct line *line = container_of(work, struct line, task.work); |
1da177e4c Linux-2.6.12-rc2 |
28 |
|
2f8a2dc2c uml: console tidying |
29 |
if (!line->throttled) |
e4dcee809 [PATCH] uml: Add ... |
30 31 |
chan_interrupt(&line->chan_list, &line->task, line->tty, line->driver->read_irq); |
1da177e4c Linux-2.6.12-rc2 |
32 |
} |
2f8a2dc2c uml: console tidying |
33 34 |
/* * Returns the free space inside the ring buffer of this line. |
b97b77cca [PATCH] uml: redo... |
35 |
* |
b60745b96 spelling fixes: a... |
36 |
* Should be called while holding line->lock (this does not modify data). |
b97b77cca [PATCH] uml: redo... |
37 38 |
*/ static int write_room(struct line *line) |
1da177e4c Linux-2.6.12-rc2 |
39 40 |
{ int n; |
b97b77cca [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 Linux-2.6.12-rc2 |
46 |
|
1da177e4c Linux-2.6.12-rc2 |
47 |
if (n <= 0) |
acb2cf34c uml: console driv... |
48 |
n += LINE_BUFSIZE; /* The other case */ |
b97b77cca [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 [PATCH] uml: redo... |
57 58 59 |
spin_lock_irqsave(&line->lock, flags); room = write_room(line); spin_unlock_irqrestore(&line->lock, flags); |
b97b77cca [PATCH] uml: redo... |
60 |
return room; |
1da177e4c Linux-2.6.12-rc2 |
61 |
} |
b97b77cca [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 uml: console driv... |
69 |
/* write_room subtracts 1 for the needed NULL, so we readd it.*/ |
b97b77cca [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 Linux-2.6.12-rc2 |
85 86 87 |
static int buffer_data(struct line *line, const char *buf, int len) { int end, room; |
2f8a2dc2c uml: console tidying |
88 |
if (line->buffer == NULL) { |
1da177e4c Linux-2.6.12-rc2 |
89 90 |
line->buffer = kmalloc(LINE_BUFSIZE, GFP_ATOMIC); if (line->buffer == NULL) { |
2f8a2dc2c uml: console tidying |
91 92 93 94 |
printk(KERN_ERR "buffer_data - atomic allocation " "failed "); return 0; |
1da177e4c 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 [PATCH] uml: redo... |
104 |
|
2f8a2dc2c uml: console tidying |
105 |
if (len < end) { |
1da177e4c Linux-2.6.12-rc2 |
106 107 |
memcpy(line->tail, buf, len); line->tail += len; |
d50084a29 [PATCH] uml: Form... |
108 109 |
} else { |
b97b77cca [PATCH] uml: redo... |
110 |
/* The circular buffer is wrapping */ |
1da177e4c 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 [PATCH] uml: redo... |
116 |
return len; |
1da177e4c Linux-2.6.12-rc2 |
117 |
} |
b97b77cca [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 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 [PATCH] uml: redo... |
132 |
return 1; |
1da177e4c Linux-2.6.12-rc2 |
133 134 |
if (line->tail < line->head) { |
b97b77cca [PATCH] uml: redo... |
135 |
/* line->buffer + LINE_BUFSIZE is the end of the buffer! */ |
1da177e4c Linux-2.6.12-rc2 |
136 |
count = line->buffer + LINE_BUFSIZE - line->head; |
b97b77cca [PATCH] uml: redo... |
137 |
|
1da177e4c 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 [PATCH] uml: redo... |
141 142 |
return n; if (n == count) { |
2f8a2dc2c 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 Linux-2.6.12-rc2 |
147 |
line->head = line->buffer; |
b97b77cca [PATCH] uml: redo... |
148 |
} else { |
1da177e4c Linux-2.6.12-rc2 |
149 |
line->head += n; |
b97b77cca [PATCH] uml: redo... |
150 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
151 152 153 154 |
} } count = line->tail - line->head; |
d50084a29 [PATCH] uml: Form... |
155 |
n = write_chan(&line->chan_list, line->head, count, |
1da177e4c Linux-2.6.12-rc2 |
156 |
line->driver->write_irq); |
b97b77cca [PATCH] uml: redo... |
157 |
|
2f8a2dc2c uml: console tidying |
158 |
if (n < 0) |
b97b77cca [PATCH] uml: redo... |
159 |
return n; |
1da177e4c Linux-2.6.12-rc2 |
160 161 |
line->head += n; |
b97b77cca [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 [PATCH] uml: redo... |
169 |
|
b97b77cca [PATCH] uml: redo... |
170 |
spin_lock_irqsave(&line->lock, flags); |
f1c93e494 um: remove dead code |
171 |
flush_buffer(line); |
b97b77cca [PATCH] uml: redo... |
172 |
spin_unlock_irqrestore(&line->lock, flags); |
b97b77cca [PATCH] uml: redo... |
173 |
} |
2f8a2dc2c 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 [PATCH] uml: redo... |
178 179 180 181 |
void line_flush_chars(struct tty_struct *tty) { line_flush_buffer(tty); } |
3168cb98b uml: fix inconsis... |
182 |
int line_put_char(struct tty_struct *tty, unsigned char ch) |
b97b77cca [PATCH] uml: redo... |
183 |
{ |
3168cb98b uml: fix inconsis... |
184 |
return line_write(tty, &ch, sizeof(ch)); |
1da177e4c 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 uml: fix console ... |
191 |
int n, ret = 0; |
1da177e4c Linux-2.6.12-rc2 |
192 |
|
b97b77cca [PATCH] uml: redo... |
193 |
spin_lock_irqsave(&line->lock, flags); |
c59dbcadd uml: fix console ... |
194 |
if (line->head != line->tail) |
1da177e4c Linux-2.6.12-rc2 |
195 |
ret = buffer_data(line, buf, len); |
c59dbcadd uml: fix console ... |
196 |
else { |
d50084a29 [PATCH] uml: Form... |
197 |
n = write_chan(&line->chan_list, buf, len, |
1da177e4c Linux-2.6.12-rc2 |
198 |
line->driver->write_irq); |
b97b77cca [PATCH] uml: redo... |
199 |
if (n < 0) { |
1da177e4c Linux-2.6.12-rc2 |
200 201 202 203 204 205 |
ret = n; goto out_up; } len -= n; ret += n; |
b97b77cca [PATCH] uml: redo... |
206 |
if (len > 0) |
1da177e4c Linux-2.6.12-rc2 |
207 208 |
ret += buffer_data(line, buf + n, len); } |
b97b77cca [PATCH] uml: redo... |
209 210 211 |
out_up: spin_unlock_irqrestore(&line->lock, flags); return ret; |
1da177e4c Linux-2.6.12-rc2 |
212 |
} |
606d099cd [PATCH] tty: swit... |
213 |
void line_set_termios(struct tty_struct *tty, struct ktermios * old) |
1da177e4c Linux-2.6.12-rc2 |
214 215 216 |
{ /* nothing */ } |
5e7672ec3 [PATCH] uml: cons... |
217 |
static const struct { |
1da177e4c 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 uml: console tidying |
224 225 226 227 |
{ TCSETS, NULL, "TCSETS" }, { TCSETSW, NULL, "TCSETSW" }, { TCFLSH, NULL, "TCFLSH" }, { TCSBRK, NULL, "TCSBRK" }, |
1da177e4c Linux-2.6.12-rc2 |
228 229 |
/* general tty stuff */ |
2f8a2dc2c 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 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 um: remove file p... |
242 243 |
int line_ioctl(struct tty_struct *tty, unsigned int cmd, unsigned long arg) |
1da177e4c 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 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 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 uml: console tidying |
292 |
if (i == ARRAY_SIZE(tty_ioctls)) { |
1da177e4c Linux-2.6.12-rc2 |
293 294 |
printk(KERN_ERR "%s: %s: unknown ioctl: 0x%x ", |
3595726ac uml: replace rema... |
295 |
__func__, tty->name, cmd); |
1da177e4c Linux-2.6.12-rc2 |
296 297 298 299 |
} ret = -ENOIOCTLCMD; break; } |
b97b77cca [PATCH] uml: redo... |
300 |
return ret; |
1da177e4c Linux-2.6.12-rc2 |
301 |
} |
e4dcee809 [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 uml: console tidying |
317 318 |
/* * Maybe there is enough stuff pending that calling the interrupt |
e4dcee809 [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 uml: console tidying |
322 |
if (!line->throttled) |
e4dcee809 [PATCH] uml: Add ... |
323 324 |
reactivate_chan(&line->chan_list, line->driver->read_irq); } |
7bea96fd2 [PATCH] uml pt_re... |
325 |
static irqreturn_t line_write_interrupt(int irq, void *data) |
1da177e4c Linux-2.6.12-rc2 |
326 |
{ |
165dc5911 [PATCH] uml: Simp... |
327 328 329 |
struct chan *chan = data; struct line *line = chan->line; struct tty_struct *tty = line->tty; |
1da177e4c Linux-2.6.12-rc2 |
330 |
int err; |
2f8a2dc2c uml: console tidying |
331 332 333 334 |
/* * Interrupts are disabled here because we registered the interrupt with * IRQF_DISABLED (see line_setup_irq). */ |
b97b77cca [PATCH] uml: redo... |
335 |
|
ec0ac8ad3 [PATCH] um: fix c... |
336 |
spin_lock(&line->lock); |
1da177e4c Linux-2.6.12-rc2 |
337 |
err = flush_buffer(line); |
b97b77cca [PATCH] uml: redo... |
338 339 |
if (err == 0) { return IRQ_NONE; |
2f8a2dc2c uml: console tidying |
340 |
} else if (err < 0) { |
1da177e4c Linux-2.6.12-rc2 |
341 342 343 |
line->head = line->buffer; line->tail = line->buffer; } |
ec0ac8ad3 [PATCH] um: fix c... |
344 |
spin_unlock(&line->lock); |
1da177e4c Linux-2.6.12-rc2 |
345 |
|
2f8a2dc2c uml: console tidying |
346 |
if (tty == NULL) |
b97b77cca [PATCH] uml: redo... |
347 |
return IRQ_NONE; |
1da177e4c Linux-2.6.12-rc2 |
348 |
|
06ac66790 uml: fix tty-rela... |
349 |
tty_wakeup(tty); |
b97b77cca [PATCH] uml: redo... |
350 |
return IRQ_HANDLED; |
1da177e4c Linux-2.6.12-rc2 |
351 |
} |
165dc5911 [PATCH] uml: Simp... |
352 |
int line_setup_irq(int fd, int input, int output, struct line *line, void *data) |
1da177e4c Linux-2.6.12-rc2 |
353 |
{ |
5e7672ec3 [PATCH] uml: cons... |
354 |
const struct line_driver *driver = line->driver; |
bd6aa6502 [PATCH] irq-flags... |
355 |
int err = 0, flags = IRQF_DISABLED | IRQF_SHARED | IRQF_SAMPLE_RANDOM; |
1da177e4c Linux-2.6.12-rc2 |
356 |
|
b97b77cca [PATCH] uml: redo... |
357 358 |
if (input) err = um_request_irq(driver->read_irq, fd, IRQ_READ, |
d50084a29 [PATCH] uml: Form... |
359 |
line_interrupt, flags, |
165dc5911 [PATCH] uml: Simp... |
360 |
driver->read_irq_name, data); |
b97b77cca [PATCH] uml: redo... |
361 362 363 364 |
if (err) return err; if (output) err = um_request_irq(driver->write_irq, fd, IRQ_WRITE, |
d50084a29 [PATCH] uml: Form... |
365 |
line_write_interrupt, flags, |
165dc5911 [PATCH] uml: Simp... |
366 |
driver->write_irq_name, data); |
1da177e4c Linux-2.6.12-rc2 |
367 |
line->have_irq = 1; |
b97b77cca [PATCH] uml: redo... |
368 |
return err; |
1da177e4c Linux-2.6.12-rc2 |
369 |
} |
2f8a2dc2c uml: console tidying |
370 371 |
/* * Normally, a driver like this can rely mostly on the tty layer |
d79a58093 [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 [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 [PATCH] uml: cons... |
381 |
* |
f71f94845 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 [PATCH] uml: fix ... |
384 |
* first open or last close. Otherwise, open and close just return. |
d79a58093 [PATCH] uml: cons... |
385 |
*/ |
1f80171e8 [PATCH] uml: move... |
386 |
int line_open(struct line *lines, struct tty_struct *tty) |
1da177e4c Linux-2.6.12-rc2 |
387 |
{ |
d79a58093 [PATCH] uml: cons... |
388 |
struct line *line = &lines[tty->index]; |
165dc5911 [PATCH] uml: Simp... |
389 |
int err = -ENODEV; |
1da177e4c Linux-2.6.12-rc2 |
390 |
|
d79a58093 [PATCH] uml: cons... |
391 |
spin_lock(&line->count_lock); |
2f8a2dc2c uml: console tidying |
392 |
if (!line->valid) |
d79a58093 [PATCH] uml: cons... |
393 |
goto out_unlock; |
1da177e4c Linux-2.6.12-rc2 |
394 |
|
d79a58093 [PATCH] uml: cons... |
395 |
err = 0; |
f71f94845 um: fix oopsable ... |
396 |
if (line->count++) |
d79a58093 [PATCH] uml: cons... |
397 |
goto out_unlock; |
f71f94845 um: fix oopsable ... |
398 |
BUG_ON(tty->driver_data); |
165dc5911 [PATCH] uml: Simp... |
399 400 |
tty->driver_data = line; line->tty = tty; |
165dc5911 [PATCH] uml: Simp... |
401 |
|
f71f94845 um: fix oopsable ... |
402 |
spin_unlock(&line->count_lock); |
d14ad81f8 uml: handle error... |
403 |
err = enable_chan(line); |
f71f94845 um: fix oopsable ... |
404 |
if (err) /* line_close() will be called by our caller */ |
d14ad81f8 uml: handle error... |
405 |
return err; |
d79a58093 [PATCH] uml: cons... |
406 |
INIT_DELAYED_WORK(&line->task, line_timer_cb); |
165dc5911 [PATCH] uml: Simp... |
407 |
|
2f8a2dc2c uml: console tidying |
408 |
if (!line->sigio) { |
d79a58093 [PATCH] uml: cons... |
409 410 |
chan_enable_winch(&line->chan_list, tty); line->sigio = 1; |
1da177e4c Linux-2.6.12-rc2 |
411 |
} |
1da177e4c Linux-2.6.12-rc2 |
412 |
|
d79a58093 [PATCH] uml: cons... |
413 414 |
chan_window_size(&line->chan_list, &tty->winsize.ws_row, &tty->winsize.ws_col); |
f71f94845 um: fix oopsable ... |
415 |
return 0; |
d79a58093 [PATCH] uml: cons... |
416 417 418 |
out_unlock: spin_unlock(&line->count_lock); |
b97b77cca [PATCH] uml: redo... |
419 |
return err; |
1da177e4c Linux-2.6.12-rc2 |
420 |
} |
cd2ee4a30 [PATCH] uml: Fix ... |
421 |
static void unregister_winch(struct tty_struct *tty); |
1da177e4c 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 uml: console tidying |
425 426 |
/* * If line_open fails (and tty->driver_data is never set), |
d79a58093 [PATCH] uml: cons... |
427 428 |
* tty_open will call line_close. So just return in this case. */ |
2f8a2dc2c uml: console tidying |
429 |
if (line == NULL) |
d79a58093 [PATCH] uml: cons... |
430 |
return; |
b97b77cca [PATCH] uml: redo... |
431 432 433 |
/* We ignore the error anyway! */ flush_buffer(line); |
d79a58093 [PATCH] uml: cons... |
434 |
spin_lock(&line->count_lock); |
f71f94845 um: fix oopsable ... |
435 |
BUG_ON(!line->valid); |
cd2ee4a30 [PATCH] uml: Fix ... |
436 |
|
f71f94845 um: fix oopsable ... |
437 |
if (--line->count) |
d79a58093 [PATCH] uml: cons... |
438 |
goto out_unlock; |
d79a58093 [PATCH] uml: cons... |
439 440 |
line->tty = NULL; tty->driver_data = NULL; |
f71f94845 um: fix oopsable ... |
441 |
spin_unlock(&line->count_lock); |
2f8a2dc2c uml: console tidying |
442 |
if (line->sigio) { |
d79a58093 [PATCH] uml: cons... |
443 444 |
unregister_winch(tty); line->sigio = 0; |
2f8a2dc2c uml: console tidying |
445 |
} |
cd2ee4a30 [PATCH] uml: Fix ... |
446 |
|
d79a58093 [PATCH] uml: cons... |
447 448 449 450 |
return; out_unlock: spin_unlock(&line->count_lock); |
1da177e4c 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 [PATCH] uml: Simp... |
458 |
close_chan(&lines[i].chan_list, 0); |
1da177e4c Linux-2.6.12-rc2 |
459 |
} |
f28169d20 [PATCH] uml: retu... |
460 461 |
static int setup_one_line(struct line *lines, int n, char *init, int init_prio, char **error_out) |
d79a58093 [PATCH] uml: cons... |
462 463 |
{ struct line *line = &lines[n]; |
f28169d20 [PATCH] uml: retu... |
464 |
int err = -EINVAL; |
d79a58093 [PATCH] uml: cons... |
465 466 |
spin_lock(&line->count_lock); |
f71f94845 um: fix oopsable ... |
467 |
if (line->count) { |
f28169d20 [PATCH] uml: retu... |
468 |
*error_out = "Device is already open"; |
d79a58093 [PATCH] uml: cons... |
469 470 |
goto out; } |
2f8a2dc2c uml: console tidying |
471 |
if (line->init_pri <= init_prio) { |
d79a58093 [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 [PATCH] uml: retu... |
480 |
err = 0; |
d79a58093 [PATCH] uml: cons... |
481 482 |
out: spin_unlock(&line->count_lock); |
f28169d20 [PATCH] uml: retu... |
483 |
return err; |
d79a58093 [PATCH] uml: cons... |
484 |
} |
2f8a2dc2c uml: console tidying |
485 486 |
/* * Common setup code for both startup command line and mconsole initialization. |
4b3f686d4 Attack of "the th... |
487 |
* @lines contains the array (of size @num) to modify; |
b97b77cca [PATCH] uml: redo... |
488 |
* @init is the setup string; |
f28169d20 [PATCH] uml: retu... |
489 |
* @error_out is an error string in the case of failure; |
d571cd18f [PATCH] uml: Move... |
490 |
*/ |
b97b77cca [PATCH] uml: redo... |
491 |
|
f28169d20 [PATCH] uml: retu... |
492 493 |
int line_setup(struct line *lines, unsigned int num, char *init, char **error_out) |
1da177e4c Linux-2.6.12-rc2 |
494 |
{ |
f28169d20 [PATCH] uml: retu... |
495 |
int i, n, err; |
1da177e4c Linux-2.6.12-rc2 |
496 |
char *end; |
2f8a2dc2c 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 [PATCH] uml: redo... |
502 |
n = -1; |
d50084a29 [PATCH] uml: Form... |
503 504 |
} else { |
1da177e4c Linux-2.6.12-rc2 |
505 |
n = simple_strtoul(init, &end, 0); |
2f8a2dc2c uml: console tidying |
506 |
if (*end != '=') { |
f28169d20 [PATCH] uml: retu... |
507 508 |
*error_out = "Couldn't parse device number"; return -EINVAL; |
1da177e4c Linux-2.6.12-rc2 |
509 510 511 512 |
} init = end; } init++; |
b97b77cca [PATCH] uml: redo... |
513 514 |
if (n >= (signed int) num) { |
f28169d20 [PATCH] uml: retu... |
515 516 517 |
*error_out = "Device number out of range"; return -EINVAL; } |
2f8a2dc2c uml: console tidying |
518 |
else if (n >= 0) { |
f28169d20 [PATCH] uml: retu... |
519 |
err = setup_one_line(lines, n, init, INIT_ONE, error_out); |
2f8a2dc2c uml: console tidying |
520 |
if (err) |
f28169d20 [PATCH] uml: retu... |
521 |
return err; |
d50084a29 [PATCH] uml: Form... |
522 |
} |
d50084a29 [PATCH] uml: Form... |
523 |
else { |
2f8a2dc2c uml: console tidying |
524 |
for(i = 0; i < num; i++) { |
f28169d20 [PATCH] uml: retu... |
525 526 |
err = setup_one_line(lines, i, init, INIT_ALL, error_out); |
2f8a2dc2c uml: console tidying |
527 |
if (err) |
f28169d20 [PATCH] uml: retu... |
528 529 |
return err; } |
1da177e4c Linux-2.6.12-rc2 |
530 |
} |
418e55d49 [PATCH] uml: line... |
531 |
return n == -1 ? num : n; |
1da177e4c Linux-2.6.12-rc2 |
532 |
} |
1f80171e8 [PATCH] uml: move... |
533 |
int line_config(struct line *lines, unsigned int num, char *str, |
f28169d20 [PATCH] uml: retu... |
534 |
const struct chan_opts *opts, char **error_out) |
1da177e4c Linux-2.6.12-rc2 |
535 |
{ |
1f80171e8 [PATCH] uml: move... |
536 |
struct line *line; |
970d6e3a3 [PATCH] uml: use ... |
537 |
char *new; |
418e55d49 [PATCH] uml: line... |
538 |
int n; |
1da177e4c Linux-2.6.12-rc2 |
539 |
|
2f8a2dc2c uml: console tidying |
540 |
if (*str == '=') { |
f28169d20 [PATCH] uml: retu... |
541 542 |
*error_out = "Can't configure all devices from mconsole"; return -EINVAL; |
d571cd18f [PATCH] uml: Move... |
543 |
} |
970d6e3a3 [PATCH] uml: use ... |
544 |
new = kstrdup(str, GFP_KERNEL); |
2f8a2dc2c uml: console tidying |
545 |
if (new == NULL) { |
f28169d20 [PATCH] uml: retu... |
546 547 |
*error_out = "Failed to allocate memory"; return -ENOMEM; |
1da177e4c Linux-2.6.12-rc2 |
548 |
} |
f28169d20 [PATCH] uml: retu... |
549 |
n = line_setup(lines, num, new, error_out); |
2f8a2dc2c uml: console tidying |
550 |
if (n < 0) |
f28169d20 [PATCH] uml: retu... |
551 |
return n; |
1f80171e8 [PATCH] uml: move... |
552 553 |
line = &lines[n]; |
f28169d20 [PATCH] uml: retu... |
554 |
return parse_chan_pair(line->init_str, line, n, opts, error_out); |
1da177e4c Linux-2.6.12-rc2 |
555 |
} |
b97b77cca [PATCH] uml: redo... |
556 |
int line_get_config(char *name, struct line *lines, unsigned int num, char *str, |
1da177e4c 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 uml: console tidying |
564 |
if ((*end != '\0') || (end == name)) { |
1da177e4c Linux-2.6.12-rc2 |
565 |
*error_out = "line_get_config failed to parse device number"; |
b97b77cca [PATCH] uml: redo... |
566 |
return 0; |
1da177e4c Linux-2.6.12-rc2 |
567 |
} |
2f8a2dc2c uml: console tidying |
568 |
if ((dev < 0) || (dev >= num)) { |
b97b77cca [PATCH] uml: redo... |
569 570 |
*error_out = "device number out of range"; return 0; |
1da177e4c Linux-2.6.12-rc2 |
571 572 573 |
} line = &lines[dev]; |
d79a58093 [PATCH] uml: cons... |
574 |
spin_lock(&line->count_lock); |
2f8a2dc2c uml: console tidying |
575 |
if (!line->valid) |
1da177e4c Linux-2.6.12-rc2 |
576 |
CONFIG_CHUNK(str, size, n, "none", 1); |
2f8a2dc2c uml: console tidying |
577 |
else if (line->tty == NULL) |
1da177e4c 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 [PATCH] uml: cons... |
580 |
spin_unlock(&line->count_lock); |
1da177e4c Linux-2.6.12-rc2 |
581 |
|
b97b77cca [PATCH] uml: redo... |
582 |
return n; |
1da177e4c Linux-2.6.12-rc2 |
583 |
} |
29d56cfe3 [PATCH] uml: hot-... |
584 585 586 |
int line_id(char **str, int *start_out, int *end_out) { char *end; |
2f8a2dc2c uml: console tidying |
587 |
int n; |
29d56cfe3 [PATCH] uml: hot-... |
588 589 |
n = simple_strtoul(*str, &end, 0); |
2f8a2dc2c uml: console tidying |
590 591 |
if ((*end != '\0') || (end == *str)) return -1; |
29d56cfe3 [PATCH] uml: hot-... |
592 |
|
2f8a2dc2c uml: console tidying |
593 594 595 596 |
*str = end; *start_out = n; *end_out = n; return n; |
29d56cfe3 [PATCH] uml: hot-... |
597 |
} |
f28169d20 [PATCH] uml: retu... |
598 |
int line_remove(struct line *lines, unsigned int num, int n, char **error_out) |
1da177e4c Linux-2.6.12-rc2 |
599 |
{ |
418e55d49 [PATCH] uml: line... |
600 |
int err; |
1da177e4c Linux-2.6.12-rc2 |
601 |
char config[sizeof("conxxxx=none\0")]; |
29d56cfe3 [PATCH] uml: hot-... |
602 |
sprintf(config, "%d=none", n); |
f28169d20 [PATCH] uml: retu... |
603 |
err = line_setup(lines, num, config, error_out); |
2f8a2dc2c uml: console tidying |
604 |
if (err >= 0) |
418e55d49 [PATCH] uml: line... |
605 606 |
err = 0; return err; |
1da177e4c Linux-2.6.12-rc2 |
607 |
} |
d5c9ffc6c [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 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 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 uml: console tidying |
629 630 631 |
printk(KERN_ERR "register_lines : can't register %s driver ", line_driver->name); |
1da177e4c Linux-2.6.12-rc2 |
632 633 634 |
put_tty_driver(driver); return NULL; } |
2f8a2dc2c uml: console tidying |
635 636 |
for(i = 0; i < nlines; i++) { if (!lines[i].valid) |
1da177e4c 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 [PATCH] uml: Add ... |
643 644 |
static DEFINE_SPINLOCK(winch_handler_lock); static LIST_HEAD(winch_handlers); |
605a69ac8 [PATCH] uml: remo... |
645 |
|
1f80171e8 [PATCH] uml: move... |
646 |
void lines_init(struct line *lines, int nlines, struct chan_opts *opts) |
1da177e4c Linux-2.6.12-rc2 |
647 648 |
{ struct line *line; |
f28169d20 [PATCH] uml: retu... |
649 |
char *error; |
1da177e4c Linux-2.6.12-rc2 |
650 |
int i; |
2f8a2dc2c uml: console tidying |
651 |
for(i = 0; i < nlines; i++) { |
1da177e4c Linux-2.6.12-rc2 |
652 653 |
line = &lines[i]; INIT_LIST_HEAD(&line->chan_list); |
9010772cd [PATCH] uml: Add ... |
654 |
|
2f8a2dc2c uml: console tidying |
655 |
if (line->init_str == NULL) |
d50084a29 [PATCH] uml: Form... |
656 657 658 |
continue; line->init_str = kstrdup(line->init_str, GFP_KERNEL); |
2f8a2dc2c uml: console tidying |
659 660 661 |
if (line->init_str == NULL) printk(KERN_ERR "lines_init - kstrdup returned NULL "); |
1f80171e8 [PATCH] uml: move... |
662 |
|
2f8a2dc2c 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 [PATCH] uml: move... |
667 668 |
line->valid = 0; } |
1da177e4c 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 uml: SIGIO suppor... |
678 |
unsigned long stack; |
7cf3cf21a um: fix free_winc... |
679 |
struct work_struct work; |
1da177e4c Linux-2.6.12-rc2 |
680 |
}; |
7cf3cf21a um: fix free_winc... |
681 |
static void __free_winch(struct work_struct *work) |
42a359e31 uml: SIGIO suppor... |
682 |
{ |
7cf3cf21a um: fix free_winc... |
683 684 |
struct winch *winch = container_of(work, struct winch, work); free_irq(WINCH_IRQ, winch); |
42a359e31 uml: SIGIO suppor... |
685 686 687 |
if (winch->pid != -1) os_kill_process(winch->pid, 1); |
42a359e31 uml: SIGIO suppor... |
688 689 |
if (winch->stack != 0) free_stack(winch->stack, 0); |
42a359e31 uml: SIGIO suppor... |
690 691 |
kfree(winch); } |
7cf3cf21a 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 [PATCH] uml pt_re... |
701 |
static irqreturn_t winch_interrupt(int irq, void *data) |
1da177e4c Linux-2.6.12-rc2 |
702 703 704 705 |
{ struct winch *winch = data; struct tty_struct *tty; struct line *line; |
7cf3cf21a um: fix free_winc... |
706 |
int fd = winch->fd; |
1da177e4c Linux-2.6.12-rc2 |
707 708 |
int err; char c; |
7cf3cf21a um: fix free_winc... |
709 710 |
if (fd != -1) { err = generic_read(fd, &c, NULL); |
2f8a2dc2c uml: console tidying |
711 712 |
if (err < 0) { if (err != -EAGAIN) { |
7cf3cf21a um: fix free_winc... |
713 714 715 |
winch->fd = -1; list_del(&winch->list); os_close_file(fd); |
2f8a2dc2c 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 um: fix free_winc... |
722 723 |
INIT_WORK(&winch->work, __free_winch); schedule_work(&winch->work); |
b97b77cca [PATCH] uml: redo... |
724 |
return IRQ_HANDLED; |
1da177e4c Linux-2.6.12-rc2 |
725 726 727 728 |
} goto out; } } |
42a359e31 uml: SIGIO suppor... |
729 |
tty = winch->tty; |
1da177e4c Linux-2.6.12-rc2 |
730 731 |
if (tty != NULL) { line = tty->driver_data; |
438ee6798 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 Linux-2.6.12-rc2 |
737 738 |
} out: |
2f8a2dc2c uml: console tidying |
739 |
if (winch->fd != -1) |
1da177e4c Linux-2.6.12-rc2 |
740 |
reactivate_fd(winch->fd, WINCH_IRQ); |
b97b77cca [PATCH] uml: redo... |
741 |
return IRQ_HANDLED; |
1da177e4c Linux-2.6.12-rc2 |
742 |
} |
42a359e31 uml: SIGIO suppor... |
743 744 |
void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty, unsigned long stack) |
1da177e4c Linux-2.6.12-rc2 |
745 746 |
{ struct winch *winch; |
1da177e4c Linux-2.6.12-rc2 |
747 748 |
winch = kmalloc(sizeof(*winch), GFP_KERNEL); if (winch == NULL) { |
2f8a2dc2c uml: console tidying |
749 750 |
printk(KERN_ERR "register_winch_irq - kmalloc failed "); |
42a359e31 uml: SIGIO suppor... |
751 |
goto cleanup; |
1da177e4c Linux-2.6.12-rc2 |
752 |
} |
605a69ac8 [PATCH] uml: remo... |
753 |
|
1da177e4c 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 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 uml: console tidying |
764 765 766 |
printk(KERN_ERR "register_winch_irq - failed to register " "IRQ "); |
42a359e31 uml: SIGIO suppor... |
767 768 |
goto out_free; } |
605a69ac8 [PATCH] uml: remo... |
769 770 |
spin_lock(&winch_handler_lock); |
1da177e4c Linux-2.6.12-rc2 |
771 |
list_add(&winch->list, &winch_handlers); |
605a69ac8 [PATCH] uml: remo... |
772 |
spin_unlock(&winch_handler_lock); |
42a359e31 uml: SIGIO suppor... |
773 |
return; |
e464bf2be [PATCH] uml: SIGW... |
774 |
|
42a359e31 uml: SIGIO suppor... |
775 |
out_free: |
e464bf2be [PATCH] uml: SIGW... |
776 |
kfree(winch); |
42a359e31 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 [PATCH] uml: SIGW... |
782 |
} |
cd2ee4a30 [PATCH] uml: Fix ... |
783 784 |
static void unregister_winch(struct tty_struct *tty) { |
48a0b7404 arch/um/drivers/l... |
785 |
struct list_head *ele, *next; |
e464bf2be [PATCH] uml: SIGW... |
786 |
struct winch *winch; |
cd2ee4a30 [PATCH] uml: Fix ... |
787 |
|
605a69ac8 [PATCH] uml: remo... |
788 |
spin_lock(&winch_handler_lock); |
e464bf2be [PATCH] uml: SIGW... |
789 |
|
48a0b7404 arch/um/drivers/l... |
790 |
list_for_each_safe(ele, next, &winch_handlers) { |
cd2ee4a30 [PATCH] uml: Fix ... |
791 |
winch = list_entry(ele, struct winch, list); |
2f8a2dc2c uml: console tidying |
792 |
if (winch->tty == tty) { |
7cf3cf21a um: fix free_winc... |
793 |
free_winch(winch); |
e464bf2be [PATCH] uml: SIGW... |
794 |
break; |
2f8a2dc2c uml: console tidying |
795 796 |
} } |
605a69ac8 [PATCH] uml: remo... |
797 |
spin_unlock(&winch_handler_lock); |
cd2ee4a30 [PATCH] uml: Fix ... |
798 |
} |
1da177e4c Linux-2.6.12-rc2 |
799 800 |
static void winch_cleanup(void) { |
e464bf2be [PATCH] uml: SIGW... |
801 |
struct list_head *ele, *next; |
1da177e4c Linux-2.6.12-rc2 |
802 |
struct winch *winch; |
e464bf2be [PATCH] uml: SIGW... |
803 |
spin_lock(&winch_handler_lock); |
2f8a2dc2c uml: console tidying |
804 |
list_for_each_safe(ele, next, &winch_handlers) { |
1da177e4c Linux-2.6.12-rc2 |
805 |
winch = list_entry(ele, struct winch, list); |
7cf3cf21a um: fix free_winc... |
806 |
free_winch(winch); |
1da177e4c Linux-2.6.12-rc2 |
807 |
} |
e464bf2be [PATCH] uml: SIGW... |
808 809 |
spin_unlock(&winch_handler_lock); |
1da177e4c 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 [PATCH] uml: umid... |
817 |
umid = get_umid(); |
2f8a2dc2c uml: console tidying |
818 |
if (*umid == '\0') |
b97b77cca [PATCH] uml: redo... |
819 |
return base; |
165dc5911 [PATCH] uml: Simp... |
820 |
|
1da177e4c Linux-2.6.12-rc2 |
821 822 |
len = strlen(base) + strlen(" ()") + strlen(umid) + 1; title = kmalloc(len, GFP_KERNEL); |
2f8a2dc2c uml: console tidying |
823 824 825 |
if (title == NULL) { printk(KERN_ERR "Failed to allocate buffer for xterm title "); |
b97b77cca [PATCH] uml: redo... |
826 |
return base; |
1da177e4c Linux-2.6.12-rc2 |
827 828 829 |
} snprintf(title, len, "%s (%s)", base, umid); |
b97b77cca [PATCH] uml: redo... |
830 |
return title; |
1da177e4c Linux-2.6.12-rc2 |
831 |
} |