rocket.c

来自「linux 内核源代码」· C语言 代码 · 共 2,326 行 · 第 1/5 页

C
2,326
字号
			break;		}		if (!(info->flags & ROCKET_CLOSING) && (do_clocal || (sGetChanStatusLo(&info->channel) & CD_ACT)))			break;		if (signal_pending(current)) {			retval = -ERESTARTSYS;			break;		}#ifdef ROCKET_DEBUG_OPEN		printk(KERN_INFO "block_til_ready blocking: ttyR%d, count = %d, flags=0x%0x\n",		     info->line, info->count, info->flags);#endif		schedule();	/*  Don't hold spinlock here, will hang PC */	}	__set_current_state(TASK_RUNNING);	remove_wait_queue(&info->open_wait, &wait);	spin_lock_irqsave(&info->slock, flags);	if (extra_count)		info->count++;	info->blocked_open--;	spin_unlock_irqrestore(&info->slock, flags);#ifdef ROCKET_DEBUG_OPEN	printk(KERN_INFO "block_til_ready after blocking: ttyR%d, count = %d\n",	       info->line, info->count);#endif	if (retval)		return retval;	info->flags |= ROCKET_NORMAL_ACTIVE;	return 0;}/* *  Exception handler that opens a serial port.  Creates xmit_buf storage, fills in  *  port's r_port struct.  Initializes the port hardware.   */static int rp_open(struct tty_struct *tty, struct file *filp){	struct r_port *info;	int line = 0, retval;	CHANNEL_t *cp;	unsigned long page;	line = TTY_GET_LINE(tty);	if ((line < 0) || (line >= MAX_RP_PORTS) || ((info = rp_table[line]) == NULL))		return -ENXIO;	page = __get_free_page(GFP_KERNEL);	if (!page)		return -ENOMEM;	if (info->flags & ROCKET_CLOSING) {		retval = wait_for_completion_interruptible(&info->close_wait);		free_page(page);		if (retval)			return retval;		return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);	}	/*	 * We must not sleep from here until the port is marked fully in use.	 */	if (info->xmit_buf)		free_page(page);	else		info->xmit_buf = (unsigned char *) page;	tty->driver_data = info;	info->tty = tty;	if (info->count++ == 0) {		atomic_inc(&rp_num_ports_open);#ifdef ROCKET_DEBUG_OPEN		printk(KERN_INFO "rocket mod++ = %d...", atomic_read(&rp_num_ports_open));#endif	}#ifdef ROCKET_DEBUG_OPEN	printk(KERN_INFO "rp_open ttyR%d, count=%d\n", info->line, info->count);#endif	/*	 * Info->count is now 1; so it's safe to sleep now.	 */	if ((info->flags & ROCKET_INITIALIZED) == 0) {		cp = &info->channel;		sSetRxTrigger(cp, TRIG_1);		if (sGetChanStatus(cp) & CD_ACT)			info->cd_status = 1;		else			info->cd_status = 0;		sDisRxStatusMode(cp);		sFlushRxFIFO(cp);		sFlushTxFIFO(cp);		sEnInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN));		sSetRxTrigger(cp, TRIG_1);		sGetChanStatus(cp);		sDisRxStatusMode(cp);		sClrTxXOFF(cp);		sDisCTSFlowCtl(cp);		sDisTxSoftFlowCtl(cp);		sEnRxFIFO(cp);		sEnTransmit(cp);		info->flags |= ROCKET_INITIALIZED;		/*		 * Set up the tty->alt_speed kludge		 */		if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)			info->tty->alt_speed = 57600;		if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)			info->tty->alt_speed = 115200;		if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)			info->tty->alt_speed = 230400;		if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)			info->tty->alt_speed = 460800;		configure_r_port(info, NULL);		if (tty->termios->c_cflag & CBAUD) {			sSetDTR(cp);			sSetRTS(cp);		}	}	/*  Starts (or resets) the maint polling loop */	mod_timer(&rocket_timer, jiffies + POLL_PERIOD);	retval = block_til_ready(tty, filp, info);	if (retval) {#ifdef ROCKET_DEBUG_OPEN		printk(KERN_INFO "rp_open returning after block_til_ready with %d\n", retval);#endif		return retval;	}	return 0;}/* *  Exception handler that closes a serial port. info->count is considered critical.  */static void rp_close(struct tty_struct *tty, struct file *filp){	struct r_port *info = (struct r_port *) tty->driver_data;	unsigned long flags;	int timeout;	CHANNEL_t *cp;		if (rocket_paranoia_check(info, "rp_close"))		return;#ifdef ROCKET_DEBUG_OPEN	printk(KERN_INFO "rp_close ttyR%d, count = %d\n", info->line, info->count);#endif	if (tty_hung_up_p(filp))		return;	spin_lock_irqsave(&info->slock, flags);	if ((tty->count == 1) && (info->count != 1)) {		/*		 * 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(KERN_INFO "rp_close: bad serial port count; tty->count is 1, "		       "info->count is %d\n", info->count);		info->count = 1;	}	if (--info->count < 0) {		printk(KERN_INFO "rp_close: bad serial port count for ttyR%d: %d\n",		       info->line, info->count);		info->count = 0;	}	if (info->count) {		spin_unlock_irqrestore(&info->slock, flags);		return;	}	info->flags |= ROCKET_CLOSING;	spin_unlock_irqrestore(&info->slock, flags);	cp = &info->channel;	/*	 * Notify the line discpline to only process XON/XOFF characters	 */	tty->closing = 1;	/*	 * If transmission was throttled by the application request,	 * just flush the xmit buffer.	 */	if (tty->flow_stopped)		rp_flush_buffer(tty);	/*	 * Wait for the transmit buffer to clear	 */	if (info->closing_wait != ROCKET_CLOSING_WAIT_NONE)		tty_wait_until_sent(tty, info->closing_wait);	/*	 * Before we drop DTR, make sure the UART transmitter	 * has completely drained; this is especially	 * important if there is a transmit FIFO!	 */	timeout = (sGetTxCnt(cp) + 1) * HZ / info->cps;	if (timeout == 0)		timeout = 1;	rp_wait_until_sent(tty, timeout);	clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);	sDisTransmit(cp);	sDisInterrupts(cp, (TXINT_EN | MCINT_EN | RXINT_EN | SRCINT_EN | CHANINT_EN));	sDisCTSFlowCtl(cp);	sDisTxSoftFlowCtl(cp);	sClrTxXOFF(cp);	sFlushRxFIFO(cp);	sFlushTxFIFO(cp);	sClrRTS(cp);	if (C_HUPCL(tty))		sClrDTR(cp);	if (TTY_DRIVER_FLUSH_BUFFER_EXISTS(tty))		TTY_DRIVER_FLUSH_BUFFER(tty);			tty_ldisc_flush(tty);	clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);	if (info->blocked_open) {		if (info->close_delay) {			msleep_interruptible(jiffies_to_msecs(info->close_delay));		}		wake_up_interruptible(&info->open_wait);	} else {		if (info->xmit_buf) {			free_page((unsigned long) info->xmit_buf);			info->xmit_buf = NULL;		}	}	info->flags &= ~(ROCKET_INITIALIZED | ROCKET_CLOSING | ROCKET_NORMAL_ACTIVE);	tty->closing = 0;	complete_all(&info->close_wait);	atomic_dec(&rp_num_ports_open);#ifdef ROCKET_DEBUG_OPEN	printk(KERN_INFO "rocket mod-- = %d...", atomic_read(&rp_num_ports_open));	printk(KERN_INFO "rp_close ttyR%d complete shutdown\n", info->line);#endif}static void rp_set_termios(struct tty_struct *tty,			   struct ktermios *old_termios){	struct r_port *info = (struct r_port *) tty->driver_data;	CHANNEL_t *cp;	unsigned cflag;	if (rocket_paranoia_check(info, "rp_set_termios"))		return;	cflag = tty->termios->c_cflag;	if (cflag == old_termios->c_cflag)		return;	/*	 * This driver doesn't support CS5 or CS6	 */	if (((cflag & CSIZE) == CS5) || ((cflag & CSIZE) == CS6))		tty->termios->c_cflag =		    ((cflag & ~CSIZE) | (old_termios->c_cflag & CSIZE));	configure_r_port(info, old_termios);	cp = &info->channel;	/* Handle transition to B0 status */	if ((old_termios->c_cflag & CBAUD) && !(tty->termios->c_cflag & CBAUD)) {		sClrDTR(cp);		sClrRTS(cp);	}	/* Handle transition away from B0 status */	if (!(old_termios->c_cflag & CBAUD) && (tty->termios->c_cflag & CBAUD)) {		if (!tty->hw_stopped || !(tty->termios->c_cflag & CRTSCTS))			sSetRTS(cp);		sSetDTR(cp);	}	if ((old_termios->c_cflag & CRTSCTS) && !(tty->termios->c_cflag & CRTSCTS)) {		tty->hw_stopped = 0;		rp_start(tty);	}}static void rp_break(struct tty_struct *tty, int break_state){	struct r_port *info = (struct r_port *) tty->driver_data;	unsigned long flags;	if (rocket_paranoia_check(info, "rp_break"))		return;	spin_lock_irqsave(&info->slock, flags);	if (break_state == -1)		sSendBreak(&info->channel);	else		sClrBreak(&info->channel);	spin_unlock_irqrestore(&info->slock, flags);}/* * sGetChanRI used to be a macro in rocket_int.h. When the functionality for * the UPCI boards was added, it was decided to make this a function because * the macro was getting too complicated. All cases except the first one * (UPCIRingInd) are taken directly from the original macro. */static int sGetChanRI(CHANNEL_T * ChP){	CONTROLLER_t *CtlP = ChP->CtlP;	int ChanNum = ChP->ChanNum;	int RingInd = 0;	if (CtlP->UPCIRingInd)		RingInd = !(sInB(CtlP->UPCIRingInd) & sBitMapSetTbl[ChanNum]);	else if (CtlP->AltChanRingIndicator)		RingInd = sInB((ByteIO_t) (ChP->ChanStat + 8)) & DSR_ACT;	else if (CtlP->boardType == ROCKET_TYPE_PC104)		RingInd = !(sInB(CtlP->AiopIO[3]) & sBitMapSetTbl[ChanNum]);	return RingInd;}/********************************************************************************************//*  Here are the routines used by rp_ioctl.  These are all called from exception handlers.  *//* *  Returns the state of the serial modem control lines.  These next 2 functions  *  are the way kernel versions > 2.5 handle modem control lines rather than IOCTLs. */static int rp_tiocmget(struct tty_struct *tty, struct file *file){	struct r_port *info = (struct r_port *)tty->driver_data;	unsigned int control, result, ChanStatus;	ChanStatus = sGetChanStatusLo(&info->channel);	control = info->channel.TxControl[3];	result = ((control & SET_RTS) ? TIOCM_RTS : 0) | 		((control & SET_DTR) ?  TIOCM_DTR : 0) |		((ChanStatus & CD_ACT) ? TIOCM_CAR : 0) |		(sGetChanRI(&info->channel) ? TIOCM_RNG : 0) |		((ChanStatus & DSR_ACT) ? TIOCM_DSR : 0) |		((ChanStatus & CTS_ACT) ? TIOCM_CTS : 0);	return result;}/*  *  Sets the modem control lines */static int rp_tiocmset(struct tty_struct *tty, struct file *file,		    unsigned int set, unsigned int clear){	struct r_port *info = (struct r_port *)tty->driver_data;	if (set & TIOCM_RTS)		info->channel.TxControl[3] |= SET_RTS;	if (set & TIOCM_DTR)		info->channel.TxControl[3] |= SET_DTR;	if (clear & TIOCM_RTS)		info->channel.TxControl[3] &= ~SET_RTS;	if (clear & TIOCM_DTR)		info->channel.TxControl[3] &= ~SET_DTR;	sOutDW(info->channel.IndexAddr, *(DWord_t *) & (info->channel.TxControl[0]));	return 0;}static int get_config(struct r_port *info, struct rocket_config __user *retinfo){	struct rocket_config tmp;	if (!retinfo)		return -EFAULT;	memset(&tmp, 0, sizeof (tmp));	tmp.line = info->line;	tmp.flags = info->flags;	tmp.close_delay = info->close_delay;	tmp.closing_wait = info->closing_wait;	tmp.port = rcktpt_io_addr[(info->line >> 5) & 3];	if (copy_to_user(retinfo, &tmp, sizeof (*retinfo)))		return -EFAULT;	return 0;}static int set_config(struct r_port *info, struct rocket_config __user *new_info){	struct rocket_config new_serial;	if (copy_from_user(&new_serial, new_info, sizeof (new_serial)))		return -EFAULT;	if (!capable(CAP_SYS_ADMIN))	{		if ((new_serial.flags & ~ROCKET_USR_MASK) != (info->flags & ~ROCKET_USR_MASK))			return -EPERM;		info->flags = ((info->flags & ~ROCKET_USR_MASK) | (new_serial.flags & ROCKET_USR_MASK));		configure_r_port(info, NULL);		return 0;	}	info->flags = ((info->flags & ~ROCKET_FLAGS) | (new_serial.flags & ROCKET_FLAGS));	info->close_delay = new_serial.close_delay;	info->closing_wait = new_serial.closing_wait;	if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)		info->tty->alt_speed = 57600;	if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)		info->tty->alt_speed = 115200;	if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)		info->tty->alt_speed = 230400;	if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)		info->tty->alt_speed = 460800;	configure_r_port(info, NULL);	return 0;}/* *  This function fills in a rocket_ports struct with information *  about what boards/ports are in the system.  This info is passed *  to user space.  See setrocket.c where the info is used to create *  the /dev/ttyRx ports. */static int get_ports(struct r_port *info, struct rocket_ports __user *retports){	struct rocket_ports tmp;	int board;	if (!retports)		return -EFAULT;	memset(&tmp, 0, sizeof (tmp));	tmp.tty_major = rocket_driver->major;	for (board = 0; board < 4; board++) {		tmp.rocketModel[board].model = rocketModel[board].model;		strcpy(tmp.rocketModel[board].modelString, rocketModel[board].modelString);		tmp.rocketModel[board].numPorts = rocketModel[board].numPorts;		tmp.rocketModel[board].loadrm2 = rocketModel[board].loadrm2;		tmp.rocketModel[board].startingPortNumber = rocketModel[board].startingPortNumber;	}	if (copy_to_user(retports, &tmp, sizeof (*retports)))		return -EFAULT;	return 0;}

⌨️ 快捷键说明

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