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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [char/] [n_hdlc.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/* generic HDLC line discipline for Linux
2
 *
3
 * Written by Paul Fulghum paulkf@microgate.com
4
 * for Microgate Corporation
5
 *
6
 * Microgate and SyncLink are registered trademarks of Microgate Corporation
7
 *
8
 * Adapted from ppp.c, written by Michael Callahan <callahan@maths.ox.ac.uk>,
9
 *      Al Longyear <longyear@netcom.com>, Paul Mackerras <Paul.Mackerras@cs.anu.edu.au>
10
 *
11
 * Original release 01/11/99
12
 * $Id: n_hdlc.c,v 1.1.1.1 2004-04-15 01:59:40 phoenix Exp $
13
 *
14
 * This code is released under the GNU General Public License (GPL)
15
 *
16
 * This module implements the tty line discipline N_HDLC for use with
17
 * tty device drivers that support bit-synchronous HDLC communications.
18
 *
19
 * All HDLC data is frame oriented which means:
20
 *
21
 * 1. tty write calls represent one complete transmit frame of data
22
 *    The device driver should accept the complete frame or none of
23
 *    the frame (busy) in the write method. Each write call should have
24
 *    a byte count in the range of 2-65535 bytes (2 is min HDLC frame
25
 *    with 1 addr byte and 1 ctrl byte). The max byte count of 65535
26
 *    should include any crc bytes required. For example, when using
27
 *    CCITT CRC32, 4 crc bytes are required, so the maximum size frame
28
 *    the application may transmit is limited to 65531 bytes. For CCITT
29
 *    CRC16, the maximum application frame size would be 65533.
30
 *
31
 *
32
 * 2. receive callbacks from the device driver represents
33
 *    one received frame. The device driver should bypass
34
 *    the tty flip buffer and call the line discipline receive
35
 *    callback directly to avoid fragmenting or concatenating
36
 *    multiple frames into a single receive callback.
37
 *
38
 *    The HDLC line discipline queues the receive frames in seperate
39
 *    buffers so complete receive frames can be returned by the
40
 *    tty read calls.
41
 *
42
 * 3. tty read calls returns an entire frame of data or nothing.
43
 *
44
 * 4. all send and receive data is considered raw. No processing
45
 *    or translation is performed by the line discipline, regardless
46
 *    of the tty flags
47
 *
48
 * 5. When line discipline is queried for the amount of receive
49
 *    data available (FIOC), 0 is returned if no data available,
50
 *    otherwise the count of the next available frame is returned.
51
 *    (instead of the sum of all received frame counts).
52
 *
53
 * These conventions allow the standard tty programming interface
54
 * to be used for synchronous HDLC applications when used with
55
 * this line discipline (or another line discipline that is frame
56
 * oriented such as N_PPP).
57
 *
58
 * The SyncLink driver (synclink.c) implements both asynchronous
59
 * (using standard line discipline N_TTY) and synchronous HDLC
60
 * (using N_HDLC) communications, with the latter using the above
61
 * conventions.
62
 *
63
 * This implementation is very basic and does not maintain
64
 * any statistics. The main point is to enforce the raw data
65
 * and frame orientation of HDLC communications.
66
 *
67
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
68
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
69
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
70
 * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
71
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
72
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
73
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
74
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
75
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
76
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
77
 * OF THE POSSIBILITY OF SUCH DAMAGE.
78
 */
79
 
80
#define HDLC_MAGIC 0x239e
81
#define HDLC_VERSION "$Revision: 1.1.1.1 $"
82
 
83
#include <linux/version.h>
84
#include <linux/config.h>
85
#include <linux/module.h>
86
#include <linux/init.h>
87
#include <linux/kernel.h>
88
#include <linux/sched.h>
89
#include <linux/types.h>
90
#include <linux/fcntl.h>
91
#include <linux/interrupt.h>
92
#include <linux/ptrace.h>
93
 
94
#undef VERSION
95
#define VERSION(major,minor,patch) (((((major)<<8)+(minor))<<8)+(patch))
96
 
97
#include <linux/poll.h>
98
#include <linux/in.h>
99
#include <linux/slab.h>
100
#include <linux/tty.h>
101
#include <linux/errno.h>
102
#include <linux/string.h>       /* used in new tty drivers */
103
#include <linux/signal.h>       /* used in new tty drivers */
104
#include <asm/system.h>
105
#include <asm/bitops.h>
106
#include <asm/termios.h>
107
#include <linux/if.h>
108
 
109
#include <linux/ioctl.h>
110
 
111
#ifdef CONFIG_KERNELD
112
#include <linux/kerneld.h>
113
#endif
114
 
115
#include <asm/segment.h>
116
#define GET_USER(error,value,addr) error = get_user(value,addr)
117
#define COPY_FROM_USER(error,dest,src,size) error = copy_from_user(dest,src,size) ? -EFAULT : 0
118
#define PUT_USER(error,value,addr) error = put_user(value,addr)
119
#define COPY_TO_USER(error,dest,src,size) error = copy_to_user(dest,src,size) ? -EFAULT : 0
120
 
121
#include <asm/uaccess.h>
122
 
123
typedef ssize_t         rw_ret_t;
124
typedef size_t          rw_count_t;
125
 
126
/*
127
 * Buffers for individual HDLC frames
128
 */
129
#define MAX_HDLC_FRAME_SIZE 65535 
130
#define DEFAULT_RX_BUF_COUNT 10
131
#define MAX_RX_BUF_COUNT 60
132
#define DEFAULT_TX_BUF_COUNT 1
133
 
134
 
135
typedef struct _n_hdlc_buf
136
{
137
        struct _n_hdlc_buf *link;
138
        int count;
139
        char buf[1];
140
} N_HDLC_BUF;
141
 
142
#define N_HDLC_BUF_SIZE (sizeof(N_HDLC_BUF)+maxframe)
143
 
144
typedef struct _n_hdlc_buf_list
145
{
146
        N_HDLC_BUF *head;
147
        N_HDLC_BUF *tail;
148
        int count;
149
        spinlock_t spinlock;
150
 
151
} N_HDLC_BUF_LIST;
152
 
153
/*
154
 * Per device instance data structure
155
 */
156
struct n_hdlc {
157
        int             magic;          /* magic value for structure    */
158
        __u32           flags;          /* miscellaneous control flags  */
159
 
160
        struct tty_struct *tty;         /* ptr to TTY structure */
161
        struct tty_struct *backup_tty;  /* TTY to use if tty gets closed */
162
 
163
        int             tbusy;          /* reentrancy flag for tx wakeup code */
164
        int             woke_up;
165
        N_HDLC_BUF      *tbuf;          /* currently transmitting tx buffer */
166
        N_HDLC_BUF_LIST tx_buf_list;    /* list of pending transmit frame buffers */
167
        N_HDLC_BUF_LIST rx_buf_list;    /* list of received frame buffers */
168
        N_HDLC_BUF_LIST tx_free_buf_list;       /* list unused transmit frame buffers */
169
        N_HDLC_BUF_LIST rx_free_buf_list;       /* list unused received frame buffers */
170
};
171
 
172
/*
173
 * HDLC buffer list manipulation functions
174
 */
175
static void n_hdlc_buf_list_init(N_HDLC_BUF_LIST *list);
176
static void n_hdlc_buf_put(N_HDLC_BUF_LIST *list,N_HDLC_BUF *buf);
177
static N_HDLC_BUF* n_hdlc_buf_get(N_HDLC_BUF_LIST *list);
178
 
179
/* Local functions */
180
 
181
static struct n_hdlc *n_hdlc_alloc (void);
182
 
183
MODULE_PARM(debuglevel, "i");
184
MODULE_PARM(maxframe, "i");
185
 
186
#ifdef MODULE_LICENSE
187
MODULE_LICENSE("GPL");
188
#endif
189
 
190
/* debug level can be set by insmod for debugging purposes */
191
#define DEBUG_LEVEL_INFO        1
192
static int debuglevel=0;
193
 
194
/* max frame size for memory allocations */
195
static ssize_t  maxframe=4096;
196
 
197
/* TTY callbacks */
198
 
199
static rw_ret_t n_hdlc_tty_read(struct tty_struct *,
200
        struct file *, __u8 *, rw_count_t);
201
static rw_ret_t n_hdlc_tty_write(struct tty_struct *,
202
        struct file *, const __u8 *, rw_count_t);
203
static int n_hdlc_tty_ioctl(struct tty_struct *,
204
        struct file *, unsigned int, unsigned long);
205
static unsigned int n_hdlc_tty_poll (struct tty_struct *tty, struct file *filp,
206
                                  poll_table * wait);
207
static int n_hdlc_tty_open (struct tty_struct *);
208
static void n_hdlc_tty_close (struct tty_struct *);
209
static int n_hdlc_tty_room (struct tty_struct *tty);
210
static void n_hdlc_tty_receive (struct tty_struct *tty,
211
        const __u8 * cp, char *fp, int count);
212
static void n_hdlc_tty_wakeup (struct tty_struct *tty);
213
 
214
#define bset(p,b)       ((p)[(b) >> 5] |= (1 << ((b) & 0x1f)))
215
 
216
#define tty2n_hdlc(tty) ((struct n_hdlc *) ((tty)->disc_data))
217
#define n_hdlc2tty(n_hdlc)      ((n_hdlc)->tty)
218
 
219
/* Define this string only once for all macro invocations */
220
static char szVersion[] = HDLC_VERSION;
221
 
222
/* n_hdlc_release()
223
 *
224
 *      release an n_hdlc per device line discipline info structure
225
 *
226
 */
227
static void n_hdlc_release (struct n_hdlc *n_hdlc)
228
{
229
        struct tty_struct *tty = n_hdlc2tty (n_hdlc);
230
        N_HDLC_BUF *buf;
231
 
232
        if (debuglevel >= DEBUG_LEVEL_INFO)
233
                printk("%s(%d)n_hdlc_release() called\n",__FILE__,__LINE__);
234
 
235
        /* Ensure that the n_hdlcd process is not hanging on select()/poll() */
236
        wake_up_interruptible (&tty->read_wait);
237
        wake_up_interruptible (&tty->write_wait);
238
 
239
        if (tty != NULL && tty->disc_data == n_hdlc)
240
                tty->disc_data = NULL;  /* Break the tty->n_hdlc link */
241
 
242
        /* Release transmit and receive buffers */
243
        for(;;) {
244
                buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list);
245
                if (buf) {
246
                        kfree(buf);
247
                } else
248
                        break;
249
        }
250
        for(;;) {
251
                buf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list);
252
                if (buf) {
253
                        kfree(buf);
254
                } else
255
                        break;
256
        }
