diff options
Diffstat (limited to 'drivers/mmc/card/sdio_uart.c')
| -rw-r--r-- | drivers/mmc/card/sdio_uart.c | 191 |
1 files changed, 69 insertions, 122 deletions
diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c index f53755533e7..f093cea0d06 100644 --- a/drivers/mmc/card/sdio_uart.c +++ b/drivers/mmc/card/sdio_uart.c @@ -34,9 +34,10 @@ #include <linux/seq_file.h> #include <linux/serial_reg.h> #include <linux/circ_buf.h> -#include <linux/gfp.h> #include <linux/tty.h> #include <linux/tty_flip.h> +#include <linux/kfifo.h> +#include <linux/slab.h> #include <linux/mmc/core.h> #include <linux/mmc/card.h> @@ -47,19 +48,9 @@ #define UART_NR 8 /* Number of UARTs this driver can handle */ -#define UART_XMIT_SIZE PAGE_SIZE +#define FIFO_SIZE PAGE_SIZE #define WAKEUP_CHARS 256 -#define circ_empty(circ) ((circ)->head == (circ)->tail) -#define circ_clear(circ) ((circ)->head = (circ)->tail = 0) - -#define circ_chars_pending(circ) \ - (CIRC_CNT((circ)->head, (circ)->tail, UART_XMIT_SIZE)) - -#define circ_chars_free(circ) \ - (CIRC_SPACE((circ)->head, (circ)->tail, UART_XMIT_SIZE)) - - struct uart_icount { __u32 cts; __u32 dsr; @@ -75,14 +66,12 @@ struct uart_icount { struct sdio_uart_port { struct tty_port port; - struct kref kref; - struct tty_struct *tty; unsigned int index; struct sdio_func *func; struct mutex func_lock; struct task_struct *in_sdio_uart_irq; unsigned int regs_offset; - struct circ_buf xmit; + struct kfifo xmit_fifo; spinlock_t write_lock; struct uart_icount icount; unsigned int uartclk; @@ -102,9 +91,10 @@ static int sdio_uart_add_port(struct sdio_uart_port *port) { int index, ret = -EBUSY; - kref_init(&port->kref); mutex_init(&port->func_lock); spin_lock_init(&port->write_lock); + if (kfifo_alloc(&port->xmit_fifo, FIFO_SIZE, GFP_KERNEL)) + return -ENOMEM; spin_lock(&sdio_uart_table_lock); for (index = 0; index < UART_NR; index++) { @@ -130,28 +120,20 @@ static struct sdio_uart_port *sdio_uart_port_get(unsigned index) spin_lock(&sdio_uart_table_lock); port = sdio_uart_table[index]; if (port) - kref_get(&port->kref); + tty_port_get(&port->port); spin_unlock(&sdio_uart_table_lock); return port; } -static void sdio_uart_port_destroy(struct kref *kref) -{ - struct sdio_uart_port *port = - container_of(kref, struct sdio_uart_port, kref); - kfree(port); -} - static void sdio_uart_port_put(struct sdio_uart_port *port) { - kref_put(&port->kref, sdio_uart_port_destroy); + tty_port_put(&port->port); } static void sdio_uart_port_remove(struct sdio_uart_port *port) { struct sdio_func *func; - struct tty_struct *tty; BUG_ON(sdio_uart_table[port->index] != port); @@ -172,12 +154,8 @@ static void sdio_uart_port_remove(struct sdio_uart_port *port) sdio_claim_host(func); port->func = NULL; mutex_unlock(&port->func_lock); - tty = tty_port_tty_get(&port->port); /* tty_hangup is async so is this safe as is ?? */ - if (tty) { - tty_hangup(tty); - tty_kref_put(tty); - } + tty_port_tty_hangup(&port->port, false); mutex_unlock(&port->port.mutex); sdio_release_irq(func); sdio_disable_func(func); @@ -398,7 +376,6 @@ static void sdio_uart_stop_rx(struct sdio_uart_port *port) static void sdio_uart_receive_chars(struct sdio_uart_port *port, unsigned int *status) { - struct tty_struct *tty = tty_port_tty_get(&port->port); unsigned int ch, flag; int max_count = 256; @@ -435,30 +412,28 @@ static void sdio_uart_receive_chars(struct sdio_uart_port *port, } if ((*status & port->ignore_status_mask & ~UART_LSR_OE) == 0) - if (tty) - tty_insert_flip_char(tty, ch, flag); + tty_insert_flip_char(&port->port, ch, flag); /* * Overrun is special. Since it's reported immediately, * it doesn't affect the current character. */ if (*status & ~port->ignore_status_mask & UART_LSR_OE) - if (tty) - tty_insert_flip_char(tty, 0, TTY_OVERRUN); + tty_insert_flip_char(&port->port, 0, TTY_OVERRUN); *status = sdio_in(port, UART_LSR); } while ((*status & UART_LSR_DR) && (max_count-- > 0)); - if (tty) { - tty_flip_buffer_push(tty); - tty_kref_put(tty); - } + + tty_flip_buffer_push(&port->port); } static void sdio_uart_transmit_chars(struct sdio_uart_port *port) { - struct circ_buf *xmit = &port->xmit; + struct kfifo *xmit = &port->xmit_fifo; int count; struct tty_struct *tty; + u8 iobuf[16]; + int len; if (port->x_char) { sdio_out(port, UART_TX, port->x_char); @@ -469,27 +444,25 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port) tty = tty_port_tty_get(&port->port); - if (tty == NULL || circ_empty(xmit) || + if (tty == NULL || !kfifo_len(xmit) || tty->stopped || tty->hw_stopped) { sdio_uart_stop_tx(port); tty_kref_put(tty); return; } - count = 16; - do { - sdio_out(port, UART_TX, xmit->buf[xmit->tail]); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + len = kfifo_out_locked(xmit, iobuf, 16, &port->write_lock); + for (count = 0; count < len; count++) { + sdio_out(port, UART_TX, iobuf[count]); port->icount.tx++; - if (circ_empty(xmit)) - break; - } while (--count > 0); + } - if (circ_chars_pending(xmit) < WAKEUP_CHARS) + len = kfifo_len(xmit); + if (len < WAKEUP_CHARS) { tty_wakeup(tty); - - if (circ_empty(xmit)) - sdio_uart_stop_tx(port); + if (len == 0) + sdio_uart_stop_tx(port); + } tty_kref_put(tty); } @@ -514,17 +487,13 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port) wake_up_interruptible(&port->port.open_wait); else { /* DCD drop - hang up if tty attached */ - tty = tty_port_tty_get(&port->port); - if (tty) { - tty_hangup(tty); - tty_kref_put(tty); - } + tty_port_tty_hangup(&port->port, false); } } if (status & UART_MSR_DCTS) { port->icount.cts++; tty = tty_port_tty_get(&port->port); - if (tty && (tty->termios->c_cflag & CRTSCTS)) { + if (tty && (tty->termios.c_cflag & CRTSCTS)) { int cts = (status & UART_MSR_CTS); if (tty->hw_stopped) { if (cts) { @@ -581,7 +550,7 @@ static int uart_carrier_raised(struct tty_port *tport) struct sdio_uart_port *port = container_of(tport, struct sdio_uart_port, port); unsigned int ret = sdio_uart_claim_func(port); - if (ret) /* Missing hardware shoudn't block for carrier */ + if (ret) /* Missing hardware shouldn't block for carrier */ return 1; ret = sdio_uart_get_mctrl(port); sdio_uart_release_func(port); @@ -632,7 +601,6 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty) { struct sdio_uart_port *port = container_of(tport, struct sdio_uart_port, port); - unsigned long page; int ret; /* @@ -641,22 +609,17 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty) */ set_bit(TTY_IO_ERROR, &tty->flags); - /* Initialise and allocate the transmit buffer. */ - page = __get_free_page(GFP_KERNEL); - if (!page) - return -ENOMEM; - port->xmit.buf = (unsigned char *)page; - circ_clear(&port->xmit); + kfifo_reset(&port->xmit_fifo); ret = sdio_uart_claim_func(port); if (ret) - goto err1; + return ret; ret = sdio_enable_func(port->func); if (ret) - goto err2; + goto err1; ret = sdio_claim_irq(port->func, sdio_uart_irq); if (ret) - goto err3; + goto err2; /* * Clear the FIFO buffers and disable them. @@ -683,12 +646,12 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty) port->ier = UART_IER_RLSI|UART_IER_RDI|UART_IER_RTOIE|UART_IER_UUE; port->mctrl = TIOCM_OUT2; - sdio_uart_change_speed(port, tty->termios, NULL); + sdio_uart_change_speed(port, &tty->termios, NULL); - if (tty->termios->c_cflag & CBAUD) + if (tty->termios.c_cflag & CBAUD) sdio_uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR); - if (tty->termios->c_cflag & CRTSCTS) + if (tty->termios.c_cflag & CRTSCTS) if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS)) tty->hw_stopped = 1; @@ -700,12 +663,10 @@ static int sdio_uart_activate(struct tty_port *tport, struct tty_struct *tty) sdio_uart_release_func(port); return 0; -err3: - sdio_disable_func(port->func); err2: - sdio_uart_release_func(port); + sdio_disable_func(port->func); err1: - free_page((unsigned long)port->xmit.buf); + sdio_uart_release_func(port); return ret; } @@ -727,7 +688,7 @@ static void sdio_uart_shutdown(struct tty_port *tport) ret = sdio_uart_claim_func(port); if (ret) - goto skip; + return; sdio_uart_stop_rx(port); @@ -749,10 +710,14 @@ static void sdio_uart_shutdown(struct tty_port *tport) sdio_disable_func(port->func); sdio_uart_release_func(port); +} -skip: - /* Free the transmit buffer page. */ - free_page((unsigned long)port->xmit.buf); +static void sdio_uart_port_destroy(struct tty_port *tport) +{ + struct sdio_uart_port *port = + container_of(tport, struct sdio_uart_port, port); + kfifo_free(&port->xmit_fifo); + kfree(port); } /** @@ -768,15 +733,12 @@ static int sdio_uart_install(struct tty_driver *driver, struct tty_struct *tty) { int idx = tty->index; struct sdio_uart_port *port = sdio_uart_port_get(idx); - int ret = tty_init_termios(tty); + int ret = tty_standard_install(driver, tty); - if (ret == 0) { - tty_driver_kref_get(driver); - tty->count++; + if (ret == 0) /* This is the ref sdio_uart_port get provided */ tty->driver_data = port; - driver->ttys[idx] = tty; - } else + else sdio_uart_port_put(port); return ret; } @@ -822,27 +784,12 @@ static int sdio_uart_write(struct tty_struct *tty, const unsigned char *buf, int count) { struct sdio_uart_port *port = tty->driver_data; - struct circ_buf *circ = &port->xmit; - int c, ret = 0; + int ret; if (!port->func) return -ENODEV; - spin_lock(&port->write_lock); - while (1) { - c = CIRC_SPACE_TO_END(circ->head, circ->tail, UART_XMIT_SIZE); - if (count < c) - c = count; - if (c <= 0) - break; - memcpy(circ->buf + circ->head, buf, c); - circ->head = (circ->head + c) & (UART_XMIT_SIZE - 1); - buf += c; - count -= c; - ret += c; - } - spin_unlock(&port->write_lock); - + ret = kfifo_in_locked(&port->xmit_fifo, buf, count, &port->write_lock); if (!(port->ier & UART_IER_THRI)) { int err = sdio_uart_claim_func(port); if (!err) { @@ -859,13 +806,13 @@ static int sdio_uart_write(struct tty_struct *tty, const unsigned char *buf, static int sdio_uart_write_room(struct tty_struct *tty) { struct sdio_uart_port *port = tty->driver_data; - return port ? circ_chars_free(&port->xmit) : 0; + return FIFO_SIZE - kfifo_len(&port->xmit_fifo); } static int sdio_uart_chars_in_buffer(struct tty_struct *tty) { struct sdio_uart_port *port = tty->driver_data; - return port ? circ_chars_pending(&port->xmit) : 0; + return kfifo_len(&port->xmit_fifo); } static void sdio_uart_send_xchar(struct tty_struct *tty, char ch) @@ -886,7 +833,7 @@ static void sdio_uart_throttle(struct tty_struct *tty) { struct sdio_uart_port *port = tty->driver_data; - if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS)) + if (!I_IXOFF(tty) && !(tty->termios.c_cflag & CRTSCTS)) return; if (sdio_uart_claim_func(port) != 0) @@ -897,7 +844,7 @@ static void sdio_uart_throttle(struct tty_struct *tty) sdio_uart_start_tx(port); } - if (tty->termios->c_cflag & CRTSCTS) + if (tty->termios.c_cflag & CRTSCTS) sdio_uart_clear_mctrl(port, TIOCM_RTS); sdio_uart_irq(port->func); @@ -908,7 +855,7 @@ static void sdio_uart_unthrottle(struct tty_struct *tty) { struct sdio_uart_port *port = tty->driver_data; - if (!I_IXOFF(tty) && !(tty->termios->c_cflag & CRTSCTS)) + if (!I_IXOFF(tty) && !(tty->termios.c_cflag & CRTSCTS)) return; if (sdio_uart_claim_func(port) != 0) @@ -923,7 +870,7 @@ static void sdio_uart_unthrottle(struct tty_struct *tty) } } - if (tty->termios->c_cflag & CRTSCTS) + if (tty->termios.c_cflag & CRTSCTS) sdio_uart_set_mctrl(port, TIOCM_RTS); sdio_uart_irq(port->func); @@ -934,12 +881,12 @@ static void sdio_uart_set_termios(struct tty_struct *tty, struct ktermios *old_termios) { struct sdio_uart_port *port = tty->driver_data; - unsigned int cflag = tty->termios->c_cflag; + unsigned int cflag = tty->termios.c_cflag; if (sdio_uart_claim_func(port) != 0) return; - sdio_uart_change_speed(port, tty->termios, old_termios); + sdio_uart_change_speed(port, &tty->termios, old_termios); /* Handle transition to B0 status */ if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) @@ -989,7 +936,7 @@ static int sdio_uart_break_ctl(struct tty_struct *tty, int break_state) return 0; } -static int sdio_uart_tiocmget(struct tty_struct *tty, struct file *file) +static int sdio_uart_tiocmget(struct tty_struct *tty) { struct sdio_uart_port *port = tty->driver_data; int result; @@ -1003,7 +950,7 @@ static int sdio_uart_tiocmget(struct tty_struct *tty, struct file *file) return result; } -static int sdio_uart_tiocmset(struct tty_struct *tty, struct file *file, +static int sdio_uart_tiocmset(struct tty_struct *tty, unsigned int set, unsigned int clear) { struct sdio_uart_port *port = tty->driver_data; @@ -1081,6 +1028,7 @@ static const struct tty_port_operations sdio_uart_port_ops = { .carrier_raised = uart_carrier_raised, .shutdown = sdio_uart_shutdown, .activate = sdio_uart_activate, + .destruct = sdio_uart_port_destroy, }; static const struct tty_operations sdio_uart_ops = { @@ -1115,7 +1063,7 @@ static int sdio_uart_probe(struct sdio_func *func, return -ENOMEM; if (func->class == SDIO_CLASS_UART) { - printk(KERN_WARNING "%s: need info on UART class basic setup\n", + pr_warning("%s: need info on UART class basic setup\n", sdio_func_id(func)); kfree(port); return -ENOSYS; @@ -1134,23 +1082,23 @@ static int sdio_uart_probe(struct sdio_func *func, break; } if (!tpl) { - printk(KERN_WARNING + pr_warning( "%s: can't find tuple 0x91 subtuple 0 (SUBTPL_SIOREG) for GPS class\n", sdio_func_id(func)); kfree(port); return -EINVAL; } - printk(KERN_DEBUG "%s: Register ID = 0x%02x, Exp ID = 0x%02x\n", + pr_debug("%s: Register ID = 0x%02x, Exp ID = 0x%02x\n", sdio_func_id(func), tpl->data[2], tpl->data[3]); port->regs_offset = (tpl->data[4] << 0) | (tpl->data[5] << 8) | (tpl->data[6] << 16); - printk(KERN_DEBUG "%s: regs offset = 0x%x\n", + pr_debug("%s: regs offset = 0x%x\n", sdio_func_id(func), port->regs_offset); port->uartclk = tpl->data[7] * 115200; if (port->uartclk == 0) port->uartclk = 115200; - printk(KERN_DEBUG "%s: clk %d baudcode %u 4800-div %u\n", + pr_debug("%s: clk %d baudcode %u 4800-div %u\n", sdio_func_id(func), port->uartclk, tpl->data[7], tpl->data[8] | (tpl->data[9] << 8)); } else { @@ -1168,8 +1116,8 @@ static int sdio_uart_probe(struct sdio_func *func, kfree(port); } else { struct device *dev; - dev = tty_register_device(sdio_uart_tty_driver, - port->index, &func->dev); + dev = tty_port_register_device(&port->port, + sdio_uart_tty_driver, port->index, &func->dev); if (IS_ERR(dev)) { sdio_uart_port_remove(port); ret = PTR_ERR(dev); @@ -1211,7 +1159,6 @@ static int __init sdio_uart_init(void) if (!tty_drv) return -ENOMEM; - tty_drv->owner = THIS_MODULE; tty_drv->driver_name = "sdio_uart"; tty_drv->name = "ttySDIO"; tty_drv->major = 0; /* dynamically allocated */ |
