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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [drivers/] [net/] [soundmodem/] [sm.c] - Blame information for rev 199

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*****************************************************************************/
2
 
3
/*
4
 *      sm.c  -- soundcard radio modem driver.
5
 *
6
 *      Copyright (C) 1996-1998  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
 *  Command line options (insmod command line)
28
 *
29
 *  mode     mode string; eg. "wss:afsk1200"
30
 *  iobase   base address of the soundcard; common values are 0x220 for sbc,
31
 *           0x530 for wss
32
 *  irq      interrupt number; common values are 7 or 5 for sbc, 11 for wss
33
 *  dma      dma number; common values are 0 or 1
34
 *
35
 *
36
 *  History:
37
 *   0.1  21.09.96  Started
38
 *        18.10.96  Changed to new user space access routines (copy_{to,from}_user)
39
 *   0.4  21.01.97  Separately compileable soundcard/modem modules
40
 *   0.5  03.03.97  fixed LPT probing (check_lpt result was interpreted the wrong way round)
41
 *   0.6  16.04.97  init code/data tagged
42
 *   0.7  30.07.97  fixed halfduplex interrupt handlers/hotfix for CS423X
43
 *   0.8  14.04.98  cleanups
44
 */
45
 
46
/*****************************************************************************/
47
 
48
#include <linux/config.h>
49
#include <linux/module.h>
50
#include <linux/ptrace.h>
51
#include <linux/types.h>
52
#include <linux/fcntl.h>
53
#include <linux/ioport.h>
54
#include <linux/net.h>
55
#include <linux/in.h>
56
#include <linux/string.h>
57
#include <asm/system.h>
58
#include <asm/io.h>
59
#include <asm/bitops.h>
60
#include <linux/delay.h>
61
#include <linux/errno.h>
62
#include "sm.h"
63
 
64
/* --------------------------------------------------------------------- */
65
 
66
/*
67
 * currently this module is supposed to support both module styles, i.e.
68
 * the old one present up to about 2.1.9, and the new one functioning
69
 * starting with 2.1.21. The reason is I have a kit allowing to compile
70
 * this module also under 2.0.x which was requested by several people.
71
 * This will go in 2.2
72
 */
73
#include <linux/version.h>
74
 
75
#if LINUX_VERSION_CODE >= 0x20100
76
#include <asm/uaccess.h>
77
#else
78
#include <asm/segment.h>
79
#include <linux/mm.h>
80
 
81
#undef put_user
82
#undef get_user
83
 
84
#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
85
#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
86
 
87
extern inline int copy_from_user(void *to, const void *from, unsigned long n)
88
{
89
        int i = verify_area(VERIFY_READ, from, n);
90
        if (i)
91
                return i;
92
        memcpy_fromfs(to, from, n);
93
        return 0;
94
}
95
 
96
extern inline int copy_to_user(void *to, const void *from, unsigned long n)
97
{
98
        int i = verify_area(VERIFY_WRITE, to, n);
99
        if (i)
100
                return i;
101
        memcpy_tofs(to, from, n);
102
        return 0;
103
}
104
#endif
105
 
106
#if LINUX_VERSION_CODE >= 0x20123
107
#include <linux/init.h>
108
#else
109
#define __init
110
#define __initdata
111
#define __initfunc(x) x
112
#endif
113
 
114
/* --------------------------------------------------------------------- */
115
 
116
/*static*/ const char sm_drvname[] = "soundmodem";
117
static const char sm_drvinfo[] = KERN_INFO "soundmodem: (C) 1996-1998 Thomas Sailer, HB9JNX/AE4WA\n"
118
KERN_INFO "soundmodem: version 0.8 compiled " __TIME__ " " __DATE__ "\n";
119
 
120
/* --------------------------------------------------------------------- */
121
 
122
/*static*/ const struct modem_tx_info *sm_modem_tx_table[] = {
123
#ifdef CONFIG_SOUNDMODEM_AFSK1200
124
        &sm_afsk1200_tx,
125
#endif /* CONFIG_SOUNDMODEM_AFSK1200 */
126
#ifdef CONFIG_SOUNDMODEM_AFSK2400_7
127
        &sm_afsk2400_7_tx,
128
#endif /* CONFIG_SOUNDMODEM_AFSK2400_7 */
129
#ifdef CONFIG_SOUNDMODEM_AFSK2400_8
130
        &sm_afsk2400_8_tx,
131
#endif /* CONFIG_SOUNDMODEM_AFSK2400_8 */
132
#ifdef CONFIG_SOUNDMODEM_AFSK2666
133
        &sm_afsk2666_tx,
134
#endif /* CONFIG_SOUNDMODEM_AFSK2666 */
135
#ifdef CONFIG_SOUNDMODEM_PSK4800
136
        &sm_psk4800_tx,
137
#endif /* CONFIG_SOUNDMODEM_PSK4800 */
138
#ifdef CONFIG_SOUNDMODEM_HAPN4800
139
        &sm_hapn4800_8_tx,
140
        &sm_hapn4800_10_tx,
141
        &sm_hapn4800_pm8_tx,
142
        &sm_hapn4800_pm10_tx,
143
#endif /* CONFIG_SOUNDMODEM_HAPN4800 */
144
#ifdef CONFIG_SOUNDMODEM_FSK9600
145
        &sm_fsk9600_4_tx,
146
        &sm_fsk9600_5_tx,
147
#endif /* CONFIG_SOUNDMODEM_FSK9600 */
148
        NULL
149
};
150
 
151
/*static*/ const struct modem_rx_info *sm_modem_rx_table[] = {
152
#ifdef CONFIG_SOUNDMODEM_AFSK1200
153
        &sm_afsk1200_rx,
154
#endif /* CONFIG_SOUNDMODEM_AFSK1200 */
155
#ifdef CONFIG_SOUNDMODEM_AFSK2400_7
156
        &sm_afsk2400_7_rx,
157
#endif /* CONFIG_SOUNDMODEM_AFSK2400_7 */
158
#ifdef CONFIG_SOUNDMODEM_AFSK2400_8
159
        &sm_afsk2400_8_rx,
160
#endif /* CONFIG_SOUNDMODEM_AFSK2400_8 */
161
#ifdef CONFIG_SOUNDMODEM_AFSK2666
162
        &sm_afsk2666_rx,
163
#endif /* CONFIG_SOUNDMODEM_AFSK2666 */
164
#ifdef CONFIG_SOUNDMODEM_PSK4800
165
        &sm_psk4800_rx,
166
#endif /* CONFIG_SOUNDMODEM_PSK4800 */
167
#ifdef CONFIG_SOUNDMODEM_HAPN4800
168
        &sm_hapn4800_8_rx,
169
        &sm_hapn4800_10_rx,
170
        &sm_hapn4800_pm8_rx,
171
        &sm_hapn4800_pm10_rx,
172
#endif /* CONFIG_SOUNDMODEM_HAPN4800 */
173
#ifdef CONFIG_SOUNDMODEM_FSK9600
174
        &sm_fsk9600_4_rx,
175
        &sm_fsk9600_5_rx,
176
#endif /* CONFIG_SOUNDMODEM_FSK9600 */
177
        NULL
178
};
179
 
180
static const struct hardware_info *sm_hardware_table[] = {
181
#ifdef CONFIG_SOUNDMODEM_SBC
182
        &sm_hw_sbc,
183
        &sm_hw_sbcfdx,
184
#endif /* CONFIG_SOUNDMODEM_SBC */
185
#ifdef CONFIG_SOUNDMODEM_WSS
186
        &sm_hw_wss,
187
        &sm_hw_wssfdx,
188
#endif /* CONFIG_SOUNDMODEM_WSS */
189
        NULL
190
};
191
 
192
/* --------------------------------------------------------------------- */
193
 
194
#define NR_PORTS 4
195
 
196
/* --------------------------------------------------------------------- */
197
 
198
static struct device sm_device[NR_PORTS];
199
 
200
static struct {
201
        char *mode;
202
        int iobase, irq, dma, dma2, seriobase, pariobase, midiiobase;
203
} sm_ports[NR_PORTS] = {
204
        { NULL, -1, 0, 0, 0, -1, -1, -1 },
205
};
206
 
207
/* --------------------------------------------------------------------- */
208
 
209
#define UART_RBR(iobase) (iobase+0)
210
#define UART_THR(iobase) (iobase+0)
211
#define UART_IER(iobase) (iobase+1)
212
#define UART_IIR(iobase) (iobase+2)
213
#define UART_FCR(iobase) (iobase+2)
214
#define UART_LCR(iobase) (iobase+3)
215
#define UART_MCR(iobase) (iobase+4)
216
#define UART_LSR(iobase) (iobase+5)
217
#define UART_MSR(iobase) (iobase+6)
218
#define UART_SCR(iobase) (iobase+7)
219
#define UART_DLL(iobase) (iobase+0)
220
#define UART_DLM(iobase) (iobase+1)
221
 
222
#define SER_EXTENT 8
223
 
224
#define LPT_DATA(iobase)    (iobase+0)
225
#define LPT_STATUS(iobase)  (iobase+1)
226
#define LPT_CONTROL(iobase) (iobase+2)
227
#define LPT_IRQ_ENABLE      0x10
228
 
229
#define LPT_EXTENT 3
230
 
231
#define MIDI_DATA(iobase)     (iobase)
232
#define MIDI_STATUS(iobase)   (iobase+1)
233
#define MIDI_READ_FULL 0x80   /* attention: negative logic!! */
234
#define MIDI_WRITE_EMPTY 0x40 /* attention: negative logic!! */
235
 
236
#define MIDI_EXTENT 2
237
 
238
/* ---------------------------------------------------------------------- */
239
 
