device: Set disconnect timer to zero for fast disconnection
[platform/upstream/bluez.git] / monitor / jlink.c
1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 /*
3  *
4  *  BlueZ - Bluetooth protocol stack for Linux
5  *
6  *  Copyright (C) 2018  Codecoup
7  *
8  *
9  */
10
11 #ifdef HAVE_CONFIG_H
12 #include <config.h>
13 #endif
14
15 #include <dlfcn.h>
16 #include <errno.h>
17 #include <stdio.h>
18 #include <stdint.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <unistd.h>
22
23 #include "jlink.h"
24
25 #define RTT_CONTROL_START               0
26 #define RTT_CONTROL_STOP                1
27 #define RTT_CONTROL_GET_DESC            2
28 #define RTT_CONTROL_GET_NUM_BUF         3
29 #define RTT_CONTROL_GET_STAT            4
30
31 #define RTT_DIRECTION_UP                0
32 #define RTT_DIRECTION_DOWN              1
33
34 static const char * const jlink_so_name[] = {
35         "/usr/lib/libjlinkarm.so",
36         "/usr/lib/libjlinkarm.so.6",
37         "/opt/SEGGER/JLink/libjlinkarm.so",
38         "/opt/SEGGER/JLink/libjlinkarm.so.6",
39 };
40
41 struct rtt_desc {
42         uint32_t index;
43         uint32_t direction;
44         char name[32];
45         uint32_t size;
46         uint32_t flags;
47 };
48
49 static struct rtt_desc rtt_desc;
50
51 typedef int (*jlink_emu_selectbyusbsn_func) (unsigned int sn);
52 typedef int (*jlink_open_func) (void);
53 typedef int (*jlink_execcommand_func) (char *in, char *out, int size);
54 typedef int (*jlink_tif_select_func) (int);
55 typedef void (*jlink_setspeed_func) (long int speed);
56 typedef int (*jlink_connect_func) (void);
57 typedef unsigned int (*jlink_getsn_func) (void);
58 typedef void (*jlink_emu_getproductname_func) (char *out, int size);
59 typedef int (*jlink_rtterminal_control_func) (int cmd, void *data);
60 typedef int (*jlink_rtterminal_read_func) (int cmd, char *buf, int size);
61
62 struct jlink {
63         jlink_emu_selectbyusbsn_func emu_selectbyusbsn;
64         jlink_open_func open;
65         jlink_execcommand_func execcommand;
66         jlink_tif_select_func tif_select;
67         jlink_setspeed_func setspeed;
68         jlink_connect_func connect;
69         jlink_getsn_func getsn;
70         jlink_emu_getproductname_func emu_getproductname;
71         jlink_rtterminal_control_func rtterminal_control;
72         jlink_rtterminal_read_func rtterminal_read;
73 };
74
75 static struct jlink jlink;
76
77 #ifndef NELEM
78 #define NELEM(x) (sizeof(x) / sizeof((x)[0]))
79 #endif
80
81 int jlink_init(void)
82 {
83         void *so;
84         unsigned int i;
85
86         for (i = 0; i < NELEM(jlink_so_name); i++) {
87                 so = dlopen(jlink_so_name[i], RTLD_LAZY);
88                 if (so)
89                         break;
90         }
91
92         if (!so)
93                 return -EIO;
94
95         jlink.emu_selectbyusbsn = dlsym(so, "JLINK_EMU_SelectByUSBSN");
96         jlink.open = dlsym(so, "JLINK_Open");
97         jlink.execcommand = dlsym(so, "JLINK_ExecCommand");
98         jlink.tif_select = dlsym(so, "JLINK_TIF_Select");
99         jlink.setspeed = dlsym(so, "JLINK_SetSpeed");
100         jlink.connect = dlsym(so, "JLINK_Connect");
101         jlink.getsn = dlsym(so, "JLINK_GetSN");
102         jlink.emu_getproductname = dlsym(so, "JLINK_EMU_GetProductName");
103         jlink.rtterminal_control = dlsym(so, "JLINK_RTTERMINAL_Control");
104         jlink.rtterminal_read = dlsym(so, "JLINK_RTTERMINAL_Read");
105
106         if (!jlink.emu_selectbyusbsn || !jlink.open || !jlink.execcommand ||
107                         !jlink.tif_select || !jlink.setspeed ||
108                         !jlink.connect || !jlink.getsn ||
109                         !jlink.emu_getproductname ||
110                         !jlink.rtterminal_control || !jlink.rtterminal_read) {
111                 dlclose(so);
112                 return -EIO;
113         }
114
115         /* don't dlclose(so) here cause symbols from it are in use now */
116         return 0;
117 }
118
119 int jlink_connect(char *cfg)
120 {
121         const char *device = NULL;
122         int tif = 1;
123         unsigned int speed = 1000;
124         unsigned int serial_no = 0;
125         char *tok;
126         char buf[64];
127
128         tok = strtok(cfg, ",");
129         device = tok;
130
131         tok = strtok(NULL, ",");
132         if (!tok)
133                 goto connect;
134         if (strlen(tok))
135                 serial_no = atoi(tok);
136
137         tok = strtok(NULL, ",");
138         if (!tok)
139                 goto connect;
140         if (strlen(tok)) {
141                 if (!strcasecmp("swd", tok))
142                         tif = 1;
143                 else
144                         return -EINVAL;
145         }
146
147         tok = strtok(NULL, ",");
148         if (!tok)
149                 goto connect;
150         if (strlen(tok))
151                 speed = atoi(tok);
152
153 connect:
154         if (serial_no)
155                 if (jlink.emu_selectbyusbsn(serial_no) < 0) {
156                         fprintf(stderr, "Failed to select emu by SN\n");
157                         return -ENODEV;
158                 }
159
160         if (jlink.open() < 0) {
161                 fprintf(stderr, "Failed to open J-Link\n");
162                 return -ENODEV;
163         }
164
165         snprintf(buf, sizeof(buf), "device=%s", device);
166         if (jlink.execcommand(buf, NULL, 0) < 0) {
167                 fprintf(stderr, "Failed to select target device\n");
168                 return -ENODEV;
169         }
170
171         if (jlink.tif_select(tif) < 0) {
172                 fprintf(stderr, "Failed to select target interface\n");
173                 return -ENODEV;
174         }
175
176         jlink.setspeed(speed);
177
178         if (jlink.connect() < 0) {
179                 fprintf(stderr, "Failed to open target\n");
180                 return -EIO;
181         }
182
183         serial_no = jlink.getsn();
184         jlink.emu_getproductname(buf, sizeof(buf));
185
186         printf("Connected to %s (S/N: %u)\n", buf, serial_no);
187
188         return 0;
189 }
190
191 int jlink_start_rtt(char *cfg)
192 {
193         unsigned int address = 0;
194         unsigned int area_size = 0;
195         const char *buffer = "btmonitor";
196         char *tok;
197         char cmd[64];
198         int rtt_dir;
199         int count;
200         int i;
201
202         if (!cfg)
203                 goto find_rttcb;
204
205         tok = strtok(cfg, ",");
206         if (strlen(tok)) {
207                 address = strtol(tok, NULL, 0);
208                 area_size = 0x1000;
209         }
210
211         tok = strtok(NULL, ",");
212         if (!tok)
213                 goto find_rttcb;
214         if (strlen(tok))
215                 area_size = strtol(tok, NULL, 0);
216
217         tok = strtok(NULL, ",");
218         if (!tok)
219                 goto find_rttcb;
220         if (strlen(tok))
221                 buffer = tok;
222
223 find_rttcb:
224         if (address || area_size) {
225                 if (!area_size)
226                         snprintf(cmd, sizeof(cmd), "SetRTTAddr 0x%x", address);
227                 else
228                         snprintf(cmd, sizeof(cmd),
229                                                 "SetRTTSearchRanges 0x%x 0x%x",
230                                                 address, area_size);
231
232                 if (jlink.execcommand(cmd, NULL, 0) < 0)
233                         return -EIO;
234         }
235
236         if (jlink.rtterminal_control(RTT_CONTROL_START, NULL) < 0) {
237                 fprintf(stderr, "Failed to initialize RTT\n");
238                 return -1;
239         }
240
241         /* RTT may need some time to find control block so we need to wait */
242         do {
243                 usleep(100);
244                 rtt_dir = RTT_DIRECTION_UP;
245                 count = jlink.rtterminal_control(RTT_CONTROL_GET_NUM_BUF,
246                                                                 &rtt_dir);
247         } while (count < 0);
248
249         for (i = 0; i < count; i++) {
250                 memset(&rtt_desc, 0, sizeof(rtt_desc));
251                 rtt_desc.index = i;
252                 rtt_desc.direction = RTT_DIRECTION_UP;
253
254                 if (jlink.rtterminal_control(RTT_CONTROL_GET_DESC,
255                                                                 &rtt_desc) < 0)
256                         continue;
257
258                 if (rtt_desc.size > 0 && !strcmp(buffer, rtt_desc.name))
259                         break;
260         }
261
262         if (i == count)
263                 return -ENODEV;
264
265         printf("Using RTT up buffer #%d (size: %d)\n", i, rtt_desc.size);
266
267         return 0;
268 }
269
270 int jlink_rtt_read(void *buf, size_t size)
271 {
272         return jlink.rtterminal_read(rtt_desc.index, buf, size);
273 }