|
@@ -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();
|