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