257
        for(;;) {
258
                buf = n_hdlc_buf_get(&n_hdlc->rx_buf_list);
259
                if (buf) {
260
                        kfree(buf);
261
                } else
262
                        break;
263
        }
264
        for(;;) {
265
                buf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
266
                if (buf) {
267
                        kfree(buf);
268
                } else
269
                        break;
270
        }
271
        if (n_hdlc->tbuf)
272
                kfree(n_hdlc->tbuf);
273
        kfree(n_hdlc);
274
 
275
}       /* end of n_hdlc_release() */
276
 
277
/* n_hdlc_tty_close()
278
 *
279
 *      Called when the line discipline is changed to something
280
 *      else, the tty is closed, or the tty detects a hangup.
281
 */
282
static void n_hdlc_tty_close(struct tty_struct *tty)
283
{
284
        struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
285
 
286
        if (debuglevel >= DEBUG_LEVEL_INFO)
287
                printk("%s(%d)n_hdlc_tty_close() called\n",__FILE__,__LINE__);
288
 
289
        if (n_hdlc != NULL) {
290
                if (n_hdlc->magic != HDLC_MAGIC) {
291
                        printk (KERN_WARNING"n_hdlc: trying to close unopened tty!\n");
292
                        return;
293
                }
294
#if defined(TTY_NO_WRITE_SPLIT)
295
                clear_bit(TTY_NO_WRITE_SPLIT,&tty->flags);
296
#endif
297
                tty->disc_data = NULL;
298
                if (tty == n_hdlc->backup_tty)
299
                        n_hdlc->backup_tty = 0;
300
                if (tty != n_hdlc->tty)
301
                        return;
302
                if (n_hdlc->backup_tty) {
303
                        n_hdlc->tty = n_hdlc->backup_tty;
304
                } else {
305
                        n_hdlc_release (n_hdlc);
306
                        MOD_DEC_USE_COUNT;
307
                }
308
        }
309
 
310
        if (debuglevel >= DEBUG_LEVEL_INFO)
311
                printk("%s(%d)n_hdlc_tty_close() success\n",__FILE__,__LINE__);
312
 
313
}       /* end of n_hdlc_tty_close() */
314
 
