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, void __user *data, 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, void __user *data, 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(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(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, 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(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 /* --------------------------------------------------------------------- */ 678