diff options
Diffstat (limited to 'drivers/tty/hvc/hvcs.c')
-rw-r--r-- | drivers/tty/hvc/hvcs.c | 74 |
1 files changed, 43 insertions, 31 deletions
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 { | |||
309 | 309 | ||
310 | static LIST_HEAD(hvcs_structs); | 310 | static LIST_HEAD(hvcs_structs); |
311 | static DEFINE_SPINLOCK(hvcs_structs_lock); | 311 | static DEFINE_SPINLOCK(hvcs_structs_lock); |
312 | static DEFINE_MUTEX(hvcs_init_mutex); | ||
312 | 313 | ||
313 | static void hvcs_unthrottle(struct tty_struct *tty); | 314 | static void hvcs_unthrottle(struct tty_struct *tty); |
314 | static void hvcs_throttle(struct tty_struct *tty); | 315 | static void hvcs_throttle(struct tty_struct *tty); |
@@ -340,6 +341,7 @@ static int __devinit hvcs_probe(struct vio_dev *dev, | |||
340 | static int __devexit hvcs_remove(struct vio_dev *dev); | 341 | static int __devexit hvcs_remove(struct vio_dev *dev); |
341 | static int __init hvcs_module_init(void); | 342 | static int __init hvcs_module_init(void); |
342 | static void __exit hvcs_module_exit(void); | 343 | static void __exit hvcs_module_exit(void); |
344 | static int __devinit hvcs_initialize(void); | ||
343 | 345 | ||
344 | #define HVCS_SCHED_READ 0x00000001 | 346 | #define HVCS_SCHED_READ 0x00000001 |
345 | #define HVCS_QUICK_READ 0x00000002 | 347 | #define HVCS_QUICK_READ 0x00000002 |
@@ -762,7 +764,7 @@ static int __devinit hvcs_probe( | |||
762 | const struct vio_device_id *id) | 764 | const struct vio_device_id *id) |
763 | { | 765 | { |
764 | struct hvcs_struct *hvcsd; | 766 | struct hvcs_struct *hvcsd; |
765 | int index; | 767 | int index, rc; |
766 | int retval; | 768 | int retval; |
767 | 769 | ||
768 | if (!dev || !id) { | 770 | if (!dev || !id) { |
@@ -770,6 +772,13 @@ static int __devinit hvcs_probe( | |||
770 | return -EPERM; | 772 | return -EPERM; |
771 | } | 773 | } |
772 | 774 | ||
775 | /* Make sure we are properly initialized */ | ||
776 | rc = hvcs_initialize(); | ||
777 | if (rc) { | ||
778 | pr_err("HVCS: Failed to initialize core driver.\n"); | ||
779 | return rc; | ||
780 | } | ||
781 | |||
773 | /* early to avoid cleanup on failure */ | 782 | /* early to avoid cleanup on failure */ |
774 | index = hvcs_get_index(); | 783 | index = hvcs_get_index(); |
775 | if (index < 0) { | 784 | if (index < 0) { |
@@ -1464,12 +1473,15 @@ static void hvcs_free_index_list(void) | |||
1464 | hvcs_index_count = 0; | 1473 | hvcs_index_count = 0; |
1465 | } | 1474 | } |
1466 | 1475 | ||
1467 | static int __init hvcs_module_init(void) | 1476 | static int __devinit hvcs_initialize(void) |
1468 | { | 1477 | { |
1469 | int rc; | 1478 | int rc, num_ttys_to_alloc; |
1470 | int num_ttys_to_alloc; | ||
1471 | 1479 | ||
1472 | printk(KERN_INFO "Initializing %s\n", hvcs_driver_string); | 1480 | mutex_lock(&hvcs_init_mutex); |
1481 | if (hvcs_task) { | ||
1482 | mutex_unlock(&hvcs_init_mutex); | ||
1483 | return 0; | ||
1484 | } | ||
1473 | 1485 | ||
1474 | /* Has the user specified an overload with an insmod param? */ | 1486 | /* Has the user specified an overload with an insmod param? */ |
1475 | if (hvcs_parm_num_devs <= 0 || | 1487 | if (hvcs_parm_num_devs <= 0 || |
@@ -1528,35 +1540,13 @@ static int __init hvcs_module_init(void) | |||
1528 | 1540 | ||
1529 | hvcs_task = kthread_run(khvcsd, NULL, "khvcsd"); | 1541 | hvcs_task = kthread_run(khvcsd, NULL, "khvcsd"); |
1530 | if (IS_ERR(hvcs_task)) { | 1542 | if (IS_ERR(hvcs_task)) { |
1531 | printk(KERN_ERR "HVCS: khvcsd creation failed. Driver not loaded.\n"); | 1543 | printk(KERN_ERR "HVCS: khvcsd creation failed.\n"); |
1532 | rc = -EIO; | 1544 | rc = -EIO; |
1533 | goto kthread_fail; | 1545 | goto kthread_fail; |
1534 | } | 1546 | } |
1535 | 1547 | mutex_unlock(&hvcs_init_mutex); | |
1536 | rc = vio_register_driver(&hvcs_vio_driver); | ||
1537 | if (rc) { | ||
1538 | printk(KERN_ERR "HVCS: can't register vio driver\n"); | ||
1539 | goto vio_fail; | ||
1540 | } | ||
1541 | |||
1542 | /* | ||
1543 | * This needs to be done AFTER the vio_register_driver() call or else | ||
1544 | * the kobjects won't be initialized properly. | ||
1545 | */ | ||
1546 | rc = driver_create_file(&(hvcs_vio_driver.driver), &driver_attr_rescan); | ||
1547 | if (rc) { | ||
1548 | printk(KERN_ERR "HVCS: sysfs attr create failed\n"); | ||
1549 | goto attr_fail; | ||
1550 | } | ||
1551 | |||
1552 | printk(KERN_INFO "HVCS: driver module inserted.\n"); | ||
1553 | |||
1554 | return 0; | 1548 | return 0; |
1555 | 1549 | ||
1556 | attr_fail: | ||
1557 | vio_unregister_driver(&hvcs_vio_driver); | ||
1558 | vio_fail: | ||
1559 | kthread_stop(hvcs_task); | ||
1560 | kthread_fail: | 1550 | kthread_fail: |
1561 | kfree(hvcs_pi_buff); | 1551 | kfree(hvcs_pi_buff); |
1562 | buff_alloc_fail: | 1552 | buff_alloc_fail: |
@@ -1566,15 +1556,39 @@ register_fail: | |||
1566 | index_fail: | 1556 | index_fail: |
1567 | put_tty_driver(hvcs_tty_driver); | 1557 | put_tty_driver(hvcs_tty_driver); |
1568 | hvcs_tty_driver = NULL; | 1558 | hvcs_tty_driver = NULL; |
1559 | mutex_unlock(&hvcs_init_mutex); | ||
1569 | return rc; | 1560 | return rc; |
1570 | } | 1561 | } |
1571 | 1562 | ||
1563 | static int __init hvcs_module_init(void) | ||
1564 | { | ||
1565 | int rc = vio_register_driver(&hvcs_vio_driver); | ||
1566 | if (rc) { | ||
1567 | printk(KERN_ERR "HVCS: can't register vio driver\n"); | ||
1568 | return rc; | ||
1569 | } | ||
1570 | |||
1571 | pr_info("HVCS: Driver registered.\n"); | ||
1572 | |||
1573 | /* This needs to be done AFTER the vio_register_driver() call or else | ||
1574 | * the kobjects won't be initialized properly. | ||
1575 | */ | ||
1576 | rc = driver_create_file(&(hvcs_vio_driver.driver), &driver_attr_rescan); | ||
1577 | if (rc) | ||
1578 | pr_warning(KERN_ERR "HVCS: Failed to create rescan file (err %d)\n", rc); | ||
1579 | |||
1580 | return 0; | ||
1581 | } | ||
1582 | |||
1572 | static void __exit hvcs_module_exit(void) | 1583 | static void __exit hvcs_module_exit(void) |
1573 | { | 1584 | { |
1574 | /* | 1585 | /* |
1575 | * This driver receives hvcs_remove callbacks for each device upon | 1586 | * This driver receives hvcs_remove callbacks for each device upon |
1576 | * module removal. | 1587 | * module removal. |
1577 | */ | 1588 | */ |
1589 | vio_unregister_driver(&hvcs_vio_driver); | ||
1590 | if (!hvcs_task) | ||
1591 | return; | ||
1578 | 1592 | ||
1579 | /* | 1593 | /* |
1580 | * This synchronous operation will wake the khvcsd kthread if it is | 1594 | * This synchronous operation will wake the khvcsd kthread if it is |
@@ -1589,8 +1603,6 @@ static void __exit hvcs_module_exit(void) | |||
1589 | 1603 | ||
1590 | driver_remove_file(&hvcs_vio_driver.driver, &driver_attr_rescan); | 1604 | driver_remove_file(&hvcs_vio_driver.driver, &driver_attr_rescan); |
1591 | 1605 | ||
1592 | vio_unregister_driver(&hvcs_vio_driver); | ||
1593 | |||
1594 | tty_unregister_driver(hvcs_tty_driver); | 1606 | tty_unregister_driver(hvcs_tty_driver); |
1595 | 1607 | ||
1596 | hvcs_free_index_list(); | 1608 | hvcs_free_index_list(); |