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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [char/] [viocons.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/* -*- linux-c -*-
2
 *
3
 *  drivers/char/viocons.c
4
 *
5
 *  iSeries Virtual Terminal
6
 *
7
 *  Authors: Dave Boutcher <boutcher@us.ibm.com>
8
 *           Ryan Arnold <ryanarn@us.ibm.com>
9
 *           Colin Devilbiss <devilbis@us.ibm.com>
10
 *           Stephen Rothwell <sfr@au1.ibm.com>
11
 *
12
 * (C) Copyright 2000, 2001, 2002, 2003, 2004 IBM Corporation
13
 *
14
 * This program is free software;  you can redistribute it and/or
15
 * modify it under the terms of the GNU General Public License as
16
 * published by the Free Software Foundation; either version 2 of the
17
 * License, or (at your option) anyu later version.
18
 *
19
 * This program is distributed in the hope that it will be useful, but
20
 * WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
22
 * General Public License for more details.
23
 *
24
 * You should have received a copy of the GNU General Public License
25
 * along with this program; if not, write to the Free Software Foundation,
26
 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27
 */
28
#include <linux/kernel.h>
29
#include <linux/proc_fs.h>
30
#include <linux/errno.h>
31
#include <linux/vmalloc.h>
32
#include <linux/mm.h>
33
#include <linux/console.h>
34
#include <linux/module.h>
35
#include <asm/uaccess.h>
36
#include <linux/init.h>
37
#include <linux/wait.h>
38
#include <linux/spinlock.h>
39
#include <asm/ioctls.h>
40
#include <linux/kd.h>
41
#include <linux/tty.h>
42
#include <linux/tty_flip.h>
43
#include <linux/sysrq.h>
44
 
45
#include <asm/firmware.h>
46
#include <asm/iseries/vio.h>
47
#include <asm/iseries/hv_lp_event.h>
48
#include <asm/iseries/hv_call_event.h>
49
#include <asm/iseries/hv_lp_config.h>
50
#include <asm/iseries/hv_call.h>
51
 
52
#ifdef CONFIG_VT
53
#error You must turn off CONFIG_VT to use CONFIG_VIOCONS
54
#endif
55
 
56
#define VIOTTY_MAGIC (0x0DCB)
57
#define VTTY_PORTS 10
58
 
59
#define VIOCONS_KERN_WARN       KERN_WARNING "viocons: "
60
#define VIOCONS_KERN_INFO       KERN_INFO "viocons: "
61
 
62
static DEFINE_SPINLOCK(consolelock);
63
static DEFINE_SPINLOCK(consoleloglock);
64
 
65
static int vio_sysrq_pressed;
66
 
67
#define VIOCHAR_NUM_BUF         16
68
 
69
/*
70
 * Our port information.  We store a pointer to one entry in the
71
 * tty_driver_data
72
 */
73
static struct port_info {
74
        int magic;
75
        struct tty_struct *tty;
76
        HvLpIndex lp;
77
        u8 vcons;
78
        u64 seq;        /* sequence number of last HV send */
79
        u64 ack;        /* last ack from HV */
80
/*
81
 * When we get writes faster than we can send it to the partition,
82
 * buffer the data here. Note that used is a bit map of used buffers.
83
 * It had better have enough bits to hold VIOCHAR_NUM_BUF the bitops assume
84
 * it is a multiple of unsigned long
85
 */
86
        unsigned long used;
87
        u8 *buffer[VIOCHAR_NUM_BUF];
88
        int bufferBytes[VIOCHAR_NUM_BUF];
89
        int curbuf;
90
        int bufferOverflow;
91
        int overflowMessage;
92
} port_info[VTTY_PORTS];
93
 
94
#define viochar_is_console(pi)  ((pi) == &port_info[0])
95
#define viochar_port(pi)        ((pi) - &port_info[0])
96
 
97
static void initDataEvent(struct viocharlpevent *viochar, HvLpIndex lp);
98
 
99
static struct tty_driver *viotty_driver;
100
 
101
static void hvlog(char *fmt, ...)
102
{
103
        int i;
104
        unsigned long flags;
105
        va_list args;
106
        static char buf[256];
107
 
108
        spin_lock_irqsave(&consoleloglock, flags);
109
        va_start(args, fmt);
110
        i = vscnprintf(buf, sizeof(buf) - 1, fmt, args);
111
        va_end(args);
112
        buf[i++] = '\r';
113
        HvCall_writeLogBuffer(buf, i);
114
        spin_unlock_irqrestore(&consoleloglock, flags);
115
}
116
 
117
static void hvlogOutput(const char *buf, int count)
118
{
119
        unsigned long flags;
120
        int begin;
121
        int index;
122
        static const char cr = '\r';
123
 
124
        begin = 0;
125
        spin_lock_irqsave(&consoleloglock, flags);
126
        for (index = 0; index < count; index++) {
127
                if (buf[index] == '\n') {
128
                        /*
129
                         * Start right after the last '\n' or at the zeroth
130
                         * array position and output the number of characters
131
                         * including the newline.
132
                         */
133
                        HvCall_writeLogBuffer(&buf[begin], index - begin + 1);
134
                        begin = index + 1;
135
                        HvCall_writeLogBuffer(&cr, 1);
136
                }
137
        }
138
        if ((index - begin) > 0)
139
                HvCall_writeLogBuffer(&buf[begin], index - begin);
140
        spin_unlock_irqrestore(&consoleloglock, flags);
141
}
142
 
143
/*
144
 * Make sure we're pointing to a valid port_info structure.  Shamelessly
145
 * plagerized from serial.c
146
 */
147
static inline int viotty_paranoia_check(struct port_info *pi,
148
                                        char *name, const char *routine)
149
{
150
        static const char *bad_pi_addr = VIOCONS_KERN_WARN
151
                "warning: bad address for port_info struct (%s) in %s\n";
152
        static const char *badmagic = VIOCONS_KERN_WARN
153
                "warning: bad magic number for port_info struct (%s) in %s\n";
154
 
155
        if ((pi < &port_info[0]) || (viochar_port(pi) > VTTY_PORTS)) {
156
                printk(bad_pi_addr, name, routine);
157
                return 1;
158
        }
159
        if (pi->magic != VIOTTY_MAGIC) {
160
                printk(badmagic, name, routine);
161
                return 1;
162
        }
163
        return 0;
164
}
165
 
166
/*
167
 * Add data to our pending-send buffers.
168
 *
169
 * NOTE: Don't use printk in here because it gets nastily recursive.
170
 * hvlog can be used to log to the hypervisor buffer
171
 */
172
static int buffer_add(struct port_info *pi, const char *buf, size_t len)
173
{
174
        size_t bleft;
175
        size_t curlen;
176
        const char *curbuf;
177
        int nextbuf;
178
 
179
        curbuf = buf;
180
        bleft = len;
181
        while (bleft > 0) {
182
                /*
183
                 * If there is no space left in the current buffer, we have
184
                 * filled everything up, so return.  If we filled the previous
185
                 * buffer we would already have moved to the next one.
186
                 */
187
                if (pi->bufferBytes[pi->curbuf] == VIOCHAR_MAX_DATA) {
188
                        hvlog ("\n\rviocons: No overflow buffer available for memcpy().\n");
189
                        pi->bufferOverflow++;
190
                        pi->overflowMessage = 1;
191
                        break;
192
                }
193
 
194
                /*
195
                 * Turn on the "used" bit for this buffer.  If it's already on,
196
                 * that's fine.
197
                 */
198
                set_bit(pi->curbuf, &pi->used);
199
 
200
                /*
201
                 * See if this buffer has been allocated.  If not, allocate it.
202
                 */
203
                if (pi->buffer[pi->curbuf] == NULL) {
204
                        pi->buffer[pi->curbuf] =
205
                            kmalloc(VIOCHAR_MAX_DATA, GFP_ATOMIC);
206
                        if (pi->buffer[pi->curbuf] == NULL) {
207
                                hvlog("\n\rviocons: kmalloc failed allocating spaces for buffer %d.",
208
                                        pi->curbuf);
209
                                break;
210
                        }
211
                }
212
 
213
                /* Figure out how much we can copy into this buffer. */
214
                if (bleft < (VIOCHAR_MAX_DATA - pi->bufferBytes[pi->curbuf]))
215
                        curlen = bleft;
216
                else
217
                        curlen = VIOCHAR_MAX_DATA - pi->bufferBytes[pi->curbuf];
218
 
219
                /* Copy the data into the buffer. */
220
                memcpy(pi->buffer[pi->curbuf] + pi->bufferBytes[pi->curbuf],
221
                                curbuf, curlen);
222
 
223
                pi->bufferBytes[pi->curbuf] += curlen;
224
                curbuf += curlen;
225
                bleft -= curlen;
226
 
227
                /*
228
                 * Now see if we've filled this buffer.  If not then
229
                 * we'll try to use it again later.  If we've filled it
230
                 * up then we'll advance the curbuf to the next in the
231
                 * circular queue.
232
                 */
233
                if (pi->bufferBytes[pi->curbuf] == VIOCHAR_MAX_DATA) {
234
                        nextbuf = (pi->curbuf + 1) % VIOCHAR_NUM_BUF;
235
                        /*
236
                         * Move to the next buffer if it hasn't been used yet
237
                         */
238
                        if (test_bit(nextbuf, &pi->used) == 0)
239
                                pi->curbuf = nextbuf;
240
                }
241
        }
242
        return len - bleft;
243
}
244
 
245
/*
246
 * Send pending data
247
 *
248
 * NOTE: Don't use printk in here because it gets nastily recursive.
249
 * hvlog can be used to log to the hypervisor buffer
250
 */
251
static void send_buffers(struct port_info *pi)
252
{
253
        HvLpEvent_Rc hvrc;
254
        int nextbuf;
255
        struct viocharlpevent *viochar;
256
        unsigned long flags;
257
 
258
        spin_lock_irqsave(&consolelock, flags);
259
 
260
        viochar = (struct viocharlpevent *)
261
            vio_get_event_buffer(viomajorsubtype_chario);
262
 
263
        /* Make sure we got a buffer */
264
        if (viochar == NULL) {
265
                hvlog("\n\rviocons: Can't get viochar buffer in sendBuffers().");
266
                spin_unlock_irqrestore(&consolelock, flags);
267
                return;
268
        }
269
 
270
        if (pi->used == 0) {
271
                hvlog("\n\rviocons: in sendbuffers(), but no buffers used.\n");
272
                vio_free_event_buffer(viomajorsubtype_chario, viochar);
273
                spin_unlock_irqrestore(&consolelock, flags);
274
                return;
275
        }
276
 
277
        /*
278
         * curbuf points to the buffer we're filling.  We want to
279
         * start sending AFTER this one.
280
         */
281
        nextbuf = (pi->curbuf + 1) % VIOCHAR_NUM_BUF;
282
 
283
        /*
284
         * Loop until we find a buffer with the used bit on
285
         */
286
        while (test_bit(nextbuf, &pi->used) == 0)
287
                nextbuf = (nextbuf + 1) % VIOCHAR_NUM_BUF;
288
 
289
        initDataEvent(viochar, pi->lp);
290
 
291
        /*
292
         * While we have buffers with data, and our send window
293
         * is open, send them
294
         */
295
        while ((test_bit(nextbuf, &pi->used)) &&
296
               ((pi->seq - pi->ack) < VIOCHAR_WINDOW)) {
297
                viochar->len = pi->bufferBytes[nextbuf];
298
                viochar->event.xCorrelationToken = pi->seq++;
299
                viochar->event.xSizeMinus1 =
300
                        offsetof(struct viocharlpevent, data) + viochar->len;
301
 
302
                memcpy(viochar->data, pi->buffer[nextbuf], viochar->len);
303
 
304
                hvrc = HvCallEvent_signalLpEvent(&viochar->event);
305
                if (hvrc) {
306
                        /*
307
                         * MUST unlock the spinlock before doing a printk
308
                         */
309
                        vio_free_event_buffer(viomajorsubtype_chario, viochar);
310
                        spin_unlock_irqrestore(&consolelock, flags);
311
 
312
                        printk(VIOCONS_KERN_WARN
313
                               "error sending event! return code %d\n",
314
                               (int)hvrc);
315
                        return;
316
                }
317
 
318
                /*
319
                 * clear the used bit, zero the number of bytes in
320
                 * this buffer, and move to the next buffer
321
                 */
322
                clear_bit(nextbuf, &pi->used);
323
                pi->bufferBytes[nextbuf] = 0;
324
                nextbuf = (nextbuf + 1) % VIOCHAR_NUM_BUF;
325
        }
326
 
327
        /*
328
         * If we have emptied all the buffers, start at 0 again.
329
         * this will re-use any allocated buffers
330
         */
331
        if (pi->used == 0) {
332
                pi->curbuf = 0;
333
 
334
                if (pi->overflowMessage)
335
                        pi->overflowMessage = 0;
336
 
337
                if (pi->tty) {
338
                        tty_wakeup(pi->tty);
339
                }
340
        }
341
 
342
        vio_free_event_buffer(viomajorsubtype_chario, viochar);
343
        spin_unlock_irqrestore(&consolelock, flags);
344
}
345
 
346
/*
347
 * Our internal writer.  Gets called both from the console device and
348
 * the tty device.  the tty pointer will be NULL if called from the console.
349
 * Return total number of bytes "written".
350
 *
351
 * NOTE: Don't use printk in here because it gets nastily recursive.  hvlog
352
 * can be used to log to the hypervisor buffer
353
 */
354
static int internal_write(struct port_info *pi, const char *buf, size_t len)
355
{
356
        HvLpEvent_Rc hvrc;
357
        size_t bleft;
358
        size_t curlen;
359
        const char *curbuf;
360
        unsigned long flags;
361
        struct viocharlpevent *viochar;
362
 
363
        /*
364
         * Write to the hvlog of inbound data are now done prior to
365
         * calling internal_write() since internal_write() is only called in
366
         * the event that an lp event path is active, which isn't the case for
367
         * logging attempts prior to console initialization.
368
         *
369
         * If there is already data queued for this port, send it prior to
370
         * attempting to send any new data.
371
         */
372
        if (pi->used)
373
                send_buffers(pi);
374
 
375
        spin_lock_irqsave(&consolelock, flags);
376
 
377
        viochar = vio_get_event_buffer(viomajorsubtype_chario);
378
        if (viochar == NULL) {
379
                spin_unlock_irqrestore(&consolelock, flags);
380
                hvlog("\n\rviocons: Can't get vio buffer in internal_write().");
381
                return -EAGAIN;
382
        }
383
        initDataEvent(viochar, pi->lp);
384
 
385
        curbuf = buf;
386
        bleft = len;
387
 
388
        while ((bleft > 0) && (pi->used == 0) &&
389
               ((pi->seq - pi->ack) < VIOCHAR_WINDOW)) {
390
                if (bleft > VIOCHAR_MAX_DATA)
391
                        curlen = VIOCHAR_MAX_DATA;
392
                else
393
                        curlen = bleft;
394
 
395
                viochar->event.xCorrelationToken = pi->seq++;
396
                memcpy(viochar->data, curbuf, curlen);
397
                viochar->len = curlen;
398
                viochar->event.xSizeMinus1 =
399
                    offsetof(struct viocharlpevent, data) + curlen;
400
 
401
                hvrc = HvCallEvent_signalLpEvent(&viochar->event);
402
                if (hvrc) {
403
                        hvlog("viocons: error sending event! %d\n", (int)hvrc);
404
                        goto out;
405
                }
406
                curbuf += curlen;
407
                bleft -= curlen;
408
        }
409
 
410
        /* If we didn't send it all, buffer as much of it as we can. */
411
        if (bleft > 0)
412
                bleft -= buffer_add(pi, curbuf, bleft);
413
out:
414
        vio_free_event_buffer(viomajorsubtype_chario, viochar);
415
        spin_unlock_irqrestore(&consolelock, flags);
416
        return len - bleft;
417
}
418
 
419
static struct port_info *get_port_data(struct tty_struct *tty)
420
{
421
        unsigned long flags;
422
        struct port_info *pi;
423
 
424
        spin_lock_irqsave(&consolelock, flags);
425
        if (tty) {
426
                pi = (struct port_info *)tty->driver_data;
427
                if (!pi || viotty_paranoia_check(pi, tty->name,
428
                                             "get_port_data")) {
429
                        pi = NULL;
430
                }
431
        } else
432
                /*
433
                 * If this is the console device, use the lp from
434
                 * the first port entry
435
                 */
436
                pi = &port_info[0];
437
        spin_unlock_irqrestore(&consolelock, flags);
438
        return pi;
439
}
440
 
441
/*
442
 * Initialize the common fields in a charLpEvent
443
 */
444
static void initDataEvent(struct viocharlpevent *viochar, HvLpIndex lp)
445
{
446
        struct HvLpEvent *hev = &viochar->event;
447
 
448
        memset(viochar, 0, sizeof(struct viocharlpevent));
449
 
450
        hev->flags = HV_LP_EVENT_VALID | HV_LP_EVENT_DEFERRED_ACK |
451
                HV_LP_EVENT_INT;
452
        hev->xType = HvLpEvent_Type_VirtualIo;
453
        hev->xSubtype = viomajorsubtype_chario | viochardata;
454
        hev->xSourceLp = HvLpConfig_getLpIndex();
455
        hev->xTargetLp = lp;
456
        hev->xSizeMinus1 = sizeof(struct viocharlpevent);
457
        hev->xSourceInstanceId = viopath_sourceinst(lp);
458
        hev->xTargetInstanceId = viopath_targetinst(lp);
459
}
460
 
461
/*
462
 * early console device write
463
 */
464
static void viocons_write_early(struct console *co, const char *s, unsigned count)
465
{
466
        hvlogOutput(s, count);
467
}
468
 
469
/*
470
 * console device write
471
 */
472
static void viocons_write(struct console *co, const char *s, unsigned count)
473
{
474
        int index;
475
        int begin;
476
        struct port_info *pi;
477
 
478
        static const char cr = '\r';
479
 
480
        /*
481
         * Check port data first because the target LP might be valid but
482
         * simply not active, in which case we want to hvlog the output.
483
         */
484
        pi = get_port_data(NULL);
485
        if (pi == NULL) {
486
                hvlog("\n\rviocons_write: unable to get port data.");
487
                return;
488
        }
489
 
490
        hvlogOutput(s, count);
491
 
492
        if (!viopath_isactive(pi->lp))
493
                return;
494
 
495
        /*
496
         * Any newline character found will cause a
497
         * carriage return character to be emitted as well.
498
         */
499
        begin = 0;
500
        for (index = 0; index < count; index++) {
501
                if (s[index] == '\n') {
502
                        /*
503
                         * Newline found. Print everything up to and
504
                         * including the newline
505
                         */
506
                        internal_write(pi, &s[begin], index - begin + 1);
507
                        begin = index + 1;
508
                        /* Emit a carriage return as well */
509
                        internal_write(pi, &cr, 1);
510
                }
511
        }
512
 
513
        /* If any characters left to write, write them now */
514
        if ((index - begin) > 0)
515
                internal_write(pi, &s[begin], index - begin);
516
}
517
 
518
/*
519
 * Work out the device associate with this console
520
 */
521
static struct tty_driver *viocons_device(struct console *c, int *index)
522
{
523
        *index = c->index;
524
        return viotty_driver;
525
}
526
 
527
/*
528
 * console device I/O methods
529
 */
530
static struct console viocons_early = {
531
        .name = "viocons",
532
        .write = viocons_write_early,
533
        .flags = CON_PRINTBUFFER,
534
        .index = -1,
535
};
536
 
537
static struct console viocons = {
538
        .name = "viocons",
539
        .write = viocons_write,
540
        .device = viocons_device,
541
        .flags = CON_PRINTBUFFER,
542
        .index = -1,
543
};
544
 
545
/*
546
 * TTY Open method
547
 */
548
static int viotty_open(struct tty_struct *tty, struct file *filp)
549
{
550
        int port;
551
        unsigned long flags;
552
        struct port_info *pi;
553
 
554
        port = tty->index;
555
 
556
        if ((port < 0) || (port >= VTTY_PORTS))
557
                return -ENODEV;
558
 
559
        spin_lock_irqsave(&consolelock, flags);
560
 
561
        pi = &port_info[port];
562
        /* If some other TTY is already connected here, reject the open */
563
        if ((pi->tty) && (pi->tty != tty)) {
564
                spin_unlock_irqrestore(&consolelock, flags);
565
                printk(VIOCONS_KERN_WARN
566
                       "attempt to open device twice from different ttys\n");
567
                return -EBUSY;
568
        }
569
        tty->driver_data = pi;
570
        pi->tty = tty;
571
        spin_unlock_irqrestore(&consolelock, flags);
572
 
573
        return 0;
574
}
575
 
576
/*
577
 * TTY Close method
578
 */
579
static void viotty_close(struct tty_struct *tty, struct file *filp)
580
{
581
        unsigned long flags;
582
        struct port_info *pi;
583
 
584
        spin_lock_irqsave(&consolelock, flags);
585
        pi = (struct port_info *)tty->driver_data;
586
 
587
        if (!pi || viotty_paranoia_check(pi, tty->name, "viotty_close")) {
588
                spin_unlock_irqrestore(&consolelock, flags);
589
                return;
590
        }
591
        if (tty->count == 1)
592
                pi->tty = NULL;
593
        spin_unlock_irqrestore(&consolelock, flags);
594
}
595
 
596
/*
597
 * TTY Write method
598
 */
599
static int viotty_write(struct tty_struct *tty, const unsigned char *buf,
600
                int count)
601
{
602
        struct port_info *pi;
603
 
604
        pi = get_port_data(tty);
605
        if (pi == NULL) {
606
                hvlog("\n\rviotty_write: no port data.");
607
                return -ENODEV;
608
        }
609
 
610
        if (viochar_is_console(pi))
611
                hvlogOutput(buf, count);
612
 
613
        /*
614
         * If the path to this LP is closed, don't bother doing anything more.
615
         * just dump the data on the floor and return count.  For some reason
616
         * some user level programs will attempt to probe available tty's and
617
         * they'll attempt a viotty_write on an invalid port which maps to an
618
         * invalid target lp.  If this is the case then ignore the
619
         * viotty_write call and, since the viopath isn't active to this
620
         * partition, return count.
621
         */
622
        if (!viopath_isactive(pi->lp))
623
                return count;
624
 
625
        return internal_write(pi, buf, count);
626
}
627
 
628
/*
629
 * TTY put_char method
630
 */
631
static void viotty_put_char(struct tty_struct *tty, unsigned char ch)
632
{
633
        struct port_info *pi;
634
 
635
        pi = get_port_data(tty);
636
        if (pi == NULL)
637
                return;
638
 
639
        /* This will append '\r' as well if the char is '\n' */
640
        if (viochar_is_console(pi))
641
                hvlogOutput(&ch, 1);
642
 
643
        if (viopath_isactive(pi->lp))
644
                internal_write(pi, &ch, 1);
645
}
646
 
647
/*
648
 * TTY write_room method
649
 */
650
static int viotty_write_room(struct tty_struct *tty)
651
{
652
        int i;
653
        int room = 0;
654
        struct port_info *pi;
655
        unsigned long flags;
656
 
657
        spin_lock_irqsave(&consolelock, flags);
658
        pi = (struct port_info *)tty->driver_data;
659
        if (!pi || viotty_paranoia_check(pi, tty->name, "viotty_write_room")) {
660
                spin_unlock_irqrestore(&consolelock, flags);
661
                return 0;
662
        }
663
 
664
        /* If no buffers are used, return the max size. */
665
        if (pi->used == 0) {
666
                spin_unlock_irqrestore(&consolelock, flags);
667
                return VIOCHAR_MAX_DATA * VIOCHAR_NUM_BUF;
668
        }
669
 
670
        /*
671
         * We retain the spinlock because we want to get an accurate
672
         * count and it can change on us between each operation if we
673
         * don't hold the spinlock.
674
         */
675
        for (i = 0; ((i < VIOCHAR_NUM_BUF) && (room < VIOCHAR_MAX_DATA)); i++)
676
                room += (VIOCHAR_MAX_DATA - pi->bufferBytes[i]);
677
        spin_unlock_irqrestore(&consolelock, flags);
678
 
679
        if (room > VIOCHAR_MAX_DATA)
680
                room = VIOCHAR_MAX_DATA;
681
        return room;
682
}
683
 
684
/*
685
 * TTY chars_in_buffer method
686
 */
687
static int viotty_chars_in_buffer(struct tty_struct *tty)
688
{
689
        return 0;
690
}
691
 
692
static int viotty_ioctl(struct tty_struct *tty, struct file *file,
693
                        unsigned int cmd, unsigned long arg)
694
{
695
        switch (cmd) {
696
        /*
697
         * the ioctls below read/set the flags usually shown in the leds
698
         * don't use them - they will go away without warning
699
         */
700
        case KDGETLED:
701
        case KDGKBLED:
702
                return put_user(0, (char *)arg);
703
 
704
        case KDSKBLED:
705
                return 0;
706
        }
707
 
708
        return n_tty_ioctl(tty, file, cmd, arg);
709
}
710
 
711
/*
712
 * Handle an open charLpEvent.  Could be either interrupt or ack
713
 */
714
static void vioHandleOpenEvent(struct HvLpEvent *event)
715
{
716
        unsigned long flags;
717
        struct viocharlpevent *cevent = (struct viocharlpevent *)event;
718
        u8 port = cevent->virtual_device;
719
        struct port_info *pi;
720
        int reject = 0;
721
 
722
        if (hvlpevent_is_ack(event)) {
723
                if (port >= VTTY_PORTS)
724
                        return;
725
 
726
                spin_lock_irqsave(&consolelock, flags);
727
                /* Got the lock, don't cause console output */
728
 
729
                pi = &port_info[port];
730
                if (event->xRc == HvLpEvent_Rc_Good) {
731
                        pi->seq = pi->ack = 0;
732
                        /*
733
                         * This line allows connections from the primary
734
                         * partition but once one is connected from the
735
                         * primary partition nothing short of a reboot
736
                         * of linux will allow access from the hosting
737
                         * partition again without a required iSeries fix.
738
                         */
739
                        pi->lp = event->xTargetLp;
740
                }
741
 
742
                spin_unlock_irqrestore(&consolelock, flags);
743
                if (event->xRc != HvLpEvent_Rc_Good)
744
                        printk(VIOCONS_KERN_WARN
745
                               "handle_open_event: event->xRc == (%d).\n",
746
                               event->xRc);
747
 
748
                if (event->xCorrelationToken != 0) {
749
                        atomic_t *aptr= (atomic_t *)event->xCorrelationToken;
750
                        atomic_set(aptr, 1);
751
                } else
752
                        printk(VIOCONS_KERN_WARN
753
                               "weird...got open ack without atomic\n");
754
                return;
755
        }
756
 
757
        /* This had better require an ack, otherwise complain */
758
        if (!hvlpevent_need_ack(event)) {
759
                printk(VIOCONS_KERN_WARN "viocharopen without ack bit!\n");
760
                return;
761
        }
762
 
763
        spin_lock_irqsave(&consolelock, flags);
764
        /* Got the lock, don't cause console output */
765
 
766
        /* Make sure this is a good virtual tty */
767
        if (port >= VTTY_PORTS) {
768
                event->xRc = HvLpEvent_Rc_SubtypeError;
769
                cevent->subtype_result_code = viorc_openRejected;
770
                /*
771
                 * Flag state here since we can't printk while holding
772
                 * a spinlock.
773
                 */
774
                reject = 1;
775
        } else {
776
                pi = &port_info[port];
777
                if ((pi->lp != HvLpIndexInvalid) &&
778
                                (pi->lp != event->xSourceLp)) {
779
                        /*
780
                         * If this is tty is already connected to a different
781
                         * partition, fail.
782
                         */
783
                        event->xRc = HvLpEvent_Rc_SubtypeError;
784
                        cevent->subtype_result_code = viorc_openRejected;
785
                        reject = 2;
786
                } else {
787
                        pi->lp = event->xSourceLp;
788
                        event->xRc = HvLpEvent_Rc_Good;
789
                        cevent->subtype_result_code = viorc_good;
790
                        pi->seq = pi->ack = 0;
791
                        reject = 0;
792
                }
793
        }
794
 
795
        spin_unlock_irqrestore(&consolelock, flags);
796
 
797
        if (reject == 1)
798
                printk(VIOCONS_KERN_WARN "open rejected: bad virtual tty.\n");
799
        else if (reject == 2)
800
                printk(VIOCONS_KERN_WARN
801
                        "open rejected: console in exclusive use by another partition.\n");
802
 
803
        /* Return the acknowledgement */
804
        HvCallEvent_ackLpEvent(event);
805
}
806
 
807
/*
808
 * Handle a close charLpEvent.  This should ONLY be an Interrupt because the
809
 * virtual console should never actually issue a close event to the hypervisor
810
 * because the virtual console never goes away.  A close event coming from the
811
 * hypervisor simply means that there are no client consoles connected to the
812
 * virtual console.
813
 *
814
 * Regardless of the number of connections masqueraded on the other side of
815
 * the hypervisor ONLY ONE close event should be called to accompany the ONE
816
 * open event that is called.  The close event should ONLY be called when NO
817
 * MORE connections (masqueraded or not) exist on the other side of the
818
 * hypervisor.
819
 */
820
static void vioHandleCloseEvent(struct HvLpEvent *event)
821
{
822
        unsigned long flags;
823
        struct viocharlpevent *cevent = (struct viocharlpevent *)event;
824
        u8 port = cevent->virtual_device;
825
 
826
        if (hvlpevent_is_int(event)) {
827
                if (port >= VTTY_PORTS) {
828
                        printk(VIOCONS_KERN_WARN
829
                                        "close message from invalid virtual device.\n");
830
                        return;
831
                }
832
 
833
                /* For closes, just mark the console partition invalid */
834
                spin_lock_irqsave(&consolelock, flags);
835
                /* Got the lock, don't cause console output */
836
 
837
                if (port_info[port].lp == event->xSourceLp)
838
                        port_info[port].lp = HvLpIndexInvalid;
839
 
840
                spin_unlock_irqrestore(&consolelock, flags);
841
                printk(VIOCONS_KERN_INFO "close from %d\n", event->xSourceLp);
842
        } else
843
                printk(VIOCONS_KERN_WARN
844
                                "got unexpected close acknowlegement\n");
845
}
846
 
847
/*
848
 * Handle a config charLpEvent.  Could be either interrupt or ack
849
 */
850
static void vioHandleConfig(struct HvLpEvent *event)
851
{
852
        struct viocharlpevent *cevent = (struct viocharlpevent *)event;
853
 
854
        HvCall_writeLogBuffer(cevent->data, cevent->len);
855
 
856
        if (cevent->data[0] == 0x01)
857
                printk(VIOCONS_KERN_INFO "window resized to %d: %d: %d: %d\n",
858
                       cevent->data[1], cevent->data[2],
859
                       cevent->data[3], cevent->data[4]);
860
        else
861
                printk(VIOCONS_KERN_WARN "unknown config event\n");
862
}
863
 
864
/*
865
 * Handle a data charLpEvent.
866
 */
867
static void vioHandleData(struct HvLpEvent *event)
868
{
869
        struct tty_struct *tty;
870
        unsigned long flags;
871
        struct viocharlpevent *cevent = (struct viocharlpevent *)event;
872
        struct port_info *pi;
873
        int index;
874
        int num_pushed;
875
        u8 port = cevent->virtual_device;
876
 
877
        if (port >= VTTY_PORTS) {
878
                printk(VIOCONS_KERN_WARN "data on invalid virtual device %d\n",
879
                                port);
880
                return;
881
        }
882
 
883
        /*
884
         * Hold the spinlock so that we don't take an interrupt that
885
         * changes tty between the time we fetch the port_info
886
         * pointer and the time we paranoia check.
887
         */
888
        spin_lock_irqsave(&consolelock, flags);
889
        pi = &port_info[port];
890
 
891
        /*
892
         * Change 05/01/2003 - Ryan Arnold: If a partition other than
893
         * the current exclusive partition tries to send us data
894
         * events then just drop them on the floor because we don't
895
         * want his stinking data.  He isn't authorized to receive
896
         * data because he wasn't the first one to get the console,
897
         * therefore he shouldn't be allowed to send data either.
898
         * This will work without an iSeries fix.
899
         */
900
        if (pi->lp != event->xSourceLp) {
901
                spin_unlock_irqrestore(&consolelock, flags);
902
                return;
903
        }
904
 
905
        tty = pi->tty;
906
        if (tty == NULL) {
907
                spin_unlock_irqrestore(&consolelock, flags);
908
                printk(VIOCONS_KERN_WARN "no tty for virtual device %d\n",
909
                                port);
910
                return;
911
        }
912
 
913
        if (tty->magic != TTY_MAGIC) {
914
                spin_unlock_irqrestore(&consolelock, flags);
915
                printk(VIOCONS_KERN_WARN "tty bad magic\n");
916
                return;
917
        }
918
 
919
        /*
920
         * Just to be paranoid, make sure the tty points back to this port
921
         */
922
        pi = (struct port_info *)tty->driver_data;
923
        if (!pi || viotty_paranoia_check(pi, tty->name, "vioHandleData")) {
924
                spin_unlock_irqrestore(&consolelock, flags);
925
                return;
926
        }
927
        spin_unlock_irqrestore(&consolelock, flags);
928
 
929
        /*
930
         * Change 07/21/2003 - Ryan Arnold: functionality added to
931
         * support sysrq utilizing ^O as the sysrq key.  The sysrq
932
         * functionality will only work if built into the kernel and
933
         * then only if sysrq is enabled through the proc filesystem.
934
         */
935
        num_pushed = 0;
936
        for (index = 0; index < cevent->len; index++) {
937
                /*
938
                 * Will be optimized away if !CONFIG_MAGIC_SYSRQ:
939
                 */
940
                if (sysrq_on()) {
941
                        /* 0x0f is the ascii character for ^O */
942
                        if (cevent->data[index] == '\x0f') {
943
                                vio_sysrq_pressed = 1;
944
                                /*
945
                                 * continue because we don't want to add
946
                                 * the sysrq key into the data string.
947
                                 */
948
                                continue;
949
                        } else if (vio_sysrq_pressed) {
950
                                handle_sysrq(cevent->data[index], tty);
951
                                vio_sysrq_pressed = 0;
952
                                /*
953
                                 * continue because we don't want to add
954
                                 * the sysrq sequence into the data string.
955
                                 */
956
                                continue;
957
                        }
958
                }
959
                /*
960
                 * The sysrq sequence isn't included in this check if
961
                 * sysrq is enabled and compiled into the kernel because
962
                 * the sequence will never get inserted into the buffer.
963
                 * Don't attempt to copy more data into the buffer than we
964
                 * have room for because it would fail without indication.
965
                 */
966
                if(tty_insert_flip_char(tty, cevent->data[index], TTY_NORMAL) == 0) {
967
                        printk(VIOCONS_KERN_WARN "input buffer overflow!\n");
968
                        break;
969
                }
970
                num_pushed++;
971
        }
972
 
973
        if (num_pushed)
974
                tty_flip_buffer_push(tty);
975
}
976
 
977
/*
978
 * Handle an ack charLpEvent.
979
 */
980
static void vioHandleAck(struct HvLpEvent *event)
981
{
982
        struct viocharlpevent *cevent = (struct viocharlpevent *)event;
983
        unsigned long flags;
984
        u8 port = cevent->virtual_device;
985
 
986
        if (port >= VTTY_PORTS) {
987
                printk(VIOCONS_KERN_WARN "data on invalid virtual device\n");
988
                return;
989
        }
990
 
991
        spin_lock_irqsave(&consolelock, flags);
992
        port_info[port].ack = event->xCorrelationToken;
993
        spin_unlock_irqrestore(&consolelock, flags);
994
 
995
        if (port_info[port].used)
996
                send_buffers(&port_info[port]);
997
}
998
 
999
/*
1000
 * Handle charLpEvents and route to the appropriate routine
1001
 */
1002
static void vioHandleCharEvent(struct HvLpEvent *event)
1003
{
1004
        int charminor;
1005
 
1006
        if (event == NULL)
1007
                return;
1008
 
1009
        charminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK;
1010
        switch (charminor) {
1011
        case viocharopen:
1012
                vioHandleOpenEvent(event);
1013
                break;
1014
        case viocharclose:
1015
                vioHandleCloseEvent(event);
1016
                break;
1017
        case viochardata:
1018
                vioHandleData(event);
1019
                break;
1020
        case viocharack:
1021
                vioHandleAck(event);
1022
                break;
1023
        case viocharconfig:
1024
                vioHandleConfig(event);
1025
                break;
1026
        default:
1027
                if (hvlpevent_is_int(event) && hvlpevent_need_ack(event)) {
1028
                        event->xRc = HvLpEvent_Rc_InvalidSubtype;
1029
                        HvCallEvent_ackLpEvent(event);
1030
                }
1031
        }
1032
}
1033
 
1034
/*
1035
 * Send an open event
1036
 */
1037
static int send_open(HvLpIndex remoteLp, void *sem)
1038
{
1039
        return HvCallEvent_signalLpEventFast(remoteLp,
1040
                        HvLpEvent_Type_VirtualIo,
1041
                        viomajorsubtype_chario | viocharopen,
1042
                        HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
1043
                        viopath_sourceinst(remoteLp),
1044
                        viopath_targetinst(remoteLp),
1045
                        (u64)(unsigned long)sem, VIOVERSION << 16,
1046
                        0, 0, 0, 0);
1047
}
1048
 
1049
static const struct tty_operations serial_ops = {
1050
        .open = viotty_open,
1051
        .close = viotty_close,
1052
        .write = viotty_write,
1053
        .put_char = viotty_put_char,
1054
        .write_room = viotty_write_room,
1055
        .chars_in_buffer = viotty_chars_in_buffer,
1056
        .ioctl = viotty_ioctl,
1057
};
1058
 
1059
static int __init viocons_init2(void)
1060
{
1061
        atomic_t wait_flag;
1062
        int rc;
1063
 
1064
        if (!firmware_has_feature(FW_FEATURE_ISERIES))
1065
                return -ENODEV;
1066
 
1067
        /* +2 for fudge */
1068
        rc = viopath_open(HvLpConfig_getPrimaryLpIndex(),
1069
                        viomajorsubtype_chario, VIOCHAR_WINDOW + 2);
1070
        if (rc)
1071
                printk(VIOCONS_KERN_WARN "error opening to primary %d\n", rc);
1072
 
1073
        if (viopath_hostLp == HvLpIndexInvalid)
1074
                vio_set_hostlp();
1075
 
1076
        /*
1077
         * And if the primary is not the same as the hosting LP, open to the
1078
         * hosting lp
1079
         */
1080
        if ((viopath_hostLp != HvLpIndexInvalid) &&
1081
            (viopath_hostLp != HvLpConfig_getPrimaryLpIndex())) {
1082
                printk(VIOCONS_KERN_INFO "open path to hosting (%d)\n",
1083
                                viopath_hostLp);
1084
                rc = viopath_open(viopath_hostLp, viomajorsubtype_chario,
1085
                                VIOCHAR_WINDOW + 2);    /* +2 for fudge */
1086
                if (rc)
1087
                        printk(VIOCONS_KERN_WARN
1088
                                "error opening to partition %d: %d\n",
1089
                                viopath_hostLp, rc);
1090
        }
1091
 
1092
        if (vio_setHandler(viomajorsubtype_chario, vioHandleCharEvent) < 0)
1093
                printk(VIOCONS_KERN_WARN
1094
                                "error seting handler for console events!\n");
1095
 
1096
        /*
1097
         * First, try to open the console to the hosting lp.
1098
         * Wait on a semaphore for the response.
1099
         */
1100
        atomic_set(&wait_flag, 0);
1101
        if ((viopath_isactive(viopath_hostLp)) &&
1102
            (send_open(viopath_hostLp, (void *)&wait_flag) == 0)) {
1103
                printk(VIOCONS_KERN_INFO "hosting partition %d\n",
1104
                        viopath_hostLp);
1105
                while (atomic_read(&wait_flag) == 0)
1106
                        mb();
1107
                atomic_set(&wait_flag, 0);
1108
        }
1109
 
1110
        /*
1111
         * If we don't have an active console, try the primary
1112
         */
1113
        if ((!viopath_isactive(port_info[0].lp)) &&
1114
            (viopath_isactive(HvLpConfig_getPrimaryLpIndex())) &&
1115
            (send_open(HvLpConfig_getPrimaryLpIndex(), (void *)&wait_flag)
1116
             == 0)) {
1117
                printk(VIOCONS_KERN_INFO "opening console to primary partition\n");
1118
                while (atomic_read(&wait_flag) == 0)
1119
                        mb();
1120
        }
1121
 
1122
        /* Initialize the tty_driver structure */
1123
        viotty_driver = alloc_tty_driver(VTTY_PORTS);
1124
        viotty_driver->owner = THIS_MODULE;
1125
        viotty_driver->driver_name = "vioconsole";
1126
        viotty_driver->name = "tty";
1127
        viotty_driver->name_base = 1;
1128
        viotty_driver->major = TTY_MAJOR;
1129
        viotty_driver->minor_start = 1;
1130
        viotty_driver->type = TTY_DRIVER_TYPE_CONSOLE;
1131
        viotty_driver->subtype = 1;
1132
        viotty_driver->init_termios = tty_std_termios;
1133
        viotty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
1134
        tty_set_operations(viotty_driver, &serial_ops);
1135
 
1136
        if (tty_register_driver(viotty_driver)) {
1137
                printk(VIOCONS_KERN_WARN "couldn't register console driver\n");
1138
                put_tty_driver(viotty_driver);
1139
                viotty_driver = NULL;
1140
        }
1141
 
1142
        unregister_console(&viocons_early);
1143
        register_console(&viocons);
1144
 
1145
        return 0;
1146
}
1147
 
1148
static int __init viocons_init(void)
1149
{
1150
        int i;
1151
 
1152
        if (!firmware_has_feature(FW_FEATURE_ISERIES))
1153
                return -ENODEV;
1154
 
1155
        printk(VIOCONS_KERN_INFO "registering console\n");
1156
        for (i = 0; i < VTTY_PORTS; i++) {
1157
                port_info[i].lp = HvLpIndexInvalid;
1158
                port_info[i].magic = VIOTTY_MAGIC;
1159
        }
1160
        HvCall_setLogBufferFormatAndCodepage(HvCall_LogBuffer_ASCII, 437);
1161
        add_preferred_console("viocons", 0, NULL);
1162
        register_console(&viocons_early);
1163
        return 0;
1164
}
1165
 
1166
console_initcall(viocons_init);
1167
module_init(viocons_init2);

powered by: WebSVN 2.1.0

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