240
#define PARAM_TXDELAY   1
241
#define PARAM_PERSIST   2
242
#define PARAM_SLOTTIME  3
243
#define PARAM_TXTAIL    4
244
#define PARAM_FULLDUP   5
245
#define PARAM_HARDWARE  6
246
#define PARAM_RETURN    255
247
 
248
#define SP_SER  1
249
#define SP_PAR  2
250
#define SP_MIDI 4
251
 
252
/* --------------------------------------------------------------------- */
253
/*
254
 * ===================== port checking routines ========================
255
 */
256
 
257
/*
258
 * returns 0 if ok and != 0 on error;
259
 * the same behaviour as par96_check_lpt in baycom.c
260
 */
261
 
262
/*
263
 * returns 0 if ok and != 0 on error;
264
 * the same behaviour as par96_check_lpt in baycom.c
265
 */
266
 
267
static int check_lpt(unsigned int iobase)
268
{
269
        unsigned char b1,b2;
270
        int i;
271
 
272
        if (iobase <= 0 || iobase > 0x1000-LPT_EXTENT)
273
                return 0;
274
        if (check_region(iobase, LPT_EXTENT))
275
                return 0;
276
        b1 = inb(LPT_DATA(iobase));
277
        b2 = inb(LPT_CONTROL(iobase));
278
        outb(0xaa, LPT_DATA(iobase));
279
        i = inb(LPT_DATA(iobase)) == 0xaa;
280
        outb(0x55, LPT_DATA(iobase));
281
        i &= inb(LPT_DATA(iobase)) == 0x55;
282
        outb(0x0a, LPT_CONTROL(iobase));
283
        i &= (inb(LPT_CONTROL(iobase)) & 0xf) == 0x0a;
284
        outb(0x05, LPT_CONTROL(iobase));
285
        i &= (inb(LPT_CONTROL(iobase)) & 0xf) == 0x05;
286
        outb(b1, LPT_DATA(iobase));
287
        outb(b2, LPT_CONTROL(iobase));
288
        return !i;
289
}
290
 
291
/* --------------------------------------------------------------------- */
292
 
293
enum uart { c_uart_unknown, c_uart_8250,
294
        c_uart_16450, c_uart_16550, c_uart_16550A};
295
static const char *uart_str[] =
296
        { "unknown", "8250", "16450", "16550", "16550A" };
297
 
298
static enum uart check_uart(unsigned int iobase)
299
{
300
        unsigned char b1,b2,b3;
301
        enum uart u;
302
        enum uart uart_tab[] =
303
                { c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A };
304
 
305
        if (iobase <= 0 || iobase > 0x1000-SER_EXTENT)
306
                return c_uart_unknown;
307
        if (check_region(iobase, SER_EXTENT))
308
                return c_uart_unknown;
309
        b1 = inb(UART_MCR(iobase));
310
        outb(b1 | 0x10, UART_MCR(iobase));      /* loopback mode */
311
        b2 = inb(UART_MSR(iobase));
312
        outb(0x1a, UART_MCR(iobase));
313
        b3 = inb(UART_MSR(iobase)) & 0xf0;
314
        outb(b1, UART_MCR(iobase));        /* restore old values */
315
        outb(b2, UART_MSR(iobase));
316
        if (b3 != 0x90)
317
                return c_uart_unknown;
318
        inb(UART_RBR(iobase));
319
        inb(UART_RBR(iobase));
320
        outb(0x01, UART_FCR(iobase));           /* enable FIFOs */
321
        u = uart_tab[(inb(UART_IIR(iobase)) >> 6) & 3];
322
        if (u == c_uart_16450) {
323
                outb(0x5a, UART_SCR(iobase));
324
                b1 = inb(UART_SCR(iobase));
325
                outb(0xa5, UART_SCR(iobase));
326
                b2 = inb(UART_SCR(iobase));
327
                if ((b1 != 0x5a) || (b2 != 0xa5))
328
                        u = c_uart_8250;
329
        }
330
        return u;
331
}
332
 
333
/* --------------------------------------------------------------------- */
334
 
335
static int check_midi(unsigned int iobase)
336
{
337
        unsigned long timeout;
338
        unsigned long flags;
339
        unsigned char b;
340
 
341
        if (iobase <= 0 || iobase > 0x1000-MIDI_EXTENT)
342
                return 0;
343
        if (check_region(iobase, MIDI_EXTENT))
344
                return 0;
345
        timeout = jiffies + (HZ / 100);
346
        while (inb(MIDI_STATUS(iobase)) & MIDI_WRITE_EMPTY)
347
                if ((signed)(jiffies - timeout) > 0)
348
                        return 0;
349
        save_flags(flags);
350
        cli();
351
        outb(0xff, MIDI_DATA(iobase));
352
        b = inb(MIDI_STATUS(iobase));
353
        restore_flags(flags);
354
        if (!(b & MIDI_WRITE_EMPTY))
355
                return 0;
356
        while (inb(MIDI_STATUS(iobase)) & MIDI_WRITE_EMPTY)
357
                if ((signed)(jiffies - timeout) > 0)
358
                        return 0;
359
        return 1;
360
}
361
 
362
/* --------------------------------------------------------------------- */
363
 
364
void sm_output_status(struct sm_state *sm)
365
{
366
        int invert_dcd = 0;
367
        int invert_ptt = 0;
368
 
369
        int ptt = /*hdlcdrv_ptt(&sm->hdrv)*/(sm->dma.ptt_cnt > 0) ^ invert_ptt;
370
        int dcd = (!!sm->hdrv.hdlcrx.dcd) ^ invert_dcd;
371
 
372
        if (sm->hdrv.ptt_out.flags & SP_SER) {
373
                outb(dcd | (ptt << 1), UART_MCR(sm->hdrv.ptt_out.seriobase));
374
                outb(0x40 & (-ptt), UART_LCR(sm->hdrv.ptt_out.seriobase));
375
        }
376
        if (sm->hdrv.ptt_out.flags & SP_PAR) {
377
                outb(ptt | (dcd << 1), LPT_DATA(sm->hdrv.ptt_out.pariobase));
378
        }
379
        if (sm->hdrv.ptt_out.flags & SP_MIDI && hdlcdrv_ptt(&sm->hdrv)) {
380
                outb(0, MIDI_DATA(sm->hdrv.ptt_out.midiiobase));
381
        }
382
}
383
 
384
/* --------------------------------------------------------------------- */
385
 
386
static void sm_output_open(struct sm_state *sm)
387
{
388
        enum uart u = c_uart_unknown;
389
 
390
        sm->hdrv.ptt_out.flags = 0;
391
        if (sm->hdrv.ptt_out.seriobase > 0 &&
392
            sm->hdrv.ptt_out.seriobase <= 0x1000-SER_EXTENT &&
393
            ((u = check_uart(sm->hdrv.ptt_out.seriobase))) != c_uart_unknown) {
394
                sm->hdrv.ptt_out.flags |= SP_SER;
395
                request_region(sm->hdrv.ptt_out.seriobase, SER_EXTENT, "sm ser ptt");
396
                outb(0, UART_IER(sm->hdrv.ptt_out.seriobase));
397
                /* 5 bits, 1 stop, no parity, no break, Div latch access */
398
                outb(0x80, UART_LCR(sm->hdrv.ptt_out.seriobase));
399
                outb(0, UART_DLM(sm->hdrv.ptt_out.seriobase));
400
                outb(1, UART_DLL(sm->hdrv.ptt_out.seriobase)); /* as fast as possible */
401
                /* LCR and MCR set by output_status */
402
        }
403
        if (sm->hdrv.ptt_out.pariobase > 0 &&
404
            sm->hdrv.ptt_out.pariobase <= 0x1000-LPT_EXTENT &&
405
            !check_lpt(sm->hdrv.ptt_out.pariobase)) {
406
                sm->hdrv.ptt_out.flags |= SP_PAR;
407
                request_region(sm->hdrv.ptt_out.pariobase, LPT_EXTENT, "sm par ptt");
408
        }
409
        if (sm->hdrv.ptt_out.midiiobase > 0 &&
410
            sm->hdrv.ptt_out.midiiobase <= 0x1000-MIDI_EXTENT &&
411
            check_midi(sm->hdrv.ptt_out.midiiobase)) {
412
                sm->hdrv.ptt_out.flags |= SP_MIDI;
413
                request_region(sm->hdrv.ptt_out.midiiobase, MIDI_EXTENT,
414
                               "sm midi ptt");
415
        }
416
        sm_output_status(sm);
417
 
418
        printk(KERN_INFO "%s: ptt output:", sm_drvname);
419
        if (sm->hdrv.ptt_out.flags & SP_SER)
420
                printk(" serial interface at 0x%x, uart %s", sm->hdrv.ptt_out.seriobase,
421
                       uart_str[u]);
422
        if (sm->hdrv.ptt_out.flags & SP_PAR)
423
                printk(" parallel interface at 0x%x", sm->hdrv.ptt_out.pariobase);
424
        if (sm->hdrv.ptt_out.flags & SP_MIDI)
425
                printk(" mpu401 (midi) interface at 0x%x", sm->hdrv.ptt_out.midiiobase);
426
        if (!sm->hdrv.ptt_out.flags)
427
                printk(" none");
428
        printk("\n");
429
}
430
 
431
/* --------------------------------------------------------------------- */
432
 
433
static void sm_output_close(struct sm_state *sm)
434
{
435
        /* release regions used for PTT output */
436
        sm->hdrv.hdlctx.ptt = sm->hdrv.hdlctx.calibrate = 0;
437
        sm_output_status(sm);
438
        if (sm->hdrv.ptt_out.flags & SP_SER)
439
                release_region(sm->hdrv.ptt_out.seriobase, SER_EXTENT);
440
        if (sm->hdrv.ptt_out.flags & SP_PAR)
441
                release_region(sm->hdrv.ptt_out.pariobase, LPT_EXTENT);
442
        if (sm->hdrv.ptt_out.flags & SP_MIDI)
443
                release_region(sm->hdrv.ptt_out.midiiobase, MIDI_EXTENT);
444
        sm->hdrv.ptt_out.flags = 0;
445
}
446
 
