synclink drivers bool conversion
[safe/jmp/linux-2.6] / drivers / char / synclink_gt.c
index 2a7736b..f3d8d72 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: synclink_gt.c,v 4.36 2006/08/28 20:47:14 paulkf Exp $
+ * $Id: synclink_gt.c,v 4.50 2007/07/25 19:29:25 paulkf Exp $
  *
  * Device driver for Microgate SyncLink GT serial adapters.
  *
@@ -73,6 +73,7 @@
 #include <linux/bitops.h>
 #include <linux/workqueue.h>
 #include <linux/hdlc.h>
+#include <linux/synclink.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -81,8 +82,6 @@
 #include <asm/types.h>
 #include <asm/uaccess.h>
 
-#include "linux/synclink.h"
-
 #if defined(CONFIG_HDLC) || (defined(CONFIG_HDLC_MODULE) && defined(CONFIG_SYNCLINK_GT_MODULE))
 #define SYNCLINK_GENERIC_HDLC 1
 #else
@@ -93,7 +92,7 @@
  * module identification
  */
 static char *driver_name     = "SyncLink GT";
-static char *driver_version  = "$Revision: 4.36 $";
+static char *driver_version  = "$Revision: 4.50 $";
 static char *tty_driver_name = "synclink_gt";
 static char *tty_dev_prefix  = "ttySLG";
 MODULE_LICENSE("GPL");
@@ -118,7 +117,7 @@ static struct pci_driver pci_driver = {
        .remove         = __devexit_p(remove_one),
 };
 
-static int pci_registered;
+static bool pci_registered;
 
 /*
  * module configuration and status
@@ -144,8 +143,6 @@ 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);
@@ -208,10 +205,10 @@ static void flush_cond_wait(struct cond_wait **head);
  */
 struct slgt_desc
 {
-       unsigned short count;
-       unsigned short status;
-       unsigned int pbuf;  /* physical address of data buffer */
-       unsigned int next;  /* physical address of next descriptor */
+       __le16 count;
+       __le16 status;
+       __le32 pbuf;  /* physical address of data buffer */
+       __le32 next;  /* physical address of next descriptor */
 
        /* driver book keeping */
        char *buf;          /* virtual  address of data buffer */
@@ -292,12 +289,12 @@ struct slgt_info {
 
        struct work_struct task;
        u32 pending_bh;
-       int bh_requested;
-       int bh_running;
+       bool bh_requested;
+       bool bh_running;
 
        int isr_overflow;
-       int irq_requested;      /* nonzero if IRQ requested */
-       int irq_occurred;       /* for diagnostics use */
+       bool irq_requested;     /* true if IRQ requested */
+       bool irq_occurred;      /* for diagnostics use */
 
        /* device configuration */
 
@@ -307,7 +304,7 @@ struct slgt_info {
 
        unsigned char __iomem * reg_addr;  /* memory mapped registers address */
        u32 phys_reg_addr;
-       int reg_addr_requested;
+       bool reg_addr_requested;
 
        MGSL_PARAMS params;       /* communications parameters */
        u32 idle_mode;
@@ -318,11 +315,11 @@ struct slgt_info {
 
        /* device status */
 
-       int rx_enabled;
-       int rx_restart;
+       bool rx_enabled;
+       bool rx_restart;
 
-       int tx_enabled;
-       int tx_active;
+       bool tx_enabled;
+       bool tx_active;
 
        unsigned char signals;    /* serial signal states */
        int init_error;  /* initialization error */
@@ -332,7 +329,7 @@ struct slgt_info {
 
        char flag_buf[MAX_ASYNC_BUFFER_SIZE];
        char char_buf[MAX_ASYNC_BUFFER_SIZE];
-       BOOLEAN drop_rts_on_tx_done;
+       bool drop_rts_on_tx_done;
        struct  _input_signal_events    input_signal_events;
 
        int dcd_chkcount;       /* check counts to prevent */
@@ -470,8 +467,8 @@ static void rx_start(struct slgt_info *info);
 static void reset_rbufs(struct slgt_info *info);
 static void free_rbufs(struct slgt_info *info, unsigned int first, unsigned int last);
 static void rdma_reset(struct slgt_info *info);
-static int  rx_get_frame(struct slgt_info *info);
-static int  rx_get_buf(struct slgt_info *info);
+static bool rx_get_frame(struct slgt_info *info);
+static bool rx_get_buf(struct slgt_info *info);
 
 static void tx_start(struct slgt_info *info);
 static void tx_stop(struct slgt_info *info);
@@ -479,6 +476,7 @@ static void tx_set_idle(struct slgt_info *info);
 static unsigned int free_tbuf_count(struct slgt_info *info);
 static void reset_tbufs(struct slgt_info *info);
 static void tdma_reset(struct slgt_info *info);
+static void tdma_start(struct slgt_info *info);
 static void tx_load(struct slgt_info *info, const char *buf, unsigned int count);
 
 static void get_signals(struct slgt_info *info);
@@ -493,7 +491,6 @@ 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);
 
 static int  alloc_dma_bufs(struct slgt_info *info);
 static void free_dma_bufs(struct slgt_info *info);
@@ -823,12 +820,6 @@ static void set_termios(struct tty_struct *tty, struct ktermios *old_termios)
 
        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 */
@@ -912,6 +903,8 @@ start:
                spin_lock_irqsave(&info->lock,flags);
                if (!info->tx_active)
                        tx_start(info);
+               else
+                       tdma_start(info);
                spin_unlock_irqrestore(&info->lock,flags);
        }
 
@@ -1171,6 +1164,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)
@@ -1464,6 +1563,9 @@ static int hdlcdev_open(struct net_device *dev)
        int rc;
        unsigned long flags;
 
+       if (!try_module_get(THIS_MODULE))
+               return -EBUSY;
+
        DBGINFO(("%s hdlcdev_open\n", dev->name));
 
        /* generic HDLC layer open processing */
@@ -1533,6 +1635,7 @@ static int hdlcdev_close(struct net_device *dev)
        info->netcount=0;
        spin_unlock_irqrestore(&info->netlock, flags);
 
+       module_put(THIS_MODULE);
        return 0;
 }
 
@@ -1865,8 +1968,8 @@ static int bh_action(struct slgt_info *info)
                rc = BH_STATUS;
        } else {
                /* Mark BH routine as complete */
-               info->bh_running   = 0;
-               info->bh_requested = 0;
+               info->bh_running = false;
+               info->bh_requested = false;
                rc = 0;
        }
 
@@ -1885,7 +1988,7 @@ static void bh_handler(struct work_struct *work)
 
        if (!info)
                return;
-       info->bh_running = 1;
+       info->bh_running = true;
 
        while((action = bh_action(info))) {
                switch (action) {
@@ -1935,37 +2038,41 @@ static void bh_transmit(struct slgt_info *info)
                tty_wakeup(tty);
 }
 
-static void dsr_change(struct slgt_info *info)
+static void dsr_change(struct slgt_info *info, unsigned short status)
 {
-       get_signals(info);
+       if (status & BIT3) {
+               info->signals |= SerialSignal_DSR;
+               info->input_signal_events.dsr_up++;
+       } else {
+               info->signals &= ~SerialSignal_DSR;
+               info->input_signal_events.dsr_down++;
+       }
        DBGISR(("dsr_change %s signals=%04X\n", info->device_name, info->signals));
        if ((info->dsr_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
                slgt_irq_off(info, IRQ_DSR);
                return;
        }
        info->icount.dsr++;
-       if (info->signals & SerialSignal_DSR)
-               info->input_signal_events.dsr_up++;
-       else
-               info->input_signal_events.dsr_down++;
        wake_up_interruptible(&info->status_event_wait_q);
        wake_up_interruptible(&info->event_wait_q);
        info->pending_bh |= BH_STATUS;
 }
 
-static void cts_change(struct slgt_info *info)
+static void cts_change(struct slgt_info *info, unsigned short status)
 {
-       get_signals(info);
+       if (status & BIT2) {
+               info->signals |= SerialSignal_CTS;
+               info->input_signal_events.cts_up++;
+       } else {
+               info->signals &= ~SerialSignal_CTS;
+               info->input_signal_events.cts_down++;
+       }
        DBGISR(("cts_change %s signals=%04X\n", info->device_name, info->signals));
        if ((info->cts_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
                slgt_irq_off(info, IRQ_CTS);
                return;
        }
        info->icount.cts++;
-       if (info->signals & SerialSignal_CTS)
-               info->input_signal_events.cts_up++;
-       else
-               info->input_signal_events.cts_down++;
        wake_up_interruptible(&info->status_event_wait_q);
        wake_up_interruptible(&info->event_wait_q);
        info->pending_bh |= BH_STATUS;
@@ -1986,20 +2093,21 @@ static void cts_change(struct slgt_info *info)
        }
 }
 
-static void dcd_change(struct slgt_info *info)
+static void dcd_change(struct slgt_info *info, unsigned short status)
 {
-       get_signals(info);
+       if (status & BIT1) {
+               info->signals |= SerialSignal_DCD;
+               info->input_signal_events.dcd_up++;
+       } else {
+               info->signals &= ~SerialSignal_DCD;
+               info->input_signal_events.dcd_down++;
+       }
        DBGISR(("dcd_change %s signals=%04X\n", info->device_name, info->signals));
        if ((info->dcd_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
                slgt_irq_off(info, IRQ_DCD);
                return;
        }
        info->icount.dcd++;
-       if (info->signals & SerialSignal_DCD) {
-               info->input_signal_events.dcd_up++;
-       } else {
-               info->input_signal_events.dcd_down++;
-       }
 #if SYNCLINK_GENERIC_HDLC
        if (info->netcount) {
                if (info->signals & SerialSignal_DCD)
@@ -2022,20 +2130,21 @@ static void dcd_change(struct slgt_info *info)
        }
 }
 
-static void ri_change(struct slgt_info *info)
+static void ri_change(struct slgt_info *info, unsigned short status)
 {
-       get_signals(info);
+       if (status & BIT0) {
+               info->signals |= SerialSignal_RI;
+               info->input_signal_events.ri_up++;
+       } else {
+               info->signals &= ~SerialSignal_RI;
+               info->input_signal_events.ri_down++;
+       }
        DBGISR(("ri_change %s signals=%04X\n", info->device_name, info->signals));
        if ((info->ri_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {
                slgt_irq_off(info, IRQ_RI);
                return;
        }
-       info->icount.dcd++;
-       if (info->signals & SerialSignal_RI) {
-               info->input_signal_events.ri_up++;
-       } else {
-               info->input_signal_events.ri_down++;
-       }
+       info->icount.rng++;
        wake_up_interruptible(&info->status_event_wait_q);
        wake_up_interruptible(&info->event_wait_q);
        info->pending_bh |= BH_STATUS;
@@ -2049,7 +2158,7 @@ static void isr_serial(struct slgt_info *info)
 
        wr_reg16(info, SSR, status); /* clear pending */
 
-       info->irq_occurred = 1;
+       info->irq_occurred = true;
 
        if (info->params.mode == MGSL_MODE_ASYNC) {
                if (status & IRQ_TXIDLE) {
@@ -2086,13 +2195,13 @@ static void isr_serial(struct slgt_info *info)
        }
 
        if (status & IRQ_DSR)
-               dsr_change(info);
+               dsr_change(info, status);
        if (status & IRQ_CTS)
-               cts_change(info);
+               cts_change(info, status);
        if (status & IRQ_DCD)
-               dcd_change(info);
+               dcd_change(info, status);
        if (status & IRQ_RI)
-               ri_change(info);
+               ri_change(info, status);
 }
 
 static void isr_rdma(struct slgt_info *info)
@@ -2116,7 +2225,7 @@ static void isr_rdma(struct slgt_info *info)
 
        if (status & (BIT5 + BIT4)) {
                DBGISR(("%s isr_rdma rx_restart=1\n", info->device_name));
-               info->rx_restart = 1;
+               info->rx_restart = true;
        }
        info->pending_bh |= BH_RECEIVE;
 }
@@ -2167,14 +2276,14 @@ static void isr_txeom(struct slgt_info *info, unsigned short status)
                                info->icount.txok++;
                }
 
-               info->tx_active = 0;
+               info->tx_active = false;
                info->tx_count = 0;
 
                del_timer(&info->tx_timer);
 
                if (info->params.mode != MGSL_MODE_ASYNC && info->drop_rts_on_tx_done) {
                        info->signals &= ~SerialSignal_RTS;
-                       info->drop_rts_on_tx_done = 0;
+                       info->drop_rts_on_tx_done = false;
                        set_signals(info);
                }
 
@@ -2216,23 +2325,19 @@ static void isr_gpio(struct slgt_info *info, unsigned int changed, unsigned int
  *     irq     interrupt number
  *     dev_id  device ID supplied during interrupt registration
  */
-static irqreturn_t slgt_interrupt(int irq, void *dev_id)
+static irqreturn_t slgt_interrupt(int dummy, void *dev_id)
 {
-       struct slgt_info *info;
+       struct slgt_info *info = dev_id;
        unsigned int gsr;
        unsigned int i;
 
-       DBGISR(("slgt_interrupt irq=%d entry\n", irq));
-
-       info = dev_id;
-       if (!info)
-               return IRQ_NONE;
+       DBGISR(("slgt_interrupt irq=%d entry\n", info->irq_level));
 
        spin_lock(&info->lock);
 
        while((gsr = rd_reg32(info, GSR) & 0xffffff00)) {
                DBGISR(("%s gsr=%08x\n", info->device_name, gsr));
-               info->irq_occurred = 1;
+               info->irq_occurred = true;
                for(i=0; i < info->port_count ; i++) {
                        if (info->port_array[i] == NULL)
                                continue;
@@ -2269,13 +2374,13 @@ static irqreturn_t slgt_interrupt(int irq, void *dev_id)
                    !port->bh_requested) {
                        DBGISR(("%s bh queued\n", port->device_name));
                        schedule_work(&port->task);
-                       port->bh_requested = 1;
+                       port->bh_requested = true;
                }
        }
 
        spin_unlock(&info->lock);
 
-       DBGISR(("slgt_interrupt irq=%d exit\n", irq));
+       DBGISR(("slgt_interrupt irq=%d exit\n", info->irq_level));
        return IRQ_HANDLED;
 }
 
@@ -3005,7 +3110,8 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
 {
        DECLARE_WAITQUEUE(wait, current);
        int             retval;
-       int             do_clocal = 0, extra_count = 0;
+       bool            do_clocal = false;
+       bool            extra_count = false;
        unsigned long   flags;
 
        DBGINFO(("%s block_til_ready\n", tty->driver->name));
@@ -3017,7 +3123,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
        }
 
        if (tty->termios->c_cflag & CLOCAL)
-               do_clocal = 1;
+               do_clocal = true;
 
        /* Wait for carrier detect and the line to become
         * free (i.e., not in use by the callout).  While we are in
@@ -3031,7 +3137,7 @@ static int block_til_ready(struct tty_struct *tty, struct file *filp,
 
        spin_lock_irqsave(&info->lock, flags);
        if (!tty_hung_up_p(filp)) {
-               extra_count = 1;
+               extra_count = true;
                info->count--;
        }
        spin_unlock_irqrestore(&info->lock, flags);
@@ -3216,7 +3322,7 @@ static int claim_resources(struct slgt_info *info)
                goto errout;
        }
        else
-               info->reg_addr_requested = 1;
+               info->reg_addr_requested = true;
 
        info->reg_addr = ioremap(info->phys_reg_addr, SLGT_REG_SIZE);
        if (!info->reg_addr) {
@@ -3236,12 +3342,12 @@ static void release_resources(struct slgt_info *info)
 {
        if (info->irq_requested) {
                free_irq(info->irq_level, info);
-               info->irq_requested = 0;
+               info->irq_requested = false;
        }
 
        if (info->reg_addr_requested) {
                release_mem_region(info->phys_reg_addr, SLGT_REG_SIZE);
-               info->reg_addr_requested = 0;
+               info->reg_addr_requested = false;
        }
 
        if (info->reg_addr) {
@@ -3316,13 +3422,12 @@ 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->max_frame_size = 4096;
@@ -3407,7 +3512,7 @@ static void device_init(int adapter_num, struct pci_dev *pdev)
                                port_array[0]->device_name,
                                port_array[0]->irq_level));
                } else {
-                       port_array[0]->irq_requested = 1;
+                       port_array[0]->irq_requested = true;
                        adapter_test(port_array[0]);
                        for (i=1 ; i < port_count ; i++) {
                                port_array[i]->init_error = port_array[0]->init_error;
@@ -3446,6 +3551,7 @@ static const 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,
@@ -3549,7 +3655,7 @@ static int __init slgt_init(void)
                printk("%s pci_register_driver error=%d\n", driver_name, rc);
                goto error;
        }
-       pci_registered = 1;
+       pci_registered = true;
 
        if (!slgt_device_list)
                printk("%s no devices found\n",driver_name);
@@ -3707,8 +3813,8 @@ static void rx_stop(struct slgt_info *info)
 
        rdma_reset(info);
 
-       info->rx_enabled = 0;
-       info->rx_restart = 0;
+       info->rx_enabled = false;
+       info->rx_restart = false;
 }
 
 static void rx_start(struct slgt_info *info)
@@ -3744,8 +3850,8 @@ static void rx_start(struct slgt_info *info)
        /* enable receiver */
        wr_reg16(info, RCR, (unsigned short)(rd_reg16(info, RCR) | BIT1));
 
-       info->rx_restart = 0;
-       info->rx_enabled = 1;
+       info->rx_restart = false;
+       info->rx_enabled = true;
 }
 
 static void tx_start(struct slgt_info *info)
@@ -3753,11 +3859,11 @@ static void tx_start(struct slgt_info *info)
        if (!info->tx_enabled) {
                wr_reg16(info, TCR,
                         (unsigned short)((rd_reg16(info, TCR) | BIT1) & ~BIT2));
-               info->tx_enabled = TRUE;
+               info->tx_enabled = true;
        }
 
        if (info->tx_count) {
-               info->drop_rts_on_tx_done = 0;
+               info->drop_rts_on_tx_done = false;
 
                if (info->params.mode != MGSL_MODE_ASYNC) {
                        if (info->params.flags & HDLC_FLAG_AUTO_RTS) {
@@ -3765,7 +3871,7 @@ static void tx_start(struct slgt_info *info)
                                if (!(info->signals & SerialSignal_RTS)) {
                                        info->signals |= SerialSignal_RTS;
                                        set_signals(info);
-                                       info->drop_rts_on_tx_done = 1;
+                                       info->drop_rts_on_tx_done = true;
                                }
                        }
 
@@ -3773,41 +3879,55 @@ static void tx_start(struct slgt_info *info)
                        slgt_irq_on(info, IRQ_TXUNDER + IRQ_TXIDLE);
                        /* clear tx idle and underrun status bits */
                        wr_reg16(info, SSR, (unsigned short)(IRQ_TXIDLE + IRQ_TXUNDER));
-
-                       if (!(rd_reg32(info, TDCSR) & BIT0)) {
-                               /* tx DMA stopped, restart tx DMA */
-                               tdma_reset(info);
-                               /* set 1st descriptor address */
-                               wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc);
-                               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 */
-                                       break;
-                               default:
-                                       wr_reg32(info, TDCSR, BIT0); /* DMA enable */
-                               }
-                       }
-
                        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 */
-                       wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc);
-
                        slgt_irq_off(info, IRQ_TXDATA);
                        slgt_irq_on(info, IRQ_TXIDLE);
                        /* clear tx idle status bit */
                        wr_reg16(info, SSR, IRQ_TXIDLE);
-
-                       /* enable tx DMA */
-                       wr_reg32(info, TDCSR, BIT0);
                }
+               tdma_start(info);
+               info->tx_active = true;
+       }
+}
 
