aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/Kconfig2
-rw-r--r--drivers/char/Makefile1
-rw-r--r--drivers/char/amiserial.c2
-rw-r--r--drivers/char/viocons.c1171
4 files changed, 2 insertions, 1174 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/amiserial.c b/drivers/char/amiserial.c
index 3530ff417a51..6e763e3f5a81 100644
--- a/drivers/char/amiserial.c
+++ b/drivers/char/amiserial.c
@@ -1254,7 +1254,7 @@ static int rs_break(struct tty_struct *tty, int break_state)
1254 unsigned long flags; 1254 unsigned long flags;
1255 1255
1256 if (serial_paranoia_check(info, tty->name, "rs_break")) 1256 if (serial_paranoia_check(info, tty->name, "rs_break"))
1257 return; 1257 return -EINVAL;
1258 1258
1259 local_irq_save(flags); 1259 local_irq_save(flags);
1260 if (break_state == -1) 1260 if (break_state == -1)
diff --git a/drivers/char/viocons.c b/drivers/char/viocons.c
deleted file mode 100644
index 65fb848e1cce..000000000000
--- a/drivers/char/viocons.c
+++ /dev/null
@@ -1,1171 +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 /* FIXME: WTF is this being called for ??? */
709 lock_kernel();
710 ret = n_tty_ioctl(tty, file, cmd, arg);
711 unlock_kernel();
712 return ret;
713}
714
715/*
716 * Handle an open charLpEvent. Could be either interrupt or ack
717 */
718static void vioHandleOpenEvent(struct HvLpEvent *event)
719{
720 unsigned long flags;
721 struct viocharlpevent *cevent = (struct viocharlpevent *)event;
722 u8 port = cevent->virtual_device;
723 struct port_info *pi;
724 int reject = 0;
725
726 if (hvlpevent_is_ack(event)) {
727 if (port >= VTTY_PORTS)
728 return;
729
730 spin_lock_irqsave(&consolelock, flags);
731 /* Got the lock, don't cause console output */
732
733 pi = &port_info[port];
734 if (event->xRc == HvLpEvent_Rc_Good) {
735 pi->seq = pi->ack = 0;
736 /*
737 * This line allows connections from the primary
738 * partition but once one is connected from the
739 * primary partition nothing short of a reboot
740 * of linux will allow access from the hosting
741 * partition again without a required iSeries fix.
742 */
743 pi->lp = event->xTargetLp;
744 }
745
746 spin_unlock_irqrestore(&consolelock, flags);
747 if (event->xRc != HvLpEvent_Rc_Good)
748 printk(VIOCONS_KERN_WARN
749 "handle_open_event: event->xRc == (%d).\n",
750 event->xRc);
751
752 if (event->xCorrelationToken != 0) {
753 atomic_t *aptr= (atomic_t *)event->xCorrelationToken;
754 atomic_set(aptr, 1);
755 } else
756 printk(VIOCONS_KERN_WARN
757 "weird...got open ack without atomic\n");
758 return;
759 }
760
761 /* This had better require an ack, otherwise complain */
762 if (!hvlpevent_need_ack(event)) {
763 printk(VIOCONS_KERN_WARN "viocharopen without ack bit!\n");
764 return;
765 }
766
767 spin_lock_irqsave(&consolelock, flags);
768 /* Got the lock, don't cause console output */
769
770 /* Make sure this is a good virtual tty */
771 if (port >= VTTY_PORTS) {
772 event->xRc = HvLpEvent_Rc_SubtypeError;
773 cevent->subtype_result_code = viorc_openRejected;
774 /*
775 * Flag state here since we can't printk while holding
776 * a spinlock.
777 */
778 reject = 1;
779 } else {
780 pi = &port_info[port];
781 if ((pi->lp != HvLpIndexInvalid) &&
782 (pi->lp != event->xSourceLp)) {
783 /*
784 * If this is tty is already connected to a different
785 * partition, fail.
786 */
787 event->xRc = HvLpEvent_Rc_SubtypeError;
788 cevent->subtype_result_code = viorc_openRejected;
789 reject = 2;
790 } else {
791 pi->lp = event->xSourceLp;
792 event->xRc = HvLpEvent_Rc_Good;
793 cevent->subtype_result_code = viorc_good;
794 pi->seq = pi->ack = 0;
795 reject = 0;
796 }
797 }
798
799 spin_unlock_irqrestore(&consolelock, flags);
800
801 if (reject == 1)
802 printk(VIOCONS_KERN_WARN "open rejected: bad virtual tty.\n");
803 else if (reject == 2)
804 printk(VIOCONS_KERN_WARN
805 "open rejected: console in exclusive use by another partition.\n");
806
807 /* Return the acknowledgement */
808 HvCallEvent_ackLpEvent(event);
809}
810
811/*
812 * Handle a close charLpEvent. This should ONLY be an Interrupt because the
813 * virtual console should never actually issue a close event to the hypervisor
814 * because the virtual console never goes away. A close event coming from the
815 * hypervisor simply means that there are no client consoles connected to the
816 * virtual console.
817 *
818 * Regardless of the number of connections masqueraded on the other side of
819 * the hypervisor ONLY ONE close event should be called to accompany the ONE
820 * open event that is called. The close event should ONLY be called when NO
821 * MORE connections (masqueraded or not) exist on the other side of the
822 * hypervisor.
823 */
824static void vioHandleCloseEvent(struct HvLpEvent *event)
825{
826 unsigned long flags;
827 struct viocharlpevent *cevent = (struct viocharlpevent *)event;
828 u8 port = cevent->virtual_device;
829
830 if (hvlpevent_is_int(event)) {
831 if (port >= VTTY_PORTS) {
832 printk(VIOCONS_KERN_WARN
833 "close message from invalid virtual device.\n");
834 return;
835 }
836
837 /* For closes, just mark the console partition invalid */
838 spin_lock_irqsave(&consolelock, flags);
839 /* Got the lock, don't cause console output */
840
841 if (port_info[port].lp == event->xSourceLp)
842 port_info[port].lp = HvLpIndexInvalid;
843
844 spin_unlock_irqrestore(&consolelock, flags);
845 printk(VIOCONS_KERN_INFO "close from %d\n", event->xSourceLp);
846 } else
847 printk(VIOCONS_KERN_WARN
848 "got unexpected close acknowlegement\n");
849}
850
851/*
852 * Handle a config charLpEvent. Could be either interrupt or ack
853 */
854static void vioHandleConfig(struct HvLpEvent *event)
855{
856 struct viocharlpevent *cevent = (struct viocharlpevent *)event;
857
858 HvCall_writeLogBuffer(cevent->data, cevent->len);
859
860 if (cevent->data[0] == 0x01)
861 printk(VIOCONS_KERN_INFO "window resized to %d: %d: %d: %d\n",
862 cevent->data[1], cevent->data[2],
863 cevent->data[3], cevent->data[4]);
864 else
865 printk(VIOCONS_KERN_WARN "unknown config event\n");
866}
867
868/*
869 * Handle a data charLpEvent.
870 */
871static void vioHandleData(struct HvLpEvent *event)
872{
873 struct tty_struct *tty;
874 unsigned long flags;
875 struct viocharlpevent *cevent = (struct viocharlpevent *)event;
876 struct port_info *pi;
877 int index;
878 int num_pushed;
879 u8 port = cevent->virtual_device;
880
881 if (port >= VTTY_PORTS) {
882 printk(VIOCONS_KERN_WARN "data on invalid virtual device %d\n",
883 port);
884 return;
885 }
886
887 /*
888 * Hold the spinlock so that we don't take an interrupt that
889 * changes tty between the time we fetch the port_info
890 * pointer and the time we paranoia check.
891 */
892 spin_lock_irqsave(&consolelock, flags);
893 pi = &port_info[port];
894
895 /*
896 * Change 05/01/2003 - Ryan Arnold: If a partition other than
897 * the current exclusive partition tries to send us data
898 * events then just drop them on the floor because we don't
899 * want his stinking data. He isn't authorized to receive
900 * data because he wasn't the first one to get the console,
901 * therefore he shouldn't be allowed to send data either.
902 * This will work without an iSeries fix.
903 */
904 if (pi->lp != event->xSourceLp) {
905 spin_unlock_irqrestore(&consolelock, flags);
906 return;
907 }
908
909 tty = pi->tty;
910 if (tty == NULL) {
911 spin_unlock_irqrestore(&consolelock, flags);
912 printk(VIOCONS_KERN_WARN "no tty for virtual device %d\n",
913 port);
914 return;
915 }
916
917 if (tty->magic != TTY_MAGIC) {
918 spin_unlock_irqrestore(&consolelock, flags);
919 printk(VIOCONS_KERN_WARN "tty bad magic\n");
920 return;
921 }
922
923 /*
924 * Just to be paranoid, make sure the tty points back to this port
925 */
926 pi = (struct port_info *)tty->driver_data;
927 if (!pi || viotty_paranoia_check(pi, tty->name, "vioHandleData")) {
928 spin_unlock_irqrestore(&consolelock, flags);
929 return;
930 }
931 spin_unlock_irqrestore(&consolelock, flags);
932
933 /*
934 * Change 07/21/2003 - Ryan Arnold: functionality added to
935 * support sysrq utilizing ^O as the sysrq key. The sysrq
936 * functionality will only work if built into the kernel and
937 * then only if sysrq is enabled through the proc filesystem.
938 */
939 num_pushed = 0;
940 for (index = 0; index < cevent->len; index++) {
941 /*
942 * Will be optimized away if !CONFIG_MAGIC_SYSRQ:
943 */
944 if (sysrq_on()) {
945 /* 0x0f is the ascii character for ^O */
946 if (cevent->data[index] == '\x0f') {
947 vio_sysrq_pressed = 1;
948 /*
949 * continue because we don't want to add
950 * the sysrq key into the data string.
951 */
952 continue;
953 } else if (vio_sysrq_pressed) {
954 handle_sysrq(cevent->data[index], tty);
955 vio_sysrq_pressed = 0;
956 /*
957 * continue because we don't want to add
958 * the sysrq sequence into the data string.
959 */
960 continue;
961 }
962 }
963 /*
964 * The sysrq sequence isn't included in this check if
965 * sysrq is enabled and compiled into the kernel because
966 * the sequence will never get inserted into the buffer.
967 * Don't attempt to copy more data into the buffer than we
968 * have room for because it would fail without indication.
969 */
970 if(tty_insert_flip_char(tty, cevent->data[index], TTY_NORMAL) == 0) {
971 printk(VIOCONS_KERN_WARN "input buffer overflow!\n");
972 break;
973 }
974 num_pushed++;
975 }
976
977 if (num_pushed)
978 tty_flip_buffer_push(tty);
979}
980
981/*
982 * Handle an ack charLpEvent.
983 */
984static void vioHandleAck(struct HvLpEvent *event)
985{
986 struct viocharlpevent *cevent = (struct viocharlpevent *)event;
987 unsigned long flags;
988 u8 port = cevent->virtual_device;
989
990 if (port >= VTTY_PORTS) {
991 printk(VIOCONS_KERN_WARN "data on invalid virtual device\n");
992 return;
993 }
994
995 spin_lock_irqsave(&consolelock, flags);
996 port_info[port].ack = event->xCorrelationToken;
997 spin_unlock_irqrestore(&consolelock, flags);
998
999 if (port_info[port].used)
1000 send_buffers(&port_info[port]);
1001}
1002
1003/*
1004 * Handle charLpEvents and route to the appropriate routine
1005 */
1006static void vioHandleCharEvent(struct HvLpEvent *event)
1007{
1008 int charminor;
1009
1010 if (event == NULL)
1011 return;
1012
1013 charminor = event->xSubtype & VIOMINOR_SUBTYPE_MASK;
1014 switch (charminor) {
1015 case viocharopen:
1016 vioHandleOpenEvent(event);
1017 break;
1018 case viocharclose:
1019 vioHandleCloseEvent(event);
1020 break;
1021 case viochardata:
1022 vioHandleData(event);
1023 break;
1024 case viocharack:
1025 vioHandleAck(event);
1026 break;
1027 case viocharconfig:
1028 vioHandleConfig(event);
1029 break;
1030 default:
1031 if (hvlpevent_is_int(event) && hvlpevent_need_ack(event)) {
1032 event->xRc = HvLpEvent_Rc_InvalidSubtype;
1033 HvCallEvent_ackLpEvent(event);
1034 }
1035 }
1036}
1037
1038/*
1039 * Send an open event
1040 */
1041static int send_open(HvLpIndex remoteLp, void *sem)
1042{
1043 return HvCallEvent_signalLpEventFast(remoteLp,
1044 HvLpEvent_Type_VirtualIo,
1045 viomajorsubtype_chario | viocharopen,
1046 HvLpEvent_AckInd_DoAck, HvLpEvent_AckType_ImmediateAck,
1047 viopath_sourceinst(remoteLp),
1048 viopath_targetinst(remoteLp),
1049 (u64)(unsigned long)sem, VIOVERSION << 16,
1050 0, 0, 0, 0);
1051}
1052
1053static const struct tty_operations serial_ops = {
1054 .open = viotty_open,
1055 .close = viotty_close,
1056 .write = viotty_write,
1057 .put_char = viotty_put_char,
1058 .write_room = viotty_write_room,
1059 .chars_in_buffer = viotty_chars_in_buffer,
1060 .ioctl = viotty_ioctl,
1061};
1062
1063static int __init viocons_init2(void)
1064{
1065 atomic_t wait_flag;
1066 int rc;
1067
1068 if (!firmware_has_feature(FW_FEATURE_ISERIES))
1069 return -ENODEV;
1070
1071 /* +2 for fudge */
1072 rc = viopath_open(HvLpConfig_getPrimaryLpIndex(),
1073 viomajorsubtype_chario, VIOCHAR_WINDOW + 2);
1074 if (rc)
1075 printk(VIOCONS_KERN_WARN "error opening to primary %d\n", rc);
1076
1077 if (viopath_hostLp == HvLpIndexInvalid)
1078 vio_set_hostlp();
1079
1080 /*
1081 * And if the primary is not the same as the hosting LP, open to the
1082 * hosting lp
1083 */
1084 if ((viopath_hostLp != HvLpIndexInvalid) &&
1085 (viopath_hostLp != HvLpConfig_getPrimaryLpIndex())) {
1086 printk(VIOCONS_KERN_INFO "open path to hosting (%d)\n",
1087 viopath_hostLp);
1088 rc = viopath_open(viopath_hostLp, viomajorsubtype_chario,
1089 VIOCHAR_WINDOW + 2); /* +2 for fudge */
1090 if (rc)
1091 printk(VIOCONS_KERN_WARN
1092 "error opening to partition %d: %d\n",
1093 viopath_hostLp, rc);
1094 }
1095
1096 if (vio_setHandler(viomajorsubtype_chario, vioHandleCharEvent) < 0)
1097 printk(VIOCONS_KERN_WARN
1098 "error seting handler for console events!\n");
1099
1100 /*
1101 * First, try to open the console to the hosting lp.
1102 * Wait on a semaphore for the response.
1103 */
1104 atomic_set(&wait_flag, 0);
1105 if ((viopath_isactive(viopath_hostLp)) &&
1106 (send_open(viopath_hostLp, (void *)&wait_flag) == 0)) {
1107 printk(VIOCONS_KERN_INFO "hosting partition %d\n",
1108 viopath_hostLp);
1109 while (atomic_read(&wait_flag) == 0)
1110 mb();
1111 atomic_set(&wait_flag, 0);
1112 }
1113
1114 /*
1115 * If we don't have an active console, try the primary
1116 */
1117 if ((!viopath_isactive(port_info[0].lp)) &&
1118 (viopath_isactive(HvLpConfig_getPrimaryLpIndex())) &&
1119 (send_open(HvLpConfig_getPrimaryLpIndex(), (void *)&wait_flag)
1120 == 0)) {
1121 printk(VIOCONS_KERN_INFO "opening console to primary partition\n");
1122 while (atomic_read(&wait_flag) == 0)
1123 mb();
1124 }
1125
1126 /* Initialize the tty_driver structure */
1127 viotty_driver = alloc_tty_driver(VTTY_PORTS);
1128 viotty_driver->owner = THIS_MODULE;
1129 viotty_driver->driver_name = "vioconsole";
1130 viotty_driver->name = "tty";
1131 viotty_driver->name_base = 1;
1132 viotty_driver->major = TTY_MAJOR;
1133 viotty_driver->minor_start = 1;
1134 viotty_driver->type = TTY_DRIVER_TYPE_CONSOLE;
1135 viotty_driver->subtype = 1;
1136 viotty_driver->init_termios = tty_std_termios;
1137 viotty_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS;
1138 tty_set_operations(viotty_driver, &serial_ops);
1139
1140 if (tty_register_driver(viotty_driver)) {
1141 printk(VIOCONS_KERN_WARN "couldn't register console driver\n");
1142 put_tty_driver(viotty_driver);
1143 viotty_driver = NULL;
1144 }
1145
1146 unregister_console(&viocons_early);
1147 register_console(&viocons);
1148
1149 return 0;
1150}
1151
1152static int __init viocons_init(void)
1153{
1154 int i;
1155
1156 if (!firmware_has_feature(FW_FEATURE_ISERIES))
1157 return -ENODEV;
1158
1159 printk(VIOCONS_KERN_INFO "registering console\n");
1160 for (i = 0; i < VTTY_PORTS; i++) {
1161 port_info[i].lp = HvLpIndexInvalid;
1162 port_info[i].magic = VIOTTY_MAGIC;
1163 }
1164 HvCall_setLogBufferFormatAndCodepage(HvCall_LogBuffer_ASCII, 437);
1165 add_preferred_console("viocons", 0, NULL);
1166 register_console(&viocons_early);
1167 return 0;
1168}
1169
1170console_initcall(viocons_init);
1171module_init(viocons_init2);