rocket.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,368 行 · 第 1/5 页

C
2,368
字号
#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.	 */	info->session = current->signal->session;	info->pgrp = process_group(current);	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) {			current->state = TASK_INTERRUPTIBLE;			schedule_timeout(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;	wake_up_interruptible(&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 termios *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;}static int reset_rm2(struct r_port *info, void __user *arg){	int reset;	if (copy_from_user(&reset, arg, sizeof (int)))		return -EFAULT;	if (reset)		reset = 1;	if (rcktpt_type[info->board] != ROCKET_TYPE_MODEMII &&            rcktpt_type[info->board] != ROCKET_TYPE_MODEMIII)		return -EINVAL;	if (info->ctlp->BusType == isISA)		sModemReset(info->ctlp, info->chan, reset);	else		sPCIModemReset(info->ctlp, info->chan, reset);	return 0;}static int get_version(struct r_port *info, struct rocket_version __user *retvers){	if (copy_to_user(retvers, &driver_version, sizeof (*retvers)))		return -EFAULT;	return 0;}/*  IOCTL call handler into the driver */static int rp_ioctl(struct tty_struct *tty, struct file *file,		    unsigned int cmd, unsigned long arg){	struct r_port *info = (struct r_port *) tty->driver_data;	void __user *argp = (void __user *)arg;	if (cmd != RCKP_GET_PORTS && rocket_paranoia_check(info, "rp_ioctl"))		return -ENXIO;	switch (cmd) {	case RCKP_GET_STRUCT:		if (copy_to_user(argp, info, sizeof (struct r_port)))			return -EFAULT;		return 0;	case RCKP_GET_CONFIG:		return get_config(info, argp);	case RCKP_SET_CONFIG:		return set_config(info, argp);	case RCKP_GET_PORTS:		return get_ports(info, argp);	case RCKP_RESET_RM2:		return reset_rm2(info, argp);	case RCKP_GET_VERSION:		return get_version(info, argp);	default:		return -ENOIOCTLCMD;	}	return 0;}static void rp_send_xchar(struct tty_struct *tty, char ch){	struct r_port *info = (struct r_port *) tty->driver_data;	CHANNEL_t *cp;	if (rocket_paranoia_check(info, "rp_send_xchar"))		return;	cp = &info->channel;	if (sGetTxCnt(cp))		sWriteTxPrioByte(cp, ch);	else		sWriteTxByte(sGetTxRxDataIO(cp), ch);}static void rp_throttle(struct tty_struct *tty){	struct r_port *info = (struct r_port *) tty->driver_data;	CHANNEL_t *cp;

⌨️ 快捷键说明

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