?? zs.c
字號:
tty->hw_stopped = 0; zs_start(tty); }}/* * ------------------------------------------------------------ * zs_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 * ZILOG structure from the interrupt chain if necessary, and we free * that IRQ if nothing is left in the chain. * ------------------------------------------------------------ */static void zs_close(struct tty_struct *tty, struct file * filp){ struct sun_serial * info = (struct sun_serial *) tty->driver_data; unsigned long flags; if (!info || serial_paranoia_check(info, tty->device, "zs_close")) return; save_flags(flags); cli(); if (tty_hung_up_p(filp)) { restore_flags(flags); return; } #ifdef SERIAL_DEBUG_OPEN printk("zs_close tty-%d, count = %d\n", info->line, info->count);#endif if ((tty->count == 1) && (info->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. Info->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("zs_close: bad serial port count; tty->count is 1, " "info->count is %d\n", info->count); info->count = 1; } if (--info->count < 0) { printk("zs_close: bad serial port count for ttys%d: %d\n", info->line, info->count); info->count = 0; } if (info->count) { restore_flags(flags); return; } info->flags |= ZILOG_CLOSING; /* * Save the termios structure, since this port may have * separate termios for callout and dialin. */ if (info->flags & ZILOG_NORMAL_ACTIVE) info->normal_termios = *tty->termios; if (info->flags & ZILOG_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 != ZILOG_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, and tell the * interrupt driver to stop checking the data ready bit in the * line status register. */ /** if (!info->iscons) ... **/ info->curregs[3] &= ~RxENAB; write_zsreg(info->zs_channel, 3, info->curregs[3]); info->curregs[1] &= ~(RxINT_MASK); write_zsreg(info->zs_channel, 1, info->curregs[1]); ZS_CLEARFIFO(info->zs_channel); 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 &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE| ZILOG_CLOSING); wake_up_interruptible(&info->close_wait);#ifdef SERIAL_DEBUG_OPEN printk("zs_close tty-%d exiting, count = %d\n", info->line, info->count);#endif restore_flags(flags);}/* * zs_hangup() --- called by tty_hangup() when a hangup is signaled. */void zs_hangup(struct tty_struct *tty){ struct sun_serial * info = (struct sun_serial *) tty->driver_data; if (serial_paranoia_check(info, tty->device, "zs_hangup")) return; if (info->is_cons) return;#ifdef SERIAL_DEBUG_OPEN printk("zs_hangup<%p: tty-%d, count = %d bye\n", __builtin_return_address(0), info->line, info->count);#endif zs_flush_buffer(tty); shutdown(info); info->event = 0; info->count = 0; info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE); info->tty = 0; wake_up_interruptible(&info->open_wait);}/* * * line_info - returns information about each channel * */static inline int line_info(char *buf, struct sun_serial *info){ unsigned char status; char stat_buf[30]; int ret; ret = sprintf(buf, "%d: uart:Zilog8530 port:%x irq:%d", info->line, info->port, info->irq); cli(); status = sbus_readb(&info->zs_channel->control); ZSDELAY(); ZSLOG(REGCTRL, status, 0); sti(); stat_buf[0] = 0; stat_buf[1] = 0; if (info->curregs[5] & RTS) strcat(stat_buf, "|RTS"); if (status & CTS) strcat(stat_buf, "|CTS"); if (info->curregs[5] & DTR) strcat(stat_buf, "|DTR"); if (status & SYNC) strcat(stat_buf, "|DSR"); if (status & DCD) strcat(stat_buf, "|CD"); ret += sprintf(buf + ret, " baud:%d %s\n", info->zs_baud, stat_buf + 1); return ret;}/* * * zs_read_proc() - called when /proc/tty/driver/serial is read. * */int zs_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data){ char *revision = "$Revision: 1.68.2.2 $"; char *version, *p; int i, len = 0, l; off_t begin = 0; version = strchr(revision, ' '); p = strchr(++version, ' '); *p = '\0'; len += sprintf(page, "serinfo:1.0 driver:%s\n", version); *p = ' '; for (i = 0; i < NUM_CHANNELS && len < 4000; i++) { l = line_info(page + len, &zs_soft[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);}/* * ------------------------------------------------------------ * zs_open() and friends * ------------------------------------------------------------ */static int block_til_ready(struct tty_struct *tty, struct file * filp, struct sun_serial *info){ DECLARE_WAITQUEUE(wait, current); int retval, do_clocal = 0; unsigned char r0; /* * If the device is in the middle of being closed, then block * until it's done, and then try again. */ if (info->flags & ZILOG_CLOSING) { interruptible_sleep_on(&info->close_wait);#ifdef SERIAL_DO_RESTART if (info->flags & ZILOG_HUP_NOTIFY) return -EAGAIN; else return -ERESTARTSYS;#else return -EAGAIN;#endif } /* * 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 & ZILOG_NORMAL_ACTIVE) return -EBUSY; if ((info->flags & ZILOG_CALLOUT_ACTIVE) && (info->flags & ZILOG_SESSION_LOCKOUT) && (info->session != current->session)) return -EBUSY; if ((info->flags & ZILOG_CALLOUT_ACTIVE) && (info->flags & ZILOG_PGRP_LOCKOUT) && (info->pgrp != current->pgrp)) return -EBUSY; info->flags |= ZILOG_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 & ZILOG_CALLOUT_ACTIVE) return -EBUSY; info->flags |= ZILOG_NORMAL_ACTIVE; return 0; } if (info->flags & ZILOG_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 * zs_close() knows when to free things. We restore it upon * exit, either normal or abnormal. */ retval = 0; add_wait_queue(&info->open_wait, &wait);#ifdef SERIAL_DEBUG_OPEN printk("block_til_ready before block: ttys%d, count = %d\n", info->line, info->count);#endif cli(); if(!tty_hung_up_p(filp)) info->count--; sti(); info->blocked_open++; while (1) { cli(); if (!(info->flags & ZILOG_CALLOUT_ACTIVE)) zs_rtsdtr(info, 1); sti(); set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ZILOG_INITIALIZED)) {#ifdef SERIAL_DEBUG_OPEN printk("block_til_ready hup-ed: ttys%d, count = %d\n", info->line, info->count);#endif#ifdef SERIAL_DO_RESTART if (info->flags & ZILOG_HUP_NOTIFY) retval = -EAGAIN; else retval = -ERESTARTSYS; #else retval = -EAGAIN;#endif break; } cli(); r0 = read_zsreg(info->zs_channel, R0); sti(); if (!(info->flags & ZILOG_CALLOUT_ACTIVE) && !(info->flags & ZILOG_CLOSING) && (do_clocal || (DCD & r0))) 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 (!tty_hung_up_p(filp)) 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 |= ZILOG_NORMAL_ACTIVE; return 0;} /* * This routine is called whenever a serial port is opened. It * enables interrupts for a serial port, linking in its ZILOG structure into * the IRQ chain. It also performs the serial-specific * initialization for the tty structure. */int zs_open(struct tty_struct *tty, struct file * filp){ struct sun_serial *info; int retval, line; line = MINOR(tty->device) - tty->driver.minor_start; /* The zilog lines for the mouse/keyboard must be * opened using their respective drivers. */ if ((line < 0) || (line >= NUM_CHANNELS)) return -ENODEV; if((line == KEYBOARD_LINE) || (line == MOUSE_LINE)) return -ENODEV; info = zs_soft + line; /* Is the kgdb running over this line? */ if (info->kgdb_channel) return -ENODEV; if (serial_paranoia_check(info, tty->device, "zs_open")) return -ENODEV;#ifdef SERIAL_DEBUG_OPEN printk("zs_open %s%d, count = %d\n", tty->driver.name, info->line, info->count);#endif if (info->tty != 0 && info->tty != tty) { /* Never happen? */ printk("zs_open %s%d, tty overwrite.\n", tty->driver.name, info->line); return -EBUSY; } if (!tmp_buf) { unsigned long page = get_free_page(GFP_KERNEL); if (!page) return -ENOMEM; if (tmp_buf) free_page(page); else tmp_buf = (unsigned char *) page; } 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) {#ifdef SERIAL_DEBUG_OPEN printk("zs_open returning after block_til_ready with %d\n", retval);#endif return retval; } if ((info->count == 1) && (info->flags & ZILOG_SPLIT_TERMIOS)) { if (tty->driver.subtype == SERIAL_TYPE_NORMAL) *tty->termios = info->normal_termios; else *tty->termios = info->callout_termios; change_speed(info); }#ifdef CONFIG_SERIAL_CONSOLE if (zs_console.cflag && zs_console.index == line) { tty->termios->c_cflag = zs_console.cflag; zs_console.cflag = 0; change_speed(info); }#endif info->session = current->session; info->pgrp = current->pgrp;#ifdef SERIAL_DEBUG_OPEN printk("zs_open ttys%d successful...", info->line);#endif return 0;}/* Finally, routines used to initialize the serial driver. */static void show_serial_version(void){ char *revision = "$Revision: 1.68.2.2 $"; char *version, *p; version = strchr(revision, ' '); p = strchr(++version, ' '); *p = '\0'; printk("Sparc Zilog8530 serial driver version %s\n", version); *p = ' ';}/* Probe the PROM for the request zs chip number. * * Note: The Sun Voyager shows two addresses and two intr for it's * Zilogs, what the second does, I don't know. It does work * with using only the first number of each property. Also * we have a special version for sun4u. */#ifdef __sparc_v9__static struct sun_zslayout * __init get_zs(int chip){ unsigned int vaddr[2] = { 0, 0 }; unsigned long mapped_addr = 0; int busnode, seen, zsnode, sun4u_ino; static int irq = 0; if(chip < 0 || chip >= NUM_SERIAL) { prom_printf("get_zs bogon zs chip number"); prom_halt(); } if(central_bus) busnode = central_bus->child->prom_node; else busnode = prom_searchsiblings(prom_getchild(prom_root_node), "sbus"); if(busnode == 0 || busnode == -1) { prom_printf("get_zs: no zs bus to search"); prom_halt(); } zsnode = prom_getchild(busnode); seen = 0; while(zsnode) { int slave; zsnode = prom_searchsiblings(zsnode, "zs"); slave = prom_getintdefault(zsnode, "slave", -1); if((slave == chip) || (seen == chip)) { int len = prom_getproperty(zsnode, "address", (void *) vaddr, sizeof(vaddr)); if(len == -1 || central_bus != NULL) { struct sbus_bus *sbus = NULL; struct sbus_dev *sdev = NULL; /* "address" property is not guarenteed,
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -