diff options
Diffstat (limited to 'drivers/mmc/card/sdio_uart.c')
| -rw-r--r-- | drivers/mmc/card/sdio_uart.c | 531 |
1 files changed, 288 insertions, 243 deletions
diff --git a/drivers/mmc/card/sdio_uart.c b/drivers/mmc/card/sdio_uart.c index eeea84c309e..f093cea0d06 100644 --- a/drivers/mmc/card/sdio_uart.c +++ b/drivers/mmc/card/sdio_uart.c @@ -29,12 +29,15 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/kernel.h> +#include <linux/sched.h> #include <linux/mutex.h> +#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> @@ -45,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; @@ -72,20 +65,18 @@ struct uart_icount { }; struct sdio_uart_port { - struct kref kref; - struct tty_struct *tty; + struct tty_port port; unsigned int index; - unsigned int opened; - struct mutex open_lock; 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; unsigned int mctrl; + unsigned int rx_mctrl; unsigned int read_status_mask; unsigned int ignore_status_mask; unsigned char x_char; @@ -100,10 +91,10 @@ static int sdio_uart_add_port(struct sdio_uart_port *port) { int index, ret = -EBUSY; - kref_init(&port->kref); - mutex_init(&port->open_lock); 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++) { @@ -129,22 +120,15 @@ 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) @@ -164,15 +148,15 @@ static void sdio_uart_port_remove(struct sdio_uart_port *port) * give up on that port ASAP. * Beware: the lock ordering is critical. */ - mutex_lock(&port->open_lock); + mutex_lock(&port->port.mutex); mutex_lock(&port->func_lock); func = port->func; sdio_claim_host(func); port->func = NULL; mutex_unlock(&port->func_lock); - if (port->opened) - tty_hangup(port->tty); - mutex_unlock(&port->open_lock); + /* tty_hangup is async so is this safe as is ?? */ + tty_port_tty_hangup(&port->port, false); + mutex_unlock(&port->port.mutex); sdio_release_irq(func); sdio_disable_func(func); sdio_release_host(func); @@ -216,6 +200,8 @@ static unsigned int sdio_uart_get_mctrl(struct sdio_uart_port *port) unsigned char status; unsigned int ret; + /* FIXME: What stops this losing the delta bits and breaking + sdio_uart_check_modem_status ? */ status = sdio_in(port, UART_MSR); ret = 0; @@ -230,7 +216,8 @@ static unsigned int sdio_uart_get_mctrl(struct sdio_uart_port *port) return ret; } -static void sdio_uart_write_mctrl(struct sdio_uart_port *port, unsigned int mctrl) +static void sdio_uart_write_mctrl(struct sdio_uart_port *port, + unsigned int mctrl) { unsigned char mcr = 0; @@ -386,9 +373,9 @@ static void sdio_uart_stop_rx(struct sdio_uart_port *port) sdio_out(port, UART_IER, port->ier); } -static void sdio_uart_receive_chars(struct sdio_uart_port *port, unsigned int *status) +static void sdio_uart_receive_chars(struct sdio_uart_port *port, + unsigned int *status) { - struct tty_struct *tty = port->tty; unsigned int ch, flag; int max_count = 256; @@ -398,7 +385,7 @@ static void sdio_uart_receive_chars(struct sdio_uart_port *port, unsigned int *s port->icount.rx++; if (unlikely(*status & (UART_LSR_BI | UART_LSR_PE | - UART_LSR_FE | UART_LSR_OE))) { + UART_LSR_FE | UART_LSR_OE))) { /* * For statistics only */ @@ -416,33 +403,37 @@ static void sdio_uart_receive_chars(struct sdio_uart_port *port, unsigned int *s * Mask off conditions which should be ignored. */ *status &= port->read_status_mask; - if (*status & UART_LSR_BI) { + if (*status & UART_LSR_BI) flag = TTY_BREAK; - } else if (*status & UART_LSR_PE) + else if (*status & UART_LSR_PE) flag = TTY_PARITY; else if (*status & UART_LSR_FE) flag = TTY_FRAME; } if ((*status & port->ignore_status_mask & ~UART_LSR_OE) == 0) - 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) - 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)); - tty_flip_buffer_push(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); @@ -450,30 +441,35 @@ static void sdio_uart_transmit_chars(struct sdio_uart_port *port) port->x_char = 0; return; } - if (circ_empty(xmit) || port->tty->stopped || port->tty->hw_stopped) { + + tty = tty_port_tty_get(&port->port); + + 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) - tty_wakeup(port->tty); + } - if (circ_empty(xmit)) - sdio_uart_stop_tx(port); + len = kfifo_len(xmit); + if (len < WAKEUP_CHARS) { + tty_wakeup(tty); + if (len == 0) + sdio_uart_stop_tx(port); + } + tty_kref_put(tty); } static void sdio_uart_check_modem_status(struct sdio_uart_port *port) { int status; + struct tty_struct *tty; status = sdio_in(port, UART_MSR); @@ -484,25 +480,35 @@ static void sdio_uart_check_modem_status(struct sdio_uart_port *port) port->icount.rng++; if (status & UART_MSR_DDSR) port->icount.dsr++; - if (status & UART_MSR_DDCD) + if (status & UART_MSR_DDCD) { port->icount.dcd++; + /* DCD raise - wake for open */ + if (status & UART_MSR_DCD) + wake_up_interruptible(&port->port.open_wait); + else { + /* DCD drop - hang up if tty attached */ + tty_port_tty_hangup(&port->port, false); + } + } if (status & UART_MSR_DCTS) { port->icount.cts++; - if (port->tty->termios->c_cflag & CRTSCTS) { + tty = tty_port_tty_get(&port->port); + if (tty && (tty->termios.c_cflag & CRTSCTS)) { int cts = (status & UART_MSR_CTS); - if (port->tty->hw_stopped) { + if (tty->hw_stopped) { if (cts) { - port->tty->hw_stopped = 0; + tty->hw_stopped = 0; sdio_uart_start_tx(port); - tty_wakeup(port->tty); + tty_wakeup(tty); } } else { if (!cts) { - port->tty->hw_stopped = 1; + tty->hw_stopped = 1; sdio_uart_stop_tx(port); } } } + tty_kref_put(tty); } } @@ -539,33 +545,81 @@ static void sdio_uart_irq(struct sdio_func *func) port->in_sdio_uart_irq = NULL; } -static int sdio_uart_startup(struct sdio_uart_port *port) +static int uart_carrier_raised(struct tty_port *tport) { - unsigned long page; + 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 shouldn't block for carrier */ + return 1; + ret = sdio_uart_get_mctrl(port); + sdio_uart_release_func(port); + if (ret & TIOCM_CAR) + return 1; + return 0; +} + +/** + * uart_dtr_rts - port helper to set uart signals + * @tport: tty port to be updated + * @onoff: set to turn on DTR/RTS + * + * Called by the tty port helpers when the modem signals need to be + * adjusted during an open, close and hangup. + */ + +static void uart_dtr_rts(struct tty_port *tport, int onoff) +{ + struct sdio_uart_port *port = + container_of(tport, struct sdio_uart_port, port); + int ret = sdio_uart_claim_func(port); + if (ret) + return; + if (onoff == 0) + sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); + else + sdio_uart_set_mctrl(port, TIOCM_DTR | TIOCM_RTS); + sdio_uart_release_func(port); +} + +/** + * sdio_uart_activate - start up hardware + * @tport: tty port to activate + * @tty: tty bound to this port + * + * Activate a tty port. The port locking guarantees us this will be + * run exactly once per set of opens, and if successful will see the + * shutdown method run exactly once to match. Start up and shutdown are + * protected from each other by the internal locking and will not run + * at the same time even during a hangup event. + * + * If we successfully start up the port we take an extra kref as we + * will keep it around until shutdown when the kref is dropped. + */ + +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); int ret; /* * Set the TTY IO error marker - we will only clear this * once we have successfully opened the port. */ - set_bit(TTY_IO_ERROR, &port->tty->flags); + 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. @@ -573,7 +627,7 @@ static int sdio_uart_startup(struct sdio_uart_port *port) */ sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO); sdio_out(port, UART_FCR, UART_FCR_ENABLE_FIFO | - UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); + UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT); sdio_out(port, UART_FCR, 0); /* @@ -589,19 +643,19 @@ static int sdio_uart_startup(struct sdio_uart_port *port) */ sdio_out(port, UART_LCR, UART_LCR_WLEN8); - port->ier = UART_IER_RLSI | UART_IER_RDI | UART_IER_RTOIE | UART_IER_UUE; + port->ier = UART_IER_RLSI|UART_IER_RDI|UART_IER_RTOIE|UART_IER_UUE; port->mctrl = TIOCM_OUT2; - sdio_uart_change_speed(port, port->tty->termios, NULL); + sdio_uart_change_speed(port, &tty->termios, NULL); - if (port->tty->termios->c_cflag & CBAUD) + if (tty->termios.c_cflag & CBAUD) sdio_uart_set_mctrl(port, TIOCM_RTS | TIOCM_DTR); - if (port->tty->termios->c_cflag & CRTSCTS) + if (tty->termios.c_cflag & CRTSCTS) if (!(sdio_uart_get_mctrl(port) & TIOCM_CTS)) - port->tty->hw_stopped = 1; + tty->hw_stopped = 1; - clear_bit(TTY_IO_ERROR, &port->tty->flags); + clear_bit(TTY_IO_ERROR, &tty->flags); /* Kick the IRQ handler once while we're still holding the host lock */ sdio_uart_irq(port->func); @@ -609,32 +663,36 @@ static int sdio_uart_startup(struct sdio_uart_port *port) 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; } -static void sdio_uart_shutdown(struct sdio_uart_port *port) +/** + * sdio_uart_shutdown - stop hardware + * @tport: tty port to shut down + * + * Deactivate a tty port. The port locking guarantees us this will be + * run only if a successful matching activate already ran. The two are + * protected from each other by the internal locking and will not run + * at the same time even during a hangup event. + */ + +static void sdio_uart_shutdown(struct tty_port *tport) { + struct sdio_uart_port *port = + container_of(tport, struct sdio_uart_port, port); int ret; ret = sdio_uart_claim_func(port); if (ret) - goto skip; + return; sdio_uart_stop_rx(port); - /* TODO: wait here for TX FIFO to drain */ - - /* Turn off DTR and RTS early. */ - if (port->tty->termios->c_cflag & HUPCL) - sdio_uart_clear_mctrl(port, TIOCM_DTR | TIOCM_RTS); - - /* Disable interrupts from this port */ + /* Disable interrupts from this port */ sdio_release_irq(port->func); port->ier = 0; sdio_out(port, UART_IER, 0); @@ -652,108 +710,87 @@ static void sdio_uart_shutdown(struct sdio_uart_port *port) sdio_disable_func(port->func); sdio_uart_release_func(port); - -skip: - /* Free the transmit buffer page. */ - free_page((unsigned long)port->xmit.buf); } -static int sdio_uart_open (struct tty_struct *tty, struct file * filp) +static void sdio_uart_port_destroy(struct tty_port *tport) { - struct sdio_uart_port *port; - int ret; - - port = sdio_uart_port_get(tty->index); - if (!port) - return -ENODEV; + struct sdio_uart_port *port = + container_of(tport, struct sdio_uart_port, port); + kfifo_free(&port->xmit_fifo); + kfree(port); +} - mutex_lock(&port->open_lock); +/** + * sdio_uart_install - install method + * @driver: the driver in use (sdio_uart in our case) + * @tty: the tty being bound + * + * Look up and bind the tty and the driver together. Initialize + * any needed private data (in our case the termios) + */ - /* - * Make sure not to mess up with a dead port - * which has not been closed yet. - */ - if (tty->driver_data && tty->driver_data != port) { - mutex_unlock(&port->open_lock); - sdio_uart_port_put(port); - return -EBUSY; - } +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_standard_install(driver, tty); - if (!port->opened) { + if (ret == 0) + /* This is the ref sdio_uart_port get provided */ tty->driver_data = port; - port->tty = tty; - ret = sdio_uart_startup(port); - if (ret) { - tty->driver_data = NULL; - port->tty = NULL; - mutex_unlock(&port->open_lock); - sdio_uart_port_put(port); - return ret; - } - } - port->opened++; - mutex_unlock(&port->open_lock); - return 0; + else + sdio_uart_port_put(port); + return ret; } -static void sdio_uart_close(struct tty_struct *tty, struct file * filp) +/** + * sdio_uart_cleanup - called on the last tty kref drop + * @tty: the tty being destroyed + * + * Called asynchronously when the last reference to the tty is dropped. + * We cannot destroy the tty->driver_data port kref until this point + */ + +static void sdio_uart_cleanup(struct tty_struct *tty) { struct sdio_uart_port *port = tty->driver_data; + tty->driver_data = NULL; /* Bug trap */ + sdio_uart_port_put(port); +} - if (!port) - return; +/* + * Open/close/hangup is now entirely boilerplate + */ - mutex_lock(&port->open_lock); - BUG_ON(!port->opened); +static int sdio_uart_open(struct tty_struct *tty, struct file *filp) +{ + struct sdio_uart_port *port = tty->driver_data; + return tty_port_open(&port->port, tty, filp); +} - /* - * This is messy. The tty layer calls us even when open() - * returned an error. Ignore this close request if tty->count - * is larger than port->count. - */ - if (tty->count > port->opened) { - mutex_unlock(&port->open_lock); - return; - } +static void sdio_uart_close(struct tty_struct *tty, struct file * filp) +{ + struct sdio_uart_port *port = tty->driver_data; + tty_port_close(&port->port, tty, filp); +} - if (--port->opened == 0) { - tty->closing = 1; - sdio_uart_shutdown(port); - tty_ldisc_flush(tty); - port->tty = NULL; - tty->driver_data = NULL; - tty->closing = 0; - } - mutex_unlock(&port->open_lock); - sdio_uart_port_put(port); +static void sdio_uart_hangup(struct tty_struct *tty) +{ + struct sdio_uart_port *port = tty->driver_data; + tty_port_hangup(&port->port); } -static int sdio_uart_write(struct tty_struct * tty, const unsigned char *buf, +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); - - if ( !(port->ier & UART_IER_THRI)) { + 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) { sdio_uart_start_tx(port); @@ -769,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) @@ -796,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) @@ -807,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); @@ -818,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) @@ -833,28 +870,23 @@ 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); sdio_uart_release_func(port); } -static void sdio_uart_set_termios(struct tty_struct *tty, struct ktermios *old_termios) +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; - -#define RELEVANT_IFLAG(iflag) ((iflag) & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK)) - - if ((cflag ^ old_termios->c_cflag) == 0 && - RELEVANT_IFLAG(tty->termios->c_iflag ^ old_termios->c_iflag) == 0) - return; + 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)) @@ -885,12 +917,14 @@ static void sdio_uart_set_termios(struct tty_struct *tty, struct ktermios *old_t sdio_uart_release_func(port); } -static void sdio_uart_break_ctl(struct tty_struct *tty, int break_state) +static int sdio_uart_break_ctl(struct tty_struct *tty, int break_state) { struct sdio_uart_port *port = tty->driver_data; + int result; - if (sdio_uart_claim_func(port) != 0) - return; + result = sdio_uart_claim_func(port); + if (result != 0) + return result; if (break_state == -1) port->lcr |= UART_LCR_SBC; @@ -899,9 +933,10 @@ static void sdio_uart_break_ctl(struct tty_struct *tty, int break_state) sdio_out(port, UART_LCR, port->lcr); sdio_uart_release_func(port); + 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; @@ -915,14 +950,14 @@ 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; int result; - result =sdio_uart_claim_func(port); - if(!result) { + result = sdio_uart_claim_func(port); + if (!result) { sdio_uart_update_mctrl(port, set, clear); sdio_uart_release_func(port); } @@ -930,67 +965,72 @@ static int sdio_uart_tiocmset(struct tty_struct *tty, struct file *file, return result; } -static int sdio_uart_read_proc(char *page, char **start, off_t off, - int count, int *eof, void *data) +static int sdio_uart_proc_show(struct seq_file *m, void *v) { - int i, len = 0; - off_t begin = 0; + int i; - len += sprintf(page, "serinfo:1.0 driver%s%s revision:%s\n", + seq_printf(m, "serinfo:1.0 driver%s%s revision:%s\n", "", "", ""); - for (i = 0; i < UART_NR && len < PAGE_SIZE - 96; i++) { + for (i = 0; i < UART_NR; i++) { struct sdio_uart_port *port = sdio_uart_port_get(i); if (port) { - len += sprintf(page+len, "%d: uart:SDIO", i); - if(capable(CAP_SYS_ADMIN)) { - len += sprintf(page + len, " tx:%d rx:%d", - port->icount.tx, port->icount.rx); + seq_printf(m, "%d: uart:SDIO", i); + if (capable(CAP_SYS_ADMIN)) { + seq_printf(m, " tx:%d rx:%d", + port->icount.tx, port->icount.rx); if (port->icount.frame) - len += sprintf(page + len, " fe:%d", - port->icount.frame); + seq_printf(m, " fe:%d", + port->icount.frame); if (port->icount.parity) - len += sprintf(page + len, " pe:%d", - port->icount.parity); + seq_printf(m, " pe:%d", + port->icount.parity); if (port->icount.brk) - len += sprintf(page + len, " brk:%d", - port->icount.brk); + seq_printf(m, " brk:%d", + port->icount.brk); if (port->icount.overrun) - len += sprintf(page + len, " oe:%d", - port->icount.overrun); + seq_printf(m, " oe:%d", + port->icount.overrun); if (port->icount.cts) - len += sprintf(page + len, " cts:%d", - port->icount.cts); + seq_printf(m, " cts:%d", + port->icount.cts); if (port->icount.dsr) - len += sprintf(page + len, " dsr:%d", - port->icount.dsr); + seq_printf(m, " dsr:%d", + port->icount.dsr); if (port->icount.rng) - len += sprintf(page + len, " rng:%d", - port->icount.rng); + seq_printf(m, " rng:%d", + port->icount.rng); if (port->icount.dcd) - len += sprintf(page + len, " dcd:%d", - port->icount.dcd); + seq_printf(m, " dcd:%d", + port->icount.dcd); } - strcat(page, "\n"); - len++; sdio_uart_port_put(port); - } - - if (len + begin > off + count) - goto done; - if (len + begin < off) { - begin += len; - len = 0; + seq_putc(m, '\n'); } } - *eof = 1; + return 0; +} -done: - if (off >= len + begin) - return 0; - *start = page + (off - begin); - return (count < begin + len - off) ? count : (begin + len - off); +static int sdio_uart_proc_open(struct inode *inode, struct file *file) +{ + return single_open(file, sdio_uart_proc_show, NULL); } +static const struct file_operations sdio_uart_proc_fops = { + .owner = THIS_MODULE, + .open = sdio_uart_proc_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct tty_port_operations sdio_uart_port_ops = { + .dtr_rts = uart_dtr_rts, + .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 = { .open = sdio_uart_open, .close = sdio_uart_close, @@ -1001,10 +1041,13 @@ static const struct tty_operations sdio_uart_ops = { .throttle = sdio_uart_throttle, .unthrottle = sdio_uart_unthrottle, .set_termios = sdio_uart_set_termios, + .hangup = sdio_uart_hangup, .break_ctl = sdio_uart_break_ctl, .tiocmget = sdio_uart_tiocmget, .tiocmset = sdio_uart_tiocmset, - .read_proc = sdio_uart_read_proc, + .install = sdio_uart_install, + .cleanup = sdio_uart_cleanup, + .proc_fops = &sdio_uart_proc_fops, }; static struct tty_driver *sdio_uart_tty_driver; @@ -1020,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; @@ -1039,23 +1082,23 @@ static int sdio_uart_probe(struct sdio_func *func, break; } if (!tpl) { - printk(KERN_WARNING - "%s: can't find tuple 0x91 subtuple 0 (SUBTPL_SIOREG) for GPS class\n", + 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 { @@ -1065,13 +1108,16 @@ static int sdio_uart_probe(struct sdio_func *func, port->func = func; sdio_set_drvdata(func, port); + tty_port_init(&port->port); + port->port.ops = &sdio_uart_port_ops; ret = sdio_uart_add_port(port); if (ret) { 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); @@ -1113,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 */ |
