summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/kernel/linux/Makefile4
-rw-r--r--app/kernel/linux/sirf_iob_cdev.c125
-rw-r--r--app/kernel/linux/sirf_iob_pal_linux_km.c424
-rw-r--r--app/kernel/linux/sirf_iob_pal_linux_km.h103
-rw-r--r--app/kernel/linux/sirf_iob_spi.c130
-rw-r--r--app/kernel/linux/sirf_iob_uart.c146
-rw-r--r--app/lib/inc/sirf_iob_user.h60
-rw-r--r--include/sirf_iob.h155
-rw-r--r--include/sirf_iob_buf.h57
-rw-r--r--include/sirf_iob_config.h31
-rw-r--r--include/sirf_iob_debug.h57
-rw-r--r--include/sirf_iob_pal.h84
-rw-r--r--readme/How to build.txt26
-rw-r--r--source/sirf_iob_config.c103
-rw-r--r--source/sirf_iob_core.c1137
-rw-r--r--source/sirf_iob_debug.c95
16 files changed, 2737 insertions, 0 deletions
diff --git a/app/kernel/linux/Makefile b/app/kernel/linux/Makefile
new file mode 100644
index 0000000..594ee3e
--- /dev/null
+++ b/app/kernel/linux/Makefile
@@ -0,0 +1,4 @@
+
+obj-y += sirf_iob_m.o
+
+sirf_iob_m-y := sirf_iob_cdev.o sirf_iob_pal_linux_km.o sirf_iob_spi.o sirf_iob_uart.o sirf_iob_core.o
diff --git a/app/kernel/linux/sirf_iob_cdev.c b/app/kernel/linux/sirf_iob_cdev.c
new file mode 100644
index 0000000..d003cf7
--- /dev/null
+++ b/app/kernel/linux/sirf_iob_cdev.c
@@ -0,0 +1,125 @@
+/*
+ Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, and the entire permission notice in its entirety,
+ including the disclaimer of warranties.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+ ALTERNATIVELY, this product may be distributed under the terms of
+ the GNU General Public License, version 2, in which case the provisions
+ of the GPL version 2 are required INSTEAD OF the BSD license.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE.
+*/
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/spi/spi.h>
+#include <linux/fs.h>
+#include "csr_iob.h"
+#include "sirf_iob_pal.h"
+#include "sirf_iob_pal_linux_km.h"
+
+
+static sirf_iob_t *_iob = 0;
+
+
+static ssize_t sirf_iob_fops_read(struct file *file, char __user *buf, size_t count, loff_t * ppos)
+{
+ sirf_iob_t *iob = (sirf_iob_t *)file->private_data;
+
+ return sirf_iob_pal_user_read(iob, buf, count);
+}
+
+static ssize_t sirf_iob_fops_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
+{
+ sirf_iob_t *iob = (sirf_iob_t *)file->private_data;
+
+ return sirf_iob_pal_user_write(iob, buf, count);
+}
+
+static int sirf_iob_fops_open(struct inode *inode, struct file *file)
+{
+ sirf_iob_t *iob = _iob;
+
+ file->private_data = iob;
+
+ sirf_iob_open(iob);
+
+ return 0;
+}
+
+static int sirf_iob_fops_release(struct inode *inode, struct file *file)
+{
+ sirf_iob_t *iob = (sirf_iob_t *)file->private_data;
+
+ sirf_iob_close(iob);
+
+ return 0;
+}
+
+const struct file_operations sirf_iob_fops =
+{
+ .owner = THIS_MODULE,
+ .read = sirf_iob_fops_read,
+ .write = sirf_iob_fops_write,
+ .open = sirf_iob_fops_open,
+ .release = sirf_iob_fops_release,
+};
+
+void sirf_iob_drv_probe(void)
+{
+ register_chrdev(0, "sirf_iob", &sirf_iob_fops);
+}
+EXPORT_SYMBOL(sirf_iob_drv_probe);
+
+void sirf_iob_drv_remove(void)
+{
+ unregister_chrdev(0, "sirf_iob");
+}
+EXPORT_SYMBOL(sirf_iob_drv_remove);
+
+static int __init sirf_iob_drv_init(void)
+{
+ if (sirf_iob_uart_drv_init() < 0)
+ return -EFAULT;
+
+ if (sirf_iob_spi_drv_init() < 0)
+ return -EFAULT;
+
+ return 0;
+}
+
+static void __exit sirf_iob_drv_exit(void)
+{
+ sirf_iob_uart_drv_exit();
+
+ sirf_iob_spi_drv_exit();
+}
+
+arch_initcall(sirf_iob_drv_init);
+module_exit(sirf_iob_drv_exit);
+
+MODULE_DESCRIPTION("SIRF IOB driver");
+MODULE_LICENSE("GPL");
diff --git a/app/kernel/linux/sirf_iob_pal_linux_km.c b/app/kernel/linux/sirf_iob_pal_linux_km.c
new file mode 100644
index 0000000..b845d37
--- /dev/null
+++ b/app/kernel/linux/sirf_iob_pal_linux_km.c
@@ -0,0 +1,424 @@
+/*
+ Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, and the entire permission notice in its entirety,
+ including the disclaimer of warranties.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+ ALTERNATIVELY, this product may be distributed under the terms of
+ the GNU General Public License, version 2, in which case the provisions
+ of the GPL version 2 are required INSTEAD OF the BSD license.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE.
+*/
+
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/gpio.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/kfifo.h>
+#include <linux/delay.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+
+#include "sirf_iob.h"
+#include "sirf_iob_pal.h"
+#include "sirf_iob_buf.h"
+#include "sirf_iob_debug.h"
+#include "sirf_iob_pal_linux_km.h"
+
+#define MAX_TIMER_NUM 2
+
+
+//static sirf_iob_port_t *_port;
+
+
+
+
+static irqreturn_t sirf_iob_irq_handler(int irq, void *dev_id)
+{
+ sirf_iob_port_t *port = dev_id;
+ unsigned int ionum;
+ int gpio = irq_to_gpio(irq);
+
+ do {
+ if (gpio == port->ctl_ports.gpio_1pps)
+ ionum = SIRF_IOB_GPIO_DIN_DRI;
+ else if (gpio == port->ctl_ports.gpio_wakeup)
+ ionum = SIRF_IOB_GPIO_DIN_WAKEUP;
+ else
+ break;
+
+ sirf_iob_gpio_input_isr(&port->iob, ionum, gpio_get_value(gpio));
+ } while (0);
+
+ return IRQ_HANDLED;
+}
+
+static void sirf_iob_wq_func(struct work_struct *work)
+{
+ struct sirf_iob_work *iob_work = (struct sirf_iob_work *)work;
+ sirf_iob_port_t *port = iob_work->port;
+
+ port->handler(port->arg);
+}
+
+void sirf_iob_pal_send_event(sirf_iob_t *iob, unsigned int event, void *parm, int len)
+{
+ sirf_iob_port_t *port = (sirf_iob_port_t *)iob;
+ sirf_iob_event_t evt;
+
+ ENTER();
+
+ evt.evt = event;
+ evt.len = len;
+ if (len > 0)
+ memcpy(evt.arg, parm, len);
+
+ kfifo_in_locked(&port->evt_fifo, &evt, 1, &port->fifo_lock);
+
+ queue_work(port->wqueue, &port->work.work);
+
+ EXIT();
+}
+
+int sirf_iob_pal_wait_event(sirf_iob_t *iob, unsigned int *event, unsigned char *evtobj, int objLen, int block)
+{
+ sirf_iob_port_t *port = (sirf_iob_port_t *)iob;
+ sirf_iob_event_t evt;
+ int ret = -1;
+
+ ENTER();
+
+ do {
+ ret = kfifo_out_locked(&port->evt_fifo, &evt, sizeof(evt), &port->fifo_lock);
+
+ if (ret > 0) {
+ *event = evt.evt;
+ if (evt.len > 0)
+ memcpy(evtobj, evt.arg, evt.len);
+ ret = evt.len;
+ } else if (!ret) {
+ *event = SIRF_IOB_EVENT_TIMEOUT;
+ break;
+ } else if (ret < 0) {
+ *event = SIRF_IOB_EVENT_ERR;
+ break;
+ }
+ } while (0);
+
+ EXIT();
+ return ret;
+}
+
+
+void sirf_iob_pal_start_task(sirf_iob_t *iob, sirf_iob_task_f handler, void *arg)
+{
+ sirf_iob_port_t *port = (sirf_iob_port_t *)iob;
+
+ port->wqueue = create_singlethread_workqueue("gps_wqueue");
+ port->handler = handler;
+ port->arg = arg;
+
+ INIT_WORK((struct work_struct *)&port->work, sirf_iob_wq_func);
+
+ sirf_iob_pal_lock(iob);
+ iob->task_alive = 1;
+ sirf_iob_pal_unlock(iob);
+}
+
+void sirf_iob_pal_lock(struct sirf_iob *iob)
+{
+ sirf_iob_port_t *port = (sirf_iob_port_t *)iob;
+
+ spin_lock(&port->lock);
+}
+
+void sirf_iob_pal_unlock(struct sirf_iob *iob)
+{
+ sirf_iob_port_t *port = (sirf_iob_port_t *)iob;
+
+ spin_unlock(&port->lock);
+}
+
+int sirf_iob_pal_get_from_host(struct sirf_iob *iob, unsigned char *buf, int len)
+{
+ sirf_iob_port_t *port = (sirf_iob_port_t *)iob;
+
+ return kfifo_out_locked(&port->tx_fifo, buf, len, &port->wlock);
+}
+
+int sirf_iob_pal_put_to_host(struct sirf_iob *iob, unsigned char *buf, int len)
+{
+ sirf_iob_port_t *port = (sirf_iob_port_t *)iob;
+
+ return kfifo_in_locked(&port->rx_fifo, buf, len, &port->rlock);
+}
+
+
+int sirf_iob_pal_get_gpio_val(struct sirf_iob *iob, unsigned int ionum)
+{
+ sirf_iob_port_t *port = (sirf_iob_port_t *)iob;
+
+ switch (ionum) {
+ case SIRF_IOB_GPIO_DOUT_POWER:
+ return gpio_get_value(port->ctl_ports.gpio_power);
+ case SIRF_IOB_GPIO_DOUT_ONOFF:
+ return gpio_get_value(port->ctl_ports.gpio_on_off);
+ case SIRF_IOB_GPIO_DOUT_RESET:
+ return gpio_get_value(port->ctl_ports.gpio_reset);
+ case SIRF_IOB_GPIO_DIN_DRI:
+ return gpio_get_value(port->ctl_ports.gpio_dri);
+ case SIRF_IOB_GPIO_DIN_WAKEUP:
+ return gpio_get_value(port->ctl_ports.gpio_wakeup);
+ case SIRF_IOB_GPIO_DIN_1PPS:
+ return gpio_get_value(port->ctl_ports.gpio_1pps);
+ default:
+ return -1;
+ }
+}
+
+void sirf_iob_pal_ctrl_onoff(struct sirf_iob *iob, int on)
+{
+ sirf_iob_port_t *port = (sirf_iob_port_t *)iob;
+
+ gpio_set_value(port->ctl_ports.gpio_on_off, on);
+}
+
+void sirf_iob_pal_ctrl_reset(struct sirf_iob *iob, int reset)
+{
+ sirf_iob_port_t *port = (sirf_iob_port_t *)iob;
+
+ gpio_set_value(port->ctl_ports.gpio_reset, reset);
+}
+
+void sirf_iob_pal_ctrl_poweron(struct sirf_iob *iob, int on)
+{
+ sirf_iob_port_t *port = (sirf_iob_port_t *)iob;
+
+ gpio_set_value(port->ctl_ports.gpio_power, on);
+}
+
+void sirf_iob_pal_wake_sender(struct sirf_iob *iob)
+{
+
+}
+
+int sirf_iob_pal_schedule_now(struct sirf_iob *iob)
+{
+ sirf_iob_port_t *port = (sirf_iob_port_t *)iob;
+
+ sirf_iob_pal_send_event(&port->iob, SIRF_IOB_EVENT_IO_INITIATE, 0, 0);
+
+ return 0;
+}
+
+void sirf_iob_pal_get_timeofday(unsigned int *sec, unsigned int *nsec)
+{
+ struct timespec tv;
+
+ getnstimeofday(&tv);
+
+ *sec = tv.tv_sec;
+ *nsec = tv.tv_nsec;
+}
+
+int sirf_iob_pal_create_timer(struct sirf_iob *iob, SIRF_IOB_TIMER_ID id, sirf_iob_timer_handler handler, void *parm)
+{
+ sirf_iob_port_t *port = (sirf_iob_port_t *)iob;
+
+ setup_timer(&port->timer[id], handler, (unsigned long)parm);
+
+ return 0;
+}
+
+void sirf_iob_pal_delete_timer(struct sirf_iob *iob, SIRF_IOB_TIMER_ID id)
+{
+ sirf_iob_port_t *port = (sirf_iob_port_t *)iob;
+
+ del_timer(&port->timer[id]);
+}
+
+void sirf_iob_pal_set_timer(struct sirf_iob *iob, SIRF_IOB_TIMER_ID id, int msec)
+{
+ sirf_iob_port_t *port = (sirf_iob_port_t *)iob;
+
+ mod_timer(&port->timer[id], jiffies + msecs_to_jiffies(msec));
+}
+
+
+sirf_iob_t *sirf_iob_pal_create_iob(void)
+{
+ sirf_iob_t *buf = kzalloc(sizeof(sirf_iob_port_t), GFP_KERNEL);
+
+ return buf;
+}
+
+int sirf_iob_pal_init(struct sirf_iob *iob, sirf_iob_init_t *init)
+{
+ sirf_iob_port_t *port = (sirf_iob_port_t *)iob;
+ int ret;
+ unsigned long n;
+ const char *dev_name = "sirf_iob";
+
+ spin_lock_init(&port->lock);
+ spin_lock_init(&port->rlock);
+ spin_lock_init(&port->wlock);
+ spin_lock_init(&port->fifo_lock);
+
+ ret = kfifo_alloc(&port->evt_fifo, sizeof(sirf_iob_event_t) * 4, GFP_KERNEL);
+ if (ret < 0) {
+ pr_err("kfifo_alloc failed\n");
+ return -1;
+ }
+
+ ret = kfifo_alloc(&port->rx_fifo, MAX_RBUFF_SZ, GFP_KERNEL);
+ if (ret < 0) {
+ pr_err("kfifo_alloc failed\n");
+ return -1;
+ }
+
+ ret = kfifo_alloc(&port->tx_fifo, MAX_WBUFF_SZ, GFP_KERNEL);
+ if (ret < 0) {
+ pr_err("kfifo_alloc failed\n");
+ return -1;
+ }
+
+ switch (init->phy_type) {
+ case SIRF_IOB_PHY_UART:
+// ret = sirf_iob_pal_init_uart(port);
+ break;
+ case SIRF_IOB_PHY_SPI:
+// ret = sirf_iob_pal_init_spi(port);
+ break;
+ default:
+ break;
+ }
+
+
+ if (init->power_dev) {
+ if (!kstrtoul(init->power_dev, 10, &n))
+ port->ctl_ports.gpio_power = n;
+ }
+
+ if (init->onoff_dev) {
+ if (!kstrtoul(init->onoff_dev, 10, &n))
+ port->ctl_ports.gpio_on_off = n;
+ }
+
+ if (init->reset_dev) {
+ if (!kstrtoul(init->reset_dev, 10, &n))
+ port->ctl_ports.gpio_reset = n;
+ }
+
+ if (init->dri_dev) {
+ if (!kstrtoul(init->dri_dev, 10, &n))
+ port->ctl_ports.gpio_dri = n;
+ }
+
+ if (init->wake_dev) {
+ if (!kstrtoul(init->wake_dev, 10, &n))
+ port->ctl_ports.gpio_wakeup = n;
+ }
+
+ if (init->tm_dev) {
+ if (!kstrtoul(init->tm_dev, 10, &n))
+ port->ctl_ports.gpio_1pps = n;
+ }
+
+ if (port->ctl_ports.gpio_dri > 0) {
+ ret = request_irq(gpio_to_irq(port->ctl_ports.gpio_dri), sirf_iob_irq_handler, \
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, dev_name, iob);
+ if (ret < 0)
+ printk("Failed to request IRQ: #%d: %d\n", gpio_to_irq(port->ctl_ports.gpio_dri), ret);
+ }
+
+ if (port->ctl_ports.gpio_1pps > 0) {
+ ret = request_irq(gpio_to_irq(port->ctl_ports.gpio_1pps), sirf_iob_irq_handler, \
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, dev_name, iob);
+ if (ret < 0)
+ printk("Failed to request IRQ: #%d: %d\n", gpio_to_irq(port->ctl_ports.gpio_1pps), ret);
+ }
+
+ if (port->ctl_ports.gpio_wakeup > 0) {
+ ret = request_irq(gpio_to_irq(port->ctl_ports.gpio_wakeup), sirf_iob_irq_handler, \
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, dev_name, iob);
+ if (ret < 0)
+ printk("Failed to request IRQ: #%d: %d\n", gpio_to_irq(port->ctl_ports.gpio_wakeup), ret);
+ }
+
+ return ret;
+}
+
+
+void sirf_iob_pal_deinit(struct sirf_iob *iob)
+{
+ sirf_iob_port_t *port = (sirf_iob_port_t *)iob;
+
+ kfifo_free(&port->evt_fifo);
+ kfifo_free(&port->rx_fifo);
+ kfifo_free(&port->tx_fifo);
+
+ if (port->ctl_ports.gpio_dri > 0)
+ free_irq(gpio_to_irq(port->ctl_ports.gpio_dri), iob);
+
+ if (port->ctl_ports.gpio_1pps > 0)
+ free_irq(gpio_to_irq(port->ctl_ports.gpio_1pps), iob);
+
+ if (port->ctl_ports.gpio_wakeup > 0)
+ free_irq(gpio_to_irq(port->ctl_ports.gpio_wakeup), iob);
+}
+
+
+int sirf_iob_pal_user_read(sirf_iob_t *iob, unsigned char *buf, int len)
+{
+ sirf_iob_port_t *port = (sirf_iob_port_t *)iob;
+ int count;
+
+ count = kfifo_out_locked(&port->rx_fifo, port->rbuf, len, &port->rlock);
+
+ if (count > 0)
+ copy_to_user(buf, port->rbuf, count);
+
+ return count;
+}
+
+int sirf_iob_pal_user_write(sirf_iob_t *iob, const unsigned char *buf, int len)
+{
+ sirf_iob_port_t *port = (sirf_iob_port_t *)iob;
+ int count;
+
+ copy_from_user(port->wbuf, buf, len);
+
+ count = kfifo_in_locked(&port->tx_fifo, port->wbuf, len, &port->wlock);
+
+ sirf_iob_pal_send_event(iob, SIRF_IOB_EVENT_IO_INITIATE, 0, 0);
+
+ return count;
+}
+
+void sirf_iob_pal_msleep(int msec)
+{
+ msleep(msec);
+}
diff --git a/app/kernel/linux/sirf_iob_pal_linux_km.h b/app/kernel/linux/sirf_iob_pal_linux_km.h
new file mode 100644
index 0000000..5b68532
--- /dev/null
+++ b/app/kernel/linux/sirf_iob_pal_linux_km.h
@@ -0,0 +1,103 @@
+/*
+ Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, and the entire permission notice in its entirety,
+ including the disclaimer of warranties.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+ ALTERNATIVELY, this product may be distributed under the terms of
+ the GNU General Public License, version 2, in which case the provisions
+ of the GPL version 2 are required INSTEAD OF the BSD license.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE.
+*/
+#ifndef __SIRF_IOB_PAL_LINUX_KM_H
+#define __SIRF_IOB_PAL_LINUX_KM_H
+
+#include <linux/spinlock.h>
+#include <linux/kfifo.h>
+#include <linux/timer.h>
+
+#include "sirf_iob_pal.h"
+
+#define MAX_RBUFF_SZ 4096
+#define MAX_WBUFF_SZ 2048
+
+
+struct sirf_iob_port;
+
+typedef struct {
+ unsigned short evt;
+ unsigned short len;
+ unsigned char arg[128];
+} sirf_iob_event_t;
+
+
+typedef struct sirf_iob_work {
+ struct work_struct work;
+ struct sirf_iob_port *port;
+} sirf_iob_work_t;
+
+typedef struct sirf_iob_port {
+ sirf_iob_t iob;
+ spinlock_t lock;
+ int monitor_state;
+ struct timer_list timer[2];
+ struct sirf_iob_work work;
+ struct workqueue_struct *wqueue;
+ struct kfifo evt_fifo;
+ spinlock_t fifo_lock;
+ sirf_iob_task_f handler;
+ void *arg;
+ struct {
+ unsigned int gpio_on_off;
+ unsigned int gpio_reset;
+ unsigned int gpio_wakeup;
+ unsigned int gpio_power;
+ unsigned int gpio_dri;
+ unsigned int gpio_1pps;
+ } ctl_ports;
+ struct kfifo rx_fifo;
+ struct kfifo tx_fifo;
+ struct kfifo uart_raw_fifo;
+ unsigned char rbuf[MAX_RBUFF_SZ];
+ unsigned char wbuf[MAX_WBUFF_SZ];
+ spinlock_t rlock;
+ spinlock_t wlock;
+ spinlock_t uartlock;
+} sirf_iob_port_t;
+
+
+void sirf_iob_drv_probe(void);
+
+void sirf_iob_drv_remove(void);
+
+int sirf_iob_uart_drv_init(void);
+
+void sirf_iob_uart_drv_exit(void);
+
+int sirf_iob_spi_drv_init(void);
+
+void sirf_iob_spi_drv_exit(void);
+
+#endif
diff --git a/app/kernel/linux/sirf_iob_spi.c b/app/kernel/linux/sirf_iob_spi.c
new file mode 100644
index 0000000..8b9837b
--- /dev/null
+++ b/app/kernel/linux/sirf_iob_spi.c
@@ -0,0 +1,130 @@
+/*
+ Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, and the entire permission notice in its entirety,
+ including the disclaimer of warranties.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+ ALTERNATIVELY, this product may be distributed under the terms of
+ the GNU General Public License, version 2, in which case the provisions
+ of the GPL version 2 are required INSTEAD OF the BSD license.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE.
+*/
+
+#include <linux/spi/spi.h>
+#include <linux/fs.h>
+
+#include "sirf_iob.h"
+#include "sirf_iob_pal_linux_km.h"
+
+
+int sirf_iob_pal_init_spi(sirf_iob_port_t *port)
+{
+ struct spi_device *spi = port->iob.priv;
+ int ret = 0;
+
+ spi->mode = SPI_MODE_1;
+ spi->max_speed_hz = 6800000;
+ spi->bits_per_word = 8;
+
+ spi_setup(spi);
+
+ return ret;
+}
+
+
+void sirf_iob_pal_spi_exchange(struct sirf_iob *iob, unsigned char *txbuf, unsigned char *rxbuf, int len)
+{
+ struct spi_device *spi = iob->priv;
+ struct spi_transfer t;
+ struct spi_message m;
+
+ spi_message_init(&m);
+ memset(&t, 0, sizeof(t));
+
+ t.tx_buf = txbuf;
+ t.rx_buf = rxbuf;
+ t.len = len;
+ spi_message_add_tail(&t, &m);
+
+ spi_sync(spi, &m);
+}
+
+
+static int sirf_iob_spi_probe(struct spi_device *spi)
+{
+ sirf_iob_t *iob;
+ struct plat_csrgps *data;
+ sirf_iob_init_t *init_data;
+ int ret = -1;
+
+ data = spi->dev.platform_data;
+ if (data == NULL) {
+ dev_err(&spi->dev, "no device data specified\n");
+ return -EINVAL;
+ }
+
+ iob = sirf_iob_pal_create_iob();
+ if (!iob)
+ return -ENOMEM;
+
+ iob->priv = spi;
+
+ init_data = (sirf_iob_init_t *)data;
+ sirf_iob_init(iob, *init_data);
+
+ sirf_iob_drv_probe();
+
+ return 0;
+}
+
+static int __exit sirf_iob_spi_remove(struct spi_device *spi)
+{
+ sirf_iob_drv_remove();
+
+ return 0;
+}
+
+
+struct spi_driver sirf_iob_spi_driver = {
+ .driver = {
+ .name = "sirf_iob",
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ },
+ .probe = sirf_iob_spi_probe,
+ .remove = __exit_p(sirf_iob_spi_remove),
+};
+
+int sirf_iob_spi_drv_init(void)
+{
+ return spi_register_driver(&sirf_iob_spi_driver);
+}
+EXPORT_SYMBOL(sirf_iob_spi_drv_init);
+
+void sirf_iob_spi_drv_exit(void)
+{
+ spi_unregister_driver(&sirf_iob_spi_driver);
+}
+EXPORT_SYMBOL(sirf_iob_spi_drv_exit);
diff --git a/app/kernel/linux/sirf_iob_uart.c b/app/kernel/linux/sirf_iob_uart.c
new file mode 100644
index 0000000..48671af
--- /dev/null
+++ b/app/kernel/linux/sirf_iob_uart.c
@@ -0,0 +1,146 @@
+/*
+ Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+ 1. Redistributions of source code must retain the above copyright
+ notice, and the entire permission notice in its entirety,
+ including the disclaimer of warranties.
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ 3. The name of the author may not be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+ ALTERNATIVELY, this product may be distributed under the terms of
+ the GNU General Public License, version 2, in which case the provisions
+ of the GPL version 2 are required INSTEAD OF the BSD license.
+
+ THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
+ WHICH ARE HEREBY DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
+ LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
+ OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ USE OF THIS SOFTWARE, EVEN IF NOT ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE.
+*/
+
+#include <linux/fs.h>
+#include <linux/kfifo.h>
+#include <linux/tty.h>
+
+#include "sirf_iob.h"
+#include "sirf_iob_pal_linux_km.h"
+
+
+#define UART_BUF_SIZE PAGE_SIZE
+#define N_SIRF_IOB 25
+
+int sirf_iob_pal_init_uart(sirf_iob_port_t *port)
+{
+ int ret = 0;
+
+ spin_lock_init(&port->uartlock);
+
+ ret = kfifo_alloc(&port->uart_raw_fifo, UART_BUF_SIZE, GFP_KERNEL);
+ if (ret < 0) {
+ pr_err("kfifo_alloc failed\n");
+ return -1;
+ }
+
+ return ret;
+}
+
+int sirf_iob_pal_stream_transmit(sirf_iob_t *iob, unsigned char *data, int len)
+{
+ struct tty_struct *tty = (struct tty_struct *)iob->priv;
+
+ return tty->ops->write(tty, data, len);
+}
+
+int sirf_iob_pal_stream_receive(sirf_iob_t *iob, unsigned char *data, int len)
+{
+ sirf_iob_port_t *port = (sirf_iob_port_t *)iob;
+
+ return kfifo_out_locked(&port->uart_raw_fifo, data, len, &port->uartlock);
+}
+
+int sirf_iob_pal_change_speed(sirf_iob_t *iob, unsigned int speed)
+{
+ int ret = 0;
+
+ return ret;
+}
+
+
+
+int sirf_iob_ld_open(struct tty_struct *tty)
+{
+ sirf_iob_t *iob;
+
+ iob = sirf_iob_pal_create_iob();
+ if (!iob)
+ return -ENOMEM;
+
+ tty->disc_data = iob;
+ tty->receive_room = PAGE_SIZE;
+
+ /* Attach the initial passive connection */
+ iob->priv = tty_kref_get(tty);
+
+// init_data = (sirf_iob_init_t *)data;
+// sirf_iob_init(iob, *init_data);
+
+ sirf_iob_drv_probe();
+
+ return 0;
+}
+
+void sirf_iob_ld_close(struct tty_struct *tty)
+{
+ sirf_iob_drv_remove();
+}
+
+void sirf_iob_ld_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
+{
+ sirf_iob_port_t *port = (sirf_iob_port_t *)tty->disc_data;
+
+ if (port) {
+ kfifo_in_locked(&port->uart_raw_fifo, cp, count, &port->uartlock);
+
+ sirf_iob_pal_schedule_now(&port->iob);
+ }
+}
+
+static struct tty_ldisc_ops sirf_iob_tty_ldisc = {
+ .owner = THIS_MODULE,
+ .magic = TTY_LDISC_MAGIC,
+ .name = "sirf_iob",
+ .open = sirf_iob_ld_open,
+ .close = sirf_iob_ld_close,
+ .receive_buf = sirf_iob_ld_receive_buf,
+};
+
+
+int sirf_iob_uart_drv_init(void)
+{
+ int status = tty_register_ldisc(N_SIRF_IOB, &sirf_iob_tty_ldisc);
+
+ if (status != 0) {
+ printk("%s: can't register line discipline (err = %d)\n", __FUNCTION__, status);
+ }
+
+ return status;
+}
+
+void sirf_iob_uart_drv_exit(void)
+{
+ tty_unregister_ldisc(N_SIRF_IOB);
+}
diff --git a/app/lib/inc/sirf_iob_user.h b/app/lib/inc/sirf_iob_user.h
new file mode 100644
index 0000000..935e997
--- /dev/null
+++ b/app/lib/inc/sirf_iob_user.h
@@ -0,0 +1,60 @@
+/*
+ Copyright (c) 2000-2014, The Linux Foundation. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the <organization> nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef __SIRF_IOB_USER_H
+#define __SIRF_IOB_USER_H
+
+
+typedef void* SIRF_IOB_USER_HANDLE;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+SIRF_IOB_USER_HANDLE sirf_iob_user_open(const char *dev_name,
+ const char *powerdev_name,
+ const char *onooffdev_name,
+ const char *resetdev_name,
+ const char *wakeupdev_name,
+ const char *dridev_name,
+ const char *timemarkdev_name);
+
+void sirf_iob_user_close(SIRF_IOB_USER_HANDLE iob);
+
+int sirf_iob_user_read(SIRF_IOB_USER_HANDLE iob, unsigned char *buf, int len);
+
+int sirf_iob_user_write(SIRF_IOB_USER_HANDLE iob, const unsigned char *buf, int len);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __SIRF_IOB_USER_H */
+
+
+
diff --git a/include/sirf_iob.h b/include/sirf_iob.h
new file mode 100644
index 0000000..9b375f8
--- /dev/null
+++ b/include/sirf_iob.h
@@ -0,0 +1,155 @@
+/*
+ Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+ This library is dual licensed. If it is used to create a linux driver, it is
+ licensed under the GPL. If it used to create a usermode driver, the library
+ is licensed under the terms of the license agreement for the usermode driver.
+*/
+
+#ifndef __SIRF_IOB_H
+#define __SIRF_IOB_H
+
+
+#define SIRF_IOB_XMIT_BLOCK_SIZE 512
+
+// Bit 16..31 : Reserved for Host Output
+#define SIRF_IOB_GPIO_DOUT_DR_REV_EXT (1 << 7)
+#define SIRF_IOB_GPIO_DOUT_DR_VSS_EXT (1 << 8)
+#define SIRF_IOB_GPIO_DOUT_TSYNC (1 << 9)
+#define SIRF_IOB_GPIO_DOUT_BOOTMODE1 (1 << 10)
+#define SIRF_IOB_GPIO_DOUT_BOOTMODE2 (1 << 12)
+#define SIRF_IOB_GPIO_DOUT_ONOFF (1 << 13)
+#define SIRF_IOB_GPIO_DOUT_RESET (1 << 14)
+#define SIRF_IOB_GPIO_DOUT_POWER (1 << 15)
+
+// Bit 16..31 : Reserved for Host Input
+#define SIRF_IOB_GPIO_DIN_DR_REV_EXT (1 << 24)
+#define SIRF_IOB_GPIO_DIN_DR_VSS_EXT (1 << 25)
+#define SIRF_IOB_GPIO_DIN_RESERVED (1 << 26)
+#define SIRF_IOB_GPIO_DIN_DR_REV (1 << 27)
+#define SIRF_IOB_GPIO_DIN_DR_SYNC (1 << 28)
+#define SIRF_IOB_GPIO_DIN_1PPS (1 << 29)
+#define SIRF_IOB_GPIO_DIN_DRI (1 << 30)
+#define SIRF_IOB_GPIO_DIN_WAKEUP (1 << 31)
+
+typedef enum {
+ SIRF_IOB_PHY_UNKNOWN = 0,
+ SIRF_IOB_PHY_UART,
+ SIRF_IOB_PHY_I2C,
+ SIRF_IOB_PHY_SPI,
+ SIRF_IOB_PHY_FTDI,
+} SIRF_IOB_PHY_TYPE;
+
+typedef enum {
+ SIRF_IOB_EVENT_ERR = -1,
+ SIRF_IOB_EVENT_TIMEOUT = 0,
+ SIRF_IOB_EVENT_POLL_TIMER_EXPIRED = 1,
+ SIRF_IOB_EVENT_PROTO_TIMER_EXPIRED,
+ SIRF_IOB_EVENT_IO_INITIATE,
+ SIRF_IOB_EVENT_GPIO_CHANGED,
+ SIRF_IOB_EVENT_STOP,
+} SIRF_IOB_INTEVT;
+
+typedef enum {
+ SIRF_IOB_STATE_UNKNOWN = 0,
+ SIRF_IOB_STATE_HIBERNATE,
+ SIRF_IOB_STATE_PREWAKE,
+ SIRF_IOB_STATE_RUNNING,
+ SIRF_IOB_STATE_RESET,
+} SIRF_IOB_STATE;
+
+typedef struct {
+ unsigned int gpio;
+ int val;
+} sirf_iob_evt_gpio_changed;
+
+struct sirf_iob;
+
+typedef int (*sirf_iob_xfer_work_f)(struct sirf_iob *);
+typedef void (*sirf_iob_state_enter)(struct sirf_iob *);
+typedef void (*sirf_iob_state_exit)(struct sirf_iob *);
+typedef int (*sirf_iob_event_handler)(struct sirf_iob *, SIRF_IOB_INTEVT, void *);
+typedef int (*sirf_iob_downstream_handler)(struct sirf_iob *);
+typedef int (*sirf_iob_upstream_handler)(struct sirf_iob *);
+typedef int (*sirf_iob_state_get_waittime)(struct sirf_iob *);
+
+typedef struct _sirf_iob_state {
+ SIRF_IOB_STATE state;
+ const char *name;
+ sirf_iob_state_enter enter;
+ sirf_iob_state_exit exit;
+ sirf_iob_event_handler handler;
+ sirf_iob_downstream_handler downstream;
+ sirf_iob_upstream_handler upstream;
+ sirf_iob_state_get_waittime waittime;
+} sirf_iob_state_t;
+
+typedef struct sirf_iob {
+ void *priv;
+ int use_dri;
+ int traffic_flags;
+ int task_alive;
+ sirf_iob_state_t *state;
+ sirf_iob_state_t **state_set;
+ int uart_speed_index; // uart only
+ struct {
+ int sec;
+ int nsec;
+ } target_timemark;
+ struct {
+ unsigned char tmp_buf[SIRF_IOB_XMIT_BLOCK_SIZE];
+ unsigned char dummy_buf[SIRF_IOB_XMIT_BLOCK_SIZE];
+ unsigned char buf[SIRF_IOB_XMIT_BLOCK_SIZE + 4];
+ int cursor;
+ int len;
+ int state;
+ } xmit_frag;
+ struct {
+ unsigned char buf[SIRF_IOB_XMIT_BLOCK_SIZE];
+ } recv_frag;
+ struct {
+ int locked;
+ int stage;
+ int len_in_data;
+ int packet_len;
+ int run;
+ unsigned char packet[SIRF_IOB_XMIT_BLOCK_SIZE * 2];
+ } dec_state;
+ struct {
+ unsigned int rising_in;
+ unsigned int rising_out;
+ unsigned int falling_in;
+ unsigned int falling_out;
+ } gpio_report_mask;
+} sirf_iob_t;
+
+typedef struct {
+ SIRF_IOB_PHY_TYPE phy_type;
+ char *port_dev;
+ char *onoff_dev;
+ char *reset_dev;
+ char *power_dev;
+ char *dri_dev;
+ char *wake_dev;
+ char *tm_dev;
+} sirf_iob_init_t;
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void sirf_iob_init(sirf_iob_t *iob, sirf_iob_init_t init_data);
+
+void sirf_iob_open(sirf_iob_t *iob);
+
+void sirf_iob_close(sirf_iob_t *iob);
+
+void sirf_iob_gpio_input_isr(sirf_iob_t *iob, unsigned int ionum, int val);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/include/sirf_iob_buf.h b/include/sirf_iob_buf.h
new file mode 100644
index 0000000..108dc5e
--- /dev/null
+++ b/include/sirf_iob_buf.h
@@ -0,0 +1,57 @@
+/*
+ Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+ This library is dual licensed. If it is used to create a linux driver, it is
+ licensed under the GPL. If it used to create a usermode driver, the library
+ is licensed under the terms of the license agreement for the usermode driver.
+*/
+
+#ifndef __SIRF_IOB_BUF_H
+#define __SIRF_IOB_BUF_H
+
+#define BUF_SIZE 0x8000
+
+typedef struct {
+ unsigned char data[BUF_SIZE];
+ int rcursor;
+ int wcursor;
+} sirf_iob_buf_t;
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static __inline int sirf_iob_buffer_empty(sirf_iob_buf_t *buf)
+{
+ return (buf->rcursor == buf->wcursor);
+}
+
+static __inline int sirf_iob_buffer_full(sirf_iob_buf_t *buf)
+{
+ int next_wcursor = (buf->wcursor + 1) & (BUF_SIZE - 1);
+
+ return (buf->rcursor == next_wcursor);
+}
+
+static __inline unsigned char sirf_iob_pop_buffer(sirf_iob_buf_t *buf)
+{
+ unsigned char c;
+
+ c = buf->data[buf->rcursor++];
+ buf->rcursor &= (BUF_SIZE - 1);
+
+ return c;
+}
+
+static __inline void sirf_iob_push_buffer(sirf_iob_buf_t *buf, unsigned char c)
+{
+ buf->data[buf->wcursor++] = c;
+ buf->wcursor &= (BUF_SIZE - 1);
+}
+
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __SIRF_IOB_BUF_H */
diff --git a/include/sirf_iob_config.h b/include/sirf_iob_config.h
new file mode 100644
index 0000000..fd08c63
--- /dev/null
+++ b/include/sirf_iob_config.h
@@ -0,0 +1,31 @@
+/*
+ Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+ This library is dual licensed. If it is used to create a linux driver, it is
+ licensed under the GPL. If it used to create a usermode driver, the library
+ is licensed under the terms of the license agreement for the usermode driver.
+*/
+
+
+#ifndef __SIRF_IOB_CONFIG_H
+#define __SIRF_IOB_CONFIG_H
+
+typedef struct {
+ char port_name[128];
+ char onoff_name[128];
+ char reset_name[128];
+ char power_name[128];
+ char wakeup_name[128];
+ char dri_name[128];
+ char timemark_name[128];
+ int server_port_num;
+
+ char remote_addr[16];
+ int remote_flag; // for future use.
+
+} sirf_iob_config_t;
+
+
+void sirf_iob_config_parse(const char *str, int len, sirf_iob_config_t *config);
+
+#endif
diff --git a/include/sirf_iob_debug.h b/include/sirf_iob_debug.h
new file mode 100644
index 0000000..61bc44f
--- /dev/null
+++ b/include/sirf_iob_debug.h
@@ -0,0 +1,57 @@
+/*
+ Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+ This library is dual licensed. If it is used to create a linux driver, it is
+ licensed under the GPL. If it used to create a usermode driver, the library
+ is licensed under the terms of the license agreement for the usermode driver.
+*/
+#ifndef __SIRF_IOB_DEBUG_H
+#define __SIRF_IOB_DEBUG_H
+
+#ifndef __KERNEL__
+#include <stdio.h>
+#endif
+
+typedef enum {
+ SIRF_IOB_LOG_STDIO,
+ SIRF_IOB_LOG_FILE,
+} SIRF_IOB_LOG_TYPE;
+
+#define SIRF_IOB_LOG_LVL_NONE 0
+#define SIRF_IOB_LOG_LVL_ERR 1
+#define SIRF_IOB_LOG_LVL_WARNING 2
+#define SIRF_IOB_LOG_LVL_INFO 3
+#define SIRF_IOB_LOG_LVL_DEBUG 4
+#define SIRF_IOB_LOG_LVL_TRACE 5
+
+#if defined(WIN32) || defined(__KERNEL__)
+#define ERR
+#define WARNING
+#define INFO
+#define DEBUG
+#define ENTER()
+#define EXIT()
+#else
+#define ERR(fmt, args...) sirf_iob_dbg_err(__LINE__, __FILE__, fmt, ##args)
+#define WARNING(fmt, args...) sirf_iob_dbg_log(SIRF_IOB_LOG_LVL_WARNING, fmt, ##args)
+#define INFO(fmt, args...) sirf_iob_dbg_log(SIRF_IOB_LOG_LVL_INFO, fmt, ##args)
+#define DEBUG(fmt, args...) sirf_iob_dbg_log(SIRF_IOB_LOG_LVL_DEBUG, fmt, ##args)
+
+extern FILE *logfile;
+
+#define ENTER() sirf_iob_dbg_log(SIRF_IOB_LOG_LVL_TRACE, "+%s", __FUNCTION__);
+#define EXIT() sirf_iob_dbg_log(SIRF_IOB_LOG_LVL_TRACE, "-%s", __FUNCTION__);
+
+
+int sirf_iob_init_log(SIRF_IOB_LOG_TYPE type, const char *name);
+
+void sirf_iob_deinit_log(void);
+
+void sirf_iob_set_log_level(int level);
+
+void sirf_iob_dbg_err(int line, const char *file, char *fmt, ...);
+
+void sirf_iob_dbg_log(int level, char *fmt, ...);
+#endif
+
+#endif
diff --git a/include/sirf_iob_pal.h b/include/sirf_iob_pal.h
new file mode 100644
index 0000000..059537a
--- /dev/null
+++ b/include/sirf_iob_pal.h
@@ -0,0 +1,84 @@
+/*
+ Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+ This library is dual licensed. If it is used to create a linux driver, it is
+ licensed under the GPL. If it used to create a usermode driver, the library
+ is licensed under the terms of the license agreement for the usermode driver.
+*/
+
+#ifndef __SIRF_IOB_PAL_H_
+#define __SIRF_IOB_PAL_H_
+
+#include "sirf_iob.h"
+
+typedef enum {
+ SIRF_IOB_TIMER_POLL,
+ SIRF_IOB_TIMER_PROTO_SEARCH,
+} SIRF_IOB_TIMER_ID;
+
+typedef void *(*sirf_iob_task_f)(void *);
+typedef void (*sirf_iob_timer_handler)(void *obj);
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+sirf_iob_t *sirf_iob_pal_create_iob(void);
+
+int sirf_iob_pal_init(sirf_iob_t *iob, sirf_iob_init_t *init);
+
+void sirf_iob_pal_deinit(sirf_iob_t *iob);
+
+void sirf_iob_pal_start_task(sirf_iob_t *iob, sirf_iob_task_f handler, void *arg);
+
+void sirf_iob_pal_lock(sirf_iob_t *iob);
+
+void sirf_iob_pal_unlock(sirf_iob_t *iob);
+
+int sirf_iob_pal_get_from_host(sirf_iob_t *iob, unsigned char *buf, int len); /* receive data from Host */
+
+int sirf_iob_pal_put_to_host(sirf_iob_t *iob, unsigned char *buf, int len); /* transmit data to Host */
+
+void sirf_iob_pal_spi_exchange(sirf_iob_t *iob, unsigned char *txbuf, unsigned char *rxbuf, int len); /* exchange data over SPI transport */
+
+int sirf_iob_pal_stream_transmit(sirf_iob_t *iob, unsigned char *data, int len); /* traminit data over stream interface */
+
+int sirf_iob_pal_stream_receive(sirf_iob_t *iob, unsigned char *data, int len); /* receive data from stream interface */
+
+int sirf_iob_pal_change_speed(sirf_iob_t *iob, unsigned int speed);
+
+int sirf_iob_pal_get_gpio_val(sirf_iob_t *iob, unsigned int ionum);
+
+void sirf_iob_pal_ctrl_onoff(sirf_iob_t *iob, int on);
+
+void sirf_iob_pal_ctrl_reset(sirf_iob_t *iob, int reset);
+
+void sirf_iob_pal_ctrl_poweron(sirf_iob_t *gps, int on);
+
+void sirf_iob_pal_wake_sender(sirf_iob_t *iob); /* wakeup sender - Linux kernel driver only */ /* consider callback */
+
+int sirf_iob_pal_schedule_now(sirf_iob_t *iob);
+
+void sirf_iob_pal_get_timeofday(unsigned int *sec, unsigned int *nsec);
+
+void sirf_iob_pal_send_event(sirf_iob_t *iob, unsigned int event, void *parm, int len);
+
+int sirf_iob_pal_create_timer(sirf_iob_t *iob, SIRF_IOB_TIMER_ID id, sirf_iob_timer_handler handler, void *parm);
+
+void sirf_iob_pal_delete_timer(sirf_iob_t *iob, SIRF_IOB_TIMER_ID id);
+
+void sirf_iob_pal_set_timer(sirf_iob_t *iob, SIRF_IOB_TIMER_ID id, int msec);
+
+void sirf_iob_pal_msleep(int usec);
+
+int sirf_iob_pal_user_read(sirf_iob_t *iob, unsigned char *buf, int len);
+
+int sirf_iob_pal_user_write(sirf_iob_t *iob, const unsigned char *buf, int len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/readme/How to build.txt b/readme/How to build.txt
new file mode 100644
index 0000000..ed50b78
--- /dev/null
+++ b/readme/How to build.txt
@@ -0,0 +1,26 @@
+
+Linux Kernel Driver
+===================
+
+1. make a directory "sirf_iob" under ${KERNEL}/drivers/char/
+
+2. copy all kernel driver source code to ${KERNEL}/drivers/char/
+
+ cp ${IOB_BASE}/source/* ${KERNEL}/drivers/char/sirf_iob/
+ cp ${IOB_BASE}/include/* ${KERNEL}/drivers/char/sirf_iob/
+ cp ${IOB_BASE}/app/kernel/* ${KERNEL}/drivers/char/sirf_iob/
+
+3. add below line to the Makefile in ${KERNEL}/drivers/char/
+ obj-y += sirf_iob/
+
+4. build kernel image
+
+
+Linux user mode driver (daemon)
+===============================
+${IOB_BASE}\app\daemon\posix\linux\Makefile
+
+
+Android user mode driver (daemon)
+=================================
+${IOB_BASE}\app\daemon\posix\Android\jni\Android.mk
diff --git a/source/sirf_iob_config.c b/source/sirf_iob_config.c
new file mode 100644
index 0000000..0379bb9
--- /dev/null
+++ b/source/sirf_iob_config.c
@@ -0,0 +1,103 @@
+/*
+ Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+ This library is dual licensed. If it is used to create a linux driver, it is
+ licensed under the GPL. If it used to create a usermode driver, the library
+ is licensed under the terms of the license agreement for the usermode driver.
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "sirf_iob_config.h"
+#include "sirf_xml.h"
+
+#define TAG_IOB "IOBridge"
+#define TAG_ACTIVE "Active"
+#define TAG_CONFIGS "Configs"
+#define TAG_CONFIG "Config"
+#define TAG_TRANSPORT_DEV_NAME "Device"
+#define TAG_ONOFF_DEV_NAME "DO_OnOff"
+#define TAG_RESET_DEV_NAME "DO_Reset"
+#define TAG_POWER_DEV_NAME "DO_Power"
+#define TAG_WAKE_DEV_NAME "DI_Wakeup"
+#define TAG_DRI_DEV_NAME "DI_DRI"
+#define TAG_TIMEMARK_DEV_NAME "DI_PPS"
+#define TAG_PORT_NUM "PortNum"
+#define TAG_REMOTE_FLAG "Remote_Flag"
+#define TAG_REMOTE_ADDR "Remote_Addr"
+
+static void sirf_iob_load_string(const char *str, int len, const char *tag, char *target)
+{
+ unsigned int content_len;
+ const char *content;
+
+ content = FindTagContentInConfigString(len, (const char *)str, strlen(tag), tag, &content_len);
+ if (content != 0 && (content_len > 0))
+ strncpy(target, content, content_len);
+}
+
+static int sirf_iob_load_int(const char *str, int len, const char *tag)
+{
+ unsigned int content_len;
+ const char *content;
+ char tmp[32];
+
+ content = FindTagContentInConfigString(len, (const char *)str, strlen(tag), tag, &content_len);
+ if (content && content_len > 0) {
+ strncpy(tmp, content, content_len);
+ tmp[content_len] = 0;
+
+ return atoi(tmp);
+ }
+
+ return -1;
+}
+
+void sirf_iob_config_parse(const char *str, int len, sirf_iob_config_t *config)
+{
+ unsigned int content_len;
+ unsigned int config_len;
+ const char *content;
+ const char *config_content;
+ const char *tmp;
+ char active[32];
+ int remained;
+
+ memset(config, 0, sizeof(sirf_iob_config_t));
+ memset(active, 0, 32);
+
+ content = FindTagContentInConfigString(len, str, strlen(TAG_IOB), TAG_IOB, &content_len);
+
+ sirf_iob_load_string(content, content_len, TAG_ACTIVE, active);
+
+ content = FindTagContentInConfigString(len, str, strlen(TAG_CONFIGS), TAG_CONFIGS, &content_len);
+ remained = content_len;
+ while (remained > 0) {
+ config_content = FindTagInConfigString(remained, content, strlen(TAG_CONFIG), TAG_CONFIG, &config_len);
+ if (config_content == NULL)
+ break;
+
+ tmp = FindWordInConfigString(config_len, config_content, strlen(active), active);
+ if (tmp != NULL) {
+ sirf_iob_load_string(config_content, config_len, TAG_TRANSPORT_DEV_NAME, config->port_name);
+ sirf_iob_load_string(config_content, config_len, TAG_ONOFF_DEV_NAME, config->onoff_name);
+ sirf_iob_load_string(config_content, config_len, TAG_RESET_DEV_NAME, config->reset_name);
+ sirf_iob_load_string(config_content, config_len, TAG_POWER_DEV_NAME, config->power_name);
+ sirf_iob_load_string(config_content, config_len, TAG_WAKE_DEV_NAME, config->wakeup_name);
+ sirf_iob_load_string(config_content, config_len, TAG_DRI_DEV_NAME, config->dri_name);
+ sirf_iob_load_string(config_content, config_len, TAG_TIMEMARK_DEV_NAME, config->timemark_name);
+ sirf_iob_load_string(config_content, config_len, TAG_REMOTE_ADDR, config->remote_addr);
+
+ break;
+ }
+
+ content += config_len;
+ remained -= config_len;
+ }
+
+ config->remote_flag = sirf_iob_load_int(str, len, TAG_REMOTE_FLAG);
+ config->server_port_num = sirf_iob_load_int(str, len, TAG_PORT_NUM);
+}
diff --git a/source/sirf_iob_core.c b/source/sirf_iob_core.c
new file mode 100644
index 0000000..5a16e8d
--- /dev/null
+++ b/source/sirf_iob_core.c
@@ -0,0 +1,1137 @@
+/*
+ Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+ This library is dual licensed. If it is used to create a linux driver, it is
+ licensed under the GPL. If it used to create a usermode driver, the library
+ is licensed under the terms of the license agreement for the usermode driver.
+*/
+
+
+#ifndef __KERNEL__
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#else
+#include <linux/string.h>
+#endif
+
+
+#include "sirf_iob.h"
+#include "sirf_iob_pal.h"
+#include "sirf_iob_debug.h"
+
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0]))
+#endif
+
+
+#define IOB_OSP_DEC_SEARCH_A0 0
+#define IOB_OSP_DEC_SEARCH_A2 1
+#define IOB_OSP_DEC_LENGTH_HIGH 2
+#define IOB_OSP_DEC_LENGTH_LOW 3
+#define IOB_OSP_DEC_BODY 4
+#define IOB_OSP_DEC_FOUND_B0 5
+
+#define IOB_SFEEP_CHECK_NORMAL 0
+#define IOB_SFEEP_CHECK_ESC 1
+
+#define IOB_SFEEP_IDLE 0x7E
+#define IOB_SFEEP_ESC 0x7D
+#define IOB_SFEEP_ESC_IDLE 0x5E
+#define IOB_SFEEP_ESC_ESC 0x5D
+
+#define IOB_DSTRM_STATE_STORING (1)
+#define IOB_DSTRM_STATE_CLOSE (1 << 1)
+
+#define IOB_TRAFFIC_RX (1)
+#define IOB_TRAFFIC_TX (1 << 1)
+#define IOB_TRAFFIC_INITWAIT (1 << 5)
+
+#define IOB_DRI_SENSE_TRIGGER_NUM 5
+
+#define IOB_OSP_PACKET_CAPSULE_SIZE 8
+
+
+#define SIRF_IOB_GPIO_MASK_DOUT (SIRF_IOB_GPIO_DOUT_POWER | SIRF_IOB_GPIO_DOUT_RESET | SIRF_IOB_GPIO_DOUT_ONOFF)
+#define SIRF_IOB_GPIO_MASK_DIN (SIRF_IOB_GPIO_DIN_DRI | SIRF_IOB_GPIO_DIN_WAKEUP | SIRF_IOB_GPIO_DIN_1PPS)
+#define SIRF_IOB_GPIO_MASK_ALL (SIRF_IOB_GPIO_MASK_DOUT | SIRF_IOB_GPIO_MASK_DIN)
+
+extern int sirf_iob_pal_wait_event(sirf_iob_t *iob, unsigned int *event, unsigned char *evtobj, int objLen, int block);
+
+static void sirf_iob_unknown_enter(sirf_iob_t *iob);
+static void sirf_iob_prewake_enter(sirf_iob_t *iob);
+static void sirf_iob_running_enter(sirf_iob_t *iob);
+static void sirf_iob_running_uart_enter(sirf_iob_t *iob);
+
+static int sirf_iob_evt_hibernate_handler(sirf_iob_t *iob, SIRF_IOB_INTEVT evt, void *parm);
+static int sirf_iob_evt_prewake_handler(sirf_iob_t *iob, SIRF_IOB_INTEVT evt, void *parm);
+static int sirf_iob_evt_running_handler(sirf_iob_t *iob, SIRF_IOB_INTEVT evt, void *parm);
+
+static int sirf_iob_downstream_generic_handler(sirf_iob_t *iob);
+static int sirf_iob_downstream_running_spi_handler(sirf_iob_t *iob);
+static int sirf_iob_downstream_running_uart_handler(sirf_iob_t *iob);
+static int sirf_iob_upstream_generic_handler(sirf_iob_t *iob);
+static int sirf_iob_upstream_running_spi_handler(sirf_iob_t *iob);
+static int sirf_iob_upstream_running_uart_handler(sirf_iob_t *iob);
+
+static int sirf_iob_hibernate_waittime(sirf_iob_t *iob);
+static int sirf_iob_prewake_waittime(sirf_iob_t *iob);
+static int sirf_iob_running_uart_waittime(sirf_iob_t *iob);
+static int sirf_iob_running_spi_waittime(sirf_iob_t *iob);
+
+static int uart_speed_table[] = {
+ 4800, 9600, 38400, 57600, 115200, 230400, 460800, 921600
+};
+
+
+static sirf_iob_state_t generic_unkown_state = {
+ .state = SIRF_IOB_STATE_UNKNOWN,
+ .name = "UNKOWN",
+ .enter = sirf_iob_unknown_enter,
+};
+
+static sirf_iob_state_t generic_hibernate_state = {
+ .state = SIRF_IOB_STATE_HIBERNATE,
+ .name = "HIBERNATE",
+ .handler = sirf_iob_evt_hibernate_handler,
+ .downstream = sirf_iob_downstream_generic_handler,
+ .upstream = sirf_iob_upstream_generic_handler,
+ .waittime = sirf_iob_hibernate_waittime,
+};
+
+static sirf_iob_state_t generic_prewake_state = {
+ .state = SIRF_IOB_STATE_PREWAKE,
+ .name = "PREWAKE",
+ .enter = sirf_iob_prewake_enter,
+ .handler = sirf_iob_evt_prewake_handler,
+ .downstream = sirf_iob_downstream_generic_handler,
+ .upstream = sirf_iob_upstream_generic_handler,
+ .waittime = sirf_iob_prewake_waittime,
+};
+
+static sirf_iob_state_t uart_running_state = {
+ .state = SIRF_IOB_STATE_RUNNING,
+ .name = "RUNNING_UART",
+ .enter = sirf_iob_running_uart_enter,
+ .handler = sirf_iob_evt_running_handler,
+ .downstream = sirf_iob_downstream_running_uart_handler,
+ .upstream = sirf_iob_upstream_running_uart_handler,
+ .waittime = sirf_iob_running_uart_waittime,
+};
+
+static sirf_iob_state_t spi_running_state = {
+ .state = SIRF_IOB_STATE_RUNNING,
+ .name = "RUNNING_SPI",
+ .enter = sirf_iob_running_enter,
+ .handler = sirf_iob_evt_running_handler,
+ .downstream = sirf_iob_downstream_running_spi_handler,
+ .upstream = sirf_iob_upstream_running_spi_handler,
+ .waittime = sirf_iob_running_spi_waittime,
+};
+
+static sirf_iob_state_t generic_reset_state = {
+ .state = SIRF_IOB_STATE_RESET,
+ .name = "RESET",
+ .handler = sirf_iob_evt_hibernate_handler,
+ .downstream = sirf_iob_downstream_generic_handler,
+};
+
+static sirf_iob_state_t *uart_state[] = {
+ &generic_unkown_state,
+ &generic_hibernate_state,
+ &generic_prewake_state,
+ &uart_running_state,
+ &generic_reset_state,
+};
+
+static sirf_iob_state_t *spi_state[] = {
+ &generic_unkown_state,
+ &generic_hibernate_state,
+ &generic_prewake_state,
+ &spi_running_state,
+ &generic_reset_state,
+};
+
+
+
+static void sirf_iob_change_state(sirf_iob_t *iob, SIRF_IOB_STATE new_state);
+
+static __inline int sirf_iob_pack_8(unsigned char *cursor, unsigned char val)
+{
+ *cursor = val;
+
+ return 1;
+}
+
+static __inline int sirf_iob_unpack_8(unsigned char *cursor, unsigned char *val)
+{
+ *val = cursor[0];
+
+ return 1;
+}
+
+static __inline int sirf_iob_pack_16(unsigned char *cursor, unsigned short val)
+{
+ cursor[0] = (val >> 8) & 0xff;
+ cursor[1] = (val >> 0) & 0xff;
+
+ return 2;
+}
+
+static __inline int sirf_iob_unpack_16(unsigned char *cursor, unsigned short *val)
+{
+ *val = cursor[0] << 8;
+ *val |= cursor[1];
+
+ return 2;
+}
+
+static __inline int sirf_iob_pack_32(unsigned char *cursor, unsigned int val)
+{
+ cursor[0] = (val >> 24) & 0xff;
+ cursor[1] = (val >> 16) & 0xff;
+ cursor[2] = (val >> 8) & 0xff;
+ cursor[3] = (val >> 0) & 0xff;
+
+ return 4;
+}
+
+static __inline int sirf_iob_unpack_32(unsigned char *cursor, unsigned int *val)
+{
+ *val = cursor[0] << 24;
+ *val |= cursor[1] << 16;
+ *val |= cursor[2] << 8;
+ *val |= cursor[3];
+
+ return 4;
+}
+
+static __inline unsigned short sirf_iob_calc_cs(unsigned char *data, int len)
+{
+ unsigned short cs = 0;
+ int i;
+
+ for (i = 0; i < len; ++i)
+ cs += data[i];
+
+ cs &= 0x7FFF;
+
+ return cs;
+}
+
+static void sirf_iob_set_traffic_flag(sirf_iob_t *iob, unsigned int flag)
+{
+ sirf_iob_pal_lock(iob);
+ iob->traffic_flags |= flag;
+ sirf_iob_pal_unlock(iob);
+}
+
+static unsigned int sirf_iob_get_traffic_flag(sirf_iob_t *iob)
+{
+ unsigned int flag;
+
+ sirf_iob_pal_lock(iob);
+
+ flag = iob->traffic_flags;
+
+ sirf_iob_pal_unlock(iob);
+
+ return flag;
+}
+
+
+static void sirf_iob_report_gpio_event(sirf_iob_t *iob, int isout, unsigned int change_mask)
+{
+ unsigned char packet[64];
+ unsigned int sec, nsec;
+ unsigned char *cursor = packet;
+ unsigned int mask_in, mask_out;
+ unsigned short cs;
+ const unsigned short len = 28;
+ const int packet_len = len + 8;
+ unsigned int in, out;
+
+ in = out = 0;
+
+ in |= sirf_iob_pal_get_gpio_val(iob, SIRF_IOB_GPIO_DIN_1PPS) ? SIRF_IOB_GPIO_DIN_1PPS : 0;
+ in |= sirf_iob_pal_get_gpio_val(iob, SIRF_IOB_GPIO_DIN_DRI) ? SIRF_IOB_GPIO_DIN_DRI : 0;
+ in |= sirf_iob_pal_get_gpio_val(iob, SIRF_IOB_GPIO_DIN_WAKEUP) ? SIRF_IOB_GPIO_DIN_WAKEUP : 0;
+
+ out |= sirf_iob_pal_get_gpio_val(iob, SIRF_IOB_GPIO_DOUT_BOOTMODE1) ? SIRF_IOB_GPIO_DOUT_BOOTMODE1 : 0;
+ out |= sirf_iob_pal_get_gpio_val(iob, SIRF_IOB_GPIO_DOUT_BOOTMODE2) ? SIRF_IOB_GPIO_DOUT_BOOTMODE2 : 0;
+ out |= sirf_iob_pal_get_gpio_val(iob, SIRF_IOB_GPIO_DOUT_ONOFF) ? SIRF_IOB_GPIO_DOUT_ONOFF : 0;
+ out |= sirf_iob_pal_get_gpio_val(iob, SIRF_IOB_GPIO_DOUT_RESET) ? SIRF_IOB_GPIO_DOUT_RESET : 0;
+ out |= sirf_iob_pal_get_gpio_val(iob, SIRF_IOB_GPIO_DOUT_POWER) ? SIRF_IOB_GPIO_DOUT_POWER : 0;
+ out <<= 16;
+
+ sirf_iob_pal_get_timeofday(&sec, &nsec);
+
+ mask_in = mask_out = 0;
+ if (isout)
+ mask_out = change_mask;
+ else
+ mask_in = change_mask;
+
+ cursor += sirf_iob_pack_8(cursor, 0xA0);
+ cursor += sirf_iob_pack_8(cursor, 0xA2);
+
+ cursor += sirf_iob_pack_16(cursor, len); // length
+ cursor += sirf_iob_pack_8(cursor, 47); // pid
+ cursor += sirf_iob_pack_8(cursor, 11); // sid
+
+ cursor += sirf_iob_pack_16(cursor, 0); // seq id
+ cursor += sirf_iob_pack_32(cursor, mask_in);
+ cursor += sirf_iob_pack_32(cursor, mask_out);
+ cursor += sirf_iob_pack_32(cursor, in);
+ cursor += sirf_iob_pack_32(cursor, out);
+ cursor += sirf_iob_pack_32(cursor, sec); // time
+ cursor += sirf_iob_pack_32(cursor, nsec);
+
+ cs = sirf_iob_calc_cs(&packet[4], len);
+ cursor += sirf_iob_pack_16(cursor, cs);
+
+ cursor += sirf_iob_pack_8(cursor, 0xB0);
+ cursor += sirf_iob_pack_8(cursor, 0xB3);
+
+ sirf_iob_pal_put_to_host(iob, packet, packet_len);
+}
+
+
+static void sirf_iob_check_gpio_out_report(sirf_iob_t *iob, unsigned int mask, int val)
+{
+ unsigned int setting;
+
+ if (val)
+ setting = iob->gpio_report_mask.rising_out;
+ else
+ setting = iob->gpio_report_mask.falling_out;
+
+ if (setting & mask)
+ sirf_iob_report_gpio_event(iob, 1, mask);
+}
+
+static void sirf_iob_ctrl_onoff(sirf_iob_t *iob, int on)
+{
+ sirf_iob_pal_ctrl_onoff(iob, on);
+
+ if (on) {
+ if (iob->state->state != SIRF_IOB_STATE_RUNNING && iob->state->state != SIRF_IOB_STATE_PREWAKE)
+ sirf_iob_change_state(iob, SIRF_IOB_STATE_PREWAKE);
+ else
+ INFO("ONOFF is already triggered\n");
+ } else {
+ sirf_iob_change_state(iob, SIRF_IOB_STATE_HIBERNATE);
+ }
+
+ sirf_iob_check_gpio_out_report(iob, (SIRF_IOB_GPIO_DOUT_ONOFF << 16), on);
+}
+
+static void sirf_iob_ctrl_reset(sirf_iob_t *iob, int reset)
+{
+ sirf_iob_pal_ctrl_reset(iob, reset);
+
+ sirf_iob_check_gpio_out_report(iob, SIRF_IOB_GPIO_DOUT_RESET, reset);
+}
+
+static void sirf_iob_ctrl_poweron(sirf_iob_t *iob, int on)
+{
+ sirf_iob_pal_ctrl_poweron(iob, on);
+
+ sirf_iob_check_gpio_out_report(iob, SIRF_IOB_GPIO_DOUT_POWER, on);
+}
+
+static __inline void sirf_iob_reset_traffic_flags(sirf_iob_t *iob)
+{
+ sirf_iob_pal_lock(iob);
+ iob->traffic_flags = 0;
+ sirf_iob_pal_unlock(iob);
+}
+
+static __inline void sirf_iob_reset_xmit_fragment(sirf_iob_t *iob)
+{
+ iob->xmit_frag.state = 0;
+ iob->xmit_frag.cursor = 0;
+ iob->xmit_frag.len = 0;
+}
+
+
+static void sirf_iob_send_gpio_read_confirm(sirf_iob_t *iob, unsigned short seq)
+{
+ unsigned char packet[64];
+ unsigned int sec, nsec;
+ unsigned char *cursor = packet;
+ unsigned short cs;
+ const unsigned short len = 4;
+ const int packet_len = len + IOB_OSP_PACKET_CAPSULE_SIZE;
+
+ sirf_iob_pal_get_timeofday(&sec, &nsec);
+
+ cursor += sirf_iob_pack_8(cursor, 0xA0);
+ cursor += sirf_iob_pack_8(cursor, 0xA2);
+
+ cursor += sirf_iob_pack_16(cursor, len); // length
+ cursor += sirf_iob_pack_8(cursor, 47); // pid
+ cursor += sirf_iob_pack_8(cursor, 8); // sid
+
+ cursor += sirf_iob_pack_16(cursor, seq); // seq id
+
+ cs = sirf_iob_calc_cs(&packet[4], len);
+ cursor += sirf_iob_pack_16(cursor, cs);
+
+ cursor += sirf_iob_pack_8(cursor, 0xB0);
+ cursor += sirf_iob_pack_8(cursor, 0xB3);
+
+ sirf_iob_pal_put_to_host(iob, packet, packet_len);
+}
+
+static void sirf_iob_send_gpio_write_confirm(sirf_iob_t *iob, unsigned short seq, unsigned int mask, unsigned int out, unsigned int delay, unsigned int delay_nsec)
+{
+ unsigned char packet[64];
+ unsigned int sec, nsec;
+ unsigned char *cursor = packet;
+ unsigned short cs;
+ const unsigned short len = 20;
+ const int packet_len = len + IOB_OSP_PACKET_CAPSULE_SIZE;
+
+ sirf_iob_pal_get_timeofday(&sec, &nsec);
+
+ cursor += sirf_iob_pack_8(cursor, 0xA0);
+ cursor += sirf_iob_pack_8(cursor, 0xA2);
+
+ cursor += sirf_iob_pack_16(cursor, len); // length
+ //
+ cursor += sirf_iob_pack_8(cursor, 47); // pid
+ cursor += sirf_iob_pack_8(cursor, 9); // sid
+
+ cursor += sirf_iob_pack_16(cursor, seq); // seq id
+ cursor += sirf_iob_pack_32(cursor, mask);
+ cursor += sirf_iob_pack_32(cursor, out);
+ cursor += sirf_iob_pack_32(cursor, delay);
+ cursor += sirf_iob_pack_32(cursor, delay_nsec);
+
+ cs = sirf_iob_calc_cs(&packet[4], len);
+ cursor += sirf_iob_pack_16(cursor, cs);
+
+ cursor += sirf_iob_pack_8(cursor, 0xB0);
+ cursor += sirf_iob_pack_8(cursor, 0xB3);
+
+ sirf_iob_pal_put_to_host(iob, packet, packet_len);
+}
+
+static void sirf_iob_send_gpio_report_confirm(sirf_iob_t *iob, unsigned short seq, unsigned int rising_in, unsigned int rising_out, unsigned int falling_in, unsigned int falling_out)
+{
+ unsigned char packet[64];
+ unsigned int sec, nsec;
+ unsigned char *cursor = packet;
+ unsigned short cs;
+ const unsigned short len = 20;
+ const int packet_len = len + IOB_OSP_PACKET_CAPSULE_SIZE;
+
+ ENTER();
+
+ sirf_iob_pal_get_timeofday(&sec, &nsec);
+
+ cursor += sirf_iob_pack_8(cursor, 0xA0);
+ cursor += sirf_iob_pack_8(cursor, 0xA2);
+
+ cursor += sirf_iob_pack_16(cursor, len); // length
+ cursor += sirf_iob_pack_8(cursor, 47); // pid
+ cursor += sirf_iob_pack_8(cursor, 10); // sid
+
+ cursor += sirf_iob_pack_16(cursor, seq); // seq id
+ cursor += sirf_iob_pack_32(cursor, rising_in);
+ cursor += sirf_iob_pack_32(cursor, rising_out);
+ cursor += sirf_iob_pack_32(cursor, falling_in);
+ cursor += sirf_iob_pack_32(cursor, falling_out);
+
+ cs = sirf_iob_calc_cs(&packet[4], len);
+ cursor += sirf_iob_pack_16(cursor, cs);
+
+ cursor += sirf_iob_pack_8(cursor, 0xB0);
+ cursor += sirf_iob_pack_8(cursor, 0xB3);
+
+ sirf_iob_pal_put_to_host(iob, packet, packet_len);
+
+ EXIT();
+}
+
+static void sirf_iob_report_gpio(sirf_iob_t *iob)
+{
+ sirf_iob_report_gpio_event(iob, 0, 0);
+}
+
+static void sirf_iob_handle_extosp_gpio_read_req(sirf_iob_t *iob, unsigned char *data, int length)
+{
+ unsigned short seq;
+ unsigned char flag;
+ unsigned short interval;
+ unsigned int repeat;
+ unsigned char *cursor = data;
+
+ cursor += sirf_iob_unpack_16(cursor, &seq);
+ cursor += sirf_iob_unpack_8(cursor, &flag);
+ cursor += sirf_iob_unpack_16(cursor, &interval);
+ cursor += sirf_iob_unpack_32(cursor, &repeat);
+
+ if (flag & (1 << 1)) {
+ if (!interval || !repeat)
+ sirf_iob_report_gpio(iob);
+
+ // TODO : implement interval & repeat report
+ }
+
+ sirf_iob_send_gpio_read_confirm(iob, seq);
+}
+
+static void sirf_iob_handle_extosp_gpio_write_req(sirf_iob_t *iob, unsigned char *data, int length)
+{
+ unsigned char *cursor = data;
+ unsigned int mask, outval, delay, delay_nsec;
+ unsigned short seq;
+ int set;
+
+
+ cursor += sirf_iob_unpack_16(cursor, &seq);
+ cursor += sirf_iob_unpack_32(cursor, &mask);
+ cursor += sirf_iob_unpack_32(cursor, &outval);
+ cursor += sirf_iob_unpack_32(cursor, &delay);
+ cursor += sirf_iob_unpack_32(cursor, &delay_nsec);
+
+ if (!delay && !delay_nsec) {
+ if (mask & (SIRF_IOB_GPIO_DOUT_POWER << 16)) {
+ set = (outval & (SIRF_IOB_GPIO_DOUT_POWER << 16)) ? 1 : 0;
+ sirf_iob_ctrl_poweron(iob, set);
+ }
+
+ if (mask & (SIRF_IOB_GPIO_DOUT_RESET << 16)) {
+ set = (outval & (SIRF_IOB_GPIO_DOUT_RESET << 16)) ? 1 : 0;
+ sirf_iob_ctrl_reset(iob, set);
+ }
+
+ if (mask & (SIRF_IOB_GPIO_DOUT_ONOFF << 16)) {
+ set = (outval & (SIRF_IOB_GPIO_DOUT_ONOFF << 16)) ? 1 : 0;
+ sirf_iob_ctrl_onoff(iob, set);
+ }
+ } else {
+ // TODO : delayed GPIO writing
+ }
+
+ sirf_iob_send_gpio_write_confirm(iob, seq, mask, outval, delay, delay_nsec);
+}
+
+static void sirf_iob_handle_extosp_gpio_report_req(sirf_iob_t *iob, unsigned char *data, int length)
+{
+ unsigned char *cursor = data;
+ unsigned int rising_in, rising_out, falling_in, falling_out;
+ unsigned short seq;
+
+ seq = rising_in = rising_out = falling_in = falling_out = 0;
+ cursor += sirf_iob_unpack_16(cursor, &seq);
+ cursor += sirf_iob_unpack_32(cursor, &iob->gpio_report_mask.rising_in);
+ cursor += sirf_iob_unpack_32(cursor, &iob->gpio_report_mask.rising_out);
+ cursor += sirf_iob_unpack_32(cursor, &iob->gpio_report_mask.falling_in);
+ cursor += sirf_iob_unpack_32(cursor, &iob->gpio_report_mask.falling_out);
+
+ sirf_iob_send_gpio_report_confirm(iob, seq, \
+ iob->gpio_report_mask.rising_in, iob->gpio_report_mask.rising_out, \
+ iob->gpio_report_mask.falling_in, iob->gpio_report_mask.falling_out);
+}
+
+static int sirf_iob_handle_extosp(sirf_iob_t *iob)
+{
+ unsigned char *cursor = iob->xmit_frag.buf;
+ unsigned char pid, sid;
+ unsigned short length;
+
+ // skip A0 A2
+ cursor += 2;
+ cursor += sirf_iob_unpack_16(cursor, &length);
+ cursor += sirf_iob_unpack_8(cursor, &pid);
+ cursor += sirf_iob_unpack_8(cursor, &sid);
+
+ INFO("%s %dbytes, packetlen: %d\n", __FUNCTION__, iob->xmit_frag.len, length);
+ if (pid == 175) {
+ switch (sid) {
+ case 8:
+ sirf_iob_handle_extosp_gpio_read_req(iob, cursor, length);
+ break;
+ case 9:
+ sirf_iob_handle_extosp_gpio_write_req(iob, cursor, length);
+ break;
+ case 10:
+ sirf_iob_handle_extosp_gpio_report_req(iob, cursor, length);
+ break;
+ default:
+ break;
+ }
+ } else if (pid == 178) {
+ iob->use_dri += 10;
+ return 0;
+ } else {
+ return 0;
+ }
+
+ return 1;
+}
+
+static void sirf_iob_fill_idlepattern(char *buf, int from)
+{
+ int i;
+
+ for (i = from; i < SIRF_IOB_XMIT_BLOCK_SIZE; i += 2) {
+ buf[i] = 0xB4;
+ buf[i + 1] = 0xA7;
+ }
+}
+
+static __inline void sirf_iob_update_dec_state(sirf_iob_t *iob, unsigned char data)
+{
+ iob->dec_state.packet[iob->dec_state.packet_len++] = data;
+ ++iob->dec_state.stage;
+}
+
+static void sirf_iob_reset_dec_state(sirf_iob_t *iob)
+{
+ iob->dec_state.stage = IOB_OSP_DEC_SEARCH_A0;
+ iob->dec_state.packet_len = 0;
+ iob->dec_state.len_in_data = 0;
+}
+
+static int sirf_iob_filter_received_data(sirf_iob_t *iob, unsigned char *data, int len)
+{
+ int i;
+ int dataExist = 0;
+
+ for (i = 0; i < len; ++i) {
+ switch (iob->dec_state.stage) {
+ case IOB_OSP_DEC_SEARCH_A0:
+ if (*data == 0xA0)
+ sirf_iob_update_dec_state(iob, *data);
+ break;
+
+ case IOB_OSP_DEC_SEARCH_A2:
+ if (*data == 0xA2)
+ sirf_iob_update_dec_state(iob, *data);
+ else
+ sirf_iob_reset_dec_state(iob);
+ break;
+
+ case IOB_OSP_DEC_LENGTH_HIGH:
+ iob->dec_state.len_in_data = *data << 8;
+ sirf_iob_update_dec_state(iob, *data);
+ dataExist = 1;
+ break;
+
+ case IOB_OSP_DEC_LENGTH_LOW:
+ iob->dec_state.len_in_data |= *data;
+ sirf_iob_update_dec_state(iob, *data);
+ dataExist = 1;
+ break;
+
+ case IOB_OSP_DEC_BODY:
+ dataExist = 1;
+ if (*data == 0xB0) {
+ sirf_iob_update_dec_state(iob, *data);
+ } else {
+ iob->dec_state.packet[iob->dec_state.packet_len++] = *data;
+ }
+
+ break;
+
+ case IOB_OSP_DEC_FOUND_B0:
+ dataExist = 1;
+ iob->dec_state.packet[iob->dec_state.packet_len++] = *data;
+
+ if (*data != 0xB3) {
+ if (*data != 0xB0) {
+ iob->dec_state.stage = IOB_OSP_DEC_BODY;
+ }
+ } else {
+ iob->dec_state.locked = 1;
+
+ sirf_iob_pal_put_to_host(iob, iob->dec_state.packet, iob->dec_state.packet_len);
+ sirf_iob_reset_dec_state(iob);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ data++;
+ }
+
+ return dataExist;
+}
+
+
+static void sirf_iob_transfer_spi(sirf_iob_t *iob)
+{
+ sirf_iob_fill_idlepattern((char *)iob->xmit_frag.buf, iob->xmit_frag.len);
+
+ sirf_iob_pal_spi_exchange(iob, iob->xmit_frag.buf, iob->recv_frag.buf, SIRF_IOB_XMIT_BLOCK_SIZE);
+
+ if (sirf_iob_filter_received_data(iob, iob->recv_frag.buf, SIRF_IOB_XMIT_BLOCK_SIZE) > 0)
+ sirf_iob_set_traffic_flag(iob, IOB_TRAFFIC_RX);
+}
+
+static void sirf_iob_transfer_uart(sirf_iob_t *iob)
+{
+ if (sirf_iob_pal_stream_transmit(iob, iob->xmit_frag.buf, iob->xmit_frag.len) > 0)
+ sirf_iob_set_traffic_flag(iob, IOB_TRAFFIC_TX);
+}
+
+static void sirf_iob_handle_data_from_receiver_spi(sirf_iob_t *iob)
+{
+ sirf_iob_pal_spi_exchange(iob, iob->xmit_frag.dummy_buf, iob->recv_frag.buf, SIRF_IOB_XMIT_BLOCK_SIZE);
+
+ if (sirf_iob_filter_received_data(iob, iob->recv_frag.buf, SIRF_IOB_XMIT_BLOCK_SIZE) > 0)
+ sirf_iob_set_traffic_flag(iob, IOB_TRAFFIC_RX);
+}
+
+static void sirf_iob_handle_data_from_receiver_uart(sirf_iob_t *iob)
+{
+ int len;
+
+ len = sirf_iob_pal_stream_receive(iob, iob->recv_frag.buf, SIRF_IOB_XMIT_BLOCK_SIZE);
+
+ if (sirf_iob_filter_received_data(iob, iob->recv_frag.buf, len) > 0)
+ sirf_iob_set_traffic_flag(iob, IOB_TRAFFIC_RX);
+}
+
+
+static __inline int is_closing_mark(sirf_iob_t *iob)
+{
+ return (iob->xmit_frag.buf[iob->xmit_frag.cursor - 1] == 0xB3 && iob->xmit_frag.buf[iob->xmit_frag.cursor - 2] == 0xB0);
+}
+
+
+
+
+static int sirf_iob_handle_downstream_frag(sirf_iob_t *iob, unsigned char *buf, int len)
+{
+ int i;
+ int ret = 0;
+
+ for (i = 0; i < len; ++i) {
+ if (iob->xmit_frag.state != IOB_DSTRM_STATE_STORING) {
+ if (iob->xmit_frag.tmp_buf[i] == 0xA0) {
+ iob->xmit_frag.buf[iob->xmit_frag.cursor++] = buf[i];
+ iob->xmit_frag.state = IOB_DSTRM_STATE_STORING;
+ }
+ } else {
+ iob->xmit_frag.buf[iob->xmit_frag.cursor++] = buf[i];
+
+ if (is_closing_mark(iob) && (i + 1 == len || buf[i + 1] == 0xA0)) {
+ iob->xmit_frag.len = iob->xmit_frag.cursor;
+
+ ret += iob->state->downstream(iob);
+
+ iob->xmit_frag.state = IOB_DSTRM_STATE_CLOSE;
+ iob->xmit_frag.cursor = 0;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int sirf_iob_downstream(sirf_iob_t *iob)
+{
+ int len;
+ int ret;
+
+ ENTER();
+
+ len = sirf_iob_pal_get_from_host(iob, iob->xmit_frag.tmp_buf, SIRF_IOB_XMIT_BLOCK_SIZE);
+ ret = sirf_iob_handle_downstream_frag(iob, iob->xmit_frag.tmp_buf, len);
+
+ EXIT();
+
+ return ret;
+}
+
+static int sirf_iob_upstream(sirf_iob_t *iob)
+{
+ if (iob->state->upstream)
+ return iob->state->upstream(iob);
+ else
+ return -1;
+}
+
+static int sirf_iob_xfer_work(sirf_iob_t *iob)
+{
+ sirf_iob_reset_traffic_flags(iob);
+
+ sirf_iob_downstream(iob);
+
+ return sirf_iob_upstream(iob);
+}
+
+
+static void sirf_iob_change_state(sirf_iob_t *iob, SIRF_IOB_STATE new_state)
+{
+ if (iob->state) {
+ INFO("%s", iob->state->name);
+ if (iob->state->exit)
+ iob->state->exit(iob);
+ }
+
+ iob->state = iob->state_set[new_state];
+ INFO(" -> %s\n", iob->state->name);
+
+ if (iob->state->enter)
+ iob->state->enter(iob);
+}
+
+
+static void sirf_iob_unknown_enter(sirf_iob_t *iob)
+{
+ int onoff = sirf_iob_pal_get_gpio_val(iob, SIRF_IOB_GPIO_DOUT_ONOFF);
+ int reset = sirf_iob_pal_get_gpio_val(iob, SIRF_IOB_GPIO_DOUT_RESET);
+
+ if (!reset)
+ sirf_iob_change_state(iob, SIRF_IOB_STATE_RESET);
+ else if (!onoff)
+ sirf_iob_change_state(iob, SIRF_IOB_STATE_HIBERNATE);
+ else
+ sirf_iob_change_state(iob, SIRF_IOB_STATE_PREWAKE);
+}
+
+static void sirf_iob_prewake_enter(sirf_iob_t *iob)
+{
+ sirf_iob_pal_set_timer(iob, SIRF_IOB_TIMER_POLL, 400);
+}
+
+static void sirf_iob_running_enter(sirf_iob_t *iob)
+{
+ sirf_iob_pal_set_timer(iob, SIRF_IOB_TIMER_POLL, 50);
+}
+
+static void sirf_iob_running_uart_enter(sirf_iob_t *iob)
+{
+ iob->uart_speed_index = -1;
+
+ sirf_iob_pal_set_timer(iob, SIRF_IOB_TIMER_POLL, 50);
+ sirf_iob_pal_set_timer(iob, SIRF_IOB_TIMER_PROTO_SEARCH, 1000);
+}
+
+static int sirf_iob_evt_hibernate_handler(sirf_iob_t *iob, SIRF_IOB_INTEVT evt, void *parm)
+{
+ sirf_iob_evt_gpio_changed *gpio;
+
+ ENTER();
+
+ switch (evt) {
+ case SIRF_IOB_EVENT_IO_INITIATE:
+ sirf_iob_xfer_work(iob);
+ break;
+
+ case SIRF_IOB_EVENT_GPIO_CHANGED:
+ gpio = (sirf_iob_evt_gpio_changed *)parm;
+ if ((gpio->gpio & SIRF_IOB_GPIO_DOUT_ONOFF) && gpio->val > 0)
+ sirf_iob_change_state(iob, SIRF_IOB_STATE_PREWAKE);
+ break;
+
+ default:
+ break;
+ }
+
+ EXIT();
+ return 0;
+}
+
+
+static int sirf_iob_evt_prewake_handler(sirf_iob_t *iob, SIRF_IOB_INTEVT evt, void *parm)
+{
+ sirf_iob_evt_gpio_changed *gpio;
+
+ switch (evt) {
+ case SIRF_IOB_EVENT_POLL_TIMER_EXPIRED:
+ sirf_iob_change_state(iob, SIRF_IOB_STATE_RUNNING);
+ break;
+
+ case SIRF_IOB_EVENT_IO_INITIATE:
+ sirf_iob_xfer_work(iob);
+ break;
+
+ case SIRF_IOB_EVENT_GPIO_CHANGED:
+ gpio = (sirf_iob_evt_gpio_changed *)parm;
+
+ if ((gpio->gpio & SIRF_IOB_GPIO_DOUT_ONOFF) && gpio->val == 0)
+ sirf_iob_change_state(iob, SIRF_IOB_STATE_HIBERNATE);
+
+ if ((gpio->gpio & SIRF_IOB_GPIO_DOUT_RESET) && gpio->val == 0)
+ sirf_iob_change_state(iob, SIRF_IOB_STATE_RESET);
+ break;
+
+ default:
+ // rewind timer
+ break;
+ }
+
+ return 0;
+}
+
+
+static int sirf_iob_evt_running_handler(sirf_iob_t *iob, SIRF_IOB_INTEVT evt, void *parm)
+{
+ sirf_iob_evt_gpio_changed *gpio;
+
+ switch (evt) {
+ case SIRF_IOB_EVENT_POLL_TIMER_EXPIRED:
+ case SIRF_IOB_EVENT_IO_INITIATE:
+ sirf_iob_xfer_work(iob);
+ sirf_iob_pal_set_timer(iob, SIRF_IOB_TIMER_POLL, iob->state->waittime(iob));
+ break;
+
+ case SIRF_IOB_EVENT_PROTO_TIMER_EXPIRED:
+ ++iob->uart_speed_index;
+ if (iob->uart_speed_index >= (int)ARRAY_SIZE(uart_speed_table))
+ return -1;
+
+ sirf_iob_pal_change_speed(iob, uart_speed_table[iob->uart_speed_index]);
+
+ sirf_iob_pal_set_timer(iob, SIRF_IOB_TIMER_PROTO_SEARCH, 1000);
+ break;
+
+ case SIRF_IOB_EVENT_GPIO_CHANGED:
+ gpio = (sirf_iob_evt_gpio_changed *)parm;
+
+ if ((gpio->gpio & SIRF_IOB_GPIO_DOUT_ONOFF) && gpio->val == 0)
+ sirf_iob_change_state(iob, SIRF_IOB_STATE_HIBERNATE);
+
+ if ((gpio->gpio & SIRF_IOB_GPIO_DOUT_RESET) && gpio->val == 0)
+ sirf_iob_change_state(iob, SIRF_IOB_STATE_RESET);
+ break;
+
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+
+
+static int sirf_iob_downstream_generic_handler(sirf_iob_t *iob)
+{
+ return sirf_iob_handle_extosp(iob);
+}
+
+static int sirf_iob_downstream_running_spi_handler(sirf_iob_t *iob)
+{
+ if (!sirf_iob_handle_extosp(iob))
+ sirf_iob_transfer_spi(iob);
+
+ return 0;
+}
+
+static int sirf_iob_downstream_running_uart_handler(sirf_iob_t *iob)
+{
+ if (!sirf_iob_handle_extosp(iob))
+ sirf_iob_transfer_uart(iob);
+
+ return 0;
+}
+
+static int sirf_iob_upstream_generic_handler(sirf_iob_t *iob)
+{
+ return 0;
+}
+
+static int sirf_iob_upstream_running_spi_handler(sirf_iob_t *iob)
+{
+ unsigned int flag = sirf_iob_get_traffic_flag(iob);
+
+ if (!(flag & IOB_TRAFFIC_TX))
+ sirf_iob_handle_data_from_receiver_spi(iob);
+
+ return 0;
+}
+
+static int sirf_iob_upstream_running_uart_handler(sirf_iob_t *iob)
+{
+ sirf_iob_handle_data_from_receiver_uart(iob);
+
+ if (sirf_iob_get_traffic_flag(iob) && IOB_TRAFFIC_RX)
+ sirf_iob_pal_set_timer(iob, SIRF_IOB_TIMER_PROTO_SEARCH, 0); // cancel timer
+
+ return 0;
+}
+
+static int sirf_iob_hibernate_waittime(sirf_iob_t *iob)
+{
+ return 1000;
+}
+
+static int sirf_iob_prewake_waittime(sirf_iob_t *iob)
+{
+ unsigned int sec, nsec;
+
+ sirf_iob_pal_get_timeofday(&sec, &nsec);
+
+ return 0;
+}
+
+static int sirf_iob_running_uart_waittime(sirf_iob_t *iob)
+{
+ return 1;
+}
+
+static int sirf_iob_running_spi_waittime(sirf_iob_t *iob)
+{
+ int wait = 100;
+
+ sirf_iob_pal_lock(iob);
+
+ if (iob->traffic_flags & (IOB_TRAFFIC_RX | IOB_TRAFFIC_TX))
+ wait = 1;
+ else if (iob->use_dri > IOB_DRI_SENSE_TRIGGER_NUM) {
+ if (sirf_iob_pal_get_gpio_val(iob, SIRF_IOB_GPIO_DIN_DRI) > 0)
+ wait = 1;
+ else
+ wait = 800;
+ }
+
+ sirf_iob_pal_unlock(iob);
+
+ return wait;
+}
+
+
+static void sirf_iob_poll_timer_handler(void *arg)
+{
+ sirf_iob_t *iob = (sirf_iob_t *)arg;
+
+ sirf_iob_pal_send_event(iob, SIRF_IOB_EVENT_POLL_TIMER_EXPIRED, 0, 0);
+}
+
+static void sirf_iob_protocol_timer_handler(void *arg)
+{
+ sirf_iob_t *iob = (sirf_iob_t *)arg;
+
+ sirf_iob_pal_send_event(iob, SIRF_IOB_EVENT_PROTO_TIMER_EXPIRED, 0, 0);
+}
+
+static void *sirf_iob_io_thread(void *parm)
+{
+ sirf_iob_t *iob = (sirf_iob_t *)parm;
+ int event;
+ static unsigned char msgbuf[512];
+ int block = 1;
+ int loop = 1;
+
+ sirf_iob_pal_lock(iob);
+ iob->task_alive = 1;
+ sirf_iob_pal_unlock(iob);
+
+#ifdef __KERNEL__
+ loop = 0;
+#endif
+ while (loop)
+ {
+ sirf_iob_pal_wait_event(iob, (unsigned int *)&event, msgbuf, 512, block);
+
+ if (event == SIRF_IOB_EVENT_TIMEOUT)
+ break;
+ else if (event == SIRF_IOB_EVENT_STOP) {
+ DEBUG("stop event received\n");
+ block = 0;
+ } else if (event == SIRF_IOB_EVENT_ERR)
+ ERR("fail to wait event\n");
+ else
+ iob->state->handler(iob, event, msgbuf);
+ }
+
+ sirf_iob_pal_lock(iob);
+ iob->task_alive = 0;
+ sirf_iob_pal_unlock(iob);
+
+ return 0;
+}
+
+
+
+
+/* exported API */
+void sirf_iob_init(sirf_iob_t *iob, sirf_iob_init_t init_data)
+{
+ memset(iob, 0, sizeof(sirf_iob_t));
+
+ sirf_iob_fill_idlepattern((char *)iob->xmit_frag.dummy_buf, 0);
+
+ switch (init_data.phy_type) {
+ case SIRF_IOB_PHY_UART:
+ iob->state_set = uart_state;
+ break;
+ case SIRF_IOB_PHY_I2C:
+ break;
+ case SIRF_IOB_PHY_SPI:
+ iob->state_set = spi_state;
+ break;
+ default:
+ break;
+ }
+
+ sirf_iob_pal_init(iob, &init_data);
+
+ sirf_iob_pal_create_timer(iob, SIRF_IOB_TIMER_POLL, sirf_iob_poll_timer_handler, iob);
+ sirf_iob_pal_create_timer(iob, SIRF_IOB_TIMER_PROTO_SEARCH, sirf_iob_protocol_timer_handler, iob);
+}
+
+void sirf_iob_open(sirf_iob_t *iob)
+{
+ int alive = 0;
+
+ sirf_iob_change_state(iob, SIRF_IOB_STATE_UNKNOWN);
+
+ sirf_iob_pal_start_task(iob, sirf_iob_io_thread, (void *)iob);
+
+ do {
+ sirf_iob_pal_msleep(1);
+
+ sirf_iob_pal_lock(iob);
+ alive = iob->task_alive;
+ sirf_iob_pal_unlock(iob);
+ } while (!alive);
+}
+
+void sirf_iob_close(sirf_iob_t *iob)
+{
+ int alive = 0;
+
+ ENTER();
+
+ sirf_iob_pal_send_event(iob, SIRF_IOB_EVENT_STOP, 0, 0);
+
+ do {
+ sirf_iob_pal_msleep(1);
+
+ sirf_iob_pal_lock(iob);
+ alive = iob->task_alive;
+ sirf_iob_pal_unlock(iob);
+ } while (alive);
+
+ sirf_iob_pal_deinit(iob);
+ EXIT();
+}
+
+void sirf_iob_gpio_input_isr(sirf_iob_t *iob, unsigned int ionum, int val)
+{
+ if (ionum == SIRF_IOB_GPIO_DIN_DRI) {
+ if (val) {
+ ++iob->use_dri;
+ sirf_iob_pal_schedule_now(iob);
+ }
+ }
+
+ if (val) {
+ if (iob->gpio_report_mask.rising_in & ionum)
+ sirf_iob_report_gpio_event(iob, 0, ionum);
+ } else {
+ if (iob->gpio_report_mask.falling_in & ionum)
+ sirf_iob_report_gpio_event(iob, 0, ionum);
+ }
+}
+
diff --git a/source/sirf_iob_debug.c b/source/sirf_iob_debug.c
new file mode 100644
index 0000000..925333c
--- /dev/null
+++ b/source/sirf_iob_debug.c
@@ -0,0 +1,95 @@
+/*
+ Copyright (c) 2015, The Linux Foundation. All rights reserved.
+
+ This library is dual licensed. If it is used to create a linux driver, it is
+ licensed under the GPL. If it used to create a usermode driver, the library
+ is licensed under the terms of the license agreement for the usermode driver.
+*/
+
+
+#include <stdarg.h>
+#include "sirf_iob_debug.h"
+
+#ifdef OS_ANDROID
+#include <android/log.h>
+#define TAG_IOB "sirf_iob"
+#endif
+
+static int log_level = SIRF_IOB_LOG_LVL_INFO;
+static SIRF_IOB_LOG_TYPE log_type;
+static FILE *log_file;
+static const char *log_name = "iob.log";
+char log_buf[1024];
+
+int sirf_iob_init_log(SIRF_IOB_LOG_TYPE type, const char *name)
+{
+ log_type = type;
+ if (log_type == SIRF_IOB_LOG_FILE) {
+ if (name != NULL)
+ log_name = name;
+
+ log_file = fopen(log_name, "w");
+ if (log_file == 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+void sirf_iob_deinit_log(void)
+{
+ fclose(log_file);
+}
+
+void sirf_iob_set_log_level(int level)
+{
+ log_level = level;
+}
+
+void sirf_iob_dbg_err(int line, const char *file, char *fmt, ...)
+{
+ va_list arg;
+ int count;
+
+ if (log_level >= SIRF_IOB_LOG_LVL_ERR) {
+ count = sprintf(log_buf, "line %d, %s ", line, file);
+
+ va_start(arg, fmt);
+ count += vsprintf(&log_buf[count], fmt, arg);
+ va_end(arg);
+
+ if (log_type == SIRF_IOB_LOG_FILE) {
+ fwrite(log_buf, 1, count, log_file);
+ } else {
+#ifdef OS_ANDROID
+ __android_log_print(ANDROID_LOG_ERROR, TAG_IOB, "%s", log_buf);
+#else
+ puts(log_buf);
+#endif
+ }
+ }
+}
+
+void sirf_iob_dbg_log(int level, char *fmt, ...)
+{
+ va_list arg;
+ int count;
+
+ if (log_level >= level) {
+ va_start(arg, fmt);
+ count = vsprintf(log_buf, fmt, arg);
+ va_end(arg);
+
+ if (log_type == SIRF_IOB_LOG_FILE) {
+ fwrite(log_buf, 1, count, log_file);
+ } else {
+#ifdef OS_ANDROID
+ __android_log_print(ANDROID_LOG_VERBOSE, TAG_IOB, "%s", log_buf);
+#else
+ printf("%s", log_buf);
+#endif
+ }
+ }
+}
+
+