📄 sab82532.c
字号:
if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; } switch (cmd) { case TIOCGSOFTCAR: return put_user(C_CLOCAL(tty) ? 1 : 0, (int *) arg); case TIOCSSOFTCAR: if (get_user(arg, (unsigned int *) 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 sab82532 *) arg, info, sizeof(struct sab82532))) return -EFAULT; return 0; /* * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change * - mask passed in arg for lines of interest * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) * Caller should use TIOCGICOUNT to see which one it was */ case TIOCMIWAIT: cli(); /* note the counters on entry */ cprev = info->icount; sti(); while (1) { interruptible_sleep_on(&info->delta_msr_wait); /* see if a signal did it */ if (signal_pending(current)) return -ERESTARTSYS; cli(); cnow = info->icount; /* atomic copy */ sti(); if (cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && cnow.dcd == cprev.dcd && cnow.cts == cprev.cts) return -EIO; /* no change => error */ if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { return 0; } cprev = cnow; } /* NOTREACHED */ /* * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) * Return: write counters to the user passed counter struct * NB: both 1->0 and 0->1 transitions are counted except for * RI where only 0->1 is counted. */ case TIOCGICOUNT: cli(); cnow = info->icount; sti(); p_cuser = (struct serial_icounter_struct *) arg; if (put_user(cnow.cts, &p_cuser->cts) || put_user(cnow.dsr, &p_cuser->dsr) || put_user(cnow.rng, &p_cuser->rng) || put_user(cnow.dcd, &p_cuser->dcd)) return -EFAULT; return 0; default: return -ENOIOCTLCMD; } return 0;}static void sab82532_set_termios(struct tty_struct *tty, struct termios *old_termios){ struct sab82532 *info = (struct sab82532 *)tty->driver_data; if ( (tty->termios->c_cflag == old_termios->c_cflag) && ( RELEVANT_IFLAG(tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) return; change_speed(info); /* Handle transition to B0 status */ if ((old_termios->c_cflag & CBAUD) && !(tty->termios->c_cflag & CBAUD)) { writeb(readb(&info->regs->w.mode) | SAB82532_MODE_FRTS, &info->regs->w.mode); writeb(readb(&info->regs->w.mode) | SAB82532_MODE_RTS, &info->regs->w.mode); writeb(readb(&info->regs->w.pvr) | info->pvr_dtr_bit, &info->regs->w.pvr); } /* Handle transition away from B0 status */ if (!(old_termios->c_cflag & CBAUD) && (tty->termios->c_cflag & CBAUD)) { writeb(readb(&info->regs->w.pvr) & ~(info->pvr_dtr_bit), &info->regs->w.pvr); if (tty->termios->c_cflag & CRTSCTS) { writeb(readb(&info->regs->w.mode) & ~(SAB82532_MODE_RTS), &info->regs->w.mode); writeb(readb(&info->regs->w.mode) | SAB82532_MODE_FRTS, &info->regs->w.mode); } else if (test_bit(TTY_THROTTLED, &tty->flags)) { writeb(readb(&info->regs->w.mode) & ~(SAB82532_MODE_FRTS | SAB82532_MODE_RTS), &info->regs->w.mode); } else { writeb(readb(&info->regs->w.mode) & ~(SAB82532_MODE_FRTS), &info->regs->w.mode); writeb(readb(&info->regs->w.mode) | SAB82532_MODE_RTS, &info->regs->w.mode); } } /* Handle turning off CRTSCTS */ if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) { tty->hw_stopped = 0; sab82532_start(tty); }}/* * ------------------------------------------------------------ * sab82532_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 * async structure from the interrupt chain if necessary, and we free * that IRQ if nothing is left in the chain. * ------------------------------------------------------------ */static void sab82532_close(struct tty_struct *tty, struct file * filp){ struct sab82532 *info = (struct sab82532 *)tty->driver_data; unsigned long flags; if (!info || serial_paranoia_check(info, tty->device, "sab82532_close")) return; save_flags(flags); cli(); if (tty_hung_up_p(filp)) { MOD_DEC_USE_COUNT; restore_flags(flags); return; }#ifdef SERIAL_DEBUG_OPEN printk("sab82532_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("sab82532_close: bad serial port count; tty->count is 1," " info->count is %d\n", info->count); info->count = 1; } if (--info->count < 0) { printk("sab82532_close: bad serial port count for ttys%d: %d\n", info->line, info->count); info->count = 0; } if (info->count) { MOD_DEC_USE_COUNT; restore_flags(flags); return; } info->flags |= ASYNC_CLOSING; /* * Save the termios structure, since this port may have * separate termios for callout and dialin. */ if (info->flags & ASYNC_NORMAL_ACTIVE) info->normal_termios = *tty->termios; if (info->flags & ASYNC_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 != ASYNC_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 turn off * the receiver. */ info->interrupt_mask0 |= SAB82532_IMR0_TCD; writeb(info->interrupt_mask0, &info->regs->w.imr0); if (info->flags & ASYNC_INITIALIZED) { /* * Before we drop DTR, make sure the UART transmitter * has completely drained; this is especially * important if there is a transmit FIFO! */ sab82532_wait_until_sent(tty, info->timeout); } 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 (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(info->close_delay); } wake_up_interruptible(&info->open_wait); } info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); MOD_DEC_USE_COUNT; restore_flags(flags);}/* * sab82532_wait_until_sent() --- wait until the transmitter is empty */static void sab82532_wait_until_sent(struct tty_struct *tty, int timeout){ struct sab82532 *info = (struct sab82532 *)tty->driver_data; unsigned long orig_jiffies, char_time; if (serial_paranoia_check(info,tty->device,"sab82532_wait_until_sent")) return; /* * 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. * * Note: we have to use pretty tight timings here to satisfy * the NIST-PCTS. */ 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(char_time, timeout);#ifdef SERIAL_DEBUG_WAIT_UNTIL_SENT printk("In sab82532_wait_until_sent(%d) check=%lu " "xmit_cnt = %ld, alls = %d (jiff=%lu)...\n", timeout, char_time, CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE), test_bit(SAB82532_ALLS, &info->irqflags), jiffies);#endif orig_jiffies = jiffies; while ((info->xmit.head != info->xmit.tail) || !test_bit(SAB82532_ALLS, &info->irqflags)) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(char_time); if (signal_pending(current)) break; if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; }#ifdef SERIAL_DEBUG_WAIT_UNTIL_SENT printk("xmit_cnt = %ld, alls = %d (jiff=%lu)...done\n", CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE), test_bit(SAB82532_ALLS, &info->irqflags), jiffies);#endif}/* * sab82532_hangup() --- called by tty_hangup() when a hangup is signaled. */static void sab82532_hangup(struct tty_struct *tty){ struct sab82532 * info = (struct sab82532 *)tty->driver_data; if (serial_paranoia_check(info, tty->device, "sab82532_hangup")) return;#ifdef CONFIG_SERIAL_CONSOLE if (info->is_console) return;#endif sab82532_flush_buffer(tty); shutdown(info); info->event = 0; info->count = 0; info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); info->tty = 0; wake_up_interruptible(&info->open_wait);}/* * ------------------------------------------------------------ * sab82532_open() and friends * ------------------------------------------------------------ */static int block_til_ready(struct tty_struct *tty, struct file * filp, struct sab82532 *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 (tty_hung_up_p(filp) || (info->flags & ASYNC_CLOSING)) { if (info->flags & ASYNC_CLOSING) interruptible_sleep_on(&info->close_wait);#ifdef SERIAL_DO_RESTART if (info->flags & ASYNC_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 & ASYNC_NORMAL_ACTIVE) return -EBUSY; if ((info->flags & ASYNC_CALLOUT_ACTIVE) && (info->flags & ASYNC_SESSION_LOCKOUT) && (info->session != current->session)) return -EBUSY; if ((info->flags & ASYNC_CALLOUT_ACTIVE) && (info->flags & ASYNC_PGRP_LOCKOUT) && (info->pgrp != current->pgrp)) return -EBUSY; info->flags |= ASYNC_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 & ASYNC_CALLOUT_ACTIVE) return -EBUSY; info->flags |= ASYNC_NORMAL_ACTIVE; return 0; } if (info->flags & ASYNC_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 * sab82532_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 & ASYNC_CALLOUT_ACTIVE) && (tty->termios->c_cflag & CBAUD)) { writeb(readb(&info->regs->rw.pvr) & ~(info->pvr_dtr_bit), &info->regs->rw.pvr); writeb(readb(&info->regs->rw.mode) | SAB82532_MODE_FRTS, &info->regs->rw.mode); writeb(readb(&info->regs->rw.mode) & ~(SAB82532_MODE_RTS), &info->regs->rw.mode); } sti(); set_current_state(TASK_INTERRUPTIBLE); if (tty_hung_up_p(filp) || !(info->flags & ASYNC_INITIALIZED)) {#ifdef SERIAL_DO_RESTART if (info->flags & ASYNC_HUP_NOTIFY) retval = -EAGAIN; else retval = -ERESTARTSYS; #else retval = -EAGAIN;#endif break; } if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && !(info->flags & ASYNC_CLOSING) && (do_clocal || !(readb(&info->regs->r.vstr) & SAB82532_VSTR_CD))) break; if (signal_pending(current)) { retval = -ERESTARTSYS; break; }#ifdef SERIAL_DEBUG_OPEN printk("block_til_ready blocking: ttyS%d, count = %d, flags = %x, clocal = %d, vstr = %02x\n", info->line, info->count, info->flags, do_clocal, readb(&info->regs->r.vstr));#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 |= 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 int sab82532_open(struct tty_struct *tty, struct file * filp){ struct sab82532 *info = sab82532_chain; int retval, line; unsigned long page;#ifdef SERIAL_DEBUG_OPEN printk("sab82532_open: count = %d\n", info->count);#endif line = MINOR(tty->device) - tty->driver.minor_start; if ((line < 0) || (line >= NR_PORTS)) return -ENODEV; while (info) { if (info->line == line) break; info = info->next; } if (!info) { printk("sab82532_open: can't find info for line %d\n", line); return -ENODEV; } if (serial_paranoia_check(info, tty->device, "sab82532_open")) return -ENODEV;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -