Commit 137fd8d5 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] m68knommu: fixes to the ColdFire serial driver

From: <gerg@snapgear.com>

A whole bunch of fixes for the ColdFire serial driver:

. remove unused CONFIG_LEDMAN code
. reformat port definitions to new style structure init
. change "addr" field type to reduce casting in ColdFire serial driver
. cleanup locking problems in mcfrs_write().
. implement fraction baud rate clock support for hardware that
  supports it (namely the ColdFire 5272)
. implement wait_until_sent, some ColdFire parts of hardware support
  for this (again the 5272).
. correctly use return values from put_user(), get_user() and copy_to_user()

Many of these originaly from kernel janitors.
parent 2ab37538
...@@ -10,6 +10,11 @@ ...@@ -10,6 +10,11 @@
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1998 TSHG * Copyright (C) 1998 TSHG
* Copyright (c) 1999 Rt-Control Inc. <jeff@uclinux.org> * Copyright (c) 1999 Rt-Control Inc. <jeff@uclinux.org>
*
* Changes:
* 08/07/2003 Daniele Bellucci <bellucda@tiscali.it>
* some cleanups in mcfrs_write.
*
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -27,11 +32,7 @@ ...@@ -27,11 +32,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/serial.h> #include <linux/serial.h>
#include <linux/serialP.h> #include <linux/serialP.h>
#ifdef CONFIG_LEDMAN
#include <linux/ledman.h>
#endif
#include <linux/console.h> #include <linux/console.h>
#include <linux/version.h>
#include <linux/init.h> #include <linux/init.h>
#include <asm/io.h> #include <asm/io.h>
...@@ -84,8 +85,6 @@ static struct tty_driver *mcfrs_serial_driver; ...@@ -84,8 +85,6 @@ static struct tty_driver *mcfrs_serial_driver;
#undef SERIAL_DEBUG_OPEN #undef SERIAL_DEBUG_OPEN
#undef SERIAL_DEBUG_FLOW #undef SERIAL_DEBUG_FLOW
#define _INLINE_ inline
#ifdef CONFIG_M5282 #ifdef CONFIG_M5282
#define IRQBASE 77 #define IRQBASE 77
#else #else
...@@ -96,8 +95,18 @@ static struct tty_driver *mcfrs_serial_driver; ...@@ -96,8 +95,18 @@ static struct tty_driver *mcfrs_serial_driver;
* Configuration table, UARTs to look for at startup. * Configuration table, UARTs to look for at startup.
*/ */
static struct mcf_serial mcfrs_table[] = { static struct mcf_serial mcfrs_table[] = {
{ 0, (MCF_MBAR+MCFUART_BASE1), IRQBASE, ASYNC_BOOT_AUTOCONF }, /* ttyS0 */ { /* ttyS0 */
{ 0, (MCF_MBAR+MCFUART_BASE2), IRQBASE+1, ASYNC_BOOT_AUTOCONF }, /* ttyS1 */ .magic = 0,
.addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE1),
.irq = IRQBASE,
.flags = ASYNC_BOOT_AUTOCONF,
},
{ /* ttyS1 */
.magic = 0,
.addr = (volatile unsigned char *) (MCF_MBAR+MCFUART_BASE2),
.irq = IRQBASE+1,
.flags = ASYNC_BOOT_AUTOCONF,
},
}; };
...@@ -138,15 +147,16 @@ static DECLARE_MUTEX(mcfrs_tmp_buf_sem); ...@@ -138,15 +147,16 @@ static DECLARE_MUTEX(mcfrs_tmp_buf_sem);
* Forware declarations... * Forware declarations...
*/ */
static void mcfrs_change_speed(struct mcf_serial *info); static void mcfrs_change_speed(struct mcf_serial *info);
static void mcfrs_wait_until_sent(struct tty_struct *tty, int timeout);
static inline int serial_paranoia_check(struct mcf_serial *info, static inline int serial_paranoia_check(struct mcf_serial *info,
char *name, const char *routine) char *name, const char *routine)
{ {
#ifdef SERIAL_PARANOIA_CHECK #ifdef SERIAL_PARANOIA_CHECK
static const char *badmagic = static const char badmagic[] =
"MCFRS(warning): bad magic number for serial struct %s in %s\n"; "MCFRS(warning): bad magic number for serial struct %s in %s\n";
static const char *badinfo = static const char badinfo[] =
"MCFRS(warning): null mcf_serial for %s in %s\n"; "MCFRS(warning): null mcf_serial for %s in %s\n";
if (!info) { if (!info) {
...@@ -184,7 +194,7 @@ static void mcfrs_setsignals(struct mcf_serial *info, int dtr, int rts) ...@@ -184,7 +194,7 @@ static void mcfrs_setsignals(struct mcf_serial *info, int dtr, int rts)
#endif #endif
} }
if (rts >= 0) { if (rts >= 0) {
uartp = (volatile unsigned char *) info->addr; uartp = info->addr;
if (rts) { if (rts) {
info->sigs |= TIOCM_RTS; info->sigs |= TIOCM_RTS;
uartp[MCFUART_UOP1] = MCFUART_UOP_RTS; uartp[MCFUART_UOP1] = MCFUART_UOP_RTS;
...@@ -214,7 +224,7 @@ static int mcfrs_getsignals(struct mcf_serial *info) ...@@ -214,7 +224,7 @@ static int mcfrs_getsignals(struct mcf_serial *info)
#endif #endif
local_irq_save(flags); local_irq_save(flags);
uartp = (volatile unsigned char *) info->addr; uartp = info->addr;
sigs = (uartp[MCFUART_UIPR] & MCFUART_UIPR_CTS) ? 0 : TIOCM_CTS; sigs = (uartp[MCFUART_UIPR] & MCFUART_UIPR_CTS) ? 0 : TIOCM_CTS;
sigs |= (info->sigs & TIOCM_RTS); sigs |= (info->sigs & TIOCM_RTS);
...@@ -254,7 +264,7 @@ static void mcfrs_stop(struct tty_struct *tty) ...@@ -254,7 +264,7 @@ static void mcfrs_stop(struct tty_struct *tty)
return; return;
local_irq_save(flags); local_irq_save(flags);
uartp = (volatile unsigned char *) info->addr; uartp = info->addr;
info->imr &= ~MCFUART_UIR_TXREADY; info->imr &= ~MCFUART_UIR_TXREADY;
uartp[MCFUART_UIMR] = info->imr; uartp[MCFUART_UIMR] = info->imr;
local_irq_restore(flags); local_irq_restore(flags);
...@@ -271,7 +281,7 @@ static void mcfrs_start(struct tty_struct *tty) ...@@ -271,7 +281,7 @@ static void mcfrs_start(struct tty_struct *tty)
local_irq_save(flags); local_irq_save(flags);
if (info->xmit_cnt && info->xmit_buf) { if (info->xmit_cnt && info->xmit_buf) {
uartp = (volatile unsigned char *) info->addr; uartp = info->addr;
info->imr |= MCFUART_UIR_TXREADY; info->imr |= MCFUART_UIR_TXREADY;
uartp[MCFUART_UIMR] = info->imr; uartp[MCFUART_UIMR] = info->imr;
} }
...@@ -299,7 +309,7 @@ static void mcfrs_start(struct tty_struct *tty) ...@@ -299,7 +309,7 @@ static void mcfrs_start(struct tty_struct *tty)
* ----------------------------------------------------------------------- * -----------------------------------------------------------------------
*/ */
static _INLINE_ void receive_chars(struct mcf_serial *info, struct pt_regs *regs, unsigned short rx) static inline void receive_chars(struct mcf_serial *info)
{ {
volatile unsigned char *uartp; volatile unsigned char *uartp;
struct tty_struct *tty = info->tty; struct tty_struct *tty = info->tty;
...@@ -308,11 +318,7 @@ static _INLINE_ void receive_chars(struct mcf_serial *info, struct pt_regs *regs ...@@ -308,11 +318,7 @@ static _INLINE_ void receive_chars(struct mcf_serial *info, struct pt_regs *regs
if (!tty) if (!tty)
return; return;
#if defined(CONFIG_LEDMAN) uartp = info->addr;
ledman_cmd(LEDMAN_CMD_SET, info->line ? LEDMAN_COM2_RX : LEDMAN_COM1_RX);
#endif
uartp = (volatile unsigned char *) info->addr;
while ((status = uartp[MCFUART_USR]) & MCFUART_USR_RXREADY) { while ((status = uartp[MCFUART_USR]) & MCFUART_USR_RXREADY) {
...@@ -354,15 +360,11 @@ static _INLINE_ void receive_chars(struct mcf_serial *info, struct pt_regs *regs ...@@ -354,15 +360,11 @@ static _INLINE_ void receive_chars(struct mcf_serial *info, struct pt_regs *regs
return; return;
} }
static _INLINE_ void transmit_chars(struct mcf_serial *info) static inline void transmit_chars(struct mcf_serial *info)
{ {
volatile unsigned char *uartp; volatile unsigned char *uartp;
#if defined(CONFIG_LEDMAN) uartp = info->addr;
ledman_cmd(LEDMAN_CMD_SET, info->line ? LEDMAN_COM2_TX : LEDMAN_COM1_TX);
#endif
uartp = (volatile unsigned char *) info->addr;
if (info->x_char) { if (info->x_char) {
/* Send special char - probably flow control */ /* Send special char - probably flow control */
...@@ -399,10 +401,10 @@ irqreturn_t mcfrs_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -399,10 +401,10 @@ irqreturn_t mcfrs_interrupt(int irq, void *dev_id, struct pt_regs *regs)
unsigned char isr; unsigned char isr;
info = &mcfrs_table[(irq - IRQBASE)]; info = &mcfrs_table[(irq - IRQBASE)];
isr = (((volatile unsigned char *)info->addr)[MCFUART_UISR]) & info->imr; isr = info->addr[MCFUART_UISR] & info->imr;
if (isr & MCFUART_UIR_RXREADY) if (isr & MCFUART_UIR_RXREADY)
receive_chars(info, regs, isr); receive_chars(info);
if (isr & MCFUART_UIR_TXREADY) if (isr & MCFUART_UIR_TXREADY)
transmit_chars(info); transmit_chars(info);
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -525,7 +527,7 @@ static int startup(struct mcf_serial * info) ...@@ -525,7 +527,7 @@ static int startup(struct mcf_serial * info)
/* /*
* Reset UART, get it into known state... * Reset UART, get it into known state...
*/ */
uartp = (volatile unsigned char *) info->addr; uartp = info->addr;
uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */ uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */
uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */ uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */
mcfrs_setsignals(info, 1, 1); mcfrs_setsignals(info, 1, 1);
...@@ -571,7 +573,7 @@ static void shutdown(struct mcf_serial * info) ...@@ -571,7 +573,7 @@ static void shutdown(struct mcf_serial * info)
local_irq_save(flags); local_irq_save(flags);
uartp = (volatile unsigned char *) info->addr; uartp = info->addr;
uartp[MCFUART_UIMR] = 0; /* mask all interrupts */ uartp[MCFUART_UIMR] = 0; /* mask all interrupts */
uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */ uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETRX; /* reset RX */
uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */ uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETTX; /* reset TX */
...@@ -603,6 +605,9 @@ static void mcfrs_change_speed(struct mcf_serial *info) ...@@ -603,6 +605,9 @@ static void mcfrs_change_speed(struct mcf_serial *info)
unsigned long flags; unsigned long flags;
unsigned char mr1, mr2; unsigned char mr1, mr2;
int i; int i;
#ifdef CONFIG_M5272
unsigned int fraction;
#endif
if (!info->tty || !info->tty->termios) if (!info->tty || !info->tty->termios)
return; return;
...@@ -626,7 +631,20 @@ static void mcfrs_change_speed(struct mcf_serial *info) ...@@ -626,7 +631,20 @@ static void mcfrs_change_speed(struct mcf_serial *info)
mcfrs_setsignals(info, 0, -1); mcfrs_setsignals(info, 0, -1);
return; return;
} }
/* compute the baudrate clock */
#ifdef CONFIG_M5272
/*
* For the MCF5272, also compute the baudrate fraction.
*/
baudclk = (MCF_BUSCLK / mcfrs_baud_table[i]) / 32;
fraction = MCF_BUSCLK - (baudclk * 32 * mcfrs_baud_table[i]);
fraction *= 16;
fraction /= (32 * mcfrs_baud_table[i]);
#else
baudclk = ((MCF_BUSCLK / mcfrs_baud_table[i]) + 16) / 32; baudclk = ((MCF_BUSCLK / mcfrs_baud_table[i]) + 16) / 32;
#endif
info->baud = mcfrs_baud_table[i]; info->baud = mcfrs_baud_table[i];
mr1 = MCFUART_MR1_RXIRQRDY | MCFUART_MR1_RXERRCHAR; mr1 = MCFUART_MR1_RXIRQRDY | MCFUART_MR1_RXERRCHAR;
...@@ -671,7 +689,7 @@ static void mcfrs_change_speed(struct mcf_serial *info) ...@@ -671,7 +689,7 @@ static void mcfrs_change_speed(struct mcf_serial *info)
else else
info->flags |= ASYNC_CHECK_CD; info->flags |= ASYNC_CHECK_CD;
uartp = (volatile unsigned char *) info->addr; uartp = info->addr;
local_irq_save(flags); local_irq_save(flags);
#if 0 #if 0
...@@ -690,6 +708,9 @@ static void mcfrs_change_speed(struct mcf_serial *info) ...@@ -690,6 +708,9 @@ static void mcfrs_change_speed(struct mcf_serial *info)
uartp[MCFUART_UMR] = mr2; uartp[MCFUART_UMR] = mr2;
uartp[MCFUART_UBG1] = (baudclk & 0xff00) >> 8; /* set msb byte */ uartp[MCFUART_UBG1] = (baudclk & 0xff00) >> 8; /* set msb byte */
uartp[MCFUART_UBG2] = (baudclk & 0xff); /* set lsb byte */ uartp[MCFUART_UBG2] = (baudclk & 0xff); /* set lsb byte */
#ifdef CONFIG_M5272
uartp[MCFUART_UFPD] = (fraction & 0xf); /* set fraction */
#endif
uartp[MCFUART_UCSR] = MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER; uartp[MCFUART_UCSR] = MCFUART_UCSR_RXCLKTIMER | MCFUART_UCSR_TXCLKTIMER;
uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE; uartp[MCFUART_UCR] = MCFUART_UCR_RXENABLE | MCFUART_UCR_TXENABLE;
mcfrs_setsignals(info, 1, -1); mcfrs_setsignals(info, 1, -1);
...@@ -712,7 +733,7 @@ static void mcfrs_flush_chars(struct tty_struct *tty) ...@@ -712,7 +733,7 @@ static void mcfrs_flush_chars(struct tty_struct *tty)
/* Enable transmitter */ /* Enable transmitter */
local_irq_save(flags); local_irq_save(flags);
uartp = (volatile unsigned char *) info->addr; uartp = info->addr;
info->imr |= MCFUART_UIR_TXREADY; info->imr |= MCFUART_UIR_TXREADY;
uartp[MCFUART_UIMR] = info->imr; uartp[MCFUART_UIMR] = info->imr;
local_irq_restore(flags); local_irq_restore(flags);
...@@ -742,24 +763,26 @@ static int mcfrs_write(struct tty_struct * tty, int from_user, ...@@ -742,24 +763,26 @@ static int mcfrs_write(struct tty_struct * tty, int from_user,
local_irq_disable(); local_irq_disable();
c = min(count, (int) min(((int)SERIAL_XMIT_SIZE) - info->xmit_cnt - 1, c = min(count, (int) min(((int)SERIAL_XMIT_SIZE) - info->xmit_cnt - 1,
((int)SERIAL_XMIT_SIZE) - info->xmit_head)); ((int)SERIAL_XMIT_SIZE) - info->xmit_head));
if (c <= 0) {
local_irq_restore(flags); local_irq_restore(flags);
if (c <= 0)
break; break;
}
if (from_user) { if (from_user) {
down(&mcfrs_tmp_buf_sem); down(&mcfrs_tmp_buf_sem);
copy_from_user(mcfrs_tmp_buf, buf, c); if (copy_from_user(mcfrs_tmp_buf, buf, c))
local_irq_restore(flags); return -EFAULT;
local_irq_disable(); local_irq_disable();
c = min(c, (int) min(((int)SERIAL_XMIT_SIZE) - info->xmit_cnt - 1, c = min(c, (int) min(((int)SERIAL_XMIT_SIZE) - info->xmit_cnt - 1,
((int)SERIAL_XMIT_SIZE) - info->xmit_head)); ((int)SERIAL_XMIT_SIZE) - info->xmit_head));
local_irq_restore(flags);
memcpy(info->xmit_buf + info->xmit_head, mcfrs_tmp_buf, c); memcpy(info->xmit_buf + info->xmit_head, mcfrs_tmp_buf, c);
up(&mcfrs_tmp_buf_sem); up(&mcfrs_tmp_buf_sem);
} else } else
memcpy(info->xmit_buf + info->xmit_head, buf, c); memcpy(info->xmit_buf + info->xmit_head, buf, c);
local_irq_disable();
info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);
info->xmit_cnt += c; info->xmit_cnt += c;
local_irq_restore(flags); local_irq_restore(flags);
...@@ -770,7 +793,7 @@ static int mcfrs_write(struct tty_struct * tty, int from_user, ...@@ -770,7 +793,7 @@ static int mcfrs_write(struct tty_struct * tty, int from_user,
} }
local_irq_disable(); local_irq_disable();
uartp = (volatile unsigned char *) info->addr; uartp = info->addr;
info->imr |= MCFUART_UIR_TXREADY; info->imr |= MCFUART_UIR_TXREADY;
uartp[MCFUART_UIMR] = info->imr; uartp[MCFUART_UIMR] = info->imr;
local_irq_restore(flags); local_irq_restore(flags);
...@@ -884,15 +907,14 @@ static int get_serial_info(struct mcf_serial * info, ...@@ -884,15 +907,14 @@ static int get_serial_info(struct mcf_serial * info,
memset(&tmp, 0, sizeof(tmp)); memset(&tmp, 0, sizeof(tmp));
tmp.type = info->type; tmp.type = info->type;
tmp.line = info->line; tmp.line = info->line;
tmp.port = info->addr; tmp.port = (unsigned int) info->addr;
tmp.irq = info->irq; tmp.irq = info->irq;
tmp.flags = info->flags; tmp.flags = info->flags;
tmp.baud_base = info->baud_base; tmp.baud_base = info->baud_base;
tmp.close_delay = info->close_delay; tmp.close_delay = info->close_delay;
tmp.closing_wait = info->closing_wait; tmp.closing_wait = info->closing_wait;
tmp.custom_divisor = info->custom_divisor; tmp.custom_divisor = info->custom_divisor;
copy_to_user(retinfo,&tmp,sizeof(*retinfo)); return copy_to_user(retinfo,&tmp,sizeof(*retinfo)) ? -EFAULT : 0;
return 0;
} }
static int set_serial_info(struct mcf_serial * info, static int set_serial_info(struct mcf_serial * info,
...@@ -904,7 +926,8 @@ static int set_serial_info(struct mcf_serial * info, ...@@ -904,7 +926,8 @@ static int set_serial_info(struct mcf_serial * info,
if (!new_info) if (!new_info)
return -EFAULT; return -EFAULT;
copy_from_user(&new_serial,new_info,sizeof(new_serial)); if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
return -EFAULT;
old_info = *info; old_info = *info;
if (!capable(CAP_SYS_ADMIN)) { if (!capable(CAP_SYS_ADMIN)) {
...@@ -957,12 +980,11 @@ static int get_lsr_info(struct mcf_serial * info, unsigned int *value) ...@@ -957,12 +980,11 @@ static int get_lsr_info(struct mcf_serial * info, unsigned int *value)
unsigned char status; unsigned char status;
local_irq_save(flags); local_irq_save(flags);
uartp = (volatile unsigned char *) info->addr; uartp = info->addr;
status = (uartp[MCFUART_USR] & MCFUART_USR_TXEMPTY) ? TIOCSER_TEMT : 0; status = (uartp[MCFUART_USR] & MCFUART_USR_TXEMPTY) ? TIOCSER_TEMT : 0;
local_irq_restore(flags); local_irq_restore(flags);
put_user(status,value); return put_user(status,value);
return 0;
} }
/* /*
...@@ -976,7 +998,7 @@ static void send_break( struct mcf_serial * info, int duration) ...@@ -976,7 +998,7 @@ static void send_break( struct mcf_serial * info, int duration)
if (!info->addr) if (!info->addr)
return; return;
current->state = TASK_INTERRUPTIBLE; current->state = TASK_INTERRUPTIBLE;
uartp = (volatile unsigned char *) info->addr; uartp = info->addr;
local_irq_save(flags); local_irq_save(flags);
uartp[MCFUART_UCR] = MCFUART_UCR_CMDBREAKSTART; uartp[MCFUART_UCR] = MCFUART_UCR_CMDBREAKSTART;
...@@ -1026,9 +1048,6 @@ static int mcfrs_ioctl(struct tty_struct *tty, struct file * file, ...@@ -1026,9 +1048,6 @@ static int mcfrs_ioctl(struct tty_struct *tty, struct file * file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
{ {
struct mcf_serial * info = (struct mcf_serial *)tty->driver_data; struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
#ifdef TIOCSET422
unsigned int val;
#endif
int retval, error; int retval, error;
if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl")) if (serial_paranoia_check(info, tty->name, "mcfrs_ioctl"))
...@@ -1058,11 +1077,10 @@ static int mcfrs_ioctl(struct tty_struct *tty, struct file * file, ...@@ -1058,11 +1077,10 @@ static int mcfrs_ioctl(struct tty_struct *tty, struct file * file,
send_break(info, arg ? arg*(HZ/10) : HZ/4); send_break(info, arg ? arg*(HZ/10) : HZ/4);
return 0; return 0;
case TIOCGSOFTCAR: case TIOCGSOFTCAR:
error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long)); error = put_user(C_CLOCAL(tty) ? 1 : 0,
(unsigned long *) arg);
if (error) if (error)
return error; return error;
put_user(C_CLOCAL(tty) ? 1 : 0,
(unsigned long *) arg);
return 0; return 0;
case TIOCSSOFTCAR: case TIOCSSOFTCAR:
get_user(arg, (unsigned long *) arg); get_user(arg, (unsigned long *) arg);
...@@ -1089,23 +1107,25 @@ static int mcfrs_ioctl(struct tty_struct *tty, struct file * file, ...@@ -1089,23 +1107,25 @@ static int mcfrs_ioctl(struct tty_struct *tty, struct file * file,
return get_lsr_info(info, (unsigned int *) arg); return get_lsr_info(info, (unsigned int *) arg);
case TIOCSERGSTRUCT: case TIOCSERGSTRUCT:
error = verify_area(VERIFY_WRITE, (void *) arg, error = copy_to_user((struct mcf_serial *) arg,
sizeof(struct mcf_serial));
if (error)
return error;
copy_to_user((struct mcf_serial *) arg,
info, sizeof(struct mcf_serial)); info, sizeof(struct mcf_serial));
if (error)
return -EFAULT;
return 0; return 0;
#ifdef TIOCSET422 #ifdef TIOCSET422
case TIOCSET422: case TIOCSET422: {
unsigned int val;
get_user(val, (unsigned int *) arg); get_user(val, (unsigned int *) arg);
mcf_setpa(MCFPP_PA11, (val ? 0 : MCFPP_PA11)); mcf_setpa(MCFPP_PA11, (val ? 0 : MCFPP_PA11));
break; break;
case TIOCGET422: }
case TIOCGET422: {
unsigned int val;
val = (mcf_getpa() & MCFPP_PA11) ? 0 : 1; val = (mcf_getpa() & MCFPP_PA11) ? 0 : 1;
put_user(val, (unsigned int *) arg); put_user(val, (unsigned int *) arg);
break; break;
}
#endif #endif
default: default:
...@@ -1200,7 +1220,7 @@ static void mcfrs_close(struct tty_struct *tty, struct file * filp) ...@@ -1200,7 +1220,7 @@ static void mcfrs_close(struct tty_struct *tty, struct file * filp)
* line status register. * line status register.
*/ */
info->imr &= ~MCFUART_UIR_RXREADY; info->imr &= ~MCFUART_UIR_RXREADY;
uartp = (volatile unsigned char *) info->addr; uartp = info->addr;
uartp[MCFUART_UIMR] = info->imr; uartp[MCFUART_UIMR] = info->imr;
#if 0 #if 0
...@@ -1237,6 +1257,76 @@ static void mcfrs_close(struct tty_struct *tty, struct file * filp) ...@@ -1237,6 +1257,76 @@ static void mcfrs_close(struct tty_struct *tty, struct file * filp)
local_irq_restore(flags); local_irq_restore(flags);
} }
/*
* mcfrs_wait_until_sent() --- wait until the transmitter is empty
*/
static void
mcfrs_wait_until_sent(struct tty_struct *tty, int timeout)
{
#ifdef CONFIG_M5272
#define MCF5272_FIFO_SIZE 25 /* fifo size + shift reg */
struct mcf_serial * info = (struct mcf_serial *)tty->driver_data;
volatile unsigned char *uartp;
unsigned long orig_jiffies, fifo_time, char_time, fifo_cnt;
if (serial_paranoia_check(info, tty->name, "mcfrs_wait_until_sent"))
return;
orig_jiffies = jiffies;
/*
* Set the check interval to be 1/5 of the approximate time
* to send the entire fifo, and make it at least 1. The check
* interval should also be less than the timeout.
*
* Note: we have to use pretty tight timings here to satisfy
* the NIST-PCTS.
*/
fifo_time = (MCF5272_FIFO_SIZE * HZ * 10) / info->baud;
char_time = fifo_time / 5;
if (char_time == 0)
char_time = 1;
if (timeout && timeout < char_time)
char_time = timeout;
/*
* Clamp the timeout period at 2 * the time to empty the
* fifo. Just to be safe, set the minimum at .5 seconds.
*/
fifo_time *= 2;
if (fifo_time < (HZ/2))
fifo_time = HZ/2;
if (!timeout || timeout > fifo_time)
timeout = fifo_time;
/*
* Account for the number of bytes in the UART
* transmitter FIFO plus any byte being shifted out.
*/
uartp = (volatile unsigned char *) info->addr;
for (;;) {
fifo_cnt = (uartp[MCFUART_UTF] & MCFUART_UTF_TXB);
if ((uartp[MCFUART_USR] & (MCFUART_USR_TXREADY|
MCFUART_USR_TXEMPTY)) ==
MCFUART_USR_TXREADY)
fifo_cnt++;
if (fifo_cnt == 0)
break;
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(char_time);
if (signal_pending(current))
break;
if (timeout && time_after(jiffies, orig_jiffies + timeout))
break;
}
#else
/*
* For the other coldfire models, assume all data has been sent
*/
#endif
}
/* /*
* mcfrs_hangup() --- called by tty_hangup() when a hangup is signaled. * mcfrs_hangup() --- called by tty_hangup() when a hangup is signaled.
*/ */
...@@ -1413,7 +1503,7 @@ static void mcfrs_irqinit(struct mcf_serial *info) ...@@ -1413,7 +1503,7 @@ static void mcfrs_irqinit(struct mcf_serial *info)
volatile unsigned long *portp; volatile unsigned long *portp;
volatile unsigned char *uartp; volatile unsigned char *uartp;
uartp = (volatile unsigned char *) info->addr; uartp = info->addr;
icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR2); icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR2);
switch (info->line) { switch (info->line) {
...@@ -1438,7 +1528,7 @@ static void mcfrs_irqinit(struct mcf_serial *info) ...@@ -1438,7 +1528,7 @@ static void mcfrs_irqinit(struct mcf_serial *info)
volatile unsigned char *icrp, *uartp; volatile unsigned char *icrp, *uartp;
volatile unsigned long *imrp; volatile unsigned long *imrp;
uartp = (volatile unsigned char *) info->addr; uartp = info->addr;
icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 + icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 +
MCFINTC_ICR0 + MCFINT_UART0 + info->line); MCFINTC_ICR0 + MCFINT_UART0 + info->line);
...@@ -1469,7 +1559,7 @@ static void mcfrs_irqinit(struct mcf_serial *info) ...@@ -1469,7 +1559,7 @@ static void mcfrs_irqinit(struct mcf_serial *info)
return; return;
} }
uartp = (volatile unsigned char *) info->addr; uartp = info->addr;
uartp[MCFUART_UIVR] = info->irq; uartp[MCFUART_UIVR] = info->irq;
#endif #endif
...@@ -1503,7 +1593,7 @@ int mcfrs_readproc(char *page, char **start, off_t off, int count, ...@@ -1503,7 +1593,7 @@ int mcfrs_readproc(char *page, char **start, off_t off, int count,
for (i = 0; (i < NR_PORTS); i++) { for (i = 0; (i < NR_PORTS); i++) {
info = &mcfrs_table[i]; info = &mcfrs_table[i];
len += sprintf((page + len), "%d: port:%x irq=%d baud:%d ", len += sprintf((page + len), "%d: port:%x irq=%d baud:%d ",
i, info->addr, info->irq, info->baud); i, (unsigned int) info->addr, info->irq, info->baud);
if (info->stats.rx || info->stats.tx) if (info->stats.rx || info->stats.tx)
len += sprintf((page + len), "tx:%d rx:%d ", len += sprintf((page + len), "tx:%d rx:%d ",
info->stats.tx, info->stats.rx); info->stats.tx, info->stats.rx);
...@@ -1562,6 +1652,7 @@ static struct tty_operations mcfrs_ops = { ...@@ -1562,6 +1652,7 @@ static struct tty_operations mcfrs_ops = {
.start = mcfrs_start, .start = mcfrs_start,
.hangup = mcfrs_hangup, .hangup = mcfrs_hangup,
.read_proc = mcfrs_readproc, .read_proc = mcfrs_readproc,
.wait_until_sent = mcfrs_wait_until_sent,
.tiocmget = mcfrs_tiocmget, .tiocmget = mcfrs_tiocmget,
.tiocmset = mcfrs_tiocmset, .tiocmset = mcfrs_tiocmset,
}; };
...@@ -1590,7 +1681,9 @@ mcfrs_init(void) ...@@ -1590,7 +1681,9 @@ mcfrs_init(void)
show_serial_version(); show_serial_version();
/* Initialize the tty_driver structure */ /* Initialize the tty_driver structure */
mcfrs_serial_driver->owner = THIS_MODULE;
mcfrs_serial_driver->name = "ttyS"; mcfrs_serial_driver->name = "ttyS";
mcfrs_serial_driver->devfs_name = "ttys/";
mcfrs_serial_driver->driver_name = "serial"; mcfrs_serial_driver->driver_name = "serial";
mcfrs_serial_driver->major = TTY_MAJOR; mcfrs_serial_driver->major = TTY_MAJOR;
mcfrs_serial_driver->minor_start = 64; mcfrs_serial_driver->minor_start = 64;
...@@ -1635,7 +1728,8 @@ mcfrs_init(void) ...@@ -1635,7 +1728,8 @@ mcfrs_init(void)
mcfrs_setsignals(info, 0, 0); mcfrs_setsignals(info, 0, 0);
mcfrs_irqinit(info); mcfrs_irqinit(info);
printk("ttyS%d at 0x%04x (irq = %d)", info->line, info->addr, info->irq); printk("ttyS%d at 0x%04x (irq = %d)", info->line,
(unsigned int) info->addr, info->irq);
printk(" is a builtin ColdFire UART\n"); printk(" is a builtin ColdFire UART\n");
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment