X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=sound%2Foss%2Fpss.c;h=ece428b2ba9fef34319670b25039bf5783c5bfe6;hb=refs%2Fheads%2Fvserver;hp=9a1c915809c1806fef3e75b33143b23757a85a1b;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/sound/oss/pss.c b/sound/oss/pss.c index 9a1c91580..ece428b2b 100644 --- a/sound/oss/pss.c +++ b/sound/oss/pss.c @@ -1,5 +1,5 @@ /* - * sound/pss.c + * sound/oss/pss.c * * The low level driver for the Personal Sound System (ECHO ESC614). * @@ -57,7 +57,6 @@ */ -#include #include #include #include @@ -118,9 +117,9 @@ /* If compiled into kernel, it enable or disable pss mixer */ #ifdef CONFIG_PSS_MIXER -static unsigned char pss_mixer = 1; +static int pss_mixer = 1; #else -static unsigned char pss_mixer; +static int pss_mixer; #endif @@ -143,12 +142,13 @@ typedef struct pss_confdata { static pss_confdata pss_data; static pss_confdata *devc = &pss_data; -static spinlock_t lock=SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(lock); static int pss_initialized; static int nonstandard_microcode; static int pss_cdrom_port = -1; /* Parameter for the PSS cdrom port */ static int pss_enable_joystick; /* Parameter for enabling the joystick */ +static coproc_operations pss_coproc_operations; static void pss_write(pss_confdata *devc, int data) { @@ -174,7 +174,7 @@ static void pss_write(pss_confdata *devc, int data) printk(KERN_WARNING "PSS: DSP Command (%04x) Timeout.\n", data); } -int __init probe_pss(struct address_info *hw_config) +static int __init probe_pss(struct address_info *hw_config) { unsigned short id; int irq, dma; @@ -188,13 +188,19 @@ int __init probe_pss(struct address_info *hw_config) if (devc->base != 0x230 && devc->base != 0x250) /* Some cards use these */ return 0; - if (check_region(devc->base, 0x19 /*16*/)) { + if (!request_region(devc->base, 0x10, "PSS mixer, SB emulation")) { printk(KERN_ERR "PSS: I/O port conflict\n"); return 0; } id = inw(REG(PSS_ID)); if ((id >> 8) != 'E') { printk(KERN_ERR "No PSS signature detected at 0x%x (0x%x)\n", devc->base, id); + release_region(devc->base, 0x10); + return 0; + } + if (!request_region(devc->base + 0x10, 0x9, "PSS config")) { + printk(KERN_ERR "PSS: I/O port conflict\n"); + release_region(devc->base, 0x10); return 0; } return 1; @@ -453,20 +459,36 @@ static void pss_mixer_reset(pss_confdata *devc) } } -static void arg_to_volume_mono(unsigned int volume, int *aleft) +static int set_volume_mono(unsigned __user *p, int *aleft) { int left; + unsigned volume; + if (get_user(volume, p)) + return -EFAULT; - left = volume & 0x00ff; + left = volume & 0xff; if (left > 100) left = 100; *aleft = left; + return 0; } -static void arg_to_volume_stereo(unsigned int volume, int *aleft, int *aright) +static int set_volume_stereo(unsigned __user *p, int *aleft, int *aright) { - arg_to_volume_mono(volume, aleft); - arg_to_volume_mono(volume >> 8, aright); + int left, right; + unsigned volume; + if (get_user(volume, p)) + return -EFAULT; + + left = volume & 0xff; + if (left > 100) + left = 100; + right = (volume >> 8) & 0xff; + if (right > 100) + right = 100; + *aleft = left; + *aright = right; + return 0; } static int ret_vol_mono(int left) @@ -479,7 +501,7 @@ static int ret_vol_stereo(int left, int right) return ((right << 8) | left); } -static int call_ad_mixer(pss_confdata *devc,unsigned int cmd, caddr_t arg) +static int call_ad_mixer(pss_confdata *devc,unsigned int cmd, void __user *arg) { if (devc->ad_mixer_dev != NO_WSS_MIXER) return mixer_devs[devc->ad_mixer_dev]->ioctl(devc->ad_mixer_dev, cmd, arg); @@ -487,7 +509,7 @@ static int call_ad_mixer(pss_confdata *devc,unsigned int cmd, caddr_t arg) return -EINVAL; } -static int pss_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) +static int pss_mixer_ioctl (int dev, unsigned int cmd, void __user *arg) { pss_confdata *devc = mixer_devs[dev]->devc; int cmdf = cmd & 0xff; @@ -513,33 +535,38 @@ static int pss_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) return call_ad_mixer(devc, cmd, arg); else { - if (*(int *)arg != 0) + int v; + if (get_user(v, (int __user *)arg)) + return -EFAULT; + if (v != 0) return -EINVAL; return 0; } case SOUND_MIXER_VOLUME: - arg_to_volume_stereo(*(unsigned int *)arg, &devc->mixer.volume_l, - &devc->mixer.volume_r); + if (set_volume_stereo(arg, + &devc->mixer.volume_l, + &devc->mixer.volume_r)) + return -EFAULT; set_master_volume(devc, devc->mixer.volume_l, devc->mixer.volume_r); return ret_vol_stereo(devc->mixer.volume_l, devc->mixer.volume_r); case SOUND_MIXER_BASS: - arg_to_volume_mono(*(unsigned int *)arg, - &devc->mixer.bass); + if (set_volume_mono(arg, &devc->mixer.bass)) + return -EFAULT; set_bass(devc, devc->mixer.bass); return ret_vol_mono(devc->mixer.bass); case SOUND_MIXER_TREBLE: - arg_to_volume_mono(*(unsigned int *)arg, - &devc->mixer.treble); + if (set_volume_mono(arg, &devc->mixer.treble)) + return -EFAULT; set_treble(devc, devc->mixer.treble); return ret_vol_mono(devc->mixer.treble); case SOUND_MIXER_SYNTH: - arg_to_volume_mono(*(unsigned int *)arg, - &devc->mixer.synth); + if (set_volume_mono(arg, &devc->mixer.synth)) + return -EFAULT; set_synth_volume(devc, devc->mixer.synth); return ret_vol_mono(devc->mixer.synth); @@ -549,54 +576,67 @@ static int pss_mixer_ioctl (int dev, unsigned int cmd, caddr_t arg) } else { + int val, and_mask = 0, or_mask = 0; /* * Return parameters */ switch (cmdf) { - case SOUND_MIXER_DEVMASK: if (call_ad_mixer(devc, cmd, arg) == -EINVAL) - *(int *)arg = 0; /* no mixer devices */ - return (*(int *)arg |= SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_SYNTH); + break; + and_mask = ~0; + or_mask = SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_SYNTH; + break; case SOUND_MIXER_STEREODEVS: if (call_ad_mixer(devc, cmd, arg) == -EINVAL) - *(int *)arg = 0; /* no stereo devices */ - return (*(int *)arg |= SOUND_MASK_VOLUME); + break; + and_mask = ~0; + or_mask = SOUND_MASK_VOLUME; + break; case SOUND_MIXER_RECMASK: if (devc->ad_mixer_dev != NO_WSS_MIXER) return call_ad_mixer(devc, cmd, arg); - else - return (*(int *)arg = 0); /* no record devices */ + break; case SOUND_MIXER_CAPS: if (devc->ad_mixer_dev != NO_WSS_MIXER) return call_ad_mixer(devc, cmd, arg); - else - return (*(int *)arg = SOUND_CAP_EXCL_INPUT); + or_mask = SOUND_CAP_EXCL_INPUT; + break; case SOUND_MIXER_RECSRC: if (devc->ad_mixer_dev != NO_WSS_MIXER) return call_ad_mixer(devc, cmd, arg); - else - return (*(int *)arg = 0); /* no record source */ + break; case SOUND_MIXER_VOLUME: - return (*(int *)arg = ret_vol_stereo(devc->mixer.volume_l, devc->mixer.volume_r)); + or_mask = ret_vol_stereo(devc->mixer.volume_l, devc->mixer.volume_r); + break; case SOUND_MIXER_BASS: - return (*(int *)arg = ret_vol_mono(devc->mixer.bass)); + or_mask = ret_vol_mono(devc->mixer.bass); + break; case SOUND_MIXER_TREBLE: - return (*(int *)arg = ret_vol_mono(devc->mixer.treble)); + or_mask = ret_vol_mono(devc->mixer.treble); + break; case SOUND_MIXER_SYNTH: - return (*(int *)arg = ret_vol_mono(devc->mixer.synth)); + or_mask = ret_vol_mono(devc->mixer.synth); + break; default: return -EINVAL; } + if (get_user(val, (int __user *)arg)) + return -EFAULT; + val &= and_mask; + val |= or_mask; + if (put_user(val, (int __user *)arg)) + return -EFAULT; + return val; } } @@ -608,7 +648,7 @@ static struct mixer_operations pss_mixer_operations = .ioctl = pss_mixer_ioctl }; -void disable_all_emulations(void) +static void disable_all_emulations(void) { outw(0x0000, REG(CONF_PSS)); /* 0x0400 enables joystick */ outw(0x0000, REG(CONF_WSS)); @@ -617,7 +657,7 @@ void disable_all_emulations(void) outw(0x0000, REG(CONF_CDROM)); } -void configure_nonsound_components(void) +static void configure_nonsound_components(void) { /* Configure Joystick port */ @@ -651,7 +691,7 @@ void configure_nonsound_components(void) } } -void __init attach_pss(struct address_info *hw_config) +static int __init attach_pss(struct address_info *hw_config) { unsigned short id; char tmp[100]; @@ -663,10 +703,7 @@ void __init attach_pss(struct address_info *hw_config) devc->ad_mixer_dev = NO_WSS_MIXER; if (!probe_pss(hw_config)) - return; - - request_region(hw_config->io_base, 0x10, "PSS mixer, SB emulation"); - request_region(hw_config->io_base + 0x10, 0x9, "PSS config"); + return 0; id = inw(REG(PSS_ID)) & 0x00ff; @@ -676,21 +713,27 @@ void __init attach_pss(struct address_info *hw_config) disable_all_emulations(); -#if YOU_REALLY_WANT_TO_ALLOCATE_THESE_RESOURCES +#ifdef YOU_REALLY_WANT_TO_ALLOCATE_THESE_RESOURCES if (sound_alloc_dma(hw_config->dma, "PSS")) { printk("pss.c: Can't allocate DMA channel.\n"); - return; + release_region(hw_config->io_base, 0x10); + release_region(hw_config->io_base+0x10, 0x9); + return 0; } if (!set_irq(devc, CONF_PSS, devc->irq)) { printk("PSS: IRQ allocation error.\n"); - return; + release_region(hw_config->io_base, 0x10); + release_region(hw_config->io_base+0x10, 0x9); + return 0; } if (!set_dma(devc, CONF_PSS, devc->dma)) { printk(KERN_ERR "PSS: DMA allocation error\n"); - return; + release_region(hw_config->io_base, 0x10); + release_region(hw_config->io_base+0x10, 0x9); + return 0; } #endif @@ -698,39 +741,38 @@ void __init attach_pss(struct address_info *hw_config) pss_initialized = 1; sprintf(tmp, "ECHO-PSS Rev. %d", id); conf_printf(tmp, hw_config); + return 1; } -int __init probe_pss_mpu(struct address_info *hw_config) +static int __init probe_pss_mpu(struct address_info *hw_config) { + struct resource *ports; int timeout; if (!pss_initialized) return 0; - if (check_region(hw_config->io_base, 2)) - { + ports = request_region(hw_config->io_base, 2, "mpu401"); + + if (!ports) { printk(KERN_ERR "PSS: MPU I/O port conflict\n"); return 0; } - if (!set_io_base(devc, CONF_MIDI, hw_config->io_base)) - { - printk(KERN_ERR "PSS: MIDI base could not be set.\n"); - return 0; + if (!set_io_base(devc, CONF_MIDI, hw_config->io_base)) { + printk(KERN_ERR "PSS: MIDI base could not be set.\n"); + goto fail; } - if (!set_irq(devc, CONF_MIDI, hw_config->irq)) - { - printk(KERN_ERR "PSS: MIDI IRQ allocation error.\n"); - return 0; + if (!set_irq(devc, CONF_MIDI, hw_config->irq)) { + printk(KERN_ERR "PSS: MIDI IRQ allocation error.\n"); + goto fail; } - if (!pss_synthLen) - { + if (!pss_synthLen) { printk(KERN_ERR "PSS: Can't enable MPU. MIDI synth microcode not available.\n"); - return 0; + goto fail; } - if (!pss_download_boot(devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) - { + if (!pss_download_boot(devc, pss_synth, pss_synthLen, CPF_FIRST | CPF_LAST)) { printk(KERN_ERR "PSS: Unable to load MIDI synth microcode to DSP.\n"); - return 0; + goto fail; } /* @@ -746,7 +788,16 @@ int __init probe_pss_mpu(struct address_info *hw_config) break; /* No more input */ } - return probe_mpu401(hw_config); + if (!probe_mpu401(hw_config, ports)) + goto fail; + + attach_mpu401(hw_config, THIS_MODULE); /* Slot 1 */ + if (hw_config->slots[1] != -1) /* The MPU driver installed itself */ + midi_devs[hw_config->slots[1]]->coproc = &pss_coproc_operations; + return 1; +fail: + release_region(hw_config->io_base, 2); + return 0; } static int pss_coproc_open(void *dev_info, int sub_device) @@ -803,7 +854,7 @@ static int download_boot_block(void *dev_info, copr_buffer * buf) return 0; } -static int pss_coproc_ioctl(void *dev_info, unsigned int cmd, caddr_t arg, int local) +static int pss_coproc_ioctl(void *dev_info, unsigned int cmd, void __user *arg, int local) { copr_buffer *buf; copr_msg *mbuf; @@ -987,39 +1038,36 @@ static coproc_operations pss_coproc_operations = &pss_data }; -static void __init attach_pss_mpu(struct address_info *hw_config) -{ - attach_mpu401(hw_config, THIS_MODULE); /* Slot 1 */ - if (hw_config->slots[1] != -1) /* The MPU driver installed itself */ - midi_devs[hw_config->slots[1]]->coproc = &pss_coproc_operations; -} - static int __init probe_pss_mss(struct address_info *hw_config) { volatile int timeout; + struct resource *ports; + int my_mix = -999; /* gcc shut up */ if (!pss_initialized) return 0; - if (check_region(hw_config->io_base, 8)) - { - printk(KERN_ERR "PSS: WSS I/O port conflicts.\n"); - return 0; + if (!request_region(hw_config->io_base, 4, "WSS config")) { + printk(KERN_ERR "PSS: WSS I/O port conflicts.\n"); + return 0; } - if (!set_io_base(devc, CONF_WSS, hw_config->io_base)) - { - printk("PSS: WSS base not settable.\n"); + ports = request_region(hw_config->io_base + 4, 4, "ad1848"); + if (!ports) { + printk(KERN_ERR "PSS: WSS I/O port conflicts.\n"); + release_region(hw_config->io_base, 4); return 0; } - if (!set_irq(devc, CONF_WSS, hw_config->irq)) - { + if (!set_io_base(devc, CONF_WSS, hw_config->io_base)) { + printk("PSS: WSS base not settable.\n"); + goto fail; + } + if (!set_irq(devc, CONF_WSS, hw_config->irq)) { printk("PSS: WSS IRQ allocation error.\n"); - return 0; + goto fail; } - if (!set_dma(devc, CONF_WSS, hw_config->dma)) - { + if (!set_dma(devc, CONF_WSS, hw_config->dma)) { printk(KERN_ERR "PSS: WSS DMA allocation error\n"); - return 0; + goto fail; } /* * For some reason the card returns 0xff in the WSS status register @@ -1037,13 +1085,9 @@ static int __init probe_pss_mss(struct address_info *hw_config) (timeout < 100000); timeout++) ; - return probe_ms_sound(hw_config); -} + if (!probe_ms_sound(hw_config, ports)) + goto fail; -static void __init attach_pss_mss(struct address_info *hw_config) -{ - int my_mix = -999; /* gcc shut up */ - devc->ad_mixer_dev = NO_WSS_MIXER; if (pss_mixer) { @@ -1054,11 +1098,11 @@ static void __init attach_pss_mss(struct address_info *hw_config) devc)) < 0) { printk(KERN_ERR "Could not install PSS mixer\n"); - return; + goto fail; } } pss_mixer_reset(devc); - attach_ms_sound(hw_config, THIS_MODULE); /* Slot 0 */ + attach_ms_sound(hw_config, ports, THIS_MODULE); /* Slot 0 */ if (hw_config->slots[0] != -1) { @@ -1070,6 +1114,11 @@ static void __init attach_pss_mss(struct address_info *hw_config) devc->ad_mixer_dev = audio_devs[hw_config->slots[0]]->mixer_dev; } } + return 1; +fail: + release_region(hw_config->io_base + 4, 4); + release_region(hw_config->io_base, 4); + return 0; } static inline void __exit unload_pss(struct address_info *hw_config) @@ -1099,33 +1148,33 @@ static int mss_irq __initdata = -1; static int mss_dma __initdata = -1; static int mpu_io __initdata = -1; static int mpu_irq __initdata = -1; -static int pss_no_sound __initdata = 0; /* Just configure non-sound components */ +static int pss_no_sound = 0; /* Just configure non-sound components */ static int pss_keep_settings = 1; /* Keep hardware settings at module exit */ static char *pss_firmware = "/etc/sound/pss_synth"; -MODULE_PARM(pss_io, "i"); +module_param(pss_io, int, 0); MODULE_PARM_DESC(pss_io, "Set i/o base of PSS card (probably 0x220 or 0x240)"); -MODULE_PARM(mss_io, "i"); +module_param(mss_io, int, 0); MODULE_PARM_DESC(mss_io, "Set WSS (audio) i/o base (0x530, 0x604, 0xE80, 0xF40, or other. Address must end in 0 or 4 and must be from 0x100 to 0xFF4)"); -MODULE_PARM(mss_irq, "i"); +module_param(mss_irq, int, 0); MODULE_PARM_DESC(mss_irq, "Set WSS (audio) IRQ (3, 5, 7, 9, 10, 11, 12)"); -MODULE_PARM(mss_dma, "i"); +module_param(mss_dma, int, 0); MODULE_PARM_DESC(mss_dma, "Set WSS (audio) DMA (0, 1, 3)"); -MODULE_PARM(mpu_io, "i"); +module_param(mpu_io, int, 0); MODULE_PARM_DESC(mpu_io, "Set MIDI i/o base (0x330 or other. Address must be on 4 location boundaries and must be from 0x100 to 0xFFC)"); -MODULE_PARM(mpu_irq, "i"); +module_param(mpu_irq, int, 0); MODULE_PARM_DESC(mpu_irq, "Set MIDI IRQ (3, 5, 7, 9, 10, 11, 12)"); -MODULE_PARM(pss_cdrom_port, "i"); +module_param(pss_cdrom_port, int, 0); MODULE_PARM_DESC(pss_cdrom_port, "Set the PSS CDROM port i/o base (0x340 or other)"); -MODULE_PARM(pss_enable_joystick, "i"); +module_param(pss_enable_joystick, bool, 0); MODULE_PARM_DESC(pss_enable_joystick, "Enables the PSS joystick port (1 to enable, 0 to disable)"); -MODULE_PARM(pss_no_sound, "i"); +module_param(pss_no_sound, bool, 0); MODULE_PARM_DESC(pss_no_sound, "Configure sound compoents (0 - no, 1 - yes)"); -MODULE_PARM(pss_keep_settings, "i"); +module_param(pss_keep_settings, bool, 0); MODULE_PARM_DESC(pss_keep_settings, "Keep hardware setting at driver unloading (0 - no, 1 - yes)"); -MODULE_PARM(pss_firmware, "s"); +module_param(pss_firmware, charp, 0); MODULE_PARM_DESC(pss_firmware, "Location of the firmware file (default - /etc/sound/pss_synth)"); -MODULE_PARM(pss_mixer, "b"); +module_param(pss_mixer, bool, 0); MODULE_PARM_DESC(pss_mixer, "Enable (1) or disable (0) PSS mixer (controlling of output volume, bass, treble, synth volume). The mixer is not available on all PSS cards."); MODULE_AUTHOR("Hannu Savolainen, Vladimir Michl"); MODULE_DESCRIPTION("Module for PSS sound cards (based on AD1848, ADSP-2115 and ESC614). This module includes control of output amplifier and synth volume of the Beethoven ADSP-16 card (this may work with other PSS cards)."); @@ -1151,6 +1200,8 @@ static int __init init_pss(void) printk(KERN_INFO "PSS: loading in no sound mode.\n"); disable_all_emulations(); configure_nonsound_components(); + release_region(pss_io, 0x10); + release_region(pss_io + 0x10, 0x9); return 0; } @@ -1172,20 +1223,16 @@ static int __init init_pss(void) fw_load = 1; pss_synthLen = mod_firmware_load(pss_firmware, (void *) &pss_synth); } - if (!probe_pss(&cfg)) + if (!attach_pss(&cfg)) return -ENODEV; - attach_pss(&cfg); /* * Attach stuff */ - if (probe_pss_mpu(&cfg_mpu)) { + if (probe_pss_mpu(&cfg_mpu)) pssmpu = 1; - attach_pss_mpu(&cfg_mpu); - } - if (probe_pss_mss(&cfg2)) { + + if (probe_pss_mss(&cfg2)) pssmss = 1; - attach_pss_mss(&cfg2); - } return 0; }