Linux-2.6.12-rc2
[linux-flexiantxendom0-natty.git] / drivers / s390 / char / tty3270.c
1 /*
2  *  drivers/s390/char/tty3270.c
3  *    IBM/3270 Driver - tty functions.
4  *
5  *  Author(s):
6  *    Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
7  *    Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com>
8  *      -- Copyright (C) 2003 IBM Deutschland Entwicklung GmbH, IBM Corporation
9  */
10
11 #include <linux/config.h>
12 #include <linux/module.h>
13 #include <linux/types.h>
14 #include <linux/kdev_t.h>
15 #include <linux/tty.h>
16 #include <linux/vt_kern.h>
17 #include <linux/init.h>
18 #include <linux/console.h>
19 #include <linux/interrupt.h>
20
21 #include <linux/slab.h>
22 #include <linux/bootmem.h>
23
24 #include <asm/ccwdev.h>
25 #include <asm/cio.h>
26 #include <asm/ebcdic.h>
27 #include <asm/uaccess.h>
28
29
30 #include "raw3270.h"
31 #include "keyboard.h"
32
33 #define TTY3270_CHAR_BUF_SIZE 256
34 #define TTY3270_OUTPUT_BUFFER_SIZE 1024
35 #define TTY3270_STRING_PAGES 5
36
37 struct tty_driver *tty3270_driver;
38 static int tty3270_max_index;
39
40 struct raw3270_fn tty3270_fn;
41
42 struct tty3270_cell {
43         unsigned char character;
44         unsigned char highlight;
45         unsigned char f_color;
46 };
47
48 struct tty3270_line {
49         struct tty3270_cell *cells;
50         int len;
51 };
52
53 #define ESCAPE_NPAR 8
54
55 /*
56  * The main tty view data structure.
57  * FIXME:
58  * 1) describe line orientation & lines list concept against screen
59  * 2) describe conversion of screen to lines
60  * 3) describe line format.
61  */
62 struct tty3270 {
63         struct raw3270_view view;
64         struct tty_struct *tty;         /* Pointer to tty structure */
65         void **freemem_pages;           /* Array of pages used for freemem. */
66         struct list_head freemem;       /* List of free memory for strings. */
67
68         /* Output stuff. */
69         struct list_head lines;         /* List of lines. */
70         struct list_head update;        /* List of lines to update. */
71         unsigned char wcc;              /* Write control character. */
72         int nr_lines;                   /* # lines in list. */
73         int nr_up;                      /* # lines up in history. */
74         unsigned long update_flags;     /* Update indication bits. */
75         struct string *status;          /* Lower right of display. */
76         struct raw3270_request *write;  /* Single write request. */
77         struct timer_list timer;        /* Output delay timer. */
78
79         /* Current tty screen. */
80         unsigned int cx, cy;            /* Current output position. */
81         unsigned int highlight;         /* Blink/reverse/underscore */
82         unsigned int f_color;           /* Foreground color */
83         struct tty3270_line *screen;
84
85         /* Input stuff. */
86         struct string *prompt;          /* Output string for input area. */
87         struct string *input;           /* Input string for read request. */
88         struct raw3270_request *read;   /* Single read request. */
89         struct raw3270_request *kreset; /* Single keyboard reset request. */
90         unsigned char inattr;           /* Visible/invisible input. */
91         int throttle, attn;             /* tty throttle/unthrottle. */
92         struct tasklet_struct readlet;  /* Tasklet to issue read request. */
93         struct kbd_data *kbd;           /* key_maps stuff. */
94
95         /* Escape sequence parsing. */
96         int esc_state, esc_ques, esc_npar;
97         int esc_par[ESCAPE_NPAR];
98         unsigned int saved_cx, saved_cy;
99         unsigned int saved_highlight, saved_f_color;
100
101         /* Command recalling. */
102         struct list_head rcl_lines;     /* List of recallable lines. */
103         struct list_head *rcl_walk;     /* Point in rcl_lines list. */
104         int rcl_nr, rcl_max;            /* Number/max number of rcl_lines. */
105
106         /* Character array for put_char/flush_chars. */
107         unsigned int char_count;
108         char char_buf[TTY3270_CHAR_BUF_SIZE];
109 };
110
111 /* tty3270->update_flags. See tty3270_update for details. */
112 #define TTY_UPDATE_ERASE        1       /* Use EWRITEA instead of WRITE. */
113 #define TTY_UPDATE_LIST         2       /* Update lines in tty3270->update. */
114 #define TTY_UPDATE_INPUT        4       /* Update input line. */
115 #define TTY_UPDATE_STATUS       8       /* Update status line. */
116 #define TTY_UPDATE_ALL          15
117
118 static void tty3270_update(struct tty3270 *);
119
120 /*
121  * Setup timeout for a device. On timeout trigger an update.
122  */
123 void
124 tty3270_set_timer(struct tty3270 *tp, int expires)
125 {
126         if (expires == 0) {
127                 if (timer_pending(&tp->timer) && del_timer(&tp->timer))
128                         raw3270_put_view(&tp->view);
129                 return;
130         }
131         if (timer_pending(&tp->timer) &&
132             mod_timer(&tp->timer, jiffies + expires))
133                 return;
134         raw3270_get_view(&tp->view);
135         tp->timer.function = (void (*)(unsigned long)) tty3270_update;
136         tp->timer.data = (unsigned long) tp;
137         tp->timer.expires = jiffies + expires;
138         add_timer(&tp->timer);
139 }
140
141 /*
142  * The input line are the two last lines of the screen.
143  */
144 static void
145 tty3270_update_prompt(struct tty3270 *tp, char *input, int count)
146 {
147         struct string *line;
148         unsigned int off;
149
150         line = tp->prompt;
151         if (count != 0)
152                 line->string[5] = TF_INMDT;
153         else
154                 line->string[5] = tp->inattr;
155         if (count > tp->view.cols * 2 - 11)
156                 count = tp->view.cols * 2 - 11;
157         memcpy(line->string + 6, input, count);
158         line->string[6 + count] = TO_IC;
159         /* Clear to end of input line. */
160         if (count < tp->view.cols * 2 - 11) {
161                 line->string[7 + count] = TO_RA;
162                 line->string[10 + count] = 0;
163                 off = tp->view.cols * tp->view.rows - 9;
164                 raw3270_buffer_address(tp->view.dev, line->string+count+8, off);
165                 line->len = 11 + count;
166         } else
167                 line->len = 7 + count;
168         tp->update_flags |= TTY_UPDATE_INPUT;
169 }
170
171 static void
172 tty3270_create_prompt(struct tty3270 *tp)
173 {
174         static const unsigned char blueprint[] =
175                 { TO_SBA, 0, 0, 0x6e, TO_SF, TF_INPUT,
176                   /* empty input string */
177                   TO_IC, TO_RA, 0, 0, 0 };
178         struct string *line;
179         unsigned int offset;
180
181         line = alloc_string(&tp->freemem,
182                             sizeof(blueprint) + tp->view.cols * 2 - 9);
183         tp->prompt = line;
184         tp->inattr = TF_INPUT;
185         /* Copy blueprint to status line */
186         memcpy(line->string, blueprint, sizeof(blueprint));
187         line->len = sizeof(blueprint);
188         /* Set output offsets. */
189         offset = tp->view.cols * (tp->view.rows - 2);
190         raw3270_buffer_address(tp->view.dev, line->string + 1, offset);
191         offset = tp->view.cols * tp->view.rows - 9;
192         raw3270_buffer_address(tp->view.dev, line->string + 8, offset);
193
194         /* Allocate input string for reading. */
195         tp->input = alloc_string(&tp->freemem, tp->view.cols * 2 - 9 + 6);
196 }
197
198 /*
199  * The status line is the last line of the screen. It shows the string
200  * "Running"/"Holding" in the lower right corner of the screen.
201  */
202 static void
203 tty3270_update_status(struct tty3270 * tp)
204 {
205         char *str;
206
207         str = (tp->nr_up != 0) ? "History" : "Running";
208         memcpy(tp->status->string + 8, str, 7);
209         codepage_convert(tp->view.ascebc, tp->status->string + 8, 7);
210         tp->update_flags |= TTY_UPDATE_STATUS;
211 }
212
213 static void
214 tty3270_create_status(struct tty3270 * tp)
215 {
216         static const unsigned char blueprint[] =
217                 { TO_SBA, 0, 0, TO_SF, TF_LOG, TO_SA, TAT_COLOR, TAC_GREEN,
218                   0, 0, 0, 0, 0, 0, 0, TO_SF, TF_LOG, TO_SA, TAT_COLOR,
219                   TAC_RESET };
220         struct string *line;
221         unsigned int offset;
222
223         line = alloc_string(&tp->freemem,sizeof(blueprint));
224         tp->status = line;
225         /* Copy blueprint to status line */
226         memcpy(line->string, blueprint, sizeof(blueprint));
227         /* Set address to start of status string (= last 9 characters). */
228         offset = tp->view.cols * tp->view.rows - 9;
229         raw3270_buffer_address(tp->view.dev, line->string + 1, offset);
230 }
231
232 /*
233  * Set output offsets to 3270 datastream fragment of a tty string.
234  * (TO_SBA offset at the start and TO_RA offset at the end of the string)
235  */
236 static void
237 tty3270_update_string(struct tty3270 *tp, struct string *line, int nr)
238 {
239         unsigned char *cp;
240
241         raw3270_buffer_address(tp->view.dev, line->string + 1,
242                                tp->view.cols * nr);
243         cp = line->string + line->len - 4;
244         if (*cp == TO_RA)
245                 raw3270_buffer_address(tp->view.dev, cp + 1,
246                                        tp->view.cols * (nr + 1));
247 }
248
249 /*
250  * Rebuild update list to print all lines.
251  */
252 static void
253 tty3270_rebuild_update(struct tty3270 *tp)
254 {
255         struct string *s, *n;
256         int line, nr_up;
257
258         /* 
259          * Throw away update list and create a new one,
260          * containing all lines that will fit on the screen.
261          */
262         list_for_each_entry_safe(s, n, &tp->update, update)
263                 list_del_init(&s->update);
264         line = tp->view.rows - 3;
265         nr_up = tp->nr_up;
266         list_for_each_entry_reverse(s, &tp->lines, list) {
267                 if (nr_up > 0) {
268                         nr_up--;
269                         continue;
270                 }
271                 tty3270_update_string(tp, s, line);
272                 list_add(&s->update, &tp->update);
273                 if (--line < 0)
274                         break;
275         }
276         tp->update_flags |= TTY_UPDATE_LIST;
277 }
278
279 /*
280  * Alloc string for size bytes. If there is not enough room in
281  * freemem, free strings until there is room.
282  */
283 static struct string *
284 tty3270_alloc_string(struct tty3270 *tp, size_t size)
285 {
286         struct string *s, *n;
287
288         s = alloc_string(&tp->freemem, size);
289         if (s)
290                 return s;
291         list_for_each_entry_safe(s, n, &tp->lines, list) {
292                 BUG_ON(tp->nr_lines <= tp->view.rows - 2);
293                 list_del(&s->list);
294                 if (!list_empty(&s->update))
295                         list_del(&s->update);
296                 tp->nr_lines--;
297                 if (free_string(&tp->freemem, s) >= size)
298                         break;
299         }
300         s = alloc_string(&tp->freemem, size);
301         BUG_ON(!s);
302         if (tp->nr_up != 0 &&
303             tp->nr_up + tp->view.rows - 2 >= tp->nr_lines) {
304                 tp->nr_up = tp->nr_lines - tp->view.rows + 2;
305                 tty3270_rebuild_update(tp);
306                 tty3270_update_status(tp);
307         }
308         return s;
309 }
310
311 /*
312  * Add an empty line to the list.
313  */
314 static void
315 tty3270_blank_line(struct tty3270 *tp)
316 {
317         static const unsigned char blueprint[] =
318                 { TO_SBA, 0, 0, TO_SA, TAT_EXTHI, TAX_RESET,
319                   TO_SA, TAT_COLOR, TAC_RESET, TO_RA, 0, 0, 0 };
320         struct string *s;
321
322         s = tty3270_alloc_string(tp, sizeof(blueprint));
323         memcpy(s->string, blueprint, sizeof(blueprint));
324         s->len = sizeof(blueprint);
325         list_add_tail(&s->list, &tp->lines);
326         tp->nr_lines++;
327         if (tp->nr_up != 0)
328                 tp->nr_up++;
329 }
330
331 /*
332  * Write request completion callback.
333  */
334 static void
335 tty3270_write_callback(struct raw3270_request *rq, void *data)
336 {
337         struct tty3270 *tp;
338
339         tp = (struct tty3270 *) rq->view;
340         if (rq->rc != 0) {
341                 /* Write wasn't successfull. Refresh all. */
342                 tty3270_rebuild_update(tp);
343                 tp->update_flags = TTY_UPDATE_ALL;
344                 tty3270_set_timer(tp, 1);
345         }
346         raw3270_request_reset(rq);
347         xchg(&tp->write, rq);
348 }
349
350 /*
351  * Update 3270 display.
352  */
353 static void
354 tty3270_update(struct tty3270 *tp)
355 {
356         static char invalid_sba[2] = { 0xff, 0xff };
357         struct raw3270_request *wrq;
358         unsigned long updated;
359         struct string *s, *n;
360         char *sba, *str;
361         int rc, len;
362
363         wrq = xchg(&tp->write, 0);
364         if (!wrq) {
365                 tty3270_set_timer(tp, 1);
366                 return;
367         }
368
369         spin_lock(&tp->view.lock);
370         updated = 0;
371         if (tp->update_flags & TTY_UPDATE_ERASE) {
372                 /* Use erase write alternate to erase display. */
373                 raw3270_request_set_cmd(wrq, TC_EWRITEA);
374                 updated |= TTY_UPDATE_ERASE;
375         } else
376                 raw3270_request_set_cmd(wrq, TC_WRITE);
377
378         raw3270_request_add_data(wrq, &tp->wcc, 1);
379         tp->wcc = TW_NONE;
380
381         /*
382          * Update status line.
383          */
384         if (tp->update_flags & TTY_UPDATE_STATUS)
385                 if (raw3270_request_add_data(wrq, tp->status->string,
386                                              tp->status->len) == 0)
387                         updated |= TTY_UPDATE_STATUS;
388
389         /*
390          * Write input line.
391          */
392         if (tp->update_flags & TTY_UPDATE_INPUT)
393                 if (raw3270_request_add_data(wrq, tp->prompt->string,
394                                              tp->prompt->len) == 0)
395                         updated |= TTY_UPDATE_INPUT;
396
397         sba = invalid_sba;
398         
399         if (tp->update_flags & TTY_UPDATE_LIST) {
400                 /* Write strings in the update list to the screen. */
401                 list_for_each_entry_safe(s, n, &tp->update, update) {
402                         str = s->string;
403                         len = s->len;
404                         /*
405                          * Skip TO_SBA at the start of the string if the
406                          * last output position matches the start address
407                          * of this line.
408                          */
409                         if (s->string[1] == sba[0] && s->string[2] == sba[1])
410                                 str += 3, len -= 3;
411                         if (raw3270_request_add_data(wrq, str, len) != 0)
412                                 break;
413                         list_del_init(&s->update);
414                         sba = s->string + s->len - 3;
415                 }
416                 if (list_empty(&tp->update))
417                         updated |= TTY_UPDATE_LIST;
418         }
419         wrq->callback = tty3270_write_callback;
420         rc = raw3270_start(&tp->view, wrq);
421         if (rc == 0) {
422                 tp->update_flags &= ~updated;
423                 if (tp->update_flags)
424                         tty3270_set_timer(tp, 1);
425         } else {
426                 raw3270_request_reset(wrq);
427                 xchg(&tp->write, wrq);
428         }
429         spin_unlock(&tp->view.lock);
430         raw3270_put_view(&tp->view);
431 }
432
433 /*
434  * Command recalling.
435  */
436 static void
437 tty3270_rcl_add(struct tty3270 *tp, char *input, int len)
438 {
439         struct string *s;
440
441         tp->rcl_walk = 0;
442         if (len <= 0)
443                 return;
444         if (tp->rcl_nr >= tp->rcl_max) {
445                 s = list_entry(tp->rcl_lines.next, struct string, list);
446                 list_del(&s->list);
447                 free_string(&tp->freemem, s);
448                 tp->rcl_nr--;
449         }
450         s = tty3270_alloc_string(tp, len);
451         memcpy(s->string, input, len);
452         list_add_tail(&s->list, &tp->rcl_lines);
453         tp->rcl_nr++;
454 }
455
456 static void
457 tty3270_rcl_backward(struct kbd_data *kbd)
458 {
459         struct tty3270 *tp;
460         struct string *s;
461
462         tp = kbd->tty->driver_data;
463         spin_lock_bh(&tp->view.lock);
464         if (tp->inattr == TF_INPUT) {
465                 if (tp->rcl_walk && tp->rcl_walk->prev != &tp->rcl_lines)
466                         tp->rcl_walk = tp->rcl_walk->prev;
467                 else if (!list_empty(&tp->rcl_lines))
468                         tp->rcl_walk = tp->rcl_lines.prev;
469                 s = tp->rcl_walk ? 
470                         list_entry(tp->rcl_walk, struct string, list) : 0;
471                 if (tp->rcl_walk) {
472                         s = list_entry(tp->rcl_walk, struct string, list);
473                         tty3270_update_prompt(tp, s->string, s->len);
474                 } else
475                         tty3270_update_prompt(tp, 0, 0);
476                 tty3270_set_timer(tp, 1);
477         }
478         spin_unlock_bh(&tp->view.lock);
479 }
480
481 /*
482  * Deactivate tty view.
483  */
484 static void
485 tty3270_exit_tty(struct kbd_data *kbd)
486 {
487         struct tty3270 *tp;
488
489         tp = kbd->tty->driver_data;
490         raw3270_deactivate_view(&tp->view);
491 }
492
493 /*
494  * Scroll forward in history.
495  */
496 static void
497 tty3270_scroll_forward(struct kbd_data *kbd)
498 {
499         struct tty3270 *tp;
500         int nr_up;
501
502         tp = kbd->tty->driver_data;
503         spin_lock_bh(&tp->view.lock);
504         nr_up = tp->nr_up - tp->view.rows + 2;
505         if (nr_up < 0)
506                 nr_up = 0;
507         if (nr_up != tp->nr_up) {
508                 tp->nr_up = nr_up;
509                 tty3270_rebuild_update(tp);
510                 tty3270_update_status(tp);
511                 tty3270_set_timer(tp, 1);
512         }
513         spin_unlock_bh(&tp->view.lock);
514 }
515
516 /*
517  * Scroll backward in history.
518  */
519 static void
520 tty3270_scroll_backward(struct kbd_data *kbd)
521 {
522         struct tty3270 *tp;
523         int nr_up;
524
525         tp = kbd->tty->driver_data;
526         spin_lock_bh(&tp->view.lock);
527         nr_up = tp->nr_up + tp->view.rows - 2;
528         if (nr_up + tp->view.rows - 2 > tp->nr_lines)
529                 nr_up = tp->nr_lines - tp->view.rows + 2;
530         if (nr_up != tp->nr_up) {
531                 tp->nr_up = nr_up;
532                 tty3270_rebuild_update(tp);
533                 tty3270_update_status(tp);
534                 tty3270_set_timer(tp, 1);
535         }
536         spin_unlock_bh(&tp->view.lock);
537 }
538
539 /*
540  * Pass input line to tty.
541  */
542 static void
543 tty3270_read_tasklet(struct raw3270_request *rrq)
544 {
545         static char kreset_data = TW_KR;
546         struct tty3270 *tp;
547         char *input;
548         int len;
549
550         tp = (struct tty3270 *) rrq->view;
551         spin_lock_bh(&tp->view.lock);
552         /*
553          * Two AID keys are special: For 0x7d (enter) the input line
554          * has to be emitted to the tty and for 0x6d the screen
555          * needs to be redrawn.
556          */
557         input = 0;
558         len = 0;
559         if (tp->input->string[0] == 0x7d) {
560                 /* Enter: write input to tty. */
561                 input = tp->input->string + 6;
562                 len = tp->input->len - 6 - rrq->rescnt;
563                 if (tp->inattr != TF_INPUTN)
564                         tty3270_rcl_add(tp, input, len);
565                 if (tp->nr_up > 0) {
566                         tp->nr_up = 0;
567                         tty3270_rebuild_update(tp);
568                         tty3270_update_status(tp);
569                 }
570                 /* Clear input area. */
571                 tty3270_update_prompt(tp, 0, 0);
572                 tty3270_set_timer(tp, 1);
573         } else if (tp->input->string[0] == 0x6d) {
574                 /* Display has been cleared. Redraw. */
575                 tty3270_rebuild_update(tp);
576                 tp->update_flags = TTY_UPDATE_ALL;
577                 tty3270_set_timer(tp, 1);
578         }
579         spin_unlock_bh(&tp->view.lock);
580
581         /* Start keyboard reset command. */
582         raw3270_request_reset(tp->kreset);
583         raw3270_request_set_cmd(tp->kreset, TC_WRITE);
584         raw3270_request_add_data(tp->kreset, &kreset_data, 1);
585         raw3270_start(&tp->view, tp->kreset);
586
587         /* Emit input string. */
588         if (tp->tty) {
589                 while (len-- > 0)
590                         kbd_keycode(tp->kbd, *input++);
591                 /* Emit keycode for AID byte. */
592                 kbd_keycode(tp->kbd, 256 + tp->input->string[0]);
593         }
594
595         raw3270_request_reset(rrq);
596         xchg(&tp->read, rrq);
597         raw3270_put_view(&tp->view);
598 }
599
600 /*
601  * Read request completion callback.
602  */
603 static void
604 tty3270_read_callback(struct raw3270_request *rq, void *data)
605 {
606         raw3270_get_view(rq->view);
607         /* Schedule tasklet to pass input to tty. */
608         tasklet_schedule(&((struct tty3270 *) rq->view)->readlet);
609 }
610
611 /*
612  * Issue a read request. Call with device lock.
613  */
614 static void
615 tty3270_issue_read(struct tty3270 *tp, int lock)
616 {
617         struct raw3270_request *rrq;
618         int rc;
619
620         rrq = xchg(&tp->read, 0);
621         if (!rrq)
622                 /* Read already scheduled. */
623                 return;
624         rrq->callback = tty3270_read_callback;
625         rrq->callback_data = tp;
626         raw3270_request_set_cmd(rrq, TC_READMOD);
627         raw3270_request_set_data(rrq, tp->input->string, tp->input->len);
628         /* Issue the read modified request. */
629         if (lock) {
630                 rc = raw3270_start(&tp->view, rrq);
631         } else
632                 rc = raw3270_start_irq(&tp->view, rrq);
633         if (rc) {
634                 raw3270_request_reset(rrq);
635                 xchg(&tp->read, rrq);
636         }
637 }
638
639 /*
640  * Switch to the tty view.
641  */
642 static int
643 tty3270_activate(struct raw3270_view *view)
644 {
645         struct tty3270 *tp;
646         unsigned long flags;
647
648         tp = (struct tty3270 *) view;
649         spin_lock_irqsave(&tp->view.lock, flags);
650         tp->nr_up = 0;
651         tty3270_rebuild_update(tp);
652         tty3270_update_status(tp);
653         tp->update_flags = TTY_UPDATE_ALL;
654         tty3270_set_timer(tp, 1);
655         spin_unlock_irqrestore(&tp->view.lock, flags);
656         start_tty(tp->tty);
657         return 0;
658 }
659
660 static void
661 tty3270_deactivate(struct raw3270_view *view)
662 {
663         struct tty3270 *tp;
664
665         tp = (struct tty3270 *) view;
666         if (tp && tp->tty)
667                 stop_tty(tp->tty);
668 }
669
670 static int
671 tty3270_irq(struct tty3270 *tp, struct raw3270_request *rq, struct irb *irb)
672 {
673         /* Handle ATTN. Schedule tasklet to read aid. */
674         if (irb->scsw.dstat & DEV_STAT_ATTENTION) {
675                 if (!tp->throttle)
676                         tty3270_issue_read(tp, 0);
677                 else
678                         tp->attn = 1;
679         }
680
681         if (rq) {
682                 if (irb->scsw.dstat & DEV_STAT_UNIT_CHECK)
683                         rq->rc = -EIO;
684                 else
685                         /* Normal end. Copy residual count. */
686                         rq->rescnt = irb->scsw.count;
687         }
688         return RAW3270_IO_DONE;
689 }
690
691 /*
692  * Allocate tty3270 structure.
693  */
694 static struct tty3270 *
695 tty3270_alloc_view(void)
696 {
697         struct tty3270 *tp;
698         int pages;
699
700         tp = kmalloc(sizeof(struct tty3270),GFP_KERNEL);
701         if (!tp)
702                 goto out_err;
703         memset(tp, 0, sizeof(struct tty3270));
704         tp->freemem_pages =
705                 kmalloc(sizeof(void *) * TTY3270_STRING_PAGES, GFP_KERNEL);
706         if (!tp->freemem_pages)
707                 goto out_tp;
708         INIT_LIST_HEAD(&tp->freemem);
709         init_timer(&tp->timer);
710         for (pages = 0; pages < TTY3270_STRING_PAGES; pages++) {
711                 tp->freemem_pages[pages] = (void *)
712                         __get_free_pages(GFP_KERNEL|GFP_DMA, 0);
713                 if (!tp->freemem_pages[pages])
714                         goto out_pages;
715                 add_string_memory(&tp->freemem,
716                                   tp->freemem_pages[pages], PAGE_SIZE);
717         }
718         tp->write = raw3270_request_alloc(TTY3270_OUTPUT_BUFFER_SIZE);
719         if (!tp->write)
720                 goto out_pages;
721         tp->read = raw3270_request_alloc(0);
722         if (!tp->read)
723                 goto out_write;
724         tp->kreset = raw3270_request_alloc(1);
725         if (!tp->kreset)
726                 goto out_read;
727         tp->kbd = kbd_alloc();
728         if (!tp->kbd)
729                 goto out_reset;
730         return tp;
731
732 out_reset:
733         raw3270_request_free(tp->kreset);
734 out_read:
735         raw3270_request_free(tp->read);
736 out_write:
737         raw3270_request_free(tp->write);
738 out_pages:
739         while (pages--)
740                 free_pages((unsigned long) tp->freemem_pages[pages], 0);
741         kfree(tp->freemem_pages);
742 out_tp:
743         kfree(tp);
744 out_err:
745         return ERR_PTR(-ENOMEM);
746 }
747
748 /*
749  * Free tty3270 structure.
750  */
751 static void
752 tty3270_free_view(struct tty3270 *tp)
753 {
754         int pages;
755
756         kbd_free(tp->kbd);
757         raw3270_request_free(tp->kreset);
758         raw3270_request_free(tp->read);
759         raw3270_request_free(tp->write);
760         for (pages = 0; pages < TTY3270_STRING_PAGES; pages++)
761                 free_pages((unsigned long) tp->freemem_pages[pages], 0);
762         kfree(tp->freemem_pages);
763         kfree(tp);
764 }
765
766 /*
767  * Allocate tty3270 screen.
768  */
769 static int
770 tty3270_alloc_screen(struct tty3270 *tp)
771 {
772         unsigned long size;
773         int lines;
774
775         size = sizeof(struct tty3270_line) * (tp->view.rows - 2);
776         tp->screen = kmalloc(size, GFP_KERNEL);
777         if (!tp->screen)
778                 goto out_err;
779         memset(tp->screen, 0, size);
780         for (lines = 0; lines < tp->view.rows - 2; lines++) {
781                 size = sizeof(struct tty3270_cell) * tp->view.cols;
782                 tp->screen[lines].cells = kmalloc(size, GFP_KERNEL);
783                 if (!tp->screen[lines].cells)
784                         goto out_screen;
785                 memset(tp->screen[lines].cells, 0, size);
786         }
787         return 0;
788 out_screen:
789         while (lines--)
790                 kfree(tp->screen[lines].cells);
791         kfree(tp->screen);
792 out_err:
793         return -ENOMEM;
794 }
795
796 /*
797  * Free tty3270 screen.
798  */
799 static void
800 tty3270_free_screen(struct tty3270 *tp)
801 {
802         int lines;
803
804         for (lines = 0; lines < tp->view.rows - 2; lines++)
805                 kfree(tp->screen[lines].cells);
806         kfree(tp->screen);
807 }
808
809 /*
810  * Unlink tty3270 data structure from tty.
811  */
812 static void
813 tty3270_release(struct raw3270_view *view)
814 {
815         struct tty3270 *tp;
816         struct tty_struct *tty;
817
818         tp = (struct tty3270 *) view;
819         tty = tp->tty;
820         if (tty) {
821                 tty->driver_data = 0;
822                 tp->tty = tp->kbd->tty = 0;
823                 tty_hangup(tty);
824                 raw3270_put_view(&tp->view);
825         }
826 }
827
828 /*
829  * Free tty3270 data structure
830  */
831 static void
832 tty3270_free(struct raw3270_view *view)
833 {
834         tty3270_free_screen((struct tty3270 *) view);
835         tty3270_free_view((struct tty3270 *) view);
836 }
837
838 /*
839  * Delayed freeing of tty3270 views.
840  */
841 static void
842 tty3270_del_views(void)
843 {
844         struct tty3270 *tp;
845         int i;
846
847         for (i = 0; i < tty3270_max_index; i++) {
848                 tp = (struct tty3270 *) raw3270_find_view(&tty3270_fn, i);
849                 if (!IS_ERR(tp))
850                         raw3270_del_view(&tp->view);
851         }
852 }
853
854 struct raw3270_fn tty3270_fn = {
855         .activate = tty3270_activate,
856         .deactivate = tty3270_deactivate,
857         .intv = (void *) tty3270_irq,
858         .release = tty3270_release,
859         .free = tty3270_free
860 };
861
862 /*
863  * This routine is called whenever a 3270 tty is opened.
864  */
865 static int
866 tty3270_open(struct tty_struct *tty, struct file * filp)
867 {
868         struct tty3270 *tp;
869         int i, rc;
870
871         if (tty->count > 1)
872                 return 0;
873         /* Check if the tty3270 is already there. */
874         tp = (struct tty3270 *) raw3270_find_view(&tty3270_fn, tty->index);
875         if (!IS_ERR(tp)) {
876                 tty->driver_data = tp;
877                 tty->winsize.ws_row = tp->view.rows - 2;
878                 tty->winsize.ws_col = tp->view.cols;
879                 tty->low_latency = 0;
880                 tp->tty = tty;
881                 tp->kbd->tty = tty;
882                 tp->inattr = TF_INPUT;
883                 return 0;
884         }
885         if (tty3270_max_index < tty->index + 1)
886                 tty3270_max_index = tty->index + 1;
887
888         /* Quick exit if there is no device for tty->index. */
889         if (PTR_ERR(tp) == -ENODEV)
890                 return -ENODEV;
891
892         /* Allocate tty3270 structure on first open. */
893         tp = tty3270_alloc_view();
894         if (IS_ERR(tp))
895                 return PTR_ERR(tp);
896
897         INIT_LIST_HEAD(&tp->lines);
898         INIT_LIST_HEAD(&tp->update);
899         INIT_LIST_HEAD(&tp->rcl_lines);
900         tp->rcl_max = 20;
901         init_timer(&tp->timer);
902         tasklet_init(&tp->readlet, 
903                      (void (*)(unsigned long)) tty3270_read_tasklet,
904                      (unsigned long) tp->read);
905
906         rc = raw3270_add_view(&tp->view, &tty3270_fn, tty->index);
907         if (rc) {
908                 tty3270_free_view(tp);
909                 return rc;
910         }
911
912         rc = tty3270_alloc_screen(tp);
913         if (rc) {
914                 raw3270_del_view(&tp->view);
915                 raw3270_put_view(&tp->view);
916                 return rc;
917         }
918
919         tp->tty = tty;
920         tty->low_latency = 0;
921         tty->driver_data = tp;
922         tty->winsize.ws_row = tp->view.rows - 2;
923         tty->winsize.ws_col = tp->view.cols;
924
925         tty3270_create_prompt(tp);
926         tty3270_create_status(tp);
927         tty3270_update_status(tp);
928
929         /* Create blank line for every line in the tty output area. */
930         for (i = 0; i < tp->view.rows - 2; i++)
931                 tty3270_blank_line(tp);
932
933         tp->kbd->tty = tty;
934         tp->kbd->fn_handler[KVAL(K_INCRCONSOLE)] = tty3270_exit_tty;
935         tp->kbd->fn_handler[KVAL(K_SCROLLBACK)] = tty3270_scroll_backward;
936         tp->kbd->fn_handler[KVAL(K_SCROLLFORW)] = tty3270_scroll_forward;
937         tp->kbd->fn_handler[KVAL(K_CONS)] = tty3270_rcl_backward;
938         kbd_ascebc(tp->kbd, tp->view.ascebc);
939
940         raw3270_activate_view(&tp->view);
941         return 0;
942 }
943
944 /*
945  * This routine is called when the 3270 tty is closed. We wait
946  * for the remaining request to be completed. Then we clean up.
947  */
948 static void
949 tty3270_close(struct tty_struct *tty, struct file * filp)
950 {
951         struct tty3270 *tp;
952
953         if (tty->count > 1)
954                 return;
955         tp = (struct tty3270 *) tty->driver_data;
956         if (tp) {
957                 tty->driver_data = 0;
958                 tp->tty = tp->kbd->tty = 0;
959                 raw3270_put_view(&tp->view);
960         }
961 }
962
963 /*
964  * We always have room.
965  */
966 static int
967 tty3270_write_room(struct tty_struct *tty)
968 {
969         return INT_MAX;
970 }
971
972 /*
973  * Insert character into the screen at the current position with the
974  * current color and highlight. This function does NOT do cursor movement.
975  */
976 static void
977 tty3270_put_character(struct tty3270 *tp, char ch)
978 {
979         struct tty3270_line *line;
980         struct tty3270_cell *cell;
981
982         line = tp->screen + tp->cy;
983         if (line->len <= tp->cx) {
984                 while (line->len < tp->cx) {
985                         cell = line->cells + line->len;
986                         cell->character = tp->view.ascebc[' '];
987                         cell->highlight = tp->highlight;
988                         cell->f_color = tp->f_color;
989                         line->len++;
990                 }
991                 line->len++;
992         }
993         cell = line->cells + tp->cx;
994         cell->character = tp->view.ascebc[(unsigned int) ch];
995         cell->highlight = tp->highlight;
996         cell->f_color = tp->f_color;
997 }
998
999 /*
1000  * Convert a tty3270_line to a 3270 data fragment usable for output.
1001  */
1002 static void
1003 tty3270_convert_line(struct tty3270 *tp, int line_nr)
1004 {
1005         struct tty3270_line *line;
1006         struct tty3270_cell *cell;
1007         struct string *s, *n;
1008         unsigned char highlight;
1009         unsigned char f_color;
1010         char *cp;
1011         int flen, i;
1012
1013         /* Determine how long the fragment will be. */
1014         flen = 3;               /* Prefix (TO_SBA). */
1015         line = tp->screen + line_nr;
1016         flen += line->len;
1017         highlight = TAX_RESET;
1018         f_color = TAC_RESET;
1019         for (i = 0, cell = line->cells; i < line->len; i++, cell++) {
1020                 if (cell->highlight != highlight) {
1021                         flen += 3;      /* TO_SA to switch highlight. */
1022                         highlight = cell->highlight;
1023                 }
1024                 if (cell->f_color != f_color) {
1025                         flen += 3;      /* TO_SA to switch color. */
1026                         f_color = cell->f_color;
1027                 }
1028         }
1029         if (highlight != TAX_RESET)
1030                 flen += 3;      /* TO_SA to reset hightlight. */
1031         if (f_color != TAC_RESET)
1032                 flen += 3;      /* TO_SA to reset color. */
1033         if (line->len < tp->view.cols)
1034                 flen += 4;      /* Postfix (TO_RA). */
1035
1036         /* Find the line in the list. */
1037         i = tp->view.rows - 2 - line_nr;
1038         list_for_each_entry_reverse(s, &tp->lines, list)
1039                 if (--i <= 0)
1040                         break;
1041         /*
1042          * Check if the line needs to get reallocated.
1043          */
1044         if (s->len != flen) {
1045                 /* Reallocate string. */
1046                 n = tty3270_alloc_string(tp, flen);
1047                 list_add(&n->list, &s->list);
1048                 list_del_init(&s->list);
1049                 if (!list_empty(&s->update))
1050                         list_del_init(&s->update);
1051                 free_string(&tp->freemem, s);
1052                 s = n;
1053         }
1054
1055         /* Write 3270 data fragment. */
1056         cp = s->string;
1057         *cp++ = TO_SBA;
1058         *cp++ = 0;
1059         *cp++ = 0;
1060
1061         highlight = TAX_RESET;
1062         f_color = TAC_RESET;
1063         for (i = 0, cell = line->cells; i < line->len; i++, cell++) {
1064                 if (cell->highlight != highlight) {
1065                         *cp++ = TO_SA;
1066                         *cp++ = TAT_EXTHI;
1067                         *cp++ = cell->highlight;
1068                         highlight = cell->highlight;
1069                 }
1070                 if (cell->f_color != f_color) {
1071                         *cp++ = TO_SA;
1072                         *cp++ = TAT_COLOR;
1073                         *cp++ = cell->f_color;
1074                         f_color = cell->f_color;
1075                 }
1076                 *cp++ = cell->character;
1077         }
1078         if (highlight != TAX_RESET) {
1079                 *cp++ = TO_SA;
1080                 *cp++ = TAT_EXTHI;
1081                 *cp++ = TAX_RESET;
1082         }
1083         if (f_color != TAC_RESET) {
1084                 *cp++ = TO_SA;
1085                 *cp++ = TAT_COLOR;
1086                 *cp++ = TAC_RESET;
1087         }
1088         if (line->len < tp->view.cols) {
1089                 *cp++ = TO_RA;
1090                 *cp++ = 0;
1091                 *cp++ = 0;
1092                 *cp++ = 0;
1093         }
1094
1095         if (tp->nr_up + line_nr < tp->view.rows - 2) {
1096                 /* Line is currently visible on screen. */
1097                 tty3270_update_string(tp, s, line_nr);
1098                 /* Add line to update list. */
1099                 if (list_empty(&s->update)) {
1100                         list_add_tail(&s->update, &tp->update);
1101                         tp->update_flags |= TTY_UPDATE_LIST;
1102                 }
1103         }
1104 }
1105
1106 /*
1107  * Do carriage return.
1108  */
1109 static void
1110 tty3270_cr(struct tty3270 *tp)
1111 {
1112         tp->cx = 0;
1113 }
1114
1115 /*
1116  * Do line feed.
1117  */
1118 static void
1119 tty3270_lf(struct tty3270 *tp)
1120 {
1121         struct tty3270_line temp;
1122         int i;
1123
1124         tty3270_convert_line(tp, tp->cy);
1125         if (tp->cy < tp->view.rows - 3) {
1126                 tp->cy++;
1127                 return;
1128         }
1129         /* Last line just filled up. Add new, blank line. */
1130         tty3270_blank_line(tp);
1131         temp = tp->screen[0];
1132         temp.len = 0;
1133         for (i = 0; i < tp->view.rows - 3; i++)
1134                 tp->screen[i] = tp->screen[i+1];
1135         tp->screen[tp->view.rows - 3] = temp;
1136         tty3270_rebuild_update(tp);
1137 }
1138
1139 static void
1140 tty3270_ri(struct tty3270 *tp)
1141 {
1142         if (tp->cy > 0) {
1143             tty3270_convert_line(tp, tp->cy);
1144             tp->cy--;
1145         }
1146 }
1147
1148 /*
1149  * Insert characters at current position.
1150  */
1151 static void
1152 tty3270_insert_characters(struct tty3270 *tp, int n)
1153 {
1154         struct tty3270_line *line;
1155         int k;
1156
1157         line = tp->screen + tp->cy;
1158         while (line->len < tp->cx) {
1159                 line->cells[line->len].character = tp->view.ascebc[' '];
1160                 line->cells[line->len].highlight = TAX_RESET;
1161                 line->cells[line->len].f_color = TAC_RESET;
1162                 line->len++;
1163         }
1164         if (n > tp->view.cols - tp->cx)
1165                 n = tp->view.cols - tp->cx;
1166         k = min_t(int, line->len - tp->cx, tp->view.cols - tp->cx - n);
1167         while (k--)
1168                 line->cells[tp->cx + n + k] = line->cells[tp->cx + k];
1169         line->len += n;
1170         if (line->len > tp->view.cols)
1171                 line->len = tp->view.cols;
1172         while (n-- > 0) {
1173                 line->cells[tp->cx + n].character = tp->view.ascebc[' '];
1174                 line->cells[tp->cx + n].highlight = tp->highlight;
1175                 line->cells[tp->cx + n].f_color = tp->f_color;
1176         }
1177 }
1178
1179 /*
1180  * Delete characters at current position.
1181  */
1182 static void
1183 tty3270_delete_characters(struct tty3270 *tp, int n)
1184 {
1185         struct tty3270_line *line;
1186         int i;
1187
1188         line = tp->screen + tp->cy;
1189         if (line->len <= tp->cx)
1190                 return;
1191         if (line->len - tp->cx <= n) {
1192                 line->len = tp->cx;
1193                 return;
1194         }
1195         for (i = tp->cx; i + n < line->len; i++)
1196                 line->cells[i] = line->cells[i + n];
1197         line->len -= n;
1198 }
1199
1200 /*
1201  * Erase characters at current position.
1202  */
1203 static void
1204 tty3270_erase_characters(struct tty3270 *tp, int n)
1205 {
1206         struct tty3270_line *line;
1207         struct tty3270_cell *cell;
1208
1209         line = tp->screen + tp->cy;
1210         while (line->len > tp->cx && n-- > 0) {
1211                 cell = line->cells + tp->cx++;
1212                 cell->character = ' ';
1213                 cell->highlight = TAX_RESET;
1214                 cell->f_color = TAC_RESET;
1215         }
1216         tp->cx += n;
1217         tp->cx = min_t(int, tp->cx, tp->view.cols - 1);
1218 }
1219
1220 /*
1221  * Erase line, 3 different cases:
1222  *  Esc [ 0 K   Erase from current position to end of line inclusive
1223  *  Esc [ 1 K   Erase from beginning of line to current position inclusive
1224  *  Esc [ 2 K   Erase entire line (without moving cursor)
1225  */
1226 static void
1227 tty3270_erase_line(struct tty3270 *tp, int mode)
1228 {
1229         struct tty3270_line *line;
1230         struct tty3270_cell *cell;
1231         int i;
1232
1233         line = tp->screen + tp->cy;
1234         if (mode == 0)
1235                 line->len = tp->cx;
1236         else if (mode == 1) {
1237                 for (i = 0; i < tp->cx; i++) {
1238                         cell = line->cells + i;
1239                         cell->character = ' ';
1240                         cell->highlight = TAX_RESET;
1241                         cell->f_color = TAC_RESET;
1242                 }
1243                 if (line->len <= tp->cx)
1244                         line->len = tp->cx + 1;
1245         } else if (mode == 2)
1246                 line->len = 0;
1247         tty3270_convert_line(tp, tp->cy);
1248 }
1249
1250 /*
1251  * Erase display, 3 different cases:
1252  *  Esc [ 0 J   Erase from current position to bottom of screen inclusive
1253  *  Esc [ 1 J   Erase from top of screen to current position inclusive
1254  *  Esc [ 2 J   Erase entire screen (without moving the cursor)
1255  */
1256 static void
1257 tty3270_erase_display(struct tty3270 *tp, int mode)
1258 {
1259         int i;
1260
1261         if (mode == 0) {
1262                 tty3270_erase_line(tp, 0);
1263                 for (i = tp->cy + 1; i < tp->view.rows - 2; i++) {
1264                         tp->screen[i].len = 0;
1265                         tty3270_convert_line(tp, i);
1266                 }
1267         } else if (mode == 1) {
1268                 for (i = 0; i < tp->cy; i++) {
1269                         tp->screen[i].len = 0;
1270                         tty3270_convert_line(tp, i);
1271                 }
1272                 tty3270_erase_line(tp, 1);
1273         } else if (mode == 2) {
1274                 for (i = 0; i < tp->view.rows - 2; i++) {
1275                         tp->screen[i].len = 0;
1276                         tty3270_convert_line(tp, i);
1277                 }
1278         }
1279         tty3270_rebuild_update(tp);
1280 }
1281
1282 /*
1283  * Set attributes found in an escape sequence.
1284  *  Esc [ <attr> ; <attr> ; ... m
1285  */
1286 static void
1287 tty3270_set_attributes(struct tty3270 *tp)
1288 {
1289         static unsigned char f_colors[] = {
1290                 TAC_DEFAULT, TAC_RED, TAC_GREEN, TAC_YELLOW, TAC_BLUE,
1291                 TAC_PINK, TAC_TURQ, TAC_WHITE, 0, TAC_DEFAULT
1292         };
1293         int i, attr;
1294
1295         for (i = 0; i <= tp->esc_npar; i++) {
1296                 attr = tp->esc_par[i];
1297                 switch (attr) {
1298                 case 0:         /* Reset */
1299                         tp->highlight = TAX_RESET;
1300                         tp->f_color = TAC_RESET;
1301                         break;
1302                 /* Highlight. */
1303                 case 4:         /* Start underlining. */
1304                         tp->highlight = TAX_UNDER;
1305                         break;
1306                 case 5:         /* Start blink. */
1307                         tp->highlight = TAX_BLINK;
1308                         break;
1309                 case 7:         /* Start reverse. */
1310                         tp->highlight = TAX_REVER;
1311                         break;
1312                 case 24:        /* End underlining */
1313                         if (tp->highlight == TAX_UNDER)
1314                                 tp->highlight = TAX_RESET;
1315                         break;
1316                 case 25:        /* End blink. */
1317                         if (tp->highlight == TAX_BLINK)
1318                                 tp->highlight = TAX_RESET;
1319                         break;
1320                 case 27:        /* End reverse. */
1321                         if (tp->highlight == TAX_REVER)
1322                                 tp->highlight = TAX_RESET;
1323                         break;
1324                 /* Foreground color. */
1325                 case 30:        /* Black */
1326                 case 31:        /* Red */
1327                 case 32:        /* Green */
1328                 case 33:        /* Yellow */
1329                 case 34:        /* Blue */
1330                 case 35:        /* Magenta */
1331                 case 36:        /* Cyan */
1332                 case 37:        /* White */
1333                 case 39:        /* Black */
1334                         tp->f_color = f_colors[attr - 30];
1335                         break;
1336                 }
1337         }
1338 }
1339
1340 static inline int
1341 tty3270_getpar(struct tty3270 *tp, int ix)
1342 {
1343         return (tp->esc_par[ix] > 0) ? tp->esc_par[ix] : 1;
1344 }
1345
1346 static void
1347 tty3270_goto_xy(struct tty3270 *tp, int cx, int cy)
1348 {
1349         tp->cx = min_t(int, tp->view.cols - 1, max_t(int, 0, cx));
1350         cy = min_t(int, tp->view.rows - 3, max_t(int, 0, cy));
1351         if (cy != tp->cy) {
1352                 tty3270_convert_line(tp, tp->cy);
1353                 tp->cy = cy;
1354         }
1355 }
1356
1357 /*
1358  * Process escape sequences. Known sequences:
1359  *  Esc 7                       Save Cursor Position
1360  *  Esc 8                       Restore Cursor Position
1361  *  Esc [ Pn ; Pn ; .. m        Set attributes
1362  *  Esc [ Pn ; Pn H             Cursor Position
1363  *  Esc [ Pn ; Pn f             Cursor Position
1364  *  Esc [ Pn A                  Cursor Up
1365  *  Esc [ Pn B                  Cursor Down
1366  *  Esc [ Pn C                  Cursor Forward
1367  *  Esc [ Pn D                  Cursor Backward
1368  *  Esc [ Pn G                  Cursor Horizontal Absolute
1369  *  Esc [ Pn X                  Erase Characters
1370  *  Esc [ Ps J                  Erase in Display
1371  *  Esc [ Ps K                  Erase in Line
1372  * // FIXME: add all the new ones.
1373  *
1374  *  Pn is a numeric parameter, a string of zero or more decimal digits.
1375  *  Ps is a selective parameter.
1376  */
1377 static void
1378 tty3270_escape_sequence(struct tty3270 *tp, char ch)
1379 {
1380         enum { ESnormal, ESesc, ESsquare, ESgetpars };
1381
1382         if (tp->esc_state == ESnormal) {
1383                 if (ch == 0x1b)
1384                         /* Starting new escape sequence. */
1385                         tp->esc_state = ESesc;
1386                 return;
1387         }
1388         if (tp->esc_state == ESesc) {
1389                 tp->esc_state = ESnormal;
1390                 switch (ch) {
1391                 case '[':
1392                         tp->esc_state = ESsquare;
1393                         break;
1394                 case 'E':
1395                         tty3270_cr(tp);
1396                         tty3270_lf(tp);
1397                         break;
1398                 case 'M':
1399                         tty3270_ri(tp);
1400                         break;
1401                 case 'D':
1402                         tty3270_lf(tp);
1403                         break;
1404                 case 'Z':               /* Respond ID. */
1405                         kbd_puts_queue(tp->tty, "\033[?6c");
1406                         break;
1407                 case '7':               /* Save cursor position. */
1408                         tp->saved_cx = tp->cx;
1409                         tp->saved_cy = tp->cy;
1410                         tp->saved_highlight = tp->highlight;
1411                         tp->saved_f_color = tp->f_color;
1412                         break;
1413                 case '8':               /* Restore cursor position. */
1414                         tty3270_convert_line(tp, tp->cy);
1415                         tty3270_goto_xy(tp, tp->saved_cx, tp->saved_cy);
1416                         tp->highlight = tp->saved_highlight;
1417                         tp->f_color = tp->saved_f_color;
1418                         break;
1419                 case 'c':               /* Reset terminal. */
1420                         tp->cx = tp->saved_cx = 0;
1421                         tp->cy = tp->saved_cy = 0;
1422                         tp->highlight = tp->saved_highlight = TAX_RESET;
1423                         tp->f_color = tp->saved_f_color = TAC_RESET;
1424                         tty3270_erase_display(tp, 2);
1425                         break;
1426                 }
1427                 return;
1428         }
1429         if (tp->esc_state == ESsquare) {
1430                 tp->esc_state = ESgetpars;
1431                 memset(tp->esc_par, 0, sizeof(tp->esc_par));
1432                 tp->esc_npar = 0;
1433                 tp->esc_ques = (ch == '?');
1434                 if (tp->esc_ques)
1435                         return;
1436         }
1437         if (tp->esc_state == ESgetpars) {
1438                 if (ch == ';' && tp->esc_npar < ESCAPE_NPAR - 1) {
1439                         tp->esc_npar++;
1440                         return;
1441                 }
1442                 if (ch >= '0' && ch <= '9') {
1443                         tp->esc_par[tp->esc_npar] *= 10;
1444                         tp->esc_par[tp->esc_npar] += ch - '0';
1445                         return;
1446                 }
1447         }
1448         tp->esc_state = ESnormal;
1449         if (ch == 'n' && !tp->esc_ques) {
1450                 if (tp->esc_par[0] == 5)                /* Status report. */
1451                         kbd_puts_queue(tp->tty, "\033[0n");
1452                 else if (tp->esc_par[0] == 6) { /* Cursor report. */
1453                         char buf[40];
1454                         sprintf(buf, "\033[%d;%dR", tp->cy + 1, tp->cx + 1);
1455                         kbd_puts_queue(tp->tty, buf);
1456                 }
1457                 return;
1458         }
1459         if (tp->esc_ques)
1460                 return;
1461         switch (ch) {
1462         case 'm':
1463                 tty3270_set_attributes(tp);
1464                 break;
1465         case 'H':       /* Set cursor position. */
1466         case 'f':
1467                 tty3270_goto_xy(tp, tty3270_getpar(tp, 1) - 1,
1468                                 tty3270_getpar(tp, 0) - 1);
1469                 break;
1470         case 'd':       /* Set y position. */
1471                 tty3270_goto_xy(tp, tp->cx, tty3270_getpar(tp, 0) - 1);
1472                 break;
1473         case 'A':       /* Cursor up. */
1474         case 'F':
1475                 tty3270_goto_xy(tp, tp->cx, tp->cy - tty3270_getpar(tp, 0));
1476                 break;
1477         case 'B':       /* Cursor down. */
1478         case 'e':
1479         case 'E':
1480                 tty3270_goto_xy(tp, tp->cx, tp->cy + tty3270_getpar(tp, 0));
1481                 break;
1482         case 'C':       /* Cursor forward. */
1483         case 'a':
1484                 tty3270_goto_xy(tp, tp->cx + tty3270_getpar(tp, 0), tp->cy);
1485                 break;
1486         case 'D':       /* Cursor backward. */
1487                 tty3270_goto_xy(tp, tp->cx - tty3270_getpar(tp, 0), tp->cy);
1488                 break;
1489         case 'G':       /* Set x position. */
1490         case '`':
1491                 tty3270_goto_xy(tp, tty3270_getpar(tp, 0), tp->cy);
1492                 break;
1493         case 'X':       /* Erase Characters. */
1494                 tty3270_erase_characters(tp, tty3270_getpar(tp, 0));
1495                 break;
1496         case 'J':       /* Erase display. */
1497                 tty3270_erase_display(tp, tp->esc_par[0]);
1498                 break;
1499         case 'K':       /* Erase line. */
1500                 tty3270_erase_line(tp, tp->esc_par[0]);
1501                 break;
1502         case 'P':       /* Delete characters. */
1503                 tty3270_delete_characters(tp, tty3270_getpar(tp, 0));
1504                 break;
1505         case '@':       /* Insert characters. */
1506                 tty3270_insert_characters(tp, tty3270_getpar(tp, 0));
1507                 break;
1508         case 's':       /* Save cursor position. */
1509                 tp->saved_cx = tp->cx;
1510                 tp->saved_cy = tp->cy;
1511                 tp->saved_highlight = tp->highlight;
1512                 tp->saved_f_color = tp->f_color;
1513                 break;
1514         case 'u':       /* Restore cursor position. */
1515                 tty3270_convert_line(tp, tp->cy);
1516                 tty3270_goto_xy(tp, tp->saved_cx, tp->saved_cy);
1517                 tp->highlight = tp->saved_highlight;
1518                 tp->f_color = tp->saved_f_color;
1519                 break;
1520         }
1521 }
1522
1523 /*
1524  * String write routine for 3270 ttys
1525  */
1526 static void
1527 tty3270_do_write(struct tty3270 *tp, const unsigned char *buf, int count)
1528 {
1529         int i_msg, i;
1530
1531         spin_lock_bh(&tp->view.lock);
1532         for (i_msg = 0; !tp->tty->stopped && i_msg < count; i_msg++) {
1533                 if (tp->esc_state != 0) {
1534                         /* Continue escape sequence. */
1535                         tty3270_escape_sequence(tp, buf[i_msg]);
1536                         continue;
1537                 }
1538
1539                 switch (buf[i_msg]) {
1540                 case 0x07:              /* '\a' -- Alarm */
1541                         tp->wcc |= TW_PLUSALARM;
1542                         break;
1543                 case 0x08:              /* Backspace. */
1544                         if (tp->cx > 0) {
1545                                 tp->cx--;
1546                                 tty3270_put_character(tp, ' ');
1547                         }
1548                         break;
1549                 case 0x09:              /* '\t' -- Tabulate */
1550                         for (i = tp->cx % 8; i < 8; i++) {
1551                                 if (tp->cx >= tp->view.cols) {
1552                                         tty3270_cr(tp);
1553                                         tty3270_lf(tp);
1554                                         break;
1555                                 }
1556                                 tty3270_put_character(tp, ' ');
1557                                 tp->cx++;
1558                         }
1559                         break;
1560                 case 0x0a:              /* '\n' -- New Line */
1561                         tty3270_cr(tp);
1562                         tty3270_lf(tp);
1563                         break;
1564                 case 0x0c:              /* '\f' -- Form Feed */
1565                         tty3270_erase_display(tp, 2);
1566                         tp->cx = tp->cy = 0;
1567                         break;
1568                 case 0x0d:              /* '\r' -- Carriage Return */
1569                         tp->cx = 0;
1570                         break;
1571                 case 0x0f:              /* SuSE "exit alternate mode" */
1572                         break;
1573                 case 0x1b:              /* Start escape sequence. */
1574                         tty3270_escape_sequence(tp, buf[i_msg]);
1575                         break;
1576                 default:                /* Insert normal character. */
1577                         if (tp->cx >= tp->view.cols) {
1578                                 tty3270_cr(tp);
1579                                 tty3270_lf(tp);
1580                         }
1581                         tty3270_put_character(tp, buf[i_msg]);
1582                         tp->cx++;
1583                         break;
1584                 }
1585         }
1586         /* Convert current line to 3270 data fragment. */
1587         tty3270_convert_line(tp, tp->cy);
1588
1589         /* Setup timer to update display after 1/10 second */
1590         if (!timer_pending(&tp->timer))
1591                 tty3270_set_timer(tp, HZ/10);
1592
1593         spin_unlock_bh(&tp->view.lock);
1594 }
1595
1596 /*
1597  * String write routine for 3270 ttys
1598  */
1599 static int
1600 tty3270_write(struct tty_struct * tty,
1601               const unsigned char *buf, int count)
1602 {
1603         struct tty3270 *tp;
1604
1605         tp = tty->driver_data;
1606         if (!tp)
1607                 return 0;
1608         if (tp->char_count > 0) {
1609                 tty3270_do_write(tp, tp->char_buf, tp->char_count);
1610                 tp->char_count = 0;
1611         }
1612         tty3270_do_write(tp, buf, count);
1613         return count;
1614 }
1615
1616 /*
1617  * Put single characters to the ttys character buffer
1618  */
1619 static void
1620 tty3270_put_char(struct tty_struct *tty, unsigned char ch)
1621 {
1622         struct tty3270 *tp;
1623
1624         tp = tty->driver_data;
1625         if (!tp)
1626                 return;
1627         if (tp->char_count < TTY3270_CHAR_BUF_SIZE)
1628                 tp->char_buf[tp->char_count++] = ch;
1629 }
1630
1631 /*
1632  * Flush all characters from the ttys characeter buffer put there
1633  * by tty3270_put_char.
1634  */
1635 static void
1636 tty3270_flush_chars(struct tty_struct *tty)
1637 {
1638         struct tty3270 *tp;
1639
1640         tp = tty->driver_data;
1641         if (!tp)
1642                 return;
1643         if (tp->char_count > 0) {
1644                 tty3270_do_write(tp, tp->char_buf, tp->char_count);
1645                 tp->char_count = 0;
1646         }
1647 }
1648
1649 /*
1650  * Returns the number of characters in the output buffer. This is
1651  * used in tty_wait_until_sent to wait until all characters have
1652  * appeared on the screen.
1653  */
1654 static int
1655 tty3270_chars_in_buffer(struct tty_struct *tty)
1656 {
1657         return 0;
1658 }
1659
1660 static void
1661 tty3270_flush_buffer(struct tty_struct *tty)
1662 {
1663 }
1664
1665 /*
1666  * Check for visible/invisible input switches
1667  */
1668 static void
1669 tty3270_set_termios(struct tty_struct *tty, struct termios *old)
1670 {
1671         struct tty3270 *tp;
1672         int new;
1673
1674         tp = tty->driver_data;
1675         if (!tp)
1676                 return;
1677         spin_lock_bh(&tp->view.lock);
1678         if (L_ICANON(tty)) {
1679                 new = L_ECHO(tty) ? TF_INPUT: TF_INPUTN;
1680                 if (new != tp->inattr) {
1681                         tp->inattr = new;
1682                         tty3270_update_prompt(tp, 0, 0);
1683                         tty3270_set_timer(tp, 1);
1684                 }
1685         }
1686         spin_unlock_bh(&tp->view.lock);
1687 }
1688
1689 /*
1690  * Disable reading from a 3270 tty
1691  */
1692 static void
1693 tty3270_throttle(struct tty_struct * tty)
1694 {
1695         struct tty3270 *tp;
1696
1697         tp = tty->driver_data;
1698         if (!tp)
1699                 return;
1700         tp->throttle = 1;
1701 }
1702
1703 /*
1704  * Enable reading from a 3270 tty
1705  */
1706 static void
1707 tty3270_unthrottle(struct tty_struct * tty)
1708 {
1709         struct tty3270 *tp;
1710
1711         tp = tty->driver_data;
1712         if (!tp)
1713                 return;
1714         tp->throttle = 0;
1715         if (tp->attn)
1716                 tty3270_issue_read(tp, 1);
1717 }
1718
1719 /*
1720  * Hang up the tty device.
1721  */
1722 static void
1723 tty3270_hangup(struct tty_struct *tty)
1724 {
1725         // FIXME: implement
1726 }
1727
1728 static void
1729 tty3270_wait_until_sent(struct tty_struct *tty, int timeout)
1730 {
1731 }
1732
1733 static int
1734 tty3270_ioctl(struct tty_struct *tty, struct file *file,
1735               unsigned int cmd, unsigned long arg)
1736 {
1737         struct tty3270 *tp;
1738
1739         tp = tty->driver_data;
1740         if (!tp)
1741                 return -ENODEV;
1742         if (tty->flags & (1 << TTY_IO_ERROR))
1743                 return -EIO;
1744         return kbd_ioctl(tp->kbd, file, cmd, arg);
1745 }
1746
1747 static struct tty_operations tty3270_ops = {
1748         .open = tty3270_open,
1749         .close = tty3270_close,
1750         .write = tty3270_write,
1751         .put_char = tty3270_put_char,
1752         .flush_chars = tty3270_flush_chars,
1753         .write_room = tty3270_write_room,
1754         .chars_in_buffer = tty3270_chars_in_buffer,
1755         .flush_buffer = tty3270_flush_buffer,
1756         .throttle = tty3270_throttle,
1757         .unthrottle = tty3270_unthrottle,
1758         .hangup = tty3270_hangup,
1759         .wait_until_sent = tty3270_wait_until_sent,
1760         .ioctl = tty3270_ioctl,
1761         .set_termios = tty3270_set_termios
1762 };
1763
1764 void
1765 tty3270_notifier(int index, int active)
1766 {
1767         if (active)
1768                 tty_register_device(tty3270_driver, index, 0);
1769         else
1770                 tty_unregister_device(tty3270_driver, index);
1771 }
1772
1773 /*
1774  * 3270 tty registration code called from tty_init().
1775  * Most kernel services (incl. kmalloc) are available at this poimt.
1776  */
1777 int __init
1778 tty3270_init(void)
1779 {
1780         struct tty_driver *driver;
1781         int ret;
1782
1783         driver = alloc_tty_driver(256);
1784         if (!driver)
1785                 return -ENOMEM;
1786
1787         /*
1788          * Initialize the tty_driver structure
1789          * Entries in tty3270_driver that are NOT initialized:
1790          * proc_entry, set_termios, flush_buffer, set_ldisc, write_proc
1791          */
1792         driver->owner = THIS_MODULE;
1793         driver->devfs_name = "ttyTUB/";
1794         driver->driver_name = "ttyTUB";
1795         driver->name = "ttyTUB";
1796         driver->major = IBM_TTY3270_MAJOR;
1797         driver->type = TTY_DRIVER_TYPE_SYSTEM;
1798         driver->subtype = SYSTEM_TYPE_TTY;
1799         driver->init_termios = tty_std_termios;
1800         driver->flags = TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_NO_DEVFS;
1801         tty_set_operations(driver, &tty3270_ops);
1802         ret = tty_register_driver(driver);
1803         if (ret) {
1804                 printk(KERN_ERR "tty3270 registration failed with %d\n", ret);
1805                 put_tty_driver(driver);
1806                 return ret;
1807         }
1808         tty3270_driver = driver;
1809         ret = raw3270_register_notifier(tty3270_notifier);
1810         if (ret) {
1811                 printk(KERN_ERR "tty3270 notifier registration failed "
1812                        "with %d\n", ret);
1813                 put_tty_driver(driver);
1814                 return ret;
1815
1816         }
1817         return 0;
1818 }
1819
1820 static void __exit
1821 tty3270_exit(void)
1822 {
1823         struct tty_driver *driver;
1824
1825         raw3270_unregister_notifier(tty3270_notifier);
1826         driver = tty3270_driver;
1827         tty3270_driver = 0;
1828         tty_unregister_driver(driver);
1829         tty3270_del_views();
1830 }
1831
1832 MODULE_LICENSE("GPL");
1833 MODULE_ALIAS_CHARDEV_MAJOR(IBM_TTY3270_MAJOR);
1834
1835 module_init(tty3270_init);
1836 module_exit(tty3270_exit);