n_r3964.c
字号:
/* 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 + -