4d3561e486df01db8976869801b0029be6550d75
[platform/upstream/connman.git] / plugins / tist.c
1 /*
2  *
3  *  Connection Manager
4  *
5  *  Copyright (C) 2012  Intel Corporation. All rights reserved.
6  *
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.
10  *
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.
15  *
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
19  *
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #define _GNU_SOURCE
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <unistd.h>
32 #include <string.h>
33 #include <stdint.h>
34 #include <sys/ioctl.h>
35 #include <termios.h>
36 #include <unistd.h>
37
38 #include <gdbus.h>
39
40 #define CONNMAN_API_SUBJECT_TO_CHANGE
41 #include <connman/plugin.h>
42 #include <connman/log.h>
43
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"
47
48 /* Shared transport line discipline */
49 #define N_TI_WL 22
50
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;
55
56 static guint install_watch = 0;
57 static guint uart_watch = 0;
58
59 static int install_count = 0;
60
61 #define NCCS2 19
62 struct termios2 {
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 */
71 };
72
73 #define  BOTHER         0x00001000
74
75 /* HCI definitions */
76 #define HCI_HDR_OPCODE          0xff36
77 #define HCI_COMMAND_PKT         0x01
78 #define HCI_EVENT_PKT           0x04
79 #define EVT_CMD_COMPLETE        0x0E
80
81 /* HCI Command structure to set the target baud rate */
82 struct speed_change_cmd {
83         uint8_t uart_prefix;
84         uint16_t opcode;
85         uint8_t plen;
86         uint32_t speed;
87 } __attribute__ ((packed));
88
89 /* HCI Event structure to set the cusrom baud rate*/
90 struct cmd_complete {
91         uint8_t uart_prefix;
92         uint8_t evt;
93         uint8_t plen;
94         uint8_t ncmd;
95         uint16_t opcode;
96         uint8_t status;
97         uint8_t data[16];
98 } __attribute__ ((packed));
99
100 static int read_baud_rate(unsigned long *baud)
101 {
102         int err;
103         FILE *f;
104
105         DBG("");
106
107         f = fopen(TIST_SYSFS_BAUD, "r");
108         if (f == NULL)
109                 return -EIO;
110
111         err = fscanf(f, "%lu", baud);
112         fclose(f);
113
114         DBG("baud rate %lu", *baud);
115
116         return err;
117 }
118
119 static int read_uart_name(char uart_name[], size_t uart_name_len)
120 {
121         int err;
122         FILE *f;
123
124         DBG("");
125
126         memset(uart_name, 0, uart_name_len);
127
128         f = fopen(TIST_SYSFS_UART, "r");
129         if (f == NULL)
130                 return -EIO;
131
132         err = fscanf(f, "%s", uart_name);
133         fclose(f);
134
135         DBG("UART name %s", uart_name);
136
137         return err;
138 }
139
140 static int read_hci_event(int fd, unsigned char *buf, int size)
141 {
142         int prefix_len, param_len;
143
144         if (size <= 0)
145                 return -EINVAL;
146
147         /* First 3 bytes are prefix, event and param length */
148         prefix_len = read(fd, buf, 3);
149         if (prefix_len < 0)
150                 return prefix_len;
151
152         if (prefix_len < 3) {
153                 connman_error("Truncated HCI prefix %d bytes 0x%x",
154                                                 prefix_len, buf[0]);
155                 return -EIO;
156         }
157
158         DBG("type 0x%x event 0x%x param len %d", buf[0], buf[1], buf[2]);
159
160         param_len = buf[2];
161         if (param_len > size - 3) {
162                 connman_error("Buffer is too small %d", size);
163                 return -EINVAL;
164         }
165
166         return read(fd, buf + 3, param_len);
167 }
168
169 static int read_command_complete(int fd, unsigned short opcode)
170 {
171         struct cmd_complete resp;
172         int err;
173
174         DBG("");
175
176         err = read_hci_event(fd, (unsigned char *)&resp, sizeof(resp));
177         if (err < 0)
178                 return err;
179
180         DBG("HCI event %d bytes", err);
181
182         if (resp.uart_prefix != HCI_EVENT_PKT) {
183                 connman_error("Not an event packet");
184                 return -EIO;
185         }
186
187         if (resp.evt != EVT_CMD_COMPLETE) {
188                 connman_error("Not a cmd complete event");
189                 return -EIO;
190         }
191
192         if (resp.plen < 4) {
193                 connman_error("HCI header length %d", resp.plen);
194                 return -EIO;
195         }
196
197         if (resp.opcode != (unsigned short) opcode) {
198                 connman_error("opcode 0x%04x 0x%04x", resp.opcode, opcode);
199                 return -EIO;
200         }
201
202         return 0;
203 }
204
205 /* The default baud rate is 115200 */
206 static int set_default_baud_rate(int fd)
207 {
208         struct termios ti;
209         int err;
210
211         DBG("");
212
213         err = tcflush(fd, TCIOFLUSH);
214         if (err < 0)
215                 goto err;
216
217         err = tcgetattr(fd, &ti);
218         if (err < 0)
219                 goto err;
220
221         cfmakeraw(&ti);
222
223         ti.c_cflag |= 1;
224         ti.c_cflag |= CRTSCTS;
225
226         err = tcsetattr(fd, TCSANOW, &ti);
227         if (err < 0)
228                 goto err;
229
230         cfsetospeed(&ti, B115200);
231         cfsetispeed(&ti, B115200);
232
233         err = tcsetattr(fd, TCSANOW, &ti);
234         if (err < 0)
235                 goto err;
236
237         err = tcflush(fd, TCIOFLUSH);
238         if (err < 0)
239                 goto err;
240
241         return 0;
242
243 err:
244         connman_error("%s", strerror(errno));
245
246         return err;
247 }
248
249 static int set_custom_baud_rate(int fd, unsigned long cus_baud_rate, int flow_ctrl)
250 {
251         struct termios ti;
252         struct termios2 ti2;
253         int err;
254
255         DBG("baud rate %lu flow_ctrl %d", cus_baud_rate, flow_ctrl);
256
257         err = tcflush(fd, TCIOFLUSH);
258         if (err < 0)
259                 goto err;
260
261         err = tcgetattr(fd, &ti);
262         if (err < 0)
263                 goto err;
264
265         if (flow_ctrl)
266                 ti.c_cflag |= CRTSCTS;
267         else
268                 ti.c_cflag &= ~CRTSCTS;
269
270         /*
271          * Set the parameters associated with the UART
272          * The change will occur immediately by using TCSANOW.
273          */
274         err = tcsetattr(fd, TCSANOW, &ti);
275         if (err < 0)
276                 goto err;
277
278         err = tcflush(fd, TCIOFLUSH);
279         if (err < 0)
280                 goto err;
281
282         /* Set the actual baud rate */
283         err = ioctl(fd, TCGETS2, &ti2);
284         if (err < 0)
285                 goto err;
286
287         ti2.c_cflag &= ~CBAUD;
288         ti2.c_cflag |= BOTHER;
289         ti2.c_ospeed = cus_baud_rate;
290
291         err = ioctl(fd, TCSETS2, &ti2);
292         if (err < 0)
293                 goto err;
294
295         return 0;
296
297 err:
298         DBG("%s", strerror(errno));
299
300         return err;
301 }
302
303 static gboolean uart_event(GIOChannel *channel,
304                                 GIOCondition cond, gpointer data)
305 {
306         int uart_fd, ldisc;
307
308         DBG("");
309
310         uart_fd = g_io_channel_unix_get_fd(channel);
311
312         if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) {
313                 connman_error("UART event 0x%x", cond);
314                 if (uart_watch > 0)
315                         g_source_remove(uart_watch);
316
317                 goto err;
318         }
319
320         if (read_command_complete(uart_fd, HCI_HDR_OPCODE) < 0)
321                 goto err;
322
323         if (set_custom_baud_rate(uart_fd, baud_rate, 1) < 0)
324                 goto err;
325
326         ldisc = N_TI_WL;
327         if (ioctl(uart_fd, TIOCSETD, &ldisc) < 0)
328                 goto err;
329
330         install_count = 1;
331         __sync_synchronize();
332
333         return FALSE;
334
335 err:
336         install_count = 0;
337         __sync_synchronize();
338
339         g_io_channel_shutdown(channel, TRUE, NULL);
340         g_io_channel_unref(channel);
341
342         return FALSE;
343 }
344
345 static int install_ldisc(GIOChannel *channel, gboolean install)
346 {
347         int uart_fd, err;
348         struct speed_change_cmd cmd;
349         GIOFlags flags;
350
351         DBG("%d %p", install, uart_channel);
352
353         if (install == FALSE) {
354                 install_count = 0;
355                 __sync_synchronize();
356
357                 if (uart_channel == NULL) {
358                         DBG("UART channel is NULL");
359                         return 0;
360                 }
361
362                 g_io_channel_shutdown(uart_channel, TRUE, NULL);
363                 g_io_channel_unref(uart_channel);
364
365                 uart_channel = NULL;
366
367                 return 0;
368         }
369
370         if (uart_channel != NULL) {
371                 g_io_channel_shutdown(uart_channel, TRUE, NULL);
372                 g_io_channel_unref(uart_channel);
373                 uart_channel = NULL;
374         }
375
376         DBG("opening %s custom baud %lu", uart_dev_name, baud_rate);
377         
378         uart_fd = open(uart_dev_name, O_RDWR | O_CLOEXEC);
379         if (uart_fd < 0)
380                 return -EIO;
381
382         uart_channel = g_io_channel_unix_new(uart_fd);  
383         g_io_channel_set_close_on_unref(uart_channel, TRUE);
384
385         g_io_channel_set_encoding(uart_channel, NULL, NULL);
386         g_io_channel_set_buffered(uart_channel, FALSE);
387
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);
391
392         err = set_default_baud_rate(uart_fd);
393         if (err < 0) {
394                 g_io_channel_shutdown(uart_channel, TRUE, NULL);
395                 g_io_channel_unref(uart_channel);
396                 uart_channel = NULL;
397
398                 return err;
399         }
400
401         if (baud_rate == 115200) {
402                 int ldisc;
403
404                 ldisc = N_TI_WL;
405                 if (ioctl(uart_fd, TIOCSETD, &ldisc) < 0) {
406                         g_io_channel_shutdown(uart_channel, TRUE, NULL);
407                         g_io_channel_unref(uart_channel);
408                         uart_channel = NULL;
409                 }
410
411                 install_count = 0;
412                 __sync_synchronize();
413
414                 return 0;
415         }
416
417         cmd.uart_prefix = HCI_COMMAND_PKT;
418         cmd.opcode = HCI_HDR_OPCODE;
419         cmd.plen = sizeof(unsigned long);
420         cmd.speed = baud_rate;
421
422         uart_watch = g_io_add_watch(uart_channel,
423                         G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
424                                 uart_event, NULL);
425
426         err = write(uart_fd, &cmd, sizeof(cmd));
427         if (err < 0) {
428                 connman_error("Write failed %d", err);
429
430                 g_io_channel_shutdown(uart_channel, TRUE, NULL);
431                 g_io_channel_unref(uart_channel);
432                 uart_channel = NULL;
433         }
434
435         return err;
436 }
437
438
439 static gboolean install_event(GIOChannel *channel,
440                                 GIOCondition cond, gpointer data)
441 {
442         GIOStatus status = G_IO_STATUS_NORMAL;
443         unsigned int install_state;
444         gboolean install;
445         char buf[8];
446         gsize len;
447
448         DBG("");
449
450         if (cond & (G_IO_HUP | G_IO_NVAL)) {
451                 connman_error("install event 0x%x", cond);
452                 return FALSE;
453         }
454
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);
461                         return FALSE;
462                 }
463
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);
469                         return FALSE;
470                 }
471
472                 install_state = atoi(buf);
473                 DBG("install event while installing %d %c", install_state, buf[0]);
474
475                 return TRUE;
476         } else {
477                 install_count = 1;
478                 __sync_synchronize();
479         }
480
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);
485                 return FALSE;
486         }
487
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);
493                 return FALSE;
494         }
495
496         install_state = atoi(buf);
497
498         DBG("install state %d", install_state);
499
500         install = !!install_state;
501
502         if (install_ldisc(channel, install) < 0) {
503                 connman_error("ldisc installation failed");
504                 install_count = 0;
505                 __sync_synchronize();
506                 return TRUE;
507         }
508
509         return TRUE;
510 }
511
512
513 static int tist_init(void)
514 {
515         GIOStatus status = G_IO_STATUS_NORMAL;
516         GIOFlags flags;
517         unsigned int install_state;
518         char buf[8];
519         int fd, err;
520         gsize len;
521
522         err = read_uart_name(uart_dev_name, sizeof(uart_dev_name));
523         if (err < 0) {
524                 connman_error("Could not read the UART name");
525                 return err;
526         }
527
528         err = read_baud_rate(&baud_rate);
529         if (err < 0) {
530                 connman_error("Could not read the baud rate");
531                 return err;
532         }
533
534         fd = open(TIST_SYSFS_INSTALL, O_RDONLY | O_CLOEXEC);
535         if (fd < 0) {
536                 connman_error("Failed to open TI ST sysfs install file");
537                 return -EIO;
538         }
539
540         install_channel = g_io_channel_unix_new(fd);
541         g_io_channel_set_close_on_unref(install_channel, TRUE);
542
543         g_io_channel_set_encoding(install_channel, NULL, NULL);
544         g_io_channel_set_buffered(install_channel, FALSE);
545
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);
549
550         status = g_io_channel_read_chars(install_channel, (gchar *) buf, 8,
551                                                                 &len, NULL);
552         if (status != G_IO_STATUS_NORMAL) {
553                 g_io_channel_shutdown(install_channel, TRUE, NULL);
554                 g_io_channel_unref(install_channel);
555                 return status;
556         }
557
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);
563                 return -EIO;
564         }
565
566         install_state = atoi(buf);
567
568         DBG("Initial state %d", install_state);
569
570         install_watch = g_io_add_watch_full(install_channel, G_PRIORITY_HIGH,
571                                 G_IO_PRI | G_IO_ERR,
572                                             install_event, NULL, NULL);
573
574         if (install_state) {
575                 install_count = 1;
576                 __sync_synchronize();
577
578                 err = install_ldisc(install_channel, TRUE);
579                 if (err < 0) {
580                         connman_error("ldisc installtion failed");
581                         return err;
582                 }
583         }
584
585         return 0;
586 }
587
588
589 static void tist_exit(void)
590 {
591
592         if (install_watch > 0)
593                 g_source_remove(install_watch);
594
595         DBG("uart_channel %p", uart_channel);
596
597         g_io_channel_shutdown(install_channel, TRUE, NULL);
598         g_io_channel_unref(install_channel);
599
600         if (uart_channel != NULL) {
601                 g_io_channel_shutdown(uart_channel, TRUE, NULL);
602                 g_io_channel_unref(uart_channel);
603                 uart_channel = NULL;
604         }
605
606 }
607
608 CONNMAN_PLUGIN_DEFINE(tist, "TI shared transport support", VERSION,
609                 CONNMAN_PLUGIN_PRIORITY_DEFAULT, tist_init, tist_exit)