Commit | Line | Data |
---|---|---|
4061f498 | 1 | /* Copyright (c) 2010, 2014 The Linux Foundation. All rights reserved. |
16c63f8e DW |
2 | * |
3 | * This program is free software; you can redistribute it and/or modify | |
4 | * it under the terms of the GNU General Public License version 2 and | |
5 | * only version 2 as published by the Free Software Foundation. | |
6 | * | |
7 | * This program is distributed in the hope that it will be useful, | |
8 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
9 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
10 | * GNU General Public License for more details. | |
16c63f8e DW |
11 | */ |
12 | ||
16c63f8e | 13 | #include <linux/init.h> |
16c63f8e | 14 | |
4061f498 | 15 | #include <asm/dcc.h> |
16c63f8e DW |
16 | #include <asm/processor.h> |
17 | ||
18 | #include "hvc_console.h" | |
19 | ||
20 | /* DCC Status Bits */ | |
21 | #define DCC_STATUS_RX (1 << 30) | |
22 | #define DCC_STATUS_TX (1 << 29) | |
23 | ||
16c63f8e DW |
24 | static int hvc_dcc_put_chars(uint32_t vt, const char *buf, int count) |
25 | { | |
26 | int i; | |
27 | ||
28 | for (i = 0; i < count; i++) { | |
29 | while (__dcc_getstatus() & DCC_STATUS_TX) | |
30 | cpu_relax(); | |
31 | ||
bf73bd35 | 32 | __dcc_putchar(buf[i]); |
16c63f8e DW |
33 | } |
34 | ||
35 | return count; | |
36 | } | |
37 | ||
38 | static int hvc_dcc_get_chars(uint32_t vt, char *buf, int count) | |
39 | { | |
40 | int i; | |
41 | ||
bf73bd35 | 42 | for (i = 0; i < count; ++i) |
16c63f8e | 43 | if (__dcc_getstatus() & DCC_STATUS_RX) |
bf73bd35 SB |
44 | buf[i] = __dcc_getchar(); |
45 | else | |
16c63f8e | 46 | break; |
16c63f8e DW |
47 | |
48 | return i; | |
49 | } | |
50 | ||
f377775d RH |
51 | static bool hvc_dcc_check(void) |
52 | { | |
53 | unsigned long time = jiffies + (HZ / 10); | |
54 | ||
55 | /* Write a test character to check if it is handled */ | |
56 | __dcc_putchar('\n'); | |
57 | ||
58 | while (time_is_after_jiffies(time)) { | |
59 | if (!(__dcc_getstatus() & DCC_STATUS_TX)) | |
60 | return true; | |
61 | } | |
62 | ||
63 | return false; | |
64 | } | |
65 | ||
16c63f8e DW |
66 | static const struct hv_ops hvc_dcc_get_put_ops = { |
67 | .get_chars = hvc_dcc_get_chars, | |
68 | .put_chars = hvc_dcc_put_chars, | |
69 | }; | |
70 | ||
71 | static int __init hvc_dcc_console_init(void) | |
72 | { | |
3d270701 TT |
73 | int ret; |
74 | ||
f377775d RH |
75 | if (!hvc_dcc_check()) |
76 | return -ENODEV; | |
77 | ||
3d270701 TT |
78 | /* Returns -1 if error */ |
79 | ret = hvc_instantiate(0, 0, &hvc_dcc_get_put_ops); | |
80 | ||
81 | return ret < 0 ? -ENODEV : 0; | |
16c63f8e DW |
82 | } |
83 | console_initcall(hvc_dcc_console_init); | |
84 | ||
85 | static int __init hvc_dcc_init(void) | |
86 | { | |
3d270701 TT |
87 | struct hvc_struct *p; |
88 | ||
f377775d RH |
89 | if (!hvc_dcc_check()) |
90 | return -ENODEV; | |
91 | ||
3d270701 TT |
92 | p = hvc_alloc(0, 0, &hvc_dcc_get_put_ops, 128); |
93 | ||
94 | return PTR_ERR_OR_ZERO(p); | |
16c63f8e DW |
95 | } |
96 | device_initcall(hvc_dcc_init); |