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