diff options
author | Todd Poynor <tpoynor@mvista.com> | 2005-07-11 22:34:39 -0400 |
---|---|---|
committer | Thomas Gleixner <tglx@mtd.linutronix.de> | 2005-07-12 18:58:44 -0400 |
commit | a98a5d04f400ad112e59cadd739dbabf89417e60 (patch) | |
tree | 5eeb7f45c0090de40c7523e2b9dfd5e86b22169e /drivers/char/hvc_console.c | |
parent | 751382dd5cb2702368d281a50b55c2d6c4e8fbfc (diff) | |
parent | 7ac3db59fd4410405ce55e2a25c397aec440d8da (diff) |
Merge with rsync://fileserver/linux
Diffstat (limited to 'drivers/char/hvc_console.c')
-rw-r--r-- | drivers/char/hvc_console.c | 429 |
1 files changed, 234 insertions, 195 deletions
diff --git a/drivers/char/hvc_console.c b/drivers/char/hvc_console.c index 88cd858f74d0..cddb789902db 100644 --- a/drivers/char/hvc_console.c +++ b/drivers/char/hvc_console.c | |||
@@ -22,6 +22,7 @@ | |||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 | */ | 23 | */ |
24 | 24 | ||
25 | #include <linux/config.h> | ||
25 | #include <linux/console.h> | 26 | #include <linux/console.h> |
26 | #include <linux/cpumask.h> | 27 | #include <linux/cpumask.h> |
27 | #include <linux/init.h> | 28 | #include <linux/init.h> |
@@ -40,7 +41,6 @@ | |||
40 | #include <linux/delay.h> | 41 | #include <linux/delay.h> |
41 | #include <asm/uaccess.h> | 42 | #include <asm/uaccess.h> |
42 | #include <asm/hvconsole.h> | 43 | #include <asm/hvconsole.h> |
43 | #include <asm/vio.h> | ||
44 | 44 | ||
45 | #define HVC_MAJOR 229 | 45 | #define HVC_MAJOR 229 |
46 | #define HVC_MINOR 0 | 46 | #define HVC_MINOR 0 |
@@ -61,16 +61,21 @@ | |||
61 | */ | 61 | */ |
62 | #define HVC_ALLOC_TTY_ADAPTERS 8 | 62 | #define HVC_ALLOC_TTY_ADAPTERS 8 |
63 | 63 | ||
64 | static struct tty_driver *hvc_driver; | ||
65 | #ifdef CONFIG_MAGIC_SYSRQ | ||
66 | static int sysrq_pressed; | ||
67 | #endif | ||
68 | |||
69 | #define N_OUTBUF 16 | 64 | #define N_OUTBUF 16 |
70 | #define N_INBUF 16 | 65 | #define N_INBUF 16 |
71 | 66 | ||
72 | #define __ALIGNED__ __attribute__((__aligned__(8))) | 67 | #define __ALIGNED__ __attribute__((__aligned__(8))) |
73 | 68 | ||
69 | static struct tty_driver *hvc_driver; | ||
70 | static struct task_struct *hvc_task; | ||
71 | |||
72 | /* Picks up late kicks after list walk but before schedule() */ | ||
73 | static int hvc_kicked; | ||
74 | |||
75 | #ifdef CONFIG_MAGIC_SYSRQ | ||
76 | static int sysrq_pressed; | ||
77 | #endif | ||
78 | |||
74 | struct hvc_struct { | 79 | struct hvc_struct { |
75 | spinlock_t lock; | 80 | spinlock_t lock; |
76 | int index; | 81 | int index; |
@@ -80,11 +85,11 @@ struct hvc_struct { | |||
80 | char outbuf[N_OUTBUF] __ALIGNED__; | 85 | char outbuf[N_OUTBUF] __ALIGNED__; |
81 | int n_outbuf; | 86 | int n_outbuf; |
82 | uint32_t vtermno; | 87 | uint32_t vtermno; |
88 | struct hv_ops *ops; | ||
83 | int irq_requested; | 89 | int irq_requested; |
84 | int irq; | 90 | int irq; |
85 | struct list_head next; | 91 | struct list_head next; |
86 | struct kobject kobj; /* ref count & hvc_struct lifetime */ | 92 | struct kobject kobj; /* ref count & hvc_struct lifetime */ |
87 | struct vio_dev *vdev; | ||
88 | }; | 93 | }; |
89 | 94 | ||
90 | /* dynamic list of hvc_struct instances */ | 95 | /* dynamic list of hvc_struct instances */ |
@@ -97,26 +102,185 @@ static struct list_head hvc_structs = LIST_HEAD_INIT(hvc_structs); | |||
97 | static DEFINE_SPINLOCK(hvc_structs_lock); | 102 | static DEFINE_SPINLOCK(hvc_structs_lock); |
98 | 103 | ||
99 | /* | 104 | /* |
105 | * This value is used to assign a tty->index value to a hvc_struct based | ||
106 | * upon order of exposure via hvc_probe(), when we can not match it to | ||
107 | * a console canidate registered with hvc_instantiate(). | ||
108 | */ | ||
109 | static int last_hvc = -1; | ||
110 | |||
111 | /* | ||
112 | * Do not call this function with either the hvc_strucst_lock or the hvc_struct | ||
113 | * lock held. If successful, this function increments the kobject reference | ||
114 | * count against the target hvc_struct so it should be released when finished. | ||
115 | */ | ||
116 | struct hvc_struct *hvc_get_by_index(int index) | ||
117 | { | ||
118 | struct hvc_struct *hp; | ||
119 | unsigned long flags; | ||
120 | |||
121 | spin_lock(&hvc_structs_lock); | ||
122 | |||
123 | list_for_each_entry(hp, &hvc_structs, next) { | ||
124 | spin_lock_irqsave(&hp->lock, flags); | ||
125 | if (hp->index == index) { | ||
126 | kobject_get(&hp->kobj); | ||
127 | spin_unlock_irqrestore(&hp->lock, flags); | ||
128 | spin_unlock(&hvc_structs_lock); | ||
129 | return hp; | ||
130 | } | ||
131 | spin_unlock_irqrestore(&hp->lock, flags); | ||
132 | } | ||
133 | hp = NULL; | ||
134 | |||
135 | spin_unlock(&hvc_structs_lock); | ||
136 | return hp; | ||
137 | } | ||
138 | |||
139 | |||
140 | /* | ||
100 | * Initial console vtermnos for console API usage prior to full console | 141 | * Initial console vtermnos for console API usage prior to full console |
101 | * initialization. Any vty adapter outside this range will not have usable | 142 | * initialization. Any vty adapter outside this range will not have usable |
102 | * console interfaces but can still be used as a tty device. This has to be | 143 | * console interfaces but can still be used as a tty device. This has to be |
103 | * static because kmalloc will not work during early console init. | 144 | * static because kmalloc will not work during early console init. |
104 | */ | 145 | */ |
105 | static uint32_t vtermnos[MAX_NR_HVC_CONSOLES]; | 146 | static struct hv_ops *cons_ops[MAX_NR_HVC_CONSOLES]; |
147 | static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] = | ||
148 | {[0 ... MAX_NR_HVC_CONSOLES - 1] = -1}; | ||
106 | 149 | ||
107 | /* Used for accounting purposes */ | 150 | /* |
108 | static int num_vterms = 0; | 151 | * Console APIs, NOT TTY. These APIs are available immediately when |
152 | * hvc_console_setup() finds adapters. | ||
153 | */ | ||
109 | 154 | ||
110 | static struct task_struct *hvc_task; | 155 | void hvc_console_print(struct console *co, const char *b, unsigned count) |
156 | { | ||
157 | char c[16] __ALIGNED__; | ||
158 | unsigned i = 0, n = 0; | ||
159 | int r, donecr = 0, index = co->index; | ||
160 | |||
161 | /* Console access attempt outside of acceptable console range. */ | ||
162 | if (index >= MAX_NR_HVC_CONSOLES) | ||
163 | return; | ||
164 | |||
165 | /* This console adapter was removed so it is not useable. */ | ||
166 | if (vtermnos[index] < 0) | ||
167 | return; | ||
168 | |||
169 | while (count > 0 || i > 0) { | ||
170 | if (count > 0 && i < sizeof(c)) { | ||
171 | if (b[n] == '\n' && !donecr) { | ||
172 | c[i++] = '\r'; | ||
173 | donecr = 1; | ||
174 | } else { | ||
175 | c[i++] = b[n++]; | ||
176 | donecr = 0; | ||
177 | --count; | ||
178 | } | ||
179 | } else { | ||
180 | r = cons_ops[index]->put_chars(vtermnos[index], c, i); | ||
181 | if (r < 0) { | ||
182 | /* throw away chars on error */ | ||
183 | i = 0; | ||
184 | } else if (r > 0) { | ||
185 | i -= r; | ||
186 | if (i > 0) | ||
187 | memmove(c, c+r, i); | ||
188 | } | ||
189 | } | ||
190 | } | ||
191 | } | ||
192 | |||
193 | static struct tty_driver *hvc_console_device(struct console *c, int *index) | ||
194 | { | ||
195 | if (vtermnos[c->index] == -1) | ||
196 | return NULL; | ||
197 | |||
198 | *index = c->index; | ||
199 | return hvc_driver; | ||
200 | } | ||
201 | |||
202 | static int __init hvc_console_setup(struct console *co, char *options) | ||
203 | { | ||
204 | if (co->index < 0 || co->index >= MAX_NR_HVC_CONSOLES) | ||
205 | return -ENODEV; | ||
206 | |||
207 | if (vtermnos[co->index] == -1) | ||
208 | return -ENODEV; | ||
209 | |||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | struct console hvc_con_driver = { | ||
214 | .name = "hvc", | ||
215 | .write = hvc_console_print, | ||
216 | .device = hvc_console_device, | ||
217 | .setup = hvc_console_setup, | ||
218 | .flags = CON_PRINTBUFFER, | ||
219 | .index = -1, | ||
220 | }; | ||
111 | 221 | ||
112 | /* | 222 | /* |
113 | * This value is used to associate a tty->index value to a hvc_struct based | 223 | * Early console initialization. Preceeds driver initialization. |
114 | * upon order of exposure via hvc_probe(). | 224 | * |
225 | * (1) we are first, and the user specified another driver | ||
226 | * -- index will remain -1 | ||
227 | * (2) we are first and the user specified no driver | ||
228 | * -- index will be set to 0, then we will fail setup. | ||
229 | * (3) we are first and the user specified our driver | ||
230 | * -- index will be set to user specified driver, and we will fail | ||
231 | * (4) we are after driver, and this initcall will register us | ||
232 | * -- if the user didn't specify a driver then the console will match | ||
233 | * | ||
234 | * Note that for cases 2 and 3, we will match later when the io driver | ||
235 | * calls hvc_instantiate() and call register again. | ||
115 | */ | 236 | */ |
116 | static int hvc_count = -1; | 237 | static int __init hvc_console_init(void) |
238 | { | ||
239 | register_console(&hvc_con_driver); | ||
240 | return 0; | ||
241 | } | ||
242 | console_initcall(hvc_console_init); | ||
117 | 243 | ||
118 | /* Picks up late kicks after list walk but before schedule() */ | 244 | /* |
119 | static int hvc_kicked; | 245 | * hvc_instantiate() is an early console discovery method which locates |
246 | * consoles * prior to the vio subsystem discovering them. Hotplugged | ||
247 | * vty adapters do NOT get an hvc_instantiate() callback since they | ||
248 | * appear after early console init. | ||
249 | */ | ||
250 | int hvc_instantiate(uint32_t vtermno, int index, struct hv_ops *ops) | ||
251 | { | ||
252 | struct hvc_struct *hp; | ||
253 | |||
254 | if (index < 0 || index >= MAX_NR_HVC_CONSOLES) | ||
255 | return -1; | ||
256 | |||
257 | if (vtermnos[index] != -1) | ||
258 | return -1; | ||
259 | |||
260 | /* make sure no no tty has been registerd in this index */ | ||
261 | hp = hvc_get_by_index(index); | ||
262 | if (hp) { | ||
263 | kobject_put(&hp->kobj); | ||
264 | return -1; | ||
265 | } | ||
266 | |||
267 | vtermnos[index] = vtermno; | ||
268 | cons_ops[index] = ops; | ||
269 | |||
270 | /* reserve all indices upto and including this index */ | ||
271 | if (last_hvc < index) | ||
272 | last_hvc = index; | ||
273 | |||
274 | /* if this index is what the user requested, then register | ||
275 | * now (setup won't fail at this point). It's ok to just | ||
276 | * call register again if previously .setup failed. | ||
277 | */ | ||
278 | if (index == hvc_con_driver.index) | ||
279 | register_console(&hvc_con_driver); | ||
280 | |||
281 | return 0; | ||
282 | } | ||
283 | EXPORT_SYMBOL(hvc_instantiate); | ||
120 | 284 | ||
121 | /* Wake the sleeping khvcd */ | 285 | /* Wake the sleeping khvcd */ |
122 | static void hvc_kick(void) | 286 | static void hvc_kick(void) |
@@ -125,13 +289,17 @@ static void hvc_kick(void) | |||
125 | wake_up_process(hvc_task); | 289 | wake_up_process(hvc_task); |
126 | } | 290 | } |
127 | 291 | ||
292 | static int hvc_poll(struct hvc_struct *hp); | ||
293 | |||
128 | /* | 294 | /* |
129 | * NOTE: This API isn't used if the console adapter doesn't support interrupts. | 295 | * NOTE: This API isn't used if the console adapter doesn't support interrupts. |
130 | * In this case the console is poll driven. | 296 | * In this case the console is poll driven. |
131 | */ | 297 | */ |
132 | static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance, struct pt_regs *regs) | 298 | static irqreturn_t hvc_handle_interrupt(int irq, void *dev_instance, struct pt_regs *regs) |
133 | { | 299 | { |
134 | hvc_kick(); | 300 | /* if hvc_poll request a repoll, then kick the hvcd thread */ |
301 | if (hvc_poll(dev_instance)) | ||
302 | hvc_kick(); | ||
135 | return IRQ_HANDLED; | 303 | return IRQ_HANDLED; |
136 | } | 304 | } |
137 | 305 | ||
@@ -141,34 +309,6 @@ static void hvc_unthrottle(struct tty_struct *tty) | |||
141 | } | 309 | } |
142 | 310 | ||
143 | /* | 311 | /* |
144 | * Do not call this function with either the hvc_strucst_lock or the hvc_struct | ||
145 | * lock held. If successful, this function increments the kobject reference | ||
146 | * count against the target hvc_struct so it should be released when finished. | ||
147 | */ | ||
148 | struct hvc_struct *hvc_get_by_index(int index) | ||
149 | { | ||
150 | struct hvc_struct *hp; | ||
151 | unsigned long flags; | ||
152 | |||
153 | spin_lock(&hvc_structs_lock); | ||
154 | |||
155 | list_for_each_entry(hp, &hvc_structs, next) { | ||
156 | spin_lock_irqsave(&hp->lock, flags); | ||
157 | if (hp->index == index) { | ||
158 | kobject_get(&hp->kobj); | ||
159 | spin_unlock_irqrestore(&hp->lock, flags); | ||
160 | spin_unlock(&hvc_structs_lock); | ||
161 | return hp; | ||
162 | } | ||
163 | spin_unlock_irqrestore(&hp->lock, flags); | ||
164 | } | ||
165 | hp = NULL; | ||
166 | |||
167 | spin_unlock(&hvc_structs_lock); | ||
168 | return hp; | ||
169 | } | ||
170 | |||
171 | /* | ||
172 | * The TTY interface won't be used until after the vio layer has exposed the vty | 312 | * The TTY interface won't be used until after the vio layer has exposed the vty |
173 | * adapter to the kernel. | 313 | * adapter to the kernel. |
174 | */ | 314 | */ |
@@ -329,7 +469,7 @@ static void hvc_push(struct hvc_struct *hp) | |||
329 | { | 469 | { |
330 | int n; | 470 | int n; |
331 | 471 | ||
332 | n = hvc_put_chars(hp->vtermno, hp->outbuf, hp->n_outbuf); | 472 | n = hp->ops->put_chars(hp->vtermno, hp->outbuf, hp->n_outbuf); |
333 | if (n <= 0) { | 473 | if (n <= 0) { |
334 | if (n == 0) | 474 | if (n == 0) |
335 | return; | 475 | return; |
@@ -467,7 +607,7 @@ static int hvc_poll(struct hvc_struct *hp) | |||
467 | break; | 607 | break; |
468 | } | 608 | } |
469 | 609 | ||
470 | n = hvc_get_chars(hp->vtermno, buf, count); | 610 | n = hp->ops->get_chars(hp->vtermno, buf, count); |
471 | if (n <= 0) { | 611 | if (n <= 0) { |
472 | /* Hangup the tty when disconnected from host */ | 612 | /* Hangup the tty when disconnected from host */ |
473 | if (n == -EPIPE) { | 613 | if (n == -EPIPE) { |
@@ -479,14 +619,17 @@ static int hvc_poll(struct hvc_struct *hp) | |||
479 | } | 619 | } |
480 | for (i = 0; i < n; ++i) { | 620 | for (i = 0; i < n; ++i) { |
481 | #ifdef CONFIG_MAGIC_SYSRQ | 621 | #ifdef CONFIG_MAGIC_SYSRQ |
482 | /* Handle the SysRq Hack */ | 622 | if (hp->index == hvc_con_driver.index) { |
483 | if (buf[i] == '\x0f') { /* ^O -- should support a sequence */ | 623 | /* Handle the SysRq Hack */ |
484 | sysrq_pressed = 1; | 624 | /* XXX should support a sequence */ |
485 | continue; | 625 | if (buf[i] == '\x0f') { /* ^O */ |
486 | } else if (sysrq_pressed) { | 626 | sysrq_pressed = 1; |
487 | handle_sysrq(buf[i], NULL, tty); | 627 | continue; |
488 | sysrq_pressed = 0; | 628 | } else if (sysrq_pressed) { |
489 | continue; | 629 | handle_sysrq(buf[i], NULL, tty); |
630 | sysrq_pressed = 0; | ||
631 | continue; | ||
632 | } | ||
490 | } | 633 | } |
491 | #endif /* CONFIG_MAGIC_SYSRQ */ | 634 | #endif /* CONFIG_MAGIC_SYSRQ */ |
492 | tty_insert_flip_char(tty, buf[i], 0); | 635 | tty_insert_flip_char(tty, buf[i], 0); |
@@ -497,8 +640,8 @@ static int hvc_poll(struct hvc_struct *hp) | |||
497 | 640 | ||
498 | /* | 641 | /* |
499 | * Account for the total amount read in one loop, and if above | 642 | * Account for the total amount read in one loop, and if above |
500 | * 64 bytes, we do a quick schedule loop to let the tty grok the | 643 | * 64 bytes, we do a quick schedule loop to let the tty grok |
501 | * data and eventually throttle us. | 644 | * the data and eventually throttle us. |
502 | */ | 645 | */ |
503 | read_total += n; | 646 | read_total += n; |
504 | if (read_total >= 64) { | 647 | if (read_total >= 64) { |
@@ -542,7 +685,6 @@ int khvcd(void *unused) | |||
542 | if (cpus_empty(cpus_in_xmon)) { | 685 | if (cpus_empty(cpus_in_xmon)) { |
543 | spin_lock(&hvc_structs_lock); | 686 | spin_lock(&hvc_structs_lock); |
544 | list_for_each_entry(hp, &hvc_structs, next) { | 687 | list_for_each_entry(hp, &hvc_structs, next) { |
545 | /*hp = list_entry(node, struct hvc_struct, * next); */ | ||
546 | poll_mask |= hvc_poll(hp); | 688 | poll_mask |= hvc_poll(hp); |
547 | } | 689 | } |
548 | spin_unlock(&hvc_structs_lock); | 690 | spin_unlock(&hvc_structs_lock); |
@@ -577,14 +719,6 @@ static struct tty_operations hvc_ops = { | |||
577 | .chars_in_buffer = hvc_chars_in_buffer, | 719 | .chars_in_buffer = hvc_chars_in_buffer, |
578 | }; | 720 | }; |
579 | 721 | ||
580 | char hvc_driver_name[] = "hvc_console"; | ||
581 | |||
582 | static struct vio_device_id hvc_driver_table[] __devinitdata= { | ||
583 | {"serial", "hvterm1"}, | ||
584 | { NULL, } | ||
585 | }; | ||
586 | MODULE_DEVICE_TABLE(vio, hvc_driver_table); | ||
587 | |||
588 | /* callback when the kboject ref count reaches zero. */ | 722 | /* callback when the kboject ref count reaches zero. */ |
589 | static void destroy_hvc_struct(struct kobject *kobj) | 723 | static void destroy_hvc_struct(struct kobject *kobj) |
590 | { | 724 | { |
@@ -606,41 +740,51 @@ static struct kobj_type hvc_kobj_type = { | |||
606 | .release = destroy_hvc_struct, | 740 | .release = destroy_hvc_struct, |
607 | }; | 741 | }; |
608 | 742 | ||
609 | static int __devinit hvc_probe( | 743 | struct hvc_struct __devinit *hvc_alloc(uint32_t vtermno, int irq, |
610 | struct vio_dev *dev, | 744 | struct hv_ops *ops) |
611 | const struct vio_device_id *id) | ||
612 | { | 745 | { |
613 | struct hvc_struct *hp; | 746 | struct hvc_struct *hp; |
614 | 747 | int i; | |
615 | /* probed with invalid parameters. */ | ||
616 | if (!dev || !id) | ||
617 | return -EPERM; | ||
618 | 748 | ||
619 | hp = kmalloc(sizeof(*hp), GFP_KERNEL); | 749 | hp = kmalloc(sizeof(*hp), GFP_KERNEL); |
620 | if (!hp) | 750 | if (!hp) |
621 | return -ENOMEM; | 751 | return ERR_PTR(-ENOMEM); |
622 | 752 | ||
623 | memset(hp, 0x00, sizeof(*hp)); | 753 | memset(hp, 0x00, sizeof(*hp)); |
624 | hp->vtermno = dev->unit_address; | 754 | |
625 | hp->vdev = dev; | 755 | hp->vtermno = vtermno; |
626 | hp->vdev->dev.driver_data = hp; | 756 | hp->irq = irq; |
627 | hp->irq = dev->irq; | 757 | hp->ops = ops; |
628 | 758 | ||
629 | kobject_init(&hp->kobj); | 759 | kobject_init(&hp->kobj); |
630 | hp->kobj.ktype = &hvc_kobj_type; | 760 | hp->kobj.ktype = &hvc_kobj_type; |
631 | 761 | ||
632 | spin_lock_init(&hp->lock); | 762 | spin_lock_init(&hp->lock); |
633 | spin_lock(&hvc_structs_lock); | 763 | spin_lock(&hvc_structs_lock); |
634 | hp->index = ++hvc_count; | 764 | |
765 | /* | ||
766 | * find index to use: | ||
767 | * see if this vterm id matches one registered for console. | ||
768 | */ | ||
769 | for (i=0; i < MAX_NR_HVC_CONSOLES; i++) | ||
770 | if (vtermnos[i] == hp->vtermno) | ||
771 | break; | ||
772 | |||
773 | /* no matching slot, just use a counter */ | ||
774 | if (i >= MAX_NR_HVC_CONSOLES) | ||
775 | i = ++last_hvc; | ||
776 | |||
777 | hp->index = i; | ||
778 | |||
635 | list_add_tail(&(hp->next), &hvc_structs); | 779 | list_add_tail(&(hp->next), &hvc_structs); |
636 | spin_unlock(&hvc_structs_lock); | 780 | spin_unlock(&hvc_structs_lock); |
637 | 781 | ||
638 | return 0; | 782 | return hp; |
639 | } | 783 | } |
784 | EXPORT_SYMBOL(hvc_alloc); | ||
640 | 785 | ||
641 | static int __devexit hvc_remove(struct vio_dev *dev) | 786 | int __devexit hvc_remove(struct hvc_struct *hp) |
642 | { | 787 | { |
643 | struct hvc_struct *hp = dev->dev.driver_data; | ||
644 | unsigned long flags; | 788 | unsigned long flags; |
645 | struct kobject *kobjp; | 789 | struct kobject *kobjp; |
646 | struct tty_struct *tty; | 790 | struct tty_struct *tty; |
@@ -673,23 +817,14 @@ static int __devexit hvc_remove(struct vio_dev *dev) | |||
673 | tty_hangup(tty); | 817 | tty_hangup(tty); |
674 | return 0; | 818 | return 0; |
675 | } | 819 | } |
676 | 820 | EXPORT_SYMBOL(hvc_remove); | |
677 | static struct vio_driver hvc_vio_driver = { | ||
678 | .name = hvc_driver_name, | ||
679 | .id_table = hvc_driver_table, | ||
680 | .probe = hvc_probe, | ||
681 | .remove = hvc_remove, | ||
682 | }; | ||
683 | 821 | ||
684 | /* Driver initialization. Follow console initialization. This is where the TTY | 822 | /* Driver initialization. Follow console initialization. This is where the TTY |
685 | * interfaces start to become available. */ | 823 | * interfaces start to become available. */ |
686 | int __init hvc_init(void) | 824 | int __init hvc_init(void) |
687 | { | 825 | { |
688 | int rc; | 826 | /* We need more than hvc_count adapters due to hotplug additions. */ |
689 | |||
690 | /* We need more than num_vterms adapters due to hotplug additions. */ | ||
691 | hvc_driver = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS); | 827 | hvc_driver = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS); |
692 | /* hvc_driver = alloc_tty_driver(num_vterms); */ | ||
693 | if (!hvc_driver) | 828 | if (!hvc_driver) |
694 | return -ENOMEM; | 829 | return -ENOMEM; |
695 | 830 | ||
@@ -716,116 +851,20 @@ int __init hvc_init(void) | |||
716 | return -EIO; | 851 | return -EIO; |
717 | } | 852 | } |
718 | 853 | ||
719 | /* Register as a vio device to receive callbacks */ | 854 | return 0; |
720 | rc = vio_register_driver(&hvc_vio_driver); | ||
721 | |||
722 | return rc; | ||
723 | } | 855 | } |
856 | module_init(hvc_init); | ||
724 | 857 | ||
725 | /* This isn't particularily necessary due to this being a console driver but it | 858 | /* This isn't particularily necessary due to this being a console driver |
726 | * is nice to be thorough */ | 859 | * but it is nice to be thorough. |
860 | */ | ||
727 | static void __exit hvc_exit(void) | 861 | static void __exit hvc_exit(void) |
728 | { | 862 | { |
729 | kthread_stop(hvc_task); | 863 | kthread_stop(hvc_task); |
730 | 864 | ||
731 | vio_unregister_driver(&hvc_vio_driver); | ||
732 | tty_unregister_driver(hvc_driver); | 865 | tty_unregister_driver(hvc_driver); |
733 | /* return tty_struct instances allocated in hvc_init(). */ | 866 | /* return tty_struct instances allocated in hvc_init(). */ |
734 | put_tty_driver(hvc_driver); | 867 | put_tty_driver(hvc_driver); |
868 | unregister_console(&hvc_con_driver); | ||
735 | } | 869 | } |
736 | |||
737 | /* | ||
738 | * Console APIs, NOT TTY. These APIs are available immediately when | ||
739 | * hvc_console_setup() finds adapters. | ||
740 | */ | ||
741 | |||
742 | /* | ||
743 | * hvc_instantiate() is an early console discovery method which locates consoles | ||
744 | * prior to the vio subsystem discovering them. Hotplugged vty adapters do NOT | ||
745 | * get an hvc_instantiate() callback since the appear after early console init. | ||
746 | */ | ||
747 | int hvc_instantiate(uint32_t vtermno, int index) | ||
748 | { | ||
749 | if (index < 0 || index >= MAX_NR_HVC_CONSOLES) | ||
750 | return -1; | ||
751 | |||
752 | if (vtermnos[index] != -1) | ||
753 | return -1; | ||
754 | |||
755 | vtermnos[index] = vtermno; | ||
756 | return 0; | ||
757 | } | ||
758 | |||
759 | void hvc_console_print(struct console *co, const char *b, unsigned count) | ||
760 | { | ||
761 | char c[16] __ALIGNED__; | ||
762 | unsigned i = 0, n = 0; | ||
763 | int r, donecr = 0; | ||
764 | |||
765 | /* Console access attempt outside of acceptable console range. */ | ||
766 | if (co->index >= MAX_NR_HVC_CONSOLES) | ||
767 | return; | ||
768 | |||
769 | /* This console adapter was removed so it is not useable. */ | ||
770 | if (vtermnos[co->index] < 0) | ||
771 | return; | ||
772 | |||
773 | while (count > 0 || i > 0) { | ||
774 | if (count > 0 && i < sizeof(c)) { | ||
775 | if (b[n] == '\n' && !donecr) { | ||
776 | c[i++] = '\r'; | ||
777 | donecr = 1; | ||
778 | } else { | ||
779 | c[i++] = b[n++]; | ||
780 | donecr = 0; | ||
781 | --count; | ||
782 | } | ||
783 | } else { | ||
784 | r = hvc_put_chars(vtermnos[co->index], c, i); | ||
785 | if (r < 0) { | ||
786 | /* throw away chars on error */ | ||
787 | i = 0; | ||
788 | } else if (r > 0) { | ||
789 | i -= r; | ||
790 | if (i > 0) | ||
791 | memmove(c, c+r, i); | ||
792 | } | ||
793 | } | ||
794 | } | ||
795 | } | ||
796 | |||
797 | static struct tty_driver *hvc_console_device(struct console *c, int *index) | ||
798 | { | ||
799 | *index = c->index; | ||
800 | return hvc_driver; | ||
801 | } | ||
802 | |||
803 | static int __init hvc_console_setup(struct console *co, char *options) | ||
804 | { | ||
805 | return 0; | ||
806 | } | ||
807 | |||
808 | struct console hvc_con_driver = { | ||
809 | .name = "hvc", | ||
810 | .write = hvc_console_print, | ||
811 | .device = hvc_console_device, | ||
812 | .setup = hvc_console_setup, | ||
813 | .flags = CON_PRINTBUFFER, | ||
814 | .index = -1, | ||
815 | }; | ||
816 | |||
817 | /* Early console initialization. Preceeds driver initialization. */ | ||
818 | static int __init hvc_console_init(void) | ||
819 | { | ||
820 | int i; | ||
821 | |||
822 | for (i=0; i<MAX_NR_HVC_CONSOLES; i++) | ||
823 | vtermnos[i] = -1; | ||
824 | num_vterms = hvc_find_vtys(); | ||
825 | register_console(&hvc_con_driver); | ||
826 | return 0; | ||
827 | } | ||
828 | console_initcall(hvc_console_init); | ||
829 | |||
830 | module_init(hvc_init); | ||
831 | module_exit(hvc_exit); | 870 | module_exit(hvc_exit); |