📄 dz.c
字号:
info->count = 0; } if (info->count) { restore_flags(flags); return; } info->flags |= DZ_CLOSING; /* * Save the termios structure, since this port may have * separate termios for callout and dialin. */ if (info->flags & DZ_NORMAL_ACTIVE) info->normal_termios = *tty->termios; if (info->flags & DZ_CALLOUT_ACTIVE) info->callout_termios = *tty->termios; /* * Now we wait for the transmit buffer to clear; and we notify the line * discipline to only process XON/XOFF characters. */ tty->closing = 1; if (info->closing_wait != DZ_CLOSING_WAIT_NONE) tty_wait_until_sent(tty, info->closing_wait); /* * At this point we stop accepting input. To do this, we disable the * receive line status interrupts. */ shutdown(info); if (tty->driver.flush_buffer) tty->driver.flush_buffer (tty); if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer (tty); tty->closing = 0; info->event = 0; info->tty = 0; if (tty->ldisc.num != ldiscs[N_TTY].num) { if (tty->ldisc.close) tty->ldisc.close(tty); tty->ldisc = ldiscs[N_TTY]; tty->termios->c_line = N_TTY; if (tty->ldisc.open) tty->ldisc.open(tty); } 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 &= ~(DZ_NORMAL_ACTIVE | DZ_CALLOUT_ACTIVE | DZ_CLOSING); wake_up_interruptible(&info->close_wait); restore_flags(flags);}/* * dz_hangup () --- called by tty_hangup() when a hangup is signaled. */static void dz_hangup (struct tty_struct *tty){ struct dz_serial *info = (struct dz_serial *) tty->driver_data; dz_flush_buffer(tty); shutdown(info); info->event = 0; info->count = 0; info->flags &= ~(DZ_NORMAL_ACTIVE | DZ_CALLOUT_ACTIVE); info->tty = 0; wake_up_interruptible(&info->open_wait);}/* * ------------------------------------------------------------ * rs_open() and friends * ------------------------------------------------------------ */static int block_til_ready(struct tty_struct *tty, struct file *filp, struct dz_serial *info){ DECLARE_WAITQUEUE(wait, current); int retval; int do_clocal = 0; /* * If the device is in the middle of being closed, then block * until it's done, and then try again. */ if (info->flags & DZ_CLOSING) { interruptible_sleep_on(&info->close_wait); return -EAGAIN; } /* * If this is a callout device, then just make sure the normal * device isn't being used. */ if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { if (info->flags & DZ_NORMAL_ACTIVE) return -EBUSY; if ((info->flags & DZ_CALLOUT_ACTIVE) && (info->flags & DZ_SESSION_LOCKOUT) && (info->session != current->session)) return -EBUSY; if ((info->flags & DZ_CALLOUT_ACTIVE) && (info->flags & DZ_PGRP_LOCKOUT) && (info->pgrp != current->pgrp)) return -EBUSY; info->flags |= DZ_CALLOUT_ACTIVE; return 0; } /* * If non-blocking mode is set, or the port is not enabled, then make * the check up front and then exit. */ if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) { if (info->flags & DZ_CALLOUT_ACTIVE) return -EBUSY; info->flags |= DZ_NORMAL_ACTIVE; return 0; } if (info->flags & DZ_CALLOUT_ACTIVE) { if (info->normal_termios.c_cflag & CLOCAL) do_clocal = 1; } else { if (tty->termios->c_cflag & CLOCAL) do_clocal = 1; } /* * Block waiting for the carrier detect and the line to become free * (i.e., not in use by the callout). While we are in this loop, * info->count is dropped by one, so that dz_close() knows when to free * things. We restore it upon exit, either normal or abnormal. */ retval = 0; add_wait_queue(&info->open_wait, &wait); info->count--; info->blocked_open++; while (1) { set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p (filp) || !(info->is_initialized)) { retval = -EAGAIN; break; } if (!(info->flags & DZ_CALLOUT_ACTIVE) && !(info->flags & DZ_CLOSING) && do_clocal) break; if (signal_pending(current)) { retval = -ERESTARTSYS; break; } schedule(); } current->state = TASK_RUNNING; remove_wait_queue (&info->open_wait, &wait); if (!tty_hung_up_p(filp)) info->count++; info->blocked_open--; if (retval) return retval; info->flags |= DZ_NORMAL_ACTIVE; return 0;}/* * This routine is called whenever a serial port is opened. It * enables interrupts for a serial port. It also performs the * serial-specific initialization for the tty structure. */static int dz_open (struct tty_struct *tty, struct file *filp){ struct dz_serial *info; int retval, line; line = MINOR(tty->device) - tty->driver.minor_start; /* * The dz lines for the mouse/keyboard must be opened using their * respective drivers. */ if ((line < 0) || (line >= DZ_NB_PORT)) return -ENODEV; if ((line == DZ_KEYBOARD) || (line == DZ_MOUSE)) return -ENODEV; info = lines[line]; info->count++; tty->driver_data = info; info->tty = tty; /* * Start up serial port */ retval = startup (info); if (retval) return retval; retval = block_til_ready (tty, filp, info); if (retval) return retval; if ((info->count == 1) && (info->flags & DZ_SPLIT_TERMIOS)) { if (tty->driver.subtype == SERIAL_TYPE_NORMAL) *tty->termios = info->normal_termios; else *tty->termios = info->callout_termios; change_speed(info); } info->session = current->session; info->pgrp = current->pgrp; return 0;}static void show_serial_version (void){ printk("%s%s\n", dz_name, dz_version);}int __init dz_init(void){ int i, flags; struct dz_serial *info; /* Setup base handler, and timer table. */ init_bh(SERIAL_BH, do_serial_bh); show_serial_version(); memset(&serial_driver, 0, sizeof(struct tty_driver)); serial_driver.magic = TTY_DRIVER_MAGIC;#if (LINUX_VERSION_CODE > 0x2032D && defined(CONFIG_DEVFS_FS)) serial_driver.name = "ttyS";#else serial_driver.name = "tts/%d";#endif serial_driver.major = TTY_MAJOR; serial_driver.minor_start = 64; serial_driver.num = DZ_NB_PORT; 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 = dz_open; serial_driver.close = dz_close; serial_driver.write = dz_write; serial_driver.flush_chars = dz_flush_chars; serial_driver.write_room = dz_write_room; serial_driver.chars_in_buffer = dz_chars_in_buffer; serial_driver.flush_buffer = dz_flush_buffer; serial_driver.ioctl = dz_ioctl; serial_driver.throttle = dz_throttle; serial_driver.unthrottle = dz_unthrottle; serial_driver.send_xchar = dz_send_xchar; serial_driver.set_termios = dz_set_termios; serial_driver.stop = dz_stop; serial_driver.start = dz_start; serial_driver.hangup = dz_hangup; /* * 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";#else callout_driver.name = "cua/%d";#endif callout_driver.major = TTYAUX_MAJOR; callout_driver.subtype = SERIAL_TYPE_CALLOUT; 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"); save_flags(flags); cli(); for (i=0; i < DZ_NB_PORT; i++) { info = &multi[i]; lines[i] = info; info->magic = SERIAL_MAGIC; if ((mips_machtype == MACH_DS23100) || (mips_machtype == MACH_DS5100)) info->port = (unsigned long) KN01_DZ11_BASE; else info->port = (unsigned long) KN02_DZ11_BASE; info->line = i; info->tty = 0; info->close_delay = 50; info->closing_wait = 3000; info->x_char = 0; info->event = 0; info->count = 0; info->blocked_open = 0; info->tqueue.routine = do_softint; info->tqueue.data = info; info->tqueue_hangup.routine = do_serial_hangup; info->tqueue_hangup.data = info; info->callout_termios = callout_driver.init_termios; info->normal_termios = serial_driver.init_termios; init_waitqueue_head(&info->open_wait); init_waitqueue_head(&info->close_wait); /* * If we are pointing to address zero then punt - not correctly * set up in setup.c to handle this. */ if (! info->port) return 0; printk("ttyS%02d at 0x%08x (irq = %d)\n", info->line, info->port, SERIAL); tty_register_devfs(&serial_driver, 0, serial_driver.minor_start + info->line); tty_register_devfs(&callout_driver, 0, callout_driver.minor_start + info->line); } /* Reset the chip */#ifndef CONFIG_SERIAL_CONSOLE { int tmp; dz_out(info, DZ_CSR, DZ_CLR); while ((tmp = dz_in(info,DZ_CSR)) & DZ_CLR); wbflush(); /* Enable scanning */ dz_out(info, DZ_CSR, DZ_MSE); }#endif /* * Order matters here... the trick is that flags is updated... in * request_irq - to immediatedly obliterate it is unwise. */ restore_flags(flags); if (request_irq(SERIAL, dz_interrupt, SA_INTERRUPT, "DZ", lines[0])) panic("Unable to register DZ interrupt\n"); return 0;}#ifdef CONFIG_SERIAL_CONSOLEstatic void dz_console_put_char (unsigned char ch){ unsigned long flags; int loops = 2500; unsigned short tmp = ch; /* * this code sends stuff out to serial device - spinning its wheels and * waiting. */ /* force the issue - point it at lines[3]*/ dz_console = &multi[CONSOLE_LINE]; save_and_cli(flags); /* spin our wheels */ while (((dz_in(dz_console, DZ_CSR) & DZ_TRDY) != DZ_TRDY) && loops--) ; /* Actually transmit the character. */ dz_out(dz_console, DZ_TDR, tmp); restore_flags(flags); }/* * ------------------------------------------------------------------- * dz_console_print () * * dz_console_print is registered for printk. * The console must be locked when we get here. * ------------------------------------------------------------------- */static void dz_console_print (struct console *cons, const char *str, unsigned int count){#ifdef DEBUG_DZ prom_printf((char *)str);#endif while (count--) { if (*str == '\n') dz_console_put_char('\r'); dz_console_put_char(*str++); }}static int dz_console_wait_key(struct console *co){ return 0;}static kdev_t dz_console_device(struct console *c){ return MKDEV(TTY_MAJOR, 64 + c->index);}static int __init dz_console_setup(struct console *co, char *options){ int baud = 9600; int bits = 8; int parity = 'n'; int cflag = CREAD | HUPCL | CLOCAL; char *s; unsigned short mask,tmp; if (options) { baud = simple_strtoul(options, NULL, 10); s = options; while (*s >= '0' && *s <= '9') s++; if (*s) parity = *s++; if (*s) bits = *s - '0'; } /* * Now construct a cflag setting. */ switch (baud) { case 1200: cflag |= DZ_B1200; break; case 2400: cflag |= DZ_B2400; break; case 4800: cflag |= DZ_B4800; break; case 9600: default: cflag |= DZ_B9600; break; } switch (bits) { case 7: cflag |= DZ_CS7; break; default: case 8: cflag |= DZ_CS8; break; } switch (parity) { case 'o': case 'O': cflag |= DZ_PARODD; break; case 'e': case 'E': cflag |= DZ_PARENB; break; } co->cflag = cflag; /* TOFIX: force to console line */ dz_console = &multi[CONSOLE_LINE]; if ((mips_machtype == MACH_DS23100) || (mips_machtype == MACH_DS5100)) dz_console->port = KN01_DZ11_BASE; else dz_console->port = KN02_DZ11_BASE; dz_console->line = CONSOLE_LINE; dz_out(dz_console, DZ_CSR, DZ_CLR); while ((tmp = dz_in(dz_console,DZ_CSR)) & DZ_CLR) ; /* enable scanning */ dz_out(dz_console, DZ_CSR, DZ_MSE); /* Set up flags... */ dz_console->cflags = 0; dz_console->cflags |= DZ_B9600; dz_console->cflags |= DZ_CS8; dz_console->cflags |= DZ_PARENB; dz_out(dz_console, DZ_LPR, dz_console->cflags); mask = 1 << dz_console->line; tmp = dz_in (dz_console, DZ_TCR); /* read the TX flag */ if (!(tmp & mask)) { tmp |= mask; /* set the TX flag */ dz_out (dz_console, DZ_TCR, tmp); } return 0;}static struct console dz_sercons = { name: "ttyS", write: dz_console_print, device: dz_console_device, wait_key: dz_console_wait_key, setup: dz_console_setup, flags: CON_CONSDEV | CON_PRINTBUFFER, index: CONSOLE_LINE,};void __init dz_serial_console_init(void){ register_console(&dz_sercons);}#endif /* ifdef CONFIG_SERIAL_CONSOLE */MODULE_LICENSE("GPL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -