OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [char/] [n_r3964.c] - Blame information for rev 62

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.