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

📄 esp.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	       info->irq);#endif		spin_lock_irqsave(&info->lock, flags);	/*	 * clear delta_msr_wait queue to avoid mem leaks: we may free the irq	 * here so the queue might never be waken up	 */	wake_up_interruptible(&info->delta_msr_wait);	wake_up_interruptible(&info->break_wait);	/* stop a DMA transfer on the port being closed */	/* DMA lock is higher priority always */	if (info->stat_flags & (ESP_STAT_DMA_RX | ESP_STAT_DMA_TX)) {		f=claim_dma_lock();		disable_dma(dma);		clear_dma_ff(dma);		release_dma_lock(f);				dma_bytes = 0;	}		/*	 * Free the IRQ	 */	free_irq(info->irq, info);	if (dma_buffer) {		struct esp_struct *current_port = ports;		while (current_port) {			if ((current_port != info) &&			    (current_port->flags & ASYNC_INITIALIZED))				break;			current_port = current_port->next_port;		}		if (!current_port) {			free_dma(dma);			free_pages((unsigned long)dma_buffer,				   get_order(DMA_BUFFER_SZ));			dma_buffer = NULL;		}			}	if (info->xmit_buf) {		free_page((unsigned long) info->xmit_buf);		info->xmit_buf = NULL;	}	info->IER = 0;	serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);	serial_out(info, UART_ESI_CMD2, 0x00);	if (!info->tty || (info->tty->termios->c_cflag & HUPCL))		info->MCR &= ~(UART_MCR_DTR|UART_MCR_RTS);	info->MCR &= ~UART_MCR_OUT2;	serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);	serial_out(info, UART_ESI_CMD2, UART_MCR);	serial_out(info, UART_ESI_CMD2, info->MCR);	if (info->tty)		set_bit(TTY_IO_ERROR, &info->tty->flags);		info->flags &= ~ASYNC_INITIALIZED;	spin_unlock_irqrestore(&info->lock, 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 esp_struct *info){	unsigned short port;	int	quot = 0;	unsigned cflag,cval;	int	baud, bits;	unsigned char flow1 = 0, flow2 = 0;	unsigned long flags;	if (!info->tty || !info->tty->termios)		return;	cflag = info->tty->termios->c_cflag;	port = info->port;		/* byte size and parity */	switch (cflag & CSIZE) {	      case CS5: cval = 0x00; bits = 7; break;	      case CS6: cval = 0x01; bits = 8; break;	      case CS7: cval = 0x02; bits = 9; break;	      case CS8: cval = 0x03; bits = 10; break;	      default:  cval = 0x00; bits = 7; break;	}	if (cflag & CSTOPB) {		cval |= 0x04;		bits++;	}	if (cflag & PARENB) {		cval |= UART_LCR_PARITY;		bits++;	}	if (!(cflag & PARODD))		cval |= UART_LCR_EPAR;#ifdef CMSPAR	if (cflag & CMSPAR)		cval |= UART_LCR_SPAR;#endif	baud = tty_get_baud_rate(info->tty);	if (baud == 38400 &&	    ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))		quot = info->custom_divisor;	else {		if (baud == 134)			/* Special case since 134 is really 134.5 */			quot = (2*BASE_BAUD / 269);		else if (baud)			quot = BASE_BAUD / baud;	}	/* If the quotient is ever zero, default to 9600 bps */	if (!quot)		quot = BASE_BAUD / 9600;		info->timeout = ((1024 * HZ * bits * quot) / BASE_BAUD) + (HZ / 50);	/* CTS flow control flag and modem status interrupts */	/* info->IER &= ~UART_IER_MSI; */	if (cflag & CRTSCTS) {		info->flags |= ASYNC_CTS_FLOW;		/* info->IER |= UART_IER_MSI; */		flow1 = 0x04;		flow2 = 0x10;	} else		info->flags &= ~ASYNC_CTS_FLOW;	if (cflag & CLOCAL)		info->flags &= ~ASYNC_CHECK_CD;	else {		info->flags |= ASYNC_CHECK_CD;		/* info->IER |= UART_IER_MSI; */	}	/*	 * Set up parity check flag	 */	info->read_status_mask = UART_LSR_OE | UART_LSR_THRE | UART_LSR_DR;	if (I_INPCK(info->tty))		info->read_status_mask |= UART_LSR_FE | UART_LSR_PE;	if (I_BRKINT(info->tty) || I_PARMRK(info->tty))		info->read_status_mask |= UART_LSR_BI;		info->ignore_status_mask = 0;#if 0	/* This should be safe, but for some broken bits of hardware... */	if (I_IGNPAR(info->tty)) {		info->ignore_status_mask |= UART_LSR_PE | UART_LSR_FE;		info->read_status_mask |= UART_LSR_PE | UART_LSR_FE;	}#endif	if (I_IGNBRK(info->tty)) {		info->ignore_status_mask |= UART_LSR_BI;		info->read_status_mask |= UART_LSR_BI;		/*		 * If we're ignore parity and break indicators, ignore 		 * overruns too.  (For real raw support).		 */		if (I_IGNPAR(info->tty)) {			info->ignore_status_mask |= UART_LSR_OE | \				UART_LSR_PE | UART_LSR_FE;			info->read_status_mask |= UART_LSR_OE | \				UART_LSR_PE | UART_LSR_FE;		}	}	if (I_IXOFF(info->tty))		flow1 |= 0x81;	spin_lock_irqsave(&info->lock, flags);	/* set baud */	serial_out(info, UART_ESI_CMD1, ESI_SET_BAUD);	serial_out(info, UART_ESI_CMD2, quot >> 8);	serial_out(info, UART_ESI_CMD2, quot & 0xff);	/* set data bits, parity, etc. */	serial_out(info, UART_ESI_CMD1, ESI_WRITE_UART);	serial_out(info, UART_ESI_CMD2, UART_LCR);	serial_out(info, UART_ESI_CMD2, cval);	/* Enable flow control */	serial_out(info, UART_ESI_CMD1, ESI_SET_FLOW_CNTL);	serial_out(info, UART_ESI_CMD2, flow1);	serial_out(info, UART_ESI_CMD2, flow2);	/* set flow control characters (XON/XOFF only) */	if (I_IXOFF(info->tty)) {		serial_out(info, UART_ESI_CMD1, ESI_SET_FLOW_CHARS);		serial_out(info, UART_ESI_CMD2, START_CHAR(info->tty));		serial_out(info, UART_ESI_CMD2, STOP_CHAR(info->tty));		serial_out(info, UART_ESI_CMD2, 0x10);		serial_out(info, UART_ESI_CMD2, 0x21);		switch (cflag & CSIZE) {			case CS5:				serial_out(info, UART_ESI_CMD2, 0x1f);				break;			case CS6:				serial_out(info, UART_ESI_CMD2, 0x3f);				break;			case CS7:			case CS8:				serial_out(info, UART_ESI_CMD2, 0x7f);				break;			default:				serial_out(info, UART_ESI_CMD2, 0xff);				break;		}	}	/* Set high/low water */	serial_out(info, UART_ESI_CMD1, ESI_SET_FLOW_LVL);	serial_out(info, UART_ESI_CMD2, info->config.flow_off >> 8);	serial_out(info, UART_ESI_CMD2, info->config.flow_off);	serial_out(info, UART_ESI_CMD2, info->config.flow_on >> 8);	serial_out(info, UART_ESI_CMD2, info->config.flow_on);	spin_unlock_irqrestore(&info->lock, flags);}static void rs_put_char(struct tty_struct *tty, unsigned char ch){	struct esp_struct *info = (struct esp_struct *)tty->driver_data;	unsigned long flags;	if (serial_paranoia_check(info, tty->name, "rs_put_char"))		return;	if (!info->xmit_buf)		return;	spin_lock_irqsave(&info->lock, flags);	if (info->xmit_cnt < ESP_XMIT_SIZE - 1) {		info->xmit_buf[info->xmit_head++] = ch;		info->xmit_head &= ESP_XMIT_SIZE-1;		info->xmit_cnt++;	}	spin_unlock_irqrestore(&info->lock, flags);}static void rs_flush_chars(struct tty_struct *tty){	struct esp_struct *info = (struct esp_struct *)tty->driver_data;	unsigned long flags;					if (serial_paranoia_check(info, tty->name, "rs_flush_chars"))		return;	spin_lock_irqsave(&info->lock, flags);	if (info->xmit_cnt <= 0 || tty->stopped || !info->xmit_buf)		goto out;	if (!(info->IER & UART_IER_THRI)) {		info->IER |= UART_IER_THRI;		serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);		serial_out(info, UART_ESI_CMD2, info->IER);	}out:	spin_unlock_irqrestore(&info->lock, flags);}static int rs_write(struct tty_struct * tty,		    const unsigned char *buf, int count){	int	c, t, ret = 0;	struct esp_struct *info = (struct esp_struct *)tty->driver_data;	unsigned long flags;	if (serial_paranoia_check(info, tty->name, "rs_write"))		return 0;	if (!info->xmit_buf)		return 0;	    	while (1) {		/* Thanks to R. Wolff for suggesting how to do this with */		/* interrupts enabled */		c = count;		t = ESP_XMIT_SIZE - info->xmit_cnt - 1;				if (t < c)			c = t;		t = ESP_XMIT_SIZE - info->xmit_head;				if (t < c)			c = t;		if (c <= 0)			break;		memcpy(info->xmit_buf + info->xmit_head, buf, c);		info->xmit_head = (info->xmit_head + c) & (ESP_XMIT_SIZE-1);		info->xmit_cnt += c;		buf += c;		count -= c;		ret += c;	}	spin_lock_irqsave(&info->lock, flags);	if (info->xmit_cnt && !tty->stopped && !(info->IER & UART_IER_THRI)) {		info->IER |= UART_IER_THRI;		serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);		serial_out(info, UART_ESI_CMD2, info->IER);	}	spin_unlock_irqrestore(&info->lock, flags);	return ret;}static int rs_write_room(struct tty_struct *tty){	struct esp_struct *info = (struct esp_struct *)tty->driver_data;	int	ret;	unsigned long flags;					if (serial_paranoia_check(info, tty->name, "rs_write_room"))		return 0;	spin_lock_irqsave(&info->lock, flags);	ret = ESP_XMIT_SIZE - info->xmit_cnt - 1;	if (ret < 0)		ret = 0;	spin_unlock_irqrestore(&info->lock, flags);	return ret;}static int rs_chars_in_buffer(struct tty_struct *tty){	struct esp_struct *info = (struct esp_struct *)tty->driver_data;					if (serial_paranoia_check(info, tty->name, "rs_chars_in_buffer"))		return 0;	return info->xmit_cnt;}static void rs_flush_buffer(struct tty_struct *tty){	struct esp_struct *info = (struct esp_struct *)tty->driver_data;	unsigned long flags;					if (serial_paranoia_check(info, tty->name, "rs_flush_buffer"))		return;	spin_lock_irqsave(&info->lock, flags);	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;	spin_unlock_irqrestore(&info->lock, flags);	tty_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 esp_struct *info = (struct esp_struct *)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->name, "rs_throttle"))		return;	spin_lock_irqsave(&info->lock, flags);	info->IER &= ~UART_IER_RDI;	serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);	serial_out(info, UART_ESI_CMD2, info->IER);	serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT);	serial_out(info, UART_ESI_CMD2, 0x00);	spin_unlock_irqrestore(&info->lock, flags);}static void rs_unthrottle(struct tty_struct * tty){	struct esp_struct *info = (struct esp_struct *)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->name, "rs_unthrottle"))		return;		spin_lock_irqsave(&info->lock, flags);	info->IER |= UART_IER_RDI;	serial_out(info, UART_ESI_CMD1, ESI_SET_SRV_MASK);	serial_out(info, UART_ESI_CMD2, info->IER);	serial_out(info, UART_ESI_CMD1, ESI_SET_RX_TIMEOUT);	serial_out(info, UART_ESI_CMD2, info->config.rx_timeout);	spin_unlock_irqrestore(&info->lock, flags);}/* * ------------------------------------------------------------ * rs_ioctl() and friends * ------------------------------------------------------------ */static int get_serial_info(struct esp_struct * info,			   struct serial_struct __user *retinfo){	struct serial_struct tmp;  	memset(&tmp, 0, sizeof(tmp));	tmp.type = PORT_16550A;	tmp.line = info->line;	tmp.port = info->port;	tmp.irq = info->irq;	tmp.flags = info->flags;	tmp.xmit_fifo_size = 1024;	tmp.baud_base = BASE_BAUD;	tmp.close_delay = info->close_delay;	tmp.closing_wait = info->closing_wait;	tmp.custom_divisor = info->custom_divisor;	tmp.hub6 = 0;	if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))		return -EFAULT;	return 0;}static int get_esp_config(struct esp_struct * info,			  struct hayes_esp_config __user *retinfo){	struct hayes_esp_config tmp;  	if (!retinfo)		return -EFAULT;	memset(&tmp, 0, sizeof(tmp));	tmp.rx_timeout = info->config.rx_timeout;	tmp.rx_trigger = info->config.rx_trigger;	tmp.tx_trigger = info->config.tx_trigger;	tmp.flow_off = info->config.flow_off;	tmp.flow_on = info->config.flow_on;	tmp.pio_threshold = info->config.pio_threshold;	tmp.dma_channel = (info->stat_flags & ESP_STAT_NEVER_DMA ? 0 : dma);	return copy_to_user(retinfo, &tmp, sizeof(*retinfo)) ? -EFAULT : 0;}static int set_serial_info(struct esp_struct * info,			   struct serial_struct __user *new_info){	struct serial_struct new_serial;	struct esp_struct old_info;	unsigned int change_irq;	int retval = 0;	struct esp_struct *current_async;	if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))		return -EFAULT;	old_info = *info;	if ((new_serial.type != PORT_16550A) ||	    (new_serial.hub6) ||	    (info->port != new_serial.port) ||	    (new_serial.baud_base != BASE_BAUD) ||	    (new_serial.irq > 15) ||	    (new_serial.irq < 2) ||	    (new_serial.irq == 6) ||	    (new_serial.irq == 8) ||	    (new_serial.irq == 13))		return -EINVAL;

⌨️ 快捷键说明

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