X-Git-Url: http://pilppa.org/gitweb/gitweb.cgi?a=blobdiff_plain;f=drivers%2Fchar%2Fhvc_console.c;h=44160d5ebca06dbcd7e300c9835cbeb1763c1a4c;hb=7dac6f8df607929e51f4fd598d80bd009c45a9f8;hp=83c1151ec7a21559257f3663a59d0f59e4d92abc;hpb=40b42f1ebf653cd72c32eb1a1a0b9fea2dfbfd7d;p=linux-2.6-omap-h63xx.git diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 83c1151ec7a..44160d5ebca 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include @@ -69,6 +69,8 @@ static struct task_struct *hvc_task; /* Picks up late kicks after list walk but before schedule() */ static int hvc_kicked; +static int hvc_init(void); + #ifdef CONFIG_MAGIC_SYSRQ static int sysrq_pressed; #endif @@ -87,11 +89,11 @@ struct hvc_struct { int irq_requested; int irq; struct list_head next; - struct kobject kobj; /* ref count & hvc_struct lifetime */ + struct kref kref; /* ref count & hvc_struct lifetime */ }; /* dynamic list of hvc_struct instances */ -static struct list_head hvc_structs = LIST_HEAD_INIT(hvc_structs); +static LIST_HEAD(hvc_structs); /* * Protect the list of hvc_struct instances from inserts and removals during @@ -108,7 +110,7 @@ static int last_hvc = -1; /* * Do not call this function with either the hvc_structs_lock or the hvc_struct - * lock held. If successful, this function increments the kobject reference + * lock held. If successful, this function increments the kref reference * count against the target hvc_struct so it should be released when finished. */ static struct hvc_struct *hvc_get_by_index(int index) @@ -121,7 +123,7 @@ static struct hvc_struct *hvc_get_by_index(int index) list_for_each_entry(hp, &hvc_structs, next) { spin_lock_irqsave(&hp->lock, flags); if (hp->index == index) { - kobject_get(&hp->kobj); + kref_get(&hp->kref); spin_unlock_irqrestore(&hp->lock, flags); spin_unlock(&hvc_structs_lock); return hp; @@ -240,6 +242,23 @@ static int __init hvc_console_init(void) } console_initcall(hvc_console_init); +/* callback when the kboject ref count reaches zero. */ +static void destroy_hvc_struct(struct kref *kref) +{ + struct hvc_struct *hp = container_of(kref, struct hvc_struct, kref); + unsigned long flags; + + spin_lock(&hvc_structs_lock); + + spin_lock_irqsave(&hp->lock, flags); + list_del(&(hp->next)); + spin_unlock_irqrestore(&hp->lock, flags); + + spin_unlock(&hvc_structs_lock); + + kfree(hp); +} + /* * hvc_instantiate() is an early console discovery method which locates * consoles * prior to the vio subsystem discovering them. Hotplugged @@ -259,7 +278,7 @@ int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops) /* make sure no no tty has been registered in this index */ hp = hvc_get_by_index(index); if (hp) { - kobject_put(&hp->kobj); + kref_put(&hp->kref, destroy_hvc_struct); return -1; } @@ -316,9 +335,8 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) unsigned long flags; int irq = 0; int rc = 0; - struct kobject *kobjp; - /* Auto increments kobject reference if found. */ + /* Auto increments kref reference if found. */ if (!(hp = hvc_get_by_index(tty->index))) return -ENODEV; @@ -339,8 +357,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) if (irq) hp->irq_requested = 1; - kobjp = &hp->kobj; - spin_unlock_irqrestore(&hp->lock, flags); /* check error, fallback to non-irq */ if (irq) @@ -350,7 +366,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) * If the request_irq() fails and we return an error. The tty layer * will call hvc_close() after a failed open but we don't want to clean * up there so we'll clean up here and clear out the previously set - * tty fields and return the kobject reference. + * tty fields and return the kref reference. */ if (rc) { spin_lock_irqsave(&hp->lock, flags); @@ -358,7 +374,7 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) hp->irq_requested = 0; spin_unlock_irqrestore(&hp->lock, flags); tty->driver_data = NULL; - kobject_put(kobjp); + kref_put(&hp->kref, destroy_hvc_struct); printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc); } /* Force wakeup of the polling thread */ @@ -370,7 +386,6 @@ static int hvc_open(struct tty_struct *tty, struct file * filp) static void hvc_close(struct tty_struct *tty, struct file * filp) { struct hvc_struct *hp; - struct kobject *kobjp; int irq = 0; unsigned long flags; @@ -380,7 +395,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) /* * No driver_data means that this close was issued after a failed * hvc_open by the tty layer's release_dev() function and we can just - * exit cleanly because the kobject reference wasn't made. + * exit cleanly because the kref reference wasn't made. */ if (!tty->driver_data) return; @@ -388,7 +403,6 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) hp = tty->driver_data; spin_lock_irqsave(&hp->lock, flags); - kobjp = &hp->kobj; if (--hp->count == 0) { if (hp->irq_requested) irq = hp->irq; @@ -415,7 +429,7 @@ static void hvc_close(struct tty_struct *tty, struct file * filp) spin_unlock_irqrestore(&hp->lock, flags); } - kobject_put(kobjp); + kref_put(&hp->kref, destroy_hvc_struct); } static void hvc_hangup(struct tty_struct *tty) @@ -424,7 +438,6 @@ static void hvc_hangup(struct tty_struct *tty) unsigned long flags; int irq = 0; int temp_open_count; - struct kobject *kobjp; if (!hp) return; @@ -441,7 +454,6 @@ static void hvc_hangup(struct tty_struct *tty) return; } - kobjp = &hp->kobj; temp_open_count = hp->count; hp->count = 0; hp->n_outbuf = 0; @@ -455,7 +467,7 @@ static void hvc_hangup(struct tty_struct *tty) free_irq(irq, hp); while(temp_open_count) { --temp_open_count; - kobject_put(kobjp); + kref_put(&hp->kref, destroy_hvc_struct); } } @@ -727,33 +739,19 @@ static const struct tty_operations hvc_ops = { .chars_in_buffer = hvc_chars_in_buffer, }; -/* callback when the kboject ref count reaches zero. */ -static void destroy_hvc_struct(struct kobject *kobj) -{ - struct hvc_struct *hp = container_of(kobj, struct hvc_struct, kobj); - unsigned long flags; - - spin_lock(&hvc_structs_lock); - - spin_lock_irqsave(&hp->lock, flags); - list_del(&(hp->next)); - spin_unlock_irqrestore(&hp->lock, flags); - - spin_unlock(&hvc_structs_lock); - - kfree(hp); -} - -static struct kobj_type hvc_kobj_type = { - .release = destroy_hvc_struct, -}; - struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, struct hv_ops *ops, int outbuf_size) { struct hvc_struct *hp; int i; + /* We wait until a driver actually comes along */ + if (!hvc_driver) { + int err = hvc_init(); + if (err) + return ERR_PTR(err); + } + hp = kmalloc(ALIGN(sizeof(*hp), sizeof(long)) + outbuf_size, GFP_KERNEL); if (!hp) @@ -767,8 +765,7 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, hp->outbuf_size = outbuf_size; hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))]; - kobject_init(&hp->kobj); - hp->kobj.ktype = &hvc_kobj_type; + kref_init(&hp->kref); spin_lock_init(&hp->lock); spin_lock(&hvc_structs_lock); @@ -797,12 +794,10 @@ struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, int __devexit hvc_remove(struct hvc_struct *hp) { unsigned long flags; - struct kobject *kobjp; struct tty_struct *tty; spin_lock_irqsave(&hp->lock, flags); tty = hp->tty; - kobjp = &hp->kobj; if (hp->index < MAX_NR_HVC_CONSOLES) vtermnos[hp->index] = -1; @@ -812,12 +807,12 @@ int __devexit hvc_remove(struct hvc_struct *hp) spin_unlock_irqrestore(&hp->lock, flags); /* - * We 'put' the instance that was grabbed when the kobject instance - * was initialized using kobject_init(). Let the last holder of this - * kobject cause it to be removed, which will probably be the tty_hangup + * We 'put' the instance that was grabbed when the kref instance + * was initialized using kref_init(). Let the last holder of this + * kref cause it to be removed, which will probably be the tty_hangup * below. */ - kobject_put(kobjp); + kref_put(&hp->kref, destroy_hvc_struct); /* * This function call will auto chain call hvc_hangup. The tty should @@ -829,16 +824,18 @@ int __devexit hvc_remove(struct hvc_struct *hp) return 0; } -/* Driver initialization. Follow console initialization. This is where the TTY - * interfaces start to become available. */ -static int __init hvc_init(void) +/* Driver initialization: called as soon as someone uses hvc_alloc(). */ +static int hvc_init(void) { struct tty_driver *drv; + int err; /* We need more than hvc_count adapters due to hotplug additions. */ drv = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS); - if (!drv) - return -ENOMEM; + if (!drv) { + err = -ENOMEM; + goto out; + } drv->owner = THIS_MODULE; drv->driver_name = "hvc"; @@ -854,30 +851,43 @@ static int __init hvc_init(void) * added later. */ hvc_task = kthread_run(khvcd, NULL, "khvcd"); if (IS_ERR(hvc_task)) { - panic("Couldn't create kthread for console.\n"); - put_tty_driver(drv); - return -EIO; + printk(KERN_ERR "Couldn't create kthread for console.\n"); + err = PTR_ERR(hvc_task); + goto put_tty; } - if (tty_register_driver(drv)) - panic("Couldn't register hvc console driver\n"); + err = tty_register_driver(drv); + if (err) { + printk(KERN_ERR "Couldn't register hvc console driver\n"); + goto stop_thread; + } + /* FIXME: This mb() seems completely random. Remove it. */ mb(); hvc_driver = drv; return 0; + +put_tty: + put_tty_driver(hvc_driver); +stop_thread: + kthread_stop(hvc_task); + hvc_task = NULL; +out: + return err; } -module_init(hvc_init); /* This isn't particularly necessary due to this being a console driver * but it is nice to be thorough. */ static void __exit hvc_exit(void) { - kthread_stop(hvc_task); + if (hvc_driver) { + kthread_stop(hvc_task); - tty_unregister_driver(hvc_driver); - /* return tty_struct instances allocated in hvc_init(). */ - put_tty_driver(hvc_driver); - unregister_console(&hvc_con_driver); + tty_unregister_driver(hvc_driver); + /* return tty_struct instances allocated in hvc_init(). */ + put_tty_driver(hvc_driver); + unregister_console(&hvc_con_driver); + } } module_exit(hvc_exit);