315
/* n_hdlc_tty_open
316
 *
317
 *      called when line discipline changed to n_hdlc
318
 *
319
 * Arguments:   tty     pointer to tty info structure
320
 * Return Value:        0 if success, otherwise error code
321
 */
322
static int n_hdlc_tty_open (struct tty_struct *tty)
323
{
324
        struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
325
 
326
        if (debuglevel >= DEBUG_LEVEL_INFO)
327
                printk("%s(%d)n_hdlc_tty_open() called (major=%u,minor=%u)\n",
328
                __FILE__,__LINE__,
329
                MAJOR(tty->device), MINOR(tty->device));
330
 
331
        /* There should not be an existing table for this slot. */
332
        if (n_hdlc) {
333
                printk (KERN_ERR"n_hdlc_tty_open:tty already associated!\n" );
334
                return -EEXIST;
335
        }
336
 
337
        n_hdlc = n_hdlc_alloc();
338
        if (!n_hdlc) {
339
                printk (KERN_ERR "n_hdlc_alloc failed\n");
340
                return -ENFILE;
341
        }
342
 
343
        tty->disc_data = n_hdlc;
344
        n_hdlc->tty    = tty;
345
 
346
        MOD_INC_USE_COUNT;
347
 
348
#if defined(TTY_NO_WRITE_SPLIT)
349
        /* change tty_io write() to not split large writes into 8K chunks */
350
        set_bit(TTY_NO_WRITE_SPLIT,&tty->flags);
351
#endif
352
 
353
        /* Flush any pending characters in the driver and discipline. */
354
 
355
        if (tty->ldisc.flush_buffer)
356
                tty->ldisc.flush_buffer (tty);
357
 
358
        if (tty->driver.flush_buffer)
359
                tty->driver.flush_buffer (tty);
360
 
361
        if (debuglevel >= DEBUG_LEVEL_INFO)
362
                printk("%s(%d)n_hdlc_tty_open() success\n",__FILE__,__LINE__);
363
 
364
        return 0;
365
 
366
}       /* end of n_tty_hdlc_open() */
367
 
368
/* n_hdlc_send_frames()
369
 *
370
 *      send frames on pending send buffer list until the
371
 *      driver does not accept a frame (busy)
372
 *      this function is called after adding a frame to the
373
 *      send buffer list and by the tty wakeup callback
374
 *
375
 * Arguments:           n_hdlc          pointer to ldisc instance data
376
 *                      tty             pointer to tty instance data
377
 * Return Value:        None
378
 */
