[WATCHDOG] omap_wdt.c - default error for IOCTL is -ENOTTY
[safe/jmp/linux-2.6] / drivers / char / synclink_gt.c
index 2b9cde9..372a37e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: synclink_gt.c,v 4.20 2005/11/08 19:51:55 paulkf Exp $
+ * $Id: synclink_gt.c,v 4.36 2006/08/28 20:47:14 paulkf Exp $
  *
  * Device driver for Microgate SyncLink GT serial adapters.
  *
@@ -46,7 +46,6 @@
 //#define DBGRBUF(info) dump_rbufs(info)
 
 
-#include <linux/config.h>
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/errno.h>
@@ -75,7 +74,6 @@
 #include <linux/workqueue.h>
 #include <linux/hdlc.h>
 
-#include <asm/serial.h>
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
 
 #include "linux/synclink.h"
 
-#ifdef CONFIG_HDLC_MODULE
-#define CONFIG_HDLC 1
+#if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_GT_MODULE))
+#define SYNCLINK_GENERIC_HDLC 1
+#else
+#define SYNCLINK_GENERIC_HDLC 0
 #endif
 
 /*
  * module identification
  */
 static char *driver_name     = "SyncLink GT";
-static char *driver_version  = "$Revision: 4.20 $";
+static char *driver_version  = "$Revision: 4.36 $";
 static char *tty_driver_name = "synclink_gt";
 static char *tty_dev_prefix  = "ttySLG";
 MODULE_LICENSE("GPL");
 #define MGSL_MAGIC 0x5401
