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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [drivers/] [net/] [baycom.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1626 jcastillo
/*****************************************************************************/
2
 
3
/*
4
 *      baycom.c  -- baycom ser12 and par96 radio modem driver.
5
 *
6
 *      Copyright (C) 1996  Thomas Sailer (sailer@ife.ee.ethz.ch)
7
 *
8
 *      This program is free software; you can redistribute it and/or modify
9
 *      it under the terms of the GNU General Public License as published by
10
 *      the Free Software Foundation; either version 2 of the License, or
11
 *      (at your option) any later version.
12
 *
13
 *      This program is distributed in the hope that it will be useful,
14
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 *      GNU General Public License for more details.
17
 *
18
 *      You should have received a copy of the GNU General Public License
19
 *      along with this program; if not, write to the Free Software
20
 *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
 *
22
 *  Please note that the GPL allows you to use the driver, NOT the radio.
23
 *  In order to use the radio, you need a license from the communications
24
 *  authority of your country.
25
 *
26
 *
27
 *  Supported modems
28
 *
29
 *  ser12:  This is a very simple 1200 baud AFSK modem. The modem consists only
30
 *          of a modulator/demodulator chip, usually a TI TCM3105. The computer
31
 *          is responsible for regenerating the receiver bit clock, as well as
32
 *          for handling the HDLC protocol. The modem connects to a serial port,
33
 *          hence the name. Since the serial port is not used as an async serial
34
 *          port, the kernel driver for serial ports cannot be used, and this
35
 *          driver only supports standard serial hardware (8250, 16450, 16550)
36
 *
37
 *  par96:  This is a modem for 9600 baud FSK compatible to the G3RUH standard.
38
 *          The modem does all the filtering and regenerates the receiver clock.
39
 *          Data is transferred from and to the PC via a shift register.
40
 *          The shift register is filled with 16 bits and an interrupt is
41
 *          signalled. The PC then empties the shift register in a burst. This
42
 *          modem connects to the parallel port, hence the name. The modem
43
 *          leaves the implementation of the HDLC protocol and the scrambler
44
 *          polynomial to the PC. This modem is no longer available (at least
45
 *          from Baycom) and has been replaced by the PICPAR modem (see below).
46
 *          You may however still build one from the schematics published in
47
 *          cq-DL :-).
48
 *
49
 *  picpar: This is a redesign of the par96 modem by Henning Rech, DF9IC. The
50
 *          modem is protocol compatible to par96, but uses only three low
51
 *          power ICs and can therefore be fed from the parallel port and
52
 *          does not require an additional power supply. It features
53
 *          built in DCD circuitry. The driver should therefore be configured
54
 *          for hardware DCD.
55
 *
56
 *
57
 *  Command line options (insmod command line)
58
 *
59
 *  mode     driver mode string. Valid choices are ser12 and par96. An
60
 *           optional * enables software DCD.
61
 *           2=par96/par97, any other value invalid
62
 *  iobase   base address of the port; common values are for ser12 0x3f8,
63
 *           0x2f8, 0x3e8, 0x2e8 and for par96/par97 0x378, 0x278, 0x3bc
64
 *  irq      interrupt line of the port; common values are for ser12 3,4
65
 *           and for par96/par97 7
66
 *
67
 *
68
 *  History:
69
 *   0.1  26.06.96  Adapted from baycom.c and made network driver interface
70
 *        18.10.96  Changed to new user space access routines (copy_{to,from}_user)
71
 *   0.3  26.04.96  init code/data tagged
72
 */
73
 
74
/*****************************************************************************/
75
 
76
#include <linux/module.h>
77
#include <linux/kernel.h>
78
#include <linux/sched.h>
79
#include <linux/types.h>
80
#include <linux/fcntl.h>
81
#include <linux/interrupt.h>
82
#include <linux/ioport.h>
83
#include <linux/in.h>
84
#include <linux/string.h>
85
#include <asm/system.h>
86
#include <asm/bitops.h>
87
#include <asm/io.h>
88
#include <linux/delay.h>
89
#include <linux/errno.h>
90
#include <linux/netdevice.h>
91
#include <linux/hdlcdrv.h>
92
#include <linux/baycom.h>
93
 
94
/* --------------------------------------------------------------------- */
95
 
96
/*
97
 * currently this module is supposed to support both module styles, i.e.
98
 * the old one present up to about 2.1.9, and the new one functioning
99
 * starting with 2.1.21. The reason is I have a kit allowing to compile
100
 * this module also under 2.0.x which was requested by several people.
101
 * This will go in 2.2
102
 */
103
#include <linux/version.h>
104
 
105
#if LINUX_VERSION_CODE >= 0x20100
106
#include <asm/uaccess.h>
107
#else
108
#include <asm/segment.h>
109
#include <linux/mm.h>
110
 
111
#undef put_user
112
#undef get_user
113
 
114
#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
115
#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
116
 
117
extern inline int copy_from_user(void *to, const void *from, unsigned long n)
118
{
119
        int i = verify_area(VERIFY_READ, from, n);
120
        if (i)
121
                return i;
122
        memcpy_fromfs(to, from, n);
123
        return 0;
124
}
125
 
126
extern inline int copy_to_user(void *to, const void *from, unsigned long n)
127
{
128
        int i = verify_area(VERIFY_WRITE, to, n);
129
        if (i)
130
                return i;
131
        memcpy_tofs(to, from, n);
132
        return 0;
133
}
134
#endif
135
 
136
#if LINUX_VERSION_CODE >= 0x20123
137
#include <linux/init.h>
138
#else
139
#define __init
140
#define __initdata
141
#define __initfunc(x) x
142
#endif
143
 
144
/* --------------------------------------------------------------------- */
145
 
146
#define BAYCOM_DEBUG
147
 
148
/*
149
 * modem options; bit mask
150
 */
151
#define BAYCOM_OPTIONS_SOFTDCD  1
152
 
153
/* --------------------------------------------------------------------- */
154
 
155
static const char bc_drvname[] = "baycom";
156
static const char bc_drvinfo[] = KERN_INFO "baycom: (C) 1996 Thomas Sailer, HB9JNX/AE4WA\n"
157
KERN_INFO "baycom: version 0.3 compiled " __TIME__ " " __DATE__ "\n";
158
 
159
/* --------------------------------------------------------------------- */
160
 
161
#define NR_PORTS 4
162
 
163
static struct device baycom_device[NR_PORTS];
164
 
165
static struct {
166
        char *mode;
167
        int iobase, irq;
168
} baycom_ports[NR_PORTS] = { { NULL, 0, 0 }, };
169
 
170
/* --------------------------------------------------------------------- */
171
 
172
#define RBR(iobase) (iobase+0)
173
#define THR(iobase) (iobase+0)
174
#define IER(iobase) (iobase+1)
175
#define IIR(iobase) (iobase+2)
176
#define FCR(iobase) (iobase+2)
177
#define LCR(iobase) (iobase+3)
178
#define MCR(iobase) (iobase+4)
179
#define LSR(iobase) (iobase+5)
180
#define MSR(iobase) (iobase+6)
181
#define SCR(iobase) (iobase+7)
182
#define DLL(iobase) (iobase+0)
183
#define DLM(iobase) (iobase+1)
184
 
185
#define SER12_EXTENT 8
186
 
187
#define LPT_DATA(iobase)    (iobase+0)
188
#define LPT_STATUS(iobase)  (iobase+1)
189
#define LPT_CONTROL(iobase) (iobase+2)
190
#define LPT_IRQ_ENABLE      0x10
191
#define PAR96_BURSTBITS 16
192
#define PAR96_BURST     4
193
#define PAR96_PTT       2
194
#define PAR96_TXBIT     1
195
#define PAR96_ACK       0x40
196
#define PAR96_RXBIT     0x20
197
#define PAR96_DCD       0x10
198
#define PAR97_POWER     0xf8
199
 
200
#define PAR96_EXTENT 3
201
 
202
/* ---------------------------------------------------------------------- */
203
/*
204
 * Information that need to be kept for each board.
205
 */
206
 
207
struct baycom_state {
208
        struct hdlcdrv_state hdrv;
209
 
210
        unsigned int options;
211
 
212
        struct modem_state {
213
                short arb_divider;
214
                unsigned char flags;
215
                unsigned int shreg;
216
                struct modem_state_ser12 {
217
                        unsigned char last_sample;
218
                        unsigned char interm_sample;
219
                        unsigned int bit_pll;
220
                        unsigned int dcd_shreg;
221
                        int dcd_sum0, dcd_sum1, dcd_sum2;
222
                        unsigned int dcd_time;
223
                        unsigned char last_rxbit;
224
                        unsigned char tx_bit;
225
                } ser12;
226
                struct modem_state_par96 {
227
                        int dcd_count;
228
                        unsigned int dcd_shreg;
229
                        unsigned long descram;
230
                        unsigned long scram;
231
                } par96;
232
        } modem;
233
 
234
#ifdef BAYCOM_DEBUG
235
        struct debug_vals {
236
                unsigned long last_jiffies;
237
                unsigned cur_intcnt;
238
                unsigned last_intcnt;
239
                int cur_pllcorr;
240
                int last_pllcorr;
241
        } debug_vals;
242
#endif /* BAYCOM_DEBUG */
243
};
244
 
245
/* --------------------------------------------------------------------- */
246
 
247
#define min(a, b) (((a) < (b)) ? (a) : (b))
248
#define max(a, b) (((a) > (b)) ? (a) : (b))
249
 
250
/* --------------------------------------------------------------------- */
251
 
252
static void inline baycom_int_freq(struct baycom_state *bc)
253
{
254
#ifdef BAYCOM_DEBUG
255
        unsigned long cur_jiffies = jiffies;
256
        /*
257
         * measure the interrupt frequency
258
         */
259
        bc->debug_vals.cur_intcnt++;
260
        if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) {
261
                bc->debug_vals.last_jiffies = cur_jiffies;
262
                bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt;
263
                bc->debug_vals.cur_intcnt = 0;
264
                bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr;
265
                bc->debug_vals.cur_pllcorr = 0;
266
        }
267
#endif /* BAYCOM_DEBUG */
268
}
269
 
