blob: a9dde00c51b98778f35aded40c629649027afea8 [file] [log] [blame]
John Stultz5c69c8c2015-11-23 17:13:51 -08001/*
2 * User Mode Init manager - For TI shared transport
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program;if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18#include <stdio.h>
19#include <errno.h>
20#include <fcntl.h>
21#include <string.h>
22#include <signal.h>
23#include <sys/ioctl.h>
24#include <termios.h>
25#include <poll.h>
26#include <stdint.h>
27#include <stdlib.h>
28#include <sys/stat.h>
29#include <sys/utsname.h>
30
31#include <unistd.h>
32#include <time.h>
33
34#include "uim.h"
35
36/* Maintains the exit state of UIM*/
37static int exiting;
38static int line_discipline;
39static int dev_fd;
40
41/* BD address as string and a pointer to array of hex bytes */
42char uim_bd_address[BD_ADDR_LEN];
43bdaddr_t *bd_addr;
44
45/*****************************************************************************/
46#ifdef UIM_DEBUG
47/* Function to Read the firmware version
48 * module into the system. Currently used for
49 * debugging purpose, whenever the baud rate is changed
50 */
51void read_firmware_version(int dev_fd)
52{
53 int index = 0;
54 char resp_buffer[20] = { 0 };
55 unsigned char buffer[] = { 0x01, 0x01, 0x10, 0x00 };
56
57 UIM_START_FUNC();
58 UIM_VER(" wrote %d bytes", (int)write(dev_fd, buffer, 4));
59 UIM_VER(" reading %d bytes", (int)read(dev_fd, resp_buffer, 15));
60
61 for (index = 0; index < 15; index++)
62 UIM_VER(" %x ", resp_buffer[index]);
63
64 printf("\n");
65}
66#endif
67
68/*****************************************************************************/
69/* Function to read the HCI event from the given file descriptor
70 *
71 * This will parse the response received and returns error
72 * if the required response is not received
73 */
74int read_hci_event(int fd, unsigned char *buf, int size)
75{
76 int remain, rd;
77 int count = 0;
78 int reading = 1;
79 int rd_retry_count = 0;
80 struct timespec tm = {0, 50*1000*1000};
81
82 UIM_START_FUNC();
83
84 UIM_VER(" read_hci_event");
85 if (size <= 0)
86 return -1;
87
88 /* The first byte identifies the packet type. For HCI event packets, it
89 * should be 0x04, so we read until we get to the 0x04. */
90 while (reading) {
91 rd = read(fd, buf, 1);
92 if (rd <= 0 && rd_retry_count++ < 4) {
93 nanosleep(&tm, NULL);
94 continue;
95 } else if (rd_retry_count >= 4) {
96 return -1;
97 }
98
99 if (buf[0] == RESP_PREFIX) {
100 break;
101 }
102 }
103 count++;
104
105 /* The next two bytes are the event code and parameter total length. */
106 while (count < 3) {
107 rd = read(fd, buf + count, 3 - count);
108 if (rd <= 0)
109 return -1;
110 count += rd;
111 }
112
113 /* Now we read the parameters. */
114 if (buf[2] < (size - 3))
115 remain = buf[2];
116 else
117 remain = size - 3;
118
119 while ((count - 3) < remain) {
120 rd = read(fd, buf + count, remain - (count - 3));
121 if (rd <= 0)
122 return -1;
123 count += rd;
124 }
125
126 return count;
127}
128
129/* Function to read the Command complete event
130 *
131 * This will read the response for the change speed
132 * command that was sent to configure the UART speed
133 * with the custom baud rate
134 */
135static int read_command_complete(int fd, unsigned short opcode)
136{
137 command_complete_t resp;
138
139 UIM_START_FUNC();
140
141 UIM_VER(" Command complete started");
142 if (read_hci_event(fd, (unsigned char *)&resp, sizeof(resp)) < 0) {
143 UIM_ERR("Invalid response");
144 return -1;
145 }
146
147 /* Response should be an event packet */
148 if (resp.uart_prefix != HCI_EVENT_PKT) {
149 UIM_ERR ("Error in response: not an event packet, 0x%02x!",
150 resp.uart_prefix);
151 return -1;
152 }
153
154 /* Response should be a command complete event */
155 if (resp.hci_hdr.evt != EVT_CMD_COMPLETE) {
156 /* event must be event-complete */
157 UIM_ERR("Error in response: not a cmd-complete event,0x%02x!",
158 resp.hci_hdr.evt);
159 return -1;
160 }
161
162 if (resp.hci_hdr.plen < 4) {
163 /* plen >= 4 for EVT_CMD_COMPLETE */
164 UIM_ERR("Error in response: plen is not >= 4, but 0x%02x!",
165 resp.hci_hdr.plen);
166 return -1;
167 }
168
169 if (resp.cmd_complete.opcode != (unsigned short)opcode) {
170 UIM_ERR("Error in response: opcode is 0x%04x, not 0x%04x!",
171 resp.cmd_complete.opcode, opcode);
172 return -1;
173 }
174
175 UIM_DBG("Command complete done");
176 return resp.status == 0 ? 0 : -1;
177}
178
179/* Function to set the default baud rate
180 *
181 * The default baud rate of 115200 is set to the UART from the host side
182 * by making a call to this function.This function is also called before
183 * making a call to set the custom baud rate
184 */
185static int set_baud_rate(int dev_fd)
186{
187 UIM_START_FUNC();
188 struct termios ti;
189
190 tcflush(dev_fd, TCIOFLUSH);
191
192 /* Get the attributes of UART */
193 if (tcgetattr(dev_fd, &ti) < 0) {
194 UIM_ERR(" Can't get port settings");
195 return -1;
196 }
197
198 /* Change the UART attributes before
199 * setting the default baud rate*/
200 cfmakeraw(&ti);
201
202 ti.c_cflag |= 1;
203 ti.c_cflag |= CRTSCTS;
204
205 /* Set the attributes of UART after making
206 * the above changes
207 */
208 tcsetattr(dev_fd, TCSANOW, &ti);
209
210 /* Set the actual default baud rate */
211 cfsetospeed(&ti, B115200);
212 cfsetispeed(&ti, B115200);
213 tcsetattr(dev_fd, TCSANOW, &ti);
214
215 tcflush(dev_fd, TCIOFLUSH);
216 UIM_DBG("set_baud_rate() done");
217
218 return 0;
219}
220
221
222/* Function to set the UART custom baud rate.
223 *
224 * The UART baud rate has already been
225 * set to default value 115200 before calling this function.
226 * The baud rate is then changed to custom baud rate by this function*/
227static int set_custom_baud_rate(int dev_fd, int baud_rate, int flow_ctrl)
228{
229 UIM_START_FUNC();
230
231 struct termios ti;
232 struct termios2 ti2;
233
234 tcflush(dev_fd, TCIOFLUSH);
235 /* Get the attributes of UART */
236 if (tcgetattr(dev_fd, &ti) < 0) {
237 UIM_ERR(" Can't get port settings");
238 return -1;
239 }
240
241 /*Set the UART flow control */
242 if (flow_ctrl)
243 ti.c_cflag |= CRTSCTS;
244 else
245 ti.c_cflag &= ~CRTSCTS;
246
247 /*
248 * Set the parameters associated with the UART
249 * The change will occur immediately by using TCSANOW
250 */
251 if (tcsetattr(dev_fd, TCSANOW, &ti) < 0) {
252 UIM_ERR(" Can't set port settings");
253 return -1;
254 }
255
256 tcflush(dev_fd, TCIOFLUSH);
257
258 /*Set the actual baud rate */
259 ioctl(dev_fd, TCGETS2, &ti2);
260 ti2.c_cflag &= ~CBAUD;
261 ti2.c_cflag |= BOTHER;
262 ti2.c_ospeed = baud_rate;
263 ioctl(dev_fd, TCSETS2, &ti2);
264
265 return 0;
266}
267
268/* Function to configure the UART
269 * on receiving a notification from the ST KIM driver to install the line
270 * discipline, this function does UART configuration necessary for the STK
271 */
272int st_uart_config(unsigned char install)
273{
274 int ldisc, len, fd, flow_ctrl;
275 unsigned char buf[UART_DEV_NAME_LEN];
276 uim_speed_change_cmd cmd;
277 char uart_dev_name[UART_DEV_NAME_LEN];
278 unsigned int cust_baud_rate;
279
280 uim_bdaddr_change_cmd addr_cmd;
281
282 UIM_START_FUNC();
283
284 if (install == '1') {
285 memset(buf, 0, UART_DEV_NAME_LEN);
286 fd = open(DEV_NAME_SYSFS, O_RDONLY);
287 if (fd < 0) {
288 UIM_ERR("Can't open %s", DEV_NAME_SYSFS);
289 return -1;
290 }
291 len = read(fd, buf, UART_DEV_NAME_LEN);
292 if (len < 0) {
293 UIM_ERR("read err (%s)", strerror(errno));
294 close(fd);
295 return len;
296 }
297 sscanf((const char*)buf, "%s", uart_dev_name);
298 close(fd);
299
300 memset(buf, 0, UART_DEV_NAME_LEN);
301 fd = open(BAUD_RATE_SYSFS, O_RDONLY);
302 if (fd < 0) {
303 UIM_ERR("Can't open %s", BAUD_RATE_SYSFS);
304 return -1;
305 }
306 len = read(fd, buf, UART_DEV_NAME_LEN);
307 if (len < 0) {
308 UIM_ERR("read err (%s)", strerror(errno));
309 close(fd);
310 return len;
311 }
312 close(fd);
313 sscanf((const char*)buf, "%d", &cust_baud_rate);
314
315 memset(buf, 0, UART_DEV_NAME_LEN);
316 fd = open(FLOW_CTRL_SYSFS, O_RDONLY);
317 if (fd < 0) {
318 UIM_ERR("Can't open %s", FLOW_CTRL_SYSFS);
319 close(fd);
320 return -1;
321 }
322 len = read(fd, buf, UART_DEV_NAME_LEN);
323 if (len < 0) {
324 UIM_ERR("read err (%s)", strerror(errno));
325 close(fd);
326 return len;
327 }
328 close(fd);
329 sscanf((const char*)buf, "%d", &flow_ctrl);
330
331 UIM_VER(" signal received, opening %s", uart_dev_name);
332
333 dev_fd = open(uart_dev_name, O_RDWR);
334 if (dev_fd < 0) {
335 UIM_ERR("Can't open %s", uart_dev_name);
336 return -1;
337 }
338
339 /*
340 * Set only the default baud rate.
341 * This will set the baud rate to default 115200
342 */
343 if (set_baud_rate(dev_fd) < 0) {
344 UIM_ERR("set_baudrate() failed");
345 close(dev_fd);
346 return -1;
347 }
348
349 fcntl(dev_fd, F_SETFL,fcntl(dev_fd, F_GETFL) | O_NONBLOCK);
350 /* Set only the custom baud rate */
351 if (cust_baud_rate != 115200) {
352
353 UIM_VER("Setting speed to %d", cust_baud_rate);
354 /* Forming the packet for Change speed command */
355 cmd.uart_prefix = HCI_COMMAND_PKT;
356 cmd.hci_hdr.opcode = HCI_HDR_OPCODE;
357 cmd.hci_hdr.plen = sizeof(unsigned int);
358 cmd.speed = cust_baud_rate;
359
360 /* Writing the change speed command to the UART
361 * This will change the UART speed at the controller
362 * side
363 */
364 len = write(dev_fd, &cmd, sizeof(cmd));
365 if (len < 0) {
366 UIM_ERR("Failed to write speed-set command");
367 close(dev_fd);
368 return -1;
369 }
370
371 /* Read the response for the Change speed command */
372 if (read_command_complete(dev_fd, HCI_HDR_OPCODE) < 0) {
373 close(dev_fd);
374 return -1;
375 }
376
377 UIM_VER("Speed changing to %d, %d", cust_baud_rate, flow_ctrl);
378 /* Set the actual custom baud rate at the host side */
379 if (set_custom_baud_rate(dev_fd, cust_baud_rate, flow_ctrl) < 0) {
380 UIM_ERR("set_custom_baud_rate() failed");
381 close(dev_fd);
382 return -1;
383 }
384
385 /* Set the uim BD address */
386 if (uim_bd_address[0] != 0) {
387
388 memset(&addr_cmd, 0, sizeof(addr_cmd));
389 /* Forming the packet for change BD address command*/
390 addr_cmd.uart_prefix = HCI_COMMAND_PKT;
391 addr_cmd.hci_hdr.opcode = WRITE_BD_ADDR_OPCODE;
392 addr_cmd.hci_hdr.plen = sizeof(bdaddr_t);
393 memcpy(&addr_cmd.addr, bd_addr, sizeof(bdaddr_t));
394
395 /* Writing the change BD address command to the UART
396 * This will change the change BD address at the controller
397 * side
398 */
399 len = write(dev_fd, &addr_cmd, sizeof(addr_cmd));
400 if (len < 0) {
401 UIM_ERR("Failed to write BD address command");
402 close(dev_fd);
403 return -1;
404 }
405
406 /* Read the response for the change BD address command */
407 if (read_command_complete(dev_fd, WRITE_BD_ADDR_OPCODE) < 0) {
408 close(dev_fd);
409 return -1;
410 }
411 UIM_VER("BD address changed to %s", uim_bd_address);
412 }
413#ifdef UIM_DEBUG
414 read_firmware_version(dev_fd);
415#endif
416 }
417
418 /* After the UART speed has been changed, the IOCTL is
419 * is called to set the line discipline to N_TI_WL
420 */
421 ldisc = N_TI_WL;
422 if (ioctl(dev_fd, TIOCSETD, &ldisc) < 0) {
423 UIM_ERR(" Can't set line discipline");
424 close(dev_fd);
425 return -1;
426 }
427 UIM_DBG("Installed N_TI_WL Line displine");
428 }
429 else {
430 UIM_DBG("Un-Installed N_TI_WL Line displine");
431 /* UNINSTALL_N_TI_WL - When the Signal is received from KIM */
432 /* closing UART fd */
433 close(dev_fd);
434 }
435 return 0;
436}
437
438/* Function to convert the BD address from ascii to hex value */
439bdaddr_t *strtoba(const char *str)
440{
441 const char *ptr = str;
442 int i;
443
444 uint8_t *ba = malloc(sizeof(bdaddr_t));
445 if (!ba)
446 return NULL;
447
448 for (i = 0; i < 6; i++) {
449 ba[i] = (uint8_t) strtol(ptr, NULL, 16);
450 if (i != 5 && !(ptr = strchr(ptr, ':')))
451 ptr = ":00:00:00:00:00";
452 ptr++;
453 }
454
455 return (bdaddr_t *) ba;
456}
457
458/*****************************************************************************/
459int main(int argc, char *argv[])
460{
461 int st_fd, err,trials;
462 unsigned char install;
463 struct pollfd p;
464
465 UIM_START_FUNC();
466 err = 0;
467 trials = 5;
468
469 /* Parse the user input */
470 if ((argc > 2)) {
471 UIM_ERR("Invalid arguements");
472 UIM_ERR("Usage: uim <bd address>");
473 return -1;
474 }
475 if (argc == 2) {
476 if (strlen(argv[2]) != BD_ADDR_LEN) {
477 UIM_ERR("Usage: uim XX:XX:XX:XX:XX:XX");
478 return -1;
479 }
480 /* BD address passed as string in xx:xx:xx:xx:xx:xx format */
481 strncpy(uim_bd_address, argv[2], sizeof(uim_bd_address));
482 bd_addr = strtoba(uim_bd_address);
483 }
484
485 line_discipline = N_TI_WL;
486
487 /* sysfs entry may get populated after service is started so we retry if it fails*/
488 while (trials > 0) {
489 st_fd = open(INSTALL_SYSFS_ENTRY, O_RDONLY);
490 if(st_fd > 0)
491 break;
492 usleep(500000);
493 --trials;
494 }
495 if (st_fd < 0) {
496 UIM_DBG("unable to open %s(%s)", INSTALL_SYSFS_ENTRY, strerror(errno));
497 return -1;
498 }
499
500RE_POLL:
501 /* read to start proper poll */
502 err = read(st_fd, &install, 1);
503 /* special case where bluetoothd starts before the UIM, and UIM
504 * needs to turn on bluetooth because of that.
505 */
506 if ((err > 0) && install == '1') {
507 UIM_DBG("install set previously...");
508 st_uart_config(install);
509 }
510
511 UIM_DBG("begin polling...");
512
513 memset(&p, 0, sizeof(p));
514 p.fd = st_fd;
515 p.events = POLLERR | POLLPRI;
516
517 while (!exiting) {
518 p.revents = 0;
519 err = poll(&p, 1, -1);
520 UIM_DBG("poll broke due to event %d(PRI:%d/ERR:%d)\n", p.revents, POLLPRI, POLLERR);
521 if (err < 0 && errno == EINTR)
522 continue;
523 if (err)
524 break;
525 }
526
527 close(st_fd);
528 st_fd = open(INSTALL_SYSFS_ENTRY, O_RDONLY);
529 if (st_fd < 0) {
530 UIM_DBG("unable to open %s (%s)", INSTALL_SYSFS_ENTRY, strerror(errno));
531 return -1;
532 }
533
534 if (!exiting)
535 {
536 err = read(st_fd, &install, 1);
537 UIM_DBG("read %c from install \n", install);
538 if (err > 0)
539 st_uart_config(install);
540 goto RE_POLL;
541 }
542
543 close(st_fd);
544 return 0;
545}