X-Git-Url: http://pilppa.org/gitweb/?a=blobdiff_plain;f=drivers%2Fchar%2Fsynclink_gt.c;h=1f954acf2bac49125be4b18f0167eb437ec0cbe0;hb=c3667d5c321ac2211d04a746f91a48d339a0e0a1;hp=428b514201f4654bfbb97beddaeef00b85bb6e9c;hpb=add096909da63ef32d6766f6771c07c9f16c6ee5;p=linux-2.6-omap-h63xx.git diff --git a/drivers/char/synclink_gt.c b/drivers/char/synclink_gt.c index 428b514201f..1f954acf2ba 100644 --- a/drivers/char/synclink_gt.c +++ b/drivers/char/synclink_gt.c @@ -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 #include #include +#include #include #include @@ -81,8 +82,6 @@ #include #include -#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"); @@ -206,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 */ @@ -477,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); @@ -904,6 +904,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); } @@ -1562,6 +1564,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 */ @@ -1631,6 +1636,7 @@ static int hdlcdev_close(struct net_device *dev) info->netcount=0; spin_unlock_irqrestore(&info->netlock, flags); + module_put(THIS_MODULE); return 0; } @@ -2033,37 +2039,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; @@ -2084,20 +2094,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) @@ -2120,20 +2131,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; @@ -2184,13 +2196,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) @@ -3414,13 +3426,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; @@ -3872,44 +3883,58 @@ 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 = 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 */ + } +} + static void tx_stop(struct slgt_info *info) { unsigned short val; @@ -4643,8 +4668,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;