270
/* --------------------------------------------------------------------- */
271
/*
272
 * ===================== SER12 specific routines =========================
273
 */
274
 
275
static void inline ser12_set_divisor(struct device *dev,
276
                                     unsigned char divisor)
277
{
278
        outb(0x81, LCR(dev->base_addr));        /* DLAB = 1 */
279
        outb(divisor, DLL(dev->base_addr));
280
        outb(0, DLM(dev->base_addr));
281
        outb(0x01, LCR(dev->base_addr));        /* word length = 6 */
282
        /*
283
         * make sure the next interrupt is generated;
284
         * 0 must be used to power the modem; the modem draws its
285
         * power from the TxD line
286
         */
287
        outb(0x00, THR(dev->base_addr));
288
        /*
289
         * it is important not to set the divider while transmitting;
290
         * this reportedly makes some UARTs generating interrupts
291
         * in the hundredthousands per second region
292
         * Reported by: Ignacio.Arenaza@studi.epfl.ch (Ignacio Arenaza Nuno)
293
         */
294
}
295
 
296
/* --------------------------------------------------------------------- */
297
 
298
/*
299
 * must call the TX arbitrator every 10ms
300
 */
301
#define SER12_ARB_DIVIDER(bc) ((bc->options & BAYCOM_OPTIONS_SOFTDCD) ? \
302
                               36 : 24)
303
#define SER12_DCD_INTERVAL(bc) ((bc->options & BAYCOM_OPTIONS_SOFTDCD) ? \
304
                                240 : 12)
305
 
306
static inline void ser12_tx(struct device *dev, struct baycom_state *bc)
307
{
308
        /* one interrupt per channel bit */
309
        ser12_set_divisor(dev, 12);
310
        /*
311
         * first output the last bit (!) then call HDLC transmitter,
312
         * since this may take quite long
313
         */
314
        outb(0x0e | (!!bc->modem.ser12.tx_bit), MCR(dev->base_addr));
315
        if (bc->modem.shreg <= 1)
316
                bc->modem.shreg = 0x10000 | hdlcdrv_getbits(&bc->hdrv);
317
        bc->modem.ser12.tx_bit = !(bc->modem.ser12.tx_bit ^
318
                                   (bc->modem.shreg & 1));
319
        bc->modem.shreg >>= 1;
320
}
321
 
322
/* --------------------------------------------------------------------- */
323
 
324
static inline void ser12_rx(struct device *dev, struct baycom_state *bc)
325
{
326
        unsigned char cur_s;
327
        /*
328
         * do demodulator
329
         */
330
        cur_s = inb(MSR(dev->base_addr)) & 0x10;        /* the CTS line */
331
        hdlcdrv_channelbit(&bc->hdrv, cur_s);
332
        bc->modem.ser12.dcd_shreg = (bc->modem.ser12.dcd_shreg << 1) |
333
                (cur_s != bc->modem.ser12.last_sample);
334
        bc->modem.ser12.last_sample = cur_s;
335
        if(bc->modem.ser12.dcd_shreg & 1) {
336
                if (bc->options & BAYCOM_OPTIONS_SOFTDCD) {
337
                        unsigned int dcdspos, dcdsneg;
338
 
339
                        dcdspos = dcdsneg = 0;
340
                        dcdspos += ((bc->modem.ser12.dcd_shreg >> 1) & 1);
341
                        if (!(bc->modem.ser12.dcd_shreg & 0x7ffffffe))
342
                                dcdspos += 2;
343
                        dcdsneg += ((bc->modem.ser12.dcd_shreg >> 2) & 1);
344
                        dcdsneg += ((bc->modem.ser12.dcd_shreg >> 3) & 1);
345
                        dcdsneg += ((bc->modem.ser12.dcd_shreg >> 4) & 1);
346
 
347
                        bc->modem.ser12.dcd_sum0 += 16*dcdspos - dcdsneg;
348
                } else
349
                        bc->modem.ser12.dcd_sum0--;
350
        }
351
        if(!bc->modem.ser12.dcd_time) {
352
                hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 +
353
                                           bc->modem.ser12.dcd_sum1 +
354
                                           bc->modem.ser12.dcd_sum2) < 0);
355
                bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1;
356
                bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0;
357
                /* offset to ensure DCD off on silent input */
358
                bc->modem.ser12.dcd_sum0 = 2;
359
                bc->modem.ser12.dcd_time = SER12_DCD_INTERVAL(bc);
360
        }
361
        bc->modem.ser12.dcd_time--;
