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