- /*
- * and set the speed of the serial port
- */
- spin_unlock_irqrestore(&info->slock, flags);
- mxser_change_speed(info, NULL);
-
- info->flags |= ASYNC_INITIALIZED;
- return (0);
-}
-
-/*
- * This routine will shutdown a serial port; interrupts maybe disabled, and
- * DTR is dropped if the hangup on close termio flag is on.
- */
-static void mxser_shutdown(struct mxser_struct *info)
-{
- unsigned long flags;
-
- if (!(info->flags & ASYNC_INITIALIZED))
- return;
-
- spin_lock_irqsave(&info->slock, flags);
-
- /*
- * clear delta_msr_wait queue to avoid mem leaks: we may free the irq
- * here so the queue might never be waken up
- */
- wake_up_interruptible(&info->delta_msr_wait);
-
- /*
- * Free the IRQ, if necessary
- */
- if (info->xmit_buf) {
- free_page((unsigned long) info->xmit_buf);
- info->xmit_buf = NULL;
- }
-
- info->IER = 0;
- outb(0x00, info->base + UART_IER);
-
- if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
- info->MCR &= ~(UART_MCR_DTR | UART_MCR_RTS);
- outb(info->MCR, info->base + UART_MCR);
-
- /* clear Rx/Tx FIFO's */
- // following add by Victor Yu. 08-30-2002
- if (info->IsMoxaMustChipFlag)
- outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT | MOXA_MUST_FCR_GDA_MODE_ENABLE), info->base + UART_FCR);
- else
- // above add by Victor Yu. 08-30-2002
- outb((UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), info->base + UART_FCR);
-
- /* read data port to reset things */
- (void) inb(info->base + UART_RX);
-
- if (info->tty)
- set_bit(TTY_IO_ERROR, &info->tty->flags);
-
- info->flags &= ~ASYNC_INITIALIZED;
-
- // following add by Victor Yu. 09-23-2002
- if (info->IsMoxaMustChipFlag) {
- SET_MOXA_MUST_NO_SOFTWARE_FLOW_CONTROL(info->base);
- }
- // above add by Victor Yu. 09-23-2002
-
- spin_unlock_irqrestore(&info->slock, flags);
-}
-
-/*
- * This routine is called to set the UART divisor registers to match
- * the specified baud rate for a serial port.
- */
-static int mxser_change_speed(struct mxser_struct *info, struct termios *old_termios)
-{
- unsigned cflag, cval, fcr;
- int ret = 0;
- unsigned char status;
- long baud;
- unsigned long flags;
-
-
- if (!info->tty || !info->tty->termios)
- return ret;
- cflag = info->tty->termios->c_cflag;
- if (!(info->base))
- return ret;
-
-
-#ifndef B921600
-#define B921600 (B460800 +1)
-#endif
- if (mxser_set_baud_method[info->port] == 0) {
- switch (cflag & (CBAUD | CBAUDEX)) {
- case B921600:
- baud = 921600;
- break;
- case B460800:
- baud = 460800;
- break;
- case B230400:
- baud = 230400;
- break;
- case B115200:
- baud = 115200;
- break;
- case B57600:
- baud = 57600;
- break;
- case B38400:
- baud = 38400;
- break;
- case B19200:
- baud = 19200;
- break;
- case B9600:
- baud = 9600;
- break;
- case B4800:
- baud = 4800;
- break;
- case B2400:
- baud = 2400;
- break;
- case B1800:
- baud = 1800;
- break;
- case B1200:
- baud = 1200;
- break;
- case B600:
- baud = 600;
- break;
- case B300:
- baud = 300;
- break;
- case B200:
- baud = 200;
- break;
- case B150:
- baud = 150;
- break;
- case B134:
- baud = 134;
- break;
- case B110:
- baud = 110;
- break;
- case B75:
- baud = 75;
- break;
- case B50:
- baud = 50;
- break;
- default:
- baud = 0;
- break;
- }
- mxser_set_baud(info, baud);
- }
-
- /* byte size and parity */
- switch (cflag & CSIZE) {
- case CS5:
- cval = 0x00;
- break;
- case CS6:
- cval = 0x01;
- break;
- case CS7:
- cval = 0x02;
- break;
- case CS8:
- cval = 0x03;
- break;
- default:
- cval = 0x00;
- break; /* too keep GCC shut... */
- }
- if (cflag & CSTOPB)
- cval |= 0x04;
- if (cflag & PARENB)
- cval |= UART_LCR_PARITY;
- if (!(cflag & PARODD)) {
- cval |= UART_LCR_EPAR;
- }
- if (cflag & CMSPAR)
- cval |= UART_LCR_SPAR;
-
- if ((info->type == PORT_8250) || (info->type == PORT_16450)) {
- if (info->IsMoxaMustChipFlag) {
- fcr = UART_FCR_ENABLE_FIFO;
- fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
- SET_MOXA_MUST_FIFO_VALUE(info);
- } else
- fcr = 0;
- } else {
- fcr = UART_FCR_ENABLE_FIFO;
- // following add by Victor Yu. 08-30-2002
- if (info->IsMoxaMustChipFlag) {
- fcr |= MOXA_MUST_FCR_GDA_MODE_ENABLE;
- SET_MOXA_MUST_FIFO_VALUE(info);
- } else {
- // above add by Victor Yu. 08-30-2002
-
- switch (info->rx_trigger) {
- case 1:
- fcr |= UART_FCR_TRIGGER_1;
- break;
- case 4:
- fcr |= UART_FCR_TRIGGER_4;
- break;
- case 8:
- fcr |= UART_FCR_TRIGGER_8;
- break;
- default:
- fcr |= UART_FCR_TRIGGER_14;
- break;
- }
- }
- }
-
- /* CTS flow control flag and modem status interrupts */
- info->IER &= ~UART_IER_MSI;
- info->MCR &= ~UART_MCR_AFE;
- if (cflag & CRTSCTS) {
- info->flags |= ASYNC_CTS_FLOW;
- info->IER |= UART_IER_MSI;
- if ((info->type == PORT_16550A) || (info->IsMoxaMustChipFlag)) {
- info->MCR |= UART_MCR_AFE;
- //status = mxser_get_msr(info->base, 0, info->port);
-/* save_flags(flags);
- cli();
- status = inb(baseaddr + UART_MSR);
- restore_flags(flags);*/
- //mxser_check_modem_status(info, status);
- } else {
- //status = mxser_get_msr(info->base, 0, info->port);
-
- //MX_LOCK(&info->slock);
- status = inb(info->base + UART_MSR);
- //MX_UNLOCK(&info->slock);
- if (info->tty->hw_stopped) {
- if (status & UART_MSR_CTS) {
- info->tty->hw_stopped = 0;
- if ((info->type != PORT_16550A) && (!info->IsMoxaMustChipFlag)) {
- info->IER |= UART_IER_THRI;
- outb(info->IER, info->base + UART_IER);
- }
- set_bit(MXSER_EVENT_TXLOW, &info->event);
- schedule_work(&info->tqueue); }
- } else {
- if (!(status & UART_MSR_CTS)) {
- info->tty->hw_stopped = 1;
- if ((info->type != PORT_16550A) && (!info->IsMoxaMustChipFlag)) {
- info->IER &= ~UART_IER_THRI;
- outb(info->IER, info->base + UART_IER);
- }
- }
- }
- }
- } else {
- info->flags &= ~ASYNC_CTS_FLOW;
- }
- outb(info->MCR, info->base + UART_MCR);
- if (cflag & CLOCAL) {
- info->flags &= ~ASYNC_CHECK_CD;
- } else {
- info->flags |= ASYNC_CHECK_CD;
- info->IER |= UART_IER_MSI;
- }
- outb(info->IER, info->base + UART_IER);
-
- /*
- * Set up parity check flag
- */
- info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;
- if (I_INPCK(info->tty))
- info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;
- if (I_BRKINT(info->tty) || I_PARMRK(info->tty))
- info->read_status_mask |= UART_LSR_BI;
-
- info->ignore_status_mask = 0;
-
- if (I_IGNBRK(info->tty)) {
- info->ignore_status_mask |= UART_LSR_BI;
- info->read_status_mask |= UART_LSR_BI;
- /*
- * If we're ignore parity and break indicators, ignore
- * overruns too. (For real raw support).
- */
- if (I_IGNPAR(info->tty)) {
- info->ignore_status_mask |= UART_LSR_OE | UART_LSR_PE | UART_LSR_FE;
- info->read_status_mask |= UART_LSR_OE | UART_LSR_PE | UART_LSR_FE;
- }
- }
- // following add by Victor Yu. 09-02-2002
- if (info->IsMoxaMustChipFlag) {
- spin_lock_irqsave(&info->slock, flags);
- SET_MOXA_MUST_XON1_VALUE(info->base, START_CHAR(info->tty));
- SET_MOXA_MUST_XOFF1_VALUE(info->base, STOP_CHAR(info->tty));
- if (I_IXON(info->tty)) {
- ENABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->base);
- } else {
- DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->base);
- }
- if (I_IXOFF(info->tty)) {
- ENABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->base);
- } else {
- DISABLE_MOXA_MUST_TX_SOFTWARE_FLOW_CONTROL(info->base);
- }
- /*
- if ( I_IXANY(info->tty) ) {
- info->MCR |= MOXA_MUST_MCR_XON_ANY;
- ENABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(info->base);
- } else {
- info->MCR &= ~MOXA_MUST_MCR_XON_ANY;
- DISABLE_MOXA_MUST_XON_ANY_FLOW_CONTROL(info->base);
- }
- */
- spin_unlock_irqrestore(&info->slock, flags);
- }
- // above add by Victor Yu. 09-02-2002
-
-
- outb(fcr, info->base + UART_FCR); /* set fcr */
- outb(cval, info->base + UART_LCR);
-
- return ret;
-}
-
-
-static int mxser_set_baud(struct mxser_struct *info, long newspd)
-{
- int quot = 0;
- unsigned char cval;
- int ret = 0;
- unsigned long flags;
-
- if (!info->tty || !info->tty->termios)
- return ret;
-
- if (!(info->base))
- return ret;
-
- if (newspd > info->MaxCanSetBaudRate)
- return 0;
-
- info->realbaud = newspd;
- if (newspd == 134) {
- quot = (2 * info->baud_base / 269);
- } else if (newspd) {
- quot = info->baud_base / newspd;
-
- if (quot == 0)
- quot = 1;
-
- } else {
- quot = 0;
- }
-
- info->timeout = ((info->xmit_fifo_size * HZ * 10 * quot) / info->baud_base);
- info->timeout += HZ / 50; /* Add .02 seconds of slop */
-
- if (quot) {
- spin_lock_irqsave(&info->slock, flags);
- info->MCR |= UART_MCR_DTR;
- outb(info->MCR, info->base + UART_MCR);
- spin_unlock_irqrestore(&info->slock, flags);
- } else {
- spin_lock_irqsave(&info->slock, flags);
- info->MCR &= ~UART_MCR_DTR;
- outb(info->MCR, info->base + UART_MCR);
- spin_unlock_irqrestore(&info->slock, flags);
- return ret;
- }
-
- cval = inb(info->base + UART_LCR);
-
- outb(cval | UART_LCR_DLAB, info->base + UART_LCR); /* set DLAB */
-
- outb(quot & 0xff, info->base + UART_DLL); /* LS of divisor */
- outb(quot >> 8, info->base + UART_DLM); /* MS of divisor */
- outb(cval, info->base + UART_LCR); /* reset DLAB */
-
-
- return ret;
-}
-
-
-
-/*
- * ------------------------------------------------------------
- * friends of mxser_ioctl()
- * ------------------------------------------------------------
- */
-static int mxser_get_serial_info(struct mxser_struct *info, struct serial_struct __user *retinfo)
-{
- struct serial_struct tmp;
-
- if (!retinfo)
- return (-EFAULT);
- memset(&tmp, 0, sizeof(tmp));
- tmp.type = info->type;
- tmp.line = info->port;
- tmp.port = info->base;
- tmp.irq = info->irq;
- tmp.flags = info->flags;
- tmp.baud_base = info->baud_base;
- tmp.close_delay = info->close_delay;
- tmp.closing_wait = info->closing_wait;
- tmp.custom_divisor = info->custom_divisor;
- tmp.hub6 = 0;
- if (copy_to_user(retinfo, &tmp, sizeof(*retinfo)))
- return -EFAULT;
- return (0);
-}
-
-static int mxser_set_serial_info(struct mxser_struct *info, struct serial_struct __user *new_info)
-{
- struct serial_struct new_serial;
- unsigned int flags;
- int retval = 0;
-
- if (!new_info || !info->base)
- return (-EFAULT);
- if (copy_from_user(&new_serial, new_info, sizeof(new_serial)))
- return -EFAULT;
-
- if ((new_serial.irq != info->irq) || (new_serial.port != info->base) || (new_serial.custom_divisor != info->custom_divisor) || (new_serial.baud_base != info->baud_base))
- return (-EPERM);
-
- flags = info->flags & ASYNC_SPD_MASK;
-
- if (!capable(CAP_SYS_ADMIN)) {
- if ((new_serial.baud_base != info->baud_base) || (new_serial.close_delay != info->close_delay) || ((new_serial.flags & ~ASYNC_USR_MASK) != (info->flags & ~ASYNC_USR_MASK)))
- return (-EPERM);
- info->flags = ((info->flags & ~ASYNC_USR_MASK) | (new_serial.flags & ASYNC_USR_MASK));
- } else {
- /*
- * OK, past this point, all the error checking has been done.
- * At this point, we start making changes.....
- */
- info->flags = ((info->flags & ~ASYNC_FLAGS) | (new_serial.flags & ASYNC_FLAGS));
- info->close_delay = new_serial.close_delay * HZ / 100;
- info->closing_wait = new_serial.closing_wait * HZ / 100;
- info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
- info->tty->low_latency = 0; //(info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
- }
-
- /* added by casper, 3/17/2000, for mouse */
- info->type = new_serial.type;
-
- process_txrx_fifo(info);
-
- /* */
- if (info->flags & ASYNC_INITIALIZED) {
- if (flags != (info->flags & ASYNC_SPD_MASK)) {
- mxser_change_speed(info, NULL);
- }
- } else {
- retval = mxser_startup(info);
- }
- return (retval);
-}
-
-/*
- * mxser_get_lsr_info - get line status register info
- *
- * Purpose: Let user call ioctl() to get info when the UART physically
- * is emptied. On bus types like RS485, the transmitter must
- * release the bus after transmitting. This must be done when
- * the transmit shift register is empty, not be done when the
- * transmit holding register is empty. This functionality
- * allows an RS485 driver to be written in user space.
- */
-static int mxser_get_lsr_info(struct mxser_struct *info, unsigned int __user *value)
-{
- unsigned char status;
- unsigned int result;
- unsigned long flags;
-
- spin_lock_irqsave(&info->slock, flags);
- status = inb(info->base + UART_LSR);
- spin_unlock_irqrestore(&info->slock, flags);
- result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
- return put_user(result, value);
-}