Re: [PATCH] SC26XX: New serial driver for SC2681 uarts

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sun,  2 Dec 2007 20:43:46 +0100 (CET)
Thomas Bogendoerfer <[email protected]> wrote:

> New serial driver for SC2681/SC2691 uarts. Older SNI RM400 machines are
> using these chips for onboard serial ports.
> 

Little things...

> --- /dev/null
> +++ b/drivers/serial/sc26xx.c
> @@ -0,0 +1,757 @@
> +/*
> + * SC268xx.c: Serial driver for Philiphs SC2681/SC2692 devices.
> + *
> + * Copyright (C) 2006,2007 Thomas Bogend__rfer ([email protected])
> + */
> +
> +#include <linux/module.h>
> +#include <linux/kernel.h>
> +#include <linux/errno.h>
> +#include <linux/tty.h>
> +#include <linux/tty_flip.h>
> +#include <linux/major.h>
> +#include <linux/circ_buf.h>
> +#include <linux/serial.h>
> +#include <linux/sysrq.h>
> +#include <linux/console.h>
> +#include <linux/spinlock.h>
> +#include <linux/slab.h>
> +#include <linux/delay.h>
> +#include <linux/init.h>
> +#include <linux/platform_device.h>
> +#include <linux/irq.h>
> +
> +#if defined(CONFIG_MAGIC_SYSRQ)
> +#define SUPPORT_SYSRQ
> +#endif
> +
> +#include <linux/serial_core.h>
> +
> +#define SC26XX_MAJOR         204
> +#define SC26XX_MINOR_START   205
> +#define SC26XX_NR            2
> +
> +struct uart_sc26xx_port {
> +	struct uart_port      port[2];
> +	u8     dsr_mask[2];
> +	u8     cts_mask[2];
> +	u8     dcd_mask[2];
> +	u8     ri_mask[2];
> +	u8     dtr_mask[2];
> +	u8     rts_mask[2];
> +	u8     imr;
> +};
> +
> +/* register common to both ports */
> +#define RD_ISR      0x14
> +#define RD_IPR      0x34
> +
> +#define WR_ACR      0x10
> +#define WR_IMR      0x14
> +#define WR_OPCR     0x34
> +#define WR_OPR_SET  0x38
> +#define WR_OPR_CLR  0x3C
> +
> +/* access common register */
> +#define READ_SC(p, r)        readb ((p)->membase + RD_##r)
> +#define WRITE_SC(p, r, v)    writeb ((v), (p)->membase + WR_##r)

