summaryrefslogtreecommitdiffstats
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/agp/hp-agp.c5
-rw-r--r--drivers/char/hvc_iucv.c204
-rw-r--r--drivers/char/hvcs.c6
-rw-r--r--drivers/char/hw_random/Kconfig13
-rw-r--r--drivers/char/hw_random/Makefile1
-rw-r--r--drivers/char/hw_random/core.c1
-rw-r--r--drivers/char/hw_random/tx4939-rng.c184
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c4
-rw-r--r--drivers/char/isicom.c2
-rw-r--r--drivers/char/mem.c115
-rw-r--r--drivers/char/misc.c15
-rw-r--r--drivers/char/ppdev.c29
-rw-r--r--drivers/char/ps3flash.c296
-rw-r--r--drivers/char/pty.c53
-rw-r--r--drivers/char/raw.c6
-rw-r--r--drivers/char/sysrq.c15
-rw-r--r--drivers/char/tty_io.c2
-rw-r--r--drivers/char/tty_ioctl.c5
-rw-r--r--drivers/char/tty_ldisc.c9
-rw-r--r--drivers/char/viotape.c2
-rw-r--r--drivers/char/vt.c13
22 files changed, 674 insertions, 308 deletions
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index 30bae6de6a0..0bd01f49cfd 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -807,7 +807,7 @@ if RTC_LIB=n
config RTC
tristate "Enhanced Real Time Clock Support (legacy PC RTC driver)"
depends on !PPC && !PARISC && !IA64 && !M68K && !SPARC && !FRV \
- && !ARM && !SUPERH && !S390 && !AVR32
+ && !ARM && !SUPERH && !S390 && !AVR32 && !BLACKFIN
---help---
If you say Y here and create a character special file /dev/rtc with
major number 10 and minor number 135 using mknod ("man mknod"), you
diff --git a/drivers/char/agp/hp-agp.c b/drivers/char/agp/hp-agp.c
index 183ac3fe44f..9c7e2343c39 100644
--- a/drivers/char/agp/hp-agp.c
+++ b/drivers/char/agp/hp-agp.c
@@ -518,8 +518,9 @@ zx1_gart_probe (acpi_handle obj, u32 depth, void *context, void **ret)
if (hp_zx1_setup(sba_hpa + HP_ZX1_IOC_OFFSET, lba_hpa))
return AE_OK;
- printk(KERN_INFO PFX "Detected HP ZX1 %s AGP chipset (ioc=%lx, lba=%lx)\n",
- (char *) context, sba_hpa + HP_ZX1_IOC_OFFSET, lba_hpa);
+ printk(KERN_INFO PFX "Detected HP ZX1 %s AGP chipset "
+ "(ioc=%llx, lba=%llx)\n", (char *)context,
+ sba_hpa + HP_ZX1_IOC_OFFSET, lba_hpa);
hp_zx1_gart_found = 1;
return AE_CTRL_TERMINATE; /* we only support one bridge; quit looking */
diff --git a/drivers/char/hvc_iucv.c b/drivers/char/hvc_iucv.c
index 54481a88776..86105efb4eb 100644
--- a/drivers/char/hvc_iucv.c
+++ b/drivers/char/hvc_iucv.c
@@ -4,7 +4,7 @@
* This HVC device driver provides terminal access using
* z/VM IUCV communication paths.
*
- * Copyright IBM Corp. 2008
+ * Copyright IBM Corp. 2008, 2009
*
* Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
*/
@@ -15,6 +15,7 @@
#include <asm/ebcdic.h>
#include <linux/ctype.h>
#include <linux/delay.h>
+#include <linux/device.h>
#include <linux/init.h>
#include <linux/mempool.h>
#include <linux/moduleparam.h>
@@ -74,6 +75,7 @@ struct hvc_iucv_private {
wait_queue_head_t sndbuf_waitq; /* wait for send completion */
struct list_head tty_outqueue; /* outgoing IUCV messages */
struct list_head tty_inqueue; /* incoming IUCV messages */
+ struct device *dev; /* device structure */
};
struct iucv_tty_buffer {
@@ -542,7 +544,68 @@ static void flush_sndbuf_sync(struct hvc_iucv_private *priv)
if (sync_wait)
wait_event_timeout(priv->sndbuf_waitq,
- tty_outqueue_empty(priv), HZ);
+ tty_outqueue_empty(priv), HZ/10);
+}
+
+/**
+ * hvc_iucv_hangup() - Sever IUCV path and schedule hvc tty hang up
+ * @priv: Pointer to hvc_iucv_private structure
+ *
+ * This routine severs an existing IUCV communication path and hangs
+ * up the underlying HVC terminal device.
+ * The hang-up occurs only if an IUCV communication path is established;
+ * otherwise there is no need to hang up the terminal device.
+ *
+ * The IUCV HVC hang-up is separated into two steps:
+ * 1. After the IUCV path has been severed, the iucv_state is set to
+ * IUCV_SEVERED.
+ * 2. Later, when the HVC thread calls hvc_iucv_get_chars(), the
+ * IUCV_SEVERED state causes the tty hang-up in the HVC layer.
+ *
+ * If the tty has not yet been opened, clean up the hvc_iucv_private
+ * structure to allow re-connects.
+ * If the tty has been opened, let get_chars() return -EPIPE to signal
+ * the HVC layer to hang up the tty and, if so, wake up the HVC thread
+ * to call get_chars()...
+ *
+ * Special notes on hanging up a HVC terminal instantiated as console:
+ * Hang-up: 1. do_tty_hangup() replaces file ops (= hung_up_tty_fops)
+ * 2. do_tty_hangup() calls tty->ops->close() for console_filp
+ * => no hangup notifier is called by HVC (default)
+ * 2. hvc_close() returns because of tty_hung_up_p(filp)
+ * => no delete notifier is called!
+ * Finally, the back-end is not being notified, thus, the tty session is
+ * kept active (TTY_OPEN) to be ready for re-connects.
+ *
+ * Locking: spin_lock(&priv->lock) w/o disabling bh
+ */
+static void hvc_iucv_hangup(struct hvc_iucv_private *priv)
+{
+ struct iucv_path *path;
+
+ path = NULL;
+ spin_lock(&priv->lock);
+ if (priv->iucv_state == IUCV_CONNECTED) {
+ path = priv->path;
+ priv->path = NULL;
+ priv->iucv_state = IUCV_SEVERED;
+ if (priv->tty_state == TTY_CLOSED)
+ hvc_iucv_cleanup(priv);
+ else
+ /* console is special (see above) */
+ if (priv->is_console) {
+ hvc_iucv_cleanup(priv);
+ priv->tty_state = TTY_OPENED;
+ } else
+ hvc_kick();
+ }
+ spin_unlock(&priv->lock);
+
+ /* finally sever path (outside of priv->lock due to lock ordering) */
+ if (path) {
+ iucv_path_sever(path, NULL);
+ iucv_path_free(path);
+ }
}
/**
@@ -735,11 +798,8 @@ out_path_handled:
* @ipuser: User specified data for this path
* (AF_IUCV: port/service name and originator port)
*
- * The function also severs the path (as required by the IUCV protocol) and
- * sets the iucv state to IUCV_SEVERED for the associated struct
- * hvc_iucv_private instance. Later, the IUCV_SEVERED state triggers a tty
- * hangup (hvc_iucv_get_chars() / hvc_iucv_write()).
- * If tty portion of the HVC is closed, clean up the outqueue.
+ * This function calls the hvc_iucv_hangup() function for the
+ * respective IUCV HVC terminal.
*
* Locking: struct hvc_iucv_private->lock
*/
@@ -747,33 +807,7 @@ static void hvc_iucv_path_severed(struct iucv_path *path, u8 ipuser[16])
{
struct hvc_iucv_private *priv = path->private;
- spin_lock(&priv->lock);
- priv->iucv_state = IUCV_SEVERED;
-
- /* If the tty has not yet been opened, clean up the hvc_iucv_private
- * structure to allow re-connects.
- * This is also done for our console device because console hangups
- * are handled specially and no notifier is called by HVC.
- * The tty session is active (TTY_OPEN) and ready for re-connects...
- *
- * If it has been opened, let get_chars() return -EPIPE to signal the
- * HVC layer to hang up the tty.
- * If so, we need to wake up the HVC thread to call get_chars()...
- */
- priv->path = NULL;
- if (priv->tty_state == TTY_CLOSED)
- hvc_iucv_cleanup(priv);
- else
- if (priv->is_console) {
- hvc_iucv_cleanup(priv);
- priv->tty_state = TTY_OPENED;
- } else
- hvc_kick();
- spin_unlock(&priv->lock);
-
- /* finally sever path (outside of priv->lock due to lock ordering) */
- iucv_path_sever(path, ipuser);
- iucv_path_free(path);
+ hvc_iucv_hangup(priv);
}
/**
@@ -853,6 +887,37 @@ static void hvc_iucv_msg_complete(struct iucv_path *path,
destroy_tty_buffer_list(&list_remove);
}
+/**
+ * hvc_iucv_pm_freeze() - Freeze PM callback
+ * @dev: IUVC HVC terminal device
+ *
+ * Sever an established IUCV communication path and
+ * trigger a hang-up of the underlying HVC terminal.
+ */
+static int hvc_iucv_pm_freeze(struct device *dev)
+{
+ struct hvc_iucv_private *priv = dev_get_drvdata(dev);
+
+ local_bh_disable();
+ hvc_iucv_hangup(priv);
+ local_bh_enable();
+
+ return 0;
+}
+
+/**
+ * hvc_iucv_pm_restore_thaw() - Thaw and restore PM callback
+ * @dev: IUVC HVC terminal device
+ *
+ * Wake up the HVC thread to trigger hang-up and respective
+ * HVC back-end notifier invocations.
+ */
+static int hvc_iucv_pm_restore_thaw(struct device *dev)
+{
+ hvc_kick();
+ return 0;
+}
+
/* HVC operations */
static struct hv_ops hvc_iucv_ops = {
@@ -863,6 +928,20 @@ static struct hv_ops hvc_iucv_ops = {
.notifier_hangup = hvc_iucv_notifier_hangup,
};
+/* Suspend / resume device operations */
+static struct dev_pm_ops hvc_iucv_pm_ops = {
+ .freeze = hvc_iucv_pm_freeze,
+ .thaw = hvc_iucv_pm_restore_thaw,
+ .restore = hvc_iucv_pm_restore_thaw,
+};
+
+/* IUCV HVC device driver */
+static struct device_driver hvc_iucv_driver = {
+ .name = KMSG_COMPONENT,
+ .bus = &iucv_bus,
+ .pm = &hvc_iucv_pm_ops,
+};
+
/**
* hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance
* @id: hvc_iucv_table index
@@ -897,14 +976,12 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console)
/* set console flag */
priv->is_console = is_console;
- /* finally allocate hvc */
+ /* allocate hvc device */
priv->hvc = hvc_alloc(HVC_IUCV_MAGIC + id, /* PAGE_SIZE */
HVC_IUCV_MAGIC + id, &hvc_iucv_ops, 256);
if (IS_ERR(priv->hvc)) {
rc = PTR_ERR(priv->hvc);
- free_page((unsigned long) priv->sndbuf);
- kfree(priv);
- return rc;
+ goto out_error_hvc;
}
/* notify HVC thread instead of using polling */
@@ -915,8 +992,45 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console)
memcpy(priv->srv_name, name, 8);
ASCEBC(priv->srv_name, 8);
+ /* create and setup device */
+ priv->dev = kzalloc(sizeof(*priv->dev), GFP_KERNEL);
+ if (!priv->dev) {
+ rc = -ENOMEM;
+ goto out_error_dev;
+ }
+ dev_set_name(priv->dev, "hvc_iucv%d", id);
+ dev_set_drvdata(priv->dev, priv);
+ priv->dev->bus = &iucv_bus;
+ priv->dev->parent = iucv_root;
+ priv->dev->driver = &hvc_iucv_driver;
+ priv->dev->release = (void (*)(struct device *)) kfree;
+ rc = device_register(priv->dev);
+ if (rc) {
+ kfree(priv->dev);
+ goto out_error_dev;
+ }
+
hvc_iucv_table[id] = priv;
return 0;
+
+out_error_dev:
+ hvc_remove(priv->hvc);
+out_error_hvc:
+ free_page((unsigned long) priv->sndbuf);
+ kfree(priv);
+
+ return rc;
+}
+
+/**
+ * hvc_iucv_destroy() - Destroy and free hvc_iucv_private instances
+ */
+static void __init hvc_iucv_destroy(struct hvc_iucv_private *priv)
+{
+ hvc_remove(priv->hvc);
+ device_unregister(priv->dev);
+ free_page((unsigned long) priv->sndbuf);
+ kfree(priv);
}
/**
@@ -1109,6 +1223,11 @@ static int __init hvc_iucv_init(void)
goto out_error;
}
+ /* register IUCV HVC device driver */
+ rc = driver_register(&hvc_iucv_driver);
+ if (rc)
+ goto out_error;
+
/* parse hvc_iucv_allow string and create z/VM user ID filter list */
if (hvc_iucv_filter_string) {
rc = hvc_iucv_setup_filter(hvc_iucv_filter_string);
@@ -1183,15 +1302,14 @@ out_error_iucv:
iucv_unregister(&hvc_iucv_handler, 0);
out_error_hvc:
for (i = 0; i < hvc_iucv_devices; i++)
- if (hvc_iucv_table[i]) {
- if (hvc_iucv_table[i]->hvc)
- hvc_remove(hvc_iucv_table[i]->hvc);
- kfree(hvc_iucv_table[i]);
- }
+ if (hvc_iucv_table[i])
+ hvc_iucv_destroy(hvc_iucv_table[i]);
out_error_memory:
mempool_destroy(hvc_iucv_mempool);
kmem_cache_destroy(hvc_iucv_buffer_cache);
out_error:
+ if (hvc_iucv_filter)
+ kfree(hvc_iucv_filter);
hvc_iucv_devices = 0; /* ensure that we do not provide any device */
return rc;
}
diff --git a/drivers/char/hvcs.c b/drivers/char/hvcs.c
index c76bccf5354..7d64e4230e6 100644
--- a/drivers/char/hvcs.c
+++ b/drivers/char/hvcs.c
@@ -347,7 +347,7 @@ static void __exit hvcs_module_exit(void);
static inline struct hvcs_struct *from_vio_dev(struct vio_dev *viod)
{
- return viod->dev.driver_data;
+ return dev_get_drvdata(&viod->dev);
}
/* The sysfs interface for the driver and devices */
@@ -785,7 +785,7 @@ static int __devinit hvcs_probe(
kref_init(&hvcsd->kref);
hvcsd->vdev = dev;
- dev->dev.driver_data = hvcsd;
+ dev_set_drvdata(&dev->dev, hvcsd);
hvcsd->index = index;
@@ -831,7 +831,7 @@ static int __devinit hvcs_probe(
static int __devexit hvcs_remove(struct vio_dev *dev)
{
- struct hvcs_struct *hvcsd = dev->dev.driver_data;
+ struct hvcs_struct *hvcsd = dev_get_drvdata(&dev->dev);
unsigned long flags;
struct tty_struct *tty;
diff --git a/drivers/char/hw_random/Kconfig b/drivers/char/hw_random/Kconfig
index f4b3f7293fe..ce66a70184f 100644
--- a/drivers/char/hw_random/Kconfig
+++ b/drivers/char/hw_random/Kconfig
@@ -149,6 +149,19 @@ config HW_RANDOM_VIRTIO
To compile this driver as a module, choose M here: the
module will be called virtio-rng. If unsure, say N.
+config HW_RANDOM_TX4939
+ tristate "TX4939 Random Number Generator support"
+ depends on HW_RANDOM && SOC_TX4939
+ default HW_RANDOM
+ ---help---
+ This driver provides kernel-side support for the Random Number
+ Generator hardware found on TX4939 SoC.
+
+ To compile this driver as a module, choose M here: the
+ module will be called tx4939-rng.
+
+ If unsure, say Y.
+
config HW_RANDOM_MXC_RNGA
tristate "Freescale i.MX RNGA Random Number Generator"
depends on HW_RANDOM && ARCH_HAS_RNGA
diff --git a/drivers/char/hw_random/Makefile b/drivers/char/hw_random/Makefile
index fd1ecd2f673..676828ba812 100644
--- a/drivers/char/hw_random/Makefile
+++ b/drivers/char/hw_random/Makefile
@@ -15,4 +15,5 @@ obj-$(CONFIG_HW_RANDOM_IXP4XX) += ixp4xx-rng.o
obj-$(CONFIG_HW_RANDOM_OMAP) += omap-rng.o
obj-$(CONFIG_HW_RANDOM_PASEMI) += pasemi-rng.o
obj-$(CONFIG_HW_RANDOM_VIRTIO) += virtio-rng.o
+obj-$(CONFIG_HW_RANDOM_TX4939) += tx4939-rng.o
obj-$(CONFIG_HW_RANDOM_MXC_RNGA) += mxc-rnga.o
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index e5d583c84e4..fc93e2fc7c7 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -153,6 +153,7 @@ static const struct file_operations rng_chrdev_ops = {
static struct miscdevice rng_miscdev = {
.minor = RNG_MISCDEV_MINOR,
.name = RNG_MODULE_NAME,
+ .devnode = "hwrng",
.fops = &rng_chrdev_ops,
};
diff --git a/drivers/char/hw_random/tx4939-rng.c b/drivers/char/hw_random/tx4939-rng.c
new file mode 100644
index 00000000000..544d9085a8e
--- /dev/null
+++ b/drivers/char/hw_random/tx4939-rng.c
@@ -0,0 +1,184 @@
+/*
+ * RNG driver for TX4939 Random Number Generators (RNG)
+ *
+ * Copyright (C) 2009 Atsushi Nemoto <anemo@mba.ocn.ne.jp>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/hw_random.h>
+
+#define TX4939_RNG_RCSR 0x00000000
+#define TX4939_RNG_ROR(n) (0x00000018 + (n) * 8)
+
+#define TX4939_RNG_RCSR_INTE 0x00000008
+#define TX4939_RNG_RCSR_RST 0x00000004
+#define TX4939_RNG_RCSR_FIN 0x00000002
+#define TX4939_RNG_RCSR_ST 0x00000001
+
+struct tx4939_rng {
+ struct hwrng rng;
+ void __iomem *base;
+ u64 databuf[3];
+ unsigned int data_avail;
+};
+
+static void rng_io_start(void)
+{
+#ifndef CONFIG_64BIT
+ /*
+ * readq is reading a 64-bit register using a 64-bit load. On
+ * a 32-bit kernel however interrupts or any other processor
+ * exception would clobber the upper 32-bit of the processor
+ * register so interrupts need to be disabled.
+ */
+ local_irq_disable();
+#endif
+}
+
+static void rng_io_end(void)
+{
+#ifndef CONFIG_64BIT
+ local_irq_enable();
+#endif
+}
+
+static u64 read_rng(void __iomem *base, unsigned int offset)
+{
+ return ____raw_readq(base + offset);
+}
+
+static void write_rng(u64 val, void __iomem *base, unsigned int offset)
+{
+ return ____raw_writeq(val, base + offset);
+}
+
+static int tx4939_rng_data_present(struct hwrng *rng, int wait)
+{
+ struct tx4939_rng *rngdev = container_of(rng, struct tx4939_rng, rng);
+ int i;
+
+ if (rngdev->data_avail)
+ return rngdev->data_avail;
+ for (i = 0; i < 20; i++) {
+ rng_io_start();
+ if (!(read_rng(rngdev->base, TX4939_RNG_RCSR)
+ & TX4939_RNG_RCSR_ST)) {
+ rngdev->databuf[0] =
+ read_rng(rngdev->base, TX4939_RNG_ROR(0));
+ rngdev->databuf[1] =
+ read_rng(rngdev->base, TX4939_RNG_ROR(1));
+ rngdev->databuf[2] =
+ read_rng(rngdev->base, TX4939_RNG_ROR(2));
+ rngdev->data_avail =
+ sizeof(rngdev->databuf) / sizeof(u32);
+ /* Start RNG */
+ write_rng(TX4939_RNG_RCSR_ST,
+ rngdev->base, TX4939_RNG_RCSR);
+ wait = 0;
+ }
+ rng_io_end();
+ if (!wait)
+ break;
+ /* 90 bus clock cycles by default for generation */
+ ndelay(90 * 5);
+ }
+ return rngdev->data_avail;
+}
+
+static int tx4939_rng_data_read(struct hwrng *rng, u32 *buffer)
+{
+ struct tx4939_rng *rngdev = container_of(rng, struct tx4939_rng, rng);
+
+ rngdev->data_avail--;
+ *buffer = *((u32 *)&rngdev->databuf + rngdev->data_avail);
+ return sizeof(u32);
+}
+
+static int __init tx4939_rng_probe(struct platform_device *dev)
+{
+ struct tx4939_rng *rngdev;
+ struct resource *r;
+ int i;
+
+ r = platform_get_resource(dev, IORESOURCE_MEM, 0);
+ if (!r)
+ return -EBUSY;
+ rngdev = devm_kzalloc(&dev->dev, sizeof(*rngdev), GFP_KERNEL);
+ if (!rngdev)
+ return -ENOMEM;
+ if (!devm_request_mem_region(&dev->dev, r->start, resource_size(r),
+ dev_name(&dev->dev)))
+ return -EBUSY;
+ rngdev->base = devm_ioremap(&dev->dev, r->start, resource_size(r));
+ if (!rngdev->base)
+ return -EBUSY;
+
+ rngdev->rng.name = dev_name(&dev->dev);
+ rngdev->rng.data_present = tx4939_rng_data_present;
+ rngdev->rng.data_read = tx4939_rng_data_read;
+
+ rng_io_start();
+ /* Reset RNG */
+ write_rng(TX4939_RNG_RCSR_RST, rngdev->base, TX4939_RNG_RCSR);
+ write_rng(0, rngdev->base, TX4939_RNG_RCSR);
+ /* Start RNG */
+ write_rng(TX4939_RNG_RCSR_ST, rngdev->base, TX4939_RNG_RCSR);
+ rng_io_end();
+ /*
+ * Drop first two results. From the datasheet:
+ * The quality of the random numbers generated immediately
+ * after reset can be insufficient. Therefore, do not use
+ * random numbers obtained from the first and second
+ * generations; use the ones from the third or subsequent
+ * generation.
+ */
+ for (i = 0; i < 2; i++) {
+ rngdev->data_avail = 0;
+ if (!tx4939_rng_data_present(&rngdev->rng, 1))
+ return -EIO;
+ }
+
+ platform_set_drvdata(dev, rngdev);
+ return hwrng_register(&rngdev->rng);
+}
+
+static int __exit tx4939_rng_remove(struct platform_device *dev)
+{
+ struct tx4939_rng *rngdev = platform_get_drvdata(dev);
+
+ hwrng_unregister(&rngdev->rng);
+ platform_set_drvdata(dev, NULL);
+ return 0;
+}
+
+static struct platform_driver tx4939_rng_driver = {
+ .driver = {
+ .name = "tx4939-rng",
+ .owner = THIS_MODULE,
+ },
+ .remove = tx4939_rng_remove,
+};
+
+static int __init tx4939rng_init(void)
+{
+ return platform_driver_probe(&tx4939_rng_driver, tx4939_rng_probe);
+}
+
+static void __exit tx4939rng_exit(void)
+{
+ platform_driver_unregister(&tx4939_rng_driver);
+}
+
+module_init(tx4939rng_init);
+module_exit(tx4939rng_exit);
+
+MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver for TX4939");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 259644646b8..d2e698096ac 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -2375,14 +2375,14 @@ static int __devinit ipmi_of_probe(struct of_device *dev,
info->io.addr_data, info->io.regsize, info->io.regspacing,
info->irq);
- dev->dev.driver_data = (void *) info;
+ dev_set_drvdata(&dev->dev, info);
return try_smi_init(info);
}
static int __devexit ipmi_of_remove(struct of_device *dev)
{
- cleanup_one_si(dev->dev.driver_data);
+ cleanup_one_si(dev_get_drvdata(&dev->dev));
return 0;
}
diff --git a/drivers/char/isicom.c b/drivers/char/isicom.c
index 4d745a89504..4159292e35c 100644
--- a/drivers/char/isicom.c
+++ b/drivers/char/isicom.c
@@ -1593,7 +1593,7 @@ static unsigned int card_count;
static int __devinit isicom_probe(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
- unsigned int signature, index;
+ unsigned int uninitialized_var(signature), index;
int retval = -EPERM;
struct isi_board *board = NULL;
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index f96d0bef855..afa8813e737 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -863,59 +863,58 @@ static const struct file_operations kmsg_fops = {
.write = kmsg_write,
};
-static int memory_open(struct inode * inode, struct file * filp)
-{
- int ret = 0;
-
- lock_kernel();
- switch (iminor(inode)) {
- case 1:
- filp->f_op = &mem_fops;
- filp->f_mapping->backing_dev_info =
- &directly_mappable_cdev_bdi;
- break;
+static const struct {
+ unsigned int minor;
+ char *name;
+ umode_t mode;
+ const struct file_operations *fops;
+ struct backing_dev_info *dev_info;
+} devlist[] = { /* list of minor devices */
+ {1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops,
+ &directly_mappable_cdev_bdi},
#ifdef CONFIG_DEVKMEM
- case 2:
- filp->f_op = &kmem_fops;
- filp->f_mapping->backing_dev_info =
- &directly_mappable_cdev_bdi;
- break;
+ {2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops,
+ &directly_mappable_cdev_bdi},
#endif
- case 3:
- filp->f_op = &null_fops;
- break;
+ {3, "null", S_IRUGO | S_IWUGO, &null_fops, NULL},
#ifdef CONFIG_DEVPORT
- case 4:
- filp->f_op = &port_fops;
- break;
+ {4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops, NULL},
#endif
- case 5:
- filp->f_mapping->backing_dev_info = &zero_bdi;
- filp->f_op = &zero_fops;
- break;
- case 7:
- filp->f_op = &full_fops;
- break;
- case 8:
- filp->f_op = &random_fops;
- break;
- case 9:
- filp->f_op = &urandom_fops;
- break;
- case 11:
- filp->f_op = &kmsg_fops;
- break;
+ {5, "zero", S_IRUGO | S_IWUGO, &zero_fops, &zero_bdi},
+ {7, "full", S_IRUGO | S_IWUGO, &full_fops, NULL},
+ {8, "random", S_IRUGO | S_IWUSR, &random_fops, NULL},
+ {9, "urandom", S_IRUGO | S_IWUSR, &urandom_fops, NULL},
+ {11,"kmsg", S_IRUGO | S_IWUSR, &kmsg_fops, NULL},
#ifdef CONFIG_CRASH_DUMP
- case 12:
- filp->f_op = &oldmem_fops;
- break;
+ {12,"oldmem", S_IRUSR | S_IWUSR | S_IRGRP, &oldmem_fops, NULL},
#endif
- default:
- unlock_kernel();
- return -ENXIO;
+};
+
+static int memory_open(struct inode *inode, struct file *filp)
+{
+ int ret = 0;
+ int i;
+
+ lock_kernel();
+
+ for (i = 0; i < ARRAY_SIZE(devlist); i++) {
+ if (devlist[i].minor == iminor(inode)) {
+ filp->f_op = devlist[i].fops;
+ if (devlist[i].dev_info) {
+ filp->f_mapping->backing_dev_info =
+ devlist[i].dev_info;
+ }
+
+ break;
+ }
}
- if (filp->f_op && filp->f_op->open)
- ret = filp->f_op->open(inode,filp);
+
+ if (i == ARRAY_SIZE(devlist))
+ ret = -ENXIO;
+ else
+ if (filp->f_op && filp->f_op->open)
+ ret = filp->f_op->open(inode, filp);
+
unlock_kernel();
return ret;
}
@@ -924,30 +923,6 @@ static const struct file_operations memory_fops = {
.open = memory_open, /* just a selector for the real open */
};
-static const struct {
- unsigned int minor;
- char *name;
- umode_t mode;
- const struct file_operations *fops;
-} devlist[] = { /* list of minor devices */
- {1, "mem", S_IRUSR | S_IWUSR | S_IRGRP, &mem_fops},
-#ifdef CONFIG_DEVKMEM
- {2, "kmem", S_IRUSR | S_IWUSR | S_IRGRP, &kmem_fops},
-#endif
- {3, "null", S_IRUGO | S_IWUGO, &null_fops},
-#ifdef CONFIG_DEVPORT
- {4, "port", S_IRUSR | S_IWUSR | S_IRGRP, &port_fops},
-#endif
- {5, "zero", S_IRUGO | S_IWUGO, &zero_fops},
- {7, "full", S_IRUGO | S_IWUGO, &full_fops},
- {8, "random", S_IRUGO | S_IWUSR, &random_fops},
- {9, "urandom", S_IRUGO | S_IWUSR, &urandom_fops},
- {11,"kmsg", S_IRUGO | S_IWUSR, &kmsg_fops},
-#ifdef CONFIG_CRASH_DUMP
- {12,"oldmem", S_IRUSR | S_IWUSR | S_IRGRP, &oldmem_fops},
-#endif
-};
-
static struct class *mem_class;
static int __init chr_dev_init(void)
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index a5e0db9d766..62c99fa59e2 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -168,7 +168,6 @@ static const struct file_operations misc_fops = {
.open = misc_open,
};
-
/**
* misc_register - register a miscellaneous device
* @misc: device structure
@@ -217,8 +216,8 @@ int misc_register(struct miscdevice * misc)
misc_minors[misc->minor >> 3] |= 1 << (misc->minor & 7);
dev = MKDEV(MISC_MAJOR, misc->minor);
- misc->this_device = device_create(misc_class, misc->parent, dev, NULL,
- "%s", misc->name);
+ misc->this_device = device_create(misc_class, misc->parent, dev,
+ misc, "%s", misc->name);
if (IS_ERR(misc->this_device)) {
err = PTR_ERR(misc->this_device);
goto out;
@@ -264,6 +263,15 @@ int misc_deregister(struct miscdevice *misc)
EXPORT_SYMBOL(misc_register);
EXPORT_SYMBOL(misc_deregister);
+static char *misc_nodename(struct device *dev)
+{
+ struct miscdevice *c = dev_get_drvdata(dev);
+
+ if (c->devnode)
+ return kstrdup(c->devnode, GFP_KERNEL);
+ return NULL;
+}
+
static int __init misc_init(void)
{
int err;
@@ -279,6 +287,7 @@ static int __init misc_init(void)
err = -EIO;
if (register_chrdev(MISC_MAJOR,"misc",&misc_fops))
goto fail_printk;
+ misc_class->nodename = misc_nodename;
return 0;
fail_printk:
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index c84c34fb123..432655bcb04 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -114,8 +114,7 @@ static ssize_t pp_read (struct file * file, char __user * buf, size_t count,
if (!(pp->flags & PP_CLAIMED)) {
/* Don't have the port claimed */
- printk (KERN_DEBUG CHRDEV "%x: claim the port first\n",
- minor);
+ pr_debug(CHRDEV "%x: claim the port first\n", minor);
return -EINVAL;
}
@@ -198,8 +197,7 @@ static ssize_t pp_write (struct file * file, const char __user * buf,
if (!(pp->flags & PP_CLAIMED)) {
/* Don't have the port claimed */
- printk (KERN_DEBUG CHRDEV "%x: claim the port first\n",
- minor);
+ pr_debug(CHRDEV "%x: claim the port first\n", minor);
return -EINVAL;
}
@@ -313,7 +311,7 @@ static int register_device (int minor, struct pp_struct *pp)
}
pp->pdev = pdev;
- printk (KERN_DEBUG "%s: registered pardevice\n", name);
+ pr_debug("%s: registered pardevice\n", name);
return 0;
}
@@ -343,8 +341,7 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
int ret;
if (pp->flags & PP_CLAIMED) {
- printk (KERN_DEBUG CHRDEV
- "%x: you've already got it!\n", minor);
+ pr_debug(CHRDEV "%x: you've already got it!\n", minor);
return -EINVAL;
}
@@ -379,7 +376,7 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
}
case PPEXCL:
if (pp->pdev) {
- printk (KERN_DEBUG CHRDEV "%x: too late for PPEXCL; "
+ pr_debug(CHRDEV "%x: too late for PPEXCL; "
"already registered\n", minor);
if (pp->flags & PP_EXCL)
/* But it's not really an error. */
@@ -491,8 +488,7 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
/* Everything else requires the port to be claimed, so check
* that now. */
if ((pp->flags & PP_CLAIMED) == 0) {
- printk (KERN_DEBUG CHRDEV "%x: claim the port first\n",
- minor);
+ pr_debug(CHRDEV "%x: claim the port first\n", minor);
return -EINVAL;
}
@@ -624,8 +620,7 @@ static int pp_do_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
return 0;
default:
- printk (KERN_DEBUG CHRDEV "%x: What? (cmd=0x%x)\n", minor,
- cmd);
+ pr_debug(CHRDEV "%x: What? (cmd=0x%x)\n", minor, cmd);
return -EINVAL;
}
@@ -698,9 +693,8 @@ static int pp_release (struct inode * inode, struct file * file)
}
if (compat_negot) {
parport_negotiate (pp->pdev->port, IEEE1284_MODE_COMPAT);
- printk (KERN_DEBUG CHRDEV
- "%x: negotiated back to compatibility mode because "
- "user-space forgot\n", minor);
+ pr_debug(CHRDEV "%x: negotiated back to compatibility "
+ "mode because user-space forgot\n", minor);
}
if (pp->flags & PP_CLAIMED) {
@@ -713,7 +707,7 @@ static int pp_release (struct inode * inode, struct file * file)
info->phase = pp->saved_state.phase;
parport_release (pp->pdev);
if (compat_negot != 1) {
- printk (KERN_DEBUG CHRDEV "%x: released pardevice "
+ pr_debug(CHRDEV "%x: released pardevice "
"because user-space forgot\n", minor);
}
}
@@ -723,8 +717,7 @@ static int pp_release (struct inode * inode, struct file * file)
parport_unregister_device (pp->pdev);
kfree (name);
pp->pdev = NULL;
- printk (KERN_DEBUG CHRDEV "%x: unregistered pardevice\n",
- minor);
+ pr_debug(CHRDEV "%x: unregistered pardevice\n", minor);
}
kfree (pp);
diff --git a/drivers/char/ps3flash.c b/drivers/char/ps3flash.c
index afbe45676d7..f424d394a28 100644
--- a/drivers/char/ps3flash.c
+++ b/drivers/char/ps3flash.c
@@ -33,48 +33,64 @@
struct ps3flash_private {
struct mutex mutex; /* Bounce buffer mutex */
+ u64 chunk_sectors;
+ int tag; /* Start sector of buffer, -1 if invalid */
+ bool dirty;
};
static struct ps3_storage_device *ps3flash_dev;
-static ssize_t ps3flash_read_write_sectors(struct ps3_storage_device *dev,
- u64 lpar, u64 start_sector,
- u64 sectors, int write)
+static int ps3flash_read_write_sectors(struct ps3_storage_device *dev,
+ u64 start_sector, int write)
{
- u64 res = ps3stor_read_write_sectors(dev, lpar, start_sector, sectors,
+ struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
+ u64 res = ps3stor_read_write_sectors(dev, dev->bounce_lpar,
+ start_sector, priv->chunk_sectors,
write);
if (res) {
dev_err(&dev->sbd.core, "%s:%u: %s failed 0x%llx\n", __func__,
__LINE__, write ? "write" : "read", res);
return -EIO;
}
- return sectors;
+ return 0;
}
-static ssize_t ps3flash_read_sectors(struct ps3_storage_device *dev,
- u64 start_sector, u64 sectors,
- unsigned int sector_offset)
+static int ps3flash_writeback(struct ps3_storage_device *dev)
{
- u64 max_sectors, lpar;
+ struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
+ int res;
- max_sectors = dev->bounce_size / dev->blk_size;
- if (sectors > max_sectors) {
- dev_dbg(&dev->sbd.core, "%s:%u Limiting sectors to %llu\n",
- __func__, __LINE__, max_sectors);
- sectors = max_sectors;
- }
+ if (!priv->dirty || priv->tag < 0)
+ return 0;
- lpar = dev->bounce_lpar + sector_offset * dev->blk_size;
- return ps3flash_read_write_sectors(dev, lpar, start_sector, sectors,
- 0);
+ res = ps3flash_read_write_sectors(dev, priv->tag, 1);
+ if (res)
+ return res;
+
+ priv->dirty = false;
+ return 0;
}
-static ssize_t ps3flash_write_chunk(struct ps3_storage_device *dev,
- u64 start_sector)
+static int ps3flash_fetch(struct ps3_storage_device *dev, u64 start_sector)
{
- u64 sectors = dev->bounce_size / dev->blk_size;
- return ps3flash_read_write_sectors(dev, dev->bounce_lpar, start_sector,
- sectors, 1);
+ struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
+ int res;
+
+ if (start_sector == priv->tag)
+ return 0;
+
+ res = ps3flash_writeback(dev);
+ if (res)
+ return res;
+
+ priv->tag = -1;
+
+ res = ps3flash_read_write_sectors(dev, start_sector, 0);
+ if (res)
+ return res;
+
+ priv->tag = start_sector;
+ return 0;
}
static loff_t ps3flash_llseek(struct file *file, loff_t offset, int origin)
@@ -104,18 +120,19 @@ out:
return res;
}
-static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count,
- loff_t *pos)
+static ssize_t ps3flash_read(char __user *userbuf, void *kernelbuf,
+ size_t count, loff_t *pos)
{
struct ps3_storage_device *dev = ps3flash_dev;
- struct ps3flash_private *priv = dev->sbd.core.driver_data;
- u64 size, start_sector, end_sector, offset;
- ssize_t sectors_read;
+ struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
+ u64 size, sector, offset;
+ int res;
size_t remaining, n;
+ const void *src;
dev_dbg(&dev->sbd.core,
- "%s:%u: Reading %zu bytes at position %lld to user 0x%p\n",
- __func__, __LINE__, count, *pos, buf);
+ "%s:%u: Reading %zu bytes at position %lld to U0x%p/K0x%p\n",
+ __func__, __LINE__, count, *pos, userbuf, kernelbuf);
size = dev->regions[dev->region_idx].size*dev->blk_size;
if (*pos >= size || !count)
@@ -128,61 +145,63 @@ static ssize_t ps3flash_read(struct file *file, char __user *buf, size_t count,
count = size - *pos;
}
- start_sector = *pos / dev->blk_size;
- offset = *pos % dev->blk_size;
- end_sector = DIV_ROUND_UP(*pos + count, dev->blk_size);
+ sector = *pos / dev->bounce_size * priv->chunk_sectors;
+ offset = *pos % dev->bounce_size;
remaining = count;
do {
+ n = min_t(u64, remaining, dev->bounce_size - offset);
+ src = dev->bounce_buf + offset;
+
mutex_lock(&priv->mutex);
- sectors_read = ps3flash_read_sectors(dev, start_sector,
- end_sector-start_sector,
- 0);
- if (sectors_read < 0) {
- mutex_unlock(&priv->mutex);
+ res = ps3flash_fetch(dev, sector);
+ if (res)
goto fail;
- }
- n = min_t(u64, remaining, sectors_read*dev->blk_size-offset);
dev_dbg(&dev->sbd.core,
- "%s:%u: copy %lu bytes from 0x%p to user 0x%p\n",
- __func__, __LINE__, n, dev->bounce_buf+offset, buf);
- if (copy_to_user(buf, dev->bounce_buf+offset, n)) {
- mutex_unlock(&priv->mutex);
- sectors_read = -EFAULT;
- goto fail;
+ "%s:%u: copy %lu bytes from 0x%p to U0x%p/K0x%p\n",
+ __func__, __LINE__, n, src, userbuf, kernelbuf);
+ if (userbuf) {
+ if (copy_to_user(userbuf, src, n)) {
+ res = -EFAULT;
+ goto fail;
+ }
+ userbuf += n;
+ }
+ if (kernelbuf) {
+ memcpy(kernelbuf, src, n);
+ kernelbuf += n;
}
mutex_unlock(&priv->mutex);
*pos += n;
- buf += n;
remaining -= n;
- start_sector += sectors_read;
+ sector += priv->chunk_sectors;
offset = 0;
} while (remaining > 0);
return count;
fail:
- return sectors_read;
+ mutex_unlock(&priv->mutex);
+ return res;
}
-static ssize_t ps3flash_write(struct file *file, const char __user *buf,
- size_t count, loff_t *pos)
+static ssize_t ps3flash_write(const char __user *userbuf,
+ const void *kernelbuf, size_t count, loff_t *pos)
{
struct ps3_storage_device *dev = ps3flash_dev;
- struct ps3flash_private *priv = dev->sbd.core.driver_data;
- u64 size, chunk_sectors, start_write_sector, end_write_sector,
- end_read_sector, start_read_sector, head, tail, offset;
- ssize_t res;
+ struct ps3flash_private *priv = ps3_system_bus_get_drvdata(&dev->sbd);
+ u64 size, sector, offset;
+ int res = 0;
size_t remaining, n;
- unsigned int sec_off;
+ void *dst;
dev_dbg(&dev->sbd.core,
- "%s:%u: Writing %zu bytes at position %lld from user 0x%p\n",
- __func__, __LINE__, count, *pos, buf);
+ "%s:%u: Writing %zu bytes at position %lld from U0x%p/K0x%p\n",
+ __func__, __LINE__, count, *pos, userbuf, kernelbuf);
size = dev->regions[dev->region_idx].size*dev->blk_size;
if (*pos >= size || !count)
@@ -195,89 +214,46 @@ static ssize_t ps3flash_write(struct file *file, const char __user *buf,
count = size - *pos;
}
- chunk_sectors = dev->bounce_size / dev->blk_size;
-
- start_write_sector = *pos / dev->bounce_size * chunk_sectors;
+ sector = *pos / dev->bounce_size * priv->chunk_sectors;
offset = *pos % dev->bounce_size;
- end_write_sector = DIV_ROUND_UP(*pos + count, dev->bounce_size) *
- chunk_sectors;
-
- end_read_sector = DIV_ROUND_UP(*pos, dev->blk_size);
- start_read_sector = (*pos + count) / dev->blk_size;
-
- /*
- * As we have to write in 256 KiB chunks, while we can read in blk_size
- * (usually 512 bytes) chunks, we perform the following steps:
- * 1. Read from start_write_sector to end_read_sector ("head")
- * 2. Read from start_read_sector to end_write_sector ("tail")
- * 3. Copy data to buffer
- * 4. Write from start_write_sector to end_write_sector
- * All of this is complicated by using only one 256 KiB bounce buffer.
- */
-
- head = end_read_sector - start_write_sector;
- tail = end_write_sector - start_read_sector;
remaining = count;
do {
+ n = min_t(u64, remaining, dev->bounce_size - offset);
+ dst = dev->bounce_buf + offset;
+
mutex_lock(&priv->mutex);
- if (end_read_sector >= start_read_sector) {
- /* Merge head and tail */
- dev_dbg(&dev->sbd.core,
- "Merged head and tail: %llu sectors at %llu\n",
- chunk_sectors, start_write_sector);
- res = ps3flash_read_sectors(dev, start_write_sector,
- chunk_sectors, 0);
- if (res < 0)
+ if (n != dev->bounce_size)
+ res = ps3flash_fetch(dev, sector);
+ else if (sector != priv->tag)
+ res = ps3flash_writeback(dev);
+ if (res)
+ goto fail;
+
+ dev_dbg(&dev->sbd.core,
+ "%s:%u: copy %lu bytes from U0x%p/K0x%p to 0x%p\n",
+ __func__, __LINE__, n, userbuf, kernelbuf, dst);
+ if (userbuf) {
+ if (copy_from_user(dst, userbuf, n)) {
+ res = -EFAULT;
goto fail;
- } else {
- if (head) {
- /* Read head */
- dev_dbg(&dev->sbd.core,
- "head: %llu sectors at %llu\n", head,
- start_write_sector);
- res = ps3flash_read_sectors(dev,
- start_write_sector,
- head, 0);
- if (res < 0)
- goto fail;
- }
- if (start_read_sector <
- start_write_sector+chunk_sectors) {
- /* Read tail */
- dev_dbg(&dev->sbd.core,
- "tail: %llu sectors at %llu\n", tail,
- start_read_sector);
- sec_off = start_read_sector-start_write_sector;
- res = ps3flash_read_sectors(dev,
- start_read_sector,
- tail, sec_off);
- if (res < 0)
- goto fail;
}
+ userbuf += n;
}
-
- n = min_t(u64, remaining, dev->bounce_size-offset);
- dev_dbg(&dev->sbd.core,
- "%s:%u: copy %lu bytes from user 0x%p to 0x%p\n",
- __func__, __LINE__, n, buf, dev->bounce_buf+offset);
- if (copy_from_user(dev->bounce_buf+offset, buf, n)) {
- res = -EFAULT;
- goto fail;
+ if (kernelbuf) {
+ memcpy(dst, kernelbuf, n);
+ kernelbuf += n;
}
- res = ps3flash_write_chunk(dev, start_write_sector);
- if (res < 0)
- goto fail;
+ priv->tag = sector;
+ priv->dirty = true;
mutex_unlock(&priv->mutex);
*pos += n;
- buf += n;
remaining -= n;
- start_write_sector += chunk_sectors;
- head = 0;
+ sector += priv->chunk_sectors;
offset = 0;
} while (remaining > 0);
@@ -288,6 +264,51 @@ fail:
return res;
}
+static ssize_t ps3flash_user_read(struct file *file, char __user *buf,
+ size_t count, loff_t *pos)
+{
+ return ps3flash_read(buf, NULL, count, pos);
+}
+
+static ssize_t ps3flash_user_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ return ps3flash_write(buf, NULL, count, pos);
+}
+
+static ssize_t ps3flash_kernel_read(void *buf, size_t count, loff_t pos)
+{
+ return ps3flash_read(NULL, buf, count, &pos);
+}
+
+static ssize_t ps3flash_kernel_write(const void *buf, size_t count,
+ loff_t pos)
+{
+ ssize_t res;
+ int wb;
+
+ res = ps3flash_write(NULL, buf, count, &pos);
+ if (res < 0)
+ return res;
+
+ /* Make kernel writes synchronous */
+ wb = ps3flash_writeback(ps3flash_dev);
+ if (wb)
+ return wb;
+
+ return res;
+}
+
+static int ps3flash_flush(struct file *file, fl_owner_t id)
+{
+ return ps3flash_writeback(ps3flash_dev);
+}
+
+static int ps3flash_fsync(struct file *file, struct dentry *dentry,
+ int datasync)
+{
+ return ps3flash_writeback(ps3flash_dev);
+}
static irqreturn_t ps3flash_interrupt(int irq, void *data)
{
@@ -312,12 +333,18 @@ static irqreturn_t ps3flash_interrupt(int irq, void *data)
return IRQ_HANDLED;
}
-
static const struct file_operations ps3flash_fops = {
.owner = THIS_MODULE,
.llseek = ps3flash_llseek,
- .read = ps3flash_read,
- .write = ps3flash_write,
+ .read = ps3flash_user_read,
+ .write = ps3flash_user_write,
+ .flush = ps3flash_flush,
+ .fsync = ps3flash_fsync,
+};
+
+static const struct ps3_os_area_flash_ops ps3flash_kernel_ops = {
+ .read = ps3flash_kernel_read,
+ .write = ps3flash_kernel_write,
};
static struct miscdevice ps3flash_misc = {
@@ -366,11 +393,13 @@ static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev)
goto fail;
}
- dev->sbd.core.driver_data = priv;
+ ps3_system_bus_set_drvdata(&dev->sbd, priv);
mutex_init(&priv->mutex);
+ priv->tag = -1;
dev->bounce_size = ps3flash_bounce_buffer.size;
dev->bounce_buf = ps3flash_bounce_buffer.address;
+ priv->chunk_sectors = dev->bounce_size / dev->blk_size;
error = ps3stor_setup(dev, ps3flash_interrupt);
if (error)
@@ -386,13 +415,15 @@ static int __devinit ps3flash_probe(struct ps3_system_bus_device *_dev)
dev_info(&dev->sbd.core, "%s:%u: registered misc device %d\n",
__func__, __LINE__, ps3flash_misc.minor);
+
+ ps3_os_area_flash_register(&ps3flash_kernel_ops);
return 0;
fail_teardown:
ps3stor_teardown(dev);
fail_free_priv:
kfree(priv);
- dev->sbd.core.driver_data = NULL;
+ ps3_system_bus_set_drvdata(&dev->sbd, NULL);
fail:
ps3flash_dev = NULL;
return error;
@@ -402,10 +433,11 @@ static int ps3flash_remove(struct ps3_system_bus_device *_dev)
{
struct ps3_storage_device *dev = to_ps3_storage_device(&_dev->core);
+ ps3_os_area_flash_register(NULL);
misc_deregister(&ps3flash_misc);
ps3stor_teardown(dev);
- kfree(dev->sbd.core.driver_data);
- dev->sbd.core.driver_data = NULL;
+ kfree(ps3_system_bus_get_drvdata(&dev->sbd));
+ ps3_system_bus_set_drvdata(&dev->sbd, NULL);
ps3flash_dev = NULL;
return 0;
}
diff --git a/drivers/char/pty.c b/drivers/char/pty.c
index 5acd29e6e04..daebe1ba43d 100644
--- a/drivers/char/pty.c
+++ b/drivers/char/pty.c
@@ -95,23 +95,34 @@ static void pty_unthrottle(struct tty_struct *tty)
* a count.
*
* FIXME: Our pty_write method is called with our ldisc lock held but
- * not our partners. We can't just take the other one blindly without
- * risking deadlocks.
+ * not our partners. We can't just wait on the other one blindly without
+ * risking deadlocks. At some point when everything has settled down we need
+ * to look into making pty_write at least able to sleep over an ldisc change.
+ *
+ * The return on no ldisc is a bit counter intuitive but the logic works
+ * like this. During an ldisc change the other end will flush its buffers. We
+ * thus return the full length which is identical to the case where we had
+ * proper locking and happened to queue the bytes just before the flush during
+ * the ldisc change.
*/
static int pty_write(struct tty_struct *tty, const unsigned char *buf,
int count)
{
struct tty_struct *to = tty->link;
- int c;
+ struct tty_ldisc *ld;
+ int c = count;
if (!to || tty->stopped)
return 0;
-
- c = to->receive_room;
- if (c > count)
- c = count;
- to->ldisc->ops->receive_buf(to, buf, NULL, c);
-
+ ld = tty_ldisc_ref(to);
+
+ if (ld) {
+ c = to->receive_room;
+ if (c > count)
+ c = count;
+ ld->ops->receive_buf(to, buf, NULL, c);
+ tty_ldisc_deref(ld);
+ }
return c;
}
@@ -145,14 +156,23 @@ static int pty_write_room(struct tty_struct *tty)
static int pty_chars_in_buffer(struct tty_struct *tty)
{
struct tty_struct *to = tty->link;
- int count;
+ struct tty_ldisc *ld;
+ int count = 0;
/* We should get the line discipline lock for "tty->link" */
- if (!to || !to->ldisc->ops->chars_in_buffer)
+ if (!to)
+ return 0;
+ /* We cannot take a sleeping reference here without deadlocking with
+ an ldisc change - but it doesn't really matter */
+ ld = tty_ldisc_ref(to);
+ if (ld == NULL)
return 0;
/* The ldisc must report 0 if no characters available to be read */
- count = to->ldisc->ops->chars_in_buffer(to);
+ if (ld->ops->chars_in_buffer)
+ count = ld->ops->chars_in_buffer(to);
+
+ tty_ldisc_deref(ld);
if (tty->driver->subtype == PTY_TYPE_SLAVE)
return count;
@@ -182,12 +202,19 @@ static void pty_flush_buffer(struct tty_struct *tty)
{
struct tty_struct *to = tty->link;
unsigned long flags;
+ struct tty_ldisc *ld;
if (!to)
return;
+ ld = tty_ldisc_ref(to);
+
+ /* The other end is changing discipline */
+ if (!ld)
+ return;
- if (to->ldisc->ops->flush_buffer)
+ if (ld->ops->flush_buffer)
to->ldisc->ops->flush_buffer(to);
+ tty_ldisc_deref(ld);
if (to->packet) {
spin_lock_irqsave(&tty->ctrl_lock, flags);
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index db32f0e4c7d..05f9d18b936 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -261,6 +261,11 @@ static const struct file_operations raw_ctl_fops = {
static struct cdev raw_cdev;
+static char *raw_nodename(struct device *dev)
+{
+ return kasprintf(GFP_KERNEL, "raw/%s", dev_name(dev));
+}
+
static int __init raw_init(void)
{
dev_t dev = MKDEV(RAW_MAJOR, 0);
@@ -284,6 +289,7 @@ static int __init raw_init(void)
ret = PTR_ERR(raw_class);
goto error_region;
}
+ raw_class->nodename = raw_nodename;
device_create(raw_class, NULL, MKDEV(RAW_MAJOR, 0), NULL, "rawctl");
return 0;
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 39a05b5fa9c..0db35857e4d 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -121,20 +121,17 @@ static struct sysrq_key_op sysrq_unraw_op = {
#define sysrq_unraw_op (*(struct sysrq_key_op *)0)
#endif /* CONFIG_VT */
-#ifdef CONFIG_KEXEC
-static void sysrq_handle_crashdump(int key, struct tty_struct *tty)
+static void sysrq_handle_crash(int key, struct tty_struct *tty)
{
- crash_kexec(get_irq_regs());
+ char *killer = NULL;
+ *killer = 1;
}
static struct sysrq_key_op sysrq_crashdump_op = {
- .handler = sysrq_handle_crashdump,
- .help_msg = "Crashdump",
- .action_msg = "Trigger a crashdump",
+ .handler = sysrq_handle_crash,
+ .help_msg = "Crash",
+ .action_msg = "Trigger a crash",
.enable_mask = SYSRQ_ENABLE_DUMP,
};
-#else
-#define sysrq_crashdump_op (*(struct sysrq_key_op *)0)
-#endif
static void sysrq_handle_reboot(int key, struct tty_struct *tty)
{
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 939e198d767..a3afa0c387c 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -1263,7 +1263,9 @@ static int tty_reopen(struct tty_struct *tty)
tty->count++;
tty->driver = driver; /* N.B. why do this every time?? */
+ mutex_lock(&tty->ldisc_mutex);
WARN_ON(!test_bit(TTY_LDISC, &tty->flags));
+ mutex_unlock(&tty->ldisc_mutex);
return 0;
}
diff --git a/drivers/char/tty_ioctl.c b/drivers/char/tty_ioctl.c
index 8116bb1c8f8..b24f6c6a1ea 100644
--- a/drivers/char/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -947,7 +947,6 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
void __user *p = (void __user *)arg;
int ret = 0;
struct ktermios kterm;
- struct termiox ktermx;
if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
tty->driver->subtype == PTY_TYPE_MASTER)
@@ -1049,7 +1048,8 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
return ret;
#endif
#ifdef TCGETX
- case TCGETX:
+ case TCGETX: {
+ struct termiox ktermx;
if (real_tty->termiox == NULL)
return -EINVAL;
mutex_lock(&real_tty->termios_mutex);
@@ -1058,6 +1058,7 @@ int tty_mode_ioctl(struct tty_struct *tty, struct file *file,
if (copy_to_user(p, &ktermx, sizeof(struct termiox)))
ret = -EFAULT;
return ret;
+ }
case TCSETX:
return set_termiox(real_tty, p, 0);
case TCSETXW:
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c
index 39c8f86dedd..a19e935847b 100644
--- a/drivers/char/tty_ldisc.c
+++ b/drivers/char/tty_ldisc.c
@@ -148,8 +148,10 @@ static struct tty_ldisc *tty_ldisc_try_get(int disc)
}
}
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
- if (err)
+ if (err) {
+ kfree(ld);
return ERR_PTR(err);
+ }
return ld;
}
@@ -205,6 +207,7 @@ static void tty_ldisc_put(struct tty_ldisc *ld)
ldo->refcount--;
module_put(ldo->owner);
spin_unlock_irqrestore(&tty_ldisc_lock, flags);
+ WARN_ON(ld->refcount);
kfree(ld);
}
@@ -262,7 +265,7 @@ const struct file_operations tty_ldiscs_proc_fops = {
* @ld: line discipline
*
* Install an instance of a line discipline into a tty structure. The
- * ldisc must have a reference count above zero to ensure it remains/
+ * ldisc must have a reference count above zero to ensure it remains.
* The tty instance refcount starts at zero.
*
* Locking:
@@ -791,6 +794,8 @@ void tty_ldisc_hangup(struct tty_struct *tty)
/* Avoid racing set_ldisc */
mutex_lock(&tty->ldisc_mutex);
/* Switch back to N_TTY */
+ tty_ldisc_halt(tty);
+ tty_ldisc_wait_idle(tty);
tty_ldisc_reinit(tty);
/* At this point we have a closed ldisc and we want to
reopen it. We could defer this to the next open but
diff --git a/drivers/char/viotape.c b/drivers/char/viotape.c
index ffc9254f7e0..042c8149a6d 100644
--- a/drivers/char/viotape.c
+++ b/drivers/char/viotape.c
@@ -867,7 +867,7 @@ static int viotape_probe(struct vio_dev *vdev, const struct vio_device_id *id)
int j;
struct device_node *node = vdev->dev.archdata.of_node;
- if (i > VIOTAPE_MAX_TAPE)
+ if (i >= VIOTAPE_MAX_TAPE)
return -ENODEV;
if (!node)
return -ENODEV;
diff --git a/drivers/char/vt.c b/drivers/char/vt.c
index c796a86ab7f..d9113b4c76e 100644
--- a/drivers/char/vt.c
+++ b/drivers/char/vt.c
@@ -171,8 +171,9 @@ int do_poke_blanked_console;
int console_blanked;
static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */
-static int blankinterval = 10*60*HZ;
static int vesa_off_interval;
+static int blankinterval = 10*60;
+core_param(consoleblank, blankinterval, int, 0444);
static DECLARE_WORK(console_work, console_callback);
@@ -1485,7 +1486,7 @@ static void setterm_command(struct vc_data *vc)
update_attr(vc);
break;
case 9: /* set blanking interval */
- blankinterval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60 * HZ;
+ blankinterval = ((vc->vc_par[1] < 60) ? vc->vc_par[1] : 60) * 60;
poke_blanked_console();
break;
case 10: /* set bell frequency in Hz */
@@ -2871,7 +2872,7 @@ static int __init con_init(void)
if (blankinterval) {
blank_state = blank_normal_wait;
- mod_timer(&console_timer, jiffies + blankinterval);
+ mod_timer(&console_timer, jiffies + (blankinterval * HZ));
}
for (currcons = 0; currcons < MIN_NR_CONSOLES; currcons++) {
@@ -3677,7 +3678,7 @@ void do_unblank_screen(int leaving_gfx)
return; /* but leave console_blanked != 0 */
if (blankinterval) {
- mod_timer(&console_timer, jiffies + blankinterval);
+ mod_timer(&console_timer, jiffies + (blankinterval * HZ));
blank_state = blank_normal_wait;
}
@@ -3711,7 +3712,7 @@ void unblank_screen(void)
static void blank_screen_t(unsigned long dummy)
{
if (unlikely(!keventd_up())) {
- mod_timer(&console_timer, jiffies + blankinterval);
+ mod_timer(&console_timer, jiffies + (blankinterval * HZ));
return;
}
blank_timer_expired = 1;
@@ -3741,7 +3742,7 @@ void poke_blanked_console(void)
if (console_blanked)
unblank_screen();
else if (blankinterval) {
- mod_timer(&console_timer, jiffies + blankinterval);
+ mod_timer(&console_timer, jiffies + (blankinterval * HZ));
blank_state = blank_normal_wait;
}
}