linux/sound/isa/msnd/msnd_pinnacle.c
<<
>>
Prefs
   1/*********************************************************************
   2 *
   3 * Linux multisound pinnacle/fiji driver for ALSA.
   4 *
   5 * 2002/06/30 Karsten Wiese:
   6 *      for now this is only used to build a pinnacle / fiji driver.
   7 *      the OSS parent of this code is designed to also support
   8 *      the multisound classic via the file msnd_classic.c.
   9 *      to make it easier for some brave heart to implemt classic
  10 *      support in alsa, i left all the MSND_CLASSIC tokens in this file.
  11 *      but for now this untested & undone.
  12 *
  13 *
  14 * ripped from linux kernel 2.4.18 by Karsten Wiese.
  15 *
  16 * the following is a copy of the 2.4.18 OSS FREE file-heading comment:
  17 *
  18 * Turtle Beach MultiSound Sound Card Driver for Linux
  19 * msnd_pinnacle.c / msnd_classic.c
  20 *
  21 * -- If MSND_CLASSIC is defined:
  22 *
  23 *     -> driver for Turtle Beach Classic/Monterey/Tahiti
  24 *
  25 * -- Else
  26 *
  27 *     -> driver for Turtle Beach Pinnacle/Fiji
  28 *
  29 * 12-3-2000  Modified IO port validation  Steve Sycamore
  30 *
  31 * Copyright (C) 1998 Andrew Veliath
  32 *
  33 * This program is free software; you can redistribute it and/or modify
  34 * it under the terms of the GNU General Public License as published by
  35 * the Free Software Foundation; either version 2 of the License, or
  36 * (at your option) any later version.
  37 *
  38 * This program is distributed in the hope that it will be useful,
  39 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  40 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  41 * GNU General Public License for more details.
  42 *
  43 * You should have received a copy of the GNU General Public License
  44 * along with this program; if not, write to the Free Software
  45 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  46 *
  47 ********************************************************************/
  48
  49#include <linux/kernel.h>
  50#include <linux/module.h>
  51#include <linux/interrupt.h>
  52#include <linux/types.h>
  53#include <linux/delay.h>
  54#include <linux/ioport.h>
  55#include <linux/firmware.h>
  56#include <linux/isa.h>
  57#include <linux/isapnp.h>
  58#include <linux/irq.h>
  59#include <linux/io.h>
  60
  61#include <sound/core.h>
  62#include <sound/initval.h>
  63#include <sound/asound.h>
  64#include <sound/pcm.h>
  65#include <sound/mpu401.h>
  66
  67#ifdef MSND_CLASSIC
  68# ifndef __alpha__
  69#  define SLOWIO
  70# endif
  71#endif
  72#include "msnd.h"
  73#ifdef MSND_CLASSIC
  74#  include "msnd_classic.h"
  75#  define LOGNAME                       "msnd_classic"
  76#  define DEV_NAME                      "msnd-classic"
  77#else
  78#  include "msnd_pinnacle.h"
  79#  define LOGNAME                       "snd_msnd_pinnacle"
  80#  define DEV_NAME                      "msnd-pinnacle"
  81#endif
  82
  83static void set_default_audio_parameters(struct snd_msnd *chip)
  84{
  85        chip->play_sample_size = DEFSAMPLESIZE;
  86        chip->play_sample_rate = DEFSAMPLERATE;
  87        chip->play_channels = DEFCHANNELS;
  88        chip->capture_sample_size = DEFSAMPLESIZE;
  89        chip->capture_sample_rate = DEFSAMPLERATE;
  90        chip->capture_channels = DEFCHANNELS;
  91}
  92
  93static void snd_msnd_eval_dsp_msg(struct snd_msnd *chip, u16 wMessage)
  94{
  95        switch (HIBYTE(wMessage)) {
  96        case HIMT_PLAY_DONE: {
  97                if (chip->banksPlayed < 3)
  98                        snd_printdd("%08X: HIMT_PLAY_DONE: %i\n",
  99                                (unsigned)jiffies, LOBYTE(wMessage));
 100
 101                if (chip->last_playbank == LOBYTE(wMessage)) {
 102                        snd_printdd("chip.last_playbank == LOBYTE(wMessage)\n");
 103                        break;
 104                }
 105                chip->banksPlayed++;
 106
 107                if (test_bit(F_WRITING, &chip->flags))
 108                        snd_msnd_DAPQ(chip, 0);
 109
 110                chip->last_playbank = LOBYTE(wMessage);
 111                chip->playDMAPos += chip->play_period_bytes;
 112                if (chip->playDMAPos > chip->playLimit)
 113                        chip->playDMAPos = 0;
 114                snd_pcm_period_elapsed(chip->playback_substream);
 115
 116                break;
 117        }
 118        case HIMT_RECORD_DONE:
 119                if (chip->last_recbank == LOBYTE(wMessage))
 120                        break;
 121                chip->last_recbank = LOBYTE(wMessage);
 122                chip->captureDMAPos += chip->capturePeriodBytes;
 123                if (chip->captureDMAPos > (chip->captureLimit))
 124                        chip->captureDMAPos = 0;
 125
 126                if (test_bit(F_READING, &chip->flags))
 127                        snd_msnd_DARQ(chip, chip->last_recbank);
 128
 129                snd_pcm_period_elapsed(chip->capture_substream);
 130                break;
 131
 132        case HIMT_DSP:
 133                switch (LOBYTE(wMessage)) {
 134#ifndef MSND_CLASSIC
 135                case HIDSP_PLAY_UNDER:
 136#endif
 137                case HIDSP_INT_PLAY_UNDER:
 138                        snd_printd(KERN_WARNING LOGNAME ": Play underflow %i\n",
 139                                chip->banksPlayed);
 140                        if (chip->banksPlayed > 2)
 141                                clear_bit(F_WRITING, &chip->flags);
 142                        break;
 143
 144                case HIDSP_INT_RECORD_OVER:
 145                        snd_printd(KERN_WARNING LOGNAME ": Record overflow\n");
 146                        clear_bit(F_READING, &chip->flags);
 147                        break;
 148
 149                default:
 150                        snd_printd(KERN_WARNING LOGNAME
 151                                   ": DSP message %d 0x%02x\n",
 152                                   LOBYTE(wMessage), LOBYTE(wMessage));
 153                        break;
 154                }
 155                break;
 156
 157        case HIMT_MIDI_IN_UCHAR:
 158                if (chip->msndmidi_mpu)
 159                        snd_msndmidi_input_read(chip->msndmidi_mpu);
 160                break;
 161
 162        default:
 163                snd_printd(KERN_WARNING LOGNAME ": HIMT message %d 0x%02x\n",
 164                           HIBYTE(wMessage), HIBYTE(wMessage));
 165                break;
 166        }
 167}
 168
 169static irqreturn_t snd_msnd_interrupt(int irq, void *dev_id)
 170{
 171        struct snd_msnd *chip = dev_id;
 172        void *pwDSPQData = chip->mappedbase + DSPQ_DATA_BUFF;
 173
 174        /* Send ack to DSP */
 175        /* inb(chip->io + HP_RXL); */
 176
 177        /* Evaluate queued DSP messages */
 178        while (readw(chip->DSPQ + JQS_wTail) != readw(chip->DSPQ + JQS_wHead)) {
 179                u16 wTmp;
 180
 181                snd_msnd_eval_dsp_msg(chip,
 182                        readw(pwDSPQData + 2 * readw(chip->DSPQ + JQS_wHead)));
 183
 184                wTmp = readw(chip->DSPQ + JQS_wHead) + 1;
 185                if (wTmp > readw(chip->DSPQ + JQS_wSize))
 186                        writew(0, chip->DSPQ + JQS_wHead);
 187                else
 188                        writew(wTmp, chip->DSPQ + JQS_wHead);
 189        }
 190        /* Send ack to DSP */
 191        inb(chip->io + HP_RXL);
 192        return IRQ_HANDLED;
 193}
 194
 195
 196static int snd_msnd_reset_dsp(long io, unsigned char *info)
 197{
 198        int timeout = 100;
 199
 200        outb(HPDSPRESET_ON, io + HP_DSPR);
 201        msleep(1);
 202#ifndef MSND_CLASSIC
 203        if (info)
 204                *info = inb(io + HP_INFO);
 205#endif
 206        outb(HPDSPRESET_OFF, io + HP_DSPR);
 207        msleep(1);
 208        while (timeout-- > 0) {
 209                if (inb(io + HP_CVR) == HP_CVR_DEF)
 210                        return 0;
 211                msleep(1);
 212        }
 213        snd_printk(KERN_ERR LOGNAME ": Cannot reset DSP\n");
 214
 215        return -EIO;
 216}
 217
 218static int snd_msnd_probe(struct snd_card *card)
 219{
 220        struct snd_msnd *chip = card->private_data;
 221        unsigned char info;
 222#ifndef MSND_CLASSIC
 223        char *xv, *rev = NULL;
 224        char *pin = "TB Pinnacle", *fiji = "TB Fiji";
 225        char *pinfiji = "TB Pinnacle/Fiji";
 226#endif
 227
 228        if (!request_region(chip->io, DSP_NUMIO, "probing")) {
 229                snd_printk(KERN_ERR LOGNAME ": I/O port conflict\n");
 230                return -ENODEV;
 231        }
 232
 233        if (snd_msnd_reset_dsp(chip->io, &info) < 0) {
 234                release_region(chip->io, DSP_NUMIO);
 235                return -ENODEV;
 236        }
 237
 238#ifdef MSND_CLASSIC
 239        strcpy(card->shortname, "Classic/Tahiti/Monterey");
 240        strcpy(card->longname, "Turtle Beach Multisound");
 241        printk(KERN_INFO LOGNAME ": %s, "
 242               "I/O 0x%lx-0x%lx, IRQ %d, memory mapped to 0x%lX-0x%lX\n",
 243               card->shortname,
 244               chip->io, chip->io + DSP_NUMIO - 1,
 245               chip->irq,
 246               chip->base, chip->base + 0x7fff);
 247#else
 248        switch (info >> 4) {
 249        case 0xf:
 250                xv = "<= 1.15";
 251                break;
 252        case 0x1:
 253                xv = "1.18/1.2";
 254                break;
 255        case 0x2:
 256                xv = "1.3";
 257                break;
 258        case 0x3:
 259                xv = "1.4";
 260                break;
 261        default:
 262                xv = "unknown";
 263                break;
 264        }
 265
 266        switch (info & 0x7) {
 267        case 0x0:
 268                rev = "I";
 269                strcpy(card->shortname, pin);
 270                break;
 271        case 0x1:
 272                rev = "F";
 273                strcpy(card->shortname, pin);
 274                break;
 275        case 0x2:
 276                rev = "G";
 277                strcpy(card->shortname, pin);
 278                break;
 279        case 0x3:
 280                rev = "H";
 281                strcpy(card->shortname, pin);
 282                break;
 283        case 0x4:
 284                rev = "E";
 285                strcpy(card->shortname, fiji);
 286                break;
 287        case 0x5:
 288                rev = "C";
 289                strcpy(card->shortname, fiji);
 290                break;
 291        case 0x6:
 292                rev = "D";
 293                strcpy(card->shortname, fiji);
 294                break;
 295        case 0x7:
 296                rev = "A-B (Fiji) or A-E (Pinnacle)";
 297                strcpy(card->shortname, pinfiji);
 298                break;
 299        }
 300        strcpy(card->longname, "Turtle Beach Multisound Pinnacle");
 301        printk(KERN_INFO LOGNAME ": %s revision %s, Xilinx version %s, "
 302               "I/O 0x%lx-0x%lx, IRQ %d, memory mapped to 0x%lX-0x%lX\n",
 303               card->shortname,
 304               rev, xv,
 305               chip->io, chip->io + DSP_NUMIO - 1,
 306               chip->irq,
 307               chip->base, chip->base + 0x7fff);
 308#endif
 309
 310        release_region(chip->io, DSP_NUMIO);
 311        return 0;
 312}
 313
 314static int snd_msnd_init_sma(struct snd_msnd *chip)
 315{
 316        static int initted;
 317        u16 mastVolLeft, mastVolRight;
 318        unsigned long flags;
 319
 320#ifdef MSND_CLASSIC
 321        outb(chip->memid, chip->io + HP_MEMM);
 322#endif
 323        outb(HPBLKSEL_0, chip->io + HP_BLKS);
 324        /* Motorola 56k shared memory base */
 325        chip->SMA = chip->mappedbase + SMA_STRUCT_START;
 326
 327        if (initted) {
 328                mastVolLeft = readw(chip->SMA + SMA_wCurrMastVolLeft);
 329                mastVolRight = readw(chip->SMA + SMA_wCurrMastVolRight);
 330        } else
 331                mastVolLeft = mastVolRight = 0;
 332        memset_io(chip->mappedbase, 0, 0x8000);
 333
 334        /* Critical section: bank 1 access */
 335        spin_lock_irqsave(&chip->lock, flags);
 336        outb(HPBLKSEL_1, chip->io + HP_BLKS);
 337        memset_io(chip->mappedbase, 0, 0x8000);
 338        outb(HPBLKSEL_0, chip->io + HP_BLKS);
 339        spin_unlock_irqrestore(&chip->lock, flags);
 340
 341        /* Digital audio play queue */
 342        chip->DAPQ = chip->mappedbase + DAPQ_OFFSET;
 343        snd_msnd_init_queue(chip->DAPQ, DAPQ_DATA_BUFF, DAPQ_BUFF_SIZE);
 344
 345        /* Digital audio record queue */
 346        chip->DARQ = chip->mappedbase + DARQ_OFFSET;
 347        snd_msnd_init_queue(chip->DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE);
 348
 349        /* MIDI out queue */
 350        chip->MODQ = chip->mappedbase + MODQ_OFFSET;
 351        snd_msnd_init_queue(chip->MODQ, MODQ_DATA_BUFF, MODQ_BUFF_SIZE);
 352
 353        /* MIDI in queue */
 354        chip->MIDQ = chip->mappedbase + MIDQ_OFFSET;
 355        snd_msnd_init_queue(chip->MIDQ, MIDQ_DATA_BUFF, MIDQ_BUFF_SIZE);
 356
 357        /* DSP -> host message queue */
 358        chip->DSPQ = chip->mappedbase + DSPQ_OFFSET;
 359        snd_msnd_init_queue(chip->DSPQ, DSPQ_DATA_BUFF, DSPQ_BUFF_SIZE);
 360
 361        /* Setup some DSP values */
 362#ifndef MSND_CLASSIC
 363        writew(1, chip->SMA + SMA_wCurrPlayFormat);
 364        writew(chip->play_sample_size, chip->SMA + SMA_wCurrPlaySampleSize);
 365        writew(chip->play_channels, chip->SMA + SMA_wCurrPlayChannels);
 366        writew(chip->play_sample_rate, chip->SMA + SMA_wCurrPlaySampleRate);
 367#endif
 368        writew(chip->play_sample_rate, chip->SMA + SMA_wCalFreqAtoD);
 369        writew(mastVolLeft, chip->SMA + SMA_wCurrMastVolLeft);
 370        writew(mastVolRight, chip->SMA + SMA_wCurrMastVolRight);
 371#ifndef MSND_CLASSIC
 372        writel(0x00010000, chip->SMA + SMA_dwCurrPlayPitch);
 373        writel(0x00000001, chip->SMA + SMA_dwCurrPlayRate);
 374#endif
 375        writew(0x303, chip->SMA + SMA_wCurrInputTagBits);
 376
 377        initted = 1;
 378
 379        return 0;
 380}
 381
 382
 383static int upload_dsp_code(struct snd_card *card)
 384{
 385        struct snd_msnd *chip = card->private_data;
 386        const struct firmware *init_fw = NULL, *perm_fw = NULL;
 387        int err;
 388
 389        outb(HPBLKSEL_0, chip->io + HP_BLKS);
 390
 391        err = request_firmware(&init_fw, INITCODEFILE, card->dev);
 392        if (err < 0) {
 393                printk(KERN_ERR LOGNAME ": Error loading " INITCODEFILE);
 394                goto cleanup1;
 395        }
 396        err = request_firmware(&perm_fw, PERMCODEFILE, card->dev);
 397        if (err < 0) {
 398                printk(KERN_ERR LOGNAME ": Error loading " PERMCODEFILE);
 399                goto cleanup;
 400        }
 401
 402        memcpy_toio(chip->mappedbase, perm_fw->data, perm_fw->size);
 403        if (snd_msnd_upload_host(chip, init_fw->data, init_fw->size) < 0) {
 404                printk(KERN_WARNING LOGNAME ": Error uploading to DSP\n");
 405                err = -ENODEV;
 406                goto cleanup;
 407        }
 408        printk(KERN_INFO LOGNAME ": DSP firmware uploaded\n");
 409        err = 0;
 410
 411cleanup:
 412        release_firmware(perm_fw);
 413cleanup1:
 414        release_firmware(init_fw);
 415        return err;
 416}
 417
 418#ifdef MSND_CLASSIC
 419static void reset_proteus(struct snd_msnd *chip)
 420{
 421        outb(HPPRORESET_ON, chip->io + HP_PROR);
 422        msleep(TIME_PRO_RESET);
 423        outb(HPPRORESET_OFF, chip->io + HP_PROR);
 424        msleep(TIME_PRO_RESET_DONE);
 425}
 426#endif
 427
 428static int snd_msnd_initialize(struct snd_card *card)
 429{
 430        struct snd_msnd *chip = card->private_data;
 431        int err, timeout;
 432
 433#ifdef MSND_CLASSIC
 434        outb(HPWAITSTATE_0, chip->io + HP_WAIT);
 435        outb(HPBITMODE_16, chip->io + HP_BITM);
 436
 437        reset_proteus(chip);
 438#endif
 439        err = snd_msnd_init_sma(chip);
 440        if (err < 0) {
 441                printk(KERN_WARNING LOGNAME ": Cannot initialize SMA\n");
 442                return err;
 443        }
 444
 445        err = snd_msnd_reset_dsp(chip->io, NULL);
 446        if (err < 0)
 447                return err;
 448
 449        err = upload_dsp_code(card);
 450        if (err < 0) {
 451                printk(KERN_WARNING LOGNAME ": Cannot upload DSP code\n");
 452                return err;
 453        }
 454
 455        timeout = 200;
 456
 457        while (readw(chip->mappedbase)) {
 458                msleep(1);
 459                if (!timeout--) {
 460                        snd_printd(KERN_ERR LOGNAME ": DSP reset timeout\n");
 461                        return -EIO;
 462                }
 463        }
 464
 465        snd_msndmix_setup(chip);
 466        return 0;
 467}
 468
 469static int snd_msnd_dsp_full_reset(struct snd_card *card)
 470{
 471        struct snd_msnd *chip = card->private_data;
 472        int rv;
 473
 474        if (test_bit(F_RESETTING, &chip->flags) || ++chip->nresets > 10)
 475                return 0;
 476
 477        set_bit(F_RESETTING, &chip->flags);
 478        snd_msnd_dsp_halt(chip, NULL);  /* Unconditionally halt */
 479
 480        rv = snd_msnd_initialize(card);
 481        if (rv)
 482                printk(KERN_WARNING LOGNAME ": DSP reset failed\n");
 483        snd_msndmix_force_recsrc(chip, 0);
 484        clear_bit(F_RESETTING, &chip->flags);
 485        return rv;
 486}
 487
 488static int snd_msnd_dev_free(struct snd_device *device)
 489{
 490        snd_printdd("snd_msnd_chip_free()\n");
 491        return 0;
 492}
 493
 494static int snd_msnd_send_dsp_cmd_chk(struct snd_msnd *chip, u8 cmd)
 495{
 496        if (snd_msnd_send_dsp_cmd(chip, cmd) == 0)
 497                return 0;
 498        snd_msnd_dsp_full_reset(chip->card);
 499        return snd_msnd_send_dsp_cmd(chip, cmd);
 500}
 501
 502static int snd_msnd_calibrate_adc(struct snd_msnd *chip, u16 srate)
 503{
 504        snd_printdd("snd_msnd_calibrate_adc(%i)\n", srate);
 505        writew(srate, chip->SMA + SMA_wCalFreqAtoD);
 506        if (chip->calibrate_signal == 0)
 507                writew(readw(chip->SMA + SMA_wCurrHostStatusFlags)
 508                       | 0x0001, chip->SMA + SMA_wCurrHostStatusFlags);
 509        else
 510                writew(readw(chip->SMA + SMA_wCurrHostStatusFlags)
 511                       & ~0x0001, chip->SMA + SMA_wCurrHostStatusFlags);
 512        if (snd_msnd_send_word(chip, 0, 0, HDEXAR_CAL_A_TO_D) == 0 &&
 513            snd_msnd_send_dsp_cmd_chk(chip, HDEX_AUX_REQ) == 0) {
 514                schedule_timeout_interruptible(msecs_to_jiffies(333));
 515                return 0;
 516        }
 517        printk(KERN_WARNING LOGNAME ": ADC calibration failed\n");
 518        return -EIO;
 519}
 520
 521/*
 522 * ALSA callback function, called when attempting to open the MIDI device.
 523 */
 524static int snd_msnd_mpu401_open(struct snd_mpu401 *mpu)
 525{
 526        snd_msnd_enable_irq(mpu->private_data);
 527        snd_msnd_send_dsp_cmd(mpu->private_data, HDEX_MIDI_IN_START);
 528        return 0;
 529}
 530
 531static void snd_msnd_mpu401_close(struct snd_mpu401 *mpu)
 532{
 533        snd_msnd_send_dsp_cmd(mpu->private_data, HDEX_MIDI_IN_STOP);
 534        snd_msnd_disable_irq(mpu->private_data);
 535}
 536
 537static long mpu_io[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
 538static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
 539
 540static int snd_msnd_attach(struct snd_card *card)
 541{
 542        struct snd_msnd *chip = card->private_data;
 543        int err;
 544        static struct snd_device_ops ops = {
 545                .dev_free =      snd_msnd_dev_free,
 546                };
 547
 548        err = request_irq(chip->irq, snd_msnd_interrupt, 0, card->shortname,
 549                          chip);
 550        if (err < 0) {
 551                printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", chip->irq);
 552                return err;
 553        }
 554        if (request_region(chip->io, DSP_NUMIO, card->shortname) == NULL) {
 555                free_irq(chip->irq, chip);
 556                return -EBUSY;
 557        }
 558
 559        if (!request_mem_region(chip->base, BUFFSIZE, card->shortname)) {
 560                printk(KERN_ERR LOGNAME
 561                        ": unable to grab memory region 0x%lx-0x%lx\n",
 562                        chip->base, chip->base + BUFFSIZE - 1);
 563                release_region(chip->io, DSP_NUMIO);
 564                free_irq(chip->irq, chip);
 565                return -EBUSY;
 566        }
 567        chip->mappedbase = ioremap_nocache(chip->base, 0x8000);
 568        if (!chip->mappedbase) {
 569                printk(KERN_ERR LOGNAME
 570                        ": unable to map memory region 0x%lx-0x%lx\n",
 571                        chip->base, chip->base + BUFFSIZE - 1);
 572                err = -EIO;
 573                goto err_release_region;
 574        }
 575
 576        err = snd_msnd_dsp_full_reset(card);
 577        if (err < 0)
 578                goto err_release_region;
 579
 580        /* Register device */
 581        err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
 582        if (err < 0)
 583                goto err_release_region;
 584
 585        err = snd_msnd_pcm(card, 0);
 586        if (err < 0) {
 587                printk(KERN_ERR LOGNAME ": error creating new PCM device\n");
 588                goto err_release_region;
 589        }
 590
 591        err = snd_msndmix_new(card);
 592        if (err < 0) {
 593                printk(KERN_ERR LOGNAME ": error creating new Mixer device\n");
 594                goto err_release_region;
 595        }
 596
 597
 598        if (mpu_io[0] != SNDRV_AUTO_PORT) {
 599                struct snd_mpu401 *mpu;
 600
 601                err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
 602                                          mpu_io[0],
 603                                          MPU401_MODE_INPUT |
 604                                          MPU401_MODE_OUTPUT,
 605                                          mpu_irq[0],
 606                                          &chip->rmidi);
 607                if (err < 0) {
 608                        printk(KERN_ERR LOGNAME
 609                                ": error creating new Midi device\n");
 610                        goto err_release_region;
 611                }
 612                mpu = chip->rmidi->private_data;
 613
 614                mpu->open_input = snd_msnd_mpu401_open;
 615                mpu->close_input = snd_msnd_mpu401_close;
 616                mpu->private_data = chip;
 617        }
 618
 619        disable_irq(chip->irq);
 620        snd_msnd_calibrate_adc(chip, chip->play_sample_rate);
 621        snd_msndmix_force_recsrc(chip, 0);
 622
 623        err = snd_card_register(card);
 624        if (err < 0)
 625                goto err_release_region;
 626
 627        return 0;
 628
 629err_release_region:
 630        iounmap(chip->mappedbase);
 631        release_mem_region(chip->base, BUFFSIZE);
 632        release_region(chip->io, DSP_NUMIO);
 633        free_irq(chip->irq, chip);
 634        return err;
 635}
 636
 637
 638static void snd_msnd_unload(struct snd_card *card)
 639{
 640        struct snd_msnd *chip = card->private_data;
 641
 642        iounmap(chip->mappedbase);
 643        release_mem_region(chip->base, BUFFSIZE);
 644        release_region(chip->io, DSP_NUMIO);
 645        free_irq(chip->irq, chip);
 646        snd_card_free(card);
 647}
 648
 649#ifndef MSND_CLASSIC
 650
 651/* Pinnacle/Fiji Logical Device Configuration */
 652
 653static int snd_msnd_write_cfg(int cfg, int reg, int value)
 654{
 655        outb(reg, cfg);
 656        outb(value, cfg + 1);
 657        if (value != inb(cfg + 1)) {
 658                printk(KERN_ERR LOGNAME ": snd_msnd_write_cfg: I/O error\n");
 659                return -EIO;
 660        }
 661        return 0;
 662}
 663
 664static int snd_msnd_write_cfg_io0(int cfg, int num, u16 io)
 665{
 666        if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
 667                return -EIO;
 668        if (snd_msnd_write_cfg(cfg, IREG_IO0_BASEHI, HIBYTE(io)))
 669                return -EIO;
 670        if (snd_msnd_write_cfg(cfg, IREG_IO0_BASELO, LOBYTE(io)))
 671                return -EIO;
 672        return 0;
 673}
 674
 675static int snd_msnd_write_cfg_io1(int cfg, int num, u16 io)
 676{
 677        if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
 678                return -EIO;
 679        if (snd_msnd_write_cfg(cfg, IREG_IO1_BASEHI, HIBYTE(io)))
 680                return -EIO;
 681        if (snd_msnd_write_cfg(cfg, IREG_IO1_BASELO, LOBYTE(io)))
 682                return -EIO;
 683        return 0;
 684}
 685
 686static int snd_msnd_write_cfg_irq(int cfg, int num, u16 irq)
 687{
 688        if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
 689                return -EIO;
 690        if (snd_msnd_write_cfg(cfg, IREG_IRQ_NUMBER, LOBYTE(irq)))
 691                return -EIO;
 692        if (snd_msnd_write_cfg(cfg, IREG_IRQ_TYPE, IRQTYPE_EDGE))
 693                return -EIO;
 694        return 0;
 695}
 696
 697static int snd_msnd_write_cfg_mem(int cfg, int num, int mem)
 698{
 699        u16 wmem;
 700
 701        mem >>= 8;
 702        wmem = (u16)(mem & 0xfff);
 703        if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
 704                return -EIO;
 705        if (snd_msnd_write_cfg(cfg, IREG_MEMBASEHI, HIBYTE(wmem)))
 706                return -EIO;
 707        if (snd_msnd_write_cfg(cfg, IREG_MEMBASELO, LOBYTE(wmem)))
 708                return -EIO;
 709        if (wmem && snd_msnd_write_cfg(cfg, IREG_MEMCONTROL,
 710                                       MEMTYPE_HIADDR | MEMTYPE_16BIT))
 711                return -EIO;
 712        return 0;
 713}
 714
 715static int snd_msnd_activate_logical(int cfg, int num)
 716{
 717        if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
 718                return -EIO;
 719        if (snd_msnd_write_cfg(cfg, IREG_ACTIVATE, LD_ACTIVATE))
 720                return -EIO;
 721        return 0;
 722}
 723
 724static int snd_msnd_write_cfg_logical(int cfg, int num, u16 io0,
 725                                      u16 io1, u16 irq, int mem)
 726{
 727        if (snd_msnd_write_cfg(cfg, IREG_LOGDEVICE, num))
 728                return -EIO;
 729        if (snd_msnd_write_cfg_io0(cfg, num, io0))
 730                return -EIO;
 731        if (snd_msnd_write_cfg_io1(cfg, num, io1))
 732                return -EIO;
 733        if (snd_msnd_write_cfg_irq(cfg, num, irq))
 734                return -EIO;
 735        if (snd_msnd_write_cfg_mem(cfg, num, mem))
 736                return -EIO;
 737        if (snd_msnd_activate_logical(cfg, num))
 738                return -EIO;
 739        return 0;
 740}
 741
 742static int snd_msnd_pinnacle_cfg_reset(int cfg)
 743{
 744        int i;
 745
 746        /* Reset devices if told to */
 747        printk(KERN_INFO LOGNAME ": Resetting all devices\n");
 748        for (i = 0; i < 4; ++i)
 749                if (snd_msnd_write_cfg_logical(cfg, i, 0, 0, 0, 0))
 750                        return -EIO;
 751
 752        return 0;
 753}
 754#endif
 755
 756static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;      /* Index 0-MAX */
 757static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;       /* ID for this card */
 758
 759module_param_array(index, int, NULL, S_IRUGO);
 760MODULE_PARM_DESC(index, "Index value for msnd_pinnacle soundcard.");
 761module_param_array(id, charp, NULL, S_IRUGO);
 762MODULE_PARM_DESC(id, "ID string for msnd_pinnacle soundcard.");
 763
 764static long io[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
 765static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
 766static long mem[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
 767
 768#ifndef MSND_CLASSIC
 769static long cfg[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
 770
 771/* Extra Peripheral Configuration (Default: Disable) */
 772static long ide_io0[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
 773static long ide_io1[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
 774static int ide_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
 775
 776static long joystick_io[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
 777/* If we have the digital daugherboard... */
 778static int digital[SNDRV_CARDS];
 779
 780/* Extra Peripheral Configuration */
 781static int reset[SNDRV_CARDS];
 782#endif
 783
 784static int write_ndelay[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = 1 };
 785
 786static int calibrate_signal;
 787
 788#ifdef CONFIG_PNP
 789static bool isapnp[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
 790module_param_array(isapnp, bool, NULL, 0444);
 791MODULE_PARM_DESC(isapnp, "ISA PnP detection for specified soundcard.");
 792#define has_isapnp(x) isapnp[x]
 793#else
 794#define has_isapnp(x) 0
 795#endif
 796
 797MODULE_AUTHOR("Karsten Wiese <annabellesgarden@yahoo.de>");
 798MODULE_DESCRIPTION("Turtle Beach " LONGNAME " Linux Driver");
 799MODULE_LICENSE("GPL");
 800MODULE_FIRMWARE(INITCODEFILE);
 801MODULE_FIRMWARE(PERMCODEFILE);
 802
 803module_param_array(io, long, NULL, S_IRUGO);
 804MODULE_PARM_DESC(io, "IO port #");
 805module_param_array(irq, int, NULL, S_IRUGO);
 806module_param_array(mem, long, NULL, S_IRUGO);
 807module_param_array(write_ndelay, int, NULL, S_IRUGO);
 808module_param(calibrate_signal, int, S_IRUGO);
 809#ifndef MSND_CLASSIC
 810module_param_array(digital, int, NULL, S_IRUGO);
 811module_param_array(cfg, long, NULL, S_IRUGO);
 812module_param_array(reset, int, 0, S_IRUGO);
 813module_param_array(mpu_io, long, NULL, S_IRUGO);
 814module_param_array(mpu_irq, int, NULL, S_IRUGO);
 815module_param_array(ide_io0, long, NULL, S_IRUGO);
 816module_param_array(ide_io1, long, NULL, S_IRUGO);
 817module_param_array(ide_irq, int, NULL, S_IRUGO);
 818module_param_array(joystick_io, long, NULL, S_IRUGO);
 819#endif
 820
 821
 822static int snd_msnd_isa_match(struct device *pdev, unsigned int i)
 823{
 824        if (io[i] == SNDRV_AUTO_PORT)
 825                return 0;
 826
 827        if (irq[i] == SNDRV_AUTO_PORT || mem[i] == SNDRV_AUTO_PORT) {
 828                printk(KERN_WARNING LOGNAME ": io, irq and mem must be set\n");
 829                return 0;
 830        }
 831
 832#ifdef MSND_CLASSIC
 833        if (!(io[i] == 0x290 ||
 834              io[i] == 0x260 ||
 835              io[i] == 0x250 ||
 836              io[i] == 0x240 ||
 837              io[i] == 0x230 ||
 838              io[i] == 0x220 ||
 839              io[i] == 0x210 ||
 840              io[i] == 0x3e0)) {
 841                printk(KERN_ERR LOGNAME ": \"io\" - DSP I/O base must be set "
 842                        " to 0x210, 0x220, 0x230, 0x240, 0x250, 0x260, 0x290, "
 843                        "or 0x3E0\n");
 844                return 0;
 845        }
 846#else
 847        if (io[i] < 0x100 || io[i] > 0x3e0 || (io[i] % 0x10) != 0) {
 848                printk(KERN_ERR LOGNAME
 849                        ": \"io\" - DSP I/O base must within the range 0x100 "
 850                        "to 0x3E0 and must be evenly divisible by 0x10\n");
 851                return 0;
 852        }
 853#endif /* MSND_CLASSIC */
 854
 855        if (!(irq[i] == 5 ||
 856              irq[i] == 7 ||
 857              irq[i] == 9 ||
 858              irq[i] == 10 ||
 859              irq[i] == 11 ||
 860              irq[i] == 12)) {
 861                printk(KERN_ERR LOGNAME
 862                        ": \"irq\" - must be set to 5, 7, 9, 10, 11 or 12\n");
 863                return 0;
 864        }
 865
 866        if (!(mem[i] == 0xb0000 ||
 867              mem[i] == 0xc8000 ||
 868              mem[i] == 0xd0000 ||
 869              mem[i] == 0xd8000 ||
 870              mem[i] == 0xe0000 ||
 871              mem[i] == 0xe8000)) {
 872                printk(KERN_ERR LOGNAME ": \"mem\" - must be set to "
 873                       "0xb0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000 or "
 874                       "0xe8000\n");
 875                return 0;
 876        }
 877
 878#ifndef MSND_CLASSIC
 879        if (cfg[i] == SNDRV_AUTO_PORT) {
 880                printk(KERN_INFO LOGNAME ": Assuming PnP mode\n");
 881        } else if (cfg[i] != 0x250 && cfg[i] != 0x260 && cfg[i] != 0x270) {
 882                printk(KERN_INFO LOGNAME
 883                        ": Config port must be 0x250, 0x260 or 0x270 "
 884                        "(or unspecified for PnP mode)\n");
 885                return 0;
 886        }
 887#endif /* MSND_CLASSIC */
 888
 889        return 1;
 890}
 891
 892static int snd_msnd_isa_probe(struct device *pdev, unsigned int idx)
 893{
 894        int err;
 895        struct snd_card *card;
 896        struct snd_msnd *chip;
 897
 898        if (has_isapnp(idx)
 899#ifndef MSND_CLASSIC
 900            || cfg[idx] == SNDRV_AUTO_PORT
 901#endif
 902            ) {
 903                printk(KERN_INFO LOGNAME ": Assuming PnP mode\n");
 904                return -ENODEV;
 905        }
 906
 907        err = snd_card_new(pdev, index[idx], id[idx], THIS_MODULE,
 908                           sizeof(struct snd_msnd), &card);
 909        if (err < 0)
 910                return err;
 911
 912        chip = card->private_data;
 913        chip->card = card;
 914
 915#ifdef MSND_CLASSIC
 916        switch (irq[idx]) {
 917        case 5:
 918                chip->irqid = HPIRQ_5; break;
 919        case 7:
 920                chip->irqid = HPIRQ_7; break;
 921        case 9:
 922                chip->irqid = HPIRQ_9; break;
 923        case 10:
 924                chip->irqid = HPIRQ_10; break;
 925        case 11:
 926                chip->irqid = HPIRQ_11; break;
 927        case 12:
 928                chip->irqid = HPIRQ_12; break;
 929        }
 930
 931        switch (mem[idx]) {
 932        case 0xb0000:
 933                chip->memid = HPMEM_B000; break;
 934        case 0xc8000:
 935                chip->memid = HPMEM_C800; break;
 936        case 0xd0000:
 937                chip->memid = HPMEM_D000; break;
 938        case 0xd8000:
 939                chip->memid = HPMEM_D800; break;
 940        case 0xe0000:
 941                chip->memid = HPMEM_E000; break;
 942        case 0xe8000:
 943                chip->memid = HPMEM_E800; break;
 944        }
 945#else
 946        printk(KERN_INFO LOGNAME ": Non-PnP mode: configuring at port 0x%lx\n",
 947                        cfg[idx]);
 948
 949        if (!request_region(cfg[idx], 2, "Pinnacle/Fiji Config")) {
 950                printk(KERN_ERR LOGNAME ": Config port 0x%lx conflict\n",
 951                           cfg[idx]);
 952                snd_card_free(card);
 953                return -EIO;
 954        }
 955        if (reset[idx])
 956                if (snd_msnd_pinnacle_cfg_reset(cfg[idx])) {
 957                        err = -EIO;
 958                        goto cfg_error;
 959                }
 960
 961        /* DSP */
 962        err = snd_msnd_write_cfg_logical(cfg[idx], 0,
 963                                         io[idx], 0,
 964                                         irq[idx], mem[idx]);
 965
 966        if (err)
 967                goto cfg_error;
 968
 969        /* The following are Pinnacle specific */
 970
 971        /* MPU */
 972        if (mpu_io[idx] != SNDRV_AUTO_PORT
 973            && mpu_irq[idx] != SNDRV_AUTO_IRQ) {
 974                printk(KERN_INFO LOGNAME
 975                       ": Configuring MPU to I/O 0x%lx IRQ %d\n",
 976                       mpu_io[idx], mpu_irq[idx]);
 977                err = snd_msnd_write_cfg_logical(cfg[idx], 1,
 978                                                 mpu_io[idx], 0,
 979                                                 mpu_irq[idx], 0);
 980
 981                if (err)
 982                        goto cfg_error;
 983        }
 984
 985        /* IDE */
 986        if (ide_io0[idx] != SNDRV_AUTO_PORT
 987            && ide_io1[idx] != SNDRV_AUTO_PORT
 988            && ide_irq[idx] != SNDRV_AUTO_IRQ) {
 989                printk(KERN_INFO LOGNAME
 990                       ": Configuring IDE to I/O 0x%lx, 0x%lx IRQ %d\n",
 991                       ide_io0[idx], ide_io1[idx], ide_irq[idx]);
 992                err = snd_msnd_write_cfg_logical(cfg[idx], 2,
 993                                                 ide_io0[idx], ide_io1[idx],
 994                                                 ide_irq[idx], 0);
 995
 996                if (err)
 997                        goto cfg_error;
 998        }
 999
1000        /* Joystick */
1001        if (joystick_io[idx] != SNDRV_AUTO_PORT) {
1002                printk(KERN_INFO LOGNAME
1003                       ": Configuring joystick to I/O 0x%lx\n",
1004                       joystick_io[idx]);
1005                err = snd_msnd_write_cfg_logical(cfg[idx], 3,
1006                                                 joystick_io[idx], 0,
1007                                                 0, 0);
1008
1009                if (err)
1010                        goto cfg_error;
1011        }
1012        release_region(cfg[idx], 2);
1013
1014#endif /* MSND_CLASSIC */
1015
1016        set_default_audio_parameters(chip);
1017#ifdef MSND_CLASSIC
1018        chip->type = msndClassic;
1019#else
1020        chip->type = msndPinnacle;
1021#endif
1022        chip->io = io[idx];
1023        chip->irq = irq[idx];
1024        chip->base = mem[idx];
1025
1026        chip->calibrate_signal = calibrate_signal ? 1 : 0;
1027        chip->recsrc = 0;
1028        chip->dspq_data_buff = DSPQ_DATA_BUFF;
1029        chip->dspq_buff_size = DSPQ_BUFF_SIZE;
1030        if (write_ndelay[idx])
1031                clear_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);
1032        else
1033                set_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);
1034#ifndef MSND_CLASSIC
1035        if (digital[idx])
1036                set_bit(F_HAVEDIGITAL, &chip->flags);
1037#endif
1038        spin_lock_init(&chip->lock);
1039        err = snd_msnd_probe(card);
1040        if (err < 0) {
1041                printk(KERN_ERR LOGNAME ": Probe failed\n");
1042                snd_card_free(card);
1043                return err;
1044        }
1045
1046        err = snd_msnd_attach(card);
1047        if (err < 0) {
1048                printk(KERN_ERR LOGNAME ": Attach failed\n");
1049                snd_card_free(card);
1050                return err;
1051        }
1052        dev_set_drvdata(pdev, card);
1053
1054        return 0;
1055
1056#ifndef MSND_CLASSIC
1057cfg_error:
1058        release_region(cfg[idx], 2);
1059        snd_card_free(card);
1060        return err;
1061#endif
1062}
1063
1064static int snd_msnd_isa_remove(struct device *pdev, unsigned int dev)
1065{
1066        snd_msnd_unload(dev_get_drvdata(pdev));
1067        return 0;
1068}
1069
1070static struct isa_driver snd_msnd_driver = {
1071        .match          = snd_msnd_isa_match,
1072        .probe          = snd_msnd_isa_probe,
1073        .remove         = snd_msnd_isa_remove,
1074        /* FIXME: suspend, resume */
1075        .driver         = {
1076                .name   = DEV_NAME
1077        },
1078};
1079
1080#ifdef CONFIG_PNP
1081static int snd_msnd_pnp_detect(struct pnp_card_link *pcard,
1082                               const struct pnp_card_device_id *pid)
1083{
1084        static int idx;
1085        struct pnp_dev *pnp_dev;
1086        struct pnp_dev *mpu_dev;
1087        struct snd_card *card;
1088        struct snd_msnd *chip;
1089        int ret;
1090
1091        for ( ; idx < SNDRV_CARDS; idx++) {
1092                if (has_isapnp(idx))
1093                        break;
1094        }
1095        if (idx >= SNDRV_CARDS)
1096                return -ENODEV;
1097
1098        /*
1099         * Check that we still have room for another sound card ...
1100         */
1101        pnp_dev = pnp_request_card_device(pcard, pid->devs[0].id, NULL);
1102        if (!pnp_dev)
1103                return -ENODEV;
1104
1105        mpu_dev = pnp_request_card_device(pcard, pid->devs[1].id, NULL);
1106        if (!mpu_dev)
1107                return -ENODEV;
1108
1109        if (!pnp_is_active(pnp_dev) && pnp_activate_dev(pnp_dev) < 0) {
1110                printk(KERN_INFO "msnd_pinnacle: device is inactive\n");
1111                return -EBUSY;
1112        }
1113
1114        if (!pnp_is_active(mpu_dev) && pnp_activate_dev(mpu_dev) < 0) {
1115                printk(KERN_INFO "msnd_pinnacle: MPU device is inactive\n");
1116                return -EBUSY;
1117        }
1118
1119        /*
1120         * Create a new ALSA sound card entry, in anticipation
1121         * of detecting our hardware ...
1122         */
1123        ret = snd_card_new(&pcard->card->dev,
1124                           index[idx], id[idx], THIS_MODULE,
1125                           sizeof(struct snd_msnd), &card);
1126        if (ret < 0)
1127                return ret;
1128
1129        chip = card->private_data;
1130        chip->card = card;
1131
1132        /*
1133         * Read the correct parameters off the ISA PnP bus ...
1134         */
1135        io[idx] = pnp_port_start(pnp_dev, 0);
1136        irq[idx] = pnp_irq(pnp_dev, 0);
1137        mem[idx] = pnp_mem_start(pnp_dev, 0);
1138        mpu_io[idx] = pnp_port_start(mpu_dev, 0);
1139        mpu_irq[idx] = pnp_irq(mpu_dev, 0);
1140
1141        set_default_audio_parameters(chip);
1142#ifdef MSND_CLASSIC
1143        chip->type = msndClassic;
1144#else
1145        chip->type = msndPinnacle;
1146#endif
1147        chip->io = io[idx];
1148        chip->irq = irq[idx];
1149        chip->base = mem[idx];
1150
1151        chip->calibrate_signal = calibrate_signal ? 1 : 0;
1152        chip->recsrc = 0;
1153        chip->dspq_data_buff = DSPQ_DATA_BUFF;
1154        chip->dspq_buff_size = DSPQ_BUFF_SIZE;
1155        if (write_ndelay[idx])
1156                clear_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);
1157        else
1158                set_bit(F_DISABLE_WRITE_NDELAY, &chip->flags);
1159#ifndef MSND_CLASSIC
1160        if (digital[idx])
1161                set_bit(F_HAVEDIGITAL, &chip->flags);
1162#endif
1163        spin_lock_init(&chip->lock);
1164        ret = snd_msnd_probe(card);
1165        if (ret < 0) {
1166                printk(KERN_ERR LOGNAME ": Probe failed\n");
1167                goto _release_card;
1168        }
1169
1170        ret = snd_msnd_attach(card);
1171        if (ret < 0) {
1172                printk(KERN_ERR LOGNAME ": Attach failed\n");
1173                goto _release_card;
1174        }
1175
1176        pnp_set_card_drvdata(pcard, card);
1177        ++idx;
1178        return 0;
1179
1180_release_card:
1181        snd_card_free(card);
1182        return ret;
1183}
1184
1185static void snd_msnd_pnp_remove(struct pnp_card_link *pcard)
1186{
1187        snd_msnd_unload(pnp_get_card_drvdata(pcard));
1188        pnp_set_card_drvdata(pcard, NULL);
1189}
1190
1191static int isa_registered;
1192static int pnp_registered;
1193
1194static struct pnp_card_device_id msnd_pnpids[] = {
1195        /* Pinnacle PnP */
1196        { .id = "BVJ0440", .devs = { { "TBS0000" }, { "TBS0001" } } },
1197        { .id = "" }    /* end */
1198};
1199
1200MODULE_DEVICE_TABLE(pnp_card, msnd_pnpids);
1201
1202static struct pnp_card_driver msnd_pnpc_driver = {
1203        .flags = PNP_DRIVER_RES_DO_NOT_CHANGE,
1204        .name = "msnd_pinnacle",
1205        .id_table = msnd_pnpids,
1206        .probe = snd_msnd_pnp_detect,
1207        .remove = snd_msnd_pnp_remove,
1208};
1209#endif /* CONFIG_PNP */
1210
1211static int __init snd_msnd_init(void)
1212{
1213        int err;
1214
1215        err = isa_register_driver(&snd_msnd_driver, SNDRV_CARDS);
1216#ifdef CONFIG_PNP
1217        if (!err)
1218                isa_registered = 1;
1219
1220        err = pnp_register_card_driver(&msnd_pnpc_driver);
1221        if (!err)
1222                pnp_registered = 1;
1223
1224        if (isa_registered)
1225                err = 0;
1226#endif
1227        return err;
1228}
1229
1230static void __exit snd_msnd_exit(void)
1231{
1232#ifdef CONFIG_PNP
1233        if (pnp_registered)
1234                pnp_unregister_card_driver(&msnd_pnpc_driver);
1235        if (isa_registered)
1236#endif
1237                isa_unregister_driver(&snd_msnd_driver);
1238}
1239
1240module_init(snd_msnd_init);
1241module_exit(snd_msnd_exit);
1242
1243