cyclades.c

来自「linux 内核源代码」· C语言 代码 · 共 2,048 行 · 第 1/5 页

C
2,048
字号
		ch_ctrl = &(zfw_ctrl->ch_ctrl[channel]);		buf_ctrl = &(zfw_ctrl->buf_ctrl[channel]);		switch (cmd) {		case C_CM_PR_ERROR:			tty_insert_flip_char(tty, 0, TTY_PARITY);			info->icount.rx++;			special_count++;			break;		case C_CM_FR_ERROR:			tty_insert_flip_char(tty, 0, TTY_FRAME);			info->icount.rx++;			special_count++;			break;		case C_CM_RXBRK:			tty_insert_flip_char(tty, 0, TTY_BREAK);			info->icount.rx++;			special_count++;			break;		case C_CM_MDCD:			info->icount.dcd++;			delta_count++;			if (info->flags & ASYNC_CHECK_CD) {				if ((fw_ver > 241 ? ((u_long) param) :						readl(&ch_ctrl->rs_status)) &						C_RS_DCD) {					wake_up_interruptible(&info->open_wait);				} else {					tty_hangup(info->tty);					wake_up_interruptible(&info->open_wait);					info->flags &= ~ASYNC_NORMAL_ACTIVE;				}			}			break;		case C_CM_MCTS:			info->icount.cts++;			delta_count++;			break;		case C_CM_MRI:			info->icount.rng++;			delta_count++;			break;		case C_CM_MDSR:			info->icount.dsr++;			delta_count++;			break;#ifdef Z_WAKE		case C_CM_IOCTLW:			complete(&info->shutdown_wait);			break;#endif#ifdef CONFIG_CYZ_INTR		case C_CM_RXHIWM:		case C_CM_RXNNDT:		case C_CM_INTBACK2:			/* Reception Interrupt */#ifdef CY_DEBUG_INTERRUPTS			printk(KERN_DEBUG "cyz_interrupt: rcvd intr, card %d, "					"port %ld\n", info->card, channel);#endif			cyz_handle_rx(info, buf_ctrl);			break;		case C_CM_TXBEMPTY:		case C_CM_TXLOWWM:		case C_CM_INTBACK:			/* Transmission Interrupt */#ifdef CY_DEBUG_INTERRUPTS			printk(KERN_DEBUG "cyz_interrupt: xmit intr, card %d, "					"port %ld\n", info->card, channel);#endif			cyz_handle_tx(info, buf_ctrl);			break;#endif				/* CONFIG_CYZ_INTR */		case C_CM_FATAL:			/* should do something with this !!! */			break;		default:			break;		}		if (delta_count)			wake_up_interruptible(&info->delta_msr_wait);		if (special_count)			tty_schedule_flip(tty);	}}#ifdef CONFIG_CYZ_INTRstatic irqreturn_t cyz_interrupt(int irq, void *dev_id){	struct cyclades_card *cinfo = dev_id;	if (unlikely(cinfo == NULL)) {#ifdef CY_DEBUG_INTERRUPTS		printk(KERN_DEBUG "cyz_interrupt: spurious interrupt %d\n",irq);#endif		return IRQ_NONE;	/* spurious interrupt */	}	if (unlikely(!ISZLOADED(*cinfo))) {#ifdef CY_DEBUG_INTERRUPTS		printk(KERN_DEBUG "cyz_interrupt: board not yet loaded "				"(IRQ%d).\n", irq);#endif		return IRQ_NONE;	}	/* Handle the interrupts */	cyz_handle_cmd(cinfo);	return IRQ_HANDLED;}				/* cyz_interrupt */static void cyz_rx_restart(unsigned long arg){	struct cyclades_port *info = (struct cyclades_port *)arg;	struct cyclades_card *card = info->card;	int retval;	__u32 channel = info->line - card->first_line;	unsigned long flags;	spin_lock_irqsave(&card->card_lock, flags);	retval = cyz_issue_cmd(card, channel, C_CM_INTBACK2, 0L);	if (retval != 0) {		printk(KERN_ERR "cyc:cyz_rx_restart retval on ttyC%d was %x\n",			info->line, retval);	}	spin_unlock_irqrestore(&card->card_lock, flags);}#else				/* CONFIG_CYZ_INTR */static void cyz_poll(unsigned long arg){	struct cyclades_card *cinfo;	struct cyclades_port *info;	struct tty_struct *tty;	struct FIRM_ID __iomem *firm_id;	struct ZFW_CTRL __iomem *zfw_ctrl;	struct BOARD_CTRL __iomem *board_ctrl;	struct BUF_CTRL __iomem *buf_ctrl;	unsigned long expires = jiffies + HZ;	unsigned int port, card;	for (card = 0; card < NR_CARDS; card++) {		cinfo = &cy_card[card];		if (!IS_CYC_Z(*cinfo))			continue;		if (!ISZLOADED(*cinfo))			continue;		firm_id = cinfo->base_addr + ID_ADDRESS;		zfw_ctrl = cinfo->base_addr +				(readl(&firm_id->zfwctrl_addr) & 0xfffff);		board_ctrl = &(zfw_ctrl->board_ctrl);	/* Skip first polling cycle to avoid racing conditions with the FW */		if (!cinfo->intr_enabled) {			cinfo->nports = (int)readl(&board_ctrl->n_channel);			cinfo->intr_enabled = 1;			continue;		}		cyz_handle_cmd(cinfo);		for (port = 0; port < cinfo->nports; port++) {			info = &cinfo->ports[port];			tty = info->tty;			buf_ctrl = &(zfw_ctrl->buf_ctrl[port]);			if (!info->throttle)				cyz_handle_rx(info, buf_ctrl);			cyz_handle_tx(info, buf_ctrl);		}		/* poll every 'cyz_polling_cycle' period */		expires = jiffies + cyz_polling_cycle;	}	mod_timer(&cyz_timerlist, expires);}				/* cyz_poll */#endif				/* CONFIG_CYZ_INTR *//********** End of block of Cyclades-Z specific code *********//***********************************************************//* This is called whenever a port becomes active;   interrupts are enabled and DTR & RTS are turned on. */static int startup(struct cyclades_port *info){	struct cyclades_card *card;	unsigned long flags;	int retval = 0;	void __iomem *base_addr;	int chip, channel, index;	unsigned long page;	card = info->card;	channel = info->line - card->first_line;	page = get_zeroed_page(GFP_KERNEL);	if (!page)		return -ENOMEM;	spin_lock_irqsave(&card->card_lock, flags);	if (info->flags & ASYNC_INITIALIZED) {		free_page(page);		goto errout;	}	if (!info->type) {		if (info->tty) {			set_bit(TTY_IO_ERROR, &info->tty->flags);		}		free_page(page);		goto errout;	}	if (info->xmit_buf)		free_page(page);	else		info->xmit_buf = (unsigned char *)page;	spin_unlock_irqrestore(&card->card_lock, flags);	set_line_char(info);	if (!IS_CYC_Z(*card)) {		chip = channel >> 2;		channel &= 0x03;		index = card->bus_index;		base_addr = card->base_addr + (cy_chip_offset[chip] << index);#ifdef CY_DEBUG_OPEN		printk(KERN_DEBUG "cyc startup card %d, chip %d, channel %d, "				"base_addr %p\n",				card, chip, channel, base_addr);#endif		spin_lock_irqsave(&card->card_lock, flags);		cy_writeb(base_addr + (CyCAR << index), (u_char) channel);		cy_writeb(base_addr + (CyRTPR << index),			(info->default_timeout ? info->default_timeout : 0x02));		/* 10ms rx timeout */		cyy_issue_cmd(base_addr, CyCHAN_CTL | CyENB_RCVR | CyENB_XMTR,				index);		cy_writeb(base_addr + (CyCAR << index), (u_char) channel);		cy_writeb(base_addr + (CyMSVR1 << index), CyRTS);		cy_writeb(base_addr + (CyMSVR2 << index), CyDTR);#ifdef CY_DEBUG_DTR		printk(KERN_DEBUG "cyc:startup raising DTR\n");		printk(KERN_DEBUG "     status: 0x%x, 0x%x\n",			readb(base_addr + (CyMSVR1 << index)),			readb(base_addr + (CyMSVR2 << index)));#endif		cy_writeb(base_addr + (CySRER << index),			readb(base_addr + (CySRER << index)) | CyRxData);		info->flags |= ASYNC_INITIALIZED;		if (info->tty) {			clear_bit(TTY_IO_ERROR, &info->tty->flags);		}		info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;		info->breakon = info->breakoff = 0;		memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));		info->idle_stats.in_use =		info->idle_stats.recv_idle =		info->idle_stats.xmit_idle = jiffies;		spin_unlock_irqrestore(&card->card_lock, flags);	} else {		struct FIRM_ID __iomem *firm_id;		struct ZFW_CTRL __iomem *zfw_ctrl;		struct BOARD_CTRL __iomem *board_ctrl;		struct CH_CTRL __iomem *ch_ctrl;		base_addr = card->base_addr;		firm_id = base_addr + ID_ADDRESS;		if (!ISZLOADED(*card)) {			return -ENODEV;		}		zfw_ctrl = card->base_addr +				(readl(&firm_id->zfwctrl_addr) & 0xfffff);		board_ctrl = &zfw_ctrl->board_ctrl;		ch_ctrl = zfw_ctrl->ch_ctrl;#ifdef CY_DEBUG_OPEN		printk(KERN_DEBUG "cyc startup Z card %d, channel %d, "			"base_addr %p\n", card, channel, base_addr);#endif		spin_lock_irqsave(&card->card_lock, flags);		cy_writel(&ch_ctrl[channel].op_mode, C_CH_ENABLE);#ifdef Z_WAKE#ifdef CONFIG_CYZ_INTR		cy_writel(&ch_ctrl[channel].intr_enable,			  C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |			  C_IN_RXNNDT | C_IN_IOCTLW | C_IN_MDCD);#else		cy_writel(&ch_ctrl[channel].intr_enable,			  C_IN_IOCTLW | C_IN_MDCD);#endif				/* CONFIG_CYZ_INTR */#else#ifdef CONFIG_CYZ_INTR		cy_writel(&ch_ctrl[channel].intr_enable,			  C_IN_TXBEMPTY | C_IN_TXLOWWM | C_IN_RXHIWM |			  C_IN_RXNNDT | C_IN_MDCD);#else		cy_writel(&ch_ctrl[channel].intr_enable, C_IN_MDCD);#endif				/* CONFIG_CYZ_INTR */#endif				/* Z_WAKE */		retval = cyz_issue_cmd(card, channel, C_CM_IOCTL, 0L);		if (retval != 0) {			printk(KERN_ERR "cyc:startup(1) retval on ttyC%d was "				"%x\n", info->line, retval);		}		/* Flush RX buffers before raising DTR and RTS */		retval = cyz_issue_cmd(card, channel, C_CM_FLUSH_RX, 0L);		if (retval != 0) {			printk(KERN_ERR "cyc:startup(2) retval on ttyC%d was "				"%x\n", info->line, retval);		}		/* set timeout !!! */		/* set RTS and DTR !!! */		cy_writel(&ch_ctrl[channel].rs_control,			readl(&ch_ctrl[channel].rs_control) | C_RS_RTS |			C_RS_DTR);		retval = cyz_issue_cmd(card, channel, C_CM_IOCTLM, 0L);		if (retval != 0) {			printk(KERN_ERR "cyc:startup(3) retval on ttyC%d was "				"%x\n", info->line, retval);		}#ifdef CY_DEBUG_DTR		printk(KERN_DEBUG "cyc:startup raising Z DTR\n");#endif		/* enable send, recv, modem !!! */		info->flags |= ASYNC_INITIALIZED;		if (info->tty) {			clear_bit(TTY_IO_ERROR, &info->tty->flags);		}		info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;		info->breakon = info->breakoff = 0;		memset((char *)&info->idle_stats, 0, sizeof(info->idle_stats));		info->idle_stats.in_use =		info->idle_stats.recv_idle =		info->idle_stats.xmit_idle = jiffies;		spin_unlock_irqrestore(&card->card_lock, flags);	}#ifdef CY_DEBUG_OPEN	printk(KERN_DEBUG "cyc startup done\n");#endif	return 0;errout:	spin_unlock_irqrestore(&card->card_lock, flags);	return retval;}				/* startup */static void start_xmit(struct cyclades_port *info){	struct cyclades_card *card;	unsigned long flags;	void __iomem *base_addr;	int chip, channel, index;	card = info->card;	channel = info->line - card->first_line;	if (!IS_CYC_Z(*card)) {		chip = channel >> 2;		channel &= 0x03;		index = card->bus_index;		base_addr = card->base_addr + (cy_chip_offset[chip] << index);		spin_lock_irqsave(&card->card_lock, flags);		cy_writeb(base_addr + (CyCAR << index), channel);		cy_writeb(base_addr + (CySRER << index),			readb(base_addr + (CySRER << index)) | CyTxRdy);		spin_unlock_irqrestore(&card->card_lock, flags);	} else {#ifdef CONFIG_CYZ_INTR		int retval;		spin_lock_irqsave(&card->card_lock, flags);		retval = cyz_issue_cmd(card, channel, C_CM_INTBACK, 0L);		if (retval != 0) {			printk(KERN_ERR "cyc:start_xmit retval on ttyC%d was "				"%x\n", info->line, retval);		}		spin_unlock_irqrestore(&card->card_lock, flags);#else				/* CONFIG_CYZ_INTR */		/* Don't have 

⌨️ 快捷键说明

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