447
/* --------------------------------------------------------------------- */
448
 
449
static int sm_open(struct device *dev);
450
static int sm_close(struct device *dev);
451
static int sm_ioctl(struct device *dev, struct ifreq *ifr,
452
                    struct hdlcdrv_ioctl *hi, int cmd);
453
 
454
/* --------------------------------------------------------------------- */
455
 
456
static const struct hdlcdrv_ops sm_ops = {
457
        sm_drvname, sm_drvinfo, sm_open, sm_close, sm_ioctl
458
};
459
 
460
/* --------------------------------------------------------------------- */
461
 
462
static int sm_open(struct device *dev)
463
{
464
        struct sm_state *sm;
465
        int err;
466
 
467
        if (!dev || !dev->priv ||
468
            ((struct sm_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) {
469
                printk(KERN_ERR "sm_open: invalid device struct\n");
470
                return -EINVAL;
471
        }
472
        sm = (struct sm_state *)dev->priv;
473
 
474
        if (!sm->mode_tx || !sm->mode_rx || !sm->hwdrv || !sm->hwdrv->open)
475
                return -ENODEV;
476
        sm->hdrv.par.bitrate = sm->mode_rx->bitrate;
477
        err = sm->hwdrv->open(dev, sm);
478
        if (err)
479
                return err;
480
        sm_output_open(sm);
481
        MOD_INC_USE_COUNT;
482
        printk(KERN_INFO "%s: %s mode %s.%s at iobase 0x%lx irq %u dma %u dma2 %u\n",
483
               sm_drvname, sm->hwdrv->hw_name, sm->mode_tx->name,
484
               sm->mode_rx->name, dev->base_addr, dev->irq, dev->dma, sm->hdrv.ptt_out.dma2);
485
        return 0;
486
}
487
 
488
/* --------------------------------------------------------------------- */
489
 
490
static int sm_close(struct device *dev)
491
{
492
        struct sm_state *sm;
493
        int err = -ENODEV;
494
 
495
        if (!dev || !dev->priv ||
496
            ((struct sm_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) {
497
                printk(KERN_ERR "sm_close: invalid device struct\n");
498
                return -EINVAL;
499
        }
500
        sm = (struct sm_state *)dev->priv;
501
 
502
 
503
        if (sm->hwdrv && sm->hwdrv->close)
504
                err = sm->hwdrv && sm->hwdrv->close(dev, sm);
505
        sm_output_close(sm);
506
        MOD_DEC_USE_COUNT;
507
        printk(KERN_INFO "%s: close %s at iobase 0x%lx irq %u dma %u\n",
508
               sm_drvname, sm->hwdrv->hw_name, dev->base_addr, dev->irq, dev->dma);
509
        return err;
510
}
511
 
512
/* --------------------------------------------------------------------- */
513
 
514
static int sethw(struct device *dev, struct sm_state *sm, char *mode)
515
{
516
        char *cp = strchr(mode, ':');
517
        const struct hardware_info **hwp = sm_hardware_table;
518
 
519
        if (!cp)
520
                cp = mode;
521
        else {
522
                *cp++ = '\0';
523
                while (hwp && (*hwp) && (*hwp)->hw_name && strcmp((*hwp)->hw_name, mode))
524
                        hwp++;
525
                if (!hwp || !*hwp || !(*hwp)->hw_name)
526
                        return -EINVAL;
527
                if ((*hwp)->loc_storage > sizeof(sm->hw)) {
528
                        printk(KERN_ERR "%s: insufficient storage for hw driver %s (%d)\n",
529
                               sm_drvname, (*hwp)->hw_name, (*hwp)->loc_storage);
530
                        return -EINVAL;
531
                }
532
                sm->hwdrv = *hwp;
533
        }
534
        if (!*cp)
535
                return 0;
536
        if (sm->hwdrv && sm->hwdrv->sethw)
537
                return sm->hwdrv->sethw(dev, sm, cp);
538
        return -EINVAL;
539
}
540
 
541
/* --------------------------------------------------------------------- */
542
 
543
static int sm_ioctl(struct device *dev, struct ifreq *ifr,
544
                    struct hdlcdrv_ioctl *hi, int cmd)
545
{
546
        struct sm_state *sm;
547
        struct sm_ioctl bi;
548
        unsigned long flags;
549
        unsigned int newdiagmode;
550
        unsigned int newdiagflags;
551
        char *cp;
552
        const struct modem_tx_info **mtp = sm_modem_tx_table;
553
        const struct modem_rx_info **mrp = sm_modem_rx_table;
554
        const struct hardware_info **hwp = sm_hardware_table;
555
 
556
        if (!dev || !dev->priv ||
557
            ((struct sm_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) {
558
                printk(KERN_ERR "sm_ioctl: invalid device struct\n");
559
                return -EINVAL;
560
        }
561
        sm = (struct sm_state *)dev->priv;
562
 
563
        if (cmd != SIOCDEVPRIVATE) {
564
                if (!sm->hwdrv || !sm->hwdrv->ioctl)
565
                        return sm->hwdrv->ioctl(dev, sm, ifr, hi, cmd);
566
                return -ENOIOCTLCMD;
567
        }
568
        switch (hi->cmd) {
569
        default:
570
                if (sm->hwdrv && sm->hwdrv->ioctl)
571
                        return sm->hwdrv->ioctl(dev, sm, ifr, hi, cmd);
572
                return -ENOIOCTLCMD;
573
 
574
        case HDLCDRVCTL_GETMODE:
575
                cp = hi->data.modename;
576
                if (sm->hwdrv && sm->hwdrv->hw_name)
577
                        cp += sprintf(cp, "%s:", sm->hwdrv->hw_name);
578
                else
579
                        cp += sprintf(cp, "<unspec>:");
580
                if (sm->mode_tx && sm->mode_tx->name)
581
                        cp += sprintf(cp, "%s", sm->mode_tx->name);
582
                else
583
                        cp += sprintf(cp, "<unspec>");
584
                if (!sm->mode_rx || !sm->mode_rx ||
585
                    strcmp(sm->mode_rx->name, sm->mode_tx->name)) {
586
                        if (sm->mode_rx && sm->mode_rx->name)
587
                                cp += sprintf(cp, ",%s", sm->mode_rx->name);
588
                        else
589
                                cp += sprintf(cp, ",<unspec>");
590
                }
591
                if (copy_to_user(ifr->ifr_data, hi, sizeof(*hi)))
592
                        return -EFAULT;
593
                return 0;
594
 
595
        case HDLCDRVCTL_SETMODE:
596
                if (dev->start || !suser())
597
                        return -EACCES;
598
                hi->data.modename[sizeof(hi->data.modename)-1] = '\0';
599
                return sethw(dev, sm, hi->data.modename);
600
 
601
        case HDLCDRVCTL_MODELIST:
602
                cp = hi->data.modename;
603
                while (*hwp) {
604
                        if ((*hwp)->hw_name)
605
                                cp += sprintf("%s:,", (*hwp)->hw_name);
606
                        hwp++;
607
                }
608
                while (*mtp) {
609
                        if ((*mtp)->name)
610
                                cp += sprintf(">%s,", (*mtp)->name);
611
                        mtp++;
612
                }
613
                while (*mrp) {
614
                        if ((*mrp)->name)
615
                                cp += sprintf("<%s,", (*mrp)->name);
616
                        mrp++;
617
                }
618
                cp[-1] = '\0';
619
                if (copy_to_user(ifr->ifr_data, hi, sizeof(*hi)))
620
                        return -EFAULT;
621
                return 0;
622
 
623
#ifdef SM_DEBUG
624
        case SMCTL_GETDEBUG:
625
                if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi)))
626
                        return -EFAULT;
627
                bi.data.dbg.int_rate = sm->debug_vals.last_intcnt;
628
                bi.data.dbg.mod_cycles = sm->debug_vals.mod_cyc;
629
                bi.data.dbg.demod_cycles = sm->debug_vals.demod_cyc;
630
                bi.data.dbg.dma_residue = sm->debug_vals.dma_residue;
631
                sm->debug_vals.mod_cyc = sm->debug_vals.demod_cyc =
632
                        sm->debug_vals.dma_residue = 0;
633
                if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi)))
634
                        return -EFAULT;
635
                return 0;
636
#endif /* SM_DEBUG */
637
 
638
        case SMCTL_DIAGNOSE:
639
                if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi)))
