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

📄 synclink_gt.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		info->rbuf_index = 0;		free_rbufs(info, end, end);		if (++end == info->rbuf_count)			end = 0;		/* if entire list searched then no frame available */		if (end == start)			break;	}	if (tty && chars)		tty_flip_buffer_push(tty);}/* * return next bottom half action to perform */static int bh_action(struct slgt_info *info){	unsigned long flags;	int rc;	spin_lock_irqsave(&info->lock,flags);	if (info->pending_bh & BH_RECEIVE) {		info->pending_bh &= ~BH_RECEIVE;		rc = BH_RECEIVE;	} else if (info->pending_bh & BH_TRANSMIT) {		info->pending_bh &= ~BH_TRANSMIT;		rc = BH_TRANSMIT;	} else if (info->pending_bh & BH_STATUS) {		info->pending_bh &= ~BH_STATUS;		rc = BH_STATUS;	} else {		/* Mark BH routine as complete */		info->bh_running   = 0;		info->bh_requested = 0;		rc = 0;	}	spin_unlock_irqrestore(&info->lock,flags);	return rc;}/* * perform bottom half processing */static void bh_handler(struct work_struct *work){	struct slgt_info *info = container_of(work, struct slgt_info, task);	int action;	if (!info)		return;	info->bh_running = 1;	while((action = bh_action(info))) {		switch (action) {		case BH_RECEIVE:			DBGBH(("%s bh receive\n", info->device_name));			switch(info->params.mode) {			case MGSL_MODE_ASYNC:				rx_async(info);				break;			case MGSL_MODE_HDLC:				while(rx_get_frame(info));				break;			case MGSL_MODE_RAW:			case MGSL_MODE_MONOSYNC:			case MGSL_MODE_BISYNC:				while(rx_get_buf(info));				break;			}			/* restart receiver if rx DMA buffers exhausted */			if (info->rx_restart)				rx_start(info);			break;		case BH_TRANSMIT:			bh_transmit(info);			break;		case BH_STATUS:			DBGBH(("%s bh status\n", info->device_name));			info->ri_chkcount = 0;			info->dsr_chkcount = 0;			info->dcd_chkcount = 0;			info->cts_chkcount = 0;			break;		default:			DBGBH(("%s unknown action\n", info->device_name));			break;		}	}	DBGBH(("%s bh_handler exit\n", info->device_name));}static void bh_transmit(struct slgt_info *info){	struct tty_struct *tty = info->tty;	DBGBH(("%s bh_transmit\n", info->device_name));	if (tty)		tty_wakeup(tty);}static void dsr_change(struct slgt_info *info){	get_signals(info);	DBGISR(("dsr_change %s signals=%04X\n", info->device_name, info->signals));	if ((info->dsr_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {		slgt_irq_off(info, IRQ_DSR);		return;	}	info->icount.dsr++;	if (info->signals & SerialSignal_DSR)		info->input_signal_events.dsr_up++;	else		info->input_signal_events.dsr_down++;	wake_up_interruptible(&info->status_event_wait_q);	wake_up_interruptible(&info->event_wait_q);	info->pending_bh |= BH_STATUS;}static void cts_change(struct slgt_info *info){	get_signals(info);	DBGISR(("cts_change %s signals=%04X\n", info->device_name, info->signals));	if ((info->cts_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {		slgt_irq_off(info, IRQ_CTS);		return;	}	info->icount.cts++;	if (info->signals & SerialSignal_CTS)		info->input_signal_events.cts_up++;	else		info->input_signal_events.cts_down++;	wake_up_interruptible(&info->status_event_wait_q);	wake_up_interruptible(&info->event_wait_q);	info->pending_bh |= BH_STATUS;	if (info->flags & ASYNC_CTS_FLOW) {		if (info->tty) {			if (info->tty->hw_stopped) {				if (info->signals & SerialSignal_CTS) {		 			info->tty->hw_stopped = 0;					info->pending_bh |= BH_TRANSMIT;					return;				}			} else {				if (!(info->signals & SerialSignal_CTS))		 			info->tty->hw_stopped = 1;			}		}	}}static void dcd_change(struct slgt_info *info){	get_signals(info);	DBGISR(("dcd_change %s signals=%04X\n", info->device_name, info->signals));	if ((info->dcd_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {		slgt_irq_off(info, IRQ_DCD);		return;	}	info->icount.dcd++;	if (info->signals & SerialSignal_DCD) {		info->input_signal_events.dcd_up++;	} else {		info->input_signal_events.dcd_down++;	}#if SYNCLINK_GENERIC_HDLC	if (info->netcount) {		if (info->signals & SerialSignal_DCD)			netif_carrier_on(info->netdev);		else			netif_carrier_off(info->netdev);	}#endif	wake_up_interruptible(&info->status_event_wait_q);	wake_up_interruptible(&info->event_wait_q);	info->pending_bh |= BH_STATUS;	if (info->flags & ASYNC_CHECK_CD) {		if (info->signals & SerialSignal_DCD)			wake_up_interruptible(&info->open_wait);		else {			if (info->tty)				tty_hangup(info->tty);		}	}}static void ri_change(struct slgt_info *info){	get_signals(info);	DBGISR(("ri_change %s signals=%04X\n", info->device_name, info->signals));	if ((info->ri_chkcount)++ == IO_PIN_SHUTDOWN_LIMIT) {		slgt_irq_off(info, IRQ_RI);		return;	}	info->icount.dcd++;	if (info->signals & SerialSignal_RI) {		info->input_signal_events.ri_up++;	} else {		info->input_signal_events.ri_down++;	}	wake_up_interruptible(&info->status_event_wait_q);	wake_up_interruptible(&info->event_wait_q);	info->pending_bh |= BH_STATUS;}static void isr_serial(struct slgt_info *info){	unsigned short status = rd_reg16(info, SSR);	DBGISR(("%s isr_serial status=%04X\n", info->device_name, status));	wr_reg16(info, SSR, status); /* clear pending */	info->irq_occurred = 1;	if (info->params.mode == MGSL_MODE_ASYNC) {		if (status & IRQ_TXIDLE) {			if (info->tx_count)				isr_txeom(info, status);		}		if ((status & IRQ_RXBREAK) && (status & RXBREAK)) {			info->icount.brk++;			/* process break detection if tty control allows */			if (info->tty) {				if (!(status & info->ignore_status_mask)) {					if (info->read_status_mask & MASK_BREAK) {						tty_insert_flip_char(info->tty, 0, TTY_BREAK);						if (info->flags & ASYNC_SAK)							do_SAK(info->tty);					}				}			}		}	} else {		if (status & (IRQ_TXIDLE + IRQ_TXUNDER))			isr_txeom(info, status);		if (status & IRQ_RXIDLE) {			if (status & RXIDLE)				info->icount.rxidle++;			else				info->icount.exithunt++;			wake_up_interruptible(&info->event_wait_q);		}		if (status & IRQ_RXOVER)			rx_start(info);	}	if (status & IRQ_DSR)		dsr_change(info);	if (status & IRQ_CTS)		cts_change(info);	if (status & IRQ_DCD)		dcd_change(info);	if (status & IRQ_RI)		ri_change(info);}static void isr_rdma(struct slgt_info *info){	unsigned int status = rd_reg32(info, RDCSR);	DBGISR(("%s isr_rdma status=%08x\n", info->device_name, status));	/* RDCSR (rx DMA control/status)	 *	 * 31..07  reserved	 * 06      save status byte to DMA buffer	 * 05      error	 * 04      eol (end of list)	 * 03      eob (end of buffer)	 * 02      IRQ enable	 * 01      reset	 * 00      enable	 */	wr_reg32(info, RDCSR, status);	/* clear pending */	if (status & (BIT5 + BIT4)) {		DBGISR(("%s isr_rdma rx_restart=1\n", info->device_name));		info->rx_restart = 1;	}	info->pending_bh |= BH_RECEIVE;}static void isr_tdma(struct slgt_info *info){	unsigned int status = rd_reg32(info, TDCSR);	DBGISR(("%s isr_tdma status=%08x\n", info->device_name, status));	/* TDCSR (tx DMA control/status)	 *	 * 31..06  reserved	 * 05      error	 * 04      eol (end of list)	 * 03      eob (end of buffer)	 * 02      IRQ enable	 * 01      reset	 * 00      enable	 */	wr_reg32(info, TDCSR, status);	/* clear pending */	if (status & (BIT5 + BIT4 + BIT3)) {		// another transmit buffer has completed		// run bottom half to get more send data from user		info->pending_bh |= BH_TRANSMIT;	}}static void isr_txeom(struct slgt_info *info, unsigned short status){	DBGISR(("%s txeom status=%04x\n", info->device_name, status));	slgt_irq_off(info, IRQ_TXDATA + IRQ_TXIDLE + IRQ_TXUNDER);	tdma_reset(info);	reset_tbufs(info);	if (status & IRQ_TXUNDER) {		unsigned short val = rd_reg16(info, TCR);		wr_reg16(info, TCR, (unsigned short)(val | BIT2)); /* set reset bit */		wr_reg16(info, TCR, val); /* clear reset bit */	}	if (info->tx_active) {		if (info->params.mode != MGSL_MODE_ASYNC) {			if (status & IRQ_TXUNDER)				info->icount.txunder++;			else if (status & IRQ_TXIDLE)				info->icount.txok++;		}		info->tx_active = 0;		info->tx_count = 0;		del_timer(&info->tx_timer);		if (info->params.mode != MGSL_MODE_ASYNC && info->drop_rts_on_tx_done) {			info->signals &= ~SerialSignal_RTS;			info->drop_rts_on_tx_done = 0;			set_signals(info);		}#if SYNCLINK_GENERIC_HDLC		if (info->netcount)			hdlcdev_tx_done(info);		else#endif		{			if (info->tty && (info->tty->stopped || info->tty->hw_stopped)) {				tx_stop(info);				return;			}			info->pending_bh |= BH_TRANSMIT;		}	}}static void isr_gpio(struct slgt_info *info, unsigned int changed, unsigned int state){	struct cond_wait *w, *prev;	/* wake processes waiting for specific transitions */	for (w = info->gpio_wait_q, prev = NULL ; w != NULL ; w = w->next) {		if (w->data & changed) {			w->data = state;			wake_up_interruptible(&w->q);			if (prev != NULL)				prev->next = w->next;			else				info->gpio_wait_q = w->next;		} else			prev = w;	}}/* interrupt service routine * * 	irq	interrupt number * 	dev_id	device ID supplied during interrupt registration */static irqreturn_t slgt_interrupt(int irq, void *dev_id){	struct slgt_info *info;	unsigned int gsr;	unsigned int i;	DBGISR(("slgt_interrupt irq=%d entry\n", irq));	info = dev_id;	if (!info)		return IRQ_NONE;	spin_lock(&info->lock);	while((gsr = rd_reg32(info, GSR) & 0xffffff00)) {		DBGISR(("%s gsr=%08x\n", info->device_name, gsr));		info->irq_occurred = 1;		for(i=0; i < info->port_count ; i++) {			if (info->port_array[i] == NULL)				continue;			if (gsr & (BIT8 << i))				isr_serial(info->port_array[i]);			if (gsr & (BIT16 << (i*2)))				isr_rdma(info->port_array[i]);			if (gsr & (BIT17 << (i*2)))				isr_tdma(info->port_array[i]);		}	}	if (info->gpio_present) {		unsigned int state;		unsigned int changed;		while ((changed = rd_reg32(info, IOSR)) != 0) {			DBGISR(("%s iosr=%08x\n", info->device_name, changed));			/* read latched state of GPIO signals */			state = rd_reg32(info, IOVR);			/* clear pending GPIO interrupt bits */			wr_reg32(info, IOSR, changed);			for (i=0 ; i < info->port_count ; i++) {				if (info->port_array[i] != NULL)					isr_gpio(info->port_array[i], changed, state);			}		}	}	for(i=0; i < info->port_count ; i++) {		struct slgt_info *port = info->port_array[i];		if (port && (port->count || port->netcount) &&		    port->pending_bh && !port->bh_running &&		    !port->bh_requested) {			DBGISR(("%s bh queued\n", port->device_name));			schedule_work(&port->task);			port->bh_requested = 1;		}	}	spin_unlock(&info->lock);	DBGISR(("slgt_interrupt irq=%d exit\n", irq));	return IRQ_HANDLED;}static int startup(struct slgt_info *info){	DBGINFO(("%s startup\n", info->device_name));	if (info->flags & ASYNC_INITIALIZED)		return 0;	if (!info->tx_buf) {		info->tx_buf = kmalloc(info->max_frame_size, GFP_KERNEL);		if (!info->tx_buf) {			DBGERR(("%s can't allocate tx buffer\n", info->device_name));			return -ENOMEM;		}	}	info->pending_bh = 0;	memset(&info->icount, 0, sizeof(info->icount));	/* program hardware for current parameters */	change_params(info);	if (info->tty)		clear_bit(TTY_IO_ERROR, &info->tty->flags);	info->flags |= ASYNC_INITIALIZED;	return 0;}/* *

⌨️ 快捷键说明

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