summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--io-module/Makefile5
-rw-r--r--io-module/mts_io.c1334
-rw-r--r--io-module/mts_io.h7
-rwxr-xr-xio-tool/mts-io-sysfs241
-rw-r--r--io-tool/mts-io-sysfs-inc.sh92
-rwxr-xr-xio-tool/sysfs-tests181
6 files changed, 1860 insertions, 0 deletions
diff --git a/io-module/Makefile b/io-module/Makefile
new file mode 100644
index 0000000..c82afc5
--- /dev/null
+++ b/io-module/Makefile
@@ -0,0 +1,5 @@
+obj-m := mts_io.o
+
+clean:
+ rm -f *.ko
+
diff --git a/io-module/mts_io.c b/io-module/mts_io.c
new file mode 100644
index 0000000..a10b6c3
--- /dev/null
+++ b/io-module/mts_io.c
@@ -0,0 +1,1334 @@
+/*
+ * IO Controller for the Sparkcell Platform
+ *
+ * Copyright (C) 2010 by Multi-Tech Systems
+ *
+ * Author: James Maki <jmaki@multitech.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+/*
+ * See arch/arm/mach-at91board-sam9g20ek.c for an alternate approach to
+ * setting LEDs (ek_leds) and adding platform devices and platform drivers.
+ *
+ */
+#include <linux/delay.h>
+#include <linux/ioctl.h>
+#include <linux/input.h>
+#include <linux/cdev.h>
+#include <linux/clk.h>
+#include <linux/sched.h>
+#include <linux/reboot.h>
+#include <linux/uaccess.h>
+#include <linux/gpio.h>
+#include <linux/sched.h>
+#include <linux/workqueue.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/bitops.h>
+
+#include "mts_io.h"
+
+#define DRIVER_VERSION "v0.2.0"
+#define DRIVER_AUTHOR "James Maki <jmaki@multitech.com>"
+#define DRIVER_DESC "IO Controller for the SparkCell Platform"
+#define DRIVER_NAME "mts-io"
+
+#define PLATFORM_NAME "sparkcell"
+
+#if DEBUG
+# define dbg(fmt, args...) printk(KERN_DEBUG __FILE__ ": " fmt "\n" , ##args)
+#else
+# define dbg(fmt, args...) do {} while (0)
+#endif
+#define error(fmt, args...) printk(KERN_ERR __FILE__ ": " fmt "\n" , ##args)
+#define info(fmt, args...) printk(KERN_INFO fmt "\n" , ##args)
+
+#define BOARD_REVA 0
+#define BOARD_REVB 1
+#define BOARD_REVC 2
+
+#define LED_CD_BIT BIT(0)
+#define EXTSERIAL_RI_BIT BIT(1)
+#define EXTSERIAL_DSR_BIT BIT(2)
+#define CS0_BIT3 BIT(3)
+#define LED_SIG1_BIT BIT(4)
+#define LED_SIG2_BIT BIT(5)
+#define LED_SIG3_BIT BIT(6)
+#define EXTSERIAL_DCD_BIT BIT(7)
+
+#define GPIO_CS0 AT91_PIN_PB3
+#define GPIO_CS1 AT91_PIN_PC5
+#define GPIO_CS2 AT91_PIN_PC4
+#define GPIO_CS3 AT91_PIN_PC3
+#define GPIO_ENIO AT91_PIN_PC15
+#define GPIO_ETH0_ENABLED AT91_PIN_PB31
+#define GPIO_RADIO_RESET AT91_PIN_PB30
+#define GPIO_OPTRST AT91_PIN_PA22
+#define GPIO_LS_LED AT91_PIN_PC9
+#define GPIO_SERCLK AT91_PIN_PB2
+#define GPIO_SERDOUT AT91_PIN_PB1
+#define GPIO_SERDIN AT91_PIN_PB0
+#define GPIO_VER0 AT91_PIN_PA23
+#define GPIO_VER1 AT91_PIN_PA24
+#define GPIO_RSERSRC AT91_PIN_PC7
+#define GPIO_DBSERON AT91_PIN_PC6
+#define GPIO_DTR1 AT91_PIN_PC10
+#define GPIO_RXD1MON AT91_PIN_PC8
+#define GPIO_EXTIN0 AT91_PIN_PB13
+#define GPIO_EXTIN1 AT91_PIN_PB12
+#define GPIO_EXTIN2 AT91_PIN_PB11
+#define GPIO_EXTIN3 AT91_PIN_PB10
+#define GPIO_EXTIN4 AT91_PIN_PB9
+#define GPIO_EXTIN5 AT91_PIN_PB8
+#define GPIO_GPS_NINT2 AT91_PIN_PC2
+#define GPIO_STATUS_LED AT91_PIN_PA30
+
+#define LED_STATUS_CONTROLLABLE 1
+#define LED_LS_CONTROLLABLE 0
+
+enum {
+ LED_OFF,
+ LED_ON,
+ LED_FLASHING,
+};
+
+static u8 board_rev = BOARD_REVA;
+static u8 cs0_bits = 0xFF;
+static DEFINE_MUTEX(mts_io_mutex);
+#if LED_STATUS_CONTROLLABLE
+static int led_mode_status = LED_OFF;
+#endif
+
+static pid_t reset_pid = -1;
+static pid_t reset_count = 0;
+static int reset_short_signal = SIGUSR1;
+static int reset_long_signal = SIGUSR2;
+
+
+#define BLINK_PER_SEC 8
+#define BLINK_INTERVAL (HZ / BLINK_PER_SEC)
+#define RESET_HOLD_COUNT (BLINK_PER_SEC * 3)
+
+static void blink_callback(struct work_struct *ignored);
+
+static DECLARE_DELAYED_WORK(blink_work, blink_callback);
+
+static void blink_callback(struct work_struct *ignored)
+{
+ unsigned long reset_pressed = !at91_get_gpio_value(GPIO_OPTRST);
+ struct pid *vpid = NULL;
+
+ mutex_lock(&mts_io_mutex);
+
+ if (reset_pid > 0) {
+ vpid = find_vpid(reset_pid);
+ }
+
+ if (vpid) {
+ if (reset_pressed) {
+ reset_count++;
+ } else if (reset_count > 0 && reset_count < RESET_HOLD_COUNT) {
+ kill_pid(vpid, reset_short_signal, 1);
+ reset_count = 0;
+ }
+
+ if (reset_count >= RESET_HOLD_COUNT) {
+ reset_count = 0;
+ kill_pid(vpid, reset_long_signal, 1);
+ }
+ } else {
+ reset_count = 0;
+ }
+
+#if LED_STATUS_CONTROLLABLE
+ if (led_mode_status == LED_FLASHING) {
+ at91_set_gpio_value(GPIO_STATUS_LED, !at91_get_gpio_value(GPIO_STATUS_LED));
+ }
+#endif
+
+ mutex_unlock(&mts_io_mutex);
+
+ schedule_delayed_work(&blink_work, BLINK_INTERVAL);
+}
+
+static void serial_writeb(u8 data, int cs)
+{
+ int i;
+
+ if (board_rev == BOARD_REVA) {
+ if (cs == GPIO_CS0) {
+ cs = 2;
+ } else if (cs == GPIO_CS1) {
+ cs = 3;
+ } else if (cs == GPIO_CS2) {
+ cs = 4;
+ } else if (cs == GPIO_CS3) {
+ cs = 5;
+ } else {
+ return;
+ }
+ at91_set_gpio_value(GPIO_CS0, cs & 1);
+ at91_set_gpio_value(GPIO_CS1, cs & 2);
+ at91_set_gpio_value(GPIO_CS2, cs & 4);
+ } else {
+ at91_set_gpio_value(cs, 0);
+ }
+
+ for (i = 7; i >= 0; i--) {
+ at91_set_gpio_value(GPIO_SERDOUT, data & (1 << i));
+ at91_set_gpio_value(GPIO_SERCLK, 1);
+ at91_set_gpio_value(GPIO_SERCLK, 0);
+ }
+
+ if (board_rev == BOARD_REVA) {
+ at91_set_gpio_value(GPIO_CS0, 1);
+ at91_set_gpio_value(GPIO_CS1, 1);
+ at91_set_gpio_value(GPIO_CS2, 1);
+ } else {
+ at91_set_gpio_value(cs, 1);
+ }
+}
+
+static u16 serial_readw(int cs)
+{
+ int i;
+ u16 data;
+
+ at91_set_gpio_value(GPIO_SERCLK, 1);
+
+ /* set low so we don't power down temp sensor */
+ at91_set_gpio_value(GPIO_SERDOUT, 0);
+
+ if (board_rev == BOARD_REVA) {
+ if (cs == GPIO_CS0) {
+ cs = 2;
+ } else if (cs == GPIO_CS1) {
+ cs = 3;
+ } else if (cs == GPIO_CS2) {
+ cs = 4;
+ } else if (cs == GPIO_CS3) {
+ cs = 5;
+ } else {
+ cs = 2;
+ }
+ at91_set_gpio_value(GPIO_CS0, cs & 1);
+ at91_set_gpio_value(GPIO_CS1, cs & 2);
+ at91_set_gpio_value(GPIO_CS2, cs & 4);
+ } else {
+ at91_set_gpio_value(cs, 0);
+ }
+
+ data = 0;
+ for (i = 15; i >= 0; i--) {
+ at91_set_gpio_value(GPIO_SERCLK, 0);
+ at91_set_gpio_value(GPIO_SERCLK, 1);
+ data |= (((u16) at91_get_gpio_value(GPIO_SERDIN)) << i);
+ }
+
+ if (board_rev == BOARD_REVA) {
+ at91_set_gpio_value(GPIO_CS0, 1);
+ at91_set_gpio_value(GPIO_CS1, 1);
+ at91_set_gpio_value(GPIO_CS2, 1);
+ } else {
+ at91_set_gpio_value(cs, 1);
+ }
+
+ at91_set_gpio_value(GPIO_SERCLK, 0);
+
+ return data;
+}
+
+static int radio_reset(void)
+{
+ int ret;
+
+ ret = at91_set_gpio_value(GPIO_RADIO_RESET, 0);
+ if (ret) {
+ return ret;
+ }
+
+ udelay(1000);
+
+ ret = at91_set_gpio_value(GPIO_RADIO_RESET, 1);
+
+ return ret;
+}
+
+static int board_temperature(void)
+{
+ int temp;
+
+ temp = serial_readw(GPIO_CS2);
+
+ /*
+ * If sign bit set, convert raw value to negative integer.
+ * @see: ADT7302 datasheet
+ */
+ if (temp & 0x2000) {
+ temp = temp - 16384;
+ }
+
+ temp = temp / 32 + 1 * ((temp % 32) >= 16);
+
+ return temp;
+}
+
+static ssize_t show_radio_reset(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int value;
+
+ mutex_lock(&mts_io_mutex);
+
+ value = at91_get_gpio_value(GPIO_RADIO_RESET);
+
+ mutex_unlock(&mts_io_mutex);
+
+ if (value < 0) {
+ return value;
+ }
+
+ return sprintf(buf, "%d\n", value);
+}
+
+static ssize_t store_radio_reset(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int value;
+ int err;
+
+ if (sscanf(buf, "%i", &value) != 1) {
+ return -EINVAL;
+ }
+ if (value != 0) {
+ return -EINVAL;
+ }
+
+ mutex_lock(&mts_io_mutex);
+
+ err = radio_reset();
+
+ mutex_unlock(&mts_io_mutex);
+
+ if (err) {
+ return err;
+ }
+
+ return count;
+}
+
+static struct device_attribute dev_attr_radio_reset = {
+ .attr = {
+ .name = "radio-reset",
+ .mode = 0644,
+ },
+ .show = show_radio_reset,
+ .store = store_radio_reset,
+};
+
+static ssize_t show_eth0_enabled(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int value;
+
+ mutex_lock(&mts_io_mutex);
+
+ value = at91_get_gpio_value(GPIO_ETH0_ENABLED);
+
+ mutex_unlock(&mts_io_mutex);
+
+ if (value < 0) {
+ return value;
+ }
+
+ return sprintf(buf, "%d\n", value);
+}
+
+static ssize_t store_eth0_enabled(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int value;
+ int err;
+
+ if (sscanf(buf, "%i", &value) != 1) {
+ return -EINVAL;
+ }
+
+ mutex_lock(&mts_io_mutex);
+
+ err = at91_set_gpio_value(GPIO_ETH0_ENABLED, value);
+
+ mutex_unlock(&mts_io_mutex);
+
+ if (err) {
+ return err;
+ }
+
+ return count;
+}
+
+static struct device_attribute dev_attr_eth0_enabled = {
+ .attr = {
+ .name = "eth0-enabled",
+ .mode = 0644,
+ },
+ .show = show_eth0_enabled,
+ .store = store_eth0_enabled,
+};
+
+static ssize_t show_extserial_dcd(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int value;
+
+ mutex_lock(&mts_io_mutex);
+
+ value = !(cs0_bits & EXTSERIAL_DCD_BIT);
+
+ mutex_unlock(&mts_io_mutex);
+
+ return sprintf(buf, "%d\n", value);
+}
+
+static ssize_t store_extserial_dcd(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int value;
+
+ if (sscanf(buf, "%i", &value) != 1) {
+ return -EINVAL;
+ }
+
+ mutex_lock(&mts_io_mutex);
+
+ if (value) {
+ cs0_bits &= ~EXTSERIAL_DCD_BIT;
+ } else {
+ cs0_bits |= EXTSERIAL_DCD_BIT;
+ }
+ serial_writeb(cs0_bits, GPIO_CS0);
+
+ mutex_unlock(&mts_io_mutex);
+
+ return count;
+}
+
+static struct device_attribute dev_attr_extserial_dcd = {
+ .attr = {
+ .name = "extserial-dcd",
+ .mode = 0644,
+ },
+ .show = show_extserial_dcd,
+ .store = store_extserial_dcd,
+};
+
+static ssize_t show_extserial_ri(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int value;
+
+ mutex_lock(&mts_io_mutex);
+
+ value = !(cs0_bits & EXTSERIAL_RI_BIT);
+
+ mutex_unlock(&mts_io_mutex);
+
+ return sprintf(buf, "%d\n", value);
+}
+
+static ssize_t store_extserial_ri(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int value;
+
+ if (sscanf(buf, "%i", &value) != 1) {
+ return -EINVAL;
+ }
+
+ mutex_lock(&mts_io_mutex);
+
+ if (value) {
+ cs0_bits &= ~EXTSERIAL_RI_BIT;
+ } else {
+ cs0_bits |= EXTSERIAL_RI_BIT;
+ }
+ serial_writeb(cs0_bits, GPIO_CS0);
+
+ mutex_unlock(&mts_io_mutex);
+
+ return count;
+}
+
+static struct device_attribute dev_attr_extserial_ri = {
+ .attr = {
+ .name = "extserial-ri",
+ .mode = 0644,
+ },
+ .show = show_extserial_ri,
+ .store = store_extserial_ri,
+};
+
+static ssize_t show_extserial_dsr(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int value;
+
+ mutex_lock(&mts_io_mutex);
+
+ value = !(cs0_bits & EXTSERIAL_DSR_BIT);
+
+ mutex_unlock(&mts_io_mutex);
+
+ return sprintf(buf, "%d\n", value);
+}
+
+static ssize_t store_extserial_dsr(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int value;
+
+ if (sscanf(buf, "%i", &value) != 1) {
+ return -EINVAL;
+ }
+
+ mutex_lock(&mts_io_mutex);
+
+ if (value) {
+ cs0_bits &= ~EXTSERIAL_DSR_BIT;
+ } else {
+ cs0_bits |= EXTSERIAL_DSR_BIT;
+ }
+ serial_writeb(cs0_bits, GPIO_CS0);
+
+ mutex_unlock(&mts_io_mutex);
+
+ return count;
+}
+
+static struct device_attribute dev_attr_extserial_dsr = {
+ .attr = {
+ .name = "extserial-dsr",
+ .mode = 0644,
+ },
+ .show = show_extserial_dsr,
+ .store = store_extserial_dsr,
+};
+
+static ssize_t show_led_sig1(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int value;
+
+ mutex_lock(&mts_io_mutex);
+
+ value = !(cs0_bits & LED_SIG1_BIT);
+
+ mutex_unlock(&mts_io_mutex);
+
+ return sprintf(buf, "%d\n", value);
+}
+
+static ssize_t store_led_sig1(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int value;
+
+ if (sscanf(buf, "%i", &value) != 1) {
+ return -EINVAL;
+ }
+
+ mutex_lock(&mts_io_mutex);
+
+ if (value) {
+ cs0_bits &= ~LED_SIG1_BIT;
+ } else {
+ cs0_bits |= LED_SIG1_BIT;
+ }
+ serial_writeb(cs0_bits, GPIO_CS0);
+
+ mutex_unlock(&mts_io_mutex);
+
+ return count;
+}
+
+static struct device_attribute dev_attr_led_sig1 = {
+ .attr = {
+ .name = "led-sig1",
+ .mode = 0644,
+ },
+ .show = show_led_sig1,
+ .store = store_led_sig1,
+};
+
+static struct device_attribute dev_attr_led_sdk_c = {
+ .attr = {
+ .name = "led-sdk-c",
+ .mode = 0644,
+ },
+ .show = show_led_sig1,
+ .store = store_led_sig1,
+};
+
+static ssize_t show_led_sig2(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int value;
+
+ mutex_lock(&mts_io_mutex);
+
+ value = !(cs0_bits & LED_SIG2_BIT);
+
+ mutex_unlock(&mts_io_mutex);
+
+ return sprintf(buf, "%d\n", value);
+}
+
+static ssize_t store_led_sig2(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int value;
+
+ if (sscanf(buf, "%i", &value) != 1) {
+ return -EINVAL;
+ }
+
+ mutex_lock(&mts_io_mutex);
+
+ if (value) {
+ cs0_bits &= ~LED_SIG2_BIT;
+ } else {
+ cs0_bits |= LED_SIG2_BIT;
+ }
+ serial_writeb(cs0_bits, GPIO_CS0);
+
+ mutex_unlock(&mts_io_mutex);
+
+ return count;
+}
+
+static struct device_attribute dev_attr_led_sig2 = {
+ .attr = {
+ .name = "led-sig2",
+ .mode = 0644,
+ },
+ .show = show_led_sig2,
+ .store = store_led_sig2,
+};
+
+static struct device_attribute dev_attr_led_sdk_d = {
+ .attr = {
+ .name = "led-sdk-d",
+ .mode = 0644,
+ },
+ .show = show_led_sig2,
+ .store = store_led_sig2,
+};
+
+static ssize_t show_led_sig3(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int value;
+
+ mutex_lock(&mts_io_mutex);
+
+ value = !(cs0_bits & LED_SIG3_BIT);
+
+ mutex_unlock(&mts_io_mutex);
+
+ return sprintf(buf, "%d\n", value);
+}
+
+static ssize_t store_led_sig3(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int value;
+
+ if (sscanf(buf, "%i", &value) != 1) {
+ return -EINVAL;
+ }
+
+ mutex_lock(&mts_io_mutex);
+
+ if (value) {
+ cs0_bits &= ~LED_SIG3_BIT;
+ } else {
+ cs0_bits |= LED_SIG3_BIT;
+ }
+ serial_writeb(cs0_bits, GPIO_CS0);
+
+ mutex_unlock(&mts_io_mutex);
+
+ return count;
+}
+
+static struct device_attribute dev_attr_led_sig3 = {
+ .attr = {
+ .name = "led-sig3",
+ .mode = 0644,
+ },
+ .show = show_led_sig3,
+ .store = store_led_sig3,
+};
+
+static struct device_attribute dev_attr_led_sdk_e = {
+ .attr = {
+ .name = "led-sdk-e",
+ .mode = 0644,
+ },
+ .show = show_led_sig3,
+ .store = store_led_sig3,
+};
+
+static ssize_t show_led_cd(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int value;
+
+ mutex_lock(&mts_io_mutex);
+
+ value = !(cs0_bits & LED_CD_BIT);
+
+ mutex_unlock(&mts_io_mutex);
+
+ return sprintf(buf, "%d\n", value);
+}
+
+static ssize_t store_led_cd(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int value;
+
+ if (sscanf(buf, "%i", &value) != 1) {
+ return -EINVAL;
+ }
+
+ mutex_lock(&mts_io_mutex);
+
+ if (value) {
+ cs0_bits &= ~LED_CD_BIT;
+ } else {
+ cs0_bits |= LED_CD_BIT;
+ }
+ serial_writeb(cs0_bits, GPIO_CS0);
+
+ mutex_unlock(&mts_io_mutex);
+
+ return count;
+}
+
+static struct device_attribute dev_attr_led_cd = {
+ .attr = {
+ .name = "led-cd",
+ .mode = 0644,
+ },
+ .show = show_led_cd,
+ .store = store_led_cd,
+};
+
+static struct device_attribute dev_attr_led_sdk_b = {
+ .attr = {
+ .name = "led-sdk-b",
+ .mode = 0644,
+ },
+ .show = show_led_cd,
+ .store = store_led_cd,
+};
+
+#if LED_STATUS_CONTROLLABLE
+static ssize_t show_led_status(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%d\n", led_mode_status);
+}
+
+static ssize_t store_led_status(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int value;
+ int ret;
+
+ if (sscanf(buf, "%i", &value) != 1) {
+ return -EINVAL;
+ }
+
+ mutex_lock(&mts_io_mutex);
+
+ switch (value) {
+ case LED_OFF:
+ led_mode_status = LED_OFF;
+ ret = at91_set_gpio_value(GPIO_STATUS_LED, 1);
+
+ break;
+
+ case LED_ON:
+ led_mode_status = LED_ON;
+ ret = at91_set_gpio_value(GPIO_STATUS_LED, 0);
+
+ break;
+
+ case LED_FLASHING:
+ led_mode_status = LED_FLASHING;
+ ret = at91_set_gpio_value(GPIO_STATUS_LED, 0);
+
+ break;
+
+ default:
+ ret = -EINVAL;
+ }
+
+ mutex_unlock(&mts_io_mutex);
+
+ return count;
+}
+
+static struct device_attribute dev_attr_led_status = {
+ .attr = {
+ .name = "led-status",
+ .mode = 0644,
+ },
+ .show = show_led_status,
+ .store = store_led_status,
+};
+
+static struct device_attribute dev_attr_led_sdk_a = {
+ .attr = {
+ .name = "led-sdk-a",
+ .mode = 0644,
+ },
+ .show = show_led_status,
+ .store = store_led_status,
+};
+#endif
+
+#if LED_LS_CONTROLLABLE
+static ssize_t show_led_ls(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int value;
+
+ mutex_lock(&mts_io_mutex);
+
+ value = at91_get_gpio_value(GPIO_LS_LED);
+
+ mutex_unlock(&mts_io_mutex);
+
+ if (value < 0) {
+ return value;
+ }
+
+ return sprintf(buf, "%d\n", !value);
+}
+
+static ssize_t store_led_ls(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ int value;
+ int err;
+
+ if (sscanf(buf, "%i", &value) != 1) {
+ return -EINVAL;
+ }
+
+ mutex_lock(&mts_io_mutex);
+
+ err = at91_set_gpio_value(GPIO_LS_LED, !value);
+
+ mutex_unlock(&mts_io_mutex);
+
+ if (err) {
+ return err;
+ }
+
+ return count;
+}
+
+static struct device_attribute dev_attr_led_ls = {
+ .attr = {
+ .name = "led-ls",
+ .mode = 0644,
+ },
+ .show = show_led_ls,
+ .store = store_led_ls,
+};
+#endif
+
+static ssize_t show_reset(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int value;
+
+ mutex_lock(&mts_io_mutex);
+
+ value = !at91_get_gpio_value(GPIO_OPTRST);
+
+ mutex_unlock(&mts_io_mutex);
+
+ if (value < 0) {
+ return value;
+ }
+
+ return sprintf(buf, "%d\n", value);
+}
+
+static struct device_attribute dev_attr_reset = {
+ .attr = {
+ .name = "reset",
+ .mode = 0444,
+ },
+ .show = show_reset,
+};
+
+static ssize_t show_reset_monitor(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+
+ mutex_lock(&mts_io_mutex);
+
+ ret = sprintf(buf, "%d %d %d\n", reset_pid, reset_short_signal, reset_long_signal);
+
+ mutex_unlock(&mts_io_mutex);
+
+ return ret;
+}
+
+static ssize_t store_reset_monitor(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ pid_t pid;
+ int short_signal;
+ int long_signal;
+
+ if (sscanf(buf, "%i %i %i", &pid, &short_signal, &long_signal) != 3) {
+ return -EINVAL;
+ }
+
+ mutex_lock(&mts_io_mutex);
+
+ reset_pid = pid;
+ reset_short_signal = short_signal;
+ reset_long_signal = long_signal;
+
+ mutex_unlock(&mts_io_mutex);
+
+ return count;
+}
+
+static struct device_attribute dev_attr_reset_monitor = {
+ .attr = {
+ .name = "reset-monitor",
+ .mode = 0644,
+ },
+ .show = show_reset_monitor,
+ .store = store_reset_monitor,
+};
+
+static ssize_t show_board_temperature(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ int ret;
+
+ mutex_lock(&mts_io_mutex);
+
+ ret = sprintf(buf, "%d\n", board_temperature());
+
+ mutex_unlock(&mts_io_mutex);
+
+ return ret;
+}
+
+static struct device_attribute dev_attr_board_temperature = {
+ .attr = {
+ .name = "board-temperature",
+ .mode = 0444,
+ },
+ .show = show_board_temperature,
+};
+
+static struct attribute *platform_attributes[] = {
+ &dev_attr_radio_reset.attr,
+ &dev_attr_eth0_enabled.attr,
+ &dev_attr_extserial_dcd.attr,
+ &dev_attr_extserial_ri.attr,
+ &dev_attr_led_sig1.attr,
+ &dev_attr_led_sdk_c.attr,
+ &dev_attr_led_sig2.attr,
+ &dev_attr_led_sdk_d.attr,
+ &dev_attr_led_sig3.attr,
+ &dev_attr_led_sdk_e.attr,
+ &dev_attr_led_cd.attr,
+ &dev_attr_led_sdk_b.attr,
+#if LED_STATUS_CONTROLLABLE
+ &dev_attr_led_status.attr,
+ &dev_attr_led_sdk_a.attr,
+#endif
+#if LED_LS_CONTROLLABLE
+ &dev_attr_led_ls.attr,
+#endif
+ &dev_attr_reset.attr,
+ &dev_attr_reset_monitor.attr,
+ &dev_attr_board_temperature.attr,
+ NULL,
+};
+
+static struct attribute_group platform_attribute_group = {
+ .attrs = platform_attributes
+};
+
+static struct platform_device *mts_io_platform_device;
+
+enum {
+ DIR_INPUT,
+ DIR_OUTPUT,
+};
+
+struct gpio_pin_init {
+ char name[32];
+ unsigned long pin;
+ int direction;
+ int output_value;
+ int use_pullup;
+ int board_rev_added;
+};
+
+static struct gpio_pin_init init_pins[] = {
+ /*
+ * GPIO_{VER0,VER1} need to be first in the list.
+ */
+ {
+ .name = "GPIO_VER0",
+ .pin = GPIO_VER0,
+ .direction = DIR_INPUT,
+ .output_value = 0,
+ .use_pullup = 0,
+ .board_rev_added = BOARD_REVA,
+ },
+ {
+ .name = "GPIO_VER1",
+ .pin = GPIO_VER1,
+ .direction = DIR_INPUT,
+ .output_value = 0,
+ .use_pullup = 0,
+ .board_rev_added = BOARD_REVA,
+ },
+ {
+ .name = "GPIO_CS0",
+ .pin = GPIO_CS0,
+ .direction = DIR_OUTPUT,
+ .output_value = 1,
+ .use_pullup = 1,
+ .board_rev_added = BOARD_REVA,
+ },
+ {
+ .name = "GPIO_CS1",
+ .pin = GPIO_CS1,
+ .direction = DIR_OUTPUT,
+ .output_value = 1,
+ .use_pullup = 1,
+ .board_rev_added = BOARD_REVA,
+ },
+ {
+ .name = "GPIO_CS2",
+ .pin = GPIO_CS2,
+ .direction = DIR_OUTPUT,
+ .output_value = 1,
+ .use_pullup = 1,
+ .board_rev_added = BOARD_REVA,
+ },
+ {
+ .name = "GPIO_CS3",
+ .pin = GPIO_CS3,
+ .direction = DIR_OUTPUT,
+ .output_value = 1,
+ .use_pullup = 1,
+ .board_rev_added = BOARD_REVC,
+ },
+ {
+ .name = "GPIO_ENIO",
+ .pin = GPIO_ENIO,
+ .direction = DIR_OUTPUT,
+ .output_value = 1,
+ .use_pullup = 0,
+ .board_rev_added = BOARD_REVA,
+ },
+ {
+ .name = "GPIO_ETH0_ENABLED",
+ .pin = AT91_PIN_PB31,
+ .direction = DIR_OUTPUT,
+ .output_value = 1,
+ .use_pullup = 0,
+ .board_rev_added = BOARD_REVA,
+ },
+ {
+ .name = "GPIO_RADIO_RESET",
+ .pin = GPIO_RADIO_RESET,
+ .direction = DIR_OUTPUT,
+ .output_value = 1,
+ .use_pullup = 0,
+ .board_rev_added = BOARD_REVA,
+ },
+ {
+ .name = "GPIO_OPTRST",
+ .pin = GPIO_OPTRST,
+ .direction = DIR_INPUT,
+ .output_value = 0,
+ .use_pullup = 0,
+ .board_rev_added = BOARD_REVA,
+ },
+#if LED_LS_CONTROLLABLE
+ {
+ .name = "GPIO_LS_LED",
+ .pin = GPIO_LS_LED,
+ .direction = DIR_OUTPUT,
+ .output_value = 1,
+ .use_pullup = 0,
+ .board_rev_added = BOARD_REVA,
+ },
+#endif
+ {
+ .name = "GPIO_SERCLK",
+ .pin = GPIO_SERCLK,
+ .direction = DIR_OUTPUT,
+ .output_value = 0,
+ .use_pullup = 0,
+ .board_rev_added = BOARD_REVA,
+ },
+ {
+ .name = "GPIO_SERDOUT",
+ .pin = GPIO_SERDOUT,
+ .direction = DIR_OUTPUT,
+ .output_value = 0,
+ .use_pullup = 1,
+ .board_rev_added = BOARD_REVA,
+ },
+ {
+ .name = "GPIO_SERDIN",
+ .pin = GPIO_SERDIN,
+ .direction = DIR_INPUT,
+ .output_value = 0,
+ .use_pullup = 1,
+ .board_rev_added = BOARD_REVA,
+ },
+#if LED_STATUS_CONTROLLABLE
+ {
+ .name = "GPIO_STATUS_LED",
+ .pin = GPIO_STATUS_LED,
+ .direction = DIR_OUTPUT,
+ .output_value = 1,
+ .use_pullup = 0,
+ .board_rev_added = BOARD_REVA,
+ },
+#endif
+ {
+ .name = "GPIO_RSERSRC",
+ .pin = GPIO_RSERSRC,
+ .direction = DIR_OUTPUT,
+ .output_value = 1,
+ .use_pullup = 0,
+ .board_rev_added = BOARD_REVB,
+ },
+ {
+ .name = "GPIO_DBSERON",
+ .pin = GPIO_DBSERON,
+ .direction = DIR_OUTPUT,
+ .output_value = 1,
+ .use_pullup = 0,
+ .board_rev_added = BOARD_REVB,
+ },
+ {
+ .name = "GPIO_DTR1",
+ .pin = GPIO_DTR1,
+ .direction = DIR_INPUT,
+ .output_value = 0,
+ .use_pullup = 0,
+ .board_rev_added = BOARD_REVB,
+ },
+ {
+ .name = "GPIO_RXD1MON",
+ .pin = GPIO_RXD1MON,
+ .direction = DIR_INPUT,
+ .output_value = 0,
+ .use_pullup = 0,
+ .board_rev_added = BOARD_REVB,
+ },
+ {
+ .name = "GPIO_EXTIN0",
+ .pin = GPIO_EXTIN0,
+ .direction = DIR_INPUT,
+ .output_value = 0,
+ .use_pullup = 0,
+ .board_rev_added = BOARD_REVB,
+ },
+ {
+ .name = "GPIO_EXTIN1",
+ .pin = GPIO_EXTIN1,
+ .direction = DIR_INPUT,
+ .output_value = 0,
+ .use_pullup = 0,
+ .board_rev_added = BOARD_REVB,
+ },
+ {
+ .name = "GPIO_EXTIN2",
+ .pin = GPIO_EXTIN2,
+ .direction = DIR_INPUT,
+ .output_value = 0,
+ .use_pullup = 0,
+ .board_rev_added = BOARD_REVB,
+ },
+#if 0
+ {
+ .name = "GPIO_EXTIN3",
+ .pin = GPIO_EXTIN3,
+ .direction = DIR_INPUT,
+ .output_value = 0,
+ .use_pullup = 0,
+ .board_rev_added = BOARD_REVC,
+ },
+ {
+ .name = "GPIO_EXTIN4",
+ .pin = GPIO_EXTIN4,
+ .direction = DIR_INPUT,
+ .output_value = 0,
+ .use_pullup = 0,
+ .board_rev_added = BOARD_REVC,
+ },
+ {
+ .name = "GPIO_EXTIN5",
+ .pin = GPIO_EXTIN5,
+ .direction = DIR_INPUT,
+ .output_value = 0,
+ .use_pullup = 0,
+ .board_rev_added = BOARD_REVC,
+ },
+ {
+ .name = "GPIO_GPS_NINT2",
+ .pin = GPIO_GPS_NINT2,
+ .direction = DIR_INPUT,
+ .output_value = 0,
+ .use_pullup = 0,
+ .board_rev_added = BOARD_REVC,
+ },
+#endif
+};
+
+static int __init mts_io_init(void)
+{
+ int i;
+ int ret;
+
+ info(DRIVER_NAME ": init");
+
+ mts_io_platform_device = platform_device_alloc(PLATFORM_NAME, -1);
+ if (!mts_io_platform_device) {
+ ret = -ENOMEM;
+ goto error_platform_device_alloc;
+ }
+
+ ret = platform_device_add(mts_io_platform_device);
+ if (ret) {
+ goto error_platform_device_add;
+ }
+
+ ret = sysfs_create_group(&mts_io_platform_device->dev.kobj,
+ &platform_attribute_group);
+ if (ret) {
+ goto error_sysfs_create_group;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(init_pins); i++) {
+ gpio_request(init_pins[i].pin, init_pins[i].name);
+
+ if (board_rev >= init_pins[i].board_rev_added) {
+ if (init_pins[i].direction == DIR_OUTPUT) {
+ at91_set_gpio_output(init_pins[i].pin, init_pins[i].output_value);
+ } else {
+ at91_set_gpio_input(init_pins[i].pin, init_pins[i].use_pullup);
+ }
+ }
+
+ if (i == 1) {
+ board_rev = (at91_get_gpio_value(GPIO_VER1) << 1) | at91_get_gpio_value(GPIO_VER0);
+ board_rev ^= 0x03;
+ info(DRIVER_NAME ": board rev: %d", board_rev);
+ }
+ }
+
+ serial_writeb(cs0_bits, GPIO_CS0);
+ serial_writeb(0xFF, GPIO_CS1);
+
+ /*
+ * enable serial device data output bus
+ */
+ at91_set_gpio_value(GPIO_ENIO, 0);
+
+ blink_callback(NULL);
+
+ return 0;
+
+error_sysfs_create_group:
+ platform_device_del(mts_io_platform_device);
+error_platform_device_add:
+ platform_device_put(mts_io_platform_device);
+error_platform_device_alloc:
+ error(DRIVER_NAME " init failed: %d", ret);
+
+ return ret;
+}
+
+static void __exit mts_io_exit(void)
+{
+ int i;
+
+ cancel_delayed_work_sync(&blink_work);
+
+ if (board_rev >= init_pins[i].board_rev_added) {
+ for (i = 0; i < ARRAY_SIZE(init_pins); i++) {
+ at91_set_gpio_input(init_pins[i].pin, init_pins[i].use_pullup);
+ }
+ }
+
+ sysfs_remove_group(&mts_io_platform_device->dev.kobj,
+ &platform_attribute_group);
+ platform_device_unregister(mts_io_platform_device);
+
+ info(DRIVER_NAME ": exiting");
+}
+
+module_init(mts_io_init);
+module_exit(mts_io_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_LICENSE("GPL");
+
+
+
diff --git a/io-module/mts_io.h b/io-module/mts_io.h
new file mode 100644
index 0000000..6cd1189
--- /dev/null
+++ b/io-module/mts_io.h
@@ -0,0 +1,7 @@
+
+#ifndef __MTS_IO_H
+#define __MTS_IO_H
+
+
+#endif /* ~__MTS_IO_H */
+
diff --git a/io-tool/mts-io-sysfs b/io-tool/mts-io-sysfs
new file mode 100755
index 0000000..b32b005
--- /dev/null
+++ b/io-tool/mts-io-sysfs
@@ -0,0 +1,241 @@
+#!/usr/bin/env bash
+#
+# vim: set sw=2 ts=2 expandtab:
+#
+# Copyright (C) 2010 by Multi-Tech Systems
+#
+# Author: James Maki <jmaki@multitech.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+PATH=${PATH}:.
+
+source /usr/lib/mts-io-sysfs/mts-io-sysfs-inc.sh
+
+trap "exit_handler" EXIT
+exit_handler() {
+ local exit_code=$?
+ if [ ${exit_code} -ne 0 ]; then
+ log_error "exiting with ${exit_code}"
+ fi
+}
+
+reset_short_handler() {
+ echo "reset short signal received"
+}
+reset_long_handler() {
+ echo "reset long signal received"
+}
+RESET_SHORT_CMD="reset_short_handler"
+RESET_LONG_CMD="reset_long_handler"
+RESET_SHORT_SIGNAL=$(kill -l SIGUSR1)
+RESET_LONG_SIGNAL=$(kill -l SIGUSR2)
+
+PROGRAM=$(basename $0)
+VERSION="0.0.2"
+
+print_version() {
+ printf "${PROGRAM} ${VERSION}\n"
+ printf "Copyright (C) 2010 by Multi-Tech Systems\n"
+cat <<EOF
+This program is free software; you may redistribute it under the terms of
+the GNU General Public License version 2 or (at your option) any later version.
+This program has absolutely no warranty.
+EOF
+}
+
+usage() {
+ local out=1
+ if [ $# -eq 1 ]; then
+ out=${1}
+ fi
+
+ printf "Usage: ${PROGRAM} [ OPTIONS ] OBJECT [--] [ ARGUMENTS ]\n" >&${out}
+ printf "where OBJECT := {\n" >&${out}
+ printf " show SHOW-NAME |\n" >&${out}
+ printf " store STORE-NAME { value } |\n" >&${out}
+ printf " reset-monitor-trap [short-cmd cmd signame] [long-cmd cmd signame]\n" >&${out}
+ printf " }\n" >&${out}
+ printf "\n" >&${out}
+ printf " SHOW-NAME := {\n" >&${out}
+ printf " board-temperature |\n" >&${out}
+ printf " eth0-enabled |\n" >&${out}
+ printf " extserial-dcd |\n" >&${out}
+ printf " extserial-ri |\n" >&${out}
+ printf " led-cd |\n" >&${out}
+ printf " led-sdk-b |\n" >&${out}
+ printf " led-sig1 |\n" >&${out}
+ printf " led-sdk-c |\n" >&${out}
+ printf " led-sig2 |\n" >&${out}
+ printf " led-sdk-d |\n" >&${out}
+ printf " led-sig3 |\n" >&${out}
+ printf " led-sdk-e |\n" >&${out}
+if [ "${MTS_IO_CONTROLS_STATUS_LED}" = "true" ]; then
+ printf " led-status |\n" >&${out}
+ printf " led-sdk-a |\n" >&${out}
+fi
+if [ "${MTS_IO_CONTROLS_LS_LED}" = "true" ]; then
+ printf " led-ls |\n" >&${out}
+fi
+ printf " radio-reset |\n" >&${out}
+ printf " reset |\n" >&${out}
+ printf " reset-monitor\n" >&${out}
+ printf " }\n" >&${out}
+ printf "\n" >&${out}
+ printf " STORE-NAME := {\n" >&${out}
+ printf " eth0-enabled BOOLEAN |\n" >&${out}
+ printf " extserial-dcd BOOLEAN |\n" >&${out}
+ printf " extserial-ri BOOLEAN |\n" >&${out}
+ printf " led-cd BOOLEAN |\n" >&${out}
+ printf " led-sdk-b BOOLEAN |\n" >&${out}
+ printf " led-sig1 BOOLEAN |\n" >&${out}
+ printf " led-sdk-c BOOLEAN |\n" >&${out}
+ printf " led-sig2 BOOLEAN |\n" >&${out}
+ printf " led-sdk-d BOOLEAN |\n" >&${out}
+ printf " led-sig3 BOOLEAN |\n" >&${out}
+ printf " led-sdk-e BOOLEAN |\n" >&${out}
+if [ "${MTS_IO_CONTROLS_STATUS_LED}" = "true" ]; then
+ printf " led-status LED-VALUE |\n" >&${out}
+ printf " led-sdk-a LED-VALUE |\n" >&${out}
+fi
+if [ "${MTS_IO_CONTROLS_LS_LED}" = "true" ]; then
+ printf " led-ls BOOLEAN |\n" >&${out}
+fi
+ printf " radio-reset { 0 } |\n" >&${out}
+ printf " reset-monitor { pid short-signal long-signal }\n" >&${out}
+ printf " }\n" >&${out}
+ printf "\n" >&${out}
+ printf " OPTIONS := {\n" >&${out}
+ printf " --verbose\n" >&${out}
+ printf " }\n" >&${out}
+ printf "\n" >&${out}
+ printf " BOOLEAN := { OFF | ON }\n" >&${out}
+ printf " LED-VALUE := { OFF | ON | LED-FLASHING }\n" >&${out}
+ printf " OFF := 0\n" >&${out}
+ printf " ON := 1\n" >&${out}
+ printf " LED-FLASHING := 2\n" >&${out}
+ printf "\n" >&${out}
+}
+
+ARGS=$(getopt -o "" --long verbose,version,help -n $0 -- "$@")
+if [ $? != 0 ]; then
+ usage 2
+ exit 1
+fi
+eval set -- "${ARGS}"
+
+while true; do
+ case "$1" in
+ --version)
+ print_version
+ exit 0
+ shift
+ ;;
+
+ --help)
+ usage 1
+ exit 0
+ shift
+ ;;
+
+ --verbose)
+ VERBOSE=true
+ shift
+ ;;
+ --)
+ shift
+ break
+ ;;
+ *)
+ usage 2
+ exit 1
+ ;;
+ esac
+done
+
+if [ $# -lt 1 ]; then
+ usage 2
+ exit 1
+fi
+
+cmd=${1}
+shift
+
+case "${cmd}" in
+show)
+ show "$@"
+ ;;
+store)
+ store "$@"
+ ;;
+show-trigger)
+ show_trigger "$@"
+ ;;
+store-trigger)
+ store_trigger "$@"
+ ;;
+reset-monitor-trap)
+ while true; do
+ if [ $# -eq 0 ]; then
+ break
+ fi
+
+ if [ $# -ne 3 ]; then
+ usage 2
+ exit 1
+ fi
+
+ case "${1}" in
+ short-cmd)
+ RESET_SHORT_CMD=${2}
+ RESET_SHORT_SIGNAL=$(kill -l ${3})
+ if [ $? -ne 0 ]; then
+ exit 1
+ fi
+ ;;
+ long-cmd)
+ RESET_LONG_CMD=${2}
+ RESET_LONG_SIGNAL=$(kill -l ${3})
+ if [ $? -ne 0 ]; then
+ exit 1
+ fi
+ ;;
+ *)
+ usage 2
+ exit 1
+ ;;
+ esac
+
+ shift; shift; shift
+ done
+
+ trap "${RESET_SHORT_CMD}" ${RESET_SHORT_SIGNAL}
+ trap "${RESET_LONG_CMD}" ${RESET_LONG_SIGNAL}
+
+ store reset-monitor "$$ ${RESET_SHORT_SIGNAL} ${RESET_LONG_SIGNAL}"
+
+ while true; do
+ sleep 1
+ done
+ ;;
+*)
+ usage 2
+ exit 1
+ ;;
+esac
+
+exit 0
+
diff --git a/io-tool/mts-io-sysfs-inc.sh b/io-tool/mts-io-sysfs-inc.sh
new file mode 100644
index 0000000..f3fde5f
--- /dev/null
+++ b/io-tool/mts-io-sysfs-inc.sh
@@ -0,0 +1,92 @@
+#!/usr/bin/env bash
+#
+# vim: set sw=2 ts=2 expandtab:
+#
+# Copyright (C) 2010 by Multi-Tech Systems
+#
+# Author: James Maki <jmaki@multitech.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+#
+
+VERBOSE=false
+
+PLATFORM_NAME=sparkcell
+SYSFS_PLATFORM_DIR=/sys/devices/platform/${PLATFORM_NAME}
+
+MTS_IO_CONTROLS_STATUS_LED=true
+MTS_IO_CONTROLS_LS_LED=false
+
+LEDS_GPIO_DIR=/sys/devices/platform/leds-gpio/leds
+
+log_info() {
+ if [ "${VERBOSE}" = "true" ]; then
+ echo "info:" "$@"
+ fi
+}
+
+log_error() {
+ echo "error:" "$@" >&2
+}
+
+store() {
+ if [ $# -ne 2 ]; then
+ log_error "store name value"
+ exit 99
+ fi
+
+ local name=${1}
+ local value=${2}
+
+ log_info "setting ${name} to '${value}'"
+ echo -n "${value}" > ${SYSFS_PLATFORM_DIR}/${name}
+}
+
+show() {
+ if [ $# -ne 1 ]; then
+ log_error "show name"
+ exit 99
+ fi
+
+ local name=${1}
+
+ cat ${SYSFS_PLATFORM_DIR}/${name}
+}
+
+store_trigger() {
+ if [ $# -ne 2 ]; then
+ log_error "store_trigger name value"
+ exit 99
+ fi
+
+ local name=${1}
+ local value=${2}
+
+ log_info "setting ${name} to '${value}'"
+ echo -n "${value}" > cat ${LEDS_GPIO_DIR}/${name}/trigger
+}
+
+show_trigger() {
+ if [ $# -ne 1 ]; then
+ log_error "show_trigger name"
+ exit 99
+ fi
+
+ local name=${1}
+
+ cat ${LEDS_GPIO_DIR}/${name}/trigger
+}
+
+
diff --git a/io-tool/sysfs-tests b/io-tool/sysfs-tests
new file mode 100755
index 0000000..cb65c57
--- /dev/null
+++ b/io-tool/sysfs-tests
@@ -0,0 +1,181 @@
+#!/usr/bin/env bash
+
+PATH=${PATH}:.
+
+source /usr/lib/mts-io-sysfs/mts-io-sysfs-inc.sh
+
+yesno() {
+ if [ $# -ne 1 ]; then
+ echo "yesno question"
+ exit 99
+ fi
+
+ local question=${1}
+
+ while :
+ do
+ echo -n "${question}? [y/n] "
+ read line
+ local line=$(echo ${line} | tr A-Z a-z)
+ case "${line}" in
+ y)
+ return 0
+ ;;
+ n)
+ return 1
+ ;;
+ *)
+ ;;
+ esac
+ done
+}
+
+store_assert() {
+ if [ $# -ne 2 ]; then
+ log_error "store_assert name value"
+ exit 99
+ fi
+
+ local name=${1}
+ local value=${2}
+
+ local old_value="$(cat ${SYSFS_PLATFORM_DIR}/${name})"
+ store ${name} "${value}"
+ local new_value="$(cat ${SYSFS_PLATFORM_DIR}/${name})"
+
+ if [ "${new_value}" != "${value}" ]; then
+ log_error "${name}: '${new_value}' != '${value}'"
+ exit 1
+ fi
+}
+
+show_assert() {
+ if [ $# -ne 2 ]; then
+ log_error "show_assert name value"
+ exit 99
+ fi
+
+ local name=${1}
+ local expected_value=${2}
+
+ log_info "checking if ${name} is '${expected_value}'"
+
+ local actual_value="$(show ${name})"
+
+ if [ "${expected_value}" != "${actual_value}" ]; then
+ log_error "${name}: '${expected_value}' != '${actual_value}'"
+ exit 1
+ fi
+}
+
+show_assert_in_set() {
+ if [ $# -lt 2 ]; then
+ log_error "show_assert_in_set name value0 [value1 ...]"
+ exit 99
+ fi
+
+ local name=${1}
+ shift
+
+ log_info "checking if ${name} is in set [$*]"
+
+ local actual_value="$(show ${name})"
+
+ for value in "$@"; do
+ if [ "${value}" = "${actual_value}" ]; then
+ log_info "${name} is '${value}'"
+ return
+ fi
+ done
+
+ exit 1
+}
+
+VERBOSE=true
+
+echo none > /sys/devices/platform/leds-gpio/leds/status/trigger
+
+modprobe -r mts-io
+modprobe mts-io
+
+sleep 2
+
+show_assert radio-reset 1
+log_info "resetting radio..."
+store radio-reset 0
+sleep 2
+show_assert radio-reset 1
+log_info "radio reset"
+
+show_assert eth0-enabled 1
+store_assert eth0-enabled 0
+sleep 2
+if ! yesno "Are the ethernet LEDs off"; then
+ exit 1
+fi
+store_assert eth0-enabled 1
+sleep 2
+if ! yesno "Are the ethernet LEDs on"; then
+ exit 1
+fi
+
+show_assert extserial-dcd 0
+store_assert extserial-dcd 1
+store_assert extserial-dcd 0
+
+show_assert extserial-ri 0
+store_assert extserial-ri 1
+store_assert extserial-ri 0
+
+show_assert led-sig1 0
+store_assert led-sig1 1
+store_assert led-sig1 0
+
+show_assert led-sdk-c 0
+store_assert led-sdk-c 1
+store_assert led-sdk-c 0
+
+show_assert led-sig2 0
+store_assert led-sig2 1
+store_assert led-sig2 0
+
+show_assert led-sdk-d 0
+store_assert led-sdk-d 1
+store_assert led-sdk-d 0
+
+show_assert led-sig3 0
+store_assert led-sig3 1
+store_assert led-sig3 0
+
+show_assert led-sdk-e 0
+store_assert led-sdk-e 1
+store_assert led-sdk-e 0
+
+show_assert led-cd 0
+store_assert led-cd 1
+store_assert led-cd 0
+
+show_assert led-sdk-b 0
+store_assert led-sdk-b 1
+store_assert led-sdk-b 0
+
+show_assert led-status 0
+store_assert led-status 1
+store_assert led-status 0
+
+show_assert led-sdk-a 0
+store_assert led-sdk-a 1
+store_assert led-sdk-a 0
+
+show_assert reset 0
+store reset 1
+show_assert reset 0
+
+show_assert_in_set board-temperature {30..40}
+store board-temperature 1000
+show_assert_in_set board-temperature {30..40}
+
+show_assert reset-monitor "-1 10 12"
+
+exit 0
+