欢迎来到虫虫下载站 | 资源下载 资源专辑 关于我们
虫虫下载站

n_r3964.c

linux 内核源代码
C
第 1 页 / 共 3 页
字号:
/* r3964 linediscipline for linux * * ----------------------------------------------------------- * Copyright by  * Philips Automation Projects * Kassel (Germany) * http://www.pap-philips.de * ----------------------------------------------------------- * This software may be used and distributed according to the terms of * the GNU General Public License, incorporated herein by reference. * * Author: * L. Haag * * $Log: n_r3964.c,v $ * Revision 1.10  2001/03/18 13:02:24  dwmw2 * Fix timer usage, use spinlocks properly. * * Revision 1.9  2001/03/18 12:52:14  dwmw2 * Merge changes in 2.4.2 * * Revision 1.8  2000/03/23 14:14:54  dwmw2 * Fix race in sleeping in r3964_read() * * Revision 1.7  1999/28/08 11:41:50  dwmw2 * Port to 2.3 kernel * * Revision 1.6  1998/09/30 00:40:40  dwmw2 * Fixed compilation on 2.0.x kernels * Updated to newly registered tty-ldisc number 9 * * Revision 1.5  1998/09/04 21:57:36  dwmw2 * Signal handling bug fixes, port to 2.1.x. * * Revision 1.4  1998/04/02 20:26:59  lhaag * select, blocking, ... * * Revision 1.3  1998/02/12 18:58:43  root * fixed some memory leaks * calculation of checksum characters * * Revision 1.2  1998/02/07 13:03:34  root * ioctl read_telegram * * Revision 1.1  1998/02/06 19:21:03  root * Initial revision * * */#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/types.h>#include <linux/fcntl.h>#include <linux/interrupt.h>#include <linux/ptrace.h>#include <linux/ioport.h>#include <linux/in.h>#include <linux/slab.h>#include <linux/tty.h>#include <linux/errno.h>#include <linux/string.h>	/* used in new tty drivers */#include <linux/signal.h>	/* used in new tty drivers */#include <linux/ioctl.h>#include <linux/n_r3964.h>#include <linux/poll.h>#include <linux/init.h>#include <asm/uaccess.h>/*#define DEBUG_QUEUE*//* Log successful handshake and protocol operations  *//*#define DEBUG_PROTO_S*//* Log handshake and protocol errors: *//*#define DEBUG_PROTO_E*//* Log Linediscipline operations (open, close, read, write...): *//*#define DEBUG_LDISC*//* Log module and memory operations (init, cleanup; kmalloc, kfree): *//*#define DEBUG_MODUL*//* Macro helpers for debug output: */#define TRACE(format, args...) printk("r3964: " format "\n" , ## args)#ifdef DEBUG_MODUL#define TRACE_M(format, args...) printk("r3964: " format "\n" , ## args)#else#define TRACE_M(fmt, arg...) do {} while (0)#endif#ifdef DEBUG_PROTO_S#define TRACE_PS(format, args...) printk("r3964: " format "\n" , ## args)#else#define TRACE_PS(fmt, arg...) do {} while (0)#endif#ifdef DEBUG_PROTO_E#define TRACE_PE(format, args...) printk("r3964: " format "\n" , ## args)#else#define TRACE_PE(fmt, arg...) do {} while (0)#endif#ifdef DEBUG_LDISC#define TRACE_L(format, args...) printk("r3964: " format "\n" , ## args)#else#define TRACE_L(fmt, arg...) do {} while (0)#endif#ifdef DEBUG_QUEUE#define TRACE_Q(format, args...) printk("r3964: " format "\n" , ## args)#else#define TRACE_Q(fmt, arg...) do {} while (0)#endifstatic void add_tx_queue(struct r3964_info *, struct r3964_block_header *);static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code);static void put_char(struct r3964_info *pInfo, unsigned char ch);static void trigger_transmit(struct r3964_info *pInfo);static void retry_transmit(struct r3964_info *pInfo);static void transmit_block(struct r3964_info *pInfo);static void receive_char(struct r3964_info *pInfo, const unsigned char c);static void receive_error(struct r3964_info *pInfo, const char flag);static void on_timeout(unsigned long priv);static int enable_signals(struct r3964_info *pInfo, struct pid *pid, int arg);static int read_telegram(struct r3964_info *pInfo, struct pid *pid,		unsigned char __user * buf);static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,		int error_code, struct r3964_block_header *pBlock);static struct r3964_message *remove_msg(struct r3964_info *pInfo,		struct r3964_client_info *pClient);static void remove_client_block(struct r3964_info *pInfo,		struct r3964_client_info *pClient);static int r3964_open(struct tty_struct *tty);static void r3964_close(struct tty_struct *tty);static ssize_t r3964_read(struct tty_struct *tty, struct file *file,		unsigned char __user * buf, size_t nr);static ssize_t r3964_write(struct tty_struct *tty, struct file *file,		const unsigned char *buf, size_t nr);static int r3964_ioctl(struct tty_struct *tty, struct file *file,		unsigned int cmd, unsigned long arg);static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old);static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,		struct poll_table_struct *wait);static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,		char *fp, int count);static struct tty_ldisc tty_ldisc_N_R3964 = {	.owner = THIS_MODULE,	.magic = TTY_LDISC_MAGIC,	.name = "R3964",	.open = r3964_open,	.close = r3964_close,	.read = r3964_read,	.write = r3964_write,	.ioctl = r3964_ioctl,	.set_termios = r3964_set_termios,	.poll = r3964_poll,	.receive_buf = r3964_receive_buf,};static void dump_block(const unsigned char *block, unsigned int length){	unsigned int i, j;	char linebuf[16 * 3 + 1];	for (i = 0; i < length; i += 16) {		for (j = 0; (j < 16) && (j + i < length); j++) {			sprintf(linebuf + 3 * j, "%02x ", block[i + j]);		}		linebuf[3 * j] = '\0';		TRACE_PS("%s", linebuf);	}}/************************************************************* * Driver initialisation *************************************************************//************************************************************* * Module support routines *************************************************************/static void __exit r3964_exit(void){	int status;	TRACE_M("cleanup_module()");	status = tty_unregister_ldisc(N_R3964);	if (status != 0) {		printk(KERN_ERR "r3964: error unregistering linediscipline: "				"%d\n", status);	} else {		TRACE_L("linediscipline successfully unregistered");	}}static int __init r3964_init(void){	int status;	printk("r3964: Philips r3964 Driver $Revision: 1.10 $\n");	/*	 * Register the tty line discipline	 */	status = tty_register_ldisc(N_R3964, &tty_ldisc_N_R3964);	if (status == 0) {		TRACE_L("line discipline %d registered", N_R3964);		TRACE_L("flags=%x num=%x", tty_ldisc_N_R3964.flags,			tty_ldisc_N_R3964.num);		TRACE_L("open=%p", tty_ldisc_N_R3964.open);		TRACE_L("tty_ldisc_N_R3964 = %p", &tty_ldisc_N_R3964);	} else {		printk(KERN_ERR "r3964: error registering line discipline: "				"%d\n", status);	}	return status;}module_init(r3964_init);module_exit(r3964_exit);/************************************************************* * Protocol implementation routines *************************************************************/static void add_tx_queue(struct r3964_info *pInfo,			 struct r3964_block_header *pHeader){	unsigned long flags;	spin_lock_irqsave(&pInfo->lock, flags);	pHeader->next = NULL;	if (pInfo->tx_last == NULL) {		pInfo->tx_first = pInfo->tx_last = pHeader;	} else {		pInfo->tx_last->next = pHeader;		pInfo->tx_last = pHeader;	}	spin_unlock_irqrestore(&pInfo->lock, flags);	TRACE_Q("add_tx_queue %p, length %d, tx_first = %p",		pHeader, pHeader->length, pInfo->tx_first);}static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code){	struct r3964_block_header *pHeader;	unsigned long flags;#ifdef DEBUG_QUEUE	struct r3964_block_header *pDump;#endif	pHeader = pInfo->tx_first;	if (pHeader == NULL)		return;#ifdef DEBUG_QUEUE	printk("r3964: remove_from_tx_queue: %p, length %u - ",		pHeader, pHeader->length);	for (pDump = pHeader; pDump; pDump = pDump->next)		printk("%p ", pDump);	printk("\n");#endif	if (pHeader->owner) {		if (error_code) {			add_msg(pHeader->owner, R3964_MSG_ACK, 0,				error_code, NULL);		} else {			add_msg(pHeader->owner, R3964_MSG_ACK, pHeader->length,				error_code, NULL);		}		wake_up_interruptible(&pInfo->read_wait);	}	spin_lock_irqsave(&pInfo->lock, flags);	pInfo->tx_first = pHeader->next;	if (pInfo->tx_first == NULL) {		pInfo->tx_last = NULL;	}	spin_unlock_irqrestore(&pInfo->lock, flags);	kfree(pHeader);	TRACE_M("remove_from_tx_queue - kfree %p", pHeader);	TRACE_Q("remove_from_tx_queue: tx_first = %p, tx_last = %p",		pInfo->tx_first, pInfo->tx_last);}static void add_rx_queue(struct r3964_info *pInfo,			 struct r3964_block_header *pHeader){	unsigned long flags;	spin_lock_irqsave(&pInfo->lock, flags);	pHeader->next = NULL;	if (pInfo->rx_last == NULL) {		pInfo->rx_first = pInfo->rx_last = pHeader;	} else {		pInfo->rx_last->next = pHeader;		pInfo->rx_last = pHeader;	}	pInfo->blocks_in_rx_queue++;	spin_unlock_irqrestore(&pInfo->lock, flags);	TRACE_Q("add_rx_queue: %p, length = %d, rx_first = %p, count = %d",		pHeader, pHeader->length,		pInfo->rx_first, pInfo->blocks_in_rx_queue);}static void remove_from_rx_queue(struct r3964_info *pInfo,				 struct r3964_block_header *pHeader){	unsigned long flags;	struct r3964_block_header *pFind;	if (pHeader == NULL)		return;	TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d",		pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue);	TRACE_Q("remove_from_rx_queue: %p, length %u",		pHeader, pHeader->length);	spin_lock_irqsave(&pInfo->lock, flags);	if (pInfo->rx_first == pHeader) {		/* Remove the first block in the linked list: */		pInfo->rx_first = pHeader->next;		if (pInfo->rx_first == NULL) {			pInfo->rx_last = NULL;		}		pInfo->blocks_in_rx_queue--;	} else {		/* Find block to remove: */		for (pFind = pInfo->rx_first; pFind; pFind = pFind->next) {			if (pFind->next == pHeader) {				/* Got it. */				pFind->next = pHeader->next;				pInfo->blocks_in_rx_queue--;				if (pFind->next == NULL) {					/* Oh, removed the last one! */					pInfo->rx_last = pFind;				}				break;			}		}	}	spin_unlock_irqrestore(&pInfo->lock, flags);	kfree(pHeader);	TRACE_M("remove_from_rx_queue - kfree %p", pHeader);	TRACE_Q("remove_from_rx_queue: rx_first = %p, rx_last = %p, count = %d",		pInfo->rx_first, pInfo->rx_last, pInfo->blocks_in_rx_queue);}static void put_char(struct r3964_info *pInfo, unsigned char ch){	struct tty_struct *tty = pInfo->tty;	if (tty == NULL)		return;	if (tty->driver->put_char) {		tty->driver->put_char(tty, ch);	}	pInfo->bcc ^= ch;}static void flush(struct r3964_info *pInfo){	struct tty_struct *tty = pInfo->tty;	if (tty == NULL)		return;	if (tty->driver->flush_chars) {		tty->driver->flush_chars(tty);	}}static void trigger_transmit(struct r3964_info *pInfo){	unsigned long flags;	spin_lock_irqsave(&pInfo->lock, flags);	if ((pInfo->state == R3964_IDLE) && (pInfo->tx_first != NULL)) {		pInfo->state = R3964_TX_REQUEST;		pInfo->nRetry = 0;		pInfo->flags &= ~R3964_ERROR;		mod_timer(&pInfo->tmr, jiffies + R3964_TO_QVZ);		spin_unlock_irqrestore(&pInfo->lock, flags);		TRACE_PS("trigger_transmit - sent STX");		put_char(pInfo, STX);		flush(pInfo);		pInfo->bcc = 0;	} else {		spin_unlock_irqrestore(&pInfo->lock, flags);	}}

⌨️ 快捷键说明

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