linux/sound/isa/azt2320.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3    card-azt2320.c - driver for Aztech Systems AZT2320 based soundcards.
   4    Copyright (C) 1999-2000 by Massimo Piccioni <dafastidio@libero.it>
   5
   6*/
   7
   8/*
   9    This driver should provide support for most Aztech AZT2320 based cards.
  10    Several AZT2316 chips are also supported/tested, but autoprobe doesn't
  11    work: all module option have to be set.
  12
  13    No docs available for us at Aztech headquarters !!!   Unbelievable ...
  14    No other help obtained.
  15
  16    Thanks to Rainer Wiesner <rainer.wiesner@01019freenet.de> for the WSS
  17    activation method (full-duplex audio!).
  18*/
  19
  20#include <linux/io.h>
  21#include <linux/delay.h>
  22#include <linux/init.h>
  23#include <linux/time.h>
  24#include <linux/wait.h>
  25#include <linux/pnp.h>
  26#include <linux/module.h>
  27#include <sound/core.h>
  28#include <sound/initval.h>
  29#include <sound/wss.h>
  30#include <sound/mpu401.h>
  31#include <sound/opl3.h>
  32
  33#define PFX "azt2320: "
  34
  35MODULE_AUTHOR("Massimo Piccioni <dafastidio@libero.it>");
  36MODULE_DESCRIPTION("Aztech Systems AZT2320");
  37MODULE_LICENSE("GPL");
  38MODULE_SUPPORTED_DEVICE("{{Aztech Systems,PRO16V},"
  39                "{Aztech Systems,AZT2320},"
  40                "{Aztech Systems,AZT3300},"
  41                "{Aztech Systems,AZT2320},"
  42                "{Aztech Systems,AZT3000}}");
  43
  44static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;      /* Index 0-MAX */
  45static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;       /* ID for this card */
  46static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_ISAPNP; /* Enable this card */
  47static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;     /* PnP setup */
  48static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
  49static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; /* PnP setup */
  50static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;  /* PnP setup */
  51static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;        /* Pnp setup */
  52static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;    /* Pnp setup */
  53static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;       /* PnP setup */
  54static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;       /* PnP setup */
  55
  56module_param_array(index, int, NULL, 0444);
  57MODULE_PARM_DESC(index, "Index value for azt2320 based soundcard.");
  58module_param_array(id, charp, NULL, 0444);
  59MODULE_PARM_DESC(id, "ID string for azt2320 based soundcard.");
  60module_param_array(enable, bool, NULL, 0444);
  61MODULE_PARM_DESC(enable, "Enable azt2320 based soundcard.");
  62
  63struct snd_card_azt2320 {
  64        int dev_no;
  65        struct pnp_dev *dev;
  66        struct pnp_dev *devmpu;
  67        struct snd_wss *chip;
  68};
  69
  70static const struct pnp_card_device_id snd_azt2320_pnpids[] = {
  71        /* PRO16V */
  72        { .id = "AZT1008", .devs = { { "AZT1008" }, { "AZT2001" }, } },
  73        /* Aztech Sound Galaxy 16 */
  74        { .id = "AZT2320", .devs = { { "AZT0001" }, { "AZT0002" }, } },
  75        /* Packard Bell Sound III 336 AM/SP */
  76        { .id = "AZT3000", .devs = { { "AZT1003" }, { "AZT2001" }, } },
  77        /* AT3300 */
  78        { .id = "AZT3002", .devs = { { "AZT1004" }, { "AZT2001" }, } },
  79        /* --- */
  80        { .id = "AZT3005", .devs = { { "AZT1003" }, { "AZT2001" }, } },
  81        /* --- */
  82        { .id = "AZT3011", .devs = { { "AZT1003" }, { "AZT2001" }, } },
  83        { .id = "" }    /* end */
  84};
  85
  86MODULE_DEVICE_TABLE(pnp_card, snd_azt2320_pnpids);
  87
  88#define DRIVER_NAME     "snd-card-azt2320"
  89
  90static int snd_card_azt2320_pnp(int dev, struct snd_card_azt2320 *acard,
  91                                struct pnp_card_link *card,
  92                                const struct pnp_card_device_id *id)
  93{
  94        struct pnp_dev *pdev;
  95        int err;
  96
  97        acard->dev = pnp_request_card_device(card, id->devs[0].id, NULL);
  98        if (acard->dev == NULL)
  99                return -ENODEV;
 100
 101        acard->devmpu = pnp_request_card_device(card, id->devs[1].id, NULL);
 102
 103        pdev = acard->dev;
 104
 105        err = pnp_activate_dev(pdev);
 106        if (err < 0) {
 107                snd_printk(KERN_ERR PFX "AUDIO pnp configure failure\n");
 108                return err;
 109        }
 110        port[dev] = pnp_port_start(pdev, 0);
 111        fm_port[dev] = pnp_port_start(pdev, 1);
 112        wss_port[dev] = pnp_port_start(pdev, 2);
 113        dma1[dev] = pnp_dma(pdev, 0);
 114        dma2[dev] = pnp_dma(pdev, 1);
 115        irq[dev] = pnp_irq(pdev, 0);
 116
 117        pdev = acard->devmpu;
 118        if (pdev != NULL) {
 119                err = pnp_activate_dev(pdev);
 120                if (err < 0)
 121                        goto __mpu_error;
 122                mpu_port[dev] = pnp_port_start(pdev, 0);
 123                mpu_irq[dev] = pnp_irq(pdev, 0);
 124        } else {
 125             __mpu_error:
 126                if (pdev) {
 127                        pnp_release_card_device(pdev);
 128                        snd_printk(KERN_ERR PFX "MPU401 pnp configure failure, skipping\n");
 129                }
 130                acard->devmpu = NULL;
 131                mpu_port[dev] = -1;
 132        }
 133
 134        return 0;
 135}
 136
 137/* same of snd_sbdsp_command by Jaroslav Kysela */
 138static int snd_card_azt2320_command(unsigned long port, unsigned char val)
 139{
 140        int i;
 141        unsigned long limit;
 142
 143        limit = jiffies + HZ / 10;
 144        for (i = 50000; i && time_after(limit, jiffies); i--)
 145                if (!(inb(port + 0x0c) & 0x80)) {
 146                        outb(val, port + 0x0c);
 147                        return 0;
 148                }
 149        return -EBUSY;
 150}
 151
 152static int snd_card_azt2320_enable_wss(unsigned long port)
 153{
 154        int error;
 155
 156        if ((error = snd_card_azt2320_command(port, 0x09)))
 157                return error;
 158        if ((error = snd_card_azt2320_command(port, 0x00)))
 159                return error;
 160
 161        mdelay(5);
 162        return 0;
 163}
 164
 165static int snd_card_azt2320_probe(int dev,
 166                                  struct pnp_card_link *pcard,
 167                                  const struct pnp_card_device_id *pid)
 168{
 169        int error;
 170        struct snd_card *card;
 171        struct snd_card_azt2320 *acard;
 172        struct snd_wss *chip;
 173        struct snd_opl3 *opl3;
 174
 175        error = snd_card_new(&pcard->card->dev,
 176                             index[dev], id[dev], THIS_MODULE,
 177                             sizeof(struct snd_card_azt2320), &card);
 178        if (error < 0)
 179                return error;
 180        acard = card->private_data;
 181
 182        if ((error = snd_card_azt2320_pnp(dev, acard, pcard, pid))) {
 183                snd_card_free(card);
 184                return error;
 185        }
 186
 187        if ((error = snd_card_azt2320_enable_wss(port[dev]))) {
 188                snd_card_free(card);
 189                return error;
 190        }
 191
 192        error = snd_wss_create(card, wss_port[dev], -1,
 193                               irq[dev],
 194                               dma1[dev], dma2[dev],
 195                               WSS_HW_DETECT, 0, &chip);
 196        if (error < 0) {
 197                snd_card_free(card);
 198                return error;
 199        }
 200
 201        strcpy(card->driver, "AZT2320");
 202        strcpy(card->shortname, "Aztech AZT2320");
 203        sprintf(card->longname, "%s, WSS at 0x%lx, irq %i, dma %i&%i",
 204                card->shortname, chip->port, irq[dev], dma1[dev], dma2[dev]);
 205
 206        error = snd_wss_pcm(chip, 0);
 207        if (error < 0) {
 208                snd_card_free(card);
 209                return error;
 210        }
 211        error = snd_wss_mixer(chip);
 212        if (error < 0) {
 213                snd_card_free(card);
 214                return error;
 215        }
 216        error = snd_wss_timer(chip, 0);
 217        if (error < 0) {
 218                snd_card_free(card);
 219                return error;
 220        }
 221
 222        if (mpu_port[dev] > 0 && mpu_port[dev] != SNDRV_AUTO_PORT) {
 223                if (snd_mpu401_uart_new(card, 0, MPU401_HW_AZT2320,
 224                                mpu_port[dev], 0,
 225                                mpu_irq[dev], NULL) < 0)
 226                        snd_printk(KERN_ERR PFX "no MPU-401 device at 0x%lx\n", mpu_port[dev]);
 227        }
 228
 229        if (fm_port[dev] > 0 && fm_port[dev] != SNDRV_AUTO_PORT) {
 230                if (snd_opl3_create(card,
 231                                    fm_port[dev], fm_port[dev] + 2,
 232                                    OPL3_HW_AUTO, 0, &opl3) < 0) {
 233                        snd_printk(KERN_ERR PFX "no OPL device at 0x%lx-0x%lx\n",
 234                                   fm_port[dev], fm_port[dev] + 2);
 235                } else {
 236                        if ((error = snd_opl3_timer_new(opl3, 1, 2)) < 0) {
 237                                snd_card_free(card);
 238                                return error;
 239                        }
 240                        if ((error = snd_opl3_hwdep_new(opl3, 0, 1, NULL)) < 0) {
 241                                snd_card_free(card);
 242                                return error;
 243                        }
 244                }
 245        }
 246
 247        if ((error = snd_card_register(card)) < 0) {
 248                snd_card_free(card);
 249                return error;
 250        }
 251        pnp_set_card_drvdata(pcard, card);
 252        return 0;
 253}
 254
 255static unsigned int azt2320_devices;
 256
 257static int snd_azt2320_pnp_detect(struct pnp_card_link *card,
 258                                  const struct pnp_card_device_id *id)
 259{
 260        static int dev;
 261        int res;
 262
 263        for ( ; dev < SNDRV_CARDS; dev++) {
 264                if (!enable[dev])
 265                        continue;
 266                res = snd_card_azt2320_probe(dev, card, id);
 267                if (res < 0)
 268                        return res;
 269                dev++;
 270                azt2320_devices++;
 271                return 0;
 272        }
 273        return -ENODEV;
 274}
 275
 276static void snd_azt2320_pnp_remove(struct pnp_card_link *pcard)
 277{
 278        snd_card_free(pnp_get_card_drvdata(pcard));
 279        pnp_set_card_drvdata(pcard, NULL);
 280}
 281
 282#ifdef CONFIG_PM
 283static int snd_azt2320_pnp_suspend(struct pnp_card_link *pcard, pm_message_t state)
 284{
 285        struct snd_card *card = pnp_get_card_drvdata(pcard);
 286        struct snd_card_azt2320 *acard = card->private_data;
 287        struct snd_wss *chip = acard->chip;
 288
 289        snd_power_change_state(card, SNDRV_CTL_POWER_D3hot);
 290        chip->suspend(chip);
 291        return 0;
 292}
 293
 294static int snd_azt2320_pnp_resume(struct pnp_card_link *pcard)
 295{
 296        struct snd_card *card = pnp_get_card_drvdata(pcard);
 297        struct snd_card_azt2320 *acard = card->private_data;
 298        struct snd_wss *chip = acard->chip;
 299
 300        chip->resume(chip);
 301        snd_power_change_state(card, SNDRV_CTL_POWER_D0);
 302        return 0;
 303}
 304#endif
 305
 306static struct pnp_card_driver azt2320_pnpc_driver = {
 307        .flags          = PNP_DRIVER_RES_DISABLE,
 308        .name           = "azt2320",
 309        .id_table       = snd_azt2320_pnpids,
 310        .probe          = snd_azt2320_pnp_detect,
 311        .remove         = snd_azt2320_pnp_remove,
 312#ifdef CONFIG_PM
 313        .suspend        = snd_azt2320_pnp_suspend,
 314        .resume         = snd_azt2320_pnp_resume,
 315#endif
 316};
 317
 318static int __init alsa_card_azt2320_init(void)
 319{
 320        int err;
 321
 322        err = pnp_register_card_driver(&azt2320_pnpc_driver);
 323        if (err)
 324                return err;
 325
 326        if (!azt2320_devices) {
 327                pnp_unregister_card_driver(&azt2320_pnpc_driver);
 328#ifdef MODULE
 329                snd_printk(KERN_ERR "no AZT2320 based soundcards found\n");
 330#endif
 331                return -ENODEV;
 332        }
 333        return 0;
 334}
 335
 336static void __exit alsa_card_azt2320_exit(void)
 337{
 338        pnp_unregister_card_driver(&azt2320_pnpc_driver);
 339}
 340
 341module_init(alsa_card_azt2320_init)
 342module_exit(alsa_card_azt2320_exit)
 343