-#define MAX_DEVICES 12
+#define MAX_DEVICES 32
 
 static struct pci_device_id pci_table[] = {
        {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
+       {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT2_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
        {PCI_VENDOR_ID_MICROGATE, SYNCLINK_GT4_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
        {PCI_VENDOR_ID_MICROGATE, SYNCLINK_AC_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,},
        {0,}, /* terminate list */
@@ -143,14 +144,12 @@ MODULE_PARM_DESC(dosyncppp, "Enable synchronous net device, 0=disable 1=enable")
 /*
  * tty support and callbacks
  */
-#define RELEVANT_IFLAG(iflag) (iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK))
-
 static struct tty_driver *serial_driver;
 
 static int  open(struct tty_struct *tty, struct file * filp);
 static void close(struct tty_struct *tty, struct file * filp);
 static void hangup(struct tty_struct *tty);
-static void set_termios(struct tty_struct *tty, struct termios *old_termios);
+static void set_termios(struct tty_struct *tty, struct ktermios *old_termios);
 
 static int  write(struct tty_struct *tty, const unsigned char *buf, int count);
 static void put_char(struct tty_struct *tty, unsigned char ch);
@@ -172,7 +171,7 @@ static void set_break(struct tty_struct *tty, int break_state);
 /*
  * generic HDLC support and callbacks
  */
-#ifdef CONFIG_HDLC
+#if SYNCLINK_GENERIC_HDLC
 #define dev_to_port(D) (dev_to_hdlc(D)->priv)
 static void hdlcdev_tx_done(struct slgt_info *info);
 static void hdlcdev_rx(struct slgt_info *info, char *buf, int size);
@@ -189,6 +188,20 @@ static void hdlcdev_exit(struct slgt_info *info);
 #define SLGT_REG_SIZE  256
 
 /*
+ * conditional wait facility
+ */
+struct cond_wait {
+       struct cond_wait *next;
+       wait_queue_head_t q;
+       wait_queue_t wait;
+       unsigned int data;
+};
+static void init_cond_wait(struct cond_wait *w, unsigned int data);
+static void add_cond_wait(struct cond_wait **head, struct cond_wait *w);
+static void remove_cond_wait(struct cond_wait **head, struct cond_wait *w);
+static void flush_cond_wait(struct cond_wait **head);
+
+/*
  * DMA buffer descriptor and access macros
  */
 struct slgt_desc
@@ -270,6 +283,9 @@ struct slgt_info {
        struct timer_list       tx_timer;
        struct timer_list       rx_timer;
 
+       unsigned int            gpio_present;
+       struct cond_wait        *gpio_wait_q;
+
        spinlock_t lock;        /* spinlock for synchronizing with ISR */
 
        struct work_struct task;
@@ -289,7 +305,6 @@ struct slgt_info {
 
        unsigned char __iomem * reg_addr;  /* memory mapped registers address */
        u32 phys_reg_addr;
-       u32 reg_offset;
        int reg_addr_requested;
 
        MGSL_PARAMS params;       /* communications parameters */
@@ -308,7 +323,7 @@ struct slgt_info {
        int tx_active;
 
        unsigned char signals;    /* serial signal states */
-       unsigned int init_error;  /* initialization error */
+       int init_error;  /* initialization error */
 
        unsigned char *tx_buf;
        int tx_count;
@@ -344,7 +359,7 @@ struct slgt_info {
        int netcount;
        int dosyncppp;
        spinlock_t netlock;
-#ifdef CONFIG_HDLC
+#if SYNCLINK_GENERIC_HDLC
        struct net_device *netdev;
 #endif
 
@@ -376,11 +391,16 @@ static MGSL_PARAMS default_params = {
 #define DESC_LIST_SIZE 4096
 
 #define MASK_PARITY  BIT1
-#define MASK_FRAMING BIT2
-#define MASK_BREAK   BIT3
+#define MASK_FRAMING BIT0
+#define MASK_BREAK   BIT14
 #define MASK_OVERRUN BIT4
 
 #define GSR   0x00 /* global status */
+#define JCR   0x04 /* JTAG control */
+#define IODR  0x08 /* GPIO direction */
+#define IOER  0x0c /* GPIO interrupt enable */
+#define IOVR  0x10 /* GPIO value */
+#define IOSR  0x14 /* GPIO interrupt status */
 #define TDR   0x80 /* tx data */
 #define RDR   0x80 /* rx data */
 #define TCR   0x82 /* tx control */
@@ -441,7 +461,7 @@ static int  adapter_test(struct slgt_info *info);
 static void reset_adapter(struct slgt_info *info);
 static void reset_port(struct slgt_info *info);
 static void async_mode(struct slgt_info *info);
-static void hdlc_mode(struct slgt_info *info);
+static void sync_mode(struct slgt_info *info);
 
 static void rx_stop(struct slgt_info *info);
 static void rx_start(struct slgt_info *info);
@@ -465,13 +485,13 @@ static void enable_loopback(struct slgt_info *info);
 static void set_rate(struct slgt_info *info, u32 data_rate);
 
 static int  bh_action(struct slgt_info *info);
-static void bh_handler(void* context);
+static void bh_handler(struct work_struct *work);
 static void bh_transmit(struct slgt_info *info);
 static void isr_serial(struct slgt_info *info);
 static void isr_rdma(struct slgt_info *info);
 static void isr_txeom(struct slgt_info *info, unsigned short status);
 static void isr_tdma(struct slgt_info *info);
-static irqreturn_t slgt_interrupt(int irq, void *dev_id, struct pt_regs * regs);
+static irqreturn_t slgt_interrupt(int irq, void *dev_id);
 
 static int  alloc_dma_bufs(struct slgt_info *info);
 static void free_dma_bufs(struct slgt_info *info);
@@ -505,6 +525,9 @@ static int  tiocmset(struct tty_struct *tty, struct file *file,
 static void set_break(struct tty_struct *tty, int break_state);
 static int  get_interface(struct slgt_info *info, int __user *if_mode);
 static int  set_interface(struct slgt_info *info, int if_mode);
+static int  set_gpio(struct slgt_info *info, struct gpio_desc __user *gpio);
+static int  get_gpio(struct slgt_info *info, struct gpio_desc __user *gpio);
+static int  wait_gpio(struct slgt_info *info, struct gpio_desc __user *gpio);
 
 /*
  * driver functions
@@ -791,19 +814,13 @@ static void hangup(struct tty_struct *tty)
        wake_up_interruptible(&info->open_wait);
 }
 
-static void set_termios(struct tty_struct *tty, struct termios *old_termios)
+static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 {
        struct slgt_info *info = tty->driver_data;
        unsigned long flags;
 
        DBGINFO(("%s set_termios\n", tty->driver->name));
 
-       /* just return if nothing has changed */
-       if ((tty->termios->c_cflag == old_termios->c_cflag)
-           && (RELEVANT_IFLAG(tty->termios->c_iflag)
-               == RELEVANT_IFLAG(old_termios->c_iflag)))
-               return;
-
        change_params(info);
 
        /* Handle transition to B0 status */
@@ -847,7 +864,7 @@ static int write(struct tty_struct *tty,
                goto cleanup;
        DBGINFO(("%s write count=%d\n", info->device_name, count));
 
-       if (!tty || !info->tx_buf)
+       if (!info->tx_buf)
                goto cleanup;
 
        if (count > info->max_frame_size) {
@@ -858,7 +875,9 @@ static int write(struct tty_struct *tty,
        if (!count)
                goto cleanup;
 
-       if (info->params.mode == MGSL_MODE_RAW) {
+       if (info->params.mode == MGSL_MODE_RAW ||
+           info->params.mode == MGSL_MODE_MONOSYNC ||
+           info->params.mode == MGSL_MODE_BISYNC) {
                unsigned int bufs_needed = (count/DMABUFSIZE);
                unsigned int bufs_free = free_tbuf_count(info);
                if (count % DMABUFSIZE)
@@ -901,7 +920,7 @@ static void put_char(struct tty_struct *tty, unsigned char ch)
        if (sanity_check(info, tty->name, "put_char"))
                return;
        DBGINFO(("%s put_char(%d)\n", info->device_name, ch));
-       if (!tty || !info->tx_buf)
+       if (!info->tx_buf)
                return;
        spin_lock_irqsave(&info->lock,flags);
        if (!info->tx_active && (info->tx_count < info->max_frame_size))
@@ -1018,7 +1037,6 @@ static void flush_buffer(struct tty_struct *tty)
                info->tx_count = 0;
        spin_unlock_irqrestore(&info->lock,flags);
 
-       wake_up_interruptible(&tty->write_wait);
        tty_wakeup(tty);
 }
 
@@ -1114,6 +1132,12 @@ static int ioctl(struct tty_struct *tty, struct file *file,
                return get_interface(info, argp);
        case MGSL_IOCSIF:
                return set_interface(info,(int)arg);
+       case MGSL_IOCSGPIO:
+               return set_gpio(info, argp);
+       case MGSL_IOCGGPIO:
+               return get_gpio(info, argp);
+       case MGSL_IOCWAITGPIO:
+               return wait_gpio(info, argp);
        case TIOCGICOUNT:
                spin_lock_irqsave(&info->lock,flags);
                cnow = info->icount;
@@ -1139,6 +1163,112 @@ static int ioctl(struct tty_struct *tty, struct file *file,
 }
 
 /*
+ * support for 32 bit ioctl calls on 64 bit systems
+ */
+#ifdef CONFIG_COMPAT
+static long get_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *user_params)
+{
+       struct MGSL_PARAMS32 tmp_params;
+
+       DBGINFO(("%s get_params32\n", info->device_name));
+       tmp_params.mode            = (compat_ulong_t)info->params.mode;
+       tmp_params.loopback        = info->params.loopback;
+       tmp_params.flags           = info->params.flags;
+       tmp_params.encoding        = info->params.encoding;
+       tmp_params.clock_speed     = (compat_ulong_t)info->params.clock_speed;
+       tmp_params.addr_filter     = info->params.addr_filter;
+       tmp_params.crc_type        = info->params.crc_type;
+       tmp_params.preamble_length = info->params.preamble_length;
+       tmp_params.preamble        = info->params.preamble;
+       tmp_params.data_rate       = (compat_ulong_t)info->params.data_rate;
+       tmp_params.data_bits       = info->params.data_bits;
+       tmp_params.stop_bits       = info->params.stop_bits;
+       tmp_params.parity          = info->params.parity;
+       if (copy_to_user(user_params, &tmp_params, sizeof(struct MGSL_PARAMS32)))
+               return -EFAULT;
+       return 0;
+}
+
+static long set_params32(struct slgt_info *info, struct MGSL_PARAMS32 __user *new_params)
+{
+       struct MGSL_PARAMS32 tmp_params;
+
+       DBGINFO(("%s set_params32\n", info->device_name));
+       if (copy_from_user(&tmp_params, new_params, sizeof(struct MGSL_PARAMS32)))
+               return -EFAULT;
+
+       spin_lock(&info->lock);
+       info->params.mode            = tmp_params.mode;
+       info->params.loopback        = tmp_params.loopback;
+       info->params.flags           = tmp_params.flags;
+       info->params.encoding        = tmp_params.encoding;
+       info->params.clock_speed     = tmp_params.clock_speed;
+       info->params.addr_filter     = tmp_params.addr_filter;
+       info->params.crc_type        = tmp_params.crc_type;
+       info->params.preamble_length = tmp_params.preamble_length;
+       info->params.preamble        = tmp_params.preamble;
+       info->params.data_rate       = tmp_params.data_rate;
+       info->params.data_bits       = tmp_params.data_bits;
+       info->params.stop_bits       = tmp_params.stop_bits;
+       info->params.parity          = tmp_params.parity;
+       spin_unlock(&info->lock);
+
+       change_params(info);
+
+       return 0;
+}
+
+static long slgt_compat_ioctl(struct tty_struct *tty, struct file *file,
+                        unsigned int cmd, unsigned long arg)
+{
+       struct slgt_info *info = tty->driver_data;
+       int rc = -ENOIOCTLCMD;
+
+       if (sanity_check(info, tty->name, "compat_ioctl"))
+               return -ENODEV;
+       DBGINFO(("%s compat_ioctl() cmd=%08X\n", info->device_name, cmd));
+
+       switch (cmd) {
+
+       case MGSL_IOCSPARAMS32:
+               rc = set_params32(info, compat_ptr(arg));
+               break;
+
+       case MGSL_IOCGPARAMS32:
+               rc = get_params32(info, compat_ptr(arg));
+               break;
+
+       case MGSL_IOCGPARAMS:
+       case MGSL_IOCSPARAMS:
+       case MGSL_IOCGTXIDLE:
+       case MGSL_IOCGSTATS:
+       case MGSL_IOCWAITEVENT:
+       case MGSL_IOCGIF:
+       case MGSL_IOCSGPIO:
+       case MGSL_IOCGGPIO:
+       case MGSL_IOCWAITGPIO:
+       case TIOCGICOUNT:
+               rc = ioctl(tty, file, cmd, (unsigned long)(compat_ptr(arg)));
+               break;
+
+       case MGSL_IOCSTXIDLE:
+       case MGSL_IOCTXENABLE:
+       case MGSL_IOCRXENABLE:
+       case MGSL_IOCTXABORT:
+       case TIOCMIWAIT:
+       case MGSL_IOCSIF:
+               rc = ioctl(tty, file, cmd, arg);
+               break;
+       }
+
+       DBGINFO(("%s compat_ioctl() cmd=%08X rc=%d\n", info->device_name, cmd, rc));
+       return rc;
+}
+#else
+#define slgt_compat_ioctl NULL
+#endif /* ifdef CONFIG_COMPAT */
+
+/*
  * proc fs support
  */
 static inline int line_info(char *buf, struct slgt_info *info)
@@ -1323,7 +1453,7 @@ static void set_break(struct tty_struct *tty, int break_state)
        spin_unlock_irqrestore(&info->lock,flags);
 }
 
-#ifdef CONFIG_HDLC
+#if SYNCLINK_GENERIC_HDLC
 
 /**
  * called by generic HDLC layer when protocol selected (PPP, frame relay, etc.)
@@ -1367,7 +1497,7 @@ static int hdlcdev_attach(struct net_device *dev, unsigned short encoding,
        }
 
        info->params.encoding = new_encoding;
-       info->params.crc_type = new_crctype;;
+       info->params.crc_type = new_crctype;
 
        /* if network interface up, reprogram hardware */
        if (info->netcount)
@@ -1468,8 +1598,10 @@ static int hdlcdev_open(struct net_device *dev)
        spin_lock_irqsave(&info->lock, flags);
        get_signals(info);
        spin_unlock_irqrestore(&info->lock, flags);
-       hdlc_set_carrier(info->signals & SerialSignal_DCD, dev);
-
+       if (info->signals & SerialSignal_DCD)
+               netif_carrier_on(dev);
+       else
+               netif_carrier_off(dev);
        return 0;
 }
 
@@ -1750,6 +1882,9 @@ static void rx_async(struct slgt_info *info)
        unsigned char status;
        struct slgt_desc *bufs = info->rbufs;
        int i, count;
+       int chars = 0;
+       int stat;
+       unsigned char ch;
 
        start = end = info->rbuf_current;
 
@@ -1761,43 +1896,34 @@ static void rx_async(struct slgt_info *info)
                DBGDATA(info, p, count, "rx");
 
                for(i=0 ; i < count; i+=2, p+=2) {
-                       if (tty) {
-                               if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-                                       tty_flip_buffer_push(tty);
-                               if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-                                       break;
-                               *tty->flip.char_buf_ptr = *p;
-                               *tty->flip.flag_buf_ptr = 0;
-                       }
+                       ch = *p;
                        icount->rx++;
 
-                       if ((status = *(p+1) & (BIT9 + BIT8))) {
-                               if (status & BIT9)
+                       stat = 0;
+
+                       if ((status = *(p+1) & (BIT1 + BIT0))) {
+                               if (status & BIT1)
                                        icount->parity++;
-                               else if (status & BIT8)
+                               else if (status & BIT0)
                                        icount->frame++;
                                /* discard char if tty control flags say so */
                                if (status & info->ignore_status_mask)
                                        continue;
-                               if (tty) {
-                                       if (status & BIT9)
-                                               *tty->flip.flag_buf_ptr = TTY_PARITY;
-                                       else if (status & BIT8)
-                                               *tty->flip.flag_buf_ptr = TTY_FRAME;
-                               }
+                               if (status & BIT1)
+                                       stat = TTY_PARITY;
+                               else if (status & BIT0)
+                                       stat = TTY_FRAME;
                        }
                        if (tty) {
-                               tty->flip.flag_buf_ptr++;
-                               tty->flip.char_buf_ptr++;
-                               tty->flip.count++;
+                               tty_insert_flip_char(tty, ch, stat);
+                               chars++;
                        }
                }
 
                if (i < count) {
                        /* receive buffer not completed */
                        info->rbuf_index += i;
-                       info->rx_timer.expires = jiffies + 1;
-                       add_timer(&info->rx_timer);
+                       mod_timer(&info->rx_timer, jiffies + 1);
                        break;
                }
 
@@ -1812,7 +1938,7 @@ static void rx_async(struct slgt_info *info)
                        break;
        }
 
-       if (tty && tty->flip.count)
+       if (tty && chars)
                tty_flip_buffer_push(tty);
 }
 
@@ -1850,9 +1976,9 @@ static int bh_action(struct slgt_info *info)
 /*
  * perform bottom half processing
  */
-static void bh_handler(void* context)
+static void bh_handler(struct work_struct *work)
 {
-       struct slgt_info *info = context;
+       struct slgt_info *info = container_of(work, struct slgt_info, task);
        int action;
 
        if (!info)
@@ -1871,6 +1997,8 @@ static void bh_handler(void* context)
                                while(rx_get_frame(info));
                                break;
                        case MGSL_MODE_RAW:
+                       case MGSL_MODE_MONOSYNC:
+                       case MGSL_MODE_BISYNC:
                                while(rx_get_buf(info));
                                break;
                        }
@@ -1901,10 +2029,8 @@ static void bh_transmit(struct slgt_info *info)
        struct tty_struct *tty = info->tty;
 
        DBGBH(("%s bh_transmit\n", info->device_name));
-       if (tty) {
+       if (tty)
                tty_wakeup(tty);
-               wake_up_interruptible(&tty->write_wait);
-       }
 }
 
 static void dsr_change(struct slgt_info *info)
@@ -1972,9 +2098,13 @@ static void dcd_change(struct slgt_info *info)
        } else {
                info->input_signal_events.dcd_down++;
        }
-#ifdef CONFIG_HDLC
-       if (info->netcount)
-               hdlc_set_carrier(info->signals & SerialSignal_DCD, info->netdev);
+#if SYNCLINK_GENERIC_HDLC
+       if (info->netcount) {
+               if (info->signals & SerialSignal_DCD)
+                       netif_carrier_on(info->netdev);
+               else
+                       netif_carrier_off(info->netdev);
+       }
 #endif
        wake_up_interruptible(&info->status_event_wait_q);
        wake_up_interruptible(&info->event_wait_q);
@@ -2030,7 +2160,7 @@ static void isr_serial(struct slgt_info *info)
                        if (info->tty) {
                                if (!(status & info->ignore_status_mask)) {
                                        if (info->read_status_mask & MASK_BREAK) {
-                                               *info->tty->flip.flag_buf_ptr = TTY_BREAK;
+                                               tty_insert_flip_char(info->tty, 0, TTY_BREAK);
                                                if (info->flags & ASYNC_SAK)
                                                        do_SAK(info->tty);
                                        }
@@ -2146,7 +2276,7 @@ static void isr_txeom(struct slgt_info *info, unsigned short status)
                        set_signals(info);
                }
 
-#ifdef CONFIG_HDLC
+#if SYNCLINK_GENERIC_HDLC
                if (info->netcount)
                        hdlcdev_tx_done(info);
                else
@@ -2161,13 +2291,30 @@ static void isr_txeom(struct slgt_info *info, unsigned short status)
        }
 }
 
+static void isr_gpio(struct slgt_info *info, unsigned int changed, unsigned int state)
+{
+       struct cond_wait *w, *prev;
+
+       /* wake processes waiting for specific transitions */
+       for (w = info->gpio_wait_q, prev = NULL ; w != NULL ; w = w->next) {
+               if (w->data & changed) {
+                       w->data = state;
+                       wake_up_interruptible(&w->q);
+                       if (prev != NULL)
+                               prev->next = w->next;
+                       else
+                               info->gpio_wait_q = w->next;
+               } else
+                       prev = w;
+       }
+}
+
 /* interrupt service routine
  *
  *     irq     interrupt number
  *     dev_id  device ID supplied during interrupt registration
- *     regs    interrupted processor context
  */
-static irqreturn_t slgt_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+static irqreturn_t slgt_interrupt(int irq, void *dev_id)
 {
        struct slgt_info *info;
        unsigned int gsr;
@@ -2196,6 +2343,22 @@ static irqreturn_t slgt_interrupt(int irq, void *dev_id, struct pt_regs * regs)
                }
        }
 
+       if (info->gpio_present) {
+               unsigned int state;
+               unsigned int changed;
+               while ((changed = rd_reg32(info, IOSR)) != 0) {
+                       DBGISR(("%s iosr=%08x\n", info->device_name, changed));
+                       /* read latched state of GPIO signals */
+                       state = rd_reg32(info, IOVR);
+                       /* clear pending GPIO interrupt bits */
+                       wr_reg32(info, IOSR, changed);
+                       for (i=0 ; i < info->port_count ; i++) {
+                               if (info->port_array[i] != NULL)
+                                       isr_gpio(info->port_array[i], changed, state);
+                       }
+               }
+       }
+
        for(i=0; i < info->port_count ; i++) {
                struct slgt_info *port = info->port_array[i];
 
@@ -2279,6 +2442,8 @@ static void shutdown(struct slgt_info *info)
                set_signals(info);
        }
 
+       flush_cond_wait(&info->gpio_wait_q);
+
        spin_unlock_irqrestore(&info->lock,flags);
 
        if (info->tty)
@@ -2296,10 +2461,9 @@ static void program_hw(struct slgt_info *info)
        rx_stop(info);
        tx_stop(info);
 
-       if (info->params.mode == MGSL_MODE_HDLC ||
-           info->params.mode == MGSL_MODE_RAW ||
+       if (info->params.mode != MGSL_MODE_ASYNC ||
            info->netcount)
-               hdlc_mode(info);
+               sync_mode(info);
        else
                async_mode(info);
 
@@ -2455,7 +2619,8 @@ static int set_txidle(struct slgt_info *info, int idle_mode)
        DBGINFO(("%s set_txidle(%d)\n", info->device_name, idle_mode));
        spin_lock_irqsave(&info->lock,flags);
        info->idle_mode = idle_mode;
-       tx_set_idle(info);
+       if (info->params.mode != MGSL_MODE_ASYNC)
+               tx_set_idle(info);
        spin_unlock_irqrestore(&info->lock,flags);
        return 0;
 }
@@ -2497,6 +2662,10 @@ static int rx_enable(struct slgt_info *info, int enable)
        if (enable) {
                if (!info->rx_enabled)
                        rx_start(info);
+               else if (enable == 2) {
+                       /* force hunt mode (write 1 to RCR[3]) */
+                       wr_reg16(info, RCR, rd_reg16(info, RCR) | BIT3);
+               }
        } else {
                if (info->rx_enabled)
                        rx_stop(info);
@@ -2633,7 +2802,7 @@ static int get_interface(struct slgt_info *info, int __user *if_mode)
 static int set_interface(struct slgt_info *info, int if_mode)
 {
        unsigned long flags;
-       unsigned char val;
+       unsigned short val;
 
        DBGINFO(("%s set_interface=%x)\n", info->device_name, if_mode));
        spin_lock_irqsave(&info->lock,flags);
@@ -2653,6 +2822,175 @@ static int set_interface(struct slgt_info *info, int if_mode)
        return 0;
 }
 
+/*
+ * set general purpose IO pin state and direction
+ *
+ * user_gpio fields:
+ * state   each bit indicates a pin state
+ * smask   set bit indicates pin state to set
+ * dir     each bit indicates a pin direction (0=input, 1=output)
+ * dmask   set bit indicates pin direction to set
+ */
+static int set_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio)
+{
+       unsigned long flags;
+       struct gpio_desc gpio;
+       __u32 data;
+
+       if (!info->gpio_present)
+               return -EINVAL;
+       if (copy_from_user(&gpio, user_gpio, sizeof(gpio)))
+               return -EFAULT;
+       DBGINFO(("%s set_gpio state=%08x smask=%08x dir=%08x dmask=%08x\n",
+                info->device_name, gpio.state, gpio.smask,
+                gpio.dir, gpio.dmask));
+
+       spin_lock_irqsave(&info->lock,flags);
+       if (gpio.dmask) {
+               data = rd_reg32(info, IODR);
+               data |= gpio.dmask & gpio.dir;
+               data &= ~(gpio.dmask & ~gpio.dir);
+               wr_reg32(info, IODR, data);
+       }
+       if (gpio.smask) {
+               data = rd_reg32(info, IOVR);
+               data |= gpio.smask & gpio.state;
+               data &= ~(gpio.smask & ~gpio.state);
+               wr_reg32(info, IOVR, data);
+       }
+       spin_unlock_irqrestore(&info->lock,flags);
+
+       return 0;
+}
+
+/*
+ * get general purpose IO pin state and direction
+ */
+static int get_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio)
+{
+       struct gpio_desc gpio;
+       if (!info->gpio_present)
+               return -EINVAL;
+       gpio.state = rd_reg32(info, IOVR);
+       gpio.smask = 0xffffffff;
+       gpio.dir   = rd_reg32(info, IODR);
+       gpio.dmask = 0xffffffff;
+       if (copy_to_user(user_gpio, &gpio, sizeof(gpio)))
+               return -EFAULT;
+       DBGINFO(("%s get_gpio state=%08x dir=%08x\n",
+                info->device_name, gpio.state, gpio.dir));
+       return 0;
+}
+
+/*
+ * conditional wait facility
+ */
+static void init_cond_wait(struct cond_wait *w, unsigned int data)
+{
+       init_waitqueue_head(&w->q);
+       init_waitqueue_entry(&w->wait, current);
+       w->data = data;
+}
+
+static void add_cond_wait(struct cond_wait **head, struct cond_wait *w)
+{
+       set_current_state(TASK_INTERRUPTIBLE);
+       add_wait_queue(&w->q, &w->wait);
+       w->next = *head;
+       *head = w;
+}
+
+static void remove_cond_wait(struct cond_wait **head, struct cond_wait *cw)
+{
+       struct cond_wait *w, *prev;
+       remove_wait_queue(&cw->q, &cw->wait);
+       set_current_state(TASK_RUNNING);
+       for (w = *head, prev = NULL ; w != NULL ; prev = w, w = w->next) {
+               if (w == cw) {
+                       if (prev != NULL)
+                               prev->next = w->next;
+                       else
+                               *head = w->next;
+                       break;
+               }
+       }
+}
+
+static void flush_cond_wait(struct cond_wait **head)
+{
+       while (*head != NULL) {
+               wake_up_interruptible(&(*head)->q);
+               *head = (*head)->next;
+       }
+}
+
+/*
+ * wait for general purpose I/O pin(s) to enter specified state
+ *
+ * user_gpio fields:
+ * state - bit indicates target pin state
+ * smask - set bit indicates watched pin
+ *
+ * The wait ends when at least one watched pin enters the specified
+ * state. When 0 (no error) is returned, user_gpio->state is set to the
+ * state of all GPIO pins when the wait ends.
+ *
+ * Note: Each pin may be a dedicated input, dedicated output, or
+ * configurable input/output. The number and configuration of pins
+ * varies with the specific adapter model. Only input pins (dedicated
+ * or configured) can be monitored with this function.
+ */
+static int wait_gpio(struct slgt_info *info, struct gpio_desc __user *user_gpio)
+{
+       unsigned long flags;
+       int rc = 0;
+       struct gpio_desc gpio;
+       struct cond_wait wait;
+       u32 state;
+
+       if (!info->gpio_present)
+               return -EINVAL;
+       if (copy_from_user(&gpio, user_gpio, sizeof(gpio)))
+               return -EFAULT;
+       DBGINFO(("%s wait_gpio() state=%08x smask=%08x\n",
+                info->device_name, gpio.state, gpio.smask));
+       /* ignore output pins identified by set IODR bit */
+       if ((gpio.smask &= ~rd_reg32(info, IODR)) == 0)
+               return -EINVAL;
+       init_cond_wait(&wait, gpio.smask);
+
+       spin_lock_irqsave(&info->lock, flags);
+       /* enable interrupts for watched pins */
+       wr_reg32(info, IOER, rd_reg32(info, IOER) | gpio.smask);
+       /* get current pin states */
+       state = rd_reg32(info, IOVR);
+
+       if (gpio.smask & ~(state ^ gpio.state)) {
+               /* already in target state */
+               gpio.state = state;
+       } else {
+               /* wait for target state */
+               add_cond_wait(&info->gpio_wait_q, &wait);
+               spin_unlock_irqrestore(&info->lock, flags);
+               schedule();
+               if (signal_pending(current))
+                       rc = -ERESTARTSYS;
+               else
+                       gpio.state = wait.data;
+               spin_lock_irqsave(&info->lock, flags);
+               remove_cond_wait(&info->gpio_wait_q, &wait);
+       }
+
+       /* disable all GPIO interrupts if no waiting processes */
+       if (info->gpio_wait_q == NULL)
+               wr_reg32(info, IOER, 0);
+       spin_unlock_irqrestore(&info->lock,flags);
+
+       if ((rc == 0) && copy_to_user(user_gpio, &gpio, sizeof(gpio)))
+               rc = -EFAULT;
+       return rc;
+}
+
 static int modem_input_wait(struct slgt_info *info,int arg)
 {
        unsigned long flags;
@@ -2847,7 +3185,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
 
 static int alloc_tmp_rbuf(struct slgt_info *info)
 {
-       info->tmp_rbuf = kmalloc(info->max_frame_size, GFP_KERNEL);
+       info->tmp_rbuf = kmalloc(info->max_frame_size + 5, GFP_KERNEL);
        if (info->tmp_rbuf == NULL)
                return -ENOMEM;
        return 0;
@@ -2978,14 +3316,13 @@ static int claim_resources(struct slgt_info *info)
        else
                info->reg_addr_requested = 1;
 
-       info->reg_addr = ioremap(info->phys_reg_addr, PAGE_SIZE);
+       info->reg_addr = ioremap(info->phys_reg_addr, SLGT_REG_SIZE);
        if (!info->reg_addr) {
                DBGERR(("%s cant map device registers, addr=%08X\n",
                        info->device_name, info->phys_reg_addr));
                info->init_error = DiagStatus_CantAssignPciResources;
                goto errout;
        }
-       info->reg_addr += info->reg_offset;
        return 0;
 
 errout:
@@ -3006,7 +3343,7 @@ static void release_resources(struct slgt_info *info)
        }
 
        if (info->reg_addr) {
-               iounmap(info->reg_addr - info->reg_offset);
+               iounmap(info->reg_addr);
                info->reg_addr = NULL;
        }
 }
@@ -3048,6 +3385,9 @@ static void add_device(struct slgt_info *info)
        case SYNCLINK_GT_DEVICE_ID:
                devstr = "GT";
                break;
+       case SYNCLINK_GT2_DEVICE_ID:
+               devstr = "GT2";
+               break;
        case SYNCLINK_GT4_DEVICE_ID:
                devstr = "GT4";
                break;
@@ -3062,7 +3402,7 @@ static void add_device(struct slgt_info *info)
                devstr, info->device_name, info->phys_reg_addr,
                info->irq_level, info->max_frame_size);
 
-#ifdef CONFIG_HDLC
+#if SYNCLINK_GENERIC_HDLC
        hdlcdev_init(info);
 #endif
 }
@@ -3074,15 +3414,14 @@ static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev
 {
        struct slgt_info *info;
 
-       info = kmalloc(sizeof(struct slgt_info), GFP_KERNEL);
+       info = kzalloc(sizeof(struct slgt_info), GFP_KERNEL);
 
        if (!info) {
                DBGERR(("%s device alloc failed adapter=%d port=%d\n",
                        driver_name, adapter_num, port_num));
        } else {
-               memset(info, 0, sizeof(struct slgt_info));
                info->magic = MGSL_MAGIC;
-               INIT_WORK(&info->task, bh_handler, info);
+               INIT_WORK(&info->task, bh_handler);
                info->max_frame_size = 4096;
                info->raw_rx_size = DMABUFSIZE;
                info->close_delay = 5*HZ/10;
@@ -3097,27 +3436,16 @@ static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev
                info->adapter_num = adapter_num;
                info->port_num = port_num;
 
-               init_timer(&info->tx_timer);
-               info->tx_timer.data = (unsigned long)info;
-               info->tx_timer.function = tx_timeout;
-
-               init_timer(&info->rx_timer);
-               info->rx_timer.data = (unsigned long)info;
-               info->rx_timer.function = rx_timeout;
+               setup_timer(&info->tx_timer, tx_timeout, (unsigned long)info);
+               setup_timer(&info->rx_timer, rx_timeout, (unsigned long)info);
 
                /* Copy configuration info to device instance data */
                info->pdev = pdev;
                info->irq_level = pdev->irq;
                info->phys_reg_addr = pci_resource_start(pdev,0);
 
-               /* veremap works on page boundaries
-                * map full page starting at the page boundary
-                */
-               info->reg_offset    = info->phys_reg_addr & (PAGE_SIZE-1);
-               info->phys_reg_addr &= ~(PAGE_SIZE-1);
-
                info->bus_type = MGSL_BUS_TYPE_PCI;
-               info->irq_flags = SA_SHIRQ;
+               info->irq_flags = IRQF_SHARED;
 
                info->init_error = -1; /* assume error, set to 0 on successful init */
        }
@@ -3131,7 +3459,9 @@ static void device_init(int adapter_num, struct pci_dev *pdev)
        int i;
        int port_count = 1;
 
-       if (pdev->device == SYNCLINK_GT4_DEVICE_ID)
+       if (pdev->device == SYNCLINK_GT2_DEVICE_ID)
+               port_count = 2;
+       else if (pdev->device == SYNCLINK_GT4_DEVICE_ID)
                port_count = 4;
 
        /* allocate device instances for all ports */
@@ -3176,10 +3506,15 @@ static void device_init(int adapter_num, struct pci_dev *pdev)
                } else {
                        port_array[0]->irq_requested = 1;
                        adapter_test(port_array[0]);
-                       for (i=1 ; i < port_count ; i++)
+                       for (i=1 ; i < port_count ; i++) {
                                port_array[i]->init_error = port_array[0]->init_error;
+                               port_array[i]->gpio_present = port_array[0]->gpio_present;
+                       }
                }
        }
+
+       for (i=0; i < port_count; ++i)
+               tty_register_device(serial_driver, port_array[i]->line, &(port_array[i]->pdev->dev));
 }
 
 static int __devinit init_one(struct pci_dev *dev,
@@ -3198,7 +3533,7 @@ static void __devexit remove_one(struct pci_dev *dev)
 {
 }
 
-static struct tty_operations ops = {
+static const struct tty_operations ops = {
        .open = open,
        .close = close,
        .write = write,
@@ -3208,6 +3543,7 @@ static struct tty_operations ops = {
        .chars_in_buffer = chars_in_buffer,
        .flush_buffer = flush_buffer,
        .ioctl = ioctl,
+       .compat_ioctl = slgt_compat_ioctl,
        .throttle = throttle,
        .unthrottle = unthrottle,
        .send_xchar = send_xchar,
@@ -3231,6 +3567,8 @@ static void slgt_cleanup(void)
        printk("unload %s %s\n", driver_name, driver_version);
 
        if (serial_driver) {
+               for (info=slgt_device_list ; info != NULL ; info=info->next_device)
+                       tty_unregister_device(serial_driver, info->line);
                if ((rc = tty_unregister_driver(serial_driver)))
                        DBGERR(("tty_unregister_driver error=%d\n", rc));
                put_tty_driver(serial_driver);
@@ -3246,7 +3584,7 @@ static void slgt_cleanup(void)
        /* release devices */
        info = slgt_device_list;
        while(info) {
-#ifdef CONFIG_HDLC
+#if SYNCLINK_GENERIC_HDLC
                hdlcdev_exit(info);
 #endif
                free_dma_bufs(info);
@@ -3271,22 +3609,10 @@ static int __init slgt_init(void)
 
        printk("%s %s\n", driver_name, driver_version);
 
-       slgt_device_count = 0;
-       if ((rc = pci_register_driver(&pci_driver)) < 0) {
-               printk("%s pci_register_driver error=%d\n", driver_name, rc);
-               return rc;
-       }
-       pci_registered = 1;
-
-       if (!slgt_device_list) {
-               printk("%s no devices found\n",driver_name);
-               return -ENODEV;
-       }
-
        serial_driver = alloc_tty_driver(MAX_DEVICES);
        if (!serial_driver) {
-               rc = -ENOMEM;
-               goto error;
+               printk("%s can't allocate tty driver\n", driver_name);
+               return -ENOMEM;
        }
 
        /* Initialize the tty_driver structure */
@@ -3301,7 +3627,9 @@ static int __init slgt_init(void)
        serial_driver->init_termios = tty_std_termios;
        serial_driver->init_termios.c_cflag =
                B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-       serial_driver->flags = TTY_DRIVER_REAL_RAW;
+       serial_driver->init_termios.c_ispeed = 9600;
+       serial_driver->init_termios.c_ospeed = 9600;
+       serial_driver->flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_DYNAMIC_DEV;
        tty_set_operations(serial_driver, &ops);
        if ((rc = tty_register_driver(serial_driver)) < 0) {
                DBGERR(("%s can't register serial driver\n", driver_name));
@@ -3314,6 +3642,16 @@ static int __init slgt_init(void)
                driver_name, driver_version,
                serial_driver->major);
 
+       slgt_device_count = 0;
+       if ((rc = pci_register_driver(&pci_driver)) < 0) {
+               printk("%s pci_register_driver error=%d\n", driver_name, rc);
+               goto error;
+       }
+       pci_registered = 1;
+
+       if (!slgt_device_list)
+               printk("%s no devices found\n",driver_name);
+
        return 0;
 
 error:
@@ -3512,7 +3850,7 @@ static void tx_start(struct slgt_info *info)
 {
        if (!info->tx_enabled) {
                wr_reg16(info, TCR,
-                       (unsigned short)(rd_reg16(info, TCR) | BIT1));
+                        (unsigned short)((rd_reg16(info, TCR) | BIT1) & ~BIT2));
                info->tx_enabled = TRUE;
        }
 
@@ -3539,16 +3877,20 @@ static void tx_start(struct slgt_info *info)
                                tdma_reset(info);
                                /* set 1st descriptor address */
                                wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc);
-                               if (info->params.mode == MGSL_MODE_RAW)
+                               switch(info->params.mode) {
+                               case MGSL_MODE_RAW:
+                               case MGSL_MODE_MONOSYNC:
+                               case MGSL_MODE_BISYNC:
                                        wr_reg32(info, TDCSR, BIT2 + BIT0); /* IRQ + DMA enable */
-                               else
+                                       break;
+                               default:
                                        wr_reg32(info, TDCSR, BIT0); /* DMA enable */
+                               }
                        }
 
-                       if (info->params.mode != MGSL_MODE_RAW) {
-                               info->tx_timer.expires = jiffies + msecs_to_jiffies(5000);
-                               add_timer(&info->tx_timer);
-                       }
+                       if (info->params.mode == MGSL_MODE_HDLC)
+                               mod_timer(&info->tx_timer, jiffies +
+                                               msecs_to_jiffies(5000));
                } else {
                        tdma_reset(info);
                        /* set 1st descriptor address */
@@ -3578,7 +3920,6 @@ static void tx_stop(struct slgt_info *info)
        /* reset and disable transmitter */
        val = rd_reg16(info, TCR) & ~BIT1;          /* clear enable bit */
        wr_reg16(info, TCR, (unsigned short)(val | BIT2)); /* set reset bit */
-       wr_reg16(info, TCR, val);                  /* clear reset */
 
        slgt_irq_off(info, IRQ_TXDATA + IRQ_TXIDLE + IRQ_TXUNDER);
 
@@ -3716,8 +4057,6 @@ static void async_mode(struct slgt_info *info)
 
        msc_set_vcr(info);
 
-       tx_set_idle(info);
-
        /* SCR (serial control)
         *
         * 15  1=tx req on FIFO half empty
@@ -3748,7 +4087,7 @@ static void async_mode(struct slgt_info *info)
                enable_loopback(info);
 }
 
-static void hdlc_mode(struct slgt_info *info)
+static void sync_mode(struct slgt_info *info)
 {
        unsigned short val;
 
@@ -3758,7 +4097,7 @@ static void hdlc_mode(struct slgt_info *info)
 
        /* TCR (tx control)
         *
-        * 15..13  mode, 000=HDLC 001=raw sync
+        * 15..13  mode, 000=HDLC 001=raw 010=async 011=monosync 100=bisync
         * 12..10  encoding
         * 09      CRC enable
         * 08      CRC32
@@ -3772,8 +4111,11 @@ static void hdlc_mode(struct slgt_info *info)
         */
        val = 0;
 
-       if (info->params.mode == MGSL_MODE_RAW)
-               val |= BIT13;
+       switch(info->params.mode) {
+       case MGSL_MODE_MONOSYNC: val |= BIT14 + BIT13; break;
+       case MGSL_MODE_BISYNC:   val |= BIT15; break;
+       case MGSL_MODE_RAW:      val |= BIT13; break;
+       }
        if (info->if_mode & MGSL_INTERFACE_RTS_EN)
                val |= BIT7;
 
@@ -3788,7 +4130,7 @@ static void hdlc_mode(struct slgt_info *info)
        case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: val |= BIT12 + BIT11 + BIT10; break;
        }
 
-       switch (info->params.crc_type)
+       switch (info->params.crc_type & HDLC_CRC_MASK)
        {
        case HDLC_CRC_16_CCITT: val |= BIT9; break;
        case HDLC_CRC_32_CCITT: val |= BIT9 + BIT8; break;
@@ -3824,7 +4166,7 @@ static void hdlc_mode(struct slgt_info *info)
 
        /* RCR (rx control)
         *
-        * 15..13  mode, 000=HDLC 001=raw sync
+        * 15..13  mode, 000=HDLC 001=raw 010=async 011=monosync 100=bisync
         * 12..10  encoding
         * 09      CRC enable
         * 08      CRC32
@@ -3835,8 +4177,11 @@ static void hdlc_mode(struct slgt_info *info)
         */
        val = 0;
 
-       if (info->params.mode == MGSL_MODE_RAW)
-               val |= BIT13;
+       switch(info->params.mode) {
+       case MGSL_MODE_MONOSYNC: val |= BIT14 + BIT13; break;
+       case MGSL_MODE_BISYNC:   val |= BIT15; break;
+       case MGSL_MODE_RAW:      val |= BIT13; break;
+       }
 
        switch(info->params.encoding)
        {
@@ -3849,7 +4194,7 @@ static void hdlc_mode(struct slgt_info *info)
        case HDLC_ENCODING_DIFF_BIPHASE_LEVEL: val |= BIT12 + BIT11 + BIT10; break;
        }
 
-       switch (info->params.crc_type)
+       switch (info->params.crc_type & HDLC_CRC_MASK)
        {
        case HDLC_CRC_16_CCITT: val |= BIT9; break;
        case HDLC_CRC_32_CCITT: val |= BIT9 + BIT8; break;
@@ -3951,17 +4296,38 @@ static void hdlc_mode(struct slgt_info *info)
  */
 static void tx_set_idle(struct slgt_info *info)
 {
-       unsigned char val = 0xff;
+       unsigned char val;
+       unsigned short tcr;
 
-       switch(info->idle_mode)
-       {
-       case HDLC_TXIDLE_FLAGS:          val = 0x7e; break;
-       case HDLC_TXIDLE_ALT_ZEROS_ONES: val = 0xaa; break;
-       case HDLC_TXIDLE_ZEROS:          val = 0x00; break;
-       case HDLC_TXIDLE_ONES:           val = 0xff; break;
-       case HDLC_TXIDLE_ALT_MARK_SPACE: val = 0xaa; break;
-       case HDLC_TXIDLE_SPACE:          val = 0x00; break;
-       case HDLC_TXIDLE_MARK:           val = 0xff; break;
+       /* if preamble enabled (tcr[6] == 1) then tx idle size = 8 bits
+        * else tcr[5:4] = tx idle size: 00 = 8 bits, 01 = 16 bits
+        */
+       tcr = rd_reg16(info, TCR);
+       if (info->idle_mode & HDLC_TXIDLE_CUSTOM_16) {
+               /* disable preamble, set idle size to 16 bits */
+               tcr = (tcr & ~(BIT6 + BIT5)) | BIT4;
+               /* MSB of 16 bit idle specified in tx preamble register (TPR) */
+               wr_reg8(info, TPR, (unsigned char)((info->idle_mode >> 8) & 0xff));
+       } else if (!(tcr & BIT6)) {
+               /* preamble is disabled, set idle size to 8 bits */
+               tcr &= ~(BIT5 + BIT4);
+       }
+       wr_reg16(info, TCR, tcr);
+
+       if (info->idle_mode & (HDLC_TXIDLE_CUSTOM_8 | HDLC_TXIDLE_CUSTOM_16)) {
+               /* LSB of custom tx idle specified in tx idle register */
+               val = (unsigned char)(info->idle_mode & 0xff);
+       } else {
+               /* standard 8 bit idle patterns */
+               switch(info->idle_mode)
+               {
+               case HDLC_TXIDLE_FLAGS:          val = 0x7e; break;
+               case HDLC_TXIDLE_ALT_ZEROS_ONES:
+               case HDLC_TXIDLE_ALT_MARK_SPACE: val = 0xaa; break;
+               case HDLC_TXIDLE_ZEROS:
+               case HDLC_TXIDLE_SPACE:          val = 0x00; break;
+               default:                         val = 0xff;
+               }
        }
 
        wr_reg8(info, TIR, val);
@@ -4054,10 +4420,15 @@ static void free_rbufs(struct slgt_info *info, unsigned int i, unsigned int last
        while(!done) {
                /* reset current buffer for reuse */
                info->rbufs[i].status = 0;
-               if (info->params.mode == MGSL_MODE_RAW)
+               switch(info->params.mode) {
+               case MGSL_MODE_RAW:
+               case MGSL_MODE_MONOSYNC:
+               case MGSL_MODE_BISYNC:
                        set_desc_count(info->rbufs[i], info->raw_rx_size);
-               else
+                       break;
+               default:
                        set_desc_count(info->rbufs[i], DMABUFSIZE);
+               }
 
                if (i == last)
                        done = 1;
@@ -4089,6 +4460,12 @@ static int rx_get_frame(struct slgt_info *info)
        unsigned long flags;
        struct tty_struct *tty = info->tty;
        unsigned char addr_field = 0xff;
+       unsigned int crc_size = 0;
+
+       switch (info->params.crc_type & HDLC_CRC_MASK) {
+       case HDLC_CRC_16_CCITT: crc_size = 2; break;
+       case HDLC_CRC_32_CCITT: crc_size = 4; break;
+       }
 
 check_again:
 
@@ -4133,7 +4510,7 @@ check_again:
        status = desc_status(info->rbufs[end]);
 
        /* ignore CRC bit if not using CRC (bit is undefined) */
-       if (info->params.crc_type == HDLC_CRC_NONE)
+       if ((info->params.crc_type & HDLC_CRC_MASK) == HDLC_CRC_NONE)
                status &= ~BIT1;
 
        if (framesize == 0 ||
@@ -4142,34 +4519,34 @@ check_again:
                goto check_again;
        }
 
-       if (framesize < 2 || status & (BIT1+BIT0)) {
-               if (framesize < 2 || (status & BIT0))
-                       info->icount.rxshort++;
-               else
-                       info->icount.rxcrc++;
+       if (framesize < (2 + crc_size) || status & BIT0) {
+               info->icount.rxshort++;
                framesize = 0;
+       } else if (status & BIT1) {
+               info->icount.rxcrc++;
+               if (!(info->params.crc_type & HDLC_CRC_RETURN_EX))
+                       framesize = 0;
+       }
 
-#ifdef CONFIG_HDLC
-               {
-                       struct net_device_stats *stats = hdlc_stats(info->netdev);
-                       stats->rx_errors++;
-                       stats->rx_frame_errors++;
-               }
-#endif
-       } else {
-               /* adjust frame size for CRC, if any */
-               if (info->params.crc_type == HDLC_CRC_16_CCITT)
-                       framesize -= 2;
-               else if (info->params.crc_type == HDLC_CRC_32_CCITT)
-                       framesize -= 4;
+#if SYNCLINK_GENERIC_HDLC
+       if (framesize == 0) {
+               struct net_device_stats *stats = hdlc_stats(info->netdev);
+               stats->rx_errors++;
+               stats->rx_frame_errors++;
        }
+#endif
 
        DBGBH(("%s rx frame status=%04X size=%d\n",
                info->device_name, status, framesize));
        DBGDATA(info, info->rbufs[start].buf, min_t(int, framesize, DMABUFSIZE), "rx");
 
        if (framesize) {
-               if (framesize > info->max_frame_size)
+               if (!(info->params.crc_type & HDLC_CRC_RETURN_EX)) {
+                       framesize -= crc_size;
+                       crc_size = 0;
+               }
+
+               if (framesize > info->max_frame_size + crc_size)
                        info->icount.rxlong++;
                else {
                        /* copy dma buffer(s) to contiguous temp buffer */
@@ -4189,7 +4566,12 @@ check_again:
                                        i = 0;
                        }
 
-#ifdef CONFIG_HDLC
+                       if (info->params.crc_type & HDLC_CRC_RETURN_EX) {
+                               *p = (status & BIT1) ? RX_CRC_ERROR : RX_OK;
+                               framesize++;
+                       }
+
+#if SYNCLINK_GENERIC_HDLC
                        if (info->netcount)
                                hdlcdev_rx(info,info->tmp_rbuf, framesize);
                        else
@@ -4211,13 +4593,24 @@ cleanup:
 static int rx_get_buf(struct slgt_info *info)
 {
        unsigned int i = info->rbuf_current;
+       unsigned int count;
 
        if (!desc_complete(info->rbufs[i]))
                return 0;
-       DBGDATA(info, info->rbufs[i].buf, desc_count(info->rbufs[i]), "rx");
-       DBGINFO(("rx_get_buf size=%d\n", desc_count(info->rbufs[i])));
-       ldisc_receive_buf(info->tty, info->rbufs[i].buf,
-                         info->flag_buf, desc_count(info->rbufs[i]));
+       count = desc_count(info->rbufs[i]);
+       switch(info->params.mode) {
+       case MGSL_MODE_MONOSYNC:
+       case MGSL_MODE_BISYNC:
+               /* ignore residue in byte synchronous modes */
+               if (desc_residue(info->rbufs[i]))
+                       count--;
+               break;
+       }
+       DBGDATA(info, info->rbufs[i].buf, count, "rx");
+       DBGINFO(("rx_get_buf size=%d\n", count));
+       if (count)
+               ldisc_receive_buf(info->tty, info->rbufs[i].buf,
+                                 info->flag_buf, count);
        free_rbufs(info, i, i);
        return 1;
 }
@@ -4283,8 +4676,13 @@ static void tx_load(struct slgt_info *info, const char *buf, unsigned int size)
                size -= count;
                buf  += count;
 
-               if (!size && info->params.mode != MGSL_MODE_RAW)
-                       set_desc_eof(*d, 1); /* HDLC: set EOF of last desc */
+               /*
+                * set EOF bit for last buffer of HDLC frame or
+                * for every buffer in raw mode
+                */
+               if ((!size && info->params.mode == MGSL_MODE_HDLC) ||
+                   info->params.mode == MGSL_MODE_RAW)
+                       set_desc_eof(*d, 1);
                else
                        set_desc_eof(*d, 0);
 
@@ -4311,7 +4709,7 @@ static int register_test(struct slgt_info *info)
                        break;
                }
        }
-
+       info->gpio_present = (rd_reg32(info, JCR) & BIT5) ? 1 : 0;
        info->init_error = rc ? 0 : DiagStatus_AddressFailure;
        return rc;
 }
@@ -4447,13 +4845,13 @@ static int loopback_test(struct slgt_info *info)
 static int adapter_test(struct slgt_info *info)
 {
        DBGINFO(("testing %s\n", info->device_name));
-       if ((info->init_error = register_test(info)) < 0) {
+       if (register_test(info) < 0) {
                printk("register test failure %s addr=%08X\n",
                        info->device_name, info->phys_reg_addr);
-       } else if ((info->init_error = irq_test(info)) < 0) {
+       } else if (irq_test(info) < 0) {
                printk("IRQ test failure %s IRQ=%d\n",
                        info->device_name, info->irq_level);
-       } else if ((info->init_error = loopback_test(info)) < 0) {
+       } else if (loopback_test(info) < 0) {
                printk("loopback test failure %s\n", info->device_name);
        }
        return info->init_error;
@@ -4476,7 +4874,7 @@ static void tx_timeout(unsigned long context)
        info->tx_count = 0;
        spin_unlock_irqrestore(&info->lock,flags);
 
-#ifdef CONFIG_HDLC
+#if SYNCLINK_GENERIC_HDLC
        if (info->netcount)
                hdlcdev_tx_done(info);
        else
@@ -4496,6 +4894,6 @@ static void rx_timeout(unsigned long context)
        spin_lock_irqsave(&info->lock, flags);
        info->pending_bh |= BH_RECEIVE;
        spin_unlock_irqrestore(&info->lock, flags);
-       bh_handler(info);
+       bh_handler(&info->task);
 }