Merge branch 'tty-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
[pandora-kernel.git] / drivers / tty / serial / mrst_max3110.c
index 492c14d..4c309e8 100644 (file)
  *    interrupt for a low speed UART device
  */
 
+#ifdef CONFIG_MAGIC_SYSRQ
+#define SUPPORT_SYSRQ
+#endif
+
 #include <linux/module.h>
 #include <linux/ioport.h>
 #include <linux/irq.h>
@@ -73,9 +77,9 @@ struct uart_max3110 {
 /* global data structure, may need be removed */
 static struct uart_max3110 *pmax;
 
-static void receive_chars(struct uart_max3110 *max,
-                               unsigned char *str, int len);
-static int max3110_read_multi(struct uart_max3110 *max, u8 *buf);
+static int receive_chars(struct uart_max3110 *max,
+                               unsigned short *str, int len);
+static int max3110_read_multi(struct uart_max3110 *max);
 static void max3110_con_receive(struct uart_max3110 *max);
 
 static int max3110_write_then_read(struct uart_max3110 *max,
@@ -108,7 +112,6 @@ static int max3110_out(struct uart_max3110 *max, const u16 out)
 {
        void *buf;
        u16 *obuf, *ibuf;
-       u8  ch;
        int ret;
 
        buf = kzalloc(8, GFP_KERNEL | GFP_DMA);
@@ -125,11 +128,7 @@ static int max3110_out(struct uart_max3110 *max, const u16 out)
                goto exit;
        }
 
-       /* If some valid data is read back */
-       if (*ibuf & MAX3110_READ_DATA_AVAILABLE) {
-               ch = *ibuf & 0xff;
-               receive_chars(max, &ch, 1);
-       }
+       receive_chars(max, ibuf, 1);
 
 exit:
        kfree(buf);
@@ -142,12 +141,11 @@ exit:
  *
  * Return how many valide bytes are read back
  */
-static int max3110_read_multi(struct uart_max3110 *max, u8 *rxbuf)
+static int max3110_read_multi(struct uart_max3110 *max)
 {
        void *buf;
        u16 *obuf, *ibuf;
-       u8 *pbuf, valid_str[M3110_RX_FIFO_DEPTH];
-       int i, j, blen;
+       int ret, blen;
 
        blen = M3110_RX_FIFO_DEPTH * sizeof(u16);
        buf = kzalloc(blen * 2, GFP_KERNEL | GFP_DMA);
@@ -165,19 +163,10 @@ static int max3110_read_multi(struct uart_max3110 *max, u8 *rxbuf)
                return 0;
        }
 
-       /* If caller doesn't provide a buffer, then handle received char */
-       pbuf = rxbuf ? rxbuf : valid_str;
-
-       for (i = 0, j = 0; i < M3110_RX_FIFO_DEPTH; i++) {
-               if (ibuf[i] & MAX3110_READ_DATA_AVAILABLE)
-                       pbuf[j++] = ibuf[i] & 0xff;
-       }
-
-       if (j && (pbuf == valid_str))
-               receive_chars(max, valid_str, j);
+       ret = receive_chars(max, ibuf, M3110_RX_FIFO_DEPTH);
 
        kfree(buf);
-       return j;
+       return ret;
 }
 
 static void serial_m3110_con_putchar(struct uart_port *port, int ch)
@@ -207,7 +196,7 @@ static void serial_m3110_con_write(struct console *co,
        uart_console_write(&pmax->port, s, count, serial_m3110_con_putchar);
 
        if (!test_and_set_bit(CON_TX_NEEDED, &pmax->uart_flags))
-               wake_up_process(pmax->main_thread);
+               wake_up(&pmax->wq);
 }
 
 static int __init
@@ -276,8 +265,7 @@ static void send_circ_buf(struct uart_max3110 *max,
 {
        void *buf;
        u16 *obuf, *ibuf;
-       u8 valid_str[WORDS_PER_XFER];
-       int i, j, len, blen, dma_size, left, ret = 0;
+       int i, len, blen, dma_size, left, ret = 0;
 
 
        dma_size = WORDS_PER_XFER * sizeof(u16) * 2;
@@ -301,18 +289,13 @@ static void send_circ_buf(struct uart_max3110 *max,
                        }
 
                        /* Fail to send msg to console is not very critical */
+
                        ret = max3110_write_then_read(max, obuf, ibuf, blen, 0);
                        if (ret)
                                pr_warning(PR_FMT "%s(): get err msg %d\n",
                                                __func__, ret);
 
-                       for (i = 0, j = 0; i < len; i++) {
-                               if (ibuf[i] & MAX3110_READ_DATA_AVAILABLE)
-                                       valid_str[j++] = ibuf[i] & 0xff;
-                       }
-
-                       if (j)
-                               receive_chars(max, valid_str, j);
+                       receive_chars(max, ibuf, len);
 
                        max->port.icount.tx += len;
                        left -= len;
@@ -349,33 +332,54 @@ static void serial_m3110_start_tx(struct uart_port *port)
                container_of(port, struct uart_max3110, port);
 
        if (!test_and_set_bit(UART_TX_NEEDED, &max->uart_flags))
-               wake_up_process(max->main_thread);
+               wake_up(&max->wq);
 }
 
-static void receive_chars(struct uart_max3110 *max, unsigned char *str, int len)
+static int
+receive_chars(struct uart_max3110 *max, unsigned short *str, int len)
 {
        struct uart_port *port = &max->port;
        struct tty_struct *tty;
-       int usable;
+       char buf[M3110_RX_FIFO_DEPTH];
+       int r, w, usable;
 
        /* If uart is not opened, just return */
        if (!port->state)
-               return;
+               return 0;
 
-       tty = port->state->port.tty;
+       tty = tty_port_tty_get(&port->state->port);
        if (!tty)
-               return;
+               return 0;
+
+       for (r = 0, w = 0; r < len; r++) {
+               if (str[r] & MAX3110_BREAK &&
+                   uart_handle_break(port))
+                       continue;
+
+               if (str[r] & MAX3110_READ_DATA_AVAILABLE) {
+                       if (uart_handle_sysrq_char(port, str[r] & 0xff))
+                               continue;
+
+                       buf[w++] = str[r] & 0xff;
+               }
+       }
+
+       if (!w) {
+               tty_kref_put(tty);
+               return 0;
+       }
 
-       while (len) {
-               usable = tty_buffer_request_room(tty, len);
+       for (r = 0; w; r += usable, w -= usable) {
+               usable = tty_buffer_request_room(tty, w);
                if (usable) {
-                       tty_insert_flip_string(tty, str, usable);
-                       str += usable;
+                       tty_insert_flip_string(tty, buf + r, usable);
                        port->icount.rx += usable;
                }
-               len -= usable;
        }
        tty_flip_buffer_push(tty);
+       tty_kref_put(tty);
+
+       return r;
 }
 
 /*
@@ -390,28 +394,15 @@ static void receive_chars(struct uart_max3110 *max, unsigned char *str, int len)
  */
 static void max3110_con_receive(struct uart_max3110 *max)
 {
-       int loop = 1, num, total = 0;
-       u8 recv_buf[512], *pbuf;
+       int loop = 1, num;
 
-       pbuf = recv_buf;
        do {
-               num = max3110_read_multi(max, pbuf);
+               num = max3110_read_multi(max);
 
                if (num) {
                        loop = 5;
-                       pbuf += num;
-                       total += num;
-
-                       if (total >= 504) {
-                               receive_chars(max, recv_buf, total);
-                               pbuf = recv_buf;
-                               total = 0;
-                       }
                }
        } while (--loop);
-
-       if (total)
-               receive_chars(max, recv_buf, total);
 }
 
 static int max3110_main_thread(void *_max)
@@ -424,7 +415,8 @@ static int max3110_main_thread(void *_max)
        pr_info(PR_FMT "start main thread\n");
 
        do {
-               wait_event_interruptible(*wq, max->uart_flags || kthread_should_stop());
+               wait_event_interruptible(*wq,
+                               max->uart_flags || kthread_should_stop());
 
                mutex_lock(&max->thread_mutex);
 
@@ -452,8 +444,9 @@ static irqreturn_t serial_m3110_irq(int irq, void *dev_id)
 
        /* max3110's irq is a falling edge, not level triggered,
         * so no need to disable the irq */
+
        if (!test_and_set_bit(BIT_IRQ_PENDING, &max->uart_flags))
-               wake_up_process(max->main_thread);
+               wake_up(&max->wq);
 
        return IRQ_HANDLED;
 }