640
                        return -EFAULT;
641
                newdiagmode = bi.data.diag.mode;
642
                newdiagflags = bi.data.diag.flags;
643
                if (newdiagmode > SM_DIAGMODE_CONSTELLATION)
644
                        return -EINVAL;
645
                bi.data.diag.mode = sm->diag.mode;
646
                bi.data.diag.flags = sm->diag.flags;
647
                bi.data.diag.samplesperbit = sm->mode_rx->sperbit;
648
                if (sm->diag.mode != newdiagmode) {
649
                        save_flags(flags);
650
                        cli();
651
                        sm->diag.ptr = -1;
652
                        sm->diag.flags = newdiagflags & ~SM_DIAGFLAG_VALID;
653
                        sm->diag.mode = newdiagmode;
654
                        restore_flags(flags);
655
                        if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi)))
656
                                return -EFAULT;
657
                        return 0;
658
                }
659
                if (sm->diag.ptr < 0 || sm->diag.mode == SM_DIAGMODE_OFF) {
660
                        if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi)))
661
                                return -EFAULT;
662
                        return 0;
663
                }
664
                if (bi.data.diag.datalen > DIAGDATALEN)
665
                        bi.data.diag.datalen = DIAGDATALEN;
666
                if (sm->diag.ptr < bi.data.diag.datalen) {
667
                        if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi)))
668
                                return -EFAULT;
669
                        return 0;
670
                }
671
                if (copy_to_user(bi.data.diag.data, sm->diag.data,
672
                                 bi.data.diag.datalen * sizeof(short)))
673
                        return -EFAULT;
674
                bi.data.diag.flags |= SM_DIAGFLAG_VALID;
675
                save_flags(flags);
676
                cli();
677
                sm->diag.ptr = -1;
678
                sm->diag.flags = newdiagflags & ~SM_DIAGFLAG_VALID;
679
                sm->diag.mode = newdiagmode;
680
                restore_flags(flags);
681
                if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi)))
682
                        return -EFAULT;
683
                return 0;
684
        }
685
}
686
 
687
/* --------------------------------------------------------------------- */
688
 
689
#ifdef __i386__
690
 
691
int sm_x86_capability = 0;
692
 
693
__initfunc(static void i386_capability(void))
694
{
695
       unsigned long flags;
696
       unsigned long fl1;
697
       union {
698
               struct {
699
                       unsigned int ebx, edx, ecx;
700
               } r;
701
               unsigned char s[13];
702
       } id;
703
       unsigned int eax;
704
 
705
       save_flags(flags);
706
       flags |= 0x200000;
707
       restore_flags(flags);
708
       save_flags(flags);
709
       fl1 = flags;
710
       flags &= ~0x200000;
711
       restore_flags(flags);
712
       save_flags(flags);
713
       if (!(fl1 & 0x200000) || (flags & 0x200000)) {
714
               printk(KERN_WARNING "%s: cpu does not support CPUID\n", sm_drvname);
715
               return;
716
       }
717
       __asm__ ("cpuid" : "=a" (eax), "=b" (id.r.ebx), "=c" (id.r.ecx), "=d" (id.r.edx) :
718
                "0" (0));
719
       id.s[12] = 0;
720
       if (eax < 1) {
721
               printk(KERN_WARNING "%s: cpu (vendor string %s) does not support capability "
722
                      "list\n", sm_drvname, id.s);
723
               return;
724
       }
725
       printk(KERN_INFO "%s: cpu: vendor string %s ", sm_drvname, id.s);
726
       __asm__ ("cpuid" : "=a" (eax), "=d" (sm_x86_capability) : "0" (1) : "ebx", "ecx");
727
       printk("fam %d mdl %d step %d cap 0x%x\n", (eax >> 8) & 15, (eax >> 4) & 15,
728
              eax & 15, sm_x86_capability);
729
}
730
#endif /* __i386__ */  
731
 
732
/* --------------------------------------------------------------------- */
733
 
734
#ifdef MODULE
735
__initfunc(static int sm_init(void))
736
#else /* MODULE */
737
__initfunc(int sm_init(void))
738
#endif /* MODULE */
739
{
740
        int i, j, found = 0;
741
        char set_hw = 1;
742
        struct sm_state *sm;
743
        char ifname[HDLCDRV_IFNAMELEN];
744
 
745
        printk(sm_drvinfo);
746
#ifdef __i386__
747
       i386_capability();
748
#endif /* __i386__ */  
749
        /*
750
         * register net devices
751
         */
752
        for (i = 0; i < NR_PORTS; i++) {
753
                struct device *dev = sm_device+i;
754
                sprintf(ifname, "sm%d", i);
755
 
756
                if (!sm_ports[i].mode)
757
                        set_hw = 0;
758
                if (!set_hw)
759
                        sm_ports[i].iobase = sm_ports[i].irq = 0;
760
                j = hdlcdrv_register_hdlcdrv(dev, &sm_ops, sizeof(struct sm_state),
761
                                             ifname, sm_ports[i].iobase,
762
                                             sm_ports[i].irq, sm_ports[i].dma);
763
                if (!j) {
764
                        sm = (struct sm_state *)dev->priv;
765
                        sm->hdrv.ptt_out.dma2 = sm_ports[i].dma2;
766
                        sm->hdrv.ptt_out.seriobase = sm_ports[i].seriobase;
767
                        sm->hdrv.ptt_out.pariobase = sm_ports[i].pariobase;
768
                        sm->hdrv.ptt_out.midiiobase = sm_ports[i].midiiobase;
769
                        if (set_hw && sethw(dev, sm, sm_ports[i].mode))
770
                                set_hw = 0;
771
                        found++;
772
                } else {
773
                        printk(KERN_WARNING "%s: cannot register net device\n",
774
                               sm_drvname);
775
                }
776
        }
777
        if (!found)
778
                return -ENXIO;
779
        return 0;
780
}
781
 
