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

1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * baycom_ser_fdx.c -- baycom ser12 fullduplex 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,
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
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
45 * 0.3 26.04.1997 init code/data tagged
63 #include <linux/init.h>
74 /* --------------------------------------------------------------------- */
78 /* --------------------------------------------------------------------- */
81 static const char bc_drvinfo[] = KERN_INFO "baycom_ser_fdx: (C) 1996-2000 Thomas Sailer, HB9JNX/AE4…
84 /* --------------------------------------------------------------------- */
90 /* --------------------------------------------------------------------- */
107 /* ---------------------------------------------------------------------- */
130 } modem; member
143 /* --------------------------------------------------------------------- */
152 bc->debug_vals.cur_intcnt++; in baycom_int_freq()
153 if (time_after_eq(cur_jiffies, bc->debug_vals.last_jiffies + HZ)) { in baycom_int_freq()
154 bc->debug_vals.last_jiffies = cur_jiffies; in baycom_int_freq()
155 bc->debug_vals.last_intcnt = bc->debug_vals.cur_intcnt; in baycom_int_freq()
156 bc->debug_vals.cur_intcnt = 0; in baycom_int_freq()
157 bc->debug_vals.last_pllcorr = bc->debug_vals.cur_pllcorr; in baycom_int_freq()
158 bc->debug_vals.cur_pllcorr = 0; in baycom_int_freq()
163 /* --------------------------------------------------------------------- */
168 /* --------------------------------------------------------------------- */
173 outb(0x81, LCR(dev->base_addr)); /* DLAB = 1 */ in ser12_set_divisor()
174 outb(divisor, DLL(dev->base_addr)); in ser12_set_divisor()
175 outb(divisor >> 8, DLM(dev->base_addr)); in ser12_set_divisor()
176 outb(0x01, LCR(dev->base_addr)); /* word length = 6 */ in ser12_set_divisor()
179 * 0 must be used to power the modem; the modem draws its in ser12_set_divisor()
182 outb(0x00, THR(dev->base_addr)); in ser12_set_divisor()
194 int bdus8 = bc->baud_us >> 3; in ser12_rx()
195 int bdus4 = bc->baud_us >> 2; in ser12_rx()
196 int bdus2 = bc->baud_us >> 1; in ser12_rx()
198 timediff = 1000000 + ts->tv_nsec / NSEC_PER_USEC - in ser12_rx()
199 bc->modem.ser12.pll_time; in ser12_rx()
201 timediff -= 1000000; in ser12_rx()
203 timediff -= bc->baud_us; in ser12_rx()
204 bc->modem.ser12.pll_time += bc->baud_us; in ser12_rx()
205 bc->modem.ser12.dcd_time--; in ser12_rx()
207 if (bc->modem.shreg & 1) { in ser12_rx()
208 hdlcdrv_putbits(&bc->hdrv, (bc->modem.shreg >> 1) ^ 0xffff); in ser12_rx()
209 bc->modem.shreg = 0x10000; in ser12_rx()
212 bc->modem.shreg >>= 1; in ser12_rx()
214 if (bc->modem.ser12.dcd_time <= 0) { in ser12_rx()
215 if (!bc->opt_dcd) in ser12_rx()
216 hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 + in ser12_rx()
217 bc->modem.ser12.dcd_sum1 + in ser12_rx()
218 bc->modem.ser12.dcd_sum2) < 0); in ser12_rx()
219 bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1; in ser12_rx()
220 bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0; in ser12_rx()
221 bc->modem.ser12.dcd_sum0 = 2; /* slight bias */ in ser12_rx()
222 bc->modem.ser12.dcd_time += 120; in ser12_rx()
224 if (bc->modem.ser12.last_rxbit != curs) { in ser12_rx()
225 bc->modem.ser12.last_rxbit = curs; in ser12_rx()
226 bc->modem.shreg |= 0x10000; in ser12_rx()
229 bc->modem.ser12.pll_time += bdus8; in ser12_rx()
231 bc->modem.ser12.pll_time += 1000000 - bdus8; in ser12_rx()
234 bc->modem.ser12.dcd_sum0 += 4; in ser12_rx()
236 bc->modem.ser12.dcd_sum0--; in ser12_rx()
238 bc->debug_vals.cur_pllcorr = timediff; in ser12_rx()
241 while (bc->modem.ser12.pll_time >= 1000000) in ser12_rx()
242 bc->modem.ser12.pll_time -= 1000000; in ser12_rx()
245 /* --------------------------------------------------------------------- */
255 if (!bc || bc->hdrv.magic != HDLCDRV_MAGIC) in ser12_interrupt()
258 if ((iir = inb(IIR(dev->base_addr))) & 1) in ser12_interrupt()
262 msr = inb(MSR(dev->base_addr)); in ser12_interrupt()
264 if ((msr & 8) && bc->opt_dcd) in ser12_interrupt()
265 hdlcdrv_setdcd(&bc->hdrv, !((msr ^ bc->opt_dcd) & 0x80)); in ser12_interrupt()
269 inb(LSR(dev->base_addr)); in ser12_interrupt()
273 inb(RBR(dev->base_addr)); in ser12_interrupt()
279 * 0 must be used to power the modem; the modem draws its in ser12_interrupt()
282 outb(0x00, THR(dev->base_addr)); in ser12_interrupt()
289 if (bc->modem.ptt) in ser12_interrupt()
290 outb(0x0e | (!!bc->modem.ser12.tx_bit), MCR(dev->base_addr)); in ser12_interrupt()
292 outb(0x0d, MCR(dev->base_addr)); /* transmitter off */ in ser12_interrupt()
296 msr = inb(MSR(dev->base_addr)); in ser12_interrupt()
298 if ((msr & 8) && bc->opt_dcd) in ser12_interrupt()
299 hdlcdrv_setdcd(&bc->hdrv, !((msr ^ bc->opt_dcd) & 0x80)); in ser12_interrupt()
302 iir = inb(IIR(dev->base_addr)); in ser12_interrupt()
305 if (bc->modem.ptt && txcount) { in ser12_interrupt()
306 if (bc->modem.ser12.txshreg <= 1) { in ser12_interrupt()
307 bc->modem.ser12.txshreg = 0x10000 | hdlcdrv_getbits(&bc->hdrv); in ser12_interrupt()
308 if (!hdlcdrv_ptt(&bc->hdrv)) { in ser12_interrupt()
310 bc->modem.ptt = 0; in ser12_interrupt()
314 bc->modem.ser12.tx_bit = !(bc->modem.ser12.tx_bit ^ (bc->modem.ser12.txshreg & 1)); in ser12_interrupt()
315 bc->modem.ser12.txshreg >>= 1; in ser12_interrupt()
319 if (!bc->modem.ptt && txcount) { in ser12_interrupt()
320 hdlcdrv_arbitrate(dev, &bc->hdrv); in ser12_interrupt()
321 if (hdlcdrv_ptt(&bc->hdrv)) { in ser12_interrupt()
322 ser12_set_divisor(dev, bc->baud_uartdiv); in ser12_interrupt()
323 bc->modem.ser12.txshreg = 1; in ser12_interrupt()
324 bc->modem.ptt = 1; in ser12_interrupt()
327 hdlcdrv_transmitter(dev, &bc->hdrv); in ser12_interrupt()
328 hdlcdrv_receiver(dev, &bc->hdrv); in ser12_interrupt()
333 /* --------------------------------------------------------------------- */
372 /* --------------------------------------------------------------------- */
380 return -ENXIO; in ser12_open()
381 if (!dev->base_addr || dev->base_addr > 0xffff-SER12_EXTENT || in ser12_open()
382 dev->irq < 2 || dev->irq > nr_irqs) { in ser12_open()
385 0xffff-SER12_EXTENT, nr_irqs); in ser12_open()
386 return -ENXIO; in ser12_open()
388 if (bc->baud < 300 || bc->baud > 4800) { in ser12_open()
391 return -EINVAL; in ser12_open()
393 if (!request_region(dev->base_addr, SER12_EXTENT, "baycom_ser_fdx")) { in ser12_open()
395 dev->base_addr); in ser12_open()
396 return -EACCES; in ser12_open()
398 memset(&bc->modem, 0, sizeof(bc->modem)); in ser12_open()
399 bc->hdrv.par.bitrate = bc->baud; in ser12_open()
400 bc->baud_us = 1000000/bc->baud; in ser12_open()
401 bc->baud_uartdiv = (115200/8)/bc->baud; in ser12_open()
402 if ((u = ser12_check_uart(dev->base_addr)) == c_uart_unknown){ in ser12_open()
403 release_region(dev->base_addr, SER12_EXTENT); in ser12_open()
404 return -EIO; in ser12_open()
406 outb(0, FCR(dev->base_addr)); /* disable FIFOs */ in ser12_open()
407 outb(0x0d, MCR(dev->base_addr)); in ser12_open()
408 outb(0, IER(dev->base_addr)); in ser12_open()
409 if (request_irq(dev->irq, ser12_interrupt, IRQF_SHARED, in ser12_open()
411 release_region(dev->base_addr, SER12_EXTENT); in ser12_open()
412 return -EBUSY; in ser12_open()
423 * enable transmitter empty interrupt and modem status interrupt in ser12_open()
425 outb(0x0a, IER(dev->base_addr)); in ser12_open()
428 * 0 must be used to power the modem; the modem draws its in ser12_open()
431 outb(0x00, THR(dev->base_addr)); in ser12_open()
432 hdlcdrv_setdcd(&bc->hdrv, 0); in ser12_open()
434 bc_drvname, dev->base_addr, dev->irq, bc->baud, uart_str[u]); in ser12_open()
438 /* --------------------------------------------------------------------- */
445 return -EINVAL; in ser12_close()
449 outb(0, IER(dev->base_addr)); in ser12_close()
450 outb(1, MCR(dev->base_addr)); in ser12_close()
451 free_irq(dev->irq, dev); in ser12_close()
452 release_region(dev->base_addr, SER12_EXTENT); in ser12_close()
454 bc_drvname, dev->base_addr, dev->irq); in ser12_close()
458 /* --------------------------------------------------------------------- */
463 /* --------------------------------------------------------------------- */
468 /* --------------------------------------------------------------------- */
478 /* --------------------------------------------------------------------- */
487 bc->baud = baud*100; in baycom_setmode()
490 bc->opt_dcd = 0; in baycom_setmode()
492 bc->opt_dcd = -1; in baycom_setmode()
494 bc->opt_dcd = 1; in baycom_setmode()
498 /* --------------------------------------------------------------------- */
507 return -EINVAL; in baycom_ioctl()
510 BUG_ON(bc->hdrv.magic != HDLCDRV_MAGIC); in baycom_ioctl()
513 return -ENOIOCTLCMD; in baycom_ioctl()
514 switch (hi->cmd) { in baycom_ioctl()
519 sprintf(hi->data.modename, "ser%u", bc->baud / 100); in baycom_ioctl()
520 if (bc->opt_dcd <= 0) in baycom_ioctl()
521 strcat(hi->data.modename, (!bc->opt_dcd) ? "*" : "+"); in baycom_ioctl()
522 if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl))) in baycom_ioctl()
523 return -EFAULT; in baycom_ioctl()
528 return -EACCES; in baycom_ioctl()
529 hi->data.modename[sizeof(hi->data.modename)-1] = '\0'; in baycom_ioctl()
530 return baycom_setmode(bc, hi->data.modename); in baycom_ioctl()
533 strcpy(hi->data.modename, "ser12,ser3,ser24"); in baycom_ioctl()
534 if (copy_to_user(ifr->ifr_data, hi, sizeof(struct hdlcdrv_ioctl))) in baycom_ioctl()
535 return -EFAULT; in baycom_ioctl()
543 if (copy_from_user(&bi, ifr->ifr_data, sizeof(bi))) in baycom_ioctl()
544 return -EFAULT; in baycom_ioctl()
547 return -ENOIOCTLCMD; in baycom_ioctl()
551 bi.data.dbg.debug1 = bc->hdrv.ptt_keyed; in baycom_ioctl()
552 bi.data.dbg.debug2 = bc->debug_vals.last_intcnt; in baycom_ioctl()
553 bi.data.dbg.debug3 = bc->debug_vals.last_pllcorr; in baycom_ioctl()
558 if (copy_to_user(ifr->ifr_data, &bi, sizeof(bi))) in baycom_ioctl()
559 return -EFAULT; in baycom_ioctl()
564 /* --------------------------------------------------------------------- */
572 static int baud[NR_PORTS] = { [0 ... NR_PORTS-1] = 1200 };
584 MODULE_DESCRIPTION("Baycom ser12 full duplex amateur radio modem driver");
587 /* --------------------------------------------------------------------- */
619 bc->baud = baud[i]; in init_baycomserfdx()
625 return -ENXIO; in init_baycomserfdx()
643 /* --------------------------------------------------------------------- */
677 /* --------------------------------------------------------------------- */