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

📄 rocket.c

📁 powerpc内核mpc8241linux系统下char驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
			printk("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("CTS change...\n");	}	if (IntMask & DELTA_DSR) {	/* DSR change */		printk("DSR change...\n");	}#endif}/* * The top level polling routine. */static void rp_do_poll(void){	CONTROLLER_t *ctlp;	int ctrl, aiop, ch, line;	unsigned int xmitmask;	unsigned char CtlMask, AiopMask;#ifdef TIME_STAT	unsigned long low=0, high=0, loop_time;	unsigned long long time_stat_tmp=0, time_stat_tmp2=0;	__asm__(".byte 0x0f,0x31"		:"=a" (low), "=d" (high));	time_stat_tmp = high;	time_stat_tmp <<= 32;	time_stat_tmp += low;#endif /* TIME_STAT */	for (ctrl=0; ctrl < max_board; ctrl++) {		if (rcktpt_io_addr[ctrl] <= 0)			continue;		ctlp= sCtlNumToCtlPtr(ctrl);#ifdef ENABLE_PCI		if(ctlp->BusType == isPCI)			CtlMask= sPCIGetControllerIntStatus(ctlp);		else#endif			CtlMask= sGetControllerIntStatus(ctlp);		for (aiop=0; CtlMask; CtlMask >>= 1, aiop++) {			if (CtlMask & 1) {				AiopMask= sGetAiopIntStatus(ctlp, aiop);				for (ch=0; AiopMask; AiopMask >>= 1, ch++) {					if (AiopMask & 1) {						line = (ctrl << 5) | 							(aiop << 3) | ch;						rp_handle_port(rp_table[line]);					}				}			}		}		xmitmask = xmit_flags[ctrl];		for (line = ctrl << 5; xmitmask; xmitmask >>= 1, line++) {			if (xmitmask & 1)				rp_do_transmit(rp_table[line]);		}	}	/*	 * Reset the timer so we get called at the next clock tick.	 */	if (rp_num_ports_open) {		timer_active |= 1 << COMTROL_TIMER;	}#ifdef TIME_STAT	__asm__(".byte 0x0f,0x31"		:"=a" (low), "=d" (high));	time_stat_tmp2 = high;	time_stat_tmp2 <<= 32;	time_stat_tmp2 += low;	time_stat_tmp2 -= time_stat_tmp;	time_stat += time_stat_tmp2;	if (time_counter == 0) 		time_stat_short = time_stat_long = time_stat_tmp2;	else {		if ( time_stat_tmp2 < time_stat_short )			time_stat_short = time_stat_tmp2;		else if ( time_stat_tmp2 > time_stat_long )			time_stat_long = time_stat_tmp2;	}	if ( ++time_counter == TIME_COUNTER ) {		loop_time = (unsigned long) ( ((unsigned long)(time_stat >> 32) * ( (unsigned long)(0xffffffff)/(TIME_STAT_CPU * TIME_COUNTER) ) ) + ((unsigned long)time_stat/(TIME_STAT_CPU*TIME_COUNTER)));#ifdef TIME_STAT_VERBOSE		printk("rp_do_poll: Interrupt Timings\n");		printk("     %5ld iterations; %ld us min,\n",		       (long)TIME_COUNTER, (time_stat_short/TIME_STAT_CPU));		printk("     %5ld us max, %ld us average per iteration.\n",		       (time_stat_long/TIME_STAT_CPU), loop_time);		printk("We want to use < 5,000 us for an iteration.\n");#else /* TIME_STAT_VERBOSE */		printk("rp: %ld loops: %ld min, %ld max, %ld us/loop.\n",		       (long)TIME_COUNTER, (time_stat_short/TIME_STAT_CPU),		       (time_stat_long/TIME_STAT_CPU), loop_time);#endif /* TIME_STAT_VERBOSE */		time_counter = time_stat = 0;		time_stat_short = time_stat_long = 0;	}#endif /* TIME_STAT */}/* * Here ends the interrupt/polling routine. *//* * This function initializes the r_port structure, as well as enabling * the port on the RocketPort board. */static void init_r_port(int board, int aiop, int chan){	struct r_port *info;	int line;	CONTROLLER_T *ctlp;	CHANNEL_t	*cp;		line = (board << 5) | (aiop << 3) | chan;	ctlp= sCtlNumToCtlPtr(board);	info = kmalloc(sizeof(struct r_port), GFP_KERNEL);	if (!info) {		printk("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;	info->callout_termios =callout_driver.init_termios;	info->normal_termios = rocket_driver.init_termios;	info->intmask = RXF_TRIG | TXFIFO_MT | SRC_INT | DELTA_CD |		DELTA_CTS | DELTA_DSR;	if (sInitChan(ctlp, &info->channel, aiop, chan) == 0) {		printk("Rocketport sInitChan(%d, %d, %d) failed!\n",		       board, aiop, chan);		kfree(info);		return;	}	cp = &info->channel;	rp_table[line] = info;}#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */static int baud_table[] = {	0, 50, 75, 110, 134, 150, 200, 300,	600, 1200, 1800, 2400, 4800, 9600, 19200,	38400, 57600, 115200, 230400, 460800, 0 };#endif/* * This routine configures a rocketport port so according to its * termio settings. */static void configure_r_port(struct r_port *info){	unsigned cflag;	unsigned long 	flags;	int	bits, baud;#if (LINUX_VERSION_CODE < 131393) /* Linux 2.1.65 */	int i;#endif	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 */#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */	i = cflag & CBAUD;	if (i & CBAUDEX) {		i &= ~CBAUDEX;		if (i < 1 || i > 4) 			info->tty->termios->c_cflag &= ~CBAUDEX;		else			i += 15;	}	if (i == 15) {		if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_HI)			i += 1;		if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_VHI)			i += 2;		if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_SHI)			i += 3;		if ((info->flags & ROCKET_SPD_MASK) == ROCKET_SPD_WARP)			i += 4;	}	baud = baud_table[i] ? baud_table[i] : 9600;#else	baud = tty_get_baud_rate(info->tty);	if (!baud)		baud = 9600;#endif	info->cps = baud / bits;	sSetBaud(cp, (rp_baud_base/baud) - 1);		if (cflag & CRTSCTS) {		info->intmask |= DELTA_CTS;		sEnCTSFlowCtl(cp);	} else {		info->intmask &= ~DELTA_CTS;		sDisCTSFlowCtl(cp);	}	sSetRTS(&info->channel);	if (cflag & CLOCAL)		info->intmask &= ~DELTA_CD;	else {		save_flags(flags); cli();		if (sGetChanStatus(cp) & CD_ACT)			info->cd_status = 1;		else			info->cd_status = 0;		info->intmask |= DELTA_CD;		restore_flags(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;	}}static int block_til_ready(struct tty_struct *tty, struct file * filp,			   struct r_port *info){	struct wait_queue wait = { current, NULL };	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 this is a callout device, then just make sure the normal	 * device isn't being used.	 */	if (tty->driver.subtype == SERIAL_TYPE_CALLOUT) {		if (info->flags & ROCKET_NORMAL_ACTIVE)			return -EBUSY;		if ((info->flags & ROCKET_CALLOUT_ACTIVE) &&		    (info->flags & ROCKET_SESSION_LOCKOUT) &&		    (info->session != current->session))		    return -EBUSY;		if ((info->flags & ROCKET_CALLOUT_ACTIVE) &&		    (info->flags & ROCKET_PGRP_LOCKOUT) &&		    (info->pgrp != current->pgrp))		    return -EBUSY;		info->flags |= ROCKET_CALLOUT_ACTIVE;		return 0;	}		/*	 * 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))) {		if (info->flags & ROCKET_CALLOUT_ACTIVE)			return -EBUSY;		info->flags |= ROCKET_NORMAL_ACTIVE;		return 0;	}	if (info->flags & ROCKET_CALLOUT_ACTIVE) {		if (info->normal_termios.c_cflag & CLOCAL)			do_clocal = 1;	} else {		if (tty->termios->c_cflag & CLOCAL)			do_clocal = 1;	}		/*	 * Block waiting for the carrier detect and the line to become	 * free (i.e., not in use by the callout).  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("block_til_ready before block: ttyR%d, count = %d\n",	       info->line, info->count);#endif	save_flags(flags); cli();	if (!tty_hung_up_p(filp)) {		extra_count = 1;		info->count--;	}	restore_flags(flags);	info->blocked_open++;	while (1) {		if (!(info->flags & ROCKET_CALLOUT_ACTIVE) &&		    (tty->termios->c_cflag & CBAUD)) {			sSetDTR(&info->channel);			sSetRTS(&info->channel);		}		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_CALLOUT_ACTIVE) &&		    !(info->flags & ROCKET_CLOSING) &&		    (do_clocal || (sGetChanStatusLo(&info->channel) &				   CD_ACT)))			break;		if (signal_pending(current)) {			retval = -ERESTARTSYS;			break;		}#ifdef ROCKET_DEBUG_OPEN		printk("block_til_ready blocking: ttyR%d, count = %d, flags=0x%0x\n",		       info->line, info->count, info->flags);#endif		schedule();	}	current->state = TASK_RUNNING;	remove_wait_queue(&info->open_wait, &wait);	cli();	if (extra_count)		info->count++;	restore_flags(flags);	info->blocked_open--;#ifdef ROCKET_DEBUG_OPEN	printk("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;}	/* * This routine is called whenever a rocketport board is opened. */static int rp_open(struct tty_struct *tty, struct file * filp){	struct r_port *info;	int	line, retval;	CHANNEL_t	*cp;	unsigned long page;		line = MINOR(tty->device) - tty->driver.minor_start;	if ((line < 0) || (line >= MAX_RP_PORTS))		return -ENODEV;	if (!tmp_buf) {		page = get_free_page(GFP_KERNEL);		if (!page)			return -ENOMEM;		if (tmp_buf)			free_page(page);		else			tmp_buf = (unsigned char *) page;	}	page = get_free_page(GFP_KERNEL);	if (!page)		return -ENOMEM;	tty->driver_data = info = rp_table[line];		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 (rp_table[line] == NULL) {		tty->flags = (1 << TTY_IO_ERROR);		free_page(page);		return 0;	}	if (!info) {		printk("rp_open: rp_table[%d] is NULL!\n", line);		free_page(page);		return -EIO;	}	if (info->xmit_buf)		free_page(page);	else		info->xmit_buf = (unsigned char *) page;	info->tty = tty;	if (info->flags & ROCKET_CLOSING) {		interruptible_sleep_on(&info->close_wait);		return ((info->flags & ROCKET_HUP_NOTIFY) ? 			-EAGAIN : -ERESTARTSYS);	}	if (info->count++ == 0) {#ifdef MODULE		MOD_INC_USE_COUNT;#endif

⌨️ 快捷键说明

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