diff options
Diffstat (limited to 'drivers/tty/hvc/hvc_console.c')
-rw-r--r-- | drivers/tty/hvc/hvc_console.c | 914 |
1 files changed, 914 insertions, 0 deletions
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c new file mode 100644 index 000000000000..e9cba13ee800 --- /dev/null +++ b/drivers/tty/hvc/hvc_console.c | |||
@@ -0,0 +1,914 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2001 Anton Blanchard <anton@au.ibm.com>, IBM | ||
3 | * Copyright (C) 2001 Paul Mackerras <paulus@au.ibm.com>, IBM | ||
4 | * Copyright (C) 2004 Benjamin Herrenschmidt <benh@kernel.crashing.org>, IBM Corp. | ||
5 | * Copyright (C) 2004 IBM Corporation | ||
6 | * | ||
7 | * Additional Author(s): | ||
8 | * Ryan S. Arnold <rsa@us.ibm.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License as published by | ||
12 | * the Free Software Foundation; either version 2 of the License, or | ||
13 | * (at your option) any later version. | ||
14 | * | ||
15 | * This program is distributed in the hope that it will be useful, | ||
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | * GNU General Public License for more details. | ||
19 | * | ||
20 | * You should have received a copy of the GNU General Public License | ||
21 | * along with this program; if not, write to the Free Software | ||
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
23 | */ | ||
24 | |||
25 | #include <linux/console.h> | ||
26 | #include <linux/cpumask.h> | ||
27 | #include <linux/init.h> | ||
28 | #include <linux/kbd_kern.h> | ||
29 | #include <linux/kernel.h> | ||
30 | #include <linux/kthread.h> | ||
31 | #include <linux/list.h> | ||
32 | #include <linux/module.h> | ||
33 | #include <linux/major.h> | ||
34 | #include <linux/sysrq.h> | ||
35 | #include <linux/tty.h> | ||
36 | #include <linux/tty_flip.h> | ||
37 | #include <linux/sched.h> | ||
38 | #include <linux/spinlock.h> | ||
39 | #include <linux/delay.h> | ||
40 | #include <linux/freezer.h> | ||
41 | #include <linux/slab.h> | ||
42 | |||
43 | #include <asm/uaccess.h> | ||
44 | |||
45 | #include "hvc_console.h" | ||
46 | |||
47 | #define HVC_MAJOR 229 | ||
48 | #define HVC_MINOR 0 | ||
49 | |||
50 | /* | ||
51 | * Wait this long per iteration while trying to push buffered data to the | ||
52 | * hypervisor before allowing the tty to complete a close operation. | ||
53 | */ | ||
54 | #define HVC_CLOSE_WAIT (HZ/100) /* 1/10 of a second */ | ||
55 | |||
56 | /* | ||
57 | * These sizes are most efficient for vio, because they are the | ||
58 | * native transfer size. We could make them selectable in the | ||
59 | * future to better deal with backends that want other buffer sizes. | ||
60 | */ | ||
61 | #define N_OUTBUF 16 | ||
62 | #define N_INBUF 16 | ||
63 | |||
64 | #define __ALIGNED__ __attribute__((__aligned__(sizeof(long)))) | ||
65 | |||
66 | static struct tty_driver *hvc_driver; | ||
67 | static struct task_struct *hvc_task; | ||
68 | |||
69 | /* Picks up late kicks after list walk but before schedule() */ | ||
70 | static int hvc_kicked; | ||
71 | |||
72 | static int hvc_init(void); | ||
73 | |||
74 | #ifdef CONFIG_MAGIC_SYSRQ | ||
75 | static int sysrq_pressed; | ||
76 | #endif | ||
77 | |||
78 | /* dynamic list of hvc_struct instances */ | ||
79 | static LIST_HEAD(hvc_structs); | ||
80 | |||
81 | /* | ||
82 | * Protect the list of hvc_struct instances from inserts and removals during | ||
83 | * list traversal. | ||
84 | */ | ||
85 | static DEFINE_SPINLOCK(hvc_structs_lock); | ||
86 | |||
87 | /* | ||
88 | * This value is used to assign a tty->index value to a hvc_struct based | ||
89 | * upon order of exposure via hvc_probe(), when we can not match it to | ||
90 | * a console candidate registered with hvc_instantiate(). | ||
91 | */ | ||
92 | static int last_hvc = -1; | ||
93 | |||
94 | /* | ||
95 | * Do not call this function with either the hvc_structs_lock or the hvc_struct | ||
96 | * lock held. If successful, this function increments the kref reference | ||
97 | * count against the target hvc_struct so it should be released when finished. | ||
98 | */ | ||
99 | static struct hvc_struct *hvc_get_by_index(int index) | ||
100 | { | ||
101 | struct hvc_struct *hp; | ||
102 | unsigned long flags; | ||
103 | |||
104 | spin_lock(&hvc_structs_lock); | ||
105 | |||
106 | list_for_each_entry(hp, &hvc_structs, next) { | ||
107 | spin_lock_irqsave(&hp->lock, flags); | ||
108 | if (hp->index == index) { | ||
109 | kref_get(&hp->kref); | ||
110 | spin_unlock_irqrestore(&hp->lock, flags); | ||
111 | spin_unlock(&hvc_structs_lock); | ||
112 | return hp; | ||
113 | } | ||
114 | spin_unlock_irqrestore(&hp->lock, flags); | ||
115 | } | ||
116 | hp = NULL; | ||
117 | |||
118 | spin_unlock(&hvc_structs_lock); | ||
119 | return hp; | ||
120 | } | ||
121 | |||
122 | |||
123 | /* | ||
124 | * Initial console vtermnos for console API usage prior to full console | ||
125 | * initialization. Any vty adapter outside this range will not have usable | ||
126 | * console interfaces but can still be used as a tty device. This has to be | ||
127 | * static because kmalloc will not work during early console init. | ||
128 | */ | ||
129 | static const struct hv_ops *cons_ops[MAX_NR_HVC_CONSOLES]; | ||
130 | static uint32_t vtermnos[MAX_NR_HVC_CONSOLES] = | ||
131 | {[0 ... MAX_NR_HVC_CONSOLES - 1] = -1}; | ||
132 | |||
133 | /* | ||
134 | * Console APIs, NOT TTY. These APIs are available immediately when | ||
135 | * hvc_console_setup() finds adapters. | ||
136 | */ | ||
137 | |||
138 | static void hvc_console_print(struct console *co, const char *b, | ||
139 | unsigned count) | ||
140 | { | ||
141 | char c[N_OUTBUF] __ALIGNED__; | ||
142 | unsigned i = 0, n = 0; | ||
143 | int r, donecr = 0, index = co->index; | ||
144 | |||
145 | /* Console access attempt outside of acceptable console range. */ | ||
146 | if (index >= MAX_NR_HVC_CONSOLES) | ||
147 | return; | ||
148 | |||
149 | /* This console adapter was removed so it is not usable. */ | ||
150 | if (vtermnos[index] == -1) | ||
151 | return; | ||
152 | |||
153 | while (count > 0 || i > 0) { | ||
154 | if (count > 0 && i < sizeof(c)) { | ||
155 | if (b[n] == '\n' && !donecr) { | ||
156 | c[i++] = '\r'; | ||
157 | donecr = 1; | ||
158 | } else { | ||
159 | c[i++] = b[n++]; | ||
160 | donecr = 0; | ||
161 | --count; | ||
162 | } | ||
163 | } else { | ||
164 | r = cons_ops[index]->put_chars(vtermnos[index], c, i); | ||
165 | if (r <= 0) { | ||
166 | /* throw away chars on error */ | ||
167 | i = 0; | ||
168 | } else if (r > 0) { | ||
169 | i -= r; | ||
170 | if (i > 0) | ||
171 | memmove(c, c+r, i); | ||
172 | } | ||
173 | } | ||
174 | } | ||
175 | } | ||
176 | |||
177 | static struct tty_driver *hvc_console_device(struct console *c, int *index) | ||
178 | { | ||
179 | if (vtermnos[c->index] == -1) | ||
180 | return NULL; | ||
181 | |||
182 | *index = c->index; | ||
183 | return hvc_driver; | ||
184 | } | ||
185 | |||
186 | static int __init hvc_console_setup(struct console *co, char *options) | ||
187 | { | ||
188 | if (co->index < 0 || co->index >= MAX_NR_HVC_CONSOLES) | ||
189 | return -ENODEV; | ||
190 | |||
191 | if (vtermnos[co->index] == -1) | ||
192 | return -ENODEV; | ||
193 | |||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | static struct console hvc_console = { | ||
198 | .name = "hvc", | ||
199 | .write = hvc_console_print, | ||
200 | .device = hvc_console_device, | ||
201 | .setup = hvc_console_setup, | ||
202 | .flags = CON_PRINTBUFFER, | ||
203 | .index = -1, | ||
204 | }; | ||
205 | |||
206 | /* | ||
207 | * Early console initialization. Precedes driver initialization. | ||
208 | * | ||
209 | * (1) we are first, and the user specified another driver | ||
210 | * -- index will remain -1 | ||
211 | * (2) we are first and the user specified no driver | ||
212 | * -- index will be set to 0, then we will fail setup. | ||
213 | * (3) we are first and the user specified our driver | ||
214 | * -- index will be set to user specified driver, and we will fail | ||
215 | * (4) we are after driver, and this initcall will register us | ||
216 | * -- if the user didn't specify a driver then the console will match | ||
217 | * | ||
218 | * Note that for cases 2 and 3, we will match later when the io driver | ||
219 | * calls hvc_instantiate() and call register again. | ||
220 | */ | ||
221 | static int __init hvc_console_init(void) | ||
222 | { | ||
223 | register_console(&hvc_console); | ||
224 | return 0; | ||
225 | } | ||
226 | console_initcall(hvc_console_init); | ||
227 | |||
228 | /* callback when the kboject ref count reaches zero. */ | ||
229 | static void destroy_hvc_struct(struct kref *kref) | ||
230 | { | ||
231 | struct hvc_struct *hp = container_of(kref, struct hvc_struct, kref); | ||
232 | unsigned long flags; | ||
233 | |||
234 | spin_lock(&hvc_structs_lock); | ||
235 | |||
236 | spin_lock_irqsave(&hp->lock, flags); | ||
237 | list_del(&(hp->next)); | ||
238 | spin_unlock_irqrestore(&hp->lock, flags); | ||
239 | |||
240 | spin_unlock(&hvc_structs_lock); | ||
241 | |||
242 | kfree(hp); | ||
243 | } | ||
244 | |||
245 | /* | ||
246 | * hvc_instantiate() is an early console discovery method which locates | ||
247 | * consoles * prior to the vio subsystem discovering them. Hotplugged | ||
248 | * vty adapters do NOT get an hvc_instantiate() callback since they | ||
249 | * appear after early console init. | ||
250 | */ | ||
251 | int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops) | ||
252 | { | ||
253 | struct hvc_struct *hp; | ||
254 | |||
255 | if (index < 0 || index >= MAX_NR_HVC_CONSOLES) | ||
256 | return -1; | ||
257 | |||
258 | if (vtermnos[index] != -1) | ||
259 | return -1; | ||
260 | |||
261 | /* make sure no no tty has been registered in this index */ | ||
262 | hp = hvc_get_by_index(index); | ||
263 | if (hp) { | ||
264 | kref_put(&hp->kref, destroy_hvc_struct); | ||
265 | return -1; | ||
266 | } | ||
267 | |||
268 | vtermnos[index] = vtermno; | ||
269 | cons_ops[index] = ops; | ||
270 | |||
271 | /* reserve all indices up to and including this index */ | ||
272 | if (last_hvc < index) | ||
273 | last_hvc = index; | ||
274 | |||
275 | /* if this index is what the user requested, then register | ||
276 | * now (setup won't fail at this point). It's ok to just | ||
277 | * call register again if previously .setup failed. | ||
278 | */ | ||
279 | if (index == hvc_console.index) | ||
280 | register_console(&hvc_console); | ||
281 | |||
282 | return 0; | ||
283 | } | ||
284 | EXPORT_SYMBOL_GPL(hvc_instantiate); | ||
285 | |||
286 | /* Wake the sleeping khvcd */ | ||
287 | void hvc_kick(void) | ||
288 | { | ||
289 | hvc_kicked = 1; | ||
290 | wake_up_process(hvc_task); | ||
291 | } | ||
292 | EXPORT_SYMBOL_GPL(hvc_kick); | ||
293 | |||
294 | static void hvc_unthrottle(struct tty_struct *tty) | ||
295 | { | ||
296 | hvc_kick(); | ||
297 | } | ||
298 | |||
299 | /* | ||
300 | * The TTY interface won't be used until after the vio layer has exposed the vty | ||
301 | * adapter to the kernel. | ||
302 | */ | ||
303 | static int hvc_open(struct tty_struct *tty, struct file * filp) | ||
304 | { | ||
305 | struct hvc_struct *hp; | ||
306 | unsigned long flags; | ||
307 | int rc = 0; | ||
308 | |||
309 | /* Auto increments kref reference if found. */ | ||
310 | if (!(hp = hvc_get_by_index(tty->index))) | ||
311 | return -ENODEV; | ||
312 | |||
313 | spin_lock_irqsave(&hp->lock, flags); | ||
314 | /* Check and then increment for fast path open. */ | ||
315 | if (hp->count++ > 0) { | ||
316 | tty_kref_get(tty); | ||
317 | spin_unlock_irqrestore(&hp->lock, flags); | ||
318 | hvc_kick(); | ||
319 | return 0; | ||
320 | } /* else count == 0 */ | ||
321 | |||
322 | tty->driver_data = hp; | ||
323 | |||
324 | hp->tty = tty_kref_get(tty); | ||
325 | |||
326 | spin_unlock_irqrestore(&hp->lock, flags); | ||
327 | |||
328 | if (hp->ops->notifier_add) | ||
329 | rc = hp->ops->notifier_add(hp, hp->data); | ||
330 | |||
331 | /* | ||
332 | * If the notifier fails we return an error. The tty layer | ||
333 | * will call hvc_close() after a failed open but we don't want to clean | ||
334 | * up there so we'll clean up here and clear out the previously set | ||
335 | * tty fields and return the kref reference. | ||
336 | */ | ||
337 | if (rc) { | ||
338 | spin_lock_irqsave(&hp->lock, flags); | ||
339 | hp->tty = NULL; | ||
340 | spin_unlock_irqrestore(&hp->lock, flags); | ||
341 | tty_kref_put(tty); | ||
342 | tty->driver_data = NULL; | ||
343 | kref_put(&hp->kref, destroy_hvc_struct); | ||
344 | printk(KERN_ERR "hvc_open: request_irq failed with rc %d.\n", rc); | ||
345 | } | ||
346 | /* Force wakeup of the polling thread */ | ||
347 | hvc_kick(); | ||
348 | |||
349 | return rc; | ||
350 | } | ||
351 | |||
352 | static void hvc_close(struct tty_struct *tty, struct file * filp) | ||
353 | { | ||
354 | struct hvc_struct *hp; | ||
355 | unsigned long flags; | ||
356 | |||
357 | if (tty_hung_up_p(filp)) | ||
358 | return; | ||
359 | |||
360 | /* | ||
361 | * No driver_data means that this close was issued after a failed | ||
362 | * hvc_open by the tty layer's release_dev() function and we can just | ||
363 | * exit cleanly because the kref reference wasn't made. | ||
364 | */ | ||
365 | if (!tty->driver_data) | ||
366 | return; | ||
367 | |||
368 | hp = tty->driver_data; | ||
369 | |||
370 | spin_lock_irqsave(&hp->lock, flags); | ||
371 | |||
372 | if (--hp->count == 0) { | ||
373 | /* We are done with the tty pointer now. */ | ||
374 | hp->tty = NULL; | ||
375 | spin_unlock_irqrestore(&hp->lock, flags); | ||
376 | |||
377 | if (hp->ops->notifier_del) | ||
378 | hp->ops->notifier_del(hp, hp->data); | ||
379 | |||
380 | /* cancel pending tty resize work */ | ||
381 | cancel_work_sync(&hp->tty_resize); | ||
382 | |||
383 | /* | ||
384 | * Chain calls chars_in_buffer() and returns immediately if | ||
385 | * there is no buffered data otherwise sleeps on a wait queue | ||
386 | * waking periodically to check chars_in_buffer(). | ||
387 | */ | ||
388 | tty_wait_until_sent(tty, HVC_CLOSE_WAIT); | ||
389 | } else { | ||
390 | if (hp->count < 0) | ||
391 | printk(KERN_ERR "hvc_close %X: oops, count is %d\n", | ||
392 | hp->vtermno, hp->count); | ||
393 | spin_unlock_irqrestore(&hp->lock, flags); | ||
394 | } | ||
395 | |||
396 | tty_kref_put(tty); | ||
397 | kref_put(&hp->kref, destroy_hvc_struct); | ||
398 | } | ||
399 | |||
400 | static void hvc_hangup(struct tty_struct *tty) | ||
401 | { | ||
402 | struct hvc_struct *hp = tty->driver_data; | ||
403 | unsigned long flags; | ||
404 | int temp_open_count; | ||
405 | |||
406 | if (!hp) | ||
407 | return; | ||
408 | |||
409 | /* cancel pending tty resize work */ | ||
410 | cancel_work_sync(&hp->tty_resize); | ||
411 | |||
412 | spin_lock_irqsave(&hp->lock, flags); | ||
413 | |||
414 | /* | ||
415 | * The N_TTY line discipline has problems such that in a close vs | ||
416 | * open->hangup case this can be called after the final close so prevent | ||
417 | * that from happening for now. | ||
418 | */ | ||
419 | if (hp->count <= 0) { | ||
420 | spin_unlock_irqrestore(&hp->lock, flags); | ||
421 | return; | ||
422 | } | ||
423 | |||
424 | temp_open_count = hp->count; | ||
425 | hp->count = 0; | ||
426 | hp->n_outbuf = 0; | ||
427 | hp->tty = NULL; | ||
428 | |||
429 | spin_unlock_irqrestore(&hp->lock, flags); | ||
430 | |||
431 | if (hp->ops->notifier_hangup) | ||
432 | hp->ops->notifier_hangup(hp, hp->data); | ||
433 | |||
434 | while(temp_open_count) { | ||
435 | --temp_open_count; | ||
436 | tty_kref_put(tty); | ||
437 | kref_put(&hp->kref, destroy_hvc_struct); | ||
438 | } | ||
439 | } | ||
440 | |||
441 | /* | ||
442 | * Push buffered characters whether they were just recently buffered or waiting | ||
443 | * on a blocked hypervisor. Call this function with hp->lock held. | ||
444 | */ | ||
445 | static int hvc_push(struct hvc_struct *hp) | ||
446 | { | ||
447 | int n; | ||
448 | |||
449 | n = hp->ops->put_chars(hp->vtermno, hp->outbuf, hp->n_outbuf); | ||
450 | if (n <= 0) { | ||
451 | if (n == 0) { | ||
452 | hp->do_wakeup = 1; | ||
453 | return 0; | ||
454 | } | ||
455 | /* throw away output on error; this happens when | ||
456 | there is no session connected to the vterm. */ | ||
457 | hp->n_outbuf = 0; | ||
458 | } else | ||
459 | hp->n_outbuf -= n; | ||
460 | if (hp->n_outbuf > 0) | ||
461 | memmove(hp->outbuf, hp->outbuf + n, hp->n_outbuf); | ||
462 | else | ||
463 | hp->do_wakeup = 1; | ||
464 | |||
465 | return n; | ||
466 | } | ||
467 | |||
468 | static int hvc_write(struct tty_struct *tty, const unsigned char *buf, int count) | ||
469 | { | ||
470 | struct hvc_struct *hp = tty->driver_data; | ||
471 | unsigned long flags; | ||
472 | int rsize, written = 0; | ||
473 | |||
474 | /* This write was probably executed during a tty close. */ | ||
475 | if (!hp) | ||
476 | return -EPIPE; | ||
477 | |||
478 | if (hp->count <= 0) | ||
479 | return -EIO; | ||
480 | |||
481 | spin_lock_irqsave(&hp->lock, flags); | ||
482 | |||
483 | /* Push pending writes */ | ||
484 | if (hp->n_outbuf > 0) | ||
485 | hvc_push(hp); | ||
486 | |||
487 | while (count > 0 && (rsize = hp->outbuf_size - hp->n_outbuf) > 0) { | ||
488 | if (rsize > count) | ||
489 | rsize = count; | ||
490 | memcpy(hp->outbuf + hp->n_outbuf, buf, rsize); | ||
491 | count -= rsize; | ||
492 | buf += rsize; | ||
493 | hp->n_outbuf += rsize; | ||
494 | written += rsize; | ||
495 | hvc_push(hp); | ||
496 | } | ||
497 | spin_unlock_irqrestore(&hp->lock, flags); | ||
498 | |||
499 | /* | ||
500 | * Racy, but harmless, kick thread if there is still pending data. | ||
501 | */ | ||
502 | if (hp->n_outbuf) | ||
503 | hvc_kick(); | ||
504 | |||
505 | return written; | ||
506 | } | ||
507 | |||
508 | /** | ||
509 | * hvc_set_winsz() - Resize the hvc tty terminal window. | ||
510 | * @work: work structure. | ||
511 | * | ||
512 | * The routine shall not be called within an atomic context because it | ||
513 | * might sleep. | ||
514 | * | ||
515 | * Locking: hp->lock | ||
516 | */ | ||
517 | static void hvc_set_winsz(struct work_struct *work) | ||
518 | { | ||
519 | struct hvc_struct *hp; | ||
520 | unsigned long hvc_flags; | ||
521 | struct tty_struct *tty; | ||
522 | struct winsize ws; | ||
523 | |||
524 | hp = container_of(work, struct hvc_struct, tty_resize); | ||
525 | |||
526 | spin_lock_irqsave(&hp->lock, hvc_flags); | ||
527 | if (!hp->tty) { | ||
528 | spin_unlock_irqrestore(&hp->lock, hvc_flags); | ||
529 | return; | ||
530 | } | ||
531 | ws = hp->ws; | ||
532 | tty = tty_kref_get(hp->tty); | ||
533 | spin_unlock_irqrestore(&hp->lock, hvc_flags); | ||
534 | |||
535 | tty_do_resize(tty, &ws); | ||
536 | tty_kref_put(tty); | ||
537 | } | ||
538 | |||
539 | /* | ||
540 | * This is actually a contract between the driver and the tty layer outlining | ||
541 | * how much write room the driver can guarantee will be sent OR BUFFERED. This | ||
542 | * driver MUST honor the return value. | ||
543 | */ | ||
544 | static int hvc_write_room(struct tty_struct *tty) | ||
545 | { | ||
546 | struct hvc_struct *hp = tty->driver_data; | ||
547 | |||
548 | if (!hp) | ||
549 | return -1; | ||
550 | |||
551 | return hp->outbuf_size - hp->n_outbuf; | ||
552 | } | ||
553 | |||
554 | static int hvc_chars_in_buffer(struct tty_struct *tty) | ||
555 | { | ||
556 | struct hvc_struct *hp = tty->driver_data; | ||
557 | |||
558 | if (!hp) | ||
559 | return 0; | ||
560 | return hp->n_outbuf; | ||
561 | } | ||
562 | |||
563 | /* | ||
564 | * timeout will vary between the MIN and MAX values defined here. By default | ||
565 | * and during console activity we will use a default MIN_TIMEOUT of 10. When | ||
566 | * the console is idle, we increase the timeout value on each pass through | ||
567 | * msleep until we reach the max. This may be noticeable as a brief (average | ||
568 | * one second) delay on the console before the console responds to input when | ||
569 | * there has been no input for some time. | ||
570 | */ | ||
571 | #define MIN_TIMEOUT (10) | ||
572 | #define MAX_TIMEOUT (2000) | ||
573 | static u32 timeout = MIN_TIMEOUT; | ||
574 | |||
575 | #define HVC_POLL_READ 0x00000001 | ||
576 | #define HVC_POLL_WRITE 0x00000002 | ||
577 | |||
578 | int hvc_poll(struct hvc_struct *hp) | ||
579 | { | ||
580 | struct tty_struct *tty; | ||
581 | int i, n, poll_mask = 0; | ||
582 | char buf[N_INBUF] __ALIGNED__; | ||
583 | unsigned long flags; | ||
584 | int read_total = 0; | ||
585 | int written_total = 0; | ||
586 | |||
587 | spin_lock_irqsave(&hp->lock, flags); | ||
588 | |||
589 | /* Push pending writes */ | ||
590 | if (hp->n_outbuf > 0) | ||
591 | written_total = hvc_push(hp); | ||
592 | |||
593 | /* Reschedule us if still some write pending */ | ||
594 | if (hp->n_outbuf > 0) { | ||
595 | poll_mask |= HVC_POLL_WRITE; | ||
596 | /* If hvc_push() was not able to write, sleep a few msecs */ | ||
597 | timeout = (written_total) ? 0 : MIN_TIMEOUT; | ||
598 | } | ||
599 | |||
600 | /* No tty attached, just skip */ | ||
601 | tty = tty_kref_get(hp->tty); | ||
602 | if (tty == NULL) | ||
603 | goto bail; | ||
604 | |||
605 | /* Now check if we can get data (are we throttled ?) */ | ||
606 | if (test_bit(TTY_THROTTLED, &tty->flags)) | ||
607 | goto throttled; | ||
608 | |||
609 | /* If we aren't notifier driven and aren't throttled, we always | ||
610 | * request a reschedule | ||
611 | */ | ||
612 | if (!hp->irq_requested) | ||
613 | poll_mask |= HVC_POLL_READ; | ||
614 | |||
615 | /* Read data if any */ | ||
616 | for (;;) { | ||
617 | int count = tty_buffer_request_room(tty, N_INBUF); | ||
618 | |||
619 | /* If flip is full, just reschedule a later read */ | ||
620 | if (count == 0) { | ||
621 | poll_mask |= HVC_POLL_READ; | ||
622 | break; | ||
623 | } | ||
624 | |||
625 | n = hp->ops->get_chars(hp->vtermno, buf, count); | ||
626 | if (n <= 0) { | ||
627 | /* Hangup the tty when disconnected from host */ | ||
628 | if (n == -EPIPE) { | ||
629 | spin_unlock_irqrestore(&hp->lock, flags); | ||
630 | tty_hangup(tty); | ||
631 | spin_lock_irqsave(&hp->lock, flags); | ||
632 | } else if ( n == -EAGAIN ) { | ||
633 | /* | ||
634 | * Some back-ends can only ensure a certain min | ||
635 | * num of bytes read, which may be > 'count'. | ||
636 | * Let the tty clear the flip buff to make room. | ||
637 | */ | ||
638 | poll_mask |= HVC_POLL_READ; | ||
639 | } | ||
640 | break; | ||
641 | } | ||
642 | for (i = 0; i < n; ++i) { | ||
643 | #ifdef CONFIG_MAGIC_SYSRQ | ||
644 | if (hp->index == hvc_console.index) { | ||
645 | /* Handle the SysRq Hack */ | ||
646 | /* XXX should support a sequence */ | ||
647 | if (buf[i] == '\x0f') { /* ^O */ | ||
648 | /* if ^O is pressed again, reset | ||
649 | * sysrq_pressed and flip ^O char */ | ||
650 | sysrq_pressed = !sysrq_pressed; | ||
651 | if (sysrq_pressed) | ||
652 | continue; | ||
653 | } else if (sysrq_pressed) { | ||
654 | handle_sysrq(buf[i]); | ||
655 | sysrq_pressed = 0; | ||
656 | continue; | ||
657 | } | ||
658 | } | ||
659 | #endif /* CONFIG_MAGIC_SYSRQ */ | ||
660 | tty_insert_flip_char(tty, buf[i], 0); | ||
661 | } | ||
662 | |||
663 | read_total += n; | ||
664 | } | ||
665 | throttled: | ||
666 | /* Wakeup write queue if necessary */ | ||
667 | if (hp->do_wakeup) { | ||
668 | hp->do_wakeup = 0; | ||
669 | tty_wakeup(tty); | ||
670 | } | ||
671 | bail: | ||
672 | spin_unlock_irqrestore(&hp->lock, flags); | ||
673 | |||
674 | if (read_total) { | ||
675 | /* Activity is occurring, so reset the polling backoff value to | ||
676 | a minimum for performance. */ | ||
677 | timeout = MIN_TIMEOUT; | ||
678 | |||
679 | tty_flip_buffer_push(tty); | ||
680 | } | ||
681 | if (tty) | ||
682 | tty_kref_put(tty); | ||
683 | |||
684 | return poll_mask; | ||
685 | } | ||
686 | EXPORT_SYMBOL_GPL(hvc_poll); | ||
687 | |||
688 | /** | ||
689 | * __hvc_resize() - Update terminal window size information. | ||
690 | * @hp: HVC console pointer | ||
691 | * @ws: Terminal window size structure | ||
692 | * | ||
693 | * Stores the specified window size information in the hvc structure of @hp. | ||
694 | * The function schedule the tty resize update. | ||
695 | * | ||
696 | * Locking: Locking free; the function MUST be called holding hp->lock | ||
697 | */ | ||
698 | void __hvc_resize(struct hvc_struct *hp, struct winsize ws) | ||
699 | { | ||
700 | hp->ws = ws; | ||
701 | schedule_work(&hp->tty_resize); | ||
702 | } | ||
703 | EXPORT_SYMBOL_GPL(__hvc_resize); | ||
704 | |||
705 | /* | ||
706 | * This kthread is either polling or interrupt driven. This is determined by | ||
707 | * calling hvc_poll() who determines whether a console adapter support | ||
708 | * interrupts. | ||
709 | */ | ||
710 | static int khvcd(void *unused) | ||
711 | { | ||
712 | int poll_mask; | ||
713 | struct hvc_struct *hp; | ||
714 | |||
715 | set_freezable(); | ||
716 | do { | ||
717 | poll_mask = 0; | ||
718 | hvc_kicked = 0; | ||
719 | try_to_freeze(); | ||
720 | wmb(); | ||
721 | if (!cpus_are_in_xmon()) { | ||
722 | spin_lock(&hvc_structs_lock); | ||
723 | list_for_each_entry(hp, &hvc_structs, next) { | ||
724 | poll_mask |= hvc_poll(hp); | ||
725 | } | ||
726 | spin_unlock(&hvc_structs_lock); | ||
727 | } else | ||
728 | poll_mask |= HVC_POLL_READ; | ||
729 | if (hvc_kicked) | ||
730 | continue; | ||
731 | set_current_state(TASK_INTERRUPTIBLE); | ||
732 | if (!hvc_kicked) { | ||
733 | if (poll_mask == 0) | ||
734 | schedule(); | ||
735 | else { | ||
736 | if (timeout < MAX_TIMEOUT) | ||
737 | timeout += (timeout >> 6) + 1; | ||
738 | |||
739 | msleep_interruptible(timeout); | ||
740 | } | ||
741 | } | ||
742 | __set_current_state(TASK_RUNNING); | ||
743 | } while (!kthread_should_stop()); | ||
744 | |||
745 | return 0; | ||
746 | } | ||
747 | |||
748 | static const struct tty_operations hvc_ops = { | ||
749 | .open = hvc_open, | ||
750 | .close = hvc_close, | ||
751 | .write = hvc_write, | ||
752 | .hangup = hvc_hangup, | ||
753 | .unthrottle = hvc_unthrottle, | ||
754 | .write_room = hvc_write_room, | ||
755 | .chars_in_buffer = hvc_chars_in_buffer, | ||
756 | }; | ||
757 | |||
758 | struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, | ||
759 | const struct hv_ops *ops, | ||
760 | int outbuf_size) | ||
761 | { | ||
762 | struct hvc_struct *hp; | ||
763 | int i; | ||
764 | |||
765 | /* We wait until a driver actually comes along */ | ||
766 | if (!hvc_driver) { | ||
767 | int err = hvc_init(); | ||
768 | if (err) | ||
769 | return ERR_PTR(err); | ||
770 | } | ||
771 | |||
772 | hp = kzalloc(ALIGN(sizeof(*hp), sizeof(long)) + outbuf_size, | ||
773 | GFP_KERNEL); | ||
774 | if (!hp) | ||
775 | return ERR_PTR(-ENOMEM); | ||
776 | |||
777 | hp->vtermno = vtermno; | ||
778 | hp->data = data; | ||
779 | hp->ops = ops; | ||
780 | hp->outbuf_size = outbuf_size; | ||
781 | hp->outbuf = &((char *)hp)[ALIGN(sizeof(*hp), sizeof(long))]; | ||
782 | |||
783 | kref_init(&hp->kref); | ||
784 | |||
785 | INIT_WORK(&hp->tty_resize, hvc_set_winsz); | ||
786 | spin_lock_init(&hp->lock); | ||
787 | spin_lock(&hvc_structs_lock); | ||
788 | |||
789 | /* | ||
790 | * find index to use: | ||
791 | * see if this vterm id matches one registered for console. | ||
792 | */ | ||
793 | for (i=0; i < MAX_NR_HVC_CONSOLES; i++) | ||
794 | if (vtermnos[i] == hp->vtermno && | ||
795 | cons_ops[i] == hp->ops) | ||
796 | break; | ||
797 | |||
798 | /* no matching slot, just use a counter */ | ||
799 | if (i >= MAX_NR_HVC_CONSOLES) | ||
800 | i = ++last_hvc; | ||
801 | |||
802 | hp->index = i; | ||
803 | |||
804 | list_add_tail(&(hp->next), &hvc_structs); | ||
805 | spin_unlock(&hvc_structs_lock); | ||
806 | |||
807 | return hp; | ||
808 | } | ||
809 | EXPORT_SYMBOL_GPL(hvc_alloc); | ||
810 | |||
811 | int hvc_remove(struct hvc_struct *hp) | ||
812 | { | ||
813 | unsigned long flags; | ||
814 | struct tty_struct *tty; | ||
815 | |||
816 | spin_lock_irqsave(&hp->lock, flags); | ||
817 | tty = tty_kref_get(hp->tty); | ||
818 | |||
819 | if (hp->index < MAX_NR_HVC_CONSOLES) | ||
820 | vtermnos[hp->index] = -1; | ||
821 | |||
822 | /* Don't whack hp->irq because tty_hangup() will need to free the irq. */ | ||
823 | |||
824 | spin_unlock_irqrestore(&hp->lock, flags); | ||
825 | |||
826 | /* | ||
827 | * We 'put' the instance that was grabbed when the kref instance | ||
828 | * was initialized using kref_init(). Let the last holder of this | ||
829 | * kref cause it to be removed, which will probably be the tty_vhangup | ||
830 | * below. | ||
831 | */ | ||
832 | kref_put(&hp->kref, destroy_hvc_struct); | ||
833 | |||
834 | /* | ||
835 | * This function call will auto chain call hvc_hangup. | ||
836 | */ | ||
837 | if (tty) { | ||
838 | tty_vhangup(tty); | ||
839 | tty_kref_put(tty); | ||
840 | } | ||
841 | return 0; | ||
842 | } | ||
843 | EXPORT_SYMBOL_GPL(hvc_remove); | ||
844 | |||
845 | /* Driver initialization: called as soon as someone uses hvc_alloc(). */ | ||
846 | static int hvc_init(void) | ||
847 | { | ||
848 | struct tty_driver *drv; | ||
849 | int err; | ||
850 | |||
851 | /* We need more than hvc_count adapters due to hotplug additions. */ | ||
852 | drv = alloc_tty_driver(HVC_ALLOC_TTY_ADAPTERS); | ||
853 | if (!drv) { | ||
854 | err = -ENOMEM; | ||
855 | goto out; | ||
856 | } | ||
857 | |||
858 | drv->owner = THIS_MODULE; | ||
859 | drv->driver_name = "hvc"; | ||
860 | drv->name = "hvc"; | ||
861 | drv->major = HVC_MAJOR; | ||
862 | drv->minor_start = HVC_MINOR; | ||
863 | drv->type = TTY_DRIVER_TYPE_SYSTEM; | ||
864 | drv->init_termios = tty_std_termios; | ||
865 | drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS; | ||
866 | tty_set_operations(drv, &hvc_ops); | ||
867 | |||
868 | /* Always start the kthread because there can be hotplug vty adapters | ||
869 | * added later. */ | ||
870 | hvc_task = kthread_run(khvcd, NULL, "khvcd"); | ||
871 | if (IS_ERR(hvc_task)) { | ||
872 | printk(KERN_ERR "Couldn't create kthread for console.\n"); | ||
873 | err = PTR_ERR(hvc_task); | ||
874 | goto put_tty; | ||
875 | } | ||
876 | |||
877 | err = tty_register_driver(drv); | ||
878 | if (err) { | ||
879 | printk(KERN_ERR "Couldn't register hvc console driver\n"); | ||
880 | goto stop_thread; | ||
881 | } | ||
882 | |||
883 | /* | ||
884 | * Make sure tty is fully registered before allowing it to be | ||
885 | * found by hvc_console_device. | ||
886 | */ | ||
887 | smp_mb(); | ||
888 | hvc_driver = drv; | ||
889 | return 0; | ||
890 | |||
891 | stop_thread: | ||
892 | kthread_stop(hvc_task); | ||
893 | hvc_task = NULL; | ||
894 | put_tty: | ||
895 | put_tty_driver(drv); | ||
896 | out: | ||
897 | return err; | ||
898 | } | ||
899 | |||
900 | /* This isn't particularly necessary due to this being a console driver | ||
901 | * but it is nice to be thorough. | ||
902 | */ | ||
903 | static void __exit hvc_exit(void) | ||
904 | { | ||
905 | if (hvc_driver) { | ||
906 | kthread_stop(hvc_task); | ||
907 | |||
908 | tty_unregister_driver(hvc_driver); | ||
909 | /* return tty_struct instances allocated in hvc_init(). */ | ||
910 | put_tty_driver(hvc_driver); | ||
911 | unregister_console(&hvc_console); | ||
912 | } | ||
913 | } | ||
914 | module_exit(hvc_exit); | ||