rocket.c

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

C
2,368
字号
		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, i;	unsigned int xmitmask;	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 interupt 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 = kmalloc(sizeof (struct r_port), GFP_KERNEL);	if (!info) {		printk(KERN_INFO "Couldn't allocate info struct for line #%d\n", line);		return;	}	memset(info, 0, sizeof (struct r_port));	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_waitqueue_head(&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);	sema_init(&info->write_sem, 1);	rp_table[line] = info;	if (pci_dev)		tty_register_device(rocket_driver, line, &pci_dev->dev);}/* *  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 termios *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) {		interruptible_sleep_on(&info->close_wait);		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;			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 */	}	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) {		interruptible_sleep_on(&info->close_wait);		free_page(page);		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);

⌨️ 快捷键说明

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