362
        if (bc->options & BAYCOM_OPTIONS_SOFTDCD) {
363
                /*
364
                 * PLL code for the improved software DCD algorithm
365
                 */
366
                if (bc->modem.ser12.interm_sample) {
367
                        /*
368
                         * intermediate sample; set timing correction to normal
369
                         */
370
                        ser12_set_divisor(dev, 4);
371
                } else {
372
                        /*
373
                         * do PLL correction and call HDLC receiver
374
                         */
375
                        switch (bc->modem.ser12.dcd_shreg & 7) {
376
                        case 1: /* transition too late */
377
                                ser12_set_divisor(dev, 5);
378
#ifdef BAYCOM_DEBUG
379
                                bc->debug_vals.cur_pllcorr++;
380
#endif /* BAYCOM_DEBUG */
381
                                break;
382
                        case 4: /* transition too early */
383
                                ser12_set_divisor(dev, 3);
384
#ifdef BAYCOM_DEBUG
385
                                bc->debug_vals.cur_pllcorr--;
386
#endif /* BAYCOM_DEBUG */
387
                                break;
388
                        default:
389
                                ser12_set_divisor(dev, 4);
390
                                break;
391
                        }
392
                        bc->modem.shreg >>= 1;
393
                        if (bc->modem.ser12.last_sample ==
394
                            bc->modem.ser12.last_rxbit)
395
                                bc->modem.shreg |= 0x10000;
396
                        bc->modem.ser12.last_rxbit =
397
                                bc->modem.ser12.last_sample;
398
                }
399
                if (++bc->modem.ser12.interm_sample >= 3)
400
                        bc->modem.ser12.interm_sample = 0;
401
                /*
402
                 * DCD stuff
403
                 */
404
                if (bc->modem.ser12.dcd_shreg & 1) {
405
                        unsigned int dcdspos, dcdsneg;
406
 
407
                        dcdspos = dcdsneg = 0;
408
                        dcdspos += ((bc->modem.ser12.dcd_shreg >> 1) & 1);
409
                        dcdspos += (!(bc->modem.ser12.dcd_shreg & 0x7ffffffe))
410
                                << 1;
411
                        dcdsneg += ((bc->modem.ser12.dcd_shreg >> 2) & 1);
412
                        dcdsneg += ((bc->modem.ser12.dcd_shreg >> 3) & 1);
413
                        dcdsneg += ((bc->modem.ser12.dcd_shreg >> 4) & 1);
414
 
415
                        bc->modem.ser12.dcd_sum0 += 16*dcdspos - dcdsneg;
416
                }
417
        } else {
418
                /*
419
                 * PLL algorithm for the hardware squelch DCD algorithm
420
                 */
421
                if (bc->modem.ser12.interm_sample) {
422
                        /*
423
                         * intermediate sample; set timing correction to normal
424
                         */
425
                        ser12_set_divisor(dev, 6);
426
                } else {
427
                        /*
428
                         * do PLL correction and call HDLC receiver
429
                         */
430
                        switch (bc->modem.ser12.dcd_shreg & 3) {
431
                        case 1: /* transition too late */
432
                                ser12_set_divisor(dev, 7);
433
#ifdef BAYCOM_DEBUG
434
                                bc->debug_vals.cur_pllcorr++;
435
#endif /* BAYCOM_DEBUG */
436
                                break;
437
                        case 2: /* transition too early */
438
                                ser12_set_divisor(dev, 5);
439
#ifdef BAYCOM_DEBUG
440
                                bc->debug_vals.cur_pllcorr--;
441
#endif /* BAYCOM_DEBUG */
442
                                break;
443
                        default:
444
                                ser12_set_divisor(dev, 6);
445
                                break;
446
                        }
447
                        bc->modem.shreg >>= 1;
448
                        if (bc->modem.ser12.last_sample ==
449
                            bc->modem.ser12.last_rxbit)
450
                                bc->modem.shreg |= 0x10000;
451
                        bc->modem.ser12.last_rxbit =
452
                                bc->modem.ser12.last_sample;
453
                }
454
                bc->modem.ser12.interm_sample = !bc->modem.ser12.interm_sample;
455
                /*
456
                 * DCD stuff
457
                 */
458
                bc->modem.ser12.dcd_sum0 -= (bc->modem.ser12.dcd_shreg & 1);
459
        }
460
        outb(0x0d, MCR(dev->base_addr));                /* transmitter off */
461
        if (bc->modem.shreg & 1) {
462
                hdlcdrv_putbits(&bc->hdrv, bc->modem.shreg >> 1);
463
                bc->modem.shreg = 0x10000;
464
        }
465
        if(!bc->modem.ser12.dcd_time) {
466
                hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 +
467
                                           bc->modem.ser12.dcd_sum1 +
468
                                           bc->modem.ser12.dcd_sum2) < 0);
469
                bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1;
470
                bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0;
471
                /* offset to ensure DCD off on silent input */
472
                bc->modem.ser12.dcd_sum0 = 2;
473
                bc->modem.ser12.dcd_time = SER12_DCD_INTERVAL(bc);
474
        }
475
        bc->modem.ser12.dcd_time--;
476
}
477
 
478
/* --------------------------------------------------------------------- */
479
 
480
static void ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs)
481
{
482
        struct device *dev = (struct device *)dev_id;
483
        struct baycom_state *bc = (struct baycom_state *)dev->priv;
484
 
485
        if (!dev || !bc || bc->hdrv.magic != HDLCDRV_MAGIC)
486
                return;
487
 
488
        baycom_int_freq(bc);
489
        /*
490
         * check if transmitter active
491
         */
492
        if (hdlcdrv_ptt(&bc->hdrv))
493
                ser12_tx(dev, bc);
494
        else {
495
                ser12_rx(dev, bc);
496
                if (--bc->modem.arb_divider <= 0) {
497
                        bc->modem.arb_divider = SER12_ARB_DIVIDER(bc);
498
                        sti();
499
                        hdlcdrv_arbitrate(dev, &bc->hdrv);
500
                }
501
        }
502
        sti();
503
        hdlcdrv_transmitter(dev, &bc->hdrv);
504
        hdlcdrv_receiver(dev, &bc->hdrv);
505
}
506
 
507
/* --------------------------------------------------------------------- */
508
 
509
enum uart { c_uart_unknown, c_uart_8250,
510
        c_uart_16450, c_uart_16550, c_uart_16550A};
511
static const char *uart_str[] =
512
        { "unknown", "8250", "16450", "16550", "16550A" };
513
 
514
static enum uart ser12_check_uart(unsigned int iobase)
515
{
516
        unsigned char b1,b2,b3;
517
        enum uart u;
518
        enum uart uart_tab[] =
519
                { c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A };
520
 
521
        b1 = inb(MCR(iobase));
522
        outb(b1 | 0x10, MCR(iobase));   /* loopback mode */
523
        b2 = inb(MSR(iobase));
524
        outb(0x1a, MCR(iobase));
525
        b3 = inb(MSR(iobase)) & 0xf0;
526
        outb(b1, MCR(iobase));                  /* restore old values */
527
        outb(b2, MSR(iobase));
528
        if (b3 != 0x90)
529
                return c_uart_unknown;
530
        inb(RBR(iobase));
531
        inb(RBR(iobase));
532
        outb(0x01, FCR(iobase));                /* enable FIFOs */
533
        u = uart_tab[(inb(IIR(iobase)) >> 6) & 3];
534
        if (u == c_uart_16450) {
535
                outb(0x5a, SCR(iobase));
536
                b1 = inb(SCR(iobase));
537
                outb(0xa5, SCR(iobase));
538
                b2 = inb(SCR(iobase));
539
                if ((b1 != 0x5a) || (b2 != 0xa5))
540
                        u = c_uart_8250;
541
        }
542
        return u;
543
}
544
 
545
/* --------------------------------------------------------------------- */
546
 
547
static int ser12_open(struct device *dev)
548
{
549
        struct baycom_state *bc = (struct baycom_state *)dev->priv;
550
        enum uart u;
551
 
552
        if (!dev || !bc)
553
                return -ENXIO;
554
        if (!dev->base_addr || dev->base_addr > 0x1000-SER12_EXTENT ||
555
            dev->irq < 2 || dev->irq > 15)
556
                return -ENXIO;
557
        if (check_region(dev->base_addr, SER12_EXTENT))
558
                return -EACCES;
559
        memset(&bc->modem, 0, sizeof(bc->modem));
560
        bc->hdrv.par.bitrate = 1200;
561
        if ((u = ser12_check_uart(dev->base_addr)) == c_uart_unknown)
562
                return -EIO;
563
        outb(0, FCR(dev->base_addr));  /* disable FIFOs */
564
        outb(0x0d, MCR(dev->base_addr));
565
        outb(0x0d, MCR(dev->base_addr));
566
        outb(0, IER(dev->base_addr));
567
        if (request_irq(dev->irq, ser12_interrupt, SA_INTERRUPT,
568
                        "baycom_ser12", dev))
569
                return -EBUSY;
570
        request_region(dev->base_addr, SER12_EXTENT, "baycom_ser12");
571
        /*
572
         * enable transmitter empty interrupt
573
         */
574
        outb(2, IER(dev->base_addr));
575
        /*
576
         * set the SIO to 6 Bits/character and 19200 or 28800 baud, so that
577
         * we get exactly (hopefully) 2 or 3 interrupts per radio symbol,
578
         * depending on the usage of the software DCD routine
579
         */
580
        ser12_set_divisor(dev, (bc->options & BAYCOM_OPTIONS_SOFTDCD) ? 4 : 6);
581
        printk(KERN_INFO "%s: ser12 at iobase 0x%lx irq %u options "
582
               "0x%x uart %s\n", bc_drvname, dev->base_addr, dev->irq,
583
               bc->options, uart_str[u]);
584
        MOD_INC_USE_COUNT;
585
        return 0;
586
}
587
 
588
/* --------------------------------------------------------------------- */
589
 
590
static int ser12_close(struct device *dev)
591
{
592
        struct baycom_state *bc = (struct baycom_state *)dev->priv;
593
 
594
        if (!dev || !bc)
595
                return -EINVAL;
596
        /*
597
         * disable interrupts
598
         */
599
        outb(0, IER(dev->base_addr));
600
        outb(1, MCR(dev->base_addr));
601
        free_irq(dev->irq, dev);
602
        release_region(dev->base_addr, SER12_EXTENT);
603
        printk(KERN_INFO "%s: close ser12 at iobase 0x%lx irq %u\n",
604
               bc_drvname, dev->base_addr, dev->irq);
605
        MOD_DEC_USE_COUNT;
606
        return 0;
607
}
608
 
609
/* --------------------------------------------------------------------- */
610
/*
611
 * ===================== PAR96 specific routines =========================
612
 */
613
 
614
#define PAR96_DESCRAM_TAP1 0x20000
615
#define PAR96_DESCRAM_TAP2 0x01000
616
#define PAR96_DESCRAM_TAP3 0x00001
617
 
618
#define PAR96_DESCRAM_TAPSH1 17
619
#define PAR96_DESCRAM_TAPSH2 12
620
#define PAR96_DESCRAM_TAPSH3 0
621
 
622
#define PAR96_SCRAM_TAP1 0x20000 /* X^17 */
623
#define PAR96_SCRAM_TAPN 0x00021 /* X^0+X^5 */
624
 
625
/* --------------------------------------------------------------------- */
626
 
627
static inline void par96_tx(struct device *dev, struct baycom_state *bc)
628
{
629
        int i;
630
        unsigned int data = hdlcdrv_getbits(&bc->hdrv);
631
 
632
        for(i = 0; i < PAR96_BURSTBITS; i++, data >>= 1) {
633
                unsigned char val = PAR97_POWER;
634
                bc->modem.par96.scram = ((bc->modem.par96.scram << 1) |
635
                                         (bc->modem.par96.scram & 1));
636
                if (!(data & 1))
637
                        bc->modem.par96.scram ^= 1;
638
                if (bc->modem.par96.scram & (PAR96_SCRAM_TAP1 << 1))
639
                        bc->modem.par96.scram ^=
640
                                (PAR96_SCRAM_TAPN << 1);
641
                if (bc->modem.par96.scram & (PAR96_SCRAM_TAP1 << 2))
642
                        val |= PAR96_TXBIT;
643
                outb(val, LPT_DATA(dev->base_addr));
644
                outb(val | PAR96_BURST, LPT_DATA(dev->base_addr));
645
        }
646
}
647
 
648
/* --------------------------------------------------------------------- */
649
 
650
static inline void par96_rx(struct device *dev, struct baycom_state *bc)
651
{
652
        int i;
653
        unsigned int data, mask, mask2, descx;
654
 
655
        /*
656
         * do receiver; differential decode and descramble on the fly
657
         */
658
        for(data = i = 0; i < PAR96_BURSTBITS; i++) {
659
                bc->modem.par96.descram = (bc->modem.par96.descram << 1);
660
                if (inb(LPT_STATUS(dev->base_addr)) & PAR96_RXBIT)
661
                        bc->modem.par96.descram |= 1;
662
                descx = bc->modem.par96.descram ^
663
                        (bc->modem.par96.descram >> 1);
664
                /* now the diff decoded data is inverted in descram */
665
                outb(PAR97_POWER | PAR96_PTT, LPT_DATA(dev->base_addr));
666
                descx ^= ((descx >> PAR96_DESCRAM_TAPSH1) ^
667
                          (descx >> PAR96_DESCRAM_TAPSH2));
668
                data >>= 1;
669
                if (!(descx & 1))
670
                        data |= 0x8000;
671
                outb(PAR97_POWER | PAR96_PTT | PAR96_BURST,
672
                     LPT_DATA(dev->base_addr));
673
        }
674
        hdlcdrv_putbits(&bc->hdrv, data);
675
        /*
676
         * do DCD algorithm
677
         */
678
        if (bc->options & BAYCOM_OPTIONS_SOFTDCD) {
679
                bc->modem.par96.dcd_shreg = (bc->modem.par96.dcd_shreg >> 16)
680
                        | (data << 16);
681
                /* search for flags and set the dcd counter appropriately */
682
                for(mask = 0x1fe00, mask2 = 0xfc00, i = 0;
683
                    i < PAR96_BURSTBITS; i++, mask <<= 1, mask2 <<= 1)
684
                        if ((bc->modem.par96.dcd_shreg & mask) == mask2)
685
                                bc->modem.par96.dcd_count = HDLCDRV_MAXFLEN+4;
686
                /* check for abort/noise sequences */
687
                for(mask = 0x1fe00, mask2 = 0x1fe00, i = 0;
688
                    i < PAR96_BURSTBITS; i++, mask <<= 1, mask2 <<= 1)
689
                        if (((bc->modem.par96.dcd_shreg & mask) == mask2) &&
690
                            (bc->modem.par96.dcd_count >= 0))
691
                                bc->modem.par96.dcd_count -= HDLCDRV_MAXFLEN-10;
692
                /* decrement and set the dcd variable */
693
                if (bc->modem.par96.dcd_count >= 0)
694
                        bc->modem.par96.dcd_count -= 2;
695
                hdlcdrv_setdcd(&bc->hdrv, bc->modem.par96.dcd_count > 0);
696
        } else {
697
                hdlcdrv_setdcd(&bc->hdrv, !!(inb(LPT_STATUS(dev->base_addr))
698
                                             & PAR96_DCD));
699
        }
700
}
701
 
702
/* --------------------------------------------------------------------- */
703
 
704
static void par96_interrupt(int irq, void *dev_id, struct pt_regs *regs)
705
{
706
        struct device *dev = (struct device *)dev_id;
707
        struct baycom_state *bc = (struct baycom_state *)dev->priv;
708
 
709
        if (!dev || !bc || bc->hdrv.magic != HDLCDRV_MAGIC)
710
                return;
711
 
712
        baycom_int_freq(bc);
713
        /*
714
         * check if transmitter active
715
         */
716
        if (hdlcdrv_ptt(&bc->hdrv))
717
                par96_tx(dev, bc);
718
        else {
719
                par96_rx(dev, bc);
720
                if (--bc->modem.arb_divider <= 0) {
721
                        bc->modem.arb_divider = 6;
722
                        sti();
723
                        hdlcdrv_arbitrate(dev, &bc->hdrv);
724
                }
725
        }
726
        sti();
727
        hdlcdrv_transmitter(dev, &bc->hdrv);
728
        hdlcdrv_receiver(dev, &bc->hdrv);
729
}
730
 
731
/* --------------------------------------------------------------------- */
732
 
733
static int par96_check_lpt(unsigned int iobase)
734
{
735
        unsigned char b1,b2;
736
        int i;
737
 
738
        b1 = inb(LPT_DATA(iobase));
739
        b2 = inb(LPT_CONTROL(iobase));
740
        outb(0xaa, LPT_DATA(iobase));
741
        i = inb(LPT_DATA(iobase)) == 0xaa;
742
        outb(0x55, LPT_DATA(iobase));
743
        i &= inb(LPT_DATA(iobase)) == 0x55;
744
        outb(0x0a, LPT_CONTROL(iobase));
745
        i &= (inb(LPT_CONTROL(iobase)) & 0xf) == 0x0a;
746
        outb(0x05, LPT_CONTROL(iobase));
747
        i &= (inb(LPT_CONTROL(iobase)) & 0xf) == 0x05;
748
        outb(b1, LPT_DATA(iobase));
749
        outb(b2, LPT_CONTROL(iobase));
750
        return !i;
751
}
752
 
753
/* --------------------------------------------------------------------- */
754
 
