diff options
Diffstat (limited to 'drivers/tty/hvc')
-rw-r--r-- | drivers/tty/hvc/hvc_console.c | 33 | ||||
-rw-r--r-- | drivers/tty/hvc/hvc_vio.c | 123 |
2 files changed, 96 insertions, 60 deletions
diff --git a/drivers/tty/hvc/hvc_console.c b/drivers/tty/hvc/hvc_console.c index 4a652999380f..a5dec1ca1b82 100644 --- a/drivers/tty/hvc/hvc_console.c +++ b/drivers/tty/hvc/hvc_console.c | |||
@@ -245,6 +245,20 @@ static void hvc_port_destruct(struct tty_port *port) | |||
245 | kfree(hp); | 245 | kfree(hp); |
246 | } | 246 | } |
247 | 247 | ||
248 | static void hvc_check_console(int index) | ||
249 | { | ||
250 | /* Already enabled, bail out */ | ||
251 | if (hvc_console.flags & CON_ENABLED) | ||
252 | return; | ||
253 | |||
254 | /* If this index is what the user requested, then register | ||
255 | * now (setup won't fail at this point). It's ok to just | ||
256 | * call register again if previously .setup failed. | ||
257 | */ | ||
258 | if (index == hvc_console.index) | ||
259 | register_console(&hvc_console); | ||
260 | } | ||
261 | |||
248 | /* | 262 | /* |
249 | * hvc_instantiate() is an early console discovery method which locates | 263 | * hvc_instantiate() is an early console discovery method which locates |
250 | * consoles * prior to the vio subsystem discovering them. Hotplugged | 264 | * consoles * prior to the vio subsystem discovering them. Hotplugged |
@@ -275,12 +289,8 @@ int hvc_instantiate(uint32_t vtermno, int index, const struct hv_ops *ops) | |||
275 | if (last_hvc < index) | 289 | if (last_hvc < index) |
276 | last_hvc = index; | 290 | last_hvc = index; |
277 | 291 | ||
278 | /* if this index is what the user requested, then register | 292 | /* check if we need to re-register the kernel console */ |
279 | * now (setup won't fail at this point). It's ok to just | 293 | hvc_check_console(index); |
280 | * call register again if previously .setup failed. | ||
281 | */ | ||
282 | if (index == hvc_console.index) | ||
283 | register_console(&hvc_console); | ||
284 | 294 | ||
285 | return 0; | 295 | return 0; |
286 | } | 296 | } |
@@ -877,10 +887,15 @@ struct hvc_struct *hvc_alloc(uint32_t vtermno, int data, | |||
877 | i = ++last_hvc; | 887 | i = ++last_hvc; |
878 | 888 | ||
879 | hp->index = i; | 889 | hp->index = i; |
890 | cons_ops[i] = ops; | ||
891 | vtermnos[i] = vtermno; | ||
880 | 892 | ||
881 | list_add_tail(&(hp->next), &hvc_structs); | 893 | list_add_tail(&(hp->next), &hvc_structs); |
882 | spin_unlock(&hvc_structs_lock); | 894 | spin_unlock(&hvc_structs_lock); |
883 | 895 | ||
896 | /* check if we need to re-register the kernel console */ | ||
897 | hvc_check_console(i); | ||
898 | |||
884 | return hp; | 899 | return hp; |
885 | } | 900 | } |
886 | EXPORT_SYMBOL_GPL(hvc_alloc); | 901 | EXPORT_SYMBOL_GPL(hvc_alloc); |
@@ -893,8 +908,12 @@ int hvc_remove(struct hvc_struct *hp) | |||
893 | tty = tty_port_tty_get(&hp->port); | 908 | tty = tty_port_tty_get(&hp->port); |
894 | 909 | ||
895 | spin_lock_irqsave(&hp->lock, flags); | 910 | spin_lock_irqsave(&hp->lock, flags); |
896 | if (hp->index < MAX_NR_HVC_CONSOLES) | 911 | if (hp->index < MAX_NR_HVC_CONSOLES) { |
912 | console_lock(); | ||
897 | vtermnos[hp->index] = -1; | 913 | vtermnos[hp->index] = -1; |
914 | cons_ops[hp->index] = NULL; | ||
915 | console_unlock(); | ||
916 | } | ||
898 | 917 | ||
899 | /* Don't whack hp->irq because tty_hangup() will need to free the irq. */ | 918 | /* Don't whack hp->irq because tty_hangup() will need to free the irq. */ |
900 | 919 | ||
diff --git a/drivers/tty/hvc/hvc_vio.c b/drivers/tty/hvc/hvc_vio.c index ee307799271a..070c0ee68642 100644 --- a/drivers/tty/hvc/hvc_vio.c +++ b/drivers/tty/hvc/hvc_vio.c | |||
@@ -230,6 +230,69 @@ static const struct hv_ops hvterm_hvsi_ops = { | |||
230 | .tiocmset = hvterm_hvsi_tiocmset, | 230 | .tiocmset = hvterm_hvsi_tiocmset, |
231 | }; | 231 | }; |
232 | 232 | ||
233 | static void udbg_hvc_putc(char c) | ||
234 | { | ||
235 | int count = -1; | ||
236 | |||
237 | if (!hvterm_privs[0]) | ||
238 | return; | ||
239 | |||
240 | if (c == '\n') | ||
241 | udbg_hvc_putc('\r'); | ||
242 | |||
243 | do { | ||
244 | switch(hvterm_privs[0]->proto) { | ||
245 | case HV_PROTOCOL_RAW: | ||
246 | count = hvterm_raw_put_chars(0, &c, 1); | ||
247 | break; | ||
248 | case HV_PROTOCOL_HVSI: | ||
249 | count = hvterm_hvsi_put_chars(0, &c, 1); | ||
250 | break; | ||
251 | } | ||
252 | } while(count == 0); | ||
253 | } | ||
254 | |||
255 | static int udbg_hvc_getc_poll(void) | ||
256 | { | ||
257 | int rc = 0; | ||
258 | char c; | ||
259 | |||
260 | if (!hvterm_privs[0]) | ||
261 | return -1; | ||
262 | |||
263 | switch(hvterm_privs[0]->proto) { | ||
264 | case HV_PROTOCOL_RAW: | ||
265 | rc = hvterm_raw_get_chars(0, &c, 1); | ||
266 | break; | ||
267 | case HV_PROTOCOL_HVSI: | ||
268 | rc = hvterm_hvsi_get_chars(0, &c, 1); | ||
269 | break; | ||
270 | } | ||
271 | if (!rc) | ||
272 | return -1; | ||
273 | return c; | ||
274 | } | ||
275 | |||
276 | static int udbg_hvc_getc(void) | ||
277 | { | ||
278 | int ch; | ||
279 | |||
280 | if (!hvterm_privs[0]) | ||
281 | return -1; | ||
282 | |||
283 | for (;;) { | ||
284 | ch = udbg_hvc_getc_poll(); | ||
285 | if (ch == -1) { | ||
286 | /* This shouldn't be needed...but... */ | ||
287 | volatile unsigned long delay; | ||
288 | for (delay=0; delay < 2000000; delay++) | ||
289 | ; | ||
290 | } else { | ||
291 | return ch; | ||
292 | } | ||
293 | } | ||
294 | } | ||
295 | |||
233 | static int __devinit hvc_vio_probe(struct vio_dev *vdev, | 296 | static int __devinit hvc_vio_probe(struct vio_dev *vdev, |
234 | const struct vio_device_id *id) | 297 | const struct vio_device_id *id) |
235 | { | 298 | { |
@@ -289,6 +352,13 @@ static int __devinit hvc_vio_probe(struct vio_dev *vdev, | |||
289 | return PTR_ERR(hp); | 352 | return PTR_ERR(hp); |
290 | dev_set_drvdata(&vdev->dev, hp); | 353 | dev_set_drvdata(&vdev->dev, hp); |
291 | 354 | ||
355 | /* register udbg if it's not there already for console 0 */ | ||
356 | if (hp->index == 0 && !udbg_putc) { | ||
357 | udbg_putc = udbg_hvc_putc; | ||
358 | udbg_getc = udbg_hvc_getc; | ||
359 | udbg_getc_poll = udbg_hvc_getc_poll; | ||
360 | } | ||
361 | |||
292 | return 0; | 362 | return 0; |
293 | } | 363 | } |
294 | 364 | ||
@@ -331,59 +401,6 @@ static void __exit hvc_vio_exit(void) | |||
331 | } | 401 | } |
332 | module_exit(hvc_vio_exit); | 402 | module_exit(hvc_vio_exit); |
333 | 403 | ||
334 | static void udbg_hvc_putc(char c) | ||
335 | { | ||
336 | int count = -1; | ||
337 | |||
338 | if (c == '\n') | ||
339 | udbg_hvc_putc('\r'); | ||
340 | |||
341 | do { | ||
342 | switch(hvterm_priv0.proto) { | ||
343 | case HV_PROTOCOL_RAW: | ||
344 | count = hvterm_raw_put_chars(0, &c, 1); | ||
345 | break; | ||
346 | case HV_PROTOCOL_HVSI: | ||
347 | count = hvterm_hvsi_put_chars(0, &c, 1); | ||
348 | break; | ||
349 | } | ||
350 | } while(count == 0); | ||
351 | } | ||
352 | |||
353 | static int udbg_hvc_getc_poll(void) | ||
354 | { | ||
355 | int rc = 0; | ||
356 | char c; | ||
357 | |||
358 | switch(hvterm_priv0.proto) { | ||
359 | case HV_PROTOCOL_RAW: | ||
360 | rc = hvterm_raw_get_chars(0, &c, 1); | ||
361 | break; | ||
362 | case HV_PROTOCOL_HVSI: | ||
363 | rc = hvterm_hvsi_get_chars(0, &c, 1); | ||
364 | break; | ||
365 | } | ||
366 | if (!rc) | ||
367 | return -1; | ||
368 | return c; | ||
369 | } | ||
370 | |||
371 | static int udbg_hvc_getc(void) | ||
372 | { | ||
373 | int ch; | ||
374 | for (;;) { | ||
375 | ch = udbg_hvc_getc_poll(); | ||
376 | if (ch == -1) { | ||
377 | /* This shouldn't be needed...but... */ | ||
378 | volatile unsigned long delay; | ||
379 | for (delay=0; delay < 2000000; delay++) | ||
380 | ; | ||
381 | } else { | ||
382 | return ch; | ||
383 | } | ||
384 | } | ||
385 | } | ||
386 | |||
387 | void __init hvc_vio_init_early(void) | 404 | void __init hvc_vio_init_early(void) |
388 | { | 405 | { |
389 | struct device_node *stdout_node; | 406 | struct device_node *stdout_node; |