diff options
Diffstat (limited to 'drivers/char/hfmodem/main.c')
-rw-r--r-- | drivers/char/hfmodem/main.c | 736 |
1 files changed, 736 insertions, 0 deletions
diff --git a/drivers/char/hfmodem/main.c b/drivers/char/hfmodem/main.c new file mode 100644 index 000000000..eb30cec3e --- /dev/null +++ b/drivers/char/hfmodem/main.c @@ -0,0 +1,736 @@ +/*****************************************************************************/ + +/* + * main.c -- Linux soundcard HF FSK driver. + * + * 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. + * + * Command line options (insmod command line) + * + * History: + * 0.1 15.04.97 Adapted from baycom.c and made network driver interface + * 0.2 05.07.97 All floating point stuff thrown out due to Linus' rantings :) + * + */ + +/*****************************************************************************/ + + +#include <linux/module.h> + +#include <linux/kernel.h> +#include <linux/sched.h> +#include <linux/malloc.h> +#include <linux/errno.h> +#include <linux/miscdevice.h> +#include <linux/ioport.h> +#include <linux/hfmodem.h> + +#include <asm/io.h> +#include <asm/segment.h> +#include <asm/system.h> +#include <asm/irq.h> +#include <asm/dma.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 + +/* --------------------------------------------------------------------- */ + +/*static*/ const char hfmodem_drvname[] = "hfmodem"; +static const char hfmodem_drvinfo[] = KERN_INFO "hfmodem: (C) 1997 Thomas Sailer, HB9JNX/AE4WA\n" +KERN_INFO "hfmodem: version 0.2 compiled " __TIME__ " " __DATE__ "\n"; + +/* --------------------------------------------------------------------- */ +/* + * currently we support only one device + */ + +struct hfmodem_state hfmodem_state[NR_DEVICE]; + +/* --------------------------------------------------------------------- */ +/* + * ===================== port checking routines ======================== + */ + + +#define UART_RBR(iobase) (iobase+0) +#define UART_THR(iobase) (iobase+0) +#define UART_IER(iobase) (iobase+1) +#define UART_IIR(iobase) (iobase+2) +#define UART_FCR(iobase) (iobase+2) +#define UART_LCR(iobase) (iobase+3) +#define UART_MCR(iobase) (iobase+4) +#define UART_LSR(iobase) (iobase+5) +#define UART_MSR(iobase) (iobase+6) +#define UART_SCR(iobase) (iobase+7) +#define UART_DLL(iobase) (iobase+0) +#define UART_DLM(iobase) (iobase+1) + +#define SER_EXTENT 8 + +#define LPT_DATA(iobase) (iobase+0) +#define LPT_STATUS(iobase) (iobase+1) +#define LPT_CONTROL(iobase) (iobase+2) +#define LPT_IRQ_ENABLE 0x10 + +#define LPT_EXTENT 3 + +#define MIDI_DATA(iobase) (iobase) +#define MIDI_STATUS(iobase) (iobase+1) +#define MIDI_READ_FULL 0x80 /* attention: negative logic!! */ +#define MIDI_WRITE_EMPTY 0x40 /* attention: negative logic!! */ + +#define MIDI_EXTENT 2 + +#define SP_SER 1 +#define SP_PAR 2 +#define SP_MIDI 4 + +/* ---------------------------------------------------------------------- */ +/* + * returns 0 if ok and != 0 on error; + * the same behaviour as par96_check_lpt in baycom.c + */ + +__initfunc(static int check_lpt(unsigned int iobase)) +{ + unsigned char b1,b2; + int i; + + if (iobase <= 0 || iobase > 0x1000-LPT_EXTENT) + return 0; + if (check_region(iobase, LPT_EXTENT)) + return 0; + b1 = inb(LPT_DATA(iobase)); + b2 = inb(LPT_CONTROL(iobase)); + outb(0xaa, LPT_DATA(iobase)); + i = inb(LPT_DATA(iobase)) == 0xaa; + outb(0x55, LPT_DATA(iobase)); + i &= inb(LPT_DATA(iobase)) == 0x55; + outb(0x0a, LPT_CONTROL(iobase)); + i &= (inb(LPT_CONTROL(iobase)) & 0xf) == 0x0a; + outb(0x05, LPT_CONTROL(iobase)); + i &= (inb(LPT_CONTROL(iobase)) & 0xf) == 0x05; + outb(b1, LPT_DATA(iobase)); + outb(b2, LPT_CONTROL(iobase)); + return !i; +} + +/* --------------------------------------------------------------------- */ + +enum uart { c_uart_unknown, c_uart_8250, c_uart_16450, c_uart_16550, c_uart_16550A }; +static const char *uart_str[] __initdata = { "unknown", "8250", "16450", "16550", "16550A" }; + +__initfunc(static enum uart check_uart(unsigned int iobase)) +{ + unsigned char b1,b2,b3; + enum uart u; + enum uart uart_tab[] = { c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A }; + + if (iobase <= 0 || iobase > 0x1000-SER_EXTENT) + return c_uart_unknown; + if (check_region(iobase, SER_EXTENT)) + return c_uart_unknown; + b1 = inb(UART_MCR(iobase)); + outb(b1 | 0x10, UART_MCR(iobase)); /* loopback mode */ + b2 = inb(UART_MSR(iobase)); + outb(0x1a, UART_MCR(iobase)); + b3 = inb(UART_MSR(iobase)) & 0xf0; + outb(b1, UART_MCR(iobase)); /* restore old values */ + outb(b2, UART_MSR(iobase)); + if (b3 != 0x90) + return c_uart_unknown; + inb(UART_RBR(iobase)); + inb(UART_RBR(iobase)); + outb(0x01, UART_FCR(iobase)); /* enable FIFOs */ + u = uart_tab[(inb(UART_IIR(iobase)) >> 6) & 3]; + if (u == c_uart_16450) { + outb(0x5a, UART_SCR(iobase)); + b1 = inb(UART_SCR(iobase)); + outb(0xa5, UART_SCR(iobase)); + b2 = inb(UART_SCR(iobase)); + if ((b1 != 0x5a) || (b2 != 0xa5)) + u = c_uart_8250; + } + return u; +} + +/* --------------------------------------------------------------------- */ + +__initfunc(static int check_midi(unsigned int iobase)) +{ + unsigned long timeout; + unsigned long flags; + unsigned char b; + + if (iobase <= 0 || iobase > 0x1000-MIDI_EXTENT) + return 0; + if (check_region(iobase, MIDI_EXTENT)) + return 0; + timeout = jiffies + (HZ / 100); + while (inb(MIDI_STATUS(iobase)) & MIDI_WRITE_EMPTY) + if ((signed)(jiffies - timeout) > 0) + return 0; + save_flags(flags); + cli(); + outb(0xff, MIDI_DATA(iobase)); + b = inb(MIDI_STATUS(iobase)); + restore_flags(flags); + if (!(b & MIDI_WRITE_EMPTY)) + return 0; + while (inb(MIDI_STATUS(iobase)) & MIDI_WRITE_EMPTY) + if ((signed)(jiffies - timeout) > 0) + return 0; + return 1; +} + +/* --------------------------------------------------------------------- */ + +static void output_status(struct hfmodem_state *dev, int ptt) +{ + int dcd = 0; + + ptt = !!ptt; + if (dev->ptt_out.flags & SP_SER) { + outb(dcd | (ptt << 1), UART_MCR(dev->ptt_out.seriobase)); + outb(0x40 & (-ptt), UART_LCR(dev->ptt_out.seriobase)); + } + if (dev->ptt_out.flags & SP_PAR) { + outb(ptt | (dcd << 1), LPT_DATA(dev->ptt_out.pariobase)); + } + if (dev->ptt_out.flags & SP_MIDI && ptt) { + outb(0, MIDI_DATA(dev->ptt_out.midiiobase)); + } +} + +/* --------------------------------------------------------------------- */ + +__initfunc(static void output_check(struct hfmodem_state *dev)) +{ + enum uart u = c_uart_unknown; + + if (dev->ptt_out.seriobase > 0 && dev->ptt_out.seriobase <= 0x1000-SER_EXTENT && + ((u = check_uart(dev->ptt_out.seriobase))) != c_uart_unknown) + printk(KERN_INFO "%s: PTT output: uart found at address 0x%x type %s\n", + hfmodem_drvname, dev->ptt_out.seriobase, uart_str[u]); + else { + if (dev->ptt_out.seriobase > 0) + printk(KERN_WARNING "%s: PTT output: no uart found at address 0x%x\n", + hfmodem_drvname, dev->ptt_out.seriobase); + dev->ptt_out.seriobase = 0; + } + if (dev->ptt_out.pariobase > 0 && dev->ptt_out.pariobase <= 0x1000-LPT_EXTENT && + !check_lpt(dev->ptt_out.pariobase)) + printk(KERN_INFO "%s: PTT output: parallel port found at address 0x%x\n", + hfmodem_drvname, dev->ptt_out.pariobase); + else { + if (dev->ptt_out.pariobase > 0) + printk(KERN_WARNING "%s: PTT output: no parallel port found at address 0x%x\n", + hfmodem_drvname, dev->ptt_out.pariobase); + dev->ptt_out.pariobase = 0; + } + if (dev->ptt_out.midiiobase > 0 && dev->ptt_out.midiiobase <= 0x1000-MIDI_EXTENT && + check_midi(dev->ptt_out.midiiobase)) + printk(KERN_INFO "%s: PTT output: midi port found at address 0x%x\n", + hfmodem_drvname, dev->ptt_out.midiiobase); + else { + if (dev->ptt_out.midiiobase > 0) + printk(KERN_WARNING "%s: PTT output: no midi port found at address 0x%x\n", + hfmodem_drvname, dev->ptt_out.midiiobase); + dev->ptt_out.midiiobase = 0; + } +} + +/* --------------------------------------------------------------------- */ + +static void output_open(struct hfmodem_state *dev) +{ + dev->ptt_out.flags = 0; + if (dev->ptt_out.seriobase > 0) { + if (!check_region(dev->ptt_out.seriobase, SER_EXTENT)) { + request_region(dev->ptt_out.seriobase, SER_EXTENT, "hfmodem ser ptt"); + dev->ptt_out.flags |= SP_SER; + outb(0, UART_IER(dev->ptt_out.seriobase)); + /* 5 bits, 1 stop, no parity, no break, Div latch access */ + outb(0x80, UART_LCR(dev->ptt_out.seriobase)); + outb(0, UART_DLM(dev->ptt_out.seriobase)); + outb(1, UART_DLL(dev->ptt_out.seriobase)); /* as fast as possible */ + /* LCR and MCR set by output_status */ + } else + printk(KERN_WARNING "%s: PTT output: serial port at 0x%x busy\n", + hfmodem_drvname, dev->ptt_out.seriobase); + } + if (dev->ptt_out.pariobase > 0) { + if (!check_region(dev->ptt_out.pariobase, LPT_EXTENT)) { + request_region(dev->ptt_out.pariobase, LPT_EXTENT, "hfmodem par ptt"); + dev->ptt_out.flags |= SP_PAR; + } else + printk(KERN_WARNING "%s: PTT output: parallel port at 0x%x busy\n", + hfmodem_drvname, dev->ptt_out.pariobase); + } + if (dev->ptt_out.midiiobase > 0) { + if (!check_region(dev->ptt_out.midiiobase, MIDI_EXTENT)) { + request_region(dev->ptt_out.midiiobase, MIDI_EXTENT, "hfmodem midi ptt"); + dev->ptt_out.flags |= SP_MIDI; + } else + printk(KERN_WARNING "%s: PTT output: midi port at 0x%x busy\n", + hfmodem_drvname, dev->ptt_out.midiiobase); + } + output_status(dev, 0); + printk(KERN_INFO "%s: PTT output:", hfmodem_drvname); + if (dev->ptt_out.flags & SP_SER) + printk(" serial interface at 0x%x", dev->ptt_out.seriobase); + if (dev->ptt_out.flags & SP_PAR) + printk(" parallel interface at 0x%x", dev->ptt_out.pariobase); + if (dev->ptt_out.flags & SP_MIDI) + printk(" mpu401 (midi) interface at 0x%x", dev->ptt_out.midiiobase); + if (!dev->ptt_out.flags) + printk(" none"); + printk("\n"); +} + +/* --------------------------------------------------------------------- */ + +static void output_close(struct hfmodem_state *dev) +{ + /* release regions used for PTT output */ + output_status(dev, 0); + if (dev->ptt_out.flags & SP_SER) + release_region(dev->ptt_out.seriobase, SER_EXTENT); + if (dev->ptt_out.flags & SP_PAR) + release_region(dev->ptt_out.pariobase, LPT_EXTENT); + if (dev->ptt_out.flags & SP_MIDI) + release_region(dev->ptt_out.midiiobase, MIDI_EXTENT); + dev->ptt_out.flags = 0; +} + +/* --------------------------------------------------------------------- */ + +#define INC_SAMPLE (1000000/HFMODEM_SRATE) +#define INC_FRAGMENT (HFMODEM_FRAGSAMPLES*1000000/HFMODEM_SRATE) +#define SIZE (HFMODEM_FRAGSAMPLES*HFMODEM_NUMFRAGS) + +static void hfmodem_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + struct hfmodem_state *dev = (struct hfmodem_state *)dev_id; + unsigned int dmaptr; + __s16 *s; + unsigned int curfrag, nfrags; + int i; + hfmodem_time_t l1time; + + dmaptr = dev->scops->intack(dev); + l1time = hfmodem_refclock_current(dev, ((SIZE+dmaptr-dev->dma.last_dmaptr) % SIZE) * + INC_SAMPLE, 1); + curfrag = (dev->dma.last_dmaptr = dmaptr) / HFMODEM_FRAGSAMPLES; + l1time -= INC_SAMPLE * (SIZE+dmaptr-dev->dma.fragptr*HFMODEM_FRAGSAMPLES) % SIZE; + sti(); + /* + * handle receiving + */ + if (dev->dma.ptt_frames <= 0) { + while (dev->dma.fragptr != curfrag) { + if (dev->dma.fragptr < HFMODEM_EXCESSFRAGS) { + s = dev->dma.buf + SIZE + HFMODEM_FRAGSAMPLES * dev->dma.fragptr; + memcpy(s, s - SIZE, HFMODEM_FRAGSIZE); + } else + s = dev->dma.buf + HFMODEM_FRAGSAMPLES * dev->dma.fragptr; + if (dev->sbuf.kbuf && dev->sbuf.kptr && dev->sbuf.rem > 0) { + i = HFMODEM_FRAGSAMPLES; + if (i > dev->sbuf.rem) + i = dev->sbuf.rem; + memcpy(dev->sbuf.kptr, s, i * sizeof(s[0])); + dev->sbuf.rem -= i; + dev->sbuf.kptr += i; + } + hfmodem_input_samples(dev, l1time, INC_SAMPLE, s); + l1time += INC_FRAGMENT; + dev->dma.fragptr++; + if (dev->dma.fragptr >= HFMODEM_NUMFRAGS) + dev->dma.fragptr = 0; + } + /* + * check for output + */ + if (hfmodem_next_tx_event(dev, l1time) > (long)INC_FRAGMENT/2) + goto int_return; + /* + * start output + */ + output_status(dev, 1); + dev->scops->prepare_output(dev); + dev->dma.last_dmaptr = 0; + /* + * clock adjust + */ + l1time = hfmodem_refclock_current(dev, 0, 0); + /* + * fill first two fragments + */ + dev->dma.ptt_frames = 1; + for (i = 0; i < 2 && i < HFMODEM_NUMFRAGS; i++) + if (hfmodem_output_samples(dev, l1time+i*INC_FRAGMENT, INC_SAMPLE, + dev->dma.buf+i*HFMODEM_FRAGSAMPLES)) + dev->dma.ptt_frames = i + 1; + dev->dma.lastfrag = 0; + dev->scops->trigger_output(dev); + /* + * finish already pending rx requests + */ + hfmodem_finish_pending_rx_requests(dev); + goto int_return; + } + /* + * handle transmitting + */ + nfrags = HFMODEM_NUMFRAGS + curfrag - dev->dma.lastfrag; + dev->dma.lastfrag = curfrag; + if (nfrags >= HFMODEM_NUMFRAGS) + nfrags -= HFMODEM_NUMFRAGS; + dev->dma.ptt_frames -= nfrags; + if (dev->dma.ptt_frames < 0) + dev->dma.ptt_frames = 0; + while (dev->dma.ptt_frames < HFMODEM_NUMFRAGS && dev->dma.ptt_frames < 4 && + hfmodem_output_samples(dev, l1time+dev->dma.ptt_frames*INC_FRAGMENT, + INC_SAMPLE, dev->dma.buf + HFMODEM_FRAGSAMPLES * + ((curfrag + dev->dma.ptt_frames) % HFMODEM_NUMFRAGS))) + dev->dma.ptt_frames++; + if (dev->dma.ptt_frames > 0) + goto int_return; + /* + * start receiving + */ + output_status(dev, 0); + dev->dma.last_dmaptr = 0; + dev->dma.lastfrag = 0; + dev->dma.fragptr = 0; + dev->dma.ptt_frames = 0; + dev->scops->prepare_input(dev); + dev->scops->trigger_input(dev); + hfmodem_refclock_current(dev, 0, 0); /* needed to reset the time difference */ +int_return: + hfmodem_wakeup(dev); +} + +/* --------------------------------------------------------------------- */ + +static int hfmodem_close(struct inode *inode, struct file *file) +{ + struct hfmodem_state *dev = &hfmodem_state[0]; + + if (!dev->active) + return -EPERM; + dev->active = 0; + dev->scops->stop(dev); + free_irq(dev->io.irq, dev); + disable_dma(dev->io.dma); + free_dma(dev->io.dma); + release_region(dev->io.base_addr, dev->scops->extent); + kfree_s(dev->dma.buf, HFMODEM_FRAGSIZE * (HFMODEM_NUMFRAGS+HFMODEM_EXCESSFRAGS)); + hfmodem_clear_rq(dev); + 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; + } + output_close(dev); + MOD_DEC_USE_COUNT; + return 0; +} + +/* --------------------------------------------------------------------- */ + +static int hfmodem_open(struct inode *inode, struct file *file) +{ + struct hfmodem_state *dev = &hfmodem_state[0]; + + if (dev->active) + return -EBUSY; + if (!dev->scops) + return -EPERM; + /* + * clear vars + */ + memset(&dev->l1, 0, sizeof(dev->l1)); + dev->dma.last_dmaptr = 0; + dev->dma.lastfrag = 0; + dev->dma.fragptr = 0; + dev->dma.ptt_frames = 0; + /* + * allocate memory + */ + if (!(dev->dma.buf = kmalloc(HFMODEM_FRAGSIZE * (HFMODEM_NUMFRAGS+HFMODEM_EXCESSFRAGS), GFP_KERNEL | GFP_DMA))) + return -ENOMEM; + /* + * allocate resources + */ + if (request_dma(dev->io.dma, hfmodem_drvname)) { + kfree_s(dev->dma.buf, HFMODEM_FRAGSIZE * (HFMODEM_NUMFRAGS+HFMODEM_EXCESSFRAGS)); + return -EBUSY; + } + if (request_irq(dev->io.irq, hfmodem_interrupt, SA_INTERRUPT, hfmodem_drvname, dev)) { + free_dma(dev->io.dma); + kfree_s(dev->dma.buf, HFMODEM_FRAGSIZE * (HFMODEM_NUMFRAGS+HFMODEM_EXCESSFRAGS)); + return -EBUSY; + } + request_region(dev->io.base_addr, dev->scops->extent, hfmodem_drvname); + + /* clear requests */ + dev->active++; + MOD_INC_USE_COUNT; + hfmodem_refclock_init(dev); + output_open(dev); + dev->scops->init(dev); + dev->scops->prepare_input(dev); + dev->scops->trigger_input(dev); + return 0; +} + +/* --------------------------------------------------------------------- */ + +static struct file_operations hfmodem_fops = { + NULL, /* hfmodem_seek */ + NULL, /* hfmodem_read */ + NULL, /* hfmodem_write */ + NULL, /* hfmodem_readdir */ +#if LINUX_VERSION_CODE >= 0x20100 + hfmodem_poll, /* hfmodem_poll */ +#else + hfmodem_select, /* hfmodem_select */ +#endif + hfmodem_ioctl, /* hfmodem_ioctl */ + NULL, /* hfmodem_mmap */ + hfmodem_open, /* hfmodem_open */ + hfmodem_close, /* hfmodem_close */ + NULL, /* hfmodem_fsync */ + NULL, /* hfmodem_fasync */ + NULL, /* hfmodem_check_media_change */ + NULL /* hfmodem_revalidate */ +}; + +/* --------------------------------------------------------------------- */ + +static struct miscdevice hfmodem_device = { + HFMODEM_MINOR, hfmodem_drvname, &hfmodem_fops +}; + +/* --------------------------------------------------------------------- */ + +#ifdef MODULE + +/* + * Command line parameters + */ + +static int hw = 0; +static unsigned int iobase = 0x220; +static unsigned int irq = 7; +static unsigned int dma = 1; + +static unsigned int serio = 0; +static unsigned int pario = 0; +static unsigned int midiio = 0; + +#if LINUX_VERSION_CODE >= 0x20115 + +MODULE_PARM(hw, "i"); +MODULE_PARM_DESC(hw, "hardware type: 0=SBC, 1=WSS"); +MODULE_PARM(iobase, "i"); +MODULE_PARM_DESC(iobase, "io base address"); +MODULE_PARM(irq, "i"); +MODULE_PARM_DESC(irq, "interrupt number"); +MODULE_PARM(dma, "i"); +MODULE_PARM_DESC(dma, "dma number (>=4 for SB16/32/64/etc, <=3 for the rest)"); +MODULE_PARM(serio, "i"); +MODULE_PARM_DESC(serio, "address of serial port to output PTT"); +MODULE_PARM(pario, "i"); +MODULE_PARM_DESC(pario, "address of parial port to output PTT"); +MODULE_PARM(midiio, "i"); +MODULE_PARM_DESC(midiio, "address of midi (MPU401) port to output PTT"); + +MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu"); +MODULE_DESCRIPTION("HF FSK modem code"); + +/* these are the module parameters from refclock.c */ + +MODULE_PARM(scale_tvusec, "i"); +MODULE_PARM_DESC(scale_tvusec, "Scaling value for the tv_usec field (can be obta +ined by refclock)"); + +#ifdef __i386__ +MODULE_PARM(scale_rdtsc, "i"); +MODULE_PARM_DESC(scale_rdtsc, "Scaling value for the rdtsc counter (can be obtai +ned by refclock)"); +MODULE_PARM(rdtsc_ok, "i"); +MODULE_PARM_DESC(rdtsc_ok, "Set to 0 to disable the use of the rdtsc instruction +"); +#endif /* __i386__ */ + +#endif + +__initfunc(int init_module(void)) +{ + int i; + + printk(hfmodem_drvinfo); + memset(hfmodem_state, 0, sizeof(hfmodem_state)); + memset(hfmodem_correlator_cache, 0, sizeof(hfmodem_correlator_cache)); + hfmodem_state[0].io.base_addr = iobase; + hfmodem_state[0].io.irq = irq; + hfmodem_state[0].io.dma = dma; + hfmodem_state[0].ptt_out.seriobase = serio; + hfmodem_state[0].ptt_out.pariobase = pario; + hfmodem_state[0].ptt_out.midiiobase = midiio; + hfmodem_refclock_probe(); + output_check(&hfmodem_state[0]); +#if defined(CONFIG_HFMODEM_WSS) && defined(CONFIG_HFMODEM_SBC) + if (hw) + i = hfmodem_wssprobe(&hfmodem_state[0]); + else + i = hfmodem_sbcprobe(&hfmodem_state[0]); +#else + i = -EINVAL; +#ifdef CONFIG_HFMODEM_WSS + i = hfmodem_wssprobe(&hfmodem_state[0]); +#endif +#ifdef CONFIG_HFMODEM_SBC + i = hfmodem_sbcprobe(&hfmodem_state[0]); +#endif +#endif + if (i) + return i; + if ((i = misc_register(&hfmodem_device))) { + printk(KERN_ERR "%s: cannot register misc device\n", hfmodem_drvname); + return i; + } + return 0; +} + +void cleanup_module(void) +{ + misc_deregister(&hfmodem_device); +} + +#else /* MODULE */ +/* --------------------------------------------------------------------- */ + +static int hw = 0; + +__initfunc(void hfmodem_setup(char *str, int *ints)) +{ + if (ints[0] < 7) { + printk(KERN_WARNING "%s: setup: too few parameters\n", hfmodem_drvname); + return; + } + memset(hfmodem_state, 0, sizeof(hfmodem_state)); + memset(hfmodem_correlator_cache, 0, sizeof(hfmodem_correlator_cache)); + hw = ints[1]; + hfmodem_state[0].io.base_addr = ints[2]; + hfmodem_state[0].io.irq = ints[3]; + hfmodem_state[0].io.dma = ints[4]; + if (ints[0] >= 8) + hfmodem_state[0].ptt_out.seriobase = ints[5]; + if (ints[0] >= 9) + hfmodem_state[0].ptt_out.pariobase = ints[6]; + if (ints[0] >= 10) + hfmodem_state[0].ptt_out.midiiobase = ints[7]; + hfmodem_refclock_setscale(ints[ints[0]-2], ints[ints[0]-1], ints[ints[0]]); +} + +__initfunc(void hfmodem_init(void)) +{ + int i; + + printk(hfmodem_drvinfo); + hfmodem_refclock_probe(); + output_check(&hfmodem_state[0]); +#if defined(CONFIG_HFMODEM_WSS) && defined(CONFIG_HFMODEM_SBC) + if (hw) + i = hfmodem_wssprobe(&hfmodem_state[0]); + else + i = hfmodem_sbcprobe(&hfmodem_state[0]); +#else + i = -EINVAL; +#ifdef CONFIG_HFMODEM_WSS + i = hfmodem_wssprobe(&hfmodem_state[0]); +#endif +#ifdef CONFIG_HFMODEM_SBC + i = hfmodem_sbcprobe(&hfmodem_state[0]); +#endif +#endif + if (i) { + printk(KERN_ERR "%s: soundcard probe failed\n", hfmodem_drvname); + return; + } + if ((i = misc_register(&hfmodem_device))) { + printk(KERN_ERR "%s: cannot register misc device\n", hfmodem_drvname); + return; + } +} + +/* --------------------------------------------------------------------- */ +#endif /* MODULE */ + |