static void __init attach_maui(struct address_info *hw_config) { int this_dev; conf_printf("Maui", hw_config); hw_config->irq *= -1; hw_config->name = "Maui"; attach_mpu401(hw_config, THIS_MODULE); if (hw_config->slots[1] != -1) /* The MPU401 driver installed itself */ { struct synth_operations *synth; this_dev = hw_config->slots[1]; /* * Intercept patch loading calls so that they can be handled * by the Maui driver. */ synth = midi_devs[this_dev]->converter; synth->id = "MAUI"; if (synth != NULL) { orig_load_patch = synth->load_patch; synth->load_patch = &maui_load_patch; } else printk(KERN_ERR "Maui: Can't install patch loader\n"); } }
static void __init attach_uart6850(struct address_info *hw_config) { int ok, timeout; unsigned long flags; if (!uart6850_detected) return; if ((my_dev = sound_alloc_mididev()) == -1) { printk(KERN_INFO "uart6850: Too many midi devices detected\n"); return; } uart6850_base = hw_config->io_base; uart6850_osp = hw_config->osp; uart6850_irq = hw_config->irq; spin_lock_irqsave(&lock,flags); for (timeout = 30000; timeout > 0 && !output_ready(); timeout--); /* * Wait */ uart6850_cmd(UART_MODE_ON); ok = 1; spin_unlock_irqrestore(&lock,flags); conf_printf("6850 Midi Interface", hw_config); std_midi_synth.midi_dev = my_dev; hw_config->slots[4] = my_dev; midi_devs[my_dev] = &uart6850_operations; sequencer_init(); }
void attach_vidc(struct address_info *hw_config) { char name[32]; int i; sprintf(name, "VIDC %d-bit sound", hw_config->card_subtype); conf_printf(name, hw_config); for (i = 0; i < 2; i++) { dma_buf[i] = get_free_page(GFP_KERNEL); dma_pbuf[i] = virt_to_phys(dma_buf[i]); } if (sound_alloc_dma(hw_config->dma, "VIDCsound")) { printk(KERN_ERR "VIDCsound: can't allocate virtual DMA channel\n"); return; } if (request_irq(hw_config->irq, vidc_sound_dma_irq, 0, "VIDCsound", &dma_start)) { printk(KERN_ERR "VIDCsound: can't allocate DMA interrupt\n"); return; } // vidc_synth_init(hw_config); vidc_audio_init(hw_config); vidc_mixer_init(hw_config); }
/* ** Set the DefFiltOpts: line for a group. */ int group_deffiltopts_internal(const char *group) { if(grpopen(group, TRUE, FALSE)) { fprintf(errors, "The group \"%s\" does not exist.\n", group); return EXIT_BADDEST; } { void *qobj = NULL; const char *p; gu_Try { qobj = queueinfo_new(QUEUEINFO_GROUP, group); queueinfo_set_warnings_file(qobj, errors); queueinfo_set_debug_level(qobj, debug_level); /* Modify the group's configuration file. */ while(confread()) { if(lmatch(confline, "DefFiltOpts:")) continue; if((p = lmatchp(confline, "Printer:"))) queueinfo_add_printer(qobj, p); conf_printf("%s\n", confline); } if((p = queueinfo_computedDefaultFilterOptions(qobj))) conf_printf("DefFiltOpts: %s\n", p); confclose(); } gu_Final { if(qobj) queueinfo_free(qobj); } gu_Catch { confabort(); fprintf(errors, "%s: %s\n", myname, gu_exception); return exception_to_exitcode(gu_exception_code); } } return EXIT_OK; } /* end of group_deffiltopts_internal() */
/* ** Set a group's rotate setting. */ int group_rotate(const char *argv[]) { const char *group = argv[0]; int newstate; if( ! am_administrator() ) return EXIT_DENIED; if(! group || ! argv[1] || ((newstate=gu_torf(argv[1]))==ANSWER_UNKNOWN) ) { fputs(_("You must supply the name of a group and \"true\" or \"false\".\n"), errors); return EXIT_SYNTAX; } /* make sure the group exists */ if(grpopen(group, TRUE, FALSE)) { fprintf(errors, _("The group \"%s\" does not exist.\n"),group); return EXIT_BADDEST; } /* Modify the group's configuration file. */ while(confread()) { if(lmatch(confline, "Rotate:")) break; else conf_printf("%s\n", confline); } conf_printf("Rotate: %s\n", newstate ? "True" : "False"); while(confread()) /* copy rest of file, */ { if(lmatch(confline, "Rotate:")) /* discard */ continue; else /* copy */ conf_printf("%s\n", confline); } confclose(); reread_group(group); /* pprd must know the rotate setting */ return EXIT_OK; } /* end of group_rotate() */
void attach_sb16midi(struct address_info * hw_config) { int ok, timeout; u_long flags; sb16midi_base = hw_config->io_base; if (!sb16midi_detected) return; flags = splhigh(); for (timeout = 30000; timeout < 0 && !output_ready(); timeout--); /* Wait */ input_byte = 0; sb16midi_cmd(UART_MODE_ON); ok = 0; for (timeout = 50000; timeout > 0 && !ok; timeout--) if (input_byte == MPU_ACK) ok = 1; else if (input_avail()) if (sb16midi_read() == MPU_ACK) ok = 1; splx(flags); if (num_midis >= MAX_MIDI_DEV) { printf("Sound: Too many midi devices detected\n"); return; } conf_printf("SoundBlaster MPU-401", hw_config); std_midi_synth.midi_dev = my_dev = num_midis; midi_devs[num_midis++] = &sb16midi_operations; return; }
void __init attach_sscape(struct address_info *hw_config) { #ifndef SSCAPE_REGS /* * Config register values for Spea/V7 Media FX and Ensoniq S-2000. * These values are card * dependent. If you have another SoundScape based card, you have to * find the correct values. Do the following: * - Compile this driver with SSCAPE_DEBUG1 defined. * - Shut down and power off your machine. * - Boot with DOS so that the SSINIT.EXE program is run. * - Warm boot to {Linux|SYSV|BSD} and write down the lines displayed * when detecting the SoundScape. * - Modify the following list to use the values printed during boot. * Undefine the SSCAPE_DEBUG1 */ #define SSCAPE_REGS { \ /* I0 */ 0x00, \ /* I1 */ 0xf0, /* Note! Ignored. Set always to 0xf0 */ \ /* I2 */ 0x20, /* Note! Ignored. Set always to 0x20 */ \ /* I3 */ 0x20, /* Note! Ignored. Set always to 0x20 */ \ /* I4 */ 0xf5, /* Ignored */ \ /* I5 */ 0x10, \ /* I6 */ 0x00, \ /* I7 */ 0x2e, /* I7 MEM config A. Likely to vary between models */ \ /* I8 */ 0x00, /* I8 MEM config B. Likely to vary between models */ \ /* I9 */ 0x40 /* Ignored */ \ } #endif unsigned long flags; static unsigned char regs[10] = SSCAPE_REGS; int i, irq_bits = 0xff; if (sscape_detected != hw_config->io_base) return; request_region(devc->base + 2, 6, "SoundScape"); if (old_hardware) { valid_interrupts = valid_interrupts_old; conf_printf("Ensoniq SoundScape (old)", hw_config); } else conf_printf("Ensoniq SoundScape", hw_config); for (i = 0; i < sizeof(valid_interrupts); i++) { if (hw_config->irq == valid_interrupts[i]) { irq_bits = i; break; } } if (hw_config->irq > 15 || ((regs[4] = irq_bits) == 0xff)) { printk(KERN_ERR "Invalid IRQ%d\n", hw_config->irq); return; } if (!sscape_is_pnp) { save_flags(flags); cli(); for (i = 1; i < 10; i++) { switch (i) { case 1: /* Host interrupt enable */ sscape_write(devc, i, 0xf0); /* All interrupts enabled */ break; case 2: /* DMA A status/trigger register */ case 3: /* DMA B status/trigger register */ sscape_write(devc, i, 0x20); /* DMA channel disabled */ break; case 4: /* Host interrupt config reg */ sscape_write(devc, i, 0xf0 | (irq_bits << 2) | irq_bits); break; case 5: /* Don't destroy CD-ROM DMA config bits (0xc0) */ sscape_write(devc, i, (regs[i] & 0x3f) | (sscape_read(devc, i) & 0xc0)); break; case 6: /* CD-ROM config (WSS codec actually) */ sscape_write(devc, i, regs[i]); break; case 9: /* Master control reg. Don't modify CR-ROM bits. Disable SB emul */ sscape_write(devc, i, (sscape_read(devc, i) & 0xf0) | 0x08); break; default: sscape_write(devc, i, regs[i]); } } restore_flags(flags); } #ifdef SSCAPE_DEBUG2 /* * Temporary debugging aid. Print contents of the registers after * changing them. */ { int i; for (i = 0; i < 13; i++) printk("I%d = %02x (new value)\n", i, sscape_read(devc, i)); } #endif if (probe_mpu401(hw_config)) hw_config->always_detect = 1; hw_config->name = "SoundScape"; hw_config->irq *= -1; /* Negative value signals IRQ sharing */ attach_mpu401(hw_config, THIS_MODULE); hw_config->irq *= -1; /* Restore it */ if (hw_config->slots[1] != -1) /* The MPU driver installed itself */ { sscape_mididev = hw_config->slots[1]; midi_devs[hw_config->slots[1]]->coproc = &sscape_coproc_operations; } sscape_write(devc, GA_INTENA_REG, 0x80); /* Master IRQ enable */ devc->ok = 1; devc->failed = 0; }
int probe_uart401(struct address_info *hw_config, struct module *owner) { uart401_devc *devc; char *name = "MPU-401 (UART) MIDI"; int ok = 0; unsigned long flags; DDB(printk("Entered probe_uart401()\n")); /* Default to "not found" */ hw_config->slots[4] = -1; if (!request_region(hw_config->io_base, 4, "MPU-401 UART")) { printk(KERN_INFO "uart401: could not request_region(%d, 4)\n", hw_config->io_base); return 0; } devc = kmalloc(sizeof(uart401_devc), GFP_KERNEL); if (!devc) { printk(KERN_WARNING "uart401: Can't allocate memory\n"); goto cleanup_region; } devc->base = hw_config->io_base; devc->irq = hw_config->irq; devc->osp = hw_config->osp; devc->midi_input_intr = NULL; devc->opened = 0; devc->input_byte = 0; devc->my_dev = 0; devc->share_irq = 0; spin_lock_init(&devc->lock); spin_lock_irqsave(&devc->lock,flags); ok = reset_uart401(devc); spin_unlock_irqrestore(&devc->lock,flags); if (!ok) goto cleanup_devc; if (hw_config->name) name = hw_config->name; if (devc->irq < 0) { devc->share_irq = 1; devc->irq *= -1; } else devc->share_irq = 0; if (!devc->share_irq) if (request_irq(devc->irq, uart401intr, 0, "MPU-401 UART", devc) < 0) { printk(KERN_WARNING "uart401: Failed to allocate IRQ%d\n", devc->irq); devc->share_irq = 1; } devc->my_dev = sound_alloc_mididev(); enter_uart_mode(devc); if (devc->my_dev == -1) { printk(KERN_INFO "uart401: Too many midi devices detected\n"); goto cleanup_irq; } conf_printf(name, hw_config); midi_devs[devc->my_dev] = kmemdup(&uart401_operations, sizeof(struct midi_operations), GFP_KERNEL); if (!midi_devs[devc->my_dev]) { printk(KERN_ERR "uart401: Failed to allocate memory\n"); goto cleanup_unload_mididev; } if (owner) midi_devs[devc->my_dev]->owner = owner; midi_devs[devc->my_dev]->devc = devc; midi_devs[devc->my_dev]->converter = kmemdup(&std_midi_synth, sizeof(struct synth_operations),
static int __init probe_maui(struct address_info *hw_config) { struct resource *ports; int this_dev; int i; int tmp1, tmp2, ret; ports = request_region(hw_config->io_base, 2, "mpu401"); if (!ports) return 0; if (!request_region(hw_config->io_base + 2, 6, "Maui")) goto out; maui_base = hw_config->io_base; maui_osp = hw_config->osp; if (request_irq(hw_config->irq, mauiintr, 0, "Maui", NULL) < 0) goto out2; /* * Initialize the processor if necessary */ if (maui_osLen > 0) { if (!(inb(HOST_STAT_PORT) & STAT_TX_AVAIL) || !maui_write(0x9F) || /* Report firmware version */ !maui_short_wait(STAT_RX_AVAIL) || maui_read() == -1 || maui_read() == -1) if (!maui_init(hw_config->irq)) goto out3; } if (!maui_write(0xCF)) /* Report hardware version */ { printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n"); goto out3; } if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1) { printk(KERN_ERR "No WaveFront firmware detected (card uninitialized?)\n"); goto out3; } if (tmp1 == 0xff || tmp2 == 0xff) goto out3; printk(KERN_DEBUG "WaveFront hardware version %d.%d\n", tmp1, tmp2); if (!maui_write(0x9F)) /* Report firmware version */ goto out3; if ((tmp1 = maui_read()) == -1 || (tmp2 = maui_read()) == -1) goto out3; printk(KERN_DEBUG "WaveFront firmware version %d.%d\n", tmp1, tmp2); if (!maui_write(0x85)) /* Report free DRAM */ goto out3; tmp1 = 0; for (i = 0; i < 4; i++) { tmp1 |= maui_read() << (7 * i); } printk(KERN_DEBUG "Available DRAM %dk\n", tmp1 / 1024); for (i = 0; i < 1000; i++) if (probe_mpu401(hw_config, ports)) break; ret = probe_mpu401(hw_config, ports); if (!ret) goto out3; conf_printf("Maui", hw_config); hw_config->irq *= -1; hw_config->name = "Maui"; attach_mpu401(hw_config, THIS_MODULE); if (hw_config->slots[1] != -1) /* The MPU401 driver installed itself */ { struct synth_operations *synth; this_dev = hw_config->slots[1]; /* * Intercept patch loading calls so that they can be handled * by the Maui driver. */ synth = midi_devs[this_dev]->converter; if (synth != NULL) { synth->id = "MAUI"; orig_load_patch = synth->load_patch; synth->load_patch = &maui_load_patch; } else printk(KERN_ERR "Maui: Can't install patch loader\n"); } return 1; out3: free_irq(hw_config->irq, NULL); out2: release_region(hw_config->io_base + 2, 6); out: release_region(hw_config->io_base, 2); return 0; }
void attach_sscape(struct address_info * hw_config) { #ifndef SSCAPE_REGS /* * Config register values for Spea/V7 Media FX and Ensoniq S-2000. * These values are card dependent. If you have another SoundScape * based card, you have to find the correct values. Do the following: * - Compile this driver with SSCAPE_DEBUG1 defined. - Shut down and * power off your machine. - Boot with DOS so that the SSINIT.EXE * program is run. - Warm boot to {Linux|SYSV|BSD} and write down the * lines displayed when detecting the SoundScape. - Modify the * following list to use the values printed during boot. Undefine the * SSCAPE_DEBUG1 */ #define SSCAPE_REGS { \ /* I0 */ 0x00, \ 0xf0, /* Note! Ignored. Set always to 0xf0 */ \ 0x20, /* Note! Ignored. Set always to 0x20 */ \ 0x20, /* Note! Ignored. Set always to 0x20 */ \ 0xf5, /* Ignored */ \ 0x10, \ 0x00, \ 0x2e, /* I7 MEM config A. Likely to vary between models */ \ 0x00, /* I8 MEM config B. Likely to vary between models */ \ /* I9 */ 0x40 /* Ignored */ \ } #endif u_long flags; static u_char regs[10] = SSCAPE_REGS; int i, irq_bits = 0xff; if (sscape_detected != hw_config->io_base) return; if (old_hardware) { valid_interrupts = valid_interrupts_old; conf_printf("Ensoniq Soundscape (old)", hw_config); } else conf_printf("Ensoniq Soundscape", hw_config); for (i = 0; i < sizeof(valid_interrupts); i++) if (hw_config->irq == valid_interrupts[i]) { irq_bits = i; break; } if (hw_config->irq > 15 || (regs[4] = irq_bits == 0xff)) { printf("Invalid IRQ%d\n", hw_config->irq); return; } flags = splhigh(); for (i = 1; i < 10; i++) switch (i) { case 1: /* Host interrupt enable */ sscape_write(devc, i, 0xf0); /* All interrupts enabled */ break; case 2: /* DMA A status/trigger register */ case 3: /* DMA B status/trigger register */ sscape_write(devc, i, 0x20); /* DMA channel disabled */ break; case 4: /* Host interrupt config reg */ sscape_write(devc, i, 0xf0 | (irq_bits << 2) | irq_bits); break; case 5: /* Don't destroy CD-ROM DMA config bits (0xc0) */ sscape_write(devc, i, (regs[i] & 0x3f) | (sscape_read(devc, i) & 0xc0)); break; case 6: /* CD-ROM config. Don't touch. */ break; case 9: /* Master control reg. Don't modify CR-ROM * bits. Disable SB emul */ sscape_write(devc, i, (sscape_read(devc, i) & 0xf0) | 0x00); break; default: sscape_write(devc, i, regs[i]); } splx(flags); #ifdef SSCAPE_DEBUG2 /* * Temporary debugging aid. Print contents of the registers after * changing them. */ { int i; for (i = 0; i < 13; i++) printf("I%d = %02x (new value)\n", i, sscape_read(devc, i)); } #endif #if defined(CONFIG_MIDI) && defined(CONFIG_MPU_EMU) if (probe_mpu401(hw_config)) hw_config->always_detect = 1; { int prev_devs; prev_devs = num_midis; attach_mpu401(hw_config); if (num_midis == (prev_devs + 1)) /* The MPU driver * installed itself */ midi_devs[prev_devs]->coproc = &sscape_coproc_operations; } #endif #ifndef EXCLUDE_NATIVE_PCM /* Not supported yet */ #ifdef CONFIG_AUDIO if (num_audiodevs < MAX_AUDIO_DEV) { int my_dev; audio_devs[my_dev = num_audiodevs++] = &sscape_audio_operations; audio_devs[my_dev]->dmachan1 = hw_config->dma; audio_devs[my_dev]->buffsize = DSP_BUFFSIZE; audio_devs[my_dev]->devc = devc; devc->my_audiodev = my_dev; devc->opened = 0; audio_devs[my_dev]->coproc = &sscape_coproc_operations; if (snd_set_irq_handler(hw_config->irq, sscapeintr, devc->osp) < 0) printf("Error: Can't allocate IRQ for SoundScape\n"); sscape_write(devc, GA_INTENA_REG, 0x80); /* Master IRQ enable */ } else printf("SoundScape: More than enough audio devices detected\n"); #endif #endif devc->ok = 1; devc->failed = 0; return; }
/* ** Remove a member from a group. This is a separate function because ** it is called from ppad_printer.c when a printer is deleted and ** it is the member of a group. ** ** sucess: EXIT_OK ** bad group: EXIT_BADDEST ** bad member: EXIT_NOTFOUND */ int group_remove_internal(const char *group, const char *member) { char *ptr; int found = FALSE; void *qobj = NULL; if(grpopen(group, TRUE, FALSE)) return EXIT_BADDEST; gu_Try { qobj = queueinfo_new(QUEUEINFO_GROUP, group); queueinfo_set_warnings_file(qobj, errors); queueinfo_set_debug_level(qobj, debug_level); /* ** Copy the configuration file. */ while(confread()) { if(lmatch(confline, "DefFiltOpts:")) /* delete old lines */ continue; if(lmatch(confline, "Printer:")) /* if member name, */ { ptr = &confline[8]; ptr += strspn(ptr, " \t"); if(strcmp(ptr,member)==0) /* If it is the one we */ { /* are deleting, */ found=TRUE; /* set a flag */ continue; /* and don't copy. */ } queueinfo_add_printer(qobj, ptr); /* Otherwise, add its PPD file, */ } conf_printf("%s\n",confline); } /* Emmit the new "DefFiltOpts:" line. */ { const char *cp = queueinfo_computedDefaultFilterOptions(qobj); if(cp) conf_printf("DefFiltOpts: %s\n", cp); } confclose(); } gu_Final { if(qobj) queueinfo_free(qobj); } gu_Catch { confabort(); fprintf(errors, "%s: %s\n", myname, gu_exception); return exception_to_exitcode(gu_exception_code); } if(found) { reread_group(group); return EXIT_OK; } else { return EXIT_NOTFOUND; } } /* end of _group_remove() */
/* ** Add a member to a group, creating the group if ** it does not already exist. */ int group_members_add(const char *argv[], gu_boolean do_add) { const char *group = argv[0]; int x; char *ptr; int count = 0; void *qobj = NULL; if( ! am_administrator() ) return EXIT_DENIED; if(do_add) { if(! group || ! argv[1]) { fputs(_("You must specify a new or existing group and one or more printers\n" "to add to it.\n"), errors); return EXIT_SYNTAX; } } else { if(!group) { fputs(_("You must specify a new or existing group and zero or more printers\n" "to be its members.\n"), errors); return EXIT_SYNTAX; } } if(strlen(group) > MAX_DESTNAME) { fputs(_("Group name is too long.\n"), errors); return EXIT_SYNTAX; } if(strpbrk(group, DEST_DISALLOWED)) { fputs(_("Group name contains a disallowed character.\n"), errors); return EXIT_SYNTAX; } if(strchr(DEST_DISALLOWED_LEADING, (int)group[0])) { fputs(_("Group name begins with a disallowed character.\n"), errors); return EXIT_SYNTAX; } /* ** Make sure the proposed new members really exist. ** We do this by trying to open their configuration files ** with prnopen(). */ for(x=1; argv[x]; x++) { if(prnopen(argv[x], FALSE)) { fprintf(errors, _("The printer \"%s\" does not exist.\n"), argv[x]); return EXIT_BADDEST; } else { confclose(); } } /* ** If the group to which we are adding a printer ** does not exist, create it. */ if(grpopen(group, TRUE, TRUE)) return EXIT_INTERNAL; /* Copy up to but not including the 1st "Printer:" line. */ while(confread()) { if(lmatch(confline, "DefFiltOpts:")) /* discard */ continue; if(lmatch(confline, "Printer:")) /* stop */ break; conf_printf("%s\n", confline); /* copy */ } gu_Try { qobj = queueinfo_new(QUEUEINFO_GROUP, group); queueinfo_set_warnings_file(qobj, errors); queueinfo_set_debug_level(qobj, debug_level); /* Copy all the remaining lines. */ do { if((ptr = lmatchp(confline, "Printer:"))) { if(!do_add) /* If we are adding, just delete it. */ continue; for(x=1; argv[x]; x++) /* Is this the same as one we are adding? */ { if(strcmp(ptr, argv[x]) == 0) gu_Throw(_("%d Printer \"%s\" is already a member of \"%s\".\n"), EXIT_ALREADY, argv[x], group); queueinfo_add_printer(qobj, ptr); count++; } } /* Delete old "DefFiltOpts:" lines as we go. */ else if(lmatch(confline, "DefFiltOpts:")) continue; /* Other lines we keep. */ conf_printf("%s\n", confline); } while(confread()); /* Add a "Printer:" line for each new member. */ for(x=1; argv[x]; x++) { conf_printf("Printer: %s\n", argv[x]); queueinfo_add_printer(qobj, argv[x]); count++; } /* Emmit the new "DefFiltOpts:" line. */ { const char *cp = queueinfo_computedDefaultFilterOptions(qobj); if(cp) conf_printf("DefFiltOpts: %s\n", cp); } /* See if adding our printer will make the group too big. */ if(count > MAX_GROUPSIZE) gu_Throw(_("%d Group \"%s\" would have %d members, only %d are allowed.\n"), EXIT_OVERFLOW, group, count, MAX_GROUPSIZE); /* Commit the changes. */ confclose(); } gu_Final { if(qobj) queueinfo_free(qobj); } gu_Catch { confabort(); /* roll back the changes */ fprintf(errors, "%s: %s\n", myname, gu_exception); return exception_to_exitcode(gu_exception_code); } /* necessary because pprd keeps track of mounted media */ reread_group(group); return EXIT_OK; } /* end of group_add() */
/* * Install OPL3-SA2 based card(s). * * Need to have ad1848 and mpu401 loaded ready. */ static int __init init_opl3sa2(void) { int card; int max; /* Sanitize isapnp and multiple settings */ isapnp = isapnp != 0 ? 1 : 0; multiple = multiple != 0 ? 1 : 0; max = (multiple && isapnp) ? OPL3SA2_CARDS_MAX : 1; for(card = 0; card < max; card++, opl3sa2_cards_num++) { #if defined CONFIG_ISAPNP || defined CONFIG_ISAPNP_MODULE /* * Please remember that even with CONFIG_ISAPNP defined one * should still be able to disable PNP support for this * single driver! */ if(isapnp && opl3sa2_isapnp_probe(&cfg[card], &cfg_mss[card], &cfg_mpu[card], card) < 0) { if(!opl3sa2_cards_num) printk(KERN_INFO "opl3sa2: No PnP cards found\n"); if(io == -1) break; isapnp=0; printk(KERN_INFO "opl3sa2: Search for a card at 0x%d.\n", io); /* Fall through */ } #endif /* If a user wants an I/O then assume they meant it */ if(!isapnp) { if(io == -1 || irq == -1 || dma == -1 || dma2 == -1 || mss_io == -1) { printk(KERN_ERR "opl3sa2: io, mss_io, irq, dma, and dma2 must be set\n"); return -EINVAL; } /* * Our own config: * (NOTE: IRQ and DMA aren't used, so they're set to * give pretty output from conf_printf. :) */ cfg[card].io_base = io; cfg[card].irq = irq; cfg[card].dma = dma; cfg[card].dma2 = dma2; /* The MSS config: */ cfg_mss[card].io_base = mss_io; cfg_mss[card].irq = irq; cfg_mss[card].dma = dma; cfg_mss[card].dma2 = dma2; cfg_mss[card].card_subtype = 1; /* No IRQ or DMA setup */ cfg_mpu[card].io_base = mpu_io; cfg_mpu[card].irq = irq; cfg_mpu[card].dma = -1; cfg_mpu[card].always_detect = 1; /* Use shared IRQs */ /* Call me paranoid: */ opl3sa2_clear_slots(&cfg[card]); opl3sa2_clear_slots(&cfg_mss[card]); opl3sa2_clear_slots(&cfg_mpu[card]); } if(!probe_opl3sa2(&cfg[card], card) || !probe_opl3sa2_mss(&cfg_mss[card])) { /* * If one or more cards are already registered, don't * return an error but print a warning. Note, this * should never really happen unless the hardware or * ISA PnP screwed up. */ if(opl3sa2_cards_num) { printk(KERN_WARNING "opl3sa2: There was a problem probing one " " of the ISA PNP cards, continuing\n"); opl3sa2_cards_num--; continue; } else return -ENODEV; } attach_opl3sa2(&cfg[card], card); conf_printf(chipset_name[card], &cfg[card]); attach_opl3sa2_mss(&cfg_mss[card]); attach_opl3sa2_mixer(&cfg[card], card); /* * Set the Yamaha 3D enhancement mode (aka Ymersion) if asked to and * it's supported. */ if(ymode != -1) { if(chipset[card] == CHIPSET_OPL3SA2) { printk(KERN_ERR "opl3sa2: ymode not supported on OPL3-SA2\n"); } else { opl3sa2_set_ymode(&cfg[card], ymode); } } /* Set A/D input to Mono loopback if asked to. */ if(loopback != -1) { opl3sa2_set_loopback(&cfg[card], loopback); } /* Attach MPU if we've been asked to do so */ if(cfg_mpu[card].io_base != -1) { if(probe_opl3sa2_mpu(&cfg_mpu[card])) { attach_opl3sa2_mpu(&cfg_mpu[card]); } } } if(isapnp) { printk(KERN_NOTICE "opl3sa2: %d PnP card(s) found.\n", opl3sa2_cards_num); } return 0; }