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