diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-26 17:11:09 +0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-10-26 17:11:09 +0400 |
commit | efb8d21b2c6db3497655cc6a033ae8a9883e4063 (patch) | |
tree | a14a0dbb9fec3a6db5e542ba7ed4a49681706420 /drivers/tty/serial/mrst_max3110.c | |
parent | 3cb603284b3d256ae9ae9e65887cee8416bfef15 (diff) | |
parent | d208a3bf77f902283894f546b6b5383202cf7882 (diff) | |
download | linux-efb8d21b2c6db3497655cc6a033ae8a9883e4063.tar.xz |
Merge branch 'tty-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
* 'tty-next' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (79 commits)
TTY: serial_core: Fix crash if DCD drop during suspend
tty/serial: atmel_serial: bootconsole removed from auto-enumerates
Revert "TTY: call tty_driver_lookup_tty unconditionally"
tty/serial: atmel_serial: add device tree support
tty/serial: atmel_serial: auto-enumerate ports
tty/serial: atmel_serial: whitespace and braces modifications
tty/serial: atmel_serial: change platform_data variable name
tty/serial: RS485 bindings for device tree
TTY: call tty_driver_lookup_tty unconditionally
TTY: pty, release tty in all ptmx_open fail paths
TTY: make tty_add_file non-failing
TTY: drop driver reference in tty_open fail path
8250_pci: Fix kernel panic when pch_uart is disabled
h8300: drivers/serial/Kconfig was moved
parport_pc: release IO region properly if unsupported ITE887x card is found
tty: Support compat_ioctl get/set termios_locked
hvc_console: display printk messages on console.
TTY: snyclinkmp: forever loop in tx_load_dma_buffer()
tty/n_gsm: avoid fifo overflow in gsm_dlci_data_output
tty/n_gsm: fix a bug in gsm_dlci_data_output (adaption = 2 case)
...
Fix up Conflicts in:
- drivers/tty/serial/8250_pci.c
Trivial conflict with removed duplicate device ID
- drivers/tty/serial/atmel_serial.c
Annoying silly conflict between "specify the port num via
platform_data" and other changes to atmel_console_init
Diffstat (limited to 'drivers/tty/serial/mrst_max3110.c')
-rw-r--r-- | drivers/tty/serial/mrst_max3110.c | 115 |
1 files changed, 54 insertions, 61 deletions
diff --git a/drivers/tty/serial/mrst_max3110.c b/drivers/tty/serial/mrst_max3110.c index 492c14d63e99..4c309e869903 100644 --- a/drivers/tty/serial/mrst_max3110.c +++ b/drivers/tty/serial/mrst_max3110.c @@ -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) @@ -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; } |