379
static void n_hdlc_send_frames (struct n_hdlc *n_hdlc, struct tty_struct *tty)
380
{
381
        register int actual;
382
        unsigned long flags;
383
        N_HDLC_BUF *tbuf;
384
 
385
        if (debuglevel >= DEBUG_LEVEL_INFO)
386
                printk("%s(%d)n_hdlc_send_frames() called\n",__FILE__,__LINE__);
387
 check_again:
388
 
389
        save_flags(flags);
390
        cli ();
391
        if (n_hdlc->tbusy) {
392
                n_hdlc->woke_up = 1;
393
                restore_flags(flags);
394
                return;
395
        }
396
        n_hdlc->tbusy = 1;
397
        n_hdlc->woke_up = 0;
398
        restore_flags(flags);
399
 
400
        /* get current transmit buffer or get new transmit */
401
        /* buffer from list of pending transmit buffers */
402
 
403
        tbuf = n_hdlc->tbuf;
404
        if (!tbuf)
405
                tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
406
 
407
        while (tbuf) {
408
                if (debuglevel >= DEBUG_LEVEL_INFO)
409
                        printk("%s(%d)sending frame %p, count=%d\n",
410
                                __FILE__,__LINE__,tbuf,tbuf->count);
411
 
412
                /* Send the next block of data to device */
413
                tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
414
                actual = tty->driver.write(tty, 0, tbuf->buf, tbuf->count);
415
 
416
                /* if transmit error, throw frame away by */
417
                /* pretending it was accepted by driver */
418
                if (actual < 0)
419
                        actual = tbuf->count;
420
 
421
                if (actual == tbuf->count) {
422
                        if (debuglevel >= DEBUG_LEVEL_INFO)
423
                                printk("%s(%d)frame %p completed\n",
424
                                        __FILE__,__LINE__,tbuf);
425
 
426
                        /* free current transmit buffer */
427
                        n_hdlc_buf_put(&n_hdlc->tx_free_buf_list,tbuf);
428
 
429
                        /* this tx buffer is done */
430
                        n_hdlc->tbuf = NULL;
431
 
432
                        /* wait up sleeping writers */
433
                        wake_up_interruptible(&tty->write_wait);
434
 
435
                        /* get next pending transmit buffer */
436
                        tbuf = n_hdlc_buf_get(&n_hdlc->tx_buf_list);
437
                } else {
438
                        if (debuglevel >= DEBUG_LEVEL_INFO)
439
                                printk("%s(%d)frame %p pending\n",
440
                                        __FILE__,__LINE__,tbuf);
441
 
442
                        /* buffer not accepted by driver */
443
                        /* set this buffer as pending buffer */
444
                        n_hdlc->tbuf = tbuf;
445
                        break;
446
                }
447
        }
448
 
449
        if (!tbuf)
450
                tty->flags  &= ~(1 << TTY_DO_WRITE_WAKEUP);
451
 
452
        /* Clear the re-entry flag */
453
        save_flags(flags);
454
        cli ();
455
        n_hdlc->tbusy = 0;
456
        restore_flags(flags);
457
 
458
        if (n_hdlc->woke_up)
459
          goto check_again;
460
 
461
        if (debuglevel >= DEBUG_LEVEL_INFO)
462
                printk("%s(%d)n_hdlc_send_frames() exit\n",__FILE__,__LINE__);
463
 
464
}       /* end of n_hdlc_send_frames() */
465
 
466
/* n_hdlc_tty_wakeup()
467
 *
468
 *      Callback for transmit wakeup. Called when low level
469
 *      device driver can accept more send data.
470
 *
471
 * Arguments:           tty     pointer to associated tty instance data
472
 * Return Value:        None
473
 */
474
static void n_hdlc_tty_wakeup (struct tty_struct *tty)
475
{
476
        struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
477
 
478
        if (debuglevel >= DEBUG_LEVEL_INFO)
479
                printk("%s(%d)n_hdlc_tty_wakeup() called\n",__FILE__,__LINE__);
480
 
481
        if (!n_hdlc)
482
                return;
483
 
484
        if (tty != n_hdlc->tty) {
485
                tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
486
                return;
487
        }
488
 
489
        n_hdlc_send_frames (n_hdlc, tty);
490
 
491
}       /* end of n_hdlc_tty_wakeup() */
492
 
493
/* n_hdlc_tty_room()
494
 *
495
 *      Callback function from tty driver. Return the amount of
496
 *      space left in the receiver's buffer to decide if remote
497
 *      transmitter is to be throttled.
498
 *
499
 * Arguments:           tty     pointer to associated tty instance data
500
 * Return Value:        number of bytes left in receive buffer
501
 */
502
static int n_hdlc_tty_room (struct tty_struct *tty)
503
{
504
        if (debuglevel >= DEBUG_LEVEL_INFO)
505
                printk("%s(%d)n_hdlc_tty_room() called\n",__FILE__,__LINE__);
506
        /* always return a larger number to prevent */
507
        /* throttling of remote transmitter. */
508
        return 65536;
509
}       /* end of n_hdlc_tty_root() */
510
 
511
/* n_hdlc_tty_receive()
512
 *
513
 *      Called by tty low level driver when receive data is
514
 *      available. Data is interpreted as one HDLC frame.
515
 *
516
 * Arguments:           tty             pointer to tty isntance data
517
 *                      data            pointer to received data
518
 *                      flags           pointer to flags for data
519
 *                      count           count of received data in bytes
520
 *
521
 * Return Value:        None
522
 */
523
static void n_hdlc_tty_receive(struct tty_struct *tty,
524
        const __u8 * data, char *flags, int count)
525
{
526
        register struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
527
        register N_HDLC_BUF *buf;
528
 
529
        if (debuglevel >= DEBUG_LEVEL_INFO)
530
                printk("%s(%d)n_hdlc_tty_receive() called count=%d\n",
531
                        __FILE__,__LINE__, count);
532
 
533
        /* This can happen if stuff comes in on the backup tty */
534
        if (n_hdlc == 0 || tty != n_hdlc->tty)
535
                return;
536
 
537
        /* verify line is using HDLC discipline */
538
        if (n_hdlc->magic != HDLC_MAGIC) {
539
                printk("%s(%d) line not using HDLC discipline\n",
540
                        __FILE__,__LINE__);
541
                return;
542
        }
543
 
544
        if ( count>maxframe ) {
545
                if (debuglevel >= DEBUG_LEVEL_INFO)
546
                        printk("%s(%d) rx count>maxframesize, data discarded\n",
547
                               __FILE__,__LINE__);
548
                return;
549
        }
550
 
551
        /* get a free HDLC buffer */
552
        buf = n_hdlc_buf_get(&n_hdlc->rx_free_buf_list);
553
        if (!buf) {
554
                /* no buffers in free list, attempt to allocate another rx buffer */
555
                /* unless the maximum count has been reached */
556
                if (n_hdlc->rx_buf_list.count < MAX_RX_BUF_COUNT)
557
                        buf = (N_HDLC_BUF*)kmalloc(N_HDLC_BUF_SIZE,GFP_ATOMIC);
558
        }
559
 
560
        if (!buf) {
561
                if (debuglevel >= DEBUG_LEVEL_INFO)
562
                        printk("%s(%d) no more rx buffers, data discarded\n",
563
                               __FILE__,__LINE__);
564
                return;
565
        }
566
 
567
        /* copy received data to HDLC buffer */
568
        memcpy(buf->buf,data,count);
569
        buf->count=count;
570
 
571
        /* add HDLC buffer to list of received frames */
572
        n_hdlc_buf_put(&n_hdlc->rx_buf_list,buf);
573
 
574
        /* wake up any blocked reads and perform async signalling */
575
        wake_up_interruptible (&tty->read_wait);
576
        if (n_hdlc->tty->fasync != NULL)
577
                kill_fasync (&n_hdlc->tty->fasync, SIGIO, POLL_IN);
578
 
579
}       /* end of n_hdlc_tty_receive() */
580
 
581
/* n_hdlc_tty_read()
582
 *
583
 *      Called to retreive one frame of data (if available)
584
 *
585
 * Arguments:
586
 *
587
 *      tty             pointer to tty instance data
588
 *      file            pointer to open file object
589
 *      buf             pointer to returned data buffer
590
 *      nr              size of returned data buffer
591
 *
592
 * Return Value:
593
 *
594
 *      Number of bytes returned or error code
595
 */
596
static rw_ret_t n_hdlc_tty_read (struct tty_struct *tty,
597
        struct file *file, __u8 * buf, rw_count_t nr)
598
{
599
        struct n_hdlc *n_hdlc = tty2n_hdlc(tty);
600
        int error;
601
        rw_ret_t ret;
602
        N_HDLC_BUF *rbuf;
603
 
604
        if (debuglevel >= DEBUG_LEVEL_INFO)
605
                printk("%s(%d)n_hdlc_tty_read() called\n",__FILE__,__LINE__);
606
 
607
        /* Validate the pointers */
608
        if (!n_hdlc)
609
                return -EIO;
610
 
611
        /* verify user access to buffer */
612
        error = verify_area (VERIFY_WRITE, buf, nr);
613
        if (error != 0) {
614
                printk(KERN_WARNING"%s(%d) n_hdlc_tty_read() can't verify user "
615
                "buffer\n",__FILE__,__LINE__);
616
                return (error);
617
        }
618
 
619
        for (;;) {
620
                if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
621
                        return -EIO;
622
 
623
                n_hdlc = tty2n_hdlc (tty);
624
                if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC ||
625
                         tty != n_hdlc->tty)
626
                        return 0;
627
 
628
                rbuf = n_hdlc_buf_get(&n_hdlc->rx_buf_list);
629
                if (rbuf)
630
                        break;
631
 
632
                /* no data */
633
                if (file->f_flags & O_NONBLOCK)
634
                        return -EAGAIN;
635
 
636
                interruptible_sleep_on (&tty->read_wait);
637
                if (signal_pending(current))
638
                        return -EINTR;
639
        }
640
 
641
        if (rbuf->count > nr) {
642
                /* frame too large for caller's buffer (discard frame) */
643
                ret = (rw_ret_t)-EOVERFLOW;
644
        } else {
645
                /* Copy the data to the caller's buffer */
646
                COPY_TO_USER(error,buf,rbuf->buf,rbuf->count);
647
                if (error)
648
                        ret = (rw_ret_t)error;
649
                else
650
                        ret = (rw_ret_t)rbuf->count;
651
        }
