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

📄 synclink.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
static int __init synclink_init_one (struct pci_dev *dev,				     const struct pci_device_id *ent);static void __exit synclink_remove_one (struct pci_dev *dev);static struct pci_device_id synclink_pci_tbl[] __devinitdata = {	{ PCI_VENDOR_ID_MICROGATE, PCI_DEVICE_ID_MICROGATE_USC, PCI_ANY_ID, PCI_ANY_ID, },	{ 0, }, /* terminate list */};MODULE_DEVICE_TABLE(pci, synclink_pci_tbl);static struct pci_driver synclink_pci_driver = {	name:		"synclink",	id_table:	synclink_pci_tbl,	probe:		synclink_init_one,	remove:		synclink_remove_one,};static struct tty_driver serial_driver, callout_driver;static int serial_refcount;/* number of characters left in xmit buffer before we ask for more */#define WAKEUP_CHARS 256static void mgsl_change_params(struct mgsl_struct *info);static void mgsl_wait_until_sent(struct tty_struct *tty, int timeout);static struct tty_struct *serial_table[MAX_TOTAL_DEVICES];static struct termios *serial_termios[MAX_TOTAL_DEVICES];static struct termios *serial_termios_locked[MAX_TOTAL_DEVICES];#ifndef MIN#define MIN(a,b)	((a) < (b) ? (a) : (b))#endif/* * 1st function defined in .text section. Calling this function in * init_module() followed by a breakpoint allows a remote debugger * (gdb) to get the .text address for the add-symbol-file command. * This allows remote debugging of dynamically loadable modules. */void* mgsl_get_text_ptr(void);void* mgsl_get_text_ptr() {return mgsl_get_text_ptr;}/* * tmp_buf is used as a temporary buffer by mgsl_write.  We need to * lock it in case the COPY_FROM_USER blocks while swapping in a page, * and some other program tries to do a serial write at the same time. * Since the lock will only come under contention when the system is * swapping and available memory is low, it makes sense to share one * buffer across all the serial ioports, since it significantly saves * memory if large numbers of serial ports are open. */static unsigned char *tmp_buf;static DECLARE_MUTEX(tmp_buf_sem);static inline int mgsl_paranoia_check(struct mgsl_struct *info,					kdev_t device, const char *routine){#ifdef MGSL_PARANOIA_CHECK	static const char *badmagic =		"Warning: bad magic number for mgsl struct (%s) in %s\n";	static const char *badinfo =		"Warning: null mgsl_struct for (%s) in %s\n";	if (!info) {		printk(badinfo, kdevname(device), routine);		return 1;	}	if (info->magic != MGSL_MAGIC) {		printk(badmagic, kdevname(device), routine);		return 1;	}#endif	return 0;}/* mgsl_stop()		throttle (stop) transmitter * 	 * Arguments:		tty	pointer to tty info structure * Return Value:	None */static void mgsl_stop(struct tty_struct *tty){	struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;	unsigned long flags;		if (mgsl_paranoia_check(info, tty->device, "mgsl_stop"))		return;		if ( debug_level >= DEBUG_LEVEL_INFO )		printk("mgsl_stop(%s)\n",info->device_name);				spin_lock_irqsave(&info->irq_spinlock,flags);	if (info->tx_enabled)	 	usc_stop_transmitter(info);	spin_unlock_irqrestore(&info->irq_spinlock,flags);	}	/* end of mgsl_stop() *//* mgsl_start()		release (start) transmitter * 	 * Arguments:		tty	pointer to tty info structure * Return Value:	None */static void mgsl_start(struct tty_struct *tty){	struct mgsl_struct *info = (struct mgsl_struct *)tty->driver_data;	unsigned long flags;		if (mgsl_paranoia_check(info, tty->device, "mgsl_start"))		return;		if ( debug_level >= DEBUG_LEVEL_INFO )		printk("mgsl_start(%s)\n",info->device_name);				spin_lock_irqsave(&info->irq_spinlock,flags);	if (!info->tx_enabled)	 	usc_start_transmitter(info);	spin_unlock_irqrestore(&info->irq_spinlock,flags);	}	/* end of mgsl_start() *//* * Bottom half work queue access functions *//* mgsl_bh_action()	Return next bottom half action to perform. * Return Value:	BH action code or 0 if nothing to do. */int mgsl_bh_action(struct mgsl_struct *info){	unsigned long flags;	int rc = 0;		spin_lock_irqsave(&info->irq_spinlock,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;	}	if (!rc) {		/* Mark BH routine as complete */		info->bh_running   = 0;		info->bh_requested = 0;	}		spin_unlock_irqrestore(&info->irq_spinlock,flags);		return rc;}/* * 	Perform bottom half processing of work items queued by ISR. */void mgsl_bh_handler(void* Context){	struct mgsl_struct *info = (struct mgsl_struct*)Context;	int action;	if (!info)		return;			if ( debug_level >= DEBUG_LEVEL_BH )		printk( "%s(%d):mgsl_bh_handler(%s) entry\n",			__FILE__,__LINE__,info->device_name);		info->bh_running = 1;	while((action = mgsl_bh_action(info)) != 0) {			/* Process work item */		if ( debug_level >= DEBUG_LEVEL_BH )			printk( "%s(%d):mgsl_bh_handler() work item action=%d\n",				__FILE__,__LINE__,action);		switch (action) {				case BH_RECEIVE:			mgsl_bh_receive(info);			break;		case BH_TRANSMIT:			mgsl_bh_transmit(info);			break;		case BH_STATUS:			mgsl_bh_status(info);			break;		default:			/* unknown work item ID */			printk("Unknown work item ID=%08X!\n", action);			break;		}	}	if ( debug_level >= DEBUG_LEVEL_BH )		printk( "%s(%d):mgsl_bh_handler(%s) exit\n",			__FILE__,__LINE__,info->device_name);}void mgsl_bh_receive(struct mgsl_struct *info){	if ( debug_level >= DEBUG_LEVEL_BH )		printk( "%s(%d):mgsl_bh_receive(%s)\n",			__FILE__,__LINE__,info->device_name);		while( mgsl_get_rx_frame(info) );}void mgsl_bh_transmit(struct mgsl_struct *info){	struct tty_struct *tty = info->tty;	unsigned long flags;		if ( debug_level >= DEBUG_LEVEL_BH )		printk( "%s(%d):mgsl_bh_transmit() entry on %s\n",			__FILE__,__LINE__,info->device_name);	if (tty) {		if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&		    tty->ldisc.write_wakeup) {			if ( debug_level >= DEBUG_LEVEL_BH )				printk( "%s(%d):calling ldisc.write_wakeup on %s\n",					__FILE__,__LINE__,info->device_name);			(tty->ldisc.write_wakeup)(tty);		}		wake_up_interruptible(&tty->write_wait);	}	/* if transmitter idle and loopmode_send_done_requested	 * then start echoing RxD to TxD	 */	spin_lock_irqsave(&info->irq_spinlock,flags); 	if ( !info->tx_active && info->loopmode_send_done_requested ) 		usc_loopmode_send_done( info );	spin_unlock_irqrestore(&info->irq_spinlock,flags);}void mgsl_bh_status(struct mgsl_struct *info){	if ( debug_level >= DEBUG_LEVEL_BH )		printk( "%s(%d):mgsl_bh_status() entry on %s\n",			__FILE__,__LINE__,info->device_name);	info->ri_chkcount = 0;	info->dsr_chkcount = 0;	info->dcd_chkcount = 0;	info->cts_chkcount = 0;}/* mgsl_isr_receive_status() *  *	Service a receive status interrupt. The type of status *	interrupt is indicated by the state of the RCSR. *	This is only used for HDLC mode. * * Arguments:		info	pointer to device instance data * Return Value:	None */void mgsl_isr_receive_status( struct mgsl_struct *info ){	u16 status = usc_InReg( info, RCSR );	if ( debug_level >= DEBUG_LEVEL_ISR )			printk("%s(%d):mgsl_isr_receive_status status=%04X\n",			__FILE__,__LINE__,status);			 	if ( (status & RXSTATUS_ABORT_RECEIVED) && 		info->loopmode_insert_requested && 		usc_loopmode_active(info) ) 	{		++info->icount.rxabort;	 	info->loopmode_insert_requested = FALSE;  		/* clear CMR:13 to start echoing RxD to TxD */		info->cmr_value &= ~BIT13; 		usc_OutReg(info, CMR, info->cmr_value); 		/* disable received abort irq (no longer required) */	 	usc_OutReg(info, RICR, 			(usc_InReg(info, RICR) & ~RXSTATUS_ABORT_RECEIVED)); 	}	if (status & (RXSTATUS_EXITED_HUNT + RXSTATUS_IDLE_RECEIVED)) {		if (status & RXSTATUS_EXITED_HUNT)			info->icount.exithunt++;		if (status & RXSTATUS_IDLE_RECEIVED)			info->icount.rxidle++;		wake_up_interruptible(&info->event_wait_q);	}	if (status & RXSTATUS_OVERRUN){		info->icount.rxover++;		usc_process_rxoverrun_sync( info );	}	usc_ClearIrqPendingBits( info, RECEIVE_STATUS );	usc_UnlatchRxstatusBits( info, status );}	/* end of mgsl_isr_receive_status() *//* mgsl_isr_transmit_status() *  * 	Service a transmit status interrupt *	HDLC mode :end of transmit frame *	Async mode:all data is sent * 	transmit status is indicated by bits in the TCSR. *  * Arguments:		info	       pointer to device instance data * Return Value:	None */void mgsl_isr_transmit_status( struct mgsl_struct *info ){	u16 status = usc_InReg( info, TCSR );	if ( debug_level >= DEBUG_LEVEL_ISR )			printk("%s(%d):mgsl_isr_transmit_status status=%04X\n",			__FILE__,__LINE__,status);		usc_ClearIrqPendingBits( info, TRANSMIT_STATUS );	usc_UnlatchTxstatusBits( info, status );		if ( status & (TXSTATUS_UNDERRUN | TXSTATUS_ABORT_SENT) )	{		/* finished sending HDLC abort. This may leave	*/		/* the TxFifo with data from the aborted frame	*/		/* so purge the TxFifo. Also shutdown the DMA	*/		/* channel in case there is data remaining in 	*/		/* the DMA buffer				*/ 		usc_DmaCmd( info, DmaCmd_ResetTxChannel ); 		usc_RTCmd( info, RTCmd_PurgeTxFifo );	} 	if ( status & TXSTATUS_EOF_SENT )		info->icount.txok++;	else if ( status & TXSTATUS_UNDERRUN )		info->icount.txunder++;	else if ( status & TXSTATUS_ABORT_SENT )		info->icount.txabort++;	else		info->icount.txunder++;				info->tx_active = 0;	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;	del_timer(&info->tx_timer);			if ( info->drop_rts_on_tx_done ) {		usc_get_serial_signals( info );		if ( info->serial_signals & SerialSignal_RTS ) {			info->serial_signals &= ~SerialSignal_RTS;			usc_set_serial_signals( info );		}		info->drop_rts_on_tx_done = 0;	}#ifdef CONFIG_SYNCLINK_SYNCPPP		if (info->netcount)		mgsl_sppp_tx_done(info);	else #endif	{		if (info->tty->stopped || info->tty->hw_stopped) {			usc_stop_transmitter(info);			return;		}		info->pending_bh |= BH_TRANSMIT;	}}	/* end of mgsl_isr_transmit_status() *//* mgsl_isr_io_pin() *  * 	Service an Input/Output pin interrupt. The type of * 	interrupt is indicated by bits in the MISR * 	 * Arguments:		info	       pointer to device instance data * Return Value:	None */void mgsl_isr_io_pin( struct mgsl_struct *info ){ 	struct	mgsl_icount *icount;	u16 status = usc_InReg( info, MISR );	if ( debug_level >= DEBUG_LEVEL_ISR )			printk("%s(%d):mgsl_isr_io_pin status=%04X\n",			__FILE__,__LINE__,status);				usc_ClearIrqPendingBits( info, IO_PIN );	usc_UnlatchIostatusBits( info, status );	if (status & (MISCSTATUS_CTS_LATCHED | MISCSTATUS_DCD_LATCHED |	              MISCSTATUS_DSR_LATCHED | MISCSTATUS_RI_LATCHED) ) {		icount = &info->icount;		/* update input line counters */		if (status & MISCSTATUS_RI_LATCHED) {			if ((info->ri_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)				usc_DisablestatusIrqs(info,SICR_RI);			icount->rng++;			if ( status & MISCSTATUS_RI )				info->input_signal_events.ri_up++;				else				info->input_signal_events.ri_down++;			}		if (status & MISCSTATUS_DSR_LATCHED) {			if ((info->dsr_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)				usc_DisablestatusIrqs(info,SICR_DSR);			icount->dsr++;			if ( status & MISCSTATUS_DSR )				info->input_signal_events.dsr_up++;			else				info->input_signal_events.dsr_down++;		}		if (status & MISCSTATUS_DCD_LATCHED) {			if ((info->dcd_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)				usc_DisablestatusIrqs(info,SICR_DCD);			icount->dcd++;			if (status & MISCSTATUS_DCD) {				info->input_signal_events.dcd_up++;#ifdef CONFIG_SYNCLINK_SYNCPPP					if (info->netcount)					sppp_reopen(info->netdev);#endif			} else				info->input_signal_events.dcd_down++;#ifdef CONFIG_HARD_PPS			if ((info->flags & ASYNC_HARDPPS_CD) &&			    (status & MISCSTATUS_DCD_LATCHED))				hardpps();#endif		}		if (status & MISCSTATUS_CTS_LATCHED)		{			if ((info->cts_chkcount)++ >= IO_PIN_SHUTDOWN_LIMIT)				usc_DisablestatusIrqs(info,SICR_CTS);			icount->cts++;			if ( status & MISCSTATUS_CTS )				info->input_signal_events.cts_up++;

⌨️ 快捷键说明

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