~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/drivers/char/n_r3964.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 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/malloc.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 successfull 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 int  r3964_read(struct tty_struct *tty, struct file *file,
136                      unsigned char *buf, unsigned int nr);
137 static int  r3964_write(struct tty_struct * tty, struct file * file,
138                       const unsigned char * buf, unsigned int 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       save_flags(flags);
987       cli();
988 
989       pMsg = kmalloc(sizeof(struct r3964_message), GFP_KERNEL);
990       TRACE_M("add_msg - kmalloc %x",(int)pMsg);
991       if(pMsg==NULL)
992          return;
993 
994       pMsg->msg_id = msg_id;
995       pMsg->arg    = arg;
996       pMsg->error_code = error_code;
997       pMsg->block  = pBlock;
998       pMsg->next   = NULL;
999       
1000       if(pClient->last_msg==NULL)
1001       {
1002          pClient->first_msg=pClient->last_msg=pMsg;
1003       }
1004       else
1005       {
1006          pClient->last_msg->next = pMsg;
1007          pClient->last_msg=pMsg;
1008       }
1009 
1010       pClient->msg_count++;
1011 
1012       if(pBlock!=NULL)
1013       {
1014          pBlock->locks++;
1015       }
1016       restore_flags(flags);
1017    }
1018    else
1019    {
1020       if((pClient->last_msg->msg_id == R3964_MSG_ACK)
1021                  && (pClient->last_msg->error_code==R3964_OVERFLOW))
1022       {
1023          pClient->last_msg->arg++;
1024                  TRACE_PE("add_msg - inc prev OVERFLOW-msg");
1025       }
1026       else
1027       {
1028          msg_id = R3964_MSG_ACK;
1029          arg = 0;
1030                  error_code = R3964_OVERFLOW;
1031          pBlock = NULL;
1032                  TRACE_PE("add_msg - queue OVERFLOW-msg");
1033          goto queue_the_message;
1034       }
1035    }
1036    /* Send SIGIO signal to client process: */
1037    if(pClient->sig_flags & R3964_USE_SIGIO)
1038    {
1039       kill_proc(pClient->pid, SIGIO, 1);
1040    }
1041 }
1042 
1043 static struct r3964_message *remove_msg(struct r3964_info *pInfo,
1044                        struct r3964_client_info *pClient)
1045 {
1046    struct r3964_message *pMsg=NULL;
1047    unsigned long flags;
1048 
1049    if(pClient->first_msg)
1050    {
1051       save_flags(flags);
1052       cli();
1053 
1054       pMsg = pClient->first_msg;
1055       pClient->first_msg = pMsg->next;
1056       if(pClient->first_msg==NULL)
1057       {
1058          pClient->last_msg = NULL;
1059       }
1060       
1061       pClient->msg_count--;
1062       if(pMsg->block)
1063       {
1064         remove_client_block(pInfo, pClient);
1065         pClient->next_block_to_read = pMsg->block;
1066       }
1067       restore_flags(flags);
1068    }
1069    return pMsg;
1070 }
1071 
1072 static void remove_client_block(struct r3964_info *pInfo, 
1073                 struct r3964_client_info *pClient)
1074 {
1075     struct r3964_block_header *block;
1076 
1077     TRACE_PS("remove_client_block PID %d", pClient->pid);
1078 
1079     block=pClient->next_block_to_read;
1080     if(block)
1081     {
1082         block->locks--;
1083         if(block->locks==0)
1084         {
1085             remove_from_rx_queue(pInfo, block);
1086         }
1087     }
1088     pClient->next_block_to_read = NULL;
1089 }
1090 
1091 
1092 /*************************************************************
1093  * Line discipline routines
1094  *************************************************************/
1095 
1096 static int r3964_open(struct tty_struct *tty)
1097 {
1098    struct r3964_info *pInfo;
1099    
1100    MOD_INC_USE_COUNT;
1101 
1102    TRACE_L("open");
1103    TRACE_L("tty=%x, PID=%d, disc_data=%x", 
1104           (int)tty, current->pid, (int)tty->disc_data);
1105    
1106    pInfo=kmalloc(sizeof(struct r3964_info), GFP_KERNEL); 
1107    TRACE_M("r3964_open - info kmalloc %x",(int)pInfo);
1108 
1109    if(!pInfo)
1110    {
1111       printk(KERN_ERR "r3964: failed to alloc info structure\n");
1112       return -ENOMEM;
1113    }
1114 
1115    pInfo->rx_buf = kmalloc(RX_BUF_SIZE, GFP_KERNEL);
1116    TRACE_M("r3964_open - rx_buf kmalloc %x",(int)pInfo->rx_buf);
1117 
1118    if(!pInfo->rx_buf)
1119    {
1120       printk(KERN_ERR "r3964: failed to alloc receive buffer\n");
1121       kfree(pInfo);
1122       TRACE_M("r3964_open - info kfree %x",(int)pInfo);
1123       return -ENOMEM;
1124    }
1125    
1126    pInfo->tx_buf = kmalloc(TX_BUF_SIZE, GFP_KERNEL);
1127    TRACE_M("r3964_open - tx_buf kmalloc %x",(int)pInfo->tx_buf);
1128 
1129    if(!pInfo->tx_buf)
1130    {
1131       printk(KERN_ERR "r3964: failed to alloc transmit buffer\n");
1132       kfree(pInfo->rx_buf);
1133       TRACE_M("r3964_open - rx_buf kfree %x",(int)pInfo->rx_buf);
1134       kfree(pInfo);
1135       TRACE_M("r3964_open - info kfree %x",(int)pInfo);
1136       return -ENOMEM;
1137    }
1138 
1139    pInfo->tty = tty;
1140    init_waitqueue_head (&pInfo->read_wait);
1141    pInfo->priority = R3964_MASTER;
1142    pInfo->rx_first = pInfo->rx_last = NULL;
1143    pInfo->tx_first = pInfo->tx_last = NULL;
1144    pInfo->rx_position = 0;
1145    pInfo->tx_position = 0;
1146    pInfo->last_rx = 0;
1147    pInfo->blocks_in_rx_queue = 0;
1148    pInfo->firstClient=NULL;
1149    pInfo->state=R3964_IDLE;
1150    pInfo->flags = R3964_DEBUG;
1151    pInfo->count_down = 0;
1152    pInfo->nRetry = 0;
1153    
1154    tty->disc_data = pInfo;
1155 
1156    /*
1157     * Add 'on_timer' to timer task queue
1158     * (will be called from timer bh)
1159     */
1160    INIT_LIST_HEAD(&pInfo->bh_1.list);
1161    pInfo->bh_1.sync = 0;
1162    pInfo->bh_1.routine = &on_timer_1;
1163    pInfo->bh_1.data = pInfo;
1164    
1165    INIT_LIST_HEAD(&pInfo->bh_2.list);
1166    pInfo->bh_2.sync = 0;
1167    pInfo->bh_2.routine = &on_timer_2;
1168    pInfo->bh_2.data = pInfo;
1169 
1170    queue_task(&pInfo->bh_1, &tq_timer);
1171 
1172    return 0;
1173 }
1174 
1175 static void r3964_close(struct tty_struct *tty)
1176 {
1177    struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
1178    struct r3964_client_info *pClient, *pNext;
1179    struct r3964_message *pMsg;
1180    struct r3964_block_header *pHeader, *pNextHeader;
1181    unsigned long flags;
1182 
1183    TRACE_L("close");
1184 
1185     /*
1186      * Make sure that our task queue isn't activated.  If it
1187      * is, take it out of the linked list.
1188      */
1189     spin_lock_irqsave(&tqueue_lock, flags);
1190     if (pInfo->bh_1.sync)
1191         list_del(&pInfo->bh_1.list);
1192     if (pInfo->bh_2.sync)
1193         list_del(&pInfo->bh_2.list);
1194     spin_unlock_irqrestore(&tqueue_lock, flags);
1195 
1196    /* Remove client-structs and message queues: */
1197     pClient=pInfo->firstClient;
1198     while(pClient)
1199     {
1200        pNext=pClient->next;
1201        while(pClient->msg_count)
1202        {
1203           pMsg=remove_msg(pInfo, pClient);
1204           if(pMsg)
1205           {
1206              kfree(pMsg);
1207              TRACE_M("r3964_close - msg kfree %x",(int)pMsg);
1208           }
1209        }
1210        kfree(pClient);
1211        TRACE_M("r3964_close - client kfree %x",(int)pClient);
1212        pClient=pNext;
1213     }
1214     /* Remove jobs from tx_queue: */
1215         save_flags(flags);
1216         cli();
1217         pHeader=pInfo->tx_first;
1218         pInfo->tx_first=pInfo->tx_last=NULL;
1219         restore_flags(flags);
1220         
1221     while(pHeader)
1222         {
1223            pNextHeader=pHeader->next;
1224            kfree(pHeader);
1225            pHeader=pNextHeader;
1226         }
1227 
1228     /* Free buffers: */
1229     wake_up_interruptible(&pInfo->read_wait);
1230     kfree(pInfo->rx_buf);
1231     TRACE_M("r3964_close - rx_buf kfree %x",(int)pInfo->rx_buf);
1232     kfree(pInfo->tx_buf);
1233     TRACE_M("r3964_close - tx_buf kfree %x",(int)pInfo->tx_buf);
1234     kfree(pInfo);
1235     TRACE_M("r3964_close - info kfree %x",(int)pInfo);
1236 
1237     MOD_DEC_USE_COUNT;
1238 }
1239 
1240 static int r3964_read(struct tty_struct *tty, struct file *file,
1241                      unsigned char *buf, unsigned int nr)
1242 {
1243    struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
1244    struct r3964_client_info *pClient;
1245    struct r3964_message *pMsg;
1246    struct r3964_client_message theMsg;
1247    DECLARE_WAITQUEUE (wait, current);
1248    
1249    int pid = current->pid;
1250    int count;
1251    
1252    TRACE_L("read()");
1253  
1254    pClient=findClient(pInfo, pid);
1255    if(pClient)
1256    {
1257       pMsg = remove_msg(pInfo, pClient);
1258       if(pMsg==NULL)
1259       {
1260                  /* no messages available. */
1261          if (file->f_flags & O_NONBLOCK)
1262                  {
1263             return -EAGAIN;
1264                  }
1265          /* block until there is a message: */
1266          add_wait_queue(&pInfo->read_wait, &wait);
1267 repeat:
1268          current->state = TASK_INTERRUPTIBLE;
1269          pMsg = remove_msg(pInfo, pClient);
1270          if (!pMsg && !signal_pending(current))
1271                  {
1272             schedule();
1273             goto repeat;
1274          }
1275          current->state = TASK_RUNNING;
1276          remove_wait_queue(&pInfo->read_wait, &wait);
1277       }
1278       
1279       /* If we still haven't got a message, we must have been signalled */
1280 
1281       if (!pMsg) return -EINTR;
1282 
1283       /* deliver msg to client process: */
1284       theMsg.msg_id = pMsg->msg_id;
1285       theMsg.arg    = pMsg->arg;
1286       theMsg.error_code = pMsg->error_code;
1287       count = sizeof(struct r3964_client_message);
1288 
1289       kfree(pMsg);
1290       TRACE_M("r3964_read - msg kfree %x",(int)pMsg);
1291 
1292       if (copy_to_user(buf,&theMsg, count))
1293         return -EFAULT;
1294 
1295       TRACE_PS("read - return %d", count);
1296       return count;
1297    }
1298    return -EPERM;
1299 }
1300 
1301 static int r3964_write(struct tty_struct * tty, struct file * file,
1302                       const unsigned char *data, unsigned int count)
1303 {
1304    struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
1305    struct r3964_block_header *pHeader;
1306    struct r3964_client_info *pClient;
1307    unsigned char *new_data;
1308    int status;
1309    int pid;
1310    
1311    TRACE_L("write request, %d characters", count);
1312 /* 
1313  * Verify the pointers 
1314  */
1315 
1316    if(!pInfo)
1317       return -EIO;
1318 
1319    status = verify_area (VERIFY_READ, data, count);
1320    if (status != 0) 
1321    {
1322       return status;
1323    }
1324 
1325 /*
1326  * Ensure that the caller does not wish to send too much.
1327  */
1328    if (count > R3964_MTU) 
1329    {
1330       if (pInfo->flags & R3964_DEBUG)
1331       {
1332          TRACE_L (KERN_WARNING
1333                  "r3964_write: truncating user packet "
1334                  "from %u to mtu %d", count, R3964_MTU);
1335       }
1336       count = R3964_MTU;
1337    }
1338 /*
1339  * Allocate a buffer for the data and fetch it from the user space.
1340  */
1341    new_data = kmalloc (count+sizeof(struct r3964_block_header), GFP_KERNEL);
1342    TRACE_M("r3964_write - kmalloc %x",(int)new_data);
1343    if (new_data == NULL) {
1344       if (pInfo->flags & R3964_DEBUG)
1345       {
1346          printk (KERN_ERR
1347                "r3964_write: no memory\n");
1348       }
1349       return -ENOSPC;
1350    }
1351    
1352    pHeader = (struct r3964_block_header *)new_data;
1353    pHeader->data = new_data + sizeof(struct r3964_block_header);
1354    pHeader->length = count;
1355    pHeader->locks = 0;
1356    pHeader->owner = NULL;
1357    
1358    pid=current->pid;
1359    
1360    pClient=findClient(pInfo, pid);
1361    if(pClient)
1362    {
1363       pHeader->owner = pClient;
1364    }
1365 
1366    copy_from_user (pHeader->data, data, count); /* We already verified this */
1367 
1368    if(pInfo->flags & R3964_DEBUG)
1369    {
1370       dump_block(pHeader->data, count);
1371    }
1372 
1373 /*
1374  * Add buffer to transmit-queue:
1375  */
1376    add_tx_queue(pInfo, pHeader);
1377    trigger_transmit(pInfo);
1378    
1379    return 0;
1380 }
1381 
1382 static int r3964_ioctl(struct tty_struct * tty, struct file * file,
1383                unsigned int cmd, unsigned long arg)
1384 {
1385    struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
1386    if(pInfo==NULL)
1387       return -EINVAL;
1388    switch(cmd)
1389    {
1390       case R3964_ENABLE_SIGNALS:
1391          return enable_signals(pInfo, current->pid, arg);
1392       case R3964_SETPRIORITY:
1393          if(arg<R3964_MASTER || arg>R3964_SLAVE)
1394             return -EINVAL;
1395          pInfo->priority = arg & 0xff;
1396          return 0;
1397       case R3964_USE_BCC:
1398              if(arg)
1399             pInfo->flags |= R3964_BCC;
1400          else
1401             pInfo->flags &= ~R3964_BCC;
1402          return 0;
1403       case R3964_READ_TELEGRAM:
1404          return read_telegram(pInfo, current->pid, (unsigned char *)arg);
1405       default:
1406          return -ENOIOCTLCMD;
1407    }
1408 }
1409 
1410 static void r3964_set_termios(struct tty_struct *tty, struct termios * old)
1411 {
1412    TRACE_L("set_termios");
1413 }
1414 
1415 /* Called without the kernel lock held - fine */
1416 static unsigned int r3964_poll(struct tty_struct * tty, struct file * file,
1417                       struct poll_table_struct *wait)
1418 {
1419    struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
1420    int pid=current->pid;
1421    struct r3964_client_info *pClient;
1422    struct r3964_message *pMsg=NULL;
1423    unsigned int flags;
1424    int result = POLLOUT;
1425 
1426    TRACE_L("POLL");
1427 
1428    pClient=findClient(pInfo,pid);
1429    if(pClient)
1430      {
1431        poll_wait(file, &pInfo->read_wait, wait);
1432        save_flags(flags);
1433        cli();
1434        pMsg=pClient->first_msg;
1435        restore_flags(flags);
1436        if(pMsg)
1437            result |= POLLIN | POLLRDNORM;
1438      }
1439    else
1440      {
1441        result = -EINVAL;
1442      }
1443    return result;
1444 }
1445 
1446 static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
1447                               char *fp, int count)
1448 {
1449    struct r3964_info *pInfo=(struct r3964_info*)tty->disc_data;
1450     const unsigned char *p;
1451     char *f, flags = 0;
1452     int i;
1453 
1454     for (i=count, p = cp, f = fp; i; i--, p++) {
1455         if (f)
1456             flags = *f++;
1457         if(flags==TTY_NORMAL)
1458         {
1459             receive_char(pInfo, *p);
1460         }
1461         else
1462         {
1463             receive_error(pInfo, flags);
1464         }
1465         
1466     }
1467 }
1468 
1469 static int r3964_receive_room(struct tty_struct *tty)
1470 {
1471    TRACE_L("receive_room");
1472    return -1;
1473 }
1474 
1475 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.