5 * Copyright (C) 2012 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
34 #include <sys/ioctl.h>
40 #define CONNMAN_API_SUBJECT_TO_CHANGE
41 #include <connman/plugin.h>
42 #include <connman/log.h>
44 #define TIST_SYSFS_INSTALL "/sys/devices/platform/kim/install"
45 #define TIST_SYSFS_UART "/sys/devices/platform/kim/dev_name"
46 #define TIST_SYSFS_BAUD "/sys/devices/platform/kim/baud_rate"
48 /* Shared transport line discipline */
51 static GIOChannel *install_channel = NULL;
52 static GIOChannel *uart_channel = NULL;
53 static char uart_dev_name[32];
54 static unsigned long baud_rate = 0;
56 static guint install_watch = 0;
57 static guint uart_watch = 0;
59 static int install_count = 0;
63 tcflag_t c_iflag; /* input mode flags */
64 tcflag_t c_oflag; /* output mode flags */
65 tcflag_t c_cflag; /* control mode flags */
66 tcflag_t c_lflag; /* local mode flags */
67 cc_t c_line; /* line discipline */
68 cc_t c_cc[NCCS2]; /* control characters */
69 speed_t c_ispeed; /* input speed */
70 speed_t c_ospeed; /* output speed */
73 #define BOTHER 0x00001000
76 #define HCI_HDR_OPCODE 0xff36
77 #define HCI_COMMAND_PKT 0x01
78 #define HCI_EVENT_PKT 0x04
79 #define EVT_CMD_COMPLETE 0x0E
81 /* HCI Command structure to set the target baud rate */
82 struct speed_change_cmd {
87 } __attribute__ ((packed));
89 /* HCI Event structure to set the cusrom baud rate*/
98 } __attribute__ ((packed));
100 static int read_baud_rate(unsigned long *baud)
107 f = fopen(TIST_SYSFS_BAUD, "r");
111 err = fscanf(f, "%lu", baud);
114 DBG("baud rate %lu", *baud);
119 static int read_uart_name(char uart_name[], size_t uart_name_len)
126 memset(uart_name, 0, uart_name_len);
128 f = fopen(TIST_SYSFS_UART, "r");
132 err = fscanf(f, "%s", uart_name);
135 DBG("UART name %s", uart_name);
140 static int read_hci_event(int fd, unsigned char *buf, int size)
142 int prefix_len, param_len;
147 /* First 3 bytes are prefix, event and param length */
148 prefix_len = read(fd, buf, 3);
152 if (prefix_len < 3) {
153 connman_error("Truncated HCI prefix %d bytes 0x%x",
158 DBG("type 0x%x event 0x%x param len %d", buf[0], buf[1], buf[2]);
161 if (param_len > size - 3) {
162 connman_error("Buffer is too small %d", size);
166 return read(fd, buf + 3, param_len);
169 static int read_command_complete(int fd, unsigned short opcode)
171 struct cmd_complete resp;
176 err = read_hci_event(fd, (unsigned char *)&resp, sizeof(resp));
180 DBG("HCI event %d bytes", err);
182 if (resp.uart_prefix != HCI_EVENT_PKT) {
183 connman_error("Not an event packet");
187 if (resp.evt != EVT_CMD_COMPLETE) {
188 connman_error("Not a cmd complete event");
193 connman_error("HCI header length %d", resp.plen);
197 if (resp.opcode != (unsigned short) opcode) {
198 connman_error("opcode 0x%04x 0x%04x", resp.opcode, opcode);
205 /* The default baud rate is 115200 */
206 static int set_default_baud_rate(int fd)
213 err = tcflush(fd, TCIOFLUSH);
217 err = tcgetattr(fd, &ti);
224 ti.c_cflag |= CRTSCTS;
226 err = tcsetattr(fd, TCSANOW, &ti);
230 cfsetospeed(&ti, B115200);
231 cfsetispeed(&ti, B115200);
233 err = tcsetattr(fd, TCSANOW, &ti);
237 err = tcflush(fd, TCIOFLUSH);
244 connman_error("%s", strerror(errno));
249 static int set_custom_baud_rate(int fd, unsigned long cus_baud_rate, int flow_ctrl)
255 DBG("baud rate %lu flow_ctrl %d", cus_baud_rate, flow_ctrl);
257 err = tcflush(fd, TCIOFLUSH);
261 err = tcgetattr(fd, &ti);
266 ti.c_cflag |= CRTSCTS;
268 ti.c_cflag &= ~CRTSCTS;
271 * Set the parameters associated with the UART
272 * The change will occur immediately by using TCSANOW.
274 err = tcsetattr(fd, TCSANOW, &ti);
278 err = tcflush(fd, TCIOFLUSH);
282 /* Set the actual baud rate */
283 err = ioctl(fd, TCGETS2, &ti2);
287 ti2.c_cflag &= ~CBAUD;
288 ti2.c_cflag |= BOTHER;
289 ti2.c_ospeed = cus_baud_rate;
291 err = ioctl(fd, TCSETS2, &ti2);
298 DBG("%s", strerror(errno));
303 static gboolean uart_event(GIOChannel *channel,
304 GIOCondition cond, gpointer data)
310 uart_fd = g_io_channel_unix_get_fd(channel);
312 if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) {
313 connman_error("UART event 0x%x", cond);
315 g_source_remove(uart_watch);
320 if (read_command_complete(uart_fd, HCI_HDR_OPCODE) < 0)
323 if (set_custom_baud_rate(uart_fd, baud_rate, 1) < 0)
327 if (ioctl(uart_fd, TIOCSETD, &ldisc) < 0)
331 __sync_synchronize();
337 __sync_synchronize();
339 g_io_channel_shutdown(channel, TRUE, NULL);
340 g_io_channel_unref(channel);
345 static int install_ldisc(GIOChannel *channel, gboolean install)
348 struct speed_change_cmd cmd;
351 DBG("%d %p", install, uart_channel);
353 if (install == FALSE) {
355 __sync_synchronize();
357 if (uart_channel == NULL) {
358 DBG("UART channel is NULL");
362 g_io_channel_shutdown(uart_channel, TRUE, NULL);
363 g_io_channel_unref(uart_channel);
370 if (uart_channel != NULL) {
371 g_io_channel_shutdown(uart_channel, TRUE, NULL);
372 g_io_channel_unref(uart_channel);
376 DBG("opening %s custom baud %lu", uart_dev_name, baud_rate);
378 uart_fd = open(uart_dev_name, O_RDWR | O_CLOEXEC);
382 uart_channel = g_io_channel_unix_new(uart_fd);
383 g_io_channel_set_close_on_unref(uart_channel, TRUE);
385 g_io_channel_set_encoding(uart_channel, NULL, NULL);
386 g_io_channel_set_buffered(uart_channel, FALSE);
388 flags = g_io_channel_get_flags(uart_channel);
389 flags |= G_IO_FLAG_NONBLOCK;
390 g_io_channel_set_flags(uart_channel, flags, NULL);
392 err = set_default_baud_rate(uart_fd);
394 g_io_channel_shutdown(uart_channel, TRUE, NULL);
395 g_io_channel_unref(uart_channel);
401 if (baud_rate == 115200) {
405 if (ioctl(uart_fd, TIOCSETD, &ldisc) < 0) {
406 g_io_channel_shutdown(uart_channel, TRUE, NULL);
407 g_io_channel_unref(uart_channel);
412 __sync_synchronize();
417 cmd.uart_prefix = HCI_COMMAND_PKT;
418 cmd.opcode = HCI_HDR_OPCODE;
419 cmd.plen = sizeof(unsigned long);
420 cmd.speed = baud_rate;
422 uart_watch = g_io_add_watch(uart_channel,
423 G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
426 err = write(uart_fd, &cmd, sizeof(cmd));
428 connman_error("Write failed %d", err);
430 g_io_channel_shutdown(uart_channel, TRUE, NULL);
431 g_io_channel_unref(uart_channel);
439 static gboolean install_event(GIOChannel *channel,
440 GIOCondition cond, gpointer data)
442 GIOStatus status = G_IO_STATUS_NORMAL;
443 unsigned int install_state;
450 if (cond & (G_IO_HUP | G_IO_NVAL)) {
451 connman_error("install event 0x%x", cond);
455 __sync_synchronize();
456 if (install_count != 0) {
457 status = g_io_channel_seek_position(channel, 0, G_SEEK_SET, NULL);
458 if (status != G_IO_STATUS_NORMAL) {
459 g_io_channel_shutdown(channel, TRUE, NULL);
460 g_io_channel_unref(channel);
464 /* Read the install value */
465 status = g_io_channel_read_chars(channel, (gchar *) buf, 8, &len, NULL);
466 if (status != G_IO_STATUS_NORMAL) {
467 g_io_channel_shutdown(channel, TRUE, NULL);
468 g_io_channel_unref(channel);
472 install_state = atoi(buf);
473 DBG("install event while installing %d %c", install_state, buf[0]);
478 __sync_synchronize();
481 status = g_io_channel_seek_position(channel, 0, G_SEEK_SET, NULL);
482 if (status != G_IO_STATUS_NORMAL) {
483 g_io_channel_shutdown(channel, TRUE, NULL);
484 g_io_channel_unref(channel);
488 /* Read the install value */
489 status = g_io_channel_read_chars(channel, (gchar *) buf, 8, &len, NULL);
490 if (status != G_IO_STATUS_NORMAL) {
491 g_io_channel_shutdown(channel, TRUE, NULL);
492 g_io_channel_unref(channel);
496 install_state = atoi(buf);
498 DBG("install state %d", install_state);
500 install = !!install_state;
502 if (install_ldisc(channel, install) < 0) {
503 connman_error("ldisc installation failed");
505 __sync_synchronize();
513 static int tist_init(void)
515 GIOStatus status = G_IO_STATUS_NORMAL;
517 unsigned int install_state;
522 err = read_uart_name(uart_dev_name, sizeof(uart_dev_name));
524 connman_error("Could not read the UART name");
528 err = read_baud_rate(&baud_rate);
530 connman_error("Could not read the baud rate");
534 fd = open(TIST_SYSFS_INSTALL, O_RDONLY | O_CLOEXEC);
536 connman_error("Failed to open TI ST sysfs install file");
540 install_channel = g_io_channel_unix_new(fd);
541 g_io_channel_set_close_on_unref(install_channel, TRUE);
543 g_io_channel_set_encoding(install_channel, NULL, NULL);
544 g_io_channel_set_buffered(install_channel, FALSE);
546 flags = g_io_channel_get_flags(install_channel);
547 flags |= G_IO_FLAG_NONBLOCK;
548 g_io_channel_set_flags(install_channel, flags, NULL);
550 status = g_io_channel_read_chars(install_channel, (gchar *) buf, 8,
552 if (status != G_IO_STATUS_NORMAL) {
553 g_io_channel_shutdown(install_channel, TRUE, NULL);
554 g_io_channel_unref(install_channel);
558 status = g_io_channel_seek_position(install_channel, 0, G_SEEK_SET, NULL);
559 if (status != G_IO_STATUS_NORMAL) {
560 connman_error("Initial seek failed");
561 g_io_channel_shutdown(install_channel, TRUE, NULL);
562 g_io_channel_unref(install_channel);
566 install_state = atoi(buf);
568 DBG("Initial state %d", install_state);
570 install_watch = g_io_add_watch_full(install_channel, G_PRIORITY_HIGH,
572 install_event, NULL, NULL);
576 __sync_synchronize();
578 err = install_ldisc(install_channel, TRUE);
580 connman_error("ldisc installtion failed");
589 static void tist_exit(void)
592 if (install_watch > 0)
593 g_source_remove(install_watch);
595 DBG("uart_channel %p", uart_channel);
597 g_io_channel_shutdown(install_channel, TRUE, NULL);
598 g_io_channel_unref(install_channel);
600 if (uart_channel != NULL) {
601 g_io_channel_shutdown(uart_channel, TRUE, NULL);
602 g_io_channel_unref(uart_channel);
608 CONNMAN_PLUGIN_DEFINE(tist, "TI shared transport support", VERSION,
609 CONNMAN_PLUGIN_PRIORITY_DEFAULT, tist_init, tist_exit)