blob: 0c5a8f7e8f0070766b763039ff6040c331330e97 [file] [log] [blame]
Shad Ansari2f7f9be2017-06-07 13:34:53 -07001/*
2<:copyright-BRCM:2016:DUAL/GPL:standard
3
4 Broadcom Proprietary and Confidential.(c) 2016 Broadcom
5 All Rights Reserved
6
7Unless you and Broadcom execute a separate written software license
8agreement governing use of this software, this software is licensed
9to you under the terms of the GNU General Public License version 2
10(the "GPL"), available at http://www.broadcom.com/licenses/GPLv2.php,
11with the following added to such license:
12
13 As a special exception, the copyright holders of this software give
14 you permission to link this software with independent modules, and
15 to copy and distribute the resulting executable under terms of your
16 choice, provided that you also meet, for each linked independent
17 module, the terms and conditions of the license of that module.
18 An independent module is a module which is not derived from this
19 software. The special exception does not apply to any modifications
20 of the software.
21
22Not withstanding the above, under no circumstances may you combine
23this software in any way with any other Broadcom software provided
24under a license other than the GPL, without Broadcom's express prior
25written consent.
26
27:>
28 */
29
30/*
31 * bcm_embedded_cli.c - embedded CLI access from the host
32 */
33
34#include <bcmos_system.h>
35#include <bcmolt_embedded_cli.h>
36#include <bcmolt_model_types.h>
37#include <bcmolt_api.h>
38#include <bcmtr_interface.h>
39#include <bcmcli.h>
40
41#define EMBEDDED_CLI_BUFFER_SIZE 2048
42#define EMBEDDED_CLI_TIMER_DELAY_US 100000
43
44/* Embedded CLI client context */
45typedef struct
46{
47 bcmolt_devid device;
48 bcmos_task task;
49 bcmos_timer timer;
50 bcmcli_session *session;
51 uint8_t inbuf[EMBEDDED_CLI_BUFFER_SIZE];
52 uint32_t inbuf_length;
53} embedded_cli_context;
54
55static embedded_cli_context *cli_context;
56
57static bcmos_timer_rc embedded_cli_timer_handler(bcmos_timer *timer, long data)
58{
59 /* FFU: this timer is for future line editing support */
60 return BCMOS_TIMER_OK;
61}
62
63static void embedded_cli_output_msg_handler(bcmolt_devid olt, bcmolt_msg *msg)
64{
65 bcmolt_debug_cli_input *cli_msg = (bcmolt_debug_cli_input *)msg;
66
67 if (cli_context && cli_msg->data.data.val)
68 {
69 /* print directly because output can contain ESC sequences */
70 uint8_t *val = cli_msg->data.data.val;
71 while (*val)
72 {
73 bcmos_putchar(*(val++));
74 }
75 }
76 bcmolt_msg_free(msg);
77}
78
79static void embedded_cli_send_input(embedded_cli_context *context)
80{
81 bcmolt_debug_key key = {};
82 bcmolt_debug_cli_input msg;
83 bcmolt_u8_list_u32 data = { context->inbuf_length, context->inbuf };
84
85 if (!context->inbuf_length)
86 {
87 return;
88 }
89 BCMOLT_OPER_INIT(&msg, debug, cli_input, key);
90 BCMOLT_OPER_PROP_SET(&msg, debug, cli_input, data, data);
91 bcmolt_oper_submit(context->device, &msg.hdr);
92 context->inbuf_length = 0;
93}
94
95/* Initialize embedded CLI module */
96bcmos_errno bcm_embedded_cli_enter(bcmcli_session *session, bcmolt_devid device)
97{
98 static char *embedded_cli_task_name = "embedded_cli";
99 bcmos_task_parm taskp =
100 {
101 .name = embedded_cli_task_name,
102 .priority = TASK_PRIORITY_CLI,
103 .data = device
104 };
105 bcmos_module_parm modulep = {};
106 bcmos_timer_parm timerp =
107 {
108 .owner = BCMOS_MODULE_ID_CLI_OVER_PCIE,
109 .handler = embedded_cli_timer_handler,
110 .data = device
111 };
112 bcmtr_handler_parm msgp =
113 {
114 .object = BCMOLT_OBJ_ID_DEBUG,
115 .group = BCMOLT_MGT_GROUP_AUTO,
116 .subgroup = BCMOLT_DEBUG_AUTO_ID_CLI_OUTPUT,
117 .module = BCMOS_MODULE_ID_CLI_OVER_PCIE,
118 .app_cb = embedded_cli_output_msg_handler,
119 .flags = BCMOLT_AUTO_FLAGS_DISPATCH
120 };
121 bcmtr_handler_parm old_msgp =
122 {
123 .object = BCMOLT_OBJ_ID_DEBUG,
124 .group = BCMOLT_MGT_GROUP_AUTO,
125 .subgroup = BCMOLT_DEBUG_AUTO_ID_CLI_OUTPUT,
126 };
127
128 int c;
129 bcmos_errno rc;
130 bcmos_bool raw_mode = BCMOS_FALSE;
131
132 /* Only 1 instance is supported */
133 if (cli_context)
134 {
135 BCMOS_TRACE_RETURN(BCM_ERR_ALREADY, "embedded_cli client is already active for device %u\n",
136 cli_context->device);
137 }
138 cli_context = bcmos_calloc(sizeof(*cli_context));
139 if (!cli_context)
140 {
141 BCMOS_TRACE_RETURN(BCM_ERR_NOMEM, "can't allocate embedded CLI context\n");
142 }
143 cli_context->session = session;
144 cli_context->device = device;
145
146 /* Create input/output task & module */
147 rc = bcmos_task_create(&cli_context->task, &taskp);
148 if (rc)
149 {
150 BCMOS_TRACE_ERR("Can't create embedded cli task: %s\n", bcmos_strerror(rc));
151 goto cleanup1;
152 }
153
154 modulep.data = (long)cli_context;
155 rc = bcmos_module_create(BCMOS_MODULE_ID_CLI_OVER_PCIE, &cli_context->task, &modulep);
156 if (rc)
157 {
158 BCMOS_TRACE_ERR("Can't create embedded cli module: %s\n", bcmos_strerror(rc));
159 goto cleanup2;
160 }
161
162 timerp.data = (long)cli_context;
163 rc = bcmos_timer_create(&cli_context->timer, &timerp);
164 if (rc)
165 {
166 BCMOS_TRACE_ERR("Can't create embedded cli timer: %s\n", bcmos_strerror(rc));
167 goto cleanup3;
168 }
169
170 /* Query existing indication in order to be able to restore it */
171 bcmtr_msg_handler_register_get(device, &old_msgp);
172
173 /* Unregister old handler */
174 bcmtr_msg_handler_unregister(device, &old_msgp);
175
176 /* Register for cli_output indication */
177 rc = bcmtr_msg_handler_register(device, &msgp);
178 if (rc)
179 {
180 BCMOS_TRACE_ERR("Can't register for cli_output indication: %s\n", bcmos_strerror(rc));
181 goto cleanup4;
182 }
183
184 bcmcli_session_print(session, "Device %u: Entering embedded CLI. Type %c to terminate\n",
185 device, BCM_EMBEDDED_CONSOLE_EXIT_CHAR);
186
187 /* Try to enter raw mode if line editing is requested */
188 rc = bcmcli_session_raw_mode_set(session, BCMOS_TRUE);
189 if (rc)
190 {
191 bcmcli_session_print(session, "Can't enable RAW input mode. Line editing is disabled\n");
192 }
193 else
194 {
195 raw_mode = BCMOS_TRUE;
196 }
197 /* No we read input and push it into input buffer */
198 if (raw_mode)
199 {
200 c = bcmos_getchar();
201 while (c >= 0 && c != BCM_EMBEDDED_CONSOLE_EXIT_CHAR)
202 {
203 cli_context->inbuf[cli_context->inbuf_length++] = c;
204 embedded_cli_send_input(cli_context);
205 c = bcmos_getchar();
206 }
207 bcmcli_session_raw_mode_set(session, BCMOS_FALSE);
208 }
209 else
210 {
211 /* Line mode */
212 char *buf;
213
214 buf = bcmcli_session_gets(session, (char *)cli_context->inbuf, sizeof(cli_context->inbuf));
215 while (buf && buf[0] != BCM_EMBEDDED_CONSOLE_EXIT_CHAR)
216 {
217 cli_context->inbuf_length = strlen(buf);
218 if (!cli_context->inbuf_length)
219 continue;
220 if (buf[cli_context->inbuf_length-1] != '\n' && buf[cli_context->inbuf_length-1] != '\r' &&
221 cli_context->inbuf_length < sizeof(cli_context->inbuf) - 1)
222 {
223 buf[cli_context->inbuf_length++] = '\n';
224 }
225 embedded_cli_send_input(cli_context);
226 buf = bcmcli_session_gets(session, (char *)cli_context->inbuf, sizeof(cli_context->inbuf));
227 }
228 }
229
230 bcmos_timer_stop(&cli_context->timer);
231 bcmcli_session_print(session, "Device %u: Embedded CLI terminated\n", device);
232 bcmtr_msg_handler_unregister(device, &msgp);
233 if (old_msgp.app_cb)
234 rc = bcmtr_msg_handler_register(device, &old_msgp);
235
236cleanup4:
237 bcmos_timer_destroy(&cli_context->timer);
238cleanup3:
239 bcmos_module_destroy(BCMOS_MODULE_ID_CLI_OVER_PCIE);
240cleanup2:
241 bcmos_task_destroy(&cli_context->task);
242cleanup1:
243 bcmos_free(cli_context);
244 cli_context = NULL;
245
246 return rc;
247}
248
249static bcmos_errno bcm_embedded_cli_command(bcmcli_session *session, const bcmcli_cmd_parm parm[], uint16_t nparms)
250{
251 bcmolt_devid device = parm[0].value.number;
252 return bcm_embedded_cli_enter(session, device);
253}
254
255/* Initialize embedded CLI module */
256bcmos_errno bcm_embedded_cli_init(void)
257{
258 BCMCLI_MAKE_CMD(NULL, "embedded", "Embedded CLI", bcm_embedded_cli_command,
259 BCMCLI_MAKE_PARM_RANGE("device", "Device index", BCMCLI_PARM_DECIMAL, 0, 0, BCMTR_MAX_OLTS-1));
260
261 return BCM_ERR_OK;
262}
263
264/* Cleanup embedded CVLI module */
265bcmos_errno bcm_embedded_cli_exit(void)
266{
267 return BCM_ERR_OK;
268}