⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mxser.c

📁 MOXA 串口驱动编程
💻 C
📖 第 1 页 / 共 5 页
字号:
	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 + -