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

📄 synclink.c

📁 powerpc内核mpc8241linux系统下char驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
static struct termios **serial_termios = NULL;static struct termios **serial_termios_locked = NULL;#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 struct semaphore tmp_buf_sem = MUTEX;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_format_bh_queue() *  * 	Initialize the bottom half processing queue *  * Arguments:		info	pointer to device instance data * Return Value:	None */void mgsl_format_bh_queue( struct mgsl_struct *info ){	BH_QUEUE bh_queue = info->bh_queue;	int i;	/* go through sequentially tacking the little bits together */	for ( i=0; i < MAX_BH_QUEUE_ENTRIES; i++ ) {		if ( info->free_bh_queue_tail == NULL )			info->free_bh_queue_head = bh_queue;		else			info->free_bh_queue_tail->link = bh_queue;		info->free_bh_queue_tail = bh_queue++;	}	/* As a safety measure, mark the end of the chain with a NULL */	info->free_bh_queue_tail->link = NULL;}	/* end of mgsl_format_bh_queue() *//* mgsl_bh_queue_put() *  * 	Add a BH event to the BH queue *  * Arguments:		info		pointer to device instance data * 			type	BH event type * 			status		BH event status *  * Return Value:	None */void mgsl_bh_queue_put( struct mgsl_struct *info, unsigned char type, unsigned short status ){	BH_EVENT *event = info->free_bh_queue_head;	if ( event != NULL ) {		/* remove free element from head of free list */		info->free_bh_queue_head = event->link;		event->link = NULL;		/* file out new BH event */		event->type = type;		event->status = status;		/* add element to tail of pending list */		if ( info->bh_queue_head != NULL ){			/* BH queue is not empty, add current element to tail */			info->bh_queue_tail->link = event;		} else {			/* the BH queue is empty so this element becomes the head of queue */			info->bh_queue_head = event;		}		/* the new element becomes tail of queue */		info->bh_queue_tail = event;	} else {		/* No more free BH action elements in queue. */		/* This happens when too many interrupts are occuring */		/* for the mgsl_bh_handler to process so set a flag. */		info->isr_overflow = 1;	}}	/* end of mgsl_bh_queue_put() *//* mgsl_bh_queue_get() *  *	Free the current work item (if any) and get the * 	next work item from the head of the pending work item queue. * * Effects: *  * 	If a BH action element is available on the BH action queue * 	then the head of the queue is removed and bh_action * 	is set to point to the removed element. *  * Arguments:		info	pointer to device instance data * Return Value:	1 if BH action removed from queue */int mgsl_bh_queue_get( struct mgsl_struct *info ){	unsigned long flags;		spin_lock_irqsave(&info->irq_spinlock,flags);	if ( info->bh_action ) {		/* free the current work item */		if ( info->free_bh_queue_head != NULL ){			/* free queue is not empty, add current element to tail */			info->free_bh_queue_tail->link = info->bh_action;		} else {			/* free queue is empty so this element becomes the head of queue */			info->free_bh_queue_head = info->bh_action;		}		/* add element to tail of free queue */		info->free_bh_queue_tail = info->bh_action;		info->free_bh_queue_tail->link = NULL;	}		/* attempt to remove element from head of queue */	info->bh_action = info->bh_queue_head;	if ( info->bh_action != NULL ){		/* BH queue is not empty, remove element from queue head */		info->bh_queue_head = info->bh_action->link;		spin_unlock_irqrestore(&info->irq_spinlock,flags);		return 1;	}	/* Mark BH routine as complete */	info->bh_running   = 0;	info->bh_requested = 0;		spin_unlock_irqrestore(&info->irq_spinlock,flags);		return 0;}	/* end of mgsl_bh_queue_get() *//* mgsl_bh_handler() *  * 	Perform bottom half processing of work items queued by ISR. * * Arguments:		Context		pointer to device instance data * Return Value:	None */void mgsl_bh_handler(void* Context){	struct mgsl_struct *info = (struct mgsl_struct*)Context;		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;	/* Attempt to clear out the BH queue */	while( mgsl_bh_queue_get(info) ) {			/* Process work item */		if ( debug_level >= DEBUG_LEVEL_BH )			printk( "%s(%d):mgsl_bh_handler() work item action=%d\n",				__FILE__,__LINE__,info->bh_action->type);		switch ( info->bh_action->type ) {				case BH_TYPE_RECEIVE_DMA:			mgsl_bh_receive_dma( info, info->bh_action->status );			break;		case BH_TYPE_TRANSMIT_STATUS:		case BH_TYPE_TRANSMIT_DATA:			mgsl_bh_transmit_data( info, info->bh_action->status );			break;		case BH_TYPE_STATUS:			mgsl_bh_status_handler( info, info->bh_action->status );			break;		default:			/* unknown work item ID */			printk("Unknown work item ID=%08X!\n",				info->bh_action->type );			break;		}	}	if ( info->isr_overflow ) {		printk("ISR overflow detected.\n");	}	if ( debug_level >= DEBUG_LEVEL_BH )		printk( "%s(%d):mgsl_bh_handler(%s) exit\n",			__FILE__,__LINE__,info->device_name);	}	/* end of mgsl_bh_handler() *//* mgsl_bh_receive_dma() *  * 	Perform bottom half processing for a receive DMA interrupt * 	This occurs in HDLC mode after a DMA buffer has terminated * 	or the DMA buffers have been exhausted. *  * Arguments: *  * 	info		pointer to device instance data * 	status		status word *  * Return Value:	None */void mgsl_bh_receive_dma( struct mgsl_struct *info, unsigned short status ){	if ( debug_level >= DEBUG_LEVEL_BH )		printk( "%s(%d):mgsl_bh_receive_dma(%s)\n",			__FILE__,__LINE__,info->device_name);		while( mgsl_get_rx_frame(info) );}	/* end of mgsl_bh_receive_dma() *//* mgsl_bh_transmit_data() *  * 	Process a transmit data interrupt event * 	This occurs in asynchronous communications mode. *  * Arguments:		info	pointer to device instance data * Return Value:	None */void mgsl_bh_transmit_data( struct mgsl_struct *info, unsigned short Datacount ){	struct tty_struct *tty = info->tty;		if ( debug_level >= DEBUG_LEVEL_BH )		printk( "%s(%d):mgsl_bh_transmit_data() entry on %s\n",			__FILE__,__LINE__,info->device_name);				/* wakeup any waiting write requests */ 	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);	}	}	/* End Of mgsl_bh_transmit_data() *//* mgsl_bh_status_handler() *  * 	Peform bottom half processing for a status interrupt *  * 	This event is generated when a I/O pin (serial signal) * 	has a transition. If there is a pending WaitEvent call * 	and the status transition is identified in the EventMast * 	of the pending call then complete the pending call. *  * Arguments: *  * 	info		pointer to device instance data * 	status		status word *  * Return Value:	None */void mgsl_bh_status_handler( struct mgsl_struct *info, unsigned short status ){	if ( debug_level >= DEBUG_LEVEL_BH )		printk( "%s(%d):mgsl_bh_status_handler() entry on %s\n",			__FILE__,__LINE__,info->device_name);}	/* End Of mgsl_bh_status_handler() *//* 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);				usc_ClearIrqPendingBits( info, RECEIVE_STATUS );	usc_UnlatchRxstatusBits( info, status );	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){		/* Purge receive FIFO to allow DMA buffer completion		 * with overrun status stored in the receive status block.		 */		usc_RCmd( info, RCmd_EnterHuntmode );		usc_RTCmd( info, RTCmd_PurgeRxFifo );	}}	/* 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_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;

⌨️ 快捷键说明

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