Пример #1
0
/*
** RIOClose the port.
** The operating system thinks that this is last close for the device.
** As there are two interfaces to the port (Modem and tty), we need to
** check that both are closed before we close the device.
*/
int riotclose(void *ptr)
{
	struct Port *PortP = ptr;	/* pointer to the port structure */
	int deleted = 0;
	int try = -1;		/* Disable the timeouts by setting them to -1 */
	int repeat_this = -1;	/* Congrats to those having 15 years of
				   uptime! (You get to break the driver.) */
	unsigned long end_time;
	struct tty_struct *tty;
	unsigned long flags;
	int rv = 0;

	rio_dprintk(RIO_DEBUG_TTY, "port close SysPort %d\n", PortP->PortNum);

	/* PortP = p->RIOPortp[SysPort]; */
	rio_dprintk(RIO_DEBUG_TTY, "Port is at address %p\n", PortP);
	/* tp = PortP->TtyP; *//* Get tty */
	tty = PortP->gs.tty;
	rio_dprintk(RIO_DEBUG_TTY, "TTY is at address %p\n", tty);

	if (PortP->gs.closing_wait)
		end_time = jiffies + PortP->gs.closing_wait;
	else
		end_time = jiffies + MAX_SCHEDULE_TIMEOUT;

	rio_spin_lock_irqsave(&PortP->portSem, flags);

	/*
	 ** Setting this flag will make any process trying to open
	 ** this port block until we are complete closing it.
	 */
	PortP->State |= RIO_CLOSING;

	if ((PortP->State & RIO_DELETED)) {
		rio_dprintk(RIO_DEBUG_TTY, "Close on deleted RTA\n");
		deleted = 1;
	}

	if (p->RIOHalted) {
		RIOClearUp(PortP);
		rv = -EIO;
		goto close_end;
	}

	rio_dprintk(RIO_DEBUG_TTY, "Clear bits\n");
	/*
	 ** clear the open bits for this device
	 */
	PortP->State &= ~RIO_MOPEN;
	PortP->State &= ~RIO_CARR_ON;
	PortP->ModemState &= ~MSVR1_CD;
	/*
	 ** If the device was open as both a Modem and a tty line
	 ** then we need to wimp out here, as the port has not really
	 ** been finally closed (gee, whizz!) The test here uses the
	 ** bit for the OTHER mode of operation, to see if THAT is
	 ** still active!
	 */
	if ((PortP->State & (RIO_LOPEN | RIO_MOPEN))) {
		/*
		 ** The port is still open for the other task -
		 ** return, pretending that we are still active.
		 */
		rio_dprintk(RIO_DEBUG_TTY, "Channel %d still open !\n", PortP->PortNum);
		PortP->State &= ~RIO_CLOSING;
		if (PortP->firstOpen)
			PortP->firstOpen--;
		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
		return -EIO;
	}

	rio_dprintk(RIO_DEBUG_TTY, "Closing down - everything must go!\n");

	PortP->State &= ~RIO_DYNOROD;

	/*
	 ** This is where we wait for the port
	 ** to drain down before closing. Bye-bye....
	 ** (We never meant to do this)
	 */
	rio_dprintk(RIO_DEBUG_TTY, "Timeout 1 starts\n");

	if (!deleted)
		while ((PortP->InUse != NOT_INUSE) && !p->RIOHalted && (PortP->TxBufferIn != PortP->TxBufferOut)) {
			if (repeat_this-- <= 0) {
				rv = -EINTR;
				rio_dprintk(RIO_DEBUG_TTY, "Waiting for not idle closed broken by signal\n");
				RIOPreemptiveCmd(p, PortP, FCLOSE);
				goto close_end;
			}
			rio_dprintk(RIO_DEBUG_TTY, "Calling timeout to flush in closing\n");
			rio_spin_unlock_irqrestore(&PortP->portSem, flags);
			if (RIODelay_ni(PortP, HUNDRED_MS * 10) == RIO_FAIL) {
				rio_dprintk(RIO_DEBUG_TTY, "RTA EINTR in delay \n");
				rv = -EINTR;
				rio_spin_lock_irqsave(&PortP->portSem, flags);
				goto close_end;
			}
			rio_spin_lock_irqsave(&PortP->portSem, flags);
		}

	PortP->TxBufferIn = PortP->TxBufferOut = 0;
	repeat_this = 0xff;

	PortP->InUse = 0;
	if ((PortP->State & (RIO_LOPEN | RIO_MOPEN))) {
		/*
		 ** The port has been re-opened for the other task -
		 ** return, pretending that we are still active.
		 */
		rio_dprintk(RIO_DEBUG_TTY, "Channel %d re-open!\n", PortP->PortNum);
		PortP->State &= ~RIO_CLOSING;
		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
		if (PortP->firstOpen)
			PortP->firstOpen--;
		return -EIO;
	}

	if (p->RIOHalted) {
		RIOClearUp(PortP);
		goto close_end;
	}

	/* Can't call RIOShortCommand with the port locked. */
	rio_spin_unlock_irqrestore(&PortP->portSem, flags);

	if (RIOShortCommand(p, PortP, CLOSE, 1, 0) == RIO_FAIL) {
		RIOPreemptiveCmd(p, PortP, FCLOSE);
		rio_spin_lock_irqsave(&PortP->portSem, flags);
		goto close_end;
	}

	if (!deleted)
		while (try && (PortP->PortState & PORT_ISOPEN)) {
			try--;
			if (time_after(jiffies, end_time)) {
				rio_dprintk(RIO_DEBUG_TTY, "Run out of tries - force the bugger shut!\n");
				RIOPreemptiveCmd(p, PortP, FCLOSE);
				break;
			}
			rio_dprintk(RIO_DEBUG_TTY, "Close: PortState:ISOPEN is %d\n", PortP->PortState & PORT_ISOPEN);

			if (p->RIOHalted) {
				RIOClearUp(PortP);
				rio_spin_lock_irqsave(&PortP->portSem, flags);
				goto close_end;
			}
			if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) {
				rio_dprintk(RIO_DEBUG_TTY, "RTA EINTR in delay \n");
				RIOPreemptiveCmd(p, PortP, FCLOSE);
				break;
			}
		}
	rio_spin_lock_irqsave(&PortP->portSem, flags);
	rio_dprintk(RIO_DEBUG_TTY, "Close: try was %d on completion\n", try);

	/* RIOPreemptiveCmd(p, PortP, FCLOSE); */

/*
** 15.10.1998 ARG - ESIL 0761 part fix
** RIO has it's own CTSFLOW and RTSFLOW flags in 'Config' in the port structure,** we need to make sure that the flags are clear when the port is opened.
*/
	PortP->Config &= ~(RIO_CTSFLOW | RIO_RTSFLOW);

	/*
	 ** Count opens for port statistics reporting
	 */
	if (PortP->statsGather)
		PortP->closes++;

close_end:
	/* XXX: Why would a "DELETED" flag be reset here? I'd have
	   thought that a "deleted" flag means that the port was
	   permanently gone, but here we can make it reappear by it
	   being in close during the "deletion".
	 */
	PortP->State &= ~(RIO_CLOSING | RIO_DELETED);
	if (PortP->firstOpen)
		PortP->firstOpen--;
	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
	rio_dprintk(RIO_DEBUG_TTY, "Return from close\n");
	return rv;
}



static void RIOClearUp(struct Port *PortP)
{
	rio_dprintk(RIO_DEBUG_TTY, "RIOHalted set\n");
	PortP->Config = 0;	/* Direct semaphore */
	PortP->PortState = 0;
	PortP->firstOpen = 0;
	PortP->FlushCmdBodge = 0;
	PortP->ModemState = PortP->CookMode = 0;
	PortP->Mapped = 0;
	PortP->WflushFlag = 0;
	PortP->MagicFlags = 0;
	PortP->RxDataStart = 0;
	PortP->TxBufferIn = 0;
	PortP->TxBufferOut = 0;
}

