905e1dfb37222708a117ff23ed6c6773d485800c
[fw/openocd] / src / target / target_request.c
1 /***************************************************************************
2  *   Copyright (C) 2007 by Dominic Rath                                    *
3  *   Dominic.Rath@gmx.de                                                   *
4  *                                                                         *
5  *   Copyright (C) 2007,2008 Ã˜yvind Harboe                                 *
6  *   oyvind.harboe@zylin.com                                               *
7  *                                                                         *
8  *   Copyright (C) 2008 by Spencer Oliver                                  *
9  *   spen@spen-soft.co.uk                                                  *
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  *   This program is distributed in the hope that it will be useful,       *
17  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
18  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
19  *   GNU General Public License for more details.                          *
20  *                                                                         *
21  *   You should have received a copy of the GNU General Public License     *
22  *   along with this program; if not, write to the                         *
23  *   Free Software Foundation, Inc.,                                       *
24  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
25  ***************************************************************************/
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include "target_request.h"
31 #include "target_type.h"
32 #include "binarybuffer.h"
33 #include "trace.h"
34 #include "log.h"
35
36
37 static command_t *target_request_cmd = NULL;
38 static int charmsg_mode = 0;
39
40 static int target_asciimsg(target_t *target, u32 length)
41 {
42         char *msg = malloc(CEIL(length + 1, 4) * 4);
43         debug_msg_receiver_t *c = target->dbgmsg;
44
45         target->type->target_request_data(target, CEIL(length, 4), (uint8_t*)msg);
46         msg[length] = 0;
47
48         LOG_DEBUG("%s", msg);
49
50         while (c)
51         {
52                 command_print(c->cmd_ctx, "%s", msg);
53                 c = c->next;
54         }
55
56         return ERROR_OK;
57 }
58
59 static int target_charmsg(target_t *target, uint8_t msg)
60 {
61         LOG_USER_N("%c", msg);
62
63         return ERROR_OK;
64 }
65
66 static int target_hexmsg(target_t *target, int size, u32 length)
67 {
68         uint8_t *data = malloc(CEIL(length * size, 4) * 4);
69         char line[128];
70         int line_len;
71         debug_msg_receiver_t *c = target->dbgmsg;
72         u32 i;
73
74         LOG_DEBUG("size: %i, length: %i", size, length);
75
76         target->type->target_request_data(target, CEIL(length * size, 4), (uint8_t*)data);
77
78         line_len = 0;
79         for (i = 0; i < length; i++)
80         {
81                 switch (size)
82                 {
83                         case 4:
84                                 line_len += snprintf(line + line_len, 128 - line_len, "%8.8x ", le_to_h_u32(data + (4*i)));
85                                 break;
86                         case 2:
87                                 line_len += snprintf(line + line_len, 128 - line_len, "%4.4x ", le_to_h_u16(data + (2*i)));
88                                 break;
89                         case 1:
90                                 line_len += snprintf(line + line_len, 128 - line_len, "%2.2x ", data[i]);
91                                 break;
92                 }
93
94                 if ((i%8 == 7) || (i == length - 1))
95                 {
96                         LOG_DEBUG("%s", line);
97
98                         while (c)
99                         {
100                                 command_print(c->cmd_ctx, "%s", line);
101                                 c = c->next;
102                         }
103                         c = target->dbgmsg;
104                         line_len = 0;
105                 }
106         }
107
108         free(data);
109
110         return ERROR_OK;
111 }
112
113 /* handle requests from the target received by a target specific
114  * side-band channel (e.g. ARM7/9 DCC)
115  */
116 int target_request(target_t *target, u32 request)
117 {
118         target_req_cmd_t target_req_cmd = request & 0xff;
119
120         if ( charmsg_mode ) {
121                 target_charmsg(target, target_req_cmd );
122                 return ERROR_OK;
123         }
124         switch (target_req_cmd)
125         {
126                 case TARGET_REQ_TRACEMSG:
127                         trace_point(target, (request & 0xffffff00) >> 8);
128                         break;
129                 case TARGET_REQ_DEBUGMSG:
130                         if (((request & 0xff00) >> 8) == 0)
131                         {
132                                 target_asciimsg(target, (request & 0xffff0000) >> 16);
133                         }
134                         else
135                         {
136                                 target_hexmsg(target, (request & 0xff00) >> 8, (request & 0xffff0000) >> 16);
137                         }
138                         break;
139                 case TARGET_REQ_DEBUGCHAR:
140                         target_charmsg(target, (request & 0x00ff0000) >> 16);
141                         break;
142 /*              case TARGET_REQ_SEMIHOSTING:
143  *                      break;
144  */
145                 default:
146                         LOG_ERROR("unknown target request: %2.2x", target_req_cmd);
147                         break;
148         }
149
150         return ERROR_OK;
151 }
152
153 static int add_debug_msg_receiver(struct command_context_s *cmd_ctx, target_t *target)
154 {
155         debug_msg_receiver_t **p = &target->dbgmsg;
156
157         if (target == NULL)
158                 return ERROR_INVALID_ARGUMENTS;
159
160         /* see if there's already a list */
161         if (*p)
162         {
163                 /* find end of linked list */
164                 p = &target->dbgmsg;
165                 while ((*p)->next)
166                         p = &((*p)->next);
167                 p = &((*p)->next);
168         }
169
170         /* add new debug message receiver */
171         (*p) = malloc(sizeof(debug_msg_receiver_t));
172         (*p)->cmd_ctx = cmd_ctx;
173         (*p)->next = NULL;
174
175         /* enable callback */
176         target->dbg_msg_enabled = 1;
177
178         return ERROR_OK;
179 }
180
181 static debug_msg_receiver_t* find_debug_msg_receiver(struct command_context_s *cmd_ctx, target_t *target)
182 {
183         int do_all_targets = 0;
184         debug_msg_receiver_t **p = &target->dbgmsg;
185
186         /* if no target has been specified search all of them */
187         if (target == NULL)
188         {
189                 /* if no targets haven been specified */
190                 if (all_targets == NULL)
191                         return NULL;
192
193                 target = all_targets;
194                 do_all_targets = 1;
195         }
196
197         do
198         {
199                 while (*p)
200                 {
201                         if ((*p)->cmd_ctx == cmd_ctx)
202                         {
203                                 return *p;
204                         }
205                         p = &((*p)->next);
206                 }
207
208                 target = target->next;
209         } while (target && do_all_targets);
210
211         return NULL;
212 }
213
214 int delete_debug_msg_receiver(struct command_context_s *cmd_ctx, target_t *target)
215 {
216         debug_msg_receiver_t **p;
217         debug_msg_receiver_t *c;
218         int do_all_targets = 0;
219
220         /* if no target has been specified search all of them */
221         if (target == NULL)
222         {
223                 /* if no targets haven been specified */
224                 if (all_targets == NULL)
225                         return ERROR_OK;
226
227                 target = all_targets;
228                 do_all_targets = 1;
229         }
230
231         do
232         {
233                 p = &target->dbgmsg;
234                 c = *p;
235                 while (c)
236                 {
237                         debug_msg_receiver_t *next = c->next;
238                         if (c->cmd_ctx == cmd_ctx)
239                         {
240                                 *p = next;
241                                 free(c);
242                                 if (*p == NULL)
243                                 {
244                                         /* disable callback */
245                                         target->dbg_msg_enabled = 0;
246                                 }
247                                 return ERROR_OK;
248                         }
249                         else
250                                 p = &(c->next);
251                         c = next;
252                 }
253
254                 target = target->next;
255         } while (target && do_all_targets);
256
257         return ERROR_OK;
258 }
259
260 static int handle_target_request_debugmsgs_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
261 {
262         target_t *target = get_current_target(cmd_ctx);
263
264         int receiving = 0;
265
266         /* see if reciever is already registered */
267         if (find_debug_msg_receiver(cmd_ctx, target) != NULL)
268                 receiving = 1;
269
270         if (argc > 0)
271         {
272                 if (!strcmp(args[0], "enable") || !strcmp(args[0], "charmsg"))
273                 {
274                         /* don't register if this command context is already receiving */
275                         if (!receiving)
276                         {
277                                 receiving = 1;
278                                 add_debug_msg_receiver(cmd_ctx, target);
279                         }
280                         charmsg_mode = !strcmp(args[0], "charmsg");
281                 }
282                 else if (!strcmp(args[0], "disable"))
283                 {
284                         /* no need to delete a receiver if none is registered */
285                         if (receiving)
286                         {
287                                 receiving = 0;
288                                 delete_debug_msg_receiver(cmd_ctx, target);
289                         }
290                 }
291                 else
292                 {
293                         command_print(cmd_ctx, "usage: target_request debugmsgs ['enable'|'disable'|'charmsg']");
294                 }
295         }
296
297         command_print(cmd_ctx, "receiving debug messages from current target %s",
298                       (receiving) ? (charmsg_mode?"charmsg":"enabled") : "disabled" );
299         return ERROR_OK;
300 }
301
302 int target_request_register_commands(struct command_context_s *cmd_ctx)
303 {
304         target_request_cmd =
305                 register_command(cmd_ctx, NULL, "target_request", NULL, COMMAND_ANY, "target_request commands");
306
307         register_command(cmd_ctx, target_request_cmd, "debugmsgs", handle_target_request_debugmsgs_command,
308                 COMMAND_EXEC, "enable/disable reception of debug messages from target");
309
310         return ERROR_OK;
311 }