Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

drivers/char/hfmodem/main.c

Go to the documentation of this file.
00001 /*****************************************************************************/
00002 
00003 /*
00004  *      main.c  --  Linux soundcard HF FSK driver.
00005  *
00006  *      Copyright (C) 1997  Thomas Sailer (sailer@ife.ee.ethz.ch)
00007  *        Swiss Federal Institute of Technology (ETH), Electronics Lab
00008  *
00009  *      This program is free software; you can redistribute it and/or modify
00010  *      it under the terms of the GNU General Public License as published by
00011  *      the Free Software Foundation; either version 2 of the License, or
00012  *      (at your option) any later version.
00013  *
00014  *      This program is distributed in the hope that it will be useful,
00015  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  *      GNU General Public License for more details.
00018  *
00019  *      You should have received a copy of the GNU General Public License
00020  *      along with this program; if not, write to the Free Software
00021  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00022  *
00023  *  Command line options (insmod command line)
00024  *
00025  *  History:
00026  *   0.1  15.04.97  Adapted from baycom.c and made network driver interface
00027  *   0.2  05.07.97  All floating point stuff thrown out due to Linus' rantings :)
00028  *
00029  */
00030 
00031 /*****************************************************************************/
00032       
00033 
00034 #include <linux/config.h> /* for CONFIG_HFMODEM_WSS and CONFIG_HFMODEM_SBC */
00035 #include <linux/module.h>
00036 
00037 #include <linux/kernel.h>
00038 #include <linux/sched.h>
00039 #include <linux/malloc.h>
00040 #include <linux/errno.h>
00041 #include <linux/miscdevice.h>
00042 #include <linux/ioport.h>
00043 #include <linux/hfmodem.h>
00044 
00045 #include <asm/io.h>
00046 #include <asm/segment.h>
00047 #include <asm/system.h>
00048 #include <asm/irq.h>
00049 #include <asm/dma.h>
00050 
00051 /* --------------------------------------------------------------------- */
00052 
00053 /*
00054  * currently this module is supposed to support both module styles, i.e.
00055  * the old one present up to about 2.1.9, and the new one functioning
00056  * starting with 2.1.21. The reason is I have a kit allowing to compile
00057  * this module also under 2.0.x which was requested by several people.
00058  * This will go in 2.2
00059  */
00060 #include <linux/version.h>
00061 
00062 #if LINUX_VERSION_CODE >= 0x20100
00063 #include <asm/uaccess.h>
00064 #else
00065 #include <asm/segment.h>
00066 #include <linux/mm.h>
00067 
00068 #undef put_user
00069 #undef get_user
00070 
00071 #define put_user(x,ptr) ({ __put_user((unsigned long)(x),(ptr),sizeof(*(ptr))); 0; })
00072 #define get_user(x,ptr) ({ x = ((__typeof__(*(ptr)))__get_user((ptr),sizeof(*(ptr)))); 0; })
00073 
00074 extern inline int copy_from_user(void *to, const void *from, unsigned long n)
00075 {
00076         int i = verify_area(VERIFY_READ, from, n);
00077         if (i)
00078                 return i;
00079         memcpy_fromfs(to, from, n);
00080         return 0;
00081 }
00082 
00083 extern inline int copy_to_user(void *to, const void *from, unsigned long n)
00084 {
00085         int i = verify_area(VERIFY_WRITE, to, n);
00086         if (i)
00087                 return i;
00088         memcpy_tofs(to, from, n);
00089         return 0;
00090 }
00091 #endif
00092 
00093 #if LINUX_VERSION_CODE >= 0x20123
00094 #include <linux/init.h>
00095 #else
00096 #define __init
00097 #define __initdata
00098 #define __initfunc(x) x
00099 #endif
00100 
00101 /* --------------------------------------------------------------------- */
00102 
00103 /*static*/ const char hfmodem_drvname[] = "hfmodem";
00104 static const char hfmodem_drvinfo[] = KERN_INFO "hfmodem: (C) 1997 Thomas Sailer, HB9JNX/AE4WA\n"
00105 KERN_INFO "hfmodem: version 0.2 compiled " __TIME__ " " __DATE__ "\n";
00106 
00107 /* --------------------------------------------------------------------- */
00108 /*
00109  * currently we support only one device
00110  */
00111 
00112 struct hfmodem_state hfmodem_state[NR_DEVICE];
00113 
00114 /* --------------------------------------------------------------------- */
00115 /*
00116  * ===================== port checking routines ========================
00117  */
00118 
00119 
00120 #define UART_RBR(iobase) (iobase+0)
00121 #define UART_THR(iobase) (iobase+0)
00122 #define UART_IER(iobase) (iobase+1)
00123 #define UART_IIR(iobase) (iobase+2)
00124 #define UART_FCR(iobase) (iobase+2)
00125 #define UART_LCR(iobase) (iobase+3)
00126 #define UART_MCR(iobase) (iobase+4)
00127 #define UART_LSR(iobase) (iobase+5)
00128 #define UART_MSR(iobase) (iobase+6)
00129 #define UART_SCR(iobase) (iobase+7)
00130 #define UART_DLL(iobase) (iobase+0)
00131 #define UART_DLM(iobase) (iobase+1)
00132 
00133 #define SER_EXTENT 8
00134 
00135 #define LPT_DATA(iobase)    (iobase+0)
00136 #define LPT_STATUS(iobase)  (iobase+1)
00137 #define LPT_CONTROL(iobase) (iobase+2)
00138 #define LPT_IRQ_ENABLE      0x10
00139 
00140 #define MIDI_DATA(iobase)     (iobase)
00141 #define MIDI_STATUS(iobase)   (iobase+1)
00142 #define MIDI_READ_FULL 0x80   /* attention: negative logic!! */
00143 #define MIDI_WRITE_EMPTY 0x40 /* attention: negative logic!! */
00144 
00145 #define MIDI_EXTENT 2
00146 
00147 #define SP_SER  1
00148 #define SP_PAR  2
00149 #define SP_MIDI 4
00150 
00151 /* --------------------------------------------------------------------- */
00152 
00153 static void parptt_wakeup(void *handle)
00154 {
00155         struct hfmodem_state *dev = (struct hfmodem_state *)handle;
00156 
00157         printk(KERN_DEBUG "%s: parptt: why am I being woken up?\n", hfmodem_drvname);
00158         if (!parport_claim(dev->ptt_out.pardev))
00159                 printk(KERN_DEBUG "%s: parptt: I'm broken.\n", hfmodem_drvname);
00160 }
00161 
00162 /* --------------------------------------------------------------------- */
00163 __initfunc(static int check_lpt(struct hfmodem_state *dev, unsigned int iobase))
00164 {
00165         struct parport *pp = parport_enumerate();
00166 
00167         while (pp && pp->base != iobase)
00168                 pp = pp->next;
00169         if (!pp)
00170                 return 0;
00171         if (!(dev->ptt_out.pardev = parport_register_device(pp, hfmodem_drvname, NULL, parptt_wakeup, 
00172                                                             NULL, PARPORT_DEV_EXCL, dev)))
00173                 return 0;
00174         return 1;
00175 }
00176 
00177 /* --------------------------------------------------------------------- */
00178 
00179 enum uart { c_uart_unknown, c_uart_8250, c_uart_16450, c_uart_16550, c_uart_16550A };
00180 static const char *uart_str[] __initdata = { "unknown", "8250", "16450", "16550", "16550A" };
00181 
00182 __initfunc(static enum uart check_uart(unsigned int iobase))
00183 {
00184         unsigned char b1,b2,b3;
00185         enum uart u;
00186         enum uart uart_tab[] = { c_uart_16450, c_uart_unknown, c_uart_16550, c_uart_16550A };
00187 
00188         if (iobase <= 0 || iobase > 0x1000-SER_EXTENT)
00189                 return c_uart_unknown;
00190         if (check_region(iobase, SER_EXTENT))
00191                 return c_uart_unknown;
00192         b1 = inb(UART_MCR(iobase));
00193         outb(b1 | 0x10, UART_MCR(iobase));      /* loopback mode */
00194         b2 = inb(UART_MSR(iobase));
00195         outb(0x1a, UART_MCR(iobase));
00196         b3 = inb(UART_MSR(iobase)) & 0xf0;
00197         outb(b1, UART_MCR(iobase));        /* restore old values */
00198         outb(b2, UART_MSR(iobase));
00199         if (b3 != 0x90)
00200                 return c_uart_unknown;
00201         inb(UART_RBR(iobase));
00202         inb(UART_RBR(iobase));
00203         outb(0x01, UART_FCR(iobase));           /* enable FIFOs */
00204         u = uart_tab[(inb(UART_IIR(iobase)) >> 6) & 3];
00205         if (u == c_uart_16450) {
00206                 outb(0x5a, UART_SCR(iobase));
00207                 b1 = inb(UART_SCR(iobase));
00208                 outb(0xa5, UART_SCR(iobase));
00209                 b2 = inb(UART_SCR(iobase));
00210                 if ((b1 != 0x5a) || (b2 != 0xa5))
00211                         u = c_uart_8250;
00212         }
00213         return u;
00214 }
00215 
00216 /* --------------------------------------------------------------------- */
00217 
00218 __initfunc(static int check_midi(unsigned int iobase))
00219 {
00220         unsigned long timeout;
00221         unsigned long flags;
00222         unsigned char b;
00223 
00224         if (iobase <= 0 || iobase > 0x1000-MIDI_EXTENT)
00225                 return 0;
00226         if (check_region(iobase, MIDI_EXTENT))
00227                 return 0;
00228         timeout = jiffies + (HZ / 100);
00229         while (inb(MIDI_STATUS(iobase)) & MIDI_WRITE_EMPTY)
00230                 if ((signed)(jiffies - timeout) > 0)
00231                         return 0;
00232         save_flags(flags);
00233         cli();
00234         outb(0xff, MIDI_DATA(iobase));
00235         b = inb(MIDI_STATUS(iobase));
00236         restore_flags(flags);
00237         if (!(b & MIDI_WRITE_EMPTY))
00238                 return 0;
00239         while (inb(MIDI_STATUS(iobase)) & MIDI_WRITE_EMPTY)
00240                 if ((signed)(jiffies - timeout) > 0)
00241                         return 0;
00242         return 1;
00243 }
00244 
00245 /* --------------------------------------------------------------------- */
00246 
00247 static void output_status(struct hfmodem_state *dev, int ptt)
00248 {
00249         int dcd = 0;
00250 
00251         ptt = !!ptt;
00252         if (dev->ptt_out.flags & SP_SER) {
00253                 outb(dcd | (ptt << 1), UART_MCR(dev->ptt_out.seriobase));
00254                 outb(0x40 & (-ptt), UART_LCR(dev->ptt_out.seriobase));
00255         }
00256         if (dev->ptt_out.flags & SP_PAR) {
00257                 outb(ptt | (dcd << 1), LPT_DATA(dev->ptt_out.pariobase));
00258         }
00259         if (dev->ptt_out.flags & SP_MIDI && ptt) {
00260                 outb(0, MIDI_DATA(dev->ptt_out.midiiobase));
00261         }
00262 }
00263 
00264 /* --------------------------------------------------------------------- */
00265 
00266 __initfunc(static void output_check(struct hfmodem_state *dev))
00267 {
00268         enum uart u = c_uart_unknown;
00269 
00270         if (((u = check_uart(dev->ptt_out.seriobase))) != c_uart_unknown)
00271                 printk(KERN_INFO "%s: PTT output: uart found at address 0x%x type %s\n",
00272                        hfmodem_drvname, dev->ptt_out.seriobase, uart_str[u]);
00273         else {
00274                 if (dev->ptt_out.seriobase > 0)
00275                         printk(KERN_WARNING "%s: PTT output: no uart found at address 0x%x\n",
00276                                hfmodem_drvname, dev->ptt_out.seriobase);
00277                 dev->ptt_out.seriobase = 0;
00278         }
00279         if (check_lpt(dev, dev->ptt_out.pariobase)) 
00280                 printk(KERN_INFO "%s: PTT output: parallel port found at address 0x%x\n",
00281                        hfmodem_drvname, dev->ptt_out.pariobase);
00282         else {
00283                 if (dev->ptt_out.pariobase > 0)
00284                         printk(KERN_WARNING "%s: PTT output: no parallel port found at address 0x%x\n",
00285                                hfmodem_drvname, dev->ptt_out.pariobase);
00286                 dev->ptt_out.pariobase = 0;
00287                 dev->ptt_out.pardev = NULL;
00288         }
00289         if (dev->ptt_out.midiiobase > 0 && dev->ptt_out.midiiobase <= 0x1000-MIDI_EXTENT &&
00290             check_midi(dev->ptt_out.midiiobase))
00291                 printk(KERN_INFO "%s: PTT output: midi port found at address 0x%x\n",
00292                        hfmodem_drvname, dev->ptt_out.midiiobase);
00293         else {
00294                 if (dev->ptt_out.midiiobase > 0)
00295                         printk(KERN_WARNING "%s: PTT output: no midi port found at address 0x%x\n",
00296                                hfmodem_drvname, dev->ptt_out.midiiobase);
00297                 dev->ptt_out.midiiobase = 0;
00298         }
00299 }
00300 
00301 /* --------------------------------------------------------------------- */
00302 
00303 static void output_open(struct hfmodem_state *dev)
00304 {
00305         dev->ptt_out.flags = 0;
00306         if (dev->ptt_out.seriobase > 0) {
00307                 if (!check_region(dev->ptt_out.seriobase, SER_EXTENT)) {
00308                         request_region(dev->ptt_out.seriobase, SER_EXTENT, "hfmodem ser ptt");
00309                         dev->ptt_out.flags |= SP_SER;
00310                         outb(0, UART_IER(dev->ptt_out.seriobase));
00311                         /* 5 bits, 1 stop, no parity, no break, Div latch access */
00312                         outb(0x80, UART_LCR(dev->ptt_out.seriobase));
00313                         outb(0, UART_DLM(dev->ptt_out.seriobase));
00314                         outb(1, UART_DLL(dev->ptt_out.seriobase)); /* as fast as possible */
00315                         /* LCR and MCR set by output_status */
00316                 } else
00317                         printk(KERN_WARNING "%s: PTT output: serial port at 0x%x busy\n",
00318                                hfmodem_drvname, dev->ptt_out.seriobase);
00319         }
00320         if (dev->ptt_out.pariobase > 0) {
00321                 if (parport_claim(dev->ptt_out.pardev)) 
00322                         printk(KERN_WARNING "%s: PTT output: parallel port at 0x%x busy\n",
00323                                hfmodem_drvname, dev->ptt_out.pariobase);
00324                 else 
00325                         dev->ptt_out.flags |= SP_PAR;
00326         }
00327         if (dev->ptt_out.midiiobase > 0) {
00328                 if (!check_region(dev->ptt_out.midiiobase, MIDI_EXTENT)) {
00329                         request_region(dev->ptt_out.midiiobase, MIDI_EXTENT, "hfmodem midi ptt");
00330                         dev->ptt_out.flags |= SP_MIDI;
00331                 } else
00332                         printk(KERN_WARNING "%s: PTT output: midi port at 0x%x busy\n",
00333                                hfmodem_drvname, dev->ptt_out.midiiobase);
00334         }
00335         output_status(dev, 0);
00336         printk(KERN_INFO "%s: PTT output:", hfmodem_drvname);
00337         if (dev->ptt_out.flags & SP_SER)
00338                 printk(" serial interface at 0x%x", dev->ptt_out.seriobase);
00339         if (dev->ptt_out.flags & SP_PAR)
00340                 printk(" parallel interface at 0x%x", dev->ptt_out.pariobase);
00341         if (dev->ptt_out.flags & SP_MIDI)
00342                 printk(" mpu401 (midi) interface at 0x%x", dev->ptt_out.midiiobase);
00343         if (!dev->ptt_out.flags)
00344                 printk(" none");
00345         printk("\n");
00346 }
00347 
00348 /* --------------------------------------------------------------------- */
00349 
00350 static void output_close(struct hfmodem_state *dev)
00351 {
00352         /* release regions used for PTT output */
00353         output_status(dev, 0);
00354         if (dev->ptt_out.flags & SP_SER)
00355                 release_region(dev->ptt_out.seriobase, SER_EXTENT);
00356         if (dev->ptt_out.flags & SP_PAR)
00357                 parport_release(dev->ptt_out.pardev);
00358         if (dev->ptt_out.flags & SP_MIDI)
00359                 release_region(dev->ptt_out.midiiobase, MIDI_EXTENT);
00360         dev->ptt_out.flags = 0;
00361 }
00362 
00363 /* --------------------------------------------------------------------- */
00364 
00365 #define INC_SAMPLE   (1000000/HFMODEM_SRATE)
00366 #define INC_FRAGMENT (HFMODEM_FRAGSAMPLES*1000000/HFMODEM_SRATE)
00367 #define SIZE         (HFMODEM_FRAGSAMPLES*HFMODEM_NUMFRAGS)
00368 
00369 static void hfmodem_interrupt(int irq, void *dev_id, struct pt_regs *regs)
00370 {
00371         struct hfmodem_state *dev = (struct hfmodem_state *)dev_id;
00372         unsigned int dmaptr;
00373         __s16 *s;
00374         unsigned int curfrag, nfrags;
00375         int i;
00376         hfmodem_time_t l1time;
00377 
00378         dmaptr = dev->scops->intack(dev);
00379         l1time = hfmodem_refclock_current(dev, ((SIZE+dmaptr-dev->dma.last_dmaptr) % SIZE) * 
00380                                           INC_SAMPLE, 1);
00381         curfrag = (dev->dma.last_dmaptr = dmaptr) / HFMODEM_FRAGSAMPLES;
00382         l1time -= INC_SAMPLE * (SIZE+dmaptr-dev->dma.fragptr*HFMODEM_FRAGSAMPLES) % SIZE;
00383         sti();
00384         /*
00385          * handle receiving
00386          */
00387         if (dev->dma.ptt_frames <= 0) {
00388                 while (dev->dma.fragptr != curfrag) {
00389                         if (dev->dma.fragptr < HFMODEM_EXCESSFRAGS) {
00390                                 s = dev->dma.buf + SIZE + HFMODEM_FRAGSAMPLES * dev->dma.fragptr;
00391                                 memcpy(s, s - SIZE, HFMODEM_FRAGSIZE);
00392                         } else
00393                                 s = dev->dma.buf + HFMODEM_FRAGSAMPLES * dev->dma.fragptr;
00394                         if (dev->sbuf.kbuf && dev->sbuf.kptr && dev->sbuf.rem > 0) {
00395                                 i = HFMODEM_FRAGSAMPLES;
00396                                 if (i > dev->sbuf.rem)
00397                                         i = dev->sbuf.rem;
00398                                 memcpy(dev->sbuf.kptr, s, i * sizeof(s[0]));
00399                                 dev->sbuf.rem -= i;
00400                                 dev->sbuf.kptr += i;
00401                         }
00402                         hfmodem_input_samples(dev, l1time, INC_SAMPLE, s);
00403                         l1time += INC_FRAGMENT;
00404                         dev->dma.fragptr++;
00405                         if (dev->dma.fragptr >= HFMODEM_NUMFRAGS)
00406                                 dev->dma.fragptr = 0;
00407                 }
00408                 /*
00409                  * check for output
00410                  */
00411                 if (hfmodem_next_tx_event(dev, l1time) > (long)INC_FRAGMENT/2)
00412                         goto int_return;
00413                 /*
00414                  * start output
00415                  */
00416                 output_status(dev, 1);
00417                 dev->scops->prepare_output(dev);
00418                 dev->dma.last_dmaptr = 0;
00419                 /*
00420                  * clock adjust
00421                  */
00422                 l1time = hfmodem_refclock_current(dev, 0, 0);
00423                 /*
00424                  * fill first two fragments
00425                  */
00426                 dev->dma.ptt_frames = 1;
00427                 for (i = 0; i < 2 && i < HFMODEM_NUMFRAGS; i++)
00428                         if (hfmodem_output_samples(dev, l1time+i*INC_FRAGMENT, INC_SAMPLE, 
00429                                                    dev->dma.buf+i*HFMODEM_FRAGSAMPLES))
00430                                 dev->dma.ptt_frames = i + 1;
00431                 dev->dma.lastfrag = 0;
00432                 dev->scops->trigger_output(dev);
00433                 /*
00434                  * finish already pending rx requests
00435                  */
00436                 hfmodem_finish_pending_rx_requests(dev);
00437                 goto int_return;
00438         }
00439         /*
00440          * handle transmitting
00441          */
00442         nfrags = HFMODEM_NUMFRAGS + curfrag - dev->dma.lastfrag;
00443         dev->dma.lastfrag = curfrag;
00444         if (nfrags >= HFMODEM_NUMFRAGS)
00445                 nfrags -= HFMODEM_NUMFRAGS;
00446         dev->dma.ptt_frames -= nfrags;
00447         if (dev->dma.ptt_frames < 0)
00448                 dev->dma.ptt_frames = 0;
00449         while (dev->dma.ptt_frames < HFMODEM_NUMFRAGS && dev->dma.ptt_frames < 4 && 
00450                hfmodem_output_samples(dev, l1time+dev->dma.ptt_frames*INC_FRAGMENT, 
00451                                       INC_SAMPLE, dev->dma.buf + HFMODEM_FRAGSAMPLES * 
00452                                       ((curfrag + dev->dma.ptt_frames) % HFMODEM_NUMFRAGS)))
00453                 dev->dma.ptt_frames++;
00454         if (dev->dma.ptt_frames > 0)
00455                 goto int_return;
00456         /* 
00457          * start receiving
00458          */
00459         output_status(dev, 0);
00460         dev->dma.last_dmaptr = 0;
00461         dev->dma.lastfrag = 0;
00462         dev->dma.fragptr = 0;
00463         dev->dma.ptt_frames = 0;
00464         dev->scops->prepare_input(dev);
00465         dev->scops->trigger_input(dev);
00466         hfmodem_refclock_current(dev, 0, 0);  /* needed to reset the time difference */
00467 int_return:
00468         hfmodem_wakeup(dev);
00469 }
00470 
00471 /* --------------------------------------------------------------------- */
00472 
00473 static int hfmodem_close(struct inode *inode, struct file *file)
00474 {
00475         struct hfmodem_state *dev = &hfmodem_state[0];
00476 
00477         if (!dev->active)
00478                 return -EPERM;
00479         dev->active = 0;
00480         dev->scops->stop(dev);
00481         free_irq(dev->io.irq, dev);        
00482         disable_dma(dev->io.dma);
00483         free_dma(dev->io.dma);
00484         release_region(dev->io.base_addr, dev->scops->extent);
00485         kfree_s(dev->dma.buf, HFMODEM_FRAGSIZE * (HFMODEM_NUMFRAGS+HFMODEM_EXCESSFRAGS));
00486         hfmodem_clear_rq(dev);
00487         if (dev->sbuf.kbuf) {
00488                 kfree_s(dev->sbuf.kbuf, dev->sbuf.size);
00489                 dev->sbuf.kbuf = dev->sbuf.kptr = NULL;
00490                 dev->sbuf.size = dev->sbuf.rem = 0;
00491         }
00492         output_close(dev);
00493         MOD_DEC_USE_COUNT;
00494         return 0;
00495 }
00496 
00497 /* --------------------------------------------------------------------- */
00498 
00499 static int hfmodem_open(struct inode *inode, struct file *file)
00500 {
00501         struct hfmodem_state *dev = &hfmodem_state[0];
00502 
00503         if (dev->active)
00504                 return -EBUSY;
00505         if (!dev->scops)
00506                 return -EPERM;
00507         /*
00508          * clear vars
00509          */
00510         memset(&dev->l1, 0, sizeof(dev->l1));
00511         dev->dma.last_dmaptr = 0;
00512         dev->dma.lastfrag = 0;
00513         dev->dma.fragptr = 0;
00514         dev->dma.ptt_frames = 0;
00515         /*
00516          * allocate memory
00517          */
00518         if (!(dev->dma.buf = kmalloc(HFMODEM_FRAGSIZE * (HFMODEM_NUMFRAGS+HFMODEM_EXCESSFRAGS), GFP_KERNEL | GFP_DMA)))
00519                 return -ENOMEM;
00520         /*
00521          * allocate resources
00522          */
00523         if (request_dma(dev->io.dma, hfmodem_drvname)) {
00524                 kfree_s(dev->dma.buf, HFMODEM_FRAGSIZE * (HFMODEM_NUMFRAGS+HFMODEM_EXCESSFRAGS));
00525                 return -EBUSY;
00526         }
00527         if (request_irq(dev->io.irq, hfmodem_interrupt, SA_INTERRUPT, hfmodem_drvname, dev)) {
00528                 free_dma(dev->io.dma);
00529                 kfree_s(dev->dma.buf, HFMODEM_FRAGSIZE * (HFMODEM_NUMFRAGS+HFMODEM_EXCESSFRAGS));
00530                 return -EBUSY;
00531         }
00532         request_region(dev->io.base_addr, dev->scops->extent, hfmodem_drvname);
00533         
00534         /* clear requests */
00535         dev->active++;
00536         MOD_INC_USE_COUNT;
00537         hfmodem_refclock_init(dev);
00538         output_open(dev);
00539         dev->scops->init(dev);
00540         dev->scops->prepare_input(dev);
00541         dev->scops->trigger_input(dev);
00542         return 0;
00543 }
00544 
00545 /* --------------------------------------------------------------------- */
00546 
00547 static struct file_operations hfmodem_fops = {
00548         NULL,               /* hfmodem_seek */
00549         NULL,               /* hfmodem_read */
00550         NULL,               /* hfmodem_write */
00551         NULL,               /* hfmodem_readdir */
00552 #if LINUX_VERSION_CODE >= 0x20100
00553         hfmodem_poll,       /* hfmodem_poll */
00554 #else 
00555         hfmodem_select,     /* hfmodem_select */
00556 #endif
00557         hfmodem_ioctl,      /* hfmodem_ioctl */
00558         NULL,               /* hfmodem_mmap */
00559         hfmodem_open,       /* hfmodem_open */
00560         NULL,               /* flush */
00561         hfmodem_close,      /* hfmodem_close */
00562         NULL,               /* hfmodem_fsync */
00563         NULL,               /* hfmodem_fasync */
00564         NULL,               /* hfmodem_check_media_change */
00565         NULL                /* hfmodem_revalidate */
00566 };
00567 
00568 /* --------------------------------------------------------------------- */
00569 
00570 static struct miscdevice hfmodem_device = {
00571         HFMODEM_MINOR, hfmodem_drvname, &hfmodem_fops
00572 };
00573 
00574 /* --------------------------------------------------------------------- */
00575 
00576 #ifdef MODULE
00577 
00578 /*
00579  * Command line parameters
00580  */
00581 
00582 static int hw = 0;
00583 static unsigned int iobase = 0x220;
00584 static unsigned int irq = 7;
00585 static unsigned int dma = 1;
00586 
00587 static unsigned int serio = 0;
00588 static unsigned int pario = 0;
00589 static unsigned int midiio = 0;
00590 
00591 #if LINUX_VERSION_CODE >= 0x20115
00592 
00593 MODULE_PARM(hw, "i");
00594 MODULE_PARM_DESC(hw, "hardware type: 0=SBC, 1=WSS");
00595 MODULE_PARM(iobase, "i");
00596 MODULE_PARM_DESC(iobase, "io base address");
00597 MODULE_PARM(irq, "i");
00598 MODULE_PARM_DESC(irq, "interrupt number");
00599 MODULE_PARM(dma, "i");
00600 MODULE_PARM_DESC(dma, "dma number (>=4 for SB16/32/64/etc, <=3 for the rest)");
00601 MODULE_PARM(serio, "i");
00602 MODULE_PARM_DESC(serio, "address of serial port to output PTT");
00603 MODULE_PARM(pario, "i");
00604 MODULE_PARM_DESC(pario, "address of parallel port to output PTT");
00605 MODULE_PARM(midiio, "i");
00606 MODULE_PARM_DESC(midiio, "address of midi (MPU401) port to output PTT");
00607 
00608 MODULE_AUTHOR("Thomas M. Sailer, sailer@ife.ee.ethz.ch, hb9jnx@hb9w.che.eu");
00609 MODULE_DESCRIPTION("HF FSK modem code");
00610 
00611 /* these are the module parameters from refclock.c */
00612 
00613 MODULE_PARM(scale_tvusec, "i");
00614 MODULE_PARM_DESC(scale_tvusec, "Scaling value for the tv_usec field (can be obta
00615 ined by refclock)");
00616 
00617 #ifdef __i386__
00618 MODULE_PARM(scale_rdtsc, "i");
00619 MODULE_PARM_DESC(scale_rdtsc, "Scaling value for the rdtsc counter (can be obtai
00620 ned by refclock)");
00621 MODULE_PARM(rdtsc_ok, "i");
00622 MODULE_PARM_DESC(rdtsc_ok, "Set to 0 to disable the use of the rdtsc instruction
00623 ");
00624 #endif /* __i386__ */
00625 
00626 #endif
00627 
00628 __initfunc(int init_module(void))
00629 {
00630         int i;
00631 
00632         printk(hfmodem_drvinfo);
00633         memset(hfmodem_state, 0, sizeof(hfmodem_state));
00634         memset(hfmodem_correlator_cache, 0, sizeof(hfmodem_correlator_cache));
00635         hfmodem_state[0].io.base_addr = iobase;
00636         hfmodem_state[0].io.irq = irq;
00637         hfmodem_state[0].io.dma = dma;
00638         hfmodem_state[0].ptt_out.seriobase = serio;
00639         hfmodem_state[0].ptt_out.pariobase = pario;
00640         hfmodem_state[0].ptt_out.midiiobase = midiio;
00641         hfmodem_refclock_probe();
00642         output_check(&hfmodem_state[0]);
00643 #if defined(CONFIG_HFMODEM_WSS) && defined(CONFIG_HFMODEM_SBC)
00644         if (hw) 
00645                 i = hfmodem_wssprobe(&hfmodem_state[0]);
00646         else
00647                 i = hfmodem_sbcprobe(&hfmodem_state[0]);
00648 #else
00649         i = -EINVAL;
00650 #ifdef CONFIG_HFMODEM_WSS
00651         i = hfmodem_wssprobe(&hfmodem_state[0]);
00652 #endif
00653 #ifdef CONFIG_HFMODEM_SBC
00654         i = hfmodem_sbcprobe(&hfmodem_state[0]);
00655 #endif
00656 #endif
00657         if (i)
00658                 return i;
00659         if ((i =  misc_register(&hfmodem_device))) {
00660                 printk(KERN_ERR "%s: cannot register misc device\n", hfmodem_drvname);
00661                 return i;
00662         }
00663         return 0;
00664 }
00665 
00666 void cleanup_module(void)
00667 {
00668         struct hfmodem_state *dev = &hfmodem_state[0];
00669 
00670         if (dev->ptt_out.pariobase > 0)
00671                 parport_unregister_device(dev->ptt_out.pardev);
00672         misc_deregister(&hfmodem_device);
00673 }
00674 
00675 #else /* MODULE */
00676 /* --------------------------------------------------------------------- */
00677 
00678 static int hw = 0;
00679 
00680 __initfunc(void hfmodem_setup(char *str, int *ints))
00681 {
00682         if (ints[0] < 7) {
00683                 printk(KERN_WARNING "%s: setup: too few parameters\n", hfmodem_drvname);
00684                 return;
00685         }       
00686         memset(hfmodem_state, 0, sizeof(hfmodem_state));
00687         memset(hfmodem_correlator_cache, 0, sizeof(hfmodem_correlator_cache));
00688         hw = ints[1];
00689         hfmodem_state[0].io.base_addr = ints[2];
00690         hfmodem_state[0].io.irq = ints[3];
00691         hfmodem_state[0].io.dma = ints[4];
00692         if (ints[0] >= 8)
00693                 hfmodem_state[0].ptt_out.seriobase = ints[5];
00694         if (ints[0] >= 9)
00695                 hfmodem_state[0].ptt_out.pariobase = ints[6];
00696         if (ints[0] >= 10)
00697                 hfmodem_state[0].ptt_out.midiiobase = ints[7];
00698         hfmodem_refclock_setscale(ints[ints[0]-2], ints[ints[0]-1], ints[ints[0]]);
00699 }
00700 
00701 __initfunc(void hfmodem_init(void))
00702 {
00703         int i;
00704 
00705         printk(hfmodem_drvinfo);
00706         hfmodem_refclock_probe();
00707         output_check(&hfmodem_state[0]);
00708 #if defined(CONFIG_HFMODEM_WSS) && defined(CONFIG_HFMODEM_SBC)
00709         if (hw) 
00710                 i = hfmodem_wssprobe(&hfmodem_state[0]);
00711         else
00712                 i = hfmodem_sbcprobe(&hfmodem_state[0]);
00713 #else
00714         i = -EINVAL;
00715 #ifdef CONFIG_HFMODEM_WSS
00716         i = hfmodem_wssprobe(&hfmodem_state[0]);
00717 #endif
00718 #ifdef CONFIG_HFMODEM_SBC
00719         i = hfmodem_sbcprobe(&hfmodem_state[0]);
00720 #endif
00721 #endif
00722         if (i) {
00723                 printk(KERN_ERR "%s: soundcard probe failed\n", hfmodem_drvname);
00724                 return;
00725         }
00726         if ((i =  misc_register(&hfmodem_device))) {
00727                 printk(KERN_ERR "%s: cannot register misc device\n", hfmodem_drvname);
00728                 return;
00729         }
00730 }
00731 
00732 /* --------------------------------------------------------------------- */
00733 #endif /* MODULE */