icom.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,703 行 · 第 1/3 页

C
1,703
字号
		temp = readl(int_mask_tbl[port].global_int_mask);		writel(temp & ~int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask);		/* write flush */		readl(int_mask_tbl[port].global_int_mask);	} else {		dev_err(&icom_port->adapter->pci_dev->dev,                        "Invalid port assignment\n");	}	spin_unlock_irqrestore(&icom_lock, flags);	return 0;}static void shutdown(struct icom_port *icom_port){	unsigned long temp;	unsigned char cmdReg;	unsigned long flags;	int port;	spin_lock_irqsave(&icom_lock, flags);	trace(icom_port, "SHUTDOWN", 0);	/*	 * disable all interrupts	 */	port = icom_port->port;	if (port == 0 || port == 1)		int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask;	else		int_mask_tbl[port].global_int_mask = &icom_port->global_reg->int_mask_2;	if (port < 4) {		temp = readl(int_mask_tbl[port].global_int_mask);		writel(temp | int_mask_tbl[port].processor_id, int_mask_tbl[port].global_int_mask);		/* write flush */		readl(int_mask_tbl[port].global_int_mask);	} else {		dev_err(&icom_port->adapter->pci_dev->dev,                        "Invalid port assignment\n");	}	spin_unlock_irqrestore(&icom_lock, flags);	/*	 * disable break condition	 */	cmdReg = readb(&icom_port->dram->CmdReg);	if ((cmdReg | CMD_SND_BREAK) == CMD_SND_BREAK) {		writeb(cmdReg & ~CMD_SND_BREAK, &icom_port->dram->CmdReg);	}}static int icom_write(struct uart_port *port){	unsigned long data_count;	unsigned char cmdReg;	unsigned long offset;	int temp_tail = port->info->xmit.tail;	trace(ICOM_PORT, "WRITE", 0);	if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) &	    SA_FLAGS_READY_TO_XMIT) {		trace(ICOM_PORT, "WRITE_FULL", 0);		return 0;	}	data_count = 0;	while ((port->info->xmit.head != temp_tail) &&	       (data_count <= XMIT_BUFF_SZ)) {		ICOM_PORT->xmit_buf[data_count++] =		    port->info->xmit.buf[temp_tail];		temp_tail++;		temp_tail &= (UART_XMIT_SIZE - 1);	}	if (data_count) {		ICOM_PORT->statStg->xmit[0].flags =		    cpu_to_le16(SA_FLAGS_READY_TO_XMIT);		ICOM_PORT->statStg->xmit[0].leLength =		    cpu_to_le16(data_count);		offset =		    (unsigned long) &ICOM_PORT->statStg->xmit[0] -		    (unsigned long) ICOM_PORT->statStg;		*ICOM_PORT->xmitRestart =		    cpu_to_le32(ICOM_PORT->statStg_pci + offset);		cmdReg = readb(&ICOM_PORT->dram->CmdReg);		writeb(cmdReg | CMD_XMIT_RCV_ENABLE,		       &ICOM_PORT->dram->CmdReg);		writeb(START_XMIT, &ICOM_PORT->dram->StartXmitCmd);		trace(ICOM_PORT, "WRITE_START", data_count);		/* write flush */		readb(&ICOM_PORT->dram->StartXmitCmd);	}	return data_count;}static inline void check_modem_status(struct icom_port *icom_port){	static char old_status = 0;	char delta_status;	unsigned char status;	spin_lock(&icom_port->uart_port.lock);	/*modem input register */	status = readb(&icom_port->dram->isr);	trace(icom_port, "CHECK_MODEM", status);	delta_status = status ^ old_status;	if (delta_status) {		if (delta_status & ICOM_RI)			icom_port->uart_port.icount.rng++;		if (delta_status & ICOM_DSR)			icom_port->uart_port.icount.dsr++;		if (delta_status & ICOM_DCD)			uart_handle_dcd_change(&icom_port->uart_port,					       delta_status & ICOM_DCD);		if (delta_status & ICOM_CTS)			uart_handle_cts_change(&icom_port->uart_port,					       delta_status & ICOM_CTS);		wake_up_interruptible(&icom_port->uart_port.info->				      delta_msr_wait);		old_status = status;	}	spin_unlock(&icom_port->uart_port.lock);}static void xmit_interrupt(u16 port_int_reg, struct icom_port *icom_port){	unsigned short int count;	int i;	if (port_int_reg & (INT_XMIT_COMPLETED)) {		trace(icom_port, "XMIT_COMPLETE", 0);		/* clear buffer in use bit */		icom_port->statStg->xmit[0].flags &=			cpu_to_le16(~SA_FLAGS_READY_TO_XMIT);		count = (unsigned short int)			cpu_to_le16(icom_port->statStg->xmit[0].leLength);		icom_port->uart_port.icount.tx += count;		for (i=0; i<count &&			!uart_circ_empty(&icom_port->uart_port.info->xmit); i++) {			icom_port->uart_port.info->xmit.tail++;			icom_port->uart_port.info->xmit.tail &=				(UART_XMIT_SIZE - 1);		}		if (!icom_write(&icom_port->uart_port))			/* activate write queue */			uart_write_wakeup(&icom_port->uart_port);	} else		trace(icom_port, "XMIT_DISABLED", 0);}static void recv_interrupt(u16 port_int_reg, struct icom_port *icom_port){	short int count, rcv_buff;	struct tty_struct *tty = icom_port->uart_port.info->tty;	unsigned short int status;	struct uart_icount *icount;	unsigned long offset;	trace(icom_port, "RCV_COMPLETE", 0);	rcv_buff = icom_port->next_rcv;	status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags);	while (status & SA_FL_RCV_DONE) {		trace(icom_port, "FID_STATUS", status);		count = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].leLength);		trace(icom_port, "RCV_COUNT", count);		if (count > (TTY_FLIPBUF_SIZE - tty->flip.count))			count = TTY_FLIPBUF_SIZE - tty->flip.count;		trace(icom_port, "REAL_COUNT", count);		offset =			cpu_to_le32(icom_port->statStg->rcv[rcv_buff].leBuffer) -			icom_port->recv_buf_pci;		memcpy(tty->flip.char_buf_ptr,(unsigned char *)		       ((unsigned long)icom_port->recv_buf + offset), count);		if (count > 0) {			tty->flip.count += count - 1;			tty->flip.char_buf_ptr += count - 1;			memset(tty->flip.flag_buf_ptr, 0, count);			tty->flip.flag_buf_ptr += count - 1;		}		icount = &icom_port->uart_port.icount;		icount->rx += count;		/* Break detect logic */		if ((status & SA_FLAGS_FRAME_ERROR)		    && (tty->flip.char_buf_ptr[0] == 0x00)) {			status &= ~SA_FLAGS_FRAME_ERROR;			status |= SA_FLAGS_BREAK_DET;			trace(icom_port, "BREAK_DET", 0);		}		if (status &		    (SA_FLAGS_BREAK_DET | SA_FLAGS_PARITY_ERROR |		     SA_FLAGS_FRAME_ERROR | SA_FLAGS_OVERRUN)) {			if (status & SA_FLAGS_BREAK_DET)				icount->brk++;			if (status & SA_FLAGS_PARITY_ERROR)				icount->parity++;			if (status & SA_FLAGS_FRAME_ERROR)				icount->frame++;			if (status & SA_FLAGS_OVERRUN)				icount->overrun++;			/*			 * Now check to see if character should be			 * ignored, and mask off conditions which			 * should be ignored.			 */			if (status & icom_port->ignore_status_mask) {				trace(icom_port, "IGNORE_CHAR", 0);				goto ignore_char;			}			status &= icom_port->read_status_mask;			if (status & SA_FLAGS_BREAK_DET) {				*tty->flip.flag_buf_ptr = TTY_BREAK;			} else if (status & SA_FLAGS_PARITY_ERROR) {				trace(icom_port, "PARITY_ERROR", 0);				*tty->flip.flag_buf_ptr = TTY_PARITY;			} else if (status & SA_FLAGS_FRAME_ERROR)				*tty->flip.flag_buf_ptr = TTY_FRAME;			if (status & SA_FLAGS_OVERRUN) {				/*				 * Overrun is special, since it's				 * reported immediately, and doesn't				 * affect the current character				 */				if (tty->flip.count < TTY_FLIPBUF_SIZE) {					tty->flip.count++;					tty->flip.flag_buf_ptr++;					tty->flip.char_buf_ptr++;					*tty->flip.flag_buf_ptr = TTY_OVERRUN;				}			}		}		tty->flip.flag_buf_ptr++;		tty->flip.char_buf_ptr++;		tty->flip.count++;		ignore_char:			icom_port->statStg->rcv[rcv_buff].flags = 0;		icom_port->statStg->rcv[rcv_buff].leLength = 0;		icom_port->statStg->rcv[rcv_buff].WorkingLength =			(unsigned short int) cpu_to_le16(RCV_BUFF_SZ);		rcv_buff++;		if (rcv_buff == NUM_RBUFFS)			rcv_buff = 0;		status = cpu_to_le16(icom_port->statStg->rcv[rcv_buff].flags);	}	icom_port->next_rcv = rcv_buff;	tty_flip_buffer_push(tty);}static void process_interrupt(u16 port_int_reg,			      struct icom_port *icom_port){	spin_lock(&icom_port->uart_port.lock);	trace(icom_port, "INTERRUPT", port_int_reg);	if (port_int_reg & (INT_XMIT_COMPLETED | INT_XMIT_DISABLED))		xmit_interrupt(port_int_reg, icom_port);	if (port_int_reg & INT_RCV_COMPLETED)		recv_interrupt(port_int_reg, icom_port);	spin_unlock(&icom_port->uart_port.lock);}static irqreturn_t icom_interrupt(int irq, void *dev_id,				  struct pt_regs *regs){	unsigned long int_reg;	u32 adapter_interrupts;	u16 port_int_reg;	struct icom_adapter *icom_adapter;	struct icom_port *icom_port;	/* find icom_port for this interrupt */	icom_adapter = (struct icom_adapter *) dev_id;	if ((icom_adapter->version | ADAPTER_V2) == ADAPTER_V2) {		int_reg = icom_adapter->base_addr + 0x8024;		adapter_interrupts = readl((void *) int_reg);		if (adapter_interrupts & 0x00003FFF) {			/* port 2 interrupt,  NOTE:  for all ADAPTER_V2, port 2 will be active */			icom_port = &icom_adapter->port_info[2];			port_int_reg = (u16) adapter_interrupts;			process_interrupt(port_int_reg, icom_port);			check_modem_status(icom_port);		}		if (adapter_interrupts & 0x3FFF0000) {			/* port 3 interrupt */			icom_port = &icom_adapter->port_info[3];			if (icom_port->status == ICOM_PORT_ACTIVE) {				port_int_reg =				    (u16) (adapter_interrupts >> 16);				process_interrupt(port_int_reg, icom_port);				check_modem_status(icom_port);			}		}		/* Clear out any pending interrupts */		writel(adapter_interrupts, (void *) int_reg);		int_reg = icom_adapter->base_addr + 0x8004;	} else {		int_reg = icom_adapter->base_addr + 0x4004;	}	adapter_interrupts = readl((void *) int_reg);	if (adapter_interrupts & 0x00003FFF) {		/* port 0 interrupt, NOTE:  for all adapters, port 0 will be active */		icom_port = &icom_adapter->port_info[0];		port_int_reg = (u16) adapter_interrupts;		process_interrupt(port_int_reg, icom_port);		check_modem_status(icom_port);	}	if (adapter_interrupts & 0x3FFF0000) {		/* port 1 interrupt */		icom_port = &icom_adapter->port_info[1];		if (icom_port->status == ICOM_PORT_ACTIVE) {			port_int_reg = (u16) (adapter_interrupts >> 16);			process_interrupt(port_int_reg, icom_port);			check_modem_status(icom_port);		}	}	/* Clear out any pending interrupts */	writel(adapter_interrupts, (void *) int_reg);	/* flush the write */	adapter_interrupts = readl((void *) int_reg);	return IRQ_HANDLED;}/* * ------------------------------------------------------------------ * Begin serial-core API * ------------------------------------------------------------------ */static unsigned int icom_tx_empty(struct uart_port *port){	int ret;	unsigned long flags;	spin_lock_irqsave(&port->lock, flags);	if (cpu_to_le16(ICOM_PORT->statStg->xmit[0].flags) &	    SA_FLAGS_READY_TO_XMIT)		ret = TIOCSER_TEMT;	else		ret = 0;	spin_unlock_irqrestore(&port->lock, flags);	return ret;}static void icom_set_mctrl(struct uart_port *port, unsigned int mctrl){	unsigned char local_osr;	trace(ICOM_PORT, "SET_MODEM", 0);	local_osr = readb(&ICOM_PORT->dram->osr);	if (mctrl & TIOCM_RTS) {		trace(ICOM_PORT, "RAISE_RTS", 0);		local_osr |= ICOM_RTS;	} else {		trace(ICOM_PORT, "LOWER_RTS", 0);		local_osr &= ~ICOM_RTS;	}	if (mctrl & TIOCM_DTR) {		trace(ICOM_PORT, "RAISE_DTR", 0);		local_osr |= ICOM_DTR;	} else {		trace(ICOM_PORT, "LOWER_DTR", 0);		local_osr &= ~ICOM_DTR;	}	writeb(local_osr, &ICOM_PORT->dram->osr);}static unsigned int icom_get_mctrl(struct uart_port *port){	unsigned char status;	unsigned int result;	trace(ICOM_PORT, "GET_MODEM", 0);	status = readb(&ICOM_PORT->dram->isr);	result = ((status & ICOM_DCD) ? TIOCM_CAR : 0)	    | ((status & ICOM_RI) ? TIOCM_RNG : 0)	    | ((status & ICOM_DSR) ? TIOCM_DSR : 0)	    | ((status & ICOM_CTS) ? TIOCM_CTS : 0);	return result;}static void icom_stop_tx(struct uart_port *port, unsigned int tty_stop){	unsigned char cmdReg;	if (tty_stop) {		trace(ICOM_PORT, "STOP", 0);		cmdReg = readb(&ICOM_PORT->dram->CmdReg);		writeb(cmdReg | CMD_HOLD_XMIT, &ICOM_PORT->dram->CmdReg);	}}static void icom_start_tx(struct uart_port *port, unsigned int tty_start){	unsigned char cmdReg;	trace(ICOM_PORT, "START", 0);	cmdReg = readb(&ICOM_PORT->dram->CmdReg);	if ((cmdReg & CMD_HOLD_XMIT) == CMD_HOLD_XMIT)		writeb(cmdReg & ~CMD_HOLD_XMIT,		       &ICOM_PORT->dram->CmdReg);	icom_write(port);}static void icom_send_xchar(struct uart_port *port, char ch){	unsigned char xdata;	int index;	unsigned long flags;	trace(ICOM_PORT, "SEND_XCHAR", ch);	/* wait .1 sec to send char */	for (index = 0; index < 10; index++) {		spin_lock_irqsave(&port->lock, flags);		xdata = readb(&ICOM_PORT->dram->xchar);		if (xdata == 0x00) {			trace(ICOM_PORT, "QUICK_WRITE", 0);			writeb(ch, &ICOM_PORT->dram->xchar);			/* flush write operation */			xdata = readb(&ICOM_PORT->dram->xchar);			spin_unlock_irqrestore(&port->lock, flags);			break;		}		spin_unlock_irqrestore(&port->lock, flags);		msleep(10);	}}static void icom_stop_rx(struct uart_port *port){	unsigned char cmdReg;	cmdReg = readb(&ICOM_PORT->dram->CmdReg);	writeb(cmdReg & ~CMD_RCV_ENABLE, &ICOM_PORT->dram->CmdReg);}static void icom_enable_ms(struct uart_port *port){	/* no-op */}static void icom_break(struct uart_port *port, int break_state){	unsigned char cmdReg;	unsigned long flags;	spin_lock_irqsave(&port->lock, flags);	trace(ICOM_PORT, "BREAK", 0);	cmdReg = readb(&ICOM_PORT->dram->CmdReg);	if (break_state == -1) {		writeb(cmdReg | CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg);	} else {		writeb(cmdReg & ~CMD_SND_BREAK, &ICOM_PORT->dram->CmdReg);	}	spin_unlock_irqrestore(&port->lock, flags);}static int icom_open(struct uart_port *port){	int retval;	kobject_get(&ICOM_PORT->adapter->kobj);	retval = startup(ICOM_PORT);	if (retval) {		kobject_put(&ICOM_PORT->adapter->kobj);		trace(ICOM_PORT, "STARTUP_ERROR", 0);		return retval;	}	return 0;}static void icom_close(struct uart_port *port){	unsigned char cmdReg;	trace(ICOM_PORT, "CLOSE", 0);	/* stop receiver */	cmdReg = readb(&ICOM_PORT->dram->CmdReg);	writeb(cmdReg & (unsigned char) ~CMD_RCV_ENABLE,	       &ICOM_PORT->dram->CmdReg);	shutdown(ICOM_PORT);	kobject_put(&ICOM_PORT->adapter->kobj);}static void icom_set_termios(struct uart_port *port,			     struct termios *termios,			     struct termios *old_termios){	int baud;	unsigned cflag, iflag;	int bits;	char new_config2;	char new_config3 = 0;	char tmp_byte;	int index;	int rcv_buff, xmit_buff;	unsigned long offset;	unsigned long flags;	spin_lock_irqsave(&port->lock, flags);	trace(ICOM_PORT, "CHANGE_SPEED", 0);	cflag = termios->c_cflag;	iflag = termios->c_iflag;	new_config2 = ICOM_ACFG_DRIVE1;	/* byte size and parity */	switch (cflag & CSIZE) {	case CS5:		/* 5 bits/char */		new_config2 |= ICOM_ACFG_5BPC;

⌨️ 快捷键说明

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