root/sound/isa/galaxy/galaxy.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. dsp_get_byte
  2. dsp_reset
  3. dsp_command
  4. dsp_get_version
  5. wss_detect
  6. wss_set_config
  7. snd_galaxy_match
  8. galaxy_init
  9. galaxy_set_mode
  10. galaxy_set_config
  11. galaxy_config
  12. galaxy_wss_config
  13. snd_galaxy_free
  14. snd_galaxy_probe
  15. snd_galaxy_remove

   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 
  19 MODULE_DESCRIPTION(CRD_NAME);
  20 MODULE_AUTHOR("Rene Herman");
  21 MODULE_LICENSE("GPL");
  22 
  23 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
  24 static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
  25 static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE;
  26 
  27 module_param_array(index, int, NULL, 0444);
  28 MODULE_PARM_DESC(index, "Index value for " CRD_NAME " soundcard.");
  29 module_param_array(id, charp, NULL, 0444);
  30 MODULE_PARM_DESC(id, "ID string for " CRD_NAME " soundcard.");
  31 module_param_array(enable, bool, NULL, 0444);
  32 MODULE_PARM_DESC(enable, "Enable " CRD_NAME " soundcard.");
  33 
  34 static long port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
  35 static long wss_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
  36 static long mpu_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
  37 static long fm_port[SNDRV_CARDS] = SNDRV_DEFAULT_PORT;
  38 static int irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
  39 static int mpu_irq[SNDRV_CARDS] = SNDRV_DEFAULT_IRQ;
  40 static int dma1[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
  41 static int dma2[SNDRV_CARDS] = SNDRV_DEFAULT_DMA;
  42 
  43 module_param_hw_array(port, long, ioport, NULL, 0444);
  44 MODULE_PARM_DESC(port, "Port # for " CRD_NAME " driver.");
  45 module_param_hw_array(wss_port, long, ioport, NULL, 0444);
  46 MODULE_PARM_DESC(wss_port, "WSS port # for " CRD_NAME " driver.");
  47 module_param_hw_array(mpu_port, long, ioport, NULL, 0444);
  48 MODULE_PARM_DESC(mpu_port, "MPU-401 port # for " CRD_NAME " driver.");
  49 module_param_hw_array(fm_port, long, ioport, NULL, 0444);
  50 MODULE_PARM_DESC(fm_port, "FM port # for " CRD_NAME " driver.");
  51 module_param_hw_array(irq, int, irq, NULL, 0444);
  52 MODULE_PARM_DESC(irq, "IRQ # for " CRD_NAME " driver.");
  53 module_param_hw_array(mpu_irq, int, irq, NULL, 0444);
  54 MODULE_PARM_DESC(mpu_irq, "MPU-401 IRQ # for " CRD_NAME " driver.");
  55 module_param_hw_array(dma1, int, dma, NULL, 0444);
  56 MODULE_PARM_DESC(dma1, "Playback DMA # for " CRD_NAME " driver.");
  57 module_param_hw_array(dma2, int, dma, NULL, 0444);
  58 MODULE_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 
  74 static 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 
  87 static 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 
 101 static 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 
 114 static 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 
 151 static 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 
 159 static 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 
 181 struct 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 
 191 static u32 config[SNDRV_CARDS];
 192 static u8 wss_config[SNDRV_CARDS];
 193 
 194 static 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                 /* Fall through */
 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                 /* Fall through */
 296         default:
 297                 dev_err(dev, "invalid capture DMA %d\n", dma2[n]);
 298                 return 0;
 299         }
 300 
 301 mpu:
 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                 /* Fall through */
 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 
 355 fm:
 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 
 372 static 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 
 404 static 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 
 428 static 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 
 442 static 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 
 454 static 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 
 471 static 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                 ioport_unmap(galaxy->wss_port);
 478                 release_and_free_resource(galaxy->res_wss_port);
 479         }
 480         if (galaxy->config_port) {
 481                 galaxy_set_config(galaxy, galaxy->config);
 482                 ioport_unmap(galaxy->config_port);
 483                 release_and_free_resource(galaxy->res_config_port);
 484         }
 485         if (galaxy->port) {
 486                 ioport_unmap(galaxy->port);
 487                 release_and_free_resource(galaxy->res_port);
 488         }
 489 }
 490 
 491 static int snd_galaxy_probe(struct device *dev, unsigned int n)
 492 {
 493         struct snd_galaxy *galaxy;
 494         struct snd_wss *chip;
 495         struct snd_card *card;
 496         u8 type;
 497         int err;
 498 
 499         err = snd_card_new(dev, index[n], id[n], THIS_MODULE,
 500                            sizeof(*galaxy), &card);
 501         if (err < 0)
 502                 return err;
 503 
 504         card->private_free = snd_galaxy_free;
 505         galaxy = card->private_data;
 506 
 507         galaxy->res_port = request_region(port[n], 16, DRV_NAME);
 508         if (!galaxy->res_port) {
 509                 dev_err(dev, "could not grab ports %#lx-%#lx\n", port[n],
 510                         port[n] + 15);
 511                 err = -EBUSY;
 512                 goto error;
 513         }
 514         galaxy->port = ioport_map(port[n], 16);
 515 
 516         err = galaxy_init(galaxy, &type);
 517         if (err < 0) {
 518                 dev_err(dev, "did not find a Sound Galaxy at %#lx\n", port[n]);
 519                 goto error;
 520         }
 521         dev_info(dev, "Sound Galaxy (type %d) found at %#lx\n", type, port[n]);
 522 
 523         galaxy->res_config_port = request_region(port[n] + GALAXY_PORT_CONFIG,
 524                                                  16, DRV_NAME);
 525         if (!galaxy->res_config_port) {
 526                 dev_err(dev, "could not grab ports %#lx-%#lx\n",
 527                         port[n] + GALAXY_PORT_CONFIG,
 528                         port[n] + GALAXY_PORT_CONFIG + 15);
 529                 err = -EBUSY;
 530                 goto error;
 531         }
 532         galaxy->config_port = ioport_map(port[n] + GALAXY_PORT_CONFIG, 16);
 533 
 534         galaxy_config(galaxy, config[n]);
 535 
 536         galaxy->res_wss_port = request_region(wss_port[n], 4, DRV_NAME);
 537         if (!galaxy->res_wss_port)  {
 538                 dev_err(dev, "could not grab ports %#lx-%#lx\n", wss_port[n],
 539                         wss_port[n] + 3);
 540                 err = -EBUSY;
 541                 goto error;
 542         }
 543         galaxy->wss_port = ioport_map(wss_port[n], 4);
 544 
 545         err = galaxy_wss_config(galaxy, wss_config[n]);
 546         if (err < 0) {
 547                 dev_err(dev, "could not configure WSS\n");
 548                 goto error;
 549         }
 550 
 551         strcpy(card->driver, DRV_NAME);
 552         strcpy(card->shortname, DRV_NAME);
 553         sprintf(card->longname, "%s at %#lx/%#lx, irq %d, dma %d/%d",
 554                 card->shortname, port[n], wss_port[n], irq[n], dma1[n],
 555                 dma2[n]);
 556 
 557         err = snd_wss_create(card, wss_port[n] + 4, -1, irq[n], dma1[n],
 558                              dma2[n], WSS_HW_DETECT, 0, &chip);
 559         if (err < 0)
 560                 goto error;
 561 
 562         err = snd_wss_pcm(chip, 0);
 563         if (err < 0)
 564                 goto error;
 565 
 566         err = snd_wss_mixer(chip);
 567         if (err < 0)
 568                 goto error;
 569 
 570         err = snd_wss_timer(chip, 0);
 571         if (err < 0)
 572                 goto error;
 573 
 574         if (mpu_port[n] >= 0) {
 575                 err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401,
 576                                           mpu_port[n], 0, mpu_irq[n], NULL);
 577                 if (err < 0)
 578                         goto error;
 579         }
 580 
 581         if (fm_port[n] >= 0) {
 582                 struct snd_opl3 *opl3;
 583 
 584                 err = snd_opl3_create(card, fm_port[n], fm_port[n] + 2,
 585                                       OPL3_HW_AUTO, 0, &opl3);
 586                 if (err < 0) {
 587                         dev_err(dev, "no OPL device at %#lx\n", fm_port[n]);
 588                         goto error;
 589                 }
 590                 err = snd_opl3_timer_new(opl3, 1, 2);
 591                 if (err < 0)
 592                         goto error;
 593 
 594                 err = snd_opl3_hwdep_new(opl3, 0, 1, NULL);
 595                 if (err < 0)
 596                         goto error;
 597         }
 598 
 599         err = snd_card_register(card);
 600         if (err < 0)
 601                 goto error;
 602 
 603         dev_set_drvdata(dev, card);
 604         return 0;
 605 
 606 error:
 607         snd_card_free(card);
 608         return err;
 609 }
 610 
 611 static int snd_galaxy_remove(struct device *dev, unsigned int n)
 612 {
 613         snd_card_free(dev_get_drvdata(dev));
 614         return 0;
 615 }
 616 
 617 static struct isa_driver snd_galaxy_driver = {
 618         .match          = snd_galaxy_match,
 619         .probe          = snd_galaxy_probe,
 620         .remove         = snd_galaxy_remove,
 621 
 622         .driver         = {
 623                 .name   = DEV_NAME
 624         }
 625 };
 626 
 627 module_isa_driver(snd_galaxy_driver, SNDRV_CARDS);

/* [<][>][^][v][top][bottom][index][help] */