📄 waveartist.c
字号:
} else if (recmask & SOUND_MASK_MIC) { recmask = SOUND_MASK_MIC; recdev = ADC_MUX_MIC; } *dev_l = *dev_r = recdev; return recmask;}static intwaveartist_decode_mixer(wavnc_info *devc, int dev, unsigned char lev_l, unsigned char lev_r){ switch (dev) { case SOUND_MIXER_VOLUME: case SOUND_MIXER_SYNTH: case SOUND_MIXER_PCM: case SOUND_MIXER_LINE: case SOUND_MIXER_MIC: case SOUND_MIXER_IGAIN: case SOUND_MIXER_LINE1: case SOUND_MIXER_LINE2: devc->levels[dev] = lev_l | lev_r << 8; break; case SOUND_MIXER_IMIX: break; default: dev = -EINVAL; break; } return dev;}static int waveartist_get_mixer(wavnc_info *devc, int dev){ return devc->levels[dev];}static const struct waveartist_mixer_info waveartist_mixer = { supported_devs: SUPPORTED_MIXER_DEVICES | SOUND_MASK_IGAIN, recording_devs: SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_LINE1 | SOUND_MASK_LINE2 | SOUND_MASK_IMIX, stereo_devs: (SUPPORTED_MIXER_DEVICES | SOUND_MASK_IGAIN) & ~ (SOUND_MASK_SPEAKER | SOUND_MASK_IMIX), select_input: waveartist_select_input, decode_mixer: waveartist_decode_mixer, get_mixer: waveartist_get_mixer,};static voidwaveartist_set_recmask(wavnc_info *devc, unsigned int recmask){ unsigned char dev_l, dev_r; recmask &= devc->mix->recording_devs; /* * If more than one recording device selected, * disable the device that is currently in use. */ if (hweight32(recmask) > 1) recmask &= ~devc->recmask; /* * Translate the recording device mask into * the ADC multiplexer settings. */ devc->recmask = devc->mix->select_input(devc, recmask, &dev_l, &dev_r); waveartist_set_adc_mux(devc, dev_l, dev_r);}static intwaveartist_set_mixer(wavnc_info *devc, int dev, unsigned int level){ unsigned int lev_left = level & 0x00ff; unsigned int lev_right = (level & 0xff00) >> 8; if (lev_left > 100) lev_left = 100; if (lev_right > 100) lev_right = 100; /* * Mono devices have their right volume forced to their * left volume. (from ALSA driver OSS emulation). */ if (!(devc->mix->stereo_devs & (1 << dev))) lev_right = lev_left; dev = devc->mix->decode_mixer(devc, dev, lev_left, lev_right); if (dev >= 0) waveartist_mixer_update(devc, dev); return dev < 0 ? dev : 0;}static intwaveartist_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg){ wavnc_info *devc = (wavnc_info *)audio_devs[dev]->devc; int ret = 0, val, nr; /* * All SOUND_MIXER_* ioctls use type 'M' */ if (((cmd >> 8) & 255) != 'M') return -ENOIOCTLCMD;#ifdef CONFIG_ARCH_NETWINDER if (machine_is_netwinder()) { ret = vnc_private_ioctl(dev, cmd, arg); if (ret != -ENOIOCTLCMD) return ret; else ret = 0; }#endif nr = cmd & 0xff; if (_SIOC_DIR(cmd) & _SIOC_WRITE) { if (get_user(val, (int *)arg)) return -EFAULT; switch (nr) { case SOUND_MIXER_RECSRC: waveartist_set_recmask(devc, val); break; default: ret = -EINVAL; if (nr < SOUND_MIXER_NRDEVICES && devc->mix->supported_devs & (1 << nr)) ret = waveartist_set_mixer(devc, nr, val); } } if (ret == 0 && _SIOC_DIR(cmd) & _SIOC_READ) { ret = -EINVAL; switch (nr) { case SOUND_MIXER_RECSRC: ret = devc->recmask; break; case SOUND_MIXER_DEVMASK: ret = devc->mix->supported_devs; break; case SOUND_MIXER_STEREODEVS: ret = devc->mix->stereo_devs; break; case SOUND_MIXER_RECMASK: ret = devc->mix->recording_devs; break; case SOUND_MIXER_CAPS: ret = SOUND_CAP_EXCL_INPUT; break; default: if (nr < SOUND_MIXER_NRDEVICES) ret = devc->mix->get_mixer(devc, nr); break; } if (ret >= 0) ret = put_user(ret, (int *)arg) ? -EFAULT : 0; } return ret;}static struct mixer_operations waveartist_mixer_operations ={ owner: THIS_MODULE, id: "WaveArtist", name: "WaveArtist", ioctl: waveartist_mixer_ioctl};static voidwaveartist_mixer_reset(wavnc_info *devc){ int i; if (debug_flg & DEBUG_MIXER) printk("%s: mixer_reset\n", devc->hw.name); /* * reset mixer cmd */ waveartist_cmd1(devc, WACMD_RST_MIXER); /* * set input for ADC to come from 'quiet' * turn on default modes */ waveartist_cmd3(devc, WACMD_SET_MIXER, 0x9800, 0xa836); /* * set mixer input select to none, RX filter gains 0 dB */ waveartist_cmd3(devc, WACMD_SET_MIXER, 0x4c00, 0x8c00); /* * set bit 0 reg 2 to 1 - unmute MonoOut */ waveartist_cmd3(devc, WACMD_SET_MIXER, 0x2801, 0x6800); /* set default input device = internal mic * current recording device = none */ waveartist_set_recmask(devc, 0); for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) waveartist_mixer_update(devc, i);}static int __init waveartist_init(wavnc_info *devc){ wavnc_port_info *portc; char rev[3], dev_name[64]; int my_dev; if (waveartist_reset(devc)) return -ENODEV; sprintf(dev_name, "%s (%s", devc->hw.name, devc->chip_name); if (waveartist_getrev(devc, rev)) { strcat(dev_name, " rev. "); strcat(dev_name, rev); } strcat(dev_name, ")"); conf_printf2(dev_name, devc->hw.io_base, devc->hw.irq, devc->hw.dma, devc->hw.dma2); portc = (wavnc_port_info *)kmalloc(sizeof(wavnc_port_info), GFP_KERNEL); if (portc == NULL) goto nomem; memset(portc, 0, sizeof(wavnc_port_info)); my_dev = sound_install_audiodrv(AUDIO_DRIVER_VERSION, dev_name, &waveartist_audio_driver, sizeof(struct audio_driver), devc->audio_flags, AFMT_U8 | AFMT_S16_LE | AFMT_S8, devc, devc->hw.dma, devc->hw.dma2); if (my_dev < 0) goto free; audio_devs[my_dev]->portc = portc; waveartist_mixer_reset(devc); /* * clear any pending interrupt */ waveartist_iack(devc); if (request_irq(devc->hw.irq, waveartist_intr, 0, devc->hw.name, devc) < 0) { printk(KERN_ERR "%s: IRQ %d in use\n", devc->hw.name, devc->hw.irq); goto uninstall; } if (sound_alloc_dma(devc->hw.dma, devc->hw.name)) { printk(KERN_ERR "%s: Can't allocate DMA%d\n", devc->hw.name, devc->hw.dma); goto uninstall_irq; } if (devc->hw.dma != devc->hw.dma2 && devc->hw.dma2 != NO_DMA) if (sound_alloc_dma(devc->hw.dma2, devc->hw.name)) { printk(KERN_ERR "%s: can't allocate DMA%d\n", devc->hw.name, devc->hw.dma2); goto uninstall_dma; } waveartist_set_ctlr(&devc->hw, 0, DMA1_IE | DMA0_IE); audio_devs[my_dev]->mixer_dev = sound_install_mixer(MIXER_DRIVER_VERSION, dev_name, &waveartist_mixer_operations, sizeof(struct mixer_operations), devc); return my_dev;uninstall_dma: sound_free_dma(devc->hw.dma);uninstall_irq: free_irq(devc->hw.irq, devc);uninstall: sound_unload_audiodev(my_dev);free: kfree(portc);nomem: return -1;}static int __init probe_waveartist(struct address_info *hw_config){ wavnc_info *devc = &adev_info[nr_waveartist_devs]; if (nr_waveartist_devs >= MAX_AUDIO_DEV) { printk(KERN_WARNING "waveartist: too many audio devices\n"); return 0; } if (check_region(hw_config->io_base, 15)) { printk(KERN_WARNING "WaveArtist: I/O port conflict\n"); return 0; } if (hw_config->irq > 15 || hw_config->irq < 0) { printk(KERN_WARNING "WaveArtist: Bad IRQ %d\n", hw_config->irq); return 0; } if (hw_config->dma != 3) { printk(KERN_WARNING "WaveArtist: Bad DMA %d\n", hw_config->dma); return 0; } hw_config->name = "WaveArtist"; devc->hw = *hw_config; devc->open_mode = 0; devc->chip_name = "RWA-010"; return 1;}static void __initattach_waveartist(struct address_info *hw, const struct waveartist_mixer_info *mix){ wavnc_info *devc = &adev_info[nr_waveartist_devs]; /* * NOTE! If irq < 0, there is another driver which has allocated the * IRQ so that this driver doesn't need to allocate/deallocate it. * The actually used IRQ is ABS(irq). */ devc->hw = *hw; devc->hw.irq = (hw->irq > 0) ? hw->irq : 0; devc->open_mode = 0; devc->playback_dev = 0; devc->record_dev = 0; devc->audio_flags = DMA_AUTOMODE; devc->levels = levels; if (hw->dma != hw->dma2 && hw->dma2 != NO_DMA) devc->audio_flags |= DMA_DUPLEX; request_region(hw->io_base, 15, devc->hw.name); devc->mix = mix; devc->dev_no = waveartist_init(devc); if (devc->dev_no < 0) release_region(hw->io_base, 15); else {#ifdef CONFIG_ARCH_NETWINDER if (machine_is_netwinder()) { init_timer(&vnc_timer); vnc_timer.function = vnc_slider_tick; vnc_timer.expires = jiffies; vnc_timer.data = nr_waveartist_devs; add_timer(&vnc_timer); vnc_configure_mixer(devc, 0); devc->no_autoselect = 1; }#endif nr_waveartist_devs += 1; }}static void __exit unload_waveartist(struct address_info *hw){ wavnc_info *devc = NULL; int i; for (i = 0; i < nr_waveartist_devs; i++) if (hw->io_base == adev_info[i].hw.io_base) { devc = adev_info + i; break; } if (devc != NULL) { int mixer;#ifdef CONFIG_ARCH_NETWINDER if (machine_is_netwinder()) del_timer(&vnc_timer);#endif release_region(devc->hw.io_base, 15); waveartist_set_ctlr(&devc->hw, DMA1_IE|DMA0_IE, 0); if (devc->hw.irq >= 0) free_irq(devc->hw.irq, devc); sound_free_dma(devc->hw.dma); if (devc->hw.dma != devc->hw.dma2 && devc->hw.dma2 != NO_DMA) sound_free_dma(devc->hw.dma2); mixer = audio_devs[devc->dev_no]->mixer_dev; if (mixer >= 0) sound_unload_mixerdev(mixer); if (devc->dev_no >= 0) sound_unload_audiodev(devc->dev_no); nr_waveartist_devs -= 1; for (; i < nr_waveartist_devs; i++) adev_info[i] = adev_info[i + 1]; } else printk(KERN_WARNING "waveartist: can't find device " "to unload\n");}#ifdef CONFIG_ARCH_NETWINDER/* * Rebel.com Netwinder specifics... */#include <asm/hardware/dec21285.h> #define VNC_TIMER_PERIOD (HZ/4) //check slider 4 times/sec#define MIXER_PRIVATE3_RESET 0x53570000#define MIXER_PRIVATE3_READ 0x53570001#define MIXER_PRIVATE3_WRITE 0x53570002#define VNC_MUTE_INTERNAL_SPKR 0x01 //the sw mute on/off control bit#define VNC_MUTE_LINE_OUT 0x10#define VNC_PHONE_DETECT 0x20#define VNC_HANDSET_DETECT 0x40#define VNC_DISABLE_AUTOSWITCH 0x80extern spinlock_t gpio_lock;static inline voidvnc_mute_spkr(wavnc_info *devc){ unsigned long flags; spin_lock_irqsave(&gpio_lock, flags); cpld_modify(CPLD_UNMUTE, devc->spkr_mute_state ? 0 : CPLD_UNMUTE); spin_unlock_irqrestore(&gpio_lock, flags);}static voidvnc_mute_lout(wavnc_info *devc){ unsigned int left, right; left = waveartist_cmd1_r(devc, WACMD_GET_LEVEL); right = waveartist_cmd1_r(devc, WACMD_GET_LEVEL | 0x400); if (devc->line_mute_state) { left &= ~1; right &= ~1; } else { left |= 1; right |= 1; } waveartist_cmd3(devc, WACMD_SET_MIXER, left, right); }static intvnc_volume_slider(wavnc_info *devc){ static signed int old_slider_volume; unsigned long flags; signed int volume = 255; *CSR_TIMER1_LOAD = 0x00ffffff; save_flags(flags); cli();
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -