diff options
author | Vincent Cuissard <cuissard@marvell.com> | 2015-06-15 11:14:36 +0200 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2015-08-22 00:43:35 +0200 |
commit | 3cbcea75d474351383d00bb9a75cc5caf034ec49 (patch) | |
tree | 20da55ff25444fa52da8eb7ec38e6c51bd0284e9 | |
parent | 0ba961c0033dc80f312744dd523eabec0b416086 (diff) | |
download | neard-3cbcea75d474351383d00bb9a75cc5caf034ec49.tar.gz |
tools: Add nciattach tool
This tool is needed to configure NCI UART drivers.
-rw-r--r-- | Makefile.am | 4 | ||||
-rw-r--r-- | include/nfc_copy.h | 12 | ||||
-rw-r--r-- | tools/nciattach.c | 350 |
3 files changed, 365 insertions, 1 deletions
diff --git a/Makefile.am b/Makefile.am index ad25ba3..00160de 100644 --- a/Makefile.am +++ b/Makefile.am @@ -155,7 +155,7 @@ test_SCRIPTS = $(test_scripts) endif if TOOLS -bin_PROGRAMS += tools/nfctool/nfctool +bin_PROGRAMS += tools/nfctool/nfctool tools/nciattach noinst_PROGRAMS = tools/snep-send @@ -191,6 +191,8 @@ tools_nfctool_nfctool_CPPFLAGS = ${GLIB_CFLAGS} ${DBUS_CFLAGS} ${NETLINK_CFLAGS} -DCONFIGDIR=\""$(configdir)\"" \ -I$(builddir)/include -I$(builddir)/src -I$(srcdir)/gdbus +tools_nciattach_SOURCES = tools/nciattach.c + unit_tests = unit/test-ndef-parse unit/test-ndef-build unit/test-snep-read unit_test_ndef_parse_SOURCES = $(gdbus_sources) src/log.c src/dbus.c \ diff --git a/include/nfc_copy.h b/include/nfc_copy.h index 0b25f5c..9e21738 100644 --- a/include/nfc_copy.h +++ b/include/nfc_copy.h @@ -287,4 +287,16 @@ struct sockaddr_nfc_llcp { #define NFC_LLCP_REMOTE_LTO 3 #define NFC_LLCP_REMOTE_RW 4 +#ifndef N_NCI +#define N_NCI 25 +#endif + +/* Ioctl */ +#define NCIUARTSETDRIVER _IOW('U', 0, char *) + +enum nci_uart_driver { + NCI_UART_DRIVER_MARVELL = 0, + NCI_UART_DRIVER_MAX +}; + #endif /*__LINUX_NFC_H */ diff --git a/tools/nciattach.c b/tools/nciattach.c new file mode 100644 index 0000000..c71d9c7 --- /dev/null +++ b/tools/nciattach.c @@ -0,0 +1,350 @@ +/* + * Copyright (C) 2015 Marvell International Ltd. + * + * This software file (the "File") is distributed by Marvell International + * Ltd. under the terms of the GNU General Public License Version 2, June 1991 + * (the "License"). You may use, redistribute and/or modify this File in + * accordance with the terms and conditions of the License, a copy of which + * is available on the worldwide web at + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt. + * + * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE + * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE + * ARE EXPRESSLY DISCLAIMED. The License provides additional details about + * this warranty disclaimer. + */ + +/* + * Adaptation of Bluez hciattach.c + * + * Copyright (C) 2000-2001 Qualcomm Incorporated + * Copyright (C) 2002-2003 Maxim Krasnyansky <maxk@qualcomm.com> + * Copyright (C) 2002-2010 Marcel Holtmann <marcel@holtmann.org> + */ + +#define _GNU_SOURCE + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <syslog.h> +#include <termios.h> +#include <time.h> +#include <sys/time.h> +#include <sys/poll.h> +#include <sys/param.h> +#include <sys/ioctl.h> +#include <termios.h> +#include <linux/tty.h> +#include "near.h" + +#define FLOW_CTL 0x0001 +#define ENABLE_PM 1 +#define DISABLE_PM 0 + +struct nci_driver_info { + const char *name; + enum nci_uart_driver driver_id; +}; + +static struct nci_driver_info __nci_drivers[] = { + { .name = "marvell", .driver_id = NCI_UART_DRIVER_MARVELL }, +}; + +static volatile sig_atomic_t __io_canceled = 0; + +static void sig_hup(int sig) +{ +} + +static void sig_term(int sig) +{ + __io_canceled = 1; +} + +static int uart_speed(int s) +{ + switch (s) { + case 9600: + return B9600; + case 19200: + return B19200; + case 38400: + return B38400; + case 57600: + return B57600; + case 115200: + return B115200; + case 230400: + return B230400; + case 460800: + return B460800; + case 500000: + return B500000; + case 576000: + return B576000; + case 921600: + return B921600; + case 1000000: + return B1000000; + case 1152000: + return B1152000; + case 1500000: + return B1500000; + case 2000000: + return B2000000; +#ifdef B2500000 + case 2500000: + return B2500000; +#endif +#ifdef B3000000 + case 3000000: + return B3000000; +#endif +#ifdef B3500000 + case 3500000: + return B3500000; +#endif +#ifdef B3710000 + case 3710000 + return B3710000; +#endif +#ifdef B4000000 + case 4000000: + return B4000000; +#endif + default: + return B57600; + } +} + +static int set_speed(int fd, struct termios *ti, int speed) +{ + if (cfsetospeed(ti, uart_speed(speed)) < 0) + return -errno; + + if (cfsetispeed(ti, uart_speed(speed)) < 0) + return -errno; + + if (tcsetattr(fd, TCSANOW, ti) < 0) + return -errno; + + return 0; +} + +/* Initialize UART driver */ +static int init_uart(char *dev, const char *driver, int speed, int flow_control) +{ + struct termios ti; + int fd; + unsigned int i; + int driver_id = -1; + + /* Find the driver */ + for (i = 0; i < sizeof (__nci_drivers) / sizeof (__nci_drivers[0]); ++i) + if (!strcmp(driver, __nci_drivers[i].name)) { + driver_id = __nci_drivers[i].driver_id; + break; + } + + if (driver_id < 0) { + errno = ENOENT; + perror("unknown driver"); + return -1; + } + + + fd = open(dev, O_RDWR | O_NOCTTY); + if (fd < 0) { + perror("Can't open serial port"); + return -1; + } + + tcflush(fd, TCIOFLUSH); + + if (tcgetattr(fd, &ti) < 0) { + perror("Can't get port settings"); + return -1; + } + + cfmakeraw(&ti); + + ti.c_cflag |= CLOCAL; + if (flow_control) + ti.c_cflag |= CRTSCTS; + else + ti.c_cflag &= ~CRTSCTS; + + if (tcsetattr(fd, TCSANOW, &ti) < 0) { + perror("Can't set port settings"); + return -1; + } + + /* Set initial baudrate */ + if (set_speed(fd, &ti, speed) < 0) { + perror("Can't set baud rate"); + return -1; + } + + tcflush(fd, TCIOFLUSH); + + /* Set TTY to N_NCI line discipline */ + i = N_NCI; + if (ioctl(fd, TIOCSETD, &i) < 0) { + perror("Can't set line discipline"); + return -1; + } + + if (ioctl(fd, NCIUARTSETDRIVER, driver_id) < 0) { + perror("Can't set driver"); + return -1; + } + + return fd; +} + +static void usage(void) +{ + printf("nciattach - NCI UART driver initialization utility\n"); + printf("Usage:\n"); + printf("\tnciattach [-n] [-p] <tty> <driver> " + "[speed] [flow|noflow]\n"); +} + +int main(int argc, char *argv[]) +{ + int detach, printpid, opt, i, n, ld, err; + pid_t pid; + int speed = 115200; + int flow_control = 0; + struct sigaction sa; + struct pollfd p; + sigset_t sigs; + char dev[PATH_MAX]; + char driver[32]; + + detach = 1; + printpid = 0; + + while ((opt=getopt(argc, argv, "np")) != EOF) { + switch(opt) { + case 'n': + detach = 0; + break; + + case 'p': + printpid = 1; + break; + + default: + usage(); + exit(1); + } + } + + n = argc - optind; + if (n < 2) { + usage(); + exit(1); + } + + for (n = 0; optind < argc; n++, optind++) { + char *opt; + + opt = argv[optind]; + + switch(n) { + case 0: + dev[0] = 0; + if (!strchr(opt, '/')) + strcpy(dev, "/dev/"); + strcat(dev, opt); + break; + + case 1: + memset(driver, 0, sizeof (driver)); + strcpy(driver, argv[optind]); + break; + + case 2: + speed = atoi(argv[optind]); + break; + + case 3: + if (!strcmp("flow", argv[optind])) + flow_control = 1; + else + flow_control = 0; + break; + } + } + + memset(&sa, 0, sizeof(sa)); + + n = init_uart(dev, driver, speed, flow_control); + if (n < 0) { + perror("Can't initialize device"); + exit(1); + } + + memset(&sa, 0, sizeof(sa)); + sa.sa_flags = SA_NOCLDSTOP; + sa.sa_handler = SIG_IGN; + sigaction(SIGCHLD, &sa, NULL); + sigaction(SIGPIPE, &sa, NULL); + + sa.sa_handler = sig_term; + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + + sa.sa_handler = sig_hup; + sigaction(SIGHUP, &sa, NULL); + + if (detach) { + if ((pid = fork())) { + if (printpid) + printf("%d\n", pid); + return 0; + } + + for (i = 0; i < 20; i++) + if (i != n) + close(i); + } + + p.fd = n; + p.events = POLLERR | POLLHUP; + + sigfillset(&sigs); + sigdelset(&sigs, SIGCHLD); + sigdelset(&sigs, SIGPIPE); + sigdelset(&sigs, SIGTERM); + sigdelset(&sigs, SIGINT); + sigdelset(&sigs, SIGHUP); + + while (!__io_canceled) { + p.revents = 0; + err = ppoll(&p, 1, NULL, &sigs); + if (err < 0 && errno == EINTR) + continue; + if (err) + break; + } + + /* Restore TTY line discipline */ + ld = N_TTY; + if (ioctl(n, TIOCSETD, &ld) < 0) { + perror("Can't restore line discipline"); + exit(1); + } + + return 0; +} |