652
 
653
        /* return HDLC buffer to free list unless the free list */
654
        /* count has exceeded the default value, in which case the */
655
        /* buffer is freed back to the OS to conserve memory */
656
        if (n_hdlc->rx_free_buf_list.count > DEFAULT_RX_BUF_COUNT)
657
                kfree(rbuf);
658
        else
659
                n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,rbuf);
660
 
661
        return ret;
662
 
663
}       /* end of n_hdlc_tty_read() */
664
 
665
/* n_hdlc_tty_write()
666
 *
667
 *      write a single frame of data to device
668
 *
669
 * Arguments:   tty     pointer to associated tty device instance data
670
 *              file    pointer to file object data
671
 *              data    pointer to transmit data (one frame)
672
 *              count   size of transmit frame in bytes
673
 *
674
 * Return Value:        number of bytes written (or error code)
675
 */
676
static rw_ret_t n_hdlc_tty_write (struct tty_struct *tty, struct file *file,
677
        const __u8 * data, rw_count_t count)
678
{
679
        struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
680
        int error = 0;
681
        DECLARE_WAITQUEUE(wait, current);
682
        N_HDLC_BUF *tbuf;
683
 
684
        if (debuglevel >= DEBUG_LEVEL_INFO)
685
                printk("%s(%d)n_hdlc_tty_write() called count=%d\n",
686
                        __FILE__,__LINE__,count);
687
 
688
        /* Verify pointers */
689
        if (!n_hdlc)
690
                return -EIO;
691
 
692
        if (n_hdlc->magic != HDLC_MAGIC)
693
                return -EIO;
694
 
695
        /* verify frame size */
696
        if (count > maxframe ) {
697
                if (debuglevel & DEBUG_LEVEL_INFO)
698
                        printk (KERN_WARNING
699
                                "n_hdlc_tty_write: truncating user packet "
700
                                "from %lu to %d\n", (unsigned long) count,
701
                                maxframe );
702
                count = maxframe;
703
        }
704
 
705
        add_wait_queue(&tty->write_wait, &wait);
706
        set_current_state(TASK_INTERRUPTIBLE);
707
 
708
        /* Allocate transmit buffer */
709
        /* sleep until transmit buffer available */
710
        while (!(tbuf = n_hdlc_buf_get(&n_hdlc->tx_free_buf_list))) {
711
                schedule();
712
 
713
                n_hdlc = tty2n_hdlc (tty);
714
                if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC ||
715
                    tty != n_hdlc->tty) {
716
                        printk("n_hdlc_tty_write: %p invalid after wait!\n", n_hdlc);
717
                        error = -EIO;
718
                        break;
719
                }
720
 
721
                if (signal_pending(current)) {
722
                        error = -EINTR;
723
                        break;
724
                }
725
        }
726
 
727
        set_current_state(TASK_RUNNING);
728
        remove_wait_queue(&tty->write_wait, &wait);
729
 
730
        if (!error) {
731
                /* Retrieve the user's buffer */
732
                COPY_FROM_USER (error, tbuf->buf, data, count);
733
                if (error) {
734
                        /* return tx buffer to free list */
735
                        n_hdlc_buf_put(&n_hdlc->tx_free_buf_list,tbuf);
736
                } else {
737
                        /* Send the data */
738
                        tbuf->count = error = count;
739
                        n_hdlc_buf_put(&n_hdlc->tx_buf_list,tbuf);
740
                        n_hdlc_send_frames(n_hdlc,tty);
741
                }
742
        }
743
 
744
        return error;
745
 
746
}       /* end of n_hdlc_tty_write() */
747
 
748
/* n_hdlc_tty_ioctl()
749
 *
750
 *      Process IOCTL system call for the tty device.
751
 *
752
 * Arguments:
753
 *
754
 *      tty             pointer to tty instance data
755
 *      file            pointer to open file object for device
756
 *      cmd             IOCTL command code
757
 *      arg             argument for IOCTL call (cmd dependent)
758
 *
759
 * Return Value:        Command dependent
760
 */
761
static int n_hdlc_tty_ioctl (struct tty_struct *tty, struct file * file,
762
               unsigned int cmd, unsigned long arg)
763
{
764
        struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
765
        int error = 0;
766
        int count;
767
        unsigned long flags;
768
 
769
        if (debuglevel >= DEBUG_LEVEL_INFO)
770
                printk("%s(%d)n_hdlc_tty_ioctl() called %d\n",
771
                        __FILE__,__LINE__,cmd);
772
 
773
        /* Verify the status of the device */
774
        if (!n_hdlc || n_hdlc->magic != HDLC_MAGIC)
775
                return -EBADF;
776
 
777
        switch (cmd) {
778
        case FIONREAD:
779
                /* report count of read data available */
780
                /* in next available frame (if any) */
781
                spin_lock_irqsave(&n_hdlc->rx_buf_list.spinlock,flags);
782
                if (n_hdlc->rx_buf_list.head)
783
                        count = n_hdlc->rx_buf_list.head->count;
784
                else
785
                        count = 0;
786
                spin_unlock_irqrestore(&n_hdlc->rx_buf_list.spinlock,flags);
787
                PUT_USER (error, count, (int *) arg);
788
                break;
789
 
790
        case TIOCOUTQ:
791
                /* get the pending tx byte count in the driver */
792
                count = tty->driver.chars_in_buffer ?
793
                                tty->driver.chars_in_buffer(tty) : 0;
794
                /* add size of next output frame in queue */
795
                spin_lock_irqsave(&n_hdlc->tx_buf_list.spinlock,flags);
796
                if (n_hdlc->tx_buf_list.head)
797
                        count += n_hdlc->tx_buf_list.head->count;
798
                spin_unlock_irqrestore(&n_hdlc->tx_buf_list.spinlock,flags);
799
                PUT_USER (error, count, (int*)arg);
800
                break;
801
 
802
        default:
803
                error = n_tty_ioctl (tty, file, cmd, arg);
804
                break;
805
        }
806
        return error;
807
 
808
}       /* end of n_hdlc_tty_ioctl() */
809
 
