Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*****************************************************************************/
0003 
0004 /*
0005  *  baycom_ser_fdx.c  -- baycom ser12 fullduplex radio modem driver.
0006  *
0007  *  Copyright (C) 1996-2000  Thomas Sailer (sailer@ife.ee.ethz.ch)
0008  *
0009  *  Please note that the GPL allows you to use the driver, NOT the radio.
0010  *  In order to use the radio, you need a license from the communications
0011  *  authority of your country.
0012  *
0013  *  Supported modems
0014  *
0015  *  ser12:  This is a very simple 1200 baud AFSK modem. The modem consists only
0016  *          of a modulator/demodulator chip, usually a TI TCM3105. The computer
0017  *          is responsible for regenerating the receiver bit clock, as well as
0018  *          for handling the HDLC protocol. The modem connects to a serial port,
0019  *          hence the name. Since the serial port is not used as an async serial
0020  *          port, the kernel driver for serial ports cannot be used, and this
0021  *          driver only supports standard serial hardware (8250, 16450, 16550A)
0022  *
0023  *          This modem usually draws its supply current out of the otherwise unused
0024  *          TXD pin of the serial port. Thus a contiguous stream of 0x00-bytes
0025  *          is transmitted to achieve a positive supply voltage.
0026  *
0027  *  hsk:    This is a 4800 baud FSK modem, designed for TNC use. It works fine
0028  *          in 'baycom-mode' :-)  In contrast to the TCM3105 modem, power is
0029  *          externally supplied. So there's no need to provide the 0x00-byte-stream
0030  *          when receiving or idle, which drastically reduces interrupt load.
0031  *
0032  *  Command line options (insmod command line)
0033  *
0034  *  mode     ser#    hardware DCD
0035  *           ser#*   software DCD
0036  *           ser#+   hardware DCD, inverted signal at DCD pin
0037  *           '#' denotes the baud rate / 100, eg. ser12* is '1200 baud, soft DCD'
0038  *  iobase   base address of the port; common values are 0x3f8, 0x2f8, 0x3e8, 0x2e8
0039  *  baud     baud rate (between 300 and 4800)
0040  *  irq      interrupt line of the port; common values are 4,3
0041  *
0042  *  History:
0043  *   0.1  26.06.1996  Adapted from baycom.c and made network driver interface
0044  *        18.10.1996  Changed to new user space access routines (copy_{to,from}_user)
0045  *   0.3  26.04.1997  init code/data tagged
0046  *   0.4  08.07.1997  alternative ser12 decoding algorithm (uses delta CTS ints)
0047  *   0.5  11.11.1997  ser12/par96 split into separate files
0048  *   0.6  24.01.1998  Thorsten Kranzkowski, dl8bcu and Thomas Sailer:
0049  *                    reduced interrupt load in transmit case
0050  *                    reworked receiver
0051  *   0.7  03.08.1999  adapt to Linus' new __setup/__initcall
0052  *   0.8  10.08.1999  use module_init/module_exit
0053  *   0.9  12.02.2000  adapted to softnet driver interface
0054  *   0.10 03.07.2000  fix interface name handling
0055  */
0056 
0057 /*****************************************************************************/
0058 
0059 #include <linux/capability.h>
0060 #include <linux/module.h>
0061 #include <linux/ioport.h>
0062 #include <linux/string.h>
0063 #include <linux/init.h>
0064 #include <linux/interrupt.h>
0065 #include <linux/hdlcdrv.h>
0066 #include <linux/baycom.h>
0067 #include <linux/jiffies.h>
0068 #include <linux/time64.h>
0069 
0070 #include <linux/uaccess.h>
0071 #include <asm/io.h>
0072 #include <asm/irq.h>
0073 
0074 /* --------------------------------------------------------------------- */
0075 
0076 #define BAYCOM_DEBUG
0077 
0078 /* --------------------------------------------------------------------- */
0079 
0080 static const char bc_drvname[] = "baycom_ser_fdx";
0081 static const char bc_drvinfo[] = KERN_INFO "baycom_ser_fdx: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n"
0082 "baycom_ser_fdx: version 0.10\n";
0083 
0084 /* --------------------------------------------------------------------- */
0085 
0086 #define NR_PORTS 4
0087 
0088 static struct net_device *baycom_device[NR_PORTS];
0089 
0090 /* --------------------------------------------------------------------- */
0091 
0092 #define RBR(iobase) (iobase+0)
0093 #define THR(iobase) (iobase+0)
0094 #define IER(iobase) (iobase+1)
0095 #define IIR(iobase) (iobase+2)
0096 #define FCR(iobase) (iobase+2)
0097 #define LCR(iobase) (iobase+3)
0098 #define MCR(iobase) (iobase+4)
0099 #define LSR(iobase) (iobase+5)
0100 #define MSR(iobase) (iobase+6)
0101 #define SCR(iobase) (iobase+7)
0102 #define DLL(iobase) (iobase+0)
0103 #define DLM(iobase) (iobase+1)
0104 
0105 #define SER12_EXTENT 8
0106 
0107 /* ---------------------------------------------------------------------- */
0108 /*
0109  * Information that need to be kept for each board.
0110  */
0111 
0112 struct baycom_state {
0113     struct hdlcdrv_state hdrv;
0114 
0115     unsigned int baud, baud_us, baud_arbdiv, baud_uartdiv, baud_dcdtimeout;
0116     int opt_dcd;
0117 
0118     struct modem_state {
0119         unsigned char flags;
0120         unsigned char ptt;
0121         unsigned int shreg;
0122         struct modem_state_ser12 {
0123             unsigned char tx_bit;
0124             unsigned char last_rxbit;
0125             int dcd_sum0, dcd_sum1, dcd_sum2;
0126             int dcd_time;
0127             unsigned int pll_time;
0128             unsigned int txshreg;
0129         } ser12;
0130     } modem;
0131 
0132 #ifdef BAYCOM_DEBUG
0133     struct debug_vals {
0134         unsigned long last_jiffies;
0135         unsigned cur_intcnt;
0136         unsigned last_intcnt;
0137         int cur_pllcorr;
0138         int last_pllcorr;
0139     } debug_vals;
0140 #endif /* BAYCOM_DEBUG */
0141 };
0142 
0143 /* --------------------------------------------------------------------- */
0144 
0145 static inline void baycom_int_freq(struct baycom_state *bc)
0146 {
0147 #ifdef BAYCOM_DEBUG
0148     unsigned long cur_jiffies = jiffies;
0149     /*
0150      * measure the interrupt frequency
0151      */
0152     bc->debug_vals.cur_intcnt++;
0153     if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) {
0154         bc->debug_vals.last_jiffies = cur_jiffies;
0155         bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt;
0156         bc->debug_vals.cur_intcnt = 0;
0157         bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr;
0158         bc->debug_vals.cur_pllcorr = 0;
0159     }
0160 #endif /* BAYCOM_DEBUG */
0161 }
0162 
0163 /* --------------------------------------------------------------------- */
0164 /*
0165  * ===================== SER12 specific routines =========================
0166  */
0167 
0168 /* --------------------------------------------------------------------- */
0169 
0170 static inline void ser12_set_divisor(struct net_device *dev,
0171                                      unsigned int divisor)
0172 {
0173         outb(0x81, LCR(dev->base_addr));        /* DLAB = 1 */
0174         outb(divisor, DLL(dev->base_addr));
0175         outb(divisor >> 8, DLM(dev->base_addr));
0176         outb(0x01, LCR(dev->base_addr));        /* word length = 6 */
0177         /*
0178          * make sure the next interrupt is generated;
0179          * 0 must be used to power the modem; the modem draws its
0180          * power from the TxD line
0181          */
0182         outb(0x00, THR(dev->base_addr));
0183         /*
0184          * it is important not to set the divider while transmitting;
0185          * this reportedly makes some UARTs generating interrupts
0186          * in the hundredthousands per second region
0187          * Reported by: Ignacio.Arenaza@studi.epfl.ch (Ignacio Arenaza Nuno)
0188          */
0189 }
0190 
0191 static __inline__ void ser12_rx(struct net_device *dev, struct baycom_state *bc, struct timespec64 *ts, unsigned char curs)
0192 {
0193     int timediff;
0194     int bdus8 = bc->baud_us >> 3;
0195     int bdus4 = bc->baud_us >> 2;
0196     int bdus2 = bc->baud_us >> 1;
0197 
0198     timediff = 1000000 + ts->tv_nsec / NSEC_PER_USEC -
0199                     bc->modem.ser12.pll_time;
0200     while (timediff >= 500000)
0201         timediff -= 1000000;
0202     while (timediff >= bdus2) {
0203         timediff -= bc->baud_us;
0204         bc->modem.ser12.pll_time += bc->baud_us;
0205         bc->modem.ser12.dcd_time--;
0206         /* first check if there is room to add a bit */
0207         if (bc->modem.shreg & 1) {
0208             hdlcdrv_putbits(&bc->hdrv, (bc->modem.shreg >> 1) ^ 0xffff);
0209             bc->modem.shreg = 0x10000;
0210         }
0211         /* add a one bit */
0212         bc->modem.shreg >>= 1;
0213     }
0214     if (bc->modem.ser12.dcd_time <= 0) {
0215         if (!bc->opt_dcd)
0216             hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 + 
0217                            bc->modem.ser12.dcd_sum1 + 
0218                            bc->modem.ser12.dcd_sum2) < 0);
0219         bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1;
0220         bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0;
0221         bc->modem.ser12.dcd_sum0 = 2; /* slight bias */
0222         bc->modem.ser12.dcd_time += 120;
0223     }
0224     if (bc->modem.ser12.last_rxbit != curs) {
0225         bc->modem.ser12.last_rxbit = curs;
0226         bc->modem.shreg |= 0x10000;
0227         /* adjust the PLL */
0228         if (timediff > 0)
0229             bc->modem.ser12.pll_time += bdus8;
0230         else
0231             bc->modem.ser12.pll_time += 1000000 - bdus8;
0232         /* update DCD */
0233         if (abs(timediff) > bdus4)
0234             bc->modem.ser12.dcd_sum0 += 4;
0235         else
0236             bc->modem.ser12.dcd_sum0--;
0237 #ifdef BAYCOM_DEBUG
0238         bc->debug_vals.cur_pllcorr = timediff;
0239 #endif /* BAYCOM_DEBUG */
0240     }
0241     while (bc->modem.ser12.pll_time >= 1000000)
0242         bc->modem.ser12.pll_time -= 1000000;
0243 }
0244 
0245 /* --------------------------------------------------------------------- */
0246 
0247 static irqreturn_t ser12_interrupt(int irq, void *dev_id)
0248 {
0249     struct net_device *dev = (struct net_device *)dev_id;
0250     struct baycom_state *bc = netdev_priv(dev);
0251     struct timespec64 ts;
0252     unsigned char iir, msr;
0253     unsigned int txcount = 0;
0254 
0255     if (!bc || bc->hdrv.magic != HDLCDRV_MAGIC)
0256         return IRQ_NONE;
0257     /* fast way out for shared irq */
0258     if ((iir = inb(IIR(dev->base_addr))) & 1)   
0259         return IRQ_NONE;
0260     /* get current time */
0261     ktime_get_ts64(&ts);
0262     msr = inb(MSR(dev->base_addr));
0263     /* delta DCD */
0264     if ((msr & 8) && bc->opt_dcd)
0265         hdlcdrv_setdcd(&bc->hdrv, !((msr ^ bc->opt_dcd) & 0x80));
0266     do {
0267         switch (iir & 6) {
0268         case 6:
0269             inb(LSR(dev->base_addr));
0270             break;
0271             
0272         case 4:
0273             inb(RBR(dev->base_addr));
0274             break;
0275             
0276         case 2:
0277             /*
0278              * make sure the next interrupt is generated;
0279              * 0 must be used to power the modem; the modem draws its
0280              * power from the TxD line
0281              */
0282             outb(0x00, THR(dev->base_addr));
0283             baycom_int_freq(bc);
0284             txcount++;
0285             /*
0286              * first output the last bit (!) then call HDLC transmitter,
0287              * since this may take quite long
0288              */
0289             if (bc->modem.ptt)
0290                 outb(0x0e | (!!bc->modem.ser12.tx_bit), MCR(dev->base_addr));
0291             else
0292                 outb(0x0d, MCR(dev->base_addr));       /* transmitter off */
0293             break;
0294             
0295         default:
0296             msr = inb(MSR(dev->base_addr));
0297             /* delta DCD */
0298             if ((msr & 8) && bc->opt_dcd) 
0299                 hdlcdrv_setdcd(&bc->hdrv, !((msr ^ bc->opt_dcd) & 0x80));
0300             break;
0301         }
0302         iir = inb(IIR(dev->base_addr));
0303     } while (!(iir & 1));
0304     ser12_rx(dev, bc, &ts, msr & 0x10); /* CTS */
0305     if (bc->modem.ptt && txcount) {
0306         if (bc->modem.ser12.txshreg <= 1) {
0307             bc->modem.ser12.txshreg = 0x10000 | hdlcdrv_getbits(&bc->hdrv);
0308             if (!hdlcdrv_ptt(&bc->hdrv)) {
0309                 ser12_set_divisor(dev, 115200/100/8);
0310                 bc->modem.ptt = 0;
0311                 goto end_transmit;
0312             }
0313         }
0314         bc->modem.ser12.tx_bit = !(bc->modem.ser12.tx_bit ^ (bc->modem.ser12.txshreg & 1));
0315         bc->modem.ser12.txshreg >>= 1;
0316     }
0317  end_transmit:
0318     local_irq_enable();
0319     if (!bc->modem.ptt && txcount) {
0320         hdlcdrv_arbitrate(dev, &bc->hdrv);
0321         if (hdlcdrv_ptt(&bc->hdrv)) {
0322             ser12_set_divisor(dev, bc->baud_uartdiv);
0323             bc->modem.ser12.txshreg = 1;
0324             bc->modem.ptt = 1;
0325         }
0326     }
0327     hdlcdrv_transmitter(dev, &bc->hdrv);
0328     hdlcdrv_receiver(dev, &bc->hdrv);
0329     local_irq_disable();
0330     return IRQ_HANDLED;
0331 }
0332 
0333 /* --------------------------------------------------------------------- */
0334 
0335 enum uart { c_uart_unknown, c_uart_8250,
0336         c_uart_16450, c_uart_16550, c_uart_16550A};
0337 static const char *uart_str[] = { 
0338     "unknown", "8250", "16450", "16550", "16550A" 
0339 };
0340 
0341 static enum uart ser12_check_uart(unsigned int iobase)
0342 {
0343     unsigned char b1,b2,b3;
0344     enum uart u;
0345     enum uart uart_tab[] =
0346         { c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A };
0347 
0348     b1 = inb(MCR(iobase));
0349     outb(b1 | 0x10, MCR(iobase));   /* loopback mode */
0350     b2 = inb(MSR(iobase));
0351     outb(0x1a, MCR(iobase));
0352     b3 = inb(MSR(iobase)) & 0xf0;
0353     outb(b1, MCR(iobase));          /* restore old values */
0354     outb(b2, MSR(iobase));
0355     if (b3 != 0x90)
0356         return c_uart_unknown;
0357     inb(RBR(iobase));
0358     inb(RBR(iobase));
0359     outb(0x01, FCR(iobase));        /* enable FIFOs */
0360     u = uart_tab[(inb(IIR(iobase)) >> 6) & 3];
0361     if (u == c_uart_16450) {
0362         outb(0x5a, SCR(iobase));
0363         b1 = inb(SCR(iobase));
0364         outb(0xa5, SCR(iobase));
0365         b2 = inb(SCR(iobase));
0366         if ((b1 != 0x5a) || (b2 != 0xa5))
0367             u = c_uart_8250;
0368     }
0369     return u;
0370 }
0371 
0372 /* --------------------------------------------------------------------- */
0373 
0374 static int ser12_open(struct net_device *dev)
0375 {
0376     struct baycom_state *bc = netdev_priv(dev);
0377     enum uart u;
0378 
0379     if (!dev || !bc)
0380         return -ENXIO;
0381     if (!dev->base_addr || dev->base_addr > 0xffff-SER12_EXTENT ||
0382         dev->irq < 2 || dev->irq > nr_irqs) {
0383         printk(KERN_INFO "baycom_ser_fdx: invalid portnumber (max %u) "
0384                 "or irq (2 <= irq <= %d)\n",
0385                 0xffff-SER12_EXTENT, nr_irqs);
0386         return -ENXIO;
0387     }
0388     if (bc->baud < 300 || bc->baud > 4800) {
0389         printk(KERN_INFO "baycom_ser_fdx: invalid baudrate "
0390                 "(300...4800)\n");
0391         return -EINVAL;
0392     }
0393     if (!request_region(dev->base_addr, SER12_EXTENT, "baycom_ser_fdx")) {
0394         printk(KERN_WARNING "BAYCOM_SER_FSX: I/O port 0x%04lx busy\n",
0395                dev->base_addr);
0396         return -EACCES;
0397     }
0398     memset(&bc->modem, 0, sizeof(bc->modem));
0399     bc->hdrv.par.bitrate = bc->baud;
0400     bc->baud_us = 1000000/bc->baud;
0401     bc->baud_uartdiv = (115200/8)/bc->baud;
0402     if ((u = ser12_check_uart(dev->base_addr)) == c_uart_unknown){
0403         release_region(dev->base_addr, SER12_EXTENT);
0404         return -EIO;
0405     }
0406     outb(0, FCR(dev->base_addr));  /* disable FIFOs */
0407     outb(0x0d, MCR(dev->base_addr));
0408     outb(0, IER(dev->base_addr));
0409     if (request_irq(dev->irq, ser12_interrupt, IRQF_SHARED,
0410             "baycom_ser_fdx", dev)) {
0411         release_region(dev->base_addr, SER12_EXTENT);
0412         return -EBUSY;
0413     }
0414     /*
0415      * set the SIO to 6 Bits/character; during receive,
0416      * the baud rate is set to produce 100 ints/sec
0417      * to feed the channel arbitration process,
0418      * during transmit to baud ints/sec to run
0419      * the transmitter
0420      */
0421     ser12_set_divisor(dev, 115200/100/8);
0422     /*
0423      * enable transmitter empty interrupt and modem status interrupt
0424      */
0425     outb(0x0a, IER(dev->base_addr));
0426     /*
0427      * make sure the next interrupt is generated;
0428      * 0 must be used to power the modem; the modem draws its
0429      * power from the TxD line
0430      */
0431     outb(0x00, THR(dev->base_addr));
0432     hdlcdrv_setdcd(&bc->hdrv, 0);
0433     printk(KERN_INFO "%s: ser_fdx at iobase 0x%lx irq %u baud %u uart %s\n",
0434            bc_drvname, dev->base_addr, dev->irq, bc->baud, uart_str[u]);
0435     return 0;
0436 }
0437 
0438 /* --------------------------------------------------------------------- */
0439 
0440 static int ser12_close(struct net_device *dev)
0441 {
0442     struct baycom_state *bc = netdev_priv(dev);
0443 
0444     if (!dev || !bc)
0445         return -EINVAL;
0446     /*
0447      * disable interrupts
0448      */
0449     outb(0, IER(dev->base_addr));
0450     outb(1, MCR(dev->base_addr));
0451     free_irq(dev->irq, dev);
0452     release_region(dev->base_addr, SER12_EXTENT);
0453     printk(KERN_INFO "%s: close ser_fdx at iobase 0x%lx irq %u\n",
0454            bc_drvname, dev->base_addr, dev->irq);
0455     return 0;
0456 }
0457 
0458 /* --------------------------------------------------------------------- */
0459 /*
0460  * ===================== hdlcdrv driver interface =========================
0461  */
0462 
0463 /* --------------------------------------------------------------------- */
0464 
0465 static int baycom_ioctl(struct net_device *dev, void __user *data,
0466             struct hdlcdrv_ioctl *hi, int cmd);
0467 
0468 /* --------------------------------------------------------------------- */
0469 
0470 static const struct hdlcdrv_ops ser12_ops = {
0471     .drvname = bc_drvname,
0472     .drvinfo = bc_drvinfo,
0473     .open    = ser12_open,
0474     .close   = ser12_close,
0475     .ioctl   = baycom_ioctl,
0476 };
0477 
0478 /* --------------------------------------------------------------------- */
0479 
0480 static int baycom_setmode(struct baycom_state *bc, const char *modestr)
0481 {
0482     unsigned int baud;
0483 
0484     if (!strncmp(modestr, "ser", 3)) {
0485         baud = simple_strtoul(modestr+3, NULL, 10);
0486         if (baud >= 3 && baud <= 48)
0487             bc->baud = baud*100;
0488     }
0489     if (strchr(modestr, '*'))
0490         bc->opt_dcd = 0;
0491     else if (strchr(modestr, '+'))
0492         bc->opt_dcd = -1;
0493     else
0494         bc->opt_dcd = 1;
0495     return 0;
0496 }
0497 
0498 /* --------------------------------------------------------------------- */
0499 
0500 static int baycom_ioctl(struct net_device *dev, void __user *data,
0501             struct hdlcdrv_ioctl *hi, int cmd)
0502 {
0503     struct baycom_state *bc;
0504     struct baycom_ioctl bi;
0505 
0506     if (!dev)
0507         return -EINVAL;
0508 
0509     bc = netdev_priv(dev);
0510     BUG_ON(bc->hdrv.magic != HDLCDRV_MAGIC);
0511 
0512     if (cmd != SIOCDEVPRIVATE)
0513         return -ENOIOCTLCMD;
0514     switch (hi->cmd) {
0515     default:
0516         break;
0517 
0518     case HDLCDRVCTL_GETMODE:
0519         sprintf(hi->data.modename, "ser%u", bc->baud / 100);
0520         if (bc->opt_dcd <= 0)
0521             strcat(hi->data.modename, (!bc->opt_dcd) ? "*" : "+");
0522         if (copy_to_user(data, hi, sizeof(struct hdlcdrv_ioctl)))
0523             return -EFAULT;
0524         return 0;
0525 
0526     case HDLCDRVCTL_SETMODE:
0527         if (netif_running(dev) || !capable(CAP_NET_ADMIN))
0528             return -EACCES;
0529         hi->data.modename[sizeof(hi->data.modename)-1] = '\0';
0530         return baycom_setmode(bc, hi->data.modename);
0531 
0532     case HDLCDRVCTL_MODELIST:
0533         strcpy(hi->data.modename, "ser12,ser3,ser24");
0534         if (copy_to_user(data, hi, sizeof(struct hdlcdrv_ioctl)))
0535             return -EFAULT;
0536         return 0;
0537 
0538     case HDLCDRVCTL_MODEMPARMASK:
0539         return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ;
0540 
0541     }
0542 
0543     if (copy_from_user(&bi, data, sizeof(bi)))
0544         return -EFAULT;
0545     switch (bi.cmd) {
0546     default:
0547         return -ENOIOCTLCMD;
0548 
0549 #ifdef BAYCOM_DEBUG
0550     case BAYCOMCTL_GETDEBUG:
0551         bi.data.dbg.debug1 = bc->hdrv.ptt_keyed;
0552         bi.data.dbg.debug2 = bc->debug_vals.last_intcnt;
0553         bi.data.dbg.debug3 = bc->debug_vals.last_pllcorr;
0554         break;
0555 #endif /* BAYCOM_DEBUG */
0556 
0557     }
0558     if (copy_to_user(data, &bi, sizeof(bi)))
0559         return -EFAULT;
0560     return 0;
0561 
0562 }
0563 
0564 /* --------------------------------------------------------------------- */
0565 
0566 /*
0567  * command line settable parameters
0568  */
0569 static char *mode[NR_PORTS] = { "ser12*", };
0570 static int iobase[NR_PORTS] = { 0x3f8, };
0571 static int irq[NR_PORTS] = { 4, };
0572 static int baud[NR_PORTS] = { [0 ... NR_PORTS-1] = 1200 };
0573 
0574 module_param_array(mode, charp, NULL, 0);
0575 MODULE_PARM_DESC(mode, "baycom operating mode; * for software DCD");
0576 module_param_hw_array(iobase, int, ioport, NULL, 0);
0577 MODULE_PARM_DESC(iobase, "baycom io base address");
0578 module_param_hw_array(irq, int, irq, NULL, 0);
0579 MODULE_PARM_DESC(irq, "baycom irq number");
0580 module_param_array(baud, int, NULL, 0);
0581 MODULE_PARM_DESC(baud, "baycom baud rate (300 to 4800)");
0582 
0583 MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
0584 MODULE_DESCRIPTION("Baycom ser12 full duplex amateur radio modem driver");
0585 MODULE_LICENSE("GPL");
0586 
0587 /* --------------------------------------------------------------------- */
0588 
0589 static int __init init_baycomserfdx(void)
0590 {
0591     int i, found = 0;
0592     char set_hw = 1;
0593 
0594     printk(bc_drvinfo);
0595     /*
0596      * register net devices
0597      */
0598     for (i = 0; i < NR_PORTS; i++) {
0599         struct net_device *dev;
0600         struct baycom_state *bc;
0601         char ifname[IFNAMSIZ];
0602 
0603         sprintf(ifname, "bcsf%d", i);
0604 
0605         if (!mode[i])
0606             set_hw = 0;
0607         if (!set_hw)
0608             iobase[i] = irq[i] = 0;
0609 
0610         dev = hdlcdrv_register(&ser12_ops, 
0611                        sizeof(struct baycom_state),
0612                        ifname, iobase[i], irq[i], 0);
0613         if (IS_ERR(dev)) 
0614             break;
0615 
0616         bc = netdev_priv(dev);
0617         if (set_hw && baycom_setmode(bc, mode[i]))
0618             set_hw = 0;
0619         bc->baud = baud[i];
0620         found++;
0621         baycom_device[i] = dev;
0622     }
0623 
0624     if (!found)
0625         return -ENXIO;
0626     return 0;
0627 }
0628 
0629 static void __exit cleanup_baycomserfdx(void)
0630 {
0631     int i;
0632 
0633     for(i = 0; i < NR_PORTS; i++) {
0634         struct net_device *dev = baycom_device[i];
0635         if (dev) 
0636             hdlcdrv_unregister(dev);
0637     }
0638 }
0639 
0640 module_init(init_baycomserfdx);
0641 module_exit(cleanup_baycomserfdx);
0642 
0643 /* --------------------------------------------------------------------- */
0644 
0645 #ifndef MODULE
0646 
0647 /*
0648  * format: baycom_ser_fdx=io,irq,mode
0649  * mode: ser#    hardware DCD
0650  *       ser#*   software DCD
0651  *       ser#+   hardware DCD, inverted signal at DCD pin
0652  * '#' denotes the baud rate / 100, eg. ser12* is '1200 baud, soft DCD'
0653  */
0654 
0655 static int __init baycom_ser_fdx_setup(char *str)
0656 {
0657         static unsigned nr_dev;
0658         int ints[4];
0659 
0660         if (nr_dev >= NR_PORTS)
0661                 return 0;
0662         str = get_options(str, 4, ints);
0663         if (ints[0] < 2)
0664                 return 0;
0665         mode[nr_dev] = str;
0666         iobase[nr_dev] = ints[1];
0667         irq[nr_dev] = ints[2];
0668     if (ints[0] >= 3)
0669         baud[nr_dev] = ints[3];
0670     nr_dev++;
0671     return 1;
0672 }
0673 
0674 __setup("baycom_ser_fdx=", baycom_ser_fdx_setup);
0675 
0676 #endif /* MODULE */
0677 /* --------------------------------------------------------------------- */