1/* 2 * Beat hypervisor console driver 3 * 4 * (C) Copyright 2006 TOSHIBA CORPORATION 5 * 6 * This code is based on drivers/char/hvc_rtas.c: 7 * (C) Copyright IBM Corporation 2001-2005 8 * (C) Copyright Red Hat, Inc. 2005 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License as published by 12 * the Free Software Foundation; either version 2 of the License, or 13 * (at your option) any later version. 14 * 15 * This program is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU General Public License for more details. 19 * 20 * You should have received a copy of the GNU General Public License along 21 * with this program; if not, write to the Free Software Foundation, Inc., 22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 23 */ 24 25#include <linux/module.h> 26#include <linux/init.h> 27#include <linux/err.h> 28#include <linux/string.h> 29#include <linux/console.h> 30#include <asm/prom.h> 31#include <asm/hvconsole.h> 32#include <asm/firmware.h> 33 34#include "hvc_console.h" 35 36extern int64_t beat_get_term_char(uint64_t, uint64_t *, uint64_t *, uint64_t *); 37extern int64_t beat_put_term_char(uint64_t, uint64_t, uint64_t, uint64_t); 38 39struct hvc_struct *hvc_beat_dev = NULL; 40 41/* bug: only one queue is available regardless of vtermno */ 42static int hvc_beat_get_chars(uint32_t vtermno, char *buf, int cnt) 43{ 44 static unsigned char q[sizeof(unsigned long) * 2] 45 __attribute__((aligned(sizeof(unsigned long)))); 46 static int qlen = 0; 47 u64 got; 48 49again: 50 if (qlen) { 51 if (qlen > cnt) { 52 memcpy(buf, q, cnt); 53 qlen -= cnt; 54 memmove(q + cnt, q, qlen); 55 return cnt; 56 } else { /* qlen <= cnt */ 57 int r; 58 59 memcpy(buf, q, qlen); 60 r = qlen; 61 qlen = 0; 62 return r; 63 } 64 } 65 if (beat_get_term_char(vtermno, &got, 66 ((u64 *)q), ((u64 *)q) + 1) == 0) { 67 qlen = got; 68 goto again; 69 } 70 return 0; 71} 72 73static int hvc_beat_put_chars(uint32_t vtermno, const char *buf, int cnt) 74{ 75 unsigned long kb[2]; 76 int rest, nlen; 77 78 for (rest = cnt; rest > 0; rest -= nlen) { 79 nlen = (rest > 16) ? 16 : rest; 80 memcpy(kb, buf, nlen); 81 beat_put_term_char(vtermno, nlen, kb[0], kb[1]); 82 buf += nlen; 83 } 84 return cnt; 85} 86 87static const struct hv_ops hvc_beat_get_put_ops = { 88 .get_chars = hvc_beat_get_chars, 89 .put_chars = hvc_beat_put_chars, 90}; 91 92static int hvc_beat_useit = 1; 93 94static int hvc_beat_config(char *p) 95{ 96 hvc_beat_useit = simple_strtoul(p, NULL, 0); 97 return 0; 98} 99 100static int __init hvc_beat_console_init(void) 101{ 102 if (hvc_beat_useit && of_machine_is_compatible("Beat")) { 103 hvc_instantiate(0, 0, &hvc_beat_get_put_ops); 104 } 105 return 0; 106} 107 108/* temp */ 109static int __init hvc_beat_init(void) 110{ 111 struct hvc_struct *hp; 112 113 if (!firmware_has_feature(FW_FEATURE_BEAT)) 114 return -ENODEV; 115 116 hp = hvc_alloc(0, 0, &hvc_beat_get_put_ops, 16); 117 if (IS_ERR(hp)) 118 return PTR_ERR(hp); 119 hvc_beat_dev = hp; 120 return 0; 121} 122 123static void __exit hvc_beat_exit(void) 124{ 125 if (hvc_beat_dev) 126 hvc_remove(hvc_beat_dev); 127} 128 129module_init(hvc_beat_init); 130module_exit(hvc_beat_exit); 131 132__setup("hvc_beat=", hvc_beat_config); 133 134console_initcall(hvc_beat_console_init); 135