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

📄 mxpcdrv.c

📁 isa总线设备
💻 C
📖 第 1 页 / 共 5 页
字号:
		MX_MOD_INC;	if ( (line < 0) || (line > MXPCDRV_PORTS) )	    return(-ENODEV);	info = mxvar_table + line;	if ( !info->base )	    return(-ENODEV);	tty->driver_data = info;	info->tty = tty;	if ( !mxvar_tmp_buf ) {	    page = GET_FPAGE(GFP_KERNEL);	    if ( !page )		return(-ENOMEM);	    if ( mxvar_tmp_buf )		free_page(page);	    else		mxvar_tmp_buf = (unsigned char *)page;	}	/*	 * Start up serial port	 */	info->count++;	retval = mxpcdrv_startup(info);	if ( retval )	    return(retval);	retval = mxpcdrv_block_til_ready(tty, filp, info);	if ( retval )	    return(retval);	if ( (info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS) ) {	    if ( MX_TTY_DRV(subtype) == SERIAL_TYPE_NORMAL )		*tty->termios = info->normal_termios;	    else		*tty->termios = info->callout_termios;	    mxpcdrv_change_speed(info, 0);	}	info->session = MX_SESSION();	info->pgrp = MX_CGRP();#ifdef TTY_DONT_FLIP	clear_bit(TTY_DONT_FLIP, &tty->flags);#endif/* unmark here for very high baud rate (ex. 921600 bps) used*/#if (LINUX_VERSION_CODE >= VERSION_CODE(2,1,0))	tty->low_latency = 1;#endif	return(0);}/* * This routine is called when the serial port gets closed.  First, we * wait for the last remaining data to be sent.  Then, we unlink its * async structure from the interrupt chain if necessary, and we free * that IRQ if nothing is left in the chain. */static void mxpcdrv_close(struct tty_struct * tty, struct file * filp){	struct mxpcdrv_struct * info = (struct mxpcdrv_struct *)tty->driver_data;#if (LINUX_VERSION_CODE > VERSION_CODE(2,6,9))	struct tty_ldisc *ld;#endif	unsigned long	timeout;	MX_LOCK_INIT();	if ( PORTNO(tty) == MXPCDRV_PORTS )	    return;	if ( !info ){			MX_MOD_DEC;	    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("mxpcdrv_close: bad serial port count; tty->count is 1, "		   "info->count is %d\n", info->count);	    info->count = 1;	}	if ( --info->count < 0 ) {	    printk("mxpcdrv_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);	// add by Victor Yu. 09-26-2002	/*	 * 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) ) {#if (LINUX_VERSION_CODE >= VERSION_CODE(2,3,0))				set_current_state(TASK_INTERRUPTIBLE);#else				current->state = TASK_INTERRUPTIBLE;#endif		schedule_timeout(5);		if ( time_after(jiffies, timeout) )		    break;	    }	}	mxpcdrv_shutdown(info);	// 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	if ( MX_TTY_DRV(flush_buffer) )	    MX_TTY_DRV(flush_buffer)(tty);	    #if (LINUX_VERSION_CODE < VERSION_CODE(2,6,10))	if ( tty->ldisc.flush_buffer )	    tty->ldisc.flush_buffer(tty);#else    	ld = tty_ldisc_ref(tty);	if (ld) {		if(ld->flush_buffer)			ld->flush_buffer(tty);		tty_ldisc_deref(ld);	}#endif	tty->closing = 0;	info->event = 0;	info->tty = 0;	if ( info->blocked_open ) {	    if ( info->close_delay ) {#if (LINUX_VERSION_CODE >= VERSION_CODE(2,3,0))				set_current_state(TASK_INTERRUPTIBLE);#else				current->state = TASK_INTERRUPTIBLE;#endif		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_UNLOCK(&info->slock);	// mask by Vicror Yu. 09-26-2002	MX_MOD_DEC;}#if (LINUX_VERSION_CODE < VERSION_CODE(2,6,10))static int mxpcdrv_write(struct tty_struct * tty, int from_user,		       const unsigned char * buf, int count)#elsestatic int mxpcdrv_write(struct tty_struct * tty, 		       const unsigned char * buf, int count)#endif{	int		c, total = 0;	struct mxpcdrv_struct *info = (struct mxpcdrv_struct *)tty->driver_data;	MX_LOCK_INIT();	if ( !tty || !info->xmit_buf || !mxvar_tmp_buf )	    return(0);#if (LINUX_VERSION_CODE < VERSION_CODE(2,6,10))	if ( from_user )	    down(&mxvar_tmp_buf_sem);#endif	while ( 1 ) {	    c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,			       SERIAL_XMIT_SIZE - info->xmit_head));	    if ( c <= 0 )		break;#if (LINUX_VERSION_CODE < VERSION_CODE(2,6,10))	    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);#else		memcpy(info->xmit_buf + info->xmit_head, buf, c);#endif	    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 (LINUX_VERSION_CODE < VERSION_CODE(2,6,10))	if ( from_user )	    up(&mxvar_tmp_buf_sem);#endif	if ( info->xmit_cnt && !tty->stopped ){         	    MX_LOCK(&info->slock);			        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);	}	return(total);}static void mxpcdrv_put_char(struct tty_struct * tty, unsigned char ch){	struct mxpcdrv_struct *info = (struct mxpcdrv_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) */) {        		MX_LOCK(&info->slock);		        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);	}}static void mxpcdrv_flush_chars(struct tty_struct * tty){	struct mxpcdrv_struct *info = (struct mxpcdrv_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);	info->IER |= UART_IER_THRI;	outb(info->IER, info->base + UART_IER);	MX_UNLOCK(&info->slock);}static int mxpcdrv_write_room(struct tty_struct * tty){	struct mxpcdrv_struct *info = (struct mxpcdrv_struct *)tty->driver_data;	int	ret;	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;	if ( ret < 0 )	    ret = 0;	return(ret);}static int mxpcdrv_chars_in_buffer(struct tty_struct * tty){	int len;	struct mxpcdrv_struct *info = (struct mxpcdrv_struct *)tty->driver_data;	len = info->xmit_cnt;	if(!(inb(info->base + UART_LSR) & UART_LSR_THRE))  		len++;			return len;}static void mxpcdrv_flush_buffer(struct tty_struct * tty){	struct mxpcdrv_struct *info = (struct mxpcdrv_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);	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);	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 mxpcdrv_ioctl(struct tty_struct * tty, struct file * file,		       unsigned int cmd, unsigned long arg){	int			error;	struct mxpcdrv_struct *	info = (struct mxpcdrv_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) == MXPCDRV_PORTS )	    return(mxpcdrv_ioctl_special(cmd, arg));	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 )		mxpcdrv_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);	    mxpcdrv_send_break(info, arg ? arg*(HZ/10) : HZ/4);	    return(0);	case TIOCGSOFTCAR:	    error = MX_ACCESS_CHK(VERIFY_WRITE, (void *)arg, sizeof(long));	    if ( MX_ERR(error) )		return(error);	    put_to_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *)arg);	    return 0;	case TIOCSSOFTCAR:	    error = MX_ACCESS_CHK(VERIFY_READ, (void *)arg, sizeof(long));	    if ( MX_ERR(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 = MX_ACCESS_CHK(VERIFY_WRITE, (void *)arg,				sizeof(unsigned int));	    if ( MX_ERR(error) )		return(error);	    return(mxpcdrv_get_modem_info(info, (unsigned int *)arg));	case TIOCMBIS:	case TIOCMBIC:	case TIOCMSET:	    return(mxpcdrv_set_modem_info(info, cmd, (unsigned int *)arg));#endif	case TIOCGSERIAL:	    error = MX_ACCESS_CHK(VERIFY_WRITE, (void *)arg,				sizeof(struct serial_struct));	    if ( MX_ERR(error) )		return(error);	    return(mxpcdrv_get_serial_info(info, (struct serial_struct *)arg));	case TIOCSSERIAL:	    error = MX_ACCESS_CHK(VERIFY_READ, (void *)arg,				sizeof(struct serial_struct));	    if ( MX_ERR(error) )		return(error);	    return(mxpcdrv_set_serial_info(info, (struct serial_struct *)arg));	case TIOCSERGETLSR: /* Get line status register */	    error = MX_ACCESS_CHK(VERIFY_WRITE, (void *)arg,				sizeof(unsigned int));	    if ( MX_ERR(error) )		return(error);	    else		return(mxpcdrv_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:	    MX_LOCK(&info->slock);	    cprev = info->icount;   /* note the counters on entry */	    MX_UNLOCK(&info->slock);	    while ( 1 ) {		//interruptible_sleep_on(&info->delta_msr_wait);		/* see if a signal did it */		if ( signal_pending(current) )		    return(-ERESTARTSYS);	    MX_LOCK(&info->slock);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -