OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [s390/] [char/] [tuball.c] - Blame information for rev 1275

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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() */
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
 
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
 
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
141
tub3270_con_device(struct console *conp)
142
{
143
        return MKDEV(IBM_TTY3270_MAJOR, conp->index + 1);
144
}
145
 
146
static 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
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
 
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
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
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
217
tub_inc_use_count(void)
218
{
219
        MOD_INC_USE_COUNT;
220
}
221
 
222
void
223
tub_dec_use_count(void)
224
{
225
        MOD_DEC_USE_COUNT;
226
}
227
 
228
static int
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
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
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
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
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))
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
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
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 *
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
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
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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.