📄 istallion.c
字号:
interruptible_sleep_on(&portp->raw_wait); } }/* * Write the close command into shared memory. */ EBRDENABLE(brdp); cp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl; cp->closearg = arg; cp->close = 1; hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR); bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset + portp->portidx; *bits |= portp->portbit; EBRDDISABLE(brdp); set_bit(ST_CLOSING, &portp->state); if (wait == 0) { restore_flags(flags); return(0); }/* * Slave is in action, so now we must wait for the open acknowledgment * to come back. */ rc = 0; while (test_bit(ST_CLOSING, &portp->state)) { if (signal_pending(current)) { rc = -ERESTARTSYS; break; } interruptible_sleep_on(&portp->raw_wait); } restore_flags(flags); 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(stlibrd_t *brdp, stliport_t *portp, unsigned long cmd, void *arg, int size, int copyback){ unsigned long flags;#if DEBUG printk("stli_cmdwait(brdp=%x,portp=%x,cmd=%x,arg=%x,size=%d," "copyback=%d)\n", (int) brdp, (int) portp, (int) cmd, (int) arg, size, copyback);#endif save_flags(flags); cli(); while (test_bit(ST_CMDING, &portp->state)) { if (signal_pending(current)) { restore_flags(flags); return(-ERESTARTSYS); } interruptible_sleep_on(&portp->raw_wait); } stli_sendcmd(brdp, portp, cmd, arg, size, copyback); while (test_bit(ST_CMDING, &portp->state)) { if (signal_pending(current)) { restore_flags(flags); return(-ERESTARTSYS); } interruptible_sleep_on(&portp->raw_wait); } restore_flags(flags); 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(stliport_t *portp){ stlibrd_t *brdp; asyport_t aport;#if DEBUG printk("stli_setport(portp=%x)\n", (int) portp);#endif if (portp == (stliport_t *) NULL) return(-ENODEV); if (portp->tty == (struct tty_struct *) NULL) return(-ENODEV); if ((portp->brdnr < 0) && (portp->brdnr >= stli_nrbrds)) return(-ENODEV); brdp = stli_brds[portp->brdnr]; if (brdp == (stlibrd_t *) NULL) return(-ENODEV); stli_mkasyport(portp, &aport, portp->tty->termios); return(stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0));}/*****************************************************************************//* * Wait for a specified delay period, this is not a busy-loop. It will * give up the processor while waiting. Unfortunately this has some * rather intimate knowledge of the process management stuff. */static void stli_delay(int len){#if DEBUG printk("stli_delay(len=%d)\n", len);#endif if (len > 0) { current->state = TASK_INTERRUPTIBLE; schedule_timeout(len); current->state = TASK_RUNNING; }}/*****************************************************************************//* * 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(stlibrd_t *brdp, stliport_t *portp, struct file *filp){ unsigned long flags; int rc, doclocal;#if DEBUG printk("stli_waitcarrier(brdp=%x,portp=%x,filp=%x)\n", (int) brdp, (int) portp, (int) filp);#endif rc = 0; doclocal = 0; if (portp->flags & ASYNC_CALLOUT_ACTIVE) { if (portp->normaltermios.c_cflag & CLOCAL) doclocal++; } else { if (portp->tty->termios->c_cflag & CLOCAL) doclocal++; } save_flags(flags); cli(); portp->openwaitcnt++; if (! tty_hung_up_p(filp)) portp->refcount--; for (;;) { if ((portp->flags & ASYNC_CALLOUT_ACTIVE) == 0) { 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_CALLOUT_ACTIVE) == 0) && ((portp->flags & ASYNC_CLOSING) == 0) && (doclocal || (portp->sigs & TIOCM_CD))) { break; } if (signal_pending(current)) { rc = -ERESTARTSYS; break; } interruptible_sleep_on(&portp->open_wait); } if (! tty_hung_up_p(filp)) portp->refcount++; portp->openwaitcnt--; restore_flags(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, int from_user, const unsigned char *buf, int count){ volatile cdkasy_t *ap; volatile cdkhdr_t *hdrp; volatile unsigned char *bits; unsigned char *shbuf, *chbuf; stliport_t *portp; stlibrd_t *brdp; unsigned int len, stlen, head, tail, size; unsigned long flags;#if DEBUG printk("stli_write(tty=%x,from_user=%d,buf=%x,count=%d)\n", (int) tty, from_user, (int) buf, count);#endif if ((tty == (struct tty_struct *) NULL) || (stli_tmpwritebuf == (char *) NULL)) return(0); if (tty == stli_txcooktty) stli_flushchars(tty); portp = tty->driver_data; if (portp == (stliport_t *) NULL) return(0); if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds)) return(0); brdp = stli_brds[portp->brdnr]; if (brdp == (stlibrd_t *) NULL) return(0); chbuf = (unsigned char *) buf;/* * If copying direct from user space we need to be able to handle page * faults while we are copying. To do this copy as much as we can now * into a kernel buffer. From there we copy it into shared memory. The * big problem is that we do not want shared memory enabled when we are * sleeping (other boards may be serviced while asleep). Something else * to note here is the reading of the tail twice. Since the boards * shared memory can be on an 8-bit bus then we need to be very careful * reading 16 bit quantities - since both the board (slave) and host * could be writing and reading at the same time. */ if (from_user) { save_flags(flags); cli(); EBRDENABLE(brdp); ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr); head = (unsigned int) ap->txq.head; tail = (unsigned int) ap->txq.tail; if (tail != ((unsigned int) ap->txq.tail)) tail = (unsigned int) ap->txq.tail; len = (head >= tail) ? (portp->txsize - (head - tail) - 1) : (tail - head - 1); count = MIN(len, count); EBRDDISABLE(brdp); restore_flags(flags); down(&stli_tmpwritesem); copy_from_user(stli_tmpwritebuf, chbuf, count); chbuf = &stli_tmpwritebuf[0]; }/* * All data is now local, shove as much as possible into shared memory. */ save_flags(flags); cli(); EBRDENABLE(brdp); ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr); head = (unsigned int) ap->txq.head; tail = (unsigned int) ap->txq.tail; if (tail != ((unsigned int) ap->txq.tail)) tail = (unsigned int) 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, count); count = 0; shbuf = (char *) EBRDGETMEMPTR(brdp, portp->txoffset); while (len > 0) { stlen = MIN(len, stlen); memcpy((shbuf + head), chbuf, stlen); chbuf += stlen; len -= stlen; count += stlen; head += stlen; if (head >= size) { head = 0; stlen = tail; } } ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr); ap->txq.head = head; if (test_bit(ST_TXBUSY, &portp->state)) { if (ap->changed.data & DT_TXEMPTY) ap->changed.data &= ~DT_TXEMPTY; } hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR); bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset + portp->portidx; *bits |= portp->portbit; set_bit(ST_TXBUSY, &portp->state); EBRDDISABLE(brdp); if (from_user) up(&stli_tmpwritesem); restore_flags(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 DEBUG printk("stli_putchar(tty=%x,ch=%x)\n", (int) tty, (int) ch);#endif if (tty == (struct tty_struct *) NULL) return; if (tty != stli_txcooktty) { if (stli_txcooktty != (struct tty_struct *) 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){ volatile cdkhdr_t *hdrp; volatile unsigned char *bits; volatile cdkasy_t *ap; struct tty_struct *cooktty; stliport_t *portp; stlibrd_t *brdp; unsigned int len, stlen, head, tail, size, count, cooksize; unsigned char *buf, *shbuf; unsigned long flags;#if DEBUG printk("stli_flushchars(tty=%x)\n", (int) tty);#endif cooksize = stli_txcooksize; cooktty = stli_txcooktty; stli_txcooksize = 0; stli_txcookrealsize = 0; stli_txcooktty = (struct tty_struct *) NULL; if (tty == (struct tty_struct *) NULL) return; if (cooktty == (struct tty_struct *) NULL) return; if (tty != cooktty) tty = cooktty; if (cooksize == 0) return; portp = tty->driver_data; if (portp == (stliport_t *) NULL) return; if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds)) return; brdp = stli_brds[portp->brdnr]; if (brdp == (stlibrd_t *) NULL) return; save_flags(flags); cli(); EBRDENABLE(brdp); ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr); head = (unsigned int) ap->txq.head; tail = (unsigned int) ap->txq.tail; if (tail != ((unsigned int) ap->txq.tail)) tail = (unsigned int) 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, cooksize); count = 0; shbuf = (char *) EBRDGETMEMPTR(brdp, portp->txoffset); buf = stli_txcookbuf; while (len > 0) { stlen = MIN(len, stlen); memcpy((shbuf + head), buf, stlen); buf += stlen; len -= stlen; count += stlen; head += stlen; if (head >= size) { head = 0; stlen = tail; } } ap = (volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr); ap->txq.head = head; if (test_bit(ST_TXBUSY, &portp->state)) { if (ap->changed.data & DT_TXEMPTY) ap->changed.data &= ~DT_TXEMPTY; } hdrp = (volatile cdkhdr_t *) EBRDGETMEMPTR(brdp, CDK_CDKADDR); bits = ((volatile unsigned char *) hdrp) + brdp->slaveoffset + portp->portidx; *bits |= portp->portbit; set_bit(ST_TXBUSY, &portp->state); EBRDDISABLE(brdp); restore_flags(flags);}/*****************************************************************************/static int stli_writeroom(struct tty_struct *tty){ volatile cdkasyrq_t *rp; stliport_t *portp; stlibrd_t *brdp;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -