2 * IBM/3270 Driver -- Copyright (C) 2000 UTS Global LLC
4 * tuball.c -- Initialization, termination, irq lookup
10 * Author: Richard Hitt
12 #include <linux/config.h>
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>
20 #include "../../../../arch/s390/kernel/cpcmd.h"
24 /* Module parameters */
26 int tubscrolltime = -1;
27 int tubxcorrect = 1; /* Do correct ebc<->asc tables */
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");
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
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 *);
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);
57 extern int fs3270_init(void);
58 extern void fs3270_fini(void);
59 extern int tty3270_init(void);
60 extern void tty3270_fini(void);
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 };
72 int tub3270_init(void);
77 * Can't have this driver a module & support console at the same time
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 *,
85 static struct console tub3270_con = {
87 tub3270_con_write, /* write */
89 tub3270_con_device, /* device */
90 tub3270_con_unblank, /* unblank */
92 CON_PRINTBUFFER, /* flags */
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 */
104 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
105 int tub3270_con_devno = -1; /* set by tub3270_con_setup() */
106 __initfunc(void tub3270_con_setup(char *str, int *ints))
110 vdev = simple_strtoul(str, 0, 16);
111 if (vdev >= 0 && vdev < 65536)
112 tub3270_con_devno = vdev;
116 __initfunc (long tub3270_con_init(long kmem_start, long kmem_end))
118 tub3270_con_bcb.bc_len = 65536;
119 if (!MACHINE_IS_VM && !MACHINE_IS_P390)
121 tub3270_con_bcb.bc_buf = (void *)kmem_start;
122 kmem_start += tub3270_con_bcb.bc_len;
123 register_console(&tub3270_con);
127 #define tub3270_con_devno console_device
129 void __init tub3270_con_init(void)
131 tub3270_con_bcb.bc_len = 65536;
132 if (!CONSOLE_IS_3270)
134 tub3270_con_bcb.bc_buf = (void *)alloc_bootmem_low(
135 tub3270_con_bcb.bc_len);
136 register_console(&tub3270_con);
141 tub3270_con_device(struct console *conp)
143 return MKDEV(IBM_TTY3270_MAJOR, conp->index + 1);
147 tub3270_con_unblank(void)
149 /* flush everything: panic has occurred */
152 int tub3270_con_write_deadlock_ct;
153 int tub3270_con_write_deadlock_bytes;
155 tub3270_con_write(struct console *conp,
156 const char *buf, unsigned int count)
159 tub_t *tubp = tub3270_con_tubp;
160 void tty3270_sched_bh(tub_t *);
164 obcb.bc_buf = (char *)buf;
165 obcb.bc_len = obcb.bc_cnt = obcb.bc_wr =
166 MIN(count, tub3270_con_bcb.bc_len);
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);
173 if (tubp && rc && TUBTRYLOCK(tubp->irq, flags)) {
174 tty3270_sched_bh(tubp);
175 TUBUNLOCK(tubp->irq, flags);
179 int tub3270_con_copy(tub_t *tubp)
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);
189 #endif /* CONFIG_TN3270_CONSOLE */
190 #else /* If generated as a MODULE */
192 * module init: find tubes; get a major nbr
197 if (tubnummins != 0) {
198 printk(KERN_ERR "EEEK!! Tube driver cobbigling!!\n");
201 return tub3270_init();
205 * remove driver: unregister the major number
214 #endif /* Not a MODULE or a MODULE */
217 tub_inc_use_count(void)
223 tub_dec_use_count(void)
229 tub3270_is_ours(s390_dev_info_t *dp)
231 if ((dp->sid_data.cu_type & 0xfff0) == 0x3270)
233 if (dp->sid_data.cu_type == 0x3174)
239 * tub3270_init() called by kernel or module initialization
248 * Copy and correct ebcdic - ascii translate tables
250 memcpy(tub_ascebc, _ascebc, sizeof tub_ascebc);
251 memcpy(tub_ebcasc, _ebcasc, sizeof tub_ebcasc);
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] = '^';
262 rc = tubinitminors();
266 if (fs3270_init() || tty3270_init()) {
267 printk(KERN_ERR "fs3270_init() or tty3270_init() failed\n");
274 for (i = get_irq_first(); i >= 0; i = get_irq_next(i)) {
275 if ((rc = get_dev_info_by_irq(i, &d)))
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;
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;
291 #endif /* LINUX_VERSION_CODE */
292 #endif /* CONFIG_TN3270_CONSOLE */
293 if (!tub3270_is_ours(&d))
296 rc = tubmakemin(i, &d);
299 "3270 tube registration ran out of memory"
300 " after %d devices\n", tubnummins - 1);
303 printk(KERN_INFO "3270: %.4x on sch %d, minor %d\n",
312 * tub3270_movedata(bcb_t *, bcb_t *) -- Move data stream
315 tub3270_movedata(bcb_t *ib, bcb_t *ob, int fromuser)
317 int count; /* Total move length */
320 rc = count = MIN(ib->bc_cnt, ob->bc_len - ob->bc_cnt);
322 int len1; /* Contig bytes avail in ib */
324 if (ib->bc_wr > ib->bc_rd)
325 len1 = ib->bc_wr - ib->bc_rd;
327 len1 = ib->bc_len - ib->bc_rd;
332 int len2; /* Contig space avail in ob */
334 if (ob->bc_rd > ob->bc_wr)
335 len2 = ob->bc_rd - ob->bc_wr;
337 len2 = ob->bc_len - ob->bc_wr;
342 len2 -= copy_from_user(ob->bc_buf + ob->bc_wr,
343 ib->bc_buf + ib->bc_rd,
351 memcpy(ob->bc_buf + ob->bc_wr,
352 ib->bc_buf + ib->bc_rd,
356 if (ib->bc_rd == ib->bc_len)
361 if (ob->bc_wr == ob->bc_len)
373 * receive an interrupt
376 tubint(int irq, void *ipp, struct pt_regs *prp)
378 devstat_t *dsp = ipp;
381 if ((tubp = IRQ2TUB(irq)) && (tubp->intv))
382 (tubp->intv)(tubp, dsp);
386 * Initialize array of pointers to minor structures tub_t.
387 * Returns 0 or -ENOMEM.
392 tubminors = (tub_t *(*)[TUBMAXMINS])kmalloc(sizeof *tubminors,
394 if (tubminors == NULL)
396 memset(tubminors, 0, sizeof *tubminors);
401 * Add a minor 327x device. Argument is an irq value.
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.
410 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
411 tubmakemin(int irq, dev_info_t *dp)
413 tubmakemin(int irq, s390_dev_info_t *dp)
420 if ((minor = ++tubnummins) == TUBMAXMINS)
423 tubp = kmalloc(sizeof(tub_t), GFP_KERNEL);
427 if (tubaddbyirq(tubp, irq) != 0) {
431 memset(tubp, 0, sizeof(tub_t));
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);
440 tubp->tty_bcb.bc_len = TTY_OUTPUT_SIZE;
441 tubp->tty_bcb.bc_buf = (void *)kmalloc(tubp->tty_bcb.bc_len,
443 if (tubp->tty_bcb.bc_buf == NULL) {
444 TUBUNLOCK(tubp->irq, flags);
445 tubdelbyirq(tubp, irq);
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;
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 *);
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,
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;
477 #endif /* CONFIG_TN3270_CONSOLE */
479 #ifdef CONFIG_DEVFS_FS
480 fs3270_devfs_register(tubp);
483 TUBUNLOCK(tubp->irq, flags);
488 * Release array of pointers to minor structures tub_t, but first
489 * release any storage pointed to by them.
495 tub_t **tubpp, *tubp;
497 if (tubminors == NULL)
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);
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;
513 tubp->tty_bcb.bc_buf = NULL;
514 tubp->ttyscreen = NULL;
525 * tubaddbyirq() -- Add tub_t for irq lookup in tubint()
528 tubaddbyirq(tub_t *tubp, int irq)
530 int irqhi = (irq >> 8) & 255;
531 int irqlo = irq & 255;
532 tub_t *(*itubpp)[256];
534 /* Allocate array (*tubirqs)[] if first time */
535 if (tubirqs == NULL) {
536 tubirqs = (tub_t *(*(*)[256])[256])
537 kmalloc(sizeof *tubirqs, GFP_KERNEL);
540 memset(tubirqs, 0, sizeof *tubirqs);
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 */
554 memset(itubpp, 0, sizeof(*itubpp));
555 (*tubirqs)[irqhi] = itubpp;
559 /* Request interrupt service */
560 if ((tubp->irqrc = request_irq(irq, tubint, SA_INTERRUPT,
561 "3270 tube driver", &tubp->devstat)) != 0)
564 /* Fill in the proper subarray element */
565 (*itubpp)[irqlo] = tubp;
573 tubfindbyirq(int irq)
575 int irqhi = (irq >> 8) & 255;
576 int irqlo = irq & 255;
581 if ((*tubirqs)[irqhi] == NULL)
583 tubp = (*(*tubirqs)[irqhi])[irqlo];
584 if (tubp->irq == irq)
590 * tubdelbyirq(tub_t*, irq)
593 tubdelbyirq(tub_t *tubp, int irq)
595 int irqhi = (irq >> 8) & 255;
596 int irqlo = irq & 255;
597 tub_t *(*itubpp)[256], *itubp;
599 if (tubirqs == NULL) {
600 printk(KERN_ERR "tubirqs is NULL\n");
603 itubpp = (*tubirqs)[irqhi];
604 if (itubpp == NULL) {
605 printk(KERN_ERR "tubirqs[%d] is NULL\n", irqhi);
608 itubp = (*itubpp)[irqlo];
610 printk(KERN_ERR "tubirqs[%d][%d] is NULL\n", irqhi, irqlo);
613 if (itubp->irqrc == 0)
614 free_irq(irq, &itubp->devstat);
615 (*itubpp)[irqlo] = NULL;
619 * tubfiniirqs() -- clean up storage in tub_t *(*(*tubirqs)[256])[256]
625 tub_t *(*itubpp)[256];
627 if (tubirqs != NULL) {
628 for (i = 0; i < 256; i++) {
629 if ((itubpp = (*tubirqs)[i])) {
631 (*tubirqs)[i] = NULL;