struct EMU10kxData* AllocDriverData( struct pci_dev* dev, struct DriverBase* AHIsubBase ) #endif { struct EMU10kxBase* EMU10kxBase = (struct EMU10kxBase*) AHIsubBase; struct EMU10kxData* dd; UWORD command_word; // FIXME: This should be non-cachable, DMA-able memory dd = AllocVec( sizeof( *dd ), MEMF_PUBLIC | MEMF_CLEAR ); if( dd == NULL ) { Req( "Unable to allocate driver structure." ); return NULL; } dd->ahisubbase = AHIsubBase; dd->interrupt.is_Node.ln_Type = INTERRUPT_NODE_TYPE; dd->interrupt.is_Node.ln_Pri = 0; dd->interrupt.is_Node.ln_Name = (STRPTR) LibName; dd->interrupt.is_Code = (void(*)(void)) &emu10kxinterrupt; dd->interrupt.is_Data = (APTR) dd; dd->playback_interrupt.is_Node.ln_Type = INTERRUPT_NODE_TYPE; dd->playback_interrupt.is_Node.ln_Pri = 0; dd->playback_interrupt.is_Node.ln_Name = (STRPTR) LibName; dd->playback_interrupt.is_Code = (void(*)(void)) &playbackinterrupt; dd->playback_interrupt.is_Data = (APTR) dd; dd->record_interrupt.is_Node.ln_Type = INTERRUPT_NODE_TYPE; dd->record_interrupt.is_Node.ln_Pri = 0; dd->record_interrupt.is_Node.ln_Name = (STRPTR) LibName; dd->record_interrupt.is_Code = (void(*)(void)) &recordinterrupt; dd->record_interrupt.is_Data = (APTR) dd; dd->card.pci_dev = dev; // if( pci_set_dma_mask(dd->card.pci_dev, EMU10K1_DMA_MASK) ) // { // printf( "Unable to set DMA mask for card." ); // goto error; // } #ifdef __AMIGAOS4__ command_word = dev->ReadConfigWord( PCI_COMMAND ); command_word |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; dev->WriteConfigWord( PCI_COMMAND, command_word ); #else command_word = pci_read_config_word( PCI_COMMAND, dd->card.pci_dev ); command_word |= PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER; pci_write_config_word( PCI_COMMAND, command_word, dd->card.pci_dev ); #endif dd->pci_master_enabled = TRUE; // FIXME: How about latency/pcibios_set_master()?? #ifdef __AMIGAOS4__ dd->card.iobase = dev->GetResourceRange(0)->BaseAddress; dd->card.length = ~( dev->GetResourceRange(0)->Size & PCI_BASE_ADDRESS_IO_MASK ); dd->card.irq = dev->MapInterrupt(); dd->card.chiprev = dev->ReadConfigByte( PCI_REVISION_ID); dd->card.model = dev->ReadConfigWord( PCI_SUBSYSTEM_ID); dd->card.is_audigy = ( dev->ReadConfigWord( PCI_DEVICE_ID) == PCI_DEVICE_ID_CREATIVE_AUDIGY ); dd->card.is_aps = ( dev->ReadConfigLong( PCI_SUBSYSTEM_VENDOR_ID) == EMU_APS_SUBID ); dev->OutLong(dd->card.iobase + IPR, 0xffffffff); dev->OutLong(dd->card.iobase + INTE, 0); AddIntServer(dev->MapInterrupt(), &dd->interrupt ); #else dd->card.iobase = dev->base_address[ 0 ]; dd->card.length = ~( dev->base_size[ 0 ] & PCI_BASE_ADDRESS_IO_MASK ); dd->card.irq = dev->irq; dd->card.chiprev = pci_read_config_byte( PCI_REVISION_ID, dd->card.pci_dev ); dd->card.model = pci_read_config_word( PCI_SUBSYSTEM_ID, dd->card.pci_dev ); dd->card.is_audigy = ( dev->device == PCI_DEVICE_ID_CREATIVE_AUDIGY ); dd->card.is_aps = ( pci_read_config_long( PCI_SUBSYSTEM_VENDOR_ID, dd->card.pci_dev ) == EMU_APS_SUBID ); pci_add_intserver( &dd->interrupt, dd->card.pci_dev ); #endif dd->interrupt_added = TRUE; /* Initialize chip */ if( emu10k1_init( &dd->card ) < 0 ) { Req( "Unable to initialize EMU10kx subsystem."); return NULL; } dd->emu10k1_initialized = TRUE; /* Initialize mixer */ emu10k1_writeac97( &dd->card, AC97_RESET, 0L); Delay( 1 ); if (emu10k1_readac97( &dd->card, AC97_RESET ) & 0x8000) { Req( "ac97 codec not present."); return NULL; } dd->input = 0; dd->output = 0; dd->monitor_volume = Linear2MixerGain( 0, &dd->monitor_volume_bits ); dd->input_gain = Linear2RecordGain( 0x10000, &dd->input_gain_bits ); dd->output_volume = Linear2MixerGain( 0x10000, &dd->output_volume_bits ); // No attenuation and natural tone for all outputs emu10k1_writeac97( &dd->card, AC97_MASTER_VOL_STEREO, 0x0000 ); emu10k1_writeac97( &dd->card, AC97_HEADPHONE_VOL, 0x0000 ); emu10k1_writeac97( &dd->card, AC97_MASTER_VOL_MONO, 0x0000 ); emu10k1_writeac97( &dd->card, AC97_MASTER_TONE, 0x0f0f ); emu10k1_writeac97( &dd->card, AC97_RECORD_GAIN, 0x0000 ); emu10k1_writeac97( &dd->card, AC97_RECORD_SELECT, InputBits[ 0 ] ); emu10k1_writeac97( &dd->card, AC97_PCMOUT_VOL, 0x0808 ); emu10k1_writeac97( &dd->card, AC97_PCBEEP_VOL, 0x0000 ); emu10k1_writeac97( &dd->card, AC97_LINEIN_VOL, 0x0808 ); emu10k1_writeac97( &dd->card, AC97_MIC_VOL, AC97_MUTE | 0x0008 ); emu10k1_writeac97( &dd->card, AC97_CD_VOL, 0x0808 ); emu10k1_writeac97( &dd->card, AC97_AUX_VOL, 0x0808 ); emu10k1_writeac97( &dd->card, AC97_PHONE_VOL, 0x0008 ); emu10k1_writeac97( &dd->card, AC97_VIDEO_VOL, 0x0808 ); if (emu10k1_readac97( &dd->card, AC97_EXTENDED_ID ) & 0x0080 ) { sblive_writeptr( &dd->card, AC97SLOT, 0, AC97SLOT_CNTR | AC97SLOT_LFE); emu10k1_writeac97( &dd->card, AC97_SURROUND_MASTER, 0x0 ); } return dd; }
/* Driver initialization routine */ static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id) { struct emu10k1_card *card; if ((card = kmalloc(sizeof(struct emu10k1_card), GFP_KERNEL)) == NULL) { printk(KERN_ERR "emu10k1: out of memory\n"); return -ENOMEM; } memset(card, 0, sizeof(struct emu10k1_card)); #if LINUX_VERSION_CODE > 0x020320 if (!pci_dma_supported(pci_dev, EMU10K1_DMA_MASK)) { printk(KERN_ERR "emu10k1: architecture does not support 32bit PCI busmaster DMA\n"); kfree(card); return -ENODEV; } if (pci_enable_device(pci_dev)) { printk(KERN_ERR "emu10k1: couldn't enable device\n"); kfree(card); return -ENODEV; } pci_set_master(pci_dev); card->iobase = pci_dev->resource[0].start; if (request_region(card->iobase, EMU10K1_EXTENT, card_names[pci_id->driver_data]) == NULL) { printk(KERN_ERR "emu10k1: IO space in use\n"); kfree(card); return -ENODEV; } pci_dev->driver_data = card; pci_dev->dma_mask = EMU10K1_DMA_MASK; #else pci_set_master(pci_dev); card->iobase = pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK; if (check_region(card->iobase, EMU10K1_EXTENT)) { printk(KERN_ERR "emu10k1: IO space in use\n"); kfree(card); return -ENODEV; } request_region(card->iobase, EMU10K1_EXTENT, card_names[pci_id->driver_data]); #endif card->irq = pci_dev->irq; card->pci_dev = pci_dev; /* Reserve IRQ Line */ if (request_irq(card->irq, emu10k1_interrupt, SA_SHIRQ, card_names[pci_id->driver_data], card)) { printk(KERN_ERR "emu10k1: IRQ in use\n"); goto err_irq; } pci_read_config_byte(pci_dev, PCI_REVISION_ID, &card->chiprev); printk(KERN_INFO "emu10k1: %s rev %d found at IO 0x%04lx, IRQ %d\n", card_names[pci_id->driver_data], card->chiprev, card->iobase, card->irq); spin_lock_init(&card->lock); card->mixeraddx = card->iobase + AC97DATA; init_MUTEX(&card->open_sem); card->open_mode = 0; init_waitqueue_head(&card->open_wait); /* Register devices */ if ((card->audio1_num = register_sound_dsp(&emu10k1_audio_fops, -1)) < 0) { printk(KERN_ERR "emu10k1: cannot register first audio device!\n"); goto err_dev0; } if ((card->audio2_num = register_sound_dsp(&emu10k1_audio_fops, -1)) < 0) { printk(KERN_ERR "emu10k1: cannot register second audio device!\n"); goto err_dev1; } if ((card->mixer_num = register_sound_mixer(&emu10k1_mixer_fops, -1)) < 0) { printk(KERN_ERR "emu10k1: cannot register mixer device!\n"); goto err_dev2; } if ((card->midi_num = register_sound_midi(&emu10k1_midi_fops, -1)) < 0) { printk(KERN_ERR "emu10k1: cannot register midi device!\n"); goto err_dev3; } if (emu10k1_init(card) != CTSTATUS_SUCCESS) { printk(KERN_ERR "emu10k1: cannot initialize device!\n"); goto err_emu10k1_init; } if (audio_init(card) != CTSTATUS_SUCCESS) { printk(KERN_ERR "emu10k1: cannot initialize audio!\n"); goto err_audio_init; } if (midi_init(card) != CTSTATUS_SUCCESS) { printk(KERN_ERR "emu10k1: cannot initialize midi!\n"); goto err_midi_init; } mixer_init(card); DPD(2, "Hardware initialized. TRAM allocated: %u bytes\n", (unsigned int) card->tmemsize); list_add(&card->list, &emu10k1_devs); return 0; err_midi_init: audio_exit(card); err_audio_init: emu10k1_exit(card); err_emu10k1_init: unregister_sound_midi(card->midi_num); err_dev3: unregister_sound_mixer(card->mixer_num); err_dev2: unregister_sound_dsp(card->audio2_num); err_dev1: unregister_sound_dsp(card->audio1_num); err_dev0: free_irq(card->irq, card); err_irq: release_region(card->iobase, EMU10K1_EXTENT); kfree(card); return -ENODEV; }