Import 2.3.10pre5
[davej-history.git] / drivers / net / hamradio / baycom_ser_hdx.c
blob20681a134c0dfa5865098d0d68c10d0b9fbe7f75
1 /*****************************************************************************/
3 /*
4 * baycom_ser_hdx.c -- baycom ser12 halfduplex radio modem driver.
6 * Copyright (C) 1997 Thomas Sailer (sailer@ife.ee.ethz.ch)
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.
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.
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.
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.
27 * Supported modems
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)
38 * Command line options (insmod command line)
40 * mode * enables software DCD.
41 * iobase base address of the port; common values are 0x3f8, 0x2f8, 0x3e8, 0x2e8
42 * irq interrupt line of the port; common values are 4,3
45 * History:
46 * 0.1 26.06.96 Adapted from baycom.c and made network driver interface
47 * 18.10.96 Changed to new user space access routines (copy_{to,from}_user)
48 * 0.3 26.04.97 init code/data tagged
49 * 0.4 08.07.97 alternative ser12 decoding algorithm (uses delta CTS ints)
50 * 0.5 11.11.97 ser12/par96 split into separate files
51 * 0.6 14.04.98 cleanups
54 /*****************************************************************************/
56 #include <linux/module.h>
57 #include <linux/kernel.h>
58 #include <linux/sched.h>
59 #include <linux/types.h>
60 #include <linux/fcntl.h>
61 #include <linux/interrupt.h>
62 #include <linux/ioport.h>
63 #include <linux/in.h>
64 #include <linux/string.h>
65 #include <linux/init.h>
66 #include <asm/uaccess.h>
67 #include <asm/system.h>
68 #include <asm/bitops.h>
69 #include <asm/io.h>
70 #include <linux/delay.h>
71 #include <linux/errno.h>
72 #include <linux/netdevice.h>
73 #include <linux/hdlcdrv.h>
74 #include <linux/baycom.h>
75 #include <linux/version.h>
77 /* --------------------------------------------------------------------- */
79 #define BAYCOM_DEBUG
82 * modem options; bit mask
84 #define BAYCOM_OPTIONS_SOFTDCD 1
86 /* --------------------------------------------------------------------- */
88 static const char bc_drvname[] = "baycom_ser_hdx";
89 static const char bc_drvinfo[] = KERN_INFO "baycom_ser_hdx: (C) 1997-1998 Thomas Sailer, HB9JNX/AE4WA\n"
90 KERN_INFO "baycom_ser_hdx: version 0.6 compiled " __TIME__ " " __DATE__ "\n";
92 /* --------------------------------------------------------------------- */
94 #define NR_PORTS 4
96 static struct device baycom_device[NR_PORTS];
98 static struct {
99 char *mode;
100 int iobase, irq;
101 } baycom_ports[NR_PORTS] = { { NULL, 0, 0 }, };
103 /* --------------------------------------------------------------------- */
105 #define RBR(iobase) (iobase+0)
106 #define THR(iobase) (iobase+0)
107 #define IER(iobase) (iobase+1)
108 #define IIR(iobase) (iobase+2)
109 #define FCR(iobase) (iobase+2)
110 #define LCR(iobase) (iobase+3)
111 #define MCR(iobase) (iobase+4)
112 #define LSR(iobase) (iobase+5)
113 #define MSR(iobase) (iobase+6)
114 #define SCR(iobase) (iobase+7)
115 #define DLL(iobase) (iobase+0)
116 #define DLM(iobase) (iobase+1)
118 #define SER12_EXTENT 8
120 /* ---------------------------------------------------------------------- */
122 * Information that need to be kept for each board.
125 struct baycom_state {
126 struct hdlcdrv_state hdrv;
128 unsigned int options;
130 struct modem_state {
131 short arb_divider;
132 unsigned char flags;
133 unsigned int shreg;
134 struct modem_state_ser12 {
135 unsigned char tx_bit;
136 int dcd_sum0, dcd_sum1, dcd_sum2;
137 unsigned char last_sample;
138 unsigned char last_rxbit;
139 unsigned int dcd_shreg;
140 unsigned int dcd_time;
141 unsigned int bit_pll;
142 unsigned char interm_sample;
143 } ser12;
144 } modem;
146 #ifdef BAYCOM_DEBUG
147 struct debug_vals {
148 unsigned long last_jiffies;
149 unsigned cur_intcnt;
150 unsigned last_intcnt;
151 int cur_pllcorr;
152 int last_pllcorr;
153 } debug_vals;
154 #endif /* BAYCOM_DEBUG */
157 /* --------------------------------------------------------------------- */
159 #define min(a, b) (((a) < (b)) ? (a) : (b))
160 #define max(a, b) (((a) > (b)) ? (a) : (b))
162 /* --------------------------------------------------------------------- */
164 static void inline baycom_int_freq(struct baycom_state *bc)
166 #ifdef BAYCOM_DEBUG
167 unsigned long cur_jiffies = jiffies;
169 * measure the interrupt frequency
171 bc->debug_vals.cur_intcnt++;
172 if ((cur_jiffies - bc->debug_vals.last_jiffies) >= HZ) {
173 bc->debug_vals.last_jiffies = cur_jiffies;
174 bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt;
175 bc->debug_vals.cur_intcnt = 0;
176 bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr;
177 bc->debug_vals.cur_pllcorr = 0;
179 #endif /* BAYCOM_DEBUG */
182 /* --------------------------------------------------------------------- */
184 * ===================== SER12 specific routines =========================
187 static void inline ser12_set_divisor(struct device *dev,
188 unsigned char divisor)
190 outb(0x81, LCR(dev->base_addr)); /* DLAB = 1 */
191 outb(divisor, DLL(dev->base_addr));
192 outb(0, DLM(dev->base_addr));
193 outb(0x01, LCR(dev->base_addr)); /* word length = 6 */
195 * make sure the next interrupt is generated;
196 * 0 must be used to power the modem; the modem draws its
197 * power from the TxD line
199 outb(0x00, THR(dev->base_addr));
201 * it is important not to set the divider while transmitting;
202 * this reportedly makes some UARTs generating interrupts
203 * in the hundredthousands per second region
204 * Reported by: Ignacio.Arenaza@studi.epfl.ch (Ignacio Arenaza Nuno)
208 /* --------------------------------------------------------------------- */
211 * must call the TX arbitrator every 10ms
213 #define SER12_ARB_DIVIDER(bc) ((bc->options & BAYCOM_OPTIONS_SOFTDCD) ? \
214 36 : 24)
215 #define SER12_DCD_INTERVAL(bc) ((bc->options & BAYCOM_OPTIONS_SOFTDCD) ? \
216 240 : 12)
218 static inline void ser12_tx(struct device *dev, struct baycom_state *bc)
220 /* one interrupt per channel bit */
221 ser12_set_divisor(dev, 12);
223 * first output the last bit (!) then call HDLC transmitter,
224 * since this may take quite long
226 outb(0x0e | (!!bc->modem.ser12.tx_bit), MCR(dev->base_addr));
227 if (bc->modem.shreg <= 1)
228 bc->modem.shreg = 0x10000 | hdlcdrv_getbits(&bc->hdrv);
229 bc->modem.ser12.tx_bit = !(bc->modem.ser12.tx_bit ^
230 (bc->modem.shreg & 1));
231 bc->modem.shreg >>= 1;
234 /* --------------------------------------------------------------------- */
236 static inline void ser12_rx(struct device *dev, struct baycom_state *bc)
238 unsigned char cur_s;
240 * do demodulator
242 cur_s = inb(MSR(dev->base_addr)) & 0x10; /* the CTS line */
243 hdlcdrv_channelbit(&bc->hdrv, cur_s);
244 bc->modem.ser12.dcd_shreg = (bc->modem.ser12.dcd_shreg << 1) |
245 (cur_s != bc->modem.ser12.last_sample);
246 bc->modem.ser12.last_sample = cur_s;
247 if(bc->modem.ser12.dcd_shreg & 1) {
248 if (bc->options & BAYCOM_OPTIONS_SOFTDCD) {
249 unsigned int dcdspos, dcdsneg;
251 dcdspos = dcdsneg = 0;
252 dcdspos += ((bc->modem.ser12.dcd_shreg >> 1) & 1);
253 if (!(bc->modem.ser12.dcd_shreg & 0x7ffffffe))
254 dcdspos += 2;
255 dcdsneg += ((bc->modem.ser12.dcd_shreg >> 2) & 1);
256 dcdsneg += ((bc->modem.ser12.dcd_shreg >> 3) & 1);
257 dcdsneg += ((bc->modem.ser12.dcd_shreg >> 4) & 1);
259 bc->modem.ser12.dcd_sum0 += 16*dcdspos - dcdsneg;
260 } else
261 bc->modem.ser12.dcd_sum0--;
263 if(!bc->modem.ser12.dcd_time) {
264 hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 +
265 bc->modem.ser12.dcd_sum1 +
266 bc->modem.ser12.dcd_sum2) < 0);
267 bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1;
268 bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0;
269 /* offset to ensure DCD off on silent input */
270 bc->modem.ser12.dcd_sum0 = 2;
271 bc->modem.ser12.dcd_time = SER12_DCD_INTERVAL(bc);
273 bc->modem.ser12.dcd_time--;
274 if (bc->options & BAYCOM_OPTIONS_SOFTDCD) {
276 * PLL code for the improved software DCD algorithm
278 if (bc->modem.ser12.interm_sample) {
280 * intermediate sample; set timing correction to normal
282 ser12_set_divisor(dev, 4);
283 } else {
285 * do PLL correction and call HDLC receiver
287 switch (bc->modem.ser12.dcd_shreg & 7) {
288 case 1: /* transition too late */
289 ser12_set_divisor(dev, 5);
290 #ifdef BAYCOM_DEBUG
291 bc->debug_vals.cur_pllcorr++;
292 #endif /* BAYCOM_DEBUG */
293 break;
294 case 4: /* transition too early */
295 ser12_set_divisor(dev, 3);
296 #ifdef BAYCOM_DEBUG
297 bc->debug_vals.cur_pllcorr--;
298 #endif /* BAYCOM_DEBUG */
299 break;
300 default:
301 ser12_set_divisor(dev, 4);
302 break;
304 bc->modem.shreg >>= 1;
305 if (bc->modem.ser12.last_sample ==
306 bc->modem.ser12.last_rxbit)
307 bc->modem.shreg |= 0x10000;
308 bc->modem.ser12.last_rxbit =
309 bc->modem.ser12.last_sample;
311 if (++bc->modem.ser12.interm_sample >= 3)
312 bc->modem.ser12.interm_sample = 0;
314 * DCD stuff
316 if (bc->modem.ser12.dcd_shreg & 1) {
317 unsigned int dcdspos, dcdsneg;
319 dcdspos = dcdsneg = 0;
320 dcdspos += ((bc->modem.ser12.dcd_shreg >> 1) & 1);
321 dcdspos += (!(bc->modem.ser12.dcd_shreg & 0x7ffffffe))
322 << 1;
323 dcdsneg += ((bc->modem.ser12.dcd_shreg >> 2) & 1);
324 dcdsneg += ((bc->modem.ser12.dcd_shreg >> 3) & 1);
325 dcdsneg += ((bc->modem.ser12.dcd_shreg >> 4) & 1);
327 bc->modem.ser12.dcd_sum0 += 16*dcdspos - dcdsneg;
329 } else {
331 * PLL algorithm for the hardware squelch DCD algorithm
333 if (bc->modem.ser12.interm_sample) {
335 * intermediate sample; set timing correction to normal
337 ser12_set_divisor(dev, 6);
338 } else {
340 * do PLL correction and call HDLC receiver
342 switch (bc->modem.ser12.dcd_shreg & 3) {
343 case 1: /* transition too late */
344 ser12_set_divisor(dev, 7);
345 #ifdef BAYCOM_DEBUG
346 bc->debug_vals.cur_pllcorr++;
347 #endif /* BAYCOM_DEBUG */
348 break;
349 case 2: /* transition too early */
350 ser12_set_divisor(dev, 5);
351 #ifdef BAYCOM_DEBUG
352 bc->debug_vals.cur_pllcorr--;
353 #endif /* BAYCOM_DEBUG */
354 break;
355 default:
356 ser12_set_divisor(dev, 6);
357 break;
359 bc->modem.shreg >>= 1;
360 if (bc->modem.ser12.last_sample ==
361 bc->modem.ser12.last_rxbit)
362 bc->modem.shreg |= 0x10000;
363 bc->modem.ser12.last_rxbit =
364 bc->modem.ser12.last_sample;
366 bc->modem.ser12.interm_sample = !bc->modem.ser12.interm_sample;
368 * DCD stuff
370 bc->modem.ser12.dcd_sum0 -= (bc->modem.ser12.dcd_shreg & 1);
372 outb(0x0d, MCR(dev->base_addr)); /* transmitter off */
373 if (bc->modem.shreg & 1) {
374 hdlcdrv_putbits(&bc->hdrv, bc->modem.shreg >> 1);
375 bc->modem.shreg = 0x10000;
377 if(!bc->modem.ser12.dcd_time) {
378 hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 +
379 bc->modem.ser12.dcd_sum1 +
380 bc->modem.ser12.dcd_sum2) < 0);
381 bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1;
382 bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0;
383 /* offset to ensure DCD off on silent input */
384 bc->modem.ser12.dcd_sum0 = 2;
385 bc->modem.ser12.dcd_time = SER12_DCD_INTERVAL(bc);
387 bc->modem.ser12.dcd_time--;
390 /* --------------------------------------------------------------------- */
392 static void ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs)
394 struct device *dev = (struct device *)dev_id;
395 struct baycom_state *bc = (struct baycom_state *)dev->priv;
396 unsigned char iir;
398 if (!dev || !bc || bc->hdrv.magic != HDLCDRV_MAGIC)
399 return;
400 /* fast way out */
401 if ((iir = inb(IIR(dev->base_addr))) & 1)
402 return;
403 baycom_int_freq(bc);
404 do {
405 switch (iir & 6) {
406 case 6:
407 inb(LSR(dev->base_addr));
408 break;
410 case 4:
411 inb(RBR(dev->base_addr));
412 break;
414 case 2:
416 * check if transmitter active
418 if (hdlcdrv_ptt(&bc->hdrv))
419 ser12_tx(dev, bc);
420 else {
421 ser12_rx(dev, bc);
422 bc->modem.arb_divider--;
424 outb(0x00, THR(dev->base_addr));
425 break;
427 default:
428 inb(MSR(dev->base_addr));
429 break;
431 iir = inb(IIR(dev->base_addr));
432 } while (!(iir & 1));
433 if (bc->modem.arb_divider <= 0) {
434 bc->modem.arb_divider = SER12_ARB_DIVIDER(bc);
435 __sti();
436 hdlcdrv_arbitrate(dev, &bc->hdrv);
438 __sti();
439 hdlcdrv_transmitter(dev, &bc->hdrv);
440 hdlcdrv_receiver(dev, &bc->hdrv);
441 __cli();
444 /* --------------------------------------------------------------------- */
446 enum uart { c_uart_unknown, c_uart_8250,
447 c_uart_16450, c_uart_16550, c_uart_16550A};
448 static const char *uart_str[] = {
449 "unknown", "8250", "16450", "16550", "16550A"
452 static enum uart ser12_check_uart(unsigned int iobase)
454 unsigned char b1,b2,b3;
455 enum uart u;
456 enum uart uart_tab[] =
457 { c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A };
459 b1 = inb(MCR(iobase));
460 outb(b1 | 0x10, MCR(iobase)); /* loopback mode */
461 b2 = inb(MSR(iobase));
462 outb(0x1a, MCR(iobase));
463 b3 = inb(MSR(iobase)) & 0xf0;
464 outb(b1, MCR(iobase)); /* restore old values */
465 outb(b2, MSR(iobase));
466 if (b3 != 0x90)
467 return c_uart_unknown;
468 inb(RBR(iobase));
469 inb(RBR(iobase));
470 outb(0x01, FCR(iobase)); /* enable FIFOs */
471 u = uart_tab[(inb(IIR(iobase)) >> 6) & 3];
472 if (u == c_uart_16450) {
473 outb(0x5a, SCR(iobase));
474 b1 = inb(SCR(iobase));
475 outb(0xa5, SCR(iobase));
476 b2 = inb(SCR(iobase));
477 if ((b1 != 0x5a) || (b2 != 0xa5))
478 u = c_uart_8250;
480 return u;
483 /* --------------------------------------------------------------------- */
485 static int ser12_open(struct device *dev)
487 struct baycom_state *bc = (struct baycom_state *)dev->priv;
488 enum uart u;
490 if (!dev || !bc)
491 return -ENXIO;
492 if (!dev->base_addr || dev->base_addr > 0x1000-SER12_EXTENT ||
493 dev->irq < 2 || dev->irq > 15)
494 return -ENXIO;
495 if (check_region(dev->base_addr, SER12_EXTENT))
496 return -EACCES;
497 memset(&bc->modem, 0, sizeof(bc->modem));
498 bc->hdrv.par.bitrate = 1200;
499 if ((u = ser12_check_uart(dev->base_addr)) == c_uart_unknown)
500 return -EIO;
501 outb(0, FCR(dev->base_addr)); /* disable FIFOs */
502 outb(0x0d, MCR(dev->base_addr));
503 outb(0, IER(dev->base_addr));
504 if (request_irq(dev->irq, ser12_interrupt, SA_INTERRUPT | SA_SHIRQ,
505 "baycom_ser12", dev))
506 return -EBUSY;
507 request_region(dev->base_addr, SER12_EXTENT, "baycom_ser12");
509 * enable transmitter empty interrupt
511 outb(2, IER(dev->base_addr));
513 * set the SIO to 6 Bits/character and 19200 or 28800 baud, so that
514 * we get exactly (hopefully) 2 or 3 interrupts per radio symbol,
515 * depending on the usage of the software DCD routine
517 ser12_set_divisor(dev, (bc->options & BAYCOM_OPTIONS_SOFTDCD) ? 4 : 6);
518 printk(KERN_INFO "%s: ser12 at iobase 0x%lx irq %u options "
519 "0x%x uart %s\n", bc_drvname, dev->base_addr, dev->irq,
520 bc->options, uart_str[u]);
521 MOD_INC_USE_COUNT;
522 return 0;
525 /* --------------------------------------------------------------------- */
527 static int ser12_close(struct device *dev)
529 struct baycom_state *bc = (struct baycom_state *)dev->priv;
531 if (!dev || !bc)
532 return -EINVAL;
534 * disable interrupts
536 outb(0, IER(dev->base_addr));
537 outb(1, MCR(dev->base_addr));
538 free_irq(dev->irq, dev);
539 release_region(dev->base_addr, SER12_EXTENT);
540 printk(KERN_INFO "%s: close ser12 at iobase 0x%lx irq %u\n",
541 bc_drvname, dev->base_addr, dev->irq);
542 MOD_DEC_USE_COUNT;
543 return 0;
546 /* --------------------------------------------------------------------- */
548 * ===================== hdlcdrv driver interface =========================
551 /* --------------------------------------------------------------------- */
553 static int baycom_ioctl(struct device *dev, struct ifreq *ifr,
554 struct hdlcdrv_ioctl *hi, int cmd);
556 /* --------------------------------------------------------------------- */
558 static struct hdlcdrv_ops ser12_ops = {
559 bc_drvname,
560 bc_drvinfo,
561 ser12_open,
562 ser12_close,
563 baycom_ioctl
566 /* --------------------------------------------------------------------- */
568 static int baycom_setmode(struct baycom_state *bc, const char *modestr)
570 bc->options = !!strchr(modestr, '*');
571 return 0;
574 /* --------------------------------------------------------------------- */
576 static int baycom_ioctl(struct device *dev, struct ifreq *ifr,
577 struct hdlcdrv_ioctl *hi, int cmd)
579 struct baycom_state *bc;
580 struct baycom_ioctl bi;
581 int cmd2;
583 if (!dev || !dev->priv ||
584 ((struct baycom_state *)dev->priv)->hdrv.magic != HDLCDRV_MAGIC) {
585 printk(KERN_ERR "bc_ioctl: invalid device struct\n");
586 return -EINVAL;
588 bc = (struct baycom_state *)dev->priv;
590 if (cmd != SIOCDEVPRIVATE)
591 return -ENOIOCTLCMD;
592 if (get_user(cmd2, (int *)ifr->ifr_data))
593 return -EFAULT;
594 switch (hi->cmd) {
595 default:
596 break;
598 case HDLCDRVCTL_GETMODE:
599 strcpy(hi->data.modename, "ser12");
600 if (bc->options & 1)
601 strcat(hi->data.modename, "*");
602 if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl)))
603 return -EFAULT;
604 return 0;
606 case HDLCDRVCTL_SETMODE:
607 if (dev->start || !suser())
608 return -EACCES;
609 hi->data.modename[sizeof(hi->data.modename)-1] = '\0';
610 return baycom_setmode(bc, hi->data.modename);
612 case HDLCDRVCTL_MODELIST:
613 strcpy(hi->data.modename, "ser12");
614 if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl)))
615 return -EFAULT;
616 return 0;
618 case HDLCDRVCTL_MODEMPARMASK:
619 return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ;
623 if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi)))
624 return -EFAULT;
625 switch (bi.cmd) {
626 default:
627 return -ENOIOCTLCMD;
629 #ifdef BAYCOM_DEBUG
630 case BAYCOMCTL_GETDEBUG:
631 bi.data.dbg.debug1 = bc->hdrv.ptt_keyed;
632 bi.data.dbg.debug2 = bc->debug_vals.last_intcnt;
633 bi.data.dbg.debug3 = bc->debug_vals.last_pllcorr;
634 break;
635 #endif /* BAYCOM_DEBUG */
638 if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi)))
639 return -EFAULT;
640 return 0;
644 /* --------------------------------------------------------------------- */
646 int __init baycom_ser_hdx_init(void)
648 int i, j, found = 0;
649 char set_hw = 1;
650 struct baycom_state *bc;
651 char ifname[HDLCDRV_IFNAMELEN];
654 printk(bc_drvinfo);
656 * register net devices
658 for (i = 0; i < NR_PORTS; i++) {
659 struct device *dev = baycom_device+i;
660 sprintf(ifname, "bcsh%d", i);
662 if (!baycom_ports[i].mode)
663 set_hw = 0;
664 if (!set_hw)
665 baycom_ports[i].iobase = baycom_ports[i].irq = 0;
666 j = hdlcdrv_register_hdlcdrv(dev, &ser12_ops,
667 sizeof(struct baycom_state),
668 ifname, baycom_ports[i].iobase,
669 baycom_ports[i].irq, 0);
670 if (!j) {
671 bc = (struct baycom_state *)dev->priv;
672 if (set_hw && baycom_setmode(bc, baycom_ports[i].mode))
673 set_hw = 0;
674 found++;
675 } else {
676 printk(KERN_WARNING "%s: cannot register net device\n",
677 bc_drvname);
680 if (!found)
681 return -ENXIO;
682 return 0;
685 /* --------------------------------------------------------------------- */
687 #ifdef MODULE
690 * command line settable parameters
692 static char *mode[NR_PORTS] = { "ser12*", };
693 static int iobase[NR_PORTS] = { 0x3f8, };
694 static int irq[NR_PORTS] = { 4, };
696 #if LINUX_VERSION_CODE >= 0x20115
698 MODULE_PARM(mode, "1-" __MODULE_STRING(NR_PORTS) "s");
699 MODULE_PARM_DESC(mode, "baycom operating mode; * for software DCD");
700 MODULE_PARM(iobase, "1-" __MODULE_STRING(NR_PORTS) "i");
701 MODULE_PARM_DESC(iobase, "baycom io base address");
702 MODULE_PARM(irq, "1-" __MODULE_STRING(NR_PORTS) "i");
703 MODULE_PARM_DESC(irq, "baycom irq number");
705 MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
706 MODULE_DESCRIPTION("Baycom ser12 half duplex amateur radio modem driver");
708 #endif
710 int __init init_module(void)
712 int i;
714 for (i = 0; (i < NR_PORTS) && (mode[i]); i++) {
715 baycom_ports[i].mode = mode[i];
716 baycom_ports[i].iobase = iobase[i];
717 baycom_ports[i].irq = irq[i];
719 if (i < NR_PORTS-1)
720 baycom_ports[i+1].mode = NULL;
721 return baycom_ser_hdx_init();
724 /* --------------------------------------------------------------------- */
726 void cleanup_module(void)
728 int i;
730 for(i = 0; i < NR_PORTS; i++) {
731 struct device *dev = baycom_device+i;
732 struct baycom_state *bc = (struct baycom_state *)dev->priv;
734 if (bc) {
735 if (bc->hdrv.magic != HDLCDRV_MAGIC)
736 printk(KERN_ERR "baycom: invalid magic in "
737 "cleanup_module\n");
738 else
739 hdlcdrv_unregister_hdlcdrv(dev);
744 #else /* MODULE */
745 /* --------------------------------------------------------------------- */
747 * format: baycom_ser_=io,irq,mode
748 * mode: [*]
749 * * indicates sofware DCD
752 void __init baycom_ser_hdx_setup(char *str, int *ints)
754 int i;
756 for (i = 0; (i < NR_PORTS) && (baycom_ports[i].mode); i++);
757 if ((i >= NR_PORTS) || (ints[0] < 2)) {
758 printk(KERN_INFO "%s: too many or invalid interface "
759 "specifications\n", bc_drvname);
760 return;
762 baycom_ports[i].mode = str;
763 baycom_ports[i].iobase = ints[1];
764 baycom_ports[i].irq = ints[2];
765 if (i < NR_PORTS-1)
766 baycom_ports[i+1].mode = NULL;
769 #endif /* MODULE */
770 /* --------------------------------------------------------------------- */