diff options
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.patch | 2395 |
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, >m501l_gpio_operations); -+ debugfs_create_file("pmic", S_IFREG | S_IRUGO, -+ gtm_dev->debugfs, NULL, >m501l_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 *)>m_dev->flags); -+#ifdef DEBUG -+ debugfs_create_x32("debug", S_IFREG | S_IRUGO, -+ gtm_dev->debugfs, >m501l_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(®_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 *)(>m_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, >m_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, >m_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(>m_dev->timer)) { -+ gtm_dev->timer.expires = jiffies + GTM501L_BACKOFF_TIMER; -+ gtm_dev->timer.function = gtm501l_timer; -+ gtm_dev->timer.data = (unsigned long)>m_dev->io_work_tasklet; -+ add_timer(>m_dev->timer); -+ } -+ } -+ else -+ tasklet_hi_schedule(>m_dev->io_work_tasklet); -+ } -+ else set_bit(GTM501L_STATE_IO_READY, >m_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, >m_dev->flags)) -+ return; -+ -+ if (!test_and_set_bit(GTM501L_STATE_IO_IN_PROGRESS, >m_dev->flags)) { -+ gtm501l_prepare_tx_buffer(gtm_dev); -+ -+ if(gtm_dev->stats) gtm_dev->stats->transfer_start(gtm_dev->frame_stats); -+ -+ spi_message_init(>m_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(>m_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(>m_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(>m_dev->spi_xfer, >m_dev->spi_msg); -+ -+ retval = spi_async(gtm_dev->spi_dev, >m_dev->spi_msg); -+ -+ if (retval) { -+ dprintk(DEBUG_SPI, "ERROR: spi_async failed (%d)\n", retval); -+ clear_bit(GTM501L_STATE_IO_IN_PROGRESS, -+ >m_dev->flags); -+ tasklet_hi_schedule(>m_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, >m501l_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, -+ >m_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(>m_ser->throttle_fifo_lock); -+ lockdep_set_class_and_subclass(>m_ser->throttle_fifo_lock, >m501l_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(>m_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, >m_dev->flags)) -+ return; -+ -+ if (!gtm_dev->spi_msg.status) { -+#if 0 -+ dma_unmap_single(>m_dev->spi_dev->dev, -+ gtm_dev->tx_dma[(gtm_dev->tx_buffer_used + 1) % 2], -+ GTM501L_TRANSFER_SIZE, DMA_TO_DEVICE); -+ dma_unmap_single(>m_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, >m_dev->flags); -+ -+ //gtm501l_prepare_tx_buffer(gtm_dev); -+ -+ if(test_and_clear_bit(GTM501L_STATE_IO_READY, >m_dev->flags)) -+ tasklet_hi_schedule(>m_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(>m_dev->timer)) { -+ del_timer_sync(>m_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(>m_dev->timer)) { -+ del_timer_sync(>m_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(>m_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(>m_dev->io_work_tasklet, -+ (void (*)(unsigned long))gtm501l_io, -+ (unsigned long)gtm_dev); -+ -+ init_timer(>m_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(>m_dev->ref, gtm501l_free_device); -+ func_exit(); -+ return -EIO; -+ } -+ -+ set_bit(GTM501L_STATE_PRESENT, >m_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(>m_dev->timer); -+ -+ clear_bit(GTM501L_STATE_PRESENT, >m_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(>m_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(>m501l_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, >m501l_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(>m501l_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 = >m501l_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 |