/* * baycom_ser_fdx.c -- baycom ser12 fullduplex radio modem driver. * * Copyright (C) 1996-2000 Thomas Sailer (sailer@ife.ee.ethz.ch) * * Please note that the GPL allows you to use the driver, NOT the radio. * In order to use the radio, you need a license from the communications * authority of your country. * * Supported modems * * ser12: This is a very simple 1200 baud AFSK modem. The modem consists only * of a modulator/demodulator chip, usually a TI TCM3105. The computer * is responsible for regenerating the receiver bit clock, as well as * for handling the HDLC protocol. The modem connects to a serial port, * hence the name. Since the serial port is not used as an async serial * port, the kernel driver for serial ports cannot be used, and this * driver only supports standard serial hardware (8250, 16450, 16550A) * * This modem usually draws its supply current out of the otherwise unused * TXD pin of the serial port. Thus a contiguous stream of 0x00-bytes * is transmitted to achieve a positive supply voltage. * * hsk: This is a 4800 baud FSK modem, designed for TNC use. It works fine * in 'baycom-mode' :-) In contrast to the TCM3105 modem, power is * externally supplied. So there's no need to provide the 0x00-byte-stream * when receiving or idle, which drastically reduces interrupt load. * * Command line options (insmod command line) * * mode ser# hardware DCD * ser#* software DCD * ser#+ hardware DCD, inverted signal at DCD pin * '#' denotes the baud rate / 100, eg. ser12* is '1200 baud, soft DCD' * iobase base address of the port; common values are 0x3f8, 0x2f8, 0x3e8, 0x2e8 * baud baud rate (between 300 and 4800) * irq interrupt line of the port; common values are 4,3 * * History: * 0.1 26.06.1996 Adapted from baycom.c and made network driver interface * 18.10.1996 Changed to new user space access routines (copy_{to,from}_user) * 0.3 26.04.1997 init code/data tagged * 0.4 08.07.1997 alternative ser12 decoding algorithm (uses delta CTS ints) * 0.5 11.11.1997 ser12/par96 split into separate files * 0.6 24.01.1998 Thorsten Kranzkowski, dl8bcu and Thomas Sailer: * reduced interrupt load in transmit case * reworked receiver * 0.7 03.08.1999 adapt to Linus' new __setup/__initcall * 0.8 10.08.1999 use module_init/module_exit * 0.9 12.02.2000 adapted to softnet driver interface * 0.10 03.07.2000 fix interface name handling
*/
staticinlinevoid ser12_set_divisor(struct net_device *dev, unsignedint divisor)
{
outb(0x81, LCR(dev->base_addr)); /* DLAB = 1 */
outb(divisor, DLL(dev->base_addr));
outb(divisor >> 8, DLM(dev->base_addr));
outb(0x01, LCR(dev->base_addr)); /* word length = 6 */ /* * make sure the next interrupt is generated; * 0 must be used to power the modem; the modem draws its * power from the TxD line
*/
outb(0x00, THR(dev->base_addr)); /* * it is important not to set the divider while transmitting; * this reportedly makes some UARTs generating interrupts * in the hundredthousands per second region * Reported by: Ignacio.Arenaza@studi.epfl.ch (Ignacio Arenaza Nuno)
*/
}
static __inline__ void ser12_rx(struct net_device *dev, struct baycom_state *bc, struct timespec64 *ts, unsignedchar curs)
{ int timediff; int bdus8 = bc->baud_us >> 3; int bdus4 = bc->baud_us >> 2; int bdus2 = bc->baud_us >> 1;
timediff = 1000000 + ts->tv_nsec / NSEC_PER_USEC -
bc->modem.ser12.pll_time; while (timediff >= 500000)
timediff -= 1000000; while (timediff >= bdus2) {
timediff -= bc->baud_us;
bc->modem.ser12.pll_time += bc->baud_us;
bc->modem.ser12.dcd_time--; /* first check if there is room to add a bit */ if (bc->modem.shreg & 1) {
hdlcdrv_putbits(&bc->hdrv, (bc->modem.shreg >> 1) ^ 0xffff);
bc->modem.shreg = 0x10000;
} /* add a one bit */
bc->modem.shreg >>= 1;
} if (bc->modem.ser12.dcd_time <= 0) { if (!bc->opt_dcd)
hdlcdrv_setdcd(&bc->hdrv, (bc->modem.ser12.dcd_sum0 +
bc->modem.ser12.dcd_sum1 +
bc->modem.ser12.dcd_sum2) < 0);
bc->modem.ser12.dcd_sum2 = bc->modem.ser12.dcd_sum1;
bc->modem.ser12.dcd_sum1 = bc->modem.ser12.dcd_sum0;
bc->modem.ser12.dcd_sum0 = 2; /* slight bias */
bc->modem.ser12.dcd_time += 120;
} if (bc->modem.ser12.last_rxbit != curs) {
bc->modem.ser12.last_rxbit = curs;
bc->modem.shreg |= 0x10000; /* adjust the PLL */ if (timediff > 0)
bc->modem.ser12.pll_time += bdus8; else
bc->modem.ser12.pll_time += 1000000 - bdus8; /* update DCD */ if (abs(timediff) > bdus4)
bc->modem.ser12.dcd_sum0 += 4; else
bc->modem.ser12.dcd_sum0--; #ifdef BAYCOM_DEBUG
bc->debug_vals.cur_pllcorr = timediff; #endif/* BAYCOM_DEBUG */
} while (bc->modem.ser12.pll_time >= 1000000)
bc->modem.ser12.pll_time -= 1000000;
}
if (!bc || bc->hdrv.magic != HDLCDRV_MAGIC) return IRQ_NONE; /* fast way out for shared irq */ if ((iir = inb(IIR(dev->base_addr))) & 1) return IRQ_NONE; /* get current time */
ktime_get_ts64(&ts);
msr = inb(MSR(dev->base_addr)); /* delta DCD */ if ((msr & 8) && bc->opt_dcd)
hdlcdrv_setdcd(&bc->hdrv, !((msr ^ bc->opt_dcd) & 0x80)); do { switch (iir & 6) { case 6:
inb(LSR(dev->base_addr)); break;
case 4:
inb(RBR(dev->base_addr)); break;
case 2: /* * make sure the next interrupt is generated; * 0 must be used to power the modem; the modem draws its * power from the TxD line
*/
outb(0x00, THR(dev->base_addr));
baycom_int_freq(bc);
txcount++; /* * first output the last bit (!) then call HDLC transmitter, * since this may take quite long
*/ if (bc->modem.ptt)
outb(0x0e | (!!bc->modem.ser12.tx_bit), MCR(dev->base_addr)); else
outb(0x0d, MCR(dev->base_addr)); /* transmitter off */ break;
MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
MODULE_DESCRIPTION("Baycom ser12 full duplex amateur radio modem driver");
MODULE_LICENSE("GPL");
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.