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.c273
1 files changed, 171 insertions, 102 deletions
diff --git a/arch/um/drivers/chan_kern.c b/arch/um/drivers/chan_kern.c
index 5b58fad45290..cd13b91b9ff6 100644
--- a/arch/um/drivers/chan_kern.c
+++ b/arch/um/drivers/chan_kern.c
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) 2 * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL 3 * Licensed under the GPL
4 */ 4 */
@@ -58,7 +58,7 @@ static void *not_configged_init(char *str, int device, struct chan_opts *opts)
58{ 58{
59 my_puts("Using a channel type which is configured out of " 59 my_puts("Using a channel type which is configured out of "
60 "UML\n"); 60 "UML\n");
61 return(NULL); 61 return NULL;
62} 62}
63 63
64static int not_configged_open(int input, int output, int primary, void *data, 64static int not_configged_open(int input, int output, int primary, void *data,
@@ -66,7 +66,7 @@ static int not_configged_open(int input, int output, int primary, void *data,
66{ 66{
67 my_puts("Using a channel type which is configured out of " 67 my_puts("Using a channel type which is configured out of "
68 "UML\n"); 68 "UML\n");
69 return(-ENODEV); 69 return -ENODEV;
70} 70}
71 71
72static void not_configged_close(int fd, void *data) 72static void not_configged_close(int fd, void *data)
@@ -79,21 +79,21 @@ static int not_configged_read(int fd, char *c_out, void *data)
79{ 79{
80 my_puts("Using a channel type which is configured out of " 80 my_puts("Using a channel type which is configured out of "
81 "UML\n"); 81 "UML\n");
82 return(-EIO); 82 return -EIO;
83} 83}
84 84
85static int not_configged_write(int fd, const char *buf, int len, void *data) 85static int not_configged_write(int fd, const char *buf, int len, void *data)
86{ 86{
87 my_puts("Using a channel type which is configured out of " 87 my_puts("Using a channel type which is configured out of "
88 "UML\n"); 88 "UML\n");
89 return(-EIO); 89 return -EIO;
90} 90}
91 91
92static int not_configged_console_write(int fd, const char *buf, int len) 92static int not_configged_console_write(int fd, const char *buf, int len)
93{ 93{
94 my_puts("Using a channel type which is configured out of " 94 my_puts("Using a channel type which is configured out of "
95 "UML\n"); 95 "UML\n");
96 return(-EIO); 96 return -EIO;
97} 97}
98 98
99static int not_configged_window_size(int fd, void *data, unsigned short *rows, 99static int not_configged_window_size(int fd, void *data, unsigned short *rows,
@@ -101,7 +101,7 @@ static int not_configged_window_size(int fd, void *data, unsigned short *rows,
101{ 101{
102 my_puts("Using a channel type which is configured out of " 102 my_puts("Using a channel type which is configured out of "
103 "UML\n"); 103 "UML\n");
104 return(-ENODEV); 104 return -ENODEV;
105} 105}
106 106
107static void not_configged_free(void *data) 107static void not_configged_free(void *data)
@@ -135,17 +135,17 @@ int generic_read(int fd, char *c_out, void *unused)
135 n = os_read_file(fd, c_out, sizeof(*c_out)); 135 n = os_read_file(fd, c_out, sizeof(*c_out));
136 136
137 if(n == -EAGAIN) 137 if(n == -EAGAIN)
138 return(0); 138 return 0;
139 else if(n == 0) 139 else if(n == 0)
140 return(-EIO); 140 return -EIO;
141 return(n); 141 return n;
142} 142}
143 143
144/* XXX Trivial wrapper around os_write_file */ 144/* XXX Trivial wrapper around os_write_file */
145 145
146int generic_write(int fd, const char *buf, int n, void *unused) 146int generic_write(int fd, const char *buf, int n, void *unused)
147{ 147{
148 return(os_write_file(fd, buf, n)); 148 return os_write_file(fd, buf, n);
149} 149}
150 150
151int generic_window_size(int fd, void *unused, unsigned short *rows_out, 151int generic_window_size(int fd, void *unused, unsigned short *rows_out,
@@ -156,14 +156,14 @@ int generic_window_size(int fd, void *unused, unsigned short *rows_out,
156 156
157 ret = os_window_size(fd, &rows, &cols); 157 ret = os_window_size(fd, &rows, &cols);
158 if(ret < 0) 158 if(ret < 0)
159 return(ret); 159 return ret;
160 160
161 ret = ((*rows_out != rows) || (*cols_out != cols)); 161 ret = ((*rows_out != rows) || (*cols_out != cols));
162 162
163 *rows_out = rows; 163 *rows_out = rows;
164 *cols_out = cols; 164 *cols_out = cols;
165 165
166 return(ret); 166 return ret;
167} 167}
168 168
169void generic_free(void *data) 169void generic_free(void *data)
@@ -186,25 +186,29 @@ static void tty_receive_char(struct tty_struct *tty, char ch)
186 } 186 }
187 } 187 }
188 188
189 if((tty->flip.flag_buf_ptr == NULL) || 189 if((tty->flip.flag_buf_ptr == NULL) ||
190 (tty->flip.char_buf_ptr == NULL)) 190 (tty->flip.char_buf_ptr == NULL))
191 return; 191 return;
192 tty_insert_flip_char(tty, ch, TTY_NORMAL); 192 tty_insert_flip_char(tty, ch, TTY_NORMAL);
193} 193}
194 194
195static int open_one_chan(struct chan *chan, int input, int output, int primary) 195static int open_one_chan(struct chan *chan)
196{ 196{
197 int fd; 197 int fd;
198 198
199 if(chan->opened) return(0); 199 if(chan->opened)
200 if(chan->ops->open == NULL) fd = 0; 200 return 0;
201 else fd = (*chan->ops->open)(input, output, primary, chan->data, 201
202 &chan->dev); 202 if(chan->ops->open == NULL)
203 if(fd < 0) return(fd); 203 fd = 0;
204 else fd = (*chan->ops->open)(chan->input, chan->output, chan->primary,
205 chan->data, &chan->dev);
206 if(fd < 0)
207 return fd;
204 chan->fd = fd; 208 chan->fd = fd;
205 209
206 chan->opened = 1; 210 chan->opened = 1;
207 return(0); 211 return 0;
208} 212}
209 213
210int open_chan(struct list_head *chans) 214int open_chan(struct list_head *chans)
@@ -215,11 +219,11 @@ int open_chan(struct list_head *chans)
215 219
216 list_for_each(ele, chans){ 220 list_for_each(ele, chans){
217 chan = list_entry(ele, struct chan, list); 221 chan = list_entry(ele, struct chan, list);
218 ret = open_one_chan(chan, chan->input, chan->output, 222 ret = open_one_chan(chan);
219 chan->primary); 223 if(chan->primary)
220 if(chan->primary) err = ret; 224 err = ret;
221 } 225 }
222 return(err); 226 return err;
223} 227}
224 228
225void chan_enable_winch(struct list_head *chans, struct tty_struct *tty) 229void chan_enable_winch(struct list_head *chans, struct tty_struct *tty)
@@ -236,20 +240,65 @@ void chan_enable_winch(struct list_head *chans, struct tty_struct *tty)
236 } 240 }
237} 241}
238 242
239void enable_chan(struct list_head *chans, struct tty_struct *tty) 243void enable_chan(struct line *line)
240{ 244{
241 struct list_head *ele; 245 struct list_head *ele;
242 struct chan *chan; 246 struct chan *chan;
243 247
244 list_for_each(ele, chans){ 248 list_for_each(ele, &line->chan_list){
245 chan = list_entry(ele, struct chan, list); 249 chan = list_entry(ele, struct chan, list);
246 if(!chan->opened) continue; 250 if(open_one_chan(chan))
251 continue;
252
253 if(chan->enabled)
254 continue;
255 line_setup_irq(chan->fd, chan->input, chan->output, line,
256 chan);
257 chan->enabled = 1;
258 }
259}
260
261static LIST_HEAD(irqs_to_free);
262
263void free_irqs(void)
264{
265 struct chan *chan;
266
267 while(!list_empty(&irqs_to_free)){
268 chan = list_entry(irqs_to_free.next, struct chan, free_list);
269 list_del(&chan->free_list);
247 270
248 line_setup_irq(chan->fd, chan->input, chan->output, tty); 271 if(chan->input)
272 free_irq(chan->line->driver->read_irq, chan);
273 if(chan->output)
274 free_irq(chan->line->driver->write_irq, chan);
275 chan->enabled = 0;
276 }
277}
278
279static void close_one_chan(struct chan *chan, int delay_free_irq)
280{
281 if(!chan->opened)
282 return;
283
284 if(delay_free_irq){
285 list_add(&chan->free_list, &irqs_to_free);
249 } 286 }
287 else {
288 if(chan->input)
289 free_irq(chan->line->driver->read_irq, chan);
290 if(chan->output)
291 free_irq(chan->line->driver->write_irq, chan);
292 chan->enabled = 0;
293 }
294 if(chan->ops->close != NULL)
295 (*chan->ops->close)(chan->fd, chan->data);
296
297 chan->opened = 0;
298 chan->fd = -1;
250} 299}
251 300
252void close_chan(struct list_head *chans) 301void close_chan(struct list_head *chans, int delay_free_irq)
253{ 302{
254 struct chan *chan; 303 struct chan *chan;
255 304
@@ -259,15 +308,37 @@ void close_chan(struct list_head *chans)
259 * so it must be the last closed. 308 * so it must be the last closed.
260 */ 309 */
261 list_for_each_entry_reverse(chan, chans, list) { 310 list_for_each_entry_reverse(chan, chans, list) {
262 if(!chan->opened) continue; 311 close_one_chan(chan, delay_free_irq);
263 if(chan->ops->close != NULL) 312 }
264 (*chan->ops->close)(chan->fd, chan->data); 313}
265 chan->opened = 0; 314
266 chan->fd = -1; 315void deactivate_chan(struct list_head *chans, int irq)
316{
317 struct list_head *ele;
318
319 struct chan *chan;
320 list_for_each(ele, chans) {
321 chan = list_entry(ele, struct chan, list);
322
323 if(chan->enabled && chan->input)
324 deactivate_fd(chan->fd, irq);
325 }
326}
327
328void reactivate_chan(struct list_head *chans, int irq)
329{
330 struct list_head *ele;
331 struct chan *chan;
332
333 list_for_each(ele, chans) {
334 chan = list_entry(ele, struct chan, list);
335
336 if(chan->enabled && chan->input)
337 reactivate_fd(chan->fd, irq);
267 } 338 }
268} 339}
269 340
270int write_chan(struct list_head *chans, const char *buf, int len, 341int write_chan(struct list_head *chans, const char *buf, int len,
271 int write_irq) 342 int write_irq)
272{ 343{
273 struct list_head *ele; 344 struct list_head *ele;
@@ -285,7 +356,7 @@ int write_chan(struct list_head *chans, const char *buf, int len,
285 reactivate_fd(chan->fd, write_irq); 356 reactivate_fd(chan->fd, write_irq);
286 } 357 }
287 } 358 }
288 return(ret); 359 return ret;
289} 360}
290 361
291int console_write_chan(struct list_head *chans, const char *buf, int len) 362int console_write_chan(struct list_head *chans, const char *buf, int len)
@@ -301,19 +372,18 @@ int console_write_chan(struct list_head *chans, const char *buf, int len)
301 n = chan->ops->console_write(chan->fd, buf, len); 372 n = chan->ops->console_write(chan->fd, buf, len);
302 if(chan->primary) ret = n; 373 if(chan->primary) ret = n;
303 } 374 }
304 return(ret); 375 return ret;
305} 376}
306 377
307int console_open_chan(struct line *line, struct console *co, struct chan_opts *opts) 378int console_open_chan(struct line *line, struct console *co,
379 struct chan_opts *opts)
308{ 380{
309 if (!list_empty(&line->chan_list)) 381 int err;
310 return 0; 382
383 err = open_chan(&line->chan_list);
384 if(err)
385 return err;
311 386
312 if (0 != parse_chan_pair(line->init_str, &line->chan_list,
313 line->init_pri, co->index, opts))
314 return -1;
315 if (0 != open_chan(&line->chan_list))
316 return -1;
317 printk("Console initialized on /dev/%s%d\n",co->name,co->index); 387 printk("Console initialized on /dev/%s%d\n",co->name,co->index);
318 return 0; 388 return 0;
319} 389}
@@ -327,32 +397,36 @@ int chan_window_size(struct list_head *chans, unsigned short *rows_out,
327 list_for_each(ele, chans){ 397 list_for_each(ele, chans){
328 chan = list_entry(ele, struct chan, list); 398 chan = list_entry(ele, struct chan, list);
329 if(chan->primary){ 399 if(chan->primary){
330 if(chan->ops->window_size == NULL) return(0); 400 if(chan->ops->window_size == NULL)
331 return(chan->ops->window_size(chan->fd, chan->data, 401 return 0;
332 rows_out, cols_out)); 402 return chan->ops->window_size(chan->fd, chan->data,
403 rows_out, cols_out);
333 } 404 }
334 } 405 }
335 return(0); 406 return 0;
336} 407}
337 408
338void free_one_chan(struct chan *chan) 409void free_one_chan(struct chan *chan, int delay_free_irq)
339{ 410{
340 list_del(&chan->list); 411 list_del(&chan->list);
412
413 close_one_chan(chan, delay_free_irq);
414
341 if(chan->ops->free != NULL) 415 if(chan->ops->free != NULL)
342 (*chan->ops->free)(chan->data); 416 (*chan->ops->free)(chan->data);
343 free_irq_by_fd(chan->fd); 417
344 if(chan->primary && chan->output) ignore_sigio_fd(chan->fd); 418 if(chan->primary && chan->output) ignore_sigio_fd(chan->fd);
345 kfree(chan); 419 kfree(chan);
346} 420}
347 421
348void free_chan(struct list_head *chans) 422void free_chan(struct list_head *chans, int delay_free_irq)
349{ 423{
350 struct list_head *ele, *next; 424 struct list_head *ele, *next;
351 struct chan *chan; 425 struct chan *chan;
352 426
353 list_for_each_safe(ele, next, chans){ 427 list_for_each_safe(ele, next, chans){
354 chan = list_entry(ele, struct chan, list); 428 chan = list_entry(ele, struct chan, list);
355 free_one_chan(chan); 429 free_one_chan(chan, delay_free_irq);
356 } 430 }
357} 431}
358 432
@@ -363,23 +437,23 @@ static int one_chan_config_string(struct chan *chan, char *str, int size,
363 437
364 if(chan == NULL){ 438 if(chan == NULL){
365 CONFIG_CHUNK(str, size, n, "none", 1); 439 CONFIG_CHUNK(str, size, n, "none", 1);
366 return(n); 440 return n;
367 } 441 }
368 442
369 CONFIG_CHUNK(str, size, n, chan->ops->type, 0); 443 CONFIG_CHUNK(str, size, n, chan->ops->type, 0);
370 444
371 if(chan->dev == NULL){ 445 if(chan->dev == NULL){
372 CONFIG_CHUNK(str, size, n, "", 1); 446 CONFIG_CHUNK(str, size, n, "", 1);
373 return(n); 447 return n;
374 } 448 }
375 449
376 CONFIG_CHUNK(str, size, n, ":", 0); 450 CONFIG_CHUNK(str, size, n, ":", 0);
377 CONFIG_CHUNK(str, size, n, chan->dev, 0); 451 CONFIG_CHUNK(str, size, n, chan->dev, 0);
378 452
379 return(n); 453 return n;
380} 454}
381 455
382static int chan_pair_config_string(struct chan *in, struct chan *out, 456static int chan_pair_config_string(struct chan *in, struct chan *out,
383 char *str, int size, char **error_out) 457 char *str, int size, char **error_out)
384{ 458{
385 int n; 459 int n;
@@ -390,7 +464,7 @@ static int chan_pair_config_string(struct chan *in, struct chan *out,
390 464
391 if(in == out){ 465 if(in == out){
392 CONFIG_CHUNK(str, size, n, "", 1); 466 CONFIG_CHUNK(str, size, n, "", 1);
393 return(n); 467 return n;
394 } 468 }
395 469
396 CONFIG_CHUNK(str, size, n, ",", 1); 470 CONFIG_CHUNK(str, size, n, ",", 1);
@@ -399,10 +473,10 @@ static int chan_pair_config_string(struct chan *in, struct chan *out,
399 size -= n; 473 size -= n;
400 CONFIG_CHUNK(str, size, n, "", 1); 474 CONFIG_CHUNK(str, size, n, "", 1);
401 475
402 return(n); 476 return n;
403} 477}
404 478
405int chan_config_string(struct list_head *chans, char *str, int size, 479int chan_config_string(struct list_head *chans, char *str, int size,
406 char **error_out) 480 char **error_out)
407{ 481{
408 struct list_head *ele; 482 struct list_head *ele;
@@ -418,7 +492,7 @@ int chan_config_string(struct list_head *chans, char *str, int size,
418 out = chan; 492 out = chan;
419 } 493 }
420 494
421 return(chan_pair_config_string(in, out, str, size, error_out)); 495 return chan_pair_config_string(in, out, str, size, error_out);
422} 496}
423 497
424struct chan_type { 498struct chan_type {
@@ -462,7 +536,7 @@ struct chan_type chan_table[] = {
462#endif 536#endif
463}; 537};
464 538
465static struct chan *parse_chan(char *str, int pri, int device, 539static struct chan *parse_chan(struct line *line, char *str, int device,
466 struct chan_opts *opts) 540 struct chan_opts *opts)
467{ 541{
468 struct chan_type *entry; 542 struct chan_type *entry;
@@ -484,36 +558,42 @@ static struct chan *parse_chan(char *str, int pri, int device,
484 if(ops == NULL){ 558 if(ops == NULL){
485 my_printf("parse_chan couldn't parse \"%s\"\n", 559 my_printf("parse_chan couldn't parse \"%s\"\n",
486 str); 560 str);
487 return(NULL); 561 return NULL;
488 } 562 }
489 if(ops->init == NULL) return(NULL); 563 if(ops->init == NULL)
564 return NULL;
490 data = (*ops->init)(str, device, opts); 565 data = (*ops->init)(str, device, opts);
491 if(data == NULL) return(NULL); 566 if(data == NULL)
567 return NULL;
492 568
493 chan = kmalloc(sizeof(*chan), GFP_ATOMIC); 569 chan = kmalloc(sizeof(*chan), GFP_ATOMIC);
494 if(chan == NULL) return(NULL); 570 if(chan == NULL)
571 return NULL;
495 *chan = ((struct chan) { .list = LIST_HEAD_INIT(chan->list), 572 *chan = ((struct chan) { .list = LIST_HEAD_INIT(chan->list),
573 .free_list =
574 LIST_HEAD_INIT(chan->free_list),
575 .line = line,
496 .primary = 1, 576 .primary = 1,
497 .input = 0, 577 .input = 0,
498 .output = 0, 578 .output = 0,
499 .opened = 0, 579 .opened = 0,
580 .enabled = 0,
500 .fd = -1, 581 .fd = -1,
501 .pri = pri,
502 .ops = ops, 582 .ops = ops,
503 .data = data }); 583 .data = data });
504 return(chan); 584 return chan;
505} 585}
506 586
507int parse_chan_pair(char *str, struct list_head *chans, int pri, int device, 587int parse_chan_pair(char *str, struct line *line, int device,
508 struct chan_opts *opts) 588 struct chan_opts *opts)
509{ 589{
590 struct list_head *chans = &line->chan_list;
510 struct chan *new, *chan; 591 struct chan *new, *chan;
511 char *in, *out; 592 char *in, *out;
512 593
513 if(!list_empty(chans)){ 594 if(!list_empty(chans)){
514 chan = list_entry(chans->next, struct chan, list); 595 chan = list_entry(chans->next, struct chan, list);
515 if(chan->pri >= pri) return(0); 596 free_chan(chans, 0);
516 free_chan(chans);
517 INIT_LIST_HEAD(chans); 597 INIT_LIST_HEAD(chans);
518 } 598 }
519 599
@@ -522,24 +602,30 @@ int parse_chan_pair(char *str, struct list_head *chans, int pri, int device,
522 in = str; 602 in = str;
523 *out = '\0'; 603 *out = '\0';
524 out++; 604 out++;
525 new = parse_chan(in, pri, device, opts); 605 new = parse_chan(line, in, device, opts);
526 if(new == NULL) return(-1); 606 if(new == NULL)
607 return -1;
608
527 new->input = 1; 609 new->input = 1;
528 list_add(&new->list, chans); 610 list_add(&new->list, chans);
529 611
530 new = parse_chan(out, pri, device, opts); 612 new = parse_chan(line, out, device, opts);
531 if(new == NULL) return(-1); 613 if(new == NULL)
614 return -1;
615
532 list_add(&new->list, chans); 616 list_add(&new->list, chans);
533 new->output = 1; 617 new->output = 1;
534 } 618 }
535 else { 619 else {
536 new = parse_chan(str, pri, device, opts); 620 new = parse_chan(line, str, device, opts);
537 if(new == NULL) return(-1); 621 if(new == NULL)
622 return -1;
623
538 list_add(&new->list, chans); 624 list_add(&new->list, chans);
539 new->input = 1; 625 new->input = 1;
540 new->output = 1; 626 new->output = 1;
541 } 627 }
542 return(0); 628 return 0;
543} 629}
544 630
545int chan_out_fd(struct list_head *chans) 631int chan_out_fd(struct list_head *chans)
@@ -550,9 +636,9 @@ int chan_out_fd(struct list_head *chans)
550 list_for_each(ele, chans){ 636 list_for_each(ele, chans){
551 chan = list_entry(ele, struct chan, list); 637 chan = list_entry(ele, struct chan, list);
552 if(chan->primary && chan->output) 638 if(chan->primary && chan->output)
553 return(chan->fd); 639 return chan->fd;
554 } 640 }
555 return(-1); 641 return -1;
556} 642}
557 643
558void chan_interrupt(struct list_head *chans, struct work_struct *task, 644void chan_interrupt(struct list_head *chans, struct work_struct *task,
@@ -567,9 +653,9 @@ void chan_interrupt(struct list_head *chans, struct work_struct *task,
567 chan = list_entry(ele, struct chan, list); 653 chan = list_entry(ele, struct chan, list);
568 if(!chan->input || (chan->ops->read == NULL)) continue; 654 if(!chan->input || (chan->ops->read == NULL)) continue;
569 do { 655 do {
570 if((tty != NULL) && 656 if((tty != NULL) &&
571 (tty->flip.count >= TTY_FLIPBUF_SIZE)){ 657 (tty->flip.count >= TTY_FLIPBUF_SIZE)){
572 schedule_work(task); 658 schedule_delayed_work(task, 1);
573 goto out; 659 goto out;
574 } 660 }
575 err = chan->ops->read(chan->fd, &c, chan->data); 661 err = chan->ops->read(chan->fd, &c, chan->data);
@@ -582,29 +668,12 @@ void chan_interrupt(struct list_head *chans, struct work_struct *task,
582 if(chan->primary){ 668 if(chan->primary){
583 if(tty != NULL) 669 if(tty != NULL)
584 tty_hangup(tty); 670 tty_hangup(tty);
585 line_disable(tty, irq); 671 close_chan(chans, 1);
586 close_chan(chans);
587 free_chan(chans);
588 return; 672 return;
589 } 673 }
590 else { 674 else close_one_chan(chan, 1);
591 if(chan->ops->close != NULL)
592 chan->ops->close(chan->fd, chan->data);
593 free_one_chan(chan);
594 }
595 } 675 }
596 } 676 }
597 out: 677 out:
598 if(tty) tty_flip_buffer_push(tty); 678 if(tty) tty_flip_buffer_push(tty);
599} 679}
600
601/*
602 * Overrides for Emacs so that we follow Linus's tabbing style.
603 * Emacs will notice this stuff at the end of the file and automatically
604 * adjust the settings for this buffer only. This must remain at the end
605 * of the file.
606 * ---------------------------------------------------------------------------
607 * Local variables:
608 * c-file-style: "linux"
609 * End:
610 */