linux/sound/isa/galaxy/galaxy.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Aztech AZT1605/AZT2316 Driver
   4 * Copyright (C) 2007,2010  Rene Herman
   5 */
   6
   7#include <linux/kernel.h>
   8#include <linux/module.h>
   9#include <linux/isa.h>
  10#include <linux/delay.h>
  11#include <linux/io.h>
  12#include <asm/processor.h>
  13#include <sound/core.h>
  14#include <sound/initval.h>
  15#include <sound/wss.h>
  16#include <sound/mpu401.h>
  17#include <sound/opl3.h>
  18
  19MODULE_DESCRIPTION(CRD_NAME);
  20MODULE_AUTHOR("Rene Herman");
  21MODULE_LICENSE("GPL");
  22
  23static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
  24static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
  25static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
  26
  27module_param_array(index, int, NULL, 0444);
  28MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
  29module_param_array(id, charp, NULL, 0444);
  30MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
  31module_param_array(enable, bool, NULL, 0444);
  32MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
  33
  34static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
  35static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
  36static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
  37static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
  38static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
  39static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
  40static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
  41static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
  42
  43module_param_hw_array(port, long, ioport, NULL, 0444);
  44MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
  45module_param_hw_array(wss_port, long, ioport, NULL, 0444);
  46MODULE_PARM_DESC(wss_port, "WSS port # for " CRD_NAME " driver.");
  47module_param_hw_array(mpu_port, long, ioport, NULL, 0444);
  48MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver.");
  49module_param_hw_array(fm_port, long, ioport, NULL, 0444);
  50MODULE_PARM_DESC(fm_port, "FM port # for " CRD_NAME " driver.");
  51module_param_hw_array(irq, int, irq, NULL, 0444);
  52MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver.");
  53module_param_hw_array(mpu_irq, int, irq, NULL, 0444);
  54MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver.");
  55module_param_hw_array(dma1, int, dma, NULL, 0444);
  56MODULE_PARM_DESC(dma1, "Playback DMA # for " CRD_NAME " driver.");
  57module_param_hw_array(dma2, int, dma, NULL, 0444);
  58MODULE_PARM_DESC(dma2, "Capture DMA # for " CRD_NAME " driver.");
  59
  60/*
  61 * Generic SB DSP support routines
  62 */
  63
  64#define DSP_PORT_RESET          0x6
  65#define DSP_PORT_READ           0xa
  66#define DSP_PORT_COMMAND        0xc
  67#define DSP_PORT_STATUS         0xc
  68#define DSP_PORT_DATA_AVAIL     0xe
  69
  70#define DSP_SIGNATURE           0xaa
  71
  72#define DSP_COMMAND_GET_VERSION 0xe1
  73
  74static int dsp_get_byte(void __iomem *port, u8 *val)
  75{
  76        int loops = 1000;
  77
  78        while (!(ioread8(port + DSP_PORT_DATA_AVAIL) & 0x80)) {
  79                if (!loops--)
  80                        return -EIO;
  81                cpu_relax();
  82        }
  83        *val = ioread8(port + DSP_PORT_READ);
  84        return 0;
  85}
  86
  87static int dsp_reset(void __iomem *port)
  88{
  89        u8 val;
  90
  91        iowrite8(1, port + DSP_PORT_RESET);
  92        udelay(10);
  93        iowrite8(0, port + DSP_PORT_RESET);
  94
  95        if (dsp_get_byte(port, &val) < 0 || val != DSP_SIGNATURE)
  96                return -ENODEV;
  97
  98        return 0;
  99}
 100
 101static int dsp_command(void __iomem *port, u8 cmd)
 102{
 103        int loops = 1000;
 104
 105        while (ioread8(port + DSP_PORT_STATUS) & 0x80) {
 106                if (!loops--)
 107                        return -EIO;
 108                cpu_relax();
 109        }
 110        iowrite8(cmd, port + DSP_PORT_COMMAND);
 111        return 0;
 112}
 113
 114static int dsp_get_version(void __iomem *port, u8 *major, u8 *minor)
 115{
 116        int err;
 117
 118        err = dsp_command(port, DSP_COMMAND_GET_VERSION);
 119        if (err < 0)
 120                return err;
 121
 122        err = dsp_get_byte(port, major);
 123        if (err < 0)
 124                return err;
 125
 126        err = dsp_get_byte(port, minor);
 127        if (err < 0)
 128                return err;
 129
 130        return 0;
 131}
 132
 133/*
 134 * Generic WSS support routines
 135 */
 136
 137#define WSS_CONFIG_DMA_0        (1 << 0)
 138#define WSS_CONFIG_DMA_1        (2 << 0)
 139#define WSS_CONFIG_DMA_3        (3 << 0)
 140#define WSS_CONFIG_DUPLEX       (1 << 2)
 141#define WSS_CONFIG_IRQ_7        (1 << 3)
 142#define WSS_CONFIG_IRQ_9        (2 << 3)
 143#define WSS_CONFIG_IRQ_10       (3 << 3)
 144#define WSS_CONFIG_IRQ_11       (4 << 3)
 145
 146#define WSS_PORT_CONFIG         0
 147#define WSS_PORT_SIGNATURE      3
 148
 149#define WSS_SIGNATURE           4
 150
 151static int wss_detect(void __iomem *wss_port)
 152{
 153        if ((ioread8(wss_port + WSS_PORT_SIGNATURE) & 0x3f) != WSS_SIGNATURE)
 154                return -ENODEV;
 155
 156        return 0;
 157}
 158
 159static void wss_set_config(void __iomem *wss_port, u8 wss_config)
 160{
 161        iowrite8(wss_config, wss_port + WSS_PORT_CONFIG);
 162}
 163
 164/*
 165 * Aztech Sound Galaxy specifics
 166 */
 167
 168#define GALAXY_PORT_CONFIG      1024
 169#define CONFIG_PORT_SET         4
 170
 171#define DSP_COMMAND_GALAXY_8    8
 172#define GALAXY_COMMAND_GET_TYPE 5
 173
 174#define DSP_COMMAND_GALAXY_9    9
 175#define GALAXY_COMMAND_WSSMODE  0
 176#define GALAXY_COMMAND_SB8MODE  1
 177
 178#define GALAXY_MODE_WSS         GALAXY_COMMAND_WSSMODE
 179#define GALAXY_MODE_SB8         GALAXY_COMMAND_SB8MODE
 180
 181struct snd_galaxy {
 182        void __iomem *port;
 183        void __iomem *config_port;
 184        void __iomem *wss_port;
 185        u32 config;
 186        struct resource *res_port;
 187        struct resource *res_config_port;
 188        struct resource *res_wss_port;
 189};
 190
 191static u32 config[SNDRV_CARDS];
 192static u8 wss_config[SNDRV_CARDS];
 193
 194static int snd_galaxy_match(struct device *dev, unsigned int n)
 195{
 196        if (!enable[n])
 197                return 0;
 198
 199        switch (port[n]) {
 200        case SNDRV_AUTO_PORT:
 201                dev_err(dev, "please specify port\n");
 202                return 0;
 203        case 0x220:
 204                config[n] |= GALAXY_CONFIG_SBA_220;
 205                break;
 206        case 0x240:
 207                config[n] |= GALAXY_CONFIG_SBA_240;
 208                break;
 209        case 0x260:
 210                config[n] |= GALAXY_CONFIG_SBA_260;
 211                break;
 212        case 0x280:
 213                config[n] |= GALAXY_CONFIG_SBA_280;
 214                break;
 215        default:
 216                dev_err(dev, "invalid port %#lx\n", port[n]);
 217                return 0;
 218        }
 219
 220        switch (wss_port[n]) {
 221        case SNDRV_AUTO_PORT:
 222                dev_err(dev,  "please specify wss_port\n");
 223                return 0;
 224        case 0x530:
 225                config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_530;
 226                break;
 227        case 0x604:
 228                config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_604;
 229                break;
 230        case 0xe80:
 231                config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_E80;
 232                break;
 233        case 0xf40:
 234                config[n] |= GALAXY_CONFIG_WSS_ENABLE | GALAXY_CONFIG_WSSA_F40;
 235                break;
 236        default:
 237                dev_err(dev, "invalid WSS port %#lx\n", wss_port[n]);
 238                return 0;
 239        }
 240
 241        switch (irq[n]) {
 242        case SNDRV_AUTO_IRQ:
 243                dev_err(dev,  "please specify irq\n");
 244                return 0;
 245        case 7:
 246                wss_config[n] |= WSS_CONFIG_IRQ_7;
 247                break;
 248        case 2:
 249                irq[n] = 9;
 250                fallthrough;
 251        case 9:
 252                wss_config[n] |= WSS_CONFIG_IRQ_9;
 253                break;
 254        case 10:
 255                wss_config[n] |= WSS_CONFIG_IRQ_10;
 256                break;
 257        case 11:
 258                wss_config[n] |= WSS_CONFIG_IRQ_11;
 259                break;
 260        default:
 261                dev_err(dev, "invalid IRQ %d\n", irq[n]);
 262                return 0;
 263        }
 264
 265        switch (dma1[n]) {
 266        case SNDRV_AUTO_DMA:
 267                dev_err(dev,  "please specify dma1\n");
 268                return 0;
 269        case 0:
 270                wss_config[n] |= WSS_CONFIG_DMA_0;
 271                break;
 272        case 1:
 273                wss_config[n] |= WSS_CONFIG_DMA_1;
 274                break;
 275        case 3:
 276                wss_config[n] |= WSS_CONFIG_DMA_3;
 277                break;
 278        default:
 279                dev_err(dev, "invalid playback DMA %d\n", dma1[n]);
 280                return 0;
 281        }
 282
 283        if (dma2[n] == SNDRV_AUTO_DMA || dma2[n] == dma1[n]) {
 284                dma2[n] = -1;
 285                goto mpu;
 286        }
 287
 288        wss_config[n] |= WSS_CONFIG_DUPLEX;
 289        switch (dma2[n]) {
 290        case 0:
 291                break;
 292        case 1:
 293                if (dma1[n] == 0)
 294                        break;
 295                fallthrough;
 296        default:
 297                dev_err(dev, "invalid capture DMA %d\n", dma2[n]);
 298                return 0;
 299        }
 300
 301mpu:
 302        switch (mpu_port[n]) {
 303        case SNDRV_AUTO_PORT:
 304                dev_warn(dev, "mpu_port not specified; not using MPU-401\n");
 305                mpu_port[n] = -1;
 306                goto fm;
 307        case 0x300:
 308                config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_300;
 309                break;
 310        case 0x330:
 311                config[n] |= GALAXY_CONFIG_MPU_ENABLE | GALAXY_CONFIG_MPUA_330;
 312                break;
 313        default:
 314                dev_err(dev, "invalid MPU port %#lx\n", mpu_port[n]);
 315                return 0;
 316        }
 317
 318        switch (mpu_irq[n]) {
 319        case SNDRV_AUTO_IRQ:
 320                dev_warn(dev, "mpu_irq not specified: using polling mode\n");
 321                mpu_irq[n] = -1;
 322                break;
 323        case 2:
 324                mpu_irq[n] = 9;
 325                fallthrough;
 326        case 9:
 327                config[n] |= GALAXY_CONFIG_MPUIRQ_2;
 328                break;
 329#ifdef AZT1605
 330        case 3:
 331                config[n] |= GALAXY_CONFIG_MPUIRQ_3;
 332                break;
 333#endif
 334        case 5:
 335                config[n] |= GALAXY_CONFIG_MPUIRQ_5;
 336                break;
 337        case 7:
 338                config[n] |= GALAXY_CONFIG_MPUIRQ_7;
 339                break;
 340#ifdef AZT2316
 341        case 10:
 342                config[n] |= GALAXY_CONFIG_MPUIRQ_10;
 343                break;
 344#endif
 345        default:
 346                dev_err(dev, "invalid MPU IRQ %d\n", mpu_irq[n]);
 347                return 0;
 348        }
 349
 350        if (mpu_irq[n] == irq[n]) {
 351                dev_err(dev, "cannot share IRQ between WSS and MPU-401\n");
 352                return 0;
 353        }
 354
 355fm:
 356        switch (fm_port[n]) {
 357        case SNDRV_AUTO_PORT:
 358                dev_warn(dev, "fm_port not specified: not using OPL3\n");
 359                fm_port[n] = -1;
 360                break;
 361        case 0x388:
 362                break;
 363        default:
 364                dev_err(dev, "illegal FM port %#lx\n", fm_port[n]);
 365                return 0;
 366        }
 367
 368        config[n] |= GALAXY_CONFIG_GAME_ENABLE;
 369        return 1;
 370}
 371
 372static int galaxy_init(struct snd_galaxy *galaxy, u8 *type)
 373{
 374        u8 major;
 375        u8 minor;
 376        int err;
 377
 378        err = dsp_reset(galaxy->port);
 379        if (err < 0)
 380                return err;
 381
 382        err = dsp_get_version(galaxy->port, &major, &minor);
 383        if (err < 0)
 384                return err;
 385
 386        if (major != GALAXY_DSP_MAJOR || minor != GALAXY_DSP_MINOR)
 387                return -ENODEV;
 388
 389        err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_8);
 390        if (err < 0)
 391                return err;
 392
 393        err = dsp_command(galaxy->port, GALAXY_COMMAND_GET_TYPE);
 394        if (err < 0)
 395                return err;
 396
 397        err = dsp_get_byte(galaxy->port, type);
 398        if (err < 0)
 399                return err;
 400
 401        return 0;
 402}
 403
 404static int galaxy_set_mode(struct snd_galaxy *galaxy, u8 mode)
 405{
 406        int err;
 407
 408        err = dsp_command(galaxy->port, DSP_COMMAND_GALAXY_9);
 409        if (err < 0)
 410                return err;
 411
 412        err = dsp_command(galaxy->port, mode);
 413        if (err < 0)
 414                return err;
 415
 416#ifdef AZT1605
 417        /*
 418         * Needed for MPU IRQ on AZT1605, but AZT2316 loses WSS again
 419         */
 420        err = dsp_reset(galaxy->port);
 421        if (err < 0)
 422                return err;
 423#endif
 424
 425        return 0;
 426}
 427
 428static void galaxy_set_config(struct snd_galaxy *galaxy, u32 config)
 429{
 430        u8 tmp = ioread8(galaxy->config_port + CONFIG_PORT_SET);
 431        int i;
 432
 433        iowrite8(tmp | 0x80, galaxy->config_port + CONFIG_PORT_SET);
 434        for (i = 0; i < GALAXY_CONFIG_SIZE; i++) {
 435                iowrite8(config, galaxy->config_port + i);
 436                config >>= 8;
 437        }
 438        iowrite8(tmp & 0x7f, galaxy->config_port + CONFIG_PORT_SET);
 439        msleep(10);
 440}
 441
 442static void galaxy_config(struct snd_galaxy *galaxy, u32 config)
 443{
 444        int i;
 445
 446        for (i = GALAXY_CONFIG_SIZE; i; i--) {
 447                u8 tmp = ioread8(galaxy->config_port + i - 1);
 448                galaxy->config = (galaxy->config << 8) | tmp;
 449        }
 450        config |= galaxy->config & GALAXY_CONFIG_MASK;
 451        galaxy_set_config(galaxy, config);
 452}
 453
 454static int galaxy_wss_config(struct snd_galaxy *galaxy, u8 wss_config)
 455{
 456        int err;
 457
 458        err = wss_detect(galaxy->wss_port);
 459        if (err < 0)
 460                return err;
 461
 462        wss_set_config(galaxy->wss_port, wss_config);
 463
 464        err = galaxy_set_mode(galaxy, GALAXY_MODE_WSS);
 465        if (err < 0)
 466                return err;
 467
 468        return 0;
 469}
 470
 471static void snd_galaxy_free(struct snd_card *card)
 472{
 473        struct snd_galaxy *galaxy = card->private_data;
 474
 475        if (galaxy->wss_port)
 476                wss_set_config(galaxy->wss_port, 0);
 477        if (galaxy->config_port)
 478                galaxy_set_config(galaxy, galaxy->config);
 479}
 480
 481static int snd_galaxy_probe(struct device *dev, unsigned int n)
 482{
 483        struct snd_galaxy *galaxy;
 484        struct snd_wss *chip;
 485        struct snd_card *card;
 486        u8 type;
 487        int err;
 488
 489        err = snd_devm_card_new(dev, index[n], id[n], THIS_MODULE,
 490                                sizeof(*galaxy), &card);
 491        if (err < 0)
 492                return err;
 493
 494        card->private_free = snd_galaxy_free;
 495        galaxy = card->private_data;
 496
 497        galaxy->res_port = devm_request_region(dev, port[n], 16, DRV_NAME);
 498        if (!galaxy->res_port) {
 499                dev_err(dev, "could not grab ports %#lx-%#lx\n", port[n],
 500                        port[n] + 15);
 501                return -EBUSY;
 502        }
 503        galaxy->port = devm_ioport_map(dev, port[n], 16);
 504        if (!galaxy->port)
 505                return -ENOMEM;
 506
 507        err = galaxy_init(galaxy, &type);
 508        if (err < 0) {
 509                dev_err(dev, "did not find a Sound Galaxy at %#lx\n", port[n]);
 510                return err;
 511        }
 512        dev_info(dev, "Sound Galaxy (type %d) found at %#lx\n", type, port[n]);
 513
 514        galaxy->res_config_port =
 515                devm_request_region(dev, port[n] + GALAXY_PORT_CONFIG, 16,
 516                                    DRV_NAME);
 517        if (!galaxy->res_config_port) {
 518                dev_err(dev, "could not grab ports %#lx-%#lx\n",
 519                        port[n] + GALAXY_PORT_CONFIG,
 520                        port[n] + GALAXY_PORT_CONFIG + 15);
 521                return -EBUSY;
 522        }
 523        galaxy->config_port =
 524                devm_ioport_map(dev, port[n] + GALAXY_PORT_CONFIG, 16);
 525        if (!galaxy->config_port)
 526                return -ENOMEM;
 527        galaxy_config(galaxy, config[n]);
 528
 529        galaxy->res_wss_port = devm_request_region(dev, wss_port[n], 4, DRV_NAME);
 530        if (!galaxy->res_wss_port)  {
 531                dev_err(dev, "could not grab ports %#lx-%#lx\n", wss_port[n],
 532                        wss_port[n] + 3);
 533                return -EBUSY;
 534        }
 535        galaxy->wss_port = devm_ioport_map(dev, wss_port[n], 4);
 536        if (!galaxy->wss_port)
 537                return -ENOMEM;
 538
 539        err = galaxy_wss_config(galaxy, wss_config[n]);
 540        if (err < 0) {
 541                dev_err(dev, "could not configure WSS\n");
 542                return err;
 543        }
 544
 545        strcpy(card->driver, DRV_NAME);
 546        strcpy(card->shortname, DRV_NAME);
 547        sprintf(card->longname, "%s at %#lx/%#lx, irq %d, dma %d/%d",
 548                card->shortname, port[n], wss_port[n], irq[n], dma1[n],
 549                dma2[n]);
 550
 551        err = snd_wss_create(card, wss_port[n] + 4, -1, irq[n], dma1[n],
 552                             dma2[n], WSS_HW_DETECT, 0, &chip);
 553        if (err < 0)
 554                return err;
 555
 556        err = snd_wss_pcm(chip, 0);
 557        if (err < 0)
 558                return err;
 559
 560        err = snd_wss_mixer(chip);
 561        if (err < 0)
 562                return err;
 563
 564        err = snd_wss_timer(chip, 0);
 565        if (err < 0)
 566                return err;
 567
 568        if (mpu_port[n] >= 0) {
 569                err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
 570                                          mpu_port[n], 0, mpu_irq[n], NULL);
 571                if (err < 0)
 572                        return err;
 573        }
 574
 575        if (fm_port[n] >= 0) {
 576                struct snd_opl3 *opl3;
 577
 578                err = snd_opl3_create(card, fm_port[n], fm_port[n] + 2,
 579                                      OPL3_HW_AUTO, 0, &opl3);
 580                if (err < 0) {
 581                        dev_err(dev, "no OPL device at %#lx\n", fm_port[n]);
 582                        return err;
 583                }
 584                err = snd_opl3_timer_new(opl3, 1, 2);
 585                if (err < 0)
 586                        return err;
 587
 588                err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
 589                if (err < 0)
 590                        return err;
 591        }
 592
 593        err = snd_card_register(card);
 594        if (err < 0)
 595                return err;
 596
 597        dev_set_drvdata(dev, card);
 598        return 0;
 599}
 600
 601static struct isa_driver snd_galaxy_driver = {
 602        .match          = snd_galaxy_match,
 603        .probe          = snd_galaxy_probe,
 604
 605        .driver         = {
 606                .name   = DEV_NAME
 607        }
 608};
 609
 610module_isa_driver(snd_galaxy_driver, SNDRV_CARDS);
 611