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

📄 pcxx.c

📁 powerpc内核mpc8241linux系统下char驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
}static unsigned termios2digi_i(struct channel *ch, unsigned iflag){	unsigned res = iflag & (IGNBRK|BRKINT|IGNPAR|PARMRK|INPCK|ISTRIP|IXON|IXANY|IXOFF);		if(ch->digiext.digi_flags & DIGI_AIXON)		res |= IAIXON;	return res;}static unsigned termios2digi_h(struct channel *ch, unsigned cflag){	unsigned res = 0;	if(cflag & CRTSCTS) {		ch->digiext.digi_flags |= (RTSPACE|CTSPACE);		res |= (CTS | RTS);	}	if(ch->digiext.digi_flags & RTSPACE)		res |= RTS;	if(ch->digiext.digi_flags & DTRPACE)		res |= DTR;	if(ch->digiext.digi_flags & CTSPACE)		res |= CTS;	if(ch->digiext.digi_flags & DSRPACE)		res |= ch->dsr;	if(ch->digiext.digi_flags & DCDPACE)		res |= ch->dcd;	if (res & RTS)		ch->digiext.digi_flags |= RTSPACE;	if (res & CTS)		ch->digiext.digi_flags |= CTSPACE;	return res;}static void pcxxparam(struct tty_struct *tty, struct channel *ch){	volatile struct board_chan *bc;	unsigned int head;	unsigned mval, hflow, cflag, iflag;	struct termios *ts;	bc = ch->brdchan;	assertgwinon(ch);	ts = tty->termios;	if((ts->c_cflag & CBAUD) == 0) {		head = bc->rin;		bc->rout = head;		head = bc->tin;		fepcmd(ch, STOUT, (unsigned) head, 0, 0, 0);		mval = 0;	} else {		cflag = termios2digi_c(ch, ts->c_cflag);		if(cflag != ch->fepcflag) {			ch->fepcflag = cflag;			fepcmd(ch, SETCTRLFLAGS, (unsigned) cflag, 0, 0, 0);		}		if(cflag & CLOCAL)			ch->asyncflags &= ~ASYNC_CHECK_CD;		else {			ch->asyncflags |= ASYNC_CHECK_CD;		}		mval = DTR | RTS;	}	iflag = termios2digi_i(ch, ts->c_iflag);	if(iflag != ch->fepiflag) {		ch->fepiflag = iflag;		fepcmd(ch, SETIFLAGS, (unsigned int) ch->fepiflag, 0, 0, 0);	}	bc->mint = ch->dcd;	if((ts->c_cflag & CLOCAL) || (ch->digiext.digi_flags & DIGI_FORCEDCD))		if(ch->digiext.digi_flags & DIGI_FORCEDCD)			bc->mint = 0;	ch->imodem = bc->mstat;	hflow = termios2digi_h(ch, ts->c_cflag);	if(hflow != ch->hflow) {		ch->hflow = hflow;		fepcmd(ch, SETHFLOW, hflow, 0xff, 0, 1);	}	/* mval ^= ch->modemfake & (mval ^ ch->modem); */	if(ch->omodem != mval) {		ch->omodem = mval;		fepcmd(ch, SETMODEM, mval, RTS|DTR, 0, 1);	}	if(ch->startc != ch->fepstartc || ch->stopc != ch->fepstopc) {		ch->fepstartc = ch->startc;		ch->fepstopc = ch->stopc;		fepcmd(ch, SONOFFC, ch->fepstartc, ch->fepstopc, 0, 1);	}	if(ch->startca != ch->fepstartca || ch->stopca != ch->fepstopca) {		ch->fepstartca = ch->startca;		ch->fepstopca = ch->stopca;		fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);	}}static void receive_data(struct channel *ch){	volatile struct board_chan *bc;	struct tty_struct *tty;	unsigned int tail, head, wrapmask;	int n;	int piece;	struct termios *ts=0;	unchar *rptr;	int rc;	int wrapgap;    globalwinon(ch);	if (ch->statusflags & RXSTOPPED)		return;	tty = ch->tty;	if(tty)		ts = tty->termios;	bc = ch->brdchan;	if(!bc) {		printk("bc is NULL in receive_data!\n");		return;	}	wrapmask = ch->rxbufsize - 1;	head = bc->rin;	head &= wrapmask;	tail = bc->rout & wrapmask;	n = (head-tail) & wrapmask;	if(n == 0)		return;	/*	 * If CREAD bit is off or device not open, set TX tail to head	 */	if(!tty || !ts || !(ts->c_cflag & CREAD)) {		bc->rout = head;		return;	}	if(tty->flip.count == TTY_FLIPBUF_SIZE) {		/* printk("tty->flip.count = TTY_FLIPBUF_SIZE\n"); */		return;	}	if(bc->orun) {		bc->orun = 0;		printk("overrun! DigiBoard device minor=%d\n",MINOR(tty->device));	}	rxwinon(ch);	rptr = tty->flip.char_buf_ptr;	rc = tty->flip.count;	while(n > 0) {		wrapgap = (head >= tail) ? head - tail : ch->rxbufsize - tail;		piece = (wrapgap < n) ? wrapgap : n;		/*		 * Make sure we don't overflow the buffer		 */		if ((rc + piece) > TTY_FLIPBUF_SIZE)			piece = TTY_FLIPBUF_SIZE - rc;		if (piece == 0)			break;		memcpy(rptr, ch->rxptr + tail, piece);		rptr += piece;		rc += piece;		tail = (tail + piece) & wrapmask;		n -= piece;	}	tty->flip.count = rc;	tty->flip.char_buf_ptr = rptr;    globalwinon(ch);	bc->rout = tail;	/* Must be called with global data */	tty_schedule_flip(ch->tty); 	return;}static int pcxe_ioctl(struct tty_struct *tty, struct file * file,		    unsigned int cmd, unsigned long arg){	int error;	struct channel *ch = (struct channel *) tty->driver_data;	volatile struct board_chan *bc;	int retval;	unsigned int mflag, mstat;	unsigned char startc, stopc;	unsigned long flags;	digiflow_t dflow;	if(ch)		bc = ch->brdchan;	else {		printk("ch is NULL in pcxe_ioctl!\n");		return(-EINVAL);	}	save_flags(flags);	switch(cmd) {		case TCSBRK:	/* SVID version: non-zero arg --> no break */			retval = tty_check_change(tty);			if(retval)				return retval;			setup_empty_event(tty,ch);					tty_wait_until_sent(tty, 0);			if(!arg)				digi_send_break(ch, HZ/4);    /* 1/4 second */			return 0;		case TCSBRKP:	/* support for POSIX tcsendbreak() */			retval = tty_check_change(tty);			if(retval)				return retval;			setup_empty_event(tty,ch);					tty_wait_until_sent(tty, 0);			digi_send_break(ch, arg ? arg*(HZ/10) : HZ/4);			return 0;		case TIOCGSOFTCAR:			return put_user(C_CLOCAL(tty) ? 1 : 0,			    (unsigned int *) arg);		case TIOCSSOFTCAR:			{			    unsigned int value;			    error = get_user( value, (unsigned int *) arg);			    if (error)				return error;			    tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (value ? CLOCAL : 0));			}			return 0;		case TIOCMODG:		case TIOCMGET:			mflag = 0;			cli();			globalwinon(ch);			mstat = bc->mstat;			memoff(ch);			restore_flags(flags);			if(mstat & DTR)				mflag |= TIOCM_DTR;			if(mstat & RTS)				mflag |= TIOCM_RTS;			if(mstat & CTS)				mflag |= TIOCM_CTS;			if(mstat & ch->dsr)				mflag |= TIOCM_DSR;			if(mstat & RI)				mflag |= TIOCM_RI;			if(mstat & ch->dcd)				mflag |= TIOCM_CD;			error = put_user(mflag, (unsigned int *) arg);			if(error)				return error;			break;		case TIOCMBIS:		case TIOCMBIC:		case TIOCMODS:		case TIOCMSET:			error = get_user(mstat, (unsigned int *) arg);			if(error)				return error;			mflag = 0;			if(mstat & TIOCM_DTR)				mflag |= DTR;			if(mstat & TIOCM_RTS)				mflag |= RTS;			switch(cmd) {				case TIOCMODS:				case TIOCMSET:					ch->modemfake = DTR|RTS;					ch->modem = mflag;					break;				case TIOCMBIS:					ch->modemfake |= mflag;					ch->modem |= mflag;					break;				case TIOCMBIC:					ch->modemfake &= ~mflag;					ch->modem &= ~mflag;					break;			}			cli();			globalwinon(ch);			pcxxparam(tty,ch);			memoff(ch);			restore_flags(flags);			break;		case TIOCSDTR:			cli();			ch->omodem |= DTR;			globalwinon(ch);			fepcmd(ch, SETMODEM, DTR, 0, 10, 1);			memoff(ch);			restore_flags(flags);			break;		case TIOCCDTR:			ch->omodem &= ~DTR;			cli();			globalwinon(ch);			fepcmd(ch, SETMODEM, 0, DTR, 10, 1);			memoff(ch);			restore_flags(flags);			break;		case DIGI_GETA:			if((error=verify_area(VERIFY_WRITE, (char*)arg, sizeof(digi_t))))				return(error);			copy_to_user((char*)arg, &ch->digiext, sizeof(digi_t));			break;		case DIGI_SETAW:		case DIGI_SETAF:			if(cmd == DIGI_SETAW) {				setup_empty_event(tty,ch);						tty_wait_until_sent(tty, 0);			}			else {				if(tty->ldisc.flush_buffer)					tty->ldisc.flush_buffer(tty);			}			/* Fall Thru */		case DIGI_SETA:			if((error=verify_area(VERIFY_READ, (char*)arg,sizeof(digi_t))))				return(error);			copy_from_user(&ch->digiext, (char*)arg, sizeof(digi_t));#ifdef DEBUG_IOCTL			printk("ioctl(DIGI_SETA): flags = %x\n", ch->digiext.digi_flags);#endif						if(ch->digiext.digi_flags & DIGI_ALTPIN) {				ch->dcd = DSR;				ch->dsr = CD;			} else {				ch->dcd = CD;				ch->dsr = DSR;			}					cli();			globalwinon(ch);			pcxxparam(tty,ch);			memoff(ch);			restore_flags(flags);			break;		case DIGI_GETFLOW:		case DIGI_GETAFLOW:			cli();				globalwinon(ch);			if(cmd == DIGI_GETFLOW) {				dflow.startc = bc->startc;				dflow.stopc = bc->stopc;			} else {				dflow.startc = bc->startca;				dflow.stopc = bc->stopca;			}			memoff(ch);			restore_flags(flags);			if((error=verify_area(VERIFY_WRITE, (char*)arg,sizeof(dflow))))				return(error);			copy_to_user((char*)arg, &dflow, sizeof(dflow));			break;		case DIGI_SETAFLOW:		case DIGI_SETFLOW:			if(cmd == DIGI_SETFLOW) {				startc = ch->startc;				stopc = ch->stopc;			} else {				startc = ch->startca;				stopc = ch->stopca;			}			if((error=verify_area(VERIFY_READ, (char*)arg,sizeof(dflow))))				return(error);			copy_from_user(&dflow, (char*)arg, sizeof(dflow));			if(dflow.startc != startc || dflow.stopc != stopc) {				cli();				globalwinon(ch);				if(cmd == DIGI_SETFLOW) {					ch->fepstartc = ch->startc = dflow.startc;					ch->fepstopc = ch->stopc = dflow.stopc;					fepcmd(ch,SONOFFC,ch->fepstartc,ch->fepstopc,0, 1);				} else {					ch->fepstartca = ch->startca = dflow.startc;					ch->fepstopca  = ch->stopca = dflow.stopc;					fepcmd(ch, SAUXONOFFC, ch->fepstartca, ch->fepstopca, 0, 1);				}				if(ch->statusflags & TXSTOPPED)					pcxe_start(tty);				memoff(ch);				restore_flags(flags);			}			break;		default:			return -ENOIOCTLCMD;	}	return 0;}static void pcxe_set_termios(struct tty_struct *tty, struct termios *old_termios){	struct channel *info;	if ((info=chan(tty))!=NULL) {		unsigned long flags;		save_flags(flags);		cli();		globalwinon(info);		pcxxparam(tty,info);		memoff(info);		if ((old_termios->c_cflag & CRTSCTS) &&			((tty->termios->c_cflag & CRTSCTS) == 0))			tty->hw_stopped = 0;		if(!(old_termios->c_cflag & CLOCAL) &&			(tty->termios->c_cflag & CLOCAL))			wake_up_interruptible(&info->open_wait);		restore_flags(flags);	}}static void do_pcxe_bh(void){	run_task_queue(&tq_pcxx);}static void do_softint(void *private_){	struct channel *info = (struct channel *) private_;		if(info && info->magic == PCXX_MAGIC) {		struct tty_struct *tty = info->tty;		if (tty && tty->driver_data) {			if(test_and_clear_bit(PCXE_EVENT_HANGUP, &info->event)) {				tty_hangup(tty);				wake_up_interruptible(&info->open_wait);				info->asyncflags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE);			}		}	}}static void pcxe_stop(struct tty_struct *tty){	struct channel *info;	if ((info=chan(tty))!=NULL) {		unsigned long flags;		save_flags(flags); 		cli();		if ((info->statusflags & TXSTOPPED) == 0) {			globalwinon(info);			fepcmd(info, PAUSETX, 0, 0, 0, 0);			info->statusflags |= TXSTOPPED;			memoff(info);		}		restore_flags(flags);	}}static void pcxe_throttle(struct tty_struct * tty){	struct channel *info;	if ((info=chan(tty))!=NULL) {		unsigned long flags;		save_flags(flags);		cli();		if ((info->statusflags & RXSTOPPED) == 0) {			globalwinon(info);			fepcmd(info, PAUSERX, 0, 0, 0, 0);			info->statusflags |= RXSTOPPED;			memoff(info);		}		restore_flags(flags);	}}static void pcxe_unthrottle(struct tty_struct *tty){	struct channel *info;	if ((info=chan(tty)) != NULL) {		unsigned long flags;		/* Just in case output was resumed because of a change in Digi-flow */		save_flags(flags);		cli();		if(info->statusflags & RXSTOPPED) {			volatile struct board_chan *bc;			globalwinon(info);			bc = info->brdchan;			fepcmd(info, RESUMERX, 0, 0, 0, 0);			info->statusflags &= ~RXSTOPPED;			memoff(info);		}		restore_flags(flags);	}}static void pcxe_start(struct tty_struct *tty){	struct channel *info;	if ((info=chan(tty))!=NULL) {		unsigned long flags;		save_flags(flags);		cli();		/* Just in case output was resumed because of a change in Digi-flow */		if(info->statusflags & TXSTOPPED) {			volatile struct board_chan *bc;			globalwinon(info);			bc = info->brdchan;			if(info->statusflags & LOWWAIT)				bc->ilow = 1;			fepcmd(info, RESUMETX, 0, 0, 0, 0);			info->statusflags &= ~TXSTOPPED;			memoff(info);		}		restore_flags(flags);	}}void digi_send_break(struct channel *ch, int msec){	unsigned long flags;	save_flags(flags);	cli();	globalwinon(ch);	/* 	 * Maybe I should send an infinite break here, schedule() for	 * msec amount of time, and then stop the break.  This way,	 * the user can't screw up the FEP by causing digi_send_break()	 * to be called (i.e. via an ioctl()) more than once in msec amount 	 * of time.  Try this for now...	 */	fepcmd(ch, SENDBREAK, msec, 0, 10, 0);	memoff(ch);	restore_flags(flags);}static void setup_empty_event(struct tty_struct *tty, struct channel *ch){	volatile struct board_chan *bc;	unsigned long flags;	save_flags(flags);	cli();	globalwinon(ch);	ch->statusflags |= EMPTYWAIT;	bc = ch->brdchan;	bc->iempty = 1;	memoff(ch);	restore_flags(flags);}

⌨️ 快捷键说明

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