diff options
Diffstat (limited to 'drivers/char/hvc_console.c')
| -rw-r--r-- | drivers/char/hvc_console.c | 56 |
1 files changed, 40 insertions, 16 deletions
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 83c1151ec7a2..8252f8668538 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c | |||
| @@ -69,6 +69,8 @@ static struct task_struct *hvc_task; | |||
| 69 | /* Picks up late kicks after list walk but before schedule() */ | 69 | /* Picks up late kicks after list walk but before schedule() */ |
| 70 | static int hvc_kicked; | 70 | static int hvc_kicked; |
| 71 | 71 | ||
| 72 | static int hvc_init(void); | ||
| 73 | |||
| 72 | #ifdef CONFIG_MAGIC_SYSRQ | 74 | #ifdef CONFIG_MAGIC_SYSRQ |
| 73 | static int sysrq_pressed; | 75 | static int sysrq_pressed; |
| 74 | #endif | 76 | #endif |
| @@ -754,6 +756,13 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, | |||
| 754 | struct hvc_struct *hp; | 756 | struct hvc_struct *hp; |
| 755 | int i; | 757 | int i; |
| 756 | 758 | ||
| 759 | /* We wait until a driver actually comes along */ | ||
| 760 | if (!hvc_driver) { | ||
| 761 | int err = hvc_init(); | ||
| 762 | if (err) | ||
| 763 | return ERR_PTR(err); | ||
| 764 | } | ||
| 765 | |||
| 757 | hp = kmalloc(ALIGN(sizeof(*hp), sizeof(long)) + outbuf_size, | 766 | hp = kmalloc(ALIGN(sizeof(*hp), sizeof(long)) + outbuf_size, |
| 758 | GFP_KERNEL); | 767 | GFP_KERNEL); |
| 759 | if (!hp) | 768 | if (!hp) |
| @@ -829,16 +838,18 @@ int __devexit hvc_remove(struct hvc_struct *hp) | |||
| 829 | return 0; | 838 | return 0; |
| 830 | } | 839 | } |
| 831 | 840 | ||
| 832 | /* Driver initialization. Follow console initialization. This is where the TTY | 841 | /* Driver initialization: called as soon as someone uses hvc_alloc(). */ |
| 833 | * interfaces start to become available. */ | 842 | static int hvc_init(void) |
| 834 | static int __init hvc_init(void) | ||
| 835 | { | 843 | { |
| 836 | struct tty_driver *drv; | 844 | struct tty_driver *drv; |
| 845 | int err; | ||
| 837 | 846 | ||
| 838 | /* We need more than hvc_count adapters due to hotplug additions. */ | 847 | /* We need more than hvc_count adapters due to hotplug additions. */ |
| 839 | drv = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS); | 848 | drv = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS); |
| 840 | if (!drv) | 849 | if (!drv) { |
| 841 | return -ENOMEM; | 850 | err = -ENOMEM; |
| 851 | goto out; | ||
| 852 | } | ||
| 842 | 853 | ||
| 843 | drv->owner = THIS_MODULE; | 854 | drv->owner = THIS_MODULE; |
| 844 | drv->driver_name = "hvc"; | 855 | drv->driver_name = "hvc"; |
| @@ -854,30 +865,43 @@ static int __init hvc_init(void) | |||
| 854 | * added later. */ | 865 | * added later. */ |
| 855 | hvc_task = kthread_run(khvcd, NULL, "khvcd"); | 866 | hvc_task = kthread_run(khvcd, NULL, "khvcd"); |
| 856 | if (IS_ERR(hvc_task)) { | 867 | if (IS_ERR(hvc_task)) { |
| 857 | panic("Couldn't create kthread for console.\n"); | 868 | printk(KERN_ERR "Couldn't create kthread for console.\n"); |
| 858 | put_tty_driver(drv); | 869 | err = PTR_ERR(hvc_task); |
| 859 | return -EIO; | 870 | goto put_tty; |
| 860 | } | 871 | } |
| 861 | 872 | ||
| 862 | if (tty_register_driver(drv)) | 873 | err = tty_register_driver(drv); |
| 863 | panic("Couldn't register hvc console driver\n"); | 874 | if (err) { |
| 875 | printk(KERN_ERR "Couldn't register hvc console driver\n"); | ||
| 876 | goto stop_thread; | ||
| 877 | } | ||
| 864 | 878 | ||
| 879 | /* FIXME: This mb() seems completely random. Remove it. */ | ||
| 865 | mb(); | 880 | mb(); |
| 866 | hvc_driver = drv; | 881 | hvc_driver = drv; |
| 867 | return 0; | 882 | return 0; |
| 883 | |||
| 884 | put_tty: | ||
| 885 | put_tty_driver(hvc_driver); | ||
| 886 | stop_thread: | ||
| 887 | kthread_stop(hvc_task); | ||
| 888 | hvc_task = NULL; | ||
| 889 | out: | ||
| 890 | return err; | ||
| 868 | } | 891 | } |
| 869 | module_init(hvc_init); | ||
| 870 | 892 | ||
| 871 | /* This isn't particularly necessary due to this being a console driver | 893 | /* This isn't particularly necessary due to this being a console driver |
| 872 | * but it is nice to be thorough. | 894 | * but it is nice to be thorough. |
| 873 | */ | 895 | */ |
| 874 | static void __exit hvc_exit(void) | 896 | static void __exit hvc_exit(void) |
| 875 | { | 897 | { |
| 876 | kthread_stop(hvc_task); | 898 | if (hvc_driver) { |
| 899 | kthread_stop(hvc_task); | ||
| 877 | 900 | ||
| 878 | tty_unregister_driver(hvc_driver); | 901 | tty_unregister_driver(hvc_driver); |
| 879 | /* return tty_struct instances allocated in hvc_init(). */ | 902 | /* return tty_struct instances allocated in hvc_init(). */ |
| 880 | put_tty_driver(hvc_driver); | 903 | put_tty_driver(hvc_driver); |
| 881 | unregister_console(&hvc_con_driver); | 904 | unregister_console(&hvc_con_driver); |
| 905 | } | ||
| 882 | } | 906 | } |
| 883 | module_exit(hvc_exit); | 907 | module_exit(hvc_exit); |