-               info->tx_active = 1;
+/*
+ * start transmit DMA if inactive and there are unsent buffers
+ */
+static void tdma_start(struct slgt_info *info)
+{
+       unsigned int i;
+
+       if (rd_reg32(info, TDCSR) & BIT0)
+               return;
+
+       /* transmit DMA inactive, check for unsent buffers */
+       i = info->tbuf_start;
+       while (!desc_count(info->tbufs[i])) {
+               if (++i == info->tbuf_count)
+                       i = 0;
+               if (i == info->tbuf_current)
+                       return;
+       }
+       info->tbuf_start = i;
+
+       /* there are unsent buffers, start transmit DMA */
+
+       /* reset needed if previous error condition */
+       tdma_reset(info);
+
+       /* set 1st descriptor address */
+       wr_reg32(info, TDDAR, info->tbufs[info->tbuf_start].pdesc);
+       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 */
+               break;
+       default:
+               wr_reg32(info, TDCSR, BIT0); /* DMA enable */
        }
 }
 
@@ -3830,8 +3950,8 @@ static void tx_stop(struct slgt_info *info)
 
        reset_tbufs(info);
 
-       info->tx_enabled = 0;
-       info->tx_active  = 0;
+       info->tx_enabled = false;
+       info->tx_active = false;
 }
 
 static void reset_port(struct slgt_info *info)
