aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVincent Cuissard <cuissard@marvell.com>2015-06-15 11:14:36 +0200
committerSamuel Ortiz <sameo@linux.intel.com>2015-08-22 00:43:35 +0200
commit3cbcea75d474351383d00bb9a75cc5caf034ec49 (patch)
tree20da55ff25444fa52da8eb7ec38e6c51bd0284e9
parent0ba961c0033dc80f312744dd523eabec0b416086 (diff)
downloadneard-3cbcea75d474351383d00bb9a75cc5caf034ec49.tar.gz
tools: Add nciattach tool
This tool is needed to configure NCI UART drivers.
-rw-r--r--Makefile.am4
-rw-r--r--include/nfc_copy.h12
-rw-r--r--tools/nciattach.c350
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;
+}