810
/* n_hdlc_tty_poll()
811
 *
812
 *      TTY callback for poll system call. Determine which
813
 *      operations (read/write) will not block and return
814
 *      info to caller.
815
 *
816
 * Arguments:
817
 *
818
 *      tty             pointer to tty instance data
819
 *      filp            pointer to open file object for device
820
 *      poll_table      wait queue for operations
821
 *
822
 * Return Value:
823
 *
824
 *      bit mask containing info on which ops will not block
825
 */
826
static unsigned int n_hdlc_tty_poll (struct tty_struct *tty,
827
         struct file *filp, poll_table * wait)
828
{
829
        struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
830
        unsigned int mask = 0;
831
 
832
        if (debuglevel >= DEBUG_LEVEL_INFO)
833
                printk("%s(%d)n_hdlc_tty_poll() called\n",__FILE__,__LINE__);
834
 
835
        if (n_hdlc && n_hdlc->magic == HDLC_MAGIC && tty == n_hdlc->tty) {
836
                /* queue current process into any wait queue that */
837
                /* may awaken in the future (read and write) */
838
 
839
                poll_wait(filp, &tty->read_wait, wait);
840
                poll_wait(filp, &tty->write_wait, wait);
841
 
842
                /* set bits for operations that wont block */
843
                if(n_hdlc->rx_buf_list.head)
844
                        mask |= POLLIN | POLLRDNORM;    /* readable */
845
                if (test_bit(TTY_OTHER_CLOSED, &tty->flags))
846
                        mask |= POLLHUP;
847
                if(tty_hung_up_p(filp))
848
                        mask |= POLLHUP;
849
                if(n_hdlc->tx_free_buf_list.head)
850
                        mask |= POLLOUT | POLLWRNORM;   /* writable */
851
        }
852
        return mask;
853
}       /* end of n_hdlc_tty_poll() */
854
 
855
/* n_hdlc_alloc()
856
 *
857
 *      Allocate an n_hdlc instance data structure
858
 *
859
 * Arguments:           None
860
 * Return Value:        pointer to structure if success, otherwise 0
861
 */
862
static struct n_hdlc *n_hdlc_alloc (void)
863
{
864
        struct n_hdlc   *n_hdlc;
865
        N_HDLC_BUF      *buf;
866
        int             i;
867
 
868
        n_hdlc = (struct n_hdlc *)kmalloc(sizeof(struct n_hdlc), GFP_KERNEL);
869
        if (!n_hdlc)
870
                return 0;
871
 
872
        memset(n_hdlc, 0, sizeof(*n_hdlc));
873
 
874
        n_hdlc_buf_list_init(&n_hdlc->rx_free_buf_list);
875
        n_hdlc_buf_list_init(&n_hdlc->tx_free_buf_list);
876
        n_hdlc_buf_list_init(&n_hdlc->rx_buf_list);
877
        n_hdlc_buf_list_init(&n_hdlc->tx_buf_list);
878
 
879
        /* allocate free rx buffer list */
880
        for(i=0;i<DEFAULT_RX_BUF_COUNT;i++) {
881
                buf = (N_HDLC_BUF*)kmalloc(N_HDLC_BUF_SIZE,GFP_KERNEL);
882
                if (buf)
883
                        n_hdlc_buf_put(&n_hdlc->rx_free_buf_list,buf);
884
                else if (debuglevel >= DEBUG_LEVEL_INFO)
885
                        printk("%s(%d)n_hdlc_alloc(), kalloc() failed for rx buffer %d\n",__FILE__,__LINE__, i);
886
        }
887
 
888
        /* allocate free tx buffer list */
889
        for(i=0;i<DEFAULT_TX_BUF_COUNT;i++) {
890
                buf = (N_HDLC_BUF*)kmalloc(N_HDLC_BUF_SIZE,GFP_KERNEL);
891
                if (buf)
892
                        n_hdlc_buf_put(&n_hdlc->tx_free_buf_list,buf);
893
                else if (debuglevel >= DEBUG_LEVEL_INFO)
894
                        printk("%s(%d)n_hdlc_alloc(), kalloc() failed for tx buffer %d\n",__FILE__,__LINE__, i);
895
        }
896
 
897
        /* Initialize the control block */
898
        n_hdlc->magic  = HDLC_MAGIC;
899
        n_hdlc->flags  = 0;
900
 
901
        return n_hdlc;
902
 
903
}       /* end of n_hdlc_alloc() */
904
 
