Lines Matching +full:modem +full:- +full:init

1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * baycom_ser_hdx.c -- baycom ser12 halfduplex radio modem driver.
7 * Copyright (C) 1996-2000 Thomas Sailer (sailer@ife.ee.ethz.ch)
15 * ser12: This is a very simple 1200 baud AFSK modem. The modem consists only
18 * for handling the HDLC protocol. The modem connects to a serial port,
28 * mutes audio input to the modem
36 * 0.3 26.04.1997 init code/data tagged
52 #include <linux/init.h>
60 /* --------------------------------------------------------------------- */
64 /* --------------------------------------------------------------------- */
67 static const char bc_drvinfo[] = KERN_INFO "baycom_ser_hdx: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4…
70 /* --------------------------------------------------------------------- */
76 /* --------------------------------------------------------------------- */
93 /* ---------------------------------------------------------------------- */
117 } modem; member
130 /* --------------------------------------------------------------------- */
139 bc->debug_vals.cur_intcnt++; in baycom_int_freq()
140 if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) { in baycom_int_freq()
141 bc->debug_vals.last_jiffies = cur_jiffies; in baycom_int_freq()
142 bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt; in baycom_int_freq()
143 bc->debug_vals.cur_intcnt = 0; in baycom_int_freq()
144 bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr; in baycom_int_freq()
145 bc->debug_vals.cur_pllcorr = 0; in baycom_int_freq()
150 /* --------------------------------------------------------------------- */
158 outb(0x81, LCR(dev->base_addr)); /* DLAB = 1 */ in ser12_set_divisor()
159 outb(divisor, DLL(dev->base_addr)); in ser12_set_divisor()
160 outb(0, DLM(dev->base_addr)); in ser12_set_divisor()
161 outb(0x01, LCR(dev->base_addr)); /* word length = 6 */ in ser12_set_divisor()
164 * 0 must be used to power the modem; the modem draws its in ser12_set_divisor()
167 outb(0x00, THR(dev->base_addr)); in ser12_set_divisor()
176 /* --------------------------------------------------------------------- */
181 #define SER12_ARB_DIVIDER(bc) (bc->opt_dcd ? 24 : 36)
183 #define SER12_DCD_INTERVAL(bc) (bc->opt_dcd ? 12 : 240)
193 outb(0x0e | (!!bc->modem.ser12.tx_bit), MCR(dev->base_addr)); in ser12_tx()
194 if (bc->modem.shreg <= 1) in ser12_tx()
195 bc->modem.shreg = 0x10000 | hdlcdrv_getbits(&bc->hdrv); in ser12_tx()
196 bc->modem.ser12.tx_bit = !(bc->modem.ser12.tx_bit ^ in ser12_tx()
197 (bc->modem.shreg & 1)); in ser12_tx()
198 bc->modem.shreg >>= 1; in ser12_tx()
201 /* --------------------------------------------------------------------- */
209 cur_s = inb(MSR(dev->base_addr)) & 0x10; /* the CTS line */ in ser12_rx()
210 hdlcdrv_channelbit(&bc->hdrv, cur_s); in ser12_rx()
211 bc->modem.ser12.dcd_shreg = (bc->modem.ser12.dcd_shreg << 1) | in ser12_rx()
212 (cur_s != bc->modem.ser12.last_sample); in ser12_rx()
213 bc->modem.ser12.last_sample = cur_s; in ser12_rx()
214 if(bc->modem.ser12.dcd_shreg & 1) { in ser12_rx()
215 if (!bc->opt_dcd) { in ser12_rx()
219 dcdspos += ((bc->modem.ser12.dcd_shreg >> 1) & 1); in ser12_rx()
220 if (!(bc->modem.ser12.dcd_shreg & 0x7ffffffe)) in ser12_rx()
222 dcdsneg += ((bc->modem.ser12.dcd_shreg >> 2) & 1); in ser12_rx()
223 dcdsneg += ((bc->modem.ser12.dcd_shreg >> 3) & 1); in ser12_rx()
224 dcdsneg += ((bc->modem.ser12.dcd_shreg >> 4) & 1); in ser12_rx()
226 bc->modem.ser12.dcd_sum0 += 16*dcdspos - dcdsneg; in ser12_rx()
228 bc->modem.ser12.dcd_sum0--; in ser12_rx()
230 if(!bc->modem.ser12.dcd_time) { in ser12_rx()
231 hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 + in ser12_rx()
232 bc->modem.ser12.dcd_sum1 + in ser12_rx()
233 bc->modem.ser12.dcd_sum2) < 0); in ser12_rx()
234 bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1; in ser12_rx()
235 bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0; in ser12_rx()
237 bc->modem.ser12.dcd_sum0 = 2; in ser12_rx()
238 bc->modem.ser12.dcd_time = SER12_DCD_INTERVAL(bc); in ser12_rx()
240 bc->modem.ser12.dcd_time--; in ser12_rx()
241 if (!bc->opt_dcd) { in ser12_rx()
245 if (bc->modem.ser12.interm_sample) { in ser12_rx()
254 switch (bc->modem.ser12.dcd_shreg & 7) { in ser12_rx()
258 bc->debug_vals.cur_pllcorr++; in ser12_rx()
264 bc->debug_vals.cur_pllcorr--; in ser12_rx()
271 bc->modem.shreg >>= 1; in ser12_rx()
272 if (bc->modem.ser12.last_sample == in ser12_rx()
273 bc->modem.ser12.last_rxbit) in ser12_rx()
274 bc->modem.shreg |= 0x10000; in ser12_rx()
275 bc->modem.ser12.last_rxbit = in ser12_rx()
276 bc->modem.ser12.last_sample; in ser12_rx()
278 if (++bc->modem.ser12.interm_sample >= 3) in ser12_rx()
279 bc->modem.ser12.interm_sample = 0; in ser12_rx()
283 if (bc->modem.ser12.dcd_shreg & 1) { in ser12_rx()
287 dcdspos += ((bc->modem.ser12.dcd_shreg >> 1) & 1); in ser12_rx()
288 dcdspos += (!(bc->modem.ser12.dcd_shreg & 0x7ffffffe)) in ser12_rx()
290 dcdsneg += ((bc->modem.ser12.dcd_shreg >> 2) & 1); in ser12_rx()
291 dcdsneg += ((bc->modem.ser12.dcd_shreg >> 3) & 1); in ser12_rx()
292 dcdsneg += ((bc->modem.ser12.dcd_shreg >> 4) & 1); in ser12_rx()
294 bc->modem.ser12.dcd_sum0 += 16*dcdspos - dcdsneg; in ser12_rx()
300 if (bc->modem.ser12.interm_sample) { in ser12_rx()
309 switch (bc->modem.ser12.dcd_shreg & 3) { in ser12_rx()
313 bc->debug_vals.cur_pllcorr++; in ser12_rx()
319 bc->debug_vals.cur_pllcorr--; in ser12_rx()
326 bc->modem.shreg >>= 1; in ser12_rx()
327 if (bc->modem.ser12.last_sample == in ser12_rx()
328 bc->modem.ser12.last_rxbit) in ser12_rx()
329 bc->modem.shreg |= 0x10000; in ser12_rx()
330 bc->modem.ser12.last_rxbit = in ser12_rx()
331 bc->modem.ser12.last_sample; in ser12_rx()
333 bc->modem.ser12.interm_sample = !bc->modem.ser12.interm_sample; in ser12_rx()
337 bc->modem.ser12.dcd_sum0 -= (bc->modem.ser12.dcd_shreg & 1); in ser12_rx()
339 outb(0x0d, MCR(dev->base_addr)); /* transmitter off */ in ser12_rx()
340 if (bc->modem.shreg & 1) { in ser12_rx()
341 hdlcdrv_putbits(&bc->hdrv, bc->modem.shreg >> 1); in ser12_rx()
342 bc->modem.shreg = 0x10000; in ser12_rx()
344 if(!bc->modem.ser12.dcd_time) { in ser12_rx()
345 if (bc->opt_dcd & 1) in ser12_rx()
346 hdlcdrv_setdcd(&bc->hdrv, !((inb(MSR(dev->base_addr)) ^ bc->opt_dcd) & 0x80)); in ser12_rx()
348 hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 + in ser12_rx()
349 bc->modem.ser12.dcd_sum1 + in ser12_rx()
350 bc->modem.ser12.dcd_sum2) < 0); in ser12_rx()
351 bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1; in ser12_rx()
352 bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0; in ser12_rx()
354 bc->modem.ser12.dcd_sum0 = 2; in ser12_rx()
355 bc->modem.ser12.dcd_time = SER12_DCD_INTERVAL(bc); in ser12_rx()
357 bc->modem.ser12.dcd_time--; in ser12_rx()
360 /* --------------------------------------------------------------------- */
368 if (!dev || !bc || bc->hdrv.magic != HDLCDRV_MAGIC) in ser12_interrupt()
371 if ((iir = inb(IIR(dev->base_addr))) & 1) in ser12_interrupt()
377 inb(LSR(dev->base_addr)); in ser12_interrupt()
381 inb(RBR(dev->base_addr)); in ser12_interrupt()
388 if (hdlcdrv_ptt(&bc->hdrv)) in ser12_interrupt()
392 bc->modem.arb_divider--; in ser12_interrupt()
394 outb(0x00, THR(dev->base_addr)); in ser12_interrupt()
398 inb(MSR(dev->base_addr)); in ser12_interrupt()
401 iir = inb(IIR(dev->base_addr)); in ser12_interrupt()
403 if (bc->modem.arb_divider <= 0) { in ser12_interrupt()
404 bc->modem.arb_divider = SER12_ARB_DIVIDER(bc); in ser12_interrupt()
406 hdlcdrv_arbitrate(dev, &bc->hdrv); in ser12_interrupt()
409 hdlcdrv_transmitter(dev, &bc->hdrv); in ser12_interrupt()
410 hdlcdrv_receiver(dev, &bc->hdrv); in ser12_interrupt()
415 /* --------------------------------------------------------------------- */
454 /* --------------------------------------------------------------------- */
462 return -ENXIO; in ser12_open()
463 if (!dev->base_addr || dev->base_addr > 0x1000-SER12_EXTENT || in ser12_open()
464 dev->irq < 2 || dev->irq > 15) in ser12_open()
465 return -ENXIO; in ser12_open()
466 if (!request_region(dev->base_addr, SER12_EXTENT, "baycom_ser12")) in ser12_open()
467 return -EACCES; in ser12_open()
468 memset(&bc->modem, 0, sizeof(bc->modem)); in ser12_open()
469 bc->hdrv.par.bitrate = 1200; in ser12_open()
470 if ((u = ser12_check_uart(dev->base_addr)) == c_uart_unknown) { in ser12_open()
471 release_region(dev->base_addr, SER12_EXTENT); in ser12_open()
472 return -EIO; in ser12_open()
474 outb(0, FCR(dev->base_addr)); /* disable FIFOs */ in ser12_open()
475 outb(0x0d, MCR(dev->base_addr)); in ser12_open()
476 outb(0, IER(dev->base_addr)); in ser12_open()
477 if (request_irq(dev->irq, ser12_interrupt, IRQF_SHARED, in ser12_open()
479 release_region(dev->base_addr, SER12_EXTENT); in ser12_open()
480 return -EBUSY; in ser12_open()
485 outb(2, IER(dev->base_addr)); in ser12_open()
491 ser12_set_divisor(dev, bc->opt_dcd ? 6 : 4); in ser12_open()
493 bc_drvname, dev->base_addr, dev->irq, uart_str[u]); in ser12_open()
497 /* --------------------------------------------------------------------- */
504 return -EINVAL; in ser12_close()
508 outb(0, IER(dev->base_addr)); in ser12_close()
509 outb(1, MCR(dev->base_addr)); in ser12_close()
510 free_irq(dev->irq, dev); in ser12_close()
511 release_region(dev->base_addr, SER12_EXTENT); in ser12_close()
513 bc_drvname, dev->base_addr, dev->irq); in ser12_close()
517 /* --------------------------------------------------------------------- */
522 /* --------------------------------------------------------------------- */
527 /* --------------------------------------------------------------------- */
537 /* --------------------------------------------------------------------- */
542 bc->opt_dcd = 0; in baycom_setmode()
544 bc->opt_dcd = -1; in baycom_setmode()
546 bc->opt_dcd = -2; in baycom_setmode()
548 bc->opt_dcd = 1; in baycom_setmode()
552 /* --------------------------------------------------------------------- */
561 return -EINVAL; in baycom_ioctl()
564 BUG_ON(bc->hdrv.magic != HDLCDRV_MAGIC); in baycom_ioctl()
567 return -ENOIOCTLCMD; in baycom_ioctl()
568 switch (hi->cmd) { in baycom_ioctl()
573 strcpy(hi->data.modename, "ser12"); in baycom_ioctl()
574 if (bc->opt_dcd <= 0) in baycom_ioctl()
575 strcat(hi->data.modename, (!bc->opt_dcd) ? "*" : (bc->opt_dcd == -2) ? "@" : "+"); in baycom_ioctl()
576 if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl))) in baycom_ioctl()
577 return -EFAULT; in baycom_ioctl()
582 return -EACCES; in baycom_ioctl()
583 hi->data.modename[sizeof(hi->data.modename)-1] = '\0'; in baycom_ioctl()
584 return baycom_setmode(bc, hi->data.modename); in baycom_ioctl()
587 strcpy(hi->data.modename, "ser12"); in baycom_ioctl()
588 if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl))) in baycom_ioctl()
589 return -EFAULT; in baycom_ioctl()
597 if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) in baycom_ioctl()
598 return -EFAULT; in baycom_ioctl()
601 return -ENOIOCTLCMD; in baycom_ioctl()
605 bi.data.dbg.debug1 = bc->hdrv.ptt_keyed; in baycom_ioctl()
606 bi.data.dbg.debug2 = bc->debug_vals.last_intcnt; in baycom_ioctl()
607 bi.data.dbg.debug3 = bc->debug_vals.last_pllcorr; in baycom_ioctl()
612 if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) in baycom_ioctl()
613 return -EFAULT; in baycom_ioctl()
618 /* --------------------------------------------------------------------- */
635 MODULE_DESCRIPTION("Baycom ser12 half duplex amateur radio modem driver");
638 /* --------------------------------------------------------------------- */
675 return -ENXIO; in init_baycomserhdx()
694 /* --------------------------------------------------------------------- */
703 * mutes audio input to the modem
727 /* --------------------------------------------------------------------- */