brute-forced more changes from MontaVista's tree. SCSI partition table read still...
[linux-2.4.git] / 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 - 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
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 
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
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
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 
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
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
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
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
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
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
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
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
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
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 
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
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
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
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
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
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
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
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
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
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 }