linux/sound/isa/als100.c
<<
>>
Prefs
   1
   2/*
   3    card-als100.c - driver for Avance Logic ALS100 based soundcards.
   4    Copyright (C) 1999-2000 by Massimo Piccioni <dafastidio@libero.it>
   5    Copyright (C) 1999-2002 by Massimo Piccioni <dafastidio@libero.it>
   6
   7    Thanks to Pierfrancesco 'qM2' Passerini.
   8
   9    Generalised for soundcards based on DT-0196 and ALS-007 chips
  10    by Jonathan Woithe <jwoithe@just42.net>: June 2002.
  11
  12    This program is free software; you can redistribute it and/or modify
  13    it under the terms of the GNU General Public License as published by
  14    the Free Software Foundation; either version 2 of the License, or
  15    (at your option) any later version.
  16
  17    This program is distributed in the hope that it will be useful,
  18    but WITHOUT ANY WARRANTY; without even the implied warranty of
  19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  20    GNU General Public License for more details.
  21
  22    You should have received a copy of the GNU General Public License
  23    along with this program; if not, write to the Free Software
  24    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
  25*/
  26
  27#include <linux/init.h>
  28#include <linux/wait.h>
  29#include <linux/time.h>
  30#include <linux/pnp.h>
  31#include <linux/module.h>
  32#include <sound/core.h>
  33#include <sound/initval.h>
  34#include <sound/mpu401.h>
  35#include <sound/opl3.h>
  36#include <sound/sb.h>
  37
  38#define PFX "als100: "
  39
  40MODULE_DESCRIPTION("Avance Logic ALS007/ALS1X0");
  41MODULE_SUPPORTED_DEVICE("{{Diamond Technologies DT-019X},"
  42                "{Avance Logic ALS-007}}"
  43                "{{Avance Logic,ALS100 - PRO16PNP},"
  44                "{Avance Logic,ALS110},"
  45                "{Avance Logic,ALS120},"
  46                "{Avance Logic,ALS200},"
  47                "{3D Melody,MF1000},"
  48                "{Digimate,3D Sound},"
  49                "{Avance Logic,ALS120},"
  50                "{RTL,RTL3000}}");
  51
  52MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
  53MODULE_LICENSE("GPL");
  54
  55static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;      /* Index 0-MAX */
  56static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;       /* ID for this card */
  57static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE; /* Enable this card */
  58static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;     /* PnP setup */
  59static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
  60static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;  /* PnP setup */
  61static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;        /* PnP setup */
  62static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;    /* PnP setup */
  63static int dma8[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;       /* PnP setup */
  64static int dma16[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;      /* PnP setup */
  65
  66module_param_array(index, int, NULL, 0444);
  67MODULE_PARM_DESC(index, "Index value for Avance Logic based soundcard.");
  68module_param_array(id, charp, NULL, 0444);
  69MODULE_PARM_DESC(id, "ID string for Avance Logic based soundcard.");
  70module_param_array(enable, bool, NULL, 0444);
  71MODULE_PARM_DESC(enable, "Enable Avance Logic based soundcard.");
  72
  73MODULE_ALIAS("snd-dt019x");
  74
  75struct snd_card_als100 {
  76        struct pnp_dev *dev;
  77        struct pnp_dev *devmpu;
  78        struct pnp_dev *devopl;
  79        struct snd_sb *chip;
  80};
  81
  82static struct pnp_card_device_id snd_als100_pnpids[] = {
  83        /* DT197A30 */
  84        { .id = "RWB1688",
  85          .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } },
  86          .driver_data = SB_HW_DT019X },
  87        /* DT0196 / ALS-007 */
  88        { .id = "ALS0007",
  89          .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } },
  90          .driver_data = SB_HW_DT019X },
  91        /* ALS100 - PRO16PNP */
  92        { .id = "ALS0001",
  93          .devs = { { "@@@0001" }, { "@X@0001" }, { "@H@0001" } },
  94          .driver_data = SB_HW_ALS100 },
  95        /* ALS110 - MF1000 - Digimate 3D Sound */
  96        { .id = "ALS0110",
  97          .devs = { { "@@@1001" }, { "@X@1001" }, { "@H@1001" } },
  98          .driver_data = SB_HW_ALS100 },
  99        /* ALS120 */
 100        { .id = "ALS0120",
 101          .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } },
 102          .driver_data = SB_HW_ALS100 },
 103        /* ALS200 */
 104        { .id = "ALS0200",
 105          .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0001" } },
 106          .driver_data = SB_HW_ALS100 },
 107        /* ALS200 OEM */
 108        { .id = "ALS0200",
 109          .devs = { { "@@@0020" }, { "@X@0020" }, { "@H@0020" } },
 110          .driver_data = SB_HW_ALS100 },
 111        /* RTL3000 */
 112        { .id = "RTL3000",
 113          .devs = { { "@@@2001" }, { "@X@2001" }, { "@H@2001" } },
 114          .driver_data = SB_HW_ALS100 },
 115        { .id = "" } /* end */
 116};
 117
 118MODULE_DEVICE_TABLE(pnp_card, snd_als100_pnpids);
 119
 120static int snd_card_als100_pnp(int dev, struct snd_card_als100 *acard,
 121                               struct pnp_card_link *card,
 122                               const struct pnp_card_device_id *id)
 123{
 124        struct pnp_dev *pdev;
 125        int err;
 126
 127        acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
 128        if (acard->dev == NULL)
 129                return -ENODEV;
 130
 131        acard->devmpu = pnp_request_card_device(card, id->devs[1].id, acard->dev);
 132        acard->devopl = pnp_request_card_device(card, id->devs[2].id, acard->dev);
 133
 134        pdev = acard->dev;
 135
 136        err = pnp_activate_dev(pdev);
 137        if (err < 0) {
 138                snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n");
 139                return err;
 140        }
 141        port[dev] = pnp_port_start(pdev, 0);
 142        if (id->driver_data == SB_HW_DT019X)
 143                dma8[dev] = pnp_dma(pdev, 0);
 144        else {
 145                dma8[dev] = pnp_dma(pdev, 1);
 146                dma16[dev] = pnp_dma(pdev, 0);
 147        }
 148        irq[dev] = pnp_irq(pdev, 0);
 149
 150        pdev = acard->devmpu;
 151        if (pdev != NULL) {
 152                err = pnp_activate_dev(pdev);
 153                if (err < 0)
 154                        goto __mpu_error;
 155                mpu_port[dev] = pnp_port_start(pdev, 0);
 156                mpu_irq[dev] = pnp_irq(pdev, 0);
 157        } else {
 158             __mpu_error:
 159                if (pdev) {
 160                        pnp_release_card_device(pdev);
 161                        snd_printk(KERN_ERR PFX "MPU401 pnp configure failure, skipping\n");
 162                }
 163                acard->devmpu = NULL;
 164                mpu_port[dev] = -1;
 165        }
 166
 167        pdev = acard->devopl;
 168        if (pdev != NULL) {
 169                err = pnp_activate_dev(pdev);
 170                if (err < 0)
 171                        goto __fm_error;
 172                fm_port[dev] = pnp_port_start(pdev, 0);
 173        } else {
 174              __fm_error:
 175                if (pdev) {
 176                        pnp_release_card_device(pdev);
 177                        snd_printk(KERN_ERR PFX "OPL3 pnp configure failure, skipping\n");
 178                }
 179                acard->devopl = NULL;
 180                fm_port[dev] = -1;
 181        }
 182
 183        return 0;
 184}
 185
 186static int snd_card_als100_probe(int dev,
 187                                 struct pnp_card_link *pcard,
 188                                 const struct pnp_card_device_id *pid)
 189{
 190        int error;
 191        struct snd_sb *chip;
 192        struct snd_card *card;
 193        struct snd_card_als100 *acard;
 194        struct snd_opl3 *opl3;
 195
 196        error = snd_card_new(&pcard->card->dev,
 197                             index[dev], id[dev], THIS_MODULE,
 198                             sizeof(struct snd_card_als100), &card);
 199        if (error < 0)
 200                return error;
 201        acard = card->private_data;
 202
 203        if ((error = snd_card_als100_pnp(dev, acard, pcard, pid))) {
 204                snd_card_free(card);
 205                return error;
 206        }
 207
 208        if (pid->driver_data == SB_HW_DT019X)
 209                dma16[dev] = -1;
 210
 211        error = snd_sbdsp_create(card, port[dev], irq[dev],
 212                                  snd_sb16dsp_interrupt,
 213                                  dma8[dev], dma16[dev],
 214                                  pid->driver_data,
 215                                  &chip);
 216        if (error < 0) {
 217                snd_card_free(card);
 218                return error;
 219        }
 220        acard->chip = chip;
 221
 222        if (pid->driver_data == SB_HW_DT019X) {
 223                strcpy(card->driver, "DT-019X");
 224                strcpy(card->shortname, "Diamond Tech. DT-019X");
 225                sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d",
 226                        card->shortname, chip->name, chip->port,
 227                        irq[dev], dma8[dev]);
 228        } else {
 229                strcpy(card->driver, "ALS100");
 230                strcpy(card->shortname, "Avance Logic ALS100");
 231                sprintf(card->longname, "%s, %s at 0x%lx, irq %d, dma %d&%d",
 232                        card->shortname, chip->name, chip->port,
 233                        irq[dev], dma8[dev], dma16[dev]);
 234        }
 235
 236        if ((error = snd_sb16dsp_pcm(chip, 0)) < 0) {
 237                snd_card_free(card);
 238                return error;
 239        }
 240
 241        if ((error = snd_sbmixer_new(chip)) < 0) {
 242                snd_card_free(card);
 243                return error;
 244        }
 245
 246        if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
 247                int mpu_type = MPU401_HW_ALS100;
 248
 249                if (mpu_irq[dev] == SNDRV_AUTO_IRQ)
 250                        mpu_irq[dev] = -1;
 251
 252                if (pid->driver_data == SB_HW_DT019X)
 253                        mpu_type = MPU401_HW_MPU401;
 254
 255                if (snd_mpu401_uart_new(card, 0,
 256                                        mpu_type,
 257                                        mpu_port[dev], 0, 
 258                                        mpu_irq[dev],
 259                                        NULL) < 0)
 260                        snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]);
 261        }
 262
 263        if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
 264                if (snd_opl3_create(card,
 265                                    fm_port[dev], fm_port[dev] + 2,
 266                                    OPL3_HW_AUTO, 0, &opl3) < 0) {
 267                        snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx\n",
 268                                   fm_port[dev], fm_port[dev] + 2);
 269                } else {
 270                        if ((error = snd_opl3_timer_new(opl3, 0, 1)) < 0) {
 271                                snd_card_free(card);
 272                                return error;
 273                        }
 274                        if ((error = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
 275                                snd_card_free(card);
 276                                return error;
 277                        }
 278                }
 279        }
 280
 281        if ((error = snd_card_register(card)) < 0) {
 282                snd_card_free(card);
 283                return error;
 284        }
 285        pnp_set_card_drvdata(pcard, card);
 286        return 0;
 287}
 288
 289static unsigned int als100_devices;
 290
 291static int snd_als100_pnp_detect(struct pnp_card_link *card,
 292                                 const struct pnp_card_device_id *id)
 293{
 294        static int dev;
 295        int res;
 296
 297        for ( ; dev < SNDRV_CARDS; dev++) {
 298                if (!enable[dev])
 299                        continue;
 300                res = snd_card_als100_probe(dev, card, id);
 301                if (res < 0)
 302                        return res;
 303                dev++;
 304                als100_devices++;
 305                return 0;
 306        }
 307        return -ENODEV;
 308}
 309
 310static void snd_als100_pnp_remove(struct pnp_card_link *pcard)
 311{
 312        snd_card_free(pnp_get_card_drvdata(pcard));
 313        pnp_set_card_drvdata(pcard, NULL);
 314}
 315
 316#ifdef CONFIG_PM
 317static int snd_als100_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state)
 318{
 319        struct snd_card *card = pnp_get_card_drvdata(pcard);
 320        struct snd_card_als100 *acard = card->private_data;
 321        struct snd_sb *chip = acard->chip;
 322
 323        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
 324        snd_pcm_suspend_all(chip->pcm);
 325        snd_sbmixer_suspend(chip);
 326        return 0;
 327}
 328
 329static int snd_als100_pnp_resume(struct pnp_card_link *pcard)
 330{
 331        struct snd_card *card = pnp_get_card_drvdata(pcard);
 332        struct snd_card_als100 *acard = card->private_data;
 333        struct snd_sb *chip = acard->chip;
 334
 335        snd_sbdsp_reset(chip);
 336        snd_sbmixer_resume(chip);
 337        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
 338        return 0;
 339}
 340#endif
 341
 342static struct pnp_card_driver als100_pnpc_driver = {
 343        .flags          = PNP_DRIVER_RES_DISABLE,
 344        .name           = "als100",
 345        .id_table       = snd_als100_pnpids,
 346        .probe          = snd_als100_pnp_detect,
 347        .remove         = snd_als100_pnp_remove,
 348#ifdef CONFIG_PM
 349        .suspend        = snd_als100_pnp_suspend,
 350        .resume         = snd_als100_pnp_resume,
 351#endif
 352};
 353
 354static int __init alsa_card_als100_init(void)
 355{
 356        int err;
 357
 358        err = pnp_register_card_driver(&als100_pnpc_driver);
 359        if (err)
 360                return err;
 361
 362        if (!als100_devices) {
 363                pnp_unregister_card_driver(&als100_pnpc_driver);
 364#ifdef MODULE
 365                snd_printk(KERN_ERR "no Avance Logic based soundcards found\n");
 366#endif
 367                return -ENODEV;
 368        }
 369        return 0;
 370}
 371
 372static void __exit alsa_card_als100_exit(void)
 373{
 374        pnp_unregister_card_driver(&als100_pnpc_driver);
 375}
 376
 377module_init(alsa_card_als100_init)
 378module_exit(alsa_card_als100_exit)
 379