#include <linux/serialP.h>
#include <linux/console.h>
#include <linux/init.h>
+#include <linux/bitops.h>
+#include <linux/delay.h>
#include <asm/io.h>
#include <asm/irq.h>
#include <asm/system.h>
-#include <asm/segment.h>
#include <asm/semaphore.h>
-#include <asm/bitops.h>
#include <asm/delay.h>
#include <asm/coldfire.h>
#include <asm/mcfsim.h>
* keep going. Perhaps one day the cflag settings for the
* console can be used instead.
*/
-#if defined(CONFIG_ARNEWSH) || defined(CONFIG_MOTOROLA) || defined(CONFIG_senTec)
+#if defined(CONFIG_HW_FEITH)
+#define CONSOLE_BAUD_RATE 38400
+#define DEFAULT_CBAUD B38400
+#elif defined(CONFIG_MOD5272) || defined(CONFIG_M5208EVB) || defined(CONFIG_M5329EVB)
+#define CONSOLE_BAUD_RATE 115200
+#define DEFAULT_CBAUD B115200
+#elif defined(CONFIG_ARNEWSH) || defined(CONFIG_FREESCALE) || \
+ defined(CONFIG_senTec) || defined(CONFIG_SNEHA) || defined(CONFIG_AVNET)
#define CONSOLE_BAUD_RATE 19200
#define DEFAULT_CBAUD B19200
#endif
#undef SERIAL_DEBUG_OPEN
#undef SERIAL_DEBUG_FLOW
-#ifdef CONFIG_M5282
-#define IRQBASE 77
+#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
+ defined(CONFIG_M520x) || defined(CONFIG_M532x)
+#define IRQBASE (MCFINT_VECBASE+MCFINT_UART0)
#else
#define IRQBASE 73
#endif
#endif
-/*
- * tmp_buf is used as a temporary buffer by serial_write. We need to
- * lock it in case the copy_from_user blocks while swapping in a page,
- * and some other program tries to do a serial write at the same time.
- * Since the lock will only come under contention when the system is
- * swapping and available memory is low, it makes sense to share one
- * buffer across all the serial ports, since it significantly saves
- * memory if large numbers of serial ports are open.
- */
-static unsigned char mcfrs_tmp_buf[4096]; /* This is cheating */
-static DECLARE_MUTEX(mcfrs_tmp_buf_sem);
-
/*
* Forware declarations...
*/
{
volatile unsigned char *uartp;
struct tty_struct *tty = info->tty;
- unsigned char status, ch;
+ unsigned char status, ch, flag;
if (!tty)
return;
uartp = info->addr;
while ((status = uartp[MCFUART_USR]) & MCFUART_USR_RXREADY) {
-
- if (tty->flip.count >= TTY_FLIPBUF_SIZE)
- break;
-
ch = uartp[MCFUART_URB];
info->stats.rx++;
}
#endif
- tty->flip.count++;
- if (status & MCFUART_USR_RXERR)
+ flag = TTY_NORMAL;
+ if (status & MCFUART_USR_RXERR) {
uartp[MCFUART_UCR] = MCFUART_UCR_CMDRESETERR;
- if (status & MCFUART_USR_RXBREAK) {
- info->stats.rxbreak++;
- *tty->flip.flag_buf_ptr++ = TTY_BREAK;
- } else if (status & MCFUART_USR_RXPARITY) {
- info->stats.rxparity++;
- *tty->flip.flag_buf_ptr++ = TTY_PARITY;
- } else if (status & MCFUART_USR_RXOVERRUN) {
- info->stats.rxoverrun++;
- *tty->flip.flag_buf_ptr++ = TTY_OVERRUN;
- } else if (status & MCFUART_USR_RXFRAMING) {
- info->stats.rxframing++;
- *tty->flip.flag_buf_ptr++ = TTY_FRAME;
- } else {
- *tty->flip.flag_buf_ptr++ = 0;
+ if (status & MCFUART_USR_RXBREAK) {
+ info->stats.rxbreak++;
+ flag = TTY_BREAK;
+ } else if (status & MCFUART_USR_RXPARITY) {
+ info->stats.rxparity++;
+ flag = TTY_PARITY;
+ } else if (status & MCFUART_USR_RXOVERRUN) {
+ info->stats.rxoverrun++;
+ flag = TTY_OVERRUN;
+ } else if (status & MCFUART_USR_RXFRAMING) {
+ info->stats.rxframing++;
+ flag = TTY_FRAME;
+ }
}
- *tty->flip.char_buf_ptr++ = ch;
+ tty_insert_flip_char(tty, ch, flag);
}
-
- schedule_work(&tty->flip.work);
+ tty_schedule_flip(tty);
return;
}
tty = info->tty;
if (!tty)
return;
-
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup)(tty);
- wake_up_interruptible(&tty->write_wait);
+ tty_wakeup(tty);
}
if (serial_paranoia_check(info, tty->name, "mcfrs_flush_chars"))
return;
+ uartp = (volatile unsigned char *) info->addr;
+
+ /*
+ * re-enable receiver interrupt
+ */
+ local_irq_save(flags);
+ if ((!(info->imr & MCFUART_UIR_RXREADY)) &&
+ (info->flags & ASYNC_INITIALIZED) ) {
+ info->imr |= MCFUART_UIR_RXREADY;
+ uartp[MCFUART_UIMR] = info->imr;
+ }
+ local_irq_restore(flags);
+
if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
!info->xmit_buf)
return;
/* Enable transmitter */
local_irq_save(flags);
- uartp = info->addr;
info->imr |= MCFUART_UIR_TXREADY;
uartp[MCFUART_UIMR] = info->imr;
local_irq_restore(flags);
}
-static int mcfrs_write(struct tty_struct * tty, int from_user,
+static int mcfrs_write(struct tty_struct * tty,
const unsigned char *buf, int count)
{
volatile unsigned char *uartp;
int c, total = 0;
#if 0
- printk("%s(%d): mcfrs_write(tty=%x,from_user=%d,buf=%x,count=%d)\n",
- __FILE__, __LINE__, (int)tty, from_user, (int)buf, count);
+ printk("%s(%d): mcfrs_write(tty=%x,buf=%x,count=%d)\n",
+ __FILE__, __LINE__, (int)tty, (int)buf, count);
#endif
if (serial_paranoia_check(info, tty->name, "mcfrs_write"))
if (c <= 0)
break;
- if (from_user) {
- down(&mcfrs_tmp_buf_sem);
- if (copy_from_user(mcfrs_tmp_buf, buf, c))
- return -EFAULT;
-
- local_irq_disable();
- c = min(c, (int) min(((int)SERIAL_XMIT_SIZE) - info->xmit_cnt - 1,
- ((int)SERIAL_XMIT_SIZE) - info->xmit_head));
- local_irq_restore(flags);
- memcpy(info->xmit_buf + info->xmit_head, mcfrs_tmp_buf, c);
- up(&mcfrs_tmp_buf_sem);
- } 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_cnt = info->xmit_head = info->xmit_tail = 0;
local_irq_restore(flags);
- wake_up_interruptible(&tty->write_wait);
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup)(tty);
+ tty_wakeup(tty);
}
/*
if (!info->addr)
return;
- current->state = TASK_INTERRUPTIBLE;
+ set_current_state(TASK_INTERRUPTIBLE);
uartp = info->addr;
local_irq_save(flags);
uartp[MCFUART_UCR] = MCFUART_UCR_CMDBREAKSTART;
- schedule_timeout(jiffies + duration);
+ schedule_timeout(duration);
uartp[MCFUART_UCR] = MCFUART_UCR_CMDBREAKSTOP;
local_irq_restore(flags);
}
(arg ? CLOCAL : 0));
return 0;
case TIOCGSERIAL:
- error = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(struct serial_struct));
- if (error)
- return error;
- return get_serial_info(info,
+ if (access_ok(VERIFY_WRITE, (void *) arg,
+ sizeof(struct serial_struct)))
+ return get_serial_info(info,
(struct serial_struct *) arg);
+ return -EFAULT;
case TIOCSSERIAL:
return set_serial_info(info,
(struct serial_struct *) arg);
case TIOCSERGETLSR: /* Get line status register */
- error = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(unsigned int));
- if (error)
- return error;
- else
- return get_lsr_info(info, (unsigned int *) arg);
-
+ if (access_ok(VERIFY_WRITE, (void *) arg,
+ sizeof(unsigned int)))
+ return get_lsr_info(info, (unsigned int *) arg);
+ return -EFAULT;
case TIOCSERGSTRUCT:
error = copy_to_user((struct mcf_serial *) arg,
info, sizeof(struct mcf_serial));
shutdown(info);
if (tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
- if (tty->ldisc.flush_buffer)
- tty->ldisc.flush_buffer(tty);
+ tty_ldisc_flush(tty);
+
tty->closing = 0;
info->event = 0;
info->tty = 0;
+#if 0
if (tty->ldisc.num != ldiscs[N_TTY].num) {
if (tty->ldisc.close)
(tty->ldisc.close)(tty);
if (tty->ldisc.open)
(tty->ldisc.open)(tty);
}
+#endif
if (info->blocked_open) {
if (info->close_delay) {
- current->state = TASK_INTERRUPTIBLE;
- schedule_timeout(info->close_delay);
+ msleep_interruptible(jiffies_to_msecs(info->close_delay));
}
wake_up_interruptible(&info->open_wait);
}
fifo_cnt++;
if (fifo_cnt == 0)
break;
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(char_time);
+ msleep_interruptible(jiffies_to_msecs(char_time));
if (signal_pending(current))
break;
if (timeout && time_after(jiffies, orig_jiffies + timeout))
*portp = (*portp & ~0x000000ff) | 0x00000055;
portp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_PDCNT);
*portp = (*portp & ~0x000003fc) | 0x000002a8;
-#elif defined(CONFIG_M5282)
+#elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
+ volatile unsigned char *icrp, *uartp;
+ volatile unsigned long *imrp;
+
+ uartp = info->addr;
+
+ icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 +
+ MCFINTC_ICR0 + MCFINT_UART0 + info->line);
+ *icrp = 0x30 + info->line; /* level 6, line based priority */
+
+ imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 +
+ MCFINTC_IMRL);
+ *imrp &= ~((1 << (info->irq - MCFINT_VECBASE)) | 1);
+#elif defined(CONFIG_M520x)
volatile unsigned char *icrp, *uartp;
volatile unsigned long *imrp;
icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 +
MCFINTC_ICR0 + MCFINT_UART0 + info->line);
- *icrp = 0x33; /* UART0 with level 6, priority 3 */
+ *icrp = 0x03;
imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 +
MCFINTC_IMRL);
- *imrp &= ~((1 << (info->irq - 64)) | 1);
+ *imrp &= ~((1 << (info->irq - MCFINT_VECBASE)) | 1);
+ if (info->line < 2) {
+ unsigned short *uart_par;
+ uart_par = (unsigned short *)(MCF_IPSBAR + MCF_GPIO_PAR_UART);
+ if (info->line == 0)
+ *uart_par |= MCF_GPIO_PAR_UART_PAR_UTXD0
+ | MCF_GPIO_PAR_UART_PAR_URXD0;
+ else if (info->line == 1)
+ *uart_par |= MCF_GPIO_PAR_UART_PAR_UTXD1
+ | MCF_GPIO_PAR_UART_PAR_URXD1;
+ } else if (info->line == 2) {
+ unsigned char *feci2c_par;
+ feci2c_par = (unsigned char *)(MCF_IPSBAR + MCF_GPIO_PAR_FECI2C);
+ *feci2c_par &= ~0x0F;
+ *feci2c_par |= MCF_GPIO_PAR_FECI2C_PAR_SCL_UTXD2
+ | MCF_GPIO_PAR_FECI2C_PAR_SDA_URXD2;
+ }
+#elif defined(CONFIG_M532x)
+ volatile unsigned char *uartp;
+ uartp = info->addr;
+ switch (info->line) {
+ case 0:
+ MCF_INTC0_ICR26 = 0x3;
+ MCF_INTC0_CIMR = 26;
+ /* GPIO initialization */
+ MCF_GPIO_PAR_UART |= 0x000F;
+ break;
+ case 1:
+ MCF_INTC0_ICR27 = 0x3;
+ MCF_INTC0_CIMR = 27;
+ /* GPIO initialization */
+ MCF_GPIO_PAR_UART |= 0x0FF0;
+ break;
+ case 2:
+ MCF_INTC0_ICR28 = 0x3;
+ MCF_INTC0_CIMR = 28;
+ /* GPIOs also must be initalized, depends on board */
+ break;
+ }
#else
volatile unsigned char *icrp, *uartp;
/* Clear mask, so no surprise interrupts. */
uartp[MCFUART_UIMR] = 0;
- if (request_irq(info->irq, mcfrs_interrupt, SA_INTERRUPT,
+ if (request_irq(info->irq, mcfrs_interrupt, IRQF_DISABLED,
"ColdFire UART", NULL)) {
printk("MCFRS: Unable to attach ColdFire UART %d interrupt "
"vector=%d\n", info->line, info->irq);
/* Initialize the tty_driver structure */
mcfrs_serial_driver->owner = THIS_MODULE;
mcfrs_serial_driver->name = "ttyS";
- mcfrs_serial_driver->devfs_name = "ttys/";
mcfrs_serial_driver->driver_name = "serial";
mcfrs_serial_driver->major = TTY_MAJOR;
mcfrs_serial_driver->minor_start = 64;