755
static int par96_open(struct device *dev)
756
{
757
        struct baycom_state *bc = (struct baycom_state *)dev->priv;
758
 
759
        if (!dev || !bc)
760
                return -ENXIO;
761
        if (!dev->base_addr || dev->base_addr > 0x1000-PAR96_EXTENT ||
762
            dev->irq < 2 || dev->irq > 15)
763
                return -ENXIO;
764
        if (check_region(dev->base_addr, PAR96_EXTENT))
765
                return -EACCES;
766
        memset(&bc->modem, 0, sizeof(bc->modem));
767
        bc->hdrv.par.bitrate = 9600;
768
        if (par96_check_lpt(dev->base_addr))
769
                return -EIO;
770
        /* disable interrupt */
771
        outb(0, LPT_CONTROL(dev->base_addr));
772
         /* switch off PTT */
773
        outb(PAR96_PTT | PAR97_POWER, LPT_DATA(dev->base_addr));
774
        printk(KERN_INFO "%s: par96 at iobase 0x%lx irq %u options 0x%x\n",
775
               bc_drvname, dev->base_addr, dev->irq, bc->options);
776
        if (request_irq(dev->irq, par96_interrupt, SA_INTERRUPT,
777
                        "baycom_par96", dev))
778
                return -EBUSY;
779
        request_region(dev->base_addr, PAR96_EXTENT, "baycom_par96");
780
        /* enable interrupt */
781
        outb(LPT_IRQ_ENABLE, LPT_CONTROL(dev->base_addr));
782
        MOD_INC_USE_COUNT;
783
        return 0;
784
}
785
 
786
/* --------------------------------------------------------------------- */
787
 
788
static int par96_close(struct device *dev)
789
{
790
        struct baycom_state *bc = (struct baycom_state *)dev->priv;
791
 
792
        if (!dev || !bc)
793
                return -EINVAL;
794
        /* disable interrupt */
795
        outb(0, LPT_CONTROL(dev->base_addr));
796
        /* switch off PTT */
797
        outb(PAR96_PTT | PAR97_POWER, LPT_DATA(dev->base_addr));
798
        free_irq(dev->irq, dev);
799
        release_region(dev->base_addr, PAR96_EXTENT);
800
        printk(KERN_INFO "%s: close par96 at iobase 0x%lx irq %u\n",
801
               bc_drvname, dev->base_addr, dev->irq);
802
        MOD_DEC_USE_COUNT;
803
        return 0;
804
}
805
 
806
/* --------------------------------------------------------------------- */
807
/*
808
 * ===================== hdlcdrv driver interface =========================
809
 */
810
 
811
/* --------------------------------------------------------------------- */
812
 
813
static int baycom_ioctl(struct device *dev, struct ifreq *ifr,
814
                        struct hdlcdrv_ioctl *hi, int cmd);
815
 
816
/* --------------------------------------------------------------------- */
817
 
818
static struct hdlcdrv_ops ser12_ops = {
819
        bc_drvname,
820
        bc_drvinfo,
821
        ser12_open,
822
        ser12_close,
823
        baycom_ioctl
824
};
825
 
826
/* --------------------------------------------------------------------- */
827
 
828
static struct hdlcdrv_ops par96_ops = {
829
        bc_drvname,
830
        bc_drvinfo,
831
        par96_open,
832
        par96_close,
833
        baycom_ioctl
834
};
835
 
836
/* --------------------------------------------------------------------- */
837
 
838
static struct hdlcdrv_ops dummy_ops = {
839
        bc_drvname,
840
        bc_drvinfo,
841
        NULL,
842
        NULL,
843
        baycom_ioctl
844
};
845
 
846
/* --------------------------------------------------------------------- */
847
 
848
static int baycom_setmode(struct baycom_state *bc, char *modestr)
849
{
850
        struct hdlcdrv_ops *newops = NULL;
851
        unsigned long flags;
852
 
853
        if (!strncmp(modestr, "off", 3))
854
                newops = &dummy_ops;
855
        else if (!strncmp(modestr, "ser12", 5))
856
                newops = &ser12_ops;
857
        else if (!strncmp(modestr, "par96", 5))
858
                newops = &par96_ops;
859
        else
860
                return -EINVAL;
861
        save_flags(flags);
862
        cli();
863
        bc->hdrv.ops = newops;
864
        bc->options = !!strchr(modestr, '*');
865
        restore_flags(flags);
866
        return 0;
867
}
868
 
869
/* --------------------------------------------------------------------- */
870
 
871
static int baycom_ioctl(struct device *dev, struct ifreq *ifr,
872
                        struct hdlcdrv_ioctl *hi, int cmd)
873
{
874
        struct baycom_state *bc;
875
        struct baycom_ioctl bi;
876
        int cmd2;
877
 
878
        if (!dev || !dev->priv ||
879
            ((struct baycom_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) {
880
                printk(KERN_ERR "bc_ioctl: invalid device struct\n");
881
                return -EINVAL;
882
        }
883
        bc = (struct baycom_state *)dev->priv;
884
 
885
        if (cmd != SIOCDEVPRIVATE)
886
                return -ENOIOCTLCMD;
887
        if (get_user(cmd2, (int *)ifr->ifr_data))
888
                return -EFAULT;
889
        switch (hi->cmd) {
890
        default:
891
                break;
892
 
893
        case HDLCDRVCTL_GETMODE:
894
                if (bc->hdrv.ops == &ser12_ops)
895
                        strcpy(hi->data.modename, "ser12");
896
                else if (bc->hdrv.ops == &par96_ops)
897
                        strcpy(hi->data.modename, "par96");
898
                else if (bc->hdrv.ops == &dummy_ops)
899
                        strcpy(hi->data.modename, "off");
900
                else
901
                        strcpy(hi->data.modename, "invalid");
902
                if (bc->options & 1)
903
                        strcat(hi->data.modename, "*");
904
                if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl)))
905
                        return -EFAULT;
906
                return 0;
907
 
908
        case HDLCDRVCTL_SETMODE:
909
                if (!suser() || dev->start)
910
                        return -EACCES;
911
                hi->data.modename[sizeof(hi->data.modename)-1] = '\0';
912
                return baycom_setmode(bc, hi->data.modename);
913
 
914
        case HDLCDRVCTL_MODELIST:
915
                strcpy(hi->data.modename, "ser12,par96");
916
                if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl)))
