From 30004ac9c090dcdcca99556b4587b3bad828731a Mon Sep 17 00:00:00 2001 From: Dmitry Eremin-Solenikov Date: Mon, 9 Aug 2010 18:22:49 +0400 Subject: tty: add tty_struct->dev pointer to corresponding device instance Some device drivers (mostly tty line disciplines) would like to have way know a struct device instance corresponding to passed tty_struct. Add a struct device pointer to struct tty_struct and populate it during initialize_tty_struct(). Signed-off-by: Dmitry Eremin-Solenikov Acked-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- include/linux/tty.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include') diff --git a/include/linux/tty.h b/include/linux/tty.h index 67d64e6efe7a..d94eb86266c4 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -256,6 +256,7 @@ struct tty_operations; struct tty_struct { int magic; struct kref kref; + struct device *dev; struct tty_driver *driver; const struct tty_operations *ops; int index; -- cgit v1.2.3-70-g09d2 From f573bd1764f0f3f47754ca1ae7b2eb2909798a60 Mon Sep 17 00:00:00 2001 From: Pekka Enberg Date: Tue, 24 Aug 2010 07:48:34 +0300 Subject: tty: Remove __GFP_NOFAIL from tty_add_file() This patch removes __GFP_NOFAIL use from tty_add_file() and adds proper error handling to the call-sites of the function. Cc: Andrew Morton Cc: Alan Cox Cc: Arnd Bergmann Signed-off-by: Pekka Enberg Acked-by: David Rientjes Signed-off-by: Greg Kroah-Hartman --- drivers/char/pty.c | 4 +++- drivers/char/tty_io.c | 15 +++++++++++---- include/linux/tty.h | 2 +- 3 files changed, 15 insertions(+), 6 deletions(-) (limited to 'include') diff --git a/drivers/char/pty.c b/drivers/char/pty.c index c350d01716bd..923a48585501 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -676,7 +676,9 @@ static int ptmx_open(struct inode *inode, struct file *filp) set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ - tty_add_file(tty, filp); + retval = tty_add_file(tty, filp); + if (retval) + goto out; retval = devpts_pty_new(inode, tty->link); if (retval) diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index dc184d4b5638..d6c659f2f659 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -196,12 +196,13 @@ static inline struct tty_struct *file_tty(struct file *file) } /* Associate a new file with the tty structure */ -void tty_add_file(struct tty_struct *tty, struct file *file) +int tty_add_file(struct tty_struct *tty, struct file *file) { struct tty_file_private *priv; - /* XXX: must implement proper error handling in callers */ - priv = kmalloc(sizeof(*priv), GFP_KERNEL|__GFP_NOFAIL); + priv = kmalloc(sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; priv->tty = tty; priv->file = file; @@ -210,6 +211,8 @@ void tty_add_file(struct tty_struct *tty, struct file *file) spin_lock(&tty_files_lock); list_add(&priv->list, &tty->tty_files); spin_unlock(&tty_files_lock); + + return 0; } /* Delete file from its tty */ @@ -1877,7 +1880,11 @@ got_driver: return PTR_ERR(tty); } - tty_add_file(tty, filp); + retval = tty_add_file(tty, filp); + if (retval) { + tty_unlock(); + return retval; + } check_tty_count(tty, "tty_open"); if (tty->driver->type == TTY_DRIVER_TYPE_PTY && diff --git a/include/linux/tty.h b/include/linux/tty.h index d94eb86266c4..86be0cdeb11b 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h @@ -466,7 +466,7 @@ extern void proc_clear_tty(struct task_struct *p); extern struct tty_struct *get_current_tty(void); extern void tty_default_fops(struct file_operations *fops); extern struct tty_struct *alloc_tty_struct(void); -extern void tty_add_file(struct tty_struct *tty, struct file *file); +extern int tty_add_file(struct tty_struct *tty, struct file *file); extern void free_tty_struct(struct tty_struct *tty); extern void initialize_tty_struct(struct tty_struct *tty, struct tty_driver *driver, int idx); -- cgit v1.2.3-70-g09d2 From 8bc3372d9e57db3c65cf00cea6cf14969875b055 Mon Sep 17 00:00:00 2001 From: Jeff Mahoney Date: Fri, 20 Aug 2010 17:14:04 -0400 Subject: ioctl: Use asm-generic/ioctls.h on cris (enables termiox) This patch converts cris to use asm-generic/ioctls.h instead of its own version. The differences between the arch-specific version and the generic version are as follows: - CRIS defines two ioctls: TIOCSERSETRS485 and TIOCSERWRRS485, kept in arch-specific portion - CRIS defines a different value for TIOCSRS485, kept via ifndef in generic - The generic version adds support for termiox Cc: Mikael Starvik Cc: Jesper Nilsson Signed-off-by: Jeff Mahoney Signed-off-by: Greg Kroah-Hartman --- arch/cris/include/asm/ioctls.h | 84 +----------------------------------------- include/asm-generic/ioctls.h | 2 + 2 files changed, 3 insertions(+), 83 deletions(-) (limited to 'include') diff --git a/arch/cris/include/asm/ioctls.h b/arch/cris/include/asm/ioctls.h index c9129ed37443..488fbb3f5e84 100644 --- a/arch/cris/include/asm/ioctls.h +++ b/arch/cris/include/asm/ioctls.h @@ -1,93 +1,11 @@ #ifndef __ARCH_CRIS_IOCTLS_H__ #define __ARCH_CRIS_IOCTLS_H__ -/* verbatim copy of asm-i386/ioctls.h */ - -#include - -/* 0x54 is just a magic number to make these relatively unique ('T') */ - -#define TCGETS 0x5401 -#define TCSETS 0x5402 -#define TCSETSW 0x5403 -#define TCSETSF 0x5404 -#define TCGETA 0x5405 -#define TCSETA 0x5406 -#define TCSETAW 0x5407 -#define TCSETAF 0x5408 -#define TCSBRK 0x5409 -#define TCXONC 0x540A -#define TCFLSH 0x540B -#define TIOCEXCL 0x540C -#define TIOCNXCL 0x540D -#define TIOCSCTTY 0x540E -#define TIOCGPGRP 0x540F -#define TIOCSPGRP 0x5410 -#define TIOCOUTQ 0x5411 -#define TIOCSTI 0x5412 -#define TIOCGWINSZ 0x5413 -#define TIOCSWINSZ 0x5414 -#define TIOCMGET 0x5415 -#define TIOCMBIS 0x5416 -#define TIOCMBIC 0x5417 -#define TIOCMSET 0x5418 -#define TIOCGSOFTCAR 0x5419 -#define TIOCSSOFTCAR 0x541A -#define FIONREAD 0x541B -#define TIOCINQ FIONREAD -#define TIOCLINUX 0x541C -#define TIOCCONS 0x541D -#define TIOCGSERIAL 0x541E -#define TIOCSSERIAL 0x541F -#define TIOCPKT 0x5420 -#define FIONBIO 0x5421 -#define TIOCNOTTY 0x5422 -#define TIOCSETD 0x5423 -#define TIOCGETD 0x5424 -#define TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ -#define TIOCSBRK 0x5427 /* BSD compatibility */ -#define TIOCCBRK 0x5428 /* BSD compatibility */ -#define TIOCGSID 0x5429 /* Return the session ID of FD */ -#define TCGETS2 _IOR('T',0x2A, struct termios2) -#define TCSETS2 _IOW('T',0x2B, struct termios2) -#define TCSETSW2 _IOW('T',0x2C, struct termios2) -#define TCSETSF2 _IOW('T',0x2D, struct termios2) -#define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ -#define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ -#define TIOCSIG _IOW('T',0x36, int) /* Generate signal on Pty slave */ - -#define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ -#define FIOCLEX 0x5451 -#define FIOASYNC 0x5452 -#define TIOCSERCONFIG 0x5453 -#define TIOCSERGWILD 0x5454 -#define TIOCSERSWILD 0x5455 -#define TIOCGLCKTRMIOS 0x5456 -#define TIOCSLCKTRMIOS 0x5457 #define TIOCSERGSTRUCT 0x5458 /* For debugging only */ -#define TIOCSERGETLSR 0x5459 /* Get line status register */ -#define TIOCSERGETMULTI 0x545A /* Get multiport config */ -#define TIOCSERSETMULTI 0x545B /* Set multiport config */ - -#define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ -#define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ -#define FIOQSIZE 0x5460 - #define TIOCSERSETRS485 0x5461 /* enable rs-485 (deprecated) */ #define TIOCSERWRRS485 0x5462 /* write rs-485 */ #define TIOCSRS485 0x5463 /* enable rs-485 */ -#define TIOCGRS485 0x542E /* get rs-485 */ - -/* Used for packet mode */ -#define TIOCPKT_DATA 0 -#define TIOCPKT_FLUSHREAD 1 -#define TIOCPKT_FLUSHWRITE 2 -#define TIOCPKT_STOP 4 -#define TIOCPKT_START 8 -#define TIOCPKT_NOSTOP 16 -#define TIOCPKT_DOSTOP 32 -#define TIOCPKT_IOCTL 64 -#define TIOCSER_TEMT 0x01 /* Transmitter physically empty */ +#include #endif diff --git a/include/asm-generic/ioctls.h b/include/asm-generic/ioctls.h index 8554cb6a81b9..a3216655d657 100644 --- a/include/asm-generic/ioctls.h +++ b/include/asm-generic/ioctls.h @@ -62,7 +62,9 @@ #define TCSETSW2 _IOW('T', 0x2C, struct termios2) #define TCSETSF2 _IOW('T', 0x2D, struct termios2) #define TIOCGRS485 0x542E +#ifndef TIOCSRS485 #define TIOCSRS485 0x542F +#endif #define TIOCGPTN _IOR('T', 0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T', 0x31, int) /* Lock/unlock Pty */ #define TCGETX 0x5432 /* SYS5 TCGETX compatibility */ -- cgit v1.2.3-70-g09d2 From d281da7ff6f70efca0553c288bb883e8605b3862 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Thu, 16 Sep 2010 18:21:24 +0100 Subject: tty: Make tiocgicount a handler Dan Rosenberg noted that various drivers return the struct with uncleared fields. Instead of spending forever trying to stomp all the drivers that get it wrong (and every new driver) do the job in one place. This first patch adds the needed operations and hooks them up, including the needed USB midlayer and serial core plumbing. Signed-off-by: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/char/tty_io.c | 21 +++++++++++++++++++++ drivers/serial/serial_core.c | 35 ++++++++++++++++------------------- drivers/usb/serial/usb-serial.c | 13 +++++++++++++ include/linux/tty_driver.h | 9 +++++++++ include/linux/usb/serial.h | 2 ++ 5 files changed, 61 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index e185db36f8ad..c05c5af5aa04 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -96,6 +96,7 @@ #include #include #include +#include #include #include @@ -2511,6 +2512,20 @@ static int tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int return tty->ops->tiocmset(tty, file, set, clear); } +static int tty_tiocgicount(struct tty_struct *tty, void __user *arg) +{ + int retval = -EINVAL; + struct serial_icounter_struct icount; + memset(&icount, 0, sizeof(icount)); + if (tty->ops->get_icount) + retval = tty->ops->get_icount(tty, &icount); + if (retval != 0) + return retval; + if (copy_to_user(arg, &icount, sizeof(icount))) + return -EFAULT; + return 0; +} + struct tty_struct *tty_pair_get_tty(struct tty_struct *tty) { if (tty->driver->type == TTY_DRIVER_TYPE_PTY && @@ -2631,6 +2646,12 @@ long tty_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case TIOCMBIC: case TIOCMBIS: return tty_tiocmset(tty, file, cmd, p); + case TIOCGICOUNT: + retval = tty_tiocgicount(tty, p); + /* For the moment allow fall through to the old method */ + if (retval != -EINVAL) + return retval; + break; case TCFLSH: switch (arg) { case TCIFLUSH: diff --git a/drivers/serial/serial_core.c b/drivers/serial/serial_core.c index bc6cddd10294..c4ea14670d44 100644 --- a/drivers/serial/serial_core.c +++ b/drivers/serial/serial_core.c @@ -1074,10 +1074,10 @@ uart_wait_modem_status(struct uart_state *state, unsigned long arg) * NB: both 1->0 and 0->1 transitions are counted except for * RI where only 0->1 is counted. */ -static int uart_get_count(struct uart_state *state, - struct serial_icounter_struct __user *icnt) +static int uart_get_icount(struct tty_struct *tty, + struct serial_icounter_struct *icount) { - struct serial_icounter_struct icount; + struct uart_state *state = tty->driver_data; struct uart_icount cnow; struct uart_port *uport = state->uart_port; @@ -1085,19 +1085,19 @@ static int uart_get_count(struct uart_state *state, memcpy(&cnow, &uport->icount, sizeof(struct uart_icount)); spin_unlock_irq(&uport->lock); - icount.cts = cnow.cts; - icount.dsr = cnow.dsr; - icount.rng = cnow.rng; - icount.dcd = cnow.dcd; - icount.rx = cnow.rx; - icount.tx = cnow.tx; - icount.frame = cnow.frame; - icount.overrun = cnow.overrun; - icount.parity = cnow.parity; - icount.brk = cnow.brk; - icount.buf_overrun = cnow.buf_overrun; + icount->cts = cnow.cts; + icount->dsr = cnow.dsr; + icount->rng = cnow.rng; + icount->dcd = cnow.dcd; + icount->rx = cnow.rx; + icount->tx = cnow.tx; + icount->frame = cnow.frame; + icount->overrun = cnow.overrun; + icount->parity = cnow.parity; + icount->brk = cnow.brk; + icount->buf_overrun = cnow.buf_overrun; - return copy_to_user(icnt, &icount, sizeof(icount)) ? -EFAULT : 0; + return 0; } /* @@ -1150,10 +1150,6 @@ uart_ioctl(struct tty_struct *tty, struct file *filp, unsigned int cmd, case TIOCMIWAIT: ret = uart_wait_modem_status(state, arg); break; - - case TIOCGICOUNT: - ret = uart_get_count(state, uarg); - break; } if (ret != -ENOIOCTLCMD) @@ -2295,6 +2291,7 @@ static const struct tty_operations uart_ops = { #endif .tiocmget = uart_tiocmget, .tiocmset = uart_tiocmset, + .get_icount = uart_get_icount, #ifdef CONFIG_CONSOLE_POLL .poll_init = uart_poll_init, .poll_get_char = uart_poll_get_char, diff --git a/drivers/usb/serial/usb-serial.c b/drivers/usb/serial/usb-serial.c index 7a2177c79bde..e64da74bdcc5 100644 --- a/drivers/usb/serial/usb-serial.c +++ b/drivers/usb/serial/usb-serial.c @@ -519,6 +519,18 @@ static int serial_tiocmset(struct tty_struct *tty, struct file *file, return -EINVAL; } +static int serial_get_icount(struct tty_struct *tty, + struct serial_icounter_struct *icount) +{ + struct usb_serial_port *port = tty->driver_data; + + dbg("%s - port %d", __func__, port->number); + + if (port->serial->type->get_icount) + return port->serial->type->get_icount(tty, icount); + return -EINVAL; +} + /* * We would be calling tty_wakeup here, but unfortunately some line * disciplines have an annoying habit of calling tty->write from @@ -1195,6 +1207,7 @@ static const struct tty_operations serial_ops = { .chars_in_buffer = serial_chars_in_buffer, .tiocmget = serial_tiocmget, .tiocmset = serial_tiocmset, + .get_icount = serial_get_icount, .cleanup = serial_cleanup, .install = serial_install, .proc_fops = &serial_proc_fops, diff --git a/include/linux/tty_driver.h b/include/linux/tty_driver.h index b08677982525..db2d227694da 100644 --- a/include/linux/tty_driver.h +++ b/include/linux/tty_driver.h @@ -224,6 +224,12 @@ * unless the tty also has a valid tty->termiox pointer. * * Optional: Called under the termios lock + * + * int (*get_icount)(struct tty_struct *tty, struct serial_icounter *icount); + * + * Called when the device receives a TIOCGICOUNT ioctl. Passed a kernel + * structure to complete. This method is optional and will only be called + * if provided (otherwise EINVAL will be returned). */ #include @@ -232,6 +238,7 @@ struct tty_struct; struct tty_driver; +struct serial_icounter_struct; struct tty_operations { struct tty_struct * (*lookup)(struct tty_driver *driver, @@ -268,6 +275,8 @@ struct tty_operations { unsigned int set, unsigned int clear); int (*resize)(struct tty_struct *tty, struct winsize *ws); int (*set_termiox)(struct tty_struct *tty, struct termiox *tnew); + int (*get_icount)(struct tty_struct *tty, + struct serial_icounter_struct *icount); #ifdef CONFIG_CONSOLE_POLL int (*poll_init)(struct tty_driver *driver, int line, char *options); int (*poll_get_char)(struct tty_driver *driver, int line); diff --git a/include/linux/usb/serial.h b/include/linux/usb/serial.h index 55675b1efb28..16d682f4f7c3 100644 --- a/include/linux/usb/serial.h +++ b/include/linux/usb/serial.h @@ -271,6 +271,8 @@ struct usb_serial_driver { int (*tiocmget)(struct tty_struct *tty, struct file *file); int (*tiocmset)(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear); + int (*get_icount)(struct tty_struct *tty, + struct serial_icounter_struct *icount); /* Called by the tty layer for port level work. There may or may not be an attached tty at this point */ void (*dtr_rts)(struct usb_serial_port *port, int on); -- cgit v1.2.3-70-g09d2 From 432c9ed22aff641039ccd400cdabf983fabc285e Mon Sep 17 00:00:00 2001 From: Nicolas Pitre Date: Fri, 1 Oct 2010 00:10:44 -0400 Subject: vcs: invoke the vt update callback when /dev/vcs* is written to A notifier chain is called whenever the vt code modifies a terminal content, except for one case which is when the modification comes through writes to /dev/vcs* devices. Let's add the missing notifier invocation at the end of vcs_write() for that case too. Signed-off-by: Nicolas Pitre Cc: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/char/vc_screen.c | 2 ++ drivers/char/vt.c | 5 +++++ include/linux/selection.h | 1 + 3 files changed, 8 insertions(+) (limited to 'include') diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c index 6f7054e1a516..273ab44cc91d 100644 --- a/drivers/char/vc_screen.c +++ b/drivers/char/vc_screen.c @@ -538,6 +538,8 @@ vcs_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) } *ppos += written; ret = written; + if (written) + vcs_scr_updated(vc); unlock_out: release_console_sem(); diff --git a/drivers/char/vt.c b/drivers/char/vt.c index 281aada7b4a1..a8ec48ed14d9 100644 --- a/drivers/char/vt.c +++ b/drivers/char/vt.c @@ -4182,6 +4182,11 @@ void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org) } } +void vcs_scr_updated(struct vc_data *vc) +{ + notify_update(vc); +} + /* * Visible symbols for modules */ diff --git a/include/linux/selection.h b/include/linux/selection.h index 8cdaa1151d2e..85193aa8c1e3 100644 --- a/include/linux/selection.h +++ b/include/linux/selection.h @@ -39,5 +39,6 @@ extern void putconsxy(struct vc_data *vc, unsigned char *p); extern u16 vcs_scr_readw(struct vc_data *vc, const u16 *org); extern void vcs_scr_writew(struct vc_data *vc, u16 val, u16 *org); +extern void vcs_scr_updated(struct vc_data *vc); #endif -- cgit v1.2.3-70-g09d2 From 54381067ed7873e6173d6fe32818a585ad667723 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Fri, 1 Oct 2010 17:21:25 +0400 Subject: serial: Factor out uart_poll_timeout() from 8250 driver Soon we will use that handy function in the altera_uart driver. Signed-off-by: Anton Vorontsov Cc: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/serial/8250.c | 14 ++++---------- include/linux/serial_core.h | 8 ++++++++ 2 files changed, 12 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 31b8cca179cd..b586406f04ca 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -1722,12 +1722,6 @@ static void serial_unlink_irq_chain(struct uart_8250_port *up) mutex_unlock(&hash_mutex); } -/* Base timer interval for polling */ -static inline int poll_timeout(int timeout) -{ - return timeout > 6 ? (timeout / 2 - 2) : 1; -} - /* * This function is used to handle ports that do not have an * interrupt. This doesn't work very well for 16450's, but gives @@ -1742,7 +1736,7 @@ static void serial8250_timeout(unsigned long data) iir = serial_in(up, UART_IIR); if (!(iir & UART_IIR_NO_INT)) serial8250_handle_port(up); - mod_timer(&up->timer, jiffies + poll_timeout(up->port.timeout)); + mod_timer(&up->timer, jiffies + uart_poll_timeout(&up->port)); } static void serial8250_backup_timeout(unsigned long data) @@ -1787,7 +1781,7 @@ static void serial8250_backup_timeout(unsigned long data) /* Standard timer interval plus 0.2s to keep the port running */ mod_timer(&up->timer, - jiffies + poll_timeout(up->port.timeout) + HZ / 5); + jiffies + uart_poll_timeout(&up->port) + HZ / 5); } static unsigned int serial8250_tx_empty(struct uart_port *port) @@ -2071,7 +2065,7 @@ static int serial8250_startup(struct uart_port *port) up->timer.function = serial8250_backup_timeout; up->timer.data = (unsigned long)up; mod_timer(&up->timer, jiffies + - poll_timeout(up->port.timeout) + HZ / 5); + uart_poll_timeout(port) + HZ / 5); } /* @@ -2081,7 +2075,7 @@ static int serial8250_startup(struct uart_port *port) */ if (!is_real_interrupt(up->port.irq)) { up->timer.data = (unsigned long)up; - mod_timer(&up->timer, jiffies + poll_timeout(up->port.timeout)); + mod_timer(&up->timer, jiffies + uart_poll_timeout(port)); } else { retval = serial_link_irq_chain(up); if (retval) diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index 563e23400913..ac48082f3559 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -411,6 +411,14 @@ unsigned int uart_get_baud_rate(struct uart_port *port, struct ktermios *termios unsigned int max); unsigned int uart_get_divisor(struct uart_port *port, unsigned int baud); +/* Base timer interval for polling */ +static inline int uart_poll_timeout(struct uart_port *port) +{ + int timeout = port->timeout; + + return timeout > 6 ? (timeout / 2 - 2) : 1; +} + /* * Console helpers. */ -- cgit v1.2.3-70-g09d2 From 0d426eda7c94d864ead913f7099c623521368443 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Fri, 1 Oct 2010 17:21:54 +0400 Subject: altera_uart: Add support for different address strides Some controllers implement registers with a stride, to support those we must implement the proper IO accessors. Signed-off-by: Anton Vorontsov Acked-by: Tobias Klauser Cc: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/serial/altera_uart.c | 58 ++++++++++++++++++++++++++++---------------- include/linux/altera_uart.h | 1 + 2 files changed, 38 insertions(+), 21 deletions(-) (limited to 'include') diff --git a/drivers/serial/altera_uart.c b/drivers/serial/altera_uart.c index 1dfeffae5231..f1985aaf2cbc 100644 --- a/drivers/serial/altera_uart.c +++ b/drivers/serial/altera_uart.c @@ -82,9 +82,23 @@ struct altera_uart { unsigned short imr; /* Local IMR mirror */ }; +static u32 altera_uart_readl(struct uart_port *port, int reg) +{ + struct altera_uart_platform_uart *platp = port->private_data; + + return readl(port->membase + (reg << platp->bus_shift)); +} + +static void altera_uart_writel(struct uart_port *port, u32 dat, int reg) +{ + struct altera_uart_platform_uart *platp = port->private_data; + + writel(dat, port->membase + (reg << platp->bus_shift)); +} + static unsigned int altera_uart_tx_empty(struct uart_port *port) { - return (readl(port->membase + ALTERA_UART_STATUS_REG) & + return (altera_uart_readl(port, ALTERA_UART_STATUS_REG) & ALTERA_UART_STATUS_TMT_MSK) ? TIOCSER_TEMT : 0; } @@ -93,8 +107,7 @@ static unsigned int altera_uart_get_mctrl(struct uart_port *port) struct altera_uart *pp = container_of(port, struct altera_uart, port); unsigned int sigs; - sigs = - (readl(port->membase + ALTERA_UART_STATUS_REG) & + sigs = (altera_uart_readl(port, ALTERA_UART_STATUS_REG) & ALTERA_UART_STATUS_CTS_MSK) ? TIOCM_CTS : 0; sigs |= (pp->sigs & TIOCM_RTS); @@ -110,7 +123,7 @@ static void altera_uart_set_mctrl(struct uart_port *port, unsigned int sigs) pp->imr |= ALTERA_UART_CONTROL_RTS_MSK; else pp->imr &= ~ALTERA_UART_CONTROL_RTS_MSK; - writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); + altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); } static void altera_uart_start_tx(struct uart_port *port) @@ -118,7 +131,7 @@ static void altera_uart_start_tx(struct uart_port *port) struct altera_uart *pp = container_of(port, struct altera_uart, port); pp->imr |= ALTERA_UART_CONTROL_TRDY_MSK; - writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); + altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); } static void altera_uart_stop_tx(struct uart_port *port) @@ -126,7 +139,7 @@ static void altera_uart_stop_tx(struct uart_port *port) struct altera_uart *pp = container_of(port, struct altera_uart, port); pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK; - writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); + altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); } static void altera_uart_stop_rx(struct uart_port *port) @@ -134,7 +147,7 @@ static void altera_uart_stop_rx(struct uart_port *port) struct altera_uart *pp = container_of(port, struct altera_uart, port); pp->imr &= ~ALTERA_UART_CONTROL_RRDY_MSK; - writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); + altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); } static void altera_uart_break_ctl(struct uart_port *port, int break_state) @@ -147,7 +160,7 @@ static void altera_uart_break_ctl(struct uart_port *port, int break_state) pp->imr |= ALTERA_UART_CONTROL_TRBK_MSK; else pp->imr &= ~ALTERA_UART_CONTROL_TRBK_MSK; - writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); + altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); spin_unlock_irqrestore(&port->lock, flags); } @@ -171,7 +184,7 @@ static void altera_uart_set_termios(struct uart_port *port, spin_lock_irqsave(&port->lock, flags); uart_update_timeout(port, termios->c_cflag, baud); - writel(baudclk, port->membase + ALTERA_UART_DIVISOR_REG); + altera_uart_writel(port, baudclk, ALTERA_UART_DIVISOR_REG); spin_unlock_irqrestore(&port->lock, flags); } @@ -181,14 +194,15 @@ static void altera_uart_rx_chars(struct altera_uart *pp) unsigned char ch, flag; unsigned short status; - while ((status = readl(port->membase + ALTERA_UART_STATUS_REG)) & + while ((status = altera_uart_readl(port, ALTERA_UART_STATUS_REG)) & ALTERA_UART_STATUS_RRDY_MSK) { - ch = readl(port->membase + ALTERA_UART_RXDATA_REG); + ch = altera_uart_readl(port, ALTERA_UART_RXDATA_REG); flag = TTY_NORMAL; port->icount.rx++; if (status & ALTERA_UART_STATUS_E_MSK) { - writel(status, port->membase + ALTERA_UART_STATUS_REG); + altera_uart_writel(port, status, + ALTERA_UART_STATUS_REG); if (status & ALTERA_UART_STATUS_BRK_MSK) { port->icount.brk++; @@ -228,18 +242,18 @@ static void altera_uart_tx_chars(struct altera_uart *pp) if (port->x_char) { /* Send special char - probably flow control */ - writel(port->x_char, port->membase + ALTERA_UART_TXDATA_REG); + altera_uart_writel(port, port->x_char, ALTERA_UART_TXDATA_REG); port->x_char = 0; port->icount.tx++; return; } - while (readl(port->membase + ALTERA_UART_STATUS_REG) & + while (altera_uart_readl(port, ALTERA_UART_STATUS_REG) & ALTERA_UART_STATUS_TRDY_MSK) { if (xmit->head == xmit->tail) break; - writel(xmit->buf[xmit->tail], - port->membase + ALTERA_UART_TXDATA_REG); + altera_uart_writel(port, xmit->buf[xmit->tail], + ALTERA_UART_TXDATA_REG); xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; } @@ -249,7 +263,7 @@ static void altera_uart_tx_chars(struct altera_uart *pp) if (xmit->head == xmit->tail) { pp->imr &= ~ALTERA_UART_CONTROL_TRDY_MSK; - writel(pp->imr, port->membase + ALTERA_UART_CONTROL_REG); + altera_uart_writel(port, pp->imr, ALTERA_UART_CONTROL_REG); } } @@ -259,7 +273,7 @@ static irqreturn_t altera_uart_interrupt(int irq, void *data) struct altera_uart *pp = container_of(port, struct altera_uart, port); unsigned int isr; - isr = readl(port->membase + ALTERA_UART_STATUS_REG) & pp->imr; + isr = altera_uart_readl(port, ALTERA_UART_STATUS_REG) & pp->imr; spin_lock(&port->lock); if (isr & ALTERA_UART_STATUS_RRDY_MSK) @@ -285,9 +299,9 @@ static void altera_uart_config_port(struct uart_port *port, int flags) port->type = PORT_ALTERA_UART; /* Clear mask, so no surprise interrupts. */ - writel(0, port->membase + ALTERA_UART_CONTROL_REG); + altera_uart_writel(port, 0, ALTERA_UART_CONTROL_REG); /* Clear status register */ - writel(0, port->membase + ALTERA_UART_STATUS_REG); + altera_uart_writel(port, 0, ALTERA_UART_STATUS_REG); } static int altera_uart_startup(struct uart_port *port) @@ -407,6 +421,7 @@ int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp) port->uartclk = platp[i].uartclk; port->flags = ASYNC_BOOT_AUTOCONF; port->ops = &altera_uart_ops; + port->private_data = platp; } return 0; @@ -414,7 +429,7 @@ int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp) static void altera_uart_console_putc(struct uart_port *port, const char c) { - while (!(readl(port->membase + ALTERA_UART_STATUS_REG) & + while (!(altera_uart_readl(port, ALTERA_UART_STATUS_REG) & ALTERA_UART_STATUS_TRDY_MSK)) cpu_relax(); @@ -535,6 +550,7 @@ static int __devinit altera_uart_probe(struct platform_device *pdev) port->uartclk = platp->uartclk; port->ops = &altera_uart_ops; port->flags = ASYNC_BOOT_AUTOCONF; + port->private_data = platp; uart_add_one_port(&altera_uart_driver, port); diff --git a/include/linux/altera_uart.h b/include/linux/altera_uart.h index 8d441064a30d..c022c82db7ca 100644 --- a/include/linux/altera_uart.h +++ b/include/linux/altera_uart.h @@ -9,6 +9,7 @@ struct altera_uart_platform_uart { unsigned long mapbase; /* Physical address base */ unsigned int irq; /* Interrupt vector */ unsigned int uartclk; /* UART clock rate */ + unsigned int bus_shift; /* Bus shift (address stride) */ }; #endif /* __ALTUART_H */ -- cgit v1.2.3-70-g09d2 From 5d89a48acfbaae02e7ecf97d4d8cc570a31964c5 Mon Sep 17 00:00:00 2001 From: Anton Vorontsov Date: Fri, 1 Oct 2010 17:22:55 +0400 Subject: altera_uart: Fix missing prototype for registering an early console Simply add an early_altera_uart_setup() prototype declaration, otherwise platform code have to do it in .c files, which is ugly. Signed-off-by: Anton Vorontsov Acked-by: Tobias Klauser Cc: Alan Cox Signed-off-by: Greg Kroah-Hartman --- include/linux/altera_uart.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include') diff --git a/include/linux/altera_uart.h b/include/linux/altera_uart.h index c022c82db7ca..a10a90791976 100644 --- a/include/linux/altera_uart.h +++ b/include/linux/altera_uart.h @@ -5,6 +5,8 @@ #ifndef __ALTUART_H #define __ALTUART_H +#include + struct altera_uart_platform_uart { unsigned long mapbase; /* Physical address base */ unsigned int irq; /* Interrupt vector */ @@ -12,4 +14,6 @@ struct altera_uart_platform_uart { unsigned int bus_shift; /* Bus shift (address stride) */ }; +int __init early_altera_uart_setup(struct altera_uart_platform_uart *platp); + #endif /* __ALTUART_H */ -- cgit v1.2.3-70-g09d2 From c161afe9759ddcc174d08e7c4f683d08ac9ba86f Mon Sep 17 00:00:00 2001 From: Manuel Lauss Date: Sat, 25 Sep 2010 15:13:45 +0200 Subject: 8250: allow platforms to override PM hook. Add a hook for platforms to specify custom pm methods. Signed-off-by: Manuel Lauss Cc: Alan Cox Signed-off-by: Greg Kroah-Hartman --- drivers/serial/8250.c | 27 ++++++++++++++++----------- include/linux/serial_8250.h | 4 ++++ include/linux/serial_core.h | 2 ++ 3 files changed, 22 insertions(+), 11 deletions(-) (limited to 'include') diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index b586406f04ca..6994afb5571a 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -154,12 +154,6 @@ struct uart_8250_port { unsigned char lsr_saved_flags; #define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA unsigned char msr_saved_flags; - - /* - * We provide a per-port pm hook. - */ - void (*pm)(struct uart_port *port, - unsigned int state, unsigned int old); }; struct irq_info { @@ -2436,16 +2430,24 @@ serial8250_set_ldisc(struct uart_port *port, int new) port->flags &= ~UPF_HARDPPS_CD; } -static void -serial8250_pm(struct uart_port *port, unsigned int state, - unsigned int oldstate) + +void serial8250_do_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) { struct uart_8250_port *p = (struct uart_8250_port *)port; serial8250_set_sleep(p, state != 0); +} +EXPORT_SYMBOL(serial8250_do_pm); - if (p->pm) - p->pm(port, state, oldstate); +static void +serial8250_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate) +{ + if (port->pm) + port->pm(port, state, oldstate); + else + serial8250_do_pm(port, state, oldstate); } static unsigned int serial8250_port_size(struct uart_8250_port *pt) @@ -3006,6 +3008,7 @@ static int __devinit serial8250_probe(struct platform_device *dev) port.serial_in = p->serial_in; port.serial_out = p->serial_out; port.set_termios = p->set_termios; + port.pm = p->pm; port.dev = &dev->dev; port.irqflags |= irqflag; ret = serial8250_register_port(&port); @@ -3172,6 +3175,8 @@ int serial8250_register_port(struct uart_port *port) /* Possibly override set_termios call */ if (port->set_termios) uart->port.set_termios = port->set_termios; + if (port->pm) + uart->port.pm = port->pm; ret = uart_add_one_port(&serial8250_reg, &uart->port); if (ret == 0) diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index 7638deaaba65..bf9c2bdb2e05 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -35,6 +35,8 @@ struct plat_serial8250_port { void (*set_termios)(struct uart_port *, struct ktermios *new, struct ktermios *old); + void (*pm)(struct uart_port *, unsigned int state, + unsigned old); }; /* @@ -76,5 +78,7 @@ extern int serial8250_find_port_for_earlycon(void); extern int setup_early_serial8250_console(char *cmdline); extern void serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old); +extern void serial8250_do_pm(struct uart_port *port, unsigned int state, + unsigned int oldstate); #endif diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h index ac48082f3559..99e5994e6f84 100644 --- a/include/linux/serial_core.h +++ b/include/linux/serial_core.h @@ -289,6 +289,8 @@ struct uart_port { void (*set_termios)(struct uart_port *, struct ktermios *new, struct ktermios *old); + void (*pm)(struct uart_port *, unsigned int state, + unsigned int old); unsigned int irq; /* irq number */ unsigned long irqflags; /* irq flags */ unsigned int uartclk; /* base uart clock */ -- cgit v1.2.3-70-g09d2 From af7f3743567e3d5b40e2f9c21541b7f40b99c103 Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Mon, 18 Oct 2010 11:38:02 -0700 Subject: serial: abstraction for 8250 legacy ports Not every platform that has generic legacy 8250 ports manages to have them clocked the right way or without errata. Provide a generic interface to allow platforms to override the default behaviour in a manner that dumps the complexity in *their* code not the 8250 driver. Signed-off-by: Alan Cox Signed-off-by: Dirk Brandewie Acked-by: Thomas Gleixner Signed-off-by: Greg Kroah-Hartman --- drivers/serial/8250.c | 17 +++++++++++++++++ include/linux/serial_8250.h | 4 ++++ 2 files changed, 21 insertions(+) (limited to 'include') diff --git a/drivers/serial/8250.c b/drivers/serial/8250.c index 6994afb5571a..37f19a678c97 100644 --- a/drivers/serial/8250.c +++ b/drivers/serial/8250.c @@ -2672,6 +2672,16 @@ static struct uart_ops serial8250_pops = { static struct uart_8250_port serial8250_ports[UART_NR]; +static void (*serial8250_isa_config)(int port, struct uart_port *up, + unsigned short *capabilities); + +void serial8250_set_isa_configurator( + void (*v)(int port, struct uart_port *up, unsigned short *capabilities)) +{ + serial8250_isa_config = v; +} +EXPORT_SYMBOL(serial8250_set_isa_configurator); + static void __init serial8250_isa_init_ports(void) { struct uart_8250_port *up; @@ -2717,6 +2727,9 @@ static void __init serial8250_isa_init_ports(void) up->port.regshift = old_serial_port[i].iomem_reg_shift; set_io_from_upio(&up->port); up->port.irqflags |= irqflag; + if (serial8250_isa_config != NULL) + serial8250_isa_config(i, &up->port, &up->capabilities); + } } @@ -3178,6 +3191,10 @@ int serial8250_register_port(struct uart_port *port) if (port->pm) uart->port.pm = port->pm; + if (serial8250_isa_config != NULL) + serial8250_isa_config(0, &uart->port, + &uart->capabilities); + ret = uart_add_one_port(&serial8250_reg, &uart->port); if (ret == 0) ret = uart->port.line; diff --git a/include/linux/serial_8250.h b/include/linux/serial_8250.h index bf9c2bdb2e05..97f5b45bbc07 100644 --- a/include/linux/serial_8250.h +++ b/include/linux/serial_8250.h @@ -81,4 +81,8 @@ extern void serial8250_do_set_termios(struct uart_port *port, extern void serial8250_do_pm(struct uart_port *port, unsigned int state, unsigned int oldstate); +extern void serial8250_set_isa_configurator(void (*v) + (int port, struct uart_port *up, + unsigned short *capabilities)); + #endif -- cgit v1.2.3-70-g09d2