File: /usr/src/linux/drivers/char/n_r3964.c

1     /* r3964 linediscipline for linux
2      *
3      * -----------------------------------------------------------
4      * Copyright by 
5      * Philips Automation Projects
6      * Kassel (Germany)
7      * http://www.pap-philips.de
8      * -----------------------------------------------------------
9      * This software may be used and distributed according to the terms of
10      * the GNU General Public License, incorporated herein by reference.
11      *
12      * Author:
13      * L. Haag
14      *
15      * $Log: n_r3964.c,v $
16      * Revision 1.8  2000/03/23 14:14:54  dwmw2
17      * Fix race in sleeping in r3964_read()
18      *
19      * Revision 1.7  1999/28/08 11:41:50  dwmw2
20      * Port to 2.3 kernel
21      *
22      * Revision 1.6  1998/09/30 00:40:40  dwmw2
23      * Fixed compilation on 2.0.x kernels
24      * Updated to newly registered tty-ldisc number 9
25      *
26      * Revision 1.5  1998/09/04 21:57:36  dwmw2
27      * Signal handling bug fixes, port to 2.1.x.
28      *
29      * Revision 1.4  1998/04/02 20:26:59  lhaag
30      * select, blocking, ...
31      *
32      * Revision 1.3  1998/02/12 18:58:43  root
33      * fixed some memory leaks
34      * calculation of checksum characters
35      *
36      * Revision 1.2  1998/02/07 13:03:34  root
37      * ioctl read_telegram
38      *
39      * Revision 1.1  1998/02/06 19:21:03  root
40      * Initial revision
41      *
42      *
43      */
44     
45     #include <linux/module.h>
46     #include <linux/kernel.h>
47     #include <linux/sched.h>
48     #include <linux/types.h>
49     #include <linux/fcntl.h>
50     #include <linux/interrupt.h>
51     #include <linux/ptrace.h>
52     #include <linux/ioport.h>
53     #include <linux/in.h>
54     #include <linux/slab.h>
55     #include <linux/tty.h>
56     #include <linux/errno.h>
57     #include <linux/string.h>   /* used in new tty drivers */
58     #include <linux/signal.h>   /* used in new tty drivers */
59     #include <linux/ioctl.h>
60     #include <linux/n_r3964.h>
61     #include <linux/poll.h>
62     #include <linux/init.h>
63     #include <asm/uaccess.h>
64     
65     
66     //#define DEBUG_QUEUE
67     
68     /* Log successful handshake and protocol operations  */
69     //#define DEBUG_PROTO_S
70     
71     /* Log handshake and protocol errors: */
72     //#define DEBUG_PROTO_E
73     
74     /* Log Linediscipline operations (open, close, read, write...): */
75     //#define DEBUG_LDISC
76     
77     /* Log module and memory operations (init, cleanup; kmalloc, kfree): */
78     //#define DEBUG_MODUL
79     
80     /* Macro helpers for debug output: */
81     #define TRACE(format, args...) printk("r3964: " format "\n" , ## args);
82     
83     #ifdef DEBUG_MODUL
84     #define TRACE_M(format, args...) printk("r3964: " format "\n" , ## args);
85     #else
86     #define TRACE_M(fmt, arg...) /**/
87     #endif
88     
89     #ifdef DEBUG_PROTO_S
90     #define TRACE_PS(format, args...) printk("r3964: " format "\n" , ## args);
91     #else
92     #define TRACE_PS(fmt, arg...) /**/
93     #endif
94     
95     #ifdef DEBUG_PROTO_E
96     #define TRACE_PE(format, args...) printk("r3964: " format "\n" , ## args);
97     #else
98     #define TRACE_PE(fmt, arg...) /**/
99     #endif
100     
101     #ifdef DEBUG_LDISC
102     #define TRACE_L(format, args...) printk("r3964: " format "\n" , ## args);
103     #else
104     #define TRACE_L(fmt, arg...) /**/
105     #endif
106     
107     #ifdef DEBUG_QUEUE
108     #define TRACE_Q(format, args...) printk("r3964: " format "\n" , ## args);
109     #else
110     #define TRACE_Q(fmt, arg...) /**/
111     #endif
112     
113     static void on_timer_1(void*);
114     static void on_timer_2(void*);
115     static void add_tx_queue(struct r3964_info *, struct r3964_block_header *);
116     static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code);
117     static void put_char(struct r3964_info *pInfo, unsigned char ch);
118     static void trigger_transmit(struct r3964_info *pInfo);
119     static void retry_transmit(struct r3964_info *pInfo);
120     static void transmit_block(struct r3964_info *pInfo);
121     static void receive_char(struct r3964_info *pInfo, const unsigned char c);
122     static void receive_error(struct r3964_info *pInfo, const char flag);
123     static void on_timeout(struct r3964_info *pInfo);
124     static int enable_signals(struct r3964_info *pInfo, pid_t pid, int arg);
125     static int read_telegram(struct r3964_info *pInfo, pid_t pid, unsigned char *buf);
126     static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
127                  int error_code, struct r3964_block_header *pBlock);
128     static struct r3964_message* remove_msg(struct r3964_info *pInfo, 
129                  struct r3964_client_info *pClient);
130     static void remove_client_block(struct r3964_info *pInfo, 
131                     struct r3964_client_info *pClient);
132     
133     static int  r3964_open(struct tty_struct *tty);
134     static void r3964_close(struct tty_struct *tty);
135     static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
136                          unsigned char *buf, size_t nr);
137     static ssize_t r3964_write(struct tty_struct * tty, struct file * file,
138                           const unsigned char * buf, size_t nr);
139     static int r3964_ioctl(struct tty_struct * tty, struct file * file,
140                            unsigned int cmd, unsigned long arg);
141     static void r3964_set_termios(struct tty_struct *tty, struct termios * old);
142     static unsigned int r3964_poll(struct tty_struct * tty, struct file * file,
143     		      struct poll_table_struct  *wait);
144     static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
145                                   char *fp, int count);
146     static int  r3964_receive_room(struct tty_struct *tty);
147     
148     static struct tty_ldisc tty_ldisc_N_R3964 = {
149             TTY_LDISC_MAGIC,       /* magic */
150     	"R3964",               /* name */
151             0,                     /* num */
152             0,                     /* flags */
153             r3964_open,            /* open */
154             r3964_close,           /* close */
155             0,                     /* flush_buffer */
156             0,                     /* chars_in_buffer */
157             r3964_read,            /* read */
158             r3964_write,           /* write */
159             r3964_ioctl,           /* ioctl */
160             r3964_set_termios,     /* set_termios */
161             r3964_poll,            /* poll */            
162             r3964_receive_buf,     /* receive_buf */
163             r3964_receive_room,    /* receive_room */
164             0                      /* write_wakeup */
165     };
166     
167     
168     
169     static void dump_block(const unsigned char *block, unsigned int length)
170     {
171        unsigned int i,j;
172        char linebuf[16*3+1];
173        
174        for(i=0;i<length;i+=16)
175        {
176           for(j=0;(j<16) && (j+i<length);j++)
177           {
178              sprintf(linebuf+3*j,"%02x ",block[i+j]);
179           }
180           linebuf[3*j]='\0';
181           TRACE_PS("%s",linebuf);
182        }
183     }
184     
185              
186     
187     
188     /*************************************************************
189      * Driver initialisation
190      *************************************************************/
191     
192     
193     /*************************************************************
194      * Module support routines
195      *************************************************************/
196     
197     static void __exit r3964_exit(void)
198     {
199        int status;
200        
201        TRACE_M ("cleanup_module()");
202     
203        status=tty_register_ldisc(N_R3964, NULL);
204        
205        if(status!=0)
206        {
207           printk(KERN_ERR "r3964: error unregistering linediscipline: %d\n", status);
208        }
209        else
210        {
211           TRACE_L("linediscipline successfully unregistered");
212        }
213        
214     }
215     
216     static int __init r3964_init(void)
217     {
218        int status;
219        
220        printk ("r3964: Philips r3964 Driver $Revision: 1.8 $\n");
221     
222        /*
223         * Register the tty line discipline
224         */
225        
226        status = tty_register_ldisc (N_R3964, &tty_ldisc_N_R3964);
227        if (status == 0)
228          {
229            TRACE_L("line discipline %d registered", N_R3964);
230            TRACE_L("flags=%x num=%x", tty_ldisc_N_R3964.flags, 
231                    tty_ldisc_N_R3964.num);
232            TRACE_L("open=%x", (int)tty_ldisc_N_R3964.open);
233            TRACE_L("tty_ldisc_N_R3964 = %x", (int)&tty_ldisc_N_R3964);
234          }
235        else
236          {
237            printk (KERN_ERR "r3964: error registering line discipline: %d\n", status);
238          }
239        return status;
240     }
241     
242     module_init(r3964_init);
243     module_exit(r3964_exit);
244     
245     
246     /*************************************************************
247      * Protocol implementation routines
248      *************************************************************/
249     
250     static void on_timer_1(void *arg)
251     {
252        struct r3964_info *pInfo = (struct r3964_info *)arg;
253       
254        if(pInfo->count_down)
255        {
256           if(!--pInfo->count_down)
257           {
258              on_timeout(pInfo);
259           }
260        }
261        queue_task(&pInfo->bh_2, &tq_timer);
262     }
263     
264     static void on_timer_2(void *arg)
265     {
266        struct r3964_info *pInfo = (struct r3964_info *)arg;
267       
268        if(pInfo->count_down)
269        {
270           if(!--pInfo->count_down)
271           {
272              on_timeout(pInfo);
273           }
274        }
275        queue_task(&pInfo->bh_1, &tq_timer);
276     }
277     
278     static void add_tx_queue(struct r3964_info *pInfo, struct r3964_block_header *pHeader)
279     {
280        unsigned long flags;
281        
282        save_flags(flags);
283        cli();
284     
285        pHeader->next = NULL;
286     
287        if(pInfo->tx_last == NULL)
288        {
289           pInfo->tx_first = pInfo->tx_last = pHeader;
290        }
291        else
292        {
293           pInfo->tx_last->next = pHeader;
294           pInfo->tx_last = pHeader;
295        }
296        
297        restore_flags(flags);
298     
299        TRACE_Q("add_tx_queue %x, length %d, tx_first = %x", 
300               (int)pHeader, pHeader->length, (int)pInfo->tx_first );
301     }
302     
303     static void remove_from_tx_queue(struct r3964_info *pInfo, int error_code)
304     {
305        struct r3964_block_header *pHeader;
306        unsigned long flags;
307     #ifdef DEBUG_QUEUE
308        struct r3964_block_header *pDump;
309     #endif
310        
311        pHeader = pInfo->tx_first;
312     
313        if(pHeader==NULL)
314           return;
315     
316     #ifdef DEBUG_QUEUE
317        printk("r3964: remove_from_tx_queue: %x, length %d - ",
318               (int)pHeader, (int)pHeader->length );
319        for(pDump=pHeader;pDump;pDump=pDump->next)
320     	 printk("%x ", (int)pDump);
321        printk("\n");
322     #endif
323     
324     
325        if(pHeader->owner)
326        {
327           if(error_code)
328           {
329               add_msg(pHeader->owner, R3964_MSG_ACK, 0, 
330                       error_code, NULL);
331           }
332           else
333           {
334               add_msg(pHeader->owner, R3964_MSG_ACK, pHeader->length, 
335                       error_code, NULL);
336           }
337           wake_up_interruptible (&pInfo->read_wait);
338        }
339     
340        save_flags(flags);
341        cli();
342     
343        pInfo->tx_first = pHeader->next;
344        if(pInfo->tx_first==NULL)
345        {
346           pInfo->tx_last = NULL;
347        }
348     
349        restore_flags(flags);
350     
351        kfree(pHeader);
352        TRACE_M("remove_from_tx_queue - kfree %x",(int)pHeader);
353     
354        TRACE_Q("remove_from_tx_queue: tx_first = %x, tx_last = %x",
355               (int)pInfo->tx_first, (int)pInfo->tx_last );
356     }
357     
358     static void add_rx_queue(struct r3964_info *pInfo, struct r3964_block_header *pHeader)
359     {
360        unsigned long flags;
361        
362        save_flags(flags);
363        cli();
364     
365        pHeader->next = NULL;
366     
367        if(pInfo->rx_last == NULL)
368        {
369           pInfo->rx_first = pInfo->rx_last = pHeader;
370        }
371        else
372        {
373           pInfo->rx_last->next = pHeader;
374           pInfo->rx_last = pHeader;
375        }
376        pInfo->blocks_in_rx_queue++;
377        
378        restore_flags(flags);
379     
380        TRACE_Q("add_rx_queue: %x, length = %d, rx_first = %x, count = %d",
381               (int)pHeader, pHeader->length,
382               (int)pInfo->rx_first, pInfo->blocks_in_rx_queue);
383     }
384     
385     static void remove_from_rx_queue(struct r3964_info *pInfo,
386                      struct r3964_block_header *pHeader)
387     {
388        unsigned long flags;
389        struct r3964_block_header *pFind;
390        
391        if(pHeader==NULL)
392           return;
393     
394        TRACE_Q("remove_from_rx_queue: rx_first = %x, rx_last = %x, count = %d",
395               (int)pInfo->rx_first, (int)pInfo->rx_last, pInfo->blocks_in_rx_queue );
396        TRACE_Q("remove_from_rx_queue: %x, length %d",
397               (int)pHeader, (int)pHeader->length );
398     
399        save_flags(flags);
400        cli();
401     
402        if(pInfo->rx_first == pHeader)
403        {
404           /* Remove the first block in the linked list: */
405           pInfo->rx_first = pHeader->next;
406           
407           if(pInfo->rx_first==NULL)
408           {
409              pInfo->rx_last = NULL;
410           }
411           pInfo->blocks_in_rx_queue--;
412        }
413        else 
414        {
415           /* Find block to remove: */
416           for(pFind=pInfo->rx_first; pFind; pFind=pFind->next)
417           {
418              if(pFind->next == pHeader) 
419              {
420                 /* Got it. */
421                 pFind->next = pHeader->next;
422                 pInfo->blocks_in_rx_queue--;
423                 if(pFind->next==NULL)
424                 {
425                    /* Oh, removed the last one! */
426                    pInfo->rx_last = pFind;
427                 }
428                 break;
429              }
430           }
431        }
432     
433        restore_flags(flags);
434     
435        kfree(pHeader);
436        TRACE_M("remove_from_rx_queue - kfree %x",(int)pHeader);
437     
438        TRACE_Q("remove_from_rx_queue: rx_first = %x, rx_last = %x, count = %d",
439               (int)pInfo->rx_first, (int)pInfo->rx_last, pInfo->blocks_in_rx_queue );
440     }
441     
442     static void put_char(struct r3964_info *pInfo, unsigned char ch)
443     {
444        struct tty_struct *tty = pInfo->tty;
445     
446        if(tty==NULL)
447           return;
448     
449        if(tty->driver.put_char)
450        {
451           tty->driver.put_char(tty, ch);
452        }
453        pInfo->bcc ^= ch;
454     }
455     
456     static void flush(struct r3964_info *pInfo)
457     {
458        struct tty_struct *tty = pInfo->tty;
459     
460        if(tty==NULL)
461           return;
462     
463        if(tty->driver.flush_chars)
464        {
465           tty->driver.flush_chars(tty);
466        }
467     }
468     
469     static void trigger_transmit(struct r3964_info *pInfo)
470     {
471        unsigned long flags;
472        
473     
474        save_flags(flags);
475        cli();
476     
477        if((pInfo->state == R3964_IDLE) && (pInfo->tx_first!=NULL))
478        {
479           pInfo->state = R3964_TX_REQUEST;
480           pInfo->count_down = R3964_TO_QVZ;
481           pInfo->nRetry=0;
482           pInfo->flags &= ~R3964_ERROR;
483           
484           restore_flags(flags);
485     
486           TRACE_PS("trigger_transmit - sent STX");
487     
488           put_char(pInfo, STX);
489           flush(pInfo);
490     
491           pInfo->bcc = 0;
492        }
493        else
494        {
495           restore_flags(flags);
496        }
497     }
498     
499     static void retry_transmit(struct r3964_info *pInfo)
500     {
501        if(pInfo->nRetry<R3964_MAX_RETRIES)
502        {
503           TRACE_PE("transmission failed. Retry #%d", 
504                  pInfo->nRetry);
505           pInfo->bcc = 0;
506           put_char(pInfo, STX);
507           flush(pInfo);
508           pInfo->state = R3964_TX_REQUEST;
509           pInfo->count_down = R3964_TO_QVZ;
510           pInfo->nRetry++;
511        }
512        else
513        {
514           TRACE_PE("transmission failed after %d retries", 
515                  R3964_MAX_RETRIES);
516     
517           remove_from_tx_queue(pInfo, R3964_TX_FAIL);
518           
519           put_char(pInfo, NAK);
520           flush(pInfo);
521           pInfo->state = R3964_IDLE;
522     
523           trigger_transmit(pInfo);
524        }
525     }
526     
527     
528     static void transmit_block(struct r3964_info *pInfo)
529     {
530        struct tty_struct *tty = pInfo->tty;
531        struct r3964_block_header *pBlock = pInfo->tx_first;
532        int room=0;
533     
534        if((tty==NULL) || (pBlock==NULL))
535        {
536           return;
537        }
538     
539        if(tty->driver.write_room)
540           room=tty->driver.write_room(tty);
541     
542        TRACE_PS("transmit_block %x, room %d, length %d", 
543               (int)pBlock, room, pBlock->length);
544        
545        while(pInfo->tx_position < pBlock->length)
546        {
547           if(room<2)
548              break;
549      
550           if(pBlock->data[pInfo->tx_position]==DLE)
551           {
552              /* send additional DLE char: */
553              put_char(pInfo, DLE);
554           }
555           put_char(pInfo, pBlock->data[pInfo->tx_position++]);
556           
557           room--;
558        }
559     
560        if((pInfo->tx_position == pBlock->length) && (room>=3))
561        {
562           put_char(pInfo, DLE);
563           put_char(pInfo, ETX);
564           if(pInfo->flags & R3964_BCC)
565           {
566              put_char(pInfo, pInfo->bcc);
567           }
568           pInfo->state = R3964_WAIT_FOR_TX_ACK;
569           pInfo->count_down = R3964_TO_QVZ;
570        }
571        flush(pInfo);
572     }
573     
574     static void on_receive_block(struct r3964_info *pInfo)
575     {
576        unsigned int length;
577        struct r3964_client_info *pClient;
578        struct r3964_block_header *pBlock;
579        
580        length=pInfo->rx_position;
581     
582        /* compare byte checksum characters: */
583        if(pInfo->flags & R3964_BCC)
584        {
585           if(pInfo->bcc!=pInfo->last_rx)
586           {
587              TRACE_PE("checksum error - got %x but expected %x",
588                     pInfo->last_rx, pInfo->bcc);
589              pInfo->flags |= R3964_CHECKSUM;
590           }
591        }
592     
593        /* check for errors (parity, overrun,...): */
594        if(pInfo->flags & R3964_ERROR)
595        {
596           TRACE_PE("on_receive_block - transmission failed error %x",
597                  pInfo->flags & R3964_ERROR);
598           
599           put_char(pInfo, NAK);
600           flush(pInfo);
601           if(pInfo->nRetry<R3964_MAX_RETRIES)
602           {
603              pInfo->state=R3964_WAIT_FOR_RX_REPEAT;
604              pInfo->count_down = R3964_TO_RX_PANIC;
605              pInfo->nRetry++;
606           }
607           else
608           {
609              TRACE_PE("on_receive_block - failed after max retries");
610              pInfo->state=R3964_IDLE;
611           }
612           return;
613        }
614     
615        
616        /* received block; submit DLE: */
617        put_char(pInfo, DLE);
618        flush(pInfo);
619        pInfo->count_down=0;
620        TRACE_PS(" rx success: got %d chars", length);
621     
622        /* prepare struct r3964_block_header: */
623        pBlock = kmalloc(length+sizeof(struct r3964_block_header), GFP_KERNEL);
624        TRACE_M("on_receive_block - kmalloc %x",(int)pBlock);
625     
626        if(pBlock==NULL)
627           return;
628     
629        pBlock->length = length;
630        pBlock->data   = ((unsigned char*)pBlock)+sizeof(struct r3964_block_header);
631        pBlock->locks  = 0;
632        pBlock->next   = NULL;
633        pBlock->owner  = NULL;
634     
635        memcpy(pBlock->data, pInfo->rx_buf, length);
636     
637        /* queue block into rx_queue: */
638        add_rx_queue(pInfo, pBlock);
639     
640        /* notify attached client processes: */
641        for(pClient=pInfo->firstClient; pClient; pClient=pClient->next)
642        {
643           if(pClient->sig_flags & R3964_SIG_DATA)
644           {
645              add_msg(pClient, R3964_MSG_DATA, length, R3964_OK, pBlock);
646           }
647        }
648        wake_up_interruptible (&pInfo->read_wait);
649        
650        pInfo->state = R3964_IDLE;
651     
652        trigger_transmit(pInfo);
653     }
654     
655     
656     static void receive_char(struct r3964_info *pInfo, const unsigned char c)
657     {
658        switch(pInfo->state)
659        {
660           case R3964_TX_REQUEST:
661              if(c==DLE)
662              {
663                 TRACE_PS("TX_REQUEST - got DLE");
664     
665                 pInfo->state = R3964_TRANSMITTING;
666                 pInfo->tx_position = 0;
667                 
668                 transmit_block(pInfo);
669              }
670              else if(c==STX)
671              {
672                 if(pInfo->nRetry==0)
673                 {
674                    TRACE_PE("TX_REQUEST - init conflict");
675                    if(pInfo->priority == R3964_SLAVE)
676                    {
677                       goto start_receiving;
678                    }
679                 } 
680                 else 
681                 {
682                    TRACE_PE("TX_REQUEST - secondary init conflict!?"
683                             " Switching to SLAVE mode for next rx.");
684                    goto start_receiving;
685                 }
686              }
687              else
688              {
689                 TRACE_PE("TX_REQUEST - char != DLE: %x", c);
690                 retry_transmit(pInfo);
691              }
692              break;
693           case R3964_TRANSMITTING:
694              if(c==NAK)
695              {
696                 TRACE_PE("TRANSMITTING - got NAK");
697                 retry_transmit(pInfo);
698              }
699              else
700              {
701                 TRACE_PE("TRANSMITTING - got illegal char");
702      
703                 pInfo->state = R3964_WAIT_ZVZ_BEFORE_TX_RETRY;
704                 pInfo->count_down = R3964_TO_ZVZ;
705              }
706              break;
707           case R3964_WAIT_FOR_TX_ACK:
708              if(c==DLE)
709              {
710                 TRACE_PS("WAIT_FOR_TX_ACK - got DLE");
711                 remove_from_tx_queue(pInfo, R3964_OK);
712                 
713                 pInfo->state = R3964_IDLE;
714                 trigger_transmit(pInfo);
715              }
716              else
717              {
718                 retry_transmit(pInfo);
719              }
720              break;
721           case R3964_WAIT_FOR_RX_REPEAT:
722              /* FALLTROUGH */
723           case R3964_IDLE:
724              if(c==STX)
725              {
726                 /* Prevent rx_queue from overflow: */
727                 if(pInfo->blocks_in_rx_queue >= R3964_MAX_BLOCKS_IN_RX_QUEUE)
728                 {
729                    TRACE_PE("IDLE - got STX but no space in rx_queue!");
730                    pInfo->state=R3964_WAIT_FOR_RX_BUF;
731                    pInfo->count_down = R3964_TO_NO_BUF;
732                    break;
733                 }
734     start_receiving:
735                 /* Ok, start receiving: */
736                 TRACE_PS("IDLE - got STX");
737                 pInfo->rx_position = 0;
738                 pInfo->last_rx = 0;
739                 pInfo->flags &= ~R3964_ERROR;
740                 pInfo->state=R3964_RECEIVING;
741                 pInfo->count_down = R3964_TO_ZVZ;
742                 pInfo->nRetry = 0;
743                 put_char(pInfo, DLE);
744                 flush(pInfo);
745                 pInfo->bcc = 0;
746              }
747              break;
748           case R3964_RECEIVING:
749              if(pInfo->rx_position < RX_BUF_SIZE)
750              {
751                 pInfo->bcc ^= c;
752                 
753                 if(c==DLE)
754                 {
755                    if(pInfo->last_rx==DLE)
756                    {
757                       pInfo->last_rx = 0;
758                       goto char_to_buf;
759                    }
760                    pInfo->last_rx = DLE;
761                    break;
762                 } 
763                 else if((c==ETX) && (pInfo->last_rx==DLE))
764                 {
765                    if(pInfo->flags & R3964_BCC)
766                    {
767                       pInfo->state = R3964_WAIT_FOR_BCC;
768                       pInfo->count_down = R3964_TO_ZVZ;
769                    }
770                    else 
771                    {
772                       on_receive_block(pInfo);
773                    }
774                 }
775                 else
776                 {
777                    pInfo->last_rx = c;
778     char_to_buf:
779                    pInfo->rx_buf[pInfo->rx_position++] = c;
780                    pInfo->count_down = R3964_TO_ZVZ;
781                 }
782              }
783             /* else: overflow-msg? BUF_SIZE>MTU; should not happen? */ 
784              break;
785           case R3964_WAIT_FOR_BCC:
786              pInfo->last_rx = c;
787              on_receive_block(pInfo);
788              break;
789        }
790     }
791     
792     static void receive_error(struct r3964_info *pInfo, const char flag)
793     {
794         switch (flag) 
795         {
796         case TTY_NORMAL:
797             break;
798         case TTY_BREAK:
799             TRACE_PE("received break")
800             pInfo->flags |= R3964_BREAK;
801             break;
802         case TTY_PARITY:
803             TRACE_PE("parity error")
804             pInfo->flags |= R3964_PARITY;
805             break;
806         case TTY_FRAME:
807             TRACE_PE("frame error")
808             pInfo->flags |= R3964_FRAME;
809             break;
810         case TTY_OVERRUN:
811             TRACE_PE("frame overrun")
812             pInfo->flags |= R3964_OVERRUN;
813             break;
814         default:
815             TRACE_PE("receive_error - unknown flag %d", flag);
816             pInfo->flags |= R3964_UNKNOWN;
817             break;
818         }
819     }
820     
821     static void on_timeout(struct r3964_info *pInfo)
822     {
823        switch(pInfo->state)
824        {
825           case R3964_TX_REQUEST:
826              TRACE_PE("TX_REQUEST - timeout");
827              retry_transmit(pInfo);
828              break;
829           case R3964_WAIT_ZVZ_BEFORE_TX_RETRY:
830              put_char(pInfo, NAK);
831              flush(pInfo);
832              retry_transmit(pInfo);
833              break;
834           case R3964_WAIT_FOR_TX_ACK:
835              TRACE_PE("WAIT_FOR_TX_ACK - timeout");
836              retry_transmit(pInfo);
837              break;
838           case R3964_WAIT_FOR_RX_BUF:
839              TRACE_PE("WAIT_FOR_RX_BUF - timeout");
840              put_char(pInfo, NAK);
841              flush(pInfo);
842              pInfo->state=R3964_IDLE;
843              break;
844           case R3964_RECEIVING:
845              TRACE_PE("RECEIVING - timeout after %d chars", 
846                       pInfo->rx_position);
847              put_char(pInfo, NAK);
848              flush(pInfo);
849              pInfo->state=R3964_IDLE;
850              break;
851           case R3964_WAIT_FOR_RX_REPEAT:
852              TRACE_PE("WAIT_FOR_RX_REPEAT - timeout");
853              pInfo->state=R3964_IDLE;
854              break;
855           case R3964_WAIT_FOR_BCC:
856              TRACE_PE("WAIT_FOR_BCC - timeout");
857              put_char(pInfo, NAK);
858              flush(pInfo);
859              pInfo->state=R3964_IDLE;
860              break;
861        }
862     }
863     
864     static struct r3964_client_info *findClient(
865       struct r3964_info *pInfo, pid_t pid)
866     {
867        struct r3964_client_info *pClient;
868        
869        for(pClient=pInfo->firstClient; pClient; pClient=pClient->next)
870        {
871           if(pClient->pid == pid)
872           {
873              return pClient;
874           }
875        }
876        return NULL;
877     }
878     
879     static int enable_signals(struct r3964_info *pInfo, pid_t pid, int arg)
880     {
881        struct r3964_client_info *pClient;
882        struct r3964_client_info **ppClient;
883        struct r3964_message *pMsg;
884        
885        if((arg & R3964_SIG_ALL)==0)
886        {
887           /* Remove client from client list */
888           for(ppClient=&pInfo->firstClient; *ppClient; ppClient=&(*ppClient)->next)
889           {
890              pClient = *ppClient;
891              
892              if(pClient->pid == pid)
893              {
894                 TRACE_PS("removing client %d from client list", pid);
895                 *ppClient = pClient->next;
896                 while(pClient->msg_count)
897                 {
898                    pMsg=remove_msg(pInfo, pClient);
899                    if(pMsg)
900                    {
901                       kfree(pMsg);
902                       TRACE_M("enable_signals - msg kfree %x",(int)pMsg);
903                    }
904                 }
905                 kfree(pClient);
906                 TRACE_M("enable_signals - kfree %x",(int)pClient);
907                 return 0;
908              }
909           }
910           return -EINVAL;
911        }
912        else
913        {
914           pClient=findClient(pInfo, pid);
915           if(pClient)
916           {
917              /* update signal options */
918              pClient->sig_flags=arg;
919           } 
920           else 
921           {
922              /* add client to client list */
923              pClient=kmalloc(sizeof(struct r3964_client_info), GFP_KERNEL);
924              TRACE_M("enable_signals - kmalloc %x",(int)pClient);
925              if(pClient==NULL)
926                 return -ENOMEM;
927     
928              TRACE_PS("add client %d to client list", pid);
929              pClient->sig_flags=arg;
930              pClient->pid = pid;
931              pClient->next=pInfo->firstClient;
932              pClient->first_msg = NULL;
933              pClient->last_msg = NULL;
934              pClient->next_block_to_read = NULL;
935              pClient->msg_count = 0;
936              pInfo->firstClient=pClient;
937           }
938        }
939     
940        return 0;
941     }
942     
943     static int read_telegram(struct r3964_info *pInfo, pid_t pid, unsigned char *buf)
944     {
945         struct r3964_client_info *pClient;
946         struct r3964_block_header *block;
947     
948         if(!buf)
949         {
950             return -EINVAL;
951         }
952     
953         pClient=findClient(pInfo,pid);
954         if(pClient==NULL)
955         {
956            return -EINVAL;
957         }
958         
959         block=pClient->next_block_to_read;
960         if(!block)
961         {
962            return 0;
963         }
964         else
965         {
966           if (copy_to_user (buf, block->data, block->length))
967     	return -EFAULT;
968     
969            remove_client_block(pInfo, pClient);
970            return block->length;
971         }
972     
973         return -EINVAL;
974     }
975     
976     static void add_msg(struct r3964_client_info *pClient, int msg_id, int arg,
977                  int error_code, struct r3964_block_header *pBlock)
978     {
979        struct r3964_message *pMsg;
980        unsigned long flags;
981        
982        if(pClient->msg_count<R3964_MAX_MSG_COUNT-1)
983        {
984     queue_the_message:
985     
986           pMsg = kmalloc(sizeof(struct r3964_message), GFP_KERNEL);
987           TRACE_M("add_msg - kmalloc %x",(int)pMsg);
988           if(pMsg==NULL) {
989              return;
990           }
991     
992           save_flags(flags);
993           cli();
994     
995           pMsg->msg_id = msg_id;
996           pMsg->arg    = arg;
997           pMsg->error_code = error_code;
998           pMsg->block  = pBlock;
999           pMsg->next   = NULL;
1000           
1001           if(pClient->last_msg==NULL)
1002           {
1003              pClient->first_msg=pClient->last_msg=pMsg;
1004           }
1005           else
1006           {
1007              pClient->last_msg->next = pMsg;
1008              pClient->last_msg=pMsg;
1009           }
1010     
1011           pClient->msg_count++;
1012     
1013           if(pBlock!=NULL)
1014           {
1015              pBlock->locks++;
1016           }
1017           restore_flags(flags);
1018        }
1019        else
1020        {
1021           if((pClient->last_msg->msg_id == R3964_MSG_ACK)
1022     		 && (pClient->last_msg->error_code==R3964_OVERFLOW))
1023           {
1024              pClient->last_msg->arg++;
1025     		 TRACE_PE("add_msg - inc prev OVERFLOW-msg");
1026           }
1027           else
1028           {
1029              msg_id = R3964_MSG_ACK;
1030              arg = 0;
1031     		 error_code = R3964_OVERFLOW;
1032              pBlock = NULL;
1033     		 TRACE_PE("add_msg - queue OVERFLOW-msg");
1034              goto queue_the_message;
1035           }
1036        }
1037        /* Send SIGIO signal to client process: */
1038        if(pClient->sig_flags & R3964_USE_SIGIO)
1039        {
1040           kill_proc(pClient->pid, SIGIO, 1);
1041        }
1042     }
1043     
1044     static struct r3964_message *remove_msg(struct r3964_info *pInfo,
1045                            struct r3964_client_info *pClient)
1046     {
1047        struct r3964_message *pMsg=NULL;
1048        unsigned long flags;
1049     
1050        if(pClient->first_msg)
1051        {
1052           save_flags(flags);
1053           cli();
1054     
1055           pMsg = pClient->first_msg;
1056           pClient->first_msg = pMsg->next;
1057           if(pClient->first_msg==NULL)
1058           {
1059              pClient->last_msg = NULL;
1060           }
1061           
1062           pClient->msg_count--;
1063           if(pMsg->block)
1064           {
1065             remove_client_block(pInfo, pClient);
1066             pClient->next_block_to_read = pMsg->block;
1067           }
1068           restore_flags(flags);
1069        }
1070        return pMsg;
1071     }
1072     
1073     static void remove_client_block(struct r3964_info *pInfo, 
1074                     struct r3964_client_info *pClient)
1075     {
1076         struct r3964_block_header *block;
1077     
1078         TRACE_PS("remove_client_block PID %d", pClient->pid);
1079     
1080         block=pClient->next_block_to_read;
1081         if(block)
1082         {
1083             block->locks--;
1084             if(block->locks==0)
1085             {
1086                 remove_from_rx_queue(pInfo, block);
1087             }
1088         }
1089         pClient->next_block_to_read = NULL;
1090     }
1091     
1092     
1093     /*************************************************************
1094      * Line discipline routines
1095      *************************************************************/
1096     
1097     static int r3964_open(struct tty_struct *tty)
1098     {
1099        struct r3964_info *pInfo;
1100        
1101        MOD_INC_USE_COUNT;
1102     
1103        TRACE_L("open");
1104        TRACE_L("tty=%x, PID=%d, disc_data=%x", 
1105               (int)tty, current->pid, (int)tty->disc_data);
1106        
1107        pInfo=kmalloc(sizeof(struct r3964_info), GFP_KERNEL); 
1108        TRACE_M("r3964_open - info kmalloc %x",(int)pInfo);
1109     
1110        if(!pInfo)
1111        {
1112           printk(KERN_ERR "r3964: failed to alloc info structure\n");
1113           return -ENOMEM;
1114        }
1115     
1116        pInfo->rx_buf = kmalloc(RX_BUF_SIZE, GFP_KERNEL);
1117        TRACE_M("r3964_open - rx_buf kmalloc %x",(int)pInfo->rx_buf);
1118     
1119        if(!pInfo->rx_buf)
1120        {
1121           printk(KERN_ERR "r3964: failed to alloc receive buffer\n");
1122           kfree(pInfo);
1123           TRACE_M("r3964_open - info kfree %x",(int)pInfo);
1124           return -ENOMEM;
1125        }
1126        
1127        pInfo->tx_buf = kmalloc(TX_BUF_SIZE, GFP_KERNEL);
1128        TRACE_M("r3964_open - tx_buf kmalloc %x",(int)pInfo->tx_buf);
1129     
1130        if(!pInfo->tx_buf)
1131        {
1132           printk(KERN_ERR "r3964: failed to alloc transmit buffer\n");
1133           kfree(pInfo->rx_buf);
1134           TRACE_M("r3964_open - rx_buf kfree %x",(int)pInfo->rx_buf);
1135           kfree(pInfo);
1136           TRACE_M("r3964_open - info kfree %x",(int)pInfo);
1137           return -ENOMEM;
1138        }
1139     
1140        pInfo->tty = tty;
1141        init_waitqueue_head (&pInfo->read_wait);
1142        pInfo->priority = R3964_MASTER;
1143        pInfo->rx_first = pInfo->rx_last = NULL;
1144        pInfo->tx_first = pInfo->tx_last = NULL;
1145        pInfo->rx_position = 0;
1146        pInfo->tx_position = 0;
1147        pInfo->last_rx = 0;
1148        pInfo->blocks_in_rx_queue = 0;
1149        pInfo->firstClient=NULL;
1150        pInfo->state=R3964_IDLE;
1151        pInfo->flags = R3964_DEBUG;
1152        pInfo->count_down = 0;
1153        pInfo->nRetry = 0;
1154        
1155        tty->disc_data = pInfo;
1156     
1157        /*
1158         * Add 'on_timer' to timer task queue
1159         * (will be called from timer bh)
1160         */
1161        INIT_LIST_HEAD(&pInfo->bh_1.list);
1162        pInfo->bh_1.sync = 0;
1163        pInfo->bh_1.routine = &on_timer_1;
1164        pInfo->bh_1.data = pInfo;
1165        
1166        INIT_LIST_HEAD(&pInfo->bh_2.list);
1167        pInfo->bh_2.sync = 0;
1168        pInfo->bh_2.routine = &on_timer_2;
1169        pInfo->bh_2.data = pInfo;
1170     
1171        queue_task(&pInfo->bh_1, &tq_timer);
1172     
1173        return 0;
1174     }
1175     
1176     static void r3964_close(struct tty_struct *tty)
1177     {
1178        struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
1179        struct r3964_client_info *pClient, *pNext;
1180        struct r3964_message *pMsg;
1181        struct r3964_block_header *pHeader, *pNextHeader;
1182        unsigned long flags;
1183     
1184        TRACE_L("close");
1185     
1186         /*
1187          * Make sure that our task queue isn't activated.  If it
1188          * is, take it out of the linked list.
1189          */
1190         spin_lock_irqsave(&tqueue_lock, flags);
1191         if (pInfo->bh_1.sync)
1192         	list_del(&pInfo->bh_1.list);
1193         if (pInfo->bh_2.sync)
1194         	list_del(&pInfo->bh_2.list);
1195         spin_unlock_irqrestore(&tqueue_lock, flags);
1196     
1197        /* Remove client-structs and message queues: */
1198         pClient=pInfo->firstClient;
1199         while(pClient)
1200         {
1201            pNext=pClient->next;
1202            while(pClient->msg_count)
1203            {
1204               pMsg=remove_msg(pInfo, pClient);
1205               if(pMsg)
1206               {
1207                  kfree(pMsg);
1208                  TRACE_M("r3964_close - msg kfree %x",(int)pMsg);
1209               }
1210            }
1211            kfree(pClient);
1212            TRACE_M("r3964_close - client kfree %x",(int)pClient);
1213            pClient=pNext;
1214         }
1215         /* Remove jobs from tx_queue: */
1216     	save_flags(flags);
1217             cli();
1218     	pHeader=pInfo->tx_first;
1219     	pInfo->tx_first=pInfo->tx_last=NULL;
1220     	restore_flags(flags);
1221     	
1222         while(pHeader)
1223     	{
1224     	   pNextHeader=pHeader->next;
1225     	   kfree(pHeader);
1226     	   pHeader=pNextHeader;
1227     	}
1228     
1229         /* Free buffers: */
1230         wake_up_interruptible(&pInfo->read_wait);
1231         kfree(pInfo->rx_buf);
1232         TRACE_M("r3964_close - rx_buf kfree %x",(int)pInfo->rx_buf);
1233         kfree(pInfo->tx_buf);
1234         TRACE_M("r3964_close - tx_buf kfree %x",(int)pInfo->tx_buf);
1235         kfree(pInfo);
1236         TRACE_M("r3964_close - info kfree %x",(int)pInfo);
1237     
1238         MOD_DEC_USE_COUNT;
1239     }
1240     
1241     static ssize_t r3964_read(struct tty_struct *tty, struct file *file,
1242     			  unsigned char *buf, size_t nr)
1243     {
1244        struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
1245        struct r3964_client_info *pClient;
1246        struct r3964_message *pMsg;
1247        struct r3964_client_message theMsg;
1248        DECLARE_WAITQUEUE (wait, current);
1249        
1250        int pid = current->pid;
1251        int count;
1252        
1253        TRACE_L("read()");
1254      
1255        pClient=findClient(pInfo, pid);
1256        if(pClient)
1257        {
1258           pMsg = remove_msg(pInfo, pClient);
1259           if(pMsg==NULL)
1260           {
1261     		 /* no messages available. */
1262              if (file->f_flags & O_NONBLOCK)
1263     		 {
1264                 return -EAGAIN;
1265     		 }
1266              /* block until there is a message: */
1267              add_wait_queue(&pInfo->read_wait, &wait);
1268     repeat:
1269              current->state = TASK_INTERRUPTIBLE;
1270              pMsg = remove_msg(pInfo, pClient);
1271     	 if (!pMsg && !signal_pending(current))
1272     		 {
1273                 schedule();
1274                 goto repeat;
1275              }
1276              current->state = TASK_RUNNING;
1277              remove_wait_queue(&pInfo->read_wait, &wait);
1278           }
1279           
1280           /* If we still haven't got a message, we must have been signalled */
1281     
1282           if (!pMsg) return -EINTR;
1283     
1284           /* deliver msg to client process: */
1285           theMsg.msg_id = pMsg->msg_id;
1286           theMsg.arg    = pMsg->arg;
1287           theMsg.error_code = pMsg->error_code;
1288           count = sizeof(struct r3964_client_message);
1289     
1290           kfree(pMsg);
1291           TRACE_M("r3964_read - msg kfree %x",(int)pMsg);
1292     
1293           if (copy_to_user(buf,&theMsg, count))
1294     	return -EFAULT;
1295     
1296           TRACE_PS("read - return %d", count);
1297           return count;
1298        }
1299        return -EPERM;
1300     }
1301     
1302     static ssize_t r3964_write(struct tty_struct * tty, struct file * file,
1303     			   const unsigned char *data, size_t count)
1304     {
1305        struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
1306        struct r3964_block_header *pHeader;
1307        struct r3964_client_info *pClient;
1308        unsigned char *new_data;
1309        int status;
1310        int pid;
1311        
1312        TRACE_L("write request, %d characters", count);
1313     /* 
1314      * Verify the pointers 
1315      */
1316     
1317        if(!pInfo)
1318           return -EIO;
1319     
1320        status = verify_area (VERIFY_READ, data, count);
1321        if (status != 0) 
1322        {
1323           return status;
1324        }
1325     
1326     /*
1327      * Ensure that the caller does not wish to send too much.
1328      */
1329        if (count > R3964_MTU) 
1330        {
1331           if (pInfo->flags & R3964_DEBUG)
1332           {
1333              TRACE_L (KERN_WARNING
1334                      "r3964_write: truncating user packet "
1335                      "from %u to mtu %d", count, R3964_MTU);
1336           }
1337           count = R3964_MTU;
1338        }
1339     /*
1340      * Allocate a buffer for the data and fetch it from the user space.
1341      */
1342        new_data = kmalloc (count+sizeof(struct r3964_block_header), GFP_KERNEL);
1343        TRACE_M("r3964_write - kmalloc %x",(int)new_data);
1344        if (new_data == NULL) {
1345           if (pInfo->flags & R3964_DEBUG)
1346           {
1347              printk (KERN_ERR
1348                    "r3964_write: no memory\n");
1349           }
1350           return -ENOSPC;
1351        }
1352        
1353        pHeader = (struct r3964_block_header *)new_data;
1354        pHeader->data = new_data + sizeof(struct r3964_block_header);
1355        pHeader->length = count;
1356        pHeader->locks = 0;
1357        pHeader->owner = NULL;
1358        
1359        pid=current->pid;
1360        
1361        pClient=findClient(pInfo, pid);
1362        if(pClient)
1363        {
1364           pHeader->owner = pClient;
1365        }
1366     
1367        copy_from_user (pHeader->data, data, count); /* We already verified this */
1368     
1369        if(pInfo->flags & R3964_DEBUG)
1370        {
1371           dump_block(pHeader->data, count);
1372        }
1373     
1374     /*
1375      * Add buffer to transmit-queue:
1376      */
1377        add_tx_queue(pInfo, pHeader);
1378        trigger_transmit(pInfo);
1379        
1380        return 0;
1381     }
1382     
1383     static int r3964_ioctl(struct tty_struct * tty, struct file * file,
1384                    unsigned int cmd, unsigned long arg)
1385     {
1386        struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
1387        if(pInfo==NULL)
1388           return -EINVAL;
1389        switch(cmd)
1390        {
1391           case R3964_ENABLE_SIGNALS:
1392              return enable_signals(pInfo, current->pid, arg);
1393           case R3964_SETPRIORITY:
1394              if(arg<R3964_MASTER || arg>R3964_SLAVE)
1395                 return -EINVAL;
1396              pInfo->priority = arg & 0xff;
1397              return 0;
1398           case R3964_USE_BCC:
1399                  if(arg)
1400                 pInfo->flags |= R3964_BCC;
1401              else
1402                 pInfo->flags &= ~R3964_BCC;
1403              return 0;
1404           case R3964_READ_TELEGRAM:
1405              return read_telegram(pInfo, current->pid, (unsigned char *)arg);
1406           default:
1407              return -ENOIOCTLCMD;
1408        }
1409     }
1410     
1411     static void r3964_set_termios(struct tty_struct *tty, struct termios * old)
1412     {
1413        TRACE_L("set_termios");
1414     }
1415     
1416     /* Called without the kernel lock held - fine */
1417     static unsigned int r3964_poll(struct tty_struct * tty, struct file * file,
1418     		      struct poll_table_struct *wait)
1419     {
1420        struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
1421        int pid=current->pid;
1422        struct r3964_client_info *pClient;
1423        struct r3964_message *pMsg=NULL;
1424        unsigned long flags;
1425        int result = POLLOUT;
1426     
1427        TRACE_L("POLL");
1428     
1429        pClient=findClient(pInfo,pid);
1430        if(pClient)
1431          {
1432            poll_wait(file, &pInfo->read_wait, wait);
1433            save_flags(flags);
1434            cli();
1435            pMsg=pClient->first_msg;
1436            restore_flags(flags);
1437            if(pMsg)
1438     	   result |= POLLIN | POLLRDNORM;
1439          }
1440        else
1441          {
1442            result = -EINVAL;
1443          }
1444        return result;
1445     }
1446     
1447     static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
1448                                   char *fp, int count)
1449     {
1450        struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
1451         const unsigned char *p;
1452         char *f, flags = 0;
1453         int i;
1454     
1455         for (i=count, p = cp, f = fp; i; i--, p++) {
1456             if (f)
1457                 flags = *f++;
1458             if(flags==TTY_NORMAL)
1459             {
1460                 receive_char(pInfo, *p);
1461             }
1462             else
1463             {
1464                 receive_error(pInfo, flags);
1465             }
1466             
1467         }
1468     }
1469     
1470     static int r3964_receive_room(struct tty_struct *tty)
1471     {
1472        TRACE_L("receive_room");
1473        return -1;
1474     }
1475     
1476     
1477     MODULE_LICENSE("GPL");
1478     
1479     EXPORT_NO_SYMBOLS;
1480