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