📄 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.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...) /**/#endif#ifdef DEBUG_PROTO_S#define TRACE_PS(format, args...) printk("r3964: " format "\n" , ## args);#else#define TRACE_PS(fmt, arg...) /**/#endif#ifdef DEBUG_PROTO_E#define TRACE_PE(format, args...) printk("r3964: " format "\n" , ## args);#else#define TRACE_PE(fmt, arg...) /**/#endif#ifdef DEBUG_LDISC#define TRACE_L(format, args...) printk("r3964: " format "\n" , ## args);#else#define TRACE_L(fmt, arg...) /**/#endif#ifdef DEBUG_QUEUE#define TRACE_Q(format, args...) printk("r3964: " format "\n" , ## args);#else#define TRACE_Q(fmt, arg...) /**/#endifstatic void on_timer_1(void*);static void on_timer_2(void*);static 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(struct r3964_info *pInfo);static int enable_signals(struct r3964_info *pInfo, pid_t pid, int arg);static int read_telegram(struct r3964_info *pInfo, pid_t pid, unsigned char *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 *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 termios * 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 int r3964_receive_room(struct tty_struct *tty);static struct tty_ldisc tty_ldisc_N_R3964 = { TTY_LDISC_MAGIC, /* magic */ "R3964", /* name */ 0, /* num */ 0, /* flags */ r3964_open, /* open */ r3964_close, /* close */ 0, /* flush_buffer */ 0, /* chars_in_buffer */ r3964_read, /* read */ r3964_write, /* write */ r3964_ioctl, /* ioctl */ r3964_set_termios, /* set_termios */ r3964_poll, /* poll */ r3964_receive_buf, /* receive_buf */ r3964_receive_room, /* receive_room */ 0 /* write_wakeup */};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_register_ldisc(N_R3964, NULL); 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.8 $\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=%x", (int)tty_ldisc_N_R3964.open); TRACE_L("tty_ldisc_N_R3964 = %x", (int)&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 on_timer_1(void *arg){ struct r3964_info *pInfo = (struct r3964_info *)arg; if(pInfo->count_down) { if(!--pInfo->count_down) { on_timeout(pInfo); } } queue_task(&pInfo->bh_2, &tq_timer);}static void on_timer_2(void *arg){ struct r3964_info *pInfo = (struct r3964_info *)arg; if(pInfo->count_down) { if(!--pInfo->count_down) { on_timeout(pInfo); } } queue_task(&pInfo->bh_1, &tq_timer);}static void add_tx_queue(struct r3964_info *pInfo, struct r3964_block_header *pHeader){ unsigned long flags; save_flags(flags); cli(); 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; } restore_flags(flags); TRACE_Q("add_tx_queue %x, length %d, tx_first = %x", (int)pHeader, pHeader->length, (int)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: %x, length %d - ", (int)pHeader, (int)pHeader->length ); for(pDump=pHeader;pDump;pDump=pDump->next) printk("%x ", (int)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); } save_flags(flags); cli(); pInfo->tx_first = pHeader->next; if(pInfo->tx_first==NULL) { pInfo->tx_last = NULL; } restore_flags(flags); kfree(pHeader); TRACE_M("remove_from_tx_queue - kfree %x",(int)pHeader); TRACE_Q("remove_from_tx_queue: tx_first = %x, tx_last = %x", (int)pInfo->tx_first, (int)pInfo->tx_last );}static void add_rx_queue(struct r3964_info *pInfo, struct r3964_block_header *pHeader){ unsigned long flags; save_flags(flags); cli(); 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++; restore_flags(flags); TRACE_Q("add_rx_queue: %x, length = %d, rx_first = %x, count = %d", (int)pHeader, pHeader->length, (int)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 = %x, rx_last = %x, count = %d", (int)pInfo->rx_first, (int)pInfo->rx_last, pInfo->blocks_in_rx_queue ); TRACE_Q("remove_from_rx_queue: %x, length %d", (int)pHeader, (int)pHeader->length ); save_flags(flags); cli(); 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; } } } restore_flags(flags); kfree(pHeader); TRACE_M("remove_from_rx_queue - kfree %x",(int)pHeader); TRACE_Q("remove_from_rx_queue: rx_first = %x, rx_last = %x, count = %d", (int)pInfo->rx_first, (int)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; save_flags(flags); cli(); if((pInfo->state == R3964_IDLE) && (pInfo->tx_first!=NULL)) { pInfo->state = R3964_TX_REQUEST; pInfo->count_down = R3964_TO_QVZ; pInfo->nRetry=0; pInfo->flags &= ~R3964_ERROR; restore_flags(flags); TRACE_PS("trigger_transmit - sent STX"); put_char(pInfo, STX); flush(pInfo); pInfo->bcc = 0; } else {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -