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