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

📄 macserial.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	 */	if (!info->is_irda)		zs_rtsdtr(info, 1);	/*	 * Finally, enable sequencing and interrupts	 */	if (!info->dma_initted) {		/* interrupt on ext/status changes, all received chars,		   transmit ready */		info->curregs[1] = (info->curregs[1] & ~0x18)				| (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);	} else {		/* interrupt on ext/status changes, W/Req pin is		   receive DMA request */		info->curregs[1] = (info->curregs[1] & ~(0x18 | TxINT_ENAB))				| (EXT_INT_ENAB | WT_RDY_RT | WT_FN_RDYFN);		write_zsreg(info->zs_channel, 1, info->curregs[1]);		/* enable W/Req pin */		info->curregs[1] |= WT_RDY_ENAB;		write_zsreg(info->zs_channel, 1, info->curregs[1]);		/* enable interrupts on transmit ready and receive errors */		info->curregs[1] |= INT_ERR_Rx | TxINT_ENAB;	}	info->pendregs[1] = info->curregs[1];	info->curregs[3] |= (RxENABLE | Rx8);	info->pendregs[3] = info->curregs[3];	info->curregs[5] |= (TxENAB | Tx8);	info->pendregs[5] = info->curregs[5];	info->curregs[9] |= (NV | MIE);	info->pendregs[9] = info->curregs[9];	write_zsreg(info->zs_channel, 3, info->curregs[3]);	write_zsreg(info->zs_channel, 5, info->curregs[5]);	write_zsreg(info->zs_channel, 9, info->curregs[9]);	if (info->tty)		clear_bit(TTY_IO_ERROR, &info->tty->flags);	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;	/*	 * Set the speed of the serial port	 */	change_speed(info, 0);	/* Save the current value of RR0 */	info->read_reg_zero = read_zsreg(info->zs_channel, 0);	restore_flags(flags);	if (info->dma_initted) {		spin_lock_irqsave(&info->rx_dma_lock, flags);		rxdma_start(info, 0);		info->poll_dma_timer.expires = RX_DMA_TIMER;		add_timer(&info->poll_dma_timer);		spin_unlock_irqrestore(&info->rx_dma_lock, flags);	}	return 0;}/* * 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 shutdown(struct mac_serial * info){	OPNDBG("Shutting down serial port %d (irq %d)....\n", info->line,	       info->irq);	if (!(info->flags & ZILOG_INITIALIZED)) {		OPNDBG("(already shutdown)\n");		return;	}	if (info->has_dma) {		del_timer(&info->poll_dma_timer);		dbdma_reset(info->tx_dma);		dbdma_reset(&info->rx->dma);		disable_irq(info->tx_dma_irq);		disable_irq(info->rx_dma_irq);	}	disable_irq(info->irq);	info->pendregs[1] = info->curregs[1] = 0;	write_zsreg(info->zs_channel, 1, 0);	/* no interrupts */	info->curregs[3] &= ~RxENABLE;	info->pendregs[3] = info->curregs[3];	write_zsreg(info->zs_channel, 3, info->curregs[3]);	info->curregs[5] &= ~TxENAB;	if (!info->tty || C_HUPCL(info->tty))		info->curregs[5] &= ~(DTR | RTS);	info->pendregs[5] = info->curregs[5];	write_zsreg(info->zs_channel, 5, info->curregs[5]);	if (info->tty)		set_bit(TTY_IO_ERROR, &info->tty->flags);	set_scc_power(info, 0);	if (info->xmit_buf) {		free_page((unsigned long) info->xmit_buf);		info->xmit_buf = 0;	}	if (info->has_dma && info->dma_priv) {		kfree(info->dma_priv);		info->dma_priv = NULL;		info->dma_initted = 0;	}	memset(info->curregs, 0, sizeof(info->curregs));	memset(info->curregs, 0, sizeof(info->pendregs));	info->flags &= ~ZILOG_INITIALIZED;}/* * Turn power on or off to the SCC and associated stuff * (port drivers, modem, IR port, etc.) * Returns the number of milliseconds we should wait before * trying to use the port. */static int set_scc_power(struct mac_serial * info, int state){	int delay = 0;	if (feature_test(info->dev_node, FEATURE_Serial_enable) < 0)		return 0;	/* don't have serial power control */	/* The timings looks strange but that's the ones MacOS seems	   to use for the internal modem. I think we can use a lot faster	   ones, at least whe not using the modem, this should be tested.	 */	if (state) {		PWRDBG("ttyS%02d: powering up hardware\n", info->line);		if (feature_test(info->dev_node, FEATURE_Serial_enable) == 0) {			feature_set(info->dev_node, FEATURE_Serial_enable);			mdelay(10);			feature_set(info->dev_node, FEATURE_Serial_reset);			mdelay(15);			feature_clear(info->dev_node, FEATURE_Serial_reset);			mdelay(10);		}		if (info->zs_chan_a == info->zs_channel)			feature_set(info->dev_node, FEATURE_Serial_IO_A);		else			feature_set(info->dev_node, FEATURE_Serial_IO_B);		delay = 10;		if (info->is_cobalt_modem){			mdelay(300);			feature_set(info->dev_node, FEATURE_Modem_power);	   		mdelay(5);			feature_clear(info->dev_node, FEATURE_Modem_power);	   		mdelay(10);			feature_set(info->dev_node, FEATURE_Modem_power);			delay = 2500;	/* wait for 2.5s before using */		}#ifdef CONFIG_PMAC_PBOOK		if (info->is_irda)			pmu_enable_irled(1);#endif /* CONFIG_PMAC_PBOOK */	} else {		PWRDBG("ttyS%02d: shutting down hardware\n", info->line);		if (info->is_cobalt_modem) {			PWRDBG("ttyS%02d: shutting down modem\n", info->line);			feature_clear(info->dev_node, FEATURE_Modem_power);			mdelay(10);		}#ifdef CONFIG_PMAC_PBOOK		if (info->is_irda)			pmu_enable_irled(0);#endif /* CONFIG_PMAC_PBOOK */		if (info->zs_chan_a == info->zs_channel && !info->is_irda) {			PWRDBG("ttyS%02d: shutting down SCC channel A\n", info->line);			feature_clear(info->dev_node, FEATURE_Serial_IO_A);		} else if (!info->is_irda) {			PWRDBG("ttyS%02d: shutting down SCC channel B\n", info->line);			feature_clear(info->dev_node, FEATURE_Serial_IO_B);		}		/* XXX for now, shut down SCC core only on powerbooks */		if (is_powerbook		    && !(feature_test(info->dev_node, FEATURE_Serial_IO_A) ||			 feature_test(info->dev_node, FEATURE_Serial_IO_B))) {			PWRDBG("ttyS%02d: shutting down SCC core\n", info->line);			feature_set(info->dev_node, FEATURE_Serial_reset);			mdelay(15);			feature_clear(info->dev_node, FEATURE_Serial_reset);			mdelay(25);			feature_clear(info->dev_node, FEATURE_Serial_enable);			mdelay(5);		}	}	return delay;}static void irda_rts_pulses(struct mac_serial *info, int w){	unsigned long flags;	udelay(w);	save_flags(flags); cli();	write_zsreg(info->zs_channel, 5, Tx8 | TxENAB);	udelay(2);	write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);	udelay(8);	write_zsreg(info->zs_channel, 5, Tx8 | TxENAB);	udelay(4);	write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);	restore_flags(flags);}/* * Set the irda codec on the imac to the specified baud rate. */static void irda_setup(struct mac_serial *info){	int code, speed, t;	unsigned long flags;	speed = info->tty->termios->c_cflag & CBAUD;	if (speed < B2400 || speed > B115200)		return;	code = 0x4d + B115200 - speed;	/* disable serial interrupts and receive DMA */	write_zsreg(info->zs_channel, 1, info->curregs[1] & ~0x9f);	/* wait for transmitter to drain */	t = 10000;	while ((read_zsreg(info->zs_channel, 0) & Tx_BUF_EMP) == 0	       || (read_zsreg(info->zs_channel, 1) & ALL_SNT) == 0) {		if (--t <= 0) {			printk(KERN_ERR "transmitter didn't drain\n");			return;		}		udelay(10);	}	udelay(100);	/* set to 8 bits, no parity, 19200 baud, RTS on, DTR off */	write_zsreg(info->zs_channel, 4, X16CLK | SB1);	write_zsreg(info->zs_channel, 11, TCBR | RCBR);	t = BPS_TO_BRG(19200, ZS_CLOCK/16);	write_zsreg(info->zs_channel, 12, t);	write_zsreg(info->zs_channel, 13, t >> 8);	write_zsreg(info->zs_channel, 14, BRENABL);	write_zsreg(info->zs_channel, 3, Rx8 | RxENABLE);	write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);	/* set TxD low for ~104us and pulse RTS */	udelay(1000);	save_flags(flags); cli();	write_zsdata(info->zs_channel, 0xfe);	irda_rts_pulses(info, 150);	restore_flags(flags);	irda_rts_pulses(info, 180);	irda_rts_pulses(info, 50);	udelay(100);	/* assert DTR, wait 30ms, talk to the chip */	write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS | DTR);	udelay(30000);	while (read_zsreg(info->zs_channel, 0) & Rx_CH_AV)		read_zsdata(info->zs_channel);	write_zsdata(info->zs_channel, 1);	t = 1000;	while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) == 0) {		if (--t <= 0) {			printk(KERN_ERR "irda_setup timed out on 1st byte\n");			goto out;		}		udelay(10);	}	t = read_zsdata(info->zs_channel);	if (t != 4)		printk(KERN_ERR "irda_setup 1st byte = %x\n", t);	write_zsdata(info->zs_channel, code);	t = 1000;	while ((read_zsreg(info->zs_channel, 0) & Rx_CH_AV) == 0) {		if (--t <= 0) {			printk(KERN_ERR "irda_setup timed out on 2nd byte\n");			goto out;		}		udelay(10);	}	t = read_zsdata(info->zs_channel);	if (t != code)		printk(KERN_ERR "irda_setup 2nd byte = %x (%x)\n", t, code);	/* Drop DTR again and do some more RTS pulses */ out:	udelay(100);	write_zsreg(info->zs_channel, 5, Tx8 | TxENAB | RTS);	irda_rts_pulses(info, 80);	/* We should be right to go now.  We assume that load_zsregs	   will get called soon to load up the correct baud rate etc. */	info->curregs[5] = (info->curregs[5] | RTS) & ~DTR;	info->pendregs[5] = info->curregs[5];}/* * This routine is called to set the UART divisor registers to match * the specified baud rate for a serial port. */static void change_speed(struct mac_serial *info, struct termios *old_termios){	unsigned cflag;	int	bits;	int	brg, baud;	unsigned long flags;	if (!info->tty || !info->tty->termios)		return;	cflag = info->tty->termios->c_cflag;	baud = tty_get_baud_rate(info->tty);	if (baud == 0) {		if (old_termios) {			info->tty->termios->c_cflag &= ~CBAUD;			info->tty->termios->c_cflag |= (old_termios->c_cflag & CBAUD);			cflag = info->tty->termios->c_cflag;			baud = tty_get_baud_rate(info->tty);		}		else			baud = info->zs_baud;	}	if (baud > 230400)		baud = 230400;	else if (baud == 0)		baud = 38400;	save_flags(flags); cli();	info->zs_baud = baud;	info->clk_divisor = 16;	BAUDBG(KERN_DEBUG "set speed to %d bds, ", baud);	switch (baud) {	case ZS_CLOCK/16:	/* 230400 */		info->curregs[4] = X16CLK;		info->curregs[11] = 0;		break;	case ZS_CLOCK/32:	/* 115200 */		info->curregs[4] = X32CLK;		info->curregs[11] = 0;		break;	default:		info->curregs[4] = X16CLK;		info->curregs[11] = TCBR | RCBR;		brg = BPS_TO_BRG(baud, ZS_CLOCK/info->clk_divisor);		info->curregs[12] = (brg & 255);		info->curregs[13] = ((brg >> 8) & 255);		info->curregs[14] = BRENABL;	}	/* byte size and parity */	info->curregs[3] &= ~RxNBITS_MASK;	info->curregs[5] &= ~TxNBITS_MASK;	switch (cflag & CSIZE) {	case CS5:		info->curregs[3] |= Rx5;		info->curregs[5] |= Tx5;		BAUDBG("5 bits, ");		bits = 7;		break;	case CS6:		info->curregs[3] |= Rx6;		info->curregs[5] |= Tx6;		BAUDBG("6 bits, ");		bits = 8;		break;	case CS7:		info->curregs[3] |= Rx7;		info->curregs[5] |= Tx7;		BAUDBG("7 bits, ");		bits = 9;		break;	case CS8:	default: /* defaults to 8 bits */		info->curregs[3] |= Rx8;		info->curregs[5] |= Tx8;		BAUDBG("8 bits, ");		bits = 10;		break;	}	info->pendregs[3] = info->curregs[3];	info->pendregs[5] = info->curregs[5];	info->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);	if (cflag & CSTOPB) {		info->curregs[4] |= SB2;		bits++;		BAUDBG("2 stop, ");	} else {		info->curregs[4] |= SB1;		BAUDBG("1 stop, ");	}	if (cflag & PARENB) {		bits++; 		info->curregs[4] |= PAR_ENA;		BAUDBG("parity, ");	}	if (!(cflag & PARODD)) {		info->curregs[4] |= PAR_EVEN;	}	info->pendregs[4] = info->curregs[4];	if (!(cflag & CLOCAL)) {		if (!(info->curregs[15] & DCDIE))			info->read_reg_zero = read_zsreg(info->zs_channel, 0);		info->curregs[15] |= DCDIE;	} else		info->curregs[15] &= ~DCDIE;	if (cflag & CRTSCTS) {		info->curregs[15] |= CTSIE;		if ((read_zsreg(info->zs_channel, 0) & CTS) != 0)			info->tx_stopped = 1;	} else {		info->curregs[15] &= ~CTSIE;		info->tx_stopped = 0;	}	info->pendregs[15] = info->curregs[15];	/* Calc timeout value. This is pretty broken with high baud rates with HZ=100.	   This code would love a larger HZ and a >1 fifo size, but this is not	   a priority. The resulting value must be >HZ/2	 */	info->timeout = ((info->xmit_fifo_size*HZ*bits) / baud);	info->timeout += HZ/50+1;	/* Add .02 seconds of slop */	BAUDBG("timeout=%d/%ds, base:%d\n", (int)info->timeout, (int)HZ,	       (int)info->baud_base);	/* set the irda codec to the right rate */	if (info->is_irda)		irda_setup(info);	/* Load up the new values */	load_zsregs(info->zs_channel, info->curregs);	restore_flags(flags);}static void rs_flush_chars(struct tty_struct *tty){	struct mac_serial *info = (struct mac_serial *)tty->driver_data;	if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))		return;	if (info->xmit_cnt <= 0 || tty->stopped || info->tx_stopped ||	    !info->xmit_buf)		return;	/* Enable transmitter */	transmit_chars(info);}static int rs_write(struct tty_struct * tty, int from_user,		    const unsigned char *buf, int count){	int	c, ret = 0;	struct mac_serial *info = (struct mac_serial *)tty->driver_data;	unsigned long flags;	if (serial_paranoia_check(info, tty->device, "rs_write"))		return 0;	if (!tty || !info->xmit_buf || !tmp_buf)		return 0;	if (from_user) {		down(&tmp_buf_sem);		while (1) {			c = MIN(count,				MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,				    SERIAL_XMIT_SIZE - info->xmit_head));			if (c <= 0)				break;			c -= copy_from_user(tmp_buf, buf, c);			if (!c) {				if (!ret)					ret = -EFAULT;				break;			}			save_flags(flags);			cli();			c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,

⌨️ 快捷键说明

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