/*
** Put a command onto a port.
** The PortPointer, command, length and arg are passed.
** The len is the length *inclusive* of the command byte,
** and so for a command that takes no data, len==1.
** The arg is a single byte, and is only used if len==2.
** Other values of len aren't allowed, and will cause
** a panic.
*/
int RIOShortCommand(struct rio_info *p, struct Port *PortP, int command, int len, int arg)
{
	struct PKT __iomem *PacketP;
	int retries = 20;	/* at 10 per second -> 2 seconds */
	unsigned long flags;

	rio_dprintk(RIO_DEBUG_TTY, "entering shortcommand.\n");

	if (PortP->State & RIO_DELETED) {
		rio_dprintk(RIO_DEBUG_TTY, "Short command to deleted RTA ignored\n");
		return RIO_FAIL;
	}
	rio_spin_lock_irqsave(&PortP->portSem, flags);

	/*
	 ** If the port is in use for pre-emptive command, then wait for it to
	 ** be free again.
	 */
	while ((PortP->InUse != NOT_INUSE) && !p->RIOHalted) {
		rio_dprintk(RIO_DEBUG_TTY, "Waiting for not in use (%d)\n", retries);
		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
		if (retries-- <= 0) {
			return RIO_FAIL;
		}
		if (RIODelay_ni(PortP, HUNDRED_MS) == RIO_FAIL) {
			return RIO_FAIL;
		}
		rio_spin_lock_irqsave(&PortP->portSem, flags);
	}
	if (PortP->State & RIO_DELETED) {
		rio_dprintk(RIO_DEBUG_TTY, "Short command to deleted RTA ignored\n");
		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
		return RIO_FAIL;
	}

	while (!can_add_transmit(&PacketP, PortP) && !p->RIOHalted) {
		rio_dprintk(RIO_DEBUG_TTY, "Waiting to add short command to queue (%d)\n", retries);
		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
		if (retries-- <= 0) {
			rio_dprintk(RIO_DEBUG_TTY, "out of tries. Failing\n");
			return RIO_FAIL;
		}
		if (RIODelay_ni(PortP, HUNDRED_MS) == RIO_FAIL) {
			return RIO_FAIL;
		}
		rio_spin_lock_irqsave(&PortP->portSem, flags);
	}

	if (p->RIOHalted) {
		rio_spin_unlock_irqrestore(&PortP->portSem, flags);
		return RIO_FAIL;
	}

	/*
	 ** set the command byte and the argument byte
	 */
	writeb(command, &PacketP->data[0]);

	if (len == 2)
		writeb(arg, &PacketP->data[1]);

	/*
	 ** set the length of the packet and set the command bit.
	 */
	writeb(PKT_CMD_BIT | len, &PacketP->len);

	add_transmit(PortP);
	/*
	 ** Count characters transmitted for port statistics reporting
	 */
	if (PortP->statsGather)
		PortP->txchars += len;

	rio_spin_unlock_irqrestore(&PortP->portSem, flags);
	return p->RIOHalted ? RIO_FAIL : ~RIO_FAIL;
}
Пример #2
0
/* Enable and start the transmission of packets */
void RIOTxEnable(char *en)
{
	struct Port *PortP;
	struct rio_info *p;
	struct tty_struct *tty;
	int c;
	struct PKT __iomem *PacketP;
	unsigned long flags;

	PortP = (struct Port *) en;
	p = (struct rio_info *) PortP->p;
	tty = PortP->gs.tty;


	rio_dprintk(RIO_DEBUG_INTR, "tx port %d: %d chars queued.\n", PortP->PortNum, PortP->gs.xmit_cnt);

	if (!PortP->gs.xmit_cnt)
		return;


	/* This routine is an order of magnitude simpler than the specialix
	   version. One of the disadvantages is that this version will send
	   an incomplete packet (usually 64 bytes instead of 72) once for
	   every 4k worth of data. Let's just say that this won't influence
	   performance significantly..... */

	rio_spin_lock_irqsave(&PortP->portSem, flags);

	while (can_add_transmit(&PacketP, PortP)) {
		c = PortP->gs.xmit_cnt;
		if (c > PKT_MAX_DATA_LEN)
			c = PKT_MAX_DATA_LEN;

		/* Don't copy past the end of the source buffer */
		if (c > SERIAL_XMIT_SIZE - PortP->gs.xmit_tail)
			c = SERIAL_XMIT_SIZE - PortP->gs.xmit_tail;

		{
			int t;
			t = (c > 10) ? 10 : c;

			rio_dprintk(RIO_DEBUG_INTR, "rio: tx port %d: copying %d chars: %s - %s\n", PortP->PortNum, c, firstchars(PortP->gs.xmit_buf + PortP->gs.xmit_tail, t), firstchars(PortP->gs.xmit_buf + PortP->gs.xmit_tail + c - t, t));
		}
		/* If for one reason or another, we can't copy more data,
		   we're done! */
		if (c == 0)
			break;

		rio_memcpy_toio(PortP->HostP->Caddr, PacketP->data, PortP->gs.xmit_buf + PortP->gs.xmit_tail, c);
		/*    udelay (1); */

		writeb(c, &(PacketP->len));
		if (!(PortP->State & RIO_DELETED)) {
			add_transmit(PortP);
			/*
			 ** Count chars tx'd for port statistics reporting
			 */
			if (PortP->statsGather)
				PortP->txchars += c;
		}
		PortP->gs.xmit_tail = (PortP->gs.xmit_tail + c) & (SERIAL_XMIT_SIZE - 1);
		PortP->gs.xmit_cnt -= c;
	}

	rio_spin_unlock_irqrestore(&PortP->portSem, flags);

	if (PortP->gs.xmit_cnt <= (PortP->gs.wakeup_chars + 2 * PKT_MAX_DATA_LEN)) {
		rio_dprintk(RIO_DEBUG_INTR, "Waking up.... ldisc:%d (%d/%d)....", (int) (PortP->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)), PortP->gs.wakeup_chars, PortP->gs.xmit_cnt);
		if ((PortP->gs.tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && PortP->gs.tty->ldisc.write_wakeup)
			(PortP->gs.tty->ldisc.write_wakeup) (PortP->gs.tty);
		rio_dprintk(RIO_DEBUG_INTR, "(%d/%d)\n", PortP->gs.wakeup_chars, PortP->gs.xmit_cnt);
		wake_up_interruptible(&PortP->gs.tty->write_wait);
	}

}
Пример #3
0
/* 
** RIOParam is used to open or configure a port. You pass it a PortP,
** which will have a tty struct attached to it. You also pass a command,
** either OPEN or CONFIG. The port's setup is taken from the t_ fields
** of the tty struct inside the PortP, and the port is either opened
** or re-configured. You must also tell RIOParam if the device is a modem
** device or not (i.e. top bit of minor number set or clear - take special
** care when deciding on this!).
** RIOParam neither flushes nor waits for drain, and is NOT preemptive.
**
** RIOParam assumes it will be called at splrio(), and also assumes
** that CookMode is set correctly in the port structure.
**
** NB. for MPX
**    tty lock must NOT have been previously acquired.
*/
int RIOParam(struct Port *PortP, int cmd, int Modem, int SleepFlag)
{
    struct tty_struct *TtyP;
    int retval;
    struct phb_param __iomem *phb_param_ptr;
    struct PKT __iomem *PacketP;
    int res;
    u8 Cor1 = 0, Cor2 = 0, Cor4 = 0, Cor5 = 0;
    u8 TxXon = 0, TxXoff = 0, RxXon = 0, RxXoff = 0;
    u8 LNext = 0, TxBaud = 0, RxBaud = 0;
    int retries = 0xff;
    unsigned long flags;

    func_enter();

    TtyP = PortP->gs.tty;

    rio_dprintk(RIO_DEBUG_PARAM, "RIOParam: Port:%d cmd:%d Modem:%d SleepFlag:%d Mapped: %d, tty=%p\n", PortP->PortNum, cmd, Modem, SleepFlag, PortP->Mapped, TtyP);

    if (!TtyP) {
        rio_dprintk(RIO_DEBUG_PARAM, "Can't call rioparam with null tty.\n");

        func_exit();

        return RIO_FAIL;
    }
    rio_spin_lock_irqsave(&PortP->portSem, flags);

    if (cmd == RIOC_OPEN) {
        /*
         ** If the port is set to store or lock the parameters, and it is
         ** paramed with OPEN, we want to restore the saved port termio, but
         ** only if StoredTermio has been saved, i.e. NOT 1st open after reboot.
         */
    }

    /*
     ** wait for space
     */
    while (!(res = can_add_transmit(&PacketP, PortP)) || (PortP->InUse != NOT_INUSE)) {
        if (retries-- <= 0) {
            break;
        }
        if (PortP->InUse != NOT_INUSE) {
            rio_dprintk(RIO_DEBUG_PARAM, "Port IN_USE for pre-emptive command\n");
        }

        if (!res) {
            rio_dprintk(RIO_DEBUG_PARAM, "Port has no space on transmit queue\n");
        }

        if (SleepFlag != OK_TO_SLEEP) {
            rio_spin_unlock_irqrestore(&PortP->portSem, flags);
            func_exit();

            return RIO_FAIL;
        }

        rio_dprintk(RIO_DEBUG_PARAM, "wait for can_add_transmit\n");
        rio_spin_unlock_irqrestore(&PortP->portSem, flags);
        retval = RIODelay(PortP, HUNDRED_MS);
        rio_spin_lock_irqsave(&PortP->portSem, flags);
        if (retval == RIO_FAIL) {
            rio_dprintk(RIO_DEBUG_PARAM, "wait for can_add_transmit broken by signal\n");
            rio_spin_unlock_irqrestore(&PortP->portSem, flags);
            func_exit();
            return -EINTR;
        }
        if (PortP->State & RIO_DELETED) {
            rio_spin_unlock_irqrestore(&PortP->portSem, flags);
            func_exit();
            return 0;
        }
    }

    if (!res) {
        rio_spin_unlock_irqrestore(&PortP->portSem, flags);
        func_exit();

        return RIO_FAIL;
    }

    rio_dprintk(RIO_DEBUG_PARAM, "can_add_transmit() returns %x\n", res);
    rio_dprintk(RIO_DEBUG_PARAM, "Packet is %p\n", PacketP);

    phb_param_ptr = (struct phb_param __iomem *) PacketP->data;


    switch (TtyP->termios->c_cflag & CSIZE) {
    case CS5:
        {
            rio_dprintk(RIO_DEBUG_PARAM, "5 bit data\n");
            Cor1 |= RIOC_COR1_5BITS;
            break;
        }
    case CS6:
        {
            rio_dprintk(RIO_DEBUG_PARAM, "6 bit data\n");
            Cor1 |= RIOC_COR1_6BITS;
            break;
        }
    case CS7:
        {
            rio_dprintk(RIO_DEBUG_PARAM, "7 bit data\n");
            Cor1 |= RIOC_COR1_7BITS;
            break;
        }
    case CS8:
        {
            rio_dprintk(RIO_DEBUG_PARAM, "8 bit data\n");
            Cor1 |= RIOC_COR1_8BITS;
            break;
        }
    }

    if (TtyP->termios->c_cflag & CSTOPB) {
        rio_dprintk(RIO_DEBUG_PARAM, "2 stop bits\n");
        Cor1 |= RIOC_COR1_2STOP;
    } else {
        rio_dprintk(RIO_DEBUG_PARAM, "1 stop bit\n");
        Cor1 |= RIOC_COR1_1STOP;
    }

    if (TtyP->termios->c_cflag & PARENB) {
        rio_dprintk(RIO_DEBUG_PARAM, "Enable parity\n");
        Cor1 |= RIOC_COR1_NORMAL;
    } else {
        rio_dprintk(RIO_DEBUG_PARAM, "Disable parity\n");
        Cor1 |= RIOC_COR1_NOP;
    }
    if (TtyP->termios->c_cflag & PARODD) {
        rio_dprintk(RIO_DEBUG_PARAM, "Odd parity\n");
        Cor1 |= RIOC_COR1_ODD;
    } else {
        rio_dprintk(RIO_DEBUG_PARAM, "Even parity\n");
        Cor1 |= RIOC_COR1_EVEN;
    }

    /*
     ** COR 2
     */
    if (TtyP->termios->c_iflag & IXON) {
        rio_dprintk(RIO_DEBUG_PARAM, "Enable start/stop output control\n");
        Cor2 |= RIOC_COR2_IXON;
    } else {
        if (PortP->Config & RIO_IXON) {
            rio_dprintk(RIO_DEBUG_PARAM, "Force enable start/stop output control\n");
            Cor2 |= RIOC_COR2_IXON;
        } else
            rio_dprintk(RIO_DEBUG_PARAM, "IXON has been disabled.\n");
    }

    if (TtyP->termios->c_iflag & IXANY) {
        if (PortP->Config & RIO_IXANY) {
            rio_dprintk(RIO_DEBUG_PARAM, "Enable any key to restart output\n");
            Cor2 |= RIOC_COR2_IXANY;
        } else
            rio_dprintk(RIO_DEBUG_PARAM, "IXANY has been disabled due to sanity reasons.\n");
    }

    if (TtyP->termios->c_iflag & IXOFF) {
        rio_dprintk(RIO_DEBUG_PARAM, "Enable start/stop input control 2\n");
        Cor2 |= RIOC_COR2_IXOFF;
    }

    if (TtyP->termios->c_cflag & HUPCL) {
        rio_dprintk(RIO_DEBUG_PARAM, "Hangup on last close\n");
        Cor2 |= RIOC_COR2_HUPCL;
    }

    if (C_CRTSCTS(TtyP)) {
        rio_dprintk(RIO_DEBUG_PARAM, "Rx hardware flow control enabled\n");
        Cor2 |= RIOC_COR2_CTSFLOW;
        Cor2 |= RIOC_COR2_RTSFLOW;
    } else {
        rio_dprintk(RIO_DEBUG_PARAM, "Rx hardware flow control disabled\n");
        Cor2 &= ~RIOC_COR2_CTSFLOW;
        Cor2 &= ~RIOC_COR2_RTSFLOW;
    }


    if (TtyP->termios->c_cflag & CLOCAL) {
        rio_dprintk(RIO_DEBUG_PARAM, "Local line\n");
    } else {
        rio_dprintk(RIO_DEBUG_PARAM, "Possible Modem line\n");
    }

    /*
     ** COR 4 (there is no COR 3)
     */
    if (TtyP->termios->c_iflag & IGNBRK) {
        rio_dprintk(RIO_DEBUG_PARAM, "Ignore break condition\n");
        Cor4 |= RIOC_COR4_IGNBRK;
    }
    if (!(TtyP->termios->c_iflag & BRKINT)) {
        rio_dprintk(RIO_DEBUG_PARAM, "Break generates NULL condition\n");
        Cor4 |= RIOC_COR4_NBRKINT;
    } else {
        rio_dprintk(RIO_DEBUG_PARAM, "Interrupt on    break condition\n");
    }

    if (TtyP->termios->c_iflag & INLCR) {
        rio_dprintk(RIO_DEBUG_PARAM, "Map newline to carriage return on input\n");
        Cor4 |= RIOC_COR4_INLCR;
    }

    if (TtyP->termios->c_iflag & IGNCR) {
        rio_dprintk(RIO_DEBUG_PARAM, "Ignore carriage return on input\n");
        Cor4 |= RIOC_COR4_IGNCR;
    }

    if (TtyP->termios->c_iflag & ICRNL) {
        rio_dprintk(RIO_DEBUG_PARAM, "Map carriage return to newline on input\n");
        Cor4 |= RIOC_COR4_ICRNL;
    }
    if (TtyP->termios->c_iflag & IGNPAR) {
        rio_dprintk(RIO_DEBUG_PARAM, "Ignore characters with parity errors\n");
        Cor4 |= RIOC_COR4_IGNPAR;
    }
    if (TtyP->termios->c_iflag & PARMRK) {
        rio_dprintk(RIO_DEBUG_PARAM, "Mark parity errors\n");
        Cor4 |= RIOC_COR4_PARMRK;
    }

    /*
     ** Set the RAISEMOD flag to ensure that the modem lines are raised
     ** on reception of a config packet.
     ** The download code handles the zero baud condition.
     */
    Cor4 |= RIOC_COR4_RAISEMOD;

    /*
     ** COR 5
     */

    Cor5 = RIOC_COR5_CMOE;

    /*
     ** Set to monitor tbusy/tstop (or not).
     */

    if (PortP->MonitorTstate)
        Cor5 |= RIOC_COR5_TSTATE_ON;
    else
        Cor5 |= RIOC_COR5_TSTATE_OFF;

    /*
     ** Could set LNE here if you wanted LNext processing. SVR4 will use it.
     */
    if (TtyP->termios->c_iflag & ISTRIP) {
        rio_dprintk(RIO_DEBUG_PARAM, "Strip input characters\n");
        if (!(PortP->State & RIO_TRIAD_MODE)) {
            Cor5 |= RIOC_COR5_ISTRIP;
        }
    }

    if (TtyP->termios->c_oflag & ONLCR) {
        rio_dprintk(RIO_DEBUG_PARAM, "Map newline to carriage-return, newline on output\n");
        if (PortP->CookMode == COOK_MEDIUM)
            Cor5 |= RIOC_COR5_ONLCR;
    }
    if (TtyP->termios->c_oflag & OCRNL) {
        rio_dprintk(RIO_DEBUG_PARAM, "Map carriage return to newline on output\n");
        if (PortP->CookMode == COOK_MEDIUM)
            Cor5 |= RIOC_COR5_OCRNL;
    }
    if ((TtyP->termios->c_oflag & TABDLY) == TAB3) {
        rio_dprintk(RIO_DEBUG_PARAM, "Tab delay 3 set\n");
        if (PortP->CookMode == COOK_MEDIUM)
            Cor5 |= RIOC_COR5_TAB3;
    }

    /*
     ** Flow control bytes.
     */
    TxXon = TtyP->termios->c_cc[VSTART];
    TxXoff = TtyP->termios->c_cc[VSTOP];
    RxXon = TtyP->termios->c_cc[VSTART];
    RxXoff = TtyP->termios->c_cc[VSTOP];
    /*
     ** LNEXT byte
     */
    LNext = 0;

    /*
     ** Baud rate bytes
     */
    rio_dprintk(RIO_DEBUG_PARAM, "Mapping of rx/tx baud %x (%x)\n", TtyP->termios->c_cflag, CBAUD);

    switch (TtyP->termios->c_cflag & CBAUD) {
#define e(b) case B ## b : RxBaud = TxBaud = RIO_B ## b ;break
        e(50);
        e(75);
        e(110);
        e(134);
        e(150);
        e(200);
        e(300);
        e(600);
        e(1200);
        e(1800);
        e(2400);
        e(4800);
        e(9600);
        e(19200);
        e(38400);
        e(57600);
        e(115200);    /* e(230400);e(460800); e(921600);  */
    }

    rio_dprintk(RIO_DEBUG_PARAM, "tx baud 0x%x, rx baud 0x%x\n", TxBaud, RxBaud);


    /*
     ** Leftovers
     */
    if (TtyP->termios->c_cflag & CREAD)
        rio_dprintk(RIO_DEBUG_PARAM, "Enable receiver\n");
#ifdef RCV1EN
    if (TtyP->termios->c_cflag & RCV1EN)
        rio_dprintk(RIO_DEBUG_PARAM, "RCV1EN (?)\n");
#endif
#ifdef XMT1EN
    if (TtyP->termios->c_cflag & XMT1EN)
        rio_dprintk(RIO_DEBUG_PARAM, "XMT1EN (?)\n");
#endif
    if (TtyP->termios->c_lflag & ISIG)
        rio_dprintk(RIO_DEBUG_PARAM, "Input character signal generating enabled\n");
    if (TtyP->termios->c_lflag & ICANON)
        rio_dprintk(RIO_DEBUG_PARAM, "Canonical input: erase and kill enabled\n");
    if (TtyP->termios->c_lflag & XCASE)
        rio_dprintk(RIO_DEBUG_PARAM, "Canonical upper/lower presentation\n");
    if (TtyP->termios->c_lflag & ECHO)
        rio_dprintk(RIO_DEBUG_PARAM, "Enable input echo\n");
    if (TtyP->termios->c_lflag & ECHOE)
        rio_dprintk(RIO_DEBUG_PARAM, "Enable echo erase\n");
    if (TtyP->termios->c_lflag & ECHOK)
        rio_dprintk(RIO_DEBUG_PARAM, "Enable echo kill\n");
    if (TtyP->termios->c_lflag & ECHONL)
        rio_dprintk(RIO_DEBUG_PARAM, "Enable echo newline\n");
    if (TtyP->termios->c_lflag & NOFLSH)
        rio_dprintk(RIO_DEBUG_PARAM, "Disable flush after interrupt or quit\n");
#ifdef TOSTOP
    if (TtyP->termios->c_lflag & TOSTOP)
        rio_dprintk(RIO_DEBUG_PARAM, "Send SIGTTOU for background output\n");
#endif
#ifdef XCLUDE
    if (TtyP->termios->c_lflag & XCLUDE)
        rio_dprintk(RIO_DEBUG_PARAM, "Exclusive use of this line\n");
#endif
    if (TtyP->termios->c_iflag & IUCLC)
        rio_dprintk(RIO_DEBUG_PARAM, "Map uppercase to lowercase on input\n");
    if (TtyP->termios->c_oflag & OPOST)
        rio_dprintk(RIO_DEBUG_PARAM, "Enable output post-processing\n");
    if (TtyP->termios->c_oflag & OLCUC)
        rio_dprintk(RIO_DEBUG_PARAM, "Map lowercase to uppercase on output\n");
    if (TtyP->termios->c_oflag & ONOCR)
        rio_dprintk(RIO_DEBUG_PARAM, "No carriage return output at column 0\n");
    if (TtyP->termios->c_oflag & ONLRET)
        rio_dprintk(RIO_DEBUG_PARAM, "Newline performs carriage return function\n");
    if (TtyP->termios->c_oflag & OFILL)
        rio_dprintk(RIO_DEBUG_PARAM, "Use fill characters for delay\n");
    if (TtyP->termios->c_oflag & OFDEL)
        rio_dprintk(RIO_DEBUG_PARAM, "Fill character is DEL\n");
    if (TtyP->termios->c_oflag & NLDLY)
        rio_dprintk(RIO_DEBUG_PARAM, "Newline delay set\n");
    if (TtyP->termios->c_oflag & CRDLY)
        rio_dprintk(RIO_DEBUG_PARAM, "Carriage return delay set\n");
    if (TtyP->termios->c_oflag & TABDLY)
        rio_dprintk(RIO_DEBUG_PARAM, "Tab delay set\n");
    /*
     ** These things are kind of useful in a later life!
     */
    PortP->Cor2Copy = Cor2;

    if (PortP->State & RIO_DELETED) {
        rio_spin_unlock_irqrestore(&PortP->portSem, flags);
        func_exit();

        return RIO_FAIL;
    }

    /*
     ** Actually write the info into the packet to be sent
     */
    writeb(cmd, &phb_param_ptr->Cmd);
    writeb(Cor1, &phb_param_ptr->Cor1);
    writeb(Cor2, &phb_param_ptr->Cor2);
    writeb(Cor4, &phb_param_ptr->Cor4);
    writeb(Cor5, &phb_param_ptr->Cor5);
    writeb(TxXon, &phb_param_ptr->TxXon);
    writeb(RxXon, &phb_param_ptr->RxXon);
    writeb(TxXoff, &phb_param_ptr->TxXoff);
    writeb(RxXoff, &phb_param_ptr->RxXoff);
    writeb(LNext, &phb_param_ptr->LNext);
    writeb(TxBaud, &phb_param_ptr->TxBaud);
    writeb(RxBaud, &phb_param_ptr->RxBaud);

    /*
     ** Set the length/command field
     */
    writeb(12 | PKT_CMD_BIT, &PacketP->len);

    /*
     ** The packet is formed - now, whack it off
     ** to its final destination:
     */
    add_transmit(PortP);
    /*
     ** Count characters transmitted for port statistics reporting
     */
    if (PortP->statsGather)
        PortP->txchars += 12;

    rio_spin_unlock_irqrestore(&PortP->portSem, flags);

    rio_dprintk(RIO_DEBUG_PARAM, "add_transmit returned.\n");
    /*
     ** job done.
     */
    func_exit();

    return 0;
}
Пример #4
0
void RIOServiceHost(struct rio_info *p, struct Host *HostP, int From)
{
	rio_spin_lock(&HostP->HostLock);
	if ((HostP->Flags & RUN_STATE) != RC_RUNNING) {
		static int t = 0;
		rio_spin_unlock(&HostP->HostLock);
		if ((t++ % 200) == 0)
			rio_dprintk(RIO_DEBUG_INTR, "Interrupt but host not running. flags=%x.\n", (int) HostP->Flags);
		return;
	}
	rio_spin_unlock(&HostP->HostLock);

	if (readw(&HostP->ParmMapP->rup_intr)) {
		writew(0, &HostP->ParmMapP->rup_intr);
		p->RIORupCount++;
		RupIntr++;
		rio_dprintk(RIO_DEBUG_INTR, "rio: RUP interrupt on host %Zd\n", HostP - p->RIOHosts);
		RIOPollHostCommands(p, HostP);
	}

	if (readw(&HostP->ParmMapP->rx_intr)) {
		int port;

		writew(0, &HostP->ParmMapP->rx_intr);
		p->RIORxCount++;
		RxIntr++;

		rio_dprintk(RIO_DEBUG_INTR, "rio: RX interrupt on host %Zd\n", HostP - p->RIOHosts);
		/*
		 ** Loop through every port. If the port is mapped into
		 ** the system ( i.e. has /dev/ttyXXXX associated ) then it is
		 ** worth checking. If the port isn't open, grab any packets
		 ** hanging on its receive queue and stuff them on the free
		 ** list; check for commands on the way.
		 */
		for (port = p->RIOFirstPortsBooted; port < p->RIOLastPortsBooted + PORTS_PER_RTA; port++) {
			struct Port *PortP = p->RIOPortp[port];
			struct tty_struct *ttyP;
			struct PKT __iomem *PacketP;

			/*
			 ** not mapped in - most of the RIOPortp[] information
			 ** has not been set up!
			 ** Optimise: ports come in bundles of eight.
			 */
			if (!PortP->Mapped) {
				port += 7;
				continue;	/* with the next port */
			}

			/*
			 ** If the host board isn't THIS host board, check the next one.
			 ** optimise: ports come in bundles of eight.
			 */
			if (PortP->HostP != HostP) {
				port += 7;
				continue;
			}

			/*
			 ** Let us see - is the port open? If not, then don't service it.
			 */
			if (!(PortP->PortState & PORT_ISOPEN)) {
				continue;
			}

			/*
			 ** find corresponding tty structure. The process of mapping
			 ** the ports puts these here.
			 */
			ttyP = PortP->gs.tty;

			/*
			 ** Lock the port before we begin working on it.
			 */
			rio_spin_lock(&PortP->portSem);

			/*
			 ** Process received data if there is any.
			 */
			if (can_remove_receive(&PacketP, PortP))
				RIOReceive(p, PortP);

			/*
			 ** If there is no data left to be read from the port, and
			 ** it's handshake bit is set, then we must clear the handshake,
			 ** so that that downstream RTA is re-enabled.
			 */
			if (!can_remove_receive(&PacketP, PortP) && (readw(&PortP->PhbP->handshake) == PHB_HANDSHAKE_SET)) {
				/*
				 ** MAGIC! ( Basically, handshake the RX buffer, so that
				 ** the RTAs upstream can be re-enabled. )
				 */
				rio_dprintk(RIO_DEBUG_INTR, "Set RX handshake bit\n");
				writew(PHB_HANDSHAKE_SET | PHB_HANDSHAKE_RESET, &PortP->PhbP->handshake);
			}
			rio_spin_unlock(&PortP->portSem);
		}
	}

	if (readw(&HostP->ParmMapP->tx_intr)) {
		int port;

		writew(0, &HostP->ParmMapP->tx_intr);

		p->RIOTxCount++;
		TxIntr++;
		rio_dprintk(RIO_DEBUG_INTR, "rio: TX interrupt on host %Zd\n", HostP - p->RIOHosts);

		/*
		 ** Loop through every port.
		 ** If the port is mapped into the system ( i.e. has /dev/ttyXXXX
		 ** associated ) then it is worth checking.
		 */
		for (port = p->RIOFirstPortsBooted; port < p->RIOLastPortsBooted + PORTS_PER_RTA; port++) {
			struct Port *PortP = p->RIOPortp[port];
			struct tty_struct *ttyP;
			struct PKT __iomem *PacketP;

			/*
			 ** not mapped in - most of the RIOPortp[] information
			 ** has not been set up!
			 */
			if (!PortP->Mapped) {
				port += 7;
				continue;	/* with the next port */
			}

			/*
			 ** If the host board isn't running, then its data structures
			 ** are no use to us - continue quietly.
			 */
			if (PortP->HostP != HostP) {
				port += 7;
				continue;	/* with the next port */
			}

			/*
			 ** Let us see - is the port open? If not, then don't service it.
			 */
			if (!(PortP->PortState & PORT_ISOPEN)) {
				continue;
			}

			rio_dprintk(RIO_DEBUG_INTR, "rio: Looking into port %d.\n", port);
			/*
			 ** Lock the port before we begin working on it.
			 */
			rio_spin_lock(&PortP->portSem);

			/*
			 ** If we can't add anything to the transmit queue, then
			 ** we need do none of this processing.
			 */
			if (!can_add_transmit(&PacketP, PortP)) {
				rio_dprintk(RIO_DEBUG_INTR, "Can't add to port, so skipping.\n");
				rio_spin_unlock(&PortP->portSem);
				continue;
			}

			/*
			 ** find corresponding tty structure. The process of mapping
			 ** the ports puts these here.
			 */
			ttyP = PortP->gs.tty;
			/* If ttyP is NULL, the port is getting closed. Forget about it. */
			if (!ttyP) {
				rio_dprintk(RIO_DEBUG_INTR, "no tty, so skipping.\n");
				rio_spin_unlock(&PortP->portSem);
				continue;
			}
			/*
			 ** If there is more room available we start up the transmit
			 ** data process again. This can be direct I/O, if the cookmode
			 ** is set to COOK_RAW or COOK_MEDIUM, or will be a call to the
			 ** riotproc( T_OUTPUT ) if we are in COOK_WELL mode, to fetch
			 ** characters via the line discipline. We must always call
			 ** the line discipline,
			 ** so that user input characters can be echoed correctly.
			 **
			 ** ++++ Update +++++
			 ** With the advent of double buffering, we now see if
			 ** TxBufferOut-In is non-zero. If so, then we copy a packet
			 ** to the output place, and set it going. If this empties
			 ** the buffer, then we must issue a wakeup( ) on OUT.
			 ** If it frees space in the buffer then we must issue
			 ** a wakeup( ) on IN.
			 **
			 ** ++++ Extra! Extra! If PortP->WflushFlag is set, then we
			 ** have to send a WFLUSH command down the PHB, to mark the
			 ** end point of a WFLUSH. We also need to clear out any
			 ** data from the double buffer! ( note that WflushFlag is a
			 ** *count* of the number of WFLUSH commands outstanding! )
			 **
			 ** ++++ And there's more!
			 ** If an RTA is powered off, then on again, and rebooted,
			 ** whilst it has ports open, then we need to re-open the ports.
			 ** ( reasonable enough ). We can't do this when we spot the
			 ** re-boot, in interrupt time, because the queue is probably
			 ** full. So, when we come in here, we need to test if any
			 ** ports are in this condition, and re-open the port before
			 ** we try to send any more data to it. Now, the re-booted
			 ** RTA will be discarding packets from the PHB until it
			 ** receives this open packet, but don't worry tooo much
			 ** about that. The one thing that is interesting is the
			 ** combination of this effect and the WFLUSH effect!
			 */
			/* For now don't handle RTA reboots. -- REW.
			   Reenabled. Otherwise RTA reboots didn't work. Duh. -- REW */
			if (PortP->MagicFlags) {
				if (PortP->MagicFlags & MAGIC_REBOOT) {
					/*
					 ** well, the RTA has been rebooted, and there is room
					 ** on its queue to add the open packet that is required.
					 **
					 ** The messy part of this line is trying to decide if
					 ** we need to call the Param function as a tty or as
					 ** a modem.
					 ** DONT USE CLOCAL AS A TEST FOR THIS!
					 **
					 ** If we can't param the port, then move on to the
					 ** next port.
					 */
					PortP->InUse = NOT_INUSE;

					rio_spin_unlock(&PortP->portSem);
					if (RIOParam(PortP, OPEN, ((PortP->Cor2Copy & (COR2_RTSFLOW | COR2_CTSFLOW)) == (COR2_RTSFLOW | COR2_CTSFLOW)) ? 1 : 0, DONT_SLEEP) == RIO_FAIL) {
						continue;	/* with next port */
					}
					rio_spin_lock(&PortP->portSem);
					PortP->MagicFlags &= ~MAGIC_REBOOT;
				}

				/*
				 ** As mentioned above, this is a tacky hack to cope
				 ** with WFLUSH
				 */
				if (PortP->WflushFlag) {
					rio_dprintk(RIO_DEBUG_INTR, "Want to WFLUSH mark this port\n");

					if (PortP->InUse)
						rio_dprintk(RIO_DEBUG_INTR, "FAILS - PORT IS IN USE\n");
				}

				while (PortP->WflushFlag && can_add_transmit(&PacketP, PortP) && (PortP->InUse == NOT_INUSE)) {
					int p;
					struct PktCmd __iomem *PktCmdP;

					rio_dprintk(RIO_DEBUG_INTR, "Add WFLUSH marker to data queue\n");
					/*
					 ** make it look just like a WFLUSH command
					 */
					PktCmdP = (struct PktCmd __iomem *) &PacketP->data[0];

					writeb(WFLUSH, &PktCmdP->Command);

					p = PortP->HostPort % (u16) PORTS_PER_RTA;

					/*
					 ** If second block of ports for 16 port RTA, add 8
					 ** to index 8-15.
					 */
					if (PortP->SecondBlock)
						p += PORTS_PER_RTA;

					writeb(p, &PktCmdP->PhbNum);

					/*
					 ** to make debuggery easier
					 */
					writeb('W', &PacketP->data[2]);
					writeb('F', &PacketP->data[3]);
					writeb('L', &PacketP->data[4]);
					writeb('U', &PacketP->data[5]);
					writeb('S', &PacketP->data[6]);
					writeb('H', &PacketP->data[7]);
					writeb(' ', &PacketP->data[8]);
					writeb('0' + PortP->WflushFlag, &PacketP->data[9]);
					writeb(' ', &PacketP->data[10]);
					writeb(' ', &PacketP->data[11]);
					writeb('\0', &PacketP->data[12]);

					/*
					 ** its two bytes long!
					 */
					writeb(PKT_CMD_BIT | 2, &PacketP->len);

					/*
					 ** queue it!
					 */
					if (!(PortP->State & RIO_DELETED)) {
						add_transmit(PortP);
						/*
						 ** Count chars tx'd for port statistics reporting
						 */
						if (PortP->statsGather)
							PortP->txchars += 2;
					}

					if (--(PortP->WflushFlag) == 0) {
						PortP->MagicFlags &= ~MAGIC_FLUSH;
					}

					rio_dprintk(RIO_DEBUG_INTR, "Wflush count now stands at %d\n", PortP->WflushFlag);
				}
				if (PortP->MagicFlags & MORE_OUTPUT_EYGOR) {
					if (PortP->MagicFlags & MAGIC_FLUSH) {
						PortP->MagicFlags |= MORE_OUTPUT_EYGOR;
					} else {
						if (!can_add_transmit(&PacketP, PortP)) {
							rio_spin_unlock(&PortP->portSem);
							continue;
						}
						rio_spin_unlock(&PortP->portSem);
						RIOTxEnable((char *) PortP);
						rio_spin_lock(&PortP->portSem);
						PortP->MagicFlags &= ~MORE_OUTPUT_EYGOR;
					}
				}
			}


			/*
			 ** If we can't add anything to the transmit queue, then
			 ** we need do none of the remaining processing.
			 */
			if (!can_add_transmit(&PacketP, PortP)) {
				rio_spin_unlock(&PortP->portSem);
				continue;
			}

			rio_spin_unlock(&PortP->portSem);
			RIOTxEnable((char *) PortP);
		}
	}
}