📄 istallion.c
字号:
}/*****************************************************************************//* * Hangup this port. This is pretty much like closing the port, only * a little more brutal. No waiting for data to drain. Shutdown the * port and maybe drop signals. This is rather tricky really. We want * to close the port as well. */static void stli_hangup(struct tty_struct *tty){ struct stliport *portp; struct stlibrd *brdp; unsigned long flags; portp = tty->driver_data; if (portp == NULL) return; if (portp->brdnr >= stli_nrbrds) return; brdp = stli_brds[portp->brdnr]; if (brdp == NULL) return; portp->flags &= ~ASYNC_INITIALIZED; if (!test_bit(ST_CLOSING, &portp->state)) stli_rawclose(brdp, portp, 0, 0); spin_lock_irqsave(&stli_lock, flags); if (tty->termios->c_cflag & HUPCL) { stli_mkasysigs(&portp->asig, 0, 0); if (test_bit(ST_CMDING, &portp->state)) { set_bit(ST_DOSIGS, &portp->state); set_bit(ST_DOFLUSHTX, &portp->state); set_bit(ST_DOFLUSHRX, &portp->state); } else { stli_sendcmd(brdp, portp, A_SETSIGNALSF, &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); portp->tty = NULL; portp->flags &= ~ASYNC_NORMAL_ACTIVE; portp->refcount = 0; spin_unlock_irqrestore(&stli_lock, flags); wake_up_interruptible(&portp->open_wait);}/*****************************************************************************//* * Flush characters from the lower buffer. We may not have user context * so we cannot sleep waiting for it to complete. Also we need to check * if there is chars for this port in the TX cook buffer, and flush them * as well. */static void stli_flushbuffer(struct tty_struct *tty){ struct stliport *portp; struct stlibrd *brdp; unsigned long ftype, flags; portp = tty->driver_data; if (portp == NULL) return; if (portp->brdnr >= stli_nrbrds) return; brdp = stli_brds[portp->brdnr]; if (brdp == NULL) return; spin_lock_irqsave(&brd_lock, flags); if (tty == stli_txcooktty) { stli_txcooktty = NULL; stli_txcooksize = 0; stli_txcookrealsize = 0; } if (test_bit(ST_CMDING, &portp->state)) { set_bit(ST_DOFLUSHTX, &portp->state); } else { ftype = FLUSHTX; if (test_bit(ST_DOFLUSHRX, &portp->state)) { ftype |= FLUSHRX; clear_bit(ST_DOFLUSHRX, &portp->state); } __stli_sendcmd(brdp, portp, A_FLUSH, &ftype, sizeof(u32), 0); } spin_unlock_irqrestore(&brd_lock, flags); tty_wakeup(tty);}/*****************************************************************************/static void stli_breakctl(struct tty_struct *tty, int state){ struct stlibrd *brdp; struct stliport *portp; long arg; portp = tty->driver_data; if (portp == NULL) return; if (portp->brdnr >= stli_nrbrds) return; brdp = stli_brds[portp->brdnr]; if (brdp == NULL) return; arg = (state == -1) ? BREAKON : BREAKOFF; stli_cmdwait(brdp, portp, A_BREAK, &arg, sizeof(long), 0);}/*****************************************************************************/static void stli_waituntilsent(struct tty_struct *tty, int timeout){ struct stliport *portp; unsigned long tend; if (tty == NULL) return; portp = tty->driver_data; if (portp == NULL) return; if (timeout == 0) timeout = HZ; tend = jiffies + timeout; while (test_bit(ST_TXBUSY, &portp->state)) { if (signal_pending(current)) break; msleep_interruptible(20); if (time_after_eq(jiffies, tend)) break; }}/*****************************************************************************/static void stli_sendxchar(struct tty_struct *tty, char ch){ struct stlibrd *brdp; struct stliport *portp; asyctrl_t actrl; portp = tty->driver_data; if (portp == NULL) return; if (portp->brdnr >= stli_nrbrds) return; brdp = stli_brds[portp->brdnr]; if (brdp == NULL) return; memset(&actrl, 0, sizeof(asyctrl_t)); if (ch == STOP_CHAR(tty)) { actrl.rxctrl = CT_STOPFLOW; } else if (ch == START_CHAR(tty)) { actrl.rxctrl = CT_STARTFLOW; } else { actrl.txctrl = CT_SENDCHR; actrl.tximdch = ch; } stli_cmdwait(brdp, portp, A_PORTCTRL, &actrl, sizeof(asyctrl_t), 0);}/*****************************************************************************/#define MAXLINE 80/* * Format info for a specified port. The line is deliberately limited * to 80 characters. (If it is too long it will be truncated, if too * short then padded with spaces). */static int stli_portinfo(struct stlibrd *brdp, struct stliport *portp, int portnr, char *pos){ char *sp, *uart; int rc, cnt; rc = stli_portcmdstats(portp); uart = "UNKNOWN"; if (brdp->state & BST_STARTED) { switch (stli_comstats.hwid) { case 0: uart = "2681"; break; case 1: uart = "SC26198"; break; default:uart = "CD1400"; break; } } sp = pos; sp += sprintf(sp, "%d: uart:%s ", portnr, uart); if ((brdp->state & BST_STARTED) && (rc >= 0)) { sp += sprintf(sp, "tx:%d rx:%d", (int) stli_comstats.txtotal, (int) stli_comstats.rxtotal); if (stli_comstats.rxframing) sp += sprintf(sp, " fe:%d", (int) stli_comstats.rxframing); if (stli_comstats.rxparity) sp += sprintf(sp, " pe:%d", (int) stli_comstats.rxparity); if (stli_comstats.rxbreaks) sp += sprintf(sp, " brk:%d", (int) stli_comstats.rxbreaks); if (stli_comstats.rxoverrun) sp += sprintf(sp, " oe:%d", (int) stli_comstats.rxoverrun); cnt = sprintf(sp, "%s%s%s%s%s ", (stli_comstats.signals & TIOCM_RTS) ? "|RTS" : "", (stli_comstats.signals & TIOCM_CTS) ? "|CTS" : "", (stli_comstats.signals & TIOCM_DTR) ? "|DTR" : "", (stli_comstats.signals & TIOCM_CD) ? "|DCD" : "", (stli_comstats.signals & TIOCM_DSR) ? "|DSR" : ""); *sp = ' '; sp += cnt; } for (cnt = (sp - pos); (cnt < (MAXLINE - 1)); cnt++) *sp++ = ' '; if (cnt >= MAXLINE) pos[(MAXLINE - 2)] = '+'; pos[(MAXLINE - 1)] = '\n'; return(MAXLINE);}/*****************************************************************************//* * Port info, read from the /proc file system. */static int stli_readproc(char *page, char **start, off_t off, int count, int *eof, void *data){ struct stlibrd *brdp; struct stliport *portp; unsigned int brdnr, portnr, totalport; int curoff, maxoff; char *pos; pos = page; totalport = 0; curoff = 0; if (off == 0) { pos += sprintf(pos, "%s: version %s", stli_drvtitle, stli_drvversion); while (pos < (page + MAXLINE - 1)) *pos++ = ' '; *pos++ = '\n'; } curoff = MAXLINE;/* * We scan through for each board, panel and port. The offset is * calculated on the fly, and irrelevant ports are skipped. */ for (brdnr = 0; (brdnr < stli_nrbrds); brdnr++) { brdp = stli_brds[brdnr]; if (brdp == NULL) continue; if (brdp->state == 0) continue; maxoff = curoff + (brdp->nrports * MAXLINE); if (off >= maxoff) { curoff = maxoff; continue; } totalport = brdnr * STL_MAXPORTS; for (portnr = 0; (portnr < brdp->nrports); portnr++, totalport++) { portp = brdp->ports[portnr]; if (portp == NULL) continue; if (off >= (curoff += MAXLINE)) continue; if ((pos - page + MAXLINE) > count) goto stli_readdone; pos += stli_portinfo(brdp, portp, totalport, pos); } } *eof = 1;stli_readdone: *start = page; return(pos - page);}/*****************************************************************************//* * Generic send command routine. This will send a message to the slave, * of the specified type with the specified argument. Must be very * careful of data that will be copied out from shared memory - * containing command results. The command completion is all done from * a poll routine that does not have user context. Therefore you cannot * copy back directly into user space, or to the kernel stack of a * process. This routine does not sleep, so can be called from anywhere. * * The caller must hold the brd_lock (see also stli_sendcmd the usual * entry point) */static void __stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback){ cdkhdr_t __iomem *hdrp; cdkctrl_t __iomem *cp; unsigned char __iomem *bits; if (test_bit(ST_CMDING, &portp->state)) { printk(KERN_ERR "STALLION: command already busy, cmd=%x!\n", (int) cmd); return; } EBRDENABLE(brdp); cp = &((cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr))->ctrl; if (size > 0) { memcpy_toio((void __iomem *) &(cp->args[0]), arg, size); if (copyback) { portp->argp = arg; portp->argsize = size; } } writel(0, &cp->status); writel(cmd, &cp->cmd); 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_CMDING, &portp->state); EBRDDISABLE(brdp);}static void stli_sendcmd(struct stlibrd *brdp, struct stliport *portp, unsigned long cmd, void *arg, int size, int copyback){ unsigned long flags; spin_lock_irqsave(&brd_lock, flags); __stli_sendcmd(brdp, portp, cmd, arg, size, copyback); spin_unlock_irqrestore(&brd_lock, flags);}/*****************************************************************************//* * Read data from shared memory. This assumes that the shared memory * is enabled and that interrupts are off. Basically we just empty out * the shared memory buffer into the tty buffer. Must be careful to * handle the case where we fill up the tty buffer, but still have * more chars to unload. */static void stli_read(struct stlibrd *brdp, struct stliport *portp){ cdkasyrq_t __iomem *rp; char __iomem *shbuf; struct tty_struct *tty; unsigned int head, tail, size; unsigned int len, stlen; if (test_bit(ST_RXSTOP, &portp->state)) return; tty = portp->tty; if (tty == NULL) return; rp = &((cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr))->rxq; head = (unsigned int) readw(&rp->head); if (head != ((unsigned int) readw(&rp->head))) head = (unsigned int) readw(&rp->head); tail = (unsigned int) readw(&rp->tail); size = portp->rxsize; if (head >= tail) { len = head - tail; stlen = len; } else { len = size - (tail - head); stlen = size - tail; } len = tty_buffer_request_room(tty, len); shbuf = (char __iomem *) EBRDGETMEMPTR(brdp, portp->rxoffset); while (len > 0) { unsigned char *cptr; stlen = min(len, stlen); tty_prepare_flip_string(tty, &cptr, stlen); memcpy_fromio(cptr, shbuf + tail, stlen); len -= stlen; tail += stlen; if (tail >= size) { tail = 0; stlen = head; } } rp = &((cdkasy_t __iomem *) EBRDGETMEMPTR(brdp, portp->addr))->rxq; writew(tail, &rp->tail); if (head != tail) set_bit(ST_RXING, &portp->state); tty_schedule_flip(tty);}/*****************************************************************************//* * Set up and carry out any delayed commands. There is only a small set * of slave commands that can be done "off-level". So it is not too * difficult to deal with them here. */static void stli_dodelaycmd(struct stliport *portp, cdkctrl_t __iomem *cp){ int cmd; if (test_bit(ST_DOSIGS, &portp->state)) { if (test_bit(ST_DOFLUSHTX, &portp->state) && test_bit(ST_DOFLUSHRX, &portp->state)) cmd = A_SETSIGNALSF; else if (test_bit(ST_DOFLUSHTX, &portp->state)) cmd = A_SETSIGNALSFTX; else if (test_bit(ST_DOFLUSHRX, &portp->state)) cmd = A_SETSIGNALSFRX; else cmd = A_SETSIGNALS; clear_bit(ST_DOFLUSHTX, &portp->state); clear_bit(ST_DOFLUSHRX, &portp->state); clear_bit(ST_DOSIGS, &portp->state); memcpy_toio((void __iomem *) &(cp->args[0]), (void *) &portp->asig, sizeof(asysigs_t)); writel(0, &cp->status); writel(cmd, &cp->cmd); set_bit(ST_CMDING, &portp->state); } else if (test_bit(ST_DOFLUSHTX, &portp->state) || test_bit(ST_DOFLUSHRX, &portp->state)) { cmd = ((test_bit(ST_DOFLUSHTX, &portp->state)) ? FLUSHTX : 0); cmd |= ((test_bit(ST_DOFLUSHRX, &portp->state)) ? FLUSHRX : 0); clear_bit(ST_DOFLUSHTX, &portp->state); clear_bit(ST_DOFLUS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -