patch-2.1.49 linux/drivers/char/hfmodem/modem.c
Next file: linux/drivers/char/hfmodem/refclock.c
Previous file: linux/drivers/char/hfmodem/main.c
Back to the patch index
Back to the overall index
- Lines: 793
- Date:
Tue Aug 5 09:48:55 1997
- Orig file:
v2.1.48/linux/drivers/char/hfmodem/modem.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.1.48/linux/drivers/char/hfmodem/modem.c linux/drivers/char/hfmodem/modem.c
@@ -0,0 +1,792 @@
+/*****************************************************************************/
+
+/*
+ * modem.c -- Linux soundcard HF FSK driver,
+ * Modem code.
+ *
+ * Copyright (C) 1997 Thomas Sailer (sailer@ife.ee.ethz.ch)
+ * Swiss Federal Institute of Technology (ETH), Electronics Lab
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ */
+
+/*****************************************************************************/
+
+
+#include <linux/wait.h>
+#include <linux/malloc.h>
+#include <linux/hfmodem.h>
+
+/* --------------------------------------------------------------------- */
+
+/*
+ * currently this module is supposed to support both module styles, i.e.
+ * the old one present up to about 2.1.9, and the new one functioning
+ * starting with 2.1.21. The reason is I have a kit allowing to compile
+ * this module also under 2.0.x which was requested by several people.
+ * This will go in 2.2
+ */
+#include <linux/version.h>
+
+#if LINUX_VERSION_CODE >= 0x20100
+#include <asm/uaccess.h>
+#else
+#include <asm/segment.h>
+#include <linux/mm.h>
+
+#undef put_user
+#undef get_user
+
+#define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
+#define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
+
+extern inline int copy_from_user(void *to, const void *from, unsigned long n)
+{
+ int i = verify_area(VERIFY_READ, from, n);
+ if (i)
+ return i;
+ memcpy_fromfs(to, from, n);
+ return 0;
+}
+
+extern inline int copy_to_user(void *to, const void *from, unsigned long n)
+{
+ int i = verify_area(VERIFY_WRITE, to, n);
+ if (i)
+ return i;
+ memcpy_tofs(to, from, n);
+ return 0;
+}
+#endif
+
+#if LINUX_VERSION_CODE >= 0x20123
+#include <linux/init.h>
+#else
+#define __init
+#define __initdata
+#define __initfunc(x) x
+#endif
+
+/* --------------------------------------------------------------------- */
+
+struct hfmodem_correlator_cache hfmodem_correlator_cache[HFMODEM_CORRELATOR_CACHE];
+
+/* --------------------------------------------------------------------- */
+
+#include "tables.h"
+
+#define M_PI 3.14159265358979323846 /* pi */
+
+/* --------------------------------------------------------------------- */
+
+extern __inline__ int isimplecos(unsigned int arg)
+{
+ return isintab[((arg+0x4000) >> (16-SINTABBITS)) & (SINTABSIZE-1)];
+}
+
+extern __inline__ int isimplesin(unsigned int arg)
+{
+ return isintab[(arg >> (16-SINTABBITS)) & (SINTABSIZE-1)];
+}
+
+/* --------------------------------------------------------------------- */
+
+extern __inline__ int itblcos(unsigned int arg)
+{
+ unsigned int x;
+ int dx;
+ int s, c;
+
+ x = (arg + (0x8000 >> SINTABBITS)) & (0xffffu & (0xffffu << (16-SINTABBITS)));
+ dx = arg - x;
+ x >>= (16-SINTABBITS);
+ c = isintab[x+(0x4000 >> (16-SINTABBITS))];
+ s = isintab[x];
+ return c - ((s * dx * (int)(M_PI*64.0)) >> 21);
+}
+
+/* --------------------------------------------------------------------- */
+
+extern __inline__ void itblcossin(unsigned int arg, int *cos, int *sin)
+{
+ unsigned int x;
+ int dx;
+ int s, c;
+
+ x = (arg + (0x8000 >> SINTABBITS)) & (0xffffu & (0xffffu << (16-SINTABBITS)));
+ dx = arg - x;
+ x >>= (16-SINTABBITS);
+ c = isintab[x+(0x4000 >> (16-SINTABBITS))];
+ s = isintab[x];
+ *cos = c - ((s * dx * (int)(M_PI*64.0)) >> 21);
+ *sin = s + ((c * dx * (int)(M_PI*64.0)) >> 21);
+}
+
+/* --------------------------------------------------------------------- */
+
+static unsigned short random_seed;
+
+extern __inline__ unsigned short random_num(void)
+{
+ random_seed = 28629 * random_seed + 157;
+ return random_seed;
+}
+
+/* --------------------------------------------------------------------- */
+/*
+ * correlator cache routines
+ */
+
+extern __inline__ void cc_lock(unsigned int u)
+{
+ if (u >= HFMODEM_CORRELATOR_CACHE)
+ return;
+ hfmodem_correlator_cache[u].refcnt++;
+}
+
+extern __inline__ void cc_unlock(unsigned int u)
+{
+ if (u >= HFMODEM_CORRELATOR_CACHE)
+ return;
+ if ((--hfmodem_correlator_cache[u].refcnt) <= 0) {
+ unsigned int i;
+
+ for (i = 0; i < HFMODEM_CORRELATOR_CACHE; i++)
+ if (hfmodem_correlator_cache[i].lru < 32767)
+ hfmodem_correlator_cache[i].lru++;
+ hfmodem_correlator_cache[u].lru = 0;
+ hfmodem_correlator_cache[u].refcnt = 0;
+ }
+}
+
+
+/* --------------------------------------------------------------------- */
+
+extern __inline__ unsigned int cc_lookup(unsigned short phinc0, unsigned short phinc1)
+{
+ unsigned int j;
+
+ /* find correlator cache entry */
+ for (j = 0; j < HFMODEM_CORRELATOR_CACHE; j++)
+ if (hfmodem_correlator_cache[j].phase_incs[0] == phinc0 &&
+ hfmodem_correlator_cache[j].phase_incs[1] == phinc1)
+ return j;
+ return ~0;
+}
+
+/* --------------------------------------------------------------------- */
+
+extern __inline__ unsigned int cc_replace(void)
+{
+ unsigned int j, k = HFMODEM_CORRELATOR_CACHE;
+ int l = -1;
+
+ for (j = 0; j < HFMODEM_CORRELATOR_CACHE; j++)
+ if (hfmodem_correlator_cache[j].refcnt <= 0 && hfmodem_correlator_cache[j].lru > l) {
+ k = j;
+ l = hfmodem_correlator_cache[j].lru;
+ }
+ if (k < HFMODEM_CORRELATOR_CACHE)
+ return k;
+ printk(KERN_ERR "%s: modem: out of filter coefficient cache entries\n", hfmodem_drvname);
+ return random_num() % HFMODEM_CORRELATOR_CACHE;
+}
+
+/* --------------------------------------------------------------------- */
+
+#define SH1 8 /* min. ceil(log2(L1CORR_LEN)) - (31-(2*15-1)) */
+#define SH2 (3*15-2*SH1)
+
+#ifdef __i386__
+
+extern __inline__ int icorr(int n, const int *coeff, const short *inp)
+{
+ int ret, rethi, tmp1 = 0, tmp2 = 0;
+
+ __asm__("\n1:\n\t"
+ "movswl (%0),%%eax\n\t"
+ "imull (%1)\n\t"
+ "subl $2,%0\n\t"
+ "addl $4,%1\n\t"
+ "addl %%eax,%3\n\t"
+ "adcl %%edx,%4\n\t"
+ "decl %2\n\t"
+ "jne 1b\n\t"
+ : "=&S" (inp), "=&D" (coeff), "=&c" (n), "=m" (tmp1), "=m" (tmp2)
+ : "0" (inp), "1" (coeff), "2" (n)
+ : "ax", "dx");
+ __asm__("shrdl %2,%1,%0\n\t"
+ "# sarl %2,%1\n\t"
+ : "=&r" (ret), "=&r" (rethi)
+ : "i" (SH1), "0" (tmp1), "1" (tmp2));
+
+
+ return ret;
+}
+
+#else /* __i386__ */
+
+extern __inline__ int icorr(int n, const int *coeff, const short *inp)
+{
+ long long sum = 0;
+ int i;
+
+ for (i = n; i > 0; i--, coeff++, inp--)
+ sum += (*coeff) * (*inp);
+ sum >>= SH1;
+ return sum;
+}
+
+#endif /* __i386__ */
+
+/* --------------------------------------------------------------------- */
+
+extern __inline__ long long isqr(int x) __attribute__ ((const));
+
+extern __inline__ long long isqr(int x)
+{
+ return ((long long)x) * ((long long)x);
+}
+
+/* --------------------------------------------------------------------- */
+
+extern __inline__ hfmodem_soft_t do_filter(struct hfmodem_l1_rxslot *slot, short *s)
+{
+ unsigned int cc = slot->corr_cache;
+ long long ll;
+
+ if (cc >= HFMODEM_CORRELATOR_CACHE) {
+ printk(KERN_ERR "do_filter: correlator cache index overrange\n");
+ return 0;
+ }
+ ll = isqr(icorr(slot->corrlen, hfmodem_correlator_cache[cc].correlator[1][0], s)) +
+ isqr(icorr(slot->corrlen, hfmodem_correlator_cache[cc].correlator[1][1], s)) -
+ isqr(icorr(slot->corrlen, hfmodem_correlator_cache[cc].correlator[0][0], s)) -
+ isqr(icorr(slot->corrlen, hfmodem_correlator_cache[cc].correlator[0][1], s));
+ ll >>= SH2;
+ return (ll * slot->scale) >> 23;
+}
+
+/* --------------------------------------------------------------------- */
+
+static void cc_prepare(struct hfmodem_l1_rxslot *slot, unsigned short phinc0, unsigned short phinc1)
+{
+ unsigned int j, k, l, ph, phinc;
+
+ slot->scale = (1<<23) / (slot->corrlen*slot->corrlen);
+
+ j = cc_lookup(phinc0, phinc1);
+ if (j >= HFMODEM_CORRELATOR_CACHE) {
+ j = cc_replace();
+ /* calculate the correlator values */
+ printk(KERN_DEBUG "%s: corr cache calc: %u phases: 0x%04x 0x%04x\n",
+ hfmodem_drvname, j, phinc0, phinc1);
+ hfmodem_correlator_cache[j].phase_incs[0] = phinc0;
+ hfmodem_correlator_cache[j].phase_incs[1] = phinc1;
+ for (k = 0; k < 2; k++) {
+ phinc = hfmodem_correlator_cache[j].phase_incs[k];
+ for (ph = l = 0; l < HFMODEM_MAXCORRLEN; l++, ph = (ph + phinc) & 0xffff)
+ itblcossin(ph, &hfmodem_correlator_cache[j].correlator[k][0][l],
+ &hfmodem_correlator_cache[j].correlator[k][1][l]);
+ }
+ hfmodem_correlator_cache[j].refcnt = 0;
+
+#if 0
+ printk(KERN_DEBUG "%s: corr: %u ph: 0x%04x 0x%04x\n", hfmodem_drvname, j,
+ hfmodem_correlator_cache[j].phase_incs[0],
+ hfmodem_correlator_cache[j].phase_incs[1]);
+ for (l = 0; l < HFMODEM_MAXCORRLEN; l++)
+ printk(KERN_DEBUG "%s: corr: %6d %6d %6d %6d\n", hfmodem_drvname,
+ hfmodem_correlator_cache[j].correlator[0][0][l],
+ hfmodem_correlator_cache[j].correlator[0][1][l],
+ hfmodem_correlator_cache[j].correlator[1][0][l],
+ hfmodem_correlator_cache[j].correlator[1][1][l]);
+#endif
+ }
+ slot->corr_cache = j;
+ cc_lock(j);
+}
+
+/* --------------------------------------------------------------------- */
+
+void hfmodem_clear_rq(struct hfmodem_state *dev)
+{
+ unsigned long flags;
+ unsigned int i;
+
+ save_flags(flags);
+ cli();
+ for (i = 0; i < HFMODEM_NUMRXSLOTS; i++) {
+ if (dev->l1.rxslots[i].state == ss_unused)
+ continue;
+ dev->l1.rxslots[i].state = ss_unused;
+ kfree_s(dev->l1.rxslots[i].data, dev->l1.rxslots[i].nbits * sizeof(hfmodem_soft_t));
+ }
+ for (i = 0; i < HFMODEM_NUMTXSLOTS; i++) {
+ if (dev->l1.txslots[i].state == ss_unused)
+ continue;
+ dev->l1.txslots[i].state = ss_unused;
+ kfree_s(dev->l1.txslots[i].data, (dev->l1.txslots[i].nbits + 7) >> 3);
+ }
+ for (i = 0; i < HFMODEM_CORRELATOR_CACHE; i++)
+ hfmodem_correlator_cache[i].refcnt = 0;
+ restore_flags(flags);
+}
+
+/* --------------------------------------------------------------------- */
+
+int hfmodem_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct hfmodem_state *dev = &hfmodem_state[0];
+ struct hfmodem_ioctl_fsk_tx_request txrq;
+ struct hfmodem_ioctl_fsk_rx_request rxrq;
+ struct hfmodem_ioctl_mixer_params mix;
+ struct hfmodem_ioctl_sample_params spar;
+ unsigned long flags;
+ unsigned int len;
+ int ret, i, idx;
+ void *data, *userdata;
+ hfmodem_id_t id;
+ hfmodem_time_t tm = 0;
+
+ if (!dev->active)
+ return -EBUSY;
+ switch(cmd) {
+ default:
+ return -EINVAL;
+
+ case HFMODEM_IOCTL_FSKTXREQUEST:
+ if ((ret = copy_from_user(&txrq, (void *)arg, sizeof(txrq))))
+ return ret;
+ if (txrq.nbits > HFMODEM_MAXBITS)
+ return -EINVAL;
+ len = (txrq.nbits + 7) >> 3;
+ if (!(data = kmalloc(len, GFP_KERNEL)))
+ return -ENOMEM;
+ if (copy_from_user(data, txrq.data, len)) {
+ kfree_s(data, len);
+ return -EFAULT;
+ }
+ save_flags(flags);
+ cli();
+ for (i = 0; i < HFMODEM_NUMTXSLOTS && dev->l1.txslots[i].state != ss_unused; i++);
+ if (i >= HFMODEM_NUMTXSLOTS) {
+ restore_flags(flags);
+ kfree_s(data, len);
+ return -EBUSY;
+ }
+ dev->l1.txslots[i].state = ss_ready;
+ dev->l1.txslots[i].tstart = txrq.tstart;
+ dev->l1.txslots[i].tinc = txrq.tinc;
+ dev->l1.txslots[i].data = data;
+ dev->l1.txslots[i].nbits = txrq.nbits;
+ dev->l1.txslots[i].cntbits = 0;
+ dev->l1.txslots[i].inv = txrq.inv ? 0xff : 0;
+ dev->l1.txslots[i].id = txrq.id;
+ dev->l1.txslots[i].phase_incs[0] = ((txrq.freq[0]*0x10000+(HFMODEM_SRATE/2))/HFMODEM_SRATE)
+ & 0xffff;
+ dev->l1.txslots[i].phase_incs[1] = ((txrq.freq[1]*0x10000+(HFMODEM_SRATE/2))/HFMODEM_SRATE)
+ & 0xffff;
+ restore_flags(flags);
+ return 0;
+
+ case HFMODEM_IOCTL_FSKRXREQUEST:
+ if ((ret = copy_from_user(&rxrq, (void *)arg, sizeof(rxrq))))
+ return ret;
+ if (rxrq.nbits > HFMODEM_MAXBITS)
+ return -EINVAL;
+ if (rxrq.baud < HFMODEM_MINBAUD || rxrq.baud > HFMODEM_MAXBAUD)
+ return -EINVAL;
+ len = rxrq.nbits * sizeof(hfmodem_soft_t);
+ if (verify_area(VERIFY_WRITE, rxrq.data, len))
+ return -EFAULT;
+ if (!(data = kmalloc(len, GFP_KERNEL)))
+ return -ENOMEM;
+ save_flags(flags);
+ cli();
+ for (i = 0; i < HFMODEM_NUMRXSLOTS && dev->l1.rxslots[i].state != ss_unused; i++);
+ if (i >= HFMODEM_NUMRXSLOTS) {
+ restore_flags(flags);
+ kfree_s(data, len);
+ return -EBUSY;
+ }
+ dev->l1.rxslots[i].state = ss_ready;
+ dev->l1.rxslots[i].tstart = rxrq.tstart;
+ dev->l1.rxslots[i].tinc = rxrq.tinc;
+ dev->l1.rxslots[i].data = data;
+ dev->l1.rxslots[i].userdata = rxrq.data;
+ dev->l1.rxslots[i].nbits = rxrq.nbits;
+ dev->l1.rxslots[i].cntbits = 0;
+ dev->l1.rxslots[i].id = rxrq.id;
+ dev->l1.rxslots[i].corrlen = HFMODEM_SRATE/rxrq.baud;
+ cc_prepare(dev->l1.rxslots+i,
+ ((rxrq.freq[0]*0x10000+(HFMODEM_SRATE/2))/HFMODEM_SRATE) & 0xffff,
+ ((rxrq.freq[1]*0x10000+(HFMODEM_SRATE/2))/HFMODEM_SRATE) & 0xffff);
+ restore_flags(flags);
+ return 0;
+
+ case HFMODEM_IOCTL_CLEARRQ:
+ hfmodem_clear_rq(dev);
+ return 0;
+
+ case HFMODEM_IOCTL_GETCURTIME:
+ return put_user(dev->l1.last_time + 20000L, (hfmodem_time_t *)arg); /* heuristic */
+
+ case HFMODEM_IOCTL_WAITRQ:
+ save_flags(flags);
+ cli();
+ ret = 0;
+ for (idx = -1, i = 0; i < HFMODEM_NUMRXSLOTS; i++) {
+ if (dev->l1.rxslots[i].state == ss_unused)
+ continue;
+ if (dev->l1.rxslots[i].state != ss_retired) {
+ ret++;
+ continue;
+ }
+ if (idx < 0 || (signed)(tm - dev->l1.rxslots[i].tstart) > 0) {
+ idx = i;
+ tm = dev->l1.rxslots[i].tstart;
+ }
+ }
+ if (idx >= 0) {
+ cc_unlock(dev->l1.rxslots[idx].corr_cache);
+ id = dev->l1.rxslots[idx].id;
+ data = dev->l1.rxslots[idx].data;
+ userdata = dev->l1.rxslots[idx].userdata;
+ len = dev->l1.rxslots[idx].nbits * sizeof(hfmodem_soft_t);
+ dev->l1.rxslots[idx].state = ss_unused;
+ restore_flags(flags);
+ ret = copy_to_user(userdata, data, len);
+ kfree_s(data, len);
+ return (put_user(id, (hfmodem_id_t *)arg)) ? -EFAULT : ret;
+ }
+ for (idx = -1, i = 0; i < HFMODEM_NUMTXSLOTS; i++) {
+ if (dev->l1.txslots[i].state == ss_unused)
+ continue;
+ if (dev->l1.txslots[i].state != ss_retired) {
+ ret++;
+ continue;
+ }
+ if (idx < 0 || (signed)(tm - dev->l1.txslots[i].tstart) > 0) {
+ idx = i;
+ tm = dev->l1.txslots[i].tstart;
+ }
+ }
+ if (idx >= 0) {
+ id = dev->l1.txslots[idx].id;
+ data = dev->l1.txslots[idx].data;
+ len = (dev->l1.txslots[idx].nbits + 7) >> 3;
+ dev->l1.txslots[idx].state = ss_unused;
+ restore_flags(flags);
+ kfree_s(data, len);
+ return put_user(id, (hfmodem_id_t *)arg);
+ }
+ restore_flags(flags);
+ return ret ? -EAGAIN : -EPIPE;
+
+ case HFMODEM_IOCTL_MIXERPARAMS:
+ if ((ret = copy_from_user(&mix, (void *)arg, sizeof(mix))))
+ return ret;
+ dev->scops->mixer(dev, mix.src, mix.igain, mix.ogain);
+ return 0;
+
+ case HFMODEM_IOCTL_SAMPLESTART:
+ save_flags(flags);
+ cli();
+ if (dev->sbuf.kbuf)
+ kfree_s(dev->sbuf.kbuf, dev->sbuf.size);
+ dev->sbuf.kbuf = dev->sbuf.kptr = NULL;
+ dev->sbuf.size = dev->sbuf.rem = 0;
+ restore_flags(flags);
+ if ((ret = copy_from_user(&spar, (void *)arg, sizeof(spar))))
+ return ret;
+ if (spar.len == 0)
+ return 0;
+ if (spar.len < 2 || spar.len > 8192)
+ return -EINVAL;
+ if (verify_area(VERIFY_WRITE, spar.data, spar.len * sizeof(__s16)))
+ return -EFAULT;
+ if (!(dev->sbuf.kbuf = kmalloc(spar.len * sizeof(__s16), GFP_KERNEL)))
+ return -ENOMEM;
+ save_flags(flags);
+ cli();
+ dev->sbuf.kptr = dev->sbuf.kbuf;
+ dev->sbuf.size = spar.len * sizeof(__s16);
+ dev->sbuf.rem = spar.len;
+ dev->sbuf.ubuf = spar.data;
+ restore_flags(flags);
+ return 0;
+
+ case HFMODEM_IOCTL_SAMPLEFINISHED:
+ save_flags(flags);
+ cli();
+ if (dev->sbuf.rem > 0) {
+ restore_flags(flags);
+ return -EAGAIN;
+ }
+ if (!dev->sbuf.kbuf || !dev->sbuf.size) {
+ restore_flags(flags);
+ return -EPIPE;
+ }
+ restore_flags(flags);
+ ret = copy_to_user(dev->sbuf.ubuf, dev->sbuf.kbuf, dev->sbuf.size);
+ kfree_s(dev->sbuf.kbuf, dev->sbuf.size);
+ dev->sbuf.kbuf = dev->sbuf.kptr = NULL;
+ dev->sbuf.size = dev->sbuf.rem = 0;
+ return ret;
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+#if LINUX_VERSION_CODE >= 0x20100
+
+unsigned int hfmodem_poll(struct file *file, poll_table *wait)
+{
+ struct hfmodem_state *dev = &hfmodem_state[0];
+ unsigned long flags;
+ int i, cnt1, cnt2;
+
+ save_flags(flags);
+ cli();
+ for (i = cnt1 = cnt2 = 0; i < HFMODEM_NUMTXSLOTS; i++) {
+ if (dev->l1.txslots[i].state == ss_retired)
+ cnt1++;
+ if (dev->l1.txslots[i].state != ss_unused)
+ cnt2++;
+ }
+ for (i = 0; i < HFMODEM_NUMRXSLOTS; i++) {
+ if (dev->l1.rxslots[i].state == ss_retired)
+ cnt1++;
+ if (dev->l1.rxslots[i].state != ss_unused)
+ cnt2++;
+ }
+ restore_flags(flags);
+ poll_wait(&dev->wait, wait);
+ if (cnt1 || !cnt2)
+ return POLLIN | POLLRDNORM;
+ return 0;
+}
+
+#else
+
+int hfmodem_select(struct inode *inode, struct file *file, int sel_type, select_table *wait)
+{
+ struct hfmodem_state *dev = &hfmodem_state[0];
+ unsigned long flags;
+ int i, cnt1, cnt2;
+
+ if (sel_type == SEL_IN) {
+ save_flags(flags);
+ cli();
+ for (i = cnt1 = cnt2 = 0; i < HFMODEM_NUMTXSLOTS; i++) {
+ if (dev->l1.txslots[i].state == ss_retired)
+ cnt1++;
+ if (dev->l1.txslots[i].state != ss_unused)
+ cnt2++;
+ }
+ for (i = 0; i < HFMODEM_NUMRXSLOTS; i++) {
+ if (dev->l1.rxslots[i].state == ss_retired)
+ cnt1++;
+ if (dev->l1.rxslots[i].state != ss_unused)
+ cnt2++;
+ }
+ restore_flags(flags);
+ if (cnt1 || !cnt2)
+ return 1;
+ select_wait(&dev->wait, wait);
+ }
+ return 0;
+}
+
+#endif
+
+/* --------------------------------------------------------------------- */
+
+extern __inline__ unsigned int l1fsk_phinc(struct hfmodem_l1_txslot *txs, unsigned int nbit)
+{
+ return txs->phase_incs[!!((txs->data[nbit >> 3] ^ txs->inv) & (1 << (nbit & 7)))];
+}
+
+/* --------------------------------------------------------------------- */
+
+void hfmodem_input_samples(struct hfmodem_state *dev, hfmodem_time_t tstart,
+ hfmodem_time_t tinc, __s16 *samples)
+{
+ hfmodem_time_t tst, tend;
+ __s16 *s;
+ int i, j;
+ hfmodem_soft_t sample;
+
+ dev->l1.last_time = tstart + (HFMODEM_FRAGSAMPLES-1) * tinc;
+ for (i = 0; i < HFMODEM_NUMRXSLOTS; i++) {
+ struct hfmodem_l1_rxslot *rxs = dev->l1.rxslots + i;
+
+ if (rxs->state == ss_unused || rxs->state == ss_retired)
+ continue;
+ tst = tstart - (rxs->corrlen-1) * tinc;
+ tend = tst + (HFMODEM_FRAGSAMPLES-1) * tinc;
+ if (rxs->state == ss_ready) {
+ if ((signed)(rxs->tstart - tend) > 0)
+ continue;
+ rxs->state = ss_oper;
+ }
+ for (s = samples, j = 0; j < HFMODEM_FRAGSAMPLES; j++, s++, tst += tinc)
+ if ((signed)(rxs->tstart - tst) <= 0) {
+ sample = do_filter(rxs, s);
+ while ((signed)(rxs->tstart - tst) <= 0 &&
+ rxs->cntbits < rxs->nbits) {
+ rxs->data[rxs->cntbits] = sample;
+ rxs->cntbits++;
+ rxs->tstart += rxs->tinc;
+ }
+ if (rxs->cntbits >= rxs->nbits) {
+ rxs->state = ss_retired;
+ break;
+ }
+ }
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+extern __inline__ unsigned int output_one_sample(struct hfmodem_state *dev, hfmodem_time_t tm)
+{
+ int i, j, k;
+ struct hfmodem_l1_txslot *txs;
+ /*
+ * first activate new output slots
+ */
+ for (j = -1, i = 0; i < HFMODEM_NUMTXSLOTS; i++) {
+ txs = dev->l1.txslots + i;
+ if (txs->state == ss_ready && (signed)(txs->tstart - tm) <= 0) {
+ for (k = 0; k < HFMODEM_NUMTXSLOTS; k++) {
+ if (dev->l1.txslots[k].state != ss_oper)
+ continue;
+ dev->l1.txslots[k].state = ss_retired;
+ }
+ txs->state = ss_oper;
+ txs->tstart += txs->tinc;
+ txs->phinc = l1fsk_phinc(txs, 0);
+ txs->cntbits = 1;
+ };
+ if (txs->state != ss_oper)
+ continue;
+ j = i;
+ }
+ if (j < 0 || j >= HFMODEM_NUMTXSLOTS)
+ return 0;
+ /*
+ * calculate the current slot
+ */
+ txs = dev->l1.txslots + j;
+ while ((signed)(txs->tstart - tm) <= 0) {
+ if (txs->cntbits >= txs->nbits) {
+ txs->state = ss_retired;
+ return 0;
+ }
+ txs->tstart += txs->tinc;
+ txs->phinc = l1fsk_phinc(txs, txs->cntbits);
+ txs->cntbits++;
+ }
+ return txs->phinc;
+}
+
+/* --------------------------------------------------------------------- */
+
+int hfmodem_output_samples(struct hfmodem_state *dev, hfmodem_time_t tstart,
+ hfmodem_time_t tinc, __s16 *samples)
+{
+ int i, j;
+ hfmodem_time_t tend = tstart + (HFMODEM_FRAGSAMPLES-1) * tinc;
+
+ for (i = 0; i < HFMODEM_NUMTXSLOTS; i++) {
+ if (dev->l1.txslots[i].state == ss_oper)
+ break;
+ if (dev->l1.txslots[i].state == ss_ready &&
+ (signed)(dev->l1.txslots[i].tstart - tend) <= 0)
+ break;
+ }
+ if (i >= HFMODEM_NUMTXSLOTS)
+ return 0;
+ for (j = 0; j < HFMODEM_FRAGSAMPLES; j++, tstart += tinc, samples++) {
+ *samples = isimplecos(dev->l1.tx_phase);
+ dev->l1.tx_phase += output_one_sample(dev, tstart);
+ }
+ return 1;
+}
+
+/* --------------------------------------------------------------------- */
+
+long hfmodem_next_tx_event(struct hfmodem_state *dev, hfmodem_time_t curr)
+{
+ long diff = LONG_MAX, t;
+ int i;
+
+ for (i = 0; i < HFMODEM_NUMTXSLOTS; i++) {
+ if (dev->l1.txslots[i].state == ss_oper)
+ if (diff > 0)
+ diff = 0;
+ if (dev->l1.txslots[i].state == ss_ready) {
+ t = dev->l1.txslots[i].tstart - curr;
+ if (t < diff)
+ diff = t;
+ }
+ }
+ return diff;
+}
+
+/* --------------------------------------------------------------------- */
+
+void hfmodem_finish_pending_rx_requests(struct hfmodem_state *dev)
+{
+ int i;
+
+ for (i = 0; i < HFMODEM_NUMRXSLOTS; i++) {
+ if (dev->l1.rxslots[i].state != ss_oper)
+ continue;
+ while (dev->l1.rxslots[i].cntbits < dev->l1.rxslots[i].nbits) {
+ dev->l1.rxslots[i].data[dev->l1.rxslots[i].cntbits] = 0;
+ dev->l1.rxslots[i].cntbits++;
+ }
+ dev->l1.rxslots[i].state = ss_retired;
+ }
+}
+
+/* --------------------------------------------------------------------- */
+
+void hfmodem_wakeup(struct hfmodem_state *dev)
+{
+ int i, cnt1, cnt2;
+
+ for (i = cnt1 = cnt2 = 0; i < HFMODEM_NUMTXSLOTS; i++) {
+ if (dev->l1.txslots[i].state == ss_retired)
+ cnt1++;
+ if (dev->l1.txslots[i].state != ss_unused)
+ cnt2++;
+ }
+ for (i = 0; i < HFMODEM_NUMRXSLOTS; i++) {
+ if (dev->l1.rxslots[i].state == ss_retired)
+ cnt1++;
+ if (dev->l1.rxslots[i].state != ss_unused)
+ cnt2++;
+ }
+ if (cnt1 || !cnt2)
+ wake_up_interruptible(&dev->wait);
+}
+
+/* --------------------------------------------------------------------- */
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov