root/drivers/net/hamradio/baycom_ser_fdx.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. baycom_int_freq
  2. ser12_set_divisor
  3. ser12_rx
  4. ser12_interrupt
  5. ser12_check_uart
  6. ser12_open
  7. ser12_close
  8. baycom_setmode
  9. baycom_ioctl
  10. init_baycomserfdx
  11. cleanup_baycomserfdx
  12. baycom_ser_fdx_setup

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*****************************************************************************/
   3 
   4 /*
   5  *      baycom_ser_fdx.c  -- baycom ser12 fullduplex radio modem driver.
   6  *
   7  *      Copyright (C) 1996-2000  Thomas Sailer (sailer@ife.ee.ethz.ch)
   8  *
   9  *  Please note that the GPL allows you to use the driver, NOT the radio.
  10  *  In order to use the radio, you need a license from the communications
  11  *  authority of your country.
  12  *
  13  *  Supported modems
  14  *
  15  *  ser12:  This is a very simple 1200 baud AFSK modem. The modem consists only
  16  *          of a modulator/demodulator chip, usually a TI TCM3105. The computer
  17  *          is responsible for regenerating the receiver bit clock, as well as
  18  *          for handling the HDLC protocol. The modem connects to a serial port,
  19  *          hence the name. Since the serial port is not used as an async serial
  20  *          port, the kernel driver for serial ports cannot be used, and this
  21  *          driver only supports standard serial hardware (8250, 16450, 16550A)
  22  *
  23  *          This modem usually draws its supply current out of the otherwise unused
  24  *          TXD pin of the serial port. Thus a contiguous stream of 0x00-bytes
  25  *          is transmitted to achieve a positive supply voltage.
  26  *
  27  *  hsk:    This is a 4800 baud FSK modem, designed for TNC use. It works fine
  28  *          in 'baycom-mode' :-)  In contrast to the TCM3105 modem, power is
  29  *          externally supplied. So there's no need to provide the 0x00-byte-stream
  30  *          when receiving or idle, which drastically reduces interrupt load.
  31  *
  32  *  Command line options (insmod command line)
  33  *
  34  *  mode     ser#    hardware DCD
  35  *           ser#*   software DCD
  36  *           ser#+   hardware DCD, inverted signal at DCD pin
  37  *           '#' denotes the baud rate / 100, eg. ser12* is '1200 baud, soft DCD'
  38  *  iobase   base address of the port; common values are 0x3f8, 0x2f8, 0x3e8, 0x2e8
  39  *  baud     baud rate (between 300 and 4800)
  40  *  irq      interrupt line of the port; common values are 4,3
  41  *
  42  *  History:
  43  *   0.1  26.06.1996  Adapted from baycom.c and made network driver interface
  44  *        18.10.1996  Changed to new user space access routines (copy_{to,from}_user)
  45  *   0.3  26.04.1997  init code/data tagged
  46  *   0.4  08.07.1997  alternative ser12 decoding algorithm (uses delta CTS ints)
  47  *   0.5  11.11.1997  ser12/par96 split into separate files
  48  *   0.6  24.01.1998  Thorsten Kranzkowski, dl8bcu and Thomas Sailer:
  49  *                    reduced interrupt load in transmit case
  50  *                    reworked receiver
  51  *   0.7  03.08.1999  adapt to Linus' new __setup/__initcall
  52  *   0.8  10.08.1999  use module_init/module_exit
  53  *   0.9  12.02.2000  adapted to softnet driver interface
  54  *   0.10 03.07.2000  fix interface name handling
  55  */
  56 
  57 /*****************************************************************************/
  58 
  59 #include <linux/capability.h>
  60 #include <linux/module.h>
  61 #include <linux/ioport.h>
  62 #include <linux/string.h>
  63 #include <linux/init.h>
  64 #include <linux/interrupt.h>
  65 #include <linux/hdlcdrv.h>
  66 #include <linux/baycom.h>
  67 #include <linux/jiffies.h>
  68 #include <linux/time64.h>
  69 
  70 #include <linux/uaccess.h>
  71 #include <asm/io.h>
  72 #include <asm/irq.h>
  73 
  74 /* --------------------------------------------------------------------- */
  75 
  76 #define BAYCOM_DEBUG
  77 
  78 /* --------------------------------------------------------------------- */
  79 
  80 static const char bc_drvname[] = "baycom_ser_fdx";
  81 static const char bc_drvinfo[] = KERN_INFO "baycom_ser_fdx: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n"
  82 "baycom_ser_fdx: version 0.10\n";
  83 
  84 /* --------------------------------------------------------------------- */
  85 
  86 #define NR_PORTS 4
  87 
  88 static 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 
 112 struct baycom_state {
 113         struct hdlcdrv_state hdrv;
 114 
 115         unsigned int baud, baud_us, baud_arbdiv, baud_uartdiv, baud_dcdtimeout;
 116         int opt_dcd;
 117 
 118         struct modem_state {
 119                 unsigned char flags;
 120                 unsigned char ptt;
 121                 unsigned int shreg;
 122                 struct modem_state_ser12 {
 123                         unsigned char tx_bit;
 124                         unsigned char last_rxbit;
 125                         int dcd_sum0, dcd_sum1, dcd_sum2;
 126                         int dcd_time;
 127                         unsigned int pll_time;
 128                         unsigned int txshreg;
 129                 } ser12;
 130         } modem;
 131 
 132 #ifdef BAYCOM_DEBUG
 133         struct debug_vals {
 134                 unsigned long last_jiffies;
 135                 unsigned cur_intcnt;
 136                 unsigned last_intcnt;
 137                 int cur_pllcorr;
 138                 int last_pllcorr;
 139         } debug_vals;
 140 #endif /* BAYCOM_DEBUG */
 141 };
 142 
 143 /* --------------------------------------------------------------------- */
 144 
 145 static inline void baycom_int_freq(struct baycom_state *bc)
 146 {
 147 #ifdef BAYCOM_DEBUG
 148         unsigned long cur_jiffies = jiffies;
 149         /*
 150          * measure the interrupt frequency
 151          */
 152         bc->debug_vals.cur_intcnt++;
 153         if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) {
 154                 bc->debug_vals.last_jiffies = cur_jiffies;
 155                 bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt;
 156                 bc->debug_vals.cur_intcnt = 0;
 157                 bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr;
 158                 bc->debug_vals.cur_pllcorr = 0;
 159         }
 160 #endif /* BAYCOM_DEBUG */
 161 }
 162 
 163 /* --------------------------------------------------------------------- */
 164 /*
 165  * ===================== SER12 specific routines =========================
 166  */
 167 
 168 /* --------------------------------------------------------------------- */
 169 
 170 static inline void ser12_set_divisor(struct net_device *dev,
 171                                      unsigned int divisor)
 172 {
 173         outb(0x81, LCR(dev->base_addr));        /* DLAB = 1 */
 174         outb(divisor, DLL(dev->base_addr));
 175         outb(divisor >> 8, DLM(dev->base_addr));
 176         outb(0x01, LCR(dev->base_addr));        /* word length = 6 */
 177         /*
 178          * make sure the next interrupt is generated;
 179          * 0 must be used to power the modem; the modem draws its
 180          * power from the TxD line
 181          */
 182         outb(0x00, THR(dev->base_addr));
 183         /*
 184          * it is important not to set the divider while transmitting;
 185          * this reportedly makes some UARTs generating interrupts
 186          * in the hundredthousands per second region
 187          * Reported by: Ignacio.Arenaza@studi.epfl.ch (Ignacio Arenaza Nuno)
 188          */
 189 }
 190 
 191 static __inline__ void ser12_rx(struct net_device *dev, struct baycom_state *bc, struct timespec64 *ts, unsigned char curs)
 192 {
 193         int timediff;
 194         int bdus8 = bc->baud_us >> 3;
 195         int bdus4 = bc->baud_us >> 2;
 196         int bdus2 = bc->baud_us >> 1;
 197 
 198         timediff = 1000000 + ts->tv_nsec / NSEC_PER_USEC -
 199                                         bc->modem.ser12.pll_time;
 200         while (timediff >= 500000)
 201                 timediff -= 1000000;
 202         while (timediff >= bdus2) {
 203                 timediff -= bc->baud_us;
 204                 bc->modem.ser12.pll_time += bc->baud_us;
 205                 bc->modem.ser12.dcd_time--;
 206                 /* first check if there is room to add a bit */
 207                 if (bc->modem.shreg & 1) {
 208                         hdlcdrv_putbits(&bc->hdrv, (bc->modem.shreg >> 1) ^ 0xffff);
 209                         bc->modem.shreg = 0x10000;
 210                 }
 211                 /* add a one bit */
 212                 bc->modem.shreg >>= 1;
 213         }
 214         if (bc->modem.ser12.dcd_time <= 0) {
 215                 if (!bc->opt_dcd)
 216                         hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 + 
 217                                                    bc->modem.ser12.dcd_sum1 + 
 218                                                    bc->modem.ser12.dcd_sum2) < 0);
 219                 bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1;
 220                 bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0;
 221                 bc->modem.ser12.dcd_sum0 = 2; /* slight bias */
 222                 bc->modem.ser12.dcd_time += 120;
 223         }
 224         if (bc->modem.ser12.last_rxbit != curs) {
 225                 bc->modem.ser12.last_rxbit = curs;
 226                 bc->modem.shreg |= 0x10000;
 227                 /* adjust the PLL */
 228                 if (timediff > 0)
 229                         bc->modem.ser12.pll_time += bdus8;
 230                 else
 231                         bc->modem.ser12.pll_time += 1000000 - bdus8;
 232                 /* update DCD */
 233                 if (abs(timediff) > bdus4)
 234                         bc->modem.ser12.dcd_sum0 += 4;
 235                 else
 236                         bc->modem.ser12.dcd_sum0--;
 237 #ifdef BAYCOM_DEBUG
 238                 bc->debug_vals.cur_pllcorr = timediff;
 239 #endif /* BAYCOM_DEBUG */
 240         }
 241         while (bc->modem.ser12.pll_time >= 1000000)
 242                 bc->modem.ser12.pll_time -= 1000000;
 243 }
 244 
 245 /* --------------------------------------------------------------------- */
 246 
 247 static irqreturn_t ser12_interrupt(int irq, void *dev_id)
 248 {
 249         struct net_device *dev = (struct net_device *)dev_id;
 250         struct baycom_state *bc = netdev_priv(dev);
 251         struct timespec64 ts;
 252         unsigned char iir, msr;
 253         unsigned int txcount = 0;
 254 
 255         if (!bc || bc->hdrv.magic != HDLCDRV_MAGIC)
 256                 return IRQ_NONE;
 257         /* fast way out for shared irq */
 258         if ((iir = inb(IIR(dev->base_addr))) & 1)       
 259                 return IRQ_NONE;
 260         /* get current time */
 261         ktime_get_ts64(&ts);
 262         msr = inb(MSR(dev->base_addr));
 263         /* delta DCD */
 264         if ((msr & 8) && bc->opt_dcd)
 265                 hdlcdrv_setdcd(&bc->hdrv, !((msr ^ bc->opt_dcd) & 0x80));
 266         do {
 267                 switch (iir & 6) {
 268                 case 6:
 269                         inb(LSR(dev->base_addr));
 270                         break;
 271                         
 272                 case 4:
 273                         inb(RBR(dev->base_addr));
 274                         break;
 275                         
 276                 case 2:
 277                         /*
 278                          * make sure the next interrupt is generated;
 279                          * 0 must be used to power the modem; the modem draws its
 280                          * power from the TxD line
 281                          */
 282                         outb(0x00, THR(dev->base_addr));
 283                         baycom_int_freq(bc);
 284                         txcount++;
 285                         /*
 286                          * first output the last bit (!) then call HDLC transmitter,
 287                          * since this may take quite long
 288                          */
 289                         if (bc->modem.ptt)
 290                                 outb(0x0e | (!!bc->modem.ser12.tx_bit), MCR(dev->base_addr));
 291                         else
 292                                 outb(0x0d, MCR(dev->base_addr));       /* transmitter off */
 293                         break;
 294                         
 295                 default:
 296                         msr = inb(MSR(dev->base_addr));
 297                         /* delta DCD */
 298                         if ((msr & 8) && bc->opt_dcd) 
 299                                 hdlcdrv_setdcd(&bc->hdrv, !((msr ^ bc->opt_dcd) & 0x80));
 300                         break;
 301                 }
 302                 iir = inb(IIR(dev->base_addr));
 303         } while (!(iir & 1));
 304         ser12_rx(dev, bc, &ts, msr & 0x10); /* CTS */
 305         if (bc->modem.ptt && txcount) {
 306                 if (bc->modem.ser12.txshreg <= 1) {
 307                         bc->modem.ser12.txshreg = 0x10000 | hdlcdrv_getbits(&bc->hdrv);
 308                         if (!hdlcdrv_ptt(&bc->hdrv)) {
 309                                 ser12_set_divisor(dev, 115200/100/8);
 310                                 bc->modem.ptt = 0;
 311                                 goto end_transmit;
 312                         }
 313                 }
 314                 bc->modem.ser12.tx_bit = !(bc->modem.ser12.tx_bit ^ (bc->modem.ser12.txshreg & 1));
 315                 bc->modem.ser12.txshreg >>= 1;
 316         }
 317  end_transmit:
 318         local_irq_enable();
 319         if (!bc->modem.ptt && txcount) {
 320                 hdlcdrv_arbitrate(dev, &bc->hdrv);
 321                 if (hdlcdrv_ptt(&bc->hdrv)) {
 322                         ser12_set_divisor(dev, bc->baud_uartdiv);
 323                         bc->modem.ser12.txshreg = 1;
 324                         bc->modem.ptt = 1;
 325                 }
 326         }
 327         hdlcdrv_transmitter(dev, &bc->hdrv);
 328         hdlcdrv_receiver(dev, &bc->hdrv);
 329         local_irq_disable();
 330         return IRQ_HANDLED;
 331 }
 332 
 333 /* --------------------------------------------------------------------- */
 334 
 335 enum uart { c_uart_unknown, c_uart_8250,
 336             c_uart_16450, c_uart_16550, c_uart_16550A};
 337 static const char *uart_str[] = { 
 338         "unknown", "8250", "16450", "16550", "16550A" 
 339 };
 340 
 341 static enum uart ser12_check_uart(unsigned int iobase)
 342 {
 343         unsigned char b1,b2,b3;
 344         enum uart u;
 345         enum uart uart_tab[] =
 346                 { c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A };
 347 
 348         b1 = inb(MCR(iobase));
 349         outb(b1 | 0x10, MCR(iobase));   /* loopback mode */
 350         b2 = inb(MSR(iobase));
 351         outb(0x1a, MCR(iobase));
 352         b3 = inb(MSR(iobase)) & 0xf0;
 353         outb(b1, MCR(iobase));                  /* restore old values */
 354         outb(b2, MSR(iobase));
 355         if (b3 != 0x90)
 356                 return c_uart_unknown;
 357         inb(RBR(iobase));
 358         inb(RBR(iobase));
 359         outb(0x01, FCR(iobase));                /* enable FIFOs */
 360         u = uart_tab[(inb(IIR(iobase)) >> 6) & 3];
 361         if (u == c_uart_16450) {
 362                 outb(0x5a, SCR(iobase));
 363                 b1 = inb(SCR(iobase));
 364                 outb(0xa5, SCR(iobase));
 365                 b2 = inb(SCR(iobase));
 366                 if ((b1 != 0x5a) || (b2 != 0xa5))
 367                         u = c_uart_8250;
 368         }
 369         return u;
 370 }
 371 
 372 /* --------------------------------------------------------------------- */
 373 
 374 static int ser12_open(struct net_device *dev)
 375 {
 376         struct baycom_state *bc = netdev_priv(dev);
 377         enum uart u;
 378 
 379         if (!dev || !bc)
 380                 return -ENXIO;
 381         if (!dev->base_addr || dev->base_addr > 0xffff-SER12_EXTENT ||
 382             dev->irq < 2 || dev->irq > nr_irqs) {
 383                 printk(KERN_INFO "baycom_ser_fdx: invalid portnumber (max %u) "
 384                                 "or irq (2 <= irq <= %d)\n",
 385                                 0xffff-SER12_EXTENT, nr_irqs);
 386                 return -ENXIO;
 387         }
 388         if (bc->baud < 300 || bc->baud > 4800) {
 389                 printk(KERN_INFO "baycom_ser_fdx: invalid baudrate "
 390                                 "(300...4800)\n");
 391                 return -EINVAL;
 392         }
 393         if (!request_region(dev->base_addr, SER12_EXTENT, "baycom_ser_fdx")) {
 394                 printk(KERN_WARNING "BAYCOM_SER_FSX: I/O port 0x%04lx busy\n",
 395                        dev->base_addr);
 396                 return -EACCES;
 397         }
 398         memset(&bc->modem, 0, sizeof(bc->modem));
 399         bc->hdrv.par.bitrate = bc->baud;
 400         bc->baud_us = 1000000/bc->baud;
 401         bc->baud_uartdiv = (115200/8)/bc->baud;
 402         if ((u = ser12_check_uart(dev->base_addr)) == c_uart_unknown){
 403                 release_region(dev->base_addr, SER12_EXTENT);
 404                 return -EIO;
 405         }
 406         outb(0, FCR(dev->base_addr));  /* disable FIFOs */
 407         outb(0x0d, MCR(dev->base_addr));
 408         outb(0, IER(dev->base_addr));
 409         if (request_irq(dev->irq, ser12_interrupt, IRQF_SHARED,
 410                         "baycom_ser_fdx", dev)) {
 411                 release_region(dev->base_addr, SER12_EXTENT);
 412                 return -EBUSY;
 413         }
 414         /*
 415          * set the SIO to 6 Bits/character; during receive,
 416          * the baud rate is set to produce 100 ints/sec
 417          * to feed the channel arbitration process,
 418          * during transmit to baud ints/sec to run
 419          * the transmitter
 420          */
 421         ser12_set_divisor(dev, 115200/100/8);
 422         /*
 423          * enable transmitter empty interrupt and modem status interrupt
 424          */
 425         outb(0x0a, IER(dev->base_addr));
 426         /*
 427          * make sure the next interrupt is generated;
 428          * 0 must be used to power the modem; the modem draws its
 429          * power from the TxD line
 430          */
 431         outb(0x00, THR(dev->base_addr));
 432         hdlcdrv_setdcd(&bc->hdrv, 0);
 433         printk(KERN_INFO "%s: ser_fdx at iobase 0x%lx irq %u baud %u uart %s\n",
 434                bc_drvname, dev->base_addr, dev->irq, bc->baud, uart_str[u]);
 435         return 0;
 436 }
 437 
 438 /* --------------------------------------------------------------------- */
 439 
 440 static int ser12_close(struct net_device *dev)
 441 {
 442         struct baycom_state *bc = netdev_priv(dev);
 443 
 444         if (!dev || !bc)
 445                 return -EINVAL;
 446         /*
 447          * disable interrupts
 448          */
 449         outb(0, IER(dev->base_addr));
 450         outb(1, MCR(dev->base_addr));
 451         free_irq(dev->irq, dev);
 452         release_region(dev->base_addr, SER12_EXTENT);
 453         printk(KERN_INFO "%s: close ser_fdx at iobase 0x%lx irq %u\n",
 454                bc_drvname, dev->base_addr, dev->irq);
 455         return 0;
 456 }
 457 
 458 /* --------------------------------------------------------------------- */
 459 /*
 460  * ===================== hdlcdrv driver interface =========================
 461  */
 462 
 463 /* --------------------------------------------------------------------- */
 464 
 465 static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr,
 466                         struct hdlcdrv_ioctl *hi, int cmd);
 467 
 468 /* --------------------------------------------------------------------- */
 469 
 470 static const struct hdlcdrv_ops ser12_ops = {
 471         .drvname = bc_drvname,
 472         .drvinfo = bc_drvinfo,
 473         .open    = ser12_open,
 474         .close   = ser12_close,
 475         .ioctl   = baycom_ioctl,
 476 };
 477 
 478 /* --------------------------------------------------------------------- */
 479 
 480 static int baycom_setmode(struct baycom_state *bc, const char *modestr)
 481 {
 482         unsigned int baud;
 483 
 484         if (!strncmp(modestr, "ser", 3)) {
 485                 baud = simple_strtoul(modestr+3, NULL, 10);
 486                 if (baud >= 3 && baud <= 48)
 487                         bc->baud = baud*100;
 488         }
 489         if (strchr(modestr, '*'))
 490                 bc->opt_dcd = 0;
 491         else if (strchr(modestr, '+'))
 492                 bc->opt_dcd = -1;
 493         else
 494                 bc->opt_dcd = 1;
 495         return 0;
 496 }
 497 
 498 /* --------------------------------------------------------------------- */
 499 
 500 static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr,
 501                         struct hdlcdrv_ioctl *hi, int cmd)
 502 {
 503         struct baycom_state *bc;
 504         struct baycom_ioctl bi;
 505 
 506         if (!dev)
 507                 return -EINVAL;
 508 
 509         bc = netdev_priv(dev);
 510         BUG_ON(bc->hdrv.magic != HDLCDRV_MAGIC);
 511 
 512         if (cmd != SIOCDEVPRIVATE)
 513                 return -ENOIOCTLCMD;
 514         switch (hi->cmd) {
 515         default:
 516                 break;
 517 
 518         case HDLCDRVCTL_GETMODE:
 519                 sprintf(hi->data.modename, "ser%u", bc->baud / 100);
 520                 if (bc->opt_dcd <= 0)
 521                         strcat(hi->data.modename, (!bc->opt_dcd) ? "*" : "+");
 522                 if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl)))
 523                         return -EFAULT;
 524                 return 0;
 525 
 526         case HDLCDRVCTL_SETMODE:
 527                 if (netif_running(dev) || !capable(CAP_NET_ADMIN))
 528                         return -EACCES;
 529                 hi->data.modename[sizeof(hi->data.modename)-1] = '\0';
 530                 return baycom_setmode(bc, hi->data.modename);
 531 
 532         case HDLCDRVCTL_MODELIST:
 533                 strcpy(hi->data.modename, "ser12,ser3,ser24");
 534                 if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl)))
 535                         return -EFAULT;
 536                 return 0;
 537 
 538         case HDLCDRVCTL_MODEMPARMASK:
 539                 return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ;
 540 
 541         }
 542 
 543         if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi)))
 544                 return -EFAULT;
 545         switch (bi.cmd) {
 546         default:
 547                 return -ENOIOCTLCMD;
 548 
 549 #ifdef BAYCOM_DEBUG
 550         case BAYCOMCTL_GETDEBUG:
 551                 bi.data.dbg.debug1 = bc->hdrv.ptt_keyed;
 552                 bi.data.dbg.debug2 = bc->debug_vals.last_intcnt;
 553                 bi.data.dbg.debug3 = bc->debug_vals.last_pllcorr;
 554                 break;
 555 #endif /* BAYCOM_DEBUG */
 556 
 557         }
 558         if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi)))
 559                 return -EFAULT;
 560         return 0;
 561 
 562 }
 563 
 564 /* --------------------------------------------------------------------- */
 565 
 566 /*
 567  * command line settable parameters
 568  */
 569 static char *mode[NR_PORTS] = { "ser12*", };
 570 static int iobase[NR_PORTS] = { 0x3f8, };
 571 static int irq[NR_PORTS] = { 4, };
 572 static int baud[NR_PORTS] = { [0 ... NR_PORTS-1] = 1200 };
 573 
 574 module_param_array(mode, charp, NULL, 0);
 575 MODULE_PARM_DESC(mode, "baycom operating mode; * for software DCD");
 576 module_param_hw_array(iobase, int, ioport, NULL, 0);
 577 MODULE_PARM_DESC(iobase, "baycom io base address");
 578 module_param_hw_array(irq, int, irq, NULL, 0);
 579 MODULE_PARM_DESC(irq, "baycom irq number");
 580 module_param_array(baud, int, NULL, 0);
 581 MODULE_PARM_DESC(baud, "baycom baud rate (300 to 4800)");
 582 
 583 MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
 584 MODULE_DESCRIPTION("Baycom ser12 full duplex amateur radio modem driver");
 585 MODULE_LICENSE("GPL");
 586 
 587 /* --------------------------------------------------------------------- */
 588 
 589 static int __init init_baycomserfdx(void)
 590 {
 591         int i, found = 0;
 592         char set_hw = 1;
 593 
 594         printk(bc_drvinfo);
 595         /*
 596          * register net devices
 597          */
 598         for (i = 0; i < NR_PORTS; i++) {
 599                 struct net_device *dev;
 600                 struct baycom_state *bc;
 601                 char ifname[IFNAMSIZ];
 602 
 603                 sprintf(ifname, "bcsf%d", i);
 604 
 605                 if (!mode[i])
 606                         set_hw = 0;
 607                 if (!set_hw)
 608                         iobase[i] = irq[i] = 0;
 609 
 610                 dev = hdlcdrv_register(&ser12_ops, 
 611                                        sizeof(struct baycom_state),
 612                                        ifname, iobase[i], irq[i], 0);
 613                 if (IS_ERR(dev)) 
 614                         break;
 615 
 616                 bc = netdev_priv(dev);
 617                 if (set_hw && baycom_setmode(bc, mode[i]))
 618                         set_hw = 0;
 619                 bc->baud = baud[i];
 620                 found++;
 621                 baycom_device[i] = dev;
 622         }
 623 
 624         if (!found)
 625                 return -ENXIO;
 626         return 0;
 627 }
 628 
 629 static void __exit cleanup_baycomserfdx(void)
 630 {
 631         int i;
 632 
 633         for(i = 0; i < NR_PORTS; i++) {
 634                 struct net_device *dev = baycom_device[i];
 635                 if (dev) 
 636                         hdlcdrv_unregister(dev);
 637         }
 638 }
 639 
 640 module_init(init_baycomserfdx);
 641 module_exit(cleanup_baycomserfdx);
 642 
 643 /* --------------------------------------------------------------------- */
 644 
 645 #ifndef MODULE
 646 
 647 /*
 648  * format: baycom_ser_fdx=io,irq,mode
 649  * mode: ser#    hardware DCD
 650  *       ser#*   software DCD
 651  *       ser#+   hardware DCD, inverted signal at DCD pin
 652  * '#' denotes the baud rate / 100, eg. ser12* is '1200 baud, soft DCD'
 653  */
 654 
 655 static int __init baycom_ser_fdx_setup(char *str)
 656 {
 657         static unsigned nr_dev;
 658         int ints[4];
 659 
 660         if (nr_dev >= NR_PORTS)
 661                 return 0;
 662         str = get_options(str, 4, ints);
 663         if (ints[0] < 2)
 664                 return 0;
 665         mode[nr_dev] = str;
 666         iobase[nr_dev] = ints[1];
 667         irq[nr_dev] = ints[2];
 668         if (ints[0] >= 3)
 669                 baud[nr_dev] = ints[3];
 670         nr_dev++;
 671         return 1;
 672 }
 673 
 674 __setup("baycom_ser_fdx=", baycom_ser_fdx_setup);
 675 
 676 #endif /* MODULE */
 677 /* --------------------------------------------------------------------- */

/* [<][>][^][v][top][bottom][index][help] */