diff options
author | Kristina Martšenko <kristina.martsenko@gmail.com> | 2014-07-01 02:14:02 +0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-06-30 23:23:41 -0700 |
commit | 19b1e7695be8cbdf14e85ddefc9c5a9d3e88bdfd (patch) | |
tree | 62931391f54a6f3134ea3bbba60e703f26511912 /drivers/staging/dgrp/dgrp_tty.c | |
parent | 929b2d483d9a3dc5680e83e444cb99061d57d547 (diff) |
staging: dgrp: remove driver
Remove the driver as it hasn't been cleaned up and it doesn't look like
anyone is going to work on it anymore. This can be reverted if someone
wants to work to fix the remaining issues the driver has.
Signed-off-by: Kristina Martšenko <kristina.martsenko@gmail.com>
Cc: Bill Pemberton <wfp5p@worldbroken.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/staging/dgrp/dgrp_tty.c')
-rw-r--r-- | drivers/staging/dgrp/dgrp_tty.c | 3337 |
1 files changed, 0 insertions, 3337 deletions
diff --git a/drivers/staging/dgrp/dgrp_tty.c b/drivers/staging/dgrp/dgrp_tty.c deleted file mode 100644 index 30d26029b21e..000000000000 --- a/drivers/staging/dgrp/dgrp_tty.c +++ /dev/null @@ -1,3337 +0,0 @@ -/* - * - * Copyright 1999 Digi International (www.digi.com) - * Gene Olson <Gene_Olson at digi dot com> - * James Puzzo <jamesp at digi dot com> - * Jeff Randall - * Scott Kilau <scottk at digi dot com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED; without even the - * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR - * PURPOSE. See the GNU General Public License for more details. - * - */ - -/* - * - * Filename: - * - * dgrp_tty.c - * - * Description: - * - * This file implements the tty driver functionality for the - * RealPort driver software. - * - * Author: - * - * James A. Puzzo - * Ann-Marie Westgate - * - */ - -#include <linux/slab.h> -#include <linux/tty.h> -#include <linux/tty_flip.h> -#include <linux/device.h> -#include <linux/sched.h> -#include <linux/uaccess.h> - -#include "dgrp_common.h" - -#ifndef _POSIX_VDISABLE -#define _POSIX_VDISABLE ('\0') -#endif - -/* - * forward declarations - */ - -static void drp_param(struct ch_struct *); -static void dgrp_tty_close(struct tty_struct *, struct file *); - -/* ioctl helper functions */ -static int set_modem_info(struct ch_struct *, unsigned int, unsigned int *); -static int get_modem_info(struct ch_struct *, unsigned int *); -static void dgrp_set_custom_speed(struct ch_struct *, int); -static int dgrp_tty_digigetedelay(struct tty_struct *, int *); -static int dgrp_tty_digisetedelay(struct tty_struct *, int *); -static int dgrp_send_break(struct ch_struct *, int); - -static ushort tty_to_ch_flags(struct tty_struct *, char); -static tcflag_t ch_to_tty_flags(unsigned short, char); - -static void dgrp_tty_input_start(struct tty_struct *); -static void dgrp_tty_input_stop(struct tty_struct *); - -static void drp_wmove(struct ch_struct *, int, void*, int); - -static int dgrp_tty_open(struct tty_struct *, struct file *); -static void dgrp_tty_close(struct tty_struct *, struct file *); -static int dgrp_tty_write(struct tty_struct *, const unsigned char *, int); -static int dgrp_tty_write_room(struct tty_struct *); -static void dgrp_tty_flush_buffer(struct tty_struct *); -static int dgrp_tty_chars_in_buffer(struct tty_struct *); -static int dgrp_tty_ioctl(struct tty_struct *, unsigned int, unsigned long); -static void dgrp_tty_set_termios(struct tty_struct *, struct ktermios *); -static void dgrp_tty_stop(struct tty_struct *); -static void dgrp_tty_start(struct tty_struct *); -static void dgrp_tty_throttle(struct tty_struct *); -static void dgrp_tty_unthrottle(struct tty_struct *); -static void dgrp_tty_hangup(struct tty_struct *); -static int dgrp_tty_put_char(struct tty_struct *, unsigned char); -static int dgrp_tty_tiocmget(struct tty_struct *); -static int dgrp_tty_tiocmset(struct tty_struct *, unsigned int, unsigned int); -static int dgrp_tty_send_break(struct tty_struct *, int); -static void dgrp_tty_send_xchar(struct tty_struct *, char); - -/* - * tty defines - */ -#define SERIAL_TYPE_NORMAL 1 -#define SERIAL_TYPE_CALLOUT 2 -#define SERIAL_TYPE_XPRINT 3 - - -/* - * tty globals/statics - */ - - -#define PORTSERVER_DIVIDEND 1843200 - -/* - * Default transparent print information. - */ -static struct digi_struct digi_init = { - .digi_flags = DIGI_COOK, /* Flags */ - .digi_maxcps = 100, /* Max CPS */ - .digi_maxchar = 50, /* Max chars in print queue */ - .digi_bufsize = 100, /* Printer buffer size */ - .digi_onlen = 4, /* size of printer on string */ - .digi_offlen = 4, /* size of printer off string */ - .digi_onstr = "\033[5i", /* ANSI printer on string */ - .digi_offstr = "\033[4i", /* ANSI printer off string */ - .digi_term = "ansi" /* default terminal type */ -}; - -/* - * Define a local default termios struct. All ports will be created - * with this termios initially. - * - * This defines a raw port at 9600 baud, 8 data bits, no parity, - * 1 stop bit. - */ -static struct ktermios DefaultTermios = { - .c_iflag = (ICRNL | IXON), - .c_oflag = (OPOST | ONLCR), - .c_cflag = (B9600 | CS8 | CREAD | HUPCL | CLOCAL), - .c_lflag = (ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL - | ECHOKE | IEXTEN), - .c_cc = INIT_C_CC, - .c_line = 0, -}; - -/* Define our tty operations struct */ -static const struct tty_operations dgrp_tty_ops = { - .open = dgrp_tty_open, - .close = dgrp_tty_close, - .write = dgrp_tty_write, - .write_room = dgrp_tty_write_room, - .flush_buffer = dgrp_tty_flush_buffer, - .chars_in_buffer = dgrp_tty_chars_in_buffer, - .flush_chars = NULL, - .ioctl = dgrp_tty_ioctl, - .set_termios = dgrp_tty_set_termios, - .stop = dgrp_tty_stop, - .start = dgrp_tty_start, - .throttle = dgrp_tty_throttle, - .unthrottle = dgrp_tty_unthrottle, - .hangup = dgrp_tty_hangup, - .put_char = dgrp_tty_put_char, - .tiocmget = dgrp_tty_tiocmget, - .tiocmset = dgrp_tty_tiocmset, - .break_ctl = dgrp_tty_send_break, - .send_xchar = dgrp_tty_send_xchar -}; - - -static int calc_baud_rate(struct un_struct *un) -{ - int i; - int brate; - - struct baud_rates { - unsigned int rate; - unsigned int cflag; - }; - - static struct baud_rates baud_rates[] = { - { 921600, B921600 }, - { 460800, B460800 }, - { 230400, B230400 }, - { 115200, B115200 }, - { 57600, B57600 }, - { 38400, B38400 }, - { 19200, B19200 }, - { 9600, B9600 }, - { 4800, B4800 }, - { 2400, B2400 }, - { 1200, B1200 }, - { 600, B600 }, - { 300, B300 }, - { 200, B200 }, - { 150, B150 }, - { 134, B134 }, - { 110, B110 }, - { 75, B75 }, - { 50, B50 }, - { 0, B9600 } - }; - - brate = C_BAUD(un->un_tty); - - for (i = 0; baud_rates[i].rate; i++) { - if (baud_rates[i].cflag == brate) - break; - } - - return baud_rates[i].rate; -} - -static int calc_fastbaud_rate(struct un_struct *un, struct ktermios *uts) -{ - int i; - int brate; - - ulong bauds[2][16] = { - { /* fastbaud*/ - 0, 57600, 76800, 115200, - 131657, 153600, 230400, 460800, - 921600, 1200, 1800, 2400, - 4800, 9600, 19200, 38400 }, - { /* fastbaud & CBAUDEX */ - 0, 57600, 115200, 230400, - 460800, 150, 200, 921600, - 600, 1200, 1800, 2400, - 4800, 9600, 19200, 38400 } - }; - - brate = C_BAUD(un->un_tty) & 0xff; - - i = (uts->c_cflag & CBAUDEX) ? 1 : 0; - - - if ((i >= 0) && (i < 2) && (brate >= 0) && (brate < 16)) - brate = bauds[i][brate]; - else - brate = 0; - - return brate; -} - -/** - * drp_param() -- send parameter values to be sent to the node - * @ch: channel structure of port to modify - * - * Interprets the tty and modem changes made by an application - * program (by examining the termios structures) and sets up - * parameter values to be sent to the node. - */ -static void drp_param(struct ch_struct *ch) -{ - struct nd_struct *nd; - struct un_struct *un; - int brate; - int mflow; - int xflag; - int iflag; - struct ktermios *tts, *pts, *uts; - - nd = ch->ch_nd; - - /* - * If the terminal device is open, use it to set up all tty - * modes and functions. Otherwise use the printer device. - */ - - if (ch->ch_tun.un_open_count) { - - un = &ch->ch_tun; - tts = &ch->ch_tun.un_tty->termios; - - /* - * If both devices are open, copy critical line - * parameters from the tty device to the printer, - * so that if the tty is closed, the printer will - * continue without disruption. - */ - - if (ch->ch_pun.un_open_count) { - - pts = &ch->ch_pun.un_tty->termios; - - pts->c_cflag ^= - (pts->c_cflag ^ tts->c_cflag) & - (CBAUD | CSIZE | CSTOPB | CREAD | PARENB | - PARODD | HUPCL | CLOCAL); - - pts->c_iflag ^= - (pts->c_iflag ^ tts->c_iflag) & - (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK | - ISTRIP | IXON | IXANY | IXOFF); - - pts->c_cc[VSTART] = tts->c_cc[VSTART]; - pts->c_cc[VSTOP] = tts->c_cc[VSTOP]; - } - } else if (ch->ch_pun.un_open_count == 0) { - pr_warn("%s - ch_pun.un_open_count shouldn't be 0\n", - __func__); - return; - } else { - un = &ch->ch_pun; - } - - uts = &un->un_tty->termios; - - /* - * Determine if FAST writes can be performed. - */ - - if ((ch->ch_digi.digi_flags & DIGI_COOK) != 0 && - (ch->ch_tun.un_open_count != 0) && - !((un->un_tty)->ldisc->ops->flags & LDISC_FLAG_DEFINED) && - !(L_XCASE(un->un_tty))) { - ch->ch_flag |= CH_FAST_WRITE; - } else { - ch->ch_flag &= ~CH_FAST_WRITE; - } - - /* - * If FAST writes can be performed, and OPOST is on in the - * terminal device, do OPOST handling in the server. - */ - - if ((ch->ch_flag & CH_FAST_WRITE) && - O_OPOST(un->un_tty) != 0) { - int oflag = tty_to_ch_flags(un->un_tty, 'o'); - - /* add to ch_ocook any processing flags set in the termio */ - ch->ch_ocook |= oflag & (OF_OLCUC | - OF_ONLCR | - OF_OCRNL | - OF_ONLRET | - OF_TABDLY); - - /* - * the hpux driver clears any flags set in ch_ocook - * from the termios oflag. It is STILL reported though - * by a TCGETA - */ - - oflag = ch_to_tty_flags(ch->ch_ocook, 'o'); - uts->c_oflag &= ~oflag; - - } else { - /* clear the ch->ch_ocook flag */ - int oflag = ch_to_tty_flags(ch->ch_ocook, 'o'); - uts->c_oflag |= oflag; - ch->ch_ocook = 0; - } - - ch->ch_oflag = ch->ch_ocook; - - - ch->ch_flag &= ~CH_FAST_READ; - - /* - * Generate channel flags - */ - - if (C_BAUD(un->un_tty) == B0) { - if (!(ch->ch_flag & CH_BAUD0)) { - /* TODO : the HPUX driver flushes line */ - /* TODO : discipline, I assume I don't have to */ - - ch->ch_tout = ch->ch_tin; - ch->ch_rout = ch->ch_rin; - - ch->ch_break_time = 0; - - ch->ch_send |= RR_TX_FLUSH | RR_RX_FLUSH; - - ch->ch_mout &= ~(DM_DTR | DM_RTS); - - ch->ch_flag |= CH_BAUD0; - } - } else if (ch->ch_custom_speed) { - ch->ch_brate = PORTSERVER_DIVIDEND / ch->ch_custom_speed; - - if (ch->ch_flag & CH_BAUD0) { - ch->ch_mout |= DM_DTR | DM_RTS; - - ch->ch_flag &= ~CH_BAUD0; - } - } else { - /* - * Baud rate mapping. - * - * If FASTBAUD isn't on, we can scan the new baud rate list - * as required. - * - * However, if FASTBAUD is on, we must go to the old - * baud rate mapping that existed many many moons ago, - * for compatibility reasons. - */ - - if (!(ch->ch_digi.digi_flags & DIGI_FAST)) - brate = calc_baud_rate(un); - else - brate = calc_fastbaud_rate(un, uts); - - if (brate == 0) - brate = 9600; - - ch->ch_brate = PORTSERVER_DIVIDEND / brate; - - if (ch->ch_flag & CH_BAUD0) { - ch->ch_mout |= DM_DTR | DM_RTS; - - ch->ch_flag &= ~CH_BAUD0; - } - } - - /* - * Generate channel cflags from the termio. - */ - - ch->ch_cflag = tty_to_ch_flags(un->un_tty, 'c'); - - /* - * Generate channel iflags from the termio. - */ - - iflag = (int) tty_to_ch_flags(un->un_tty, 'i'); - - if (START_CHAR(un->un_tty) == _POSIX_VDISABLE || - STOP_CHAR(un->un_tty) == _POSIX_VDISABLE) { - iflag &= ~(IF_IXON | IF_IXANY | IF_IXOFF); - } - - ch->ch_iflag = iflag; - - /* - * Generate flow control characters - */ - - /* - * From the POSIX.1 spec (7.1.2.6): "If {_POSIX_VDISABLE} - * is defined for the terminal device file, and the value - * of one of the changeable special control characters (see - * 7.1.1.9) is {_POSIX_VDISABLE}, that function shall be - * disabled, that is, no input data shall be recognized as - * the disabled special character." - * - * OK, so we don't ever assign S/DXB XON or XOFF to _POSIX_VDISABLE. - */ - - if (uts->c_cc[VSTART] != _POSIX_VDISABLE) - ch->ch_xon = uts->c_cc[VSTART]; - if (uts->c_cc[VSTOP] != _POSIX_VDISABLE) - ch->ch_xoff = uts->c_cc[VSTOP]; - - ch->ch_lnext = (uts->c_cc[VLNEXT] == _POSIX_VDISABLE ? 0 : - uts->c_cc[VLNEXT]); - - /* - * Also, if either c_cc[START] or c_cc[STOP] is set to - * _POSIX_VDISABLE, we can't really do software flow - * control--in either direction--so we turn it off as - * far as S/DXB is concerned. In essence, if you disable - * one, you disable the other too. - */ - if ((uts->c_cc[VSTART] == _POSIX_VDISABLE) || - (uts->c_cc[VSTOP] == _POSIX_VDISABLE)) - ch->ch_iflag &= ~(IF_IXOFF | IF_IXON); - - /* - * Update xflags. - */ - - xflag = 0; - - if (ch->ch_digi.digi_flags & DIGI_AIXON) - xflag = XF_XIXON; - - if ((ch->ch_xxon == _POSIX_VDISABLE) || - (ch->ch_xxoff == _POSIX_VDISABLE)) - xflag &= ~XF_XIXON; - - ch->ch_xflag = xflag; - - - /* - * Figure effective DCD value. - */ - - if (C_CLOCAL(un->un_tty)) - ch->ch_flag |= CH_CLOCAL; - else - ch->ch_flag &= ~CH_CLOCAL; - - /* - * Check modem signals - */ - - dgrp_carrier(ch); - - /* - * Get hardware handshake value. - */ - - mflow = 0; - - if (C_CRTSCTS(un->un_tty)) - mflow |= (DM_RTS | DM_CTS); - - if (ch->ch_digi.digi_flags & RTSPACE) - mflow |= DM_RTS; - - if (ch->ch_digi.digi_flags & DTRPACE) - mflow |= DM_DTR; - - if (ch->ch_digi.digi_flags & CTSPACE) - mflow |= DM_CTS; - - if (ch->ch_digi.digi_flags & DSRPACE) - mflow |= DM_DSR; - - if (ch->ch_digi.digi_flags & DCDPACE) - mflow |= DM_CD; - - if (ch->ch_digi.digi_flags & DIGI_RTS_TOGGLE) - mflow |= DM_RTS_TOGGLE; - - ch->ch_mflow = mflow; - - /* - * Send the changes to the server. - */ - - ch->ch_flag |= CH_PARAM; - (ch->ch_nd)->nd_tx_work = 1; - - if (waitqueue_active(&ch->ch_flag_wait)) - wake_up_interruptible(&ch->ch_flag_wait); -} - -/* - * This function is just used as a callback for timeouts - * waiting on the ch_sleep flag. - */ -static void wake_up_drp_sleep_timer(unsigned long ptr) -{ - struct ch_struct *ch = (struct ch_struct *) ptr; - if (ch) - wake_up(&ch->ch_sleep); -} - - -/* - * Set up our own sleep that can't be cancelled - * until our timeout occurs. - */ -static void drp_my_sleep(struct ch_struct *ch) -{ - struct timer_list drp_wakeup_timer; - DECLARE_WAITQUEUE(wait, current); - - /* - * First make sure we're ready to receive the wakeup. - */ - - add_wait_queue(&ch->ch_sleep, &wait); - current->state = TASK_UNINTERRUPTIBLE; - - /* - * Since we are uninterruptible, set a timer to - * unset the uninterruptable state in 1 second. - */ - - init_timer(&drp_wakeup_timer); - drp_wakeup_timer.function = wake_up_drp_sleep_timer; - drp_wakeup_timer.data = (unsigned long) ch; - drp_wakeup_timer.expires = jiffies + (1 * HZ); - add_timer(&drp_wakeup_timer); - - schedule(); - - del_timer(&drp_wakeup_timer); - - remove_wait_queue(&ch->ch_sleep, &wait); -} - -/* - * dgrp_tty_open() - * - * returns: - * -EBUSY - this is a callout device and the normal device is active - * - there is an error in opening the tty - * -ENODEV - the channel does not exist - * -EAGAIN - we are in the middle of hanging up or closing - * - IMMEDIATE_OPEN fails - * -ENXIO or -EAGAIN - * - if the port is outside physical range - * -EINTR - the open is interrupted - * - */ -static int dgrp_tty_open(struct tty_struct *tty, struct file *file) -{ - int retval = 0; - struct nd_struct *nd; - struct ch_struct *ch; - struct un_struct *un; - int port; - int delay_error; - int otype; - int unf; - int wait_carrier; - int category; - int counts_were_incremented = 0; - ulong lock_flags; - DECLARE_WAITQUEUE(wait, current); - - /* - * Do some initial checks to see if the node and port exist - */ - - nd = nd_struct_get(MAJOR(tty_devnum(tty))); - port = PORT_NUM(MINOR(tty_devnum(tty))); - category = OPEN_CATEGORY(MINOR(tty_devnum(tty))); - - if (!nd) - return -ENODEV; - - if (port >= CHAN_MAX) - return -ENODEV; - - /* - * The channel exists. - */ - - ch = nd->nd_chan + port; - - un = IS_PRINT(MINOR(tty_devnum(tty))) ? &ch->ch_pun : &ch->ch_tun; - un->un_tty = tty; - tty->driver_data = un; - - /* - * If we are in the middle of hanging up, - * then return an error - */ - if (tty_hung_up_p(file)) { - retval = ((un->un_flag & UN_HUP_NOTIFY) ? - -EAGAIN : -ERESTARTSYS); - goto done; - } - - /* - * If the port is in the middle of closing, then block - * until it is done, then try again. - */ - retval = wait_event_interruptible(un->un_close_wait, - ((un->un_flag & UN_CLOSING) == 0)); - - if (retval) - goto done; - - /* - * If the port is in the middle of a reopen after a network disconnect, - * wait until it is done, then try again. - */ - retval = wait_event_interruptible(ch->ch_flag_wait, - ((ch->ch_flag & CH_PORT_GONE) == 0)); - - if (retval) - goto done; - - /* - * 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 (un->un_flag & UN_NORMAL_ACTIVE) { - retval = -EBUSY; - goto done; - } else { - un->un_flag |= UN_CALLOUT_ACTIVE; - } - } - - /* - * Loop waiting until the open can be successfully completed. - */ - - spin_lock_irqsave(&nd->nd_lock, lock_flags); - - nd->nd_tx_work = 1; - - for (;;) { - wait_carrier = 0; - - /* - * Determine the open type from the flags provided. - */ - - /* - * If the port is not enabled, then exit - */ - if (test_bit(TTY_IO_ERROR, &tty->flags)) { - /* there was an error in opening the tty */ - if (un->un_flag & UN_CALLOUT_ACTIVE) - retval = -EBUSY; - else - un->un_flag |= UN_NORMAL_ACTIVE; - goto unlock; - } - - if (file->f_flags & O_NONBLOCK) { - - /* - * if the O_NONBLOCK is set, errors on read and write - * must return -EAGAIN immediately and NOT sleep - * on the waitqs. - */ - otype = OTYPE_IMMEDIATE; - delay_error = -EAGAIN; - - } else if (!OPEN_WAIT_AVAIL(category) || - (file->f_flags & O_NDELAY) != 0) { - otype = OTYPE_IMMEDIATE; - delay_error = -EBUSY; - - } else if (!OPEN_WAIT_CARRIER(category) || - ((ch->ch_digi.digi_flags & DIGI_FORCEDCD) != 0) || - C_CLOCAL(tty)) { - otype = OTYPE_PERSISTENT; - delay_error = 0; - - } else { - otype = OTYPE_INCOMING; - delay_error = 0; - } - - /* - * Handle port currently outside physical port range. - */ - - if (port >= nd->nd_chan_count) { - if (otype == OTYPE_IMMEDIATE) { - retval = (nd->nd_state == NS_READY) ? - -ENXIO : -EAGAIN; - goto unlock; - } - } - - /* - * Handle port not currently open. - */ - - else if (ch->ch_open_count == 0) { - /* - * Return an error when an Incoming Open - * response indicates the port is busy. - */ - - if (ch->ch_open_error != 0 && otype == ch->ch_otype) { - retval = (ch->ch_open_error <= 2) ? - delay_error : -ENXIO; - goto unlock; - } - - /* - * Fail any new Immediate open if we do not have - * a normal connection to the server. - */ - - if (nd->nd_state != NS_READY && - otype == OTYPE_IMMEDIATE) { - retval = -EAGAIN; - goto unlock; - } - - /* - * If a Realport open of the correct type has - * succeeded, complete the open. - */ - - if (ch->ch_state == CS_READY && ch->ch_otype == otype) - break; - } - - /* - * Handle port already open and active as a device - * of same category. - */ - - else if ((ch->ch_category == category) || - IS_PRINT(MINOR(tty_devnum(tty)))) { - /* - * Fail if opening the device now would - * violate exclusive use. - */ - unf = ch->ch_tun.un_flag | ch->ch_pun.un_flag; - - if ((file->f_flags & O_EXCL) || (unf & UN_EXCL)) { - retval = -EBUSY; - goto unlock; - } - - /* - * If the open device is in the hangup state, all - * system calls fail except close(). - */ - - /* TODO : check on hangup_p calls */ - - if (ch->ch_flag & CH_HANGUP) { - retval = -ENXIO; - goto unlock; - } - - /* - * If the port is ready, and carrier is ignored - * or present, then complete the open. - */ - - if (ch->ch_state == CS_READY && - (otype != OTYPE_INCOMING || - ch->ch_flag & CH_VIRT_CD)) - break; - - wait_carrier = 1; - } - - /* - * Handle port active with a different category device. - */ - - else { - if (otype == OTYPE_IMMEDIATE) { - retval = delay_error; - goto unlock; - } - } - - /* - * Wait until conditions change, then take another - * try at the open. - */ - - ch->ch_wait_count[otype]++; - - if (wait_carrier) - ch->ch_wait_carrier++; - - /* - * Prepare the task to accept the wakeup, then - * release our locks and release control. - */ - - add_wait_queue(&ch->ch_flag_wait, &wait); - current->state = TASK_INTERRUPTIBLE; - - spin_unlock_irqrestore(&nd->nd_lock, lock_flags); - - /* - * Give up control, we'll come back if we're - * interrupted or are woken up. - */ - schedule(); - remove_wait_queue(&ch->ch_flag_wait, &wait); - - spin_lock_irqsave(&nd->nd_lock, lock_flags); - - current->state = TASK_RUNNING; - - ch->ch_wait_count[otype]--; - - if (wait_carrier) - ch->ch_wait_carrier--; - - nd->nd_tx_work = 1; - - if (signal_pending(current)) { - retval = -EINTR; - goto unlock; - } - } /* end for(;;) */ - - /* - * The open has succeeded. No turning back. - */ - counts_were_incremented = 1; - un->un_open_count++; - ch->ch_open_count++; - - /* - * Initialize the channel, if it's not already open. - */ - - if (ch->ch_open_count == 1) { - ch->ch_flag = 0; - ch->ch_inwait = 0; - ch->ch_category = category; - ch->ch_pscan_state = 0; - - /* TODO : find out what PS-1 bug Gene was referring to */ - /* TODO : in the following comment. */ - - ch->ch_send = RR_TX_START | RR_RX_START; /* PS-1 bug */ - - if (C_CLOCAL(tty) || - ch->ch_s_mlast & DM_CD || - ch->ch_digi.digi_flags & DIGI_FORCEDCD) - ch->ch_flag |= CH_VIRT_CD; - else if (OPEN_FORCES_CARRIER(category)) - ch->ch_flag |= CH_VIRT_CD; - - } - - /* - * Initialize the unit, if it is not already open. - */ - - if (un->un_open_count == 1) { - /* - * Since all terminal options are always sticky in Linux, - * we don't need the UN_STICKY flag to be handled specially. - */ - /* clears all the digi flags, leaves serial flags */ - un->un_flag &= ~UN_DIGI_MASK; - - if (file->f_flags & O_EXCL) - un->un_flag |= UN_EXCL; - - /* TODO : include "session" and "pgrp" */ - - /* - * In Linux, all terminal parameters are intended to be sticky. - * as a result, we "remove" the code which once reset the ports - * to sane values. - */ - - drp_param(ch); - - } - - un->un_flag |= UN_INITIALIZED; - - retval = 0; - -unlock: - - spin_unlock_irqrestore(&nd->nd_lock, lock_flags); - -done: - /* - * Linux does a close for every open, even failed ones! - */ - if (!counts_were_incremented) { - un->un_open_count++; - ch->ch_open_count++; - } - - if (retval) - dev_err(tty->dev, "tty open bad return (%i)\n", retval); - - return retval; -} - - - - -/* - * dgrp_tty_close() -- close function for tty_operations - */ -static void dgrp_tty_close(struct tty_struct *tty, struct file *file) -{ - struct ch_struct *ch; - struct un_struct *un; - struct nd_struct *nd; - int tpos; - int port; - int err = 0; - int s = 0; - ulong waketime; - ulong lock_flags; - int sent_printer_offstr = 0; - - port = PORT_NUM(MINOR(tty_devnum(tty))); - - un = tty->driver_data; - - if (!un) - return; - - ch = un->un_ch; - - if (!ch) - return; - - nd = ch->ch_nd; - - if (!nd) - return; - - spin_lock_irqsave(&nd->nd_lock, lock_flags); - - - /* Used to be on channel basis, now we check on a unit basis. */ - if (un->un_open_count != 1) - goto unlock; - - /* - * OK, its the last close on the unit - */ - un->un_flag |= UN_CLOSING; - - /* - * Notify the discipline to only process XON/XOFF characters. - */ - tty->closing = 1; - - /* - * Wait for output to drain only if this is - * the last close against the channel - */ - - if (ch->ch_open_count == 1) { - /* - * If its the print device, we need to ensure at all costs that - * the offstr will fit. If it won't, flush our tbuf. - */ - if (IS_PRINT(MINOR(tty_devnum(tty))) && - (((ch->ch_tout - ch->ch_tin - 1) & TBUF_MASK) < - ch->ch_digi.digi_offlen)) - ch->ch_tin = ch->ch_tout; - - /* - * Turn off the printer. Don't bother checking to see if its - * IS_PRINT... Since this is the last close the flag is going - * to be cleared, so we MUST make sure the offstr gets inserted - * into tbuf. - */ - - if ((ch->ch_flag & CH_PRON) != 0) { - drp_wmove(ch, 0, ch->ch_digi.digi_offstr, - ch->ch_digi.digi_offlen); - ch->ch_flag &= ~CH_PRON; - sent_printer_offstr = 1; - } - } - - /* - * Wait until either the output queue has drained, or we see - * absolutely no progress for 15 seconds. - */ - - tpos = ch->ch_s_tpos; - - waketime = jiffies + 15 * HZ; - - for (;;) { - - /* - * Make sure the port still exists. - */ - - if (port >= nd->nd_chan_count) { - err = 1; - break; - } - - if (signal_pending(current)) { - err = 1; - break; - } - - /* - * If the port is idle (not opened on the server), we have - * no way of draining/flushing/closing the port on that server. - * So break out of loop. - */ - if (ch->ch_state == CS_IDLE) - break; - - nd->nd_tx_work = 1; - - /* - * Exit if the queues for this unit are empty, - * and either the other unit is still open or all - * data has drained. - */ - - if ((un->un_tty)->ops->chars_in_buffer ? - ((un->un_tty)->ops->chars_in_buffer)(un->un_tty) == 0 : 1) { - - /* - * We don't need to wait for a buffer to drain - * if the other unit is open. - */ - - if (ch->ch_open_count != un->un_open_count) - break; - - /* - * The wait is complete when all queues are - * drained, and any break in progress is complete. - */ - - if (ch->ch_tin == ch->ch_tout && - ch->ch_s_tin == ch->ch_s_tpos && - (ch->ch_send & RR_TX_BREAK) == 0) { - break; - } - } - - /* - * Flush TX data and exit the wait if NDELAY is set, - * or this is not a DIGI printer, and the close timeout - * expires. - */ - - if ((file->f_flags & (O_NDELAY | O_NONBLOCK)) || - ((long)(jiffies - waketime) >= 0 && - (ch->ch_digi.digi_flags & DIGI_PRINTER) == 0)) { - - /* - * If we sent the printer off string, we cannot - * flush our internal buffers, or we might lose - * the offstr. - */ - if (!sent_printer_offstr) - dgrp_tty_flush_buffer(tty); - - spin_unlock_irqrestore(&nd->nd_lock, lock_flags); - tty_ldisc_flush(tty); - spin_lock_irqsave(&nd->nd_lock, lock_flags); - break; - } - - /* - * Otherwise take a short nap. - */ - - ch->ch_flag |= CH_DRAIN; - - spin_unlock_irqrestore(&nd->nd_lock, lock_flags); - - schedule_timeout_interruptible(1); - s = signal_pending(current); - - spin_lock_irqsave(&nd->nd_lock, lock_flags); - - if (s) { - /* - * If we had sent the printer off string, we now have - * some problems. - * - * The system won't let us sleep since we got an error - * back from sleep, presumably because the user did - * a ctrl-c... - * But we need to ensure that the offstr gets sent! - * Thus, we have to do something else besides sleeping. - * The plan: - * 1) Make this task uninterruptable. - * 2) Set up a timer to go off in 1 sec. - * 3) Act as tho we just got out of the sleep above. - * - * Thankfully, in the real world, this just - * never happens. - */ - - if (sent_printer_offstr) { - spin_unlock_irqrestore(&nd->nd_lock, - lock_flags); - drp_my_sleep(ch); - spin_lock_irqsave(&nd->nd_lock, lock_flags); - } else { - err = 1; - break; - } - } - - /* - * Restart the wait if any progress is seen. - */ - - if (ch->ch_s_tpos != tpos) { - tpos = ch->ch_s_tpos; - - /* TODO: this gives us timeout problems with nist ?? */ - waketime = jiffies + 15 * HZ; - } - } - - /* - * Close the line discipline - */ - - /* this is done in tty_io.c */ - /* if ((un->un_tty)->ldisc.close) - * ((un->un_tty)->ldisc.close)(un->un_tty); - */ - - /* don't do this here */ - /* un->un_flag = 0; */ - - /* - * Flush the receive buffer on terminal unit close only. - */ - - if (!IS_PRINT(MINOR(tty_devnum(tty)))) - ch->ch_rout = ch->ch_rin; - - - /* - * Don't permit the close to happen until we get any pending - * sync request responses. - * There could be other ports depending upon the response as well. - * - * Also, don't permit the close to happen until any parameter - * changes have been sent out from the state machine as well. - * This is required because of a ditty -a race with -HUPCL - * We MUST make sure all channel parameters have been sent to the - * Portserver before sending a close. - */ - - if ((err != 1) && (ch->ch_state != CS_IDLE)) { - spin_unlock_irqrestore(&nd->nd_lock, lock_flags); - s = wait_event_interruptible(ch->ch_flag_wait, - ((ch->ch_flag & (CH_WAITING_SYNC | CH_PARAM)) == 0)); - spin_lock_irqsave(&nd->nd_lock, lock_flags); - } - - /* - * Cleanup the channel if last unit open. - */ - - if (ch->ch_open_count == 1) { - ch->ch_flag = 0; - ch->ch_category = 0; - ch->ch_send = 0; - ch->ch_expect = 0; - ch->ch_tout = ch->ch_tin; - /* (un->un_tty)->device = 0; */ - - if (ch->ch_state == CS_READY) - ch->ch_state = CS_SEND_CLOSE; - } - - /* |