📄 vacserial.c
字号:
#endif if (retval) return retval; info->flags |= ASYNC_NORMAL_ACTIVE; return 0;}static int get_async_struct(int line, struct async_struct **ret_info){ struct async_struct *info; struct serial_state *sstate; sstate = rs_table + line; sstate->count++; if (sstate->info) { *ret_info = sstate->info; return 0; } info = kmalloc(sizeof(struct async_struct), GFP_KERNEL); if (!info) { sstate->count--; return -ENOMEM; } memset(info, 0, sizeof(struct async_struct)); init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); init_waitqueue_head(&info->delta_msr_wait); info->magic = SERIAL_MAGIC; info->port = sstate->port; info->flags = sstate->flags; info->xmit_fifo_size = sstate->xmit_fifo_size; info->line = line; info->tqueue.routine = do_softint; info->tqueue.data = info; info->state = sstate; if (sstate->info) { kfree(info); *ret_info = sstate->info; return 0; } *ret_info = sstate->info = info; return 0;}/* * This routine is called whenever a serial port is opened. It * enables interrupts for a serial port, linking in its async structure into * the IRQ chain. It also performs the serial-specific * initialization for the tty structure. */static int rs_open(struct tty_struct *tty, struct file * filp){ struct async_struct *info; int retval, line; unsigned long page; MOD_INC_USE_COUNT; line = MINOR(tty->device) - tty->driver.minor_start; if ((line < 0) || (line >= NR_PORTS)) { MOD_DEC_USE_COUNT; return -ENODEV; } retval = get_async_struct(line, &info); if (retval) { MOD_DEC_USE_COUNT; return retval; } tty->driver_data = info; info->tty = tty; if (serial_paranoia_check(info, tty->device, "rs_open")) { /* MOD_DEC_USE_COUNT; "info->tty" will cause this */ return -ENODEV; }#ifdef SERIAL_DEBUG_OPEN baget_printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, info->state->count);#endif info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; if (!tmp_buf) { page = get_free_page(GFP_KERNEL); if (!page) { /* MOD_DEC_USE_COUNT; "info->tty" will cause this */ return -ENOMEM; } if (tmp_buf) free_page(page); else tmp_buf = (unsigned char *) page; } /* * If the port is the middle of closing, bail out now */ if (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { if (info->flags & ASYNC_CLOSING) interruptible_sleep_on(&info->close_wait); /* MOD_DEC_USE_COUNT; "info->tty" will cause this */#ifdef SERIAL_DO_RESTART return ((info->flags & ASYNC_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);#else return -EAGAIN;#endif } /* * Start up serial port */ retval = startup(info); if (retval) { /* MOD_DEC_USE_COUNT; "info->tty" will cause this */ return retval; } retval = block_til_ready(tty, filp, info); if (retval) { /* MOD_DEC_USE_COUNT; "info->tty" will cause this */#ifdef SERIAL_DEBUG_OPEN baget_printk("rs_open returning after block_til_ready " "with %d\n", retval);#endif 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); }#ifdef CONFIG_SERIAL_CONSOLE if (sercons.cflag && sercons.index == line) { tty->termios->c_cflag = sercons.cflag; sercons.cflag = 0; change_speed(info); }#endif info->session = current->session; info->pgrp = current->pgrp;#ifdef SERIAL_DEBUG_OPEN baget_printk("rs_open ttys%d successful...", info->line);#endif return 0;}/* * /proc fs routines.... */static inline int line_info(char *buf, struct serial_state *state){ struct async_struct *info = state->info, scr_info; int ret; ret = sprintf(buf, "%d: uart:%s port:%X irq:%d", state->line, uart_config[state->type].name, 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 */ if (!info) { info = &scr_info; /* This is just for serial_{in,out} */ info->magic = SERIAL_MAGIC; info->port = state->port; info->flags = state->flags; info->quot = 0; info->tty = 0; } if (info->quot) { ret += sprintf(buf+ret, " baud:%d", state->baud_base / info->quot); } 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); return ret;}int rs_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\n", serial_version); for (i = 0; i < NR_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);}/* * --------------------------------------------------------------------- * 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 _INLINE_ void show_serial_version(void){ printk(KERN_INFO "%s version %s with", serial_name, serial_version);#ifdef CONFIG_SERIAL_SHARE_IRQ printk(" SHARE_IRQ");#endif#define SERIAL_OPT#ifdef CONFIG_SERIAL_DETECT_IRQ printk(" DETECT_IRQ");#endif#ifdef SERIAL_OPT printk(" enabled\n");#else printk(" no serial options enabled\n");#endif#undef SERIAL_OPT}/* * 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. The important question is * whether or not this UART is a 16550A or not, since this will * determine whether or not we can use its FIFO features or not. *//* * Functionality of this function is reduced: we already know we have a VAC, * but still need to perform some important actions (see code :-). */static void autoconfig(struct serial_state * state){ struct async_struct *info, scr_info; unsigned long flags; /* Setting up important parameters */ state->type = VAC_UART_TYPE; state->xmit_fifo_size = uart_config[state->type].dfl_xmit_fifo_size; info = &scr_info; /* This is just for serial_{in,out} */ info->magic = SERIAL_MAGIC; info->port = state->port; info->flags = state->flags; save_flags(flags); cli(); /* + Flush VAC input fifo */ (void)serial_in(info, VAC_UART_RX); (void)serial_in(info, VAC_UART_RX); (void)serial_in(info, VAC_UART_RX); (void)serial_in(info, VAC_UART_RX); /* Disable interrupts */ serial_outp(info, VAC_UART_INT_MASK, 0); restore_flags(flags);}int register_serial(struct serial_struct *req);void unregister_serial(int line);EXPORT_SYMBOL(register_serial);EXPORT_SYMBOL(unregister_serial);/* * Important function for VAC UART check and reanimation. */static void rs_timer(unsigned long dummy){ static unsigned long last_strobe = 0; struct async_struct *info; unsigned int i; unsigned long flags; if ((jiffies - last_strobe) >= RS_STROBE_TIME) { for (i=1; i < NR_IRQS; i++) { info = IRQ_ports[i]; if (!info) continue; save_flags(flags); cli();#ifdef CONFIG_SERIAL_SHARE_IRQ if (info->next_port) { do { serial_out(info, VAC_UART_INT_MASK, 0); info->IER |= VAC_UART_INT_TX_EMPTY; serial_out(info, VAC_UART_INT_MASK, info->IER); info = info->next_port; } while (info); rs_interrupt(i, NULL, NULL); } else#endif /* CONFIG_SERIAL_SHARE_IRQ */ rs_interrupt_single(i, NULL, NULL); restore_flags(flags); } } last_strobe = jiffies; mod_timer(&vacs_timer, jiffies + RS_STROBE_TIME); /* * It looks this code for case we share IRQ with console... */ if (IRQ_ports[0]) { save_flags(flags); cli();#ifdef CONFIG_SERIAL_SHARE_IRQ rs_interrupt(0, NULL, NULL);#else rs_interrupt_single(0, NULL, NULL);#endif restore_flags(flags); mod_timer(&vacs_timer, jiffies + IRQ_timeout[0] - 2); }} /* * The serial driver boot-time initialization code! */int __init rs_init(void){ int i; struct serial_state * state; extern void atomwide_serial_init (void); extern void dualsp_serial_init (void);#ifdef CONFIG_ATOMWIDE_SERIAL atomwide_serial_init ();#endif#ifdef CONFIG_DUALSP_SERIAL dualsp_serial_init ();#endif init_bh(SERIAL_BH, do_serial_bh); init_timer(&vacs_timer); vacs_timer.function = rs_timer; vacs_timer.expires = 0; for (i = 0; i < NR_IRQS; i++) { IRQ_ports[i] = 0; IRQ_timeout[i] = 0; }/* * It is not a good idea to share interrupts with console, * but it looks we cannot avoid it. */#if 0 #ifdef CONFIG_SERIAL_CONSOLE /* * The interrupt of the serial console port * can't be shared. */ if (sercons.flags & CON_CONSDEV) { for(i = 0; i < NR_PORTS; i++) if (i != sercons.index && rs_table[i].irq == rs_table[sercons.index].irq) rs_table[i].irq = 0; }#endif#endif show_serial_version(); /* Initialize the tty_driver structure */ memset(&serial_driver, 0, sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC; serial_driver.driver_name = "serial"; serial_driver.name = "ttyS"; serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64; serial_driver.num = NR_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; 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.send_xchar = rs_send_xchar; 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.wait_until_sent = rs_wait_until_sent; serial_driver.read_proc = rs_read_proc; /* * The callout device is just like normal device except for * major number and the subtype code. */ callout_driver = serial_driver; callout_driver.name = "cua"; 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_PORTS; i++,state++) { state->magic = SSTATE_MAGIC; state->line = i; state->type = PORT_UNKNOWN; 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; state->irq = irq_cannonicalize(state->irq);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -