📄 mxser.c
字号:
if ( PORTNO(tty) == MXSER_PORTS ) return; if ( !info ) return; MX_LOCK(&info->slock); if ( tty_hung_up_p(filp) ) { MX_UNLOCK(&info->slock); MX_MOD_DEC; return; }#ifndef SP1 if ( (tty->count == 1) && (info->count != 1) ) {#else#if (LINUX_VERSION_CODE < VERSION_CODE(2,4,21)) if ( (tty->count == 1) && (info->count != 1) ) {#else if ((atomic_read(&tty->count) == 1) && (info->count != 1)) {#endif#endif /* * Uh, oh. tty->count is 1, which means that the tty * structure will be freed. Info->count should always * be one in these conditions. If it's greater than * one, we've got real problems, since it means the * serial port won't be shutdown. */ printk("mxser_close: bad serial port count; tty->count is 1, " "info->count is %d\n", info->count); info->count = 1; } if ( --info->count < 0 ) { printk("mxser_close: bad serial port count for ttys%d: %d\n", info->port, info->count); info->count = 0; } if ( info->count ) { MX_UNLOCK(&info->slock); MX_MOD_DEC; return; } info->flags |= ASYNC_CLOSING; MX_UNLOCK(&info->slock); /* * Save the termios structure, since this port may have * separate termios for callout and dialin. */ if ( info->flags & ASYNC_NORMAL_ACTIVE ) info->normal_termios = *tty->termios; if ( info->flags & ASYNC_CALLOUT_ACTIVE ) info->callout_termios = *tty->termios; /* * Now we wait for the transmit buffer to clear; and we notify * the line discipline to only process XON/XOFF characters. */ tty->closing = 1; if ( info->closing_wait != ASYNC_CLOSING_WAIT_NONE ) tty_wait_until_sent(tty, info->closing_wait); /* * At this point we stop accepting input. To do this, we * disable the receive line status interrupts, and tell the * interrupt driver to stop checking the data ready bit in the * line status register. */ info->IER &= ~UART_IER_RLSI; if ( info->IsMoxaMustChipFlag ) info->IER &= ~MOXA_MUST_RECV_ISR;/* by William info->read_status_mask &= ~UART_LSR_DR;*/ if ( info->flags & ASYNC_INITIALIZED ) { outb(info->IER, info->base + UART_IER); /* * Before we drop DTR, make sure the UART transmitter * has completely drained; this is especially * important if there is a transmit FIFO! */ timeout = jiffies + HZ; while ( !(inb(info->base + UART_LSR) & UART_LSR_TEMT) ) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(5); if ( time_after(jiffies, timeout) ) break; } } mxser_shutdown(info); if ( MX_TTY_DRV(flush_buffer) ) MX_TTY_DRV(flush_buffer)(tty); if ( tty->ldisc.flush_buffer ) tty->ldisc.flush_buffer(tty); tty->closing = 0; info->event = 0; info->tty = 0; if ( info->blocked_open ) { if ( info->close_delay ) { set_current_state(TASK_INTERRUPTIBLE); schedule_timeout(info->close_delay); } wake_up_interruptible(&info->open_wait); } info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE | ASYNC_CLOSING); wake_up_interruptible(&info->close_wait); MX_MOD_DEC;}static int mxser_write(struct tty_struct * tty, int from_user, const unsigned char * buf, int count){ int c, total = 0; struct mxser_struct *info = (struct mxser_struct *)tty->driver_data; MX_LOCK_INIT(); if ( !tty || !info->xmit_buf || !mxvar_tmp_buf ) return(0); if ( from_user ) down(&mxvar_tmp_buf_sem); while ( 1 ) { c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); if ( c <= 0 ) break; if ( from_user ) { /* copy_from_user(mxvar_tmp_buf, buf, c); c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, SERIAL_XMIT_SIZE - info->xmit_head)); memcpy(info->xmit_buf + info->xmit_head, mxvar_tmp_buf, c); */ if(copy_from_user(info->xmit_buf+info->xmit_head, buf, c)==c){ total = -EFAULT; break; } } else memcpy(info->xmit_buf + info->xmit_head, buf, c); MX_LOCK(&info->slock); info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE - 1); info->xmit_cnt += c; MX_UNLOCK(&info->slock); buf += c; count -= c; total += c; } if ( from_user ) up(&mxvar_tmp_buf_sem); if ( info->xmit_cnt && !tty->stopped && !(info->IER & UART_IER_THRI) ) { if (!tty->hw_stopped || (info->type == PORT_16550A) || (info->IsMoxaMustChipFlag)) { MX_LOCK(&info->slock); info->IER |= UART_IER_THRI; outb(info->IER, info->base + UART_IER); MX_UNLOCK(&info->slock); } } return total;}static void mxser_put_char(struct tty_struct * tty, unsigned char ch){ struct mxser_struct *info = (struct mxser_struct *)tty->driver_data; MX_LOCK_INIT(); if ( !tty || !info->xmit_buf ) return; if ( info->xmit_cnt >= SERIAL_XMIT_SIZE - 1 ) { return; } MX_LOCK(&info->slock); info->xmit_buf[info->xmit_head++] = ch; info->xmit_head &= SERIAL_XMIT_SIZE - 1; info->xmit_cnt++; MX_UNLOCK(&info->slock); if ( !tty->stopped && !(info->IER & UART_IER_THRI) ) { if (!tty->hw_stopped || (info->type == PORT_16550A) || info->IsMoxaMustChipFlag) { MX_LOCK(&info->slock); info->IER |= UART_IER_THRI; outb(info->IER, info->base + UART_IER); MX_UNLOCK(&info->slock); } }}static void mxser_flush_chars(struct tty_struct * tty){ struct mxser_struct *info = (struct mxser_struct *)tty->driver_data; MX_LOCK_INIT(); if ( info->xmit_cnt <= 0 || tty->stopped || !info->xmit_buf || (tty->hw_stopped && (info->type!=PORT_16550A) && (!info->IsMoxaMustChipFlag))) return; MX_LOCK(&info->slock); info->IER |= UART_IER_THRI; outb(info->IER, info->base + UART_IER); MX_UNLOCK(&info->slock); }static int mxser_write_room(struct tty_struct * tty){ struct mxser_struct *info = (struct mxser_struct *)tty->driver_data; int ret; ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; if ( ret < 0 ) ret = 0; return(ret);}static int mxser_chars_in_buffer(struct tty_struct * tty){ struct mxser_struct *info = (struct mxser_struct *)tty->driver_data; return(info->xmit_cnt);}static void mxser_flush_buffer(struct tty_struct * tty){ struct mxser_struct *info = (struct mxser_struct *)tty->driver_data; char fcr; MX_LOCK_INIT(); MX_LOCK(&info->slock); info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; MX_UNLOCK(&info->slock); /* below added by shinhay */ //outb(0x05, info->base+UART_FCR); fcr = inb(info->base + UART_FCR); outb((fcr | UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT), info->base + UART_FCR); outb(fcr, info->base+UART_FCR);/* above added by shinhay */ wake_up_interruptible(&tty->write_wait); if ( (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && tty->ldisc.write_wakeup ) (tty->ldisc.write_wakeup)(tty);}static int mxser_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg){ int error; struct mxser_struct * info = (struct mxser_struct *)tty->driver_data; int retval; struct async_icount cprev, cnow; /* kernel counter temps */ struct serial_icounter_struct *p_cuser; /* user space */ unsigned long templ; MX_LOCK_INIT(); if ( PORTNO(tty) == MXSER_PORTS ) return(mxser_ioctl_special(cmd, arg)); // following add by Victor Yu. 01-05-2004 if ( cmd == MOXA_SET_OP_MODE || cmd == MOXA_GET_OP_MODE ) { int opmode, p; static unsigned char ModeMask[]={0xfc, 0xf3, 0xcf, 0x3f}; int shiftbit; unsigned char val, mask; p = info->port % 4; if ( cmd == MOXA_SET_OP_MODE ) { error = verify_area(VERIFY_READ, (void *)arg, sizeof(int)); if ( error ) return(error); get_from_user(opmode,(int *)arg); if ( opmode != RS232_MODE && opmode != RS485_2WIRE_MODE && opmode != RS422_MODE && opmode != RS485_4WIRE_MODE ) return -EFAULT; mask = ModeMask[p]; shiftbit = p * 2; val = inb(info->opmode_ioaddr); val &= mask; val |= (opmode << shiftbit); outb(val, info->opmode_ioaddr); } else { error = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int)); if ( error ) return(error); shiftbit = p * 2; opmode = inb(info->opmode_ioaddr) >> shiftbit; opmode &= OP_MODE_MASK; if(copy_to_user((int*)arg, &opmode, sizeof(int))) return -EFAULT; } return 0; } // above add by Victor Yu. 01-05-2004 if ( (cmd != TIOCGSERIAL) && (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT) ) { if ( tty->flags & (1 << TTY_IO_ERROR) ) return(-EIO); } switch ( cmd ) { case TCSBRK: /* SVID version: non-zero arg --> no break */ retval = tty_check_change(tty); if ( retval ) return(retval); tty_wait_until_sent(tty, 0); if ( !arg ) mxser_send_break(info, HZ/4); /* 1/4 second */ return(0); case TCSBRKP: /* support for POSIX tcsendbreak() */ retval = tty_check_change(tty); if ( retval ) return(retval); tty_wait_until_sent(tty, 0); mxser_send_break(info, arg ? arg*(HZ/10) : HZ/4); return(0); case TIOCGSOFTCAR: error = verify_area(VERIFY_WRITE, (void *)arg, sizeof(long)); if ( error ) return(error); put_to_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg); return 0; case TIOCSSOFTCAR: error = verify_area(VERIFY_READ, (void *)arg, sizeof(long)); if ( error ) return(error); get_from_user(templ,(unsigned long *)arg); arg = templ; tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); return(0);#if (LINUX_VERSION_CODE < VERSION_CODE(2,6,0)) case TIOCMGET: error = verify_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned int)); if ( error ) return(error); return(mxser_get_modem_info(info, (unsigned int *)arg)); case TIOCMBIS: case TIOCMBIC: case TIOCMSET: return(mxser_set_modem_info(info, cmd, (unsigned int *)arg));#endif case TIOCGSERIAL: error = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct serial_struct)); if ( error ) return(error); return(mxser_get_serial_info(info, (struct serial_struct *)arg)); case TIOCSSERIAL: error = verify_area(VERIFY_READ, (void *)arg, sizeof(struct serial_struct)); if ( error ) return(error); return(mxser_set_serial_info(info, (struct serial_struct *)arg)); case TIOCSERGETLSR: /* Get line status register */ error = verify_area(VERIFY_WRITE, (void *)arg, sizeof(unsigned int)); if ( error ) return(error); else return(mxser_get_lsr_info(info, (unsigned int *)arg)); /* * Wait for any of the 4 modem inputs (DCD,RI,DSR,CTS) to change * - mask passed in arg for lines of interest * (use |'ed TIOCM_RNG/DSR/CD/CTS for masking) * Caller should use TIOCGICOUNT to see which one it was */ case TIOCMIWAIT:{ DECLARE_WAITQUEUE(wait, current); int ret; MX_LOCK(&info->slock); cprev = info->icount; /* note the counters on entry */ MX_UNLOCK(&info->slock); add_wait_queue(&info->delta_msr_wait, &wait); while ( 1 ) { MX_LOCK(&info->slock); cnow = info->icount; /* atomic copy */ MX_UNLOCK(&info->slock); set_current_state(TASK_INTERRUPTIBLE); if ( ((arg & TIOCM_RNG) && (cnow.rng != cprev.rng)) || ((arg & TIOCM_DSR) && (cnow.dsr != cprev.dsr)) || ((arg & TIOCM_CD) && (cnow.dcd != cprev.dcd)) || ((arg & TIOCM_CTS) && (cnow.cts != cprev.cts)) ) { ret = 0; break; } /* see if a signal did it */ if ( signal_pending(current) ){ ret = -ERESTARTSYS; break; } cprev = cnow; } current->state = TASK_RUNNING; remove_wait_queue(&info->delta_msr_wait, &wait); break; } /* NOTREACHED */ /* * Get counter of input serial line interrupts (DCD,RI,DSR,CTS) * Return: write counters to the user passed counter struct * NB: both 1->0 and 0->1 transitions are counted except for * RI where only 0->1 is counted. */ case TIOCGICOUNT: error = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct serial_icounter_struct)); if ( error ) return(error); MX_LOCK(&info->slock); cnow = info->icount; MX_UNLOCK(&info->slock); p_cuser = (struct serial_icounter_struct *)arg;/* modified by casper 1/11/2000 */#if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0)) if (put_user(cnow.frame, &p_cuser->frame)) return -EFAULT; if (put_user(cnow.brk, &p_cuser->brk)) return -EFAULT; if (put_user(cnow.overrun, &p_cuser->overrun)) return -EFAULT; if (put_user(cnow.buf_overrun, &p_cuser->buf_overrun)) return -EFAULT; if (put_user(cnow.parity, &p_cuser->parity)) return -EFAULT; if (put_user(cnow.rx, &p_cuser->rx)) return -EFAULT; if (put_user(cnow.tx, &p_cuser->tx)) return -EFAULT;#endif put_to_user(cnow.cts, &p_cuser->cts); put_to_user(cnow.dsr, &p_cuser->dsr); put_to_user(cnow.rng, &p_cuser->rng); put_to_user(cnow.dcd, &p_cuser->dcd);/* */ return(0); case MOXA_HighSpeedOn: error = verify_area(VERIFY_WRITE, (void *)arg, sizeof(int)); if ( error ) return(error); put_to_user(info->baud_base != 115200 ? 1 : 0, (int *)arg); return(0); case MOXA_SDS_RSTICOUNTER: {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -