aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2008-08-07 00:08:27 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-08-07 21:07:10 -0400
commit4c514a5ad1314b872e3185dabaf105c81d39d7e8 (patch)
tree5217dd043156d6bd4572653d05c2260b3527e7fe /drivers/char
parentb80b601f0087391e55d3859e70f08278632b1185 (diff)
powerpc/iseries: remove the old viocons driver
This driver was declared obsolete over 2 years ago, the alternative console driver for legacy iSeries (hvc_iseries) was made the default over 1 year ago and this driver has been build broken for over 3 months, so remove it. Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/Kconfig2
-rw-r--r--drivers/char/Makefile1
-rw-r--r--drivers/char/viocons.c1167
3 files changed, 1 insertions, 1169 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index d0ac944e1696..caff85149b9d 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -8,7 +8,7 @@ config VT
8 bool "Virtual terminal" if EMBEDDED 8 bool "Virtual terminal" if EMBEDDED
9 depends on !S390 9 depends on !S390
10 select INPUT 10 select INPUT
11 default y if !VIOCONS 11 default y
12 ---help--- 12 ---help---
13 If you say Y here, you will get support for terminal devices with 13 If you say Y here, you will get support for terminal devices with
14 display and keyboard devices. These are called "virtual" because you 14 display and keyboard devices. These are called "virtual" because you
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 8a161c30e1dc..6850f6da7576 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -55,7 +55,6 @@ obj-$(CONFIG_RAW_DRIVER) += raw.o
55obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o 55obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o
56obj-$(CONFIG_MSPEC) += mspec.o 56obj-$(CONFIG_MSPEC) += mspec.o
57obj-$(CONFIG_MMTIMER) += mmtimer.o 57obj-$(CONFIG_MMTIMER) += mmtimer.o
58obj-$(CONFIG_VIOCONS) += viocons.o
59obj-$(CONFIG_VIOTAPE) += viotape.o 58obj-$(CONFIG_VIOTAPE) += viotape.o
60obj-$(CONFIG_HVCS) += hvcs.o 59obj-$(CONFIG_HVCS) += hvcs.o
61obj-$(CONFIG_IBM_BSR) += bsr.o 60obj-$(CONFIG_IBM_BSR) += bsr.o
diff --git a/drivers/char/viocons.c b/drivers/char/viocons.c
deleted file mode 100644
index 7feeb774a101..000000000000
--- a/drivers/char/viocons.c
+++ /dev/null
@@ -1,1167 +0,0 @@
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
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
62static DEFINE_SPINLOCK(consolelock);
63static DEFINE_SPINLOCK(consoleloglock);
64
65static 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 */
73static 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
97static void initDataEvent(struct viocharlpevent *viochar, HvLpIndex lp);
98
99static struct tty_driver *viotty_driver;
100
101static 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
117static 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 */
147static 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 */
172static 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 */
251static 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 */
354static 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);
413out:
414 vio_free_event_buffer(viomajorsubtype_chario, viochar);
415 spin_unlock_irqrestore(&consolelock, flags);
416 return len - bleft;
417}
418
419static 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 */
444static 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 */
464static 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 */
472static 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 */
521static 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 */
530static struct console viocons_early = {
531 .name = "viocons",
532 .write = viocons_write_early,
533 .flags = CON_PRINTBUFFER,
534 .index = -1,
535};
536
537static 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 */
548static 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 */
579static 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 */
599static 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 */
631static int 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 0;
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 return 1;
646}
647
648/*
649 * TTY write_room method
650 */
651static int viotty_write_room(struct tty_struct *tty)
652{
653 int i;
654 int room = 0;
655 struct port_info *pi;
656 unsigned long flags;
657
658 spin_lock_irqsave(&consolelock, flags);
659 pi = (struct port_info *)tty->driver_data;
660 if (!pi || viotty_paranoia_check(pi, tty->name, "viotty_write_room")) {
661 spin_unlock_irqrestore(&consolelock, flags);
662 return 0;
663 }
664
665 /* If no buffers are used, return the max size. */
666 if (pi->used == 0) {
667 spin_unlock_irqrestore(&consolelock, flags);
668 return VIOCHAR_MAX_DATA * VIOCHAR_NUM_BUF;
669 }
670
671 /*
672 * We retain the spinlock because we want to get an accurate
673 * count and it can change on us between each operation if we
674 * don't hold the spinlock.
675 */
676 for (i = 0; ((i < VIOCHAR_NUM_BUF) && (room < VIOCHAR_MAX_DATA)); i++)
677 room += (VIOCHAR_MAX_DATA - pi->bufferBytes[i]);
678 spin_unlock_irqrestore(&consolelock, flags);
679
680 if (room > VIOCHAR_MAX_DATA)
681 room = VIOCHAR_MAX_DATA;
682 return room;
683}
684
685/*
686 * TTY chars_in_buffer method
687 */
688static int viotty_chars_in_buffer(struct tty_struct *tty)
689{
690 return 0;
691}
692
693static int viotty_ioctl(struct tty_struct *tty, struct file *file,
694 unsigned int cmd, unsigned long arg)
695{
696 switch (cmd) {
697 /*
698 * the ioctls below read/set the flags usually shown in the leds
699 * don't use them - they will go away without warning
700 */
701 case KDGETLED:
702 case KDGKBLED:
703 return put_user(0, (char *)arg);
704
705 case KDSKBLED:
706 return 0;
707 }
708 return -ENOIOCTLCMD;
709}
710
711/*
712 * Handle an open charLpEvent. Could be either interrupt or ack
713 */
714static 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 */
820static 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 */
850static 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 */
867static 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 */
980static 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 */
1002static 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 */
1037static 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
1049static 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
1059static 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
1148static 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
1166console_initcall(viocons_init);
1167module_init(viocons_init2);