905
/* n_hdlc_buf_list_init()
906
 *
907
 *      initialize specified HDLC buffer list
908
 *
909
 * Arguments:           list    pointer to buffer list
910
 * Return Value:        None
911
 */
912
static void n_hdlc_buf_list_init(N_HDLC_BUF_LIST *list)
913
{
914
        memset(list,0,sizeof(N_HDLC_BUF_LIST));
915
        spin_lock_init(&list->spinlock);
916
}       /* end of n_hdlc_buf_list_init() */
917
 
918
/* n_hdlc_buf_put()
919
 *
920
 *      add specified HDLC buffer to tail of specified list
921
 *
922
 * Arguments:
923
 *
924
 *      list    pointer to buffer list
925
 *      buf     pointer to buffer
926
 *
927
 * Return Value:        None
928
 */
929
static void n_hdlc_buf_put(N_HDLC_BUF_LIST *list,N_HDLC_BUF *buf)
930
{
931
        unsigned long flags;
932
        spin_lock_irqsave(&list->spinlock,flags);
933
 
934
        buf->link=NULL;
935
        if(list->tail)
936
                list->tail->link = buf;
937
        else
938
                list->head = buf;
939
        list->tail = buf;
940
        (list->count)++;
941
 
942
        spin_unlock_irqrestore(&list->spinlock,flags);
943
 
944
}       /* end of n_hdlc_buf_put() */
945
 
946
/* n_hdlc_buf_get()
947
 *
948
 *      remove and return an HDLC buffer from the
949
 *      head of the specified HDLC buffer list
950
 *
951
 * Arguments:
952
 *
953
 *      list    pointer to HDLC buffer list
954
 *
955
 * Return Value:
956
 *
957
 *      pointer to HDLC buffer if available, otherwise NULL
958
 */
959
static N_HDLC_BUF* n_hdlc_buf_get(N_HDLC_BUF_LIST *list)
960
{
961
        unsigned long flags;
962
        N_HDLC_BUF *buf;
963
        spin_lock_irqsave(&list->spinlock,flags);
964
 
965
        buf = list->head;
966
        if (buf) {
967
                list->head = buf->link;
968
                (list->count)--;
969
        }
970
        if (!list->head)
971
                list->tail = NULL;
972
 
973
        spin_unlock_irqrestore(&list->spinlock,flags);
974
        return buf;
975
 
976
}       /* end of n_hdlc_buf_get() */
977
 
978
static int __init n_hdlc_init(void)
979
{
980
        static struct tty_ldisc n_hdlc_ldisc;
981
        int    status;
982
 
983
        /* range check maxframe arg */
984
        if ( maxframe<4096)
985
                maxframe=4096;
986
        else if ( maxframe>65535)
987
                maxframe=65535;
988
 
989
        printk("HDLC line discipline: version %s, maxframe=%u\n",
990
                szVersion, maxframe);
991
 
992
        /* Register the tty discipline */
993
 
994
        memset(&n_hdlc_ldisc, 0, sizeof (n_hdlc_ldisc));
995
        n_hdlc_ldisc.magic              = TTY_LDISC_MAGIC;
996
        n_hdlc_ldisc.name               = "hdlc";
997
        n_hdlc_ldisc.open               = n_hdlc_tty_open;
998
        n_hdlc_ldisc.close              = n_hdlc_tty_close;
999
        n_hdlc_ldisc.read               = n_hdlc_tty_read;
1000
        n_hdlc_ldisc.write              = n_hdlc_tty_write;
1001
        n_hdlc_ldisc.ioctl              = n_hdlc_tty_ioctl;
1002
        n_hdlc_ldisc.poll               = n_hdlc_tty_poll;
1003
        n_hdlc_ldisc.receive_room       = n_hdlc_tty_room;
1004
        n_hdlc_ldisc.receive_buf        = n_hdlc_tty_receive;
1005
        n_hdlc_ldisc.write_wakeup       = n_hdlc_tty_wakeup;
1006
 
1007
        status = tty_register_ldisc(N_HDLC, &n_hdlc_ldisc);
1008
        if (!status)
1009
                printk (KERN_INFO"N_HDLC line discipline registered.\n");
1010
        else
1011
                printk (KERN_ERR"error registering line discipline: %d\n",status);
1012
 
1013
        if (status)
1014
                printk(KERN_INFO"N_HDLC: init failure %d\n", status);
1015
        return (status);
1016
 
1017
}       /* end of init_module() */
1018
 
1019
static void __exit n_hdlc_exit(void)
1020
{
1021
        int status;
1022
        /* Release tty registration of line discipline */
1023
        if ((status = tty_register_ldisc(N_HDLC, NULL)))
1024
                printk("N_HDLC: can't unregister line discipline (err = %d)\n", status);
1025
        else
1026
                printk("N_HDLC: line discipline unregistered\n");
1027
}
1028
 
1029
module_init(n_hdlc_init);
1030
module_exit(n_hdlc_exit);
1031
 
1032
EXPORT_NO_SYMBOLS;

powered by: WebSVN 2.1.0

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