synclinkmp.c

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

C
2,458
字号
	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;	unsigned long flags;	if (debug_level >= DEBUG_LEVEL_INFO)		printk("%s(%d):%s write() count=%d\n",		       __FILE__,__LINE__,info->device_name,count);	if (sanity_check(info, tty->name, "write"))		goto cleanup;	if (!tty || !info->tx_buf)		goto cleanup;	if (info->params.mode == MGSL_MODE_HDLC) {		if (count > info->max_frame_size) {			ret = -EIO;			goto cleanup;		}		if (info->tx_active)			goto cleanup;		if (info->tx_count) {			/* send accumulated data from send_char() calls */			/* as frame and wait before accepting more data. */			tx_load_dma_buffer(info, info->tx_buf, info->tx_count);			goto start;		}		if (!from_user) {			ret = info->tx_count = count;			tx_load_dma_buffer(info, buf, count);			goto start;		}	}	for (;;) {		c = min_t(int, count,			min(info->max_frame_size - info->tx_count - 1,			    info->max_frame_size - info->tx_put));		if (c <= 0)			break;					if (from_user) {			COPY_FROM_USER(err, info->tx_buf + info->tx_put, buf, c);			if (err) {				if (!ret)					ret = -EFAULT;				break;			}		} else			memcpy(info->tx_buf + info->tx_put, buf, c);		spin_lock_irqsave(&info->lock,flags);		info->tx_put += c;		if (info->tx_put >= info->max_frame_size)			info->tx_put -= info->max_frame_size;		info->tx_count += c;		spin_unlock_irqrestore(&info->lock,flags);		buf += c;		count -= c;		ret += c;	}	if (info->params.mode == MGSL_MODE_HDLC) {		if (count) {			ret = info->tx_count = 0;			goto cleanup;		}		tx_load_dma_buffer(info, info->tx_buf, info->tx_count);	}start: 	if (info->tx_count && !tty->stopped && !tty->hw_stopped) {		spin_lock_irqsave(&info->lock,flags);		if (!info->tx_active)		 	tx_start(info);		spin_unlock_irqrestore(&info->lock,flags); 	}cleanup:	if (debug_level >= DEBUG_LEVEL_INFO)		printk( "%s(%d):%s write() returning=%d\n",			__FILE__,__LINE__,info->device_name,ret);	return ret;}/* Add a character to the transmit buffer. */static void put_char(struct tty_struct *tty, unsigned char ch){	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;	unsigned long flags;	if ( debug_level >= DEBUG_LEVEL_INFO ) {		printk( "%s(%d):%s put_char(%d)\n",			__FILE__,__LINE__,info->device_name,ch);	}	if (sanity_check(info, tty->name, "put_char"))		return;	if (!tty || !info->tx_buf)		return;	spin_lock_irqsave(&info->lock,flags);	if ( (info->params.mode != MGSL_MODE_HDLC) ||	     !info->tx_active ) {		if (info->tx_count < info->max_frame_size - 1) {			info->tx_buf[info->tx_put++] = ch;			if (info->tx_put >= info->max_frame_size)				info->tx_put -= info->max_frame_size;			info->tx_count++;		}	}	spin_unlock_irqrestore(&info->lock,flags);}/* Send a high-priority XON/XOFF character */static void send_xchar(struct tty_struct *tty, char ch){	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;	unsigned long flags;	if (debug_level >= DEBUG_LEVEL_INFO)		printk("%s(%d):%s send_xchar(%d)\n",			 __FILE__,__LINE__, info->device_name, ch );	if (sanity_check(info, tty->name, "send_xchar"))		return;	info->x_char = ch;	if (ch) {		/* Make sure transmit interrupts are on */		spin_lock_irqsave(&info->lock,flags);		if (!info->tx_enabled)		 	tx_start(info);		spin_unlock_irqrestore(&info->lock,flags);	}}/* Wait until the transmitter is empty. */static void wait_until_sent(struct tty_struct *tty, int timeout){	SLMP_INFO * info = (SLMP_INFO *)tty->driver_data;	unsigned long orig_jiffies, char_time;	if (!info )		return;	if (debug_level >= DEBUG_LEVEL_INFO)		printk("%s(%d):%s wait_until_sent() entry\n",			 __FILE__,__LINE__, info->device_name );	if (sanity_check(info, tty->name, "wait_until_sent"))		return;	if (!(info->flags & ASYNC_INITIALIZED))		goto exit;	orig_jiffies = jiffies;	/* Set check interval to 1/5 of estimated time to	 * send a character, and make it at least 1. The check	 * interval should also be less than the timeout.	 * Note: use tight timings here to satisfy the NIST-PCTS.	 */	if ( info->params.data_rate ) {	       	char_time = info->timeout/(32 * 5);		if (!char_time)			char_time++;	} else		char_time = 1;	if (timeout)		char_time = min_t(unsigned long, char_time, timeout);	if ( info->params.mode == MGSL_MODE_HDLC ) {		while (info->tx_active) {			set_current_state(TASK_INTERRUPTIBLE);			schedule_timeout(char_time);			if (signal_pending(current))				break;			if (timeout && time_after(jiffies, orig_jiffies + timeout))				break;		}	} else {		//TODO: determine if there is something similar to USC16C32		// 	TXSTATUS_ALL_SENT status		while ( info->tx_active && info->tx_enabled) {			set_current_state(TASK_INTERRUPTIBLE);			schedule_timeout(char_time);			if (signal_pending(current))				break;			if (timeout && time_after(jiffies, orig_jiffies + timeout))				break;		}	}exit:	if (debug_level >= DEBUG_LEVEL_INFO)		printk("%s(%d):%s wait_until_sent() exit\n",			 __FILE__,__LINE__, info->device_name );}/* Return the count of free bytes in transmit buffer */static int write_room(struct tty_struct *tty){	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;	int ret;	if (sanity_check(info, tty->name, "write_room"))		return 0;	if (info->params.mode == MGSL_MODE_HDLC) {		ret = (info->tx_active) ? 0 : HDLC_MAX_FRAME_SIZE;	} else {		ret = info->max_frame_size - info->tx_count - 1;		if (ret < 0)			ret = 0;	}	if (debug_level >= DEBUG_LEVEL_INFO)		printk("%s(%d):%s write_room()=%d\n",		       __FILE__, __LINE__, info->device_name, ret);	return ret;}/* enable transmitter and send remaining buffered characters */static void flush_chars(struct tty_struct *tty){	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;	unsigned long flags;	if ( debug_level >= DEBUG_LEVEL_INFO )		printk( "%s(%d):%s flush_chars() entry tx_count=%d\n",			__FILE__,__LINE__,info->device_name,info->tx_count);	if (sanity_check(info, tty->name, "flush_chars"))		return;	if (info->tx_count <= 0 || tty->stopped || tty->hw_stopped ||	    !info->tx_buf)		return;	if ( debug_level >= DEBUG_LEVEL_INFO )		printk( "%s(%d):%s flush_chars() entry, starting transmitter\n",			__FILE__,__LINE__,info->device_name );	spin_lock_irqsave(&info->lock,flags);	if (!info->tx_active) {		if ( (info->params.mode == MGSL_MODE_HDLC) &&			info->tx_count ) {			/* operating in synchronous (frame oriented) mode */			/* copy data from circular tx_buf to */			/* transmit DMA buffer. */			tx_load_dma_buffer(info,				 info->tx_buf,info->tx_count);		}	 	tx_start(info);	}	spin_unlock_irqrestore(&info->lock,flags);}/* Discard all data in the send buffer */static void flush_buffer(struct tty_struct *tty){	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;	unsigned long flags;	if (debug_level >= DEBUG_LEVEL_INFO)		printk("%s(%d):%s flush_buffer() entry\n",			 __FILE__,__LINE__, info->device_name );	if (sanity_check(info, tty->name, "flush_buffer"))		return;	spin_lock_irqsave(&info->lock,flags);	info->tx_count = info->tx_put = info->tx_get = 0;	del_timer(&info->tx_timer);	spin_unlock_irqrestore(&info->lock,flags);	wake_up_interruptible(&tty->write_wait);	tty_wakeup(tty);}/* throttle (stop) transmitter */static void tx_hold(struct tty_struct *tty){	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;	unsigned long flags;	if (sanity_check(info, tty->name, "tx_hold"))		return;	if ( debug_level >= DEBUG_LEVEL_INFO )		printk("%s(%d):%s tx_hold()\n",			__FILE__,__LINE__,info->device_name);	spin_lock_irqsave(&info->lock,flags);	if (info->tx_enabled)	 	tx_stop(info);	spin_unlock_irqrestore(&info->lock,flags);}/* release (start) transmitter */static void tx_release(struct tty_struct *tty){	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;	unsigned long flags;	if (sanity_check(info, tty->name, "tx_release"))		return;	if ( debug_level >= DEBUG_LEVEL_INFO )		printk("%s(%d):%s tx_release()\n",			__FILE__,__LINE__,info->device_name);	spin_lock_irqsave(&info->lock,flags);	if (!info->tx_enabled)	 	tx_start(info);	spin_unlock_irqrestore(&info->lock,flags);}/* Service an IOCTL request * * Arguments: * * 	tty	pointer to tty instance data * 	file	pointer to associated file object for device * 	cmd	IOCTL command code * 	arg	command argument/context * * Return Value:	0 if success, otherwise error code */static int ioctl(struct tty_struct *tty, struct file *file,		 unsigned int cmd, unsigned long arg){	SLMP_INFO *info = (SLMP_INFO *)tty->driver_data;	int error;	struct mgsl_icount cnow;	/* kernel counter temps */	struct serial_icounter_struct __user *p_cuser;	/* user space */	unsigned long flags;	void __user *argp = (void __user *)arg;	if (debug_level >= DEBUG_LEVEL_INFO)		printk("%s(%d):%s ioctl() cmd=%08X\n", __FILE__,__LINE__,			info->device_name, cmd );	if (sanity_check(info, tty->name, "ioctl"))		return -ENODEV;	if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) &&	    (cmd != TIOCMIWAIT) && (cmd != TIOCGICOUNT)) {		if (tty->flags & (1 << TTY_IO_ERROR))		    return -EIO;	}	switch (cmd) {	case MGSL_IOCGPARAMS:		return get_params(info, argp);	case MGSL_IOCSPARAMS:		return set_params(info, argp);	case MGSL_IOCGTXIDLE:		return get_txidle(info, argp);	case MGSL_IOCSTXIDLE:		return set_txidle(info, (int)arg);	case MGSL_IOCTXENABLE:		return tx_enable(info, (int)arg);	case MGSL_IOCRXENABLE:		return rx_enable(info, (int)arg);	case MGSL_IOCTXABORT:		return tx_abort(info);	case MGSL_IOCGSTATS:		return get_stats(info, argp);	case MGSL_IOCWAITEVENT:		return wait_mgsl_event(info, argp);	case MGSL_IOCLOOPTXDONE:		return 0; // TODO: Not supported, need to document		/* Wait for modem input (DCD,RI,DSR,CTS) change		 * as specified by mask in arg (TIOCM_RNG/DSR/CD/CTS)		 */	case TIOCMIWAIT:		return modem_input_wait(info,(int)arg);				/*		 * Get counter of input serial line interrupts (DCD,RI,DSR,CTS)		 * Return: write counters to the user passed counter struct		 * NB: both 1->0 and 0->1 transitions are counted except for		 *     RI where only 0->1 is counted.		 */	case TIOCGICOUNT:		spin_lock_irqsave(&info->lock,flags);		cnow = info->icount;		spin_unlock_irqrestore(&info->lock,flags);		p_cuser = argp;		PUT_USER(error,cnow.cts, &p_cuser->cts);		if (error) return error;		PUT_USER(error,cnow.dsr, &p_cuser->dsr);		if (error) return error;		PUT_USER(error,cnow.rng, &p_cuser->rng);		if (error) return error;		PUT_USER(error,cnow.dcd, &p_cuser->dcd);		if (error) return error;		PUT_USER(error,cnow.rx, &p_cuser->rx);		if (error) return error;		PUT_USER(error,cnow.tx, &p_cuser->tx);		if (error) return error;		PUT_USER(error,cnow.frame, &p_cuser->frame);		if (error) return error;		PUT_USER(error,cnow.overrun, &p_cuser->overrun);		if (error) return error;		PUT_USER(error,cnow.parity, &p_cuser->parity);		if (error) return error;		PUT_USER(error,cnow.brk, &p_cuser->brk);		if (error) return error;		PUT_USER(error,cnow.buf_overrun, &p_cuser->buf_overrun);		if (error) return error;		return 0;	default:		return -ENOIOCTLCMD;	}	return 0;}/* * /proc fs routines.... */static inline int line_info(char *buf, SLMP_INFO *info){	char	stat_buf[30];	int	ret;	unsigned long flags;	ret = sprintf(buf, "%s: SCABase=%08x Mem=%08X StatusControl=%08x LCR=%08X\n"		       "\tIRQ=%d MaxFrameSize=%u\n",		info->device_name,		info->phys_sca_base,		info->phys_memory_base,		info->phys_statctrl_base,		info->phys_lcr_base,		info->irq_level,		info->max_frame_size );	/* output current serial signal states */	spin_lock_irqsave(&info->lock,flags); 	get_signals(info);	spin_unlock_irqrestore(&info->lock,flags);	stat_buf[0] = 0;	stat_buf[1] = 0;	if (info->serial_signals & SerialSignal_RTS)		strcat(stat_buf, "|RTS");	if (info->serial_signals & SerialSignal_CTS)		strcat(stat_buf, "|CTS");	if (info->serial_signals & SerialSignal_DTR)		strcat(stat_buf, "|DTR");	if (info->serial_signals & SerialSignal_DSR)		strcat(stat_buf, "|DSR");	if (info->serial_signals & SerialSignal_DCD)		strcat(stat_buf, "|CD");	if (info->serial_signals & SerialSignal_RI)		strcat(stat_buf, "|RI");	if (info->params.mode == MGSL_MODE_HDLC) {		ret += sprintf(buf+ret, "\tHDLC txok:%d rxok:%d",			      info->icount.txok, info->icount.rxok);		if (info->icount.txunder)			ret += sprintf(buf+ret, " txunder:%d", info->icount.txunder);		if (info->icount.txabort)			ret += sprintf(buf+ret, " txabort:%d", info->icount.txabort);		if (info->icount.rxshort)			ret += sprintf(buf+ret, " rxshort:%d", info->icount.rxshort);		if (info->icount.rxlong)			ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxlong);		if (info->icount.rxover)			ret += sprintf(buf+ret, " rxover:%d", info->icount.rxover);		if (info->icount.rxcrc)			ret += sprintf(buf+ret, " rxlong:%d", info->icount.rxcrc);	} else {

⌨️ 快捷键说明

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