diff options
Diffstat (limited to 'drivers/char')
-rw-r--r-- | drivers/char/Kconfig | 6 | ||||
-rw-r--r-- | drivers/char/Makefile | 1 | ||||
-rw-r--r-- | drivers/char/bsr.c | 84 | ||||
-rw-r--r-- | drivers/char/hvc_console.c | 13 | ||||
-rw-r--r-- | drivers/char/hvc_console.h | 2 | ||||
-rw-r--r-- | drivers/char/hvc_iseries.c | 4 | ||||
-rw-r--r-- | drivers/char/hvc_udbg.c | 96 | ||||
-rw-r--r-- | drivers/char/hvc_vio.c | 4 | ||||
-rw-r--r-- | drivers/char/hvcs.c | 2 | ||||
-rw-r--r-- | drivers/char/hvsi.c | 2 |
10 files changed, 174 insertions, 40 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 8783457b93d..c602b547cc6 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -641,6 +641,12 @@ config HVC_XEN help Xen virtual console device driver +config HVC_UDBG + bool "udbg based fake hypervisor console" + depends on PPC && EXPERIMENTAL + select HVC_DRIVER + default n + config VIRTIO_CONSOLE tristate "Virtio console" depends on VIRTIO diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 36151bae0d7..9caf5b5ad1c 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -51,6 +51,7 @@ obj-$(CONFIG_HVC_DRIVER) += hvc_console.o obj-$(CONFIG_HVC_IRQ) += hvc_irq.o obj-$(CONFIG_HVC_XEN) += hvc_xen.o obj-$(CONFIG_HVC_IUCV) += hvc_iucv.o +obj-$(CONFIG_HVC_UDBG) += hvc_udbg.o obj-$(CONFIG_VIRTIO_CONSOLE) += virtio_console.o obj-$(CONFIG_RAW_DRIVER) += raw.o obj-$(CONFIG_SGI_SNSC) += snsc.o snsc_event.o diff --git a/drivers/char/bsr.c b/drivers/char/bsr.c index 456f54db73e..977dfb1096a 100644 --- a/drivers/char/bsr.c +++ b/drivers/char/bsr.c @@ -60,6 +60,8 @@ struct bsr_dev { unsigned bsr_num; /* bsr id number for its type */ int bsr_minor; + struct list_head bsr_list; + dev_t bsr_dev; struct cdev bsr_cdev; struct device *bsr_device; @@ -67,8 +69,8 @@ struct bsr_dev { }; -static unsigned num_bsr_devs; -static struct bsr_dev *bsr_devs; +static unsigned total_bsr_devs; +static struct list_head bsr_devs = LIST_HEAD_INIT(bsr_devs); static struct class *bsr_class; static int bsr_major; @@ -146,24 +148,25 @@ const static struct file_operations bsr_fops = { static void bsr_cleanup_devs(void) { - int i; - for (i=0 ; i < num_bsr_devs; i++) { - struct bsr_dev *cur = bsr_devs + i; + struct bsr_dev *cur, *n; + + list_for_each_entry_safe(cur, n, &bsr_devs, bsr_list) { if (cur->bsr_device) { cdev_del(&cur->bsr_cdev); device_del(cur->bsr_device); } + list_del(&cur->bsr_list); + kfree(cur); } - - kfree(bsr_devs); } -static int bsr_create_devs(struct device_node *bn) +static int bsr_add_node(struct device_node *bn) { - int bsr_stride_len, bsr_bytes_len; + int bsr_stride_len, bsr_bytes_len, num_bsr_devs; const u32 *bsr_stride; const u32 *bsr_bytes; unsigned i; + int ret = -ENODEV; bsr_stride = of_get_property(bn, "ibm,lock-stride", &bsr_stride_len); bsr_bytes = of_get_property(bn, "ibm,#lock-bytes", &bsr_bytes_len); @@ -171,35 +174,36 @@ static int bsr_create_devs(struct device_node *bn) if (!bsr_stride || !bsr_bytes || (bsr_stride_len != bsr_bytes_len)) { printk(KERN_ERR "bsr of-node has missing/incorrect property\n"); - return -ENODEV; + return ret; } num_bsr_devs = bsr_bytes_len / sizeof(u32); - /* only a warning, its informational since we'll fail and exit */ - WARN_ON(num_bsr_devs > BSR_MAX_DEVS); - - bsr_devs = kzalloc(sizeof(struct bsr_dev) * num_bsr_devs, GFP_KERNEL); - if (!bsr_devs) - return -ENOMEM; - for (i = 0 ; i < num_bsr_devs; i++) { - struct bsr_dev *cur = bsr_devs + i; + struct bsr_dev *cur = kzalloc(sizeof(struct bsr_dev), + GFP_KERNEL); struct resource res; int result; + if (!cur) { + printk(KERN_ERR "Unable to alloc bsr dev\n"); + ret = -ENOMEM; + goto out_err; + } + result = of_address_to_resource(bn, i, &res); if (result < 0) { - printk(KERN_ERR "bsr of-node has invalid reg property\n"); - goto out_err; + printk(KERN_ERR "bsr of-node has invalid reg property, skipping\n"); + kfree(cur); + continue; } - cur->bsr_minor = i; + cur->bsr_minor = i + total_bsr_devs; cur->bsr_addr = res.start; cur->bsr_len = res.end - res.start + 1; cur->bsr_bytes = bsr_bytes[i]; cur->bsr_stride = bsr_stride[i]; - cur->bsr_dev = MKDEV(bsr_major, i); + cur->bsr_dev = MKDEV(bsr_major, i + total_bsr_devs); switch(cur->bsr_bytes) { case 8: @@ -220,14 +224,15 @@ static int bsr_create_devs(struct device_node *bn) } cur->bsr_num = bsr_types[cur->bsr_type]; - bsr_types[cur->bsr_type] = cur->bsr_num + 1; snprintf(cur->bsr_name, 32, "bsr%d_%d", cur->bsr_bytes, cur->bsr_num); cdev_init(&cur->bsr_cdev, &bsr_fops); result = cdev_add(&cur->bsr_cdev, cur->bsr_dev, 1); - if (result) + if (result) { + kfree(cur); goto out_err; + } cur->bsr_device = device_create(bsr_class, NULL, cur->bsr_dev, cur, cur->bsr_name); @@ -235,16 +240,37 @@ static int bsr_create_devs(struct device_node *bn) printk(KERN_ERR "device_create failed for %s\n", cur->bsr_name); cdev_del(&cur->bsr_cdev); + kfree(cur); goto out_err; } + + bsr_types[cur->bsr_type] = cur->bsr_num + 1; + list_add_tail(&cur->bsr_list, &bsr_devs); } + total_bsr_devs += num_bsr_devs; + return 0; out_err: bsr_cleanup_devs(); - return -ENODEV; + return ret; +} + +static int bsr_create_devs(struct device_node *bn) +{ + int ret; + + while (bn) { + ret = bsr_add_node(bn); + if (ret) { + of_node_put(bn); + return ret; + } + bn = of_find_compatible_node(bn, NULL, "ibm,bsr"); + } + return 0; } static int __init bsr_init(void) @@ -254,7 +280,7 @@ static int __init bsr_init(void) int ret = -ENODEV; int result; - np = of_find_compatible_node(NULL, "ibm,bsr", "ibm,bsr"); + np = of_find_compatible_node(NULL, NULL, "ibm,bsr"); if (!np) goto out_err; @@ -272,10 +298,10 @@ static int __init bsr_init(void) goto out_err_2; } - if ((ret = bsr_create_devs(np)) < 0) + if ((ret = bsr_create_devs(np)) < 0) { + np = NULL; goto out_err_3; - - of_node_put(np); + } return 0; diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 5b819b12675..fb57f67bb42 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -642,8 +642,11 @@ int hvc_poll(struct hvc_struct *hp) /* Handle the SysRq Hack */ /* XXX should support a sequence */ if (buf[i] == '\x0f') { /* ^O */ - sysrq_pressed = 1; - continue; + /* if ^O is pressed again, reset + * sysrq_pressed and flip ^O char */ + sysrq_pressed = !sysrq_pressed; + if (sysrq_pressed) + continue; } else if (sysrq_pressed) { handle_sysrq(buf[i], tty); sysrq_pressed = 0; @@ -689,10 +692,8 @@ EXPORT_SYMBOL_GPL(hvc_poll); */ void hvc_resize(struct hvc_struct *hp, struct winsize ws) { - if ((hp->ws.ws_row != ws.ws_row) || (hp->ws.ws_col != ws.ws_col)) { - hp->ws = ws; - schedule_work(&hp->tty_resize); - } + hp->ws = ws; + schedule_work(&hp->tty_resize); } /* diff --git a/drivers/char/hvc_console.h b/drivers/char/hvc_console.h index 8297dbc2e6e..3c85d78c975 100644 --- a/drivers/char/hvc_console.h +++ b/drivers/char/hvc_console.h @@ -48,7 +48,7 @@ struct hvc_struct { spinlock_t lock; int index; struct tty_struct *tty; - unsigned int count; + int count; int do_wakeup; char *outbuf; int outbuf_size; diff --git a/drivers/char/hvc_iseries.c b/drivers/char/hvc_iseries.c index b74a2f8ab90..449727b6166 100644 --- a/drivers/char/hvc_iseries.c +++ b/drivers/char/hvc_iseries.c @@ -575,8 +575,10 @@ static int __init hvc_find_vtys(void) * of console adapters. */ if ((num_found >= MAX_NR_HVC_CONSOLES) || - (num_found >= VTTY_PORTS)) + (num_found >= VTTY_PORTS)) { + of_node_put(vty); break; + } vtermno = of_get_property(vty, "reg", NULL); if (!vtermno) diff --git a/drivers/char/hvc_udbg.c b/drivers/char/hvc_udbg.c new file mode 100644 index 00000000000..bd63ba878a5 --- /dev/null +++ b/drivers/char/hvc_udbg.c @@ -0,0 +1,96 @@ +/* + * udbg interface to hvc_console.c + * + * (C) Copyright David Gibson, IBM Corporation 2008. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/console.h> +#include <linux/delay.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/moduleparam.h> +#include <linux/types.h> +#include <linux/irq.h> + +#include <asm/udbg.h> + +#include "hvc_console.h" + +struct hvc_struct *hvc_udbg_dev; + +static int hvc_udbg_put(uint32_t vtermno, const char *buf, int count) +{ + int i; + + for (i = 0; i < count; i++) + udbg_putc(buf[i]); + + return i; +} + +static int hvc_udbg_get(uint32_t vtermno, char *buf, int count) +{ + int i, c; + + if (!udbg_getc_poll) + return 0; + + for (i = 0; i < count; i++) { + if ((c = udbg_getc_poll()) == -1) + break; + buf[i] = c; + } + + return i; +} + +static struct hv_ops hvc_udbg_ops = { + .get_chars = hvc_udbg_get, + .put_chars = hvc_udbg_put, +}; + +static int __init hvc_udbg_init(void) +{ + struct hvc_struct *hp; + + BUG_ON(hvc_udbg_dev); + + hp = hvc_alloc(0, NO_IRQ, &hvc_udbg_ops, 16); + if (IS_ERR(hp)) + return PTR_ERR(hp); + + hvc_udbg_dev = hp; + + return 0; +} +module_init(hvc_udbg_init); + +static void __exit hvc_udbg_exit(void) +{ + if (hvc_udbg_dev) + hvc_remove(hvc_udbg_dev); +} +module_exit(hvc_udbg_exit); + +static int __init hvc_udbg_console_init(void) +{ + hvc_instantiate(0, 0, &hvc_udbg_ops); + add_preferred_console("hvc", 0, NULL); + + return 0; +} +console_initcall(hvc_udbg_console_init); diff --git a/drivers/char/hvc_vio.c b/drivers/char/hvc_vio.c index 019e0b58593..bd62dc86b47 100644 --- a/drivers/char/hvc_vio.c +++ b/drivers/char/hvc_vio.c @@ -153,8 +153,10 @@ static int hvc_find_vtys(void) /* We have statically defined space for only a certain number * of console adapters. */ - if (num_found >= MAX_NR_HVC_CONSOLES) + if (num_found >= MAX_NR_HVC_CONSOLES) { + of_node_put(vty); break; + } vtermno = of_get_property(vty, "reg", NULL); if (!vtermno) diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c index 473d9b14439..6e6eb445d37 100644 --- a/drivers/char/hvcs.c +++ b/drivers/char/hvcs.c @@ -269,7 +269,7 @@ struct hvcs_struct { unsigned int index; struct tty_struct *tty; - unsigned int open_count; + int open_count; /* * Used to tell the driver kernel_thread what operations need to take diff --git a/drivers/char/hvsi.c b/drivers/char/hvsi.c index 59c6f9ab94e..af055287271 100644 --- a/drivers/char/hvsi.c +++ b/drivers/char/hvsi.c @@ -75,7 +75,7 @@ struct hvsi_struct { spinlock_t lock; int index; struct tty_struct *tty; - unsigned int count; + int count; uint8_t throttle_buf[128]; uint8_t outbuf[N_OUTBUF]; /* to implement write_room and chars_in_buffer */ /* inbuf is for packet reassembly. leave a little room for leftovers. */ |