📄 simserial.c
字号:
struct serial_state *state; int retval; if (!(info->flags & ASYNC_INITIALIZED)) return; state = info->state;#ifdef SIMSERIAL_DEBUG printk("Shutting down serial port %d (irq %d)....", info->line, state->irq);#endif save_flags(flags); cli(); /* Disable interrupts */ /* * First unlink the serial port from the IRQ chain... */ if (info->next_port) info->next_port->prev_port = info->prev_port; if (info->prev_port) info->prev_port->next_port = info->next_port; else IRQ_ports[state->irq] = info->next_port; /* * Free the IRQ, if necessary */ if (state->irq && (!IRQ_ports[state->irq] || !IRQ_ports[state->irq]->next_port)) { if (IRQ_ports[state->irq]) { free_irq(state->irq, NULL); retval = request_irq(state->irq, rs_interrupt_single, IRQ_T(info), "serial", NULL); if (retval) printk(KERN_ERR "serial shutdown: request_irq: error %d" " Couldn't reacquire IRQ.\n", retval); } else free_irq(state->irq, NULL); } if (info->xmit.buf) { free_page((unsigned long) info->xmit.buf); info->xmit.buf = 0; } if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); info->flags &= ~ASYNC_INITIALIZED; restore_flags(flags);}/* * ------------------------------------------------------------ * rs_close() * * This routine is called when the serial port gets closed. First, we * wait for the last remaining data to be sent. Then, we unlink its * async structure from the interrupt chain if necessary, and we free * that IRQ if nothing is left in the chain. * ------------------------------------------------------------ */static void rs_close(struct tty_struct *tty, struct file * filp){ struct async_struct * info = (struct async_struct *)tty->driver_data; struct serial_state *state; unsigned long flags; if (!info ) return; state = info->state; save_flags(flags); cli(); if (tty_hung_up_p(filp)) {#ifdef SIMSERIAL_DEBUG printk("rs_close: hung_up\n");#endif MOD_DEC_USE_COUNT; restore_flags(flags); return; }#ifdef SIMSERIAL_DEBUG printk("rs_close ttys%d, count = %d\n", info->line, state->count);#endif if ((tty->count == 1) && (state->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. state->count should always * be one in these conditions. If it's greater than * one, we've got real problems, since it means the * serial port won't be shutdown. */ printk(KERN_ERR "rs_close: bad serial port count; tty->count is 1, " "state->count is %d\n", state->count); state->count = 1; } if (--state->count < 0) { printk(KERN_ERR "rs_close: bad serial port count for ttys%d: %d\n", info->line, state->count); state->count = 0; } if (state->count) { MOD_DEC_USE_COUNT; restore_flags(flags); return; } info->flags |= ASYNC_CLOSING; restore_flags(flags); /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. */ shutdown(info); if (tty->driver.flush_buffer) tty->driver.flush_buffer(tty); if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); info->event = 0; info->tty = 0; if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(info->close_delay); } wake_up_interruptible(&info->open_wait); } info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); MOD_DEC_USE_COUNT;}/* * rs_wait_until_sent() --- wait until the transmitter is empty */static void rs_wait_until_sent(struct tty_struct *tty, int timeout){}/* * rs_hangup() --- called by tty_hangup() when a hangup is signaled. */static void rs_hangup(struct tty_struct *tty){ struct async_struct * info = (struct async_struct *)tty->driver_data; struct serial_state *state = info->state;#ifdef SIMSERIAL_DEBUG printk("rs_hangup: called\n");#endif state = info->state; rs_flush_buffer(tty); if (info->flags & ASYNC_CLOSING) return; shutdown(info); info->event = 0; state->count = 0; info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); info->tty = 0; wake_up_interruptible(&info->open_wait);}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;}static intstartup(struct async_struct *info){ unsigned long flags; int retval=0; void (*handler)(int, void *, struct pt_regs *); struct serial_state *state= info->state; unsigned long page; page = get_free_page(GFP_KERNEL); if (!page) return -ENOMEM; save_flags(flags); cli(); if (info->flags & ASYNC_INITIALIZED) { free_page(page); goto errout; } if (!state->port || !state->type) { if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); free_page(page); goto errout; } if (info->xmit.buf) free_page(page); else info->xmit.buf = (unsigned char *) page;#ifdef SIMSERIAL_DEBUG printk("startup: ttys%d (irq %d)...", info->line, state->irq);#endif /* * Allocate the IRQ if necessary */ if (state->irq && (!IRQ_ports[state->irq] || !IRQ_ports[state->irq]->next_port)) { if (IRQ_ports[state->irq]) { retval = -EBUSY; goto errout; } else handler = rs_interrupt_single; retval = request_irq(state->irq, handler, IRQ_T(info), "simserial", NULL); if (retval) { if (capable(CAP_SYS_ADMIN)) { if (info->tty) set_bit(TTY_IO_ERROR, &info->tty->flags); retval = 0; } goto errout; } } /* * Insert serial port into IRQ chain. */ info->prev_port = 0; info->next_port = IRQ_ports[state->irq]; if (info->next_port) info->next_port->prev_port = info; IRQ_ports[state->irq] = info; if (info->tty) clear_bit(TTY_IO_ERROR, &info->tty->flags); info->xmit.head = info->xmit.tail = 0;#if 0 /* * Set up serial timers... */ timer_table[RS_TIMER].expires = jiffies + 2*HZ/100; timer_active |= 1 << RS_TIMER;#endif /* * Set up the tty->alt_speed kludge */ if (info->tty) { if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) info->tty->alt_speed = 57600; if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) info->tty->alt_speed = 115200; if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_SHI) info->tty->alt_speed = 230400; if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP) info->tty->alt_speed = 460800; } info->flags |= ASYNC_INITIALIZED; restore_flags(flags); return 0;errout: restore_flags(flags); return retval;}/* * 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;#ifdef SIMSERIAL_DEBUG 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; } 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; } /* * figure out which console to use (should be one already) */ console = console_drivers; while (console) { if ((console->flags & CON_ENABLED) && console->write) break; console = console->next; } info->session = current->session; info->pgrp = current->pgrp;#ifdef SIMSERIAL_DEBUG printk("rs_open ttys%d successful\n", info->line);#endif return 0;}/* * /proc fs routines.... */static inline int line_info(char *buf, struct serial_state *state){ return sprintf(buf, "%d: uart:%s port:%lX irq:%d\n", state->line, uart_config[state->type].name, state->port, state->irq);}static 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, "simserinfo: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 + (begin-off); 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); printk(KERN_INFO " no serial options enabled\n");}/* * The serial driver boot-time initialization code! */static int __initsimrs_init (void){ int i; struct serial_state *state; 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 = "simserial"; serial_driver.name = "ttyS"; serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64; serial_driver.num = 1; 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; /* * Let's have a little bit of fun ! */ for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) { if (state->type == PORT_UNKNOWN) continue; if (!state->irq) { state->irq = ia64_alloc_vector(); ia64_ssc_connect_irq(KEYBOARD_INTR, state->irq); } printk(KERN_INFO "ttyS%02d at 0x%04lx (irq = %d) is a %s\n", state->line, state->port, state->irq, uart_config[state->type].name); } /* * 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 simserial driver\n"); if (tty_register_driver(&callout_driver)) panic("Couldn't register callout driver\n"); return 0;}#ifndef MODULE__initcall(simrs_init);#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -