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

📄 mac_scc.c

📁 powerpc内核mpc8241linux系统下char驱动程序
💻 C
📖 第 1 页 / 共 3 页
字号:
	else		shift = 0;	/* Channel B */	for (;;) {		zs_intreg = read_zsreg(info->private->zs_chan_a, 3);#ifdef SCC_DEBUG		printk("mac_SCC: status %x shift %d shifted %x \n", 		zs_intreg, shift, zs_intreg >> shift);#endif		zs_intreg = zs_intreg >> shift;		if ((zs_intreg & CHAN_IRQMASK) == 0)			break;		if (zs_intreg & CHBRxIP)			receive_chars(info, regs);		if (zs_intreg & CHBTxIP)			transmit_chars(info);		if (zs_intreg & CHBEXT)			status_handle(info);	}}/* * ------------------------------------------------------------------- * Here ends the serial interrupt routines. * ------------------------------------------------------------------- *//* * ------------------------------------------------------------ * rs_stop() and rs_start() * * This routines are called before setting or resetting tty->stopped. * ------------------------------------------------------------ */static void SCC_enab_tx_int( struct m68k_async_struct *info, int enab_flag ){	unsigned long flags;	if (enab_flag) {#if 0		save_flags(flags); cli();		if (info->private->curregs[5] & TxENAB) {			info->private->curregs[5] &= ~TxENAB;			info->private->pendregs[5] &= ~TxENAB;			write_zsreg(info->private->zs_channel, 5, 				    info->private->curregs[5]);		}		restore_flags(flags);#endif	/* FIXME: should call transmit_chars here ??? */		transmit_chars(info);	} else {	save_flags(flags); cli();#if 0		if (  info->xmit_cnt && info->xmit_buf && 		    !(info->private->curregs[5] & TxENAB)) {			info->private->curregs[5] |= TxENAB;			info->private->pendregs[5] = info->private->curregs[5];			write_zsreg(info->private->zs_channel, 5, 				    info->private->curregs[5]);		}#else		if ( info->xmit_cnt && info->xmit_buf && 		    !info->private->tx_active) {			transmit_chars(info);		}#endif		restore_flags(flags);		}}#if 0/* * leftover from original driver ... */static int SCC_startup(struct m68k_async_struct * info){	unsigned long flags;	save_flags(flags); cli();#ifdef SERIAL_DEBUG_OPEN	printk("starting up ttyS%d (irq %d)...", info->line, info->irq);#endif	/*	 * Clear the receive FIFO.	 */	ZS_CLEARFIFO(info->private->zs_channel);	info->xmit_fifo_size = 1;	/*	 * Clear the interrupt registers.	 */	write_zsreg(info->private->zs_channel, 0, ERR_RES);	write_zsreg(info->private->zs_channel, 0, RES_H_IUS);	/*	 * Turn on RTS and DTR.	 */	zs_rtsdtr(info, 1);	/*	 * Finally, enable sequencing and interrupts	 */	info->private->curregs[1] = (info->private->curregs[1] & ~0x18) 				    | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);	info->private->pendregs[1] = info->private->curregs[1];	info->private->curregs[3] |= (RxENABLE | Rx8);	info->private->pendregs[3] = info->private->curregs[3];	info->private->curregs[5] |= (TxENAB | Tx8);	info->private->pendregs[5] = info->private->curregs[5];	info->private->curregs[9] |= (NV | MIE);	info->private->pendregs[9] = info->private->curregs[9];	write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]);	write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);	write_zsreg(info->private->zs_channel, 9, info->private->curregs[9]);	/*	 * Set the speed of the serial port	 */	SCC_change_speed(info);	/* Save the current value of RR0 */	info->private->read_reg_zero = read_zsreg(info->private->zs_channel, 0);	restore_flags(flags);	return 0;}#endif/* FIXME: are these required ?? */static int SCC_check_open( struct m68k_async_struct *info, struct tty_struct *tty,			  struct file *file ){	/* check on the basis of info->whatever ?? */	if (info->private->kgdb_channel || info->private->is_cons)		return -EBUSY;	return( 0 );}static void SCC_init( struct m68k_async_struct *info ){	/* FIXME: init currently done in probe_sccs() */	/* BUT: startup part needs to be done here! */#ifdef SCC_DEBUG	printk("mac_SCC: init, info %lx, info->port %lx  \n", info, info->port);#endif	/*	 * Clear the receive FIFO.	 */	ZS_CLEARFIFO(info->private->zs_channel);	info->xmit_fifo_size = 1;	/*	 * Clear the interrupt registers.	 */	write_zsreg(info->private->zs_channel, 0, ERR_RES);	write_zsreg(info->private->zs_channel, 0, RES_H_IUS);	/*	 * Turn on RTS and DTR.	 */	zs_rtsdtr(info, 1);	/*	 * Finally, enable sequencing and interrupts	 */	info->private->curregs[1] = (info->private->curregs[1] & ~0x18) 				    | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);	info->private->pendregs[1] = info->private->curregs[1];	info->private->curregs[3] |= (RxENABLE | Rx8);	info->private->pendregs[3] = info->private->curregs[3];	info->private->curregs[5] |= (TxENAB | Tx8);	info->private->pendregs[5] = info->private->curregs[5];	info->private->curregs[9] |= (NV | MIE);	info->private->pendregs[9] = info->private->curregs[9];	write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]);	write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);	write_zsreg(info->private->zs_channel, 9, info->private->curregs[9]);	/*	 * Set the speed of the serial port - done in startup() !!	 */#if 0	SCC_change_speed(info);#endif	/* Save the current value of RR0 */	info->private->read_reg_zero = read_zsreg(info->private->zs_channel, 0);}static void SCC_init_port( struct m68k_async_struct *info, int type, int channel ){	static int got_autovector = 0;#ifdef SCC_DEBUG	printk("mac_SCC: init_port, info %x \n", info);#endif	info->sw = &SCC_switch;	info->private = &zs_soft_private[channel];	info->private->zs_channel = &zs_channels[channel];	info->irq = IRQ4;	info->private->clk_divisor = 16;	info->private->zs_baud = get_zsbaud(info);	info->port = (int) info->private->zs_channel->control;	/*	 * MSch: Extended interrupt scheme:	 * The generic m68k interrupt code can't use multiple handlers for	 * the same interrupt source (no chained interrupts).	 * We have to plug in a 'master' interrupt handler instead, calling 	 * mac_SCC_interrupt with the proper arguments ...	 */	if (!got_autovector) {		if(sys_request_irq(IRQ4, mac_SCC_handler, 0, "SCC master", info))			panic("macserial: can't get irq %d", IRQ4);#ifdef SCC_DEBUG		printk("mac_SCC: got SCC master interrupt %d, channel %d info %p\n",			IRQ4, channel, info);#endif		got_autovector = 1;	}	if (info->private->zs_chan_a == info->private->zs_channel) {		/* Channel A */		if (request_irq(IRQ_SCCA, mac_SCC_interrupt, 0, "SCC A", info))			panic("mac_SCC: can't get irq %d", IRQ_SCCA);#ifdef SCC_DEBUG		printk("mac_SCC: got SCC A interrupt %d, channel %d info %p\n",			IRQ_SCCA, channel, info);#endif	} else {		/* Channel B */		if (request_irq(IRQ_SCCB, mac_SCC_interrupt, 0, "SCC B", info))			panic("mac_SCC: can't get irq %d", IRQ_SCCB);#ifdef SCC_DEBUG		printk("mac_SCC: got SCC B interrupt %d, channel %d info %p\n", 			IRQ_SCCB, channel, info);#endif	}	/* If console serial line, then enable interrupts. */	if (info->private->is_cons) {		printk("mac_SCC: console line %d; enabling interrupt!\n", info->line);		write_zsreg(info->private->zs_channel, R1,			    (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB));		write_zsreg(info->private->zs_channel, R9, (NV | MIE));		write_zsreg(info->private->zs_channel, R10, (NRZ));		write_zsreg(info->private->zs_channel, R3, (Rx8 | RxENABLE));		write_zsreg(info->private->zs_channel, R5, (Tx8 | TxENAB));	}	/* If this is the kgdb line, enable interrupts because we	 * now want to receive the 'control-c' character from the	 * client attached to us asynchronously.	 */	if (info->private->kgdb_channel) {		printk("mac_SCC: kgdb line %d; enabling interrupt!\n", info->line);		kgdb_chaninit(info, 1, info->private->zs_baud);	}	/* Report settings (in m68kserial.c) */#ifndef CONFIG_MAC	printk("ttyS%d at 0x%08x (irq = %d)", info->line, 		       info->port, info->irq);	printk(" is a Z8530 SCC\n");#endif}/* * This routine will shutdown a serial port; interrupts are disabled, and * DTR is dropped if the hangup on close termio flag is on. */static void SCC_deinit(struct m68k_async_struct * info, int leave_dtr){	unsigned long	flags;	save_flags(flags); cli(); /* Disable interrupts */		info->private->pendregs[1] = info->private->curregs[1] = 0;	write_zsreg(info->private->zs_channel, 1, 0);	/* no interrupts */	info->private->curregs[3] &= ~RxENABLE;	info->private->pendregs[3] = info->private->curregs[3];	write_zsreg(info->private->zs_channel, 3, info->private->curregs[3]);	info->private->curregs[5] &= ~TxENAB;	if (!leave_dtr)		info->private->curregs[5] &= ~(DTR | RTS);	else		info->private->curregs[5] &= ~(RTS);	info->private->pendregs[5] = info->private->curregs[5];	write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);	restore_flags(flags);}/* FIXME !!! */static int SCC_check_custom_divisor( struct m68k_async_struct *info,				    int baud_base, int divisor ){	return 0;}/* * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */static void SCC_change_speed(struct m68k_async_struct *info){	unsigned short port;	unsigned cflag;	int	i;	int	brg;	unsigned long flags;	if (!info->tty || !info->tty->termios)		return;	cflag = info->tty->termios->c_cflag;	if (!(port = info->port))		return;	i = cflag & CBAUD;	if (i == 0 && !(info->flags & ASYNC_SPD_MASK)) {		/* speed == 0 -> drop DTR */		save_flags(flags);		cli();		info->private->curregs[5] &= ~(DTR | RTS);		write_zsreg(info->private->zs_channel, 5, info->private->curregs[5]);		restore_flags(flags);		return;	}	if (i & CBAUDEX) {		/* XXX CBAUDEX is not obeyed.		 * It is impossible at a 32bits PPC.  XXX??		 * But we have to report this to user ... someday.		 */		i = B9600;	}	save_flags(flags); cli();	info->private->zs_baud = baud_table[i];	info->private->clk_divisor = 16;	info->private->curregs[4] = X16CLK;	info->private->curregs[11] = TCBR | RCBR;	brg = BPS_TO_BRG(info->private->zs_baud, 			 ZS_CLOCK/info->private->clk_divisor);	info->private->curregs[12] = (brg & 255);	info->private->curregs[13] = ((brg >> 8) & 255);	info->private->curregs[14] = BRENABL;	/* byte size and parity */	info->private->curregs[3] &= ~RxNBITS_MASK;	info->private->curregs[5] &= ~TxNBITS_MASK;	switch (cflag & CSIZE) {	case CS5:		info->private->curregs[3] |= Rx5;		info->private->curregs[5] |= Tx5;		break;	case CS6:		info->private->curregs[3] |= Rx6;		info->private->curregs[5] |= Tx6;		break;	case CS7:		info->private->curregs[3] |= Rx7;		info->private->curregs[5] |= Tx7;		break;	case CS8:	default: /* defaults to 8 bits */		info->private->curregs[3] |= Rx8;		info->private->curregs[5] |= Tx8;		break;	}	info->private->pendregs[3] = info->private->curregs[3];	info->private->pendregs[5] = info->private->curregs[5];	info->private->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);	if (cflag & CSTOPB) {		info->private->curregs[4] |= SB2;	} else {		info->private->curregs[4] |= SB1;	}	if (cflag & PARENB) {		info->private->curregs[4] |= PAR_ENA;	}	if (!(cflag & PARODD)) {		info->private->curregs[4] |= PAR_EVEN;	}	info->private->pendregs[4] = info->private->curregs[4];	info->private->curregs[15] &= ~(DCDIE | CTSIE);	if (!(cflag & CLOCAL)) {		info->private->curregs[15] |= DCDIE;	}	if (cflag & CRTSCTS) {		info->private->curregs[15] |= CTSIE;		if ((read_zsreg(info->private->zs_channel, 0) & CTS) != 0)			info->private->tx_stopped = 1;	} else		info->private->tx_stopped = 0;	info->private->pendregs[15] = info->private->curregs[15];	/* Load up the new values */	load_zsregs(info->private->zs_channel, info->private->curregs);	restore_flags(flags);}/* This is for console output over ttya/ttyb */static void SCC_put_char(char ch){	struct mac_zschannel *chan = zs_conschan;	int loops = 0;	unsigned long flags;	if(!chan)		return;	save_flags(flags); cli();	while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0 && loops < 10000) {		loops++;		udelay(5);	}	write_zsdata(chan, ch);	restore_flags(flags);}/* These are for receiving and sending characters under the kgdb * source level kernel debugger. */void putDebugChar(char kgdb_char){	struct mac_zschannel *chan = zs_kgdbchan;	while ((read_zsreg(chan, 0) & Tx_BUF_EMP) == 0)		udelay(5);	write_zsdata(chan, kgdb_char);}char getDebugChar(void){	struct mac_zschannel *chan = zs_kgdbchan;	while ((read_zsreg(chan, 0) & Rx_CH_AV) == 0)		udelay(5);	return read_zsdata(chan);}/* * Fair output driver allows a process to speak. */static void SCC_fair_output(void){	int left;		/* Output no more than that */	unsigned long flags;	struct m68k_async_struct *info = zs_consinfo;	char c;	if (info == 0) return;	if (info->xmit_buf == 0) return;	save_flags(flags);  cli();	left = info->xmit_cnt;	while (left != 0) {		c = info->xmit_buf[info->xmit_tail];		info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1);		info->xmit_cnt--;		restore_flags(flags);		SCC_put_char(c);		save_flags(flags);  cli();		left = MIN(info->xmit_cnt, left-1);	}	restore_flags(flags);	return;}/* * zs_console_print is registered for printk. */static void zs_console_print(const char *p){	char c;	while ((c = *(p++)) != 0) {		if (c == '\n')			SCC_put_char('\r');		SCC_put_char(c);	}	/* Comment this if you want to have a strict interrupt-driven output */	SCC_fair_output();}/* FIXME: check with SCC_enab_tx_int!! */#if 0

⌨️ 快捷键说明

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