917
                        return -EFAULT;
918
                return 0;
919
 
920
        case HDLCDRVCTL_MODEMPARMASK:
921
                return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ;
922
 
923
        }
924
 
925
        if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi)))
926
                return -EFAULT;
927
        switch (bi.cmd) {
928
        default:
929
                return -ENOIOCTLCMD;
930
 
931
#ifdef BAYCOM_DEBUG
932
        case BAYCOMCTL_GETDEBUG:
933
                bi.data.dbg.debug1 = bc->hdrv.ptt_keyed;
934
                bi.data.dbg.debug2 = bc->debug_vals.last_intcnt;
935
                bi.data.dbg.debug3 = bc->debug_vals.last_pllcorr;
936
                break;
937
#endif /* BAYCOM_DEBUG */
938
 
939
        }
940
        if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi)))
941
                return -EFAULT;
942
        return 0;
943
 
944
}
945
 
946
/* --------------------------------------------------------------------- */
947
 
948
__initfunc(int baycom_init(void))
949
{
950
        int i, j, found = 0;
951
        char set_hw = 1;
952
        struct baycom_state *bc;
953
        char ifname[HDLCDRV_IFNAMELEN];
954
 
955
 
956
        printk(bc_drvinfo);
957
        /*
958
         * register net devices
959
         */
960
        for (i = 0; i < NR_PORTS; i++) {
961
                struct device *dev = baycom_device+i;
962
                sprintf(ifname, "bc%d", i);
963
 
964
                if (!baycom_ports[i].mode)
965
                        set_hw = 0;
966
                if (!set_hw)
967
                        baycom_ports[i].iobase = baycom_ports[i].irq = 0;
968
                j = hdlcdrv_register_hdlcdrv(dev, &dummy_ops,
969
                                             sizeof(struct baycom_state),
970
                                             ifname, baycom_ports[i].iobase,
971
                                             baycom_ports[i].irq, 0);
972
                if (!j) {
973
                        bc = (struct baycom_state *)dev->priv;
974
                        if (set_hw && baycom_setmode(bc, baycom_ports[i].mode))
975
                                set_hw = 0;
976
                        found++;
977
                } else {
978
                        printk(KERN_WARNING "%s: cannot register net device\n",
979
                               bc_drvname);
980
                }
981
        }
982
        if (!found)
983
                return -ENXIO;
984
        return 0;
985
}
986
 
987
/* --------------------------------------------------------------------- */
988
 
989
#ifdef MODULE
990
 
991
/*
992
 * command line settable parameters
993
 */
994
static char *mode = NULL;
995
static int iobase = 0x3f8;
996
static int irq = 4;
997
 
998
#if LINUX_VERSION_CODE >= 0x20115
999
 
1000
MODULE_PARM(mode, "s");
1001
MODULE_PARM_DESC(mode, "baycom operating mode; eg. ser12* or par96");
1002
MODULE_PARM(iobase, "i");
1003
MODULE_PARM_DESC(iobase, "baycom io base address");
1004
MODULE_PARM(irq, "i");
1005
MODULE_PARM_DESC(irq, "baycom irq number");
1006
 
1007
MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
1008
MODULE_DESCRIPTION("Baycom ser12, par96 and picpar amateur radio modem driver");
1009
 
1010
#endif
1011
 
1012
__initfunc(int init_module(void))
1013
{
1014
        baycom_ports[0].mode = mode;
1015
        baycom_ports[0].iobase = iobase;
1016
        baycom_ports[0].irq = irq;
1017
        baycom_ports[1].mode = NULL;
1018
 
1019
        return baycom_init();
1020
}
1021
 
1022
/* --------------------------------------------------------------------- */
1023
 
1024
void cleanup_module(void)
1025
{
1026
        int i;
1027
 
1028
        for(i = 0; i < NR_PORTS; i++) {
1029
                struct device *dev = baycom_device+i;
1030
                struct baycom_state *bc = (struct baycom_state *)dev->priv;
1031
 
1032
                if (bc) {
1033
                        if (bc->hdrv.magic != HDLCDRV_MAGIC)
1034
                                printk(KERN_ERR "baycom: invalid magic in "
1035
                                       "cleanup_module\n");
1036
                        else
1037
                                hdlcdrv_unregister_hdlcdrv(dev);
1038
                }
1039
        }
1040
}
1041
 
1042
#else /* MODULE */
1043
/* --------------------------------------------------------------------- */
1044
/*
1045
 * format: baycom=io,irq,mode
1046
 * mode: {ser12,par96}[*]
1047
 * * indicates sofware DCD
1048
 */
1049
 
1050
__initfunc(void baycom_setup(char *str, int *ints))
1051
{
1052
        int i;
1053
 
1054
        for (i = 0; (i < NR_PORTS) && (baycom_ports[i].mode); i++);
1055
        if ((i >= NR_PORTS) || (ints[0] < 2)) {
1056
                printk(KERN_INFO "%s: too many or invalid interface "
1057
                       "specifications\n", bc_drvname);
1058
                return;
1059
        }
1060
        baycom_ports[i].mode = str;
1061
        baycom_ports[i].iobase = ints[1];
1062
        baycom_ports[i].irq = ints[2];
1063
        if (i < NR_PORTS-1)
1064
                baycom_ports[i+1].mode = NULL;
1065
}
1066
 
1067
#endif /* MODULE */
1068
/* --------------------------------------------------------------------- */

powered by: WebSVN 2.1.0

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