]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/char/synclink_gt.c
rtc: push the BKL down into the driver ioctl method
[linux-2.6-omap-h63xx.git] / drivers / char / synclink_gt.c
index 0e59cf54adaf88e4eede6003866c73dca9fb1dce..3e9058993e41805c0b2cd699ad836c76844fe398 100644 (file)
@@ -214,6 +214,7 @@ struct slgt_desc
        char *buf;          /* virtual  address of data buffer */
        unsigned int pdesc; /* physical address of this descriptor */
        dma_addr_t buf_dma_addr;
+       unsigned short buf_count;
 };
 
 #define set_desc_buffer(a,b) (a).pbuf = cpu_to_le32((unsigned int)(b))
@@ -302,7 +303,7 @@ struct slgt_info {
        u32 idle_mode;
        u32 max_frame_size;       /* as set by device config */
 
-       unsigned int raw_rx_size;
+       unsigned int rbuf_fill_level;
        unsigned int if_mode;
 
        /* device status */
@@ -466,6 +467,7 @@ static void tx_start(struct slgt_info *info);
 static void tx_stop(struct slgt_info *info);
 static void tx_set_idle(struct slgt_info *info);
 static unsigned int free_tbuf_count(struct slgt_info *info);
+static unsigned int tbuf_bytes(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);
@@ -1388,10 +1390,12 @@ done:
 static int chars_in_buffer(struct tty_struct *tty)
 {
        struct slgt_info *info = tty->driver_data;
+       int count;
        if (sanity_check(info, tty->name, "chars_in_buffer"))
                return 0;
-       DBGINFO(("%s chars_in_buffer()=%d\n", info->device_name, info->tx_count));
-       return info->tx_count;
+       count = tbuf_bytes(info);
+       DBGINFO(("%s chars_in_buffer()=%d\n", info->device_name, count));
+       return count;
 }
 
 /*
@@ -2672,8 +2676,31 @@ static int tx_abort(struct slgt_info *info)
 static int rx_enable(struct slgt_info *info, int enable)
 {
        unsigned long flags;
-       DBGINFO(("%s rx_enable(%d)\n", info->device_name, enable));
+       unsigned int rbuf_fill_level;
+       DBGINFO(("%s rx_enable(%08x)\n", info->device_name, enable));
        spin_lock_irqsave(&info->lock,flags);
+       /*
+        * enable[31..16] = receive DMA buffer fill level
+        * 0 = noop (leave fill level unchanged)
+        * fill level must be multiple of 4 and <= buffer size
+        */
+       rbuf_fill_level = ((unsigned int)enable) >> 16;
+       if (rbuf_fill_level) {
+               if ((rbuf_fill_level > DMABUFSIZE) || (rbuf_fill_level % 4)) {
+                       spin_unlock_irqrestore(&info->lock, flags);
+                       return -EINVAL;
+               }
+               info->rbuf_fill_level = rbuf_fill_level;
+               rx_stop(info); /* restart receiver to use new fill level */
+       }
+
+       /*
+        * enable[1..0] = receiver enable command
+        * 0 = disable
+        * 1 = enable
+        * 2 = enable or force hunt mode if already enabled
+        */
+       enable &= 3;
        if (enable) {
                if (!info->rx_enabled)
                        rx_start(info);
@@ -3440,7 +3467,7 @@ static struct slgt_info *alloc_dev(int adapter_num, int port_num, struct pci_dev
                info->magic = MGSL_MAGIC;
                INIT_WORK(&info->task, bh_handler);
                info->max_frame_size = 4096;
-               info->raw_rx_size = DMABUFSIZE;
+               info->rbuf_fill_level = DMABUFSIZE;
                info->port.close_delay = 5*HZ/10;
                info->port.closing_wait = 30*HZ;
                init_waitqueue_head(&info->status_event_wait_q);
@@ -4130,7 +4157,7 @@ static void sync_mode(struct slgt_info *info)
         * 01      enable
         * 00      auto-CTS enable
         */
-       val = 0;
+       val = BIT2;
 
        switch(info->params.mode) {
        case MGSL_MODE_MONOSYNC: val |= BIT14 + BIT13; break;
@@ -4403,6 +4430,8 @@ static void msc_set_vcr(struct slgt_info *info)
                break;
        }
 
+       if (info->if_mode & MGSL_INTERFACE_MSB_FIRST)
+               val |= BIT4;
        if (info->signals & SerialSignal_DTR)
                val |= BIT3;
        if (info->signals & SerialSignal_RTS)
@@ -4441,16 +4470,7 @@ 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;
-               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);
-                       break;
-               default:
-                       set_desc_count(info->rbufs[i], DMABUFSIZE);
-               }
-
+               set_desc_count(info->rbufs[i], info->rbuf_fill_level);
                if (i == last)
                        done = 1;
                if (++i == info->rbuf_count)
@@ -4557,7 +4577,7 @@ check_again:
 
        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");
+       DBGDATA(info, info->rbufs[start].buf, min_t(int, framesize, info->rbuf_fill_level), "rx");
 
        if (framesize) {
                if (!(info->params.crc_type & HDLC_CRC_RETURN_EX)) {
@@ -4577,7 +4597,7 @@ check_again:
                        info->icount.rxok++;
 
                        while(copy_count) {
-                               int partial_count = min(copy_count, DMABUFSIZE);
+                               int partial_count = min_t(int, copy_count, info->rbuf_fill_level);
                                memcpy(p, info->rbufs[i].buf, partial_count);
                                p += partial_count;
                                copy_count -= partial_count;
@@ -4668,6 +4688,56 @@ static unsigned int free_tbuf_count(struct slgt_info *info)
        return count;
 }
 
+/*
+ * return number of bytes in unsent transmit DMA buffers
+ * and the serial controller tx FIFO
+ */
+static unsigned int tbuf_bytes(struct slgt_info *info)
+{
+       unsigned int total_count = 0;
+       unsigned int i = info->tbuf_current;
+       unsigned int reg_value;
+       unsigned int count;
+       unsigned int active_buf_count = 0;
+
+       /*
+        * Add descriptor counts for all tx DMA buffers.
+        * If count is zero (cleared by DMA controller after read),
+        * the buffer is complete or is actively being read from.
+        *
+        * Record buf_count of last buffer with zero count starting
+        * from current ring position. buf_count is mirror
+        * copy of count and is not cleared by serial controller.
+        * If DMA controller is active, that buffer is actively
+        * being read so add to total.
+        */
+       do {
+               count = desc_count(info->tbufs[i]);
+               if (count)
+                       total_count += count;
+               else if (!total_count)
+                       active_buf_count = info->tbufs[i].buf_count;
+               if (++i == info->tbuf_count)
+                       i = 0;
+       } while (i != info->tbuf_current);
+
+       /* read tx DMA status register */
+       reg_value = rd_reg32(info, TDCSR);
+
+       /* if tx DMA active, last zero count buffer is in use */
+       if (reg_value & BIT0)
+               total_count += active_buf_count;
+
+       /* add tx FIFO count = reg_value[15..8] */
+       total_count += (reg_value >> 8) & 0xff;
+
+       /* if transmitter active add one byte for shift register */
+       if (info->tx_active)
+               total_count++;
+
+       return total_count;
+}
+
 /*
  * load transmit DMA buffer(s) with data
  */
@@ -4706,6 +4776,7 @@ static void tx_load(struct slgt_info *info, const char *buf, unsigned int size)
                        set_desc_eof(*d, 0);
 
                set_desc_count(*d, count);
+               d->buf_count = count;
        }
 
        info->tbuf_current = i;