including adding proper support for command line parsing.
Use cleaner 1956 WAR method, getting rid of all but one ifdef
and an extra static array.
Fix bug where a 64-bit write was being done to a 32-bit register
during port initialization.
Clean up considerable whitespace and style issues.
Signed-off-by: Andrew Sharp <tigerand@gmail.com>
---
drivers/char/sb1250_duart.c | 191 ++++++++++++++++++++++++++----------------
1 files changed, 118 insertions(+), 73 deletions(-)
diff --git a/drivers/char/sb1250_duart.c b/drivers/char/sb1250_duart.c
index 4ef345c..dcbbcb9 100644
--- a/drivers/char/sb1250_duart.c
+++ b/drivers/char/sb1250_duart.c
@@ -10,13 +10,13 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
+ *
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
-/*
+/*
* Driver support for the on-chip sb1250 dual-channel serial port,
* running in asynchronous mode. Also, support for doing a serial console
* on one of those ports
@@ -81,18 +81,32 @@ char sb1250_duart_present[DUART_MAX_LINE];
EXPORT_SYMBOL(sb1250_duart_present);
/*
- * Still not sure what the termios structures set up here are for,
+ * In bug 1956, we get glitches that can mess up uart registers. This
+ * "read-mode-reg after any register access" is an accepted workaround.
+ */
+#if SIBYTE_1956_WAR
+# define SB1_SER1956_WAR {
\
+ u32 ignore;
\
+ ignore = csr_in32(uart_states[line].mode_1); \
+ ignore = csr_in32(uart_states[line].mode_2); \
+ }
+#else
+# define SB1_SER1956_WAR
+#endif
+
+/*
+ * Still not sure what the termios structures set up here are for,
* but we have to supply pointers to them to register the tty driver
*/
static struct tty_driver *sb1250_duart_driver; //, sb1250_duart_callout_driver;
/*
- * This lock protects both the open flags for all the uart states as
+ * This lock protects both the open flags for all the uart states as
* well as the reference count for the module
*/
static DEFINE_SPINLOCK(open_lock);
-typedef struct {
+typedef struct {
unsigned char outp_buf[SERIAL_XMIT_SIZE];
unsigned int outp_head;
unsigned int outp_tail;
@@ -117,33 +131,20 @@ typedef struct {
static uart_state_t uart_states[DUART_MAX_LINE];
/*
- * Inline functions local to this module
+ * Inline functions local to this module
*/
-/*
- * In bug 1956, we get glitches that can mess up uart registers. This
- * "write-mode-1 after any register access" is the accepted
- * workaround.
- */
-#if SIBYTE_1956_WAR
-static unsigned int last_mode1[DUART_MAX_LINE];
-#endif
-
static inline u32 READ_SERCSR(volatile u32 *addr, int line)
{
u32 val = csr_in32(addr);
-#if SIBYTE_1956_WAR
- csr_out32(last_mode1[line], uart_states[line].mode_1);
-#endif
+ SB1_SER1956_WAR;
return val;
}
static inline void WRITE_SERCSR(u32 val, volatile u32 *addr, int line)
{
csr_out32(val, addr);
-#if SIBYTE_1956_WAR
- csr_out32(last_mode1[line], uart_states[line].mode_1);
-#endif
+ SB1_SER1956_WAR;
}
static void init_duart_port(uart_state_t *port, int line)
@@ -158,6 +159,8 @@ static void init_duart_port(uart_state_t *port, int line)
port->mode_2 = IOADDR(UNIT_CHANREG(line, R_DUART_MODE_REG_2));
port->clk_sel = IOADDR(UNIT_CHANREG(line, R_DUART_CLK_SEL));
port->cmd = IOADDR(UNIT_CHANREG(line, R_DUART_CMD));
+ port->last_cflags = DEFAULT_CFLAGS;
+ spin_lock_init(&port->outp_lock);
port->flags |= DUART_INITIALIZED;
}
}
@@ -173,7 +176,7 @@ static inline void duart_mask_ints(unsigned int line,
unsigned int mask)
WRITE_SERCSR(tmp & ~mask, port->imr, line);
}
-
+
/* Unmask the passed interrupt lines at the duart level */
static inline void duart_unmask_ints(unsigned int line, unsigned int mask)
{
@@ -213,7 +216,7 @@ static inline void transmit_char_pio(uart_state_t *us)
duart_mask_ints(us->line, M_DUART_IMR_TX);
}
- if (us->open &&
+ if (us->open &&
(us->outp_count < (SERIAL_XMIT_SIZE/2))) {
/*
* We told the discipline at one point that we had no
@@ -227,9 +230,9 @@ static inline void transmit_char_pio(uart_state_t *us)
}
}
-/*
+/*
* Generic interrupt handler for both channels. dev_id is a pointer
- * to the proper uart_states structure, so from that we can derive
+ * to the proper uart_states structure, so from that we can derive
* which port interrupted
*/
@@ -290,10 +293,10 @@ static int duart_write_room(struct tty_struct *tty)
/* memcpy the data from src to destination, but take extra care if the
data is coming from user space */
-static inline int copy_buf(char *dest, const char *src, int size, int
from_user)
+static inline int copy_buf(char *dest, const char *src, int size, int
from_user)
{
if (from_user) {
- (void) copy_from_user(dest, src, size);
+ (void) copy_from_user(dest, src, size);
} else {
memcpy(dest, src, size);
}
@@ -316,7 +319,8 @@ static int duart_write(struct tty_struct *tty, const
unsigned char *buf,
us = tty->driver_data;
if (!us) return 0;
- pr_debug("duart_write called for %i chars by %i (%s)\n", count,
current->pid, current->comm);
+ pr_debug("duart_write called for %i chars by %i (%s)\n", count,
+ current->pid, current->comm);
spin_lock_irqsave(&us->outp_lock, flags);
@@ -342,7 +346,7 @@ static int duart_write(struct tty_struct *tty, const
unsigned char *buf,
spin_unlock_irqrestore(&us->outp_lock, flags);
- if (us->outp_count && !tty->stopped &&
+ if (us->outp_count && !tty->stopped &&
!tty->hw_stopped && !(us->flags & TX_INTEN)) {
us->flags |= TX_INTEN;
duart_unmask_ints(us->line, M_DUART_IMR_TX);
@@ -379,11 +383,13 @@ static void duart_flush_chars(struct tty_struct * tty)
{
uart_state_t *port;
- if (!tty) return;
+ if (!tty)
+ return;
port = tty->driver_data;
- if (!port) return;
+ if (!port)
+ return;
if (port->outp_count <= 0 || tty->stopped || tty->hw_stopped) {
return;
@@ -393,7 +399,7 @@ static void duart_flush_chars(struct tty_struct * tty)
duart_unmask_ints(port->line, M_DUART_IMR_TX);
}
-/* Return the number of characters in the output buffer that have yet to be
+/* Return the number of characters in the output buffer that have yet to be
written */
static int duart_chars_in_buffer(struct tty_struct *tty)
{
@@ -436,10 +442,10 @@ static inline void duart_set_cflag(unsigned int line,
unsigned int cflag)
switch (cflag & CSIZE) {
case CS7:
mode_reg1 |= V_DUART_BITS_PER_CHAR_7;
-
+
default:
- /* We don't handle CS5 or CS6...is there a way we're supposed
to flag this?
- right now we just force them to CS8 */
+ /* We don't handle CS5 or CS6...is there a way we're supposed to
+ * flag this? right now we just force them to CS8 */
mode_reg1 |= 0x0;
break;
}
@@ -452,13 +458,13 @@ static inline void duart_set_cflag(unsigned int line,
unsigned int cflag)
if (cflag & PARODD) {
mode_reg1 |= M_DUART_PARITY_TYPE_ODD;
}
-
+
/* Formula for this is (5000000/baud)-1, but we saturate
at 12 bits, which means we can't actually do anything less
that 1200 baud */
switch (cflag & CBAUD) {
- case B200:
- case B300:
+ case B200:
+ case B300:
case B1200: clk_divisor = 4095; break;
case B1800: clk_divisor = 2776; break;
case B2400: clk_divisor = 2082; break;
@@ -467,6 +473,7 @@ static inline void duart_set_cflag(unsigned int line,
unsigned int cflag)
case B9600: clk_divisor = 519; break;
case B19200: clk_divisor = 259; break;
case B38400: clk_divisor = 129; break;
+ default:
case B57600: clk_divisor = 85; break;
case B115200: clk_divisor = 42; break;
}
@@ -482,25 +489,26 @@ static void duart_set_termios(struct tty_struct *tty,
struct termios *old)
{
uart_state_t *us = (uart_state_t *) tty->driver_data;
- pr_debug("duart_set_termios called by %i (%s)\n", current->pid,
current->comm);
+ pr_debug("duart_set_termios called by %i (%s)\n", current->pid,
+ current->comm);
if (old && tty->termios->c_cflag == old->c_cflag)
return;
duart_set_cflag(us->line, tty->termios->c_cflag);
}
-static int get_serial_info(uart_state_t *us, struct serial_struct * retinfo) {
-
+static int get_serial_info(uart_state_t *us, struct serial_struct * retinfo)
+{
struct serial_struct tmp;
memset(&tmp, 0, sizeof(tmp));
- tmp.type=PORT_SB1250;
- tmp.line=us->line;
- tmp.port=UNIT_CHANREG(tmp.line,0);
- tmp.irq=UNIT_INT(tmp.line);
- tmp.xmit_fifo_size=16; /* fixed by hw */
- tmp.baud_base=5000000;
- tmp.io_type=SERIAL_IO_MEM;
+ tmp.type = PORT_SB1250;
+ tmp.line = us->line;
+ tmp.port = UNIT_CHANREG(tmp.line,0);
+ tmp.irq = UNIT_INT(tmp.line);
+ tmp.xmit_fifo_size = 16; /* fixed by hw */
+ tmp.baud_base = 5000000;
+ tmp.io_type = SERIAL_IO_MEM;
if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
return -EFAULT;
@@ -588,10 +596,10 @@ static void duart_stop(struct tty_struct *tty)
}
/* Not sure on the semantics of this; are we supposed to wait until the stuff
- already in the hardware FIFO drains, or are we supposed to wait until
- we've drained the output buffer, too? I'm assuming the former, 'cause thats
- what the other drivers seem to assume
-*/
+ * already in the hardware FIFO drains, or are we supposed to wait until
+ * we've drained the output buffer, too? I'm assuming the former, 'cause thats
+ * what the other drivers seem to assume
+ */
static void duart_wait_until_sent(struct tty_struct *tty, int timeout)
{
@@ -602,7 +610,7 @@ static void duart_wait_until_sent(struct tty_struct *tty,
int timeout)
pr_debug("duart_wait_until_sent(%d)+\n", timeout);
while (!(READ_SERCSR(us->status, us->line) & M_DUART_TX_EMT)) {
set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(1);
+ schedule_timeout(1);
if (signal_pending(current))
break;
if (timeout && time_after(jiffies, orig_jiffies + timeout))
@@ -638,8 +646,8 @@ static int duart_open(struct tty_struct *tty, struct file
*filp)
return -ENODEV;
pr_debug("duart_open called by %i (%s), tty is %p, rw is %p, ww is
%p\n",
- current->pid, current->comm, tty, tty->read_wait,
- tty->write_wait);
+ current->pid, current->comm, tty, (void *)&tty->read_wait,
+ (void *)&tty->write_wait);
us = uart_states + line;
tty->driver_data = us;
@@ -750,7 +758,7 @@ static void __init sb1250_duart_init_present_lines(void)
/* Set up the driver and register it, register the UART interrupts. This
is called from tty_init, or as a part of the module init */
-static int __init sb1250_duart_init(void)
+static int __init sb1250_duart_init(void)
{
int i;
@@ -777,14 +785,21 @@ static int __init sb1250_duart_init(void)
continue;
init_duart_port(port, i);
- spin_lock_init(&port->outp_lock);
duart_mask_ints(i, M_DUART_IMR_ALL);
if (request_irq(UNIT_INT(i), duart_int, 0, "uart", port)) {
panic("Couldn't get uart0 interrupt line");
}
- __raw_writeq(M_DUART_RX_EN|M_DUART_TX_EN,
- IOADDR(UNIT_CHANREG(i, R_DUART_CMD)));
- duart_set_cflag(i, DEFAULT_CFLAGS);
+ /*
+ * this generic write to a register does not implement the 1956
WAR
+ * and sometimes output gets corrupted afterwards, especially
+ * if the port was in use as a console.
+ */
+ __raw_writel(M_DUART_RX_EN|M_DUART_TX_EN, port->cmd);
+ /*
+ * we should really check to see if it's registered as a console
+ * before trashing those settings
+ */
+ duart_set_cflag(i, port->last_cflags);
}
/* Interrupts are now active, our ISR can be called. */
@@ -851,7 +866,7 @@ static void ser_console_write(struct console *cons, const
char *s,
if (*s == '\n')
serial_outc('\r', line);
serial_outc(*s++, line);
- }
+ }
WRITE_SERCSR(imr, port->imr, line);
}
@@ -867,25 +882,54 @@ static int ser_console_setup(struct console *cons, char
*str)
sb1250_duart_init_present_lines();
- for (i=0; i<DUART_MAX_LINE; i++) {
+ for (i = 0; i < DUART_MAX_LINE; i++) {
uart_state_t *port = uart_states + i;
+ u32 cflags = DEFAULT_CFLAGS;
if (!sb1250_duart_present[i])
continue;
init_duart_port(port, i);
-#if SIBYTE_1956_WAR
- last_mode1[i] =
V_DUART_PARITY_MODE_NONE|V_DUART_BITS_PER_CHAR_8;
-#endif
- WRITE_SERCSR(V_DUART_PARITY_MODE_NONE|V_DUART_BITS_PER_CHAR_8,
- port->mode_1, i);
- WRITE_SERCSR(M_DUART_STOP_BIT_LEN_1,
- port->mode_2, i);
- WRITE_SERCSR(V_DUART_BAUD_RATE(115200),
- port->clk_sel, i);
- WRITE_SERCSR(M_DUART_RX_EN|M_DUART_TX_EN,
- port->cmd, i);
+ if (str) {
+ int speed;
+ char par = 'n';
+ int cbits = 8;
+
+ cflags = 0;
+
+ /*
+ * format is in Documentation/serial_console.txt
+ */
+ sscanf(str, "%d%c%d", &speed, &par, &cbits);
+
+ switch (speed) {
+ case 200:
+ case 300:
+ case 1200: cflags |= B1200; break;
+ case 1800: cflags |= B1800; break;
+ case 2400: cflags |= B2400; break;
+ case 4800: cflags |= B4800; break;
+ default:
+ case 9600: cflags |= B9600; break;
+ case 19200: cflags |= B19200; break;
+ case 38400: cflags |= B38400; break;
+ case 57600: cflags |= B57600; break;
+ case 115200:cflags |= B115200; break;
+ }
+ switch (par) {
+ case 'o': cflags |= PARODD;
+ case 'e': cflags |= PARENB;
+ }
+ switch (cbits) {
+ default: // we only do 7 or 8
+ case 8: cflags |= CS8; break;
+ case 7: cflags |= CS7; break;
+ }
+ }
+ duart_set_cflag(i, cflags);
+ WRITE_SERCSR(M_DUART_RX_EN | M_DUART_TX_EN, port->cmd, i);
}
+
return 0;
}
@@ -900,6 +944,7 @@ static struct console sb1250_ser_cons = {
static int __init sb1250_serial_console_init(void)
{
+ //add_preferred_console("duart", 0, "57600n8");
register_console(&sb1250_ser_cons);
return 0;
}
--
1.4.4.4
--SLDf9lqlvOQaIe6s--
|