Open Sound System |
Do you have problems with sound/audio application development? Don't panic! Click here for help! |
This file is part of Open Sound System.
Copyright (C) 4Front Technologies 1996-2008.
This this source file is released under GPL v2 license (no other versions). See the COPYING file included in the main directory of this source distribution for the license terms and conditions.
#include "oss_sbxfi_cfg.h" #include <oss_pci.h> #include "sbxfi.h" #include "20k1reg.h" #include "hwaccess.h" #define PCI_VENDOR_CREATIVE 0x1102 #define CREATIVE_SBXFI_K1 0x0005 #define CREATIVE_SBXFI_K2 0x000b #define CREATIVE_SBXFI_E 0x0009 #define TIMER_INTERVAL 5 /* In milliseconds */ #define DEFAULT_PLAY_RATE 96000 /* Default rate of play devices */ #define DEFAULT_REC_RATE 96000 /* Default rate of rec devices */ #define HARDWARE_RATE 96000 /* Internal rate used by the hardware */ static void set_interval_timer(sbxfi_devc_t *devc, int msecs) { int tic = (HARDWARE_RATE*msecs)/1000; HwWrite20K1 (devc, TIMR, tic | TIMR_IE|TIMR_IP); } static int sbxfi_intr(oss_device_t *osdev) { unsigned int status; sbxfi_devc_t *devc = osdev->devc; status = HwRead20K1 (devc, GIP); if (status==0) /* Not for me */ return 0; devc->interrupt_count++; #if 0 // Not using loop interrupts. if (status & SRC_INT) /* SRC interrupt(s) pending */ { unsigned int srcipm, srcip; int i; srcipm = HwRead20K1 (devc, SRCIPM); /* SRC interrupt pending map register */ for (i=0;i<7;i++) if (srcipm & (1<<i)) { int j; srcip = HwRead20K1 (devc, SRCIP(i)); /* SRC interrupt pending register for block(i) */ for (j=0;j<32;j++) if (srcip & (1<<j)) { int chn=i*32+j; sbxfi_portc_t *portc; portc=devc->src_to_portc[chn]; if (portc==NULL) { cmn_err(CE_NOTE, "portc==NULL\n"); continue; } oss_audio_outputintr(portc->dev, 0); } HwWrite20K1 (devc, SRCIP(i), srcip); /* Acknowledge SRC interrupts for block(i) */ } } #endif if (status & IT_INT) {
Interval timer interrupt
sbxfi_portc_t *portc; int i; for (i=0;i<devc->nr_outdevs;i++) { portc=&devc->play_portc[i]; if (portc->running) oss_audio_outputintr(portc->dev, 0); } for (i=0;i<devc->nr_indevs;i++) { portc=&devc->rec_portc[i]; if (portc->running) oss_audio_inputintr(portc->dev, 0); } set_interval_timer(devc, TIMER_INTERVAL); /* Rearm interval timer */ } HwWrite20K1 (devc, GIP, status & FI_INT); /* Acknowledge interrupts */ return 1; } /*ARGSUSED*/ static int sbxfi_mixer_ioctl (int dev, int audiodev, unsigned int cmd, ioctl_arg arg) { return OSS_EINVAL; } static mixer_driver_t sbxfi_mixer_driver = { sbxfi_mixer_ioctl }; static int sbxfi_set_rate (int dev, int arg) { sbxfi_devc_t *devc = audio_engines[dev]->devc; sbxfi_portc_t *portc = audio_engines[dev]->portc; oss_native_word flags; MUTEX_ENTER_IRQDISABLE (devc->mutex, flags); #if 0 // TODO: Implement support for other rates if (arg == 0) { MUTEX_EXIT_IRQRESTORE (devc->mutex, flags); return portc->rate; } #else if (portc->direction == PCM_ENABLE_OUTPUT) arg=DEFAULT_PLAY_RATE; else arg=DEFAULT_REC_RATE; #endif MUTEX_EXIT_IRQRESTORE (devc->mutex, flags); return portc->rate = arg; } static short sbxfi_set_channels (int dev, short arg) { sbxfi_portc_t *portc = audio_engines[dev]->portc; if (arg == 0) return portc->channels; if (arg<2) arg=2; else if (arg > MAX_PLAY_CHANNELS) arg = MAX_PLAY_CHANNELS; arg &= ~1; /* Even number of channels */ return portc->channels = arg; } static unsigned int sbxfi_set_format (int dev, unsigned int arg) { sbxfi_portc_t *portc = audio_engines[dev]->portc; if (arg == 0) return portc->fmt; return portc->fmt = SUPPORTED_FORMAT; } static int sbxfi_ioctl (int dev, unsigned int cmd, ioctl_arg arg) { //sbxfi_portc_t *portc = audio_engines[dev]->portc; //sbxfi_devc_t *devc = audio_engines[dev]->devc; return OSS_EINVAL; } static void sbxfi_trigger (int dev, int state); static void sbxfi_reset (int dev) { sbxfi_trigger (dev, 0); } /*ARGSUSED*/ static int sbxfi_open_input (int dev, int mode, int open_flags) { sbxfi_portc_t *portc = audio_engines[dev]->portc; sbxfi_devc_t *devc = audio_engines[dev]->devc; adev_p adev = audio_engines[dev]; oss_native_word flags; if (mode & OPEN_WRITE) { cmn_err (CE_CONT, "Playback is not possible with %s\n", adev->devnode); return OSS_ENOTSUP; } MUTEX_ENTER_IRQDISABLE (devc->mutex, flags); if (portc->open_mode) { MUTEX_EXIT_IRQRESTORE (devc->mutex, flags); return OSS_EBUSY; } portc->open_mode = mode; MUTEX_EXIT_IRQRESTORE (devc->mutex, flags); return 0; } /*ARGSUSED*/ static int sbxfi_open_output (int dev, int mode, int open_flags) { sbxfi_portc_t *portc = audio_engines[dev]->portc; sbxfi_devc_t *devc = audio_engines[dev]->devc; oss_native_word flags; adev_p adev = audio_engines[dev]; if (mode == OPEN_READ) { cmn_err (CE_CONT, "Recording is not possible with %s\n", adev->devnode); return OSS_ENOTSUP; } MUTEX_ENTER_IRQDISABLE (devc->mutex, flags); if (portc->open_mode) { MUTEX_EXIT_IRQRESTORE (devc->mutex, flags); return OSS_EBUSY; } portc->open_mode = mode; MUTEX_EXIT_IRQRESTORE (devc->mutex, flags); return 0; } static void sbxfi_close (int dev, int mode) { sbxfi_portc_t *portc = audio_engines[dev]->portc; sbxfi_devc_t *devc = audio_engines[dev]->devc; oss_native_word flags; MUTEX_ENTER_IRQDISABLE (devc->mutex, flags); portc->open_mode = 0; MUTEX_EXIT_IRQRESTORE (devc->mutex, flags); } /*ARGSUSED*/ static void sbxfi_output_block (int dev, oss_native_word buf, int count, int fragsize, int intrflag) { } /*ARGSUSED*/ static void sbxfi_start_input (int dev, oss_native_word buf, int count, int fragsize, int intrflag) { } static void sbxfi_trigger (int dev, int state) { sbxfi_devc_t *devc = audio_engines[dev]->devc; sbxfi_portc_t *portc = audio_engines[dev]->portc; oss_native_word flags; MUTEX_ENTER_IRQDISABLE (devc->mutex, flags); if (portc->state_bits == state) /* No change */ { MUTEX_EXIT_IRQRESTORE (devc->mutex, flags); return; } portc->state_bits = state; if (portc->direction == PCM_ENABLE_OUTPUT) if (portc->open_mode & OPEN_WRITE) { if (state & PCM_ENABLE_OUTPUT) { SetupAndStartPlaySRC (devc, portc); portc->running=1; } else { StopPlaySRC (devc, portc); portc->running=0; } } if (portc->direction == PCM_ENABLE_INPUT) if (portc->open_mode & OPEN_READ) { if (state & PCM_ENABLE_INPUT) { SetupAndStartRecordSRC (devc, portc); portc->running=1; } else { StopRecordSRC (devc, portc); portc->running=0; } } MUTEX_EXIT_IRQRESTORE (devc->mutex, flags); } /*ARGSUSED*/ static int sbxfi_prepare_for_input (int dev, int bsize, int bcount) { sbxfi_devc_t *devc = audio_engines[dev]->devc; sbxfi_portc_t *portc = audio_engines[dev]->portc; dmap_p dmap = audio_engines[dev]->dmap_in; oss_native_word flags; int i; if (audio_engines[dev]->flags & ADEV_NOINPUT) return OSS_EACCES; MUTEX_ENTER_IRQDISABLE (devc->mutex, flags); // Fill record buffer to the page table entries. // This need to sync up with setting SRCs start addx for (i=0;i<(bsize*bcount)/4096;i++) devc->pdwPageTable[portc->pgtable_index+i] = dmap->dmabuf_phys + (i*4096); InitADC (devc, portc->dwDAChan[0], FALSE); // Program input mapper SetupRecordInputMapper (devc, portc); // Program I2S SetupRecordFormat (devc); SetupRecordMixer (devc, portc); MUTEX_EXIT_IRQRESTORE (devc->mutex, flags); return 0; } /*ARGSUSED*/ static int sbxfi_prepare_for_output (int dev, int bsize, int bcount) { sbxfi_devc_t *devc = audio_engines[dev]->devc; sbxfi_portc_t *portc = audio_engines[dev]->portc; dmap_p dmap = audio_engines[dev]->dmap_out; oss_native_word flags; int i; if (audio_engines[dev]->flags & ADEV_NOOUTPUT) return OSS_EACCES; MUTEX_ENTER_IRQDISABLE (devc->mutex, flags); // Fill play buffer to the page table entries. // This need to sync up with setting SRCs start addx for (i=0;i<(bsize*bcount)/4096;i++) devc->pdwPageTable[portc->pgtable_index+i] = dmap->dmabuf_phys + (i*4096); InitDAC (devc, portc); // Program I2S SetupPlayFormat (devc, portc); SetupPlayMixer (devc, portc); // Program input mapper SetupPlayInputMapper (devc, portc); MUTEX_EXIT_IRQRESTORE (devc->mutex, flags); return 0; } /*ARGSUSED*/ static int sbxfi_get_buffer_pointer (int dev, dmap_t * dmap, int direction) { sbxfi_devc_t *devc = audio_engines[dev]->devc; sbxfi_portc_t *portc = audio_engines[dev]->portc; int pos; pos = HwRead20K1 (devc, SRCCA(portc->SrcChan)) & 0x03ffffff; if (pos>=128) pos -= 128; /* The pointer is always 128 bytes ahead */ pos -= portc->pgtable_index*4096; return pos; } static audiodrv_t sbxfi_output_driver = { sbxfi_open_output, sbxfi_close, sbxfi_output_block, sbxfi_start_input, sbxfi_ioctl, sbxfi_prepare_for_input, sbxfi_prepare_for_output, sbxfi_reset, NULL, NULL, NULL, NULL, sbxfi_trigger, sbxfi_set_rate, sbxfi_set_format, sbxfi_set_channels, NULL, NULL, NULL, /* check input */ NULL, /* sbxfi_check_output */ NULL, /* sbxfi_alloc_buffer */ NULL, /* sbxfi_free_buffer */ NULL, NULL, sbxfi_get_buffer_pointer }; static audiodrv_t sbxfi_input_driver = { sbxfi_open_input, sbxfi_close, sbxfi_output_block, sbxfi_start_input, sbxfi_ioctl, sbxfi_prepare_for_input, sbxfi_prepare_for_output, sbxfi_reset, NULL, NULL, NULL, NULL, sbxfi_trigger, sbxfi_set_rate, sbxfi_set_format, sbxfi_set_channels, NULL, NULL, NULL, NULL, NULL, /* sbxfi_alloc_buffer */ NULL, /* sbxfi_free_buffer */ NULL, NULL, sbxfi_get_buffer_pointer }; static int init_play_device (sbxfi_devc_t * devc, char *name, int dev_flags) { int opts, dev, formats; char tmp[80]; sbxfi_portc_t *portc = NULL; adev_p adev; sprintf (tmp, "%s %s", devc->name, name); if (devc->nr_outdevs > MAX_OUTPUTDEVS) { cmn_err (CE_CONT, "Too many audio devices\n"); return -1; } opts = ADEV_AUTOMODE | ADEV_NOINPUT; formats = SUPPORTED_FORMAT; if ((dev = oss_install_audiodev (OSS_AUDIO_DRIVER_VERSION, devc->osdev, devc->osdev, tmp, &sbxfi_output_driver, sizeof (audiodrv_t), opts, formats, devc, -1)) < 0) { return -1; } if (devc->first_dev == -1) { devc->first_dev = dev; } adev = audio_engines[dev]; portc = &devc->play_portc[devc->nr_outdevs]; adev->portc = portc; adev->devc = devc; adev->mixer_dev = devc->mixer_dev; adev->rate_source = devc->first_dev; adev->min_rate = 48000; adev->max_rate = 92600; adev->min_block=4096; adev->dmabuf_maxaddr = MEMLIMIT_ISA; portc->dev = dev; portc->open_mode = 0; portc->fmt = SUPPORTED_FORMAT; portc->dev_flags = dev_flags; portc->state_bits = 0; portc->direction = PCM_ENABLE_OUTPUT; portc->rate = DEFAULT_PLAY_RATE; // use the following SRC channels for Play portc->SrcChan = devc->next_src; devc->next_src += MAX_PLAY_CHANNELS; devc->src_to_portc[portc->SrcChan]=portc; portc->dwDAChan[0] = I2SA_L; portc->dwDAChan[1] = I2SA_R; #if MAX_PLAY_CHANNELS>2 portc->dwDAChan[2] = I2SB_L; portc->dwDAChan[3] = I2SB_R; portc->dwDAChan[4] = I2SC_L; portc->dwDAChan[5] = I2SC_R; #endif portc->vol_left=portc->vol_right=MIXER_VOLSTEPS; adev->min_channels = 2; adev->max_channels = MAX_PLAY_CHANNELS; portc->pgtable_index = devc->next_pg; devc->next_pg += 128/4; // Up to 128k for buffer devc->nr_outdevs++; return dev; } static int init_rec_device (sbxfi_devc_t * devc, char *name, int dev_flags) { int opts, dev, formats; char tmp[80]; sbxfi_portc_t *portc = NULL; adev_p adev; sprintf (tmp, "%s %s", devc->name, name); if (devc->nr_indevs > MAX_INPUTDEVS) { cmn_err (CE_CONT, "Too many audio devices\n"); return -1; } opts = ADEV_AUTOMODE | ADEV_NOOUTPUT; formats = SUPPORTED_FORMAT; if ((dev = oss_install_audiodev (OSS_AUDIO_DRIVER_VERSION, devc->osdev, devc->osdev, tmp, &sbxfi_input_driver, sizeof (audiodrv_t), opts, formats, devc, -1)) < 0) { return -1; } if (devc->first_dev == -1) { devc->first_dev = dev; } adev = audio_engines[dev]; portc = &devc->rec_portc[devc->nr_indevs]; adev->portc = portc; adev->devc = devc; adev->mixer_dev = devc->mixer_dev; adev->rate_source = devc->first_dev; adev->min_rate = 48000; adev->max_rate = 96000; adev->min_block=4096; adev->dmabuf_maxaddr = MEMLIMIT_ISA; portc->dev = dev; portc->open_mode = 0; portc->fmt = SUPPORTED_FORMAT; portc->dev_flags = dev_flags; portc->state_bits = 0; portc->direction = PCM_ENABLE_INPUT; portc->rate = DEFAULT_REC_RATE; // use the following SRC channels for record portc->SrcChan = devc->next_src; devc->next_src += 2; devc->src_to_portc[portc->SrcChan]=portc; portc->dwDAChan[0] = ADC_SRC_LINEIN; portc->vol_left=portc->vol_right=MIXER_VOLSTEPS; adev->min_channels = 2; adev->max_channels = 2; portc->pgtable_index = devc->next_pg; devc->next_pg += 128/4; // Up to 128k for buffer devc->nr_indevs++; return dev; } static int sbxfi_set_playvol (int dev, int ctrl, unsigned int cmd, int value) { sbxfi_devc_t *devc = mixer_devs[dev]->devc; sbxfi_portc_t *portc; int left, right; if (ctrl<0 || ctrl >= devc->nr_outdevs) return OSS_ENXIO; portc = &devc->play_portc[ctrl]; if (cmd == SNDCTL_MIX_READ) { return portc->vol_left | (portc->vol_right << 16); } if (cmd == SNDCTL_MIX_WRITE) { left = value & 0xffff; right = (value>>16) & 0xffff; if (left > MIXER_VOLSTEPS) left=MIXER_VOLSTEPS; if (right > MIXER_VOLSTEPS) right=MIXER_VOLSTEPS; portc->vol_left=left; portc->vol_right=right; if (portc->running) SetupPlayMixer(devc, portc); return portc->vol_left | (portc->vol_right << 16); } return OSS_EINVAL; } static int sbxfi_set_recvol (int dev, int ctrl, unsigned int cmd, int value) { sbxfi_devc_t *devc = mixer_devs[dev]->devc; sbxfi_portc_t *portc; int left, right; if (ctrl<0 || ctrl >= devc->nr_indevs) return OSS_ENXIO; portc = &devc->rec_portc[ctrl]; if (cmd == SNDCTL_MIX_READ) { return portc->vol_left | (portc->vol_right << 16); } if (cmd == SNDCTL_MIX_WRITE) { left = value & 0xffff; right = (value>>16) & 0xffff; if (left > MIXER_VOLSTEPS) left=MIXER_VOLSTEPS; if (right > MIXER_VOLSTEPS) right=MIXER_VOLSTEPS; portc->vol_left=left; portc->vol_right=right; if (portc->running) SetupRecordMixer(devc, portc); return portc->vol_left | (portc->vol_right << 16); } return OSS_EINVAL; } static int sbxfi_set_recsrc (int dev, int ctrl, unsigned int cmd, int value) { sbxfi_devc_t *devc = mixer_devs[dev]->devc; sbxfi_portc_t *portc; if (ctrl<0 || ctrl >= devc->nr_indevs) return OSS_ENXIO; portc = &devc->rec_portc[ctrl]; if (cmd == SNDCTL_MIX_READ) { return portc->dwDAChan[0]; } if (cmd == SNDCTL_MIX_WRITE) { if (value<0 || value>ADC_SRC_NONE) return portc->dwDAChan[0]; return portc->dwDAChan[0]=value; } return OSS_EINVAL; } static int sbxfi_mix_init (int dev) { int root=0, ctl; if ((ctl = mixer_ext_create_control (dev, root, 0, sbxfi_set_playvol, MIXT_STEREOSLIDER16, "play", MIXER_VOLSTEPS, MIXF_PCMVOL | MIXF_READABLE | MIXF_WRITEABLE | MIXF_CENTIBEL)) < 0) return ctl; if ((ctl = mixer_ext_create_control (dev, root, 0, sbxfi_set_recvol, MIXT_STEREOSLIDER16, "rec", MIXER_VOLSTEPS, MIXF_RECVOL | MIXF_READABLE | MIXF_WRITEABLE | MIXF_CENTIBEL)) < 0) return ctl; if ((ctl = mixer_ext_create_control (dev, root, 0, sbxfi_set_recsrc, MIXT_ENUM, "recsrc", 5, MIXF_READABLE | MIXF_WRITEABLE | MIXF_CENTIBEL)) < 0) return ctl; mixer_ext_set_strings (dev, ctl, "mic line video aux none", 0); return 0; } int oss_sbxfi_attach (oss_device_t * osdev) { unsigned short pci_command, vendor, device, revision; unsigned short subvendor, subdevice; int pdev, rdev; extern int sbxfi_type; sbxfi_devc_t *devc; sbxfi_portc_t *portc; if ((devc = PMALLOC (osdev, sizeof (*devc))) == NULL) { cmn_err (CE_WARN, "Out of memory\n"); return 0; } memset (devc, 0, sizeof (*devc)); portc = &devc->play_portc[0]; devc->osdev = osdev; osdev->devc = devc; devc->name = "Sound Blaster X-Fi"; pci_read_config_word (osdev, PCI_VENDOR_ID, &vendor); pci_read_config_word (osdev, PCI_DEVICE_ID, &device); DDB (cmn_err (CE_CONT, "oss_sbxfi_attach(Vendor %x, device %x)\n", vendor, device)); if (vendor != PCI_VENDOR_CREATIVE || (device != CREATIVE_SBXFI_K1 && device != CREATIVE_SBXFI_K2 && device != CREATIVE_SBXFI_E)) { cmn_err (CE_WARN, "Hardware not recognized (vendor=%x, dev=%x)\n", vendor, device); return 0; } MUTEX_INIT (osdev, devc->mutex, MH_DRV); MUTEX_INIT (osdev, devc->low_mutex, MH_DRV + 1); pci_read_config_word (osdev, PCI_SUBSYSTEM_VENDOR_ID, &subvendor); pci_read_config_word (osdev, PCI_SUBSYSTEM_ID, &subdevice); pci_read_config_word (osdev, PCI_REVISION_ID, &revision); devc->wVendorID = vendor; devc->wDeviceID = device; devc->wSubsystemVendorID = subvendor; devc->wSubsystemID = subdevice; devc->wChipRevision = revision; switch (sbxfi_type) { case 1: devc->name = "Sound Blaster X-Fi (SB046x/067x/076x)"; devc->hw_family = HW_ORIG; break; case 2: devc->name = "Sound Blaster X-Fi (SB073x)"; devc->hw_family = HW_073x; break; case 3: devc->name = "Sound Blaster X-Fi (SB055x)"; devc->hw_family = HW_055x; break; case 4: devc->name = "Sound Blaster X-Fi (UAA)"; devc->hw_family = HW_UAA; break; case 5: devc->name = "Sound Blaster X-Fi (SB076x)"; devc->hw_family = HW_0760; break; case 6: devc->name = "Sound Blaster X-Fi (SB0880-1)"; devc->hw_family = HW_08801; break; case 7: devc->name = "Sound Blaster X-Fi (SB0880-2)"; devc->hw_family = HW_08802; break; case 8: devc->name = "Sound Blaster X-Fi (SB0880-3)"; devc->hw_family = HW_08803; break; case 0: default: devc->hw_family = 0; break; } if (!devc->hw_family && device == CREATIVE_SBXFI_K1) // EMU20K1 models switch (subdevice) { case 0x0021: /* SB0460 */ case 0x0023: case 0x0024: case 0x0025: case 0x0026: case 0x0027: case 0x0028: case 0x002a: case 0x002b: case 0x002c: case 0x002d: case 0x002e: case 0x0032: case 0x0033: case 0x0034: /* This is actually Auzentech Prelude (subvendor 415a) */
Original X-Fi hardware revision (SB046x/067x/076x)
devc->name = "Sound Blaster X-Fi (SB046x/067x/076x)"; devc->hw_family = HW_ORIG; break; case 0x0029: case 0x0031: devc->name = "Sound Blaster X-Fi (SB073x)"; devc->hw_family = HW_073x; break; case 0x0022: case 0x002f: devc->name = "Sound Blaster X-Fi (SB055x)"; devc->hw_family = HW_055x; break; default: if (subdevice >= 0x6000 && subdevice <= 0x6fff) /* "Vista compatible" HW */ { devc->name = "Sound Blaster X-Fi (UAA)"; devc->hw_family = HW_UAA; } } if (!devc->hw_family && device == CREATIVE_SBXFI_K2) // EMU 20K2 models switch (subdevice) { case PCI_SUBDEVICE_ID_CREATIVE_SB0760: devc->name = "Sound Blaster X-Fi (SB076x)"; devc->hw_family = HW_0760; break; case PCI_SUBDEVICE_ID_CREATIVE_SB08801: devc->name = "Sound Blaster X-Fi (SB0880-1)"; devc->hw_family = HW_08801; break; case PCI_SUBDEVICE_ID_CREATIVE_SB08802: devc->name = "Sound Blaster X-Fi (SB0880-2)"; devc->hw_family = HW_08802; break; case PCI_SUBDEVICE_ID_CREATIVE_SB08803: devc->name = "Sound Blaster X-Fi (SB0880-3)"; devc->hw_family = HW_08803; break; default: devc->name = "Sound Blaster X-Fi (20K2)"; devc->hw_family = HW_UAA; // Just a wild guess } if (!devc->hw_family && device == CREATIVE_SBXFI_E) // PCI-e models { devc->name = "Sound Blaster X-Fi (PCI-e)"; devc->hw_family = HW_UAA; // Just a wild guess } #if 1 // Temporary hacking until proper 20K2 support is in place if (devc->hw_family > HW_UAA) devc->hw_family = HW_UAA; #endif oss_register_device (osdev, devc->name); pci_read_config_word (osdev, PCI_COMMAND, &pci_command); pci_command |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; pci_write_config_word (osdev, PCI_COMMAND, pci_command); if ((osdev->hw_info = PMALLOC (osdev, 200)) != NULL) { sprintf (osdev->hw_info, "PCI device %04x:%04x, subdevice %04x:%04x\n", vendor, device, subvendor, subdevice); } devc->interrupt_count=0; if (oss_register_interrupts (devc->osdev, 0, sbxfi_intr, NULL) < 0) { cmn_err (CE_WARN, "Unable to install interrupt handler\n"); return 0; } // Detect and Configure X-Fi PCI config space. // Obtain the resource configuration from PCI config space. if (!DetectAndConfigureHardware (devc)) { cmn_err (CE_WARN, "Cannot configure X-Fi hardware...\n"); return 0; } if (IsVistaCompatibleHardware (devc)) { // Switch to audio core to X-Fi core. SwitchToXFiCore (devc); } // Initialize hardware. This include setup the PLL etc. if (InitHardware (devc) != CTSTATUS_SUCCESS) { cmn_err (CE_WARN, "Init Hardware failed...\n"); return 0; } devc->dwPageTableSize = 1024; /* For up to 4M of memory */ devc->pdwPageTable = CONTIG_MALLOC (devc->osdev, devc->dwPageTableSize, MEMLIMIT_ISA, &devc->dwPTBPhysAddx, devc->pgtable_dma_handle); HwWrite20K1 (devc, PTPALX, devc->dwPTBPhysAddx); HwWrite20K1 (devc, PTPAHX, 0); HwWrite20K1 (devc, TRNCTL, 0x13); HwWrite20K1 (devc, TRNIS, 0x200c01); HwWrite20K1 (devc, GIE, FI_INT); /* Enable "forced" interrupts */ HwWrite20K1 (devc, GIP, FI_INT); /* Trigger forced interrupt */ oss_udelay(1000); if (devc->interrupt_count==0) cmn_err(CE_WARN, "Interrupts don't seem to be working.\n"); set_interval_timer(devc, TIMER_INTERVAL);
Disable FI and enable selected global interrupts (SRC, Interval Timer).
HwWrite20K1 (devc, GIE, SRC_INT | IT_INT); if ((devc->mixer_dev = oss_install_mixer (OSS_MIXER_DRIVER_VERSION, devc->osdev, devc->osdev, devc->name, &sbxfi_mixer_driver, sizeof (mixer_driver_t), devc)) >= 0) { mixer_devs[devc->mixer_dev]->hw_devc = devc; mixer_devs[devc->mixer_dev]->priority = 1; /* Possible default mixer candidate */ mixer_ext_set_init_fn (devc->mixer_dev, sbxfi_mix_init, 10); } devc->first_dev=-1; /* Not assigned */ pdev = init_play_device (devc, "output", 0); rdev = init_rec_device (devc, "input", 0); #ifdef CONFIG_OSS_VMIX if (pdev != -1) { vmix_attach_audiodev (devc->osdev, pdev, rdev, 0); } #endif #if 0 // Initialize ADC InitADC (devc, ADC_SRC_LINEIN, FALSE); #endif return 1; } int oss_sbxfi_detach (oss_device_t * osdev) { sbxfi_devc_t *devc = (sbxfi_devc_t *) osdev->devc; if (oss_disable_device (osdev) < 0) return 0; HwWrite20K1 (devc, GIE, 0); /* Disable global interrupts */ oss_unregister_interrupts (devc->osdev); HwWrite20K1 (devc, PTPALX, 0); if (devc->pdwPageTable != NULL) { CONTIG_FREE (devc->osdev, devc->pdwPageTable, devc->dwPageTableSize, devc->pgtable_dma_handle); devc->pdwPageTable = NULL; } oss_unregister_device (osdev); MUTEX_CLEANUP (devc->mutex); MUTEX_CLEANUP (devc->low_mutex); return 1; }