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