#if defined(CONFIG_SERIAL_AVM_8250_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) #define SUPPORT_SYSRQ #endif #if defined(CONFIG_SERIAL_8250) #error CONFIG Fehler: entweder CONFIG_SERIAL_8250 oder CONFIG_SERIAL_AVM_8250 #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #if defined (CONFIG_MIPS_UR8) #include #include #else #include #endif /*--- #define DEBUG_UART_AVM ---*/ #include "serial_avm_8250.h" #if defined(DEBUG_UART_AVM) #define UART_PRINTK(...) printk(__VA_ARGS__) #else #define UART_PRINTK(...) #endif #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 32) #define UART_INFO info #define S_UART_INFO struct uart_info #else #define UART_INFO state #define S_UART_INFO struct uart_state #endif #if defined (CONFIG_MIPS) #define ASM_MIPS_ONLY(x) asm(x) #else #define ASM_MIPS_ONLY(x) #endif #define SERIAL_UART_AVM_NAME "ttyS" #define SERIAL_UART_AVM_MAJOR TTY_MAJOR #define SERIAL_UART_AVM_MINOR 64 #define tx_enabled(port) ((port)->unused[0]) #define rx_enabled(port) ((port)->unused[1]) #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE) #define PROCFS_NAME "avm_mute" static struct proc_dir_entry *uart_proc_file; #if defined(CONFIG_SERIAL_AVM_8250_CONSOLE_MUTE) static unsigned int avm_serial_mute_flag = 1; /*--- Ausgaben deaktivert ---*/ static unsigned int avm_serial_deaf_flag = 1; /*--- Eingabe deaktivert ---*/ #else /*--- #if defined(CONFIG_SERIAL_AVM_8250_CONSOLE_MUTE) ---*/ static unsigned int avm_serial_mute_flag = 0; /*--- Ausgaben aktivert ---*/ static unsigned int avm_serial_deaf_flag = 0; /*--- Eingabe aktivert ---*/ #endif /*--- #else ---*/ /*--- #if defined(CONFIG_SERIAL_AVM_8250_CONSOLE_MUTE) ---*/ static const char uart_avm_name[] = "Uart AVM 8250"; /* --- die folgenden Dinge werden im architekturspezifischen Teil implementiert bzw. initialisiert --- */ int nr_uart_avm_ports = 0; int avm_console_uart = 0; extern struct uart_port uart_avm_port[]; extern int uart_avm_setup_ports(void); int uart_procfile_write(struct file *file, const char *buf, unsigned long count, void *data); /* --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- --- */ /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void uart_avm_stop_tx(struct uart_port *port) { if (tx_enabled(port)) { struct avm_8250_priv *port_priv_data = port->private_data; #if defined(DEBUG_UART_AVM) port_priv_data->stop_tx_cnt ++; #endif port_priv_data->base->ier &= ~(UART_IER_THRI); /* Disable Transmitter Holding Register Empty Interrupt */ tx_enabled(port) = 0; } } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void uart_avm_start_tx(struct uart_port *port) { if (!tx_enabled(port)) { struct avm_8250_priv *port_priv_data = port->private_data; #if defined(DEBUG_UART_AVM) port_priv_data->start_tx_cnt ++; #endif port_priv_data->base->ier |= UART_IER_THRI; /* Enable Transmitter Holding Register Empty Interrupt */ tx_enabled(port) = 1; } } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void uart_avm_stop_rx(struct uart_port *port) { if (rx_enabled(port)) { struct avm_8250_priv *port_priv_data = port->private_data; port_priv_data->base->ier &= ~(UART_IER_RLSI | UART_IER_RDI); /* 0x04 Disable RX Interrupt */ rx_enabled(port) = 0; } } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void uart_avm_enable_ms(struct uart_port *port) { } /*------------------------------------------------------------------------------------------*\ * IRQ Routine \*------------------------------------------------------------------------------------------*/ void uart_avm_rx_chars(struct uart_port *port , unsigned int *lsrp){ unsigned int lsr = *lsrp; int max_count = 256; struct avm_8250_priv *port_priv_data = port->private_data; struct avm_8250_regs *regs = port_priv_data->base; S_UART_INFO *UART_INFO = port->UART_INFO; struct tty_struct *tty = UART_INFO->port.tty; unsigned int ch = 0; char flag; while ((max_count-- > 0) && (lsr & (UART_LSR_DR | UART_LSR_BI))) { ch = regs->rbr_thr; flag = TTY_NORMAL; port->icount.rx++; if (port_priv_data->is_console && avm_serial_deaf_flag) goto ignore_char; /* * Note that the error handling code is * out of the main execution path */ if (unlikely(lsr & UART_LSR_BRK_ERROR_BITS)) { /* * For statistics only */ if (lsr & UART_LSR_BI) { lsr &= ~(UART_LSR_FE | UART_LSR_PE); port->icount.brk++; /* * We do the SysRQ and SAK checking * here because otherwise the break * may get masked by ignore_status_mask * or read_status_mask. */ if (uart_handle_break(port)) goto ignore_char; } else if (lsr & UART_LSR_PE) port->icount.parity++; else if (lsr & UART_LSR_FE) port->icount.frame++; if (lsr & UART_LSR_OE) port->icount.overrun++; /* * Mask off conditions which should be ignored. */ lsr &= port->read_status_mask; if (lsr & UART_LSR_BI) { flag = TTY_BREAK; } else if (lsr & UART_LSR_PE) flag = TTY_PARITY; else if (lsr & UART_LSR_FE) flag = TTY_FRAME; } if (uart_handle_sysrq_char(port, ch)) goto ignore_char; uart_insert_char(port, lsr, UART_LSR_OE, ch, flag); ignore_char: lsr = port_priv_data->base->lsr; } spin_unlock(port->lock); tty_flip_buffer_push(tty); spin_lock(port->lock); *lsrp = lsr; } void uart_avm_tx_chars(struct uart_port *port ){ struct circ_buf *xmit = &port->UART_INFO->xmit; struct avm_8250_priv *port_priv_data = port->private_data; struct avm_8250_regs *regs = port_priv_data->base; int fifocnt; if (port->x_char) { uart_avm_console_putchar(port, (int)(port->x_char)); port->icount.tx++; port->x_char = 0; return; } if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { uart_avm_stop_tx(port); return; } /* * Constraint: Funktion wird nur aufgerufen wenn fifo komplett leer, * somit passen immer fifosize Zeichen in die Queue */ fifocnt = port->fifosize; while(fifocnt--) { if ( !port_priv_data->is_console || !avm_serial_mute_flag ) { regs->rbr_thr = xmit->buf[xmit->tail]; } xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); port->icount.tx++; if (uart_circ_empty(xmit)) break; } if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) uart_write_wakeup(port); if (uart_circ_empty(xmit)) uart_avm_stop_tx(port); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static irqreturn_t uart_avm_irq(int irq, void *dev_id) { struct uart_port *port = dev_id; struct avm_8250_priv *port_priv_data = port->private_data; unsigned int handled = 0; unsigned int iir; unsigned long flags; spin_lock_irqsave(port->lock, flags); iir = port_priv_data->base->iir_fcr; /* Vorsicht inviers: letztes bit ist '0' falls Interrupt anliegt */ if (!(iir & UART_IIR_NO_INT)) { unsigned int lsr; lsr = port_priv_data->base->lsr; if ( rx_enabled(port) && (lsr & (UART_LSR_DR | UART_LSR_BI))){ uart_avm_rx_chars(port, &lsr); handled = 1; } if ( tx_enabled(port) && (lsr & UART_LSR_THRE)) { /* tx_fifo komplett leer */ uart_avm_tx_chars(port); handled = 1; } } spin_unlock_irqrestore(port->lock, flags); return IRQ_RETVAL(handled); } /*------------------------------------------------------------------------------------------*\ * Ende IRQ Routine \*------------------------------------------------------------------------------------------*/ static unsigned int uart_avm_tx_empty(struct uart_port *port) { struct avm_8250_priv *port_priv_data = port->private_data; struct avm_8250_regs *regs = port_priv_data->base; unsigned long flags; unsigned int lsr; spin_lock_irqsave(port->lock, flags); lsr = regs->lsr; spin_unlock_irqrestore(port->lock, flags); return ((lsr & BOTH_EMPTY) == BOTH_EMPTY ) ? 1 : 0; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static unsigned int uart_avm_get_mctrl(struct uart_port *port) { /* no modem control lines */ return TIOCM_CAR | TIOCM_DSR | TIOCM_CTS; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void uart_avm_set_mctrl(struct uart_port *port, unsigned int mctrl) { /* no modem control - just return */ return; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void uart_avm_break_ctl(struct uart_port *port, int break_state) { /* no way to send a break */ return; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int uart_avm_startup(struct uart_port *port){ int ret = 0; unsigned long flags; unsigned int ier; struct avm_8250_priv *port_priv_data = port->private_data; struct avm_8250_regs *regs = port_priv_data->base; printk("[%s]port %p\n", __FUNCTION__, port); /* block the IRQs */ local_irq_save(flags); /* setup FCR */ regs->iir_fcr = UART_FCR_R_TRIG_11 |UART_FCR_CLEAR_XMIT | UART_FCR_CLEAR_RCVR | UART_FCR_ENABLE_FIFO; /* enable Interrupts */ ier = regs->ier; ier |= (UART_IER_RDI | UART_IER_THRI | UART_IER_RLSI); regs->ier = ier; local_irq_restore(flags); tx_enabled(port) = 1; rx_enabled(port) = 1; ret = request_irq( port->irq, uart_avm_irq, 0, uart_avm_name, port ); UART_PRINTK("[%s] Setup IRQ %d\n", __FUNCTION__, port->irq); return ret; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void uart_avm_shutdown(struct uart_port *port) { unsigned long flags; struct avm_8250_priv *port_priv_data = port->private_data; struct avm_8250_regs *regs = port_priv_data->base; local_irq_save(flags); regs->ier = 0; local_irq_restore(flags); disable_irq( port->irq); free_irq( port->irq, port); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void uart_avm_set_termios(struct uart_port *port, struct ktermios *termios, struct ktermios *old) { unsigned long flags; unsigned int f_size_chg = 1; unsigned int f_baudrate_chg = 1; unsigned int cflag = termios->c_cflag; struct avm_8250_priv *port_priv_data = port->private_data; struct avm_8250_regs *regs; u32 wordsize = 0; u32 baudrate = 0; u32 quot = 1; /* * We don't support modem control lines. */ termios->c_cflag &= ~(HUPCL | CRTSCTS | CMSPAR); termios->c_cflag |= CLOCAL; // only support baudrate change and word length change if ( old ) { if ( (old->c_cflag & CSIZE) == (cflag & CSIZE) ) { f_size_chg = 0; } if ( (old->c_cflag & CBAUD) == (cflag & CBAUD) ) { f_baudrate_chg = 0; } } if ( f_size_chg || f_baudrate_chg ) { regs = port_priv_data->base; if ( f_size_chg ) { switch (cflag & CSIZE) { case CS5: wordsize = UART_LCR_WLEN5; break; case CS6: wordsize = UART_LCR_WLEN6; break; case CS7: wordsize = UART_LCR_WLEN7; break; case CS8: default: wordsize = UART_LCR_WLEN8; break; } } if ( f_baudrate_chg ) { baudrate = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16 ); quot = uart_get_divisor(port, baudrate); if (port->UART_INFO && port->UART_INFO->port.tty) { struct tty_struct *tty = port->UART_INFO->port.tty; tty_encode_baud_rate(tty, baudrate, baudrate); } } spin_lock_irqsave(&port->lock, flags); /* * Update the per-port timeout. */ uart_update_timeout(port, termios->c_cflag, baudrate); if ( f_size_chg ) { unsigned int lcr = regs->lcr; lcr &= ~0x3; lcr |= wordsize; regs->lcr = lcr; } if ( f_baudrate_chg ) { unsigned int dll, dlh; struct avm_8250_regs_dlab *dlab_regs = (struct avm_8250_regs_dlab*)regs; /* hardware in DLAB mode */ regs->lcr |= UART_LCR_DLAB; dll = dlab_regs->dll; dlh = dlab_regs->dlh; /* die unteren 8 bit in dll */ dlab_regs->dll = (quot & 0xFF); /* die oberen 8 bit in dlh */ dlab_regs->dlh = (quot >> 8); regs->lcr &= ~(UART_LCR_DLAB); /* hardware wieder in normal mode */ UART_PRINTK("[%s] old_dll=%d, old_dlh=%d \n", __FUNCTION__, dll, dlh); UART_PRINTK("[%s] baudrate=%d, quot=%d, dll=%d, dlh=%d \n", __FUNCTION__, baudrate, quot, (quot & 0xFF), (quot >> 8)); } spin_unlock_irqrestore(&port->lock, flags); } } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static const char *uart_avm_type(struct uart_port *port) { return port->type == PORT_16550A ? "PORT_16550A" : NULL; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void uart_avm_release_port(struct uart_port *port) { release_mem_region(port->mapbase, sizeof(struct avm_8250_regs)); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int uart_avm_request_port(struct uart_port *port) { return request_mem_region(port->mapbase, sizeof(struct avm_8250_regs), uart_avm_name) != NULL ? 0 : -EBUSY; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void uart_avm_config_port(struct uart_port *port, int flags) { if (flags & UART_CONFIG_TYPE && uart_avm_request_port(port) == 0) port->type = PORT_16550A; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int uart_avm_verify_port(struct uart_port *port, struct serial_struct *ser) { int ret = 0; if (ser->type != PORT_UNKNOWN && ser->type != PORT_16550A) ret = -EINVAL; if (ser->irq != port->irq) ret = -EINVAL; if ( ser->baud_base < 9600 ) ret = -EINVAL; return ret; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static struct uart_ops uart_avm_ops = { .tx_empty = uart_avm_tx_empty, .get_mctrl = uart_avm_get_mctrl, .set_mctrl = uart_avm_set_mctrl, .stop_tx = uart_avm_stop_tx, .start_tx = uart_avm_start_tx, .stop_rx = uart_avm_stop_rx, .enable_ms = uart_avm_enable_ms, .break_ctl = uart_avm_break_ctl, .startup = uart_avm_startup, .shutdown = uart_avm_shutdown, .set_termios = uart_avm_set_termios, .type = uart_avm_type, .release_port = uart_avm_release_port, .request_port = uart_avm_request_port, .config_port = uart_avm_config_port, .verify_port = uart_avm_verify_port, }; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void uart_avm_console_putchar(struct uart_port *port, int ch) { struct avm_8250_priv *port_priv_data = port->private_data; struct avm_8250_regs *regs = port_priv_data->base; unsigned int status, tmout = 10000; if ( !port_priv_data->is_console || !avm_serial_mute_flag ) { regs->rbr_thr = (char)ch; } ASM_MIPS_ONLY("sync"); /* Wait up to 10ms for the character(s) to be sent. */ do { status = regs->lsr; if (--tmout == 0) break; udelay(1); } while ((status & UART_LSR_THRE ) != UART_LSR_THRE ); } #ifdef CONFIG_SERIAL_AVM_8250_CONSOLE /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void uart_avm_console_write(struct console *co, const char *s, unsigned int count) { uart_console_write(&uart_avm_port[avm_console_uart], s, count, uart_avm_console_putchar); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int __init uart_avm_console_setup(struct console *co, char *options) { struct uart_port *port = &uart_avm_port[avm_console_uart]; int baud = 38400; int bits = 8; int parity = 'n'; int flow = 'n'; /* * Check whether an invalid uart number has been specified, and * if so, search for the first available port that does have * console support. */ if (options) uart_parse_options(options, &baud, &parity, &bits, &flow); return uart_set_options(port, co, baud, parity, bits, flow); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static struct uart_driver uart_avm_driver; static struct console uart_avm_console = { .name = SERIAL_UART_AVM_NAME, .write = uart_avm_console_write, .device = uart_console_device, .setup = uart_avm_console_setup, .flags = CON_PRINTBUFFER, .index = -1, .data = &uart_avm_driver, }; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int __init rs_avm_console_init(void) { printk("[%s] (console_init)\n", __FUNCTION__); nr_uart_avm_ports = uart_avm_setup_ports(); uart_avm_post_setup_ports(); register_console(&uart_avm_console); return 0; } console_initcall(rs_avm_console_init); #define UART_AVM_8250_CONSOLE &uart_avm_console #else /*--- #ifdef CONFIG_SERIAL_AVM_8250_CONSOLE ---*/ #define UART_AVM_8250_CONSOLE NULL #endif /*--- #else ---*/ /*--- #ifdef CONFIG_SERIAL_AVM_8250_CONSOLE ---*/ /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static struct uart_driver uart_avm_driver = { .owner = THIS_MODULE, .driver_name = SERIAL_UART_AVM_NAME, .dev_name = SERIAL_UART_AVM_NAME, .major = SERIAL_UART_AVM_MAJOR, .minor = SERIAL_UART_AVM_MINOR, .cons = UART_AVM_8250_CONSOLE, /*--- .nr wird nach uart_avm_setup_ports() aufruf gesetzt ---*/ }; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int __init uart_avm_init(void) { int ret; printk("[%s] (module_init)\n", __FUNCTION__); printk(KERN_INFO "Serial: SERIAL_AVM_8250 driver\n"); nr_uart_avm_ports = uart_avm_setup_ports(); uart_avm_post_setup_ports(); ret = uart_register_driver(&uart_avm_driver); if (ret == 0){ int i; for ( i = 0; i < nr_uart_avm_ports; i++){ uart_add_one_port(&uart_avm_driver, &uart_avm_port[i]); } } uart_proc_file = create_proc_entry(PROCFS_NAME, 0644, NULL); if (uart_proc_file == NULL) { remove_proc_entry(PROCFS_NAME, &proc_root); printk(KERN_ERR "Error: Could not initialize /proc/%s\n", PROCFS_NAME); return -ENOMEM; } uart_proc_file->write_proc = uart_procfile_write; uart_proc_file->owner = THIS_MODULE; uart_proc_file->mode = S_IFREG | S_IWUGO; return ret; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void uart_avm_post_setup_ports(void) { int i; uart_avm_driver.nr = nr_uart_avm_ports; for (i = 0; i < nr_uart_avm_ports; i++) { if ( i >= NR_MAX_UARTS) { printk("[UART AVM] Max Nr. Uartports(%d) ueberschritten: %d\n", NR_MAX_UARTS, i); nr_uart_avm_ports = NR_MAX_UARTS; break; } uart_avm_port[i].type = PORT_16550A; uart_avm_port[i].ops = &uart_avm_ops; uart_avm_port[i].flags = ASYNC_BOOT_AUTOCONF; if ( uart_avm_port[i].private_data == NULL ) { struct avm_8250_priv *priv_data = &(avm_uarts_priv_data[i]); priv_data->base = (struct avm_8250_regs*)(uart_avm_port[i].membase); priv_data->is_console = 0; if ( i == avm_console_uart ){ priv_data->is_console = 1; } uart_avm_port[i].private_data = (char *)priv_data; UART_PRINTK("[%s] setup membase=%#x for uart%d\n",__FUNCTION__, (unsigned int)priv_data->base, i ); } } } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void __exit uart_avm_exit(void) { int i; remove_proc_entry(PROCFS_NAME, &proc_root); for ( i = 0; i < nr_uart_avm_ports; i++){ uart_remove_one_port(&uart_avm_driver, &uart_avm_port[i]); } uart_unregister_driver(&uart_avm_driver); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static int setup_avm_mute_flag(char *p) { if(p) { avm_serial_mute_flag = simple_strtol(p, NULL, 0); } return 0; } __setup("mute=", setup_avm_mute_flag); /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int uart_procfile_write(struct file *file, const char *buf, unsigned long count, void *data) { #define PROCFS_MAX_SIZE sizeof("output-off") static char uart_procfs_buf[PROCFS_MAX_SIZE]; if (count > PROCFS_MAX_SIZE ) { count = PROCFS_MAX_SIZE; } if ( copy_from_user(uart_procfs_buf, buf, count) ) { printk(KERN_ERR "[%s] Fehler: copy_from_user\n", __FUNCTION__); return -EFAULT; } uart_procfs_buf[count-1] = '\0'; /*--- proc liefert \n anstatt \0 ---*/ if(strcmp(uart_procfs_buf, "input-on") == 0) { avm_serial_deaf_flag = 0; } else if(strcmp(uart_procfs_buf, "input-off") == 0) { avm_serial_deaf_flag = 1; } else if(strcmp(uart_procfs_buf, "output-on") == 0) { avm_serial_mute_flag = 0; } else if(strcmp(uart_procfs_buf, "output-off") == 0) { avm_serial_mute_flag = 1; } else { printk(KERN_ERR "[%s] invalid value '%s'. Available options for serial console:\ninput-on\ninput-off\noutput-on\noutput-off\n", __FUNCTION__, uart_procfs_buf); } return count; } module_init(uart_avm_init); module_exit(uart_avm_exit); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("AVM Serial Driver for 8250 16550-Uart");