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

📄 ctctty.c

📁 内核linux2.4.20,可跟rtlinux3.2打补丁 组成实时linux系统,编译内核
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * $Id: ctctty.c,v 1.8 2001/05/16 16:28:31 felfert Exp $ * * CTC / ESCON network driver, tty interface. * * Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Fritz Elfert (elfert@de.ibm.com, felfert@millenux.com) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * */#define __NO_VERSION__#include <linux/config.h>#include <linux/module.h>#include <linux/tty.h>#include <linux/serial_reg.h>#include <linux/interrupt.h>#include <asm/uaccess.h>#ifdef CONFIG_DEVFS_FS#  include <linux/devfs_fs_kernel.h>#endif#include "ctctty.h"#if LINUX_VERSION_CODE < 0x020212typedef struct wait_queue wait_queue_t;typedef struct wait_queue *wait_queue_head_t;#define DECLARE_WAITQUEUE(wait, current) \	struct wait_queue wait = { current, NULL }#define init_waitqueue_head(x) *(x)=NULL#define __set_current_state(state_value) \	do { current->state = state_value; } while (0)#ifdef __SMP__#define set_current_state(state_value) \	do { __set_current_state(state_value); mb(); } while (0)#else#define set_current_state(state_value) __set_current_state(state_value)#endif#define init_MUTEX(x) *(x)=MUTEX#endif#define CTC_TTY_MAJOR       43#define CTC_TTY_MAX_DEVICES 64#define CTC_ASYNC_MAGIC          0x49344C01 /* for paranoia-checking        */#define CTC_ASYNC_INITIALIZED    0x80000000 /* port was initialized         */#define CTC_ASYNC_NORMAL_ACTIVE  0x20000000 /* Normal device active         */#define CTC_ASYNC_CLOSING        0x08000000 /* Serial port is closing       */#define CTC_ASYNC_CTS_FLOW       0x04000000 /* Do CTS flow control          */#define CTC_ASYNC_CHECK_CD       0x02000000 /* i.e., CLOCAL                 */#define CTC_ASYNC_HUP_NOTIFY         0x0001 /* Notify tty on hangups/closes */#define CTC_ASYNC_NETDEV_OPEN        0x0002 /* Underlying netdev is open    */#define CTC_ASYNC_TX_LINESTAT        0x0004 /* Must send line status        */#define CTC_ASYNC_SPLIT_TERMIOS      0x0008 /* Sep. termios for dialin/out  */#define CTC_TTY_XMIT_SIZE              1024 /* Default bufsize for write    */#define CTC_SERIAL_XMIT_MAX            4000 /* Maximum bufsize for write    */#define CTC_SERIAL_TYPE_NORMAL            1/* Private data (similar to async_struct in <linux/serial.h>) */typedef struct {  int			magic;  int			flags;		 /* defined in tty.h               */  int			mcr;		 /* Modem control register         */  int                   msr;             /* Modem status register          */  int                   lsr;             /* Line status register           */  int			line;  int			count;		 /* # of fd on device              */  int			blocked_open;	 /* # of blocked opens             */  net_device            *netdev;  struct sk_buff_head   tx_queue;        /* transmit queue                 */  struct sk_buff_head   rx_queue;        /* receive queue                  */  struct tty_struct 	*tty;            /* Pointer to corresponding tty   */  struct termios	normal_termios;  /* For saving termios structs     */  wait_queue_head_t	open_wait;  wait_queue_head_t	close_wait;  struct semaphore      write_sem;  struct tq_struct      tq;  struct timer_list     stoptimer;} ctc_tty_info;/* Description of one CTC-tty */typedef struct {  int                refcount;			   /* Number of opens        */  struct tty_driver  ctc_tty_device;		   /* tty-device             */  struct tty_struct  *modem_table[CTC_TTY_MAX_DEVICES];  struct termios     *modem_termios[CTC_TTY_MAX_DEVICES];  struct termios     *modem_termios_locked[CTC_TTY_MAX_DEVICES];  ctc_tty_info       info[CTC_TTY_MAX_DEVICES];	   /* Private data           */} ctc_tty_driver;static ctc_tty_driver *driver;/* Leave this unchanged unless you know what you do! */#define MODEM_PARANOIA_CHECK#define MODEM_DO_RESTART#define CTC_TTY_NAME "ctctty"#ifdef CONFIG_DEVFS_FSstatic char *ctc_ttyname = "ctc/" CTC_TTY_NAME "%d";#elsestatic char *ctc_ttyname = CTC_TTY_NAME;#endifchar *ctc_tty_revision = "$Revision: 1.8 $";static __u32 ctc_tty_magic = CTC_ASYNC_MAGIC;static int ctc_tty_shuttingdown = 0;static spinlock_t ctc_tty_lock;/* ctc_tty_try_read() is called from within ctc_tty_rcv_skb() * to stuff incoming data directly into a tty's flip-buffer. If the * flip buffer is full, the packet gets queued up. * * Return: *  1 = Success *  0 = Failure, data has to be buffered and later processed by *      ctc_tty_readmodem(). */static intctc_tty_try_read(ctc_tty_info * info, struct sk_buff *skb){	int c;	int len;	struct tty_struct *tty;	if ((tty = info->tty)) {		if (info->mcr & UART_MCR_RTS) {			c = TTY_FLIPBUF_SIZE - tty->flip.count;			len = skb->len;			if (c >= len) {				memcpy(tty->flip.char_buf_ptr, skb->data, len);				memset(tty->flip.flag_buf_ptr, 0, len);				tty->flip.count += len;				tty->flip.char_buf_ptr += len;				tty->flip.flag_buf_ptr += len;				tty_flip_buffer_push(tty);				kfree_skb(skb);				return 1;			}		}	}	return 0;}/* ctc_tty_readmodem() is called periodically from within timer-interrupt. * It tries getting received data from the receive queue an stuff it into * the tty's flip-buffer. */static intctc_tty_readmodem(ctc_tty_info *info){	int ret = 1;	struct tty_struct *tty;	if ((tty = info->tty)) {		if (info->mcr & UART_MCR_RTS) {			int c = TTY_FLIPBUF_SIZE - tty->flip.count;			struct sk_buff *skb;						if ((c > 0) && (skb = skb_dequeue(&info->rx_queue))) {				int len = skb->len;				if (len > c)					len = c;				memcpy(tty->flip.char_buf_ptr, skb->data, len);				skb_pull(skb, len);				memset(tty->flip.flag_buf_ptr, 0, len);				tty->flip.count += len;				tty->flip.char_buf_ptr += len;				tty->flip.flag_buf_ptr += len;				tty_flip_buffer_push(tty);				if (skb->len > 0)					skb_queue_head(&info->rx_queue, skb);				else {					kfree_skb(skb);					ret = skb_queue_len(&info->rx_queue);				}			}		}	}	return ret;}voidctc_tty_setcarrier(net_device *netdev, int on){	int i;	if ((!driver) || ctc_tty_shuttingdown)		return;	for (i = 0; i < CTC_TTY_MAX_DEVICES; i++)		if (driver->info[i].netdev == netdev) {			ctc_tty_info *info = &driver->info[i];			if (on)				info->msr |= UART_MSR_DCD;			else				info->msr &= ~UART_MSR_DCD;			if ((info->flags & CTC_ASYNC_CHECK_CD) && (!on))				tty_hangup(info->tty);		}}voidctc_tty_netif_rx(struct sk_buff *skb){	int i;	ctc_tty_info *info = NULL;	if (!skb)		return;	if ((!skb->dev) || (!driver) || ctc_tty_shuttingdown) {		dev_kfree_skb(skb);		return;	}	for (i = 0; i < CTC_TTY_MAX_DEVICES; i++)		if (driver->info[i].netdev == skb->dev) {			info = &driver->info[i];			break;		}	if (!info) {		dev_kfree_skb(skb);		return;	}	if (skb->len < 6) {		dev_kfree_skb(skb);		return;	}	if (memcmp(skb->data, &ctc_tty_magic, sizeof(__u32))) {		dev_kfree_skb(skb);		return;	}	skb_pull(skb, sizeof(__u32));	i = *((int *)skb->data);	skb_pull(skb, sizeof(info->mcr));	if (i & UART_MCR_RTS) {		info->msr |= UART_MSR_CTS;		if (info->flags & CTC_ASYNC_CTS_FLOW)			info->tty->hw_stopped = 0;	} else {		info->msr &= ~UART_MSR_CTS;		if (info->flags & CTC_ASYNC_CTS_FLOW)			info->tty->hw_stopped = 1;	}	if (i & UART_MCR_DTR)		info->msr |= UART_MSR_DSR;	else		info->msr &= ~UART_MSR_DSR;	if (skb->len <= 0) {		kfree_skb(skb);		return;	}	/* Try to deliver directly via tty-flip-buf if queue is empty */	if (skb_queue_empty(&info->rx_queue))		if (ctc_tty_try_read(info, skb))			return;	/* Direct deliver failed or queue wasn't empty.	 * Queue up for later dequeueing via timer-irq.	 */	skb_queue_tail(&info->rx_queue, skb);	/* Schedule dequeuing */	queue_task(&info->tq, &tq_immediate);	mark_bh(IMMEDIATE_BH);}static intctc_tty_tint(ctc_tty_info * info){	struct sk_buff *skb = skb_dequeue(&info->tx_queue);	int stopped = (info->tty->hw_stopped || info->tty->stopped);	int wake = 1;	int rc;	if (!info->netdev) {		if (skb)			kfree(skb);		return 0;	}	if (info->flags & CTC_ASYNC_TX_LINESTAT) {		int skb_res = info->netdev->hard_header_len +			sizeof(info->mcr) + sizeof(__u32);		/* If we must update line status,		 * create an empty dummy skb and insert it.		 */		if (skb)			skb_queue_head(&info->tx_queue, skb);		skb = dev_alloc_skb(skb_res);		if (!skb) {			printk(KERN_WARNING			       "ctc_tty: Out of memory in %s%d tint\n",			       CTC_TTY_NAME, info->line);			return 1;		}		skb_reserve(skb, skb_res);		stopped = 0;		wake = 0;	}	if (!skb)		return 0;	if (stopped) {		skb_queue_head(&info->tx_queue, skb);		return 1;	}#if 0	if (skb->len > 0)		printk(KERN_DEBUG "tint: %d %02x\n", skb->len, *(skb->data));	else		printk(KERN_DEBUG "tint: %d STAT\n", skb->len);#endif	memcpy(skb_push(skb, sizeof(info->mcr)), &info->mcr, sizeof(info->mcr));	memcpy(skb_push(skb, sizeof(__u32)), &ctc_tty_magic, sizeof(__u32));	rc = info->netdev->hard_start_xmit(skb, info->netdev);	if (rc) {		skb_pull(skb, sizeof(info->mcr) + sizeof(__u32));		if (skb->len > 0)			skb_queue_head(&info->tx_queue, skb);		else			kfree_skb(skb);	} else {		struct tty_struct *tty = info->tty;		info->flags &= ~CTC_ASYNC_TX_LINESTAT;		if (tty) {			if (wake && (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&			    tty->ldisc.write_wakeup)				(tty->ldisc.write_wakeup)(tty);			wake_up_interruptible(&tty->write_wait);		}	}	return (skb_queue_empty(&info->tx_queue) ? 0 : 1);}/************************************************************ * * Modem-functions * * mostly "stolen" from original Linux-serial.c and friends. * ************************************************************/static inline intctc_tty_paranoia_check(ctc_tty_info * info, kdev_t device, const char *routine){#ifdef MODEM_PARANOIA_CHECK	if (!info) {		printk(KERN_WARNING "ctc_tty: null info_struct for (%d, %d) in %s\n",		       MAJOR(device), MINOR(device), routine);		return 1;	}	if (info->magic != CTC_ASYNC_MAGIC) {		printk(KERN_WARNING "ctc_tty: bad magic for info struct (%d, %d) in %s\n",		       MAJOR(device), MINOR(device), routine);		return 1;	}#endif	return 0;}static voidctc_tty_inject(ctc_tty_info *info, char c){	int skb_res;	struct sk_buff *skb;		if (ctc_tty_shuttingdown)		return;	skb_res = info->netdev->hard_header_len + sizeof(info->mcr) +		sizeof(__u32) + 1;	skb = dev_alloc_skb(skb_res);	if (!skb) {		printk(KERN_WARNING		       "ctc_tty: Out of memory in %s%d tx_inject\n",		       CTC_TTY_NAME, info->line);		return;	}	skb_reserve(skb, skb_res);	*(skb_put(skb, 1)) = c;	skb_queue_head(&info->tx_queue, skb);	queue_task(&info->tq, &tq_immediate);	mark_bh(IMMEDIATE_BH);}static voidctc_tty_transmit_status(ctc_tty_info *info){	if (ctc_tty_shuttingdown)		return;	info->flags |= CTC_ASYNC_TX_LINESTAT;	queue_task(&info->tq, &tq_immediate);	mark_bh(IMMEDIATE_BH);}static voidctc_tty_change_speed(ctc_tty_info * info){	unsigned int cflag;	unsigned int quot;	int i;	if (!info->tty || !info->tty->termios)		return;	cflag = info->tty->termios->c_cflag;	quot = i = cflag & CBAUD;	if (i & CBAUDEX) {		i &= ~CBAUDEX;		if (i < 1 || i > 2)			info->tty->termios->c_cflag &= ~CBAUDEX;		else			i += 15;	}	if (quot) {		info->mcr |= UART_MCR_DTR;		info->mcr |= UART_MCR_RTS;		ctc_tty_transmit_status(info);	} else {		info->mcr &= ~UART_MCR_DTR;		info->mcr &= ~UART_MCR_RTS;		ctc_tty_transmit_status(info);		return;	}	/* CTS flow control flag and modem status interrupts */	if (cflag & CRTSCTS) {		info->flags |= CTC_ASYNC_CTS_FLOW;	} else		info->flags &= ~CTC_ASYNC_CTS_FLOW;	if (cflag & CLOCAL)		info->flags &= ~CTC_ASYNC_CHECK_CD;	else {		info->flags |= CTC_ASYNC_CHECK_CD;	}}

⌨️ 快捷键说明

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