Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  *    IBM/3270 Driver - tty functions.
0004  *
0005  *  Author(s):
0006  *    Original 3270 Code for 2.4 written by Richard Hitt (UTS Global)
0007  *    Rewritten for 2.5 by Martin Schwidefsky <schwidefsky@de.ibm.com>
0008  *  -- Copyright IBM Corp. 2003
0009  */
0010 
0011 #include <linux/module.h>
0012 #include <linux/types.h>
0013 #include <linux/kdev_t.h>
0014 #include <linux/tty.h>
0015 #include <linux/vt_kern.h>
0016 #include <linux/init.h>
0017 #include <linux/console.h>
0018 #include <linux/interrupt.h>
0019 #include <linux/workqueue.h>
0020 
0021 #include <linux/slab.h>
0022 #include <linux/memblock.h>
0023 #include <linux/compat.h>
0024 
0025 #include <asm/ccwdev.h>
0026 #include <asm/cio.h>
0027 #include <asm/ebcdic.h>
0028 #include <linux/uaccess.h>
0029 
0030 #include "raw3270.h"
0031 #include "tty3270.h"
0032 #include "keyboard.h"
0033 
0034 #define TTY3270_CHAR_BUF_SIZE 256
0035 #define TTY3270_OUTPUT_BUFFER_SIZE 1024
0036 #define TTY3270_STRING_PAGES 5
0037 
0038 struct tty_driver *tty3270_driver;
0039 static int tty3270_max_index;
0040 
0041 static struct raw3270_fn tty3270_fn;
0042 
0043 struct tty3270_cell {
0044     unsigned char character;
0045     unsigned char highlight;
0046     unsigned char f_color;
0047 };
0048 
0049 struct tty3270_line {
0050     struct tty3270_cell *cells;
0051     int len;
0052 };
0053 
0054 #define ESCAPE_NPAR 8
0055 
0056 /*
0057  * The main tty view data structure.
0058  * FIXME:
0059  * 1) describe line orientation & lines list concept against screen
0060  * 2) describe conversion of screen to lines
0061  * 3) describe line format.
0062  */
0063 struct tty3270 {
0064     struct raw3270_view view;
0065     struct tty_port port;
0066     void **freemem_pages;       /* Array of pages used for freemem. */
0067     struct list_head freemem;   /* List of free memory for strings. */
0068 
0069     /* Output stuff. */
0070     struct list_head lines;     /* List of lines. */
0071     struct list_head update;    /* List of lines to update. */
0072     unsigned char wcc;      /* Write control character. */
0073     int nr_lines;           /* # lines in list. */
0074     int nr_up;          /* # lines up in history. */
0075     unsigned long update_flags; /* Update indication bits. */
0076     struct string *status;      /* Lower right of display. */
0077     struct raw3270_request *write;  /* Single write request. */
0078     struct timer_list timer;    /* Output delay timer. */
0079 
0080     /* Current tty screen. */
0081     unsigned int cx, cy;        /* Current output position. */
0082     unsigned int highlight;     /* Blink/reverse/underscore */
0083     unsigned int f_color;       /* Foreground color */
0084     struct tty3270_line *screen;
0085     unsigned int n_model, n_cols, n_rows;   /* New model & size */
0086     struct work_struct resize_work;
0087 
0088     /* Input stuff. */
0089     struct string *prompt;      /* Output string for input area. */
0090     struct string *input;       /* Input string for read request. */
0091     struct raw3270_request *read;   /* Single read request. */
0092     struct raw3270_request *kreset; /* Single keyboard reset request. */
0093     unsigned char inattr;       /* Visible/invisible input. */
0094     int throttle, attn;     /* tty throttle/unthrottle. */
0095     struct tasklet_struct readlet;  /* Tasklet to issue read request. */
0096     struct tasklet_struct hanglet;  /* Tasklet to hang up the tty. */
0097     struct kbd_data *kbd;       /* key_maps stuff. */
0098 
0099     /* Escape sequence parsing. */
0100     int esc_state, esc_ques, esc_npar;
0101     int esc_par[ESCAPE_NPAR];
0102     unsigned int saved_cx, saved_cy;
0103     unsigned int saved_highlight, saved_f_color;
0104 
0105     /* Command recalling. */
0106     struct list_head rcl_lines; /* List of recallable lines. */
0107     struct list_head *rcl_walk; /* Point in rcl_lines list. */
0108     int rcl_nr, rcl_max;        /* Number/max number of rcl_lines. */
0109 
0110     /* Character array for put_char/flush_chars. */
0111     unsigned int char_count;
0112     char char_buf[TTY3270_CHAR_BUF_SIZE];
0113 };
0114 
0115 /* tty3270->update_flags. See tty3270_update for details. */
0116 #define TTY_UPDATE_ERASE    1   /* Use EWRITEA instead of WRITE. */
0117 #define TTY_UPDATE_LIST     2   /* Update lines in tty3270->update. */
0118 #define TTY_UPDATE_INPUT    4   /* Update input line. */
0119 #define TTY_UPDATE_STATUS   8   /* Update status line. */
0120 #define TTY_UPDATE_ALL      16  /* Recreate screen. */
0121 
0122 static void tty3270_update(struct timer_list *);
0123 static void tty3270_resize_work(struct work_struct *work);
0124 
0125 /*
0126  * Setup timeout for a device. On timeout trigger an update.
0127  */
0128 static void tty3270_set_timer(struct tty3270 *tp, int expires)
0129 {
0130     mod_timer(&tp->timer, jiffies + expires);
0131 }
0132 
0133 /*
0134  * The input line are the two last lines of the screen.
0135  */
0136 static void
0137 tty3270_update_prompt(struct tty3270 *tp, char *input, int count)
0138 {
0139     struct string *line;
0140     unsigned int off;
0141 
0142     line = tp->prompt;
0143     if (count != 0)
0144         line->string[5] = TF_INMDT;
0145     else
0146         line->string[5] = tp->inattr;
0147     if (count > tp->view.cols * 2 - 11)
0148         count = tp->view.cols * 2 - 11;
0149     memcpy(line->string + 6, input, count);
0150     line->string[6 + count] = TO_IC;
0151     /* Clear to end of input line. */
0152     if (count < tp->view.cols * 2 - 11) {
0153         line->string[7 + count] = TO_RA;
0154         line->string[10 + count] = 0;
0155         off = tp->view.cols * tp->view.rows - 9;
0156         raw3270_buffer_address(tp->view.dev, line->string+count+8, off);
0157         line->len = 11 + count;
0158     } else
0159         line->len = 7 + count;
0160     tp->update_flags |= TTY_UPDATE_INPUT;
0161 }
0162 
0163 static void
0164 tty3270_create_prompt(struct tty3270 *tp)
0165 {
0166     static const unsigned char blueprint[] =
0167         { TO_SBA, 0, 0, 0x6e, TO_SF, TF_INPUT,
0168           /* empty input string */
0169           TO_IC, TO_RA, 0, 0, 0 };
0170     struct string *line;
0171     unsigned int offset;
0172 
0173     line = alloc_string(&tp->freemem,
0174                 sizeof(blueprint) + tp->view.cols * 2 - 9);
0175     tp->prompt = line;
0176     tp->inattr = TF_INPUT;
0177     /* Copy blueprint to status line */
0178     memcpy(line->string, blueprint, sizeof(blueprint));
0179     line->len = sizeof(blueprint);
0180     /* Set output offsets. */
0181     offset = tp->view.cols * (tp->view.rows - 2);
0182     raw3270_buffer_address(tp->view.dev, line->string + 1, offset);
0183     offset = tp->view.cols * tp->view.rows - 9;
0184     raw3270_buffer_address(tp->view.dev, line->string + 8, offset);
0185 
0186     /* Allocate input string for reading. */
0187     tp->input = alloc_string(&tp->freemem, tp->view.cols * 2 - 9 + 6);
0188 }
0189 
0190 /*
0191  * The status line is the last line of the screen. It shows the string
0192  * "Running"/"Holding" in the lower right corner of the screen.
0193  */
0194 static void
0195 tty3270_update_status(struct tty3270 * tp)
0196 {
0197     char *str;
0198 
0199     str = (tp->nr_up != 0) ? "History" : "Running";
0200     memcpy(tp->status->string + 8, str, 7);
0201     codepage_convert(tp->view.ascebc, tp->status->string + 8, 7);
0202     tp->update_flags |= TTY_UPDATE_STATUS;
0203 }
0204 
0205 static void
0206 tty3270_create_status(struct tty3270 * tp)
0207 {
0208     static const unsigned char blueprint[] =
0209         { TO_SBA, 0, 0, TO_SF, TF_LOG, TO_SA, TAT_COLOR, TAC_GREEN,
0210           0, 0, 0, 0, 0, 0, 0, TO_SF, TF_LOG, TO_SA, TAT_COLOR,
0211           TAC_RESET };
0212     struct string *line;
0213     unsigned int offset;
0214 
0215     line = alloc_string(&tp->freemem,sizeof(blueprint));
0216     tp->status = line;
0217     /* Copy blueprint to status line */
0218     memcpy(line->string, blueprint, sizeof(blueprint));
0219     /* Set address to start of status string (= last 9 characters). */
0220     offset = tp->view.cols * tp->view.rows - 9;
0221     raw3270_buffer_address(tp->view.dev, line->string + 1, offset);
0222 }
0223 
0224 /*
0225  * Set output offsets to 3270 datastream fragment of a tty string.
0226  * (TO_SBA offset at the start and TO_RA offset at the end of the string)
0227  */
0228 static void
0229 tty3270_update_string(struct tty3270 *tp, struct string *line, int nr)
0230 {
0231     unsigned char *cp;
0232 
0233     raw3270_buffer_address(tp->view.dev, line->string + 1,
0234                    tp->view.cols * nr);
0235     cp = line->string + line->len - 4;
0236     if (*cp == TO_RA)
0237         raw3270_buffer_address(tp->view.dev, cp + 1,
0238                        tp->view.cols * (nr + 1));
0239 }
0240 
0241 /*
0242  * Rebuild update list to print all lines.
0243  */
0244 static void
0245 tty3270_rebuild_update(struct tty3270 *tp)
0246 {
0247     struct string *s, *n;
0248     int line, nr_up;
0249 
0250     /* 
0251      * Throw away update list and create a new one,
0252      * containing all lines that will fit on the screen.
0253      */
0254     list_for_each_entry_safe(s, n, &tp->update, update)
0255         list_del_init(&s->update);
0256     line = tp->view.rows - 3;
0257     nr_up = tp->nr_up;
0258     list_for_each_entry_reverse(s, &tp->lines, list) {
0259         if (nr_up > 0) {
0260             nr_up--;
0261             continue;
0262         }
0263         tty3270_update_string(tp, s, line);
0264         list_add(&s->update, &tp->update);
0265         if (--line < 0)
0266             break;
0267     }
0268     tp->update_flags |= TTY_UPDATE_LIST;
0269 }
0270 
0271 /*
0272  * Alloc string for size bytes. If there is not enough room in
0273  * freemem, free strings until there is room.
0274  */
0275 static struct string *
0276 tty3270_alloc_string(struct tty3270 *tp, size_t size)
0277 {
0278     struct string *s, *n;
0279 
0280     s = alloc_string(&tp->freemem, size);
0281     if (s)
0282         return s;
0283     list_for_each_entry_safe(s, n, &tp->lines, list) {
0284         BUG_ON(tp->nr_lines <= tp->view.rows - 2);
0285         list_del(&s->list);
0286         if (!list_empty(&s->update))
0287             list_del(&s->update);
0288         tp->nr_lines--;
0289         if (free_string(&tp->freemem, s) >= size)
0290             break;
0291     }
0292     s = alloc_string(&tp->freemem, size);
0293     BUG_ON(!s);
0294     if (tp->nr_up != 0 &&
0295         tp->nr_up + tp->view.rows - 2 >= tp->nr_lines) {
0296         tp->nr_up = tp->nr_lines - tp->view.rows + 2;
0297         tty3270_rebuild_update(tp);
0298         tty3270_update_status(tp);
0299     }
0300     return s;
0301 }
0302 
0303 /*
0304  * Add an empty line to the list.
0305  */
0306 static void
0307 tty3270_blank_line(struct tty3270 *tp)
0308 {
0309     static const unsigned char blueprint[] =
0310         { TO_SBA, 0, 0, TO_SA, TAT_EXTHI, TAX_RESET,
0311           TO_SA, TAT_COLOR, TAC_RESET, TO_RA, 0, 0, 0 };
0312     struct string *s;
0313 
0314     s = tty3270_alloc_string(tp, sizeof(blueprint));
0315     memcpy(s->string, blueprint, sizeof(blueprint));
0316     s->len = sizeof(blueprint);
0317     list_add_tail(&s->list, &tp->lines);
0318     tp->nr_lines++;
0319     if (tp->nr_up != 0)
0320         tp->nr_up++;
0321 }
0322 
0323 /*
0324  * Create a blank screen and remove all lines from the history.
0325  */
0326 static void
0327 tty3270_blank_screen(struct tty3270 *tp)
0328 {
0329     struct string *s, *n;
0330     int i;
0331 
0332     for (i = 0; i < tp->view.rows - 2; i++)
0333         tp->screen[i].len = 0;
0334     tp->nr_up = 0;
0335     list_for_each_entry_safe(s, n, &tp->lines, list) {
0336         list_del(&s->list);
0337         if (!list_empty(&s->update))
0338             list_del(&s->update);
0339         tp->nr_lines--;
0340         free_string(&tp->freemem, s);
0341     }
0342 }
0343 
0344 /*
0345  * Write request completion callback.
0346  */
0347 static void
0348 tty3270_write_callback(struct raw3270_request *rq, void *data)
0349 {
0350     struct tty3270 *tp = container_of(rq->view, struct tty3270, view);
0351 
0352     if (rq->rc != 0) {
0353         /* Write wasn't successful. Refresh all. */
0354         tp->update_flags = TTY_UPDATE_ALL;
0355         tty3270_set_timer(tp, 1);
0356     }
0357     raw3270_request_reset(rq);
0358     xchg(&tp->write, rq);
0359 }
0360 
0361 /*
0362  * Update 3270 display.
0363  */
0364 static void
0365 tty3270_update(struct timer_list *t)
0366 {
0367     struct tty3270 *tp = from_timer(tp, t, timer);
0368     static char invalid_sba[2] = { 0xff, 0xff };
0369     struct raw3270_request *wrq;
0370     unsigned long updated;
0371     struct string *s, *n;
0372     char *sba, *str;
0373     int rc, len;
0374 
0375     wrq = xchg(&tp->write, 0);
0376     if (!wrq) {
0377         tty3270_set_timer(tp, 1);
0378         return;
0379     }
0380 
0381     spin_lock(&tp->view.lock);
0382     updated = 0;
0383     if (tp->update_flags & TTY_UPDATE_ALL) {
0384         tty3270_rebuild_update(tp);
0385         tty3270_update_status(tp);
0386         tp->update_flags = TTY_UPDATE_ERASE | TTY_UPDATE_LIST |
0387             TTY_UPDATE_INPUT | TTY_UPDATE_STATUS;
0388     }
0389     if (tp->update_flags & TTY_UPDATE_ERASE) {
0390         /* Use erase write alternate to erase display. */
0391         raw3270_request_set_cmd(wrq, TC_EWRITEA);
0392         updated |= TTY_UPDATE_ERASE;
0393     } else
0394         raw3270_request_set_cmd(wrq, TC_WRITE);
0395 
0396     raw3270_request_add_data(wrq, &tp->wcc, 1);
0397     tp->wcc = TW_NONE;
0398 
0399     /*
0400      * Update status line.
0401      */
0402     if (tp->update_flags & TTY_UPDATE_STATUS)
0403         if (raw3270_request_add_data(wrq, tp->status->string,
0404                          tp->status->len) == 0)
0405             updated |= TTY_UPDATE_STATUS;
0406 
0407     /*
0408      * Write input line.
0409      */
0410     if (tp->update_flags & TTY_UPDATE_INPUT)
0411         if (raw3270_request_add_data(wrq, tp->prompt->string,
0412                          tp->prompt->len) == 0)
0413             updated |= TTY_UPDATE_INPUT;
0414 
0415     sba = invalid_sba;
0416     
0417     if (tp->update_flags & TTY_UPDATE_LIST) {
0418         /* Write strings in the update list to the screen. */
0419         list_for_each_entry_safe(s, n, &tp->update, update) {
0420             str = s->string;
0421             len = s->len;
0422             /*
0423              * Skip TO_SBA at the start of the string if the
0424              * last output position matches the start address
0425              * of this line.
0426              */
0427             if (s->string[1] == sba[0] && s->string[2] == sba[1]) {
0428                 str += 3;
0429                 len -= 3;
0430             }
0431             if (raw3270_request_add_data(wrq, str, len) != 0)
0432                 break;
0433             list_del_init(&s->update);
0434             if (s->string[s->len - 4] == TO_RA)
0435                 sba = s->string + s->len - 3;
0436             else
0437                 sba = invalid_sba;
0438         }
0439         if (list_empty(&tp->update))
0440             updated |= TTY_UPDATE_LIST;
0441     }
0442     wrq->callback = tty3270_write_callback;
0443     rc = raw3270_start(&tp->view, wrq);
0444     if (rc == 0) {
0445         tp->update_flags &= ~updated;
0446         if (tp->update_flags)
0447             tty3270_set_timer(tp, 1);
0448     } else {
0449         raw3270_request_reset(wrq);
0450         xchg(&tp->write, wrq);
0451     }
0452     spin_unlock(&tp->view.lock);
0453 }
0454 
0455 /*
0456  * Command recalling.
0457  */
0458 static void
0459 tty3270_rcl_add(struct tty3270 *tp, char *input, int len)
0460 {
0461     struct string *s;
0462 
0463     tp->rcl_walk = NULL;
0464     if (len <= 0)
0465         return;
0466     if (tp->rcl_nr >= tp->rcl_max) {
0467         s = list_entry(tp->rcl_lines.next, struct string, list);
0468         list_del(&s->list);
0469         free_string(&tp->freemem, s);
0470         tp->rcl_nr--;
0471     }
0472     s = tty3270_alloc_string(tp, len);
0473     memcpy(s->string, input, len);
0474     list_add_tail(&s->list, &tp->rcl_lines);
0475     tp->rcl_nr++;
0476 }
0477 
0478 static void
0479 tty3270_rcl_backward(struct kbd_data *kbd)
0480 {
0481     struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
0482     struct string *s;
0483 
0484     spin_lock_bh(&tp->view.lock);
0485     if (tp->inattr == TF_INPUT) {
0486         if (tp->rcl_walk && tp->rcl_walk->prev != &tp->rcl_lines)
0487             tp->rcl_walk = tp->rcl_walk->prev;
0488         else if (!list_empty(&tp->rcl_lines))
0489             tp->rcl_walk = tp->rcl_lines.prev;
0490         s = tp->rcl_walk ? 
0491             list_entry(tp->rcl_walk, struct string, list) : NULL;
0492         if (tp->rcl_walk) {
0493             s = list_entry(tp->rcl_walk, struct string, list);
0494             tty3270_update_prompt(tp, s->string, s->len);
0495         } else
0496             tty3270_update_prompt(tp, NULL, 0);
0497         tty3270_set_timer(tp, 1);
0498     }
0499     spin_unlock_bh(&tp->view.lock);
0500 }
0501 
0502 /*
0503  * Deactivate tty view.
0504  */
0505 static void
0506 tty3270_exit_tty(struct kbd_data *kbd)
0507 {
0508     struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
0509 
0510     raw3270_deactivate_view(&tp->view);
0511 }
0512 
0513 /*
0514  * Scroll forward in history.
0515  */
0516 static void
0517 tty3270_scroll_forward(struct kbd_data *kbd)
0518 {
0519     struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
0520     int nr_up;
0521 
0522     spin_lock_bh(&tp->view.lock);
0523     nr_up = tp->nr_up - tp->view.rows + 2;
0524     if (nr_up < 0)
0525         nr_up = 0;
0526     if (nr_up != tp->nr_up) {
0527         tp->nr_up = nr_up;
0528         tty3270_rebuild_update(tp);
0529         tty3270_update_status(tp);
0530         tty3270_set_timer(tp, 1);
0531     }
0532     spin_unlock_bh(&tp->view.lock);
0533 }
0534 
0535 /*
0536  * Scroll backward in history.
0537  */
0538 static void
0539 tty3270_scroll_backward(struct kbd_data *kbd)
0540 {
0541     struct tty3270 *tp = container_of(kbd->port, struct tty3270, port);
0542     int nr_up;
0543 
0544     spin_lock_bh(&tp->view.lock);
0545     nr_up = tp->nr_up + tp->view.rows - 2;
0546     if (nr_up + tp->view.rows - 2 > tp->nr_lines)
0547         nr_up = tp->nr_lines - tp->view.rows + 2;
0548     if (nr_up != tp->nr_up) {
0549         tp->nr_up = nr_up;
0550         tty3270_rebuild_update(tp);
0551         tty3270_update_status(tp);
0552         tty3270_set_timer(tp, 1);
0553     }
0554     spin_unlock_bh(&tp->view.lock);
0555 }
0556 
0557 /*
0558  * Pass input line to tty.
0559  */
0560 static void
0561 tty3270_read_tasklet(unsigned long data)
0562 {
0563     struct raw3270_request *rrq = (struct raw3270_request *)data;
0564     static char kreset_data = TW_KR;
0565     struct tty3270 *tp = container_of(rrq->view, struct tty3270, view);
0566     char *input;
0567     int len;
0568 
0569     spin_lock_bh(&tp->view.lock);
0570     /*
0571      * Two AID keys are special: For 0x7d (enter) the input line
0572      * has to be emitted to the tty and for 0x6d the screen
0573      * needs to be redrawn.
0574      */
0575     input = NULL;
0576     len = 0;
0577     if (tp->input->string[0] == 0x7d) {
0578         /* Enter: write input to tty. */
0579         input = tp->input->string + 6;
0580         len = tp->input->len - 6 - rrq->rescnt;
0581         if (tp->inattr != TF_INPUTN)
0582             tty3270_rcl_add(tp, input, len);
0583         if (tp->nr_up > 0) {
0584             tp->nr_up = 0;
0585             tty3270_rebuild_update(tp);
0586             tty3270_update_status(tp);
0587         }
0588         /* Clear input area. */
0589         tty3270_update_prompt(tp, NULL, 0);
0590         tty3270_set_timer(tp, 1);
0591     } else if (tp->input->string[0] == 0x6d) {
0592         /* Display has been cleared. Redraw. */
0593         tp->update_flags = TTY_UPDATE_ALL;
0594         tty3270_set_timer(tp, 1);
0595     }
0596     spin_unlock_bh(&tp->view.lock);
0597 
0598     /* Start keyboard reset command. */
0599     raw3270_request_reset(tp->kreset);
0600     raw3270_request_set_cmd(tp->kreset, TC_WRITE);
0601     raw3270_request_add_data(tp->kreset, &kreset_data, 1);
0602     raw3270_start(&tp->view, tp->kreset);
0603 
0604     while (len-- > 0)
0605         kbd_keycode(tp->kbd, *input++);
0606     /* Emit keycode for AID byte. */
0607     kbd_keycode(tp->kbd, 256 + tp->input->string[0]);
0608 
0609     raw3270_request_reset(rrq);
0610     xchg(&tp->read, rrq);
0611     raw3270_put_view(&tp->view);
0612 }
0613 
0614 /*
0615  * Read request completion callback.
0616  */
0617 static void
0618 tty3270_read_callback(struct raw3270_request *rq, void *data)
0619 {
0620     struct tty3270 *tp = container_of(rq->view, struct tty3270, view);
0621     raw3270_get_view(rq->view);
0622     /* Schedule tasklet to pass input to tty. */
0623     tasklet_schedule(&tp->readlet);
0624 }
0625 
0626 /*
0627  * Issue a read request. Call with device lock.
0628  */
0629 static void
0630 tty3270_issue_read(struct tty3270 *tp, int lock)
0631 {
0632     struct raw3270_request *rrq;
0633     int rc;
0634 
0635     rrq = xchg(&tp->read, 0);
0636     if (!rrq)
0637         /* Read already scheduled. */
0638         return;
0639     rrq->callback = tty3270_read_callback;
0640     rrq->callback_data = tp;
0641     raw3270_request_set_cmd(rrq, TC_READMOD);
0642     raw3270_request_set_data(rrq, tp->input->string, tp->input->len);
0643     /* Issue the read modified request. */
0644     if (lock) {
0645         rc = raw3270_start(&tp->view, rrq);
0646     } else
0647         rc = raw3270_start_irq(&tp->view, rrq);
0648     if (rc) {
0649         raw3270_request_reset(rrq);
0650         xchg(&tp->read, rrq);
0651     }
0652 }
0653 
0654 /*
0655  * Hang up the tty
0656  */
0657 static void
0658 tty3270_hangup_tasklet(unsigned long data)
0659 {
0660     struct tty3270 *tp = (struct tty3270 *)data;
0661     tty_port_tty_hangup(&tp->port, true);
0662     raw3270_put_view(&tp->view);
0663 }
0664 
0665 /*
0666  * Switch to the tty view.
0667  */
0668 static int
0669 tty3270_activate(struct raw3270_view *view)
0670 {
0671     struct tty3270 *tp = container_of(view, struct tty3270, view);
0672 
0673     tp->update_flags = TTY_UPDATE_ALL;
0674     tty3270_set_timer(tp, 1);
0675     return 0;
0676 }
0677 
0678 static void
0679 tty3270_deactivate(struct raw3270_view *view)
0680 {
0681     struct tty3270 *tp = container_of(view, struct tty3270, view);
0682 
0683     del_timer(&tp->timer);
0684 }
0685 
0686 static void
0687 tty3270_irq(struct tty3270 *tp, struct raw3270_request *rq, struct irb *irb)
0688 {
0689     /* Handle ATTN. Schedule tasklet to read aid. */
0690     if (irb->scsw.cmd.dstat & DEV_STAT_ATTENTION) {
0691         if (!tp->throttle)
0692             tty3270_issue_read(tp, 0);
0693         else
0694             tp->attn = 1;
0695     }
0696 
0697     if (rq) {
0698         if (irb->scsw.cmd.dstat & DEV_STAT_UNIT_CHECK) {
0699             rq->rc = -EIO;
0700             raw3270_get_view(&tp->view);
0701             tasklet_schedule(&tp->hanglet);
0702         } else {
0703             /* Normal end. Copy residual count. */
0704             rq->rescnt = irb->scsw.cmd.count;
0705         }
0706     } else if (irb->scsw.cmd.dstat & DEV_STAT_DEV_END) {
0707         /* Interrupt without an outstanding request -> update all */
0708         tp->update_flags = TTY_UPDATE_ALL;
0709         tty3270_set_timer(tp, 1);
0710     }
0711 }
0712 
0713 /*
0714  * Allocate tty3270 structure.
0715  */
0716 static struct tty3270 *
0717 tty3270_alloc_view(void)
0718 {
0719     struct tty3270 *tp;
0720     int pages;
0721 
0722     tp = kzalloc(sizeof(struct tty3270), GFP_KERNEL);
0723     if (!tp)
0724         goto out_err;
0725     tp->freemem_pages =
0726         kmalloc_array(TTY3270_STRING_PAGES, sizeof(void *),
0727                   GFP_KERNEL);
0728     if (!tp->freemem_pages)
0729         goto out_tp;
0730     INIT_LIST_HEAD(&tp->freemem);
0731     INIT_LIST_HEAD(&tp->lines);
0732     INIT_LIST_HEAD(&tp->update);
0733     INIT_LIST_HEAD(&tp->rcl_lines);
0734     tp->rcl_max = 20;
0735 
0736     for (pages = 0; pages < TTY3270_STRING_PAGES; pages++) {
0737         tp->freemem_pages[pages] = (void *)
0738             __get_free_pages(GFP_KERNEL|GFP_DMA, 0);
0739         if (!tp->freemem_pages[pages])
0740             goto out_pages;
0741         add_string_memory(&tp->freemem,
0742                   tp->freemem_pages[pages], PAGE_SIZE);
0743     }
0744     tp->write = raw3270_request_alloc(TTY3270_OUTPUT_BUFFER_SIZE);
0745     if (IS_ERR(tp->write))
0746         goto out_pages;
0747     tp->read = raw3270_request_alloc(0);
0748     if (IS_ERR(tp->read))
0749         goto out_write;
0750     tp->kreset = raw3270_request_alloc(1);
0751     if (IS_ERR(tp->kreset))
0752         goto out_read;
0753     tp->kbd = kbd_alloc();
0754     if (!tp->kbd)
0755         goto out_reset;
0756 
0757     tty_port_init(&tp->port);
0758     timer_setup(&tp->timer, tty3270_update, 0);
0759     tasklet_init(&tp->readlet, tty3270_read_tasklet,
0760              (unsigned long) tp->read);
0761     tasklet_init(&tp->hanglet, tty3270_hangup_tasklet,
0762              (unsigned long) tp);
0763     INIT_WORK(&tp->resize_work, tty3270_resize_work);
0764 
0765     return tp;
0766 
0767 out_reset:
0768     raw3270_request_free(tp->kreset);
0769 out_read:
0770     raw3270_request_free(tp->read);
0771 out_write:
0772     raw3270_request_free(tp->write);
0773 out_pages:
0774     while (pages--)
0775         free_pages((unsigned long) tp->freemem_pages[pages], 0);
0776     kfree(tp->freemem_pages);
0777     tty_port_destroy(&tp->port);
0778 out_tp:
0779     kfree(tp);
0780 out_err:
0781     return ERR_PTR(-ENOMEM);
0782 }
0783 
0784 /*
0785  * Free tty3270 structure.
0786  */
0787 static void
0788 tty3270_free_view(struct tty3270 *tp)
0789 {
0790     int pages;
0791 
0792     kbd_free(tp->kbd);
0793     raw3270_request_free(tp->kreset);
0794     raw3270_request_free(tp->read);
0795     raw3270_request_free(tp->write);
0796     for (pages = 0; pages < TTY3270_STRING_PAGES; pages++)
0797         free_pages((unsigned long) tp->freemem_pages[pages], 0);
0798     kfree(tp->freemem_pages);
0799     tty_port_destroy(&tp->port);
0800     kfree(tp);
0801 }
0802 
0803 /*
0804  * Allocate tty3270 screen.
0805  */
0806 static struct tty3270_line *
0807 tty3270_alloc_screen(unsigned int rows, unsigned int cols)
0808 {
0809     struct tty3270_line *screen;
0810     unsigned long size;
0811     int lines;
0812 
0813     size = sizeof(struct tty3270_line) * (rows - 2);
0814     screen = kzalloc(size, GFP_KERNEL);
0815     if (!screen)
0816         goto out_err;
0817     for (lines = 0; lines < rows - 2; lines++) {
0818         size = sizeof(struct tty3270_cell) * cols;
0819         screen[lines].cells = kzalloc(size, GFP_KERNEL);
0820         if (!screen[lines].cells)
0821             goto out_screen;
0822     }
0823     return screen;
0824 out_screen:
0825     while (lines--)
0826         kfree(screen[lines].cells);
0827     kfree(screen);
0828 out_err:
0829     return ERR_PTR(-ENOMEM);
0830 }
0831 
0832 /*
0833  * Free tty3270 screen.
0834  */
0835 static void
0836 tty3270_free_screen(struct tty3270_line *screen, unsigned int rows)
0837 {
0838     int lines;
0839 
0840     for (lines = 0; lines < rows - 2; lines++)
0841         kfree(screen[lines].cells);
0842     kfree(screen);
0843 }
0844 
0845 /*
0846  * Resize tty3270 screen
0847  */
0848 static void tty3270_resize_work(struct work_struct *work)
0849 {
0850     struct tty3270 *tp = container_of(work, struct tty3270, resize_work);
0851     struct tty3270_line *screen, *oscreen;
0852     struct tty_struct *tty;
0853     unsigned int orows;
0854     struct winsize ws;
0855 
0856     screen = tty3270_alloc_screen(tp->n_rows, tp->n_cols);
0857     if (IS_ERR(screen))
0858         return;
0859     /* Switch to new output size */
0860     spin_lock_bh(&tp->view.lock);
0861     tty3270_blank_screen(tp);
0862     oscreen = tp->screen;
0863     orows = tp->view.rows;
0864     tp->view.model = tp->n_model;
0865     tp->view.rows = tp->n_rows;
0866     tp->view.cols = tp->n_cols;
0867     tp->screen = screen;
0868     free_string(&tp->freemem, tp->prompt);
0869     free_string(&tp->freemem, tp->status);
0870     tty3270_create_prompt(tp);
0871     tty3270_create_status(tp);
0872     while (tp->nr_lines < tp->view.rows - 2)
0873         tty3270_blank_line(tp);
0874     tp->update_flags = TTY_UPDATE_ALL;
0875     spin_unlock_bh(&tp->view.lock);
0876     tty3270_free_screen(oscreen, orows);
0877     tty3270_set_timer(tp, 1);
0878     /* Informat tty layer about new size */
0879     tty = tty_port_tty_get(&tp->port);
0880     if (!tty)
0881         return;
0882     ws.ws_row = tp->view.rows - 2;
0883     ws.ws_col = tp->view.cols;
0884     tty_do_resize(tty, &ws);
0885     tty_kref_put(tty);
0886 }
0887 
0888 static void
0889 tty3270_resize(struct raw3270_view *view, int model, int rows, int cols)
0890 {
0891     struct tty3270 *tp = container_of(view, struct tty3270, view);
0892 
0893     if (tp->n_model == model && tp->n_rows == rows && tp->n_cols == cols)
0894         return;
0895     tp->n_model = model;
0896     tp->n_rows = rows;
0897     tp->n_cols = cols;
0898     schedule_work(&tp->resize_work);
0899 }
0900 
0901 /*
0902  * Unlink tty3270 data structure from tty.
0903  */
0904 static void
0905 tty3270_release(struct raw3270_view *view)
0906 {
0907     struct tty3270 *tp = container_of(view, struct tty3270, view);
0908     struct tty_struct *tty = tty_port_tty_get(&tp->port);
0909 
0910     if (tty) {
0911         tty->driver_data = NULL;
0912         tty_port_tty_set(&tp->port, NULL);
0913         tty_hangup(tty);
0914         raw3270_put_view(&tp->view);
0915         tty_kref_put(tty);
0916     }
0917 }
0918 
0919 /*
0920  * Free tty3270 data structure
0921  */
0922 static void
0923 tty3270_free(struct raw3270_view *view)
0924 {
0925     struct tty3270 *tp = container_of(view, struct tty3270, view);
0926 
0927     del_timer_sync(&tp->timer);
0928     tty3270_free_screen(tp->screen, tp->view.rows);
0929     tty3270_free_view(tp);
0930 }
0931 
0932 /*
0933  * Delayed freeing of tty3270 views.
0934  */
0935 static void
0936 tty3270_del_views(void)
0937 {
0938     int i;
0939 
0940     for (i = RAW3270_FIRSTMINOR; i <= tty3270_max_index; i++) {
0941         struct raw3270_view *view = raw3270_find_view(&tty3270_fn, i);
0942         if (!IS_ERR(view))
0943             raw3270_del_view(view);
0944     }
0945 }
0946 
0947 static struct raw3270_fn tty3270_fn = {
0948     .activate = tty3270_activate,
0949     .deactivate = tty3270_deactivate,
0950     .intv = (void *) tty3270_irq,
0951     .release = tty3270_release,
0952     .free = tty3270_free,
0953     .resize = tty3270_resize
0954 };
0955 
0956 /*
0957  * This routine is called whenever a 3270 tty is opened first time.
0958  */
0959 static int tty3270_install(struct tty_driver *driver, struct tty_struct *tty)
0960 {
0961     struct raw3270_view *view;
0962     struct tty3270 *tp;
0963     int i, rc;
0964 
0965     /* Check if the tty3270 is already there. */
0966     view = raw3270_find_view(&tty3270_fn, tty->index + RAW3270_FIRSTMINOR);
0967     if (!IS_ERR(view)) {
0968         tp = container_of(view, struct tty3270, view);
0969         tty->driver_data = tp;
0970         tty->winsize.ws_row = tp->view.rows - 2;
0971         tty->winsize.ws_col = tp->view.cols;
0972         tp->inattr = TF_INPUT;
0973         goto port_install;
0974     }
0975     if (tty3270_max_index < tty->index + 1)
0976         tty3270_max_index = tty->index + 1;
0977 
0978     /* Allocate tty3270 structure on first open. */
0979     tp = tty3270_alloc_view();
0980     if (IS_ERR(tp))
0981         return PTR_ERR(tp);
0982 
0983     rc = raw3270_add_view(&tp->view, &tty3270_fn,
0984                   tty->index + RAW3270_FIRSTMINOR,
0985                   RAW3270_VIEW_LOCK_BH);
0986     if (rc) {
0987         tty3270_free_view(tp);
0988         return rc;
0989     }
0990 
0991     tp->screen = tty3270_alloc_screen(tp->view.rows, tp->view.cols);
0992     if (IS_ERR(tp->screen)) {
0993         rc = PTR_ERR(tp->screen);
0994         raw3270_put_view(&tp->view);
0995         raw3270_del_view(&tp->view);
0996         tty3270_free_view(tp);
0997         return rc;
0998     }
0999 
1000     tty->winsize.ws_row = tp->view.rows - 2;
1001     tty->winsize.ws_col = tp->view.cols;
1002 
1003     tty3270_create_prompt(tp);
1004     tty3270_create_status(tp);
1005     tty3270_update_status(tp);
1006 
1007     /* Create blank line for every line in the tty output area. */
1008     for (i = 0; i < tp->view.rows - 2; i++)
1009         tty3270_blank_line(tp);
1010 
1011     tp->kbd->port = &tp->port;
1012     tp->kbd->fn_handler[KVAL(K_INCRCONSOLE)] = tty3270_exit_tty;
1013     tp->kbd->fn_handler[KVAL(K_SCROLLBACK)] = tty3270_scroll_backward;
1014     tp->kbd->fn_handler[KVAL(K_SCROLLFORW)] = tty3270_scroll_forward;
1015     tp->kbd->fn_handler[KVAL(K_CONS)] = tty3270_rcl_backward;
1016     kbd_ascebc(tp->kbd, tp->view.ascebc);
1017 
1018     raw3270_activate_view(&tp->view);
1019 
1020 port_install:
1021     rc = tty_port_install(&tp->port, driver, tty);
1022     if (rc) {
1023         raw3270_put_view(&tp->view);
1024         return rc;
1025     }
1026 
1027     tty->driver_data = tp;
1028 
1029     return 0;
1030 }
1031 
1032 /*
1033  * This routine is called whenever a 3270 tty is opened.
1034  */
1035 static int
1036 tty3270_open(struct tty_struct *tty, struct file *filp)
1037 {
1038     struct tty3270 *tp = tty->driver_data;
1039     struct tty_port *port = &tp->port;
1040 
1041     port->count++;
1042     tty_port_tty_set(port, tty);
1043     return 0;
1044 }
1045 
1046 /*
1047  * This routine is called when the 3270 tty is closed. We wait
1048  * for the remaining request to be completed. Then we clean up.
1049  */
1050 static void
1051 tty3270_close(struct tty_struct *tty, struct file * filp)
1052 {
1053     struct tty3270 *tp = tty->driver_data;
1054 
1055     if (tty->count > 1)
1056         return;
1057     if (tp)
1058         tty_port_tty_set(&tp->port, NULL);
1059 }
1060 
1061 static void tty3270_cleanup(struct tty_struct *tty)
1062 {
1063     struct tty3270 *tp = tty->driver_data;
1064 
1065     if (tp) {
1066         tty->driver_data = NULL;
1067         raw3270_put_view(&tp->view);
1068     }
1069 }
1070 
1071 /*
1072  * We always have room.
1073  */
1074 static unsigned int
1075 tty3270_write_room(struct tty_struct *tty)
1076 {
1077     return INT_MAX;
1078 }
1079 
1080 /*
1081  * Insert character into the screen at the current position with the
1082  * current color and highlight. This function does NOT do cursor movement.
1083  */
1084 static void tty3270_put_character(struct tty3270 *tp, char ch)
1085 {
1086     struct tty3270_line *line;
1087     struct tty3270_cell *cell;
1088 
1089     line = tp->screen + tp->cy;
1090     if (line->len <= tp->cx) {
1091         while (line->len < tp->cx) {
1092             cell = line->cells + line->len;
1093             cell->character = tp->view.ascebc[' '];
1094             cell->highlight = tp->highlight;
1095             cell->f_color = tp->f_color;
1096             line->len++;
1097         }
1098         line->len++;
1099     }
1100     cell = line->cells + tp->cx;
1101     cell->character = tp->view.ascebc[(unsigned int) ch];
1102     cell->highlight = tp->highlight;
1103     cell->f_color = tp->f_color;
1104 }
1105 
1106 /*
1107  * Convert a tty3270_line to a 3270 data fragment usable for output.
1108  */
1109 static void
1110 tty3270_convert_line(struct tty3270 *tp, int line_nr)
1111 {
1112     struct tty3270_line *line;
1113     struct tty3270_cell *cell;
1114     struct string *s, *n;
1115     unsigned char highlight;
1116     unsigned char f_color;
1117     char *cp;
1118     int flen, i;
1119 
1120     /* Determine how long the fragment will be. */
1121     flen = 3;       /* Prefix (TO_SBA). */
1122     line = tp->screen + line_nr;
1123     flen += line->len;
1124     highlight = TAX_RESET;
1125     f_color = TAC_RESET;
1126     for (i = 0, cell = line->cells; i < line->len; i++, cell++) {
1127         if (cell->highlight != highlight) {
1128             flen += 3;  /* TO_SA to switch highlight. */
1129             highlight = cell->highlight;
1130         }
1131         if (cell->f_color != f_color) {
1132             flen += 3;  /* TO_SA to switch color. */
1133             f_color = cell->f_color;
1134         }
1135     }
1136     if (highlight != TAX_RESET)
1137         flen += 3;  /* TO_SA to reset hightlight. */
1138     if (f_color != TAC_RESET)
1139         flen += 3;  /* TO_SA to reset color. */
1140     if (line->len < tp->view.cols)
1141         flen += 4;  /* Postfix (TO_RA). */
1142 
1143     /* Find the line in the list. */
1144     i = tp->view.rows - 2 - line_nr;
1145     list_for_each_entry_reverse(s, &tp->lines, list)
1146         if (--i <= 0)
1147             break;
1148     /*
1149      * Check if the line needs to get reallocated.
1150      */
1151     if (s->len != flen) {
1152         /* Reallocate string. */
1153         n = tty3270_alloc_string(tp, flen);
1154         list_add(&n->list, &s->list);
1155         list_del_init(&s->list);
1156         if (!list_empty(&s->update))
1157             list_del_init(&s->update);
1158         free_string(&tp->freemem, s);
1159         s = n;
1160     }
1161 
1162     /* Write 3270 data fragment. */
1163     cp = s->string;
1164     *cp++ = TO_SBA;
1165     *cp++ = 0;
1166     *cp++ = 0;
1167 
1168     highlight = TAX_RESET;
1169     f_color = TAC_RESET;
1170     for (i = 0, cell = line->cells; i < line->len; i++, cell++) {
1171         if (cell->highlight != highlight) {
1172             *cp++ = TO_SA;
1173             *cp++ = TAT_EXTHI;
1174             *cp++ = cell->highlight;
1175             highlight = cell->highlight;
1176         }
1177         if (cell->f_color != f_color) {
1178             *cp++ = TO_SA;
1179             *cp++ = TAT_COLOR;
1180             *cp++ = cell->f_color;
1181             f_color = cell->f_color;
1182         }
1183         *cp++ = cell->character;
1184     }
1185     if (highlight != TAX_RESET) {
1186         *cp++ = TO_SA;
1187         *cp++ = TAT_EXTHI;
1188         *cp++ = TAX_RESET;
1189     }
1190     if (f_color != TAC_RESET) {
1191         *cp++ = TO_SA;
1192         *cp++ = TAT_COLOR;
1193         *cp++ = TAC_RESET;
1194     }
1195     if (line->len < tp->view.cols) {
1196         *cp++ = TO_RA;
1197         *cp++ = 0;
1198         *cp++ = 0;
1199         *cp++ = 0;
1200     }
1201 
1202     if (tp->nr_up + line_nr < tp->view.rows - 2) {
1203         /* Line is currently visible on screen. */
1204         tty3270_update_string(tp, s, line_nr);
1205         /* Add line to update list. */
1206         if (list_empty(&s->update)) {
1207             list_add_tail(&s->update, &tp->update);
1208             tp->update_flags |= TTY_UPDATE_LIST;
1209         }
1210     }
1211 }
1212 
1213 /*
1214  * Do carriage return.
1215  */
1216 static void
1217 tty3270_cr(struct tty3270 *tp)
1218 {
1219     tp->cx = 0;
1220 }
1221 
1222 /*
1223  * Do line feed.
1224  */
1225 static void
1226 tty3270_lf(struct tty3270 *tp)
1227 {
1228     struct tty3270_line temp;
1229     int i;
1230 
1231     tty3270_convert_line(tp, tp->cy);
1232     if (tp->cy < tp->view.rows - 3) {
1233         tp->cy++;
1234         return;
1235     }
1236     /* Last line just filled up. Add new, blank line. */
1237     tty3270_blank_line(tp);
1238     temp = tp->screen[0];
1239     temp.len = 0;
1240     for (i = 0; i < tp->view.rows - 3; i++)
1241         tp->screen[i] = tp->screen[i+1];
1242     tp->screen[tp->view.rows - 3] = temp;
1243     tty3270_rebuild_update(tp);
1244 }
1245 
1246 static void
1247 tty3270_ri(struct tty3270 *tp)
1248 {
1249     if (tp->cy > 0) {
1250         tty3270_convert_line(tp, tp->cy);
1251         tp->cy--;
1252     }
1253 }
1254 
1255 /*
1256  * Insert characters at current position.
1257  */
1258 static void
1259 tty3270_insert_characters(struct tty3270 *tp, int n)
1260 {
1261     struct tty3270_line *line;
1262     int k;
1263 
1264     line = tp->screen + tp->cy;
1265     while (line->len < tp->cx) {
1266         line->cells[line->len].character = tp->view.ascebc[' '];
1267         line->cells[line->len].highlight = TAX_RESET;
1268         line->cells[line->len].f_color = TAC_RESET;
1269         line->len++;
1270     }
1271     if (n > tp->view.cols - tp->cx)
1272         n = tp->view.cols - tp->cx;
1273     k = min_t(int, line->len - tp->cx, tp->view.cols - tp->cx - n);
1274     while (k--)
1275         line->cells[tp->cx + n + k] = line->cells[tp->cx + k];
1276     line->len += n;
1277     if (line->len > tp->view.cols)
1278         line->len = tp->view.cols;
1279     while (n-- > 0) {
1280         line->cells[tp->cx + n].character = tp->view.ascebc[' '];
1281         line->cells[tp->cx + n].highlight = tp->highlight;
1282         line->cells[tp->cx + n].f_color = tp->f_color;
1283     }
1284 }
1285 
1286 /*
1287  * Delete characters at current position.
1288  */
1289 static void
1290 tty3270_delete_characters(struct tty3270 *tp, int n)
1291 {
1292     struct tty3270_line *line;
1293     int i;
1294 
1295     line = tp->screen + tp->cy;
1296     if (line->len <= tp->cx)
1297         return;
1298     if (line->len - tp->cx <= n) {
1299         line->len = tp->cx;
1300         return;
1301     }
1302     for (i = tp->cx; i + n < line->len; i++)
1303         line->cells[i] = line->cells[i + n];
1304     line->len -= n;
1305 }
1306 
1307 /*
1308  * Erase characters at current position.
1309  */
1310 static void
1311 tty3270_erase_characters(struct tty3270 *tp, int n)
1312 {
1313     struct tty3270_line *line;
1314     struct tty3270_cell *cell;
1315 
1316     line = tp->screen + tp->cy;
1317     while (line->len > tp->cx && n-- > 0) {
1318         cell = line->cells + tp->cx++;
1319         cell->character = ' ';
1320         cell->highlight = TAX_RESET;
1321         cell->f_color = TAC_RESET;
1322     }
1323     tp->cx += n;
1324     tp->cx = min_t(int, tp->cx, tp->view.cols - 1);
1325 }
1326 
1327 /*
1328  * Erase line, 3 different cases:
1329  *  Esc [ 0 K   Erase from current position to end of line inclusive
1330  *  Esc [ 1 K   Erase from beginning of line to current position inclusive
1331  *  Esc [ 2 K   Erase entire line (without moving cursor)
1332  */
1333 static void
1334 tty3270_erase_line(struct tty3270 *tp, int mode)
1335 {
1336     struct tty3270_line *line;
1337     struct tty3270_cell *cell;
1338     int i;
1339 
1340     line = tp->screen + tp->cy;
1341     if (mode == 0)
1342         line->len = tp->cx;
1343     else if (mode == 1) {
1344         for (i = 0; i < tp->cx; i++) {
1345             cell = line->cells + i;
1346             cell->character = ' ';
1347             cell->highlight = TAX_RESET;
1348             cell->f_color = TAC_RESET;
1349         }
1350         if (line->len <= tp->cx)
1351             line->len = tp->cx + 1;
1352     } else if (mode == 2)
1353         line->len = 0;
1354     tty3270_convert_line(tp, tp->cy);
1355 }
1356 
1357 /*
1358  * Erase display, 3 different cases:
1359  *  Esc [ 0 J   Erase from current position to bottom of screen inclusive
1360  *  Esc [ 1 J   Erase from top of screen to current position inclusive
1361  *  Esc [ 2 J   Erase entire screen (without moving the cursor)
1362  */
1363 static void
1364 tty3270_erase_display(struct tty3270 *tp, int mode)
1365 {
1366     int i;
1367 
1368     if (mode == 0) {
1369         tty3270_erase_line(tp, 0);
1370         for (i = tp->cy + 1; i < tp->view.rows - 2; i++) {
1371             tp->screen[i].len = 0;
1372             tty3270_convert_line(tp, i);
1373         }
1374     } else if (mode == 1) {
1375         for (i = 0; i < tp->cy; i++) {
1376             tp->screen[i].len = 0;
1377             tty3270_convert_line(tp, i);
1378         }
1379         tty3270_erase_line(tp, 1);
1380     } else if (mode == 2) {
1381         for (i = 0; i < tp->view.rows - 2; i++) {
1382             tp->screen[i].len = 0;
1383             tty3270_convert_line(tp, i);
1384         }
1385     }
1386     tty3270_rebuild_update(tp);
1387 }
1388 
1389 /*
1390  * Set attributes found in an escape sequence.
1391  *  Esc [ <attr> ; <attr> ; ... m
1392  */
1393 static void
1394 tty3270_set_attributes(struct tty3270 *tp)
1395 {
1396     static unsigned char f_colors[] = {
1397         TAC_DEFAULT, TAC_RED, TAC_GREEN, TAC_YELLOW, TAC_BLUE,
1398         TAC_PINK, TAC_TURQ, TAC_WHITE, 0, TAC_DEFAULT
1399     };
1400     int i, attr;
1401 
1402     for (i = 0; i <= tp->esc_npar; i++) {
1403         attr = tp->esc_par[i];
1404         switch (attr) {
1405         case 0:     /* Reset */
1406             tp->highlight = TAX_RESET;
1407             tp->f_color = TAC_RESET;
1408             break;
1409         /* Highlight. */
1410         case 4:     /* Start underlining. */
1411             tp->highlight = TAX_UNDER;
1412             break;
1413         case 5:     /* Start blink. */
1414             tp->highlight = TAX_BLINK;
1415             break;
1416         case 7:     /* Start reverse. */
1417             tp->highlight = TAX_REVER;
1418             break;
1419         case 24:    /* End underlining */
1420             if (tp->highlight == TAX_UNDER)
1421                 tp->highlight = TAX_RESET;
1422             break;
1423         case 25:    /* End blink. */
1424             if (tp->highlight == TAX_BLINK)
1425                 tp->highlight = TAX_RESET;
1426             break;
1427         case 27:    /* End reverse. */
1428             if (tp->highlight == TAX_REVER)
1429                 tp->highlight = TAX_RESET;
1430             break;
1431         /* Foreground color. */
1432         case 30:    /* Black */
1433         case 31:    /* Red */
1434         case 32:    /* Green */
1435         case 33:    /* Yellow */
1436         case 34:    /* Blue */
1437         case 35:    /* Magenta */
1438         case 36:    /* Cyan */
1439         case 37:    /* White */
1440         case 39:    /* Black */
1441             tp->f_color = f_colors[attr - 30];
1442             break;
1443         }
1444     }
1445 }
1446 
1447 static inline int
1448 tty3270_getpar(struct tty3270 *tp, int ix)
1449 {
1450     return (tp->esc_par[ix] > 0) ? tp->esc_par[ix] : 1;
1451 }
1452 
1453 static void
1454 tty3270_goto_xy(struct tty3270 *tp, int cx, int cy)
1455 {
1456     int max_cx = max(0, cx);
1457     int max_cy = max(0, cy);
1458 
1459     tp->cx = min_t(int, tp->view.cols - 1, max_cx);
1460     cy = min_t(int, tp->view.rows - 3, max_cy);
1461     if (cy != tp->cy) {
1462         tty3270_convert_line(tp, tp->cy);
1463         tp->cy = cy;
1464     }
1465 }
1466 
1467 /*
1468  * Process escape sequences. Known sequences:
1469  *  Esc 7           Save Cursor Position
1470  *  Esc 8           Restore Cursor Position
1471  *  Esc [ Pn ; Pn ; .. m    Set attributes
1472  *  Esc [ Pn ; Pn H     Cursor Position
1473  *  Esc [ Pn ; Pn f     Cursor Position
1474  *  Esc [ Pn A          Cursor Up
1475  *  Esc [ Pn B          Cursor Down
1476  *  Esc [ Pn C          Cursor Forward
1477  *  Esc [ Pn D          Cursor Backward
1478  *  Esc [ Pn G          Cursor Horizontal Absolute
1479  *  Esc [ Pn X          Erase Characters
1480  *  Esc [ Ps J          Erase in Display
1481  *  Esc [ Ps K          Erase in Line
1482  * // FIXME: add all the new ones.
1483  *
1484  *  Pn is a numeric parameter, a string of zero or more decimal digits.
1485  *  Ps is a selective parameter.
1486  */
1487 static void
1488 tty3270_escape_sequence(struct tty3270 *tp, char ch)
1489 {
1490     enum { ESnormal, ESesc, ESsquare, ESgetpars };
1491 
1492     if (tp->esc_state == ESnormal) {
1493         if (ch == 0x1b)
1494             /* Starting new escape sequence. */
1495             tp->esc_state = ESesc;
1496         return;
1497     }
1498     if (tp->esc_state == ESesc) {
1499         tp->esc_state = ESnormal;
1500         switch (ch) {
1501         case '[':
1502             tp->esc_state = ESsquare;
1503             break;
1504         case 'E':
1505             tty3270_cr(tp);
1506             tty3270_lf(tp);
1507             break;
1508         case 'M':
1509             tty3270_ri(tp);
1510             break;
1511         case 'D':
1512             tty3270_lf(tp);
1513             break;
1514         case 'Z':       /* Respond ID. */
1515             kbd_puts_queue(&tp->port, "\033[?6c");
1516             break;
1517         case '7':       /* Save cursor position. */
1518             tp->saved_cx = tp->cx;
1519             tp->saved_cy = tp->cy;
1520             tp->saved_highlight = tp->highlight;
1521             tp->saved_f_color = tp->f_color;
1522             break;
1523         case '8':       /* Restore cursor position. */
1524             tty3270_convert_line(tp, tp->cy);
1525             tty3270_goto_xy(tp, tp->saved_cx, tp->saved_cy);
1526             tp->highlight = tp->saved_highlight;
1527             tp->f_color = tp->saved_f_color;
1528             break;
1529         case 'c':       /* Reset terminal. */
1530             tp->cx = tp->saved_cx = 0;
1531             tp->cy = tp->saved_cy = 0;
1532             tp->highlight = tp->saved_highlight = TAX_RESET;
1533             tp->f_color = tp->saved_f_color = TAC_RESET;
1534             tty3270_erase_display(tp, 2);
1535             break;
1536         }
1537         return;
1538     }
1539     if (tp->esc_state == ESsquare) {
1540         tp->esc_state = ESgetpars;
1541         memset(tp->esc_par, 0, sizeof(tp->esc_par));
1542         tp->esc_npar = 0;
1543         tp->esc_ques = (ch == '?');
1544         if (tp->esc_ques)
1545             return;
1546     }
1547     if (tp->esc_state == ESgetpars) {
1548         if (ch == ';' && tp->esc_npar < ESCAPE_NPAR - 1) {
1549             tp->esc_npar++;
1550             return;
1551         }
1552         if (ch >= '0' && ch <= '9') {
1553             tp->esc_par[tp->esc_npar] *= 10;
1554             tp->esc_par[tp->esc_npar] += ch - '0';
1555             return;
1556         }
1557     }
1558     tp->esc_state = ESnormal;
1559     if (ch == 'n' && !tp->esc_ques) {
1560         if (tp->esc_par[0] == 5)        /* Status report. */
1561             kbd_puts_queue(&tp->port, "\033[0n");
1562         else if (tp->esc_par[0] == 6) { /* Cursor report. */
1563             char buf[40];
1564             sprintf(buf, "\033[%d;%dR", tp->cy + 1, tp->cx + 1);
1565             kbd_puts_queue(&tp->port, buf);
1566         }
1567         return;
1568     }
1569     if (tp->esc_ques)
1570         return;
1571     switch (ch) {
1572     case 'm':
1573         tty3270_set_attributes(tp);
1574         break;
1575     case 'H':   /* Set cursor position. */
1576     case 'f':
1577         tty3270_goto_xy(tp, tty3270_getpar(tp, 1) - 1,
1578                 tty3270_getpar(tp, 0) - 1);
1579         break;
1580     case 'd':   /* Set y position. */
1581         tty3270_goto_xy(tp, tp->cx, tty3270_getpar(tp, 0) - 1);
1582         break;
1583     case 'A':   /* Cursor up. */
1584     case 'F':
1585         tty3270_goto_xy(tp, tp->cx, tp->cy - tty3270_getpar(tp, 0));
1586         break;
1587     case 'B':   /* Cursor down. */
1588     case 'e':
1589     case 'E':
1590         tty3270_goto_xy(tp, tp->cx, tp->cy + tty3270_getpar(tp, 0));
1591         break;
1592     case 'C':   /* Cursor forward. */
1593     case 'a':
1594         tty3270_goto_xy(tp, tp->cx + tty3270_getpar(tp, 0), tp->cy);
1595         break;
1596     case 'D':   /* Cursor backward. */
1597         tty3270_goto_xy(tp, tp->cx - tty3270_getpar(tp, 0), tp->cy);
1598         break;
1599     case 'G':   /* Set x position. */
1600     case '`':
1601         tty3270_goto_xy(tp, tty3270_getpar(tp, 0), tp->cy);
1602         break;
1603     case 'X':   /* Erase Characters. */
1604         tty3270_erase_characters(tp, tty3270_getpar(tp, 0));
1605         break;
1606     case 'J':   /* Erase display. */
1607         tty3270_erase_display(tp, tp->esc_par[0]);
1608         break;
1609     case 'K':   /* Erase line. */
1610         tty3270_erase_line(tp, tp->esc_par[0]);
1611         break;
1612     case 'P':   /* Delete characters. */
1613         tty3270_delete_characters(tp, tty3270_getpar(tp, 0));
1614         break;
1615     case '@':   /* Insert characters. */
1616         tty3270_insert_characters(tp, tty3270_getpar(tp, 0));
1617         break;
1618     case 's':   /* Save cursor position. */
1619         tp->saved_cx = tp->cx;
1620         tp->saved_cy = tp->cy;
1621         tp->saved_highlight = tp->highlight;
1622         tp->saved_f_color = tp->f_color;
1623         break;
1624     case 'u':   /* Restore cursor position. */
1625         tty3270_convert_line(tp, tp->cy);
1626         tty3270_goto_xy(tp, tp->saved_cx, tp->saved_cy);
1627         tp->highlight = tp->saved_highlight;
1628         tp->f_color = tp->saved_f_color;
1629         break;
1630     }
1631 }
1632 
1633 /*
1634  * String write routine for 3270 ttys
1635  */
1636 static void
1637 tty3270_do_write(struct tty3270 *tp, struct tty_struct *tty,
1638         const unsigned char *buf, int count)
1639 {
1640     int i_msg, i;
1641 
1642     spin_lock_bh(&tp->view.lock);
1643     for (i_msg = 0; !tty->flow.stopped && i_msg < count; i_msg++) {
1644         if (tp->esc_state != 0) {
1645             /* Continue escape sequence. */
1646             tty3270_escape_sequence(tp, buf[i_msg]);
1647             continue;
1648         }
1649 
1650         switch (buf[i_msg]) {
1651         case 0x07:      /* '\a' -- Alarm */
1652             tp->wcc |= TW_PLUSALARM;
1653             break;
1654         case 0x08:      /* Backspace. */
1655             if (tp->cx > 0) {
1656                 tp->cx--;
1657                 tty3270_put_character(tp, ' ');
1658             }
1659             break;
1660         case 0x09:      /* '\t' -- Tabulate */
1661             for (i = tp->cx % 8; i < 8; i++) {
1662                 if (tp->cx >= tp->view.cols) {
1663                     tty3270_cr(tp);
1664                     tty3270_lf(tp);
1665                     break;
1666                 }
1667                 tty3270_put_character(tp, ' ');
1668                 tp->cx++;
1669             }
1670             break;
1671         case 0x0a:      /* '\n' -- New Line */
1672             tty3270_cr(tp);
1673             tty3270_lf(tp);
1674             break;
1675         case 0x0c:      /* '\f' -- Form Feed */
1676             tty3270_erase_display(tp, 2);
1677             tp->cx = tp->cy = 0;
1678             break;
1679         case 0x0d:      /* '\r' -- Carriage Return */
1680             tp->cx = 0;
1681             break;
1682         case 0x0f:      /* SuSE "exit alternate mode" */
1683             break;
1684         case 0x1b:      /* Start escape sequence. */
1685             tty3270_escape_sequence(tp, buf[i_msg]);
1686             break;
1687         default:        /* Insert normal character. */
1688             if (tp->cx >= tp->view.cols) {
1689                 tty3270_cr(tp);
1690                 tty3270_lf(tp);
1691             }
1692             tty3270_put_character(tp, buf[i_msg]);
1693             tp->cx++;
1694             break;
1695         }
1696     }
1697     /* Convert current line to 3270 data fragment. */
1698     tty3270_convert_line(tp, tp->cy);
1699 
1700     /* Setup timer to update display after 1/10 second */
1701     if (!timer_pending(&tp->timer))
1702         tty3270_set_timer(tp, HZ/10);
1703 
1704     spin_unlock_bh(&tp->view.lock);
1705 }
1706 
1707 /*
1708  * String write routine for 3270 ttys
1709  */
1710 static int
1711 tty3270_write(struct tty_struct * tty,
1712           const unsigned char *buf, int count)
1713 {
1714     struct tty3270 *tp;
1715 
1716     tp = tty->driver_data;
1717     if (!tp)
1718         return 0;
1719     if (tp->char_count > 0) {
1720         tty3270_do_write(tp, tty, tp->char_buf, tp->char_count);
1721         tp->char_count = 0;
1722     }
1723     tty3270_do_write(tp, tty, buf, count);
1724     return count;
1725 }
1726 
1727 /*
1728  * Put single characters to the ttys character buffer
1729  */
1730 static int tty3270_put_char(struct tty_struct *tty, unsigned char ch)
1731 {
1732     struct tty3270 *tp;
1733 
1734     tp = tty->driver_data;
1735     if (!tp || tp->char_count >= TTY3270_CHAR_BUF_SIZE)
1736         return 0;
1737     tp->char_buf[tp->char_count++] = ch;
1738     return 1;
1739 }
1740 
1741 /*
1742  * Flush all characters from the ttys characeter buffer put there
1743  * by tty3270_put_char.
1744  */
1745 static void
1746 tty3270_flush_chars(struct tty_struct *tty)
1747 {
1748     struct tty3270 *tp;
1749 
1750     tp = tty->driver_data;
1751     if (!tp)
1752         return;
1753     if (tp->char_count > 0) {
1754         tty3270_do_write(tp, tty, tp->char_buf, tp->char_count);
1755         tp->char_count = 0;
1756     }
1757 }
1758 
1759 /*
1760  * Check for visible/invisible input switches
1761  */
1762 static void
1763 tty3270_set_termios(struct tty_struct *tty, struct ktermios *old)
1764 {
1765     struct tty3270 *tp;
1766     int new;
1767 
1768     tp = tty->driver_data;
1769     if (!tp)
1770         return;
1771     spin_lock_bh(&tp->view.lock);
1772     if (L_ICANON(tty)) {
1773         new = L_ECHO(tty) ? TF_INPUT: TF_INPUTN;
1774         if (new != tp->inattr) {
1775             tp->inattr = new;
1776             tty3270_update_prompt(tp, NULL, 0);
1777             tty3270_set_timer(tp, 1);
1778         }
1779     }
1780     spin_unlock_bh(&tp->view.lock);
1781 }
1782 
1783 /*
1784  * Disable reading from a 3270 tty
1785  */
1786 static void
1787 tty3270_throttle(struct tty_struct * tty)
1788 {
1789     struct tty3270 *tp;
1790 
1791     tp = tty->driver_data;
1792     if (!tp)
1793         return;
1794     tp->throttle = 1;
1795 }
1796 
1797 /*
1798  * Enable reading from a 3270 tty
1799  */
1800 static void
1801 tty3270_unthrottle(struct tty_struct * tty)
1802 {
1803     struct tty3270 *tp;
1804 
1805     tp = tty->driver_data;
1806     if (!tp)
1807         return;
1808     tp->throttle = 0;
1809     if (tp->attn)
1810         tty3270_issue_read(tp, 1);
1811 }
1812 
1813 /*
1814  * Hang up the tty device.
1815  */
1816 static void
1817 tty3270_hangup(struct tty_struct *tty)
1818 {
1819     struct tty3270 *tp;
1820 
1821     tp = tty->driver_data;
1822     if (!tp)
1823         return;
1824     spin_lock_bh(&tp->view.lock);
1825     tp->cx = tp->saved_cx = 0;
1826     tp->cy = tp->saved_cy = 0;
1827     tp->highlight = tp->saved_highlight = TAX_RESET;
1828     tp->f_color = tp->saved_f_color = TAC_RESET;
1829     tty3270_blank_screen(tp);
1830     while (tp->nr_lines < tp->view.rows - 2)
1831         tty3270_blank_line(tp);
1832     tp->update_flags = TTY_UPDATE_ALL;
1833     spin_unlock_bh(&tp->view.lock);
1834     tty3270_set_timer(tp, 1);
1835 }
1836 
1837 static void
1838 tty3270_wait_until_sent(struct tty_struct *tty, int timeout)
1839 {
1840 }
1841 
1842 static int tty3270_ioctl(struct tty_struct *tty, unsigned int cmd,
1843              unsigned long arg)
1844 {
1845     struct tty3270 *tp;
1846 
1847     tp = tty->driver_data;
1848     if (!tp)
1849         return -ENODEV;
1850     if (tty_io_error(tty))
1851         return -EIO;
1852     return kbd_ioctl(tp->kbd, cmd, arg);
1853 }
1854 
1855 #ifdef CONFIG_COMPAT
1856 static long tty3270_compat_ioctl(struct tty_struct *tty,
1857                  unsigned int cmd, unsigned long arg)
1858 {
1859     struct tty3270 *tp;
1860 
1861     tp = tty->driver_data;
1862     if (!tp)
1863         return -ENODEV;
1864     if (tty_io_error(tty))
1865         return -EIO;
1866     return kbd_ioctl(tp->kbd, cmd, (unsigned long)compat_ptr(arg));
1867 }
1868 #endif
1869 
1870 static const struct tty_operations tty3270_ops = {
1871     .install = tty3270_install,
1872     .cleanup = tty3270_cleanup,
1873     .open = tty3270_open,
1874     .close = tty3270_close,
1875     .write = tty3270_write,
1876     .put_char = tty3270_put_char,
1877     .flush_chars = tty3270_flush_chars,
1878     .write_room = tty3270_write_room,
1879     .throttle = tty3270_throttle,
1880     .unthrottle = tty3270_unthrottle,
1881     .hangup = tty3270_hangup,
1882     .wait_until_sent = tty3270_wait_until_sent,
1883     .ioctl = tty3270_ioctl,
1884 #ifdef CONFIG_COMPAT
1885     .compat_ioctl = tty3270_compat_ioctl,
1886 #endif
1887     .set_termios = tty3270_set_termios
1888 };
1889 
1890 static void tty3270_create_cb(int minor)
1891 {
1892     tty_register_device(tty3270_driver, minor - RAW3270_FIRSTMINOR, NULL);
1893 }
1894 
1895 static void tty3270_destroy_cb(int minor)
1896 {
1897     tty_unregister_device(tty3270_driver, minor - RAW3270_FIRSTMINOR);
1898 }
1899 
1900 static struct raw3270_notifier tty3270_notifier =
1901 {
1902     .create = tty3270_create_cb,
1903     .destroy = tty3270_destroy_cb,
1904 };
1905 
1906 /*
1907  * 3270 tty registration code called from tty_init().
1908  * Most kernel services (incl. kmalloc) are available at this poimt.
1909  */
1910 static int __init tty3270_init(void)
1911 {
1912     struct tty_driver *driver;
1913     int ret;
1914 
1915     driver = tty_alloc_driver(RAW3270_MAXDEVS,
1916                   TTY_DRIVER_REAL_RAW |
1917                   TTY_DRIVER_DYNAMIC_DEV |
1918                   TTY_DRIVER_RESET_TERMIOS);
1919     if (IS_ERR(driver))
1920         return PTR_ERR(driver);
1921 
1922     /*
1923      * Initialize the tty_driver structure
1924      * Entries in tty3270_driver that are NOT initialized:
1925      * proc_entry, set_termios, flush_buffer, set_ldisc, write_proc
1926      */
1927     driver->driver_name = "tty3270";
1928     driver->name = "3270/tty";
1929     driver->major = IBM_TTY3270_MAJOR;
1930     driver->minor_start = RAW3270_FIRSTMINOR;
1931     driver->name_base = RAW3270_FIRSTMINOR;
1932     driver->type = TTY_DRIVER_TYPE_SYSTEM;
1933     driver->subtype = SYSTEM_TYPE_TTY;
1934     driver->init_termios = tty_std_termios;
1935     tty_set_operations(driver, &tty3270_ops);
1936     ret = tty_register_driver(driver);
1937     if (ret) {
1938         tty_driver_kref_put(driver);
1939         return ret;
1940     }
1941     tty3270_driver = driver;
1942     raw3270_register_notifier(&tty3270_notifier);
1943     return 0;
1944 }
1945 
1946 static void __exit
1947 tty3270_exit(void)
1948 {
1949     struct tty_driver *driver;
1950 
1951     raw3270_unregister_notifier(&tty3270_notifier);
1952     driver = tty3270_driver;
1953     tty3270_driver = NULL;
1954     tty_unregister_driver(driver);
1955     tty_driver_kref_put(driver);
1956     tty3270_del_views();
1957 }
1958 
1959 MODULE_LICENSE("GPL");
1960 MODULE_ALIAS_CHARDEV_MAJOR(IBM_TTY3270_MAJOR);
1961 
1962 module_init(tty3270_init);
1963 module_exit(tty3270_exit);