summaryrefslogtreecommitdiffstats
path: root/drivers/tty/hvc/hvcs.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/tty/hvc/hvcs.c')
-rw-r--r--drivers/tty/hvc/hvcs.c76
1 files changed, 44 insertions, 32 deletions
diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c
index bedc6c1b6fa..bef238f9ffd 100644
--- a/drivers/tty/hvc/hvcs.c
+++ b/drivers/tty/hvc/hvcs.c
@@ -292,7 +292,7 @@ struct hvcs_struct {
/*
* Any variable below the kref is valid before a tty is connected and
* stays valid after the tty is disconnected. These shouldn't be
- * whacked until the koject refcount reaches zero though some entries
+ * whacked until the kobject refcount reaches zero though some entries
* may be changed via sysfs initiatives.
*/
struct kref kref; /* ref count & hvcs_struct lifetime */
@@ -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();