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

📄 zs.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 4 页
字号:
		transmit_chars(info);	}#endif	restore_flags(flags);}/* * This routine is used to handle the "bottom half" processing for the * serial driver, known also the "software interrupt" processing. * This processing is done at the kernel interrupt level, after the * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON.  This * is where time-consuming activities which can not be done in the * interrupt driver proper are done; the interrupt driver schedules * them using rs_sched_event(), and they get done here. */static void do_serial_bh(void){	run_task_queue(&tq_zs_serial);}static void do_softint(void *private_){	struct dec_serial	*info = (struct dec_serial *) private_;	struct tty_struct	*tty;		tty = info->tty;	if (!tty)		return;	if (test_and_clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) {		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&		    tty->ldisc.write_wakeup)			(tty->ldisc.write_wakeup)(tty);		wake_up_interruptible(&tty->write_wait);	}}static int startup(struct dec_serial * info){	unsigned long flags;	if (info->flags & ZILOG_INITIALIZED)		return 0;	if (!info->xmit_buf) {		info->xmit_buf = (unsigned char *) get_free_page(GFP_KERNEL);		if (!info->xmit_buf)			return -ENOMEM;	}	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->zs_channel);	info->xmit_fifo_size = 1;	/*	 * Clear the interrupt registers.	 */	write_zsreg(info->zs_channel, 0, ERR_RES);	write_zsreg(info->zs_channel, 0, RES_H_IUS);	/*	 * Turn on RTS and DTR.	 */	zs_rtsdtr(info, 1);	/*	 * Finally, enable sequencing and interrupts	 */	info->zs_channel->curregs[1] = (info->zs_channel->curregs[1] & ~0x18) | (EXT_INT_ENAB | INT_ALL_Rx | TxINT_ENAB);	info->zs_channel->curregs[3] |= (RxENABLE | Rx8);	info->zs_channel->curregs[5] |= (TxENAB | Tx8);	info->zs_channel->curregs[15] |= (DCDIE | CTSIE | TxUIE | BRKIE);	info->zs_channel->curregs[9] |= (VIS | MIE);	write_zsreg(info->zs_channel, 1, info->zs_channel->curregs[1]);	write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]);	write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);	write_zsreg(info->zs_channel, 15, info->zs_channel->curregs[15]);	write_zsreg(info->zs_channel, 9, info->zs_channel->curregs[9]);	/*	 * And clear the interrupt registers again for luck.	 */	write_zsreg(info->zs_channel, 0, ERR_RES);	write_zsreg(info->zs_channel, 0, RES_H_IUS);	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);	/* Save the current value of RR0 */	info->read_reg_zero = read_zsreg(info->zs_channel, 0);	info->flags |= ZILOG_INITIALIZED;	restore_flags(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 dec_serial * info){	unsigned long	flags;	if (!(info->flags & ZILOG_INITIALIZED))		return;#ifdef SERIAL_DEBUG_OPEN	printk("Shutting down serial port %d (irq %d)....", info->line,	       info->irq);#endif		save_flags(flags); cli(); /* Disable interrupts */		if (info->xmit_buf) {		free_page((unsigned long) info->xmit_buf);		info->xmit_buf = 0;	}	info->zs_channel->curregs[1] = 0;	write_zsreg(info->zs_channel, 1, info->zs_channel->curregs[1]);	/* no interrupts */	info->zs_channel->curregs[3] &= ~RxENABLE;	write_zsreg(info->zs_channel, 3, info->zs_channel->curregs[3]);	info->zs_channel->curregs[5] &= ~TxENAB;	write_zsreg(info->zs_channel, 5, info->zs_channel->curregs[5]);	if (!info->tty || C_HUPCL(info->tty)) {		info->zs_chan_a->curregs[5] &= ~(DTR | RTS);		write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);	}	if (info->tty)		set_bit(TTY_IO_ERROR, &info->tty->flags);	info->flags &= ~ZILOG_INITIALIZED;	restore_flags(flags);}/* * 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 dec_serial *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;	save_flags(flags); cli();	info->zs_baud = baud_table[i];	info->clk_divisor = 16;	switch (info->zs_baud) {	default:		info->zs_channel->curregs[4] = X16CLK;		brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor);		info->zs_channel->curregs[12] = (brg & 255);		info->zs_channel->curregs[13] = ((brg >> 8) & 255);	}	/* byte size and parity */	info->zs_channel->curregs[3] &= ~RxNBITS_MASK;	info->zs_channel->curregs[5] &= ~TxNBITS_MASK;	switch (cflag & CSIZE) {	case CS5:		info->zs_channel->curregs[3] |= Rx5;		info->zs_channel->curregs[5] |= Tx5;		break;	case CS6:		info->zs_channel->curregs[3] |= Rx6;		info->zs_channel->curregs[5] |= Tx6;		break;	case CS7:		info->zs_channel->curregs[3] |= Rx7;		info->zs_channel->curregs[5] |= Tx7;		break;	case CS8:	default: /* defaults to 8 bits */		info->zs_channel->curregs[3] |= Rx8;		info->zs_channel->curregs[5] |= Tx8;		break;	}	info->zs_channel->curregs[4] &= ~(SB_MASK | PAR_ENA | PAR_EVEN);	if (cflag & CSTOPB) {		info->zs_channel->curregs[4] |= SB2;	} else {		info->zs_channel->curregs[4] |= SB1;	}	if (cflag & PARENB) {		info->zs_channel->curregs[4] |= PAR_ENA;	}	if (!(cflag & PARODD)) {		info->zs_channel->curregs[4] |= PAR_EVEN;	}	if (!(cflag & CLOCAL)) {		if (!(info->zs_channel->curregs[15] & DCDIE))			info->read_reg_zero = read_zsreg(info->zs_channel, 0);		info->zs_channel->curregs[15] |= DCDIE;	} else		info->zs_channel->curregs[15] &= ~DCDIE;	if (cflag & CRTSCTS) {		info->zs_channel->curregs[15] |= CTSIE;		if ((read_zsreg(info->zs_channel, 0) & CTS) != 0)			info->tx_stopped = 1;	} else {		info->zs_channel->curregs[15] &= ~CTSIE;		info->tx_stopped = 0;	}	/* Load up the new values */	load_zsregs(info->zs_channel, info->zs_channel->curregs);	restore_flags(flags);}static void rs_flush_chars(struct tty_struct *tty){	struct dec_serial *info = (struct dec_serial *)tty->driver_data;	unsigned long flags;	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 */	save_flags(flags); cli();	transmit_chars(info);	restore_flags(flags);}static int rs_write(struct tty_struct * tty, int from_user,		    const unsigned char *buf, int count){	int	c, total = 0;	struct dec_serial *info = (struct dec_serial *)tty->driver_data;	unsigned long flags;	if (serial_paranoia_check(info, tty->device, "rs_write"))		return 0;	if (!tty || !info->xmit_buf)		return 0;	save_flags(flags);	while (1) {		cli();				c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,				   SERIAL_XMIT_SIZE - info->xmit_head));		if (c <= 0)			break;		if (from_user) {			down(&tmp_buf_sem);			copy_from_user(tmp_buf, buf, c);			c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,				       SERIAL_XMIT_SIZE - info->xmit_head));			memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);			up(&tmp_buf_sem);		} else			memcpy(info->xmit_buf + info->xmit_head, buf, c);		info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1);		info->xmit_cnt += c;		restore_flags(flags);		buf += c;		count -= c;		total += c;	}	if (info->xmit_cnt && !tty->stopped && !info->tx_stopped	    && !info->tx_active)		transmit_chars(info);	restore_flags(flags);	return total;}static int rs_write_room(struct tty_struct *tty){	struct dec_serial *info = (struct dec_serial *)tty->driver_data;	int	ret;					if (serial_paranoia_check(info, tty->device, "rs_write_room"))		return 0;	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;	if (ret < 0)		ret = 0;	return ret;}static int rs_chars_in_buffer(struct tty_struct *tty){	struct dec_serial *info = (struct dec_serial *)tty->driver_data;				if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))		return 0;	return info->xmit_cnt;}static void rs_flush_buffer(struct tty_struct *tty){	struct dec_serial *info = (struct dec_serial *)tty->driver_data;					if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))		return;	cli();	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;	sti();	wake_up_interruptible(&tty->write_wait);	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&	    tty->ldisc.write_wakeup)		(tty->ldisc.write_wakeup)(tty);}/* * ------------------------------------------------------------ * rs_throttle() *  * This routine is called by the upper-layer tty layer to signal that * incoming characters should be throttled. * ------------------------------------------------------------ */static void rs_throttle(struct tty_struct * tty){	struct dec_serial *info = (struct dec_serial *)tty->driver_data;	unsigned long flags;#ifdef SERIAL_DEBUG_THROTTLE	char	buf[64];		printk("throttle %s: %d....\n", _tty_name(tty, buf),	       tty->ldisc.chars_in_buffer(tty));#endif	if (serial_paranoia_check(info, tty->device, "rs_throttle"))		return;		if (I_IXOFF(tty)) {		save_flags(flags); cli();		info->x_char = STOP_CHAR(tty);		if (!info->tx_active)			transmit_chars(info);		restore_flags(flags);	}	if (C_CRTSCTS(tty)) {		/*		 * Here we want to turn off the RTS line.  On Macintoshes,		 * we only get the DTR line, which goes to both DTR and		 * RTS on the modem.  RTS doesn't go out to the serial		 * port socket.  So you should make sure your modem is		 * set to ignore DTR if you're using CRTSCTS.		 */		save_flags(flags); cli();		info->zs_chan_a->curregs[5] &= ~(DTR | RTS);		write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);		restore_flags(flags);	}}static void rs_unthrottle(struct tty_struct * tty){	struct dec_serial *info = (struct dec_serial *)tty->driver_data;	unsigned long flags;#ifdef SERIAL_DEBUG_THROTTLE	char	buf[64];		printk("unthrottle %s: %d....\n", _tty_name(tty, buf),	       tty->ldisc.chars_in_buffer(tty));#endif	if (serial_paranoia_check(info, tty->device, "rs_unthrottle"))		return;		if (I_IXOFF(tty)) {		save_flags(flags); cli();		if (info->x_char)			info->x_char = 0;		else {			info->x_char = START_CHAR(tty);			if (!info->tx_active)				transmit_chars(info);		}		restore_flags(flags);	}	if (C_CRTSCTS(tty)) {		/* Assert RTS and DTR lines */		save_flags(flags); cli();		info->zs_chan_a->curregs[5] |= DTR | RTS;		write_zsreg(info->zs_chan_a, 5, info->zs_chan_a->curregs[5]);		restore_flags(flags);	}}/* * ------------------------------------------------------------ * rs_ioctl() and friends * ------------------------------------------------------------ */static int get_serial_info(struct dec_serial * info,			   struct serial_struct * retinfo){	struct serial_struct tmp;	if (!retinfo)		return -EFAULT;	memset(&tmp, 0, sizeof(tmp));	tmp.type = info->type;	tmp.line = info->line;	tmp.port = info->port;	tmp.irq = info->irq;	tmp.flags = info->flags;	tmp.baud_base = info->baud_base;	tmp.close_delay = info->close_delay;	tmp.closing_wait = info->closing_wait;	tmp.custom_divisor = info->custom_divisor;	return copy_to_user(retinfo,&tmp,sizeof(*retinfo));}static int set_serial_info(struct dec_serial * info,			   struct serial_struct * new_info){	struct serial_struct new_serial;	struct dec_serial old_info;	int 			retval = 0;	if (!new_info)		return -EFAULT;	copy_from_user(&new_serial,new_info,sizeof(new_serial));	old_info = *info;	if (!suser()) {		if ((new_serial.baud_base != info->baud_base) ||		    (new_serial.type != info->type) ||		    (new_serial.close_delay != info->close_delay) ||		    ((new_serial.flags & ~ZILOG_USR_MASK) !=		     (info->flags & ~ZILOG_USR_MASK)))			return -EPERM;		info->flags = ((info->flags & ~ZILOG_USR_MASK) |			       (new_serial.flags & ZILOG_USR_MASK));		info->custom_divisor = new_serial.custom_divisor;		goto check_and_exit;	}	if (info->count > 1)		return -EBUSY;	/*	 * OK, past this point, all the error checking has been done.	 * At this point, we start making changes.....	 */	info->baud_base = new_serial.baud_base;	info->flags = ((info->flags & ~ZILOG_FLAGS) |			(new_serial.flags & ZILOG_FLAGS));	info->type = new_serial.type;	info->close_delay = new_serial.close_delay;	info->closing_wait = new_serial.closing_wait;check_and_exit:	retval = startup(info);	return retval;}/* * get_lsr_info - get line status register info * * Purpose: Let user call ioctl() to get info when the UART physically * 	    is emptied.  On bus types like RS485, the transmitter must * 	    release the bus after transmitting. This must be done when * 	    the transmit shift register is empty, not be done when the * 	    transmit holding register is empty.  This functionality * 	    allows an RS485 driver to be written in user space.  */static int get_lsr_info(struct dec_serial * info, unsigned int *value){	unsigned char status;	cli();	status = read_zsreg(info->zs_channel, 0);	sti();	put_user(status,value);	return 0;}static int get_modem_info(struct dec_serial *info, unsigned int *value){	unsigned char control, status;	unsigned int result;	cli();	control = info->zs_chan_a->curregs[5];	status = read_zsreg(info->zs_channel, 0);	sti();

⌨️ 快捷键说明

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