0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048 #include <linux/capability.h>
0049 #include <linux/module.h>
0050 #include <linux/ioport.h>
0051 #include <linux/string.h>
0052 #include <linux/init.h>
0053 #include <linux/interrupt.h>
0054 #include <linux/uaccess.h>
0055 #include <asm/io.h>
0056 #include <linux/hdlcdrv.h>
0057 #include <linux/baycom.h>
0058 #include <linux/jiffies.h>
0059
0060
0061
0062 #define BAYCOM_DEBUG
0063
0064
0065
0066 static const char bc_drvname[] = "baycom_ser_hdx";
0067 static const char bc_drvinfo[] = KERN_INFO "baycom_ser_hdx: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4WA\n"
0068 "baycom_ser_hdx: version 0.10\n";
0069
0070
0071
0072 #define NR_PORTS 4
0073
0074 static struct net_device *baycom_device[NR_PORTS];
0075
0076
0077
0078 #define RBR(iobase) (iobase+0)
0079 #define THR(iobase) (iobase+0)
0080 #define IER(iobase) (iobase+1)
0081 #define IIR(iobase) (iobase+2)
0082 #define FCR(iobase) (iobase+2)
0083 #define LCR(iobase) (iobase+3)
0084 #define MCR(iobase) (iobase+4)
0085 #define LSR(iobase) (iobase+5)
0086 #define MSR(iobase) (iobase+6)
0087 #define SCR(iobase) (iobase+7)
0088 #define DLL(iobase) (iobase+0)
0089 #define DLM(iobase) (iobase+1)
0090
0091 #define SER12_EXTENT 8
0092
0093
0094
0095
0096
0097
0098 struct baycom_state {
0099 struct hdlcdrv_state hdrv;
0100
0101 int opt_dcd;
0102
0103 struct modem_state {
0104 short arb_divider;
0105 unsigned char flags;
0106 unsigned int shreg;
0107 struct modem_state_ser12 {
0108 unsigned char tx_bit;
0109 int dcd_sum0, dcd_sum1, dcd_sum2;
0110 unsigned char last_sample;
0111 unsigned char last_rxbit;
0112 unsigned int dcd_shreg;
0113 unsigned int dcd_time;
0114 unsigned int bit_pll;
0115 unsigned char interm_sample;
0116 } ser12;
0117 } modem;
0118
0119 #ifdef BAYCOM_DEBUG
0120 struct debug_vals {
0121 unsigned long last_jiffies;
0122 unsigned cur_intcnt;
0123 unsigned last_intcnt;
0124 int cur_pllcorr;
0125 int last_pllcorr;
0126 } debug_vals;
0127 #endif
0128 };
0129
0130
0131
0132 static inline void baycom_int_freq(struct baycom_state *bc)
0133 {
0134 #ifdef BAYCOM_DEBUG
0135 unsigned long cur_jiffies = jiffies;
0136
0137
0138
0139 bc->debug_vals.cur_intcnt++;
0140 if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) {
0141 bc->debug_vals.last_jiffies = cur_jiffies;
0142 bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt;
0143 bc->debug_vals.cur_intcnt = 0;
0144 bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr;
0145 bc->debug_vals.cur_pllcorr = 0;
0146 }
0147 #endif
0148 }
0149
0150
0151
0152
0153
0154
0155 static inline void ser12_set_divisor(struct net_device *dev,
0156 unsigned char divisor)
0157 {
0158 outb(0x81, LCR(dev->base_addr));
0159 outb(divisor, DLL(dev->base_addr));
0160 outb(0, DLM(dev->base_addr));
0161 outb(0x01, LCR(dev->base_addr));
0162
0163
0164
0165
0166
0167 outb(0x00, THR(dev->base_addr));
0168
0169
0170
0171
0172
0173
0174 }
0175
0176
0177
0178
0179
0180
0181 #define SER12_ARB_DIVIDER(bc) (bc->opt_dcd ? 24 : 36)
0182
0183 #define SER12_DCD_INTERVAL(bc) (bc->opt_dcd ? 12 : 240)
0184
0185 static inline void ser12_tx(struct net_device *dev, struct baycom_state *bc)
0186 {
0187
0188 ser12_set_divisor(dev, 12);
0189
0190
0191
0192
0193 outb(0x0e | (!!bc->modem.ser12.tx_bit), MCR(dev->base_addr));
0194 if (bc->modem.shreg <= 1)
0195 bc->modem.shreg = 0x10000 | hdlcdrv_getbits(&bc->hdrv);
0196 bc->modem.ser12.tx_bit = !(bc->modem.ser12.tx_bit ^
0197 (bc->modem.shreg & 1));
0198 bc->modem.shreg >>= 1;
0199 }
0200
0201
0202
0203 static inline void ser12_rx(struct net_device *dev, struct baycom_state *bc)
0204 {
0205 unsigned char cur_s;
0206
0207
0208
0209 cur_s = inb(MSR(dev->base_addr)) & 0x10;
0210 hdlcdrv_channelbit(&bc->hdrv, cur_s);
0211 bc->modem.ser12.dcd_shreg = (bc->modem.ser12.dcd_shreg << 1) |
0212 (cur_s != bc->modem.ser12.last_sample);
0213 bc->modem.ser12.last_sample = cur_s;
0214 if(bc->modem.ser12.dcd_shreg & 1) {
0215 if (!bc->opt_dcd) {
0216 unsigned int dcdspos, dcdsneg;
0217
0218 dcdspos = dcdsneg = 0;
0219 dcdspos += ((bc->modem.ser12.dcd_shreg >> 1) & 1);
0220 if (!(bc->modem.ser12.dcd_shreg & 0x7ffffffe))
0221 dcdspos += 2;
0222 dcdsneg += ((bc->modem.ser12.dcd_shreg >> 2) & 1);
0223 dcdsneg += ((bc->modem.ser12.dcd_shreg >> 3) & 1);
0224 dcdsneg += ((bc->modem.ser12.dcd_shreg >> 4) & 1);
0225
0226 bc->modem.ser12.dcd_sum0 += 16*dcdspos - dcdsneg;
0227 } else
0228 bc->modem.ser12.dcd_sum0--;
0229 }
0230 if(!bc->modem.ser12.dcd_time) {
0231 hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 +
0232 bc->modem.ser12.dcd_sum1 +
0233 bc->modem.ser12.dcd_sum2) < 0);
0234 bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1;
0235 bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0;
0236
0237 bc->modem.ser12.dcd_sum0 = 2;
0238 bc->modem.ser12.dcd_time = SER12_DCD_INTERVAL(bc);
0239 }
0240 bc->modem.ser12.dcd_time--;
0241 if (!bc->opt_dcd) {
0242
0243
0244
0245 if (bc->modem.ser12.interm_sample) {
0246
0247
0248
0249 ser12_set_divisor(dev, 4);
0250 } else {
0251
0252
0253
0254 switch (bc->modem.ser12.dcd_shreg & 7) {
0255 case 1:
0256 ser12_set_divisor(dev, 5);
0257 #ifdef BAYCOM_DEBUG
0258 bc->debug_vals.cur_pllcorr++;
0259 #endif
0260 break;
0261 case 4:
0262 ser12_set_divisor(dev, 3);
0263 #ifdef BAYCOM_DEBUG
0264 bc->debug_vals.cur_pllcorr--;
0265 #endif
0266 break;
0267 default:
0268 ser12_set_divisor(dev, 4);
0269 break;
0270 }
0271 bc->modem.shreg >>= 1;
0272 if (bc->modem.ser12.last_sample ==
0273 bc->modem.ser12.last_rxbit)
0274 bc->modem.shreg |= 0x10000;
0275 bc->modem.ser12.last_rxbit =
0276 bc->modem.ser12.last_sample;
0277 }
0278 if (++bc->modem.ser12.interm_sample >= 3)
0279 bc->modem.ser12.interm_sample = 0;
0280
0281
0282
0283 if (bc->modem.ser12.dcd_shreg & 1) {
0284 unsigned int dcdspos, dcdsneg;
0285
0286 dcdspos = dcdsneg = 0;
0287 dcdspos += ((bc->modem.ser12.dcd_shreg >> 1) & 1);
0288 dcdspos += (!(bc->modem.ser12.dcd_shreg & 0x7ffffffe))
0289 << 1;
0290 dcdsneg += ((bc->modem.ser12.dcd_shreg >> 2) & 1);
0291 dcdsneg += ((bc->modem.ser12.dcd_shreg >> 3) & 1);
0292 dcdsneg += ((bc->modem.ser12.dcd_shreg >> 4) & 1);
0293
0294 bc->modem.ser12.dcd_sum0 += 16*dcdspos - dcdsneg;
0295 }
0296 } else {
0297
0298
0299
0300 if (bc->modem.ser12.interm_sample) {
0301
0302
0303
0304 ser12_set_divisor(dev, 6);
0305 } else {
0306
0307
0308
0309 switch (bc->modem.ser12.dcd_shreg & 3) {
0310 case 1:
0311 ser12_set_divisor(dev, 7);
0312 #ifdef BAYCOM_DEBUG
0313 bc->debug_vals.cur_pllcorr++;
0314 #endif
0315 break;
0316 case 2:
0317 ser12_set_divisor(dev, 5);
0318 #ifdef BAYCOM_DEBUG
0319 bc->debug_vals.cur_pllcorr--;
0320 #endif
0321 break;
0322 default:
0323 ser12_set_divisor(dev, 6);
0324 break;
0325 }
0326 bc->modem.shreg >>= 1;
0327 if (bc->modem.ser12.last_sample ==
0328 bc->modem.ser12.last_rxbit)
0329 bc->modem.shreg |= 0x10000;
0330 bc->modem.ser12.last_rxbit =
0331 bc->modem.ser12.last_sample;
0332 }
0333 bc->modem.ser12.interm_sample = !bc->modem.ser12.interm_sample;
0334
0335
0336
0337 bc->modem.ser12.dcd_sum0 -= (bc->modem.ser12.dcd_shreg & 1);
0338 }
0339 outb(0x0d, MCR(dev->base_addr));
0340 if (bc->modem.shreg & 1) {
0341 hdlcdrv_putbits(&bc->hdrv, bc->modem.shreg >> 1);
0342 bc->modem.shreg = 0x10000;
0343 }
0344 if(!bc->modem.ser12.dcd_time) {
0345 if (bc->opt_dcd & 1)
0346 hdlcdrv_setdcd(&bc->hdrv, !((inb(MSR(dev->base_addr)) ^ bc->opt_dcd) & 0x80));
0347 else
0348 hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 +
0349 bc->modem.ser12.dcd_sum1 +
0350 bc->modem.ser12.dcd_sum2) < 0);
0351 bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1;
0352 bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0;
0353
0354 bc->modem.ser12.dcd_sum0 = 2;
0355 bc->modem.ser12.dcd_time = SER12_DCD_INTERVAL(bc);
0356 }
0357 bc->modem.ser12.dcd_time--;
0358 }
0359
0360
0361
0362 static irqreturn_t ser12_interrupt(int irq, void *dev_id)
0363 {
0364 struct net_device *dev = (struct net_device *)dev_id;
0365 struct baycom_state *bc = netdev_priv(dev);
0366 unsigned char iir;
0367
0368 if (!dev || !bc || bc->hdrv.magic != HDLCDRV_MAGIC)
0369 return IRQ_NONE;
0370
0371 if ((iir = inb(IIR(dev->base_addr))) & 1)
0372 return IRQ_NONE;
0373 baycom_int_freq(bc);
0374 do {
0375 switch (iir & 6) {
0376 case 6:
0377 inb(LSR(dev->base_addr));
0378 break;
0379
0380 case 4:
0381 inb(RBR(dev->base_addr));
0382 break;
0383
0384 case 2:
0385
0386
0387
0388 if (hdlcdrv_ptt(&bc->hdrv))
0389 ser12_tx(dev, bc);
0390 else {
0391 ser12_rx(dev, bc);
0392 bc->modem.arb_divider--;
0393 }
0394 outb(0x00, THR(dev->base_addr));
0395 break;
0396
0397 default:
0398 inb(MSR(dev->base_addr));
0399 break;
0400 }
0401 iir = inb(IIR(dev->base_addr));
0402 } while (!(iir & 1));
0403 if (bc->modem.arb_divider <= 0) {
0404 bc->modem.arb_divider = SER12_ARB_DIVIDER(bc);
0405 local_irq_enable();
0406 hdlcdrv_arbitrate(dev, &bc->hdrv);
0407 }
0408 local_irq_enable();
0409 hdlcdrv_transmitter(dev, &bc->hdrv);
0410 hdlcdrv_receiver(dev, &bc->hdrv);
0411 local_irq_disable();
0412 return IRQ_HANDLED;
0413 }
0414
0415
0416
0417 enum uart { c_uart_unknown, c_uart_8250,
0418 c_uart_16450, c_uart_16550, c_uart_16550A};
0419 static const char *uart_str[] = {
0420 "unknown", "8250", "16450", "16550", "16550A"
0421 };
0422
0423 static enum uart ser12_check_uart(unsigned int iobase)
0424 {
0425 unsigned char b1,b2,b3;
0426 enum uart u;
0427 enum uart uart_tab[] =
0428 { c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A };
0429
0430 b1 = inb(MCR(iobase));
0431 outb(b1 | 0x10, MCR(iobase));
0432 b2 = inb(MSR(iobase));
0433 outb(0x1a, MCR(iobase));
0434 b3 = inb(MSR(iobase)) & 0xf0;
0435 outb(b1, MCR(iobase));
0436 outb(b2, MSR(iobase));
0437 if (b3 != 0x90)
0438 return c_uart_unknown;
0439 inb(RBR(iobase));
0440 inb(RBR(iobase));
0441 outb(0x01, FCR(iobase));
0442 u = uart_tab[(inb(IIR(iobase)) >> 6) & 3];
0443 if (u == c_uart_16450) {
0444 outb(0x5a, SCR(iobase));
0445 b1 = inb(SCR(iobase));
0446 outb(0xa5, SCR(iobase));
0447 b2 = inb(SCR(iobase));
0448 if ((b1 != 0x5a) || (b2 != 0xa5))
0449 u = c_uart_8250;
0450 }
0451 return u;
0452 }
0453
0454
0455
0456 static int ser12_open(struct net_device *dev)
0457 {
0458 struct baycom_state *bc = netdev_priv(dev);
0459 enum uart u;
0460
0461 if (!dev || !bc)
0462 return -ENXIO;
0463 if (!dev->base_addr || dev->base_addr > 0x1000-SER12_EXTENT ||
0464 dev->irq < 2 || dev->irq > 15)
0465 return -ENXIO;
0466 if (!request_region(dev->base_addr, SER12_EXTENT, "baycom_ser12"))
0467 return -EACCES;
0468 memset(&bc->modem, 0, sizeof(bc->modem));
0469 bc->hdrv.par.bitrate = 1200;
0470 if ((u = ser12_check_uart(dev->base_addr)) == c_uart_unknown) {
0471 release_region(dev->base_addr, SER12_EXTENT);
0472 return -EIO;
0473 }
0474 outb(0, FCR(dev->base_addr));
0475 outb(0x0d, MCR(dev->base_addr));
0476 outb(0, IER(dev->base_addr));
0477 if (request_irq(dev->irq, ser12_interrupt, IRQF_SHARED,
0478 "baycom_ser12", dev)) {
0479 release_region(dev->base_addr, SER12_EXTENT);
0480 return -EBUSY;
0481 }
0482
0483
0484
0485 outb(2, IER(dev->base_addr));
0486
0487
0488
0489
0490
0491 ser12_set_divisor(dev, bc->opt_dcd ? 6 : 4);
0492 printk(KERN_INFO "%s: ser12 at iobase 0x%lx irq %u uart %s\n",
0493 bc_drvname, dev->base_addr, dev->irq, uart_str[u]);
0494 return 0;
0495 }
0496
0497
0498
0499 static int ser12_close(struct net_device *dev)
0500 {
0501 struct baycom_state *bc = netdev_priv(dev);
0502
0503 if (!dev || !bc)
0504 return -EINVAL;
0505
0506
0507
0508 outb(0, IER(dev->base_addr));
0509 outb(1, MCR(dev->base_addr));
0510 free_irq(dev->irq, dev);
0511 release_region(dev->base_addr, SER12_EXTENT);
0512 printk(KERN_INFO "%s: close ser12 at iobase 0x%lx irq %u\n",
0513 bc_drvname, dev->base_addr, dev->irq);
0514 return 0;
0515 }
0516
0517
0518
0519
0520
0521
0522
0523
0524 static int baycom_ioctl(struct net_device *dev, void __user *data,
0525 struct hdlcdrv_ioctl *hi, int cmd);
0526
0527
0528
0529 static const struct hdlcdrv_ops ser12_ops = {
0530 .drvname = bc_drvname,
0531 .drvinfo = bc_drvinfo,
0532 .open = ser12_open,
0533 .close = ser12_close,
0534 .ioctl = baycom_ioctl,
0535 };
0536
0537
0538
0539 static int baycom_setmode(struct baycom_state *bc, const char *modestr)
0540 {
0541 if (strchr(modestr, '*'))
0542 bc->opt_dcd = 0;
0543 else if (strchr(modestr, '+'))
0544 bc->opt_dcd = -1;
0545 else if (strchr(modestr, '@'))
0546 bc->opt_dcd = -2;
0547 else
0548 bc->opt_dcd = 1;
0549 return 0;
0550 }
0551
0552
0553
0554 static int baycom_ioctl(struct net_device *dev, void __user *data,
0555 struct hdlcdrv_ioctl *hi, int cmd)
0556 {
0557 struct baycom_state *bc;
0558 struct baycom_ioctl bi;
0559
0560 if (!dev)
0561 return -EINVAL;
0562
0563 bc = netdev_priv(dev);
0564 BUG_ON(bc->hdrv.magic != HDLCDRV_MAGIC);
0565
0566 if (cmd != SIOCDEVPRIVATE)
0567 return -ENOIOCTLCMD;
0568 switch (hi->cmd) {
0569 default:
0570 break;
0571
0572 case HDLCDRVCTL_GETMODE:
0573 strcpy(hi->data.modename, "ser12");
0574 if (bc->opt_dcd <= 0)
0575 strcat(hi->data.modename, (!bc->opt_dcd) ? "*" : (bc->opt_dcd == -2) ? "@" : "+");
0576 if (copy_to_user(data, hi, sizeof(struct hdlcdrv_ioctl)))
0577 return -EFAULT;
0578 return 0;
0579
0580 case HDLCDRVCTL_SETMODE:
0581 if (netif_running(dev) || !capable(CAP_NET_ADMIN))
0582 return -EACCES;
0583 hi->data.modename[sizeof(hi->data.modename)-1] = '\0';
0584 return baycom_setmode(bc, hi->data.modename);
0585
0586 case HDLCDRVCTL_MODELIST:
0587 strcpy(hi->data.modename, "ser12");
0588 if (copy_to_user(data, hi, sizeof(struct hdlcdrv_ioctl)))
0589 return -EFAULT;
0590 return 0;
0591
0592 case HDLCDRVCTL_MODEMPARMASK:
0593 return HDLCDRV_PARMASK_IOBASE | HDLCDRV_PARMASK_IRQ;
0594
0595 }
0596
0597 if (copy_from_user(&bi, data, sizeof(bi)))
0598 return -EFAULT;
0599 switch (bi.cmd) {
0600 default:
0601 return -ENOIOCTLCMD;
0602
0603 #ifdef BAYCOM_DEBUG
0604 case BAYCOMCTL_GETDEBUG:
0605 bi.data.dbg.debug1 = bc->hdrv.ptt_keyed;
0606 bi.data.dbg.debug2 = bc->debug_vals.last_intcnt;
0607 bi.data.dbg.debug3 = bc->debug_vals.last_pllcorr;
0608 break;
0609 #endif
0610
0611 }
0612 if (copy_to_user(data, &bi, sizeof(bi)))
0613 return -EFAULT;
0614 return 0;
0615
0616 }
0617
0618
0619
0620
0621
0622
0623 static char *mode[NR_PORTS] = { "ser12*", };
0624 static int iobase[NR_PORTS] = { 0x3f8, };
0625 static int irq[NR_PORTS] = { 4, };
0626
0627 module_param_array(mode, charp, NULL, 0);
0628 MODULE_PARM_DESC(mode, "baycom operating mode; * for software DCD");
0629 module_param_hw_array(iobase, int, ioport, NULL, 0);
0630 MODULE_PARM_DESC(iobase, "baycom io base address");
0631 module_param_hw_array(irq, int, irq, NULL, 0);
0632 MODULE_PARM_DESC(irq, "baycom irq number");
0633
0634 MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
0635 MODULE_DESCRIPTION("Baycom ser12 half duplex amateur radio modem driver");
0636 MODULE_LICENSE("GPL");
0637
0638
0639
0640 static int __init init_baycomserhdx(void)
0641 {
0642 int i, found = 0;
0643 char set_hw = 1;
0644
0645 printk(bc_drvinfo);
0646
0647
0648
0649 for (i = 0; i < NR_PORTS; i++) {
0650 struct net_device *dev;
0651 struct baycom_state *bc;
0652 char ifname[IFNAMSIZ];
0653
0654 sprintf(ifname, "bcsh%d", i);
0655
0656 if (!mode[i])
0657 set_hw = 0;
0658 if (!set_hw)
0659 iobase[i] = irq[i] = 0;
0660
0661 dev = hdlcdrv_register(&ser12_ops,
0662 sizeof(struct baycom_state),
0663 ifname, iobase[i], irq[i], 0);
0664 if (IS_ERR(dev))
0665 break;
0666
0667 bc = netdev_priv(dev);
0668 if (set_hw && baycom_setmode(bc, mode[i]))
0669 set_hw = 0;
0670 found++;
0671 baycom_device[i] = dev;
0672 }
0673
0674 if (!found)
0675 return -ENXIO;
0676 return 0;
0677 }
0678
0679 static void __exit cleanup_baycomserhdx(void)
0680 {
0681 int i;
0682
0683 for(i = 0; i < NR_PORTS; i++) {
0684 struct net_device *dev = baycom_device[i];
0685
0686 if (dev)
0687 hdlcdrv_unregister(dev);
0688 }
0689 }
0690
0691 module_init(init_baycomserhdx);
0692 module_exit(cleanup_baycomserhdx);
0693
0694
0695
0696 #ifndef MODULE
0697
0698
0699
0700
0701
0702
0703
0704
0705
0706
0707 static int __init baycom_ser_hdx_setup(char *str)
0708 {
0709 static unsigned nr_dev;
0710 int ints[3];
0711
0712 if (nr_dev >= NR_PORTS)
0713 return 0;
0714 str = get_options(str, 3, ints);
0715 if (ints[0] < 2)
0716 return 0;
0717 mode[nr_dev] = str;
0718 iobase[nr_dev] = ints[1];
0719 irq[nr_dev] = ints[2];
0720 nr_dev++;
0721 return 1;
0722 }
0723
0724 __setup("baycom_ser_hdx=", baycom_ser_hdx_setup);
0725
0726 #endif
0727