aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/um/drivers/chan.h16
-rw-r--r--arch/um/drivers/chan_kern.c172
-rw-r--r--arch/um/drivers/line.c24
-rw-r--r--arch/um/drivers/ssl.c2
-rw-r--r--arch/um/drivers/stdio_console.c2
5 files changed, 88 insertions, 128 deletions
diff --git a/arch/um/drivers/chan.h b/arch/um/drivers/chan.h
index 8df0fd9024dc..5078ec701c61 100644
--- a/arch/um/drivers/chan.h
+++ b/arch/um/drivers/chan.h
@@ -27,24 +27,24 @@ struct chan {
27 void *data; 27 void *data;
28}; 28};
29 29
30extern void chan_interrupt(struct list_head *chans, struct delayed_work *task, 30extern void chan_interrupt(struct line *line, struct delayed_work *task,
31 struct tty_struct *tty, int irq); 31 struct tty_struct *tty, int irq);
32extern int parse_chan_pair(char *str, struct line *line, int device, 32extern int parse_chan_pair(char *str, struct line *line, int device,
33 const struct chan_opts *opts, char **error_out); 33 const struct chan_opts *opts, char **error_out);
34extern int write_chan(struct list_head *chans, const char *buf, int len, 34extern int write_chan(struct chan *chan, const char *buf, int len,
35 int write_irq); 35 int write_irq);
36extern int console_write_chan(struct list_head *chans, const char *buf, 36extern int console_write_chan(struct chan *chan, const char *buf,
37 int len); 37 int len);
38extern int console_open_chan(struct line *line, struct console *co); 38extern int console_open_chan(struct line *line, struct console *co);
39extern void deactivate_chan(struct list_head *chans, int irq); 39extern void deactivate_chan(struct chan *chan, int irq);
40extern void reactivate_chan(struct list_head *chans, int irq); 40extern void reactivate_chan(struct chan *chan, int irq);
41extern void chan_enable_winch(struct list_head *chans, struct tty_struct *tty); 41extern void chan_enable_winch(struct chan *chan, struct tty_struct *tty);
42extern int enable_chan(struct line *line); 42extern int enable_chan(struct line *line);
43extern void close_chan(struct list_head *chans, int delay_free_irq); 43extern void close_chan(struct list_head *chans, int delay_free_irq);
44extern int chan_window_size(struct list_head *chans, 44extern int chan_window_size(struct line *line,
45 unsigned short *rows_out, 45 unsigned short *rows_out,
46 unsigned short *cols_out); 46 unsigned short *cols_out);
47extern int chan_config_string(struct list_head *chans, char *str, int size, 47extern int chan_config_string(struct line *line, char *str, int size,
48 char **error_out); 48 char **error_out);
49 49
50#endif 50#endif
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
index 390920d63a24..73d7bc018ab2 100644
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -140,18 +140,10 @@ static int open_chan(struct list_head *chans)
140 return err; 140 return err;
141} 141}
142 142
143void chan_enable_winch(struct list_head *chans, struct tty_struct *tty) 143void chan_enable_winch(struct chan *chan, struct tty_struct *tty)
144{ 144{
145 struct list_head *ele; 145 if (chan && chan->primary && chan->ops->winch)
146 struct chan *chan; 146 register_winch(chan->fd, tty);
147
148 list_for_each(ele, chans) {
149 chan = list_entry(ele, struct chan, list);
150 if (chan->primary && chan->output && chan->ops->winch) {
151 register_winch(chan->fd, tty);
152 return;
153 }
154 }
155} 147}
156 148
157int enable_chan(struct line *line) 149int enable_chan(struct line *line)
@@ -258,72 +250,45 @@ void close_chan(struct list_head *chans, int delay_free_irq)
258 } 250 }
259} 251}
260 252
261void deactivate_chan(struct list_head *chans, int irq) 253void deactivate_chan(struct chan *chan, int irq)
262{ 254{
263 struct list_head *ele; 255 if (chan && chan->enabled)
264 256 deactivate_fd(chan->fd, irq);
265 struct chan *chan;
266 list_for_each(ele, chans) {
267 chan = list_entry(ele, struct chan, list);
268
269 if (chan->enabled && chan->input)
270 deactivate_fd(chan->fd, irq);
271 }
272} 257}
273 258
274void reactivate_chan(struct list_head *chans, int irq) 259void reactivate_chan(struct chan *chan, int irq)
275{ 260{
276 struct list_head *ele; 261 if (chan && chan->enabled)
277 struct chan *chan; 262 reactivate_fd(chan->fd, irq);
278
279 list_for_each(ele, chans) {
280 chan = list_entry(ele, struct chan, list);
281
282 if (chan->enabled && chan->input)
283 reactivate_fd(chan->fd, irq);
284 }
285} 263}
286 264
287int write_chan(struct list_head *chans, const char *buf, int len, 265int write_chan(struct chan *chan, const char *buf, int len,
288 int write_irq) 266 int write_irq)
289{ 267{
290 struct list_head *ele;
291 struct chan *chan = NULL;
292 int n, ret = 0; 268 int n, ret = 0;
293 269
294 if (len == 0) 270 if (len == 0 || !chan || !chan->ops->write)
295 return 0; 271 return 0;
296 272
297 list_for_each(ele, chans) { 273 n = chan->ops->write(chan->fd, buf, len, chan->data);
298 chan = list_entry(ele, struct chan, list); 274 if (chan->primary) {
299 if (!chan->output || (chan->ops->write == NULL)) 275 ret = n;
300 continue; 276 if ((ret == -EAGAIN) || ((ret >= 0) && (ret < len)))
301 277 reactivate_fd(chan->fd, write_irq);
302 n = chan->ops->write(chan->fd, buf, len, chan->data);
303 if (chan->primary) {
304 ret = n;
305 if ((ret == -EAGAIN) || ((ret >= 0) && (ret < len)))
306 reactivate_fd(chan->fd, write_irq);
307 }
308 } 278 }
309 return ret; 279 return ret;
310} 280}
311 281
312int console_write_chan(struct list_head *chans, const char *buf, int len) 282int console_write_chan(struct chan *chan, const char *buf, int len)
313{ 283{
314 struct list_head *ele;
315 struct chan *chan;
316 int n, ret = 0; 284 int n, ret = 0;
317 285
318 list_for_each(ele, chans) { 286 if (!chan || !chan->ops->console_write)
319 chan = list_entry(ele, struct chan, list); 287 return 0;
320 if (!chan->output || (chan->ops->console_write == NULL))
321 continue;
322 288
323 n = chan->ops->console_write(chan->fd, buf, len); 289 n = chan->ops->console_write(chan->fd, buf, len);
324 if (chan->primary) 290 if (chan->primary)
325 ret = n; 291 ret = n;
326 }
327 return ret; 292 return ret;
328} 293}
329 294
@@ -340,20 +305,24 @@ int console_open_chan(struct line *line, struct console *co)
340 return 0; 305 return 0;
341} 306}
342 307
343int chan_window_size(struct list_head *chans, unsigned short *rows_out, 308int chan_window_size(struct line *line, unsigned short *rows_out,
344 unsigned short *cols_out) 309 unsigned short *cols_out)
345{ 310{
346 struct list_head *ele;
347 struct chan *chan; 311 struct chan *chan;
348 312
349 list_for_each(ele, chans) { 313 chan = line->chan_in;
350 chan = list_entry(ele, struct chan, list); 314 if (chan && chan->primary) {
351 if (chan->primary) { 315 if (chan->ops->window_size == NULL)
352 if (chan->ops->window_size == NULL) 316 return 0;
353 return 0; 317 return chan->ops->window_size(chan->fd, chan->data,
354 return chan->ops->window_size(chan->fd, chan->data, 318 rows_out, cols_out);
355 rows_out, cols_out); 319 }
356 } 320 chan = line->chan_out;
321 if (chan && chan->primary) {
322 if (chan->ops->window_size == NULL)
323 return 0;
324 return chan->ops->window_size(chan->fd, chan->data,
325 rows_out, cols_out);
357 } 326 }
358 return 0; 327 return 0;
359} 328}
@@ -429,21 +398,15 @@ static int chan_pair_config_string(struct chan *in, struct chan *out,
429 return n; 398 return n;
430} 399}
431 400
432int chan_config_string(struct list_head *chans, char *str, int size, 401int chan_config_string(struct line *line, char *str, int size,
433 char **error_out) 402 char **error_out)
434{ 403{
435 struct list_head *ele; 404 struct chan *in = line->chan_in, *out = line->chan_out;
436 struct chan *chan, *in = NULL, *out = NULL;
437 405
438 list_for_each(ele, chans) { 406 if (in && !in->primary)
439 chan = list_entry(ele, struct chan, list); 407 in = NULL;
440 if (!chan->primary) 408 if (out && !out->primary)
441 continue; 409 out = NULL;
442 if (chan->input)
443 in = chan;
444 if (chan->output)
445 out = chan;
446 }
447 410
448 return chan_pair_config_string(in, out, str, size, error_out); 411 return chan_pair_config_string(in, out, str, size, error_out);
449} 412}
@@ -589,39 +552,36 @@ int parse_chan_pair(char *str, struct line *line, int device,
589 return 0; 552 return 0;
590} 553}
591 554
592void chan_interrupt(struct list_head *chans, struct delayed_work *task, 555void chan_interrupt(struct line *line, struct delayed_work *task,
593 struct tty_struct *tty, int irq) 556 struct tty_struct *tty, int irq)
594{ 557{
595 struct list_head *ele, *next; 558 struct chan *chan = line->chan_in;
596 struct chan *chan;
597 int err; 559 int err;
598 char c; 560 char c;
599 561
600 list_for_each_safe(ele, next, chans) { 562 if (!chan || !chan->ops->read)
601 chan = list_entry(ele, struct chan, list); 563 goto out;
602 if (!chan->input || (chan->ops->read == NULL)) 564
603 continue; 565 do {
604 do { 566 if (tty && !tty_buffer_request_room(tty, 1)) {
605 if (tty && !tty_buffer_request_room(tty, 1)) { 567 schedule_delayed_work(task, 1);
606 schedule_delayed_work(task, 1); 568 goto out;
607 goto out; 569 }
608 } 570 err = chan->ops->read(chan->fd, &c, chan->data);
609 err = chan->ops->read(chan->fd, &c, chan->data); 571 if (err > 0)
610 if (err > 0) 572 tty_receive_char(tty, c);
611 tty_receive_char(tty, c); 573 } while (err > 0);
612 } while (err > 0); 574
613 575 if (err == 0)
614 if (err == 0) 576 reactivate_fd(chan->fd, irq);
615 reactivate_fd(chan->fd, irq); 577 if (err == -EIO) {
616 if (err == -EIO) { 578 if (chan->primary) {
617 if (chan->primary) { 579 if (tty != NULL)
618 if (tty != NULL) 580 tty_hangup(tty);
619 tty_hangup(tty); 581 close_chan(&line->chan_list, 1);
620 close_chan(chans, 1); 582 return;
621 return;
622 }
623 else close_one_chan(chan, 1);
624 } 583 }
584 else close_one_chan(chan, 1);
625 } 585 }
626 out: 586 out:
627 if (tty) 587 if (tty)
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index 9ffade87a8cf..c1aa89cefaec 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -21,7 +21,7 @@ static irqreturn_t line_interrupt(int irq, void *data)
21 struct line *line = chan->line; 21 struct line *line = chan->line;
22 22
23 if (line) 23 if (line)
24 chan_interrupt(&line->chan_list, &line->task, line->tty, irq); 24 chan_interrupt(line, &line->task, line->tty, irq);
25 return IRQ_HANDLED; 25 return IRQ_HANDLED;
26} 26}
27 27
@@ -30,7 +30,7 @@ static void line_timer_cb(struct work_struct *work)
30 struct line *line = container_of(work, struct line, task.work); 30 struct line *line = container_of(work, struct line, task.work);
31 31
32 if (!line->throttled) 32 if (!line->throttled)
33 chan_interrupt(&line->chan_list, &line->task, line->tty, 33 chan_interrupt(line, &line->task, line->tty,
34 line->driver->read_irq); 34 line->driver->read_irq);
35} 35}
36 36
@@ -145,7 +145,7 @@ static int flush_buffer(struct line *line)
145 /* line->buffer + LINE_BUFSIZE is the end of the buffer! */ 145 /* line->buffer + LINE_BUFSIZE is the end of the buffer! */
146 count = line->buffer + LINE_BUFSIZE - line->head; 146 count = line->buffer + LINE_BUFSIZE - line->head;
147 147
148 n = write_chan(&line->chan_list, line->head, count, 148 n = write_chan(line->chan_out, line->head, count,
149 line->driver->write_irq); 149 line->driver->write_irq);
150 if (n < 0) 150 if (n < 0)
151 return n; 151 return n;
@@ -162,7 +162,7 @@ static int flush_buffer(struct line *line)
162 } 162 }
163 163
164 count = line->tail - line->head; 164 count = line->tail - line->head;
165 n = write_chan(&line->chan_list, line->head, count, 165 n = write_chan(line->chan_out, line->head, count,
166 line->driver->write_irq); 166 line->driver->write_irq);
167 167
168 if (n < 0) 168 if (n < 0)
@@ -206,7 +206,7 @@ int line_write(struct tty_struct *tty, const unsigned char *buf, int len)
206 if (line->head != line->tail) 206 if (line->head != line->tail)
207 ret = buffer_data(line, buf, len); 207 ret = buffer_data(line, buf, len);
208 else { 208 else {
209 n = write_chan(&line->chan_list, buf, len, 209 n = write_chan(line->chan_out, buf, len,
210 line->driver->write_irq); 210 line->driver->write_irq);
211 if (n < 0) { 211 if (n < 0) {
212 ret = n; 212 ret = n;
@@ -318,7 +318,7 @@ void line_throttle(struct tty_struct *tty)
318{ 318{
319 struct line *line = tty->driver_data; 319 struct line *line = tty->driver_data;
320 320
321 deactivate_chan(&line->chan_list, line->driver->read_irq); 321 deactivate_chan(line->chan_in, line->driver->read_irq);
322 line->throttled = 1; 322 line->throttled = 1;
323} 323}
324 324
@@ -327,7 +327,7 @@ void line_unthrottle(struct tty_struct *tty)
327 struct line *line = tty->driver_data; 327 struct line *line = tty->driver_data;
328 328
329 line->throttled = 0; 329 line->throttled = 0;
330 chan_interrupt(&line->chan_list, &line->task, tty, 330 chan_interrupt(line, &line->task, tty,
331 line->driver->read_irq); 331 line->driver->read_irq);
332 332
333 /* 333 /*
@@ -336,7 +336,7 @@ void line_unthrottle(struct tty_struct *tty)
336 * again and we shouldn't turn the interrupt back on. 336 * again and we shouldn't turn the interrupt back on.
337 */ 337 */
338 if (!line->throttled) 338 if (!line->throttled)
339 reactivate_chan(&line->chan_list, line->driver->read_irq); 339 reactivate_chan(line->chan_in, line->driver->read_irq);
340} 340}
341 341
342static irqreturn_t line_write_interrupt(int irq, void *data) 342static irqreturn_t line_write_interrupt(int irq, void *data)
@@ -428,11 +428,11 @@ int line_open(struct line *lines, struct tty_struct *tty)
428 INIT_DELAYED_WORK(&line->task, line_timer_cb); 428 INIT_DELAYED_WORK(&line->task, line_timer_cb);
429 429
430 if (!line->sigio) { 430 if (!line->sigio) {
431 chan_enable_winch(&line->chan_list, tty); 431 chan_enable_winch(line->chan_out, tty);
432 line->sigio = 1; 432 line->sigio = 1;
433 } 433 }
434 434
435 chan_window_size(&line->chan_list, &tty->winsize.ws_row, 435 chan_window_size(line, &tty->winsize.ws_row,
436 &tty->winsize.ws_col); 436 &tty->winsize.ws_col);
437out_unlock: 437out_unlock:
438 mutex_unlock(&line->count_lock); 438 mutex_unlock(&line->count_lock);
@@ -624,7 +624,7 @@ int line_get_config(char *name, struct line *lines, unsigned int num, char *str,
624 CONFIG_CHUNK(str, size, n, "none", 1); 624 CONFIG_CHUNK(str, size, n, "none", 1);
625 else if (line->tty == NULL) 625 else if (line->tty == NULL)
626 CONFIG_CHUNK(str, size, n, line->init_str, 1); 626 CONFIG_CHUNK(str, size, n, line->init_str, 1);
627 else n = chan_config_string(&line->chan_list, str, size, error_out); 627 else n = chan_config_string(line, str, size, error_out);
628 mutex_unlock(&line->count_lock); 628 mutex_unlock(&line->count_lock);
629 629
630 return n; 630 return n;
@@ -761,7 +761,7 @@ static irqreturn_t winch_interrupt(int irq, void *data)
761 if (tty != NULL) { 761 if (tty != NULL) {
762 line = tty->driver_data; 762 line = tty->driver_data;
763 if (line != NULL) { 763 if (line != NULL) {
764 chan_window_size(&line->chan_list, &tty->winsize.ws_row, 764 chan_window_size(line, &tty->winsize.ws_row,
765 &tty->winsize.ws_col); 765 &tty->winsize.ws_col);
766 kill_pgrp(tty->pgrp, SIGWINCH, 1); 766 kill_pgrp(tty->pgrp, SIGWINCH, 1);
767 } 767 }
diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c
index d0b5ccf2379f..e09801a1327b 100644
--- a/arch/um/drivers/ssl.c
+++ b/arch/um/drivers/ssl.c
@@ -151,7 +151,7 @@ static void ssl_console_write(struct console *c, const char *string,
151 unsigned long flags; 151 unsigned long flags;
152 152
153 spin_lock_irqsave(&line->lock, flags); 153 spin_lock_irqsave(&line->lock, flags);
154 console_write_chan(&line->chan_list, string, len); 154 console_write_chan(line->chan_out, string, len);
155 spin_unlock_irqrestore(&line->lock, flags); 155 spin_unlock_irqrestore(&line->lock, flags);
156} 156}
157 157
diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c
index fe581209d629..7663541c372e 100644
--- a/arch/um/drivers/stdio_console.c
+++ b/arch/um/drivers/stdio_console.c
@@ -124,7 +124,7 @@ static void uml_console_write(struct console *console, const char *string,
124 unsigned long flags; 124 unsigned long flags;
125 125
126 spin_lock_irqsave(&line->lock, flags); 126 spin_lock_irqsave(&line->lock, flags);
127 console_write_chan(&line->chan_list, string, len); 127 console_write_chan(line->chan_out, string, len);
128 spin_unlock_irqrestore(&line->lock, flags); 128 spin_unlock_irqrestore(&line->lock, flags);
129} 129}
130 130