No space before the (.  checkpatch misses this.

> +/* register per port */
> +#define RD_PORT_MRx 0x00
> +#define RD_PORT_SR  0x04
> +#define RD_PORT_RHR 0x0c
> +
> +#define WR_PORT_MRx 0x00
> +#define WR_PORT_CSR 0x04
> +#define WR_PORT_CR  0x08
> +#define WR_PORT_THR 0x0c
> +
> +/* access port register */
> +#define READ_SC_PORT(p, r)     \
> +		readb((p)->membase + (p)->line * 0x20 + RD_PORT_##r)
> +#define WRITE_SC_PORT(p, r, v) \
> +		writeb((v), (p)->membase + (p)->line * 0x20 + WR_PORT_##r)

eww, ugly.  Why not have a nice C function which is passed RD_PORT_SR,
RD_PORT_RHR, etc?

That has the (minor) advantage that it won't malfunction if someone does

	WRITE_SC_PORT(foo++, r, v);

(the macro references an arg more than once)

> +/* SR bits */
> +#define SR_BREAK    (1 << 7)
> +#define SR_FRAME    (1 << 6)
> +#define SR_PARITY   (1 << 5)
> +#define SR_OVERRUN  (1 << 4)
> +#define SR_TXRDY    (1 << 2)
> +#define SR_RXRDY    (1 << 0)
> +
> +#define CR_RES_MR   (1 << 4)
> +#define CR_RES_RX   (2 << 4)
> +#define CR_RES_TX   (3 << 4)
> +#define CR_STRT_BRK (6 << 4)
> +#define CR_STOP_BRK (7 << 4)
> +#define CR_DIS_TX   (1 << 3)
> +#define CR_ENA_TX   (1 << 2)
> +#define CR_DIS_RX   (1 << 1)
> +#define CR_ENA_RX   (1 << 0)
> +
> +/* ISR bits */
> +#define ISR_RXRDYB  (1 << 5)
> +#define ISR_TXRDYB  (1 << 4)
> +#define ISR_RXRDYA  (1 << 1)
> +#define ISR_TXRDYA  (1 << 0)
> +
> +/* IMR bits */
> +#define IMR_RXRDY   (1 << 1)
> +#define IMR_TXRDY   (1 << 0)
> +
> +static void sc26xx_enable_irq(struct uart_port *port, int mask)
> +{
> +	struct uart_sc26xx_port *up;
> +	int line = port->line;
> +
> +	port -= line;
> +	up = (struct uart_sc26xx_port *)port;

Yeah, lots of serial drivers do this and it's old-fashioned.  It would be
clearer to use container_of() rather than the open-coded typecast.  That
way, the uart_port doesn't need to be the first member of uart_sc26xx_port,
too.


> +	up->imr |= mask << (line * 4);
> +	WRITE_SC(port, IMR, up->imr);
> +}
>
> ...
>
> +
> +/* port->lock is not held.  */
> +static unsigned int sc26xx_tx_empty(struct uart_port *port)
> +{
> +	unsigned long flags;
> +	unsigned int ret;
> +
> +	spin_lock_irqsave(&port->lock, flags);
> +	ret = (READ_SC_PORT(port, SR) & SR_TXRDY) ? TIOCSER_TEMT : 0;
> +	spin_unlock_irqrestore(&port->lock, flags);
> +	return ret;
> +}

I suspect the locking here doesn't actually do anything?

> +/* port->lock is not held.  */
> +static void sc26xx_set_termios(struct uart_port *port, struct ktermios *termios,
> +			      struct ktermios *old)

hm, termios stuff.  I'll cc Alan on the commit...

> +static struct uart_port *sc26xx_port;
> +
> +#ifdef CONFIG_SERIAL_SC26XX_CONSOLE
> +static inline void sc26xx_console_putchar(struct uart_port *port, char c)
> +{
> +	unsigned long flags;
> +	int limit = 1000000;
> +
> +	spin_lock_irqsave(&port->lock, flags);
> +
> +	while (limit-- > 0) {
> +		if (READ_SC_PORT(port, SR) & SR_TXRDY) {
> +			WRITE_SC_PORT(port, THR, c);
> +			break;
> +		}
> +		udelay(2);
> +	}
> +
> +	spin_unlock_irqrestore(&port->lock, flags);
> +}

This is far too large to be inlined.

> +static void sc26xx_console_write(struct console *con, const char *s, unsigned n)
> +{
> +	struct uart_port *port = sc26xx_port;
> +	int i;
> +
> +	for (i = 0; i < n; i++) {
> +		if (*s == '\n')
> +			sc26xx_console_putchar(port, '\r');
> +		sc26xx_console_putchar(port, *s++);
> +	}
> +}
> +
> +static int __init sc26xx_console_setup(struct console *con, char *options)
> +{
> +	struct uart_port *port = sc26xx_port;
> +	int baud = 9600;
> +	int bits = 8;
> +	int parity = 'n';
> +	int flow = 'n';
> +
> +	if (port->type != PORT_SC26XX)
> +		return -1;
> +
> +	printk(KERN_INFO "Console: ttySC%d (SC26XX)\n", con->index);
> +	if (options)
> +		uart_parse_options(options, &baud, &parity, &bits, &flow);
> +
> +	return uart_set_options(port, con, baud, parity, bits, flow);
> +}
> +
> +static struct uart_driver sc26xx_reg;
> +static struct console sc26xx_console = {
> +	.name	=	"ttySC",
> +	.write	=	sc26xx_console_write,
> +	.device	=	uart_console_device,
> +	.setup  =       sc26xx_console_setup,
> +	.flags	=	CON_PRINTBUFFER,
> +	.index	=	-1,
> +	.data	=	&sc26xx_reg,
> +};
> +#define SC26XX_CONSOLE   &sc26xx_console
> +#else
> +#define SC26XX_CONSOLE   NULL
> +#endif
> +
> +static struct uart_driver sc26xx_reg = {
> +	.owner			= THIS_MODULE,
> +	.driver_name		= "SC26xx",
> +	.dev_name		= "ttySC",
> +	.major			= SC26XX_MAJOR,
> +	.minor			= SC26XX_MINOR_START,
> +	.nr			= SC26XX_NR,
> +	.cons                   = SC26XX_CONSOLE,
> +};
> +
> +static inline u8 sc26xx_flags2mask(unsigned int flags, unsigned int bitpos)
> +{
> +	unsigned int bit = (flags >> bitpos) & 15;
> +
> +	return bit ? (1 << (bit - 1)) : 0;
> +}

This might be too big as well.  It's less of an issue for __devinit text
though.


--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux