📄 su.c
字号:
retval = -EAGAIN;#endif break; } if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && !(info->flags & ASYNC_CLOSING) && (do_clocal || (serial_in(info, UART_MSR) & UART_MSR_DCD))) break; if (signal_pending(current)) { retval = -ERESTARTSYS; break; }#ifdef SERIAL_DEBUG_OPEN printk("block_til_ready blocking: ttys%d, count = %d\n", info->line, info->count);#endif schedule(); } current->state = TASK_RUNNING; remove_wait_queue(&info->open_wait, &wait); if (extra_count) info->count++; info->blocked_open--;#ifdef SERIAL_DEBUG_OPEN printk("block_til_ready after blocking: ttys%d, count = %d\n", info->line, info->count);#endif if (retval) return retval; info->flags |= ASYNC_NORMAL_ACTIVE; 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 intsu_open(struct tty_struct *tty, struct file * filp){ struct su_struct *info; int retval, line; unsigned long page; line = MINOR(tty->device) - tty->driver.minor_start; if ((line < 0) || (line >= NR_PORTS)) return -ENODEV; info = su_table + line; info->count++; tty->driver_data = info; info->tty = tty; if (serial_paranoia_check(info, tty->device, "su_open")) { info->count--; return -ENODEV; }#ifdef SERIAL_DEBUG_OPEN printk("su_open %s%d, count = %d\n", tty->driver.name, info->line, info->count);#endif info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; if (!tmp_buf) { page = get_free_page(GFP_KERNEL); if (!page) 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);#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) return retval; MOD_INC_USE_COUNT; retval = block_til_ready(tty, filp, info); if (retval) {#ifdef SERIAL_DEBUG_OPEN printk("su_open returning after block_til_ready with %d\n", retval);#endif return retval; } if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { if (tty->driver.subtype == SERIAL_TYPE_NORMAL) *tty->termios = info->normal_termios; else *tty->termios = info->callout_termios; change_speed(info, 0); }#ifdef CONFIG_SERIAL_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("su_open ttys%d successful...", info->line);#endif return 0;}/* * /proc fs routines.... */static intline_info(char *buf, struct su_struct *info){ char stat_buf[30], control, status; int ret; unsigned long flags; if (info->port == 0 || info->type == PORT_UNKNOWN) return 0; ret = sprintf(buf, "%u: uart:%s port:%lX irq:%s", info->line, uart_config[info->type].name, (unsigned long)info->port, __irq_itoa(info->irq)); /* * Figure out the current RS-232 lines */ save_flags(flags); cli(); status = serial_in(info, UART_MSR); control = info ? info->MCR : serial_in(info, UART_MCR); restore_flags(flags); stat_buf[0] = 0; stat_buf[1] = 0; if (control & UART_MCR_RTS) strcat(stat_buf, "|RTS"); if (status & UART_MSR_CTS) strcat(stat_buf, "|CTS"); if (control & UART_MCR_DTR) strcat(stat_buf, "|DTR"); if (status & UART_MSR_DSR) strcat(stat_buf, "|DSR"); if (status & UART_MSR_DCD) strcat(stat_buf, "|CD"); if (status & UART_MSR_RI) strcat(stat_buf, "|RI"); if (info->quot) { ret += sprintf(buf+ret, " baud:%u", info->baud_base / info->quot); } ret += sprintf(buf+ret, " tx:%u rx:%u", info->icount.tx, info->icount.rx); if (info->icount.frame) ret += sprintf(buf+ret, " fe:%u", info->icount.frame); if (info->icount.parity) ret += sprintf(buf+ret, " pe:%u", info->icount.parity); if (info->icount.brk) ret += sprintf(buf+ret, " brk:%u", info->icount.brk); if (info->icount.overrun) ret += sprintf(buf+ret, " oe:%u", info->icount.overrun); /* * Last thing is the RS-232 status lines */ ret += sprintf(buf+ret, " %s\n", stat_buf+1); return ret;}int su_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ int i, len = 0; off_t begin = 0; len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version); for (i = 0; i < NR_PORTS && len < 4000; i++) { len += line_info(page + len, &su_table[i]); 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);}/* * --------------------------------------------------------------------- * su_XXX_init() and friends * * su_XXX_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 __init show_su_version(void){ char *revision = "$Revision: 1.1.1.1 $"; char *version, *p; version = strchr(revision, ' '); strcpy(serial_version, ++version); p = strchr(serial_version, ' '); *p = '\0'; printk(KERN_INFO "%s version %s\n", serial_name, serial_version);}/* * This routine is called by su_{serial|kbd_ms}_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, since this will determine * whether or not we can use its FIFO features. */static voidautoconfig(struct su_struct *info){ unsigned char status1, status2, scratch, scratch2; struct linux_ebus_device *dev = 0; struct linux_ebus *ebus;#ifdef CONFIG_SPARC64 struct isa_bridge *isa_br; struct isa_device *isa_dev;#endif#ifndef __sparc_v9__ struct linux_prom_registers reg0;#endif unsigned long flags; if (!info->port_node || !info->port_type) return; /* * First we look for Ebus-bases su's */ for_each_ebus(ebus) { for_each_ebusdev(dev, ebus) { if (dev->prom_node == info->port_node) { info->port = dev->resource[0].start; info->irq = dev->irqs[0]; goto ebus_done; } } }#ifdef CONFIG_SPARC64 for_each_isa(isa_br) { for_each_isadev(isa_dev, isa_br) { if (isa_dev->prom_node == info->port_node) { info->port = isa_dev->resource.start; info->irq = isa_dev->irq; goto ebus_done; } } }#endif#ifdef __sparc_v9__ /* * Not on Ebus, bailing. */ return;#else /* * Not on Ebus, must be OBIO. */ if (prom_getproperty(info->port_node, "reg", (char *)®0, sizeof(reg0)) == -1) { prom_printf("su: no \"reg\" property\n"); return; } prom_apply_obio_ranges(®0, 1); if (reg0.which_io != 0) { /* Just in case... */ prom_printf("su: bus number nonzero: 0x%x:%x\n", reg0.which_io, reg0.phys_addr); return; } if ((info->port = (unsigned long) ioremap(reg0.phys_addr, reg0.reg_size)) == 0) { prom_printf("su: cannot map\n"); return; } /* * There is no intr property on MrCoffee, so hardwire it. */ info->irq = IRQ_4M(13);#endifebus_done:#ifdef SERIAL_DEBUG_OPEN printk("Found 'su' at %016lx IRQ %s\n", info->port, __irq_itoa(info->irq));#endif info->magic = SERIAL_MAGIC; save_flags(flags); cli(); /* * Do a simple existence test first; if we fail this, there's * no point trying anything else. * * 0x80 is used as a nonsense port to prevent against false * positives due to ISA bus float. The assumption is that * 0x80 is a non-existent port; which should be safe since * include/asm/io.h also makes this assumption. */ scratch = serial_inp(info, UART_IER); serial_outp(info, UART_IER, 0); scratch2 = serial_inp(info, UART_IER); serial_outp(info, UART_IER, scratch); if (scratch2) { restore_flags(flags); return; /* We failed; there's nothing here */ } scratch = serial_inp(info, UART_MCR); serial_outp(info, UART_MCR, UART_MCR_LOOP | scratch); serial_outp(info, UART_MCR, UART_MCR_LOOP | 0x0A); status1 = serial_inp(info, UART_MSR) & 0xF0; serial_outp(info, UART_MCR, scratch); if (status1 != 0x90) { /* * This code fragment used to fail, now it fixed itself. * We keep the printout for a case. */ printk("su: loopback returned status 0x%02x\n", status1); restore_flags(flags); return; } scratch2 = serial_in(info, UART_LCR); serial_outp(info, UART_LCR, 0xBF); /* set up for StarTech test */ serial_outp(info, UART_EFR, 0); /* EFR is the same as FCR */ serial_outp(info, UART_LCR, 0); serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); scratch = serial_in(info, UART_IIR) >> 6; switch (scratch) { case 0: info->type = PORT_16450; break; case 1: info->type = PORT_UNKNOWN; break; case 2: info->type = PORT_16550; break; case 3: info->type = PORT_16550A; break; } if (info->type == PORT_16550A) { /* Check for Startech UART's */ serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB); if (serial_in(info, UART_EFR) == 0) { info->type = PORT_16650; } else { serial_outp(info, UART_LCR, 0xBF); if (serial_in(info, UART_EFR) == 0) info->type = PORT_16650V2; } } if (info->type == PORT_16550A) { /* Check for TI 16750 */ serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB); serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE); scratch = serial_in(info, UART_IIR) >> 5; if (scratch == 7) { serial_outp(info, UART_LCR, 0); serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); scratch = serial_in(info, UART_IIR) >> 5; if (scratch == 6) info->type = PORT_16750; } serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); } serial_outp(info, UART_LCR, scratch2); if (info->type == PORT_16450) { scratch = serial_in(info, UART_SCR); serial_outp(info, UART_SCR, 0xa5); status1 = serial_in(info, UART_SCR); serial_outp(info, UART_SCR, 0x5a); status2 = serial_in(info, UART_SCR); serial_outp(info, UART_SCR, scratch); if ((status1 != 0xa5) || (status2 != 0x5a)) info->type = PORT_8250; } info->xmit_fifo_size = uart_config[info->type].dfl_xmit_fifo_size; if (info->type == PORT_UNKNOWN) { restore_flags(flags); return; } sprintf(info->name, "su(%s)", su_typev[info->port_type]); /* * Reset the UART. */ serial_outp(info, UART_MCR, 0x00); serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR|UART_FCR_CLEAR_XMIT)); (void)serial_in(info, UART_RX); serial_outp(info, UART_IER, 0x00); restore_flags(flags);}/* This is used by the SAB driver to adjust where its minor * numbers start, we always are probed for first. */int su_num_ports = 0;EXPORT_SYMBOL(su_num_ports);/* * The serial driver boot-time initialization code! */int __init su_serial_init(void){ int i; struct su_struct *info; init_bh(SERIAL_BH, do_serial_bh); show_su_version(); /* Initialize the tty_driver structure */ memset(&serial_driver, 0, sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC; serial_driver.driver_name = "su";#ifdef 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_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 = su_open; serial_driver.close = su_close; serial_driver.write = su_write; serial_driver.put_char = su_put_char; serial_driver.flush_chars = su_flush_chars; serial_driver.write_room = su_write_room; serial_driver.chars_in_buffer = su_chars_in_buffer; serial_driver.flush_buffer = su_flush_buffer; serial_driver.ioctl = su_ioctl; serial_driver.throttle = su_throttle; serial_driver.unthrottle = su_unth
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -