summaryrefslogtreecommitdiff
path: root/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-gtm501l-driver-1.2.patch
diff options
context:
space:
mode:
authorSaul Wold <Saul.Wold@intel.com>2010-09-24 15:36:24 -0700
committerSaul Wold <Saul.Wold@intel.com>2010-09-24 16:43:21 -0700
commit239a368d5715d8f5b7733f9400339c2350c49369 (patch)
tree2953f12b45e590d9e14b6f72f8e4ee7188e41508 /meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-gtm501l-driver-1.2.patch
parentc5b9525263dac6844d152e40acf8cee4d27b60bc (diff)
downloadopenembedded-core-239a368d5715d8f5b7733f9400339c2350c49369.tar.gz
openembedded-core-239a368d5715d8f5b7733f9400339c2350c49369.tar.bz2
openembedded-core-239a368d5715d8f5b7733f9400339c2350c49369.tar.xz
openembedded-core-239a368d5715d8f5b7733f9400339c2350c49369.zip
netbook: Correct netbook build by moving netbook configuration from moblin to meta
Signed-off-by: Saul Wold <Saul.Wold@intel.com>
Diffstat (limited to 'meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-gtm501l-driver-1.2.patch')
-rw-r--r--meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-gtm501l-driver-1.2.patch2395
1 files changed, 0 insertions, 2395 deletions
diff --git a/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-gtm501l-driver-1.2.patch b/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-gtm501l-driver-1.2.patch
deleted file mode 100644
index 206e49ed6..000000000
--- a/meta-moblin/packages/linux/linux-moblin-2.6.33.2/linux-2.6.34-moorestown-gtm501l-driver-1.2.patch
+++ /dev/null
@@ -1,2395 +0,0 @@
-Index: linux-2.6.33/drivers/spi/Kconfig
-===================================================================
---- linux-2.6.33.orig/drivers/spi/Kconfig
-+++ linux-2.6.33/drivers/spi/Kconfig
-@@ -335,6 +335,10 @@ config SPI_DW_PCI
- #
- comment "SPI Protocol Masters"
-
-+config SPI_MRST_GTM501
-+ tristate "SPI protocol driver for GTM501l"
-+ depends on SPI_MRST
-+
- config SPI_SPIDEV
- tristate "User mode SPI device driver support"
- depends on EXPERIMENTAL
-Index: linux-2.6.33/drivers/spi/Makefile
-===================================================================
---- linux-2.6.33.orig/drivers/spi/Makefile
-+++ linux-2.6.33/drivers/spi/Makefile
-@@ -43,6 +43,7 @@ obj-$(CONFIG_SPI_SH_MSIOF) += spi_sh_ms
- obj-$(CONFIG_SPI_STMP3XXX) += spi_stmp.o
- obj-$(CONFIG_SPI_NUC900) += spi_nuc900.o
- obj-$(CONFIG_SPI_MRST) += mrst_spi.o
-+obj-$(CONFIG_SPI_MRST_GTM501) += gtm501l_spi.o
-
- # special build for s3c24xx spi driver with fiq support
- spi_s3c24xx_hw-y := spi_s3c24xx.o
-Index: linux-2.6.33/drivers/spi/gtm501l_spi.c
-===================================================================
---- /dev/null
-+++ linux-2.6.33/drivers/spi/gtm501l_spi.c
-@@ -0,0 +1,2029 @@
-+/****************************************************************************
-+ *
-+ * Driver for the Option GTM501L spi modem.
-+ *
-+ * Copyright (C) 2008 Option International
-+ * Copyright (C) 2008 Filip Aben <f.aben@option.com>
-+ * Denis Joseph Barrow <d.barow@option.com>
-+ * Jan Dumon <j.dumon@option.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
-+ * USA
-+ *
-+ *
-+ *
-+ *****************************************************************************/
-+
-+#include <linux/version.h>
-+#include <linux/module.h>
-+#include <linux/tty.h>
-+#include <linux/device.h>
-+#include <linux/spi/spi.h>
-+#include <linux/tty.h>
-+#include <linux/kfifo.h>
-+#include <linux/tty_flip.h>
-+#include <linux/workqueue.h>
-+#include <linux/timer.h>
-+
-+#include <linux/interrupt.h>
-+#include <linux/irq.h>
-+#include <linux/rfkill.h>
-+#include <linux/netdevice.h>
-+#include <linux/inetdevice.h>
-+#include <linux/skbuff.h>
-+#include <net/arp.h>
-+#include <linux/ip.h>
-+#include <linux/dmapool.h>
-+#include <linux/gpio.h>
-+#include <linux/sysfs.h>
-+
-+#include <asm/ipc_defs.h>
-+
-+#ifdef CONFIG_DEBUG_FS
-+#include <linux/debugfs.h>
-+#include <linux/ktime.h>
-+#include <linux/spinlock.h>
-+#endif
-+
-+#include "gtm501l_spi.h"
-+#include <linux/spi/mrst_spi.h>
-+
-+/* various static variables */
-+static struct tty_driver *tty_drv;
-+static struct ktermios *gtm501l_termios[GTM501L_MAX_MINORS];
-+static struct ktermios *gtm501l_termios_locked[GTM501L_MAX_MINORS];
-+static struct lock_class_key gtm501l_key;
-+static struct gtm501l_port_data *gtm501l_serial_ports[GTM501L_MAX_MINORS];
-+
-+/* Default port spec */
-+static struct gtm501l_port_spec gtm501l_default_port_spec[] = {
-+ { 1, GTM501L_PORT_SPEC_SERIAL, "Control" }, /* 0 */
-+ { 1, GTM501L_PORT_SPEC_SERIAL, "NetAT" }, /* 1 */
-+ { 1, GTM501L_PORT_SPEC_NET, "NetIP" }, /* 2 */
-+ { 1, GTM501L_PORT_SPEC_SERIAL, "App" }, /* 3 */
-+ { 1, GTM501L_PORT_SPEC_SERIAL, "App2" }, /* 4 */
-+ { 1, GTM501L_PORT_SPEC_SERIAL, "PC/SC" }, /* 5 */
-+ { 1, GTM501L_PORT_SPEC_SERIAL, "Modem" }, /* 6 */
-+ { 1, GTM501L_PORT_SPEC_SERIAL, "Diag" }, /* 7 */
-+ { 1, GTM501L_PORT_SPEC_SERIAL, "Logger" }, /* 8 */
-+ { 0, GTM501L_PORT_SPEC_SERIAL, "" }, /* 9 */
-+ { 1, GTM501L_PORT_SPEC_NET, "NetIP2" }, /* 10 */
-+ { 0, GTM501L_PORT_SPEC_SERIAL, "" }, /* 11 */
-+ { 0, GTM501L_PORT_SPEC_SERIAL, "" }, /* 12 */
-+ { 0, GTM501L_PORT_SPEC_SERIAL, "" }, /* 13 */
-+ { 0, GTM501L_PORT_SPEC_SERIAL, "" }, /* 14 */
-+ { 0, GTM501L_PORT_SPEC_SERIAL, "" }, /* 15 */
-+};
-+
-+/* Module load parameter */
-+static int gpio_in = -1; /* GPIO interrupt input assignment, set default to -1 */
-+static int backoff_enabled = 1; /* Enable the backoff timer */
-+static int spi_b16 = 1; /* Enable 16bit SPI word length, otherwise use 8bit SPI word length */
-+int gtm501l_debug = 0;
-+
-+/* temp debug variables */
-+static int spi_err_count = 0;
-+static unsigned int total_tty_write = 0;
-+static unsigned int total_spi_write = 0;
-+
-+static unsigned char scratch_buf[GTM501L_TRANSFER_SIZE];
-+
-+static int reset_state = 1;
-+
-+/* prototype declarations */
-+static void gtm501l_push_skb(struct gtm501l_port_data *port_data);
-+static void gtm501l_net_init(struct net_device *net);
-+static void gtm501l_spi_complete(void *ctx);
-+static void _gtm501l_set_termios(struct tty_struct *tty, struct ktermios *old);
-+static void gtm501l_throttle(struct tty_struct *tty);
-+static void gtm501l_create_ports(struct gtm501l_device *gtm_dev,
-+ struct gtm501l_port_spec *specs);
-+/*static void gtm501l_pmic_init_voltages( void );*/
-+static void gtm501l_pmic_set_wwanresetn( unsigned char level );
-+static void gtm501l_pmic_set_wwandisablen( unsigned char level );
-+
-+void gtm501l_debug_printk(const char *function, int line, char *format, ...) {
-+ va_list args;
-+ int len;
-+ char buffer[255];
-+
-+ len = snprintf(buffer, 255, DRVNAME " [%s:%d] ", function, line);
-+
-+ va_start(args, format);
-+ vsnprintf(buffer + len, 255 - len, format, args);
-+ va_end(args);
-+
-+ printk("%s", buffer);
-+}
-+
-+#define __bswap_16(x) \
-+ (__extension__ \
-+ ({ register unsigned short int __v, __x = (x); \
-+ __asm__ ("rorw $8, %w0" \
-+ : "=r" (__v) \
-+ : "0" (__x) \
-+ : "cc"); \
-+ __v; }))
-+
-+static inline void swap_buf(u16 *buf, int len) {
-+ int n;
-+ len = (len + 1) / 2;
-+ n = (len + 7) / 8;
-+ switch (len % 8) {
-+ case 0: do { *buf = __bswap_16(*buf); buf++;
-+ case 7: *buf = __bswap_16(*buf); buf++;
-+ case 6: *buf = __bswap_16(*buf); buf++;
-+ case 5: *buf = __bswap_16(*buf); buf++;
-+ case 4: *buf = __bswap_16(*buf); buf++;
-+ case 3: *buf = __bswap_16(*buf); buf++;
-+ case 2: *buf = __bswap_16(*buf); buf++;
-+ case 1: *buf = __bswap_16(*buf); buf++;
-+ } while (--n > 0);
-+ }
-+}
-+
-+#ifdef CONFIG_DEBUG_FS
-+
-+static ssize_t gtm501l_read_gpio(struct file *file, char __user *user_buf, size_t count, loff_t *ppos)
-+{
-+ char buf[32];
-+ unsigned int len = 0;
-+ if (gpio_in >= 0) {
-+ len += snprintf(buf+len, sizeof(buf)-len,
-+ "GPIO%d = %d\n", gpio_in, (gpio_get_value(gpio_in))?1:0);
-+ } else {
-+ len += snprintf(buf+len, sizeof(buf)-len,
-+ "GPIO unuse\n");
-+ }
-+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-+}
-+
-+static struct file_operations gtm501l_gpio_operations = {
-+ .owner = THIS_MODULE,
-+ .read = gtm501l_read_gpio,
-+};
-+
-+static ssize_t gtm501l_read_pmic(struct file *file, char __user *user_buf, size_t count, loff_t *ppos)
-+{
-+ char buf[8];
-+ unsigned int len = sprintf(buf, "%d\n", reset_state);
-+
-+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
-+}
-+
-+static ssize_t gtm501l_write_pmic(struct file *file, const char __user *user, size_t count, loff_t *offset)
-+{
-+ reset_state = simple_strtoul(user, NULL, 0);
-+ gtm501l_pmic_set_wwanresetn( reset_state );
-+ gtm501l_pmic_set_wwandisablen( reset_state );
-+ return count;
-+}
-+
-+static struct file_operations gtm501l_pmic_operations = {
-+ .owner = THIS_MODULE,
-+ .read = gtm501l_read_pmic,
-+ .write = gtm501l_write_pmic,
-+};
-+
-+/**
-+ * gtm501l_debugfs_init generates all debugfs file nodes.
-+ * It initialized the frame statistic structure.
-+ */
-+static int gtm501l_debugfs_init(struct gtm501l_device *gtm_dev)
-+{
-+ gtm_dev->debugfs = debugfs_create_dir("gtm501l", NULL);
-+ if (!gtm_dev->debugfs)
-+ return -ENOMEM;
-+
-+ debugfs_create_file("gpio", S_IFREG | S_IRUGO,
-+ gtm_dev->debugfs, NULL, &gtm501l_gpio_operations);
-+ debugfs_create_file("pmic", S_IFREG | S_IRUGO,
-+ gtm_dev->debugfs, NULL, &gtm501l_pmic_operations);
-+ debugfs_create_u32("backoff_timer", S_IFREG | S_IRUGO,
-+ gtm_dev->debugfs, &backoff_enabled);
-+ debugfs_create_x32("flags", S_IFREG | S_IRUGO,
-+ gtm_dev->debugfs, (unsigned int *)&gtm_dev->flags);
-+#ifdef DEBUG
-+ debugfs_create_x32("debug", S_IFREG | S_IRUGO,
-+ gtm_dev->debugfs, &gtm501l_debug);
-+#endif
-+
-+ return 0;
-+}
-+
-+static void gtm501l_debugfs_remove(struct gtm501l_device *gtm_dev)
-+{
-+ if (gtm_dev->debugfs)
-+ debugfs_remove_recursive(gtm_dev->debugfs);
-+}
-+#endif
-+
-+static __be32 gtm501l_get_ip_addr(struct net_device *net)
-+{
-+ struct in_device *in_dev;
-+
-+ if ((in_dev = __in_dev_get_rtnl(net)) != NULL) {
-+ if(in_dev->ifa_list) {
-+ return in_dev->ifa_list->ifa_local;
-+ }
-+ }
-+
-+ return 0;
-+}
-+
-+/*
-+static void gtm501l_pmic_init_voltages( void )
-+{
-+ struct ipc_pmic_reg_data reg_data;
-+
-+ reg_data.num_entries = 3;
-+
-+ // Set VDDQCNT
-+
-+ reg_data.pmic_reg_data[0].register_address = 0x037;
-+ reg_data.pmic_reg_data[0].value = 0x07;
-+
-+ // Set YMX3GDCNT
-+
-+ reg_data.pmic_reg_data[1].register_address = 0x03c;
-+ reg_data.pmic_reg_data[1].value = 0x47;
-+
-+ // Set CLKOUT
-+
-+ reg_data.pmic_reg_data[2].register_address = 0x021;
-+ reg_data.pmic_reg_data[2].value = 0x00;
-+ ipc_pmic_register_write(&reg_data, 0);
-+
-+}
-+*/
-+
-+static void gtm501l_pmic_set_wwanresetn( unsigned char level )
-+{
-+ struct ipc_pmic_mod_reg_data mod_reg_data;
-+
-+ // WWAN_RESET_N is connected to COMMS_GPO5
-+
-+ mod_reg_data.num_entries = 1;
-+ mod_reg_data.pmic_mod_reg_data[0].bit_map = 0x20;
-+ mod_reg_data.pmic_mod_reg_data[0].register_address = 0x0f4;
-+
-+ if (level)
-+ {
-+ mod_reg_data.pmic_mod_reg_data[0].value = 0x20;
-+ }
-+ else
-+ {
-+ mod_reg_data.pmic_mod_reg_data[0].value = 0x00;
-+ }
-+
-+ ipc_pmic_register_read_modify(&mod_reg_data);
-+}
-+
-+static void gtm501l_pmic_set_wwandisablen( unsigned char level )
-+{
-+ struct ipc_pmic_mod_reg_data mod_reg_data;
-+
-+ // WWAN_DISABLE_N is connected to COMMS_GPO0
-+
-+ mod_reg_data.num_entries = 1;
-+ mod_reg_data.pmic_mod_reg_data[0].bit_map = 0x01;
-+ mod_reg_data.pmic_mod_reg_data[0].register_address = 0x0f4;
-+
-+ if (level)
-+ {
-+ mod_reg_data.pmic_mod_reg_data[0].value = 0x01;
-+ }
-+ else
-+ {
-+ mod_reg_data.pmic_mod_reg_data[0].value = 0x00;
-+ }
-+
-+ ipc_pmic_register_read_modify(&mod_reg_data);
-+}
-+
-+
-+static void gtm501l_rx_netchar(struct gtm501l_net *gtm_net,
-+ unsigned char *in_buf, int size)
-+{
-+ struct net_device *net = gtm_net->net;
-+ unsigned int temp_bytes;
-+ unsigned int buffer_offset = 0, n;
-+ unsigned int frame_len;
-+ unsigned char *tmp_rx_buf;
-+ unsigned char c;
-+ int header_invalid;
-+
-+ while(size) {
-+ switch (gtm_net->rx_state) {
-+ case WAIT_IP:
-+ /* waiting for IP header. */
-+ /* wanted bytes - size of ip header */
-+ temp_bytes = (size < gtm_net->rx_buf_missing) ?
-+ size : gtm_net->rx_buf_missing;
-+
-+ memcpy(((unsigned char *)(&gtm_net->rx_ip_hdr)) +
-+ gtm_net->rx_buf_size, in_buf + buffer_offset,
-+ temp_bytes);
-+
-+ gtm_net->rx_buf_size += temp_bytes;
-+ buffer_offset += temp_bytes;
-+ gtm_net->rx_buf_missing -= temp_bytes;
-+ size -= temp_bytes;
-+
-+ if (!gtm_net->rx_buf_missing) {
-+ /* header is complete allocate an sk_buffer and
-+ * continue to WAIT_DATA */
-+
-+ header_invalid = 0;
-+
-+ frame_len = ntohs(gtm_net->rx_ip_hdr.tot_len);
-+ if ((frame_len > GTM501L_DEFAULT_MRU) ||
-+ (frame_len < sizeof(struct iphdr))) {
-+ if(!gtm_net->sync_lost)
-+ dev_err(&net->dev,
-+ "Invalid frame length (%d)\n",
-+ frame_len);
-+ header_invalid = 1;
-+ }
-+
-+ /* Validate destination address */
-+ if (!header_invalid &&
-+ (gtm501l_get_ip_addr(net) != gtm_net->rx_ip_hdr.daddr)) {
-+ if(!gtm_net->sync_lost)
-+ dev_err(&net->dev,
-+ "Not our address (" NIPQUAD_FMT ")\n",
-+ NIPQUAD(gtm_net->rx_ip_hdr.daddr));
-+ header_invalid = 1;
-+ }
-+
-+ if (header_invalid) {
-+ /* This header is not valid, roll back
-+ * for sizeof(header) bytes - 1 and
-+ * wait for sync */
-+ gtm_net->rx_state = WAIT_SYNC;
-+ n = min(buffer_offset,
-+ sizeof(struct iphdr) - 1);
-+ buffer_offset -= n;
-+ size += n;
-+ continue;
-+ }
-+
-+ /* Allocate an sk_buff */
-+ gtm_net->rx_skb = dev_alloc_skb(frame_len);
-+ if (!gtm_net->rx_skb) {
-+ /* We got no receive buffer. */
-+ //D1("ddcould not allocate memory");
-+ gtm_net->rx_state = WAIT_SYNC;
-+ return;
-+ }
-+
-+ if(gtm_net->sync_lost) {
-+ dev_info(&net->dev, "Back in sync. (%d stray bytes)\n",
-+ gtm_net->sync_lost);
-+ gtm_net->sync_lost = 0;
-+ }
-+
-+ /* Here's where it came from */
-+ gtm_net->rx_skb->dev = net;
-+
-+ /* Copy what we got so far. make room for iphdr
-+ * after tail. */
-+ tmp_rx_buf =
-+ skb_put(gtm_net->rx_skb,
-+ sizeof(struct iphdr));
-+ memcpy(tmp_rx_buf, (char *)&(gtm_net->rx_ip_hdr),
-+ sizeof(struct iphdr));
-+
-+ /* ETH_HLEN */
-+ gtm_net->rx_buf_size = sizeof(struct iphdr);
-+
-+ gtm_net->rx_buf_missing =
-+ frame_len - sizeof(struct iphdr);
-+ gtm_net->rx_state = WAIT_DATA;
-+ }
-+ break;
-+
-+ case WAIT_DATA:
-+ temp_bytes = (size < gtm_net->rx_buf_missing)
-+ ? size : gtm_net->rx_buf_missing;
-+
-+ /* Copy the rest of the bytes that are left in the
-+ * buffer into the waiting sk_buf. */
-+ /* Make room for temp_bytes after tail. */
-+ tmp_rx_buf = skb_put(gtm_net->rx_skb, temp_bytes);
-+ memcpy(tmp_rx_buf, in_buf + buffer_offset, temp_bytes);
-+
-+ gtm_net->rx_buf_missing -= temp_bytes;
-+ size -= temp_bytes;
-+ buffer_offset += temp_bytes;
-+ gtm_net->rx_buf_size += temp_bytes;
-+ if (!gtm_net->rx_buf_missing) {
-+ /* Packet is complete. Inject into stack. */
-+ /* We have IP packet here */
-+ gtm_net->rx_skb->protocol =
-+ __constant_htons(ETH_P_IP);
-+ /* don't check it */
-+ gtm_net->rx_skb->ip_summed =
-+ CHECKSUM_UNNECESSARY;
-+
-+ skb_reset_mac_header(gtm_net->rx_skb);
-+
-+ /* Ship it off to the kernel */
-+ netif_rx(gtm_net->rx_skb);
-+ /* No longer our buffer. */
-+ gtm_net->rx_skb = NULL;
-+
-+ /* update out statistics */
-+ STATS(net).rx_packets++;
-+ STATS(net).rx_bytes += gtm_net->rx_buf_size;
-+
-+ gtm_net->rx_buf_size = 0;
-+ gtm_net->rx_buf_missing = sizeof(struct iphdr);
-+ gtm_net->rx_state = WAIT_IP;
-+ }
-+ break;
-+
-+ case WAIT_SYNC:
-+ if(!gtm_net->sync_lost) {
-+ dev_err(&net->dev, "Lost sync...\n");
-+ }
-+ gtm_net->sync_lost++;
-+ /* Look for the next possible IP header */
-+ c = *(in_buf + buffer_offset);
-+ if(c >= 0x45 && c <= 0x4f) {
-+ /* This might be the begin of a new ip pkt */
-+ gtm_net->rx_state = WAIT_IP;
-+ gtm_net->rx_buf_size = 0;
-+ gtm_net->rx_buf_missing = sizeof(struct iphdr);
-+ }
-+ else {
-+ size--;
-+ buffer_offset++;
-+ }
-+ break;
-+
-+ default:
-+ size--;
-+ break;
-+ }
-+ }
-+}
-+
-+/* mux functions */
-+
-+/* function that tells you how much characters you can feed to fill your mux buffer*/
-+static inline int gtm501l_mux_to_demux(int count)
-+{
-+ int burst_cnt, remain_cnt;
-+ if (count & 0x1) {
-+ printk("Error - space in frame can't be an odd number\n");
-+ return -1;
-+ }
-+ /* We've got 2 extra bytes of framing per 512 bytes of data */
-+ burst_cnt = (count / (MUX_BURST_SIZE + 2)) * MUX_BURST_SIZE;
-+ remain_cnt = count % (MUX_BURST_SIZE + 2);
-+
-+ if (remain_cnt > 2)
-+ return remain_cnt - 2 + burst_cnt;
-+ else
-+ return burst_cnt + 1;
-+}
-+
-+/* multiplexes the data into the output buffer. output buffer is expected to be large enough to fit the data. */
-+static int gtm501l_mux_data(int chan_id, unsigned char *in_buf, int in_size,
-+ unsigned char *out_buf)
-+{
-+ int odd, cnt, result_size = 0;
-+
-+ /* check for an odd number of bytes */
-+ odd = in_size & 0x1;
-+
-+ /* make it even */
-+ in_size &= ~1;
-+
-+ /* First fill up with as much burst frames as possible */
-+ while (in_size) {
-+
-+ cnt = (in_size >= MUX_BURST_SIZE) ? MUX_BURST_SIZE : in_size;
-+ *(out_buf + result_size) =
-+ MUX_CONTROL_BYTE(chan_id, MUX_BURST_TRANSFER,
-+ MUX_MASTER_TO_SLAVE);
-+ //printk("Burst frame %d bytes\n", cnt);
-+ result_size++;
-+ *(out_buf + result_size) = cnt / 2;
-+ result_size++;
-+ memcpy(out_buf + result_size, in_buf, cnt);
-+ result_size += cnt;
-+ in_size -= cnt;
-+ in_buf += cnt;
-+ }
-+
-+ /* Then tackle the odd byte */
-+ if (odd) {
-+ *(out_buf + result_size) =
-+ MUX_CONTROL_BYTE(chan_id, MUX_DATA_TRANSFER,
-+ MUX_MASTER_TO_SLAVE);
-+ result_size++;
-+ *(out_buf + result_size) = *in_buf;
-+ result_size++;
-+
-+ }
-+
-+ return result_size;
-+}
-+
-+/* kfifo put theoretically cannot fail to copy all buffer here */
-+void gtm501l_tty_insert_flip_string(struct gtm501l_serial *gtm_ser,
-+ unsigned char *chars,size_t size)
-+{
-+ int chars_inserted;
-+ int copylen;
-+ struct tty_struct *tty;
-+
-+ if (gtm_ser && gtm_ser->tty) {
-+ tty= gtm_ser->tty;
-+ if (test_bit(TTY_THROTTLED, &tty->flags)) {
-+ dprintk(DEBUG_TTY, "received %d bytes while throttled\n", size);
-+ copylen=kfifo_in(gtm_ser->throttle_fifo,chars,size);
-+ if(copylen!=size)
-+ dprintk(DEBUG_TTY, "kfifo_put failed got %d expected %d\n",
-+ copylen, size);
-+ }
-+ else {
-+ chars_inserted=tty_insert_flip_string(tty, chars, size);
-+ if(chars_inserted!=size) {
-+
-+ size -= chars_inserted;
-+ copylen=kfifo_in(gtm_ser->throttle_fifo,
-+ &chars[chars_inserted],
-+ size);
-+ if(copylen!=size)
-+ dprintk(DEBUG_TTY, "%s kfifo_put failed got %d expected %d\n",
-+ copylen, size);
-+ }
-+ /* The flip here should force the tty layer
-+ * to throttle if neccessary
-+ */
-+ tty_flip_buffer_push(tty);
-+ }
-+ }
-+
-+}
-+
-+#define PORT_SPEC_FLAGS_ENABLED 0x80
-+#define PORT_SPEC_FLAGS_TYPE_MASK 0x7f
-+#define PORT_SPEC_FLAGS_SERIAL 0x01
-+#define PORT_SPEC_FLAGS_NET 0x02
-+
-+static void gtm501l_decode_version_info(struct gtm501l_device *gtm_dev,
-+ unsigned char *buf, int size)
-+{
-+ int i = 0, chan, flags;
-+ u16 version;
-+ u16 framelength;
-+ struct gtm501l_port_spec *new_port_spec;
-+
-+ /* Protocol version */
-+ memcpy(&version, buf + i, 2);
-+ i += 2;
-+
-+ if(version != 0 || size != 260) {
-+ /* Unknown version or size is wrong.. */
-+ return;
-+ }
-+
-+ /* Frame length */
-+ memcpy(&framelength, buf + i, 2);
-+ i += 2;
-+
-+ /* Channel descriptors */
-+ new_port_spec = kzalloc(sizeof(struct gtm501l_port_spec) * 16, GFP_KERNEL);
-+ for(chan = 0; chan < 16; chan++) {
-+ flags = buf[i++];
-+
-+ if(flags | PORT_SPEC_FLAGS_ENABLED) {
-+ new_port_spec[chan].enabled = 1;
-+ switch(flags & PORT_SPEC_FLAGS_TYPE_MASK) {
-+ case PORT_SPEC_FLAGS_SERIAL:
-+ new_port_spec[chan].type = GTM501L_PORT_SPEC_SERIAL;
-+ break;
-+ case PORT_SPEC_FLAGS_NET:
-+ new_port_spec[chan].type = GTM501L_PORT_SPEC_NET;
-+ break;
-+ default:
-+ /* Unknown channel type: disable this channel */
-+ new_port_spec[chan].enabled = 0;
-+ }
-+
-+ /* Copy the name */
-+ memcpy(&new_port_spec[chan].name, buf + i, 15);
-+ }
-+
-+ i += 15;
-+ }
-+
-+ /* Activate the new port spec */
-+ gtm501l_create_ports(gtm_dev, new_port_spec);
-+ kfree(new_port_spec);
-+}
-+
-+
-+/**
-+ * gtm501l_demux walks through the received SPI message given in in_buf with the length size and copies all
-+ * found data into the opened channels given in the gtm_dev structure. The SPI buffer length must be always
-+ * a multiple of 2 bytes!
-+ * It returns finally the real found useful data inside the SPI frame length
-+ */
-+static int gtm501l_demux(struct gtm501l_device *gtm_dev, unsigned char *in_buf,
-+ int size)
-+{
-+ int i = 0, valid = 0, copy;
-+ unsigned char temp;
-+ struct gtm501l_port_data *port_data;
-+ struct gtm501l_serial *gtm_ser = NULL;
-+ struct gtm501l_net *gtm_net = NULL;
-+ unsigned char old_dcd;
-+
-+ gtm_dev->empty_transfers++;
-+
-+ while (i < size) {
-+ gtm_ser = NULL;
-+ gtm_net = NULL;
-+ copy = 0;
-+
-+ if(spi_b16)
-+ swap_buf((u16 *)(in_buf + i), 2);
-+
-+ /* check for an end of frame sequence */
-+ if((in_buf[i]==0) && (in_buf[i+1]==0)) break;
-+
-+ if(0 && in_buf[i] == 0xFF) { /* TODO: Fill in correct check for version info */
-+ copy = in_buf[++i] * 2;
-+ i++;
-+ if(spi_b16)
-+ swap_buf((u16 *)(in_buf + i), copy);
-+ gtm501l_decode_version_info(gtm_dev, in_buf + i, copy);
-+ i += copy;
-+ continue;
-+ }
-+
-+ /* verify valid packet */
-+ temp = MUX_DEVICE(in_buf[i]);
-+ if (temp != MUX_SLAVE_TO_MASTER) {
-+ /*
-+ * ##PH: That should never happen and should counted as errorness data
-+ */
-+ i += 2;
-+ continue;
-+ }
-+
-+#ifdef DEBUG
-+ if(!valid && (i > 0) && (gtm501l_debug & DEBUG_DEMUX)) {
-+ int j;
-+ dprintk(DEBUG_DEMUX, "First valid byte found at offset %d\n", i);
-+ for(j=0 ; j<i ; j++) printk("%.2X ", in_buf[j]);
-+ printk("\n");
-+ }
-+#endif
-+
-+ valid = 1;
-+
-+ //dprintk(DEBUG_DEMUX, "Got valid mux bytes 0x%X 0x%X\n", in_buf[i], in_buf[i+1]);
-+
-+ /* verify valid channel */
-+ temp = MUX_CHANNEL(in_buf[i]);
-+ if (temp >= GTM501L_PORT_PER_DEV || !gtm_dev->port_data[temp]) {
-+ i += 2;
-+ continue;
-+ }
-+ port_data = gtm_dev->port_data[temp];
-+
-+ if (port_data->spec.type == GTM501L_PORT_SPEC_NET)
-+ gtm_net = &port_data->type.net;
-+ else if (port_data->spec.type == GTM501L_PORT_SPEC_SERIAL)
-+ gtm_ser = &port_data->type.serial;
-+ //dprintk(DEBUG_DEMUX, "For channel %d\n", temp);
-+
-+ /* start decoding data */
-+ temp = MUX_BLOCK_TYPE(in_buf[i]);
-+ if (temp == MUX_BURST_TRANSFER) {
-+ copy = in_buf[++i] * 2;
-+ if( 0 == copy ) copy = MUX_BURST_SIZE;
-+ if(spi_b16)
-+ swap_buf((u16 *)(in_buf + i + 1), copy);
-+ } else if (temp == MUX_DATA_TRANSFER) {
-+ copy = 1;
-+ }
-+
-+ if (copy) {
-+ gtm_dev->empty_transfers = 0;
-+ //dprintk(DEBUG_DEMUX, "\tNeed to copy %d data bytes\n", copy);
-+ /* regular data */
-+ if( gtm_ser && gtm_ser->tty ) {
-+ gtm501l_tty_insert_flip_string(gtm_ser, &in_buf[++i], copy);
-+ }
-+ else if (gtm_net) {
-+/*
-+ int j;
-+ for(j=i+1;j<(i+1+copy);j++) printk("0x%.2X ", in_buf[j]);
-+ printk("\n");
-+*/
-+ gtm501l_rx_netchar(gtm_net, &in_buf[++i], copy);
-+ } else {
-+ i++;
-+ }
-+
-+ i += copy;
-+ continue;
-+ }
-+
-+ if (temp == MUX_CONTROL_TRANSFER) {
-+ //dprintk(DEBUG_DEMUX, "Is a control byte\n");
-+ /* control data */
-+ temp = in_buf[i + 1];
-+ if (MUX_LINK(temp)) {
-+ set_bit(GTM501L_TX_FC,
-+ &port_data->signal_state);
-+ dprintk(DEBUG_DEMUX, "FC set\n");
-+ } else {
-+ clear_bit(GTM501L_TX_FC,
-+ &port_data->signal_state);
-+ dprintk(DEBUG_DEMUX, "FC cleared\n");
-+ }
-+
-+ if (gtm_ser) {
-+ old_dcd =
-+ test_bit(GTM501L_DCD,
-+ &port_data->signal_state);
-+
-+ if (MUX_DCD(temp)) {
-+ set_bit(GTM501L_DCD,
-+ &port_data->signal_state);
-+ dprintk(DEBUG_DEMUX, "DCD set\n");
-+ } else {
-+ clear_bit(GTM501L_DCD,
-+ &port_data->signal_state);
-+ dprintk(DEBUG_DEMUX, "DCD cleared\n");
-+ }
-+ if (MUX_CTS(temp)) {
-+ set_bit(GTM501L_CTS,
-+ &port_data->signal_state);
-+ dprintk(DEBUG_DEMUX, "CTS set\n");
-+ } else {
-+ clear_bit(GTM501L_CTS,
-+ &port_data->signal_state);
-+ dprintk(DEBUG_DEMUX, "CTS cleared\n");
-+ }
-+
-+ if (MUX_DSR(temp)) {
-+ set_bit(GTM501L_DSR,
-+ &port_data->signal_state);
-+ dprintk(DEBUG_DEMUX, "DSR set\n");
-+ } else {
-+ clear_bit(GTM501L_DSR,
-+ &port_data->signal_state);
-+ dprintk(DEBUG_DEMUX, "DSR cleared\n");
-+ }
-+
-+ if (MUX_RI(temp)) {
-+ set_bit(GTM501L_RI,
-+ &port_data->signal_state);
-+ dprintk(DEBUG_DEMUX, "RI set\n");
-+ } else {
-+ clear_bit(GTM501L_RI,
-+ &port_data->signal_state);
-+ dprintk(DEBUG_DEMUX, "RI cleared\n");
-+ }
-+
-+ if (old_dcd
-+ && !test_bit(GTM501L_DCD,
-+ &port_data->signal_state))
-+ if (gtm_ser->tty)
-+ tty_hangup(gtm_ser->tty);
-+ }
-+
-+ i += 2;
-+ }
-+
-+ }
-+ return i;
-+}
-+
-+static int gtm501l_mux_flow_control(struct gtm501l_port_data *port_data,
-+ unsigned char *out_buf)
-+{
-+ *out_buf =
-+ MUX_CONTROL_BYTE(port_data->port_id, MUX_CONTROL_TRANSFER,
-+ MUX_MASTER_TO_SLAVE);
-+ *(out_buf + 1) =
-+ (test_bit(GTM501L_DTR, &port_data->signal_state)
-+ ? (1 << MUX_DTR_SHIFT) : 0)
-+ | (test_bit(GTM501L_RTS, &port_data->signal_state)
-+ ? (1 << MUX_RTS_SHIFT): 0)
-+ | (test_bit(GTM501L_RX_FC, &port_data->signal_state)
-+ ? (1 << MUX_LINK_SHIFT): 0);
-+
-+ return 2;
-+}
-+
-+static void gtm501l_timer(unsigned long arg)
-+{
-+ struct tasklet_struct *tasklet = (struct tasklet_struct *)arg;
-+ //printk("Timer fired\n");
-+ tasklet_hi_schedule(tasklet);
-+}
-+
-+/* gpio interrupt handler */
-+
-+static irqreturn_t gtm501l_gpio_interrupt(int irq, void *dev)
-+{
-+ struct gtm501l_device *gtm_dev = (struct gtm501l_device *)dev;
-+ static int count = 0;
-+
-+ if(!gtm_dev || !test_bit(GTM501L_STATE_PRESENT, &gtm_dev->flags))
-+ return IRQ_HANDLED;
-+
-+ /*
-+ * Using the GPE layer it will set the
-+ * irq to the requested gpio_in line
-+ */
-+
-+ if(gtm_dev->stats) gtm_dev->stats->wait_finished(gtm_dev->frame_stats);
-+
-+ if (!(count % 5000))
-+ dprintk(DEBUG_GPIO, "Scheduling\n");
-+
-+ if(!test_bit(GTM501L_STATE_IO_IN_PROGRESS, &gtm_dev->flags)) {
-+
-+ /* If we received no data for the last x
-+ * frames, delay the next transfer */
-+ if(gtm_dev->empty_transfers > GTM501L_MAX_EMPTY && backoff_enabled) {
-+ if(!timer_pending(&gtm_dev->timer)) {
-+ gtm_dev->timer.expires = jiffies + GTM501L_BACKOFF_TIMER;
-+ gtm_dev->timer.function = gtm501l_timer;
-+ gtm_dev->timer.data = (unsigned long)&gtm_dev->io_work_tasklet;
-+ add_timer(&gtm_dev->timer);
-+ }
-+ }
-+ else
-+ tasklet_hi_schedule(&gtm_dev->io_work_tasklet);
-+ }
-+ else set_bit(GTM501L_STATE_IO_READY, &gtm_dev->flags);
-+
-+ count++;
-+
-+ return IRQ_HANDLED;
-+}
-+
-+static int gtm501l_prepare_tx_buffer(struct gtm501l_device *gtm_dev)
-+{
-+ int tx_count = 0;
-+ int i, j;
-+ unsigned int temp_count;
-+ struct gtm501l_port_data *port_data;
-+ int round_robin_index;
-+ unsigned char *tx_buffer;
-+ int len;
-+
-+ if(gtm_dev->stats) gtm_dev->stats->encode_start_idle_finished(gtm_dev->frame_stats);
-+
-+ tx_buffer = gtm_dev->tx_buffer[gtm_dev->tx_buffer_used];
-+
-+ /* First add flow control events for all ports */
-+ for (i = 0; i < GTM501L_PORT_PER_DEV; i++) {
-+ port_data = gtm_dev->port_data[i];
-+ if(!port_data)
-+ continue;
-+
-+ if (test_and_clear_bit (GTM501L_UPDATE, &port_data->signal_state)) {
-+ tx_count += gtm501l_mux_flow_control(port_data,
-+ tx_buffer + tx_count);
-+ }
-+ }
-+
-+ /* assemble data from buffers from all ports */
-+ round_robin_index = gtm_dev->round_robin_index;
-+ for (j = round_robin_index; j <
-+ (GTM501L_PORT_PER_DEV + round_robin_index) ; j++) {
-+ i = j % GTM501L_PORT_PER_DEV;
-+ port_data = gtm_dev->port_data[i];
-+ if(!port_data)
-+ continue;
-+
-+ /* check if this port is flow controlled */
-+ if (test_bit(GTM501L_TX_FC, &port_data->signal_state))
-+ continue;
-+
-+ /* check for data to be sent */
-+ temp_count = gtm501l_mux_to_demux(GTM501L_TRANSFER_SIZE - tx_count);
-+ temp_count = min(kfifo_len(port_data->tx_fifo), temp_count);
-+ if (temp_count) {
-+ len = kfifo_out(port_data->tx_fifo, scratch_buf, temp_count);
-+#ifdef GTM501L_DEBUG
-+ sprintf(debug_buff_name, "gtm501l tx buf port %d %d", i, len);
-+ GTM501L_BUFFER_DUMP(debug_buff_name, scratch_buf, temp_count);
-+#endif
-+ tx_count += gtm501l_mux_data(i, scratch_buf, temp_count,
-+ tx_buffer + tx_count);
-+ total_spi_write += temp_count;
-+ gtm_dev->empty_transfers = 0;
-+ }
-+ if( port_data->spec.type == GTM501L_PORT_SPEC_NET)
-+ gtm501l_push_skb(port_data);
-+ else if(port_data->type.serial.tty)
-+ tty_wakeup(port_data->type.serial.tty);
-+ }
-+ gtm_dev->round_robin_index = gtm_dev->round_robin_index + 1;
-+ if (gtm_dev->round_robin_index == GTM501L_PORT_PER_DEV)
-+ gtm_dev->round_robin_index = 0;
-+
-+ /* End-Of-Frame marker */
-+ temp_count = min(2, GTM501L_TRANSFER_SIZE - tx_count);
-+ memset(tx_buffer + tx_count, 0, temp_count);
-+ tx_count += temp_count;
-+
-+ if(spi_b16)
-+ swap_buf((u16 *)(tx_buffer), tx_count);
-+
-+ gtm_dev->tx_count = tx_count;
-+
-+ if(gtm_dev->stats) gtm_dev->stats->encode_finished(gtm_dev->frame_stats, tx_count - temp_count);
-+
-+ return tx_count;
-+}
-+
-+/* serial functions */
-+static void gtm501l_io(unsigned long data)
-+{
-+ struct gtm501l_device *gtm_dev = (struct gtm501l_device *)data;
-+ int retval;
-+#ifdef GTM501L_DEBUG
-+ char debug_buff_name[80];
-+#endif
-+
-+ if (!test_bit(GTM501L_STATE_PRESENT, &gtm_dev->flags))
-+ return;
-+
-+ if (!test_and_set_bit(GTM501L_STATE_IO_IN_PROGRESS, &gtm_dev->flags)) {
-+ gtm501l_prepare_tx_buffer(gtm_dev);
-+
-+ if(gtm_dev->stats) gtm_dev->stats->transfer_start(gtm_dev->frame_stats);
-+
-+ spi_message_init(&gtm_dev->spi_msg);
-+ gtm_dev->spi_msg.context = gtm_dev;
-+ gtm_dev->spi_msg.complete = gtm501l_spi_complete;
-+ gtm_dev->spi_msg.is_dma_mapped = 1;
-+
-+ /* set up our spi transfer */
-+ gtm_dev->spi_xfer.len = GTM501L_TRANSFER_SIZE;
-+ gtm_dev->spi_xfer.cs_change = 0;
-+#if 0
-+ gtm_dev->tx_dma[gtm_dev->tx_buffer_used] =
-+ dma_map_single(&gtm_dev->spi_dev->dev, gtm_dev->tx_buffer[gtm_dev->tx_buffer_used],
-+ GTM501L_TRANSFER_SIZE, DMA_TO_DEVICE);
-+ gtm_dev->rx_dma = dma_map_single(&gtm_dev->spi_dev->dev, gtm_dev->rx_buffer,
-+ GTM501L_TRANSFER_SIZE, DMA_FROM_DEVICE);
-+#else
-+ gtm_dev->tx_dma[gtm_dev->tx_buffer_used] = virt_to_phys(gtm_dev->tx_buffer[gtm_dev->tx_buffer_used]);
-+ gtm_dev->rx_dma = virt_to_phys(gtm_dev->rx_buffer);
-+#endif
-+
-+ gtm_dev->spi_xfer.tx_dma = gtm_dev->tx_dma[gtm_dev->tx_buffer_used];
-+ gtm_dev->spi_xfer.tx_buf = gtm_dev->tx_buffer[gtm_dev->tx_buffer_used];
-+ gtm_dev->tx_buffer_used = (++gtm_dev->tx_buffer_used) % 2;
-+ gtm_dev->tx_count = 0;
-+
-+ gtm_dev->spi_xfer.rx_dma = gtm_dev->rx_dma;
-+ gtm_dev->spi_xfer.rx_buf = gtm_dev->rx_buffer;
-+
-+ spi_message_add_tail(&gtm_dev->spi_xfer, &gtm_dev->spi_msg);
-+
-+ retval = spi_async(gtm_dev->spi_dev, &gtm_dev->spi_msg);
-+
-+ if (retval) {
-+ dprintk(DEBUG_SPI, "ERROR: spi_async failed (%d)\n", retval);
-+ clear_bit(GTM501L_STATE_IO_IN_PROGRESS,
-+ &gtm_dev->flags);
-+ tasklet_hi_schedule(&gtm_dev->io_work_tasklet);
-+ return;
-+ }
-+ } else {
-+ dprintk(DEBUG_SPI, "ERROR - gtm501l_io called, but spi still busy\n");
-+ }
-+
-+}
-+
-+static ssize_t gtm501l_sysfs_channel(struct device *dev, struct device_attribute *attr,
-+ char *buf)
-+{
-+ struct gtm501l_port_data *port_data = NULL;
-+ int i;
-+
-+ /* Look for the port_data matching this device. */
-+ if(strcmp("tty", dev->class->name) == 0) {
-+ for (i = 0; i < GTM501L_MAX_MINORS; i++) {
-+ if (gtm501l_serial_ports[i] &&
-+ gtm501l_serial_ports[i]->type.serial.dev == dev) {
-+ port_data = gtm501l_serial_ports[i];
-+ break;
-+ }
-+ }
-+ }
-+ else if(strcmp("net", dev->class->name) == 0) {
-+ port_data = net_to_gtm501l_data(to_net_dev(dev));
-+ }
-+
-+ return sprintf(buf, "%s\n", (port_data ? port_data->spec.name : "unknown"));
-+}
-+
-+static DEVICE_ATTR(channel, S_IRUGO, gtm501l_sysfs_channel, NULL);
-+
-+static void gtm501l_free_port(struct gtm501l_port_data *port_data)
-+{
-+ /* do device type specific cleanup */
-+ if (port_data->spec.type == GTM501L_PORT_SPEC_SERIAL) {
-+ /* serial device cleanup */
-+ device_remove_file(port_data->type.serial.dev, &dev_attr_channel);
-+ gtm501l_serial_ports[port_data->type.serial.minor] = 0;
-+ tty_unregister_device(tty_drv, port_data->type.serial.minor);
-+ kfifo_free(port_data->type.serial.throttle_fifo);
-+ } else if (port_data->spec.type == GTM501L_PORT_SPEC_NET) {
-+ /* net device cleanup */
-+ device_remove_file(&port_data->type.net.net->dev, &dev_attr_channel);
-+ unregister_netdev(port_data->type.net.net);
-+ free_netdev(port_data->type.net.net);
-+ }
-+
-+ /* do common device deinitialization */
-+ kfifo_free(port_data->tx_fifo);
-+ kfree(port_data);
-+}
-+
-+static int gtm501l_get_free_port(void)
-+{
-+ int i;
-+
-+ for (i = 0; i < GTM501L_MAX_MINORS; i++) {
-+ if (!gtm501l_serial_ports[i])
-+ return i;
-+ }
-+ return -1;
-+}
-+
-+static void gtm501l_create_ports(struct gtm501l_device *gtm_dev,
-+ struct gtm501l_port_spec *specs)
-+{
-+ struct net_device *net;
-+ struct gtm501l_serial *gtm_ser;
-+ struct gtm501l_port_data *port_data = NULL;
-+ int minor = -1;
-+ int i;
-+ int status;
-+
-+ for(i = 0; i < GTM501L_PORT_PER_DEV; i++) {
-+ port_data = gtm_dev->port_data[i];
-+
-+ if(port_data) {
-+ if(!specs[i].enabled) {
-+ /* A port did exist, but it's gone now */
-+ gtm501l_free_port(port_data);
-+ gtm_dev->port_data[i] = NULL;
-+ continue;
-+ }
-+ else if (specs[i].type == port_data->spec.type) {
-+ /* Old and new port are of the same type,
-+ * only update the name */
-+ memcpy(&port_data->spec.name, &specs[i].name, 16);
-+ continue;
-+ }
-+ else {
-+ /* Old and new port have different types */
-+ gtm501l_free_port(port_data);
-+ gtm_dev->port_data[i] = NULL;
-+ }
-+ }
-+
-+ /* If this port is not enabled, skip it */
-+ if(!specs[i].enabled) {
-+ continue;
-+ }
-+
-+ dprintk(DEBUG_INIT, "%d: (%d) %s\n", i, specs[i].type, specs[i].name);
-+
-+ port_data = kzalloc(sizeof(struct gtm501l_port_data), GFP_KERNEL);
-+ if (!port_data)
-+ continue;
-+
-+ memcpy(&port_data->spec, &specs[i], sizeof(struct gtm501l_port_spec));
-+
-+ spin_lock_init(&port_data->fifo_lock);
-+ lockdep_set_class_and_subclass(&port_data->fifo_lock, &gtm501l_key, 0);
-+
-+ /* common initialization */
-+ port_data->spi_itf = gtm_dev;
-+ port_data->port_id = i;
-+ port_data->tx_fifo =
-+ status = kfifo_alloc(port_data->tx_fifo, GTM501L_FIFO_SIZE, GFP_KERNEL);
-+ if (status) {
-+ printk(KERN_ERR "GTM501 failed kfifo tx alloc %d\n", status);
-+ kfree(port_data);
-+ continue;
-+ }
-+ /* device specific initialization */
-+ if (port_data->spec.type == GTM501L_PORT_SPEC_SERIAL) {
-+ /* serial device */
-+ if ((minor = gtm501l_get_free_port()) == -1) {
-+ kfree(port_data);
-+ continue;
-+ }
-+ gtm_ser = &port_data->type.serial;
-+ gtm_ser->minor = minor;
-+ gtm_ser->dev =
-+ tty_register_device(tty_drv, minor,
-+ &gtm_dev->spi_dev->dev);
-+ if (!gtm_ser->dev) {
-+ dprintk(DEBUG_INIT, "Registering tty device failed\n");
-+ kfree(port_data);
-+ continue;
-+ }
-+ gtm501l_serial_ports[minor] = port_data;
-+ spin_lock_init(&gtm_ser->throttle_fifo_lock);
-+ lockdep_set_class_and_subclass(&gtm_ser->throttle_fifo_lock, &gtm501l_key, 0);
-+ status = kfifo_alloc(gtm_ser->throttle_fifo, GTM501l_THROTTLE_FIFO_SIZE,
-+ GFP_KERNEL);
-+ if (status) {
-+ tty_unregister_device(tty_drv,
-+ gtm_ser->minor);
-+ kfree(port_data);
-+ continue;
-+ }
-+
-+ if (device_create_file(gtm_ser->dev, &dev_attr_channel))
-+ dev_err(gtm_ser->dev, "Could not create sysfs file for channel\n");
-+ }
-+ else if (port_data->spec.type == GTM501L_PORT_SPEC_NET) {
-+ /* net device */
-+ net = alloc_netdev(sizeof(struct gtm501l_port_data *), "gtm%d",
-+ gtm501l_net_init);
-+ if (!net) {
-+ kfifo_free(port_data->tx_fifo);
-+ kfree(port_data);
-+ continue;
-+ }
-+
-+ *((struct gtm501l_port_data **)netdev_priv(net)) = port_data;
-+ port_data->type.net.net = net;
-+
-+ if (register_netdev(net)) {
-+ free_netdev(net);
-+ kfifo_free(port_data->tx_fifo);
-+ kfree(port_data);
-+ continue;
-+ }
-+
-+ if (device_create_file(&net->dev, &dev_attr_channel))
-+ dev_err(&net->dev, "Could not create sysfs file for channel\n");
-+ }
-+
-+ gtm_dev->port_data[i] = port_data;
-+
-+ }
-+}
-+
-+static void gtm501l_free_device(struct kref *ref)
-+{
-+ int i;
-+ struct gtm501l_device *gtm_dev =
-+ container_of(ref, struct gtm501l_device, ref);
-+ struct gtm501l_port_data *port_data;
-+
-+ tasklet_kill(&gtm_dev->io_work_tasklet);
-+
-+ for (i = 0; i < GTM501L_PORT_PER_DEV; i++) {
-+ port_data = gtm_dev->port_data[i];
-+ if(port_data)
-+ gtm501l_free_port(port_data);
-+ }
-+#ifdef CONFIG_DEBUG_FS
-+ gtm501l_debugfs_remove(gtm_dev);
-+#endif
-+ kfree(gtm_dev);
-+}
-+
-+static void gtm501l_spi_complete(void *ctx)
-+{
-+ struct gtm501l_device *gtm_dev = (struct gtm501l_device *)ctx;
-+ unsigned int rx_count = 0;
-+
-+ if(gtm_dev->stats) {
-+ gtm_dev->stats->transfer_finished_wait_start(gtm_dev->frame_stats);
-+ gtm_dev->stats->transfer_decode_start(gtm_dev->frame_stats);
-+ }
-+
-+ /* did we get removed meanwhile ? */
-+ if (!test_bit(GTM501L_STATE_PRESENT, &gtm_dev->flags))
-+ return;
-+
-+ if (!gtm_dev->spi_msg.status) {
-+#if 0
-+ dma_unmap_single(&gtm_dev->spi_dev->dev,
-+ gtm_dev->tx_dma[(gtm_dev->tx_buffer_used + 1) % 2],
-+ GTM501L_TRANSFER_SIZE, DMA_TO_DEVICE);
-+ dma_unmap_single(&gtm_dev->spi_dev->dev, gtm_dev->rx_dma,
-+ GTM501L_TRANSFER_SIZE, DMA_FROM_DEVICE);
-+#endif
-+ rx_count = gtm501l_demux(gtm_dev, gtm_dev->rx_buffer,
-+ gtm_dev->spi_msg.actual_length);
-+ } else {
-+ spi_err_count++;
-+ printk("SPI transfer error %d - (%d)\n",
-+ gtm_dev->spi_msg.status, spi_err_count);
-+ }
-+
-+ if(gtm_dev->stats) gtm_dev->stats->decode_finished_may_idle_start(gtm_dev->frame_stats, rx_count);
-+
-+ clear_bit(GTM501L_STATE_IO_IN_PROGRESS, &gtm_dev->flags);
-+
-+ //gtm501l_prepare_tx_buffer(gtm_dev);
-+
-+ if(test_and_clear_bit(GTM501L_STATE_IO_READY, &gtm_dev->flags))
-+ tasklet_hi_schedule(&gtm_dev->io_work_tasklet);
-+}
-+
-+/* char/tty operations */
-+
-+static void gtm501l_throttle(struct tty_struct *tty)
-+{
-+ struct gtm501l_port_data *port_data =
-+ (struct gtm501l_port_data *)tty->driver_data;
-+
-+ func_enter();
-+
-+ if (port_data) {
-+ func_exit();
-+ return;
-+ }
-+
-+ if(!test_bit(GTM501L_RX_FC, &port_data->signal_state)) {
-+ set_bit(GTM501L_RX_FC, &port_data->signal_state);
-+ set_bit(GTM501L_UPDATE, &port_data->signal_state);
-+ }
-+
-+ func_exit();
-+}
-+
-+/* To be checked... I can't remember the exact details but the hso driver
-+ * needed a hso_unthrottle_tasklet to prevent hso_throttle being
-+ * called recursively, I am not sure whether this can happen here.
-+ */
-+#define UNTHROTTLE_STACK_BUF_SIZE (512)
-+static void gtm501l_unthrottle(struct tty_struct *tty)
-+{
-+ struct gtm501l_port_data *port_data =
-+ (struct gtm501l_port_data *)tty->driver_data;
-+ struct gtm501l_serial *gtm_ser;
-+ int write_length_remaining, curr_write_len;
-+ char stack_buff[UNTHROTTLE_STACK_BUF_SIZE];
-+ struct gtm501l_device *gtm_dev = port_data->spi_itf;
-+
-+ func_enter();
-+
-+ if (!port_data) {
-+ func_exit();
-+ return;
-+ }
-+
-+ gtm_ser=&port_data->type.serial;
-+ write_length_remaining=kfifo_len(gtm_ser->throttle_fifo);
-+ while (write_length_remaining) {
-+ if (test_bit(TTY_THROTTLED, &tty->flags)) {
-+ func_exit();
-+ return;
-+ }
-+ curr_write_len = min(write_length_remaining,
-+ UNTHROTTLE_STACK_BUF_SIZE);
-+ curr_write_len = kfifo_out(gtm_ser->throttle_fifo,
-+ stack_buff, curr_write_len);
-+ curr_write_len = tty_insert_flip_string
-+ (tty, stack_buff,
-+ curr_write_len);
-+ write_length_remaining -= curr_write_len;
-+ tty_flip_buffer_push(tty);
-+ }
-+
-+ clear_bit(GTM501L_RX_FC, &port_data->signal_state);
-+ set_bit(GTM501L_UPDATE, &port_data->signal_state);
-+
-+ /* If the timer is currently running, stop it and try to initiate a
-+ * transfer immediately */
-+ if(timer_pending(&gtm_dev->timer)) {
-+ del_timer_sync(&gtm_dev->timer);
-+ gtm501l_io((unsigned long)gtm_dev);
-+ }
-+
-+ func_exit();
-+}
-+
-+static int gtm501l_tiocmget(struct tty_struct *tty, struct file *filp)
-+{
-+ unsigned int value;
-+ struct gtm501l_port_data *port_data =
-+ (struct gtm501l_port_data *)tty->driver_data;
-+
-+ func_enter();
-+
-+ if (!port_data) {
-+ func_exit();
-+ return 0;
-+ }
-+
-+ value =
-+ (test_bit(GTM501L_RTS, &port_data->signal_state) ? TIOCM_RTS : 0) |
-+ (test_bit(GTM501L_DTR, &port_data->signal_state) ? TIOCM_DTR : 0) |
-+ (test_bit(GTM501L_CTS, &port_data->signal_state) ? TIOCM_CTS : 0) |
-+ (test_bit(GTM501L_DSR, &port_data->signal_state) ? TIOCM_DSR : 0) |
-+ (test_bit(GTM501L_DCD, &port_data->signal_state) ? TIOCM_CAR : 0) |
-+ (test_bit(GTM501L_RI, &port_data->signal_state) ? TIOCM_RNG : 0);
-+
-+ func_exit();
-+ return value;
-+}
-+
-+static int gtm501l_tiocmset(struct tty_struct *tty, struct file *filp,
-+ unsigned int set, unsigned int clear)
-+{
-+ struct gtm501l_port_data *port_data =
-+ (struct gtm501l_port_data *)tty->driver_data;
-+
-+ func_enter();
-+
-+ if (!port_data) {
-+ func_exit();
-+ return -ENODEV;
-+ }
-+
-+ if (set & TIOCM_RTS)
-+ set_bit(GTM501L_RTS, &port_data->signal_state);
-+ if (set & TIOCM_DTR)
-+ set_bit(GTM501L_DTR, &port_data->signal_state);
-+
-+ if (clear & TIOCM_RTS)
-+ clear_bit(GTM501L_RTS, &port_data->signal_state);
-+ if (clear & TIOCM_DTR)
-+ clear_bit(GTM501L_DTR, &port_data->signal_state);
-+
-+ set_bit(GTM501L_UPDATE, &port_data->signal_state);
-+
-+ func_exit();
-+ return 0;
-+}
-+
-+static int gtm501l_open(struct tty_struct *tty, struct file *filp)
-+{
-+ struct gtm501l_serial *gtm_ser = NULL;
-+ struct gtm501l_port_data *port_data;
-+
-+ func_enter();
-+
-+ if ((tty->index > GTM501L_MAX_MINORS)
-+ || (!gtm501l_serial_ports[tty->index])) {
-+ func_exit();
-+ return -ENODEV;
-+ }
-+
-+ port_data = gtm501l_serial_ports[tty->index];
-+ gtm_ser = &port_data->type.serial;
-+
-+ if (!test_bit(GTM501L_STATE_PRESENT, &port_data->spi_itf->flags)) {
-+ func_exit();
-+ return -ENODEV;
-+ }
-+
-+ gtm_ser->open++;
-+ tty->driver_data = port_data;
-+ tty->low_latency = 1;
-+ gtm_ser->tty = tty;
-+ _gtm501l_set_termios(tty, NULL);
-+
-+ /* signal_update_needed flag will be set by tiocmset */
-+ clear_bit(GTM501L_RX_FC, &port_data->signal_state);
-+ gtm501l_tiocmset(tty, filp, TIOCM_DTR | TIOCM_RTS, 0);
-+
-+ kref_get(&port_data->spi_itf->ref);
-+ func_exit();
-+ return 0;
-+}
-+
-+static void gtm501l_close(struct tty_struct *tty, struct file *filp)
-+{
-+ struct gtm501l_serial *gtm_ser = NULL;
-+ struct gtm501l_port_data *port_data =
-+ (struct gtm501l_port_data *)tty->driver_data;
-+
-+ func_enter();
-+
-+ if ((tty->index > GTM501L_MAX_MINORS) || !port_data) {
-+ func_exit();
-+ return;
-+ }
-+
-+ gtm_ser = &port_data->type.serial;
-+
-+ /*
-+ * ugh, the refcounting... unfortunately open() & close()'s aren't always executed symmetrically.
-+ * There are cases where after a failed open you can still get a close(). We can't handle those
-+ * here. File a tty layer bug.
-+ */
-+ if(--gtm_ser->open >= 0) {
-+ kref_put(&port_data->spi_itf->ref, gtm501l_free_device);
-+ if( gtm_ser->open == 0) {
-+ kfifo_reset(port_data->tx_fifo);
-+ /* signal_update_needed flag will be set by tiocmset */
-+ set_bit(GTM501L_RX_FC, &port_data->signal_state);
-+ gtm501l_tiocmset(tty, filp, 0, TIOCM_DTR | TIOCM_RTS);
-+ gtm_ser->tty = NULL;
-+ }
-+ } else gtm_ser->open = 0;
-+
-+ func_exit();
-+}
-+
-+static int gtm501l_write(struct tty_struct *tty, const unsigned char *buf,
-+ int count)
-+{
-+ struct gtm501l_port_data *port_data =
-+ (struct gtm501l_port_data *)tty->driver_data;
-+ struct gtm501l_serial *gtm_ser;
-+ unsigned int tx_count;
-+ unsigned char *tmp_buf = (unsigned char *)buf;
-+ struct gtm501l_device *gtm_dev = port_data->spi_itf;
-+
-+ func_enter();
-+
-+ if (!port_data) {
-+ func_exit();
-+ return -ENODEV;
-+ }
-+
-+ gtm_ser = &port_data->type.serial;
-+
-+ tx_count = kfifo_in(port_data->tx_fifo, tmp_buf, count);
-+ total_tty_write+=tx_count;
-+
-+ /* If the timer is currently running, stop it and try to initiate a
-+ * transfer immediately */
-+ if(timer_pending(&gtm_dev->timer)) {
-+ del_timer_sync(&gtm_dev->timer);
-+ gtm501l_io((unsigned long)gtm_dev);
-+ }
-+
-+ //printk("Write: wrote %d bytes in fifo (total = %d)\n", tx_count, total_tty_write);
-+
-+ func_exit();
-+
-+ return tx_count;
-+}
-+
-+static int gtm501l_write_room(struct tty_struct *tty)
-+{
-+ struct gtm501l_port_data *port_data =
-+ (struct gtm501l_port_data *)tty->driver_data;
-+
-+ if (!port_data) {
-+ return -ENODEV;
-+ }
-+
-+ //func_enter();
-+
-+ return GTM501L_FIFO_SIZE - kfifo_len(port_data->tx_fifo);
-+}
-+
-+static void _gtm501l_set_termios(struct tty_struct *tty, struct ktermios *old)
-+{
-+ struct gtm501l_port_data *port_data =
-+ (struct gtm501l_port_data *)tty->driver_data;
-+ struct gtm501l_serial *serial;
-+ struct ktermios *termios;
-+
-+ if ((!tty) || (!tty->termios) || (!port_data)) {
-+ printk(KERN_ERR "%s: no tty structures", __func__);
-+ return;
-+ }
-+
-+ serial = &port_data->type.serial;
-+ /*
-+ * * The default requirements for this device are:
-+ * */
-+ termios = tty->termios;
-+ termios->c_iflag &= ~(IGNBRK /* disable ignore break */
-+ | BRKINT /* disable break causes interrupt */
-+ | PARMRK /* disable mark parity errors */
-+ | ISTRIP /* disable clear high bit of input characters */
-+ | INLCR /* disable translate NL to CR */
-+ | IGNCR /* disable ignore CR */
-+ | ICRNL /* disable translate CR to NL */
-+ | IXON); /* disable enable XON/XOFF flow control */
-+
-+ /* disable postprocess output characters */
-+ termios->c_oflag &= ~OPOST;
-+
-+ termios->c_lflag &= ~(ECHO /* disable echo input characters */
-+ | ECHONL /* disable echo new line */
-+ | ICANON /* disable erase, kill, werase, and rprnt
-+ special characters */
-+ | ISIG /* disable interrupt, quit, and suspend special
-+ characters */
-+ | IEXTEN); /* disable non-POSIX special characters */
-+
-+ termios->c_cflag &= ~(CSIZE /* no size */
-+ | PARENB /* disable parity bit */
-+ | CBAUD /* clear current baud rate */
-+ | CBAUDEX); /* clear current buad rate */
-+ termios->c_cflag |= CS8; /* character size 8 bits */
-+
-+ tty_encode_baud_rate(serial->tty, 115200, 115200);
-+ /*
-+ * Force low_latency on; otherwise the pushes are scheduled;
-+ * this is bad as it opens up the possibility of dropping bytes
-+ * on the floor. We don't want to drop bytes on the floor. :)
-+ */
-+ serial->tty->low_latency = 1;
-+ serial->tty->termios->c_cflag |= B115200; /* baud rate 115200 */
-+ return;
-+}
-+
-+static void gtm501l_set_termios(struct tty_struct *tty, struct ktermios *old)
-+{
-+ struct gtm501l_port_data *port_data =
-+ (struct gtm501l_port_data *)tty->driver_data;
-+ struct gtm501l_serial *serial;
-+
-+ func_enter();
-+
-+ if (!port_data) {
-+ func_exit();
-+ return;
-+ }
-+ serial = &port_data->type.serial;
-+
-+ /* the actual setup */
-+ if (serial->tty)
-+ _gtm501l_set_termios(tty, old);
-+ else
-+ tty->termios = old;
-+
-+ /* done */
-+ func_exit();
-+ return;
-+}
-+
-+static int gtm501l_chars_in_buffer(struct tty_struct *tty)
-+{
-+ struct gtm501l_port_data *port_data =
-+ (struct gtm501l_port_data *)tty->driver_data;
-+
-+ if (!port_data)
-+ return -ENODEV;
-+
-+ //func_enter();
-+
-+ return kfifo_len(port_data->tx_fifo);
-+}
-+
-+static struct mrst_spi_chip mrst_gtm501l = {
-+ .poll_mode = 0,
-+ .enable_dma = 1,
-+ .type = SPI_FRF_SPI,
-+};
-+
-+/* spi operations */
-+
-+static int gtm501l_spi_probe(struct spi_device *spi)
-+{
-+ struct gtm501l_device *gtm_dev;
-+ int i;
-+
-+ func_enter();
-+
-+ /* we check here only the SPI mode and correct them, if needed */
-+ if (GTM501L_SPI_MODE != (spi->mode & (SPI_CPHA | SPI_CPOL | SPI_CS_HIGH | SPI_LSB_FIRST | SPI_3WIRE))) {
-+ pr_warning("%s: SPI mode wrong setup, found %d, correct to %d\n",
-+ DRVNAME, spi->mode, GTM501L_SPI_MODE);
-+ spi->mode = GTM501L_SPI_MODE | (SPI_LOOP & spi->mode);
-+ }
-+
-+ if (spi->mode & SPI_LOOP) {
-+ pr_warning("%s: SPI device in loop back\n", DRVNAME);
-+ }
-+
-+ /* The Bit_per_word and the maximum speed has to be setup by us, the protocol driver */
-+ if(spi_b16)
-+ spi->bits_per_word = 16;
-+ else
-+ spi->bits_per_word = 8;
-+
-+ spi->max_speed_hz = GTM501L_SPI_SPEED;
-+
-+ spi->controller_data = &mrst_gtm501l;
-+
-+ if (spi_setup(spi)) {
-+ pr_err("%s: SPI setup does wasn't successful\n", DRVNAME);
-+ func_exit();
-+ return -ENODEV;
-+ }
-+
-+ /* initialize structure to hold our device variables */
-+ gtm_dev = kzalloc(sizeof(struct gtm501l_device), GFP_ATOMIC);
-+
-+ if (!gtm_dev) {
-+ func_exit();
-+ return -ENOMEM;
-+ }
-+ gtm_dev->spi_dev = spi;
-+ kref_init(&gtm_dev->ref);
-+
-+ /*initialize transfer and dma buffers */
-+ for(i = 0; i < 2; i++) {
-+ gtm_dev->tx_buffer[i] = kzalloc(GTM501L_TRANSFER_SIZE, GFP_KERNEL | GFP_DMA);
-+ if( 0 == gtm_dev->tx_buffer[i]) {
-+ pr_err("%s: DMA-TX[%d] buffer allocation failed\n", DRVNAME, i);
-+ func_exit();
-+ return -EIO;
-+ }
-+ }
-+ gtm_dev->rx_buffer = kzalloc(GTM501L_TRANSFER_SIZE, GFP_KERNEL | GFP_DMA);
-+ if( 0 == gtm_dev->rx_buffer) {
-+ pr_err("%s: DMA-RX buffer allocation failed\n", DRVNAME);
-+ func_exit();
-+ return -EIO;
-+ }
-+
-+ /* create our tty/net ports */
-+ gtm501l_create_ports(gtm_dev, gtm501l_default_port_spec);
-+
-+ spi_set_drvdata(spi, gtm_dev);
-+
-+ tasklet_init(&gtm_dev->io_work_tasklet,
-+ (void (*)(unsigned long))gtm501l_io,
-+ (unsigned long)gtm_dev);
-+
-+ init_timer(&gtm_dev->timer);
-+
-+#ifdef CONFIG_DEBUG_FS
-+ gtm501l_debugfs_init(gtm_dev);
-+#endif
-+
-+ /*
-+ * Init GPIO and IRQ, if at least the gpio parameter is set
-+ */
-+ if (gpio_in < 0)
-+ gpio_in = GTM501L_GPIO0;
-+
-+ if (request_irq(spi->irq, gtm501l_gpio_interrupt, GTM501L_IRQ_TYPE,
-+ "option", (void *)gtm_dev)) {
-+ kref_put(&gtm_dev->ref, gtm501l_free_device);
-+ func_exit();
-+ return -EIO;
-+ }
-+
-+ set_bit(GTM501L_STATE_PRESENT, &gtm_dev->flags);
-+ /*
-+ * Schedule tasklet once in case the gpio is active at probe time.
-+ * Otherwise wait for the next interrupt
-+ */
-+ gtm501l_gpio_interrupt(spi->irq, (void *)gtm_dev);
-+
-+ func_exit();
-+ return 0;
-+}
-+
-+static int gtm501l_spi_remove(struct spi_device *spi)
-+{
-+ struct gtm501l_device *gtm_dev =
-+ (struct gtm501l_device *)spi_get_drvdata(spi);
-+
-+ func_enter();
-+
-+ del_timer_sync(&gtm_dev->timer);
-+
-+ clear_bit(GTM501L_STATE_PRESENT, &gtm_dev->flags);
-+ free_irq(spi->irq, gtm_dev);
-+ kfree(gtm_dev->tx_buffer[0]);
-+ kfree(gtm_dev->tx_buffer[1]);
-+ kfree(gtm_dev->rx_buffer);
-+ spi_set_drvdata(spi, NULL);
-+ kref_put(&gtm_dev->ref, gtm501l_free_device);
-+
-+ func_exit();
-+ return 0;
-+}
-+
-+static void gtm501l_spi_shutdown(struct spi_device *spi)
-+{
-+ func_enter();
-+}
-+
-+static int gtm501l_spi_suspend(struct spi_device *spi, pm_message_t msg)
-+{
-+ func_enter();
-+ return 0;
-+}
-+
-+static int gtm501l_spi_resume(struct spi_device *spi)
-+{
-+ func_enter();
-+ return 0;
-+}
-+
-+static struct tty_operations gtm501l_serial_ops = {
-+ .open = gtm501l_open,
-+ .close = gtm501l_close,
-+ .write = gtm501l_write,
-+ .write_room = gtm501l_write_room,
-+ .set_termios = gtm501l_set_termios,
-+ .chars_in_buffer = gtm501l_chars_in_buffer,
-+ .tiocmget = gtm501l_tiocmget,
-+ .tiocmset = gtm501l_tiocmset,
-+ .throttle = gtm501l_throttle,
-+ .unthrottle = gtm501l_unthrottle
-+};
-+
-+static struct spi_driver gtm501l_spi_driver = {
-+ .driver = {
-+ .name = "spi_opt_modem",
-+ .bus = &spi_bus_type,
-+ .owner = THIS_MODULE
-+ },
-+ .probe = gtm501l_spi_probe,
-+ .remove = __devexit_p(gtm501l_spi_remove),
-+ .shutdown = gtm501l_spi_shutdown,
-+ .suspend = gtm501l_spi_suspend,
-+ .resume = gtm501l_spi_resume,
-+};
-+
-+/* module exit point */
-+static void __exit gtm501l_exit(void)
-+{
-+ func_enter();
-+ tty_unregister_driver(tty_drv);
-+ spi_unregister_driver(&gtm501l_spi_driver);
-+ dprintk(DEBUG_CLEANUP, "GTM501L driver removed\n");
-+ func_exit();
-+}
-+
-+/* module entry point */
-+static int __init gtm501l_init(void)
-+{
-+ int result = 0;
-+
-+ func_enter();
-+
-+/* gtm501l_pmic_init_voltages();*/
-+ gtm501l_pmic_set_wwandisablen(1);
-+
-+ gtm501l_pmic_set_wwanresetn(0);
-+ msleep(100);
-+ gtm501l_pmic_set_wwanresetn(1);
-+
-+ memset(gtm501l_serial_ports, 0, sizeof(gtm501l_serial_ports));
-+ memset(gtm501l_termios, 0, sizeof(gtm501l_termios));
-+ memset(gtm501l_termios_locked, 0, sizeof(gtm501l_termios_locked));
-+
-+ /* initialize lower-edge tty driver */
-+ tty_drv = alloc_tty_driver(GTM501L_MAX_MINORS);
-+ if (!tty_drv) {
-+ func_exit();
-+ return -ENOMEM;
-+ }
-+
-+ tty_drv->magic = TTY_DRIVER_MAGIC;
-+ tty_drv->owner = THIS_MODULE;
-+ tty_drv->driver_name = "gtm501l";
-+ tty_drv->name = "ttyGTM";
-+ tty_drv->minor_start = 0;
-+ tty_drv->num = GTM501L_MAX_MINORS;
-+ tty_drv->type = TTY_DRIVER_TYPE_SERIAL;
-+ tty_drv->subtype = SERIAL_TYPE_NORMAL;
-+ tty_drv->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
-+ tty_drv->init_termios = tty_std_termios;
-+ tty_drv->init_termios.c_cflag = B115200 | CS8 | CREAD | HUPCL | CLOCAL;
-+ tty_drv->termios = gtm501l_termios;
-+ tty_drv->termios_locked = gtm501l_termios_locked;
-+
-+ tty_set_operations(tty_drv, &gtm501l_serial_ops);
-+
-+ result = tty_register_driver(tty_drv);
-+ if (result) {
-+ printk(KERN_ERR "%s - tty_register_driver failed(%d)\n",
-+ __func__, result);
-+ func_exit();
-+ return result;
-+ }
-+
-+ /*
-+ initialize upper-edge spi driver. needs to be done after tty initialization because the spi probe will
-+ race
-+ */
-+ result = spi_register_driver(&gtm501l_spi_driver);
-+ if (result) {
-+ printk(KERN_ERR "%s - spi_register_driver failed(%d)\n",
-+ __func__, result);
-+ tty_unregister_driver(tty_drv);
-+ func_exit();
-+ return result;
-+ }
-+
-+ dprintk(DEBUG_INIT, "GTM501L driver initialized successfully\n");
-+ func_exit();
-+ return 0;
-+}
-+
-+static int gtm501l_net_open(struct net_device *net)
-+{
-+ struct gtm501l_port_data *port_data = net_to_gtm501l_data(net);
-+
-+ func_enter();
-+
-+ port_data->type.net.rx_state = WAIT_IP;
-+ port_data->type.net.sync_lost = 0;
-+ port_data->type.net.rx_buf_size = 0;
-+ port_data->type.net.rx_buf_missing = sizeof(struct iphdr);
-+
-+ /* update remote side it's ok to send us data */
-+ clear_bit(GTM501L_RX_FC, &port_data->signal_state);
-+ set_bit(GTM501L_UPDATE, &port_data->signal_state);
-+ netif_start_queue(net);
-+ func_exit();
-+ return 0;
-+}
-+
-+static int gtm501l_net_close(struct net_device *net)
-+{
-+ struct gtm501l_port_data *port_data = net_to_gtm501l_data(net);
-+
-+ func_enter();
-+
-+ /* stop remote side from sending us data */
-+ set_bit(GTM501L_RX_FC, &port_data->signal_state);
-+ set_bit(GTM501L_UPDATE, &port_data->signal_state);
-+ netif_stop_queue(net);
-+ func_exit();
-+ return 0;
-+}
-+
-+static void gtm501l_push_skb(struct gtm501l_port_data *port_data)
-+{
-+ struct gtm501l_net *gtm_net = &port_data->type.net;
-+ struct sk_buff *skb = gtm_net->tx_skb;
-+ unsigned int len;
-+
-+ func_enter();
-+
-+ if (skb && gtm_net->net->flags & IFF_UP) {
-+ len = kfifo_in(port_data->tx_fifo, skb->data, skb->len);
-+ skb_pull(skb, len);
-+ if (skb->len == 0) {
-+ // dev_kfree_skb(skb); // TODO: This causes a crash...
-+ gtm_net->tx_skb = NULL;
-+ netif_start_queue(gtm_net->net);
-+ }
-+ }
-+
-+ func_exit();
-+}
-+
-+static int gtm501l_net_start_xmit(struct sk_buff *skb, struct net_device *net)
-+{
-+ int result = 0;
-+ struct gtm501l_port_data *port_data = net_to_gtm501l_data(net);
-+ struct gtm501l_net *gtm_net = &port_data->type.net;
-+
-+ func_enter();
-+
-+ netif_stop_queue(net);
-+
-+ if (gtm_net->tx_skb) {
-+ printk(KERN_ERR "%s tx_skb not null\n", __func__);
-+ result = -EIO;
-+ } else {
-+ gtm_net->tx_skb = skb;
-+ gtm501l_push_skb(port_data);
-+ }
-+ if (result) {
-+ STATS(net).tx_errors++;
-+ netif_start_queue(net);
-+ } else {
-+ STATS(net).tx_packets++;
-+ STATS(net).tx_bytes += skb->len;
-+ /* And tell the kernel when the last transmit started. */
-+ net->trans_start = jiffies;
-+ }
-+ /* we're done */
-+ func_exit();
-+ return result;
-+}
-+
-+#ifndef NETDEVICE_HAS_STATS
-+static struct net_device_stats *gtm501l_net_get_stats(struct net_device *net)
-+{
-+ return &STATS(net);
-+}
-+#endif
-+
-+/* called when a packet did not ack after watchdogtimeout */
-+static void gtm501l_net_tx_timeout(struct net_device *net)
-+{
-+ func_enter();
-+
-+ /* Tell syslog we are hosed. */
-+ dev_warn(&net->dev, "Tx timed out.\n");
-+
-+ /* Update statistics */
-+ STATS(net).tx_errors++;
-+
-+ func_exit();
-+}
-+
-+static const struct net_device_ops gtm501l_netdev_ops = {
-+ .ndo_open = gtm501l_net_open,
-+ .ndo_stop = gtm501l_net_close,
-+ .ndo_start_xmit = gtm501l_net_start_xmit,
-+#ifndef NETDEVICE_HAS_STATS
-+ .ndo_get_stats = gtm501l_net_get_stats,
-+#endif
-+ .ndo_tx_timeout = gtm501l_net_tx_timeout,
-+};
-+
-+static void gtm501l_net_init(struct net_device *net)
-+{
-+ func_enter();
-+
-+ /* fill in the other fields */
-+ net->netdev_ops = &gtm501l_netdev_ops;
-+ net->watchdog_timeo = GTM501L_NET_TX_TIMEOUT;
-+ net->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
-+ net->type = ARPHRD_NONE;
-+ net->mtu = GTM501L_DEFAULT_MTU;
-+ net->tx_queue_len = 10;
-+
-+ func_exit();
-+}
-+
-+struct gtm501l_device *gtm501l_set_stats_ops(struct gtm501_stats_ops *stats)
-+{
-+ struct gtm501l_device *gtm_dev = NULL;
-+ int i;
-+
-+ /* Look for gtm_dev */
-+ for (i = 0; i < GTM501L_MAX_MINORS; i++) {
-+ if (gtm501l_serial_ports[i] &&
-+ gtm501l_serial_ports[i]->spi_itf) {
-+ gtm_dev = gtm501l_serial_ports[i]->spi_itf;
-+ break;
-+ }
-+ }
-+
-+ if(gtm_dev)
-+ gtm_dev->stats = stats;
-+
-+ return gtm_dev;
-+}
-+
-+/* module definitions */
-+module_init(gtm501l_init);
-+module_exit(gtm501l_exit);
-+
-+module_param_named(backoff, backoff_enabled, uint, S_IRUGO);
-+MODULE_PARM_DESC(backoff, "Enable (1) or disable (0) backoff timer.");
-+
-+module_param_named(gpi, gpio_in, uint, S_IRUGO);
-+MODULE_PARM_DESC(gpi, "GPIO input base address. (default: -1 => automatic)");
-+
-+module_param_named(b16, spi_b16, bool, S_IRUGO);
-+MODULE_PARM_DESC(b16, "SPI 16Bit/word or 8Bit/word, default 16Bit");
-+
-+#ifdef DEBUG
-+module_param_named(debug, gtm501l_debug, uint, S_IRUGO);
-+MODULE_PARM_DESC(debug, "Debug flags");
-+#endif
-+
-+MODULE_AUTHOR("Option Wireless");
-+MODULE_DESCRIPTION("GTM501L spi driver");
-+MODULE_LICENSE("GPL");
-+MODULE_INFO(Version, "0.5pre1-option");
-+
-+EXPORT_SYMBOL_GPL(gtm501l_debug);
-+EXPORT_SYMBOL_GPL(gtm501l_debug_printk);
-+EXPORT_SYMBOL_GPL(gtm501l_set_stats_ops);
-+
-Index: linux-2.6.33/drivers/spi/gtm501l_spi.h
-===================================================================
---- /dev/null
-+++ linux-2.6.33/drivers/spi/gtm501l_spi.h
-@@ -0,0 +1,329 @@
-+/****************************************************************************
-+ *
-+ * Driver for the Option GTM501L spi modem.
-+ *
-+ * Copyright (C) 2008 Option International
-+ * Copyright (C) 2008 Filip Aben <f.aben@option.com>
-+ * Denis Joseph Barrow <d.barow@option.com>
-+ * Jan Dumon <j.dumon@option.com>
-+ *
-+ * This program is free software; you can redistribute it and/or modify
-+ * it under the terms of the GNU General Public License version 2 as
-+ * published by the Free Software Foundation.
-+ *
-+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
-+ * USA
-+ *
-+ *
-+ *
-+ *****************************************************************************/
-+
-+#ifndef _GTM501L_SPI_H
-+#define _GTM501L_SPI_H
-+#include <linux/version.h>
-+#include <linux/tty.h>
-+#include <linux/device.h>
-+#include <linux/spi/spi.h>
-+
-+#include <linux/netdevice.h>
-+#include <linux/ip.h>
-+
-+#define DRVNAME "gtm501l"
-+
-+#define DEBUG
-+
-+#ifdef DEBUG
-+#define DEBUG_FLOW (1 << 0)
-+#define DEBUG_INIT (1 << 1)
-+#define DEBUG_CLEANUP (1 << 2)
-+#define DEBUG_TTY (1 << 3)
-+#define DEBUG_NET (1 << 4)
-+#define DEBUG_MUX (1 << 5)
-+#define DEBUG_DEMUX (1 << 6)
-+#define DEBUG_SPI (1 << 7)
-+#define DEBUG_GPIO (1 << 8)
-+
-+#define dprintk(f, str...) if(gtm501l_debug & f) gtm501l_debug_printk(__func__, __LINE__, str)
-+
-+#define GTM501L_BUFFER_DUMP(prefix_str,buf,len) \
-+ print_hex_dump(KERN_DEBUG,prefix_str, DUMP_PREFIX_OFFSET,16,1,buf,len,1)
-+
-+void gtm501l_debug_printk(const char *function, int line, char *format, ...);
-+extern int gtm501l_debug;
-+
-+#else
-+#define dprintk(f, str...)
-+#define GTM501L_BUFFER_DUMP(prefix_str,buf,len)
-+#endif
-+
-+#define func_enter() dprintk(DEBUG_FLOW, "enter\n")
-+#define func_exit() dprintk(DEBUG_FLOW, "exit\n")
-+
-+#define GTM501L_DEFAULT_MTU 1500
-+#define GTM501L_DEFAULT_MRU 2500
-+#define GTM501L_NET_TX_TIMEOUT (HZ * 10)
-+
-+#define GTM501L_IRQ_TYPE IRQ_TYPE_EDGE_FALLING
-+#define GTM501L_GPIO_TARGET 0
-+#define GTM501L_GPIO0 0x3c /* default use Langwell GPIO60 */
-+
-+/* various macro definitions */
-+#define GTM501L_MAX_MINORS 256
-+#define GTM501L_PORT_PER_DEV 16
-+#define GTM501L_TRANSFER_SIZE 2040
-+/* GTM501l_THROTTLE_FIFO_SIZE must be a power of 2
-+ * & larger than GTM501L_TRANSFER_SIZE */
-+#define GTM501l_THROTTLE_FIFO_SIZE 4096
-+#define GTM501L_FIFO_SIZE 4096
-+
-+/* device flags bitfield definitions */
-+#define GTM501L_STATE_PRESENT 0
-+#define GTM501L_STATE_IO_IN_PROGRESS 1
-+#define GTM501L_STATE_IO_READY 2
-+
-+#define MUX_CHANNEL(x) ((x >> MUX_CHANNEL_SHIFT) & 0xF)
-+#define MUX_CHANNEL_SHIFT 0
-+#define MUX_BLOCK_TYPE(x) ((x >> MUX_BLOCK_TYPE_SHIFT) & 0x3)
-+#define MUX_BLOCK_TYPE_SHIFT 4
-+#define MUX_DEVICE(x) ((x >> MUX_DEVICE_SHIFT) & 0x3)
-+#define MUX_DEVICE_SHIFT 6
-+#define MUX_BURST_SIZE 512
-+
-+#define MUX_DATA_TRANSFER 0
-+#define MUX_BURST_TRANSFER 1
-+#define MUX_CONTROL_TRANSFER 2
-+
-+#define MUX_CONTROL_BYTE(channel,type,device) ( \
-+ (channel<<MUX_CHANNEL_SHIFT) | \
-+ (type<<MUX_BLOCK_TYPE_SHIFT) | \
-+ (device<<MUX_DEVICE_SHIFT) \
-+ )
-+
-+#define MUX_DCD(x) ((x >> MUX_DCD_SHIFT) & 0x1)
-+#define MUX_DCD_SHIFT 0
-+#define MUX_CTS(x) ((x >> MUX_CTS_SHIFT) & 0x1)
-+#define MUX_CTS_SHIFT 1
-+#define MUX_DSR(x) ((x >> MUX_DSR_SHIFT) & 0x1)
-+#define MUX_DSR_SHIFT 2
-+#define MUX_RI(x) ((x >> MUX_RI_SHIFT) & 0x1)
-+#define MUX_RI_SHIFT 3
-+#define MUX_DTR(x) ((x >> MUX_DTR_SHIFT) & 0x1)
-+#define MUX_DTR_SHIFT 4
-+#define MUX_RTS(x) ((x >> MUX_RTS_SHIFT) & 0x1)
-+#define MUX_RTS_SHIFT 5
-+#define MUX_LINK(x) ((x >> MUX_LINK_SHIFT) & 0x1)
-+#define MUX_LINK_SHIFT 7
-+
-+#define MUX_INVALID 0
-+#define MUX_SLAVE_TO_MASTER 1
-+#define MUX_MASTER_TO_SLAVE 2
-+#define MUX_INVALID2 3
-+
-+#define GTM501L_SPI_MODE SPI_MODE_1 /* SPI Mode 1 currently used */
-+
-+#define GTM501L_SPI_SPEED 12500000
-+
-+/* flow control bitfields */
-+#define GTM501L_DCD 0
-+#define GTM501L_CTS 1
-+#define GTM501L_DSR 2
-+#define GTM501L_RI 3
-+#define GTM501L_DTR 4
-+#define GTM501L_RTS 5
-+#define GTM501L_TX_FC 6
-+#define GTM501L_RX_FC 7
-+#define GTM501L_UPDATE 8
-+
-+#define GTM501L_MAX_EMPTY 500
-+#define GTM501L_BACKOFF_TIMER (HZ / 2)
-+
-+struct gtm501l_device {
-+ struct spi_device *spi_dev;
-+ struct kref ref;
-+ struct gtm501l_port_data *port_data[GTM501L_PORT_PER_DEV];
-+ struct tasklet_struct io_work_tasklet;
-+ unsigned long flags;
-+ dma_addr_t rx_dma;
-+ dma_addr_t tx_dma[2];
-+
-+ unsigned char *rx_buffer;
-+ unsigned char *tx_buffer[2];
-+ int tx_buffer_used;
-+ int tx_count;
-+
-+ struct spi_message spi_msg;
-+ struct spi_transfer spi_xfer;
-+
-+ int gpio_irq;
-+ int round_robin_index;
-+
-+ struct timer_list timer;
-+ int empty_transfers;
-+
-+#ifdef CONFIG_DEBUG_FS
-+ struct dentry *debugfs; /* debugfs parent directory */
-+ struct gtm501l_frame_stats *frame_stats;
-+#endif
-+
-+ struct gtm501_stats_ops *stats;
-+};
-+
-+struct gtm501l_serial {
-+ struct device *dev;
-+ struct tty_struct *tty;
-+ struct kfifo *throttle_fifo;
-+ spinlock_t throttle_fifo_lock;
-+ int minor;
-+ int open;
-+};
-+
-+enum rx_parse_state {
-+ syncing,
-+ getting_frame_len,
-+ filling_skb,
-+ WAIT_IP,
-+ WAIT_DATA,
-+ WAIT_SYNC
-+};
-+
-+#undef NETDEVICE_HAS_STATS
-+
-+struct gtm501l_net {
-+ enum rx_parse_state rx_state;
-+ int sync_lost;
-+ struct sk_buff *tx_skb;
-+ struct sk_buff *rx_skb;
-+ unsigned short rx_frame_len;
-+ struct net_device *net;
-+ unsigned short rx_buf_size;
-+ unsigned short rx_buf_missing;
-+ struct iphdr rx_ip_hdr;
-+#ifndef NETDEVICE_HAS_STATS
-+ struct net_device_stats stats;
-+#endif
-+};
-+
-+#define GTM501L_PORT_SPEC_SERIAL 0
-+#define GTM501L_PORT_SPEC_NET 1
-+
-+struct gtm501l_port_spec {
-+ int enabled;
-+ int type;
-+ char name[16];
-+};
-+
-+struct gtm501l_port_data {
-+ struct gtm501l_device *spi_itf;
-+ int port_id;
-+ struct gtm501l_port_spec spec;
-+ struct kfifo *tx_fifo;
-+ spinlock_t fifo_lock;
-+ unsigned long signal_state;
-+ union {
-+ struct gtm501l_serial serial;
-+ struct gtm501l_net net;
-+ } type;
-+};
-+
-+#define net_to_gtm501l_data(net) *((struct gtm501l_port_data **)netdev_priv(net))
-+
-+#ifdef NETDEVICE_HAS_STATS
-+#define STATS(net) ((net)->stats)
-+#else
-+#define STATS(net) (((struct gtm501l_port_data *)net_to_gtm501l_data(net))->type.net.stats)
-+#endif
-+
-+#ifdef CONFIG_DEBUG_FS
-+
-+/**
-+ * transfer SPI frame sequence, can be used for global sequence state or for per CPU seq state variable
-+ */
-+enum gtm501l_fsequence { /* frame sequence start states */
-+ none, /* undefined state */
-+ idle, /* idle state host driver waits */
-+ encode, /* encoding SPI frame */
-+ encode_interrupt_decode, /* encoding SPI frame started and interrupts decoding frame */
-+ decode, /* decoding SPI frame */
-+ decode_interrupt_encode /* decoding SPI frame started and interrupts decoding frame */
-+};
-+
-+/**
-+ * job time with the support for interrupt time correction, which me be used only for encoding and decoding time
-+ * measurements
-+ */
-+struct gtm501l_jtime { /* job time */
-+ ktime_t start; /* start time for that job */
-+ ktime_t correct; /* correction time, if job was interrupted */
-+ u32 dt; /* delta time need for that job in us */
-+ u32 min_dt; /* min time need for that job is us */
-+ u32 max_dt; /* max time need for that job is us */
-+ u64 total; /* total time need for that job is us */
-+ u32 bug; /* bug counter for negative time delta */
-+};
-+
-+/**
-+ * frame statistics
-+ */
-+struct gtm501l_frame_stats { /* frame transfer statistics */
-+ spinlock_t lock; /* lock for that structure */
-+ enum gtm501l_fsequence seq[NR_CPUS]; /* current sequence for each CPU separate */
-+ struct gtm501l_jtime idle; /* timings for idle, just waiting for the application or GTM501L become busy */
-+ struct gtm501l_jtime encode; /* timings for encoding SPI frame */
-+ struct gtm501l_jtime transceive; /* timings for tranceiving SPI frame */
-+ struct gtm501l_jtime decode; /* timings for decoding SPI frame */
-+ struct gtm501l_jtime wait; /* timings for waiting for GTM501L become ready */
-+ struct gtm501l_jtime cycle; /* timings for a SPI frame cycle without idle time */
-+ struct kfifo *transmit_id_pipe; /* fifo pipe frame id to transmit task */
-+ struct kfifo *decode_id_pipe; /* fifo pipe frame id to decode task */
-+ struct kfifo *decode_txb_pipe; /* fifo pipe number of transmit byte to decode task for analysis */
-+ struct kfifo *decode_dt_pipe; /* fifo pipe SPI frame transfer time to decode task for analysis */
-+ u32 transmit_id; /* id and number of transmit SPI frames */
-+ u32 receive_id; /* id and number of received SPI frames */
-+ u32 encode_start_id; /* id and number of started encoded frames */
-+ u32 encode_end_id; /* id and number of finished encoded frames */
-+ u32 decode_start_id; /* id and number of started decoded frames */
-+ u32 decode_end_id; /* id and number of started decoded frames */
-+ u32 idles; /* number of entered idle states */
-+ u32 waits; /* number of entered wait states */
-+ u32 max_tx_bytes; /* maximum transmitted bytes in a frame */
-+ u32 max_rx_bytes; /* maximum received bytes in a frame */
-+ u64 total_tx_bytes; /* total transmitted bytes in a frame for calculating average */
-+ u64 total_rx_bytes; /* total received bytes in a frame for calculating average */
-+ u32 first_tx_bytes; /* first transmitted bytes in a frame for calculating average */
-+ u32 first_rx_bytes; /* first received bytes in a frame for calculating average */
-+ u32 max_tx_rate; /* maximum transmitted bytes per time rate in bytes/sec */
-+ u32 max_rx_rate; /* maximum received bytes per time rate in bytes/sec */
-+ u32 encode_pass_decode; /* encode task pass decode task */
-+ u32 encode_interrupts_decode; /* encode task interrupts decode task on the same CPU */
-+ u32 decode_pass_encode; /* decode task pass encode task */
-+ u32 decode_interrupts_encode; /* decode task interrupts encode task on the same CPU */
-+ u32 encode_bug; /* number of counted bugs for encode process */
-+ int encode_buffers_used; /* number of need encode buffers */
-+ u32 decode_bug; /* number of counted bugs for the decode process */
-+ int decode_buffers_used; /* number of need decode buffers */
-+ struct dentry *debugfs; /* debugfs entry for the frame_stats file */
-+};
-+
-+#endif
-+
-+struct gtm501_stats_ops {
-+ void (*wait_finished)(struct gtm501l_frame_stats *fstats);
-+ void (*encode_start_idle_finished)(struct gtm501l_frame_stats *fstats);
-+ void (*encode_finished)(struct gtm501l_frame_stats *fstats, unsigned int tx_bytes);
-+ void (*transfer_start)(struct gtm501l_frame_stats *fstats);
-+ void (*transfer_finished_wait_start)(struct gtm501l_frame_stats *fstats);
-+ void (*transfer_decode_start)(struct gtm501l_frame_stats *fstats);
-+ void (*decode_finished_may_idle_start)(struct gtm501l_frame_stats *fstats, unsigned int rx_bytes);
-+};
-+
-+/* Prototypes */
-+struct gtm501l_device *gtm501l_set_stats_ops(struct gtm501_stats_ops *stats);
-+
-+#endif