static int ptmx_open(struct inode *inode, struct file *filp) { struct tty_struct *tty; int retval; int index; nonseekable_open(inode, filp); /* We refuse fsnotify events on ptmx, since it's a shared resource */ filp->f_mode |= FMODE_NONOTIFY; retval = tty_alloc_file(filp); if (retval) return retval; /* find a device that is not in use. */ tty_lock(); index = devpts_new_index(inode); tty_unlock(); if (index < 0) { retval = index; goto err_file; } mutex_lock(&tty_mutex); tty_lock(); tty = tty_init_dev(ptm_driver, index, 1); mutex_unlock(&tty_mutex); if (IS_ERR(tty)) { retval = PTR_ERR(tty); goto out; } set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ tty_add_file(tty, filp); retval = devpts_pty_new(inode, tty->link); if (retval) goto err_release; retval = ptm_driver->ops->open(tty, filp); if (retval) goto err_release; tty_unlock(); return 0; err_release: tty_unlock(); tty_release(inode, filp); return retval; out: devpts_kill_index(inode, index); tty_unlock(); err_file: tty_free_file(filp); return retval; }
static int ptmx_open(struct inode *inode, struct file *filp) { int ret; tty_unlock(); ret = __ptmx_open(inode, filp); tty_unlock(); return ret; }
static int briq_panel_open(struct inode *ino, struct file *filep) { tty_lock(); /* enforce single access, vfd_is_open is protected by BKL */ if (vfd_is_open) { tty_unlock(); return -EBUSY; } vfd_is_open = 1; tty_unlock(); return 0; }
static int ptsdev_poll(struct file *fp, int events, struct ucred *active_cred, struct thread *td) { struct tty *tp = fp->f_data; struct pts_softc *psc = tty_softc(tp); int revents = 0; tty_lock(tp); if (psc->pts_flags & PTS_FINISHED) { /* Slave device is not opened. */ tty_unlock(tp); return ((events & (POLLIN|POLLRDNORM)) | POLLHUP); } if (events & (POLLIN|POLLRDNORM)) { /* See if we can getc something. */ if (ttydisc_getc_poll(tp) || (psc->pts_flags & PTS_PKT && psc->pts_pkt)) revents |= events & (POLLIN|POLLRDNORM); } if (events & (POLLOUT|POLLWRNORM)) { /* See if we can rint something. */ if (ttydisc_rint_poll(tp)) revents |= events & (POLLOUT|POLLWRNORM); } /* * No need to check for POLLHUP here. This device cannot be used * as a callout device, which means we always have a carrier, * because the master is. */ if (revents == 0) { /* * This code might look misleading, but the naming of * poll events on this side is the opposite of the slave * device. */ if (events & (POLLIN|POLLRDNORM)) selrecord(td, &psc->pts_outpoll); if (events & (POLLOUT|POLLWRNORM)) selrecord(td, &psc->pts_inpoll); } tty_unlock(tp); return (revents); }
static void nmdm_task_tty(void *arg, int pending __unused) { struct tty *tp, *otp; struct nmdmpart *np = arg; char c; tp = np->np_tty; tty_lock(tp); if (tty_gone(tp)) { tty_unlock(tp); return; } otp = np->np_other->np_tty; KASSERT(otp != NULL, ("NULL otp in nmdmstart")); KASSERT(otp != tp, ("NULL otp == tp nmdmstart")); if (np->np_other->np_dcd) { if (!tty_opened(tp)) { np->np_other->np_dcd = 0; ttydisc_modem(otp, 0); } } else { if (tty_opened(tp)) { np->np_other->np_dcd = 1; ttydisc_modem(otp, 1); } } /* This may happen when we are in detach process. */ if (tty_gone(otp)) { tty_unlock(otp); return; } while (ttydisc_rint_poll(otp) > 0) { if (np->np_rate && !np->np_quota) break; if (ttydisc_getc(tp, &c, 1) != 1) break; np->np_quota--; ttydisc_rint(otp, c, 0); } ttydisc_rint_done(otp); tty_unlock(tp); }
static int spk_ttyio_initialise_ldisc(struct spk_synth *synth) { int ret = 0; struct tty_struct *tty; struct ktermios tmp_termios; dev_t dev; ret = get_dev_to_use(synth, &dev); if (ret) return ret; tty = tty_kopen(dev); if (IS_ERR(tty)) return PTR_ERR(tty); if (tty->ops->open) ret = tty->ops->open(tty, NULL); else ret = -ENODEV; if (ret) { tty_unlock(tty); return ret; } clear_bit(TTY_HUPPED, &tty->flags); /* ensure hardware flow control is enabled */ get_termios(tty, &tmp_termios); if (!(tmp_termios.c_cflag & CRTSCTS)) { tmp_termios.c_cflag |= CRTSCTS; tty_set_termios(tty, &tmp_termios); /* * check c_cflag to see if it's updated as tty_set_termios may not return * error even when no tty bits are changed by the request. */ get_termios(tty, &tmp_termios); if (!(tmp_termios.c_cflag & CRTSCTS)) pr_warn("speakup: Failed to set hardware flow control\n"); } tty_unlock(tty); ret = tty_set_ldisc(tty, N_SPEAKUP); if (ret) pr_err("speakup: Failed to set N_SPEAKUP on tty\n"); return ret; }
static int ptmx_open(struct inode *inode, struct file *filp) { struct tty_struct *tty; int retval; int index; nonseekable_open(inode, filp); /* find a device that is not in use. */ tty_lock(); index = devpts_new_index(inode); tty_unlock(); if (index < 0) return index; mutex_lock(&tty_mutex); tty_lock(); tty = tty_init_dev(ptm_driver, index, 1); mutex_unlock(&tty_mutex); if (IS_ERR(tty)) { retval = PTR_ERR(tty); goto out; } set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */ tty_add_file(tty, filp); retval = devpts_pty_new(inode, tty->link); if (retval) goto out1; retval = ptm_driver->ops->open(tty, filp); if (retval) goto out2; out1: tty_unlock(); return retval; out2: tty_unlock(); tty_release(inode, filp); return retval; out: devpts_kill_index(inode, index); tty_unlock(); return retval; }
int kmioctl(dev_t dev, u_long cmd, caddr_t data, int flag, proc_t p) { int error = 0; struct tty *tp = km_tty[minor(dev)]; struct winsize *wp; tty_lock(tp); switch (cmd) { case KMIOCSIZE: wp = (struct winsize *) data; *wp = tp->t_winsize; break; case TIOCSWINSZ: /* * Prevent changing of console size -- * * this ensures that login doesn't revert to the * * termcap-defined size */ error = EINVAL; break; /* * Bodge in the CLOCAL flag as the km device is always local */ case TIOCSETA_32: case TIOCSETAW_32: case TIOCSETAF_32: { struct termios32 *t = (struct termios32 *) data; t->c_cflag |= CLOCAL; /* * No Break */ } goto fallthrough; case TIOCSETA_64: case TIOCSETAW_64: case TIOCSETAF_64: { struct user_termios *t = (struct user_termios *) data; t->c_cflag |= CLOCAL; /* * No Break */ } fallthrough: default: error = (*linesw[tp->t_line].l_ioctl) (tp, cmd, data, flag, p); if (ENOTTY != error) break; error = ttioctl_locked(tp, cmd, data, flag, p); break; } tty_unlock(tp); return (error); }
static void dcons_timeout(void *v) { struct tty *tp; struct dcons_softc *dc; int i, c, polltime; for (i = 0; i < DCONS_NPORT; i ++) { dc = &sc[i]; tp = dc->tty; tty_lock(tp); while ((c = dcons_os_checkc_nopoll(dc)) != -1) { ttydisc_rint(tp, c, 0); poll_idle = 0; } ttydisc_rint_done(tp); tty_unlock(tp); } poll_idle++; polltime = hz; if (poll_idle <= (poll_hz * DCONS_POLL_IDLE)) polltime /= poll_hz; callout_reset(&dcons_callout, polltime, dcons_timeout, tp); }
void ttyoutq_setsize(struct ttyoutq *to, struct tty *tp, size_t size) { struct ttyoutq_block *tob; to->to_quota = howmany(size, TTYOUTQ_DATASIZE); while (to->to_quota > to->to_nblocks) { /* * List is getting bigger. * Add new blocks to the tail of the list. * * We must unlock the TTY temporarily, because we need * to allocate memory. This won't be a problem, because * in the worst case, another thread ends up here, which * may cause us to allocate too many blocks, but this * will be caught by the loop below. */ tty_unlock(tp); tob = uma_zalloc(ttyoutq_zone, M_WAITOK); tty_lock(tp); TTYOUTQ_INSERT_TAIL(to, tob); } }
static void aju_io_callout(void *arg) { struct altera_jtag_uart_softc *sc = arg; struct tty *tp = sc->ajus_ttyp; tty_lock(tp); AJU_LOCK(sc); /* * It would be convenient if we could share code with aju_intr() here * by testing the control register for ALTERA_JTAG_UART_CONTROL_RI and * ALTERA_JTAG_UART_CONTROL_WI. Unfortunately, it's not clear that * this is supported, so do all the work to poll for both input and * output. */ aju_handle_input(sc, tp); aju_handle_output(sc, tp); /* * Reschedule next poll attempt. There's some argument that we should * do adaptive polling based on the expectation of I/O: is something * pending in the output buffer, or have we recently had input, but we * don't. */ callout_reset(&sc->ajus_io_callout, AJU_IO_POLLINTERVAL, aju_io_callout, sc); AJU_UNLOCK(sc); tty_unlock(tp); }
static void aju_ac_callout(void *arg) { struct altera_jtag_uart_softc *sc = arg; struct tty *tp = sc->ajus_ttyp; uint32_t v; tty_lock(tp); AJU_LOCK(sc); v = aju_control_read(sc); if (v & ALTERA_JTAG_UART_CONTROL_AC) { v &= ~ALTERA_JTAG_UART_CONTROL_AC; aju_control_write(sc, v); if (*sc->ajus_jtag_presentp == 0) { *sc->ajus_jtag_missedp = 0; *sc->ajus_jtag_presentp = 1; aju_handle_output(sc, tp); } } else if (*sc->ajus_jtag_presentp != 0) { (*sc->ajus_jtag_missedp)++; if (*sc->ajus_jtag_missedp >= AJU_JTAG_MAXMISS) { *sc->ajus_jtag_presentp = 0; aju_handle_output(sc, tp); } } callout_reset(&sc->ajus_ac_callout, AJU_AC_POLLINTERVAL, aju_ac_callout, sc); AJU_UNLOCK(sc); tty_unlock(tp); }
void tty_ldisc_release(struct tty_struct *tty, struct tty_struct *o_tty) { /* * Prevent flush_to_ldisc() from rescheduling the work for later. Then * kill any delayed work. As this is the final close it does not * race with the set_ldisc code path. */ tty_unlock(); tty_ldisc_halt(tty); tty_ldisc_flush_works(tty); tty_lock(); mutex_lock(&tty->ldisc_mutex); /* * Now kill off the ldisc */ tty_ldisc_close(tty, tty->ldisc); tty_ldisc_put(tty->ldisc); /* Force an oops if we mess this up */ tty->ldisc = NULL; /* Ensure the next open requests the N_TTY ldisc */ tty_set_termios_ldisc(tty, N_TTY); mutex_unlock(&tty->ldisc_mutex); /* This will need doing differently if we need to lock */ if (o_tty) tty_ldisc_release(o_tty, NULL); /* And the memory resources remaining (buffers, termios) will be disposed of when the kref hits zero */ }
static int ptsdev_kqfilter(struct file *fp, struct knote *kn) { struct tty *tp = fp->f_data; struct pts_softc *psc = tty_softc(tp); int error = 0; tty_lock(tp); switch (kn->kn_filter) { case EVFILT_READ: kn->kn_fop = &pts_kqops_read; knlist_add(&psc->pts_outpoll.si_note, kn, 1); break; case EVFILT_WRITE: kn->kn_fop = &pts_kqops_write; knlist_add(&psc->pts_inpoll.si_note, kn, 1); break; default: error = EINVAL; break; } tty_unlock(tp); return (error); }
void xencons_rx(char *buf, unsigned len) { int i; struct tty *tp = xccons; if (xen_console_up #ifdef DDB && !kdb_active #endif ) { tty_lock(tp); for (i = 0; i < len; i++) { #ifdef KDB kdb_alt_break(buf[i], &xc_altbrk); #endif ttydisc_rint(tp, buf[i], 0); } ttydisc_rint_done(tp); tty_unlock(tp); } else { CN_LOCK(cn_mtx); for (i = 0; i < len; i++) rbuf[RBUF_MASK(rp++)] = buf[i]; CN_UNLOCK(cn_mtx); } }
static void pty_close(struct tty_struct *tty, struct file *filp) { BUG_ON(!tty); if (tty->driver->subtype == PTY_TYPE_MASTER) WARN_ON(tty->count > 1); else { if (tty->count > 2) return; } wake_up_interruptible(&tty->read_wait); wake_up_interruptible(&tty->write_wait); tty->packet = 0; if (!tty->link) return; set_bit(TTY_OTHER_CLOSED, &tty->link->flags); wake_up_interruptible(&tty->link->read_wait); wake_up_interruptible(&tty->link->write_wait); if (tty->driver->subtype == PTY_TYPE_MASTER) { set_bit(TTY_OTHER_CLOSED, &tty->flags); #ifdef CONFIG_UNIX98_PTYS if (tty->driver == ptm_driver) devpts_pty_kill(tty->link); #endif tty_unlock(); tty_vhangup(tty->link); tty_lock(); } }
/* * cons_cinput * * Driver character input from the polled mode serial console driver calls * this routine to input a character from the serial driver into the tty * line discipline specific input processing receiv interrupt routine, * l_rint(). * * Locks: Assumes that the tty_lock() is NOT held on the tp, so a * serial driver should NOT call this function as a result * of being called from a function which already holds the * lock; ECHOE will be handled at the line discipline, if * output echo processing is going to occur. */ void cons_cinput(char ch) { struct tty *tp = km_tty[0]; /* XXX */ tty_lock(tp); (*linesw[tp->t_line].l_rint) (ch, tp); tty_unlock(tp); }
/* * One-shot output retry timeout from kmoutput(); re-calls kmoutput() at * intervals until the output queue for the tty is empty, at which point * the timeout is not rescheduled by kmoutput() * * This function must take the tty_lock() around the kmoutput() call; it * ignores the return value. */ static void kmtimeout(void *arg) { struct tty *tp = (struct tty *) arg; tty_lock(tp); (void) kmoutput(tp); tty_unlock(tp); }
static void bvm_tty_close(struct tty *tp) { tty_lock(tp); callout_stop(&bvm_timer); tty_unlock(tp); }
/** * tty_ldisc_change - change line discipline * @tty: tty to change * @disc: new line discipine number * * Change the line discipline of the tty. The tty must have an old * ldisc attached to, we must handle it properly. Sandix implement * it quite simple, but please look at linux, see how complex it is! * XXX tty shoud be locked */ int tty_ldisc_change(struct tty_struct *tty, int disc) { int ret; struct tty_ldisc *old_ldisc, *new_ldisc; BUG_ON(!tty->ldisc); if (tty->ldisc->ops->num == disc) return 0; tty_lock(tty); new_ldisc = tty_ldisc_get(tty, disc); if (IS_ERR(new_ldisc)) { tty_unlock(tty); return PTR_ERR(new_ldisc); } old_ldisc = tty->ldisc; /* Close the old one */ tty_ldisc_close(tty, old_ldisc); /* Set up the new one */ tty->ldisc = new_ldisc; tty_set_termios_ldisc(tty, disc); ret = tty_ldisc_open(tty, new_ldisc); if (ret) { /* Back to the old one or N_TTY */ tty_ldisc_put(new_ldisc); tty_ldisc_restore(tty, old_ldisc); } /* * At this point we hold a reference to the new ldisc and a * reference to the old ldisc, or we hold two references to * the old ldisc (if it was restored as part of error cleanup * above). In either case, releasing a single reference from * the old ldisc is correct. */ tty_ldisc_put(old_ldisc); tty_unlock(tty); return ret; }
static ssize_t r3964_write(struct tty_struct *tty, struct file *file, const unsigned char *data, size_t count) { struct r3964_info *pInfo = tty->disc_data; struct r3964_block_header *pHeader; struct r3964_client_info *pClient; unsigned char *new_data; TRACE_L("write request, %d characters", count); if (!pInfo) return -EIO; if (count > R3964_MTU) { if (pInfo->flags & R3964_DEBUG) { TRACE_L(KERN_WARNING "r3964_write: truncating user " "packet from %u to mtu %d", count, R3964_MTU); } count = R3964_MTU; } new_data = kmalloc(count + sizeof(struct r3964_block_header), GFP_KERNEL); TRACE_M("r3964_write - kmalloc %p", new_data); if (new_data == NULL) { if (pInfo->flags & R3964_DEBUG) { printk(KERN_ERR "r3964_write: no memory\n"); } return -ENOSPC; } pHeader = (struct r3964_block_header *)new_data; pHeader->data = new_data + sizeof(struct r3964_block_header); pHeader->length = count; pHeader->locks = 0; pHeader->owner = NULL; tty_lock(); pClient = findClient(pInfo, task_pid(current)); if (pClient) { pHeader->owner = pClient; } memcpy(pHeader->data, data, count); if (pInfo->flags & R3964_DEBUG) { dump_block(pHeader->data, count); } add_tx_queue(pInfo, pHeader); trigger_transmit(pInfo); tty_unlock(); return 0; }
static ssize_t r3964_read(struct tty_struct *tty, struct file *file, unsigned char __user * buf, size_t nr) { struct r3964_info *pInfo = tty->disc_data; struct r3964_client_info *pClient; struct r3964_message *pMsg; struct r3964_client_message theMsg; int ret; TRACE_L("read()"); tty_lock(); pClient = findClient(pInfo, task_pid(current)); if (pClient) { pMsg = remove_msg(pInfo, pClient); if (pMsg == NULL) { /* no messages available. */ if (file->f_flags & O_NONBLOCK) { ret = -EAGAIN; goto unlock; } /* block until there is a message: */ wait_event_interruptible_tty(pInfo->read_wait, (pMsg = remove_msg(pInfo, pClient))); } /* If we still haven't got a message, we must have been signalled */ if (!pMsg) { ret = -EINTR; goto unlock; } /* deliver msg to client process: */ theMsg.msg_id = pMsg->msg_id; theMsg.arg = pMsg->arg; theMsg.error_code = pMsg->error_code; ret = sizeof(struct r3964_client_message); kfree(pMsg); TRACE_M("r3964_read - msg kfree %p", pMsg); if (copy_to_user(buf, &theMsg, ret)) { ret = -EFAULT; goto unlock; } TRACE_PS("read - return %d", ret); goto unlock; } ret = -EPERM; unlock: tty_unlock(); return ret; }
int kmwrite(dev_t dev, struct uio *uio, int ioflag) { int ret; struct tty *tp = km_tty[minor(dev)]; tty_lock(tp); ret = (*linesw[tp->t_line].l_write) (tp, uio, ioflag); tty_unlock(tp); return (ret); }
int tty_close() { if(!tty_port) return ME_CLOSE; DEBUG(('M',2,"tty_close")); fflush(stdin);fflush(stdout); tty_cooked(); fclose(stdin);fclose(stdout); tty_unlock(tty_port); xfree(tty_port); return ME_OK; }
void uart_tty_intr(void *arg) { struct uart_softc *sc = arg; struct tty *tp; int c, err = 0, pend, sig, xc; if (sc->sc_leaving) return; pend = atomic_readandclear_32(&sc->sc_ttypend); if (!(pend & SER_INT_MASK)) return; tp = sc->sc_u.u_tty.tp; tty_lock(tp); if (pend & SER_INT_RXREADY) { while (!uart_rx_empty(sc) && !sc->sc_isquelch) { xc = uart_rx_peek(sc); c = xc & 0xff; if (xc & UART_STAT_FRAMERR) err |= TRE_FRAMING; if (xc & UART_STAT_OVERRUN) err |= TRE_OVERRUN; if (xc & UART_STAT_PARERR) err |= TRE_PARITY; if (ttydisc_rint(tp, c, err) != 0) { sc->sc_isquelch = 1; if ((tp->t_termios.c_cflag & CRTS_IFLOW) && !sc->sc_hwiflow) UART_SETSIG(sc, SER_DRTS); } else uart_rx_next(sc); } } if (pend & SER_INT_BREAK) ttydisc_rint(tp, 0, TRE_BREAK); if (pend & SER_INT_SIGCHG) { sig = pend & SER_INT_SIGMASK; if (sig & SER_DDCD) ttydisc_modem(tp, sig & SER_DCD); if (sig & SER_DCTS) uart_tty_outwakeup(tp); } if (pend & SER_INT_TXIDLE) uart_tty_outwakeup(tp); ttydisc_rint_done(tp); tty_unlock(tp); }
int kmclose(dev_t dev, int flag, __unused int mode, __unused proc_t p) { int ret; struct tty *tp = km_tty[minor(dev)]; tty_lock(tp); ret = (*linesw[tp->t_line].l_close) (tp, flag); ttyclose(tp); tty_unlock(tp); return (ret); }
static void mambo_timeout(void *v) { int c; tty_lock(tp); while ((c = mambo_cngetc(NULL)) != -1) ttydisc_rint(tp, c, 0); ttydisc_rint_done(tp); tty_unlock(tp); callout_reset(&mambo_callout, polltime, mambo_timeout, NULL); }
void spk_ttyio_release(void) { if (!speakup_tty) return; tty_lock(speakup_tty); if (speakup_tty->ops->close) speakup_tty->ops->close(speakup_tty, NULL); tty_ldisc_flush(speakup_tty); tty_unlock(speakup_tty); tty_kclose(speakup_tty); }
static void bvm_timeout(void *v) { struct tty *tp; int c; tp = (struct tty *)v; tty_lock(tp); while ((c = bvm_cngetc(NULL)) != -1) ttydisc_rint(tp, c, 0); ttydisc_rint_done(tp); tty_unlock(tp); bvm_timeouthandle = timeout(bvm_timeout, tp, polltime); }
static int get_serial_info(struct tty_struct *tty, struct serial_struct *ss) { struct serial_state *state = tty->driver_data; tty_lock(tty); ss->line = tty->index; ss->port = state->port; ss->flags = state->tport.flags; ss->xmit_fifo_size = state->xmit_fifo_size; ss->baud_base = state->baud_base; ss->close_delay = state->tport.close_delay; ss->closing_wait = state->tport.closing_wait; ss->custom_divisor = state->custom_divisor; tty_unlock(tty); return 0; }