/* * ------------------------------------------------------------ * xmbrs_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 * S structure from the interrupt chain if necessary, and we free * that IRQ if nothing is left in the chain. * ------------------------------------------------------------ */ static void xmbrs_close(struct tty_struct *tty, struct file * filp) { volatile unsigned int *uartp; struct xmb_serial *info = (struct xmb_serial *)tty->driver_data; unsigned long flags; if (!info || serial_paranoia_check(info, tty->device, "xmbrs_close")) return; save_flags_cli(flags); if (tty_hung_up_p(filp)) { restore_flags(flags); return; } #ifdef SERIAL_DEBUG_OPEN printk("xmbrs_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("xmbrs_close: bad serial port count; tty->count is 1, " "info->count is %d\n", info->count); info->count = 1; } if (--info->count < 0) { printk("xmbrs_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 |= 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 tell the * interrupt driver to stop checking the data ready bit in the * line status register. */ uartp = (volatile unsigned int *) info->addr; DisableInterrupts(uartp); 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 != tty_ldiscs[N_TTY].num) { if (tty->ldisc.close) (tty->ldisc.close)(tty); tty->ldisc = tty_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 &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); restore_flags(flags); }
static int xmbrs_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { struct xmb_serial * info = (struct xmb_serial *)tty->driver_data; unsigned int val; int retval, error; int dtr, rts; if (serial_paranoia_check(info, tty->device, "xmbrs_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 TCSBRK: /* SVID version: non-zero arg --> no break */ retval = tty_check_change(tty); if (retval) return retval; tty_wait_until_sent(tty, 0); if (!arg) send_break(info, HZ/4); /* 1/4 second */ return 0; case TCSBRKP: /* support for POSIX tcsendbreak() */ retval = tty_check_change(tty); if (retval) return retval; tty_wait_until_sent(tty, 0); send_break(info, arg ? arg*(HZ/10) : HZ/4); return 0; case TIOCGSOFTCAR: error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long)); if (error) return error; put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); return 0; case TIOCSSOFTCAR: get_user(arg, (unsigned long *) arg); tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); return 0; 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 xmb_serial)); if (error) return error; copy_to_user((struct xmb_serial *) arg, info, sizeof(struct xmb_serial)); return 0; case TIOCMGET: if ((error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned int)))) return(error); val = 0; put_user(val, (unsigned int *) arg); break; case TIOCMBIS: if ((error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned int)))) return(error); get_user(val, (unsigned int *) arg); rts = (val & TIOCM_RTS) ? 1 : -1; dtr = (val & TIOCM_DTR) ? 1 : -1; break; case TIOCMBIC: if ((error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned int)))) return(error); get_user(val, (unsigned int *) arg); rts = (val & TIOCM_RTS) ? 0 : -1; dtr = (val & TIOCM_DTR) ? 0 : -1; break; case TIOCMSET: if ((error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned int)))) return(error); get_user(val, (unsigned int *) arg); rts = (val & TIOCM_RTS) ? 1 : 0; dtr = (val & TIOCM_DTR) ? 1 : 0; break; #ifdef TIOCSET422 case TIOCSET422: get_user(val, (unsigned int *) arg); xmb_setpa(XMBPP_PA11, (val ? 0 : XMBPP_PA11)); break; case TIOCGET422: val = (xmb_getpa() & XMBPP_PA11) ? 0 : 1; put_user(val, (unsigned int *) arg); break; #endif default: return -ENOIOCTLCMD; } return 0; }
static int rs_360_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { int error; ser_info_t *info = (ser_info_t *)tty->driver_data; int retval; struct async_icount cnow; /* struct async_icount_24 cnow;*/ /* kernel counter temps */ struct serial_icounter_struct *p_cuser; /* user space */ if (serial_paranoia_check(info, tty->name, "rs_ioctl")) return -ENODEV; if ((cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; } switch (cmd) { case TCSBRK: /* SVID version: non-zero arg --> no break */ retval = tty_check_change(tty); if (retval) return retval; tty_wait_until_sent(tty, 0); if (signal_pending(current)) return -EINTR; if (!arg) { send_break(info, 250); /* 1/4 second */ if (signal_pending(current)) return -EINTR; } return 0; case TCSBRKP: /* support for POSIX tcsendbreak() */ retval = tty_check_change(tty); if (retval) return retval; tty_wait_until_sent(tty, 0); if (signal_pending(current)) return -EINTR; send_break(info, arg ? arg*100 : 250); if (signal_pending(current)) return -EINTR; return 0; case TIOCSBRK: retval = tty_check_change(tty); if (retval) return retval; tty_wait_until_sent(tty, 0); begin_break(info); return 0; case TIOCCBRK: retval = tty_check_change(tty); if (retval) return retval; end_break(info); return 0; #ifdef maybe case TIOCSERGETLSR: /* Get line status register */ return get_lsr_info(info, (unsigned int *) arg); #endif /* * 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: #ifdef modem_control local_irq_disable(); /* note the counters on entry */ cprev = info->state->icount; local_irq_enable(); while (1) { interruptible_sleep_on(&info->delta_msr_wait); /* see if a signal did it */ if (signal_pending(current)) return -ERESTARTSYS; local_irq_disable(); cnow = info->state->icount; /* atomic copy */ local_irq_enable(); 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 */ #else return 0; #endif /* * 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: local_irq_disable(); cnow = info->state->icount; local_irq_enable(); p_cuser = (struct serial_icounter_struct *) arg; /* error = put_user(cnow.cts, &p_cuser->cts); */ /* if (error) return error; */ /* error = put_user(cnow.dsr, &p_cuser->dsr); */ /* if (error) return error; */ /* error = put_user(cnow.rng, &p_cuser->rng); */ /* if (error) return error; */ /* error = put_user(cnow.dcd, &p_cuser->dcd); */ /* if (error) return error; */ 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 0; default: return -ENOIOCTLCMD; } return 0; }
static int rs_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { int error; struct NIOS_serial * info = (struct NIOS_serial *)tty->driver_data; int retval; if (serial_paranoia_check(info, tty->device, "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 TCSBRK: /* SVID version: non-zero arg --> no break */ retval = tty_check_change(tty); if (retval) return retval; tty_wait_until_sent(tty, 0); if (!arg) send_break(info, HZ/4); /* 1/4 second */ return 0; case TCSBRKP: /* support for POSIX tcsendbreak() */ retval = tty_check_change(tty); if (retval) return retval; tty_wait_until_sent(tty, 0); send_break(info, arg ? arg*(HZ/10) : HZ/4); return 0; case TIOCGSOFTCAR: error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long)); if (error) return error; put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); return 0; case TIOCSSOFTCAR: get_user(arg, (unsigned long *) arg); tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); return 0; 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 NIOS_serial)); if (error) return error; copy_to_user((struct NIOS_serial *) arg, info, sizeof(struct NIOS_serial)); return 0; default: return -ENOIOCTLCMD; } return 0; }
/* * ------------------------------------------------------------ * mcfrs_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 * S structure from the interrupt chain if necessary, and we free * that IRQ if nothing is left in the chain. * ------------------------------------------------------------ */ static void mcfrs_close(struct tty_struct *tty, struct file * filp) { volatile unsigned char *uartp; struct mcf_serial *info = (struct mcf_serial *)tty->driver_data; unsigned long flags; if (!info || serial_paranoia_check(info, tty->name, "mcfrs_close")) return; local_irq_save(flags); if (tty_hung_up_p(filp)) { local_irq_restore(flags); return; } #ifdef SERIAL_DEBUG_OPEN printk("mcfrs_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("MCFRS: bad serial port count; tty->count is 1, " "info->count is %d\n", info->count); info->count = 1; } if (--info->count < 0) { printk("MCFRS: bad serial port count for ttyS%d: %d\n", info->line, info->count); info->count = 0; } if (info->count) { local_irq_restore(flags); return; } info->flags |= ASYNC_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 != 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 tell the * interrupt driver to stop checking the data ready bit in the * line status register. */ info->imr &= ~MCFUART_UIR_RXREADY; uartp = info->addr; uartp[MCFUART_UIMR] = info->imr; #if 0 /* FIXME: do we need to keep this enabled for console?? */ if (mcfrs_console_inited && (mcfrs_console_port == info->line)) { /* Do not disable the UART */ ; } else #endif shutdown(info); mcfrs_flush_buffer(tty); tty_ldisc_flush(tty); tty->closing = 0; info->event = 0; info->port.tty = NULL; #if 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); } #endif if (info->blocked_open) { if (info->close_delay) { msleep_interruptible(jiffies_to_msecs(info->close_delay)); } wake_up_interruptible(&info->open_wait); } info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); local_irq_restore(flags); }
int tty_set_ldisc(struct tty_struct *tty, int ldisc) { int retval; struct tty_ldisc *o_ldisc, *new_ldisc; int work, o_work = 0; struct tty_struct *o_tty; new_ldisc = tty_ldisc_get(ldisc); if (IS_ERR(new_ldisc)) return PTR_ERR(new_ldisc); /* * We need to look at the tty locking here for pty/tty pairs * when both sides try to change in parallel. */ o_tty = tty->link; /* o_tty is the pty side or NULL */ /* * Check the no-op case */ if (tty->ldisc->ops->num == ldisc) { tty_ldisc_put(new_ldisc); return 0; } /* * Problem: What do we do if this blocks ? * We could deadlock here */ tty_wait_until_sent(tty, 0); mutex_lock(&tty->ldisc_mutex); /* * We could be midstream of another ldisc change which has * dropped the lock during processing. If so we need to wait. */ while (test_bit(TTY_LDISC_CHANGING, &tty->flags)) { mutex_unlock(&tty->ldisc_mutex); wait_event(tty_ldisc_wait, test_bit(TTY_LDISC_CHANGING, &tty->flags) == 0); mutex_lock(&tty->ldisc_mutex); } set_bit(TTY_LDISC_CHANGING, &tty->flags); /* * No more input please, we are switching. The new ldisc * will update this value in the ldisc open function */ tty->receive_room = 0; o_ldisc = tty->ldisc; /* * Make sure we don't change while someone holds a * reference to the line discipline. The TTY_LDISC bit * prevents anyone taking a reference once it is clear. * We need the lock to avoid racing reference takers. * * We must clear the TTY_LDISC bit here to avoid a livelock * with a userspace app continually trying to use the tty in * parallel to the change and re-referencing the tty. */ work = tty_ldisc_halt(tty); if (o_tty) o_work = tty_ldisc_halt(o_tty); /* * Wait for ->hangup_work and ->buf.work handlers to terminate. * We must drop the mutex here in case a hangup is also in process. */ mutex_unlock(&tty->ldisc_mutex); flush_scheduled_work(); mutex_lock(&tty->ldisc_mutex); if (test_bit(TTY_HUPPED, &tty->flags)) { /* We were raced by the hangup method. It will have stomped the ldisc data and closed the ldisc down */ clear_bit(TTY_LDISC_CHANGING, &tty->flags); mutex_unlock(&tty->ldisc_mutex); tty_ldisc_put(new_ldisc); return -EIO; } /* Shutdown the current discipline. */ tty_ldisc_close(tty, o_ldisc); /* Now set up the new line discipline. */ tty_ldisc_assign(tty, new_ldisc); tty_set_termios_ldisc(tty, ldisc); retval = tty_ldisc_open(tty, new_ldisc); if (retval < 0) { /* Back to the old one or N_TTY if we can't */ tty_ldisc_put(new_ldisc); tty_ldisc_restore(tty, o_ldisc); } /* At this point we hold a reference to the new ldisc and a a reference to the old ldisc. If we ended up flipping back to the existing ldisc we have two references to it */ if (tty->ldisc->ops->num != o_ldisc->ops->num && tty->ops->set_ldisc) tty->ops->set_ldisc(tty); tty_ldisc_put(o_ldisc); /* * Allow ldisc referencing to occur again */ tty_ldisc_enable(tty); if (o_tty) tty_ldisc_enable(o_tty); /* Restart the work queue in case no characters kick it off. Safe if already running */ if (work) schedule_delayed_work(&tty->buf.work, 1); if (o_work) schedule_delayed_work(&o_tty->buf.work, 1); mutex_unlock(&tty->ldisc_mutex); return retval; }
static int ctc_tty_ioctl(struct tty_struct *tty, struct file *file, uint cmd, ulong arg) { ctc_tty_info *info = (ctc_tty_info *) tty->driver_data; int error; int retval; if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_ioctl")) return -ENODEV; if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; switch (cmd) { case TCSBRK: /* SVID version: non-zero arg --> no break */ #ifdef CTC_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "%s%d ioctl TCSBRK\n", CTC_TTY_NAME, info->line); #endif retval = tty_check_change(tty); if (retval) return retval; tty_wait_until_sent(tty, 0); return 0; case TCSBRKP: /* support for POSIX tcsendbreak() */ #ifdef CTC_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "%s%d ioctl TCSBRKP\n", CTC_TTY_NAME, info->line); #endif retval = tty_check_change(tty); if (retval) return retval; tty_wait_until_sent(tty, 0); return 0; case TIOCGSOFTCAR: #ifdef CTC_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "%s%d ioctl TIOCGSOFTCAR\n", CTC_TTY_NAME, info->line); #endif error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long)); if (error) return error; put_user(C_CLOCAL(tty) ? 1 : 0, (ulong *) arg); return 0; case TIOCSSOFTCAR: #ifdef CTC_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "%s%d ioctl TIOCSSOFTCAR\n", CTC_TTY_NAME, info->line); #endif error = verify_area(VERIFY_READ, (void *) arg, sizeof(long)); if (error) return error; get_user(arg, (ulong *) arg); tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); return 0; case TIOCMGET: #ifdef CTC_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "%s%d ioctl TIOCMGET\n", CTC_TTY_NAME, info->line); #endif error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint)); if (error) return error; return ctc_tty_get_ctc_tty_info(info, (uint *) arg); case TIOCMBIS: case TIOCMBIC: case TIOCMSET: error = verify_area(VERIFY_READ, (void *) arg, sizeof(uint)); if (error) return error; return ctc_tty_set_ctc_tty_info(info, cmd, (uint *) arg); case TIOCSERGETLSR: /* Get line status register */ #ifdef CTC_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "%s%d ioctl TIOCSERGETLSR\n", CTC_TTY_NAME, info->line); #endif error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(uint)); if (error) return error; else return ctc_tty_get_lsr_info(info, (uint *) arg); default: #ifdef CTC_DEBUG_MODEM_IOCTL printk(KERN_DEBUG "UNKNOWN ioctl 0x%08x on %s%d\n", cmd, CTC_TTY_NAME, info->line); #endif return -ENOIOCTLCMD; } return 0; }
/* * ------------------------------------------------------------ * rs_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 rs_close(struct tty_struct *tty, struct file * filp) { struct async_struct * info = (struct async_struct *)tty->driver_data; unsigned long flags; int line; if (!info || serial_paranoia_check(info, tty->device, "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 |= 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); 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; line = MINOR(tty->device) - tty->driver.minor_start; serial_close_device(info); if (info->blocked_open) { if (info->close_delay) { current->state = TASK_INTERRUPTIBLE; current->timeout = jiffies + info->close_delay; schedule(); } wake_up_interruptible(&info->open_wait); } info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); restore_flags(flags); }
void sab8253x_closeS(struct tty_struct *tty, struct file * filp) { struct sab_port *port = (struct sab_port *)tty->driver_data; unsigned long flags; MOD_DEC_USE_COUNT; if (sab8253x_serial_paranoia_check(port, tty->device, "sab8253x_closeS")) { return; } if(port->open_type == OPEN_SYNC_NET) { /* port->tty field should already be NULL */ return; } save_flags(flags); cli(); --(port->count); if (tty_hung_up_p(filp)) { if(port->count == 0) /* I think the reason for the weirdness relates to freeing of structures in the tty driver */ { port->open_type = OPEN_NOT; } else if(port->count < 0) { printk(KERN_ALERT "XX20: port->count went negative.\n"); port->count = 0; port->open_type = OPEN_NOT; } restore_flags(flags); return; } #if 0 if ((tty->count == 1) && (port->count != 0)) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. port->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("sab8253x_close: bad serial port count; tty->count is 1," " port->count is %d\n", port->count); port->count = 0; } #endif if (port->count < 0) { printk(KERN_ALERT "sab8253x_close: bad serial port count for ttys%d: %d\n", port->line, port->count); port->count = 0; } if (port->count) { restore_flags(flags); return; } port->flags |= FLAG8253X_CLOSING; /* * Save the termios structure, since this port may have * separate termios for callout and dialin. */ if (port->flags & FLAG8253X_NORMAL_ACTIVE) { port->normal_termios = *tty->termios; } if (port->flags & FLAG8253X_CALLOUT_ACTIVE) { port->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 (port->closing_wait != SAB8253X_CLOSING_WAIT_NONE) { tty_wait_until_sent(tty, port->closing_wait); } /* * At this point we stop accepting input. To do this, we * disable the receive line status interrupts, and turn off * the receiver. */ #if 0 port->interrupt_mask0 |= SAB82532_IMR0_TCD; /* not needed for sync */ #endif WRITEB(port,imr0,port->interrupt_mask0); CLEAR_REG_BIT(port, mode, SAB82532_MODE_RAC); /* turn off receiver */ if (port->flags & FLAG8253X_INITIALIZED) { /* * Before we drop DTR, make sure the UART transmitter * has completely drained; this is especially * important if there is a transmit FIFO! */ sab8253x_wait_until_sent(tty, port->timeout); } sab8253x_shutdownS(port); Sab8253xCleanUpTransceiveN(port); if (tty->driver.flush_buffer) { tty->driver.flush_buffer(tty); } tty_ldisc_flush(tty); tty->closing = 0; port->event = 0; port->tty = 0; if (port->blocked_open) { if (port->close_delay) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(port->close_delay); } wake_up_interruptible(&port->open_wait); } port->flags &= ~(FLAG8253X_NORMAL_ACTIVE|FLAG8253X_CALLOUT_ACTIVE| FLAG8253X_CLOSING); wake_up_interruptible(&port->close_wait); port->open_type = OPEN_NOT; restore_flags(flags); }
static void ctc_tty_close(struct tty_struct *tty, struct file *filp) { ctc_tty_info *info = (ctc_tty_info *) tty->driver_data; unsigned long saveflags; ulong flags; ulong timeout; if (!info || ctc_tty_paranoia_check(info, tty->device, "ctc_tty_close")) return; save_flags(flags); cli(); if (tty_hung_up_p(filp)) { restore_flags(flags); #ifdef CTC_DEBUG_MODEM_OPEN printk(KERN_DEBUG "ctc_tty_close return after tty_hung_up_p\n"); #endif return; } 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(KERN_ERR "ctc_tty_close: bad port count; tty->count is 1, " "info->count is %d\n", info->count); info->count = 1; } if (--info->count < 0) { printk(KERN_ERR "ctc_tty_close: bad port count for %s%d: %d\n", CTC_TTY_NAME, info->line, info->count); info->count = 0; } if (info->count) { restore_flags(flags); #ifdef CTC_DEBUG_MODEM_OPEN printk(KERN_DEBUG "ctc_tty_close after info->count != 0\n"); #endif return; } info->flags |= CTC_ASYNC_CLOSING; /* * Save the termios structure, since this port may have * separate termios for callout and dialin. */ if (info->flags & CTC_ASYNC_NORMAL_ACTIVE) info->normal_termios = *tty->termios; tty->closing = 1; /* * 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->flags & CTC_ASYNC_INITIALIZED) { tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */ /* * Before we drop DTR, make sure the UART transmitter * has completely drained; this is especially * important if there is a transmit FIFO! */ timeout = jiffies + HZ; while (!(info->lsr & UART_LSR_TEMT)) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(20); if (time_after(jiffies,timeout)) break; } } ctc_tty_shutdown(info); if (tty->driver.flush_buffer) tty->driver.flush_buffer(tty); if (tty->ldisc.flush_buffer) tty->ldisc.flush_buffer(tty); spin_lock_irqsave(&ctc_tty_lock, saveflags); info->tty = 0; spin_unlock_irqrestore(&ctc_tty_lock, saveflags); tty->closing = 0; if (info->blocked_open) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(50); wake_up_interruptible(&info->open_wait); } info->flags &= ~(CTC_ASYNC_NORMAL_ACTIVE | CTC_ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); restore_flags(flags); #ifdef CTC_DEBUG_MODEM_OPEN printk(KERN_DEBUG "ctc_tty_close normal exit\n"); #endif }
static void gbatxt_close(struct tty_struct *tty, struct file * filp) { struct gbatxt_serial *info = (struct gbatxt_serial *)tty->driver_data; unsigned long flags; if (!info) return; save_flags(flags); cli(); if (tty_hung_up_p(filp)) { restore_flags(flags); return; } #ifdef SERIAL_DEBUG_OPEN printk("gbatxt_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("gbatxt_close: bad serial port count; tty->count is 1, " "info->count is %d\n", info->count); info->count = 1; } if (--info->count < 0) { printk("gbatxt_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 |= 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); #if 0 /* * 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. */ info->imr &= ~MCFUART_UIR_RXREADY; uartp = (volatile unsigned char *) info->addr; uartp[MCFUART_UIMR] = info->imr; #endif #if 0 /* FIXME: do we need to keep this enabled for console?? */ if (gbatxt_console_inited && (gbatxt_console_port == info->line)) { /* Do not disable the UART */ ; } else #endif 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; current->timeout = jiffies + info->close_delay; schedule(); } wake_up_interruptible(&info->open_wait); } info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); restore_flags(flags); }
/* * ------------------------------------------------------------ * dz_close() * * This routine is called when the serial port gets closed. First, we * wait for the last remaining data to be sent. Then, we turn off * the transmit enable and receive enable flags. * ------------------------------------------------------------ */ static void dz_close(struct tty_struct *tty, struct file *filp) { struct dz_serial *info = (struct dz_serial *) tty->driver_data; unsigned long flags; if (!info) return; save_flags(flags); cli(); if (tty_hung_up_p(filp)) { restore_flags(flags); return; } 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("dz_close: bad serial port count; tty->count is 1, " "info->count is %d\n", info->count); info->count = 1; } if (--info->count < 0) { printk("ds_close: bad serial port count for ttyS%02d: %d\n", info->line, info->count); 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); tty_ldisc_flush(tty); tty->closing = 0; info->event = 0; info->tty = 0; if (tty->ldisc.num != N_TTY) { if (tty->ldisc.close) (tty->ldisc.close) (tty); tty->ldisc = *(tty_ldisc_get(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); }
static void rs_close(struct tty_struct *tty, struct file * filp) { struct async_struct * info = tty->driver_data; struct serial_state *state; unsigned long flags; if (!info || serial_paranoia_check(info, tty->name, "rs_close")) return; state = info->state; local_irq_save(flags); if (tty_hung_up_p(filp)) { DBG_CNT("before DEC-hung"); local_irq_restore(flags); return; } #ifdef SERIAL_DEBUG_OPEN printk("rs_close ttys%d, count = %d\n", info->line, state->count); #endif if ((tty->count == 1) && (state->count != 1)) { /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. state->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, " "state->count is %d\n", state->count); state->count = 1; } if (--state->count < 0) { printk("rs_close: bad serial port count for ttys%d: %d\n", info->line, state->count); state->count = 0; } if (state->count) { DBG_CNT("before DEC-2"); local_irq_restore(flags); return; } info->flags |= ASYNC_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 != 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 tell the * interrupt driver to stop checking the data ready bit in the * line status register. */ info->read_status_mask &= ~UART_LSR_DR; if (info->flags & ASYNC_INITIALIZED) { /* disable receive interrupts */ custom.intena = IF_RBF; mb(); /* clear any pending receive interrupt */ custom.intreq = IF_RBF; mb(); /* * Before we drop DTR, make sure the UART transmitter * has completely drained; this is especially * important if there is a transmit FIFO! */ rs_wait_until_sent(tty, info->timeout); } shutdown(info); rs_flush_buffer(tty); tty_ldisc_flush(tty); tty->closing = 0; info->event = 0; info->tty = NULL; if (info->blocked_open) { if (info->close_delay) { msleep_interruptible(jiffies_to_msecs(info->close_delay)); } wake_up_interruptible(&info->open_wait); } info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); local_irq_restore(flags); }
/* * ------------------------------------------------------------ * rs_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 * S structure from the interrupt chain if necessary, and we free * that IRQ if nothing is left in the chain. * ------------------------------------------------------------ */ static void rs_close(struct tty_struct *tty, struct file * filp) { struct m68k_serial * info = (struct m68k_serial *)tty->driver_data; m68328_uart *uart = &uart_addr[info->line]; unsigned long flags; if (!info || serial_paranoia_check(info, tty->name, "rs_close")) return; local_irq_save(flags); if (tty_hung_up_p(filp)) { local_irq_restore(flags); return; } 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) { local_irq_restore(flags); return; } info->flags |= S_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 != S_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. */ uart->ustcnt &= ~USTCNT_RXEN; uart->ustcnt &= ~(USTCNT_RXEN | USTCNT_RX_INTR_MASK); shutdown(info); rs_flush_buffer(tty); tty_ldisc_flush(tty); tty->closing = 0; info->event = 0; info->tty = NULL; #warning "This is not and has never been valid so fix it" #if 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); } #endif if (info->blocked_open) { if (info->close_delay) { msleep_interruptible(jiffies_to_msecs(info->close_delay)); } wake_up_interruptible(&info->open_wait); } info->flags &= ~(S_NORMAL_ACTIVE|S_CLOSING); wake_up_interruptible(&info->close_wait); local_irq_restore(flags); }
static int mcfrs_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { struct mcf_serial * info = (struct mcf_serial *)tty->driver_data; int retval, error; if (serial_paranoia_check(info, tty->name, "mcfrs_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 TCSBRK: /* SVID version: non-zero arg --> no break */ retval = tty_check_change(tty); if (retval) return retval; tty_wait_until_sent(tty, 0); if (!arg) send_break(info, HZ/4); /* 1/4 second */ return 0; case TCSBRKP: /* support for POSIX tcsendbreak() */ retval = tty_check_change(tty); if (retval) return retval; tty_wait_until_sent(tty, 0); send_break(info, arg ? arg*(HZ/10) : HZ/4); return 0; case TIOCGSERIAL: if (access_ok(VERIFY_WRITE, (void *) arg, sizeof(struct serial_struct))) return get_serial_info(info, (struct serial_struct *) arg); return -EFAULT; case TIOCSSERIAL: return set_serial_info(info, (struct serial_struct *) arg); case TIOCSERGETLSR: /* Get line status register */ if (access_ok(VERIFY_WRITE, (void *) arg, sizeof(unsigned int))) return get_lsr_info(info, (unsigned int *) arg); return -EFAULT; case TIOCSERGSTRUCT: error = copy_to_user((struct mcf_serial *) arg, info, sizeof(struct mcf_serial)); if (error) return -EFAULT; return 0; #ifdef TIOCSET422 case TIOCSET422: { unsigned int val; get_user(val, (unsigned int *) arg); mcf_setpa(MCFPP_PA11, (val ? 0 : MCFPP_PA11)); break; } case TIOCGET422: { unsigned int val; val = (mcf_getpa() & MCFPP_PA11) ? 0 : 1; put_user(val, (unsigned int *) arg); break; } #endif default: return -ENOIOCTLCMD; } return 0; }
int tty_set_ldisc(struct tty_struct *tty, int ldisc) { int retval; struct tty_ldisc o_ldisc, new_ldisc; int work; unsigned long flags; struct tty_struct *o_tty; restart: /* This is a bit ugly for now but means we can break the 'ldisc is part of the tty struct' assumption later */ retval = tty_ldisc_get(ldisc, &new_ldisc); if (retval) return retval; /* * Problem: What do we do if this blocks ? */ tty_wait_until_sent(tty, 0); if (tty->ldisc.ops->num == ldisc) { tty_ldisc_put(new_ldisc.ops); return 0; } /* * No more input please, we are switching. The new ldisc * will update this value in the ldisc open function */ tty->receive_room = 0; o_ldisc = tty->ldisc; o_tty = tty->link; /* * Make sure we don't change while someone holds a * reference to the line discipline. The TTY_LDISC bit * prevents anyone taking a reference once it is clear. * We need the lock to avoid racing reference takers. * * We must clear the TTY_LDISC bit here to avoid a livelock * with a userspace app continually trying to use the tty in * parallel to the change and re-referencing the tty. */ clear_bit(TTY_LDISC, &tty->flags); if (o_tty) clear_bit(TTY_LDISC, &o_tty->flags); spin_lock_irqsave(&tty_ldisc_lock, flags); if (tty->ldisc.refcount || (o_tty && o_tty->ldisc.refcount)) { if (tty->ldisc.refcount) { /* Free the new ldisc we grabbed. Must drop the lock first. */ spin_unlock_irqrestore(&tty_ldisc_lock, flags); tty_ldisc_put(new_ldisc.ops); /* * There are several reasons we may be busy, including * random momentary I/O traffic. We must therefore * retry. We could distinguish between blocking ops * and retries if we made tty_ldisc_wait() smarter. * That is up for discussion. */ if (wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount == 0) < 0) return -ERESTARTSYS; goto restart; } if (o_tty && o_tty->ldisc.refcount) { spin_unlock_irqrestore(&tty_ldisc_lock, flags); tty_ldisc_put(o_tty->ldisc.ops); if (wait_event_interruptible(tty_ldisc_wait, o_tty->ldisc.refcount == 0) < 0) return -ERESTARTSYS; goto restart; } } /* * If the TTY_LDISC bit is set, then we are racing against * another ldisc change */ if (test_bit(TTY_LDISC_CHANGING, &tty->flags)) { struct tty_ldisc *ld; spin_unlock_irqrestore(&tty_ldisc_lock, flags); tty_ldisc_put(new_ldisc.ops); ld = tty_ldisc_ref_wait(tty); tty_ldisc_deref(ld); goto restart; } /* * This flag is used to avoid two parallel ldisc changes. Once * open and close are fine grained locked this may work better * as a mutex shared with the open/close/hup paths */ set_bit(TTY_LDISC_CHANGING, &tty->flags); if (o_tty) set_bit(TTY_LDISC_CHANGING, &o_tty->flags); spin_unlock_irqrestore(&tty_ldisc_lock, flags); /* * From this point on we know nobody has an ldisc * usage reference, nor can they obtain one until * we say so later on. */ work = cancel_delayed_work(&tty->buf.work); /* * Wait for ->hangup_work and ->buf.work handlers to terminate * MUST NOT hold locks here. */ flush_scheduled_work(); /* Shutdown the current discipline. */ if (o_ldisc.ops->close) (o_ldisc.ops->close)(tty); /* Now set up the new line discipline. */ tty_ldisc_assign(tty, &new_ldisc); tty_set_termios_ldisc(tty, ldisc); if (new_ldisc.ops->open) retval = (new_ldisc.ops->open)(tty); if (retval < 0) { tty_ldisc_put(new_ldisc.ops); tty_ldisc_restore(tty, &o_ldisc); } /* At this point we hold a reference to the new ldisc and a a reference to the old ldisc. If we ended up flipping back to the existing ldisc we have two references to it */ if (tty->ldisc.ops->num != o_ldisc.ops->num && tty->ops->set_ldisc) tty->ops->set_ldisc(tty); tty_ldisc_put(o_ldisc.ops); /* * Allow ldisc referencing to occur as soon as the driver * ldisc callback completes. */ tty_ldisc_enable(tty); if (o_tty) tty_ldisc_enable(o_tty); /* Restart it in case no characters kick it off. Safe if already running */ if (work) schedule_delayed_work(&tty->buf.work, 1); return retval; }
static int rs_ioctl(struct tty_struct *tty, struct file * file, unsigned int cmd, unsigned long arg) { int error; struct async_struct * info = (struct async_struct *)tty->driver_data; int retval; if (serial_paranoia_check(info, tty->device, "rs_ioctl")) return -ENODEV; if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT) && (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) { if (tty->flags & (1 << TTY_IO_ERROR)) return -EIO; } switch (cmd) { case TCSBRK: /* SVID version: non-zero arg --> no break */ retval = tty_check_change(tty); if (retval) return retval; tty_wait_until_sent(tty, 0); if (!arg) send_break(info, HZ/4); /* 1/4 second */ return 0; case TCSBRKP: /* support for POSIX tcsendbreak() */ retval = tty_check_change(tty); if (retval) return retval; tty_wait_until_sent(tty, 0); send_break(info, arg ? arg*(HZ/10) : HZ/4); return 0; case TIOCGSOFTCAR: error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long)); if (error) return error; put_fs_long(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); return 0; case TIOCSSOFTCAR: error = verify_area(VERIFY_READ, (void *) arg, sizeof(long)); if (error) return error; arg = get_fs_long((unsigned long *) arg); tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); return 0; case TIOCMGET: error = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned int)); if (error) return error; return get_modem_info(info, (unsigned int *) arg); case TIOCMBIS: case TIOCMBIC: case TIOCMSET: return set_modem_info(info, cmd, (unsigned int *) arg); default: return -ENOIOCTLCMD; } return 0; }