📄 zs.c
字号:
return 0; case TIOCGSOFTCAR: if (put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg)) return -EFAULT; return 0; case TIOCSSOFTCAR: if (get_user(arg, (unsigned long *) arg)) return -EFAULT; tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); return 0; case TIOCMGET: return get_modem_info(info, (unsigned int *) arg); case TIOCMBIS: case TIOCMBIC: case TIOCMSET: return set_modem_info(info, cmd, (unsigned int *) arg); case TIOCGSERIAL: return get_serial_info(info, (struct serial_struct *) arg); case TIOCSSERIAL: return set_serial_info(info, (struct serial_struct *) arg); case TIOCSERGETLSR: /* Get line status register */ return get_lsr_info(info, (unsigned int *) arg); case TIOCSERGSTRUCT: if (copy_to_user((struct sun_serial *) arg, info, sizeof(struct sun_serial))) return -EFAULT; return 0; default: return -ENOIOCTLCMD; } return 0;}static void zs_set_termios(struct tty_struct *tty, struct termios *old_termios){ struct sun_serial *info = (struct sun_serial *) tty->driver_data; if (tty->termios->c_cflag == old_termios->c_cflag) return; change_speed(info); if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { 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);}/* * ------------------------------------------------------------ * 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; } 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.61 $"; 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, * everything in I/O is implicitly mapped * anyways by our clever TLB miss handling * scheme, so don't fail here. -DaveM */ if (central_bus == NULL) { for_each_sbus(sbus) { for_each_sbusdev(sdev, sbus) { if (sdev->prom_node == zsnode) goto found; } } } found: if (sdev == NULL && central_bus == NULL) prom_halt(); if (central_bus == NULL) { mapped_addr = sbus_ioremap(&sdev->resource[0], 0, PAGE_SIZE, "Zilog Registers"); } else { struct linux_prom_registers zsregs[1]; int err; err = prom_getproperty(zsnode, "reg", (char *)&zsregs[0], sizeof(zsregs)); if (err == -1) { prom_printf("ZS: Cannot map Zilog regs.\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -