📄 istallion.c
字号:
unsigned int head, tail, len; unsigned long flags;#if DEBUG printk("stli_writeroom(tty=%x)\n", (int) tty);#endif if (tty == (struct tty_struct *) NULL) return(0); if (tty == stli_txcooktty) { if (stli_txcookrealsize != 0) { len = stli_txcookrealsize - stli_txcooksize; return(len); } } 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); save_flags(flags); cli(); EBRDENABLE(brdp); rp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->txq; head = (unsigned int) rp->head; tail = (unsigned int) rp->tail; if (tail != ((unsigned int) rp->tail)) tail = (unsigned int) rp->tail; len = (head >= tail) ? (portp->txsize - (head - tail)) : (tail - head); len--; EBRDDISABLE(brdp); restore_flags(flags); if (tty == stli_txcooktty) { stli_txcookrealsize = len; len -= stli_txcooksize; } return(len);}/*****************************************************************************//* * Return the number of characters in the transmit buffer. Normally we * will return the number of chars in the shared memory ring queue. * We need to kludge around the case where the shared memory buffer is * empty but not all characters have drained yet, for this case just * return that there is 1 character in the buffer! */static int stli_charsinbuffer(struct tty_struct *tty){ volatile cdkasyrq_t *rp; stliport_t *portp; stlibrd_t *brdp; unsigned int head, tail, len; unsigned long flags;#if DEBUG printk("stli_charsinbuffer(tty=%x)\n", (int) tty);#endif if (tty == (struct tty_struct *) 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); save_flags(flags); cli(); EBRDENABLE(brdp); rp = &((volatile cdkasy_t *) EBRDGETMEMPTR(brdp, portp->addr))->txq; head = (unsigned int) rp->head; tail = (unsigned int) rp->tail; if (tail != ((unsigned int) rp->tail)) tail = (unsigned int) rp->tail; len = (head >= tail) ? (head - tail) : (portp->txsize - (tail - head)); if ((len == 0) && test_bit(ST_TXBUSY, &portp->state)) len = 1; EBRDDISABLE(brdp); restore_flags(flags); return(len);}/*****************************************************************************//* * Generate the serial struct info. */static void stli_getserial(stliport_t *portp, struct serial_struct *sp){ struct serial_struct sio; stlibrd_t *brdp;#if DEBUG printk("stli_getserial(portp=%x,sp=%x)\n", (int) portp, (int) sp);#endif memset(&sio, 0, sizeof(struct serial_struct)); sio.type = PORT_UNKNOWN; sio.line = portp->portnr; sio.irq = 0; sio.flags = portp->flags; sio.baud_base = portp->baud_base; sio.close_delay = portp->close_delay; sio.closing_wait = portp->closing_wait; sio.custom_divisor = portp->custom_divisor; sio.xmit_fifo_size = 0; sio.hub6 = 0; brdp = stli_brds[portp->brdnr]; if (brdp != (stlibrd_t *) NULL) sio.port = brdp->iobase; copy_to_user(sp, &sio, sizeof(struct serial_struct));}/*****************************************************************************//* * Set port according to the serial struct info. * At this point we do not do any auto-configure stuff, so we will * just quietly ignore any requests to change irq, etc. */static int stli_setserial(stliport_t *portp, struct serial_struct *sp){ struct serial_struct sio; int rc;#if DEBUG printk("stli_setserial(portp=%x,sp=%x)\n", (int) portp, (int) sp);#endif copy_from_user(&sio, sp, sizeof(struct serial_struct)); if (!capable(CAP_SYS_ADMIN)) { if ((sio.baud_base != portp->baud_base) || (sio.close_delay != portp->close_delay) || ((sio.flags & ~ASYNC_USR_MASK) != (portp->flags & ~ASYNC_USR_MASK))) return(-EPERM); } portp->flags = (portp->flags & ~ASYNC_USR_MASK) | (sio.flags & ASYNC_USR_MASK); portp->baud_base = sio.baud_base; portp->close_delay = sio.close_delay; portp->closing_wait = sio.closing_wait; portp->custom_divisor = sio.custom_divisor; if ((rc = stli_setport(portp)) < 0) return(rc); return(0);}/*****************************************************************************/static int stli_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg){ stliport_t *portp; stlibrd_t *brdp; unsigned long lval; unsigned int ival; int rc;#if DEBUG printk("stli_ioctl(tty=%x,file=%x,cmd=%x,arg=%x)\n", (int) tty, (int) file, cmd, (int) arg);#endif if (tty == (struct tty_struct *) NULL) return(-ENODEV); portp = tty->driver_data; if (portp == (stliport_t *) NULL) return(-ENODEV); if ((portp->brdnr < 0) || (portp->brdnr >= stli_nrbrds)) return(0); brdp = stli_brds[portp->brdnr]; if (brdp == (stlibrd_t *) NULL) return(0); if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && (cmd != COM_GETPORTSTATS) && (cmd != COM_CLRPORTSTATS)) { if (tty->flags & (1 << TTY_IO_ERROR)) return(-EIO); } rc = 0; switch (cmd) { case TIOCGSOFTCAR: rc = put_user(((tty->termios->c_cflag & CLOCAL) ? 1 : 0), (unsigned int *) arg); break; case TIOCSSOFTCAR: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned int))) == 0) { get_user(ival, (unsigned int *) arg); tty->termios->c_cflag = (tty->termios->c_cflag & ~CLOCAL) | (ival ? CLOCAL : 0); } break; case TIOCMGET: if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned int))) == 0) { if ((rc = stli_cmdwait(brdp, portp, A_GETSIGNALS, &portp->asig, sizeof(asysigs_t), 1)) < 0) return(rc); lval = stli_mktiocm(portp->asig.sigvalue); put_user(lval, (unsigned int *) arg); } break; case TIOCMBIS: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned int))) == 0) { get_user(ival, (unsigned int *) arg); stli_mkasysigs(&portp->asig, ((ival & TIOCM_DTR) ? 1 : -1), ((ival & TIOCM_RTS) ? 1 : -1)); rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0); } break; case TIOCMBIC: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned int))) == 0) { get_user(ival, (unsigned int *) arg); stli_mkasysigs(&portp->asig, ((ival & TIOCM_DTR) ? 0 : -1), ((ival & TIOCM_RTS) ? 0 : -1)); rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0); } break; case TIOCMSET: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned int))) == 0) { get_user(ival, (unsigned int *) arg); stli_mkasysigs(&portp->asig, ((ival & TIOCM_DTR) ? 1 : 0), ((ival & TIOCM_RTS) ? 1 : 0)); rc = stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0); } break; case TIOCGSERIAL: if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct serial_struct))) == 0) stli_getserial(portp, (struct serial_struct *) arg); break; case TIOCSSERIAL: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(struct serial_struct))) == 0) rc = stli_setserial(portp, (struct serial_struct *)arg); break; case STL_GETPFLAG: if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long))) == 0) put_user(portp->pflag, (unsigned int *) arg); break; case STL_SETPFLAG: if ((rc = verify_area(VERIFY_READ, (void *) arg, sizeof(unsigned long))) == 0) { get_user(portp->pflag, (unsigned int *) arg); stli_setport(portp); } break; case COM_GETPORTSTATS: if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(comstats_t))) == 0) rc = stli_getportstats(portp, (comstats_t *) arg); break; case COM_CLRPORTSTATS: if ((rc = verify_area(VERIFY_WRITE, (void *) arg, sizeof(comstats_t))) == 0) rc = stli_clrportstats(portp, (comstats_t *) arg); break; case TIOCSERCONFIG: case TIOCSERGWILD: case TIOCSERSWILD: case TIOCSERGETLSR: case TIOCSERGSTRUCT: case TIOCSERGETMULTI: case TIOCSERSETMULTI: default: rc = -ENOIOCTLCMD; break; } return(rc);}/*****************************************************************************//* * This routine assumes that we have user context and can sleep. * Looks like it is true for the current ttys implementation..!! */static void stli_settermios(struct tty_struct *tty, struct termios *old){ stliport_t *portp; stlibrd_t *brdp; struct termios *tiosp; asyport_t aport;#if DEBUG printk("stli_settermios(tty=%x,old=%x)\n", (int) tty, (int) old);#endif if (tty == (struct tty_struct *) NULL) 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; tiosp = tty->termios; if ((tiosp->c_cflag == old->c_cflag) && (tiosp->c_iflag == old->c_iflag)) return; stli_mkasyport(portp, &aport, tiosp); stli_cmdwait(brdp, portp, A_SETPORT, &aport, sizeof(asyport_t), 0); stli_mkasysigs(&portp->asig, ((tiosp->c_cflag & CBAUD) ? 1 : 0), -1); stli_cmdwait(brdp, portp, A_SETSIGNALS, &portp->asig, sizeof(asysigs_t), 0); if ((old->c_cflag & CRTSCTS) && ((tiosp->c_cflag & CRTSCTS) == 0)) tty->hw_stopped = 0; if (((old->c_cflag & CLOCAL) == 0) && (tiosp->c_cflag & CLOCAL)) wake_up_interruptible(&portp->open_wait);}/*****************************************************************************//* * Attempt to flow control who ever is sending us data. We won't really * do any flow control action here. We can't directly, and even if we * wanted to we would have to send a command to the slave. The slave * knows how to flow control, and will do so when its buffers reach its * internal high water marks. So what we will do is set a local state * bit that will stop us sending any RX data up from the poll routine * (which is the place where RX data from the slave is handled). */static void stli_throttle(struct tty_struct *tty){ stliport_t *portp;#if DEBUG printk("stli_throttle(tty=%x)\n", (int) tty);#endif if (tty == (struct tty_struct *) NULL) return; portp = tty->driver_data; if (portp == (stliport_t *) NULL) return; set_bit(ST_RXSTOP, &portp->state);}/*****************************************************************************//* * Unflow control the device sending us data... That means that all * we have to do is clear the RXSTOP state bit. The next poll call * will then be able to pass the RX data back up. */static void stli_unthrottle(struct tty_struct *tty){ stliport_t *portp;#if DEBUG printk("stli_unthrottle(tty=%x)\n", (int) tty);#endif if (tty == (struct tty_struct *) NULL) return; portp = tty->driver_data; if (portp == (stliport_t *) NULL) return; clear_bit(ST_RXSTOP, &portp->state);}/*****************************************************************************//* * Stop the transmitter. Basically to do this we will just turn TX * interrupts off. */static void stli_stop(struct tty_struct *tty){ stlibrd_t *brdp; stliport_t *portp; asyctrl_t actrl;#if DEBUG printk("stli_stop(tty=%x)\n", (int) tty);#endif if (tty == (struct tty_struct *) NULL) 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; memset(&actrl, 0, sizeof(asyctrl_t)); actrl.txctrl = CT_STOPFLOW;#if 0 stli_cmdwait(brdp, portp, A_PORTCTRL, &actrl, sizeof(asyctrl_t), 0);#endif}/*****************************************************************************//* * Start the transmitter again. Just turn TX interrupts back on. */static void stli_start(struct tty_struct *tty){ stliport_t *portp; stlibrd_t *brdp; asyctrl_t actrl;#if DEBUG printk("stli_start(tty=%x)\n", (int) tty);#endif if (tty == (struct tty_struct *) NULL) 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 (br
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -