📄 istallion.c
字号:
set_bit(ST_DOSIGS, &portp->state); else stli_sendcmd(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0); } clear_bit(ST_TXBUSY, &portp->state); clear_bit(ST_RXSTOP, &portp->state); set_bit(TTY_IO_ERROR, &tty->flags); if (tty->ldisc.flush_buffer) (tty->ldisc.flush_buffer)(tty); set_bit(ST_DOFLUSHRX, &portp->state); stli_flushbuffer(tty); tty->closing = 0; portp->tty = NULL; if (portp->openwaitcnt) { if (portp->close_delay) msleep_interruptible(jiffies_to_msecs(portp->close_delay)); wake_up_interruptible(&portp->open_wait); } portp->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CLOSING); wake_up_interruptible(&portp->close_wait);}/*****************************************************************************//* * Carry out first open operations on a port. This involves a number of * commands to be sent to the slave. We need to open the port, set the * notification events, set the initial port settings, get and set the * initial signal values. We sleep and wait in between each one. But * this still all happens pretty quickly. */static int stli_initopen(struct stlibrd *brdp, struct stliport *portp){ struct tty_struct *tty; asynotify_t nt; asyport_t aport; int rc; if ((rc = stli_rawopen(brdp, portp, 0, 1)) < 0) return rc; memset(&nt, 0, sizeof(asynotify_t)); nt.data = (DT_TXLOW | DT_TXEMPTY | DT_RXBUSY | DT_RXBREAK); nt.signal = SG_DCD; if ((rc = stli_cmdwait(brdp, portp, A_SETNOTIFY, &nt, sizeof(asynotify_t), 0)) < 0) return rc; tty = portp->tty; if (tty == NULL) return -ENODEV; stli_mkasyport(portp, &aport, tty->termios); if ((rc = stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0)) < 0) return rc; set_bit(ST_GETSIGS, &portp->state); if ((rc = stli_cmdwait(brdp, portp, A_GETSIGNALS, &portp->asig, sizeof(asysigs_t), 1)) < 0) return rc; if (test_and_clear_bit(ST_GETSIGS, &portp->state)) portp->sigs = stli_mktiocm(portp->asig.sigvalue); stli_mkasysigs(&portp->asig, 1, 1); if ((rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0)) < 0) return rc; return 0;}/*****************************************************************************//* * Send an open message to the slave. This will sleep waiting for the * acknowledgement, so must have user context. We need to co-ordinate * with close events here, since we don't want open and close events * to overlap. */static int stli_rawopen(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait){ cdkhdr_t __iomem *hdrp; cdkctrl_t __iomem *cp; unsigned char __iomem *bits; unsigned long flags; int rc;/* * Send a message to the slave to open this port. *//* * Slave is already closing this port. This can happen if a hangup * occurs on this port. So we must wait until it is complete. The * order of opens and closes may not be preserved across shared * memory, so we must wait until it is complete. */ wait_event_interruptible(portp->raw_wait, !test_bit(ST_CLOSING, &portp->state)); if (signal_pending(current)) { return -ERESTARTSYS; }/* * Everything is ready now, so write the open message into shared * memory. Once the message is in set the service bits to say that * this port wants service. */ spin_lock_irqsave(&brd_lock, flags); EBRDENABLE(brdp); cp = &((cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl; writel(arg, &cp->openarg); writeb(1, &cp->open); hdrp = (cdkhdr_t __iomem *) EBRDGETMEMPTR(brdp, CDK_CDKADDR); bits = ((unsigned char __iomem *) hdrp) + brdp->slaveoffset + portp->portidx; writeb(readb(bits) | portp->portbit, bits); EBRDDISABLE(brdp); if (wait == 0) { spin_unlock_irqrestore(&brd_lock, flags); return 0; }/* * Slave is in action, so now we must wait for the open acknowledgment * to come back. */ rc = 0; set_bit(ST_OPENING, &portp->state); spin_unlock_irqrestore(&brd_lock, flags); wait_event_interruptible(portp->raw_wait, !test_bit(ST_OPENING, &portp->state)); if (signal_pending(current)) rc = -ERESTARTSYS; if ((rc == 0) && (portp->rc != 0)) rc = -EIO; return rc;}/*****************************************************************************//* * Send a close message to the slave. Normally this will sleep waiting * for the acknowledgement, but if wait parameter is 0 it will not. If * wait is true then must have user context (to sleep). */static int stli_rawclose(struct stlibrd *brdp, struct stliport *portp, unsigned long arg, int wait){ cdkhdr_t __iomem *hdrp; cdkctrl_t __iomem *cp; unsigned char __iomem *bits; unsigned long flags; int rc;/* * Slave is already closing this port. This can happen if a hangup * occurs on this port. */ if (wait) { wait_event_interruptible(portp->raw_wait, !test_bit(ST_CLOSING, &portp->state)); if (signal_pending(current)) { return -ERESTARTSYS; } }/* * Write the close command into shared memory. */ spin_lock_irqsave(&brd_lock, flags); EBRDENABLE(brdp); cp = &((cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl; writel(arg, &cp->closearg); writeb(1, &cp->close); hdrp = (cdkhdr_t __iomem *) EBRDGETMEMPTR(brdp, CDK_CDKADDR); bits = ((unsigned char __iomem *) hdrp) + brdp->slaveoffset + portp->portidx; writeb(readb(bits) |portp->portbit, bits); EBRDDISABLE(brdp); set_bit(ST_CLOSING, &portp->state); spin_unlock_irqrestore(&brd_lock, flags); if (wait == 0) return 0;/* * Slave is in action, so now we must wait for the open acknowledgment * to come back. */ rc = 0; wait_event_interruptible(portp->raw_wait, !test_bit(ST_CLOSING, &portp->state)); if (signal_pending(current)) rc = -ERESTARTSYS; if ((rc == 0) && (portp->rc != 0)) rc = -EIO; return rc;}/*****************************************************************************//* * Send a command to the slave and wait for the response. This must * have user context (it sleeps). This routine is generic in that it * can send any type of command. Its purpose is to wait for that command * to complete (as opposed to initiating the command then returning). */static int stli_cmdwait(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback){ wait_event_interruptible(portp->raw_wait, !test_bit(ST_CMDING, &portp->state)); if (signal_pending(current)) return -ERESTARTSYS; stli_sendcmd(brdp, portp, cmd, arg, size, copyback); wait_event_interruptible(portp->raw_wait, !test_bit(ST_CMDING, &portp->state)); if (signal_pending(current)) return -ERESTARTSYS; if (portp->rc != 0) return -EIO; return 0;}/*****************************************************************************//* * Send the termios settings for this port to the slave. This sleeps * waiting for the command to complete - so must have user context. */static int stli_setport(struct stliport *portp){ struct stlibrd *brdp; asyport_t aport; if (portp == NULL) return -ENODEV; if (portp->tty == NULL) return -ENODEV; if (portp->brdnr >= stli_nrbrds) return -ENODEV; brdp = stli_brds[portp->brdnr]; if (brdp == NULL) return -ENODEV; stli_mkasyport(portp, &aport, portp->tty->termios); return(stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0));}/*****************************************************************************//* * Possibly need to wait for carrier (DCD signal) to come high. Say * maybe because if we are clocal then we don't need to wait... */static int stli_waitcarrier(struct stlibrd *brdp, struct stliport *portp, struct file *filp){ unsigned long flags; int rc, doclocal; rc = 0; doclocal = 0; if (portp->tty->termios->c_cflag & CLOCAL) doclocal++; spin_lock_irqsave(&stli_lock, flags); portp->openwaitcnt++; if (! tty_hung_up_p(filp)) portp->refcount--; spin_unlock_irqrestore(&stli_lock, flags); for (;;) { stli_mkasysigs(&portp->asig, 1, 1); if ((rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0)) < 0) break; if (tty_hung_up_p(filp) || ((portp->flags & ASYNC_INITIALIZED) == 0)) { if (portp->flags & ASYNC_HUP_NOTIFY) rc = -EBUSY; else rc = -ERESTARTSYS; break; } if (((portp->flags & ASYNC_CLOSING) == 0) && (doclocal || (portp->sigs & TIOCM_CD))) { break; } if (signal_pending(current)) { rc = -ERESTARTSYS; break; } interruptible_sleep_on(&portp->open_wait); } spin_lock_irqsave(&stli_lock, flags); if (! tty_hung_up_p(filp)) portp->refcount++; portp->openwaitcnt--; spin_unlock_irqrestore(&stli_lock, flags); return rc;}/*****************************************************************************//* * Write routine. Take the data and put it in the shared memory ring * queue. If port is not already sending chars then need to mark the * service bits for this port. */static int stli_write(struct tty_struct *tty, const unsigned char *buf, int count){ cdkasy_t __iomem *ap; cdkhdr_t __iomem *hdrp; unsigned char __iomem *bits; unsigned char __iomem *shbuf; unsigned char *chbuf; struct stliport *portp; struct stlibrd *brdp; unsigned int len, stlen, head, tail, size; unsigned long flags; if (tty == stli_txcooktty) stli_flushchars(tty); portp = tty->driver_data; if (portp == NULL) return 0; if (portp->brdnr >= stli_nrbrds) return 0; brdp = stli_brds[portp->brdnr]; if (brdp == NULL) return 0; chbuf = (unsigned char *) buf;/* * All data is now local, shove as much as possible into shared memory. */ spin_lock_irqsave(&brd_lock, flags); EBRDENABLE(brdp); ap = (cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr); head = (unsigned int) readw(&ap->txq.head); tail = (unsigned int) readw(&ap->txq.tail); if (tail != ((unsigned int) readw(&ap->txq.tail))) tail = (unsigned int) readw(&ap->txq.tail); size = portp->txsize; if (head >= tail) { len = size - (head - tail) - 1; stlen = size - head; } else { len = tail - head - 1; stlen = len; } len = min(len, (unsigned int)count); count = 0; shbuf = (char __iomem *) EBRDGETMEMPTR(brdp, portp->txoffset); while (len > 0) { stlen = min(len, stlen); memcpy_toio(shbuf + head, chbuf, stlen); chbuf += stlen; len -= stlen; count += stlen; head += stlen; if (head >= size) { head = 0; stlen = tail; } } ap = (cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr); writew(head, &ap->txq.head); if (test_bit(ST_TXBUSY, &portp->state)) { if (readl(&ap->changed.data) & DT_TXEMPTY) writel(readl(&ap->changed.data) & ~DT_TXEMPTY, &ap->changed.data); } hdrp = (cdkhdr_t __iomem *) EBRDGETMEMPTR(brdp, CDK_CDKADDR); bits = ((unsigned char __iomem *) hdrp) + brdp->slaveoffset + portp->portidx; writeb(readb(bits) | portp->portbit, bits); set_bit(ST_TXBUSY, &portp->state); EBRDDISABLE(brdp); spin_unlock_irqrestore(&brd_lock, flags); return(count);}/*****************************************************************************//* * Output a single character. We put it into a temporary local buffer * (for speed) then write out that buffer when the flushchars routine * is called. There is a safety catch here so that if some other port * writes chars before the current buffer has been, then we write them * first them do the new ports. */static void stli_putchar(struct tty_struct *tty, unsigned char ch){ if (tty != stli_txcooktty) { if (stli_txcooktty != NULL) stli_flushchars(stli_txcooktty); stli_txcooktty = tty; } stli_txcookbuf[stli_txcooksize++] = ch;}/*****************************************************************************//* * Transfer characters from the local TX cooking buffer to the board. * We sort of ignore the tty that gets passed in here. We rely on the * info stored with the TX cook buffer to tell us which port to flush * the data on. In any case we clean out the TX cook buffer, for re-use * by someone else. */static void stli_flushchars(struct tty_struct *tty){ cdkhdr_t __iomem *hdrp; unsigned char __iomem *bits; cdkasy_t __iomem *ap; struct tty_struct *cooktty; struct stliport *portp; struct stlibrd *brdp; unsigned int len, stlen, head, tail, size, count, cooksize; unsigned char *buf; unsigned char __iomem *shbuf; unsigned long flags; cooksize = stli_txcooksize; cooktty = stli_txcooktty; stli_txcooksize = 0; stli_txcookrealsize = 0; stli_txcooktty = NULL; if (tty == NULL) return; if (cooktty == NULL) return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -