Showing error 1705

User: Jiri Slaby
Error type: Double Unlock
Error type description: Some lock is unlocked twice unintentionally in a sequence
File location: drivers/net/hamradio/baycom_ser_hdx.c
Line in file: 422
Project: Linux Kernel
Project version: 2.6.28
Tools: Smatch (1.59)
Entered: 2013-09-10 15:16:58 UTC


Source:

  1/*****************************************************************************/
  2
  3/*
  4 *        baycom_ser_hdx.c  -- baycom ser12 halfduplex radio modem driver.
  5 *
  6 *        Copyright (C) 1996-2000  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, 16550A)
 36 *
 37 *
 38 *  Command line options (insmod command line)
 39 *
 40 *  mode     ser12    hardware DCD
 41 *           ser12*   software DCD
 42 *           ser12@   hardware/software DCD, i.e. no explicit DCD signal but hardware
 43 *                    mutes audio input to the modem
 44 *           ser12+   hardware DCD, inverted signal at DCD pin
 45 *  iobase   base address of the port; common values are 0x3f8, 0x2f8, 0x3e8, 0x2e8
 46 *  irq      interrupt line of the port; common values are 4,3
 47 *
 48 *
 49 *  History:
 50 *   0.1  26.06.1996  Adapted from baycom.c and made network driver interface
 51 *        18.10.1996  Changed to new user space access routines (copy_{to,from}_user)
 52 *   0.3  26.04.1997  init code/data tagged
 53 *   0.4  08.07.1997  alternative ser12 decoding algorithm (uses delta CTS ints)
 54 *   0.5  11.11.1997  ser12/par96 split into separate files
 55 *   0.6  14.04.1998  cleanups
 56 *   0.7  03.08.1999  adapt to Linus' new __setup/__initcall
 57 *   0.8  10.08.1999  use module_init/module_exit
 58 *   0.9  12.02.2000  adapted to softnet driver interface
 59 *   0.10 03.07.2000  fix interface name handling
 60 */
 61
 62/*****************************************************************************/
 63
 64#include <linux/module.h>
 65#include <linux/ioport.h>
 66#include <linux/string.h>
 67#include <linux/init.h>
 68#include <asm/uaccess.h>
 69#include <asm/io.h>
 70#include <linux/hdlcdrv.h>
 71#include <linux/baycom.h>
 72#include <linux/jiffies.h>
 73
 74/* --------------------------------------------------------------------- */
 75
 76#define BAYCOM_DEBUG
 77
 78/* --------------------------------------------------------------------- */
 79
 80static const char bc_drvname[] = "baycom_ser_hdx";
 81static const char bc_drvinfo[] = KERN_INFO "baycom_ser_hdx: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n"
 82KERN_INFO "baycom_ser_hdx: version 0.10 compiled " __TIME__ " " __DATE__ "\n";
 83
 84/* --------------------------------------------------------------------- */
 85
 86#define NR_PORTS 4
 87
 88static struct net_device *baycom_device[NR_PORTS];
 89
 90/* --------------------------------------------------------------------- */
 91
 92#define RBR(iobase) (iobase+0)
 93#define THR(iobase) (iobase+0)
 94#define IER(iobase) (iobase+1)
 95#define IIR(iobase) (iobase+2)
 96#define FCR(iobase) (iobase+2)
 97#define LCR(iobase) (iobase+3)
 98#define MCR(iobase) (iobase+4)
 99#define LSR(iobase) (iobase+5)
100#define MSR(iobase) (iobase+6)
101#define SCR(iobase) (iobase+7)
102#define DLL(iobase) (iobase+0)
103#define DLM(iobase) (iobase+1)
104
105#define SER12_EXTENT 8
106
107/* ---------------------------------------------------------------------- */
108/*
109 * Information that need to be kept for each board.
110 */
111
112struct baycom_state {
113        struct hdlcdrv_state hdrv;
114
115        int opt_dcd;
116
117        struct modem_state {
118                short arb_divider;
119                unsigned char flags;
120                unsigned int shreg;
121                struct modem_state_ser12 {
122                        unsigned char tx_bit;
123                        int dcd_sum0, dcd_sum1, dcd_sum2;
124                        unsigned char last_sample;
125                        unsigned char last_rxbit;
126                        unsigned int dcd_shreg;
127                        unsigned int dcd_time;
128                        unsigned int bit_pll;
129                        unsigned char interm_sample;
130                } ser12;
131        } modem;
132
133#ifdef BAYCOM_DEBUG
134        struct debug_vals {
135                unsigned long last_jiffies;
136                unsigned cur_intcnt;
137                unsigned last_intcnt;
138                int cur_pllcorr;
139                int last_pllcorr;
140        } debug_vals;
141#endif /* BAYCOM_DEBUG */
142};
143
144/* --------------------------------------------------------------------- */
145
146static inline void baycom_int_freq(struct baycom_state *bc)
147{
148#ifdef BAYCOM_DEBUG
149        unsigned long cur_jiffies = jiffies;
150        /*
151         * measure the interrupt frequency
152         */
153        bc->debug_vals.cur_intcnt++;
154        if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) {
155                bc->debug_vals.last_jiffies = cur_jiffies;
156                bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt;
157                bc->debug_vals.cur_intcnt = 0;
158                bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr;
159                bc->debug_vals.cur_pllcorr = 0;
160        }
161#endif /* BAYCOM_DEBUG */
162}
163
164/* --------------------------------------------------------------------- */
165/*
166 * ===================== SER12 specific routines =========================
167 */
168
169static inline void ser12_set_divisor(struct net_device *dev,
170                                     unsigned char divisor)
171{
172        outb(0x81, LCR(dev->base_addr));        /* DLAB = 1 */
173        outb(divisor, DLL(dev->base_addr));
174        outb(0, DLM(dev->base_addr));
175        outb(0x01, LCR(dev->base_addr));        /* word length = 6 */
176        /*
177         * make sure the next interrupt is generated;
178         * 0 must be used to power the modem; the modem draws its
179         * power from the TxD line
180         */
181        outb(0x00, THR(dev->base_addr));
182        /*
183         * it is important not to set the divider while transmitting;
184         * this reportedly makes some UARTs generating interrupts
185         * in the hundredthousands per second region
186         * Reported by: Ignacio.Arenaza@studi.epfl.ch (Ignacio Arenaza Nuno)
187         */
188}
189
190/* --------------------------------------------------------------------- */
191
192/*
193 * must call the TX arbitrator every 10ms
194 */
195#define SER12_ARB_DIVIDER(bc)  (bc->opt_dcd ? 24 : 36)
196                               
197#define SER12_DCD_INTERVAL(bc) (bc->opt_dcd ? 12 : 240)
198
199static inline void ser12_tx(struct net_device *dev, struct baycom_state *bc)
200{
201        /* one interrupt per channel bit */
202        ser12_set_divisor(dev, 12);
203        /*
204         * first output the last bit (!) then call HDLC transmitter,
205         * since this may take quite long
206         */
207        outb(0x0e | (!!bc->modem.ser12.tx_bit), MCR(dev->base_addr));
208        if (bc->modem.shreg <= 1)
209                bc->modem.shreg = 0x10000 | hdlcdrv_getbits(&bc->hdrv);
210        bc->modem.ser12.tx_bit = !(bc->modem.ser12.tx_bit ^
211                                   (bc->modem.shreg & 1));
212        bc->modem.shreg >>= 1;
213}
214
215/* --------------------------------------------------------------------- */
216
217static inline void ser12_rx(struct net_device *dev, struct baycom_state *bc)
218{
219        unsigned char cur_s;
220        /*
221         * do demodulator
222         */
223        cur_s = inb(MSR(dev->base_addr)) & 0x10;        /* the CTS line */
224        hdlcdrv_channelbit(&bc->hdrv, cur_s);
225        bc->modem.ser12.dcd_shreg = (bc->modem.ser12.dcd_shreg << 1) |
226                (cur_s != bc->modem.ser12.last_sample);
227        bc->modem.ser12.last_sample = cur_s;
228        if(bc->modem.ser12.dcd_shreg & 1) {
229                if (!bc->opt_dcd) {
230                        unsigned int dcdspos, dcdsneg;
231
232                        dcdspos = dcdsneg = 0;
233                        dcdspos += ((bc->modem.ser12.dcd_shreg >> 1) & 1);
234                        if (!(bc->modem.ser12.dcd_shreg & 0x7ffffffe))
235                                dcdspos += 2;
236                        dcdsneg += ((bc->modem.ser12.dcd_shreg >> 2) & 1);
237                        dcdsneg += ((bc->modem.ser12.dcd_shreg >> 3) & 1);
238                        dcdsneg += ((bc->modem.ser12.dcd_shreg >> 4) & 1);
239
240                        bc->modem.ser12.dcd_sum0 += 16*dcdspos - dcdsneg;
241                } else
242                        bc->modem.ser12.dcd_sum0--;
243        }
244        if(!bc->modem.ser12.dcd_time) {
245                hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 +
246                                           bc->modem.ser12.dcd_sum1 +
247                                           bc->modem.ser12.dcd_sum2) < 0);
248                bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1;
249                bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0;
250                /* offset to ensure DCD off on silent input */
251                bc->modem.ser12.dcd_sum0 = 2;
252                bc->modem.ser12.dcd_time = SER12_DCD_INTERVAL(bc);
253        }
254        bc->modem.ser12.dcd_time--;
255        if (!bc->opt_dcd) {
256                /*
257                 * PLL code for the improved software DCD algorithm
258                 */
259                if (bc->modem.ser12.interm_sample) {
260                        /*
261                         * intermediate sample; set timing correction to normal
262                         */
263                        ser12_set_divisor(dev, 4);
264                } else {
265                        /*
266                         * do PLL correction and call HDLC receiver
267                         */
268                        switch (bc->modem.ser12.dcd_shreg & 7) {
269                        case 1: /* transition too late */
270                                ser12_set_divisor(dev, 5);
271#ifdef BAYCOM_DEBUG
272                                bc->debug_vals.cur_pllcorr++;
273#endif /* BAYCOM_DEBUG */
274                                break;
275                        case 4:        /* transition too early */
276                                ser12_set_divisor(dev, 3);
277#ifdef BAYCOM_DEBUG
278                                bc->debug_vals.cur_pllcorr--;
279#endif /* BAYCOM_DEBUG */
280                                break;
281                        default:
282                                ser12_set_divisor(dev, 4);
283                                break;
284                        }
285                        bc->modem.shreg >>= 1;
286                        if (bc->modem.ser12.last_sample ==
287                            bc->modem.ser12.last_rxbit)
288                                bc->modem.shreg |= 0x10000;
289                        bc->modem.ser12.last_rxbit =
290                                bc->modem.ser12.last_sample;
291                }
292                if (++bc->modem.ser12.interm_sample >= 3)
293                        bc->modem.ser12.interm_sample = 0;
294                /*
295                 * DCD stuff
296                 */
297                if (bc->modem.ser12.dcd_shreg & 1) {
298                        unsigned int dcdspos, dcdsneg;
299
300                        dcdspos = dcdsneg = 0;
301                        dcdspos += ((bc->modem.ser12.dcd_shreg >> 1) & 1);
302                        dcdspos += (!(bc->modem.ser12.dcd_shreg & 0x7ffffffe))
303                                << 1;
304                        dcdsneg += ((bc->modem.ser12.dcd_shreg >> 2) & 1);
305                        dcdsneg += ((bc->modem.ser12.dcd_shreg >> 3) & 1);
306                        dcdsneg += ((bc->modem.ser12.dcd_shreg >> 4) & 1);
307
308                        bc->modem.ser12.dcd_sum0 += 16*dcdspos - dcdsneg;
309                }
310        } else {
311                /*
312                 * PLL algorithm for the hardware squelch DCD algorithm
313                 */
314                if (bc->modem.ser12.interm_sample) {
315                        /*
316                         * intermediate sample; set timing correction to normal
317                         */
318                        ser12_set_divisor(dev, 6);
319                } else {
320                        /*
321                         * do PLL correction and call HDLC receiver
322                         */
323                        switch (bc->modem.ser12.dcd_shreg & 3) {
324                        case 1: /* transition too late */
325                                ser12_set_divisor(dev, 7);
326#ifdef BAYCOM_DEBUG
327                                bc->debug_vals.cur_pllcorr++;
328#endif /* BAYCOM_DEBUG */
329                                break;
330                        case 2:        /* transition too early */
331                                ser12_set_divisor(dev, 5);
332#ifdef BAYCOM_DEBUG
333                                bc->debug_vals.cur_pllcorr--;
334#endif /* BAYCOM_DEBUG */
335                                break;
336                        default:
337                                ser12_set_divisor(dev, 6);
338                                break;
339                        }
340                        bc->modem.shreg >>= 1;
341                        if (bc->modem.ser12.last_sample ==
342                            bc->modem.ser12.last_rxbit)
343                                bc->modem.shreg |= 0x10000;
344                        bc->modem.ser12.last_rxbit =
345                                bc->modem.ser12.last_sample;
346                }
347                bc->modem.ser12.interm_sample = !bc->modem.ser12.interm_sample;
348                /*
349                 * DCD stuff
350                 */
351                bc->modem.ser12.dcd_sum0 -= (bc->modem.ser12.dcd_shreg & 1);
352        }
353        outb(0x0d, MCR(dev->base_addr));                /* transmitter off */
354        if (bc->modem.shreg & 1) {
355                hdlcdrv_putbits(&bc->hdrv, bc->modem.shreg >> 1);
356                bc->modem.shreg = 0x10000;
357        }
358        if(!bc->modem.ser12.dcd_time) {
359                if (bc->opt_dcd & 1) 
360                        hdlcdrv_setdcd(&bc->hdrv, !((inb(MSR(dev->base_addr)) ^ bc->opt_dcd) & 0x80));
361                else
362                        hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 +
363                                                   bc->modem.ser12.dcd_sum1 +
364                                                   bc->modem.ser12.dcd_sum2) < 0);
365                bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1;
366                bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0;
367                /* offset to ensure DCD off on silent input */
368                bc->modem.ser12.dcd_sum0 = 2;
369                bc->modem.ser12.dcd_time = SER12_DCD_INTERVAL(bc);
370        }
371        bc->modem.ser12.dcd_time--;
372}
373
374/* --------------------------------------------------------------------- */
375
376static irqreturn_t ser12_interrupt(int irq, void *dev_id)
377{
378        struct net_device *dev = (struct net_device *)dev_id;
379        struct baycom_state *bc = netdev_priv(dev);
380        unsigned char iir;
381
382        if (!dev || !bc || bc->hdrv.magic != HDLCDRV_MAGIC)
383                return IRQ_NONE;
384        /* fast way out */
385        if ((iir = inb(IIR(dev->base_addr))) & 1)
386                return IRQ_NONE;
387        baycom_int_freq(bc);
388        do {
389                switch (iir & 6) {
390                case 6:
391                        inb(LSR(dev->base_addr));
392                        break;
393                        
394                case 4:
395                        inb(RBR(dev->base_addr));
396                        break;
397                        
398                case 2:
399                        /*
400                         * check if transmitter active
401                         */
402                        if (hdlcdrv_ptt(&bc->hdrv))
403                                ser12_tx(dev, bc);
404                        else {
405                                ser12_rx(dev, bc);
406                                bc->modem.arb_divider--;
407                        }
408                        outb(0x00, THR(dev->base_addr));
409                        break;
410                        
411                default:
412                        inb(MSR(dev->base_addr));
413                        break;
414                }
415                iir = inb(IIR(dev->base_addr));
416        } while (!(iir & 1));
417        if (bc->modem.arb_divider <= 0) {
418                bc->modem.arb_divider = SER12_ARB_DIVIDER(bc);
419                local_irq_enable();
420                hdlcdrv_arbitrate(dev, &bc->hdrv);
421        }
422        local_irq_enable();
423        hdlcdrv_transmitter(dev, &bc->hdrv);
424        hdlcdrv_receiver(dev, &bc->hdrv);
425        local_irq_disable();
426        return IRQ_HANDLED;
427}
428
429/* --------------------------------------------------------------------- */
430
431enum uart { c_uart_unknown, c_uart_8250,
432            c_uart_16450, c_uart_16550, c_uart_16550A};
433static const char *uart_str[] = { 
434        "unknown", "8250", "16450", "16550", "16550A" 
435};
436
437static enum uart ser12_check_uart(unsigned int iobase)
438{
439        unsigned char b1,b2,b3;
440        enum uart u;
441        enum uart uart_tab[] =
442                { c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A };
443
444        b1 = inb(MCR(iobase));
445        outb(b1 | 0x10, MCR(iobase));        /* loopback mode */
446        b2 = inb(MSR(iobase));
447        outb(0x1a, MCR(iobase));
448        b3 = inb(MSR(iobase)) & 0xf0;
449        outb(b1, MCR(iobase));                        /* restore old values */
450        outb(b2, MSR(iobase));
451        if (b3 != 0x90)
452                return c_uart_unknown;
453        inb(RBR(iobase));
454        inb(RBR(iobase));
455        outb(0x01, FCR(iobase));                /* enable FIFOs */
456        u = uart_tab[(inb(IIR(iobase)) >> 6) & 3];
457        if (u == c_uart_16450) {
458                outb(0x5a, SCR(iobase));
459                b1 = inb(SCR(iobase));
460                outb(0xa5, SCR(iobase));
461                b2 = inb(SCR(iobase));
462                if ((b1 != 0x5a) || (b2 != 0xa5))
463                        u = c_uart_8250;
464        }
465        return u;
466}
467
468/* --------------------------------------------------------------------- */
469
470static int ser12_open(struct net_device *dev)
471{
472        struct baycom_state *bc = netdev_priv(dev);
473        enum uart u;
474
475        if (!dev || !bc)
476                return -ENXIO;
477        if (!dev->base_addr || dev->base_addr > 0x1000-SER12_EXTENT ||
478            dev->irq < 2 || dev->irq > 15)
479                return -ENXIO;
480        if (!request_region(dev->base_addr, SER12_EXTENT, "baycom_ser12"))
481                return -EACCES;
482        memset(&bc->modem, 0, sizeof(bc->modem));
483        bc->hdrv.par.bitrate = 1200;
484        if ((u = ser12_check_uart(dev->base_addr)) == c_uart_unknown) {
485                release_region(dev->base_addr, SER12_EXTENT);       
486                return -EIO;
487        }
488        outb(0, FCR(dev->base_addr));  /* disable FIFOs */
489        outb(0x0d, MCR(dev->base_addr));
490        outb(0, IER(dev->base_addr));
491        if (request_irq(dev->irq, ser12_interrupt, IRQF_DISABLED | IRQF_SHARED,
492                        "baycom_ser12", dev)) {
493                release_region(dev->base_addr, SER12_EXTENT);       
494                return -EBUSY;
495        }
496        /*
497         * enable transmitter empty interrupt
498         */
499        outb(2, IER(dev->base_addr));
500        /*
501         * set the SIO to 6 Bits/character and 19200 or 28800 baud, so that
502         * we get exactly (hopefully) 2 or 3 interrupts per radio symbol,
503         * depending on the usage of the software DCD routine
504         */
505        ser12_set_divisor(dev, bc->opt_dcd ? 6 : 4);
506        printk(KERN_INFO "%s: ser12 at iobase 0x%lx irq %u uart %s\n", 
507               bc_drvname, dev->base_addr, dev->irq, uart_str[u]);
508        return 0;
509}
510
511/* --------------------------------------------------------------------- */
512
513static int ser12_close(struct net_device *dev)
514{
515        struct baycom_state *bc = netdev_priv(dev);
516
517        if (!dev || !bc)
518                return -EINVAL;
519        /*
520         * disable interrupts
521         */
522        outb(0, IER(dev->base_addr));
523        outb(1, MCR(dev->base_addr));
524        free_irq(dev->irq, dev);
525        release_region(dev->base_addr, SER12_EXTENT);
526        printk(KERN_INFO "%s: close ser12 at iobase 0x%lx irq %u\n",
527               bc_drvname, dev->base_addr, dev->irq);
528        return 0;
529}
530
531/* --------------------------------------------------------------------- */
532/*
533 * ===================== hdlcdrv driver interface =========================
534 */
535
536/* --------------------------------------------------------------------- */
537
538static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr,
539                        struct hdlcdrv_ioctl *hi, int cmd);
540
541/* --------------------------------------------------------------------- */
542
543static struct hdlcdrv_ops ser12_ops = {
544        .drvname = bc_drvname,
545        .drvinfo = bc_drvinfo,
546        .open    = ser12_open,
547        .close   = ser12_close,
548        .ioctl   = baycom_ioctl,
549};
550
551/* --------------------------------------------------------------------- */
552
553static int baycom_setmode(struct baycom_state *bc, const char *modestr)
554{
555        if (strchr(modestr, '*'))
556                bc->opt_dcd = 0;
557        else if (strchr(modestr, '+'))
558                bc->opt_dcd = -1;
559        else if (strchr(modestr, '@'))
560                bc->opt_dcd = -2;
561        else
562                bc->opt_dcd = 1;
563        return 0;
564}
565
566/* --------------------------------------------------------------------- */
567
568static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr,
569                        struct hdlcdrv_ioctl *hi, int cmd)
570{
571        struct baycom_state *bc;
572        struct baycom_ioctl bi;
573
574        if (!dev)
575                return -EINVAL;
576
577        bc = netdev_priv(dev);
578        BUG_ON(bc->hdrv.magic != HDLCDRV_MAGIC);
579
580        if (cmd != SIOCDEVPRIVATE)
581                return -ENOIOCTLCMD;
582        switch (hi->cmd) {
583        default:
584                break;
585
586        case HDLCDRVCTL_GETMODE:
587                strcpy(hi->data.modename, "ser12");
588                if (bc->opt_dcd <= 0)
589                        strcat(hi->data.modename, (!bc->opt_dcd) ? "*" : (bc->opt_dcd == -2) ? "@" : "+");
590                if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl)))
591                        return -EFAULT;
592                return 0;
593
594        case HDLCDRVCTL_SETMODE:
595                if (netif_running(dev) || !capable(CAP_NET_ADMIN))
596                        return -EACCES;
597                hi->data.modename[sizeof(hi->data.modename)-1] = '\0';
598                return baycom_setmode(bc, hi->data.modename);
599
600        case HDLCDRVCTL_MODELIST:
601                strcpy(hi->data.modename, "ser12");
602                if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl)))
603                        return -EFAULT;
604                return 0;
605
606        case HDLCDRVCTL_MODEMPARMASK:
607                return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ;
608
609        }
610
611        if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi)))
612                return -EFAULT;
613        switch (bi.cmd) {
614        default:
615                return -ENOIOCTLCMD;
616
617#ifdef BAYCOM_DEBUG
618        case BAYCOMCTL_GETDEBUG:
619                bi.data.dbg.debug1 = bc->hdrv.ptt_keyed;
620                bi.data.dbg.debug2 = bc->debug_vals.last_intcnt;
621                bi.data.dbg.debug3 = bc->debug_vals.last_pllcorr;
622                break;
623#endif /* BAYCOM_DEBUG */
624
625        }
626        if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi)))
627                return -EFAULT;
628        return 0;
629
630}
631
632/* --------------------------------------------------------------------- */
633
634/*
635 * command line settable parameters
636 */
637static char *mode[NR_PORTS] = { "ser12*", };
638static int iobase[NR_PORTS] = { 0x3f8, };
639static int irq[NR_PORTS] = { 4, };
640
641module_param_array(mode, charp, NULL, 0);
642MODULE_PARM_DESC(mode, "baycom operating mode; * for software DCD");
643module_param_array(iobase, int, NULL, 0);
644MODULE_PARM_DESC(iobase, "baycom io base address");
645module_param_array(irq, int, NULL, 0);
646MODULE_PARM_DESC(irq, "baycom irq number");
647
648MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
649MODULE_DESCRIPTION("Baycom ser12 half duplex amateur radio modem driver");
650MODULE_LICENSE("GPL");
651
652/* --------------------------------------------------------------------- */
653
654static int __init init_baycomserhdx(void)
655{
656        int i, found = 0;
657        char set_hw = 1;
658
659        printk(bc_drvinfo);
660        /*
661         * register net devices
662         */
663        for (i = 0; i < NR_PORTS; i++) {
664                struct net_device *dev;
665                struct baycom_state *bc;
666                char ifname[IFNAMSIZ];
667
668                sprintf(ifname, "bcsh%d", i);
669
670                if (!mode[i])
671                        set_hw = 0;
672                if (!set_hw)
673                        iobase[i] = irq[i] = 0;
674
675                dev = hdlcdrv_register(&ser12_ops, 
676                                       sizeof(struct baycom_state),
677                                       ifname, iobase[i], irq[i], 0);
678                if (IS_ERR(dev)) 
679                        break;
680
681                bc = netdev_priv(dev);
682                if (set_hw && baycom_setmode(bc, mode[i]))
683                        set_hw = 0;
684                found++;
685                baycom_device[i] = dev;
686        }
687
688        if (!found)
689                return -ENXIO;
690        return 0;
691}
692
693static void __exit cleanup_baycomserhdx(void)
694{
695        int i;
696
697        for(i = 0; i < NR_PORTS; i++) {
698                struct net_device *dev = baycom_device[i];
699
700                if (dev)
701                        hdlcdrv_unregister(dev);
702        }
703}
704
705module_init(init_baycomserhdx);
706module_exit(cleanup_baycomserhdx);
707
708/* --------------------------------------------------------------------- */
709
710#ifndef MODULE
711
712/*
713 * format: baycom_ser_hdx=io,irq,mode
714 * mode: ser12    hardware DCD
715 *       ser12*   software DCD
716 *       ser12@   hardware/software DCD, i.e. no explicit DCD signal but hardware
717 *                mutes audio input to the modem
718 *       ser12+   hardware DCD, inverted signal at DCD pin
719 */
720
721static int __init baycom_ser_hdx_setup(char *str)
722{
723        static unsigned nr_dev;
724        int ints[3];
725
726        if (nr_dev >= NR_PORTS)
727                return 0;
728        str = get_options(str, 3, ints);
729        if (ints[0] < 2)
730                return 0;
731        mode[nr_dev] = str;
732        iobase[nr_dev] = ints[1];
733        irq[nr_dev] = ints[2];
734        nr_dev++;
735        return 1;
736}
737
738__setup("baycom_ser_hdx=", baycom_ser_hdx_setup);
739
740#endif /* MODULE */
741/* --------------------------------------------------------------------- */