1 /*
2  *  IBM/3270 Driver -- Copyright (C) 2000 UTS Global LLC
3  *
4  *  tuball.c -- Initialization, termination, irq lookup
5  *
6  *
7  *
8  *
9  *
10  *  Author:  Richard Hitt
11  */
12 #include <linux/config.h>
13 #include "tubio.h"
14 #ifndef MODULE
15 #include <linux/init.h>
16 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
17 #include <asm/cpcmd.h>
18 #include <linux/bootmem.h>
19 #else
20 #include "../../../../arch/s390/kernel/cpcmd.h"
21 #endif
22 #endif
23 
24 /* Module parameters */
25 int tubdebug;
26 int tubscrolltime = -1;
27 int tubxcorrect = 1;            /* Do correct ebc<->asc tables */
28 #ifdef MODULE
29 MODULE_PARM(tubdebug, "i");
30 MODULE_PARM(tubscrolltime, "i");
31 MODULE_PARM(tubxcorrect, "i");
32 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,12))
33 MODULE_LICENSE ("GPL");
34 #endif
35 #endif
36 /*
37  * Values for tubdebug and their effects:
38  * 1 - print in hex on console the first 16 bytes received
39  * 2 - print address at which array tubminors is allocated
40  * 4 - attempt to register tty3270_driver
41  */
42 int tubnummins;
43 tub_t *(*tubminors)[TUBMAXMINS];
44 tub_t *(*(*tubirqs)[256])[256];
45 unsigned char tub_ascebc[256];
46 unsigned char tub_ebcasc[256];
47 int tubinitminors(void);
48 void tubfiniminors(void);
49 void tubint(int, void *, struct pt_regs *);
50 
51 /* Lookup-by-irq functions */
52 int tubaddbyirq(tub_t *, int);
53 tub_t *tubfindbyirq(int);
54 void tubdelbyirq(tub_t *, int);
55 void tubfiniirqs(void);
56 
57 extern int fs3270_init(void);
58 extern void fs3270_fini(void);
59 extern int tty3270_init(void);
60 extern void tty3270_fini(void);
61 
62 unsigned char tub_ebcgraf[64] =
63 	{ 0x40, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
64 	  0xc8, 0xc9, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
65 	  0x50, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
66 	  0xd8, 0xd9, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
67 	  0x60, 0x61, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
68 	  0xe8, 0xe9, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
69 	  0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
70 	  0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f };
71 
72 int tub3270_init(void);
73 
74 #ifndef MODULE
75 
76 /*
77  * Can't have this driver a module & support console at the same time
78  */
79 #ifdef CONFIG_TN3270_CONSOLE
80 static kdev_t tub3270_con_device(struct console *);
81 static void tub3270_con_unblank(void);
82 static void tub3270_con_write(struct console *, const char *,
83 	unsigned int);
84 
85 static struct console tub3270_con = {
86 	"tub3270",		/* name */
87 	tub3270_con_write,	/* write */
88 	NULL,			/* read */
89 	tub3270_con_device,	/* device */
90 	tub3270_con_unblank,	/* unblank */
91 	NULL,			/* setup */
92 	CON_PRINTBUFFER,	/* flags */
93 	0,			/* index */
94 	0,			/* cflag */
95 	NULL			/* next */
96 };
97 
98 static bcb_t tub3270_con_bcb;		/* Buffer that receives con writes */
99 static spinlock_t tub3270_con_bcblock;	/* Lock for the buffer */
100 int tub3270_con_irq = -1;		/* set nonneg by _activate() */
101 tub_t *tub3270_con_tubp;		/* set nonzero by _activate() */
102 struct tty_driver tty3270_con_driver;	/* for /dev/console at 4, 64 */
103 
104 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
105 int tub3270_con_devno = -1;		/* set by tub3270_con_setup() */
__initfunc(void tub3270_con_setup (char * str,int * ints))106 __initfunc(void tub3270_con_setup(char *str, int *ints))
107 {
108 	int vdev;
109 
110 	vdev = simple_strtoul(str, 0, 16);
111 	if (vdev >= 0 && vdev < 65536)
112 		tub3270_con_devno = vdev;
113 	return;
114 }
115 
__initfunc(long tub3270_con_init (long kmem_start,long kmem_end))116 __initfunc (long tub3270_con_init(long kmem_start, long kmem_end))
117 {
118 	tub3270_con_bcb.bc_len = 65536;
119 	if (!MACHINE_IS_VM && !MACHINE_IS_P390)
120 		return kmem_start;
121 	tub3270_con_bcb.bc_buf = (void *)kmem_start;
122 	kmem_start += tub3270_con_bcb.bc_len;
123 	register_console(&tub3270_con);
124 	return kmem_start;
125 }
126 #else
127 #define tub3270_con_devno console_device
128 
tub3270_con_init(void)129 void __init tub3270_con_init(void)
130 {
131 	tub3270_con_bcb.bc_len = 65536;
132 	if (!CONSOLE_IS_3270)
133 		return;
134 	tub3270_con_bcb.bc_buf = (void *)alloc_bootmem_low(
135 		tub3270_con_bcb.bc_len);
136 	register_console(&tub3270_con);
137 }
138 #endif
139 
140 static kdev_t
tub3270_con_device(struct console * conp)141 tub3270_con_device(struct console *conp)
142 {
143 	return MKDEV(IBM_TTY3270_MAJOR, conp->index + 1);
144 }
145 
146 static void
tub3270_con_unblank(void)147 tub3270_con_unblank(void)
148 {
149 	/* flush everything:  panic has occurred */
150 }
151 
152 int tub3270_con_write_deadlock_ct;
153 int tub3270_con_write_deadlock_bytes;
154 static void
tub3270_con_write(struct console * conp,const char * buf,unsigned int count)155 tub3270_con_write(struct console *conp,
156 	const char *buf, unsigned int count)
157 {
158 	long flags;
159 	tub_t *tubp = tub3270_con_tubp;
160 	void tty3270_sched_bh(tub_t *);
161 	int rc;
162 	bcb_t obcb;
163 
164 	obcb.bc_buf = (char *)buf;
165 	obcb.bc_len = obcb.bc_cnt = obcb.bc_wr =
166 		MIN(count, tub3270_con_bcb.bc_len);
167 	obcb.bc_rd = 0;
168 
169 	spin_lock_irqsave(&tub3270_con_bcblock, flags);
170 	rc = tub3270_movedata(&obcb, &tub3270_con_bcb, 0);
171 	spin_unlock_irqrestore(&tub3270_con_bcblock, flags);
172 
173 	if (tubp && rc && TUBTRYLOCK(tubp->irq, flags)) {
174 		tty3270_sched_bh(tubp);
175 		TUBUNLOCK(tubp->irq, flags);
176 	}
177 }
178 
tub3270_con_copy(tub_t * tubp)179 int tub3270_con_copy(tub_t *tubp)
180 {
181 	long flags;
182 	int rc;
183 
184 	spin_lock_irqsave(&tub3270_con_bcblock, flags);
185 	rc = tub3270_movedata(&tub3270_con_bcb, &tubp->tty_bcb, 0);
186 	spin_unlock_irqrestore(&tub3270_con_bcblock, flags);
187 	return rc;
188 }
189 #endif /* CONFIG_TN3270_CONSOLE */
190 #else /* If generated as a MODULE */
191 /*
192  * module init:  find tubes; get a major nbr
193  */
194 int
init_module(void)195 init_module(void)
196 {
197 	if (tubnummins != 0) {
198 		printk(KERN_ERR "EEEK!!  Tube driver cobbigling!!\n");
199 		return -1;
200 	}
201 	return tub3270_init();
202 }
203 
204 /*
205  * remove driver:  unregister the major number
206  */
207 void
cleanup_module(void)208 cleanup_module(void)
209 {
210 	fs3270_fini();
211 	tty3270_fini();
212 	tubfiniminors();
213 }
214 #endif /* Not a MODULE or a MODULE */
215 
216 void
tub_inc_use_count(void)217 tub_inc_use_count(void)
218 {
219 	MOD_INC_USE_COUNT;
220 }
221 
222 void
tub_dec_use_count(void)223 tub_dec_use_count(void)
224 {
225 	MOD_DEC_USE_COUNT;
226 }
227 
228 static int
tub3270_is_ours(s390_dev_info_t * dp)229 tub3270_is_ours(s390_dev_info_t *dp)
230 {
231 	if ((dp->sid_data.cu_type & 0xfff0) == 0x3270)
232 		return 1;
233 	if (dp->sid_data.cu_type == 0x3174)
234 		return 1;
235 	return 0;
236 }
237 
238 /*
239  * tub3270_init() called by kernel or module initialization
240  */
241 int
tub3270_init(void)242 tub3270_init(void)
243 {
244 	s390_dev_info_t d;
245 	int i, rc;
246 
247 	/*
248 	 * Copy and correct ebcdic - ascii translate tables
249 	 */
250 	memcpy(tub_ascebc, _ascebc, sizeof tub_ascebc);
251 	memcpy(tub_ebcasc, _ebcasc, sizeof tub_ebcasc);
252 	if (tubxcorrect) {
253 		/* correct brackets and circumflex */
254 		tub_ascebc['['] = 0xad;
255 		tub_ascebc[']'] = 0xbd;
256 		tub_ebcasc[0xad] = '[';
257 		tub_ebcasc[0xbd] = ']';
258 		tub_ascebc['^'] = 0xb0;
259 		tub_ebcasc[0x5f] = '^';
260 	}
261 
262 	rc = tubinitminors();
263 	if (rc != 0)
264 		return rc;
265 
266 	if (fs3270_init() || tty3270_init()) {
267 		printk(KERN_ERR "fs3270_init() or tty3270_init() failed\n");
268 		fs3270_fini();
269 		tty3270_fini();
270 		tubfiniminors();
271 		return -1;
272 	}
273 
274 	for (i = get_irq_first(); i >= 0; i = get_irq_next(i)) {
275 		if ((rc = get_dev_info_by_irq(i, &d)))
276 			continue;
277 		if (d.status)
278 			continue;
279 
280 #ifdef CONFIG_TN3270_CONSOLE
281 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
282 		if (d.sid_data.cu_type == 0x3215 && MACHINE_IS_VM) {
283 			cpcmd("TERM CONMODE 3270", NULL, 0);
284 			d.sid_data.cu_type = 0x3270;
285 		}
286 #else
287 		if (d.sid_data.cu_type == 0x3215 && CONSOLE_IS_3270) {
288 			cpcmd("TERM CONMODE 3270", NULL, 0);
289 			d.sid_data.cu_type = 0x3270;
290 		}
291 #endif /* LINUX_VERSION_CODE */
292 #endif /* CONFIG_TN3270_CONSOLE */
293 		if (!tub3270_is_ours(&d))
294 			continue;
295 
296 		rc = tubmakemin(i, &d);
297 		if (rc < 0) {
298 			printk(KERN_WARNING
299 			       "3270 tube registration ran out of memory"
300 			       " after %d devices\n", tubnummins - 1);
301 			break;
302 		} else {
303 			printk(KERN_INFO "3270: %.4x on sch %d, minor %d\n",
304 				d.devno, d.irq, rc);
305 		}
306 	}
307 
308 	return 0;
309 }
310 
311 /*
312  * tub3270_movedata(bcb_t *, bcb_t *) -- Move data stream
313  */
314 int
tub3270_movedata(bcb_t * ib,bcb_t * ob,int fromuser)315 tub3270_movedata(bcb_t *ib, bcb_t *ob, int fromuser)
316 {
317 	int count;			/* Total move length */
318 	int rc;
319 
320 	rc = count = MIN(ib->bc_cnt, ob->bc_len - ob->bc_cnt);
321 	while (count > 0) {
322 		int len1;		/* Contig bytes avail in ib */
323 
324 		if (ib->bc_wr > ib->bc_rd)
325 			len1 = ib->bc_wr - ib->bc_rd;
326 		else
327 			len1 = ib->bc_len - ib->bc_rd;
328 		if (len1 > count)
329 			len1 = count;
330 
331 		while (len1 > 0) {
332 			int len2;	/* Contig space avail in ob */
333 
334 			if (ob->bc_rd > ob->bc_wr)
335 				len2 = ob->bc_rd - ob->bc_wr;
336 			else
337 				len2 = ob->bc_len - ob->bc_wr;
338 			if (len2 > len1)
339 				len2 = len1;
340 
341 			if (fromuser) {
342 				len2 -= copy_from_user(ob->bc_buf + ob->bc_wr,
343 						       ib->bc_buf + ib->bc_rd,
344 						       len2);
345 				if (len2 == 0) {
346 					if (!rc)
347 						rc = -EFAULT;
348 					break;
349 				}
350 			} else
351 				memcpy(ob->bc_buf + ob->bc_wr,
352 				       ib->bc_buf + ib->bc_rd,
353 				       len2);
354 
355 			ib->bc_rd += len2;
356 			if (ib->bc_rd == ib->bc_len)
357 				ib->bc_rd = 0;
358 			ib->bc_cnt -= len2;
359 
360 			ob->bc_wr += len2;
361 			if (ob->bc_wr == ob->bc_len)
362 				ob->bc_wr = 0;
363 			ob->bc_cnt += len2;
364 
365 			len1 -= len2;
366 			count -= len2;
367 		}
368 	}
369 	return rc;
370 }
371 
372 /*
373  * receive an interrupt
374  */
375 void
tubint(int irq,void * ipp,struct pt_regs * prp)376 tubint(int irq, void *ipp, struct pt_regs *prp)
377 {
378 	devstat_t *dsp = ipp;
379 	tub_t *tubp;
380 
381 	if ((tubp = IRQ2TUB(irq)) && (tubp->intv))
382 		(tubp->intv)(tubp, dsp);
383 }
384 
385 /*
386  * Initialize array of pointers to minor structures tub_t.
387  * Returns 0 or -ENOMEM.
388  */
389 int
tubinitminors(void)390 tubinitminors(void)
391 {
392 	tubminors = (tub_t *(*)[TUBMAXMINS])kmalloc(sizeof *tubminors,
393 		GFP_KERNEL);
394 	if (tubminors == NULL)
395 		return -ENOMEM;
396 	memset(tubminors, 0, sizeof *tubminors);
397 	return 0;
398 }
399 
400 /*
401  * Add a minor 327x device.  Argument is an irq value.
402  *
403  * Point elements of two arrays to the newly created tub_t:
404  * 1. (*tubminors)[minor]
405  * 2. (*(*tubirqs)[irqhi])[irqlo]
406  * The first looks up from minor number at context time; the second
407  * looks up from irq at interrupt time.
408  */
409 int
410 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
tubmakemin(int irq,dev_info_t * dp)411 tubmakemin(int irq, dev_info_t *dp)
412 #else
413 tubmakemin(int irq, s390_dev_info_t *dp)
414 #endif
415 {
416 	tub_t *tubp;
417 	int minor;
418 	long flags;
419 
420 	if ((minor = ++tubnummins) == TUBMAXMINS)
421 		return -ENODEV;
422 
423 	tubp = kmalloc(sizeof(tub_t), GFP_KERNEL);
424 	if (tubp == NULL) {
425 		return -ENOMEM;
426 	}
427 	if (tubaddbyirq(tubp, irq) != 0) {
428 		kfree(tubp);
429 		return -ENOMEM;
430 	}
431 	memset(tubp, 0, sizeof(tub_t));
432 	tubp->minor = minor;
433 	tubp->irq = irq;
434 	TUBLOCK(tubp->irq, flags);
435 	tubp->devno = dp->devno;
436 	tubp->geom_rows = _GEOM_ROWS;
437 	tubp->geom_cols = _GEOM_COLS;
438 	init_waitqueue_head(&tubp->waitq);
439 
440 	tubp->tty_bcb.bc_len = TTY_OUTPUT_SIZE;
441 	tubp->tty_bcb.bc_buf = (void *)kmalloc(tubp->tty_bcb.bc_len,
442 		GFP_KERNEL|GFP_DMA);
443 	if (tubp->tty_bcb.bc_buf == NULL) {
444 		TUBUNLOCK(tubp->irq, flags);
445 		tubdelbyirq(tubp, irq);
446 		kfree(tubp);
447 		return -ENOMEM;
448 	}
449 	tubp->tty_bcb.bc_cnt = 0;
450 	tubp->tty_bcb.bc_wr = 0;
451 	tubp->tty_bcb.bc_rd = 0;
452 	(*tubminors)[minor] = tubp;
453 
454 #ifdef CONFIG_TN3270_CONSOLE
455 	if (CONSOLE_IS_3270) {
456 		if (tub3270_con_tubp == NULL &&
457 		    tub3270_con_bcb.bc_buf != NULL &&
458 		    (tub3270_con_devno == -1 ||
459 		     tub3270_con_devno == dp->devno)) {
460 			extern void tty3270_int(tub_t *, devstat_t *);
461 
462 			tub3270_con_devno = dp->devno;
463 			tubp->cmd = TBC_CONOPEN;
464 			tubp->flags |= TUB_OPEN_STET | TUB_INPUT_HACK;
465 			tty3270_size(tubp, &flags);
466 			tubp->tty_input = kmalloc(GEOM_INPLEN,
467 				GFP_KERNEL|GFP_DMA);
468 			tty3270_aid_init(tubp);
469 			tty3270_scl_init(tubp);
470 			tub3270_con_irq = tubp->irq;
471 			tub3270_con_tubp = tubp;
472 			tubp->intv = tty3270_int;
473 			tubp->cmd = TBC_UPDSTAT;
474 			tty3270_build(tubp);
475 		}
476 	}
477 #endif /* CONFIG_TN3270_CONSOLE */
478 
479 #ifdef CONFIG_DEVFS_FS
480 	fs3270_devfs_register(tubp);
481 #endif
482 
483 	TUBUNLOCK(tubp->irq, flags);
484 	return minor;
485 }
486 
487 /*
488  * Release array of pointers to minor structures tub_t, but first
489  * release any storage pointed to by them.
490  */
491 void
tubfiniminors(void)492 tubfiniminors(void)
493 {
494 	int i;
495 	tub_t **tubpp, *tubp;
496 
497 	if (tubminors == NULL)
498 		return;
499 
500 	for (i = 0; i < TUBMAXMINS; i++) {
501 		tubpp = &(*tubminors)[i];
502 		if ((tubp = *tubpp)) {
503 #ifdef CONFIG_DEVFS_FS
504 			fs3270_devfs_unregister(tubp);
505 #endif
506 			tubdelbyirq(tubp, tubp->irq);
507 			tty3270_rcl_fini(tubp);
508 			kfree(tubp->tty_bcb.bc_buf);
509 			if (tubp->tty_input) {
510 				kfree(tubp->tty_input);
511 				tubp->tty_input = NULL;
512 			}
513 			tubp->tty_bcb.bc_buf = NULL;
514 			tubp->ttyscreen = NULL;
515 			kfree(tubp);
516 			*tubpp = NULL;
517 		}
518 	}
519 	kfree(tubminors);
520 	tubminors = NULL;
521 	tubfiniirqs();
522 }
523 
524 /*
525  * tubaddbyirq() -- Add tub_t for irq lookup in tubint()
526  */
527 int
tubaddbyirq(tub_t * tubp,int irq)528 tubaddbyirq(tub_t *tubp, int irq)
529 {
530 	int irqhi = (irq >> 8) & 255;
531 	int irqlo = irq & 255;
532 	tub_t *(*itubpp)[256];
533 
534 	/* Allocate array (*tubirqs)[] if first time */
535 	if (tubirqs == NULL) {
536 		tubirqs = (tub_t *(*(*)[256])[256])
537 			kmalloc(sizeof *tubirqs, GFP_KERNEL);
538 		if (tubirqs == NULL)
539 			return -ENOMEM;
540 		memset(tubirqs, 0, sizeof *tubirqs);
541 	}
542 
543 	/* Allocate subarray (*(*tubirqs)[])[] if first use */
544 	if ((itubpp = (*tubirqs)[irqhi]) == NULL) {
545 		itubpp = (tub_t *(*)[256])
546 			kmalloc(sizeof(*itubpp), GFP_KERNEL);
547 		if (itubpp == NULL) {
548 			if (tubnummins == 1) {  /* if first time */
549 				kfree(tubirqs);
550 				tubirqs = NULL;
551 			}
552 			return -ENOMEM;
553 		} else {
554 			memset(itubpp, 0, sizeof(*itubpp));
555 			(*tubirqs)[irqhi] = itubpp;
556 		}
557 	}
558 
559 	/* Request interrupt service */
560 	if ((tubp->irqrc = request_irq(irq, tubint, SA_INTERRUPT,
561 	    "3270 tube driver", &tubp->devstat)) != 0)
562 		return tubp->irqrc;
563 
564 	/* Fill in the proper subarray element */
565 	(*itubpp)[irqlo] = tubp;
566 	return 0;
567 }
568 
569 /*
570  * tubfindbyirq(irq)
571  */
572 tub_t *
tubfindbyirq(int irq)573 tubfindbyirq(int irq)
574 {
575 	int irqhi = (irq >> 8) & 255;
576 	int irqlo = irq & 255;
577 	tub_t *tubp;
578 
579 	if (tubirqs == NULL)
580 		return NULL;
581 	if ((*tubirqs)[irqhi] == NULL)
582 		return NULL;
583 	tubp = (*(*tubirqs)[irqhi])[irqlo];
584 	if (tubp->irq == irq)
585 		return tubp;
586 	return NULL;
587 }
588 
589 /*
590  * tubdelbyirq(tub_t*, irq)
591  */
592 void
tubdelbyirq(tub_t * tubp,int irq)593 tubdelbyirq(tub_t *tubp, int irq)
594 {
595 	int irqhi = (irq >> 8) & 255;
596 	int irqlo = irq & 255;
597 	tub_t *(*itubpp)[256], *itubp;
598 
599 	if (tubirqs == NULL) {
600 		printk(KERN_ERR "tubirqs is NULL\n");
601 		return;
602 	}
603 	itubpp = (*tubirqs)[irqhi];
604 	if (itubpp == NULL) {
605 		printk(KERN_ERR "tubirqs[%d] is NULL\n", irqhi);
606 		return;
607 	}
608 	itubp = (*itubpp)[irqlo];
609 	if (itubp == NULL) {
610 		printk(KERN_ERR "tubirqs[%d][%d] is NULL\n", irqhi, irqlo);
611 		return;
612 	}
613 	if (itubp->irqrc == 0)
614 		free_irq(irq, &itubp->devstat);
615 	(*itubpp)[irqlo] = NULL;
616 }
617 
618 /*
619  * tubfiniirqs() -- clean up storage in tub_t *(*(*tubirqs)[256])[256]
620  */
621 void
tubfiniirqs(void)622 tubfiniirqs(void)
623 {
624 	int i;
625 	tub_t *(*itubpp)[256];
626 
627 	if (tubirqs != NULL) {
628 		for (i = 0; i < 256; i++) {
629 			if ((itubpp = (*tubirqs)[i])) {
630 				kfree(itubpp);
631 				(*tubirqs)[i] = NULL;
632 			}
633 		}
634 		kfree(tubirqs);
635 		tubirqs = NULL;
636 	}
637 }
638