aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um/drivers/chan_kern.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um/drivers/chan_kern.c')
-rw-r--r--arch/um/drivers/chan_kern.c198
1 files changed, 88 insertions, 110 deletions
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
index 420e2c800799..ca4c7ebfd0aa 100644
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -140,18 +140,18 @@ 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}
147 148
148 list_for_each(ele, chans) { 149static void line_timer_cb(struct work_struct *work)
149 chan = list_entry(ele, struct chan, list); 150{
150 if (chan->primary && chan->output && chan->ops->winch) { 151 struct line *line = container_of(work, struct line, task.work);
151 register_winch(chan->fd, tty); 152
152 return; 153 if (!line->throttled)
153 } 154 chan_interrupt(line, line->tty, line->driver->read_irq);
154 }
155} 155}
156 156
157int enable_chan(struct line *line) 157int enable_chan(struct line *line)
@@ -160,6 +160,8 @@ int enable_chan(struct line *line)
160 struct chan *chan; 160 struct chan *chan;
161 int err; 161 int err;
162 162
163 INIT_DELAYED_WORK(&line->task, line_timer_cb);
164
163 list_for_each(ele, &line->chan_list) { 165 list_for_each(ele, &line->chan_list) {
164 chan = list_entry(ele, struct chan, list); 166 chan = list_entry(ele, struct chan, list);
165 err = open_one_chan(chan); 167 err = open_one_chan(chan);
@@ -183,7 +185,7 @@ int enable_chan(struct line *line)
183 return 0; 185 return 0;
184 186
185 out_close: 187 out_close:
186 close_chan(&line->chan_list, 0); 188 close_chan(line);
187 return err; 189 return err;
188} 190}
189 191
@@ -244,7 +246,7 @@ static void close_one_chan(struct chan *chan, int delay_free_irq)
244 chan->fd = -1; 246 chan->fd = -1;
245} 247}
246 248
247void close_chan(struct list_head *chans, int delay_free_irq) 249void close_chan(struct line *line)
248{ 250{
249 struct chan *chan; 251 struct chan *chan;
250 252
@@ -253,77 +255,50 @@ void close_chan(struct list_head *chans, int delay_free_irq)
253 * state. Then, the first one opened will have the original state, 255 * state. Then, the first one opened will have the original state,
254 * so it must be the last closed. 256 * so it must be the last closed.
255 */ 257 */
256 list_for_each_entry_reverse(chan, chans, list) { 258 list_for_each_entry_reverse(chan, &line->chan_list, list) {
257 close_one_chan(chan, delay_free_irq); 259 close_one_chan(chan, 0);
258 } 260 }
259} 261}
260 262
261void deactivate_chan(struct list_head *chans, int irq) 263void deactivate_chan(struct chan *chan, int irq)
262{ 264{
263 struct list_head *ele; 265 if (chan && chan->enabled)
264 266 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} 267}
273 268
274void reactivate_chan(struct list_head *chans, int irq) 269void reactivate_chan(struct chan *chan, int irq)
275{ 270{
276 struct list_head *ele; 271 if (chan && chan->enabled)
277 struct chan *chan; 272 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} 273}
286 274
287int write_chan(struct list_head *chans, const char *buf, int len, 275int write_chan(struct chan *chan, const char *buf, int len,
288 int write_irq) 276 int write_irq)
289{ 277{
290 struct list_head *ele;
291 struct chan *chan = NULL;
292 int n, ret = 0; 278 int n, ret = 0;
293 279
294 if (len == 0) 280 if (len == 0 || !chan || !chan->ops->write)
295 return 0; 281 return 0;
296 282
297 list_for_each(ele, chans) { 283 n = chan->ops->write(chan->fd, buf, len, chan->data);
298 chan = list_entry(ele, struct chan, list); 284 if (chan->primary) {
299 if (!chan->output || (chan->ops->write == NULL)) 285 ret = n;
300 continue; 286 if ((ret == -EAGAIN) || ((ret >= 0) && (ret < len)))
301 287 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 } 288 }
309 return ret; 289 return ret;
310} 290}
311 291
312int console_write_chan(struct list_head *chans, const char *buf, int len) 292int console_write_chan(struct chan *chan, const char *buf, int len)
313{ 293{
314 struct list_head *ele;
315 struct chan *chan;
316 int n, ret = 0; 294 int n, ret = 0;
317 295
318 list_for_each(ele, chans) { 296 if (!chan || !chan->ops->console_write)
319 chan = list_entry(ele, struct chan, list); 297 return 0;
320 if (!chan->output || (chan->ops->console_write == NULL))
321 continue;
322 298
323 n = chan->ops->console_write(chan->fd, buf, len); 299 n = chan->ops->console_write(chan->fd, buf, len);
324 if (chan->primary) 300 if (chan->primary)
325 ret = n; 301 ret = n;
326 }
327 return ret; 302 return ret;
328} 303}
329 304
@@ -340,20 +315,24 @@ int console_open_chan(struct line *line, struct console *co)
340 return 0; 315 return 0;
341} 316}
342 317
343int chan_window_size(struct list_head *chans, unsigned short *rows_out, 318int chan_window_size(struct line *line, unsigned short *rows_out,
344 unsigned short *cols_out) 319 unsigned short *cols_out)
345{ 320{
346 struct list_head *ele;
347 struct chan *chan; 321 struct chan *chan;
348 322
349 list_for_each(ele, chans) { 323 chan = line->chan_in;
350 chan = list_entry(ele, struct chan, list); 324 if (chan && chan->primary) {
351 if (chan->primary) { 325 if (chan->ops->window_size == NULL)
352 if (chan->ops->window_size == NULL) 326 return 0;
353 return 0; 327 return chan->ops->window_size(chan->fd, chan->data,
354 return chan->ops->window_size(chan->fd, chan->data, 328 rows_out, cols_out);
355 rows_out, cols_out); 329 }
356 } 330 chan = line->chan_out;
331 if (chan && chan->primary) {
332 if (chan->ops->window_size == NULL)
333 return 0;
334 return chan->ops->window_size(chan->fd, chan->data,
335 rows_out, cols_out);
357 } 336 }
358 return 0; 337 return 0;
359} 338}
@@ -429,21 +408,15 @@ static int chan_pair_config_string(struct chan *in, struct chan *out,
429 return n; 408 return n;
430} 409}
431 410
432int chan_config_string(struct list_head *chans, char *str, int size, 411int chan_config_string(struct line *line, char *str, int size,
433 char **error_out) 412 char **error_out)
434{ 413{
435 struct list_head *ele; 414 struct chan *in = line->chan_in, *out = line->chan_out;
436 struct chan *chan, *in = NULL, *out = NULL;
437 415
438 list_for_each(ele, chans) { 416 if (in && !in->primary)
439 chan = list_entry(ele, struct chan, list); 417 in = NULL;
440 if (!chan->primary) 418 if (out && !out->primary)
441 continue; 419 out = NULL;
442 if (chan->input)
443 in = chan;
444 if (chan->output)
445 out = chan;
446 }
447 420
448 return chan_pair_config_string(in, out, str, size, error_out); 421 return chan_pair_config_string(in, out, str, size, error_out);
449} 422}
@@ -547,10 +520,14 @@ int parse_chan_pair(char *str, struct line *line, int device,
547 char *in, *out; 520 char *in, *out;
548 521
549 if (!list_empty(chans)) { 522 if (!list_empty(chans)) {
523 line->chan_in = line->chan_out = NULL;
550 free_chan(chans); 524 free_chan(chans);
551 INIT_LIST_HEAD(chans); 525 INIT_LIST_HEAD(chans);
552 } 526 }
553 527
528 if (!str)
529 return 0;
530
554 out = strchr(str, ','); 531 out = strchr(str, ',');
555 if (out != NULL) { 532 if (out != NULL) {
556 in = str; 533 in = str;
@@ -562,6 +539,7 @@ int parse_chan_pair(char *str, struct line *line, int device,
562 539
563 new->input = 1; 540 new->input = 1;
564 list_add(&new->list, chans); 541 list_add(&new->list, chans);
542 line->chan_in = new;
565 543
566 new = parse_chan(line, out, device, opts, error_out); 544 new = parse_chan(line, out, device, opts, error_out);
567 if (new == NULL) 545 if (new == NULL)
@@ -569,6 +547,7 @@ int parse_chan_pair(char *str, struct line *line, int device,
569 547
570 list_add(&new->list, chans); 548 list_add(&new->list, chans);
571 new->output = 1; 549 new->output = 1;
550 line->chan_out = new;
572 } 551 }
573 else { 552 else {
574 new = parse_chan(line, str, device, opts, error_out); 553 new = parse_chan(line, str, device, opts, error_out);
@@ -578,43 +557,42 @@ int parse_chan_pair(char *str, struct line *line, int device,
578 list_add(&new->list, chans); 557 list_add(&new->list, chans);
579 new->input = 1; 558 new->input = 1;
580 new->output = 1; 559 new->output = 1;
560 line->chan_in = line->chan_out = new;
581 } 561 }
582 return 0; 562 return 0;
583} 563}
584 564
585void chan_interrupt(struct list_head *chans, struct delayed_work *task, 565void chan_interrupt(struct line *line, struct tty_struct *tty, int irq)
586 struct tty_struct *tty, int irq)
587{ 566{
588 struct list_head *ele, *next; 567 struct chan *chan = line->chan_in;
589 struct chan *chan;
590 int err; 568 int err;
591 char c; 569 char c;
592 570
593 list_for_each_safe(ele, next, chans) { 571 if (!chan || !chan->ops->read)
594 chan = list_entry(ele, struct chan, list); 572 goto out;
595 if (!chan->input || (chan->ops->read == NULL)) 573
596 continue; 574 do {
597 do { 575 if (tty && !tty_buffer_request_room(tty, 1)) {
598 if (tty && !tty_buffer_request_room(tty, 1)) { 576 schedule_delayed_work(&line->task, 1);
599 schedule_delayed_work(task, 1); 577 goto out;
600 goto out;
601 }
602 err = chan->ops->read(chan->fd, &c, chan->data);
603 if (err > 0)
604 tty_receive_char(tty, c);
605 } while (err > 0);
606
607 if (err == 0)
608 reactivate_fd(chan->fd, irq);
609 if (err == -EIO) {
610 if (chan->primary) {
611 if (tty != NULL)
612 tty_hangup(tty);
613 close_chan(chans, 1);
614 return;
615 }
616 else close_one_chan(chan, 1);
617 } 578 }
579 err = chan->ops->read(chan->fd, &c, chan->data);
580 if (err > 0)
581 tty_receive_char(tty, c);
582 } while (err > 0);
583
584 if (err == 0)
585 reactivate_fd(chan->fd, irq);
586 if (err == -EIO) {
587 if (chan->primary) {
588 if (tty != NULL)
589 tty_hangup(tty);
590 if (line->chan_out != chan)
591 close_one_chan(line->chan_out, 1);
592 }
593 close_one_chan(chan, 1);
594 if (chan->primary)
595 return;
618 } 596 }
619 out: 597 out:
620 if (tty) 598 if (tty)