aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/tty
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-03-18 06:31:43 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2011-03-18 06:31:43 -0700
commit0a95d92c0054e74fb79607ac2df958b7bf295706 (patch)
treee2c5f836e799dcfd72904949be47595af91432e7 /drivers/tty
parent08351fc6a75731226e1112fc7254542bd3a2912e (diff)
parent831532035b12a5f7b600515a6f4da0b207b82d6e (diff)
downloadkernel_samsung_smdk4412-0a95d92c0054e74fb79607ac2df958b7bf295706.zip
kernel_samsung_smdk4412-0a95d92c0054e74fb79607ac2df958b7bf295706.tar.gz
kernel_samsung_smdk4412-0a95d92c0054e74fb79607ac2df958b7bf295706.tar.bz2
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc
* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/benh/powerpc: (62 commits) powerpc/85xx: Fix signedness bug in cache-sram powerpc/fsl: 85xx: document cache sram bindings powerpc/fsl: define binding for fsl mpic interrupt controllers powerpc/fsl_msi: Handle msi-available-ranges better drivers/serial/ucc_uart.c: Add of_node_put to avoid memory leak powerpc/85xx: Fix SPE float to integer conversion failure powerpc/85xx: Update sata controller compatible for p1022ds board ATA: Add FSL sata v2 controller support powerpc/mpc8xxx_gpio: simplify searching for 'fsl, qoriq-gpio' compatiable powerpc/8xx: remove obsolete mgsuvd board powerpc/82xx: rename and update mgcoge board support powerpc/83xx: rename and update kmeter1 powerpc/85xx: Workaroudn e500 CPU erratum A005 powerpc/fsl_pci: Add support for FSL PCIe controllers v2.x powerpc/85xx: Fix writing to spin table 'cpu-release-addr' on ppc64e powerpc/pseries: Disable MSI using new interface if possible powerpc: Enable GENERIC_HARDIRQS_NO_DEPRECATED. powerpc: core irq_data conversion. powerpc: sysdev/xilinx_intc irq_data conversion. powerpc: sysdev/uic irq_data conversion. ... Fix up conflicts in arch/powerpc/sysdev/fsl_msi.c (due to getting rid of of_platform_driver in arch/powerpc)
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/hvc/hvcs.c74
-rw-r--r--drivers/tty/serial/ucc_uart.c67
2 files changed, 78 insertions, 63 deletions
diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c
index bedc6c1..7e315b7 100644
--- a/drivers/tty/hvc/hvcs.c
+++ b/drivers/tty/hvc/hvcs.c
@@ -309,6 +309,7 @@ struct hvcs_struct {
static LIST_HEAD(hvcs_structs);
static DEFINE_SPINLOCK(hvcs_structs_lock);
+static DEFINE_MUTEX(hvcs_init_mutex);
static void hvcs_unthrottle(struct tty_struct *tty);
static void hvcs_throttle(struct tty_struct *tty);
@@ -340,6 +341,7 @@ static int __devinit hvcs_probe(struct vio_dev *dev,
static int __devexit hvcs_remove(struct vio_dev *dev);
static int __init hvcs_module_init(void);
static void __exit hvcs_module_exit(void);
+static int __devinit hvcs_initialize(void);
#define HVCS_SCHED_READ 0x00000001
#define HVCS_QUICK_READ 0x00000002
@@ -762,7 +764,7 @@ static int __devinit hvcs_probe(
const struct vio_device_id *id)
{
struct hvcs_struct *hvcsd;
- int index;
+ int index, rc;
int retval;
if (!dev || !id) {
@@ -770,6 +772,13 @@ static int __devinit hvcs_probe(
return -EPERM;
}
+ /* Make sure we are properly initialized */
+ rc = hvcs_initialize();
+ if (rc) {
+ pr_err("HVCS: Failed to initialize core driver.\n");
+ return rc;
+ }
+
/* early to avoid cleanup on failure */
index = hvcs_get_index();
if (index < 0) {
@@ -1464,12 +1473,15 @@ static void hvcs_free_index_list(void)
hvcs_index_count = 0;
}
-static int __init hvcs_module_init(void)
+static int __devinit hvcs_initialize(void)
{
- int rc;
- int num_ttys_to_alloc;
+ int rc, num_ttys_to_alloc;
- printk(KERN_INFO "Initializing %s\n", hvcs_driver_string);
+ mutex_lock(&hvcs_init_mutex);
+ if (hvcs_task) {
+ mutex_unlock(&hvcs_init_mutex);
+ return 0;
+ }
/* Has the user specified an overload with an insmod param? */
if (hvcs_parm_num_devs <= 0 ||
@@ -1528,35 +1540,13 @@ static int __init hvcs_module_init(void)
hvcs_task = kthread_run(khvcsd, NULL, "khvcsd");
if (IS_ERR(hvcs_task)) {
- printk(KERN_ERR "HVCS: khvcsd creation failed. Driver not loaded.\n");
+ printk(KERN_ERR "HVCS: khvcsd creation failed.\n");
rc = -EIO;
goto kthread_fail;
}
-
- rc = vio_register_driver(&hvcs_vio_driver);
- if (rc) {
- printk(KERN_ERR "HVCS: can't register vio driver\n");
- goto vio_fail;
- }
-
- /*
- * This needs to be done AFTER the vio_register_driver() call or else
- * the kobjects won't be initialized properly.
- */
- rc = driver_create_file(&(hvcs_vio_driver.driver), &driver_attr_rescan);
- if (rc) {
- printk(KERN_ERR "HVCS: sysfs attr create failed\n");
- goto attr_fail;
- }
-
- printk(KERN_INFO "HVCS: driver module inserted.\n");
-
+ mutex_unlock(&hvcs_init_mutex);
return 0;
-attr_fail:
- vio_unregister_driver(&hvcs_vio_driver);
-vio_fail:
- kthread_stop(hvcs_task);
kthread_fail:
kfree(hvcs_pi_buff);
buff_alloc_fail:
@@ -1566,15 +1556,39 @@ register_fail:
index_fail:
put_tty_driver(hvcs_tty_driver);
hvcs_tty_driver = NULL;
+ mutex_unlock(&hvcs_init_mutex);
return rc;
}
+static int __init hvcs_module_init(void)
+{
+ int rc = vio_register_driver(&hvcs_vio_driver);
+ if (rc) {
+ printk(KERN_ERR "HVCS: can't register vio driver\n");
+ return rc;
+ }
+
+ pr_info("HVCS: Driver registered.\n");
+
+ /* This needs to be done AFTER the vio_register_driver() call or else
+ * the kobjects won't be initialized properly.
+ */
+ rc = driver_create_file(&(hvcs_vio_driver.driver), &driver_attr_rescan);
+ if (rc)
+ pr_warning(KERN_ERR "HVCS: Failed to create rescan file (err %d)\n", rc);
+
+ return 0;
+}
+
static void __exit hvcs_module_exit(void)
{
/*
* This driver receives hvcs_remove callbacks for each device upon
* module removal.
*/
+ vio_unregister_driver(&hvcs_vio_driver);
+ if (!hvcs_task)
+ return;
/*
* This synchronous operation will wake the khvcsd kthread if it is
@@ -1589,8 +1603,6 @@ static void __exit hvcs_module_exit(void)
driver_remove_file(&hvcs_vio_driver.driver, &driver_attr_rescan);
- vio_unregister_driver(&hvcs_vio_driver);
-
tty_unregister_driver(hvcs_tty_driver);
hvcs_free_index_list();
diff --git a/drivers/tty/serial/ucc_uart.c b/drivers/tty/serial/ucc_uart.c
index ff51dae..c327218 100644
--- a/drivers/tty/serial/ucc_uart.c
+++ b/drivers/tty/serial/ucc_uart.c
@@ -1269,13 +1269,12 @@ static int ucc_uart_probe(struct platform_device *ofdev)
ret = of_address_to_resource(np, 0, &res);
if (ret) {
dev_err(&ofdev->dev, "missing 'reg' property in device tree\n");
- kfree(qe_port);
- return ret;
+ goto out_free;
}
if (!res.start) {
dev_err(&ofdev->dev, "invalid 'reg' property in device tree\n");
- kfree(qe_port);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out_free;
}
qe_port->port.mapbase = res.start;
@@ -1285,17 +1284,17 @@ static int ucc_uart_probe(struct platform_device *ofdev)
if (!iprop) {
iprop = of_get_property(np, "device-id", NULL);
if (!iprop) {
- kfree(qe_port);
dev_err(&ofdev->dev, "UCC is unspecified in "
"device tree\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out_free;
}
}
if ((*iprop < 1) || (*iprop > UCC_MAX_NUM)) {
dev_err(&ofdev->dev, "no support for UCC%u\n", *iprop);
- kfree(qe_port);
- return -ENODEV;
+ ret = -ENODEV;
+ goto out_free;
}
qe_port->ucc_num = *iprop - 1;
@@ -1309,16 +1308,16 @@ static int ucc_uart_probe(struct platform_device *ofdev)
sprop = of_get_property(np, "rx-clock-name", NULL);
if (!sprop) {
dev_err(&ofdev->dev, "missing rx-clock-name in device tree\n");
- kfree(qe_port);
- return -ENODEV;
+ ret = -ENODEV;
+ goto out_free;
}
qe_port->us_info.rx_clock = qe_clock_source(sprop);
if ((qe_port->us_info.rx_clock < QE_BRG1) ||
(qe_port->us_info.rx_clock > QE_BRG16)) {
dev_err(&ofdev->dev, "rx-clock-name must be a BRG for UART\n");
- kfree(qe_port);
- return -ENODEV;
+ ret = -ENODEV;
+ goto out_free;
}
#ifdef LOOPBACK
@@ -1328,39 +1327,39 @@ static int ucc_uart_probe(struct platform_device *ofdev)
sprop = of_get_property(np, "tx-clock-name", NULL);
if (!sprop) {
dev_err(&ofdev->dev, "missing tx-clock-name in device tree\n");
- kfree(qe_port);
- return -ENODEV;
+ ret = -ENODEV;
+ goto out_free;
}
qe_port->us_info.tx_clock = qe_clock_source(sprop);
#endif
if ((qe_port->us_info.tx_clock < QE_BRG1) ||
(qe_port->us_info.tx_clock > QE_BRG16)) {
dev_err(&ofdev->dev, "tx-clock-name must be a BRG for UART\n");
- kfree(qe_port);
- return -ENODEV;
+ ret = -ENODEV;
+ goto out_free;
}
/* Get the port number, numbered 0-3 */
iprop = of_get_property(np, "port-number", NULL);
if (!iprop) {
dev_err(&ofdev->dev, "missing port-number in device tree\n");
- kfree(qe_port);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out_free;
}
qe_port->port.line = *iprop;
if (qe_port->port.line >= UCC_MAX_UART) {
dev_err(&ofdev->dev, "port-number must be 0-%u\n",
UCC_MAX_UART - 1);
- kfree(qe_port);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out_free;
}
qe_port->port.irq = irq_of_parse_and_map(np, 0);
if (qe_port->port.irq == NO_IRQ) {
dev_err(&ofdev->dev, "could not map IRQ for UCC%u\n",
qe_port->ucc_num + 1);
- kfree(qe_port);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out_free;
}
/*
@@ -1372,8 +1371,8 @@ static int ucc_uart_probe(struct platform_device *ofdev)
np = of_find_node_by_type(NULL, "qe");
if (!np) {
dev_err(&ofdev->dev, "could not find 'qe' node\n");
- kfree(qe_port);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out_free;
}
}
@@ -1381,8 +1380,8 @@ static int ucc_uart_probe(struct platform_device *ofdev)
if (!iprop) {
dev_err(&ofdev->dev,
"missing brg-frequency in device tree\n");
- kfree(qe_port);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out_np;
}
if (*iprop)
@@ -1397,16 +1396,16 @@ static int ucc_uart_probe(struct platform_device *ofdev)
if (!iprop) {
dev_err(&ofdev->dev,
"missing QE bus-frequency in device tree\n");
- kfree(qe_port);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out_np;
}
if (*iprop)
qe_port->port.uartclk = *iprop / 2;
else {
dev_err(&ofdev->dev,
"invalid QE bus-frequency in device tree\n");
- kfree(qe_port);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out_np;
}
}
@@ -1444,8 +1443,7 @@ static int ucc_uart_probe(struct platform_device *ofdev)
if (ret) {
dev_err(&ofdev->dev, "could not add /dev/ttyQE%u\n",
qe_port->port.line);
- kfree(qe_port);
- return ret;
+ goto out_np;
}
dev_set_drvdata(&ofdev->dev, qe_port);
@@ -1459,6 +1457,11 @@ static int ucc_uart_probe(struct platform_device *ofdev)
SERIAL_QE_MINOR + qe_port->port.line);
return 0;
+out_np:
+ of_node_put(np);
+out_free:
+ kfree(qe_port);
+ return ret;
}
static int ucc_uart_remove(struct platform_device *ofdev)