|
@@ -27,6 +27,10 @@
|
|
|
* 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)
|
|
@@ -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;
|
|
@@ -307,13 +295,7 @@ static void send_circ_buf(struct uart_max3110 *max,
|
|
|
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;
|
|
@@ -353,30 +335,48 @@ static void serial_m3110_start_tx(struct uart_port *port)
|
|
|
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;
|
|
|
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;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- while (len) {
|
|
|
- usable = tty_buffer_request_room(tty, len);
|
|
|
+ if (!w)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ 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);
|
|
|
+
|
|
|
+ return r;
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -391,28 +391,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)
|