X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fserial%2Fmcfserial.c;h=832abd3c4706ddabe8a3a6c07d9caf0e2b8e139f;hb=16c70f8c1b54b61c3b951b6fb220df250fe09b32;hp=7f1b9ee7e03fe4240c7101cbf4607858f294d199;hpb=c7b5ebbddf7bcd3651947760f423e3783bbe6573;p=linux-2.6.git diff --git a/drivers/serial/mcfserial.c b/drivers/serial/mcfserial.c index 7f1b9ee7e..832abd3c4 100644 --- a/drivers/serial/mcfserial.c +++ b/drivers/serial/mcfserial.c @@ -34,13 +34,13 @@ #include #include #include +#include +#include #include #include #include -#include #include -#include #include #include #include @@ -57,7 +57,14 @@ struct timer_list mcfrs_timer_struct; * 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 @@ -85,8 +92,9 @@ static struct tty_driver *mcfrs_serial_driver; #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 @@ -131,18 +139,6 @@ extern int magic_sysrq_key(int ch); #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... */ @@ -313,7 +309,7 @@ static inline void receive_chars(struct mcf_serial *info) { volatile unsigned char *uartp; struct tty_struct *tty = info->tty; - unsigned char status, ch; + unsigned char status, ch, flag; if (!tty) return; @@ -321,10 +317,6 @@ static inline void receive_chars(struct mcf_serial *info) 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++; @@ -335,28 +327,26 @@ static inline void receive_chars(struct mcf_serial *info) } #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; } @@ -723,19 +713,31 @@ static void mcfrs_flush_chars(struct tty_struct *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; @@ -744,8 +746,8 @@ static int mcfrs_write(struct tty_struct * tty, int from_user, 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")) @@ -764,19 +766,7 @@ static int mcfrs_write(struct tty_struct * tty, int from_user, 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); @@ -990,12 +980,12 @@ static void send_break( struct mcf_serial * info, int duration) 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); } @@ -1082,23 +1072,19 @@ static int mcfrs_ioctl(struct tty_struct *tty, struct file * file, (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)); @@ -1242,8 +1228,7 @@ static void mcfrs_close(struct tty_struct *tty, struct file * filp) #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); } @@ -1308,8 +1293,7 @@ mcfrs_wait_until_sent(struct tty_struct *tty, int timeout) 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)) @@ -1519,7 +1503,7 @@ static void mcfrs_irqinit(struct mcf_serial *info) *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; @@ -1527,11 +1511,62 @@ static void mcfrs_irqinit(struct mcf_serial *info) icrp = (volatile unsigned char *) (MCF_MBAR + MCFICM_INTC0 + MCFINTC_ICR0 + MCFINT_UART0 + info->line); - *icrp = 0x33; /* UART0 with level 6, priority 3 */ + *icrp = 0x30 + info->line; /* level 6, line based priority */ imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 + MCFINTC_IMRL); - *imrp &= ~((1 << (info->irq - 64)) | 1); + *imrp &= ~((1 << (info->irq - MCFINT_VECBASE)) | 1); +#elif defined(CONFIG_M520x) + 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 = 0x03; + + imrp = (volatile unsigned long *) (MCF_MBAR + MCFICM_INTC0 + + MCFINTC_IMRL); + *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; @@ -1561,7 +1596,7 @@ static void mcfrs_irqinit(struct mcf_serial *info) /* 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); @@ -1678,7 +1713,6 @@ mcfrs_init(void) /* 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;