📄 mxpcdrv.c
字号:
cnow = info->icount; /* atomic copy */ MX_UNLOCK(&info->slock); if ( cnow.rng == cprev.rng && cnow.dsr == cprev.dsr && cnow.dcd == cprev.dcd && cnow.cts == cprev.cts ) return(-EIO); /* no change => error */ 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)) ) { return(0); } cprev = cnow; } /* 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 = MX_ACCESS_CHK(VERIFY_WRITE, (void *)arg, sizeof(struct serial_icounter_struct)); if ( MX_ERR(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 = MX_ACCESS_CHK(VERIFY_WRITE, (void *)arg, sizeof(int)); if ( MX_ERR(error) ) return(error); put_to_user(info->baud_base != 115200 ? 1 : 0, (int *)arg); return(0); case MOXA_SET_SPECIAL_BAUD_RATE: error = MX_ACCESS_CHK(VERIFY_READ, (void *)arg, sizeof(int)); if ( MX_ERR(error) ) return(error); MX_LOCK(&info->slock); mxpcdrv_set_special_baudrate(info, (int)arg); MX_UNLOCK(&info->slock); return(0); case MOXA_GET_SPECIAL_BAUD_RATE: error = MX_ACCESS_CHK(VERIFY_WRITE, (void *)arg, sizeof(int)); if ( MX_ERR(error) ) return(error); put_to_user(info->cur_baud, (int *)arg); return(0); default: return(-ENOIOCTLCMD); } return(0);}static int mxpcdrv_ioctl_special(unsigned int cmd, unsigned long arg){ int error, i, result, status; switch ( cmd ) { case MOXA_GET_CONF: error = MX_ACCESS_CHK(VERIFY_WRITE, (void *)arg, sizeof(struct mxpcdrv_hwconf)*4); if ( MX_ERR(error) ) return(error); if (copy_to_user((struct mxpcdrv_hwconf *)arg, mxpcdrvcfg, sizeof(struct mxpcdrv_hwconf)*4)) return -EFAULT; return 0; case MOXA_GET_MAJOR: error = MX_ACCESS_CHK(VERIFY_WRITE, (void *)arg, sizeof(int)); if ( MX_ERR(error) ) return(error); if (copy_to_user((int*)arg, &ttymajor, sizeof(int))) return -EFAULT; return 0; case MOXA_GET_CUMAJOR: error = MX_ACCESS_CHK(VERIFY_WRITE, (void *)arg, sizeof(int)); if ( MX_ERR(error) ) return(error); if (copy_to_user((int*)arg, &calloutmajor, sizeof(int))) return -EFAULT; return 0; case MOXA_CHKPORTENABLE: error = MX_ACCESS_CHK(VERIFY_WRITE, (void *)arg, sizeof(long)); if ( MX_ERR(error) ) return(error); result = 0; for ( i=0; i<MXPCDRV_PORTS; i++ ) { if ( mxvar_table[i].base ) result |= (1 << i); } put_to_user(result, (unsigned long *)arg); return(0); case MOXA_GETDATACOUNT: error = MX_ACCESS_CHK(VERIFY_WRITE, (void *)arg, sizeof(struct mxpcdrv_log)); if ( MX_ERR(error) ) return(error); if (copy_to_user((struct mxpcdrv_log *)arg, &mxvar_log, sizeof(mxvar_log))) return -EFAULT; return(0); case MOXA_GETMSTATUS: error = MX_ACCESS_CHK(VERIFY_WRITE, (void *)arg, sizeof(struct mxpcdrv_mstatus) * MXPCDRV_PORTS); if ( MX_ERR(error) ) return(error); for(i=0; i<MXPCDRV_PORTS; i++){ GMStatus[i].ri = 0; if ( !mxvar_table[i].base ){ GMStatus[i].dcd = 0; GMStatus[i].dsr = 0; GMStatus[i].cts = 0; continue; } if ( !mxvar_table[i].tty || !mxvar_table[i].tty->termios ) GMStatus[i].cflag=mxvar_table[i].normal_termios.c_cflag; else GMStatus[i].cflag = mxvar_table[i].tty->termios->c_cflag; status = inb(mxvar_table[i].base + UART_MSR); if(status & 0x80/*UART_MSR_DCD*/) GMStatus[i].dcd = 1; else GMStatus[i].dcd = 0; if(status & 0x20/*UART_MSR_DSR*/) GMStatus[i].dsr = 1; else GMStatus[i].dsr = 0; if(status & 0x10/*UART_MSR_CTS*/) GMStatus[i].cts = 1; else GMStatus[i].cts = 0; } if (copy_to_user((struct mxpcdrv_mstatus *)arg, GMStatus, sizeof(struct mxpcdrv_mstatus) * MXPCDRV_PORTS)) return -EFAULT; return 0; default: return(-ENOIOCTLCMD); } return(0);}static void mxpcdrv_stoprx(struct tty_struct * tty){ struct mxpcdrv_struct *info = (struct mxpcdrv_struct *)tty->driver_data; MX_LOCK_INIT(); info->ldisc_stop_rx = 1; if ( I_IXOFF(tty) ) { MX_LOCK(&info->slock); // following add by Victor Yu. 09-02-2002 if ( info->IsMoxaMustChipFlag ) { info->IER &= ~MOXA_MUST_RECV_ISR; outb(info->IER, info->base+UART_IER); } else { // above add by Victor Yu. 09-02-2002 if(!(info->flags & ASYNC_CLOSING)){ info->x_char = STOP_CHAR(tty); // outb(info->IER, 0); // mask by Victor Yu. 09-02-2002 outb(0, info->base+UART_IER); info->IER |= UART_IER_THRI; outb(info->IER, info->base + UART_IER); /* force Tx interrupt */ } } // add by Victor Yu. 09-02-2002 MX_UNLOCK(&info->slock); } if ( info->tty->termios->c_cflag & CRTSCTS ) { MX_LOCK(&info->slock); info->MCR &= ~UART_MCR_RTS; outb(info->MCR, info->base + UART_MCR); MX_UNLOCK(&info->slock); }}static void mxpcdrv_startrx(struct tty_struct * tty){ struct mxpcdrv_struct *info = (struct mxpcdrv_struct *)tty->driver_data; MX_LOCK_INIT(); info->ldisc_stop_rx = 0; if ( I_IXOFF(tty) ) { if ( info->x_char ) info->x_char = 0; else { MX_LOCK(&info->slock); // following add by Victor Yu. 09-02-2002 if ( info->IsMoxaMustChipFlag ) { info->IER |= MOXA_MUST_RECV_ISR; outb(info->IER, info->base+UART_IER); } else { // above add by Victor Yu. 09-02-2002 if(!(info->flags & ASYNC_CLOSING)){ info->x_char = START_CHAR(tty); // outb(info->IER, 0); // mask by Victor Yu. 09-02-2002 outb(0, info->base+UART_IER); // add by Victor Yu. 09-02-2002 info->IER |= UART_IER_THRI; /* force Tx interrupt */ outb(info->IER, info->base + UART_IER); } } // add by Victor Yu. 09-02-2002 MX_UNLOCK(&info->slock); } } if ( info->tty->termios->c_cflag & CRTSCTS ) { MX_LOCK(&info->slock); info->MCR |= UART_MCR_RTS; outb(info->MCR, info->base + UART_MCR); MX_UNLOCK(&info->slock); }}/* * This routine is called by the upper-layer tty layer to signal that * incoming characters should be throttled. */static void mxpcdrv_throttle(struct tty_struct * tty){ mxpcdrv_stoprx(tty);}static void mxpcdrv_unthrottle(struct tty_struct * tty){ mxpcdrv_startrx(tty);}#if (LINUX_VERSION_CODE > VERSION_CODE(2,6,19))static void mxpcdrv_set_termios(struct tty_struct * tty, struct ktermios * old_termios)#elsestatic void mxpcdrv_set_termios(struct tty_struct * tty, struct termios * old_termios)#endif{ struct mxpcdrv_struct *info = (struct mxpcdrv_struct *)tty->driver_data; MX_LOCK_INIT(); if ( (tty->termios->c_cflag != old_termios->c_cflag) || (RELEVANT_IFLAG(tty->termios->c_iflag) != RELEVANT_IFLAG(old_termios->c_iflag)) ) { mxpcdrv_change_speed(info, old_termios); if ( (old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS) ) { tty->hw_stopped = 0; mxpcdrv_start(tty); } } /* Handle sw stopped */ if ( (old_termios->c_iflag & IXON) && !(tty->termios->c_iflag & IXON) ) { tty->stopped = 0; // following add by Victor Yu. 09-02-2002 if ( info->IsMoxaMustChipFlag ) { MX_LOCK(&info->slock); DISABLE_MOXA_MUST_RX_SOFTWARE_FLOW_CONTROL(info->base); MX_UNLOCK(&info->slock); } // above add by Victor Yu. 09-02-2002 mxpcdrv_start(tty); }}/* * mxpcdrv_stop() and mxpcdrv_start() * * This routines are called before setting or resetting tty->stopped. * They enable or disable transmitter interrupts, as necessary. */static void mxpcdrv_stop(struct tty_struct * tty){ struct mxpcdrv_struct *info = (struct mxpcdrv_struct *)tty->driver_data; MX_LOCK_INIT(); MX_LOCK(&info->slock); if ( info->IER & UART_IER_THRI ) { info->IER &= ~UART_IER_THRI; outb(info->IER, info->base + UART_IER); } MX_UNLOCK(&info->slock);}static void mxpcdrv_start(struct tty_struct * tty){ struct mxpcdrv_struct *info = (struct mxpcdrv_struct *)tty->driver_data; MX_LOCK_INIT(); MX_LOCK(&info->slock); if ( info->xmit_cnt && info->xmit_buf/* && !(info->IER & UART_IER_THRI)*/ ) { info->IER &= ~UART_IER_THRI ; outb(info->IER, info->base + UART_IER); info->IER |= UART_IER_THRI; outb(info->IER, info->base + UART_IER); } MX_UNLOCK(&info->slock);}#if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0))/* * mxpcdrv_wait_until_sent() --- wait until the transmitter is empty */static void mxpcdrv_wait_until_sent(struct tty_struct *tty, int timeout){ struct mxpcdrv_struct * info = (struct mxpcdrv_struct *)tty->driver_data; unsigned long orig_jiffies, char_time; int lsr; if (info->type == PORT_UNKNOWN) return; if (info->xmit_fifo_size == 0) return; /* Just in case.... */ orig_jiffies = jiffies; /* * Set the check interval to be 1/5 of the estimated time to * send a single character, and make it at least 1. The check * interval should also be less than the timeout. * * Note: we have to use pretty tight timings here to satisfy * the NIST-PCTS. */ char_time = (info->timeout - HZ/50) / info->xmit_fifo_size; char_time = char_time / 5; if (char_time == 0) char_time = 1; if (timeout && timeout < char_time) char_time = timeout; /* * If the transmitter hasn't cleared in twice the approximate * amount of time to send the entire FIFO, it probably won't * ever clear. This assumes the UART isn't doing flow * control, which is currently the case. Hence, if it ever * takes longer than info->timeout, this is probably due to a * UART bug of some kind. So, we clamp the timeout parameter at * 2*info->timeout. */ if (!timeout || timeout > 2*info->timeout) timeout = 2*info->timeout;#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT printk("In rs_wait_until_sent(%d) check=%lu...", timeout, char_time); printk("jiff=%lu...", jiffies);#endif while (!((lsr = inb(info->base+ UART_LSR)) & UART_LSR_TEMT)) {#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT printk("lsr = %d (jiff=%lu)...", lsr, jiffies);#endif#if (LINUX_VERSION_CODE >= VERSION_CODE(2,3,0)) set_current_state(TASK_INTERRUPTIBLE);#else current->state = TASK_INTERRUPTIBLE;#endif schedule_timeout(char_time); if (signal_pending(current)) break; if (timeout && time_after(jiffies, orig_jiffies + timeout)) break; }#if (LINUX_VERSION_CODE >= VERSION_CODE(2,3,0)) set_current_state(TASK_RUNNING);#else current->state = TASK_RUNNING;#endif#ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);#endif}#endif/* * This routine is called by tty_hangup() when a hangup is signaled. */void mxpcdrv_hangup(struct tty_struct * tty){ struct mxpcdrv_struct * info = (struct mxpcdrv_struct *)tty->driver_data; mxpcdrv_flush_buffer(tty); mxpcdrv_shutdown(info); info->event = 0; info->count = 0; info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); info->tty = 0; wake_up_interruptible(&info->open_wait);}/* * This is the serial driver's generic interrupt routine */#if (LINUX_VERSION_CODE > VERSION_CODE(2,6,19))static irqreturn_t mxpcdrv_interrupt(int irq, void *dev_id)#elsestatic IRQ_RET mxpcdrv_interrupt(int irq, void *dev_id, struct pt_regs * regs)#endif{ int status, iir, i; struct mxpcdrv_struct * info; struct mxpcdrv_struct * port; int max, irqbits, bits, msr; int pass_counter = 0; int handled = 0; port = 0; for(i=0; i<MXPCDRV_BOARDS; i++){ if(dev_id == &(mxvar_table[i*MXPCDRV_PORTS_PER_BOARD])){ port = dev_id; break; } } if(i==MXPCDRV_BOARDS) goto irq_stop; if(port==0) goto irq_stop; max = mxpcdrv_numports[mxpcdrvcfg[i].board_type-1];
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -