File: /usr/src/linux/drivers/s390/char/tubtty.c
1 /*
2 * IBM/3270 Driver -- Copyright (C) 2000, 2001 UTS Global LLC
3 *
4 * tubtty.c -- Linemode tty driver
5 *
6 *
7 *
8 *
9 *
10 * Author: Richard Hitt
11 */
12 #include <linux/config.h>
13 #include "tubio.h"
14
15 /* Initialization & uninitialization for tubtty */
16 int tty3270_init(void);
17 void tty3270_fini(void);
18
19 /* Interface routines from the upper tty layer to the tty driver */
20 static int tty3270_open(struct tty_struct *, struct file *);
21 static void tty3270_close(struct tty_struct *, struct file *);
22 static int tty3270_write(struct tty_struct *, int,
23 const unsigned char *, int);
24 static void tty3270_put_char(struct tty_struct *, unsigned char);
25 static void tty3270_flush_chars(struct tty_struct *);
26 static int tty3270_write_room(struct tty_struct *);
27 static int tty3270_chars_in_buffer(struct tty_struct *);
28 static int tty3270_ioctl(struct tty_struct *, struct file *,
29 unsigned int cmd, unsigned long arg);
30 static void tty3270_set_termios(struct tty_struct *, struct termios *);
31 static void tty3270_hangup(struct tty_struct *);
32 static void tty3270_flush_buffer(struct tty_struct *);
33 static int tty3270_read_proc(char *, char **, off_t, int, int *, void *);
34 static int tty3270_write_proc(struct file *, const char *,
35 unsigned long, void *);
36
37 /* tty3270 utility functions */
38 static void tty3270_bh(void *);
39 void tty3270_sched_bh(tub_t *);
40 static int tty3270_wait(tub_t *, long *);
41 void tty3270_int(tub_t *, devstat_t *);
42 int tty3270_try_logging(tub_t *);
43 static void tty3270_start_input(tub_t *);
44 static void tty3270_do_input(tub_t *);
45 static void tty3270_do_enter(tub_t *, char *, int);
46 static void tty3270_do_showi(tub_t *, char *, int);
47 int tty3270_io(tub_t *);
48 static int tty3270_show_tube(int, char *, int);
49
50 int tty3270_major = -1;
51 struct tty_driver tty3270_driver;
52 int tty3270_refcount;
53 struct tty_struct *tty3270_table[TUBMAXMINS];
54 struct termios *tty3270_termios[TUBMAXMINS];
55 struct termios *tty3270_termios_locked[TUBMAXMINS];
56 #ifdef CONFIG_TN3270_CONSOLE
57 int con3270_major = -1;
58 struct tty_driver con3270_driver;
59 int con3270_refcount;
60 struct tty_struct *con3270_table[1];
61 struct termios *con3270_termios[1];
62 struct termios *con3270_termios_locked[1];
63 #endif /* CONFIG_TN3270_CONSOLE */
64
65 int tty3270_proc_index;
66 int tty3270_proc_data;
67 int tty3270_proc_misc;
68 enum tubwhat tty3270_proc_what;
69
70 /*
71 * tty3270_init() -- Register the tty3270 driver
72 */
73 int
74 tty3270_init(void)
75 {
76 struct tty_driver *td = &tty3270_driver;
77 int rc;
78
79 /* Initialize for tty driver */
80 td->magic = TTY_DRIVER_MAGIC;
81 td->driver_name = "tty3270";
82 td->name = "tty3270";
83 td->major = IBM_TTY3270_MAJOR;
84 td->minor_start = 0;
85 td->num = TUBMAXMINS;
86 td->type = TTY_DRIVER_TYPE_SYSTEM;
87 td->subtype = SYSTEM_TYPE_TTY;
88 td->init_termios = tty_std_termios;
89 td->flags = TTY_DRIVER_RESET_TERMIOS;
90 #ifdef CONFIG_DEVFS_FS
91 td->flags |= TTY_DRIVER_NO_DEVFS;
92 #endif
93 td->refcount = &tty3270_refcount;
94 td->table = tty3270_table;
95 td->termios = tty3270_termios;
96 td->termios_locked = tty3270_termios_locked;
97
98 td->open = tty3270_open;
99 td->close = tty3270_close;
100 td->write = tty3270_write;
101 td->put_char = tty3270_put_char;
102 td->flush_chars = tty3270_flush_chars;
103 td->write_room = tty3270_write_room;
104 td->chars_in_buffer = tty3270_chars_in_buffer;
105 td->ioctl = tty3270_ioctl;
106 td->ioctl = NULL;
107 td->set_termios = tty3270_set_termios;
108 td->throttle = NULL;
109 td->unthrottle = NULL;
110 td->stop = NULL;
111 td->start = NULL;
112 td->hangup = tty3270_hangup;
113 td->break_ctl = NULL;
114 td->flush_buffer = tty3270_flush_buffer;
115 td->set_ldisc = NULL;
116 td->wait_until_sent = NULL;
117 td->send_xchar = NULL;
118 td->read_proc = tty3270_read_proc;
119 td->write_proc = tty3270_write_proc;
120
121 rc = tty_register_driver(td);
122 if (rc) {
123 printk(KERN_ERR "tty3270 registration failed with %d\n", rc);
124 } else {
125 tty3270_major = IBM_TTY3270_MAJOR;
126 if (td->proc_entry != NULL)
127 td->proc_entry->mode = S_IRUGO | S_IWUGO;
128 }
129 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
130 #ifdef CONFIG_TN3270_CONSOLE
131 if (CONSOLE_IS_3270) {
132 tty3270_con_driver = *td;
133 td = &tty3270_con_driver;
134 td->driver_name = "con3270";
135 td->name = "con3270";
136 td->major = MAJOR(S390_CONSOLE_DEV);
137 td->minor_start = MINOR(S390_CONSOLE_DEV);
138 td->num = 1;
139 td->refcount = &con3270_refcount;
140 td->table = con3270_table;
141 td->termios = con3270_termios;
142 td->termios_locked = con3270_termios_locked;
143
144 rc = tty_register_driver(td);
145 if (rc) {
146 printk(KERN_ERR
147 "con3270 registration failed with %d\n", rc);
148 } else {
149 con3270_major = MAJOR(S390_CONSOLE_DEV);
150 if (td->proc_entry != NULL)
151 td->proc_entry->mode = S_IRUGO | S_IWUGO;
152 }
153 }
154 #endif /* ifdef CONFIG_TN3270_CONSOLE */
155 #endif /* if LINUX_VERSION_CODE */
156
157 return rc;
158 }
159
160 /*
161 * tty3270_fini() -- Uninitialize linemode tubes
162 */
163 void
164 tty3270_fini(void)
165 {
166 if (tty3270_major != -1) {
167 tty_unregister_driver(&tty3270_driver);
168 tty3270_major = -1;
169 }
170 #ifdef CONFIG_TN3270_CONSOLE
171 if (CONSOLE_IS_3270 && con3270_major != -1) {
172 tty_unregister_driver(&con3270_driver);
173 con3270_major = -1;
174 }
175 #endif
176 }
177
178 static int
179 tty3270_open(struct tty_struct *tty, struct file *filp)
180 {
181 tub_t *tubp;
182 long flags;
183 int rc;
184 int cmd;
185
186 if ((tubp = TTY2TUB(tty)) == NULL) {
187 return -ENODEV;
188 }
189
190 tub_inc_use_count();
191 if ((rc = tty3270_wait(tubp, &flags)) != 0)
192 goto do_fail;
193 if (tubp->lnopen > 0) {
194 tubp->lnopen++;
195 TUBUNLOCK(tubp->irq, flags);
196 return 0;
197 }
198 if (tubp->flags & TUB_OPEN_STET) {
199 cmd = TBC_UPDLOG;
200 } else {
201 cmd = TBC_OPEN;
202 tubp->flags &= ~TUB_SIZED;
203 }
204 if ((rc = tty3270_size(tubp, &flags)) != 0)
205 goto do_fail;
206 if ((rc = tty3270_rcl_init(tubp)) != 0)
207 goto do_fail;
208 if ((rc = tty3270_aid_init(tubp)) != 0)
209 goto do_fail;
210 if ((rc = tty3270_scl_init(tubp)) != 0)
211 goto do_fail;
212 tubp->mode = TBM_LN;
213 tubp->intv = tty3270_int;
214 tubp->tty = tty;
215 tubp->lnopen = 1;
216 tty->driver_data = tubp;
217 tty->winsize.ws_row = tubp->geom_rows;
218 tty->winsize.ws_col = tubp->geom_cols;
219 tubp->tty_inattr = TF_INPUT;
220 tubp->cmd = cmd;
221 tty3270_build(tubp);
222 TUBUNLOCK(tubp->irq, flags);
223 return 0;
224
225 do_fail:
226 tty3270_scl_fini(tubp);
227 tty3270_aid_fini(tubp);
228 tty3270_rcl_fini(tubp);
229 TUBUNLOCK(tubp->irq, flags);
230 tub_dec_use_count();
231 return rc;
232 }
233
234 static void
235 tty3270_close(struct tty_struct *tty, struct file *filp)
236 {
237 tub_t *tubp;
238 long flags;
239
240 if ((tubp = tty->driver_data) == NULL)
241 return;
242
243 tty3270_wait(tubp, &flags);
244 if (--tubp->lnopen > 0)
245 goto do_return;
246 tubp->tty = NULL;
247 tty->driver_data = NULL;
248 tty3270_aid_fini(tubp);
249 tty3270_rcl_fini(tubp);
250 tty3270_scl_fini(tubp);
251 do_return:
252 tub_dec_use_count();
253 TUBUNLOCK(tubp->irq, flags);
254 }
255
256 static int
257 tty3270_write(struct tty_struct *tty, int fromuser,
258 const unsigned char *buf, int count)
259 {
260 tub_t *tubp;
261 long flags;
262 bcb_t obcb;
263 int rc = 0;
264
265 if ((tubp = tty->driver_data) == NULL)
266 return -1;
267
268 #ifdef CONFIG_TN3270_CONSOLE
269 if (CONSOLE_IS_3270 && tub3270_con_tubp == tubp)
270 tub3270_con_copy(tubp);
271 #endif /* CONFIG_TN3270_CONSOLE */
272
273 obcb.bc_buf = (char *)buf;
274 obcb.bc_len = obcb.bc_cnt = obcb.bc_wr = count;
275 obcb.bc_rd = 0;
276
277 TUBLOCK(tubp->irq, flags);
278 rc = tub3270_movedata(&obcb, &tubp->tty_bcb, fromuser);
279 tty3270_try_logging(tubp);
280 TUBUNLOCK(tubp->irq, flags);
281 return rc;
282 }
283
284 static void
285 tty3270_put_char(struct tty_struct *tty, unsigned char ch)
286 {
287 long flags;
288 tub_t *tubp;
289 bcb_t *ob;
290
291 if ((tubp = tty->driver_data) == NULL)
292 return;
293
294 TUBLOCK(tubp->irq, flags);
295 ob = &tubp->tty_bcb;
296 if (ob->bc_cnt < ob->bc_len) {
297 ob->bc_buf[ob->bc_wr++] = ch;
298 if (ob->bc_wr == ob->bc_len)
299 ob->bc_wr = 0;
300 ob->bc_cnt++;
301 }
302 tty3270_try_logging(tubp);
303 TUBUNLOCK(tubp->irq, flags);
304 }
305
306 static void
307 tty3270_flush_chars(struct tty_struct *tty)
308 {
309 tub_t *tubp;
310 long flags;
311
312 if ((tubp = tty->driver_data) == NULL)
313 return;
314
315 TUBLOCK(tubp->irq, flags);
316 tty3270_try_logging(tubp);
317 TUBUNLOCK(tubp->irq, flags);
318 }
319
320 static int
321 tty3270_write_room(struct tty_struct *tty)
322 {
323 tub_t *tubp;
324 bcb_t *ob;
325
326 if ((tubp = tty->driver_data) == NULL)
327 return -1;
328
329 ob = &tubp->tty_bcb;
330 return ob->bc_len - ob->bc_cnt;
331 }
332
333 static int
334 tty3270_chars_in_buffer(struct tty_struct *tty)
335 {
336 tub_t *tubp;
337 bcb_t *ob;
338
339 if ((tubp = tty->driver_data) == NULL)
340 return -1;
341
342 ob = &tubp->tty_bcb;
343 return ob->bc_cnt;
344 }
345
346 static int
347 tty3270_ioctl(struct tty_struct *tty, struct file *file,
348 unsigned int cmd, unsigned long arg)
349 {
350 tub_t *tubp;
351 long flags;
352 int ret = 0;
353 struct termios termios;
354
355 if ((tubp = tty->driver_data) == NULL)
356 return -ENODEV;
357
358 TUBLOCK(tubp->irq, flags);
359 if (tty->flags * (1 << TTY_IO_ERROR)) {
360 ret = -EIO;
361 goto do_return;
362 }
363 switch(cmd) {
364 case TCGETS:
365 ret = -ENOIOCTLCMD;
366 goto do_return;
367 case TCFLSH: /* arg: 2 or 0 */
368 ret = -ENOIOCTLCMD;
369 goto do_return;
370 case TCSETSF:
371 if (user_termios_to_kernel_termios(&termios,
372 (struct termios *)arg)) {
373 ret = -EFAULT;
374 goto do_return;
375 }
376 ret = -ENOIOCTLCMD;
377 goto do_return;
378 case TCGETA:
379 ret = -ENOIOCTLCMD;
380 goto do_return;
381 case TCSETA:
382 if (user_termio_to_kernel_termios(&termios,
383 (struct termio *)arg)) {
384 ret = -EFAULT;
385 goto do_return;
386 }
387 ret = -ENOIOCTLCMD;
388 goto do_return;
389 default:
390 ret = -ENOIOCTLCMD;
391 break;
392 }
393
394 do_return:
395 TUBUNLOCK(tubp->irq, flags);
396 return ret;
397 }
398
399 static void
400 tty3270_set_termios(struct tty_struct *tty, struct termios *old)
401 {
402 tub_t *tubp;
403 long flags;
404 int new;
405
406 if ((tubp = tty->driver_data) == NULL)
407 return;
408
409 if (tty3270_wait(tubp, &flags) != 0) {
410 TUBUNLOCK(tubp->irq, flags);
411 return;
412 }
413 new = L_ICANON(tty)? L_ECHO(tty)? TF_INPUT: TF_INPUTN:
414 tubp->tty_inattr;
415 if (new != tubp->tty_inattr) {
416 tubp->tty_inattr = new;
417 tubp->cmd = TBC_CLRINPUT;
418 tty3270_build(tubp);
419 }
420
421 TUBUNLOCK(tubp->irq, flags);
422 }
423
424 static void
425 tty3270_flush_buffer(struct tty_struct *tty)
426 {
427 tub_t *tubp;
428 bcb_t *ob;
429 long flags;
430
431 if ((tubp = tty->driver_data) == NULL)
432 return;
433
434 if (tubp->mode == TBM_FS && tubp->fs_pid != 0) {
435 kill_proc(tubp->fs_pid, SIGHUP, 1);
436 }
437
438 if ((tubp->flags & TUB_OPEN_STET) == 0) {
439 ob = &tubp->tty_bcb;
440 TUBLOCK(tubp->irq, flags);
441 ob->bc_rd = 0;
442 ob->bc_wr = 0;
443 ob->bc_cnt = 0;
444 TUBUNLOCK(tubp->irq, flags);
445 }
446 wake_up_interruptible(&tty->write_wait);
447 if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
448 tty->ldisc.write_wakeup)
449 (tty->ldisc.write_wakeup)(tty);
450 }
451
452 static int
453 tty3270_read_proc(char *buf, char **start, off_t off, int count,
454 int *eof, void *data)
455 {
456 tub_t *tubp;
457 int begin = 0;
458 int i;
459 int rc;
460 int len = 0;
461
462 if (tty3270_proc_what == TW_CONFIG) {
463 /*
464 * Describe the 3270 configuration in ascii lines.
465 * Line 1: 0 <fsmajor> 0
466 * Console line: <devnum> CONSOLE <minor>
467 * Other lines: <devnum> <ttymajor> <minor>
468 */
469 len += sprintf(buf + len, "0 %d 0\n", fs3270_major);
470 for (i = 1; i <= tubnummins; i++) {
471 tubp = (*tubminors)[i];
472 #ifdef CONFIG_TN3270_CONSOLE
473 if (CONSOLE_IS_3270 && tubp == tub3270_con_tubp)
474 len += sprintf(buf + len, "%.3x CONSOLE %d\n",
475 tubp->devno, i);
476 else
477 #endif
478 len += sprintf(buf + len, "%.3x %d %d\n",
479 tubp->devno, tty3270_major, i);
480 if (begin + len > off + count)
481 break;
482 if (begin + len < off) {
483 begin += len;
484 len = 0;
485 }
486 }
487 if (i > tubnummins)
488 *eof = 1;
489 if (off >= begin + len) {
490 rc = 0;
491 } else {
492 *start = buf + off - begin;
493 rc = MIN(count, begin + len - off);
494 }
495 if (*eof && rc == 0)
496 tty3270_proc_what = TW_BOGUS;
497 return rc;
498 }
499
500 len += sprintf(buf, "There are %d devices. fs major is %d, "
501 "tty major is %d.\n", tubnummins, fs3270_major,
502 tty3270_major);
503 len += sprintf(buf+len, " index=%d data=%d misc=%d\n",
504 tty3270_proc_index,
505 tty3270_proc_data,
506 tty3270_proc_misc);
507
508 /*
509 * Display info for the tube with minor nr in index
510 */
511 len += tty3270_show_tube(tty3270_proc_index, buf+len, count-len);
512
513 *eof = 1;
514 if (off >= begin + len)
515 return 0;
516 *start = buf + off - begin;
517 return MIN(count, begin + len - off);
518 }
519
520 static int
521 tty3270_write_proc(struct file *file, const char *buffer,
522 unsigned long count, void *data)
523 {
524 char mybuf[GEOM_MAXINPLEN];
525 int mycount;
526 tub_t *tubp;
527 struct tty_struct *tty;
528 kdev_t device;
529 int rc;
530
531 mycount = MIN(count, sizeof mybuf - 1);
532 if (copy_from_user(mybuf, buffer, mycount) != 0)
533 return -EFAULT;
534 mybuf[mycount] = '\0';
535
536 /*
537 * User-mode settings affect only the current tty ---
538 */
539 tubp = NULL;
540 tty = current->tty;
541 device = tty? tty->device: 0;
542 if (device) {
543 if (MAJOR(device) == IBM_TTY3270_MAJOR)
544 tubp = (*tubminors)[MINOR(device)];
545 #ifdef CONFIG_TN3270_CONSOLE
546 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
547 if (CONSOLE_IS_3270 && device == S390_CONSOLE_DEV)
548 tubp = tub3270_con_tubp;
549 #endif /* LINUX_VERSION_CODE */
550 #endif /* CONFIG_TN3270_CONSOLE */
551 }
552 if (tubp) {
553 if ((rc = tty3270_aid_set(tubp, mybuf, mycount + 1)))
554 return rc > 0? count: rc;
555 if ((rc = tty3270_rcl_set(tubp, mybuf, mycount + 1)))
556 return rc > 0? count: rc;
557 if ((rc = tty3270_scl_set(tubp, mybuf, mycount + 1)))
558 return rc > 0? count: rc;
559 }
560
561 /*
562 * Superuser-mode settings affect the driver overall ---
563 */
564 if (!suser()) {
565 return -EPERM;
566 } else if (strncmp(mybuf, "index=", 6) == 0) {
567 tty3270_proc_index = simple_strtoul(mybuf + 6, 0,0);
568 return count;
569 } else if (strncmp(mybuf, "data=", 5) == 0) {
570 tty3270_proc_data = simple_strtoul(mybuf + 5, 0, 0);
571 return count;
572 } else if (strncmp(mybuf, "misc=", 5) == 0) {
573 tty3270_proc_misc = simple_strtoul(mybuf + 5, 0, 0);
574 return count;
575 } else if (strncmp(mybuf, "what=", 5) == 0) {
576 if (strcmp(mybuf+5, "bogus") == 0)
577 tty3270_proc_what = 0;
578 else if (strncmp(mybuf+5, "config", 6) == 0)
579 tty3270_proc_what = TW_CONFIG;
580 return count;
581 } else {
582 return -EINVAL;
583 }
584 }
585
586 static void
587 tty3270_hangup(struct tty_struct *tty)
588 {
589 tub_t *tubp;
590 extern void fs3270_release(tub_t *);
591
592 if ((tubp = tty->driver_data) == NULL)
593 return;
594 tty3270_rcl_purge(tubp);
595 tty3270_aid_reinit(tubp);
596 fs3270_release(tubp);
597 }
598
599
600 /*
601 * tty3270_bh(tubp) -- Perform back-half processing
602 */
603 static void
604 tty3270_bh(void *data)
605 {
606 long flags;
607 tub_t *tubp;
608 struct tty_struct *tty;
609
610 tubp = data;
611 TUBLOCK(tubp->irq, flags);
612 tubp->flags &= ~TUB_BHPENDING;
613 tty = tubp->tty;
614
615 if (tubp->flags & TUB_UNSOL_DE) {
616 tubp->flags &= ~TUB_UNSOL_DE;
617 if (tty != NULL) {
618 tty_hangup(tty);
619 wake_up_interruptible(&tubp->waitq);
620 goto do_unlock;
621 }
622 }
623
624 if (tubp->flags & TUB_IACTIVE) { /* If read ended, */
625 tty3270_do_input(tubp);
626 tubp->flags &= ~TUB_IACTIVE;
627 }
628
629 if ((tubp->flags & TUB_WORKING) == 0) {
630 if (tubp->flags & TUB_ATTN) {
631 tty3270_start_input(tubp);
632 tubp->flags &= ~TUB_ATTN;
633 } else if (tty3270_try_logging(tubp) == 0) {
634 wake_up_interruptible(&tubp->waitq);
635 }
636 }
637
638 if (tty != NULL) {
639 if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
640 tty->ldisc.write_wakeup != NULL)
641 (tty->ldisc.write_wakeup)(tty);
642 wake_up_interruptible(&tty->write_wait);
643 }
644 do_unlock:
645 TUBUNLOCK(tubp->irq, flags);
646 }
647
648 /*
649 * tty3270_sched_bh(tubp) -- Schedule the back half
650 * Irq lock must be held on entry and remains held on exit.
651 */
652 void
653 tty3270_sched_bh(tub_t *tubp)
654 {
655 if (tubp->flags & TUB_BHPENDING)
656 return;
657 tubp->flags |= TUB_BHPENDING;
658 tubp->tqueue.routine = tty3270_bh;
659 tubp->tqueue.data = tubp;
660 queue_task(&tubp->tqueue, &tq_immediate);
661 mark_bh(IMMEDIATE_BH);
662 }
663
664 /*
665 * tty3270_io() -- Perform line-mode reads and writes here
666 */
667 int
668 tty3270_io(tub_t *tubp)
669 {
670 int rc;
671 ccw1_t *ccwp;
672
673 tubp->flags |= TUB_WORKING;
674 tubp->dstat = 0;
675 ccwp = &tubp->ttyccw;
676
677 rc = do_IO(tubp->irq, ccwp, tubp->irq, 0, 0);
678 return rc;
679 }
680
681 /*
682 * tty3270_wait(tubp) -- Wait until TUB_WORKING is off
683 * On entry the lock must not be held; on exit it is held.
684 */
685 static int
686 tty3270_wait(tub_t *tubp, long *flags)
687 {
688 DECLARE_WAITQUEUE(wait, current);
689
690 TUBLOCK(tubp->irq, *flags);
691 add_wait_queue(&tubp->waitq, &wait);
692 while (!signal_pending(current) &&
693 (tubp->flags & TUB_WORKING) != 0) {
694 current->state = TASK_INTERRUPTIBLE;
695 TUBUNLOCK(tubp->irq, *flags);
696 schedule();
697 current->state = TASK_RUNNING;
698 TUBLOCK(tubp->irq, *flags);
699 }
700 remove_wait_queue(&tubp->waitq, &wait);
701 return signal_pending(current)? -ERESTARTSYS: 0;
702 }
703
704 void
705 tty3270_int(tub_t *tubp, devstat_t *dsp)
706 {
707 #define DEV_UE_BUSY \
708 (DEV_STAT_CHN_END | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP)
709 #define DEV_NOT_WORKING \
710 (DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_CHECK)
711
712 tubp->dstat = dsp->dstat;
713
714 /* Handle CE-DE-UE and subsequent UDE */
715 if (dsp->dstat == DEV_UE_BUSY) {
716 tubp->flags |= TUB_UE_BUSY;
717 return;
718 } else if (tubp->flags & TUB_UE_BUSY) {
719 tubp->flags &= ~TUB_UE_BUSY;
720 if (dsp->dstat == DEV_STAT_DEV_END &&
721 (tubp->flags & TUB_WORKING) != 0) {
722 tty3270_io(tubp);
723 return;
724 }
725 }
726
727 /* Handle ATTN */
728 if (dsp->dstat & DEV_STAT_ATTENTION)
729 tubp->flags |= TUB_ATTN;
730
731 if (dsp->dstat & DEV_STAT_CHN_END) {
732 tubp->cswl = dsp->rescnt;
733 if ((dsp->dstat & DEV_STAT_DEV_END) == 0)
734 tubp->flags |= TUB_EXPECT_DE;
735 else
736 tubp->flags &= ~TUB_EXPECT_DE;
737 } else if (dsp->dstat & DEV_STAT_DEV_END) {
738 if ((tubp->flags & TUB_EXPECT_DE) == 0)
739 tubp->flags |= TUB_UNSOL_DE;
740 tubp->flags &= ~TUB_EXPECT_DE;
741 }
742 if (dsp->dstat & DEV_NOT_WORKING)
743 tubp->flags &= ~TUB_WORKING;
744 if (dsp->dstat & DEV_STAT_UNIT_CHECK)
745 tubp->sense = dsp->ii.sense;
746 if ((tubp->flags & TUB_WORKING) == 0)
747 tty3270_sched_bh(tubp);
748 }
749
750 /*
751 * tty3270_refresh(), called by fs3270_close() when tubp->fsopen == 0.
752 * On entry, lock is held.
753 */
754 void
755 tty3270_refresh(tub_t *tubp)
756 {
757 if (tubp->lnopen) {
758 tubp->mode = TBM_LN;
759 tubp->intv = tty3270_int;
760 tty3270_scl_resettimer(tubp);
761 tubp->cmd = TBC_UPDATE;
762 tty3270_build(tubp);
763 }
764 }
765
766 int
767 tty3270_try_logging(tub_t *tubp)
768 {
769 if (tubp->flags & TUB_WORKING)
770 return 0;
771 if (tubp->mode == TBM_FS)
772 return 0;
773 if (tubp->stat == TBS_HOLD)
774 return 0;
775 if (tubp->stat == TBS_MORE)
776 return 0;
777 #ifdef CONFIG_TN3270_CONSOLE
778 if (CONSOLE_IS_3270 && tub3270_con_tubp == tubp)
779 tub3270_con_copy(tubp);
780 #endif /* CONFIG_TN3270_CONSOLE */
781 if (tubp->tty_bcb.bc_cnt == 0)
782 return 0;
783 if (tubp->intv != tty3270_int)
784 return 0;
785 tubp->cmd = TBC_UPDLOG;
786 return tty3270_build(tubp);
787 }
788
789 /* tty3270 utility functions */
790
791 static void
792 tty3270_start_input(tub_t *tubp)
793 {
794 tubp->ttyccw.cda = virt_to_phys(&tubp->tty_input);
795 tubp->ttyccw.cmd_code = TC_READMOD;
796 tubp->ttyccw.count = GEOM_INPLEN;
797 tubp->ttyccw.flags = CCW_FLAG_SLI;
798 tty3270_io(tubp);
799 tubp->flags |= TUB_IACTIVE;
800 }
801
802 static void
803 tty3270_do_input(tub_t *tubp)
804 {
805 int count;
806 char *in;
807 int aidflags;
808 char *aidstring;
809
810 count = GEOM_INPLEN - tubp->cswl;
811 in = tubp->tty_input;
812 tty3270_aid_get(tubp, in[0], &aidflags, &aidstring);
813
814 if (aidflags & TA_CLEARKEY) {
815 tubp->stat = TBS_RUNNING;
816 tty3270_scl_resettimer(tubp);
817 tubp->cmd = TBC_UPDATE;
818 } else if (aidflags & TA_CLEARLOG) {
819 tubp->stat = TBS_RUNNING;
820 tty3270_scl_resettimer(tubp);
821 tubp->cmd = TBC_CLRUPDLOG;
822 } else if (aidflags & TA_DOENTER) {
823 if (count <= 6) {
824 switch(tubp->stat) {
825 case TBS_MORE:
826 tubp->stat = TBS_HOLD;
827 tty3270_scl_resettimer(tubp);
828 break;
829 case TBS_HOLD:
830 tubp->stat = TBS_MORE;
831 tty3270_scl_settimer(tubp);
832 break;
833 case TBS_RUNNING:
834 tty3270_do_enter(tubp, in + 6, 0);
835 break;
836 }
837 tubp->cmd = TBC_UPDSTAT;
838 goto do_build;
839 }
840 in += 6;
841 count -= 6;
842 TUB_EBCASC(in, count);
843 tubp->cmd = TBC_CLRINPUT;
844 tty3270_do_enter(tubp, in, count);
845 } else if ((aidflags & TA_DOSTRING) != 0 && aidstring != NULL) {
846 tubp->cmd = TBC_KRUPDLOG;
847 tty3270_do_enter(tubp, aidstring, strlen(aidstring));
848 } else if ((aidflags & TA_DOSTRINGD) != 0 && aidstring != NULL) {
849 tty3270_do_showi(tubp, aidstring, strlen(aidstring));
850 tubp->cmd = TBC_UPDINPUT;
851 } else {
852 if (in[0] != 0x60)
853 tubp->flags |= TUB_ALARM;
854 tubp->cmd = TBC_KRUPDLOG;
855 }
856 do_build:
857 tty3270_build(tubp);
858 }
859
860 static void
861 tty3270_do_enter(tub_t *tubp, char *cp, int count)
862 {
863 struct tty_struct *tty;
864 int func = -1;
865
866 if ((tty = tubp->tty) == NULL)
867 return;
868 if (count < 0)
869 return;
870 if (count == 2 && (cp[0] == '^' || cp[0] == '\252')) {
871 switch(cp[1]) {
872 case 'c': case 'C':
873 func = INTR_CHAR(tty);
874 break;
875 case 'd': case 'D':
876 func = EOF_CHAR(tty);
877 break;
878 case 'z': case 'Z':
879 func = SUSP_CHAR(tty);
880 break;
881 }
882 } else if (count == 2 && cp[0] == 0x1b) { /* if ESC */
883 int inc = 0;
884 char buf[GEOM_INPLEN + 1];
885 int len;
886
887 switch(cp[1]) {
888 case 'k': case 'K':
889 inc = -1;
890 break;
891 case 'j': case 'J':
892 inc = 1;
893 break;
894 }
895 if (inc == 0)
896 goto not_rcl;
897 len = tty3270_rcl_get(tubp, buf, sizeof buf, inc);
898 if (len == 0) {
899 tubp->flags |= TUB_ALARM;
900 return;
901 }
902 tty3270_do_showi(tubp, buf, len);
903 tubp->cmd = TBC_UPDINPUT;
904 return;
905 }
906 not_rcl:
907 if (func != -1) {
908 *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
909 *tty->flip.char_buf_ptr++ = func;
910 tty->flip.count++;
911 } else {
912 tty3270_rcl_put(tubp, cp, count);
913 memcpy(tty->flip.char_buf_ptr, cp, count);
914 /* Add newline unless line ends with "^n" */
915 if (count < 2 || cp[count - 1] != 'n' ||
916 (cp[count - 2] != '^' && cp[count - 2] != '\252')) {
917 tty->flip.char_buf_ptr[count] = '\n';
918 count++;
919 } else {
920 count -= 2; /* Lop trailing "^n" from text */
921 }
922 memset(tty->flip.flag_buf_ptr, TTY_NORMAL, count);
923 tty->flip.char_buf_ptr += count;
924 tty->flip.flag_buf_ptr += count;
925 tty->flip.count += count;
926 }
927 tty_flip_buffer_push(tty);
928 }
929
930 static void
931 tty3270_do_showi(tub_t *tubp, char *cp, int cl)
932 {
933 if (cl > GEOM_INPLEN)
934 cl = GEOM_INPLEN;
935 memset(tubp->tty_input, 0, GEOM_INPLEN);
936 memcpy(tubp->tty_input, cp, cl);
937 TUB_ASCEBC(tubp->tty_input, cl);
938 }
939
940
941
942 /* Debugging routine */
943 static int
944 tty3270_show_tube(int minor, char *buf, int count)
945 {
946 tub_t *tubp;
947 struct tty_struct *tty;
948 struct termios *mp;
949 int len;
950
951 /*012345678901234567890123456789012345678901234567890123456789 */
952 /*Info for tub_t[dd] at xxxxxxxx: */
953 /* geom: rows=dd cols=dd model=d */
954 /* lnopen=dd fsopen=dd waitq=xxxxxxxx */
955 /* dstat=xx mode=dd stat=dd flags=xxxx */
956 /* oucount=dddd ourd=ddddd ouwr=ddddd nextlogx=ddddd */
957 /* tty=xxxxxxxx */
958 /* write_wait=xxxxxxxx read_wait=xxxxxxxx */
959 /* iflag=xxxxxxxx oflag=xxxxxxxx cflag=xxxxxxxx lflag=xxxxxxxx */
960
961 if (minor < 0 || minor > tubnummins ||
962 (tubp = (*tubminors)[minor]) == NULL)
963 return sprintf(buf, "No tube at index=%d\n", minor);
964
965 tty = tubp->tty;
966 len = 0;
967
968 len += sprintf(buf+len, "Info for tub_t[%d] at %p:\n", minor, tubp);
969
970 len += sprintf(buf+len, "inattr is at %p\n", &tubp->tty_inattr);
971
972
973 len += sprintf(buf+len, " geom: rows=%.2d cols=%.2d model=%.1d\n",
974 tubp->geom_rows, tubp->geom_cols, tubp->tubiocb.model);
975
976 len += sprintf(buf+len,
977 " lnopen=%-2d fsopen=%-2d waitq=%p\n",
978 tubp->lnopen, tubp->fsopen, &tubp->waitq);
979
980 len += sprintf(buf+len, " dstat=%.2x mode=%-2d "
981 "stat=%-2d flags=%-4x\n", tubp->dstat,
982 tubp->mode, tubp->stat, tubp->flags);
983
984 #ifdef RBH_FIXTHIS
985 len += sprintf(buf+len,
986 " oucount=%-4d ourd=%-5d ouwr=%-5d"
987 " nextlogx=%-5d\n", tubp->tty_oucount,
988 tubp->tty_ourd, tubp->tty_ouwr, tubp->tty_nextlogx);
989 #endif
990
991 len += sprintf(buf+len, " tty=%p\n",tubp->tty);
992
993 if (tty)
994 len += sprintf(buf+len,
995 " write_wait=%.8x read_wait=%.8x\n",
996 (int)&tty->write_wait, (int)&tty->read_wait);
997
998 if (tty && ((mp = tty->termios)))
999 len += sprintf(buf+len," iflag=%.8x oflag=%.8x "
1000 "cflag=%.8x lflag=%.8x\n", mp->c_iflag,
1001 mp->c_oflag, mp->c_cflag, mp->c_lflag);
1002
1003
1004 return len;
1005 }
1006