| /* |
| ** ----------------------------------------------------------------------------- |
| ** |
| ** Perle Specialix driver for Linux |
| ** Ported from existing RIO Driver for SCO sources. |
| * |
| * (C) 1990 - 2000 Specialix International Ltd., Byfleet, Surrey, UK. |
| * |
| * 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 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
| ** |
| ** Module : riotty.c |
| ** SID : 1.3 |
| ** Last Modified : 11/6/98 10:33:47 |
| ** Retrieved : 11/6/98 10:33:50 |
| ** |
| ** ident @(#)riotty.c 1.3 |
| ** |
| ** ----------------------------------------------------------------------------- |
| */ |
| #ifdef SCCS_LABELS |
| static char *_riotty_c_sccs_ = "@(#)riotty.c 1.3"; |
| #endif |
| |
| |
| #define __EXPLICIT_DEF_H__ |
| |
| #include <linux/module.h> |
| #include <linux/slab.h> |
| #include <linux/errno.h> |
| #include <linux/tty.h> |
| #include <linux/string.h> |
| #include <asm/io.h> |
| #include <asm/system.h> |
| #include <asm/string.h> |
| #include <asm/semaphore.h> |
| #include <asm/uaccess.h> |
| |
| #include <linux/termios.h> |
| |
| #include <linux/serial.h> |
| |
| #include <linux/generic_serial.h> |
| |
| |
| #include "linux_compat.h" |
| #include "rio_linux.h" |
| #include "typdef.h" |
| #include "pkt.h" |
| #include "daemon.h" |
| #include "rio.h" |
| #include "riospace.h" |
| #include "top.h" |
| #include "cmdpkt.h" |
| #include "map.h" |
| #include "riotypes.h" |
| #include "rup.h" |
| #include "port.h" |
| #include "riodrvr.h" |
| #include "rioinfo.h" |
| #include "func.h" |
| #include "errors.h" |
| #include "pci.h" |
| |
| #include "parmmap.h" |
| #include "unixrup.h" |
| #include "board.h" |
| #include "host.h" |
| #include "error.h" |
| #include "phb.h" |
| #include "link.h" |
| #include "cmdblk.h" |
| #include "route.h" |
| #include "control.h" |
| #include "cirrus.h" |
| #include "rioioctl.h" |
| #include "param.h" |
| #include "list.h" |
| #include "sam.h" |
| |
| static void RIOClearUp(struct Port *PortP); |
| int RIOShortCommand(struct rio_info *p, struct Port *PortP, int command, int len, int arg); |
| |
| |
| extern int conv_vb[]; /* now defined in ttymgr.c */ |
| extern int conv_bv[]; /* now defined in ttymgr.c */ |
| |
| /* |
| ** 16.09.1998 ARG - Fix to build riotty.k.o for Modular Kernel Support |
| ** |
| ** ep.def.h is necessary for Modular Kernel Support |
| ** DO NOT place any kernel 'extern's after this line |
| ** or this source file will not build riotty.k.o |
| */ |
| #ifdef uLYNX |
| #include <ep.def.h> |
| #endif |
| |
| #ifdef NEED_THIS2 |
| static struct old_sgttyb default_sg = { |
| B19200, B19200, /* input and output speed */ |
| 'H' - '@', /* erase char */ |
| -1, /* 2nd erase char */ |
| 'U' - '@', /* kill char */ |
| ECHO | CRMOD, /* mode */ |
| 'C' - '@', /* interrupt character */ |
| '\\' - '@', /* quit char */ |
| 'Q' - '@', /* start char */ |
| 'S' - '@', /* stop char */ |
| 'D' - '@', /* EOF */ |
| -1, /* brk */ |
| (LCRTBS | LCRTERA | LCRTKIL | LCTLECH), /* local mode word */ |
| 'Z' - '@', /* process stop */ |
| 'Y' - '@', /* delayed stop */ |
| 'R' - '@', /* reprint line */ |
| 'O' - '@', /* flush output */ |
| 'W' - '@', /* word erase */ |
| 'V' - '@' /* literal next char */ |
| }; |
| #endif |
| |
| |
| extern struct rio_info *p; |
| |
| |
| int riotopen(struct tty_struct *tty, struct file *filp) |
| { |
| register uint SysPort; |
| int Modem; |
| int repeat_this = 250; |
| struct Port *PortP; /* pointer to the port structure */ |
| unsigned long flags; |
| int retval = 0; |
| |
| func_enter(); |
| |
| /* Make sure driver_data is NULL in case the rio isn't booted jet. Else gs_close |
| is going to oops. |
| */ |
| tty->driver_data = NULL; |
| |
| SysPort = rio_minor(tty); |
| Modem = rio_ismodem(tty); |
| |
| if (p->RIOFailed) { |
| rio_dprintk(RIO_DEBUG_TTY, "System initialisation failed\n"); |
| pseterr(ENXIO); |
| func_exit(); |
| return -ENXIO; |
| } |
| |
| rio_dprintk(RIO_DEBUG_TTY, "port open SysPort %d (%s) (mapped:%d)\n", SysPort, Modem ? "Modem" : "tty", p->RIOPortp[SysPort]->Mapped); |
| |
| /* |
| ** Validate that we have received a legitimate request. |
| ** Currently, just check that we are opening a port on |
| ** a host card that actually exists, and that the port |
| ** has been mapped onto a host. |
| */ |
| if (SysPort >= RIO_PORTS) { /* out of range ? */ |
| rio_dprintk(RIO_DEBUG_TTY, "Illegal port number %d\n", SysPort); |
| pseterr(ENXIO); |
| func_exit(); |
| return -ENXIO; |
| } |
| |
| /* |
| ** Grab pointer to the port stucture |
| */ |
| PortP = p->RIOPortp[SysPort]; /* Get control struc */ |
| rio_dprintk(RIO_DEBUG_TTY, "PortP: %p\n", PortP); |
| if (!PortP->Mapped) { /* we aren't mapped yet! */ |
| /* |
| ** The system doesn't know which RTA this port |
| ** corresponds to. |
| */ |
| rio_dprintk(RIO_DEBUG_TTY, "port not mapped into system\n"); |
| func_exit(); |
| pseterr(ENXIO); |
| return -ENXIO; |
| } |
| |
| tty->driver_data = PortP; |
| |
| PortP->gs.tty = tty; |
| PortP->gs.count++; |
| |
| rio_dprintk(RIO_DEBUG_TTY, "%d bytes in tx buffer\n", PortP->gs.xmit_cnt); |
| |
| retval = gs_init_port(&PortP->gs); |
| if (retval) { |
| PortP->gs.count--; |
| return -ENXIO; |
| } |
| /* |
| ** If the host hasn't been booted yet, then |
| ** fail |
| */ |
| if ((PortP->HostP->Flags & RUN_STATE) != RC_RUNNING) { |
| rio_dprintk(RIO_DEBUG_TTY, "Host not running\n"); |
| pseterr(ENXIO); |
| func_exit(); |
| return -ENXIO; |
| } |
| |
| /* |
| ** If the RTA has not booted yet and the user has choosen to block |
| ** until the RTA is present then we must spin here waiting for |
| ** the RTA to boot. |
| */ |
| /* I find the above code a bit hairy. I find the below code |
| easier to read and shorter. Now, if it works too that would |
| be great... -- REW |
| */ |
| rio_dprintk(RIO_DEBUG_TTY, "Checking if RTA has booted... \n"); |
| while (!(PortP->HostP->Mapping[PortP->RupNum].Flags & RTA_BOOTED)) { |
| if (!PortP->WaitUntilBooted) { |
| rio_dprintk(RIO_DEBUG_TTY, "RTA never booted\n"); |
| func_exit(); |
| return -ENXIO; |
| } |
| |
| /* Under Linux you'd normally use a wait instead of this |
| busy-waiting. I'll stick with the old implementation for |
| now. --REW |
| */ |
| if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) { |
| rio_dprintk(RIO_DEBUG_TTY, "RTA_wait_for_boot: EINTR in delay \n"); |
| func_exit(); |
| return -EINTR; |
| } |
| if (repeat_this-- <= 0) { |
| rio_dprintk(RIO_DEBUG_TTY, "Waiting for RTA to boot timeout\n"); |
| func_exit(); |
| return -EIO; |
| } |
| } |
| rio_dprintk(RIO_DEBUG_TTY, "RTA has been booted\n"); |
| rio_spin_lock_irqsave(&PortP->portSem, flags); |
| if (p->RIOHalted) { |
| goto bombout; |
| } |
| |
| /* |
| ** If the port is in the final throws of being closed, |
| ** we should wait here (politely), waiting |
| ** for it to finish, so that it doesn't close us! |
| */ |
| while ((PortP->State & RIO_CLOSING) && !p->RIOHalted) { |
| rio_dprintk(RIO_DEBUG_TTY, "Waiting for RIO_CLOSING to go away\n"); |
| if (repeat_this-- <= 0) { |
| rio_dprintk(RIO_DEBUG_TTY, "Waiting for not idle closed broken by signal\n"); |
| RIOPreemptiveCmd(p, PortP, FCLOSE); |
| retval = -EINTR; |
| goto bombout; |
| } |
| rio_spin_unlock_irqrestore(&PortP->portSem, flags); |
| if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) { |
| rio_spin_lock_irqsave(&PortP->portSem, flags); |
| retval = -EINTR; |
| goto bombout; |
| } |
| rio_spin_lock_irqsave(&PortP->portSem, flags); |
| } |
| |
| if (!PortP->Mapped) { |
| rio_dprintk(RIO_DEBUG_TTY, "Port unmapped while closing!\n"); |
| rio_spin_unlock_irqrestore(&PortP->portSem, flags); |
| retval = -ENXIO; |
| func_exit(); |
| return retval; |
| } |
| |
| if (p->RIOHalted) { |
| goto bombout; |
| } |
| |
| /* |
| ** 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. |
| */ |
| /* Uh? Suppose I turn these on and then another process opens |
| the port again? The flags get cleared! Not good. -- REW */ |
| if (!(PortP->State & (RIO_LOPEN | RIO_MOPEN))) { |
| PortP->Config &= ~(RIO_CTSFLOW | RIO_RTSFLOW); |
| } |
| |
| if (!(PortP->firstOpen)) { /* First time ? */ |
| rio_dprintk(RIO_DEBUG_TTY, "First open for this port\n"); |
| |
| |
| PortP->firstOpen++; |
| PortP->CookMode = 0; /* XXX RIOCookMode(tp); */ |
| PortP->InUse = NOT_INUSE; |
| |
| /* Tentative fix for bug PR27. Didn't work. */ |
| /* PortP->gs.xmit_cnt = 0; */ |
| |
| rio_spin_unlock_irqrestore(&PortP->portSem, flags); |
| #ifdef NEED_THIS |
| ttyseth(PortP, tp, (struct old_sgttyb *) &default_sg); |
| #endif |
| |
| /* Someone explain to me why this delay/config is |
| here. If I read the docs correctly the "open" |
| command piggybacks the parameters immediately. |
| -- REW */ |
| RIOParam(PortP, OPEN, Modem, OK_TO_SLEEP); /* Open the port */ |
| rio_spin_lock_irqsave(&PortP->portSem, flags); |
| |
| /* |
| ** wait for the port to be not closed. |
| */ |
| while (!(PortP->PortState & PORT_ISOPEN) && !p->RIOHalted) { |
| rio_dprintk(RIO_DEBUG_TTY, "Waiting for PORT_ISOPEN-currently %x\n", PortP->PortState); |
| /* |
| ** 15.10.1998 ARG - ESIL 0759 |
| ** (Part) fix for port being trashed when opened whilst RTA "disconnected" |
| ** Take out the limited wait - now wait for ever or until user |
| ** bangs us out. |
| ** |
| if (repeat_this -- <= 0) { |
| rio_dprint(RIO_DEBUG_TTY, ("Waiting for open to finish timed out.\n")); |
| RIOPreemptiveCmd(p, PortP, FCLOSE ); |
| rio_spin_unlock_irqrestore(&PortP->portSem, flags); |
| return -EINTR; |
| } |
| ** |
| */ |
| rio_spin_unlock_irqrestore(&PortP->portSem, flags); |
| if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) { |
| rio_dprintk(RIO_DEBUG_TTY, "Waiting for open to finish broken by signal\n"); |
| RIOPreemptiveCmd(p, PortP, FCLOSE); |
| func_exit(); |
| return -EINTR; |
| } |
| rio_spin_lock_irqsave(&PortP->portSem, flags); |
| } |
| |
| if (p->RIOHalted) { |
| retval = -EIO; |
| bombout: |
| /* RIOClearUp( PortP ); */ |
| rio_spin_unlock_irqrestore(&PortP->portSem, flags); |
| return retval; |
| } |
| rio_dprintk(RIO_DEBUG_TTY, "PORT_ISOPEN found\n"); |
| } |
| #ifdef MODEM_SUPPORT |
| if (Modem) { |
| rio_dprintk(RIO_DEBUG_TTY, "Modem - test for carrier\n"); |
| /* |
| ** ACTION |
| ** insert test for carrier here. -- ??? |
| ** I already see that test here. What's the deal? -- REW |
| */ |
| if ((PortP->gs.tty->termios->c_cflag & CLOCAL) || (PortP->ModemState & MSVR1_CD)) { |
| rio_dprintk(RIO_DEBUG_TTY, "open(%d) Modem carr on\n", SysPort); |
| /* |
| tp->tm.c_state |= CARR_ON; |
| wakeup((caddr_t) &tp->tm.c_canq); |
| */ |
| PortP->State |= RIO_CARR_ON; |
| wake_up_interruptible(&PortP->gs.open_wait); |
| } else { /* no carrier - wait for DCD */ |
| |
| /* |
| while (!(PortP->gs.tty->termios->c_state & CARR_ON) && |
| !(filp->f_flags & O_NONBLOCK) && !p->RIOHalted ) |
| */ |
| while (!(PortP->State & RIO_CARR_ON) && !(filp->f_flags & O_NONBLOCK) && !p->RIOHalted) { |
| |
| rio_dprintk(RIO_DEBUG_TTY, "open(%d) sleeping for carr on\n", SysPort); |
| /* |
| PortP->gs.tty->termios->c_state |= WOPEN; |
| */ |
| PortP->State |= RIO_WOPEN; |
| rio_spin_unlock_irqrestore(&PortP->portSem, flags); |
| if (RIODelay(PortP, HUNDRED_MS) == RIO_FAIL) |
| { |
| /* |
| ** ACTION: verify that this is a good thing |
| ** to do here. -- ??? |
| ** I think it's OK. -- REW |
| */ |
| rio_dprintk(RIO_DEBUG_TTY, "open(%d) sleeping for carr broken by signal\n", SysPort); |
| RIOPreemptiveCmd(p, PortP, FCLOSE); |
| /* |
| tp->tm.c_state &= ~WOPEN; |
| */ |
| PortP->State &= ~RIO_WOPEN; |
| rio_spin_unlock_irqrestore(&PortP->portSem, flags); |
| func_exit(); |
| return -EINTR; |
| } |
| } |
| PortP->State &= ~RIO_WOPEN; |
| } |
| if (p->RIOHalted) |
| goto bombout; |
| rio_dprintk(RIO_DEBUG_TTY, "Setting RIO_MOPEN\n"); |
| PortP->State |= RIO_MOPEN; |
| } else |
| #endif |
| { |
| /* |
| ** ACTION |
| ** Direct line open - force carrier (will probably mean |
| ** that sleeping Modem line fubar) |
| */ |
| PortP->State |= RIO_LOPEN; |
| } |
| |
| if (p->RIOHalted) { |
| goto bombout; |
| } |
| |
| rio_dprintk(RIO_DEBUG_TTY, "high level open done\n"); |
| |
| #ifdef STATS |
| PortP->Stat.OpenCnt++; |
| #endif |
| /* |
| ** Count opens for port statistics reporting |
| */ |
| if (PortP->statsGather) |
| PortP->opens++; |
| |
| rio_spin_unlock_irqrestore(&PortP->portSem, flags); |
| rio_dprintk(RIO_DEBUG_TTY, "Returning from open\n"); |
| func_exit(); |
| return 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 Modem; |
| 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 0x%x\n", (int) PortP); |
| /* tp = PortP->TtyP; *//* Get tty */ |
| tty = PortP->gs.tty; |
| rio_dprintk(RIO_DEBUG_TTY, "TTY is at address 0x%x\n", (int) tty); |
| |
| if (PortP->gs.closing_wait) |
| end_time = jiffies + PortP->gs.closing_wait; |
| else |
| end_time = jiffies + MAX_SCHEDULE_TIMEOUT; |
| |
| Modem = rio_ismodem(tty); |
| 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 &= (Modem ? ~RIO_MOPEN : ~RIO_LOPEN); |
| 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)) { |
| cprintf("Need to flush the ttyport\n"); |
| 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); |
| 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); |
| 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); |
| |
| #ifdef STATS |
| PortP->Stat.CloseCnt++; |
| #endif |
| /* |
| ** 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(PortP) |
| 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) |
| { |
| PKT *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 |
| */ |
| WBYTE(PacketP->data[0], command); |
| |
| if (len == 2) |
| WBYTE(PacketP->data[1], arg); |
| |
| /* |
| ** set the length of the packet and set the command bit. |
| */ |
| WBYTE(PacketP->len, PKT_CMD_BIT | 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; |
| } |
| |
| |