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
tty3270_init(void)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
tty3270_fini(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
tty3270_open(struct tty_struct * tty,struct file * filp)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 - 2;
218 tty->winsize.ws_col = tubp->geom_cols;
219 if (tubp->tty_input == NULL)
220 tubp->tty_input = kmalloc(GEOM_INPLEN, GFP_KERNEL|GFP_DMA);
221 tubp->tty_inattr = TF_INPUT;
222 tubp->cmd = cmd;
223 tty3270_build(tubp);
224 TUBUNLOCK(tubp->irq, flags);
225 return 0;
226
227 do_fail:
228 tty3270_scl_fini(tubp);
229 tty3270_aid_fini(tubp);
230 tty3270_rcl_fini(tubp);
231 TUBUNLOCK(tubp->irq, flags);
232 tub_dec_use_count();
233 return rc;
234 }
235
236 static void
tty3270_close(struct tty_struct * tty,struct file * filp)237 tty3270_close(struct tty_struct *tty, struct file *filp)
238 {
239 tub_t *tubp;
240 long flags;
241
242 if ((tubp = tty->driver_data) == NULL)
243 return;
244
245 tty3270_wait(tubp, &flags);
246 if (--tubp->lnopen > 0)
247 goto do_return;
248 tubp->tty = NULL;
249 tty->driver_data = NULL;
250 tty3270_aid_fini(tubp);
251 tty3270_rcl_fini(tubp);
252 tty3270_scl_fini(tubp);
253 do_return:
254 tub_dec_use_count();
255 TUBUNLOCK(tubp->irq, flags);
256 }
257
258 static int
tty3270_write(struct tty_struct * tty,int fromuser,const unsigned char * buf,int count)259 tty3270_write(struct tty_struct *tty, int fromuser,
260 const unsigned char *buf, int count)
261 {
262 tub_t *tubp;
263 long flags;
264 bcb_t obcb;
265 int rc = 0;
266
267 if ((tubp = tty->driver_data) == NULL)
268 return -1;
269
270 #ifdef CONFIG_TN3270_CONSOLE
271 if (CONSOLE_IS_3270 && tub3270_con_tubp == tubp)
272 tub3270_con_copy(tubp);
273 #endif /* CONFIG_TN3270_CONSOLE */
274
275 obcb.bc_buf = (char *)buf;
276 obcb.bc_len = obcb.bc_cnt = obcb.bc_wr = count;
277 obcb.bc_rd = 0;
278
279 TUBLOCK(tubp->irq, flags);
280 rc = tub3270_movedata(&obcb, &tubp->tty_bcb, fromuser);
281 tty3270_try_logging(tubp);
282 TUBUNLOCK(tubp->irq, flags);
283 return rc;
284 }
285
286 static void
tty3270_put_char(struct tty_struct * tty,unsigned char ch)287 tty3270_put_char(struct tty_struct *tty, unsigned char ch)
288 {
289 long flags;
290 tub_t *tubp;
291 bcb_t *ob;
292
293 if ((tubp = tty->driver_data) == NULL)
294 return;
295
296 TUBLOCK(tubp->irq, flags);
297 ob = &tubp->tty_bcb;
298 if (ob->bc_cnt < ob->bc_len) {
299 ob->bc_buf[ob->bc_wr++] = ch;
300 if (ob->bc_wr == ob->bc_len)
301 ob->bc_wr = 0;
302 ob->bc_cnt++;
303 }
304 tty3270_try_logging(tubp);
305 TUBUNLOCK(tubp->irq, flags);
306 }
307
308 static void
tty3270_flush_chars(struct tty_struct * tty)309 tty3270_flush_chars(struct tty_struct *tty)
310 {
311 tub_t *tubp;
312 long flags;
313
314 if ((tubp = tty->driver_data) == NULL)
315 return;
316
317 TUBLOCK(tubp->irq, flags);
318 tty3270_try_logging(tubp);
319 TUBUNLOCK(tubp->irq, flags);
320 }
321
322 static int
tty3270_write_room(struct tty_struct * tty)323 tty3270_write_room(struct tty_struct *tty)
324 {
325 tub_t *tubp;
326 bcb_t *ob;
327
328 if ((tubp = tty->driver_data) == NULL)
329 return -1;
330
331 ob = &tubp->tty_bcb;
332 return ob->bc_len - ob->bc_cnt;
333 }
334
335 static int
tty3270_chars_in_buffer(struct tty_struct * tty)336 tty3270_chars_in_buffer(struct tty_struct *tty)
337 {
338 tub_t *tubp;
339 bcb_t *ob;
340
341 if ((tubp = tty->driver_data) == NULL)
342 return -1;
343
344 ob = &tubp->tty_bcb;
345 return ob->bc_cnt;
346 }
347
348 static int
tty3270_ioctl(struct tty_struct * tty,struct file * file,unsigned int cmd,unsigned long arg)349 tty3270_ioctl(struct tty_struct *tty, struct file *file,
350 unsigned int cmd, unsigned long arg)
351 {
352 tub_t *tubp;
353 long flags;
354 int ret = 0;
355 struct termios termios;
356
357 if ((tubp = tty->driver_data) == NULL)
358 return -ENODEV;
359
360 TUBLOCK(tubp->irq, flags);
361 if (tty->flags * (1 << TTY_IO_ERROR)) {
362 ret = -EIO;
363 goto do_return;
364 }
365 switch(cmd) {
366 case TCGETS:
367 ret = -ENOIOCTLCMD;
368 goto do_return;
369 case TCFLSH: /* arg: 2 or 0 */
370 ret = -ENOIOCTLCMD;
371 goto do_return;
372 case TCSETSF:
373 if (user_termios_to_kernel_termios(&termios,
374 (struct termios *)arg)) {
375 ret = -EFAULT;
376 goto do_return;
377 }
378 ret = -ENOIOCTLCMD;
379 goto do_return;
380 case TCGETA:
381 ret = -ENOIOCTLCMD;
382 goto do_return;
383 case TCSETA:
384 if (user_termio_to_kernel_termios(&termios,
385 (struct termio *)arg)) {
386 ret = -EFAULT;
387 goto do_return;
388 }
389 ret = -ENOIOCTLCMD;
390 goto do_return;
391 default:
392 ret = -ENOIOCTLCMD;
393 break;
394 }
395
396 do_return:
397 TUBUNLOCK(tubp->irq, flags);
398 return ret;
399 }
400
401 static void
tty3270_set_termios(struct tty_struct * tty,struct termios * old)402 tty3270_set_termios(struct tty_struct *tty, struct termios *old)
403 {
404 tub_t *tubp;
405 long flags;
406 int new;
407
408 if ((tubp = tty->driver_data) == NULL)
409 return;
410
411 if (tty3270_wait(tubp, &flags) != 0) {
412 TUBUNLOCK(tubp->irq, flags);
413 return;
414 }
415 new = L_ICANON(tty)? L_ECHO(tty)? TF_INPUT: TF_INPUTN:
416 tubp->tty_inattr;
417 if (new != tubp->tty_inattr) {
418 tubp->tty_inattr = new;
419 tubp->cmd = TBC_CLRINPUT;
420 tty3270_build(tubp);
421 }
422
423 TUBUNLOCK(tubp->irq, flags);
424 }
425
426 static void
tty3270_flush_buffer(struct tty_struct * tty)427 tty3270_flush_buffer(struct tty_struct *tty)
428 {
429 tub_t *tubp;
430 bcb_t *ob;
431 long flags;
432
433 if ((tubp = tty->driver_data) == NULL)
434 return;
435
436 if (tubp->mode == TBM_FS && tubp->fs_pid != 0) {
437 kill_proc(tubp->fs_pid, SIGHUP, 1);
438 }
439
440 if ((tubp->flags & TUB_OPEN_STET) == 0) {
441 ob = &tubp->tty_bcb;
442 TUBLOCK(tubp->irq, flags);
443 ob->bc_rd = 0;
444 ob->bc_wr = 0;
445 ob->bc_cnt = 0;
446 TUBUNLOCK(tubp->irq, flags);
447 }
448 tty_wakeup(tty);
449 }
450
451 static int
tty3270_read_proc(char * buf,char ** start,off_t off,int count,int * eof,void * data)452 tty3270_read_proc(char *buf, char **start, off_t off, int count,
453 int *eof, void *data)
454 {
455 tub_t *tubp;
456 int begin = 0;
457 int i;
458 int rc;
459 int len = 0;
460
461 if (tty3270_proc_what == TW_CONFIG) {
462 /*
463 * Describe the 3270 configuration in ascii lines.
464 * Line 1: 0 <fsmajor> 0
465 * Console line: <devnum> CONSOLE <minor>
466 * Other lines: <devnum> <ttymajor> <minor>
467 */
468 len += sprintf(buf + len, "0 %d 0\n", fs3270_major);
469 for (i = 1; i <= tubnummins; i++) {
470 tubp = (*tubminors)[i];
471 #ifdef CONFIG_TN3270_CONSOLE
472 if (CONSOLE_IS_3270 && tubp == tub3270_con_tubp)
473 len += sprintf(buf + len, "%.4x CONSOLE %d\n",
474 tubp->devno, i);
475 else
476 #endif
477 len += sprintf(buf + len, "%.4x %d %d\n",
478 tubp->devno, tty3270_major, i);
479 if (begin + len > off + count)
480 break;
481 if (begin + len < off) {
482 begin += len;
483 len = 0;
484 }
485 }
486 if (i > tubnummins)
487 *eof = 1;
488 if (off >= begin + len) {
489 rc = 0;
490 } else {
491 *start = buf + off - begin;
492 rc = MIN(count, begin + len - off);
493 }
494 if (*eof && rc == 0)
495 tty3270_proc_what = TW_BOGUS;
496 return rc;
497 }
498
499 len += sprintf(buf, "There are %d devices. fs major is %d, "
500 "tty major is %d.\n", tubnummins, fs3270_major,
501 tty3270_major);
502 len += sprintf(buf+len, " index=%d data=%d misc=%d\n",
503 tty3270_proc_index,
504 tty3270_proc_data,
505 tty3270_proc_misc);
506
507 /*
508 * Display info for the tube with minor nr in index
509 */
510 len += tty3270_show_tube(tty3270_proc_index, buf+len, count-len);
511
512 *eof = 1;
513 if (off >= begin + len)
514 return 0;
515 *start = buf + off - begin;
516 return MIN(count, begin + len - off);
517 }
518
519 static int
tty3270_write_proc(struct file * file,const char * buffer,unsigned long count,void * data)520 tty3270_write_proc(struct file *file, const char *buffer,
521 unsigned long count, void *data)
522 {
523 char mybuf[GEOM_MAXINPLEN];
524 int mycount;
525 tub_t *tubp;
526 struct tty_struct *tty;
527 kdev_t device;
528 int rc;
529
530 mycount = MIN(count, sizeof mybuf - 1);
531 if (copy_from_user(mybuf, buffer, mycount) != 0)
532 return -EFAULT;
533 mybuf[mycount] = '\0';
534
535 /*
536 * User-mode settings affect only the current tty ---
537 */
538 tubp = NULL;
539 tty = current->tty;
540 device = tty? tty->device: 0;
541 if (device) {
542 if (MAJOR(device) == IBM_TTY3270_MAJOR)
543 tubp = (*tubminors)[MINOR(device)];
544 #ifdef CONFIG_TN3270_CONSOLE
545 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
546 if (CONSOLE_IS_3270 && device == S390_CONSOLE_DEV)
547 tubp = tub3270_con_tubp;
548 #endif /* LINUX_VERSION_CODE */
549 #endif /* CONFIG_TN3270_CONSOLE */
550 }
551 if (tubp) {
552 if ((rc = tty3270_aid_set(tubp, mybuf, mycount + 1)))
553 return rc > 0? count: rc;
554 if ((rc = tty3270_rcl_set(tubp, mybuf, mycount + 1)))
555 return rc > 0? count: rc;
556 if ((rc = tty3270_scl_set(tubp, mybuf, mycount + 1)))
557 return rc > 0? count: rc;
558 }
559
560 /*
561 * Superuser-mode settings affect the driver overall ---
562 */
563 if (!suser()) {
564 return -EPERM;
565 } else if (strncmp(mybuf, "index=", 6) == 0) {
566 tty3270_proc_index = simple_strtoul(mybuf + 6, 0,0);
567 return count;
568 } else if (strncmp(mybuf, "data=", 5) == 0) {
569 tty3270_proc_data = simple_strtoul(mybuf + 5, 0, 0);
570 return count;
571 } else if (strncmp(mybuf, "misc=", 5) == 0) {
572 tty3270_proc_misc = simple_strtoul(mybuf + 5, 0, 0);
573 return count;
574 } else if (strncmp(mybuf, "what=", 5) == 0) {
575 if (strcmp(mybuf+5, "bogus") == 0)
576 tty3270_proc_what = 0;
577 else if (strncmp(mybuf+5, "config", 6) == 0)
578 tty3270_proc_what = TW_CONFIG;
579 return count;
580 } else {
581 return -EINVAL;
582 }
583 }
584
585 static void
tty3270_hangup(struct tty_struct * tty)586 tty3270_hangup(struct tty_struct *tty)
587 {
588 tub_t *tubp;
589 extern void fs3270_release(tub_t *);
590
591 if ((tubp = tty->driver_data) == NULL)
592 return;
593 tty3270_rcl_purge(tubp);
594 tty3270_aid_reinit(tubp);
595 fs3270_release(tubp);
596 }
597
598
599 /*
600 * tty3270_bh(tubp) -- Perform back-half processing
601 */
602 static void
tty3270_bh(void * data)603 tty3270_bh(void *data)
604 {
605 tub_t *tubp;
606 ioinfo_t *ioinfop;
607 long flags;
608 struct tty_struct *tty;
609
610 ioinfop = ioinfo[(tubp = data)->irq];
611 while (TUBTRYLOCK(tubp->irq, flags) == 0) {
612 if (ioinfop->ui.flags.unready == 1)
613 return;
614 }
615 if (ioinfop->ui.flags.unready == 1 ||
616 ioinfop->ui.flags.ready == 0)
617 goto do_unlock;
618
619 tubp->flags &= ~TUB_BHPENDING;
620 tty = tubp->tty;
621
622 if (tubp->flags & TUB_UNSOL_DE) {
623 tubp->flags &= ~TUB_UNSOL_DE;
624 if (tty != NULL) {
625 tty_hangup(tty);
626 wake_up_interruptible(&tubp->waitq);
627 goto do_unlock;
628 }
629 }
630
631 if (tubp->flags & TUB_IACTIVE) { /* If read ended, */
632 tty3270_do_input(tubp);
633 tubp->flags &= ~TUB_IACTIVE;
634 }
635
636 if ((tubp->flags & TUB_WORKING) == 0) {
637 if (tubp->flags & TUB_ATTN) {
638 tty3270_start_input(tubp);
639 tubp->flags &= ~TUB_ATTN;
640 } else if (tty3270_try_logging(tubp) == 0) {
641 wake_up_interruptible(&tubp->waitq);
642 }
643 }
644
645 if (tty != NULL) {
646 tty_wakeup(tty);
647 }
648 do_unlock:
649 TUBUNLOCK(tubp->irq, flags);
650 }
651
652 /*
653 * tty3270_sched_bh(tubp) -- Schedule the back half
654 * Irq lock must be held on entry and remains held on exit.
655 */
656 void
tty3270_sched_bh(tub_t * tubp)657 tty3270_sched_bh(tub_t *tubp)
658 {
659 if (tubp->flags & TUB_BHPENDING)
660 return;
661 tubp->flags |= TUB_BHPENDING;
662 tubp->tqueue.routine = tty3270_bh;
663 tubp->tqueue.data = tubp;
664 queue_task(&tubp->tqueue, &tq_immediate);
665 mark_bh(IMMEDIATE_BH);
666 }
667
668 /*
669 * tty3270_io() -- Perform line-mode reads and writes here
670 */
671 int
tty3270_io(tub_t * tubp)672 tty3270_io(tub_t *tubp)
673 {
674 int rc;
675 ccw1_t *ccwp;
676
677 tubp->flags |= TUB_WORKING;
678 tubp->dstat = 0;
679 ccwp = &tubp->ttyccw;
680
681 rc = do_IO(tubp->irq, ccwp, tubp->irq, 0, 0);
682 return rc;
683 }
684
685 /*
686 * tty3270_wait(tubp) -- Wait until TUB_WORKING is off
687 * On entry the lock must not be held; on exit it is held.
688 */
689 static int
tty3270_wait(tub_t * tubp,long * flags)690 tty3270_wait(tub_t *tubp, long *flags)
691 {
692 DECLARE_WAITQUEUE(wait, current);
693
694 TUBLOCK(tubp->irq, *flags);
695 add_wait_queue(&tubp->waitq, &wait);
696 while (!signal_pending(current) &&
697 (tubp->flags & TUB_WORKING) != 0) {
698 current->state = TASK_INTERRUPTIBLE;
699 TUBUNLOCK(tubp->irq, *flags);
700 schedule();
701 current->state = TASK_RUNNING;
702 TUBLOCK(tubp->irq, *flags);
703 }
704 remove_wait_queue(&tubp->waitq, &wait);
705 return signal_pending(current)? -ERESTARTSYS: 0;
706 }
707
708 void
tty3270_int(tub_t * tubp,devstat_t * dsp)709 tty3270_int(tub_t *tubp, devstat_t *dsp)
710 {
711 #define DEV_UE_BUSY \
712 (DEV_STAT_CHN_END | DEV_STAT_DEV_END | DEV_STAT_UNIT_EXCEP)
713 #define DEV_NOT_WORKING \
714 (DEV_STAT_ATTENTION | DEV_STAT_DEV_END | DEV_STAT_UNIT_CHECK)
715
716 tubp->dstat = dsp->dstat;
717
718 /* Handle CE-DE-UE and subsequent UDE */
719 if (dsp->dstat == DEV_UE_BUSY) {
720 tubp->flags |= TUB_UE_BUSY;
721 return;
722 } else if (tubp->flags & TUB_UE_BUSY) {
723 tubp->flags &= ~TUB_UE_BUSY;
724 if (dsp->dstat == DEV_STAT_DEV_END &&
725 (tubp->flags & TUB_WORKING) != 0) {
726 tty3270_io(tubp);
727 return;
728 }
729 }
730
731 /* Handle ATTN */
732 if (dsp->dstat & DEV_STAT_ATTENTION)
733 tubp->flags |= TUB_ATTN;
734
735 if (dsp->dstat & DEV_STAT_CHN_END) {
736 tubp->cswl = dsp->rescnt;
737 if ((dsp->dstat & DEV_STAT_DEV_END) == 0)
738 tubp->flags |= TUB_EXPECT_DE;
739 else
740 tubp->flags &= ~TUB_EXPECT_DE;
741 } else if (dsp->dstat & DEV_STAT_DEV_END) {
742 if ((tubp->flags & TUB_EXPECT_DE) == 0)
743 tubp->flags |= TUB_UNSOL_DE;
744 tubp->flags &= ~TUB_EXPECT_DE;
745 }
746 if (dsp->dstat & DEV_NOT_WORKING)
747 tubp->flags &= ~TUB_WORKING;
748 if (dsp->dstat & DEV_STAT_UNIT_CHECK)
749 tubp->sense = dsp->ii.sense;
750 if ((tubp->flags & TUB_WORKING) == 0)
751 tty3270_sched_bh(tubp);
752 }
753
754 /*
755 * tty3270_refresh(), called by fs3270_close() when tubp->fsopen == 0.
756 * On entry, lock is held.
757 */
758 void
tty3270_refresh(tub_t * tubp)759 tty3270_refresh(tub_t *tubp)
760 {
761 if (tubp->lnopen) {
762 tubp->mode = TBM_LN;
763 tubp->intv = tty3270_int;
764 tty3270_scl_resettimer(tubp);
765 tubp->cmd = TBC_UPDATE;
766 tty3270_build(tubp);
767 }
768 }
769
770 int
tty3270_try_logging(tub_t * tubp)771 tty3270_try_logging(tub_t *tubp)
772 {
773 if (tubp->flags & TUB_WORKING)
774 return 0;
775 if (tubp->mode == TBM_FS)
776 return 0;
777 if (tubp->stat == TBS_HOLD)
778 return 0;
779 if (tubp->stat == TBS_MORE)
780 return 0;
781 #ifdef CONFIG_TN3270_CONSOLE
782 if (CONSOLE_IS_3270 && tub3270_con_tubp == tubp)
783 tub3270_con_copy(tubp);
784 #endif /* CONFIG_TN3270_CONSOLE */
785 if (tubp->tty_bcb.bc_cnt == 0)
786 return 0;
787 if (tubp->intv != tty3270_int)
788 return 0;
789 tubp->cmd = TBC_UPDLOG;
790 return tty3270_build(tubp);
791 }
792
793 /* tty3270 utility functions */
794
795 static void
tty3270_start_input(tub_t * tubp)796 tty3270_start_input(tub_t *tubp)
797 {
798 if (tubp->tty_input == NULL)
799 return;
800 tubp->ttyccw.cda = virt_to_phys(tubp->tty_input);
801 tubp->ttyccw.cmd_code = TC_READMOD;
802 tubp->ttyccw.count = GEOM_INPLEN;
803 tubp->ttyccw.flags = CCW_FLAG_SLI;
804 tty3270_io(tubp);
805 tubp->flags |= TUB_IACTIVE;
806 }
807
808 static void
tty3270_do_input(tub_t * tubp)809 tty3270_do_input(tub_t *tubp)
810 {
811 int count;
812 char *in;
813 int aidflags;
814 char *aidstring;
815
816 count = GEOM_INPLEN - tubp->cswl;
817 if ((in = tubp->tty_input) == NULL)
818 goto do_build;
819 tty3270_aid_get(tubp, in[0], &aidflags, &aidstring);
820
821 if (aidflags & TA_CLEARKEY) {
822 tubp->stat = TBS_RUNNING;
823 tty3270_scl_resettimer(tubp);
824 tubp->cmd = TBC_UPDATE;
825 } else if (aidflags & TA_CLEARLOG) {
826 tubp->stat = TBS_RUNNING;
827 tty3270_scl_resettimer(tubp);
828 tubp->cmd = TBC_CLRUPDLOG;
829 } else if (aidflags & TA_DOENTER) {
830 if (count <= 6) {
831 switch(tubp->stat) {
832 case TBS_MORE:
833 tubp->stat = TBS_HOLD;
834 tty3270_scl_resettimer(tubp);
835 break;
836 case TBS_HOLD:
837 tubp->stat = TBS_MORE;
838 tty3270_scl_settimer(tubp);
839 break;
840 case TBS_RUNNING:
841 tty3270_do_enter(tubp, in + 6, 0);
842 break;
843 }
844 tubp->cmd = TBC_UPDSTAT;
845 goto do_build;
846 }
847 in += 6;
848 count -= 6;
849 TUB_EBCASC(in, count);
850 tubp->cmd = TBC_CLRINPUT;
851 tty3270_do_enter(tubp, in, count);
852 } else if ((aidflags & TA_DOSTRING) != 0 && aidstring != NULL) {
853 tubp->cmd = TBC_KRUPDLOG;
854 tty3270_do_enter(tubp, aidstring, strlen(aidstring));
855 } else if ((aidflags & TA_DOSTRINGD) != 0 && aidstring != NULL) {
856 tty3270_do_showi(tubp, aidstring, strlen(aidstring));
857 tubp->cmd = TBC_UPDINPUT;
858 } else {
859 if (in[0] != 0x60)
860 tubp->flags |= TUB_ALARM;
861 tubp->cmd = TBC_KRUPDLOG;
862 }
863 do_build:
864 tty3270_build(tubp);
865 }
866
867 static void
tty3270_do_enter(tub_t * tubp,char * cp,int count)868 tty3270_do_enter(tub_t *tubp, char *cp, int count)
869 {
870 struct tty_struct *tty;
871 int func = -1;
872
873 if ((tty = tubp->tty) == NULL)
874 return;
875 if (count < 0)
876 return;
877 if (count == 2 && (cp[0] == '^' || cp[0] == '\252')) {
878 switch(cp[1]) {
879 case 'c': case 'C':
880 func = INTR_CHAR(tty);
881 break;
882 case 'd': case 'D':
883 func = EOF_CHAR(tty);
884 break;
885 case 'z': case 'Z':
886 func = SUSP_CHAR(tty);
887 break;
888 }
889 } else if (count == 2 && cp[0] == 0x1b) { /* if ESC */
890 int inc = 0;
891 char buf[GEOM_INPLEN + 1];
892 int len;
893
894 switch(cp[1]) {
895 case 'k': case 'K':
896 inc = -1;
897 break;
898 case 'j': case 'J':
899 inc = 1;
900 break;
901 }
902 if (inc == 0)
903 goto not_rcl;
904 len = tty3270_rcl_get(tubp, buf, sizeof buf, inc);
905 if (len == 0) {
906 tubp->flags |= TUB_ALARM;
907 return;
908 }
909 tty3270_do_showi(tubp, buf, len);
910 tubp->cmd = TBC_UPDINPUT;
911 return;
912 }
913 not_rcl:
914 if (func != -1) {
915 *tty->flip.flag_buf_ptr++ = TTY_NORMAL;
916 *tty->flip.char_buf_ptr++ = func;
917 tty->flip.count++;
918 } else {
919 tty3270_rcl_put(tubp, cp, count);
920 memcpy(tty->flip.char_buf_ptr, cp, count);
921 /* Add newline unless line ends with "^n" */
922 if (count < 2 || cp[count - 1] != 'n' ||
923 (cp[count - 2] != '^' && cp[count - 2] != '\252')) {
924 tty->flip.char_buf_ptr[count] = '\n';
925 count++;
926 } else {
927 count -= 2; /* Lop trailing "^n" from text */
928 }
929 memset(tty->flip.flag_buf_ptr, TTY_NORMAL, count);
930 tty->flip.char_buf_ptr += count;
931 tty->flip.flag_buf_ptr += count;
932 tty->flip.count += count;
933 }
934 tty_flip_buffer_push(tty);
935 }
936
937 static void
tty3270_do_showi(tub_t * tubp,char * cp,int cl)938 tty3270_do_showi(tub_t *tubp, char *cp, int cl)
939 {
940 if (cl > GEOM_INPLEN)
941 cl = GEOM_INPLEN;
942 memset(tubp->tty_input, 0, GEOM_INPLEN);
943 memcpy(tubp->tty_input, cp, cl);
944 TUB_ASCEBC(tubp->tty_input, cl);
945 }
946
947
948
949 /* Debugging routine */
950 static int
tty3270_show_tube(int minor,char * buf,int count)951 tty3270_show_tube(int minor, char *buf, int count)
952 {
953 tub_t *tubp;
954 struct tty_struct *tty;
955 struct termios *mp;
956 int len;
957
958 /*012345678901234567890123456789012345678901234567890123456789 */
959 /*Info for tub_t[dd] at xxxxxxxx: */
960 /* geom: rows=dd cols=dd model=d */
961 /* lnopen=dd fsopen=dd waitq=xxxxxxxx */
962 /* dstat=xx mode=dd stat=dd flags=xxxx */
963 /* oucount=dddd ourd=ddddd ouwr=ddddd nextlogx=ddddd */
964 /* tty=xxxxxxxx */
965 /* write_wait=xxxxxxxx read_wait=xxxxxxxx */
966 /* iflag=xxxxxxxx oflag=xxxxxxxx cflag=xxxxxxxx lflag=xxxxxxxx */
967
968 if (minor < 0 || minor > tubnummins ||
969 (tubp = (*tubminors)[minor]) == NULL)
970 return sprintf(buf, "No tube at index=%d\n", minor);
971
972 tty = tubp->tty;
973 len = 0;
974
975 len += sprintf(buf+len, "Info for tub_t[%d] at %p:\n", minor, tubp);
976
977 len += sprintf(buf+len, "inattr is at %p\n", &tubp->tty_inattr);
978
979
980 len += sprintf(buf+len, " geom: rows=%.2d cols=%.2d model=%.1d\n",
981 tubp->geom_rows, tubp->geom_cols, tubp->tubiocb.model);
982
983 len += sprintf(buf+len,
984 " lnopen=%-2d fsopen=%-2d waitq=%p\n",
985 tubp->lnopen, tubp->fsopen, &tubp->waitq);
986
987 len += sprintf(buf+len, " dstat=%.2x mode=%-2d "
988 "stat=%-2d flags=%-4x\n", tubp->dstat,
989 tubp->mode, tubp->stat, tubp->flags);
990
991 #ifdef RBH_FIXTHIS
992 len += sprintf(buf+len,
993 " oucount=%-4d ourd=%-5d ouwr=%-5d"
994 " nextlogx=%-5d\n", tubp->tty_oucount,
995 tubp->tty_ourd, tubp->tty_ouwr, tubp->tty_nextlogx);
996 #endif
997
998 len += sprintf(buf+len, " tty=%p\n",tubp->tty);
999
1000 if (tty)
1001 len += sprintf(buf+len,
1002 " write_wait=%p read_wait=%p\n",
1003 &tty->write_wait, &tty->read_wait);
1004
1005 if (tty && ((mp = tty->termios)))
1006 len += sprintf(buf+len," iflag=%.8x oflag=%.8x "
1007 "cflag=%.8x lflag=%.8x\n", mp->c_iflag,
1008 mp->c_oflag, mp->c_cflag, mp->c_lflag);
1009
1010
1011 return len;
1012 }
1013