@@ -4351,14 +4471,13 @@ static void reset_rbufs(struct slgt_info *info)
 /*
  * pass receive HDLC frame to upper layer
  *
- * return 1 if frame available, otherwise 0
+ * return true if frame available, otherwise false
  */
-static int rx_get_frame(struct slgt_info *info)
+static bool rx_get_frame(struct slgt_info *info)
 {
        unsigned int start, end;
        unsigned short status;
        unsigned int framesize = 0;
-       int rc = 0;
        unsigned long flags;
        struct tty_struct *tty = info->tty;
        unsigned char addr_field = 0xff;
@@ -4482,23 +4601,23 @@ check_again:
                }
        }
        free_rbufs(info, start, end);
-       rc = 1;
+       return true;
 
 cleanup:
-       return rc;
+       return false;
 }
 
 /*
  * pass receive buffer (RAW synchronous mode) to tty layer
- * return 1 if buffer available, otherwise 0
+ * return true if buffer available, otherwise false
  */
-static int rx_get_buf(struct slgt_info *info)
+static bool rx_get_buf(struct slgt_info *info)
 {
        unsigned int i = info->rbuf_current;
        unsigned int count;
 
        if (!desc_complete(info->rbufs[i]))
-               return 0;
+               return false;
        count = desc_count(info->rbufs[i]);
        switch(info->params.mode) {
        case MGSL_MODE_MONOSYNC:
@@ -4514,7 +4633,7 @@ static int rx_get_buf(struct slgt_info *info)
                ldisc_receive_buf(info->tty, info->rbufs[i].buf,
                                  info->flag_buf, count);
        free_rbufs(info, i, i);
-       return 1;
+       return true;
 }
 
 static void reset_tbufs(struct slgt_info *info)
@@ -4544,8 +4663,8 @@ static unsigned int free_tbuf_count(struct slgt_info *info)
                        i=0;
        } while (i != info->tbuf_current);
 
-       /* last buffer with zero count may be in use, assume it is */
-       if (count)
+       /* if tx DMA active, last zero count buffer is in use */
+       if (count && (rd_reg32(info, TDCSR) & BIT0))
                --count;
 
        return count;
@@ -4639,7 +4758,7 @@ static int irq_test(struct slgt_info *info)
 
        /* assume failure */
        info->init_error = DiagStatus_IrqFailure;
-       info->irq_occurred = FALSE;
+       info->irq_occurred = false;
 
        spin_unlock_irqrestore(&info->lock, flags);
 
@@ -4772,7 +4891,7 @@ static void tx_timeout(unsigned long context)
                info->icount.txtimeout++;
        }
        spin_lock_irqsave(&info->lock,flags);
-       info->tx_active = 0;
+       info->tx_active = false;
        info->tx_count = 0;
        spin_unlock_irqrestore(&info->lock,flags);