1 /*********************************************************************
5 * Turtle Beach MultiSound Sound Card Driver for Linux
7 * Copyright (C) 1998 Andrew Veliath
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 * $Id: msnd.c,v 1.17 1999/03/21 16:50:09 andrewtv Exp $
25 ********************************************************************/
27 #include <linux/version.h>
28 #include <linux/module.h>
29 #include <linux/kernel.h>
30 #include <linux/slab.h>
31 #include <linux/vmalloc.h>
32 #include <linux/types.h>
33 #include <linux/delay.h>
35 #include <linux/init.h>
37 #include <asm/uaccess.h>
38 #include <linux/spinlock.h>
42 #define LOGNAME "msnd"
44 #define MSND_MAX_DEVS 4
46 static multisound_dev_t *devs[MSND_MAX_DEVS];
49 int __init msnd_register(multisound_dev_t *dev)
53 for (i = 0; i < MSND_MAX_DEVS; ++i)
57 if (i == MSND_MAX_DEVS)
65 void msnd_unregister(multisound_dev_t *dev)
69 for (i = 0; i < MSND_MAX_DEVS; ++i)
73 if (i == MSND_MAX_DEVS) {
74 printk(KERN_WARNING LOGNAME ": Unregistering unknown device\n");
82 void msnd_init_queue(unsigned long base, int start, int size)
84 isa_writew(PCTODSP_BASED(start), base + JQS_wStart);
85 isa_writew(PCTODSP_OFFSET(size) - 1, base + JQS_wSize);
86 isa_writew(0, base + JQS_wHead);
87 isa_writew(0, base + JQS_wTail);
90 void msnd_fifo_init(msnd_fifo *f)
95 void msnd_fifo_free(msnd_fifo *f)
103 int msnd_fifo_alloc(msnd_fifo *f, size_t n)
106 f->data = (char *)vmalloc(n);
118 void msnd_fifo_make_empty(msnd_fifo *f)
120 f->len = f->tail = f->head = 0;
123 int msnd_fifo_write(msnd_fifo *f, const char *buf, size_t len)
127 while ((count < len) && (f->len != f->n)) {
131 if (f->head <= f->tail) {
132 nwritten = len - count;
133 if (nwritten > f->n - f->tail)
134 nwritten = f->n - f->tail;
137 nwritten = f->head - f->tail;
138 if (nwritten > len - count)
139 nwritten = len - count;
142 isa_memcpy_fromio(f->data + f->tail, (unsigned long) buf, nwritten);
154 int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len)
158 while ((count < len) && (f->len > 0)) {
162 if (f->tail <= f->head) {
164 if (nread > f->n - f->head)
165 nread = f->n - f->head;
168 nread = f->tail - f->head;
169 if (nread > len - count)
173 isa_memcpy_toio((unsigned long) buf, f->data + f->head, nread);
185 static int msnd_wait_TXDE(multisound_dev_t *dev)
187 register unsigned int io = dev->io;
188 register int timeout = 1000;
191 if (msnd_inb(io + HP_ISR) & HPISR_TXDE)
197 static int msnd_wait_HC0(multisound_dev_t *dev)
199 register unsigned int io = dev->io;
200 register int timeout = 1000;
203 if (!(msnd_inb(io + HP_CVR) & HPCVR_HC))
209 int msnd_send_dsp_cmd(multisound_dev_t *dev, BYTE cmd)
213 spin_lock_irqsave(&dev->lock, flags);
214 if (msnd_wait_HC0(dev) == 0) {
215 msnd_outb(cmd, dev->io + HP_CVR);
216 spin_unlock_irqrestore(&dev->lock, flags);
219 spin_unlock_irqrestore(&dev->lock, flags);
221 printk(KERN_DEBUG LOGNAME ": Send DSP command timeout\n");
226 int msnd_send_word(multisound_dev_t *dev, unsigned char high,
227 unsigned char mid, unsigned char low)
229 register unsigned int io = dev->io;
231 if (msnd_wait_TXDE(dev) == 0) {
232 msnd_outb(high, io + HP_TXH);
233 msnd_outb(mid, io + HP_TXM);
234 msnd_outb(low, io + HP_TXL);
238 printk(KERN_DEBUG LOGNAME ": Send host word timeout\n");
243 int msnd_upload_host(multisound_dev_t *dev, char *bin, int len)
248 printk(KERN_WARNING LOGNAME ": Upload host data not multiple of 3!\n");
252 for (i = 0; i < len; i += 3)
253 if (msnd_send_word(dev, bin[i], bin[i + 1], bin[i + 2]) != 0)
256 msnd_inb(dev->io + HP_RXL);
257 msnd_inb(dev->io + HP_CVR);
262 int msnd_enable_irq(multisound_dev_t *dev)
269 printk(KERN_DEBUG LOGNAME ": Enabling IRQ\n");
271 spin_lock_irqsave(&dev->lock, flags);
272 if (msnd_wait_TXDE(dev) == 0) {
273 msnd_outb(msnd_inb(dev->io + HP_ICR) | HPICR_TREQ, dev->io + HP_ICR);
274 if (dev->type == msndClassic)
275 msnd_outb(dev->irqid, dev->io + HP_IRQM);
276 msnd_outb(msnd_inb(dev->io + HP_ICR) & ~HPICR_TREQ, dev->io + HP_ICR);
277 msnd_outb(msnd_inb(dev->io + HP_ICR) | HPICR_RREQ, dev->io + HP_ICR);
278 enable_irq(dev->irq);
279 msnd_init_queue(dev->DSPQ, dev->dspq_data_buff, dev->dspq_buff_size);
280 spin_unlock_irqrestore(&dev->lock, flags);
283 spin_unlock_irqrestore(&dev->lock, flags);
285 printk(KERN_DEBUG LOGNAME ": Enable IRQ failed\n");
290 int msnd_disable_irq(multisound_dev_t *dev)
294 if (--dev->irq_ref > 0)
297 if (dev->irq_ref < 0)
298 printk(KERN_DEBUG LOGNAME ": IRQ ref count is %d\n", dev->irq_ref);
300 printk(KERN_DEBUG LOGNAME ": Disabling IRQ\n");
302 spin_lock_irqsave(&dev->lock, flags);
303 if (msnd_wait_TXDE(dev) == 0) {
304 msnd_outb(msnd_inb(dev->io + HP_ICR) & ~HPICR_RREQ, dev->io + HP_ICR);
305 if (dev->type == msndClassic)
306 msnd_outb(HPIRQ_NONE, dev->io + HP_IRQM);
307 disable_irq(dev->irq);
308 spin_unlock_irqrestore(&dev->lock, flags);
311 spin_unlock_irqrestore(&dev->lock, flags);
313 printk(KERN_DEBUG LOGNAME ": Disable IRQ failed\n");
319 EXPORT_SYMBOL(msnd_register);
320 EXPORT_SYMBOL(msnd_unregister);
322 EXPORT_SYMBOL(msnd_init_queue);
324 EXPORT_SYMBOL(msnd_fifo_init);
325 EXPORT_SYMBOL(msnd_fifo_free);
326 EXPORT_SYMBOL(msnd_fifo_alloc);
327 EXPORT_SYMBOL(msnd_fifo_make_empty);
328 EXPORT_SYMBOL(msnd_fifo_write);
329 EXPORT_SYMBOL(msnd_fifo_read);
331 EXPORT_SYMBOL(msnd_send_dsp_cmd);
332 EXPORT_SYMBOL(msnd_send_word);
333 EXPORT_SYMBOL(msnd_upload_host);
335 EXPORT_SYMBOL(msnd_enable_irq);
336 EXPORT_SYMBOL(msnd_disable_irq);
340 MODULE_AUTHOR ("Andrew Veliath <andrewtv@usa.net>");
341 MODULE_DESCRIPTION ("Turtle Beach MultiSound Driver Base");
342 MODULE_LICENSE("GPL");
345 int init_module(void)
350 void cleanup_module(void)