10 #include <linux/module.h>
11 #include <linux/types.h>
12 #include <linux/kdev_t.h>
13 #include <linux/tty.h>
19 #include <linux/slab.h>
26 #include <asm/uaccess.h>
32 #define TTY3270_CHAR_BUF_SIZE 256
33 #define TTY3270_OUTPUT_BUFFER_SIZE 1024
34 #define TTY3270_STRING_PAGES 5
37 static int tty3270_max_index;
111 #define TTY_UPDATE_ERASE 1
112 #define TTY_UPDATE_LIST 2
113 #define TTY_UPDATE_INPUT 4
114 #define TTY_UPDATE_STATUS 8
115 #define TTY_UPDATE_ALL 16
117 static void tty3270_update(
struct tty3270 *);
122 static void tty3270_set_timer(
struct tty3270 *tp,
int expires)
144 if (count > tp->
view.cols * 2 - 11)
145 count = tp->
view.cols * 2 - 11;
149 if (count < tp->view.cols * 2 - 11) {
152 off = tp->
view.cols * tp->
view.rows - 9;
161 tty3270_create_prompt(
struct tty3270 *tp)
163 static const unsigned char blueprint[] =
170 line = alloc_string(&tp->
freemem,
171 sizeof(blueprint) + tp->
view.cols * 2 - 9);
176 line->
len =
sizeof(blueprint);
178 offset = tp->
view.cols * (tp->
view.rows - 2);
180 offset = tp->
view.cols * tp->
view.rows - 9;
192 tty3270_update_status(
struct tty3270 * tp)
196 str = (tp->
nr_up != 0) ?
"History" :
"Running";
198 codepage_convert(tp->
view.ascebc, tp->
status->string + 8, 7);
203 tty3270_create_status(
struct tty3270 * tp)
205 static const unsigned char blueprint[] =
207 0, 0, 0, 0, 0, 0, 0,
TO_SF,
TF_LOG,
TO_SA,
TAT_COLOR,
212 line = alloc_string(&tp->
freemem,
sizeof(blueprint));
217 offset = tp->
view.cols * tp->
view.rows - 9;
226 tty3270_update_string(
struct tty3270 *tp,
struct string *line,
int nr)
235 tp->
view.cols * (nr + 1));
242 tty3270_rebuild_update(
struct tty3270 *tp)
252 list_del_init(&s->
update);
253 line = tp->view.
rows - 3;
260 tty3270_update_string(tp, s, line);
261 list_add(&s->update, &tp->
update);
273 tty3270_alloc_string(
struct tty3270 *tp,
size_t size)
277 s = alloc_string(&tp->
freemem, size);
283 if (!list_empty(&s->
update))
286 if (free_string(&tp->
freemem, s) >= size)
289 s = alloc_string(&tp->
freemem, size);
291 if (tp->
nr_up != 0 &&
294 tty3270_rebuild_update(tp);
295 tty3270_update_status(tp);
304 tty3270_blank_line(
struct tty3270 *tp)
306 static const unsigned char blueprint[] =
311 s = tty3270_alloc_string(tp,
sizeof(blueprint));
313 s->
len =
sizeof(blueprint);
331 tty3270_set_timer(tp, 1);
341 tty3270_update(
struct tty3270 *tp)
343 static char invalid_sba[2] = { 0xff, 0xff };
345 unsigned long updated;
352 tty3270_set_timer(tp, 1);
356 spin_lock(&tp->
view.lock);
359 tty3270_rebuild_update(tp);
360 tty3270_update_status(tp);
406 list_del_init(&s->
update);
409 if (list_empty(&tp->
update))
412 wrq->
callback = tty3270_write_callback;
417 tty3270_set_timer(tp, 1);
422 spin_unlock(&tp->
view.lock);
429 tty3270_rcl_add(
struct tty3270 *tp,
char *input,
int len)
442 s = tty3270_alloc_string(tp, len);
449 tty3270_rcl_backward(
struct kbd_data *kbd)
454 spin_lock_bh(&tp->
view.lock);
464 tty3270_update_prompt(tp, s->
string, s->
len);
466 tty3270_update_prompt(tp,
NULL, 0);
467 tty3270_set_timer(tp, 1);
469 spin_unlock_bh(&tp->
view.lock);
476 tty3270_exit_tty(
struct kbd_data *kbd)
487 tty3270_scroll_forward(
struct kbd_data *kbd)
492 spin_lock_bh(&tp->
view.lock);
496 if (nr_up != tp->
nr_up) {
498 tty3270_rebuild_update(tp);
499 tty3270_update_status(tp);
500 tty3270_set_timer(tp, 1);
502 spin_unlock_bh(&tp->
view.lock);
509 tty3270_scroll_backward(
struct kbd_data *kbd)
514 spin_lock_bh(&tp->
view.lock);
518 if (nr_up != tp->
nr_up) {
520 tty3270_rebuild_update(tp);
521 tty3270_update_status(tp);
522 tty3270_set_timer(tp, 1);
524 spin_unlock_bh(&tp->
view.lock);
533 static char kreset_data =
TW_KR;
538 spin_lock_bh(&tp->
view.lock);
546 if (tp->
input->string[0] == 0x7d) {
548 input = tp->
input->string + 6;
551 tty3270_rcl_add(tp, input, len);
554 tty3270_rebuild_update(tp);
555 tty3270_update_status(tp);
558 tty3270_update_prompt(tp,
NULL, 0);
559 tty3270_set_timer(tp, 1);
560 }
else if (tp->
input->string[0] == 0x6d) {
563 tty3270_set_timer(tp, 1);
565 spin_unlock_bh(&tp->
view.lock);
580 raw3270_put_view(&tp->
view);
590 raw3270_get_view(rq->
view);
592 tasklet_schedule(&tp->
readlet);
599 tty3270_issue_read(
struct tty3270 *tp,
int lock)
608 rrq->
callback = tty3270_read_callback;
632 tty3270_set_timer(tp, 1);
650 tty3270_issue_read(tp, 0);
669 tty3270_alloc_view(
void)
682 INIT_LIST_HEAD(&tp->
lines);
683 INIT_LIST_HEAD(&tp->
update);
690 (
void (*)(
unsigned long)) tty3270_read_tasklet,
691 (
unsigned long) tp->
read);
698 add_string_memory(&tp->
freemem,
702 if (IS_ERR(tp->
write))
705 if (IS_ERR(tp->
read))
735 tty3270_free_view(
struct tty3270 *tp)
754 tty3270_alloc_screen(
struct tty3270 *tp)
763 for (lines = 0; lines < tp->
view.rows - 2; lines++) {
766 if (!tp->
screen[lines].cells)
782 tty3270_free_screen(
struct tty3270 *tp)
786 for (lines = 0; lines < tp->
view.rows - 2; lines++)
804 raw3270_put_view(&tp->
view);
816 tty3270_free_screen(tp);
817 tty3270_free_view(tp);
824 tty3270_del_views(
void)
828 for (i = 0; i < tty3270_max_index; i++) {
837 .activate = tty3270_activate,
838 .deactivate = tty3270_deactivate,
839 .intv = (
void *) tty3270_irq,
867 if (tty3270_max_index < tty->
index + 1)
868 tty3270_max_index = tty->
index + 1;
871 if (PTR_ERR(view) == -
ENODEV)
875 tp = tty3270_alloc_view();
882 tty3270_free_view(tp);
886 rc = tty3270_alloc_screen(tp);
888 raw3270_put_view(&tp->
view);
898 tty3270_create_prompt(tp);
899 tty3270_create_status(tp);
900 tty3270_update_status(tp);
903 for (i = 0; i < tp->
view.rows - 2; i++)
904 tty3270_blank_line(tp);
917 raw3270_put_view(&tp->
view);
943 static void tty3270_cleanup(
struct tty_struct *tty)
948 raw3270_put_view(&tp->
view);
964 static void tty3270_put_character(
struct tty3270 *tp,
char ch)
970 if (line->
len <= tp->
cx) {
971 while (line->
len < tp->
cx) {
990 tty3270_convert_line(
struct tty3270 *tp,
int line_nr)
995 unsigned char highlight;
996 unsigned char f_color;
1002 line = tp->
screen + line_nr;
1006 for (i = 0, cell = line->
cells; i < line->len; i++, cell++) {
1011 if (cell->
f_color != f_color) {
1020 if (line->
len < tp->
view.cols)
1024 i = tp->
view.rows - 2 - line_nr;
1031 if (s->len != flen) {
1033 n = tty3270_alloc_string(tp, flen);
1035 list_del_init(&s->
list);
1036 if (!list_empty(&s->
update))
1037 list_del_init(&s->
update);
1050 for (i = 0, cell = line->
cells; i < line->len; i++, cell++) {
1057 if (cell->
f_color != f_color) {
1075 if (line->
len < tp->
view.cols) {
1082 if (tp->
nr_up + line_nr < tp->view.
rows - 2) {
1084 tty3270_update_string(tp, s, line_nr);
1086 if (list_empty(&s->
update)) {
1097 tty3270_cr(
struct tty3270 *tp)
1106 tty3270_lf(
struct tty3270 *tp)
1111 tty3270_convert_line(tp, tp->
cy);
1112 if (tp->
cy < tp->
view.rows - 3) {
1117 tty3270_blank_line(tp);
1120 for (i = 0; i < tp->
view.rows - 3; i++)
1123 tty3270_rebuild_update(tp);
1127 tty3270_ri(
struct tty3270 *tp)
1130 tty3270_convert_line(tp, tp->
cy);
1139 tty3270_insert_characters(
struct tty3270 *tp,
int n)
1145 while (line->
len < tp->
cx) {
1146 line->
cells[line->
len].character = tp->
view.ascebc[
' '];
1151 if (n > tp->
view.cols - tp->
cx)
1152 n = tp->
view.cols - tp->
cx;
1157 if (line->
len > tp->
view.cols)
1160 line->
cells[tp->
cx +
n].character = tp->
view.ascebc[
' '];
1170 tty3270_delete_characters(
struct tty3270 *tp,
int n)
1176 if (line->
len <= tp->
cx)
1178 if (line->
len - tp->
cx <= n) {
1182 for (i = tp->
cx; i + n < line->len; i++)
1191 tty3270_erase_characters(
struct tty3270 *tp,
int n)
1197 while (line->
len > tp->
cx && n-- > 0) {
1198 cell = line->
cells + tp->
cx++;
1223 else if (mode == 1) {
1224 for (i = 0; i < tp->
cx; i++) {
1230 if (line->
len <= tp->
cx)
1231 line->
len = tp->
cx + 1;
1232 }
else if (mode == 2)
1234 tty3270_convert_line(tp, tp->
cy);
1244 tty3270_erase_display(
struct tty3270 *tp,
int mode)
1249 tty3270_erase_line(tp, 0);
1250 for (i = tp->
cy + 1; i < tp->view.
rows - 2; i++) {
1252 tty3270_convert_line(tp, i);
1254 }
else if (mode == 1) {
1255 for (i = 0; i < tp->
cy; i++) {
1257 tty3270_convert_line(tp, i);
1259 tty3270_erase_line(tp, 1);
1260 }
else if (mode == 2) {
1261 for (i = 0; i < tp->
view.rows - 2; i++) {
1263 tty3270_convert_line(tp, i);
1266 tty3270_rebuild_update(tp);
1274 tty3270_set_attributes(
struct tty3270 *tp)
1276 static unsigned char f_colors[] = {
1282 for (i = 0; i <= tp->
esc_npar; i++) {
1321 tp->
f_color = f_colors[attr - 30];
1328 tty3270_getpar(
struct tty3270 *tp,
int ix)
1334 tty3270_goto_xy(
struct tty3270 *tp,
int cx,
int cy)
1336 int max_cx =
max(0, cx);
1337 int max_cy =
max(0, cy);
1340 cy =
min_t(
int, tp->
view.rows - 3, max_cy);
1342 tty3270_convert_line(tp, tp->
cy);
1368 tty3270_escape_sequence(
struct tty3270 *tp,
char ch)
1395 kbd_puts_queue(&tp->
port,
"\033[?6c");
1404 tty3270_convert_line(tp, tp->
cy);
1414 tty3270_erase_display(tp, 2);
1432 if (ch >=
'0' && ch <=
'9') {
1441 kbd_puts_queue(&tp->
port,
"\033[0n");
1442 else if (tp->
esc_par[0] == 6) {
1444 sprintf(buf,
"\033[%d;%dR", tp->
cy + 1, tp->
cx + 1);
1445 kbd_puts_queue(&tp->
port, buf);
1453 tty3270_set_attributes(tp);
1457 tty3270_goto_xy(tp, tty3270_getpar(tp, 1) - 1,
1458 tty3270_getpar(tp, 0) - 1);
1461 tty3270_goto_xy(tp, tp->
cx, tty3270_getpar(tp, 0) - 1);
1465 tty3270_goto_xy(tp, tp->
cx, tp->
cy - tty3270_getpar(tp, 0));
1470 tty3270_goto_xy(tp, tp->
cx, tp->
cy + tty3270_getpar(tp, 0));
1474 tty3270_goto_xy(tp, tp->
cx + tty3270_getpar(tp, 0), tp->
cy);
1477 tty3270_goto_xy(tp, tp->
cx - tty3270_getpar(tp, 0), tp->
cy);
1481 tty3270_goto_xy(tp, tty3270_getpar(tp, 0), tp->
cy);
1484 tty3270_erase_characters(tp, tty3270_getpar(tp, 0));
1487 tty3270_erase_display(tp, tp->
esc_par[0]);
1490 tty3270_erase_line(tp, tp->
esc_par[0]);
1493 tty3270_delete_characters(tp, tty3270_getpar(tp, 0));
1496 tty3270_insert_characters(tp, tty3270_getpar(tp, 0));
1505 tty3270_convert_line(tp, tp->
cy);
1518 const unsigned char *
buf,
int count)
1522 spin_lock_bh(&tp->
view.lock);
1523 for (i_msg = 0; !tty->
stopped && i_msg <
count; i_msg++) {
1526 tty3270_escape_sequence(tp, buf[i_msg]);
1530 switch (buf[i_msg]) {
1537 tty3270_put_character(tp,
' ');
1541 for (i = tp->
cx % 8; i < 8; i++) {
1542 if (tp->
cx >= tp->
view.cols) {
1547 tty3270_put_character(tp,
' ');
1556 tty3270_erase_display(tp, 2);
1557 tp->
cx = tp->
cy = 0;
1565 tty3270_escape_sequence(tp, buf[i_msg]);
1568 if (tp->
cx >= tp->
view.cols) {
1572 tty3270_put_character(tp, buf[i_msg]);
1578 tty3270_convert_line(tp, tp->
cy);
1581 if (!timer_pending(&tp->
timer))
1582 tty3270_set_timer(tp,
HZ/10);
1584 spin_unlock_bh(&tp->
view.lock);
1592 const unsigned char *buf,
int count)
1603 tty3270_do_write(tp, tty, buf, count);
1610 static int tty3270_put_char(
struct tty_struct *tty,
unsigned char ch)
1645 tty3270_chars_in_buffer(
struct tty_struct *tty)
1667 spin_lock_bh(&tp->
view.lock);
1672 tty3270_update_prompt(tp,
NULL, 0);
1673 tty3270_set_timer(tp, 1);
1676 spin_unlock_bh(&tp->
view.lock);
1706 tty3270_issue_read(tp, 1);
1719 tty3270_wait_until_sent(
struct tty_struct *tty,
int timeout)
1723 static int tty3270_ioctl(
struct tty_struct *tty,
unsigned int cmd,
1736 #ifdef CONFIG_COMPAT
1737 static long tty3270_compat_ioctl(
struct tty_struct *tty,
1738 unsigned int cmd,
unsigned long arg)
1747 return kbd_ioctl(tp->
kbd, cmd, (
unsigned long)compat_ptr(arg));
1752 .install = tty3270_install,
1753 .cleanup = tty3270_cleanup,
1754 .close = tty3270_close,
1755 .write = tty3270_write,
1756 .put_char = tty3270_put_char,
1757 .flush_chars = tty3270_flush_chars,
1758 .write_room = tty3270_write_room,
1759 .chars_in_buffer = tty3270_chars_in_buffer,
1760 .flush_buffer = tty3270_flush_buffer,
1761 .throttle = tty3270_throttle,
1762 .unthrottle = tty3270_unthrottle,
1763 .hangup = tty3270_hangup,
1764 .wait_until_sent = tty3270_wait_until_sent,
1765 .ioctl = tty3270_ioctl,
1766 #ifdef CONFIG_COMPAT
1767 .compat_ioctl = tty3270_compat_ioctl,
1769 .set_termios = tty3270_set_termios
1776 static int __init tty3270_init(
void)
1791 driver->
name =
"ttyTUB";
1814 tty3270_driver =
NULL;
1817 tty3270_del_views();