zs.c
来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,301 行 · 第 1/4 页
C
2,301 行
* release the bus after transmitting. This must be done when * the transmit shift register is empty, not be done when the * transmit holding register is empty. This functionality * allows an RS485 driver to be written in user space. */static int get_lsr_info(struct dec_serial * info, unsigned int *value){ unsigned char status; cli(); status = read_zsreg(info->zs_channel, 0); sti(); put_user(status,value); return 0;}static int rs_tiocmget(struct tty_struct *tty, struct file *file){ struct dec_serial * info = (struct dec_serial *)tty->driver_data; unsigned char control, status_a, status_b; unsigned int result; if (info->hook) return -ENODEV; if (serial_paranoia_check(info, tty->name, __FUNCTION__)) return -ENODEV; if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; if (info->zs_channel == info->zs_chan_a) result = 0; else { cli(); control = info->zs_chan_a->curregs[5]; status_a = read_zsreg(info->zs_chan_a, 0); status_b = read_zsreg(info->zs_channel, 0); sti(); result = ((control & RTS) ? TIOCM_RTS: 0) | ((control & DTR) ? TIOCM_DTR: 0) | ((status_b & DCD) ? TIOCM_CAR: 0) | ((status_a & DCD) ? TIOCM_RNG: 0) | ((status_a & SYNC_HUNT) ? TIOCM_DSR: 0) | ((status_b & CTS) ? TIOCM_CTS: 0); } return result;}static int rs_tiocmset(struct tty_struct *tty, struct file *file, unsigned int set, unsigned int clear){ struct dec_serial * info = (struct dec_serial *)tty->driver_data; int error; unsigned int arg, bits; if (info->hook) return -ENODEV; if (serial_paranoia_check(info, tty->name, __FUNCTION__)) return -ENODEV; if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; if (info->zs_channel == info->zs_chan_a) return 0; cli(); if (set & TIOCM_RTS) info->zs_chan_a->curregs[5] |= RTS; if (set & TIOCM_DTR) info->zs_chan_a->curregs[5] |= DTR; if (clear & TIOCM_RTS) info->zs_chan_a->curregs[5] &= ~RTS; if (clear & TIOCM_DTR) info->zs_chan_a->curregs[5] &= ~DTR; write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]); sti(); return 0;}/* * rs_break - turn transmit break condition on/off */static void rs_break(struct tty_struct *tty, int break_state){ struct dec_serial *info = (struct dec_serial *) tty->driver_data; unsigned long flags; if (serial_paranoia_check(info, tty->name, "rs_break")) return; if (!info->port) return; save_flags(flags); cli(); if (break_state == -1) info->zs_channel->curregs[5] |= SND_BRK; else info->zs_channel->curregs[5] &= ~SND_BRK; write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]); restore_flags(flags);}static int rs_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg){ int error; struct dec_serial * info = (struct dec_serial *)tty->driver_data; if (info->hook) return -ENODEV; if (serial_paranoia_check(info, tty->name, "rs_ioctl")) return -ENODEV; if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; } switch (cmd) { case TIOCGSERIAL: error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct serial_struct)); if (error) return error; 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 */ error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned int)); if (error) return error; else return get_lsr_info(info, (unsigned int *) arg); case TIOCSERGSTRUCT: error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct dec_serial)); if (error) return error; copy_from_user((struct dec_serial *) arg, info, sizeof(struct dec_serial)); return 0; default: return -ENOIOCTLCMD; } return 0;}static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios){ struct dec_serial *info = (struct dec_serial *)tty->driver_data; int was_stopped; if (tty->termios->c_cflag == old_termios->c_cflag) return; was_stopped = info->tx_stopped; change_speed(info); if (was_stopped && !info->tx_stopped) rs_start(tty);}/* * ------------------------------------------------------------ * rs_close() * * This routine is called when the serial port gets closed. * Wait for the last remaining data to be sent. * ------------------------------------------------------------ */static void rs_close(struct tty_struct *tty, struct file * filp){ struct dec_serial * info = (struct dec_serial *)tty->driver_data; unsigned long flags; if (!info || serial_paranoia_check(info, tty->name, "rs_close")) return; save_flags(flags); cli(); if (tty_hung_up_p(filp)) { restore_flags(flags); return; } #ifdef SERIAL_DEBUG_OPEN printk("rs_close ttyS%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("rs_close: bad serial port count; tty->count is 1, " "info->count is %d\n", info->count); info->count = 1; } if (--info->count < 0) { printk("rs_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; /* * 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 receiver and receive interrupts. */ info->zs_channel->curregs[3] &= ~RxENABLE; write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]); info->zs_channel->curregs[1] = 0; /* disable any rx ints */ write_zsreg(info->zs_channel, 1, info->zs_channel->curregs[1]); ZS_CLEARFIFO(info->zs_channel); if (info->flags & ZILOG_INITIALIZED) { /* * Before we drop DTR, make sure the SCC transmitter * has completely drained. */ rs_wait_until_sent(tty, info->timeout); } shutdown(info); if (tty->driver->flush_buffer) tty->driver->flush_buffer(tty); tty_ldisc_flush(tty); tty->closing = 0; 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 &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CLOSING); wake_up_interruptible(&info->close_wait); restore_flags(flags);}/* * rs_wait_until_sent() --- wait until the transmitter is empty */static void rs_wait_until_sent(struct tty_struct *tty, int timeout){ struct dec_serial *info = (struct dec_serial *) tty->driver_data; unsigned long orig_jiffies, char_time; if (serial_paranoia_check(info, tty->name, "rs_wait_until_sent")) return; orig_jiffies = jiffies; /* * Set the check interval to be 1/5 of the estimated time to * send a single character, and make it at least 1. The check * interval should also be less than the timeout. */ char_time = (info->timeout - HZ/50) / info->xmit_fifo_size; char_time = char_time / 5; if (char_time == 0) char_time = 1; if (timeout) char_time = min_t(unsigned long, char_time, timeout); while ((read_zsreg(info->zs_channel, 1) & Tx_BUF_EMP) == 0) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(char_time); if (signal_pending(current)) break; if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; } current->state = TASK_RUNNING;}/* * rs_hangup() --- called by tty_hangup() when a hangup is signaled. */void rs_hangup(struct tty_struct *tty){ struct dec_serial * info = (struct dec_serial *)tty->driver_data; if (serial_paranoia_check(info, tty->name, "rs_hangup")) return; rs_flush_buffer(tty); shutdown(info); info->event = 0; info->count = 0; info->flags &= ~ZILOG_NORMAL_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 dec_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 & ZILOG_CLOSING) { interruptible_sleep_on(&info->close_wait);#ifdef SERIAL_DO_RESTART return ((info->flags & ZILOG_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);#else return -EAGAIN;#endif } /* * If this is a callout device, then just make sure the normal * device isn't being used. */ /* * 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))) { info->flags |= ZILOG_NORMAL_ACTIVE; return 0; } 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 * rs_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 (tty->termios->c_cflag & CBAUD) zs_rtsdtr(info, RTS | DTR, 1); sti(); set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ZILOG_INITIALIZED)) {#ifdef SERIAL_DO_RESTART if (info->flags & ZILOG_HUP_NOTIFY) retval = -EAGAIN; else retval = -ERESTARTSYS; #else retval = -EAGAIN;#endif break; } if (!(info->flags & ZILOG_CLOSING) && (do_clocal || (read_zsreg(info->zs_channel, 0) & 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 (!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 rs_open(struct tty_struct *tty, struct file * filp){ struct dec_serial *info; int retval, line; line = tty->index; if ((line < 0) || (line >= zs_channels_found)) return -ENODEV; info = zs_soft + line; if (info->hook) return -ENODEV; if (serial_paranoia_check(info, tty->name, "rs_open")) return -ENODEV;#ifdef SERIAL_DEBUG_OPEN printk("rs_open %s, count = %d\n", tty->name, info->count);#endif info->count++; tty->driver_data = info; info->tty = tty; /* * If the port is the middle of closing, bail out now */ if (tty_hung_up_p(filp) || (info->flags & ZILOG_CLOSING)) { if (info->flags & ZILOG_CLOSING) interruptible_sleep_on(&info->close_wait);#ifdef SERIAL_DO_RESTART return ((info->flags & ZILOG_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);#else return -EAGAIN;#endif } /* * Start up serial port */ retval = zs_startup(info); if (retval) return retval; retval = block_til_ready(tty, filp, info); if (retval) {#ifdef SERIAL_DEBUG_OPEN printk("rs_open returning after block_til_ready with %d\n", retval);#endif return retval; }#ifdef CONFIG_SERIAL_CONSOLE if (sercons.cflag && sercons.index == line) { tty->termios->c_cflag = sercons.cflag; sercons.cflag = 0; change_speed(info); }#endif#ifdef SERIAL_DEBUG_OPEN printk("rs_open %s successful...", tty->name);#endif/* tty->low_latency = 1; */ return 0;}/* Finally, routines used to initialize the serial driver. */static void __init show_serial_version(void){ printk("DECstation Z8530 serial driver version 0.05\n");}/* Initialize Z8530s zs_channels */static void __init probe_sccs(void){ struct dec_serial **pp; int i, n, n_chips = 0, n_channels, chip, channel; /* * did we get here by accident? */ if(!BUS_PRESENT) { printk("Not on JUNKIO machine, skipping probe_sccs\n"); return; } /* * When serial console is activated, tc_init has not been called yet * and system_base is undefined. Unfortunately we have to hardcode * system_base for this case :-(. HK */ switch(mips_machtype) {#ifdef CONFIG_MACH_DECSTATION case MACH_DS5000_2X0: system_base = 0xbf800000; n_chips = 2; zs_parms = &ds_parms; break; case MACH_DS5000_1XX: system_base = 0xbc000000; n_chips = 2; zs_parms = &ds_parms; break; case MACH_DS5000_XX: system_base = 0xbc000000; n_chips = 1; zs_parms = &ds_parms; break;#endif#ifdef CONFIG_BAGET_MIPS case MACH_BAGET202: system_base = UNI_IO_BASE; n_chips = 2; zs_parms = &baget_parms; zs_init_regs[2] = 0x8; break;#endif default: panic("zs: unsupported bus"); } if (!zs_parms) panic("zs: uninitialized parms"); pp = &zs_chain; n_channels = 0; for (chip = 0; chip < n_chips; chip++) { for (channel = 0; channel <= 1; channel++) { /* * The sccs reside on the high byte of the 16 bit IOBUS */ zs_channels[n_channels].control = (volatile unsigned char *)system_base + (0 == chip ? zs_parms->scc0 : zs_parms->scc1) + (0 == channel ? zs_parms->channel_a_offset : zs_parms->channel_b_offset); zs_channels[n_channels].data = zs_channels[n_channels].control + 4;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?