📄 serial_netarm.c
字号:
retval = startup(info); if (retval) { MOD_DEC_USE_COUNT; return retval; } retval = block_til_ready(tty, filp, info); if (retval) {#ifdef SERIAL_DEBUG_OPEN printk("rs_open returning after block_til_ready with %d\n", retval);#endif MOD_DEC_USE_COUNT; return retval; } if ((info->state->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { if (tty->driver.subtype == SERIAL_TYPE_NORMAL) *tty->termios = info->state->normal_termios; else *tty->termios = info->state->callout_termios; change_speed(info, 0); }#ifdef CONFIG_SERIAL_NETARM_CONSOLE if (sercons.cflag && sercons.index == line) { tty->termios->c_cflag = sercons.cflag; sercons.cflag = 0; change_speed(info, 0); }#endif info->session = current->session; info->pgrp = current->pgrp;#ifdef SERIAL_DEBUG_OPEN printk("rs_open ttyS%d successful\n", info->line);#endif return 0;}/*==================================================================== Support for /proc/netarm-serial */#ifdef CONFIG_PROC_FSstatic struct proc_dir_entry *proc_nas;static inline intline_info(char *buf, struct serial_state *state){ char stat_buf[30]; int ret; unsigned long flags, status, control; netarm_serial_channel_t *regs; ret = sprintf(buf, "%d: NetARM SER port:%lX irq:%d", state->line, state->port, state->irq); if (!state->port || (state->type == PORT_UNKNOWN)) { ret += sprintf(buf+ret, "\n"); return ret; } /* * Figure out the current RS-232 lines */ regs = (netarm_serial_channel_t *) state->iomem_base; save_flags(flags); cli(); status = regs->status_a; control = regs->ctrl_a; restore_flags(flags); stat_buf[0] = 0; stat_buf[1] = 0; if (control & NETARM_SER_CTLA_RTS_EN) strcat(stat_buf, "|RTS"); if (status & NETARM_SER_STATA_CTS) strcat(stat_buf, "|CTS"); if (control & NETARM_SER_CTLA_DTR_EN) strcat(stat_buf, "|DTR"); if (status & NETARM_SER_STATA_DSR) strcat(stat_buf, "|DSR"); if (status & NETARM_SER_STATA_DCD) strcat(stat_buf, "|CD"); if (status & NETARM_SER_STATA_RI) strcat(stat_buf, "|RI"); ret += sprintf(buf+ret, " tx:%d rx:%d", state->icount.tx, state->icount.rx); if (state->icount.frame) ret += sprintf(buf+ret, " fe:%d", state->icount.frame); if (state->icount.parity) ret += sprintf(buf+ret, " pe:%d", state->icount.parity); if (state->icount.brk) ret += sprintf(buf+ret, " brk:%d", state->icount.brk); if (state->icount.overrun) ret += sprintf(buf+ret, " oe:%d", state->icount.overrun); /* * Last thing is the RS-232 status lines */ ret += sprintf(buf+ret, " %s\n", stat_buf+1); return ret;}intnas_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ int i, len = 0, l; off_t begin = 0; len += sprintf(page, "serinfo:1.0 driver:%s%s revision:%s\n", serial_version, LOCAL_VERSTRING, serial_revdate); for (i = 0; i < NR_NAS_PORTS && len < 4000; i++) { l = line_info(page + len, &rs_table[i]); len += l; if (len+begin > off+count) goto done; if (len+begin < off) { begin += len; len = 0; } } *eof = 1;done: if (off >= len+begin) return 0; *start = page + (off-begin); return ((count < begin+len-off) ? count : begin+len-off);}#endif/* end of proc support routines *//* * --------------------------------------------------------------------- * rs_init() and friends * * rs_init() is called at boot-time to initialize the serial driver. * --------------------------------------------------------------------- *//* * This routine prints out the appropriate serial driver version * number, and identifies which options were configured into this * driver. */static char serial_options[] __initdata =#ifdef CONFIG_SERIAL_NETARM_CONSOLE " CONSOLE"#define SERIAL_OPT#endif#ifdef SERIAL_OPT " enabled\n";#else " no serial options enabled\n";#endif#undef SERIAL_OPTstatic _INLINE_ voidshow_serial_version(void){ printk(KERN_INFO "%s version %s%s (%s) with%s", serial_name, serial_version, LOCAL_VERSTRING, serial_revdate, serial_options);}/* * This routine is called by rs_init() to initialize a specific serial * port. It determines what type of UART chip this serial port is * using: 8250, 16450, 16550, 16550A. * In the NetARM case, we already know what's there. */static voidautoconfig(struct serial_state * state){ struct netarm_async_struct *info, scr_info; unsigned long flags; if (!CONFIGURED_SERIAL_PORT(state)) return; state->type = PORT_NETARM; info = &scr_info; /* This is just for serial_{in,out} */ info->magic = SERIAL_MAGIC; info->state = state; info->port = state->port; info->flags = state->flags; info->io_type = state->io_type; info->registers = (netarm_serial_channel_t *) state->iomem_base; save_flags(flags); cli(); /* Reset FIFO */ info->registers->status_a = NETARM_SER_STATA_CLR_ALL; info->SCSRA = 0; restore_flags(flags);}int register_serial(struct serial_struct *req);void unregister_serial(int line);#if (LINUX_VERSION_CODE > 0x20100)EXPORT_SYMBOL(register_serial);EXPORT_SYMBOL(unregister_serial);#elsestatic struct symbol_table serial_syms = {#include <linux/symtab_begin.h> X(register_serial), X(unregister_serial),#include <linux/symtab_end.h>};#endif/* * The serial driver boot-time initialization code */static int __initrs_init(void){ int i; struct serial_state * state; init_bh(SERIAL_BH, do_serial_bh); show_serial_version(); /* Initialize the tty_driver structure */ memset(&serial_driver, 0, sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC;#if (LINUX_VERSION_CODE > 0x20100) serial_driver.driver_name = "NetARM serial";#endif#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) serial_driver.name = "tts/%d";#else serial_driver.name = "ttyS";#endif serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64 + SERIAL_DEV_OFFSET; serial_driver.num = NR_NAS_PORTS; serial_driver.type = TTY_DRIVER_TYPE_SERIAL; serial_driver.subtype = SERIAL_TYPE_NORMAL; serial_driver.init_termios = tty_std_termios; serial_driver.init_termios.c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; serial_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS; serial_driver.refcount = &serial_refcount; serial_driver.table = serial_table; serial_driver.termios = serial_termios; serial_driver.termios_locked = serial_termios_locked; serial_driver.open = rs_open; serial_driver.close = rs_close; serial_driver.write = rs_write; serial_driver.put_char = rs_put_char; serial_driver.flush_chars = rs_flush_chars; serial_driver.write_room = rs_write_room; serial_driver.chars_in_buffer = rs_chars_in_buffer; serial_driver.flush_buffer = rs_flush_buffer; serial_driver.ioctl = rs_ioctl; serial_driver.throttle = rs_throttle; serial_driver.unthrottle = rs_unthrottle; serial_driver.set_termios = rs_set_termios; serial_driver.stop = rs_stop; serial_driver.start = rs_start; serial_driver.hangup = rs_hangup; serial_driver.break_ctl = rs_break; serial_driver.send_xchar = rs_send_xchar; serial_driver.wait_until_sent = rs_wait_until_sent; serial_driver.read_proc = nas_read_proc; /* * The callout device is just like normal device except for * major number and the subtype code. */ callout_driver = serial_driver;#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) callout_driver.name = "cua/%d";#else callout_driver.name = "cua";#endif callout_driver.major = TTYAUX_MAJOR; callout_driver.subtype = SERIAL_TYPE_CALLOUT; callout_driver.read_proc = 0; callout_driver.proc_entry = 0; if (tty_register_driver(&serial_driver)) panic("Couldn't register serial driver\n"); if (tty_register_driver(&callout_driver)) panic("Couldn't register callout driver\n"); for (i = 0, state = rs_table; i < NR_NAS_PORTS; i++,state++) { state->magic = SSTATE_MAGIC; state->line = i; state->type = PORT_NETARM; state->xmit_fifo_size = NETARM_SER_FIFO_SIZE; state->custom_divisor = 0; state->close_delay = 5*HZ/10; state->closing_wait = 30*HZ; state->callout_termios = callout_driver.init_termios; state->normal_termios = serial_driver.init_termios; state->icount.cts = state->icount.dsr = state->icount.rng = state->icount.dcd = 0; state->icount.rx = state->icount.tx = 0; state->icount.frame = state->icount.parity = 0; state->icount.overrun = state->icount.brk = 0; if (i == 0) state->irq = IRQ_SER1_RX; else state->irq = IRQ_SER2_RX; state->io_type = SERIAL_IO_MEM;/* no need to call request_region if (state->port && check_region(state->port,8)) continue;*/ if (state->flags & ASYNC_BOOT_AUTOCONF) autoconfig(state); printk(KERN_INFO "ttyS%02d at 0x%04lx (irq = %d) is a NetARM\n", state->line + SERIAL_DEV_OFFSET, state->port, state->irq ); tty_register_devfs(&serial_driver, 0, serial_driver.minor_start + state->line); tty_register_devfs(&callout_driver, 0, callout_driver.minor_start + state->line); } nas_interrupts_init();#ifdef CONFIG_PROC_FS if ((proc_nas = create_proc_entry( "netarm-serial", 0, 0 ))) proc_nas->read_proc = nas_read_proc;#endif return 0;}static void __exitrs_fini(void) { unsigned long flags; int e1, e2; int i; /* printk("Unloading %s: version %s\n", serial_name, serial_version); */ del_timer_sync(&serial_timer); save_flags(flags); cli(); remove_bh(SERIAL_BH); if ((e1 = tty_unregister_driver(&serial_driver))) printk("serial: failed to unregister serial driver (%d)\n", e1); if ((e2 = tty_unregister_driver(&callout_driver))) printk("serial: failed to unregister callout driver (%d)\n", e2); restore_flags(flags);/* for (i = 0; i < NR_NAS_PORTS; i++) { if ((rs_table[i].type != PORT_UNKNOWN) && rs_table[i].port) { release_region(rs_table[i].port, 8); } }*/ if (tmp_buf) { unsigned long pg = (unsigned long) tmp_buf; tmp_buf = NULL; free_page(pg); }}module_init(rs_init);module_exit(rs_fini);MODULE_DESCRIPTION("NetARM serial driver");MODULE_AUTHOR("Rolf Peukert <peukert@imms.de>");/* * ------------------------------------------------------------ * Serial console driver * ------------------------------------------------------------ */#ifdef CONFIG_SERIAL_NETARM_CONSOLE#define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)static struct netarm_async_struct async_sercons;/* * Wait for transmitter & holding register to empty */static inline voidwait_for_xmitr(struct netarm_async_struct *info){ unsigned int status, tmout = 1000000; do { status = info->registers->status_a; if (status & NETARM_SER_STATA_RX_BRK) lsr_break_flag = NETARM_SER_STATA_RX_BRK; if (--tmout == 0) break; } while ((status & NETARM_SER_STATA_TX_DMAEN) == 0); /* This waits until transmitter has finished all characters in fifo. FIXME: Waiting for the transmit holding register to empty (checking NETARM_SER_STATA_TX_FULL) doesn't seem to work. */ /* Wait for flow control if necessary */ if (info->flags & ASYNC_CONS_FLOW) { tmout = 1000000; while (--tmout && \ (info->registers->status_a & NETARM_SER_STATA_CTS) == 0) {} }}/* * Print a string to the serial port trying not to disturb * any possible real use of the port... * * The console_lock must be held when we get here. */static voidserial_console_write(struct console *co, const char *s, unsigned count){ static struct netarm_async_struct *info = &async_sercons; volatile netarm_serial_channel_t *regs; unsigned long ier; volatile unsigned long *ser_port_fifo; unsigned long *bPtr = (unsigned long *)s; unsigned char *zPtr = (unsigned char *)s; unsigned long ctmp; int scount; /* * First save the IER then disable the interrupts */ regs = info->registers; ier = regs->ctrl_a; regs->ctrl_a = ier & ~(NETARM_SER_CTLA_IE_RX_ALL | NETARM_SER_CTLA_IE_TX_ALL); /* * Now, do all characters, add CR to every LF */ ser_port_fifo = (volatile unsigned long *) &(regs->fifo); zPtr = (unsigned char *)bPtr; while ( count > 0 ) { ctmp = 0 ; scount = 0 ; while ( ( count > 0 ) && ( scount < 4 ) ) { ctmp += *zPtr << ( scount << 3 ) ; if (*zPtr == '\n') { if ( scount < 3 ) { scount++; ctmp += '\r' << (scount << 3) ; } else { NAS_TX_WAIT_RDY(regs); *ser_port_fifo = ctmp; scount = 0 ; ctmp = '\r' ; } } zPtr++; count -- ; scount ++ ; } NAS_TX_WAIT_RDY(regs); *ser_port_fifo = ctmp; } /* * Finally, Wait for transmitter & holding register to empty * and
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -