rocket.c

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

C
2,326
字号
		printk(KERN_INFO "tx %d chars...", c);#endif	}	if (info->xmit_cnt == 0)		clear_bit((info->aiop * 8) + info->chan, (void *) &xmit_flags[info->board]);	if (info->xmit_cnt < WAKEUP_CHARS) {		tty_wakeup(tty);#ifdef ROCKETPORT_HAVE_POLL_WAIT		wake_up_interruptible(&tty->poll_wait);#endif	}	spin_unlock_irqrestore(&info->slock, flags);#ifdef ROCKET_DEBUG_INTR	printk(KERN_INFO "(%d,%d,%d,%d)...", info->xmit_cnt, info->xmit_head,	       info->xmit_tail, info->xmit_fifo_room);#endif}/* *  Called when a serial port signals it has read data in it's RX FIFO. *  It checks what interrupts are pending and services them, including *  receiving serial data.   */static void rp_handle_port(struct r_port *info){	CHANNEL_t *cp;	struct tty_struct *tty;	unsigned int IntMask, ChanStatus;	if (!info)		return;	if ((info->flags & ROCKET_INITIALIZED) == 0) {		printk(KERN_INFO "rp: WARNING: rp_handle_port called with info->flags & NOT_INIT\n");		return;	}	if (!info->tty) {		printk(KERN_INFO "rp: WARNING: rp_handle_port called with info->tty==NULL\n");		return;	}	cp = &info->channel;	tty = info->tty;	IntMask = sGetChanIntID(cp) & info->intmask;#ifdef ROCKET_DEBUG_INTR	printk(KERN_INFO "rp_interrupt %02x...", IntMask);#endif	ChanStatus = sGetChanStatus(cp);	if (IntMask & RXF_TRIG) {	/* Rx FIFO trigger level */		rp_do_receive(info, tty, cp, ChanStatus);	}	if (IntMask & DELTA_CD) {	/* CD change  */#if (defined(ROCKET_DEBUG_OPEN) || defined(ROCKET_DEBUG_INTR) || defined(ROCKET_DEBUG_HANGUP))		printk(KERN_INFO "ttyR%d CD now %s...", info->line,		       (ChanStatus & CD_ACT) ? "on" : "off");#endif		if (!(ChanStatus & CD_ACT) && info->cd_status) {#ifdef ROCKET_DEBUG_HANGUP			printk(KERN_INFO "CD drop, calling hangup.\n");#endif			tty_hangup(tty);		}		info->cd_status = (ChanStatus & CD_ACT) ? 1 : 0;		wake_up_interruptible(&info->open_wait);	}#ifdef ROCKET_DEBUG_INTR	if (IntMask & DELTA_CTS) {	/* CTS change */		printk(KERN_INFO "CTS change...\n");	}	if (IntMask & DELTA_DSR) {	/* DSR change */		printk(KERN_INFO "DSR change...\n");	}#endif}/* *  The top level polling routine.  Repeats every 1/100 HZ (10ms). */static void rp_do_poll(unsigned long dummy){	CONTROLLER_t *ctlp;	int ctrl, aiop, ch, line;	unsigned int xmitmask, i;	unsigned int CtlMask;	unsigned char AiopMask;	Word_t bit;	/*  Walk through all the boards (ctrl's) */	for (ctrl = 0; ctrl < max_board; ctrl++) {		if (rcktpt_io_addr[ctrl] <= 0)			continue;		/*  Get a ptr to the board's control struct */		ctlp = sCtlNumToCtlPtr(ctrl);		/*  Get the interrupt status from the board */#ifdef CONFIG_PCI		if (ctlp->BusType == isPCI)			CtlMask = sPCIGetControllerIntStatus(ctlp);		else#endif			CtlMask = sGetControllerIntStatus(ctlp);		/*  Check if any AIOP read bits are set */		for (aiop = 0; CtlMask; aiop++) {			bit = ctlp->AiopIntrBits[aiop];			if (CtlMask & bit) {				CtlMask &= ~bit;				AiopMask = sGetAiopIntStatus(ctlp, aiop);				/*  Check if any port read bits are set */				for (ch = 0; AiopMask;  AiopMask >>= 1, ch++) {					if (AiopMask & 1) {						/*  Get the line number (/dev/ttyRx number). */						/*  Read the data from the port. */						line = GetLineNumber(ctrl, aiop, ch);						rp_handle_port(rp_table[line]);					}				}			}		}		xmitmask = xmit_flags[ctrl];		/*		 *  xmit_flags contains bit-significant flags, indicating there is data		 *  to xmit on the port. Bit 0 is port 0 on this board, bit 1 is port 		 *  1, ... (32 total possible).  The variable i has the aiop and ch 		 *  numbers encoded in it (port 0-7 are aiop0, 8-15 are aiop1, etc).		 */		if (xmitmask) {			for (i = 0; i < rocketModel[ctrl].numPorts; i++) {				if (xmitmask & (1 << i)) {					aiop = (i & 0x18) >> 3;					ch = i & 0x07;					line = GetLineNumber(ctrl, aiop, ch);					rp_do_transmit(rp_table[line]);				}			}		}	}	/*	 * Reset the timer so we get called at the next clock tick (10ms).	 */	if (atomic_read(&rp_num_ports_open))		mod_timer(&rocket_timer, jiffies + POLL_PERIOD);}/* *  Initializes the r_port structure for a port, as well as enabling the port on  *  the board.   *  Inputs:  board, aiop, chan numbers */static void init_r_port(int board, int aiop, int chan, struct pci_dev *pci_dev){	unsigned rocketMode;	struct r_port *info;	int line;	CONTROLLER_T *ctlp;	/*  Get the next available line number */	line = SetLineNumber(board, aiop, chan);	ctlp = sCtlNumToCtlPtr(board);	/*  Get a r_port struct for the port, fill it in and save it globally, indexed by line number */	info = kzalloc(sizeof (struct r_port), GFP_KERNEL);	if (!info) {		printk(KERN_INFO "Couldn't allocate info struct for line #%d\n", line);		return;	}	info->magic = RPORT_MAGIC;	info->line = line;	info->ctlp = ctlp;	info->board = board;	info->aiop = aiop;	info->chan = chan;	info->closing_wait = 3000;	info->close_delay = 50;	init_waitqueue_head(&info->open_wait);	init_completion(&info->close_wait);	info->flags &= ~ROCKET_MODE_MASK;	switch (pc104[board][line]) {	case 422:		info->flags |= ROCKET_MODE_RS422;		break;	case 485:		info->flags |= ROCKET_MODE_RS485;		break;	case 232:	default:		info->flags |= ROCKET_MODE_RS232;		break;	}	info->intmask = RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD | DELTA_CTS | DELTA_DSR;	if (sInitChan(ctlp, &info->channel, aiop, chan) == 0) {		printk(KERN_INFO "RocketPort sInitChan(%d, %d, %d) failed!\n", board, aiop, chan);		kfree(info);		return;	}	rocketMode = info->flags & ROCKET_MODE_MASK;	if ((info->flags & ROCKET_RTS_TOGGLE) || (rocketMode == ROCKET_MODE_RS485))		sEnRTSToggle(&info->channel);	else		sDisRTSToggle(&info->channel);	if (ctlp->boardType == ROCKET_TYPE_PC104) {		switch (rocketMode) {		case ROCKET_MODE_RS485:			sSetInterfaceMode(&info->channel, InterfaceModeRS485);			break;		case ROCKET_MODE_RS422:			sSetInterfaceMode(&info->channel, InterfaceModeRS422);			break;		case ROCKET_MODE_RS232:		default:			if (info->flags & ROCKET_RTS_TOGGLE)				sSetInterfaceMode(&info->channel, InterfaceModeRS232T);			else				sSetInterfaceMode(&info->channel, InterfaceModeRS232);			break;		}	}	spin_lock_init(&info->slock);	mutex_init(&info->write_mtx);	rp_table[line] = info;	tty_register_device(rocket_driver, line, pci_dev ? &pci_dev->dev :			NULL);}/* *  Configures a rocketport port according to its termio settings.  Called from  *  user mode into the driver (exception handler).  *info CD manipulation is spinlock protected. */static void configure_r_port(struct r_port *info,			     struct ktermios *old_termios){	unsigned cflag;	unsigned long flags;	unsigned rocketMode;	int bits, baud, divisor;	CHANNEL_t *cp;	if (!info->tty || !info->tty->termios)		return;	cp = &info->channel;	cflag = info->tty->termios->c_cflag;	/* Byte size and parity */	if ((cflag & CSIZE) == CS8) {		sSetData8(cp);		bits = 10;	} else {		sSetData7(cp);		bits = 9;	}	if (cflag & CSTOPB) {		sSetStop2(cp);		bits++;	} else {		sSetStop1(cp);	}	if (cflag & PARENB) {		sEnParity(cp);		bits++;		if (cflag & PARODD) {			sSetOddParity(cp);		} else {			sSetEvenParity(cp);		}	} else {		sDisParity(cp);	}	/* baud rate */	baud = tty_get_baud_rate(info->tty);	if (!baud)		baud = 9600;	divisor = ((rp_baud_base[info->board] + (baud >> 1)) / baud) - 1;	if ((divisor >= 8192 || divisor < 0) && old_termios) {		info->tty->termios->c_cflag &= ~CBAUD;		info->tty->termios->c_cflag |=		    (old_termios->c_cflag & CBAUD);		baud = tty_get_baud_rate(info->tty);		if (!baud)			baud = 9600;		divisor = (rp_baud_base[info->board] / baud) - 1;	}	if (divisor >= 8192 || divisor < 0) {		baud = 9600;		divisor = (rp_baud_base[info->board] / baud) - 1;	}	info->cps = baud / bits;	sSetBaud(cp, divisor);	if (cflag & CRTSCTS) {		info->intmask |= DELTA_CTS;		sEnCTSFlowCtl(cp);	} else {		info->intmask &= ~DELTA_CTS;		sDisCTSFlowCtl(cp);	}	if (cflag & CLOCAL) {		info->intmask &= ~DELTA_CD;	} else {		spin_lock_irqsave(&info->slock, flags);		if (sGetChanStatus(cp) & CD_ACT)			info->cd_status = 1;		else			info->cd_status = 0;		info->intmask |= DELTA_CD;		spin_unlock_irqrestore(&info->slock, flags);	}	/*	 * Handle software flow control in the board	 */#ifdef ROCKET_SOFT_FLOW	if (I_IXON(info->tty)) {		sEnTxSoftFlowCtl(cp);		if (I_IXANY(info->tty)) {			sEnIXANY(cp);		} else {			sDisIXANY(cp);		}		sSetTxXONChar(cp, START_CHAR(info->tty));		sSetTxXOFFChar(cp, STOP_CHAR(info->tty));	} else {		sDisTxSoftFlowCtl(cp);		sDisIXANY(cp);		sClrTxXOFF(cp);	}#endif	/*	 * Set up ignore/read mask words	 */	info->read_status_mask = STMRCVROVRH | 0xFF;	if (I_INPCK(info->tty))		info->read_status_mask |= STMFRAMEH | STMPARITYH;	if (I_BRKINT(info->tty) || I_PARMRK(info->tty))		info->read_status_mask |= STMBREAKH;	/*	 * Characters to ignore	 */	info->ignore_status_mask = 0;	if (I_IGNPAR(info->tty))		info->ignore_status_mask |= STMFRAMEH | STMPARITYH;	if (I_IGNBRK(info->tty)) {		info->ignore_status_mask |= STMBREAKH;		/*		 * If we're ignoring parity and break indicators,		 * ignore overruns too.  (For real raw support).		 */		if (I_IGNPAR(info->tty))			info->ignore_status_mask |= STMRCVROVRH;	}	rocketMode = info->flags & ROCKET_MODE_MASK;	if ((info->flags & ROCKET_RTS_TOGGLE)	    || (rocketMode == ROCKET_MODE_RS485))		sEnRTSToggle(cp);	else		sDisRTSToggle(cp);	sSetRTS(&info->channel);	if (cp->CtlP->boardType == ROCKET_TYPE_PC104) {		switch (rocketMode) {		case ROCKET_MODE_RS485:			sSetInterfaceMode(cp, InterfaceModeRS485);			break;		case ROCKET_MODE_RS422:			sSetInterfaceMode(cp, InterfaceModeRS422);			break;		case ROCKET_MODE_RS232:		default:			if (info->flags & ROCKET_RTS_TOGGLE)				sSetInterfaceMode(cp, InterfaceModeRS232T);			else				sSetInterfaceMode(cp, InterfaceModeRS232);			break;		}	}}/*  info->count is considered critical, protected by spinlocks.  */static int block_til_ready(struct tty_struct *tty, struct file *filp,			   struct r_port *info){	DECLARE_WAITQUEUE(wait, current);	int retval;	int do_clocal = 0, extra_count = 0;	unsigned long flags;	/*	 * If the device is in the middle of being closed, then block	 * until it's done, and then try again.	 */	if (tty_hung_up_p(filp))		return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);	if (info->flags & ROCKET_CLOSING) {		if (wait_for_completion_interruptible(&info->close_wait))			return -ERESTARTSYS;		return ((info->flags & ROCKET_HUP_NOTIFY) ? -EAGAIN : -ERESTARTSYS);	}	/*	 * If non-blocking mode is set, or the port is not enabled,	 * then make the check up front and then exit.	 */	if ((filp->f_flags & O_NONBLOCK) || (tty->flags & (1 << TTY_IO_ERROR))) {		info->flags |= ROCKET_NORMAL_ACTIVE;		return 0;	}	if (tty->termios->c_cflag & CLOCAL)		do_clocal = 1;	/*	 * Block waiting for the carrier detect and the line to become free.  While we are in	 * this loop, info->count is dropped by one, so that rp_close() knows when to free things.           * We restore it upon exit, either normal or abnormal.	 */	retval = 0;	add_wait_queue(&info->open_wait, &wait);#ifdef ROCKET_DEBUG_OPEN	printk(KERN_INFO "block_til_ready before block: ttyR%d, count = %d\n", info->line, info->count);#endif	spin_lock_irqsave(&info->slock, flags);#ifdef ROCKET_DISABLE_SIMUSAGE	info->flags |= ROCKET_NORMAL_ACTIVE;#else	if (!tty_hung_up_p(filp)) {		extra_count = 1;		info->count--;	}#endif	info->blocked_open++;	spin_unlock_irqrestore(&info->slock, flags);	while (1) {		if (tty->termios->c_cflag & CBAUD) {			sSetDTR(&info->channel);			sSetRTS(&info->channel);		}		set_current_state(TASK_INTERRUPTIBLE);		if (tty_hung_up_p(filp) || !(info->flags & ROCKET_INITIALIZED)) {			if (info->flags & ROCKET_HUP_NOTIFY)				retval = -EAGAIN;			else				retval = -ERESTARTSYS;

⌨️ 快捷键说明

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