782
/* --------------------------------------------------------------------- */
783
 
784
#ifdef MODULE
785
 
786
/*
787
 * command line settable parameters
788
 */
789
static char *mode = NULL;
790
static int iobase = -1;
791
static int irq = -1;
792
static int dma = -1;
793
static int dma2 = -1;
794
static int serio = 0;
795
static int pario = 0;
796
static int midiio = 0;
797
 
798
#if LINUX_VERSION_CODE >= 0x20115
799
 
800
MODULE_PARM(mode, "s");
801
MODULE_PARM_DESC(mode, "soundmodem operating mode; eg. sbc:afsk1200 or wss:fsk9600");
802
MODULE_PARM(iobase, "i");
803
MODULE_PARM_DESC(iobase, "soundmodem base address");
804
MODULE_PARM(irq, "i");
805
MODULE_PARM_DESC(irq, "soundmodem interrupt");
806
MODULE_PARM(dma, "i");
807
MODULE_PARM_DESC(dma, "soundmodem dma channel");
808
MODULE_PARM(dma2, "i");
809
MODULE_PARM_DESC(dma2, "soundmodem 2nd dma channel; full duplex only");
810
MODULE_PARM(serio, "i");
811
MODULE_PARM_DESC(serio, "soundmodem PTT output on serial port");
812
MODULE_PARM(pario, "i");
813
MODULE_PARM_DESC(pario, "soundmodem PTT output on parallel port");
814
MODULE_PARM(midiio, "i");
815
MODULE_PARM_DESC(midiio, "soundmodem PTT output on midi port");
816
 
817
MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
818
MODULE_DESCRIPTION("Soundcard amateur radio modem driver");
819
 
820
#endif
821
 
822
__initfunc(int init_module(void))
823
{
824
        if (mode) {
825
                if (iobase == -1)
826
                        iobase = (!strncmp(mode, "sbc", 3)) ? 0x220 : 0x530;
827
                if (irq == -1)
828
                        irq = (!strncmp(mode, "sbc", 3)) ? 5 : 11;
829
                if (dma == -1)
830
                        dma = 1;
831
        }
832
        sm_ports[0].mode = mode;
833
        sm_ports[0].iobase = iobase;
834
        sm_ports[0].irq = irq;
835
        sm_ports[0].dma = dma;
836
        sm_ports[0].dma2 = dma2;
837
        sm_ports[0].seriobase = serio;
838
        sm_ports[0].pariobase = pario;
839
        sm_ports[0].midiiobase = midiio;
840
        sm_ports[1].mode = NULL;
841
 
842
        return sm_init();
843
}
844
 
845
/* --------------------------------------------------------------------- */
846
 
847
void cleanup_module(void)
848
{
849
        int i;
850
 
851
        printk(KERN_INFO "sm: cleanup_module called\n");
852
 
853
        for(i = 0; i < NR_PORTS; i++) {
854
                struct device *dev = sm_device+i;
855
                struct sm_state *sm = (struct sm_state *)dev->priv;
856
 
857
                if (sm) {
858
                        if (sm->hdrv.magic != HDLCDRV_MAGIC)
859
                                printk(KERN_ERR "sm: invalid magic in "
860
                                       "cleanup_module\n");
861
                        else
862
                                hdlcdrv_unregister_hdlcdrv(dev);
863
                }
864
        }
865
}
866
 
867
#else /* MODULE */
868
/* --------------------------------------------------------------------- */
869
/*
870
 * format: sm=io,irq,dma[,dma2[,serio[,pario]]],mode
871
 * mode: hw:modem
872
 * hw: sbc, wss, wssfdx
873
 * modem: afsk1200, fsk9600
874
 */
875
 
876
__initfunc(void sm_setup(char *str, int *ints))
877
{
878
        int i;
879
 
880
        for (i = 0; (i < NR_PORTS) && (sm_ports[i].mode); i++);
881
        if ((i >= NR_PORTS) || (ints[0] < 3)) {
882
                printk(KERN_INFO "%s: too many or invalid interface "
883
                       "specifications\n", sm_drvname);
884
                return;
885
        }
886
        sm_ports[i].mode = str;
887
        sm_ports[i].iobase = ints[1];
888
        sm_ports[i].irq = ints[2];
889
        sm_ports[i].dma = ints[3];
890
        sm_ports[i].dma2 = (ints[0] >= 4) ? ints[4] : 0;
891
        sm_ports[i].seriobase = (ints[0] >= 5) ? ints[5] : 0;
892
        sm_ports[i].pariobase = (ints[0] >= 6) ? ints[6] : 0;
893
        sm_ports[i].midiiobase = (ints[0] >= 7) ? ints[7] : 0;
894
        if (i < NR_PORTS-1)
895
                sm_ports[i+1].mode = NULL;
896
}
897
 
898
#endif /* MODULE */
899
/* --------------------------------------------------------------------- */

powered by: WebSVN 2.1.0

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