diff --git a/drivers/tty/hvc/hvcs.c b/drivers/tty/hvc/hvcs.c index bedc6c1b6fa5..7e315b7f8700 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 @@ static int __init hvcs_module_init(void) 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();